aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Asm/arm/7zCrcOpt.asm200
-rw-r--r--Asm/arm64/7zAsm.S181
-rw-r--r--Asm/arm64/LzmaDecOpt.S1487
-rw-r--r--Asm/x86/7zAsm.asm436
-rw-r--r--Asm/x86/7zCrcOpt.asm327
-rw-r--r--Asm/x86/AesOpt.asm979
-rw-r--r--Asm/x86/LzFindOpt.asm513
-rw-r--r--Asm/x86/LzmaDecOpt.asm2561
-rw-r--r--Asm/x86/Sha1Opt.asm263
-rw-r--r--Asm/x86/Sha256Opt.asm275
-rw-r--r--Asm/x86/XzCrc64Opt.asm444
-rw-r--r--C/7z.h406
-rw-r--r--C/7zAlloc.c169
-rw-r--r--C/7zAlloc.h38
-rw-r--r--C/7zArcIn.c3557
-rw-r--r--C/7zBuf.c72
-rw-r--r--C/7zBuf.h70
-rw-r--r--C/7zBuf2.c104
-rw-r--r--C/7zCrc.c468
-rw-r--r--C/7zCrc.h52
-rw-r--r--C/7zCrcOpt.c232
-rw-r--r--C/7zDec.c1239
-rw-r--r--C/7zFile.c729
-rw-r--r--C/7zFile.h175
-rw-r--r--C/7zStream.c375
-rw-r--r--C/7zTypes.h972
-rw-r--r--C/7zVersion.h54
-rw-r--r--C/7zVersion.rc110
-rw-r--r--C/7zWindows.h101
-rw-r--r--C/7zip_gcc_c.mak360
-rw-r--r--C/Aes.c699
-rw-r--r--C/Aes.h98
-rw-r--r--C/AesOpt.c1024
-rw-r--r--C/Alloc.c990
-rw-r--r--C/Alloc.h122
-rw-r--r--C/Android.bp13
-rw-r--r--C/Bcj2.c547
-rw-r--r--C/Bcj2.h478
-rw-r--r--C/Bcj2Enc.c817
-rw-r--r--C/Blake2.h48
-rw-r--r--C/Blake2s.c250
-rw-r--r--C/Bra.c650
-rw-r--r--C/Bra.h163
-rw-r--r--C/Bra86.c269
-rw-r--r--C/BraIA64.c67
-rw-r--r--C/BwtSort.c516
-rw-r--r--C/BwtSort.h26
-rw-r--r--C/Compiler.h192
-rw-r--r--C/CpuArch.c1041
-rw-r--r--C/CpuArch.h859
-rw-r--r--C/Delta.c233
-rw-r--r--C/Delta.h38
-rw-r--r--C/DllSecur.c219
-rw-r--r--C/DllSecur.h40
-rw-r--r--C/HuffEnc.c154
-rw-r--r--C/HuffEnc.h23
-rw-r--r--C/LzFind.c2844
-rw-r--r--C/LzFind.h280
-rw-r--r--C/LzFindMt.c2259
-rw-r--r--C/LzFindMt.h210
-rw-r--r--C/LzFindOpt.c578
-rw-r--r--C/LzHash.h91
-rw-r--r--C/Lzma2Dec.c979
-rw-r--r--C/Lzma2Dec.h241
-rw-r--r--C/Lzma2DecMt.c2177
-rw-r--r--C/Lzma2DecMt.h160
-rw-r--r--C/Lzma2Enc.c1608
-rw-r--r--C/Lzma2Enc.h112
-rw-r--r--C/Lzma86.h222
-rw-r--r--C/Lzma86Dec.c107
-rw-r--r--C/Lzma86Enc.c209
-rw-r--r--C/LzmaDec.c2548
-rw-r--r--C/LzmaDec.h471
-rw-r--r--C/LzmaEnc.c6120
-rw-r--r--C/LzmaEnc.h159
-rw-r--r--C/LzmaLib.c82
-rw-r--r--C/LzmaLib.h269
-rw-r--r--C/MtCoder.c1172
-rw-r--r--C/MtCoder.h282
-rw-r--r--C/MtDec.c2252
-rw-r--r--C/MtDec.h403
-rw-r--r--C/Ppmd.h254
-rw-r--r--C/Ppmd7.c1834
-rw-r--r--C/Ppmd7.h323
-rw-r--r--C/Ppmd7Dec.c503
-rw-r--r--C/Ppmd7Enc.c525
-rw-r--r--C/Ppmd7aDec.c295
-rw-r--r--C/Ppmd8.c1565
-rw-r--r--C/Ppmd8.h181
-rw-r--r--C/Ppmd8Dec.c295
-rw-r--r--C/Ppmd8Enc.c338
-rw-r--r--C/Precomp.h20
-rw-r--r--C/RotateDefs.h80
-rw-r--r--C/Sha1.c498
-rw-r--r--C/Sha1.h76
-rw-r--r--C/Sha1Opt.c386
-rw-r--r--C/Sha256.c764
-rw-r--r--C/Sha256.h102
-rw-r--r--C/Sha256Opt.c386
-rw-r--r--C/Sort.c282
-rw-r--r--C/Sort.h36
-rw-r--r--C/SwapBytes.c800
-rw-r--r--C/SwapBytes.h17
-rw-r--r--C/Threads.c657
-rw-r--r--C/Threads.h308
-rw-r--r--C/Util/7z/7z.dsp486
-rw-r--r--C/Util/7z/7z.dsw58
-rw-r--r--C/Util/7z/7zMain.c1574
-rw-r--r--C/Util/7z/Precomp.c8
-rw-r--r--C/Util/7z/Precomp.h24
-rw-r--r--C/Util/7z/makefile80
-rw-r--r--C/Util/7z/makefile.gcc107
-rw-r--r--C/Util/7zipInstall/7zip.icobin0 -> 1078 bytes
-rw-r--r--C/Util/7zipInstall/7zipInstall.c1699
-rw-r--r--C/Util/7zipInstall/7zipInstall.dsp248
-rw-r--r--C/Util/7zipInstall/7zipInstall.dsw29
-rw-r--r--C/Util/7zipInstall/7zipInstall.manifest18
-rw-r--r--C/Util/7zipInstall/Precomp.c4
-rw-r--r--C/Util/7zipInstall/Precomp.h14
-rw-r--r--C/Util/7zipInstall/makefile44
-rw-r--r--C/Util/7zipInstall/resource.h9
-rw-r--r--C/Util/7zipInstall/resource.rc47
-rw-r--r--C/Util/7zipUninstall/7zipUninstall.c1217
-rw-r--r--C/Util/7zipUninstall/7zipUninstall.dsp132
-rw-r--r--C/Util/7zipUninstall/7zipUninstall.dsw29
-rw-r--r--C/Util/7zipUninstall/7zipUninstall.icobin0 -> 1078 bytes
-rw-r--r--C/Util/7zipUninstall/7zipUninstall.manifest18
-rw-r--r--C/Util/7zipUninstall/Precomp.c4
-rw-r--r--C/Util/7zipUninstall/Precomp.h14
-rw-r--r--C/Util/7zipUninstall/makefile18
-rw-r--r--C/Util/7zipUninstall/resource.h9
-rw-r--r--C/Util/7zipUninstall/resource.rc47
-rw-r--r--C/Util/Lzma/LzmaUtil.c571
-rw-r--r--C/Util/Lzma/LzmaUtil.dsp356
-rw-r--r--C/Util/Lzma/LzmaUtil.dsw58
-rw-r--r--C/Util/Lzma/Precomp.h14
-rw-r--r--C/Util/Lzma/makefile58
-rw-r--r--C/Util/Lzma/makefile.gcc65
-rw-r--r--C/Util/LzmaLib/LzmaLib.def8
-rw-r--r--C/Util/LzmaLib/LzmaLib.dsp380
-rw-r--r--C/Util/LzmaLib/LzmaLib.dsw58
-rw-r--r--C/Util/LzmaLib/LzmaLibExports.c29
-rw-r--r--C/Util/LzmaLib/Precomp.c4
-rw-r--r--C/Util/LzmaLib/Precomp.h14
-rw-r--r--C/Util/LzmaLib/makefile88
-rw-r--r--C/Util/LzmaLib/resource.rc6
-rw-r--r--C/Util/SfxSetup/Precomp.c8
-rw-r--r--C/Util/SfxSetup/Precomp.h24
-rw-r--r--C/Util/SfxSetup/SfxSetup.c1296
-rw-r--r--C/Util/SfxSetup/SfxSetup.dsp462
-rw-r--r--C/Util/SfxSetup/SfxSetup.dsw58
-rw-r--r--C/Util/SfxSetup/makefile77
-rw-r--r--C/Util/SfxSetup/makefile_con78
-rw-r--r--C/Util/SfxSetup/resource.rc10
-rw-r--r--C/Xz.c180
-rw-r--r--C/Xz.h995
-rw-r--r--C/XzCrc64.c166
-rw-r--r--C/XzCrc64.h52
-rw-r--r--C/XzCrc64Opt.c130
-rw-r--r--C/XzDec.c5641
-rw-r--r--C/XzEnc.c2691
-rw-r--r--C/XzEnc.h121
-rw-r--r--C/XzIn.c659
-rw-r--r--C/var_clang.mak11
-rw-r--r--C/var_clang_arm64.mak11
-rw-r--r--C/var_clang_x64.mak11
-rw-r--r--C/var_clang_x86.mak11
-rw-r--r--C/var_gcc.mak12
-rw-r--r--C/var_gcc_arm64.mak12
-rw-r--r--C/var_gcc_x64.mak10
-rw-r--r--C/var_gcc_x86.mak10
-rw-r--r--C/var_mac_arm64.mak11
-rw-r--r--C/var_mac_x64.mak11
-rw-r--r--C/warn_clang.mak1
-rw-r--r--C/warn_clang_mac.mak1
-rw-r--r--C/warn_gcc.mak51
-rw-r--r--CPP/7zip/7zip.mak480
-rw-r--r--CPP/7zip/7zip_gcc.mak1294
-rw-r--r--CPP/7zip/Aes.mak17
-rw-r--r--CPP/7zip/Archive/7z/7z.dsp638
-rw-r--r--CPP/7zip/Archive/7z/7z.dsw29
-rw-r--r--CPP/7zip/Archive/7z/7zCompressionMode.cpp6
-rw-r--r--CPP/7zip/Archive/7z/7zCompressionMode.h167
-rw-r--r--CPP/7zip/Archive/7z/7zDecode.cpp1168
-rw-r--r--CPP/7zip/Archive/7z/7zDecode.h143
-rw-r--r--CPP/7zip/Archive/7z/7zEncode.cpp1403
-rw-r--r--CPP/7zip/Archive/7z/7zEncode.h187
-rw-r--r--CPP/7zip/Archive/7z/7zExtract.cpp868
-rw-r--r--CPP/7zip/Archive/7z/7zFolderInStream.cpp403
-rw-r--r--CPP/7zip/Archive/7z/7zFolderInStream.h162
-rw-r--r--CPP/7zip/Archive/7z/7zHandler.cpp1556
-rw-r--r--CPP/7zip/Archive/7z/7zHandler.h357
-rw-r--r--CPP/7zip/Archive/7z/7zHandlerOut.cpp2028
-rw-r--r--CPP/7zip/Archive/7z/7zHeader.cpp38
-rw-r--r--CPP/7zip/Archive/7z/7zHeader.h301
-rw-r--r--CPP/7zip/Archive/7z/7zIn.cpp3423
-rw-r--r--CPP/7zip/Archive/7z/7zIn.h896
-rw-r--r--CPP/7zip/Archive/7z/7zItem.h409
-rw-r--r--CPP/7zip/Archive/7z/7zOut.cpp1856
-rw-r--r--CPP/7zip/Archive/7z/7zOut.h665
-rw-r--r--CPP/7zip/Archive/7z/7zProperties.cpp356
-rw-r--r--CPP/7zip/Archive/7z/7zProperties.h48
-rw-r--r--CPP/7zip/Archive/7z/7zRegister.cpp48
-rw-r--r--CPP/7zip/Archive/7z/7zSpecStream.cpp53
-rw-r--r--CPP/7zip/Archive/7z/7zSpecStream.h84
-rw-r--r--CPP/7zip/Archive/7z/7zUpdate.cpp5491
-rw-r--r--CPP/7zip/Archive/7z/7zUpdate.h285
-rw-r--r--CPP/7zip/Archive/7z/StdAfx.cpp6
-rw-r--r--CPP/7zip/Archive/7z/StdAfx.h19
-rw-r--r--CPP/7zip/Archive/7z/makefile81
-rw-r--r--CPP/7zip/Archive/7z/resource.rc11
-rw-r--r--CPP/7zip/Archive/ApfsHandler.cpp4482
-rw-r--r--CPP/7zip/Archive/ApmHandler.cpp314
-rw-r--r--CPP/7zip/Archive/ArHandler.cpp843
-rw-r--r--CPP/7zip/Archive/Archive.def26
-rw-r--r--CPP/7zip/Archive/Archive2.def40
-rw-r--r--CPP/7zip/Archive/ArchiveExports.cpp309
-rw-r--r--CPP/7zip/Archive/ArjHandler.cpp1009
-rw-r--r--CPP/7zip/Archive/Base64Handler.cpp505
-rw-r--r--CPP/7zip/Archive/Bz2Handler.cpp478
-rw-r--r--CPP/7zip/Archive/Cab/CabBlockInStream.cpp100
-rw-r--r--CPP/7zip/Archive/Cab/CabBlockInStream.h39
-rw-r--r--CPP/7zip/Archive/Cab/CabHandler.cpp1261
-rw-r--r--CPP/7zip/Archive/Cab/CabHandler.h29
-rw-r--r--CPP/7zip/Archive/Cab/CabHeader.cpp15
-rw-r--r--CPP/7zip/Archive/Cab/CabHeader.h41
-rw-r--r--CPP/7zip/Archive/Cab/CabIn.cpp491
-rw-r--r--CPP/7zip/Archive/Cab/CabIn.h176
-rw-r--r--CPP/7zip/Archive/Cab/CabItem.h66
-rw-r--r--CPP/7zip/Archive/Cab/CabRegister.cpp19
-rw-r--r--CPP/7zip/Archive/Cab/StdAfx.h11
-rw-r--r--CPP/7zip/Archive/Chm/ChmHandler.cpp800
-rw-r--r--CPP/7zip/Archive/Chm/ChmHandler.h27
-rw-r--r--CPP/7zip/Archive/Chm/ChmIn.cpp1018
-rw-r--r--CPP/7zip/Archive/Chm/ChmIn.h282
-rw-r--r--CPP/7zip/Archive/Chm/StdAfx.h11
-rw-r--r--CPP/7zip/Archive/ComHandler.cpp896
-rw-r--r--CPP/7zip/Archive/Common/CoderMixer2.cpp2269
-rw-r--r--CPP/7zip/Archive/Common/CoderMixer2.h894
-rw-r--r--CPP/7zip/Archive/Common/DummyOutStream.cpp34
-rw-r--r--CPP/7zip/Archive/Common/DummyOutStream.h48
-rw-r--r--CPP/7zip/Archive/Common/FindSignature.cpp62
-rw-r--r--CPP/7zip/Archive/Common/FindSignature.h12
-rw-r--r--CPP/7zip/Archive/Common/HandlerOut.cpp543
-rw-r--r--CPP/7zip/Archive/Common/HandlerOut.h264
-rw-r--r--CPP/7zip/Archive/Common/InStreamWithCRC.cpp103
-rw-r--r--CPP/7zip/Archive/Common/InStreamWithCRC.h134
-rw-r--r--CPP/7zip/Archive/Common/ItemNameUtils.cpp223
-rw-r--r--CPP/7zip/Archive/Common/ItemNameUtils.h58
-rw-r--r--CPP/7zip/Archive/Common/MultiStream.cpp384
-rw-r--r--CPP/7zip/Archive/Common/MultiStream.h177
-rw-r--r--CPP/7zip/Archive/Common/OutStreamWithCRC.cpp36
-rw-r--r--CPP/7zip/Archive/Common/OutStreamWithCRC.h72
-rw-r--r--CPP/7zip/Archive/Common/OutStreamWithSha1.cpp18
-rw-r--r--CPP/7zip/Archive/Common/OutStreamWithSha1.h39
-rw-r--r--CPP/7zip/Archive/Common/ParseProperties.cpp6
-rw-r--r--CPP/7zip/Archive/Common/ParseProperties.h12
-rw-r--r--CPP/7zip/Archive/Common/StdAfx.h19
-rw-r--r--CPP/7zip/Archive/CpioHandler.cpp1099
-rw-r--r--CPP/7zip/Archive/CramfsHandler.cpp784
-rw-r--r--CPP/7zip/Archive/DeflateProps.cpp3
-rw-r--r--CPP/7zip/Archive/DeflateProps.h6
-rw-r--r--CPP/7zip/Archive/DllExports.cpp96
-rw-r--r--CPP/7zip/Archive/DllExports2.cpp297
-rw-r--r--CPP/7zip/Archive/DmgHandler.cpp1771
-rw-r--r--CPP/7zip/Archive/ElfHandler.cpp1108
-rw-r--r--CPP/7zip/Archive/ExtHandler.cpp2869
-rw-r--r--CPP/7zip/Archive/FatHandler.cpp1068
-rw-r--r--CPP/7zip/Archive/FlvHandler.cpp521
-rw-r--r--CPP/7zip/Archive/GptHandler.cpp472
-rw-r--r--CPP/7zip/Archive/GzHandler.cpp1210
-rw-r--r--CPP/7zip/Archive/HandlerCont.cpp346
-rw-r--r--CPP/7zip/Archive/HandlerCont.h134
-rw-r--r--CPP/7zip/Archive/HfsHandler.cpp2590
-rw-r--r--CPP/7zip/Archive/HfsHandler.h90
-rw-r--r--CPP/7zip/Archive/IArchive.h1312
-rw-r--r--CPP/7zip/Archive/Icons/apfs.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/arj.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/bz2.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/cab.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/cpio.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/deb.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/dmg.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/fat.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/gz.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/hfs.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/iso.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/lzh.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/lzma.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/ntfs.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/rar.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/rpm.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/split.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/squashfs.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/tar.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/vhd.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/wim.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/xar.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/xz.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/z.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/Icons/zip.icobin0 -> 3638 bytes
-rw-r--r--CPP/7zip/Archive/IhexHandler.cpp493
-rw-r--r--CPP/7zip/Archive/Iso/IsoHandler.cpp486
-rw-r--r--CPP/7zip/Archive/Iso/IsoHandler.h24
-rw-r--r--CPP/7zip/Archive/Iso/IsoHeader.cpp12
-rw-r--r--CPP/7zip/Archive/Iso/IsoHeader.h64
-rw-r--r--CPP/7zip/Archive/Iso/IsoIn.cpp693
-rw-r--r--CPP/7zip/Archive/Iso/IsoIn.h318
-rw-r--r--CPP/7zip/Archive/Iso/IsoItem.h320
-rw-r--r--CPP/7zip/Archive/Iso/IsoRegister.cpp21
-rw-r--r--CPP/7zip/Archive/Iso/StdAfx.h11
-rw-r--r--CPP/7zip/Archive/LpHandler.cpp1166
-rw-r--r--CPP/7zip/Archive/LzhHandler.cpp733
-rw-r--r--CPP/7zip/Archive/LzmaHandler.cpp1240
-rw-r--r--CPP/7zip/Archive/MachoHandler.cpp744
-rw-r--r--CPP/7zip/Archive/MbrHandler.cpp567
-rw-r--r--CPP/7zip/Archive/MslzHandler.cpp390
-rw-r--r--CPP/7zip/Archive/MubHandler.cpp262
-rw-r--r--CPP/7zip/Archive/Nsis/NsisDecode.cpp295
-rw-r--r--CPP/7zip/Archive/Nsis/NsisDecode.h97
-rw-r--r--CPP/7zip/Archive/Nsis/NsisHandler.cpp694
-rw-r--r--CPP/7zip/Archive/Nsis/NsisHandler.h30
-rw-r--r--CPP/7zip/Archive/Nsis/NsisIn.cpp6138
-rw-r--r--CPP/7zip/Archive/Nsis/NsisIn.h458
-rw-r--r--CPP/7zip/Archive/Nsis/NsisRegister.cpp20
-rw-r--r--CPP/7zip/Archive/Nsis/StdAfx.h11
-rw-r--r--CPP/7zip/Archive/NtfsHandler.cpp2861
-rw-r--r--CPP/7zip/Archive/PeHandler.cpp3272
-rw-r--r--CPP/7zip/Archive/PpmdHandler.cpp398
-rw-r--r--CPP/7zip/Archive/QcowHandler.cpp668
-rw-r--r--CPP/7zip/Archive/Rar/Rar5Handler.cpp3001
-rw-r--r--CPP/7zip/Archive/Rar/Rar5Handler.h419
-rw-r--r--CPP/7zip/Archive/Rar/RarHandler.cpp1782
-rw-r--r--CPP/7zip/Archive/Rar/RarHandler.h114
-rw-r--r--CPP/7zip/Archive/Rar/RarHeader.h209
-rw-r--r--CPP/7zip/Archive/Rar/RarItem.h97
-rw-r--r--CPP/7zip/Archive/Rar/RarVol.h136
-rw-r--r--CPP/7zip/Archive/Rar/StdAfx.cpp3
-rw-r--r--CPP/7zip/Archive/Rar/StdAfx.h11
-rw-r--r--CPP/7zip/Archive/RpmHandler.cpp769
-rw-r--r--CPP/7zip/Archive/SparseHandler.cpp547
-rw-r--r--CPP/7zip/Archive/SplitHandler.cpp710
-rw-r--r--CPP/7zip/Archive/SquashfsHandler.cpp2326
-rw-r--r--CPP/7zip/Archive/StdAfx.h19
-rw-r--r--CPP/7zip/Archive/SwfHandler.cpp994
-rw-r--r--CPP/7zip/Archive/Tar/StdAfx.h11
-rw-r--r--CPP/7zip/Archive/Tar/TarHandler.cpp1045
-rw-r--r--CPP/7zip/Archive/Tar/TarHandler.h58
-rw-r--r--CPP/7zip/Archive/Tar/TarHandlerOut.cpp332
-rw-r--r--CPP/7zip/Archive/Tar/TarHeader.cpp99
-rw-r--r--CPP/7zip/Archive/Tar/TarHeader.h90
-rw-r--r--CPP/7zip/Archive/Tar/TarIn.cpp1132
-rw-r--r--CPP/7zip/Archive/Tar/TarIn.h149
-rw-r--r--CPP/7zip/Archive/Tar/TarItem.h360
-rw-r--r--CPP/7zip/Archive/Tar/TarOut.cpp644
-rw-r--r--CPP/7zip/Archive/Tar/TarOut.h53
-rw-r--r--CPP/7zip/Archive/Tar/TarRegister.cpp31
-rw-r--r--CPP/7zip/Archive/Tar/TarUpdate.cpp555
-rw-r--r--CPP/7zip/Archive/Tar/TarUpdate.h74
-rw-r--r--CPP/7zip/Archive/Udf/StdAfx.h11
-rw-r--r--CPP/7zip/Archive/Udf/UdfHandler.cpp428
-rw-r--r--CPP/7zip/Archive/Udf/UdfHandler.h32
-rw-r--r--CPP/7zip/Archive/Udf/UdfIn.cpp1741
-rw-r--r--CPP/7zip/Archive/Udf/UdfIn.h507
-rw-r--r--CPP/7zip/Archive/UefiHandler.cpp1893
-rw-r--r--CPP/7zip/Archive/VdiHandler.cpp438
-rw-r--r--CPP/7zip/Archive/VhdHandler.cpp977
-rw-r--r--CPP/7zip/Archive/VhdxHandler.cpp2097
-rw-r--r--CPP/7zip/Archive/VmdkHandler.cpp1527
-rw-r--r--CPP/7zip/Archive/Wim/StdAfx.h11
-rw-r--r--CPP/7zip/Archive/Wim/WimHandler.cpp1236
-rw-r--r--CPP/7zip/Archive/Wim/WimHandler.h93
-rw-r--r--CPP/7zip/Archive/Wim/WimHandlerOut.cpp2008
-rw-r--r--CPP/7zip/Archive/Wim/WimIn.cpp1878
-rw-r--r--CPP/7zip/Archive/Wim/WimIn.h659
-rw-r--r--CPP/7zip/Archive/Wim/WimRegister.cpp29
-rw-r--r--CPP/7zip/Archive/XarHandler.cpp730
-rw-r--r--CPP/7zip/Archive/XzHandler.cpp2751
-rw-r--r--CPP/7zip/Archive/XzHandler.h22
-rw-r--r--CPP/7zip/Archive/ZHandler.cpp230
-rw-r--r--CPP/7zip/Archive/Zip/StdAfx.h11
-rw-r--r--CPP/7zip/Archive/Zip/ZipAddCommon.cpp499
-rw-r--r--CPP/7zip/Archive/Zip/ZipAddCommon.h78
-rw-r--r--CPP/7zip/Archive/Zip/ZipCompressionMode.h62
-rw-r--r--CPP/7zip/Archive/Zip/ZipHandler.cpp1716
-rw-r--r--CPP/7zip/Archive/Zip/ZipHandler.h94
-rw-r--r--CPP/7zip/Archive/Zip/ZipHandlerOut.cpp618
-rw-r--r--CPP/7zip/Archive/Zip/ZipHeader.h201
-rw-r--r--CPP/7zip/Archive/Zip/ZipIn.cpp3485
-rw-r--r--CPP/7zip/Archive/Zip/ZipIn.h449
-rw-r--r--CPP/7zip/Archive/Zip/ZipItem.cpp462
-rw-r--r--CPP/7zip/Archive/Zip/ZipItem.h356
-rw-r--r--CPP/7zip/Archive/Zip/ZipOut.cpp420
-rw-r--r--CPP/7zip/Archive/Zip/ZipOut.h103
-rw-r--r--CPP/7zip/Archive/Zip/ZipRegister.cpp38
-rw-r--r--CPP/7zip/Archive/Zip/ZipUpdate.cpp2027
-rw-r--r--CPP/7zip/Archive/Zip/ZipUpdate.h107
-rw-r--r--CPP/7zip/Archive/makefile23
-rw-r--r--CPP/7zip/Asm.mak18
-rw-r--r--CPP/7zip/Bundles/Alone/Alone.dsp3234
-rw-r--r--CPP/7zip/Bundles/Alone/Alone.dsw29
-rw-r--r--CPP/7zip/Bundles/Alone/StdAfx.cpp3
-rw-r--r--CPP/7zip/Bundles/Alone/StdAfx.h11
-rw-r--r--CPP/7zip/Bundles/Alone/afxres.h1
-rw-r--r--CPP/7zip/Bundles/Alone/makefile230
-rw-r--r--CPP/7zip/Bundles/Alone/makefile.gcc348
-rw-r--r--CPP/7zip/Bundles/Alone/resource.rc7
-rw-r--r--CPP/7zip/Bundles/Alone2/StdAfx.cpp3
-rw-r--r--CPP/7zip/Bundles/Alone2/StdAfx.h11
-rw-r--r--CPP/7zip/Bundles/Alone2/makefile29
-rw-r--r--CPP/7zip/Bundles/Alone2/makefile.gcc109
-rw-r--r--CPP/7zip/Bundles/Alone2/resource.rc7
-rw-r--r--CPP/7zip/Bundles/Alone7z/Alone.dsp3953
-rw-r--r--CPP/7zip/Bundles/Alone7z/Alone.dsw58
-rw-r--r--CPP/7zip/Bundles/Alone7z/StdAfx.cpp6
-rw-r--r--CPP/7zip/Bundles/Alone7z/StdAfx.h19
-rw-r--r--CPP/7zip/Bundles/Alone7z/makefile317
-rw-r--r--CPP/7zip/Bundles/Alone7z/makefile.gcc276
-rw-r--r--CPP/7zip/Bundles/Alone7z/resource.rc14
-rw-r--r--CPP/7zip/Bundles/Fm/FM.dsp2251
-rw-r--r--CPP/7zip/Bundles/Fm/FM.dsw29
-rw-r--r--CPP/7zip/Bundles/Fm/StdAfx.cpp3
-rw-r--r--CPP/7zip/Bundles/Fm/StdAfx.h6
-rw-r--r--CPP/7zip/Bundles/Fm/makefile84
-rw-r--r--CPP/7zip/Bundles/Fm/resource.rc7
-rw-r--r--CPP/7zip/Bundles/Format7z/StdAfx.cpp3
-rw-r--r--CPP/7zip/Bundles/Format7z/StdAfx.h11
-rw-r--r--CPP/7zip/Bundles/Format7z/makefile147
-rw-r--r--CPP/7zip/Bundles/Format7z/resource.rc5
-rw-r--r--CPP/7zip/Bundles/Format7zExtract/StdAfx.cpp3
-rw-r--r--CPP/7zip/Bundles/Format7zExtract/StdAfx.h11
-rw-r--r--CPP/7zip/Bundles/Format7zExtract/makefile116
-rw-r--r--CPP/7zip/Bundles/Format7zExtract/resource.rc5
-rw-r--r--CPP/7zip/Bundles/Format7zExtractR/StdAfx.cpp6
-rw-r--r--CPP/7zip/Bundles/Format7zExtractR/StdAfx.h19
-rw-r--r--CPP/7zip/Bundles/Format7zExtractR/makefile194
-rw-r--r--CPP/7zip/Bundles/Format7zExtractR/resource.rc10
-rw-r--r--CPP/7zip/Bundles/Format7zF/Arc.mak297
-rw-r--r--CPP/7zip/Bundles/Format7zF/Arc_gcc.mak379
-rw-r--r--CPP/7zip/Bundles/Format7zF/Format7z.dsp3266
-rw-r--r--CPP/7zip/Bundles/Format7zF/Format7z.dsw29
-rw-r--r--CPP/7zip/Bundles/Format7zF/StdAfx.cpp3
-rw-r--r--CPP/7zip/Bundles/Format7zF/StdAfx.h11
-rw-r--r--CPP/7zip/Bundles/Format7zF/makefile21
-rw-r--r--CPP/7zip/Bundles/Format7zF/makefile.gcc55
-rw-r--r--CPP/7zip/Bundles/Format7zF/resource.rc38
-rw-r--r--CPP/7zip/Bundles/Format7zR/StdAfx.cpp6
-rw-r--r--CPP/7zip/Bundles/Format7zR/StdAfx.h19
-rw-r--r--CPP/7zip/Bundles/Format7zR/makefile236
-rw-r--r--CPP/7zip/Bundles/Format7zR/resource.rc10
-rw-r--r--CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp1607
-rw-r--r--CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp1017
-rw-r--r--CPP/7zip/Bundles/LzmaCon/LzmaCon.dsw58
-rw-r--r--CPP/7zip/Bundles/LzmaCon/StdAfx.cpp6
-rw-r--r--CPP/7zip/Bundles/LzmaCon/StdAfx.h19
-rw-r--r--CPP/7zip/Bundles/LzmaCon/makefile126
-rw-r--r--CPP/7zip/Bundles/LzmaCon/makefile.gcc321
-rw-r--r--CPP/7zip/Bundles/LzmaCon/resource.rc6
-rw-r--r--CPP/7zip/Bundles/LzmaSpec/LzmaSpec.cpp715
-rw-r--r--CPP/7zip/Bundles/SFXCon/SFXCon.dsp1921
-rw-r--r--CPP/7zip/Bundles/SFXCon/SFXCon.dsw58
-rw-r--r--CPP/7zip/Bundles/SFXCon/SfxCon.cpp1003
-rw-r--r--CPP/7zip/Bundles/SFXCon/StdAfx.cpp6
-rw-r--r--CPP/7zip/Bundles/SFXCon/StdAfx.h19
-rw-r--r--CPP/7zip/Bundles/SFXCon/makefile268
-rw-r--r--CPP/7zip/Bundles/SFXCon/makefile.gcc213
-rw-r--r--CPP/7zip/Bundles/SFXCon/resource.rc14
-rw-r--r--CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.cpp492
-rw-r--r--CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.h169
-rw-r--r--CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp272
-rw-r--r--CPP/7zip/Bundles/SFXSetup/ExtractEngine.h22
-rw-r--r--CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp1667
-rw-r--r--CPP/7zip/Bundles/SFXSetup/SFXSetup.dsw58
-rw-r--r--CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp732
-rw-r--r--CPP/7zip/Bundles/SFXSetup/StdAfx.cpp6
-rw-r--r--CPP/7zip/Bundles/SFXSetup/StdAfx.h19
-rw-r--r--CPP/7zip/Bundles/SFXSetup/makefile235
-rw-r--r--CPP/7zip/Bundles/SFXSetup/resource.h12
-rw-r--r--CPP/7zip/Bundles/SFXSetup/resource.rc32
-rw-r--r--CPP/7zip/Bundles/SFXWin/SFXWin.dsp2054
-rw-r--r--CPP/7zip/Bundles/SFXWin/SFXWin.dsw58
-rw-r--r--CPP/7zip/Bundles/SFXWin/SfxWin.cpp495
-rw-r--r--CPP/7zip/Bundles/SFXWin/StdAfx.cpp6
-rw-r--r--CPP/7zip/Bundles/SFXWin/StdAfx.h20
-rw-r--r--CPP/7zip/Bundles/SFXWin/makefile309
-rw-r--r--CPP/7zip/Bundles/SFXWin/resource.h2
-rw-r--r--CPP/7zip/Bundles/SFXWin/resource.rc105
-rw-r--r--CPP/7zip/Bundles/makefile19
-rw-r--r--CPP/7zip/Common/CWrappers.cpp604
-rw-r--r--CPP/7zip/Common/CWrappers.h302
-rw-r--r--CPP/7zip/Common/CreateCoder.cpp1084
-rw-r--r--CPP/7zip/Common/CreateCoder.h392
-rw-r--r--CPP/7zip/Common/FilePathAutoRename.cpp92
-rw-r--r--CPP/7zip/Common/FilePathAutoRename.h20
-rw-r--r--CPP/7zip/Common/FileStreams.cpp1275
-rw-r--r--CPP/7zip/Common/FileStreams.h352
-rw-r--r--CPP/7zip/Common/FilterCoder.cpp1012
-rw-r--r--CPP/7zip/Common/FilterCoder.h406
-rw-r--r--CPP/7zip/Common/InBuffer.cpp327
-rw-r--r--CPP/7zip/Common/InBuffer.h201
-rw-r--r--CPP/7zip/Common/InOutTempBuffer.cpp364
-rw-r--r--CPP/7zip/Common/InOutTempBuffer.h93
-rw-r--r--CPP/7zip/Common/LimitedStreams.cpp760
-rw-r--r--CPP/7zip/Common/LimitedStreams.h473
-rw-r--r--CPP/7zip/Common/LockedStream.cpp6
-rw-r--r--CPP/7zip/Common/LockedStream.h12
-rw-r--r--CPP/7zip/Common/MemBlocks.cpp215
-rw-r--r--CPP/7zip/Common/MemBlocks.h72
-rw-r--r--CPP/7zip/Common/MethodId.cpp6
-rw-r--r--CPP/7zip/Common/MethodId.h20
-rw-r--r--CPP/7zip/Common/MethodProps.cpp1246
-rw-r--r--CPP/7zip/Common/MethodProps.h609
-rw-r--r--CPP/7zip/Common/MultiOutStream.cpp849
-rw-r--r--CPP/7zip/Common/MultiOutStream.h160
-rw-r--r--CPP/7zip/Common/OffsetStream.cpp76
-rw-r--r--CPP/7zip/Common/OffsetStream.h48
-rw-r--r--CPP/7zip/Common/OutBuffer.cpp222
-rw-r--r--CPP/7zip/Common/OutBuffer.h132
-rw-r--r--CPP/7zip/Common/OutMemStream.cpp158
-rw-r--r--CPP/7zip/Common/OutMemStream.h104
-rw-r--r--CPP/7zip/Common/ProgressMt.cpp53
-rw-r--r--CPP/7zip/Common/ProgressMt.h43
-rw-r--r--CPP/7zip/Common/ProgressUtils.cpp102
-rw-r--r--CPP/7zip/Common/ProgressUtils.h68
-rw-r--r--CPP/7zip/Common/PropId.cpp225
-rw-r--r--CPP/7zip/Common/RegisterArc.h158
-rw-r--r--CPP/7zip/Common/RegisterCodec.h212
-rw-r--r--CPP/7zip/Common/StdAfx.h19
-rw-r--r--CPP/7zip/Common/StreamBinder.cpp307
-rw-r--r--CPP/7zip/Common/StreamBinder.h138
-rw-r--r--CPP/7zip/Common/StreamObjects.cpp575
-rw-r--r--CPP/7zip/Common/StreamObjects.h303
-rw-r--r--CPP/7zip/Common/StreamUtils.cpp157
-rw-r--r--CPP/7zip/Common/StreamUtils.h44
-rw-r--r--CPP/7zip/Common/UniqBlocks.cpp114
-rw-r--r--CPP/7zip/Common/UniqBlocks.h67
-rw-r--r--CPP/7zip/Common/VirtThread.cpp95
-rw-r--r--CPP/7zip/Common/VirtThread.h48
-rw-r--r--CPP/7zip/Compress/BZip2Const.h71
-rw-r--r--CPP/7zip/Compress/BZip2Crc.cpp27
-rw-r--r--CPP/7zip/Compress/BZip2Crc.h31
-rw-r--r--CPP/7zip/Compress/BZip2Decoder.cpp1797
-rw-r--r--CPP/7zip/Compress/BZip2Decoder.h389
-rw-r--r--CPP/7zip/Compress/BZip2Encoder.cpp919
-rw-r--r--CPP/7zip/Compress/BZip2Encoder.h247
-rw-r--r--CPP/7zip/Compress/BZip2Register.cpp25
-rw-r--r--CPP/7zip/Compress/Bcj2Coder.cpp1519
-rw-r--r--CPP/7zip/Compress/Bcj2Coder.h247
-rw-r--r--CPP/7zip/Compress/Bcj2Register.cpp48
-rw-r--r--CPP/7zip/Compress/BcjCoder.cpp48
-rw-r--r--CPP/7zip/Compress/BcjCoder.h68
-rw-r--r--CPP/7zip/Compress/BcjRegister.cpp34
-rw-r--r--CPP/7zip/Compress/BitlDecoder.cpp25
-rw-r--r--CPP/7zip/Compress/BitlDecoder.h172
-rw-r--r--CPP/7zip/Compress/BitlEncoder.h56
-rw-r--r--CPP/7zip/Compress/BitmDecoder.h100
-rw-r--r--CPP/7zip/Compress/BitmEncoder.h49
-rw-r--r--CPP/7zip/Compress/BranchMisc.cpp133
-rw-r--r--CPP/7zip/Compress/BranchMisc.h92
-rw-r--r--CPP/7zip/Compress/BranchRegister.cpp96
-rw-r--r--CPP/7zip/Compress/ByteSwap.cpp183
-rw-r--r--CPP/7zip/Compress/Codec.def7
-rw-r--r--CPP/7zip/Compress/CodecExports.cpp722
-rw-r--r--CPP/7zip/Compress/CopyCoder.cpp273
-rw-r--r--CPP/7zip/Compress/CopyCoder.h83
-rw-r--r--CPP/7zip/Compress/CopyRegister.cpp30
-rw-r--r--CPP/7zip/Compress/Deflate64Register.cpp25
-rw-r--r--CPP/7zip/Compress/DeflateConst.h131
-rw-r--r--CPP/7zip/Compress/DeflateDecoder.cpp541
-rw-r--r--CPP/7zip/Compress/DeflateDecoder.h153
-rw-r--r--CPP/7zip/Compress/DeflateEncoder.cpp1019
-rw-r--r--CPP/7zip/Compress/DeflateEncoder.h203
-rw-r--r--CPP/7zip/Compress/DeflateRegister.cpp25
-rw-r--r--CPP/7zip/Compress/DeltaFilter.cpp254
-rw-r--r--CPP/7zip/Compress/DllExports2Compress.cpp28
-rw-r--r--CPP/7zip/Compress/DllExportsCompress.cpp59
-rw-r--r--CPP/7zip/Compress/HuffmanDecoder.h278
-rw-r--r--CPP/7zip/Compress/ImplodeDecoder.cpp258
-rw-r--r--CPP/7zip/Compress/ImplodeDecoder.h61
-rw-r--r--CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp3
-rw-r--r--CPP/7zip/Compress/ImplodeHuffmanDecoder.h6
-rw-r--r--CPP/7zip/Compress/LzOutWindow.cpp14
-rw-r--r--CPP/7zip/Compress/LzOutWindow.h102
-rw-r--r--CPP/7zip/Compress/LzfseDecoder.cpp942
-rw-r--r--CPP/7zip/Compress/LzfseDecoder.h63
-rw-r--r--CPP/7zip/Compress/LzhDecoder.cpp252
-rw-r--r--CPP/7zip/Compress/LzhDecoder.h69
-rw-r--r--CPP/7zip/Compress/Lzma2Decoder.cpp532
-rw-r--r--CPP/7zip/Compress/Lzma2Decoder.h183
-rw-r--r--CPP/7zip/Compress/Lzma2Encoder.cpp248
-rw-r--r--CPP/7zip/Compress/Lzma2Encoder.h72
-rw-r--r--CPP/7zip/Compress/Lzma2Register.cpp44
-rw-r--r--CPP/7zip/Compress/LzmaDecoder.cpp692
-rw-r--r--CPP/7zip/Compress/LzmaDecoder.h226
-rw-r--r--CPP/7zip/Compress/LzmaEncoder.cpp538
-rw-r--r--CPP/7zip/Compress/LzmaEncoder.h91
-rw-r--r--CPP/7zip/Compress/LzmaRegister.cpp44
-rw-r--r--CPP/7zip/Compress/LzmsDecoder.cpp576
-rw-r--r--CPP/7zip/Compress/LzmsDecoder.h271
-rw-r--r--CPP/7zip/Compress/Lzx.h59
-rw-r--r--CPP/7zip/Compress/LzxDecoder.cpp529
-rw-r--r--CPP/7zip/Compress/LzxDecoder.h243
-rw-r--r--CPP/7zip/Compress/Mtf8.h212
-rw-r--r--CPP/7zip/Compress/PpmdDecoder.cpp388
-rw-r--r--CPP/7zip/Compress/PpmdDecoder.h173
-rw-r--r--CPP/7zip/Compress/PpmdEncoder.cpp345
-rw-r--r--CPP/7zip/Compress/PpmdEncoder.h107
-rw-r--r--CPP/7zip/Compress/PpmdRegister.cpp44
-rw-r--r--CPP/7zip/Compress/PpmdZip.cpp300
-rw-r--r--CPP/7zip/Compress/PpmdZip.h85
-rw-r--r--CPP/7zip/Compress/QuantumDecoder.cpp195
-rw-r--r--CPP/7zip/Compress/QuantumDecoder.h169
-rw-r--r--CPP/7zip/Compress/Rar1Decoder.cpp518
-rw-r--r--CPP/7zip/Compress/Rar1Decoder.h71
-rw-r--r--CPP/7zip/Compress/Rar2Decoder.cpp441
-rw-r--r--CPP/7zip/Compress/Rar2Decoder.h164
-rw-r--r--CPP/7zip/Compress/Rar3Decoder.cpp935
-rw-r--r--CPP/7zip/Compress/Rar3Decoder.h275
-rw-r--r--CPP/7zip/Compress/Rar3Vm.cpp1153
-rw-r--r--CPP/7zip/Compress/Rar3Vm.h195
-rw-r--r--CPP/7zip/Compress/Rar5Decoder.cpp980
-rw-r--r--CPP/7zip/Compress/Rar5Decoder.h299
-rw-r--r--CPP/7zip/Compress/RarCodecsRegister.cpp33
-rw-r--r--CPP/7zip/Compress/ShrinkDecoder.cpp244
-rw-r--r--CPP/7zip/Compress/ShrinkDecoder.h35
-rw-r--r--CPP/7zip/Compress/StdAfx.h19
-rw-r--r--CPP/7zip/Compress/XpressDecoder.cpp131
-rw-r--r--CPP/7zip/Compress/XpressDecoder.h15
-rw-r--r--CPP/7zip/Compress/XzDecoder.cpp300
-rw-r--r--CPP/7zip/Compress/XzDecoder.h178
-rw-r--r--CPP/7zip/Compress/XzEncoder.cpp488
-rw-r--r--CPP/7zip/Compress/XzEncoder.h81
-rw-r--r--CPP/7zip/Compress/ZDecoder.cpp237
-rw-r--r--CPP/7zip/Compress/ZDecoder.h49
-rw-r--r--CPP/7zip/Compress/ZlibDecoder.cpp95
-rw-r--r--CPP/7zip/Compress/ZlibDecoder.h71
-rw-r--r--CPP/7zip/Compress/ZlibEncoder.cpp61
-rw-r--r--CPP/7zip/Compress/ZlibEncoder.h42
-rw-r--r--CPP/7zip/Compress/makefile7
-rw-r--r--CPP/7zip/Crc.mak16
-rw-r--r--CPP/7zip/Crc64.mak16
-rw-r--r--CPP/7zip/Crypto/7zAes.cpp597
-rw-r--r--CPP/7zip/Crypto/7zAes.h248
-rw-r--r--CPP/7zip/Crypto/7zAesRegister.cpp34
-rw-r--r--CPP/7zip/Crypto/Codec.def4
-rw-r--r--CPP/7zip/Crypto/HmacSha1.cpp94
-rw-r--r--CPP/7zip/Crypto/HmacSha1.h31
-rw-r--r--CPP/7zip/Crypto/HmacSha256.cpp53
-rw-r--r--CPP/7zip/Crypto/HmacSha256.h27
-rw-r--r--CPP/7zip/Crypto/MyAes.cpp358
-rw-r--r--CPP/7zip/Crypto/MyAes.h179
-rw-r--r--CPP/7zip/Crypto/MyAesReg.cpp45
-rw-r--r--CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp48
-rw-r--r--CPP/7zip/Crypto/Pbkdf2HmacSha1.h19
-rw-r--r--CPP/7zip/Crypto/RandGen.cpp474
-rw-r--r--CPP/7zip/Crypto/RandGen.h81
-rw-r--r--CPP/7zip/Crypto/Rar20Crypto.cpp130
-rw-r--r--CPP/7zip/Crypto/Rar20Crypto.h54
-rw-r--r--CPP/7zip/Crypto/Rar5Aes.cpp265
-rw-r--r--CPP/7zip/Crypto/Rar5Aes.h98
-rw-r--r--CPP/7zip/Crypto/RarAes.cpp194
-rw-r--r--CPP/7zip/Crypto/RarAes.h54
-rw-r--r--CPP/7zip/Crypto/Sha1Cls.h37
-rw-r--r--CPP/7zip/Crypto/StdAfx.h19
-rw-r--r--CPP/7zip/Crypto/WzAes.cpp231
-rw-r--r--CPP/7zip/Crypto/WzAes.h161
-rw-r--r--CPP/7zip/Crypto/ZipCrypto.cpp114
-rw-r--r--CPP/7zip/Crypto/ZipCrypto.h80
-rw-r--r--CPP/7zip/Crypto/ZipStrong.cpp264
-rw-r--r--CPP/7zip/Crypto/ZipStrong.h73
-rw-r--r--CPP/7zip/GuiCommon.rc168
-rw-r--r--CPP/7zip/Guid.txt457
-rw-r--r--CPP/7zip/ICoder.h876
-rw-r--r--CPP/7zip/IDecl.h104
-rw-r--r--CPP/7zip/IPassword.h77
-rw-r--r--CPP/7zip/IProgress.h39
-rw-r--r--CPP/7zip/IStream.h334
-rw-r--r--CPP/7zip/LzFindOpt.mak7
-rw-r--r--CPP/7zip/LzmaDec.mak12
-rw-r--r--CPP/7zip/LzmaDec_gcc.mak14
-rw-r--r--CPP/7zip/MyVersion.h4
-rw-r--r--CPP/7zip/MyVersionInfo.rc4
-rw-r--r--CPP/7zip/PropID.h305
-rw-r--r--CPP/7zip/Sha1.mak13
-rw-r--r--CPP/7zip/Sha256.mak13
-rw-r--r--CPP/7zip/SubBuild.mak6
-rw-r--r--CPP/7zip/UI/Agent/Agent.cpp1966
-rw-r--r--CPP/7zip/UI/Agent/Agent.h353
-rw-r--r--CPP/7zip/UI/Agent/AgentOut.cpp725
-rw-r--r--CPP/7zip/UI/Agent/AgentProxy.cpp752
-rw-r--r--CPP/7zip/UI/Agent/AgentProxy.h162
-rw-r--r--CPP/7zip/UI/Agent/ArchiveFolder.cpp51
-rw-r--r--CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp231
-rw-r--r--CPP/7zip/UI/Agent/ArchiveFolderOut.cpp386
-rw-r--r--CPP/7zip/UI/Agent/IFolderArchive.h107
-rw-r--r--CPP/7zip/UI/Agent/StdAfx.h11
-rw-r--r--CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp208
-rw-r--r--CPP/7zip/UI/Agent/UpdateCallbackAgent.h22
-rw-r--r--CPP/7zip/UI/Client7z/Client7z.cpp2115
-rw-r--r--CPP/7zip/UI/Client7z/Client7z.dsp562
-rw-r--r--CPP/7zip/UI/Client7z/Client7z.dsw58
-rw-r--r--CPP/7zip/UI/Client7z/StdAfx.cpp6
-rw-r--r--CPP/7zip/UI/Client7z/StdAfx.h19
-rw-r--r--CPP/7zip/UI/Client7z/makefile56
-rw-r--r--CPP/7zip/UI/Client7z/makefile.gcc69
-rw-r--r--CPP/7zip/UI/Client7z/resource.rc6
-rw-r--r--CPP/7zip/UI/Common/ArchiveCommandLine.cpp2995
-rw-r--r--CPP/7zip/UI/Common/ArchiveCommandLine.h296
-rw-r--r--CPP/7zip/UI/Common/ArchiveExtractCallback.cpp4307
-rw-r--r--CPP/7zip/UI/Common/ArchiveExtractCallback.h987
-rw-r--r--CPP/7zip/UI/Common/ArchiveName.cpp331
-rw-r--r--CPP/7zip/UI/Common/ArchiveName.h26
-rw-r--r--CPP/7zip/UI/Common/ArchiveOpenCallback.cpp554
-rw-r--r--CPP/7zip/UI/Common/ArchiveOpenCallback.h293
-rw-r--r--CPP/7zip/UI/Common/Bench.cpp8490
-rw-r--r--CPP/7zip/UI/Common/Bench.h198
-rw-r--r--CPP/7zip/UI/Common/CompressCall.cpp343
-rw-r--r--CPP/7zip/UI/Common/CompressCall.h28
-rw-r--r--CPP/7zip/UI/Common/CompressCall2.cpp327
-rw-r--r--CPP/7zip/UI/Common/DefaultName.cpp74
-rw-r--r--CPP/7zip/UI/Common/DefaultName.h22
-rw-r--r--CPP/7zip/UI/Common/DirItem.h594
-rw-r--r--CPP/7zip/UI/Common/EnumDirItems.cpp2752
-rw-r--r--CPP/7zip/UI/Common/EnumDirItems.h80
-rw-r--r--CPP/7zip/UI/Common/ExitCode.h54
-rw-r--r--CPP/7zip/UI/Common/Extract.cpp1052
-rw-r--r--CPP/7zip/UI/Common/Extract.h200
-rw-r--r--CPP/7zip/UI/Common/ExtractMode.h78
-rw-r--r--CPP/7zip/UI/Common/ExtractingFilePath.cpp576
-rw-r--r--CPP/7zip/UI/Common/ExtractingFilePath.h62
-rw-r--r--CPP/7zip/UI/Common/HashCalc.cpp2457
-rw-r--r--CPP/7zip/UI/Common/HashCalc.h438
-rw-r--r--CPP/7zip/UI/Common/IFileExtractCallback.h226
-rw-r--r--CPP/7zip/UI/Common/LoadCodecs.cpp2407
-rw-r--r--CPP/7zip/UI/Common/LoadCodecs.h906
-rw-r--r--CPP/7zip/UI/Common/OpenArchive.cpp7248
-rw-r--r--CPP/7zip/UI/Common/OpenArchive.h905
-rw-r--r--CPP/7zip/UI/Common/PropIDUtils.cpp1409
-rw-r--r--CPP/7zip/UI/Common/PropIDUtils.h36
-rw-r--r--CPP/7zip/UI/Common/Property.h28
-rw-r--r--CPP/7zip/UI/Common/SetProperties.cpp168
-rw-r--r--CPP/7zip/UI/Common/SetProperties.h20
-rw-r--r--CPP/7zip/UI/Common/SortUtils.cpp50
-rw-r--r--CPP/7zip/UI/Common/SortUtils.h20
-rw-r--r--CPP/7zip/UI/Common/StdAfx.h19
-rw-r--r--CPP/7zip/UI/Common/TempFiles.cpp38
-rw-r--r--CPP/7zip/UI/Common/TempFiles.h32
-rw-r--r--CPP/7zip/UI/Common/Update.cpp3561
-rw-r--r--CPP/7zip/UI/Common/Update.h418
-rw-r--r--CPP/7zip/UI/Common/UpdateAction.cpp128
-rw-r--r--CPP/7zip/UI/Common/UpdateAction.h132
-rw-r--r--CPP/7zip/UI/Common/UpdateCallback.cpp1797
-rw-r--r--CPP/7zip/UI/Common/UpdateCallback.h359
-rw-r--r--CPP/7zip/UI/Common/UpdatePair.cpp535
-rw-r--r--CPP/7zip/UI/Common/UpdatePair.h54
-rw-r--r--CPP/7zip/UI/Common/UpdateProduce.cpp142
-rw-r--r--CPP/7zip/UI/Common/UpdateProduce.h115
-rw-r--r--CPP/7zip/UI/Common/WorkDir.cpp180
-rw-r--r--CPP/7zip/UI/Common/WorkDir.h52
-rw-r--r--CPP/7zip/UI/Common/ZipRegistry.cpp580
-rw-r--r--CPP/7zip/UI/Common/ZipRegistry.h339
-rw-r--r--CPP/7zip/UI/Console/BenchCon.cpp82
-rw-r--r--CPP/7zip/UI/Console/BenchCon.h28
-rw-r--r--CPP/7zip/UI/Console/Console.dsp1040
-rw-r--r--CPP/7zip/UI/Console/Console.dsw29
-rw-r--r--CPP/7zip/UI/Console/Console.mak88
-rw-r--r--CPP/7zip/UI/Console/Console.manifest27
-rw-r--r--CPP/7zip/UI/Console/ConsoleClose.cpp169
-rw-r--r--CPP/7zip/UI/Console/ConsoleClose.h72
-rw-r--r--CPP/7zip/UI/Console/ExtractCallbackConsole.cpp1674
-rw-r--r--CPP/7zip/UI/Console/ExtractCallbackConsole.h345
-rw-r--r--CPP/7zip/UI/Console/HashCon.cpp793
-rw-r--r--CPP/7zip/UI/Console/HashCon.h106
-rw-r--r--CPP/7zip/UI/Console/List.cpp2749
-rw-r--r--CPP/7zip/UI/Console/List.h67
-rw-r--r--CPP/7zip/UI/Console/Main.cpp2730
-rw-r--r--CPP/7zip/UI/Console/MainAr.cpp402
-rw-r--r--CPP/7zip/UI/Console/OpenCallbackConsole.cpp230
-rw-r--r--CPP/7zip/UI/Console/OpenCallbackConsole.h134
-rw-r--r--CPP/7zip/UI/Console/PercentPrinter.cpp367
-rw-r--r--CPP/7zip/UI/Console/PercentPrinter.h124
-rw-r--r--CPP/7zip/UI/Console/StdAfx.cpp6
-rw-r--r--CPP/7zip/UI/Console/StdAfx.h19
-rw-r--r--CPP/7zip/UI/Console/UpdateCallbackConsole.cpp1587
-rw-r--r--CPP/7zip/UI/Console/UpdateCallbackConsole.h257
-rw-r--r--CPP/7zip/UI/Console/UserInputUtils.cpp227
-rw-r--r--CPP/7zip/UI/Console/UserInputUtils.h54
-rw-r--r--CPP/7zip/UI/Console/makefile132
-rw-r--r--CPP/7zip/UI/Console/makefile.gcc186
-rw-r--r--CPP/7zip/UI/Console/resource.rc14
-rw-r--r--CPP/7zip/UI/Explorer/7-zip.dll.manifest1
-rw-r--r--CPP/7zip/UI/Explorer/ContextMenu.cpp1822
-rw-r--r--CPP/7zip/UI/Explorer/ContextMenu.h167
-rw-r--r--CPP/7zip/UI/Explorer/ContextMenuFlags.h27
-rw-r--r--CPP/7zip/UI/Explorer/DllExportsExplorer.cpp264
-rw-r--r--CPP/7zip/UI/Explorer/Explorer.def9
-rw-r--r--CPP/7zip/UI/Explorer/Explorer.dsp612
-rw-r--r--CPP/7zip/UI/Explorer/Explorer.dsw29
-rw-r--r--CPP/7zip/UI/Explorer/MenuLogo.bmpbin0 -> 114 bytes
-rw-r--r--CPP/7zip/UI/Explorer/MyExplorerCommand.h217
-rw-r--r--CPP/7zip/UI/Explorer/MyMessages.cpp77
-rw-r--r--CPP/7zip/UI/Explorer/MyMessages.h32
-rw-r--r--CPP/7zip/UI/Explorer/RegistryContextMenu.cpp227
-rw-r--r--CPP/7zip/UI/Explorer/RegistryContextMenu.h13
-rw-r--r--CPP/7zip/UI/Explorer/StdAfx.cpp3
-rw-r--r--CPP/7zip/UI/Explorer/StdAfx.h6
-rw-r--r--CPP/7zip/UI/Explorer/makefile76
-rw-r--r--CPP/7zip/UI/Explorer/resource.h15
-rw-r--r--CPP/7zip/UI/Explorer/resource.rc10
-rw-r--r--CPP/7zip/UI/Explorer/resource2.rc19
-rw-r--r--CPP/7zip/UI/Far/ExtractEngine.cpp274
-rw-r--r--CPP/7zip/UI/Far/ExtractEngine.h43
-rw-r--r--CPP/7zip/UI/Far/Far.cpp587
-rw-r--r--CPP/7zip/UI/Far/Far.def35
-rw-r--r--CPP/7zip/UI/Far/Far.dsp831
-rw-r--r--CPP/7zip/UI/Far/Far.dsw29
-rw-r--r--CPP/7zip/UI/Far/FarPlugin.h560
-rw-r--r--CPP/7zip/UI/Far/FarUtils.cpp524
-rw-r--r--CPP/7zip/UI/Far/FarUtils.h203
-rw-r--r--CPP/7zip/UI/Far/Messages.h136
-rw-r--r--CPP/7zip/UI/Far/OverwriteDialogFar.cpp145
-rw-r--r--CPP/7zip/UI/Far/OverwriteDialogFar.h37
-rw-r--r--CPP/7zip/UI/Far/Plugin.cpp939
-rw-r--r--CPP/7zip/UI/Far/Plugin.h94
-rw-r--r--CPP/7zip/UI/Far/PluginCommon.cpp50
-rw-r--r--CPP/7zip/UI/Far/PluginDelete.cpp144
-rw-r--r--CPP/7zip/UI/Far/PluginRead.cpp301
-rw-r--r--CPP/7zip/UI/Far/PluginWrite.cpp839
-rw-r--r--CPP/7zip/UI/Far/ProgressBox.cpp305
-rw-r--r--CPP/7zip/UI/Far/ProgressBox.h83
-rw-r--r--CPP/7zip/UI/Far/StdAfx.cpp3
-rw-r--r--CPP/7zip/UI/Far/StdAfx.h11
-rw-r--r--CPP/7zip/UI/Far/UpdateCallbackFar.cpp237
-rw-r--r--CPP/7zip/UI/Far/UpdateCallbackFar.h44
-rw-r--r--CPP/7zip/UI/Far/makefile106
-rw-r--r--CPP/7zip/UI/Far/resource.rc3
-rw-r--r--CPP/7zip/UI/FileManager/7zFM.exe.manifest23
-rw-r--r--CPP/7zip/UI/FileManager/7zipLogo.icobin0 -> 9150 bytes
-rw-r--r--CPP/7zip/UI/FileManager/AboutDialog.cpp81
-rw-r--r--CPP/7zip/UI/FileManager/AboutDialog.h19
-rw-r--r--CPP/7zip/UI/FileManager/AboutDialog.rc26
-rw-r--r--CPP/7zip/UI/FileManager/AboutDialogRes.h8
-rw-r--r--CPP/7zip/UI/FileManager/Add.bmpbin0 -> 982 bytes
-rw-r--r--CPP/7zip/UI/FileManager/Add2.bmpbin0 -> 406 bytes
-rw-r--r--CPP/7zip/UI/FileManager/AltStreamsFolder.cpp952
-rw-r--r--CPP/7zip/UI/FileManager/AltStreamsFolder.h92
-rw-r--r--CPP/7zip/UI/FileManager/App.cpp998
-rw-r--r--CPP/7zip/UI/FileManager/App.h306
-rw-r--r--CPP/7zip/UI/FileManager/AppState.h95
-rw-r--r--CPP/7zip/UI/FileManager/BrowseDialog.cpp2113
-rw-r--r--CPP/7zip/UI/FileManager/BrowseDialog.h53
-rw-r--r--CPP/7zip/UI/FileManager/BrowseDialog.rc25
-rw-r--r--CPP/7zip/UI/FileManager/BrowseDialogRes.h18
-rw-r--r--CPP/7zip/UI/FileManager/ClassDefs.cpp12
-rw-r--r--CPP/7zip/UI/FileManager/ComboDialog.cpp128
-rw-r--r--CPP/7zip/UI/FileManager/ComboDialog.h56
-rw-r--r--CPP/7zip/UI/FileManager/ComboDialog.rc16
-rw-r--r--CPP/7zip/UI/FileManager/ComboDialogRes.h8
-rw-r--r--CPP/7zip/UI/FileManager/Copy.bmpbin0 -> 982 bytes
-rw-r--r--CPP/7zip/UI/FileManager/Copy2.bmpbin0 -> 406 bytes
-rw-r--r--CPP/7zip/UI/FileManager/CopyDialog.cpp103
-rw-r--r--CPP/7zip/UI/FileManager/CopyDialog.h31
-rw-r--r--CPP/7zip/UI/FileManager/CopyDialog.rc20
-rw-r--r--CPP/7zip/UI/FileManager/CopyDialogRes.h8
-rw-r--r--CPP/7zip/UI/FileManager/Delete.bmpbin0 -> 982 bytes
-rw-r--r--CPP/7zip/UI/FileManager/Delete2.bmpbin0 -> 406 bytes
-rw-r--r--CPP/7zip/UI/FileManager/DialogSize.h32
-rw-r--r--CPP/7zip/UI/FileManager/EditDialog.cpp57
-rw-r--r--CPP/7zip/UI/FileManager/EditDialog.h25
-rw-r--r--CPP/7zip/UI/FileManager/EditDialog.rc15
-rw-r--r--CPP/7zip/UI/FileManager/EditDialogRes.h2
-rw-r--r--CPP/7zip/UI/FileManager/EditPage.cpp159
-rw-r--r--CPP/7zip/UI/FileManager/EditPage.h30
-rw-r--r--CPP/7zip/UI/FileManager/EditPage.rc19
-rw-r--r--CPP/7zip/UI/FileManager/EditPage2.rc14
-rw-r--r--CPP/7zip/UI/FileManager/EditPageRes.h15
-rw-r--r--CPP/7zip/UI/FileManager/EnumFormatEtc.cpp107
-rw-r--r--CPP/7zip/UI/FileManager/EnumFormatEtc.h10
-rw-r--r--CPP/7zip/UI/FileManager/Extract.bmpbin0 -> 982 bytes
-rw-r--r--CPP/7zip/UI/FileManager/Extract2.bmpbin0 -> 406 bytes
-rw-r--r--CPP/7zip/UI/FileManager/ExtractCallback.cpp2093
-rw-r--r--CPP/7zip/UI/FileManager/ExtractCallback.h638
-rw-r--r--CPP/7zip/UI/FileManager/FM.cpp1116
-rw-r--r--CPP/7zip/UI/FileManager/FM.dsp1667
-rw-r--r--CPP/7zip/UI/FileManager/FM.dsw29
-rw-r--r--CPP/7zip/UI/FileManager/FM.icobin0 -> 4846 bytes
-rw-r--r--CPP/7zip/UI/FileManager/FM.mak100
-rw-r--r--CPP/7zip/UI/FileManager/FSDrives.cpp518
-rw-r--r--CPP/7zip/UI/FileManager/FSDrives.h52
-rw-r--r--CPP/7zip/UI/FileManager/FSFolder.cpp1200
-rw-r--r--CPP/7zip/UI/FileManager/FSFolder.h221
-rw-r--r--CPP/7zip/UI/FileManager/FSFolderCopy.cpp810
-rw-r--r--CPP/7zip/UI/FileManager/FileFolderPluginOpen.cpp394
-rw-r--r--CPP/7zip/UI/FileManager/FileFolderPluginOpen.h27
-rw-r--r--CPP/7zip/UI/FileManager/FilePlugins.cpp78
-rw-r--r--CPP/7zip/UI/FileManager/FilePlugins.h33
-rw-r--r--CPP/7zip/UI/FileManager/FoldersPage.cpp172
-rw-r--r--CPP/7zip/UI/FileManager/FoldersPage.h32
-rw-r--r--CPP/7zip/UI/FileManager/FoldersPage.rc23
-rw-r--r--CPP/7zip/UI/FileManager/FoldersPage2.rc16
-rw-r--r--CPP/7zip/UI/FileManager/FoldersPageRes.h12
-rw-r--r--CPP/7zip/UI/FileManager/FormatUtils.cpp56
-rw-r--r--CPP/7zip/UI/FileManager/FormatUtils.h28
-rw-r--r--CPP/7zip/UI/FileManager/HelpUtils.cpp78
-rw-r--r--CPP/7zip/UI/FileManager/HelpUtils.h10
-rw-r--r--CPP/7zip/UI/FileManager/IFolder.h187
-rw-r--r--CPP/7zip/UI/FileManager/Info.bmpbin0 -> 982 bytes
-rw-r--r--CPP/7zip/UI/FileManager/Info2.bmpbin0 -> 406 bytes
-rw-r--r--CPP/7zip/UI/FileManager/LangPage.cpp361
-rw-r--r--CPP/7zip/UI/FileManager/LangPage.h36
-rw-r--r--CPP/7zip/UI/FileManager/LangPage.rc40
-rw-r--r--CPP/7zip/UI/FileManager/LangPageRes.h9
-rw-r--r--CPP/7zip/UI/FileManager/LangUtils.cpp326
-rw-r--r--CPP/7zip/UI/FileManager/LangUtils.h88
-rw-r--r--CPP/7zip/UI/FileManager/LinkDialog.cpp400
-rw-r--r--CPP/7zip/UI/FileManager/LinkDialog.h34
-rw-r--r--CPP/7zip/UI/FileManager/LinkDialog.rc38
-rw-r--r--CPP/7zip/UI/FileManager/LinkDialogRes.h22
-rw-r--r--CPP/7zip/UI/FileManager/ListViewDialog.cpp321
-rw-r--r--CPP/7zip/UI/FileManager/ListViewDialog.h46
-rw-r--r--CPP/7zip/UI/FileManager/ListViewDialog.rc14
-rw-r--r--CPP/7zip/UI/FileManager/ListViewDialogRes.h2
-rw-r--r--CPP/7zip/UI/FileManager/MenuPage.cpp440
-rw-r--r--CPP/7zip/UI/FileManager/MenuPage.h57
-rw-r--r--CPP/7zip/UI/FileManager/MenuPage.rc24
-rw-r--r--CPP/7zip/UI/FileManager/MenuPage2.rc28
-rw-r--r--CPP/7zip/UI/FileManager/MenuPageRes.h15
-rw-r--r--CPP/7zip/UI/FileManager/MessagesDialog.cpp76
-rw-r--r--CPP/7zip/UI/FileManager/MessagesDialog.h25
-rw-r--r--CPP/7zip/UI/FileManager/MessagesDialog.rc14
-rw-r--r--CPP/7zip/UI/FileManager/MessagesDialogRes.h3
-rw-r--r--CPP/7zip/UI/FileManager/Move.bmpbin0 -> 982 bytes
-rw-r--r--CPP/7zip/UI/FileManager/Move2.bmpbin0 -> 406 bytes
-rw-r--r--CPP/7zip/UI/FileManager/MyCom2.h55
-rw-r--r--CPP/7zip/UI/FileManager/MyLoadMenu.cpp918
-rw-r--r--CPP/7zip/UI/FileManager/MyLoadMenu.h40
-rw-r--r--CPP/7zip/UI/FileManager/MyWindowsNew.h195
-rw-r--r--CPP/7zip/UI/FileManager/NetFolder.cpp281
-rw-r--r--CPP/7zip/UI/FileManager/NetFolder.h36
-rw-r--r--CPP/7zip/UI/FileManager/OpenCallback.cpp86
-rw-r--r--CPP/7zip/UI/FileManager/OpenCallback.h69
-rw-r--r--CPP/7zip/UI/FileManager/OptionsDialog.cpp89
-rw-r--r--CPP/7zip/UI/FileManager/OverwriteDialog.cpp260
-rw-r--r--CPP/7zip/UI/FileManager/OverwriteDialog.h148
-rw-r--r--CPP/7zip/UI/FileManager/OverwriteDialog.rc182
-rw-r--r--CPP/7zip/UI/FileManager/OverwriteDialogRes.h34
-rw-r--r--CPP/7zip/UI/FileManager/Panel.cpp1182
-rw-r--r--CPP/7zip/UI/FileManager/Panel.h1016
-rw-r--r--CPP/7zip/UI/FileManager/PanelCopy.cpp435
-rw-r--r--CPP/7zip/UI/FileManager/PanelCrc.cpp422
-rw-r--r--CPP/7zip/UI/FileManager/PanelDrag.cpp3006
-rw-r--r--CPP/7zip/UI/FileManager/PanelFolderChange.cpp913
-rw-r--r--CPP/7zip/UI/FileManager/PanelItemOpen.cpp1869
-rw-r--r--CPP/7zip/UI/FileManager/PanelItems.cpp1391
-rw-r--r--CPP/7zip/UI/FileManager/PanelKey.cpp357
-rw-r--r--CPP/7zip/UI/FileManager/PanelListNotify.cpp870
-rw-r--r--CPP/7zip/UI/FileManager/PanelMenu.cpp1176
-rw-r--r--CPP/7zip/UI/FileManager/PanelOperations.cpp528
-rw-r--r--CPP/7zip/UI/FileManager/PanelSelect.cpp317
-rw-r--r--CPP/7zip/UI/FileManager/PanelSort.cpp269
-rw-r--r--CPP/7zip/UI/FileManager/PanelSplitFile.cpp562
-rw-r--r--CPP/7zip/UI/FileManager/PasswordDialog.cpp116
-rw-r--r--CPP/7zip/UI/FileManager/PasswordDialog.h56
-rw-r--r--CPP/7zip/UI/FileManager/PasswordDialog.rc28
-rw-r--r--CPP/7zip/UI/FileManager/PasswordDialogRes.h10
-rw-r--r--CPP/7zip/UI/FileManager/PluginInterface.h32
-rw-r--r--CPP/7zip/UI/FileManager/PluginLoader.h31
-rw-r--r--CPP/7zip/UI/FileManager/ProgramLocation.cpp3
-rw-r--r--CPP/7zip/UI/FileManager/ProgramLocation.h6
-rw-r--r--CPP/7zip/UI/FileManager/ProgressDialog.cpp397
-rw-r--r--CPP/7zip/UI/FileManager/ProgressDialog.h341
-rw-r--r--CPP/7zip/UI/FileManager/ProgressDialog.rc24
-rw-r--r--CPP/7zip/UI/FileManager/ProgressDialog2.cpp2804
-rw-r--r--CPP/7zip/UI/FileManager/ProgressDialog2.h709
-rw-r--r--CPP/7zip/UI/FileManager/ProgressDialog2.rc80
-rw-r--r--CPP/7zip/UI/FileManager/ProgressDialog2Res.h97
-rw-r--r--CPP/7zip/UI/FileManager/ProgressDialog2a.rc165
-rw-r--r--CPP/7zip/UI/FileManager/ProgressDialogRes.h6
-rw-r--r--CPP/7zip/UI/FileManager/PropertyName.cpp46
-rw-r--r--CPP/7zip/UI/FileManager/PropertyName.h20
-rw-r--r--CPP/7zip/UI/FileManager/PropertyName.rc109
-rw-r--r--CPP/7zip/UI/FileManager/PropertyNameRes.h199
-rw-r--r--CPP/7zip/UI/FileManager/RegistryAssociations.cpp167
-rw-r--r--CPP/7zip/UI/FileManager/RegistryAssociations.h31
-rw-r--r--CPP/7zip/UI/FileManager/RegistryPlugins.cpp145
-rw-r--r--CPP/7zip/UI/FileManager/RegistryPlugins.h29
-rw-r--r--CPP/7zip/UI/FileManager/RegistryUtils.cpp196
-rw-r--r--CPP/7zip/UI/FileManager/RegistryUtils.h50
-rw-r--r--CPP/7zip/UI/FileManager/RootFolder.cpp326
-rw-r--r--CPP/7zip/UI/FileManager/RootFolder.h24
-rw-r--r--CPP/7zip/UI/FileManager/SettingsPage.cpp354
-rw-r--r--CPP/7zip/UI/FileManager/SettingsPage.h33
-rw-r--r--CPP/7zip/UI/FileManager/SettingsPage.rc22
-rw-r--r--CPP/7zip/UI/FileManager/SettingsPage2.rc19
-rw-r--r--CPP/7zip/UI/FileManager/SettingsPageRes.h17
-rw-r--r--CPP/7zip/UI/FileManager/SplitDialog.cpp114
-rw-r--r--CPP/7zip/UI/FileManager/SplitDialog.h28
-rw-r--r--CPP/7zip/UI/FileManager/SplitDialog.rc16
-rw-r--r--CPP/7zip/UI/FileManager/SplitDialogRes.h8
-rw-r--r--CPP/7zip/UI/FileManager/SplitUtils.cpp96
-rw-r--r--CPP/7zip/UI/FileManager/SplitUtils.h15
-rw-r--r--CPP/7zip/UI/FileManager/StdAfx.cpp3
-rw-r--r--CPP/7zip/UI/FileManager/StdAfx.h83
-rw-r--r--CPP/7zip/UI/FileManager/StringUtils.cpp39
-rw-r--r--CPP/7zip/UI/FileManager/StringUtils.h11
-rw-r--r--CPP/7zip/UI/FileManager/SysIconUtils.cpp533
-rw-r--r--CPP/7zip/UI/FileManager/SysIconUtils.h117
-rw-r--r--CPP/7zip/UI/FileManager/SystemPage.cpp472
-rw-r--r--CPP/7zip/UI/FileManager/SystemPage.h126
-rw-r--r--CPP/7zip/UI/FileManager/SystemPage.rc43
-rw-r--r--CPP/7zip/UI/FileManager/SystemPageRes.h9
-rw-r--r--CPP/7zip/UI/FileManager/Test.bmpbin0 -> 982 bytes
-rw-r--r--CPP/7zip/UI/FileManager/Test2.bmpbin0 -> 406 bytes
-rw-r--r--CPP/7zip/UI/FileManager/TextPairs.cpp193
-rw-r--r--CPP/7zip/UI/FileManager/TextPairs.h32
-rw-r--r--CPP/7zip/UI/FileManager/UpdateCallback100.cpp124
-rw-r--r--CPP/7zip/UI/FileManager/UpdateCallback100.h46
-rw-r--r--CPP/7zip/UI/FileManager/VerCtrl.cpp428
-rw-r--r--CPP/7zip/UI/FileManager/ViewSettings.cpp314
-rw-r--r--CPP/7zip/UI/FileManager/ViewSettings.h115
-rw-r--r--CPP/7zip/UI/FileManager/makefile108
-rw-r--r--CPP/7zip/UI/FileManager/resource.h369
-rw-r--r--CPP/7zip/UI/FileManager/resource.rc286
-rw-r--r--CPP/7zip/UI/FileManager/resourceGui.h30
-rw-r--r--CPP/7zip/UI/FileManager/resourceGui.rc19
-rw-r--r--CPP/7zip/UI/GUI/7zG.exe.manifest23
-rw-r--r--CPP/7zip/UI/GUI/BenchmarkDialog.cpp1920
-rw-r--r--CPP/7zip/UI/GUI/BenchmarkDialog.h15
-rw-r--r--CPP/7zip/UI/GUI/BenchmarkDialog.rc288
-rw-r--r--CPP/7zip/UI/GUI/BenchmarkDialogRes.h79
-rw-r--r--CPP/7zip/UI/GUI/CompressDialog.cpp3820
-rw-r--r--CPP/7zip/UI/GUI/CompressDialog.h481
-rw-r--r--CPP/7zip/UI/GUI/CompressDialog.rc231
-rw-r--r--CPP/7zip/UI/GUI/CompressDialogRes.h123
-rw-r--r--CPP/7zip/UI/GUI/CompressOptionsDialog.rc76
-rw-r--r--CPP/7zip/UI/GUI/Extract.rc118
-rw-r--r--CPP/7zip/UI/GUI/ExtractDialog.cpp839
-rw-r--r--CPP/7zip/UI/GUI/ExtractDialog.h226
-rw-r--r--CPP/7zip/UI/GUI/ExtractDialog.rc196
-rw-r--r--CPP/7zip/UI/GUI/ExtractDialogRes.h48
-rw-r--r--CPP/7zip/UI/GUI/ExtractGUI.cpp577
-rw-r--r--CPP/7zip/UI/GUI/ExtractGUI.h77
-rw-r--r--CPP/7zip/UI/GUI/ExtractRes.h102
-rw-r--r--CPP/7zip/UI/GUI/FM.icobin0 -> 4846 bytes
-rw-r--r--CPP/7zip/UI/GUI/GUI.cpp478
-rw-r--r--CPP/7zip/UI/GUI/GUI.dsp1259
-rw-r--r--CPP/7zip/UI/GUI/GUI.dsw29
-rw-r--r--CPP/7zip/UI/GUI/HashGUI.cpp363
-rw-r--r--CPP/7zip/UI/GUI/HashGUI.h54
-rw-r--r--CPP/7zip/UI/GUI/StdAfx.cpp3
-rw-r--r--CPP/7zip/UI/GUI/StdAfx.h6
-rw-r--r--CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp280
-rw-r--r--CPP/7zip/UI/GUI/UpdateCallbackGUI.h31
-rw-r--r--CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp59
-rw-r--r--CPP/7zip/UI/GUI/UpdateCallbackGUI2.h34
-rw-r--r--CPP/7zip/UI/GUI/UpdateGUI.cpp605
-rw-r--r--CPP/7zip/UI/GUI/UpdateGUI.h33
-rw-r--r--CPP/7zip/UI/GUI/makefile148
-rw-r--r--CPP/7zip/UI/GUI/resource.rc25
-rw-r--r--CPP/7zip/UI/GUI/resource2.h4
-rw-r--r--CPP/7zip/UI/GUI/resource2.rc10
-rw-r--r--CPP/7zip/UI/GUI/resource3.h10
-rw-r--r--CPP/7zip/UI/GUI/resource3.rc15
-rw-r--r--CPP/7zip/UI/makefile12
-rw-r--r--CPP/7zip/cmpl_clang.mak3
-rw-r--r--CPP/7zip/cmpl_clang_arm64.mak3
-rw-r--r--CPP/7zip/cmpl_clang_x64.mak3
-rw-r--r--CPP/7zip/cmpl_clang_x86.mak3
-rw-r--r--CPP/7zip/cmpl_gcc.mak3
-rw-r--r--CPP/7zip/cmpl_gcc_arm64.mak3
-rw-r--r--CPP/7zip/cmpl_gcc_x64.mak3
-rw-r--r--CPP/7zip/cmpl_gcc_x86.mak3
-rw-r--r--CPP/7zip/cmpl_mac_arm64.mak3
-rw-r--r--CPP/7zip/cmpl_mac_x64.mak3
-rw-r--r--CPP/7zip/makefile10
-rw-r--r--CPP/7zip/var_clang.mak11
-rw-r--r--CPP/7zip/var_clang_arm64.mak11
-rw-r--r--CPP/7zip/var_clang_x64.mak12
-rw-r--r--CPP/7zip/var_clang_x86.mak12
-rw-r--r--CPP/7zip/var_gcc.mak12
-rw-r--r--CPP/7zip/var_gcc_arm64.mak12
-rw-r--r--CPP/7zip/var_gcc_x64.mak10
-rw-r--r--CPP/7zip/var_gcc_x86.mak11
-rw-r--r--CPP/7zip/var_mac_arm64.mak11
-rw-r--r--CPP/7zip/var_mac_x64.mak11
-rw-r--r--CPP/7zip/warn_clang.mak3
-rw-r--r--CPP/7zip/warn_clang_mac.mak9
-rw-r--r--CPP/7zip/warn_gcc.mak45
-rw-r--r--CPP/Build.mak385
-rw-r--r--CPP/Common/AutoPtr.h70
-rw-r--r--CPP/Common/CRC.cpp14
-rw-r--r--CPP/Common/C_FileIO.cpp95
-rw-r--r--CPP/Common/C_FileIO.h59
-rw-r--r--CPP/Common/CksumReg.cpp55
-rw-r--r--CPP/Common/ComTry.h42
-rw-r--r--CPP/Common/CommandLineParser.cpp394
-rw-r--r--CPP/Common/CommandLineParser.h126
-rw-r--r--CPP/Common/Common.h356
-rw-r--r--CPP/Common/CrcReg.cpp190
-rw-r--r--CPP/Common/Defs.h31
-rw-r--r--CPP/Common/DynLimBuf.cpp93
-rw-r--r--CPP/Common/DynLimBuf.h41
-rw-r--r--CPP/Common/DynamicBuffer.h132
-rw-r--r--CPP/Common/IntToString.cpp385
-rw-r--r--CPP/Common/IntToString.h58
-rw-r--r--CPP/Common/Lang.cpp173
-rw-r--r--CPP/Common/Lang.h53
-rw-r--r--CPP/Common/ListFileUtils.cpp282
-rw-r--r--CPP/Common/ListFileUtils.h36
-rw-r--r--CPP/Common/LzFindPrepare.cpp7
-rw-r--r--CPP/Common/MyBuffer.h545
-rw-r--r--CPP/Common/MyBuffer2.h264
-rw-r--r--CPP/Common/MyCom.h786
-rw-r--r--CPP/Common/MyException.h28
-rw-r--r--CPP/Common/MyGuidDef.h117
-rw-r--r--CPP/Common/MyInitGuid.h102
-rw-r--r--CPP/Common/MyLinux.h117
-rw-r--r--CPP/Common/MyMap.cpp140
-rw-r--r--CPP/Common/MyMap.h28
-rw-r--r--CPP/Common/MyString.cpp3518
-rw-r--r--CPP/Common/MyString.h1932
-rw-r--r--CPP/Common/MyTypes.h72
-rw-r--r--CPP/Common/MyUnknown.h25
-rw-r--r--CPP/Common/MyVector.cpp6
-rw-r--r--CPP/Common/MyVector.h1344
-rw-r--r--CPP/Common/MyWindows.cpp437
-rw-r--r--CPP/Common/MyWindows.h555
-rw-r--r--CPP/Common/MyXml.cpp260
-rw-r--r--CPP/Common/MyXml.h43
-rw-r--r--CPP/Common/NewHandler.cpp461
-rw-r--r--CPP/Common/NewHandler.h186
-rw-r--r--CPP/Common/Random.cpp28
-rw-r--r--CPP/Common/Random.h14
-rw-r--r--CPP/Common/Sha1Prepare.cpp7
-rw-r--r--CPP/Common/Sha1Reg.cpp67
-rw-r--r--CPP/Common/Sha256Prepare.cpp7
-rw-r--r--CPP/Common/Sha256Reg.cpp107
-rw-r--r--CPP/Common/StdAfx.h16
-rw-r--r--CPP/Common/StdInStream.cpp187
-rw-r--r--CPP/Common/StdInStream.h84
-rw-r--r--CPP/Common/StdOutStream.cpp323
-rw-r--r--CPP/Common/StdOutStream.h149
-rw-r--r--CPP/Common/StringConvert.cpp1075
-rw-r--r--CPP/Common/StringConvert.h198
-rw-r--r--CPP/Common/StringToInt.cpp315
-rw-r--r--CPP/Common/StringToInt.h43
-rw-r--r--CPP/Common/TextConfig.cpp248
-rw-r--r--CPP/Common/TextConfig.h38
-rw-r--r--CPP/Common/UTFConvert.cpp1151
-rw-r--r--CPP/Common/UTFConvert.h396
-rw-r--r--CPP/Common/Wildcard.cpp1464
-rw-r--r--CPP/Common/Wildcard.h380
-rw-r--r--CPP/Common/XzCrc64Init.cpp14
-rw-r--r--CPP/Common/XzCrc64Reg.cpp81
-rw-r--r--CPP/Windows/COM.cpp41
-rw-r--r--CPP/Windows/COM.h156
-rw-r--r--CPP/Windows/Clipboard.cpp130
-rw-r--r--CPP/Windows/Clipboard.h28
-rw-r--r--CPP/Windows/CommonDialog.cpp454
-rw-r--r--CPP/Windows/CommonDialog.h66
-rw-r--r--CPP/Windows/Console.cpp10
-rw-r--r--CPP/Windows/Console.h52
-rw-r--r--CPP/Windows/Control/ComboBox.cpp132
-rw-r--r--CPP/Windows/Control/ComboBox.h142
-rw-r--r--CPP/Windows/Control/CommandBar.h104
-rw-r--r--CPP/Windows/Control/Dialog.cpp696
-rw-r--r--CPP/Windows/Control/Dialog.h364
-rw-r--r--CPP/Windows/Control/Edit.h38
-rw-r--r--CPP/Windows/Control/ImageList.cpp20
-rw-r--r--CPP/Windows/Control/ImageList.h174
-rw-r--r--CPP/Windows/Control/ListView.cpp317
-rw-r--r--CPP/Windows/Control/ListView.h302
-rw-r--r--CPP/Windows/Control/ProgressBar.h70
-rw-r--r--CPP/Windows/Control/PropertyPage.cpp308
-rw-r--r--CPP/Windows/Control/PropertyPage.h100
-rw-r--r--CPP/Windows/Control/ReBar.h68
-rw-r--r--CPP/Windows/Control/Static.h56
-rw-r--r--CPP/Windows/Control/StatusBar.h84
-rw-r--r--CPP/Windows/Control/StdAfx.h19
-rw-r--r--CPP/Windows/Control/ToolBar.h86
-rw-r--r--CPP/Windows/Control/Trackbar.h54
-rw-r--r--CPP/Windows/Control/Window2.cpp402
-rw-r--r--CPP/Windows/Control/Window2.h104
-rw-r--r--CPP/Windows/DLL.cpp288
-rw-r--r--CPP/Windows/DLL.h161
-rw-r--r--CPP/Windows/Defs.h34
-rw-r--r--CPP/Windows/ErrorMsg.cpp199
-rw-r--r--CPP/Windows/ErrorMsg.h31
-rw-r--r--CPP/Windows/FileDir.cpp1943
-rw-r--r--CPP/Windows/FileDir.h252
-rw-r--r--CPP/Windows/FileFind.cpp2078
-rw-r--r--CPP/Windows/FileFind.h509
-rw-r--r--CPP/Windows/FileIO.cpp1337
-rw-r--r--CPP/Windows/FileIO.h602
-rw-r--r--CPP/Windows/FileLink.cpp1062
-rw-r--r--CPP/Windows/FileMapping.cpp24
-rw-r--r--CPP/Windows/FileMapping.h132
-rw-r--r--CPP/Windows/FileName.cpp1733
-rw-r--r--CPP/Windows/FileName.h248
-rw-r--r--CPP/Windows/FileSystem.cpp270
-rw-r--r--CPP/Windows/FileSystem.h58
-rw-r--r--CPP/Windows/Handle.h76
-rw-r--r--CPP/Windows/MemoryGlobal.cpp36
-rw-r--r--CPP/Windows/MemoryGlobal.h55
-rw-r--r--CPP/Windows/MemoryLock.cpp236
-rw-r--r--CPP/Windows/MemoryLock.h80
-rw-r--r--CPP/Windows/Menu.cpp265
-rw-r--r--CPP/Windows/Menu.h170
-rw-r--r--CPP/Windows/NationalTime.cpp37
-rw-r--r--CPP/Windows/NationalTime.h20
-rw-r--r--CPP/Windows/Net.cpp398
-rw-r--r--CPP/Windows/Net.h87
-rw-r--r--CPP/Windows/NtCheck.h104
-rw-r--r--CPP/Windows/ProcessMessages.cpp22
-rw-r--r--CPP/Windows/ProcessMessages.h12
-rw-r--r--CPP/Windows/ProcessUtils.cpp102
-rw-r--r--CPP/Windows/ProcessUtils.h138
-rw-r--r--CPP/Windows/PropVariant.cpp738
-rw-r--r--CPP/Windows/PropVariant.h287
-rw-r--r--CPP/Windows/PropVariantConv.cpp328
-rw-r--r--CPP/Windows/PropVariantConv.h77
-rw-r--r--CPP/Windows/PropVariantUtils.cpp161
-rw-r--r--CPP/Windows/PropVariantUtils.h34
-rw-r--r--CPP/Windows/Registry.cpp796
-rw-r--r--CPP/Windows/Registry.h168
-rw-r--r--CPP/Windows/ResourceString.cpp206
-rw-r--r--CPP/Windows/ResourceString.h33
-rw-r--r--CPP/Windows/SecurityUtils.cpp367
-rw-r--r--CPP/Windows/SecurityUtils.h315
-rw-r--r--CPP/Windows/Shell.cpp1179
-rw-r--r--CPP/Windows/Shell.h224
-rw-r--r--CPP/Windows/StdAfx.h20
-rw-r--r--CPP/Windows/Synchronization.cpp97
-rw-r--r--CPP/Windows/Synchronization.h545
-rw-r--r--CPP/Windows/System.cpp420
-rw-r--r--CPP/Windows/System.h172
-rw-r--r--CPP/Windows/SystemInfo.cpp1022
-rw-r--r--CPP/Windows/SystemInfo.h19
-rw-r--r--CPP/Windows/Thread.h82
-rw-r--r--CPP/Windows/TimeUtils.cpp617
-rw-r--r--CPP/Windows/TimeUtils.h178
-rw-r--r--CPP/Windows/Window.cpp358
-rw-r--r--CPP/Windows/Window.h647
-rw-r--r--CS/7zip/Common/CRC.cs55
-rw-r--r--CS/7zip/Common/CommandLineParser.cs274
-rw-r--r--CS/7zip/Common/InBuffer.cs72
-rw-r--r--CS/7zip/Common/OutBuffer.cs47
-rw-r--r--CS/7zip/Compress/LZ/IMatchFinder.cs24
-rw-r--r--CS/7zip/Compress/LZ/LzBinTree.cs367
-rw-r--r--CS/7zip/Compress/LZ/LzInWindow.cs132
-rw-r--r--CS/7zip/Compress/LZ/LzOutWindow.cs110
-rw-r--r--CS/7zip/Compress/LZMA/LzmaBase.cs76
-rw-r--r--CS/7zip/Compress/LZMA/LzmaDecoder.cs398
-rw-r--r--CS/7zip/Compress/LZMA/LzmaEncoder.cs1480
-rw-r--r--CS/7zip/Compress/LzmaAlone/LzmaAlone.cs364
-rw-r--r--CS/7zip/Compress/LzmaAlone/LzmaAlone.csproj90
-rw-r--r--CS/7zip/Compress/LzmaAlone/LzmaAlone.sln20
-rw-r--r--CS/7zip/Compress/LzmaAlone/LzmaBench.cs340
-rw-r--r--CS/7zip/Compress/LzmaAlone/Properties/AssemblyInfo.cs29
-rw-r--r--CS/7zip/Compress/LzmaAlone/Properties/Resources.cs70
-rw-r--r--CS/7zip/Compress/LzmaAlone/Properties/Settings.cs42
-rw-r--r--CS/7zip/Compress/RangeCoder/RangeCoder.cs234
-rw-r--r--CS/7zip/Compress/RangeCoder/RangeCoderBit.cs117
-rw-r--r--CS/7zip/Compress/RangeCoder/RangeCoderBitTree.cs157
-rw-r--r--CS/7zip/ICoder.cs157
-rw-r--r--DOC/7zC.txt374
-rw-r--r--DOC/7zFormat.txt938
-rw-r--r--DOC/7zip.hhp83
-rw-r--r--DOC/7zip.wxs403
-rw-r--r--DOC/License.txt90
-rw-r--r--DOC/Methods.txt349
-rw-r--r--DOC/copying.txt502
-rw-r--r--DOC/installer.txt166
-rw-r--r--DOC/lzma-history.txt446
-rw-r--r--DOC/lzma-sdk.txt357
-rw-r--r--DOC/lzma-specification.txt1176
-rw-r--r--DOC/lzma.txt673
-rw-r--r--DOC/readme.txt273
-rw-r--r--DOC/src-history.txt709
-rw-r--r--DOC/unRarLicense.txt41
-rw-r--r--Java/SevenZip/CRC.java52
-rw-r--r--Java/SevenZip/Compression/LZ/BinTree.java382
-rw-r--r--Java/SevenZip/Compression/LZ/InWindow.java131
-rw-r--r--Java/SevenZip/Compression/LZ/OutWindow.java85
-rw-r--r--Java/SevenZip/Compression/LZMA/Base.java88
-rw-r--r--Java/SevenZip/Compression/LZMA/Decoder.java329
-rw-r--r--Java/SevenZip/Compression/LZMA/Encoder.java1416
-rw-r--r--Java/SevenZip/Compression/RangeCoder/BitTreeDecoder.java55
-rw-r--r--Java/SevenZip/Compression/RangeCoder/BitTreeEncoder.java99
-rw-r--r--Java/SevenZip/Compression/RangeCoder/Decoder.java88
-rw-r--r--Java/SevenZip/Compression/RangeCoder/Encoder.java151
-rw-r--r--Java/SevenZip/ICodeProgress.java6
-rw-r--r--Java/SevenZip/LzmaAlone.java253
-rw-r--r--Java/SevenZip/LzmaBench.java392
-rw-r--r--METADATA25
-rw-r--r--README.md2
1296 files changed, 355397 insertions, 132997 deletions
diff --git a/Asm/arm/7zCrcOpt.asm b/Asm/arm/7zCrcOpt.asm
index f008d65..6001d8e 100644
--- a/Asm/arm/7zCrcOpt.asm
+++ b/Asm/arm/7zCrcOpt.asm
@@ -1,100 +1,100 @@
- CODE32
-
- EXPORT |CrcUpdateT4@16|
-
- AREA |.text|, CODE, ARM
-
- MACRO
- CRC32_STEP_1
-
- ldrb r4, [r1], #1
- subs r2, r2, #1
- eor r4, r4, r0
- and r4, r4, #0xFF
- ldr r4, [r3, +r4, lsl #2]
- eor r0, r4, r0, lsr #8
-
- MEND
-
-
- MACRO
- CRC32_STEP_4 $STREAM_WORD
-
- eor r7, r7, r8
- eor r7, r7, r9
- eor r0, r0, r7
- eor r0, r0, $STREAM_WORD
- ldr $STREAM_WORD, [r1], #4
-
- and r7, r0, #0xFF
- and r8, r0, #0xFF00
- and r9, r0, #0xFF0000
- and r0, r0, #0xFF000000
-
- ldr r7, [r6, +r7, lsl #2]
- ldr r8, [r5, +r8, lsr #6]
- ldr r9, [r4, +r9, lsr #14]
- ldr r0, [r3, +r0, lsr #22]
-
- MEND
-
-
-|CrcUpdateT4@16| PROC
-
- stmdb sp!, {r4-r11, lr}
- cmp r2, #0
- beq |$fin|
-
-|$v1|
- tst r1, #7
- beq |$v2|
- CRC32_STEP_1
- bne |$v1|
-
-|$v2|
- cmp r2, #16
- blo |$v3|
-
- ldr r10, [r1], #4
- ldr r11, [r1], #4
-
- add r4, r3, #0x400
- add r5, r3, #0x800
- add r6, r3, #0xC00
-
- mov r7, #0
- mov r8, #0
- mov r9, #0
-
- sub r2, r2, #16
-
-|$loop|
- ; pld [r1, #0x40]
-
- CRC32_STEP_4 r10
- CRC32_STEP_4 r11
-
- subs r2, r2, #8
- bhs |$loop|
-
- sub r1, r1, #8
- add r2, r2, #16
-
- eor r7, r7, r8
- eor r7, r7, r9
- eor r0, r0, r7
-
-|$v3|
- cmp r2, #0
- beq |$fin|
-
-|$v4|
- CRC32_STEP_1
- bne |$v4|
-
-|$fin|
- ldmia sp!, {r4-r11, pc}
-
-|CrcUpdateT4@16| ENDP
-
- END
+ CODE32
+
+ EXPORT |CrcUpdateT4@16|
+
+ AREA |.text|, CODE, ARM
+
+ MACRO
+ CRC32_STEP_1
+
+ ldrb r4, [r1], #1
+ subs r2, r2, #1
+ eor r4, r4, r0
+ and r4, r4, #0xFF
+ ldr r4, [r3, +r4, lsl #2]
+ eor r0, r4, r0, lsr #8
+
+ MEND
+
+
+ MACRO
+ CRC32_STEP_4 $STREAM_WORD
+
+ eor r7, r7, r8
+ eor r7, r7, r9
+ eor r0, r0, r7
+ eor r0, r0, $STREAM_WORD
+ ldr $STREAM_WORD, [r1], #4
+
+ and r7, r0, #0xFF
+ and r8, r0, #0xFF00
+ and r9, r0, #0xFF0000
+ and r0, r0, #0xFF000000
+
+ ldr r7, [r6, +r7, lsl #2]
+ ldr r8, [r5, +r8, lsr #6]
+ ldr r9, [r4, +r9, lsr #14]
+ ldr r0, [r3, +r0, lsr #22]
+
+ MEND
+
+
+|CrcUpdateT4@16| PROC
+
+ stmdb sp!, {r4-r11, lr}
+ cmp r2, #0
+ beq |$fin|
+
+|$v1|
+ tst r1, #7
+ beq |$v2|
+ CRC32_STEP_1
+ bne |$v1|
+
+|$v2|
+ cmp r2, #16
+ blo |$v3|
+
+ ldr r10, [r1], #4
+ ldr r11, [r1], #4
+
+ add r4, r3, #0x400
+ add r5, r3, #0x800
+ add r6, r3, #0xC00
+
+ mov r7, #0
+ mov r8, #0
+ mov r9, #0
+
+ sub r2, r2, #16
+
+|$loop|
+ ; pld [r1, #0x40]
+
+ CRC32_STEP_4 r10
+ CRC32_STEP_4 r11
+
+ subs r2, r2, #8
+ bhs |$loop|
+
+ sub r1, r1, #8
+ add r2, r2, #16
+
+ eor r7, r7, r8
+ eor r7, r7, r9
+ eor r0, r0, r7
+
+|$v3|
+ cmp r2, #0
+ beq |$fin|
+
+|$v4|
+ CRC32_STEP_1
+ bne |$v4|
+
+|$fin|
+ ldmia sp!, {r4-r11, pc}
+
+|CrcUpdateT4@16| ENDP
+
+ END
diff --git a/Asm/arm64/7zAsm.S b/Asm/arm64/7zAsm.S
new file mode 100644
index 0000000..12e950b
--- /dev/null
+++ b/Asm/arm64/7zAsm.S
@@ -0,0 +1,181 @@
+// 7zAsm.S -- ASM macros for arm64
+// 2021-04-25 : Igor Pavlov : Public domain
+
+#define r0 x0
+#define r1 x1
+#define r2 x2
+#define r3 x3
+#define r4 x4
+#define r5 x5
+#define r6 x6
+#define r7 x7
+#define r8 x8
+#define r9 x9
+#define r10 x10
+#define r11 x11
+#define r12 x12
+#define r13 x13
+#define r14 x14
+#define r15 x15
+#define r16 x16
+#define r17 x17
+#define r18 x18
+#define r19 x19
+#define r20 x20
+#define r21 x21
+#define r22 x22
+#define r23 x23
+#define r24 x24
+#define r25 x25
+#define r26 x26
+#define r27 x27
+#define r28 x28
+#define r29 x29
+#define r30 x30
+
+#define REG_ABI_PARAM_0 r0
+#define REG_ABI_PARAM_1 r1
+#define REG_ABI_PARAM_2 r2
+
+
+.macro p2_add reg:req, param:req
+ add \reg, \reg, \param
+.endm
+
+.macro p2_sub reg:req, param:req
+ sub \reg, \reg, \param
+.endm
+
+.macro p2_sub_s reg:req, param:req
+ subs \reg, \reg, \param
+.endm
+
+.macro p2_and reg:req, param:req
+ and \reg, \reg, \param
+.endm
+
+.macro xor reg:req, param:req
+ eor \reg, \reg, \param
+.endm
+
+.macro or reg:req, param:req
+ orr \reg, \reg, \param
+.endm
+
+.macro shl reg:req, param:req
+ lsl \reg, \reg, \param
+.endm
+
+.macro shr reg:req, param:req
+ lsr \reg, \reg, \param
+.endm
+
+.macro sar reg:req, param:req
+ asr \reg, \reg, \param
+.endm
+
+.macro p1_neg reg:req
+ neg \reg, \reg
+.endm
+
+.macro dec reg:req
+ sub \reg, \reg, 1
+.endm
+
+.macro dec_s reg:req
+ subs \reg, \reg, 1
+.endm
+
+.macro inc reg:req
+ add \reg, \reg, 1
+.endm
+
+.macro inc_s reg:req
+ adds \reg, \reg, 1
+.endm
+
+
+.macro imul reg:req, param:req
+ mul \reg, \reg, \param
+.endm
+
+/*
+arm64 and arm use reverted c flag after subs/cmp instructions:
+ arm64-arm : x86
+ b.lo / b.cc : jb / jc
+ b.hs / b.cs : jae / jnc
+*/
+
+.macro jmp lab:req
+ b \lab
+.endm
+
+.macro je lab:req
+ b.eq \lab
+.endm
+
+.macro jz lab:req
+ b.eq \lab
+.endm
+
+.macro jnz lab:req
+ b.ne \lab
+.endm
+
+.macro jne lab:req
+ b.ne \lab
+.endm
+
+.macro jb lab:req
+ b.lo \lab
+.endm
+
+.macro jbe lab:req
+ b.ls \lab
+.endm
+
+.macro ja lab:req
+ b.hi \lab
+.endm
+
+.macro jae lab:req
+ b.hs \lab
+.endm
+
+
+.macro cmove dest:req, srcTrue:req
+ csel \dest, \srcTrue, \dest, eq
+.endm
+
+.macro cmovne dest:req, srcTrue:req
+ csel \dest, \srcTrue, \dest, ne
+.endm
+
+.macro cmovs dest:req, srcTrue:req
+ csel \dest, \srcTrue, \dest, mi
+.endm
+
+.macro cmovns dest:req, srcTrue:req
+ csel \dest, \srcTrue, \dest, pl
+.endm
+
+.macro cmovb dest:req, srcTrue:req
+ csel \dest, \srcTrue, \dest, lo
+.endm
+
+.macro cmovae dest:req, srcTrue:req
+ csel \dest, \srcTrue, \dest, hs
+.endm
+
+
+.macro MY_ALIGN_16 macro
+ .p2align 4,, (1 << 4) - 1
+.endm
+
+.macro MY_ALIGN_32 macro
+ .p2align 5,, (1 << 5) - 1
+.endm
+
+.macro MY_ALIGN_64 macro
+ .p2align 6,, (1 << 6) - 1
+.endm
diff --git a/Asm/arm64/LzmaDecOpt.S b/Asm/arm64/LzmaDecOpt.S
new file mode 100644
index 0000000..10dc473
--- /dev/null
+++ b/Asm/arm64/LzmaDecOpt.S
@@ -0,0 +1,1487 @@
+// LzmaDecOpt.S -- ARM64-ASM version of LzmaDec_DecodeReal_3() function
+// 2021-04-25 : Igor Pavlov : Public domain
+
+/*
+; 3 - is the code compatibility version of LzmaDec_DecodeReal_*()
+; function for check at link time.
+; That code is tightly coupled with LzmaDec_TryDummy()
+; and with another functions in LzmaDec.c file.
+; CLzmaDec structure, (probs) array layout, input and output of
+; LzmaDec_DecodeReal_*() must be equal in both versions (C / ASM).
+*/
+
+
+#include "7zAsm.S"
+
+ // .arch armv8-a
+ // .file "LzmaDecOpt.c"
+ .text
+ .align 2
+ .p2align 4,,15
+#ifdef __APPLE__
+ .globl _LzmaDec_DecodeReal_3
+#else
+ .global LzmaDec_DecodeReal_3
+#endif
+ // .type LzmaDec_DecodeReal_3, %function
+
+// #define _LZMA_SIZE_OPT 1
+
+#define LZMA_USE_4BYTES_FILL 1
+// #define LZMA_USE_2BYTES_COPY 1
+// #define LZMA_USE_CMOV_LZ_WRAP 1
+// #define _LZMA_PROB32 1
+
+#define MY_ALIGN_FOR_ENTRY MY_ALIGN_32
+#define MY_ALIGN_FOR_LOOP MY_ALIGN_32
+#define MY_ALIGN_FOR_LOOP_16 MY_ALIGN_16
+
+#ifdef _LZMA_PROB32
+ .equ PSHIFT , 2
+ .macro PLOAD dest:req, mem:req
+ ldr \dest, [\mem]
+ .endm
+ .macro PLOAD_PREINDEXED dest:req, mem:req, offset:req
+ ldr \dest, [\mem, \offset]!
+ .endm
+ .macro PLOAD_2 dest:req, mem1:req, mem2:req
+ ldr \dest, [\mem1, \mem2]
+ .endm
+ .macro PLOAD_LSL dest:req, mem1:req, mem2:req
+ ldr \dest, [\mem1, \mem2, lsl #PSHIFT]
+ .endm
+ .macro PSTORE src:req, mem:req
+ str \src, [\mem]
+ .endm
+ .macro PSTORE_2 src:req, mem1:req, mem2:req
+ str \src, [\mem1, \mem2]
+ .endm
+ .macro PSTORE_LSL src:req, mem1:req, mem2:req
+ str \src, [\mem1, \mem2, lsl #PSHIFT]
+ .endm
+ .macro PSTORE_LSL_M1 src:req, mem1:req, mem2:req, temp_reg:req
+ // you must check that temp_reg is free register when macro is used
+ add \temp_reg, \mem1, \mem2
+ str \src, [\temp_reg, \mem2]
+ .endm
+#else
+ // .equ PSHIFT , 1
+ #define PSHIFT 1
+ .macro PLOAD dest:req, mem:req
+ ldrh \dest, [\mem]
+ .endm
+ .macro PLOAD_PREINDEXED dest:req, mem:req, offset:req
+ ldrh \dest, [\mem, \offset]!
+ .endm
+ .macro PLOAD_2 dest:req, mem1:req, mem2:req
+ ldrh \dest, [\mem1, \mem2]
+ .endm
+ .macro PLOAD_LSL dest:req, mem1:req, mem2:req
+ ldrh \dest, [\mem1, \mem2, lsl #PSHIFT]
+ .endm
+ .macro PSTORE src:req, mem:req
+ strh \src, [\mem]
+ .endm
+ .macro PSTORE_2 src:req, mem1:req, mem2:req
+ strh \src, [\mem1, \mem2]
+ .endm
+ .macro PSTORE_LSL src:req, mem1:req, mem2:req
+ strh \src, [\mem1, \mem2, lsl #PSHIFT]
+ .endm
+ .macro PSTORE_LSL_M1 src:req, mem1:req, mem2:req, temp_reg:req
+ strh \src, [\mem1, \mem2]
+ .endm
+#endif
+
+.equ PMULT , (1 << PSHIFT)
+.equ PMULT_2 , (2 << PSHIFT)
+
+.equ kMatchSpecLen_Error_Data , (1 << 9)
+
+# x7 t0 : NORM_CALC : prob2 (IF_BIT_1)
+# x6 t1 : NORM_CALC : probs_state
+# x8 t2 : (LITM) temp : (TREE) temp
+# x4 t3 : (LITM) bit : (TREE) temp : UPDATE_0/UPDATE_0 temp
+# x10 t4 : (LITM) offs : (TREE) probs_PMULT : numBits
+# x9 t5 : (LITM) match : sym2 (ShortDist)
+# x1 t6 : (LITM) litm_prob : (TREE) prob_reg : pbPos
+# x2 t7 : (LITM) prm : probBranch : cnt
+# x3 sym : dist
+# x12 len
+# x0 range
+# x5 cod
+
+
+#define range w0
+
+// t6
+#define pbPos w1
+#define pbPos_R r1
+#define prob_reg w1
+#define litm_prob prob_reg
+
+// t7
+#define probBranch w2
+#define cnt w2
+#define cnt_R r2
+#define prm r2
+
+#define sym w3
+#define sym_R r3
+#define dist sym
+
+#define t3 w4
+#define bit w4
+#define bit_R r4
+#define update_temp_reg r4
+
+#define cod w5
+
+#define t1 w6
+#define t1_R r6
+#define probs_state t1_R
+
+#define t0 w7
+#define t0_R r7
+#define prob2 t0
+
+#define t2 w8
+#define t2_R r8
+
+// t5
+#define match w9
+#define sym2 w9
+#define sym2_R r9
+
+#define t4 w10
+#define t4_R r10
+
+#define offs w10
+#define offs_R r10
+
+#define probs r11
+
+#define len w12
+#define len_R x12
+
+#define state w13
+#define state_R r13
+
+#define dicPos r14
+#define buf r15
+#define bufLimit r16
+#define dicBufSize r17
+
+#define limit r19
+#define rep0 w20
+#define rep0_R r20
+#define rep1 w21
+#define rep2 w22
+#define rep3 w23
+#define dic r24
+#define probs_IsMatch r25
+#define probs_Spec r26
+#define checkDicSize w27
+#define processedPos w28
+#define pbMask w29
+#define lc2_lpMask w30
+
+
+.equ kNumBitModelTotalBits , 11
+.equ kBitModelTotal , (1 << kNumBitModelTotalBits)
+.equ kNumMoveBits , 5
+.equ kBitModelOffset , (kBitModelTotal - (1 << kNumMoveBits) + 1)
+
+.macro NORM_2 macro
+ ldrb t0, [buf], 1
+ shl range, 8
+ orr cod, t0, cod, lsl 8
+ /*
+ mov t0, cod
+ ldrb cod, [buf], 1
+ shl range, 8
+ bfi cod, t0, #8, #24
+ */
+.endm
+
+.macro TEST_HIGH_BYTE_range macro
+ tst range, 0xFF000000
+.endm
+
+.macro NORM macro
+ TEST_HIGH_BYTE_range
+ jnz 1f
+ NORM_2
+1:
+.endm
+
+
+# ---------- Branch MACROS ----------
+
+.macro UPDATE_0__0
+ sub prob2, probBranch, kBitModelOffset
+.endm
+
+.macro UPDATE_0__1
+ sub probBranch, probBranch, prob2, asr #(kNumMoveBits)
+.endm
+
+.macro UPDATE_0__2 probsArray:req, probOffset:req, probDisp:req
+ .if \probDisp == 0
+ PSTORE_2 probBranch, \probsArray, \probOffset
+ .elseif \probOffset == 0
+ PSTORE_2 probBranch, \probsArray, \probDisp * PMULT
+ .else
+ .error "unsupported"
+ // add update_temp_reg, \probsArray, \probOffset
+ PSTORE_2 probBranch, update_temp_reg, \probDisp * PMULT
+ .endif
+.endm
+
+.macro UPDATE_0 probsArray:req, probOffset:req, probDisp:req
+ UPDATE_0__0
+ UPDATE_0__1
+ UPDATE_0__2 \probsArray, \probOffset, \probDisp
+.endm
+
+
+.macro UPDATE_1 probsArray:req, probOffset:req, probDisp:req
+ // sub cod, cod, prob2
+ // sub range, range, prob2
+ p2_sub cod, range
+ sub range, prob2, range
+ sub prob2, probBranch, probBranch, lsr #(kNumMoveBits)
+ .if \probDisp == 0
+ PSTORE_2 prob2, \probsArray, \probOffset
+ .elseif \probOffset == 0
+ PSTORE_2 prob2, \probsArray, \probDisp * PMULT
+ .else
+ .error "unsupported"
+ // add update_temp_reg, \probsArray, \probOffset
+ PSTORE_2 prob2, update_temp_reg, \probDisp * PMULT
+ .endif
+.endm
+
+
+.macro CMP_COD_BASE
+ NORM
+ // lsr prob2, range, kNumBitModelTotalBits
+ // imul prob2, probBranch
+ // cmp cod, prob2
+ mov prob2, range
+ shr range, kNumBitModelTotalBits
+ imul range, probBranch
+ cmp cod, range
+.endm
+
+.macro CMP_COD_1 probsArray:req
+ PLOAD probBranch, \probsArray
+ CMP_COD_BASE
+.endm
+
+.macro CMP_COD_3 probsArray:req, probOffset:req, probDisp:req
+ .if \probDisp == 0
+ PLOAD_2 probBranch, \probsArray, \probOffset
+ .elseif \probOffset == 0
+ PLOAD_2 probBranch, \probsArray, \probDisp * PMULT
+ .else
+ .error "unsupported"
+ add update_temp_reg, \probsArray, \probOffset
+ PLOAD_2 probBranch, update_temp_reg, \probDisp * PMULT
+ .endif
+ CMP_COD_BASE
+.endm
+
+
+.macro IF_BIT_1_NOUP probsArray:req, probOffset:req, probDisp:req, toLabel:req
+ CMP_COD_3 \probsArray, \probOffset, \probDisp
+ jae \toLabel
+.endm
+
+
+.macro IF_BIT_1 probsArray:req, probOffset:req, probDisp:req, toLabel:req
+ IF_BIT_1_NOUP \probsArray, \probOffset, \probDisp, \toLabel
+ UPDATE_0 \probsArray, \probOffset, \probDisp
+.endm
+
+
+.macro IF_BIT_0_NOUP probsArray:req, probOffset:req, probDisp:req, toLabel:req
+ CMP_COD_3 \probsArray, \probOffset, \probDisp
+ jb \toLabel
+.endm
+
+.macro IF_BIT_0_NOUP_1 probsArray:req, toLabel:req
+ CMP_COD_1 \probsArray
+ jb \toLabel
+.endm
+
+
+# ---------- CMOV MACROS ----------
+
+.macro NORM_LSR
+ NORM
+ lsr t0, range, #kNumBitModelTotalBits
+.endm
+
+.macro COD_RANGE_SUB
+ subs t1, cod, t0
+ p2_sub range, t0
+.endm
+
+.macro RANGE_IMUL prob:req
+ imul t0, \prob
+.endm
+
+.macro NORM_CALC prob:req
+ NORM_LSR
+ RANGE_IMUL \prob
+ COD_RANGE_SUB
+.endm
+
+.macro CMOV_range
+ cmovb range, t0
+.endm
+
+.macro CMOV_code
+ cmovae cod, t1
+.endm
+
+.macro CMOV_code_Model_Pre prob:req
+ sub t0, \prob, kBitModelOffset
+ CMOV_code
+ cmovae t0, \prob
+.endm
+
+
+.macro PUP_BASE_2 prob:req, dest_reg:req
+ # only sar works for both 16/32 bit prob modes
+ sub \dest_reg, \prob, \dest_reg, asr #(kNumMoveBits)
+.endm
+
+.macro PUP prob:req, probPtr:req, mem2:req
+ PUP_BASE_2 \prob, t0
+ PSTORE_2 t0, \probPtr, \mem2
+.endm
+
+
+
+#define probs_PMULT t4_R
+
+.macro BIT_01
+ add probs_PMULT, probs, PMULT
+.endm
+
+
+.macro BIT_0_R prob:req
+ PLOAD_2 \prob, probs, 1 * PMULT
+ NORM_LSR
+ sub t3, \prob, kBitModelOffset
+ RANGE_IMUL \prob
+ PLOAD_2 t2, probs, 1 * PMULT_2
+ COD_RANGE_SUB
+ CMOV_range
+ cmovae t3, \prob
+ PLOAD_2 t0, probs, 1 * PMULT_2 + PMULT
+ PUP_BASE_2 \prob, t3
+ csel \prob, t2, t0, lo
+ CMOV_code
+ mov sym, 2
+ PSTORE_2 t3, probs, 1 * PMULT
+ adc sym, sym, wzr
+ BIT_01
+.endm
+
+.macro BIT_1_R prob:req
+ NORM_LSR
+ p2_add sym, sym
+ sub t3, \prob, kBitModelOffset
+ RANGE_IMUL \prob
+ PLOAD_LSL t2, probs, sym_R
+ COD_RANGE_SUB
+ CMOV_range
+ cmovae t3, \prob
+ PLOAD_LSL t0, probs_PMULT, sym_R
+ PUP_BASE_2 \prob, t3
+ csel \prob, t2, t0, lo
+ CMOV_code
+ PSTORE_LSL_M1 t3, probs, sym_R, t2_R
+ adc sym, sym, wzr
+.endm
+
+
+.macro BIT_2_R prob:req
+ NORM_LSR
+ p2_add sym, sym
+ sub t3, \prob, kBitModelOffset
+ RANGE_IMUL \prob
+ COD_RANGE_SUB
+ CMOV_range
+ cmovae t3, \prob
+ CMOV_code
+ PUP_BASE_2 \prob, t3
+ PSTORE_LSL_M1 t3, probs, sym_R, t2_R
+ adc sym, sym, wzr
+.endm
+
+
+# ---------- MATCHED LITERAL ----------
+
+.macro LITM_0 macro
+ shl match, (PSHIFT + 1)
+ and bit, match, 256 * PMULT
+ add prm, probs, 256 * PMULT + 1 * PMULT
+ p2_add match, match
+ p2_add prm, bit_R
+ eor offs, bit, 256 * PMULT
+ PLOAD litm_prob, prm
+
+ NORM_LSR
+ sub t2, litm_prob, kBitModelOffset
+ RANGE_IMUL litm_prob
+ COD_RANGE_SUB
+ cmovae offs, bit
+ CMOV_range
+ and bit, match, offs
+ cmovae t2, litm_prob
+ CMOV_code
+ mov sym, 2
+ PUP_BASE_2 litm_prob, t2
+ PSTORE t2, prm
+ add prm, probs, offs_R
+ adc sym, sym, wzr
+.endm
+
+.macro LITM macro
+ p2_add prm, bit_R
+ xor offs, bit
+ PLOAD_LSL litm_prob, prm, sym_R
+
+ NORM_LSR
+ p2_add match, match
+ sub t2, litm_prob, kBitModelOffset
+ RANGE_IMUL litm_prob
+ COD_RANGE_SUB
+ cmovae offs, bit
+ CMOV_range
+ and bit, match, offs
+ cmovae t2, litm_prob
+ CMOV_code
+ PUP_BASE_2 litm_prob, t2
+ PSTORE_LSL t2, prm, sym_R
+ add prm, probs, offs_R
+ adc sym, sym, sym
+.endm
+
+
+.macro LITM_2 macro
+ p2_add prm, bit_R
+ PLOAD_LSL litm_prob, prm, sym_R
+
+ NORM_LSR
+ sub t2, litm_prob, kBitModelOffset
+ RANGE_IMUL litm_prob
+ COD_RANGE_SUB
+ CMOV_range
+ cmovae t2, litm_prob
+ CMOV_code
+ PUP_BASE_2 litm_prob, t2
+ PSTORE_LSL t2, prm, sym_R
+ adc sym, sym, sym
+.endm
+
+
+# ---------- REVERSE BITS ----------
+
+.macro REV_0 prob:req
+ NORM_CALC \prob
+ CMOV_range
+ PLOAD t2, sym2_R
+ PLOAD_2 t3, probs, 3 * PMULT
+ CMOV_code_Model_Pre \prob
+ add t1_R, probs, 3 * PMULT
+ cmovae sym2_R, t1_R
+ PUP \prob, probs, 1 * PMULT
+ csel \prob, t2, t3, lo
+.endm
+
+
+.macro REV_1 prob:req, step:req
+ NORM_LSR
+ PLOAD_PREINDEXED t2, sym2_R, (\step * PMULT)
+ RANGE_IMUL \prob
+ COD_RANGE_SUB
+ CMOV_range
+ PLOAD_2 t3, sym2_R, (\step * PMULT)
+ sub t0, \prob, kBitModelOffset
+ CMOV_code
+ add t1_R, sym2_R, \step * PMULT
+ cmovae t0, \prob
+ cmovae sym2_R, t1_R
+ PUP_BASE_2 \prob, t0
+ csel \prob, t2, t3, lo
+ PSTORE_2 t0, t1_R, 0 - \step * PMULT_2
+.endm
+
+
+.macro REV_2 prob:req, step:req
+ sub t1_R, sym2_R, probs
+ NORM_LSR
+ orr sym, sym, t1, lsr #PSHIFT
+ RANGE_IMUL \prob
+ COD_RANGE_SUB
+ sub t2, sym, \step
+ CMOV_range
+ cmovb sym, t2
+ CMOV_code_Model_Pre \prob
+ PUP \prob, sym2_R, 0
+.endm
+
+
+.macro REV_1_VAR prob:req
+ PLOAD \prob, sym_R
+ mov probs, sym_R
+ p2_add sym_R, sym2_R
+ NORM_LSR
+ add t2_R, sym_R, sym2_R
+ RANGE_IMUL \prob
+ COD_RANGE_SUB
+ cmovae sym_R, t2_R
+ CMOV_range
+ CMOV_code_Model_Pre \prob
+ p2_add sym2, sym2
+ PUP \prob, probs, 0
+.endm
+
+
+.macro add_big dest:req, src:req, param:req
+ .if (\param) < (1 << 12)
+ add \dest, \src, \param
+ .else
+ #ifndef _LZMA_PROB32
+ .error "unexpcted add_big expansion"
+ #endif
+ add \dest, \src, (\param) / 2
+ add \dest, \dest, (\param) - (\param) / 2
+ .endif
+.endm
+
+.macro sub_big dest:req, src:req, param:req
+ .if (\param) < (1 << 12)
+ sub \dest, \src, \param
+ .else
+ #ifndef _LZMA_PROB32
+ .error "unexpcted sub_big expansion"
+ #endif
+ sub \dest, \src, (\param) / 2
+ sub \dest, \dest, (\param) - (\param) / 2
+ .endif
+.endm
+
+
+.macro SET_probs offset:req
+ // add_big probs, probs_Spec, (\offset) * PMULT
+ add probs, probs_IsMatch, ((\offset) - IsMatch) * PMULT
+.endm
+
+
+.macro LIT_PROBS
+ add sym, sym, processedPos, lsl 8
+ inc processedPos
+ UPDATE_0__0
+ shl sym, lc2_lpMask
+ SET_probs Literal
+ p2_and sym, lc2_lpMask
+ // p2_add probs_state, pbPos_R
+ p2_add probs, sym_R
+ UPDATE_0__1
+ add probs, probs, sym_R, lsl 1
+ UPDATE_0__2 probs_state, pbPos_R, 0
+.endm
+
+
+
+.equ kNumPosBitsMax , 4
+.equ kNumPosStatesMax , (1 << kNumPosBitsMax)
+
+.equ kLenNumLowBits , 3
+.equ kLenNumLowSymbols , (1 << kLenNumLowBits)
+.equ kLenNumHighBits , 8
+.equ kLenNumHighSymbols , (1 << kLenNumHighBits)
+.equ kNumLenProbs , (2 * kLenNumLowSymbols * kNumPosStatesMax + kLenNumHighSymbols)
+
+.equ LenLow , 0
+.equ LenChoice , LenLow
+.equ LenChoice2 , (LenLow + kLenNumLowSymbols)
+.equ LenHigh , (LenLow + 2 * kLenNumLowSymbols * kNumPosStatesMax)
+
+.equ kNumStates , 12
+.equ kNumStates2 , 16
+.equ kNumLitStates , 7
+
+.equ kStartPosModelIndex , 4
+.equ kEndPosModelIndex , 14
+.equ kNumFullDistances , (1 << (kEndPosModelIndex >> 1))
+
+.equ kNumPosSlotBits , 6
+.equ kNumLenToPosStates , 4
+
+.equ kNumAlignBits , 4
+.equ kAlignTableSize , (1 << kNumAlignBits)
+
+.equ kMatchMinLen , 2
+.equ kMatchSpecLenStart , (kMatchMinLen + kLenNumLowSymbols * 2 + kLenNumHighSymbols)
+
+// .equ kStartOffset , 1408
+.equ kStartOffset , 0
+.equ SpecPos , (-kStartOffset)
+.equ IsRep0Long , (SpecPos + kNumFullDistances)
+.equ RepLenCoder , (IsRep0Long + (kNumStates2 << kNumPosBitsMax))
+.equ LenCoder , (RepLenCoder + kNumLenProbs)
+.equ IsMatch , (LenCoder + kNumLenProbs)
+.equ kAlign , (IsMatch + (kNumStates2 << kNumPosBitsMax))
+.equ IsRep , (kAlign + kAlignTableSize)
+.equ IsRepG0 , (IsRep + kNumStates)
+.equ IsRepG1 , (IsRepG0 + kNumStates)
+.equ IsRepG2 , (IsRepG1 + kNumStates)
+.equ PosSlot , (IsRepG2 + kNumStates)
+.equ Literal , (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+.equ NUM_BASE_PROBS , (Literal + kStartOffset)
+
+.if kStartOffset != 0 // && IsMatch != 0
+ .error "Stop_Compiling_Bad_StartOffset"
+.endif
+
+.if NUM_BASE_PROBS != 1984
+ .error "Stop_Compiling_Bad_LZMA_PROBS"
+.endif
+
+.equ offset_lc , 0
+.equ offset_lp , 1
+.equ offset_pb , 2
+.equ offset_dicSize , 4
+.equ offset_probs , 4 + offset_dicSize
+.equ offset_probs_1664 , 8 + offset_probs
+.equ offset_dic , 8 + offset_probs_1664
+.equ offset_dicBufSize , 8 + offset_dic
+.equ offset_dicPos , 8 + offset_dicBufSize
+.equ offset_buf , 8 + offset_dicPos
+.equ offset_range , 8 + offset_buf
+.equ offset_code , 4 + offset_range
+.equ offset_processedPos , 4 + offset_code
+.equ offset_checkDicSize , 4 + offset_processedPos
+.equ offset_rep0 , 4 + offset_checkDicSize
+.equ offset_rep1 , 4 + offset_rep0
+.equ offset_rep2 , 4 + offset_rep1
+.equ offset_rep3 , 4 + offset_rep2
+.equ offset_state , 4 + offset_rep3
+.equ offset_remainLen , 4 + offset_state
+.equ offset_TOTAL_SIZE , 4 + offset_remainLen
+
+.if offset_TOTAL_SIZE != 96
+ .error "Incorrect offset_TOTAL_SIZE"
+.endif
+
+
+.macro IsMatchBranch_Pre
+ # prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+ and pbPos, pbMask, processedPos, lsl #(kLenNumLowBits + 1 + PSHIFT)
+ add probs_state, probs_IsMatch, state_R
+.endm
+
+
+/*
+.macro IsMatchBranch
+ IsMatchBranch_Pre
+ IF_BIT_1 probs_state, pbPos_R, (IsMatch - IsMatch), IsMatch_label
+.endm
+*/
+
+.macro CheckLimits
+ cmp buf, bufLimit
+ jae fin_OK
+ cmp dicPos, limit
+ jae fin_OK
+.endm
+
+#define CheckLimits_lit CheckLimits
+/*
+.macro CheckLimits_lit
+ cmp buf, bufLimit
+ jae fin_OK_lit
+ cmp dicPos, limit
+ jae fin_OK_lit
+.endm
+*/
+
+
+#define PARAM_lzma REG_ABI_PARAM_0
+#define PARAM_limit REG_ABI_PARAM_1
+#define PARAM_bufLimit REG_ABI_PARAM_2
+
+
+.macro LOAD_LZMA_VAR reg:req, struct_offs:req
+ ldr \reg, [PARAM_lzma, \struct_offs]
+.endm
+
+.macro LOAD_LZMA_BYTE reg:req, struct_offs:req
+ ldrb \reg, [PARAM_lzma, \struct_offs]
+.endm
+
+.macro LOAD_LZMA_PAIR reg0:req, reg1:req, struct_offs:req
+ ldp \reg0, \reg1, [PARAM_lzma, \struct_offs]
+.endm
+
+
+LzmaDec_DecodeReal_3:
+_LzmaDec_DecodeReal_3:
+/*
+.LFB0:
+ .cfi_startproc
+*/
+
+ stp x19, x20, [sp, -128]!
+ stp x21, x22, [sp, 16]
+ stp x23, x24, [sp, 32]
+ stp x25, x26, [sp, 48]
+ stp x27, x28, [sp, 64]
+ stp x29, x30, [sp, 80]
+
+ str PARAM_lzma, [sp, 120]
+
+ mov bufLimit, PARAM_bufLimit
+ mov limit, PARAM_limit
+
+ LOAD_LZMA_PAIR dic, dicBufSize, offset_dic
+ LOAD_LZMA_PAIR dicPos, buf, offset_dicPos
+ LOAD_LZMA_PAIR rep0, rep1, offset_rep0
+ LOAD_LZMA_PAIR rep2, rep3, offset_rep2
+
+ mov t0, 1 << (kLenNumLowBits + 1 + PSHIFT)
+ LOAD_LZMA_BYTE pbMask, offset_pb
+ p2_add limit, dic
+ mov len, wzr // we can set it in all requiread branches instead
+ lsl pbMask, t0, pbMask
+ p2_add dicPos, dic
+ p2_sub pbMask, t0
+
+ LOAD_LZMA_BYTE lc2_lpMask, offset_lc
+ mov t0, 256 << PSHIFT
+ LOAD_LZMA_BYTE t1, offset_lp
+ p2_add t1, lc2_lpMask
+ p2_sub lc2_lpMask, (256 << PSHIFT) - PSHIFT
+ shl t0, t1
+ p2_add lc2_lpMask, t0
+
+ LOAD_LZMA_VAR probs_Spec, offset_probs
+ LOAD_LZMA_VAR checkDicSize, offset_checkDicSize
+ LOAD_LZMA_VAR processedPos, offset_processedPos
+ LOAD_LZMA_VAR state, offset_state
+ // range is r0 : this load must be last don't move
+ LOAD_LZMA_PAIR range, cod, offset_range
+ mov sym, wzr
+ shl state, PSHIFT
+
+ add_big probs_IsMatch, probs_Spec, ((IsMatch - SpecPos) << PSHIFT)
+
+ // if (processedPos != 0 || checkDicSize != 0)
+ orr t0, checkDicSize, processedPos
+ cbz t0, 1f
+ add t0_R, dicBufSize, dic
+ cmp dicPos, dic
+ cmovne t0_R, dicPos
+ ldrb sym, [t0_R, -1]
+1:
+ IsMatchBranch_Pre
+ cmp state, 4 * PMULT
+ jb lit_end
+ cmp state, kNumLitStates * PMULT
+ jb lit_matched_end
+ jmp lz_end
+
+
+
+#define BIT_0 BIT_0_R prob_reg
+#define BIT_1 BIT_1_R prob_reg
+#define BIT_2 BIT_2_R prob_reg
+
+# ---------- LITERAL ----------
+MY_ALIGN_64
+lit_start:
+ mov state, wzr
+lit_start_2:
+ LIT_PROBS
+
+ #ifdef _LZMA_SIZE_OPT
+
+ PLOAD_2 prob_reg, probs, 1 * PMULT
+ mov sym, 1
+ BIT_01
+MY_ALIGN_FOR_LOOP
+lit_loop:
+ BIT_1
+ tbz sym, 7, lit_loop
+
+ #else
+
+ BIT_0
+ BIT_1
+ BIT_1
+ BIT_1
+ BIT_1
+ BIT_1
+ BIT_1
+
+ #endif
+
+ BIT_2
+ IsMatchBranch_Pre
+ strb sym, [dicPos], 1
+ p2_and sym, 255
+
+ CheckLimits_lit
+lit_end:
+ IF_BIT_0_NOUP probs_state, pbPos_R, (IsMatch - IsMatch), lit_start
+
+ # jmp IsMatch_label
+
+
+#define FLAG_STATE_BITS (4 + PSHIFT)
+
+# ---------- MATCHES ----------
+# MY_ALIGN_FOR_ENTRY
+IsMatch_label:
+ UPDATE_1 probs_state, pbPos_R, (IsMatch - IsMatch)
+ IF_BIT_1 probs_state, 0, (IsRep - IsMatch), IsRep_label
+
+ SET_probs LenCoder
+ or state, (1 << FLAG_STATE_BITS)
+
+# ---------- LEN DECODE ----------
+len_decode:
+ mov len, 8 - kMatchMinLen
+ IF_BIT_0_NOUP_1 probs, len_mid_0
+ UPDATE_1 probs, 0, 0
+ p2_add probs, (1 << (kLenNumLowBits + PSHIFT))
+ mov len, 0 - kMatchMinLen
+ IF_BIT_0_NOUP_1 probs, len_mid_0
+ UPDATE_1 probs, 0, 0
+ p2_add probs, LenHigh * PMULT - (1 << (kLenNumLowBits + PSHIFT))
+
+ #if 0 == 1
+ BIT_0
+ BIT_1
+ BIT_1
+ BIT_1
+ BIT_1
+ BIT_1
+ #else
+ PLOAD_2 prob_reg, probs, 1 * PMULT
+ mov sym, 1
+ BIT_01
+MY_ALIGN_FOR_LOOP
+len8_loop:
+ BIT_1
+ tbz sym, 6, len8_loop
+ #endif
+
+ mov len, (kLenNumHighSymbols - kLenNumLowSymbols * 2) - kMatchMinLen
+ jmp len_mid_2
+
+MY_ALIGN_FOR_ENTRY
+len_mid_0:
+ UPDATE_0 probs, 0, 0
+ p2_add probs, pbPos_R
+ BIT_0
+len_mid_2:
+ BIT_1
+ BIT_2
+ sub len, sym, len
+ tbz state, FLAG_STATE_BITS, copy_match
+
+# ---------- DECODE DISTANCE ----------
+ // probs + PosSlot + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
+
+ mov t0, 3 + kMatchMinLen
+ cmp len, 3 + kMatchMinLen
+ cmovb t0, len
+ SET_probs PosSlot - (kMatchMinLen << (kNumPosSlotBits))
+ add probs, probs, t0_R, lsl #(kNumPosSlotBits + PSHIFT)
+
+ #ifdef _LZMA_SIZE_OPT
+
+ PLOAD_2 prob_reg, probs, 1 * PMULT
+ mov sym, 1
+ BIT_01
+MY_ALIGN_FOR_LOOP
+slot_loop:
+ BIT_1
+ tbz sym, 5, slot_loop
+
+ #else
+
+ BIT_0
+ BIT_1
+ BIT_1
+ BIT_1
+ BIT_1
+
+ #endif
+
+ #define numBits t4
+ mov numBits, sym
+ BIT_2
+ // we need only low bits
+ p2_and sym, 3
+ cmp numBits, 32 + kEndPosModelIndex / 2
+ jb short_dist
+
+ SET_probs kAlign
+
+ # unsigned numDirectBits = (unsigned)(((distance >> 1) - 1));
+ p2_sub numBits, (32 + 1 + kNumAlignBits)
+ # distance = (2 | (distance & 1));
+ or sym, 2
+ PLOAD_2 prob_reg, probs, 1 * PMULT
+ add sym2_R, probs, 2 * PMULT
+
+# ---------- DIRECT DISTANCE ----------
+
+.macro DIRECT_1
+ shr range, 1
+ subs t0, cod, range
+ p2_add sym, sym
+ // add t1, sym, 1
+ csel cod, cod, t0, mi
+ csinc sym, sym, sym, mi
+ // csel sym, t1, sym, pl
+ // adc sym, sym, sym // not 100% compatible for "corruptued-allowed" LZMA streams
+ dec_s numBits
+ je direct_end
+.endm
+
+ #ifdef _LZMA_SIZE_OPT
+
+ jmp direct_norm
+MY_ALIGN_FOR_ENTRY
+direct_loop:
+ DIRECT_1
+direct_norm:
+ TEST_HIGH_BYTE_range
+ jnz direct_loop
+ NORM_2
+ jmp direct_loop
+
+ #else
+
+.macro DIRECT_2
+ TEST_HIGH_BYTE_range
+ jz direct_unroll
+ DIRECT_1
+.endm
+
+ DIRECT_2
+ DIRECT_2
+ DIRECT_2
+ DIRECT_2
+ DIRECT_2
+ DIRECT_2
+ DIRECT_2
+ DIRECT_2
+
+direct_unroll:
+ NORM_2
+ DIRECT_1
+ DIRECT_1
+ DIRECT_1
+ DIRECT_1
+ DIRECT_1
+ DIRECT_1
+ DIRECT_1
+ DIRECT_1
+ jmp direct_unroll
+
+ #endif
+
+MY_ALIGN_FOR_ENTRY
+direct_end:
+ shl sym, kNumAlignBits
+ REV_0 prob_reg
+ REV_1 prob_reg, 2
+ REV_1 prob_reg, 4
+ REV_2 prob_reg, 8
+
+decode_dist_end:
+
+ // if (distance >= (checkDicSize == 0 ? processedPos: checkDicSize))
+
+ tst checkDicSize, checkDicSize
+ csel t0, processedPos, checkDicSize, eq
+ cmp sym, t0
+ jae end_of_payload
+ // jmp end_of_payload # for debug
+
+ mov rep3, rep2
+ mov rep2, rep1
+ mov rep1, rep0
+ add rep0, sym, 1
+
+.macro STATE_UPDATE_FOR_MATCH
+ // state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
+ // cmp state, (kNumStates + kNumLitStates) * PMULT
+ cmp state, kNumLitStates * PMULT + (1 << FLAG_STATE_BITS)
+ mov state, kNumLitStates * PMULT
+ mov t0, (kNumLitStates + 3) * PMULT
+ cmovae state, t0
+.endm
+ STATE_UPDATE_FOR_MATCH
+
+# ---------- COPY MATCH ----------
+copy_match:
+
+ // if ((rem = limit - dicPos) == 0) break // return SZ_ERROR_DATA;
+ subs cnt_R, limit, dicPos
+ // jz fin_dicPos_LIMIT
+ jz fin_OK
+
+ // curLen = ((rem < len) ? (unsigned)rem : len);
+ cmp cnt_R, len_R
+ cmovae cnt, len
+
+ sub t0_R, dicPos, dic
+ p2_add dicPos, cnt_R
+ p2_add processedPos, cnt
+ p2_sub len, cnt
+
+ // pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0);
+ p2_sub_s t0_R, rep0_R
+ jae 1f
+
+ cmn t0_R, cnt_R
+ p2_add t0_R, dicBufSize
+ ja copy_match_cross
+1:
+# ---------- COPY MATCH FAST ----------
+ # t0_R : src_pos
+ p2_add t0_R, dic
+ ldrb sym, [t0_R]
+ p2_add t0_R, cnt_R
+ p1_neg cnt_R
+
+copy_common:
+ dec dicPos
+
+ # dicPos : (ptr_to_last_dest_BYTE)
+ # t0_R : (src_lim)
+ # cnt_R : (-curLen)
+
+ IsMatchBranch_Pre
+
+ inc_s cnt_R
+ jz copy_end
+
+ cmp rep0, 1
+ je copy_match_0
+
+ #ifdef LZMA_USE_2BYTES_COPY
+ strb sym, [dicPos, cnt_R]
+ dec dicPos
+ # dicPos : (ptr_to_last_dest_16bitWORD)
+ p2_and cnt_R, -2
+ ldrh sym, [t0_R, cnt_R]
+ adds cnt_R, cnt_R, 2
+ jz 2f
+MY_ALIGN_FOR_LOOP
+1:
+ /*
+ strh sym, [dicPos, cnt_R]
+ ldrh sym, [t0_R, cnt_R]
+ adds cnt_R, cnt_R, 2
+ jz 2f
+ */
+
+ strh sym, [dicPos, cnt_R]
+ ldrh sym, [t0_R, cnt_R]
+ adds cnt_R, cnt_R, 2
+ jnz 1b
+2:
+
+ /*
+ // for universal little/big endian code, but slow
+ strh sym, [dicPos]
+ inc dicPos
+ ldrb sym, [t0_R, -1]
+ */
+
+ #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+ // we must improve big-endian detection for another compilers
+ // for big-endian we need to revert bytes
+ rev16 sym, sym
+ #endif
+
+ // (sym) must represent as little-endian here:
+ strb sym, [dicPos], 1
+ shr sym, 8
+
+ #else
+
+MY_ALIGN_FOR_LOOP
+1:
+ strb sym, [dicPos, cnt_R]
+ ldrb sym, [t0_R, cnt_R]
+ inc_s cnt_R
+ jz copy_end
+
+ strb sym, [dicPos, cnt_R]
+ ldrb sym, [t0_R, cnt_R]
+ inc_s cnt_R
+ jnz 1b
+ #endif
+
+copy_end:
+lz_end_match:
+ strb sym, [dicPos], 1
+
+ # IsMatchBranch_Pre
+ CheckLimits
+lz_end:
+ IF_BIT_1_NOUP probs_state, pbPos_R, (IsMatch - IsMatch), IsMatch_label
+
+
+
+# ---------- LITERAL MATCHED ----------
+
+ LIT_PROBS
+
+ // matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+
+ sub t0_R, dicPos, dic
+ p2_sub_s t0_R, rep0_R
+
+ #ifdef LZMA_USE_CMOV_LZ_WRAP
+ add t1_R, t0_R, dicBufSize
+ cmovb t0_R, t1_R
+ #else
+ jae 1f
+ p2_add t0_R, dicBufSize
+1:
+ #endif
+
+ ldrb match, [dic, t0_R]
+
+ // state -= (state < 10) ? 3 : 6;
+ sub sym, state, 6 * PMULT
+ cmp state, 10 * PMULT
+ p2_sub state, 3 * PMULT
+ cmovae state, sym
+
+ #ifdef _LZMA_SIZE_OPT
+
+ mov offs, 256 * PMULT
+ shl match, (PSHIFT + 1)
+ mov sym, 1
+ and bit, match, offs
+ add prm, probs, offs_R
+
+MY_ALIGN_FOR_LOOP
+litm_loop:
+ LITM
+ tbz sym, 8, litm_loop
+
+ #else
+
+ LITM_0
+ LITM
+ LITM
+ LITM
+ LITM
+ LITM
+ LITM
+ LITM_2
+
+ #endif
+
+ IsMatchBranch_Pre
+ strb sym, [dicPos], 1
+ p2_and sym, 255
+
+ // mov len, wzr // LITM uses same regisetr (len / offs). So we clear it
+ CheckLimits_lit
+lit_matched_end:
+ IF_BIT_1_NOUP probs_state, pbPos_R, (IsMatch - IsMatch), IsMatch_label
+ # IsMatchBranch
+ p2_sub state, 3 * PMULT
+ jmp lit_start_2
+
+
+
+# ---------- REP 0 LITERAL ----------
+MY_ALIGN_FOR_ENTRY
+IsRep0Short_label:
+ UPDATE_0 probs_state, pbPos_R, 0
+
+ // dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+ sub t0_R, dicPos, dic
+
+ // state = state < kNumLitStates ? 9 : 11;
+ or state, 1 * PMULT
+
+ # the caller doesn't allow (dicPos >= limit) case for REP_SHORT
+ # so we don't need the following (dicPos == limit) check here:
+ # cmp dicPos, limit
+ # jae fin_dicPos_LIMIT_REP_SHORT
+ # // jmp fin_dicPos_LIMIT_REP_SHORT // for testing/debug puposes
+
+ inc processedPos
+
+ IsMatchBranch_Pre
+
+ p2_sub_s t0_R, rep0_R
+ #ifdef LZMA_USE_CMOV_LZ_WRAP
+ add sym_R, t0_R, dicBufSize
+ cmovb t0_R, sym_R
+ #else
+ jae 1f
+ p2_add t0_R, dicBufSize
+1:
+ #endif
+
+ ldrb sym, [dic, t0_R]
+ // mov len, wzr
+ jmp lz_end_match
+
+MY_ALIGN_FOR_ENTRY
+IsRep_label:
+ UPDATE_1 probs_state, 0, (IsRep - IsMatch)
+
+ # The (checkDicSize == 0 && processedPos == 0) case was checked before in LzmaDec.c with kBadRepCode.
+ # So we don't check it here.
+
+ # mov t0, processedPos
+ # or t0, checkDicSize
+ # jz fin_ERROR_2
+
+ // state = state < kNumLitStates ? 8 : 11;
+ cmp state, kNumLitStates * PMULT
+ mov state, 8 * PMULT
+ mov probBranch, 11 * PMULT
+ cmovae state, probBranch
+
+ SET_probs RepLenCoder
+
+ IF_BIT_1 probs_state, 0, (IsRepG0 - IsMatch), IsRepG0_label
+ sub_big probs_state, probs_state, (IsMatch - IsRep0Long) << PSHIFT
+ IF_BIT_0_NOUP probs_state, pbPos_R, 0, IsRep0Short_label
+ UPDATE_1 probs_state, pbPos_R, 0
+ jmp len_decode
+
+MY_ALIGN_FOR_ENTRY
+IsRepG0_label:
+ UPDATE_1 probs_state, 0, (IsRepG0 - IsMatch)
+ IF_BIT_1 probs_state, 0, (IsRepG1 - IsMatch), IsRepG1_label
+ mov dist, rep1
+ mov rep1, rep0
+ mov rep0, dist
+ jmp len_decode
+
+# MY_ALIGN_FOR_ENTRY
+IsRepG1_label:
+ UPDATE_1 probs_state, 0, (IsRepG1 - IsMatch)
+ IF_BIT_1 probs_state, 0, (IsRepG2 - IsMatch), IsRepG2_label
+ mov dist, rep2
+ mov rep2, rep1
+ mov rep1, rep0
+ mov rep0, dist
+ jmp len_decode
+
+# MY_ALIGN_FOR_ENTRY
+IsRepG2_label:
+ UPDATE_1 probs_state, 0, (IsRepG2 - IsMatch)
+ mov dist, rep3
+ mov rep3, rep2
+ mov rep2, rep1
+ mov rep1, rep0
+ mov rep0, dist
+ jmp len_decode
+
+
+
+# ---------- SPEC SHORT DISTANCE ----------
+
+MY_ALIGN_FOR_ENTRY
+short_dist:
+ p2_sub_s numBits, 32 + 1
+ jbe decode_dist_end
+ or sym, 2
+ shl sym, numBits
+ add sym_R, probs_Spec, sym_R, lsl #PSHIFT
+ p2_add sym_R, SpecPos * PMULT + 1 * PMULT
+ mov sym2, PMULT // # step
+MY_ALIGN_FOR_LOOP
+spec_loop:
+ REV_1_VAR prob_reg
+ dec_s numBits
+ jnz spec_loop
+
+ p2_add sym2_R, probs_Spec
+ .if SpecPos != 0
+ p2_add sym2_R, SpecPos * PMULT
+ .endif
+ p2_sub sym_R, sym2_R
+ shr sym, PSHIFT
+
+ jmp decode_dist_end
+
+
+
+# ---------- COPY MATCH 0 ----------
+MY_ALIGN_FOR_ENTRY
+copy_match_0:
+ #ifdef LZMA_USE_4BYTES_FILL
+ strb sym, [dicPos, cnt_R]
+ inc_s cnt_R
+ jz copy_end
+
+ strb sym, [dicPos, cnt_R]
+ inc_s cnt_R
+ jz copy_end
+
+ strb sym, [dicPos, cnt_R]
+ inc_s cnt_R
+ jz copy_end
+
+ orr t3, sym, sym, lsl 8
+ p2_and cnt_R, -4
+ orr t3, t3, t3, lsl 16
+MY_ALIGN_FOR_LOOP_16
+1:
+ /*
+ str t3, [dicPos, cnt_R]
+ adds cnt_R, cnt_R, 4
+ jz 2f
+ */
+
+ str t3, [dicPos, cnt_R]
+ adds cnt_R, cnt_R, 4
+ jnz 1b
+2:
+ // p2_and sym, 255
+ #else
+
+MY_ALIGN_FOR_LOOP
+1:
+ strb sym, [dicPos, cnt_R]
+ inc_s cnt_R
+ jz copy_end
+
+ strb sym, [dicPos, cnt_R]
+ inc_s cnt_R
+ jnz 1b
+ #endif
+
+ jmp copy_end
+
+
+# ---------- COPY MATCH CROSS ----------
+copy_match_cross:
+ # t0_R - src pos
+ # cnt_R - total copy len
+
+ p1_neg cnt_R
+1:
+ ldrb sym, [dic, t0_R]
+ inc t0_R
+ strb sym, [dicPos, cnt_R]
+ inc cnt_R
+ cmp t0_R, dicBufSize
+ jne 1b
+
+ ldrb sym, [dic]
+ sub t0_R, dic, cnt_R
+ jmp copy_common
+
+
+
+
+/*
+fin_dicPos_LIMIT_REP_SHORT:
+ mov len, 1
+ jmp fin_OK
+*/
+
+/*
+fin_dicPos_LIMIT:
+ jmp fin_OK
+ # For more strict mode we can stop decoding with error
+ # mov sym, 1
+ # jmp fin
+*/
+
+fin_ERROR_MATCH_DIST:
+ # rep0 = distance + 1;
+ p2_add len, kMatchSpecLen_Error_Data
+ mov rep3, rep2
+ mov rep2, rep1
+ mov rep1, rep0
+ mov rep0, sym
+ STATE_UPDATE_FOR_MATCH
+ # jmp fin_OK
+ mov sym, 1
+ jmp fin
+
+end_of_payload:
+ inc_s sym
+ jnz fin_ERROR_MATCH_DIST
+
+ mov len, kMatchSpecLenStart
+ xor state, (1 << FLAG_STATE_BITS)
+ jmp fin_OK
+
+/*
+fin_OK_lit:
+ mov len, wzr
+*/
+
+fin_OK:
+ mov sym, wzr
+
+fin:
+ NORM
+
+ #define fin_lzma_reg t0_R
+
+ .macro STORE_LZMA_VAR reg:req, struct_offs:req
+ str \reg, [fin_lzma_reg, \struct_offs]
+ .endm
+
+ .macro STORE_LZMA_PAIR reg0:req, reg1:req, struct_offs:req
+ stp \reg0, \reg1, [fin_lzma_reg, \struct_offs]
+ .endm
+
+ ldr fin_lzma_reg, [sp, 120]
+ p2_sub dicPos, dic
+ shr state, PSHIFT
+
+ STORE_LZMA_PAIR dicPos, buf, offset_dicPos
+ STORE_LZMA_PAIR range, cod, offset_range
+ STORE_LZMA_VAR processedPos, offset_processedPos
+ STORE_LZMA_PAIR rep0, rep1, offset_rep0
+ STORE_LZMA_PAIR rep2, rep3, offset_rep2
+ STORE_LZMA_PAIR state, len, offset_state
+
+ mov w0, sym
+
+ ldp x29, x30, [sp, 80]
+ ldp x27, x28, [sp, 64]
+ ldp x25, x26, [sp, 48]
+ ldp x23, x24, [sp, 32]
+ ldp x21, x22, [sp, 16]
+ ldp x19, x20, [sp], 128
+
+ ret
+/*
+ .cfi_endproc
+.LFE0:
+ .size LzmaDec_DecodeReal_3, .-LzmaDec_DecodeReal_3
+ .ident "TAG_LZMA"
+ .section .note.GNU-stack,"",@progbits
+*/
diff --git a/Asm/x86/7zAsm.asm b/Asm/x86/7zAsm.asm
index 8c30d7b..19c40da 100644
--- a/Asm/x86/7zAsm.asm
+++ b/Asm/x86/7zAsm.asm
@@ -1,147 +1,289 @@
-; 7zAsm.asm -- ASM macros
-; 2018-02-03 : Igor Pavlov : Public domain
-
-MY_ASM_START macro
- ifdef x64
- .code
- else
- .386
- .model flat
- _TEXT$00 SEGMENT PARA PUBLIC 'CODE'
- endif
-endm
-
-MY_PROC macro name:req, numParams:req
- align 16
- proc_numParams = numParams
- ifdef x64
- proc_name equ name
- else
- proc_name equ @CatStr(@,name,@, %numParams * 4)
- endif
- proc_name PROC
-endm
-
-MY_ENDP macro
- ifdef x64
- ret
- else
- if proc_numParams LT 3
- ret
- else
- ret (proc_numParams - 2) * 4
- endif
- endif
- proc_name ENDP
-endm
-
-ifdef x64
- REG_SIZE equ 8
- REG_LOGAR_SIZE equ 3
-else
- REG_SIZE equ 4
- REG_LOGAR_SIZE equ 2
-endif
-
- x0 equ EAX
- x1 equ ECX
- x2 equ EDX
- x3 equ EBX
- x4 equ ESP
- x5 equ EBP
- x6 equ ESI
- x7 equ EDI
-
- x0_W equ AX
- x1_W equ CX
- x2_W equ DX
- x3_W equ BX
-
- x5_W equ BP
- x6_W equ SI
- x7_W equ DI
-
- x0_L equ AL
- x1_L equ CL
- x2_L equ DL
- x3_L equ BL
-
- x0_H equ AH
- x1_H equ CH
- x2_H equ DH
- x3_H equ BH
-
-ifdef x64
- x5_L equ BPL
- x6_L equ SIL
- x7_L equ DIL
-
- r0 equ RAX
- r1 equ RCX
- r2 equ RDX
- r3 equ RBX
- r4 equ RSP
- r5 equ RBP
- r6 equ RSI
- r7 equ RDI
- x8 equ r8d
- x9 equ r9d
- x10 equ r10d
- x11 equ r11d
- x12 equ r12d
- x13 equ r13d
- x14 equ r14d
- x15 equ r15d
-else
- r0 equ x0
- r1 equ x1
- r2 equ x2
- r3 equ x3
- r4 equ x4
- r5 equ x5
- r6 equ x6
- r7 equ x7
-endif
-
-MY_PUSH_4_REGS macro
- push r3
- push r5
- push r6
- push r7
-endm
-
-MY_POP_4_REGS macro
- pop r7
- pop r6
- pop r5
- pop r3
-endm
-
-
-ifdef x64
-
-; for WIN64-x64 ABI:
-
-REG_PARAM_0 equ r1
-REG_PARAM_1 equ r2
-REG_PARAM_2 equ r8
-REG_PARAM_3 equ r9
-
-MY_PUSH_PRESERVED_REGS macro
- MY_PUSH_4_REGS
- push r12
- push r13
- push r14
- push r15
-endm
-
-
-MY_POP_PRESERVED_REGS macro
- pop r15
- pop r14
- pop r13
- pop r12
- MY_POP_4_REGS
-endm
-
-endif
+; 7zAsm.asm -- ASM macros
+; 2022-05-16 : Igor Pavlov : Public domain
+
+
+; UASM can require these changes
+; OPTION FRAMEPRESERVEFLAGS:ON
+; OPTION PROLOGUE:NONE
+; OPTION EPILOGUE:NONE
+
+ifdef @wordsize
+; @wordsize is defined only in JWASM and ASMC and is not defined in MASM
+; @wordsize eq 8 for 64-bit x64
+; @wordsize eq 2 for 32-bit x86
+if @wordsize eq 8
+ x64 equ 1
+endif
+else
+ifdef RAX
+ x64 equ 1
+endif
+endif
+
+
+ifdef x64
+ IS_X64 equ 1
+else
+ IS_X64 equ 0
+endif
+
+ifdef ABI_LINUX
+ IS_LINUX equ 1
+else
+ IS_LINUX equ 0
+endif
+
+ifndef x64
+; Use ABI_CDECL for x86 (32-bit) only
+; if ABI_CDECL is not defined, we use fastcall abi
+ifdef ABI_CDECL
+ IS_CDECL equ 1
+else
+ IS_CDECL equ 0
+endif
+endif
+
+OPTION PROLOGUE:NONE
+OPTION EPILOGUE:NONE
+
+MY_ASM_START macro
+ ifdef x64
+ .code
+ else
+ .386
+ .model flat
+ _TEXT$00 SEGMENT PARA PUBLIC 'CODE'
+ endif
+endm
+
+MY_PROC macro name:req, numParams:req
+ align 16
+ proc_numParams = numParams
+ if (IS_X64 gt 0)
+ proc_name equ name
+ elseif (IS_LINUX gt 0)
+ proc_name equ name
+ elseif (IS_CDECL gt 0)
+ proc_name equ @CatStr(_,name)
+ else
+ proc_name equ @CatStr(@,name,@, %numParams * 4)
+ endif
+ proc_name PROC
+endm
+
+MY_ENDP macro
+ if (IS_X64 gt 0)
+ ret
+ elseif (IS_CDECL gt 0)
+ ret
+ elseif (proc_numParams LT 3)
+ ret
+ else
+ ret (proc_numParams - 2) * 4
+ endif
+ proc_name ENDP
+endm
+
+
+ifdef x64
+ REG_SIZE equ 8
+ REG_LOGAR_SIZE equ 3
+else
+ REG_SIZE equ 4
+ REG_LOGAR_SIZE equ 2
+endif
+
+ x0 equ EAX
+ x1 equ ECX
+ x2 equ EDX
+ x3 equ EBX
+ x4 equ ESP
+ x5 equ EBP
+ x6 equ ESI
+ x7 equ EDI
+
+ x0_W equ AX
+ x1_W equ CX
+ x2_W equ DX
+ x3_W equ BX
+
+ x5_W equ BP
+ x6_W equ SI
+ x7_W equ DI
+
+ x0_L equ AL
+ x1_L equ CL
+ x2_L equ DL
+ x3_L equ BL
+
+ x0_H equ AH
+ x1_H equ CH
+ x2_H equ DH
+ x3_H equ BH
+
+ifdef x64
+ x5_L equ BPL
+ x6_L equ SIL
+ x7_L equ DIL
+
+ r0 equ RAX
+ r1 equ RCX
+ r2 equ RDX
+ r3 equ RBX
+ r4 equ RSP
+ r5 equ RBP
+ r6 equ RSI
+ r7 equ RDI
+ x8 equ r8d
+ x9 equ r9d
+ x10 equ r10d
+ x11 equ r11d
+ x12 equ r12d
+ x13 equ r13d
+ x14 equ r14d
+ x15 equ r15d
+else
+ r0 equ x0
+ r1 equ x1
+ r2 equ x2
+ r3 equ x3
+ r4 equ x4
+ r5 equ x5
+ r6 equ x6
+ r7 equ x7
+endif
+
+
+ifdef x64
+ifdef ABI_LINUX
+
+MY_PUSH_2_REGS macro
+ push r3
+ push r5
+endm
+
+MY_POP_2_REGS macro
+ pop r5
+ pop r3
+endm
+
+endif
+endif
+
+
+MY_PUSH_4_REGS macro
+ push r3
+ push r5
+ push r6
+ push r7
+endm
+
+MY_POP_4_REGS macro
+ pop r7
+ pop r6
+ pop r5
+ pop r3
+endm
+
+
+; for fastcall and for WIN-x64
+REG_PARAM_0_x equ x1
+REG_PARAM_0 equ r1
+REG_PARAM_1_x equ x2
+REG_PARAM_1 equ r2
+
+ifndef x64
+; for x86-fastcall
+
+REG_ABI_PARAM_0_x equ REG_PARAM_0_x
+REG_ABI_PARAM_0 equ REG_PARAM_0
+REG_ABI_PARAM_1_x equ REG_PARAM_1_x
+REG_ABI_PARAM_1 equ REG_PARAM_1
+
+else
+; x64
+
+if (IS_LINUX eq 0)
+
+; for WIN-x64:
+REG_PARAM_2_x equ x8
+REG_PARAM_2 equ r8
+REG_PARAM_3 equ r9
+
+REG_ABI_PARAM_0_x equ REG_PARAM_0_x
+REG_ABI_PARAM_0 equ REG_PARAM_0
+REG_ABI_PARAM_1_x equ REG_PARAM_1_x
+REG_ABI_PARAM_1 equ REG_PARAM_1
+REG_ABI_PARAM_2_x equ REG_PARAM_2_x
+REG_ABI_PARAM_2 equ REG_PARAM_2
+REG_ABI_PARAM_3 equ REG_PARAM_3
+
+else
+; for LINUX-x64:
+REG_LINUX_PARAM_0_x equ x7
+REG_LINUX_PARAM_0 equ r7
+REG_LINUX_PARAM_1_x equ x6
+REG_LINUX_PARAM_1 equ r6
+REG_LINUX_PARAM_2 equ r2
+REG_LINUX_PARAM_3 equ r1
+REG_LINUX_PARAM_4_x equ x8
+REG_LINUX_PARAM_4 equ r8
+REG_LINUX_PARAM_5 equ r9
+
+REG_ABI_PARAM_0_x equ REG_LINUX_PARAM_0_x
+REG_ABI_PARAM_0 equ REG_LINUX_PARAM_0
+REG_ABI_PARAM_1_x equ REG_LINUX_PARAM_1_x
+REG_ABI_PARAM_1 equ REG_LINUX_PARAM_1
+REG_ABI_PARAM_2 equ REG_LINUX_PARAM_2
+REG_ABI_PARAM_3 equ REG_LINUX_PARAM_3
+REG_ABI_PARAM_4_x equ REG_LINUX_PARAM_4_x
+REG_ABI_PARAM_4 equ REG_LINUX_PARAM_4
+REG_ABI_PARAM_5 equ REG_LINUX_PARAM_5
+
+MY_ABI_LINUX_TO_WIN_2 macro
+ mov r2, r6
+ mov r1, r7
+endm
+
+MY_ABI_LINUX_TO_WIN_3 macro
+ mov r8, r2
+ mov r2, r6
+ mov r1, r7
+endm
+
+MY_ABI_LINUX_TO_WIN_4 macro
+ mov r9, r1
+ mov r8, r2
+ mov r2, r6
+ mov r1, r7
+endm
+
+endif ; IS_LINUX
+
+
+MY_PUSH_PRESERVED_ABI_REGS macro
+ if (IS_LINUX gt 0)
+ MY_PUSH_2_REGS
+ else
+ MY_PUSH_4_REGS
+ endif
+ push r12
+ push r13
+ push r14
+ push r15
+endm
+
+
+MY_POP_PRESERVED_ABI_REGS macro
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ if (IS_LINUX gt 0)
+ MY_POP_2_REGS
+ else
+ MY_POP_4_REGS
+ endif
+endm
+
+endif ; x64
diff --git a/Asm/x86/7zCrcOpt.asm b/Asm/x86/7zCrcOpt.asm
index 2de5171..0fee206 100644
--- a/Asm/x86/7zCrcOpt.asm
+++ b/Asm/x86/7zCrcOpt.asm
@@ -1,147 +1,180 @@
-; 7zCrcOpt.asm -- CRC32 calculation : optimized version
-; 2009-12-12 : Igor Pavlov : Public domain
-
-include 7zAsm.asm
-
-MY_ASM_START
-
-rD equ r2
-rN equ r7
-
-ifdef x64
- num_VAR equ r8
- table_VAR equ r9
-else
- data_size equ (REG_SIZE * 5)
- crc_table equ (REG_SIZE + data_size)
- num_VAR equ [r4 + data_size]
- table_VAR equ [r4 + crc_table]
-endif
-
-SRCDAT equ rN + rD + 4 *
-
-CRC macro op:req, dest:req, src:req, t:req
- op dest, DWORD PTR [r5 + src * 4 + 0400h * t]
-endm
-
-CRC_XOR macro dest:req, src:req, t:req
- CRC xor, dest, src, t
-endm
-
-CRC_MOV macro dest:req, src:req, t:req
- CRC mov, dest, src, t
-endm
-
-CRC1b macro
- movzx x6, BYTE PTR [rD]
- inc rD
- movzx x3, x0_L
- xor x6, x3
- shr x0, 8
- CRC xor, x0, r6, 0
- dec rN
-endm
-
-MY_PROLOG macro crc_end:req
- MY_PUSH_4_REGS
-
- mov x0, x1
- mov rN, num_VAR
- mov r5, table_VAR
- test rN, rN
- jz crc_end
- @@:
- test rD, 7
- jz @F
- CRC1b
- jnz @B
- @@:
- cmp rN, 16
- jb crc_end
- add rN, rD
- mov num_VAR, rN
- sub rN, 8
- and rN, NOT 7
- sub rD, rN
- xor x0, [SRCDAT 0]
-endm
-
-MY_EPILOG macro crc_end:req
- xor x0, [SRCDAT 0]
- mov rD, rN
- mov rN, num_VAR
- sub rN, rD
- crc_end:
- test rN, rN
- jz @F
- CRC1b
- jmp crc_end
- @@:
- MY_POP_4_REGS
-endm
-
-MY_PROC CrcUpdateT8, 4
- MY_PROLOG crc_end_8
- mov x1, [SRCDAT 1]
- align 16
- main_loop_8:
- mov x6, [SRCDAT 2]
- movzx x3, x1_L
- CRC_XOR x6, r3, 3
- movzx x3, x1_H
- CRC_XOR x6, r3, 2
- shr x1, 16
- movzx x3, x1_L
- movzx x1, x1_H
- CRC_XOR x6, r3, 1
- movzx x3, x0_L
- CRC_XOR x6, r1, 0
-
- mov x1, [SRCDAT 3]
- CRC_XOR x6, r3, 7
- movzx x3, x0_H
- shr x0, 16
- CRC_XOR x6, r3, 6
- movzx x3, x0_L
- CRC_XOR x6, r3, 5
- movzx x3, x0_H
- CRC_MOV x0, r3, 4
- xor x0, x6
- add rD, 8
- jnz main_loop_8
-
- MY_EPILOG crc_end_8
-MY_ENDP
-
-MY_PROC CrcUpdateT4, 4
- MY_PROLOG crc_end_4
- align 16
- main_loop_4:
- movzx x1, x0_L
- movzx x3, x0_H
- shr x0, 16
- movzx x6, x0_H
- and x0, 0FFh
- CRC_MOV x1, r1, 3
- xor x1, [SRCDAT 1]
- CRC_XOR x1, r3, 2
- CRC_XOR x1, r6, 0
- CRC_XOR x1, r0, 1
-
- movzx x0, x1_L
- movzx x3, x1_H
- shr x1, 16
- movzx x6, x1_H
- and x1, 0FFh
- CRC_MOV x0, r0, 3
- xor x0, [SRCDAT 2]
- CRC_XOR x0, r3, 2
- CRC_XOR x0, r6, 0
- CRC_XOR x0, r1, 1
- add rD, 8
- jnz main_loop_4
-
- MY_EPILOG crc_end_4
-MY_ENDP
-
-end
+; 7zCrcOpt.asm -- CRC32 calculation : optimized version
+; 2021-02-07 : Igor Pavlov : Public domain
+
+include 7zAsm.asm
+
+MY_ASM_START
+
+rD equ r2
+rN equ r7
+rT equ r5
+
+ifdef x64
+ num_VAR equ r8
+ table_VAR equ r9
+else
+ if (IS_CDECL gt 0)
+ crc_OFFS equ (REG_SIZE * 5)
+ data_OFFS equ (REG_SIZE + crc_OFFS)
+ size_OFFS equ (REG_SIZE + data_OFFS)
+ else
+ size_OFFS equ (REG_SIZE * 5)
+ endif
+ table_OFFS equ (REG_SIZE + size_OFFS)
+ num_VAR equ [r4 + size_OFFS]
+ table_VAR equ [r4 + table_OFFS]
+endif
+
+SRCDAT equ rD + rN * 1 + 4 *
+
+CRC macro op:req, dest:req, src:req, t:req
+ op dest, DWORD PTR [rT + src * 4 + 0400h * t]
+endm
+
+CRC_XOR macro dest:req, src:req, t:req
+ CRC xor, dest, src, t
+endm
+
+CRC_MOV macro dest:req, src:req, t:req
+ CRC mov, dest, src, t
+endm
+
+CRC1b macro
+ movzx x6, BYTE PTR [rD]
+ inc rD
+ movzx x3, x0_L
+ xor x6, x3
+ shr x0, 8
+ CRC xor, x0, r6, 0
+ dec rN
+endm
+
+MY_PROLOG macro crc_end:req
+
+ ifdef x64
+ if (IS_LINUX gt 0)
+ MY_PUSH_2_REGS
+ mov x0, REG_ABI_PARAM_0_x ; x0 = x7
+ mov rT, REG_ABI_PARAM_3 ; r5 = r1
+ mov rN, REG_ABI_PARAM_2 ; r7 = r2
+ mov rD, REG_ABI_PARAM_1 ; r2 = r6
+ else
+ MY_PUSH_4_REGS
+ mov x0, REG_ABI_PARAM_0_x ; x0 = x1
+ mov rT, REG_ABI_PARAM_3 ; r5 = r9
+ mov rN, REG_ABI_PARAM_2 ; r7 = r8
+ ; mov rD, REG_ABI_PARAM_1 ; r2 = r2
+ endif
+ else
+ MY_PUSH_4_REGS
+ if (IS_CDECL gt 0)
+ mov x0, [r4 + crc_OFFS]
+ mov rD, [r4 + data_OFFS]
+ else
+ mov x0, REG_ABI_PARAM_0_x
+ endif
+ mov rN, num_VAR
+ mov rT, table_VAR
+ endif
+
+ test rN, rN
+ jz crc_end
+ @@:
+ test rD, 7
+ jz @F
+ CRC1b
+ jnz @B
+ @@:
+ cmp rN, 16
+ jb crc_end
+ add rN, rD
+ mov num_VAR, rN
+ sub rN, 8
+ and rN, NOT 7
+ sub rD, rN
+ xor x0, [SRCDAT 0]
+endm
+
+MY_EPILOG macro crc_end:req
+ xor x0, [SRCDAT 0]
+ mov rD, rN
+ mov rN, num_VAR
+ sub rN, rD
+ crc_end:
+ test rN, rN
+ jz @F
+ CRC1b
+ jmp crc_end
+ @@:
+ if (IS_X64 gt 0) and (IS_LINUX gt 0)
+ MY_POP_2_REGS
+ else
+ MY_POP_4_REGS
+ endif
+endm
+
+MY_PROC CrcUpdateT8, 4
+ MY_PROLOG crc_end_8
+ mov x1, [SRCDAT 1]
+ align 16
+ main_loop_8:
+ mov x6, [SRCDAT 2]
+ movzx x3, x1_L
+ CRC_XOR x6, r3, 3
+ movzx x3, x1_H
+ CRC_XOR x6, r3, 2
+ shr x1, 16
+ movzx x3, x1_L
+ movzx x1, x1_H
+ CRC_XOR x6, r3, 1
+ movzx x3, x0_L
+ CRC_XOR x6, r1, 0
+
+ mov x1, [SRCDAT 3]
+ CRC_XOR x6, r3, 7
+ movzx x3, x0_H
+ shr x0, 16
+ CRC_XOR x6, r3, 6
+ movzx x3, x0_L
+ CRC_XOR x6, r3, 5
+ movzx x3, x0_H
+ CRC_MOV x0, r3, 4
+ xor x0, x6
+ add rD, 8
+ jnz main_loop_8
+
+ MY_EPILOG crc_end_8
+MY_ENDP
+
+MY_PROC CrcUpdateT4, 4
+ MY_PROLOG crc_end_4
+ align 16
+ main_loop_4:
+ movzx x1, x0_L
+ movzx x3, x0_H
+ shr x0, 16
+ movzx x6, x0_H
+ and x0, 0FFh
+ CRC_MOV x1, r1, 3
+ xor x1, [SRCDAT 1]
+ CRC_XOR x1, r3, 2
+ CRC_XOR x1, r6, 0
+ CRC_XOR x1, r0, 1
+
+ movzx x0, x1_L
+ movzx x3, x1_H
+ shr x1, 16
+ movzx x6, x1_H
+ and x1, 0FFh
+ CRC_MOV x0, r0, 3
+ xor x0, [SRCDAT 2]
+ CRC_XOR x0, r3, 2
+ CRC_XOR x0, r6, 0
+ CRC_XOR x0, r1, 1
+ add rD, 8
+ jnz main_loop_4
+
+ MY_EPILOG crc_end_4
+MY_ENDP
+
+end
diff --git a/Asm/x86/AesOpt.asm b/Asm/x86/AesOpt.asm
index c32e48f..84bf897 100644
--- a/Asm/x86/AesOpt.asm
+++ b/Asm/x86/AesOpt.asm
@@ -1,237 +1,742 @@
-; AesOpt.asm -- Intel's AES.
-; 2009-12-12 : Igor Pavlov : Public domain
-
-include 7zAsm.asm
-
-MY_ASM_START
-
-ifndef x64
- .xmm
-endif
-
-ifdef x64
- num equ r8
-else
- num equ [r4 + REG_SIZE * 4]
-endif
-
-rD equ r2
-rN equ r0
-
-MY_PROLOG macro reg:req
- ifdef x64
- movdqa [r4 + 8], xmm6
- movdqa [r4 + 8 + 16], xmm7
- endif
-
- push r3
- push r5
- push r6
-
- mov rN, num
- mov x6, [r1 + 16]
- shl x6, 5
-
- movdqa reg, [r1]
- add r1, 32
-endm
-
-MY_EPILOG macro
- pop r6
- pop r5
- pop r3
-
- ifdef x64
- movdqa xmm6, [r4 + 8]
- movdqa xmm7, [r4 + 8 + 16]
- endif
-
- MY_ENDP
-endm
-
-ways equ 4
-ways16 equ (ways * 16)
-
-OP_W macro op, op2
- i = 0
- rept ways
- op @CatStr(xmm,%i), op2
- i = i + 1
- endm
-endm
-
-LOAD_OP macro op:req, offs:req
- op xmm0, [r1 + r3 offs]
-endm
-
-LOAD_OP_W macro op:req, offs:req
- movdqa xmm7, [r1 + r3 offs]
- OP_W op, xmm7
-endm
-
-
-; ---------- AES-CBC Decode ----------
-
-CBC_DEC_UPDATE macro reg, offs
- pxor reg, xmm6
- movdqa xmm6, [rD + offs]
- movdqa [rD + offs], reg
-endm
-
-DECODE macro op:req
- op aesdec, +16
- @@:
- op aesdec, +0
- op aesdec, -16
- sub x3, 32
- jnz @B
- op aesdeclast, +0
-endm
-
-MY_PROC AesCbc_Decode_Intel, 3
- MY_PROLOG xmm6
-
- sub x6, 32
-
- jmp check2
-
- align 16
- nextBlocks2:
- mov x3, x6
- OP_W movdqa, [rD + i * 16]
- LOAD_OP_W pxor, +32
- DECODE LOAD_OP_W
- OP_W CBC_DEC_UPDATE, i * 16
- add rD, ways16
- check2:
- sub rN, ways
- jnc nextBlocks2
-
- add rN, ways
- jmp check
-
- nextBlock:
- mov x3, x6
- movdqa xmm1, [rD]
- LOAD_OP movdqa, +32
- pxor xmm0, xmm1
- DECODE LOAD_OP
- pxor xmm0, xmm6
- movdqa [rD], xmm0
- movdqa xmm6, xmm1
- add rD, 16
- check:
- sub rN, 1
- jnc nextBlock
-
- movdqa [r1 - 32], xmm6
- MY_EPILOG
-
-
-; ---------- AES-CBC Encode ----------
-
-ENCODE macro op:req
- op aesenc, -16
- @@:
- op aesenc, +0
- op aesenc, +16
- add r3, 32
- jnz @B
- op aesenclast, +0
-endm
-
-MY_PROC AesCbc_Encode_Intel, 3
- MY_PROLOG xmm0
-
- add r1, r6
- neg r6
- add r6, 32
-
- jmp check_e
-
- align 16
- nextBlock_e:
- mov r3, r6
- pxor xmm0, [rD]
- pxor xmm0, [r1 + r3 - 32]
- ENCODE LOAD_OP
- movdqa [rD], xmm0
- add rD, 16
- check_e:
- sub rN, 1
- jnc nextBlock_e
-
- movdqa [r1 + r6 - 64], xmm0
- MY_EPILOG
-
-
-; ---------- AES-CTR ----------
-
-XOR_UPD_1 macro reg, offs
- pxor reg, [rD + offs]
-endm
-
-XOR_UPD_2 macro reg, offs
- movdqa [rD + offs], reg
-endm
-
-MY_PROC AesCtr_Code_Intel, 3
- MY_PROLOG xmm6
-
- mov r5, r4
- shr r5, 4
- dec r5
- shl r5, 4
-
- mov DWORD PTR [r5], 1
- mov DWORD PTR [r5 + 4], 0
- mov DWORD PTR [r5 + 8], 0
- mov DWORD PTR [r5 + 12], 0
-
- add r1, r6
- neg r6
- add r6, 32
-
- jmp check2_c
-
- align 16
- nextBlocks2_c:
- movdqa xmm7, [r5]
-
- i = 0
- rept ways
- paddq xmm6, xmm7
- movdqa @CatStr(xmm,%i), xmm6
- i = i + 1
- endm
-
- mov r3, r6
- LOAD_OP_W pxor, -32
- ENCODE LOAD_OP_W
- OP_W XOR_UPD_1, i * 16
- OP_W XOR_UPD_2, i * 16
- add rD, ways16
- check2_c:
- sub rN, ways
- jnc nextBlocks2_c
-
- add rN, ways
- jmp check_c
-
- nextBlock_c:
- paddq xmm6, [r5]
- mov r3, r6
- movdqa xmm0, [r1 + r3 - 32]
- pxor xmm0, xmm6
- ENCODE LOAD_OP
- XOR_UPD_1 xmm0, 0
- XOR_UPD_2 xmm0, 0
- add rD, 16
- check_c:
- sub rN, 1
- jnc nextBlock_c
-
- movdqa [r1 + r6 - 64], xmm6
- MY_EPILOG
-
-end
+; AesOpt.asm -- AES optimized code for x86 AES hardware instructions
+; 2021-12-25 : Igor Pavlov : Public domain
+
+include 7zAsm.asm
+
+ifdef __ASMC__
+ use_vaes_256 equ 1
+else
+ifdef ymm0
+ use_vaes_256 equ 1
+endif
+endif
+
+
+ifdef use_vaes_256
+ ECHO "++ VAES 256"
+else
+ ECHO "-- NO VAES 256"
+endif
+
+ifdef x64
+ ECHO "x86-64"
+else
+ ECHO "x86"
+if (IS_CDECL gt 0)
+ ECHO "ABI : CDECL"
+else
+ ECHO "ABI : no CDECL : FASTCALL"
+endif
+endif
+
+if (IS_LINUX gt 0)
+ ECHO "ABI : LINUX"
+else
+ ECHO "ABI : WINDOWS"
+endif
+
+MY_ASM_START
+
+ifndef x64
+ .686
+ .xmm
+endif
+
+
+; MY_ALIGN EQU ALIGN(64)
+MY_ALIGN EQU
+
+SEG_ALIGN EQU MY_ALIGN
+
+MY_SEG_PROC macro name:req, numParams:req
+ ; seg_name equ @CatStr(_TEXT$, name)
+ ; seg_name SEGMENT SEG_ALIGN 'CODE'
+ MY_PROC name, numParams
+endm
+
+MY_SEG_ENDP macro
+ ; seg_name ENDS
+endm
+
+
+NUM_AES_KEYS_MAX equ 15
+
+; the number of push operators in function PROLOG
+if (IS_LINUX eq 0) or (IS_X64 eq 0)
+num_regs_push equ 2
+stack_param_offset equ (REG_SIZE * (1 + num_regs_push))
+endif
+
+ifdef x64
+ num_param equ REG_ABI_PARAM_2
+else
+ if (IS_CDECL gt 0)
+ ; size_t size
+ ; void * data
+ ; UInt32 * aes
+ ; ret-ip <- (r4)
+ aes_OFFS equ (stack_param_offset)
+ data_OFFS equ (REG_SIZE + aes_OFFS)
+ size_OFFS equ (REG_SIZE + data_OFFS)
+ num_param equ [r4 + size_OFFS]
+ else
+ num_param equ [r4 + stack_param_offset]
+ endif
+endif
+
+keys equ REG_PARAM_0 ; r1
+rD equ REG_PARAM_1 ; r2
+rN equ r0
+
+koffs_x equ x7
+koffs_r equ r7
+
+ksize_x equ x6
+ksize_r equ r6
+
+keys2 equ r3
+
+state equ xmm0
+key equ xmm0
+key_ymm equ ymm0
+key_ymm_n equ 0
+
+ifdef x64
+ ways = 11
+else
+ ways = 4
+endif
+
+ways_start_reg equ 1
+
+iv equ @CatStr(xmm, %(ways_start_reg + ways))
+iv_ymm equ @CatStr(ymm, %(ways_start_reg + ways))
+
+
+WOP macro op, op2
+ i = 0
+ rept ways
+ op @CatStr(xmm, %(ways_start_reg + i)), op2
+ i = i + 1
+ endm
+endm
+
+
+ifndef ABI_LINUX
+ifdef x64
+
+; we use 32 bytes of home space in stack in WIN64-x64
+NUM_HOME_MM_REGS equ (32 / 16)
+; we preserve xmm registers starting from xmm6 in WIN64-x64
+MM_START_SAVE_REG equ 6
+
+SAVE_XMM macro num_used_mm_regs:req
+ num_save_mm_regs = num_used_mm_regs - MM_START_SAVE_REG
+ if num_save_mm_regs GT 0
+ num_save_mm_regs2 = num_save_mm_regs - NUM_HOME_MM_REGS
+ ; RSP is (16*x + 8) after entering the function in WIN64-x64
+ stack_offset = 16 * num_save_mm_regs2 + (stack_param_offset mod 16)
+
+ i = 0
+ rept num_save_mm_regs
+
+ if i eq NUM_HOME_MM_REGS
+ sub r4, stack_offset
+ endif
+
+ if i lt NUM_HOME_MM_REGS
+ movdqa [r4 + stack_param_offset + i * 16], @CatStr(xmm, %(MM_START_SAVE_REG + i))
+ else
+ movdqa [r4 + (i - NUM_HOME_MM_REGS) * 16], @CatStr(xmm, %(MM_START_SAVE_REG + i))
+ endif
+
+ i = i + 1
+ endm
+ endif
+endm
+
+RESTORE_XMM macro num_used_mm_regs:req
+ if num_save_mm_regs GT 0
+ i = 0
+ if num_save_mm_regs2 GT 0
+ rept num_save_mm_regs2
+ movdqa @CatStr(xmm, %(MM_START_SAVE_REG + NUM_HOME_MM_REGS + i)), [r4 + i * 16]
+ i = i + 1
+ endm
+ add r4, stack_offset
+ endif
+
+ num_low_regs = num_save_mm_regs - i
+ i = 0
+ rept num_low_regs
+ movdqa @CatStr(xmm, %(MM_START_SAVE_REG + i)), [r4 + stack_param_offset + i * 16]
+ i = i + 1
+ endm
+ endif
+endm
+
+endif ; x64
+endif ; ABI_LINUX
+
+
+MY_PROLOG macro num_used_mm_regs:req
+ ; num_regs_push: must be equal to the number of push operators
+ ; push r3
+ ; push r5
+ if (IS_LINUX eq 0) or (IS_X64 eq 0)
+ push r6
+ push r7
+ endif
+
+ mov rN, num_param ; don't move it; num_param can use stack pointer (r4)
+
+ if (IS_X64 eq 0)
+ if (IS_CDECL gt 0)
+ mov rD, [r4 + data_OFFS]
+ mov keys, [r4 + aes_OFFS]
+ endif
+ elseif (IS_LINUX gt 0)
+ MY_ABI_LINUX_TO_WIN_2
+ endif
+
+
+ ifndef ABI_LINUX
+ ifdef x64
+ SAVE_XMM num_used_mm_regs
+ endif
+ endif
+
+ mov ksize_x, [keys + 16]
+ shl ksize_x, 5
+endm
+
+
+MY_EPILOG macro
+ ifndef ABI_LINUX
+ ifdef x64
+ RESTORE_XMM num_save_mm_regs
+ endif
+ endif
+
+ if (IS_LINUX eq 0) or (IS_X64 eq 0)
+ pop r7
+ pop r6
+ endif
+ ; pop r5
+ ; pop r3
+ MY_ENDP
+endm
+
+
+OP_KEY macro op:req, offs:req
+ op state, [keys + offs]
+endm
+
+
+WOP_KEY macro op:req, offs:req
+ movdqa key, [keys + offs]
+ WOP op, key
+endm
+
+
+; ---------- AES-CBC Decode ----------
+
+
+XOR_WITH_DATA macro reg, _ppp_
+ pxor reg, [rD + i * 16]
+endm
+
+WRITE_TO_DATA macro reg, _ppp_
+ movdqa [rD + i * 16], reg
+endm
+
+
+; state0 equ @CatStr(xmm, %(ways_start_reg))
+
+key0 equ @CatStr(xmm, %(ways_start_reg + ways + 1))
+key0_ymm equ @CatStr(ymm, %(ways_start_reg + ways + 1))
+
+key_last equ @CatStr(xmm, %(ways_start_reg + ways + 2))
+key_last_ymm equ @CatStr(ymm, %(ways_start_reg + ways + 2))
+key_last_ymm_n equ (ways_start_reg + ways + 2)
+
+NUM_CBC_REGS equ (ways_start_reg + ways + 3)
+
+
+MY_SEG_PROC AesCbc_Decode_HW, 3
+
+ AesCbc_Decode_HW_start::
+ MY_PROLOG NUM_CBC_REGS
+
+ AesCbc_Decode_HW_start_2::
+ movdqa iv, [keys]
+ add keys, 32
+
+ movdqa key0, [keys + 1 * ksize_r]
+ movdqa key_last, [keys]
+ sub ksize_x, 16
+
+ jmp check2
+ align 16
+ nextBlocks2:
+ WOP movdqa, [rD + i * 16]
+ mov koffs_x, ksize_x
+ ; WOP_KEY pxor, ksize_r + 16
+ WOP pxor, key0
+ ; align 16
+ @@:
+ WOP_KEY aesdec, 1 * koffs_r
+ sub koffs_r, 16
+ jnz @B
+ ; WOP_KEY aesdeclast, 0
+ WOP aesdeclast, key_last
+
+ pxor @CatStr(xmm, %(ways_start_reg)), iv
+ i = 1
+ rept ways - 1
+ pxor @CatStr(xmm, %(ways_start_reg + i)), [rD + i * 16 - 16]
+ i = i + 1
+ endm
+ movdqa iv, [rD + ways * 16 - 16]
+ WOP WRITE_TO_DATA
+
+ add rD, ways * 16
+ AesCbc_Decode_HW_start_3::
+ check2:
+ sub rN, ways
+ jnc nextBlocks2
+ add rN, ways
+
+ sub ksize_x, 16
+
+ jmp check
+ nextBlock:
+ movdqa state, [rD]
+ mov koffs_x, ksize_x
+ ; OP_KEY pxor, 1 * ksize_r + 32
+ pxor state, key0
+ ; movdqa state0, [rD]
+ ; movdqa state, key0
+ ; pxor state, state0
+ @@:
+ OP_KEY aesdec, 1 * koffs_r + 16
+ OP_KEY aesdec, 1 * koffs_r
+ sub koffs_r, 32
+ jnz @B
+ OP_KEY aesdec, 16
+ ; OP_KEY aesdeclast, 0
+ aesdeclast state, key_last
+
+ pxor state, iv
+ movdqa iv, [rD]
+ ; movdqa iv, state0
+ movdqa [rD], state
+
+ add rD, 16
+ check:
+ sub rN, 1
+ jnc nextBlock
+
+ movdqa [keys - 32], iv
+MY_EPILOG
+
+
+
+
+; ---------- AVX ----------
+
+
+AVX__WOP_n macro op
+ i = 0
+ rept ways
+ op (ways_start_reg + i)
+ i = i + 1
+ endm
+endm
+
+AVX__WOP macro op
+ i = 0
+ rept ways
+ op @CatStr(ymm, %(ways_start_reg + i))
+ i = i + 1
+ endm
+endm
+
+
+AVX__WOP_KEY macro op:req, offs:req
+ vmovdqa key_ymm, ymmword ptr [keys2 + offs]
+ AVX__WOP_n op
+endm
+
+
+AVX__CBC_START macro reg
+ ; vpxor reg, key_ymm, ymmword ptr [rD + 32 * i]
+ vpxor reg, key0_ymm, ymmword ptr [rD + 32 * i]
+endm
+
+AVX__CBC_END macro reg
+ if i eq 0
+ vpxor reg, reg, iv_ymm
+ else
+ vpxor reg, reg, ymmword ptr [rD + i * 32 - 16]
+ endif
+endm
+
+
+AVX__WRITE_TO_DATA macro reg
+ vmovdqu ymmword ptr [rD + 32 * i], reg
+endm
+
+AVX__XOR_WITH_DATA macro reg
+ vpxor reg, reg, ymmword ptr [rD + 32 * i]
+endm
+
+AVX__CTR_START macro reg
+ vpaddq iv_ymm, iv_ymm, one_ymm
+ ; vpxor reg, iv_ymm, key_ymm
+ vpxor reg, iv_ymm, key0_ymm
+endm
+
+
+MY_VAES_INSTR_2 macro cmd, dest, a1, a2
+ db 0c4H
+ db 2 + 040H + 020h * (1 - (a2) / 8) + 080h * (1 - (dest) / 8)
+ db 5 + 8 * ((not (a1)) and 15)
+ db cmd
+ db 0c0H + 8 * ((dest) and 7) + ((a2) and 7)
+endm
+
+MY_VAES_INSTR macro cmd, dest, a
+ MY_VAES_INSTR_2 cmd, dest, dest, a
+endm
+
+MY_vaesenc macro dest, a
+ MY_VAES_INSTR 0dcH, dest, a
+endm
+MY_vaesenclast macro dest, a
+ MY_VAES_INSTR 0ddH, dest, a
+endm
+MY_vaesdec macro dest, a
+ MY_VAES_INSTR 0deH, dest, a
+endm
+MY_vaesdeclast macro dest, a
+ MY_VAES_INSTR 0dfH, dest, a
+endm
+
+
+AVX__VAES_DEC macro reg
+ MY_vaesdec reg, key_ymm_n
+endm
+
+AVX__VAES_DEC_LAST_key_last macro reg
+ ; MY_vaesdeclast reg, key_ymm_n
+ MY_vaesdeclast reg, key_last_ymm_n
+endm
+
+AVX__VAES_ENC macro reg
+ MY_vaesenc reg, key_ymm_n
+endm
+
+AVX__VAES_ENC_LAST macro reg
+ MY_vaesenclast reg, key_ymm_n
+endm
+
+AVX__vinserti128_TO_HIGH macro dest, src
+ vinserti128 dest, dest, src, 1
+endm
+
+
+MY_PROC AesCbc_Decode_HW_256, 3
+ ifdef use_vaes_256
+ MY_PROLOG NUM_CBC_REGS
+
+ cmp rN, ways * 2
+ jb AesCbc_Decode_HW_start_2
+
+ vmovdqa iv, xmmword ptr [keys]
+ add keys, 32
+
+ vbroadcasti128 key0_ymm, xmmword ptr [keys + 1 * ksize_r]
+ vbroadcasti128 key_last_ymm, xmmword ptr [keys]
+ sub ksize_x, 16
+ mov koffs_x, ksize_x
+ add ksize_x, ksize_x
+
+ AVX_STACK_SUB = ((NUM_AES_KEYS_MAX + 1 - 2) * 32)
+ push keys2
+ sub r4, AVX_STACK_SUB
+ ; sub r4, 32
+ ; sub r4, ksize_r
+ ; lea keys2, [r4 + 32]
+ mov keys2, r4
+ and keys2, -32
+ broad:
+ vbroadcasti128 key_ymm, xmmword ptr [keys + 1 * koffs_r]
+ vmovdqa ymmword ptr [keys2 + koffs_r * 2], key_ymm
+ sub koffs_r, 16
+ ; jnc broad
+ jnz broad
+
+ sub rN, ways * 2
+
+ align 16
+ avx_cbcdec_nextBlock2:
+ mov koffs_x, ksize_x
+ ; AVX__WOP_KEY AVX__CBC_START, 1 * koffs_r + 32
+ AVX__WOP AVX__CBC_START
+ @@:
+ AVX__WOP_KEY AVX__VAES_DEC, 1 * koffs_r
+ sub koffs_r, 32
+ jnz @B
+ ; AVX__WOP_KEY AVX__VAES_DEC_LAST, 0
+ AVX__WOP_n AVX__VAES_DEC_LAST_key_last
+
+ AVX__vinserti128_TO_HIGH iv_ymm, xmmword ptr [rD]
+ AVX__WOP AVX__CBC_END
+
+ vmovdqa iv, xmmword ptr [rD + ways * 32 - 16]
+ AVX__WOP AVX__WRITE_TO_DATA
+
+ add rD, ways * 32
+ sub rN, ways * 2
+ jnc avx_cbcdec_nextBlock2
+ add rN, ways * 2
+
+ shr ksize_x, 1
+
+ ; lea r4, [r4 + 1 * ksize_r + 32]
+ add r4, AVX_STACK_SUB
+ pop keys2
+
+ vzeroupper
+ jmp AesCbc_Decode_HW_start_3
+ else
+ jmp AesCbc_Decode_HW_start
+ endif
+MY_ENDP
+MY_SEG_ENDP
+
+
+
+
+; ---------- AES-CBC Encode ----------
+
+e0 equ xmm1
+
+CENC_START_KEY equ 2
+CENC_NUM_REG_KEYS equ (3 * 2)
+; last_key equ @CatStr(xmm, %(CENC_START_KEY + CENC_NUM_REG_KEYS))
+
+MY_SEG_PROC AesCbc_Encode_HW, 3
+ MY_PROLOG (CENC_START_KEY + CENC_NUM_REG_KEYS + 0)
+
+ movdqa state, [keys]
+ add keys, 32
+
+ i = 0
+ rept CENC_NUM_REG_KEYS
+ movdqa @CatStr(xmm, %(CENC_START_KEY + i)), [keys + i * 16]
+ i = i + 1
+ endm
+
+ add keys, ksize_r
+ neg ksize_r
+ add ksize_r, (16 * CENC_NUM_REG_KEYS)
+ ; movdqa last_key, [keys]
+ jmp check_e
+
+ align 16
+ nextBlock_e:
+ movdqa e0, [rD]
+ mov koffs_r, ksize_r
+ pxor e0, @CatStr(xmm, %(CENC_START_KEY))
+ pxor state, e0
+
+ i = 1
+ rept (CENC_NUM_REG_KEYS - 1)
+ aesenc state, @CatStr(xmm, %(CENC_START_KEY + i))
+ i = i + 1
+ endm
+
+ @@:
+ OP_KEY aesenc, 1 * koffs_r
+ OP_KEY aesenc, 1 * koffs_r + 16
+ add koffs_r, 32
+ jnz @B
+ OP_KEY aesenclast, 0
+ ; aesenclast state, last_key
+
+ movdqa [rD], state
+ add rD, 16
+ check_e:
+ sub rN, 1
+ jnc nextBlock_e
+
+ ; movdqa [keys - 32], state
+ movdqa [keys + 1 * ksize_r - (16 * CENC_NUM_REG_KEYS) - 32], state
+MY_EPILOG
+MY_SEG_ENDP
+
+
+
+; ---------- AES-CTR ----------
+
+ifdef x64
+ ; ways = 11
+endif
+
+
+one equ @CatStr(xmm, %(ways_start_reg + ways + 1))
+one_ymm equ @CatStr(ymm, %(ways_start_reg + ways + 1))
+key0 equ @CatStr(xmm, %(ways_start_reg + ways + 2))
+key0_ymm equ @CatStr(ymm, %(ways_start_reg + ways + 2))
+NUM_CTR_REGS equ (ways_start_reg + ways + 3)
+
+INIT_CTR macro reg, _ppp_
+ paddq iv, one
+ movdqa reg, iv
+endm
+
+
+MY_SEG_PROC AesCtr_Code_HW, 3
+ Ctr_start::
+ MY_PROLOG NUM_CTR_REGS
+
+ Ctr_start_2::
+ movdqa iv, [keys]
+ add keys, 32
+ movdqa key0, [keys]
+
+ add keys, ksize_r
+ neg ksize_r
+ add ksize_r, 16
+
+ Ctr_start_3::
+ mov koffs_x, 1
+ movd one, koffs_x
+ jmp check2_c
+
+ align 16
+ nextBlocks2_c:
+ WOP INIT_CTR, 0
+ mov koffs_r, ksize_r
+ ; WOP_KEY pxor, 1 * koffs_r -16
+ WOP pxor, key0
+ @@:
+ WOP_KEY aesenc, 1 * koffs_r
+ add koffs_r, 16
+ jnz @B
+ WOP_KEY aesenclast, 0
+
+ WOP XOR_WITH_DATA
+ WOP WRITE_TO_DATA
+ add rD, ways * 16
+ check2_c:
+ sub rN, ways
+ jnc nextBlocks2_c
+ add rN, ways
+
+ sub keys, 16
+ add ksize_r, 16
+
+ jmp check_c
+
+ ; align 16
+ nextBlock_c:
+ paddq iv, one
+ ; movdqa state, [keys + 1 * koffs_r - 16]
+ movdqa state, key0
+ mov koffs_r, ksize_r
+ pxor state, iv
+
+ @@:
+ OP_KEY aesenc, 1 * koffs_r
+ OP_KEY aesenc, 1 * koffs_r + 16
+ add koffs_r, 32
+ jnz @B
+ OP_KEY aesenc, 0
+ OP_KEY aesenclast, 16
+
+ pxor state, [rD]
+ movdqa [rD], state
+ add rD, 16
+ check_c:
+ sub rN, 1
+ jnc nextBlock_c
+
+ ; movdqa [keys - 32], iv
+ movdqa [keys + 1 * ksize_r - 16 - 32], iv
+MY_EPILOG
+
+
+MY_PROC AesCtr_Code_HW_256, 3
+ ifdef use_vaes_256
+ MY_PROLOG NUM_CTR_REGS
+
+ cmp rN, ways * 2
+ jb Ctr_start_2
+
+ vbroadcasti128 iv_ymm, xmmword ptr [keys]
+ add keys, 32
+ vbroadcasti128 key0_ymm, xmmword ptr [keys]
+ mov koffs_x, 1
+ vmovd one, koffs_x
+ vpsubq iv_ymm, iv_ymm, one_ymm
+ vpaddq one, one, one
+ AVX__vinserti128_TO_HIGH one_ymm, one
+
+ add keys, ksize_r
+ sub ksize_x, 16
+ neg ksize_r
+ mov koffs_r, ksize_r
+ add ksize_r, ksize_r
+
+ AVX_STACK_SUB = ((NUM_AES_KEYS_MAX + 1 - 1) * 32)
+ push keys2
+ lea keys2, [r4 - 32]
+ sub r4, AVX_STACK_SUB
+ and keys2, -32
+ vbroadcasti128 key_ymm, xmmword ptr [keys]
+ vmovdqa ymmword ptr [keys2], key_ymm
+ @@:
+ vbroadcasti128 key_ymm, xmmword ptr [keys + 1 * koffs_r]
+ vmovdqa ymmword ptr [keys2 + koffs_r * 2], key_ymm
+ add koffs_r, 16
+ jnz @B
+
+ sub rN, ways * 2
+
+ align 16
+ avx_ctr_nextBlock2:
+ mov koffs_r, ksize_r
+ AVX__WOP AVX__CTR_START
+ ; AVX__WOP_KEY AVX__CTR_START, 1 * koffs_r - 32
+ @@:
+ AVX__WOP_KEY AVX__VAES_ENC, 1 * koffs_r
+ add koffs_r, 32
+ jnz @B
+ AVX__WOP_KEY AVX__VAES_ENC_LAST, 0
+
+ AVX__WOP AVX__XOR_WITH_DATA
+ AVX__WOP AVX__WRITE_TO_DATA
+
+ add rD, ways * 32
+ sub rN, ways * 2
+ jnc avx_ctr_nextBlock2
+ add rN, ways * 2
+
+ vextracti128 iv, iv_ymm, 1
+ sar ksize_r, 1
+
+ add r4, AVX_STACK_SUB
+ pop keys2
+
+ vzeroupper
+ jmp Ctr_start_3
+ else
+ jmp Ctr_start
+ endif
+MY_ENDP
+MY_SEG_ENDP
+
+end
diff --git a/Asm/x86/LzFindOpt.asm b/Asm/x86/LzFindOpt.asm
new file mode 100644
index 0000000..42e10bd
--- /dev/null
+++ b/Asm/x86/LzFindOpt.asm
@@ -0,0 +1,513 @@
+; LzFindOpt.asm -- ASM version of GetMatchesSpecN_2() function
+; 2021-07-21: Igor Pavlov : Public domain
+;
+
+ifndef x64
+; x64=1
+; .err <x64_IS_REQUIRED>
+endif
+
+include 7zAsm.asm
+
+MY_ASM_START
+
+_TEXT$LZFINDOPT SEGMENT ALIGN(64) 'CODE'
+
+MY_ALIGN macro num:req
+ align num
+endm
+
+MY_ALIGN_32 macro
+ MY_ALIGN 32
+endm
+
+MY_ALIGN_64 macro
+ MY_ALIGN 64
+endm
+
+
+t0_L equ x0_L
+t0_x equ x0
+t0 equ r0
+t1_x equ x3
+t1 equ r3
+
+cp_x equ t1_x
+cp_r equ t1
+m equ x5
+m_r equ r5
+len_x equ x6
+len equ r6
+diff_x equ x7
+diff equ r7
+len0 equ r10
+len1_x equ x11
+len1 equ r11
+maxLen_x equ x12
+maxLen equ r12
+d equ r13
+ptr0 equ r14
+ptr1 equ r15
+
+d_lim equ m_r
+cycSize equ len_x
+hash_lim equ len0
+delta1_x equ len1_x
+delta1_r equ len1
+delta_x equ maxLen_x
+delta_r equ maxLen
+hash equ ptr0
+src equ ptr1
+
+
+
+if (IS_LINUX gt 0)
+
+; r1 r2 r8 r9 : win32
+; r7 r6 r2 r1 r8 r9 : linux
+
+lenLimit equ r8
+lenLimit_x equ x8
+; pos_r equ r2
+pos equ x2
+cur equ r1
+son equ r9
+
+else
+
+lenLimit equ REG_ABI_PARAM_2
+lenLimit_x equ REG_ABI_PARAM_2_x
+pos equ REG_ABI_PARAM_1_x
+cur equ REG_ABI_PARAM_0
+son equ REG_ABI_PARAM_3
+
+endif
+
+
+if (IS_LINUX gt 0)
+ maxLen_OFFS equ (REG_SIZE * (6 + 1))
+else
+ cutValue_OFFS equ (REG_SIZE * (8 + 1 + 4))
+ d_OFFS equ (REG_SIZE + cutValue_OFFS)
+ maxLen_OFFS equ (REG_SIZE + d_OFFS)
+endif
+ hash_OFFS equ (REG_SIZE + maxLen_OFFS)
+ limit_OFFS equ (REG_SIZE + hash_OFFS)
+ size_OFFS equ (REG_SIZE + limit_OFFS)
+ cycPos_OFFS equ (REG_SIZE + size_OFFS)
+ cycSize_OFFS equ (REG_SIZE + cycPos_OFFS)
+ posRes_OFFS equ (REG_SIZE + cycSize_OFFS)
+
+if (IS_LINUX gt 0)
+else
+ cutValue_PAR equ [r0 + cutValue_OFFS]
+ d_PAR equ [r0 + d_OFFS]
+endif
+ maxLen_PAR equ [r0 + maxLen_OFFS]
+ hash_PAR equ [r0 + hash_OFFS]
+ limit_PAR equ [r0 + limit_OFFS]
+ size_PAR equ [r0 + size_OFFS]
+ cycPos_PAR equ [r0 + cycPos_OFFS]
+ cycSize_PAR equ [r0 + cycSize_OFFS]
+ posRes_PAR equ [r0 + posRes_OFFS]
+
+
+ cutValue_VAR equ DWORD PTR [r4 + 8 * 0]
+ cutValueCur_VAR equ DWORD PTR [r4 + 8 * 0 + 4]
+ cycPos_VAR equ DWORD PTR [r4 + 8 * 1 + 0]
+ cycSize_VAR equ DWORD PTR [r4 + 8 * 1 + 4]
+ hash_VAR equ QWORD PTR [r4 + 8 * 2]
+ limit_VAR equ QWORD PTR [r4 + 8 * 3]
+ size_VAR equ QWORD PTR [r4 + 8 * 4]
+ distances equ QWORD PTR [r4 + 8 * 5]
+ maxLen_VAR equ QWORD PTR [r4 + 8 * 6]
+
+ Old_RSP equ QWORD PTR [r4 + 8 * 7]
+ LOCAL_SIZE equ 8 * 8
+
+COPY_VAR_32 macro dest_var, src_var
+ mov x3, src_var
+ mov dest_var, x3
+endm
+
+COPY_VAR_64 macro dest_var, src_var
+ mov r3, src_var
+ mov dest_var, r3
+endm
+
+
+; MY_ALIGN_64
+MY_PROC GetMatchesSpecN_2, 13
+MY_PUSH_PRESERVED_ABI_REGS
+ mov r0, RSP
+ lea r3, [r0 - LOCAL_SIZE]
+ and r3, -64
+ mov RSP, r3
+ mov Old_RSP, r0
+
+if (IS_LINUX gt 0)
+ mov d, REG_ABI_PARAM_5 ; r13 = r9
+ mov cutValue_VAR, REG_ABI_PARAM_4_x ; = r8
+ mov son, REG_ABI_PARAM_3 ; r9 = r1
+ mov r8, REG_ABI_PARAM_2 ; r8 = r2
+ mov pos, REG_ABI_PARAM_1_x ; r2 = x6
+ mov r1, REG_ABI_PARAM_0 ; r1 = r7
+else
+ COPY_VAR_32 cutValue_VAR, cutValue_PAR
+ mov d, d_PAR
+endif
+
+ COPY_VAR_64 limit_VAR, limit_PAR
+
+ mov hash_lim, size_PAR
+ mov size_VAR, hash_lim
+
+ mov cp_x, cycPos_PAR
+ mov hash, hash_PAR
+
+ mov cycSize, cycSize_PAR
+ mov cycSize_VAR, cycSize
+
+ ; we want cur in (rcx). So we change the cur and lenLimit variables
+ sub lenLimit, cur
+ neg lenLimit_x
+ inc lenLimit_x
+
+ mov t0_x, maxLen_PAR
+ sub t0, lenLimit
+ mov maxLen_VAR, t0
+
+ jmp main_loop
+
+MY_ALIGN_64
+fill_empty:
+ ; ptr0 = *ptr1 = kEmptyHashValue;
+ mov QWORD PTR [ptr1], 0
+ inc pos
+ inc cp_x
+ mov DWORD PTR [d - 4], 0
+ cmp d, limit_VAR
+ jae fin
+ cmp hash, hash_lim
+ je fin
+
+; MY_ALIGN_64
+main_loop:
+ ; UInt32 delta = *hash++;
+ mov diff_x, [hash] ; delta
+ add hash, 4
+ ; mov cycPos_VAR, cp_x
+
+ inc cur
+ add d, 4
+ mov m, pos
+ sub m, diff_x; ; matchPos
+
+ ; CLzRef *ptr1 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2;
+ lea ptr1, [son + 8 * cp_r]
+ ; mov cycSize, cycSize_VAR
+ cmp pos, cycSize
+ jb directMode ; if (pos < cycSize_VAR)
+
+ ; CYC MODE
+
+ cmp diff_x, cycSize
+ jae fill_empty ; if (delta >= cycSize_VAR)
+
+ xor t0_x, t0_x
+ mov cycPos_VAR, cp_x
+ sub cp_x, diff_x
+ ; jae prepare_for_tree_loop
+ ; add cp_x, cycSize
+ cmovb t0_x, cycSize
+ add cp_x, t0_x ; cp_x += (cycPos < delta ? cycSize : 0)
+ jmp prepare_for_tree_loop
+
+
+directMode:
+ cmp diff_x, pos
+ je fill_empty ; if (delta == pos)
+ jae fin_error ; if (delta >= pos)
+
+ mov cycPos_VAR, cp_x
+ mov cp_x, m
+
+prepare_for_tree_loop:
+ mov len0, lenLimit
+ mov hash_VAR, hash
+ ; CLzRef *ptr0 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2 + 1;
+ lea ptr0, [ptr1 + 4]
+ ; UInt32 *_distances = ++d;
+ mov distances, d
+
+ neg len0
+ mov len1, len0
+
+ mov t0_x, cutValue_VAR
+ mov maxLen, maxLen_VAR
+ mov cutValueCur_VAR, t0_x
+
+MY_ALIGN_32
+tree_loop:
+ neg diff
+ mov len, len0
+ cmp len1, len0
+ cmovb len, len1 ; len = (len1 < len0 ? len1 : len0);
+ add diff, cur
+
+ mov t0_x, [son + cp_r * 8] ; prefetch
+ movzx t0_x, BYTE PTR [diff + 1 * len]
+ lea cp_r, [son + cp_r * 8]
+ cmp [cur + 1 * len], t0_L
+ je matched_1
+
+ jb left_0
+
+ mov [ptr1], m
+ mov m, [cp_r + 4]
+ lea ptr1, [cp_r + 4]
+ sub diff, cur ; FIX32
+ jmp next_node
+
+MY_ALIGN_32
+left_0:
+ mov [ptr0], m
+ mov m, [cp_r]
+ mov ptr0, cp_r
+ sub diff, cur ; FIX32
+ ; jmp next_node
+
+; ------------ NEXT NODE ------------
+; MY_ALIGN_32
+next_node:
+ mov cycSize, cycSize_VAR
+ dec cutValueCur_VAR
+ je finish_tree
+
+ add diff_x, pos ; prev_match = pos + diff
+ cmp m, diff_x
+ jae fin_error ; if (new_match >= prev_match)
+
+ mov diff_x, pos
+ sub diff_x, m ; delta = pos - new_match
+ cmp pos, cycSize
+ jae cyc_mode_2 ; if (pos >= cycSize)
+
+ mov cp_x, m
+ test m, m
+ jne tree_loop ; if (m != 0)
+
+finish_tree:
+ ; ptr0 = *ptr1 = kEmptyHashValue;
+ mov DWORD PTR [ptr0], 0
+ mov DWORD PTR [ptr1], 0
+
+ inc pos
+
+ ; _distances[-1] = (UInt32)(d - _distances);
+ mov t0, distances
+ mov t1, d
+ sub t1, t0
+ shr t1_x, 2
+ mov [t0 - 4], t1_x
+
+ cmp d, limit_VAR
+ jae fin ; if (d >= limit)
+
+ mov cp_x, cycPos_VAR
+ mov hash, hash_VAR
+ mov hash_lim, size_VAR
+ inc cp_x
+ cmp hash, hash_lim
+ jne main_loop ; if (hash != size)
+ jmp fin
+
+
+MY_ALIGN_32
+cyc_mode_2:
+ cmp diff_x, cycSize
+ jae finish_tree ; if (delta >= cycSize)
+
+ mov cp_x, cycPos_VAR
+ xor t0_x, t0_x
+ sub cp_x, diff_x ; cp_x = cycPos - delta
+ cmovb t0_x, cycSize
+ add cp_x, t0_x ; cp_x += (cycPos < delta ? cycSize : 0)
+ jmp tree_loop
+
+
+MY_ALIGN_32
+matched_1:
+
+ inc len
+ ; cmp len_x, lenLimit_x
+ je short lenLimit_reach
+ movzx t0_x, BYTE PTR [diff + 1 * len]
+ cmp [cur + 1 * len], t0_L
+ jne mismatch
+
+
+MY_ALIGN_32
+match_loop:
+ ; while (++len != lenLimit) (len[diff] != len[0]) ;
+
+ inc len
+ ; cmp len_x, lenLimit_x
+ je short lenLimit_reach
+ movzx t0_x, BYTE PTR [diff + 1 * len]
+ cmp BYTE PTR [cur + 1 * len], t0_L
+ je match_loop
+
+mismatch:
+ jb left_2
+
+ mov [ptr1], m
+ mov m, [cp_r + 4]
+ lea ptr1, [cp_r + 4]
+ mov len1, len
+
+ jmp max_update
+
+MY_ALIGN_32
+left_2:
+ mov [ptr0], m
+ mov m, [cp_r]
+ mov ptr0, cp_r
+ mov len0, len
+
+max_update:
+ sub diff, cur ; restore diff
+
+ cmp maxLen, len
+ jae next_node
+
+ mov maxLen, len
+ add len, lenLimit
+ mov [d], len_x
+ mov t0_x, diff_x
+ not t0_x
+ mov [d + 4], t0_x
+ add d, 8
+
+ jmp next_node
+
+
+
+MY_ALIGN_32
+lenLimit_reach:
+
+ mov delta_r, cur
+ sub delta_r, diff
+ lea delta1_r, [delta_r - 1]
+
+ mov t0_x, [cp_r]
+ mov [ptr1], t0_x
+ mov t0_x, [cp_r + 4]
+ mov [ptr0], t0_x
+
+ mov [d], lenLimit_x
+ mov [d + 4], delta1_x
+ add d, 8
+
+ ; _distances[-1] = (UInt32)(d - _distances);
+ mov t0, distances
+ mov t1, d
+ sub t1, t0
+ shr t1_x, 2
+ mov [t0 - 4], t1_x
+
+ mov hash, hash_VAR
+ mov hash_lim, size_VAR
+
+ inc pos
+ mov cp_x, cycPos_VAR
+ inc cp_x
+
+ mov d_lim, limit_VAR
+ mov cycSize, cycSize_VAR
+ ; if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit)
+ ; break;
+ cmp hash, hash_lim
+ je fin
+ cmp d, d_lim
+ jae fin
+ cmp delta_x, [hash]
+ jne main_loop
+ movzx t0_x, BYTE PTR [diff]
+ cmp [cur], t0_L
+ jne main_loop
+
+ ; jmp main_loop ; bypass for debug
+
+ mov cycPos_VAR, cp_x
+ shl len, 3 ; cycSize * 8
+ sub diff, cur ; restore diff
+ xor t0_x, t0_x
+ cmp cp_x, delta_x ; cmp (cycPos_VAR, delta)
+ lea cp_r, [son + 8 * cp_r] ; dest
+ lea src, [cp_r + 8 * diff]
+ cmovb t0, len ; t0 = (cycPos_VAR < delta ? cycSize * 8 : 0)
+ add src, t0
+ add len, son ; len = son + cycSize * 8
+
+
+MY_ALIGN_32
+long_loop:
+ add hash, 4
+
+ ; *(UInt64 *)(void *)ptr = ((const UInt64 *)(const void *)ptr)[diff];
+
+ mov t0, [src]
+ add src, 8
+ mov [cp_r], t0
+ add cp_r, 8
+ cmp src, len
+ cmove src, son ; if end of (son) buffer is reached, we wrap to begin
+
+ mov DWORD PTR [d], 2
+ mov [d + 4], lenLimit_x
+ mov [d + 8], delta1_x
+ add d, 12
+
+ inc cur
+
+ cmp hash, hash_lim
+ je long_footer
+ cmp delta_x, [hash]
+ jne long_footer
+ movzx t0_x, BYTE PTR [diff + 1 * cur]
+ cmp [cur], t0_L
+ jne long_footer
+ cmp d, d_lim
+ jb long_loop
+
+long_footer:
+ sub cp_r, son
+ shr cp_r, 3
+ add pos, cp_x
+ sub pos, cycPos_VAR
+ mov cycSize, cycSize_VAR
+
+ cmp d, d_lim
+ jae fin
+ cmp hash, hash_lim
+ jne main_loop
+ jmp fin
+
+
+
+fin_error:
+ xor d, d
+
+fin:
+ mov RSP, Old_RSP
+ mov t0, [r4 + posRes_OFFS]
+ mov [t0], pos
+ mov r0, d
+
+MY_POP_PRESERVED_ABI_REGS
+MY_ENDP
+
+_TEXT$LZFINDOPT ENDS
+
+end
diff --git a/Asm/x86/LzmaDecOpt.asm b/Asm/x86/LzmaDecOpt.asm
index 0a89eb7..f2818e7 100644
--- a/Asm/x86/LzmaDecOpt.asm
+++ b/Asm/x86/LzmaDecOpt.asm
@@ -1,1258 +1,1303 @@
-; LzmaDecOpt.asm -- ASM version of LzmaDec_DecodeReal_3() function
-; 2018-02-06: Igor Pavlov : Public domain
-;
-; 3 - is the code compatibility version of LzmaDec_DecodeReal_*()
-; function for check at link time.
-; That code is tightly coupled with LzmaDec_TryDummy()
-; and with another functions in LzmaDec.c file.
-; CLzmaDec structure, (probs) array layout, input and output of
-; LzmaDec_DecodeReal_*() must be equal in both versions (C / ASM).
-
-ifndef x64
-; x64=1
-; .err <x64_IS_REQUIRED>
-endif
-
-include 7zAsm.asm
-
-MY_ASM_START
-
-_TEXT$LZMADECOPT SEGMENT ALIGN(64) 'CODE'
-
-MY_ALIGN macro num:req
- align num
-endm
-
-MY_ALIGN_16 macro
- MY_ALIGN 16
-endm
-
-MY_ALIGN_32 macro
- MY_ALIGN 32
-endm
-
-MY_ALIGN_64 macro
- MY_ALIGN 64
-endm
-
-
-; _LZMA_SIZE_OPT equ 1
-
-; _LZMA_PROB32 equ 1
-
-ifdef _LZMA_PROB32
- PSHIFT equ 2
- PLOAD macro dest, mem
- mov dest, dword ptr [mem]
- endm
- PSTORE macro src, mem
- mov dword ptr [mem], src
- endm
-else
- PSHIFT equ 1
- PLOAD macro dest, mem
- movzx dest, word ptr [mem]
- endm
- PSTORE macro src, mem
- mov word ptr [mem], @CatStr(src, _W)
- endm
-endif
-
-PMULT equ (1 SHL PSHIFT)
-PMULT_HALF equ (1 SHL (PSHIFT - 1))
-PMULT_2 equ (1 SHL (PSHIFT + 1))
-
-
-; x0 range
-; x1 pbPos / (prob) TREE
-; x2 probBranch / prm (MATCHED) / pbPos / cnt
-; x3 sym
-;====== r4 === RSP
-; x5 cod
-; x6 t1 NORM_CALC / probs_state / dist
-; x7 t0 NORM_CALC / prob2 IF_BIT_1
-; x8 state
-; x9 match (MATCHED) / sym2 / dist2 / lpMask_reg
-; x10 kBitModelTotal_reg
-; r11 probs
-; x12 offs (MATCHED) / dic / len_temp
-; x13 processedPos
-; x14 bit (MATCHED) / dicPos
-; r15 buf
-
-
-cod equ x5
-cod_L equ x5_L
-range equ x0
-state equ x8
-state_R equ r8
-buf equ r15
-processedPos equ x13
-kBitModelTotal_reg equ x10
-
-probBranch equ x2
-probBranch_R equ r2
-probBranch_W equ x2_W
-
-pbPos equ x1
-pbPos_R equ r1
-
-cnt equ x2
-cnt_R equ r2
-
-lpMask_reg equ x9
-dicPos equ r14
-
-sym equ x3
-sym_R equ r3
-sym_L equ x3_L
-
-probs equ r11
-dic equ r12
-
-t0 equ x7
-t0_W equ x7_W
-t0_R equ r7
-
-prob2 equ t0
-prob2_W equ t0_W
-
-t1 equ x6
-t1_R equ r6
-
-probs_state equ t1
-probs_state_R equ t1_R
-
-prm equ r2
-match equ x9
-match_R equ r9
-offs equ x12
-offs_R equ r12
-bit equ x14
-bit_R equ r14
-
-sym2 equ x9
-sym2_R equ r9
-
-len_temp equ x12
-
-dist equ sym
-dist2 equ x9
-
-
-
-kNumBitModelTotalBits equ 11
-kBitModelTotal equ (1 SHL kNumBitModelTotalBits)
-kNumMoveBits equ 5
-kBitModelOffset equ ((1 SHL kNumMoveBits) - 1)
-kTopValue equ (1 SHL 24)
-
-NORM_2 macro
- ; movzx t0, BYTE PTR [buf]
- shl cod, 8
- mov cod_L, BYTE PTR [buf]
- shl range, 8
- ; or cod, t0
- inc buf
-endm
-
-
-NORM macro
- cmp range, kTopValue
- jae SHORT @F
- NORM_2
-@@:
-endm
-
-
-; ---------- Branch MACROS ----------
-
-UPDATE_0 macro probsArray:req, probOffset:req, probDisp:req
- mov prob2, kBitModelTotal_reg
- sub prob2, probBranch
- shr prob2, kNumMoveBits
- add probBranch, prob2
- PSTORE probBranch, probOffset * 1 + probsArray + probDisp * PMULT
-endm
-
-
-UPDATE_1 macro probsArray:req, probOffset:req, probDisp:req
- sub prob2, range
- sub cod, range
- mov range, prob2
- mov prob2, probBranch
- shr probBranch, kNumMoveBits
- sub prob2, probBranch
- PSTORE prob2, probOffset * 1 + probsArray + probDisp * PMULT
-endm
-
-
-CMP_COD macro probsArray:req, probOffset:req, probDisp:req
- PLOAD probBranch, probOffset * 1 + probsArray + probDisp * PMULT
- NORM
- mov prob2, range
- shr range, kNumBitModelTotalBits
- imul range, probBranch
- cmp cod, range
-endm
-
-
-IF_BIT_1_NOUP macro probsArray:req, probOffset:req, probDisp:req, toLabel:req
- CMP_COD probsArray, probOffset, probDisp
- jae toLabel
-endm
-
-
-IF_BIT_1 macro probsArray:req, probOffset:req, probDisp:req, toLabel:req
- IF_BIT_1_NOUP probsArray, probOffset, probDisp, toLabel
- UPDATE_0 probsArray, probOffset, probDisp
-endm
-
-
-IF_BIT_0_NOUP macro probsArray:req, probOffset:req, probDisp:req, toLabel:req
- CMP_COD probsArray, probOffset, probDisp
- jb toLabel
-endm
-
-
-; ---------- CMOV MACROS ----------
-
-NORM_CALC macro prob:req
- NORM
- mov t0, range
- shr range, kNumBitModelTotalBits
- imul range, prob
- sub t0, range
- mov t1, cod
- sub cod, range
-endm
-
-
-PUP macro prob:req, probPtr:req
- sub t0, prob
- ; only sar works for both 16/32 bit prob modes
- sar t0, kNumMoveBits
- add t0, prob
- PSTORE t0, probPtr
-endm
-
-
-PUP_SUB macro prob:req, probPtr:req, symSub:req
- sbb sym, symSub
- PUP prob, probPtr
-endm
-
-
-PUP_COD macro prob:req, probPtr:req, symSub:req
- mov t0, kBitModelOffset
- cmovb cod, t1
- mov t1, sym
- cmovb t0, kBitModelTotal_reg
- PUP_SUB prob, probPtr, symSub
-endm
-
-
-BIT_0 macro prob:req, probNext:req
- PLOAD prob, probs + 1 * PMULT
- PLOAD probNext, probs + 1 * PMULT_2
-
- NORM_CALC prob
-
- cmovae range, t0
- PLOAD t0, probs + 1 * PMULT_2 + PMULT
- cmovae probNext, t0
- mov t0, kBitModelOffset
- cmovb cod, t1
- cmovb t0, kBitModelTotal_reg
- mov sym, 2
- PUP_SUB prob, probs + 1 * PMULT, 0 - 1
-endm
-
-
-BIT_1 macro prob:req, probNext:req
- PLOAD probNext, probs + sym_R * PMULT_2
- add sym, sym
-
- NORM_CALC prob
-
- cmovae range, t0
- PLOAD t0, probs + sym_R * PMULT + PMULT
- cmovae probNext, t0
- PUP_COD prob, probs + t1_R * PMULT_HALF, 0 - 1
-endm
-
-
-BIT_2 macro prob:req, symSub:req
- add sym, sym
-
- NORM_CALC prob
-
- cmovae range, t0
- PUP_COD prob, probs + t1_R * PMULT_HALF, symSub
-endm
-
-
-; ---------- MATCHED LITERAL ----------
-
-LITM_0 macro
- mov offs, 256 * PMULT
- shl match, (PSHIFT + 1)
- mov bit, offs
- and bit, match
- PLOAD x1, probs + 256 * PMULT + bit_R * 1 + 1 * PMULT
- lea prm, [probs + 256 * PMULT + bit_R * 1 + 1 * PMULT]
- ; lea prm, [probs + 256 * PMULT + 1 * PMULT]
- ; add prm, bit_R
- xor offs, bit
- add match, match
-
- NORM_CALC x1
-
- cmovae offs, bit
- mov bit, match
- cmovae range, t0
- mov t0, kBitModelOffset
- cmovb cod, t1
- cmovb t0, kBitModelTotal_reg
- mov sym, 0
- PUP_SUB x1, prm, -2-1
-endm
-
-
-LITM macro
- and bit, offs
- lea prm, [probs + offs_R * 1]
- add prm, bit_R
- PLOAD x1, prm + sym_R * PMULT
- xor offs, bit
- add sym, sym
- add match, match
-
- NORM_CALC x1
-
- cmovae offs, bit
- mov bit, match
- cmovae range, t0
- PUP_COD x1, prm + t1_R * PMULT_HALF, - 1
-endm
-
-
-LITM_2 macro
- and bit, offs
- lea prm, [probs + offs_R * 1]
- add prm, bit_R
- PLOAD x1, prm + sym_R * PMULT
- add sym, sym
-
- NORM_CALC x1
-
- cmovae range, t0
- PUP_COD x1, prm + t1_R * PMULT_HALF, 256 - 1
-endm
-
-
-; ---------- REVERSE BITS ----------
-
-REV_0 macro prob:req, probNext:req
- ; PLOAD prob, probs + 1 * PMULT
- ; lea sym2_R, [probs + 2 * PMULT]
- ; PLOAD probNext, probs + 2 * PMULT
- PLOAD probNext, sym2_R
-
- NORM_CALC prob
-
- cmovae range, t0
- PLOAD t0, probs + 3 * PMULT
- cmovae probNext, t0
- cmovb cod, t1
- mov t0, kBitModelOffset
- cmovb t0, kBitModelTotal_reg
- lea t1_R, [probs + 3 * PMULT]
- cmovae sym2_R, t1_R
- PUP prob, probs + 1 * PMULT
-endm
-
-
-REV_1 macro prob:req, probNext:req, step:req
- add sym2_R, step * PMULT
- PLOAD probNext, sym2_R
-
- NORM_CALC prob
-
- cmovae range, t0
- PLOAD t0, sym2_R + step * PMULT
- cmovae probNext, t0
- cmovb cod, t1
- mov t0, kBitModelOffset
- cmovb t0, kBitModelTotal_reg
- lea t1_R, [sym2_R + step * PMULT]
- cmovae sym2_R, t1_R
- PUP prob, t1_R - step * PMULT_2
-endm
-
-
-REV_2 macro prob:req, step:req
- sub sym2_R, probs
- shr sym2, PSHIFT
- or sym, sym2
-
- NORM_CALC prob
-
- cmovae range, t0
- lea t0, [sym - step]
- cmovb sym, t0
- cmovb cod, t1
- mov t0, kBitModelOffset
- cmovb t0, kBitModelTotal_reg
- PUP prob, probs + sym2_R * PMULT
-endm
-
-
-REV_1_VAR macro prob:req
- PLOAD prob, sym_R
- mov probs, sym_R
- add sym_R, sym2_R
-
- NORM_CALC prob
-
- cmovae range, t0
- lea t0_R, [sym_R + sym2_R]
- cmovae sym_R, t0_R
- mov t0, kBitModelOffset
- cmovb cod, t1
- ; mov t1, kBitModelTotal
- ; cmovb t0, t1
- cmovb t0, kBitModelTotal_reg
- add sym2, sym2
- PUP prob, probs
-endm
-
-
-
-
-LIT_PROBS macro lpMaskParam:req
- ; prob += (UInt32)3 * ((((processedPos << 8) + dic[(dicPos == 0 ? dicBufSize : dicPos) - 1]) & lpMask) << lc);
- mov t0, processedPos
- shl t0, 8
- add sym, t0
- and sym, lpMaskParam
- add probs_state_R, pbPos_R
- mov x1, LOC lc2
- lea sym, dword ptr[sym_R + 2 * sym_R]
- add probs, Literal * PMULT
- shl sym, x1_L
- add probs, sym_R
- UPDATE_0 probs_state_R, 0, IsMatch
- inc processedPos
-endm
-
-
-
-kNumPosBitsMax equ 4
-kNumPosStatesMax equ (1 SHL kNumPosBitsMax)
-
-kLenNumLowBits equ 3
-kLenNumLowSymbols equ (1 SHL kLenNumLowBits)
-kLenNumHighBits equ 8
-kLenNumHighSymbols equ (1 SHL kLenNumHighBits)
-kNumLenProbs equ (2 * kLenNumLowSymbols * kNumPosStatesMax + kLenNumHighSymbols)
-
-LenLow equ 0
-LenChoice equ LenLow
-LenChoice2 equ (LenLow + kLenNumLowSymbols)
-LenHigh equ (LenLow + 2 * kLenNumLowSymbols * kNumPosStatesMax)
-
-kNumStates equ 12
-kNumStates2 equ 16
-kNumLitStates equ 7
-
-kStartPosModelIndex equ 4
-kEndPosModelIndex equ 14
-kNumFullDistances equ (1 SHL (kEndPosModelIndex SHR 1))
-
-kNumPosSlotBits equ 6
-kNumLenToPosStates equ 4
-
-kNumAlignBits equ 4
-kAlignTableSize equ (1 SHL kNumAlignBits)
-
-kMatchMinLen equ 2
-kMatchSpecLenStart equ (kMatchMinLen + kLenNumLowSymbols * 2 + kLenNumHighSymbols)
-
-kStartOffset equ 1664
-SpecPos equ (-kStartOffset)
-IsRep0Long equ (SpecPos + kNumFullDistances)
-RepLenCoder equ (IsRep0Long + (kNumStates2 SHL kNumPosBitsMax))
-LenCoder equ (RepLenCoder + kNumLenProbs)
-IsMatch equ (LenCoder + kNumLenProbs)
-kAlign equ (IsMatch + (kNumStates2 SHL kNumPosBitsMax))
-IsRep equ (kAlign + kAlignTableSize)
-IsRepG0 equ (IsRep + kNumStates)
-IsRepG1 equ (IsRepG0 + kNumStates)
-IsRepG2 equ (IsRepG1 + kNumStates)
-PosSlot equ (IsRepG2 + kNumStates)
-Literal equ (PosSlot + (kNumLenToPosStates SHL kNumPosSlotBits))
-NUM_BASE_PROBS equ (Literal + kStartOffset)
-
-if kAlign ne 0
- .err <Stop_Compiling_Bad_LZMA_kAlign>
-endif
-
-if NUM_BASE_PROBS ne 1984
- .err <Stop_Compiling_Bad_LZMA_PROBS>
-endif
-
-
-PTR_FIELD equ dq ?
-
-CLzmaDec_Asm struct
- lc db ?
- lp db ?
- pb db ?
- _pad_ db ?
- dicSize dd ?
-
- probs_Spec PTR_FIELD
- probs_1664 PTR_FIELD
- dic_Spec PTR_FIELD
- dicBufSize PTR_FIELD
- dicPos_Spec PTR_FIELD
- buf_Spec PTR_FIELD
-
- range_Spec dd ?
- code_Spec dd ?
- processedPos_Spec dd ?
- checkDicSize dd ?
- rep0 dd ?
- rep1 dd ?
- rep2 dd ?
- rep3 dd ?
- state_Spec dd ?
- remainLen dd ?
-CLzmaDec_Asm ends
-
-
-CLzmaDec_Asm_Loc struct
- OLD_RSP PTR_FIELD
- lzmaPtr PTR_FIELD
- _pad0_ PTR_FIELD
- _pad1_ PTR_FIELD
- _pad2_ PTR_FIELD
- dicBufSize PTR_FIELD
- probs_Spec PTR_FIELD
- dic_Spec PTR_FIELD
-
- limit PTR_FIELD
- bufLimit PTR_FIELD
- lc2 dd ?
- lpMask dd ?
- pbMask dd ?
- checkDicSize dd ?
-
- _pad_ dd ?
- remainLen dd ?
- dicPos_Spec PTR_FIELD
- rep0 dd ?
- rep1 dd ?
- rep2 dd ?
- rep3 dd ?
-CLzmaDec_Asm_Loc ends
-
-
-GLOB_2 equ [sym_R].CLzmaDec_Asm.
-GLOB equ [r1].CLzmaDec_Asm.
-LOC_0 equ [r0].CLzmaDec_Asm_Loc.
-LOC equ [RSP].CLzmaDec_Asm_Loc.
-
-
-COPY_VAR macro name
- mov t0, GLOB_2 name
- mov LOC_0 name, t0
-endm
-
-
-RESTORE_VAR macro name
- mov t0, LOC name
- mov GLOB name, t0
-endm
-
-
-
-IsMatchBranch_Pre macro reg
- ; prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
- mov pbPos, LOC pbMask
- and pbPos, processedPos
- shl pbPos, (kLenNumLowBits + 1 + PSHIFT)
- lea probs_state_R, [probs + state_R]
-endm
-
-
-IsMatchBranch macro reg
- IsMatchBranch_Pre
- IF_BIT_1 probs_state_R, pbPos_R, IsMatch, IsMatch_label
-endm
-
-
-CheckLimits macro reg
- cmp buf, LOC bufLimit
- jae fin_OK
- cmp dicPos, LOC limit
- jae fin_OK
-endm
-
-
-
-; RSP is (16x + 8) bytes aligned in WIN64-x64
-; LocalSize equ ((((SIZEOF CLzmaDec_Asm_Loc) + 7) / 16 * 16) + 8)
-
-PARAM_lzma equ REG_PARAM_0
-PARAM_limit equ REG_PARAM_1
-PARAM_bufLimit equ REG_PARAM_2
-
-; MY_ALIGN_64
-MY_PROC LzmaDec_DecodeReal_3, 3
-MY_PUSH_PRESERVED_REGS
-
- lea r0, [RSP - (SIZEOF CLzmaDec_Asm_Loc)]
- and r0, -128
- mov r5, RSP
- mov RSP, r0
- mov LOC_0 Old_RSP, r5
- mov LOC_0 lzmaPtr, PARAM_lzma
-
- mov LOC_0 remainLen, 0 ; remainLen must be ZERO
-
- mov LOC_0 bufLimit, PARAM_bufLimit
- mov sym_R, PARAM_lzma ; CLzmaDec_Asm_Loc pointer for GLOB_2
- mov dic, GLOB_2 dic_Spec
- add PARAM_limit, dic
- mov LOC_0 limit, PARAM_limit
-
- COPY_VAR(rep0)
- COPY_VAR(rep1)
- COPY_VAR(rep2)
- COPY_VAR(rep3)
-
- mov dicPos, GLOB_2 dicPos_Spec
- add dicPos, dic
- mov LOC_0 dicPos_Spec, dicPos
- mov LOC_0 dic_Spec, dic
-
- mov x1_L, GLOB_2 pb
- mov t0, 1
- shl t0, x1_L
- dec t0
- mov LOC_0 pbMask, t0
-
- ; unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
- ; unsigned lc = p->prop.lc;
- ; unsigned lpMask = ((unsigned)0x100 << p->prop.lp) - ((unsigned)0x100 >> lc);
-
- mov x1_L, GLOB_2 lc
- mov x2, 100h
- mov t0, x2
- shr x2, x1_L
- ; inc x1
- add x1_L, PSHIFT
- mov LOC_0 lc2, x1
- mov x1_L, GLOB_2 lp
- shl t0, x1_L
- sub t0, x2
- mov LOC_0 lpMask, t0
- mov lpMask_reg, t0
-
- ; mov probs, GLOB_2 probs_Spec
- ; add probs, kStartOffset SHL PSHIFT
- mov probs, GLOB_2 probs_1664
- mov LOC_0 probs_Spec, probs
-
- mov t0_R, GLOB_2 dicBufSize
- mov LOC_0 dicBufSize, t0_R
-
- mov x1, GLOB_2 checkDicSize
- mov LOC_0 checkDicSize, x1
-
- mov processedPos, GLOB_2 processedPos_Spec
-
- mov state, GLOB_2 state_Spec
- shl state, PSHIFT
-
- mov buf, GLOB_2 buf_Spec
- mov range, GLOB_2 range_Spec
- mov cod, GLOB_2 code_Spec
- mov kBitModelTotal_reg, kBitModelTotal
- xor sym, sym
-
- ; if (processedPos != 0 || checkDicSize != 0)
- or x1, processedPos
- jz @f
-
- add t0_R, dic
- cmp dicPos, dic
- cmovnz t0_R, dicPos
- movzx sym, byte ptr[t0_R - 1]
-
-@@:
- IsMatchBranch_Pre
- cmp state, 4 * PMULT
- jb lit_end
- cmp state, kNumLitStates * PMULT
- jb lit_matched_end
- jmp lz_end
-
-
-
-
-; ---------- LITERAL ----------
-MY_ALIGN_64
-lit_start:
- xor state, state
-lit_start_2:
- LIT_PROBS lpMask_reg
-
- ifdef _LZMA_SIZE_OPT
-
- PLOAD x1, probs + 1 * PMULT
- mov sym, 1
-MY_ALIGN_16
-lit_loop:
- BIT_1 x1, x2
- mov x1, x2
- cmp sym, 127
- jbe lit_loop
-
- else
-
- BIT_0 x1, x2
- BIT_1 x2, x1
- BIT_1 x1, x2
- BIT_1 x2, x1
- BIT_1 x1, x2
- BIT_1 x2, x1
- BIT_1 x1, x2
-
- endif
-
- BIT_2 x2, 256 - 1
-
- ; mov dic, LOC dic_Spec
- mov probs, LOC probs_Spec
- IsMatchBranch_Pre
- mov byte ptr[dicPos], sym_L
- inc dicPos
-
- CheckLimits
-lit_end:
- IF_BIT_0_NOUP probs_state_R, pbPos_R, IsMatch, lit_start
-
- ; jmp IsMatch_label
-
-; ---------- MATCHES ----------
-; MY_ALIGN_32
-IsMatch_label:
- UPDATE_1 probs_state_R, pbPos_R, IsMatch
- IF_BIT_1 probs_state_R, 0, IsRep, IsRep_label
-
- add probs, LenCoder * PMULT
- add state, kNumStates * PMULT
-
-; ---------- LEN DECODE ----------
-len_decode:
- mov len_temp, 8 - 1 - kMatchMinLen
- IF_BIT_0_NOUP probs, 0, 0, len_mid_0
- UPDATE_1 probs, 0, 0
- add probs, (1 SHL (kLenNumLowBits + PSHIFT))
- mov len_temp, -1 - kMatchMinLen
- IF_BIT_0_NOUP probs, 0, 0, len_mid_0
- UPDATE_1 probs, 0, 0
- add probs, LenHigh * PMULT - (1 SHL (kLenNumLowBits + PSHIFT))
- mov sym, 1
- PLOAD x1, probs + 1 * PMULT
-
-MY_ALIGN_32
-len8_loop:
- BIT_1 x1, x2
- mov x1, x2
- cmp sym, 64
- jb len8_loop
-
- mov len_temp, (kLenNumHighSymbols - kLenNumLowSymbols * 2) - 1 - kMatchMinLen
- jmp len_mid_2
-
-MY_ALIGN_32
-len_mid_0:
- UPDATE_0 probs, 0, 0
- add probs, pbPos_R
- BIT_0 x2, x1
-len_mid_2:
- BIT_1 x1, x2
- BIT_2 x2, len_temp
- mov probs, LOC probs_Spec
- cmp state, kNumStates * PMULT
- jb copy_match
-
-
-; ---------- DECODE DISTANCE ----------
- ; probs + PosSlot + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
-
- mov t0, 3 + kMatchMinLen
- cmp sym, 3 + kMatchMinLen
- cmovb t0, sym
- add probs, PosSlot * PMULT - (kMatchMinLen SHL (kNumPosSlotBits + PSHIFT))
- shl t0, (kNumPosSlotBits + PSHIFT)
- add probs, t0_R
-
- ; sym = Len
- ; mov LOC remainLen, sym
- mov len_temp, sym
-
- ifdef _LZMA_SIZE_OPT
-
- PLOAD x1, probs + 1 * PMULT
- mov sym, 1
-MY_ALIGN_16
-slot_loop:
- BIT_1 x1, x2
- mov x1, x2
- cmp sym, 32
- jb slot_loop
-
- else
-
- BIT_0 x1, x2
- BIT_1 x2, x1
- BIT_1 x1, x2
- BIT_1 x2, x1
- BIT_1 x1, x2
-
- endif
-
- mov x1, sym
- BIT_2 x2, 64-1
-
- and sym, 3
- mov probs, LOC probs_Spec
- cmp x1, 32 + kEndPosModelIndex / 2
- jb short_dist
-
- ; unsigned numDirectBits = (unsigned)(((distance >> 1) - 1));
- sub x1, (32 + 1 + kNumAlignBits)
- ; distance = (2 | (distance & 1));
- or sym, 2
- PLOAD x2, probs + 1 * PMULT
- shl sym, kNumAlignBits + 1
- lea sym2_R, [probs + 2 * PMULT]
-
- jmp direct_norm
- ; lea t1, [sym_R + (1 SHL kNumAlignBits)]
- ; cmp range, kTopValue
- ; jb direct_norm
-
-; ---------- DIRECT DISTANCE ----------
-MY_ALIGN_32
-direct_loop:
- shr range, 1
- mov t0, cod
- sub cod, range
- cmovs cod, t0
- cmovns sym, t1
-
- comment ~
- sub cod, range
- mov x2, cod
- sar x2, 31
- lea sym, dword ptr [r2 + sym_R * 2 + 1]
- and x2, range
- add cod, x2
- ~
- dec x1
- je direct_end
-
- add sym, sym
-direct_norm:
- lea t1, [sym_R + (1 SHL kNumAlignBits)]
- cmp range, kTopValue
- jae near ptr direct_loop
- ; we align for 32 here with "near ptr" command above
- NORM_2
- jmp direct_loop
-
-MY_ALIGN_32
-direct_end:
- ; prob = + kAlign;
- ; distance <<= kNumAlignBits;
- REV_0 x2, x1
- REV_1 x1, x2, 2
- REV_1 x2, x1, 4
- REV_2 x1, 8
-
-decode_dist_end:
-
- ; if (distance >= (checkDicSize == 0 ? processedPos: checkDicSize))
-
- mov t0, LOC checkDicSize
- test t0, t0
- cmove t0, processedPos
- cmp sym, t0
- jae end_of_payload
-
- ; rep3 = rep2;
- ; rep2 = rep1;
- ; rep1 = rep0;
- ; rep0 = distance + 1;
-
- inc sym
- mov t0, LOC rep0
- mov t1, LOC rep1
- mov x1, LOC rep2
- mov LOC rep0, sym
- ; mov sym, LOC remainLen
- mov sym, len_temp
- mov LOC rep1, t0
- mov LOC rep2, t1
- mov LOC rep3, x1
-
- ; state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
- cmp state, (kNumStates + kNumLitStates) * PMULT
- mov state, kNumLitStates * PMULT
- mov t0, (kNumLitStates + 3) * PMULT
- cmovae state, t0
-
-
-; ---------- COPY MATCH ----------
-copy_match:
-
- ; len += kMatchMinLen;
- ; add sym, kMatchMinLen
-
- ; if ((rem = limit - dicPos) == 0)
- ; {
- ; p->dicPos = dicPos;
- ; return SZ_ERROR_DATA;
- ; }
- mov cnt_R, LOC limit
- sub cnt_R, dicPos
- jz fin_ERROR
-
- ; curLen = ((rem < len) ? (unsigned)rem : len);
- cmp cnt_R, sym_R
- ; cmovae cnt_R, sym_R ; 64-bit
- cmovae cnt, sym ; 32-bit
-
- mov dic, LOC dic_Spec
- mov x1, LOC rep0
-
- mov t0_R, dicPos
- add dicPos, cnt_R
- ; processedPos += curLen;
- add processedPos, cnt
- ; len -= curLen;
- sub sym, cnt
- mov LOC remainLen, sym
-
- sub t0_R, dic
-
- ; pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0);
- sub t0_R, r1
- jae @f
-
- mov r1, LOC dicBufSize
- add t0_R, r1
- sub r1, t0_R
- cmp cnt_R, r1
- ja copy_match_cross
-@@:
- ; if (curLen <= dicBufSize - pos)
-
-; ---------- COPY MATCH FAST ----------
- ; Byte *dest = dic + dicPos;
- ; mov r1, dic
- ; ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
- ; sub t0_R, dicPos
- ; dicPos += curLen;
-
- ; const Byte *lim = dest + curLen;
- add t0_R, dic
- movzx sym, byte ptr[t0_R]
- add t0_R, cnt_R
- neg cnt_R
- ; lea r1, [dicPos - 1]
-copy_common:
- dec dicPos
- ; cmp LOC rep0, 1
- ; je rep0Label
-
- ; t0_R - src_lim
- ; r1 - dest_lim - 1
- ; cnt_R - (-cnt)
-
- IsMatchBranch_Pre
- inc cnt_R
- jz copy_end
-MY_ALIGN_16
-@@:
- mov byte ptr[cnt_R * 1 + dicPos], sym_L
- movzx sym, byte ptr[cnt_R * 1 + t0_R]
- inc cnt_R
- jnz @b
-
-copy_end:
-lz_end_match:
- mov byte ptr[dicPos], sym_L
- inc dicPos
-
- ; IsMatchBranch_Pre
- CheckLimits
-lz_end:
- IF_BIT_1_NOUP probs_state_R, pbPos_R, IsMatch, IsMatch_label
-
-
-
-; ---------- LITERAL MATCHED ----------
-
- LIT_PROBS LOC lpMask
-
- ; matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
- mov x1, LOC rep0
- ; mov dic, LOC dic_Spec
- mov LOC dicPos_Spec, dicPos
-
- ; state -= (state < 10) ? 3 : 6;
- lea t0, [state_R - 6 * PMULT]
- sub state, 3 * PMULT
- cmp state, 7 * PMULT
- cmovae state, t0
-
- sub dicPos, dic
- sub dicPos, r1
- jae @f
- add dicPos, LOC dicBufSize
-@@:
- comment ~
- xor t0, t0
- sub dicPos, r1
- cmovb t0_R, LOC dicBufSize
- ~
-
- movzx match, byte ptr[dic + dicPos * 1]
-
- ifdef _LZMA_SIZE_OPT
-
- mov offs, 256 * PMULT
- shl match, (PSHIFT + 1)
- mov bit, match
- mov sym, 1
-MY_ALIGN_16
-litm_loop:
- LITM
- cmp sym, 256
- jb litm_loop
- sub sym, 256
-
- else
-
- LITM_0
- LITM
- LITM
- LITM
- LITM
- LITM
- LITM
- LITM_2
-
- endif
-
- mov probs, LOC probs_Spec
- IsMatchBranch_Pre
- ; mov dic, LOC dic_Spec
- mov dicPos, LOC dicPos_Spec
- mov byte ptr[dicPos], sym_L
- inc dicPos
-
- CheckLimits
-lit_matched_end:
- IF_BIT_1_NOUP probs_state_R, pbPos_R, IsMatch, IsMatch_label
- ; IsMatchBranch
- mov lpMask_reg, LOC lpMask
- sub state, 3 * PMULT
- jmp lit_start_2
-
-
-
-; ---------- REP 0 LITERAL ----------
-MY_ALIGN_32
-IsRep0Short_label:
- UPDATE_0 probs_state_R, pbPos_R, IsRep0Long
-
- ; dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
- mov dic, LOC dic_Spec
- mov t0_R, dicPos
- mov probBranch, LOC rep0
- sub t0_R, dic
-
- sub probs, RepLenCoder * PMULT
- inc processedPos
- ; state = state < kNumLitStates ? 9 : 11;
- or state, 1 * PMULT
- IsMatchBranch_Pre
-
- sub t0_R, probBranch_R
- jae @f
- add t0_R, LOC dicBufSize
-@@:
- movzx sym, byte ptr[dic + t0_R * 1]
- jmp lz_end_match
-
-
-MY_ALIGN_32
-IsRep_label:
- UPDATE_1 probs_state_R, 0, IsRep
-
- ; The (checkDicSize == 0 && processedPos == 0) case was checked before in LzmaDec.c with kBadRepCode.
- ; So we don't check it here.
-
- ; mov t0, processedPos
- ; or t0, LOC checkDicSize
- ; jz fin_ERROR_2
-
- ; state = state < kNumLitStates ? 8 : 11;
- cmp state, kNumLitStates * PMULT
- mov state, 8 * PMULT
- mov probBranch, 11 * PMULT
- cmovae state, probBranch
-
- ; prob = probs + RepLenCoder;
- add probs, RepLenCoder * PMULT
-
- IF_BIT_1 probs_state_R, 0, IsRepG0, IsRepG0_label
- IF_BIT_0_NOUP probs_state_R, pbPos_R, IsRep0Long, IsRep0Short_label
- UPDATE_1 probs_state_R, pbPos_R, IsRep0Long
- jmp len_decode
-
-MY_ALIGN_32
-IsRepG0_label:
- UPDATE_1 probs_state_R, 0, IsRepG0
- mov dist2, LOC rep0
- mov dist, LOC rep1
- mov LOC rep1, dist2
-
- IF_BIT_1 probs_state_R, 0, IsRepG1, IsRepG1_label
- mov LOC rep0, dist
- jmp len_decode
-
-; MY_ALIGN_32
-IsRepG1_label:
- UPDATE_1 probs_state_R, 0, IsRepG1
- mov dist2, LOC rep2
- mov LOC rep2, dist
-
- IF_BIT_1 probs_state_R, 0, IsRepG2, IsRepG2_label
- mov LOC rep0, dist2
- jmp len_decode
-
-; MY_ALIGN_32
-IsRepG2_label:
- UPDATE_1 probs_state_R, 0, IsRepG2
- mov dist, LOC rep3
- mov LOC rep3, dist2
- mov LOC rep0, dist
- jmp len_decode
-
-
-
-; ---------- SPEC SHORT DISTANCE ----------
-
-MY_ALIGN_32
-short_dist:
- sub x1, 32 + 1
- jbe decode_dist_end
- or sym, 2
- shl sym, x1_L
- lea sym_R, [probs + sym_R * PMULT + SpecPos * PMULT + 1 * PMULT]
- mov sym2, PMULT ; step
-MY_ALIGN_32
-spec_loop:
- REV_1_VAR x2
- dec x1
- jnz spec_loop
-
- mov probs, LOC probs_Spec
- sub sym, sym2
- sub sym, SpecPos * PMULT
- sub sym_R, probs
- shr sym, PSHIFT
-
- jmp decode_dist_end
-
-
-; ---------- COPY MATCH CROSS ----------
-copy_match_cross:
- ; t0_R - src pos
- ; r1 - len to dicBufSize
- ; cnt_R - total copy len
-
- mov t1_R, t0_R ; srcPos
- mov t0_R, dic
- mov r1, LOC dicBufSize ;
- neg cnt_R
-@@:
- movzx sym, byte ptr[t1_R * 1 + t0_R]
- inc t1_R
- mov byte ptr[cnt_R * 1 + dicPos], sym_L
- inc cnt_R
- cmp t1_R, r1
- jne @b
-
- movzx sym, byte ptr[t0_R]
- sub t0_R, cnt_R
- jmp copy_common
-
-
-
-
-fin_ERROR:
- mov LOC remainLen, len_temp
-; fin_ERROR_2:
- mov sym, 1
- jmp fin
-
-end_of_payload:
- cmp sym, 0FFFFFFFFh ; -1
- jne fin_ERROR
-
- mov LOC remainLen, kMatchSpecLenStart
- sub state, kNumStates * PMULT
-
-fin_OK:
- xor sym, sym
-
-fin:
- NORM
-
- mov r1, LOC lzmaPtr
-
- sub dicPos, LOC dic_Spec
- mov GLOB dicPos_Spec, dicPos
- mov GLOB buf_Spec, buf
- mov GLOB range_Spec, range
- mov GLOB code_Spec, cod
- shr state, PSHIFT
- mov GLOB state_Spec, state
- mov GLOB processedPos_Spec, processedPos
-
- RESTORE_VAR(remainLen)
- RESTORE_VAR(rep0)
- RESTORE_VAR(rep1)
- RESTORE_VAR(rep2)
- RESTORE_VAR(rep3)
-
- mov x0, sym
-
- mov RSP, LOC Old_RSP
-
-MY_POP_PRESERVED_REGS
-MY_ENDP
-
-_TEXT$LZMADECOPT ENDS
-
-end
+; LzmaDecOpt.asm -- ASM version of LzmaDec_DecodeReal_3() function
+; 2021-02-23: Igor Pavlov : Public domain
+;
+; 3 - is the code compatibility version of LzmaDec_DecodeReal_*()
+; function for check at link time.
+; That code is tightly coupled with LzmaDec_TryDummy()
+; and with another functions in LzmaDec.c file.
+; CLzmaDec structure, (probs) array layout, input and output of
+; LzmaDec_DecodeReal_*() must be equal in both versions (C / ASM).
+
+ifndef x64
+; x64=1
+; .err <x64_IS_REQUIRED>
+endif
+
+include 7zAsm.asm
+
+MY_ASM_START
+
+_TEXT$LZMADECOPT SEGMENT ALIGN(64) 'CODE'
+
+MY_ALIGN macro num:req
+ align num
+endm
+
+MY_ALIGN_16 macro
+ MY_ALIGN 16
+endm
+
+MY_ALIGN_32 macro
+ MY_ALIGN 32
+endm
+
+MY_ALIGN_64 macro
+ MY_ALIGN 64
+endm
+
+
+; _LZMA_SIZE_OPT equ 1
+
+; _LZMA_PROB32 equ 1
+
+ifdef _LZMA_PROB32
+ PSHIFT equ 2
+ PLOAD macro dest, mem
+ mov dest, dword ptr [mem]
+ endm
+ PSTORE macro src, mem
+ mov dword ptr [mem], src
+ endm
+else
+ PSHIFT equ 1
+ PLOAD macro dest, mem
+ movzx dest, word ptr [mem]
+ endm
+ PSTORE macro src, mem
+ mov word ptr [mem], @CatStr(src, _W)
+ endm
+endif
+
+PMULT equ (1 SHL PSHIFT)
+PMULT_HALF equ (1 SHL (PSHIFT - 1))
+PMULT_2 equ (1 SHL (PSHIFT + 1))
+
+kMatchSpecLen_Error_Data equ (1 SHL 9)
+
+; x0 range
+; x1 pbPos / (prob) TREE
+; x2 probBranch / prm (MATCHED) / pbPos / cnt
+; x3 sym
+;====== r4 === RSP
+; x5 cod
+; x6 t1 NORM_CALC / probs_state / dist
+; x7 t0 NORM_CALC / prob2 IF_BIT_1
+; x8 state
+; x9 match (MATCHED) / sym2 / dist2 / lpMask_reg
+; x10 kBitModelTotal_reg
+; r11 probs
+; x12 offs (MATCHED) / dic / len_temp
+; x13 processedPos
+; x14 bit (MATCHED) / dicPos
+; r15 buf
+
+
+cod equ x5
+cod_L equ x5_L
+range equ x0
+state equ x8
+state_R equ r8
+buf equ r15
+processedPos equ x13
+kBitModelTotal_reg equ x10
+
+probBranch equ x2
+probBranch_R equ r2
+probBranch_W equ x2_W
+
+pbPos equ x1
+pbPos_R equ r1
+
+cnt equ x2
+cnt_R equ r2
+
+lpMask_reg equ x9
+dicPos equ r14
+
+sym equ x3
+sym_R equ r3
+sym_L equ x3_L
+
+probs equ r11
+dic equ r12
+
+t0 equ x7
+t0_W equ x7_W
+t0_R equ r7
+
+prob2 equ t0
+prob2_W equ t0_W
+
+t1 equ x6
+t1_R equ r6
+
+probs_state equ t1
+probs_state_R equ t1_R
+
+prm equ r2
+match equ x9
+match_R equ r9
+offs equ x12
+offs_R equ r12
+bit equ x14
+bit_R equ r14
+
+sym2 equ x9
+sym2_R equ r9
+
+len_temp equ x12
+
+dist equ sym
+dist2 equ x9
+
+
+
+kNumBitModelTotalBits equ 11
+kBitModelTotal equ (1 SHL kNumBitModelTotalBits)
+kNumMoveBits equ 5
+kBitModelOffset equ ((1 SHL kNumMoveBits) - 1)
+kTopValue equ (1 SHL 24)
+
+NORM_2 macro
+ ; movzx t0, BYTE PTR [buf]
+ shl cod, 8
+ mov cod_L, BYTE PTR [buf]
+ shl range, 8
+ ; or cod, t0
+ inc buf
+endm
+
+
+NORM macro
+ cmp range, kTopValue
+ jae SHORT @F
+ NORM_2
+@@:
+endm
+
+
+; ---------- Branch MACROS ----------
+
+UPDATE_0 macro probsArray:req, probOffset:req, probDisp:req
+ mov prob2, kBitModelTotal_reg
+ sub prob2, probBranch
+ shr prob2, kNumMoveBits
+ add probBranch, prob2
+ PSTORE probBranch, probOffset * 1 + probsArray + probDisp * PMULT
+endm
+
+
+UPDATE_1 macro probsArray:req, probOffset:req, probDisp:req
+ sub prob2, range
+ sub cod, range
+ mov range, prob2
+ mov prob2, probBranch
+ shr probBranch, kNumMoveBits
+ sub prob2, probBranch
+ PSTORE prob2, probOffset * 1 + probsArray + probDisp * PMULT
+endm
+
+
+CMP_COD macro probsArray:req, probOffset:req, probDisp:req
+ PLOAD probBranch, probOffset * 1 + probsArray + probDisp * PMULT
+ NORM
+ mov prob2, range
+ shr range, kNumBitModelTotalBits
+ imul range, probBranch
+ cmp cod, range
+endm
+
+
+IF_BIT_1_NOUP macro probsArray:req, probOffset:req, probDisp:req, toLabel:req
+ CMP_COD probsArray, probOffset, probDisp
+ jae toLabel
+endm
+
+
+IF_BIT_1 macro probsArray:req, probOffset:req, probDisp:req, toLabel:req
+ IF_BIT_1_NOUP probsArray, probOffset, probDisp, toLabel
+ UPDATE_0 probsArray, probOffset, probDisp
+endm
+
+
+IF_BIT_0_NOUP macro probsArray:req, probOffset:req, probDisp:req, toLabel:req
+ CMP_COD probsArray, probOffset, probDisp
+ jb toLabel
+endm
+
+
+; ---------- CMOV MACROS ----------
+
+NORM_CALC macro prob:req
+ NORM
+ mov t0, range
+ shr range, kNumBitModelTotalBits
+ imul range, prob
+ sub t0, range
+ mov t1, cod
+ sub cod, range
+endm
+
+
+PUP macro prob:req, probPtr:req
+ sub t0, prob
+ ; only sar works for both 16/32 bit prob modes
+ sar t0, kNumMoveBits
+ add t0, prob
+ PSTORE t0, probPtr
+endm
+
+
+PUP_SUB macro prob:req, probPtr:req, symSub:req
+ sbb sym, symSub
+ PUP prob, probPtr
+endm
+
+
+PUP_COD macro prob:req, probPtr:req, symSub:req
+ mov t0, kBitModelOffset
+ cmovb cod, t1
+ mov t1, sym
+ cmovb t0, kBitModelTotal_reg
+ PUP_SUB prob, probPtr, symSub
+endm
+
+
+BIT_0 macro prob:req, probNext:req
+ PLOAD prob, probs + 1 * PMULT
+ PLOAD probNext, probs + 1 * PMULT_2
+
+ NORM_CALC prob
+
+ cmovae range, t0
+ PLOAD t0, probs + 1 * PMULT_2 + PMULT
+ cmovae probNext, t0
+ mov t0, kBitModelOffset
+ cmovb cod, t1
+ cmovb t0, kBitModelTotal_reg
+ mov sym, 2
+ PUP_SUB prob, probs + 1 * PMULT, 0 - 1
+endm
+
+
+BIT_1 macro prob:req, probNext:req
+ PLOAD probNext, probs + sym_R * PMULT_2
+ add sym, sym
+
+ NORM_CALC prob
+
+ cmovae range, t0
+ PLOAD t0, probs + sym_R * PMULT + PMULT
+ cmovae probNext, t0
+ PUP_COD prob, probs + t1_R * PMULT_HALF, 0 - 1
+endm
+
+
+BIT_2 macro prob:req, symSub:req
+ add sym, sym
+
+ NORM_CALC prob
+
+ cmovae range, t0
+ PUP_COD prob, probs + t1_R * PMULT_HALF, symSub
+endm
+
+
+; ---------- MATCHED LITERAL ----------
+
+LITM_0 macro
+ mov offs, 256 * PMULT
+ shl match, (PSHIFT + 1)
+ mov bit, offs
+ and bit, match
+ PLOAD x1, probs + 256 * PMULT + bit_R * 1 + 1 * PMULT
+ lea prm, [probs + 256 * PMULT + bit_R * 1 + 1 * PMULT]
+ ; lea prm, [probs + 256 * PMULT + 1 * PMULT]
+ ; add prm, bit_R
+ xor offs, bit
+ add match, match
+
+ NORM_CALC x1
+
+ cmovae offs, bit
+ mov bit, match
+ cmovae range, t0
+ mov t0, kBitModelOffset
+ cmovb cod, t1
+ cmovb t0, kBitModelTotal_reg
+ mov sym, 0
+ PUP_SUB x1, prm, -2-1
+endm
+
+
+LITM macro
+ and bit, offs
+ lea prm, [probs + offs_R * 1]
+ add prm, bit_R
+ PLOAD x1, prm + sym_R * PMULT
+ xor offs, bit
+ add sym, sym
+ add match, match
+
+ NORM_CALC x1
+
+ cmovae offs, bit
+ mov bit, match
+ cmovae range, t0
+ PUP_COD x1, prm + t1_R * PMULT_HALF, - 1
+endm
+
+
+LITM_2 macro
+ and bit, offs
+ lea prm, [probs + offs_R * 1]
+ add prm, bit_R
+ PLOAD x1, prm + sym_R * PMULT
+ add sym, sym
+
+ NORM_CALC x1
+
+ cmovae range, t0
+ PUP_COD x1, prm + t1_R * PMULT_HALF, 256 - 1
+endm
+
+
+; ---------- REVERSE BITS ----------
+
+REV_0 macro prob:req, probNext:req
+ ; PLOAD prob, probs + 1 * PMULT
+ ; lea sym2_R, [probs + 2 * PMULT]
+ ; PLOAD probNext, probs + 2 * PMULT
+ PLOAD probNext, sym2_R
+
+ NORM_CALC prob
+
+ cmovae range, t0
+ PLOAD t0, probs + 3 * PMULT
+ cmovae probNext, t0
+ cmovb cod, t1
+ mov t0, kBitModelOffset
+ cmovb t0, kBitModelTotal_reg
+ lea t1_R, [probs + 3 * PMULT]
+ cmovae sym2_R, t1_R
+ PUP prob, probs + 1 * PMULT
+endm
+
+
+REV_1 macro prob:req, probNext:req, step:req
+ add sym2_R, step * PMULT
+ PLOAD probNext, sym2_R
+
+ NORM_CALC prob
+
+ cmovae range, t0
+ PLOAD t0, sym2_R + step * PMULT
+ cmovae probNext, t0
+ cmovb cod, t1
+ mov t0, kBitModelOffset
+ cmovb t0, kBitModelTotal_reg
+ lea t1_R, [sym2_R + step * PMULT]
+ cmovae sym2_R, t1_R
+ PUP prob, t1_R - step * PMULT_2
+endm
+
+
+REV_2 macro prob:req, step:req
+ sub sym2_R, probs
+ shr sym2, PSHIFT
+ or sym, sym2
+
+ NORM_CALC prob
+
+ cmovae range, t0
+ lea t0, [sym - step]
+ cmovb sym, t0
+ cmovb cod, t1
+ mov t0, kBitModelOffset
+ cmovb t0, kBitModelTotal_reg
+ PUP prob, probs + sym2_R * PMULT
+endm
+
+
+REV_1_VAR macro prob:req
+ PLOAD prob, sym_R
+ mov probs, sym_R
+ add sym_R, sym2_R
+
+ NORM_CALC prob
+
+ cmovae range, t0
+ lea t0_R, [sym_R + 1 * sym2_R]
+ cmovae sym_R, t0_R
+ mov t0, kBitModelOffset
+ cmovb cod, t1
+ ; mov t1, kBitModelTotal
+ ; cmovb t0, t1
+ cmovb t0, kBitModelTotal_reg
+ add sym2, sym2
+ PUP prob, probs
+endm
+
+
+
+
+LIT_PROBS macro lpMaskParam:req
+ ; prob += (UInt32)3 * ((((processedPos << 8) + dic[(dicPos == 0 ? dicBufSize : dicPos) - 1]) & lpMask) << lc);
+ mov t0, processedPos
+ shl t0, 8
+ add sym, t0
+ and sym, lpMaskParam
+ add probs_state_R, pbPos_R
+ mov x1, LOC lc2
+ lea sym, dword ptr[sym_R + 2 * sym_R]
+ add probs, Literal * PMULT
+ shl sym, x1_L
+ add probs, sym_R
+ UPDATE_0 probs_state_R, 0, IsMatch
+ inc processedPos
+endm
+
+
+
+kNumPosBitsMax equ 4
+kNumPosStatesMax equ (1 SHL kNumPosBitsMax)
+
+kLenNumLowBits equ 3
+kLenNumLowSymbols equ (1 SHL kLenNumLowBits)
+kLenNumHighBits equ 8
+kLenNumHighSymbols equ (1 SHL kLenNumHighBits)
+kNumLenProbs equ (2 * kLenNumLowSymbols * kNumPosStatesMax + kLenNumHighSymbols)
+
+LenLow equ 0
+LenChoice equ LenLow
+LenChoice2 equ (LenLow + kLenNumLowSymbols)
+LenHigh equ (LenLow + 2 * kLenNumLowSymbols * kNumPosStatesMax)
+
+kNumStates equ 12
+kNumStates2 equ 16
+kNumLitStates equ 7
+
+kStartPosModelIndex equ 4
+kEndPosModelIndex equ 14
+kNumFullDistances equ (1 SHL (kEndPosModelIndex SHR 1))
+
+kNumPosSlotBits equ 6
+kNumLenToPosStates equ 4
+
+kNumAlignBits equ 4
+kAlignTableSize equ (1 SHL kNumAlignBits)
+
+kMatchMinLen equ 2
+kMatchSpecLenStart equ (kMatchMinLen + kLenNumLowSymbols * 2 + kLenNumHighSymbols)
+
+kStartOffset equ 1664
+SpecPos equ (-kStartOffset)
+IsRep0Long equ (SpecPos + kNumFullDistances)
+RepLenCoder equ (IsRep0Long + (kNumStates2 SHL kNumPosBitsMax))
+LenCoder equ (RepLenCoder + kNumLenProbs)
+IsMatch equ (LenCoder + kNumLenProbs)
+kAlign equ (IsMatch + (kNumStates2 SHL kNumPosBitsMax))
+IsRep equ (kAlign + kAlignTableSize)
+IsRepG0 equ (IsRep + kNumStates)
+IsRepG1 equ (IsRepG0 + kNumStates)
+IsRepG2 equ (IsRepG1 + kNumStates)
+PosSlot equ (IsRepG2 + kNumStates)
+Literal equ (PosSlot + (kNumLenToPosStates SHL kNumPosSlotBits))
+NUM_BASE_PROBS equ (Literal + kStartOffset)
+
+if kAlign ne 0
+ .err <Stop_Compiling_Bad_LZMA_kAlign>
+endif
+
+if NUM_BASE_PROBS ne 1984
+ .err <Stop_Compiling_Bad_LZMA_PROBS>
+endif
+
+
+PTR_FIELD equ dq ?
+
+CLzmaDec_Asm struct
+ lc db ?
+ lp db ?
+ pb db ?
+ _pad_ db ?
+ dicSize dd ?
+
+ probs_Spec PTR_FIELD
+ probs_1664 PTR_FIELD
+ dic_Spec PTR_FIELD
+ dicBufSize PTR_FIELD
+ dicPos_Spec PTR_FIELD
+ buf_Spec PTR_FIELD
+
+ range_Spec dd ?
+ code_Spec dd ?
+ processedPos_Spec dd ?
+ checkDicSize dd ?
+ rep0 dd ?
+ rep1 dd ?
+ rep2 dd ?
+ rep3 dd ?
+ state_Spec dd ?
+ remainLen dd ?
+CLzmaDec_Asm ends
+
+
+CLzmaDec_Asm_Loc struct
+ OLD_RSP PTR_FIELD
+ lzmaPtr PTR_FIELD
+ _pad0_ PTR_FIELD
+ _pad1_ PTR_FIELD
+ _pad2_ PTR_FIELD
+ dicBufSize PTR_FIELD
+ probs_Spec PTR_FIELD
+ dic_Spec PTR_FIELD
+
+ limit PTR_FIELD
+ bufLimit PTR_FIELD
+ lc2 dd ?
+ lpMask dd ?
+ pbMask dd ?
+ checkDicSize dd ?
+
+ _pad_ dd ?
+ remainLen dd ?
+ dicPos_Spec PTR_FIELD
+ rep0 dd ?
+ rep1 dd ?
+ rep2 dd ?
+ rep3 dd ?
+CLzmaDec_Asm_Loc ends
+
+
+GLOB_2 equ [sym_R].CLzmaDec_Asm.
+GLOB equ [r1].CLzmaDec_Asm.
+LOC_0 equ [r0].CLzmaDec_Asm_Loc.
+LOC equ [RSP].CLzmaDec_Asm_Loc.
+
+
+COPY_VAR macro name
+ mov t0, GLOB_2 name
+ mov LOC_0 name, t0
+endm
+
+
+RESTORE_VAR macro name
+ mov t0, LOC name
+ mov GLOB name, t0
+endm
+
+
+
+IsMatchBranch_Pre macro reg
+ ; prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+ mov pbPos, LOC pbMask
+ and pbPos, processedPos
+ shl pbPos, (kLenNumLowBits + 1 + PSHIFT)
+ lea probs_state_R, [probs + 1 * state_R]
+endm
+
+
+IsMatchBranch macro reg
+ IsMatchBranch_Pre
+ IF_BIT_1 probs_state_R, pbPos_R, IsMatch, IsMatch_label
+endm
+
+
+CheckLimits macro reg
+ cmp buf, LOC bufLimit
+ jae fin_OK
+ cmp dicPos, LOC limit
+ jae fin_OK
+endm
+
+
+
+; RSP is (16x + 8) bytes aligned in WIN64-x64
+; LocalSize equ ((((SIZEOF CLzmaDec_Asm_Loc) + 7) / 16 * 16) + 8)
+
+PARAM_lzma equ REG_ABI_PARAM_0
+PARAM_limit equ REG_ABI_PARAM_1
+PARAM_bufLimit equ REG_ABI_PARAM_2
+
+; MY_ALIGN_64
+MY_PROC LzmaDec_DecodeReal_3, 3
+MY_PUSH_PRESERVED_ABI_REGS
+
+ lea r0, [RSP - (SIZEOF CLzmaDec_Asm_Loc)]
+ and r0, -128
+ mov r5, RSP
+ mov RSP, r0
+ mov LOC_0 Old_RSP, r5
+ mov LOC_0 lzmaPtr, PARAM_lzma
+
+ mov LOC_0 remainLen, 0 ; remainLen must be ZERO
+
+ mov LOC_0 bufLimit, PARAM_bufLimit
+ mov sym_R, PARAM_lzma ; CLzmaDec_Asm_Loc pointer for GLOB_2
+ mov dic, GLOB_2 dic_Spec
+ add PARAM_limit, dic
+ mov LOC_0 limit, PARAM_limit
+
+ COPY_VAR(rep0)
+ COPY_VAR(rep1)
+ COPY_VAR(rep2)
+ COPY_VAR(rep3)
+
+ mov dicPos, GLOB_2 dicPos_Spec
+ add dicPos, dic
+ mov LOC_0 dicPos_Spec, dicPos
+ mov LOC_0 dic_Spec, dic
+
+ mov x1_L, GLOB_2 pb
+ mov t0, 1
+ shl t0, x1_L
+ dec t0
+ mov LOC_0 pbMask, t0
+
+ ; unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
+ ; unsigned lc = p->prop.lc;
+ ; unsigned lpMask = ((unsigned)0x100 << p->prop.lp) - ((unsigned)0x100 >> lc);
+
+ mov x1_L, GLOB_2 lc
+ mov x2, 100h
+ mov t0, x2
+ shr x2, x1_L
+ ; inc x1
+ add x1_L, PSHIFT
+ mov LOC_0 lc2, x1
+ mov x1_L, GLOB_2 lp
+ shl t0, x1_L
+ sub t0, x2
+ mov LOC_0 lpMask, t0
+ mov lpMask_reg, t0
+
+ ; mov probs, GLOB_2 probs_Spec
+ ; add probs, kStartOffset SHL PSHIFT
+ mov probs, GLOB_2 probs_1664
+ mov LOC_0 probs_Spec, probs
+
+ mov t0_R, GLOB_2 dicBufSize
+ mov LOC_0 dicBufSize, t0_R
+
+ mov x1, GLOB_2 checkDicSize
+ mov LOC_0 checkDicSize, x1
+
+ mov processedPos, GLOB_2 processedPos_Spec
+
+ mov state, GLOB_2 state_Spec
+ shl state, PSHIFT
+
+ mov buf, GLOB_2 buf_Spec
+ mov range, GLOB_2 range_Spec
+ mov cod, GLOB_2 code_Spec
+ mov kBitModelTotal_reg, kBitModelTotal
+ xor sym, sym
+
+ ; if (processedPos != 0 || checkDicSize != 0)
+ or x1, processedPos
+ jz @f
+
+ add t0_R, dic
+ cmp dicPos, dic
+ cmovnz t0_R, dicPos
+ movzx sym, byte ptr[t0_R - 1]
+
+@@:
+ IsMatchBranch_Pre
+ cmp state, 4 * PMULT
+ jb lit_end
+ cmp state, kNumLitStates * PMULT
+ jb lit_matched_end
+ jmp lz_end
+
+
+
+
+; ---------- LITERAL ----------
+MY_ALIGN_64
+lit_start:
+ xor state, state
+lit_start_2:
+ LIT_PROBS lpMask_reg
+
+ ifdef _LZMA_SIZE_OPT
+
+ PLOAD x1, probs + 1 * PMULT
+ mov sym, 1
+MY_ALIGN_16
+lit_loop:
+ BIT_1 x1, x2
+ mov x1, x2
+ cmp sym, 127
+ jbe lit_loop
+
+ else
+
+ BIT_0 x1, x2
+ BIT_1 x2, x1
+ BIT_1 x1, x2
+ BIT_1 x2, x1
+ BIT_1 x1, x2
+ BIT_1 x2, x1
+ BIT_1 x1, x2
+
+ endif
+
+ BIT_2 x2, 256 - 1
+
+ ; mov dic, LOC dic_Spec
+ mov probs, LOC probs_Spec
+ IsMatchBranch_Pre
+ mov byte ptr[dicPos], sym_L
+ inc dicPos
+
+ CheckLimits
+lit_end:
+ IF_BIT_0_NOUP probs_state_R, pbPos_R, IsMatch, lit_start
+
+ ; jmp IsMatch_label
+
+; ---------- MATCHES ----------
+; MY_ALIGN_32
+IsMatch_label:
+ UPDATE_1 probs_state_R, pbPos_R, IsMatch
+ IF_BIT_1 probs_state_R, 0, IsRep, IsRep_label
+
+ add probs, LenCoder * PMULT
+ add state, kNumStates * PMULT
+
+; ---------- LEN DECODE ----------
+len_decode:
+ mov len_temp, 8 - 1 - kMatchMinLen
+ IF_BIT_0_NOUP probs, 0, 0, len_mid_0
+ UPDATE_1 probs, 0, 0
+ add probs, (1 SHL (kLenNumLowBits + PSHIFT))
+ mov len_temp, -1 - kMatchMinLen
+ IF_BIT_0_NOUP probs, 0, 0, len_mid_0
+ UPDATE_1 probs, 0, 0
+ add probs, LenHigh * PMULT - (1 SHL (kLenNumLowBits + PSHIFT))
+ mov sym, 1
+ PLOAD x1, probs + 1 * PMULT
+
+MY_ALIGN_32
+len8_loop:
+ BIT_1 x1, x2
+ mov x1, x2
+ cmp sym, 64
+ jb len8_loop
+
+ mov len_temp, (kLenNumHighSymbols - kLenNumLowSymbols * 2) - 1 - kMatchMinLen
+ jmp short len_mid_2 ; we use short here for MASM that doesn't optimize that code as another assembler programs
+
+MY_ALIGN_32
+len_mid_0:
+ UPDATE_0 probs, 0, 0
+ add probs, pbPos_R
+ BIT_0 x2, x1
+len_mid_2:
+ BIT_1 x1, x2
+ BIT_2 x2, len_temp
+ mov probs, LOC probs_Spec
+ cmp state, kNumStates * PMULT
+ jb copy_match
+
+
+; ---------- DECODE DISTANCE ----------
+ ; probs + PosSlot + ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
+
+ mov t0, 3 + kMatchMinLen
+ cmp sym, 3 + kMatchMinLen
+ cmovb t0, sym
+ add probs, PosSlot * PMULT - (kMatchMinLen SHL (kNumPosSlotBits + PSHIFT))
+ shl t0, (kNumPosSlotBits + PSHIFT)
+ add probs, t0_R
+
+ ; sym = Len
+ ; mov LOC remainLen, sym
+ mov len_temp, sym
+
+ ifdef _LZMA_SIZE_OPT
+
+ PLOAD x1, probs + 1 * PMULT
+ mov sym, 1
+MY_ALIGN_16
+slot_loop:
+ BIT_1 x1, x2
+ mov x1, x2
+ cmp sym, 32
+ jb slot_loop
+
+ else
+
+ BIT_0 x1, x2
+ BIT_1 x2, x1
+ BIT_1 x1, x2
+ BIT_1 x2, x1
+ BIT_1 x1, x2
+
+ endif
+
+ mov x1, sym
+ BIT_2 x2, 64-1
+
+ and sym, 3
+ mov probs, LOC probs_Spec
+ cmp x1, 32 + kEndPosModelIndex / 2
+ jb short_dist
+
+ ; unsigned numDirectBits = (unsigned)(((distance >> 1) - 1));
+ sub x1, (32 + 1 + kNumAlignBits)
+ ; distance = (2 | (distance & 1));
+ or sym, 2
+ PLOAD x2, probs + 1 * PMULT
+ shl sym, kNumAlignBits + 1
+ lea sym2_R, [probs + 2 * PMULT]
+
+ jmp direct_norm
+ ; lea t1, [sym_R + (1 SHL kNumAlignBits)]
+ ; cmp range, kTopValue
+ ; jb direct_norm
+
+; ---------- DIRECT DISTANCE ----------
+MY_ALIGN_32
+direct_loop:
+ shr range, 1
+ mov t0, cod
+ sub cod, range
+ cmovs cod, t0
+ cmovns sym, t1
+
+ comment ~
+ sub cod, range
+ mov x2, cod
+ sar x2, 31
+ lea sym, dword ptr [r2 + sym_R * 2 + 1]
+ and x2, range
+ add cod, x2
+ ~
+ dec x1
+ je direct_end
+
+ add sym, sym
+direct_norm:
+ lea t1, [sym_R + (1 SHL kNumAlignBits)]
+ cmp range, kTopValue
+ jae near ptr direct_loop
+ ; we align for 32 here with "near ptr" command above
+ NORM_2
+ jmp direct_loop
+
+MY_ALIGN_32
+direct_end:
+ ; prob = + kAlign;
+ ; distance <<= kNumAlignBits;
+ REV_0 x2, x1
+ REV_1 x1, x2, 2
+ REV_1 x2, x1, 4
+ REV_2 x1, 8
+
+decode_dist_end:
+
+ ; if (distance >= (checkDicSize == 0 ? processedPos: checkDicSize))
+
+ mov t1, LOC rep0
+ mov x1, LOC rep1
+ mov x2, LOC rep2
+
+ mov t0, LOC checkDicSize
+ test t0, t0
+ cmove t0, processedPos
+ cmp sym, t0
+ jae end_of_payload
+ ; jmp end_of_payload ; for debug
+
+ ; rep3 = rep2;
+ ; rep2 = rep1;
+ ; rep1 = rep0;
+ ; rep0 = distance + 1;
+
+ inc sym
+ mov LOC rep0, sym
+ ; mov sym, LOC remainLen
+ mov sym, len_temp
+ mov LOC rep1, t1
+ mov LOC rep2, x1
+ mov LOC rep3, x2
+
+ ; state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
+ cmp state, (kNumStates + kNumLitStates) * PMULT
+ mov state, kNumLitStates * PMULT
+ mov t0, (kNumLitStates + 3) * PMULT
+ cmovae state, t0
+
+
+; ---------- COPY MATCH ----------
+copy_match:
+
+ ; len += kMatchMinLen;
+ ; add sym, kMatchMinLen
+
+ ; if ((rem = limit - dicPos) == 0)
+ ; {
+ ; p->dicPos = dicPos;
+ ; return SZ_ERROR_DATA;
+ ; }
+ mov cnt_R, LOC limit
+ sub cnt_R, dicPos
+ jz fin_dicPos_LIMIT
+
+ ; curLen = ((rem < len) ? (unsigned)rem : len);
+ cmp cnt_R, sym_R
+ ; cmovae cnt_R, sym_R ; 64-bit
+ cmovae cnt, sym ; 32-bit
+
+ mov dic, LOC dic_Spec
+ mov x1, LOC rep0
+
+ mov t0_R, dicPos
+ add dicPos, cnt_R
+ ; processedPos += curLen;
+ add processedPos, cnt
+ ; len -= curLen;
+ sub sym, cnt
+ mov LOC remainLen, sym
+
+ sub t0_R, dic
+
+ ; pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0);
+ sub t0_R, r1
+ jae @f
+
+ mov r1, LOC dicBufSize
+ add t0_R, r1
+ sub r1, t0_R
+ cmp cnt_R, r1
+ ja copy_match_cross
+@@:
+ ; if (curLen <= dicBufSize - pos)
+
+; ---------- COPY MATCH FAST ----------
+ ; Byte *dest = dic + dicPos;
+ ; mov r1, dic
+ ; ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
+ ; sub t0_R, dicPos
+ ; dicPos += curLen;
+
+ ; const Byte *lim = dest + curLen;
+ add t0_R, dic
+ movzx sym, byte ptr[t0_R]
+ add t0_R, cnt_R
+ neg cnt_R
+ ; lea r1, [dicPos - 1]
+copy_common:
+ dec dicPos
+ ; cmp LOC rep0, 1
+ ; je rep0Label
+
+ ; t0_R - src_lim
+ ; r1 - dest_lim - 1
+ ; cnt_R - (-cnt)
+
+ IsMatchBranch_Pre
+ inc cnt_R
+ jz copy_end
+MY_ALIGN_16
+@@:
+ mov byte ptr[cnt_R * 1 + dicPos], sym_L
+ movzx sym, byte ptr[cnt_R * 1 + t0_R]
+ inc cnt_R
+ jnz @b
+
+copy_end:
+lz_end_match:
+ mov byte ptr[dicPos], sym_L
+ inc dicPos
+
+ ; IsMatchBranch_Pre
+ CheckLimits
+lz_end:
+ IF_BIT_1_NOUP probs_state_R, pbPos_R, IsMatch, IsMatch_label
+
+
+
+; ---------- LITERAL MATCHED ----------
+
+ LIT_PROBS LOC lpMask
+
+ ; matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+ mov x1, LOC rep0
+ ; mov dic, LOC dic_Spec
+ mov LOC dicPos_Spec, dicPos
+
+ ; state -= (state < 10) ? 3 : 6;
+ lea t0, [state_R - 6 * PMULT]
+ sub state, 3 * PMULT
+ cmp state, 7 * PMULT
+ cmovae state, t0
+
+ sub dicPos, dic
+ sub dicPos, r1
+ jae @f
+ add dicPos, LOC dicBufSize
+@@:
+ comment ~
+ xor t0, t0
+ sub dicPos, r1
+ cmovb t0_R, LOC dicBufSize
+ ~
+
+ movzx match, byte ptr[dic + dicPos * 1]
+
+ ifdef _LZMA_SIZE_OPT
+
+ mov offs, 256 * PMULT
+ shl match, (PSHIFT + 1)
+ mov bit, match
+ mov sym, 1
+MY_ALIGN_16
+litm_loop:
+ LITM
+ cmp sym, 256
+ jb litm_loop
+ sub sym, 256
+
+ else
+
+ LITM_0
+ LITM
+ LITM
+ LITM
+ LITM
+ LITM
+ LITM
+ LITM_2
+
+ endif
+
+ mov probs, LOC probs_Spec
+ IsMatchBranch_Pre
+ ; mov dic, LOC dic_Spec
+ mov dicPos, LOC dicPos_Spec
+ mov byte ptr[dicPos], sym_L
+ inc dicPos
+
+ CheckLimits
+lit_matched_end:
+ IF_BIT_1_NOUP probs_state_R, pbPos_R, IsMatch, IsMatch_label
+ ; IsMatchBranch
+ mov lpMask_reg, LOC lpMask
+ sub state, 3 * PMULT
+ jmp lit_start_2
+
+
+
+; ---------- REP 0 LITERAL ----------
+MY_ALIGN_32
+IsRep0Short_label:
+ UPDATE_0 probs_state_R, pbPos_R, IsRep0Long
+
+ ; dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+ mov dic, LOC dic_Spec
+ mov t0_R, dicPos
+ mov probBranch, LOC rep0
+ sub t0_R, dic
+
+ sub probs, RepLenCoder * PMULT
+
+ ; state = state < kNumLitStates ? 9 : 11;
+ or state, 1 * PMULT
+
+ ; the caller doesn't allow (dicPos >= limit) case for REP_SHORT
+ ; so we don't need the following (dicPos == limit) check here:
+ ; cmp dicPos, LOC limit
+ ; jae fin_dicPos_LIMIT_REP_SHORT
+
+ inc processedPos
+
+ IsMatchBranch_Pre
+
+; xor sym, sym
+; sub t0_R, probBranch_R
+; cmovb sym_R, LOC dicBufSize
+; add t0_R, sym_R
+ sub t0_R, probBranch_R
+ jae @f
+ add t0_R, LOC dicBufSize
+@@:
+ movzx sym, byte ptr[dic + t0_R * 1]
+ jmp lz_end_match
+
+
+MY_ALIGN_32
+IsRep_label:
+ UPDATE_1 probs_state_R, 0, IsRep
+
+ ; The (checkDicSize == 0 && processedPos == 0) case was checked before in LzmaDec.c with kBadRepCode.
+ ; So we don't check it here.
+
+ ; mov t0, processedPos
+ ; or t0, LOC checkDicSize
+ ; jz fin_ERROR_2
+
+ ; state = state < kNumLitStates ? 8 : 11;
+ cmp state, kNumLitStates * PMULT
+ mov state, 8 * PMULT
+ mov probBranch, 11 * PMULT
+ cmovae state, probBranch
+
+ ; prob = probs + RepLenCoder;
+ add probs, RepLenCoder * PMULT
+
+ IF_BIT_1 probs_state_R, 0, IsRepG0, IsRepG0_label
+ IF_BIT_0_NOUP probs_state_R, pbPos_R, IsRep0Long, IsRep0Short_label
+ UPDATE_1 probs_state_R, pbPos_R, IsRep0Long
+ jmp len_decode
+
+MY_ALIGN_32
+IsRepG0_label:
+ UPDATE_1 probs_state_R, 0, IsRepG0
+ mov dist2, LOC rep0
+ mov dist, LOC rep1
+ mov LOC rep1, dist2
+
+ IF_BIT_1 probs_state_R, 0, IsRepG1, IsRepG1_label
+ mov LOC rep0, dist
+ jmp len_decode
+
+; MY_ALIGN_32
+IsRepG1_label:
+ UPDATE_1 probs_state_R, 0, IsRepG1
+ mov dist2, LOC rep2
+ mov LOC rep2, dist
+
+ IF_BIT_1 probs_state_R, 0, IsRepG2, IsRepG2_label
+ mov LOC rep0, dist2
+ jmp len_decode
+
+; MY_ALIGN_32
+IsRepG2_label:
+ UPDATE_1 probs_state_R, 0, IsRepG2
+ mov dist, LOC rep3
+ mov LOC rep3, dist2
+ mov LOC rep0, dist
+ jmp len_decode
+
+
+
+; ---------- SPEC SHORT DISTANCE ----------
+
+MY_ALIGN_32
+short_dist:
+ sub x1, 32 + 1
+ jbe decode_dist_end
+ or sym, 2
+ shl sym, x1_L
+ lea sym_R, [probs + sym_R * PMULT + SpecPos * PMULT + 1 * PMULT]
+ mov sym2, PMULT ; step
+MY_ALIGN_32
+spec_loop:
+ REV_1_VAR x2
+ dec x1
+ jnz spec_loop
+
+ mov probs, LOC probs_Spec
+ sub sym, sym2
+ sub sym, SpecPos * PMULT
+ sub sym_R, probs
+ shr sym, PSHIFT
+
+ jmp decode_dist_end
+
+
+; ---------- COPY MATCH CROSS ----------
+copy_match_cross:
+ ; t0_R - src pos
+ ; r1 - len to dicBufSize
+ ; cnt_R - total copy len
+
+ mov t1_R, t0_R ; srcPos
+ mov t0_R, dic
+ mov r1, LOC dicBufSize ;
+ neg cnt_R
+@@:
+ movzx sym, byte ptr[t1_R * 1 + t0_R]
+ inc t1_R
+ mov byte ptr[cnt_R * 1 + dicPos], sym_L
+ inc cnt_R
+ cmp t1_R, r1
+ jne @b
+
+ movzx sym, byte ptr[t0_R]
+ sub t0_R, cnt_R
+ jmp copy_common
+
+
+
+
+; fin_dicPos_LIMIT_REP_SHORT:
+ ; mov sym, 1
+
+fin_dicPos_LIMIT:
+ mov LOC remainLen, sym
+ jmp fin_OK
+ ; For more strict mode we can stop decoding with error
+ ; mov sym, 1
+ ; jmp fin
+
+
+fin_ERROR_MATCH_DIST:
+
+ ; rep3 = rep2;
+ ; rep2 = rep1;
+ ; rep1 = rep0;
+ ; rep0 = distance + 1;
+
+ add len_temp, kMatchSpecLen_Error_Data
+ mov LOC remainLen, len_temp
+
+ mov LOC rep0, sym
+ mov LOC rep1, t1
+ mov LOC rep2, x1
+ mov LOC rep3, x2
+
+ ; state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
+ cmp state, (kNumStates + kNumLitStates) * PMULT
+ mov state, kNumLitStates * PMULT
+ mov t0, (kNumLitStates + 3) * PMULT
+ cmovae state, t0
+
+ ; jmp fin_OK
+ mov sym, 1
+ jmp fin
+
+end_of_payload:
+ inc sym
+ jnz fin_ERROR_MATCH_DIST
+
+ mov LOC remainLen, kMatchSpecLenStart
+ sub state, kNumStates * PMULT
+
+fin_OK:
+ xor sym, sym
+
+fin:
+ NORM
+
+ mov r1, LOC lzmaPtr
+
+ sub dicPos, LOC dic_Spec
+ mov GLOB dicPos_Spec, dicPos
+ mov GLOB buf_Spec, buf
+ mov GLOB range_Spec, range
+ mov GLOB code_Spec, cod
+ shr state, PSHIFT
+ mov GLOB state_Spec, state
+ mov GLOB processedPos_Spec, processedPos
+
+ RESTORE_VAR(remainLen)
+ RESTORE_VAR(rep0)
+ RESTORE_VAR(rep1)
+ RESTORE_VAR(rep2)
+ RESTORE_VAR(rep3)
+
+ mov x0, sym
+
+ mov RSP, LOC Old_RSP
+
+MY_POP_PRESERVED_ABI_REGS
+MY_ENDP
+
+_TEXT$LZMADECOPT ENDS
+
+end
diff --git a/Asm/x86/Sha1Opt.asm b/Asm/x86/Sha1Opt.asm
new file mode 100644
index 0000000..3495fd1
--- /dev/null
+++ b/Asm/x86/Sha1Opt.asm
@@ -0,0 +1,263 @@
+; Sha1Opt.asm -- SHA-1 optimized code for SHA-1 x86 hardware instructions
+; 2021-03-10 : Igor Pavlov : Public domain
+
+include 7zAsm.asm
+
+MY_ASM_START
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CONST SEGMENT
+
+align 16
+Reverse_Endian_Mask db 15,14,13,12, 11,10,9,8, 7,6,5,4, 3,2,1,0
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+CONST ENDS
+
+; _TEXT$SHA1OPT SEGMENT 'CODE'
+
+ifndef x64
+ .686
+ .xmm
+endif
+
+ifdef x64
+ rNum equ REG_ABI_PARAM_2
+ if (IS_LINUX eq 0)
+ LOCAL_SIZE equ (16 * 2)
+ endif
+else
+ rNum equ r0
+ LOCAL_SIZE equ (16 * 1)
+endif
+
+rState equ REG_ABI_PARAM_0
+rData equ REG_ABI_PARAM_1
+
+
+MY_sha1rnds4 macro a1, a2, imm
+ db 0fH, 03aH, 0ccH, (0c0H + a1 * 8 + a2), imm
+endm
+
+MY_SHA_INSTR macro cmd, a1, a2
+ db 0fH, 038H, cmd, (0c0H + a1 * 8 + a2)
+endm
+
+cmd_sha1nexte equ 0c8H
+cmd_sha1msg1 equ 0c9H
+cmd_sha1msg2 equ 0caH
+
+MY_sha1nexte macro a1, a2
+ MY_SHA_INSTR cmd_sha1nexte, a1, a2
+endm
+
+MY_sha1msg1 macro a1, a2
+ MY_SHA_INSTR cmd_sha1msg1, a1, a2
+endm
+
+MY_sha1msg2 macro a1, a2
+ MY_SHA_INSTR cmd_sha1msg2, a1, a2
+endm
+
+MY_PROLOG macro
+ ifdef x64
+ if (IS_LINUX eq 0)
+ movdqa [r4 + 8], xmm6
+ movdqa [r4 + 8 + 16], xmm7
+ sub r4, LOCAL_SIZE + 8
+ movdqa [r4 ], xmm8
+ movdqa [r4 + 16], xmm9
+ endif
+ else ; x86
+ if (IS_CDECL gt 0)
+ mov rState, [r4 + REG_SIZE * 1]
+ mov rData, [r4 + REG_SIZE * 2]
+ mov rNum, [r4 + REG_SIZE * 3]
+ else ; fastcall
+ mov rNum, [r4 + REG_SIZE * 1]
+ endif
+ push r5
+ mov r5, r4
+ and r4, -16
+ sub r4, LOCAL_SIZE
+ endif
+endm
+
+MY_EPILOG macro
+ ifdef x64
+ if (IS_LINUX eq 0)
+ movdqa xmm8, [r4]
+ movdqa xmm9, [r4 + 16]
+ add r4, LOCAL_SIZE + 8
+ movdqa xmm6, [r4 + 8]
+ movdqa xmm7, [r4 + 8 + 16]
+ endif
+ else ; x86
+ mov r4, r5
+ pop r5
+ endif
+ MY_ENDP
+endm
+
+
+e0_N equ 0
+e1_N equ 1
+abcd_N equ 2
+e0_save_N equ 3
+w_regs equ 4
+
+e0 equ @CatStr(xmm, %e0_N)
+e1 equ @CatStr(xmm, %e1_N)
+abcd equ @CatStr(xmm, %abcd_N)
+e0_save equ @CatStr(xmm, %e0_save_N)
+
+
+ifdef x64
+ abcd_save equ xmm8
+ mask2 equ xmm9
+else
+ abcd_save equ [r4]
+ mask2 equ e1
+endif
+
+LOAD_MASK macro
+ movdqa mask2, XMMWORD PTR Reverse_Endian_Mask
+endm
+
+LOAD_W macro k:req
+ movdqu @CatStr(xmm, %(w_regs + k)), [rData + (16 * (k))]
+ pshufb @CatStr(xmm, %(w_regs + k)), mask2
+endm
+
+
+; pre2 can be 2 or 3 (recommended)
+pre2 equ 3
+pre1 equ (pre2 + 1)
+
+NUM_ROUNDS4 equ 20
+
+RND4 macro k
+ movdqa @CatStr(xmm, %(e0_N + ((k + 1) mod 2))), abcd
+ MY_sha1rnds4 abcd_N, (e0_N + (k mod 2)), k / 5
+
+ nextM = (w_regs + ((k + 1) mod 4))
+
+ if (k EQ NUM_ROUNDS4 - 1)
+ nextM = e0_save_N
+ endif
+
+ MY_sha1nexte (e0_N + ((k + 1) mod 2)), nextM
+
+ if (k GE (4 - pre2)) AND (k LT (NUM_ROUNDS4 - pre2))
+ pxor @CatStr(xmm, %(w_regs + ((k + pre2) mod 4))), @CatStr(xmm, %(w_regs + ((k + pre2 - 2) mod 4)))
+ endif
+
+ if (k GE (4 - pre1)) AND (k LT (NUM_ROUNDS4 - pre1))
+ MY_sha1msg1 (w_regs + ((k + pre1) mod 4)), (w_regs + ((k + pre1 - 3) mod 4))
+ endif
+
+ if (k GE (4 - pre2)) AND (k LT (NUM_ROUNDS4 - pre2))
+ MY_sha1msg2 (w_regs + ((k + pre2) mod 4)), (w_regs + ((k + pre2 - 1) mod 4))
+ endif
+endm
+
+
+REVERSE_STATE macro
+ ; abcd ; dcba
+ ; e0 ; 000e
+ pshufd abcd, abcd, 01bH ; abcd
+ pshufd e0, e0, 01bH ; e000
+endm
+
+
+
+
+
+MY_PROC Sha1_UpdateBlocks_HW, 3
+ MY_PROLOG
+
+ cmp rNum, 0
+ je end_c
+
+ movdqu abcd, [rState] ; dcba
+ movd e0, dword ptr [rState + 16] ; 000e
+
+ REVERSE_STATE
+
+ ifdef x64
+ LOAD_MASK
+ endif
+
+ align 16
+ nextBlock:
+ movdqa abcd_save, abcd
+ movdqa e0_save, e0
+
+ ifndef x64
+ LOAD_MASK
+ endif
+
+ LOAD_W 0
+ LOAD_W 1
+ LOAD_W 2
+ LOAD_W 3
+
+ paddd e0, @CatStr(xmm, %(w_regs))
+ k = 0
+ rept NUM_ROUNDS4
+ RND4 k
+ k = k + 1
+ endm
+
+ paddd abcd, abcd_save
+
+
+ add rData, 64
+ sub rNum, 1
+ jnz nextBlock
+
+ REVERSE_STATE
+
+ movdqu [rState], abcd
+ movd dword ptr [rState + 16], e0
+
+ end_c:
+MY_EPILOG
+
+; _TEXT$SHA1OPT ENDS
+
+end
diff --git a/Asm/x86/Sha256Opt.asm b/Asm/x86/Sha256Opt.asm
new file mode 100644
index 0000000..3e9f6ed
--- /dev/null
+++ b/Asm/x86/Sha256Opt.asm
@@ -0,0 +1,275 @@
+; Sha256Opt.asm -- SHA-256 optimized code for SHA-256 x86 hardware instructions
+; 2022-04-17 : Igor Pavlov : Public domain
+
+include 7zAsm.asm
+
+MY_ASM_START
+
+; .data
+; public K
+
+; we can use external SHA256_K_ARRAY defined in Sha256.c
+; but we must guarantee that SHA256_K_ARRAY is aligned for 16-bytes
+
+COMMENT @
+ifdef x64
+K_CONST equ SHA256_K_ARRAY
+else
+K_CONST equ _SHA256_K_ARRAY
+endif
+EXTRN K_CONST:xmmword
+@
+
+CONST SEGMENT
+
+align 16
+Reverse_Endian_Mask db 3,2,1,0, 7,6,5,4, 11,10,9,8, 15,14,13,12
+
+; COMMENT @
+align 16
+K_CONST \
+DD 0428a2f98H, 071374491H, 0b5c0fbcfH, 0e9b5dba5H
+DD 03956c25bH, 059f111f1H, 0923f82a4H, 0ab1c5ed5H
+DD 0d807aa98H, 012835b01H, 0243185beH, 0550c7dc3H
+DD 072be5d74H, 080deb1feH, 09bdc06a7H, 0c19bf174H
+DD 0e49b69c1H, 0efbe4786H, 00fc19dc6H, 0240ca1ccH
+DD 02de92c6fH, 04a7484aaH, 05cb0a9dcH, 076f988daH
+DD 0983e5152H, 0a831c66dH, 0b00327c8H, 0bf597fc7H
+DD 0c6e00bf3H, 0d5a79147H, 006ca6351H, 014292967H
+DD 027b70a85H, 02e1b2138H, 04d2c6dfcH, 053380d13H
+DD 0650a7354H, 0766a0abbH, 081c2c92eH, 092722c85H
+DD 0a2bfe8a1H, 0a81a664bH, 0c24b8b70H, 0c76c51a3H
+DD 0d192e819H, 0d6990624H, 0f40e3585H, 0106aa070H
+DD 019a4c116H, 01e376c08H, 02748774cH, 034b0bcb5H
+DD 0391c0cb3H, 04ed8aa4aH, 05b9cca4fH, 0682e6ff3H
+DD 0748f82eeH, 078a5636fH, 084c87814H, 08cc70208H
+DD 090befffaH, 0a4506cebH, 0bef9a3f7H, 0c67178f2H
+; @
+
+CONST ENDS
+
+; _TEXT$SHA256OPT SEGMENT 'CODE'
+
+ifndef x64
+ .686
+ .xmm
+endif
+
+; jwasm-based assemblers for linux and linker from new versions of binutils
+; can generate incorrect code for load [ARRAY + offset] instructions.
+; 22.00: we load K_CONST offset to (rTable) register to avoid jwasm+binutils problem
+ rTable equ r0
+ ; rTable equ K_CONST
+
+ifdef x64
+ rNum equ REG_ABI_PARAM_2
+ if (IS_LINUX eq 0)
+ LOCAL_SIZE equ (16 * 2)
+ endif
+else
+ rNum equ r3
+ LOCAL_SIZE equ (16 * 1)
+endif
+
+rState equ REG_ABI_PARAM_0
+rData equ REG_ABI_PARAM_1
+
+
+
+
+
+
+MY_SHA_INSTR macro cmd, a1, a2
+ db 0fH, 038H, cmd, (0c0H + a1 * 8 + a2)
+endm
+
+cmd_sha256rnds2 equ 0cbH
+cmd_sha256msg1 equ 0ccH
+cmd_sha256msg2 equ 0cdH
+
+MY_sha256rnds2 macro a1, a2
+ MY_SHA_INSTR cmd_sha256rnds2, a1, a2
+endm
+
+MY_sha256msg1 macro a1, a2
+ MY_SHA_INSTR cmd_sha256msg1, a1, a2
+endm
+
+MY_sha256msg2 macro a1, a2
+ MY_SHA_INSTR cmd_sha256msg2, a1, a2
+endm
+
+MY_PROLOG macro
+ ifdef x64
+ if (IS_LINUX eq 0)
+ movdqa [r4 + 8], xmm6
+ movdqa [r4 + 8 + 16], xmm7
+ sub r4, LOCAL_SIZE + 8
+ movdqa [r4 ], xmm8
+ movdqa [r4 + 16], xmm9
+ endif
+ else ; x86
+ push r3
+ push r5
+ mov r5, r4
+ NUM_PUSH_REGS equ 2
+ PARAM_OFFSET equ (REG_SIZE * (1 + NUM_PUSH_REGS))
+ if (IS_CDECL gt 0)
+ mov rState, [r4 + PARAM_OFFSET]
+ mov rData, [r4 + PARAM_OFFSET + REG_SIZE * 1]
+ mov rNum, [r4 + PARAM_OFFSET + REG_SIZE * 2]
+ else ; fastcall
+ mov rNum, [r4 + PARAM_OFFSET]
+ endif
+ and r4, -16
+ sub r4, LOCAL_SIZE
+ endif
+endm
+
+MY_EPILOG macro
+ ifdef x64
+ if (IS_LINUX eq 0)
+ movdqa xmm8, [r4]
+ movdqa xmm9, [r4 + 16]
+ add r4, LOCAL_SIZE + 8
+ movdqa xmm6, [r4 + 8]
+ movdqa xmm7, [r4 + 8 + 16]
+ endif
+ else ; x86
+ mov r4, r5
+ pop r5
+ pop r3
+ endif
+ MY_ENDP
+endm
+
+
+msg equ xmm0
+tmp equ xmm0
+state0_N equ 2
+state1_N equ 3
+w_regs equ 4
+
+
+state1_save equ xmm1
+state0 equ @CatStr(xmm, %state0_N)
+state1 equ @CatStr(xmm, %state1_N)
+
+
+ifdef x64
+ state0_save equ xmm8
+ mask2 equ xmm9
+else
+ state0_save equ [r4]
+ mask2 equ xmm0
+endif
+
+LOAD_MASK macro
+ movdqa mask2, XMMWORD PTR Reverse_Endian_Mask
+endm
+
+LOAD_W macro k:req
+ movdqu @CatStr(xmm, %(w_regs + k)), [rData + (16 * (k))]
+ pshufb @CatStr(xmm, %(w_regs + k)), mask2
+endm
+
+
+; pre1 <= 4 && pre2 >= 1 && pre1 > pre2 && (pre1 - pre2) <= 1
+pre1 equ 3
+pre2 equ 2
+
+
+
+RND4 macro k
+ movdqa msg, xmmword ptr [rTable + (k) * 16]
+ paddd msg, @CatStr(xmm, %(w_regs + ((k + 0) mod 4)))
+ MY_sha256rnds2 state0_N, state1_N
+ pshufd msg, msg, 0eH
+
+ if (k GE (4 - pre1)) AND (k LT (16 - pre1))
+ ; w4[0] = msg1(w4[-4], w4[-3])
+ MY_sha256msg1 (w_regs + ((k + pre1) mod 4)), (w_regs + ((k + pre1 - 3) mod 4))
+ endif
+
+ MY_sha256rnds2 state1_N, state0_N
+
+ if (k GE (4 - pre2)) AND (k LT (16 - pre2))
+ movdqa tmp, @CatStr(xmm, %(w_regs + ((k + pre2 - 1) mod 4)))
+ palignr tmp, @CatStr(xmm, %(w_regs + ((k + pre2 - 2) mod 4))), 4
+ paddd @CatStr(xmm, %(w_regs + ((k + pre2) mod 4))), tmp
+ ; w4[0] = msg2(w4[0], w4[-1])
+ MY_sha256msg2 %(w_regs + ((k + pre2) mod 4)), %(w_regs + ((k + pre2 - 1) mod 4))
+ endif
+endm
+
+
+
+
+
+REVERSE_STATE macro
+ ; state0 ; dcba
+ ; state1 ; hgfe
+ pshufd tmp, state0, 01bH ; abcd
+ pshufd state0, state1, 01bH ; efgh
+ movdqa state1, state0 ; efgh
+ punpcklqdq state0, tmp ; cdgh
+ punpckhqdq state1, tmp ; abef
+endm
+
+
+MY_PROC Sha256_UpdateBlocks_HW, 3
+ MY_PROLOG
+
+ lea rTable, [K_CONST]
+
+ cmp rNum, 0
+ je end_c
+
+ movdqu state0, [rState] ; dcba
+ movdqu state1, [rState + 16] ; hgfe
+
+ REVERSE_STATE
+
+ ifdef x64
+ LOAD_MASK
+ endif
+
+ align 16
+ nextBlock:
+ movdqa state0_save, state0
+ movdqa state1_save, state1
+
+ ifndef x64
+ LOAD_MASK
+ endif
+
+ LOAD_W 0
+ LOAD_W 1
+ LOAD_W 2
+ LOAD_W 3
+
+
+ k = 0
+ rept 16
+ RND4 k
+ k = k + 1
+ endm
+
+ paddd state0, state0_save
+ paddd state1, state1_save
+
+ add rData, 64
+ sub rNum, 1
+ jnz nextBlock
+
+ REVERSE_STATE
+
+ movdqu [rState], state0
+ movdqu [rState + 16], state1
+
+ end_c:
+MY_EPILOG
+
+; _TEXT$SHA256OPT ENDS
+
+end
diff --git a/Asm/x86/XzCrc64Opt.asm b/Asm/x86/XzCrc64Opt.asm
index 3e6d490..ad22cc2 100644
--- a/Asm/x86/XzCrc64Opt.asm
+++ b/Asm/x86/XzCrc64Opt.asm
@@ -1,205 +1,239 @@
-; XzCrc64Opt.asm -- CRC64 calculation : optimized version
-; 2011-06-28 : Igor Pavlov : Public domain
-
-include 7zAsm.asm
-
-MY_ASM_START
-
-ifdef x64
-
- rD equ r9
- rN equ r10
-
- num_VAR equ r8
- table_VAR equ r9
-
- SRCDAT equ rN + rD
-
-CRC_XOR macro dest:req, src:req, t:req
- xor dest, QWORD PTR [r5 + src * 8 + 0800h * t]
-endm
-
-CRC1b macro
- movzx x6, BYTE PTR [rD]
- inc rD
- movzx x3, x0_L
- xor x6, x3
- shr r0, 8
- CRC_XOR r0, r6, 0
- dec rN
-endm
-
-MY_PROLOG macro crc_end:req
- MY_PUSH_4_REGS
-
- mov r0, r1
- mov rN, num_VAR
- mov r5, table_VAR
- mov rD, r2
- test rN, rN
- jz crc_end
- @@:
- test rD, 3
- jz @F
- CRC1b
- jnz @B
- @@:
- cmp rN, 8
- jb crc_end
- add rN, rD
- mov num_VAR, rN
- sub rN, 4
- and rN, NOT 3
- sub rD, rN
- mov x1, [SRCDAT]
- xor r0, r1
- add rN, 4
-endm
-
-MY_EPILOG macro crc_end:req
- sub rN, 4
- mov x1, [SRCDAT]
- xor r0, r1
- mov rD, rN
- mov rN, num_VAR
- sub rN, rD
- crc_end:
- test rN, rN
- jz @F
- CRC1b
- jmp crc_end
- @@:
- MY_POP_4_REGS
-endm
-
-MY_PROC XzCrc64UpdateT4, 4
- MY_PROLOG crc_end_4
- align 16
- main_loop_4:
- mov x1, [SRCDAT]
- movzx x2, x0_L
- movzx x3, x0_H
- shr r0, 16
- movzx x6, x0_L
- movzx x7, x0_H
- shr r0, 16
- CRC_XOR r1, r2, 3
- CRC_XOR r0, r3, 2
- CRC_XOR r1, r6, 1
- CRC_XOR r0, r7, 0
- xor r0, r1
-
- add rD, 4
- jnz main_loop_4
-
- MY_EPILOG crc_end_4
-MY_ENDP
-
-else
-
- rD equ r1
- rN equ r7
-
- crc_val equ (REG_SIZE * 5)
- crc_table equ (8 + crc_val)
- table_VAR equ [r4 + crc_table]
- num_VAR equ table_VAR
-
-
- SRCDAT equ rN + rD
-
-CRC macro op0:req, op1:req, dest0:req, dest1:req, src:req, t:req
- op0 dest0, DWORD PTR [r5 + src * 8 + 0800h * t]
- op1 dest1, DWORD PTR [r5 + src * 8 + 0800h * t + 4]
-endm
-
-CRC_XOR macro dest0:req, dest1:req, src:req, t:req
- CRC xor, xor, dest0, dest1, src, t
-endm
-
-
-CRC1b macro
- movzx x6, BYTE PTR [rD]
- inc rD
- movzx x3, x0_L
- xor x6, x3
- shrd r0, r2, 8
- shr r2, 8
- CRC_XOR r0, r2, r6, 0
- dec rN
-endm
-
-MY_PROLOG macro crc_end:req
- MY_PUSH_4_REGS
-
- mov rN, r2
-
- mov x0, [r4 + crc_val]
- mov x2, [r4 + crc_val + 4]
- mov r5, table_VAR
- test rN, rN
- jz crc_end
- @@:
- test rD, 3
- jz @F
- CRC1b
- jnz @B
- @@:
- cmp rN, 8
- jb crc_end
- add rN, rD
-
- mov num_VAR, rN
-
- sub rN, 4
- and rN, NOT 3
- sub rD, rN
- xor r0, [SRCDAT]
- add rN, 4
-endm
-
-MY_EPILOG macro crc_end:req
- sub rN, 4
- xor r0, [SRCDAT]
-
- mov rD, rN
- mov rN, num_VAR
- sub rN, rD
- crc_end:
- test rN, rN
- jz @F
- CRC1b
- jmp crc_end
- @@:
- MY_POP_4_REGS
-endm
-
-MY_PROC XzCrc64UpdateT4, 5
- MY_PROLOG crc_end_4
- movzx x6, x0_L
- align 16
- main_loop_4:
- mov r3, [SRCDAT]
- xor r3, r2
-
- CRC xor, mov, r3, r2, r6, 3
- movzx x6, x0_H
- shr r0, 16
- CRC_XOR r3, r2, r6, 2
-
- movzx x6, x0_L
- movzx x0, x0_H
- CRC_XOR r3, r2, r6, 1
- CRC_XOR r3, r2, r0, 0
- movzx x6, x3_L
- mov r0, r3
-
- add rD, 4
- jnz main_loop_4
-
- MY_EPILOG crc_end_4
-MY_ENDP
-
-endif
-
-end
+; XzCrc64Opt.asm -- CRC64 calculation : optimized version
+; 2021-02-06 : Igor Pavlov : Public domain
+
+include 7zAsm.asm
+
+MY_ASM_START
+
+ifdef x64
+
+rD equ r9
+rN equ r10
+rT equ r5
+num_VAR equ r8
+
+SRCDAT4 equ dword ptr [rD + rN * 1]
+
+CRC_XOR macro dest:req, src:req, t:req
+ xor dest, QWORD PTR [rT + src * 8 + 0800h * t]
+endm
+
+CRC1b macro
+ movzx x6, BYTE PTR [rD]
+ inc rD
+ movzx x3, x0_L
+ xor x6, x3
+ shr r0, 8
+ CRC_XOR r0, r6, 0
+ dec rN
+endm
+
+MY_PROLOG macro crc_end:req
+ ifdef ABI_LINUX
+ MY_PUSH_2_REGS
+ else
+ MY_PUSH_4_REGS
+ endif
+ mov r0, REG_ABI_PARAM_0
+ mov rN, REG_ABI_PARAM_2
+ mov rT, REG_ABI_PARAM_3
+ mov rD, REG_ABI_PARAM_1
+ test rN, rN
+ jz crc_end
+ @@:
+ test rD, 3
+ jz @F
+ CRC1b
+ jnz @B
+ @@:
+ cmp rN, 8
+ jb crc_end
+ add rN, rD
+ mov num_VAR, rN
+ sub rN, 4
+ and rN, NOT 3
+ sub rD, rN
+ mov x1, SRCDAT4
+ xor r0, r1
+ add rN, 4
+endm
+
+MY_EPILOG macro crc_end:req
+ sub rN, 4
+ mov x1, SRCDAT4
+ xor r0, r1
+ mov rD, rN
+ mov rN, num_VAR
+ sub rN, rD
+ crc_end:
+ test rN, rN
+ jz @F
+ CRC1b
+ jmp crc_end
+ @@:
+ ifdef ABI_LINUX
+ MY_POP_2_REGS
+ else
+ MY_POP_4_REGS
+ endif
+endm
+
+MY_PROC XzCrc64UpdateT4, 4
+ MY_PROLOG crc_end_4
+ align 16
+ main_loop_4:
+ mov x1, SRCDAT4
+ movzx x2, x0_L
+ movzx x3, x0_H
+ shr r0, 16
+ movzx x6, x0_L
+ movzx x7, x0_H
+ shr r0, 16
+ CRC_XOR r1, r2, 3
+ CRC_XOR r0, r3, 2
+ CRC_XOR r1, r6, 1
+ CRC_XOR r0, r7, 0
+ xor r0, r1
+
+ add rD, 4
+ jnz main_loop_4
+
+ MY_EPILOG crc_end_4
+MY_ENDP
+
+else
+; x86 (32-bit)
+
+rD equ r1
+rN equ r7
+rT equ r5
+
+crc_OFFS equ (REG_SIZE * 5)
+
+if (IS_CDECL gt 0) or (IS_LINUX gt 0)
+ ; cdecl or (GNU fastcall) stack:
+ ; (UInt32 *) table
+ ; size_t size
+ ; void * data
+ ; (UInt64) crc
+ ; ret-ip <-(r4)
+ data_OFFS equ (8 + crc_OFFS)
+ size_OFFS equ (REG_SIZE + data_OFFS)
+ table_OFFS equ (REG_SIZE + size_OFFS)
+ num_VAR equ [r4 + size_OFFS]
+ table_VAR equ [r4 + table_OFFS]
+else
+ ; Windows fastcall:
+ ; r1 = data, r2 = size
+ ; stack:
+ ; (UInt32 *) table
+ ; (UInt64) crc
+ ; ret-ip <-(r4)
+ table_OFFS equ (8 + crc_OFFS)
+ table_VAR equ [r4 + table_OFFS]
+ num_VAR equ table_VAR
+endif
+
+SRCDAT4 equ dword ptr [rD + rN * 1]
+
+CRC macro op0:req, op1:req, dest0:req, dest1:req, src:req, t:req
+ op0 dest0, DWORD PTR [rT + src * 8 + 0800h * t]
+ op1 dest1, DWORD PTR [rT + src * 8 + 0800h * t + 4]
+endm
+
+CRC_XOR macro dest0:req, dest1:req, src:req, t:req
+ CRC xor, xor, dest0, dest1, src, t
+endm
+
+
+CRC1b macro
+ movzx x6, BYTE PTR [rD]
+ inc rD
+ movzx x3, x0_L
+ xor x6, x3
+ shrd r0, r2, 8
+ shr r2, 8
+ CRC_XOR r0, r2, r6, 0
+ dec rN
+endm
+
+MY_PROLOG macro crc_end:req
+ MY_PUSH_4_REGS
+
+ if (IS_CDECL gt 0) or (IS_LINUX gt 0)
+ proc_numParams = proc_numParams + 2 ; for ABI_LINUX
+ mov rN, [r4 + size_OFFS]
+ mov rD, [r4 + data_OFFS]
+ else
+ mov rN, r2
+ endif
+
+ mov x0, [r4 + crc_OFFS]
+ mov x2, [r4 + crc_OFFS + 4]
+ mov rT, table_VAR
+ test rN, rN
+ jz crc_end
+ @@:
+ test rD, 3
+ jz @F
+ CRC1b
+ jnz @B
+ @@:
+ cmp rN, 8
+ jb crc_end
+ add rN, rD
+
+ mov num_VAR, rN
+
+ sub rN, 4
+ and rN, NOT 3
+ sub rD, rN
+ xor r0, SRCDAT4
+ add rN, 4
+endm
+
+MY_EPILOG macro crc_end:req
+ sub rN, 4
+ xor r0, SRCDAT4
+
+ mov rD, rN
+ mov rN, num_VAR
+ sub rN, rD
+ crc_end:
+ test rN, rN
+ jz @F
+ CRC1b
+ jmp crc_end
+ @@:
+ MY_POP_4_REGS
+endm
+
+MY_PROC XzCrc64UpdateT4, 5
+ MY_PROLOG crc_end_4
+ movzx x6, x0_L
+ align 16
+ main_loop_4:
+ mov r3, SRCDAT4
+ xor r3, r2
+
+ CRC xor, mov, r3, r2, r6, 3
+ movzx x6, x0_H
+ shr r0, 16
+ CRC_XOR r3, r2, r6, 2
+
+ movzx x6, x0_L
+ movzx x0, x0_H
+ CRC_XOR r3, r2, r6, 1
+ CRC_XOR r3, r2, r0, 0
+ movzx x6, x3_L
+ mov r0, r3
+
+ add rD, 4
+ jnz main_loop_4
+
+ MY_EPILOG crc_end_4
+MY_ENDP
+
+endif ; ! x64
+
+end
diff --git a/C/7z.h b/C/7z.h
index 82813c2..9e27c01 100644
--- a/C/7z.h
+++ b/C/7z.h
@@ -1,202 +1,204 @@
-/* 7z.h -- 7z interface
-2017-04-03 : Igor Pavlov : Public domain */
-
-#ifndef __7Z_H
-#define __7Z_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-#define k7zStartHeaderSize 0x20
-#define k7zSignatureSize 6
-
-extern const Byte k7zSignature[k7zSignatureSize];
-
-typedef struct
-{
- const Byte *Data;
- size_t Size;
-} CSzData;
-
-/* CSzCoderInfo & CSzFolder support only default methods */
-
-typedef struct
-{
- size_t PropsOffset;
- UInt32 MethodID;
- Byte NumStreams;
- Byte PropsSize;
-} CSzCoderInfo;
-
-typedef struct
-{
- UInt32 InIndex;
- UInt32 OutIndex;
-} CSzBond;
-
-#define SZ_NUM_CODERS_IN_FOLDER_MAX 4
-#define SZ_NUM_BONDS_IN_FOLDER_MAX 3
-#define SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX 4
-
-typedef struct
-{
- UInt32 NumCoders;
- UInt32 NumBonds;
- UInt32 NumPackStreams;
- UInt32 UnpackStream;
- UInt32 PackStreams[SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX];
- CSzBond Bonds[SZ_NUM_BONDS_IN_FOLDER_MAX];
- CSzCoderInfo Coders[SZ_NUM_CODERS_IN_FOLDER_MAX];
-} CSzFolder;
-
-
-SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd);
-
-typedef struct
-{
- UInt32 Low;
- UInt32 High;
-} CNtfsFileTime;
-
-typedef struct
-{
- Byte *Defs; /* MSB 0 bit numbering */
- UInt32 *Vals;
-} CSzBitUi32s;
-
-typedef struct
-{
- Byte *Defs; /* MSB 0 bit numbering */
- // UInt64 *Vals;
- CNtfsFileTime *Vals;
-} CSzBitUi64s;
-
-#define SzBitArray_Check(p, i) (((p)[(i) >> 3] & (0x80 >> ((i) & 7))) != 0)
-
-#define SzBitWithVals_Check(p, i) ((p)->Defs && ((p)->Defs[(i) >> 3] & (0x80 >> ((i) & 7))) != 0)
-
-typedef struct
-{
- UInt32 NumPackStreams;
- UInt32 NumFolders;
-
- UInt64 *PackPositions; // NumPackStreams + 1
- CSzBitUi32s FolderCRCs; // NumFolders
-
- size_t *FoCodersOffsets; // NumFolders + 1
- UInt32 *FoStartPackStreamIndex; // NumFolders + 1
- UInt32 *FoToCoderUnpackSizes; // NumFolders + 1
- Byte *FoToMainUnpackSizeIndex; // NumFolders
- UInt64 *CoderUnpackSizes; // for all coders in all folders
-
- Byte *CodersData;
-} CSzAr;
-
-UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex);
-
-SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
- ILookInStream *stream, UInt64 startPos,
- Byte *outBuffer, size_t outSize,
- ISzAllocPtr allocMain);
-
-typedef struct
-{
- CSzAr db;
-
- UInt64 startPosAfterHeader;
- UInt64 dataPos;
-
- UInt32 NumFiles;
-
- UInt64 *UnpackPositions; // NumFiles + 1
- // Byte *IsEmptyFiles;
- Byte *IsDirs;
- CSzBitUi32s CRCs;
-
- CSzBitUi32s Attribs;
- // CSzBitUi32s Parents;
- CSzBitUi64s MTime;
- CSzBitUi64s CTime;
-
- UInt32 *FolderToFile; // NumFolders + 1
- UInt32 *FileToFolder; // NumFiles
-
- size_t *FileNameOffsets; /* in 2-byte steps */
- Byte *FileNames; /* UTF-16-LE */
-} CSzArEx;
-
-#define SzArEx_IsDir(p, i) (SzBitArray_Check((p)->IsDirs, i))
-
-#define SzArEx_GetFileSize(p, i) ((p)->UnpackPositions[(i) + 1] - (p)->UnpackPositions[i])
-
-void SzArEx_Init(CSzArEx *p);
-void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc);
-UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder);
-int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize);
-
-/*
-if dest == NULL, the return value specifies the required size of the buffer,
- in 16-bit characters, including the null-terminating character.
-if dest != NULL, the return value specifies the number of 16-bit characters that
- are written to the dest, including the null-terminating character. */
-
-size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
-
-/*
-size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex);
-UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
-*/
-
-
-
-/*
- SzArEx_Extract extracts file from archive
-
- *outBuffer must be 0 before first call for each new archive.
-
- Extracting cache:
- If you need to decompress more than one file, you can send
- these values from previous call:
- *blockIndex,
- *outBuffer,
- *outBufferSize
- You can consider "*outBuffer" as cache of solid block. If your archive is solid,
- it will increase decompression speed.
-
- If you use external function, you can declare these 3 cache variables
- (blockIndex, outBuffer, outBufferSize) as static in that external function.
-
- Free *outBuffer and set *outBuffer to 0, if you want to flush cache.
-*/
-
-SRes SzArEx_Extract(
- const CSzArEx *db,
- ILookInStream *inStream,
- UInt32 fileIndex, /* index of file */
- UInt32 *blockIndex, /* index of solid block */
- Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */
- size_t *outBufferSize, /* buffer size for output buffer */
- size_t *offset, /* offset of stream for required file in *outBuffer */
- size_t *outSizeProcessed, /* size of file in *outBuffer */
- ISzAllocPtr allocMain,
- ISzAllocPtr allocTemp);
-
-
-/*
-SzArEx_Open Errors:
-SZ_ERROR_NO_ARCHIVE
-SZ_ERROR_ARCHIVE
-SZ_ERROR_UNSUPPORTED
-SZ_ERROR_MEM
-SZ_ERROR_CRC
-SZ_ERROR_INPUT_EOF
-SZ_ERROR_FAIL
-*/
-
-SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream,
- ISzAllocPtr allocMain, ISzAllocPtr allocTemp);
-
-EXTERN_C_END
-
-#endif
+/* 7z.h -- 7z interface
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_7Z_H
+#define ZIP7_INC_7Z_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define k7zStartHeaderSize 0x20
+#define k7zSignatureSize 6
+
+extern const Byte k7zSignature[k7zSignatureSize];
+
+typedef struct
+{
+ const Byte *Data;
+ size_t Size;
+} CSzData;
+
+/* CSzCoderInfo & CSzFolder support only default methods */
+
+typedef struct
+{
+ size_t PropsOffset;
+ UInt32 MethodID;
+ Byte NumStreams;
+ Byte PropsSize;
+} CSzCoderInfo;
+
+typedef struct
+{
+ UInt32 InIndex;
+ UInt32 OutIndex;
+} CSzBond;
+
+#define SZ_NUM_CODERS_IN_FOLDER_MAX 4
+#define SZ_NUM_BONDS_IN_FOLDER_MAX 3
+#define SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX 4
+
+typedef struct
+{
+ UInt32 NumCoders;
+ UInt32 NumBonds;
+ UInt32 NumPackStreams;
+ UInt32 UnpackStream;
+ UInt32 PackStreams[SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX];
+ CSzBond Bonds[SZ_NUM_BONDS_IN_FOLDER_MAX];
+ CSzCoderInfo Coders[SZ_NUM_CODERS_IN_FOLDER_MAX];
+} CSzFolder;
+
+
+SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd);
+
+typedef struct
+{
+ UInt32 Low;
+ UInt32 High;
+} CNtfsFileTime;
+
+typedef struct
+{
+ Byte *Defs; /* MSB 0 bit numbering */
+ UInt32 *Vals;
+} CSzBitUi32s;
+
+typedef struct
+{
+ Byte *Defs; /* MSB 0 bit numbering */
+ // UInt64 *Vals;
+ CNtfsFileTime *Vals;
+} CSzBitUi64s;
+
+#define SzBitArray_Check(p, i) (((p)[(i) >> 3] & (0x80 >> ((i) & 7))) != 0)
+
+#define SzBitWithVals_Check(p, i) ((p)->Defs && ((p)->Defs[(i) >> 3] & (0x80 >> ((i) & 7))) != 0)
+
+typedef struct
+{
+ UInt32 NumPackStreams;
+ UInt32 NumFolders;
+
+ UInt64 *PackPositions; // NumPackStreams + 1
+ CSzBitUi32s FolderCRCs; // NumFolders
+
+ size_t *FoCodersOffsets; // NumFolders + 1
+ UInt32 *FoStartPackStreamIndex; // NumFolders + 1
+ UInt32 *FoToCoderUnpackSizes; // NumFolders + 1
+ Byte *FoToMainUnpackSizeIndex; // NumFolders
+ UInt64 *CoderUnpackSizes; // for all coders in all folders
+
+ Byte *CodersData;
+
+ UInt64 RangeLimit;
+} CSzAr;
+
+UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex);
+
+SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
+ ILookInStreamPtr stream, UInt64 startPos,
+ Byte *outBuffer, size_t outSize,
+ ISzAllocPtr allocMain);
+
+typedef struct
+{
+ CSzAr db;
+
+ UInt64 startPosAfterHeader;
+ UInt64 dataPos;
+
+ UInt32 NumFiles;
+
+ UInt64 *UnpackPositions; // NumFiles + 1
+ // Byte *IsEmptyFiles;
+ Byte *IsDirs;
+ CSzBitUi32s CRCs;
+
+ CSzBitUi32s Attribs;
+ // CSzBitUi32s Parents;
+ CSzBitUi64s MTime;
+ CSzBitUi64s CTime;
+
+ UInt32 *FolderToFile; // NumFolders + 1
+ UInt32 *FileToFolder; // NumFiles
+
+ size_t *FileNameOffsets; /* in 2-byte steps */
+ Byte *FileNames; /* UTF-16-LE */
+} CSzArEx;
+
+#define SzArEx_IsDir(p, i) (SzBitArray_Check((p)->IsDirs, i))
+
+#define SzArEx_GetFileSize(p, i) ((p)->UnpackPositions[(i) + 1] - (p)->UnpackPositions[i])
+
+void SzArEx_Init(CSzArEx *p);
+void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc);
+UInt64 SzArEx_GetFolderStreamPos(const CSzArEx *p, UInt32 folderIndex, UInt32 indexInFolder);
+int SzArEx_GetFolderFullPackSize(const CSzArEx *p, UInt32 folderIndex, UInt64 *resSize);
+
+/*
+if dest == NULL, the return value specifies the required size of the buffer,
+ in 16-bit characters, including the null-terminating character.
+if dest != NULL, the return value specifies the number of 16-bit characters that
+ are written to the dest, including the null-terminating character. */
+
+size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
+
+/*
+size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex);
+UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest);
+*/
+
+
+
+/*
+ SzArEx_Extract extracts file from archive
+
+ *outBuffer must be 0 before first call for each new archive.
+
+ Extracting cache:
+ If you need to decompress more than one file, you can send
+ these values from previous call:
+ *blockIndex,
+ *outBuffer,
+ *outBufferSize
+ You can consider "*outBuffer" as cache of solid block. If your archive is solid,
+ it will increase decompression speed.
+
+ If you use external function, you can declare these 3 cache variables
+ (blockIndex, outBuffer, outBufferSize) as static in that external function.
+
+ Free *outBuffer and set *outBuffer to 0, if you want to flush cache.
+*/
+
+SRes SzArEx_Extract(
+ const CSzArEx *db,
+ ILookInStreamPtr inStream,
+ UInt32 fileIndex, /* index of file */
+ UInt32 *blockIndex, /* index of solid block */
+ Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */
+ size_t *outBufferSize, /* buffer size for output buffer */
+ size_t *offset, /* offset of stream for required file in *outBuffer */
+ size_t *outSizeProcessed, /* size of file in *outBuffer */
+ ISzAllocPtr allocMain,
+ ISzAllocPtr allocTemp);
+
+
+/*
+SzArEx_Open Errors:
+SZ_ERROR_NO_ARCHIVE
+SZ_ERROR_ARCHIVE
+SZ_ERROR_UNSUPPORTED
+SZ_ERROR_MEM
+SZ_ERROR_CRC
+SZ_ERROR_INPUT_EOF
+SZ_ERROR_FAIL
+*/
+
+SRes SzArEx_Open(CSzArEx *p, ILookInStreamPtr inStream,
+ ISzAllocPtr allocMain, ISzAllocPtr allocTemp);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/7zAlloc.c b/C/7zAlloc.c
index ea32809..2f0659a 100644
--- a/C/7zAlloc.c
+++ b/C/7zAlloc.c
@@ -1,80 +1,89 @@
-/* 7zAlloc.c -- Allocation functions
-2017-04-03 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include <stdlib.h>
-
-#include "7zAlloc.h"
-
-/* #define _SZ_ALLOC_DEBUG */
-/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
-
-#ifdef _SZ_ALLOC_DEBUG
-
-#ifdef _WIN32
-#include <windows.h>
-#endif
-
-#include <stdio.h>
-int g_allocCount = 0;
-int g_allocCountTemp = 0;
-
-#endif
-
-void *SzAlloc(ISzAllocPtr p, size_t size)
-{
- UNUSED_VAR(p);
- if (size == 0)
- return 0;
- #ifdef _SZ_ALLOC_DEBUG
- fprintf(stderr, "\nAlloc %10u bytes; count = %10d", (unsigned)size, g_allocCount);
- g_allocCount++;
- #endif
- return malloc(size);
-}
-
-void SzFree(ISzAllocPtr p, void *address)
-{
- UNUSED_VAR(p);
- #ifdef _SZ_ALLOC_DEBUG
- if (address != 0)
- {
- g_allocCount--;
- fprintf(stderr, "\nFree; count = %10d", g_allocCount);
- }
- #endif
- free(address);
-}
-
-void *SzAllocTemp(ISzAllocPtr p, size_t size)
-{
- UNUSED_VAR(p);
- if (size == 0)
- return 0;
- #ifdef _SZ_ALLOC_DEBUG
- fprintf(stderr, "\nAlloc_temp %10u bytes; count = %10d", (unsigned)size, g_allocCountTemp);
- g_allocCountTemp++;
- #ifdef _WIN32
- return HeapAlloc(GetProcessHeap(), 0, size);
- #endif
- #endif
- return malloc(size);
-}
-
-void SzFreeTemp(ISzAllocPtr p, void *address)
-{
- UNUSED_VAR(p);
- #ifdef _SZ_ALLOC_DEBUG
- if (address != 0)
- {
- g_allocCountTemp--;
- fprintf(stderr, "\nFree_temp; count = %10d", g_allocCountTemp);
- }
- #ifdef _WIN32
- HeapFree(GetProcessHeap(), 0, address);
- return;
- #endif
- #endif
- free(address);
-}
+/* 7zAlloc.c -- Allocation functions for 7z processing
+2023-03-04 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <stdlib.h>
+
+#include "7zAlloc.h"
+
+/* #define SZ_ALLOC_DEBUG */
+/* use SZ_ALLOC_DEBUG to debug alloc/free operations */
+
+#ifdef SZ_ALLOC_DEBUG
+
+/*
+#ifdef _WIN32
+#include "7zWindows.h"
+#endif
+*/
+
+#include <stdio.h>
+static int g_allocCount = 0;
+static int g_allocCountTemp = 0;
+
+static void Print_Alloc(const char *s, size_t size, int *counter)
+{
+ const unsigned size2 = (unsigned)size;
+ fprintf(stderr, "\n%s count = %10d : %10u bytes; ", s, *counter, size2);
+ (*counter)++;
+}
+static void Print_Free(const char *s, int *counter)
+{
+ (*counter)--;
+ fprintf(stderr, "\n%s count = %10d", s, *counter);
+}
+#endif
+
+void *SzAlloc(ISzAllocPtr p, size_t size)
+{
+ UNUSED_VAR(p)
+ if (size == 0)
+ return 0;
+ #ifdef SZ_ALLOC_DEBUG
+ Print_Alloc("Alloc", size, &g_allocCount);
+ #endif
+ return malloc(size);
+}
+
+void SzFree(ISzAllocPtr p, void *address)
+{
+ UNUSED_VAR(p)
+ #ifdef SZ_ALLOC_DEBUG
+ if (address)
+ Print_Free("Free ", &g_allocCount);
+ #endif
+ free(address);
+}
+
+void *SzAllocTemp(ISzAllocPtr p, size_t size)
+{
+ UNUSED_VAR(p)
+ if (size == 0)
+ return 0;
+ #ifdef SZ_ALLOC_DEBUG
+ Print_Alloc("Alloc_temp", size, &g_allocCountTemp);
+ /*
+ #ifdef _WIN32
+ return HeapAlloc(GetProcessHeap(), 0, size);
+ #endif
+ */
+ #endif
+ return malloc(size);
+}
+
+void SzFreeTemp(ISzAllocPtr p, void *address)
+{
+ UNUSED_VAR(p)
+ #ifdef SZ_ALLOC_DEBUG
+ if (address)
+ Print_Free("Free_temp ", &g_allocCountTemp);
+ /*
+ #ifdef _WIN32
+ HeapFree(GetProcessHeap(), 0, address);
+ return;
+ #endif
+ */
+ #endif
+ free(address);
+}
diff --git a/C/7zAlloc.h b/C/7zAlloc.h
index c0f89d7..b2b8b0c 100644
--- a/C/7zAlloc.h
+++ b/C/7zAlloc.h
@@ -1,19 +1,19 @@
-/* 7zAlloc.h -- Allocation functions
-2017-04-03 : Igor Pavlov : Public domain */
-
-#ifndef __7Z_ALLOC_H
-#define __7Z_ALLOC_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-void *SzAlloc(ISzAllocPtr p, size_t size);
-void SzFree(ISzAllocPtr p, void *address);
-
-void *SzAllocTemp(ISzAllocPtr p, size_t size);
-void SzFreeTemp(ISzAllocPtr p, void *address);
-
-EXTERN_C_END
-
-#endif
+/* 7zAlloc.h -- Allocation functions
+2023-03-04 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_7Z_ALLOC_H
+#define ZIP7_INC_7Z_ALLOC_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+void *SzAlloc(ISzAllocPtr p, size_t size);
+void SzFree(ISzAllocPtr p, void *address);
+
+void *SzAllocTemp(ISzAllocPtr p, size_t size);
+void SzFreeTemp(ISzAllocPtr p, void *address);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/7zArcIn.c b/C/7zArcIn.c
index 68cc12f..43fa7c2 100644
--- a/C/7zArcIn.c
+++ b/C/7zArcIn.c
@@ -1,1771 +1,1786 @@
-/* 7zArcIn.c -- 7z Input functions
-2018-12-31 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include <string.h>
-
-#include "7z.h"
-#include "7zBuf.h"
-#include "7zCrc.h"
-#include "CpuArch.h"
-
-#define MY_ALLOC(T, p, size, alloc) { \
- if ((p = (T *)ISzAlloc_Alloc(alloc, (size) * sizeof(T))) == NULL) return SZ_ERROR_MEM; }
-
-#define MY_ALLOC_ZE(T, p, size, alloc) { if ((size) == 0) p = NULL; else MY_ALLOC(T, p, size, alloc) }
-
-#define MY_ALLOC_AND_CPY(to, size, from, alloc) \
- { MY_ALLOC(Byte, to, size, alloc); memcpy(to, from, size); }
-
-#define MY_ALLOC_ZE_AND_CPY(to, size, from, alloc) \
- { if ((size) == 0) to = NULL; else { MY_ALLOC_AND_CPY(to, size, from, alloc) } }
-
-#define k7zMajorVersion 0
-
-enum EIdEnum
-{
- k7zIdEnd,
- k7zIdHeader,
- k7zIdArchiveProperties,
- k7zIdAdditionalStreamsInfo,
- k7zIdMainStreamsInfo,
- k7zIdFilesInfo,
- k7zIdPackInfo,
- k7zIdUnpackInfo,
- k7zIdSubStreamsInfo,
- k7zIdSize,
- k7zIdCRC,
- k7zIdFolder,
- k7zIdCodersUnpackSize,
- k7zIdNumUnpackStream,
- k7zIdEmptyStream,
- k7zIdEmptyFile,
- k7zIdAnti,
- k7zIdName,
- k7zIdCTime,
- k7zIdATime,
- k7zIdMTime,
- k7zIdWinAttrib,
- k7zIdComment,
- k7zIdEncodedHeader,
- k7zIdStartPos,
- k7zIdDummy
- // k7zNtSecure,
- // k7zParent,
- // k7zIsReal
-};
-
-const Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
-
-#define SzBitUi32s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; }
-
-static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAllocPtr alloc)
-{
- if (num == 0)
- {
- p->Defs = NULL;
- p->Vals = NULL;
- }
- else
- {
- MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc);
- MY_ALLOC(UInt32, p->Vals, num, alloc);
- }
- return SZ_OK;
-}
-
-void SzBitUi32s_Free(CSzBitUi32s *p, ISzAllocPtr alloc)
-{
- ISzAlloc_Free(alloc, p->Defs); p->Defs = NULL;
- ISzAlloc_Free(alloc, p->Vals); p->Vals = NULL;
-}
-
-#define SzBitUi64s_Init(p) { (p)->Defs = NULL; (p)->Vals = NULL; }
-
-void SzBitUi64s_Free(CSzBitUi64s *p, ISzAllocPtr alloc)
-{
- ISzAlloc_Free(alloc, p->Defs); p->Defs = NULL;
- ISzAlloc_Free(alloc, p->Vals); p->Vals = NULL;
-}
-
-
-static void SzAr_Init(CSzAr *p)
-{
- p->NumPackStreams = 0;
- p->NumFolders = 0;
-
- p->PackPositions = NULL;
- SzBitUi32s_Init(&p->FolderCRCs);
-
- p->FoCodersOffsets = NULL;
- p->FoStartPackStreamIndex = NULL;
- p->FoToCoderUnpackSizes = NULL;
- p->FoToMainUnpackSizeIndex = NULL;
- p->CoderUnpackSizes = NULL;
-
- p->CodersData = NULL;
-}
-
-static void SzAr_Free(CSzAr *p, ISzAllocPtr alloc)
-{
- ISzAlloc_Free(alloc, p->PackPositions);
- SzBitUi32s_Free(&p->FolderCRCs, alloc);
-
- ISzAlloc_Free(alloc, p->FoCodersOffsets);
- ISzAlloc_Free(alloc, p->FoStartPackStreamIndex);
- ISzAlloc_Free(alloc, p->FoToCoderUnpackSizes);
- ISzAlloc_Free(alloc, p->FoToMainUnpackSizeIndex);
- ISzAlloc_Free(alloc, p->CoderUnpackSizes);
-
- ISzAlloc_Free(alloc, p->CodersData);
-
- SzAr_Init(p);
-}
-
-
-void SzArEx_Init(CSzArEx *p)
-{
- SzAr_Init(&p->db);
-
- p->NumFiles = 0;
- p->dataPos = 0;
-
- p->UnpackPositions = NULL;
- p->IsDirs = NULL;
-
- p->FolderToFile = NULL;
- p->FileToFolder = NULL;
-
- p->FileNameOffsets = NULL;
- p->FileNames = NULL;
-
- SzBitUi32s_Init(&p->CRCs);
- SzBitUi32s_Init(&p->Attribs);
- // SzBitUi32s_Init(&p->Parents);
- SzBitUi64s_Init(&p->MTime);
- SzBitUi64s_Init(&p->CTime);
-}
-
-void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc)
-{
- ISzAlloc_Free(alloc, p->UnpackPositions);
- ISzAlloc_Free(alloc, p->IsDirs);
-
- ISzAlloc_Free(alloc, p->FolderToFile);
- ISzAlloc_Free(alloc, p->FileToFolder);
-
- ISzAlloc_Free(alloc, p->FileNameOffsets);
- ISzAlloc_Free(alloc, p->FileNames);
-
- SzBitUi32s_Free(&p->CRCs, alloc);
- SzBitUi32s_Free(&p->Attribs, alloc);
- // SzBitUi32s_Free(&p->Parents, alloc);
- SzBitUi64s_Free(&p->MTime, alloc);
- SzBitUi64s_Free(&p->CTime, alloc);
-
- SzAr_Free(&p->db, alloc);
- SzArEx_Init(p);
-}
-
-
-static int TestSignatureCandidate(const Byte *testBytes)
-{
- unsigned i;
- for (i = 0; i < k7zSignatureSize; i++)
- if (testBytes[i] != k7zSignature[i])
- return 0;
- return 1;
-}
-
-#define SzData_Clear(p) { (p)->Data = NULL; (p)->Size = 0; }
-
-#define SZ_READ_BYTE_SD(_sd_, dest) if ((_sd_)->Size == 0) return SZ_ERROR_ARCHIVE; (_sd_)->Size--; dest = *(_sd_)->Data++;
-#define SZ_READ_BYTE(dest) SZ_READ_BYTE_SD(sd, dest)
-#define SZ_READ_BYTE_2(dest) if (sd.Size == 0) return SZ_ERROR_ARCHIVE; sd.Size--; dest = *sd.Data++;
-
-#define SKIP_DATA(sd, size) { sd->Size -= (size_t)(size); sd->Data += (size_t)(size); }
-#define SKIP_DATA2(sd, size) { sd.Size -= (size_t)(size); sd.Data += (size_t)(size); }
-
-#define SZ_READ_32(dest) if (sd.Size < 4) return SZ_ERROR_ARCHIVE; \
- dest = GetUi32(sd.Data); SKIP_DATA2(sd, 4);
-
-static MY_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value)
-{
- Byte firstByte, mask;
- unsigned i;
- UInt32 v;
-
- SZ_READ_BYTE(firstByte);
- if ((firstByte & 0x80) == 0)
- {
- *value = firstByte;
- return SZ_OK;
- }
- SZ_READ_BYTE(v);
- if ((firstByte & 0x40) == 0)
- {
- *value = (((UInt32)firstByte & 0x3F) << 8) | v;
- return SZ_OK;
- }
- SZ_READ_BYTE(mask);
- *value = v | ((UInt32)mask << 8);
- mask = 0x20;
- for (i = 2; i < 8; i++)
- {
- Byte b;
- if ((firstByte & mask) == 0)
- {
- UInt64 highPart = (unsigned)firstByte & (unsigned)(mask - 1);
- *value |= (highPart << (8 * i));
- return SZ_OK;
- }
- SZ_READ_BYTE(b);
- *value |= ((UInt64)b << (8 * i));
- mask >>= 1;
- }
- return SZ_OK;
-}
-
-
-static MY_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value)
-{
- Byte firstByte;
- UInt64 value64;
- if (sd->Size == 0)
- return SZ_ERROR_ARCHIVE;
- firstByte = *sd->Data;
- if ((firstByte & 0x80) == 0)
- {
- *value = firstByte;
- sd->Data++;
- sd->Size--;
- return SZ_OK;
- }
- RINOK(ReadNumber(sd, &value64));
- if (value64 >= (UInt32)0x80000000 - 1)
- return SZ_ERROR_UNSUPPORTED;
- if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 4)))
- return SZ_ERROR_UNSUPPORTED;
- *value = (UInt32)value64;
- return SZ_OK;
-}
-
-#define ReadID(sd, value) ReadNumber(sd, value)
-
-static SRes SkipData(CSzData *sd)
-{
- UInt64 size;
- RINOK(ReadNumber(sd, &size));
- if (size > sd->Size)
- return SZ_ERROR_ARCHIVE;
- SKIP_DATA(sd, size);
- return SZ_OK;
-}
-
-static SRes WaitId(CSzData *sd, UInt32 id)
-{
- for (;;)
- {
- UInt64 type;
- RINOK(ReadID(sd, &type));
- if (type == id)
- return SZ_OK;
- if (type == k7zIdEnd)
- return SZ_ERROR_ARCHIVE;
- RINOK(SkipData(sd));
- }
-}
-
-static SRes RememberBitVector(CSzData *sd, UInt32 numItems, const Byte **v)
-{
- UInt32 numBytes = (numItems + 7) >> 3;
- if (numBytes > sd->Size)
- return SZ_ERROR_ARCHIVE;
- *v = sd->Data;
- SKIP_DATA(sd, numBytes);
- return SZ_OK;
-}
-
-static UInt32 CountDefinedBits(const Byte *bits, UInt32 numItems)
-{
- Byte b = 0;
- unsigned m = 0;
- UInt32 sum = 0;
- for (; numItems != 0; numItems--)
- {
- if (m == 0)
- {
- b = *bits++;
- m = 8;
- }
- m--;
- sum += ((b >> m) & 1);
- }
- return sum;
-}
-
-static MY_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAllocPtr alloc)
-{
- Byte allAreDefined;
- Byte *v2;
- UInt32 numBytes = (numItems + 7) >> 3;
- *v = NULL;
- SZ_READ_BYTE(allAreDefined);
- if (numBytes == 0)
- return SZ_OK;
- if (allAreDefined == 0)
- {
- if (numBytes > sd->Size)
- return SZ_ERROR_ARCHIVE;
- MY_ALLOC_AND_CPY(*v, numBytes, sd->Data, alloc);
- SKIP_DATA(sd, numBytes);
- return SZ_OK;
- }
- MY_ALLOC(Byte, *v, numBytes, alloc);
- v2 = *v;
- memset(v2, 0xFF, (size_t)numBytes);
- {
- unsigned numBits = (unsigned)numItems & 7;
- if (numBits != 0)
- v2[(size_t)numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits));
- }
- return SZ_OK;
-}
-
-static MY_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc)
-{
- UInt32 i;
- CSzData sd;
- UInt32 *vals;
- const Byte *defs;
- MY_ALLOC_ZE(UInt32, crcs->Vals, numItems, alloc);
- sd = *sd2;
- defs = crcs->Defs;
- vals = crcs->Vals;
- for (i = 0; i < numItems; i++)
- if (SzBitArray_Check(defs, i))
- {
- SZ_READ_32(vals[i]);
- }
- else
- vals[i] = 0;
- *sd2 = sd;
- return SZ_OK;
-}
-
-static SRes ReadBitUi32s(CSzData *sd, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc)
-{
- SzBitUi32s_Free(crcs, alloc);
- RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc));
- return ReadUi32s(sd, numItems, crcs, alloc);
-}
-
-static SRes SkipBitUi32s(CSzData *sd, UInt32 numItems)
-{
- Byte allAreDefined;
- UInt32 numDefined = numItems;
- SZ_READ_BYTE(allAreDefined);
- if (!allAreDefined)
- {
- size_t numBytes = (numItems + 7) >> 3;
- if (numBytes > sd->Size)
- return SZ_ERROR_ARCHIVE;
- numDefined = CountDefinedBits(sd->Data, numItems);
- SKIP_DATA(sd, numBytes);
- }
- if (numDefined > (sd->Size >> 2))
- return SZ_ERROR_ARCHIVE;
- SKIP_DATA(sd, (size_t)numDefined * 4);
- return SZ_OK;
-}
-
-static SRes ReadPackInfo(CSzAr *p, CSzData *sd, ISzAllocPtr alloc)
-{
- RINOK(SzReadNumber32(sd, &p->NumPackStreams));
-
- RINOK(WaitId(sd, k7zIdSize));
- MY_ALLOC(UInt64, p->PackPositions, (size_t)p->NumPackStreams + 1, alloc);
- {
- UInt64 sum = 0;
- UInt32 i;
- UInt32 numPackStreams = p->NumPackStreams;
- for (i = 0; i < numPackStreams; i++)
- {
- UInt64 packSize;
- p->PackPositions[i] = sum;
- RINOK(ReadNumber(sd, &packSize));
- sum += packSize;
- if (sum < packSize)
- return SZ_ERROR_ARCHIVE;
- }
- p->PackPositions[i] = sum;
- }
-
- for (;;)
- {
- UInt64 type;
- RINOK(ReadID(sd, &type));
- if (type == k7zIdEnd)
- return SZ_OK;
- if (type == k7zIdCRC)
- {
- /* CRC of packed streams is unused now */
- RINOK(SkipBitUi32s(sd, p->NumPackStreams));
- continue;
- }
- RINOK(SkipData(sd));
- }
-}
-
-/*
-static SRes SzReadSwitch(CSzData *sd)
-{
- Byte external;
- RINOK(SzReadByte(sd, &external));
- return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED;
-}
-*/
-
-#define k_NumCodersStreams_in_Folder_MAX (SZ_NUM_BONDS_IN_FOLDER_MAX + SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX)
-
-SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd)
-{
- UInt32 numCoders, i;
- UInt32 numInStreams = 0;
- const Byte *dataStart = sd->Data;
-
- f->NumCoders = 0;
- f->NumBonds = 0;
- f->NumPackStreams = 0;
- f->UnpackStream = 0;
-
- RINOK(SzReadNumber32(sd, &numCoders));
- if (numCoders == 0 || numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX)
- return SZ_ERROR_UNSUPPORTED;
-
- for (i = 0; i < numCoders; i++)
- {
- Byte mainByte;
- CSzCoderInfo *coder = f->Coders + i;
- unsigned idSize, j;
- UInt64 id;
-
- SZ_READ_BYTE(mainByte);
- if ((mainByte & 0xC0) != 0)
- return SZ_ERROR_UNSUPPORTED;
-
- idSize = (unsigned)(mainByte & 0xF);
- if (idSize > sizeof(id))
- return SZ_ERROR_UNSUPPORTED;
- if (idSize > sd->Size)
- return SZ_ERROR_ARCHIVE;
- id = 0;
- for (j = 0; j < idSize; j++)
- {
- id = ((id << 8) | *sd->Data);
- sd->Data++;
- sd->Size--;
- }
- if (id > (UInt32)0xFFFFFFFF)
- return SZ_ERROR_UNSUPPORTED;
- coder->MethodID = (UInt32)id;
-
- coder->NumStreams = 1;
- coder->PropsOffset = 0;
- coder->PropsSize = 0;
-
- if ((mainByte & 0x10) != 0)
- {
- UInt32 numStreams;
-
- RINOK(SzReadNumber32(sd, &numStreams));
- if (numStreams > k_NumCodersStreams_in_Folder_MAX)
- return SZ_ERROR_UNSUPPORTED;
- coder->NumStreams = (Byte)numStreams;
-
- RINOK(SzReadNumber32(sd, &numStreams));
- if (numStreams != 1)
- return SZ_ERROR_UNSUPPORTED;
- }
-
- numInStreams += coder->NumStreams;
-
- if (numInStreams > k_NumCodersStreams_in_Folder_MAX)
- return SZ_ERROR_UNSUPPORTED;
-
- if ((mainByte & 0x20) != 0)
- {
- UInt32 propsSize = 0;
- RINOK(SzReadNumber32(sd, &propsSize));
- if (propsSize > sd->Size)
- return SZ_ERROR_ARCHIVE;
- if (propsSize >= 0x80)
- return SZ_ERROR_UNSUPPORTED;
- coder->PropsOffset = sd->Data - dataStart;
- coder->PropsSize = (Byte)propsSize;
- sd->Data += (size_t)propsSize;
- sd->Size -= (size_t)propsSize;
- }
- }
-
- /*
- if (numInStreams == 1 && numCoders == 1)
- {
- f->NumPackStreams = 1;
- f->PackStreams[0] = 0;
- }
- else
- */
- {
- Byte streamUsed[k_NumCodersStreams_in_Folder_MAX];
- UInt32 numBonds, numPackStreams;
-
- numBonds = numCoders - 1;
- if (numInStreams < numBonds)
- return SZ_ERROR_ARCHIVE;
- if (numBonds > SZ_NUM_BONDS_IN_FOLDER_MAX)
- return SZ_ERROR_UNSUPPORTED;
- f->NumBonds = numBonds;
-
- numPackStreams = numInStreams - numBonds;
- if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX)
- return SZ_ERROR_UNSUPPORTED;
- f->NumPackStreams = numPackStreams;
-
- for (i = 0; i < numInStreams; i++)
- streamUsed[i] = False;
-
- if (numBonds != 0)
- {
- Byte coderUsed[SZ_NUM_CODERS_IN_FOLDER_MAX];
-
- for (i = 0; i < numCoders; i++)
- coderUsed[i] = False;
-
- for (i = 0; i < numBonds; i++)
- {
- CSzBond *bp = f->Bonds + i;
-
- RINOK(SzReadNumber32(sd, &bp->InIndex));
- if (bp->InIndex >= numInStreams || streamUsed[bp->InIndex])
- return SZ_ERROR_ARCHIVE;
- streamUsed[bp->InIndex] = True;
-
- RINOK(SzReadNumber32(sd, &bp->OutIndex));
- if (bp->OutIndex >= numCoders || coderUsed[bp->OutIndex])
- return SZ_ERROR_ARCHIVE;
- coderUsed[bp->OutIndex] = True;
- }
-
- for (i = 0; i < numCoders; i++)
- if (!coderUsed[i])
- {
- f->UnpackStream = i;
- break;
- }
-
- if (i == numCoders)
- return SZ_ERROR_ARCHIVE;
- }
-
- if (numPackStreams == 1)
- {
- for (i = 0; i < numInStreams; i++)
- if (!streamUsed[i])
- break;
- if (i == numInStreams)
- return SZ_ERROR_ARCHIVE;
- f->PackStreams[0] = i;
- }
- else
- for (i = 0; i < numPackStreams; i++)
- {
- UInt32 index;
- RINOK(SzReadNumber32(sd, &index));
- if (index >= numInStreams || streamUsed[index])
- return SZ_ERROR_ARCHIVE;
- streamUsed[index] = True;
- f->PackStreams[i] = index;
- }
- }
-
- f->NumCoders = numCoders;
-
- return SZ_OK;
-}
-
-
-static MY_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num)
-{
- CSzData sd;
- sd = *sd2;
- for (; num != 0; num--)
- {
- Byte firstByte, mask;
- unsigned i;
- SZ_READ_BYTE_2(firstByte);
- if ((firstByte & 0x80) == 0)
- continue;
- if ((firstByte & 0x40) == 0)
- {
- if (sd.Size == 0)
- return SZ_ERROR_ARCHIVE;
- sd.Size--;
- sd.Data++;
- continue;
- }
- mask = 0x20;
- for (i = 2; i < 8 && (firstByte & mask) != 0; i++)
- mask >>= 1;
- if (i > sd.Size)
- return SZ_ERROR_ARCHIVE;
- SKIP_DATA2(sd, i);
- }
- *sd2 = sd;
- return SZ_OK;
-}
-
-
-#define k_Scan_NumCoders_MAX 64
-#define k_Scan_NumCodersStreams_in_Folder_MAX 64
-
-
-static SRes ReadUnpackInfo(CSzAr *p,
- CSzData *sd2,
- UInt32 numFoldersMax,
- const CBuf *tempBufs, UInt32 numTempBufs,
- ISzAllocPtr alloc)
-{
- CSzData sd;
-
- UInt32 fo, numFolders, numCodersOutStreams, packStreamIndex;
- const Byte *startBufPtr;
- Byte external;
-
- RINOK(WaitId(sd2, k7zIdFolder));
-
- RINOK(SzReadNumber32(sd2, &numFolders));
- if (numFolders > numFoldersMax)
- return SZ_ERROR_UNSUPPORTED;
- p->NumFolders = numFolders;
-
- SZ_READ_BYTE_SD(sd2, external);
- if (external == 0)
- sd = *sd2;
- else
- {
- UInt32 index;
- RINOK(SzReadNumber32(sd2, &index));
- if (index >= numTempBufs)
- return SZ_ERROR_ARCHIVE;
- sd.Data = tempBufs[index].data;
- sd.Size = tempBufs[index].size;
- }
-
- MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc);
- MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc);
- MY_ALLOC(UInt32, p->FoToCoderUnpackSizes, (size_t)numFolders + 1, alloc);
- MY_ALLOC_ZE(Byte, p->FoToMainUnpackSizeIndex, (size_t)numFolders, alloc);
-
- startBufPtr = sd.Data;
-
- packStreamIndex = 0;
- numCodersOutStreams = 0;
-
- for (fo = 0; fo < numFolders; fo++)
- {
- UInt32 numCoders, ci, numInStreams = 0;
-
- p->FoCodersOffsets[fo] = sd.Data - startBufPtr;
-
- RINOK(SzReadNumber32(&sd, &numCoders));
- if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX)
- return SZ_ERROR_UNSUPPORTED;
-
- for (ci = 0; ci < numCoders; ci++)
- {
- Byte mainByte;
- unsigned idSize;
- UInt32 coderInStreams;
-
- SZ_READ_BYTE_2(mainByte);
- if ((mainByte & 0xC0) != 0)
- return SZ_ERROR_UNSUPPORTED;
- idSize = (mainByte & 0xF);
- if (idSize > 8)
- return SZ_ERROR_UNSUPPORTED;
- if (idSize > sd.Size)
- return SZ_ERROR_ARCHIVE;
- SKIP_DATA2(sd, idSize);
-
- coderInStreams = 1;
-
- if ((mainByte & 0x10) != 0)
- {
- UInt32 coderOutStreams;
- RINOK(SzReadNumber32(&sd, &coderInStreams));
- RINOK(SzReadNumber32(&sd, &coderOutStreams));
- if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX || coderOutStreams != 1)
- return SZ_ERROR_UNSUPPORTED;
- }
-
- numInStreams += coderInStreams;
-
- if ((mainByte & 0x20) != 0)
- {
- UInt32 propsSize;
- RINOK(SzReadNumber32(&sd, &propsSize));
- if (propsSize > sd.Size)
- return SZ_ERROR_ARCHIVE;
- SKIP_DATA2(sd, propsSize);
- }
- }
-
- {
- UInt32 indexOfMainStream = 0;
- UInt32 numPackStreams = 1;
-
- if (numCoders != 1 || numInStreams != 1)
- {
- Byte streamUsed[k_Scan_NumCodersStreams_in_Folder_MAX];
- Byte coderUsed[k_Scan_NumCoders_MAX];
-
- UInt32 i;
- UInt32 numBonds = numCoders - 1;
- if (numInStreams < numBonds)
- return SZ_ERROR_ARCHIVE;
-
- if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX)
- return SZ_ERROR_UNSUPPORTED;
-
- for (i = 0; i < numInStreams; i++)
- streamUsed[i] = False;
- for (i = 0; i < numCoders; i++)
- coderUsed[i] = False;
-
- for (i = 0; i < numBonds; i++)
- {
- UInt32 index;
-
- RINOK(SzReadNumber32(&sd, &index));
- if (index >= numInStreams || streamUsed[index])
- return SZ_ERROR_ARCHIVE;
- streamUsed[index] = True;
-
- RINOK(SzReadNumber32(&sd, &index));
- if (index >= numCoders || coderUsed[index])
- return SZ_ERROR_ARCHIVE;
- coderUsed[index] = True;
- }
-
- numPackStreams = numInStreams - numBonds;
-
- if (numPackStreams != 1)
- for (i = 0; i < numPackStreams; i++)
- {
- UInt32 index;
- RINOK(SzReadNumber32(&sd, &index));
- if (index >= numInStreams || streamUsed[index])
- return SZ_ERROR_ARCHIVE;
- streamUsed[index] = True;
- }
-
- for (i = 0; i < numCoders; i++)
- if (!coderUsed[i])
- {
- indexOfMainStream = i;
- break;
- }
-
- if (i == numCoders)
- return SZ_ERROR_ARCHIVE;
- }
-
- p->FoStartPackStreamIndex[fo] = packStreamIndex;
- p->FoToCoderUnpackSizes[fo] = numCodersOutStreams;
- p->FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream;
- numCodersOutStreams += numCoders;
- if (numCodersOutStreams < numCoders)
- return SZ_ERROR_UNSUPPORTED;
- if (numPackStreams > p->NumPackStreams - packStreamIndex)
- return SZ_ERROR_ARCHIVE;
- packStreamIndex += numPackStreams;
- }
- }
-
- p->FoToCoderUnpackSizes[fo] = numCodersOutStreams;
-
- {
- size_t dataSize = sd.Data - startBufPtr;
- p->FoStartPackStreamIndex[fo] = packStreamIndex;
- p->FoCodersOffsets[fo] = dataSize;
- MY_ALLOC_ZE_AND_CPY(p->CodersData, dataSize, startBufPtr, alloc);
- }
-
- if (external != 0)
- {
- if (sd.Size != 0)
- return SZ_ERROR_ARCHIVE;
- sd = *sd2;
- }
-
- RINOK(WaitId(&sd, k7zIdCodersUnpackSize));
-
- MY_ALLOC_ZE(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc);
- {
- UInt32 i;
- for (i = 0; i < numCodersOutStreams; i++)
- {
- RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i));
- }
- }
-
- for (;;)
- {
- UInt64 type;
- RINOK(ReadID(&sd, &type));
- if (type == k7zIdEnd)
- {
- *sd2 = sd;
- return SZ_OK;
- }
- if (type == k7zIdCRC)
- {
- RINOK(ReadBitUi32s(&sd, numFolders, &p->FolderCRCs, alloc));
- continue;
- }
- RINOK(SkipData(&sd));
- }
-}
-
-
-UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex)
-{
- return p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex] + p->FoToMainUnpackSizeIndex[folderIndex]];
-}
-
-
-typedef struct
-{
- UInt32 NumTotalSubStreams;
- UInt32 NumSubDigests;
- CSzData sdNumSubStreams;
- CSzData sdSizes;
- CSzData sdCRCs;
-} CSubStreamInfo;
-
-
-static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi)
-{
- UInt64 type = 0;
- UInt32 numSubDigests = 0;
- UInt32 numFolders = p->NumFolders;
- UInt32 numUnpackStreams = numFolders;
- UInt32 numUnpackSizesInData = 0;
-
- for (;;)
- {
- RINOK(ReadID(sd, &type));
- if (type == k7zIdNumUnpackStream)
- {
- UInt32 i;
- ssi->sdNumSubStreams.Data = sd->Data;
- numUnpackStreams = 0;
- numSubDigests = 0;
- for (i = 0; i < numFolders; i++)
- {
- UInt32 numStreams;
- RINOK(SzReadNumber32(sd, &numStreams));
- if (numUnpackStreams > numUnpackStreams + numStreams)
- return SZ_ERROR_UNSUPPORTED;
- numUnpackStreams += numStreams;
- if (numStreams != 0)
- numUnpackSizesInData += (numStreams - 1);
- if (numStreams != 1 || !SzBitWithVals_Check(&p->FolderCRCs, i))
- numSubDigests += numStreams;
- }
- ssi->sdNumSubStreams.Size = sd->Data - ssi->sdNumSubStreams.Data;
- continue;
- }
- if (type == k7zIdCRC || type == k7zIdSize || type == k7zIdEnd)
- break;
- RINOK(SkipData(sd));
- }
-
- if (!ssi->sdNumSubStreams.Data)
- {
- numSubDigests = numFolders;
- if (p->FolderCRCs.Defs)
- numSubDigests = numFolders - CountDefinedBits(p->FolderCRCs.Defs, numFolders);
- }
-
- ssi->NumTotalSubStreams = numUnpackStreams;
- ssi->NumSubDigests = numSubDigests;
-
- if (type == k7zIdSize)
- {
- ssi->sdSizes.Data = sd->Data;
- RINOK(SkipNumbers(sd, numUnpackSizesInData));
- ssi->sdSizes.Size = sd->Data - ssi->sdSizes.Data;
- RINOK(ReadID(sd, &type));
- }
-
- for (;;)
- {
- if (type == k7zIdEnd)
- return SZ_OK;
- if (type == k7zIdCRC)
- {
- ssi->sdCRCs.Data = sd->Data;
- RINOK(SkipBitUi32s(sd, numSubDigests));
- ssi->sdCRCs.Size = sd->Data - ssi->sdCRCs.Data;
- }
- else
- {
- RINOK(SkipData(sd));
- }
- RINOK(ReadID(sd, &type));
- }
-}
-
-static SRes SzReadStreamsInfo(CSzAr *p,
- CSzData *sd,
- UInt32 numFoldersMax, const CBuf *tempBufs, UInt32 numTempBufs,
- UInt64 *dataOffset,
- CSubStreamInfo *ssi,
- ISzAllocPtr alloc)
-{
- UInt64 type;
-
- SzData_Clear(&ssi->sdSizes);
- SzData_Clear(&ssi->sdCRCs);
- SzData_Clear(&ssi->sdNumSubStreams);
-
- *dataOffset = 0;
- RINOK(ReadID(sd, &type));
- if (type == k7zIdPackInfo)
- {
- RINOK(ReadNumber(sd, dataOffset));
- RINOK(ReadPackInfo(p, sd, alloc));
- RINOK(ReadID(sd, &type));
- }
- if (type == k7zIdUnpackInfo)
- {
- RINOK(ReadUnpackInfo(p, sd, numFoldersMax, tempBufs, numTempBufs, alloc));
- RINOK(ReadID(sd, &type));
- }
- if (type == k7zIdSubStreamsInfo)
- {
- RINOK(ReadSubStreamsInfo(p, sd, ssi));
- RINOK(ReadID(sd, &type));
- }
- else
- {
- ssi->NumTotalSubStreams = p->NumFolders;
- // ssi->NumSubDigests = 0;
- }
-
- return (type == k7zIdEnd ? SZ_OK : SZ_ERROR_UNSUPPORTED);
-}
-
-static SRes SzReadAndDecodePackedStreams(
- ILookInStream *inStream,
- CSzData *sd,
- CBuf *tempBufs,
- UInt32 numFoldersMax,
- UInt64 baseOffset,
- CSzAr *p,
- ISzAllocPtr allocTemp)
-{
- UInt64 dataStartPos;
- UInt32 fo;
- CSubStreamInfo ssi;
-
- RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp));
-
- dataStartPos += baseOffset;
- if (p->NumFolders == 0)
- return SZ_ERROR_ARCHIVE;
-
- for (fo = 0; fo < p->NumFolders; fo++)
- Buf_Init(tempBufs + fo);
-
- for (fo = 0; fo < p->NumFolders; fo++)
- {
- CBuf *tempBuf = tempBufs + fo;
- UInt64 unpackSize = SzAr_GetFolderUnpackSize(p, fo);
- if ((size_t)unpackSize != unpackSize)
- return SZ_ERROR_MEM;
- if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp))
- return SZ_ERROR_MEM;
- }
-
- for (fo = 0; fo < p->NumFolders; fo++)
- {
- const CBuf *tempBuf = tempBufs + fo;
- RINOK(LookInStream_SeekTo(inStream, dataStartPos));
- RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp));
- }
-
- return SZ_OK;
-}
-
-static SRes SzReadFileNames(const Byte *data, size_t size, UInt32 numFiles, size_t *offsets)
-{
- size_t pos = 0;
- *offsets++ = 0;
- if (numFiles == 0)
- return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE;
- if (size < 2)
- return SZ_ERROR_ARCHIVE;
- if (data[size - 2] != 0 || data[size - 1] != 0)
- return SZ_ERROR_ARCHIVE;
- do
- {
- const Byte *p;
- if (pos == size)
- return SZ_ERROR_ARCHIVE;
- for (p = data + pos;
- #ifdef _WIN32
- *(const UInt16 *)p != 0
- #else
- p[0] != 0 || p[1] != 0
- #endif
- ; p += 2);
- pos = p - data + 2;
- *offsets++ = (pos >> 1);
- }
- while (--numFiles);
- return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
-}
-
-static MY_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num,
- CSzData *sd2,
- const CBuf *tempBufs, UInt32 numTempBufs,
- ISzAllocPtr alloc)
-{
- CSzData sd;
- UInt32 i;
- CNtfsFileTime *vals;
- Byte *defs;
- Byte external;
-
- RINOK(ReadBitVector(sd2, num, &p->Defs, alloc));
-
- SZ_READ_BYTE_SD(sd2, external);
- if (external == 0)
- sd = *sd2;
- else
- {
- UInt32 index;
- RINOK(SzReadNumber32(sd2, &index));
- if (index >= numTempBufs)
- return SZ_ERROR_ARCHIVE;
- sd.Data = tempBufs[index].data;
- sd.Size = tempBufs[index].size;
- }
-
- MY_ALLOC_ZE(CNtfsFileTime, p->Vals, num, alloc);
- vals = p->Vals;
- defs = p->Defs;
- for (i = 0; i < num; i++)
- if (SzBitArray_Check(defs, i))
- {
- if (sd.Size < 8)
- return SZ_ERROR_ARCHIVE;
- vals[i].Low = GetUi32(sd.Data);
- vals[i].High = GetUi32(sd.Data + 4);
- SKIP_DATA2(sd, 8);
- }
- else
- vals[i].High = vals[i].Low = 0;
-
- if (external == 0)
- *sd2 = sd;
-
- return SZ_OK;
-}
-
-
-#define NUM_ADDITIONAL_STREAMS_MAX 8
-
-
-static SRes SzReadHeader2(
- CSzArEx *p, /* allocMain */
- CSzData *sd,
- ILookInStream *inStream,
- CBuf *tempBufs, UInt32 *numTempBufs,
- ISzAllocPtr allocMain,
- ISzAllocPtr allocTemp
- )
-{
- CSubStreamInfo ssi;
-
-{
- UInt64 type;
-
- SzData_Clear(&ssi.sdSizes);
- SzData_Clear(&ssi.sdCRCs);
- SzData_Clear(&ssi.sdNumSubStreams);
-
- ssi.NumSubDigests = 0;
- ssi.NumTotalSubStreams = 0;
-
- RINOK(ReadID(sd, &type));
-
- if (type == k7zIdArchiveProperties)
- {
- for (;;)
- {
- UInt64 type2;
- RINOK(ReadID(sd, &type2));
- if (type2 == k7zIdEnd)
- break;
- RINOK(SkipData(sd));
- }
- RINOK(ReadID(sd, &type));
- }
-
- if (type == k7zIdAdditionalStreamsInfo)
- {
- CSzAr tempAr;
- SRes res;
-
- SzAr_Init(&tempAr);
- res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX,
- p->startPosAfterHeader, &tempAr, allocTemp);
- *numTempBufs = tempAr.NumFolders;
- SzAr_Free(&tempAr, allocTemp);
-
- if (res != SZ_OK)
- return res;
- RINOK(ReadID(sd, &type));
- }
-
- if (type == k7zIdMainStreamsInfo)
- {
- RINOK(SzReadStreamsInfo(&p->db, sd, (UInt32)1 << 30, tempBufs, *numTempBufs,
- &p->dataPos, &ssi, allocMain));
- p->dataPos += p->startPosAfterHeader;
- RINOK(ReadID(sd, &type));
- }
-
- if (type == k7zIdEnd)
- {
- return SZ_OK;
- }
-
- if (type != k7zIdFilesInfo)
- return SZ_ERROR_ARCHIVE;
-}
-
-{
- UInt32 numFiles = 0;
- UInt32 numEmptyStreams = 0;
- const Byte *emptyStreams = NULL;
- const Byte *emptyFiles = NULL;
-
- RINOK(SzReadNumber32(sd, &numFiles));
- p->NumFiles = numFiles;
-
- for (;;)
- {
- UInt64 type;
- UInt64 size;
- RINOK(ReadID(sd, &type));
- if (type == k7zIdEnd)
- break;
- RINOK(ReadNumber(sd, &size));
- if (size > sd->Size)
- return SZ_ERROR_ARCHIVE;
-
- if (type >= ((UInt32)1 << 8))
- {
- SKIP_DATA(sd, size);
- }
- else switch ((unsigned)type)
- {
- case k7zIdName:
- {
- size_t namesSize;
- const Byte *namesData;
- Byte external;
-
- SZ_READ_BYTE(external);
- if (external == 0)
- {
- namesSize = (size_t)size - 1;
- namesData = sd->Data;
- }
- else
- {
- UInt32 index;
- RINOK(SzReadNumber32(sd, &index));
- if (index >= *numTempBufs)
- return SZ_ERROR_ARCHIVE;
- namesData = (tempBufs)[index].data;
- namesSize = (tempBufs)[index].size;
- }
-
- if ((namesSize & 1) != 0)
- return SZ_ERROR_ARCHIVE;
- MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain);
- MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain);
- RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets))
- if (external == 0)
- {
- SKIP_DATA(sd, namesSize);
- }
- break;
- }
- case k7zIdEmptyStream:
- {
- RINOK(RememberBitVector(sd, numFiles, &emptyStreams));
- numEmptyStreams = CountDefinedBits(emptyStreams, numFiles);
- emptyFiles = NULL;
- break;
- }
- case k7zIdEmptyFile:
- {
- RINOK(RememberBitVector(sd, numEmptyStreams, &emptyFiles));
- break;
- }
- case k7zIdWinAttrib:
- {
- Byte external;
- CSzData sdSwitch;
- CSzData *sdPtr;
- SzBitUi32s_Free(&p->Attribs, allocMain);
- RINOK(ReadBitVector(sd, numFiles, &p->Attribs.Defs, allocMain));
-
- SZ_READ_BYTE(external);
- if (external == 0)
- sdPtr = sd;
- else
- {
- UInt32 index;
- RINOK(SzReadNumber32(sd, &index));
- if (index >= *numTempBufs)
- return SZ_ERROR_ARCHIVE;
- sdSwitch.Data = (tempBufs)[index].data;
- sdSwitch.Size = (tempBufs)[index].size;
- sdPtr = &sdSwitch;
- }
- RINOK(ReadUi32s(sdPtr, numFiles, &p->Attribs, allocMain));
- break;
- }
- /*
- case k7zParent:
- {
- SzBitUi32s_Free(&p->Parents, allocMain);
- RINOK(ReadBitVector(sd, numFiles, &p->Parents.Defs, allocMain));
- RINOK(SzReadSwitch(sd));
- RINOK(ReadUi32s(sd, numFiles, &p->Parents, allocMain));
- break;
- }
- */
- case k7zIdMTime: RINOK(ReadTime(&p->MTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break;
- case k7zIdCTime: RINOK(ReadTime(&p->CTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)); break;
- default:
- {
- SKIP_DATA(sd, size);
- }
- }
- }
-
- if (numFiles - numEmptyStreams != ssi.NumTotalSubStreams)
- return SZ_ERROR_ARCHIVE;
-
- for (;;)
- {
- UInt64 type;
- RINOK(ReadID(sd, &type));
- if (type == k7zIdEnd)
- break;
- RINOK(SkipData(sd));
- }
-
- {
- UInt32 i;
- UInt32 emptyFileIndex = 0;
- UInt32 folderIndex = 0;
- UInt32 remSubStreams = 0;
- UInt32 numSubStreams = 0;
- UInt64 unpackPos = 0;
- const Byte *digestsDefs = NULL;
- const Byte *digestsVals = NULL;
- UInt32 digestsValsIndex = 0;
- UInt32 digestIndex;
- Byte allDigestsDefined = 0;
- Byte isDirMask = 0;
- Byte crcMask = 0;
- Byte mask = 0x80;
-
- MY_ALLOC(UInt32, p->FolderToFile, p->db.NumFolders + 1, allocMain);
- MY_ALLOC_ZE(UInt32, p->FileToFolder, p->NumFiles, allocMain);
- MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain);
- MY_ALLOC_ZE(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain);
-
- RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain));
-
- if (ssi.sdCRCs.Size != 0)
- {
- SZ_READ_BYTE_SD(&ssi.sdCRCs, allDigestsDefined);
- if (allDigestsDefined)
- digestsVals = ssi.sdCRCs.Data;
- else
- {
- size_t numBytes = (ssi.NumSubDigests + 7) >> 3;
- digestsDefs = ssi.sdCRCs.Data;
- digestsVals = digestsDefs + numBytes;
- }
- }
-
- digestIndex = 0;
-
- for (i = 0; i < numFiles; i++, mask >>= 1)
- {
- if (mask == 0)
- {
- UInt32 byteIndex = (i - 1) >> 3;
- p->IsDirs[byteIndex] = isDirMask;
- p->CRCs.Defs[byteIndex] = crcMask;
- isDirMask = 0;
- crcMask = 0;
- mask = 0x80;
- }
-
- p->UnpackPositions[i] = unpackPos;
- p->CRCs.Vals[i] = 0;
-
- if (emptyStreams && SzBitArray_Check(emptyStreams, i))
- {
- if (emptyFiles)
- {
- if (!SzBitArray_Check(emptyFiles, emptyFileIndex))
- isDirMask |= mask;
- emptyFileIndex++;
- }
- else
- isDirMask |= mask;
- if (remSubStreams == 0)
- {
- p->FileToFolder[i] = (UInt32)-1;
- continue;
- }
- }
-
- if (remSubStreams == 0)
- {
- for (;;)
- {
- if (folderIndex >= p->db.NumFolders)
- return SZ_ERROR_ARCHIVE;
- p->FolderToFile[folderIndex] = i;
- numSubStreams = 1;
- if (ssi.sdNumSubStreams.Data)
- {
- RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams));
- }
- remSubStreams = numSubStreams;
- if (numSubStreams != 0)
- break;
- {
- UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
- unpackPos += folderUnpackSize;
- if (unpackPos < folderUnpackSize)
- return SZ_ERROR_ARCHIVE;
- }
-
- folderIndex++;
- }
- }
-
- p->FileToFolder[i] = folderIndex;
-
- if (emptyStreams && SzBitArray_Check(emptyStreams, i))
- continue;
-
- if (--remSubStreams == 0)
- {
- UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
- UInt64 startFolderUnpackPos = p->UnpackPositions[p->FolderToFile[folderIndex]];
- if (folderUnpackSize < unpackPos - startFolderUnpackPos)
- return SZ_ERROR_ARCHIVE;
- unpackPos = startFolderUnpackPos + folderUnpackSize;
- if (unpackPos < folderUnpackSize)
- return SZ_ERROR_ARCHIVE;
-
- if (numSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, i))
- {
- p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex];
- crcMask |= mask;
- }
- else if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex)))
- {
- p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4);
- digestsValsIndex++;
- crcMask |= mask;
- }
-
- folderIndex++;
- }
- else
- {
- UInt64 v;
- RINOK(ReadNumber(&ssi.sdSizes, &v));
- unpackPos += v;
- if (unpackPos < v)
- return SZ_ERROR_ARCHIVE;
- if (allDigestsDefined || (digestsDefs && SzBitArray_Check(digestsDefs, digestIndex)))
- {
- p->CRCs.Vals[i] = GetUi32(digestsVals + (size_t)digestsValsIndex * 4);
- digestsValsIndex++;
- crcMask |= mask;
- }
- }
- }
-
- if (mask != 0x80)
- {
- UInt32 byteIndex = (i - 1) >> 3;
- p->IsDirs[byteIndex] = isDirMask;
- p->CRCs.Defs[byteIndex] = crcMask;
- }
-
- p->UnpackPositions[i] = unpackPos;
-
- if (remSubStreams != 0)
- return SZ_ERROR_ARCHIVE;
-
- for (;;)
- {
- p->FolderToFile[folderIndex] = i;
- if (folderIndex >= p->db.NumFolders)
- break;
- if (!ssi.sdNumSubStreams.Data)
- return SZ_ERROR_ARCHIVE;
- RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams));
- if (numSubStreams != 0)
- return SZ_ERROR_ARCHIVE;
- /*
- {
- UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
- unpackPos += folderUnpackSize;
- if (unpackPos < folderUnpackSize)
- return SZ_ERROR_ARCHIVE;
- }
- */
- folderIndex++;
- }
-
- if (ssi.sdNumSubStreams.Data && ssi.sdNumSubStreams.Size != 0)
- return SZ_ERROR_ARCHIVE;
- }
-}
- return SZ_OK;
-}
-
-
-static SRes SzReadHeader(
- CSzArEx *p,
- CSzData *sd,
- ILookInStream *inStream,
- ISzAllocPtr allocMain,
- ISzAllocPtr allocTemp)
-{
- UInt32 i;
- UInt32 numTempBufs = 0;
- SRes res;
- CBuf tempBufs[NUM_ADDITIONAL_STREAMS_MAX];
-
- for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++)
- Buf_Init(tempBufs + i);
-
- res = SzReadHeader2(p, sd, inStream,
- tempBufs, &numTempBufs,
- allocMain, allocTemp);
-
- for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++)
- Buf_Free(tempBufs + i, allocTemp);
-
- RINOK(res);
-
- if (sd->Size != 0)
- return SZ_ERROR_FAIL;
-
- return res;
-}
-
-static SRes SzArEx_Open2(
- CSzArEx *p,
- ILookInStream *inStream,
- ISzAllocPtr allocMain,
- ISzAllocPtr allocTemp)
-{
- Byte header[k7zStartHeaderSize];
- Int64 startArcPos;
- UInt64 nextHeaderOffset, nextHeaderSize;
- size_t nextHeaderSizeT;
- UInt32 nextHeaderCRC;
- CBuf buf;
- SRes res;
-
- startArcPos = 0;
- RINOK(ILookInStream_Seek(inStream, &startArcPos, SZ_SEEK_CUR));
-
- RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE));
-
- if (!TestSignatureCandidate(header))
- return SZ_ERROR_NO_ARCHIVE;
- if (header[6] != k7zMajorVersion)
- return SZ_ERROR_UNSUPPORTED;
-
- nextHeaderOffset = GetUi64(header + 12);
- nextHeaderSize = GetUi64(header + 20);
- nextHeaderCRC = GetUi32(header + 28);
-
- p->startPosAfterHeader = startArcPos + k7zStartHeaderSize;
-
- if (CrcCalc(header + 12, 20) != GetUi32(header + 8))
- return SZ_ERROR_CRC;
-
- nextHeaderSizeT = (size_t)nextHeaderSize;
- if (nextHeaderSizeT != nextHeaderSize)
- return SZ_ERROR_MEM;
- if (nextHeaderSizeT == 0)
- return SZ_OK;
- if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize ||
- nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize)
- return SZ_ERROR_NO_ARCHIVE;
-
- {
- Int64 pos = 0;
- RINOK(ILookInStream_Seek(inStream, &pos, SZ_SEEK_END));
- if ((UInt64)pos < startArcPos + nextHeaderOffset ||
- (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset ||
- (UInt64)pos < startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize)
- return SZ_ERROR_INPUT_EOF;
- }
-
- RINOK(LookInStream_SeekTo(inStream, startArcPos + k7zStartHeaderSize + nextHeaderOffset));
-
- if (!Buf_Create(&buf, nextHeaderSizeT, allocTemp))
- return SZ_ERROR_MEM;
-
- res = LookInStream_Read(inStream, buf.data, nextHeaderSizeT);
-
- if (res == SZ_OK)
- {
- res = SZ_ERROR_ARCHIVE;
- if (CrcCalc(buf.data, nextHeaderSizeT) == nextHeaderCRC)
- {
- CSzData sd;
- UInt64 type;
- sd.Data = buf.data;
- sd.Size = buf.size;
-
- res = ReadID(&sd, &type);
-
- if (res == SZ_OK && type == k7zIdEncodedHeader)
- {
- CSzAr tempAr;
- CBuf tempBuf;
- Buf_Init(&tempBuf);
-
- SzAr_Init(&tempAr);
- res = SzReadAndDecodePackedStreams(inStream, &sd, &tempBuf, 1, p->startPosAfterHeader, &tempAr, allocTemp);
- SzAr_Free(&tempAr, allocTemp);
-
- if (res != SZ_OK)
- {
- Buf_Free(&tempBuf, allocTemp);
- }
- else
- {
- Buf_Free(&buf, allocTemp);
- buf.data = tempBuf.data;
- buf.size = tempBuf.size;
- sd.Data = buf.data;
- sd.Size = buf.size;
- res = ReadID(&sd, &type);
- }
- }
-
- if (res == SZ_OK)
- {
- if (type == k7zIdHeader)
- {
- /*
- CSzData sd2;
- unsigned ttt;
- for (ttt = 0; ttt < 40000; ttt++)
- {
- SzArEx_Free(p, allocMain);
- sd2 = sd;
- res = SzReadHeader(p, &sd2, inStream, allocMain, allocTemp);
- if (res != SZ_OK)
- break;
- }
- */
- res = SzReadHeader(p, &sd, inStream, allocMain, allocTemp);
- }
- else
- res = SZ_ERROR_UNSUPPORTED;
- }
- }
- }
-
- Buf_Free(&buf, allocTemp);
- return res;
-}
-
-
-SRes SzArEx_Open(CSzArEx *p, ILookInStream *inStream,
- ISzAllocPtr allocMain, ISzAllocPtr allocTemp)
-{
- SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp);
- if (res != SZ_OK)
- SzArEx_Free(p, allocMain);
- return res;
-}
-
-
-SRes SzArEx_Extract(
- const CSzArEx *p,
- ILookInStream *inStream,
- UInt32 fileIndex,
- UInt32 *blockIndex,
- Byte **tempBuf,
- size_t *outBufferSize,
- size_t *offset,
- size_t *outSizeProcessed,
- ISzAllocPtr allocMain,
- ISzAllocPtr allocTemp)
-{
- UInt32 folderIndex = p->FileToFolder[fileIndex];
- SRes res = SZ_OK;
-
- *offset = 0;
- *outSizeProcessed = 0;
-
- if (folderIndex == (UInt32)-1)
- {
- ISzAlloc_Free(allocMain, *tempBuf);
- *blockIndex = folderIndex;
- *tempBuf = NULL;
- *outBufferSize = 0;
- return SZ_OK;
- }
-
- if (*tempBuf == NULL || *blockIndex != folderIndex)
- {
- UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
- /*
- UInt64 unpackSizeSpec =
- p->UnpackPositions[p->FolderToFile[(size_t)folderIndex + 1]] -
- p->UnpackPositions[p->FolderToFile[folderIndex]];
- */
- size_t unpackSize = (size_t)unpackSizeSpec;
-
- if (unpackSize != unpackSizeSpec)
- return SZ_ERROR_MEM;
- *blockIndex = folderIndex;
- ISzAlloc_Free(allocMain, *tempBuf);
- *tempBuf = NULL;
-
- if (res == SZ_OK)
- {
- *outBufferSize = unpackSize;
- if (unpackSize != 0)
- {
- *tempBuf = (Byte *)ISzAlloc_Alloc(allocMain, unpackSize);
- if (*tempBuf == NULL)
- res = SZ_ERROR_MEM;
- }
-
- if (res == SZ_OK)
- {
- res = SzAr_DecodeFolder(&p->db, folderIndex,
- inStream, p->dataPos, *tempBuf, unpackSize, allocTemp);
- }
- }
- }
-
- if (res == SZ_OK)
- {
- UInt64 unpackPos = p->UnpackPositions[fileIndex];
- *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderToFile[folderIndex]]);
- *outSizeProcessed = (size_t)(p->UnpackPositions[(size_t)fileIndex + 1] - unpackPos);
- if (*offset + *outSizeProcessed > *outBufferSize)
- return SZ_ERROR_FAIL;
- if (SzBitWithVals_Check(&p->CRCs, fileIndex))
- if (CrcCalc(*tempBuf + *offset, *outSizeProcessed) != p->CRCs.Vals[fileIndex])
- res = SZ_ERROR_CRC;
- }
-
- return res;
-}
-
-
-size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest)
-{
- size_t offs = p->FileNameOffsets[fileIndex];
- size_t len = p->FileNameOffsets[fileIndex + 1] - offs;
- if (dest != 0)
- {
- size_t i;
- const Byte *src = p->FileNames + offs * 2;
- for (i = 0; i < len; i++)
- dest[i] = GetUi16(src + i * 2);
- }
- return len;
-}
-
-/*
-size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex)
-{
- size_t len;
- if (!p->FileNameOffsets)
- return 1;
- len = 0;
- for (;;)
- {
- UInt32 parent = (UInt32)(Int32)-1;
- len += p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];
- if SzBitWithVals_Check(&p->Parents, fileIndex)
- parent = p->Parents.Vals[fileIndex];
- if (parent == (UInt32)(Int32)-1)
- return len;
- fileIndex = parent;
- }
-}
-
-UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest)
-{
- BoolInt needSlash;
- if (!p->FileNameOffsets)
- {
- *(--dest) = 0;
- return dest;
- }
- needSlash = False;
- for (;;)
- {
- UInt32 parent = (UInt32)(Int32)-1;
- size_t curLen = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];
- SzArEx_GetFileNameUtf16(p, fileIndex, dest - curLen);
- if (needSlash)
- *(dest - 1) = '/';
- needSlash = True;
- dest -= curLen;
-
- if SzBitWithVals_Check(&p->Parents, fileIndex)
- parent = p->Parents.Vals[fileIndex];
- if (parent == (UInt32)(Int32)-1)
- return dest;
- fileIndex = parent;
- }
-}
-*/
+/* 7zArcIn.c -- 7z Input functions
+2023-05-11 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#include "7z.h"
+#include "7zBuf.h"
+#include "7zCrc.h"
+#include "CpuArch.h"
+
+#define MY_ALLOC(T, p, size, alloc) \
+ { if ((p = (T *)ISzAlloc_Alloc(alloc, (size) * sizeof(T))) == NULL) return SZ_ERROR_MEM; }
+
+#define MY_ALLOC_ZE(T, p, size, alloc) \
+ { if ((size) == 0) p = NULL; else MY_ALLOC(T, p, size, alloc) }
+
+#define MY_ALLOC_AND_CPY(to, size, from, alloc) \
+ { MY_ALLOC(Byte, to, size, alloc); memcpy(to, from, size); }
+
+#define MY_ALLOC_ZE_AND_CPY(to, size, from, alloc) \
+ { if ((size) == 0) to = NULL; else { MY_ALLOC_AND_CPY(to, size, from, alloc) } }
+
+#define k7zMajorVersion 0
+
+enum EIdEnum
+{
+ k7zIdEnd,
+ k7zIdHeader,
+ k7zIdArchiveProperties,
+ k7zIdAdditionalStreamsInfo,
+ k7zIdMainStreamsInfo,
+ k7zIdFilesInfo,
+ k7zIdPackInfo,
+ k7zIdUnpackInfo,
+ k7zIdSubStreamsInfo,
+ k7zIdSize,
+ k7zIdCRC,
+ k7zIdFolder,
+ k7zIdCodersUnpackSize,
+ k7zIdNumUnpackStream,
+ k7zIdEmptyStream,
+ k7zIdEmptyFile,
+ k7zIdAnti,
+ k7zIdName,
+ k7zIdCTime,
+ k7zIdATime,
+ k7zIdMTime,
+ k7zIdWinAttrib,
+ k7zIdComment,
+ k7zIdEncodedHeader,
+ k7zIdStartPos,
+ k7zIdDummy
+ // k7zNtSecure,
+ // k7zParent,
+ // k7zIsReal
+};
+
+const Byte k7zSignature[k7zSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
+
+#define SzBitUi32s_INIT(p) { (p)->Defs = NULL; (p)->Vals = NULL; }
+
+static SRes SzBitUi32s_Alloc(CSzBitUi32s *p, size_t num, ISzAllocPtr alloc)
+{
+ if (num == 0)
+ {
+ p->Defs = NULL;
+ p->Vals = NULL;
+ }
+ else
+ {
+ MY_ALLOC(Byte, p->Defs, (num + 7) >> 3, alloc)
+ MY_ALLOC(UInt32, p->Vals, num, alloc)
+ }
+ return SZ_OK;
+}
+
+static void SzBitUi32s_Free(CSzBitUi32s *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->Defs); p->Defs = NULL;
+ ISzAlloc_Free(alloc, p->Vals); p->Vals = NULL;
+}
+
+#define SzBitUi64s_INIT(p) { (p)->Defs = NULL; (p)->Vals = NULL; }
+
+static void SzBitUi64s_Free(CSzBitUi64s *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->Defs); p->Defs = NULL;
+ ISzAlloc_Free(alloc, p->Vals); p->Vals = NULL;
+}
+
+
+static void SzAr_Init(CSzAr *p)
+{
+ p->NumPackStreams = 0;
+ p->NumFolders = 0;
+
+ p->PackPositions = NULL;
+ SzBitUi32s_INIT(&p->FolderCRCs)
+
+ p->FoCodersOffsets = NULL;
+ p->FoStartPackStreamIndex = NULL;
+ p->FoToCoderUnpackSizes = NULL;
+ p->FoToMainUnpackSizeIndex = NULL;
+ p->CoderUnpackSizes = NULL;
+
+ p->CodersData = NULL;
+
+ p->RangeLimit = 0;
+}
+
+static void SzAr_Free(CSzAr *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->PackPositions);
+ SzBitUi32s_Free(&p->FolderCRCs, alloc);
+
+ ISzAlloc_Free(alloc, p->FoCodersOffsets);
+ ISzAlloc_Free(alloc, p->FoStartPackStreamIndex);
+ ISzAlloc_Free(alloc, p->FoToCoderUnpackSizes);
+ ISzAlloc_Free(alloc, p->FoToMainUnpackSizeIndex);
+ ISzAlloc_Free(alloc, p->CoderUnpackSizes);
+
+ ISzAlloc_Free(alloc, p->CodersData);
+
+ SzAr_Init(p);
+}
+
+
+void SzArEx_Init(CSzArEx *p)
+{
+ SzAr_Init(&p->db);
+
+ p->NumFiles = 0;
+ p->dataPos = 0;
+
+ p->UnpackPositions = NULL;
+ p->IsDirs = NULL;
+
+ p->FolderToFile = NULL;
+ p->FileToFolder = NULL;
+
+ p->FileNameOffsets = NULL;
+ p->FileNames = NULL;
+
+ SzBitUi32s_INIT(&p->CRCs)
+ SzBitUi32s_INIT(&p->Attribs)
+ // SzBitUi32s_INIT(&p->Parents)
+ SzBitUi64s_INIT(&p->MTime)
+ SzBitUi64s_INIT(&p->CTime)
+}
+
+void SzArEx_Free(CSzArEx *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->UnpackPositions);
+ ISzAlloc_Free(alloc, p->IsDirs);
+
+ ISzAlloc_Free(alloc, p->FolderToFile);
+ ISzAlloc_Free(alloc, p->FileToFolder);
+
+ ISzAlloc_Free(alloc, p->FileNameOffsets);
+ ISzAlloc_Free(alloc, p->FileNames);
+
+ SzBitUi32s_Free(&p->CRCs, alloc);
+ SzBitUi32s_Free(&p->Attribs, alloc);
+ // SzBitUi32s_Free(&p->Parents, alloc);
+ SzBitUi64s_Free(&p->MTime, alloc);
+ SzBitUi64s_Free(&p->CTime, alloc);
+
+ SzAr_Free(&p->db, alloc);
+ SzArEx_Init(p);
+}
+
+
+static int TestSignatureCandidate(const Byte *testBytes)
+{
+ unsigned i;
+ for (i = 0; i < k7zSignatureSize; i++)
+ if (testBytes[i] != k7zSignature[i])
+ return 0;
+ return 1;
+}
+
+#define SzData_CLEAR(p) { (p)->Data = NULL; (p)->Size = 0; }
+
+#define SZ_READ_BYTE_SD_NOCHECK(_sd_, dest) \
+ (_sd_)->Size--; dest = *(_sd_)->Data++;
+
+#define SZ_READ_BYTE_SD(_sd_, dest) \
+ if ((_sd_)->Size == 0) return SZ_ERROR_ARCHIVE; \
+ SZ_READ_BYTE_SD_NOCHECK(_sd_, dest)
+
+#define SZ_READ_BYTE(dest) SZ_READ_BYTE_SD(sd, dest)
+
+#define SZ_READ_BYTE_2(dest) \
+ if (sd.Size == 0) return SZ_ERROR_ARCHIVE; \
+ sd.Size--; dest = *sd.Data++;
+
+#define SKIP_DATA(sd, size) { sd->Size -= (size_t)(size); sd->Data += (size_t)(size); }
+#define SKIP_DATA2(sd, size) { sd.Size -= (size_t)(size); sd.Data += (size_t)(size); }
+
+#define SZ_READ_32(dest) if (sd.Size < 4) return SZ_ERROR_ARCHIVE; \
+ dest = GetUi32(sd.Data); SKIP_DATA2(sd, 4);
+
+static Z7_NO_INLINE SRes ReadNumber(CSzData *sd, UInt64 *value)
+{
+ Byte firstByte, mask;
+ unsigned i;
+ UInt32 v;
+
+ SZ_READ_BYTE(firstByte)
+ if ((firstByte & 0x80) == 0)
+ {
+ *value = firstByte;
+ return SZ_OK;
+ }
+ SZ_READ_BYTE(v)
+ if ((firstByte & 0x40) == 0)
+ {
+ *value = (((UInt32)firstByte & 0x3F) << 8) | v;
+ return SZ_OK;
+ }
+ SZ_READ_BYTE(mask)
+ *value = v | ((UInt32)mask << 8);
+ mask = 0x20;
+ for (i = 2; i < 8; i++)
+ {
+ Byte b;
+ if ((firstByte & mask) == 0)
+ {
+ const UInt64 highPart = (unsigned)firstByte & (unsigned)(mask - 1);
+ *value |= (highPart << (8 * i));
+ return SZ_OK;
+ }
+ SZ_READ_BYTE(b)
+ *value |= ((UInt64)b << (8 * i));
+ mask >>= 1;
+ }
+ return SZ_OK;
+}
+
+
+static Z7_NO_INLINE SRes SzReadNumber32(CSzData *sd, UInt32 *value)
+{
+ Byte firstByte;
+ UInt64 value64;
+ if (sd->Size == 0)
+ return SZ_ERROR_ARCHIVE;
+ firstByte = *sd->Data;
+ if ((firstByte & 0x80) == 0)
+ {
+ *value = firstByte;
+ sd->Data++;
+ sd->Size--;
+ return SZ_OK;
+ }
+ RINOK(ReadNumber(sd, &value64))
+ if (value64 >= (UInt32)0x80000000 - 1)
+ return SZ_ERROR_UNSUPPORTED;
+ if (value64 >= ((UInt64)(1) << ((sizeof(size_t) - 1) * 8 + 4)))
+ return SZ_ERROR_UNSUPPORTED;
+ *value = (UInt32)value64;
+ return SZ_OK;
+}
+
+#define ReadID(sd, value) ReadNumber(sd, value)
+
+static SRes SkipData(CSzData *sd)
+{
+ UInt64 size;
+ RINOK(ReadNumber(sd, &size))
+ if (size > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ SKIP_DATA(sd, size)
+ return SZ_OK;
+}
+
+static SRes WaitId(CSzData *sd, UInt32 id)
+{
+ for (;;)
+ {
+ UInt64 type;
+ RINOK(ReadID(sd, &type))
+ if (type == id)
+ return SZ_OK;
+ if (type == k7zIdEnd)
+ return SZ_ERROR_ARCHIVE;
+ RINOK(SkipData(sd))
+ }
+}
+
+static SRes RememberBitVector(CSzData *sd, UInt32 numItems, const Byte **v)
+{
+ const UInt32 numBytes = (numItems + 7) >> 3;
+ if (numBytes > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ *v = sd->Data;
+ SKIP_DATA(sd, numBytes)
+ return SZ_OK;
+}
+
+static UInt32 CountDefinedBits(const Byte *bits, UInt32 numItems)
+{
+ Byte b = 0;
+ unsigned m = 0;
+ UInt32 sum = 0;
+ for (; numItems != 0; numItems--)
+ {
+ if (m == 0)
+ {
+ b = *bits++;
+ m = 8;
+ }
+ m--;
+ sum += ((b >> m) & 1);
+ }
+ return sum;
+}
+
+static Z7_NO_INLINE SRes ReadBitVector(CSzData *sd, UInt32 numItems, Byte **v, ISzAllocPtr alloc)
+{
+ Byte allAreDefined;
+ Byte *v2;
+ const UInt32 numBytes = (numItems + 7) >> 3;
+ *v = NULL;
+ SZ_READ_BYTE(allAreDefined)
+ if (numBytes == 0)
+ return SZ_OK;
+ if (allAreDefined == 0)
+ {
+ if (numBytes > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ MY_ALLOC_AND_CPY(*v, numBytes, sd->Data, alloc)
+ SKIP_DATA(sd, numBytes)
+ return SZ_OK;
+ }
+ MY_ALLOC(Byte, *v, numBytes, alloc)
+ v2 = *v;
+ memset(v2, 0xFF, (size_t)numBytes);
+ {
+ const unsigned numBits = (unsigned)numItems & 7;
+ if (numBits != 0)
+ v2[(size_t)numBytes - 1] = (Byte)((((UInt32)1 << numBits) - 1) << (8 - numBits));
+ }
+ return SZ_OK;
+}
+
+static Z7_NO_INLINE SRes ReadUi32s(CSzData *sd2, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc)
+{
+ UInt32 i;
+ CSzData sd;
+ UInt32 *vals;
+ const Byte *defs;
+ MY_ALLOC_ZE(UInt32, crcs->Vals, numItems, alloc)
+ sd = *sd2;
+ defs = crcs->Defs;
+ vals = crcs->Vals;
+ for (i = 0; i < numItems; i++)
+ if (SzBitArray_Check(defs, i))
+ {
+ SZ_READ_32(vals[i])
+ }
+ else
+ vals[i] = 0;
+ *sd2 = sd;
+ return SZ_OK;
+}
+
+static SRes ReadBitUi32s(CSzData *sd, UInt32 numItems, CSzBitUi32s *crcs, ISzAllocPtr alloc)
+{
+ SzBitUi32s_Free(crcs, alloc);
+ RINOK(ReadBitVector(sd, numItems, &crcs->Defs, alloc))
+ return ReadUi32s(sd, numItems, crcs, alloc);
+}
+
+static SRes SkipBitUi32s(CSzData *sd, UInt32 numItems)
+{
+ Byte allAreDefined;
+ UInt32 numDefined = numItems;
+ SZ_READ_BYTE(allAreDefined)
+ if (!allAreDefined)
+ {
+ const size_t numBytes = (numItems + 7) >> 3;
+ if (numBytes > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ numDefined = CountDefinedBits(sd->Data, numItems);
+ SKIP_DATA(sd, numBytes)
+ }
+ if (numDefined > (sd->Size >> 2))
+ return SZ_ERROR_ARCHIVE;
+ SKIP_DATA(sd, (size_t)numDefined * 4)
+ return SZ_OK;
+}
+
+static SRes ReadPackInfo(CSzAr *p, CSzData *sd, ISzAllocPtr alloc)
+{
+ RINOK(SzReadNumber32(sd, &p->NumPackStreams))
+
+ RINOK(WaitId(sd, k7zIdSize))
+ MY_ALLOC(UInt64, p->PackPositions, (size_t)p->NumPackStreams + 1, alloc)
+ {
+ UInt64 sum = 0;
+ UInt32 i;
+ const UInt32 numPackStreams = p->NumPackStreams;
+ for (i = 0; i < numPackStreams; i++)
+ {
+ UInt64 packSize;
+ p->PackPositions[i] = sum;
+ RINOK(ReadNumber(sd, &packSize))
+ sum += packSize;
+ if (sum < packSize)
+ return SZ_ERROR_ARCHIVE;
+ }
+ p->PackPositions[i] = sum;
+ }
+
+ for (;;)
+ {
+ UInt64 type;
+ RINOK(ReadID(sd, &type))
+ if (type == k7zIdEnd)
+ return SZ_OK;
+ if (type == k7zIdCRC)
+ {
+ /* CRC of packed streams is unused now */
+ RINOK(SkipBitUi32s(sd, p->NumPackStreams))
+ continue;
+ }
+ RINOK(SkipData(sd))
+ }
+}
+
+/*
+static SRes SzReadSwitch(CSzData *sd)
+{
+ Byte external;
+ RINOK(SzReadByte(sd, &external));
+ return (external == 0) ? SZ_OK: SZ_ERROR_UNSUPPORTED;
+}
+*/
+
+#define k_NumCodersStreams_in_Folder_MAX (SZ_NUM_BONDS_IN_FOLDER_MAX + SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX)
+
+SRes SzGetNextFolderItem(CSzFolder *f, CSzData *sd)
+{
+ UInt32 numCoders, i;
+ UInt32 numInStreams = 0;
+ const Byte *dataStart = sd->Data;
+
+ f->NumCoders = 0;
+ f->NumBonds = 0;
+ f->NumPackStreams = 0;
+ f->UnpackStream = 0;
+
+ RINOK(SzReadNumber32(sd, &numCoders))
+ if (numCoders == 0 || numCoders > SZ_NUM_CODERS_IN_FOLDER_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+
+ for (i = 0; i < numCoders; i++)
+ {
+ Byte mainByte;
+ CSzCoderInfo *coder = f->Coders + i;
+ unsigned idSize, j;
+ UInt64 id;
+
+ SZ_READ_BYTE(mainByte)
+ if ((mainByte & 0xC0) != 0)
+ return SZ_ERROR_UNSUPPORTED;
+
+ idSize = (unsigned)(mainByte & 0xF);
+ if (idSize > sizeof(id))
+ return SZ_ERROR_UNSUPPORTED;
+ if (idSize > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ id = 0;
+ for (j = 0; j < idSize; j++)
+ {
+ id = ((id << 8) | *sd->Data);
+ sd->Data++;
+ sd->Size--;
+ }
+ if (id > (UInt32)0xFFFFFFFF)
+ return SZ_ERROR_UNSUPPORTED;
+ coder->MethodID = (UInt32)id;
+
+ coder->NumStreams = 1;
+ coder->PropsOffset = 0;
+ coder->PropsSize = 0;
+
+ if ((mainByte & 0x10) != 0)
+ {
+ UInt32 numStreams;
+
+ RINOK(SzReadNumber32(sd, &numStreams))
+ if (numStreams > k_NumCodersStreams_in_Folder_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+ coder->NumStreams = (Byte)numStreams;
+
+ RINOK(SzReadNumber32(sd, &numStreams))
+ if (numStreams != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ }
+
+ numInStreams += coder->NumStreams;
+
+ if (numInStreams > k_NumCodersStreams_in_Folder_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+
+ if ((mainByte & 0x20) != 0)
+ {
+ UInt32 propsSize = 0;
+ RINOK(SzReadNumber32(sd, &propsSize))
+ if (propsSize > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+ if (propsSize >= 0x80)
+ return SZ_ERROR_UNSUPPORTED;
+ coder->PropsOffset = (size_t)(sd->Data - dataStart);
+ coder->PropsSize = (Byte)propsSize;
+ sd->Data += (size_t)propsSize;
+ sd->Size -= (size_t)propsSize;
+ }
+ }
+
+ /*
+ if (numInStreams == 1 && numCoders == 1)
+ {
+ f->NumPackStreams = 1;
+ f->PackStreams[0] = 0;
+ }
+ else
+ */
+ {
+ Byte streamUsed[k_NumCodersStreams_in_Folder_MAX];
+ UInt32 numBonds, numPackStreams;
+
+ numBonds = numCoders - 1;
+ if (numInStreams < numBonds)
+ return SZ_ERROR_ARCHIVE;
+ if (numBonds > SZ_NUM_BONDS_IN_FOLDER_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+ f->NumBonds = numBonds;
+
+ numPackStreams = numInStreams - numBonds;
+ if (numPackStreams > SZ_NUM_PACK_STREAMS_IN_FOLDER_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+ f->NumPackStreams = numPackStreams;
+
+ for (i = 0; i < numInStreams; i++)
+ streamUsed[i] = False;
+
+ if (numBonds != 0)
+ {
+ Byte coderUsed[SZ_NUM_CODERS_IN_FOLDER_MAX];
+
+ for (i = 0; i < numCoders; i++)
+ coderUsed[i] = False;
+
+ for (i = 0; i < numBonds; i++)
+ {
+ CSzBond *bp = f->Bonds + i;
+
+ RINOK(SzReadNumber32(sd, &bp->InIndex))
+ if (bp->InIndex >= numInStreams || streamUsed[bp->InIndex])
+ return SZ_ERROR_ARCHIVE;
+ streamUsed[bp->InIndex] = True;
+
+ RINOK(SzReadNumber32(sd, &bp->OutIndex))
+ if (bp->OutIndex >= numCoders || coderUsed[bp->OutIndex])
+ return SZ_ERROR_ARCHIVE;
+ coderUsed[bp->OutIndex] = True;
+ }
+
+ for (i = 0; i < numCoders; i++)
+ if (!coderUsed[i])
+ {
+ f->UnpackStream = i;
+ break;
+ }
+
+ if (i == numCoders)
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ if (numPackStreams == 1)
+ {
+ for (i = 0; i < numInStreams; i++)
+ if (!streamUsed[i])
+ break;
+ if (i == numInStreams)
+ return SZ_ERROR_ARCHIVE;
+ f->PackStreams[0] = i;
+ }
+ else
+ for (i = 0; i < numPackStreams; i++)
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(sd, &index))
+ if (index >= numInStreams || streamUsed[index])
+ return SZ_ERROR_ARCHIVE;
+ streamUsed[index] = True;
+ f->PackStreams[i] = index;
+ }
+ }
+
+ f->NumCoders = numCoders;
+
+ return SZ_OK;
+}
+
+
+static Z7_NO_INLINE SRes SkipNumbers(CSzData *sd2, UInt32 num)
+{
+ CSzData sd;
+ sd = *sd2;
+ for (; num != 0; num--)
+ {
+ Byte firstByte, mask;
+ unsigned i;
+ SZ_READ_BYTE_2(firstByte)
+ if ((firstByte & 0x80) == 0)
+ continue;
+ if ((firstByte & 0x40) == 0)
+ {
+ if (sd.Size == 0)
+ return SZ_ERROR_ARCHIVE;
+ sd.Size--;
+ sd.Data++;
+ continue;
+ }
+ mask = 0x20;
+ for (i = 2; i < 8 && (firstByte & mask) != 0; i++)
+ mask >>= 1;
+ if (i > sd.Size)
+ return SZ_ERROR_ARCHIVE;
+ SKIP_DATA2(sd, i)
+ }
+ *sd2 = sd;
+ return SZ_OK;
+}
+
+
+#define k_Scan_NumCoders_MAX 64
+#define k_Scan_NumCodersStreams_in_Folder_MAX 64
+
+
+static SRes ReadUnpackInfo(CSzAr *p,
+ CSzData *sd2,
+ UInt32 numFoldersMax,
+ const CBuf *tempBufs, UInt32 numTempBufs,
+ ISzAllocPtr alloc)
+{
+ CSzData sd;
+
+ UInt32 fo, numFolders, numCodersOutStreams, packStreamIndex;
+ const Byte *startBufPtr;
+ Byte external;
+
+ RINOK(WaitId(sd2, k7zIdFolder))
+
+ RINOK(SzReadNumber32(sd2, &numFolders))
+ if (numFolders > numFoldersMax)
+ return SZ_ERROR_UNSUPPORTED;
+ p->NumFolders = numFolders;
+
+ SZ_READ_BYTE_SD(sd2, external)
+ if (external == 0)
+ sd = *sd2;
+ else
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(sd2, &index))
+ if (index >= numTempBufs)
+ return SZ_ERROR_ARCHIVE;
+ sd.Data = tempBufs[index].data;
+ sd.Size = tempBufs[index].size;
+ }
+
+ MY_ALLOC(size_t, p->FoCodersOffsets, (size_t)numFolders + 1, alloc)
+ MY_ALLOC(UInt32, p->FoStartPackStreamIndex, (size_t)numFolders + 1, alloc)
+ MY_ALLOC(UInt32, p->FoToCoderUnpackSizes, (size_t)numFolders + 1, alloc)
+ MY_ALLOC_ZE(Byte, p->FoToMainUnpackSizeIndex, (size_t)numFolders, alloc)
+
+ startBufPtr = sd.Data;
+
+ packStreamIndex = 0;
+ numCodersOutStreams = 0;
+
+ for (fo = 0; fo < numFolders; fo++)
+ {
+ UInt32 numCoders, ci, numInStreams = 0;
+
+ p->FoCodersOffsets[fo] = (size_t)(sd.Data - startBufPtr);
+
+ RINOK(SzReadNumber32(&sd, &numCoders))
+ if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+
+ for (ci = 0; ci < numCoders; ci++)
+ {
+ Byte mainByte;
+ unsigned idSize;
+ UInt32 coderInStreams;
+
+ SZ_READ_BYTE_2(mainByte)
+ if ((mainByte & 0xC0) != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ idSize = (mainByte & 0xF);
+ if (idSize > 8)
+ return SZ_ERROR_UNSUPPORTED;
+ if (idSize > sd.Size)
+ return SZ_ERROR_ARCHIVE;
+ SKIP_DATA2(sd, idSize)
+
+ coderInStreams = 1;
+
+ if ((mainByte & 0x10) != 0)
+ {
+ UInt32 coderOutStreams;
+ RINOK(SzReadNumber32(&sd, &coderInStreams))
+ RINOK(SzReadNumber32(&sd, &coderOutStreams))
+ if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX || coderOutStreams != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ }
+
+ numInStreams += coderInStreams;
+
+ if ((mainByte & 0x20) != 0)
+ {
+ UInt32 propsSize;
+ RINOK(SzReadNumber32(&sd, &propsSize))
+ if (propsSize > sd.Size)
+ return SZ_ERROR_ARCHIVE;
+ SKIP_DATA2(sd, propsSize)
+ }
+ }
+
+ {
+ UInt32 indexOfMainStream = 0;
+ UInt32 numPackStreams = 1;
+
+ if (numCoders != 1 || numInStreams != 1)
+ {
+ Byte streamUsed[k_Scan_NumCodersStreams_in_Folder_MAX];
+ Byte coderUsed[k_Scan_NumCoders_MAX];
+
+ UInt32 i;
+ const UInt32 numBonds = numCoders - 1;
+ if (numInStreams < numBonds)
+ return SZ_ERROR_ARCHIVE;
+
+ if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX)
+ return SZ_ERROR_UNSUPPORTED;
+
+ for (i = 0; i < numInStreams; i++)
+ streamUsed[i] = False;
+ for (i = 0; i < numCoders; i++)
+ coderUsed[i] = False;
+
+ for (i = 0; i < numBonds; i++)
+ {
+ UInt32 index;
+
+ RINOK(SzReadNumber32(&sd, &index))
+ if (index >= numInStreams || streamUsed[index])
+ return SZ_ERROR_ARCHIVE;
+ streamUsed[index] = True;
+
+ RINOK(SzReadNumber32(&sd, &index))
+ if (index >= numCoders || coderUsed[index])
+ return SZ_ERROR_ARCHIVE;
+ coderUsed[index] = True;
+ }
+
+ numPackStreams = numInStreams - numBonds;
+
+ if (numPackStreams != 1)
+ for (i = 0; i < numPackStreams; i++)
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(&sd, &index))
+ if (index >= numInStreams || streamUsed[index])
+ return SZ_ERROR_ARCHIVE;
+ streamUsed[index] = True;
+ }
+
+ for (i = 0; i < numCoders; i++)
+ if (!coderUsed[i])
+ {
+ indexOfMainStream = i;
+ break;
+ }
+
+ if (i == numCoders)
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ p->FoStartPackStreamIndex[fo] = packStreamIndex;
+ p->FoToCoderUnpackSizes[fo] = numCodersOutStreams;
+ p->FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream;
+ numCodersOutStreams += numCoders;
+ if (numCodersOutStreams < numCoders)
+ return SZ_ERROR_UNSUPPORTED;
+ if (numPackStreams > p->NumPackStreams - packStreamIndex)
+ return SZ_ERROR_ARCHIVE;
+ packStreamIndex += numPackStreams;
+ }
+ }
+
+ p->FoToCoderUnpackSizes[fo] = numCodersOutStreams;
+
+ {
+ const size_t dataSize = (size_t)(sd.Data - startBufPtr);
+ p->FoStartPackStreamIndex[fo] = packStreamIndex;
+ p->FoCodersOffsets[fo] = dataSize;
+ MY_ALLOC_ZE_AND_CPY(p->CodersData, dataSize, startBufPtr, alloc)
+ }
+
+ if (external != 0)
+ {
+ if (sd.Size != 0)
+ return SZ_ERROR_ARCHIVE;
+ sd = *sd2;
+ }
+
+ RINOK(WaitId(&sd, k7zIdCodersUnpackSize))
+
+ MY_ALLOC_ZE(UInt64, p->CoderUnpackSizes, (size_t)numCodersOutStreams, alloc)
+ {
+ UInt32 i;
+ for (i = 0; i < numCodersOutStreams; i++)
+ {
+ RINOK(ReadNumber(&sd, p->CoderUnpackSizes + i))
+ }
+ }
+
+ for (;;)
+ {
+ UInt64 type;
+ RINOK(ReadID(&sd, &type))
+ if (type == k7zIdEnd)
+ {
+ *sd2 = sd;
+ return SZ_OK;
+ }
+ if (type == k7zIdCRC)
+ {
+ RINOK(ReadBitUi32s(&sd, numFolders, &p->FolderCRCs, alloc))
+ continue;
+ }
+ RINOK(SkipData(&sd))
+ }
+}
+
+
+UInt64 SzAr_GetFolderUnpackSize(const CSzAr *p, UInt32 folderIndex)
+{
+ return p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex] + p->FoToMainUnpackSizeIndex[folderIndex]];
+}
+
+
+typedef struct
+{
+ UInt32 NumTotalSubStreams;
+ UInt32 NumSubDigests;
+ CSzData sdNumSubStreams;
+ CSzData sdSizes;
+ CSzData sdCRCs;
+} CSubStreamInfo;
+
+
+static SRes ReadSubStreamsInfo(CSzAr *p, CSzData *sd, CSubStreamInfo *ssi)
+{
+ UInt64 type = 0;
+ UInt32 numSubDigests = 0;
+ const UInt32 numFolders = p->NumFolders;
+ UInt32 numUnpackStreams = numFolders;
+ UInt32 numUnpackSizesInData = 0;
+
+ for (;;)
+ {
+ RINOK(ReadID(sd, &type))
+ if (type == k7zIdNumUnpackStream)
+ {
+ UInt32 i;
+ ssi->sdNumSubStreams.Data = sd->Data;
+ numUnpackStreams = 0;
+ numSubDigests = 0;
+ for (i = 0; i < numFolders; i++)
+ {
+ UInt32 numStreams;
+ RINOK(SzReadNumber32(sd, &numStreams))
+ if (numUnpackStreams > numUnpackStreams + numStreams)
+ return SZ_ERROR_UNSUPPORTED;
+ numUnpackStreams += numStreams;
+ if (numStreams != 0)
+ numUnpackSizesInData += (numStreams - 1);
+ if (numStreams != 1 || !SzBitWithVals_Check(&p->FolderCRCs, i))
+ numSubDigests += numStreams;
+ }
+ ssi->sdNumSubStreams.Size = (size_t)(sd->Data - ssi->sdNumSubStreams.Data);
+ continue;
+ }
+ if (type == k7zIdCRC || type == k7zIdSize || type == k7zIdEnd)
+ break;
+ RINOK(SkipData(sd))
+ }
+
+ if (!ssi->sdNumSubStreams.Data)
+ {
+ numSubDigests = numFolders;
+ if (p->FolderCRCs.Defs)
+ numSubDigests = numFolders - CountDefinedBits(p->FolderCRCs.Defs, numFolders);
+ }
+
+ ssi->NumTotalSubStreams = numUnpackStreams;
+ ssi->NumSubDigests = numSubDigests;
+
+ if (type == k7zIdSize)
+ {
+ ssi->sdSizes.Data = sd->Data;
+ RINOK(SkipNumbers(sd, numUnpackSizesInData))
+ ssi->sdSizes.Size = (size_t)(sd->Data - ssi->sdSizes.Data);
+ RINOK(ReadID(sd, &type))
+ }
+
+ for (;;)
+ {
+ if (type == k7zIdEnd)
+ return SZ_OK;
+ if (type == k7zIdCRC)
+ {
+ ssi->sdCRCs.Data = sd->Data;
+ RINOK(SkipBitUi32s(sd, numSubDigests))
+ ssi->sdCRCs.Size = (size_t)(sd->Data - ssi->sdCRCs.Data);
+ }
+ else
+ {
+ RINOK(SkipData(sd))
+ }
+ RINOK(ReadID(sd, &type))
+ }
+}
+
+static SRes SzReadStreamsInfo(CSzAr *p,
+ CSzData *sd,
+ UInt32 numFoldersMax, const CBuf *tempBufs, UInt32 numTempBufs,
+ UInt64 *dataOffset,
+ CSubStreamInfo *ssi,
+ ISzAllocPtr alloc)
+{
+ UInt64 type;
+
+ SzData_CLEAR(&ssi->sdSizes)
+ SzData_CLEAR(&ssi->sdCRCs)
+ SzData_CLEAR(&ssi->sdNumSubStreams)
+
+ *dataOffset = 0;
+ RINOK(ReadID(sd, &type))
+ if (type == k7zIdPackInfo)
+ {
+ RINOK(ReadNumber(sd, dataOffset))
+ if (*dataOffset > p->RangeLimit)
+ return SZ_ERROR_ARCHIVE;
+ RINOK(ReadPackInfo(p, sd, alloc))
+ if (p->PackPositions[p->NumPackStreams] > p->RangeLimit - *dataOffset)
+ return SZ_ERROR_ARCHIVE;
+ RINOK(ReadID(sd, &type))
+ }
+ if (type == k7zIdUnpackInfo)
+ {
+ RINOK(ReadUnpackInfo(p, sd, numFoldersMax, tempBufs, numTempBufs, alloc))
+ RINOK(ReadID(sd, &type))
+ }
+ if (type == k7zIdSubStreamsInfo)
+ {
+ RINOK(ReadSubStreamsInfo(p, sd, ssi))
+ RINOK(ReadID(sd, &type))
+ }
+ else
+ {
+ ssi->NumTotalSubStreams = p->NumFolders;
+ // ssi->NumSubDigests = 0;
+ }
+
+ return (type == k7zIdEnd ? SZ_OK : SZ_ERROR_UNSUPPORTED);
+}
+
+static SRes SzReadAndDecodePackedStreams(
+ ILookInStreamPtr inStream,
+ CSzData *sd,
+ CBuf *tempBufs,
+ UInt32 numFoldersMax,
+ UInt64 baseOffset,
+ CSzAr *p,
+ ISzAllocPtr allocTemp)
+{
+ UInt64 dataStartPos;
+ UInt32 fo;
+ CSubStreamInfo ssi;
+
+ RINOK(SzReadStreamsInfo(p, sd, numFoldersMax, NULL, 0, &dataStartPos, &ssi, allocTemp))
+
+ dataStartPos += baseOffset;
+ if (p->NumFolders == 0)
+ return SZ_ERROR_ARCHIVE;
+
+ for (fo = 0; fo < p->NumFolders; fo++)
+ Buf_Init(tempBufs + fo);
+
+ for (fo = 0; fo < p->NumFolders; fo++)
+ {
+ CBuf *tempBuf = tempBufs + fo;
+ const UInt64 unpackSize = SzAr_GetFolderUnpackSize(p, fo);
+ if ((size_t)unpackSize != unpackSize)
+ return SZ_ERROR_MEM;
+ if (!Buf_Create(tempBuf, (size_t)unpackSize, allocTemp))
+ return SZ_ERROR_MEM;
+ }
+
+ for (fo = 0; fo < p->NumFolders; fo++)
+ {
+ const CBuf *tempBuf = tempBufs + fo;
+ RINOK(LookInStream_SeekTo(inStream, dataStartPos))
+ RINOK(SzAr_DecodeFolder(p, fo, inStream, dataStartPos, tempBuf->data, tempBuf->size, allocTemp))
+ }
+
+ return SZ_OK;
+}
+
+static SRes SzReadFileNames(const Byte *data, size_t size, UInt32 numFiles, size_t *offsets)
+{
+ size_t pos = 0;
+ *offsets++ = 0;
+ if (numFiles == 0)
+ return (size == 0) ? SZ_OK : SZ_ERROR_ARCHIVE;
+ if (size < 2)
+ return SZ_ERROR_ARCHIVE;
+ if (data[size - 2] != 0 || data[size - 1] != 0)
+ return SZ_ERROR_ARCHIVE;
+ do
+ {
+ const Byte *p;
+ if (pos == size)
+ return SZ_ERROR_ARCHIVE;
+ for (p = data + pos;
+ #ifdef _WIN32
+ *(const UInt16 *)(const void *)p != 0
+ #else
+ p[0] != 0 || p[1] != 0
+ #endif
+ ; p += 2);
+ pos = (size_t)(p - data) + 2;
+ *offsets++ = (pos >> 1);
+ }
+ while (--numFiles);
+ return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
+}
+
+static Z7_NO_INLINE SRes ReadTime(CSzBitUi64s *p, UInt32 num,
+ CSzData *sd2,
+ const CBuf *tempBufs, UInt32 numTempBufs,
+ ISzAllocPtr alloc)
+{
+ CSzData sd;
+ UInt32 i;
+ CNtfsFileTime *vals;
+ Byte *defs;
+ Byte external;
+
+ RINOK(ReadBitVector(sd2, num, &p->Defs, alloc))
+
+ SZ_READ_BYTE_SD(sd2, external)
+ if (external == 0)
+ sd = *sd2;
+ else
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(sd2, &index))
+ if (index >= numTempBufs)
+ return SZ_ERROR_ARCHIVE;
+ sd.Data = tempBufs[index].data;
+ sd.Size = tempBufs[index].size;
+ }
+
+ MY_ALLOC_ZE(CNtfsFileTime, p->Vals, num, alloc)
+ vals = p->Vals;
+ defs = p->Defs;
+ for (i = 0; i < num; i++)
+ if (SzBitArray_Check(defs, i))
+ {
+ if (sd.Size < 8)
+ return SZ_ERROR_ARCHIVE;
+ vals[i].Low = GetUi32(sd.Data);
+ vals[i].High = GetUi32(sd.Data + 4);
+ SKIP_DATA2(sd, 8)
+ }
+ else
+ vals[i].High = vals[i].Low = 0;
+
+ if (external == 0)
+ *sd2 = sd;
+
+ return SZ_OK;
+}
+
+
+#define NUM_ADDITIONAL_STREAMS_MAX 8
+
+
+static SRes SzReadHeader2(
+ CSzArEx *p, /* allocMain */
+ CSzData *sd,
+ ILookInStreamPtr inStream,
+ CBuf *tempBufs, UInt32 *numTempBufs,
+ ISzAllocPtr allocMain,
+ ISzAllocPtr allocTemp
+ )
+{
+ CSubStreamInfo ssi;
+
+{
+ UInt64 type;
+
+ SzData_CLEAR(&ssi.sdSizes)
+ SzData_CLEAR(&ssi.sdCRCs)
+ SzData_CLEAR(&ssi.sdNumSubStreams)
+
+ ssi.NumSubDigests = 0;
+ ssi.NumTotalSubStreams = 0;
+
+ RINOK(ReadID(sd, &type))
+
+ if (type == k7zIdArchiveProperties)
+ {
+ for (;;)
+ {
+ UInt64 type2;
+ RINOK(ReadID(sd, &type2))
+ if (type2 == k7zIdEnd)
+ break;
+ RINOK(SkipData(sd))
+ }
+ RINOK(ReadID(sd, &type))
+ }
+
+ if (type == k7zIdAdditionalStreamsInfo)
+ {
+ CSzAr tempAr;
+ SRes res;
+
+ SzAr_Init(&tempAr);
+ tempAr.RangeLimit = p->db.RangeLimit;
+
+ res = SzReadAndDecodePackedStreams(inStream, sd, tempBufs, NUM_ADDITIONAL_STREAMS_MAX,
+ p->startPosAfterHeader, &tempAr, allocTemp);
+ *numTempBufs = tempAr.NumFolders;
+ SzAr_Free(&tempAr, allocTemp);
+
+ if (res != SZ_OK)
+ return res;
+ RINOK(ReadID(sd, &type))
+ }
+
+ if (type == k7zIdMainStreamsInfo)
+ {
+ RINOK(SzReadStreamsInfo(&p->db, sd, (UInt32)1 << 30, tempBufs, *numTempBufs,
+ &p->dataPos, &ssi, allocMain))
+ p->dataPos += p->startPosAfterHeader;
+ RINOK(ReadID(sd, &type))
+ }
+
+ if (type == k7zIdEnd)
+ {
+ return SZ_OK;
+ }
+
+ if (type != k7zIdFilesInfo)
+ return SZ_ERROR_ARCHIVE;
+}
+
+{
+ UInt32 numFiles = 0;
+ UInt32 numEmptyStreams = 0;
+ const Byte *emptyStreams = NULL;
+ const Byte *emptyFiles = NULL;
+
+ RINOK(SzReadNumber32(sd, &numFiles))
+ p->NumFiles = numFiles;
+
+ for (;;)
+ {
+ UInt64 type;
+ UInt64 size;
+ RINOK(ReadID(sd, &type))
+ if (type == k7zIdEnd)
+ break;
+ RINOK(ReadNumber(sd, &size))
+ if (size > sd->Size)
+ return SZ_ERROR_ARCHIVE;
+
+ if (type >= ((UInt32)1 << 8))
+ {
+ SKIP_DATA(sd, size)
+ }
+ else switch ((unsigned)type)
+ {
+ case k7zIdName:
+ {
+ size_t namesSize;
+ const Byte *namesData;
+ Byte external;
+
+ SZ_READ_BYTE(external)
+ if (external == 0)
+ {
+ namesSize = (size_t)size - 1;
+ namesData = sd->Data;
+ }
+ else
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(sd, &index))
+ if (index >= *numTempBufs)
+ return SZ_ERROR_ARCHIVE;
+ namesData = (tempBufs)[index].data;
+ namesSize = (tempBufs)[index].size;
+ }
+
+ if ((namesSize & 1) != 0)
+ return SZ_ERROR_ARCHIVE;
+ MY_ALLOC(size_t, p->FileNameOffsets, numFiles + 1, allocMain)
+ MY_ALLOC_ZE_AND_CPY(p->FileNames, namesSize, namesData, allocMain)
+ RINOK(SzReadFileNames(p->FileNames, namesSize, numFiles, p->FileNameOffsets))
+ if (external == 0)
+ {
+ SKIP_DATA(sd, namesSize)
+ }
+ break;
+ }
+ case k7zIdEmptyStream:
+ {
+ RINOK(RememberBitVector(sd, numFiles, &emptyStreams))
+ numEmptyStreams = CountDefinedBits(emptyStreams, numFiles);
+ emptyFiles = NULL;
+ break;
+ }
+ case k7zIdEmptyFile:
+ {
+ RINOK(RememberBitVector(sd, numEmptyStreams, &emptyFiles))
+ break;
+ }
+ case k7zIdWinAttrib:
+ {
+ Byte external;
+ CSzData sdSwitch;
+ CSzData *sdPtr;
+ SzBitUi32s_Free(&p->Attribs, allocMain);
+ RINOK(ReadBitVector(sd, numFiles, &p->Attribs.Defs, allocMain))
+
+ SZ_READ_BYTE(external)
+ if (external == 0)
+ sdPtr = sd;
+ else
+ {
+ UInt32 index;
+ RINOK(SzReadNumber32(sd, &index))
+ if (index >= *numTempBufs)
+ return SZ_ERROR_ARCHIVE;
+ sdSwitch.Data = (tempBufs)[index].data;
+ sdSwitch.Size = (tempBufs)[index].size;
+ sdPtr = &sdSwitch;
+ }
+ RINOK(ReadUi32s(sdPtr, numFiles, &p->Attribs, allocMain))
+ break;
+ }
+ /*
+ case k7zParent:
+ {
+ SzBitUi32s_Free(&p->Parents, allocMain);
+ RINOK(ReadBitVector(sd, numFiles, &p->Parents.Defs, allocMain));
+ RINOK(SzReadSwitch(sd));
+ RINOK(ReadUi32s(sd, numFiles, &p->Parents, allocMain));
+ break;
+ }
+ */
+ case k7zIdMTime: RINOK(ReadTime(&p->MTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)) break;
+ case k7zIdCTime: RINOK(ReadTime(&p->CTime, numFiles, sd, tempBufs, *numTempBufs, allocMain)) break;
+ default:
+ {
+ SKIP_DATA(sd, size)
+ }
+ }
+ }
+
+ if (numFiles - numEmptyStreams != ssi.NumTotalSubStreams)
+ return SZ_ERROR_ARCHIVE;
+
+ for (;;)
+ {
+ UInt64 type;
+ RINOK(ReadID(sd, &type))
+ if (type == k7zIdEnd)
+ break;
+ RINOK(SkipData(sd))
+ }
+
+ {
+ UInt32 i;
+ UInt32 emptyFileIndex = 0;
+ UInt32 folderIndex = 0;
+ UInt32 remSubStreams = 0;
+ UInt32 numSubStreams = 0;
+ UInt64 unpackPos = 0;
+ const Byte *digestsDefs = NULL;
+ const Byte *digestsVals = NULL;
+ UInt32 digestIndex = 0;
+ Byte isDirMask = 0;
+ Byte crcMask = 0;
+ Byte mask = 0x80;
+
+ MY_ALLOC(UInt32, p->FolderToFile, p->db.NumFolders + 1, allocMain)
+ MY_ALLOC_ZE(UInt32, p->FileToFolder, p->NumFiles, allocMain)
+ MY_ALLOC(UInt64, p->UnpackPositions, p->NumFiles + 1, allocMain)
+ MY_ALLOC_ZE(Byte, p->IsDirs, (p->NumFiles + 7) >> 3, allocMain)
+
+ RINOK(SzBitUi32s_Alloc(&p->CRCs, p->NumFiles, allocMain))
+
+ if (ssi.sdCRCs.Size != 0)
+ {
+ Byte allDigestsDefined = 0;
+ SZ_READ_BYTE_SD_NOCHECK(&ssi.sdCRCs, allDigestsDefined)
+ if (allDigestsDefined)
+ digestsVals = ssi.sdCRCs.Data;
+ else
+ {
+ const size_t numBytes = (ssi.NumSubDigests + 7) >> 3;
+ digestsDefs = ssi.sdCRCs.Data;
+ digestsVals = digestsDefs + numBytes;
+ }
+ }
+
+ for (i = 0; i < numFiles; i++, mask >>= 1)
+ {
+ if (mask == 0)
+ {
+ const UInt32 byteIndex = (i - 1) >> 3;
+ p->IsDirs[byteIndex] = isDirMask;
+ p->CRCs.Defs[byteIndex] = crcMask;
+ isDirMask = 0;
+ crcMask = 0;
+ mask = 0x80;
+ }
+
+ p->UnpackPositions[i] = unpackPos;
+ p->CRCs.Vals[i] = 0;
+
+ if (emptyStreams && SzBitArray_Check(emptyStreams, i))
+ {
+ if (emptyFiles)
+ {
+ if (!SzBitArray_Check(emptyFiles, emptyFileIndex))
+ isDirMask |= mask;
+ emptyFileIndex++;
+ }
+ else
+ isDirMask |= mask;
+ if (remSubStreams == 0)
+ {
+ p->FileToFolder[i] = (UInt32)-1;
+ continue;
+ }
+ }
+
+ if (remSubStreams == 0)
+ {
+ for (;;)
+ {
+ if (folderIndex >= p->db.NumFolders)
+ return SZ_ERROR_ARCHIVE;
+ p->FolderToFile[folderIndex] = i;
+ numSubStreams = 1;
+ if (ssi.sdNumSubStreams.Data)
+ {
+ RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams))
+ }
+ remSubStreams = numSubStreams;
+ if (numSubStreams != 0)
+ break;
+ {
+ const UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
+ unpackPos += folderUnpackSize;
+ if (unpackPos < folderUnpackSize)
+ return SZ_ERROR_ARCHIVE;
+ }
+ folderIndex++;
+ }
+ }
+
+ p->FileToFolder[i] = folderIndex;
+
+ if (emptyStreams && SzBitArray_Check(emptyStreams, i))
+ continue;
+
+ if (--remSubStreams == 0)
+ {
+ const UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
+ const UInt64 startFolderUnpackPos = p->UnpackPositions[p->FolderToFile[folderIndex]];
+ if (folderUnpackSize < unpackPos - startFolderUnpackPos)
+ return SZ_ERROR_ARCHIVE;
+ unpackPos = startFolderUnpackPos + folderUnpackSize;
+ if (unpackPos < folderUnpackSize)
+ return SZ_ERROR_ARCHIVE;
+
+ if (numSubStreams == 1 && SzBitWithVals_Check(&p->db.FolderCRCs, folderIndex))
+ {
+ p->CRCs.Vals[i] = p->db.FolderCRCs.Vals[folderIndex];
+ crcMask |= mask;
+ }
+ folderIndex++;
+ }
+ else
+ {
+ UInt64 v;
+ RINOK(ReadNumber(&ssi.sdSizes, &v))
+ unpackPos += v;
+ if (unpackPos < v)
+ return SZ_ERROR_ARCHIVE;
+ }
+ if ((crcMask & mask) == 0 && digestsVals)
+ {
+ if (!digestsDefs || SzBitArray_Check(digestsDefs, digestIndex))
+ {
+ p->CRCs.Vals[i] = GetUi32(digestsVals);
+ digestsVals += 4;
+ crcMask |= mask;
+ }
+ digestIndex++;
+ }
+ }
+
+ if (mask != 0x80)
+ {
+ const UInt32 byteIndex = (i - 1) >> 3;
+ p->IsDirs[byteIndex] = isDirMask;
+ p->CRCs.Defs[byteIndex] = crcMask;
+ }
+
+ p->UnpackPositions[i] = unpackPos;
+
+ if (remSubStreams != 0)
+ return SZ_ERROR_ARCHIVE;
+
+ for (;;)
+ {
+ p->FolderToFile[folderIndex] = i;
+ if (folderIndex >= p->db.NumFolders)
+ break;
+ if (!ssi.sdNumSubStreams.Data)
+ return SZ_ERROR_ARCHIVE;
+ RINOK(SzReadNumber32(&ssi.sdNumSubStreams, &numSubStreams))
+ if (numSubStreams != 0)
+ return SZ_ERROR_ARCHIVE;
+ /*
+ {
+ UInt64 folderUnpackSize = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
+ unpackPos += folderUnpackSize;
+ if (unpackPos < folderUnpackSize)
+ return SZ_ERROR_ARCHIVE;
+ }
+ */
+ folderIndex++;
+ }
+
+ if (ssi.sdNumSubStreams.Data && ssi.sdNumSubStreams.Size != 0)
+ return SZ_ERROR_ARCHIVE;
+ }
+}
+ return SZ_OK;
+}
+
+
+static SRes SzReadHeader(
+ CSzArEx *p,
+ CSzData *sd,
+ ILookInStreamPtr inStream,
+ ISzAllocPtr allocMain,
+ ISzAllocPtr allocTemp)
+{
+ UInt32 i;
+ UInt32 numTempBufs = 0;
+ SRes res;
+ CBuf tempBufs[NUM_ADDITIONAL_STREAMS_MAX];
+
+ for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++)
+ Buf_Init(tempBufs + i);
+
+ res = SzReadHeader2(p, sd, inStream,
+ tempBufs, &numTempBufs,
+ allocMain, allocTemp);
+
+ for (i = 0; i < NUM_ADDITIONAL_STREAMS_MAX; i++)
+ Buf_Free(tempBufs + i, allocTemp);
+
+ RINOK(res)
+
+ if (sd->Size != 0)
+ return SZ_ERROR_FAIL;
+
+ return res;
+}
+
+static SRes SzArEx_Open2(
+ CSzArEx *p,
+ ILookInStreamPtr inStream,
+ ISzAllocPtr allocMain,
+ ISzAllocPtr allocTemp)
+{
+ Byte header[k7zStartHeaderSize];
+ Int64 startArcPos;
+ UInt64 nextHeaderOffset, nextHeaderSize;
+ size_t nextHeaderSizeT;
+ UInt32 nextHeaderCRC;
+ CBuf buf;
+ SRes res;
+
+ startArcPos = 0;
+ RINOK(ILookInStream_Seek(inStream, &startArcPos, SZ_SEEK_CUR))
+
+ RINOK(LookInStream_Read2(inStream, header, k7zStartHeaderSize, SZ_ERROR_NO_ARCHIVE))
+
+ if (!TestSignatureCandidate(header))
+ return SZ_ERROR_NO_ARCHIVE;
+ if (header[6] != k7zMajorVersion)
+ return SZ_ERROR_UNSUPPORTED;
+
+ nextHeaderOffset = GetUi64(header + 12);
+ nextHeaderSize = GetUi64(header + 20);
+ nextHeaderCRC = GetUi32(header + 28);
+
+ p->startPosAfterHeader = (UInt64)startArcPos + k7zStartHeaderSize;
+
+ if (CrcCalc(header + 12, 20) != GetUi32(header + 8))
+ return SZ_ERROR_CRC;
+
+ p->db.RangeLimit = nextHeaderOffset;
+
+ nextHeaderSizeT = (size_t)nextHeaderSize;
+ if (nextHeaderSizeT != nextHeaderSize)
+ return SZ_ERROR_MEM;
+ if (nextHeaderSizeT == 0)
+ return SZ_OK;
+ if (nextHeaderOffset > nextHeaderOffset + nextHeaderSize ||
+ nextHeaderOffset > nextHeaderOffset + nextHeaderSize + k7zStartHeaderSize)
+ return SZ_ERROR_NO_ARCHIVE;
+
+ {
+ Int64 pos = 0;
+ RINOK(ILookInStream_Seek(inStream, &pos, SZ_SEEK_END))
+ if ((UInt64)pos < (UInt64)startArcPos + nextHeaderOffset ||
+ (UInt64)pos < (UInt64)startArcPos + k7zStartHeaderSize + nextHeaderOffset ||
+ (UInt64)pos < (UInt64)startArcPos + k7zStartHeaderSize + nextHeaderOffset + nextHeaderSize)
+ return SZ_ERROR_INPUT_EOF;
+ }
+
+ RINOK(LookInStream_SeekTo(inStream, (UInt64)startArcPos + k7zStartHeaderSize + nextHeaderOffset))
+
+ if (!Buf_Create(&buf, nextHeaderSizeT, allocTemp))
+ return SZ_ERROR_MEM;
+
+ res = LookInStream_Read(inStream, buf.data, nextHeaderSizeT);
+
+ if (res == SZ_OK)
+ {
+ res = SZ_ERROR_ARCHIVE;
+ if (CrcCalc(buf.data, nextHeaderSizeT) == nextHeaderCRC)
+ {
+ CSzData sd;
+ UInt64 type;
+ sd.Data = buf.data;
+ sd.Size = buf.size;
+
+ res = ReadID(&sd, &type);
+
+ if (res == SZ_OK && type == k7zIdEncodedHeader)
+ {
+ CSzAr tempAr;
+ CBuf tempBuf;
+ Buf_Init(&tempBuf);
+
+ SzAr_Init(&tempAr);
+ tempAr.RangeLimit = p->db.RangeLimit;
+
+ res = SzReadAndDecodePackedStreams(inStream, &sd, &tempBuf, 1, p->startPosAfterHeader, &tempAr, allocTemp);
+ SzAr_Free(&tempAr, allocTemp);
+
+ if (res != SZ_OK)
+ {
+ Buf_Free(&tempBuf, allocTemp);
+ }
+ else
+ {
+ Buf_Free(&buf, allocTemp);
+ buf.data = tempBuf.data;
+ buf.size = tempBuf.size;
+ sd.Data = buf.data;
+ sd.Size = buf.size;
+ res = ReadID(&sd, &type);
+ }
+ }
+
+ if (res == SZ_OK)
+ {
+ if (type == k7zIdHeader)
+ {
+ /*
+ CSzData sd2;
+ unsigned ttt;
+ for (ttt = 0; ttt < 40000; ttt++)
+ {
+ SzArEx_Free(p, allocMain);
+ sd2 = sd;
+ res = SzReadHeader(p, &sd2, inStream, allocMain, allocTemp);
+ if (res != SZ_OK)
+ break;
+ }
+ */
+ res = SzReadHeader(p, &sd, inStream, allocMain, allocTemp);
+ }
+ else
+ res = SZ_ERROR_UNSUPPORTED;
+ }
+ }
+ }
+
+ Buf_Free(&buf, allocTemp);
+ return res;
+}
+
+
+SRes SzArEx_Open(CSzArEx *p, ILookInStreamPtr inStream,
+ ISzAllocPtr allocMain, ISzAllocPtr allocTemp)
+{
+ const SRes res = SzArEx_Open2(p, inStream, allocMain, allocTemp);
+ if (res != SZ_OK)
+ SzArEx_Free(p, allocMain);
+ return res;
+}
+
+
+SRes SzArEx_Extract(
+ const CSzArEx *p,
+ ILookInStreamPtr inStream,
+ UInt32 fileIndex,
+ UInt32 *blockIndex,
+ Byte **tempBuf,
+ size_t *outBufferSize,
+ size_t *offset,
+ size_t *outSizeProcessed,
+ ISzAllocPtr allocMain,
+ ISzAllocPtr allocTemp)
+{
+ const UInt32 folderIndex = p->FileToFolder[fileIndex];
+ SRes res = SZ_OK;
+
+ *offset = 0;
+ *outSizeProcessed = 0;
+
+ if (folderIndex == (UInt32)-1)
+ {
+ ISzAlloc_Free(allocMain, *tempBuf);
+ *blockIndex = folderIndex;
+ *tempBuf = NULL;
+ *outBufferSize = 0;
+ return SZ_OK;
+ }
+
+ if (*tempBuf == NULL || *blockIndex != folderIndex)
+ {
+ const UInt64 unpackSizeSpec = SzAr_GetFolderUnpackSize(&p->db, folderIndex);
+ /*
+ UInt64 unpackSizeSpec =
+ p->UnpackPositions[p->FolderToFile[(size_t)folderIndex + 1]] -
+ p->UnpackPositions[p->FolderToFile[folderIndex]];
+ */
+ const size_t unpackSize = (size_t)unpackSizeSpec;
+
+ if (unpackSize != unpackSizeSpec)
+ return SZ_ERROR_MEM;
+ *blockIndex = folderIndex;
+ ISzAlloc_Free(allocMain, *tempBuf);
+ *tempBuf = NULL;
+
+ if (res == SZ_OK)
+ {
+ *outBufferSize = unpackSize;
+ if (unpackSize != 0)
+ {
+ *tempBuf = (Byte *)ISzAlloc_Alloc(allocMain, unpackSize);
+ if (*tempBuf == NULL)
+ res = SZ_ERROR_MEM;
+ }
+
+ if (res == SZ_OK)
+ {
+ res = SzAr_DecodeFolder(&p->db, folderIndex,
+ inStream, p->dataPos, *tempBuf, unpackSize, allocTemp);
+ }
+ }
+ }
+
+ if (res == SZ_OK)
+ {
+ const UInt64 unpackPos = p->UnpackPositions[fileIndex];
+ *offset = (size_t)(unpackPos - p->UnpackPositions[p->FolderToFile[folderIndex]]);
+ *outSizeProcessed = (size_t)(p->UnpackPositions[(size_t)fileIndex + 1] - unpackPos);
+ if (*offset + *outSizeProcessed > *outBufferSize)
+ return SZ_ERROR_FAIL;
+ if (SzBitWithVals_Check(&p->CRCs, fileIndex))
+ if (CrcCalc(*tempBuf + *offset, *outSizeProcessed) != p->CRCs.Vals[fileIndex])
+ res = SZ_ERROR_CRC;
+ }
+
+ return res;
+}
+
+
+size_t SzArEx_GetFileNameUtf16(const CSzArEx *p, size_t fileIndex, UInt16 *dest)
+{
+ const size_t offs = p->FileNameOffsets[fileIndex];
+ const size_t len = p->FileNameOffsets[fileIndex + 1] - offs;
+ if (dest != 0)
+ {
+ size_t i;
+ const Byte *src = p->FileNames + offs * 2;
+ for (i = 0; i < len; i++)
+ dest[i] = GetUi16(src + i * 2);
+ }
+ return len;
+}
+
+/*
+size_t SzArEx_GetFullNameLen(const CSzArEx *p, size_t fileIndex)
+{
+ size_t len;
+ if (!p->FileNameOffsets)
+ return 1;
+ len = 0;
+ for (;;)
+ {
+ UInt32 parent = (UInt32)(Int32)-1;
+ len += p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];
+ if SzBitWithVals_Check(&p->Parents, fileIndex)
+ parent = p->Parents.Vals[fileIndex];
+ if (parent == (UInt32)(Int32)-1)
+ return len;
+ fileIndex = parent;
+ }
+}
+
+UInt16 *SzArEx_GetFullNameUtf16_Back(const CSzArEx *p, size_t fileIndex, UInt16 *dest)
+{
+ BoolInt needSlash;
+ if (!p->FileNameOffsets)
+ {
+ *(--dest) = 0;
+ return dest;
+ }
+ needSlash = False;
+ for (;;)
+ {
+ UInt32 parent = (UInt32)(Int32)-1;
+ size_t curLen = p->FileNameOffsets[fileIndex + 1] - p->FileNameOffsets[fileIndex];
+ SzArEx_GetFileNameUtf16(p, fileIndex, dest - curLen);
+ if (needSlash)
+ *(dest - 1) = '/';
+ needSlash = True;
+ dest -= curLen;
+
+ if SzBitWithVals_Check(&p->Parents, fileIndex)
+ parent = p->Parents.Vals[fileIndex];
+ if (parent == (UInt32)(Int32)-1)
+ return dest;
+ fileIndex = parent;
+ }
+}
+*/
diff --git a/C/7zBuf.c b/C/7zBuf.c
index 438bba6..8865c32 100644
--- a/C/7zBuf.c
+++ b/C/7zBuf.c
@@ -1,36 +1,36 @@
-/* 7zBuf.c -- Byte Buffer
-2017-04-03 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "7zBuf.h"
-
-void Buf_Init(CBuf *p)
-{
- p->data = 0;
- p->size = 0;
-}
-
-int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc)
-{
- p->size = 0;
- if (size == 0)
- {
- p->data = 0;
- return 1;
- }
- p->data = (Byte *)ISzAlloc_Alloc(alloc, size);
- if (p->data)
- {
- p->size = size;
- return 1;
- }
- return 0;
-}
-
-void Buf_Free(CBuf *p, ISzAllocPtr alloc)
-{
- ISzAlloc_Free(alloc, p->data);
- p->data = 0;
- p->size = 0;
-}
+/* 7zBuf.c -- Byte Buffer
+2017-04-03 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "7zBuf.h"
+
+void Buf_Init(CBuf *p)
+{
+ p->data = 0;
+ p->size = 0;
+}
+
+int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc)
+{
+ p->size = 0;
+ if (size == 0)
+ {
+ p->data = 0;
+ return 1;
+ }
+ p->data = (Byte *)ISzAlloc_Alloc(alloc, size);
+ if (p->data)
+ {
+ p->size = size;
+ return 1;
+ }
+ return 0;
+}
+
+void Buf_Free(CBuf *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->data);
+ p->data = 0;
+ p->size = 0;
+}
diff --git a/C/7zBuf.h b/C/7zBuf.h
index 5942d6e..c0ba8a7 100644
--- a/C/7zBuf.h
+++ b/C/7zBuf.h
@@ -1,35 +1,35 @@
-/* 7zBuf.h -- Byte Buffer
-2017-04-03 : Igor Pavlov : Public domain */
-
-#ifndef __7Z_BUF_H
-#define __7Z_BUF_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-typedef struct
-{
- Byte *data;
- size_t size;
-} CBuf;
-
-void Buf_Init(CBuf *p);
-int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc);
-void Buf_Free(CBuf *p, ISzAllocPtr alloc);
-
-typedef struct
-{
- Byte *data;
- size_t size;
- size_t pos;
-} CDynBuf;
-
-void DynBuf_Construct(CDynBuf *p);
-void DynBuf_SeekToBeg(CDynBuf *p);
-int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc);
-void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc);
-
-EXTERN_C_END
-
-#endif
+/* 7zBuf.h -- Byte Buffer
+2023-03-04 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_7Z_BUF_H
+#define ZIP7_INC_7Z_BUF_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+typedef struct
+{
+ Byte *data;
+ size_t size;
+} CBuf;
+
+void Buf_Init(CBuf *p);
+int Buf_Create(CBuf *p, size_t size, ISzAllocPtr alloc);
+void Buf_Free(CBuf *p, ISzAllocPtr alloc);
+
+typedef struct
+{
+ Byte *data;
+ size_t size;
+ size_t pos;
+} CDynBuf;
+
+void DynBuf_Construct(CDynBuf *p);
+void DynBuf_SeekToBeg(CDynBuf *p);
+int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc);
+void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/7zBuf2.c b/C/7zBuf2.c
index 49b4343..2083474 100644
--- a/C/7zBuf2.c
+++ b/C/7zBuf2.c
@@ -1,52 +1,52 @@
-/* 7zBuf2.c -- Byte Buffer
-2017-04-03 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include <string.h>
-
-#include "7zBuf.h"
-
-void DynBuf_Construct(CDynBuf *p)
-{
- p->data = 0;
- p->size = 0;
- p->pos = 0;
-}
-
-void DynBuf_SeekToBeg(CDynBuf *p)
-{
- p->pos = 0;
-}
-
-int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc)
-{
- if (size > p->size - p->pos)
- {
- size_t newSize = p->pos + size;
- Byte *data;
- newSize += newSize / 4;
- data = (Byte *)ISzAlloc_Alloc(alloc, newSize);
- if (!data)
- return 0;
- p->size = newSize;
- if (p->pos != 0)
- memcpy(data, p->data, p->pos);
- ISzAlloc_Free(alloc, p->data);
- p->data = data;
- }
- if (size != 0)
- {
- memcpy(p->data + p->pos, buf, size);
- p->pos += size;
- }
- return 1;
-}
-
-void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc)
-{
- ISzAlloc_Free(alloc, p->data);
- p->data = 0;
- p->size = 0;
- p->pos = 0;
-}
+/* 7zBuf2.c -- Byte Buffer
+2017-04-03 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#include "7zBuf.h"
+
+void DynBuf_Construct(CDynBuf *p)
+{
+ p->data = 0;
+ p->size = 0;
+ p->pos = 0;
+}
+
+void DynBuf_SeekToBeg(CDynBuf *p)
+{
+ p->pos = 0;
+}
+
+int DynBuf_Write(CDynBuf *p, const Byte *buf, size_t size, ISzAllocPtr alloc)
+{
+ if (size > p->size - p->pos)
+ {
+ size_t newSize = p->pos + size;
+ Byte *data;
+ newSize += newSize / 4;
+ data = (Byte *)ISzAlloc_Alloc(alloc, newSize);
+ if (!data)
+ return 0;
+ p->size = newSize;
+ if (p->pos != 0)
+ memcpy(data, p->data, p->pos);
+ ISzAlloc_Free(alloc, p->data);
+ p->data = data;
+ }
+ if (size != 0)
+ {
+ memcpy(p->data + p->pos, buf, size);
+ p->pos += size;
+ }
+ return 1;
+}
+
+void DynBuf_Free(CDynBuf *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->data);
+ p->data = 0;
+ p->size = 0;
+ p->pos = 0;
+}
diff --git a/C/7zCrc.c b/C/7zCrc.c
index 40ab759..c995a8b 100644
--- a/C/7zCrc.c
+++ b/C/7zCrc.c
@@ -1,128 +1,340 @@
-/* 7zCrc.c -- CRC32 init
-2017-06-06 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "7zCrc.h"
-#include "CpuArch.h"
-
-#define kCrcPoly 0xEDB88320
-
-#ifdef MY_CPU_LE
- #define CRC_NUM_TABLES 8
-#else
- #define CRC_NUM_TABLES 9
-
- #define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24))
-
- UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
- UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
-#endif
-
-#ifndef MY_CPU_BE
- UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
- UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
-#endif
-
-typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table);
-
-CRC_FUNC g_CrcUpdateT4;
-CRC_FUNC g_CrcUpdateT8;
-CRC_FUNC g_CrcUpdate;
-
-UInt32 g_CrcTable[256 * CRC_NUM_TABLES];
-
-UInt32 MY_FAST_CALL CrcUpdate(UInt32 v, const void *data, size_t size)
-{
- return g_CrcUpdate(v, data, size, g_CrcTable);
-}
-
-UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size)
-{
- return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL;
-}
-
-#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
-
-UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table)
-{
- const Byte *p = (const Byte *)data;
- const Byte *pEnd = p + size;
- for (; p != pEnd; p++)
- v = CRC_UPDATE_BYTE_2(v, *p);
- return v;
-}
-
-void MY_FAST_CALL CrcGenerateTable()
-{
- UInt32 i;
- for (i = 0; i < 256; i++)
- {
- UInt32 r = i;
- unsigned j;
- for (j = 0; j < 8; j++)
- r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1)));
- g_CrcTable[i] = r;
- }
- for (i = 256; i < 256 * CRC_NUM_TABLES; i++)
- {
- UInt32 r = g_CrcTable[(size_t)i - 256];
- g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
- }
-
- #if CRC_NUM_TABLES < 4
-
- g_CrcUpdate = CrcUpdateT1;
-
- #else
-
- #ifdef MY_CPU_LE
-
- g_CrcUpdateT4 = CrcUpdateT4;
- g_CrcUpdate = CrcUpdateT4;
-
- #if CRC_NUM_TABLES >= 8
- g_CrcUpdateT8 = CrcUpdateT8;
-
- #ifdef MY_CPU_X86_OR_AMD64
- if (!CPU_Is_InOrder())
- #endif
- g_CrcUpdate = CrcUpdateT8;
- #endif
-
- #else
- {
- #ifndef MY_CPU_BE
- UInt32 k = 0x01020304;
- const Byte *p = (const Byte *)&k;
- if (p[0] == 4 && p[1] == 3)
- {
- g_CrcUpdateT4 = CrcUpdateT4;
- g_CrcUpdate = CrcUpdateT4;
- #if CRC_NUM_TABLES >= 8
- g_CrcUpdateT8 = CrcUpdateT8;
- g_CrcUpdate = CrcUpdateT8;
- #endif
- }
- else if (p[0] != 1 || p[1] != 2)
- g_CrcUpdate = CrcUpdateT1;
- else
- #endif
- {
- for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--)
- {
- UInt32 x = g_CrcTable[(size_t)i - 256];
- g_CrcTable[i] = CRC_UINT32_SWAP(x);
- }
- g_CrcUpdateT4 = CrcUpdateT1_BeT4;
- g_CrcUpdate = CrcUpdateT1_BeT4;
- #if CRC_NUM_TABLES >= 8
- g_CrcUpdateT8 = CrcUpdateT1_BeT8;
- g_CrcUpdate = CrcUpdateT1_BeT8;
- #endif
- }
- }
- #endif
-
- #endif
-}
+/* 7zCrc.c -- CRC32 calculation and init
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "7zCrc.h"
+#include "CpuArch.h"
+
+#define kCrcPoly 0xEDB88320
+
+#ifdef MY_CPU_LE
+ #define CRC_NUM_TABLES 8
+#else
+ #define CRC_NUM_TABLES 9
+
+ UInt32 Z7_FASTCALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
+ UInt32 Z7_FASTCALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
+#endif
+
+#ifndef MY_CPU_BE
+ UInt32 Z7_FASTCALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
+ UInt32 Z7_FASTCALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
+#endif
+
+/*
+extern
+CRC_FUNC g_CrcUpdateT4;
+CRC_FUNC g_CrcUpdateT4;
+*/
+extern
+CRC_FUNC g_CrcUpdateT8;
+CRC_FUNC g_CrcUpdateT8;
+extern
+CRC_FUNC g_CrcUpdateT0_32;
+CRC_FUNC g_CrcUpdateT0_32;
+extern
+CRC_FUNC g_CrcUpdateT0_64;
+CRC_FUNC g_CrcUpdateT0_64;
+extern
+CRC_FUNC g_CrcUpdate;
+CRC_FUNC g_CrcUpdate;
+
+UInt32 g_CrcTable[256 * CRC_NUM_TABLES];
+
+UInt32 Z7_FASTCALL CrcUpdate(UInt32 v, const void *data, size_t size)
+{
+ return g_CrcUpdate(v, data, size, g_CrcTable);
+}
+
+UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size)
+{
+ return g_CrcUpdate(CRC_INIT_VAL, data, size, g_CrcTable) ^ CRC_INIT_VAL;
+}
+
+#if CRC_NUM_TABLES < 4 \
+ || (CRC_NUM_TABLES == 4 && defined(MY_CPU_BE)) \
+ || (!defined(MY_CPU_LE) && !defined(MY_CPU_BE))
+#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+UInt32 Z7_FASTCALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table);
+UInt32 Z7_FASTCALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ const Byte *pEnd = p + size;
+ for (; p != pEnd; p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ return v;
+}
+#endif
+
+/* ---------- hardware CRC ---------- */
+
+#ifdef MY_CPU_LE
+
+#if defined(MY_CPU_ARM_OR_ARM64)
+
+// #pragma message("ARM*")
+
+ #if defined(_MSC_VER)
+ #if defined(MY_CPU_ARM64)
+ #if (_MSC_VER >= 1910)
+ #ifndef __clang__
+ #define USE_ARM64_CRC
+ #include <intrin.h>
+ #endif
+ #endif
+ #endif
+ #elif (defined(__clang__) && (__clang_major__ >= 3)) \
+ || (defined(__GNUC__) && (__GNUC__ > 4))
+ #if !defined(__ARM_FEATURE_CRC32)
+ #define __ARM_FEATURE_CRC32 1
+ #if defined(__clang__)
+ #if defined(MY_CPU_ARM64)
+ #define ATTRIB_CRC __attribute__((__target__("crc")))
+ #else
+ #define ATTRIB_CRC __attribute__((__target__("armv8-a,crc")))
+ #endif
+ #else
+ #if defined(MY_CPU_ARM64)
+ #define ATTRIB_CRC __attribute__((__target__("+crc")))
+ #else
+ #define ATTRIB_CRC __attribute__((__target__("arch=armv8-a+crc")))
+ #endif
+ #endif
+ #endif
+ #if defined(__ARM_FEATURE_CRC32)
+ #define USE_ARM64_CRC
+ #include <arm_acle.h>
+ #endif
+ #endif
+
+#else
+
+// no hardware CRC
+
+// #define USE_CRC_EMU
+
+#ifdef USE_CRC_EMU
+
+#pragma message("ARM64 CRC emulation")
+
+Z7_FORCE_INLINE
+UInt32 __crc32b(UInt32 v, UInt32 data)
+{
+ const UInt32 *table = g_CrcTable;
+ v = CRC_UPDATE_BYTE_2(v, (Byte)data);
+ return v;
+}
+
+Z7_FORCE_INLINE
+UInt32 __crc32w(UInt32 v, UInt32 data)
+{
+ const UInt32 *table = g_CrcTable;
+ v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+ v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+ v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+ v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+ return v;
+}
+
+Z7_FORCE_INLINE
+UInt32 __crc32d(UInt32 v, UInt64 data)
+{
+ const UInt32 *table = g_CrcTable;
+ v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+ v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+ v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+ v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+ v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+ v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+ v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+ v = CRC_UPDATE_BYTE_2(v, (Byte)data); data >>= 8;
+ return v;
+}
+
+#endif // USE_CRC_EMU
+
+#endif // defined(MY_CPU_ARM64) && defined(MY_CPU_LE)
+
+
+
+#if defined(USE_ARM64_CRC) || defined(USE_CRC_EMU)
+
+#define T0_32_UNROLL_BYTES (4 * 4)
+#define T0_64_UNROLL_BYTES (4 * 8)
+
+#ifndef ATTRIB_CRC
+#define ATTRIB_CRC
+#endif
+// #pragma message("USE ARM HW CRC")
+
+ATTRIB_CRC
+UInt32 Z7_FASTCALL CrcUpdateT0_32(UInt32 v, const void *data, size_t size, const UInt32 *table);
+ATTRIB_CRC
+UInt32 Z7_FASTCALL CrcUpdateT0_32(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ UNUSED_VAR(table);
+
+ for (; size != 0 && ((unsigned)(ptrdiff_t)p & (T0_32_UNROLL_BYTES - 1)) != 0; size--)
+ v = __crc32b(v, *p++);
+
+ if (size >= T0_32_UNROLL_BYTES)
+ {
+ const Byte *lim = p + size;
+ size &= (T0_32_UNROLL_BYTES - 1);
+ lim -= size;
+ do
+ {
+ v = __crc32w(v, *(const UInt32 *)(const void *)(p));
+ v = __crc32w(v, *(const UInt32 *)(const void *)(p + 4)); p += 2 * 4;
+ v = __crc32w(v, *(const UInt32 *)(const void *)(p));
+ v = __crc32w(v, *(const UInt32 *)(const void *)(p + 4)); p += 2 * 4;
+ }
+ while (p != lim);
+ }
+
+ for (; size != 0; size--)
+ v = __crc32b(v, *p++);
+
+ return v;
+}
+
+ATTRIB_CRC
+UInt32 Z7_FASTCALL CrcUpdateT0_64(UInt32 v, const void *data, size_t size, const UInt32 *table);
+ATTRIB_CRC
+UInt32 Z7_FASTCALL CrcUpdateT0_64(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ UNUSED_VAR(table);
+
+ for (; size != 0 && ((unsigned)(ptrdiff_t)p & (T0_64_UNROLL_BYTES - 1)) != 0; size--)
+ v = __crc32b(v, *p++);
+
+ if (size >= T0_64_UNROLL_BYTES)
+ {
+ const Byte *lim = p + size;
+ size &= (T0_64_UNROLL_BYTES - 1);
+ lim -= size;
+ do
+ {
+ v = __crc32d(v, *(const UInt64 *)(const void *)(p));
+ v = __crc32d(v, *(const UInt64 *)(const void *)(p + 8)); p += 2 * 8;
+ v = __crc32d(v, *(const UInt64 *)(const void *)(p));
+ v = __crc32d(v, *(const UInt64 *)(const void *)(p + 8)); p += 2 * 8;
+ }
+ while (p != lim);
+ }
+
+ for (; size != 0; size--)
+ v = __crc32b(v, *p++);
+
+ return v;
+}
+
+#undef T0_32_UNROLL_BYTES
+#undef T0_64_UNROLL_BYTES
+
+#endif // defined(USE_ARM64_CRC) || defined(USE_CRC_EMU)
+
+#endif // MY_CPU_LE
+
+
+
+
+void Z7_FASTCALL CrcGenerateTable(void)
+{
+ UInt32 i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ unsigned j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1)));
+ g_CrcTable[i] = r;
+ }
+ for (i = 256; i < 256 * CRC_NUM_TABLES; i++)
+ {
+ const UInt32 r = g_CrcTable[(size_t)i - 256];
+ g_CrcTable[i] = g_CrcTable[r & 0xFF] ^ (r >> 8);
+ }
+
+ #if CRC_NUM_TABLES < 4
+ g_CrcUpdate = CrcUpdateT1;
+ #elif defined(MY_CPU_LE)
+ // g_CrcUpdateT4 = CrcUpdateT4;
+ #if CRC_NUM_TABLES < 8
+ g_CrcUpdate = CrcUpdateT4;
+ #else // CRC_NUM_TABLES >= 8
+ g_CrcUpdateT8 = CrcUpdateT8;
+ /*
+ #ifdef MY_CPU_X86_OR_AMD64
+ if (!CPU_Is_InOrder())
+ #endif
+ */
+ g_CrcUpdate = CrcUpdateT8;
+ #endif
+ #else
+ {
+ #ifndef MY_CPU_BE
+ UInt32 k = 0x01020304;
+ const Byte *p = (const Byte *)&k;
+ if (p[0] == 4 && p[1] == 3)
+ {
+ #if CRC_NUM_TABLES < 8
+ // g_CrcUpdateT4 = CrcUpdateT4;
+ g_CrcUpdate = CrcUpdateT4;
+ #else // CRC_NUM_TABLES >= 8
+ g_CrcUpdateT8 = CrcUpdateT8;
+ g_CrcUpdate = CrcUpdateT8;
+ #endif
+ }
+ else if (p[0] != 1 || p[1] != 2)
+ g_CrcUpdate = CrcUpdateT1;
+ else
+ #endif // MY_CPU_BE
+ {
+ for (i = 256 * CRC_NUM_TABLES - 1; i >= 256; i--)
+ {
+ const UInt32 x = g_CrcTable[(size_t)i - 256];
+ g_CrcTable[i] = Z7_BSWAP32(x);
+ }
+ #if CRC_NUM_TABLES <= 4
+ g_CrcUpdate = CrcUpdateT1;
+ #elif CRC_NUM_TABLES <= 8
+ // g_CrcUpdateT4 = CrcUpdateT1_BeT4;
+ g_CrcUpdate = CrcUpdateT1_BeT4;
+ #else // CRC_NUM_TABLES > 8
+ g_CrcUpdateT8 = CrcUpdateT1_BeT8;
+ g_CrcUpdate = CrcUpdateT1_BeT8;
+ #endif
+ }
+ }
+ #endif // CRC_NUM_TABLES < 4
+
+ #ifdef MY_CPU_LE
+ #ifdef USE_ARM64_CRC
+ if (CPU_IsSupported_CRC32())
+ {
+ g_CrcUpdateT0_32 = CrcUpdateT0_32;
+ g_CrcUpdateT0_64 = CrcUpdateT0_64;
+ g_CrcUpdate =
+ #if defined(MY_CPU_ARM)
+ CrcUpdateT0_32;
+ #else
+ CrcUpdateT0_64;
+ #endif
+ }
+ #endif
+
+ #ifdef USE_CRC_EMU
+ g_CrcUpdateT0_32 = CrcUpdateT0_32;
+ g_CrcUpdateT0_64 = CrcUpdateT0_64;
+ g_CrcUpdate = CrcUpdateT0_64;
+ #endif
+ #endif
+}
+
+#undef kCrcPoly
+#undef CRC64_NUM_TABLES
+#undef CRC_UPDATE_BYTE_2
diff --git a/C/7zCrc.h b/C/7zCrc.h
index 3b04594..4afaeae 100644
--- a/C/7zCrc.h
+++ b/C/7zCrc.h
@@ -1,25 +1,27 @@
-/* 7zCrc.h -- CRC32 calculation
-2013-01-18 : Igor Pavlov : Public domain */
-
-#ifndef __7Z_CRC_H
-#define __7Z_CRC_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-extern UInt32 g_CrcTable[];
-
-/* Call CrcGenerateTable one time before other CRC functions */
-void MY_FAST_CALL CrcGenerateTable(void);
-
-#define CRC_INIT_VAL 0xFFFFFFFF
-#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL)
-#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
-
-UInt32 MY_FAST_CALL CrcUpdate(UInt32 crc, const void *data, size_t size);
-UInt32 MY_FAST_CALL CrcCalc(const void *data, size_t size);
-
-EXTERN_C_END
-
-#endif
+/* 7zCrc.h -- CRC32 calculation
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_7Z_CRC_H
+#define ZIP7_INC_7Z_CRC_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+extern UInt32 g_CrcTable[];
+
+/* Call CrcGenerateTable one time before other CRC functions */
+void Z7_FASTCALL CrcGenerateTable(void);
+
+#define CRC_INIT_VAL 0xFFFFFFFF
+#define CRC_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL)
+#define CRC_UPDATE_BYTE(crc, b) (g_CrcTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt32 Z7_FASTCALL CrcUpdate(UInt32 crc, const void *data, size_t size);
+UInt32 Z7_FASTCALL CrcCalc(const void *data, size_t size);
+
+typedef UInt32 (Z7_FASTCALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/7zCrcOpt.c b/C/7zCrcOpt.c
index 2ee0de8..9c64929 100644
--- a/C/7zCrcOpt.c
+++ b/C/7zCrcOpt.c
@@ -1,115 +1,117 @@
-/* 7zCrcOpt.c -- CRC32 calculation
-2017-04-03 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "CpuArch.h"
-
-#ifndef MY_CPU_BE
-
-#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
-
-UInt32 MY_FAST_CALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
-{
- const Byte *p = (const Byte *)data;
- for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
- v = CRC_UPDATE_BYTE_2(v, *p);
- for (; size >= 4; size -= 4, p += 4)
- {
- v ^= *(const UInt32 *)p;
- v =
- (table + 0x300)[((v ) & 0xFF)]
- ^ (table + 0x200)[((v >> 8) & 0xFF)]
- ^ (table + 0x100)[((v >> 16) & 0xFF)]
- ^ (table + 0x000)[((v >> 24))];
- }
- for (; size > 0; size--, p++)
- v = CRC_UPDATE_BYTE_2(v, *p);
- return v;
-}
-
-UInt32 MY_FAST_CALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
-{
- const Byte *p = (const Byte *)data;
- for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++)
- v = CRC_UPDATE_BYTE_2(v, *p);
- for (; size >= 8; size -= 8, p += 8)
- {
- UInt32 d;
- v ^= *(const UInt32 *)p;
- v =
- (table + 0x700)[((v ) & 0xFF)]
- ^ (table + 0x600)[((v >> 8) & 0xFF)]
- ^ (table + 0x500)[((v >> 16) & 0xFF)]
- ^ (table + 0x400)[((v >> 24))];
- d = *((const UInt32 *)p + 1);
- v ^=
- (table + 0x300)[((d ) & 0xFF)]
- ^ (table + 0x200)[((d >> 8) & 0xFF)]
- ^ (table + 0x100)[((d >> 16) & 0xFF)]
- ^ (table + 0x000)[((d >> 24))];
- }
- for (; size > 0; size--, p++)
- v = CRC_UPDATE_BYTE_2(v, *p);
- return v;
-}
-
-#endif
-
-
-#ifndef MY_CPU_LE
-
-#define CRC_UINT32_SWAP(v) ((v >> 24) | ((v >> 8) & 0xFF00) | ((v << 8) & 0xFF0000) | (v << 24))
-
-#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[(((crc) >> 24) ^ (b))] ^ ((crc) << 8))
-
-UInt32 MY_FAST_CALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
-{
- const Byte *p = (const Byte *)data;
- table += 0x100;
- v = CRC_UINT32_SWAP(v);
- for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
- v = CRC_UPDATE_BYTE_2_BE(v, *p);
- for (; size >= 4; size -= 4, p += 4)
- {
- v ^= *(const UInt32 *)p;
- v =
- (table + 0x000)[((v ) & 0xFF)]
- ^ (table + 0x100)[((v >> 8) & 0xFF)]
- ^ (table + 0x200)[((v >> 16) & 0xFF)]
- ^ (table + 0x300)[((v >> 24))];
- }
- for (; size > 0; size--, p++)
- v = CRC_UPDATE_BYTE_2_BE(v, *p);
- return CRC_UINT32_SWAP(v);
-}
-
-UInt32 MY_FAST_CALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
-{
- const Byte *p = (const Byte *)data;
- table += 0x100;
- v = CRC_UINT32_SWAP(v);
- for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++)
- v = CRC_UPDATE_BYTE_2_BE(v, *p);
- for (; size >= 8; size -= 8, p += 8)
- {
- UInt32 d;
- v ^= *(const UInt32 *)p;
- v =
- (table + 0x400)[((v ) & 0xFF)]
- ^ (table + 0x500)[((v >> 8) & 0xFF)]
- ^ (table + 0x600)[((v >> 16) & 0xFF)]
- ^ (table + 0x700)[((v >> 24))];
- d = *((const UInt32 *)p + 1);
- v ^=
- (table + 0x000)[((d ) & 0xFF)]
- ^ (table + 0x100)[((d >> 8) & 0xFF)]
- ^ (table + 0x200)[((d >> 16) & 0xFF)]
- ^ (table + 0x300)[((d >> 24))];
- }
- for (; size > 0; size--, p++)
- v = CRC_UPDATE_BYTE_2_BE(v, *p);
- return CRC_UINT32_SWAP(v);
-}
-
-#endif
+/* 7zCrcOpt.c -- CRC32 calculation
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "CpuArch.h"
+
+#ifndef MY_CPU_BE
+
+#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt32 Z7_FASTCALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table);
+UInt32 Z7_FASTCALL CrcUpdateT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ for (; size >= 4; size -= 4, p += 4)
+ {
+ v ^= *(const UInt32 *)(const void *)p;
+ v =
+ (table + 0x300)[((v ) & 0xFF)]
+ ^ (table + 0x200)[((v >> 8) & 0xFF)]
+ ^ (table + 0x100)[((v >> 16) & 0xFF)]
+ ^ (table + 0x000)[((v >> 24))];
+ }
+ for (; size > 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ return v;
+}
+
+UInt32 Z7_FASTCALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table);
+UInt32 Z7_FASTCALL CrcUpdateT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ for (; size >= 8; size -= 8, p += 8)
+ {
+ UInt32 d;
+ v ^= *(const UInt32 *)(const void *)p;
+ v =
+ (table + 0x700)[((v ) & 0xFF)]
+ ^ (table + 0x600)[((v >> 8) & 0xFF)]
+ ^ (table + 0x500)[((v >> 16) & 0xFF)]
+ ^ (table + 0x400)[((v >> 24))];
+ d = *((const UInt32 *)(const void *)p + 1);
+ v ^=
+ (table + 0x300)[((d ) & 0xFF)]
+ ^ (table + 0x200)[((d >> 8) & 0xFF)]
+ ^ (table + 0x100)[((d >> 16) & 0xFF)]
+ ^ (table + 0x000)[((d >> 24))];
+ }
+ for (; size > 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ return v;
+}
+
+#endif
+
+
+#ifndef MY_CPU_LE
+
+#define CRC_UINT32_SWAP(v) Z7_BSWAP32(v)
+
+#define CRC_UPDATE_BYTE_2_BE(crc, b) (table[(((crc) >> 24) ^ (b))] ^ ((crc) << 8))
+
+UInt32 Z7_FASTCALL CrcUpdateT1_BeT4(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ table += 0x100;
+ v = CRC_UINT32_SWAP(v);
+ for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2_BE(v, *p);
+ for (; size >= 4; size -= 4, p += 4)
+ {
+ v ^= *(const UInt32 *)(const void *)p;
+ v =
+ (table + 0x000)[((v ) & 0xFF)]
+ ^ (table + 0x100)[((v >> 8) & 0xFF)]
+ ^ (table + 0x200)[((v >> 16) & 0xFF)]
+ ^ (table + 0x300)[((v >> 24))];
+ }
+ for (; size > 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2_BE(v, *p);
+ return CRC_UINT32_SWAP(v);
+}
+
+UInt32 Z7_FASTCALL CrcUpdateT1_BeT8(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ table += 0x100;
+ v = CRC_UINT32_SWAP(v);
+ for (; size > 0 && ((unsigned)(ptrdiff_t)p & 7) != 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2_BE(v, *p);
+ for (; size >= 8; size -= 8, p += 8)
+ {
+ UInt32 d;
+ v ^= *(const UInt32 *)(const void *)p;
+ v =
+ (table + 0x400)[((v ) & 0xFF)]
+ ^ (table + 0x500)[((v >> 8) & 0xFF)]
+ ^ (table + 0x600)[((v >> 16) & 0xFF)]
+ ^ (table + 0x700)[((v >> 24))];
+ d = *((const UInt32 *)(const void *)p + 1);
+ v ^=
+ (table + 0x000)[((d ) & 0xFF)]
+ ^ (table + 0x100)[((d >> 8) & 0xFF)]
+ ^ (table + 0x200)[((d >> 16) & 0xFF)]
+ ^ (table + 0x300)[((d >> 24))];
+ }
+ for (; size > 0; size--, p++)
+ v = CRC_UPDATE_BYTE_2_BE(v, *p);
+ return CRC_UINT32_SWAP(v);
+}
+
+#endif
diff --git a/C/7zDec.c b/C/7zDec.c
index 2a7b090..96c6035 100644
--- a/C/7zDec.c
+++ b/C/7zDec.c
@@ -1,591 +1,648 @@
-/* 7zDec.c -- Decoding from 7z folder
-2019-02-02 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include <string.h>
-
-/* #define _7ZIP_PPMD_SUPPPORT */
-
-#include "7z.h"
-#include "7zCrc.h"
-
-#include "Bcj2.h"
-#include "Bra.h"
-#include "CpuArch.h"
-#include "Delta.h"
-#include "LzmaDec.h"
-#include "Lzma2Dec.h"
-#ifdef _7ZIP_PPMD_SUPPPORT
-#include "Ppmd7.h"
-#endif
-
-#define k_Copy 0
-#define k_Delta 3
-#define k_LZMA2 0x21
-#define k_LZMA 0x30101
-#define k_BCJ 0x3030103
-#define k_BCJ2 0x303011B
-#define k_PPC 0x3030205
-#define k_IA64 0x3030401
-#define k_ARM 0x3030501
-#define k_ARMT 0x3030701
-#define k_SPARC 0x3030805
-
-
-#ifdef _7ZIP_PPMD_SUPPPORT
-
-#define k_PPMD 0x30401
-
-typedef struct
-{
- IByteIn vt;
- const Byte *cur;
- const Byte *end;
- const Byte *begin;
- UInt64 processed;
- BoolInt extra;
- SRes res;
- const ILookInStream *inStream;
-} CByteInToLook;
-
-static Byte ReadByte(const IByteIn *pp)
-{
- CByteInToLook *p = CONTAINER_FROM_VTBL(pp, CByteInToLook, vt);
- if (p->cur != p->end)
- return *p->cur++;
- if (p->res == SZ_OK)
- {
- size_t size = p->cur - p->begin;
- p->processed += size;
- p->res = ILookInStream_Skip(p->inStream, size);
- size = (1 << 25);
- p->res = ILookInStream_Look(p->inStream, (const void **)&p->begin, &size);
- p->cur = p->begin;
- p->end = p->begin + size;
- if (size != 0)
- return *p->cur++;;
- }
- p->extra = True;
- return 0;
-}
-
-static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, const ILookInStream *inStream,
- Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
-{
- CPpmd7 ppmd;
- CByteInToLook s;
- SRes res = SZ_OK;
-
- s.vt.Read = ReadByte;
- s.inStream = inStream;
- s.begin = s.end = s.cur = NULL;
- s.extra = False;
- s.res = SZ_OK;
- s.processed = 0;
-
- if (propsSize != 5)
- return SZ_ERROR_UNSUPPORTED;
-
- {
- unsigned order = props[0];
- UInt32 memSize = GetUi32(props + 1);
- if (order < PPMD7_MIN_ORDER ||
- order > PPMD7_MAX_ORDER ||
- memSize < PPMD7_MIN_MEM_SIZE ||
- memSize > PPMD7_MAX_MEM_SIZE)
- return SZ_ERROR_UNSUPPORTED;
- Ppmd7_Construct(&ppmd);
- if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
- return SZ_ERROR_MEM;
- Ppmd7_Init(&ppmd, order);
- }
- {
- CPpmd7z_RangeDec rc;
- Ppmd7z_RangeDec_CreateVTable(&rc);
- rc.Stream = &s.vt;
- if (!Ppmd7z_RangeDec_Init(&rc))
- res = SZ_ERROR_DATA;
- else if (s.extra)
- res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
- else
- {
- SizeT i;
- for (i = 0; i < outSize; i++)
- {
- int sym = Ppmd7_DecodeSymbol(&ppmd, &rc.vt);
- if (s.extra || sym < 0)
- break;
- outBuffer[i] = (Byte)sym;
- }
- if (i != outSize)
- res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
- else if (s.processed + (s.cur - s.begin) != inSize || !Ppmd7z_RangeDec_IsFinishedOK(&rc))
- res = SZ_ERROR_DATA;
- }
- }
- Ppmd7_Free(&ppmd, allocMain);
- return res;
-}
-
-#endif
-
-
-static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
- Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
-{
- CLzmaDec state;
- SRes res = SZ_OK;
-
- LzmaDec_Construct(&state);
- RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain));
- state.dic = outBuffer;
- state.dicBufSize = outSize;
- LzmaDec_Init(&state);
-
- for (;;)
- {
- const void *inBuf = NULL;
- size_t lookahead = (1 << 18);
- if (lookahead > inSize)
- lookahead = (size_t)inSize;
- res = ILookInStream_Look(inStream, &inBuf, &lookahead);
- if (res != SZ_OK)
- break;
-
- {
- SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
- ELzmaStatus status;
- res = LzmaDec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status);
- lookahead -= inProcessed;
- inSize -= inProcessed;
- if (res != SZ_OK)
- break;
-
- if (status == LZMA_STATUS_FINISHED_WITH_MARK)
- {
- if (outSize != state.dicPos || inSize != 0)
- res = SZ_ERROR_DATA;
- break;
- }
-
- if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
- break;
-
- if (inProcessed == 0 && dicPos == state.dicPos)
- {
- res = SZ_ERROR_DATA;
- break;
- }
-
- res = ILookInStream_Skip(inStream, inProcessed);
- if (res != SZ_OK)
- break;
- }
- }
-
- LzmaDec_FreeProbs(&state, allocMain);
- return res;
-}
-
-
-#ifndef _7Z_NO_METHOD_LZMA2
-
-static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStream *inStream,
- Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
-{
- CLzma2Dec state;
- SRes res = SZ_OK;
-
- Lzma2Dec_Construct(&state);
- if (propsSize != 1)
- return SZ_ERROR_DATA;
- RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain));
- state.decoder.dic = outBuffer;
- state.decoder.dicBufSize = outSize;
- Lzma2Dec_Init(&state);
-
- for (;;)
- {
- const void *inBuf = NULL;
- size_t lookahead = (1 << 18);
- if (lookahead > inSize)
- lookahead = (size_t)inSize;
- res = ILookInStream_Look(inStream, &inBuf, &lookahead);
- if (res != SZ_OK)
- break;
-
- {
- SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
- ELzmaStatus status;
- res = Lzma2Dec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status);
- lookahead -= inProcessed;
- inSize -= inProcessed;
- if (res != SZ_OK)
- break;
-
- if (status == LZMA_STATUS_FINISHED_WITH_MARK)
- {
- if (outSize != state.decoder.dicPos || inSize != 0)
- res = SZ_ERROR_DATA;
- break;
- }
-
- if (inProcessed == 0 && dicPos == state.decoder.dicPos)
- {
- res = SZ_ERROR_DATA;
- break;
- }
-
- res = ILookInStream_Skip(inStream, inProcessed);
- if (res != SZ_OK)
- break;
- }
- }
-
- Lzma2Dec_FreeProbs(&state, allocMain);
- return res;
-}
-
-#endif
-
-
-static SRes SzDecodeCopy(UInt64 inSize, ILookInStream *inStream, Byte *outBuffer)
-{
- while (inSize > 0)
- {
- const void *inBuf;
- size_t curSize = (1 << 18);
- if (curSize > inSize)
- curSize = (size_t)inSize;
- RINOK(ILookInStream_Look(inStream, &inBuf, &curSize));
- if (curSize == 0)
- return SZ_ERROR_INPUT_EOF;
- memcpy(outBuffer, inBuf, curSize);
- outBuffer += curSize;
- inSize -= curSize;
- RINOK(ILookInStream_Skip(inStream, curSize));
- }
- return SZ_OK;
-}
-
-static BoolInt IS_MAIN_METHOD(UInt32 m)
-{
- switch (m)
- {
- case k_Copy:
- case k_LZMA:
- #ifndef _7Z_NO_METHOD_LZMA2
- case k_LZMA2:
- #endif
- #ifdef _7ZIP_PPMD_SUPPPORT
- case k_PPMD:
- #endif
- return True;
- }
- return False;
-}
-
-static BoolInt IS_SUPPORTED_CODER(const CSzCoderInfo *c)
-{
- return
- c->NumStreams == 1
- /* && c->MethodID <= (UInt32)0xFFFFFFFF */
- && IS_MAIN_METHOD((UInt32)c->MethodID);
-}
-
-#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4)
-
-static SRes CheckSupportedFolder(const CSzFolder *f)
-{
- if (f->NumCoders < 1 || f->NumCoders > 4)
- return SZ_ERROR_UNSUPPORTED;
- if (!IS_SUPPORTED_CODER(&f->Coders[0]))
- return SZ_ERROR_UNSUPPORTED;
- if (f->NumCoders == 1)
- {
- if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0)
- return SZ_ERROR_UNSUPPORTED;
- return SZ_OK;
- }
-
-
- #ifndef _7Z_NO_METHODS_FILTERS
-
- if (f->NumCoders == 2)
- {
- const CSzCoderInfo *c = &f->Coders[1];
- if (
- /* c->MethodID > (UInt32)0xFFFFFFFF || */
- c->NumStreams != 1
- || f->NumPackStreams != 1
- || f->PackStreams[0] != 0
- || f->NumBonds != 1
- || f->Bonds[0].InIndex != 1
- || f->Bonds[0].OutIndex != 0)
- return SZ_ERROR_UNSUPPORTED;
- switch ((UInt32)c->MethodID)
- {
- case k_Delta:
- case k_BCJ:
- case k_PPC:
- case k_IA64:
- case k_SPARC:
- case k_ARM:
- case k_ARMT:
- break;
- default:
- return SZ_ERROR_UNSUPPORTED;
- }
- return SZ_OK;
- }
-
- #endif
-
-
- if (f->NumCoders == 4)
- {
- if (!IS_SUPPORTED_CODER(&f->Coders[1])
- || !IS_SUPPORTED_CODER(&f->Coders[2])
- || !IS_BCJ2(&f->Coders[3]))
- return SZ_ERROR_UNSUPPORTED;
- if (f->NumPackStreams != 4
- || f->PackStreams[0] != 2
- || f->PackStreams[1] != 6
- || f->PackStreams[2] != 1
- || f->PackStreams[3] != 0
- || f->NumBonds != 3
- || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0
- || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1
- || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2)
- return SZ_ERROR_UNSUPPORTED;
- return SZ_OK;
- }
-
- return SZ_ERROR_UNSUPPORTED;
-}
-
-#define CASE_BRA_CONV(isa) case k_ ## isa: isa ## _Convert(outBuffer, outSize, 0, 0); break;
-
-static SRes SzFolder_Decode2(const CSzFolder *folder,
- const Byte *propsData,
- const UInt64 *unpackSizes,
- const UInt64 *packPositions,
- ILookInStream *inStream, UInt64 startPos,
- Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain,
- Byte *tempBuf[])
-{
- UInt32 ci;
- SizeT tempSizes[3] = { 0, 0, 0};
- SizeT tempSize3 = 0;
- Byte *tempBuf3 = 0;
-
- RINOK(CheckSupportedFolder(folder));
-
- for (ci = 0; ci < folder->NumCoders; ci++)
- {
- const CSzCoderInfo *coder = &folder->Coders[ci];
-
- if (IS_MAIN_METHOD((UInt32)coder->MethodID))
- {
- UInt32 si = 0;
- UInt64 offset;
- UInt64 inSize;
- Byte *outBufCur = outBuffer;
- SizeT outSizeCur = outSize;
- if (folder->NumCoders == 4)
- {
- UInt32 indices[] = { 3, 2, 0 };
- UInt64 unpackSize = unpackSizes[ci];
- si = indices[ci];
- if (ci < 2)
- {
- Byte *temp;
- outSizeCur = (SizeT)unpackSize;
- if (outSizeCur != unpackSize)
- return SZ_ERROR_MEM;
- temp = (Byte *)ISzAlloc_Alloc(allocMain, outSizeCur);
- if (!temp && outSizeCur != 0)
- return SZ_ERROR_MEM;
- outBufCur = tempBuf[1 - ci] = temp;
- tempSizes[1 - ci] = outSizeCur;
- }
- else if (ci == 2)
- {
- if (unpackSize > outSize) /* check it */
- return SZ_ERROR_PARAM;
- tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
- tempSize3 = outSizeCur = (SizeT)unpackSize;
- }
- else
- return SZ_ERROR_UNSUPPORTED;
- }
- offset = packPositions[si];
- inSize = packPositions[(size_t)si + 1] - offset;
- RINOK(LookInStream_SeekTo(inStream, startPos + offset));
-
- if (coder->MethodID == k_Copy)
- {
- if (inSize != outSizeCur) /* check it */
- return SZ_ERROR_DATA;
- RINOK(SzDecodeCopy(inSize, inStream, outBufCur));
- }
- else if (coder->MethodID == k_LZMA)
- {
- RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
- }
- #ifndef _7Z_NO_METHOD_LZMA2
- else if (coder->MethodID == k_LZMA2)
- {
- RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
- }
- #endif
- #ifdef _7ZIP_PPMD_SUPPPORT
- else if (coder->MethodID == k_PPMD)
- {
- RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain));
- }
- #endif
- else
- return SZ_ERROR_UNSUPPORTED;
- }
- else if (coder->MethodID == k_BCJ2)
- {
- UInt64 offset = packPositions[1];
- UInt64 s3Size = packPositions[2] - offset;
-
- if (ci != 3)
- return SZ_ERROR_UNSUPPORTED;
-
- tempSizes[2] = (SizeT)s3Size;
- if (tempSizes[2] != s3Size)
- return SZ_ERROR_MEM;
- tempBuf[2] = (Byte *)ISzAlloc_Alloc(allocMain, tempSizes[2]);
- if (!tempBuf[2] && tempSizes[2] != 0)
- return SZ_ERROR_MEM;
-
- RINOK(LookInStream_SeekTo(inStream, startPos + offset));
- RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2]));
-
- if ((tempSizes[0] & 3) != 0 ||
- (tempSizes[1] & 3) != 0 ||
- tempSize3 + tempSizes[0] + tempSizes[1] != outSize)
- return SZ_ERROR_DATA;
-
- {
- CBcj2Dec p;
-
- p.bufs[0] = tempBuf3; p.lims[0] = tempBuf3 + tempSize3;
- p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0];
- p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1];
- p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2];
-
- p.dest = outBuffer;
- p.destLim = outBuffer + outSize;
-
- Bcj2Dec_Init(&p);
- RINOK(Bcj2Dec_Decode(&p));
-
- {
- unsigned i;
- for (i = 0; i < 4; i++)
- if (p.bufs[i] != p.lims[i])
- return SZ_ERROR_DATA;
-
- if (!Bcj2Dec_IsFinished(&p))
- return SZ_ERROR_DATA;
-
- if (p.dest != p.destLim
- || p.state != BCJ2_STREAM_MAIN)
- return SZ_ERROR_DATA;
- }
- }
- }
- #ifndef _7Z_NO_METHODS_FILTERS
- else if (ci == 1)
- {
- if (coder->MethodID == k_Delta)
- {
- if (coder->PropsSize != 1)
- return SZ_ERROR_UNSUPPORTED;
- {
- Byte state[DELTA_STATE_SIZE];
- Delta_Init(state);
- Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize);
- }
- }
- else
- {
- if (coder->PropsSize != 0)
- return SZ_ERROR_UNSUPPORTED;
- switch (coder->MethodID)
- {
- case k_BCJ:
- {
- UInt32 state;
- x86_Convert_Init(state);
- x86_Convert(outBuffer, outSize, 0, &state, 0);
- break;
- }
- CASE_BRA_CONV(PPC)
- CASE_BRA_CONV(IA64)
- CASE_BRA_CONV(SPARC)
- CASE_BRA_CONV(ARM)
- CASE_BRA_CONV(ARMT)
- default:
- return SZ_ERROR_UNSUPPORTED;
- }
- }
- }
- #endif
- else
- return SZ_ERROR_UNSUPPORTED;
- }
-
- return SZ_OK;
-}
-
-
-SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
- ILookInStream *inStream, UInt64 startPos,
- Byte *outBuffer, size_t outSize,
- ISzAllocPtr allocMain)
-{
- SRes res;
- CSzFolder folder;
- CSzData sd;
-
- const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex];
- sd.Data = data;
- sd.Size = p->FoCodersOffsets[(size_t)folderIndex + 1] - p->FoCodersOffsets[folderIndex];
-
- res = SzGetNextFolderItem(&folder, &sd);
-
- if (res != SZ_OK)
- return res;
-
- if (sd.Size != 0
- || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex]
- || outSize != SzAr_GetFolderUnpackSize(p, folderIndex))
- return SZ_ERROR_FAIL;
- {
- unsigned i;
- Byte *tempBuf[3] = { 0, 0, 0};
-
- res = SzFolder_Decode2(&folder, data,
- &p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]],
- p->PackPositions + p->FoStartPackStreamIndex[folderIndex],
- inStream, startPos,
- outBuffer, (SizeT)outSize, allocMain, tempBuf);
-
- for (i = 0; i < 3; i++)
- ISzAlloc_Free(allocMain, tempBuf[i]);
-
- if (res == SZ_OK)
- if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex))
- if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex])
- res = SZ_ERROR_CRC;
-
- return res;
- }
-}
+/* 7zDec.c -- Decoding from 7z folder
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+/* #define Z7_PPMD_SUPPORT */
+
+#include "7z.h"
+#include "7zCrc.h"
+
+#include "Bcj2.h"
+#include "Bra.h"
+#include "CpuArch.h"
+#include "Delta.h"
+#include "LzmaDec.h"
+#include "Lzma2Dec.h"
+#ifdef Z7_PPMD_SUPPORT
+#include "Ppmd7.h"
+#endif
+
+#define k_Copy 0
+#ifndef Z7_NO_METHOD_LZMA2
+#define k_LZMA2 0x21
+#endif
+#define k_LZMA 0x30101
+#define k_BCJ2 0x303011B
+
+#if !defined(Z7_NO_METHODS_FILTERS)
+#define Z7_USE_BRANCH_FILTER
+#endif
+
+#if !defined(Z7_NO_METHODS_FILTERS) || \
+ defined(Z7_USE_NATIVE_BRANCH_FILTER) && defined(MY_CPU_ARM64)
+#define Z7_USE_FILTER_ARM64
+#ifndef Z7_USE_BRANCH_FILTER
+#define Z7_USE_BRANCH_FILTER
+#endif
+#define k_ARM64 0xa
+#endif
+
+#if !defined(Z7_NO_METHODS_FILTERS) || \
+ defined(Z7_USE_NATIVE_BRANCH_FILTER) && defined(MY_CPU_ARMT)
+#define Z7_USE_FILTER_ARMT
+#ifndef Z7_USE_BRANCH_FILTER
+#define Z7_USE_BRANCH_FILTER
+#endif
+#define k_ARMT 0x3030701
+#endif
+
+#ifndef Z7_NO_METHODS_FILTERS
+#define k_Delta 3
+#define k_BCJ 0x3030103
+#define k_PPC 0x3030205
+#define k_IA64 0x3030401
+#define k_ARM 0x3030501
+#define k_SPARC 0x3030805
+#endif
+
+#ifdef Z7_PPMD_SUPPORT
+
+#define k_PPMD 0x30401
+
+typedef struct
+{
+ IByteIn vt;
+ const Byte *cur;
+ const Byte *end;
+ const Byte *begin;
+ UInt64 processed;
+ BoolInt extra;
+ SRes res;
+ ILookInStreamPtr inStream;
+} CByteInToLook;
+
+static Byte ReadByte(IByteInPtr pp)
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CByteInToLook)
+ if (p->cur != p->end)
+ return *p->cur++;
+ if (p->res == SZ_OK)
+ {
+ size_t size = (size_t)(p->cur - p->begin);
+ p->processed += size;
+ p->res = ILookInStream_Skip(p->inStream, size);
+ size = (1 << 25);
+ p->res = ILookInStream_Look(p->inStream, (const void **)&p->begin, &size);
+ p->cur = p->begin;
+ p->end = p->begin + size;
+ if (size != 0)
+ return *p->cur++;
+ }
+ p->extra = True;
+ return 0;
+}
+
+static SRes SzDecodePpmd(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream,
+ Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
+{
+ CPpmd7 ppmd;
+ CByteInToLook s;
+ SRes res = SZ_OK;
+
+ s.vt.Read = ReadByte;
+ s.inStream = inStream;
+ s.begin = s.end = s.cur = NULL;
+ s.extra = False;
+ s.res = SZ_OK;
+ s.processed = 0;
+
+ if (propsSize != 5)
+ return SZ_ERROR_UNSUPPORTED;
+
+ {
+ unsigned order = props[0];
+ UInt32 memSize = GetUi32(props + 1);
+ if (order < PPMD7_MIN_ORDER ||
+ order > PPMD7_MAX_ORDER ||
+ memSize < PPMD7_MIN_MEM_SIZE ||
+ memSize > PPMD7_MAX_MEM_SIZE)
+ return SZ_ERROR_UNSUPPORTED;
+ Ppmd7_Construct(&ppmd);
+ if (!Ppmd7_Alloc(&ppmd, memSize, allocMain))
+ return SZ_ERROR_MEM;
+ Ppmd7_Init(&ppmd, order);
+ }
+ {
+ ppmd.rc.dec.Stream = &s.vt;
+ if (!Ppmd7z_RangeDec_Init(&ppmd.rc.dec))
+ res = SZ_ERROR_DATA;
+ else if (!s.extra)
+ {
+ Byte *buf = outBuffer;
+ const Byte *lim = buf + outSize;
+ for (; buf != lim; buf++)
+ {
+ int sym = Ppmd7z_DecodeSymbol(&ppmd);
+ if (s.extra || sym < 0)
+ break;
+ *buf = (Byte)sym;
+ }
+ if (buf != lim)
+ res = SZ_ERROR_DATA;
+ else if (!Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec))
+ {
+ /* if (Ppmd7z_DecodeSymbol(&ppmd) != PPMD7_SYM_END || !Ppmd7z_RangeDec_IsFinishedOK(&ppmd.rc.dec)) */
+ res = SZ_ERROR_DATA;
+ }
+ }
+ if (s.extra)
+ res = (s.res != SZ_OK ? s.res : SZ_ERROR_DATA);
+ else if (s.processed + (size_t)(s.cur - s.begin) != inSize)
+ res = SZ_ERROR_DATA;
+ }
+ Ppmd7_Free(&ppmd, allocMain);
+ return res;
+}
+
+#endif
+
+
+static SRes SzDecodeLzma(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream,
+ Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
+{
+ CLzmaDec state;
+ SRes res = SZ_OK;
+
+ LzmaDec_CONSTRUCT(&state)
+ RINOK(LzmaDec_AllocateProbs(&state, props, propsSize, allocMain))
+ state.dic = outBuffer;
+ state.dicBufSize = outSize;
+ LzmaDec_Init(&state);
+
+ for (;;)
+ {
+ const void *inBuf = NULL;
+ size_t lookahead = (1 << 18);
+ if (lookahead > inSize)
+ lookahead = (size_t)inSize;
+ res = ILookInStream_Look(inStream, &inBuf, &lookahead);
+ if (res != SZ_OK)
+ break;
+
+ {
+ SizeT inProcessed = (SizeT)lookahead, dicPos = state.dicPos;
+ ELzmaStatus status;
+ res = LzmaDec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status);
+ lookahead -= inProcessed;
+ inSize -= inProcessed;
+ if (res != SZ_OK)
+ break;
+
+ if (status == LZMA_STATUS_FINISHED_WITH_MARK)
+ {
+ if (outSize != state.dicPos || inSize != 0)
+ res = SZ_ERROR_DATA;
+ break;
+ }
+
+ if (outSize == state.dicPos && inSize == 0 && status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
+ break;
+
+ if (inProcessed == 0 && dicPos == state.dicPos)
+ {
+ res = SZ_ERROR_DATA;
+ break;
+ }
+
+ res = ILookInStream_Skip(inStream, inProcessed);
+ if (res != SZ_OK)
+ break;
+ }
+ }
+
+ LzmaDec_FreeProbs(&state, allocMain);
+ return res;
+}
+
+
+#ifndef Z7_NO_METHOD_LZMA2
+
+static SRes SzDecodeLzma2(const Byte *props, unsigned propsSize, UInt64 inSize, ILookInStreamPtr inStream,
+ Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain)
+{
+ CLzma2Dec state;
+ SRes res = SZ_OK;
+
+ Lzma2Dec_CONSTRUCT(&state)
+ if (propsSize != 1)
+ return SZ_ERROR_DATA;
+ RINOK(Lzma2Dec_AllocateProbs(&state, props[0], allocMain))
+ state.decoder.dic = outBuffer;
+ state.decoder.dicBufSize = outSize;
+ Lzma2Dec_Init(&state);
+
+ for (;;)
+ {
+ const void *inBuf = NULL;
+ size_t lookahead = (1 << 18);
+ if (lookahead > inSize)
+ lookahead = (size_t)inSize;
+ res = ILookInStream_Look(inStream, &inBuf, &lookahead);
+ if (res != SZ_OK)
+ break;
+
+ {
+ SizeT inProcessed = (SizeT)lookahead, dicPos = state.decoder.dicPos;
+ ELzmaStatus status;
+ res = Lzma2Dec_DecodeToDic(&state, outSize, (const Byte *)inBuf, &inProcessed, LZMA_FINISH_END, &status);
+ lookahead -= inProcessed;
+ inSize -= inProcessed;
+ if (res != SZ_OK)
+ break;
+
+ if (status == LZMA_STATUS_FINISHED_WITH_MARK)
+ {
+ if (outSize != state.decoder.dicPos || inSize != 0)
+ res = SZ_ERROR_DATA;
+ break;
+ }
+
+ if (inProcessed == 0 && dicPos == state.decoder.dicPos)
+ {
+ res = SZ_ERROR_DATA;
+ break;
+ }
+
+ res = ILookInStream_Skip(inStream, inProcessed);
+ if (res != SZ_OK)
+ break;
+ }
+ }
+
+ Lzma2Dec_FreeProbs(&state, allocMain);
+ return res;
+}
+
+#endif
+
+
+static SRes SzDecodeCopy(UInt64 inSize, ILookInStreamPtr inStream, Byte *outBuffer)
+{
+ while (inSize > 0)
+ {
+ const void *inBuf;
+ size_t curSize = (1 << 18);
+ if (curSize > inSize)
+ curSize = (size_t)inSize;
+ RINOK(ILookInStream_Look(inStream, &inBuf, &curSize))
+ if (curSize == 0)
+ return SZ_ERROR_INPUT_EOF;
+ memcpy(outBuffer, inBuf, curSize);
+ outBuffer += curSize;
+ inSize -= curSize;
+ RINOK(ILookInStream_Skip(inStream, curSize))
+ }
+ return SZ_OK;
+}
+
+static BoolInt IS_MAIN_METHOD(UInt32 m)
+{
+ switch (m)
+ {
+ case k_Copy:
+ case k_LZMA:
+ #ifndef Z7_NO_METHOD_LZMA2
+ case k_LZMA2:
+ #endif
+ #ifdef Z7_PPMD_SUPPORT
+ case k_PPMD:
+ #endif
+ return True;
+ }
+ return False;
+}
+
+static BoolInt IS_SUPPORTED_CODER(const CSzCoderInfo *c)
+{
+ return
+ c->NumStreams == 1
+ /* && c->MethodID <= (UInt32)0xFFFFFFFF */
+ && IS_MAIN_METHOD((UInt32)c->MethodID);
+}
+
+#define IS_BCJ2(c) ((c)->MethodID == k_BCJ2 && (c)->NumStreams == 4)
+
+static SRes CheckSupportedFolder(const CSzFolder *f)
+{
+ if (f->NumCoders < 1 || f->NumCoders > 4)
+ return SZ_ERROR_UNSUPPORTED;
+ if (!IS_SUPPORTED_CODER(&f->Coders[0]))
+ return SZ_ERROR_UNSUPPORTED;
+ if (f->NumCoders == 1)
+ {
+ if (f->NumPackStreams != 1 || f->PackStreams[0] != 0 || f->NumBonds != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ return SZ_OK;
+ }
+
+
+ #if defined(Z7_USE_BRANCH_FILTER)
+
+ if (f->NumCoders == 2)
+ {
+ const CSzCoderInfo *c = &f->Coders[1];
+ if (
+ /* c->MethodID > (UInt32)0xFFFFFFFF || */
+ c->NumStreams != 1
+ || f->NumPackStreams != 1
+ || f->PackStreams[0] != 0
+ || f->NumBonds != 1
+ || f->Bonds[0].InIndex != 1
+ || f->Bonds[0].OutIndex != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ switch ((UInt32)c->MethodID)
+ {
+ #if !defined(Z7_NO_METHODS_FILTERS)
+ case k_Delta:
+ case k_BCJ:
+ case k_PPC:
+ case k_IA64:
+ case k_SPARC:
+ case k_ARM:
+ #endif
+ #ifdef Z7_USE_FILTER_ARM64
+ case k_ARM64:
+ #endif
+ #ifdef Z7_USE_FILTER_ARMT
+ case k_ARMT:
+ #endif
+ break;
+ default:
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ return SZ_OK;
+ }
+
+ #endif
+
+
+ if (f->NumCoders == 4)
+ {
+ if (!IS_SUPPORTED_CODER(&f->Coders[1])
+ || !IS_SUPPORTED_CODER(&f->Coders[2])
+ || !IS_BCJ2(&f->Coders[3]))
+ return SZ_ERROR_UNSUPPORTED;
+ if (f->NumPackStreams != 4
+ || f->PackStreams[0] != 2
+ || f->PackStreams[1] != 6
+ || f->PackStreams[2] != 1
+ || f->PackStreams[3] != 0
+ || f->NumBonds != 3
+ || f->Bonds[0].InIndex != 5 || f->Bonds[0].OutIndex != 0
+ || f->Bonds[1].InIndex != 4 || f->Bonds[1].OutIndex != 1
+ || f->Bonds[2].InIndex != 3 || f->Bonds[2].OutIndex != 2)
+ return SZ_ERROR_UNSUPPORTED;
+ return SZ_OK;
+ }
+
+ return SZ_ERROR_UNSUPPORTED;
+}
+
+
+
+
+
+
+static SRes SzFolder_Decode2(const CSzFolder *folder,
+ const Byte *propsData,
+ const UInt64 *unpackSizes,
+ const UInt64 *packPositions,
+ ILookInStreamPtr inStream, UInt64 startPos,
+ Byte *outBuffer, SizeT outSize, ISzAllocPtr allocMain,
+ Byte *tempBuf[])
+{
+ UInt32 ci;
+ SizeT tempSizes[3] = { 0, 0, 0};
+ SizeT tempSize3 = 0;
+ Byte *tempBuf3 = 0;
+
+ RINOK(CheckSupportedFolder(folder))
+
+ for (ci = 0; ci < folder->NumCoders; ci++)
+ {
+ const CSzCoderInfo *coder = &folder->Coders[ci];
+
+ if (IS_MAIN_METHOD((UInt32)coder->MethodID))
+ {
+ UInt32 si = 0;
+ UInt64 offset;
+ UInt64 inSize;
+ Byte *outBufCur = outBuffer;
+ SizeT outSizeCur = outSize;
+ if (folder->NumCoders == 4)
+ {
+ const UInt32 indices[] = { 3, 2, 0 };
+ const UInt64 unpackSize = unpackSizes[ci];
+ si = indices[ci];
+ if (ci < 2)
+ {
+ Byte *temp;
+ outSizeCur = (SizeT)unpackSize;
+ if (outSizeCur != unpackSize)
+ return SZ_ERROR_MEM;
+ temp = (Byte *)ISzAlloc_Alloc(allocMain, outSizeCur);
+ if (!temp && outSizeCur != 0)
+ return SZ_ERROR_MEM;
+ outBufCur = tempBuf[1 - ci] = temp;
+ tempSizes[1 - ci] = outSizeCur;
+ }
+ else if (ci == 2)
+ {
+ if (unpackSize > outSize) /* check it */
+ return SZ_ERROR_PARAM;
+ tempBuf3 = outBufCur = outBuffer + (outSize - (size_t)unpackSize);
+ tempSize3 = outSizeCur = (SizeT)unpackSize;
+ }
+ else
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ offset = packPositions[si];
+ inSize = packPositions[(size_t)si + 1] - offset;
+ RINOK(LookInStream_SeekTo(inStream, startPos + offset))
+
+ if (coder->MethodID == k_Copy)
+ {
+ if (inSize != outSizeCur) /* check it */
+ return SZ_ERROR_DATA;
+ RINOK(SzDecodeCopy(inSize, inStream, outBufCur))
+ }
+ else if (coder->MethodID == k_LZMA)
+ {
+ RINOK(SzDecodeLzma(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain))
+ }
+ #ifndef Z7_NO_METHOD_LZMA2
+ else if (coder->MethodID == k_LZMA2)
+ {
+ RINOK(SzDecodeLzma2(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain))
+ }
+ #endif
+ #ifdef Z7_PPMD_SUPPORT
+ else if (coder->MethodID == k_PPMD)
+ {
+ RINOK(SzDecodePpmd(propsData + coder->PropsOffset, coder->PropsSize, inSize, inStream, outBufCur, outSizeCur, allocMain))
+ }
+ #endif
+ else
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ else if (coder->MethodID == k_BCJ2)
+ {
+ const UInt64 offset = packPositions[1];
+ const UInt64 s3Size = packPositions[2] - offset;
+
+ if (ci != 3)
+ return SZ_ERROR_UNSUPPORTED;
+
+ tempSizes[2] = (SizeT)s3Size;
+ if (tempSizes[2] != s3Size)
+ return SZ_ERROR_MEM;
+ tempBuf[2] = (Byte *)ISzAlloc_Alloc(allocMain, tempSizes[2]);
+ if (!tempBuf[2] && tempSizes[2] != 0)
+ return SZ_ERROR_MEM;
+
+ RINOK(LookInStream_SeekTo(inStream, startPos + offset))
+ RINOK(SzDecodeCopy(s3Size, inStream, tempBuf[2]))
+
+ if ((tempSizes[0] & 3) != 0 ||
+ (tempSizes[1] & 3) != 0 ||
+ tempSize3 + tempSizes[0] + tempSizes[1] != outSize)
+ return SZ_ERROR_DATA;
+
+ {
+ CBcj2Dec p;
+
+ p.bufs[0] = tempBuf3; p.lims[0] = tempBuf3 + tempSize3;
+ p.bufs[1] = tempBuf[0]; p.lims[1] = tempBuf[0] + tempSizes[0];
+ p.bufs[2] = tempBuf[1]; p.lims[2] = tempBuf[1] + tempSizes[1];
+ p.bufs[3] = tempBuf[2]; p.lims[3] = tempBuf[2] + tempSizes[2];
+
+ p.dest = outBuffer;
+ p.destLim = outBuffer + outSize;
+
+ Bcj2Dec_Init(&p);
+ RINOK(Bcj2Dec_Decode(&p))
+
+ {
+ unsigned i;
+ for (i = 0; i < 4; i++)
+ if (p.bufs[i] != p.lims[i])
+ return SZ_ERROR_DATA;
+ if (p.dest != p.destLim || !Bcj2Dec_IsMaybeFinished(&p))
+ return SZ_ERROR_DATA;
+ }
+ }
+ }
+ #if defined(Z7_USE_BRANCH_FILTER)
+ else if (ci == 1)
+ {
+ #if !defined(Z7_NO_METHODS_FILTERS)
+ if (coder->MethodID == k_Delta)
+ {
+ if (coder->PropsSize != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ {
+ Byte state[DELTA_STATE_SIZE];
+ Delta_Init(state);
+ Delta_Decode(state, (unsigned)(propsData[coder->PropsOffset]) + 1, outBuffer, outSize);
+ }
+ continue;
+ }
+ #endif
+
+ #ifdef Z7_USE_FILTER_ARM64
+ if (coder->MethodID == k_ARM64)
+ {
+ UInt32 pc = 0;
+ if (coder->PropsSize == 4)
+ pc = GetUi32(propsData + coder->PropsOffset);
+ else if (coder->PropsSize != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ z7_BranchConv_ARM64_Dec(outBuffer, outSize, pc);
+ continue;
+ }
+ #endif
+
+ #if !defined(Z7_NO_METHODS_FILTERS) || defined(Z7_USE_FILTER_ARMT)
+ {
+ if (coder->PropsSize != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ #define CASE_BRA_CONV(isa) case k_ ## isa: Z7_BRANCH_CONV_DEC(isa)(outBuffer, outSize, 0); break; // pc = 0;
+ switch (coder->MethodID)
+ {
+ #if !defined(Z7_NO_METHODS_FILTERS)
+ case k_BCJ:
+ {
+ UInt32 state = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL;
+ z7_BranchConvSt_X86_Dec(outBuffer, outSize, 0, &state); // pc = 0
+ break;
+ }
+ CASE_BRA_CONV(PPC)
+ CASE_BRA_CONV(IA64)
+ CASE_BRA_CONV(SPARC)
+ CASE_BRA_CONV(ARM)
+ #endif
+ #if !defined(Z7_NO_METHODS_FILTERS) || defined(Z7_USE_FILTER_ARMT)
+ CASE_BRA_CONV(ARMT)
+ #endif
+ default:
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ continue;
+ }
+ #endif
+ } // (c == 1)
+ #endif
+ else
+ return SZ_ERROR_UNSUPPORTED;
+ }
+
+ return SZ_OK;
+}
+
+
+SRes SzAr_DecodeFolder(const CSzAr *p, UInt32 folderIndex,
+ ILookInStreamPtr inStream, UInt64 startPos,
+ Byte *outBuffer, size_t outSize,
+ ISzAllocPtr allocMain)
+{
+ SRes res;
+ CSzFolder folder;
+ CSzData sd;
+
+ const Byte *data = p->CodersData + p->FoCodersOffsets[folderIndex];
+ sd.Data = data;
+ sd.Size = p->FoCodersOffsets[(size_t)folderIndex + 1] - p->FoCodersOffsets[folderIndex];
+
+ res = SzGetNextFolderItem(&folder, &sd);
+
+ if (res != SZ_OK)
+ return res;
+
+ if (sd.Size != 0
+ || folder.UnpackStream != p->FoToMainUnpackSizeIndex[folderIndex]
+ || outSize != SzAr_GetFolderUnpackSize(p, folderIndex))
+ return SZ_ERROR_FAIL;
+ {
+ unsigned i;
+ Byte *tempBuf[3] = { 0, 0, 0};
+
+ res = SzFolder_Decode2(&folder, data,
+ &p->CoderUnpackSizes[p->FoToCoderUnpackSizes[folderIndex]],
+ p->PackPositions + p->FoStartPackStreamIndex[folderIndex],
+ inStream, startPos,
+ outBuffer, (SizeT)outSize, allocMain, tempBuf);
+
+ for (i = 0; i < 3; i++)
+ ISzAlloc_Free(allocMain, tempBuf[i]);
+
+ if (res == SZ_OK)
+ if (SzBitWithVals_Check(&p->FolderCRCs, folderIndex))
+ if (CrcCalc(outBuffer, outSize) != p->FolderCRCs.Vals[folderIndex])
+ res = SZ_ERROR_CRC;
+
+ return res;
+ }
+}
diff --git a/C/7zFile.c b/C/7zFile.c
index e486901..ba5daa1 100644
--- a/C/7zFile.c
+++ b/C/7zFile.c
@@ -1,286 +1,443 @@
-/* 7zFile.c -- File IO
-2017-04-03 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "7zFile.h"
-
-#ifndef USE_WINDOWS_FILE
-
-#ifndef UNDER_CE
-#include <errno.h>
-#endif
-
-#else
-
-/*
- ReadFile and WriteFile functions in Windows have BUG:
- If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
- from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
- (Insufficient system resources exist to complete the requested service).
- Probably in some version of Windows there are problems with other sizes:
- for 32 MB (maybe also for 16 MB).
- And message can be "Network connection was lost"
-*/
-
-#define kChunkSizeMax (1 << 22)
-
-#endif
-
-void File_Construct(CSzFile *p)
-{
- #ifdef USE_WINDOWS_FILE
- p->handle = INVALID_HANDLE_VALUE;
- #else
- p->file = NULL;
- #endif
-}
-
-#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
-static WRes File_Open(CSzFile *p, const char *name, int writeMode)
-{
- #ifdef USE_WINDOWS_FILE
- p->handle = CreateFileA(name,
- writeMode ? GENERIC_WRITE : GENERIC_READ,
- FILE_SHARE_READ, NULL,
- writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, NULL);
- return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
- #else
- p->file = fopen(name, writeMode ? "wb+" : "rb");
- return (p->file != 0) ? 0 :
- #ifdef UNDER_CE
- 2; /* ENOENT */
- #else
- errno;
- #endif
- #endif
-}
-
-WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); }
-WRes OutFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 1); }
-#endif
-
-#ifdef USE_WINDOWS_FILE
-static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode)
-{
- p->handle = CreateFileW(name,
- writeMode ? GENERIC_WRITE : GENERIC_READ,
- FILE_SHARE_READ, NULL,
- writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL, NULL);
- return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
-}
-WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); }
-WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); }
-#endif
-
-WRes File_Close(CSzFile *p)
-{
- #ifdef USE_WINDOWS_FILE
- if (p->handle != INVALID_HANDLE_VALUE)
- {
- if (!CloseHandle(p->handle))
- return GetLastError();
- p->handle = INVALID_HANDLE_VALUE;
- }
- #else
- if (p->file != NULL)
- {
- int res = fclose(p->file);
- if (res != 0)
- return res;
- p->file = NULL;
- }
- #endif
- return 0;
-}
-
-WRes File_Read(CSzFile *p, void *data, size_t *size)
-{
- size_t originalSize = *size;
- if (originalSize == 0)
- return 0;
-
- #ifdef USE_WINDOWS_FILE
-
- *size = 0;
- do
- {
- DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
- DWORD processed = 0;
- BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL);
- data = (void *)((Byte *)data + processed);
- originalSize -= processed;
- *size += processed;
- if (!res)
- return GetLastError();
- if (processed == 0)
- break;
- }
- while (originalSize > 0);
- return 0;
-
- #else
-
- *size = fread(data, 1, originalSize, p->file);
- if (*size == originalSize)
- return 0;
- return ferror(p->file);
-
- #endif
-}
-
-WRes File_Write(CSzFile *p, const void *data, size_t *size)
-{
- size_t originalSize = *size;
- if (originalSize == 0)
- return 0;
-
- #ifdef USE_WINDOWS_FILE
-
- *size = 0;
- do
- {
- DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
- DWORD processed = 0;
- BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL);
- data = (void *)((Byte *)data + processed);
- originalSize -= processed;
- *size += processed;
- if (!res)
- return GetLastError();
- if (processed == 0)
- break;
- }
- while (originalSize > 0);
- return 0;
-
- #else
-
- *size = fwrite(data, 1, originalSize, p->file);
- if (*size == originalSize)
- return 0;
- return ferror(p->file);
-
- #endif
-}
-
-WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin)
-{
- #ifdef USE_WINDOWS_FILE
-
- LARGE_INTEGER value;
- DWORD moveMethod;
- value.LowPart = (DWORD)*pos;
- value.HighPart = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */
- switch (origin)
- {
- case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break;
- case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break;
- case SZ_SEEK_END: moveMethod = FILE_END; break;
- default: return ERROR_INVALID_PARAMETER;
- }
- value.LowPart = SetFilePointer(p->handle, value.LowPart, &value.HighPart, moveMethod);
- if (value.LowPart == 0xFFFFFFFF)
- {
- WRes res = GetLastError();
- if (res != NO_ERROR)
- return res;
- }
- *pos = ((Int64)value.HighPart << 32) | value.LowPart;
- return 0;
-
- #else
-
- int moveMethod;
- int res;
- switch (origin)
- {
- case SZ_SEEK_SET: moveMethod = SEEK_SET; break;
- case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break;
- case SZ_SEEK_END: moveMethod = SEEK_END; break;
- default: return 1;
- }
- res = fseek(p->file, (long)*pos, moveMethod);
- *pos = ftell(p->file);
- return res;
-
- #endif
-}
-
-WRes File_GetLength(CSzFile *p, UInt64 *length)
-{
- #ifdef USE_WINDOWS_FILE
-
- DWORD sizeHigh;
- DWORD sizeLow = GetFileSize(p->handle, &sizeHigh);
- if (sizeLow == 0xFFFFFFFF)
- {
- DWORD res = GetLastError();
- if (res != NO_ERROR)
- return res;
- }
- *length = (((UInt64)sizeHigh) << 32) + sizeLow;
- return 0;
-
- #else
-
- long pos = ftell(p->file);
- int res = fseek(p->file, 0, SEEK_END);
- *length = ftell(p->file);
- fseek(p->file, pos, SEEK_SET);
- return res;
-
- #endif
-}
-
-
-/* ---------- FileSeqInStream ---------- */
-
-static SRes FileSeqInStream_Read(const ISeqInStream *pp, void *buf, size_t *size)
-{
- CFileSeqInStream *p = CONTAINER_FROM_VTBL(pp, CFileSeqInStream, vt);
- return File_Read(&p->file, buf, size) == 0 ? SZ_OK : SZ_ERROR_READ;
-}
-
-void FileSeqInStream_CreateVTable(CFileSeqInStream *p)
-{
- p->vt.Read = FileSeqInStream_Read;
-}
-
-
-/* ---------- FileInStream ---------- */
-
-static SRes FileInStream_Read(const ISeekInStream *pp, void *buf, size_t *size)
-{
- CFileInStream *p = CONTAINER_FROM_VTBL(pp, CFileInStream, vt);
- return (File_Read(&p->file, buf, size) == 0) ? SZ_OK : SZ_ERROR_READ;
-}
-
-static SRes FileInStream_Seek(const ISeekInStream *pp, Int64 *pos, ESzSeek origin)
-{
- CFileInStream *p = CONTAINER_FROM_VTBL(pp, CFileInStream, vt);
- return File_Seek(&p->file, pos, origin);
-}
-
-void FileInStream_CreateVTable(CFileInStream *p)
-{
- p->vt.Read = FileInStream_Read;
- p->vt.Seek = FileInStream_Seek;
-}
-
-
-/* ---------- FileOutStream ---------- */
-
-static size_t FileOutStream_Write(const ISeqOutStream *pp, const void *data, size_t size)
-{
- CFileOutStream *p = CONTAINER_FROM_VTBL(pp, CFileOutStream, vt);
- File_Write(&p->file, data, &size);
- return size;
-}
-
-void FileOutStream_CreateVTable(CFileOutStream *p)
-{
- p->vt.Write = FileOutStream_Write;
-}
+/* 7zFile.c -- File IO
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "7zFile.h"
+
+#ifndef USE_WINDOWS_FILE
+
+ #include <errno.h>
+
+ #ifndef USE_FOPEN
+ #include <stdio.h>
+ #include <fcntl.h>
+ #ifdef _WIN32
+ #include <io.h>
+ typedef int ssize_t;
+ typedef int off_t;
+ #else
+ #include <unistd.h>
+ #endif
+ #endif
+
+#else
+
+/*
+ ReadFile and WriteFile functions in Windows have BUG:
+ If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
+ from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
+ (Insufficient system resources exist to complete the requested service).
+ Probably in some version of Windows there are problems with other sizes:
+ for 32 MB (maybe also for 16 MB).
+ And message can be "Network connection was lost"
+*/
+
+#endif
+
+#define kChunkSizeMax (1 << 22)
+
+void File_Construct(CSzFile *p)
+{
+ #ifdef USE_WINDOWS_FILE
+ p->handle = INVALID_HANDLE_VALUE;
+ #elif defined(USE_FOPEN)
+ p->file = NULL;
+ #else
+ p->fd = -1;
+ #endif
+}
+
+#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
+
+static WRes File_Open(CSzFile *p, const char *name, int writeMode)
+{
+ #ifdef USE_WINDOWS_FILE
+
+ p->handle = CreateFileA(name,
+ writeMode ? GENERIC_WRITE : GENERIC_READ,
+ FILE_SHARE_READ, NULL,
+ writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
+
+ #elif defined(USE_FOPEN)
+
+ p->file = fopen(name, writeMode ? "wb+" : "rb");
+ return (p->file != 0) ? 0 :
+ #ifdef UNDER_CE
+ 2; /* ENOENT */
+ #else
+ errno;
+ #endif
+
+ #else
+
+ int flags = (writeMode ? (O_CREAT | O_EXCL | O_WRONLY) : O_RDONLY);
+ #ifdef O_BINARY
+ flags |= O_BINARY;
+ #endif
+ p->fd = open(name, flags, 0666);
+ return (p->fd != -1) ? 0 : errno;
+
+ #endif
+}
+
+WRes InFile_Open(CSzFile *p, const char *name) { return File_Open(p, name, 0); }
+
+WRes OutFile_Open(CSzFile *p, const char *name)
+{
+ #if defined(USE_WINDOWS_FILE) || defined(USE_FOPEN)
+ return File_Open(p, name, 1);
+ #else
+ p->fd = creat(name, 0666);
+ return (p->fd != -1) ? 0 : errno;
+ #endif
+}
+
+#endif
+
+
+#ifdef USE_WINDOWS_FILE
+static WRes File_OpenW(CSzFile *p, const WCHAR *name, int writeMode)
+{
+ p->handle = CreateFileW(name,
+ writeMode ? GENERIC_WRITE : GENERIC_READ,
+ FILE_SHARE_READ, NULL,
+ writeMode ? CREATE_ALWAYS : OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, NULL);
+ return (p->handle != INVALID_HANDLE_VALUE) ? 0 : GetLastError();
+}
+WRes InFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 0); }
+WRes OutFile_OpenW(CSzFile *p, const WCHAR *name) { return File_OpenW(p, name, 1); }
+#endif
+
+WRes File_Close(CSzFile *p)
+{
+ #ifdef USE_WINDOWS_FILE
+
+ if (p->handle != INVALID_HANDLE_VALUE)
+ {
+ if (!CloseHandle(p->handle))
+ return GetLastError();
+ p->handle = INVALID_HANDLE_VALUE;
+ }
+
+ #elif defined(USE_FOPEN)
+
+ if (p->file != NULL)
+ {
+ int res = fclose(p->file);
+ if (res != 0)
+ {
+ if (res == EOF)
+ return errno;
+ return res;
+ }
+ p->file = NULL;
+ }
+
+ #else
+
+ if (p->fd != -1)
+ {
+ if (close(p->fd) != 0)
+ return errno;
+ p->fd = -1;
+ }
+
+ #endif
+
+ return 0;
+}
+
+
+WRes File_Read(CSzFile *p, void *data, size_t *size)
+{
+ size_t originalSize = *size;
+ *size = 0;
+ if (originalSize == 0)
+ return 0;
+
+ #ifdef USE_WINDOWS_FILE
+
+ do
+ {
+ const DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
+ DWORD processed = 0;
+ const BOOL res = ReadFile(p->handle, data, curSize, &processed, NULL);
+ data = (void *)((Byte *)data + processed);
+ originalSize -= processed;
+ *size += processed;
+ if (!res)
+ return GetLastError();
+ // debug : we can break here for partial reading mode
+ if (processed == 0)
+ break;
+ }
+ while (originalSize > 0);
+
+ #elif defined(USE_FOPEN)
+
+ do
+ {
+ const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
+ const size_t processed = fread(data, 1, curSize, p->file);
+ data = (void *)((Byte *)data + (size_t)processed);
+ originalSize -= processed;
+ *size += processed;
+ if (processed != curSize)
+ return ferror(p->file);
+ // debug : we can break here for partial reading mode
+ if (processed == 0)
+ break;
+ }
+ while (originalSize > 0);
+
+ #else
+
+ do
+ {
+ const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
+ const ssize_t processed = read(p->fd, data, curSize);
+ if (processed == -1)
+ return errno;
+ if (processed == 0)
+ break;
+ data = (void *)((Byte *)data + (size_t)processed);
+ originalSize -= (size_t)processed;
+ *size += (size_t)processed;
+ // debug : we can break here for partial reading mode
+ // break;
+ }
+ while (originalSize > 0);
+
+ #endif
+
+ return 0;
+}
+
+
+WRes File_Write(CSzFile *p, const void *data, size_t *size)
+{
+ size_t originalSize = *size;
+ *size = 0;
+ if (originalSize == 0)
+ return 0;
+
+ #ifdef USE_WINDOWS_FILE
+
+ do
+ {
+ const DWORD curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : (DWORD)originalSize;
+ DWORD processed = 0;
+ const BOOL res = WriteFile(p->handle, data, curSize, &processed, NULL);
+ data = (const void *)((const Byte *)data + processed);
+ originalSize -= processed;
+ *size += processed;
+ if (!res)
+ return GetLastError();
+ if (processed == 0)
+ break;
+ }
+ while (originalSize > 0);
+
+ #elif defined(USE_FOPEN)
+
+ do
+ {
+ const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
+ const size_t processed = fwrite(data, 1, curSize, p->file);
+ data = (void *)((Byte *)data + (size_t)processed);
+ originalSize -= processed;
+ *size += processed;
+ if (processed != curSize)
+ return ferror(p->file);
+ if (processed == 0)
+ break;
+ }
+ while (originalSize > 0);
+
+ #else
+
+ do
+ {
+ const size_t curSize = (originalSize > kChunkSizeMax) ? kChunkSizeMax : originalSize;
+ const ssize_t processed = write(p->fd, data, curSize);
+ if (processed == -1)
+ return errno;
+ if (processed == 0)
+ break;
+ data = (const void *)((const Byte *)data + (size_t)processed);
+ originalSize -= (size_t)processed;
+ *size += (size_t)processed;
+ }
+ while (originalSize > 0);
+
+ #endif
+
+ return 0;
+}
+
+
+WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin)
+{
+ #ifdef USE_WINDOWS_FILE
+
+ DWORD moveMethod;
+ UInt32 low = (UInt32)*pos;
+ LONG high = (LONG)((UInt64)*pos >> 16 >> 16); /* for case when UInt64 is 32-bit only */
+ // (int) to eliminate clang warning
+ switch ((int)origin)
+ {
+ case SZ_SEEK_SET: moveMethod = FILE_BEGIN; break;
+ case SZ_SEEK_CUR: moveMethod = FILE_CURRENT; break;
+ case SZ_SEEK_END: moveMethod = FILE_END; break;
+ default: return ERROR_INVALID_PARAMETER;
+ }
+ low = SetFilePointer(p->handle, (LONG)low, &high, moveMethod);
+ if (low == (UInt32)0xFFFFFFFF)
+ {
+ WRes res = GetLastError();
+ if (res != NO_ERROR)
+ return res;
+ }
+ *pos = ((Int64)high << 32) | low;
+ return 0;
+
+ #else
+
+ int moveMethod; // = origin;
+
+ switch ((int)origin)
+ {
+ case SZ_SEEK_SET: moveMethod = SEEK_SET; break;
+ case SZ_SEEK_CUR: moveMethod = SEEK_CUR; break;
+ case SZ_SEEK_END: moveMethod = SEEK_END; break;
+ default: return EINVAL;
+ }
+
+ #if defined(USE_FOPEN)
+ {
+ int res = fseek(p->file, (long)*pos, moveMethod);
+ if (res == -1)
+ return errno;
+ *pos = ftell(p->file);
+ if (*pos == -1)
+ return errno;
+ return 0;
+ }
+ #else
+ {
+ off_t res = lseek(p->fd, (off_t)*pos, moveMethod);
+ if (res == -1)
+ return errno;
+ *pos = res;
+ return 0;
+ }
+
+ #endif // USE_FOPEN
+ #endif // USE_WINDOWS_FILE
+}
+
+
+WRes File_GetLength(CSzFile *p, UInt64 *length)
+{
+ #ifdef USE_WINDOWS_FILE
+
+ DWORD sizeHigh;
+ DWORD sizeLow = GetFileSize(p->handle, &sizeHigh);
+ if (sizeLow == 0xFFFFFFFF)
+ {
+ DWORD res = GetLastError();
+ if (res != NO_ERROR)
+ return res;
+ }
+ *length = (((UInt64)sizeHigh) << 32) + sizeLow;
+ return 0;
+
+ #elif defined(USE_FOPEN)
+
+ long pos = ftell(p->file);
+ int res = fseek(p->file, 0, SEEK_END);
+ *length = ftell(p->file);
+ fseek(p->file, pos, SEEK_SET);
+ return res;
+
+ #else
+
+ off_t pos;
+ *length = 0;
+ pos = lseek(p->fd, 0, SEEK_CUR);
+ if (pos != -1)
+ {
+ const off_t len2 = lseek(p->fd, 0, SEEK_END);
+ const off_t res2 = lseek(p->fd, pos, SEEK_SET);
+ if (len2 != -1)
+ {
+ *length = (UInt64)len2;
+ if (res2 != -1)
+ return 0;
+ }
+ }
+ return errno;
+
+ #endif
+}
+
+
+/* ---------- FileSeqInStream ---------- */
+
+static SRes FileSeqInStream_Read(ISeqInStreamPtr pp, void *buf, size_t *size)
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileSeqInStream)
+ const WRes wres = File_Read(&p->file, buf, size);
+ p->wres = wres;
+ return (wres == 0) ? SZ_OK : SZ_ERROR_READ;
+}
+
+void FileSeqInStream_CreateVTable(CFileSeqInStream *p)
+{
+ p->vt.Read = FileSeqInStream_Read;
+}
+
+
+/* ---------- FileInStream ---------- */
+
+static SRes FileInStream_Read(ISeekInStreamPtr pp, void *buf, size_t *size)
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileInStream)
+ const WRes wres = File_Read(&p->file, buf, size);
+ p->wres = wres;
+ return (wres == 0) ? SZ_OK : SZ_ERROR_READ;
+}
+
+static SRes FileInStream_Seek(ISeekInStreamPtr pp, Int64 *pos, ESzSeek origin)
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileInStream)
+ const WRes wres = File_Seek(&p->file, pos, origin);
+ p->wres = wres;
+ return (wres == 0) ? SZ_OK : SZ_ERROR_READ;
+}
+
+void FileInStream_CreateVTable(CFileInStream *p)
+{
+ p->vt.Read = FileInStream_Read;
+ p->vt.Seek = FileInStream_Seek;
+}
+
+
+/* ---------- FileOutStream ---------- */
+
+static size_t FileOutStream_Write(ISeqOutStreamPtr pp, const void *data, size_t size)
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CFileOutStream)
+ const WRes wres = File_Write(&p->file, data, &size);
+ p->wres = wres;
+ return size;
+}
+
+void FileOutStream_CreateVTable(CFileOutStream *p)
+{
+ p->vt.Write = FileOutStream_Write;
+}
diff --git a/C/7zFile.h b/C/7zFile.h
index 7e263be..f5069cd 100644
--- a/C/7zFile.h
+++ b/C/7zFile.h
@@ -1,83 +1,92 @@
-/* 7zFile.h -- File IO
-2017-04-03 : Igor Pavlov : Public domain */
-
-#ifndef __7Z_FILE_H
-#define __7Z_FILE_H
-
-#ifdef _WIN32
-#define USE_WINDOWS_FILE
-#endif
-
-#ifdef USE_WINDOWS_FILE
-#include <windows.h>
-#else
-#include <stdio.h>
-#endif
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-/* ---------- File ---------- */
-
-typedef struct
-{
- #ifdef USE_WINDOWS_FILE
- HANDLE handle;
- #else
- FILE *file;
- #endif
-} CSzFile;
-
-void File_Construct(CSzFile *p);
-#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
-WRes InFile_Open(CSzFile *p, const char *name);
-WRes OutFile_Open(CSzFile *p, const char *name);
-#endif
-#ifdef USE_WINDOWS_FILE
-WRes InFile_OpenW(CSzFile *p, const WCHAR *name);
-WRes OutFile_OpenW(CSzFile *p, const WCHAR *name);
-#endif
-WRes File_Close(CSzFile *p);
-
-/* reads max(*size, remain file's size) bytes */
-WRes File_Read(CSzFile *p, void *data, size_t *size);
-
-/* writes *size bytes */
-WRes File_Write(CSzFile *p, const void *data, size_t *size);
-
-WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin);
-WRes File_GetLength(CSzFile *p, UInt64 *length);
-
-
-/* ---------- FileInStream ---------- */
-
-typedef struct
-{
- ISeqInStream vt;
- CSzFile file;
-} CFileSeqInStream;
-
-void FileSeqInStream_CreateVTable(CFileSeqInStream *p);
-
-
-typedef struct
-{
- ISeekInStream vt;
- CSzFile file;
-} CFileInStream;
-
-void FileInStream_CreateVTable(CFileInStream *p);
-
-
-typedef struct
-{
- ISeqOutStream vt;
- CSzFile file;
-} CFileOutStream;
-
-void FileOutStream_CreateVTable(CFileOutStream *p);
-
-EXTERN_C_END
-
-#endif
+/* 7zFile.h -- File IO
+2023-03-05 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_FILE_H
+#define ZIP7_INC_FILE_H
+
+#ifdef _WIN32
+#define USE_WINDOWS_FILE
+// #include <windows.h>
+#endif
+
+#ifdef USE_WINDOWS_FILE
+#include "7zWindows.h"
+
+#else
+// note: USE_FOPEN mode is limited to 32-bit file size
+// #define USE_FOPEN
+// #include <stdio.h>
+#endif
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/* ---------- File ---------- */
+
+typedef struct
+{
+ #ifdef USE_WINDOWS_FILE
+ HANDLE handle;
+ #elif defined(USE_FOPEN)
+ FILE *file;
+ #else
+ int fd;
+ #endif
+} CSzFile;
+
+void File_Construct(CSzFile *p);
+#if !defined(UNDER_CE) || !defined(USE_WINDOWS_FILE)
+WRes InFile_Open(CSzFile *p, const char *name);
+WRes OutFile_Open(CSzFile *p, const char *name);
+#endif
+#ifdef USE_WINDOWS_FILE
+WRes InFile_OpenW(CSzFile *p, const WCHAR *name);
+WRes OutFile_OpenW(CSzFile *p, const WCHAR *name);
+#endif
+WRes File_Close(CSzFile *p);
+
+/* reads max(*size, remain file's size) bytes */
+WRes File_Read(CSzFile *p, void *data, size_t *size);
+
+/* writes *size bytes */
+WRes File_Write(CSzFile *p, const void *data, size_t *size);
+
+WRes File_Seek(CSzFile *p, Int64 *pos, ESzSeek origin);
+WRes File_GetLength(CSzFile *p, UInt64 *length);
+
+
+/* ---------- FileInStream ---------- */
+
+typedef struct
+{
+ ISeqInStream vt;
+ CSzFile file;
+ WRes wres;
+} CFileSeqInStream;
+
+void FileSeqInStream_CreateVTable(CFileSeqInStream *p);
+
+
+typedef struct
+{
+ ISeekInStream vt;
+ CSzFile file;
+ WRes wres;
+} CFileInStream;
+
+void FileInStream_CreateVTable(CFileInStream *p);
+
+
+typedef struct
+{
+ ISeqOutStream vt;
+ CSzFile file;
+ WRes wres;
+} CFileOutStream;
+
+void FileOutStream_CreateVTable(CFileOutStream *p);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/7zStream.c b/C/7zStream.c
index 579741f..74e75b6 100644
--- a/C/7zStream.c
+++ b/C/7zStream.c
@@ -1,176 +1,199 @@
-/* 7zStream.c -- 7z Stream functions
-2017-04-03 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include <string.h>
-
-#include "7zTypes.h"
-
-SRes SeqInStream_Read2(const ISeqInStream *stream, void *buf, size_t size, SRes errorType)
-{
- while (size != 0)
- {
- size_t processed = size;
- RINOK(ISeqInStream_Read(stream, buf, &processed));
- if (processed == 0)
- return errorType;
- buf = (void *)((Byte *)buf + processed);
- size -= processed;
- }
- return SZ_OK;
-}
-
-SRes SeqInStream_Read(const ISeqInStream *stream, void *buf, size_t size)
-{
- return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
-}
-
-SRes SeqInStream_ReadByte(const ISeqInStream *stream, Byte *buf)
-{
- size_t processed = 1;
- RINOK(ISeqInStream_Read(stream, buf, &processed));
- return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF;
-}
-
-
-
-SRes LookInStream_SeekTo(const ILookInStream *stream, UInt64 offset)
-{
- Int64 t = offset;
- return ILookInStream_Seek(stream, &t, SZ_SEEK_SET);
-}
-
-SRes LookInStream_LookRead(const ILookInStream *stream, void *buf, size_t *size)
-{
- const void *lookBuf;
- if (*size == 0)
- return SZ_OK;
- RINOK(ILookInStream_Look(stream, &lookBuf, size));
- memcpy(buf, lookBuf, *size);
- return ILookInStream_Skip(stream, *size);
-}
-
-SRes LookInStream_Read2(const ILookInStream *stream, void *buf, size_t size, SRes errorType)
-{
- while (size != 0)
- {
- size_t processed = size;
- RINOK(ILookInStream_Read(stream, buf, &processed));
- if (processed == 0)
- return errorType;
- buf = (void *)((Byte *)buf + processed);
- size -= processed;
- }
- return SZ_OK;
-}
-
-SRes LookInStream_Read(const ILookInStream *stream, void *buf, size_t size)
-{
- return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
-}
-
-
-
-#define GET_LookToRead2 CLookToRead2 *p = CONTAINER_FROM_VTBL(pp, CLookToRead2, vt);
-
-static SRes LookToRead2_Look_Lookahead(const ILookInStream *pp, const void **buf, size_t *size)
-{
- SRes res = SZ_OK;
- GET_LookToRead2
- size_t size2 = p->size - p->pos;
- if (size2 == 0 && *size != 0)
- {
- p->pos = 0;
- p->size = 0;
- size2 = p->bufSize;
- res = ISeekInStream_Read(p->realStream, p->buf, &size2);
- p->size = size2;
- }
- if (*size > size2)
- *size = size2;
- *buf = p->buf + p->pos;
- return res;
-}
-
-static SRes LookToRead2_Look_Exact(const ILookInStream *pp, const void **buf, size_t *size)
-{
- SRes res = SZ_OK;
- GET_LookToRead2
- size_t size2 = p->size - p->pos;
- if (size2 == 0 && *size != 0)
- {
- p->pos = 0;
- p->size = 0;
- if (*size > p->bufSize)
- *size = p->bufSize;
- res = ISeekInStream_Read(p->realStream, p->buf, size);
- size2 = p->size = *size;
- }
- if (*size > size2)
- *size = size2;
- *buf = p->buf + p->pos;
- return res;
-}
-
-static SRes LookToRead2_Skip(const ILookInStream *pp, size_t offset)
-{
- GET_LookToRead2
- p->pos += offset;
- return SZ_OK;
-}
-
-static SRes LookToRead2_Read(const ILookInStream *pp, void *buf, size_t *size)
-{
- GET_LookToRead2
- size_t rem = p->size - p->pos;
- if (rem == 0)
- return ISeekInStream_Read(p->realStream, buf, size);
- if (rem > *size)
- rem = *size;
- memcpy(buf, p->buf + p->pos, rem);
- p->pos += rem;
- *size = rem;
- return SZ_OK;
-}
-
-static SRes LookToRead2_Seek(const ILookInStream *pp, Int64 *pos, ESzSeek origin)
-{
- GET_LookToRead2
- p->pos = p->size = 0;
- return ISeekInStream_Seek(p->realStream, pos, origin);
-}
-
-void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead)
-{
- p->vt.Look = lookahead ?
- LookToRead2_Look_Lookahead :
- LookToRead2_Look_Exact;
- p->vt.Skip = LookToRead2_Skip;
- p->vt.Read = LookToRead2_Read;
- p->vt.Seek = LookToRead2_Seek;
-}
-
-
-
-static SRes SecToLook_Read(const ISeqInStream *pp, void *buf, size_t *size)
-{
- CSecToLook *p = CONTAINER_FROM_VTBL(pp, CSecToLook, vt);
- return LookInStream_LookRead(p->realStream, buf, size);
-}
-
-void SecToLook_CreateVTable(CSecToLook *p)
-{
- p->vt.Read = SecToLook_Read;
-}
-
-static SRes SecToRead_Read(const ISeqInStream *pp, void *buf, size_t *size)
-{
- CSecToRead *p = CONTAINER_FROM_VTBL(pp, CSecToRead, vt);
- return ILookInStream_Read(p->realStream, buf, size);
-}
-
-void SecToRead_CreateVTable(CSecToRead *p)
-{
- p->vt.Read = SecToRead_Read;
-}
+/* 7zStream.c -- 7z Stream functions
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#include "7zTypes.h"
+
+
+SRes SeqInStream_ReadMax(ISeqInStreamPtr stream, void *buf, size_t *processedSize)
+{
+ size_t size = *processedSize;
+ *processedSize = 0;
+ while (size != 0)
+ {
+ size_t cur = size;
+ const SRes res = ISeqInStream_Read(stream, buf, &cur);
+ *processedSize += cur;
+ buf = (void *)((Byte *)buf + cur);
+ size -= cur;
+ if (res != SZ_OK)
+ return res;
+ if (cur == 0)
+ return SZ_OK;
+ }
+ return SZ_OK;
+}
+
+/*
+SRes SeqInStream_Read2(ISeqInStreamPtr stream, void *buf, size_t size, SRes errorType)
+{
+ while (size != 0)
+ {
+ size_t processed = size;
+ RINOK(ISeqInStream_Read(stream, buf, &processed))
+ if (processed == 0)
+ return errorType;
+ buf = (void *)((Byte *)buf + processed);
+ size -= processed;
+ }
+ return SZ_OK;
+}
+
+SRes SeqInStream_Read(ISeqInStreamPtr stream, void *buf, size_t size)
+{
+ return SeqInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
+}
+*/
+
+
+SRes SeqInStream_ReadByte(ISeqInStreamPtr stream, Byte *buf)
+{
+ size_t processed = 1;
+ RINOK(ISeqInStream_Read(stream, buf, &processed))
+ return (processed == 1) ? SZ_OK : SZ_ERROR_INPUT_EOF;
+}
+
+
+
+SRes LookInStream_SeekTo(ILookInStreamPtr stream, UInt64 offset)
+{
+ Int64 t = (Int64)offset;
+ return ILookInStream_Seek(stream, &t, SZ_SEEK_SET);
+}
+
+SRes LookInStream_LookRead(ILookInStreamPtr stream, void *buf, size_t *size)
+{
+ const void *lookBuf;
+ if (*size == 0)
+ return SZ_OK;
+ RINOK(ILookInStream_Look(stream, &lookBuf, size))
+ memcpy(buf, lookBuf, *size);
+ return ILookInStream_Skip(stream, *size);
+}
+
+SRes LookInStream_Read2(ILookInStreamPtr stream, void *buf, size_t size, SRes errorType)
+{
+ while (size != 0)
+ {
+ size_t processed = size;
+ RINOK(ILookInStream_Read(stream, buf, &processed))
+ if (processed == 0)
+ return errorType;
+ buf = (void *)((Byte *)buf + processed);
+ size -= processed;
+ }
+ return SZ_OK;
+}
+
+SRes LookInStream_Read(ILookInStreamPtr stream, void *buf, size_t size)
+{
+ return LookInStream_Read2(stream, buf, size, SZ_ERROR_INPUT_EOF);
+}
+
+
+
+#define GET_LookToRead2 Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CLookToRead2)
+
+static SRes LookToRead2_Look_Lookahead(ILookInStreamPtr pp, const void **buf, size_t *size)
+{
+ SRes res = SZ_OK;
+ GET_LookToRead2
+ size_t size2 = p->size - p->pos;
+ if (size2 == 0 && *size != 0)
+ {
+ p->pos = 0;
+ p->size = 0;
+ size2 = p->bufSize;
+ res = ISeekInStream_Read(p->realStream, p->buf, &size2);
+ p->size = size2;
+ }
+ if (*size > size2)
+ *size = size2;
+ *buf = p->buf + p->pos;
+ return res;
+}
+
+static SRes LookToRead2_Look_Exact(ILookInStreamPtr pp, const void **buf, size_t *size)
+{
+ SRes res = SZ_OK;
+ GET_LookToRead2
+ size_t size2 = p->size - p->pos;
+ if (size2 == 0 && *size != 0)
+ {
+ p->pos = 0;
+ p->size = 0;
+ if (*size > p->bufSize)
+ *size = p->bufSize;
+ res = ISeekInStream_Read(p->realStream, p->buf, size);
+ size2 = p->size = *size;
+ }
+ if (*size > size2)
+ *size = size2;
+ *buf = p->buf + p->pos;
+ return res;
+}
+
+static SRes LookToRead2_Skip(ILookInStreamPtr pp, size_t offset)
+{
+ GET_LookToRead2
+ p->pos += offset;
+ return SZ_OK;
+}
+
+static SRes LookToRead2_Read(ILookInStreamPtr pp, void *buf, size_t *size)
+{
+ GET_LookToRead2
+ size_t rem = p->size - p->pos;
+ if (rem == 0)
+ return ISeekInStream_Read(p->realStream, buf, size);
+ if (rem > *size)
+ rem = *size;
+ memcpy(buf, p->buf + p->pos, rem);
+ p->pos += rem;
+ *size = rem;
+ return SZ_OK;
+}
+
+static SRes LookToRead2_Seek(ILookInStreamPtr pp, Int64 *pos, ESzSeek origin)
+{
+ GET_LookToRead2
+ p->pos = p->size = 0;
+ return ISeekInStream_Seek(p->realStream, pos, origin);
+}
+
+void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead)
+{
+ p->vt.Look = lookahead ?
+ LookToRead2_Look_Lookahead :
+ LookToRead2_Look_Exact;
+ p->vt.Skip = LookToRead2_Skip;
+ p->vt.Read = LookToRead2_Read;
+ p->vt.Seek = LookToRead2_Seek;
+}
+
+
+
+static SRes SecToLook_Read(ISeqInStreamPtr pp, void *buf, size_t *size)
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSecToLook)
+ return LookInStream_LookRead(p->realStream, buf, size);
+}
+
+void SecToLook_CreateVTable(CSecToLook *p)
+{
+ p->vt.Read = SecToLook_Read;
+}
+
+static SRes SecToRead_Read(ISeqInStreamPtr pp, void *buf, size_t *size)
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSecToRead)
+ return ILookInStream_Read(p->realStream, buf, size);
+}
+
+void SecToRead_CreateVTable(CSecToRead *p)
+{
+ p->vt.Read = SecToRead_Read;
+}
diff --git a/C/7zTypes.h b/C/7zTypes.h
index 593f5aa..1fcb247 100644
--- a/C/7zTypes.h
+++ b/C/7zTypes.h
@@ -1,375 +1,597 @@
-/* 7zTypes.h -- Basic types
-2018-08-04 : Igor Pavlov : Public domain */
-
-#ifndef __7Z_TYPES_H
-#define __7Z_TYPES_H
-
-#ifdef _WIN32
-/* #include <windows.h> */
-#endif
-
-#include <stddef.h>
-
-#ifndef EXTERN_C_BEGIN
-#ifdef __cplusplus
-#define EXTERN_C_BEGIN extern "C" {
-#define EXTERN_C_END }
-#else
-#define EXTERN_C_BEGIN
-#define EXTERN_C_END
-#endif
-#endif
-
-EXTERN_C_BEGIN
-
-#define SZ_OK 0
-
-#define SZ_ERROR_DATA 1
-#define SZ_ERROR_MEM 2
-#define SZ_ERROR_CRC 3
-#define SZ_ERROR_UNSUPPORTED 4
-#define SZ_ERROR_PARAM 5
-#define SZ_ERROR_INPUT_EOF 6
-#define SZ_ERROR_OUTPUT_EOF 7
-#define SZ_ERROR_READ 8
-#define SZ_ERROR_WRITE 9
-#define SZ_ERROR_PROGRESS 10
-#define SZ_ERROR_FAIL 11
-#define SZ_ERROR_THREAD 12
-
-#define SZ_ERROR_ARCHIVE 16
-#define SZ_ERROR_NO_ARCHIVE 17
-
-typedef int SRes;
-
-
-#ifdef _WIN32
-
-/* typedef DWORD WRes; */
-typedef unsigned WRes;
-#define MY_SRes_HRESULT_FROM_WRes(x) HRESULT_FROM_WIN32(x)
-
-#else
-
-typedef int WRes;
-#define MY__FACILITY_WIN32 7
-#define MY__FACILITY__WRes MY__FACILITY_WIN32
-#define MY_SRes_HRESULT_FROM_WRes(x) ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : ((HRESULT) (((x) & 0x0000FFFF) | (MY__FACILITY__WRes << 16) | 0x80000000)))
-
-#endif
-
-
-#ifndef RINOK
-#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
-#endif
-
-typedef unsigned char Byte;
-typedef short Int16;
-typedef unsigned short UInt16;
-
-#ifdef _LZMA_UINT32_IS_ULONG
-typedef long Int32;
-typedef unsigned long UInt32;
-#else
-typedef int Int32;
-typedef unsigned int UInt32;
-#endif
-
-#ifdef _SZ_NO_INT_64
-
-/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
- NOTES: Some code will work incorrectly in that case! */
-
-typedef long Int64;
-typedef unsigned long UInt64;
-
-#else
-
-#if defined(_MSC_VER) || defined(__BORLANDC__)
-typedef __int64 Int64;
-typedef unsigned __int64 UInt64;
-#define UINT64_CONST(n) n
-#else
-typedef long long int Int64;
-typedef unsigned long long int UInt64;
-#define UINT64_CONST(n) n ## ULL
-#endif
-
-#endif
-
-#ifdef _LZMA_NO_SYSTEM_SIZE_T
-typedef UInt32 SizeT;
-#else
-typedef size_t SizeT;
-#endif
-
-typedef int BoolInt;
-/* typedef BoolInt Bool; */
-#define True 1
-#define False 0
-
-
-#ifdef _WIN32
-#define MY_STD_CALL __stdcall
-#else
-#define MY_STD_CALL
-#endif
-
-#ifdef _MSC_VER
-
-#if _MSC_VER >= 1300
-#define MY_NO_INLINE __declspec(noinline)
-#else
-#define MY_NO_INLINE
-#endif
-
-#define MY_FORCE_INLINE __forceinline
-
-#define MY_CDECL __cdecl
-#define MY_FAST_CALL __fastcall
-
-#else
-
-#define MY_NO_INLINE
-#define MY_FORCE_INLINE
-#define MY_CDECL
-#define MY_FAST_CALL
-
-/* inline keyword : for C++ / C99 */
-
-/* GCC, clang: */
-/*
-#if defined (__GNUC__) && (__GNUC__ >= 4)
-#define MY_FORCE_INLINE __attribute__((always_inline))
-#define MY_NO_INLINE __attribute__((noinline))
-#endif
-*/
-
-#endif
-
-
-/* The following interfaces use first parameter as pointer to structure */
-
-typedef struct IByteIn IByteIn;
-struct IByteIn
-{
- Byte (*Read)(const IByteIn *p); /* reads one byte, returns 0 in case of EOF or error */
-};
-#define IByteIn_Read(p) (p)->Read(p)
-
-
-typedef struct IByteOut IByteOut;
-struct IByteOut
-{
- void (*Write)(const IByteOut *p, Byte b);
-};
-#define IByteOut_Write(p, b) (p)->Write(p, b)
-
-
-typedef struct ISeqInStream ISeqInStream;
-struct ISeqInStream
-{
- SRes (*Read)(const ISeqInStream *p, void *buf, size_t *size);
- /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
- (output(*size) < input(*size)) is allowed */
-};
-#define ISeqInStream_Read(p, buf, size) (p)->Read(p, buf, size)
-
-/* it can return SZ_ERROR_INPUT_EOF */
-SRes SeqInStream_Read(const ISeqInStream *stream, void *buf, size_t size);
-SRes SeqInStream_Read2(const ISeqInStream *stream, void *buf, size_t size, SRes errorType);
-SRes SeqInStream_ReadByte(const ISeqInStream *stream, Byte *buf);
-
-
-typedef struct ISeqOutStream ISeqOutStream;
-struct ISeqOutStream
-{
- size_t (*Write)(const ISeqOutStream *p, const void *buf, size_t size);
- /* Returns: result - the number of actually written bytes.
- (result < size) means error */
-};
-#define ISeqOutStream_Write(p, buf, size) (p)->Write(p, buf, size)
-
-typedef enum
-{
- SZ_SEEK_SET = 0,
- SZ_SEEK_CUR = 1,
- SZ_SEEK_END = 2
-} ESzSeek;
-
-
-typedef struct ISeekInStream ISeekInStream;
-struct ISeekInStream
-{
- SRes (*Read)(const ISeekInStream *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
- SRes (*Seek)(const ISeekInStream *p, Int64 *pos, ESzSeek origin);
-};
-#define ISeekInStream_Read(p, buf, size) (p)->Read(p, buf, size)
-#define ISeekInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin)
-
-
-typedef struct ILookInStream ILookInStream;
-struct ILookInStream
-{
- SRes (*Look)(const ILookInStream *p, const void **buf, size_t *size);
- /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
- (output(*size) > input(*size)) is not allowed
- (output(*size) < input(*size)) is allowed */
- SRes (*Skip)(const ILookInStream *p, size_t offset);
- /* offset must be <= output(*size) of Look */
-
- SRes (*Read)(const ILookInStream *p, void *buf, size_t *size);
- /* reads directly (without buffer). It's same as ISeqInStream::Read */
- SRes (*Seek)(const ILookInStream *p, Int64 *pos, ESzSeek origin);
-};
-
-#define ILookInStream_Look(p, buf, size) (p)->Look(p, buf, size)
-#define ILookInStream_Skip(p, offset) (p)->Skip(p, offset)
-#define ILookInStream_Read(p, buf, size) (p)->Read(p, buf, size)
-#define ILookInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin)
-
-
-SRes LookInStream_LookRead(const ILookInStream *stream, void *buf, size_t *size);
-SRes LookInStream_SeekTo(const ILookInStream *stream, UInt64 offset);
-
-/* reads via ILookInStream::Read */
-SRes LookInStream_Read2(const ILookInStream *stream, void *buf, size_t size, SRes errorType);
-SRes LookInStream_Read(const ILookInStream *stream, void *buf, size_t size);
-
-
-
-typedef struct
-{
- ILookInStream vt;
- const ISeekInStream *realStream;
-
- size_t pos;
- size_t size; /* it's data size */
-
- /* the following variables must be set outside */
- Byte *buf;
- size_t bufSize;
-} CLookToRead2;
-
-void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead);
-
-#define LookToRead2_Init(p) { (p)->pos = (p)->size = 0; }
-
-
-typedef struct
-{
- ISeqInStream vt;
- const ILookInStream *realStream;
-} CSecToLook;
-
-void SecToLook_CreateVTable(CSecToLook *p);
-
-
-
-typedef struct
-{
- ISeqInStream vt;
- const ILookInStream *realStream;
-} CSecToRead;
-
-void SecToRead_CreateVTable(CSecToRead *p);
-
-
-typedef struct ICompressProgress ICompressProgress;
-
-struct ICompressProgress
-{
- SRes (*Progress)(const ICompressProgress *p, UInt64 inSize, UInt64 outSize);
- /* Returns: result. (result != SZ_OK) means break.
- Value (UInt64)(Int64)-1 for size means unknown value. */
-};
-#define ICompressProgress_Progress(p, inSize, outSize) (p)->Progress(p, inSize, outSize)
-
-
-
-typedef struct ISzAlloc ISzAlloc;
-typedef const ISzAlloc * ISzAllocPtr;
-
-struct ISzAlloc
-{
- void *(*Alloc)(ISzAllocPtr p, size_t size);
- void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */
-};
-
-#define ISzAlloc_Alloc(p, size) (p)->Alloc(p, size)
-#define ISzAlloc_Free(p, a) (p)->Free(p, a)
-
-/* deprecated */
-#define IAlloc_Alloc(p, size) ISzAlloc_Alloc(p, size)
-#define IAlloc_Free(p, a) ISzAlloc_Free(p, a)
-
-
-
-
-
-#ifndef MY_offsetof
- #ifdef offsetof
- #define MY_offsetof(type, m) offsetof(type, m)
- /*
- #define MY_offsetof(type, m) FIELD_OFFSET(type, m)
- */
- #else
- #define MY_offsetof(type, m) ((size_t)&(((type *)0)->m))
- #endif
-#endif
-
-
-
-#ifndef MY_container_of
-
-/*
-#define MY_container_of(ptr, type, m) container_of(ptr, type, m)
-#define MY_container_of(ptr, type, m) CONTAINING_RECORD(ptr, type, m)
-#define MY_container_of(ptr, type, m) ((type *)((char *)(ptr) - offsetof(type, m)))
-#define MY_container_of(ptr, type, m) (&((type *)0)->m == (ptr), ((type *)(((char *)(ptr)) - MY_offsetof(type, m))))
-*/
-
-/*
- GCC shows warning: "perhaps the 'offsetof' macro was used incorrectly"
- GCC 3.4.4 : classes with constructor
- GCC 4.8.1 : classes with non-public variable members"
-*/
-
-#define MY_container_of(ptr, type, m) ((type *)((char *)(1 ? (ptr) : &((type *)0)->m) - MY_offsetof(type, m)))
-
-
-#endif
-
-#define CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) ((type *)(ptr))
-
-/*
-#define CONTAINER_FROM_VTBL(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m)
-*/
-#define CONTAINER_FROM_VTBL(ptr, type, m) MY_container_of(ptr, type, m)
-
-#define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m)
-/*
-#define CONTAINER_FROM_VTBL_CLS(ptr, type, m) CONTAINER_FROM_VTBL(ptr, type, m)
-*/
-
-
-
-#ifdef _WIN32
-
-#define CHAR_PATH_SEPARATOR '\\'
-#define WCHAR_PATH_SEPARATOR L'\\'
-#define STRING_PATH_SEPARATOR "\\"
-#define WSTRING_PATH_SEPARATOR L"\\"
-
-#else
-
-#define CHAR_PATH_SEPARATOR '/'
-#define WCHAR_PATH_SEPARATOR L'/'
-#define STRING_PATH_SEPARATOR "/"
-#define WSTRING_PATH_SEPARATOR L"/"
-
-#endif
-
-EXTERN_C_END
-
-#endif
+/* 7zTypes.h -- Basic types
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_7Z_TYPES_H
+#define ZIP7_7Z_TYPES_H
+
+#ifdef _WIN32
+/* #include <windows.h> */
+#else
+#include <errno.h>
+#endif
+
+#include <stddef.h>
+
+#ifndef EXTERN_C_BEGIN
+#ifdef __cplusplus
+#define EXTERN_C_BEGIN extern "C" {
+#define EXTERN_C_END }
+#else
+#define EXTERN_C_BEGIN
+#define EXTERN_C_END
+#endif
+#endif
+
+EXTERN_C_BEGIN
+
+#define SZ_OK 0
+
+#define SZ_ERROR_DATA 1
+#define SZ_ERROR_MEM 2
+#define SZ_ERROR_CRC 3
+#define SZ_ERROR_UNSUPPORTED 4
+#define SZ_ERROR_PARAM 5
+#define SZ_ERROR_INPUT_EOF 6
+#define SZ_ERROR_OUTPUT_EOF 7
+#define SZ_ERROR_READ 8
+#define SZ_ERROR_WRITE 9
+#define SZ_ERROR_PROGRESS 10
+#define SZ_ERROR_FAIL 11
+#define SZ_ERROR_THREAD 12
+
+#define SZ_ERROR_ARCHIVE 16
+#define SZ_ERROR_NO_ARCHIVE 17
+
+typedef int SRes;
+
+
+#ifdef _MSC_VER
+ #if _MSC_VER > 1200
+ #define MY_ALIGN(n) __declspec(align(n))
+ #else
+ #define MY_ALIGN(n)
+ #endif
+#else
+ /*
+ // C11/C++11:
+ #include <stdalign.h>
+ #define MY_ALIGN(n) alignas(n)
+ */
+ #define MY_ALIGN(n) __attribute__ ((aligned(n)))
+#endif
+
+
+#ifdef _WIN32
+
+/* typedef DWORD WRes; */
+typedef unsigned WRes;
+#define MY_SRes_HRESULT_FROM_WRes(x) HRESULT_FROM_WIN32(x)
+
+// #define MY_HRES_ERROR_INTERNAL_ERROR MY_SRes_HRESULT_FROM_WRes(ERROR_INTERNAL_ERROR)
+
+#else // _WIN32
+
+// #define ENV_HAVE_LSTAT
+typedef int WRes;
+
+// (FACILITY_ERRNO = 0x800) is 7zip's FACILITY constant to represent (errno) errors in HRESULT
+#define MY_FACILITY_ERRNO 0x800
+#define MY_FACILITY_WIN32 7
+#define MY_FACILITY_WRes MY_FACILITY_ERRNO
+
+#define MY_HRESULT_FROM_errno_CONST_ERROR(x) ((HRESULT)( \
+ ( (HRESULT)(x) & 0x0000FFFF) \
+ | (MY_FACILITY_WRes << 16) \
+ | (HRESULT)0x80000000 ))
+
+#define MY_SRes_HRESULT_FROM_WRes(x) \
+ ((HRESULT)(x) <= 0 ? ((HRESULT)(x)) : MY_HRESULT_FROM_errno_CONST_ERROR(x))
+
+// we call macro HRESULT_FROM_WIN32 for system errors (WRes) that are (errno)
+#define HRESULT_FROM_WIN32(x) MY_SRes_HRESULT_FROM_WRes(x)
+
+/*
+#define ERROR_FILE_NOT_FOUND 2L
+#define ERROR_ACCESS_DENIED 5L
+#define ERROR_NO_MORE_FILES 18L
+#define ERROR_LOCK_VIOLATION 33L
+#define ERROR_FILE_EXISTS 80L
+#define ERROR_DISK_FULL 112L
+#define ERROR_NEGATIVE_SEEK 131L
+#define ERROR_ALREADY_EXISTS 183L
+#define ERROR_DIRECTORY 267L
+#define ERROR_TOO_MANY_POSTS 298L
+
+#define ERROR_INTERNAL_ERROR 1359L
+#define ERROR_INVALID_REPARSE_DATA 4392L
+#define ERROR_REPARSE_TAG_INVALID 4393L
+#define ERROR_REPARSE_TAG_MISMATCH 4394L
+*/
+
+// we use errno equivalents for some WIN32 errors:
+
+#define ERROR_INVALID_PARAMETER EINVAL
+#define ERROR_INVALID_FUNCTION EINVAL
+#define ERROR_ALREADY_EXISTS EEXIST
+#define ERROR_FILE_EXISTS EEXIST
+#define ERROR_PATH_NOT_FOUND ENOENT
+#define ERROR_FILE_NOT_FOUND ENOENT
+#define ERROR_DISK_FULL ENOSPC
+// #define ERROR_INVALID_HANDLE EBADF
+
+// we use FACILITY_WIN32 for errors that has no errno equivalent
+// Too many posts were made to a semaphore.
+#define ERROR_TOO_MANY_POSTS ((HRESULT)0x8007012AL)
+#define ERROR_INVALID_REPARSE_DATA ((HRESULT)0x80071128L)
+#define ERROR_REPARSE_TAG_INVALID ((HRESULT)0x80071129L)
+
+// if (MY_FACILITY_WRes != FACILITY_WIN32),
+// we use FACILITY_WIN32 for COM errors:
+#define E_OUTOFMEMORY ((HRESULT)0x8007000EL)
+#define E_INVALIDARG ((HRESULT)0x80070057L)
+#define MY_E_ERROR_NEGATIVE_SEEK ((HRESULT)0x80070083L)
+
+/*
+// we can use FACILITY_ERRNO for some COM errors, that have errno equivalents:
+#define E_OUTOFMEMORY MY_HRESULT_FROM_errno_CONST_ERROR(ENOMEM)
+#define E_INVALIDARG MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL)
+#define MY_E_ERROR_NEGATIVE_SEEK MY_HRESULT_FROM_errno_CONST_ERROR(EINVAL)
+*/
+
+#define TEXT(quote) quote
+
+#define FILE_ATTRIBUTE_READONLY 0x0001
+#define FILE_ATTRIBUTE_HIDDEN 0x0002
+#define FILE_ATTRIBUTE_SYSTEM 0x0004
+#define FILE_ATTRIBUTE_DIRECTORY 0x0010
+#define FILE_ATTRIBUTE_ARCHIVE 0x0020
+#define FILE_ATTRIBUTE_DEVICE 0x0040
+#define FILE_ATTRIBUTE_NORMAL 0x0080
+#define FILE_ATTRIBUTE_TEMPORARY 0x0100
+#define FILE_ATTRIBUTE_SPARSE_FILE 0x0200
+#define FILE_ATTRIBUTE_REPARSE_POINT 0x0400
+#define FILE_ATTRIBUTE_COMPRESSED 0x0800
+#define FILE_ATTRIBUTE_OFFLINE 0x1000
+#define FILE_ATTRIBUTE_NOT_CONTENT_INDEXED 0x2000
+#define FILE_ATTRIBUTE_ENCRYPTED 0x4000
+
+#define FILE_ATTRIBUTE_UNIX_EXTENSION 0x8000 /* trick for Unix */
+
+#endif
+
+
+#ifndef RINOK
+#define RINOK(x) { const int _result_ = (x); if (_result_ != 0) return _result_; }
+#endif
+
+#ifndef RINOK_WRes
+#define RINOK_WRes(x) { const WRes _result_ = (x); if (_result_ != 0) return _result_; }
+#endif
+
+typedef unsigned char Byte;
+typedef short Int16;
+typedef unsigned short UInt16;
+
+#ifdef Z7_DECL_Int32_AS_long
+typedef long Int32;
+typedef unsigned long UInt32;
+#else
+typedef int Int32;
+typedef unsigned int UInt32;
+#endif
+
+
+#ifndef _WIN32
+
+typedef int INT;
+typedef Int32 INT32;
+typedef unsigned int UINT;
+typedef UInt32 UINT32;
+typedef INT32 LONG; // LONG, ULONG and DWORD must be 32-bit for _WIN32 compatibility
+typedef UINT32 ULONG;
+
+#undef DWORD
+typedef UINT32 DWORD;
+
+#define VOID void
+
+#define HRESULT LONG
+
+typedef void *LPVOID;
+// typedef void VOID;
+// typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
+// gcc / clang on Unix : sizeof(long==sizeof(void*) in 32 or 64 bits)
+typedef long INT_PTR;
+typedef unsigned long UINT_PTR;
+typedef long LONG_PTR;
+typedef unsigned long DWORD_PTR;
+
+typedef size_t SIZE_T;
+
+#endif // _WIN32
+
+
+#define MY_HRES_ERROR_INTERNAL_ERROR ((HRESULT)0x8007054FL)
+
+
+#ifdef Z7_DECL_Int64_AS_long
+
+typedef long Int64;
+typedef unsigned long UInt64;
+
+#else
+
+#if (defined(_MSC_VER) || defined(__BORLANDC__)) && !defined(__clang__)
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#else
+#if defined(__clang__) || defined(__GNUC__)
+#include <stdint.h>
+typedef int64_t Int64;
+typedef uint64_t UInt64;
+#else
+typedef long long int Int64;
+typedef unsigned long long int UInt64;
+// #define UINT64_CONST(n) n ## ULL
+#endif
+#endif
+
+#endif
+
+#define UINT64_CONST(n) n
+
+
+#ifdef Z7_DECL_SizeT_AS_unsigned_int
+typedef unsigned int SizeT;
+#else
+typedef size_t SizeT;
+#endif
+
+/*
+#if (defined(_MSC_VER) && _MSC_VER <= 1200)
+typedef size_t MY_uintptr_t;
+#else
+#include <stdint.h>
+typedef uintptr_t MY_uintptr_t;
+#endif
+*/
+
+typedef int BoolInt;
+/* typedef BoolInt Bool; */
+#define True 1
+#define False 0
+
+
+#ifdef _WIN32
+#define Z7_STDCALL __stdcall
+#else
+#define Z7_STDCALL
+#endif
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1300
+#define Z7_NO_INLINE __declspec(noinline)
+#else
+#define Z7_NO_INLINE
+#endif
+
+#define Z7_FORCE_INLINE __forceinline
+
+#define Z7_CDECL __cdecl
+#define Z7_FASTCALL __fastcall
+
+#else // _MSC_VER
+
+#if (defined(__GNUC__) && (__GNUC__ >= 4)) \
+ || (defined(__clang__) && (__clang_major__ >= 4)) \
+ || defined(__INTEL_COMPILER) \
+ || defined(__xlC__)
+#define Z7_NO_INLINE __attribute__((noinline))
+#define Z7_FORCE_INLINE __attribute__((always_inline)) inline
+#else
+#define Z7_NO_INLINE
+#define Z7_FORCE_INLINE
+#endif
+
+#define Z7_CDECL
+
+#if defined(_M_IX86) \
+ || defined(__i386__)
+// #define Z7_FASTCALL __attribute__((fastcall))
+// #define Z7_FASTCALL __attribute__((cdecl))
+#define Z7_FASTCALL
+#elif defined(MY_CPU_AMD64)
+// #define Z7_FASTCALL __attribute__((ms_abi))
+#define Z7_FASTCALL
+#else
+#define Z7_FASTCALL
+#endif
+
+#endif // _MSC_VER
+
+
+/* The following interfaces use first parameter as pointer to structure */
+
+// #define Z7_C_IFACE_CONST_QUAL
+#define Z7_C_IFACE_CONST_QUAL const
+
+#define Z7_C_IFACE_DECL(a) \
+ struct a ## _; \
+ typedef Z7_C_IFACE_CONST_QUAL struct a ## _ * a ## Ptr; \
+ typedef struct a ## _ a; \
+ struct a ## _
+
+
+Z7_C_IFACE_DECL (IByteIn)
+{
+ Byte (*Read)(IByteInPtr p); /* reads one byte, returns 0 in case of EOF or error */
+};
+#define IByteIn_Read(p) (p)->Read(p)
+
+
+Z7_C_IFACE_DECL (IByteOut)
+{
+ void (*Write)(IByteOutPtr p, Byte b);
+};
+#define IByteOut_Write(p, b) (p)->Write(p, b)
+
+
+Z7_C_IFACE_DECL (ISeqInStream)
+{
+ SRes (*Read)(ISeqInStreamPtr p, void *buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) < input(*size)) is allowed */
+};
+#define ISeqInStream_Read(p, buf, size) (p)->Read(p, buf, size)
+
+/* try to read as much as avail in stream and limited by (*processedSize) */
+SRes SeqInStream_ReadMax(ISeqInStreamPtr stream, void *buf, size_t *processedSize);
+/* it can return SZ_ERROR_INPUT_EOF */
+// SRes SeqInStream_Read(ISeqInStreamPtr stream, void *buf, size_t size);
+// SRes SeqInStream_Read2(ISeqInStreamPtr stream, void *buf, size_t size, SRes errorType);
+SRes SeqInStream_ReadByte(ISeqInStreamPtr stream, Byte *buf);
+
+
+Z7_C_IFACE_DECL (ISeqOutStream)
+{
+ size_t (*Write)(ISeqOutStreamPtr p, const void *buf, size_t size);
+ /* Returns: result - the number of actually written bytes.
+ (result < size) means error */
+};
+#define ISeqOutStream_Write(p, buf, size) (p)->Write(p, buf, size)
+
+typedef enum
+{
+ SZ_SEEK_SET = 0,
+ SZ_SEEK_CUR = 1,
+ SZ_SEEK_END = 2
+} ESzSeek;
+
+
+Z7_C_IFACE_DECL (ISeekInStream)
+{
+ SRes (*Read)(ISeekInStreamPtr p, void *buf, size_t *size); /* same as ISeqInStream::Read */
+ SRes (*Seek)(ISeekInStreamPtr p, Int64 *pos, ESzSeek origin);
+};
+#define ISeekInStream_Read(p, buf, size) (p)->Read(p, buf, size)
+#define ISeekInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin)
+
+
+Z7_C_IFACE_DECL (ILookInStream)
+{
+ SRes (*Look)(ILookInStreamPtr p, const void **buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) > input(*size)) is not allowed
+ (output(*size) < input(*size)) is allowed */
+ SRes (*Skip)(ILookInStreamPtr p, size_t offset);
+ /* offset must be <= output(*size) of Look */
+ SRes (*Read)(ILookInStreamPtr p, void *buf, size_t *size);
+ /* reads directly (without buffer). It's same as ISeqInStream::Read */
+ SRes (*Seek)(ILookInStreamPtr p, Int64 *pos, ESzSeek origin);
+};
+
+#define ILookInStream_Look(p, buf, size) (p)->Look(p, buf, size)
+#define ILookInStream_Skip(p, offset) (p)->Skip(p, offset)
+#define ILookInStream_Read(p, buf, size) (p)->Read(p, buf, size)
+#define ILookInStream_Seek(p, pos, origin) (p)->Seek(p, pos, origin)
+
+
+SRes LookInStream_LookRead(ILookInStreamPtr stream, void *buf, size_t *size);
+SRes LookInStream_SeekTo(ILookInStreamPtr stream, UInt64 offset);
+
+/* reads via ILookInStream::Read */
+SRes LookInStream_Read2(ILookInStreamPtr stream, void *buf, size_t size, SRes errorType);
+SRes LookInStream_Read(ILookInStreamPtr stream, void *buf, size_t size);
+
+
+typedef struct
+{
+ ILookInStream vt;
+ ISeekInStreamPtr realStream;
+
+ size_t pos;
+ size_t size; /* it's data size */
+
+ /* the following variables must be set outside */
+ Byte *buf;
+ size_t bufSize;
+} CLookToRead2;
+
+void LookToRead2_CreateVTable(CLookToRead2 *p, int lookahead);
+
+#define LookToRead2_INIT(p) { (p)->pos = (p)->size = 0; }
+
+
+typedef struct
+{
+ ISeqInStream vt;
+ ILookInStreamPtr realStream;
+} CSecToLook;
+
+void SecToLook_CreateVTable(CSecToLook *p);
+
+
+
+typedef struct
+{
+ ISeqInStream vt;
+ ILookInStreamPtr realStream;
+} CSecToRead;
+
+void SecToRead_CreateVTable(CSecToRead *p);
+
+
+Z7_C_IFACE_DECL (ICompressProgress)
+{
+ SRes (*Progress)(ICompressProgressPtr p, UInt64 inSize, UInt64 outSize);
+ /* Returns: result. (result != SZ_OK) means break.
+ Value (UInt64)(Int64)-1 for size means unknown value. */
+};
+
+#define ICompressProgress_Progress(p, inSize, outSize) (p)->Progress(p, inSize, outSize)
+
+
+
+typedef struct ISzAlloc ISzAlloc;
+typedef const ISzAlloc * ISzAllocPtr;
+
+struct ISzAlloc
+{
+ void *(*Alloc)(ISzAllocPtr p, size_t size);
+ void (*Free)(ISzAllocPtr p, void *address); /* address can be 0 */
+};
+
+#define ISzAlloc_Alloc(p, size) (p)->Alloc(p, size)
+#define ISzAlloc_Free(p, a) (p)->Free(p, a)
+
+/* deprecated */
+#define IAlloc_Alloc(p, size) ISzAlloc_Alloc(p, size)
+#define IAlloc_Free(p, a) ISzAlloc_Free(p, a)
+
+
+
+
+
+#ifndef MY_offsetof
+ #ifdef offsetof
+ #define MY_offsetof(type, m) offsetof(type, m)
+ /*
+ #define MY_offsetof(type, m) FIELD_OFFSET(type, m)
+ */
+ #else
+ #define MY_offsetof(type, m) ((size_t)&(((type *)0)->m))
+ #endif
+#endif
+
+
+
+#ifndef Z7_container_of
+
+/*
+#define Z7_container_of(ptr, type, m) container_of(ptr, type, m)
+#define Z7_container_of(ptr, type, m) CONTAINING_RECORD(ptr, type, m)
+#define Z7_container_of(ptr, type, m) ((type *)((char *)(ptr) - offsetof(type, m)))
+#define Z7_container_of(ptr, type, m) (&((type *)0)->m == (ptr), ((type *)(((char *)(ptr)) - MY_offsetof(type, m))))
+*/
+
+/*
+ GCC shows warning: "perhaps the 'offsetof' macro was used incorrectly"
+ GCC 3.4.4 : classes with constructor
+ GCC 4.8.1 : classes with non-public variable members"
+*/
+
+#define Z7_container_of(ptr, type, m) \
+ ((type *)(void *)((char *)(void *) \
+ (1 ? (ptr) : &((type *)NULL)->m) - MY_offsetof(type, m)))
+
+#define Z7_container_of_CONST(ptr, type, m) \
+ ((const type *)(const void *)((const char *)(const void *) \
+ (1 ? (ptr) : &((type *)NULL)->m) - MY_offsetof(type, m)))
+
+/*
+#define Z7_container_of_NON_CONST_FROM_CONST(ptr, type, m) \
+ ((type *)(void *)(const void *)((const char *)(const void *) \
+ (1 ? (ptr) : &((type *)NULL)->m) - MY_offsetof(type, m)))
+*/
+
+#endif
+
+#define Z7_CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m) ((type *)(void *)(ptr))
+
+// #define Z7_CONTAINER_FROM_VTBL(ptr, type, m) Z7_CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m)
+#define Z7_CONTAINER_FROM_VTBL(ptr, type, m) Z7_container_of(ptr, type, m)
+// #define Z7_CONTAINER_FROM_VTBL(ptr, type, m) Z7_container_of_NON_CONST_FROM_CONST(ptr, type, m)
+
+#define Z7_CONTAINER_FROM_VTBL_CONST(ptr, type, m) Z7_container_of_CONST(ptr, type, m)
+
+#define Z7_CONTAINER_FROM_VTBL_CLS(ptr, type, m) Z7_CONTAINER_FROM_VTBL_SIMPLE(ptr, type, m)
+/*
+#define Z7_CONTAINER_FROM_VTBL_CLS(ptr, type, m) Z7_CONTAINER_FROM_VTBL(ptr, type, m)
+*/
+#if defined (__clang__) || defined(__GNUC__)
+#define Z7_DIAGNOSCTIC_IGNORE_BEGIN_CAST_QUAL \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wcast-qual\"")
+#define Z7_DIAGNOSCTIC_IGNORE_END_CAST_QUAL \
+ _Pragma("GCC diagnostic pop")
+#else
+#define Z7_DIAGNOSCTIC_IGNORE_BEGIN_CAST_QUAL
+#define Z7_DIAGNOSCTIC_IGNORE_END_CAST_QUAL
+#endif
+
+#define Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR(ptr, type, m, p) \
+ Z7_DIAGNOSCTIC_IGNORE_BEGIN_CAST_QUAL \
+ type *p = Z7_CONTAINER_FROM_VTBL(ptr, type, m); \
+ Z7_DIAGNOSCTIC_IGNORE_END_CAST_QUAL
+
+#define Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(type) \
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR(pp, type, vt, p)
+
+
+// #define ZIP7_DECLARE_HANDLE(name) typedef void *name;
+#define Z7_DECLARE_HANDLE(name) struct name##_dummy{int unused;}; typedef struct name##_dummy *name;
+
+
+#define Z7_memset_0_ARRAY(a) memset((a), 0, sizeof(a))
+
+#ifndef Z7_ARRAY_SIZE
+#define Z7_ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#endif
+
+
+#ifdef _WIN32
+
+#define CHAR_PATH_SEPARATOR '\\'
+#define WCHAR_PATH_SEPARATOR L'\\'
+#define STRING_PATH_SEPARATOR "\\"
+#define WSTRING_PATH_SEPARATOR L"\\"
+
+#else
+
+#define CHAR_PATH_SEPARATOR '/'
+#define WCHAR_PATH_SEPARATOR L'/'
+#define STRING_PATH_SEPARATOR "/"
+#define WSTRING_PATH_SEPARATOR L"/"
+
+#endif
+
+#define k_PropVar_TimePrec_0 0
+#define k_PropVar_TimePrec_Unix 1
+#define k_PropVar_TimePrec_DOS 2
+#define k_PropVar_TimePrec_HighPrec 3
+#define k_PropVar_TimePrec_Base 16
+#define k_PropVar_TimePrec_100ns (k_PropVar_TimePrec_Base + 7)
+#define k_PropVar_TimePrec_1ns (k_PropVar_TimePrec_Base + 9)
+
+EXTERN_C_END
+
+#endif
+
+/*
+#ifndef Z7_ST
+#ifdef _7ZIP_ST
+#define Z7_ST
+#endif
+#endif
+*/
diff --git a/C/7zVersion.h b/C/7zVersion.h
index 0074c64..7549239 100644
--- a/C/7zVersion.h
+++ b/C/7zVersion.h
@@ -1,27 +1,27 @@
-#define MY_VER_MAJOR 19
-#define MY_VER_MINOR 00
-#define MY_VER_BUILD 0
-#define MY_VERSION_NUMBERS "19.00"
-#define MY_VERSION MY_VERSION_NUMBERS
-
-#ifdef MY_CPU_NAME
- #define MY_VERSION_CPU MY_VERSION " (" MY_CPU_NAME ")"
-#else
- #define MY_VERSION_CPU MY_VERSION
-#endif
-
-#define MY_DATE "2019-02-21"
-#undef MY_COPYRIGHT
-#undef MY_VERSION_COPYRIGHT_DATE
-#define MY_AUTHOR_NAME "Igor Pavlov"
-#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain"
-#define MY_COPYRIGHT_CR "Copyright (c) 1999-2018 Igor Pavlov"
-
-#ifdef USE_COPYRIGHT_CR
- #define MY_COPYRIGHT MY_COPYRIGHT_CR
-#else
- #define MY_COPYRIGHT MY_COPYRIGHT_PD
-#endif
-
-#define MY_COPYRIGHT_DATE MY_COPYRIGHT " : " MY_DATE
-#define MY_VERSION_COPYRIGHT_DATE MY_VERSION_CPU " : " MY_COPYRIGHT " : " MY_DATE
+#define MY_VER_MAJOR 23
+#define MY_VER_MINOR 01
+#define MY_VER_BUILD 0
+#define MY_VERSION_NUMBERS "23.01"
+#define MY_VERSION MY_VERSION_NUMBERS
+
+#ifdef MY_CPU_NAME
+ #define MY_VERSION_CPU MY_VERSION " (" MY_CPU_NAME ")"
+#else
+ #define MY_VERSION_CPU MY_VERSION
+#endif
+
+#define MY_DATE "2023-06-20"
+#undef MY_COPYRIGHT
+#undef MY_VERSION_COPYRIGHT_DATE
+#define MY_AUTHOR_NAME "Igor Pavlov"
+#define MY_COPYRIGHT_PD "Igor Pavlov : Public domain"
+#define MY_COPYRIGHT_CR "Copyright (c) 1999-2023 Igor Pavlov"
+
+#ifdef USE_COPYRIGHT_CR
+ #define MY_COPYRIGHT MY_COPYRIGHT_CR
+#else
+ #define MY_COPYRIGHT MY_COPYRIGHT_PD
+#endif
+
+#define MY_COPYRIGHT_DATE MY_COPYRIGHT " : " MY_DATE
+#define MY_VERSION_COPYRIGHT_DATE MY_VERSION_CPU " : " MY_COPYRIGHT " : " MY_DATE
diff --git a/C/7zVersion.rc b/C/7zVersion.rc
index 6ed26de..e520995 100644
--- a/C/7zVersion.rc
+++ b/C/7zVersion.rc
@@ -1,55 +1,55 @@
-#define MY_VS_FFI_FILEFLAGSMASK 0x0000003FL
-#define MY_VOS_NT_WINDOWS32 0x00040004L
-#define MY_VOS_CE_WINDOWS32 0x00050004L
-
-#define MY_VFT_APP 0x00000001L
-#define MY_VFT_DLL 0x00000002L
-
-// #include <WinVer.h>
-
-#ifndef MY_VERSION
-#include "7zVersion.h"
-#endif
-
-#define MY_VER MY_VER_MAJOR,MY_VER_MINOR,MY_VER_BUILD,0
-
-#ifdef DEBUG
-#define DBG_FL VS_FF_DEBUG
-#else
-#define DBG_FL 0
-#endif
-
-#define MY_VERSION_INFO(fileType, descr, intName, origName) \
-LANGUAGE 9, 1 \
-1 VERSIONINFO \
- FILEVERSION MY_VER \
- PRODUCTVERSION MY_VER \
- FILEFLAGSMASK MY_VS_FFI_FILEFLAGSMASK \
- FILEFLAGS DBG_FL \
- FILEOS MY_VOS_NT_WINDOWS32 \
- FILETYPE fileType \
- FILESUBTYPE 0x0L \
-BEGIN \
- BLOCK "StringFileInfo" \
- BEGIN \
- BLOCK "040904b0" \
- BEGIN \
- VALUE "CompanyName", "Igor Pavlov" \
- VALUE "FileDescription", descr \
- VALUE "FileVersion", MY_VERSION \
- VALUE "InternalName", intName \
- VALUE "LegalCopyright", MY_COPYRIGHT \
- VALUE "OriginalFilename", origName \
- VALUE "ProductName", "7-Zip" \
- VALUE "ProductVersion", MY_VERSION \
- END \
- END \
- BLOCK "VarFileInfo" \
- BEGIN \
- VALUE "Translation", 0x409, 1200 \
- END \
-END
-
-#define MY_VERSION_INFO_APP(descr, intName) MY_VERSION_INFO(MY_VFT_APP, descr, intName, intName ".exe")
-
-#define MY_VERSION_INFO_DLL(descr, intName) MY_VERSION_INFO(MY_VFT_DLL, descr, intName, intName ".dll")
+#define MY_VS_FFI_FILEFLAGSMASK 0x0000003FL
+#define MY_VOS_NT_WINDOWS32 0x00040004L
+#define MY_VOS_CE_WINDOWS32 0x00050004L
+
+#define MY_VFT_APP 0x00000001L
+#define MY_VFT_DLL 0x00000002L
+
+// #include <WinVer.h>
+
+#ifndef MY_VERSION
+#include "7zVersion.h"
+#endif
+
+#define MY_VER MY_VER_MAJOR,MY_VER_MINOR,MY_VER_BUILD,0
+
+#ifdef DEBUG
+#define DBG_FL VS_FF_DEBUG
+#else
+#define DBG_FL 0
+#endif
+
+#define MY_VERSION_INFO(fileType, descr, intName, origName) \
+LANGUAGE 9, 1 \
+1 VERSIONINFO \
+ FILEVERSION MY_VER \
+ PRODUCTVERSION MY_VER \
+ FILEFLAGSMASK MY_VS_FFI_FILEFLAGSMASK \
+ FILEFLAGS DBG_FL \
+ FILEOS MY_VOS_NT_WINDOWS32 \
+ FILETYPE fileType \
+ FILESUBTYPE 0x0L \
+BEGIN \
+ BLOCK "StringFileInfo" \
+ BEGIN \
+ BLOCK "040904b0" \
+ BEGIN \
+ VALUE "CompanyName", "Igor Pavlov" \
+ VALUE "FileDescription", descr \
+ VALUE "FileVersion", MY_VERSION \
+ VALUE "InternalName", intName \
+ VALUE "LegalCopyright", MY_COPYRIGHT \
+ VALUE "OriginalFilename", origName \
+ VALUE "ProductName", "7-Zip" \
+ VALUE "ProductVersion", MY_VERSION \
+ END \
+ END \
+ BLOCK "VarFileInfo" \
+ BEGIN \
+ VALUE "Translation", 0x409, 1200 \
+ END \
+END
+
+#define MY_VERSION_INFO_APP(descr, intName) MY_VERSION_INFO(MY_VFT_APP, descr, intName, intName ".exe")
+
+#define MY_VERSION_INFO_DLL(descr, intName) MY_VERSION_INFO(MY_VFT_DLL, descr, intName, intName ".dll")
diff --git a/C/7zWindows.h b/C/7zWindows.h
new file mode 100644
index 0000000..42c6db8
--- /dev/null
+++ b/C/7zWindows.h
@@ -0,0 +1,101 @@
+/* 7zWindows.h -- StdAfx
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_7Z_WINDOWS_H
+#define ZIP7_INC_7Z_WINDOWS_H
+
+#ifdef _WIN32
+
+#if defined(__clang__)
+# pragma clang diagnostic push
+#endif
+
+#if defined(_MSC_VER)
+
+#pragma warning(push)
+#pragma warning(disable : 4668) // '_WIN32_WINNT' is not defined as a preprocessor macro, replacing with '0' for '#if/#elif'
+
+#if _MSC_VER == 1900
+// for old kit10 versions
+// #pragma warning(disable : 4255) // winuser.h(13979): warning C4255: 'GetThreadDpiAwarenessContext':
+#endif
+// win10 Windows Kit:
+#endif // _MSC_VER
+
+#if defined(_MSC_VER) && _MSC_VER <= 1200 && !defined(_WIN64)
+// for msvc6 without sdk2003
+#define RPC_NO_WINDOWS_H
+#endif
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+// #if defined(__GNUC__) && !defined(__clang__)
+#include <windows.h>
+#else
+#include <Windows.h>
+#endif
+// #include <basetsd.h>
+// #include <wtypes.h>
+
+// but if precompiled with clang-cl then we need
+// #include <windows.h>
+#if defined(_MSC_VER)
+#pragma warning(pop)
+#endif
+
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER <= 1200 && !defined(_WIN64)
+#ifndef _W64
+
+typedef long LONG_PTR, *PLONG_PTR;
+typedef unsigned long ULONG_PTR, *PULONG_PTR;
+typedef ULONG_PTR DWORD_PTR, *PDWORD_PTR;
+
+#define Z7_OLD_WIN_SDK
+#endif // _W64
+#endif // _MSC_VER == 1200
+
+#ifdef Z7_OLD_WIN_SDK
+
+#ifndef INVALID_FILE_ATTRIBUTES
+#define INVALID_FILE_ATTRIBUTES ((DWORD)-1)
+#endif
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER ((DWORD)-1)
+#endif
+#ifndef FILE_SPECIAL_ACCESS
+#define FILE_SPECIAL_ACCESS (FILE_ANY_ACCESS)
+#endif
+
+// ShlObj.h:
+// #define BIF_NEWDIALOGSTYLE 0x0040
+
+#pragma warning(disable : 4201)
+// #pragma warning(disable : 4115)
+
+#undef VARIANT_TRUE
+#define VARIANT_TRUE ((VARIANT_BOOL)-1)
+#endif
+
+#endif // Z7_OLD_WIN_SDK
+
+#ifdef UNDER_CE
+#undef VARIANT_TRUE
+#define VARIANT_TRUE ((VARIANT_BOOL)-1)
+#endif
+
+
+#if defined(_MSC_VER)
+#if _MSC_VER >= 1400 && _MSC_VER <= 1600
+ // BaseTsd.h(148) : 'HandleToULong' : unreferenced inline function has been removed
+ // string.h
+ // #pragma warning(disable : 4514)
+#endif
+#endif
+
+
+/* #include "7zTypes.h" */
+
+#endif
diff --git a/C/7zip_gcc_c.mak b/C/7zip_gcc_c.mak
new file mode 100644
index 0000000..f19a99b
--- /dev/null
+++ b/C/7zip_gcc_c.mak
@@ -0,0 +1,360 @@
+
+MY_ARCH_2 = $(MY_ARCH)
+
+MY_ASM = jwasm
+MY_ASM = asmc
+
+ifndef RC
+#RC=windres.exe --target=pe-x86-64
+#RC=windres.exe -F pe-i386
+RC=windres.exe
+endif
+
+PROGPATH = $(O)/$(PROG)
+PROGPATH_STATIC = $(O)/$(PROG)s
+
+ifneq ($(CC), xlc)
+CFLAGS_WARN_WALL = -Wall -Werror -Wextra
+endif
+
+# for object file
+CFLAGS_BASE_LIST = -c
+# for ASM file
+# CFLAGS_BASE_LIST = -S
+
+FLAGS_FLTO =
+FLAGS_FLTO = -flto
+
+CFLAGS_BASE = $(MY_ARCH_2) -O2 $(CFLAGS_BASE_LIST) $(CFLAGS_WARN_WALL) $(CFLAGS_WARN) \
+ -DNDEBUG -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+
+
+ifdef SystemDrive
+IS_MINGW = 1
+else
+ifdef SYSTEMDRIVE
+# ifdef OS
+IS_MINGW = 1
+endif
+endif
+
+ifdef IS_MINGW
+LDFLAGS_STATIC_2 = -static
+else
+ifndef DEF_FILE
+ifndef IS_NOT_STANDALONE
+ifndef MY_DYNAMIC_LINK
+ifneq ($(CC), clang)
+LDFLAGS_STATIC_2 =
+# -static
+# -static-libstdc++ -static-libgcc
+endif
+endif
+endif
+endif
+endif
+
+LDFLAGS_STATIC = -DNDEBUG $(LDFLAGS_STATIC_2)
+
+ifdef DEF_FILE
+
+
+ifdef IS_MINGW
+SHARED_EXT=.dll
+LDFLAGS = -shared -DEF $(DEF_FILE) $(LDFLAGS_STATIC)
+else
+SHARED_EXT=.so
+LDFLAGS = -shared -fPIC $(LDFLAGS_STATIC)
+CC_SHARED=-fPIC
+endif
+
+
+else
+
+LDFLAGS = $(LDFLAGS_STATIC)
+# -s is not required for clang, do we need it for GGC ???
+# -s
+
+#-static -static-libgcc -static-libstdc++
+
+ifdef IS_MINGW
+SHARED_EXT=.exe
+else
+SHARED_EXT=
+endif
+
+endif
+
+
+PROGPATH = $(O)/$(PROG)$(SHARED_EXT)
+PROGPATH_STATIC = $(O)/$(PROG)s$(SHARED_EXT)
+
+ifndef O
+O=_o
+endif
+
+ifdef IS_MINGW
+
+ifdef MSYSTEM
+RM = rm -f
+MY_MKDIR=mkdir -p
+DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS)
+else
+RM = del
+MY_MKDIR=mkdir
+DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll
+endif
+
+
+LIB2 = -lOle32 -loleaut32 -luuid -ladvapi32 -lUser32 -lShell32
+
+CFLAGS_EXTRA = -DUNICODE -D_UNICODE
+# -Wno-delete-non-virtual-dtor
+
+
+else
+
+RM = rm -f
+MY_MKDIR=mkdir -p
+# CFLAGS_BASE := $(CFLAGS_BASE) -DZ7_ST
+# CFLAGS_EXTRA = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+
+# LOCAL_LIBS=-lpthread
+# LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+LIB2 = -lpthread -ldl
+
+DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS)
+
+endif
+
+
+ifdef IS_X64
+AFLAGS_ABI = -elf64 -DABI_LINUX
+else
+AFLAGS_ABI = -elf -DABI_LINUX -DABI_CDECL
+# -DABI_CDECL
+# -DABI_LINUX
+# -DABI_CDECL
+endif
+AFLAGS = $(AFLAGS_ABI) -Fo$(O)/
+
+C_WARN_FLAGS =
+
+CFLAGS = $(LOCAL_FLAGS) $(CFLAGS_BASE2) $(CFLAGS_BASE) $(CFLAGS_EXTRA) $(C_WARN_FLAGS) $(FLAGS_FLTO) $(CC_SHARED) -o $@
+
+STATIC_TARGET=
+ifdef COMPL_STATIC
+STATIC_TARGET=$(PROGPATH_STATIC)
+endif
+
+
+all: $(O) $(PROGPATH) $(STATIC_TARGET)
+
+$(O):
+ $(MY_MKDIR) $(O)
+
+ifneq ($(CC), $(CROSS_COMPILE)clang)
+LFLAGS_STRIP = -s
+endif
+
+LFLAGS_ALL = $(LFLAGS_STRIP) $(MY_ARCH_2) $(LDFLAGS) $(FLAGS_FLTO) $(LD_arch) $(OBJS) $(MY_LIBS) $(LIB2)
+$(PROGPATH): $(OBJS)
+ $(CC) -o $(PROGPATH) $(LFLAGS_ALL)
+
+$(PROGPATH_STATIC): $(OBJS)
+ $(CC) -static -o $(PROGPATH_STATIC) $(LFLAGS_ALL)
+
+
+ifndef NO_DEFAULT_RES
+# old mingw without -FO
+# windres.exe $(RFLAGS) resource.rc $O/resource.o
+$O/resource.o: resource.rc
+ $(RC) $(RFLAGS) resource.rc $(O)/resource.o
+endif
+# windres.exe $(RFLAGS) resource.rc $(O)\resource.o
+# windres.exe $(RFLAGS) resource.rc -FO $(O)/resource.o
+# $(RC) $(RFLAGS) resource.rc -FO $(O)/resource.o
+
+
+
+$O/7zAlloc.o: ../../../C/7zAlloc.c
+ $(CC) $(CFLAGS) $<
+$O/7zArcIn.o: ../../../C/7zArcIn.c
+ $(CC) $(CFLAGS) $<
+$O/7zBuf.o: ../../../C/7zBuf.c
+ $(CC) $(CFLAGS) $<
+$O/7zBuf2.o: ../../../C/7zBuf2.c
+ $(CC) $(CFLAGS) $<
+$O/7zCrc.o: ../../../C/7zCrc.c
+ $(CC) $(CFLAGS) $<
+$O/7zDec.o: ../../../C/7zDec.c
+ $(CC) $(CFLAGS) $<
+$O/7zFile.o: ../../../C/7zFile.c
+ $(CC) $(CFLAGS) $<
+$O/7zStream.o: ../../../C/7zStream.c
+ $(CC) $(CFLAGS) $<
+$O/Aes.o: ../../../C/Aes.c
+ $(CC) $(CFLAGS) $<
+$O/Alloc.o: ../../../C/Alloc.c
+ $(CC) $(CFLAGS) $<
+$O/Bcj2.o: ../../../C/Bcj2.c
+ $(CC) $(CFLAGS) $<
+$O/Bcj2Enc.o: ../../../C/Bcj2Enc.c
+ $(CC) $(CFLAGS) $<
+$O/Blake2s.o: ../../../C/Blake2s.c
+ $(CC) $(CFLAGS) $<
+$O/Bra.o: ../../../C/Bra.c
+ $(CC) $(CFLAGS) $<
+$O/Bra86.o: ../../../C/Bra86.c
+ $(CC) $(CFLAGS) $<
+$O/BraIA64.o: ../../../C/BraIA64.c
+ $(CC) $(CFLAGS) $<
+$O/BwtSort.o: ../../../C/BwtSort.c
+ $(CC) $(CFLAGS) $<
+
+$O/CpuArch.o: ../../../C/CpuArch.c
+ $(CC) $(CFLAGS) $<
+$O/Delta.o: ../../../C/Delta.c
+ $(CC) $(CFLAGS) $<
+$O/DllSecur.o: ../../../C/DllSecur.c
+ $(CC) $(CFLAGS) $<
+$O/HuffEnc.o: ../../../C/HuffEnc.c
+ $(CC) $(CFLAGS) $<
+$O/LzFind.o: ../../../C/LzFind.c
+ $(CC) $(CFLAGS) $<
+
+# ifdef MT_FILES
+$O/LzFindMt.o: ../../../C/LzFindMt.c
+ $(CC) $(CFLAGS) $<
+$O/LzFindOpt.o: ../../../C/LzFindOpt.c
+ $(CC) $(CFLAGS) $<
+
+$O/Threads.o: ../../../C/Threads.c
+ $(CC) $(CFLAGS) $<
+# endif
+
+$O/LzmaEnc.o: ../../../C/LzmaEnc.c
+ $(CC) $(CFLAGS) $<
+$O/Lzma86Dec.o: ../../../C/Lzma86Dec.c
+ $(CC) $(CFLAGS) $<
+$O/Lzma86Enc.o: ../../../C/Lzma86Enc.c
+ $(CC) $(CFLAGS) $<
+$O/Lzma2Dec.o: ../../../C/Lzma2Dec.c
+ $(CC) $(CFLAGS) $<
+$O/Lzma2DecMt.o: ../../../C/Lzma2DecMt.c
+ $(CC) $(CFLAGS) $<
+$O/Lzma2Enc.o: ../../../C/Lzma2Enc.c
+ $(CC) $(CFLAGS) $<
+$O/LzmaLib.o: ../../../C/LzmaLib.c
+ $(CC) $(CFLAGS) $<
+$O/MtCoder.o: ../../../C/MtCoder.c
+ $(CC) $(CFLAGS) $<
+$O/MtDec.o: ../../../C/MtDec.c
+ $(CC) $(CFLAGS) $<
+$O/Ppmd7.o: ../../../C/Ppmd7.c
+ $(CC) $(CFLAGS) $<
+$O/Ppmd7aDec.o: ../../../C/Ppmd7aDec.c
+ $(CC) $(CFLAGS) $<
+$O/Ppmd7Dec.o: ../../../C/Ppmd7Dec.c
+ $(CC) $(CFLAGS) $<
+$O/Ppmd7Enc.o: ../../../C/Ppmd7Enc.c
+ $(CC) $(CFLAGS) $<
+$O/Ppmd8.o: ../../../C/Ppmd8.c
+ $(CC) $(CFLAGS) $<
+$O/Ppmd8Dec.o: ../../../C/Ppmd8Dec.c
+ $(CC) $(CFLAGS) $<
+$O/Ppmd8Enc.o: ../../../C/Ppmd8Enc.c
+ $(CC) $(CFLAGS) $<
+$O/Sha1.o: ../../../C/Sha1.c
+ $(CC) $(CFLAGS) $<
+$O/Sha256.o: ../../../C/Sha256.c
+ $(CC) $(CFLAGS) $<
+$O/Sort.o: ../../../C/Sort.c
+ $(CC) $(CFLAGS) $<
+$O/SwapBytes.o: ../../../C/SwapBytes.c
+ $(CC) $(CFLAGS) $<
+$O/Xz.o: ../../../C/Xz.c
+ $(CC) $(CFLAGS) $<
+$O/XzCrc64.o: ../../../C/XzCrc64.c
+ $(CC) $(CFLAGS) $<
+$O/XzDec.o: ../../../C/XzDec.c
+ $(CC) $(CFLAGS) $<
+$O/XzEnc.o: ../../../C/XzEnc.c
+ $(CC) $(CFLAGS) $<
+$O/XzIn.o: ../../../C/XzIn.c
+ $(CC) $(CFLAGS) $<
+
+
+ifdef USE_ASM
+ifdef IS_X64
+USE_X86_ASM=1
+else
+ifdef IS_X86
+USE_X86_ASM=1
+endif
+endif
+endif
+
+ifdef USE_X86_ASM
+$O/7zCrcOpt.o: ../../../Asm/x86/7zCrcOpt.asm
+ $(MY_ASM) $(AFLAGS) $<
+$O/XzCrc64Opt.o: ../../../Asm/x86/XzCrc64Opt.asm
+ $(MY_ASM) $(AFLAGS) $<
+$O/AesOpt.o: ../../../Asm/x86/AesOpt.asm
+ $(MY_ASM) $(AFLAGS) $<
+$O/Sha1Opt.o: ../../../Asm/x86/Sha1Opt.asm
+ $(MY_ASM) $(AFLAGS) $<
+$O/Sha256Opt.o: ../../../Asm/x86/Sha256Opt.asm
+ $(MY_ASM) $(AFLAGS) $<
+else
+$O/7zCrcOpt.o: ../../7zCrcOpt.c
+ $(CC) $(CFLAGS) $<
+$O/XzCrc64Opt.o: ../../XzCrc64Opt.c
+ $(CC) $(CFLAGS) $<
+$O/Sha1Opt.o: ../../Sha1Opt.c
+ $(CC) $(CFLAGS) $<
+$O/Sha256Opt.o: ../../Sha256Opt.c
+ $(CC) $(CFLAGS) $<
+$O/AesOpt.o: ../../AesOpt.c
+ $(CC) $(CFLAGS) $<
+endif
+
+
+ifdef USE_LZMA_DEC_ASM
+
+ifdef IS_X64
+$O/LzmaDecOpt.o: ../../../Asm/x86/LzmaDecOpt.asm
+ $(MY_ASM) $(AFLAGS) $<
+endif
+
+ifdef IS_ARM64
+$O/LzmaDecOpt.o: ../../../Asm/arm64/LzmaDecOpt.S ../../../Asm/arm64/7zAsm.S
+ $(CC) $(CFLAGS) $<
+endif
+
+$O/LzmaDec.o: ../../LzmaDec.c
+ $(CC) $(CFLAGS) -DZ7_LZMA_DEC_OPT $<
+
+else
+
+$O/LzmaDec.o: ../../LzmaDec.c
+ $(CC) $(CFLAGS) $<
+
+endif
+
+
+
+$O/7zMain.o: ../../../C/Util/7z/7zMain.c
+ $(CC) $(CFLAGS) $<
+$O/7zipInstall.o: ../../../C/Util/7zipInstall/7zipInstall.c
+ $(CC) $(CFLAGS) $<
+$O/7zipUninstall.o: ../../../C/Util/7zipUninstall/7zipUninstall.c
+ $(CC) $(CFLAGS) $<
+$O/LzmaUtil.o: ../../../C/Util/Lzma/LzmaUtil.c
+ $(CC) $(CFLAGS) $<
+$O/XzUtil.o: ../../../C/Util/Xz/XzUtil.c
+ $(CC) $(CFLAGS) $<
+
+
+clean:
+ -$(DEL_OBJ_EXE)
diff --git a/C/Aes.c b/C/Aes.c
index 8f7d50e..bcaafab 100644
--- a/C/Aes.c
+++ b/C/Aes.c
@@ -1,306 +1,393 @@
-/* Aes.c -- AES encryption / decryption
-2017-01-24 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "Aes.h"
-#include "CpuArch.h"
-
-static UInt32 T[256 * 4];
-static const Byte Sbox[256] = {
- 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
- 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
- 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
- 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
- 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
- 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
- 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
- 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
- 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
- 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
- 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
- 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
- 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
- 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
- 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
- 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
-
-void MY_FAST_CALL AesCbc_Encode(UInt32 *ivAes, Byte *data, size_t numBlocks);
-void MY_FAST_CALL AesCbc_Decode(UInt32 *ivAes, Byte *data, size_t numBlocks);
-void MY_FAST_CALL AesCtr_Code(UInt32 *ivAes, Byte *data, size_t numBlocks);
-
-void MY_FAST_CALL AesCbc_Encode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);
-void MY_FAST_CALL AesCbc_Decode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);
-void MY_FAST_CALL AesCtr_Code_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);
-
-AES_CODE_FUNC g_AesCbc_Encode;
-AES_CODE_FUNC g_AesCbc_Decode;
-AES_CODE_FUNC g_AesCtr_Code;
-
-static UInt32 D[256 * 4];
-static Byte InvS[256];
-
-static const Byte Rcon[11] = { 0x00, 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36 };
-
-#define xtime(x) ((((x) << 1) ^ (((x) & 0x80) != 0 ? 0x1B : 0)) & 0xFF)
-
-#define Ui32(a0, a1, a2, a3) ((UInt32)(a0) | ((UInt32)(a1) << 8) | ((UInt32)(a2) << 16) | ((UInt32)(a3) << 24))
-
-#define gb0(x) ( (x) & 0xFF)
-#define gb1(x) (((x) >> ( 8)) & 0xFF)
-#define gb2(x) (((x) >> (16)) & 0xFF)
-#define gb3(x) (((x) >> (24)))
-
-#define gb(n, x) gb ## n(x)
-
-#define TT(x) (T + (x << 8))
-#define DD(x) (D + (x << 8))
-
-
-void AesGenTables(void)
-{
- unsigned i;
- for (i = 0; i < 256; i++)
- InvS[Sbox[i]] = (Byte)i;
-
- for (i = 0; i < 256; i++)
- {
- {
- UInt32 a1 = Sbox[i];
- UInt32 a2 = xtime(a1);
- UInt32 a3 = a2 ^ a1;
- TT(0)[i] = Ui32(a2, a1, a1, a3);
- TT(1)[i] = Ui32(a3, a2, a1, a1);
- TT(2)[i] = Ui32(a1, a3, a2, a1);
- TT(3)[i] = Ui32(a1, a1, a3, a2);
- }
- {
- UInt32 a1 = InvS[i];
- UInt32 a2 = xtime(a1);
- UInt32 a4 = xtime(a2);
- UInt32 a8 = xtime(a4);
- UInt32 a9 = a8 ^ a1;
- UInt32 aB = a8 ^ a2 ^ a1;
- UInt32 aD = a8 ^ a4 ^ a1;
- UInt32 aE = a8 ^ a4 ^ a2;
- DD(0)[i] = Ui32(aE, a9, aD, aB);
- DD(1)[i] = Ui32(aB, aE, a9, aD);
- DD(2)[i] = Ui32(aD, aB, aE, a9);
- DD(3)[i] = Ui32(a9, aD, aB, aE);
- }
- }
-
- g_AesCbc_Encode = AesCbc_Encode;
- g_AesCbc_Decode = AesCbc_Decode;
- g_AesCtr_Code = AesCtr_Code;
-
- #ifdef MY_CPU_X86_OR_AMD64
- if (CPU_Is_Aes_Supported())
- {
- g_AesCbc_Encode = AesCbc_Encode_Intel;
- g_AesCbc_Decode = AesCbc_Decode_Intel;
- g_AesCtr_Code = AesCtr_Code_Intel;
- }
- #endif
-}
-
-
-#define HT(i, x, s) TT(x)[gb(x, s[(i + x) & 3])]
-
-#define HT4(m, i, s, p) m[i] = \
- HT(i, 0, s) ^ \
- HT(i, 1, s) ^ \
- HT(i, 2, s) ^ \
- HT(i, 3, s) ^ w[p + i]
-
-#define HT16(m, s, p) \
- HT4(m, 0, s, p); \
- HT4(m, 1, s, p); \
- HT4(m, 2, s, p); \
- HT4(m, 3, s, p); \
-
-#define FT(i, x) Sbox[gb(x, m[(i + x) & 3])]
-#define FT4(i) dest[i] = Ui32(FT(i, 0), FT(i, 1), FT(i, 2), FT(i, 3)) ^ w[i];
-
-
-#define HD(i, x, s) DD(x)[gb(x, s[(i - x) & 3])]
-
-#define HD4(m, i, s, p) m[i] = \
- HD(i, 0, s) ^ \
- HD(i, 1, s) ^ \
- HD(i, 2, s) ^ \
- HD(i, 3, s) ^ w[p + i];
-
-#define HD16(m, s, p) \
- HD4(m, 0, s, p); \
- HD4(m, 1, s, p); \
- HD4(m, 2, s, p); \
- HD4(m, 3, s, p); \
-
-#define FD(i, x) InvS[gb(x, m[(i - x) & 3])]
-#define FD4(i) dest[i] = Ui32(FD(i, 0), FD(i, 1), FD(i, 2), FD(i, 3)) ^ w[i];
-
-void MY_FAST_CALL Aes_SetKey_Enc(UInt32 *w, const Byte *key, unsigned keySize)
-{
- unsigned i, wSize;
- wSize = keySize + 28;
- keySize /= 4;
- w[0] = ((UInt32)keySize / 2) + 3;
- w += 4;
-
- for (i = 0; i < keySize; i++, key += 4)
- w[i] = GetUi32(key);
-
- for (; i < wSize; i++)
- {
- UInt32 t = w[(size_t)i - 1];
- unsigned rem = i % keySize;
- if (rem == 0)
- t = Ui32(Sbox[gb1(t)] ^ Rcon[i / keySize], Sbox[gb2(t)], Sbox[gb3(t)], Sbox[gb0(t)]);
- else if (keySize > 6 && rem == 4)
- t = Ui32(Sbox[gb0(t)], Sbox[gb1(t)], Sbox[gb2(t)], Sbox[gb3(t)]);
- w[i] = w[i - keySize] ^ t;
- }
-}
-
-void MY_FAST_CALL Aes_SetKey_Dec(UInt32 *w, const Byte *key, unsigned keySize)
-{
- unsigned i, num;
- Aes_SetKey_Enc(w, key, keySize);
- num = keySize + 20;
- w += 8;
- for (i = 0; i < num; i++)
- {
- UInt32 r = w[i];
- w[i] =
- DD(0)[Sbox[gb0(r)]] ^
- DD(1)[Sbox[gb1(r)]] ^
- DD(2)[Sbox[gb2(r)]] ^
- DD(3)[Sbox[gb3(r)]];
- }
-}
-
-/* Aes_Encode and Aes_Decode functions work with little-endian words.
- src and dest are pointers to 4 UInt32 words.
- src and dest can point to same block */
-
-static void Aes_Encode(const UInt32 *w, UInt32 *dest, const UInt32 *src)
-{
- UInt32 s[4];
- UInt32 m[4];
- UInt32 numRounds2 = w[0];
- w += 4;
- s[0] = src[0] ^ w[0];
- s[1] = src[1] ^ w[1];
- s[2] = src[2] ^ w[2];
- s[3] = src[3] ^ w[3];
- w += 4;
- for (;;)
- {
- HT16(m, s, 0);
- if (--numRounds2 == 0)
- break;
- HT16(s, m, 4);
- w += 8;
- }
- w += 4;
- FT4(0); FT4(1); FT4(2); FT4(3);
-}
-
-static void Aes_Decode(const UInt32 *w, UInt32 *dest, const UInt32 *src)
-{
- UInt32 s[4];
- UInt32 m[4];
- UInt32 numRounds2 = w[0];
- w += 4 + numRounds2 * 8;
- s[0] = src[0] ^ w[0];
- s[1] = src[1] ^ w[1];
- s[2] = src[2] ^ w[2];
- s[3] = src[3] ^ w[3];
- for (;;)
- {
- w -= 8;
- HD16(m, s, 4);
- if (--numRounds2 == 0)
- break;
- HD16(s, m, 0);
- }
- FD4(0); FD4(1); FD4(2); FD4(3);
-}
-
-void AesCbc_Init(UInt32 *p, const Byte *iv)
-{
- unsigned i;
- for (i = 0; i < 4; i++)
- p[i] = GetUi32(iv + i * 4);
-}
-
-void MY_FAST_CALL AesCbc_Encode(UInt32 *p, Byte *data, size_t numBlocks)
-{
- for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE)
- {
- p[0] ^= GetUi32(data);
- p[1] ^= GetUi32(data + 4);
- p[2] ^= GetUi32(data + 8);
- p[3] ^= GetUi32(data + 12);
-
- Aes_Encode(p + 4, p, p);
-
- SetUi32(data, p[0]);
- SetUi32(data + 4, p[1]);
- SetUi32(data + 8, p[2]);
- SetUi32(data + 12, p[3]);
- }
-}
-
-void MY_FAST_CALL AesCbc_Decode(UInt32 *p, Byte *data, size_t numBlocks)
-{
- UInt32 in[4], out[4];
- for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE)
- {
- in[0] = GetUi32(data);
- in[1] = GetUi32(data + 4);
- in[2] = GetUi32(data + 8);
- in[3] = GetUi32(data + 12);
-
- Aes_Decode(p + 4, out, in);
-
- SetUi32(data, p[0] ^ out[0]);
- SetUi32(data + 4, p[1] ^ out[1]);
- SetUi32(data + 8, p[2] ^ out[2]);
- SetUi32(data + 12, p[3] ^ out[3]);
-
- p[0] = in[0];
- p[1] = in[1];
- p[2] = in[2];
- p[3] = in[3];
- }
-}
-
-void MY_FAST_CALL AesCtr_Code(UInt32 *p, Byte *data, size_t numBlocks)
-{
- for (; numBlocks != 0; numBlocks--)
- {
- UInt32 temp[4];
- unsigned i;
-
- if (++p[0] == 0)
- p[1]++;
-
- Aes_Encode(p + 4, temp, p);
-
- for (i = 0; i < 4; i++, data += 4)
- {
- UInt32 t = temp[i];
-
- #ifdef MY_CPU_LE_UNALIGN
- *((UInt32 *)data) ^= t;
- #else
- data[0] ^= (t & 0xFF);
- data[1] ^= ((t >> 8) & 0xFF);
- data[2] ^= ((t >> 16) & 0xFF);
- data[3] ^= ((t >> 24));
- #endif
- }
- }
-}
+/* Aes.c -- AES encryption / decryption
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "CpuArch.h"
+#include "Aes.h"
+
+AES_CODE_FUNC g_AesCbc_Decode;
+#ifndef Z7_SFX
+AES_CODE_FUNC g_AesCbc_Encode;
+AES_CODE_FUNC g_AesCtr_Code;
+UInt32 g_Aes_SupportedFunctions_Flags;
+#endif
+
+static UInt32 T[256 * 4];
+static const Byte Sbox[256] = {
+ 0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b, 0xfe, 0xd7, 0xab, 0x76,
+ 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0, 0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0,
+ 0xb7, 0xfd, 0x93, 0x26, 0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+ 0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2, 0xeb, 0x27, 0xb2, 0x75,
+ 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0, 0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84,
+ 0x53, 0xd1, 0x00, 0xed, 0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+ 0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f, 0x50, 0x3c, 0x9f, 0xa8,
+ 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5, 0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2,
+ 0xcd, 0x0c, 0x13, 0xec, 0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+ 0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14, 0xde, 0x5e, 0x0b, 0xdb,
+ 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c, 0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79,
+ 0xe7, 0xc8, 0x37, 0x6d, 0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+ 0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f, 0x4b, 0xbd, 0x8b, 0x8a,
+ 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e, 0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e,
+ 0xe1, 0xf8, 0x98, 0x11, 0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+ 0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f, 0xb0, 0x54, 0xbb, 0x16};
+
+
+static UInt32 D[256 * 4];
+static Byte InvS[256];
+
+#define xtime(x) ((((x) << 1) ^ (((x) & 0x80) != 0 ? 0x1B : 0)) & 0xFF)
+
+#define Ui32(a0, a1, a2, a3) ((UInt32)(a0) | ((UInt32)(a1) << 8) | ((UInt32)(a2) << 16) | ((UInt32)(a3) << 24))
+
+#define gb0(x) ( (x) & 0xFF)
+#define gb1(x) (((x) >> ( 8)) & 0xFF)
+#define gb2(x) (((x) >> (16)) & 0xFF)
+#define gb3(x) (((x) >> (24)))
+
+#define gb(n, x) gb ## n(x)
+
+#define TT(x) (T + (x << 8))
+#define DD(x) (D + (x << 8))
+
+
+// #define Z7_SHOW_AES_STATUS
+
+#ifdef MY_CPU_X86_OR_AMD64
+ #define USE_HW_AES
+#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE)
+ #if defined(__clang__)
+ #if (__clang_major__ >= 8) // fix that check
+ #define USE_HW_AES
+ #endif
+ #elif defined(__GNUC__)
+ #if (__GNUC__ >= 6) // fix that check
+ #define USE_HW_AES
+ #endif
+ #elif defined(_MSC_VER)
+ #if _MSC_VER >= 1910
+ #define USE_HW_AES
+ #endif
+ #endif
+#endif
+
+#ifdef USE_HW_AES
+#ifdef Z7_SHOW_AES_STATUS
+#include <stdio.h>
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+#endif
+
+
+void AesGenTables(void)
+{
+ unsigned i;
+ for (i = 0; i < 256; i++)
+ InvS[Sbox[i]] = (Byte)i;
+
+ for (i = 0; i < 256; i++)
+ {
+ {
+ const UInt32 a1 = Sbox[i];
+ const UInt32 a2 = xtime(a1);
+ const UInt32 a3 = a2 ^ a1;
+ TT(0)[i] = Ui32(a2, a1, a1, a3);
+ TT(1)[i] = Ui32(a3, a2, a1, a1);
+ TT(2)[i] = Ui32(a1, a3, a2, a1);
+ TT(3)[i] = Ui32(a1, a1, a3, a2);
+ }
+ {
+ const UInt32 a1 = InvS[i];
+ const UInt32 a2 = xtime(a1);
+ const UInt32 a4 = xtime(a2);
+ const UInt32 a8 = xtime(a4);
+ const UInt32 a9 = a8 ^ a1;
+ const UInt32 aB = a8 ^ a2 ^ a1;
+ const UInt32 aD = a8 ^ a4 ^ a1;
+ const UInt32 aE = a8 ^ a4 ^ a2;
+ DD(0)[i] = Ui32(aE, a9, aD, aB);
+ DD(1)[i] = Ui32(aB, aE, a9, aD);
+ DD(2)[i] = Ui32(aD, aB, aE, a9);
+ DD(3)[i] = Ui32(a9, aD, aB, aE);
+ }
+ }
+
+ {
+ AES_CODE_FUNC d = AesCbc_Decode;
+ #ifndef Z7_SFX
+ AES_CODE_FUNC e = AesCbc_Encode;
+ AES_CODE_FUNC c = AesCtr_Code;
+ UInt32 flags = 0;
+ #endif
+
+ #ifdef USE_HW_AES
+ if (CPU_IsSupported_AES())
+ {
+ // #pragma message ("AES HW")
+ PRF(printf("\n===AES HW\n"));
+ d = AesCbc_Decode_HW;
+
+ #ifndef Z7_SFX
+ e = AesCbc_Encode_HW;
+ c = AesCtr_Code_HW;
+ flags = k_Aes_SupportedFunctions_HW;
+ #endif
+
+ #ifdef MY_CPU_X86_OR_AMD64
+ if (CPU_IsSupported_VAES_AVX2())
+ {
+ PRF(printf("\n===vaes avx2\n"));
+ d = AesCbc_Decode_HW_256;
+ #ifndef Z7_SFX
+ c = AesCtr_Code_HW_256;
+ flags |= k_Aes_SupportedFunctions_HW_256;
+ #endif
+ }
+ #endif
+ }
+ #endif
+
+ g_AesCbc_Decode = d;
+ #ifndef Z7_SFX
+ g_AesCbc_Encode = e;
+ g_AesCtr_Code = c;
+ g_Aes_SupportedFunctions_Flags = flags;
+ #endif
+ }
+}
+
+
+#define HT(i, x, s) TT(x)[gb(x, s[(i + x) & 3])]
+
+#define HT4(m, i, s, p) m[i] = \
+ HT(i, 0, s) ^ \
+ HT(i, 1, s) ^ \
+ HT(i, 2, s) ^ \
+ HT(i, 3, s) ^ w[p + i]
+
+#define HT16(m, s, p) \
+ HT4(m, 0, s, p); \
+ HT4(m, 1, s, p); \
+ HT4(m, 2, s, p); \
+ HT4(m, 3, s, p); \
+
+#define FT(i, x) Sbox[gb(x, m[(i + x) & 3])]
+#define FT4(i) dest[i] = Ui32(FT(i, 0), FT(i, 1), FT(i, 2), FT(i, 3)) ^ w[i];
+
+
+#define HD(i, x, s) DD(x)[gb(x, s[(i - x) & 3])]
+
+#define HD4(m, i, s, p) m[i] = \
+ HD(i, 0, s) ^ \
+ HD(i, 1, s) ^ \
+ HD(i, 2, s) ^ \
+ HD(i, 3, s) ^ w[p + i];
+
+#define HD16(m, s, p) \
+ HD4(m, 0, s, p); \
+ HD4(m, 1, s, p); \
+ HD4(m, 2, s, p); \
+ HD4(m, 3, s, p); \
+
+#define FD(i, x) InvS[gb(x, m[(i - x) & 3])]
+#define FD4(i) dest[i] = Ui32(FD(i, 0), FD(i, 1), FD(i, 2), FD(i, 3)) ^ w[i];
+
+void Z7_FASTCALL Aes_SetKey_Enc(UInt32 *w, const Byte *key, unsigned keySize)
+{
+ unsigned i, m;
+ const UInt32 *wLim;
+ UInt32 t;
+ UInt32 rcon = 1;
+
+ keySize /= 4;
+ w[0] = ((UInt32)keySize / 2) + 3;
+ w += 4;
+
+ for (i = 0; i < keySize; i++, key += 4)
+ w[i] = GetUi32(key);
+
+ t = w[(size_t)keySize - 1];
+ wLim = w + (size_t)keySize * 3 + 28;
+ m = 0;
+ do
+ {
+ if (m == 0)
+ {
+ t = Ui32(Sbox[gb1(t)] ^ rcon, Sbox[gb2(t)], Sbox[gb3(t)], Sbox[gb0(t)]);
+ rcon <<= 1;
+ if (rcon & 0x100)
+ rcon = 0x1b;
+ m = keySize;
+ }
+ else if (m == 4 && keySize > 6)
+ t = Ui32(Sbox[gb0(t)], Sbox[gb1(t)], Sbox[gb2(t)], Sbox[gb3(t)]);
+ m--;
+ t ^= w[0];
+ w[keySize] = t;
+ }
+ while (++w != wLim);
+}
+
+void Z7_FASTCALL Aes_SetKey_Dec(UInt32 *w, const Byte *key, unsigned keySize)
+{
+ unsigned i, num;
+ Aes_SetKey_Enc(w, key, keySize);
+ num = keySize + 20;
+ w += 8;
+ for (i = 0; i < num; i++)
+ {
+ UInt32 r = w[i];
+ w[i] =
+ DD(0)[Sbox[gb0(r)]] ^
+ DD(1)[Sbox[gb1(r)]] ^
+ DD(2)[Sbox[gb2(r)]] ^
+ DD(3)[Sbox[gb3(r)]];
+ }
+}
+
+/* Aes_Encode and Aes_Decode functions work with little-endian words.
+ src and dest are pointers to 4 UInt32 words.
+ src and dest can point to same block */
+
+// Z7_FORCE_INLINE
+static void Aes_Encode(const UInt32 *w, UInt32 *dest, const UInt32 *src)
+{
+ UInt32 s[4];
+ UInt32 m[4];
+ UInt32 numRounds2 = w[0];
+ w += 4;
+ s[0] = src[0] ^ w[0];
+ s[1] = src[1] ^ w[1];
+ s[2] = src[2] ^ w[2];
+ s[3] = src[3] ^ w[3];
+ w += 4;
+ for (;;)
+ {
+ HT16(m, s, 0)
+ if (--numRounds2 == 0)
+ break;
+ HT16(s, m, 4)
+ w += 8;
+ }
+ w += 4;
+ FT4(0)
+ FT4(1)
+ FT4(2)
+ FT4(3)
+}
+
+Z7_FORCE_INLINE
+static void Aes_Decode(const UInt32 *w, UInt32 *dest, const UInt32 *src)
+{
+ UInt32 s[4];
+ UInt32 m[4];
+ UInt32 numRounds2 = w[0];
+ w += 4 + numRounds2 * 8;
+ s[0] = src[0] ^ w[0];
+ s[1] = src[1] ^ w[1];
+ s[2] = src[2] ^ w[2];
+ s[3] = src[3] ^ w[3];
+ for (;;)
+ {
+ w -= 8;
+ HD16(m, s, 4)
+ if (--numRounds2 == 0)
+ break;
+ HD16(s, m, 0)
+ }
+ FD4(0)
+ FD4(1)
+ FD4(2)
+ FD4(3)
+}
+
+void AesCbc_Init(UInt32 *p, const Byte *iv)
+{
+ unsigned i;
+ for (i = 0; i < 4; i++)
+ p[i] = GetUi32(iv + i * 4);
+}
+
+void Z7_FASTCALL AesCbc_Encode(UInt32 *p, Byte *data, size_t numBlocks)
+{
+ for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE)
+ {
+ p[0] ^= GetUi32(data);
+ p[1] ^= GetUi32(data + 4);
+ p[2] ^= GetUi32(data + 8);
+ p[3] ^= GetUi32(data + 12);
+
+ Aes_Encode(p + 4, p, p);
+
+ SetUi32(data, p[0])
+ SetUi32(data + 4, p[1])
+ SetUi32(data + 8, p[2])
+ SetUi32(data + 12, p[3])
+ }
+}
+
+void Z7_FASTCALL AesCbc_Decode(UInt32 *p, Byte *data, size_t numBlocks)
+{
+ UInt32 in[4], out[4];
+ for (; numBlocks != 0; numBlocks--, data += AES_BLOCK_SIZE)
+ {
+ in[0] = GetUi32(data);
+ in[1] = GetUi32(data + 4);
+ in[2] = GetUi32(data + 8);
+ in[3] = GetUi32(data + 12);
+
+ Aes_Decode(p + 4, out, in);
+
+ SetUi32(data, p[0] ^ out[0])
+ SetUi32(data + 4, p[1] ^ out[1])
+ SetUi32(data + 8, p[2] ^ out[2])
+ SetUi32(data + 12, p[3] ^ out[3])
+
+ p[0] = in[0];
+ p[1] = in[1];
+ p[2] = in[2];
+ p[3] = in[3];
+ }
+}
+
+void Z7_FASTCALL AesCtr_Code(UInt32 *p, Byte *data, size_t numBlocks)
+{
+ for (; numBlocks != 0; numBlocks--)
+ {
+ UInt32 temp[4];
+ unsigned i;
+
+ if (++p[0] == 0)
+ p[1]++;
+
+ Aes_Encode(p + 4, temp, p);
+
+ for (i = 0; i < 4; i++, data += 4)
+ {
+ const UInt32 t = temp[i];
+
+ #ifdef MY_CPU_LE_UNALIGN
+ *((UInt32 *)(void *)data) ^= t;
+ #else
+ data[0] = (Byte)(data[0] ^ (t & 0xFF));
+ data[1] = (Byte)(data[1] ^ ((t >> 8) & 0xFF));
+ data[2] = (Byte)(data[2] ^ ((t >> 16) & 0xFF));
+ data[3] = (Byte)(data[3] ^ ((t >> 24)));
+ #endif
+ }
+ }
+}
+
+#undef xtime
+#undef Ui32
+#undef gb0
+#undef gb1
+#undef gb2
+#undef gb3
+#undef gb
+#undef TT
+#undef DD
+#undef USE_HW_AES
+#undef PRF
diff --git a/C/Aes.h b/C/Aes.h
index 381e979..7f0182a 100644
--- a/C/Aes.h
+++ b/C/Aes.h
@@ -1,38 +1,60 @@
-/* Aes.h -- AES encryption / decryption
-2013-01-18 : Igor Pavlov : Public domain */
-
-#ifndef __AES_H
-#define __AES_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-#define AES_BLOCK_SIZE 16
-
-/* Call AesGenTables one time before other AES functions */
-void AesGenTables(void);
-
-/* UInt32 pointers must be 16-byte aligned */
-
-/* 16-byte (4 * 32-bit words) blocks: 1 (IV) + 1 (keyMode) + 15 (AES-256 roundKeys) */
-#define AES_NUM_IVMRK_WORDS ((1 + 1 + 15) * 4)
-
-/* aes - 16-byte aligned pointer to keyMode+roundKeys sequence */
-/* keySize = 16 or 24 or 32 (bytes) */
-typedef void (MY_FAST_CALL *AES_SET_KEY_FUNC)(UInt32 *aes, const Byte *key, unsigned keySize);
-void MY_FAST_CALL Aes_SetKey_Enc(UInt32 *aes, const Byte *key, unsigned keySize);
-void MY_FAST_CALL Aes_SetKey_Dec(UInt32 *aes, const Byte *key, unsigned keySize);
-
-/* ivAes - 16-byte aligned pointer to iv+keyMode+roundKeys sequence: UInt32[AES_NUM_IVMRK_WORDS] */
-void AesCbc_Init(UInt32 *ivAes, const Byte *iv); /* iv size is AES_BLOCK_SIZE */
-/* data - 16-byte aligned pointer to data */
-/* numBlocks - the number of 16-byte blocks in data array */
-typedef void (MY_FAST_CALL *AES_CODE_FUNC)(UInt32 *ivAes, Byte *data, size_t numBlocks);
-extern AES_CODE_FUNC g_AesCbc_Encode;
-extern AES_CODE_FUNC g_AesCbc_Decode;
-extern AES_CODE_FUNC g_AesCtr_Code;
-
-EXTERN_C_END
-
-#endif
+/* Aes.h -- AES encryption / decryption
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_AES_H
+#define ZIP7_INC_AES_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define AES_BLOCK_SIZE 16
+
+/* Call AesGenTables one time before other AES functions */
+void AesGenTables(void);
+
+/* UInt32 pointers must be 16-byte aligned */
+
+/* 16-byte (4 * 32-bit words) blocks: 1 (IV) + 1 (keyMode) + 15 (AES-256 roundKeys) */
+#define AES_NUM_IVMRK_WORDS ((1 + 1 + 15) * 4)
+
+/* aes - 16-byte aligned pointer to keyMode+roundKeys sequence */
+/* keySize = 16 or 24 or 32 (bytes) */
+typedef void (Z7_FASTCALL *AES_SET_KEY_FUNC)(UInt32 *aes, const Byte *key, unsigned keySize);
+void Z7_FASTCALL Aes_SetKey_Enc(UInt32 *aes, const Byte *key, unsigned keySize);
+void Z7_FASTCALL Aes_SetKey_Dec(UInt32 *aes, const Byte *key, unsigned keySize);
+
+/* ivAes - 16-byte aligned pointer to iv+keyMode+roundKeys sequence: UInt32[AES_NUM_IVMRK_WORDS] */
+void AesCbc_Init(UInt32 *ivAes, const Byte *iv); /* iv size is AES_BLOCK_SIZE */
+
+/* data - 16-byte aligned pointer to data */
+/* numBlocks - the number of 16-byte blocks in data array */
+typedef void (Z7_FASTCALL *AES_CODE_FUNC)(UInt32 *ivAes, Byte *data, size_t numBlocks);
+
+extern AES_CODE_FUNC g_AesCbc_Decode;
+#ifndef Z7_SFX
+extern AES_CODE_FUNC g_AesCbc_Encode;
+extern AES_CODE_FUNC g_AesCtr_Code;
+#define k_Aes_SupportedFunctions_HW (1 << 2)
+#define k_Aes_SupportedFunctions_HW_256 (1 << 3)
+extern UInt32 g_Aes_SupportedFunctions_Flags;
+#endif
+
+
+#define Z7_DECLARE_AES_CODE_FUNC(funcName) \
+ void Z7_FASTCALL funcName(UInt32 *ivAes, Byte *data, size_t numBlocks);
+
+Z7_DECLARE_AES_CODE_FUNC (AesCbc_Encode)
+Z7_DECLARE_AES_CODE_FUNC (AesCbc_Decode)
+Z7_DECLARE_AES_CODE_FUNC (AesCtr_Code)
+
+Z7_DECLARE_AES_CODE_FUNC (AesCbc_Encode_HW)
+Z7_DECLARE_AES_CODE_FUNC (AesCbc_Decode_HW)
+Z7_DECLARE_AES_CODE_FUNC (AesCtr_Code_HW)
+
+Z7_DECLARE_AES_CODE_FUNC (AesCbc_Decode_HW_256)
+Z7_DECLARE_AES_CODE_FUNC (AesCtr_Code_HW_256)
+
+EXTERN_C_END
+
+#endif
diff --git a/C/AesOpt.c b/C/AesOpt.c
index 0e7f49a..cfa6413 100644
--- a/C/AesOpt.c
+++ b/C/AesOpt.c
@@ -1,184 +1,840 @@
-/* AesOpt.c -- Intel's AES
-2017-06-08 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "CpuArch.h"
-
-#ifdef MY_CPU_X86_OR_AMD64
-#if (_MSC_VER > 1500) || (_MSC_FULL_VER >= 150030729)
-#define USE_INTEL_AES
-#endif
-#endif
-
-#ifdef USE_INTEL_AES
-
-#include <wmmintrin.h>
-
-void MY_FAST_CALL AesCbc_Encode_Intel(__m128i *p, __m128i *data, size_t numBlocks)
-{
- __m128i m = *p;
- for (; numBlocks != 0; numBlocks--, data++)
- {
- UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1;
- const __m128i *w = p + 3;
- m = _mm_xor_si128(m, *data);
- m = _mm_xor_si128(m, p[2]);
- do
- {
- m = _mm_aesenc_si128(m, w[0]);
- m = _mm_aesenc_si128(m, w[1]);
- w += 2;
- }
- while (--numRounds2 != 0);
- m = _mm_aesenc_si128(m, w[0]);
- m = _mm_aesenclast_si128(m, w[1]);
- *data = m;
- }
- *p = m;
-}
-
-#define NUM_WAYS 3
-
-#define AES_OP_W(op, n) { \
- const __m128i t = w[n]; \
- m0 = op(m0, t); \
- m1 = op(m1, t); \
- m2 = op(m2, t); \
- }
-
-#define AES_DEC(n) AES_OP_W(_mm_aesdec_si128, n)
-#define AES_DEC_LAST(n) AES_OP_W(_mm_aesdeclast_si128, n)
-#define AES_ENC(n) AES_OP_W(_mm_aesenc_si128, n)
-#define AES_ENC_LAST(n) AES_OP_W(_mm_aesenclast_si128, n)
-
-void MY_FAST_CALL AesCbc_Decode_Intel(__m128i *p, __m128i *data, size_t numBlocks)
-{
- __m128i iv = *p;
- for (; numBlocks >= NUM_WAYS; numBlocks -= NUM_WAYS, data += NUM_WAYS)
- {
- UInt32 numRounds2 = *(const UInt32 *)(p + 1);
- const __m128i *w = p + numRounds2 * 2;
- __m128i m0, m1, m2;
- {
- const __m128i t = w[2];
- m0 = _mm_xor_si128(t, data[0]);
- m1 = _mm_xor_si128(t, data[1]);
- m2 = _mm_xor_si128(t, data[2]);
- }
- numRounds2--;
- do
- {
- AES_DEC(1)
- AES_DEC(0)
- w -= 2;
- }
- while (--numRounds2 != 0);
- AES_DEC(1)
- AES_DEC_LAST(0)
-
- {
- __m128i t;
- t = _mm_xor_si128(m0, iv); iv = data[0]; data[0] = t;
- t = _mm_xor_si128(m1, iv); iv = data[1]; data[1] = t;
- t = _mm_xor_si128(m2, iv); iv = data[2]; data[2] = t;
- }
- }
- for (; numBlocks != 0; numBlocks--, data++)
- {
- UInt32 numRounds2 = *(const UInt32 *)(p + 1);
- const __m128i *w = p + numRounds2 * 2;
- __m128i m = _mm_xor_si128(w[2], *data);
- numRounds2--;
- do
- {
- m = _mm_aesdec_si128(m, w[1]);
- m = _mm_aesdec_si128(m, w[0]);
- w -= 2;
- }
- while (--numRounds2 != 0);
- m = _mm_aesdec_si128(m, w[1]);
- m = _mm_aesdeclast_si128(m, w[0]);
-
- m = _mm_xor_si128(m, iv);
- iv = *data;
- *data = m;
- }
- *p = iv;
-}
-
-void MY_FAST_CALL AesCtr_Code_Intel(__m128i *p, __m128i *data, size_t numBlocks)
-{
- __m128i ctr = *p;
- __m128i one;
- one.m128i_u64[0] = 1;
- one.m128i_u64[1] = 0;
- for (; numBlocks >= NUM_WAYS; numBlocks -= NUM_WAYS, data += NUM_WAYS)
- {
- UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1;
- const __m128i *w = p;
- __m128i m0, m1, m2;
- {
- const __m128i t = w[2];
- ctr = _mm_add_epi64(ctr, one); m0 = _mm_xor_si128(ctr, t);
- ctr = _mm_add_epi64(ctr, one); m1 = _mm_xor_si128(ctr, t);
- ctr = _mm_add_epi64(ctr, one); m2 = _mm_xor_si128(ctr, t);
- }
- w += 3;
- do
- {
- AES_ENC(0)
- AES_ENC(1)
- w += 2;
- }
- while (--numRounds2 != 0);
- AES_ENC(0)
- AES_ENC_LAST(1)
- data[0] = _mm_xor_si128(data[0], m0);
- data[1] = _mm_xor_si128(data[1], m1);
- data[2] = _mm_xor_si128(data[2], m2);
- }
- for (; numBlocks != 0; numBlocks--, data++)
- {
- UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1;
- const __m128i *w = p;
- __m128i m;
- ctr = _mm_add_epi64(ctr, one);
- m = _mm_xor_si128(ctr, p[2]);
- w += 3;
- do
- {
- m = _mm_aesenc_si128(m, w[0]);
- m = _mm_aesenc_si128(m, w[1]);
- w += 2;
- }
- while (--numRounds2 != 0);
- m = _mm_aesenc_si128(m, w[0]);
- m = _mm_aesenclast_si128(m, w[1]);
- *data = _mm_xor_si128(*data, m);
- }
- *p = ctr;
-}
-
-#else
-
-void MY_FAST_CALL AesCbc_Encode(UInt32 *ivAes, Byte *data, size_t numBlocks);
-void MY_FAST_CALL AesCbc_Decode(UInt32 *ivAes, Byte *data, size_t numBlocks);
-void MY_FAST_CALL AesCtr_Code(UInt32 *ivAes, Byte *data, size_t numBlocks);
-
-void MY_FAST_CALL AesCbc_Encode_Intel(UInt32 *p, Byte *data, size_t numBlocks)
-{
- AesCbc_Encode(p, data, numBlocks);
-}
-
-void MY_FAST_CALL AesCbc_Decode_Intel(UInt32 *p, Byte *data, size_t numBlocks)
-{
- AesCbc_Decode(p, data, numBlocks);
-}
-
-void MY_FAST_CALL AesCtr_Code_Intel(UInt32 *p, Byte *data, size_t numBlocks)
-{
- AesCtr_Code(p, data, numBlocks);
-}
-
-#endif
+/* AesOpt.c -- AES optimized code for x86 AES hardware instructions
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Aes.h"
+#include "CpuArch.h"
+
+#ifdef MY_CPU_X86_OR_AMD64
+
+ #if defined(__INTEL_COMPILER)
+ #if (__INTEL_COMPILER >= 1110)
+ #define USE_INTEL_AES
+ #if (__INTEL_COMPILER >= 1900)
+ #define USE_INTEL_VAES
+ #endif
+ #endif
+ #elif defined(__clang__) && (__clang_major__ > 3 || __clang_major__ == 3 && __clang_minor__ >= 8) \
+ || defined(__GNUC__) && (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 4)
+ #define USE_INTEL_AES
+ #if !defined(__AES__)
+ #define ATTRIB_AES __attribute__((__target__("aes")))
+ #endif
+ #if defined(__clang__) && (__clang_major__ >= 8) \
+ || defined(__GNUC__) && (__GNUC__ >= 8)
+ #define USE_INTEL_VAES
+ #if !defined(__AES__) || !defined(__VAES__) || !defined(__AVX__) || !defined(__AVX2__)
+ #define ATTRIB_VAES __attribute__((__target__("aes,vaes,avx,avx2")))
+ #endif
+ #endif
+ #elif defined(_MSC_VER)
+ #if (_MSC_VER > 1500) || (_MSC_FULL_VER >= 150030729)
+ #define USE_INTEL_AES
+ #if (_MSC_VER >= 1910)
+ #define USE_INTEL_VAES
+ #endif
+ #endif
+ #endif
+
+#ifndef ATTRIB_AES
+ #define ATTRIB_AES
+#endif
+#ifndef ATTRIB_VAES
+ #define ATTRIB_VAES
+#endif
+
+
+#ifdef USE_INTEL_AES
+
+#include <wmmintrin.h>
+
+#ifndef USE_INTEL_VAES
+#define AES_TYPE_keys UInt32
+#define AES_TYPE_data Byte
+// #define AES_TYPE_keys __m128i
+// #define AES_TYPE_data __m128i
+#endif
+
+#define AES_FUNC_START(name) \
+ void Z7_FASTCALL name(UInt32 *ivAes, Byte *data8, size_t numBlocks)
+ // void Z7_FASTCALL name(__m128i *p, __m128i *data, size_t numBlocks)
+
+#define AES_FUNC_START2(name) \
+AES_FUNC_START (name); \
+ATTRIB_AES \
+AES_FUNC_START (name)
+
+#define MM_OP(op, dest, src) dest = op(dest, src);
+#define MM_OP_m(op, src) MM_OP(op, m, src)
+
+#define MM_XOR( dest, src) MM_OP(_mm_xor_si128, dest, src)
+#define AVX_XOR(dest, src) MM_OP(_mm256_xor_si256, dest, src)
+
+
+AES_FUNC_START2 (AesCbc_Encode_HW)
+{
+ __m128i *p = (__m128i *)(void *)ivAes;
+ __m128i *data = (__m128i *)(void *)data8;
+ __m128i m = *p;
+ const __m128i k0 = p[2];
+ const __m128i k1 = p[3];
+ const UInt32 numRounds2 = *(const UInt32 *)(p + 1) - 1;
+ for (; numBlocks != 0; numBlocks--, data++)
+ {
+ UInt32 r = numRounds2;
+ const __m128i *w = p + 4;
+ __m128i temp = *data;
+ MM_XOR (temp, k0)
+ MM_XOR (m, temp)
+ MM_OP_m (_mm_aesenc_si128, k1)
+ do
+ {
+ MM_OP_m (_mm_aesenc_si128, w[0])
+ MM_OP_m (_mm_aesenc_si128, w[1])
+ w += 2;
+ }
+ while (--r);
+ MM_OP_m (_mm_aesenclast_si128, w[0])
+ *data = m;
+ }
+ *p = m;
+}
+
+
+#define WOP_1(op)
+#define WOP_2(op) WOP_1 (op) op (m1, 1)
+#define WOP_3(op) WOP_2 (op) op (m2, 2)
+#define WOP_4(op) WOP_3 (op) op (m3, 3)
+#ifdef MY_CPU_AMD64
+#define WOP_5(op) WOP_4 (op) op (m4, 4)
+#define WOP_6(op) WOP_5 (op) op (m5, 5)
+#define WOP_7(op) WOP_6 (op) op (m6, 6)
+#define WOP_8(op) WOP_7 (op) op (m7, 7)
+#endif
+/*
+#define WOP_9(op) WOP_8 (op) op (m8, 8);
+#define WOP_10(op) WOP_9 (op) op (m9, 9);
+#define WOP_11(op) WOP_10(op) op (m10, 10);
+#define WOP_12(op) WOP_11(op) op (m11, 11);
+#define WOP_13(op) WOP_12(op) op (m12, 12);
+#define WOP_14(op) WOP_13(op) op (m13, 13);
+*/
+
+#ifdef MY_CPU_AMD64
+ #define NUM_WAYS 8
+ #define WOP_M1 WOP_8
+#else
+ #define NUM_WAYS 4
+ #define WOP_M1 WOP_4
+#endif
+
+#define WOP(op) op (m0, 0) WOP_M1(op)
+
+
+#define DECLARE_VAR(reg, ii) __m128i reg;
+#define LOAD_data( reg, ii) reg = data[ii];
+#define STORE_data( reg, ii) data[ii] = reg;
+#if (NUM_WAYS > 1)
+#define XOR_data_M1(reg, ii) MM_XOR (reg, data[ii- 1])
+#endif
+
+#define AVX_DECLARE_VAR(reg, ii) __m256i reg;
+#define AVX_LOAD_data( reg, ii) reg = ((const __m256i *)(const void *)data)[ii];
+#define AVX_STORE_data( reg, ii) ((__m256i *)(void *)data)[ii] = reg;
+#define AVX_XOR_data_M1(reg, ii) AVX_XOR (reg, (((const __m256i *)(const void *)(data - 1))[ii]))
+
+#define MM_OP_key(op, reg) MM_OP(op, reg, key);
+
+#define AES_DEC( reg, ii) MM_OP_key (_mm_aesdec_si128, reg)
+#define AES_DEC_LAST( reg, ii) MM_OP_key (_mm_aesdeclast_si128, reg)
+#define AES_ENC( reg, ii) MM_OP_key (_mm_aesenc_si128, reg)
+#define AES_ENC_LAST( reg, ii) MM_OP_key (_mm_aesenclast_si128, reg)
+#define AES_XOR( reg, ii) MM_OP_key (_mm_xor_si128, reg)
+
+
+#define AVX_AES_DEC( reg, ii) MM_OP_key (_mm256_aesdec_epi128, reg)
+#define AVX_AES_DEC_LAST( reg, ii) MM_OP_key (_mm256_aesdeclast_epi128, reg)
+#define AVX_AES_ENC( reg, ii) MM_OP_key (_mm256_aesenc_epi128, reg)
+#define AVX_AES_ENC_LAST( reg, ii) MM_OP_key (_mm256_aesenclast_epi128, reg)
+#define AVX_AES_XOR( reg, ii) MM_OP_key (_mm256_xor_si256, reg)
+
+#define CTR_START(reg, ii) MM_OP (_mm_add_epi64, ctr, one) reg = ctr;
+#define CTR_END( reg, ii) MM_XOR (data[ii], reg)
+
+#define AVX_CTR_START(reg, ii) MM_OP (_mm256_add_epi64, ctr2, two) reg = _mm256_xor_si256(ctr2, key);
+#define AVX_CTR_END( reg, ii) AVX_XOR (((__m256i *)(void *)data)[ii], reg)
+
+#define WOP_KEY(op, n) { \
+ const __m128i key = w[n]; \
+ WOP(op); }
+
+#define AVX_WOP_KEY(op, n) { \
+ const __m256i key = w[n]; \
+ WOP(op); }
+
+
+#define WIDE_LOOP_START \
+ dataEnd = data + numBlocks; \
+ if (numBlocks >= NUM_WAYS) \
+ { dataEnd -= NUM_WAYS; do { \
+
+
+#define WIDE_LOOP_END \
+ data += NUM_WAYS; \
+ } while (data <= dataEnd); \
+ dataEnd += NUM_WAYS; } \
+
+
+#define SINGLE_LOOP \
+ for (; data < dataEnd; data++)
+
+
+#define NUM_AES_KEYS_MAX 15
+
+#define WIDE_LOOP_START_AVX(OP) \
+ dataEnd = data + numBlocks; \
+ if (numBlocks >= NUM_WAYS * 2) \
+ { __m256i keys[NUM_AES_KEYS_MAX]; \
+ UInt32 ii; \
+ OP \
+ for (ii = 0; ii < numRounds; ii++) \
+ keys[ii] = _mm256_broadcastsi128_si256(p[ii]); \
+ dataEnd -= NUM_WAYS * 2; do { \
+
+
+#define WIDE_LOOP_END_AVX(OP) \
+ data += NUM_WAYS * 2; \
+ } while (data <= dataEnd); \
+ dataEnd += NUM_WAYS * 2; \
+ OP \
+ _mm256_zeroupper(); \
+ } \
+
+/* MSVC for x86: If we don't call _mm256_zeroupper(), and -arch:IA32 is not specified,
+ MSVC still can insert vzeroupper instruction. */
+
+
+AES_FUNC_START2 (AesCbc_Decode_HW)
+{
+ __m128i *p = (__m128i *)(void *)ivAes;
+ __m128i *data = (__m128i *)(void *)data8;
+ __m128i iv = *p;
+ const __m128i *wStart = p + *(const UInt32 *)(p + 1) * 2 + 2 - 1;
+ const __m128i *dataEnd;
+ p += 2;
+
+ WIDE_LOOP_START
+ {
+ const __m128i *w = wStart;
+
+ WOP (DECLARE_VAR)
+ WOP (LOAD_data)
+ WOP_KEY (AES_XOR, 1)
+
+ do
+ {
+ WOP_KEY (AES_DEC, 0)
+ w--;
+ }
+ while (w != p);
+ WOP_KEY (AES_DEC_LAST, 0)
+
+ MM_XOR (m0, iv)
+ WOP_M1 (XOR_data_M1)
+ iv = data[NUM_WAYS - 1];
+ WOP (STORE_data)
+ }
+ WIDE_LOOP_END
+
+ SINGLE_LOOP
+ {
+ const __m128i *w = wStart - 1;
+ __m128i m = _mm_xor_si128 (w[2], *data);
+ do
+ {
+ MM_OP_m (_mm_aesdec_si128, w[1])
+ MM_OP_m (_mm_aesdec_si128, w[0])
+ w -= 2;
+ }
+ while (w != p);
+ MM_OP_m (_mm_aesdec_si128, w[1])
+ MM_OP_m (_mm_aesdeclast_si128, w[0])
+
+ MM_XOR (m, iv)
+ iv = *data;
+ *data = m;
+ }
+
+ p[-2] = iv;
+}
+
+
+AES_FUNC_START2 (AesCtr_Code_HW)
+{
+ __m128i *p = (__m128i *)(void *)ivAes;
+ __m128i *data = (__m128i *)(void *)data8;
+ __m128i ctr = *p;
+ UInt32 numRoundsMinus2 = *(const UInt32 *)(p + 1) * 2 - 1;
+ const __m128i *dataEnd;
+ __m128i one = _mm_cvtsi32_si128(1);
+
+ p += 2;
+
+ WIDE_LOOP_START
+ {
+ const __m128i *w = p;
+ UInt32 r = numRoundsMinus2;
+ WOP (DECLARE_VAR)
+ WOP (CTR_START)
+ WOP_KEY (AES_XOR, 0)
+ w += 1;
+ do
+ {
+ WOP_KEY (AES_ENC, 0)
+ w += 1;
+ }
+ while (--r);
+ WOP_KEY (AES_ENC_LAST, 0)
+
+ WOP (CTR_END)
+ }
+ WIDE_LOOP_END
+
+ SINGLE_LOOP
+ {
+ UInt32 numRounds2 = *(const UInt32 *)(p - 2 + 1) - 1;
+ const __m128i *w = p;
+ __m128i m;
+ MM_OP (_mm_add_epi64, ctr, one)
+ m = _mm_xor_si128 (ctr, p[0]);
+ w += 1;
+ do
+ {
+ MM_OP_m (_mm_aesenc_si128, w[0])
+ MM_OP_m (_mm_aesenc_si128, w[1])
+ w += 2;
+ }
+ while (--numRounds2);
+ MM_OP_m (_mm_aesenc_si128, w[0])
+ MM_OP_m (_mm_aesenclast_si128, w[1])
+ MM_XOR (*data, m)
+ }
+
+ p[-2] = ctr;
+}
+
+
+
+#ifdef USE_INTEL_VAES
+
+/*
+GCC before 2013-Jun:
+ <immintrin.h>:
+ #ifdef __AVX__
+ #include <avxintrin.h>
+ #endif
+GCC after 2013-Jun:
+ <immintrin.h>:
+ #include <avxintrin.h>
+CLANG 3.8+:
+{
+ <immintrin.h>:
+ #if !defined(_MSC_VER) || defined(__AVX__)
+ #include <avxintrin.h>
+ #endif
+
+ if (the compiler is clang for Windows and if global arch is not set for __AVX__)
+ [ if (defined(_MSC_VER) && !defined(__AVX__)) ]
+ {
+ <immintrin.h> doesn't include <avxintrin.h>
+ and we have 2 ways to fix it:
+ 1) we can define required __AVX__ before <immintrin.h>
+ or
+ 2) we can include <avxintrin.h> after <immintrin.h>
+ }
+}
+
+If we include <avxintrin.h> manually for GCC/CLANG, it's
+required that <immintrin.h> must be included before <avxintrin.h>.
+*/
+
+/*
+#if defined(__clang__) && defined(_MSC_VER)
+#define __AVX__
+#define __AVX2__
+#define __VAES__
+#endif
+*/
+
+#include <immintrin.h>
+#if defined(__clang__) && defined(_MSC_VER)
+ #if !defined(__AVX__)
+ #include <avxintrin.h>
+ #endif
+ #if !defined(__AVX2__)
+ #include <avx2intrin.h>
+ #endif
+ #if !defined(__VAES__)
+ #include <vaesintrin.h>
+ #endif
+#endif // __clang__ && _MSC_VER
+
+
+#define VAES_FUNC_START2(name) \
+AES_FUNC_START (name); \
+ATTRIB_VAES \
+AES_FUNC_START (name)
+
+VAES_FUNC_START2 (AesCbc_Decode_HW_256)
+{
+ __m128i *p = (__m128i *)(void *)ivAes;
+ __m128i *data = (__m128i *)(void *)data8;
+ __m128i iv = *p;
+ const __m128i *dataEnd;
+ UInt32 numRounds = *(const UInt32 *)(p + 1) * 2 + 1;
+ p += 2;
+
+ WIDE_LOOP_START_AVX(;)
+ {
+ const __m256i *w = keys + numRounds - 2;
+
+ WOP (AVX_DECLARE_VAR)
+ WOP (AVX_LOAD_data)
+ AVX_WOP_KEY (AVX_AES_XOR, 1)
+
+ do
+ {
+ AVX_WOP_KEY (AVX_AES_DEC, 0)
+ w--;
+ }
+ while (w != keys);
+ AVX_WOP_KEY (AVX_AES_DEC_LAST, 0)
+
+ AVX_XOR (m0, _mm256_setr_m128i(iv, data[0]))
+ WOP_M1 (AVX_XOR_data_M1)
+ iv = data[NUM_WAYS * 2 - 1];
+ WOP (AVX_STORE_data)
+ }
+ WIDE_LOOP_END_AVX(;)
+
+ SINGLE_LOOP
+ {
+ const __m128i *w = p + *(const UInt32 *)(p + 1 - 2) * 2 + 1 - 3;
+ __m128i m = _mm_xor_si128 (w[2], *data);
+ do
+ {
+ MM_OP_m (_mm_aesdec_si128, w[1])
+ MM_OP_m (_mm_aesdec_si128, w[0])
+ w -= 2;
+ }
+ while (w != p);
+ MM_OP_m (_mm_aesdec_si128, w[1])
+ MM_OP_m (_mm_aesdeclast_si128, w[0])
+
+ MM_XOR (m, iv)
+ iv = *data;
+ *data = m;
+ }
+
+ p[-2] = iv;
+}
+
+
+/*
+SSE2: _mm_cvtsi32_si128 : movd
+AVX: _mm256_setr_m128i : vinsertf128
+AVX2: _mm256_add_epi64 : vpaddq ymm, ymm, ymm
+ _mm256_extracti128_si256 : vextracti128
+ _mm256_broadcastsi128_si256 : vbroadcasti128
+*/
+
+#define AVX_CTR_LOOP_START \
+ ctr2 = _mm256_setr_m128i(_mm_sub_epi64(ctr, one), ctr); \
+ two = _mm256_setr_m128i(one, one); \
+ two = _mm256_add_epi64(two, two); \
+
+// two = _mm256_setr_epi64x(2, 0, 2, 0);
+
+#define AVX_CTR_LOOP_ENC \
+ ctr = _mm256_extracti128_si256 (ctr2, 1); \
+
+VAES_FUNC_START2 (AesCtr_Code_HW_256)
+{
+ __m128i *p = (__m128i *)(void *)ivAes;
+ __m128i *data = (__m128i *)(void *)data8;
+ __m128i ctr = *p;
+ UInt32 numRounds = *(const UInt32 *)(p + 1) * 2 + 1;
+ const __m128i *dataEnd;
+ __m128i one = _mm_cvtsi32_si128(1);
+ __m256i ctr2, two;
+ p += 2;
+
+ WIDE_LOOP_START_AVX (AVX_CTR_LOOP_START)
+ {
+ const __m256i *w = keys;
+ UInt32 r = numRounds - 2;
+ WOP (AVX_DECLARE_VAR)
+ AVX_WOP_KEY (AVX_CTR_START, 0)
+
+ w += 1;
+ do
+ {
+ AVX_WOP_KEY (AVX_AES_ENC, 0)
+ w += 1;
+ }
+ while (--r);
+ AVX_WOP_KEY (AVX_AES_ENC_LAST, 0)
+
+ WOP (AVX_CTR_END)
+ }
+ WIDE_LOOP_END_AVX (AVX_CTR_LOOP_ENC)
+
+ SINGLE_LOOP
+ {
+ UInt32 numRounds2 = *(const UInt32 *)(p - 2 + 1) - 1;
+ const __m128i *w = p;
+ __m128i m;
+ MM_OP (_mm_add_epi64, ctr, one)
+ m = _mm_xor_si128 (ctr, p[0]);
+ w += 1;
+ do
+ {
+ MM_OP_m (_mm_aesenc_si128, w[0])
+ MM_OP_m (_mm_aesenc_si128, w[1])
+ w += 2;
+ }
+ while (--numRounds2);
+ MM_OP_m (_mm_aesenc_si128, w[0])
+ MM_OP_m (_mm_aesenclast_si128, w[1])
+ MM_XOR (*data, m)
+ }
+
+ p[-2] = ctr;
+}
+
+#endif // USE_INTEL_VAES
+
+#else // USE_INTEL_AES
+
+/* no USE_INTEL_AES */
+
+#pragma message("AES HW_SW stub was used")
+
+#define AES_TYPE_keys UInt32
+#define AES_TYPE_data Byte
+
+#define AES_FUNC_START(name) \
+ void Z7_FASTCALL name(UInt32 *p, Byte *data, size_t numBlocks) \
+
+#define AES_COMPAT_STUB(name) \
+ AES_FUNC_START(name); \
+ AES_FUNC_START(name ## _HW) \
+ { name(p, data, numBlocks); }
+
+AES_COMPAT_STUB (AesCbc_Encode)
+AES_COMPAT_STUB (AesCbc_Decode)
+AES_COMPAT_STUB (AesCtr_Code)
+
+#endif // USE_INTEL_AES
+
+
+#ifndef USE_INTEL_VAES
+
+#pragma message("VAES HW_SW stub was used")
+
+#define VAES_COMPAT_STUB(name) \
+ void Z7_FASTCALL name ## _256(UInt32 *p, Byte *data, size_t numBlocks); \
+ void Z7_FASTCALL name ## _256(UInt32 *p, Byte *data, size_t numBlocks) \
+ { name((AES_TYPE_keys *)(void *)p, (AES_TYPE_data *)(void *)data, numBlocks); }
+
+VAES_COMPAT_STUB (AesCbc_Decode_HW)
+VAES_COMPAT_STUB (AesCtr_Code_HW)
+
+#endif // ! USE_INTEL_VAES
+
+
+#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE)
+
+ #if defined(__clang__)
+ #if (__clang_major__ >= 8) // fix that check
+ #define USE_HW_AES
+ #endif
+ #elif defined(__GNUC__)
+ #if (__GNUC__ >= 6) // fix that check
+ #define USE_HW_AES
+ #endif
+ #elif defined(_MSC_VER)
+ #if _MSC_VER >= 1910
+ #define USE_HW_AES
+ #endif
+ #endif
+
+#ifdef USE_HW_AES
+
+// #pragma message("=== AES HW === ")
+
+#if defined(__clang__) || defined(__GNUC__)
+ #ifdef MY_CPU_ARM64
+ #define ATTRIB_AES __attribute__((__target__("+crypto")))
+ #else
+ #define ATTRIB_AES __attribute__((__target__("fpu=crypto-neon-fp-armv8")))
+ #endif
+#else
+ // _MSC_VER
+ // for arm32
+ #define _ARM_USE_NEW_NEON_INTRINSICS
+#endif
+
+#ifndef ATTRIB_AES
+ #define ATTRIB_AES
+#endif
+
+#if defined(_MSC_VER) && defined(MY_CPU_ARM64)
+#include <arm64_neon.h>
+#else
+#include <arm_neon.h>
+#endif
+
+typedef uint8x16_t v128;
+
+#define AES_FUNC_START(name) \
+ void Z7_FASTCALL name(UInt32 *ivAes, Byte *data8, size_t numBlocks)
+ // void Z7_FASTCALL name(v128 *p, v128 *data, size_t numBlocks)
+
+#define AES_FUNC_START2(name) \
+AES_FUNC_START (name); \
+ATTRIB_AES \
+AES_FUNC_START (name)
+
+#define MM_OP(op, dest, src) dest = op(dest, src);
+#define MM_OP_m(op, src) MM_OP(op, m, src)
+#define MM_OP1_m(op) m = op(m);
+
+#define MM_XOR( dest, src) MM_OP(veorq_u8, dest, src)
+#define MM_XOR_m( src) MM_XOR(m, src)
+
+#define AES_E_m(k) MM_OP_m (vaeseq_u8, k)
+#define AES_E_MC_m(k) AES_E_m (k) MM_OP1_m(vaesmcq_u8)
+
+
+AES_FUNC_START2 (AesCbc_Encode_HW)
+{
+ v128 *p = (v128*)(void*)ivAes;
+ v128 *data = (v128*)(void*)data8;
+ v128 m = *p;
+ const v128 k0 = p[2];
+ const v128 k1 = p[3];
+ const v128 k2 = p[4];
+ const v128 k3 = p[5];
+ const v128 k4 = p[6];
+ const v128 k5 = p[7];
+ const v128 k6 = p[8];
+ const v128 k7 = p[9];
+ const v128 k8 = p[10];
+ const v128 k9 = p[11];
+ const UInt32 numRounds2 = *(const UInt32 *)(p + 1);
+ const v128 *w = p + ((size_t)numRounds2 * 2);
+ const v128 k_z1 = w[1];
+ const v128 k_z0 = w[2];
+ for (; numBlocks != 0; numBlocks--, data++)
+ {
+ MM_XOR_m (*data);
+ AES_E_MC_m (k0)
+ AES_E_MC_m (k1)
+ AES_E_MC_m (k2)
+ AES_E_MC_m (k3)
+ AES_E_MC_m (k4)
+ AES_E_MC_m (k5)
+ AES_E_MC_m (k6)
+ AES_E_MC_m (k7)
+ AES_E_MC_m (k8)
+ if (numRounds2 >= 6)
+ {
+ AES_E_MC_m (k9)
+ AES_E_MC_m (p[12])
+ if (numRounds2 != 6)
+ {
+ AES_E_MC_m (p[13])
+ AES_E_MC_m (p[14])
+ }
+ }
+ AES_E_m (k_z1)
+ MM_XOR_m (k_z0);
+ *data = m;
+ }
+ *p = m;
+}
+
+
+#define WOP_1(op)
+#define WOP_2(op) WOP_1 (op) op (m1, 1)
+#define WOP_3(op) WOP_2 (op) op (m2, 2)
+#define WOP_4(op) WOP_3 (op) op (m3, 3)
+#define WOP_5(op) WOP_4 (op) op (m4, 4)
+#define WOP_6(op) WOP_5 (op) op (m5, 5)
+#define WOP_7(op) WOP_6 (op) op (m6, 6)
+#define WOP_8(op) WOP_7 (op) op (m7, 7)
+
+ #define NUM_WAYS 8
+ #define WOP_M1 WOP_8
+
+#define WOP(op) op (m0, 0) WOP_M1(op)
+
+#define DECLARE_VAR(reg, ii) v128 reg;
+#define LOAD_data( reg, ii) reg = data[ii];
+#define STORE_data( reg, ii) data[ii] = reg;
+#if (NUM_WAYS > 1)
+#define XOR_data_M1(reg, ii) MM_XOR (reg, data[ii- 1])
+#endif
+
+#define MM_OP_key(op, reg) MM_OP (op, reg, key)
+
+#define AES_D_m(k) MM_OP_m (vaesdq_u8, k)
+#define AES_D_IMC_m(k) AES_D_m (k) MM_OP1_m (vaesimcq_u8)
+
+#define AES_XOR( reg, ii) MM_OP_key (veorq_u8, reg)
+#define AES_D( reg, ii) MM_OP_key (vaesdq_u8, reg)
+#define AES_E( reg, ii) MM_OP_key (vaeseq_u8, reg)
+
+#define AES_D_IMC( reg, ii) AES_D (reg, ii) reg = vaesimcq_u8(reg);
+#define AES_E_MC( reg, ii) AES_E (reg, ii) reg = vaesmcq_u8(reg);
+
+#define CTR_START(reg, ii) MM_OP (vaddq_u64, ctr, one) reg = vreinterpretq_u8_u64(ctr);
+#define CTR_END( reg, ii) MM_XOR (data[ii], reg)
+
+#define WOP_KEY(op, n) { \
+ const v128 key = w[n]; \
+ WOP(op) }
+
+#define WIDE_LOOP_START \
+ dataEnd = data + numBlocks; \
+ if (numBlocks >= NUM_WAYS) \
+ { dataEnd -= NUM_WAYS; do { \
+
+#define WIDE_LOOP_END \
+ data += NUM_WAYS; \
+ } while (data <= dataEnd); \
+ dataEnd += NUM_WAYS; } \
+
+#define SINGLE_LOOP \
+ for (; data < dataEnd; data++)
+
+
+AES_FUNC_START2 (AesCbc_Decode_HW)
+{
+ v128 *p = (v128*)(void*)ivAes;
+ v128 *data = (v128*)(void*)data8;
+ v128 iv = *p;
+ const v128 *wStart = p + ((size_t)*(const UInt32 *)(p + 1)) * 2;
+ const v128 *dataEnd;
+ p += 2;
+
+ WIDE_LOOP_START
+ {
+ const v128 *w = wStart;
+ WOP (DECLARE_VAR)
+ WOP (LOAD_data)
+ WOP_KEY (AES_D_IMC, 2)
+ do
+ {
+ WOP_KEY (AES_D_IMC, 1)
+ WOP_KEY (AES_D_IMC, 0)
+ w -= 2;
+ }
+ while (w != p);
+ WOP_KEY (AES_D, 1)
+ WOP_KEY (AES_XOR, 0)
+ MM_XOR (m0, iv);
+ WOP_M1 (XOR_data_M1)
+ iv = data[NUM_WAYS - 1];
+ WOP (STORE_data)
+ }
+ WIDE_LOOP_END
+
+ SINGLE_LOOP
+ {
+ const v128 *w = wStart;
+ v128 m = *data;
+ AES_D_IMC_m (w[2])
+ do
+ {
+ AES_D_IMC_m (w[1]);
+ AES_D_IMC_m (w[0]);
+ w -= 2;
+ }
+ while (w != p);
+ AES_D_m (w[1]);
+ MM_XOR_m (w[0]);
+ MM_XOR_m (iv);
+ iv = *data;
+ *data = m;
+ }
+
+ p[-2] = iv;
+}
+
+
+AES_FUNC_START2 (AesCtr_Code_HW)
+{
+ v128 *p = (v128*)(void*)ivAes;
+ v128 *data = (v128*)(void*)data8;
+ uint64x2_t ctr = vreinterpretq_u64_u8(*p);
+ const v128 *wEnd = p + ((size_t)*(const UInt32 *)(p + 1)) * 2;
+ const v128 *dataEnd;
+ uint64x2_t one = vdupq_n_u64(0);
+ one = vsetq_lane_u64(1, one, 0);
+ p += 2;
+
+ WIDE_LOOP_START
+ {
+ const v128 *w = p;
+ WOP (DECLARE_VAR)
+ WOP (CTR_START)
+ do
+ {
+ WOP_KEY (AES_E_MC, 0)
+ WOP_KEY (AES_E_MC, 1)
+ w += 2;
+ }
+ while (w != wEnd);
+ WOP_KEY (AES_E_MC, 0)
+ WOP_KEY (AES_E, 1)
+ WOP_KEY (AES_XOR, 2)
+ WOP (CTR_END)
+ }
+ WIDE_LOOP_END
+
+ SINGLE_LOOP
+ {
+ const v128 *w = p;
+ v128 m;
+ CTR_START (m, 0);
+ do
+ {
+ AES_E_MC_m (w[0]);
+ AES_E_MC_m (w[1]);
+ w += 2;
+ }
+ while (w != wEnd);
+ AES_E_MC_m (w[0])
+ AES_E_m (w[1])
+ MM_XOR_m (w[2])
+ CTR_END (m, 0)
+ }
+
+ p[-2] = vreinterpretq_u8_u64(ctr);
+}
+
+#endif // USE_HW_AES
+
+#endif // MY_CPU_ARM_OR_ARM64
+
+#undef NUM_WAYS
+#undef WOP_M1
+#undef WOP
+#undef DECLARE_VAR
+#undef LOAD_data
+#undef STORE_data
+#undef USE_INTEL_AES
+#undef USE_HW_AES
diff --git a/C/Alloc.c b/C/Alloc.c
index 30b499e..d841bf2 100644
--- a/C/Alloc.c
+++ b/C/Alloc.c
@@ -1,455 +1,535 @@
-/* Alloc.c -- Memory allocation functions
-2018-04-27 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include <stdio.h>
-
-#ifdef _WIN32
-#include <windows.h>
-#endif
-#include <stdlib.h>
-
-#include "Alloc.h"
-
-/* #define _SZ_ALLOC_DEBUG */
-
-/* use _SZ_ALLOC_DEBUG to debug alloc/free operations */
-#ifdef _SZ_ALLOC_DEBUG
-
-#include <stdio.h>
-int g_allocCount = 0;
-int g_allocCountMid = 0;
-int g_allocCountBig = 0;
-
-
-#define CONVERT_INT_TO_STR(charType, tempSize) \
- unsigned char temp[tempSize]; unsigned i = 0; \
- while (val >= 10) { temp[i++] = (unsigned char)('0' + (unsigned)(val % 10)); val /= 10; } \
- *s++ = (charType)('0' + (unsigned)val); \
- while (i != 0) { i--; *s++ = temp[i]; } \
- *s = 0;
-
-static void ConvertUInt64ToString(UInt64 val, char *s)
-{
- CONVERT_INT_TO_STR(char, 24);
-}
-
-#define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))))
-
-static void ConvertUInt64ToHex(UInt64 val, char *s)
-{
- UInt64 v = val;
- unsigned i;
- for (i = 1;; i++)
- {
- v >>= 4;
- if (v == 0)
- break;
- }
- s[i] = 0;
- do
- {
- unsigned t = (unsigned)(val & 0xF);
- val >>= 4;
- s[--i] = GET_HEX_CHAR(t);
- }
- while (i);
-}
-
-#define DEBUG_OUT_STREAM stderr
-
-static void Print(const char *s)
-{
- fputs(s, DEBUG_OUT_STREAM);
-}
-
-static void PrintAligned(const char *s, size_t align)
-{
- size_t len = strlen(s);
- for(;;)
- {
- fputc(' ', DEBUG_OUT_STREAM);
- if (len >= align)
- break;
- ++len;
- }
- Print(s);
-}
-
-static void PrintLn()
-{
- Print("\n");
-}
-
-static void PrintHex(UInt64 v, size_t align)
-{
- char s[32];
- ConvertUInt64ToHex(v, s);
- PrintAligned(s, align);
-}
-
-static void PrintDec(UInt64 v, size_t align)
-{
- char s[32];
- ConvertUInt64ToString(v, s);
- PrintAligned(s, align);
-}
-
-static void PrintAddr(void *p)
-{
- PrintHex((UInt64)(size_t)(ptrdiff_t)p, 12);
-}
-
-
-#define PRINT_ALLOC(name, cnt, size, ptr) \
- Print(name " "); \
- PrintDec(cnt++, 10); \
- PrintHex(size, 10); \
- PrintAddr(ptr); \
- PrintLn();
-
-#define PRINT_FREE(name, cnt, ptr) if (ptr) { \
- Print(name " "); \
- PrintDec(--cnt, 10); \
- PrintAddr(ptr); \
- PrintLn(); }
-
-#else
-
-#define PRINT_ALLOC(name, cnt, size, ptr)
-#define PRINT_FREE(name, cnt, ptr)
-#define Print(s)
-#define PrintLn()
-#define PrintHex(v, align)
-#define PrintDec(v, align)
-#define PrintAddr(p)
-
-#endif
-
-
-
-void *MyAlloc(size_t size)
-{
- if (size == 0)
- return NULL;
- #ifdef _SZ_ALLOC_DEBUG
- {
- void *p = malloc(size);
- PRINT_ALLOC("Alloc ", g_allocCount, size, p);
- return p;
- }
- #else
- return malloc(size);
- #endif
-}
-
-void MyFree(void *address)
-{
- PRINT_FREE("Free ", g_allocCount, address);
-
- free(address);
-}
-
-#ifdef _WIN32
-
-void *MidAlloc(size_t size)
-{
- if (size == 0)
- return NULL;
-
- PRINT_ALLOC("Alloc-Mid", g_allocCountMid, size, NULL);
-
- return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
-}
-
-void MidFree(void *address)
-{
- PRINT_FREE("Free-Mid", g_allocCountMid, address);
-
- if (!address)
- return;
- VirtualFree(address, 0, MEM_RELEASE);
-}
-
-#ifndef MEM_LARGE_PAGES
-#undef _7ZIP_LARGE_PAGES
-#endif
-
-#ifdef _7ZIP_LARGE_PAGES
-SIZE_T g_LargePageSize = 0;
-typedef SIZE_T (WINAPI *GetLargePageMinimumP)();
-#endif
-
-void SetLargePageSize()
-{
- #ifdef _7ZIP_LARGE_PAGES
- SIZE_T size;
- GetLargePageMinimumP largePageMinimum = (GetLargePageMinimumP)
- GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "GetLargePageMinimum");
- if (!largePageMinimum)
- return;
- size = largePageMinimum();
- if (size == 0 || (size & (size - 1)) != 0)
- return;
- g_LargePageSize = size;
- #endif
-}
-
-
-void *BigAlloc(size_t size)
-{
- if (size == 0)
- return NULL;
-
- PRINT_ALLOC("Alloc-Big", g_allocCountBig, size, NULL);
-
- #ifdef _7ZIP_LARGE_PAGES
- {
- SIZE_T ps = g_LargePageSize;
- if (ps != 0 && ps <= (1 << 30) && size > (ps / 2))
- {
- size_t size2;
- ps--;
- size2 = (size + ps) & ~ps;
- if (size2 >= size)
- {
- void *res = VirtualAlloc(NULL, size2, MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE);
- if (res)
- return res;
- }
- }
- }
- #endif
-
- return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
-}
-
-void BigFree(void *address)
-{
- PRINT_FREE("Free-Big", g_allocCountBig, address);
-
- if (!address)
- return;
- VirtualFree(address, 0, MEM_RELEASE);
-}
-
-#endif
-
-
-static void *SzAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MyAlloc(size); }
-static void SzFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MyFree(address); }
-const ISzAlloc g_Alloc = { SzAlloc, SzFree };
-
-static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return MidAlloc(size); }
-static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); MidFree(address); }
-const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree };
-
-static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p); return BigAlloc(size); }
-static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p); BigFree(address); }
-const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
-
-
-/*
- uintptr_t : <stdint.h> C99 (optional)
- : unsupported in VS6
-*/
-
-#ifdef _WIN32
- typedef UINT_PTR UIntPtr;
-#else
- /*
- typedef uintptr_t UIntPtr;
- */
- typedef ptrdiff_t UIntPtr;
-#endif
-
-
-#define ADJUST_ALLOC_SIZE 0
-/*
-#define ADJUST_ALLOC_SIZE (sizeof(void *) - 1)
-*/
-/*
- Use (ADJUST_ALLOC_SIZE = (sizeof(void *) - 1)), if
- MyAlloc() can return address that is NOT multiple of sizeof(void *).
-*/
-
-
-/*
-#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((char *)(p) - ((size_t)(UIntPtr)(p) & ((align) - 1))))
-*/
-#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((((UIntPtr)(p)) & ~((UIntPtr)(align) - 1))))
-
-#define MY_ALIGN_PTR_UP_PLUS(p, align) MY_ALIGN_PTR_DOWN(((char *)(p) + (align) + ADJUST_ALLOC_SIZE), align)
-
-
-#if (_POSIX_C_SOURCE >= 200112L) && !defined(_WIN32)
- #define USE_posix_memalign
-#endif
-
-/*
- This posix_memalign() is for test purposes only.
- We also need special Free() function instead of free(),
- if this posix_memalign() is used.
-*/
-
-/*
-static int posix_memalign(void **ptr, size_t align, size_t size)
-{
- size_t newSize = size + align;
- void *p;
- void *pAligned;
- *ptr = NULL;
- if (newSize < size)
- return 12; // ENOMEM
- p = MyAlloc(newSize);
- if (!p)
- return 12; // ENOMEM
- pAligned = MY_ALIGN_PTR_UP_PLUS(p, align);
- ((void **)pAligned)[-1] = p;
- *ptr = pAligned;
- return 0;
-}
-*/
-
-/*
- ALLOC_ALIGN_SIZE >= sizeof(void *)
- ALLOC_ALIGN_SIZE >= cache_line_size
-*/
-
-#define ALLOC_ALIGN_SIZE ((size_t)1 << 7)
-
-static void *SzAlignedAlloc(ISzAllocPtr pp, size_t size)
-{
- #ifndef USE_posix_memalign
-
- void *p;
- void *pAligned;
- size_t newSize;
- UNUSED_VAR(pp);
-
- /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned
- block to prevent cache line sharing with another allocated blocks */
-
- newSize = size + ALLOC_ALIGN_SIZE * 1 + ADJUST_ALLOC_SIZE;
- if (newSize < size)
- return NULL;
-
- p = MyAlloc(newSize);
-
- if (!p)
- return NULL;
- pAligned = MY_ALIGN_PTR_UP_PLUS(p, ALLOC_ALIGN_SIZE);
-
- Print(" size="); PrintHex(size, 8);
- Print(" a_size="); PrintHex(newSize, 8);
- Print(" ptr="); PrintAddr(p);
- Print(" a_ptr="); PrintAddr(pAligned);
- PrintLn();
-
- ((void **)pAligned)[-1] = p;
-
- return pAligned;
-
- #else
-
- void *p;
- UNUSED_VAR(pp);
- if (posix_memalign(&p, ALLOC_ALIGN_SIZE, size))
- return NULL;
-
- Print(" posix_memalign="); PrintAddr(p);
- PrintLn();
-
- return p;
-
- #endif
-}
-
-
-static void SzAlignedFree(ISzAllocPtr pp, void *address)
-{
- UNUSED_VAR(pp);
- #ifndef USE_posix_memalign
- if (address)
- MyFree(((void **)address)[-1]);
- #else
- free(address);
- #endif
-}
-
-
-const ISzAlloc g_AlignedAlloc = { SzAlignedAlloc, SzAlignedFree };
-
-
-
-#define MY_ALIGN_PTR_DOWN_1(p) MY_ALIGN_PTR_DOWN(p, sizeof(void *))
-
-/* we align ptr to support cases where CAlignOffsetAlloc::offset is not multiply of sizeof(void *) */
-#define REAL_BLOCK_PTR_VAR(p) ((void **)MY_ALIGN_PTR_DOWN_1(p))[-1]
-/*
-#define REAL_BLOCK_PTR_VAR(p) ((void **)(p))[-1]
-*/
-
-static void *AlignOffsetAlloc_Alloc(ISzAllocPtr pp, size_t size)
-{
- CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt);
- void *adr;
- void *pAligned;
- size_t newSize;
- size_t extra;
- size_t alignSize = (size_t)1 << p->numAlignBits;
-
- if (alignSize < sizeof(void *))
- alignSize = sizeof(void *);
-
- if (p->offset >= alignSize)
- return NULL;
-
- /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned
- block to prevent cache line sharing with another allocated blocks */
- extra = p->offset & (sizeof(void *) - 1);
- newSize = size + alignSize + extra + ADJUST_ALLOC_SIZE;
- if (newSize < size)
- return NULL;
-
- adr = ISzAlloc_Alloc(p->baseAlloc, newSize);
-
- if (!adr)
- return NULL;
-
- pAligned = (char *)MY_ALIGN_PTR_DOWN((char *)adr +
- alignSize - p->offset + extra + ADJUST_ALLOC_SIZE, alignSize) + p->offset;
-
- PrintLn();
- Print("- Aligned: ");
- Print(" size="); PrintHex(size, 8);
- Print(" a_size="); PrintHex(newSize, 8);
- Print(" ptr="); PrintAddr(adr);
- Print(" a_ptr="); PrintAddr(pAligned);
- PrintLn();
-
- REAL_BLOCK_PTR_VAR(pAligned) = adr;
-
- return pAligned;
-}
-
-
-static void AlignOffsetAlloc_Free(ISzAllocPtr pp, void *address)
-{
- if (address)
- {
- CAlignOffsetAlloc *p = CONTAINER_FROM_VTBL(pp, CAlignOffsetAlloc, vt);
- PrintLn();
- Print("- Aligned Free: ");
- PrintLn();
- ISzAlloc_Free(p->baseAlloc, REAL_BLOCK_PTR_VAR(address));
- }
-}
-
-
-void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p)
-{
- p->vt.Alloc = AlignOffsetAlloc_Alloc;
- p->vt.Free = AlignOffsetAlloc_Free;
-}
+/* Alloc.c -- Memory allocation functions
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#ifdef _WIN32
+#include "7zWindows.h"
+#endif
+#include <stdlib.h>
+
+#include "Alloc.h"
+
+#ifdef _WIN32
+#ifdef Z7_LARGE_PAGES
+#if defined(__clang__) || defined(__GNUC__)
+typedef void (*Z7_voidFunction)(void);
+#define MY_CAST_FUNC (Z7_voidFunction)
+#elif defined(_MSC_VER) && _MSC_VER > 1920
+#define MY_CAST_FUNC (void *)
+// #pragma warning(disable : 4191) // 'type cast': unsafe conversion from 'FARPROC' to 'void (__cdecl *)()'
+#else
+#define MY_CAST_FUNC
+#endif
+#endif // Z7_LARGE_PAGES
+#endif // _WIN32
+
+// #define SZ_ALLOC_DEBUG
+/* #define SZ_ALLOC_DEBUG */
+
+/* use SZ_ALLOC_DEBUG to debug alloc/free operations */
+#ifdef SZ_ALLOC_DEBUG
+
+#include <string.h>
+#include <stdio.h>
+static int g_allocCount = 0;
+#ifdef _WIN32
+static int g_allocCountMid = 0;
+static int g_allocCountBig = 0;
+#endif
+
+
+#define CONVERT_INT_TO_STR(charType, tempSize) \
+ char temp[tempSize]; unsigned i = 0; \
+ while (val >= 10) { temp[i++] = (char)('0' + (unsigned)(val % 10)); val /= 10; } \
+ *s++ = (charType)('0' + (unsigned)val); \
+ while (i != 0) { i--; *s++ = temp[i]; } \
+ *s = 0;
+
+static void ConvertUInt64ToString(UInt64 val, char *s)
+{
+ CONVERT_INT_TO_STR(char, 24)
+}
+
+#define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))))
+
+static void ConvertUInt64ToHex(UInt64 val, char *s)
+{
+ UInt64 v = val;
+ unsigned i;
+ for (i = 1;; i++)
+ {
+ v >>= 4;
+ if (v == 0)
+ break;
+ }
+ s[i] = 0;
+ do
+ {
+ unsigned t = (unsigned)(val & 0xF);
+ val >>= 4;
+ s[--i] = GET_HEX_CHAR(t);
+ }
+ while (i);
+}
+
+#define DEBUG_OUT_STREAM stderr
+
+static void Print(const char *s)
+{
+ fputs(s, DEBUG_OUT_STREAM);
+}
+
+static void PrintAligned(const char *s, size_t align)
+{
+ size_t len = strlen(s);
+ for(;;)
+ {
+ fputc(' ', DEBUG_OUT_STREAM);
+ if (len >= align)
+ break;
+ ++len;
+ }
+ Print(s);
+}
+
+static void PrintLn(void)
+{
+ Print("\n");
+}
+
+static void PrintHex(UInt64 v, size_t align)
+{
+ char s[32];
+ ConvertUInt64ToHex(v, s);
+ PrintAligned(s, align);
+}
+
+static void PrintDec(int v, size_t align)
+{
+ char s[32];
+ ConvertUInt64ToString((unsigned)v, s);
+ PrintAligned(s, align);
+}
+
+static void PrintAddr(void *p)
+{
+ PrintHex((UInt64)(size_t)(ptrdiff_t)p, 12);
+}
+
+
+#define PRINT_REALLOC(name, cnt, size, ptr) { \
+ Print(name " "); \
+ if (!ptr) PrintDec(cnt++, 10); \
+ PrintHex(size, 10); \
+ PrintAddr(ptr); \
+ PrintLn(); }
+
+#define PRINT_ALLOC(name, cnt, size, ptr) { \
+ Print(name " "); \
+ PrintDec(cnt++, 10); \
+ PrintHex(size, 10); \
+ PrintAddr(ptr); \
+ PrintLn(); }
+
+#define PRINT_FREE(name, cnt, ptr) if (ptr) { \
+ Print(name " "); \
+ PrintDec(--cnt, 10); \
+ PrintAddr(ptr); \
+ PrintLn(); }
+
+#else
+
+#ifdef _WIN32
+#define PRINT_ALLOC(name, cnt, size, ptr)
+#endif
+#define PRINT_FREE(name, cnt, ptr)
+#define Print(s)
+#define PrintLn()
+#define PrintHex(v, align)
+#define PrintAddr(p)
+
+#endif
+
+
+/*
+by specification:
+ malloc(non_NULL, 0) : returns NULL or a unique pointer value that can later be successfully passed to free()
+ realloc(NULL, size) : the call is equivalent to malloc(size)
+ realloc(non_NULL, 0) : the call is equivalent to free(ptr)
+
+in main compilers:
+ malloc(0) : returns non_NULL
+ realloc(NULL, 0) : returns non_NULL
+ realloc(non_NULL, 0) : returns NULL
+*/
+
+
+void *MyAlloc(size_t size)
+{
+ if (size == 0)
+ return NULL;
+ // PRINT_ALLOC("Alloc ", g_allocCount, size, NULL)
+ #ifdef SZ_ALLOC_DEBUG
+ {
+ void *p = malloc(size);
+ if (p)
+ {
+ PRINT_ALLOC("Alloc ", g_allocCount, size, p)
+ }
+ return p;
+ }
+ #else
+ return malloc(size);
+ #endif
+}
+
+void MyFree(void *address)
+{
+ PRINT_FREE("Free ", g_allocCount, address)
+
+ free(address);
+}
+
+void *MyRealloc(void *address, size_t size)
+{
+ if (size == 0)
+ {
+ MyFree(address);
+ return NULL;
+ }
+ // PRINT_REALLOC("Realloc ", g_allocCount, size, address)
+ #ifdef SZ_ALLOC_DEBUG
+ {
+ void *p = realloc(address, size);
+ if (p)
+ {
+ PRINT_REALLOC("Realloc ", g_allocCount, size, address)
+ }
+ return p;
+ }
+ #else
+ return realloc(address, size);
+ #endif
+}
+
+
+#ifdef _WIN32
+
+void *MidAlloc(size_t size)
+{
+ if (size == 0)
+ return NULL;
+ #ifdef SZ_ALLOC_DEBUG
+ {
+ void *p = VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
+ if (p)
+ {
+ PRINT_ALLOC("Alloc-Mid", g_allocCountMid, size, p)
+ }
+ return p;
+ }
+ #else
+ return VirtualAlloc(NULL, size, MEM_COMMIT, PAGE_READWRITE);
+ #endif
+}
+
+void MidFree(void *address)
+{
+ PRINT_FREE("Free-Mid", g_allocCountMid, address)
+
+ if (!address)
+ return;
+ VirtualFree(address, 0, MEM_RELEASE);
+}
+
+#ifdef Z7_LARGE_PAGES
+
+#ifdef MEM_LARGE_PAGES
+ #define MY__MEM_LARGE_PAGES MEM_LARGE_PAGES
+#else
+ #define MY__MEM_LARGE_PAGES 0x20000000
+#endif
+
+extern
+SIZE_T g_LargePageSize;
+SIZE_T g_LargePageSize = 0;
+typedef SIZE_T (WINAPI *Func_GetLargePageMinimum)(VOID);
+
+void SetLargePageSize(void)
+{
+ #ifdef Z7_LARGE_PAGES
+ SIZE_T size;
+ const
+ Func_GetLargePageMinimum fn =
+ (Func_GetLargePageMinimum) MY_CAST_FUNC GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")),
+ "GetLargePageMinimum");
+ if (!fn)
+ return;
+ size = fn();
+ if (size == 0 || (size & (size - 1)) != 0)
+ return;
+ g_LargePageSize = size;
+ #endif
+}
+
+#endif // Z7_LARGE_PAGES
+
+void *BigAlloc(size_t size)
+{
+ if (size == 0)
+ return NULL;
+
+ PRINT_ALLOC("Alloc-Big", g_allocCountBig, size, NULL)
+
+ #ifdef Z7_LARGE_PAGES
+ {
+ SIZE_T ps = g_LargePageSize;
+ if (ps != 0 && ps <= (1 << 30) && size > (ps / 2))
+ {
+ size_t size2;
+ ps--;
+ size2 = (size + ps) & ~ps;
+ if (size2 >= size)
+ {
+ void *p = VirtualAlloc(NULL, size2, MEM_COMMIT | MY__MEM_LARGE_PAGES, PAGE_READWRITE);
+ if (p)
+ {
+ PRINT_ALLOC("Alloc-BM ", g_allocCountMid, size2, p)
+ return p;
+ }
+ }
+ }
+ }
+ #endif
+
+ return MidAlloc(size);
+}
+
+void BigFree(void *address)
+{
+ PRINT_FREE("Free-Big", g_allocCountBig, address)
+ MidFree(address);
+}
+
+#endif // _WIN32
+
+
+static void *SzAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return MyAlloc(size); }
+static void SzFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) MyFree(address); }
+const ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+#ifdef _WIN32
+static void *SzMidAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return MidAlloc(size); }
+static void SzMidFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) MidFree(address); }
+static void *SzBigAlloc(ISzAllocPtr p, size_t size) { UNUSED_VAR(p) return BigAlloc(size); }
+static void SzBigFree(ISzAllocPtr p, void *address) { UNUSED_VAR(p) BigFree(address); }
+const ISzAlloc g_MidAlloc = { SzMidAlloc, SzMidFree };
+const ISzAlloc g_BigAlloc = { SzBigAlloc, SzBigFree };
+#endif
+
+/*
+ uintptr_t : <stdint.h> C99 (optional)
+ : unsupported in VS6
+*/
+
+#ifdef _WIN32
+ typedef UINT_PTR UIntPtr;
+#else
+ /*
+ typedef uintptr_t UIntPtr;
+ */
+ typedef ptrdiff_t UIntPtr;
+#endif
+
+
+#define ADJUST_ALLOC_SIZE 0
+/*
+#define ADJUST_ALLOC_SIZE (sizeof(void *) - 1)
+*/
+/*
+ Use (ADJUST_ALLOC_SIZE = (sizeof(void *) - 1)), if
+ MyAlloc() can return address that is NOT multiple of sizeof(void *).
+*/
+
+
+/*
+#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((char *)(p) - ((size_t)(UIntPtr)(p) & ((align) - 1))))
+*/
+#define MY_ALIGN_PTR_DOWN(p, align) ((void *)((((UIntPtr)(p)) & ~((UIntPtr)(align) - 1))))
+
+
+#if !defined(_WIN32) && defined(_POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L)
+ #define USE_posix_memalign
+#endif
+
+#ifndef USE_posix_memalign
+#define MY_ALIGN_PTR_UP_PLUS(p, align) MY_ALIGN_PTR_DOWN(((char *)(p) + (align) + ADJUST_ALLOC_SIZE), align)
+#endif
+
+/*
+ This posix_memalign() is for test purposes only.
+ We also need special Free() function instead of free(),
+ if this posix_memalign() is used.
+*/
+
+/*
+static int posix_memalign(void **ptr, size_t align, size_t size)
+{
+ size_t newSize = size + align;
+ void *p;
+ void *pAligned;
+ *ptr = NULL;
+ if (newSize < size)
+ return 12; // ENOMEM
+ p = MyAlloc(newSize);
+ if (!p)
+ return 12; // ENOMEM
+ pAligned = MY_ALIGN_PTR_UP_PLUS(p, align);
+ ((void **)pAligned)[-1] = p;
+ *ptr = pAligned;
+ return 0;
+}
+*/
+
+/*
+ ALLOC_ALIGN_SIZE >= sizeof(void *)
+ ALLOC_ALIGN_SIZE >= cache_line_size
+*/
+
+#define ALLOC_ALIGN_SIZE ((size_t)1 << 7)
+
+static void *SzAlignedAlloc(ISzAllocPtr pp, size_t size)
+{
+ #ifndef USE_posix_memalign
+
+ void *p;
+ void *pAligned;
+ size_t newSize;
+ UNUSED_VAR(pp)
+
+ /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned
+ block to prevent cache line sharing with another allocated blocks */
+
+ newSize = size + ALLOC_ALIGN_SIZE * 1 + ADJUST_ALLOC_SIZE;
+ if (newSize < size)
+ return NULL;
+
+ p = MyAlloc(newSize);
+
+ if (!p)
+ return NULL;
+ pAligned = MY_ALIGN_PTR_UP_PLUS(p, ALLOC_ALIGN_SIZE);
+
+ Print(" size="); PrintHex(size, 8);
+ Print(" a_size="); PrintHex(newSize, 8);
+ Print(" ptr="); PrintAddr(p);
+ Print(" a_ptr="); PrintAddr(pAligned);
+ PrintLn();
+
+ ((void **)pAligned)[-1] = p;
+
+ return pAligned;
+
+ #else
+
+ void *p;
+ UNUSED_VAR(pp)
+ if (posix_memalign(&p, ALLOC_ALIGN_SIZE, size))
+ return NULL;
+
+ Print(" posix_memalign="); PrintAddr(p);
+ PrintLn();
+
+ return p;
+
+ #endif
+}
+
+
+static void SzAlignedFree(ISzAllocPtr pp, void *address)
+{
+ UNUSED_VAR(pp)
+ #ifndef USE_posix_memalign
+ if (address)
+ MyFree(((void **)address)[-1]);
+ #else
+ free(address);
+ #endif
+}
+
+
+const ISzAlloc g_AlignedAlloc = { SzAlignedAlloc, SzAlignedFree };
+
+
+
+#define MY_ALIGN_PTR_DOWN_1(p) MY_ALIGN_PTR_DOWN(p, sizeof(void *))
+
+/* we align ptr to support cases where CAlignOffsetAlloc::offset is not multiply of sizeof(void *) */
+#define REAL_BLOCK_PTR_VAR(p) ((void **)MY_ALIGN_PTR_DOWN_1(p))[-1]
+/*
+#define REAL_BLOCK_PTR_VAR(p) ((void **)(p))[-1]
+*/
+
+static void *AlignOffsetAlloc_Alloc(ISzAllocPtr pp, size_t size)
+{
+ const CAlignOffsetAlloc *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CAlignOffsetAlloc, vt);
+ void *adr;
+ void *pAligned;
+ size_t newSize;
+ size_t extra;
+ size_t alignSize = (size_t)1 << p->numAlignBits;
+
+ if (alignSize < sizeof(void *))
+ alignSize = sizeof(void *);
+
+ if (p->offset >= alignSize)
+ return NULL;
+
+ /* also we can allocate additional dummy ALLOC_ALIGN_SIZE bytes after aligned
+ block to prevent cache line sharing with another allocated blocks */
+ extra = p->offset & (sizeof(void *) - 1);
+ newSize = size + alignSize + extra + ADJUST_ALLOC_SIZE;
+ if (newSize < size)
+ return NULL;
+
+ adr = ISzAlloc_Alloc(p->baseAlloc, newSize);
+
+ if (!adr)
+ return NULL;
+
+ pAligned = (char *)MY_ALIGN_PTR_DOWN((char *)adr +
+ alignSize - p->offset + extra + ADJUST_ALLOC_SIZE, alignSize) + p->offset;
+
+ PrintLn();
+ Print("- Aligned: ");
+ Print(" size="); PrintHex(size, 8);
+ Print(" a_size="); PrintHex(newSize, 8);
+ Print(" ptr="); PrintAddr(adr);
+ Print(" a_ptr="); PrintAddr(pAligned);
+ PrintLn();
+
+ REAL_BLOCK_PTR_VAR(pAligned) = adr;
+
+ return pAligned;
+}
+
+
+static void AlignOffsetAlloc_Free(ISzAllocPtr pp, void *address)
+{
+ if (address)
+ {
+ const CAlignOffsetAlloc *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CAlignOffsetAlloc, vt);
+ PrintLn();
+ Print("- Aligned Free: ");
+ PrintLn();
+ ISzAlloc_Free(p->baseAlloc, REAL_BLOCK_PTR_VAR(address));
+ }
+}
+
+
+void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p)
+{
+ p->vt.Alloc = AlignOffsetAlloc_Alloc;
+ p->vt.Free = AlignOffsetAlloc_Free;
+}
diff --git a/C/Alloc.h b/C/Alloc.h
index 3d796e5..fac5b62 100644
--- a/C/Alloc.h
+++ b/C/Alloc.h
@@ -1,51 +1,71 @@
-/* Alloc.h -- Memory allocation functions
-2018-02-19 : Igor Pavlov : Public domain */
-
-#ifndef __COMMON_ALLOC_H
-#define __COMMON_ALLOC_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-void *MyAlloc(size_t size);
-void MyFree(void *address);
-
-#ifdef _WIN32
-
-void SetLargePageSize();
-
-void *MidAlloc(size_t size);
-void MidFree(void *address);
-void *BigAlloc(size_t size);
-void BigFree(void *address);
-
-#else
-
-#define MidAlloc(size) MyAlloc(size)
-#define MidFree(address) MyFree(address)
-#define BigAlloc(size) MyAlloc(size)
-#define BigFree(address) MyFree(address)
-
-#endif
-
-extern const ISzAlloc g_Alloc;
-extern const ISzAlloc g_BigAlloc;
-extern const ISzAlloc g_MidAlloc;
-extern const ISzAlloc g_AlignedAlloc;
-
-
-typedef struct
-{
- ISzAlloc vt;
- ISzAllocPtr baseAlloc;
- unsigned numAlignBits; /* ((1 << numAlignBits) >= sizeof(void *)) */
- size_t offset; /* (offset == (k * sizeof(void *)) && offset < (1 << numAlignBits) */
-} CAlignOffsetAlloc;
-
-void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p);
-
-
-EXTERN_C_END
-
-#endif
+/* Alloc.h -- Memory allocation functions
+2023-03-04 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_ALLOC_H
+#define ZIP7_INC_ALLOC_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/*
+ MyFree(NULL) : is allowed, as free(NULL)
+ MyAlloc(0) : returns NULL : but malloc(0) is allowed to return NULL or non_NULL
+ MyRealloc(NULL, 0) : returns NULL : but realloc(NULL, 0) is allowed to return NULL or non_NULL
+MyRealloc() is similar to realloc() for the following cases:
+ MyRealloc(non_NULL, 0) : returns NULL and always calls MyFree(ptr)
+ MyRealloc(NULL, non_ZERO) : returns NULL, if allocation failed
+ MyRealloc(non_NULL, non_ZERO) : returns NULL, if reallocation failed
+*/
+
+void *MyAlloc(size_t size);
+void MyFree(void *address);
+void *MyRealloc(void *address, size_t size);
+
+#ifdef _WIN32
+
+#ifdef Z7_LARGE_PAGES
+void SetLargePageSize(void);
+#endif
+
+void *MidAlloc(size_t size);
+void MidFree(void *address);
+void *BigAlloc(size_t size);
+void BigFree(void *address);
+
+#else
+
+#define MidAlloc(size) MyAlloc(size)
+#define MidFree(address) MyFree(address)
+#define BigAlloc(size) MyAlloc(size)
+#define BigFree(address) MyFree(address)
+
+#endif
+
+extern const ISzAlloc g_Alloc;
+
+#ifdef _WIN32
+extern const ISzAlloc g_BigAlloc;
+extern const ISzAlloc g_MidAlloc;
+#else
+#define g_BigAlloc g_AlignedAlloc
+#define g_MidAlloc g_AlignedAlloc
+#endif
+
+extern const ISzAlloc g_AlignedAlloc;
+
+
+typedef struct
+{
+ ISzAlloc vt;
+ ISzAllocPtr baseAlloc;
+ unsigned numAlignBits; /* ((1 << numAlignBits) >= sizeof(void *)) */
+ size_t offset; /* (offset == (k * sizeof(void *)) && offset < (1 << numAlignBits) */
+} CAlignOffsetAlloc;
+
+void AlignOffsetAlloc_CreateVTable(CAlignOffsetAlloc *p);
+
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Android.bp b/C/Android.bp
index c5d201b..071f557 100644
--- a/C/Android.bp
+++ b/C/Android.bp
@@ -24,7 +24,7 @@ cc_library {
stl: "none",
cflags: [
- "-D_7ZIP_ST",
+ "-DZ7_ST",
"-Wall",
"-Werror",
"-Wno-empty-body",
@@ -66,6 +66,7 @@ cc_library {
"Ppmd7Dec.c",
"Ppmd7Enc.c",
"Sha256.c",
+ "Sha256Opt.c",
"Sort.c",
"Xz.c",
"XzCrc64.c",
@@ -75,6 +76,15 @@ cc_library {
"XzIn.c",
],
+ arch: {
+ arm: {
+ cflags: ["-march=armv8-a+crypto"],
+ },
+ arm64: {
+ cflags: ["-march=armv8-a+crypto"],
+ },
+ },
+
target: {
linux_bionic: {
enabled: true,
@@ -85,6 +95,7 @@ cc_library {
"Bcj2Enc.c",
"DllSecur.c",
"LzFindMt.c",
+ "LzFindOpt.c",
"Lzma2DecMt.c",
"MtCoder.c",
"MtDec.c",
diff --git a/C/Bcj2.c b/C/Bcj2.c
index da93985..7cb57ad 100644
--- a/C/Bcj2.c
+++ b/C/Bcj2.c
@@ -1,257 +1,290 @@
-/* Bcj2.c -- BCJ2 Decoder (Converter for x86 code)
-2018-04-28 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "Bcj2.h"
-#include "CpuArch.h"
-
-#define CProb UInt16
-
-#define kTopValue ((UInt32)1 << 24)
-#define kNumModelBits 11
-#define kBitModelTotal (1 << kNumModelBits)
-#define kNumMoveBits 5
-
-#define _IF_BIT_0 ttt = *prob; bound = (p->range >> kNumModelBits) * ttt; if (p->code < bound)
-#define _UPDATE_0 p->range = bound; *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
-#define _UPDATE_1 p->range -= bound; p->code -= bound; *prob = (CProb)(ttt - (ttt >> kNumMoveBits));
-
-void Bcj2Dec_Init(CBcj2Dec *p)
-{
- unsigned i;
-
- p->state = BCJ2_DEC_STATE_OK;
- p->ip = 0;
- p->temp[3] = 0;
- p->range = 0;
- p->code = 0;
- for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++)
- p->probs[i] = kBitModelTotal >> 1;
-}
-
-SRes Bcj2Dec_Decode(CBcj2Dec *p)
-{
- if (p->range <= 5)
- {
- p->state = BCJ2_DEC_STATE_OK;
- for (; p->range != 5; p->range++)
- {
- if (p->range == 1 && p->code != 0)
- return SZ_ERROR_DATA;
-
- if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC])
- {
- p->state = BCJ2_STREAM_RC;
- return SZ_OK;
- }
-
- p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
- }
-
- if (p->code == 0xFFFFFFFF)
- return SZ_ERROR_DATA;
-
- p->range = 0xFFFFFFFF;
- }
- else if (p->state >= BCJ2_DEC_STATE_ORIG_0)
- {
- while (p->state <= BCJ2_DEC_STATE_ORIG_3)
- {
- Byte *dest = p->dest;
- if (dest == p->destLim)
- return SZ_OK;
- *dest = p->temp[(size_t)p->state - BCJ2_DEC_STATE_ORIG_0];
- p->state++;
- p->dest = dest + 1;
- }
- }
-
- /*
- if (BCJ2_IS_32BIT_STREAM(p->state))
- {
- const Byte *cur = p->bufs[p->state];
- if (cur == p->lims[p->state])
- return SZ_OK;
- p->bufs[p->state] = cur + 4;
-
- {
- UInt32 val;
- Byte *dest;
- SizeT rem;
-
- p->ip += 4;
- val = GetBe32(cur) - p->ip;
- dest = p->dest;
- rem = p->destLim - dest;
- if (rem < 4)
- {
- SizeT i;
- SetUi32(p->temp, val);
- for (i = 0; i < rem; i++)
- dest[i] = p->temp[i];
- p->dest = dest + rem;
- p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem;
- return SZ_OK;
- }
- SetUi32(dest, val);
- p->temp[3] = (Byte)(val >> 24);
- p->dest = dest + 4;
- p->state = BCJ2_DEC_STATE_OK;
- }
- }
- */
-
- for (;;)
- {
- if (BCJ2_IS_32BIT_STREAM(p->state))
- p->state = BCJ2_DEC_STATE_OK;
- else
- {
- if (p->range < kTopValue)
- {
- if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC])
- {
- p->state = BCJ2_STREAM_RC;
- return SZ_OK;
- }
- p->range <<= 8;
- p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
- }
-
- {
- const Byte *src = p->bufs[BCJ2_STREAM_MAIN];
- const Byte *srcLim;
- Byte *dest;
- SizeT num = p->lims[BCJ2_STREAM_MAIN] - src;
-
- if (num == 0)
- {
- p->state = BCJ2_STREAM_MAIN;
- return SZ_OK;
- }
-
- dest = p->dest;
- if (num > (SizeT)(p->destLim - dest))
- {
- num = p->destLim - dest;
- if (num == 0)
- {
- p->state = BCJ2_DEC_STATE_ORIG;
- return SZ_OK;
- }
- }
-
- srcLim = src + num;
-
- if (p->temp[3] == 0x0F && (src[0] & 0xF0) == 0x80)
- *dest = src[0];
- else for (;;)
- {
- Byte b = *src;
- *dest = b;
- if (b != 0x0F)
- {
- if ((b & 0xFE) == 0xE8)
- break;
- dest++;
- if (++src != srcLim)
- continue;
- break;
- }
- dest++;
- if (++src == srcLim)
- break;
- if ((*src & 0xF0) != 0x80)
- continue;
- *dest = *src;
- break;
- }
-
- num = src - p->bufs[BCJ2_STREAM_MAIN];
-
- if (src == srcLim)
- {
- p->temp[3] = src[-1];
- p->bufs[BCJ2_STREAM_MAIN] = src;
- p->ip += (UInt32)num;
- p->dest += num;
- p->state =
- p->bufs[BCJ2_STREAM_MAIN] ==
- p->lims[BCJ2_STREAM_MAIN] ?
- (unsigned)BCJ2_STREAM_MAIN :
- (unsigned)BCJ2_DEC_STATE_ORIG;
- return SZ_OK;
- }
-
- {
- UInt32 bound, ttt;
- CProb *prob;
- Byte b = src[0];
- Byte prev = (Byte)(num == 0 ? p->temp[3] : src[-1]);
-
- p->temp[3] = b;
- p->bufs[BCJ2_STREAM_MAIN] = src + 1;
- num++;
- p->ip += (UInt32)num;
- p->dest += num;
-
- prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)prev : (b == 0xE9 ? 1 : 0));
-
- _IF_BIT_0
- {
- _UPDATE_0
- continue;
- }
- _UPDATE_1
-
- }
- }
- }
-
- {
- UInt32 val;
- unsigned cj = (p->temp[3] == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP;
- const Byte *cur = p->bufs[cj];
- Byte *dest;
- SizeT rem;
-
- if (cur == p->lims[cj])
- {
- p->state = cj;
- break;
- }
-
- val = GetBe32(cur);
- p->bufs[cj] = cur + 4;
-
- p->ip += 4;
- val -= p->ip;
- dest = p->dest;
- rem = p->destLim - dest;
-
- if (rem < 4)
- {
- p->temp[0] = (Byte)val; if (rem > 0) dest[0] = (Byte)val; val >>= 8;
- p->temp[1] = (Byte)val; if (rem > 1) dest[1] = (Byte)val; val >>= 8;
- p->temp[2] = (Byte)val; if (rem > 2) dest[2] = (Byte)val; val >>= 8;
- p->temp[3] = (Byte)val;
- p->dest = dest + rem;
- p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem;
- break;
- }
-
- SetUi32(dest, val);
- p->temp[3] = (Byte)(val >> 24);
- p->dest = dest + 4;
- }
- }
-
- if (p->range < kTopValue && p->bufs[BCJ2_STREAM_RC] != p->lims[BCJ2_STREAM_RC])
- {
- p->range <<= 8;
- p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
- }
-
- return SZ_OK;
-}
+/* Bcj2.c -- BCJ2 Decoder (Converter for x86 code)
+2023-03-01 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Bcj2.h"
+#include "CpuArch.h"
+
+#define kTopValue ((UInt32)1 << 24)
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+// UInt32 bcj2_stats[256 + 2][2];
+
+void Bcj2Dec_Init(CBcj2Dec *p)
+{
+ unsigned i;
+ p->state = BCJ2_STREAM_RC; // BCJ2_DEC_STATE_OK;
+ p->ip = 0;
+ p->temp = 0;
+ p->range = 0;
+ p->code = 0;
+ for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++)
+ p->probs[i] = kBitModelTotal >> 1;
+}
+
+SRes Bcj2Dec_Decode(CBcj2Dec *p)
+{
+ UInt32 v = p->temp;
+ // const Byte *src;
+ if (p->range <= 5)
+ {
+ UInt32 code = p->code;
+ p->state = BCJ2_DEC_STATE_ERROR; /* for case if we return SZ_ERROR_DATA; */
+ for (; p->range != 5; p->range++)
+ {
+ if (p->range == 1 && code != 0)
+ return SZ_ERROR_DATA;
+ if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC])
+ {
+ p->state = BCJ2_STREAM_RC;
+ return SZ_OK;
+ }
+ code = (code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
+ p->code = code;
+ }
+ if (code == 0xffffffff)
+ return SZ_ERROR_DATA;
+ p->range = 0xffffffff;
+ }
+ // else
+ {
+ unsigned state = p->state;
+ // we check BCJ2_IS_32BIT_STREAM() here instead of check in the main loop
+ if (BCJ2_IS_32BIT_STREAM(state))
+ {
+ const Byte *cur = p->bufs[state];
+ if (cur == p->lims[state])
+ return SZ_OK;
+ p->bufs[state] = cur + 4;
+ {
+ const UInt32 ip = p->ip + 4;
+ v = GetBe32a(cur) - ip;
+ p->ip = ip;
+ }
+ state = BCJ2_DEC_STATE_ORIG_0;
+ }
+ if ((unsigned)(state - BCJ2_DEC_STATE_ORIG_0) < 4)
+ {
+ Byte *dest = p->dest;
+ for (;;)
+ {
+ if (dest == p->destLim)
+ {
+ p->state = state;
+ p->temp = v;
+ return SZ_OK;
+ }
+ *dest++ = (Byte)v;
+ p->dest = dest;
+ if (++state == BCJ2_DEC_STATE_ORIG_3 + 1)
+ break;
+ v >>= 8;
+ }
+ }
+ }
+
+ // src = p->bufs[BCJ2_STREAM_MAIN];
+ for (;;)
+ {
+ /*
+ if (BCJ2_IS_32BIT_STREAM(p->state))
+ p->state = BCJ2_DEC_STATE_OK;
+ else
+ */
+ {
+ if (p->range < kTopValue)
+ {
+ if (p->bufs[BCJ2_STREAM_RC] == p->lims[BCJ2_STREAM_RC])
+ {
+ p->state = BCJ2_STREAM_RC;
+ p->temp = v;
+ return SZ_OK;
+ }
+ p->range <<= 8;
+ p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
+ }
+ {
+ const Byte *src = p->bufs[BCJ2_STREAM_MAIN];
+ const Byte *srcLim;
+ Byte *dest = p->dest;
+ {
+ const SizeT rem = (SizeT)(p->lims[BCJ2_STREAM_MAIN] - src);
+ SizeT num = (SizeT)(p->destLim - dest);
+ if (num >= rem)
+ num = rem;
+ #define NUM_ITERS 4
+ #if (NUM_ITERS & (NUM_ITERS - 1)) == 0
+ num &= ~((SizeT)NUM_ITERS - 1); // if (NUM_ITERS == (1 << x))
+ #else
+ num -= num % NUM_ITERS; // if (NUM_ITERS != (1 << x))
+ #endif
+ srcLim = src + num;
+ }
+
+ #define NUM_SHIFT_BITS 24
+ #define ONE_ITER(indx) { \
+ const unsigned b = src[indx]; \
+ *dest++ = (Byte)b; \
+ v = (v << NUM_SHIFT_BITS) | b; \
+ if (((b + (0x100 - 0xe8)) & 0xfe) == 0) break; \
+ if (((v - (((UInt32)0x0f << (NUM_SHIFT_BITS)) + 0x80)) & \
+ ((((UInt32)1 << (4 + NUM_SHIFT_BITS)) - 0x1) << 4)) == 0) break; \
+ /* ++dest */; /* v = b; */ }
+
+ if (src != srcLim)
+ for (;;)
+ {
+ /* The dependency chain of 2-cycle for (v) calculation is not big problem here.
+ But we can remove dependency chain with v = b in the end of loop. */
+ ONE_ITER(0)
+ #if (NUM_ITERS > 1)
+ ONE_ITER(1)
+ #if (NUM_ITERS > 2)
+ ONE_ITER(2)
+ #if (NUM_ITERS > 3)
+ ONE_ITER(3)
+ #if (NUM_ITERS > 4)
+ ONE_ITER(4)
+ #if (NUM_ITERS > 5)
+ ONE_ITER(5)
+ #if (NUM_ITERS > 6)
+ ONE_ITER(6)
+ #if (NUM_ITERS > 7)
+ ONE_ITER(7)
+ #endif
+ #endif
+ #endif
+ #endif
+ #endif
+ #endif
+ #endif
+
+ src += NUM_ITERS;
+ if (src == srcLim)
+ break;
+ }
+
+ if (src == srcLim)
+ #if (NUM_ITERS > 1)
+ for (;;)
+ #endif
+ {
+ #if (NUM_ITERS > 1)
+ if (src == p->lims[BCJ2_STREAM_MAIN] || dest == p->destLim)
+ #endif
+ {
+ const SizeT num = (SizeT)(src - p->bufs[BCJ2_STREAM_MAIN]);
+ p->bufs[BCJ2_STREAM_MAIN] = src;
+ p->dest = dest;
+ p->ip += (UInt32)num;
+ /* state BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */
+ p->state =
+ src == p->lims[BCJ2_STREAM_MAIN] ?
+ (unsigned)BCJ2_STREAM_MAIN :
+ (unsigned)BCJ2_DEC_STATE_ORIG;
+ p->temp = v;
+ return SZ_OK;
+ }
+ #if (NUM_ITERS > 1)
+ ONE_ITER(0)
+ src++;
+ #endif
+ }
+
+ {
+ const SizeT num = (SizeT)(dest - p->dest);
+ p->dest = dest; // p->dest += num;
+ p->bufs[BCJ2_STREAM_MAIN] += num; // = src;
+ p->ip += (UInt32)num;
+ }
+ {
+ UInt32 bound, ttt;
+ CBcj2Prob *prob; // unsigned index;
+ /*
+ prob = p->probs + (unsigned)((Byte)v == 0xe8 ?
+ 2 + (Byte)(v >> 8) :
+ ((v >> 5) & 1)); // ((Byte)v < 0xe8 ? 0 : 1));
+ */
+ {
+ const unsigned c = ((v + 0x17) >> 6) & 1;
+ prob = p->probs + (unsigned)
+ (((0 - c) & (Byte)(v >> NUM_SHIFT_BITS)) + c + ((v >> 5) & 1));
+ // (Byte)
+ // 8x->0 : e9->1 : xxe8->xx+2
+ // 8x->0x100 : e9->0x101 : xxe8->xx
+ // (((0x100 - (e & ~v)) & (0x100 | (v >> 8))) + (e & v));
+ // (((0x101 + (~e | v)) & (0x100 | (v >> 8))) + (e & v));
+ }
+ ttt = *prob;
+ bound = (p->range >> kNumBitModelTotalBits) * ttt;
+ if (p->code < bound)
+ {
+ // bcj2_stats[prob - p->probs][0]++;
+ p->range = bound;
+ *prob = (CBcj2Prob)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
+ continue;
+ }
+ {
+ // bcj2_stats[prob - p->probs][1]++;
+ p->range -= bound;
+ p->code -= bound;
+ *prob = (CBcj2Prob)(ttt - (ttt >> kNumMoveBits));
+ }
+ }
+ }
+ }
+ {
+ /* (v == 0xe8 ? 0 : 1) uses setcc instruction with additional zero register usage in x64 MSVC. */
+ // const unsigned cj = ((Byte)v == 0xe8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP;
+ const unsigned cj = (((v + 0x57) >> 6) & 1) + BCJ2_STREAM_CALL;
+ const Byte *cur = p->bufs[cj];
+ Byte *dest;
+ SizeT rem;
+ if (cur == p->lims[cj])
+ {
+ p->state = cj;
+ break;
+ }
+ v = GetBe32a(cur);
+ p->bufs[cj] = cur + 4;
+ {
+ const UInt32 ip = p->ip + 4;
+ v -= ip;
+ p->ip = ip;
+ }
+ dest = p->dest;
+ rem = (SizeT)(p->destLim - dest);
+ if (rem < 4)
+ {
+ if ((unsigned)rem > 0) { dest[0] = (Byte)v; v >>= 8;
+ if ((unsigned)rem > 1) { dest[1] = (Byte)v; v >>= 8;
+ if ((unsigned)rem > 2) { dest[2] = (Byte)v; v >>= 8; }}}
+ p->temp = v;
+ p->dest = dest + rem;
+ p->state = BCJ2_DEC_STATE_ORIG_0 + (unsigned)rem;
+ break;
+ }
+ SetUi32(dest, v)
+ v >>= 24;
+ p->dest = dest + 4;
+ }
+ }
+
+ if (p->range < kTopValue && p->bufs[BCJ2_STREAM_RC] != p->lims[BCJ2_STREAM_RC])
+ {
+ p->range <<= 8;
+ p->code = (p->code << 8) | *(p->bufs[BCJ2_STREAM_RC])++;
+ }
+ return SZ_OK;
+}
+
+#undef NUM_ITERS
+#undef ONE_ITER
+#undef NUM_SHIFT_BITS
+#undef kTopValue
+#undef kNumBitModelTotalBits
+#undef kBitModelTotal
+#undef kNumMoveBits
diff --git a/C/Bcj2.h b/C/Bcj2.h
index 68893d2..4575545 100644
--- a/C/Bcj2.h
+++ b/C/Bcj2.h
@@ -1,146 +1,332 @@
-/* Bcj2.h -- BCJ2 Converter for x86 code
-2014-11-10 : Igor Pavlov : Public domain */
-
-#ifndef __BCJ2_H
-#define __BCJ2_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-#define BCJ2_NUM_STREAMS 4
-
-enum
-{
- BCJ2_STREAM_MAIN,
- BCJ2_STREAM_CALL,
- BCJ2_STREAM_JUMP,
- BCJ2_STREAM_RC
-};
-
-enum
-{
- BCJ2_DEC_STATE_ORIG_0 = BCJ2_NUM_STREAMS,
- BCJ2_DEC_STATE_ORIG_1,
- BCJ2_DEC_STATE_ORIG_2,
- BCJ2_DEC_STATE_ORIG_3,
-
- BCJ2_DEC_STATE_ORIG,
- BCJ2_DEC_STATE_OK
-};
-
-enum
-{
- BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS,
- BCJ2_ENC_STATE_OK
-};
-
-
-#define BCJ2_IS_32BIT_STREAM(s) ((s) == BCJ2_STREAM_CALL || (s) == BCJ2_STREAM_JUMP)
-
-/*
-CBcj2Dec / CBcj2Enc
-bufs sizes:
- BUF_SIZE(n) = lims[n] - bufs[n]
-bufs sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP must be mutliply of 4:
- (BUF_SIZE(BCJ2_STREAM_CALL) & 3) == 0
- (BUF_SIZE(BCJ2_STREAM_JUMP) & 3) == 0
-*/
-
-/*
-CBcj2Dec:
-dest is allowed to overlap with bufs[BCJ2_STREAM_MAIN], with the following conditions:
- bufs[BCJ2_STREAM_MAIN] >= dest &&
- bufs[BCJ2_STREAM_MAIN] - dest >= tempReserv +
- BUF_SIZE(BCJ2_STREAM_CALL) +
- BUF_SIZE(BCJ2_STREAM_JUMP)
- tempReserv = 0 : for first call of Bcj2Dec_Decode
- tempReserv = 4 : for any other calls of Bcj2Dec_Decode
- overlap with offset = 1 is not allowed
-*/
-
-typedef struct
-{
- const Byte *bufs[BCJ2_NUM_STREAMS];
- const Byte *lims[BCJ2_NUM_STREAMS];
- Byte *dest;
- const Byte *destLim;
-
- unsigned state; /* BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */
-
- UInt32 ip;
- Byte temp[4];
- UInt32 range;
- UInt32 code;
- UInt16 probs[2 + 256];
-} CBcj2Dec;
-
-void Bcj2Dec_Init(CBcj2Dec *p);
-
-/* Returns: SZ_OK or SZ_ERROR_DATA */
-SRes Bcj2Dec_Decode(CBcj2Dec *p);
-
-#define Bcj2Dec_IsFinished(_p_) ((_p_)->code == 0)
-
-
-
-typedef enum
-{
- BCJ2_ENC_FINISH_MODE_CONTINUE,
- BCJ2_ENC_FINISH_MODE_END_BLOCK,
- BCJ2_ENC_FINISH_MODE_END_STREAM
-} EBcj2Enc_FinishMode;
-
-typedef struct
-{
- Byte *bufs[BCJ2_NUM_STREAMS];
- const Byte *lims[BCJ2_NUM_STREAMS];
- const Byte *src;
- const Byte *srcLim;
-
- unsigned state;
- EBcj2Enc_FinishMode finishMode;
-
- Byte prevByte;
-
- Byte cache;
- UInt32 range;
- UInt64 low;
- UInt64 cacheSize;
-
- UInt32 ip;
-
- /* 32-bit ralative offset in JUMP/CALL commands is
- - (mod 4 GB) in 32-bit mode
- - signed Int32 in 64-bit mode
- We use (mod 4 GB) check for fileSize.
- Use fileSize up to 2 GB, if you want to support 32-bit and 64-bit code conversion. */
- UInt32 fileIp;
- UInt32 fileSize; /* (fileSize <= ((UInt32)1 << 31)), 0 means no_limit */
- UInt32 relatLimit; /* (relatLimit <= ((UInt32)1 << 31)), 0 means desable_conversion */
-
- UInt32 tempTarget;
- unsigned tempPos;
- Byte temp[4 * 2];
-
- unsigned flushPos;
-
- UInt16 probs[2 + 256];
-} CBcj2Enc;
-
-void Bcj2Enc_Init(CBcj2Enc *p);
-void Bcj2Enc_Encode(CBcj2Enc *p);
-
-#define Bcj2Enc_Get_InputData_Size(p) ((SizeT)((p)->srcLim - (p)->src) + (p)->tempPos)
-#define Bcj2Enc_IsFinished(p) ((p)->flushPos == 5)
-
-
-#define BCJ2_RELAT_LIMIT_NUM_BITS 26
-#define BCJ2_RELAT_LIMIT ((UInt32)1 << BCJ2_RELAT_LIMIT_NUM_BITS)
-
-/* limit for CBcj2Enc::fileSize variable */
-#define BCJ2_FileSize_MAX ((UInt32)1 << 31)
-
-EXTERN_C_END
-
-#endif
+/* Bcj2.h -- BCJ2 converter for x86 code (Branch CALL/JUMP variant2)
+2023-03-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_BCJ2_H
+#define ZIP7_INC_BCJ2_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define BCJ2_NUM_STREAMS 4
+
+enum
+{
+ BCJ2_STREAM_MAIN,
+ BCJ2_STREAM_CALL,
+ BCJ2_STREAM_JUMP,
+ BCJ2_STREAM_RC
+};
+
+enum
+{
+ BCJ2_DEC_STATE_ORIG_0 = BCJ2_NUM_STREAMS,
+ BCJ2_DEC_STATE_ORIG_1,
+ BCJ2_DEC_STATE_ORIG_2,
+ BCJ2_DEC_STATE_ORIG_3,
+
+ BCJ2_DEC_STATE_ORIG,
+ BCJ2_DEC_STATE_ERROR /* after detected data error */
+};
+
+enum
+{
+ BCJ2_ENC_STATE_ORIG = BCJ2_NUM_STREAMS,
+ BCJ2_ENC_STATE_FINISHED /* it's state after fully encoded stream */
+};
+
+
+/* #define BCJ2_IS_32BIT_STREAM(s) ((s) == BCJ2_STREAM_CALL || (s) == BCJ2_STREAM_JUMP) */
+#define BCJ2_IS_32BIT_STREAM(s) ((unsigned)((unsigned)(s) - (unsigned)BCJ2_STREAM_CALL) < 2)
+
+/*
+CBcj2Dec / CBcj2Enc
+bufs sizes:
+ BUF_SIZE(n) = lims[n] - bufs[n]
+bufs sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP must be multiply of 4:
+ (BUF_SIZE(BCJ2_STREAM_CALL) & 3) == 0
+ (BUF_SIZE(BCJ2_STREAM_JUMP) & 3) == 0
+*/
+
+// typedef UInt32 CBcj2Prob;
+typedef UInt16 CBcj2Prob;
+
+/*
+BCJ2 encoder / decoder internal requirements:
+ - If last bytes of stream contain marker (e8/e8/0f8x), then
+ there is also encoded symbol (0 : no conversion) in RC stream.
+ - One case of overlapped instructions is supported,
+ if last byte of converted instruction is (0f) and next byte is (8x):
+ marker [xx xx xx 0f] 8x
+ then the pair (0f 8x) is treated as marker.
+*/
+
+/* ---------- BCJ2 Decoder ---------- */
+
+/*
+CBcj2Dec:
+(dest) is allowed to overlap with bufs[BCJ2_STREAM_MAIN], with the following conditions:
+ bufs[BCJ2_STREAM_MAIN] >= dest &&
+ bufs[BCJ2_STREAM_MAIN] - dest >=
+ BUF_SIZE(BCJ2_STREAM_CALL) +
+ BUF_SIZE(BCJ2_STREAM_JUMP)
+ reserve = bufs[BCJ2_STREAM_MAIN] - dest -
+ ( BUF_SIZE(BCJ2_STREAM_CALL) +
+ BUF_SIZE(BCJ2_STREAM_JUMP) )
+ and additional conditions:
+ if (it's first call of Bcj2Dec_Decode() after Bcj2Dec_Init())
+ {
+ (reserve != 1) : if (ver < v23.00)
+ }
+ else // if there are more than one calls of Bcj2Dec_Decode() after Bcj2Dec_Init())
+ {
+ (reserve >= 6) : if (ver < v23.00)
+ (reserve >= 4) : if (ver >= v23.00)
+ We need that (reserve) because after first call of Bcj2Dec_Decode(),
+ CBcj2Dec::temp can contain up to 4 bytes for writing to (dest).
+ }
+ (reserve == 0) is allowed, if we decode full stream via single call of Bcj2Dec_Decode().
+ (reserve == 0) also is allowed in case of multi-call, if we use fixed buffers,
+ and (reserve) is calculated from full (final) sizes of all streams before first call.
+*/
+
+typedef struct
+{
+ const Byte *bufs[BCJ2_NUM_STREAMS];
+ const Byte *lims[BCJ2_NUM_STREAMS];
+ Byte *dest;
+ const Byte *destLim;
+
+ unsigned state; /* BCJ2_STREAM_MAIN has more priority than BCJ2_STATE_ORIG */
+
+ UInt32 ip; /* property of starting base for decoding */
+ UInt32 temp; /* Byte temp[4]; */
+ UInt32 range;
+ UInt32 code;
+ CBcj2Prob probs[2 + 256];
+} CBcj2Dec;
+
+
+/* Note:
+ Bcj2Dec_Init() sets (CBcj2Dec::ip = 0)
+ if (ip != 0) property is required, the caller must set CBcj2Dec::ip after Bcj2Dec_Init()
+*/
+void Bcj2Dec_Init(CBcj2Dec *p);
+
+
+/* Bcj2Dec_Decode():
+ returns:
+ SZ_OK
+ SZ_ERROR_DATA : if data in 5 starting bytes of BCJ2_STREAM_RC stream are not correct
+*/
+SRes Bcj2Dec_Decode(CBcj2Dec *p);
+
+/* To check that decoding was finished you can compare
+ sizes of processed streams with sizes known from another sources.
+ You must do at least one mandatory check from the two following options:
+ - the check for size of processed output (ORIG) stream.
+ - the check for size of processed input (MAIN) stream.
+ additional optional checks:
+ - the checks for processed sizes of all input streams (MAIN, CALL, JUMP, RC)
+ - the checks Bcj2Dec_IsMaybeFinished*()
+ also before actual decoding you can check that the
+ following condition is met for stream sizes:
+ ( size(ORIG) == size(MAIN) + size(CALL) + size(JUMP) )
+*/
+
+/* (state == BCJ2_STREAM_MAIN) means that decoder is ready for
+ additional input data in BCJ2_STREAM_MAIN stream.
+ Note that (state == BCJ2_STREAM_MAIN) is allowed for non-finished decoding.
+*/
+#define Bcj2Dec_IsMaybeFinished_state_MAIN(_p_) ((_p_)->state == BCJ2_STREAM_MAIN)
+
+/* if the stream decoding was finished correctly, then range decoder
+ part of CBcj2Dec also was finished, and then (CBcj2Dec::code == 0).
+ Note that (CBcj2Dec::code == 0) is allowed for non-finished decoding.
+*/
+#define Bcj2Dec_IsMaybeFinished_code(_p_) ((_p_)->code == 0)
+
+/* use Bcj2Dec_IsMaybeFinished() only as additional check
+ after at least one mandatory check from the two following options:
+ - the check for size of processed output (ORIG) stream.
+ - the check for size of processed input (MAIN) stream.
+*/
+#define Bcj2Dec_IsMaybeFinished(_p_) ( \
+ Bcj2Dec_IsMaybeFinished_state_MAIN(_p_) && \
+ Bcj2Dec_IsMaybeFinished_code(_p_))
+
+
+
+/* ---------- BCJ2 Encoder ---------- */
+
+typedef enum
+{
+ BCJ2_ENC_FINISH_MODE_CONTINUE,
+ BCJ2_ENC_FINISH_MODE_END_BLOCK,
+ BCJ2_ENC_FINISH_MODE_END_STREAM
+} EBcj2Enc_FinishMode;
+
+/*
+ BCJ2_ENC_FINISH_MODE_CONTINUE:
+ process non finished encoding.
+ It notifies the encoder that additional further calls
+ can provide more input data (src) than provided by current call.
+ In that case the CBcj2Enc encoder still can move (src) pointer
+ up to (srcLim), but CBcj2Enc encoder can store some of the last
+ processed bytes (up to 4 bytes) from src to internal CBcj2Enc::temp[] buffer.
+ at return:
+ (CBcj2Enc::src will point to position that includes
+ processed data and data copied to (temp[]) buffer)
+ That data from (temp[]) buffer will be used in further calls.
+
+ BCJ2_ENC_FINISH_MODE_END_BLOCK:
+ finish encoding of current block (ended at srcLim) without RC flushing.
+ at return: if (CBcj2Enc::state == BCJ2_ENC_STATE_ORIG) &&
+ CBcj2Enc::src == CBcj2Enc::srcLim)
+ : it shows that block encoding was finished. And the encoder is
+ ready for new (src) data or for stream finish operation.
+ finished block means
+ {
+ CBcj2Enc has completed block encoding up to (srcLim).
+ (1 + 4 bytes) or (2 + 4 bytes) CALL/JUMP cortages will
+ not cross block boundary at (srcLim).
+ temporary CBcj2Enc buffer for (ORIG) src data is empty.
+ 3 output uncompressed streams (MAIN, CALL, JUMP) were flushed.
+ RC stream was not flushed. And RC stream will cross block boundary.
+ }
+ Note: some possible implementation of BCJ2 encoder could
+ write branch marker (e8/e8/0f8x) in one call of Bcj2Enc_Encode(),
+ and it could calculate symbol for RC in another call of Bcj2Enc_Encode().
+ BCJ2 encoder uses ip/fileIp/fileSize/relatLimit values to calculate RC symbol.
+ And these CBcj2Enc variables can have different values in different Bcj2Enc_Encode() calls.
+ So caller must finish each block with BCJ2_ENC_FINISH_MODE_END_BLOCK
+ to ensure that RC symbol is calculated and written in proper block.
+
+ BCJ2_ENC_FINISH_MODE_END_STREAM
+ finish encoding of stream (ended at srcLim) fully including RC flushing.
+ at return: if (CBcj2Enc::state == BCJ2_ENC_STATE_FINISHED)
+ : it shows that stream encoding was finished fully,
+ and all output streams were flushed fully.
+ also Bcj2Enc_IsFinished() can be called.
+*/
+
+
+/*
+ 32-bit relative offset in JUMP/CALL commands is
+ - (mod 4 GiB) for 32-bit x86 code
+ - signed Int32 for 64-bit x86-64 code
+ BCJ2 encoder also does internal relative to absolute address conversions.
+ And there are 2 possible ways to do it:
+ before v23: we used 32-bit variables and (mod 4 GiB) conversion
+ since v23: we use 64-bit variables and (signed Int32 offset) conversion.
+ The absolute address condition for conversion in v23:
+ ((UInt64)((Int64)ip64 - (Int64)fileIp64 + 5 + (Int32)offset) < (UInt64)fileSize64)
+ note that if (fileSize64 > 2 GiB). there is difference between
+ old (mod 4 GiB) way (v22) and new (signed Int32 offset) way (v23).
+ And new (v23) way is more suitable to encode 64-bit x86-64 code for (fileSize64 > 2 GiB) cases.
+*/
+
+/*
+// for old (v22) way for conversion:
+typedef UInt32 CBcj2Enc_ip_unsigned;
+typedef Int32 CBcj2Enc_ip_signed;
+#define BCJ2_ENC_FileSize_MAX ((UInt32)1 << 31)
+*/
+typedef UInt64 CBcj2Enc_ip_unsigned;
+typedef Int64 CBcj2Enc_ip_signed;
+
+/* maximum size of file that can be used for conversion condition */
+#define BCJ2_ENC_FileSize_MAX ((CBcj2Enc_ip_unsigned)0 - 2)
+
+/* default value of fileSize64_minus1 variable that means
+ that absolute address limitation will not be used */
+#define BCJ2_ENC_FileSizeField_UNLIMITED ((CBcj2Enc_ip_unsigned)0 - 1)
+
+/* calculate value that later can be set to CBcj2Enc::fileSize64_minus1 */
+#define BCJ2_ENC_GET_FileSizeField_VAL_FROM_FileSize(fileSize) \
+ ((CBcj2Enc_ip_unsigned)(fileSize) - 1)
+
+/* set CBcj2Enc::fileSize64_minus1 variable from size of file */
+#define Bcj2Enc_SET_FileSize(p, fileSize) \
+ (p)->fileSize64_minus1 = BCJ2_ENC_GET_FileSizeField_VAL_FROM_FileSize(fileSize);
+
+
+typedef struct
+{
+ Byte *bufs[BCJ2_NUM_STREAMS];
+ const Byte *lims[BCJ2_NUM_STREAMS];
+ const Byte *src;
+ const Byte *srcLim;
+
+ unsigned state;
+ EBcj2Enc_FinishMode finishMode;
+
+ Byte context;
+ Byte flushRem;
+ Byte isFlushState;
+
+ Byte cache;
+ UInt32 range;
+ UInt64 low;
+ UInt64 cacheSize;
+
+ // UInt32 context; // for marker version, it can include marker flag.
+
+ /* (ip64) and (fileIp64) correspond to virtual source stream position
+ that doesn't include data in temp[] */
+ CBcj2Enc_ip_unsigned ip64; /* current (ip) position */
+ CBcj2Enc_ip_unsigned fileIp64; /* start (ip) position of current file */
+ CBcj2Enc_ip_unsigned fileSize64_minus1; /* size of current file (for conversion limitation) */
+ UInt32 relatLimit; /* (relatLimit <= ((UInt32)1 << 31)) : 0 means disable_conversion */
+ // UInt32 relatExcludeBits;
+
+ UInt32 tempTarget;
+ unsigned tempPos; /* the number of bytes that were copied to temp[] buffer
+ (tempPos <= 4) outside of Bcj2Enc_Encode() */
+ // Byte temp[4]; // for marker version
+ Byte temp[8];
+ CBcj2Prob probs[2 + 256];
+} CBcj2Enc;
+
+void Bcj2Enc_Init(CBcj2Enc *p);
+
+
+/*
+Bcj2Enc_Encode(): at exit:
+ p->State < BCJ2_NUM_STREAMS : we need more buffer space for output stream
+ (bufs[p->State] == lims[p->State])
+ p->State == BCJ2_ENC_STATE_ORIG : we need more data in input src stream
+ (src == srcLim)
+ p->State == BCJ2_ENC_STATE_FINISHED : after fully encoded stream
+*/
+void Bcj2Enc_Encode(CBcj2Enc *p);
+
+/* Bcj2Enc encoder can look ahead for up 4 bytes of source stream.
+ CBcj2Enc::tempPos : is the number of bytes that were copied from input stream to temp[] buffer.
+ (CBcj2Enc::src) after Bcj2Enc_Encode() is starting position after
+ fully processed data and after data copied to temp buffer.
+ So if the caller needs to get real number of fully processed input
+ bytes (without look ahead data in temp buffer),
+ the caller must subtruct (CBcj2Enc::tempPos) value from processed size
+ value that is calculated based on current (CBcj2Enc::src):
+ cur_processed_pos = Calc_Big_Processed_Pos(enc.src)) -
+ Bcj2Enc_Get_AvailInputSize_in_Temp(&enc);
+*/
+/* get the size of input data that was stored in temp[] buffer: */
+#define Bcj2Enc_Get_AvailInputSize_in_Temp(p) ((p)->tempPos)
+
+#define Bcj2Enc_IsFinished(p) ((p)->flushRem == 0)
+
+/* Note : the decoder supports overlapping of marker (0f 80).
+ But we can eliminate such overlapping cases by setting
+ the limit for relative offset conversion as
+ CBcj2Enc::relatLimit <= (0x0f << 24) == (240 MiB)
+*/
+/* default value for CBcj2Enc::relatLimit */
+#define BCJ2_ENC_RELAT_LIMIT_DEFAULT ((UInt32)0x0f << 24)
+#define BCJ2_ENC_RELAT_LIMIT_MAX ((UInt32)1 << 31)
+// #define BCJ2_RELAT_EXCLUDE_NUM_BITS 5
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Bcj2Enc.c b/C/Bcj2Enc.c
index 7a02ecd..79460bb 100644
--- a/C/Bcj2Enc.c
+++ b/C/Bcj2Enc.c
@@ -1,311 +1,506 @@
-/* Bcj2Enc.c -- BCJ2 Encoder (Converter for x86 code)
-2019-02-02 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-/* #define SHOW_STAT */
-
-#ifdef SHOW_STAT
-#include <stdio.h>
-#define PRF(x) x
-#else
-#define PRF(x)
-#endif
-
-#include <string.h>
-
-#include "Bcj2.h"
-#include "CpuArch.h"
-
-#define CProb UInt16
-
-#define kTopValue ((UInt32)1 << 24)
-#define kNumModelBits 11
-#define kBitModelTotal (1 << kNumModelBits)
-#define kNumMoveBits 5
-
-void Bcj2Enc_Init(CBcj2Enc *p)
-{
- unsigned i;
-
- p->state = BCJ2_ENC_STATE_OK;
- p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
-
- p->prevByte = 0;
-
- p->cache = 0;
- p->range = 0xFFFFFFFF;
- p->low = 0;
- p->cacheSize = 1;
-
- p->ip = 0;
-
- p->fileIp = 0;
- p->fileSize = 0;
- p->relatLimit = BCJ2_RELAT_LIMIT;
-
- p->tempPos = 0;
-
- p->flushPos = 0;
-
- for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++)
- p->probs[i] = kBitModelTotal >> 1;
-}
-
-static BoolInt MY_FAST_CALL RangeEnc_ShiftLow(CBcj2Enc *p)
-{
- if ((UInt32)p->low < (UInt32)0xFF000000 || (UInt32)(p->low >> 32) != 0)
- {
- Byte *buf = p->bufs[BCJ2_STREAM_RC];
- do
- {
- if (buf == p->lims[BCJ2_STREAM_RC])
- {
- p->state = BCJ2_STREAM_RC;
- p->bufs[BCJ2_STREAM_RC] = buf;
- return True;
- }
- *buf++ = (Byte)(p->cache + (Byte)(p->low >> 32));
- p->cache = 0xFF;
- }
- while (--p->cacheSize);
- p->bufs[BCJ2_STREAM_RC] = buf;
- p->cache = (Byte)((UInt32)p->low >> 24);
- }
- p->cacheSize++;
- p->low = (UInt32)p->low << 8;
- return False;
-}
-
-static void Bcj2Enc_Encode_2(CBcj2Enc *p)
-{
- if (BCJ2_IS_32BIT_STREAM(p->state))
- {
- Byte *cur = p->bufs[p->state];
- if (cur == p->lims[p->state])
- return;
- SetBe32(cur, p->tempTarget);
- p->bufs[p->state] = cur + 4;
- }
-
- p->state = BCJ2_ENC_STATE_ORIG;
-
- for (;;)
- {
- if (p->range < kTopValue)
- {
- if (RangeEnc_ShiftLow(p))
- return;
- p->range <<= 8;
- }
-
- {
- {
- const Byte *src = p->src;
- const Byte *srcLim;
- Byte *dest;
- SizeT num = p->srcLim - src;
-
- if (p->finishMode == BCJ2_ENC_FINISH_MODE_CONTINUE)
- {
- if (num <= 4)
- return;
- num -= 4;
- }
- else if (num == 0)
- break;
-
- dest = p->bufs[BCJ2_STREAM_MAIN];
- if (num > (SizeT)(p->lims[BCJ2_STREAM_MAIN] - dest))
- {
- num = p->lims[BCJ2_STREAM_MAIN] - dest;
- if (num == 0)
- {
- p->state = BCJ2_STREAM_MAIN;
- return;
- }
- }
-
- srcLim = src + num;
-
- if (p->prevByte == 0x0F && (src[0] & 0xF0) == 0x80)
- *dest = src[0];
- else for (;;)
- {
- Byte b = *src;
- *dest = b;
- if (b != 0x0F)
- {
- if ((b & 0xFE) == 0xE8)
- break;
- dest++;
- if (++src != srcLim)
- continue;
- break;
- }
- dest++;
- if (++src == srcLim)
- break;
- if ((*src & 0xF0) != 0x80)
- continue;
- *dest = *src;
- break;
- }
-
- num = src - p->src;
-
- if (src == srcLim)
- {
- p->prevByte = src[-1];
- p->bufs[BCJ2_STREAM_MAIN] = dest;
- p->src = src;
- p->ip += (UInt32)num;
- continue;
- }
-
- {
- Byte context = (Byte)(num == 0 ? p->prevByte : src[-1]);
- BoolInt needConvert;
-
- p->bufs[BCJ2_STREAM_MAIN] = dest + 1;
- p->ip += (UInt32)num + 1;
- src++;
-
- needConvert = False;
-
- if ((SizeT)(p->srcLim - src) >= 4)
- {
- UInt32 relatVal = GetUi32(src);
- if ((p->fileSize == 0 || (UInt32)(p->ip + 4 + relatVal - p->fileIp) < p->fileSize)
- && ((relatVal + p->relatLimit) >> 1) < p->relatLimit)
- needConvert = True;
- }
-
- {
- UInt32 bound;
- unsigned ttt;
- Byte b = src[-1];
- CProb *prob = p->probs + (unsigned)(b == 0xE8 ? 2 + (unsigned)context : (b == 0xE9 ? 1 : 0));
-
- ttt = *prob;
- bound = (p->range >> kNumModelBits) * ttt;
-
- if (!needConvert)
- {
- p->range = bound;
- *prob = (CProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
- p->src = src;
- p->prevByte = b;
- continue;
- }
-
- p->low += bound;
- p->range -= bound;
- *prob = (CProb)(ttt - (ttt >> kNumMoveBits));
-
- {
- UInt32 relatVal = GetUi32(src);
- UInt32 absVal;
- p->ip += 4;
- absVal = p->ip + relatVal;
- p->prevByte = src[3];
- src += 4;
- p->src = src;
- {
- unsigned cj = (b == 0xE8) ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP;
- Byte *cur = p->bufs[cj];
- if (cur == p->lims[cj])
- {
- p->state = cj;
- p->tempTarget = absVal;
- return;
- }
- SetBe32(cur, absVal);
- p->bufs[cj] = cur + 4;
- }
- }
- }
- }
- }
- }
- }
-
- if (p->finishMode != BCJ2_ENC_FINISH_MODE_END_STREAM)
- return;
-
- for (; p->flushPos < 5; p->flushPos++)
- if (RangeEnc_ShiftLow(p))
- return;
- p->state = BCJ2_ENC_STATE_OK;
-}
-
-
-void Bcj2Enc_Encode(CBcj2Enc *p)
-{
- PRF(printf("\n"));
- PRF(printf("---- ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src));
-
- if (p->tempPos != 0)
- {
- unsigned extra = 0;
-
- for (;;)
- {
- const Byte *src = p->src;
- const Byte *srcLim = p->srcLim;
- EBcj2Enc_FinishMode finishMode = p->finishMode;
-
- p->src = p->temp;
- p->srcLim = p->temp + p->tempPos;
- if (src != srcLim)
- p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
-
- PRF(printf(" ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src));
-
- Bcj2Enc_Encode_2(p);
-
- {
- unsigned num = (unsigned)(p->src - p->temp);
- unsigned tempPos = p->tempPos - num;
- unsigned i;
- p->tempPos = tempPos;
- for (i = 0; i < tempPos; i++)
- p->temp[i] = p->temp[(size_t)i + num];
-
- p->src = src;
- p->srcLim = srcLim;
- p->finishMode = finishMode;
-
- if (p->state != BCJ2_ENC_STATE_ORIG || src == srcLim)
- return;
-
- if (extra >= tempPos)
- {
- p->src = src - tempPos;
- p->tempPos = 0;
- break;
- }
-
- p->temp[tempPos] = src[0];
- p->tempPos = tempPos + 1;
- p->src = src + 1;
- extra++;
- }
- }
- }
-
- PRF(printf("++++ ip = %8d tempPos = %8d src = %8d\n", p->ip, p->tempPos, p->srcLim - p->src));
-
- Bcj2Enc_Encode_2(p);
-
- if (p->state == BCJ2_ENC_STATE_ORIG)
- {
- const Byte *src = p->src;
- unsigned rem = (unsigned)(p->srcLim - src);
- unsigned i;
- for (i = 0; i < rem; i++)
- p->temp[i] = src[i];
- p->tempPos = rem;
- p->src = src + rem;
- }
-}
+/* Bcj2Enc.c -- BCJ2 Encoder converter for x86 code (Branch CALL/JUMP variant2)
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+/* #define SHOW_STAT */
+#ifdef SHOW_STAT
+#include <stdio.h>
+#define PRF2(s) printf("%s ip=%8x tempPos=%d src= %8x\n", s, (unsigned)p->ip64, p->tempPos, (unsigned)(p->srcLim - p->src));
+#else
+#define PRF2(s)
+#endif
+
+#include "Bcj2.h"
+#include "CpuArch.h"
+
+#define kTopValue ((UInt32)1 << 24)
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+void Bcj2Enc_Init(CBcj2Enc *p)
+{
+ unsigned i;
+ p->state = BCJ2_ENC_STATE_ORIG;
+ p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
+ p->context = 0;
+ p->flushRem = 5;
+ p->isFlushState = 0;
+ p->cache = 0;
+ p->range = 0xffffffff;
+ p->low = 0;
+ p->cacheSize = 1;
+ p->ip64 = 0;
+ p->fileIp64 = 0;
+ p->fileSize64_minus1 = BCJ2_ENC_FileSizeField_UNLIMITED;
+ p->relatLimit = BCJ2_ENC_RELAT_LIMIT_DEFAULT;
+ // p->relatExcludeBits = 0;
+ p->tempPos = 0;
+ for (i = 0; i < sizeof(p->probs) / sizeof(p->probs[0]); i++)
+ p->probs[i] = kBitModelTotal >> 1;
+}
+
+// Z7_NO_INLINE
+Z7_FORCE_INLINE
+static BoolInt Bcj2_RangeEnc_ShiftLow(CBcj2Enc *p)
+{
+ const UInt32 low = (UInt32)p->low;
+ const unsigned high = (unsigned)
+ #if defined(Z7_MSC_VER_ORIGINAL) \
+ && defined(MY_CPU_X86) \
+ && defined(MY_CPU_LE) \
+ && !defined(MY_CPU_64BIT)
+ // we try to rid of __aullshr() call in MSVS-x86
+ (((const UInt32 *)&p->low)[1]); // [1] : for little-endian only
+ #else
+ (p->low >> 32);
+ #endif
+ if (low < (UInt32)0xff000000 || high != 0)
+ {
+ Byte *buf = p->bufs[BCJ2_STREAM_RC];
+ do
+ {
+ if (buf == p->lims[BCJ2_STREAM_RC])
+ {
+ p->state = BCJ2_STREAM_RC;
+ p->bufs[BCJ2_STREAM_RC] = buf;
+ return True;
+ }
+ *buf++ = (Byte)(p->cache + high);
+ p->cache = 0xff;
+ }
+ while (--p->cacheSize);
+ p->bufs[BCJ2_STREAM_RC] = buf;
+ p->cache = (Byte)(low >> 24);
+ }
+ p->cacheSize++;
+ p->low = low << 8;
+ return False;
+}
+
+
+/*
+We can use 2 alternative versions of code:
+1) non-marker version:
+ Byte CBcj2Enc::context
+ Byte temp[8];
+ Last byte of marker (e8/e9/[0f]8x) can be written to temp[] buffer.
+ Encoder writes last byte of marker (e8/e9/[0f]8x) to dest, only in conjunction
+ with writing branch symbol to range coder in same Bcj2Enc_Encode_2() call.
+
+2) marker version:
+ UInt32 CBcj2Enc::context
+ Byte CBcj2Enc::temp[4];
+ MARKER_FLAG in CBcj2Enc::context shows that CBcj2Enc::context contains finded marker.
+ it's allowed that
+ one call of Bcj2Enc_Encode_2() writes last byte of marker (e8/e9/[0f]8x) to dest,
+ and another call of Bcj2Enc_Encode_2() does offset conversion.
+ So different values of (fileIp) and (fileSize) are possible
+ in these different Bcj2Enc_Encode_2() calls.
+
+Also marker version requires additional if((v & MARKER_FLAG) == 0) check in main loop.
+So we use non-marker version.
+*/
+
+/*
+ Corner cases with overlap in multi-block.
+ before v23: there was one corner case, where converted instruction
+ could start in one sub-stream and finish in next sub-stream.
+ If multi-block (solid) encoding is used,
+ and BCJ2_ENC_FINISH_MODE_END_BLOCK is used for each sub-stream.
+ and (0f) is last byte of previous sub-stream
+ and (8x) is first byte of current sub-stream
+ then (0f 8x) pair is treated as marker by BCJ2 encoder and decoder.
+ BCJ2 encoder can converts 32-bit offset for that (0f 8x) cortage,
+ if that offset meets limit requirements.
+ If encoder allows 32-bit offset conversion for such overlap case,
+ then the data in 3 uncompressed BCJ2 streams for some sub-stream
+ can depend from data of previous sub-stream.
+ That corner case is not big problem, and it's rare case.
+ Since v23.00 we do additional check to prevent conversions in such overlap cases.
+*/
+
+/*
+ Bcj2Enc_Encode_2() output variables at exit:
+ {
+ if (Bcj2Enc_Encode_2() exits with (p->state == BCJ2_ENC_STATE_ORIG))
+ {
+ it means that encoder needs more input data.
+ if (p->srcLim == p->src) at exit, then
+ {
+ (p->finishMode != BCJ2_ENC_FINISH_MODE_END_STREAM)
+ all input data were read and processed, and we are ready for
+ new input data.
+ }
+ else
+ {
+ (p->srcLim != p->src)
+ (p->finishMode == BCJ2_ENC_FINISH_MODE_CONTINUE)
+ The encoder have found e8/e9/0f_8x marker,
+ and p->src points to last byte of that marker,
+ Bcj2Enc_Encode_2() needs more input data to get totally
+ 5 bytes (last byte of marker and 32-bit branch offset)
+ as continuous array starting from p->src.
+ (p->srcLim - p->src < 5) requirement is met after exit.
+ So non-processed resedue from p->src to p->srcLim is always less than 5 bytes.
+ }
+ }
+ }
+*/
+
+Z7_NO_INLINE
+static void Bcj2Enc_Encode_2(CBcj2Enc *p)
+{
+ if (!p->isFlushState)
+ {
+ const Byte *src;
+ UInt32 v;
+ {
+ const unsigned state = p->state;
+ if (BCJ2_IS_32BIT_STREAM(state))
+ {
+ Byte *cur = p->bufs[state];
+ if (cur == p->lims[state])
+ return;
+ SetBe32a(cur, p->tempTarget)
+ p->bufs[state] = cur + 4;
+ }
+ }
+ p->state = BCJ2_ENC_STATE_ORIG; // for main reason of exit
+ src = p->src;
+ v = p->context;
+
+ // #define WRITE_CONTEXT p->context = v; // for marker version
+ #define WRITE_CONTEXT p->context = (Byte)v;
+ #define WRITE_CONTEXT_AND_SRC p->src = src; WRITE_CONTEXT
+
+ for (;;)
+ {
+ // const Byte *src;
+ // UInt32 v;
+ CBcj2Enc_ip_unsigned ip;
+ if (p->range < kTopValue)
+ {
+ // to reduce register pressure and code size: we save and restore local variables.
+ WRITE_CONTEXT_AND_SRC
+ if (Bcj2_RangeEnc_ShiftLow(p))
+ return;
+ p->range <<= 8;
+ src = p->src;
+ v = p->context;
+ }
+ // src = p->src;
+ // #define MARKER_FLAG ((UInt32)1 << 17)
+ // if ((v & MARKER_FLAG) == 0) // for marker version
+ {
+ const Byte *srcLim;
+ Byte *dest = p->bufs[BCJ2_STREAM_MAIN];
+ {
+ const SizeT remSrc = (SizeT)(p->srcLim - src);
+ SizeT rem = (SizeT)(p->lims[BCJ2_STREAM_MAIN] - dest);
+ if (rem >= remSrc)
+ rem = remSrc;
+ srcLim = src + rem;
+ }
+ /* p->context contains context of previous byte:
+ bits [0 : 7] : src[-1], if (src) was changed in this call
+ bits [8 : 31] : are undefined for non-marker version
+ */
+ // v = p->context;
+ #define NUM_SHIFT_BITS 24
+ #define CONV_FLAG ((UInt32)1 << 16)
+ #define ONE_ITER { \
+ b = src[0]; \
+ *dest++ = (Byte)b; \
+ v = (v << NUM_SHIFT_BITS) | b; \
+ if (((b + (0x100 - 0xe8)) & 0xfe) == 0) break; \
+ if (((v - (((UInt32)0x0f << (NUM_SHIFT_BITS)) + 0x80)) & \
+ ((((UInt32)1 << (4 + NUM_SHIFT_BITS)) - 0x1) << 4)) == 0) break; \
+ src++; if (src == srcLim) { break; } }
+
+ if (src != srcLim)
+ for (;;)
+ {
+ /* clang can generate ineffective code with setne instead of two jcc instructions.
+ we can use 2 iterations and external (unsigned b) to avoid that ineffective code genaration. */
+ unsigned b;
+ ONE_ITER
+ ONE_ITER
+ }
+
+ ip = p->ip64 + (CBcj2Enc_ip_unsigned)(SizeT)(dest - p->bufs[BCJ2_STREAM_MAIN]);
+ p->bufs[BCJ2_STREAM_MAIN] = dest;
+ p->ip64 = ip;
+
+ if (src == srcLim)
+ {
+ WRITE_CONTEXT_AND_SRC
+ if (src != p->srcLim)
+ {
+ p->state = BCJ2_STREAM_MAIN;
+ return;
+ }
+ /* (p->src == p->srcLim)
+ (p->state == BCJ2_ENC_STATE_ORIG) */
+ if (p->finishMode != BCJ2_ENC_FINISH_MODE_END_STREAM)
+ return;
+ /* (p->finishMode == BCJ2_ENC_FINISH_MODE_END_STREAM */
+ // (p->flushRem == 5);
+ p->isFlushState = 1;
+ break;
+ }
+ src++;
+ // p->src = src;
+ }
+ // ip = p->ip; // for marker version
+ /* marker was found */
+ /* (v) contains marker that was found:
+ bits [NUM_SHIFT_BITS : NUM_SHIFT_BITS + 7]
+ : value of src[-2] : xx/xx/0f
+ bits [0 : 7] : value of src[-1] : e8/e9/8x
+ */
+ {
+ {
+ #if NUM_SHIFT_BITS != 24
+ v &= ~(UInt32)CONV_FLAG;
+ #endif
+ // UInt32 relat = 0;
+ if ((SizeT)(p->srcLim - src) >= 4)
+ {
+ /*
+ if (relat != 0 || (Byte)v != 0xe8)
+ BoolInt isBigOffset = True;
+ */
+ const UInt32 relat = GetUi32(src);
+ /*
+ #define EXCLUDE_FLAG ((UInt32)1 << 4)
+ #define NEED_CONVERT(rel) ((((rel) + EXCLUDE_FLAG) & (0 - EXCLUDE_FLAG * 2)) != 0)
+ if (p->relatExcludeBits != 0)
+ {
+ const UInt32 flag = (UInt32)1 << (p->relatExcludeBits - 1);
+ isBigOffset = (((relat + flag) & (0 - flag * 2)) != 0);
+ }
+ // isBigOffset = False; // for debug
+ */
+ ip -= p->fileIp64;
+ // Use the following if check, if (ip) is 64-bit:
+ if (ip > (((v + 0x20) >> 5) & 1)) // 23.00 : we eliminate milti-block overlap for (Of 80) and (e8/e9)
+ if ((CBcj2Enc_ip_unsigned)((CBcj2Enc_ip_signed)ip + 4 + (Int32)relat) <= p->fileSize64_minus1)
+ if (((UInt32)(relat + p->relatLimit) >> 1) < p->relatLimit)
+ v |= CONV_FLAG;
+ }
+ else if (p->finishMode == BCJ2_ENC_FINISH_MODE_CONTINUE)
+ {
+ // (p->srcLim - src < 4)
+ // /*
+ // for non-marker version
+ p->ip64--; // p->ip = ip - 1;
+ p->bufs[BCJ2_STREAM_MAIN]--;
+ src--;
+ v >>= NUM_SHIFT_BITS;
+ // (0 < p->srcLim - p->src <= 4)
+ // */
+ // v |= MARKER_FLAG; // for marker version
+ /* (p->state == BCJ2_ENC_STATE_ORIG) */
+ WRITE_CONTEXT_AND_SRC
+ return;
+ }
+ {
+ const unsigned c = ((v + 0x17) >> 6) & 1;
+ CBcj2Prob *prob = p->probs + (unsigned)
+ (((0 - c) & (Byte)(v >> NUM_SHIFT_BITS)) + c + ((v >> 5) & 1));
+ /*
+ ((Byte)v == 0xe8 ? 2 + ((Byte)(v >> 8)) :
+ ((Byte)v < 0xe8 ? 0 : 1)); // ((v >> 5) & 1));
+ */
+ const unsigned ttt = *prob;
+ const UInt32 bound = (p->range >> kNumBitModelTotalBits) * ttt;
+ if ((v & CONV_FLAG) == 0)
+ {
+ // static int yyy = 0; yyy++; printf("\n!needConvert = %d\n", yyy);
+ // v = (Byte)v; // for marker version
+ p->range = bound;
+ *prob = (CBcj2Prob)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
+ // WRITE_CONTEXT_AND_SRC
+ continue;
+ }
+ p->low += bound;
+ p->range -= bound;
+ *prob = (CBcj2Prob)(ttt - (ttt >> kNumMoveBits));
+ }
+ // p->context = src[3];
+ {
+ // const unsigned cj = ((Byte)v == 0xe8 ? BCJ2_STREAM_CALL : BCJ2_STREAM_JUMP);
+ const unsigned cj = (((v + 0x57) >> 6) & 1) + BCJ2_STREAM_CALL;
+ ip = p->ip64;
+ v = GetUi32(src); // relat
+ ip += 4;
+ p->ip64 = ip;
+ src += 4;
+ // p->src = src;
+ {
+ const UInt32 absol = (UInt32)ip + v;
+ Byte *cur = p->bufs[cj];
+ v >>= 24;
+ // WRITE_CONTEXT
+ if (cur == p->lims[cj])
+ {
+ p->state = cj;
+ p->tempTarget = absol;
+ WRITE_CONTEXT_AND_SRC
+ return;
+ }
+ SetBe32a(cur, absol)
+ p->bufs[cj] = cur + 4;
+ }
+ }
+ }
+ }
+ } // end of loop
+ }
+
+ for (; p->flushRem != 0; p->flushRem--)
+ if (Bcj2_RangeEnc_ShiftLow(p))
+ return;
+ p->state = BCJ2_ENC_STATE_FINISHED;
+}
+
+
+/*
+BCJ2 encoder needs look ahead for up to 4 bytes in (src) buffer.
+So base function Bcj2Enc_Encode_2()
+ in BCJ2_ENC_FINISH_MODE_CONTINUE mode can return with
+ (p->state == BCJ2_ENC_STATE_ORIG && p->src < p->srcLim)
+Bcj2Enc_Encode() solves that look ahead problem by using p->temp[] buffer.
+ so if (p->state == BCJ2_ENC_STATE_ORIG) after Bcj2Enc_Encode(),
+ then (p->src == p->srcLim).
+ And the caller's code is simpler with Bcj2Enc_Encode().
+*/
+
+Z7_NO_INLINE
+void Bcj2Enc_Encode(CBcj2Enc *p)
+{
+ PRF2("\n----")
+ if (p->tempPos != 0)
+ {
+ /* extra: number of bytes that were copied from (src) to (temp) buffer in this call */
+ unsigned extra = 0;
+ /* We will touch only minimal required number of bytes in input (src) stream.
+ So we will add input bytes from (src) stream to temp[] with step of 1 byte.
+ We don't add new bytes to temp[] before Bcj2Enc_Encode_2() call
+ in first loop iteration because
+ - previous call of Bcj2Enc_Encode() could use another (finishMode),
+ - previous call could finish with (p->state != BCJ2_ENC_STATE_ORIG).
+ the case with full temp[] buffer (p->tempPos == 4) is possible here.
+ */
+ for (;;)
+ {
+ // (0 < p->tempPos <= 5) // in non-marker version
+ /* p->src : the current src data position including extra bytes
+ that were copied to temp[] buffer in this call */
+ const Byte *src = p->src;
+ const Byte *srcLim = p->srcLim;
+ const EBcj2Enc_FinishMode finishMode = p->finishMode;
+ if (src != srcLim)
+ {
+ /* if there are some src data after the data copied to temp[],
+ then we use MODE_CONTINUE for temp data */
+ p->finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
+ }
+ p->src = p->temp;
+ p->srcLim = p->temp + p->tempPos;
+ PRF2(" ")
+ Bcj2Enc_Encode_2(p);
+ {
+ const unsigned num = (unsigned)(p->src - p->temp);
+ const unsigned tempPos = p->tempPos - num;
+ unsigned i;
+ p->tempPos = tempPos;
+ for (i = 0; i < tempPos; i++)
+ p->temp[i] = p->temp[(SizeT)i + num];
+ // tempPos : number of bytes in temp buffer
+ p->src = src;
+ p->srcLim = srcLim;
+ p->finishMode = finishMode;
+ if (p->state != BCJ2_ENC_STATE_ORIG)
+ {
+ // (p->tempPos <= 4) // in non-marker version
+ /* if (the reason of exit from Bcj2Enc_Encode_2()
+ is not BCJ2_ENC_STATE_ORIG),
+ then we exit from Bcj2Enc_Encode() with same reason */
+ // optional code begin : we rollback (src) and tempPos, if it's possible:
+ if (extra >= tempPos)
+ extra = tempPos;
+ p->src = src - extra;
+ p->tempPos = tempPos - extra;
+ // optional code end : rollback of (src) and tempPos
+ return;
+ }
+ /* (p->tempPos <= 4)
+ (p->state == BCJ2_ENC_STATE_ORIG)
+ so encoder needs more data than in temp[] */
+ if (src == srcLim)
+ return; // src buffer has no more input data.
+ /* (src != srcLim)
+ so we can provide more input data from src for Bcj2Enc_Encode_2() */
+ if (extra >= tempPos)
+ {
+ /* (extra >= tempPos) means that temp buffer contains
+ only data from src buffer of this call.
+ So now we can encode without temp buffer */
+ p->src = src - tempPos; // rollback (src)
+ p->tempPos = 0;
+ break;
+ }
+ // we append one additional extra byte from (src) to temp[] buffer:
+ p->temp[tempPos] = *src;
+ p->tempPos = tempPos + 1;
+ // (0 < p->tempPos <= 5) // in non-marker version
+ p->src = src + 1;
+ extra++;
+ }
+ }
+ }
+
+ PRF2("++++")
+ // (p->tempPos == 0)
+ Bcj2Enc_Encode_2(p);
+ PRF2("====")
+
+ if (p->state == BCJ2_ENC_STATE_ORIG)
+ {
+ const Byte *src = p->src;
+ const Byte *srcLim = p->srcLim;
+ const unsigned rem = (unsigned)(srcLim - src);
+ /* (rem <= 4) here.
+ if (p->src != p->srcLim), then
+ - we copy non-processed bytes from (p->src) to temp[] buffer,
+ - we set p->src equal to p->srcLim.
+ */
+ if (rem)
+ {
+ unsigned i = 0;
+ p->src = srcLim;
+ p->tempPos = rem;
+ // (0 < p->tempPos <= 4)
+ do
+ p->temp[i] = src[i];
+ while (++i != rem);
+ }
+ // (p->tempPos <= 4)
+ // (p->src == p->srcLim)
+ }
+}
+
+#undef PRF2
+#undef CONV_FLAG
+#undef MARKER_FLAG
+#undef WRITE_CONTEXT
+#undef WRITE_CONTEXT_AND_SRC
+#undef ONE_ITER
+#undef NUM_SHIFT_BITS
+#undef kTopValue
+#undef kNumBitModelTotalBits
+#undef kBitModelTotal
+#undef kNumMoveBits
diff --git a/C/Blake2.h b/C/Blake2.h
new file mode 100644
index 0000000..7235235
--- /dev/null
+++ b/C/Blake2.h
@@ -0,0 +1,48 @@
+/* Blake2.h -- BLAKE2 Hash
+2023-03-04 : Igor Pavlov : Public domain
+2015 : Samuel Neves : Public domain */
+
+#ifndef ZIP7_INC_BLAKE2_H
+#define ZIP7_INC_BLAKE2_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define BLAKE2S_BLOCK_SIZE 64
+#define BLAKE2S_DIGEST_SIZE 32
+#define BLAKE2SP_PARALLEL_DEGREE 8
+
+typedef struct
+{
+ UInt32 h[8];
+ UInt32 t[2];
+ UInt32 f[2];
+ Byte buf[BLAKE2S_BLOCK_SIZE];
+ UInt32 bufPos;
+ UInt32 lastNode_f1;
+ UInt32 dummy[2]; /* for sizeof(CBlake2s) alignment */
+} CBlake2s;
+
+/* You need to xor CBlake2s::h[i] with input parameter block after Blake2s_Init0() */
+/*
+void Blake2s_Init0(CBlake2s *p);
+void Blake2s_Update(CBlake2s *p, const Byte *data, size_t size);
+void Blake2s_Final(CBlake2s *p, Byte *digest);
+*/
+
+
+typedef struct
+{
+ CBlake2s S[BLAKE2SP_PARALLEL_DEGREE];
+ unsigned bufPos;
+} CBlake2sp;
+
+
+void Blake2sp_Init(CBlake2sp *p);
+void Blake2sp_Update(CBlake2sp *p, const Byte *data, size_t size);
+void Blake2sp_Final(CBlake2sp *p, Byte *digest);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Blake2s.c b/C/Blake2s.c
new file mode 100644
index 0000000..2a84b57
--- /dev/null
+++ b/C/Blake2s.c
@@ -0,0 +1,250 @@
+/* Blake2s.c -- BLAKE2s and BLAKE2sp Hash
+2023-03-04 : Igor Pavlov : Public domain
+2015 : Samuel Neves : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#include "Blake2.h"
+#include "CpuArch.h"
+#include "RotateDefs.h"
+
+#define rotr32 rotrFixed
+
+#define BLAKE2S_NUM_ROUNDS 10
+#define BLAKE2S_FINAL_FLAG (~(UInt32)0)
+
+static const UInt32 k_Blake2s_IV[8] =
+{
+ 0x6A09E667UL, 0xBB67AE85UL, 0x3C6EF372UL, 0xA54FF53AUL,
+ 0x510E527FUL, 0x9B05688CUL, 0x1F83D9ABUL, 0x5BE0CD19UL
+};
+
+static const Byte k_Blake2s_Sigma[BLAKE2S_NUM_ROUNDS][16] =
+{
+ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 } ,
+ { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 } ,
+ { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 } ,
+ { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 } ,
+ { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 } ,
+ { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 } ,
+ { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 } ,
+ { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 } ,
+ { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 } ,
+ { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13 , 0 } ,
+};
+
+
+static void Blake2s_Init0(CBlake2s *p)
+{
+ unsigned i;
+ for (i = 0; i < 8; i++)
+ p->h[i] = k_Blake2s_IV[i];
+ p->t[0] = 0;
+ p->t[1] = 0;
+ p->f[0] = 0;
+ p->f[1] = 0;
+ p->bufPos = 0;
+ p->lastNode_f1 = 0;
+}
+
+
+static void Blake2s_Compress(CBlake2s *p)
+{
+ UInt32 m[16];
+ UInt32 v[16];
+
+ {
+ unsigned i;
+
+ for (i = 0; i < 16; i++)
+ m[i] = GetUi32(p->buf + i * sizeof(m[i]));
+
+ for (i = 0; i < 8; i++)
+ v[i] = p->h[i];
+ }
+
+ v[ 8] = k_Blake2s_IV[0];
+ v[ 9] = k_Blake2s_IV[1];
+ v[10] = k_Blake2s_IV[2];
+ v[11] = k_Blake2s_IV[3];
+
+ v[12] = p->t[0] ^ k_Blake2s_IV[4];
+ v[13] = p->t[1] ^ k_Blake2s_IV[5];
+ v[14] = p->f[0] ^ k_Blake2s_IV[6];
+ v[15] = p->f[1] ^ k_Blake2s_IV[7];
+
+ #define G(r,i,a,b,c,d) \
+ a += b + m[sigma[2*i+0]]; d ^= a; d = rotr32(d, 16); c += d; b ^= c; b = rotr32(b, 12); \
+ a += b + m[sigma[2*i+1]]; d ^= a; d = rotr32(d, 8); c += d; b ^= c; b = rotr32(b, 7); \
+
+ #define R(r) \
+ G(r,0,v[ 0],v[ 4],v[ 8],v[12]) \
+ G(r,1,v[ 1],v[ 5],v[ 9],v[13]) \
+ G(r,2,v[ 2],v[ 6],v[10],v[14]) \
+ G(r,3,v[ 3],v[ 7],v[11],v[15]) \
+ G(r,4,v[ 0],v[ 5],v[10],v[15]) \
+ G(r,5,v[ 1],v[ 6],v[11],v[12]) \
+ G(r,6,v[ 2],v[ 7],v[ 8],v[13]) \
+ G(r,7,v[ 3],v[ 4],v[ 9],v[14]) \
+
+ {
+ unsigned r;
+ for (r = 0; r < BLAKE2S_NUM_ROUNDS; r++)
+ {
+ const Byte *sigma = k_Blake2s_Sigma[r];
+ R(r)
+ }
+ /* R(0); R(1); R(2); R(3); R(4); R(5); R(6); R(7); R(8); R(9); */
+ }
+
+ #undef G
+ #undef R
+
+ {
+ unsigned i;
+ for (i = 0; i < 8; i++)
+ p->h[i] ^= v[i] ^ v[i + 8];
+ }
+}
+
+
+#define Blake2s_Increment_Counter(S, inc) \
+ { p->t[0] += (inc); p->t[1] += (p->t[0] < (inc)); }
+
+#define Blake2s_Set_LastBlock(p) \
+ { p->f[0] = BLAKE2S_FINAL_FLAG; p->f[1] = p->lastNode_f1; }
+
+
+static void Blake2s_Update(CBlake2s *p, const Byte *data, size_t size)
+{
+ while (size != 0)
+ {
+ unsigned pos = (unsigned)p->bufPos;
+ unsigned rem = BLAKE2S_BLOCK_SIZE - pos;
+
+ if (size <= rem)
+ {
+ memcpy(p->buf + pos, data, size);
+ p->bufPos += (UInt32)size;
+ return;
+ }
+
+ memcpy(p->buf + pos, data, rem);
+ Blake2s_Increment_Counter(S, BLAKE2S_BLOCK_SIZE)
+ Blake2s_Compress(p);
+ p->bufPos = 0;
+ data += rem;
+ size -= rem;
+ }
+}
+
+
+static void Blake2s_Final(CBlake2s *p, Byte *digest)
+{
+ unsigned i;
+
+ Blake2s_Increment_Counter(S, (UInt32)p->bufPos)
+ Blake2s_Set_LastBlock(p)
+ memset(p->buf + p->bufPos, 0, BLAKE2S_BLOCK_SIZE - p->bufPos);
+ Blake2s_Compress(p);
+
+ for (i = 0; i < 8; i++)
+ {
+ SetUi32(digest + sizeof(p->h[i]) * i, p->h[i])
+ }
+}
+
+
+/* ---------- BLAKE2s ---------- */
+
+/* we need to xor CBlake2s::h[i] with input parameter block after Blake2s_Init0() */
+/*
+typedef struct
+{
+ Byte digest_length;
+ Byte key_length;
+ Byte fanout;
+ Byte depth;
+ UInt32 leaf_length;
+ Byte node_offset[6];
+ Byte node_depth;
+ Byte inner_length;
+ Byte salt[BLAKE2S_SALTBYTES];
+ Byte personal[BLAKE2S_PERSONALBYTES];
+} CBlake2sParam;
+*/
+
+
+static void Blake2sp_Init_Spec(CBlake2s *p, unsigned node_offset, unsigned node_depth)
+{
+ Blake2s_Init0(p);
+
+ p->h[0] ^= (BLAKE2S_DIGEST_SIZE | ((UInt32)BLAKE2SP_PARALLEL_DEGREE << 16) | ((UInt32)2 << 24));
+ p->h[2] ^= ((UInt32)node_offset);
+ p->h[3] ^= ((UInt32)node_depth << 16) | ((UInt32)BLAKE2S_DIGEST_SIZE << 24);
+ /*
+ P->digest_length = BLAKE2S_DIGEST_SIZE;
+ P->key_length = 0;
+ P->fanout = BLAKE2SP_PARALLEL_DEGREE;
+ P->depth = 2;
+ P->leaf_length = 0;
+ store48(P->node_offset, node_offset);
+ P->node_depth = node_depth;
+ P->inner_length = BLAKE2S_DIGEST_SIZE;
+ */
+}
+
+
+void Blake2sp_Init(CBlake2sp *p)
+{
+ unsigned i;
+
+ p->bufPos = 0;
+
+ for (i = 0; i < BLAKE2SP_PARALLEL_DEGREE; i++)
+ Blake2sp_Init_Spec(&p->S[i], i, 0);
+
+ p->S[BLAKE2SP_PARALLEL_DEGREE - 1].lastNode_f1 = BLAKE2S_FINAL_FLAG;
+}
+
+
+void Blake2sp_Update(CBlake2sp *p, const Byte *data, size_t size)
+{
+ unsigned pos = p->bufPos;
+ while (size != 0)
+ {
+ unsigned index = pos / BLAKE2S_BLOCK_SIZE;
+ unsigned rem = BLAKE2S_BLOCK_SIZE - (pos & (BLAKE2S_BLOCK_SIZE - 1));
+ if (rem > size)
+ rem = (unsigned)size;
+ Blake2s_Update(&p->S[index], data, rem);
+ size -= rem;
+ data += rem;
+ pos += rem;
+ pos &= (BLAKE2S_BLOCK_SIZE * BLAKE2SP_PARALLEL_DEGREE - 1);
+ }
+ p->bufPos = pos;
+}
+
+
+void Blake2sp_Final(CBlake2sp *p, Byte *digest)
+{
+ CBlake2s R;
+ unsigned i;
+
+ Blake2sp_Init_Spec(&R, 0, 1);
+ R.lastNode_f1 = BLAKE2S_FINAL_FLAG;
+
+ for (i = 0; i < BLAKE2SP_PARALLEL_DEGREE; i++)
+ {
+ Byte hash[BLAKE2S_DIGEST_SIZE];
+ Blake2s_Final(&p->S[i], hash);
+ Blake2s_Update(&R, hash, BLAKE2S_DIGEST_SIZE);
+ }
+
+ Blake2s_Final(&R, digest);
+}
+
+#undef rotr32
diff --git a/C/Bra.c b/C/Bra.c
index cbdcb29..22e0e47 100644
--- a/C/Bra.c
+++ b/C/Bra.c
@@ -1,230 +1,420 @@
-/* Bra.c -- Converters for RISC code
-2017-04-04 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "CpuArch.h"
-#include "Bra.h"
-
-SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
-{
- Byte *p;
- const Byte *lim;
- size &= ~(size_t)3;
- ip += 4;
- p = data;
- lim = data + size;
-
- if (encoding)
-
- for (;;)
- {
- for (;;)
- {
- if (p >= lim)
- return p - data;
- p += 4;
- if (p[-1] == 0xEB)
- break;
- }
- {
- UInt32 v = GetUi32(p - 4);
- v <<= 2;
- v += ip + (UInt32)(p - data);
- v >>= 2;
- v &= 0x00FFFFFF;
- v |= 0xEB000000;
- SetUi32(p - 4, v);
- }
- }
-
- for (;;)
- {
- for (;;)
- {
- if (p >= lim)
- return p - data;
- p += 4;
- if (p[-1] == 0xEB)
- break;
- }
- {
- UInt32 v = GetUi32(p - 4);
- v <<= 2;
- v -= ip + (UInt32)(p - data);
- v >>= 2;
- v &= 0x00FFFFFF;
- v |= 0xEB000000;
- SetUi32(p - 4, v);
- }
- }
-}
-
-
-SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
-{
- Byte *p;
- const Byte *lim;
- size &= ~(size_t)1;
- p = data;
- lim = data + size - 4;
-
- if (encoding)
-
- for (;;)
- {
- UInt32 b1;
- for (;;)
- {
- UInt32 b3;
- if (p > lim)
- return p - data;
- b1 = p[1];
- b3 = p[3];
- p += 2;
- b1 ^= 8;
- if ((b3 & b1) >= 0xF8)
- break;
- }
- {
- UInt32 v =
- ((UInt32)b1 << 19)
- + (((UInt32)p[1] & 0x7) << 8)
- + (((UInt32)p[-2] << 11))
- + (p[0]);
-
- p += 2;
- {
- UInt32 cur = (ip + (UInt32)(p - data)) >> 1;
- v += cur;
- }
-
- p[-4] = (Byte)(v >> 11);
- p[-3] = (Byte)(0xF0 | ((v >> 19) & 0x7));
- p[-2] = (Byte)v;
- p[-1] = (Byte)(0xF8 | (v >> 8));
- }
- }
-
- for (;;)
- {
- UInt32 b1;
- for (;;)
- {
- UInt32 b3;
- if (p > lim)
- return p - data;
- b1 = p[1];
- b3 = p[3];
- p += 2;
- b1 ^= 8;
- if ((b3 & b1) >= 0xF8)
- break;
- }
- {
- UInt32 v =
- ((UInt32)b1 << 19)
- + (((UInt32)p[1] & 0x7) << 8)
- + (((UInt32)p[-2] << 11))
- + (p[0]);
-
- p += 2;
- {
- UInt32 cur = (ip + (UInt32)(p - data)) >> 1;
- v -= cur;
- }
-
- /*
- SetUi16(p - 4, (UInt16)(((v >> 11) & 0x7FF) | 0xF000));
- SetUi16(p - 2, (UInt16)(v | 0xF800));
- */
-
- p[-4] = (Byte)(v >> 11);
- p[-3] = (Byte)(0xF0 | ((v >> 19) & 0x7));
- p[-2] = (Byte)v;
- p[-1] = (Byte)(0xF8 | (v >> 8));
- }
- }
-}
-
-
-SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
-{
- Byte *p;
- const Byte *lim;
- size &= ~(size_t)3;
- ip -= 4;
- p = data;
- lim = data + size;
-
- for (;;)
- {
- for (;;)
- {
- if (p >= lim)
- return p - data;
- p += 4;
- /* if ((v & 0xFC000003) == 0x48000001) */
- if ((p[-4] & 0xFC) == 0x48 && (p[-1] & 3) == 1)
- break;
- }
- {
- UInt32 v = GetBe32(p - 4);
- if (encoding)
- v += ip + (UInt32)(p - data);
- else
- v -= ip + (UInt32)(p - data);
- v &= 0x03FFFFFF;
- v |= 0x48000000;
- SetBe32(p - 4, v);
- }
- }
-}
-
-
-SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
-{
- Byte *p;
- const Byte *lim;
- size &= ~(size_t)3;
- ip -= 4;
- p = data;
- lim = data + size;
-
- for (;;)
- {
- for (;;)
- {
- if (p >= lim)
- return p - data;
- /*
- v = GetBe32(p);
- p += 4;
- m = v + ((UInt32)5 << 29);
- m ^= (UInt32)7 << 29;
- m += (UInt32)1 << 22;
- if ((m & ((UInt32)0x1FF << 23)) == 0)
- break;
- */
- p += 4;
- if ((p[-4] == 0x40 && (p[-3] & 0xC0) == 0) ||
- (p[-4] == 0x7F && (p[-3] >= 0xC0)))
- break;
- }
- {
- UInt32 v = GetBe32(p - 4);
- v <<= 2;
- if (encoding)
- v += ip + (UInt32)(p - data);
- else
- v -= ip + (UInt32)(p - data);
-
- v &= 0x01FFFFFF;
- v -= (UInt32)1 << 24;
- v ^= 0xFF000000;
- v >>= 2;
- v |= 0x40000000;
- SetBe32(p - 4, v);
- }
- }
-}
+/* Bra.c -- Branch converters for RISC code
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Bra.h"
+#include "CpuArch.h"
+#include "RotateDefs.h"
+
+#if defined(MY_CPU_SIZEOF_POINTER) \
+ && ( MY_CPU_SIZEOF_POINTER == 4 \
+ || MY_CPU_SIZEOF_POINTER == 8)
+ #define BR_CONV_USE_OPT_PC_PTR
+#endif
+
+#ifdef BR_CONV_USE_OPT_PC_PTR
+#define BR_PC_INIT pc -= (UInt32)(SizeT)p;
+#define BR_PC_GET (pc + (UInt32)(SizeT)p)
+#else
+#define BR_PC_INIT pc += (UInt32)size;
+#define BR_PC_GET (pc - (UInt32)(SizeT)(lim - p))
+// #define BR_PC_INIT
+// #define BR_PC_GET (pc + (UInt32)(SizeT)(p - data))
+#endif
+
+#define BR_CONVERT_VAL(v, c) if (encoding) v += c; else v -= c;
+// #define BR_CONVERT_VAL(v, c) if (!encoding) c = (UInt32)0 - c; v += c;
+
+#define Z7_BRANCH_CONV(name) z7_BranchConv_ ## name
+
+#define Z7_BRANCH_FUNC_MAIN(name) \
+static \
+Z7_FORCE_INLINE \
+Z7_ATTRIB_NO_VECTOR \
+Byte *Z7_BRANCH_CONV(name)(Byte *p, SizeT size, UInt32 pc, int encoding)
+
+#define Z7_BRANCH_FUNC_IMP(name, m, encoding) \
+Z7_NO_INLINE \
+Z7_ATTRIB_NO_VECTOR \
+Byte *m(name)(Byte *data, SizeT size, UInt32 pc) \
+ { return Z7_BRANCH_CONV(name)(data, size, pc, encoding); } \
+
+#ifdef Z7_EXTRACT_ONLY
+#define Z7_BRANCH_FUNCS_IMP(name) \
+ Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_DEC, 0)
+#else
+#define Z7_BRANCH_FUNCS_IMP(name) \
+ Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_DEC, 0) \
+ Z7_BRANCH_FUNC_IMP(name, Z7_BRANCH_CONV_ENC, 1)
+#endif
+
+#if defined(__clang__)
+#define BR_EXTERNAL_FOR
+#define BR_NEXT_ITERATION continue;
+#else
+#define BR_EXTERNAL_FOR for (;;)
+#define BR_NEXT_ITERATION break;
+#endif
+
+#if defined(__clang__) && (__clang_major__ >= 8) \
+ || defined(__GNUC__) && (__GNUC__ >= 1000) \
+ // GCC is not good for __builtin_expect() here
+ /* || defined(_MSC_VER) && (_MSC_VER >= 1920) */
+ // #define Z7_unlikely [[unlikely]]
+ // #define Z7_LIKELY(x) (__builtin_expect((x), 1))
+ #define Z7_UNLIKELY(x) (__builtin_expect((x), 0))
+ // #define Z7_likely [[likely]]
+#else
+ // #define Z7_LIKELY(x) (x)
+ #define Z7_UNLIKELY(x) (x)
+ // #define Z7_likely
+#endif
+
+
+Z7_BRANCH_FUNC_MAIN(ARM64)
+{
+ // Byte *p = data;
+ const Byte *lim;
+ const UInt32 flag = (UInt32)1 << (24 - 4);
+ const UInt32 mask = ((UInt32)1 << 24) - (flag << 1);
+ size &= ~(SizeT)3;
+ // if (size == 0) return p;
+ lim = p + size;
+ BR_PC_INIT
+ pc -= 4; // because (p) will point to next instruction
+
+ BR_EXTERNAL_FOR
+ {
+ // Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ for (;;)
+ {
+ UInt32 v;
+ if Z7_UNLIKELY(p == lim)
+ return p;
+ v = GetUi32a(p);
+ p += 4;
+ if Z7_UNLIKELY(((v - 0x94000000) & 0xfc000000) == 0)
+ {
+ UInt32 c = BR_PC_GET >> 2;
+ BR_CONVERT_VAL(v, c)
+ v &= 0x03ffffff;
+ v |= 0x94000000;
+ SetUi32a(p - 4, v)
+ BR_NEXT_ITERATION
+ }
+ // v = rotlFixed(v, 8); v += (flag << 8) - 0x90; if Z7_UNLIKELY((v & ((mask << 8) + 0x9f)) == 0)
+ v -= 0x90000000; if Z7_UNLIKELY((v & 0x9f000000) == 0)
+ {
+ UInt32 z, c;
+ // v = rotrFixed(v, 8);
+ v += flag; if Z7_UNLIKELY(v & mask) continue;
+ z = (v & 0xffffffe0) | (v >> 26);
+ c = (BR_PC_GET >> (12 - 3)) & ~(UInt32)7;
+ BR_CONVERT_VAL(z, c)
+ v &= 0x1f;
+ v |= 0x90000000;
+ v |= z << 26;
+ v |= 0x00ffffe0 & ((z & (((flag << 1) - 1))) - flag);
+ SetUi32a(p - 4, v)
+ }
+ }
+ }
+}
+Z7_BRANCH_FUNCS_IMP(ARM64)
+
+
+Z7_BRANCH_FUNC_MAIN(ARM)
+{
+ // Byte *p = data;
+ const Byte *lim;
+ size &= ~(SizeT)3;
+ lim = p + size;
+ BR_PC_INIT
+ /* in ARM: branch offset is relative to the +2 instructions from current instruction.
+ (p) will point to next instruction */
+ pc += 8 - 4;
+
+ for (;;)
+ {
+ for (;;)
+ {
+ if Z7_UNLIKELY(p >= lim) { return p; } p += 4; if Z7_UNLIKELY(p[-1] == 0xeb) break;
+ if Z7_UNLIKELY(p >= lim) { return p; } p += 4; if Z7_UNLIKELY(p[-1] == 0xeb) break;
+ }
+ {
+ UInt32 v = GetUi32a(p - 4);
+ UInt32 c = BR_PC_GET >> 2;
+ BR_CONVERT_VAL(v, c)
+ v &= 0x00ffffff;
+ v |= 0xeb000000;
+ SetUi32a(p - 4, v)
+ }
+ }
+}
+Z7_BRANCH_FUNCS_IMP(ARM)
+
+
+Z7_BRANCH_FUNC_MAIN(PPC)
+{
+ // Byte *p = data;
+ const Byte *lim;
+ size &= ~(SizeT)3;
+ lim = p + size;
+ BR_PC_INIT
+ pc -= 4; // because (p) will point to next instruction
+
+ for (;;)
+ {
+ UInt32 v;
+ for (;;)
+ {
+ if Z7_UNLIKELY(p == lim)
+ return p;
+ // v = GetBe32a(p);
+ v = *(UInt32 *)(void *)p;
+ p += 4;
+ // if ((v & 0xfc000003) == 0x48000001) break;
+ // if ((p[-4] & 0xFC) == 0x48 && (p[-1] & 3) == 1) break;
+ if Z7_UNLIKELY(
+ ((v - Z7_CONV_BE_TO_NATIVE_CONST32(0x48000001))
+ & Z7_CONV_BE_TO_NATIVE_CONST32(0xfc000003)) == 0) break;
+ }
+ {
+ v = Z7_CONV_NATIVE_TO_BE_32(v);
+ {
+ UInt32 c = BR_PC_GET;
+ BR_CONVERT_VAL(v, c)
+ }
+ v &= 0x03ffffff;
+ v |= 0x48000000;
+ SetBe32a(p - 4, v)
+ }
+ }
+}
+Z7_BRANCH_FUNCS_IMP(PPC)
+
+
+#ifdef Z7_CPU_FAST_ROTATE_SUPPORTED
+#define BR_SPARC_USE_ROTATE
+#endif
+
+Z7_BRANCH_FUNC_MAIN(SPARC)
+{
+ // Byte *p = data;
+ const Byte *lim;
+ const UInt32 flag = (UInt32)1 << 22;
+ size &= ~(SizeT)3;
+ lim = p + size;
+ BR_PC_INIT
+ pc -= 4; // because (p) will point to next instruction
+ for (;;)
+ {
+ UInt32 v;
+ for (;;)
+ {
+ if Z7_UNLIKELY(p == lim)
+ return p;
+ /* // the code without GetBe32a():
+ { const UInt32 v = GetUi16a(p) & 0xc0ff; p += 4; if (v == 0x40 || v == 0xc07f) break; }
+ */
+ v = GetBe32a(p);
+ p += 4;
+ #ifdef BR_SPARC_USE_ROTATE
+ v = rotlFixed(v, 2);
+ v += (flag << 2) - 1;
+ if Z7_UNLIKELY((v & (3 - (flag << 3))) == 0)
+ #else
+ v += (UInt32)5 << 29;
+ v ^= (UInt32)7 << 29;
+ v += flag;
+ if Z7_UNLIKELY((v & (0 - (flag << 1))) == 0)
+ #endif
+ break;
+ }
+ {
+ // UInt32 v = GetBe32a(p - 4);
+ #ifndef BR_SPARC_USE_ROTATE
+ v <<= 2;
+ #endif
+ {
+ UInt32 c = BR_PC_GET;
+ BR_CONVERT_VAL(v, c)
+ }
+ v &= (flag << 3) - 1;
+ #ifdef BR_SPARC_USE_ROTATE
+ v -= (flag << 2) - 1;
+ v = rotrFixed(v, 2);
+ #else
+ v -= (flag << 2);
+ v >>= 2;
+ v |= (UInt32)1 << 30;
+ #endif
+ SetBe32a(p - 4, v)
+ }
+ }
+}
+Z7_BRANCH_FUNCS_IMP(SPARC)
+
+
+Z7_BRANCH_FUNC_MAIN(ARMT)
+{
+ // Byte *p = data;
+ Byte *lim;
+ size &= ~(SizeT)1;
+ // if (size == 0) return p;
+ if (size <= 2) return p;
+ size -= 2;
+ lim = p + size;
+ BR_PC_INIT
+ /* in ARM: branch offset is relative to the +2 instructions from current instruction.
+ (p) will point to the +2 instructions from current instruction */
+ // pc += 4 - 4;
+ // if (encoding) pc -= 0xf800 << 1; else pc += 0xf800 << 1;
+ // #define ARMT_TAIL_PROC { goto armt_tail; }
+ #define ARMT_TAIL_PROC { return p; }
+
+ do
+ {
+ /* in MSVC 32-bit x86 compilers:
+ UInt32 version : it loads value from memory with movzx
+ Byte version : it loads value to 8-bit register (AL/CL)
+ movzx version is slightly faster in some cpus
+ */
+ unsigned b1;
+ // Byte / unsigned
+ b1 = p[1];
+ // optimized version to reduce one (p >= lim) check:
+ // unsigned a1 = p[1]; b1 = p[3]; p += 2; if Z7_LIKELY((b1 & (a1 ^ 8)) < 0xf8)
+ for (;;)
+ {
+ unsigned b3; // Byte / UInt32
+ /* (Byte)(b3) normalization can use low byte computations in MSVC.
+ It gives smaller code, and no loss of speed in some compilers/cpus.
+ But new MSVC 32-bit x86 compilers use more slow load
+ from memory to low byte register in that case.
+ So we try to use full 32-bit computations for faster code.
+ */
+ // if (p >= lim) { ARMT_TAIL_PROC } b3 = b1 + 8; b1 = p[3]; p += 2; if ((b3 & b1) >= 0xf8) break;
+ if Z7_UNLIKELY(p >= lim) { ARMT_TAIL_PROC } b3 = p[3]; p += 2; if Z7_UNLIKELY((b3 & (b1 ^ 8)) >= 0xf8) break;
+ if Z7_UNLIKELY(p >= lim) { ARMT_TAIL_PROC } b1 = p[3]; p += 2; if Z7_UNLIKELY((b1 & (b3 ^ 8)) >= 0xf8) break;
+ }
+ {
+ /* we can adjust pc for (0xf800) to rid of (& 0x7FF) operation.
+ But gcc/clang for arm64 can use bfi instruction for full code here */
+ UInt32 v =
+ ((UInt32)GetUi16a(p - 2) << 11) |
+ ((UInt32)GetUi16a(p) & 0x7FF);
+ /*
+ UInt32 v =
+ ((UInt32)p[1 - 2] << 19)
+ + (((UInt32)p[1] & 0x7) << 8)
+ + (((UInt32)p[-2] << 11))
+ + (p[0]);
+ */
+ p += 2;
+ {
+ UInt32 c = BR_PC_GET >> 1;
+ BR_CONVERT_VAL(v, c)
+ }
+ SetUi16a(p - 4, (UInt16)(((v >> 11) & 0x7ff) | 0xf000))
+ SetUi16a(p - 2, (UInt16)(v | 0xf800))
+ /*
+ p[-4] = (Byte)(v >> 11);
+ p[-3] = (Byte)(0xf0 | ((v >> 19) & 0x7));
+ p[-2] = (Byte)v;
+ p[-1] = (Byte)(0xf8 | (v >> 8));
+ */
+ }
+ }
+ while (p < lim);
+ return p;
+ // armt_tail:
+ // if ((Byte)((lim[1] & 0xf8)) != 0xf0) { lim += 2; } return lim;
+ // return (Byte *)(lim + ((Byte)((lim[1] ^ 0xf0) & 0xf8) == 0 ? 0 : 2));
+ // return (Byte *)(lim + (((lim[1] ^ ~0xfu) & ~7u) == 0 ? 0 : 2));
+ // return (Byte *)(lim + 2 - (((((unsigned)lim[1] ^ 8) + 8) >> 7) & 2));
+}
+Z7_BRANCH_FUNCS_IMP(ARMT)
+
+
+// #define BR_IA64_NO_INLINE
+
+Z7_BRANCH_FUNC_MAIN(IA64)
+{
+ // Byte *p = data;
+ const Byte *lim;
+ size &= ~(SizeT)15;
+ lim = p + size;
+ pc -= 1 << 4;
+ pc >>= 4 - 1;
+ // pc -= 1 << 1;
+
+ for (;;)
+ {
+ unsigned m;
+ for (;;)
+ {
+ if Z7_UNLIKELY(p == lim)
+ return p;
+ m = (unsigned)((UInt32)0x334b0000 >> (*p & 0x1e));
+ p += 16;
+ pc += 1 << 1;
+ if (m &= 3)
+ break;
+ }
+ {
+ p += (ptrdiff_t)m * 5 - 20; // negative value is expected here.
+ do
+ {
+ const UInt32 t =
+ #if defined(MY_CPU_X86_OR_AMD64)
+ // we use 32-bit load here to reduce code size on x86:
+ GetUi32(p);
+ #else
+ GetUi16(p);
+ #endif
+ UInt32 z = GetUi32(p + 1) >> m;
+ p += 5;
+ if (((t >> m) & (0x70 << 1)) == 0
+ && ((z - (0x5000000 << 1)) & (0xf000000 << 1)) == 0)
+ {
+ UInt32 v = (UInt32)((0x8fffff << 1) | 1) & z;
+ z ^= v;
+ #ifdef BR_IA64_NO_INLINE
+ v |= (v & ((UInt32)1 << (23 + 1))) >> 3;
+ {
+ UInt32 c = pc;
+ BR_CONVERT_VAL(v, c)
+ }
+ v &= (0x1fffff << 1) | 1;
+ #else
+ {
+ if (encoding)
+ {
+ // pc &= ~(0xc00000 << 1); // we just need to clear at least 2 bits
+ pc &= (0x1fffff << 1) | 1;
+ v += pc;
+ }
+ else
+ {
+ // pc |= 0xc00000 << 1; // we need to set at least 2 bits
+ pc |= ~(UInt32)((0x1fffff << 1) | 1);
+ v -= pc;
+ }
+ }
+ v &= ~(UInt32)(0x600000 << 1);
+ #endif
+ v += (0x700000 << 1);
+ v &= (0x8fffff << 1) | 1;
+ z |= v;
+ z <<= m;
+ SetUi32(p + 1 - 5, z)
+ }
+ m++;
+ }
+ while (m &= 3); // while (m < 4);
+ }
+ }
+}
+Z7_BRANCH_FUNCS_IMP(IA64)
diff --git a/C/Bra.h b/C/Bra.h
index aba8dce..a4ee568 100644
--- a/C/Bra.h
+++ b/C/Bra.h
@@ -1,64 +1,99 @@
-/* Bra.h -- Branch converters for executables
-2013-01-18 : Igor Pavlov : Public domain */
-
-#ifndef __BRA_H
-#define __BRA_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-/*
-These functions convert relative addresses to absolute addresses
-in CALL instructions to increase the compression ratio.
-
- In:
- data - data buffer
- size - size of data
- ip - current virtual Instruction Pinter (IP) value
- state - state variable for x86 converter
- encoding - 0 (for decoding), 1 (for encoding)
-
- Out:
- state - state variable for x86 converter
-
- Returns:
- The number of processed bytes. If you call these functions with multiple calls,
- you must start next call with first byte after block of processed bytes.
-
- Type Endian Alignment LookAhead
-
- x86 little 1 4
- ARMT little 2 2
- ARM little 4 0
- PPC big 4 0
- SPARC big 4 0
- IA64 little 16 0
-
- size must be >= Alignment + LookAhead, if it's not last block.
- If (size < Alignment + LookAhead), converter returns 0.
-
- Example:
-
- UInt32 ip = 0;
- for ()
- {
- ; size must be >= Alignment + LookAhead, if it's not last block
- SizeT processed = Convert(data, size, ip, 1);
- data += processed;
- size -= processed;
- ip += processed;
- }
-*/
-
-#define x86_Convert_Init(state) { state = 0; }
-SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding);
-SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
-SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
-SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
-SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
-SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
-
-EXTERN_C_END
-
-#endif
+/* Bra.h -- Branch converters for executables
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_BRA_H
+#define ZIP7_INC_BRA_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define Z7_BRANCH_CONV_DEC(name) z7_BranchConv_ ## name ## _Dec
+#define Z7_BRANCH_CONV_ENC(name) z7_BranchConv_ ## name ## _Enc
+#define Z7_BRANCH_CONV_ST_DEC(name) z7_BranchConvSt_ ## name ## _Dec
+#define Z7_BRANCH_CONV_ST_ENC(name) z7_BranchConvSt_ ## name ## _Enc
+
+#define Z7_BRANCH_CONV_DECL(name) Byte * name(Byte *data, SizeT size, UInt32 pc)
+#define Z7_BRANCH_CONV_ST_DECL(name) Byte * name(Byte *data, SizeT size, UInt32 pc, UInt32 *state)
+
+typedef Z7_BRANCH_CONV_DECL( (*z7_Func_BranchConv));
+typedef Z7_BRANCH_CONV_ST_DECL((*z7_Func_BranchConvSt));
+
+#define Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL 0
+Z7_BRANCH_CONV_ST_DECL(Z7_BRANCH_CONV_ST_DEC(X86));
+Z7_BRANCH_CONV_ST_DECL(Z7_BRANCH_CONV_ST_ENC(X86));
+
+#define Z7_BRANCH_FUNCS_DECL(name) \
+Z7_BRANCH_CONV_DECL(Z7_BRANCH_CONV_DEC(name)); \
+Z7_BRANCH_CONV_DECL(Z7_BRANCH_CONV_ENC(name));
+
+Z7_BRANCH_FUNCS_DECL(ARM64)
+Z7_BRANCH_FUNCS_DECL(ARM)
+Z7_BRANCH_FUNCS_DECL(ARMT)
+Z7_BRANCH_FUNCS_DECL(PPC)
+Z7_BRANCH_FUNCS_DECL(SPARC)
+Z7_BRANCH_FUNCS_DECL(IA64)
+
+/*
+These functions convert data that contain CPU instructions.
+Each such function converts relative addresses to absolute addresses in some
+branch instructions: CALL (in all converters) and JUMP (X86 converter only).
+Such conversion allows to increase compression ratio, if we compress that data.
+
+There are 2 types of converters:
+ Byte * Conv_RISC (Byte *data, SizeT size, UInt32 pc);
+ Byte * ConvSt_X86(Byte *data, SizeT size, UInt32 pc, UInt32 *state);
+Each Converter supports 2 versions: one for encoding
+and one for decoding (_Enc/_Dec postfixes in function name).
+
+In params:
+ data : data buffer
+ size : size of data
+ pc : current virtual Program Counter (Instruction Pinter) value
+In/Out param:
+ state : pointer to state variable (for X86 converter only)
+
+Return:
+ The pointer to position in (data) buffer after last byte that was processed.
+ If the caller calls converter again, it must call it starting with that position.
+ But the caller is allowed to move data in buffer. so pointer to
+ current processed position also will be changed for next call.
+ Also the caller must increase internal (pc) value for next call.
+
+Each converter has some characteristics: Endian, Alignment, LookAhead.
+ Type Endian Alignment LookAhead
+
+ X86 little 1 4
+ ARMT little 2 2
+ ARM little 4 0
+ ARM64 little 4 0
+ PPC big 4 0
+ SPARC big 4 0
+ IA64 little 16 0
+
+ (data) must be aligned for (Alignment).
+ processed size can be calculated as:
+ SizeT processed = Conv(data, size, pc) - data;
+ if (processed == 0)
+ it means that converter needs more data for processing.
+ If (size < Alignment + LookAhead)
+ then (processed == 0) is allowed.
+
+Example code for conversion in loop:
+ UInt32 pc = 0;
+ size = 0;
+ for (;;)
+ {
+ size += Load_more_input_data(data + size);
+ SizeT processed = Conv(data, size, pc) - data;
+ if (processed == 0 && no_more_input_data_after_size)
+ break; // we stop convert loop
+ data += processed;
+ size -= processed;
+ pc += processed;
+ }
+*/
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Bra86.c b/C/Bra86.c
index a6463c6..d81f392 100644
--- a/C/Bra86.c
+++ b/C/Bra86.c
@@ -1,82 +1,187 @@
-/* Bra86.c -- Converter for x86 code (BCJ)
-2017-04-03 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "Bra.h"
-
-#define Test86MSByte(b) ((((b) + 1) & 0xFE) == 0)
-
-SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding)
-{
- SizeT pos = 0;
- UInt32 mask = *state & 7;
- if (size < 5)
- return 0;
- size -= 4;
- ip += 5;
-
- for (;;)
- {
- Byte *p = data + pos;
- const Byte *limit = data + size;
- for (; p < limit; p++)
- if ((*p & 0xFE) == 0xE8)
- break;
-
- {
- SizeT d = (SizeT)(p - data - pos);
- pos = (SizeT)(p - data);
- if (p >= limit)
- {
- *state = (d > 2 ? 0 : mask >> (unsigned)d);
- return pos;
- }
- if (d > 2)
- mask = 0;
- else
- {
- mask >>= (unsigned)d;
- if (mask != 0 && (mask > 4 || mask == 3 || Test86MSByte(p[(size_t)(mask >> 1) + 1])))
- {
- mask = (mask >> 1) | 4;
- pos++;
- continue;
- }
- }
- }
-
- if (Test86MSByte(p[4]))
- {
- UInt32 v = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]);
- UInt32 cur = ip + (UInt32)pos;
- pos += 5;
- if (encoding)
- v += cur;
- else
- v -= cur;
- if (mask != 0)
- {
- unsigned sh = (mask & 6) << 2;
- if (Test86MSByte((Byte)(v >> sh)))
- {
- v ^= (((UInt32)0x100 << sh) - 1);
- if (encoding)
- v += cur;
- else
- v -= cur;
- }
- mask = 0;
- }
- p[1] = (Byte)v;
- p[2] = (Byte)(v >> 8);
- p[3] = (Byte)(v >> 16);
- p[4] = (Byte)(0 - ((v >> 24) & 1));
- }
- else
- {
- mask = (mask >> 1) | 4;
- pos++;
- }
- }
-}
+/* Bra86.c -- Branch converter for X86 code (BCJ)
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Bra.h"
+#include "CpuArch.h"
+
+
+#if defined(MY_CPU_SIZEOF_POINTER) \
+ && ( MY_CPU_SIZEOF_POINTER == 4 \
+ || MY_CPU_SIZEOF_POINTER == 8)
+ #define BR_CONV_USE_OPT_PC_PTR
+#endif
+
+#ifdef BR_CONV_USE_OPT_PC_PTR
+#define BR_PC_INIT pc -= (UInt32)(SizeT)p; // (MY_uintptr_t)
+#define BR_PC_GET (pc + (UInt32)(SizeT)p)
+#else
+#define BR_PC_INIT pc += (UInt32)size;
+#define BR_PC_GET (pc - (UInt32)(SizeT)(lim - p))
+// #define BR_PC_INIT
+// #define BR_PC_GET (pc + (UInt32)(SizeT)(p - data))
+#endif
+
+#define BR_CONVERT_VAL(v, c) if (encoding) v += c; else v -= c;
+// #define BR_CONVERT_VAL(v, c) if (!encoding) c = (UInt32)0 - c; v += c;
+
+#define Z7_BRANCH_CONV_ST(name) z7_BranchConvSt_ ## name
+
+#define BR86_NEED_CONV_FOR_MS_BYTE(b) ((((b) + 1) & 0xfe) == 0)
+
+#ifdef MY_CPU_LE_UNALIGN
+ #define BR86_PREPARE_BCJ_SCAN const UInt32 v = GetUi32(p) ^ 0xe8e8e8e8;
+ #define BR86_IS_BCJ_BYTE(n) ((v & ((UInt32)0xfe << (n) * 8)) == 0)
+#else
+ #define BR86_PREPARE_BCJ_SCAN
+ // bad for MSVC X86 (partial write to byte reg):
+ #define BR86_IS_BCJ_BYTE(n) ((p[n - 4] & 0xfe) == 0xe8)
+ // bad for old MSVC (partial write to byte reg):
+ // #define BR86_IS_BCJ_BYTE(n) (((*p ^ 0xe8) & 0xfe) == 0)
+#endif
+
+static
+Z7_FORCE_INLINE
+Z7_ATTRIB_NO_VECTOR
+Byte *Z7_BRANCH_CONV_ST(X86)(Byte *p, SizeT size, UInt32 pc, UInt32 *state, int encoding)
+{
+ if (size < 5)
+ return p;
+ {
+ // Byte *p = data;
+ const Byte *lim = p + size - 4;
+ unsigned mask = (unsigned)*state; // & 7;
+#ifdef BR_CONV_USE_OPT_PC_PTR
+ /* if BR_CONV_USE_OPT_PC_PTR is defined: we need to adjust (pc) for (+4),
+ because call/jump offset is relative to the next instruction.
+ if BR_CONV_USE_OPT_PC_PTR is not defined : we don't need to adjust (pc) for (+4),
+ because BR_PC_GET uses (pc - (lim - p)), and lim was adjusted for (-4) before.
+ */
+ pc += 4;
+#endif
+ BR_PC_INIT
+ goto start;
+
+ for (;; mask |= 4)
+ {
+ // cont: mask |= 4;
+ start:
+ if (p >= lim)
+ goto fin;
+ {
+ BR86_PREPARE_BCJ_SCAN
+ p += 4;
+ if (BR86_IS_BCJ_BYTE(0)) { goto m0; } mask >>= 1;
+ if (BR86_IS_BCJ_BYTE(1)) { goto m1; } mask >>= 1;
+ if (BR86_IS_BCJ_BYTE(2)) { goto m2; } mask = 0;
+ if (BR86_IS_BCJ_BYTE(3)) { goto a3; }
+ }
+ goto main_loop;
+
+ m0: p--;
+ m1: p--;
+ m2: p--;
+ if (mask == 0)
+ goto a3;
+ if (p > lim)
+ goto fin_p;
+
+ // if (((0x17u >> mask) & 1) == 0)
+ if (mask > 4 || mask == 3)
+ {
+ mask >>= 1;
+ continue; // goto cont;
+ }
+ mask >>= 1;
+ if (BR86_NEED_CONV_FOR_MS_BYTE(p[mask]))
+ continue; // goto cont;
+ // if (!BR86_NEED_CONV_FOR_MS_BYTE(p[3])) continue; // goto cont;
+ {
+ UInt32 v = GetUi32(p);
+ UInt32 c;
+ v += (1 << 24); if (v & 0xfe000000) continue; // goto cont;
+ c = BR_PC_GET;
+ BR_CONVERT_VAL(v, c)
+ {
+ mask <<= 3;
+ if (BR86_NEED_CONV_FOR_MS_BYTE(v >> mask))
+ {
+ v ^= (((UInt32)0x100 << mask) - 1);
+ #ifdef MY_CPU_X86
+ // for X86 : we can recalculate (c) to reduce register pressure
+ c = BR_PC_GET;
+ #endif
+ BR_CONVERT_VAL(v, c)
+ }
+ mask = 0;
+ }
+ // v = (v & ((1 << 24) - 1)) - (v & (1 << 24));
+ v &= (1 << 25) - 1; v -= (1 << 24);
+ SetUi32(p, v)
+ p += 4;
+ goto main_loop;
+ }
+
+ main_loop:
+ if (p >= lim)
+ goto fin;
+ for (;;)
+ {
+ BR86_PREPARE_BCJ_SCAN
+ p += 4;
+ if (BR86_IS_BCJ_BYTE(0)) { goto a0; }
+ if (BR86_IS_BCJ_BYTE(1)) { goto a1; }
+ if (BR86_IS_BCJ_BYTE(2)) { goto a2; }
+ if (BR86_IS_BCJ_BYTE(3)) { goto a3; }
+ if (p >= lim)
+ goto fin;
+ }
+
+ a0: p--;
+ a1: p--;
+ a2: p--;
+ a3:
+ if (p > lim)
+ goto fin_p;
+ // if (!BR86_NEED_CONV_FOR_MS_BYTE(p[3])) continue; // goto cont;
+ {
+ UInt32 v = GetUi32(p);
+ UInt32 c;
+ v += (1 << 24); if (v & 0xfe000000) continue; // goto cont;
+ c = BR_PC_GET;
+ BR_CONVERT_VAL(v, c)
+ // v = (v & ((1 << 24) - 1)) - (v & (1 << 24));
+ v &= (1 << 25) - 1; v -= (1 << 24);
+ SetUi32(p, v)
+ p += 4;
+ goto main_loop;
+ }
+ }
+
+fin_p:
+ p--;
+fin:
+ // the following processing for tail is optional and can be commented
+ /*
+ lim += 4;
+ for (; p < lim; p++, mask >>= 1)
+ if ((*p & 0xfe) == 0xe8)
+ break;
+ */
+ *state = (UInt32)mask;
+ return p;
+ }
+}
+
+
+#define Z7_BRANCH_CONV_ST_FUNC_IMP(name, m, encoding) \
+Z7_NO_INLINE \
+Z7_ATTRIB_NO_VECTOR \
+Byte *m(name)(Byte *data, SizeT size, UInt32 pc, UInt32 *state) \
+ { return Z7_BRANCH_CONV_ST(name)(data, size, pc, state, encoding); }
+
+Z7_BRANCH_CONV_ST_FUNC_IMP(X86, Z7_BRANCH_CONV_ST_DEC, 0)
+#ifndef Z7_EXTRACT_ONLY
+Z7_BRANCH_CONV_ST_FUNC_IMP(X86, Z7_BRANCH_CONV_ST_ENC, 1)
+#endif
diff --git a/C/BraIA64.c b/C/BraIA64.c
index 2656907..9dfe3e2 100644
--- a/C/BraIA64.c
+++ b/C/BraIA64.c
@@ -1,53 +1,14 @@
-/* BraIA64.c -- Converter for IA-64 code
-2017-01-26 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "CpuArch.h"
-#include "Bra.h"
-
-SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding)
-{
- SizeT i;
- if (size < 16)
- return 0;
- size -= 16;
- i = 0;
- do
- {
- unsigned m = ((UInt32)0x334B0000 >> (data[i] & 0x1E)) & 3;
- if (m)
- {
- m++;
- do
- {
- Byte *p = data + (i + (size_t)m * 5 - 8);
- if (((p[3] >> m) & 15) == 5
- && (((p[-1] | ((UInt32)p[0] << 8)) >> m) & 0x70) == 0)
- {
- unsigned raw = GetUi32(p);
- unsigned v = raw >> m;
- v = (v & 0xFFFFF) | ((v & (1 << 23)) >> 3);
-
- v <<= 4;
- if (encoding)
- v += ip + (UInt32)i;
- else
- v -= ip + (UInt32)i;
- v >>= 4;
-
- v &= 0x1FFFFF;
- v += 0x700000;
- v &= 0x8FFFFF;
- raw &= ~((UInt32)0x8FFFFF << m);
- raw |= (v << m);
- SetUi32(p, raw);
- }
- }
- while (++m <= 4);
- }
- i += 16;
- }
- while (i <= size);
- return i;
-}
+/* BraIA64.c -- Converter for IA-64 code
+2023-02-20 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+// the code was moved to Bra.c
+
+#ifdef _MSC_VER
+#pragma warning(disable : 4206) // nonstandard extension used : translation unit is empty
+#endif
+
+#if defined(__clang__)
+#pragma GCC diagnostic ignored "-Wempty-translation-unit"
+#endif
diff --git a/C/BwtSort.c b/C/BwtSort.c
new file mode 100644
index 0000000..05ad6de
--- /dev/null
+++ b/C/BwtSort.c
@@ -0,0 +1,516 @@
+/* BwtSort.c -- BWT block sorting
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "BwtSort.h"
+#include "Sort.h"
+
+/* #define BLOCK_SORT_USE_HEAP_SORT */
+
+/* Don't change it !!! */
+#define kNumHashBytes 2
+#define kNumHashValues (1 << (kNumHashBytes * 8))
+
+/* kNumRefBitsMax must be < (kNumHashBytes * 8) = 16 */
+#define kNumRefBitsMax 12
+
+#define BS_TEMP_SIZE kNumHashValues
+
+#ifdef BLOCK_SORT_EXTERNAL_FLAGS
+
+/* 32 Flags in UInt32 word */
+#define kNumFlagsBits 5
+#define kNumFlagsInWord (1 << kNumFlagsBits)
+#define kFlagsMask (kNumFlagsInWord - 1)
+#define kAllFlags 0xFFFFFFFF
+
+#else
+
+#define kNumBitsMax 20
+#define kIndexMask ((1 << kNumBitsMax) - 1)
+#define kNumExtraBits (32 - kNumBitsMax)
+#define kNumExtra0Bits (kNumExtraBits - 2)
+#define kNumExtra0Mask ((1 << kNumExtra0Bits) - 1)
+
+#define SetFinishedGroupSize(p, size) \
+ { *(p) |= ((((size) - 1) & kNumExtra0Mask) << kNumBitsMax); \
+ if ((size) > (1 << kNumExtra0Bits)) { \
+ *(p) |= 0x40000000; *((p) + 1) |= ((((size) - 1)>> kNumExtra0Bits) << kNumBitsMax); } } \
+
+static void SetGroupSize(UInt32 *p, UInt32 size)
+{
+ if (--size == 0)
+ return;
+ *p |= 0x80000000 | ((size & kNumExtra0Mask) << kNumBitsMax);
+ if (size >= (1 << kNumExtra0Bits))
+ {
+ *p |= 0x40000000;
+ p[1] |= ((size >> kNumExtra0Bits) << kNumBitsMax);
+ }
+}
+
+#endif
+
+/*
+SortGroup - is recursive Range-Sort function with HeapSort optimization for small blocks
+ "range" is not real range. It's only for optimization.
+returns: 1 - if there are groups, 0 - no more groups
+*/
+
+static
+UInt32
+Z7_FASTCALL
+SortGroup(UInt32 BlockSize, UInt32 NumSortedBytes, UInt32 groupOffset, UInt32 groupSize, int NumRefBits, UInt32 *Indices
+ #ifndef BLOCK_SORT_USE_HEAP_SORT
+ , UInt32 left, UInt32 range
+ #endif
+ )
+{
+ UInt32 *ind2 = Indices + groupOffset;
+ UInt32 *Groups;
+ if (groupSize <= 1)
+ {
+ /*
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ SetFinishedGroupSize(ind2, 1)
+ #endif
+ */
+ return 0;
+ }
+ Groups = Indices + BlockSize + BS_TEMP_SIZE;
+ if (groupSize <= ((UInt32)1 << NumRefBits)
+ #ifndef BLOCK_SORT_USE_HEAP_SORT
+ && groupSize <= range
+ #endif
+ )
+ {
+ UInt32 *temp = Indices + BlockSize;
+ UInt32 j;
+ UInt32 mask, thereAreGroups, group, cg;
+ {
+ UInt32 gPrev;
+ UInt32 gRes = 0;
+ {
+ UInt32 sp = ind2[0] + NumSortedBytes;
+ if (sp >= BlockSize) sp -= BlockSize;
+ gPrev = Groups[sp];
+ temp[0] = (gPrev << NumRefBits);
+ }
+
+ for (j = 1; j < groupSize; j++)
+ {
+ UInt32 sp = ind2[j] + NumSortedBytes;
+ UInt32 g;
+ if (sp >= BlockSize) sp -= BlockSize;
+ g = Groups[sp];
+ temp[j] = (g << NumRefBits) | j;
+ gRes |= (gPrev ^ g);
+ }
+ if (gRes == 0)
+ {
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ SetGroupSize(ind2, groupSize);
+ #endif
+ return 1;
+ }
+ }
+
+ HeapSort(temp, groupSize);
+ mask = (((UInt32)1 << NumRefBits) - 1);
+ thereAreGroups = 0;
+
+ group = groupOffset;
+ cg = (temp[0] >> NumRefBits);
+ temp[0] = ind2[temp[0] & mask];
+
+ {
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ UInt32 *Flags = Groups + BlockSize;
+ #else
+ UInt32 prevGroupStart = 0;
+ #endif
+
+ for (j = 1; j < groupSize; j++)
+ {
+ UInt32 val = temp[j];
+ UInt32 cgCur = (val >> NumRefBits);
+
+ if (cgCur != cg)
+ {
+ cg = cgCur;
+ group = groupOffset + j;
+
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ {
+ UInt32 t = group - 1;
+ Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
+ }
+ #else
+ SetGroupSize(temp + prevGroupStart, j - prevGroupStart);
+ prevGroupStart = j;
+ #endif
+ }
+ else
+ thereAreGroups = 1;
+ {
+ UInt32 ind = ind2[val & mask];
+ temp[j] = ind;
+ Groups[ind] = group;
+ }
+ }
+
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ SetGroupSize(temp + prevGroupStart, j - prevGroupStart);
+ #endif
+ }
+
+ for (j = 0; j < groupSize; j++)
+ ind2[j] = temp[j];
+ return thereAreGroups;
+ }
+
+ /* Check that all strings are in one group (cannot sort) */
+ {
+ UInt32 group, j;
+ UInt32 sp = ind2[0] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
+ group = Groups[sp];
+ for (j = 1; j < groupSize; j++)
+ {
+ sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
+ if (Groups[sp] != group)
+ break;
+ }
+ if (j == groupSize)
+ {
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ SetGroupSize(ind2, groupSize);
+ #endif
+ return 1;
+ }
+ }
+
+ #ifndef BLOCK_SORT_USE_HEAP_SORT
+ {
+ /* ---------- Range Sort ---------- */
+ UInt32 i;
+ UInt32 mid;
+ for (;;)
+ {
+ UInt32 j;
+ if (range <= 1)
+ {
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ SetGroupSize(ind2, groupSize);
+ #endif
+ return 1;
+ }
+ mid = left + ((range + 1) >> 1);
+ j = groupSize;
+ i = 0;
+ do
+ {
+ UInt32 sp = ind2[i] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
+ if (Groups[sp] >= mid)
+ {
+ for (j--; j > i; j--)
+ {
+ sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
+ if (Groups[sp] < mid)
+ {
+ UInt32 temp = ind2[i]; ind2[i] = ind2[j]; ind2[j] = temp;
+ break;
+ }
+ }
+ if (i >= j)
+ break;
+ }
+ }
+ while (++i < j);
+ if (i == 0)
+ {
+ range = range - (mid - left);
+ left = mid;
+ }
+ else if (i == groupSize)
+ range = (mid - left);
+ else
+ break;
+ }
+
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ {
+ UInt32 t = (groupOffset + i - 1);
+ UInt32 *Flags = Groups + BlockSize;
+ Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
+ }
+ #endif
+
+ {
+ UInt32 j;
+ for (j = i; j < groupSize; j++)
+ Groups[ind2[j]] = groupOffset + i;
+ }
+
+ {
+ UInt32 res = SortGroup(BlockSize, NumSortedBytes, groupOffset, i, NumRefBits, Indices, left, mid - left);
+ return res | SortGroup(BlockSize, NumSortedBytes, groupOffset + i, groupSize - i, NumRefBits, Indices, mid, range - (mid - left));
+ }
+
+ }
+
+ #else
+
+ /* ---------- Heap Sort ---------- */
+
+ {
+ UInt32 j;
+ for (j = 0; j < groupSize; j++)
+ {
+ UInt32 sp = ind2[j] + NumSortedBytes; if (sp >= BlockSize) sp -= BlockSize;
+ ind2[j] = sp;
+ }
+
+ HeapSortRef(ind2, Groups, groupSize);
+
+ /* Write Flags */
+ {
+ UInt32 sp = ind2[0];
+ UInt32 group = Groups[sp];
+
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ UInt32 *Flags = Groups + BlockSize;
+ #else
+ UInt32 prevGroupStart = 0;
+ #endif
+
+ for (j = 1; j < groupSize; j++)
+ {
+ sp = ind2[j];
+ if (Groups[sp] != group)
+ {
+ group = Groups[sp];
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ {
+ UInt32 t = groupOffset + j - 1;
+ Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
+ }
+ #else
+ SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart);
+ prevGroupStart = j;
+ #endif
+ }
+ }
+
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ SetGroupSize(ind2 + prevGroupStart, j - prevGroupStart);
+ #endif
+ }
+ {
+ /* Write new Groups values and Check that there are groups */
+ UInt32 thereAreGroups = 0;
+ for (j = 0; j < groupSize; j++)
+ {
+ UInt32 group = groupOffset + j;
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ UInt32 subGroupSize = ((ind2[j] & ~0xC0000000) >> kNumBitsMax);
+ if ((ind2[j] & 0x40000000) != 0)
+ subGroupSize += ((ind2[(size_t)j + 1] >> kNumBitsMax) << kNumExtra0Bits);
+ subGroupSize++;
+ for (;;)
+ {
+ UInt32 original = ind2[j];
+ UInt32 sp = original & kIndexMask;
+ if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes;
+ ind2[j] = sp | (original & ~kIndexMask);
+ Groups[sp] = group;
+ if (--subGroupSize == 0)
+ break;
+ j++;
+ thereAreGroups = 1;
+ }
+ #else
+ UInt32 *Flags = Groups + BlockSize;
+ for (;;)
+ {
+ UInt32 sp = ind2[j]; if (sp < NumSortedBytes) sp += BlockSize; sp -= NumSortedBytes;
+ ind2[j] = sp;
+ Groups[sp] = group;
+ if ((Flags[(groupOffset + j) >> kNumFlagsBits] & (1 << ((groupOffset + j) & kFlagsMask))) == 0)
+ break;
+ j++;
+ thereAreGroups = 1;
+ }
+ #endif
+ }
+ return thereAreGroups;
+ }
+ }
+ #endif
+}
+
+/* conditions: blockSize > 0 */
+UInt32 BlockSort(UInt32 *Indices, const Byte *data, UInt32 blockSize)
+{
+ UInt32 *counters = Indices + blockSize;
+ UInt32 i;
+ UInt32 *Groups;
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ UInt32 *Flags;
+ #endif
+
+ /* Radix-Sort for 2 bytes */
+ for (i = 0; i < kNumHashValues; i++)
+ counters[i] = 0;
+ for (i = 0; i < blockSize - 1; i++)
+ counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]]++;
+ counters[((UInt32)data[i] << 8) | data[0]]++;
+
+ Groups = counters + BS_TEMP_SIZE;
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ Flags = Groups + blockSize;
+ {
+ UInt32 numWords = (blockSize + kFlagsMask) >> kNumFlagsBits;
+ for (i = 0; i < numWords; i++)
+ Flags[i] = kAllFlags;
+ }
+ #endif
+
+ {
+ UInt32 sum = 0;
+ for (i = 0; i < kNumHashValues; i++)
+ {
+ UInt32 groupSize = counters[i];
+ if (groupSize > 0)
+ {
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+ UInt32 t = sum + groupSize - 1;
+ Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask));
+ #endif
+ sum += groupSize;
+ }
+ counters[i] = sum - groupSize;
+ }
+
+ for (i = 0; i < blockSize - 1; i++)
+ Groups[i] = counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]];
+ Groups[i] = counters[((UInt32)data[i] << 8) | data[0]];
+
+ for (i = 0; i < blockSize - 1; i++)
+ Indices[counters[((UInt32)data[i] << 8) | data[(size_t)i + 1]]++] = i;
+ Indices[counters[((UInt32)data[i] << 8) | data[0]]++] = i;
+
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ {
+ UInt32 prev = 0;
+ for (i = 0; i < kNumHashValues; i++)
+ {
+ UInt32 prevGroupSize = counters[i] - prev;
+ if (prevGroupSize == 0)
+ continue;
+ SetGroupSize(Indices + prev, prevGroupSize);
+ prev = counters[i];
+ }
+ }
+ #endif
+ }
+
+ {
+ int NumRefBits;
+ UInt32 NumSortedBytes;
+ for (NumRefBits = 0; ((blockSize - 1) >> NumRefBits) != 0; NumRefBits++);
+ NumRefBits = 32 - NumRefBits;
+ if (NumRefBits > kNumRefBitsMax)
+ NumRefBits = kNumRefBitsMax;
+
+ for (NumSortedBytes = kNumHashBytes; ; NumSortedBytes <<= 1)
+ {
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ UInt32 finishedGroupSize = 0;
+ #endif
+ UInt32 newLimit = 0;
+ for (i = 0; i < blockSize;)
+ {
+ UInt32 groupSize;
+ #ifdef BLOCK_SORT_EXTERNAL_FLAGS
+
+ if ((Flags[i >> kNumFlagsBits] & (1 << (i & kFlagsMask))) == 0)
+ {
+ i++;
+ continue;
+ }
+ for (groupSize = 1;
+ (Flags[(i + groupSize) >> kNumFlagsBits] & (1 << ((i + groupSize) & kFlagsMask))) != 0;
+ groupSize++);
+
+ groupSize++;
+
+ #else
+
+ groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax);
+ {
+ BoolInt finishedGroup = ((Indices[i] & 0x80000000) == 0);
+ if ((Indices[i] & 0x40000000) != 0)
+ {
+ groupSize += ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits);
+ Indices[(size_t)i + 1] &= kIndexMask;
+ }
+ Indices[i] &= kIndexMask;
+ groupSize++;
+ if (finishedGroup || groupSize == 1)
+ {
+ Indices[i - finishedGroupSize] &= kIndexMask;
+ if (finishedGroupSize > 1)
+ Indices[(size_t)(i - finishedGroupSize) + 1] &= kIndexMask;
+ {
+ UInt32 newGroupSize = groupSize + finishedGroupSize;
+ SetFinishedGroupSize(Indices + i - finishedGroupSize, newGroupSize)
+ finishedGroupSize = newGroupSize;
+ }
+ i += groupSize;
+ continue;
+ }
+ finishedGroupSize = 0;
+ }
+
+ #endif
+
+ if (NumSortedBytes >= blockSize)
+ {
+ UInt32 j;
+ for (j = 0; j < groupSize; j++)
+ {
+ UInt32 t = (i + j);
+ /* Flags[t >> kNumFlagsBits] &= ~(1 << (t & kFlagsMask)); */
+ Groups[Indices[t]] = t;
+ }
+ }
+ else
+ if (SortGroup(blockSize, NumSortedBytes, i, groupSize, NumRefBits, Indices
+ #ifndef BLOCK_SORT_USE_HEAP_SORT
+ , 0, blockSize
+ #endif
+ ) != 0)
+ newLimit = i + groupSize;
+ i += groupSize;
+ }
+ if (newLimit == 0)
+ break;
+ }
+ }
+ #ifndef BLOCK_SORT_EXTERNAL_FLAGS
+ for (i = 0; i < blockSize;)
+ {
+ UInt32 groupSize = ((Indices[i] & ~0xC0000000) >> kNumBitsMax);
+ if ((Indices[i] & 0x40000000) != 0)
+ {
+ groupSize += ((Indices[(size_t)i + 1] >> kNumBitsMax) << kNumExtra0Bits);
+ Indices[(size_t)i + 1] &= kIndexMask;
+ }
+ Indices[i] &= kIndexMask;
+ groupSize++;
+ i += groupSize;
+ }
+ #endif
+ return Groups[0];
+}
diff --git a/C/BwtSort.h b/C/BwtSort.h
new file mode 100644
index 0000000..a34b243
--- /dev/null
+++ b/C/BwtSort.h
@@ -0,0 +1,26 @@
+/* BwtSort.h -- BWT block sorting
+2023-03-03 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_BWT_SORT_H
+#define ZIP7_INC_BWT_SORT_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/* use BLOCK_SORT_EXTERNAL_FLAGS if blockSize can be > 1M */
+/* #define BLOCK_SORT_EXTERNAL_FLAGS */
+
+#ifdef BLOCK_SORT_EXTERNAL_FLAGS
+#define BLOCK_SORT_EXTERNAL_SIZE(blockSize) ((((blockSize) + 31) >> 5))
+#else
+#define BLOCK_SORT_EXTERNAL_SIZE(blockSize) 0
+#endif
+
+#define BLOCK_SORT_BUF_SIZE(blockSize) ((blockSize) * 2 + BLOCK_SORT_EXTERNAL_SIZE(blockSize) + (1 << 16))
+
+UInt32 BlockSort(UInt32 *indices, const Byte *data, UInt32 blockSize);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Compiler.h b/C/Compiler.h
index c788648..185a52d 100644
--- a/C/Compiler.h
+++ b/C/Compiler.h
@@ -1,33 +1,159 @@
-/* Compiler.h
-2017-04-03 : Igor Pavlov : Public domain */
-
-#ifndef __7Z_COMPILER_H
-#define __7Z_COMPILER_H
-
-#ifdef _MSC_VER
-
- #ifdef UNDER_CE
- #define RPC_NO_WINDOWS_H
- /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */
- #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
- #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int
- #endif
-
- #if _MSC_VER >= 1300
- #pragma warning(disable : 4996) // This function or variable may be unsafe
- #else
- #pragma warning(disable : 4511) // copy constructor could not be generated
- #pragma warning(disable : 4512) // assignment operator could not be generated
- #pragma warning(disable : 4514) // unreferenced inline function has been removed
- #pragma warning(disable : 4702) // unreachable code
- #pragma warning(disable : 4710) // not inlined
- #pragma warning(disable : 4714) // function marked as __forceinline not inlined
- #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information
- #endif
-
-#endif
-
-#define UNUSED_VAR(x) (void)x;
-/* #define UNUSED_VAR(x) x=x; */
-
-#endif
+/* Compiler.h : Compiler specific defines and pragmas
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_COMPILER_H
+#define ZIP7_INC_COMPILER_H
+
+#if defined(__clang__)
+# define Z7_CLANG_VERSION (__clang_major__ * 10000 + __clang_minor__ * 100 + __clang_patchlevel__)
+#endif
+#if defined(__clang__) && defined(__apple_build_version__)
+# define Z7_APPLE_CLANG_VERSION Z7_CLANG_VERSION
+#elif defined(__clang__)
+# define Z7_LLVM_CLANG_VERSION Z7_CLANG_VERSION
+#elif defined(__GNUC__)
+# define Z7_GCC_VERSION (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__)
+#endif
+
+#ifdef _MSC_VER
+#if !defined(__clang__) && !defined(__GNUC__)
+#define Z7_MSC_VER_ORIGINAL _MSC_VER
+#endif
+#endif
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#define Z7_MINGW
+#endif
+
+// #pragma GCC diagnostic ignored "-Wunknown-pragmas"
+
+#ifdef __clang__
+// padding size of '' with 4 bytes to alignment boundary
+#pragma GCC diagnostic ignored "-Wpadded"
+#endif
+
+
+#ifdef _MSC_VER
+
+ #ifdef UNDER_CE
+ #define RPC_NO_WINDOWS_H
+ /* #pragma warning(disable : 4115) // '_RPC_ASYNC_STATE' : named type definition in parentheses */
+ #pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
+ #pragma warning(disable : 4214) // nonstandard extension used : bit field types other than int
+ #endif
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+
+// == 1200 : -O1 : for __forceinline
+// >= 1900 : -O1 : for printf
+#pragma warning(disable : 4710) // function not inlined
+
+#if _MSC_VER < 1900
+// winnt.h: 'Int64ShllMod32'
+#pragma warning(disable : 4514) // unreferenced inline function has been removed
+#endif
+
+#if _MSC_VER < 1300
+// #pragma warning(disable : 4702) // unreachable code
+// Bra.c : -O1:
+#pragma warning(disable : 4714) // function marked as __forceinline not inlined
+#endif
+
+/*
+#if _MSC_VER > 1400 && _MSC_VER <= 1900
+// strcat: This function or variable may be unsafe
+// sysinfoapi.h: kit10: GetVersion was declared deprecated
+#pragma warning(disable : 4996)
+#endif
+*/
+
+#if _MSC_VER > 1200
+// -Wall warnings
+
+#pragma warning(disable : 4711) // function selected for automatic inline expansion
+#pragma warning(disable : 4820) // '2' bytes padding added after data member
+
+#if _MSC_VER >= 1400 && _MSC_VER < 1920
+// 1400: string.h: _DBG_MEMCPY_INLINE_
+// 1600 - 191x : smmintrin.h __cplusplus'
+// is not defined as a preprocessor macro, replacing with '0' for '#if/#elif'
+#pragma warning(disable : 4668)
+
+// 1400 - 1600 : WinDef.h : 'FARPROC' :
+// 1900 - 191x : immintrin.h: _readfsbase_u32
+// no function prototype given : converting '()' to '(void)'
+#pragma warning(disable : 4255)
+#endif
+
+#if _MSC_VER >= 1914
+// Compiler will insert Spectre mitigation for memory load if /Qspectre switch specified
+#pragma warning(disable : 5045)
+#endif
+
+#endif // _MSC_VER > 1200
+#endif // _MSC_VER
+
+
+#if defined(__clang__) && (__clang_major__ >= 4)
+ #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \
+ _Pragma("clang loop unroll(disable)") \
+ _Pragma("clang loop vectorize(disable)")
+ #define Z7_ATTRIB_NO_VECTORIZE
+#elif defined(__GNUC__) && (__GNUC__ >= 5)
+ #define Z7_ATTRIB_NO_VECTORIZE __attribute__((optimize("no-tree-vectorize")))
+ // __attribute__((optimize("no-unroll-loops")));
+ #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+#elif defined(_MSC_VER) && (_MSC_VER >= 1920)
+ #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE \
+ _Pragma("loop( no_vector )")
+ #define Z7_ATTRIB_NO_VECTORIZE
+#else
+ #define Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ #define Z7_ATTRIB_NO_VECTORIZE
+#endif
+
+#if defined(MY_CPU_X86_OR_AMD64) && ( \
+ defined(__clang__) && (__clang_major__ >= 4) \
+ || defined(__GNUC__) && (__GNUC__ >= 5))
+ #define Z7_ATTRIB_NO_SSE __attribute__((__target__("no-sse")))
+#else
+ #define Z7_ATTRIB_NO_SSE
+#endif
+
+#define Z7_ATTRIB_NO_VECTOR \
+ Z7_ATTRIB_NO_VECTORIZE \
+ Z7_ATTRIB_NO_SSE
+
+
+#if defined(__clang__) && (__clang_major__ >= 8) \
+ || defined(__GNUC__) && (__GNUC__ >= 1000) \
+ /* || defined(_MSC_VER) && (_MSC_VER >= 1920) */
+ // GCC is not good for __builtin_expect()
+ #define Z7_LIKELY(x) (__builtin_expect((x), 1))
+ #define Z7_UNLIKELY(x) (__builtin_expect((x), 0))
+ // #define Z7_unlikely [[unlikely]]
+ // #define Z7_likely [[likely]]
+#else
+ #define Z7_LIKELY(x) (x)
+ #define Z7_UNLIKELY(x) (x)
+ // #define Z7_likely
+#endif
+
+
+#if (defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 36000))
+#define Z7_DIAGNOSCTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER \
+ _Pragma("GCC diagnostic push") \
+ _Pragma("GCC diagnostic ignored \"-Wreserved-macro-identifier\"")
+#define Z7_DIAGNOSCTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER \
+ _Pragma("GCC diagnostic pop")
+#else
+#define Z7_DIAGNOSCTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
+#define Z7_DIAGNOSCTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
+#endif
+
+#define UNUSED_VAR(x) (void)x;
+/* #define UNUSED_VAR(x) x=x; */
+
+#endif
diff --git a/C/CpuArch.c b/C/CpuArch.c
index ff1890e..33f8a3a 100644
--- a/C/CpuArch.c
+++ b/C/CpuArch.c
@@ -1,218 +1,823 @@
-/* CpuArch.c -- CPU specific code
-2018-02-18: Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "CpuArch.h"
-
-#ifdef MY_CPU_X86_OR_AMD64
-
-#if (defined(_MSC_VER) && !defined(MY_CPU_AMD64)) || defined(__GNUC__)
-#define USE_ASM
-#endif
-
-#if !defined(USE_ASM) && _MSC_VER >= 1500
-#include <intrin.h>
-#endif
-
-#if defined(USE_ASM) && !defined(MY_CPU_AMD64)
-static UInt32 CheckFlag(UInt32 flag)
-{
- #ifdef _MSC_VER
- __asm pushfd;
- __asm pop EAX;
- __asm mov EDX, EAX;
- __asm xor EAX, flag;
- __asm push EAX;
- __asm popfd;
- __asm pushfd;
- __asm pop EAX;
- __asm xor EAX, EDX;
- __asm push EDX;
- __asm popfd;
- __asm and flag, EAX;
- #else
- __asm__ __volatile__ (
- "pushf\n\t"
- "pop %%EAX\n\t"
- "movl %%EAX,%%EDX\n\t"
- "xorl %0,%%EAX\n\t"
- "push %%EAX\n\t"
- "popf\n\t"
- "pushf\n\t"
- "pop %%EAX\n\t"
- "xorl %%EDX,%%EAX\n\t"
- "push %%EDX\n\t"
- "popf\n\t"
- "andl %%EAX, %0\n\t":
- "=c" (flag) : "c" (flag) :
- "%eax", "%edx");
- #endif
- return flag;
-}
-#define CHECK_CPUID_IS_SUPPORTED if (CheckFlag(1 << 18) == 0 || CheckFlag(1 << 21) == 0) return False;
-#else
-#define CHECK_CPUID_IS_SUPPORTED
-#endif
-
-void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d)
-{
- #ifdef USE_ASM
-
- #ifdef _MSC_VER
-
- UInt32 a2, b2, c2, d2;
- __asm xor EBX, EBX;
- __asm xor ECX, ECX;
- __asm xor EDX, EDX;
- __asm mov EAX, function;
- __asm cpuid;
- __asm mov a2, EAX;
- __asm mov b2, EBX;
- __asm mov c2, ECX;
- __asm mov d2, EDX;
-
- *a = a2;
- *b = b2;
- *c = c2;
- *d = d2;
-
- #else
-
- __asm__ __volatile__ (
- #if defined(MY_CPU_AMD64) && defined(__PIC__)
- "mov %%rbx, %%rdi;"
- "cpuid;"
- "xchg %%rbx, %%rdi;"
- : "=a" (*a) ,
- "=D" (*b) ,
- #elif defined(MY_CPU_X86) && defined(__PIC__)
- "mov %%ebx, %%edi;"
- "cpuid;"
- "xchgl %%ebx, %%edi;"
- : "=a" (*a) ,
- "=D" (*b) ,
- #else
- "cpuid"
- : "=a" (*a) ,
- "=b" (*b) ,
- #endif
- "=c" (*c) ,
- "=d" (*d)
- : "0" (function)) ;
-
- #endif
-
- #else
-
- int CPUInfo[4];
- __cpuid(CPUInfo, function);
- *a = CPUInfo[0];
- *b = CPUInfo[1];
- *c = CPUInfo[2];
- *d = CPUInfo[3];
-
- #endif
-}
-
-BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p)
-{
- CHECK_CPUID_IS_SUPPORTED
- MyCPUID(0, &p->maxFunc, &p->vendor[0], &p->vendor[2], &p->vendor[1]);
- MyCPUID(1, &p->ver, &p->b, &p->c, &p->d);
- return True;
-}
-
-static const UInt32 kVendors[][3] =
-{
- { 0x756E6547, 0x49656E69, 0x6C65746E},
- { 0x68747541, 0x69746E65, 0x444D4163},
- { 0x746E6543, 0x48727561, 0x736C7561}
-};
-
-int x86cpuid_GetFirm(const Cx86cpuid *p)
-{
- unsigned i;
- for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[i]); i++)
- {
- const UInt32 *v = kVendors[i];
- if (v[0] == p->vendor[0] &&
- v[1] == p->vendor[1] &&
- v[2] == p->vendor[2])
- return (int)i;
- }
- return -1;
-}
-
-BoolInt CPU_Is_InOrder()
-{
- Cx86cpuid p;
- int firm;
- UInt32 family, model;
- if (!x86cpuid_CheckAndRead(&p))
- return True;
-
- family = x86cpuid_GetFamily(p.ver);
- model = x86cpuid_GetModel(p.ver);
-
- firm = x86cpuid_GetFirm(&p);
-
- switch (firm)
- {
- case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && (
- /* In-Order Atom CPU */
- model == 0x1C /* 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330 */
- || model == 0x26 /* 45 nm, Z6xx */
- || model == 0x27 /* 32 nm, Z2460 */
- || model == 0x35 /* 32 nm, Z2760 */
- || model == 0x36 /* 32 nm, N2xxx, D2xxx */
- )));
- case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA)));
- case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
- }
- return True;
-}
-
-#if !defined(MY_CPU_AMD64) && defined(_WIN32)
-#include <windows.h>
-static BoolInt CPU_Sys_Is_SSE_Supported()
-{
- OSVERSIONINFO vi;
- vi.dwOSVersionInfoSize = sizeof(vi);
- if (!GetVersionEx(&vi))
- return False;
- return (vi.dwMajorVersion >= 5);
-}
-#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False;
-#else
-#define CHECK_SYS_SSE_SUPPORT
-#endif
-
-BoolInt CPU_Is_Aes_Supported()
-{
- Cx86cpuid p;
- CHECK_SYS_SSE_SUPPORT
- if (!x86cpuid_CheckAndRead(&p))
- return False;
- return (p.c >> 25) & 1;
-}
-
-BoolInt CPU_IsSupported_PageGB()
-{
- Cx86cpuid cpuid;
- if (!x86cpuid_CheckAndRead(&cpuid))
- return False;
- {
- UInt32 d[4] = { 0 };
- MyCPUID(0x80000000, &d[0], &d[1], &d[2], &d[3]);
- if (d[0] < 0x80000001)
- return False;
- }
- {
- UInt32 d[4] = { 0 };
- MyCPUID(0x80000001, &d[0], &d[1], &d[2], &d[3]);
- return (d[3] >> 26) & 1;
- }
-}
-
-#endif
+/* CpuArch.c -- CPU specific code
+2023-05-18 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+// #include <stdio.h>
+
+#include "CpuArch.h"
+
+#ifdef MY_CPU_X86_OR_AMD64
+
+#undef NEED_CHECK_FOR_CPUID
+#if !defined(MY_CPU_AMD64)
+#define NEED_CHECK_FOR_CPUID
+#endif
+
+/*
+ cpuid instruction supports (subFunction) parameter in ECX,
+ that is used only with some specific (function) parameter values.
+ But we always use only (subFunction==0).
+*/
+/*
+ __cpuid(): MSVC and GCC/CLANG use same function/macro name
+ but parameters are different.
+ We use MSVC __cpuid() parameters style for our z7_x86_cpuid() function.
+*/
+
+#if defined(__GNUC__) /* && (__GNUC__ >= 10) */ \
+ || defined(__clang__) /* && (__clang_major__ >= 10) */
+
+/* there was some CLANG/GCC compilers that have issues with
+ rbx(ebx) handling in asm blocks in -fPIC mode (__PIC__ is defined).
+ compiler's <cpuid.h> contains the macro __cpuid() that is similar to our code.
+ The history of __cpuid() changes in CLANG/GCC:
+ GCC:
+ 2007: it preserved ebx for (__PIC__ && __i386__)
+ 2013: it preserved rbx and ebx for __PIC__
+ 2014: it doesn't preserves rbx and ebx anymore
+ we suppose that (__GNUC__ >= 5) fixed that __PIC__ ebx/rbx problem.
+ CLANG:
+ 2014+: it preserves rbx, but only for 64-bit code. No __PIC__ check.
+ Why CLANG cares about 64-bit mode only, and doesn't care about ebx (in 32-bit)?
+ Do we need __PIC__ test for CLANG or we must care about rbx even if
+ __PIC__ is not defined?
+*/
+
+#define ASM_LN "\n"
+
+#if defined(MY_CPU_AMD64) && defined(__PIC__) \
+ && ((defined (__GNUC__) && (__GNUC__ < 5)) || defined(__clang__))
+
+#define x86_cpuid_MACRO(p, func) { \
+ __asm__ __volatile__ ( \
+ ASM_LN "mov %%rbx, %q1" \
+ ASM_LN "cpuid" \
+ ASM_LN "xchg %%rbx, %q1" \
+ : "=a" ((p)[0]), "=&r" ((p)[1]), "=c" ((p)[2]), "=d" ((p)[3]) : "0" (func), "2"(0)); }
+
+ /* "=&r" selects free register. It can select even rbx, if that register is free.
+ "=&D" for (RDI) also works, but the code can be larger with "=&D"
+ "2"(0) means (subFunction = 0),
+ 2 is (zero-based) index in the output constraint list "=c" (ECX). */
+
+#elif defined(MY_CPU_X86) && defined(__PIC__) \
+ && ((defined (__GNUC__) && (__GNUC__ < 5)) || defined(__clang__))
+
+#define x86_cpuid_MACRO(p, func) { \
+ __asm__ __volatile__ ( \
+ ASM_LN "mov %%ebx, %k1" \
+ ASM_LN "cpuid" \
+ ASM_LN "xchg %%ebx, %k1" \
+ : "=a" ((p)[0]), "=&r" ((p)[1]), "=c" ((p)[2]), "=d" ((p)[3]) : "0" (func), "2"(0)); }
+
+#else
+
+#define x86_cpuid_MACRO(p, func) { \
+ __asm__ __volatile__ ( \
+ ASM_LN "cpuid" \
+ : "=a" ((p)[0]), "=b" ((p)[1]), "=c" ((p)[2]), "=d" ((p)[3]) : "0" (func), "2"(0)); }
+
+#endif
+
+
+void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func)
+{
+ x86_cpuid_MACRO(p, func)
+}
+
+
+Z7_NO_INLINE
+UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void)
+{
+ #if defined(NEED_CHECK_FOR_CPUID)
+ #define EFALGS_CPUID_BIT 21
+ UInt32 a;
+ __asm__ __volatile__ (
+ ASM_LN "pushf"
+ ASM_LN "pushf"
+ ASM_LN "pop %0"
+ // ASM_LN "movl %0, %1"
+ // ASM_LN "xorl $0x200000, %0"
+ ASM_LN "btc %1, %0"
+ ASM_LN "push %0"
+ ASM_LN "popf"
+ ASM_LN "pushf"
+ ASM_LN "pop %0"
+ ASM_LN "xorl (%%esp), %0"
+
+ ASM_LN "popf"
+ ASM_LN
+ : "=&r" (a) // "=a"
+ : "i" (EFALGS_CPUID_BIT)
+ );
+ if ((a & (1 << EFALGS_CPUID_BIT)) == 0)
+ return 0;
+ #endif
+ {
+ UInt32 p[4];
+ x86_cpuid_MACRO(p, 0)
+ return p[0];
+ }
+}
+
+#undef ASM_LN
+
+#elif !defined(_MSC_VER)
+
+/*
+// for gcc/clang and other: we can try to use __cpuid macro:
+#include <cpuid.h>
+void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func)
+{
+ __cpuid(func, p[0], p[1], p[2], p[3]);
+}
+UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void)
+{
+ return (UInt32)__get_cpuid_max(0, NULL);
+}
+*/
+// for unsupported cpuid:
+void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func)
+{
+ UNUSED_VAR(func)
+ p[0] = p[1] = p[2] = p[3] = 0;
+}
+UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void)
+{
+ return 0;
+}
+
+#else // _MSC_VER
+
+#if !defined(MY_CPU_AMD64)
+
+UInt32 __declspec(naked) Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void)
+{
+ #if defined(NEED_CHECK_FOR_CPUID)
+ #define EFALGS_CPUID_BIT 21
+ __asm pushfd
+ __asm pushfd
+ /*
+ __asm pop eax
+ // __asm mov edx, eax
+ __asm btc eax, EFALGS_CPUID_BIT
+ __asm push eax
+ */
+ __asm btc dword ptr [esp], EFALGS_CPUID_BIT
+ __asm popfd
+ __asm pushfd
+ __asm pop eax
+ // __asm xor eax, edx
+ __asm xor eax, [esp]
+ // __asm push edx
+ __asm popfd
+ __asm and eax, (1 shl EFALGS_CPUID_BIT)
+ __asm jz end_func
+ #endif
+ __asm push ebx
+ __asm xor eax, eax // func
+ __asm xor ecx, ecx // subFunction (optional) for (func == 0)
+ __asm cpuid
+ __asm pop ebx
+ #if defined(NEED_CHECK_FOR_CPUID)
+ end_func:
+ #endif
+ __asm ret 0
+}
+
+void __declspec(naked) Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func)
+{
+ UNUSED_VAR(p)
+ UNUSED_VAR(func)
+ __asm push ebx
+ __asm push edi
+ __asm mov edi, ecx // p
+ __asm mov eax, edx // func
+ __asm xor ecx, ecx // subfunction (optional) for (func == 0)
+ __asm cpuid
+ __asm mov [edi ], eax
+ __asm mov [edi + 4], ebx
+ __asm mov [edi + 8], ecx
+ __asm mov [edi + 12], edx
+ __asm pop edi
+ __asm pop ebx
+ __asm ret 0
+}
+
+#else // MY_CPU_AMD64
+
+ #if _MSC_VER >= 1600
+ #include <intrin.h>
+ #define MY_cpuidex __cpuidex
+ #else
+/*
+ __cpuid (func == (0 or 7)) requires subfunction number in ECX.
+ MSDN: The __cpuid intrinsic clears the ECX register before calling the cpuid instruction.
+ __cpuid() in new MSVC clears ECX.
+ __cpuid() in old MSVC (14.00) x64 doesn't clear ECX
+ We still can use __cpuid for low (func) values that don't require ECX,
+ but __cpuid() in old MSVC will be incorrect for some func values: (func == 7).
+ So here we use the hack for old MSVC to send (subFunction) in ECX register to cpuid instruction,
+ where ECX value is first parameter for FASTCALL / NO_INLINE func,
+ So the caller of MY_cpuidex_HACK() sets ECX as subFunction, and
+ old MSVC for __cpuid() doesn't change ECX and cpuid instruction gets (subFunction) value.
+
+DON'T remove Z7_NO_INLINE and Z7_FASTCALL for MY_cpuidex_HACK(): !!!
+*/
+static
+Z7_NO_INLINE void Z7_FASTCALL MY_cpuidex_HACK(UInt32 subFunction, UInt32 func, int *CPUInfo)
+{
+ UNUSED_VAR(subFunction)
+ __cpuid(CPUInfo, func);
+}
+ #define MY_cpuidex(info, func, func2) MY_cpuidex_HACK(func2, func, info)
+ #pragma message("======== MY_cpuidex_HACK WAS USED ========")
+ #endif // _MSC_VER >= 1600
+
+#if !defined(MY_CPU_AMD64)
+/* inlining for __cpuid() in MSVC x86 (32-bit) produces big ineffective code,
+ so we disable inlining here */
+Z7_NO_INLINE
+#endif
+void Z7_FASTCALL z7_x86_cpuid(UInt32 p[4], UInt32 func)
+{
+ MY_cpuidex((int *)p, (int)func, 0);
+}
+
+Z7_NO_INLINE
+UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void)
+{
+ int a[4];
+ MY_cpuidex(a, 0, 0);
+ return a[0];
+}
+
+#endif // MY_CPU_AMD64
+#endif // _MSC_VER
+
+#if defined(NEED_CHECK_FOR_CPUID)
+#define CHECK_CPUID_IS_SUPPORTED { if (z7_x86_cpuid_GetMaxFunc() == 0) return 0; }
+#else
+#define CHECK_CPUID_IS_SUPPORTED
+#endif
+#undef NEED_CHECK_FOR_CPUID
+
+
+static
+BoolInt x86cpuid_Func_1(UInt32 *p)
+{
+ CHECK_CPUID_IS_SUPPORTED
+ z7_x86_cpuid(p, 1);
+ return True;
+}
+
+/*
+static const UInt32 kVendors[][1] =
+{
+ { 0x756E6547 }, // , 0x49656E69, 0x6C65746E },
+ { 0x68747541 }, // , 0x69746E65, 0x444D4163 },
+ { 0x746E6543 } // , 0x48727561, 0x736C7561 }
+};
+*/
+
+/*
+typedef struct
+{
+ UInt32 maxFunc;
+ UInt32 vendor[3];
+ UInt32 ver;
+ UInt32 b;
+ UInt32 c;
+ UInt32 d;
+} Cx86cpuid;
+
+enum
+{
+ CPU_FIRM_INTEL,
+ CPU_FIRM_AMD,
+ CPU_FIRM_VIA
+};
+int x86cpuid_GetFirm(const Cx86cpuid *p);
+#define x86cpuid_ver_GetFamily(ver) (((ver >> 16) & 0xff0) | ((ver >> 8) & 0xf))
+#define x86cpuid_ver_GetModel(ver) (((ver >> 12) & 0xf0) | ((ver >> 4) & 0xf))
+#define x86cpuid_ver_GetStepping(ver) (ver & 0xf)
+
+int x86cpuid_GetFirm(const Cx86cpuid *p)
+{
+ unsigned i;
+ for (i = 0; i < sizeof(kVendors) / sizeof(kVendors[0]); i++)
+ {
+ const UInt32 *v = kVendors[i];
+ if (v[0] == p->vendor[0]
+ // && v[1] == p->vendor[1]
+ // && v[2] == p->vendor[2]
+ )
+ return (int)i;
+ }
+ return -1;
+}
+
+BoolInt CPU_Is_InOrder()
+{
+ Cx86cpuid p;
+ UInt32 family, model;
+ if (!x86cpuid_CheckAndRead(&p))
+ return True;
+
+ family = x86cpuid_ver_GetFamily(p.ver);
+ model = x86cpuid_ver_GetModel(p.ver);
+
+ switch (x86cpuid_GetFirm(&p))
+ {
+ case CPU_FIRM_INTEL: return (family < 6 || (family == 6 && (
+ // In-Order Atom CPU
+ model == 0x1C // 45 nm, N4xx, D4xx, N5xx, D5xx, 230, 330
+ || model == 0x26 // 45 nm, Z6xx
+ || model == 0x27 // 32 nm, Z2460
+ || model == 0x35 // 32 nm, Z2760
+ || model == 0x36 // 32 nm, N2xxx, D2xxx
+ )));
+ case CPU_FIRM_AMD: return (family < 5 || (family == 5 && (model < 6 || model == 0xA)));
+ case CPU_FIRM_VIA: return (family < 6 || (family == 6 && model < 0xF));
+ }
+ return False; // v23 : unknown processors are not In-Order
+}
+*/
+
+#ifdef _WIN32
+#include "7zWindows.h"
+#endif
+
+#if !defined(MY_CPU_AMD64) && defined(_WIN32)
+
+/* for legacy SSE ia32: there is no user-space cpu instruction to check
+ that OS supports SSE register storing/restoring on context switches.
+ So we need some OS-specific function to check that it's safe to use SSE registers.
+*/
+
+Z7_FORCE_INLINE
+static BoolInt CPU_Sys_Is_SSE_Supported(void)
+{
+#ifdef _MSC_VER
+ #pragma warning(push)
+ #pragma warning(disable : 4996) // `GetVersion': was declared deprecated
+#endif
+ /* low byte is major version of Windows
+ We suppose that any Windows version since
+ Windows2000 (major == 5) supports SSE registers */
+ return (Byte)GetVersion() >= 5;
+#if defined(_MSC_VER)
+ #pragma warning(pop)
+#endif
+}
+#define CHECK_SYS_SSE_SUPPORT if (!CPU_Sys_Is_SSE_Supported()) return False;
+#else
+#define CHECK_SYS_SSE_SUPPORT
+#endif
+
+
+#if !defined(MY_CPU_AMD64)
+
+BoolInt CPU_IsSupported_CMOV(void)
+{
+ UInt32 a[4];
+ if (!x86cpuid_Func_1(&a[0]))
+ return 0;
+ return (a[3] >> 15) & 1;
+}
+
+BoolInt CPU_IsSupported_SSE(void)
+{
+ UInt32 a[4];
+ CHECK_SYS_SSE_SUPPORT
+ if (!x86cpuid_Func_1(&a[0]))
+ return 0;
+ return (a[3] >> 25) & 1;
+}
+
+BoolInt CPU_IsSupported_SSE2(void)
+{
+ UInt32 a[4];
+ CHECK_SYS_SSE_SUPPORT
+ if (!x86cpuid_Func_1(&a[0]))
+ return 0;
+ return (a[3] >> 26) & 1;
+}
+
+#endif
+
+
+static UInt32 x86cpuid_Func_1_ECX(void)
+{
+ UInt32 a[4];
+ CHECK_SYS_SSE_SUPPORT
+ if (!x86cpuid_Func_1(&a[0]))
+ return 0;
+ return a[2];
+}
+
+BoolInt CPU_IsSupported_AES(void)
+{
+ return (x86cpuid_Func_1_ECX() >> 25) & 1;
+}
+
+BoolInt CPU_IsSupported_SSSE3(void)
+{
+ return (x86cpuid_Func_1_ECX() >> 9) & 1;
+}
+
+BoolInt CPU_IsSupported_SSE41(void)
+{
+ return (x86cpuid_Func_1_ECX() >> 19) & 1;
+}
+
+BoolInt CPU_IsSupported_SHA(void)
+{
+ CHECK_SYS_SSE_SUPPORT
+
+ if (z7_x86_cpuid_GetMaxFunc() < 7)
+ return False;
+ {
+ UInt32 d[4];
+ z7_x86_cpuid(d, 7);
+ return (d[1] >> 29) & 1;
+ }
+}
+
+/*
+MSVC: _xgetbv() intrinsic is available since VS2010SP1.
+ MSVC also defines (_XCR_XFEATURE_ENABLED_MASK) macro in
+ <immintrin.h> that we can use or check.
+ For any 32-bit x86 we can use asm code in MSVC,
+ but MSVC asm code is huge after compilation.
+ So _xgetbv() is better
+
+ICC: _xgetbv() intrinsic is available (in what version of ICC?)
+ ICC defines (__GNUC___) and it supports gnu assembler
+ also ICC supports MASM style code with -use-msasm switch.
+ but ICC doesn't support __attribute__((__target__))
+
+GCC/CLANG 9:
+ _xgetbv() is macro that works via __builtin_ia32_xgetbv()
+ and we need __attribute__((__target__("xsave")).
+ But with __target__("xsave") the function will be not
+ inlined to function that has no __target__("xsave") attribute.
+ If we want _xgetbv() call inlining, then we should use asm version
+ instead of calling _xgetbv().
+ Note:intrinsic is broke before GCC 8.2:
+ https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85684
+*/
+
+#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1100) \
+ || defined(_MSC_VER) && (_MSC_VER >= 1600) && (_MSC_FULL_VER >= 160040219) \
+ || defined(__GNUC__) && (__GNUC__ >= 9) \
+ || defined(__clang__) && (__clang_major__ >= 9)
+// we define ATTRIB_XGETBV, if we want to use predefined _xgetbv() from compiler
+#if defined(__INTEL_COMPILER)
+#define ATTRIB_XGETBV
+#elif defined(__GNUC__) || defined(__clang__)
+// we don't define ATTRIB_XGETBV here, because asm version is better for inlining.
+// #define ATTRIB_XGETBV __attribute__((__target__("xsave")))
+#else
+#define ATTRIB_XGETBV
+#endif
+#endif
+
+#if defined(ATTRIB_XGETBV)
+#include <immintrin.h>
+#endif
+
+
+// XFEATURE_ENABLED_MASK/XCR0
+#define MY_XCR_XFEATURE_ENABLED_MASK 0
+
+#if defined(ATTRIB_XGETBV)
+ATTRIB_XGETBV
+#endif
+static UInt64 x86_xgetbv_0(UInt32 num)
+{
+#if defined(ATTRIB_XGETBV)
+ {
+ return
+ #if (defined(_MSC_VER))
+ _xgetbv(num);
+ #else
+ __builtin_ia32_xgetbv(
+ #if !defined(__clang__)
+ (int)
+ #endif
+ num);
+ #endif
+ }
+
+#elif defined(__GNUC__) || defined(__clang__) || defined(__SUNPRO_CC)
+
+ UInt32 a, d;
+ #if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 4))
+ __asm__
+ (
+ "xgetbv"
+ : "=a"(a), "=d"(d) : "c"(num) : "cc"
+ );
+ #else // is old gcc
+ __asm__
+ (
+ ".byte 0x0f, 0x01, 0xd0" "\n\t"
+ : "=a"(a), "=d"(d) : "c"(num) : "cc"
+ );
+ #endif
+ return ((UInt64)d << 32) | a;
+ // return a;
+
+#elif defined(_MSC_VER) && !defined(MY_CPU_AMD64)
+
+ UInt32 a, d;
+ __asm {
+ push eax
+ push edx
+ push ecx
+ mov ecx, num;
+ // xor ecx, ecx // = MY_XCR_XFEATURE_ENABLED_MASK
+ _emit 0x0f
+ _emit 0x01
+ _emit 0xd0
+ mov a, eax
+ mov d, edx
+ pop ecx
+ pop edx
+ pop eax
+ }
+ return ((UInt64)d << 32) | a;
+ // return a;
+
+#else // it's unknown compiler
+ // #error "Need xgetbv function"
+ UNUSED_VAR(num)
+ // for MSVC-X64 we could call external function from external file.
+ /* Actually we had checked OSXSAVE/AVX in cpuid before.
+ So it's expected that OS supports at least AVX and below. */
+ // if (num != MY_XCR_XFEATURE_ENABLED_MASK) return 0; // if not XCR0
+ return
+ // (1 << 0) | // x87
+ (1 << 1) // SSE
+ | (1 << 2); // AVX
+
+#endif
+}
+
+#ifdef _WIN32
+/*
+ Windows versions do not know about new ISA extensions that
+ can be introduced. But we still can use new extensions,
+ even if Windows doesn't report about supporting them,
+ But we can use new extensions, only if Windows knows about new ISA extension
+ that changes the number or size of registers: SSE, AVX/XSAVE, AVX512
+ So it's enough to check
+ MY_PF_AVX_INSTRUCTIONS_AVAILABLE
+ instead of
+ MY_PF_AVX2_INSTRUCTIONS_AVAILABLE
+*/
+#define MY_PF_XSAVE_ENABLED 17
+// #define MY_PF_SSSE3_INSTRUCTIONS_AVAILABLE 36
+// #define MY_PF_SSE4_1_INSTRUCTIONS_AVAILABLE 37
+// #define MY_PF_SSE4_2_INSTRUCTIONS_AVAILABLE 38
+// #define MY_PF_AVX_INSTRUCTIONS_AVAILABLE 39
+// #define MY_PF_AVX2_INSTRUCTIONS_AVAILABLE 40
+// #define MY_PF_AVX512F_INSTRUCTIONS_AVAILABLE 41
+#endif
+
+BoolInt CPU_IsSupported_AVX(void)
+{
+ #ifdef _WIN32
+ if (!IsProcessorFeaturePresent(MY_PF_XSAVE_ENABLED))
+ return False;
+ /* PF_AVX_INSTRUCTIONS_AVAILABLE probably is supported starting from
+ some latest Win10 revisions. But we need AVX in older Windows also.
+ So we don't use the following check: */
+ /*
+ if (!IsProcessorFeaturePresent(MY_PF_AVX_INSTRUCTIONS_AVAILABLE))
+ return False;
+ */
+ #endif
+
+ /*
+ OS must use new special XSAVE/XRSTOR instructions to save
+ AVX registers when it required for context switching.
+ At OS statring:
+ OS sets CR4.OSXSAVE flag to signal the processor that OS supports the XSAVE extensions.
+ Also OS sets bitmask in XCR0 register that defines what
+ registers will be processed by XSAVE instruction:
+ XCR0.SSE[bit 0] - x87 registers and state
+ XCR0.SSE[bit 1] - SSE registers and state
+ XCR0.AVX[bit 2] - AVX registers and state
+ CR4.OSXSAVE is reflected to CPUID.1:ECX.OSXSAVE[bit 27].
+ So we can read that bit in user-space.
+ XCR0 is available for reading in user-space by new XGETBV instruction.
+ */
+ {
+ const UInt32 c = x86cpuid_Func_1_ECX();
+ if (0 == (1
+ & (c >> 28) // AVX instructions are supported by hardware
+ & (c >> 27))) // OSXSAVE bit: XSAVE and related instructions are enabled by OS.
+ return False;
+ }
+
+ /* also we can check
+ CPUID.1:ECX.XSAVE [bit 26] : that shows that
+ XSAVE, XRESTOR, XSETBV, XGETBV instructions are supported by hardware.
+ But that check is redundant, because if OSXSAVE bit is set, then XSAVE is also set */
+
+ /* If OS have enabled XSAVE extension instructions (OSXSAVE == 1),
+ in most cases we expect that OS also will support storing/restoring
+ for AVX and SSE states at least.
+ But to be ensure for that we call user-space instruction
+ XGETBV(0) to get XCR0 value that contains bitmask that defines
+ what exact states(registers) OS have enabled for storing/restoring.
+ */
+
+ {
+ const UInt32 bm = (UInt32)x86_xgetbv_0(MY_XCR_XFEATURE_ENABLED_MASK);
+ // printf("\n=== XGetBV=%d\n", bm);
+ return 1
+ & (bm >> 1) // SSE state is supported (set by OS) for storing/restoring
+ & (bm >> 2); // AVX state is supported (set by OS) for storing/restoring
+ }
+ // since Win7SP1: we can use GetEnabledXStateFeatures();
+}
+
+
+BoolInt CPU_IsSupported_AVX2(void)
+{
+ if (!CPU_IsSupported_AVX())
+ return False;
+ if (z7_x86_cpuid_GetMaxFunc() < 7)
+ return False;
+ {
+ UInt32 d[4];
+ z7_x86_cpuid(d, 7);
+ // printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]);
+ return 1
+ & (d[1] >> 5); // avx2
+ }
+}
+
+BoolInt CPU_IsSupported_VAES_AVX2(void)
+{
+ if (!CPU_IsSupported_AVX())
+ return False;
+ if (z7_x86_cpuid_GetMaxFunc() < 7)
+ return False;
+ {
+ UInt32 d[4];
+ z7_x86_cpuid(d, 7);
+ // printf("\ncpuid(7): ebx=%8x ecx=%8x\n", d[1], d[2]);
+ return 1
+ & (d[1] >> 5) // avx2
+ // & (d[1] >> 31) // avx512vl
+ & (d[2] >> 9); // vaes // VEX-256/EVEX
+ }
+}
+
+BoolInt CPU_IsSupported_PageGB(void)
+{
+ CHECK_CPUID_IS_SUPPORTED
+ {
+ UInt32 d[4];
+ z7_x86_cpuid(d, 0x80000000);
+ if (d[0] < 0x80000001)
+ return False;
+ z7_x86_cpuid(d, 0x80000001);
+ return (d[3] >> 26) & 1;
+ }
+}
+
+
+#elif defined(MY_CPU_ARM_OR_ARM64)
+
+#ifdef _WIN32
+
+#include "7zWindows.h"
+
+BoolInt CPU_IsSupported_CRC32(void) { return IsProcessorFeaturePresent(PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE) ? 1 : 0; }
+BoolInt CPU_IsSupported_CRYPTO(void) { return IsProcessorFeaturePresent(PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE) ? 1 : 0; }
+BoolInt CPU_IsSupported_NEON(void) { return IsProcessorFeaturePresent(PF_ARM_NEON_INSTRUCTIONS_AVAILABLE) ? 1 : 0; }
+
+#else
+
+#if defined(__APPLE__)
+
+/*
+#include <stdio.h>
+#include <string.h>
+static void Print_sysctlbyname(const char *name)
+{
+ size_t bufSize = 256;
+ char buf[256];
+ int res = sysctlbyname(name, &buf, &bufSize, NULL, 0);
+ {
+ int i;
+ printf("\nres = %d : %s : '%s' : bufSize = %d, numeric", res, name, buf, (unsigned)bufSize);
+ for (i = 0; i < 20; i++)
+ printf(" %2x", (unsigned)(Byte)buf[i]);
+
+ }
+}
+*/
+/*
+ Print_sysctlbyname("hw.pagesize");
+ Print_sysctlbyname("machdep.cpu.brand_string");
+*/
+
+static BoolInt z7_sysctlbyname_Get_BoolInt(const char *name)
+{
+ UInt32 val = 0;
+ if (z7_sysctlbyname_Get_UInt32(name, &val) == 0 && val == 1)
+ return 1;
+ return 0;
+}
+
+BoolInt CPU_IsSupported_CRC32(void)
+{
+ return z7_sysctlbyname_Get_BoolInt("hw.optional.armv8_crc32");
+}
+
+BoolInt CPU_IsSupported_NEON(void)
+{
+ return z7_sysctlbyname_Get_BoolInt("hw.optional.neon");
+}
+
+#ifdef MY_CPU_ARM64
+#define APPLE_CRYPTO_SUPPORT_VAL 1
+#else
+#define APPLE_CRYPTO_SUPPORT_VAL 0
+#endif
+
+BoolInt CPU_IsSupported_SHA1(void) { return APPLE_CRYPTO_SUPPORT_VAL; }
+BoolInt CPU_IsSupported_SHA2(void) { return APPLE_CRYPTO_SUPPORT_VAL; }
+BoolInt CPU_IsSupported_AES (void) { return APPLE_CRYPTO_SUPPORT_VAL; }
+
+
+#else // __APPLE__
+
+#include <sys/auxv.h>
+
+#define USE_HWCAP
+
+#ifdef USE_HWCAP
+
+#include <asm/hwcap.h>
+
+ #define MY_HWCAP_CHECK_FUNC_2(name1, name2) \
+ BoolInt CPU_IsSupported_ ## name1() { return (getauxval(AT_HWCAP) & (HWCAP_ ## name2)) ? 1 : 0; }
+
+#ifdef MY_CPU_ARM64
+ #define MY_HWCAP_CHECK_FUNC(name) \
+ MY_HWCAP_CHECK_FUNC_2(name, name)
+ MY_HWCAP_CHECK_FUNC_2(NEON, ASIMD)
+// MY_HWCAP_CHECK_FUNC (ASIMD)
+#elif defined(MY_CPU_ARM)
+ #define MY_HWCAP_CHECK_FUNC(name) \
+ BoolInt CPU_IsSupported_ ## name() { return (getauxval(AT_HWCAP2) & (HWCAP2_ ## name)) ? 1 : 0; }
+ MY_HWCAP_CHECK_FUNC_2(NEON, NEON)
+#endif
+
+#else // USE_HWCAP
+
+ #define MY_HWCAP_CHECK_FUNC(name) \
+ BoolInt CPU_IsSupported_ ## name() { return 0; }
+ MY_HWCAP_CHECK_FUNC(NEON)
+
+#endif // USE_HWCAP
+
+MY_HWCAP_CHECK_FUNC (CRC32)
+MY_HWCAP_CHECK_FUNC (SHA1)
+MY_HWCAP_CHECK_FUNC (SHA2)
+MY_HWCAP_CHECK_FUNC (AES)
+
+#endif // __APPLE__
+#endif // _WIN32
+
+#endif // MY_CPU_ARM_OR_ARM64
+
+
+
+#ifdef __APPLE__
+
+#include <sys/sysctl.h>
+
+int z7_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize)
+{
+ return sysctlbyname(name, buf, bufSize, NULL, 0);
+}
+
+int z7_sysctlbyname_Get_UInt32(const char *name, UInt32 *val)
+{
+ size_t bufSize = sizeof(*val);
+ const int res = z7_sysctlbyname_Get(name, val, &bufSize);
+ if (res == 0 && bufSize != sizeof(*val))
+ return EFAULT;
+ return res;
+}
+
+#endif
diff --git a/C/CpuArch.h b/C/CpuArch.h
index 5f74c1c..8e5d8a5 100644
--- a/C/CpuArch.h
+++ b/C/CpuArch.h
@@ -1,336 +1,523 @@
-/* CpuArch.h -- CPU specific code
-2018-02-18 : Igor Pavlov : Public domain */
-
-#ifndef __CPU_ARCH_H
-#define __CPU_ARCH_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-/*
-MY_CPU_LE means that CPU is LITTLE ENDIAN.
-MY_CPU_BE means that CPU is BIG ENDIAN.
-If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform.
-
-MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
-*/
-
-#if defined(_M_X64) \
- || defined(_M_AMD64) \
- || defined(__x86_64__) \
- || defined(__AMD64__) \
- || defined(__amd64__)
- #define MY_CPU_AMD64
- #ifdef __ILP32__
- #define MY_CPU_NAME "x32"
- #else
- #define MY_CPU_NAME "x64"
- #endif
- #define MY_CPU_64BIT
-#endif
-
-
-#if defined(_M_IX86) \
- || defined(__i386__)
- #define MY_CPU_X86
- #define MY_CPU_NAME "x86"
- #define MY_CPU_32BIT
-#endif
-
-
-#if defined(_M_ARM64) \
- || defined(__AARCH64EL__) \
- || defined(__AARCH64EB__) \
- || defined(__aarch64__)
- #define MY_CPU_ARM64
- #define MY_CPU_NAME "arm64"
- #define MY_CPU_64BIT
-#endif
-
-
-#if defined(_M_ARM) \
- || defined(_M_ARM_NT) \
- || defined(_M_ARMT) \
- || defined(__arm__) \
- || defined(__thumb__) \
- || defined(__ARMEL__) \
- || defined(__ARMEB__) \
- || defined(__THUMBEL__) \
- || defined(__THUMBEB__)
- #define MY_CPU_ARM
- #define MY_CPU_NAME "arm"
- #define MY_CPU_32BIT
-#endif
-
-
-#if defined(_M_IA64) \
- || defined(__ia64__)
- #define MY_CPU_IA64
- #define MY_CPU_NAME "ia64"
- #define MY_CPU_64BIT
-#endif
-
-
-#if defined(__mips64) \
- || defined(__mips64__) \
- || (defined(__mips) && (__mips == 64 || __mips == 4 || __mips == 3))
- #define MY_CPU_NAME "mips64"
- #define MY_CPU_64BIT
-#elif defined(__mips__)
- #define MY_CPU_NAME "mips"
- /* #define MY_CPU_32BIT */
-#endif
-
-
-#if defined(__ppc64__) \
- || defined(__powerpc64__)
- #ifdef __ILP32__
- #define MY_CPU_NAME "ppc64-32"
- #else
- #define MY_CPU_NAME "ppc64"
- #endif
- #define MY_CPU_64BIT
-#elif defined(__ppc__) \
- || defined(__powerpc__)
- #define MY_CPU_NAME "ppc"
- #define MY_CPU_32BIT
-#endif
-
-
-#if defined(__sparc64__)
- #define MY_CPU_NAME "sparc64"
- #define MY_CPU_64BIT
-#elif defined(__sparc__)
- #define MY_CPU_NAME "sparc"
- /* #define MY_CPU_32BIT */
-#endif
-
-
-#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
-#define MY_CPU_X86_OR_AMD64
-#endif
-
-
-#ifdef _WIN32
-
- #ifdef MY_CPU_ARM
- #define MY_CPU_ARM_LE
- #endif
-
- #ifdef MY_CPU_ARM64
- #define MY_CPU_ARM64_LE
- #endif
-
- #ifdef _M_IA64
- #define MY_CPU_IA64_LE
- #endif
-
-#endif
-
-
-#if defined(MY_CPU_X86_OR_AMD64) \
- || defined(MY_CPU_ARM_LE) \
- || defined(MY_CPU_ARM64_LE) \
- || defined(MY_CPU_IA64_LE) \
- || defined(__LITTLE_ENDIAN__) \
- || defined(__ARMEL__) \
- || defined(__THUMBEL__) \
- || defined(__AARCH64EL__) \
- || defined(__MIPSEL__) \
- || defined(__MIPSEL) \
- || defined(_MIPSEL) \
- || defined(__BFIN__) \
- || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
- #define MY_CPU_LE
-#endif
-
-#if defined(__BIG_ENDIAN__) \
- || defined(__ARMEB__) \
- || defined(__THUMBEB__) \
- || defined(__AARCH64EB__) \
- || defined(__MIPSEB__) \
- || defined(__MIPSEB) \
- || defined(_MIPSEB) \
- || defined(__m68k__) \
- || defined(__s390__) \
- || defined(__s390x__) \
- || defined(__zarch__) \
- || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
- #define MY_CPU_BE
-#endif
-
-
-#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
- #error Stop_Compiling_Bad_Endian
-#endif
-
-
-#if defined(MY_CPU_32BIT) && defined(MY_CPU_64BIT)
- #error Stop_Compiling_Bad_32_64_BIT
-#endif
-
-
-#ifndef MY_CPU_NAME
- #ifdef MY_CPU_LE
- #define MY_CPU_NAME "LE"
- #elif defined(MY_CPU_BE)
- #define MY_CPU_NAME "BE"
- #else
- /*
- #define MY_CPU_NAME ""
- */
- #endif
-#endif
-
-
-
-
-
-#ifdef MY_CPU_LE
- #if defined(MY_CPU_X86_OR_AMD64) \
- || defined(MY_CPU_ARM64) \
- || defined(__ARM_FEATURE_UNALIGNED)
- #define MY_CPU_LE_UNALIGN
- #endif
-#endif
-
-
-#ifdef MY_CPU_LE_UNALIGN
-
-#define GetUi16(p) (*(const UInt16 *)(const void *)(p))
-#define GetUi32(p) (*(const UInt32 *)(const void *)(p))
-#define GetUi64(p) (*(const UInt64 *)(const void *)(p))
-
-#define SetUi16(p, v) { *(UInt16 *)(p) = (v); }
-#define SetUi32(p, v) { *(UInt32 *)(p) = (v); }
-#define SetUi64(p, v) { *(UInt64 *)(p) = (v); }
-
-#else
-
-#define GetUi16(p) ( (UInt16) ( \
- ((const Byte *)(p))[0] | \
- ((UInt16)((const Byte *)(p))[1] << 8) ))
-
-#define GetUi32(p) ( \
- ((const Byte *)(p))[0] | \
- ((UInt32)((const Byte *)(p))[1] << 8) | \
- ((UInt32)((const Byte *)(p))[2] << 16) | \
- ((UInt32)((const Byte *)(p))[3] << 24))
-
-#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
-
-#define SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
- _ppp_[0] = (Byte)_vvv_; \
- _ppp_[1] = (Byte)(_vvv_ >> 8); }
-
-#define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
- _ppp_[0] = (Byte)_vvv_; \
- _ppp_[1] = (Byte)(_vvv_ >> 8); \
- _ppp_[2] = (Byte)(_vvv_ >> 16); \
- _ppp_[3] = (Byte)(_vvv_ >> 24); }
-
-#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \
- SetUi32(_ppp2_ , (UInt32)_vvv2_); \
- SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)); }
-
-#endif
-
-#ifdef __has_builtin
- #define MY__has_builtin(x) __has_builtin(x)
-#else
- #define MY__has_builtin(x) 0
-#endif
-
-#if defined(MY_CPU_LE_UNALIGN) && /* defined(_WIN64) && */ (_MSC_VER >= 1300)
-
-/* Note: we use bswap instruction, that is unsupported in 386 cpu */
-
-#include <stdlib.h>
-
-#pragma intrinsic(_byteswap_ushort)
-#pragma intrinsic(_byteswap_ulong)
-#pragma intrinsic(_byteswap_uint64)
-
-/* #define GetBe16(p) _byteswap_ushort(*(const UInt16 *)(const Byte *)(p)) */
-#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p))
-#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p))
-
-#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = _byteswap_ulong(v)
-
-#elif defined(MY_CPU_LE_UNALIGN) && ( \
- (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \
- || (defined(__clang__) && MY__has_builtin(__builtin_bswap16)) )
-
-/* #define GetBe16(p) __builtin_bswap16(*(const UInt16 *)(const Byte *)(p)) */
-#define GetBe32(p) __builtin_bswap32(*(const UInt32 *)(const Byte *)(p))
-#define GetBe64(p) __builtin_bswap64(*(const UInt64 *)(const Byte *)(p))
-
-#define SetBe32(p, v) (*(UInt32 *)(void *)(p)) = __builtin_bswap32(v)
-
-#else
-
-#define GetBe32(p) ( \
- ((UInt32)((const Byte *)(p))[0] << 24) | \
- ((UInt32)((const Byte *)(p))[1] << 16) | \
- ((UInt32)((const Byte *)(p))[2] << 8) | \
- ((const Byte *)(p))[3] )
-
-#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))
-
-#define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
- _ppp_[0] = (Byte)(_vvv_ >> 24); \
- _ppp_[1] = (Byte)(_vvv_ >> 16); \
- _ppp_[2] = (Byte)(_vvv_ >> 8); \
- _ppp_[3] = (Byte)_vvv_; }
-
-#endif
-
-
-#ifndef GetBe16
-
-#define GetBe16(p) ( (UInt16) ( \
- ((UInt16)((const Byte *)(p))[0] << 8) | \
- ((const Byte *)(p))[1] ))
-
-#endif
-
-
-
-#ifdef MY_CPU_X86_OR_AMD64
-
-typedef struct
-{
- UInt32 maxFunc;
- UInt32 vendor[3];
- UInt32 ver;
- UInt32 b;
- UInt32 c;
- UInt32 d;
-} Cx86cpuid;
-
-enum
-{
- CPU_FIRM_INTEL,
- CPU_FIRM_AMD,
- CPU_FIRM_VIA
-};
-
-void MyCPUID(UInt32 function, UInt32 *a, UInt32 *b, UInt32 *c, UInt32 *d);
-
-BoolInt x86cpuid_CheckAndRead(Cx86cpuid *p);
-int x86cpuid_GetFirm(const Cx86cpuid *p);
-
-#define x86cpuid_GetFamily(ver) (((ver >> 16) & 0xFF0) | ((ver >> 8) & 0xF))
-#define x86cpuid_GetModel(ver) (((ver >> 12) & 0xF0) | ((ver >> 4) & 0xF))
-#define x86cpuid_GetStepping(ver) (ver & 0xF)
-
-BoolInt CPU_Is_InOrder();
-BoolInt CPU_Is_Aes_Supported();
-BoolInt CPU_IsSupported_PageGB();
-
-#endif
-
-EXTERN_C_END
-
-#endif
+/* CpuArch.h -- CPU specific code
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_CPU_ARCH_H
+#define ZIP7_INC_CPU_ARCH_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/*
+MY_CPU_LE means that CPU is LITTLE ENDIAN.
+MY_CPU_BE means that CPU is BIG ENDIAN.
+If MY_CPU_LE and MY_CPU_BE are not defined, we don't know about ENDIANNESS of platform.
+
+MY_CPU_LE_UNALIGN means that CPU is LITTLE ENDIAN and CPU supports unaligned memory accesses.
+
+MY_CPU_64BIT means that processor can work with 64-bit registers.
+ MY_CPU_64BIT can be used to select fast code branch
+ MY_CPU_64BIT doesn't mean that (sizeof(void *) == 8)
+*/
+
+#if defined(_M_X64) \
+ || defined(_M_AMD64) \
+ || defined(__x86_64__) \
+ || defined(__AMD64__) \
+ || defined(__amd64__)
+ #define MY_CPU_AMD64
+ #ifdef __ILP32__
+ #define MY_CPU_NAME "x32"
+ #define MY_CPU_SIZEOF_POINTER 4
+ #else
+ #define MY_CPU_NAME "x64"
+ #define MY_CPU_SIZEOF_POINTER 8
+ #endif
+ #define MY_CPU_64BIT
+#endif
+
+
+#if defined(_M_IX86) \
+ || defined(__i386__)
+ #define MY_CPU_X86
+ #define MY_CPU_NAME "x86"
+ /* #define MY_CPU_32BIT */
+ #define MY_CPU_SIZEOF_POINTER 4
+#endif
+
+
+#if defined(_M_ARM64) \
+ || defined(__AARCH64EL__) \
+ || defined(__AARCH64EB__) \
+ || defined(__aarch64__)
+ #define MY_CPU_ARM64
+ #ifdef __ILP32__
+ #define MY_CPU_NAME "arm64-32"
+ #define MY_CPU_SIZEOF_POINTER 4
+ #else
+ #define MY_CPU_NAME "arm64"
+ #define MY_CPU_SIZEOF_POINTER 8
+ #endif
+ #define MY_CPU_64BIT
+#endif
+
+
+#if defined(_M_ARM) \
+ || defined(_M_ARM_NT) \
+ || defined(_M_ARMT) \
+ || defined(__arm__) \
+ || defined(__thumb__) \
+ || defined(__ARMEL__) \
+ || defined(__ARMEB__) \
+ || defined(__THUMBEL__) \
+ || defined(__THUMBEB__)
+ #define MY_CPU_ARM
+
+ #if defined(__thumb__) || defined(__THUMBEL__) || defined(_M_ARMT)
+ #define MY_CPU_ARMT
+ #define MY_CPU_NAME "armt"
+ #else
+ #define MY_CPU_ARM32
+ #define MY_CPU_NAME "arm"
+ #endif
+ /* #define MY_CPU_32BIT */
+ #define MY_CPU_SIZEOF_POINTER 4
+#endif
+
+
+#if defined(_M_IA64) \
+ || defined(__ia64__)
+ #define MY_CPU_IA64
+ #define MY_CPU_NAME "ia64"
+ #define MY_CPU_64BIT
+#endif
+
+
+#if defined(__mips64) \
+ || defined(__mips64__) \
+ || (defined(__mips) && (__mips == 64 || __mips == 4 || __mips == 3))
+ #define MY_CPU_NAME "mips64"
+ #define MY_CPU_64BIT
+#elif defined(__mips__)
+ #define MY_CPU_NAME "mips"
+ /* #define MY_CPU_32BIT */
+#endif
+
+
+#if defined(__ppc64__) \
+ || defined(__powerpc64__) \
+ || defined(__ppc__) \
+ || defined(__powerpc__) \
+ || defined(__PPC__) \
+ || defined(_POWER)
+
+#define MY_CPU_PPC_OR_PPC64
+
+#if defined(__ppc64__) \
+ || defined(__powerpc64__) \
+ || defined(_LP64) \
+ || defined(__64BIT__)
+ #ifdef __ILP32__
+ #define MY_CPU_NAME "ppc64-32"
+ #define MY_CPU_SIZEOF_POINTER 4
+ #else
+ #define MY_CPU_NAME "ppc64"
+ #define MY_CPU_SIZEOF_POINTER 8
+ #endif
+ #define MY_CPU_64BIT
+#else
+ #define MY_CPU_NAME "ppc"
+ #define MY_CPU_SIZEOF_POINTER 4
+ /* #define MY_CPU_32BIT */
+#endif
+#endif
+
+
+#if defined(__riscv) \
+ || defined(__riscv__)
+ #if __riscv_xlen == 32
+ #define MY_CPU_NAME "riscv32"
+ #elif __riscv_xlen == 64
+ #define MY_CPU_NAME "riscv64"
+ #else
+ #define MY_CPU_NAME "riscv"
+ #endif
+#endif
+
+
+#if defined(MY_CPU_X86) || defined(MY_CPU_AMD64)
+#define MY_CPU_X86_OR_AMD64
+#endif
+
+#if defined(MY_CPU_ARM) || defined(MY_CPU_ARM64)
+#define MY_CPU_ARM_OR_ARM64
+#endif
+
+
+#ifdef _WIN32
+
+ #ifdef MY_CPU_ARM
+ #define MY_CPU_ARM_LE
+ #endif
+
+ #ifdef MY_CPU_ARM64
+ #define MY_CPU_ARM64_LE
+ #endif
+
+ #ifdef _M_IA64
+ #define MY_CPU_IA64_LE
+ #endif
+
+#endif
+
+
+#if defined(MY_CPU_X86_OR_AMD64) \
+ || defined(MY_CPU_ARM_LE) \
+ || defined(MY_CPU_ARM64_LE) \
+ || defined(MY_CPU_IA64_LE) \
+ || defined(__LITTLE_ENDIAN__) \
+ || defined(__ARMEL__) \
+ || defined(__THUMBEL__) \
+ || defined(__AARCH64EL__) \
+ || defined(__MIPSEL__) \
+ || defined(__MIPSEL) \
+ || defined(_MIPSEL) \
+ || defined(__BFIN__) \
+ || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__))
+ #define MY_CPU_LE
+#endif
+
+#if defined(__BIG_ENDIAN__) \
+ || defined(__ARMEB__) \
+ || defined(__THUMBEB__) \
+ || defined(__AARCH64EB__) \
+ || defined(__MIPSEB__) \
+ || defined(__MIPSEB) \
+ || defined(_MIPSEB) \
+ || defined(__m68k__) \
+ || defined(__s390__) \
+ || defined(__s390x__) \
+ || defined(__zarch__) \
+ || (defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__))
+ #define MY_CPU_BE
+#endif
+
+
+#if defined(MY_CPU_LE) && defined(MY_CPU_BE)
+ #error Stop_Compiling_Bad_Endian
+#endif
+
+#if !defined(MY_CPU_LE) && !defined(MY_CPU_BE)
+ #error Stop_Compiling_CPU_ENDIAN_must_be_detected_at_compile_time
+#endif
+
+#if defined(MY_CPU_32BIT) && defined(MY_CPU_64BIT)
+ #error Stop_Compiling_Bad_32_64_BIT
+#endif
+
+#ifdef __SIZEOF_POINTER__
+ #ifdef MY_CPU_SIZEOF_POINTER
+ #if MY_CPU_SIZEOF_POINTER != __SIZEOF_POINTER__
+ #error Stop_Compiling_Bad_MY_CPU_PTR_SIZE
+ #endif
+ #else
+ #define MY_CPU_SIZEOF_POINTER __SIZEOF_POINTER__
+ #endif
+#endif
+
+#if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4)
+#if defined (_LP64)
+ #error Stop_Compiling_Bad_MY_CPU_PTR_SIZE
+#endif
+#endif
+
+#ifdef _MSC_VER
+ #if _MSC_VER >= 1300
+ #define MY_CPU_pragma_pack_push_1 __pragma(pack(push, 1))
+ #define MY_CPU_pragma_pop __pragma(pack(pop))
+ #else
+ #define MY_CPU_pragma_pack_push_1
+ #define MY_CPU_pragma_pop
+ #endif
+#else
+ #ifdef __xlC__
+ #define MY_CPU_pragma_pack_push_1 _Pragma("pack(1)")
+ #define MY_CPU_pragma_pop _Pragma("pack()")
+ #else
+ #define MY_CPU_pragma_pack_push_1 _Pragma("pack(push, 1)")
+ #define MY_CPU_pragma_pop _Pragma("pack(pop)")
+ #endif
+#endif
+
+
+#ifndef MY_CPU_NAME
+ #ifdef MY_CPU_LE
+ #define MY_CPU_NAME "LE"
+ #elif defined(MY_CPU_BE)
+ #define MY_CPU_NAME "BE"
+ #else
+ /*
+ #define MY_CPU_NAME ""
+ */
+ #endif
+#endif
+
+
+
+
+
+#ifdef __has_builtin
+ #define Z7_has_builtin(x) __has_builtin(x)
+#else
+ #define Z7_has_builtin(x) 0
+#endif
+
+
+#define Z7_BSWAP32_CONST(v) \
+ ( (((UInt32)(v) << 24) ) \
+ | (((UInt32)(v) << 8) & (UInt32)0xff0000) \
+ | (((UInt32)(v) >> 8) & (UInt32)0xff00 ) \
+ | (((UInt32)(v) >> 24) ))
+
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1300)
+
+#include <stdlib.h>
+
+/* Note: these macros will use bswap instruction (486), that is unsupported in 386 cpu */
+
+#pragma intrinsic(_byteswap_ushort)
+#pragma intrinsic(_byteswap_ulong)
+#pragma intrinsic(_byteswap_uint64)
+
+#define Z7_BSWAP16(v) _byteswap_ushort(v)
+#define Z7_BSWAP32(v) _byteswap_ulong (v)
+#define Z7_BSWAP64(v) _byteswap_uint64(v)
+#define Z7_CPU_FAST_BSWAP_SUPPORTED
+
+#elif (defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3))) \
+ || (defined(__clang__) && Z7_has_builtin(__builtin_bswap16))
+
+#define Z7_BSWAP16(v) __builtin_bswap16(v)
+#define Z7_BSWAP32(v) __builtin_bswap32(v)
+#define Z7_BSWAP64(v) __builtin_bswap64(v)
+#define Z7_CPU_FAST_BSWAP_SUPPORTED
+
+#else
+
+#define Z7_BSWAP16(v) ((UInt16) \
+ ( ((UInt32)(v) << 8) \
+ | ((UInt32)(v) >> 8) \
+ ))
+
+#define Z7_BSWAP32(v) Z7_BSWAP32_CONST(v)
+
+#define Z7_BSWAP64(v) \
+ ( ( ( (UInt64)(v) ) << 8 * 7 ) \
+ | ( ( (UInt64)(v) & ((UInt32)0xff << 8 * 1) ) << 8 * 5 ) \
+ | ( ( (UInt64)(v) & ((UInt32)0xff << 8 * 2) ) << 8 * 3 ) \
+ | ( ( (UInt64)(v) & ((UInt32)0xff << 8 * 3) ) << 8 * 1 ) \
+ | ( ( (UInt64)(v) >> 8 * 1 ) & ((UInt32)0xff << 8 * 3) ) \
+ | ( ( (UInt64)(v) >> 8 * 3 ) & ((UInt32)0xff << 8 * 2) ) \
+ | ( ( (UInt64)(v) >> 8 * 5 ) & ((UInt32)0xff << 8 * 1) ) \
+ | ( ( (UInt64)(v) >> 8 * 7 ) ) \
+ )
+
+#endif
+
+
+
+#ifdef MY_CPU_LE
+ #if defined(MY_CPU_X86_OR_AMD64) \
+ || defined(MY_CPU_ARM64)
+ #define MY_CPU_LE_UNALIGN
+ #define MY_CPU_LE_UNALIGN_64
+ #elif defined(__ARM_FEATURE_UNALIGNED)
+ /* gcc9 for 32-bit arm can use LDRD instruction that requires 32-bit alignment.
+ So we can't use unaligned 64-bit operations. */
+ #define MY_CPU_LE_UNALIGN
+ #endif
+#endif
+
+
+#ifdef MY_CPU_LE_UNALIGN
+
+#define GetUi16(p) (*(const UInt16 *)(const void *)(p))
+#define GetUi32(p) (*(const UInt32 *)(const void *)(p))
+#ifdef MY_CPU_LE_UNALIGN_64
+#define GetUi64(p) (*(const UInt64 *)(const void *)(p))
+#define SetUi64(p, v) { *(UInt64 *)(void *)(p) = (v); }
+#endif
+
+#define SetUi16(p, v) { *(UInt16 *)(void *)(p) = (v); }
+#define SetUi32(p, v) { *(UInt32 *)(void *)(p) = (v); }
+
+#else
+
+#define GetUi16(p) ( (UInt16) ( \
+ ((const Byte *)(p))[0] | \
+ ((UInt16)((const Byte *)(p))[1] << 8) ))
+
+#define GetUi32(p) ( \
+ ((const Byte *)(p))[0] | \
+ ((UInt32)((const Byte *)(p))[1] << 8) | \
+ ((UInt32)((const Byte *)(p))[2] << 16) | \
+ ((UInt32)((const Byte *)(p))[3] << 24))
+
+#define SetUi16(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
+ _ppp_[0] = (Byte)_vvv_; \
+ _ppp_[1] = (Byte)(_vvv_ >> 8); }
+
+#define SetUi32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
+ _ppp_[0] = (Byte)_vvv_; \
+ _ppp_[1] = (Byte)(_vvv_ >> 8); \
+ _ppp_[2] = (Byte)(_vvv_ >> 16); \
+ _ppp_[3] = (Byte)(_vvv_ >> 24); }
+
+#endif
+
+
+#ifndef GetUi64
+#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
+#endif
+
+#ifndef SetUi64
+#define SetUi64(p, v) { Byte *_ppp2_ = (Byte *)(p); UInt64 _vvv2_ = (v); \
+ SetUi32(_ppp2_ , (UInt32)_vvv2_) \
+ SetUi32(_ppp2_ + 4, (UInt32)(_vvv2_ >> 32)) }
+#endif
+
+
+#if defined(MY_CPU_LE_UNALIGN) && defined(Z7_CPU_FAST_BSWAP_SUPPORTED)
+
+#define GetBe32(p) Z7_BSWAP32 (*(const UInt32 *)(const void *)(p))
+#define SetBe32(p, v) { (*(UInt32 *)(void *)(p)) = Z7_BSWAP32(v); }
+
+#if defined(MY_CPU_LE_UNALIGN_64)
+#define GetBe64(p) Z7_BSWAP64 (*(const UInt64 *)(const void *)(p))
+#endif
+
+#else
+
+#define GetBe32(p) ( \
+ ((UInt32)((const Byte *)(p))[0] << 24) | \
+ ((UInt32)((const Byte *)(p))[1] << 16) | \
+ ((UInt32)((const Byte *)(p))[2] << 8) | \
+ ((const Byte *)(p))[3] )
+
+#define SetBe32(p, v) { Byte *_ppp_ = (Byte *)(p); UInt32 _vvv_ = (v); \
+ _ppp_[0] = (Byte)(_vvv_ >> 24); \
+ _ppp_[1] = (Byte)(_vvv_ >> 16); \
+ _ppp_[2] = (Byte)(_vvv_ >> 8); \
+ _ppp_[3] = (Byte)_vvv_; }
+
+#endif
+
+#ifndef GetBe64
+#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))
+#endif
+
+#ifndef GetBe16
+#define GetBe16(p) ( (UInt16) ( \
+ ((UInt16)((const Byte *)(p))[0] << 8) | \
+ ((const Byte *)(p))[1] ))
+#endif
+
+
+#if defined(MY_CPU_BE)
+#define Z7_CONV_BE_TO_NATIVE_CONST32(v) (v)
+#define Z7_CONV_LE_TO_NATIVE_CONST32(v) Z7_BSWAP32_CONST(v)
+#define Z7_CONV_NATIVE_TO_BE_32(v) (v)
+#elif defined(MY_CPU_LE)
+#define Z7_CONV_BE_TO_NATIVE_CONST32(v) Z7_BSWAP32_CONST(v)
+#define Z7_CONV_LE_TO_NATIVE_CONST32(v) (v)
+#define Z7_CONV_NATIVE_TO_BE_32(v) Z7_BSWAP32(v)
+#else
+#error Stop_Compiling_Unknown_Endian_CONV
+#endif
+
+
+#if defined(MY_CPU_BE)
+
+#define GetBe32a(p) (*(const UInt32 *)(const void *)(p))
+#define GetBe16a(p) (*(const UInt16 *)(const void *)(p))
+#define SetBe32a(p, v) { *(UInt32 *)(void *)(p) = (v); }
+#define SetBe16a(p, v) { *(UInt16 *)(void *)(p) = (v); }
+
+#define GetUi32a(p) GetUi32(p)
+#define GetUi16a(p) GetUi16(p)
+#define SetUi32a(p, v) SetUi32(p, v)
+#define SetUi16a(p, v) SetUi16(p, v)
+
+#elif defined(MY_CPU_LE)
+
+#define GetUi32a(p) (*(const UInt32 *)(const void *)(p))
+#define GetUi16a(p) (*(const UInt16 *)(const void *)(p))
+#define SetUi32a(p, v) { *(UInt32 *)(void *)(p) = (v); }
+#define SetUi16a(p, v) { *(UInt16 *)(void *)(p) = (v); }
+
+#define GetBe32a(p) GetBe32(p)
+#define GetBe16a(p) GetBe16(p)
+#define SetBe32a(p, v) SetBe32(p, v)
+#define SetBe16a(p, v) SetBe16(p, v)
+
+#else
+#error Stop_Compiling_Unknown_Endian_CPU_a
+#endif
+
+
+#if defined(MY_CPU_X86_OR_AMD64) \
+ || defined(MY_CPU_ARM_OR_ARM64) \
+ || defined(MY_CPU_PPC_OR_PPC64)
+ #define Z7_CPU_FAST_ROTATE_SUPPORTED
+#endif
+
+
+#ifdef MY_CPU_X86_OR_AMD64
+
+void Z7_FASTCALL z7_x86_cpuid(UInt32 a[4], UInt32 function);
+UInt32 Z7_FASTCALL z7_x86_cpuid_GetMaxFunc(void);
+#if defined(MY_CPU_AMD64)
+#define Z7_IF_X86_CPUID_SUPPORTED
+#else
+#define Z7_IF_X86_CPUID_SUPPORTED if (z7_x86_cpuid_GetMaxFunc())
+#endif
+
+BoolInt CPU_IsSupported_AES(void);
+BoolInt CPU_IsSupported_AVX(void);
+BoolInt CPU_IsSupported_AVX2(void);
+BoolInt CPU_IsSupported_VAES_AVX2(void);
+BoolInt CPU_IsSupported_CMOV(void);
+BoolInt CPU_IsSupported_SSE(void);
+BoolInt CPU_IsSupported_SSE2(void);
+BoolInt CPU_IsSupported_SSSE3(void);
+BoolInt CPU_IsSupported_SSE41(void);
+BoolInt CPU_IsSupported_SHA(void);
+BoolInt CPU_IsSupported_PageGB(void);
+
+#elif defined(MY_CPU_ARM_OR_ARM64)
+
+BoolInt CPU_IsSupported_CRC32(void);
+BoolInt CPU_IsSupported_NEON(void);
+
+#if defined(_WIN32)
+BoolInt CPU_IsSupported_CRYPTO(void);
+#define CPU_IsSupported_SHA1 CPU_IsSupported_CRYPTO
+#define CPU_IsSupported_SHA2 CPU_IsSupported_CRYPTO
+#define CPU_IsSupported_AES CPU_IsSupported_CRYPTO
+#else
+BoolInt CPU_IsSupported_SHA1(void);
+BoolInt CPU_IsSupported_SHA2(void);
+BoolInt CPU_IsSupported_AES(void);
+#endif
+
+#endif
+
+#if defined(__APPLE__)
+int z7_sysctlbyname_Get(const char *name, void *buf, size_t *bufSize);
+int z7_sysctlbyname_Get_UInt32(const char *name, UInt32 *val);
+#endif
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Delta.c b/C/Delta.c
index 6cbbe46..c4a4499 100644
--- a/C/Delta.c
+++ b/C/Delta.c
@@ -1,64 +1,169 @@
-/* Delta.c -- Delta converter
-2009-05-26 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "Delta.h"
-
-void Delta_Init(Byte *state)
-{
- unsigned i;
- for (i = 0; i < DELTA_STATE_SIZE; i++)
- state[i] = 0;
-}
-
-static void MyMemCpy(Byte *dest, const Byte *src, unsigned size)
-{
- unsigned i;
- for (i = 0; i < size; i++)
- dest[i] = src[i];
-}
-
-void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size)
-{
- Byte buf[DELTA_STATE_SIZE];
- unsigned j = 0;
- MyMemCpy(buf, state, delta);
- {
- SizeT i;
- for (i = 0; i < size;)
- {
- for (j = 0; j < delta && i < size; i++, j++)
- {
- Byte b = data[i];
- data[i] = (Byte)(b - buf[j]);
- buf[j] = b;
- }
- }
- }
- if (j == delta)
- j = 0;
- MyMemCpy(state, buf + j, delta - j);
- MyMemCpy(state + delta - j, buf, j);
-}
-
-void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size)
-{
- Byte buf[DELTA_STATE_SIZE];
- unsigned j = 0;
- MyMemCpy(buf, state, delta);
- {
- SizeT i;
- for (i = 0; i < size;)
- {
- for (j = 0; j < delta && i < size; i++, j++)
- {
- buf[j] = data[i] = (Byte)(buf[j] + data[i]);
- }
- }
- }
- if (j == delta)
- j = 0;
- MyMemCpy(state, buf + j, delta - j);
- MyMemCpy(state + delta - j, buf, j);
-}
+/* Delta.c -- Delta converter
+2021-02-09 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Delta.h"
+
+void Delta_Init(Byte *state)
+{
+ unsigned i;
+ for (i = 0; i < DELTA_STATE_SIZE; i++)
+ state[i] = 0;
+}
+
+
+void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size)
+{
+ Byte temp[DELTA_STATE_SIZE];
+
+ if (size == 0)
+ return;
+
+ {
+ unsigned i = 0;
+ do
+ temp[i] = state[i];
+ while (++i != delta);
+ }
+
+ if (size <= delta)
+ {
+ unsigned i = 0, k;
+ do
+ {
+ Byte b = *data;
+ *data++ = (Byte)(b - temp[i]);
+ temp[i] = b;
+ }
+ while (++i != size);
+
+ k = 0;
+
+ do
+ {
+ if (i == delta)
+ i = 0;
+ state[k] = temp[i++];
+ }
+ while (++k != delta);
+
+ return;
+ }
+
+ {
+ Byte *p = data + size - delta;
+ {
+ unsigned i = 0;
+ do
+ state[i] = *p++;
+ while (++i != delta);
+ }
+ {
+ const Byte *lim = data + delta;
+ ptrdiff_t dif = -(ptrdiff_t)delta;
+
+ if (((ptrdiff_t)size + dif) & 1)
+ {
+ --p; *p = (Byte)(*p - p[dif]);
+ }
+
+ while (p != lim)
+ {
+ --p; *p = (Byte)(*p - p[dif]);
+ --p; *p = (Byte)(*p - p[dif]);
+ }
+
+ dif = -dif;
+
+ do
+ {
+ --p; *p = (Byte)(*p - temp[--dif]);
+ }
+ while (dif != 0);
+ }
+ }
+}
+
+
+void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size)
+{
+ unsigned i;
+ const Byte *lim;
+
+ if (size == 0)
+ return;
+
+ i = 0;
+ lim = data + size;
+
+ if (size <= delta)
+ {
+ do
+ *data = (Byte)(*data + state[i++]);
+ while (++data != lim);
+
+ for (; delta != i; state++, delta--)
+ *state = state[i];
+ data -= i;
+ }
+ else
+ {
+ /*
+ #define B(n) b ## n
+ #define I(n) Byte B(n) = state[n];
+ #define U(n) { B(n) = (Byte)((B(n)) + *data++); data[-1] = (B(n)); }
+ #define F(n) if (data != lim) { U(n) }
+
+ if (delta == 1)
+ {
+ I(0)
+ if ((lim - data) & 1) { U(0) }
+ while (data != lim) { U(0) U(0) }
+ data -= 1;
+ }
+ else if (delta == 2)
+ {
+ I(0) I(1)
+ lim -= 1; while (data < lim) { U(0) U(1) }
+ lim += 1; F(0)
+ data -= 2;
+ }
+ else if (delta == 3)
+ {
+ I(0) I(1) I(2)
+ lim -= 2; while (data < lim) { U(0) U(1) U(2) }
+ lim += 2; F(0) F(1)
+ data -= 3;
+ }
+ else if (delta == 4)
+ {
+ I(0) I(1) I(2) I(3)
+ lim -= 3; while (data < lim) { U(0) U(1) U(2) U(3) }
+ lim += 3; F(0) F(1) F(2)
+ data -= 4;
+ }
+ else
+ */
+ {
+ do
+ {
+ *data = (Byte)(*data + state[i++]);
+ data++;
+ }
+ while (i != delta);
+
+ {
+ ptrdiff_t dif = -(ptrdiff_t)delta;
+ do
+ *data = (Byte)(*data + data[dif]);
+ while (++data != lim);
+ data += dif;
+ }
+ }
+ }
+
+ do
+ *state++ = *data;
+ while (++data != lim);
+}
diff --git a/C/Delta.h b/C/Delta.h
index e59d5a2..7060954 100644
--- a/C/Delta.h
+++ b/C/Delta.h
@@ -1,19 +1,19 @@
-/* Delta.h -- Delta converter
-2013-01-18 : Igor Pavlov : Public domain */
-
-#ifndef __DELTA_H
-#define __DELTA_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-#define DELTA_STATE_SIZE 256
-
-void Delta_Init(Byte *state);
-void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size);
-void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size);
-
-EXTERN_C_END
-
-#endif
+/* Delta.h -- Delta converter
+2023-03-03 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_DELTA_H
+#define ZIP7_INC_DELTA_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define DELTA_STATE_SIZE 256
+
+void Delta_Init(Byte *state);
+void Delta_Encode(Byte *state, unsigned delta, Byte *data, SizeT size);
+void Delta_Decode(Byte *state, unsigned delta, Byte *data, SizeT size);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/DllSecur.c b/C/DllSecur.c
index 19a22a9..02a0f97 100644
--- a/C/DllSecur.c
+++ b/C/DllSecur.c
@@ -1,108 +1,111 @@
-/* DllSecur.c -- DLL loading security
-2018-02-21 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#ifdef _WIN32
-
-#include <windows.h>
-
-#include "DllSecur.h"
-
-#ifndef UNDER_CE
-
-typedef BOOL (WINAPI *Func_SetDefaultDllDirectories)(DWORD DirectoryFlags);
-
-#define MY_LOAD_LIBRARY_SEARCH_USER_DIRS 0x400
-#define MY_LOAD_LIBRARY_SEARCH_SYSTEM32 0x800
-
-static const char * const g_Dlls =
- #ifndef _CONSOLE
- "UXTHEME\0"
- #endif
- "USERENV\0"
- "SETUPAPI\0"
- "APPHELP\0"
- "PROPSYS\0"
- "DWMAPI\0"
- "CRYPTBASE\0"
- "OLEACC\0"
- "CLBCATQ\0"
- "VERSION\0"
- ;
-
-#endif
-
-void My_SetDefaultDllDirectories()
-{
- #ifndef UNDER_CE
-
- OSVERSIONINFO vi;
- vi.dwOSVersionInfoSize = sizeof(vi);
- GetVersionEx(&vi);
- if (!GetVersionEx(&vi) || vi.dwMajorVersion != 6 || vi.dwMinorVersion != 0)
- {
- Func_SetDefaultDllDirectories setDllDirs = (Func_SetDefaultDllDirectories)
- GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "SetDefaultDllDirectories");
- if (setDllDirs)
- if (setDllDirs(MY_LOAD_LIBRARY_SEARCH_SYSTEM32 | MY_LOAD_LIBRARY_SEARCH_USER_DIRS))
- return;
- }
-
- #endif
-}
-
-
-void LoadSecurityDlls()
-{
- #ifndef UNDER_CE
-
- wchar_t buf[MAX_PATH + 100];
-
- {
- // at Vista (ver 6.0) : CoCreateInstance(CLSID_ShellLink, ...) doesn't work after SetDefaultDllDirectories() : Check it ???
- OSVERSIONINFO vi;
- vi.dwOSVersionInfoSize = sizeof(vi);
- if (!GetVersionEx(&vi) || vi.dwMajorVersion != 6 || vi.dwMinorVersion != 0)
- {
- Func_SetDefaultDllDirectories setDllDirs = (Func_SetDefaultDllDirectories)
- GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "SetDefaultDllDirectories");
- if (setDllDirs)
- if (setDllDirs(MY_LOAD_LIBRARY_SEARCH_SYSTEM32 | MY_LOAD_LIBRARY_SEARCH_USER_DIRS))
- return;
- }
- }
-
- {
- unsigned len = GetSystemDirectoryW(buf, MAX_PATH + 2);
- if (len == 0 || len > MAX_PATH)
- return;
- }
- {
- const char *dll;
- unsigned pos = (unsigned)lstrlenW(buf);
-
- if (buf[pos - 1] != '\\')
- buf[pos++] = '\\';
-
- for (dll = g_Dlls; dll[0] != 0;)
- {
- unsigned k = 0;
- for (;;)
- {
- char c = *dll++;
- buf[pos + k] = (Byte)c;
- k++;
- if (c == 0)
- break;
- }
-
- lstrcatW(buf, L".dll");
- LoadLibraryExW(buf, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
- }
- }
-
- #endif
-}
-
-#endif
+/* DllSecur.c -- DLL loading security
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#ifdef _WIN32
+
+#include "7zWindows.h"
+
+#include "DllSecur.h"
+
+#ifndef UNDER_CE
+
+#if (defined(__GNUC__) && (__GNUC__ >= 8)) || defined(__clang__)
+ // #pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+
+#if defined(__clang__) || defined(__GNUC__)
+typedef void (*Z7_voidFunction)(void);
+#define MY_CAST_FUNC (Z7_voidFunction)
+#elif defined(_MSC_VER) && _MSC_VER > 1920
+#define MY_CAST_FUNC (void *)
+// #pragma warning(disable : 4191) // 'type cast': unsafe conversion from 'FARPROC' to 'void (__cdecl *)()'
+#else
+#define MY_CAST_FUNC
+#endif
+
+typedef BOOL (WINAPI *Func_SetDefaultDllDirectories)(DWORD DirectoryFlags);
+
+#define MY_LOAD_LIBRARY_SEARCH_USER_DIRS 0x400
+#define MY_LOAD_LIBRARY_SEARCH_SYSTEM32 0x800
+
+#define DELIM "\0"
+
+static const char * const g_Dlls =
+ "userenv"
+ DELIM "setupapi"
+ DELIM "apphelp"
+ DELIM "propsys"
+ DELIM "dwmapi"
+ DELIM "cryptbase"
+ DELIM "oleacc"
+ DELIM "clbcatq"
+ DELIM "version"
+ #ifndef _CONSOLE
+ DELIM "uxtheme"
+ #endif
+ DELIM;
+
+#endif
+
+#ifdef __clang__
+ #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+#if defined (_MSC_VER) && _MSC_VER >= 1900
+// sysinfoapi.h: kit10: GetVersion was declared deprecated
+#pragma warning(disable : 4996)
+#endif
+
+#define IF_NON_VISTA_SET_DLL_DIRS_AND_RETURN \
+ if ((UInt16)GetVersion() != 6) { \
+ const \
+ Func_SetDefaultDllDirectories setDllDirs = \
+ (Func_SetDefaultDllDirectories) MY_CAST_FUNC GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), \
+ "SetDefaultDllDirectories"); \
+ if (setDllDirs) if (setDllDirs(MY_LOAD_LIBRARY_SEARCH_SYSTEM32 | MY_LOAD_LIBRARY_SEARCH_USER_DIRS)) return; }
+
+void My_SetDefaultDllDirectories(void)
+{
+ #ifndef UNDER_CE
+ IF_NON_VISTA_SET_DLL_DIRS_AND_RETURN
+ #endif
+}
+
+
+void LoadSecurityDlls(void)
+{
+ #ifndef UNDER_CE
+ // at Vista (ver 6.0) : CoCreateInstance(CLSID_ShellLink, ...) doesn't work after SetDefaultDllDirectories() : Check it ???
+ IF_NON_VISTA_SET_DLL_DIRS_AND_RETURN
+ {
+ wchar_t buf[MAX_PATH + 100];
+ const char *dll;
+ unsigned pos = GetSystemDirectoryW(buf, MAX_PATH + 2);
+ if (pos == 0 || pos > MAX_PATH)
+ return;
+ if (buf[pos - 1] != '\\')
+ buf[pos++] = '\\';
+ for (dll = g_Dlls; *dll != 0;)
+ {
+ wchar_t *dest = &buf[pos];
+ for (;;)
+ {
+ const char c = *dll++;
+ if (c == 0)
+ break;
+ *dest++ = (Byte)c;
+ }
+ dest[0] = '.';
+ dest[1] = 'd';
+ dest[2] = 'l';
+ dest[3] = 'l';
+ dest[4] = 0;
+ // lstrcatW(buf, L".dll");
+ LoadLibraryExW(buf, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
+ }
+ }
+ #endif
+}
+
+#endif // _WIN32
diff --git a/C/DllSecur.h b/C/DllSecur.h
index 4c11356..9fa4153 100644
--- a/C/DllSecur.h
+++ b/C/DllSecur.h
@@ -1,20 +1,20 @@
-/* DllSecur.h -- DLL loading for security
-2018-02-19 : Igor Pavlov : Public domain */
-
-#ifndef __DLL_SECUR_H
-#define __DLL_SECUR_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-#ifdef _WIN32
-
-void My_SetDefaultDllDirectories();
-void LoadSecurityDlls();
-
-#endif
-
-EXTERN_C_END
-
-#endif
+/* DllSecur.h -- DLL loading for security
+2023-03-03 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_DLL_SECUR_H
+#define ZIP7_INC_DLL_SECUR_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#ifdef _WIN32
+
+void My_SetDefaultDllDirectories(void);
+void LoadSecurityDlls(void);
+
+#endif
+
+EXTERN_C_END
+
+#endif
diff --git a/C/HuffEnc.c b/C/HuffEnc.c
new file mode 100644
index 0000000..3dc1e39
--- /dev/null
+++ b/C/HuffEnc.c
@@ -0,0 +1,154 @@
+/* HuffEnc.c -- functions for Huffman encoding
+2023-03-04 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "HuffEnc.h"
+#include "Sort.h"
+
+#define kMaxLen 16
+#define NUM_BITS 10
+#define MASK (((unsigned)1 << NUM_BITS) - 1)
+
+#define NUM_COUNTERS 64
+
+#define HUFFMAN_SPEED_OPT
+
+void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 numSymbols, UInt32 maxLen)
+{
+ UInt32 num = 0;
+ /* if (maxLen > 10) maxLen = 10; */
+ {
+ UInt32 i;
+
+ #ifdef HUFFMAN_SPEED_OPT
+
+ UInt32 counters[NUM_COUNTERS];
+ for (i = 0; i < NUM_COUNTERS; i++)
+ counters[i] = 0;
+ for (i = 0; i < numSymbols; i++)
+ {
+ UInt32 freq = freqs[i];
+ counters[(freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1]++;
+ }
+
+ for (i = 1; i < NUM_COUNTERS; i++)
+ {
+ UInt32 temp = counters[i];
+ counters[i] = num;
+ num += temp;
+ }
+
+ for (i = 0; i < numSymbols; i++)
+ {
+ UInt32 freq = freqs[i];
+ if (freq == 0)
+ lens[i] = 0;
+ else
+ p[counters[((freq < NUM_COUNTERS - 1) ? freq : NUM_COUNTERS - 1)]++] = i | (freq << NUM_BITS);
+ }
+ counters[0] = 0;
+ HeapSort(p + counters[NUM_COUNTERS - 2], counters[NUM_COUNTERS - 1] - counters[NUM_COUNTERS - 2]);
+
+ #else
+
+ for (i = 0; i < numSymbols; i++)
+ {
+ UInt32 freq = freqs[i];
+ if (freq == 0)
+ lens[i] = 0;
+ else
+ p[num++] = i | (freq << NUM_BITS);
+ }
+ HeapSort(p, num);
+
+ #endif
+ }
+
+ if (num < 2)
+ {
+ unsigned minCode = 0;
+ unsigned maxCode = 1;
+ if (num == 1)
+ {
+ maxCode = (unsigned)p[0] & MASK;
+ if (maxCode == 0)
+ maxCode++;
+ }
+ p[minCode] = 0;
+ p[maxCode] = 1;
+ lens[minCode] = lens[maxCode] = 1;
+ return;
+ }
+
+ {
+ UInt32 b, e, i;
+
+ i = b = e = 0;
+ do
+ {
+ UInt32 n, m, freq;
+ n = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++;
+ freq = (p[n] & ~MASK);
+ p[n] = (p[n] & MASK) | (e << NUM_BITS);
+ m = (i != num && (b == e || (p[i] >> NUM_BITS) <= (p[b] >> NUM_BITS))) ? i++ : b++;
+ freq += (p[m] & ~MASK);
+ p[m] = (p[m] & MASK) | (e << NUM_BITS);
+ p[e] = (p[e] & MASK) | freq;
+ e++;
+ }
+ while (num - e > 1);
+
+ {
+ UInt32 lenCounters[kMaxLen + 1];
+ for (i = 0; i <= kMaxLen; i++)
+ lenCounters[i] = 0;
+
+ p[--e] &= MASK;
+ lenCounters[1] = 2;
+ while (e != 0)
+ {
+ UInt32 len = (p[p[--e] >> NUM_BITS] >> NUM_BITS) + 1;
+ p[e] = (p[e] & MASK) | (len << NUM_BITS);
+ if (len >= maxLen)
+ for (len = maxLen - 1; lenCounters[len] == 0; len--);
+ lenCounters[len]--;
+ lenCounters[(size_t)len + 1] += 2;
+ }
+
+ {
+ UInt32 len;
+ i = 0;
+ for (len = maxLen; len != 0; len--)
+ {
+ UInt32 k;
+ for (k = lenCounters[len]; k != 0; k--)
+ lens[p[i++] & MASK] = (Byte)len;
+ }
+ }
+
+ {
+ UInt32 nextCodes[kMaxLen + 1];
+ {
+ UInt32 code = 0;
+ UInt32 len;
+ for (len = 1; len <= kMaxLen; len++)
+ nextCodes[len] = code = (code + lenCounters[(size_t)len - 1]) << 1;
+ }
+ /* if (code + lenCounters[kMaxLen] - 1 != (1 << kMaxLen) - 1) throw 1; */
+
+ {
+ UInt32 k;
+ for (k = 0; k < numSymbols; k++)
+ p[k] = nextCodes[lens[k]]++;
+ }
+ }
+ }
+ }
+}
+
+#undef kMaxLen
+#undef NUM_BITS
+#undef MASK
+#undef NUM_COUNTERS
+#undef HUFFMAN_SPEED_OPT
diff --git a/C/HuffEnc.h b/C/HuffEnc.h
new file mode 100644
index 0000000..cbc5d11
--- /dev/null
+++ b/C/HuffEnc.h
@@ -0,0 +1,23 @@
+/* HuffEnc.h -- Huffman encoding
+2023-03-05 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_HUFF_ENC_H
+#define ZIP7_INC_HUFF_ENC_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/*
+Conditions:
+ num <= 1024 = 2 ^ NUM_BITS
+ Sum(freqs) < 4M = 2 ^ (32 - NUM_BITS)
+ maxLen <= 16 = kMaxLen
+ Num_Items(p) >= HUFFMAN_TEMP_SIZE(num)
+*/
+
+void Huffman_Generate(const UInt32 *freqs, UInt32 *p, Byte *lens, UInt32 num, UInt32 maxLen);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/LzFind.c b/C/LzFind.c
index 4eefc17..0fbd5aa 100644
--- a/C/LzFind.c
+++ b/C/LzFind.c
@@ -1,1127 +1,1717 @@
-/* LzFind.c -- Match finder for LZ algorithms
-2018-07-08 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include <string.h>
-
-#include "LzFind.h"
-#include "LzHash.h"
-
-#define kEmptyHashValue 0
-#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
-#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
-#define kNormalizeMask (~(UInt32)(kNormalizeStepMin - 1))
-#define kMaxHistorySize ((UInt32)7 << 29)
-
-#define kStartMaxLen 3
-
-static void LzInWindow_Free(CMatchFinder *p, ISzAllocPtr alloc)
-{
- if (!p->directInput)
- {
- ISzAlloc_Free(alloc, p->bufferBase);
- p->bufferBase = NULL;
- }
-}
-
-/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
-
-static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAllocPtr alloc)
-{
- UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
- if (p->directInput)
- {
- p->blockSize = blockSize;
- return 1;
- }
- if (!p->bufferBase || p->blockSize != blockSize)
- {
- LzInWindow_Free(p, alloc);
- p->blockSize = blockSize;
- p->bufferBase = (Byte *)ISzAlloc_Alloc(alloc, (size_t)blockSize);
- }
- return (p->bufferBase != NULL);
-}
-
-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
-
-UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
-
-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
-{
- p->posLimit -= subValue;
- p->pos -= subValue;
- p->streamPos -= subValue;
-}
-
-static void MatchFinder_ReadBlock(CMatchFinder *p)
-{
- if (p->streamEndWasReached || p->result != SZ_OK)
- return;
-
- /* We use (p->streamPos - p->pos) value. (p->streamPos < p->pos) is allowed. */
-
- if (p->directInput)
- {
- UInt32 curSize = 0xFFFFFFFF - (p->streamPos - p->pos);
- if (curSize > p->directInputRem)
- curSize = (UInt32)p->directInputRem;
- p->directInputRem -= curSize;
- p->streamPos += curSize;
- if (p->directInputRem == 0)
- p->streamEndWasReached = 1;
- return;
- }
-
- for (;;)
- {
- Byte *dest = p->buffer + (p->streamPos - p->pos);
- size_t size = (p->bufferBase + p->blockSize - dest);
- if (size == 0)
- return;
-
- p->result = ISeqInStream_Read(p->stream, dest, &size);
- if (p->result != SZ_OK)
- return;
- if (size == 0)
- {
- p->streamEndWasReached = 1;
- return;
- }
- p->streamPos += (UInt32)size;
- if (p->streamPos - p->pos > p->keepSizeAfter)
- return;
- }
-}
-
-void MatchFinder_MoveBlock(CMatchFinder *p)
-{
- memmove(p->bufferBase,
- p->buffer - p->keepSizeBefore,
- (size_t)(p->streamPos - p->pos) + p->keepSizeBefore);
- p->buffer = p->bufferBase + p->keepSizeBefore;
-}
-
-int MatchFinder_NeedMove(CMatchFinder *p)
-{
- if (p->directInput)
- return 0;
- /* if (p->streamEndWasReached) return 0; */
- return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
-}
-
-void MatchFinder_ReadIfRequired(CMatchFinder *p)
-{
- if (p->streamEndWasReached)
- return;
- if (p->keepSizeAfter >= p->streamPos - p->pos)
- MatchFinder_ReadBlock(p);
-}
-
-static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
-{
- if (MatchFinder_NeedMove(p))
- MatchFinder_MoveBlock(p);
- MatchFinder_ReadBlock(p);
-}
-
-static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
-{
- p->cutValue = 32;
- p->btMode = 1;
- p->numHashBytes = 4;
- p->bigHash = 0;
-}
-
-#define kCrcPoly 0xEDB88320
-
-void MatchFinder_Construct(CMatchFinder *p)
-{
- unsigned i;
- p->bufferBase = NULL;
- p->directInput = 0;
- p->hash = NULL;
- p->expectedDataSize = (UInt64)(Int64)-1;
- MatchFinder_SetDefaultSettings(p);
-
- for (i = 0; i < 256; i++)
- {
- UInt32 r = (UInt32)i;
- unsigned j;
- for (j = 0; j < 8; j++)
- r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1)));
- p->crc[i] = r;
- }
-}
-
-static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAllocPtr alloc)
-{
- ISzAlloc_Free(alloc, p->hash);
- p->hash = NULL;
-}
-
-void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc)
-{
- MatchFinder_FreeThisClassMemory(p, alloc);
- LzInWindow_Free(p, alloc);
-}
-
-static CLzRef* AllocRefs(size_t num, ISzAllocPtr alloc)
-{
- size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
- if (sizeInBytes / sizeof(CLzRef) != num)
- return NULL;
- return (CLzRef *)ISzAlloc_Alloc(alloc, sizeInBytes);
-}
-
-int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
- UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
- ISzAllocPtr alloc)
-{
- UInt32 sizeReserv;
-
- if (historySize > kMaxHistorySize)
- {
- MatchFinder_Free(p, alloc);
- return 0;
- }
-
- sizeReserv = historySize >> 1;
- if (historySize >= ((UInt32)3 << 30)) sizeReserv = historySize >> 3;
- else if (historySize >= ((UInt32)2 << 30)) sizeReserv = historySize >> 2;
-
- sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
-
- p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
- p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
-
- /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
-
- if (LzInWindow_Create(p, sizeReserv, alloc))
- {
- UInt32 newCyclicBufferSize = historySize + 1;
- UInt32 hs;
- p->matchMaxLen = matchMaxLen;
- {
- p->fixedHashSize = 0;
- if (p->numHashBytes == 2)
- hs = (1 << 16) - 1;
- else
- {
- hs = historySize;
- if (hs > p->expectedDataSize)
- hs = (UInt32)p->expectedDataSize;
- if (hs != 0)
- hs--;
- hs |= (hs >> 1);
- hs |= (hs >> 2);
- hs |= (hs >> 4);
- hs |= (hs >> 8);
- hs >>= 1;
- hs |= 0xFFFF; /* don't change it! It's required for Deflate */
- if (hs > (1 << 24))
- {
- if (p->numHashBytes == 3)
- hs = (1 << 24) - 1;
- else
- hs >>= 1;
- /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */
- }
- }
- p->hashMask = hs;
- hs++;
- if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
- if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
- if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
- hs += p->fixedHashSize;
- }
-
- {
- size_t newSize;
- size_t numSons;
- p->historySize = historySize;
- p->hashSizeSum = hs;
- p->cyclicBufferSize = newCyclicBufferSize;
-
- numSons = newCyclicBufferSize;
- if (p->btMode)
- numSons <<= 1;
- newSize = hs + numSons;
-
- if (p->hash && p->numRefs == newSize)
- return 1;
-
- MatchFinder_FreeThisClassMemory(p, alloc);
- p->numRefs = newSize;
- p->hash = AllocRefs(newSize, alloc);
-
- if (p->hash)
- {
- p->son = p->hash + p->hashSizeSum;
- return 1;
- }
- }
- }
-
- MatchFinder_Free(p, alloc);
- return 0;
-}
-
-static void MatchFinder_SetLimits(CMatchFinder *p)
-{
- UInt32 limit = kMaxValForNormalize - p->pos;
- UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
-
- if (limit2 < limit)
- limit = limit2;
- limit2 = p->streamPos - p->pos;
-
- if (limit2 <= p->keepSizeAfter)
- {
- if (limit2 > 0)
- limit2 = 1;
- }
- else
- limit2 -= p->keepSizeAfter;
-
- if (limit2 < limit)
- limit = limit2;
-
- {
- UInt32 lenLimit = p->streamPos - p->pos;
- if (lenLimit > p->matchMaxLen)
- lenLimit = p->matchMaxLen;
- p->lenLimit = lenLimit;
- }
- p->posLimit = p->pos + limit;
-}
-
-
-void MatchFinder_Init_LowHash(CMatchFinder *p)
-{
- size_t i;
- CLzRef *items = p->hash;
- size_t numItems = p->fixedHashSize;
- for (i = 0; i < numItems; i++)
- items[i] = kEmptyHashValue;
-}
-
-
-void MatchFinder_Init_HighHash(CMatchFinder *p)
-{
- size_t i;
- CLzRef *items = p->hash + p->fixedHashSize;
- size_t numItems = (size_t)p->hashMask + 1;
- for (i = 0; i < numItems; i++)
- items[i] = kEmptyHashValue;
-}
-
-
-void MatchFinder_Init_3(CMatchFinder *p, int readData)
-{
- p->cyclicBufferPos = 0;
- p->buffer = p->bufferBase;
- p->pos =
- p->streamPos = p->cyclicBufferSize;
- p->result = SZ_OK;
- p->streamEndWasReached = 0;
-
- if (readData)
- MatchFinder_ReadBlock(p);
-
- MatchFinder_SetLimits(p);
-}
-
-
-void MatchFinder_Init(CMatchFinder *p)
-{
- MatchFinder_Init_HighHash(p);
- MatchFinder_Init_LowHash(p);
- MatchFinder_Init_3(p, True);
-}
-
-
-static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
-{
- return (p->pos - p->historySize - 1) & kNormalizeMask;
-}
-
-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems)
-{
- size_t i;
- for (i = 0; i < numItems; i++)
- {
- UInt32 value = items[i];
- if (value <= subValue)
- value = kEmptyHashValue;
- else
- value -= subValue;
- items[i] = value;
- }
-}
-
-static void MatchFinder_Normalize(CMatchFinder *p)
-{
- UInt32 subValue = MatchFinder_GetSubValue(p);
- MatchFinder_Normalize3(subValue, p->hash, p->numRefs);
- MatchFinder_ReduceOffsets(p, subValue);
-}
-
-
-MY_NO_INLINE
-static void MatchFinder_CheckLimits(CMatchFinder *p)
-{
- if (p->pos == kMaxValForNormalize)
- MatchFinder_Normalize(p);
- if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
- MatchFinder_CheckAndMoveAndRead(p);
- if (p->cyclicBufferPos == p->cyclicBufferSize)
- p->cyclicBufferPos = 0;
- MatchFinder_SetLimits(p);
-}
-
-
-/*
- (lenLimit > maxLen)
-*/
-MY_FORCE_INLINE
-static UInt32 * Hc_GetMatchesSpec(unsigned lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
- UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
- UInt32 *distances, unsigned maxLen)
-{
- /*
- son[_cyclicBufferPos] = curMatch;
- for (;;)
- {
- UInt32 delta = pos - curMatch;
- if (cutValue-- == 0 || delta >= _cyclicBufferSize)
- return distances;
- {
- const Byte *pb = cur - delta;
- curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
- if (pb[maxLen] == cur[maxLen] && *pb == *cur)
- {
- UInt32 len = 0;
- while (++len != lenLimit)
- if (pb[len] != cur[len])
- break;
- if (maxLen < len)
- {
- maxLen = len;
- *distances++ = len;
- *distances++ = delta - 1;
- if (len == lenLimit)
- return distances;
- }
- }
- }
- }
- */
-
- const Byte *lim = cur + lenLimit;
- son[_cyclicBufferPos] = curMatch;
- do
- {
- UInt32 delta = pos - curMatch;
- if (delta >= _cyclicBufferSize)
- break;
- {
- ptrdiff_t diff;
- curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
- diff = (ptrdiff_t)0 - delta;
- if (cur[maxLen] == cur[maxLen + diff])
- {
- const Byte *c = cur;
- while (*c == c[diff])
- {
- if (++c == lim)
- {
- distances[0] = (UInt32)(lim - cur);
- distances[1] = delta - 1;
- return distances + 2;
- }
- }
- {
- unsigned len = (unsigned)(c - cur);
- if (maxLen < len)
- {
- maxLen = len;
- distances[0] = (UInt32)len;
- distances[1] = delta - 1;
- distances += 2;
- }
- }
- }
- }
- }
- while (--cutValue);
-
- return distances;
-}
-
-
-MY_FORCE_INLINE
-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
- UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
- UInt32 *distances, UInt32 maxLen)
-{
- CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1;
- CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
- unsigned len0 = 0, len1 = 0;
- for (;;)
- {
- UInt32 delta = pos - curMatch;
- if (cutValue-- == 0 || delta >= _cyclicBufferSize)
- {
- *ptr0 = *ptr1 = kEmptyHashValue;
- return distances;
- }
- {
- CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
- const Byte *pb = cur - delta;
- unsigned len = (len0 < len1 ? len0 : len1);
- UInt32 pair0 = pair[0];
- if (pb[len] == cur[len])
- {
- if (++len != lenLimit && pb[len] == cur[len])
- while (++len != lenLimit)
- if (pb[len] != cur[len])
- break;
- if (maxLen < len)
- {
- maxLen = (UInt32)len;
- *distances++ = (UInt32)len;
- *distances++ = delta - 1;
- if (len == lenLimit)
- {
- *ptr1 = pair0;
- *ptr0 = pair[1];
- return distances;
- }
- }
- }
- if (pb[len] < cur[len])
- {
- *ptr1 = curMatch;
- ptr1 = pair + 1;
- curMatch = *ptr1;
- len1 = len;
- }
- else
- {
- *ptr0 = curMatch;
- ptr0 = pair;
- curMatch = *ptr0;
- len0 = len;
- }
- }
- }
-}
-
-static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
- UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
-{
- CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1;
- CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
- unsigned len0 = 0, len1 = 0;
- for (;;)
- {
- UInt32 delta = pos - curMatch;
- if (cutValue-- == 0 || delta >= _cyclicBufferSize)
- {
- *ptr0 = *ptr1 = kEmptyHashValue;
- return;
- }
- {
- CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
- const Byte *pb = cur - delta;
- unsigned len = (len0 < len1 ? len0 : len1);
- if (pb[len] == cur[len])
- {
- while (++len != lenLimit)
- if (pb[len] != cur[len])
- break;
- {
- if (len == lenLimit)
- {
- *ptr1 = pair[0];
- *ptr0 = pair[1];
- return;
- }
- }
- }
- if (pb[len] < cur[len])
- {
- *ptr1 = curMatch;
- ptr1 = pair + 1;
- curMatch = *ptr1;
- len1 = len;
- }
- else
- {
- *ptr0 = curMatch;
- ptr0 = pair;
- curMatch = *ptr0;
- len0 = len;
- }
- }
- }
-}
-
-#define MOVE_POS \
- ++p->cyclicBufferPos; \
- p->buffer++; \
- if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
-
-#define MOVE_POS_RET MOVE_POS return (UInt32)offset;
-
-static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
-
-#define GET_MATCHES_HEADER2(minLen, ret_op) \
- unsigned lenLimit; UInt32 hv; const Byte *cur; UInt32 curMatch; \
- lenLimit = (unsigned)p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
- cur = p->buffer;
-
-#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
-#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue)
-
-#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
-
-#define GET_MATCHES_FOOTER(offset, maxLen) \
- offset = (unsigned)(GetMatchesSpec1((UInt32)lenLimit, curMatch, MF_PARAMS(p), \
- distances + offset, (UInt32)maxLen) - distances); MOVE_POS_RET;
-
-#define SKIP_FOOTER \
- SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
-
-#define UPDATE_maxLen { \
- ptrdiff_t diff = (ptrdiff_t)0 - d2; \
- const Byte *c = cur + maxLen; \
- const Byte *lim = cur + lenLimit; \
- for (; c != lim; c++) if (*(c + diff) != *c) break; \
- maxLen = (unsigned)(c - cur); }
-
-static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
-{
- unsigned offset;
- GET_MATCHES_HEADER(2)
- HASH2_CALC;
- curMatch = p->hash[hv];
- p->hash[hv] = p->pos;
- offset = 0;
- GET_MATCHES_FOOTER(offset, 1)
-}
-
-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
-{
- unsigned offset;
- GET_MATCHES_HEADER(3)
- HASH_ZIP_CALC;
- curMatch = p->hash[hv];
- p->hash[hv] = p->pos;
- offset = 0;
- GET_MATCHES_FOOTER(offset, 2)
-}
-
-static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
-{
- UInt32 h2, d2, pos;
- unsigned maxLen, offset;
- UInt32 *hash;
- GET_MATCHES_HEADER(3)
-
- HASH3_CALC;
-
- hash = p->hash;
- pos = p->pos;
-
- d2 = pos - hash[h2];
-
- curMatch = (hash + kFix3HashSize)[hv];
-
- hash[h2] = pos;
- (hash + kFix3HashSize)[hv] = pos;
-
- maxLen = 2;
- offset = 0;
-
- if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
- {
- UPDATE_maxLen
- distances[0] = (UInt32)maxLen;
- distances[1] = d2 - 1;
- offset = 2;
- if (maxLen == lenLimit)
- {
- SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p));
- MOVE_POS_RET;
- }
- }
-
- GET_MATCHES_FOOTER(offset, maxLen)
-}
-
-static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
-{
- UInt32 h2, h3, d2, d3, pos;
- unsigned maxLen, offset;
- UInt32 *hash;
- GET_MATCHES_HEADER(4)
-
- HASH4_CALC;
-
- hash = p->hash;
- pos = p->pos;
-
- d2 = pos - hash [h2];
- d3 = pos - (hash + kFix3HashSize)[h3];
-
- curMatch = (hash + kFix4HashSize)[hv];
-
- hash [h2] = pos;
- (hash + kFix3HashSize)[h3] = pos;
- (hash + kFix4HashSize)[hv] = pos;
-
- maxLen = 0;
- offset = 0;
-
- if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
- {
- maxLen = 2;
- distances[0] = 2;
- distances[1] = d2 - 1;
- offset = 2;
- }
-
- if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
- {
- maxLen = 3;
- distances[(size_t)offset + 1] = d3 - 1;
- offset += 2;
- d2 = d3;
- }
-
- if (offset != 0)
- {
- UPDATE_maxLen
- distances[(size_t)offset - 2] = (UInt32)maxLen;
- if (maxLen == lenLimit)
- {
- SkipMatchesSpec((UInt32)lenLimit, curMatch, MF_PARAMS(p));
- MOVE_POS_RET;
- }
- }
-
- if (maxLen < 3)
- maxLen = 3;
-
- GET_MATCHES_FOOTER(offset, maxLen)
-}
-
-/*
-static UInt32 Bt5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
-{
- UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos;
- UInt32 *hash;
- GET_MATCHES_HEADER(5)
-
- HASH5_CALC;
-
- hash = p->hash;
- pos = p->pos;
-
- d2 = pos - hash [h2];
- d3 = pos - (hash + kFix3HashSize)[h3];
- d4 = pos - (hash + kFix4HashSize)[h4];
-
- curMatch = (hash + kFix5HashSize)[hv];
-
- hash [h2] = pos;
- (hash + kFix3HashSize)[h3] = pos;
- (hash + kFix4HashSize)[h4] = pos;
- (hash + kFix5HashSize)[hv] = pos;
-
- maxLen = 0;
- offset = 0;
-
- if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
- {
- distances[0] = maxLen = 2;
- distances[1] = d2 - 1;
- offset = 2;
- if (*(cur - d2 + 2) == cur[2])
- distances[0] = maxLen = 3;
- else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
- {
- distances[2] = maxLen = 3;
- distances[3] = d3 - 1;
- offset = 4;
- d2 = d3;
- }
- }
- else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
- {
- distances[0] = maxLen = 3;
- distances[1] = d3 - 1;
- offset = 2;
- d2 = d3;
- }
-
- if (d2 != d4 && d4 < p->cyclicBufferSize
- && *(cur - d4) == *cur
- && *(cur - d4 + 3) == *(cur + 3))
- {
- maxLen = 4;
- distances[(size_t)offset + 1] = d4 - 1;
- offset += 2;
- d2 = d4;
- }
-
- if (offset != 0)
- {
- UPDATE_maxLen
- distances[(size_t)offset - 2] = maxLen;
- if (maxLen == lenLimit)
- {
- SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
- MOVE_POS_RET;
- }
- }
-
- if (maxLen < 4)
- maxLen = 4;
-
- GET_MATCHES_FOOTER(offset, maxLen)
-}
-*/
-
-static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
-{
- UInt32 h2, h3, d2, d3, pos;
- unsigned maxLen, offset;
- UInt32 *hash;
- GET_MATCHES_HEADER(4)
-
- HASH4_CALC;
-
- hash = p->hash;
- pos = p->pos;
-
- d2 = pos - hash [h2];
- d3 = pos - (hash + kFix3HashSize)[h3];
- curMatch = (hash + kFix4HashSize)[hv];
-
- hash [h2] = pos;
- (hash + kFix3HashSize)[h3] = pos;
- (hash + kFix4HashSize)[hv] = pos;
-
- maxLen = 0;
- offset = 0;
-
- if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
- {
- maxLen = 2;
- distances[0] = 2;
- distances[1] = d2 - 1;
- offset = 2;
- }
-
- if (d2 != d3 && d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
- {
- maxLen = 3;
- distances[(size_t)offset + 1] = d3 - 1;
- offset += 2;
- d2 = d3;
- }
-
- if (offset != 0)
- {
- UPDATE_maxLen
- distances[(size_t)offset - 2] = (UInt32)maxLen;
- if (maxLen == lenLimit)
- {
- p->son[p->cyclicBufferPos] = curMatch;
- MOVE_POS_RET;
- }
- }
-
- if (maxLen < 3)
- maxLen = 3;
-
- offset = (unsigned)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
- distances + offset, maxLen) - (distances));
- MOVE_POS_RET
-}
-
-/*
-static UInt32 Hc5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
-{
- UInt32 h2, h3, h4, d2, d3, d4, maxLen, offset, pos
- UInt32 *hash;
- GET_MATCHES_HEADER(5)
-
- HASH5_CALC;
-
- hash = p->hash;
- pos = p->pos;
-
- d2 = pos - hash [h2];
- d3 = pos - (hash + kFix3HashSize)[h3];
- d4 = pos - (hash + kFix4HashSize)[h4];
-
- curMatch = (hash + kFix5HashSize)[hv];
-
- hash [h2] = pos;
- (hash + kFix3HashSize)[h3] = pos;
- (hash + kFix4HashSize)[h4] = pos;
- (hash + kFix5HashSize)[hv] = pos;
-
- maxLen = 0;
- offset = 0;
-
- if (d2 < p->cyclicBufferSize && *(cur - d2) == *cur)
- {
- distances[0] = maxLen = 2;
- distances[1] = d2 - 1;
- offset = 2;
- if (*(cur - d2 + 2) == cur[2])
- distances[0] = maxLen = 3;
- else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
- {
- distances[2] = maxLen = 3;
- distances[3] = d3 - 1;
- offset = 4;
- d2 = d3;
- }
- }
- else if (d3 < p->cyclicBufferSize && *(cur - d3) == *cur)
- {
- distances[0] = maxLen = 3;
- distances[1] = d3 - 1;
- offset = 2;
- d2 = d3;
- }
-
- if (d2 != d4 && d4 < p->cyclicBufferSize
- && *(cur - d4) == *cur
- && *(cur - d4 + 3) == *(cur + 3))
- {
- maxLen = 4;
- distances[(size_t)offset + 1] = d4 - 1;
- offset += 2;
- d2 = d4;
- }
-
- if (offset != 0)
- {
- UPDATE_maxLen
- distances[(size_t)offset - 2] = maxLen;
- if (maxLen == lenLimit)
- {
- p->son[p->cyclicBufferPos] = curMatch;
- MOVE_POS_RET;
- }
- }
-
- if (maxLen < 4)
- maxLen = 4;
-
- offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
- distances + offset, maxLen) - (distances));
- MOVE_POS_RET
-}
-*/
-
-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
-{
- unsigned offset;
- GET_MATCHES_HEADER(3)
- HASH_ZIP_CALC;
- curMatch = p->hash[hv];
- p->hash[hv] = p->pos;
- offset = (unsigned)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
- distances, 2) - (distances));
- MOVE_POS_RET
-}
-
-static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
-{
- do
- {
- SKIP_HEADER(2)
- HASH2_CALC;
- curMatch = p->hash[hv];
- p->hash[hv] = p->pos;
- SKIP_FOOTER
- }
- while (--num != 0);
-}
-
-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
-{
- do
- {
- SKIP_HEADER(3)
- HASH_ZIP_CALC;
- curMatch = p->hash[hv];
- p->hash[hv] = p->pos;
- SKIP_FOOTER
- }
- while (--num != 0);
-}
-
-static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
-{
- do
- {
- UInt32 h2;
- UInt32 *hash;
- SKIP_HEADER(3)
- HASH3_CALC;
- hash = p->hash;
- curMatch = (hash + kFix3HashSize)[hv];
- hash[h2] =
- (hash + kFix3HashSize)[hv] = p->pos;
- SKIP_FOOTER
- }
- while (--num != 0);
-}
-
-static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
-{
- do
- {
- UInt32 h2, h3;
- UInt32 *hash;
- SKIP_HEADER(4)
- HASH4_CALC;
- hash = p->hash;
- curMatch = (hash + kFix4HashSize)[hv];
- hash [h2] =
- (hash + kFix3HashSize)[h3] =
- (hash + kFix4HashSize)[hv] = p->pos;
- SKIP_FOOTER
- }
- while (--num != 0);
-}
-
-/*
-static void Bt5_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
-{
- do
- {
- UInt32 h2, h3, h4;
- UInt32 *hash;
- SKIP_HEADER(5)
- HASH5_CALC;
- hash = p->hash;
- curMatch = (hash + kFix5HashSize)[hv];
- hash [h2] =
- (hash + kFix3HashSize)[h3] =
- (hash + kFix4HashSize)[h4] =
- (hash + kFix5HashSize)[hv] = p->pos;
- SKIP_FOOTER
- }
- while (--num != 0);
-}
-*/
-
-static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
-{
- do
- {
- UInt32 h2, h3;
- UInt32 *hash;
- SKIP_HEADER(4)
- HASH4_CALC;
- hash = p->hash;
- curMatch = (hash + kFix4HashSize)[hv];
- hash [h2] =
- (hash + kFix3HashSize)[h3] =
- (hash + kFix4HashSize)[hv] = p->pos;
- p->son[p->cyclicBufferPos] = curMatch;
- MOVE_POS
- }
- while (--num != 0);
-}
-
-/*
-static void Hc5_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
-{
- do
- {
- UInt32 h2, h3, h4;
- UInt32 *hash;
- SKIP_HEADER(5)
- HASH5_CALC;
- hash = p->hash;
- curMatch = hash + kFix5HashSize)[hv];
- hash [h2] =
- (hash + kFix3HashSize)[h3] =
- (hash + kFix4HashSize)[h4] =
- (hash + kFix5HashSize)[hv] = p->pos;
- p->son[p->cyclicBufferPos] = curMatch;
- MOVE_POS
- }
- while (--num != 0);
-}
-*/
-
-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
-{
- do
- {
- SKIP_HEADER(3)
- HASH_ZIP_CALC;
- curMatch = p->hash[hv];
- p->hash[hv] = p->pos;
- p->son[p->cyclicBufferPos] = curMatch;
- MOVE_POS
- }
- while (--num != 0);
-}
-
-void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
-{
- vTable->Init = (Mf_Init_Func)MatchFinder_Init;
- vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
- vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
- if (!p->btMode)
- {
- /* if (p->numHashBytes <= 4) */
- {
- vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
- vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
- }
- /*
- else
- {
- vTable->GetMatches = (Mf_GetMatches_Func)Hc5_MatchFinder_GetMatches;
- vTable->Skip = (Mf_Skip_Func)Hc5_MatchFinder_Skip;
- }
- */
- }
- else if (p->numHashBytes == 2)
- {
- vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
- vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
- }
- else if (p->numHashBytes == 3)
- {
- vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
- vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
- }
- else /* if (p->numHashBytes == 4) */
- {
- vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
- vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
- }
- /*
- else
- {
- vTable->GetMatches = (Mf_GetMatches_Func)Bt5_MatchFinder_GetMatches;
- vTable->Skip = (Mf_Skip_Func)Bt5_MatchFinder_Skip;
- }
- */
-}
+/* LzFind.c -- Match finder for LZ algorithms
+2023-03-14 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+// #include <stdio.h>
+
+#include "CpuArch.h"
+#include "LzFind.h"
+#include "LzHash.h"
+
+#define kBlockMoveAlign (1 << 7) // alignment for memmove()
+#define kBlockSizeAlign (1 << 16) // alignment for block allocation
+#define kBlockSizeReserveMin (1 << 24) // it's 1/256 from 4 GB dictinary
+
+#define kEmptyHashValue 0
+
+#define kMaxValForNormalize ((UInt32)0)
+// #define kMaxValForNormalize ((UInt32)(1 << 20) + 0xfff) // for debug
+
+// #define kNormalizeAlign (1 << 7) // alignment for speculated accesses
+
+#define GET_AVAIL_BYTES(p) \
+ Inline_MatchFinder_GetNumAvailableBytes(p)
+
+
+// #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
+#define kFix5HashSize kFix4HashSize
+
+/*
+ HASH2_CALC:
+ if (hv) match, then cur[0] and cur[1] also match
+*/
+#define HASH2_CALC hv = GetUi16(cur);
+
+// (crc[0 ... 255] & 0xFF) provides one-to-one correspondence to [0 ... 255]
+
+/*
+ HASH3_CALC:
+ if (cur[0]) and (h2) match, then cur[1] also match
+ if (cur[0]) and (hv) match, then cur[1] and cur[2] also match
+*/
+#define HASH3_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ h2 = temp & (kHash2Size - 1); \
+ hv = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
+
+#define HASH4_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ h2 = temp & (kHash2Size - 1); \
+ temp ^= ((UInt32)cur[2] << 8); \
+ h3 = temp & (kHash3Size - 1); \
+ hv = (temp ^ (p->crc[cur[3]] << kLzHash_CrcShift_1)) & p->hashMask; }
+
+#define HASH5_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ h2 = temp & (kHash2Size - 1); \
+ temp ^= ((UInt32)cur[2] << 8); \
+ h3 = temp & (kHash3Size - 1); \
+ temp ^= (p->crc[cur[3]] << kLzHash_CrcShift_1); \
+ /* h4 = temp & p->hash4Mask; */ /* (kHash4Size - 1); */ \
+ hv = (temp ^ (p->crc[cur[4]] << kLzHash_CrcShift_2)) & p->hashMask; }
+
+#define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
+
+
+static void LzInWindow_Free(CMatchFinder *p, ISzAllocPtr alloc)
+{
+ // if (!p->directInput)
+ {
+ ISzAlloc_Free(alloc, p->bufBase);
+ p->bufBase = NULL;
+ }
+}
+
+
+static int LzInWindow_Create2(CMatchFinder *p, UInt32 blockSize, ISzAllocPtr alloc)
+{
+ if (blockSize == 0)
+ return 0;
+ if (!p->bufBase || p->blockSize != blockSize)
+ {
+ // size_t blockSizeT;
+ LzInWindow_Free(p, alloc);
+ p->blockSize = blockSize;
+ // blockSizeT = blockSize;
+
+ // printf("\nblockSize = 0x%x\n", blockSize);
+ /*
+ #if defined _WIN64
+ // we can allocate 4GiB, but still use UInt32 for (p->blockSize)
+ // we use UInt32 type for (p->blockSize), because
+ // we don't want to wrap over 4 GiB,
+ // when we use (p->streamPos - p->pos) that is UInt32.
+ if (blockSize >= (UInt32)0 - (UInt32)kBlockSizeAlign)
+ {
+ blockSizeT = ((size_t)1 << 32);
+ printf("\nchanged to blockSizeT = 4GiB\n");
+ }
+ #endif
+ */
+
+ p->bufBase = (Byte *)ISzAlloc_Alloc(alloc, blockSize);
+ // printf("\nbufferBase = %p\n", p->bufBase);
+ // return 0; // for debug
+ }
+ return (p->bufBase != NULL);
+}
+
+static const Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
+
+static UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return GET_AVAIL_BYTES(p); }
+
+
+Z7_NO_INLINE
+static void MatchFinder_ReadBlock(CMatchFinder *p)
+{
+ if (p->streamEndWasReached || p->result != SZ_OK)
+ return;
+
+ /* We use (p->streamPos - p->pos) value.
+ (p->streamPos < p->pos) is allowed. */
+
+ if (p->directInput)
+ {
+ UInt32 curSize = 0xFFFFFFFF - GET_AVAIL_BYTES(p);
+ if (curSize > p->directInputRem)
+ curSize = (UInt32)p->directInputRem;
+ p->streamPos += curSize;
+ p->directInputRem -= curSize;
+ if (p->directInputRem == 0)
+ p->streamEndWasReached = 1;
+ return;
+ }
+
+ for (;;)
+ {
+ const Byte *dest = p->buffer + GET_AVAIL_BYTES(p);
+ size_t size = (size_t)(p->bufBase + p->blockSize - dest);
+ if (size == 0)
+ {
+ /* we call ReadBlock() after NeedMove() and MoveBlock().
+ NeedMove() and MoveBlock() povide more than (keepSizeAfter)
+ to the end of (blockSize).
+ So we don't execute this branch in normal code flow.
+ We can go here, if we will call ReadBlock() before NeedMove(), MoveBlock().
+ */
+ // p->result = SZ_ERROR_FAIL; // we can show error here
+ return;
+ }
+
+ // #define kRead 3
+ // if (size > kRead) size = kRead; // for debug
+
+ /*
+ // we need cast (Byte *)dest.
+ #ifdef __clang__
+ #pragma GCC diagnostic ignored "-Wcast-qual"
+ #endif
+ */
+ p->result = ISeqInStream_Read(p->stream,
+ p->bufBase + (dest - p->bufBase), &size);
+ if (p->result != SZ_OK)
+ return;
+ if (size == 0)
+ {
+ p->streamEndWasReached = 1;
+ return;
+ }
+ p->streamPos += (UInt32)size;
+ if (GET_AVAIL_BYTES(p) > p->keepSizeAfter)
+ return;
+ /* here and in another (p->keepSizeAfter) checks we keep on 1 byte more than was requested by Create() function
+ (GET_AVAIL_BYTES(p) >= p->keepSizeAfter) - minimal required size */
+ }
+
+ // on exit: (p->result != SZ_OK || p->streamEndWasReached || GET_AVAIL_BYTES(p) > p->keepSizeAfter)
+}
+
+
+
+Z7_NO_INLINE
+void MatchFinder_MoveBlock(CMatchFinder *p)
+{
+ const size_t offset = (size_t)(p->buffer - p->bufBase) - p->keepSizeBefore;
+ const size_t keepBefore = (offset & (kBlockMoveAlign - 1)) + p->keepSizeBefore;
+ p->buffer = p->bufBase + keepBefore;
+ memmove(p->bufBase,
+ p->bufBase + (offset & ~((size_t)kBlockMoveAlign - 1)),
+ keepBefore + (size_t)GET_AVAIL_BYTES(p));
+}
+
+/* We call MoveBlock() before ReadBlock().
+ So MoveBlock() can be wasteful operation, if the whole input data
+ can fit in current block even without calling MoveBlock().
+ in important case where (dataSize <= historySize)
+ condition (p->blockSize > dataSize + p->keepSizeAfter) is met
+ So there is no MoveBlock() in that case case.
+*/
+
+int MatchFinder_NeedMove(CMatchFinder *p)
+{
+ if (p->directInput)
+ return 0;
+ if (p->streamEndWasReached || p->result != SZ_OK)
+ return 0;
+ return ((size_t)(p->bufBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
+}
+
+void MatchFinder_ReadIfRequired(CMatchFinder *p)
+{
+ if (p->keepSizeAfter >= GET_AVAIL_BYTES(p))
+ MatchFinder_ReadBlock(p);
+}
+
+
+
+static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
+{
+ p->cutValue = 32;
+ p->btMode = 1;
+ p->numHashBytes = 4;
+ p->numHashBytes_Min = 2;
+ p->numHashOutBits = 0;
+ p->bigHash = 0;
+}
+
+#define kCrcPoly 0xEDB88320
+
+void MatchFinder_Construct(CMatchFinder *p)
+{
+ unsigned i;
+ p->buffer = NULL;
+ p->bufBase = NULL;
+ p->directInput = 0;
+ p->stream = NULL;
+ p->hash = NULL;
+ p->expectedDataSize = (UInt64)(Int64)-1;
+ MatchFinder_SetDefaultSettings(p);
+
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = (UInt32)i;
+ unsigned j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (kCrcPoly & ((UInt32)0 - (r & 1)));
+ p->crc[i] = r;
+ }
+}
+
+#undef kCrcPoly
+
+static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->hash);
+ p->hash = NULL;
+}
+
+void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc)
+{
+ MatchFinder_FreeThisClassMemory(p, alloc);
+ LzInWindow_Free(p, alloc);
+}
+
+static CLzRef* AllocRefs(size_t num, ISzAllocPtr alloc)
+{
+ const size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
+ if (sizeInBytes / sizeof(CLzRef) != num)
+ return NULL;
+ return (CLzRef *)ISzAlloc_Alloc(alloc, sizeInBytes);
+}
+
+#if (kBlockSizeReserveMin < kBlockSizeAlign * 2)
+ #error Stop_Compiling_Bad_Reserve
+#endif
+
+
+
+static UInt32 GetBlockSize(CMatchFinder *p, UInt32 historySize)
+{
+ UInt32 blockSize = (p->keepSizeBefore + p->keepSizeAfter);
+ /*
+ if (historySize > kMaxHistorySize)
+ return 0;
+ */
+ // printf("\nhistorySize == 0x%x\n", historySize);
+
+ if (p->keepSizeBefore < historySize || blockSize < p->keepSizeBefore) // if 32-bit overflow
+ return 0;
+
+ {
+ const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)kBlockSizeAlign;
+ const UInt32 rem = kBlockSizeMax - blockSize;
+ const UInt32 reserve = (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2))
+ + (1 << 12) + kBlockMoveAlign + kBlockSizeAlign; // do not overflow 32-bit here
+ if (blockSize >= kBlockSizeMax
+ || rem < kBlockSizeReserveMin) // we reject settings that will be slow
+ return 0;
+ if (reserve >= rem)
+ blockSize = kBlockSizeMax;
+ else
+ {
+ blockSize += reserve;
+ blockSize &= ~(UInt32)(kBlockSizeAlign - 1);
+ }
+ }
+ // printf("\n LzFind_blockSize = %x\n", blockSize);
+ // printf("\n LzFind_blockSize = %d\n", blockSize >> 20);
+ return blockSize;
+}
+
+
+// input is historySize
+static UInt32 MatchFinder_GetHashMask2(CMatchFinder *p, UInt32 hs)
+{
+ if (p->numHashBytes == 2)
+ return (1 << 16) - 1;
+ if (hs != 0)
+ hs--;
+ hs |= (hs >> 1);
+ hs |= (hs >> 2);
+ hs |= (hs >> 4);
+ hs |= (hs >> 8);
+ // we propagated 16 bits in (hs). Low 16 bits must be set later
+ if (hs >= (1 << 24))
+ {
+ if (p->numHashBytes == 3)
+ hs = (1 << 24) - 1;
+ /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */
+ }
+ // (hash_size >= (1 << 16)) : Required for (numHashBytes > 2)
+ hs |= (1 << 16) - 1; /* don't change it! */
+ // bt5: we adjust the size with recommended minimum size
+ if (p->numHashBytes >= 5)
+ hs |= (256 << kLzHash_CrcShift_2) - 1;
+ return hs;
+}
+
+// input is historySize
+static UInt32 MatchFinder_GetHashMask(CMatchFinder *p, UInt32 hs)
+{
+ if (p->numHashBytes == 2)
+ return (1 << 16) - 1;
+ if (hs != 0)
+ hs--;
+ hs |= (hs >> 1);
+ hs |= (hs >> 2);
+ hs |= (hs >> 4);
+ hs |= (hs >> 8);
+ // we propagated 16 bits in (hs). Low 16 bits must be set later
+ hs >>= 1;
+ if (hs >= (1 << 24))
+ {
+ if (p->numHashBytes == 3)
+ hs = (1 << 24) - 1;
+ else
+ hs >>= 1;
+ /* if (bigHash) mode, GetHeads4b() in LzFindMt.c needs (hs >= ((1 << 24) - 1))) */
+ }
+ // (hash_size >= (1 << 16)) : Required for (numHashBytes > 2)
+ hs |= (1 << 16) - 1; /* don't change it! */
+ // bt5: we adjust the size with recommended minimum size
+ if (p->numHashBytes >= 5)
+ hs |= (256 << kLzHash_CrcShift_2) - 1;
+ return hs;
+}
+
+
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+ ISzAllocPtr alloc)
+{
+ /* we need one additional byte in (p->keepSizeBefore),
+ since we use MoveBlock() after (p->pos++) and before dictionary using */
+ // keepAddBufferBefore = (UInt32)0xFFFFFFFF - (1 << 22); // for debug
+ p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
+
+ keepAddBufferAfter += matchMaxLen;
+ /* we need (p->keepSizeAfter >= p->numHashBytes) */
+ if (keepAddBufferAfter < p->numHashBytes)
+ keepAddBufferAfter = p->numHashBytes;
+ // keepAddBufferAfter -= 2; // for debug
+ p->keepSizeAfter = keepAddBufferAfter;
+
+ if (p->directInput)
+ p->blockSize = 0;
+ if (p->directInput || LzInWindow_Create2(p, GetBlockSize(p, historySize), alloc))
+ {
+ size_t hashSizeSum;
+ {
+ UInt32 hs;
+ UInt32 hsCur;
+
+ if (p->numHashOutBits != 0)
+ {
+ unsigned numBits = p->numHashOutBits;
+ const unsigned nbMax =
+ (p->numHashBytes == 2 ? 16 :
+ (p->numHashBytes == 3 ? 24 : 32));
+ if (numBits > nbMax)
+ numBits = nbMax;
+ if (numBits >= 32)
+ hs = (UInt32)0 - 1;
+ else
+ hs = ((UInt32)1 << numBits) - 1;
+ // (hash_size >= (1 << 16)) : Required for (numHashBytes > 2)
+ hs |= (1 << 16) - 1; /* don't change it! */
+ if (p->numHashBytes >= 5)
+ hs |= (256 << kLzHash_CrcShift_2) - 1;
+ {
+ const UInt32 hs2 = MatchFinder_GetHashMask2(p, historySize);
+ if (hs > hs2)
+ hs = hs2;
+ }
+ hsCur = hs;
+ if (p->expectedDataSize < historySize)
+ {
+ const UInt32 hs2 = MatchFinder_GetHashMask2(p, (UInt32)p->expectedDataSize);
+ if (hsCur > hs2)
+ hsCur = hs2;
+ }
+ }
+ else
+ {
+ hs = MatchFinder_GetHashMask(p, historySize);
+ hsCur = hs;
+ if (p->expectedDataSize < historySize)
+ {
+ hsCur = MatchFinder_GetHashMask(p, (UInt32)p->expectedDataSize);
+ if (hsCur > hs) // is it possible?
+ hsCur = hs;
+ }
+ }
+
+ p->hashMask = hsCur;
+
+ hashSizeSum = hs;
+ hashSizeSum++;
+ if (hashSizeSum < hs)
+ return 0;
+ {
+ UInt32 fixedHashSize = 0;
+ if (p->numHashBytes > 2 && p->numHashBytes_Min <= 2) fixedHashSize += kHash2Size;
+ if (p->numHashBytes > 3 && p->numHashBytes_Min <= 3) fixedHashSize += kHash3Size;
+ // if (p->numHashBytes > 4) p->fixedHashSize += hs4; // kHash4Size;
+ hashSizeSum += fixedHashSize;
+ p->fixedHashSize = fixedHashSize;
+ }
+ }
+
+ p->matchMaxLen = matchMaxLen;
+
+ {
+ size_t newSize;
+ size_t numSons;
+ const UInt32 newCyclicBufferSize = historySize + 1; // do not change it
+ p->historySize = historySize;
+ p->cyclicBufferSize = newCyclicBufferSize; // it must be = (historySize + 1)
+
+ numSons = newCyclicBufferSize;
+ if (p->btMode)
+ numSons <<= 1;
+ newSize = hashSizeSum + numSons;
+
+ if (numSons < newCyclicBufferSize || newSize < numSons)
+ return 0;
+
+ // aligned size is not required here, but it can be better for some loops
+ #define NUM_REFS_ALIGN_MASK 0xF
+ newSize = (newSize + NUM_REFS_ALIGN_MASK) & ~(size_t)NUM_REFS_ALIGN_MASK;
+
+ // 22.02: we don't reallocate buffer, if old size is enough
+ if (p->hash && p->numRefs >= newSize)
+ return 1;
+
+ MatchFinder_FreeThisClassMemory(p, alloc);
+ p->numRefs = newSize;
+ p->hash = AllocRefs(newSize, alloc);
+
+ if (p->hash)
+ {
+ p->son = p->hash + hashSizeSum;
+ return 1;
+ }
+ }
+ }
+
+ MatchFinder_Free(p, alloc);
+ return 0;
+}
+
+
+static void MatchFinder_SetLimits(CMatchFinder *p)
+{
+ UInt32 k;
+ UInt32 n = kMaxValForNormalize - p->pos;
+ if (n == 0)
+ n = (UInt32)(Int32)-1; // we allow (pos == 0) at start even with (kMaxValForNormalize == 0)
+
+ k = p->cyclicBufferSize - p->cyclicBufferPos;
+ if (k < n)
+ n = k;
+
+ k = GET_AVAIL_BYTES(p);
+ {
+ const UInt32 ksa = p->keepSizeAfter;
+ UInt32 mm = p->matchMaxLen;
+ if (k > ksa)
+ k -= ksa; // we must limit exactly to keepSizeAfter for ReadBlock
+ else if (k >= mm)
+ {
+ // the limitation for (p->lenLimit) update
+ k -= mm; // optimization : to reduce the number of checks
+ k++;
+ // k = 1; // non-optimized version : for debug
+ }
+ else
+ {
+ mm = k;
+ if (k != 0)
+ k = 1;
+ }
+ p->lenLimit = mm;
+ }
+ if (k < n)
+ n = k;
+
+ p->posLimit = p->pos + n;
+}
+
+
+void MatchFinder_Init_LowHash(CMatchFinder *p)
+{
+ size_t i;
+ CLzRef *items = p->hash;
+ const size_t numItems = p->fixedHashSize;
+ for (i = 0; i < numItems; i++)
+ items[i] = kEmptyHashValue;
+}
+
+
+void MatchFinder_Init_HighHash(CMatchFinder *p)
+{
+ size_t i;
+ CLzRef *items = p->hash + p->fixedHashSize;
+ const size_t numItems = (size_t)p->hashMask + 1;
+ for (i = 0; i < numItems; i++)
+ items[i] = kEmptyHashValue;
+}
+
+
+void MatchFinder_Init_4(CMatchFinder *p)
+{
+ if (!p->directInput)
+ p->buffer = p->bufBase;
+ {
+ /* kEmptyHashValue = 0 (Zero) is used in hash tables as NO-VALUE marker.
+ the code in CMatchFinderMt expects (pos = 1) */
+ p->pos =
+ p->streamPos =
+ 1; // it's smallest optimal value. do not change it
+ // 0; // for debug
+ }
+ p->result = SZ_OK;
+ p->streamEndWasReached = 0;
+}
+
+
+// (CYC_TO_POS_OFFSET == 0) is expected by some optimized code
+#define CYC_TO_POS_OFFSET 0
+// #define CYC_TO_POS_OFFSET 1 // for debug
+
+void MatchFinder_Init(CMatchFinder *p)
+{
+ MatchFinder_Init_HighHash(p);
+ MatchFinder_Init_LowHash(p);
+ MatchFinder_Init_4(p);
+ // if (readData)
+ MatchFinder_ReadBlock(p);
+
+ /* if we init (cyclicBufferPos = pos), then we can use one variable
+ instead of both (cyclicBufferPos) and (pos) : only before (cyclicBufferPos) wrapping */
+ p->cyclicBufferPos = (p->pos - CYC_TO_POS_OFFSET); // init with relation to (pos)
+ // p->cyclicBufferPos = 0; // smallest value
+ // p->son[0] = p->son[1] = 0; // unused: we can init skipped record for speculated accesses.
+ MatchFinder_SetLimits(p);
+}
+
+
+
+#ifdef MY_CPU_X86_OR_AMD64
+ #if defined(__clang__) && (__clang_major__ >= 4) \
+ || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40701)
+ // || defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1900)
+
+ #define USE_LZFIND_SATUR_SUB_128
+ #define USE_LZFIND_SATUR_SUB_256
+ #define LZFIND_ATTRIB_SSE41 __attribute__((__target__("sse4.1")))
+ #define LZFIND_ATTRIB_AVX2 __attribute__((__target__("avx2")))
+ #elif defined(_MSC_VER)
+ #if (_MSC_VER >= 1600)
+ #define USE_LZFIND_SATUR_SUB_128
+ #endif
+ #if (_MSC_VER >= 1900)
+ #define USE_LZFIND_SATUR_SUB_256
+ #endif
+ #endif
+
+// #elif defined(MY_CPU_ARM_OR_ARM64)
+#elif defined(MY_CPU_ARM64)
+
+ #if defined(__clang__) && (__clang_major__ >= 8) \
+ || defined(__GNUC__) && (__GNUC__ >= 8)
+ #define USE_LZFIND_SATUR_SUB_128
+ #ifdef MY_CPU_ARM64
+ // #define LZFIND_ATTRIB_SSE41 __attribute__((__target__("")))
+ #else
+ // #define LZFIND_ATTRIB_SSE41 __attribute__((__target__("fpu=crypto-neon-fp-armv8")))
+ #endif
+
+ #elif defined(_MSC_VER)
+ #if (_MSC_VER >= 1910)
+ #define USE_LZFIND_SATUR_SUB_128
+ #endif
+ #endif
+
+ #if defined(_MSC_VER) && defined(MY_CPU_ARM64)
+ #include <arm64_neon.h>
+ #else
+ #include <arm_neon.h>
+ #endif
+
+#endif
+
+
+#ifdef USE_LZFIND_SATUR_SUB_128
+
+// #define Z7_SHOW_HW_STATUS
+
+#ifdef Z7_SHOW_HW_STATUS
+#include <stdio.h>
+#define PRF(x) x
+PRF(;)
+#else
+#define PRF(x)
+#endif
+
+
+#ifdef MY_CPU_ARM_OR_ARM64
+
+#ifdef MY_CPU_ARM64
+// #define FORCE_LZFIND_SATUR_SUB_128
+#endif
+typedef uint32x4_t LzFind_v128;
+#define SASUB_128_V(v, s) \
+ vsubq_u32(vmaxq_u32(v, s), s)
+
+#else // MY_CPU_ARM_OR_ARM64
+
+#include <smmintrin.h> // sse4.1
+
+typedef __m128i LzFind_v128;
+// SSE 4.1
+#define SASUB_128_V(v, s) \
+ _mm_sub_epi32(_mm_max_epu32(v, s), s)
+
+#endif // MY_CPU_ARM_OR_ARM64
+
+
+#define SASUB_128(i) \
+ *( LzFind_v128 *)( void *)(items + (i) * 4) = SASUB_128_V( \
+ *(const LzFind_v128 *)(const void *)(items + (i) * 4), sub2);
+
+
+Z7_NO_INLINE
+static
+#ifdef LZFIND_ATTRIB_SSE41
+LZFIND_ATTRIB_SSE41
+#endif
+void
+Z7_FASTCALL
+LzFind_SaturSub_128(UInt32 subValue, CLzRef *items, const CLzRef *lim)
+{
+ const LzFind_v128 sub2 =
+ #ifdef MY_CPU_ARM_OR_ARM64
+ vdupq_n_u32(subValue);
+ #else
+ _mm_set_epi32((Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue);
+ #endif
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ do
+ {
+ SASUB_128(0) SASUB_128(1) items += 2 * 4;
+ SASUB_128(0) SASUB_128(1) items += 2 * 4;
+ }
+ while (items != lim);
+}
+
+
+
+#ifdef USE_LZFIND_SATUR_SUB_256
+
+#include <immintrin.h> // avx
+/*
+clang :immintrin.h uses
+#if !(defined(_MSC_VER) || defined(__SCE__)) || __has_feature(modules) || \
+ defined(__AVX2__)
+#include <avx2intrin.h>
+#endif
+so we need <avxintrin.h> for clang-cl */
+
+#if defined(__clang__)
+#include <avxintrin.h>
+#include <avx2intrin.h>
+#endif
+
+// AVX2:
+#define SASUB_256(i) \
+ *( __m256i *)( void *)(items + (i) * 8) = \
+ _mm256_sub_epi32(_mm256_max_epu32( \
+ *(const __m256i *)(const void *)(items + (i) * 8), sub2), sub2);
+
+Z7_NO_INLINE
+static
+#ifdef LZFIND_ATTRIB_AVX2
+LZFIND_ATTRIB_AVX2
+#endif
+void
+Z7_FASTCALL
+LzFind_SaturSub_256(UInt32 subValue, CLzRef *items, const CLzRef *lim)
+{
+ const __m256i sub2 = _mm256_set_epi32(
+ (Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue,
+ (Int32)subValue, (Int32)subValue, (Int32)subValue, (Int32)subValue);
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ do
+ {
+ SASUB_256(0) SASUB_256(1) items += 2 * 8;
+ SASUB_256(0) SASUB_256(1) items += 2 * 8;
+ }
+ while (items != lim);
+}
+#endif // USE_LZFIND_SATUR_SUB_256
+
+#ifndef FORCE_LZFIND_SATUR_SUB_128
+typedef void (Z7_FASTCALL *LZFIND_SATUR_SUB_CODE_FUNC)(
+ UInt32 subValue, CLzRef *items, const CLzRef *lim);
+static LZFIND_SATUR_SUB_CODE_FUNC g_LzFind_SaturSub;
+#endif // FORCE_LZFIND_SATUR_SUB_128
+
+#endif // USE_LZFIND_SATUR_SUB_128
+
+
+// kEmptyHashValue must be zero
+// #define SASUB_32(i) { UInt32 v = items[i]; UInt32 m = v - subValue; if (v < subValue) m = kEmptyHashValue; items[i] = m; }
+#define SASUB_32(i) { UInt32 v = items[i]; if (v < subValue) v = subValue; items[i] = v - subValue; }
+
+#ifdef FORCE_LZFIND_SATUR_SUB_128
+
+#define DEFAULT_SaturSub LzFind_SaturSub_128
+
+#else
+
+#define DEFAULT_SaturSub LzFind_SaturSub_32
+
+Z7_NO_INLINE
+static
+void
+Z7_FASTCALL
+LzFind_SaturSub_32(UInt32 subValue, CLzRef *items, const CLzRef *lim)
+{
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ do
+ {
+ SASUB_32(0) SASUB_32(1) items += 2;
+ SASUB_32(0) SASUB_32(1) items += 2;
+ SASUB_32(0) SASUB_32(1) items += 2;
+ SASUB_32(0) SASUB_32(1) items += 2;
+ }
+ while (items != lim);
+}
+
+#endif
+
+
+Z7_NO_INLINE
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems)
+{
+ #define LZFIND_NORM_ALIGN_BLOCK_SIZE (1 << 7)
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ for (; numItems != 0 && ((unsigned)(ptrdiff_t)items & (LZFIND_NORM_ALIGN_BLOCK_SIZE - 1)) != 0; numItems--)
+ {
+ SASUB_32(0)
+ items++;
+ }
+ {
+ const size_t k_Align_Mask = (LZFIND_NORM_ALIGN_BLOCK_SIZE / 4 - 1);
+ CLzRef *lim = items + (numItems & ~(size_t)k_Align_Mask);
+ numItems &= k_Align_Mask;
+ if (items != lim)
+ {
+ #if defined(USE_LZFIND_SATUR_SUB_128) && !defined(FORCE_LZFIND_SATUR_SUB_128)
+ if (g_LzFind_SaturSub)
+ g_LzFind_SaturSub(subValue, items, lim);
+ else
+ #endif
+ DEFAULT_SaturSub(subValue, items, lim);
+ }
+ items = lim;
+ }
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ for (; numItems != 0; numItems--)
+ {
+ SASUB_32(0)
+ items++;
+ }
+}
+
+
+
+// call MatchFinder_CheckLimits() only after (p->pos++) update
+
+Z7_NO_INLINE
+static void MatchFinder_CheckLimits(CMatchFinder *p)
+{
+ if (// !p->streamEndWasReached && p->result == SZ_OK &&
+ p->keepSizeAfter == GET_AVAIL_BYTES(p))
+ {
+ // we try to read only in exact state (p->keepSizeAfter == GET_AVAIL_BYTES(p))
+ if (MatchFinder_NeedMove(p))
+ MatchFinder_MoveBlock(p);
+ MatchFinder_ReadBlock(p);
+ }
+
+ if (p->pos == kMaxValForNormalize)
+ if (GET_AVAIL_BYTES(p) >= p->numHashBytes) // optional optimization for last bytes of data.
+ /*
+ if we disable normalization for last bytes of data, and
+ if (data_size == 4 GiB), we don't call wastfull normalization,
+ but (pos) will be wrapped over Zero (0) in that case.
+ And we cannot resume later to normal operation
+ */
+ {
+ // MatchFinder_Normalize(p);
+ /* after normalization we need (p->pos >= p->historySize + 1); */
+ /* we can reduce subValue to aligned value, if want to keep alignment
+ of (p->pos) and (p->buffer) for speculated accesses. */
+ const UInt32 subValue = (p->pos - p->historySize - 1) /* & ~(UInt32)(kNormalizeAlign - 1) */;
+ // const UInt32 subValue = (1 << 15); // for debug
+ // printf("\nMatchFinder_Normalize() subValue == 0x%x\n", subValue);
+ MatchFinder_REDUCE_OFFSETS(p, subValue)
+ MatchFinder_Normalize3(subValue, p->hash, (size_t)p->hashMask + 1 + p->fixedHashSize);
+ {
+ size_t numSonRefs = p->cyclicBufferSize;
+ if (p->btMode)
+ numSonRefs <<= 1;
+ MatchFinder_Normalize3(subValue, p->son, numSonRefs);
+ }
+ }
+
+ if (p->cyclicBufferPos == p->cyclicBufferSize)
+ p->cyclicBufferPos = 0;
+
+ MatchFinder_SetLimits(p);
+}
+
+
+/*
+ (lenLimit > maxLen)
+*/
+Z7_FORCE_INLINE
+static UInt32 * Hc_GetMatchesSpec(size_t lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+ UInt32 *d, unsigned maxLen)
+{
+ /*
+ son[_cyclicBufferPos] = curMatch;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ return d;
+ {
+ const Byte *pb = cur - delta;
+ curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+ if (pb[maxLen] == cur[maxLen] && *pb == *cur)
+ {
+ UInt32 len = 0;
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ maxLen = len;
+ *d++ = len;
+ *d++ = delta - 1;
+ if (len == lenLimit)
+ return d;
+ }
+ }
+ }
+ }
+ */
+
+ const Byte *lim = cur + lenLimit;
+ son[_cyclicBufferPos] = curMatch;
+
+ do
+ {
+ UInt32 delta;
+
+ if (curMatch == 0)
+ break;
+ // if (curMatch2 >= curMatch) return NULL;
+ delta = pos - curMatch;
+ if (delta >= _cyclicBufferSize)
+ break;
+ {
+ ptrdiff_t diff;
+ curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+ diff = (ptrdiff_t)0 - (ptrdiff_t)delta;
+ if (cur[maxLen] == cur[(ptrdiff_t)maxLen + diff])
+ {
+ const Byte *c = cur;
+ while (*c == c[diff])
+ {
+ if (++c == lim)
+ {
+ d[0] = (UInt32)(lim - cur);
+ d[1] = delta - 1;
+ return d + 2;
+ }
+ }
+ {
+ const unsigned len = (unsigned)(c - cur);
+ if (maxLen < len)
+ {
+ maxLen = len;
+ d[0] = (UInt32)len;
+ d[1] = delta - 1;
+ d += 2;
+ }
+ }
+ }
+ }
+ }
+ while (--cutValue);
+
+ return d;
+}
+
+
+Z7_FORCE_INLINE
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+ UInt32 *d, UInt32 maxLen)
+{
+ CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
+ unsigned len0 = 0, len1 = 0;
+
+ UInt32 cmCheck;
+
+ // if (curMatch >= pos) { *ptr0 = *ptr1 = kEmptyHashValue; return NULL; }
+
+ cmCheck = (UInt32)(pos - _cyclicBufferSize);
+ if ((UInt32)pos <= _cyclicBufferSize)
+ cmCheck = 0;
+
+ if (cmCheck < curMatch)
+ do
+ {
+ const UInt32 delta = pos - curMatch;
+ {
+ CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ unsigned len = (len0 < len1 ? len0 : len1);
+ const UInt32 pair0 = pair[0];
+ if (pb[len] == cur[len])
+ {
+ if (++len != lenLimit && pb[len] == cur[len])
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ maxLen = (UInt32)len;
+ *d++ = (UInt32)len;
+ *d++ = delta - 1;
+ if (len == lenLimit)
+ {
+ *ptr1 = pair0;
+ *ptr0 = pair[1];
+ return d;
+ }
+ }
+ }
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ // const UInt32 curMatch2 = pair[1];
+ // if (curMatch2 >= curMatch) { *ptr0 = *ptr1 = kEmptyHashValue; return NULL; }
+ // curMatch = curMatch2;
+ curMatch = pair[1];
+ ptr1 = pair + 1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ curMatch = pair[0];
+ ptr0 = pair;
+ len0 = len;
+ }
+ }
+ }
+ while(--cutValue && cmCheck < curMatch);
+
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ return d;
+}
+
+
+static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
+{
+ CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
+ unsigned len0 = 0, len1 = 0;
+
+ UInt32 cmCheck;
+
+ cmCheck = (UInt32)(pos - _cyclicBufferSize);
+ if ((UInt32)pos <= _cyclicBufferSize)
+ cmCheck = 0;
+
+ if (// curMatch >= pos || // failure
+ cmCheck < curMatch)
+ do
+ {
+ const UInt32 delta = pos - curMatch;
+ {
+ CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ unsigned len = (len0 < len1 ? len0 : len1);
+ if (pb[len] == cur[len])
+ {
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ {
+ if (len == lenLimit)
+ {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ return;
+ }
+ }
+ }
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ curMatch = pair[1];
+ ptr1 = pair + 1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ curMatch = pair[0];
+ ptr0 = pair;
+ len0 = len;
+ }
+ }
+ }
+ while(--cutValue && cmCheck < curMatch);
+
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ return;
+}
+
+
+#define MOVE_POS \
+ ++p->cyclicBufferPos; \
+ p->buffer++; \
+ { const UInt32 pos1 = p->pos + 1; p->pos = pos1; if (pos1 == p->posLimit) MatchFinder_CheckLimits(p); }
+
+#define MOVE_POS_RET MOVE_POS return distances;
+
+Z7_NO_INLINE
+static void MatchFinder_MovePos(CMatchFinder *p)
+{
+ /* we go here at the end of stream data, when (avail < num_hash_bytes)
+ We don't update sons[cyclicBufferPos << btMode].
+ So (sons) record will contain junk. And we cannot resume match searching
+ to normal operation, even if we will provide more input data in buffer.
+ p->sons[p->cyclicBufferPos << p->btMode] = 0; // kEmptyHashValue
+ if (p->btMode)
+ p->sons[(p->cyclicBufferPos << p->btMode) + 1] = 0; // kEmptyHashValue
+ */
+ MOVE_POS
+}
+
+#define GET_MATCHES_HEADER2(minLen, ret_op) \
+ unsigned lenLimit; UInt32 hv; const Byte *cur; UInt32 curMatch; \
+ lenLimit = (unsigned)p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
+ cur = p->buffer;
+
+#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return distances)
+#define SKIP_HEADER(minLen) do { GET_MATCHES_HEADER2(minLen, continue)
+
+#define MF_PARAMS(p) lenLimit, curMatch, p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
+
+#define SKIP_FOOTER SkipMatchesSpec(MF_PARAMS(p)); MOVE_POS } while (--num);
+
+#define GET_MATCHES_FOOTER_BASE(_maxLen_, func) \
+ distances = func(MF_PARAMS(p), \
+ distances, (UInt32)_maxLen_); MOVE_POS_RET
+
+#define GET_MATCHES_FOOTER_BT(_maxLen_) \
+ GET_MATCHES_FOOTER_BASE(_maxLen_, GetMatchesSpec1)
+
+#define GET_MATCHES_FOOTER_HC(_maxLen_) \
+ GET_MATCHES_FOOTER_BASE(_maxLen_, Hc_GetMatchesSpec)
+
+
+
+#define UPDATE_maxLen { \
+ const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)d2; \
+ const Byte *c = cur + maxLen; \
+ const Byte *lim = cur + lenLimit; \
+ for (; c != lim; c++) if (*(c + diff) != *c) break; \
+ maxLen = (unsigned)(c - cur); }
+
+static UInt32* Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ GET_MATCHES_HEADER(2)
+ HASH2_CALC
+ curMatch = p->hash[hv];
+ p->hash[hv] = p->pos;
+ GET_MATCHES_FOOTER_BT(1)
+}
+
+UInt32* Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ GET_MATCHES_HEADER(3)
+ HASH_ZIP_CALC
+ curMatch = p->hash[hv];
+ p->hash[hv] = p->pos;
+ GET_MATCHES_FOOTER_BT(2)
+}
+
+
+#define SET_mmm \
+ mmm = p->cyclicBufferSize; \
+ if (pos < mmm) \
+ mmm = pos;
+
+
+static UInt32* Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 mmm;
+ UInt32 h2, d2, pos;
+ unsigned maxLen;
+ UInt32 *hash;
+ GET_MATCHES_HEADER(3)
+
+ HASH3_CALC
+
+ hash = p->hash;
+ pos = p->pos;
+
+ d2 = pos - hash[h2];
+
+ curMatch = (hash + kFix3HashSize)[hv];
+
+ hash[h2] = pos;
+ (hash + kFix3HashSize)[hv] = pos;
+
+ SET_mmm
+
+ maxLen = 2;
+
+ if (d2 < mmm && *(cur - d2) == *cur)
+ {
+ UPDATE_maxLen
+ distances[0] = (UInt32)maxLen;
+ distances[1] = d2 - 1;
+ distances += 2;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(MF_PARAMS(p));
+ MOVE_POS_RET
+ }
+ }
+
+ GET_MATCHES_FOOTER_BT(maxLen)
+}
+
+
+static UInt32* Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 mmm;
+ UInt32 h2, h3, d2, d3, pos;
+ unsigned maxLen;
+ UInt32 *hash;
+ GET_MATCHES_HEADER(4)
+
+ HASH4_CALC
+
+ hash = p->hash;
+ pos = p->pos;
+
+ d2 = pos - hash [h2];
+ d3 = pos - (hash + kFix3HashSize)[h3];
+ curMatch = (hash + kFix4HashSize)[hv];
+
+ hash [h2] = pos;
+ (hash + kFix3HashSize)[h3] = pos;
+ (hash + kFix4HashSize)[hv] = pos;
+
+ SET_mmm
+
+ maxLen = 3;
+
+ for (;;)
+ {
+ if (d2 < mmm && *(cur - d2) == *cur)
+ {
+ distances[0] = 2;
+ distances[1] = d2 - 1;
+ distances += 2;
+ if (*(cur - d2 + 2) == cur[2])
+ {
+ // distances[-2] = 3;
+ }
+ else if (d3 < mmm && *(cur - d3) == *cur)
+ {
+ d2 = d3;
+ distances[1] = d3 - 1;
+ distances += 2;
+ }
+ else
+ break;
+ }
+ else if (d3 < mmm && *(cur - d3) == *cur)
+ {
+ d2 = d3;
+ distances[1] = d3 - 1;
+ distances += 2;
+ }
+ else
+ break;
+
+ UPDATE_maxLen
+ distances[-2] = (UInt32)maxLen;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(MF_PARAMS(p));
+ MOVE_POS_RET
+ }
+ break;
+ }
+
+ GET_MATCHES_FOOTER_BT(maxLen)
+}
+
+
+static UInt32* Bt5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 mmm;
+ UInt32 h2, h3, d2, d3, maxLen, pos;
+ UInt32 *hash;
+ GET_MATCHES_HEADER(5)
+
+ HASH5_CALC
+
+ hash = p->hash;
+ pos = p->pos;
+
+ d2 = pos - hash [h2];
+ d3 = pos - (hash + kFix3HashSize)[h3];
+ // d4 = pos - (hash + kFix4HashSize)[h4];
+
+ curMatch = (hash + kFix5HashSize)[hv];
+
+ hash [h2] = pos;
+ (hash + kFix3HashSize)[h3] = pos;
+ // (hash + kFix4HashSize)[h4] = pos;
+ (hash + kFix5HashSize)[hv] = pos;
+
+ SET_mmm
+
+ maxLen = 4;
+
+ for (;;)
+ {
+ if (d2 < mmm && *(cur - d2) == *cur)
+ {
+ distances[0] = 2;
+ distances[1] = d2 - 1;
+ distances += 2;
+ if (*(cur - d2 + 2) == cur[2])
+ {
+ }
+ else if (d3 < mmm && *(cur - d3) == *cur)
+ {
+ distances[1] = d3 - 1;
+ distances += 2;
+ d2 = d3;
+ }
+ else
+ break;
+ }
+ else if (d3 < mmm && *(cur - d3) == *cur)
+ {
+ distances[1] = d3 - 1;
+ distances += 2;
+ d2 = d3;
+ }
+ else
+ break;
+
+ distances[-2] = 3;
+ if (*(cur - d2 + 3) != cur[3])
+ break;
+ UPDATE_maxLen
+ distances[-2] = (UInt32)maxLen;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(MF_PARAMS(p));
+ MOVE_POS_RET
+ }
+ break;
+ }
+
+ GET_MATCHES_FOOTER_BT(maxLen)
+}
+
+
+static UInt32* Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 mmm;
+ UInt32 h2, h3, d2, d3, pos;
+ unsigned maxLen;
+ UInt32 *hash;
+ GET_MATCHES_HEADER(4)
+
+ HASH4_CALC
+
+ hash = p->hash;
+ pos = p->pos;
+
+ d2 = pos - hash [h2];
+ d3 = pos - (hash + kFix3HashSize)[h3];
+ curMatch = (hash + kFix4HashSize)[hv];
+
+ hash [h2] = pos;
+ (hash + kFix3HashSize)[h3] = pos;
+ (hash + kFix4HashSize)[hv] = pos;
+
+ SET_mmm
+
+ maxLen = 3;
+
+ for (;;)
+ {
+ if (d2 < mmm && *(cur - d2) == *cur)
+ {
+ distances[0] = 2;
+ distances[1] = d2 - 1;
+ distances += 2;
+ if (*(cur - d2 + 2) == cur[2])
+ {
+ // distances[-2] = 3;
+ }
+ else if (d3 < mmm && *(cur - d3) == *cur)
+ {
+ d2 = d3;
+ distances[1] = d3 - 1;
+ distances += 2;
+ }
+ else
+ break;
+ }
+ else if (d3 < mmm && *(cur - d3) == *cur)
+ {
+ d2 = d3;
+ distances[1] = d3 - 1;
+ distances += 2;
+ }
+ else
+ break;
+
+ UPDATE_maxLen
+ distances[-2] = (UInt32)maxLen;
+ if (maxLen == lenLimit)
+ {
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS_RET
+ }
+ break;
+ }
+
+ GET_MATCHES_FOOTER_HC(maxLen)
+}
+
+
+static UInt32 * Hc5_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 mmm;
+ UInt32 h2, h3, d2, d3, maxLen, pos;
+ UInt32 *hash;
+ GET_MATCHES_HEADER(5)
+
+ HASH5_CALC
+
+ hash = p->hash;
+ pos = p->pos;
+
+ d2 = pos - hash [h2];
+ d3 = pos - (hash + kFix3HashSize)[h3];
+ // d4 = pos - (hash + kFix4HashSize)[h4];
+
+ curMatch = (hash + kFix5HashSize)[hv];
+
+ hash [h2] = pos;
+ (hash + kFix3HashSize)[h3] = pos;
+ // (hash + kFix4HashSize)[h4] = pos;
+ (hash + kFix5HashSize)[hv] = pos;
+
+ SET_mmm
+
+ maxLen = 4;
+
+ for (;;)
+ {
+ if (d2 < mmm && *(cur - d2) == *cur)
+ {
+ distances[0] = 2;
+ distances[1] = d2 - 1;
+ distances += 2;
+ if (*(cur - d2 + 2) == cur[2])
+ {
+ }
+ else if (d3 < mmm && *(cur - d3) == *cur)
+ {
+ distances[1] = d3 - 1;
+ distances += 2;
+ d2 = d3;
+ }
+ else
+ break;
+ }
+ else if (d3 < mmm && *(cur - d3) == *cur)
+ {
+ distances[1] = d3 - 1;
+ distances += 2;
+ d2 = d3;
+ }
+ else
+ break;
+
+ distances[-2] = 3;
+ if (*(cur - d2 + 3) != cur[3])
+ break;
+ UPDATE_maxLen
+ distances[-2] = maxLen;
+ if (maxLen == lenLimit)
+ {
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS_RET
+ }
+ break;
+ }
+
+ GET_MATCHES_FOOTER_HC(maxLen)
+}
+
+
+UInt32* Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ GET_MATCHES_HEADER(3)
+ HASH_ZIP_CALC
+ curMatch = p->hash[hv];
+ p->hash[hv] = p->pos;
+ GET_MATCHES_FOOTER_HC(2)
+}
+
+
+static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ SKIP_HEADER(2)
+ {
+ HASH2_CALC
+ curMatch = p->hash[hv];
+ p->hash[hv] = p->pos;
+ }
+ SKIP_FOOTER
+}
+
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ SKIP_HEADER(3)
+ {
+ HASH_ZIP_CALC
+ curMatch = p->hash[hv];
+ p->hash[hv] = p->pos;
+ }
+ SKIP_FOOTER
+}
+
+static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ SKIP_HEADER(3)
+ {
+ UInt32 h2;
+ UInt32 *hash;
+ HASH3_CALC
+ hash = p->hash;
+ curMatch = (hash + kFix3HashSize)[hv];
+ hash[h2] =
+ (hash + kFix3HashSize)[hv] = p->pos;
+ }
+ SKIP_FOOTER
+}
+
+static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ SKIP_HEADER(4)
+ {
+ UInt32 h2, h3;
+ UInt32 *hash;
+ HASH4_CALC
+ hash = p->hash;
+ curMatch = (hash + kFix4HashSize)[hv];
+ hash [h2] =
+ (hash + kFix3HashSize)[h3] =
+ (hash + kFix4HashSize)[hv] = p->pos;
+ }
+ SKIP_FOOTER
+}
+
+static void Bt5_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ SKIP_HEADER(5)
+ {
+ UInt32 h2, h3;
+ UInt32 *hash;
+ HASH5_CALC
+ hash = p->hash;
+ curMatch = (hash + kFix5HashSize)[hv];
+ hash [h2] =
+ (hash + kFix3HashSize)[h3] =
+ // (hash + kFix4HashSize)[h4] =
+ (hash + kFix5HashSize)[hv] = p->pos;
+ }
+ SKIP_FOOTER
+}
+
+
+#define HC_SKIP_HEADER(minLen) \
+ do { if (p->lenLimit < minLen) { MatchFinder_MovePos(p); num--; continue; } { \
+ const Byte *cur; \
+ UInt32 *hash; \
+ UInt32 *son; \
+ UInt32 pos = p->pos; \
+ UInt32 num2 = num; \
+ /* (p->pos == p->posLimit) is not allowed here !!! */ \
+ { const UInt32 rem = p->posLimit - pos; if (num2 > rem) num2 = rem; } \
+ num -= num2; \
+ { const UInt32 cycPos = p->cyclicBufferPos; \
+ son = p->son + cycPos; \
+ p->cyclicBufferPos = cycPos + num2; } \
+ cur = p->buffer; \
+ hash = p->hash; \
+ do { \
+ UInt32 curMatch; \
+ UInt32 hv;
+
+
+#define HC_SKIP_FOOTER \
+ cur++; pos++; *son++ = curMatch; \
+ } while (--num2); \
+ p->buffer = cur; \
+ p->pos = pos; \
+ if (pos == p->posLimit) MatchFinder_CheckLimits(p); \
+ }} while(num); \
+
+
+static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ HC_SKIP_HEADER(4)
+
+ UInt32 h2, h3;
+ HASH4_CALC
+ curMatch = (hash + kFix4HashSize)[hv];
+ hash [h2] =
+ (hash + kFix3HashSize)[h3] =
+ (hash + kFix4HashSize)[hv] = pos;
+
+ HC_SKIP_FOOTER
+}
+
+
+static void Hc5_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ HC_SKIP_HEADER(5)
+
+ UInt32 h2, h3;
+ HASH5_CALC
+ curMatch = (hash + kFix5HashSize)[hv];
+ hash [h2] =
+ (hash + kFix3HashSize)[h3] =
+ // (hash + kFix4HashSize)[h4] =
+ (hash + kFix5HashSize)[hv] = pos;
+
+ HC_SKIP_FOOTER
+}
+
+
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ HC_SKIP_HEADER(3)
+
+ HASH_ZIP_CALC
+ curMatch = hash[hv];
+ hash[hv] = pos;
+
+ HC_SKIP_FOOTER
+}
+
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder2 *vTable)
+{
+ vTable->Init = (Mf_Init_Func)MatchFinder_Init;
+ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
+ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
+ if (!p->btMode)
+ {
+ if (p->numHashBytes <= 4)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
+ }
+ else
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Hc5_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Hc5_MatchFinder_Skip;
+ }
+ }
+ else if (p->numHashBytes == 2)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
+ }
+ else if (p->numHashBytes == 3)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
+ }
+ else if (p->numHashBytes == 4)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+ }
+ else
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt5_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt5_MatchFinder_Skip;
+ }
+}
+
+
+
+void LzFindPrepare(void)
+{
+ #ifndef FORCE_LZFIND_SATUR_SUB_128
+ #ifdef USE_LZFIND_SATUR_SUB_128
+ LZFIND_SATUR_SUB_CODE_FUNC f = NULL;
+ #ifdef MY_CPU_ARM_OR_ARM64
+ {
+ if (CPU_IsSupported_NEON())
+ {
+ // #pragma message ("=== LzFind NEON")
+ PRF(printf("\n=== LzFind NEON\n"));
+ f = LzFind_SaturSub_128;
+ }
+ // f = 0; // for debug
+ }
+ #else // MY_CPU_ARM_OR_ARM64
+ if (CPU_IsSupported_SSE41())
+ {
+ // #pragma message ("=== LzFind SSE41")
+ PRF(printf("\n=== LzFind SSE41\n"));
+ f = LzFind_SaturSub_128;
+
+ #ifdef USE_LZFIND_SATUR_SUB_256
+ if (CPU_IsSupported_AVX2())
+ {
+ // #pragma message ("=== LzFind AVX2")
+ PRF(printf("\n=== LzFind AVX2\n"));
+ f = LzFind_SaturSub_256;
+ }
+ #endif
+ }
+ #endif // MY_CPU_ARM_OR_ARM64
+ g_LzFind_SaturSub = f;
+ #endif // USE_LZFIND_SATUR_SUB_128
+ #endif // FORCE_LZFIND_SATUR_SUB_128
+}
+
+
+#undef MOVE_POS
+#undef MOVE_POS_RET
+#undef PRF
diff --git a/C/LzFind.h b/C/LzFind.h
index c77adde..a3f72c9 100644
--- a/C/LzFind.h
+++ b/C/LzFind.h
@@ -1,121 +1,159 @@
-/* LzFind.h -- Match finder for LZ algorithms
-2017-06-10 : Igor Pavlov : Public domain */
-
-#ifndef __LZ_FIND_H
-#define __LZ_FIND_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-typedef UInt32 CLzRef;
-
-typedef struct _CMatchFinder
-{
- Byte *buffer;
- UInt32 pos;
- UInt32 posLimit;
- UInt32 streamPos;
- UInt32 lenLimit;
-
- UInt32 cyclicBufferPos;
- UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
-
- Byte streamEndWasReached;
- Byte btMode;
- Byte bigHash;
- Byte directInput;
-
- UInt32 matchMaxLen;
- CLzRef *hash;
- CLzRef *son;
- UInt32 hashMask;
- UInt32 cutValue;
-
- Byte *bufferBase;
- ISeqInStream *stream;
-
- UInt32 blockSize;
- UInt32 keepSizeBefore;
- UInt32 keepSizeAfter;
-
- UInt32 numHashBytes;
- size_t directInputRem;
- UInt32 historySize;
- UInt32 fixedHashSize;
- UInt32 hashSizeSum;
- SRes result;
- UInt32 crc[256];
- size_t numRefs;
-
- UInt64 expectedDataSize;
-} CMatchFinder;
-
-#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
-
-#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
-
-#define Inline_MatchFinder_IsFinishedOK(p) \
- ((p)->streamEndWasReached \
- && (p)->streamPos == (p)->pos \
- && (!(p)->directInput || (p)->directInputRem == 0))
-
-int MatchFinder_NeedMove(CMatchFinder *p);
-Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
-void MatchFinder_MoveBlock(CMatchFinder *p);
-void MatchFinder_ReadIfRequired(CMatchFinder *p);
-
-void MatchFinder_Construct(CMatchFinder *p);
-
-/* Conditions:
- historySize <= 3 GB
- keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
-*/
-int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
- UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
- ISzAllocPtr alloc);
-void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc);
-void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems);
-void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
-
-UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
- UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
- UInt32 *distances, UInt32 maxLen);
-
-/*
-Conditions:
- Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
- Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
-*/
-
-typedef void (*Mf_Init_Func)(void *object);
-typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
-typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
-typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
-typedef void (*Mf_Skip_Func)(void *object, UInt32);
-
-typedef struct _IMatchFinder
-{
- Mf_Init_Func Init;
- Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
- Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
- Mf_GetMatches_Func GetMatches;
- Mf_Skip_Func Skip;
-} IMatchFinder;
-
-void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
-
-void MatchFinder_Init_LowHash(CMatchFinder *p);
-void MatchFinder_Init_HighHash(CMatchFinder *p);
-void MatchFinder_Init_3(CMatchFinder *p, int readData);
-void MatchFinder_Init(CMatchFinder *p);
-
-UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
-UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
-
-void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
-void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
-
-EXTERN_C_END
-
-#endif
+/* LzFind.h -- Match finder for LZ algorithms
+2023-03-04 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_LZ_FIND_H
+#define ZIP7_INC_LZ_FIND_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+typedef UInt32 CLzRef;
+
+typedef struct
+{
+ const Byte *buffer;
+ UInt32 pos;
+ UInt32 posLimit;
+ UInt32 streamPos; /* wrap over Zero is allowed (streamPos < pos). Use (UInt32)(streamPos - pos) */
+ UInt32 lenLimit;
+
+ UInt32 cyclicBufferPos;
+ UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
+
+ Byte streamEndWasReached;
+ Byte btMode;
+ Byte bigHash;
+ Byte directInput;
+
+ UInt32 matchMaxLen;
+ CLzRef *hash;
+ CLzRef *son;
+ UInt32 hashMask;
+ UInt32 cutValue;
+
+ Byte *bufBase;
+ ISeqInStreamPtr stream;
+
+ UInt32 blockSize;
+ UInt32 keepSizeBefore;
+ UInt32 keepSizeAfter;
+
+ UInt32 numHashBytes;
+ size_t directInputRem;
+ UInt32 historySize;
+ UInt32 fixedHashSize;
+ Byte numHashBytes_Min;
+ Byte numHashOutBits;
+ Byte _pad2_[2];
+ SRes result;
+ UInt32 crc[256];
+ size_t numRefs;
+
+ UInt64 expectedDataSize;
+} CMatchFinder;
+
+#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((const Byte *)(p)->buffer)
+
+#define Inline_MatchFinder_GetNumAvailableBytes(p) ((UInt32)((p)->streamPos - (p)->pos))
+
+/*
+#define Inline_MatchFinder_IsFinishedOK(p) \
+ ((p)->streamEndWasReached \
+ && (p)->streamPos == (p)->pos \
+ && (!(p)->directInput || (p)->directInputRem == 0))
+*/
+
+int MatchFinder_NeedMove(CMatchFinder *p);
+/* Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p); */
+void MatchFinder_MoveBlock(CMatchFinder *p);
+void MatchFinder_ReadIfRequired(CMatchFinder *p);
+
+void MatchFinder_Construct(CMatchFinder *p);
+
+/* (directInput = 0) is default value.
+ It's required to provide correct (directInput) value
+ before calling MatchFinder_Create().
+ You can set (directInput) by any of the following calls:
+ - MatchFinder_SET_DIRECT_INPUT_BUF()
+ - MatchFinder_SET_STREAM()
+ - MatchFinder_SET_STREAM_MODE()
+*/
+
+#define MatchFinder_SET_DIRECT_INPUT_BUF(p, _src_, _srcLen_) { \
+ (p)->stream = NULL; \
+ (p)->directInput = 1; \
+ (p)->buffer = (_src_); \
+ (p)->directInputRem = (_srcLen_); }
+
+/*
+#define MatchFinder_SET_STREAM_MODE(p) { \
+ (p)->directInput = 0; }
+*/
+
+#define MatchFinder_SET_STREAM(p, _stream_) { \
+ (p)->stream = _stream_; \
+ (p)->directInput = 0; }
+
+
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+ ISzAllocPtr alloc);
+void MatchFinder_Free(CMatchFinder *p, ISzAllocPtr alloc);
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, size_t numItems);
+
+/*
+#define MatchFinder_INIT_POS(p, val) \
+ (p)->pos = (val); \
+ (p)->streamPos = (val);
+*/
+
+// void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
+#define MatchFinder_REDUCE_OFFSETS(p, subValue) \
+ (p)->pos -= (subValue); \
+ (p)->streamPos -= (subValue);
+
+
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
+ size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
+ UInt32 *distances, UInt32 maxLen);
+
+/*
+Conditions:
+ Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
+ Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
+*/
+
+typedef void (*Mf_Init_Func)(void *object);
+typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
+typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
+typedef UInt32 * (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
+typedef void (*Mf_Skip_Func)(void *object, UInt32);
+
+typedef struct
+{
+ Mf_Init_Func Init;
+ Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
+ Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
+ Mf_GetMatches_Func GetMatches;
+ Mf_Skip_Func Skip;
+} IMatchFinder2;
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder2 *vTable);
+
+void MatchFinder_Init_LowHash(CMatchFinder *p);
+void MatchFinder_Init_HighHash(CMatchFinder *p);
+void MatchFinder_Init_4(CMatchFinder *p);
+void MatchFinder_Init(CMatchFinder *p);
+
+UInt32* Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+UInt32* Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+
+void LzFindPrepare(void);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/LzFindMt.c b/C/LzFindMt.c
index df32146..5253e6e 100644
--- a/C/LzFindMt.c
+++ b/C/LzFindMt.c
@@ -1,853 +1,1406 @@
-/* LzFindMt.c -- multithreaded Match finder for LZ algorithms
-2018-12-29 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "LzHash.h"
-
-#include "LzFindMt.h"
-
-static void MtSync_Construct(CMtSync *p)
-{
- p->wasCreated = False;
- p->csWasInitialized = False;
- p->csWasEntered = False;
- Thread_Construct(&p->thread);
- Event_Construct(&p->canStart);
- Event_Construct(&p->wasStarted);
- Event_Construct(&p->wasStopped);
- Semaphore_Construct(&p->freeSemaphore);
- Semaphore_Construct(&p->filledSemaphore);
-}
-
-static void MtSync_GetNextBlock(CMtSync *p)
-{
- if (p->needStart)
- {
- p->numProcessedBlocks = 1;
- p->needStart = False;
- p->stopWriting = False;
- p->exit = False;
- Event_Reset(&p->wasStarted);
- Event_Reset(&p->wasStopped);
-
- Event_Set(&p->canStart);
- Event_Wait(&p->wasStarted);
-
- // if (mt) MatchFinder_Init_LowHash(mt->MatchFinder);
- }
- else
- {
- CriticalSection_Leave(&p->cs);
- p->csWasEntered = False;
- p->numProcessedBlocks++;
- Semaphore_Release1(&p->freeSemaphore);
- }
- Semaphore_Wait(&p->filledSemaphore);
- CriticalSection_Enter(&p->cs);
- p->csWasEntered = True;
-}
-
-/* MtSync_StopWriting must be called if Writing was started */
-
-static void MtSync_StopWriting(CMtSync *p)
-{
- UInt32 myNumBlocks = p->numProcessedBlocks;
- if (!Thread_WasCreated(&p->thread) || p->needStart)
- return;
- p->stopWriting = True;
- if (p->csWasEntered)
- {
- CriticalSection_Leave(&p->cs);
- p->csWasEntered = False;
- }
- Semaphore_Release1(&p->freeSemaphore);
-
- Event_Wait(&p->wasStopped);
-
- while (myNumBlocks++ != p->numProcessedBlocks)
- {
- Semaphore_Wait(&p->filledSemaphore);
- Semaphore_Release1(&p->freeSemaphore);
- }
- p->needStart = True;
-}
-
-static void MtSync_Destruct(CMtSync *p)
-{
- if (Thread_WasCreated(&p->thread))
- {
- MtSync_StopWriting(p);
- p->exit = True;
- if (p->needStart)
- Event_Set(&p->canStart);
- Thread_Wait(&p->thread);
- Thread_Close(&p->thread);
- }
- if (p->csWasInitialized)
- {
- CriticalSection_Delete(&p->cs);
- p->csWasInitialized = False;
- }
-
- Event_Close(&p->canStart);
- Event_Close(&p->wasStarted);
- Event_Close(&p->wasStopped);
- Semaphore_Close(&p->freeSemaphore);
- Semaphore_Close(&p->filledSemaphore);
-
- p->wasCreated = False;
-}
-
-#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; }
-
-static SRes MtSync_Create2(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks)
-{
- if (p->wasCreated)
- return SZ_OK;
-
- RINOK_THREAD(CriticalSection_Init(&p->cs));
- p->csWasInitialized = True;
-
- RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart));
- RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStarted));
- RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped));
-
- RINOK_THREAD(Semaphore_Create(&p->freeSemaphore, numBlocks, numBlocks));
- RINOK_THREAD(Semaphore_Create(&p->filledSemaphore, 0, numBlocks));
-
- p->needStart = True;
-
- RINOK_THREAD(Thread_Create(&p->thread, startAddress, obj));
- p->wasCreated = True;
- return SZ_OK;
-}
-
-static SRes MtSync_Create(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj, UInt32 numBlocks)
-{
- SRes res = MtSync_Create2(p, startAddress, obj, numBlocks);
- if (res != SZ_OK)
- MtSync_Destruct(p);
- return res;
-}
-
-void MtSync_Init(CMtSync *p) { p->needStart = True; }
-
-#define kMtMaxValForNormalize 0xFFFFFFFF
-
-#define DEF_GetHeads2(name, v, action) \
- static void GetHeads ## name(const Byte *p, UInt32 pos, \
- UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc) \
- { action; for (; numHeads != 0; numHeads--) { \
- const UInt32 value = (v); p++; *heads++ = pos - hash[value]; hash[value] = pos++; } }
-
-#define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;)
-
-DEF_GetHeads2(2, (p[0] | ((UInt32)p[1] << 8)), UNUSED_VAR(hashMask); UNUSED_VAR(crc); )
-DEF_GetHeads(3, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8)) & hashMask)
-DEF_GetHeads(4, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5)) & hashMask)
-DEF_GetHeads(4b, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ ((UInt32)p[3] << 16)) & hashMask)
-/* DEF_GetHeads(5, (crc[p[0]] ^ p[1] ^ ((UInt32)p[2] << 8) ^ (crc[p[3]] << 5) ^ (crc[p[4]] << 3)) & hashMask) */
-
-static void HashThreadFunc(CMatchFinderMt *mt)
-{
- CMtSync *p = &mt->hashSync;
- for (;;)
- {
- UInt32 numProcessedBlocks = 0;
- Event_Wait(&p->canStart);
- Event_Set(&p->wasStarted);
-
- MatchFinder_Init_HighHash(mt->MatchFinder);
-
- for (;;)
- {
- if (p->exit)
- return;
- if (p->stopWriting)
- {
- p->numProcessedBlocks = numProcessedBlocks;
- Event_Set(&p->wasStopped);
- break;
- }
-
- {
- CMatchFinder *mf = mt->MatchFinder;
- if (MatchFinder_NeedMove(mf))
- {
- CriticalSection_Enter(&mt->btSync.cs);
- CriticalSection_Enter(&mt->hashSync.cs);
- {
- const Byte *beforePtr = Inline_MatchFinder_GetPointerToCurrentPos(mf);
- ptrdiff_t offset;
- MatchFinder_MoveBlock(mf);
- offset = beforePtr - Inline_MatchFinder_GetPointerToCurrentPos(mf);
- mt->pointerToCurPos -= offset;
- mt->buffer -= offset;
- }
- CriticalSection_Leave(&mt->btSync.cs);
- CriticalSection_Leave(&mt->hashSync.cs);
- continue;
- }
-
- Semaphore_Wait(&p->freeSemaphore);
-
- MatchFinder_ReadIfRequired(mf);
- if (mf->pos > (kMtMaxValForNormalize - kMtHashBlockSize))
- {
- UInt32 subValue = (mf->pos - mf->historySize - 1);
- MatchFinder_ReduceOffsets(mf, subValue);
- MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, (size_t)mf->hashMask + 1);
- }
- {
- UInt32 *heads = mt->hashBuf + ((numProcessedBlocks++) & kMtHashNumBlocksMask) * kMtHashBlockSize;
- UInt32 num = mf->streamPos - mf->pos;
- heads[0] = 2;
- heads[1] = num;
- if (num >= mf->numHashBytes)
- {
- num = num - mf->numHashBytes + 1;
- if (num > kMtHashBlockSize - 2)
- num = kMtHashBlockSize - 2;
- mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc);
- heads[0] = 2 + num;
- }
- mf->pos += num;
- mf->buffer += num;
- }
- }
-
- Semaphore_Release1(&p->filledSemaphore);
- }
- }
-}
-
-static void MatchFinderMt_GetNextBlock_Hash(CMatchFinderMt *p)
-{
- MtSync_GetNextBlock(&p->hashSync);
- p->hashBufPosLimit = p->hashBufPos = ((p->hashSync.numProcessedBlocks - 1) & kMtHashNumBlocksMask) * kMtHashBlockSize;
- p->hashBufPosLimit += p->hashBuf[p->hashBufPos++];
- p->hashNumAvail = p->hashBuf[p->hashBufPos++];
-}
-
-#define kEmptyHashValue 0
-
-#define MFMT_GM_INLINE
-
-#ifdef MFMT_GM_INLINE
-
-/*
- we use size_t for _cyclicBufferPos instead of UInt32
- to eliminate "movsx" BUG in old MSVC x64 compiler.
-*/
-
-MY_NO_INLINE
-static UInt32 *GetMatchesSpecN(UInt32 lenLimit, UInt32 pos, const Byte *cur, CLzRef *son,
- size_t _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
- UInt32 *distances, UInt32 _maxLen, const UInt32 *hash, const UInt32 *limit, UInt32 size, UInt32 *posRes)
-{
- do
- {
- UInt32 *_distances = ++distances;
- UInt32 delta = *hash++;
-
- CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1;
- CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
- unsigned len0 = 0, len1 = 0;
- UInt32 cutValue = _cutValue;
- unsigned maxLen = (unsigned)_maxLen;
-
- /*
- if (size > 1)
- {
- UInt32 delta = *hash;
- if (delta < _cyclicBufferSize)
- {
- UInt32 cyc1 = _cyclicBufferPos + 1;
- CLzRef *pair = son + ((size_t)(cyc1 - delta + ((delta > cyc1) ? _cyclicBufferSize : 0)) << 1);
- Byte b = *(cur + 1 - delta);
- _distances[0] = pair[0];
- _distances[1] = b;
- }
- }
- */
- if (cutValue == 0 || delta >= _cyclicBufferSize)
- {
- *ptr0 = *ptr1 = kEmptyHashValue;
- }
- else
- for(;;)
- {
- {
- CLzRef *pair = son + ((size_t)(_cyclicBufferPos - delta + ((_cyclicBufferPos < delta) ? _cyclicBufferSize : 0)) << 1);
- const Byte *pb = cur - delta;
- unsigned len = (len0 < len1 ? len0 : len1);
- UInt32 pair0 = *pair;
- if (pb[len] == cur[len])
- {
- if (++len != lenLimit && pb[len] == cur[len])
- while (++len != lenLimit)
- if (pb[len] != cur[len])
- break;
- if (maxLen < len)
- {
- maxLen = len;
- *distances++ = (UInt32)len;
- *distances++ = delta - 1;
- if (len == lenLimit)
- {
- UInt32 pair1 = pair[1];
- *ptr1 = pair0;
- *ptr0 = pair1;
- break;
- }
- }
- }
- {
- UInt32 curMatch = pos - delta;
- // delta = pos - *pair;
- // delta = pos - pair[((UInt32)pb[len] - (UInt32)cur[len]) >> 31];
- if (pb[len] < cur[len])
- {
- delta = pos - pair[1];
- *ptr1 = curMatch;
- ptr1 = pair + 1;
- len1 = len;
- }
- else
- {
- delta = pos - *pair;
- *ptr0 = curMatch;
- ptr0 = pair;
- len0 = len;
- }
- }
- }
- if (--cutValue == 0 || delta >= _cyclicBufferSize)
- {
- *ptr0 = *ptr1 = kEmptyHashValue;
- break;
- }
- }
- pos++;
- _cyclicBufferPos++;
- cur++;
- {
- UInt32 num = (UInt32)(distances - _distances);
- _distances[-1] = num;
- }
- }
- while (distances < limit && --size != 0);
- *posRes = pos;
- return distances;
-}
-
-#endif
-
-
-
-static void BtGetMatches(CMatchFinderMt *p, UInt32 *distances)
-{
- UInt32 numProcessed = 0;
- UInt32 curPos = 2;
- UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2); // * 2
-
- distances[1] = p->hashNumAvail;
-
- while (curPos < limit)
- {
- if (p->hashBufPos == p->hashBufPosLimit)
- {
- MatchFinderMt_GetNextBlock_Hash(p);
- distances[1] = numProcessed + p->hashNumAvail;
- if (p->hashNumAvail >= p->numHashBytes)
- continue;
- distances[0] = curPos + p->hashNumAvail;
- distances += curPos;
- for (; p->hashNumAvail != 0; p->hashNumAvail--)
- *distances++ = 0;
- return;
- }
- {
- UInt32 size = p->hashBufPosLimit - p->hashBufPos;
- UInt32 lenLimit = p->matchMaxLen;
- UInt32 pos = p->pos;
- UInt32 cyclicBufferPos = p->cyclicBufferPos;
- if (lenLimit >= p->hashNumAvail)
- lenLimit = p->hashNumAvail;
- {
- UInt32 size2 = p->hashNumAvail - lenLimit + 1;
- if (size2 < size)
- size = size2;
- size2 = p->cyclicBufferSize - cyclicBufferPos;
- if (size2 < size)
- size = size2;
- }
-
- #ifndef MFMT_GM_INLINE
- while (curPos < limit && size-- != 0)
- {
- UInt32 *startDistances = distances + curPos;
- UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++],
- pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue,
- startDistances + 1, p->numHashBytes - 1) - startDistances);
- *startDistances = num - 1;
- curPos += num;
- cyclicBufferPos++;
- pos++;
- p->buffer++;
- }
- #else
- {
- UInt32 posRes;
- curPos = (UInt32)(GetMatchesSpecN(lenLimit, pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue,
- distances + curPos, p->numHashBytes - 1, p->hashBuf + p->hashBufPos,
- distances + limit,
- size, &posRes) - distances);
- p->hashBufPos += posRes - pos;
- cyclicBufferPos += posRes - pos;
- p->buffer += posRes - pos;
- pos = posRes;
- }
- #endif
-
- numProcessed += pos - p->pos;
- p->hashNumAvail -= pos - p->pos;
- p->pos = pos;
- if (cyclicBufferPos == p->cyclicBufferSize)
- cyclicBufferPos = 0;
- p->cyclicBufferPos = cyclicBufferPos;
- }
- }
-
- distances[0] = curPos;
-}
-
-static void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex)
-{
- CMtSync *sync = &p->hashSync;
- if (!sync->needStart)
- {
- CriticalSection_Enter(&sync->cs);
- sync->csWasEntered = True;
- }
-
- BtGetMatches(p, p->btBuf + (globalBlockIndex & kMtBtNumBlocksMask) * kMtBtBlockSize);
-
- if (p->pos > kMtMaxValForNormalize - kMtBtBlockSize)
- {
- UInt32 subValue = p->pos - p->cyclicBufferSize;
- MatchFinder_Normalize3(subValue, p->son, (size_t)p->cyclicBufferSize * 2);
- p->pos -= subValue;
- }
-
- if (!sync->needStart)
- {
- CriticalSection_Leave(&sync->cs);
- sync->csWasEntered = False;
- }
-}
-
-void BtThreadFunc(CMatchFinderMt *mt)
-{
- CMtSync *p = &mt->btSync;
- for (;;)
- {
- UInt32 blockIndex = 0;
- Event_Wait(&p->canStart);
- Event_Set(&p->wasStarted);
- for (;;)
- {
- if (p->exit)
- return;
- if (p->stopWriting)
- {
- p->numProcessedBlocks = blockIndex;
- MtSync_StopWriting(&mt->hashSync);
- Event_Set(&p->wasStopped);
- break;
- }
- Semaphore_Wait(&p->freeSemaphore);
- BtFillBlock(mt, blockIndex++);
- Semaphore_Release1(&p->filledSemaphore);
- }
- }
-}
-
-void MatchFinderMt_Construct(CMatchFinderMt *p)
-{
- p->hashBuf = NULL;
- MtSync_Construct(&p->hashSync);
- MtSync_Construct(&p->btSync);
-}
-
-static void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAllocPtr alloc)
-{
- ISzAlloc_Free(alloc, p->hashBuf);
- p->hashBuf = NULL;
-}
-
-void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc)
-{
- MtSync_Destruct(&p->hashSync);
- MtSync_Destruct(&p->btSync);
- MatchFinderMt_FreeMem(p, alloc);
-}
-
-#define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks)
-#define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks)
-
-static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; }
-static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE BtThreadFunc2(void *p)
-{
- Byte allocaDummy[0x180];
- unsigned i = 0;
- for (i = 0; i < 16; i++)
- allocaDummy[i] = (Byte)0;
- if (allocaDummy[0] == 0)
- BtThreadFunc((CMatchFinderMt *)p);
- return 0;
-}
-
-SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore,
- UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc)
-{
- CMatchFinder *mf = p->MatchFinder;
- p->historySize = historySize;
- if (kMtBtBlockSize <= matchMaxLen * 4)
- return SZ_ERROR_PARAM;
- if (!p->hashBuf)
- {
- p->hashBuf = (UInt32 *)ISzAlloc_Alloc(alloc, (kHashBufferSize + kBtBufferSize) * sizeof(UInt32));
- if (!p->hashBuf)
- return SZ_ERROR_MEM;
- p->btBuf = p->hashBuf + kHashBufferSize;
- }
- keepAddBufferBefore += (kHashBufferSize + kBtBufferSize);
- keepAddBufferAfter += kMtHashBlockSize;
- if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc))
- return SZ_ERROR_MEM;
-
- RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p, kMtHashNumBlocks));
- RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p, kMtBtNumBlocks));
- return SZ_OK;
-}
-
-/* Call it after ReleaseStream / SetStream */
-static void MatchFinderMt_Init(CMatchFinderMt *p)
-{
- CMatchFinder *mf = p->MatchFinder;
-
- p->btBufPos =
- p->btBufPosLimit = 0;
- p->hashBufPos =
- p->hashBufPosLimit = 0;
-
- /* Init without data reading. We don't want to read data in this thread */
- MatchFinder_Init_3(mf, False);
- MatchFinder_Init_LowHash(mf);
-
- p->pointerToCurPos = Inline_MatchFinder_GetPointerToCurrentPos(mf);
- p->btNumAvailBytes = 0;
- p->lzPos = p->historySize + 1;
-
- p->hash = mf->hash;
- p->fixedHashSize = mf->fixedHashSize;
- p->crc = mf->crc;
-
- p->son = mf->son;
- p->matchMaxLen = mf->matchMaxLen;
- p->numHashBytes = mf->numHashBytes;
- p->pos = mf->pos;
- p->buffer = mf->buffer;
- p->cyclicBufferPos = mf->cyclicBufferPos;
- p->cyclicBufferSize = mf->cyclicBufferSize;
- p->cutValue = mf->cutValue;
-}
-
-/* ReleaseStream is required to finish multithreading */
-void MatchFinderMt_ReleaseStream(CMatchFinderMt *p)
-{
- MtSync_StopWriting(&p->btSync);
- /* p->MatchFinder->ReleaseStream(); */
-}
-
-static void MatchFinderMt_Normalize(CMatchFinderMt *p)
-{
- MatchFinder_Normalize3(p->lzPos - p->historySize - 1, p->hash, p->fixedHashSize);
- p->lzPos = p->historySize + 1;
-}
-
-static void MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p)
-{
- UInt32 blockIndex;
- MtSync_GetNextBlock(&p->btSync);
- blockIndex = ((p->btSync.numProcessedBlocks - 1) & kMtBtNumBlocksMask);
- p->btBufPosLimit = p->btBufPos = blockIndex * kMtBtBlockSize;
- p->btBufPosLimit += p->btBuf[p->btBufPos++];
- p->btNumAvailBytes = p->btBuf[p->btBufPos++];
- if (p->lzPos >= kMtMaxValForNormalize - kMtBtBlockSize)
- MatchFinderMt_Normalize(p);
-}
-
-static const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p)
-{
- return p->pointerToCurPos;
-}
-
-#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p);
-
-static UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p)
-{
- GET_NEXT_BLOCK_IF_REQUIRED;
- return p->btNumAvailBytes;
-}
-
-static UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
-{
- UInt32 h2, curMatch2;
- UInt32 *hash = p->hash;
- const Byte *cur = p->pointerToCurPos;
- UInt32 lzPos = p->lzPos;
- MT_HASH2_CALC
-
- curMatch2 = hash[h2];
- hash[h2] = lzPos;
-
- if (curMatch2 >= matchMinPos)
- if (cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
- {
- *distances++ = 2;
- *distances++ = lzPos - curMatch2 - 1;
- }
-
- return distances;
-}
-
-static UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
-{
- UInt32 h2, h3, curMatch2, curMatch3;
- UInt32 *hash = p->hash;
- const Byte *cur = p->pointerToCurPos;
- UInt32 lzPos = p->lzPos;
- MT_HASH3_CALC
-
- curMatch2 = hash[ h2];
- curMatch3 = (hash + kFix3HashSize)[h3];
-
- hash[ h2] = lzPos;
- (hash + kFix3HashSize)[h3] = lzPos;
-
- if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
- {
- distances[1] = lzPos - curMatch2 - 1;
- if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
- {
- distances[0] = 3;
- return distances + 2;
- }
- distances[0] = 2;
- distances += 2;
- }
-
- if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
- {
- *distances++ = 3;
- *distances++ = lzPos - curMatch3 - 1;
- }
-
- return distances;
-}
-
-/*
-static UInt32 *MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *distances)
-{
- UInt32 h2, h3, h4, curMatch2, curMatch3, curMatch4;
- UInt32 *hash = p->hash;
- const Byte *cur = p->pointerToCurPos;
- UInt32 lzPos = p->lzPos;
- MT_HASH4_CALC
-
- curMatch2 = hash[ h2];
- curMatch3 = (hash + kFix3HashSize)[h3];
- curMatch4 = (hash + kFix4HashSize)[h4];
-
- hash[ h2] = lzPos;
- (hash + kFix3HashSize)[h3] = lzPos;
- (hash + kFix4HashSize)[h4] = lzPos;
-
- if (curMatch2 >= matchMinPos && cur[(ptrdiff_t)curMatch2 - lzPos] == cur[0])
- {
- distances[1] = lzPos - curMatch2 - 1;
- if (cur[(ptrdiff_t)curMatch2 - lzPos + 2] == cur[2])
- {
- distances[0] = (cur[(ptrdiff_t)curMatch2 - lzPos + 3] == cur[3]) ? 4 : 3;
- return distances + 2;
- }
- distances[0] = 2;
- distances += 2;
- }
-
- if (curMatch3 >= matchMinPos && cur[(ptrdiff_t)curMatch3 - lzPos] == cur[0])
- {
- distances[1] = lzPos - curMatch3 - 1;
- if (cur[(ptrdiff_t)curMatch3 - lzPos + 3] == cur[3])
- {
- distances[0] = 4;
- return distances + 2;
- }
- distances[0] = 3;
- distances += 2;
- }
-
- if (curMatch4 >= matchMinPos)
- if (
- cur[(ptrdiff_t)curMatch4 - lzPos] == cur[0] &&
- cur[(ptrdiff_t)curMatch4 - lzPos + 3] == cur[3]
- )
- {
- *distances++ = 4;
- *distances++ = lzPos - curMatch4 - 1;
- }
-
- return distances;
-}
-*/
-
-#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++;
-
-static UInt32 MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *distances)
-{
- const UInt32 *btBuf = p->btBuf + p->btBufPos;
- UInt32 len = *btBuf++;
- p->btBufPos += 1 + len;
- p->btNumAvailBytes--;
- {
- UInt32 i;
- for (i = 0; i < len; i += 2)
- {
- UInt32 v0 = btBuf[0];
- UInt32 v1 = btBuf[1];
- btBuf += 2;
- distances[0] = v0;
- distances[1] = v1;
- distances += 2;
- }
- }
- INCREASE_LZ_POS
- return len;
-}
-
-static UInt32 MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *distances)
-{
- const UInt32 *btBuf = p->btBuf + p->btBufPos;
- UInt32 len = *btBuf++;
- p->btBufPos += 1 + len;
-
- if (len == 0)
- {
- /* change for bt5 ! */
- if (p->btNumAvailBytes-- >= 4)
- len = (UInt32)(p->MixMatchesFunc(p, p->lzPos - p->historySize, distances) - (distances));
- }
- else
- {
- /* Condition: there are matches in btBuf with length < p->numHashBytes */
- UInt32 *distances2;
- p->btNumAvailBytes--;
- distances2 = p->MixMatchesFunc(p, p->lzPos - btBuf[1], distances);
- do
- {
- UInt32 v0 = btBuf[0];
- UInt32 v1 = btBuf[1];
- btBuf += 2;
- distances2[0] = v0;
- distances2[1] = v1;
- distances2 += 2;
- }
- while ((len -= 2) != 0);
- len = (UInt32)(distances2 - (distances));
- }
- INCREASE_LZ_POS
- return len;
-}
-
-#define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED
-#define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash;
-#define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += p->btBuf[p->btBufPos] + 1; } while (--num != 0);
-
-static void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num)
-{
- SKIP_HEADER2_MT { p->btNumAvailBytes--;
- SKIP_FOOTER_MT
-}
-
-static void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num)
-{
- SKIP_HEADER_MT(2)
- UInt32 h2;
- MT_HASH2_CALC
- hash[h2] = p->lzPos;
- SKIP_FOOTER_MT
-}
-
-static void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num)
-{
- SKIP_HEADER_MT(3)
- UInt32 h2, h3;
- MT_HASH3_CALC
- (hash + kFix3HashSize)[h3] =
- hash[ h2] =
- p->lzPos;
- SKIP_FOOTER_MT
-}
-
-/*
-static void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num)
-{
- SKIP_HEADER_MT(4)
- UInt32 h2, h3, h4;
- MT_HASH4_CALC
- (hash + kFix4HashSize)[h4] =
- (hash + kFix3HashSize)[h3] =
- hash[ h2] =
- p->lzPos;
- SKIP_FOOTER_MT
-}
-*/
-
-void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable)
-{
- vTable->Init = (Mf_Init_Func)MatchFinderMt_Init;
- vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes;
- vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos;
- vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches;
-
- switch (p->MatchFinder->numHashBytes)
- {
- case 2:
- p->GetHeadsFunc = GetHeads2;
- p->MixMatchesFunc = (Mf_Mix_Matches)NULL;
- vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip;
- vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches;
- break;
- case 3:
- p->GetHeadsFunc = GetHeads3;
- p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2;
- vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip;
- break;
- default:
- /* case 4: */
- p->GetHeadsFunc = p->MatchFinder->bigHash ? GetHeads4b : GetHeads4;
- p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3;
- vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip;
- break;
- /*
- default:
- p->GetHeadsFunc = GetHeads5;
- p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4;
- vTable->Skip = (Mf_Skip_Func)MatchFinderMt4_Skip;
- break;
- */
- }
-}
+/* LzFindMt.c -- multithreaded Match finder for LZ algorithms
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+// #include <stdio.h>
+
+#include "CpuArch.h"
+
+#include "LzHash.h"
+#include "LzFindMt.h"
+
+// #define LOG_ITERS
+
+// #define LOG_THREAD
+
+#ifdef LOG_THREAD
+#include <stdio.h>
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#ifdef LOG_ITERS
+#include <stdio.h>
+extern UInt64 g_NumIters_Tree;
+extern UInt64 g_NumIters_Loop;
+extern UInt64 g_NumIters_Bytes;
+#define LOG_ITER(x) x
+#else
+#define LOG_ITER(x)
+#endif
+
+#define kMtHashBlockSize ((UInt32)1 << 17)
+#define kMtHashNumBlocks (1 << 1)
+
+#define GET_HASH_BLOCK_OFFSET(i) (((i) & (kMtHashNumBlocks - 1)) * kMtHashBlockSize)
+
+#define kMtBtBlockSize ((UInt32)1 << 16)
+#define kMtBtNumBlocks (1 << 4)
+
+#define GET_BT_BLOCK_OFFSET(i) (((i) & (kMtBtNumBlocks - 1)) * (size_t)kMtBtBlockSize)
+
+/*
+ HASH functions:
+ We use raw 8/16 bits from a[1] and a[2],
+ xored with crc(a[0]) and crc(a[3]).
+ We check a[0], a[3] only. We don't need to compare a[1] and a[2] in matches.
+ our crc() function provides one-to-one correspondence for low 8-bit values:
+ (crc[0...0xFF] & 0xFF) <-> [0...0xFF]
+*/
+
+#define MF(mt) ((mt)->MatchFinder)
+#define MF_CRC (p->crc)
+
+// #define MF(mt) (&(mt)->MatchFinder)
+// #define MF_CRC (p->MatchFinder.crc)
+
+#define MT_HASH2_CALC \
+ h2 = (MF_CRC[cur[0]] ^ cur[1]) & (kHash2Size - 1);
+
+#define MT_HASH3_CALC { \
+ UInt32 temp = MF_CRC[cur[0]] ^ cur[1]; \
+ h2 = temp & (kHash2Size - 1); \
+ h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
+
+/*
+#define MT_HASH3_CALC__NO_2 { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
+
+#define MT_HASH4_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ h2 = temp & (kHash2Size - 1); \
+ temp ^= ((UInt32)cur[2] << 8); \
+ h3 = temp & (kHash3Size - 1); \
+ h4 = (temp ^ (p->crc[cur[3]] << kLzHash_CrcShift_1)) & p->hash4Mask; }
+ // (kHash4Size - 1);
+*/
+
+
+Z7_NO_INLINE
+static void MtSync_Construct(CMtSync *p)
+{
+ p->affinity = 0;
+ p->wasCreated = False;
+ p->csWasInitialized = False;
+ p->csWasEntered = False;
+ Thread_CONSTRUCT(&p->thread)
+ Event_Construct(&p->canStart);
+ Event_Construct(&p->wasStopped);
+ Semaphore_Construct(&p->freeSemaphore);
+ Semaphore_Construct(&p->filledSemaphore);
+}
+
+
+#define DEBUG_BUFFER_LOCK // define it to debug lock state
+
+#ifdef DEBUG_BUFFER_LOCK
+#include <stdlib.h>
+#define BUFFER_MUST_BE_LOCKED(p) if (!(p)->csWasEntered) exit(1);
+#define BUFFER_MUST_BE_UNLOCKED(p) if ( (p)->csWasEntered) exit(1);
+#else
+#define BUFFER_MUST_BE_LOCKED(p)
+#define BUFFER_MUST_BE_UNLOCKED(p)
+#endif
+
+#define LOCK_BUFFER(p) { \
+ BUFFER_MUST_BE_UNLOCKED(p); \
+ CriticalSection_Enter(&(p)->cs); \
+ (p)->csWasEntered = True; }
+
+#define UNLOCK_BUFFER(p) { \
+ BUFFER_MUST_BE_LOCKED(p); \
+ CriticalSection_Leave(&(p)->cs); \
+ (p)->csWasEntered = False; }
+
+
+Z7_NO_INLINE
+static UInt32 MtSync_GetNextBlock(CMtSync *p)
+{
+ UInt32 numBlocks = 0;
+ if (p->needStart)
+ {
+ BUFFER_MUST_BE_UNLOCKED(p)
+ p->numProcessedBlocks = 1;
+ p->needStart = False;
+ p->stopWriting = False;
+ p->exit = False;
+ Event_Reset(&p->wasStopped);
+ Event_Set(&p->canStart);
+ }
+ else
+ {
+ UNLOCK_BUFFER(p)
+ // we free current block
+ numBlocks = p->numProcessedBlocks++;
+ Semaphore_Release1(&p->freeSemaphore);
+ }
+
+ // buffer is UNLOCKED here
+ Semaphore_Wait(&p->filledSemaphore);
+ LOCK_BUFFER(p)
+ return numBlocks;
+}
+
+
+/* if Writing (Processing) thread was started, we must call MtSync_StopWriting() */
+
+Z7_NO_INLINE
+static void MtSync_StopWriting(CMtSync *p)
+{
+ if (!Thread_WasCreated(&p->thread) || p->needStart)
+ return;
+
+ PRF(printf("\nMtSync_StopWriting %p\n", p));
+
+ if (p->csWasEntered)
+ {
+ /* we don't use buffer in this thread after StopWriting().
+ So we UNLOCK buffer.
+ And we restore default UNLOCKED state for stopped thread */
+ UNLOCK_BUFFER(p)
+ }
+
+ /* We send (p->stopWriting) message and release freeSemaphore
+ to free current block.
+ So the thread will see (p->stopWriting) at some
+ iteration after Wait(freeSemaphore).
+ The thread doesn't need to fill all avail free blocks,
+ so we can get fast thread stop.
+ */
+
+ p->stopWriting = True;
+ Semaphore_Release1(&p->freeSemaphore); // check semaphore count !!!
+
+ PRF(printf("\nMtSync_StopWriting %p : Event_Wait(&p->wasStopped)\n", p));
+ Event_Wait(&p->wasStopped);
+ PRF(printf("\nMtSync_StopWriting %p : Event_Wait() finsihed\n", p));
+
+ /* 21.03 : we don't restore samaphore counters here.
+ We will recreate and reinit samaphores in next start */
+
+ p->needStart = True;
+}
+
+
+Z7_NO_INLINE
+static void MtSync_Destruct(CMtSync *p)
+{
+ PRF(printf("\nMtSync_Destruct %p\n", p));
+
+ if (Thread_WasCreated(&p->thread))
+ {
+ /* we want thread to be in Stopped state before sending EXIT command.
+ note: stop(btSync) will stop (htSync) also */
+ MtSync_StopWriting(p);
+ /* thread in Stopped state here : (p->needStart == true) */
+ p->exit = True;
+ // if (p->needStart) // it's (true)
+ Event_Set(&p->canStart); // we send EXIT command to thread
+ Thread_Wait_Close(&p->thread); // we wait thread finishing
+ }
+
+ if (p->csWasInitialized)
+ {
+ CriticalSection_Delete(&p->cs);
+ p->csWasInitialized = False;
+ }
+ p->csWasEntered = False;
+
+ Event_Close(&p->canStart);
+ Event_Close(&p->wasStopped);
+ Semaphore_Close(&p->freeSemaphore);
+ Semaphore_Close(&p->filledSemaphore);
+
+ p->wasCreated = False;
+}
+
+
+// #define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; }
+// we want to get real system error codes here instead of SZ_ERROR_THREAD
+#define RINOK_THREAD(x) RINOK_WRes(x)
+
+
+// call it before each new file (when new starting is required):
+Z7_NO_INLINE
+static SRes MtSync_Init(CMtSync *p, UInt32 numBlocks)
+{
+ WRes wres;
+ // BUFFER_MUST_BE_UNLOCKED(p)
+ if (!p->needStart || p->csWasEntered)
+ return SZ_ERROR_FAIL;
+ wres = Semaphore_OptCreateInit(&p->freeSemaphore, numBlocks, numBlocks);
+ if (wres == 0)
+ wres = Semaphore_OptCreateInit(&p->filledSemaphore, 0, numBlocks);
+ return MY_SRes_HRESULT_FROM_WRes(wres);
+}
+
+
+static WRes MtSync_Create_WRes(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj)
+{
+ WRes wres;
+
+ if (p->wasCreated)
+ return SZ_OK;
+
+ RINOK_THREAD(CriticalSection_Init(&p->cs))
+ p->csWasInitialized = True;
+ p->csWasEntered = False;
+
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->canStart))
+ RINOK_THREAD(AutoResetEvent_CreateNotSignaled(&p->wasStopped))
+
+ p->needStart = True;
+ p->exit = True; /* p->exit is unused before (canStart) Event.
+ But in case of some unexpected code failure we will get fast exit from thread */
+
+ // return ERROR_TOO_MANY_POSTS; // for debug
+ // return EINVAL; // for debug
+
+ if (p->affinity != 0)
+ wres = Thread_Create_With_Affinity(&p->thread, startAddress, obj, (CAffinityMask)p->affinity);
+ else
+ wres = Thread_Create(&p->thread, startAddress, obj);
+
+ RINOK_THREAD(wres)
+ p->wasCreated = True;
+ return SZ_OK;
+}
+
+
+Z7_NO_INLINE
+static SRes MtSync_Create(CMtSync *p, THREAD_FUNC_TYPE startAddress, void *obj)
+{
+ const WRes wres = MtSync_Create_WRes(p, startAddress, obj);
+ if (wres == 0)
+ return 0;
+ MtSync_Destruct(p);
+ return MY_SRes_HRESULT_FROM_WRes(wres);
+}
+
+
+// ---------- HASH THREAD ----------
+
+#define kMtMaxValForNormalize 0xFFFFFFFF
+// #define kMtMaxValForNormalize ((1 << 21)) // for debug
+// #define kNormalizeAlign (1 << 7) // alignment for speculated accesses
+
+#ifdef MY_CPU_LE_UNALIGN
+ #define GetUi24hi_from32(p) ((UInt32)GetUi32(p) >> 8)
+#else
+ #define GetUi24hi_from32(p) ((p)[1] ^ ((UInt32)(p)[2] << 8) ^ ((UInt32)(p)[3] << 16))
+#endif
+
+#define GetHeads_DECL(name) \
+ static void GetHeads ## name(const Byte *p, UInt32 pos, \
+ UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc)
+
+#define GetHeads_LOOP(v) \
+ for (; numHeads != 0; numHeads--) { \
+ const UInt32 value = (v); \
+ p++; \
+ *heads++ = pos - hash[value]; \
+ hash[value] = pos++; }
+
+#define DEF_GetHeads2(name, v, action) \
+ GetHeads_DECL(name) { action \
+ GetHeads_LOOP(v) }
+
+#define DEF_GetHeads(name, v) DEF_GetHeads2(name, v, ;)
+
+DEF_GetHeads2(2, GetUi16(p), UNUSED_VAR(hashMask); UNUSED_VAR(crc); )
+DEF_GetHeads(3, (crc[p[0]] ^ GetUi16(p + 1)) & hashMask)
+DEF_GetHeads2(3b, GetUi16(p) ^ ((UInt32)(p)[2] << 16), UNUSED_VAR(hashMask); UNUSED_VAR(crc); )
+// BT3 is not good for crc collisions for big hashMask values.
+
+/*
+GetHeads_DECL(3b)
+{
+ UNUSED_VAR(hashMask);
+ UNUSED_VAR(crc);
+ {
+ const Byte *pLim = p + numHeads;
+ if (numHeads == 0)
+ return;
+ pLim--;
+ while (p < pLim)
+ {
+ UInt32 v1 = GetUi32(p);
+ UInt32 v0 = v1 & 0xFFFFFF;
+ UInt32 h0, h1;
+ p += 2;
+ v1 >>= 8;
+ h0 = hash[v0]; hash[v0] = pos; heads[0] = pos - h0; pos++;
+ h1 = hash[v1]; hash[v1] = pos; heads[1] = pos - h1; pos++;
+ heads += 2;
+ }
+ if (p == pLim)
+ {
+ UInt32 v0 = GetUi16(p) ^ ((UInt32)(p)[2] << 16);
+ *heads = pos - hash[v0];
+ hash[v0] = pos;
+ }
+ }
+}
+*/
+
+/*
+GetHeads_DECL(4)
+{
+ unsigned sh = 0;
+ UNUSED_VAR(crc)
+ while ((hashMask & 0x80000000) == 0)
+ {
+ hashMask <<= 1;
+ sh++;
+ }
+ GetHeads_LOOP((GetUi32(p) * 0xa54a1) >> sh)
+}
+#define GetHeads4b GetHeads4
+*/
+
+#define USE_GetHeads_LOCAL_CRC
+
+#ifdef USE_GetHeads_LOCAL_CRC
+
+GetHeads_DECL(4)
+{
+ UInt32 crc0[256];
+ UInt32 crc1[256];
+ {
+ unsigned i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 v = crc[i];
+ crc0[i] = v & hashMask;
+ crc1[i] = (v << kLzHash_CrcShift_1) & hashMask;
+ // crc1[i] = rotlFixed(v, 8) & hashMask;
+ }
+ }
+ GetHeads_LOOP(crc0[p[0]] ^ crc1[p[3]] ^ (UInt32)GetUi16(p+1))
+}
+
+GetHeads_DECL(4b)
+{
+ UInt32 crc0[256];
+ {
+ unsigned i;
+ for (i = 0; i < 256; i++)
+ crc0[i] = crc[i] & hashMask;
+ }
+ GetHeads_LOOP(crc0[p[0]] ^ GetUi24hi_from32(p))
+}
+
+GetHeads_DECL(5)
+{
+ UInt32 crc0[256];
+ UInt32 crc1[256];
+ UInt32 crc2[256];
+ {
+ unsigned i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 v = crc[i];
+ crc0[i] = v & hashMask;
+ crc1[i] = (v << kLzHash_CrcShift_1) & hashMask;
+ crc2[i] = (v << kLzHash_CrcShift_2) & hashMask;
+ }
+ }
+ GetHeads_LOOP(crc0[p[0]] ^ crc1[p[3]] ^ crc2[p[4]] ^ (UInt32)GetUi16(p+1))
+}
+
+GetHeads_DECL(5b)
+{
+ UInt32 crc0[256];
+ UInt32 crc1[256];
+ {
+ unsigned i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 v = crc[i];
+ crc0[i] = v & hashMask;
+ crc1[i] = (v << kLzHash_CrcShift_1) & hashMask;
+ }
+ }
+ GetHeads_LOOP(crc0[p[0]] ^ crc1[p[4]] ^ GetUi24hi_from32(p))
+}
+
+#else
+
+DEF_GetHeads(4, (crc[p[0]] ^ (crc[p[3]] << kLzHash_CrcShift_1) ^ (UInt32)GetUi16(p+1)) & hashMask)
+DEF_GetHeads(4b, (crc[p[0]] ^ GetUi24hi_from32(p)) & hashMask)
+DEF_GetHeads(5, (crc[p[0]] ^ (crc[p[3]] << kLzHash_CrcShift_1) ^ (crc[p[4]] << kLzHash_CrcShift_2) ^ (UInt32)GetUi16(p + 1)) & hashMask)
+DEF_GetHeads(5b, (crc[p[0]] ^ (crc[p[4]] << kLzHash_CrcShift_1) ^ GetUi24hi_from32(p)) & hashMask)
+
+#endif
+
+
+static void HashThreadFunc(CMatchFinderMt *mt)
+{
+ CMtSync *p = &mt->hashSync;
+ PRF(printf("\nHashThreadFunc\n"));
+
+ for (;;)
+ {
+ UInt32 blockIndex = 0;
+ PRF(printf("\nHashThreadFunc : Event_Wait(&p->canStart)\n"));
+ Event_Wait(&p->canStart);
+ PRF(printf("\nHashThreadFunc : Event_Wait(&p->canStart) : after \n"));
+ if (p->exit)
+ {
+ PRF(printf("\nHashThreadFunc : exit \n"));
+ return;
+ }
+
+ MatchFinder_Init_HighHash(MF(mt));
+
+ for (;;)
+ {
+ PRF(printf("Hash thread block = %d pos = %d\n", (unsigned)blockIndex, mt->MatchFinder->pos));
+
+ {
+ CMatchFinder *mf = MF(mt);
+ if (MatchFinder_NeedMove(mf))
+ {
+ CriticalSection_Enter(&mt->btSync.cs);
+ CriticalSection_Enter(&mt->hashSync.cs);
+ {
+ const Byte *beforePtr = Inline_MatchFinder_GetPointerToCurrentPos(mf);
+ ptrdiff_t offset;
+ MatchFinder_MoveBlock(mf);
+ offset = beforePtr - Inline_MatchFinder_GetPointerToCurrentPos(mf);
+ mt->pointerToCurPos -= offset;
+ mt->buffer -= offset;
+ }
+ CriticalSection_Leave(&mt->hashSync.cs);
+ CriticalSection_Leave(&mt->btSync.cs);
+ continue;
+ }
+
+ Semaphore_Wait(&p->freeSemaphore);
+
+ if (p->exit) // exit is unexpected here. But we check it here for some failure case
+ return;
+
+ // for faster stop : we check (p->stopWriting) after Wait(freeSemaphore)
+ if (p->stopWriting)
+ break;
+
+ MatchFinder_ReadIfRequired(mf);
+ {
+ UInt32 *heads = mt->hashBuf + GET_HASH_BLOCK_OFFSET(blockIndex++);
+ UInt32 num = Inline_MatchFinder_GetNumAvailableBytes(mf);
+ heads[0] = 2;
+ heads[1] = num;
+
+ /* heads[1] contains the number of avail bytes:
+ if (avail < mf->numHashBytes) :
+ {
+ it means that stream was finished
+ HASH_THREAD and BT_TREAD must move position for heads[1] (avail) bytes.
+ HASH_THREAD doesn't stop,
+ HASH_THREAD fills only the header (2 numbers) for all next blocks:
+ {2, NumHashBytes - 1}, {2,0}, {2,0}, ... , {2,0}
+ }
+ else
+ {
+ HASH_THREAD and BT_TREAD must move position for (heads[0] - 2) bytes;
+ }
+ */
+
+ if (num >= mf->numHashBytes)
+ {
+ num = num - mf->numHashBytes + 1;
+ if (num > kMtHashBlockSize - 2)
+ num = kMtHashBlockSize - 2;
+
+ if (mf->pos > (UInt32)kMtMaxValForNormalize - num)
+ {
+ const UInt32 subValue = (mf->pos - mf->historySize - 1); // & ~(UInt32)(kNormalizeAlign - 1);
+ MatchFinder_REDUCE_OFFSETS(mf, subValue)
+ MatchFinder_Normalize3(subValue, mf->hash + mf->fixedHashSize, (size_t)mf->hashMask + 1);
+ }
+
+ heads[0] = 2 + num;
+ mt->GetHeadsFunc(mf->buffer, mf->pos, mf->hash + mf->fixedHashSize, mf->hashMask, heads + 2, num, mf->crc);
+ }
+
+ mf->pos += num; // wrap over zero is allowed at the end of stream
+ mf->buffer += num;
+ }
+ }
+
+ Semaphore_Release1(&p->filledSemaphore);
+ } // for() processing end
+
+ // p->numBlocks_Sent = blockIndex;
+ Event_Set(&p->wasStopped);
+ } // for() thread end
+}
+
+
+
+
+// ---------- BT THREAD ----------
+
+/* we use one variable instead of two (cyclicBufferPos == pos) before CyclicBuf wrap.
+ here we define fixed offset of (p->pos) from (p->cyclicBufferPos) */
+#define CYC_TO_POS_OFFSET 0
+// #define CYC_TO_POS_OFFSET 1 // for debug
+
+#define MFMT_GM_INLINE
+
+#ifdef MFMT_GM_INLINE
+
+/*
+ we use size_t for (pos) instead of UInt32
+ to eliminate "movsx" BUG in old MSVC x64 compiler.
+*/
+
+
+UInt32 * Z7_FASTCALL GetMatchesSpecN_2(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son,
+ UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size,
+ size_t _cyclicBufferPos, UInt32 _cyclicBufferSize,
+ UInt32 *posRes);
+
+#endif
+
+
+static void BtGetMatches(CMatchFinderMt *p, UInt32 *d)
+{
+ UInt32 numProcessed = 0;
+ UInt32 curPos = 2;
+
+ /* GetMatchesSpec() functions don't create (len = 1)
+ in [len, dist] match pairs, if (p->numHashBytes >= 2)
+ Also we suppose here that (matchMaxLen >= 2).
+ So the following code for (reserve) is not required
+ UInt32 reserve = (p->matchMaxLen * 2);
+ const UInt32 kNumHashBytes_Max = 5; // BT_HASH_BYTES_MAX
+ if (reserve < kNumHashBytes_Max - 1)
+ reserve = kNumHashBytes_Max - 1;
+ const UInt32 limit = kMtBtBlockSize - (reserve);
+ */
+
+ const UInt32 limit = kMtBtBlockSize - (p->matchMaxLen * 2);
+
+ d[1] = p->hashNumAvail;
+
+ if (p->failure_BT)
+ {
+ // printf("\n == 1 BtGetMatches() p->failure_BT\n");
+ d[0] = 0;
+ // d[1] = 0;
+ return;
+ }
+
+ while (curPos < limit)
+ {
+ if (p->hashBufPos == p->hashBufPosLimit)
+ {
+ // MatchFinderMt_GetNextBlock_Hash(p);
+ UInt32 avail;
+ {
+ const UInt32 bi = MtSync_GetNextBlock(&p->hashSync);
+ const UInt32 k = GET_HASH_BLOCK_OFFSET(bi);
+ const UInt32 *h = p->hashBuf + k;
+ avail = h[1];
+ p->hashBufPosLimit = k + h[0];
+ p->hashNumAvail = avail;
+ p->hashBufPos = k + 2;
+ }
+
+ {
+ /* we must prevent UInt32 overflow for avail total value,
+ if avail was increased with new hash block */
+ UInt32 availSum = numProcessed + avail;
+ if (availSum < numProcessed)
+ availSum = (UInt32)(Int32)-1;
+ d[1] = availSum;
+ }
+
+ if (avail >= p->numHashBytes)
+ continue;
+
+ // if (p->hashBufPos != p->hashBufPosLimit) exit(1);
+
+ /* (avail < p->numHashBytes)
+ It means that stream was finished.
+ And (avail) - is a number of remaining bytes,
+ we fill (d) for (avail) bytes for LZ_THREAD (receiver).
+ but we don't update (p->pos) and (p->cyclicBufferPos) here in BT_THREAD */
+
+ /* here we suppose that we have space enough:
+ (kMtBtBlockSize - curPos >= p->hashNumAvail) */
+ p->hashNumAvail = 0;
+ d[0] = curPos + avail;
+ d += curPos;
+ for (; avail != 0; avail--)
+ *d++ = 0;
+ return;
+ }
+ {
+ UInt32 size = p->hashBufPosLimit - p->hashBufPos;
+ UInt32 pos = p->pos;
+ UInt32 cyclicBufferPos = p->cyclicBufferPos;
+ UInt32 lenLimit = p->matchMaxLen;
+ if (lenLimit >= p->hashNumAvail)
+ lenLimit = p->hashNumAvail;
+ {
+ UInt32 size2 = p->hashNumAvail - lenLimit + 1;
+ if (size2 < size)
+ size = size2;
+ size2 = p->cyclicBufferSize - cyclicBufferPos;
+ if (size2 < size)
+ size = size2;
+ }
+
+ if (pos > (UInt32)kMtMaxValForNormalize - size)
+ {
+ const UInt32 subValue = (pos - p->cyclicBufferSize); // & ~(UInt32)(kNormalizeAlign - 1);
+ pos -= subValue;
+ p->pos = pos;
+ MatchFinder_Normalize3(subValue, p->son, (size_t)p->cyclicBufferSize * 2);
+ }
+
+ #ifndef MFMT_GM_INLINE
+ while (curPos < limit && size-- != 0)
+ {
+ UInt32 *startDistances = d + curPos;
+ UInt32 num = (UInt32)(GetMatchesSpec1(lenLimit, pos - p->hashBuf[p->hashBufPos++],
+ pos, p->buffer, p->son, cyclicBufferPos, p->cyclicBufferSize, p->cutValue,
+ startDistances + 1, p->numHashBytes - 1) - startDistances);
+ *startDistances = num - 1;
+ curPos += num;
+ cyclicBufferPos++;
+ pos++;
+ p->buffer++;
+ }
+ #else
+ {
+ UInt32 posRes = pos;
+ const UInt32 *d_end;
+ {
+ d_end = GetMatchesSpecN_2(
+ p->buffer + lenLimit - 1,
+ pos, p->buffer, p->son, p->cutValue, d + curPos,
+ p->numHashBytes - 1, p->hashBuf + p->hashBufPos,
+ d + limit, p->hashBuf + p->hashBufPos + size,
+ cyclicBufferPos, p->cyclicBufferSize,
+ &posRes);
+ }
+ {
+ if (!d_end)
+ {
+ // printf("\n == 2 BtGetMatches() p->failure_BT\n");
+ // internal data failure
+ p->failure_BT = True;
+ d[0] = 0;
+ // d[1] = 0;
+ return;
+ }
+ }
+ curPos = (UInt32)(d_end - d);
+ {
+ const UInt32 processed = posRes - pos;
+ pos = posRes;
+ p->hashBufPos += processed;
+ cyclicBufferPos += processed;
+ p->buffer += processed;
+ }
+ }
+ #endif
+
+ {
+ const UInt32 processed = pos - p->pos;
+ numProcessed += processed;
+ p->hashNumAvail -= processed;
+ p->pos = pos;
+ }
+ if (cyclicBufferPos == p->cyclicBufferSize)
+ cyclicBufferPos = 0;
+ p->cyclicBufferPos = cyclicBufferPos;
+ }
+ }
+
+ d[0] = curPos;
+}
+
+
+static void BtFillBlock(CMatchFinderMt *p, UInt32 globalBlockIndex)
+{
+ CMtSync *sync = &p->hashSync;
+
+ BUFFER_MUST_BE_UNLOCKED(sync)
+
+ if (!sync->needStart)
+ {
+ LOCK_BUFFER(sync)
+ }
+
+ BtGetMatches(p, p->btBuf + GET_BT_BLOCK_OFFSET(globalBlockIndex));
+
+ /* We suppose that we have called GetNextBlock() from start.
+ So buffer is LOCKED */
+
+ UNLOCK_BUFFER(sync)
+}
+
+
+Z7_NO_INLINE
+static void BtThreadFunc(CMatchFinderMt *mt)
+{
+ CMtSync *p = &mt->btSync;
+ for (;;)
+ {
+ UInt32 blockIndex = 0;
+ Event_Wait(&p->canStart);
+
+ for (;;)
+ {
+ PRF(printf(" BT thread block = %d pos = %d\n", (unsigned)blockIndex, mt->pos));
+ /* (p->exit == true) is possible after (p->canStart) at first loop iteration
+ and is unexpected after more Wait(freeSemaphore) iterations */
+ if (p->exit)
+ return;
+
+ Semaphore_Wait(&p->freeSemaphore);
+
+ // for faster stop : we check (p->stopWriting) after Wait(freeSemaphore)
+ if (p->stopWriting)
+ break;
+
+ BtFillBlock(mt, blockIndex++);
+
+ Semaphore_Release1(&p->filledSemaphore);
+ }
+
+ // we stop HASH_THREAD here
+ MtSync_StopWriting(&mt->hashSync);
+
+ // p->numBlocks_Sent = blockIndex;
+ Event_Set(&p->wasStopped);
+ }
+}
+
+
+void MatchFinderMt_Construct(CMatchFinderMt *p)
+{
+ p->hashBuf = NULL;
+ MtSync_Construct(&p->hashSync);
+ MtSync_Construct(&p->btSync);
+}
+
+static void MatchFinderMt_FreeMem(CMatchFinderMt *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->hashBuf);
+ p->hashBuf = NULL;
+}
+
+void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc)
+{
+ /*
+ HASH_THREAD can use CriticalSection(s) btSync.cs and hashSync.cs.
+ So we must be sure that HASH_THREAD will not use CriticalSection(s)
+ after deleting CriticalSection here.
+
+ we call ReleaseStream(p)
+ that calls StopWriting(btSync)
+ that calls StopWriting(hashSync), if it's required to stop HASH_THREAD.
+ after StopWriting() it's safe to destruct MtSync(s) in any order */
+
+ MatchFinderMt_ReleaseStream(p);
+
+ MtSync_Destruct(&p->btSync);
+ MtSync_Destruct(&p->hashSync);
+
+ LOG_ITER(
+ printf("\nTree %9d * %7d iter = %9d = sum : bytes = %9d\n",
+ (UInt32)(g_NumIters_Tree / 1000),
+ (UInt32)(((UInt64)g_NumIters_Loop * 1000) / (g_NumIters_Tree + 1)),
+ (UInt32)(g_NumIters_Loop / 1000),
+ (UInt32)(g_NumIters_Bytes / 1000)
+ ));
+
+ MatchFinderMt_FreeMem(p, alloc);
+}
+
+
+#define kHashBufferSize (kMtHashBlockSize * kMtHashNumBlocks)
+#define kBtBufferSize (kMtBtBlockSize * kMtBtNumBlocks)
+
+
+static THREAD_FUNC_DECL HashThreadFunc2(void *p) { HashThreadFunc((CMatchFinderMt *)p); return 0; }
+static THREAD_FUNC_DECL BtThreadFunc2(void *p)
+{
+ Byte allocaDummy[0x180];
+ unsigned i = 0;
+ for (i = 0; i < 16; i++)
+ allocaDummy[i] = (Byte)0;
+ if (allocaDummy[0] == 0)
+ BtThreadFunc((CMatchFinderMt *)p);
+ return 0;
+}
+
+
+SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore,
+ UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc)
+{
+ CMatchFinder *mf = MF(p);
+ p->historySize = historySize;
+ if (kMtBtBlockSize <= matchMaxLen * 4)
+ return SZ_ERROR_PARAM;
+ if (!p->hashBuf)
+ {
+ p->hashBuf = (UInt32 *)ISzAlloc_Alloc(alloc, ((size_t)kHashBufferSize + (size_t)kBtBufferSize) * sizeof(UInt32));
+ if (!p->hashBuf)
+ return SZ_ERROR_MEM;
+ p->btBuf = p->hashBuf + kHashBufferSize;
+ }
+ keepAddBufferBefore += (kHashBufferSize + kBtBufferSize);
+ keepAddBufferAfter += kMtHashBlockSize;
+ if (!MatchFinder_Create(mf, historySize, keepAddBufferBefore, matchMaxLen, keepAddBufferAfter, alloc))
+ return SZ_ERROR_MEM;
+
+ RINOK(MtSync_Create(&p->hashSync, HashThreadFunc2, p))
+ RINOK(MtSync_Create(&p->btSync, BtThreadFunc2, p))
+ return SZ_OK;
+}
+
+
+SRes MatchFinderMt_InitMt(CMatchFinderMt *p)
+{
+ RINOK(MtSync_Init(&p->hashSync, kMtHashNumBlocks))
+ return MtSync_Init(&p->btSync, kMtBtNumBlocks);
+}
+
+
+static void MatchFinderMt_Init(CMatchFinderMt *p)
+{
+ CMatchFinder *mf = MF(p);
+
+ p->btBufPos =
+ p->btBufPosLimit = NULL;
+ p->hashBufPos =
+ p->hashBufPosLimit = 0;
+ p->hashNumAvail = 0; // 21.03
+
+ p->failure_BT = False;
+
+ /* Init without data reading. We don't want to read data in this thread */
+ MatchFinder_Init_4(mf);
+
+ MatchFinder_Init_LowHash(mf);
+
+ p->pointerToCurPos = Inline_MatchFinder_GetPointerToCurrentPos(mf);
+ p->btNumAvailBytes = 0;
+ p->failure_LZ_BT = False;
+ // p->failure_LZ_LZ = False;
+
+ p->lzPos =
+ 1; // optimal smallest value
+ // 0; // for debug: ignores match to start
+ // kNormalizeAlign; // for debug
+
+ p->hash = mf->hash;
+ p->fixedHashSize = mf->fixedHashSize;
+ // p->hash4Mask = mf->hash4Mask;
+ p->crc = mf->crc;
+ // memcpy(p->crc, mf->crc, sizeof(mf->crc));
+
+ p->son = mf->son;
+ p->matchMaxLen = mf->matchMaxLen;
+ p->numHashBytes = mf->numHashBytes;
+
+ /* (mf->pos) and (mf->streamPos) were already initialized to 1 in MatchFinder_Init_4() */
+ // mf->streamPos = mf->pos = 1; // optimal smallest value
+ // 0; // for debug: ignores match to start
+ // kNormalizeAlign; // for debug
+
+ /* we must init (p->pos = mf->pos) for BT, because
+ BT code needs (p->pos == delta_value_for_empty_hash_record == mf->pos) */
+ p->pos = mf->pos; // do not change it
+
+ p->cyclicBufferPos = (p->pos - CYC_TO_POS_OFFSET);
+ p->cyclicBufferSize = mf->cyclicBufferSize;
+ p->buffer = mf->buffer;
+ p->cutValue = mf->cutValue;
+ // p->son[0] = p->son[1] = 0; // unused: to init skipped record for speculated accesses.
+}
+
+
+/* ReleaseStream is required to finish multithreading */
+void MatchFinderMt_ReleaseStream(CMatchFinderMt *p)
+{
+ // Sleep(1); // for debug
+ MtSync_StopWriting(&p->btSync);
+ // Sleep(200); // for debug
+ /* p->MatchFinder->ReleaseStream(); */
+}
+
+
+Z7_NO_INLINE
+static UInt32 MatchFinderMt_GetNextBlock_Bt(CMatchFinderMt *p)
+{
+ if (p->failure_LZ_BT)
+ p->btBufPos = p->failureBuf;
+ else
+ {
+ const UInt32 bi = MtSync_GetNextBlock(&p->btSync);
+ const UInt32 *bt = p->btBuf + GET_BT_BLOCK_OFFSET(bi);
+ {
+ const UInt32 numItems = bt[0];
+ p->btBufPosLimit = bt + numItems;
+ p->btNumAvailBytes = bt[1];
+ p->btBufPos = bt + 2;
+ if (numItems < 2 || numItems > kMtBtBlockSize)
+ {
+ p->failureBuf[0] = 0;
+ p->btBufPos = p->failureBuf;
+ p->btBufPosLimit = p->failureBuf + 1;
+ p->failure_LZ_BT = True;
+ // p->btNumAvailBytes = 0;
+ /* we don't want to decrease AvailBytes, that was load before.
+ that can be unxepected for the code that have loaded anopther value before */
+ }
+ }
+
+ if (p->lzPos >= (UInt32)kMtMaxValForNormalize - (UInt32)kMtBtBlockSize)
+ {
+ /* we don't check (lzPos) over exact avail bytes in (btBuf).
+ (fixedHashSize) is small, so normalization is fast */
+ const UInt32 subValue = (p->lzPos - p->historySize - 1); // & ~(UInt32)(kNormalizeAlign - 1);
+ p->lzPos -= subValue;
+ MatchFinder_Normalize3(subValue, p->hash, p->fixedHashSize);
+ }
+ }
+ return p->btNumAvailBytes;
+}
+
+
+
+static const Byte * MatchFinderMt_GetPointerToCurrentPos(CMatchFinderMt *p)
+{
+ return p->pointerToCurPos;
+}
+
+
+#define GET_NEXT_BLOCK_IF_REQUIRED if (p->btBufPos == p->btBufPosLimit) MatchFinderMt_GetNextBlock_Bt(p);
+
+
+static UInt32 MatchFinderMt_GetNumAvailableBytes(CMatchFinderMt *p)
+{
+ if (p->btBufPos != p->btBufPosLimit)
+ return p->btNumAvailBytes;
+ return MatchFinderMt_GetNextBlock_Bt(p);
+}
+
+
+// #define CHECK_FAILURE_LZ(_match_, _pos_) if (_match_ >= _pos_) { p->failure_LZ_LZ = True; return d; }
+#define CHECK_FAILURE_LZ(_match_, _pos_)
+
+static UInt32 * MixMatches2(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *d)
+{
+ UInt32 h2, c2;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ const UInt32 m = p->lzPos;
+ MT_HASH2_CALC
+
+ c2 = hash[h2];
+ hash[h2] = m;
+
+ if (c2 >= matchMinPos)
+ {
+ CHECK_FAILURE_LZ(c2, m)
+ if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0])
+ {
+ *d++ = 2;
+ *d++ = m - c2 - 1;
+ }
+ }
+
+ return d;
+}
+
+static UInt32 * MixMatches3(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *d)
+{
+ UInt32 h2, h3, c2, c3;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ const UInt32 m = p->lzPos;
+ MT_HASH3_CALC
+
+ c2 = hash[h2];
+ c3 = (hash + kFix3HashSize)[h3];
+
+ hash[h2] = m;
+ (hash + kFix3HashSize)[h3] = m;
+
+ if (c2 >= matchMinPos)
+ {
+ CHECK_FAILURE_LZ(c2, m)
+ if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0])
+ {
+ d[1] = m - c2 - 1;
+ if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 2] == cur[2])
+ {
+ d[0] = 3;
+ return d + 2;
+ }
+ d[0] = 2;
+ d += 2;
+ }
+ }
+
+ if (c3 >= matchMinPos)
+ {
+ CHECK_FAILURE_LZ(c3, m)
+ if (cur[(ptrdiff_t)c3 - (ptrdiff_t)m] == cur[0])
+ {
+ *d++ = 3;
+ *d++ = m - c3 - 1;
+ }
+ }
+
+ return d;
+}
+
+
+#define INCREASE_LZ_POS p->lzPos++; p->pointerToCurPos++;
+
+/*
+static
+UInt32* MatchFinderMt_GetMatches_Bt4(CMatchFinderMt *p, UInt32 *d)
+{
+ const UInt32 *bt = p->btBufPos;
+ const UInt32 len = *bt++;
+ const UInt32 *btLim = bt + len;
+ UInt32 matchMinPos;
+ UInt32 avail = p->btNumAvailBytes - 1;
+ p->btBufPos = btLim;
+
+ {
+ p->btNumAvailBytes = avail;
+
+ #define BT_HASH_BYTES_MAX 5
+
+ matchMinPos = p->lzPos;
+
+ if (len != 0)
+ matchMinPos -= bt[1];
+ else if (avail < (BT_HASH_BYTES_MAX - 1) - 1)
+ {
+ INCREASE_LZ_POS
+ return d;
+ }
+ else
+ {
+ const UInt32 hs = p->historySize;
+ if (matchMinPos > hs)
+ matchMinPos -= hs;
+ else
+ matchMinPos = 1;
+ }
+ }
+
+ for (;;)
+ {
+
+ UInt32 h2, h3, c2, c3;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ UInt32 m = p->lzPos;
+ MT_HASH3_CALC
+
+ c2 = hash[h2];
+ c3 = (hash + kFix3HashSize)[h3];
+
+ hash[h2] = m;
+ (hash + kFix3HashSize)[h3] = m;
+
+ if (c2 >= matchMinPos && cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0])
+ {
+ d[1] = m - c2 - 1;
+ if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 2] == cur[2])
+ {
+ d[0] = 3;
+ d += 2;
+ break;
+ }
+ // else
+ {
+ d[0] = 2;
+ d += 2;
+ }
+ }
+ if (c3 >= matchMinPos && cur[(ptrdiff_t)c3 - (ptrdiff_t)m] == cur[0])
+ {
+ *d++ = 3;
+ *d++ = m - c3 - 1;
+ }
+ break;
+ }
+
+ if (len != 0)
+ {
+ do
+ {
+ const UInt32 v0 = bt[0];
+ const UInt32 v1 = bt[1];
+ bt += 2;
+ d[0] = v0;
+ d[1] = v1;
+ d += 2;
+ }
+ while (bt != btLim);
+ }
+ INCREASE_LZ_POS
+ return d;
+}
+*/
+
+
+static UInt32 * MixMatches4(CMatchFinderMt *p, UInt32 matchMinPos, UInt32 *d)
+{
+ UInt32 h2, h3, /* h4, */ c2, c3 /* , c4 */;
+ UInt32 *hash = p->hash;
+ const Byte *cur = p->pointerToCurPos;
+ const UInt32 m = p->lzPos;
+ MT_HASH3_CALC
+ // MT_HASH4_CALC
+ c2 = hash[h2];
+ c3 = (hash + kFix3HashSize)[h3];
+ // c4 = (hash + kFix4HashSize)[h4];
+
+ hash[h2] = m;
+ (hash + kFix3HashSize)[h3] = m;
+ // (hash + kFix4HashSize)[h4] = m;
+
+ // #define BT5_USE_H2
+ // #ifdef BT5_USE_H2
+ if (c2 >= matchMinPos && cur[(ptrdiff_t)c2 - (ptrdiff_t)m] == cur[0])
+ {
+ d[1] = m - c2 - 1;
+ if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 2] == cur[2])
+ {
+ // d[0] = (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 3] == cur[3]) ? 4 : 3;
+ // return d + 2;
+
+ if (cur[(ptrdiff_t)c2 - (ptrdiff_t)m + 3] == cur[3])
+ {
+ d[0] = 4;
+ return d + 2;
+ }
+ d[0] = 3;
+ d += 2;
+
+ #ifdef BT5_USE_H4
+ if (c4 >= matchMinPos)
+ if (
+ cur[(ptrdiff_t)c4 - (ptrdiff_t)m] == cur[0] &&
+ cur[(ptrdiff_t)c4 - (ptrdiff_t)m + 3] == cur[3]
+ )
+ {
+ *d++ = 4;
+ *d++ = m - c4 - 1;
+ }
+ #endif
+ return d;
+ }
+ d[0] = 2;
+ d += 2;
+ }
+ // #endif
+
+ if (c3 >= matchMinPos && cur[(ptrdiff_t)c3 - (ptrdiff_t)m] == cur[0])
+ {
+ d[1] = m - c3 - 1;
+ if (cur[(ptrdiff_t)c3 - (ptrdiff_t)m + 3] == cur[3])
+ {
+ d[0] = 4;
+ return d + 2;
+ }
+ d[0] = 3;
+ d += 2;
+ }
+
+ #ifdef BT5_USE_H4
+ if (c4 >= matchMinPos)
+ if (
+ cur[(ptrdiff_t)c4 - (ptrdiff_t)m] == cur[0] &&
+ cur[(ptrdiff_t)c4 - (ptrdiff_t)m + 3] == cur[3]
+ )
+ {
+ *d++ = 4;
+ *d++ = m - c4 - 1;
+ }
+ #endif
+
+ return d;
+}
+
+
+static UInt32 * MatchFinderMt2_GetMatches(CMatchFinderMt *p, UInt32 *d)
+{
+ const UInt32 *bt = p->btBufPos;
+ const UInt32 len = *bt++;
+ const UInt32 *btLim = bt + len;
+ p->btBufPos = btLim;
+ p->btNumAvailBytes--;
+ INCREASE_LZ_POS
+ {
+ while (bt != btLim)
+ {
+ const UInt32 v0 = bt[0];
+ const UInt32 v1 = bt[1];
+ bt += 2;
+ d[0] = v0;
+ d[1] = v1;
+ d += 2;
+ }
+ }
+ return d;
+}
+
+
+
+static UInt32 * MatchFinderMt_GetMatches(CMatchFinderMt *p, UInt32 *d)
+{
+ const UInt32 *bt = p->btBufPos;
+ UInt32 len = *bt++;
+ const UInt32 avail = p->btNumAvailBytes - 1;
+ p->btNumAvailBytes = avail;
+ p->btBufPos = bt + len;
+ if (len == 0)
+ {
+ #define BT_HASH_BYTES_MAX 5
+ if (avail >= (BT_HASH_BYTES_MAX - 1) - 1)
+ {
+ UInt32 m = p->lzPos;
+ if (m > p->historySize)
+ m -= p->historySize;
+ else
+ m = 1;
+ d = p->MixMatchesFunc(p, m, d);
+ }
+ }
+ else
+ {
+ /*
+ first match pair from BinTree: (match_len, match_dist),
+ (match_len >= numHashBytes).
+ MixMatchesFunc() inserts only hash matches that are nearer than (match_dist)
+ */
+ d = p->MixMatchesFunc(p, p->lzPos - bt[1], d);
+ // if (d) // check for failure
+ do
+ {
+ const UInt32 v0 = bt[0];
+ const UInt32 v1 = bt[1];
+ bt += 2;
+ d[0] = v0;
+ d[1] = v1;
+ d += 2;
+ }
+ while (len -= 2);
+ }
+ INCREASE_LZ_POS
+ return d;
+}
+
+#define SKIP_HEADER2_MT do { GET_NEXT_BLOCK_IF_REQUIRED
+#define SKIP_HEADER_MT(n) SKIP_HEADER2_MT if (p->btNumAvailBytes-- >= (n)) { const Byte *cur = p->pointerToCurPos; UInt32 *hash = p->hash;
+#define SKIP_FOOTER_MT } INCREASE_LZ_POS p->btBufPos += (size_t)*p->btBufPos + 1; } while (--num != 0);
+
+static void MatchFinderMt0_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER2_MT { p->btNumAvailBytes--;
+ SKIP_FOOTER_MT
+}
+
+static void MatchFinderMt2_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER_MT(2)
+ UInt32 h2;
+ MT_HASH2_CALC
+ hash[h2] = p->lzPos;
+ SKIP_FOOTER_MT
+}
+
+static void MatchFinderMt3_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER_MT(3)
+ UInt32 h2, h3;
+ MT_HASH3_CALC
+ (hash + kFix3HashSize)[h3] =
+ hash[ h2] =
+ p->lzPos;
+ SKIP_FOOTER_MT
+}
+
+/*
+// MatchFinderMt4_Skip() is similar to MatchFinderMt3_Skip().
+// The difference is that MatchFinderMt3_Skip() updates hash for last 3 bytes of stream.
+
+static void MatchFinderMt4_Skip(CMatchFinderMt *p, UInt32 num)
+{
+ SKIP_HEADER_MT(4)
+ UInt32 h2, h3; // h4
+ MT_HASH3_CALC
+ // MT_HASH4_CALC
+ // (hash + kFix4HashSize)[h4] =
+ (hash + kFix3HashSize)[h3] =
+ hash[ h2] =
+ p->lzPos;
+ SKIP_FOOTER_MT
+}
+*/
+
+void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder2 *vTable)
+{
+ vTable->Init = (Mf_Init_Func)MatchFinderMt_Init;
+ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinderMt_GetNumAvailableBytes;
+ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinderMt_GetPointerToCurrentPos;
+ vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches;
+
+ switch (MF(p)->numHashBytes)
+ {
+ case 2:
+ p->GetHeadsFunc = GetHeads2;
+ p->MixMatchesFunc = (Mf_Mix_Matches)NULL;
+ vTable->Skip = (Mf_Skip_Func)MatchFinderMt0_Skip;
+ vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt2_GetMatches;
+ break;
+ case 3:
+ p->GetHeadsFunc = MF(p)->bigHash ? GetHeads3b : GetHeads3;
+ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches2;
+ vTable->Skip = (Mf_Skip_Func)MatchFinderMt2_Skip;
+ break;
+ case 4:
+ p->GetHeadsFunc = MF(p)->bigHash ? GetHeads4b : GetHeads4;
+
+ // it's fast inline version of GetMatches()
+ // vTable->GetMatches = (Mf_GetMatches_Func)MatchFinderMt_GetMatches_Bt4;
+
+ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches3;
+ vTable->Skip = (Mf_Skip_Func)MatchFinderMt3_Skip;
+ break;
+ default:
+ p->GetHeadsFunc = MF(p)->bigHash ? GetHeads5b : GetHeads5;
+ p->MixMatchesFunc = (Mf_Mix_Matches)MixMatches4;
+ vTable->Skip =
+ (Mf_Skip_Func)MatchFinderMt3_Skip;
+ // (Mf_Skip_Func)MatchFinderMt4_Skip;
+ break;
+ }
+}
+
+#undef RINOK_THREAD
+#undef PRF
+#undef MF
+#undef GetUi24hi_from32
+#undef LOCK_BUFFER
+#undef UNLOCK_BUFFER
diff --git a/C/LzFindMt.h b/C/LzFindMt.h
index fdd1700..db5923e 100644
--- a/C/LzFindMt.h
+++ b/C/LzFindMt.h
@@ -1,101 +1,109 @@
-/* LzFindMt.h -- multithreaded Match finder for LZ algorithms
-2018-07-04 : Igor Pavlov : Public domain */
-
-#ifndef __LZ_FIND_MT_H
-#define __LZ_FIND_MT_H
-
-#include "LzFind.h"
-#include "Threads.h"
-
-EXTERN_C_BEGIN
-
-#define kMtHashBlockSize (1 << 13)
-#define kMtHashNumBlocks (1 << 3)
-#define kMtHashNumBlocksMask (kMtHashNumBlocks - 1)
-
-#define kMtBtBlockSize (1 << 14)
-#define kMtBtNumBlocks (1 << 6)
-#define kMtBtNumBlocksMask (kMtBtNumBlocks - 1)
-
-typedef struct _CMtSync
-{
- BoolInt wasCreated;
- BoolInt needStart;
- BoolInt exit;
- BoolInt stopWriting;
-
- CThread thread;
- CAutoResetEvent canStart;
- CAutoResetEvent wasStarted;
- CAutoResetEvent wasStopped;
- CSemaphore freeSemaphore;
- CSemaphore filledSemaphore;
- BoolInt csWasInitialized;
- BoolInt csWasEntered;
- CCriticalSection cs;
- UInt32 numProcessedBlocks;
-} CMtSync;
-
-typedef UInt32 * (*Mf_Mix_Matches)(void *p, UInt32 matchMinPos, UInt32 *distances);
-
-/* kMtCacheLineDummy must be >= size_of_CPU_cache_line */
-#define kMtCacheLineDummy 128
-
-typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos,
- UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc);
-
-typedef struct _CMatchFinderMt
-{
- /* LZ */
- const Byte *pointerToCurPos;
- UInt32 *btBuf;
- UInt32 btBufPos;
- UInt32 btBufPosLimit;
- UInt32 lzPos;
- UInt32 btNumAvailBytes;
-
- UInt32 *hash;
- UInt32 fixedHashSize;
- UInt32 historySize;
- const UInt32 *crc;
-
- Mf_Mix_Matches MixMatchesFunc;
-
- /* LZ + BT */
- CMtSync btSync;
- Byte btDummy[kMtCacheLineDummy];
-
- /* BT */
- UInt32 *hashBuf;
- UInt32 hashBufPos;
- UInt32 hashBufPosLimit;
- UInt32 hashNumAvail;
-
- CLzRef *son;
- UInt32 matchMaxLen;
- UInt32 numHashBytes;
- UInt32 pos;
- const Byte *buffer;
- UInt32 cyclicBufferPos;
- UInt32 cyclicBufferSize; /* it must be historySize + 1 */
- UInt32 cutValue;
-
- /* BT + Hash */
- CMtSync hashSync;
- /* Byte hashDummy[kMtCacheLineDummy]; */
-
- /* Hash */
- Mf_GetHeads GetHeadsFunc;
- CMatchFinder *MatchFinder;
-} CMatchFinderMt;
-
-void MatchFinderMt_Construct(CMatchFinderMt *p);
-void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc);
-SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore,
- UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc);
-void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder *vTable);
-void MatchFinderMt_ReleaseStream(CMatchFinderMt *p);
-
-EXTERN_C_END
-
-#endif
+/* LzFindMt.h -- multithreaded Match finder for LZ algorithms
+2023-03-05 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_LZ_FIND_MT_H
+#define ZIP7_INC_LZ_FIND_MT_H
+
+#include "LzFind.h"
+#include "Threads.h"
+
+EXTERN_C_BEGIN
+
+typedef struct
+{
+ UInt32 numProcessedBlocks;
+ CThread thread;
+ UInt64 affinity;
+
+ BoolInt wasCreated;
+ BoolInt needStart;
+ BoolInt csWasInitialized;
+ BoolInt csWasEntered;
+
+ BoolInt exit;
+ BoolInt stopWriting;
+
+ CAutoResetEvent canStart;
+ CAutoResetEvent wasStopped;
+ CSemaphore freeSemaphore;
+ CSemaphore filledSemaphore;
+ CCriticalSection cs;
+ // UInt32 numBlocks_Sent;
+} CMtSync;
+
+typedef UInt32 * (*Mf_Mix_Matches)(void *p, UInt32 matchMinPos, UInt32 *distances);
+
+/* kMtCacheLineDummy must be >= size_of_CPU_cache_line */
+#define kMtCacheLineDummy 128
+
+typedef void (*Mf_GetHeads)(const Byte *buffer, UInt32 pos,
+ UInt32 *hash, UInt32 hashMask, UInt32 *heads, UInt32 numHeads, const UInt32 *crc);
+
+typedef struct
+{
+ /* LZ */
+ const Byte *pointerToCurPos;
+ UInt32 *btBuf;
+ const UInt32 *btBufPos;
+ const UInt32 *btBufPosLimit;
+ UInt32 lzPos;
+ UInt32 btNumAvailBytes;
+
+ UInt32 *hash;
+ UInt32 fixedHashSize;
+ // UInt32 hash4Mask;
+ UInt32 historySize;
+ const UInt32 *crc;
+
+ Mf_Mix_Matches MixMatchesFunc;
+ UInt32 failure_LZ_BT; // failure in BT transfered to LZ
+ // UInt32 failure_LZ_LZ; // failure in LZ tables
+ UInt32 failureBuf[1];
+ // UInt32 crc[256];
+
+ /* LZ + BT */
+ CMtSync btSync;
+ Byte btDummy[kMtCacheLineDummy];
+
+ /* BT */
+ UInt32 *hashBuf;
+ UInt32 hashBufPos;
+ UInt32 hashBufPosLimit;
+ UInt32 hashNumAvail;
+ UInt32 failure_BT;
+
+
+ CLzRef *son;
+ UInt32 matchMaxLen;
+ UInt32 numHashBytes;
+ UInt32 pos;
+ const Byte *buffer;
+ UInt32 cyclicBufferPos;
+ UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
+ UInt32 cutValue;
+
+ /* BT + Hash */
+ CMtSync hashSync;
+ /* Byte hashDummy[kMtCacheLineDummy]; */
+
+ /* Hash */
+ Mf_GetHeads GetHeadsFunc;
+ CMatchFinder *MatchFinder;
+ // CMatchFinder MatchFinder;
+} CMatchFinderMt;
+
+// only for Mt part
+void MatchFinderMt_Construct(CMatchFinderMt *p);
+void MatchFinderMt_Destruct(CMatchFinderMt *p, ISzAllocPtr alloc);
+
+SRes MatchFinderMt_Create(CMatchFinderMt *p, UInt32 historySize, UInt32 keepAddBufferBefore,
+ UInt32 matchMaxLen, UInt32 keepAddBufferAfter, ISzAllocPtr alloc);
+void MatchFinderMt_CreateVTable(CMatchFinderMt *p, IMatchFinder2 *vTable);
+
+/* call MatchFinderMt_InitMt() before IMatchFinder::Init() */
+SRes MatchFinderMt_InitMt(CMatchFinderMt *p);
+void MatchFinderMt_ReleaseStream(CMatchFinderMt *p);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/LzFindOpt.c b/C/LzFindOpt.c
new file mode 100644
index 0000000..85bdc13
--- /dev/null
+++ b/C/LzFindOpt.c
@@ -0,0 +1,578 @@
+/* LzFindOpt.c -- multithreaded Match finder for LZ algorithms
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "CpuArch.h"
+#include "LzFind.h"
+
+// #include "LzFindMt.h"
+
+// #define LOG_ITERS
+
+// #define LOG_THREAD
+
+#ifdef LOG_THREAD
+#include <stdio.h>
+#define PRF(x) x
+#else
+// #define PRF(x)
+#endif
+
+#ifdef LOG_ITERS
+#include <stdio.h>
+UInt64 g_NumIters_Tree;
+UInt64 g_NumIters_Loop;
+UInt64 g_NumIters_Bytes;
+#define LOG_ITER(x) x
+#else
+#define LOG_ITER(x)
+#endif
+
+// ---------- BT THREAD ----------
+
+#define USE_SON_PREFETCH
+#define USE_LONG_MATCH_OPT
+
+#define kEmptyHashValue 0
+
+// #define CYC_TO_POS_OFFSET 0
+
+// #define CYC_TO_POS_OFFSET 1 // for debug
+
+/*
+Z7_NO_INLINE
+UInt32 * Z7_FASTCALL GetMatchesSpecN_1(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son,
+ UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size, UInt32 *posRes)
+{
+ do
+ {
+ UInt32 delta;
+ if (hash == size)
+ break;
+ delta = *hash++;
+
+ if (delta == 0 || delta > (UInt32)pos)
+ return NULL;
+
+ lenLimit++;
+
+ if (delta == (UInt32)pos)
+ {
+ CLzRef *ptr1 = son + ((size_t)pos << 1) - CYC_TO_POS_OFFSET * 2;
+ *d++ = 0;
+ ptr1[0] = kEmptyHashValue;
+ ptr1[1] = kEmptyHashValue;
+ }
+else
+{
+ UInt32 *_distances = ++d;
+
+ CLzRef *ptr0 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2 + 1;
+ CLzRef *ptr1 = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2;
+
+ const Byte *len0 = cur, *len1 = cur;
+ UInt32 cutValue = _cutValue;
+ const Byte *maxLen = cur + _maxLen;
+
+ for (LOG_ITER(g_NumIters_Tree++);;)
+ {
+ LOG_ITER(g_NumIters_Loop++);
+ {
+ const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta;
+ CLzRef *pair = son + ((size_t)(((ptrdiff_t)pos - CYC_TO_POS_OFFSET) + diff) << 1);
+ const Byte *len = (len0 < len1 ? len0 : len1);
+
+ #ifdef USE_SON_PREFETCH
+ const UInt32 pair0 = *pair;
+ #endif
+
+ if (len[diff] == len[0])
+ {
+ if (++len != lenLimit && len[diff] == len[0])
+ while (++len != lenLimit)
+ {
+ LOG_ITER(g_NumIters_Bytes++);
+ if (len[diff] != len[0])
+ break;
+ }
+ if (maxLen < len)
+ {
+ maxLen = len;
+ *d++ = (UInt32)(len - cur);
+ *d++ = delta - 1;
+
+ if (len == lenLimit)
+ {
+ const UInt32 pair1 = pair[1];
+ *ptr1 =
+ #ifdef USE_SON_PREFETCH
+ pair0;
+ #else
+ pair[0];
+ #endif
+ *ptr0 = pair1;
+
+ _distances[-1] = (UInt32)(d - _distances);
+
+ #ifdef USE_LONG_MATCH_OPT
+
+ if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit)
+ break;
+
+ {
+ for (;;)
+ {
+ hash++;
+ pos++;
+ cur++;
+ lenLimit++;
+ {
+ CLzRef *ptr = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2;
+ #if 0
+ *(UInt64 *)(void *)ptr = ((const UInt64 *)(const void *)ptr)[diff];
+ #else
+ const UInt32 p0 = ptr[0 + (diff * 2)];
+ const UInt32 p1 = ptr[1 + (diff * 2)];
+ ptr[0] = p0;
+ ptr[1] = p1;
+ // ptr[0] = ptr[0 + (diff * 2)];
+ // ptr[1] = ptr[1 + (diff * 2)];
+ #endif
+ }
+ // PrintSon(son + 2, pos - 1);
+ // printf("\npos = %x delta = %x\n", pos, delta);
+ len++;
+ *d++ = 2;
+ *d++ = (UInt32)(len - cur);
+ *d++ = delta - 1;
+ if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit)
+ break;
+ }
+ }
+ #endif
+
+ break;
+ }
+ }
+ }
+
+ {
+ const UInt32 curMatch = (UInt32)pos - delta; // (UInt32)(pos + diff);
+ if (len[diff] < len[0])
+ {
+ delta = pair[1];
+ if (delta >= curMatch)
+ return NULL;
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ len1 = len;
+ }
+ else
+ {
+ delta = *pair;
+ if (delta >= curMatch)
+ return NULL;
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ len0 = len;
+ }
+
+ delta = (UInt32)pos - delta;
+
+ if (--cutValue == 0 || delta >= pos)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ _distances[-1] = (UInt32)(d - _distances);
+ break;
+ }
+ }
+ }
+ } // for (tree iterations)
+}
+ pos++;
+ cur++;
+ }
+ while (d < limit);
+ *posRes = (UInt32)pos;
+ return d;
+}
+*/
+
+/* define cbs if you use 2 functions.
+ GetMatchesSpecN_1() : (pos < _cyclicBufferSize)
+ GetMatchesSpecN_2() : (pos >= _cyclicBufferSize)
+
+ do not define cbs if you use 1 function:
+ GetMatchesSpecN_2()
+*/
+
+// #define cbs _cyclicBufferSize
+
+/*
+ we use size_t for (pos) and (_cyclicBufferPos_ instead of UInt32
+ to eliminate "movsx" BUG in old MSVC x64 compiler.
+*/
+
+UInt32 * Z7_FASTCALL GetMatchesSpecN_2(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son,
+ UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size,
+ size_t _cyclicBufferPos, UInt32 _cyclicBufferSize,
+ UInt32 *posRes);
+
+Z7_NO_INLINE
+UInt32 * Z7_FASTCALL GetMatchesSpecN_2(const Byte *lenLimit, size_t pos, const Byte *cur, CLzRef *son,
+ UInt32 _cutValue, UInt32 *d, size_t _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size,
+ size_t _cyclicBufferPos, UInt32 _cyclicBufferSize,
+ UInt32 *posRes)
+{
+ do // while (hash != size)
+ {
+ UInt32 delta;
+
+ #ifndef cbs
+ UInt32 cbs;
+ #endif
+
+ if (hash == size)
+ break;
+
+ delta = *hash++;
+
+ if (delta == 0)
+ return NULL;
+
+ lenLimit++;
+
+ #ifndef cbs
+ cbs = _cyclicBufferSize;
+ if ((UInt32)pos < cbs)
+ {
+ if (delta > (UInt32)pos)
+ return NULL;
+ cbs = (UInt32)pos;
+ }
+ #endif
+
+ if (delta >= cbs)
+ {
+ CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
+ *d++ = 0;
+ ptr1[0] = kEmptyHashValue;
+ ptr1[1] = kEmptyHashValue;
+ }
+else
+{
+ UInt32 *_distances = ++d;
+
+ CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
+
+ UInt32 cutValue = _cutValue;
+ const Byte *len0 = cur, *len1 = cur;
+ const Byte *maxLen = cur + _maxLen;
+
+ // if (cutValue == 0) { *ptr0 = *ptr1 = kEmptyHashValue; } else
+ for (LOG_ITER(g_NumIters_Tree++);;)
+ {
+ LOG_ITER(g_NumIters_Loop++);
+ {
+ // SPEC code
+ CLzRef *pair = son + ((size_t)((ptrdiff_t)_cyclicBufferPos - (ptrdiff_t)delta
+ + (ptrdiff_t)(UInt32)(_cyclicBufferPos < delta ? cbs : 0)
+ ) << 1);
+
+ const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta;
+ const Byte *len = (len0 < len1 ? len0 : len1);
+
+ #ifdef USE_SON_PREFETCH
+ const UInt32 pair0 = *pair;
+ #endif
+
+ if (len[diff] == len[0])
+ {
+ if (++len != lenLimit && len[diff] == len[0])
+ while (++len != lenLimit)
+ {
+ LOG_ITER(g_NumIters_Bytes++);
+ if (len[diff] != len[0])
+ break;
+ }
+ if (maxLen < len)
+ {
+ maxLen = len;
+ *d++ = (UInt32)(len - cur);
+ *d++ = delta - 1;
+
+ if (len == lenLimit)
+ {
+ const UInt32 pair1 = pair[1];
+ *ptr1 =
+ #ifdef USE_SON_PREFETCH
+ pair0;
+ #else
+ pair[0];
+ #endif
+ *ptr0 = pair1;
+
+ _distances[-1] = (UInt32)(d - _distances);
+
+ #ifdef USE_LONG_MATCH_OPT
+
+ if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit)
+ break;
+
+ {
+ for (;;)
+ {
+ *d++ = 2;
+ *d++ = (UInt32)(lenLimit - cur);
+ *d++ = delta - 1;
+ cur++;
+ lenLimit++;
+ // SPEC
+ _cyclicBufferPos++;
+ {
+ // SPEC code
+ CLzRef *dest = son + ((size_t)(_cyclicBufferPos) << 1);
+ const CLzRef *src = dest + ((diff
+ + (ptrdiff_t)(UInt32)((_cyclicBufferPos < delta) ? cbs : 0)) << 1);
+ // CLzRef *ptr = son + ((size_t)(pos) << 1) - CYC_TO_POS_OFFSET * 2;
+ #if 0
+ *(UInt64 *)(void *)dest = *((const UInt64 *)(const void *)src);
+ #else
+ const UInt32 p0 = src[0];
+ const UInt32 p1 = src[1];
+ dest[0] = p0;
+ dest[1] = p1;
+ #endif
+ }
+ pos++;
+ hash++;
+ if (hash == size || *hash != delta || lenLimit[diff] != lenLimit[0] || d >= limit)
+ break;
+ } // for() end for long matches
+ }
+ #endif
+
+ break; // break from TREE iterations
+ }
+ }
+ }
+ {
+ const UInt32 curMatch = (UInt32)pos - delta; // (UInt32)(pos + diff);
+ if (len[diff] < len[0])
+ {
+ delta = pair[1];
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ len1 = len;
+ if (delta >= curMatch)
+ return NULL;
+ }
+ else
+ {
+ delta = *pair;
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ len0 = len;
+ if (delta >= curMatch)
+ return NULL;
+ }
+ delta = (UInt32)pos - delta;
+
+ if (--cutValue == 0 || delta >= cbs)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ _distances[-1] = (UInt32)(d - _distances);
+ break;
+ }
+ }
+ }
+ } // for (tree iterations)
+}
+ pos++;
+ _cyclicBufferPos++;
+ cur++;
+ }
+ while (d < limit);
+ *posRes = (UInt32)pos;
+ return d;
+}
+
+
+
+/*
+typedef UInt32 uint32plus; // size_t
+
+UInt32 * Z7_FASTCALL GetMatchesSpecN_3(uint32plus lenLimit, size_t pos, const Byte *cur, CLzRef *son,
+ UInt32 _cutValue, UInt32 *d, uint32plus _maxLen, const UInt32 *hash, const UInt32 *limit, const UInt32 *size,
+ size_t _cyclicBufferPos, UInt32 _cyclicBufferSize,
+ UInt32 *posRes)
+{
+ do // while (hash != size)
+ {
+ UInt32 delta;
+
+ #ifndef cbs
+ UInt32 cbs;
+ #endif
+
+ if (hash == size)
+ break;
+
+ delta = *hash++;
+
+ if (delta == 0)
+ return NULL;
+
+ #ifndef cbs
+ cbs = _cyclicBufferSize;
+ if ((UInt32)pos < cbs)
+ {
+ if (delta > (UInt32)pos)
+ return NULL;
+ cbs = (UInt32)pos;
+ }
+ #endif
+
+ if (delta >= cbs)
+ {
+ CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
+ *d++ = 0;
+ ptr1[0] = kEmptyHashValue;
+ ptr1[1] = kEmptyHashValue;
+ }
+else
+{
+ CLzRef *ptr0 = son + ((size_t)_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + ((size_t)_cyclicBufferPos << 1);
+ UInt32 *_distances = ++d;
+ uint32plus len0 = 0, len1 = 0;
+ UInt32 cutValue = _cutValue;
+ uint32plus maxLen = _maxLen;
+ // lenLimit++; // const Byte *lenLimit = cur + _lenLimit;
+
+ for (LOG_ITER(g_NumIters_Tree++);;)
+ {
+ LOG_ITER(g_NumIters_Loop++);
+ {
+ // const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta;
+ CLzRef *pair = son + ((size_t)((ptrdiff_t)_cyclicBufferPos - delta
+ + (ptrdiff_t)(UInt32)(_cyclicBufferPos < delta ? cbs : 0)
+ ) << 1);
+ const Byte *pb = cur - delta;
+ uint32plus len = (len0 < len1 ? len0 : len1);
+
+ #ifdef USE_SON_PREFETCH
+ const UInt32 pair0 = *pair;
+ #endif
+
+ if (pb[len] == cur[len])
+ {
+ if (++len != lenLimit && pb[len] == cur[len])
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ maxLen = len;
+ *d++ = (UInt32)len;
+ *d++ = delta - 1;
+ if (len == lenLimit)
+ {
+ {
+ const UInt32 pair1 = pair[1];
+ *ptr0 = pair1;
+ *ptr1 =
+ #ifdef USE_SON_PREFETCH
+ pair0;
+ #else
+ pair[0];
+ #endif
+ }
+
+ _distances[-1] = (UInt32)(d - _distances);
+
+ #ifdef USE_LONG_MATCH_OPT
+
+ if (hash == size || *hash != delta || pb[lenLimit] != cur[lenLimit] || d >= limit)
+ break;
+
+ {
+ const ptrdiff_t diff = (ptrdiff_t)0 - (ptrdiff_t)delta;
+ for (;;)
+ {
+ *d++ = 2;
+ *d++ = (UInt32)lenLimit;
+ *d++ = delta - 1;
+ _cyclicBufferPos++;
+ {
+ CLzRef *dest = son + ((size_t)_cyclicBufferPos << 1);
+ const CLzRef *src = dest + ((diff +
+ (ptrdiff_t)(UInt32)(_cyclicBufferPos < delta ? cbs : 0)) << 1);
+ #if 0
+ *(UInt64 *)(void *)dest = *((const UInt64 *)(const void *)src);
+ #else
+ const UInt32 p0 = src[0];
+ const UInt32 p1 = src[1];
+ dest[0] = p0;
+ dest[1] = p1;
+ #endif
+ }
+ hash++;
+ pos++;
+ cur++;
+ pb++;
+ if (hash == size || *hash != delta || pb[lenLimit] != cur[lenLimit] || d >= limit)
+ break;
+ }
+ }
+ #endif
+
+ break;
+ }
+ }
+ }
+ {
+ const UInt32 curMatch = (UInt32)pos - delta;
+ if (pb[len] < cur[len])
+ {
+ delta = pair[1];
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ len1 = len;
+ }
+ else
+ {
+ delta = *pair;
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ len0 = len;
+ }
+
+ {
+ if (delta >= curMatch)
+ return NULL;
+ delta = (UInt32)pos - delta;
+ if (delta >= cbs
+ // delta >= _cyclicBufferSize || delta >= pos
+ || --cutValue == 0)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ _distances[-1] = (UInt32)(d - _distances);
+ break;
+ }
+ }
+ }
+ }
+ } // for (tree iterations)
+}
+ pos++;
+ _cyclicBufferPos++;
+ cur++;
+ }
+ while (d < limit);
+ *posRes = (UInt32)pos;
+ return d;
+}
+*/
diff --git a/C/LzHash.h b/C/LzHash.h
index 2191444..2b6290b 100644
--- a/C/LzHash.h
+++ b/C/LzHash.h
@@ -1,57 +1,34 @@
-/* LzHash.h -- HASH functions for LZ algorithms
-2015-04-12 : Igor Pavlov : Public domain */
-
-#ifndef __LZ_HASH_H
-#define __LZ_HASH_H
-
-#define kHash2Size (1 << 10)
-#define kHash3Size (1 << 16)
-#define kHash4Size (1 << 20)
-
-#define kFix3HashSize (kHash2Size)
-#define kFix4HashSize (kHash2Size + kHash3Size)
-#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
-
-#define HASH2_CALC hv = cur[0] | ((UInt32)cur[1] << 8);
-
-#define HASH3_CALC { \
- UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
- h2 = temp & (kHash2Size - 1); \
- hv = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
-
-#define HASH4_CALC { \
- UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
- h2 = temp & (kHash2Size - 1); \
- temp ^= ((UInt32)cur[2] << 8); \
- h3 = temp & (kHash3Size - 1); \
- hv = (temp ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
-
-#define HASH5_CALC { \
- UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
- h2 = temp & (kHash2Size - 1); \
- temp ^= ((UInt32)cur[2] << 8); \
- h3 = temp & (kHash3Size - 1); \
- temp ^= (p->crc[cur[3]] << 5); \
- h4 = temp & (kHash4Size - 1); \
- hv = (temp ^ (p->crc[cur[4]] << 3)) & p->hashMask; }
-
-/* #define HASH_ZIP_CALC hv = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
-#define HASH_ZIP_CALC hv = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
-
-
-#define MT_HASH2_CALC \
- h2 = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
-
-#define MT_HASH3_CALC { \
- UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
- h2 = temp & (kHash2Size - 1); \
- h3 = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
-
-#define MT_HASH4_CALC { \
- UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
- h2 = temp & (kHash2Size - 1); \
- temp ^= ((UInt32)cur[2] << 8); \
- h3 = temp & (kHash3Size - 1); \
- h4 = (temp ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
-
-#endif
+/* LzHash.h -- HASH constants for LZ algorithms
+2023-03-05 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_LZ_HASH_H
+#define ZIP7_INC_LZ_HASH_H
+
+/*
+ (kHash2Size >= (1 << 8)) : Required
+ (kHash3Size >= (1 << 16)) : Required
+*/
+
+#define kHash2Size (1 << 10)
+#define kHash3Size (1 << 16)
+// #define kHash4Size (1 << 20)
+
+#define kFix3HashSize (kHash2Size)
+#define kFix4HashSize (kHash2Size + kHash3Size)
+// #define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
+
+/*
+ We use up to 3 crc values for hash:
+ crc0
+ crc1 << Shift_1
+ crc2 << Shift_2
+ (Shift_1 = 5) and (Shift_2 = 10) is good tradeoff.
+ Small values for Shift are not good for collision rate.
+ Big value for Shift_2 increases the minimum size
+ of hash table, that will be slow for small files.
+*/
+
+#define kLzHash_CrcShift_1 5
+#define kLzHash_CrcShift_2 10
+
+#endif
diff --git a/C/Lzma2Dec.c b/C/Lzma2Dec.c
index 2e63105..388cbc7 100644
--- a/C/Lzma2Dec.c
+++ b/C/Lzma2Dec.c
@@ -1,488 +1,491 @@
-/* Lzma2Dec.c -- LZMA2 Decoder
-2019-02-02 : Igor Pavlov : Public domain */
-
-/* #define SHOW_DEBUG_INFO */
-
-#include "Precomp.h"
-
-#ifdef SHOW_DEBUG_INFO
-#include <stdio.h>
-#endif
-
-#include <string.h>
-
-#include "Lzma2Dec.h"
-
-/*
-00000000 - End of data
-00000001 U U - Uncompressed, reset dic, need reset state and set new prop
-00000010 U U - Uncompressed, no reset
-100uuuuu U U P P - LZMA, no reset
-101uuuuu U U P P - LZMA, reset state
-110uuuuu U U P P S - LZMA, reset state + set new prop
-111uuuuu U U P P S - LZMA, reset state + set new prop, reset dic
-
- u, U - Unpack Size
- P - Pack Size
- S - Props
-*/
-
-#define LZMA2_CONTROL_COPY_RESET_DIC 1
-
-#define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & (1 << 7)) == 0)
-
-#define LZMA2_LCLP_MAX 4
-#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11))
-
-#ifdef SHOW_DEBUG_INFO
-#define PRF(x) x
-#else
-#define PRF(x)
-#endif
-
-typedef enum
-{
- LZMA2_STATE_CONTROL,
- LZMA2_STATE_UNPACK0,
- LZMA2_STATE_UNPACK1,
- LZMA2_STATE_PACK0,
- LZMA2_STATE_PACK1,
- LZMA2_STATE_PROP,
- LZMA2_STATE_DATA,
- LZMA2_STATE_DATA_CONT,
- LZMA2_STATE_FINISHED,
- LZMA2_STATE_ERROR
-} ELzma2State;
-
-static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props)
-{
- UInt32 dicSize;
- if (prop > 40)
- return SZ_ERROR_UNSUPPORTED;
- dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop);
- props[0] = (Byte)LZMA2_LCLP_MAX;
- props[1] = (Byte)(dicSize);
- props[2] = (Byte)(dicSize >> 8);
- props[3] = (Byte)(dicSize >> 16);
- props[4] = (Byte)(dicSize >> 24);
- return SZ_OK;
-}
-
-SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc)
-{
- Byte props[LZMA_PROPS_SIZE];
- RINOK(Lzma2Dec_GetOldProps(prop, props));
- return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc);
-}
-
-SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc)
-{
- Byte props[LZMA_PROPS_SIZE];
- RINOK(Lzma2Dec_GetOldProps(prop, props));
- return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc);
-}
-
-void Lzma2Dec_Init(CLzma2Dec *p)
-{
- p->state = LZMA2_STATE_CONTROL;
- p->needInitLevel = 0xE0;
- p->isExtraMode = False;
- p->unpackSize = 0;
-
- // p->decoder.dicPos = 0; // we can use it instead of full init
- LzmaDec_Init(&p->decoder);
-}
-
-static ELzma2State Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b)
-{
- switch (p->state)
- {
- case LZMA2_STATE_CONTROL:
- p->isExtraMode = False;
- p->control = b;
- PRF(printf("\n %8X", (unsigned)p->decoder.dicPos));
- PRF(printf(" %02X", (unsigned)b));
- if (b == 0)
- return LZMA2_STATE_FINISHED;
- if (LZMA2_IS_UNCOMPRESSED_STATE(p))
- {
- if (b == LZMA2_CONTROL_COPY_RESET_DIC)
- p->needInitLevel = 0xC0;
- else if (b > 2 || p->needInitLevel == 0xE0)
- return LZMA2_STATE_ERROR;
- }
- else
- {
- if (b < p->needInitLevel)
- return LZMA2_STATE_ERROR;
- p->needInitLevel = 0;
- p->unpackSize = (UInt32)(b & 0x1F) << 16;
- }
- return LZMA2_STATE_UNPACK0;
-
- case LZMA2_STATE_UNPACK0:
- p->unpackSize |= (UInt32)b << 8;
- return LZMA2_STATE_UNPACK1;
-
- case LZMA2_STATE_UNPACK1:
- p->unpackSize |= (UInt32)b;
- p->unpackSize++;
- PRF(printf(" %7u", (unsigned)p->unpackSize));
- return LZMA2_IS_UNCOMPRESSED_STATE(p) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0;
-
- case LZMA2_STATE_PACK0:
- p->packSize = (UInt32)b << 8;
- return LZMA2_STATE_PACK1;
-
- case LZMA2_STATE_PACK1:
- p->packSize |= (UInt32)b;
- p->packSize++;
- // if (p->packSize < 5) return LZMA2_STATE_ERROR;
- PRF(printf(" %5u", (unsigned)p->packSize));
- return (p->control & 0x40) ? LZMA2_STATE_PROP : LZMA2_STATE_DATA;
-
- case LZMA2_STATE_PROP:
- {
- unsigned lc, lp;
- if (b >= (9 * 5 * 5))
- return LZMA2_STATE_ERROR;
- lc = b % 9;
- b /= 9;
- p->decoder.prop.pb = (Byte)(b / 5);
- lp = b % 5;
- if (lc + lp > LZMA2_LCLP_MAX)
- return LZMA2_STATE_ERROR;
- p->decoder.prop.lc = (Byte)lc;
- p->decoder.prop.lp = (Byte)lp;
- return LZMA2_STATE_DATA;
- }
- }
- return LZMA2_STATE_ERROR;
-}
-
-static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size)
-{
- memcpy(p->dic + p->dicPos, src, size);
- p->dicPos += size;
- if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size)
- p->checkDicSize = p->prop.dicSize;
- p->processedPos += (UInt32)size;
-}
-
-void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState);
-
-
-SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
- const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
-{
- SizeT inSize = *srcLen;
- *srcLen = 0;
- *status = LZMA_STATUS_NOT_SPECIFIED;
-
- while (p->state != LZMA2_STATE_ERROR)
- {
- SizeT dicPos;
-
- if (p->state == LZMA2_STATE_FINISHED)
- {
- *status = LZMA_STATUS_FINISHED_WITH_MARK;
- return SZ_OK;
- }
-
- dicPos = p->decoder.dicPos;
-
- if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY)
- {
- *status = LZMA_STATUS_NOT_FINISHED;
- return SZ_OK;
- }
-
- if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT)
- {
- if (*srcLen == inSize)
- {
- *status = LZMA_STATUS_NEEDS_MORE_INPUT;
- return SZ_OK;
- }
- (*srcLen)++;
- p->state = Lzma2Dec_UpdateState(p, *src++);
- if (dicPos == dicLimit && p->state != LZMA2_STATE_FINISHED)
- break;
- continue;
- }
-
- {
- SizeT inCur = inSize - *srcLen;
- SizeT outCur = dicLimit - dicPos;
- ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY;
-
- if (outCur >= p->unpackSize)
- {
- outCur = (SizeT)p->unpackSize;
- curFinishMode = LZMA_FINISH_END;
- }
-
- if (LZMA2_IS_UNCOMPRESSED_STATE(p))
- {
- if (inCur == 0)
- {
- *status = LZMA_STATUS_NEEDS_MORE_INPUT;
- return SZ_OK;
- }
-
- if (p->state == LZMA2_STATE_DATA)
- {
- BoolInt initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC);
- LzmaDec_InitDicAndState(&p->decoder, initDic, False);
- }
-
- if (inCur > outCur)
- inCur = outCur;
- if (inCur == 0)
- break;
-
- LzmaDec_UpdateWithUncompressed(&p->decoder, src, inCur);
-
- src += inCur;
- *srcLen += inCur;
- p->unpackSize -= (UInt32)inCur;
- p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT;
- }
- else
- {
- SRes res;
-
- if (p->state == LZMA2_STATE_DATA)
- {
- BoolInt initDic = (p->control >= 0xE0);
- BoolInt initState = (p->control >= 0xA0);
- LzmaDec_InitDicAndState(&p->decoder, initDic, initState);
- p->state = LZMA2_STATE_DATA_CONT;
- }
-
- if (inCur > p->packSize)
- inCur = (SizeT)p->packSize;
-
- res = LzmaDec_DecodeToDic(&p->decoder, dicPos + outCur, src, &inCur, curFinishMode, status);
-
- src += inCur;
- *srcLen += inCur;
- p->packSize -= (UInt32)inCur;
- outCur = p->decoder.dicPos - dicPos;
- p->unpackSize -= (UInt32)outCur;
-
- if (res != 0)
- break;
-
- if (*status == LZMA_STATUS_NEEDS_MORE_INPUT)
- {
- if (p->packSize == 0)
- break;
- return SZ_OK;
- }
-
- if (inCur == 0 && outCur == 0)
- {
- if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
- || p->unpackSize != 0
- || p->packSize != 0)
- break;
- p->state = LZMA2_STATE_CONTROL;
- }
-
- *status = LZMA_STATUS_NOT_SPECIFIED;
- }
- }
- }
-
- *status = LZMA_STATUS_NOT_SPECIFIED;
- p->state = LZMA2_STATE_ERROR;
- return SZ_ERROR_DATA;
-}
-
-
-
-
-ELzma2ParseStatus Lzma2Dec_Parse(CLzma2Dec *p,
- SizeT outSize,
- const Byte *src, SizeT *srcLen,
- int checkFinishBlock)
-{
- SizeT inSize = *srcLen;
- *srcLen = 0;
-
- while (p->state != LZMA2_STATE_ERROR)
- {
- if (p->state == LZMA2_STATE_FINISHED)
- return (ELzma2ParseStatus)LZMA_STATUS_FINISHED_WITH_MARK;
-
- if (outSize == 0 && !checkFinishBlock)
- return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED;
-
- if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT)
- {
- if (*srcLen == inSize)
- return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT;
- (*srcLen)++;
-
- p->state = Lzma2Dec_UpdateState(p, *src++);
-
- if (p->state == LZMA2_STATE_UNPACK0)
- {
- // if (p->decoder.dicPos != 0)
- if (p->control == LZMA2_CONTROL_COPY_RESET_DIC || p->control >= 0xE0)
- return LZMA2_PARSE_STATUS_NEW_BLOCK;
- // if (outSize == 0) return LZMA_STATUS_NOT_FINISHED;
- }
-
- // The following code can be commented.
- // It's not big problem, if we read additional input bytes.
- // It will be stopped later in LZMA2_STATE_DATA / LZMA2_STATE_DATA_CONT state.
-
- if (outSize == 0 && p->state != LZMA2_STATE_FINISHED)
- {
- // checkFinishBlock is true. So we expect that block must be finished,
- // We can return LZMA_STATUS_NOT_SPECIFIED or LZMA_STATUS_NOT_FINISHED here
- // break;
- return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED;
- }
-
- if (p->state == LZMA2_STATE_DATA)
- return LZMA2_PARSE_STATUS_NEW_CHUNK;
-
- continue;
- }
-
- if (outSize == 0)
- return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED;
-
- {
- SizeT inCur = inSize - *srcLen;
-
- if (LZMA2_IS_UNCOMPRESSED_STATE(p))
- {
- if (inCur == 0)
- return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT;
- if (inCur > p->unpackSize)
- inCur = p->unpackSize;
- if (inCur > outSize)
- inCur = outSize;
- p->decoder.dicPos += inCur;
- src += inCur;
- *srcLen += inCur;
- outSize -= inCur;
- p->unpackSize -= (UInt32)inCur;
- p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT;
- }
- else
- {
- p->isExtraMode = True;
-
- if (inCur == 0)
- {
- if (p->packSize != 0)
- return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT;
- }
- else if (p->state == LZMA2_STATE_DATA)
- {
- p->state = LZMA2_STATE_DATA_CONT;
- if (*src != 0)
- {
- // first byte of lzma chunk must be Zero
- *srcLen += 1;
- p->packSize--;
- break;
- }
- }
-
- if (inCur > p->packSize)
- inCur = (SizeT)p->packSize;
-
- src += inCur;
- *srcLen += inCur;
- p->packSize -= (UInt32)inCur;
-
- if (p->packSize == 0)
- {
- SizeT rem = outSize;
- if (rem > p->unpackSize)
- rem = p->unpackSize;
- p->decoder.dicPos += rem;
- p->unpackSize -= (UInt32)rem;
- outSize -= rem;
- if (p->unpackSize == 0)
- p->state = LZMA2_STATE_CONTROL;
- }
- }
- }
- }
-
- p->state = LZMA2_STATE_ERROR;
- return (ELzma2ParseStatus)LZMA_STATUS_NOT_SPECIFIED;
-}
-
-
-
-
-SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
-{
- SizeT outSize = *destLen, inSize = *srcLen;
- *srcLen = *destLen = 0;
-
- for (;;)
- {
- SizeT inCur = inSize, outCur, dicPos;
- ELzmaFinishMode curFinishMode;
- SRes res;
-
- if (p->decoder.dicPos == p->decoder.dicBufSize)
- p->decoder.dicPos = 0;
- dicPos = p->decoder.dicPos;
- curFinishMode = LZMA_FINISH_ANY;
- outCur = p->decoder.dicBufSize - dicPos;
-
- if (outCur >= outSize)
- {
- outCur = outSize;
- curFinishMode = finishMode;
- }
-
- res = Lzma2Dec_DecodeToDic(p, dicPos + outCur, src, &inCur, curFinishMode, status);
-
- src += inCur;
- inSize -= inCur;
- *srcLen += inCur;
- outCur = p->decoder.dicPos - dicPos;
- memcpy(dest, p->decoder.dic + dicPos, outCur);
- dest += outCur;
- outSize -= outCur;
- *destLen += outCur;
- if (res != 0)
- return res;
- if (outCur == 0 || outSize == 0)
- return SZ_OK;
- }
-}
-
-
-SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
- Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAllocPtr alloc)
-{
- CLzma2Dec p;
- SRes res;
- SizeT outSize = *destLen, inSize = *srcLen;
- *destLen = *srcLen = 0;
- *status = LZMA_STATUS_NOT_SPECIFIED;
- Lzma2Dec_Construct(&p);
- RINOK(Lzma2Dec_AllocateProbs(&p, prop, alloc));
- p.decoder.dic = dest;
- p.decoder.dicBufSize = outSize;
- Lzma2Dec_Init(&p);
- *srcLen = inSize;
- res = Lzma2Dec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
- *destLen = p.decoder.dicPos;
- if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
- res = SZ_ERROR_INPUT_EOF;
- Lzma2Dec_FreeProbs(&p, alloc);
- return res;
-}
+/* Lzma2Dec.c -- LZMA2 Decoder
+2023-03-03 : Igor Pavlov : Public domain */
+
+/* #define SHOW_DEBUG_INFO */
+
+#include "Precomp.h"
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#endif
+
+#include <string.h>
+
+#include "Lzma2Dec.h"
+
+/*
+00000000 - End of data
+00000001 U U - Uncompressed, reset dic, need reset state and set new prop
+00000010 U U - Uncompressed, no reset
+100uuuuu U U P P - LZMA, no reset
+101uuuuu U U P P - LZMA, reset state
+110uuuuu U U P P S - LZMA, reset state + set new prop
+111uuuuu U U P P S - LZMA, reset state + set new prop, reset dic
+
+ u, U - Unpack Size
+ P - Pack Size
+ S - Props
+*/
+
+#define LZMA2_CONTROL_COPY_RESET_DIC 1
+
+#define LZMA2_IS_UNCOMPRESSED_STATE(p) (((p)->control & (1 << 7)) == 0)
+
+#define LZMA2_LCLP_MAX 4
+#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11))
+
+#ifdef SHOW_DEBUG_INFO
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+typedef enum
+{
+ LZMA2_STATE_CONTROL,
+ LZMA2_STATE_UNPACK0,
+ LZMA2_STATE_UNPACK1,
+ LZMA2_STATE_PACK0,
+ LZMA2_STATE_PACK1,
+ LZMA2_STATE_PROP,
+ LZMA2_STATE_DATA,
+ LZMA2_STATE_DATA_CONT,
+ LZMA2_STATE_FINISHED,
+ LZMA2_STATE_ERROR
+} ELzma2State;
+
+static SRes Lzma2Dec_GetOldProps(Byte prop, Byte *props)
+{
+ UInt32 dicSize;
+ if (prop > 40)
+ return SZ_ERROR_UNSUPPORTED;
+ dicSize = (prop == 40) ? 0xFFFFFFFF : LZMA2_DIC_SIZE_FROM_PROP(prop);
+ props[0] = (Byte)LZMA2_LCLP_MAX;
+ props[1] = (Byte)(dicSize);
+ props[2] = (Byte)(dicSize >> 8);
+ props[3] = (Byte)(dicSize >> 16);
+ props[4] = (Byte)(dicSize >> 24);
+ return SZ_OK;
+}
+
+SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc)
+{
+ Byte props[LZMA_PROPS_SIZE];
+ RINOK(Lzma2Dec_GetOldProps(prop, props))
+ return LzmaDec_AllocateProbs(&p->decoder, props, LZMA_PROPS_SIZE, alloc);
+}
+
+SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc)
+{
+ Byte props[LZMA_PROPS_SIZE];
+ RINOK(Lzma2Dec_GetOldProps(prop, props))
+ return LzmaDec_Allocate(&p->decoder, props, LZMA_PROPS_SIZE, alloc);
+}
+
+void Lzma2Dec_Init(CLzma2Dec *p)
+{
+ p->state = LZMA2_STATE_CONTROL;
+ p->needInitLevel = 0xE0;
+ p->isExtraMode = False;
+ p->unpackSize = 0;
+
+ // p->decoder.dicPos = 0; // we can use it instead of full init
+ LzmaDec_Init(&p->decoder);
+}
+
+// ELzma2State
+static unsigned Lzma2Dec_UpdateState(CLzma2Dec *p, Byte b)
+{
+ switch (p->state)
+ {
+ case LZMA2_STATE_CONTROL:
+ p->isExtraMode = False;
+ p->control = b;
+ PRF(printf("\n %8X", (unsigned)p->decoder.dicPos));
+ PRF(printf(" %02X", (unsigned)b));
+ if (b == 0)
+ return LZMA2_STATE_FINISHED;
+ if (LZMA2_IS_UNCOMPRESSED_STATE(p))
+ {
+ if (b == LZMA2_CONTROL_COPY_RESET_DIC)
+ p->needInitLevel = 0xC0;
+ else if (b > 2 || p->needInitLevel == 0xE0)
+ return LZMA2_STATE_ERROR;
+ }
+ else
+ {
+ if (b < p->needInitLevel)
+ return LZMA2_STATE_ERROR;
+ p->needInitLevel = 0;
+ p->unpackSize = (UInt32)(b & 0x1F) << 16;
+ }
+ return LZMA2_STATE_UNPACK0;
+
+ case LZMA2_STATE_UNPACK0:
+ p->unpackSize |= (UInt32)b << 8;
+ return LZMA2_STATE_UNPACK1;
+
+ case LZMA2_STATE_UNPACK1:
+ p->unpackSize |= (UInt32)b;
+ p->unpackSize++;
+ PRF(printf(" %7u", (unsigned)p->unpackSize));
+ return LZMA2_IS_UNCOMPRESSED_STATE(p) ? LZMA2_STATE_DATA : LZMA2_STATE_PACK0;
+
+ case LZMA2_STATE_PACK0:
+ p->packSize = (UInt32)b << 8;
+ return LZMA2_STATE_PACK1;
+
+ case LZMA2_STATE_PACK1:
+ p->packSize |= (UInt32)b;
+ p->packSize++;
+ // if (p->packSize < 5) return LZMA2_STATE_ERROR;
+ PRF(printf(" %5u", (unsigned)p->packSize));
+ return (p->control & 0x40) ? LZMA2_STATE_PROP : LZMA2_STATE_DATA;
+
+ case LZMA2_STATE_PROP:
+ {
+ unsigned lc, lp;
+ if (b >= (9 * 5 * 5))
+ return LZMA2_STATE_ERROR;
+ lc = b % 9;
+ b /= 9;
+ p->decoder.prop.pb = (Byte)(b / 5);
+ lp = b % 5;
+ if (lc + lp > LZMA2_LCLP_MAX)
+ return LZMA2_STATE_ERROR;
+ p->decoder.prop.lc = (Byte)lc;
+ p->decoder.prop.lp = (Byte)lp;
+ return LZMA2_STATE_DATA;
+ }
+ }
+ return LZMA2_STATE_ERROR;
+}
+
+static void LzmaDec_UpdateWithUncompressed(CLzmaDec *p, const Byte *src, SizeT size)
+{
+ memcpy(p->dic + p->dicPos, src, size);
+ p->dicPos += size;
+ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= size)
+ p->checkDicSize = p->prop.dicSize;
+ p->processedPos += (UInt32)size;
+}
+
+void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState);
+
+
+SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT inSize = *srcLen;
+ *srcLen = 0;
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+
+ while (p->state != LZMA2_STATE_ERROR)
+ {
+ SizeT dicPos;
+
+ if (p->state == LZMA2_STATE_FINISHED)
+ {
+ *status = LZMA_STATUS_FINISHED_WITH_MARK;
+ return SZ_OK;
+ }
+
+ dicPos = p->decoder.dicPos;
+
+ if (dicPos == dicLimit && finishMode == LZMA_FINISH_ANY)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_OK;
+ }
+
+ if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT)
+ {
+ if (*srcLen == inSize)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ (*srcLen)++;
+ p->state = Lzma2Dec_UpdateState(p, *src++);
+ if (dicPos == dicLimit && p->state != LZMA2_STATE_FINISHED)
+ break;
+ continue;
+ }
+
+ {
+ SizeT inCur = inSize - *srcLen;
+ SizeT outCur = dicLimit - dicPos;
+ ELzmaFinishMode curFinishMode = LZMA_FINISH_ANY;
+
+ if (outCur >= p->unpackSize)
+ {
+ outCur = (SizeT)p->unpackSize;
+ curFinishMode = LZMA_FINISH_END;
+ }
+
+ if (LZMA2_IS_UNCOMPRESSED_STATE(p))
+ {
+ if (inCur == 0)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+
+ if (p->state == LZMA2_STATE_DATA)
+ {
+ BoolInt initDic = (p->control == LZMA2_CONTROL_COPY_RESET_DIC);
+ LzmaDec_InitDicAndState(&p->decoder, initDic, False);
+ }
+
+ if (inCur > outCur)
+ inCur = outCur;
+ if (inCur == 0)
+ break;
+
+ LzmaDec_UpdateWithUncompressed(&p->decoder, src, inCur);
+
+ src += inCur;
+ *srcLen += inCur;
+ p->unpackSize -= (UInt32)inCur;
+ p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT;
+ }
+ else
+ {
+ SRes res;
+
+ if (p->state == LZMA2_STATE_DATA)
+ {
+ BoolInt initDic = (p->control >= 0xE0);
+ BoolInt initState = (p->control >= 0xA0);
+ LzmaDec_InitDicAndState(&p->decoder, initDic, initState);
+ p->state = LZMA2_STATE_DATA_CONT;
+ }
+
+ if (inCur > p->packSize)
+ inCur = (SizeT)p->packSize;
+
+ res = LzmaDec_DecodeToDic(&p->decoder, dicPos + outCur, src, &inCur, curFinishMode, status);
+
+ src += inCur;
+ *srcLen += inCur;
+ p->packSize -= (UInt32)inCur;
+ outCur = p->decoder.dicPos - dicPos;
+ p->unpackSize -= (UInt32)outCur;
+
+ if (res != 0)
+ break;
+
+ if (*status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ {
+ if (p->packSize == 0)
+ break;
+ return SZ_OK;
+ }
+
+ if (inCur == 0 && outCur == 0)
+ {
+ if (*status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ || p->unpackSize != 0
+ || p->packSize != 0)
+ break;
+ p->state = LZMA2_STATE_CONTROL;
+ }
+
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+ }
+ }
+ }
+
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+ p->state = LZMA2_STATE_ERROR;
+ return SZ_ERROR_DATA;
+}
+
+
+
+
+ELzma2ParseStatus Lzma2Dec_Parse(CLzma2Dec *p,
+ SizeT outSize,
+ const Byte *src, SizeT *srcLen,
+ int checkFinishBlock)
+{
+ SizeT inSize = *srcLen;
+ *srcLen = 0;
+
+ while (p->state != LZMA2_STATE_ERROR)
+ {
+ if (p->state == LZMA2_STATE_FINISHED)
+ return (ELzma2ParseStatus)LZMA_STATUS_FINISHED_WITH_MARK;
+
+ if (outSize == 0 && !checkFinishBlock)
+ return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED;
+
+ if (p->state != LZMA2_STATE_DATA && p->state != LZMA2_STATE_DATA_CONT)
+ {
+ if (*srcLen == inSize)
+ return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT;
+ (*srcLen)++;
+
+ p->state = Lzma2Dec_UpdateState(p, *src++);
+
+ if (p->state == LZMA2_STATE_UNPACK0)
+ {
+ // if (p->decoder.dicPos != 0)
+ if (p->control == LZMA2_CONTROL_COPY_RESET_DIC || p->control >= 0xE0)
+ return LZMA2_PARSE_STATUS_NEW_BLOCK;
+ // if (outSize == 0) return LZMA_STATUS_NOT_FINISHED;
+ }
+
+ // The following code can be commented.
+ // It's not big problem, if we read additional input bytes.
+ // It will be stopped later in LZMA2_STATE_DATA / LZMA2_STATE_DATA_CONT state.
+
+ if (outSize == 0 && p->state != LZMA2_STATE_FINISHED)
+ {
+ // checkFinishBlock is true. So we expect that block must be finished,
+ // We can return LZMA_STATUS_NOT_SPECIFIED or LZMA_STATUS_NOT_FINISHED here
+ // break;
+ return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED;
+ }
+
+ if (p->state == LZMA2_STATE_DATA)
+ return LZMA2_PARSE_STATUS_NEW_CHUNK;
+
+ continue;
+ }
+
+ if (outSize == 0)
+ return (ELzma2ParseStatus)LZMA_STATUS_NOT_FINISHED;
+
+ {
+ SizeT inCur = inSize - *srcLen;
+
+ if (LZMA2_IS_UNCOMPRESSED_STATE(p))
+ {
+ if (inCur == 0)
+ return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT;
+ if (inCur > p->unpackSize)
+ inCur = p->unpackSize;
+ if (inCur > outSize)
+ inCur = outSize;
+ p->decoder.dicPos += inCur;
+ src += inCur;
+ *srcLen += inCur;
+ outSize -= inCur;
+ p->unpackSize -= (UInt32)inCur;
+ p->state = (p->unpackSize == 0) ? LZMA2_STATE_CONTROL : LZMA2_STATE_DATA_CONT;
+ }
+ else
+ {
+ p->isExtraMode = True;
+
+ if (inCur == 0)
+ {
+ if (p->packSize != 0)
+ return (ELzma2ParseStatus)LZMA_STATUS_NEEDS_MORE_INPUT;
+ }
+ else if (p->state == LZMA2_STATE_DATA)
+ {
+ p->state = LZMA2_STATE_DATA_CONT;
+ if (*src != 0)
+ {
+ // first byte of lzma chunk must be Zero
+ *srcLen += 1;
+ p->packSize--;
+ break;
+ }
+ }
+
+ if (inCur > p->packSize)
+ inCur = (SizeT)p->packSize;
+
+ src += inCur;
+ *srcLen += inCur;
+ p->packSize -= (UInt32)inCur;
+
+ if (p->packSize == 0)
+ {
+ SizeT rem = outSize;
+ if (rem > p->unpackSize)
+ rem = p->unpackSize;
+ p->decoder.dicPos += rem;
+ p->unpackSize -= (UInt32)rem;
+ outSize -= rem;
+ if (p->unpackSize == 0)
+ p->state = LZMA2_STATE_CONTROL;
+ }
+ }
+ }
+ }
+
+ p->state = LZMA2_STATE_ERROR;
+ return (ELzma2ParseStatus)LZMA_STATUS_NOT_SPECIFIED;
+}
+
+
+
+
+SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT outSize = *destLen, inSize = *srcLen;
+ *srcLen = *destLen = 0;
+
+ for (;;)
+ {
+ SizeT inCur = inSize, outCur, dicPos;
+ ELzmaFinishMode curFinishMode;
+ SRes res;
+
+ if (p->decoder.dicPos == p->decoder.dicBufSize)
+ p->decoder.dicPos = 0;
+ dicPos = p->decoder.dicPos;
+ curFinishMode = LZMA_FINISH_ANY;
+ outCur = p->decoder.dicBufSize - dicPos;
+
+ if (outCur >= outSize)
+ {
+ outCur = outSize;
+ curFinishMode = finishMode;
+ }
+
+ res = Lzma2Dec_DecodeToDic(p, dicPos + outCur, src, &inCur, curFinishMode, status);
+
+ src += inCur;
+ inSize -= inCur;
+ *srcLen += inCur;
+ outCur = p->decoder.dicPos - dicPos;
+ memcpy(dest, p->decoder.dic + dicPos, outCur);
+ dest += outCur;
+ outSize -= outCur;
+ *destLen += outCur;
+ if (res != 0)
+ return res;
+ if (outCur == 0 || outSize == 0)
+ return SZ_OK;
+ }
+}
+
+
+SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAllocPtr alloc)
+{
+ CLzma2Dec p;
+ SRes res;
+ SizeT outSize = *destLen, inSize = *srcLen;
+ *destLen = *srcLen = 0;
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+ Lzma2Dec_CONSTRUCT(&p)
+ RINOK(Lzma2Dec_AllocateProbs(&p, prop, alloc))
+ p.decoder.dic = dest;
+ p.decoder.dicBufSize = outSize;
+ Lzma2Dec_Init(&p);
+ *srcLen = inSize;
+ res = Lzma2Dec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
+ *destLen = p.decoder.dicPos;
+ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ res = SZ_ERROR_INPUT_EOF;
+ Lzma2Dec_FreeProbs(&p, alloc);
+ return res;
+}
+
+#undef PRF
diff --git a/C/Lzma2Dec.h b/C/Lzma2Dec.h
index da50387..1f5233a 100644
--- a/C/Lzma2Dec.h
+++ b/C/Lzma2Dec.h
@@ -1,120 +1,121 @@
-/* Lzma2Dec.h -- LZMA2 Decoder
-2018-02-19 : Igor Pavlov : Public domain */
-
-#ifndef __LZMA2_DEC_H
-#define __LZMA2_DEC_H
-
-#include "LzmaDec.h"
-
-EXTERN_C_BEGIN
-
-/* ---------- State Interface ---------- */
-
-typedef struct
-{
- unsigned state;
- Byte control;
- Byte needInitLevel;
- Byte isExtraMode;
- Byte _pad_;
- UInt32 packSize;
- UInt32 unpackSize;
- CLzmaDec decoder;
-} CLzma2Dec;
-
-#define Lzma2Dec_Construct(p) LzmaDec_Construct(&(p)->decoder)
-#define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc)
-#define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc)
-
-SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc);
-SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc);
-void Lzma2Dec_Init(CLzma2Dec *p);
-
-/*
-finishMode:
- It has meaning only if the decoding reaches output limit (*destLen or dicLimit).
- LZMA_FINISH_ANY - use smallest number of input bytes
- LZMA_FINISH_END - read EndOfStream marker after decoding
-
-Returns:
- SZ_OK
- status:
- LZMA_STATUS_FINISHED_WITH_MARK
- LZMA_STATUS_NOT_FINISHED
- LZMA_STATUS_NEEDS_MORE_INPUT
- SZ_ERROR_DATA - Data error
-*/
-
-SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
- const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
-
-SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen,
- const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
-
-
-/* ---------- LZMA2 block and chunk parsing ---------- */
-
-/*
-Lzma2Dec_Parse() parses compressed data stream up to next independent block or next chunk data.
-It can return LZMA_STATUS_* code or LZMA2_PARSE_STATUS_* code:
- - LZMA2_PARSE_STATUS_NEW_BLOCK - there is new block, and 1 additional byte (control byte of next block header) was read from input.
- - LZMA2_PARSE_STATUS_NEW_CHUNK - there is new chunk, and only lzma2 header of new chunk was read.
- CLzma2Dec::unpackSize contains unpack size of that chunk
-*/
-
-typedef enum
-{
-/*
- LZMA_STATUS_NOT_SPECIFIED // data error
- LZMA_STATUS_FINISHED_WITH_MARK
- LZMA_STATUS_NOT_FINISHED //
- LZMA_STATUS_NEEDS_MORE_INPUT
- LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK // unused
-*/
- LZMA2_PARSE_STATUS_NEW_BLOCK = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + 1,
- LZMA2_PARSE_STATUS_NEW_CHUNK
-} ELzma2ParseStatus;
-
-ELzma2ParseStatus Lzma2Dec_Parse(CLzma2Dec *p,
- SizeT outSize, // output size
- const Byte *src, SizeT *srcLen,
- int checkFinishBlock // set (checkFinishBlock = 1), if it must read full input data, if decoder.dicPos reaches blockMax position.
- );
-
-/*
-LZMA2 parser doesn't decode LZMA chunks, so we must read
- full input LZMA chunk to decode some part of LZMA chunk.
-
-Lzma2Dec_GetUnpackExtra() returns the value that shows
- max possible number of output bytes that can be output by decoder
- at current input positon.
-*/
-
-#define Lzma2Dec_GetUnpackExtra(p) ((p)->isExtraMode ? (p)->unpackSize : 0);
-
-
-/* ---------- One Call Interface ---------- */
-
-/*
-finishMode:
- It has meaning only if the decoding reaches output limit (*destLen).
- LZMA_FINISH_ANY - use smallest number of input bytes
- LZMA_FINISH_END - read EndOfStream marker after decoding
-
-Returns:
- SZ_OK
- status:
- LZMA_STATUS_FINISHED_WITH_MARK
- LZMA_STATUS_NOT_FINISHED
- SZ_ERROR_DATA - Data error
- SZ_ERROR_MEM - Memory allocation error
- SZ_ERROR_UNSUPPORTED - Unsupported properties
- SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
-*/
-
-SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
- Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAllocPtr alloc);
-
-EXTERN_C_END
-
-#endif
+/* Lzma2Dec.h -- LZMA2 Decoder
+2023-03-03 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_LZMA2_DEC_H
+#define ZIP7_INC_LZMA2_DEC_H
+
+#include "LzmaDec.h"
+
+EXTERN_C_BEGIN
+
+/* ---------- State Interface ---------- */
+
+typedef struct
+{
+ unsigned state;
+ Byte control;
+ Byte needInitLevel;
+ Byte isExtraMode;
+ Byte _pad_;
+ UInt32 packSize;
+ UInt32 unpackSize;
+ CLzmaDec decoder;
+} CLzma2Dec;
+
+#define Lzma2Dec_CONSTRUCT(p) LzmaDec_CONSTRUCT(&(p)->decoder)
+#define Lzma2Dec_Construct(p) Lzma2Dec_CONSTRUCT(p)
+#define Lzma2Dec_FreeProbs(p, alloc) LzmaDec_FreeProbs(&(p)->decoder, alloc)
+#define Lzma2Dec_Free(p, alloc) LzmaDec_Free(&(p)->decoder, alloc)
+
+SRes Lzma2Dec_AllocateProbs(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc);
+SRes Lzma2Dec_Allocate(CLzma2Dec *p, Byte prop, ISzAllocPtr alloc);
+void Lzma2Dec_Init(CLzma2Dec *p);
+
+/*
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen or dicLimit).
+ LZMA_FINISH_ANY - use smallest number of input bytes
+ LZMA_FINISH_END - read EndOfStream marker after decoding
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_NEEDS_MORE_INPUT
+ SZ_ERROR_DATA - Data error
+*/
+
+SRes Lzma2Dec_DecodeToDic(CLzma2Dec *p, SizeT dicLimit,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+SRes Lzma2Dec_DecodeToBuf(CLzma2Dec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- LZMA2 block and chunk parsing ---------- */
+
+/*
+Lzma2Dec_Parse() parses compressed data stream up to next independent block or next chunk data.
+It can return LZMA_STATUS_* code or LZMA2_PARSE_STATUS_* code:
+ - LZMA2_PARSE_STATUS_NEW_BLOCK - there is new block, and 1 additional byte (control byte of next block header) was read from input.
+ - LZMA2_PARSE_STATUS_NEW_CHUNK - there is new chunk, and only lzma2 header of new chunk was read.
+ CLzma2Dec::unpackSize contains unpack size of that chunk
+*/
+
+typedef enum
+{
+/*
+ LZMA_STATUS_NOT_SPECIFIED // data error
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED //
+ LZMA_STATUS_NEEDS_MORE_INPUT
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK // unused
+*/
+ LZMA2_PARSE_STATUS_NEW_BLOCK = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK + 1,
+ LZMA2_PARSE_STATUS_NEW_CHUNK
+} ELzma2ParseStatus;
+
+ELzma2ParseStatus Lzma2Dec_Parse(CLzma2Dec *p,
+ SizeT outSize, // output size
+ const Byte *src, SizeT *srcLen,
+ int checkFinishBlock // set (checkFinishBlock = 1), if it must read full input data, if decoder.dicPos reaches blockMax position.
+ );
+
+/*
+LZMA2 parser doesn't decode LZMA chunks, so we must read
+ full input LZMA chunk to decode some part of LZMA chunk.
+
+Lzma2Dec_GetUnpackExtra() returns the value that shows
+ max possible number of output bytes that can be output by decoder
+ at current input positon.
+*/
+
+#define Lzma2Dec_GetUnpackExtra(p) ((p)->isExtraMode ? (p)->unpackSize : 0)
+
+
+/* ---------- One Call Interface ---------- */
+
+/*
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - use smallest number of input bytes
+ LZMA_FINISH_END - read EndOfStream marker after decoding
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+*/
+
+SRes Lzma2Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ Byte prop, ELzmaFinishMode finishMode, ELzmaStatus *status, ISzAllocPtr alloc);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Lzma2DecMt.c b/C/Lzma2DecMt.c
index 87d5567..4bc4dde 100644
--- a/C/Lzma2DecMt.c
+++ b/C/Lzma2DecMt.c
@@ -1,1082 +1,1095 @@
-/* Lzma2DecMt.c -- LZMA2 Decoder Multi-thread
-2019-02-02 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-// #define SHOW_DEBUG_INFO
-
-#ifdef SHOW_DEBUG_INFO
-#include <stdio.h>
-#endif
-
-#ifdef SHOW_DEBUG_INFO
-#define PRF(x) x
-#else
-#define PRF(x)
-#endif
-
-#define PRF_STR(s) PRF(printf("\n" s "\n"))
-#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d))
-#define PRF_STR_INT_2(s, d1, d2) PRF(printf("\n" s " %d %d\n", (unsigned)d1, (unsigned)d2))
-
-// #define _7ZIP_ST
-
-#include "Alloc.h"
-
-#include "Lzma2Dec.h"
-#include "Lzma2DecMt.h"
-
-#ifndef _7ZIP_ST
-#include "MtDec.h"
-#endif
-
-
-#define LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT (1 << 28)
-
-void Lzma2DecMtProps_Init(CLzma2DecMtProps *p)
-{
- p->inBufSize_ST = 1 << 20;
- p->outStep_ST = 1 << 20;
-
- #ifndef _7ZIP_ST
- p->numThreads = 1;
- p->inBufSize_MT = 1 << 18;
- p->outBlockMax = LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT;
- p->inBlockMax = p->outBlockMax + p->outBlockMax / 16;
- #endif
-}
-
-
-
-#ifndef _7ZIP_ST
-
-/* ---------- CLzma2DecMtThread ---------- */
-
-typedef struct
-{
- CLzma2Dec dec;
- Byte dec_created;
- Byte needInit;
-
- Byte *outBuf;
- size_t outBufSize;
-
- EMtDecParseState state;
- ELzma2ParseStatus parseStatus;
-
- size_t inPreSize;
- size_t outPreSize;
-
- size_t inCodeSize;
- size_t outCodeSize;
- SRes codeRes;
-
- CAlignOffsetAlloc alloc;
-
- Byte mtPad[1 << 7];
-} CLzma2DecMtThread;
-
-#endif
-
-
-/* ---------- CLzma2DecMt ---------- */
-
-typedef struct
-{
- // ISzAllocPtr alloc;
- ISzAllocPtr allocMid;
-
- CAlignOffsetAlloc alignOffsetAlloc;
- CLzma2DecMtProps props;
- Byte prop;
-
- ISeqInStream *inStream;
- ISeqOutStream *outStream;
- ICompressProgress *progress;
-
- BoolInt finishMode;
- BoolInt outSize_Defined;
- UInt64 outSize;
-
- UInt64 outProcessed;
- UInt64 inProcessed;
- BoolInt readWasFinished;
- SRes readRes;
-
- Byte *inBuf;
- size_t inBufSize;
- Byte dec_created;
- CLzma2Dec dec;
-
- size_t inPos;
- size_t inLim;
-
- #ifndef _7ZIP_ST
- UInt64 outProcessed_Parse;
- BoolInt mtc_WasConstructed;
- CMtDec mtc;
- CLzma2DecMtThread coders[MTDEC__THREADS_MAX];
- #endif
-
-} CLzma2DecMt;
-
-
-
-CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid)
-{
- CLzma2DecMt *p = (CLzma2DecMt *)ISzAlloc_Alloc(alloc, sizeof(CLzma2DecMt));
- if (!p)
- return NULL;
-
- // p->alloc = alloc;
- p->allocMid = allocMid;
-
- AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc);
- p->alignOffsetAlloc.numAlignBits = 7;
- p->alignOffsetAlloc.offset = 0;
- p->alignOffsetAlloc.baseAlloc = alloc;
-
- p->inBuf = NULL;
- p->inBufSize = 0;
- p->dec_created = False;
-
- // Lzma2DecMtProps_Init(&p->props);
-
- #ifndef _7ZIP_ST
- p->mtc_WasConstructed = False;
- {
- unsigned i;
- for (i = 0; i < MTDEC__THREADS_MAX; i++)
- {
- CLzma2DecMtThread *t = &p->coders[i];
- t->dec_created = False;
- t->outBuf = NULL;
- t->outBufSize = 0;
- }
- }
- #endif
-
- return p;
-}
-
-
-#ifndef _7ZIP_ST
-
-static void Lzma2DecMt_FreeOutBufs(CLzma2DecMt *p)
-{
- unsigned i;
- for (i = 0; i < MTDEC__THREADS_MAX; i++)
- {
- CLzma2DecMtThread *t = &p->coders[i];
- if (t->outBuf)
- {
- ISzAlloc_Free(p->allocMid, t->outBuf);
- t->outBuf = NULL;
- t->outBufSize = 0;
- }
- }
-}
-
-#endif
-
-
-static void Lzma2DecMt_FreeSt(CLzma2DecMt *p)
-{
- if (p->dec_created)
- {
- Lzma2Dec_Free(&p->dec, &p->alignOffsetAlloc.vt);
- p->dec_created = False;
- }
- if (p->inBuf)
- {
- ISzAlloc_Free(p->allocMid, p->inBuf);
- p->inBuf = NULL;
- }
- p->inBufSize = 0;
-}
-
-
-void Lzma2DecMt_Destroy(CLzma2DecMtHandle pp)
-{
- CLzma2DecMt *p = (CLzma2DecMt *)pp;
-
- Lzma2DecMt_FreeSt(p);
-
- #ifndef _7ZIP_ST
-
- if (p->mtc_WasConstructed)
- {
- MtDec_Destruct(&p->mtc);
- p->mtc_WasConstructed = False;
- }
- {
- unsigned i;
- for (i = 0; i < MTDEC__THREADS_MAX; i++)
- {
- CLzma2DecMtThread *t = &p->coders[i];
- if (t->dec_created)
- {
- // we don't need to free dict here
- Lzma2Dec_FreeProbs(&t->dec, &t->alloc.vt); // p->alloc !!!
- t->dec_created = False;
- }
- }
- }
- Lzma2DecMt_FreeOutBufs(p);
-
- #endif
-
- ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, pp);
-}
-
-
-
-#ifndef _7ZIP_ST
-
-static void Lzma2DecMt_MtCallback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc)
-{
- CLzma2DecMt *me = (CLzma2DecMt *)obj;
- CLzma2DecMtThread *t = &me->coders[coderIndex];
-
- PRF_STR_INT_2("Parse", coderIndex, cc->srcSize);
-
- cc->state = MTDEC_PARSE_CONTINUE;
-
- if (cc->startCall)
- {
- if (!t->dec_created)
- {
- Lzma2Dec_Construct(&t->dec);
- t->dec_created = True;
- AlignOffsetAlloc_CreateVTable(&t->alloc);
- {
- /* (1 << 12) is expected size of one way in data cache.
- We optimize alignment for cache line size of 128 bytes and smaller */
- const unsigned kNumAlignBits = 12;
- const unsigned kNumCacheLineBits = 7; /* <= kNumAlignBits */
- t->alloc.numAlignBits = kNumAlignBits;
- t->alloc.offset = ((UInt32)coderIndex * ((1 << 11) + (1 << 8) + (1 << 6))) & ((1 << kNumAlignBits) - (1 << kNumCacheLineBits));
- t->alloc.baseAlloc = me->alignOffsetAlloc.baseAlloc;
- }
- }
- Lzma2Dec_Init(&t->dec);
-
- t->inPreSize = 0;
- t->outPreSize = 0;
- // t->blockWasFinished = False;
- // t->finishedWithMark = False;
- t->parseStatus = (ELzma2ParseStatus)LZMA_STATUS_NOT_SPECIFIED;
- t->state = MTDEC_PARSE_CONTINUE;
-
- t->inCodeSize = 0;
- t->outCodeSize = 0;
- t->codeRes = SZ_OK;
-
- // (cc->srcSize == 0) is allowed
- }
-
- {
- ELzma2ParseStatus status;
- BoolInt overflow;
- UInt32 unpackRem = 0;
-
- int checkFinishBlock = True;
- size_t limit = me->props.outBlockMax;
- if (me->outSize_Defined)
- {
- UInt64 rem = me->outSize - me->outProcessed_Parse;
- if (limit >= rem)
- {
- limit = (size_t)rem;
- if (!me->finishMode)
- checkFinishBlock = False;
- }
- }
-
- // checkFinishBlock = False, if we want to decode partial data
- // that must be finished at position <= outBlockMax.
-
- {
- const SizeT srcOrig = cc->srcSize;
- SizeT srcSize_Point = 0;
- SizeT dicPos_Point = 0;
-
- cc->srcSize = 0;
- overflow = False;
-
- for (;;)
- {
- SizeT srcCur = srcOrig - cc->srcSize;
-
- status = Lzma2Dec_Parse(&t->dec,
- limit - t->dec.decoder.dicPos,
- cc->src + cc->srcSize, &srcCur,
- checkFinishBlock);
-
- cc->srcSize += srcCur;
-
- if (status == LZMA2_PARSE_STATUS_NEW_CHUNK)
- {
- if (t->dec.unpackSize > me->props.outBlockMax - t->dec.decoder.dicPos)
- {
- overflow = True;
- break;
- }
- continue;
- }
-
- if (status == LZMA2_PARSE_STATUS_NEW_BLOCK)
- {
- if (t->dec.decoder.dicPos == 0)
- continue;
- // we decode small blocks in one thread
- if (t->dec.decoder.dicPos >= (1 << 14))
- break;
- dicPos_Point = t->dec.decoder.dicPos;
- srcSize_Point = cc->srcSize;
- continue;
- }
-
- if ((int)status == LZMA_STATUS_NOT_FINISHED && checkFinishBlock
- // && limit == t->dec.decoder.dicPos
- // && limit == me->props.outBlockMax
- )
- {
- overflow = True;
- break;
- }
-
- unpackRem = Lzma2Dec_GetUnpackExtra(&t->dec);
- break;
- }
-
- if (dicPos_Point != 0
- && (int)status != LZMA2_PARSE_STATUS_NEW_BLOCK
- && (int)status != LZMA_STATUS_FINISHED_WITH_MARK
- && (int)status != LZMA_STATUS_NOT_SPECIFIED)
- {
- // we revert to latest newBlock state
- status = LZMA2_PARSE_STATUS_NEW_BLOCK;
- unpackRem = 0;
- t->dec.decoder.dicPos = dicPos_Point;
- cc->srcSize = srcSize_Point;
- overflow = False;
- }
- }
-
- t->inPreSize += cc->srcSize;
- t->parseStatus = status;
-
- if (overflow)
- cc->state = MTDEC_PARSE_OVERFLOW;
- else
- {
- size_t dicPos = t->dec.decoder.dicPos;
-
- if ((int)status != LZMA_STATUS_NEEDS_MORE_INPUT)
- {
- if (status == LZMA2_PARSE_STATUS_NEW_BLOCK)
- {
- cc->state = MTDEC_PARSE_NEW;
- cc->srcSize--; // we don't need control byte of next block
- t->inPreSize--;
- }
- else
- {
- cc->state = MTDEC_PARSE_END;
- if ((int)status != LZMA_STATUS_FINISHED_WITH_MARK)
- {
- // (status == LZMA_STATUS_NOT_SPECIFIED)
- // (status == LZMA_STATUS_NOT_FINISHED)
- if (unpackRem != 0)
- {
- /* we also reserve space for max possible number of output bytes of current LZMA chunk */
- SizeT rem = limit - dicPos;
- if (rem > unpackRem)
- rem = unpackRem;
- dicPos += rem;
- }
- }
- }
-
- me->outProcessed_Parse += dicPos;
- }
-
- cc->outPos = dicPos;
- t->outPreSize = (size_t)dicPos;
- }
-
- t->state = cc->state;
- return;
- }
-}
-
-
-static SRes Lzma2DecMt_MtCallback_PreCode(void *pp, unsigned coderIndex)
-{
- CLzma2DecMt *me = (CLzma2DecMt *)pp;
- CLzma2DecMtThread *t = &me->coders[coderIndex];
- Byte *dest = t->outBuf;
-
- if (t->inPreSize == 0)
- {
- t->codeRes = SZ_ERROR_DATA;
- return t->codeRes;
- }
-
- if (!dest || t->outBufSize < t->outPreSize)
- {
- if (dest)
- {
- ISzAlloc_Free(me->allocMid, dest);
- t->outBuf = NULL;
- t->outBufSize = 0;
- }
-
- dest = (Byte *)ISzAlloc_Alloc(me->allocMid, t->outPreSize
- // + (1 << 28)
- );
- // Sleep(200);
- if (!dest)
- return SZ_ERROR_MEM;
- t->outBuf = dest;
- t->outBufSize = t->outPreSize;
- }
-
- t->dec.decoder.dic = dest;
- t->dec.decoder.dicBufSize = t->outPreSize;
-
- t->needInit = True;
-
- return Lzma2Dec_AllocateProbs(&t->dec, me->prop, &t->alloc.vt); // alloc.vt
-}
-
-
-static SRes Lzma2DecMt_MtCallback_Code(void *pp, unsigned coderIndex,
- const Byte *src, size_t srcSize, int srcFinished,
- // int finished, int blockFinished,
- UInt64 *inCodePos, UInt64 *outCodePos, int *stop)
-{
- CLzma2DecMt *me = (CLzma2DecMt *)pp;
- CLzma2DecMtThread *t = &me->coders[coderIndex];
-
- UNUSED_VAR(srcFinished)
-
- PRF_STR_INT_2("Code", coderIndex, srcSize);
-
- *inCodePos = t->inCodeSize;
- *outCodePos = 0;
- *stop = True;
-
- if (t->needInit)
- {
- Lzma2Dec_Init(&t->dec);
- t->needInit = False;
- }
-
- {
- ELzmaStatus status;
- size_t srcProcessed = srcSize;
- BoolInt blockWasFinished =
- ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK
- || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK);
-
- SRes res = Lzma2Dec_DecodeToDic(&t->dec,
- t->outPreSize,
- src, &srcProcessed,
- blockWasFinished ? LZMA_FINISH_END : LZMA_FINISH_ANY,
- &status);
-
- t->codeRes = res;
-
- t->inCodeSize += srcProcessed;
- *inCodePos = t->inCodeSize;
- t->outCodeSize = t->dec.decoder.dicPos;
- *outCodePos = t->dec.decoder.dicPos;
-
- if (res != SZ_OK)
- return res;
-
- if (srcProcessed == srcSize)
- *stop = False;
-
- if (blockWasFinished)
- {
- if (srcSize != srcProcessed)
- return SZ_ERROR_FAIL;
-
- if (t->inPreSize == t->inCodeSize)
- {
- if (t->outPreSize != t->outCodeSize)
- return SZ_ERROR_FAIL;
- *stop = True;
- }
- }
- else
- {
- if (t->outPreSize == t->outCodeSize)
- *stop = True;
- }
-
- return SZ_OK;
- }
-}
-
-
-#define LZMA2DECMT_STREAM_WRITE_STEP (1 << 24)
-
-static SRes Lzma2DecMt_MtCallback_Write(void *pp, unsigned coderIndex,
- BoolInt needWriteToStream,
- const Byte *src, size_t srcSize,
- BoolInt *needContinue, BoolInt *canRecode)
-{
- CLzma2DecMt *me = (CLzma2DecMt *)pp;
- const CLzma2DecMtThread *t = &me->coders[coderIndex];
- size_t size = t->outCodeSize;
- const Byte *data = t->outBuf;
- BoolInt needContinue2 = True;
-
- PRF_STR_INT_2("Write", coderIndex, srcSize);
-
- *needContinue = False;
- *canRecode = True;
- UNUSED_VAR(src)
- UNUSED_VAR(srcSize)
-
- if (
- // t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK
- t->state == MTDEC_PARSE_OVERFLOW
- || t->state == MTDEC_PARSE_END)
- needContinue2 = False;
-
-
- if (!needWriteToStream)
- return SZ_OK;
-
- me->mtc.inProcessed += t->inCodeSize;
-
- if (t->codeRes == SZ_OK)
- if ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK
- || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK)
- if (t->outPreSize != t->outCodeSize
- || t->inPreSize != t->inCodeSize)
- return SZ_ERROR_FAIL;
-
- *canRecode = False;
-
- if (me->outStream)
- {
- for (;;)
- {
- size_t cur = size;
- size_t written;
- if (cur > LZMA2DECMT_STREAM_WRITE_STEP)
- cur = LZMA2DECMT_STREAM_WRITE_STEP;
-
- written = ISeqOutStream_Write(me->outStream, data, cur);
-
- me->outProcessed += written;
- // me->mtc.writtenTotal += written;
- if (written != cur)
- return SZ_ERROR_WRITE;
- data += cur;
- size -= cur;
- if (size == 0)
- {
- *needContinue = needContinue2;
- return SZ_OK;
- }
- RINOK(MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0));
- }
- }
-
- return SZ_ERROR_FAIL;
- /*
- if (size > me->outBufSize)
- return SZ_ERROR_OUTPUT_EOF;
- memcpy(me->outBuf, data, size);
- me->outBufSize -= size;
- me->outBuf += size;
- *needContinue = needContinue2;
- return SZ_OK;
- */
-}
-
-#endif
-
-
-static SRes Lzma2Dec_Prepare_ST(CLzma2DecMt *p)
-{
- if (!p->dec_created)
- {
- Lzma2Dec_Construct(&p->dec);
- p->dec_created = True;
- }
-
- RINOK(Lzma2Dec_Allocate(&p->dec, p->prop, &p->alignOffsetAlloc.vt));
-
- if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST)
- {
- ISzAlloc_Free(p->allocMid, p->inBuf);
- p->inBufSize = 0;
- p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST);
- if (!p->inBuf)
- return SZ_ERROR_MEM;
- p->inBufSize = p->props.inBufSize_ST;
- }
-
- Lzma2Dec_Init(&p->dec);
-
- return SZ_OK;
-}
-
-
-static SRes Lzma2Dec_Decode_ST(CLzma2DecMt *p
- #ifndef _7ZIP_ST
- , BoolInt tMode
- #endif
- )
-{
- SizeT wrPos;
- size_t inPos, inLim;
- const Byte *inData;
- UInt64 inPrev, outPrev;
-
- CLzma2Dec *dec;
-
- #ifndef _7ZIP_ST
- if (tMode)
- {
- Lzma2DecMt_FreeOutBufs(p);
- tMode = MtDec_PrepareRead(&p->mtc);
- }
- #endif
-
- RINOK(Lzma2Dec_Prepare_ST(p));
-
- dec = &p->dec;
-
- inPrev = p->inProcessed;
- outPrev = p->outProcessed;
-
- inPos = 0;
- inLim = 0;
- inData = NULL;
- wrPos = dec->decoder.dicPos;
-
- for (;;)
- {
- SizeT dicPos;
- SizeT size;
- ELzmaFinishMode finishMode;
- SizeT inProcessed;
- ELzmaStatus status;
- SRes res;
-
- SizeT outProcessed;
- BoolInt outFinished;
- BoolInt needStop;
-
- if (inPos == inLim)
- {
- #ifndef _7ZIP_ST
- if (tMode)
- {
- inData = MtDec_Read(&p->mtc, &inLim);
- inPos = 0;
- if (inData)
- continue;
- tMode = False;
- inLim = 0;
- }
- #endif
-
- if (!p->readWasFinished)
- {
- inPos = 0;
- inLim = p->inBufSize;
- inData = p->inBuf;
- p->readRes = ISeqInStream_Read(p->inStream, (void *)inData, &inLim);
- // p->readProcessed += inLim;
- // inLim -= 5; p->readWasFinished = True; // for test
- if (inLim == 0 || p->readRes != SZ_OK)
- p->readWasFinished = True;
- }
- }
-
- dicPos = dec->decoder.dicPos;
- {
- SizeT next = dec->decoder.dicBufSize;
- if (next - wrPos > p->props.outStep_ST)
- next = wrPos + p->props.outStep_ST;
- size = next - dicPos;
- }
-
- finishMode = LZMA_FINISH_ANY;
- if (p->outSize_Defined)
- {
- const UInt64 rem = p->outSize - p->outProcessed;
- if (size >= rem)
- {
- size = (SizeT)rem;
- if (p->finishMode)
- finishMode = LZMA_FINISH_END;
- }
- }
-
- inProcessed = inLim - inPos;
-
- res = Lzma2Dec_DecodeToDic(dec, dicPos + size, inData + inPos, &inProcessed, finishMode, &status);
-
- inPos += inProcessed;
- p->inProcessed += inProcessed;
- outProcessed = dec->decoder.dicPos - dicPos;
- p->outProcessed += outProcessed;
-
- outFinished = (p->outSize_Defined && p->outSize <= p->outProcessed);
-
- needStop = (res != SZ_OK
- || (inProcessed == 0 && outProcessed == 0)
- || status == LZMA_STATUS_FINISHED_WITH_MARK
- || (!p->finishMode && outFinished));
-
- if (needStop || outProcessed >= size)
- {
- SRes res2;
- {
- size_t writeSize = dec->decoder.dicPos - wrPos;
- size_t written = ISeqOutStream_Write(p->outStream, dec->decoder.dic + wrPos, writeSize);
- res2 = (written == writeSize) ? SZ_OK : SZ_ERROR_WRITE;
- }
-
- if (dec->decoder.dicPos == dec->decoder.dicBufSize)
- dec->decoder.dicPos = 0;
- wrPos = dec->decoder.dicPos;
-
- RINOK(res2);
-
- if (needStop)
- {
- if (res != SZ_OK)
- return res;
-
- if (status == LZMA_STATUS_FINISHED_WITH_MARK)
- {
- if (p->finishMode)
- {
- if (p->outSize_Defined && p->outSize != p->outProcessed)
- return SZ_ERROR_DATA;
- }
- return SZ_OK;
- }
-
- if (!p->finishMode && outFinished)
- return SZ_OK;
-
- if (status == LZMA_STATUS_NEEDS_MORE_INPUT)
- return SZ_ERROR_INPUT_EOF;
-
- return SZ_ERROR_DATA;
- }
- }
-
- if (p->progress)
- {
- UInt64 inDelta = p->inProcessed - inPrev;
- UInt64 outDelta = p->outProcessed - outPrev;
- if (inDelta >= (1 << 22) || outDelta >= (1 << 22))
- {
- RINOK(ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed));
- inPrev = p->inProcessed;
- outPrev = p->outProcessed;
- }
- }
- }
-}
-
-
-
-SRes Lzma2DecMt_Decode(CLzma2DecMtHandle pp,
- Byte prop,
- const CLzma2DecMtProps *props,
- ISeqOutStream *outStream, const UInt64 *outDataSize, int finishMode,
- // Byte *outBuf, size_t *outBufSize,
- ISeqInStream *inStream,
- // const Byte *inData, size_t inDataSize,
- UInt64 *inProcessed,
- // UInt64 *outProcessed,
- int *isMT,
- ICompressProgress *progress)
-{
- CLzma2DecMt *p = (CLzma2DecMt *)pp;
- #ifndef _7ZIP_ST
- BoolInt tMode;
- #endif
-
- *inProcessed = 0;
-
- if (prop > 40)
- return SZ_ERROR_UNSUPPORTED;
-
- p->prop = prop;
- p->props = *props;
-
- p->inStream = inStream;
- p->outStream = outStream;
- p->progress = progress;
-
- p->outSize = 0;
- p->outSize_Defined = False;
- if (outDataSize)
- {
- p->outSize_Defined = True;
- p->outSize = *outDataSize;
- }
- p->finishMode = finishMode;
-
- p->outProcessed = 0;
- p->inProcessed = 0;
-
- p->readWasFinished = False;
-
- *isMT = False;
-
-
- #ifndef _7ZIP_ST
-
- tMode = False;
-
- // p->mtc.parseRes = SZ_OK;
-
- // p->mtc.numFilledThreads = 0;
- // p->mtc.crossStart = 0;
- // p->mtc.crossEnd = 0;
- // p->mtc.allocError_for_Read_BlockIndex = 0;
- // p->mtc.isAllocError = False;
-
- if (p->props.numThreads > 1)
- {
- IMtDecCallback vt;
-
- Lzma2DecMt_FreeSt(p);
-
- p->outProcessed_Parse = 0;
-
- if (!p->mtc_WasConstructed)
- {
- p->mtc_WasConstructed = True;
- MtDec_Construct(&p->mtc);
- }
-
- p->mtc.progress = progress;
- p->mtc.inStream = inStream;
-
- // p->outBuf = NULL;
- // p->outBufSize = 0;
- /*
- if (!outStream)
- {
- // p->outBuf = outBuf;
- // p->outBufSize = *outBufSize;
- // *outBufSize = 0;
- return SZ_ERROR_PARAM;
- }
- */
-
- // p->mtc.inBlockMax = p->props.inBlockMax;
- p->mtc.alloc = &p->alignOffsetAlloc.vt;
- // p->alignOffsetAlloc.baseAlloc;
- // p->mtc.inData = inData;
- // p->mtc.inDataSize = inDataSize;
- p->mtc.mtCallback = &vt;
- p->mtc.mtCallbackObject = p;
-
- p->mtc.inBufSize = p->props.inBufSize_MT;
-
- p->mtc.numThreadsMax = p->props.numThreads;
-
- *isMT = True;
-
- vt.Parse = Lzma2DecMt_MtCallback_Parse;
- vt.PreCode = Lzma2DecMt_MtCallback_PreCode;
- vt.Code = Lzma2DecMt_MtCallback_Code;
- vt.Write = Lzma2DecMt_MtCallback_Write;
-
- {
- BoolInt needContinue = False;
-
- SRes res = MtDec_Code(&p->mtc);
-
- /*
- if (!outStream)
- *outBufSize = p->outBuf - outBuf;
- */
-
- *inProcessed = p->mtc.inProcessed;
-
- needContinue = False;
-
- if (res == SZ_OK)
- {
- if (p->mtc.mtProgress.res != SZ_OK)
- res = p->mtc.mtProgress.res;
- else
- needContinue = p->mtc.needContinue;
- }
-
- if (!needContinue)
- {
- if (res == SZ_OK)
- return p->mtc.readRes;
- return res;
- }
-
- tMode = True;
- p->readRes = p->mtc.readRes;
- p->readWasFinished = p->mtc.readWasFinished;
- p->inProcessed = p->mtc.inProcessed;
-
- PRF_STR("----- decoding ST -----");
- }
- }
-
- #endif
-
-
- *isMT = False;
-
- {
- SRes res = Lzma2Dec_Decode_ST(p
- #ifndef _7ZIP_ST
- , tMode
- #endif
- );
-
- *inProcessed = p->inProcessed;
-
- // res = SZ_OK; // for test
- if (res == SZ_OK && p->readRes != SZ_OK)
- res = p->readRes;
-
- /*
- #ifndef _7ZIP_ST
- if (res == SZ_OK && tMode && p->mtc.parseRes != SZ_OK)
- res = p->mtc.parseRes;
- #endif
- */
-
- return res;
- }
-}
-
-
-/* ---------- Read from CLzma2DecMtHandle Interface ---------- */
-
-SRes Lzma2DecMt_Init(CLzma2DecMtHandle pp,
- Byte prop,
- const CLzma2DecMtProps *props,
- const UInt64 *outDataSize, int finishMode,
- ISeqInStream *inStream)
-{
- CLzma2DecMt *p = (CLzma2DecMt *)pp;
-
- if (prop > 40)
- return SZ_ERROR_UNSUPPORTED;
-
- p->prop = prop;
- p->props = *props;
-
- p->inStream = inStream;
-
- p->outSize = 0;
- p->outSize_Defined = False;
- if (outDataSize)
- {
- p->outSize_Defined = True;
- p->outSize = *outDataSize;
- }
- p->finishMode = finishMode;
-
- p->outProcessed = 0;
- p->inProcessed = 0;
-
- p->inPos = 0;
- p->inLim = 0;
-
- return Lzma2Dec_Prepare_ST(p);
-}
-
-
-SRes Lzma2DecMt_Read(CLzma2DecMtHandle pp,
- Byte *data, size_t *outSize,
- UInt64 *inStreamProcessed)
-{
- CLzma2DecMt *p = (CLzma2DecMt *)pp;
- ELzmaFinishMode finishMode;
- SRes readRes;
- size_t size = *outSize;
-
- *outSize = 0;
- *inStreamProcessed = 0;
-
- finishMode = LZMA_FINISH_ANY;
- if (p->outSize_Defined)
- {
- const UInt64 rem = p->outSize - p->outProcessed;
- if (size >= rem)
- {
- size = (size_t)rem;
- if (p->finishMode)
- finishMode = LZMA_FINISH_END;
- }
- }
-
- readRes = SZ_OK;
-
- for (;;)
- {
- SizeT inCur;
- SizeT outCur;
- ELzmaStatus status;
- SRes res;
-
- if (p->inPos == p->inLim && readRes == SZ_OK)
- {
- p->inPos = 0;
- p->inLim = p->props.inBufSize_ST;
- readRes = ISeqInStream_Read(p->inStream, p->inBuf, &p->inLim);
- }
-
- inCur = p->inLim - p->inPos;
- outCur = size;
-
- res = Lzma2Dec_DecodeToBuf(&p->dec, data, &outCur,
- p->inBuf + p->inPos, &inCur, finishMode, &status);
-
- p->inPos += inCur;
- p->inProcessed += inCur;
- *inStreamProcessed += inCur;
- p->outProcessed += outCur;
- *outSize += outCur;
- size -= outCur;
- data += outCur;
-
- if (res != 0)
- return res;
-
- /*
- if (status == LZMA_STATUS_FINISHED_WITH_MARK)
- return readRes;
-
- if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT)
- {
- if (p->finishMode && p->outSize_Defined && p->outProcessed >= p->outSize)
- return SZ_ERROR_DATA;
- return readRes;
- }
- */
-
- if (inCur == 0 && outCur == 0)
- return readRes;
- }
-}
+/* Lzma2DecMt.c -- LZMA2 Decoder Multi-thread
+2023-04-13 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+// #define SHOW_DEBUG_INFO
+// #define Z7_ST
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#endif
+
+#include "Alloc.h"
+
+#include "Lzma2Dec.h"
+#include "Lzma2DecMt.h"
+
+#ifndef Z7_ST
+#include "MtDec.h"
+
+#define LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT (1 << 28)
+#endif
+
+
+#ifndef Z7_ST
+#ifdef SHOW_DEBUG_INFO
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+#define PRF_STR(s) PRF(printf("\n" s "\n");)
+#define PRF_STR_INT_2(s, d1, d2) PRF(printf("\n" s " %d %d\n", (unsigned)d1, (unsigned)d2);)
+#endif
+
+
+void Lzma2DecMtProps_Init(CLzma2DecMtProps *p)
+{
+ p->inBufSize_ST = 1 << 20;
+ p->outStep_ST = 1 << 20;
+
+ #ifndef Z7_ST
+ p->numThreads = 1;
+ p->inBufSize_MT = 1 << 18;
+ p->outBlockMax = LZMA2DECMT_OUT_BLOCK_MAX_DEFAULT;
+ p->inBlockMax = p->outBlockMax + p->outBlockMax / 16;
+ #endif
+}
+
+
+
+#ifndef Z7_ST
+
+/* ---------- CLzma2DecMtThread ---------- */
+
+typedef struct
+{
+ CLzma2Dec dec;
+ Byte dec_created;
+ Byte needInit;
+
+ Byte *outBuf;
+ size_t outBufSize;
+
+ EMtDecParseState state;
+ ELzma2ParseStatus parseStatus;
+
+ size_t inPreSize;
+ size_t outPreSize;
+
+ size_t inCodeSize;
+ size_t outCodeSize;
+ SRes codeRes;
+
+ CAlignOffsetAlloc alloc;
+
+ Byte mtPad[1 << 7];
+} CLzma2DecMtThread;
+
+#endif
+
+
+/* ---------- CLzma2DecMt ---------- */
+
+struct CLzma2DecMt
+{
+ // ISzAllocPtr alloc;
+ ISzAllocPtr allocMid;
+
+ CAlignOffsetAlloc alignOffsetAlloc;
+ CLzma2DecMtProps props;
+ Byte prop;
+
+ ISeqInStreamPtr inStream;
+ ISeqOutStreamPtr outStream;
+ ICompressProgressPtr progress;
+
+ BoolInt finishMode;
+ BoolInt outSize_Defined;
+ UInt64 outSize;
+
+ UInt64 outProcessed;
+ UInt64 inProcessed;
+ BoolInt readWasFinished;
+ SRes readRes;
+
+ Byte *inBuf;
+ size_t inBufSize;
+ Byte dec_created;
+ CLzma2Dec dec;
+
+ size_t inPos;
+ size_t inLim;
+
+ #ifndef Z7_ST
+ UInt64 outProcessed_Parse;
+ BoolInt mtc_WasConstructed;
+ CMtDec mtc;
+ CLzma2DecMtThread coders[MTDEC_THREADS_MAX];
+ #endif
+};
+
+
+
+CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid)
+{
+ CLzma2DecMt *p = (CLzma2DecMt *)ISzAlloc_Alloc(alloc, sizeof(CLzma2DecMt));
+ if (!p)
+ return NULL;
+
+ // p->alloc = alloc;
+ p->allocMid = allocMid;
+
+ AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc);
+ p->alignOffsetAlloc.numAlignBits = 7;
+ p->alignOffsetAlloc.offset = 0;
+ p->alignOffsetAlloc.baseAlloc = alloc;
+
+ p->inBuf = NULL;
+ p->inBufSize = 0;
+ p->dec_created = False;
+
+ // Lzma2DecMtProps_Init(&p->props);
+
+ #ifndef Z7_ST
+ p->mtc_WasConstructed = False;
+ {
+ unsigned i;
+ for (i = 0; i < MTDEC_THREADS_MAX; i++)
+ {
+ CLzma2DecMtThread *t = &p->coders[i];
+ t->dec_created = False;
+ t->outBuf = NULL;
+ t->outBufSize = 0;
+ }
+ }
+ #endif
+
+ return (CLzma2DecMtHandle)(void *)p;
+}
+
+
+#ifndef Z7_ST
+
+static void Lzma2DecMt_FreeOutBufs(CLzma2DecMt *p)
+{
+ unsigned i;
+ for (i = 0; i < MTDEC_THREADS_MAX; i++)
+ {
+ CLzma2DecMtThread *t = &p->coders[i];
+ if (t->outBuf)
+ {
+ ISzAlloc_Free(p->allocMid, t->outBuf);
+ t->outBuf = NULL;
+ t->outBufSize = 0;
+ }
+ }
+}
+
+#endif
+
+
+static void Lzma2DecMt_FreeSt(CLzma2DecMt *p)
+{
+ if (p->dec_created)
+ {
+ Lzma2Dec_Free(&p->dec, &p->alignOffsetAlloc.vt);
+ p->dec_created = False;
+ }
+ if (p->inBuf)
+ {
+ ISzAlloc_Free(p->allocMid, p->inBuf);
+ p->inBuf = NULL;
+ }
+ p->inBufSize = 0;
+}
+
+
+// #define GET_CLzma2DecMt_p CLzma2DecMt *p = (CLzma2DecMt *)(void *)pp;
+
+void Lzma2DecMt_Destroy(CLzma2DecMtHandle p)
+{
+ // GET_CLzma2DecMt_p
+
+ Lzma2DecMt_FreeSt(p);
+
+ #ifndef Z7_ST
+
+ if (p->mtc_WasConstructed)
+ {
+ MtDec_Destruct(&p->mtc);
+ p->mtc_WasConstructed = False;
+ }
+ {
+ unsigned i;
+ for (i = 0; i < MTDEC_THREADS_MAX; i++)
+ {
+ CLzma2DecMtThread *t = &p->coders[i];
+ if (t->dec_created)
+ {
+ // we don't need to free dict here
+ Lzma2Dec_FreeProbs(&t->dec, &t->alloc.vt); // p->alloc !!!
+ t->dec_created = False;
+ }
+ }
+ }
+ Lzma2DecMt_FreeOutBufs(p);
+
+ #endif
+
+ ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, p);
+}
+
+
+
+#ifndef Z7_ST
+
+static void Lzma2DecMt_MtCallback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc)
+{
+ CLzma2DecMt *me = (CLzma2DecMt *)obj;
+ CLzma2DecMtThread *t = &me->coders[coderIndex];
+
+ PRF_STR_INT_2("Parse", coderIndex, cc->srcSize)
+
+ cc->state = MTDEC_PARSE_CONTINUE;
+
+ if (cc->startCall)
+ {
+ if (!t->dec_created)
+ {
+ Lzma2Dec_CONSTRUCT(&t->dec)
+ t->dec_created = True;
+ AlignOffsetAlloc_CreateVTable(&t->alloc);
+ {
+ /* (1 << 12) is expected size of one way in data cache.
+ We optimize alignment for cache line size of 128 bytes and smaller */
+ const unsigned kNumAlignBits = 12;
+ const unsigned kNumCacheLineBits = 7; /* <= kNumAlignBits */
+ t->alloc.numAlignBits = kNumAlignBits;
+ t->alloc.offset = ((UInt32)coderIndex * (((unsigned)1 << 11) + (1 << 8) + (1 << 6))) & (((unsigned)1 << kNumAlignBits) - ((unsigned)1 << kNumCacheLineBits));
+ t->alloc.baseAlloc = me->alignOffsetAlloc.baseAlloc;
+ }
+ }
+ Lzma2Dec_Init(&t->dec);
+
+ t->inPreSize = 0;
+ t->outPreSize = 0;
+ // t->blockWasFinished = False;
+ // t->finishedWithMark = False;
+ t->parseStatus = (ELzma2ParseStatus)LZMA_STATUS_NOT_SPECIFIED;
+ t->state = MTDEC_PARSE_CONTINUE;
+
+ t->inCodeSize = 0;
+ t->outCodeSize = 0;
+ t->codeRes = SZ_OK;
+
+ // (cc->srcSize == 0) is allowed
+ }
+
+ {
+ ELzma2ParseStatus status;
+ BoolInt overflow;
+ UInt32 unpackRem = 0;
+
+ int checkFinishBlock = True;
+ size_t limit = me->props.outBlockMax;
+ if (me->outSize_Defined)
+ {
+ UInt64 rem = me->outSize - me->outProcessed_Parse;
+ if (limit >= rem)
+ {
+ limit = (size_t)rem;
+ if (!me->finishMode)
+ checkFinishBlock = False;
+ }
+ }
+
+ // checkFinishBlock = False, if we want to decode partial data
+ // that must be finished at position <= outBlockMax.
+
+ {
+ const size_t srcOrig = cc->srcSize;
+ SizeT srcSize_Point = 0;
+ SizeT dicPos_Point = 0;
+
+ cc->srcSize = 0;
+ overflow = False;
+
+ for (;;)
+ {
+ SizeT srcCur = (SizeT)(srcOrig - cc->srcSize);
+
+ status = Lzma2Dec_Parse(&t->dec,
+ (SizeT)limit - t->dec.decoder.dicPos,
+ cc->src + cc->srcSize, &srcCur,
+ checkFinishBlock);
+
+ cc->srcSize += srcCur;
+
+ if (status == LZMA2_PARSE_STATUS_NEW_CHUNK)
+ {
+ if (t->dec.unpackSize > me->props.outBlockMax - t->dec.decoder.dicPos)
+ {
+ overflow = True;
+ break;
+ }
+ continue;
+ }
+
+ if (status == LZMA2_PARSE_STATUS_NEW_BLOCK)
+ {
+ if (t->dec.decoder.dicPos == 0)
+ continue;
+ // we decode small blocks in one thread
+ if (t->dec.decoder.dicPos >= (1 << 14))
+ break;
+ dicPos_Point = t->dec.decoder.dicPos;
+ srcSize_Point = (SizeT)cc->srcSize;
+ continue;
+ }
+
+ if ((int)status == LZMA_STATUS_NOT_FINISHED && checkFinishBlock
+ // && limit == t->dec.decoder.dicPos
+ // && limit == me->props.outBlockMax
+ )
+ {
+ overflow = True;
+ break;
+ }
+
+ unpackRem = Lzma2Dec_GetUnpackExtra(&t->dec);
+ break;
+ }
+
+ if (dicPos_Point != 0
+ && (int)status != LZMA2_PARSE_STATUS_NEW_BLOCK
+ && (int)status != LZMA_STATUS_FINISHED_WITH_MARK
+ && (int)status != LZMA_STATUS_NOT_SPECIFIED)
+ {
+ // we revert to latest newBlock state
+ status = LZMA2_PARSE_STATUS_NEW_BLOCK;
+ unpackRem = 0;
+ t->dec.decoder.dicPos = dicPos_Point;
+ cc->srcSize = srcSize_Point;
+ overflow = False;
+ }
+ }
+
+ t->inPreSize += cc->srcSize;
+ t->parseStatus = status;
+
+ if (overflow)
+ cc->state = MTDEC_PARSE_OVERFLOW;
+ else
+ {
+ size_t dicPos = t->dec.decoder.dicPos;
+
+ if ((int)status != LZMA_STATUS_NEEDS_MORE_INPUT)
+ {
+ if (status == LZMA2_PARSE_STATUS_NEW_BLOCK)
+ {
+ cc->state = MTDEC_PARSE_NEW;
+ cc->srcSize--; // we don't need control byte of next block
+ t->inPreSize--;
+ }
+ else
+ {
+ cc->state = MTDEC_PARSE_END;
+ if ((int)status != LZMA_STATUS_FINISHED_WITH_MARK)
+ {
+ // (status == LZMA_STATUS_NOT_SPECIFIED)
+ // (status == LZMA_STATUS_NOT_FINISHED)
+ if (unpackRem != 0)
+ {
+ /* we also reserve space for max possible number of output bytes of current LZMA chunk */
+ size_t rem = limit - dicPos;
+ if (rem > unpackRem)
+ rem = unpackRem;
+ dicPos += rem;
+ }
+ }
+ }
+
+ me->outProcessed_Parse += dicPos;
+ }
+
+ cc->outPos = dicPos;
+ t->outPreSize = (size_t)dicPos;
+ }
+
+ t->state = cc->state;
+ return;
+ }
+}
+
+
+static SRes Lzma2DecMt_MtCallback_PreCode(void *pp, unsigned coderIndex)
+{
+ CLzma2DecMt *me = (CLzma2DecMt *)pp;
+ CLzma2DecMtThread *t = &me->coders[coderIndex];
+ Byte *dest = t->outBuf;
+
+ if (t->inPreSize == 0)
+ {
+ t->codeRes = SZ_ERROR_DATA;
+ return t->codeRes;
+ }
+
+ if (!dest || t->outBufSize < t->outPreSize)
+ {
+ if (dest)
+ {
+ ISzAlloc_Free(me->allocMid, dest);
+ t->outBuf = NULL;
+ t->outBufSize = 0;
+ }
+
+ dest = (Byte *)ISzAlloc_Alloc(me->allocMid, t->outPreSize
+ // + (1 << 28)
+ );
+ // Sleep(200);
+ if (!dest)
+ return SZ_ERROR_MEM;
+ t->outBuf = dest;
+ t->outBufSize = t->outPreSize;
+ }
+
+ t->dec.decoder.dic = dest;
+ t->dec.decoder.dicBufSize = (SizeT)t->outPreSize;
+
+ t->needInit = True;
+
+ return Lzma2Dec_AllocateProbs(&t->dec, me->prop, &t->alloc.vt); // alloc.vt
+}
+
+
+static SRes Lzma2DecMt_MtCallback_Code(void *pp, unsigned coderIndex,
+ const Byte *src, size_t srcSize, int srcFinished,
+ // int finished, int blockFinished,
+ UInt64 *inCodePos, UInt64 *outCodePos, int *stop)
+{
+ CLzma2DecMt *me = (CLzma2DecMt *)pp;
+ CLzma2DecMtThread *t = &me->coders[coderIndex];
+
+ UNUSED_VAR(srcFinished)
+
+ PRF_STR_INT_2("Code", coderIndex, srcSize)
+
+ *inCodePos = t->inCodeSize;
+ *outCodePos = 0;
+ *stop = True;
+
+ if (t->needInit)
+ {
+ Lzma2Dec_Init(&t->dec);
+ t->needInit = False;
+ }
+
+ {
+ ELzmaStatus status;
+ SizeT srcProcessed = (SizeT)srcSize;
+ BoolInt blockWasFinished =
+ ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK
+ || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK);
+
+ SRes res = Lzma2Dec_DecodeToDic(&t->dec,
+ (SizeT)t->outPreSize,
+ src, &srcProcessed,
+ blockWasFinished ? LZMA_FINISH_END : LZMA_FINISH_ANY,
+ &status);
+
+ t->codeRes = res;
+
+ t->inCodeSize += srcProcessed;
+ *inCodePos = t->inCodeSize;
+ t->outCodeSize = t->dec.decoder.dicPos;
+ *outCodePos = t->dec.decoder.dicPos;
+
+ if (res != SZ_OK)
+ return res;
+
+ if (srcProcessed == srcSize)
+ *stop = False;
+
+ if (blockWasFinished)
+ {
+ if (srcSize != srcProcessed)
+ return SZ_ERROR_FAIL;
+
+ if (t->inPreSize == t->inCodeSize)
+ {
+ if (t->outPreSize != t->outCodeSize)
+ return SZ_ERROR_FAIL;
+ *stop = True;
+ }
+ }
+ else
+ {
+ if (t->outPreSize == t->outCodeSize)
+ *stop = True;
+ }
+
+ return SZ_OK;
+ }
+}
+
+
+#define LZMA2DECMT_STREAM_WRITE_STEP (1 << 24)
+
+static SRes Lzma2DecMt_MtCallback_Write(void *pp, unsigned coderIndex,
+ BoolInt needWriteToStream,
+ const Byte *src, size_t srcSize, BoolInt isCross,
+ BoolInt *needContinue, BoolInt *canRecode)
+{
+ CLzma2DecMt *me = (CLzma2DecMt *)pp;
+ const CLzma2DecMtThread *t = &me->coders[coderIndex];
+ size_t size = t->outCodeSize;
+ const Byte *data = t->outBuf;
+ BoolInt needContinue2 = True;
+
+ UNUSED_VAR(src)
+ UNUSED_VAR(srcSize)
+ UNUSED_VAR(isCross)
+
+ PRF_STR_INT_2("Write", coderIndex, srcSize)
+
+ *needContinue = False;
+ *canRecode = True;
+
+ if (
+ // t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK
+ t->state == MTDEC_PARSE_OVERFLOW
+ || t->state == MTDEC_PARSE_END)
+ needContinue2 = False;
+
+
+ if (!needWriteToStream)
+ return SZ_OK;
+
+ me->mtc.inProcessed += t->inCodeSize;
+
+ if (t->codeRes == SZ_OK)
+ if ((int)t->parseStatus == LZMA_STATUS_FINISHED_WITH_MARK
+ || t->parseStatus == LZMA2_PARSE_STATUS_NEW_BLOCK)
+ if (t->outPreSize != t->outCodeSize
+ || t->inPreSize != t->inCodeSize)
+ return SZ_ERROR_FAIL;
+
+ *canRecode = False;
+
+ if (me->outStream)
+ {
+ for (;;)
+ {
+ size_t cur = size;
+ size_t written;
+ if (cur > LZMA2DECMT_STREAM_WRITE_STEP)
+ cur = LZMA2DECMT_STREAM_WRITE_STEP;
+
+ written = ISeqOutStream_Write(me->outStream, data, cur);
+
+ me->outProcessed += written;
+ // me->mtc.writtenTotal += written;
+ if (written != cur)
+ return SZ_ERROR_WRITE;
+ data += cur;
+ size -= cur;
+ if (size == 0)
+ {
+ *needContinue = needContinue2;
+ return SZ_OK;
+ }
+ RINOK(MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0))
+ }
+ }
+
+ return SZ_ERROR_FAIL;
+ /*
+ if (size > me->outBufSize)
+ return SZ_ERROR_OUTPUT_EOF;
+ memcpy(me->outBuf, data, size);
+ me->outBufSize -= size;
+ me->outBuf += size;
+ *needContinue = needContinue2;
+ return SZ_OK;
+ */
+}
+
+#endif
+
+
+static SRes Lzma2Dec_Prepare_ST(CLzma2DecMt *p)
+{
+ if (!p->dec_created)
+ {
+ Lzma2Dec_CONSTRUCT(&p->dec)
+ p->dec_created = True;
+ }
+
+ RINOK(Lzma2Dec_Allocate(&p->dec, p->prop, &p->alignOffsetAlloc.vt))
+
+ if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST)
+ {
+ ISzAlloc_Free(p->allocMid, p->inBuf);
+ p->inBufSize = 0;
+ p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST);
+ if (!p->inBuf)
+ return SZ_ERROR_MEM;
+ p->inBufSize = p->props.inBufSize_ST;
+ }
+
+ Lzma2Dec_Init(&p->dec);
+
+ return SZ_OK;
+}
+
+
+static SRes Lzma2Dec_Decode_ST(CLzma2DecMt *p
+ #ifndef Z7_ST
+ , BoolInt tMode
+ #endif
+ )
+{
+ SizeT wrPos;
+ size_t inPos, inLim;
+ const Byte *inData;
+ UInt64 inPrev, outPrev;
+
+ CLzma2Dec *dec;
+
+ #ifndef Z7_ST
+ if (tMode)
+ {
+ Lzma2DecMt_FreeOutBufs(p);
+ tMode = MtDec_PrepareRead(&p->mtc);
+ }
+ #endif
+
+ RINOK(Lzma2Dec_Prepare_ST(p))
+
+ dec = &p->dec;
+
+ inPrev = p->inProcessed;
+ outPrev = p->outProcessed;
+
+ inPos = 0;
+ inLim = 0;
+ inData = NULL;
+ wrPos = dec->decoder.dicPos;
+
+ for (;;)
+ {
+ SizeT dicPos;
+ SizeT size;
+ ELzmaFinishMode finishMode;
+ SizeT inProcessed;
+ ELzmaStatus status;
+ SRes res;
+
+ SizeT outProcessed;
+ BoolInt outFinished;
+ BoolInt needStop;
+
+ if (inPos == inLim)
+ {
+ #ifndef Z7_ST
+ if (tMode)
+ {
+ inData = MtDec_Read(&p->mtc, &inLim);
+ inPos = 0;
+ if (inData)
+ continue;
+ tMode = False;
+ inLim = 0;
+ }
+ #endif
+
+ if (!p->readWasFinished)
+ {
+ inPos = 0;
+ inLim = p->inBufSize;
+ inData = p->inBuf;
+ p->readRes = ISeqInStream_Read(p->inStream, (void *)(p->inBuf), &inLim);
+ // p->readProcessed += inLim;
+ // inLim -= 5; p->readWasFinished = True; // for test
+ if (inLim == 0 || p->readRes != SZ_OK)
+ p->readWasFinished = True;
+ }
+ }
+
+ dicPos = dec->decoder.dicPos;
+ {
+ SizeT next = dec->decoder.dicBufSize;
+ if (next - wrPos > p->props.outStep_ST)
+ next = wrPos + (SizeT)p->props.outStep_ST;
+ size = next - dicPos;
+ }
+
+ finishMode = LZMA_FINISH_ANY;
+ if (p->outSize_Defined)
+ {
+ const UInt64 rem = p->outSize - p->outProcessed;
+ if (size >= rem)
+ {
+ size = (SizeT)rem;
+ if (p->finishMode)
+ finishMode = LZMA_FINISH_END;
+ }
+ }
+
+ inProcessed = (SizeT)(inLim - inPos);
+
+ res = Lzma2Dec_DecodeToDic(dec, dicPos + size, inData + inPos, &inProcessed, finishMode, &status);
+
+ inPos += inProcessed;
+ p->inProcessed += inProcessed;
+ outProcessed = dec->decoder.dicPos - dicPos;
+ p->outProcessed += outProcessed;
+
+ outFinished = (p->outSize_Defined && p->outSize <= p->outProcessed);
+
+ needStop = (res != SZ_OK
+ || (inProcessed == 0 && outProcessed == 0)
+ || status == LZMA_STATUS_FINISHED_WITH_MARK
+ || (!p->finishMode && outFinished));
+
+ if (needStop || outProcessed >= size)
+ {
+ SRes res2;
+ {
+ size_t writeSize = dec->decoder.dicPos - wrPos;
+ size_t written = ISeqOutStream_Write(p->outStream, dec->decoder.dic + wrPos, writeSize);
+ res2 = (written == writeSize) ? SZ_OK : SZ_ERROR_WRITE;
+ }
+
+ if (dec->decoder.dicPos == dec->decoder.dicBufSize)
+ dec->decoder.dicPos = 0;
+ wrPos = dec->decoder.dicPos;
+
+ RINOK(res2)
+
+ if (needStop)
+ {
+ if (res != SZ_OK)
+ return res;
+
+ if (status == LZMA_STATUS_FINISHED_WITH_MARK)
+ {
+ if (p->finishMode)
+ {
+ if (p->outSize_Defined && p->outSize != p->outProcessed)
+ return SZ_ERROR_DATA;
+ }
+ return SZ_OK;
+ }
+
+ if (!p->finishMode && outFinished)
+ return SZ_OK;
+
+ if (status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ return SZ_ERROR_INPUT_EOF;
+
+ return SZ_ERROR_DATA;
+ }
+ }
+
+ if (p->progress)
+ {
+ UInt64 inDelta = p->inProcessed - inPrev;
+ UInt64 outDelta = p->outProcessed - outPrev;
+ if (inDelta >= (1 << 22) || outDelta >= (1 << 22))
+ {
+ RINOK(ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed))
+ inPrev = p->inProcessed;
+ outPrev = p->outProcessed;
+ }
+ }
+ }
+}
+
+
+
+SRes Lzma2DecMt_Decode(CLzma2DecMtHandle p,
+ Byte prop,
+ const CLzma2DecMtProps *props,
+ ISeqOutStreamPtr outStream, const UInt64 *outDataSize, int finishMode,
+ // Byte *outBuf, size_t *outBufSize,
+ ISeqInStreamPtr inStream,
+ // const Byte *inData, size_t inDataSize,
+ UInt64 *inProcessed,
+ // UInt64 *outProcessed,
+ int *isMT,
+ ICompressProgressPtr progress)
+{
+ // GET_CLzma2DecMt_p
+ #ifndef Z7_ST
+ BoolInt tMode;
+ #endif
+
+ *inProcessed = 0;
+
+ if (prop > 40)
+ return SZ_ERROR_UNSUPPORTED;
+
+ p->prop = prop;
+ p->props = *props;
+
+ p->inStream = inStream;
+ p->outStream = outStream;
+ p->progress = progress;
+
+ p->outSize = 0;
+ p->outSize_Defined = False;
+ if (outDataSize)
+ {
+ p->outSize_Defined = True;
+ p->outSize = *outDataSize;
+ }
+ p->finishMode = finishMode;
+
+ p->outProcessed = 0;
+ p->inProcessed = 0;
+
+ p->readWasFinished = False;
+ p->readRes = SZ_OK;
+
+ *isMT = False;
+
+
+ #ifndef Z7_ST
+
+ tMode = False;
+
+ // p->mtc.parseRes = SZ_OK;
+
+ // p->mtc.numFilledThreads = 0;
+ // p->mtc.crossStart = 0;
+ // p->mtc.crossEnd = 0;
+ // p->mtc.allocError_for_Read_BlockIndex = 0;
+ // p->mtc.isAllocError = False;
+
+ if (p->props.numThreads > 1)
+ {
+ IMtDecCallback2 vt;
+
+ Lzma2DecMt_FreeSt(p);
+
+ p->outProcessed_Parse = 0;
+
+ if (!p->mtc_WasConstructed)
+ {
+ p->mtc_WasConstructed = True;
+ MtDec_Construct(&p->mtc);
+ }
+
+ p->mtc.progress = progress;
+ p->mtc.inStream = inStream;
+
+ // p->outBuf = NULL;
+ // p->outBufSize = 0;
+ /*
+ if (!outStream)
+ {
+ // p->outBuf = outBuf;
+ // p->outBufSize = *outBufSize;
+ // *outBufSize = 0;
+ return SZ_ERROR_PARAM;
+ }
+ */
+
+ // p->mtc.inBlockMax = p->props.inBlockMax;
+ p->mtc.alloc = &p->alignOffsetAlloc.vt;
+ // p->alignOffsetAlloc.baseAlloc;
+ // p->mtc.inData = inData;
+ // p->mtc.inDataSize = inDataSize;
+ p->mtc.mtCallback = &vt;
+ p->mtc.mtCallbackObject = p;
+
+ p->mtc.inBufSize = p->props.inBufSize_MT;
+
+ p->mtc.numThreadsMax = p->props.numThreads;
+
+ *isMT = True;
+
+ vt.Parse = Lzma2DecMt_MtCallback_Parse;
+ vt.PreCode = Lzma2DecMt_MtCallback_PreCode;
+ vt.Code = Lzma2DecMt_MtCallback_Code;
+ vt.Write = Lzma2DecMt_MtCallback_Write;
+
+ {
+ BoolInt needContinue = False;
+
+ SRes res = MtDec_Code(&p->mtc);
+
+ /*
+ if (!outStream)
+ *outBufSize = p->outBuf - outBuf;
+ */
+
+ *inProcessed = p->mtc.inProcessed;
+
+ needContinue = False;
+
+ if (res == SZ_OK)
+ {
+ if (p->mtc.mtProgress.res != SZ_OK)
+ res = p->mtc.mtProgress.res;
+ else
+ needContinue = p->mtc.needContinue;
+ }
+
+ if (!needContinue)
+ {
+ if (res == SZ_OK)
+ return p->mtc.readRes;
+ return res;
+ }
+
+ tMode = True;
+ p->readRes = p->mtc.readRes;
+ p->readWasFinished = p->mtc.readWasFinished;
+ p->inProcessed = p->mtc.inProcessed;
+
+ PRF_STR("----- decoding ST -----")
+ }
+ }
+
+ #endif
+
+
+ *isMT = False;
+
+ {
+ SRes res = Lzma2Dec_Decode_ST(p
+ #ifndef Z7_ST
+ , tMode
+ #endif
+ );
+
+ *inProcessed = p->inProcessed;
+
+ // res = SZ_OK; // for test
+ if (res == SZ_ERROR_INPUT_EOF)
+ {
+ if (p->readRes != SZ_OK)
+ res = p->readRes;
+ }
+ else if (res == SZ_OK && p->readRes != SZ_OK)
+ res = p->readRes;
+
+ /*
+ #ifndef Z7_ST
+ if (res == SZ_OK && tMode && p->mtc.parseRes != SZ_OK)
+ res = p->mtc.parseRes;
+ #endif
+ */
+
+ return res;
+ }
+}
+
+
+/* ---------- Read from CLzma2DecMtHandle Interface ---------- */
+
+SRes Lzma2DecMt_Init(CLzma2DecMtHandle p,
+ Byte prop,
+ const CLzma2DecMtProps *props,
+ const UInt64 *outDataSize, int finishMode,
+ ISeqInStreamPtr inStream)
+{
+ // GET_CLzma2DecMt_p
+
+ if (prop > 40)
+ return SZ_ERROR_UNSUPPORTED;
+
+ p->prop = prop;
+ p->props = *props;
+
+ p->inStream = inStream;
+
+ p->outSize = 0;
+ p->outSize_Defined = False;
+ if (outDataSize)
+ {
+ p->outSize_Defined = True;
+ p->outSize = *outDataSize;
+ }
+ p->finishMode = finishMode;
+
+ p->outProcessed = 0;
+ p->inProcessed = 0;
+
+ p->inPos = 0;
+ p->inLim = 0;
+
+ return Lzma2Dec_Prepare_ST(p);
+}
+
+
+SRes Lzma2DecMt_Read(CLzma2DecMtHandle p,
+ Byte *data, size_t *outSize,
+ UInt64 *inStreamProcessed)
+{
+ // GET_CLzma2DecMt_p
+ ELzmaFinishMode finishMode;
+ SRes readRes;
+ size_t size = *outSize;
+
+ *outSize = 0;
+ *inStreamProcessed = 0;
+
+ finishMode = LZMA_FINISH_ANY;
+ if (p->outSize_Defined)
+ {
+ const UInt64 rem = p->outSize - p->outProcessed;
+ if (size >= rem)
+ {
+ size = (size_t)rem;
+ if (p->finishMode)
+ finishMode = LZMA_FINISH_END;
+ }
+ }
+
+ readRes = SZ_OK;
+
+ for (;;)
+ {
+ SizeT inCur;
+ SizeT outCur;
+ ELzmaStatus status;
+ SRes res;
+
+ if (p->inPos == p->inLim && readRes == SZ_OK)
+ {
+ p->inPos = 0;
+ p->inLim = p->props.inBufSize_ST;
+ readRes = ISeqInStream_Read(p->inStream, p->inBuf, &p->inLim);
+ }
+
+ inCur = (SizeT)(p->inLim - p->inPos);
+ outCur = (SizeT)size;
+
+ res = Lzma2Dec_DecodeToBuf(&p->dec, data, &outCur,
+ p->inBuf + p->inPos, &inCur, finishMode, &status);
+
+ p->inPos += inCur;
+ p->inProcessed += inCur;
+ *inStreamProcessed += inCur;
+ p->outProcessed += outCur;
+ *outSize += outCur;
+ size -= outCur;
+ data += outCur;
+
+ if (res != 0)
+ return res;
+
+ /*
+ if (status == LZMA_STATUS_FINISHED_WITH_MARK)
+ return readRes;
+
+ if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT)
+ {
+ if (p->finishMode && p->outSize_Defined && p->outProcessed >= p->outSize)
+ return SZ_ERROR_DATA;
+ return readRes;
+ }
+ */
+
+ if (inCur == 0 && outCur == 0)
+ return readRes;
+ }
+}
+
+#undef PRF
+#undef PRF_STR
+#undef PRF_STR_INT_2
diff --git a/C/Lzma2DecMt.h b/C/Lzma2DecMt.h
index 96f89a3..93a5cd5 100644
--- a/C/Lzma2DecMt.h
+++ b/C/Lzma2DecMt.h
@@ -1,79 +1,81 @@
-/* Lzma2DecMt.h -- LZMA2 Decoder Multi-thread
-2018-02-17 : Igor Pavlov : Public domain */
-
-#ifndef __LZMA2_DEC_MT_H
-#define __LZMA2_DEC_MT_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-typedef struct
-{
- size_t inBufSize_ST;
- size_t outStep_ST;
-
- #ifndef _7ZIP_ST
- unsigned numThreads;
- size_t inBufSize_MT;
- size_t outBlockMax;
- size_t inBlockMax;
- #endif
-} CLzma2DecMtProps;
-
-/* init to single-thread mode */
-void Lzma2DecMtProps_Init(CLzma2DecMtProps *p);
-
-
-/* ---------- CLzma2DecMtHandle Interface ---------- */
-
-/* Lzma2DecMt_ * functions can return the following exit codes:
-SRes:
- SZ_OK - OK
- SZ_ERROR_MEM - Memory allocation error
- SZ_ERROR_PARAM - Incorrect paramater in props
- SZ_ERROR_WRITE - ISeqOutStream write callback error
- // SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output
- SZ_ERROR_PROGRESS - some break from progress callback
- SZ_ERROR_THREAD - error in multithreading functions (only for Mt version)
-*/
-
-typedef void * CLzma2DecMtHandle;
-
-CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid);
-void Lzma2DecMt_Destroy(CLzma2DecMtHandle p);
-
-SRes Lzma2DecMt_Decode(CLzma2DecMtHandle p,
- Byte prop,
- const CLzma2DecMtProps *props,
- ISeqOutStream *outStream,
- const UInt64 *outDataSize, // NULL means undefined
- int finishMode, // 0 - partial unpacking is allowed, 1 - if lzma2 stream must be finished
- // Byte *outBuf, size_t *outBufSize,
- ISeqInStream *inStream,
- // const Byte *inData, size_t inDataSize,
-
- // out variables:
- UInt64 *inProcessed,
- int *isMT, /* out: (*isMT == 0), if single thread decoding was used */
-
- // UInt64 *outProcessed,
- ICompressProgress *progress);
-
-
-/* ---------- Read from CLzma2DecMtHandle Interface ---------- */
-
-SRes Lzma2DecMt_Init(CLzma2DecMtHandle pp,
- Byte prop,
- const CLzma2DecMtProps *props,
- const UInt64 *outDataSize, int finishMode,
- ISeqInStream *inStream);
-
-SRes Lzma2DecMt_Read(CLzma2DecMtHandle pp,
- Byte *data, size_t *outSize,
- UInt64 *inStreamProcessed);
-
-
-EXTERN_C_END
-
-#endif
+/* Lzma2DecMt.h -- LZMA2 Decoder Multi-thread
+2023-04-13 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_LZMA2_DEC_MT_H
+#define ZIP7_INC_LZMA2_DEC_MT_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+typedef struct
+{
+ size_t inBufSize_ST;
+ size_t outStep_ST;
+
+ #ifndef Z7_ST
+ unsigned numThreads;
+ size_t inBufSize_MT;
+ size_t outBlockMax;
+ size_t inBlockMax;
+ #endif
+} CLzma2DecMtProps;
+
+/* init to single-thread mode */
+void Lzma2DecMtProps_Init(CLzma2DecMtProps *p);
+
+
+/* ---------- CLzma2DecMtHandle Interface ---------- */
+
+/* Lzma2DecMt_ * functions can return the following exit codes:
+SRes:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater in props
+ SZ_ERROR_WRITE - ISeqOutStream write callback error
+ // SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output
+ SZ_ERROR_PROGRESS - some break from progress callback
+ SZ_ERROR_THREAD - error in multithreading functions (only for Mt version)
+*/
+
+typedef struct CLzma2DecMt CLzma2DecMt;
+typedef CLzma2DecMt * CLzma2DecMtHandle;
+// Z7_DECLARE_HANDLE(CLzma2DecMtHandle)
+
+CLzma2DecMtHandle Lzma2DecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid);
+void Lzma2DecMt_Destroy(CLzma2DecMtHandle p);
+
+SRes Lzma2DecMt_Decode(CLzma2DecMtHandle p,
+ Byte prop,
+ const CLzma2DecMtProps *props,
+ ISeqOutStreamPtr outStream,
+ const UInt64 *outDataSize, // NULL means undefined
+ int finishMode, // 0 - partial unpacking is allowed, 1 - if lzma2 stream must be finished
+ // Byte *outBuf, size_t *outBufSize,
+ ISeqInStreamPtr inStream,
+ // const Byte *inData, size_t inDataSize,
+
+ // out variables:
+ UInt64 *inProcessed,
+ int *isMT, /* out: (*isMT == 0), if single thread decoding was used */
+
+ // UInt64 *outProcessed,
+ ICompressProgressPtr progress);
+
+
+/* ---------- Read from CLzma2DecMtHandle Interface ---------- */
+
+SRes Lzma2DecMt_Init(CLzma2DecMtHandle pp,
+ Byte prop,
+ const CLzma2DecMtProps *props,
+ const UInt64 *outDataSize, int finishMode,
+ ISeqInStreamPtr inStream);
+
+SRes Lzma2DecMt_Read(CLzma2DecMtHandle pp,
+ Byte *data, size_t *outSize,
+ UInt64 *inStreamProcessed);
+
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Lzma2Enc.c b/C/Lzma2Enc.c
index d541477..703e146 100644
--- a/C/Lzma2Enc.c
+++ b/C/Lzma2Enc.c
@@ -1,803 +1,805 @@
-/* Lzma2Enc.c -- LZMA2 Encoder
-2018-07-04 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include <string.h>
-
-/* #define _7ZIP_ST */
-
-#include "Lzma2Enc.h"
-
-#ifndef _7ZIP_ST
-#include "MtCoder.h"
-#else
-#define MTCODER__THREADS_MAX 1
-#endif
-
-#define LZMA2_CONTROL_LZMA (1 << 7)
-#define LZMA2_CONTROL_COPY_NO_RESET 2
-#define LZMA2_CONTROL_COPY_RESET_DIC 1
-#define LZMA2_CONTROL_EOF 0
-
-#define LZMA2_LCLP_MAX 4
-
-#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11))
-
-#define LZMA2_PACK_SIZE_MAX (1 << 16)
-#define LZMA2_COPY_CHUNK_SIZE LZMA2_PACK_SIZE_MAX
-#define LZMA2_UNPACK_SIZE_MAX (1 << 21)
-#define LZMA2_KEEP_WINDOW_SIZE LZMA2_UNPACK_SIZE_MAX
-
-#define LZMA2_CHUNK_SIZE_COMPRESSED_MAX ((1 << 16) + 16)
-
-
-#define PRF(x) /* x */
-
-
-/* ---------- CLimitedSeqInStream ---------- */
-
-typedef struct
-{
- ISeqInStream vt;
- ISeqInStream *realStream;
- UInt64 limit;
- UInt64 processed;
- int finished;
-} CLimitedSeqInStream;
-
-static void LimitedSeqInStream_Init(CLimitedSeqInStream *p)
-{
- p->limit = (UInt64)(Int64)-1;
- p->processed = 0;
- p->finished = 0;
-}
-
-static SRes LimitedSeqInStream_Read(const ISeqInStream *pp, void *data, size_t *size)
-{
- CLimitedSeqInStream *p = CONTAINER_FROM_VTBL(pp, CLimitedSeqInStream, vt);
- size_t size2 = *size;
- SRes res = SZ_OK;
-
- if (p->limit != (UInt64)(Int64)-1)
- {
- UInt64 rem = p->limit - p->processed;
- if (size2 > rem)
- size2 = (size_t)rem;
- }
- if (size2 != 0)
- {
- res = ISeqInStream_Read(p->realStream, data, &size2);
- p->finished = (size2 == 0 ? 1 : 0);
- p->processed += size2;
- }
- *size = size2;
- return res;
-}
-
-
-/* ---------- CLzma2EncInt ---------- */
-
-typedef struct
-{
- CLzmaEncHandle enc;
- Byte propsAreSet;
- Byte propsByte;
- Byte needInitState;
- Byte needInitProp;
- UInt64 srcPos;
-} CLzma2EncInt;
-
-
-static SRes Lzma2EncInt_InitStream(CLzma2EncInt *p, const CLzma2EncProps *props)
-{
- if (!p->propsAreSet)
- {
- SizeT propsSize = LZMA_PROPS_SIZE;
- Byte propsEncoded[LZMA_PROPS_SIZE];
- RINOK(LzmaEnc_SetProps(p->enc, &props->lzmaProps));
- RINOK(LzmaEnc_WriteProperties(p->enc, propsEncoded, &propsSize));
- p->propsByte = propsEncoded[0];
- p->propsAreSet = True;
- }
- return SZ_OK;
-}
-
-static void Lzma2EncInt_InitBlock(CLzma2EncInt *p)
-{
- p->srcPos = 0;
- p->needInitState = True;
- p->needInitProp = True;
-}
-
-
-SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp, ISeqInStream *inStream, UInt32 keepWindowSize,
- ISzAllocPtr alloc, ISzAllocPtr allocBig);
-SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
- UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig);
-SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit,
- Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize);
-const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp);
-void LzmaEnc_Finish(CLzmaEncHandle pp);
-void LzmaEnc_SaveState(CLzmaEncHandle pp);
-void LzmaEnc_RestoreState(CLzmaEncHandle pp);
-
-/*
-UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp);
-*/
-
-static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf,
- size_t *packSizeRes, ISeqOutStream *outStream)
-{
- size_t packSizeLimit = *packSizeRes;
- size_t packSize = packSizeLimit;
- UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX;
- unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0);
- BoolInt useCopyBlock;
- SRes res;
-
- *packSizeRes = 0;
- if (packSize < lzHeaderSize)
- return SZ_ERROR_OUTPUT_EOF;
- packSize -= lzHeaderSize;
-
- LzmaEnc_SaveState(p->enc);
- res = LzmaEnc_CodeOneMemBlock(p->enc, p->needInitState,
- outBuf + lzHeaderSize, &packSize, LZMA2_PACK_SIZE_MAX, &unpackSize);
-
- PRF(printf("\npackSize = %7d unpackSize = %7d ", packSize, unpackSize));
-
- if (unpackSize == 0)
- return res;
-
- if (res == SZ_OK)
- useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16));
- else
- {
- if (res != SZ_ERROR_OUTPUT_EOF)
- return res;
- res = SZ_OK;
- useCopyBlock = True;
- }
-
- if (useCopyBlock)
- {
- size_t destPos = 0;
- PRF(printf("################# COPY "));
-
- while (unpackSize > 0)
- {
- UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE;
- if (packSizeLimit - destPos < u + 3)
- return SZ_ERROR_OUTPUT_EOF;
- outBuf[destPos++] = (Byte)(p->srcPos == 0 ? LZMA2_CONTROL_COPY_RESET_DIC : LZMA2_CONTROL_COPY_NO_RESET);
- outBuf[destPos++] = (Byte)((u - 1) >> 8);
- outBuf[destPos++] = (Byte)(u - 1);
- memcpy(outBuf + destPos, LzmaEnc_GetCurBuf(p->enc) - unpackSize, u);
- unpackSize -= u;
- destPos += u;
- p->srcPos += u;
-
- if (outStream)
- {
- *packSizeRes += destPos;
- if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos)
- return SZ_ERROR_WRITE;
- destPos = 0;
- }
- else
- *packSizeRes = destPos;
- /* needInitState = True; */
- }
-
- LzmaEnc_RestoreState(p->enc);
- return SZ_OK;
- }
-
- {
- size_t destPos = 0;
- UInt32 u = unpackSize - 1;
- UInt32 pm = (UInt32)(packSize - 1);
- unsigned mode = (p->srcPos == 0) ? 3 : (p->needInitState ? (p->needInitProp ? 2 : 1) : 0);
-
- PRF(printf(" "));
-
- outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | ((u >> 16) & 0x1F));
- outBuf[destPos++] = (Byte)(u >> 8);
- outBuf[destPos++] = (Byte)u;
- outBuf[destPos++] = (Byte)(pm >> 8);
- outBuf[destPos++] = (Byte)pm;
-
- if (p->needInitProp)
- outBuf[destPos++] = p->propsByte;
-
- p->needInitProp = False;
- p->needInitState = False;
- destPos += packSize;
- p->srcPos += unpackSize;
-
- if (outStream)
- if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos)
- return SZ_ERROR_WRITE;
-
- *packSizeRes = destPos;
- return SZ_OK;
- }
-}
-
-
-/* ---------- Lzma2 Props ---------- */
-
-void Lzma2EncProps_Init(CLzma2EncProps *p)
-{
- LzmaEncProps_Init(&p->lzmaProps);
- p->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO;
- p->numBlockThreads_Reduced = -1;
- p->numBlockThreads_Max = -1;
- p->numTotalThreads = -1;
-}
-
-void Lzma2EncProps_Normalize(CLzma2EncProps *p)
-{
- UInt64 fileSize;
- int t1, t1n, t2, t2r, t3;
- {
- CLzmaEncProps lzmaProps = p->lzmaProps;
- LzmaEncProps_Normalize(&lzmaProps);
- t1n = lzmaProps.numThreads;
- }
-
- t1 = p->lzmaProps.numThreads;
- t2 = p->numBlockThreads_Max;
- t3 = p->numTotalThreads;
-
- if (t2 > MTCODER__THREADS_MAX)
- t2 = MTCODER__THREADS_MAX;
-
- if (t3 <= 0)
- {
- if (t2 <= 0)
- t2 = 1;
- t3 = t1n * t2;
- }
- else if (t2 <= 0)
- {
- t2 = t3 / t1n;
- if (t2 == 0)
- {
- t1 = 1;
- t2 = t3;
- }
- if (t2 > MTCODER__THREADS_MAX)
- t2 = MTCODER__THREADS_MAX;
- }
- else if (t1 <= 0)
- {
- t1 = t3 / t2;
- if (t1 == 0)
- t1 = 1;
- }
- else
- t3 = t1n * t2;
-
- p->lzmaProps.numThreads = t1;
-
- t2r = t2;
-
- fileSize = p->lzmaProps.reduceSize;
-
- if ( p->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID
- && p->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO
- && (p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1))
- p->lzmaProps.reduceSize = p->blockSize;
-
- LzmaEncProps_Normalize(&p->lzmaProps);
-
- p->lzmaProps.reduceSize = fileSize;
-
- t1 = p->lzmaProps.numThreads;
-
- if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID)
- {
- t2r = t2 = 1;
- t3 = t1;
- }
- else if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO && t2 <= 1)
- {
- /* if there is no block multi-threading, we use SOLID block */
- p->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID;
- }
- else
- {
- if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO)
- {
- const UInt32 kMinSize = (UInt32)1 << 20;
- const UInt32 kMaxSize = (UInt32)1 << 28;
- const UInt32 dictSize = p->lzmaProps.dictSize;
- UInt64 blockSize = (UInt64)dictSize << 2;
- if (blockSize < kMinSize) blockSize = kMinSize;
- if (blockSize > kMaxSize) blockSize = kMaxSize;
- if (blockSize < dictSize) blockSize = dictSize;
- blockSize += (kMinSize - 1);
- blockSize &= ~(UInt64)(kMinSize - 1);
- p->blockSize = blockSize;
- }
-
- if (t2 > 1 && fileSize != (UInt64)(Int64)-1)
- {
- UInt64 numBlocks = fileSize / p->blockSize;
- if (numBlocks * p->blockSize != fileSize)
- numBlocks++;
- if (numBlocks < (unsigned)t2)
- {
- t2r = (unsigned)numBlocks;
- if (t2r == 0)
- t2r = 1;
- t3 = t1 * t2r;
- }
- }
- }
-
- p->numBlockThreads_Max = t2;
- p->numBlockThreads_Reduced = t2r;
- p->numTotalThreads = t3;
-}
-
-
-static SRes Progress(ICompressProgress *p, UInt64 inSize, UInt64 outSize)
-{
- return (p && ICompressProgress_Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK;
-}
-
-
-/* ---------- Lzma2 ---------- */
-
-typedef struct
-{
- Byte propEncoded;
- CLzma2EncProps props;
- UInt64 expectedDataSize;
-
- Byte *tempBufLzma;
-
- ISzAllocPtr alloc;
- ISzAllocPtr allocBig;
-
- CLzma2EncInt coders[MTCODER__THREADS_MAX];
-
- #ifndef _7ZIP_ST
-
- ISeqOutStream *outStream;
- Byte *outBuf;
- size_t outBuf_Rem; /* remainder in outBuf */
-
- size_t outBufSize; /* size of allocated outBufs[i] */
- size_t outBufsDataSizes[MTCODER__BLOCKS_MAX];
- BoolInt mtCoder_WasConstructed;
- CMtCoder mtCoder;
- Byte *outBufs[MTCODER__BLOCKS_MAX];
-
- #endif
-
-} CLzma2Enc;
-
-
-
-CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig)
-{
- CLzma2Enc *p = (CLzma2Enc *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Enc));
- if (!p)
- return NULL;
- Lzma2EncProps_Init(&p->props);
- Lzma2EncProps_Normalize(&p->props);
- p->expectedDataSize = (UInt64)(Int64)-1;
- p->tempBufLzma = NULL;
- p->alloc = alloc;
- p->allocBig = allocBig;
- {
- unsigned i;
- for (i = 0; i < MTCODER__THREADS_MAX; i++)
- p->coders[i].enc = NULL;
- }
-
- #ifndef _7ZIP_ST
- p->mtCoder_WasConstructed = False;
- {
- unsigned i;
- for (i = 0; i < MTCODER__BLOCKS_MAX; i++)
- p->outBufs[i] = NULL;
- p->outBufSize = 0;
- }
- #endif
-
- return p;
-}
-
-
-#ifndef _7ZIP_ST
-
-static void Lzma2Enc_FreeOutBufs(CLzma2Enc *p)
-{
- unsigned i;
- for (i = 0; i < MTCODER__BLOCKS_MAX; i++)
- if (p->outBufs[i])
- {
- ISzAlloc_Free(p->alloc, p->outBufs[i]);
- p->outBufs[i] = NULL;
- }
- p->outBufSize = 0;
-}
-
-#endif
-
-
-void Lzma2Enc_Destroy(CLzma2EncHandle pp)
-{
- CLzma2Enc *p = (CLzma2Enc *)pp;
- unsigned i;
- for (i = 0; i < MTCODER__THREADS_MAX; i++)
- {
- CLzma2EncInt *t = &p->coders[i];
- if (t->enc)
- {
- LzmaEnc_Destroy(t->enc, p->alloc, p->allocBig);
- t->enc = NULL;
- }
- }
-
-
- #ifndef _7ZIP_ST
- if (p->mtCoder_WasConstructed)
- {
- MtCoder_Destruct(&p->mtCoder);
- p->mtCoder_WasConstructed = False;
- }
- Lzma2Enc_FreeOutBufs(p);
- #endif
-
- ISzAlloc_Free(p->alloc, p->tempBufLzma);
- p->tempBufLzma = NULL;
-
- ISzAlloc_Free(p->alloc, pp);
-}
-
-
-SRes Lzma2Enc_SetProps(CLzma2EncHandle pp, const CLzma2EncProps *props)
-{
- CLzma2Enc *p = (CLzma2Enc *)pp;
- CLzmaEncProps lzmaProps = props->lzmaProps;
- LzmaEncProps_Normalize(&lzmaProps);
- if (lzmaProps.lc + lzmaProps.lp > LZMA2_LCLP_MAX)
- return SZ_ERROR_PARAM;
- p->props = *props;
- Lzma2EncProps_Normalize(&p->props);
- return SZ_OK;
-}
-
-
-void Lzma2Enc_SetDataSize(CLzmaEncHandle pp, UInt64 expectedDataSiize)
-{
- CLzma2Enc *p = (CLzma2Enc *)pp;
- p->expectedDataSize = expectedDataSiize;
-}
-
-
-Byte Lzma2Enc_WriteProperties(CLzma2EncHandle pp)
-{
- CLzma2Enc *p = (CLzma2Enc *)pp;
- unsigned i;
- UInt32 dicSize = LzmaEncProps_GetDictSize(&p->props.lzmaProps);
- for (i = 0; i < 40; i++)
- if (dicSize <= LZMA2_DIC_SIZE_FROM_PROP(i))
- break;
- return (Byte)i;
-}
-
-
-static SRes Lzma2Enc_EncodeMt1(
- CLzma2Enc *me,
- CLzma2EncInt *p,
- ISeqOutStream *outStream,
- Byte *outBuf, size_t *outBufSize,
- ISeqInStream *inStream,
- const Byte *inData, size_t inDataSize,
- int finished,
- ICompressProgress *progress)
-{
- UInt64 unpackTotal = 0;
- UInt64 packTotal = 0;
- size_t outLim = 0;
- CLimitedSeqInStream limitedInStream;
-
- if (outBuf)
- {
- outLim = *outBufSize;
- *outBufSize = 0;
- }
-
- if (!p->enc)
- {
- p->propsAreSet = False;
- p->enc = LzmaEnc_Create(me->alloc);
- if (!p->enc)
- return SZ_ERROR_MEM;
- }
-
- limitedInStream.realStream = inStream;
- if (inStream)
- {
- limitedInStream.vt.Read = LimitedSeqInStream_Read;
- }
-
- if (!outBuf)
- {
- // outStream version works only in one thread. So we use CLzma2Enc::tempBufLzma
- if (!me->tempBufLzma)
- {
- me->tempBufLzma = (Byte *)ISzAlloc_Alloc(me->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX);
- if (!me->tempBufLzma)
- return SZ_ERROR_MEM;
- }
- }
-
- RINOK(Lzma2EncInt_InitStream(p, &me->props));
-
- for (;;)
- {
- SRes res = SZ_OK;
- size_t inSizeCur = 0;
-
- Lzma2EncInt_InitBlock(p);
-
- LimitedSeqInStream_Init(&limitedInStream);
- limitedInStream.limit = me->props.blockSize;
-
- if (inStream)
- {
- UInt64 expected = (UInt64)(Int64)-1;
- // inStream version works only in one thread. So we use CLzma2Enc::expectedDataSize
- if (me->expectedDataSize != (UInt64)(Int64)-1
- && me->expectedDataSize >= unpackTotal)
- expected = me->expectedDataSize - unpackTotal;
- if (me->props.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID
- && expected > me->props.blockSize)
- expected = (size_t)me->props.blockSize;
-
- LzmaEnc_SetDataSize(p->enc, expected);
-
- RINOK(LzmaEnc_PrepareForLzma2(p->enc,
- &limitedInStream.vt,
- LZMA2_KEEP_WINDOW_SIZE,
- me->alloc,
- me->allocBig));
- }
- else
- {
- inSizeCur = inDataSize - (size_t)unpackTotal;
- if (me->props.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID
- && inSizeCur > me->props.blockSize)
- inSizeCur = (size_t)me->props.blockSize;
-
- // LzmaEnc_SetDataSize(p->enc, inSizeCur);
-
- RINOK(LzmaEnc_MemPrepare(p->enc,
- inData + (size_t)unpackTotal, inSizeCur,
- LZMA2_KEEP_WINDOW_SIZE,
- me->alloc,
- me->allocBig));
- }
-
- for (;;)
- {
- size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX;
- if (outBuf)
- packSize = outLim - (size_t)packTotal;
-
- res = Lzma2EncInt_EncodeSubblock(p,
- outBuf ? outBuf + (size_t)packTotal : me->tempBufLzma, &packSize,
- outBuf ? NULL : outStream);
-
- if (res != SZ_OK)
- break;
-
- packTotal += packSize;
- if (outBuf)
- *outBufSize = (size_t)packTotal;
-
- res = Progress(progress, unpackTotal + p->srcPos, packTotal);
- if (res != SZ_OK)
- break;
-
- /*
- if (LzmaEnc_GetNumAvailableBytes(p->enc) == 0)
- break;
- */
-
- if (packSize == 0)
- break;
- }
-
- LzmaEnc_Finish(p->enc);
-
- unpackTotal += p->srcPos;
-
- RINOK(res);
-
- if (p->srcPos != (inStream ? limitedInStream.processed : inSizeCur))
- return SZ_ERROR_FAIL;
-
- if (inStream ? limitedInStream.finished : (unpackTotal == inDataSize))
- {
- if (finished)
- {
- if (outBuf)
- {
- size_t destPos = *outBufSize;
- if (destPos >= outLim)
- return SZ_ERROR_OUTPUT_EOF;
- outBuf[destPos] = 0;
- *outBufSize = destPos + 1;
- }
- else
- {
- Byte b = 0;
- if (ISeqOutStream_Write(outStream, &b, 1) != 1)
- return SZ_ERROR_WRITE;
- }
- }
- return SZ_OK;
- }
- }
-}
-
-
-
-#ifndef _7ZIP_ST
-
-static SRes Lzma2Enc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex,
- const Byte *src, size_t srcSize, int finished)
-{
- CLzma2Enc *me = (CLzma2Enc *)pp;
- size_t destSize = me->outBufSize;
- SRes res;
- CMtProgressThunk progressThunk;
-
- Byte *dest = me->outBufs[outBufIndex];
-
- me->outBufsDataSizes[outBufIndex] = 0;
-
- if (!dest)
- {
- dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize);
- if (!dest)
- return SZ_ERROR_MEM;
- me->outBufs[outBufIndex] = dest;
- }
-
- MtProgressThunk_CreateVTable(&progressThunk);
- progressThunk.mtProgress = &me->mtCoder.mtProgress;
- progressThunk.inSize = 0;
- progressThunk.outSize = 0;
-
- res = Lzma2Enc_EncodeMt1(me,
- &me->coders[coderIndex],
- NULL, dest, &destSize,
- NULL, src, srcSize,
- finished,
- &progressThunk.vt);
-
- me->outBufsDataSizes[outBufIndex] = destSize;
-
- return res;
-}
-
-
-static SRes Lzma2Enc_MtCallback_Write(void *pp, unsigned outBufIndex)
-{
- CLzma2Enc *me = (CLzma2Enc *)pp;
- size_t size = me->outBufsDataSizes[outBufIndex];
- const Byte *data = me->outBufs[outBufIndex];
-
- if (me->outStream)
- return ISeqOutStream_Write(me->outStream, data, size) == size ? SZ_OK : SZ_ERROR_WRITE;
-
- if (size > me->outBuf_Rem)
- return SZ_ERROR_OUTPUT_EOF;
- memcpy(me->outBuf, data, size);
- me->outBuf_Rem -= size;
- me->outBuf += size;
- return SZ_OK;
-}
-
-#endif
-
-
-
-SRes Lzma2Enc_Encode2(CLzma2EncHandle pp,
- ISeqOutStream *outStream,
- Byte *outBuf, size_t *outBufSize,
- ISeqInStream *inStream,
- const Byte *inData, size_t inDataSize,
- ICompressProgress *progress)
-{
- CLzma2Enc *p = (CLzma2Enc *)pp;
-
- if (inStream && inData)
- return SZ_ERROR_PARAM;
-
- if (outStream && outBuf)
- return SZ_ERROR_PARAM;
-
- {
- unsigned i;
- for (i = 0; i < MTCODER__THREADS_MAX; i++)
- p->coders[i].propsAreSet = False;
- }
-
- #ifndef _7ZIP_ST
-
- if (p->props.numBlockThreads_Reduced > 1)
- {
- IMtCoderCallback2 vt;
-
- if (!p->mtCoder_WasConstructed)
- {
- p->mtCoder_WasConstructed = True;
- MtCoder_Construct(&p->mtCoder);
- }
-
- vt.Code = Lzma2Enc_MtCallback_Code;
- vt.Write = Lzma2Enc_MtCallback_Write;
-
- p->outStream = outStream;
- p->outBuf = NULL;
- p->outBuf_Rem = 0;
- if (!outStream)
- {
- p->outBuf = outBuf;
- p->outBuf_Rem = *outBufSize;
- *outBufSize = 0;
- }
-
- p->mtCoder.allocBig = p->allocBig;
- p->mtCoder.progress = progress;
- p->mtCoder.inStream = inStream;
- p->mtCoder.inData = inData;
- p->mtCoder.inDataSize = inDataSize;
- p->mtCoder.mtCallback = &vt;
- p->mtCoder.mtCallbackObject = p;
-
- p->mtCoder.blockSize = (size_t)p->props.blockSize;
- if (p->mtCoder.blockSize != p->props.blockSize)
- return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */
-
- {
- size_t destBlockSize = p->mtCoder.blockSize + (p->mtCoder.blockSize >> 10) + 16;
- if (destBlockSize < p->mtCoder.blockSize)
- return SZ_ERROR_PARAM;
- if (p->outBufSize != destBlockSize)
- Lzma2Enc_FreeOutBufs(p);
- p->outBufSize = destBlockSize;
- }
-
- p->mtCoder.numThreadsMax = p->props.numBlockThreads_Max;
- p->mtCoder.expectedDataSize = p->expectedDataSize;
-
- {
- SRes res = MtCoder_Code(&p->mtCoder);
- if (!outStream)
- *outBufSize = p->outBuf - outBuf;
- return res;
- }
- }
-
- #endif
-
-
- return Lzma2Enc_EncodeMt1(p,
- &p->coders[0],
- outStream, outBuf, outBufSize,
- inStream, inData, inDataSize,
- True, /* finished */
- progress);
-}
+/* Lzma2Enc.c -- LZMA2 Encoder
+2023-04-13 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+/* #define Z7_ST */
+
+#include "Lzma2Enc.h"
+
+#ifndef Z7_ST
+#include "MtCoder.h"
+#else
+#define MTCODER_THREADS_MAX 1
+#endif
+
+#define LZMA2_CONTROL_LZMA (1 << 7)
+#define LZMA2_CONTROL_COPY_NO_RESET 2
+#define LZMA2_CONTROL_COPY_RESET_DIC 1
+#define LZMA2_CONTROL_EOF 0
+
+#define LZMA2_LCLP_MAX 4
+
+#define LZMA2_DIC_SIZE_FROM_PROP(p) (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11))
+
+#define LZMA2_PACK_SIZE_MAX (1 << 16)
+#define LZMA2_COPY_CHUNK_SIZE LZMA2_PACK_SIZE_MAX
+#define LZMA2_UNPACK_SIZE_MAX (1 << 21)
+#define LZMA2_KEEP_WINDOW_SIZE LZMA2_UNPACK_SIZE_MAX
+
+#define LZMA2_CHUNK_SIZE_COMPRESSED_MAX ((1 << 16) + 16)
+
+
+#define PRF(x) /* x */
+
+
+/* ---------- CLimitedSeqInStream ---------- */
+
+typedef struct
+{
+ ISeqInStream vt;
+ ISeqInStreamPtr realStream;
+ UInt64 limit;
+ UInt64 processed;
+ int finished;
+} CLimitedSeqInStream;
+
+static void LimitedSeqInStream_Init(CLimitedSeqInStream *p)
+{
+ p->limit = (UInt64)(Int64)-1;
+ p->processed = 0;
+ p->finished = 0;
+}
+
+static SRes LimitedSeqInStream_Read(ISeqInStreamPtr pp, void *data, size_t *size)
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CLimitedSeqInStream)
+ size_t size2 = *size;
+ SRes res = SZ_OK;
+
+ if (p->limit != (UInt64)(Int64)-1)
+ {
+ const UInt64 rem = p->limit - p->processed;
+ if (size2 > rem)
+ size2 = (size_t)rem;
+ }
+ if (size2 != 0)
+ {
+ res = ISeqInStream_Read(p->realStream, data, &size2);
+ p->finished = (size2 == 0 ? 1 : 0);
+ p->processed += size2;
+ }
+ *size = size2;
+ return res;
+}
+
+
+/* ---------- CLzma2EncInt ---------- */
+
+typedef struct
+{
+ CLzmaEncHandle enc;
+ Byte propsAreSet;
+ Byte propsByte;
+ Byte needInitState;
+ Byte needInitProp;
+ UInt64 srcPos;
+} CLzma2EncInt;
+
+
+static SRes Lzma2EncInt_InitStream(CLzma2EncInt *p, const CLzma2EncProps *props)
+{
+ if (!p->propsAreSet)
+ {
+ SizeT propsSize = LZMA_PROPS_SIZE;
+ Byte propsEncoded[LZMA_PROPS_SIZE];
+ RINOK(LzmaEnc_SetProps(p->enc, &props->lzmaProps))
+ RINOK(LzmaEnc_WriteProperties(p->enc, propsEncoded, &propsSize))
+ p->propsByte = propsEncoded[0];
+ p->propsAreSet = True;
+ }
+ return SZ_OK;
+}
+
+static void Lzma2EncInt_InitBlock(CLzma2EncInt *p)
+{
+ p->srcPos = 0;
+ p->needInitState = True;
+ p->needInitProp = True;
+}
+
+
+SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle p, ISeqInStreamPtr inStream, UInt32 keepWindowSize,
+ ISzAllocPtr alloc, ISzAllocPtr allocBig);
+SRes LzmaEnc_MemPrepare(CLzmaEncHandle p, const Byte *src, SizeT srcLen,
+ UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig);
+SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle p, BoolInt reInit,
+ Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize);
+const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle p);
+void LzmaEnc_Finish(CLzmaEncHandle p);
+void LzmaEnc_SaveState(CLzmaEncHandle p);
+void LzmaEnc_RestoreState(CLzmaEncHandle p);
+
+/*
+UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle p);
+*/
+
+static SRes Lzma2EncInt_EncodeSubblock(CLzma2EncInt *p, Byte *outBuf,
+ size_t *packSizeRes, ISeqOutStreamPtr outStream)
+{
+ size_t packSizeLimit = *packSizeRes;
+ size_t packSize = packSizeLimit;
+ UInt32 unpackSize = LZMA2_UNPACK_SIZE_MAX;
+ unsigned lzHeaderSize = 5 + (p->needInitProp ? 1 : 0);
+ BoolInt useCopyBlock;
+ SRes res;
+
+ *packSizeRes = 0;
+ if (packSize < lzHeaderSize)
+ return SZ_ERROR_OUTPUT_EOF;
+ packSize -= lzHeaderSize;
+
+ LzmaEnc_SaveState(p->enc);
+ res = LzmaEnc_CodeOneMemBlock(p->enc, p->needInitState,
+ outBuf + lzHeaderSize, &packSize, LZMA2_PACK_SIZE_MAX, &unpackSize);
+
+ PRF(printf("\npackSize = %7d unpackSize = %7d ", packSize, unpackSize));
+
+ if (unpackSize == 0)
+ return res;
+
+ if (res == SZ_OK)
+ useCopyBlock = (packSize + 2 >= unpackSize || packSize > (1 << 16));
+ else
+ {
+ if (res != SZ_ERROR_OUTPUT_EOF)
+ return res;
+ res = SZ_OK;
+ useCopyBlock = True;
+ }
+
+ if (useCopyBlock)
+ {
+ size_t destPos = 0;
+ PRF(printf("################# COPY "));
+
+ while (unpackSize > 0)
+ {
+ const UInt32 u = (unpackSize < LZMA2_COPY_CHUNK_SIZE) ? unpackSize : LZMA2_COPY_CHUNK_SIZE;
+ if (packSizeLimit - destPos < u + 3)
+ return SZ_ERROR_OUTPUT_EOF;
+ outBuf[destPos++] = (Byte)(p->srcPos == 0 ? LZMA2_CONTROL_COPY_RESET_DIC : LZMA2_CONTROL_COPY_NO_RESET);
+ outBuf[destPos++] = (Byte)((u - 1) >> 8);
+ outBuf[destPos++] = (Byte)(u - 1);
+ memcpy(outBuf + destPos, LzmaEnc_GetCurBuf(p->enc) - unpackSize, u);
+ unpackSize -= u;
+ destPos += u;
+ p->srcPos += u;
+
+ if (outStream)
+ {
+ *packSizeRes += destPos;
+ if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos)
+ return SZ_ERROR_WRITE;
+ destPos = 0;
+ }
+ else
+ *packSizeRes = destPos;
+ /* needInitState = True; */
+ }
+
+ LzmaEnc_RestoreState(p->enc);
+ return SZ_OK;
+ }
+
+ {
+ size_t destPos = 0;
+ const UInt32 u = unpackSize - 1;
+ const UInt32 pm = (UInt32)(packSize - 1);
+ const unsigned mode = (p->srcPos == 0) ? 3 : (p->needInitState ? (p->needInitProp ? 2 : 1) : 0);
+
+ PRF(printf(" "));
+
+ outBuf[destPos++] = (Byte)(LZMA2_CONTROL_LZMA | (mode << 5) | ((u >> 16) & 0x1F));
+ outBuf[destPos++] = (Byte)(u >> 8);
+ outBuf[destPos++] = (Byte)u;
+ outBuf[destPos++] = (Byte)(pm >> 8);
+ outBuf[destPos++] = (Byte)pm;
+
+ if (p->needInitProp)
+ outBuf[destPos++] = p->propsByte;
+
+ p->needInitProp = False;
+ p->needInitState = False;
+ destPos += packSize;
+ p->srcPos += unpackSize;
+
+ if (outStream)
+ if (ISeqOutStream_Write(outStream, outBuf, destPos) != destPos)
+ return SZ_ERROR_WRITE;
+
+ *packSizeRes = destPos;
+ return SZ_OK;
+ }
+}
+
+
+/* ---------- Lzma2 Props ---------- */
+
+void Lzma2EncProps_Init(CLzma2EncProps *p)
+{
+ LzmaEncProps_Init(&p->lzmaProps);
+ p->blockSize = LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO;
+ p->numBlockThreads_Reduced = -1;
+ p->numBlockThreads_Max = -1;
+ p->numTotalThreads = -1;
+}
+
+void Lzma2EncProps_Normalize(CLzma2EncProps *p)
+{
+ UInt64 fileSize;
+ int t1, t1n, t2, t2r, t3;
+ {
+ CLzmaEncProps lzmaProps = p->lzmaProps;
+ LzmaEncProps_Normalize(&lzmaProps);
+ t1n = lzmaProps.numThreads;
+ }
+
+ t1 = p->lzmaProps.numThreads;
+ t2 = p->numBlockThreads_Max;
+ t3 = p->numTotalThreads;
+
+ if (t2 > MTCODER_THREADS_MAX)
+ t2 = MTCODER_THREADS_MAX;
+
+ if (t3 <= 0)
+ {
+ if (t2 <= 0)
+ t2 = 1;
+ t3 = t1n * t2;
+ }
+ else if (t2 <= 0)
+ {
+ t2 = t3 / t1n;
+ if (t2 == 0)
+ {
+ t1 = 1;
+ t2 = t3;
+ }
+ if (t2 > MTCODER_THREADS_MAX)
+ t2 = MTCODER_THREADS_MAX;
+ }
+ else if (t1 <= 0)
+ {
+ t1 = t3 / t2;
+ if (t1 == 0)
+ t1 = 1;
+ }
+ else
+ t3 = t1n * t2;
+
+ p->lzmaProps.numThreads = t1;
+
+ t2r = t2;
+
+ fileSize = p->lzmaProps.reduceSize;
+
+ if ( p->blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID
+ && p->blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO
+ && (p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1))
+ p->lzmaProps.reduceSize = p->blockSize;
+
+ LzmaEncProps_Normalize(&p->lzmaProps);
+
+ p->lzmaProps.reduceSize = fileSize;
+
+ t1 = p->lzmaProps.numThreads;
+
+ if (p->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID)
+ {
+ t2r = t2 = 1;
+ t3 = t1;
+ }
+ else if (p->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO && t2 <= 1)
+ {
+ /* if there is no block multi-threading, we use SOLID block */
+ p->blockSize = LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID;
+ }
+ else
+ {
+ if (p->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO)
+ {
+ const UInt32 kMinSize = (UInt32)1 << 20;
+ const UInt32 kMaxSize = (UInt32)1 << 28;
+ const UInt32 dictSize = p->lzmaProps.dictSize;
+ UInt64 blockSize = (UInt64)dictSize << 2;
+ if (blockSize < kMinSize) blockSize = kMinSize;
+ if (blockSize > kMaxSize) blockSize = kMaxSize;
+ if (blockSize < dictSize) blockSize = dictSize;
+ blockSize += (kMinSize - 1);
+ blockSize &= ~(UInt64)(kMinSize - 1);
+ p->blockSize = blockSize;
+ }
+
+ if (t2 > 1 && fileSize != (UInt64)(Int64)-1)
+ {
+ UInt64 numBlocks = fileSize / p->blockSize;
+ if (numBlocks * p->blockSize != fileSize)
+ numBlocks++;
+ if (numBlocks < (unsigned)t2)
+ {
+ t2r = (int)numBlocks;
+ if (t2r == 0)
+ t2r = 1;
+ t3 = t1 * t2r;
+ }
+ }
+ }
+
+ p->numBlockThreads_Max = t2;
+ p->numBlockThreads_Reduced = t2r;
+ p->numTotalThreads = t3;
+}
+
+
+static SRes Progress(ICompressProgressPtr p, UInt64 inSize, UInt64 outSize)
+{
+ return (p && ICompressProgress_Progress(p, inSize, outSize) != SZ_OK) ? SZ_ERROR_PROGRESS : SZ_OK;
+}
+
+
+/* ---------- Lzma2 ---------- */
+
+struct CLzma2Enc
+{
+ Byte propEncoded;
+ CLzma2EncProps props;
+ UInt64 expectedDataSize;
+
+ Byte *tempBufLzma;
+
+ ISzAllocPtr alloc;
+ ISzAllocPtr allocBig;
+
+ CLzma2EncInt coders[MTCODER_THREADS_MAX];
+
+ #ifndef Z7_ST
+
+ ISeqOutStreamPtr outStream;
+ Byte *outBuf;
+ size_t outBuf_Rem; /* remainder in outBuf */
+
+ size_t outBufSize; /* size of allocated outBufs[i] */
+ size_t outBufsDataSizes[MTCODER_BLOCKS_MAX];
+ BoolInt mtCoder_WasConstructed;
+ CMtCoder mtCoder;
+ Byte *outBufs[MTCODER_BLOCKS_MAX];
+
+ #endif
+};
+
+
+
+CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ CLzma2Enc *p = (CLzma2Enc *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Enc));
+ if (!p)
+ return NULL;
+ Lzma2EncProps_Init(&p->props);
+ Lzma2EncProps_Normalize(&p->props);
+ p->expectedDataSize = (UInt64)(Int64)-1;
+ p->tempBufLzma = NULL;
+ p->alloc = alloc;
+ p->allocBig = allocBig;
+ {
+ unsigned i;
+ for (i = 0; i < MTCODER_THREADS_MAX; i++)
+ p->coders[i].enc = NULL;
+ }
+
+ #ifndef Z7_ST
+ p->mtCoder_WasConstructed = False;
+ {
+ unsigned i;
+ for (i = 0; i < MTCODER_BLOCKS_MAX; i++)
+ p->outBufs[i] = NULL;
+ p->outBufSize = 0;
+ }
+ #endif
+
+ return (CLzma2EncHandle)p;
+}
+
+
+#ifndef Z7_ST
+
+static void Lzma2Enc_FreeOutBufs(CLzma2Enc *p)
+{
+ unsigned i;
+ for (i = 0; i < MTCODER_BLOCKS_MAX; i++)
+ if (p->outBufs[i])
+ {
+ ISzAlloc_Free(p->alloc, p->outBufs[i]);
+ p->outBufs[i] = NULL;
+ }
+ p->outBufSize = 0;
+}
+
+#endif
+
+// #define GET_CLzma2Enc_p CLzma2Enc *p = (CLzma2Enc *)(void *)p;
+
+void Lzma2Enc_Destroy(CLzma2EncHandle p)
+{
+ // GET_CLzma2Enc_p
+ unsigned i;
+ for (i = 0; i < MTCODER_THREADS_MAX; i++)
+ {
+ CLzma2EncInt *t = &p->coders[i];
+ if (t->enc)
+ {
+ LzmaEnc_Destroy(t->enc, p->alloc, p->allocBig);
+ t->enc = NULL;
+ }
+ }
+
+
+ #ifndef Z7_ST
+ if (p->mtCoder_WasConstructed)
+ {
+ MtCoder_Destruct(&p->mtCoder);
+ p->mtCoder_WasConstructed = False;
+ }
+ Lzma2Enc_FreeOutBufs(p);
+ #endif
+
+ ISzAlloc_Free(p->alloc, p->tempBufLzma);
+ p->tempBufLzma = NULL;
+
+ ISzAlloc_Free(p->alloc, p);
+}
+
+
+SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props)
+{
+ // GET_CLzma2Enc_p
+ CLzmaEncProps lzmaProps = props->lzmaProps;
+ LzmaEncProps_Normalize(&lzmaProps);
+ if (lzmaProps.lc + lzmaProps.lp > LZMA2_LCLP_MAX)
+ return SZ_ERROR_PARAM;
+ p->props = *props;
+ Lzma2EncProps_Normalize(&p->props);
+ return SZ_OK;
+}
+
+
+void Lzma2Enc_SetDataSize(CLzma2EncHandle p, UInt64 expectedDataSiize)
+{
+ // GET_CLzma2Enc_p
+ p->expectedDataSize = expectedDataSiize;
+}
+
+
+Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p)
+{
+ // GET_CLzma2Enc_p
+ unsigned i;
+ UInt32 dicSize = LzmaEncProps_GetDictSize(&p->props.lzmaProps);
+ for (i = 0; i < 40; i++)
+ if (dicSize <= LZMA2_DIC_SIZE_FROM_PROP(i))
+ break;
+ return (Byte)i;
+}
+
+
+static SRes Lzma2Enc_EncodeMt1(
+ CLzma2Enc *me,
+ CLzma2EncInt *p,
+ ISeqOutStreamPtr outStream,
+ Byte *outBuf, size_t *outBufSize,
+ ISeqInStreamPtr inStream,
+ const Byte *inData, size_t inDataSize,
+ int finished,
+ ICompressProgressPtr progress)
+{
+ UInt64 unpackTotal = 0;
+ UInt64 packTotal = 0;
+ size_t outLim = 0;
+ CLimitedSeqInStream limitedInStream;
+
+ if (outBuf)
+ {
+ outLim = *outBufSize;
+ *outBufSize = 0;
+ }
+
+ if (!p->enc)
+ {
+ p->propsAreSet = False;
+ p->enc = LzmaEnc_Create(me->alloc);
+ if (!p->enc)
+ return SZ_ERROR_MEM;
+ }
+
+ limitedInStream.realStream = inStream;
+ if (inStream)
+ {
+ limitedInStream.vt.Read = LimitedSeqInStream_Read;
+ }
+
+ if (!outBuf)
+ {
+ // outStream version works only in one thread. So we use CLzma2Enc::tempBufLzma
+ if (!me->tempBufLzma)
+ {
+ me->tempBufLzma = (Byte *)ISzAlloc_Alloc(me->alloc, LZMA2_CHUNK_SIZE_COMPRESSED_MAX);
+ if (!me->tempBufLzma)
+ return SZ_ERROR_MEM;
+ }
+ }
+
+ RINOK(Lzma2EncInt_InitStream(p, &me->props))
+
+ for (;;)
+ {
+ SRes res = SZ_OK;
+ SizeT inSizeCur = 0;
+
+ Lzma2EncInt_InitBlock(p);
+
+ LimitedSeqInStream_Init(&limitedInStream);
+ limitedInStream.limit = me->props.blockSize;
+
+ if (inStream)
+ {
+ UInt64 expected = (UInt64)(Int64)-1;
+ // inStream version works only in one thread. So we use CLzma2Enc::expectedDataSize
+ if (me->expectedDataSize != (UInt64)(Int64)-1
+ && me->expectedDataSize >= unpackTotal)
+ expected = me->expectedDataSize - unpackTotal;
+ if (me->props.blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID
+ && expected > me->props.blockSize)
+ expected = (size_t)me->props.blockSize;
+
+ LzmaEnc_SetDataSize(p->enc, expected);
+
+ RINOK(LzmaEnc_PrepareForLzma2(p->enc,
+ &limitedInStream.vt,
+ LZMA2_KEEP_WINDOW_SIZE,
+ me->alloc,
+ me->allocBig))
+ }
+ else
+ {
+ inSizeCur = (SizeT)(inDataSize - (size_t)unpackTotal);
+ if (me->props.blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID
+ && inSizeCur > me->props.blockSize)
+ inSizeCur = (SizeT)(size_t)me->props.blockSize;
+
+ // LzmaEnc_SetDataSize(p->enc, inSizeCur);
+
+ RINOK(LzmaEnc_MemPrepare(p->enc,
+ inData + (size_t)unpackTotal, inSizeCur,
+ LZMA2_KEEP_WINDOW_SIZE,
+ me->alloc,
+ me->allocBig))
+ }
+
+ for (;;)
+ {
+ size_t packSize = LZMA2_CHUNK_SIZE_COMPRESSED_MAX;
+ if (outBuf)
+ packSize = outLim - (size_t)packTotal;
+
+ res = Lzma2EncInt_EncodeSubblock(p,
+ outBuf ? outBuf + (size_t)packTotal : me->tempBufLzma, &packSize,
+ outBuf ? NULL : outStream);
+
+ if (res != SZ_OK)
+ break;
+
+ packTotal += packSize;
+ if (outBuf)
+ *outBufSize = (size_t)packTotal;
+
+ res = Progress(progress, unpackTotal + p->srcPos, packTotal);
+ if (res != SZ_OK)
+ break;
+
+ /*
+ if (LzmaEnc_GetNumAvailableBytes(p->enc) == 0)
+ break;
+ */
+
+ if (packSize == 0)
+ break;
+ }
+
+ LzmaEnc_Finish(p->enc);
+
+ unpackTotal += p->srcPos;
+
+ RINOK(res)
+
+ if (p->srcPos != (inStream ? limitedInStream.processed : inSizeCur))
+ return SZ_ERROR_FAIL;
+
+ if (inStream ? limitedInStream.finished : (unpackTotal == inDataSize))
+ {
+ if (finished)
+ {
+ if (outBuf)
+ {
+ const size_t destPos = *outBufSize;
+ if (destPos >= outLim)
+ return SZ_ERROR_OUTPUT_EOF;
+ outBuf[destPos] = LZMA2_CONTROL_EOF; // 0
+ *outBufSize = destPos + 1;
+ }
+ else
+ {
+ const Byte b = LZMA2_CONTROL_EOF; // 0;
+ if (ISeqOutStream_Write(outStream, &b, 1) != 1)
+ return SZ_ERROR_WRITE;
+ }
+ }
+ return SZ_OK;
+ }
+ }
+}
+
+
+
+#ifndef Z7_ST
+
+static SRes Lzma2Enc_MtCallback_Code(void *p, unsigned coderIndex, unsigned outBufIndex,
+ const Byte *src, size_t srcSize, int finished)
+{
+ CLzma2Enc *me = (CLzma2Enc *)p;
+ size_t destSize = me->outBufSize;
+ SRes res;
+ CMtProgressThunk progressThunk;
+
+ Byte *dest = me->outBufs[outBufIndex];
+
+ me->outBufsDataSizes[outBufIndex] = 0;
+
+ if (!dest)
+ {
+ dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize);
+ if (!dest)
+ return SZ_ERROR_MEM;
+ me->outBufs[outBufIndex] = dest;
+ }
+
+ MtProgressThunk_CreateVTable(&progressThunk);
+ progressThunk.mtProgress = &me->mtCoder.mtProgress;
+ progressThunk.inSize = 0;
+ progressThunk.outSize = 0;
+
+ res = Lzma2Enc_EncodeMt1(me,
+ &me->coders[coderIndex],
+ NULL, dest, &destSize,
+ NULL, src, srcSize,
+ finished,
+ &progressThunk.vt);
+
+ me->outBufsDataSizes[outBufIndex] = destSize;
+
+ return res;
+}
+
+
+static SRes Lzma2Enc_MtCallback_Write(void *p, unsigned outBufIndex)
+{
+ CLzma2Enc *me = (CLzma2Enc *)p;
+ size_t size = me->outBufsDataSizes[outBufIndex];
+ const Byte *data = me->outBufs[outBufIndex];
+
+ if (me->outStream)
+ return ISeqOutStream_Write(me->outStream, data, size) == size ? SZ_OK : SZ_ERROR_WRITE;
+
+ if (size > me->outBuf_Rem)
+ return SZ_ERROR_OUTPUT_EOF;
+ memcpy(me->outBuf, data, size);
+ me->outBuf_Rem -= size;
+ me->outBuf += size;
+ return SZ_OK;
+}
+
+#endif
+
+
+
+SRes Lzma2Enc_Encode2(CLzma2EncHandle p,
+ ISeqOutStreamPtr outStream,
+ Byte *outBuf, size_t *outBufSize,
+ ISeqInStreamPtr inStream,
+ const Byte *inData, size_t inDataSize,
+ ICompressProgressPtr progress)
+{
+ // GET_CLzma2Enc_p
+
+ if (inStream && inData)
+ return SZ_ERROR_PARAM;
+
+ if (outStream && outBuf)
+ return SZ_ERROR_PARAM;
+
+ {
+ unsigned i;
+ for (i = 0; i < MTCODER_THREADS_MAX; i++)
+ p->coders[i].propsAreSet = False;
+ }
+
+ #ifndef Z7_ST
+
+ if (p->props.numBlockThreads_Reduced > 1)
+ {
+ IMtCoderCallback2 vt;
+
+ if (!p->mtCoder_WasConstructed)
+ {
+ p->mtCoder_WasConstructed = True;
+ MtCoder_Construct(&p->mtCoder);
+ }
+
+ vt.Code = Lzma2Enc_MtCallback_Code;
+ vt.Write = Lzma2Enc_MtCallback_Write;
+
+ p->outStream = outStream;
+ p->outBuf = NULL;
+ p->outBuf_Rem = 0;
+ if (!outStream)
+ {
+ p->outBuf = outBuf;
+ p->outBuf_Rem = *outBufSize;
+ *outBufSize = 0;
+ }
+
+ p->mtCoder.allocBig = p->allocBig;
+ p->mtCoder.progress = progress;
+ p->mtCoder.inStream = inStream;
+ p->mtCoder.inData = inData;
+ p->mtCoder.inDataSize = inDataSize;
+ p->mtCoder.mtCallback = &vt;
+ p->mtCoder.mtCallbackObject = p;
+
+ p->mtCoder.blockSize = (size_t)p->props.blockSize;
+ if (p->mtCoder.blockSize != p->props.blockSize)
+ return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */
+
+ {
+ const size_t destBlockSize = p->mtCoder.blockSize + (p->mtCoder.blockSize >> 10) + 16;
+ if (destBlockSize < p->mtCoder.blockSize)
+ return SZ_ERROR_PARAM;
+ if (p->outBufSize != destBlockSize)
+ Lzma2Enc_FreeOutBufs(p);
+ p->outBufSize = destBlockSize;
+ }
+
+ p->mtCoder.numThreadsMax = (unsigned)p->props.numBlockThreads_Max;
+ p->mtCoder.expectedDataSize = p->expectedDataSize;
+
+ {
+ const SRes res = MtCoder_Code(&p->mtCoder);
+ if (!outStream)
+ *outBufSize = (size_t)(p->outBuf - outBuf);
+ return res;
+ }
+ }
+
+ #endif
+
+
+ return Lzma2Enc_EncodeMt1(p,
+ &p->coders[0],
+ outStream, outBuf, outBufSize,
+ inStream, inData, inDataSize,
+ True, /* finished */
+ progress);
+}
+
+#undef PRF
diff --git a/C/Lzma2Enc.h b/C/Lzma2Enc.h
index 65f2dd1..cb25275 100644
--- a/C/Lzma2Enc.h
+++ b/C/Lzma2Enc.h
@@ -1,55 +1,57 @@
-/* Lzma2Enc.h -- LZMA2 Encoder
-2017-07-27 : Igor Pavlov : Public domain */
-
-#ifndef __LZMA2_ENC_H
-#define __LZMA2_ENC_H
-
-#include "LzmaEnc.h"
-
-EXTERN_C_BEGIN
-
-#define LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO 0
-#define LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID ((UInt64)(Int64)-1)
-
-typedef struct
-{
- CLzmaEncProps lzmaProps;
- UInt64 blockSize;
- int numBlockThreads_Reduced;
- int numBlockThreads_Max;
- int numTotalThreads;
-} CLzma2EncProps;
-
-void Lzma2EncProps_Init(CLzma2EncProps *p);
-void Lzma2EncProps_Normalize(CLzma2EncProps *p);
-
-/* ---------- CLzmaEnc2Handle Interface ---------- */
-
-/* Lzma2Enc_* functions can return the following exit codes:
-SRes:
- SZ_OK - OK
- SZ_ERROR_MEM - Memory allocation error
- SZ_ERROR_PARAM - Incorrect paramater in props
- SZ_ERROR_WRITE - ISeqOutStream write callback error
- SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output
- SZ_ERROR_PROGRESS - some break from progress callback
- SZ_ERROR_THREAD - error in multithreading functions (only for Mt version)
-*/
-
-typedef void * CLzma2EncHandle;
-
-CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig);
-void Lzma2Enc_Destroy(CLzma2EncHandle p);
-SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props);
-void Lzma2Enc_SetDataSize(CLzma2EncHandle p, UInt64 expectedDataSiize);
-Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p);
-SRes Lzma2Enc_Encode2(CLzma2EncHandle p,
- ISeqOutStream *outStream,
- Byte *outBuf, size_t *outBufSize,
- ISeqInStream *inStream,
- const Byte *inData, size_t inDataSize,
- ICompressProgress *progress);
-
-EXTERN_C_END
-
-#endif
+/* Lzma2Enc.h -- LZMA2 Encoder
+2023-04-13 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_LZMA2_ENC_H
+#define ZIP7_INC_LZMA2_ENC_H
+
+#include "LzmaEnc.h"
+
+EXTERN_C_BEGIN
+
+#define LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO 0
+#define LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID ((UInt64)(Int64)-1)
+
+typedef struct
+{
+ CLzmaEncProps lzmaProps;
+ UInt64 blockSize;
+ int numBlockThreads_Reduced;
+ int numBlockThreads_Max;
+ int numTotalThreads;
+} CLzma2EncProps;
+
+void Lzma2EncProps_Init(CLzma2EncProps *p);
+void Lzma2EncProps_Normalize(CLzma2EncProps *p);
+
+/* ---------- CLzmaEnc2Handle Interface ---------- */
+
+/* Lzma2Enc_* functions can return the following exit codes:
+SRes:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater in props
+ SZ_ERROR_WRITE - ISeqOutStream write callback error
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output
+ SZ_ERROR_PROGRESS - some break from progress callback
+ SZ_ERROR_THREAD - error in multithreading functions (only for Mt version)
+*/
+
+typedef struct CLzma2Enc CLzma2Enc;
+typedef CLzma2Enc * CLzma2EncHandle;
+// Z7_DECLARE_HANDLE(CLzma2EncHandle)
+
+CLzma2EncHandle Lzma2Enc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig);
+void Lzma2Enc_Destroy(CLzma2EncHandle p);
+SRes Lzma2Enc_SetProps(CLzma2EncHandle p, const CLzma2EncProps *props);
+void Lzma2Enc_SetDataSize(CLzma2EncHandle p, UInt64 expectedDataSiize);
+Byte Lzma2Enc_WriteProperties(CLzma2EncHandle p);
+SRes Lzma2Enc_Encode2(CLzma2EncHandle p,
+ ISeqOutStreamPtr outStream,
+ Byte *outBuf, size_t *outBufSize,
+ ISeqInStreamPtr inStream,
+ const Byte *inData, size_t inDataSize,
+ ICompressProgressPtr progress);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Lzma86.h b/C/Lzma86.h
index 83057e5..e7707e2 100644
--- a/C/Lzma86.h
+++ b/C/Lzma86.h
@@ -1,111 +1,111 @@
-/* Lzma86.h -- LZMA + x86 (BCJ) Filter
-2013-01-18 : Igor Pavlov : Public domain */
-
-#ifndef __LZMA86_H
-#define __LZMA86_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-#define LZMA86_SIZE_OFFSET (1 + 5)
-#define LZMA86_HEADER_SIZE (LZMA86_SIZE_OFFSET + 8)
-
-/*
-It's an example for LZMA + x86 Filter use.
-You can use .lzma86 extension, if you write that stream to file.
-.lzma86 header adds one additional byte to standard .lzma header.
-.lzma86 header (14 bytes):
- Offset Size Description
- 0 1 = 0 - no filter, pure LZMA
- = 1 - x86 filter + LZMA
- 1 1 lc, lp and pb in encoded form
- 2 4 dictSize (little endian)
- 6 8 uncompressed size (little endian)
-
-
-Lzma86_Encode
--------------
-level - compression level: 0 <= level <= 9, the default value for "level" is 5.
-
-dictSize - The dictionary size in bytes. The maximum value is
- 128 MB = (1 << 27) bytes for 32-bit version
- 1 GB = (1 << 30) bytes for 64-bit version
- The default value is 16 MB = (1 << 24) bytes, for level = 5.
- It's recommended to use the dictionary that is larger than 4 KB and
- that can be calculated as (1 << N) or (3 << N) sizes.
- For better compression ratio dictSize must be >= inSize.
-
-filterMode:
- SZ_FILTER_NO - no Filter
- SZ_FILTER_YES - x86 Filter
- SZ_FILTER_AUTO - it tries both alternatives to select best.
- Encoder will use 2 or 3 passes:
- 2 passes when FILTER_NO provides better compression.
- 3 passes when FILTER_YES provides better compression.
-
-Lzma86Encode allocates Data with MyAlloc functions.
-RAM Requirements for compressing:
- RamSize = dictionarySize * 11.5 + 6MB + FilterBlockSize
- filterMode FilterBlockSize
- SZ_FILTER_NO 0
- SZ_FILTER_YES inSize
- SZ_FILTER_AUTO inSize
-
-
-Return code:
- SZ_OK - OK
- SZ_ERROR_MEM - Memory allocation error
- SZ_ERROR_PARAM - Incorrect paramater
- SZ_ERROR_OUTPUT_EOF - output buffer overflow
- SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
-*/
-
-enum ESzFilterMode
-{
- SZ_FILTER_NO,
- SZ_FILTER_YES,
- SZ_FILTER_AUTO
-};
-
-SRes Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen,
- int level, UInt32 dictSize, int filterMode);
-
-
-/*
-Lzma86_GetUnpackSize:
- In:
- src - input data
- srcLen - input data size
- Out:
- unpackSize - size of uncompressed stream
- Return code:
- SZ_OK - OK
- SZ_ERROR_INPUT_EOF - Error in headers
-*/
-
-SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize);
-
-/*
-Lzma86_Decode:
- In:
- dest - output data
- destLen - output data size
- src - input data
- srcLen - input data size
- Out:
- destLen - processed output size
- srcLen - processed input size
- Return code:
- SZ_OK - OK
- SZ_ERROR_DATA - Data error
- SZ_ERROR_MEM - Memory allocation error
- SZ_ERROR_UNSUPPORTED - unsupported file
- SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer
-*/
-
-SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen);
-
-EXTERN_C_END
-
-#endif
+/* Lzma86.h -- LZMA + x86 (BCJ) Filter
+2023-03-03 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_LZMA86_H
+#define ZIP7_INC_LZMA86_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define LZMA86_SIZE_OFFSET (1 + 5)
+#define LZMA86_HEADER_SIZE (LZMA86_SIZE_OFFSET + 8)
+
+/*
+It's an example for LZMA + x86 Filter use.
+You can use .lzma86 extension, if you write that stream to file.
+.lzma86 header adds one additional byte to standard .lzma header.
+.lzma86 header (14 bytes):
+ Offset Size Description
+ 0 1 = 0 - no filter, pure LZMA
+ = 1 - x86 filter + LZMA
+ 1 1 lc, lp and pb in encoded form
+ 2 4 dictSize (little endian)
+ 6 8 uncompressed size (little endian)
+
+
+Lzma86_Encode
+-------------
+level - compression level: 0 <= level <= 9, the default value for "level" is 5.
+
+dictSize - The dictionary size in bytes. The maximum value is
+ 128 MB = (1 << 27) bytes for 32-bit version
+ 1 GB = (1 << 30) bytes for 64-bit version
+ The default value is 16 MB = (1 << 24) bytes, for level = 5.
+ It's recommended to use the dictionary that is larger than 4 KB and
+ that can be calculated as (1 << N) or (3 << N) sizes.
+ For better compression ratio dictSize must be >= inSize.
+
+filterMode:
+ SZ_FILTER_NO - no Filter
+ SZ_FILTER_YES - x86 Filter
+ SZ_FILTER_AUTO - it tries both alternatives to select best.
+ Encoder will use 2 or 3 passes:
+ 2 passes when FILTER_NO provides better compression.
+ 3 passes when FILTER_YES provides better compression.
+
+Lzma86Encode allocates Data with MyAlloc functions.
+RAM Requirements for compressing:
+ RamSize = dictionarySize * 11.5 + 6MB + FilterBlockSize
+ filterMode FilterBlockSize
+ SZ_FILTER_NO 0
+ SZ_FILTER_YES inSize
+ SZ_FILTER_AUTO inSize
+
+
+Return code:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+*/
+
+enum ESzFilterMode
+{
+ SZ_FILTER_NO,
+ SZ_FILTER_YES,
+ SZ_FILTER_AUTO
+};
+
+SRes Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen,
+ int level, UInt32 dictSize, int filterMode);
+
+
+/*
+Lzma86_GetUnpackSize:
+ In:
+ src - input data
+ srcLen - input data size
+ Out:
+ unpackSize - size of uncompressed stream
+ Return code:
+ SZ_OK - OK
+ SZ_ERROR_INPUT_EOF - Error in headers
+*/
+
+SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize);
+
+/*
+Lzma86_Decode:
+ In:
+ dest - output data
+ destLen - output data size
+ src - input data
+ srcLen - input data size
+ Out:
+ destLen - processed output size
+ srcLen - processed input size
+ Return code:
+ SZ_OK - OK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - unsupported file
+ SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer
+*/
+
+SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Lzma86Dec.c b/C/Lzma86Dec.c
index 20ac5e7..f094d4c 100644
--- a/C/Lzma86Dec.c
+++ b/C/Lzma86Dec.c
@@ -1,54 +1,53 @@
-/* Lzma86Dec.c -- LZMA + x86 (BCJ) Filter Decoder
-2016-05-16 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "Lzma86.h"
-
-#include "Alloc.h"
-#include "Bra.h"
-#include "LzmaDec.h"
-
-SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize)
-{
- unsigned i;
- if (srcLen < LZMA86_HEADER_SIZE)
- return SZ_ERROR_INPUT_EOF;
- *unpackSize = 0;
- for (i = 0; i < sizeof(UInt64); i++)
- *unpackSize += ((UInt64)src[LZMA86_SIZE_OFFSET + i]) << (8 * i);
- return SZ_OK;
-}
-
-SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen)
-{
- SRes res;
- int useFilter;
- SizeT inSizePure;
- ELzmaStatus status;
-
- if (*srcLen < LZMA86_HEADER_SIZE)
- return SZ_ERROR_INPUT_EOF;
-
- useFilter = src[0];
-
- if (useFilter > 1)
- {
- *destLen = 0;
- return SZ_ERROR_UNSUPPORTED;
- }
-
- inSizePure = *srcLen - LZMA86_HEADER_SIZE;
- res = LzmaDecode(dest, destLen, src + LZMA86_HEADER_SIZE, &inSizePure,
- src + 1, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &g_Alloc);
- *srcLen = inSizePure + LZMA86_HEADER_SIZE;
- if (res != SZ_OK)
- return res;
- if (useFilter == 1)
- {
- UInt32 x86State;
- x86_Convert_Init(x86State);
- x86_Convert(dest, *destLen, 0, &x86State, 0);
- }
- return SZ_OK;
-}
+/* Lzma86Dec.c -- LZMA + x86 (BCJ) Filter Decoder
+2023-03-03 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Lzma86.h"
+
+#include "Alloc.h"
+#include "Bra.h"
+#include "LzmaDec.h"
+
+SRes Lzma86_GetUnpackSize(const Byte *src, SizeT srcLen, UInt64 *unpackSize)
+{
+ unsigned i;
+ if (srcLen < LZMA86_HEADER_SIZE)
+ return SZ_ERROR_INPUT_EOF;
+ *unpackSize = 0;
+ for (i = 0; i < sizeof(UInt64); i++)
+ *unpackSize += ((UInt64)src[LZMA86_SIZE_OFFSET + i]) << (8 * i);
+ return SZ_OK;
+}
+
+SRes Lzma86_Decode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen)
+{
+ SRes res;
+ int useFilter;
+ SizeT inSizePure;
+ ELzmaStatus status;
+
+ if (*srcLen < LZMA86_HEADER_SIZE)
+ return SZ_ERROR_INPUT_EOF;
+
+ useFilter = src[0];
+
+ if (useFilter > 1)
+ {
+ *destLen = 0;
+ return SZ_ERROR_UNSUPPORTED;
+ }
+
+ inSizePure = *srcLen - LZMA86_HEADER_SIZE;
+ res = LzmaDecode(dest, destLen, src + LZMA86_HEADER_SIZE, &inSizePure,
+ src + 1, LZMA_PROPS_SIZE, LZMA_FINISH_ANY, &status, &g_Alloc);
+ *srcLen = inSizePure + LZMA86_HEADER_SIZE;
+ if (res != SZ_OK)
+ return res;
+ if (useFilter == 1)
+ {
+ UInt32 x86State = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL;
+ z7_BranchConvSt_X86_Dec(dest, *destLen, 0, &x86State);
+ }
+ return SZ_OK;
+}
diff --git a/C/Lzma86Enc.c b/C/Lzma86Enc.c
index 8d35e6d..0cdde1c 100644
--- a/C/Lzma86Enc.c
+++ b/C/Lzma86Enc.c
@@ -1,106 +1,103 @@
-/* Lzma86Enc.c -- LZMA + x86 (BCJ) Filter Encoder
-2018-07-04 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include <string.h>
-
-#include "Lzma86.h"
-
-#include "Alloc.h"
-#include "Bra.h"
-#include "LzmaEnc.h"
-
-#define SZE_OUT_OVERFLOW SZE_DATA_ERROR
-
-int Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen,
- int level, UInt32 dictSize, int filterMode)
-{
- size_t outSize2 = *destLen;
- Byte *filteredStream;
- BoolInt useFilter;
- int mainResult = SZ_ERROR_OUTPUT_EOF;
- CLzmaEncProps props;
- LzmaEncProps_Init(&props);
- props.level = level;
- props.dictSize = dictSize;
-
- *destLen = 0;
- if (outSize2 < LZMA86_HEADER_SIZE)
- return SZ_ERROR_OUTPUT_EOF;
-
- {
- int i;
- UInt64 t = srcLen;
- for (i = 0; i < 8; i++, t >>= 8)
- dest[LZMA86_SIZE_OFFSET + i] = (Byte)t;
- }
-
- filteredStream = 0;
- useFilter = (filterMode != SZ_FILTER_NO);
- if (useFilter)
- {
- if (srcLen != 0)
- {
- filteredStream = (Byte *)MyAlloc(srcLen);
- if (filteredStream == 0)
- return SZ_ERROR_MEM;
- memcpy(filteredStream, src, srcLen);
- }
- {
- UInt32 x86State;
- x86_Convert_Init(x86State);
- x86_Convert(filteredStream, srcLen, 0, &x86State, 1);
- }
- }
-
- {
- size_t minSize = 0;
- BoolInt bestIsFiltered = False;
-
- /* passes for SZ_FILTER_AUTO:
- 0 - BCJ + LZMA
- 1 - LZMA
- 2 - BCJ + LZMA agaian, if pass 0 (BCJ + LZMA) is better.
- */
- int numPasses = (filterMode == SZ_FILTER_AUTO) ? 3 : 1;
-
- int i;
- for (i = 0; i < numPasses; i++)
- {
- size_t outSizeProcessed = outSize2 - LZMA86_HEADER_SIZE;
- size_t outPropsSize = 5;
- SRes curRes;
- BoolInt curModeIsFiltered = (numPasses > 1 && i == numPasses - 1);
- if (curModeIsFiltered && !bestIsFiltered)
- break;
- if (useFilter && i == 0)
- curModeIsFiltered = True;
-
- curRes = LzmaEncode(dest + LZMA86_HEADER_SIZE, &outSizeProcessed,
- curModeIsFiltered ? filteredStream : src, srcLen,
- &props, dest + 1, &outPropsSize, 0,
- NULL, &g_Alloc, &g_Alloc);
-
- if (curRes != SZ_ERROR_OUTPUT_EOF)
- {
- if (curRes != SZ_OK)
- {
- mainResult = curRes;
- break;
- }
- if (outSizeProcessed <= minSize || mainResult != SZ_OK)
- {
- minSize = outSizeProcessed;
- bestIsFiltered = curModeIsFiltered;
- mainResult = SZ_OK;
- }
- }
- }
- dest[0] = (Byte)(bestIsFiltered ? 1 : 0);
- *destLen = LZMA86_HEADER_SIZE + minSize;
- }
- if (useFilter)
- MyFree(filteredStream);
- return mainResult;
-}
+/* Lzma86Enc.c -- LZMA + x86 (BCJ) Filter Encoder
+2023-03-03 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#include "Lzma86.h"
+
+#include "Alloc.h"
+#include "Bra.h"
+#include "LzmaEnc.h"
+
+int Lzma86_Encode(Byte *dest, size_t *destLen, const Byte *src, size_t srcLen,
+ int level, UInt32 dictSize, int filterMode)
+{
+ size_t outSize2 = *destLen;
+ Byte *filteredStream;
+ BoolInt useFilter;
+ int mainResult = SZ_ERROR_OUTPUT_EOF;
+ CLzmaEncProps props;
+ LzmaEncProps_Init(&props);
+ props.level = level;
+ props.dictSize = dictSize;
+
+ *destLen = 0;
+ if (outSize2 < LZMA86_HEADER_SIZE)
+ return SZ_ERROR_OUTPUT_EOF;
+
+ {
+ int i;
+ UInt64 t = srcLen;
+ for (i = 0; i < 8; i++, t >>= 8)
+ dest[LZMA86_SIZE_OFFSET + i] = (Byte)t;
+ }
+
+ filteredStream = 0;
+ useFilter = (filterMode != SZ_FILTER_NO);
+ if (useFilter)
+ {
+ if (srcLen != 0)
+ {
+ filteredStream = (Byte *)MyAlloc(srcLen);
+ if (filteredStream == 0)
+ return SZ_ERROR_MEM;
+ memcpy(filteredStream, src, srcLen);
+ }
+ {
+ UInt32 x86State = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL;
+ z7_BranchConvSt_X86_Enc(filteredStream, srcLen, 0, &x86State);
+ }
+ }
+
+ {
+ size_t minSize = 0;
+ BoolInt bestIsFiltered = False;
+
+ /* passes for SZ_FILTER_AUTO:
+ 0 - BCJ + LZMA
+ 1 - LZMA
+ 2 - BCJ + LZMA agaian, if pass 0 (BCJ + LZMA) is better.
+ */
+ int numPasses = (filterMode == SZ_FILTER_AUTO) ? 3 : 1;
+
+ int i;
+ for (i = 0; i < numPasses; i++)
+ {
+ size_t outSizeProcessed = outSize2 - LZMA86_HEADER_SIZE;
+ size_t outPropsSize = 5;
+ SRes curRes;
+ BoolInt curModeIsFiltered = (numPasses > 1 && i == numPasses - 1);
+ if (curModeIsFiltered && !bestIsFiltered)
+ break;
+ if (useFilter && i == 0)
+ curModeIsFiltered = True;
+
+ curRes = LzmaEncode(dest + LZMA86_HEADER_SIZE, &outSizeProcessed,
+ curModeIsFiltered ? filteredStream : src, srcLen,
+ &props, dest + 1, &outPropsSize, 0,
+ NULL, &g_Alloc, &g_Alloc);
+
+ if (curRes != SZ_ERROR_OUTPUT_EOF)
+ {
+ if (curRes != SZ_OK)
+ {
+ mainResult = curRes;
+ break;
+ }
+ if (outSizeProcessed <= minSize || mainResult != SZ_OK)
+ {
+ minSize = outSizeProcessed;
+ bestIsFiltered = curModeIsFiltered;
+ mainResult = SZ_OK;
+ }
+ }
+ }
+ dest[0] = (Byte)(bestIsFiltered ? 1 : 0);
+ *destLen = LZMA86_HEADER_SIZE + minSize;
+ }
+ if (useFilter)
+ MyFree(filteredStream);
+ return mainResult;
+}
diff --git a/C/LzmaDec.c b/C/LzmaDec.c
index 4d15764..69bb8bb 100644
--- a/C/LzmaDec.c
+++ b/C/LzmaDec.c
@@ -1,1185 +1,1363 @@
-/* LzmaDec.c -- LZMA Decoder
-2018-07-04 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include <string.h>
-
-/* #include "CpuArch.h" */
-#include "LzmaDec.h"
-
-#define kNumTopBits 24
-#define kTopValue ((UInt32)1 << kNumTopBits)
-
-#define kNumBitModelTotalBits 11
-#define kBitModelTotal (1 << kNumBitModelTotalBits)
-#define kNumMoveBits 5
-
-#define RC_INIT_SIZE 5
-
-#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
-
-#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound)
-#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
-#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
-#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
- { UPDATE_0(p); i = (i + i); A0; } else \
- { UPDATE_1(p); i = (i + i) + 1; A1; }
-
-#define TREE_GET_BIT(probs, i) { GET_BIT2(probs + i, i, ;, ;); }
-
-#define REV_BIT(p, i, A0, A1) IF_BIT_0(p + i) \
- { UPDATE_0(p + i); A0; } else \
- { UPDATE_1(p + i); A1; }
-#define REV_BIT_VAR( p, i, m) REV_BIT(p, i, i += m; m += m, m += m; i += m; )
-#define REV_BIT_CONST(p, i, m) REV_BIT(p, i, i += m; , i += m * 2; )
-#define REV_BIT_LAST( p, i, m) REV_BIT(p, i, i -= m , ; )
-
-#define TREE_DECODE(probs, limit, i) \
- { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
-
-/* #define _LZMA_SIZE_OPT */
-
-#ifdef _LZMA_SIZE_OPT
-#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
-#else
-#define TREE_6_DECODE(probs, i) \
- { i = 1; \
- TREE_GET_BIT(probs, i); \
- TREE_GET_BIT(probs, i); \
- TREE_GET_BIT(probs, i); \
- TREE_GET_BIT(probs, i); \
- TREE_GET_BIT(probs, i); \
- TREE_GET_BIT(probs, i); \
- i -= 0x40; }
-#endif
-
-#define NORMAL_LITER_DEC TREE_GET_BIT(prob, symbol)
-#define MATCHED_LITER_DEC \
- matchByte += matchByte; \
- bit = offs; \
- offs &= matchByte; \
- probLit = prob + (offs + bit + symbol); \
- GET_BIT2(probLit, symbol, offs ^= bit; , ;)
-
-
-
-#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
-
-#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound)
-#define UPDATE_0_CHECK range = bound;
-#define UPDATE_1_CHECK range -= bound; code -= bound;
-#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
- { UPDATE_0_CHECK; i = (i + i); A0; } else \
- { UPDATE_1_CHECK; i = (i + i) + 1; A1; }
-#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)
-#define TREE_DECODE_CHECK(probs, limit, i) \
- { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; }
-
-
-#define REV_BIT_CHECK(p, i, m) IF_BIT_0_CHECK(p + i) \
- { UPDATE_0_CHECK; i += m; m += m; } else \
- { UPDATE_1_CHECK; m += m; i += m; }
-
-
-#define kNumPosBitsMax 4
-#define kNumPosStatesMax (1 << kNumPosBitsMax)
-
-#define kLenNumLowBits 3
-#define kLenNumLowSymbols (1 << kLenNumLowBits)
-#define kLenNumHighBits 8
-#define kLenNumHighSymbols (1 << kLenNumHighBits)
-
-#define LenLow 0
-#define LenHigh (LenLow + 2 * (kNumPosStatesMax << kLenNumLowBits))
-#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
-
-#define LenChoice LenLow
-#define LenChoice2 (LenLow + (1 << kLenNumLowBits))
-
-#define kNumStates 12
-#define kNumStates2 16
-#define kNumLitStates 7
-
-#define kStartPosModelIndex 4
-#define kEndPosModelIndex 14
-#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
-
-#define kNumPosSlotBits 6
-#define kNumLenToPosStates 4
-
-#define kNumAlignBits 4
-#define kAlignTableSize (1 << kNumAlignBits)
-
-#define kMatchMinLen 2
-#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols * 2 + kLenNumHighSymbols)
-
-/* External ASM code needs same CLzmaProb array layout. So don't change it. */
-
-/* (probs_1664) is faster and better for code size at some platforms */
-/*
-#ifdef MY_CPU_X86_OR_AMD64
-*/
-#define kStartOffset 1664
-#define GET_PROBS p->probs_1664
-/*
-#define GET_PROBS p->probs + kStartOffset
-#else
-#define kStartOffset 0
-#define GET_PROBS p->probs
-#endif
-*/
-
-#define SpecPos (-kStartOffset)
-#define IsRep0Long (SpecPos + kNumFullDistances)
-#define RepLenCoder (IsRep0Long + (kNumStates2 << kNumPosBitsMax))
-#define LenCoder (RepLenCoder + kNumLenProbs)
-#define IsMatch (LenCoder + kNumLenProbs)
-#define Align (IsMatch + (kNumStates2 << kNumPosBitsMax))
-#define IsRep (Align + kAlignTableSize)
-#define IsRepG0 (IsRep + kNumStates)
-#define IsRepG1 (IsRepG0 + kNumStates)
-#define IsRepG2 (IsRepG1 + kNumStates)
-#define PosSlot (IsRepG2 + kNumStates)
-#define Literal (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
-#define NUM_BASE_PROBS (Literal + kStartOffset)
-
-#if Align != 0 && kStartOffset != 0
- #error Stop_Compiling_Bad_LZMA_kAlign
-#endif
-
-#if NUM_BASE_PROBS != 1984
- #error Stop_Compiling_Bad_LZMA_PROBS
-#endif
-
-
-#define LZMA_LIT_SIZE 0x300
-
-#define LzmaProps_GetNumProbs(p) (NUM_BASE_PROBS + ((UInt32)LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
-
-
-#define CALC_POS_STATE(processedPos, pbMask) (((processedPos) & (pbMask)) << 4)
-#define COMBINED_PS_STATE (posState + state)
-#define GET_LEN_STATE (posState)
-
-#define LZMA_DIC_MIN (1 << 12)
-
-/*
-p->remainLen : shows status of LZMA decoder:
- < kMatchSpecLenStart : normal remain
- = kMatchSpecLenStart : finished
- = kMatchSpecLenStart + 1 : need init range coder
- = kMatchSpecLenStart + 2 : need init range coder and state
-*/
-
-/* ---------- LZMA_DECODE_REAL ---------- */
-/*
-LzmaDec_DecodeReal_3() can be implemented in external ASM file.
-3 - is the code compatibility version of that function for check at link time.
-*/
-
-#define LZMA_DECODE_REAL LzmaDec_DecodeReal_3
-
-/*
-LZMA_DECODE_REAL()
-In:
- RangeCoder is normalized
- if (p->dicPos == limit)
- {
- LzmaDec_TryDummy() was called before to exclude LITERAL and MATCH-REP cases.
- So first symbol can be only MATCH-NON-REP. And if that MATCH-NON-REP symbol
- is not END_OF_PAYALOAD_MARKER, then function returns error code.
- }
-
-Processing:
- first LZMA symbol will be decoded in any case
- All checks for limits are at the end of main loop,
- It will decode new LZMA-symbols while (p->buf < bufLimit && dicPos < limit),
- RangeCoder is still without last normalization when (p->buf < bufLimit) is being checked.
-
-Out:
- RangeCoder is normalized
- Result:
- SZ_OK - OK
- SZ_ERROR_DATA - Error
- p->remainLen:
- < kMatchSpecLenStart : normal remain
- = kMatchSpecLenStart : finished
-*/
-
-
-#ifdef _LZMA_DEC_OPT
-
-int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit);
-
-#else
-
-static
-int MY_FAST_CALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
-{
- CLzmaProb *probs = GET_PROBS;
- unsigned state = (unsigned)p->state;
- UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
- unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
- unsigned lc = p->prop.lc;
- unsigned lpMask = ((unsigned)0x100 << p->prop.lp) - ((unsigned)0x100 >> lc);
-
- Byte *dic = p->dic;
- SizeT dicBufSize = p->dicBufSize;
- SizeT dicPos = p->dicPos;
-
- UInt32 processedPos = p->processedPos;
- UInt32 checkDicSize = p->checkDicSize;
- unsigned len = 0;
-
- const Byte *buf = p->buf;
- UInt32 range = p->range;
- UInt32 code = p->code;
-
- do
- {
- CLzmaProb *prob;
- UInt32 bound;
- unsigned ttt;
- unsigned posState = CALC_POS_STATE(processedPos, pbMask);
-
- prob = probs + IsMatch + COMBINED_PS_STATE;
- IF_BIT_0(prob)
- {
- unsigned symbol;
- UPDATE_0(prob);
- prob = probs + Literal;
- if (processedPos != 0 || checkDicSize != 0)
- prob += (UInt32)3 * ((((processedPos << 8) + dic[(dicPos == 0 ? dicBufSize : dicPos) - 1]) & lpMask) << lc);
- processedPos++;
-
- if (state < kNumLitStates)
- {
- state -= (state < 4) ? state : 3;
- symbol = 1;
- #ifdef _LZMA_SIZE_OPT
- do { NORMAL_LITER_DEC } while (symbol < 0x100);
- #else
- NORMAL_LITER_DEC
- NORMAL_LITER_DEC
- NORMAL_LITER_DEC
- NORMAL_LITER_DEC
- NORMAL_LITER_DEC
- NORMAL_LITER_DEC
- NORMAL_LITER_DEC
- NORMAL_LITER_DEC
- #endif
- }
- else
- {
- unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
- unsigned offs = 0x100;
- state -= (state < 10) ? 3 : 6;
- symbol = 1;
- #ifdef _LZMA_SIZE_OPT
- do
- {
- unsigned bit;
- CLzmaProb *probLit;
- MATCHED_LITER_DEC
- }
- while (symbol < 0x100);
- #else
- {
- unsigned bit;
- CLzmaProb *probLit;
- MATCHED_LITER_DEC
- MATCHED_LITER_DEC
- MATCHED_LITER_DEC
- MATCHED_LITER_DEC
- MATCHED_LITER_DEC
- MATCHED_LITER_DEC
- MATCHED_LITER_DEC
- MATCHED_LITER_DEC
- }
- #endif
- }
-
- dic[dicPos++] = (Byte)symbol;
- continue;
- }
-
- {
- UPDATE_1(prob);
- prob = probs + IsRep + state;
- IF_BIT_0(prob)
- {
- UPDATE_0(prob);
- state += kNumStates;
- prob = probs + LenCoder;
- }
- else
- {
- UPDATE_1(prob);
- /*
- // that case was checked before with kBadRepCode
- if (checkDicSize == 0 && processedPos == 0)
- return SZ_ERROR_DATA;
- */
- prob = probs + IsRepG0 + state;
- IF_BIT_0(prob)
- {
- UPDATE_0(prob);
- prob = probs + IsRep0Long + COMBINED_PS_STATE;
- IF_BIT_0(prob)
- {
- UPDATE_0(prob);
- dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
- dicPos++;
- processedPos++;
- state = state < kNumLitStates ? 9 : 11;
- continue;
- }
- UPDATE_1(prob);
- }
- else
- {
- UInt32 distance;
- UPDATE_1(prob);
- prob = probs + IsRepG1 + state;
- IF_BIT_0(prob)
- {
- UPDATE_0(prob);
- distance = rep1;
- }
- else
- {
- UPDATE_1(prob);
- prob = probs + IsRepG2 + state;
- IF_BIT_0(prob)
- {
- UPDATE_0(prob);
- distance = rep2;
- }
- else
- {
- UPDATE_1(prob);
- distance = rep3;
- rep3 = rep2;
- }
- rep2 = rep1;
- }
- rep1 = rep0;
- rep0 = distance;
- }
- state = state < kNumLitStates ? 8 : 11;
- prob = probs + RepLenCoder;
- }
-
- #ifdef _LZMA_SIZE_OPT
- {
- unsigned lim, offset;
- CLzmaProb *probLen = prob + LenChoice;
- IF_BIT_0(probLen)
- {
- UPDATE_0(probLen);
- probLen = prob + LenLow + GET_LEN_STATE;
- offset = 0;
- lim = (1 << kLenNumLowBits);
- }
- else
- {
- UPDATE_1(probLen);
- probLen = prob + LenChoice2;
- IF_BIT_0(probLen)
- {
- UPDATE_0(probLen);
- probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits);
- offset = kLenNumLowSymbols;
- lim = (1 << kLenNumLowBits);
- }
- else
- {
- UPDATE_1(probLen);
- probLen = prob + LenHigh;
- offset = kLenNumLowSymbols * 2;
- lim = (1 << kLenNumHighBits);
- }
- }
- TREE_DECODE(probLen, lim, len);
- len += offset;
- }
- #else
- {
- CLzmaProb *probLen = prob + LenChoice;
- IF_BIT_0(probLen)
- {
- UPDATE_0(probLen);
- probLen = prob + LenLow + GET_LEN_STATE;
- len = 1;
- TREE_GET_BIT(probLen, len);
- TREE_GET_BIT(probLen, len);
- TREE_GET_BIT(probLen, len);
- len -= 8;
- }
- else
- {
- UPDATE_1(probLen);
- probLen = prob + LenChoice2;
- IF_BIT_0(probLen)
- {
- UPDATE_0(probLen);
- probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits);
- len = 1;
- TREE_GET_BIT(probLen, len);
- TREE_GET_BIT(probLen, len);
- TREE_GET_BIT(probLen, len);
- }
- else
- {
- UPDATE_1(probLen);
- probLen = prob + LenHigh;
- TREE_DECODE(probLen, (1 << kLenNumHighBits), len);
- len += kLenNumLowSymbols * 2;
- }
- }
- }
- #endif
-
- if (state >= kNumStates)
- {
- UInt32 distance;
- prob = probs + PosSlot +
- ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
- TREE_6_DECODE(prob, distance);
- if (distance >= kStartPosModelIndex)
- {
- unsigned posSlot = (unsigned)distance;
- unsigned numDirectBits = (unsigned)(((distance >> 1) - 1));
- distance = (2 | (distance & 1));
- if (posSlot < kEndPosModelIndex)
- {
- distance <<= numDirectBits;
- prob = probs + SpecPos;
- {
- UInt32 m = 1;
- distance++;
- do
- {
- REV_BIT_VAR(prob, distance, m);
- }
- while (--numDirectBits);
- distance -= m;
- }
- }
- else
- {
- numDirectBits -= kNumAlignBits;
- do
- {
- NORMALIZE
- range >>= 1;
-
- {
- UInt32 t;
- code -= range;
- t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
- distance = (distance << 1) + (t + 1);
- code += range & t;
- }
- /*
- distance <<= 1;
- if (code >= range)
- {
- code -= range;
- distance |= 1;
- }
- */
- }
- while (--numDirectBits);
- prob = probs + Align;
- distance <<= kNumAlignBits;
- {
- unsigned i = 1;
- REV_BIT_CONST(prob, i, 1);
- REV_BIT_CONST(prob, i, 2);
- REV_BIT_CONST(prob, i, 4);
- REV_BIT_LAST (prob, i, 8);
- distance |= i;
- }
- if (distance == (UInt32)0xFFFFFFFF)
- {
- len = kMatchSpecLenStart;
- state -= kNumStates;
- break;
- }
- }
- }
-
- rep3 = rep2;
- rep2 = rep1;
- rep1 = rep0;
- rep0 = distance + 1;
- state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
- if (distance >= (checkDicSize == 0 ? processedPos: checkDicSize))
- {
- p->dicPos = dicPos;
- return SZ_ERROR_DATA;
- }
- }
-
- len += kMatchMinLen;
-
- {
- SizeT rem;
- unsigned curLen;
- SizeT pos;
-
- if ((rem = limit - dicPos) == 0)
- {
- p->dicPos = dicPos;
- return SZ_ERROR_DATA;
- }
-
- curLen = ((rem < len) ? (unsigned)rem : len);
- pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0);
-
- processedPos += (UInt32)curLen;
-
- len -= curLen;
- if (curLen <= dicBufSize - pos)
- {
- Byte *dest = dic + dicPos;
- ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
- const Byte *lim = dest + curLen;
- dicPos += (SizeT)curLen;
- do
- *(dest) = (Byte)*(dest + src);
- while (++dest != lim);
- }
- else
- {
- do
- {
- dic[dicPos++] = dic[pos];
- if (++pos == dicBufSize)
- pos = 0;
- }
- while (--curLen != 0);
- }
- }
- }
- }
- while (dicPos < limit && buf < bufLimit);
-
- NORMALIZE;
-
- p->buf = buf;
- p->range = range;
- p->code = code;
- p->remainLen = (UInt32)len;
- p->dicPos = dicPos;
- p->processedPos = processedPos;
- p->reps[0] = rep0;
- p->reps[1] = rep1;
- p->reps[2] = rep2;
- p->reps[3] = rep3;
- p->state = (UInt32)state;
-
- return SZ_OK;
-}
-#endif
-
-static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
-{
- if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)
- {
- Byte *dic = p->dic;
- SizeT dicPos = p->dicPos;
- SizeT dicBufSize = p->dicBufSize;
- unsigned len = (unsigned)p->remainLen;
- SizeT rep0 = p->reps[0]; /* we use SizeT to avoid the BUG of VC14 for AMD64 */
- SizeT rem = limit - dicPos;
- if (rem < len)
- len = (unsigned)(rem);
-
- if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
- p->checkDicSize = p->prop.dicSize;
-
- p->processedPos += (UInt32)len;
- p->remainLen -= (UInt32)len;
- while (len != 0)
- {
- len--;
- dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
- dicPos++;
- }
- p->dicPos = dicPos;
- }
-}
-
-
-#define kRange0 0xFFFFFFFF
-#define kBound0 ((kRange0 >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1))
-#define kBadRepCode (kBound0 + (((kRange0 - kBound0) >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1)))
-#if kBadRepCode != (0xC0000000 - 0x400)
- #error Stop_Compiling_Bad_LZMA_Check
-#endif
-
-static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
-{
- do
- {
- SizeT limit2 = limit;
- if (p->checkDicSize == 0)
- {
- UInt32 rem = p->prop.dicSize - p->processedPos;
- if (limit - p->dicPos > rem)
- limit2 = p->dicPos + rem;
-
- if (p->processedPos == 0)
- if (p->code >= kBadRepCode)
- return SZ_ERROR_DATA;
- }
-
- RINOK(LZMA_DECODE_REAL(p, limit2, bufLimit));
-
- if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize)
- p->checkDicSize = p->prop.dicSize;
-
- LzmaDec_WriteRem(p, limit);
- }
- while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
-
- return 0;
-}
-
-typedef enum
-{
- DUMMY_ERROR, /* unexpected end of input stream */
- DUMMY_LIT,
- DUMMY_MATCH,
- DUMMY_REP
-} ELzmaDummy;
-
-static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)
-{
- UInt32 range = p->range;
- UInt32 code = p->code;
- const Byte *bufLimit = buf + inSize;
- const CLzmaProb *probs = GET_PROBS;
- unsigned state = (unsigned)p->state;
- ELzmaDummy res;
-
- {
- const CLzmaProb *prob;
- UInt32 bound;
- unsigned ttt;
- unsigned posState = CALC_POS_STATE(p->processedPos, (1 << p->prop.pb) - 1);
-
- prob = probs + IsMatch + COMBINED_PS_STATE;
- IF_BIT_0_CHECK(prob)
- {
- UPDATE_0_CHECK
-
- /* if (bufLimit - buf >= 7) return DUMMY_LIT; */
-
- prob = probs + Literal;
- if (p->checkDicSize != 0 || p->processedPos != 0)
- prob += ((UInt32)LZMA_LIT_SIZE *
- ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +
- (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
-
- if (state < kNumLitStates)
- {
- unsigned symbol = 1;
- do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
- }
- else
- {
- unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
- (p->dicPos < p->reps[0] ? p->dicBufSize : 0)];
- unsigned offs = 0x100;
- unsigned symbol = 1;
- do
- {
- unsigned bit;
- const CLzmaProb *probLit;
- matchByte += matchByte;
- bit = offs;
- offs &= matchByte;
- probLit = prob + (offs + bit + symbol);
- GET_BIT2_CHECK(probLit, symbol, offs ^= bit; , ; )
- }
- while (symbol < 0x100);
- }
- res = DUMMY_LIT;
- }
- else
- {
- unsigned len;
- UPDATE_1_CHECK;
-
- prob = probs + IsRep + state;
- IF_BIT_0_CHECK(prob)
- {
- UPDATE_0_CHECK;
- state = 0;
- prob = probs + LenCoder;
- res = DUMMY_MATCH;
- }
- else
- {
- UPDATE_1_CHECK;
- res = DUMMY_REP;
- prob = probs + IsRepG0 + state;
- IF_BIT_0_CHECK(prob)
- {
- UPDATE_0_CHECK;
- prob = probs + IsRep0Long + COMBINED_PS_STATE;
- IF_BIT_0_CHECK(prob)
- {
- UPDATE_0_CHECK;
- NORMALIZE_CHECK;
- return DUMMY_REP;
- }
- else
- {
- UPDATE_1_CHECK;
- }
- }
- else
- {
- UPDATE_1_CHECK;
- prob = probs + IsRepG1 + state;
- IF_BIT_0_CHECK(prob)
- {
- UPDATE_0_CHECK;
- }
- else
- {
- UPDATE_1_CHECK;
- prob = probs + IsRepG2 + state;
- IF_BIT_0_CHECK(prob)
- {
- UPDATE_0_CHECK;
- }
- else
- {
- UPDATE_1_CHECK;
- }
- }
- }
- state = kNumStates;
- prob = probs + RepLenCoder;
- }
- {
- unsigned limit, offset;
- const CLzmaProb *probLen = prob + LenChoice;
- IF_BIT_0_CHECK(probLen)
- {
- UPDATE_0_CHECK;
- probLen = prob + LenLow + GET_LEN_STATE;
- offset = 0;
- limit = 1 << kLenNumLowBits;
- }
- else
- {
- UPDATE_1_CHECK;
- probLen = prob + LenChoice2;
- IF_BIT_0_CHECK(probLen)
- {
- UPDATE_0_CHECK;
- probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits);
- offset = kLenNumLowSymbols;
- limit = 1 << kLenNumLowBits;
- }
- else
- {
- UPDATE_1_CHECK;
- probLen = prob + LenHigh;
- offset = kLenNumLowSymbols * 2;
- limit = 1 << kLenNumHighBits;
- }
- }
- TREE_DECODE_CHECK(probLen, limit, len);
- len += offset;
- }
-
- if (state < 4)
- {
- unsigned posSlot;
- prob = probs + PosSlot +
- ((len < kNumLenToPosStates - 1 ? len : kNumLenToPosStates - 1) <<
- kNumPosSlotBits);
- TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
- if (posSlot >= kStartPosModelIndex)
- {
- unsigned numDirectBits = ((posSlot >> 1) - 1);
-
- /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
-
- if (posSlot < kEndPosModelIndex)
- {
- prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits);
- }
- else
- {
- numDirectBits -= kNumAlignBits;
- do
- {
- NORMALIZE_CHECK
- range >>= 1;
- code -= range & (((code - range) >> 31) - 1);
- /* if (code >= range) code -= range; */
- }
- while (--numDirectBits);
- prob = probs + Align;
- numDirectBits = kNumAlignBits;
- }
- {
- unsigned i = 1;
- unsigned m = 1;
- do
- {
- REV_BIT_CHECK(prob, i, m);
- }
- while (--numDirectBits);
- }
- }
- }
- }
- }
- NORMALIZE_CHECK;
- return res;
-}
-
-
-void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState)
-{
- p->remainLen = kMatchSpecLenStart + 1;
- p->tempBufSize = 0;
-
- if (initDic)
- {
- p->processedPos = 0;
- p->checkDicSize = 0;
- p->remainLen = kMatchSpecLenStart + 2;
- }
- if (initState)
- p->remainLen = kMatchSpecLenStart + 2;
-}
-
-void LzmaDec_Init(CLzmaDec *p)
-{
- p->dicPos = 0;
- LzmaDec_InitDicAndState(p, True, True);
-}
-
-
-SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
- ELzmaFinishMode finishMode, ELzmaStatus *status)
-{
- SizeT inSize = *srcLen;
- (*srcLen) = 0;
-
- *status = LZMA_STATUS_NOT_SPECIFIED;
-
- if (p->remainLen > kMatchSpecLenStart)
- {
- for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
- p->tempBuf[p->tempBufSize++] = *src++;
- if (p->tempBufSize != 0 && p->tempBuf[0] != 0)
- return SZ_ERROR_DATA;
- if (p->tempBufSize < RC_INIT_SIZE)
- {
- *status = LZMA_STATUS_NEEDS_MORE_INPUT;
- return SZ_OK;
- }
- p->code =
- ((UInt32)p->tempBuf[1] << 24)
- | ((UInt32)p->tempBuf[2] << 16)
- | ((UInt32)p->tempBuf[3] << 8)
- | ((UInt32)p->tempBuf[4]);
- p->range = 0xFFFFFFFF;
- p->tempBufSize = 0;
-
- if (p->remainLen > kMatchSpecLenStart + 1)
- {
- SizeT numProbs = LzmaProps_GetNumProbs(&p->prop);
- SizeT i;
- CLzmaProb *probs = p->probs;
- for (i = 0; i < numProbs; i++)
- probs[i] = kBitModelTotal >> 1;
- p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
- p->state = 0;
- }
-
- p->remainLen = 0;
- }
-
- LzmaDec_WriteRem(p, dicLimit);
-
- while (p->remainLen != kMatchSpecLenStart)
- {
- int checkEndMarkNow = 0;
-
- if (p->dicPos >= dicLimit)
- {
- if (p->remainLen == 0 && p->code == 0)
- {
- *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
- return SZ_OK;
- }
- if (finishMode == LZMA_FINISH_ANY)
- {
- *status = LZMA_STATUS_NOT_FINISHED;
- return SZ_OK;
- }
- if (p->remainLen != 0)
- {
- *status = LZMA_STATUS_NOT_FINISHED;
- return SZ_ERROR_DATA;
- }
- checkEndMarkNow = 1;
- }
-
- if (p->tempBufSize == 0)
- {
- SizeT processed;
- const Byte *bufLimit;
- if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
- {
- int dummyRes = LzmaDec_TryDummy(p, src, inSize);
- if (dummyRes == DUMMY_ERROR)
- {
- memcpy(p->tempBuf, src, inSize);
- p->tempBufSize = (unsigned)inSize;
- (*srcLen) += inSize;
- *status = LZMA_STATUS_NEEDS_MORE_INPUT;
- return SZ_OK;
- }
- if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
- {
- *status = LZMA_STATUS_NOT_FINISHED;
- return SZ_ERROR_DATA;
- }
- bufLimit = src;
- }
- else
- bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
- p->buf = src;
- if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)
- return SZ_ERROR_DATA;
- processed = (SizeT)(p->buf - src);
- (*srcLen) += processed;
- src += processed;
- inSize -= processed;
- }
- else
- {
- unsigned rem = p->tempBufSize, lookAhead = 0;
- while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)
- p->tempBuf[rem++] = src[lookAhead++];
- p->tempBufSize = rem;
- if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
- {
- int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, (SizeT)rem);
- if (dummyRes == DUMMY_ERROR)
- {
- (*srcLen) += (SizeT)lookAhead;
- *status = LZMA_STATUS_NEEDS_MORE_INPUT;
- return SZ_OK;
- }
- if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
- {
- *status = LZMA_STATUS_NOT_FINISHED;
- return SZ_ERROR_DATA;
- }
- }
- p->buf = p->tempBuf;
- if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
- return SZ_ERROR_DATA;
-
- {
- unsigned kkk = (unsigned)(p->buf - p->tempBuf);
- if (rem < kkk)
- return SZ_ERROR_FAIL; /* some internal error */
- rem -= kkk;
- if (lookAhead < rem)
- return SZ_ERROR_FAIL; /* some internal error */
- lookAhead -= rem;
- }
- (*srcLen) += (SizeT)lookAhead;
- src += lookAhead;
- inSize -= (SizeT)lookAhead;
- p->tempBufSize = 0;
- }
- }
-
- if (p->code != 0)
- return SZ_ERROR_DATA;
- *status = LZMA_STATUS_FINISHED_WITH_MARK;
- return SZ_OK;
-}
-
-
-SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
-{
- SizeT outSize = *destLen;
- SizeT inSize = *srcLen;
- *srcLen = *destLen = 0;
- for (;;)
- {
- SizeT inSizeCur = inSize, outSizeCur, dicPos;
- ELzmaFinishMode curFinishMode;
- SRes res;
- if (p->dicPos == p->dicBufSize)
- p->dicPos = 0;
- dicPos = p->dicPos;
- if (outSize > p->dicBufSize - dicPos)
- {
- outSizeCur = p->dicBufSize;
- curFinishMode = LZMA_FINISH_ANY;
- }
- else
- {
- outSizeCur = dicPos + outSize;
- curFinishMode = finishMode;
- }
-
- res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
- src += inSizeCur;
- inSize -= inSizeCur;
- *srcLen += inSizeCur;
- outSizeCur = p->dicPos - dicPos;
- memcpy(dest, p->dic + dicPos, outSizeCur);
- dest += outSizeCur;
- outSize -= outSizeCur;
- *destLen += outSizeCur;
- if (res != 0)
- return res;
- if (outSizeCur == 0 || outSize == 0)
- return SZ_OK;
- }
-}
-
-void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc)
-{
- ISzAlloc_Free(alloc, p->probs);
- p->probs = NULL;
-}
-
-static void LzmaDec_FreeDict(CLzmaDec *p, ISzAllocPtr alloc)
-{
- ISzAlloc_Free(alloc, p->dic);
- p->dic = NULL;
-}
-
-void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc)
-{
- LzmaDec_FreeProbs(p, alloc);
- LzmaDec_FreeDict(p, alloc);
-}
-
-SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
-{
- UInt32 dicSize;
- Byte d;
-
- if (size < LZMA_PROPS_SIZE)
- return SZ_ERROR_UNSUPPORTED;
- else
- dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
-
- if (dicSize < LZMA_DIC_MIN)
- dicSize = LZMA_DIC_MIN;
- p->dicSize = dicSize;
-
- d = data[0];
- if (d >= (9 * 5 * 5))
- return SZ_ERROR_UNSUPPORTED;
-
- p->lc = (Byte)(d % 9);
- d /= 9;
- p->pb = (Byte)(d / 5);
- p->lp = (Byte)(d % 5);
-
- return SZ_OK;
-}
-
-static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAllocPtr alloc)
-{
- UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
- if (!p->probs || numProbs != p->numProbs)
- {
- LzmaDec_FreeProbs(p, alloc);
- p->probs = (CLzmaProb *)ISzAlloc_Alloc(alloc, numProbs * sizeof(CLzmaProb));
- if (!p->probs)
- return SZ_ERROR_MEM;
- p->probs_1664 = p->probs + 1664;
- p->numProbs = numProbs;
- }
- return SZ_OK;
-}
-
-SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc)
-{
- CLzmaProps propNew;
- RINOK(LzmaProps_Decode(&propNew, props, propsSize));
- RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
- p->prop = propNew;
- return SZ_OK;
-}
-
-SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc)
-{
- CLzmaProps propNew;
- SizeT dicBufSize;
- RINOK(LzmaProps_Decode(&propNew, props, propsSize));
- RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
-
- {
- UInt32 dictSize = propNew.dicSize;
- SizeT mask = ((UInt32)1 << 12) - 1;
- if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1;
- else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1;;
- dicBufSize = ((SizeT)dictSize + mask) & ~mask;
- if (dicBufSize < dictSize)
- dicBufSize = dictSize;
- }
-
- if (!p->dic || dicBufSize != p->dicBufSize)
- {
- LzmaDec_FreeDict(p, alloc);
- p->dic = (Byte *)ISzAlloc_Alloc(alloc, dicBufSize);
- if (!p->dic)
- {
- LzmaDec_FreeProbs(p, alloc);
- return SZ_ERROR_MEM;
- }
- }
- p->dicBufSize = dicBufSize;
- p->prop = propNew;
- return SZ_OK;
-}
-
-SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
- const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
- ELzmaStatus *status, ISzAllocPtr alloc)
-{
- CLzmaDec p;
- SRes res;
- SizeT outSize = *destLen, inSize = *srcLen;
- *destLen = *srcLen = 0;
- *status = LZMA_STATUS_NOT_SPECIFIED;
- if (inSize < RC_INIT_SIZE)
- return SZ_ERROR_INPUT_EOF;
- LzmaDec_Construct(&p);
- RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc));
- p.dic = dest;
- p.dicBufSize = outSize;
- LzmaDec_Init(&p);
- *srcLen = inSize;
- res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
- *destLen = p.dicPos;
- if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
- res = SZ_ERROR_INPUT_EOF;
- LzmaDec_FreeProbs(&p, alloc);
- return res;
-}
+/* LzmaDec.c -- LZMA Decoder
+2023-04-07 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+/* #include "CpuArch.h" */
+#include "LzmaDec.h"
+
+// #define kNumTopBits 24
+#define kTopValue ((UInt32)1 << 24)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+
+#define RC_INIT_SIZE 5
+
+#ifndef Z7_LZMA_DEC_OPT
+
+#define kNumMoveBits 5
+#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound)
+#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
+#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
+#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
+ { UPDATE_0(p) i = (i + i); A0; } else \
+ { UPDATE_1(p) i = (i + i) + 1; A1; }
+
+#define TREE_GET_BIT(probs, i) { GET_BIT2(probs + i, i, ;, ;); }
+
+#define REV_BIT(p, i, A0, A1) IF_BIT_0(p + i) \
+ { UPDATE_0(p + i) A0; } else \
+ { UPDATE_1(p + i) A1; }
+#define REV_BIT_VAR( p, i, m) REV_BIT(p, i, i += m; m += m, m += m; i += m; )
+#define REV_BIT_CONST(p, i, m) REV_BIT(p, i, i += m; , i += m * 2; )
+#define REV_BIT_LAST( p, i, m) REV_BIT(p, i, i -= m , ; )
+
+#define TREE_DECODE(probs, limit, i) \
+ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
+
+/* #define Z7_LZMA_SIZE_OPT */
+
+#ifdef Z7_LZMA_SIZE_OPT
+#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
+#else
+#define TREE_6_DECODE(probs, i) \
+ { i = 1; \
+ TREE_GET_BIT(probs, i) \
+ TREE_GET_BIT(probs, i) \
+ TREE_GET_BIT(probs, i) \
+ TREE_GET_BIT(probs, i) \
+ TREE_GET_BIT(probs, i) \
+ TREE_GET_BIT(probs, i) \
+ i -= 0x40; }
+#endif
+
+#define NORMAL_LITER_DEC TREE_GET_BIT(prob, symbol)
+#define MATCHED_LITER_DEC \
+ matchByte += matchByte; \
+ bit = offs; \
+ offs &= matchByte; \
+ probLit = prob + (offs + bit + symbol); \
+ GET_BIT2(probLit, symbol, offs ^= bit; , ;)
+
+#endif // Z7_LZMA_DEC_OPT
+
+
+#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_INPUT_EOF; range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK bound = (range >> kNumBitModelTotalBits) * (UInt32)ttt; if (code < bound)
+#define UPDATE_0_CHECK range = bound;
+#define UPDATE_1_CHECK range -= bound; code -= bound;
+#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
+ { UPDATE_0_CHECK i = (i + i); A0; } else \
+ { UPDATE_1_CHECK i = (i + i) + 1; A1; }
+#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)
+#define TREE_DECODE_CHECK(probs, limit, i) \
+ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; }
+
+
+#define REV_BIT_CHECK(p, i, m) IF_BIT_0_CHECK(p + i) \
+ { UPDATE_0_CHECK i += m; m += m; } else \
+ { UPDATE_1_CHECK m += m; i += m; }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenLow 0
+#define LenHigh (LenLow + 2 * (kNumPosStatesMax << kLenNumLowBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+#define LenChoice LenLow
+#define LenChoice2 (LenLow + (1 << kLenNumLowBits))
+
+#define kNumStates 12
+#define kNumStates2 16
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols * 2 + kLenNumHighSymbols)
+
+#define kMatchSpecLen_Error_Data (1 << 9)
+#define kMatchSpecLen_Error_Fail (kMatchSpecLen_Error_Data - 1)
+
+/* External ASM code needs same CLzmaProb array layout. So don't change it. */
+
+/* (probs_1664) is faster and better for code size at some platforms */
+/*
+#ifdef MY_CPU_X86_OR_AMD64
+*/
+#define kStartOffset 1664
+#define GET_PROBS p->probs_1664
+/*
+#define GET_PROBS p->probs + kStartOffset
+#else
+#define kStartOffset 0
+#define GET_PROBS p->probs
+#endif
+*/
+
+#define SpecPos (-kStartOffset)
+#define IsRep0Long (SpecPos + kNumFullDistances)
+#define RepLenCoder (IsRep0Long + (kNumStates2 << kNumPosBitsMax))
+#define LenCoder (RepLenCoder + kNumLenProbs)
+#define IsMatch (LenCoder + kNumLenProbs)
+#define Align (IsMatch + (kNumStates2 << kNumPosBitsMax))
+#define IsRep (Align + kAlignTableSize)
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define PosSlot (IsRepG2 + kNumStates)
+#define Literal (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define NUM_BASE_PROBS (Literal + kStartOffset)
+
+#if Align != 0 && kStartOffset != 0
+ #error Stop_Compiling_Bad_LZMA_kAlign
+#endif
+
+#if NUM_BASE_PROBS != 1984
+ #error Stop_Compiling_Bad_LZMA_PROBS
+#endif
+
+
+#define LZMA_LIT_SIZE 0x300
+
+#define LzmaProps_GetNumProbs(p) (NUM_BASE_PROBS + ((UInt32)LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
+
+
+#define CALC_POS_STATE(processedPos, pbMask) (((processedPos) & (pbMask)) << 4)
+#define COMBINED_PS_STATE (posState + state)
+#define GET_LEN_STATE (posState)
+
+#define LZMA_DIC_MIN (1 << 12)
+
+/*
+p->remainLen : shows status of LZMA decoder:
+ < kMatchSpecLenStart : the number of bytes to be copied with (p->rep0) offset
+ = kMatchSpecLenStart : the LZMA stream was finished with end mark
+ = kMatchSpecLenStart + 1 : need init range coder
+ = kMatchSpecLenStart + 2 : need init range coder and state
+ = kMatchSpecLen_Error_Fail : Internal Code Failure
+ = kMatchSpecLen_Error_Data + [0 ... 273] : LZMA Data Error
+*/
+
+/* ---------- LZMA_DECODE_REAL ---------- */
+/*
+LzmaDec_DecodeReal_3() can be implemented in external ASM file.
+3 - is the code compatibility version of that function for check at link time.
+*/
+
+#define LZMA_DECODE_REAL LzmaDec_DecodeReal_3
+
+/*
+LZMA_DECODE_REAL()
+In:
+ RangeCoder is normalized
+ if (p->dicPos == limit)
+ {
+ LzmaDec_TryDummy() was called before to exclude LITERAL and MATCH-REP cases.
+ So first symbol can be only MATCH-NON-REP. And if that MATCH-NON-REP symbol
+ is not END_OF_PAYALOAD_MARKER, then the function doesn't write any byte to dictionary,
+ the function returns SZ_OK, and the caller can use (p->remainLen) and (p->reps[0]) later.
+ }
+
+Processing:
+ The first LZMA symbol will be decoded in any case.
+ All main checks for limits are at the end of main loop,
+ It decodes additional LZMA-symbols while (p->buf < bufLimit && dicPos < limit),
+ RangeCoder is still without last normalization when (p->buf < bufLimit) is being checked.
+ But if (p->buf < bufLimit), the caller provided at least (LZMA_REQUIRED_INPUT_MAX + 1) bytes for
+ next iteration before limit (bufLimit + LZMA_REQUIRED_INPUT_MAX),
+ that is enough for worst case LZMA symbol with one additional RangeCoder normalization for one bit.
+ So that function never reads bufLimit [LZMA_REQUIRED_INPUT_MAX] byte.
+
+Out:
+ RangeCoder is normalized
+ Result:
+ SZ_OK - OK
+ p->remainLen:
+ < kMatchSpecLenStart : the number of bytes to be copied with (p->reps[0]) offset
+ = kMatchSpecLenStart : the LZMA stream was finished with end mark
+
+ SZ_ERROR_DATA - error, when the MATCH-Symbol refers out of dictionary
+ p->remainLen : undefined
+ p->reps[*] : undefined
+*/
+
+
+#ifdef Z7_LZMA_DEC_OPT
+
+int Z7_FASTCALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit);
+
+#else
+
+static
+int Z7_FASTCALL LZMA_DECODE_REAL(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ CLzmaProb *probs = GET_PROBS;
+ unsigned state = (unsigned)p->state;
+ UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
+ unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
+ unsigned lc = p->prop.lc;
+ unsigned lpMask = ((unsigned)0x100 << p->prop.lp) - ((unsigned)0x100 >> lc);
+
+ Byte *dic = p->dic;
+ SizeT dicBufSize = p->dicBufSize;
+ SizeT dicPos = p->dicPos;
+
+ UInt32 processedPos = p->processedPos;
+ UInt32 checkDicSize = p->checkDicSize;
+ unsigned len = 0;
+
+ const Byte *buf = p->buf;
+ UInt32 range = p->range;
+ UInt32 code = p->code;
+
+ do
+ {
+ CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = CALC_POS_STATE(processedPos, pbMask);
+
+ prob = probs + IsMatch + COMBINED_PS_STATE;
+ IF_BIT_0(prob)
+ {
+ unsigned symbol;
+ UPDATE_0(prob)
+ prob = probs + Literal;
+ if (processedPos != 0 || checkDicSize != 0)
+ prob += (UInt32)3 * ((((processedPos << 8) + dic[(dicPos == 0 ? dicBufSize : dicPos) - 1]) & lpMask) << lc);
+ processedPos++;
+
+ if (state < kNumLitStates)
+ {
+ state -= (state < 4) ? state : 3;
+ symbol = 1;
+ #ifdef Z7_LZMA_SIZE_OPT
+ do { NORMAL_LITER_DEC } while (symbol < 0x100);
+ #else
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ NORMAL_LITER_DEC
+ #endif
+ }
+ else
+ {
+ unsigned matchByte = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+ unsigned offs = 0x100;
+ state -= (state < 10) ? 3 : 6;
+ symbol = 1;
+ #ifdef Z7_LZMA_SIZE_OPT
+ do
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ MATCHED_LITER_DEC
+ }
+ while (symbol < 0x100);
+ #else
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ MATCHED_LITER_DEC
+ }
+ #endif
+ }
+
+ dic[dicPos++] = (Byte)symbol;
+ continue;
+ }
+
+ {
+ UPDATE_1(prob)
+ prob = probs + IsRep + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob)
+ state += kNumStates;
+ prob = probs + LenCoder;
+ }
+ else
+ {
+ UPDATE_1(prob)
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob)
+ prob = probs + IsRep0Long + COMBINED_PS_STATE;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob)
+
+ // that case was checked before with kBadRepCode
+ // if (checkDicSize == 0 && processedPos == 0) { len = kMatchSpecLen_Error_Data + 1; break; }
+ // The caller doesn't allow (dicPos == limit) case here
+ // so we don't need the following check:
+ // if (dicPos == limit) { state = state < kNumLitStates ? 9 : 11; len = 1; break; }
+
+ dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+ dicPos++;
+ processedPos++;
+ state = state < kNumLitStates ? 9 : 11;
+ continue;
+ }
+ UPDATE_1(prob)
+ }
+ else
+ {
+ UInt32 distance;
+ UPDATE_1(prob)
+ prob = probs + IsRepG1 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob)
+ distance = rep1;
+ }
+ else
+ {
+ UPDATE_1(prob)
+ prob = probs + IsRepG2 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob)
+ distance = rep2;
+ }
+ else
+ {
+ UPDATE_1(prob)
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ state = state < kNumLitStates ? 8 : 11;
+ prob = probs + RepLenCoder;
+ }
+
+ #ifdef Z7_LZMA_SIZE_OPT
+ {
+ unsigned lim, offset;
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen)
+ probLen = prob + LenLow + GET_LEN_STATE;
+ offset = 0;
+ lim = (1 << kLenNumLowBits);
+ }
+ else
+ {
+ UPDATE_1(probLen)
+ probLen = prob + LenChoice2;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen)
+ probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits);
+ offset = kLenNumLowSymbols;
+ lim = (1 << kLenNumLowBits);
+ }
+ else
+ {
+ UPDATE_1(probLen)
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols * 2;
+ lim = (1 << kLenNumHighBits);
+ }
+ }
+ TREE_DECODE(probLen, lim, len)
+ len += offset;
+ }
+ #else
+ {
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen)
+ probLen = prob + LenLow + GET_LEN_STATE;
+ len = 1;
+ TREE_GET_BIT(probLen, len)
+ TREE_GET_BIT(probLen, len)
+ TREE_GET_BIT(probLen, len)
+ len -= 8;
+ }
+ else
+ {
+ UPDATE_1(probLen)
+ probLen = prob + LenChoice2;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen)
+ probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits);
+ len = 1;
+ TREE_GET_BIT(probLen, len)
+ TREE_GET_BIT(probLen, len)
+ TREE_GET_BIT(probLen, len)
+ }
+ else
+ {
+ UPDATE_1(probLen)
+ probLen = prob + LenHigh;
+ TREE_DECODE(probLen, (1 << kLenNumHighBits), len)
+ len += kLenNumLowSymbols * 2;
+ }
+ }
+ }
+ #endif
+
+ if (state >= kNumStates)
+ {
+ UInt32 distance;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
+ TREE_6_DECODE(prob, distance)
+ if (distance >= kStartPosModelIndex)
+ {
+ unsigned posSlot = (unsigned)distance;
+ unsigned numDirectBits = (unsigned)(((distance >> 1) - 1));
+ distance = (2 | (distance & 1));
+ if (posSlot < kEndPosModelIndex)
+ {
+ distance <<= numDirectBits;
+ prob = probs + SpecPos;
+ {
+ UInt32 m = 1;
+ distance++;
+ do
+ {
+ REV_BIT_VAR(prob, distance, m)
+ }
+ while (--numDirectBits);
+ distance -= m;
+ }
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE
+ range >>= 1;
+
+ {
+ UInt32 t;
+ code -= range;
+ t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
+ distance = (distance << 1) + (t + 1);
+ code += range & t;
+ }
+ /*
+ distance <<= 1;
+ if (code >= range)
+ {
+ code -= range;
+ distance |= 1;
+ }
+ */
+ }
+ while (--numDirectBits);
+ prob = probs + Align;
+ distance <<= kNumAlignBits;
+ {
+ unsigned i = 1;
+ REV_BIT_CONST(prob, i, 1)
+ REV_BIT_CONST(prob, i, 2)
+ REV_BIT_CONST(prob, i, 4)
+ REV_BIT_LAST (prob, i, 8)
+ distance |= i;
+ }
+ if (distance == (UInt32)0xFFFFFFFF)
+ {
+ len = kMatchSpecLenStart;
+ state -= kNumStates;
+ break;
+ }
+ }
+ }
+
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ rep0 = distance + 1;
+ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
+ if (distance >= (checkDicSize == 0 ? processedPos: checkDicSize))
+ {
+ len += kMatchSpecLen_Error_Data + kMatchMinLen;
+ // len = kMatchSpecLen_Error_Data;
+ // len += kMatchMinLen;
+ break;
+ }
+ }
+
+ len += kMatchMinLen;
+
+ {
+ SizeT rem;
+ unsigned curLen;
+ SizeT pos;
+
+ if ((rem = limit - dicPos) == 0)
+ {
+ /*
+ We stop decoding and return SZ_OK, and we can resume decoding later.
+ Any error conditions can be tested later in caller code.
+ For more strict mode we can stop decoding with error
+ // len += kMatchSpecLen_Error_Data;
+ */
+ break;
+ }
+
+ curLen = ((rem < len) ? (unsigned)rem : len);
+ pos = dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0);
+
+ processedPos += (UInt32)curLen;
+
+ len -= curLen;
+ if (curLen <= dicBufSize - pos)
+ {
+ Byte *dest = dic + dicPos;
+ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
+ const Byte *lim = dest + curLen;
+ dicPos += (SizeT)curLen;
+ do
+ *(dest) = (Byte)*(dest + src);
+ while (++dest != lim);
+ }
+ else
+ {
+ do
+ {
+ dic[dicPos++] = dic[pos];
+ if (++pos == dicBufSize)
+ pos = 0;
+ }
+ while (--curLen != 0);
+ }
+ }
+ }
+ }
+ while (dicPos < limit && buf < bufLimit);
+
+ NORMALIZE
+
+ p->buf = buf;
+ p->range = range;
+ p->code = code;
+ p->remainLen = (UInt32)len; // & (kMatchSpecLen_Error_Data - 1); // we can write real length for error matches too.
+ p->dicPos = dicPos;
+ p->processedPos = processedPos;
+ p->reps[0] = rep0;
+ p->reps[1] = rep1;
+ p->reps[2] = rep2;
+ p->reps[3] = rep3;
+ p->state = (UInt32)state;
+ if (len >= kMatchSpecLen_Error_Data)
+ return SZ_ERROR_DATA;
+ return SZ_OK;
+}
+#endif
+
+
+
+static void Z7_FASTCALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
+{
+ unsigned len = (unsigned)p->remainLen;
+ if (len == 0 /* || len >= kMatchSpecLenStart */)
+ return;
+ {
+ SizeT dicPos = p->dicPos;
+ Byte *dic;
+ SizeT dicBufSize;
+ SizeT rep0; /* we use SizeT to avoid the BUG of VC14 for AMD64 */
+ {
+ SizeT rem = limit - dicPos;
+ if (rem < len)
+ {
+ len = (unsigned)(rem);
+ if (len == 0)
+ return;
+ }
+ }
+
+ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
+ p->checkDicSize = p->prop.dicSize;
+
+ p->processedPos += (UInt32)len;
+ p->remainLen -= (UInt32)len;
+ dic = p->dic;
+ rep0 = p->reps[0];
+ dicBufSize = p->dicBufSize;
+ do
+ {
+ dic[dicPos] = dic[dicPos - rep0 + (dicPos < rep0 ? dicBufSize : 0)];
+ dicPos++;
+ }
+ while (--len);
+ p->dicPos = dicPos;
+ }
+}
+
+
+/*
+At staring of new stream we have one of the following symbols:
+ - Literal - is allowed
+ - Non-Rep-Match - is allowed only if it's end marker symbol
+ - Rep-Match - is not allowed
+We use early check of (RangeCoder:Code) over kBadRepCode to simplify main decoding code
+*/
+
+#define kRange0 0xFFFFFFFF
+#define kBound0 ((kRange0 >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1))
+#define kBadRepCode (kBound0 + (((kRange0 - kBound0) >> kNumBitModelTotalBits) << (kNumBitModelTotalBits - 1)))
+#if kBadRepCode != (0xC0000000 - 0x400)
+ #error Stop_Compiling_Bad_LZMA_Check
+#endif
+
+
+/*
+LzmaDec_DecodeReal2():
+ It calls LZMA_DECODE_REAL() and it adjusts limit according (p->checkDicSize).
+
+We correct (p->checkDicSize) after LZMA_DECODE_REAL() and in LzmaDec_WriteRem(),
+and we support the following state of (p->checkDicSize):
+ if (total_processed < p->prop.dicSize) then
+ {
+ (total_processed == p->processedPos)
+ (p->checkDicSize == 0)
+ }
+ else
+ (p->checkDicSize == p->prop.dicSize)
+*/
+
+static int Z7_FASTCALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ if (p->checkDicSize == 0)
+ {
+ UInt32 rem = p->prop.dicSize - p->processedPos;
+ if (limit - p->dicPos > rem)
+ limit = p->dicPos + rem;
+ }
+ {
+ int res = LZMA_DECODE_REAL(p, limit, bufLimit);
+ if (p->checkDicSize == 0 && p->processedPos >= p->prop.dicSize)
+ p->checkDicSize = p->prop.dicSize;
+ return res;
+ }
+}
+
+
+
+typedef enum
+{
+ DUMMY_INPUT_EOF, /* need more input data */
+ DUMMY_LIT,
+ DUMMY_MATCH,
+ DUMMY_REP
+} ELzmaDummy;
+
+
+#define IS_DUMMY_END_MARKER_POSSIBLE(dummyRes) ((dummyRes) == DUMMY_MATCH)
+
+static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, const Byte **bufOut)
+{
+ UInt32 range = p->range;
+ UInt32 code = p->code;
+ const Byte *bufLimit = *bufOut;
+ const CLzmaProb *probs = GET_PROBS;
+ unsigned state = (unsigned)p->state;
+ ELzmaDummy res;
+
+ for (;;)
+ {
+ const CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = CALC_POS_STATE(p->processedPos, ((unsigned)1 << p->prop.pb) - 1);
+
+ prob = probs + IsMatch + COMBINED_PS_STATE;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK
+
+ prob = probs + Literal;
+ if (p->checkDicSize != 0 || p->processedPos != 0)
+ prob += ((UInt32)LZMA_LIT_SIZE *
+ ((((p->processedPos) & (((unsigned)1 << (p->prop.lp)) - 1)) << p->prop.lc) +
+ ((unsigned)p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
+
+ if (state < kNumLitStates)
+ {
+ unsigned symbol = 1;
+ do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
+ }
+ else
+ {
+ unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
+ (p->dicPos < p->reps[0] ? p->dicBufSize : 0)];
+ unsigned offs = 0x100;
+ unsigned symbol = 1;
+ do
+ {
+ unsigned bit;
+ const CLzmaProb *probLit;
+ matchByte += matchByte;
+ bit = offs;
+ offs &= matchByte;
+ probLit = prob + (offs + bit + symbol);
+ GET_BIT2_CHECK(probLit, symbol, offs ^= bit; , ; )
+ }
+ while (symbol < 0x100);
+ }
+ res = DUMMY_LIT;
+ }
+ else
+ {
+ unsigned len;
+ UPDATE_1_CHECK
+
+ prob = probs + IsRep + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK
+ state = 0;
+ prob = probs + LenCoder;
+ res = DUMMY_MATCH;
+ }
+ else
+ {
+ UPDATE_1_CHECK
+ res = DUMMY_REP;
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK
+ prob = probs + IsRep0Long + COMBINED_PS_STATE;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK
+ break;
+ }
+ else
+ {
+ UPDATE_1_CHECK
+ }
+ }
+ else
+ {
+ UPDATE_1_CHECK
+ prob = probs + IsRepG1 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK
+ }
+ else
+ {
+ UPDATE_1_CHECK
+ prob = probs + IsRepG2 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK
+ }
+ else
+ {
+ UPDATE_1_CHECK
+ }
+ }
+ }
+ state = kNumStates;
+ prob = probs + RepLenCoder;
+ }
+ {
+ unsigned limit, offset;
+ const CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK
+ probLen = prob + LenLow + GET_LEN_STATE;
+ offset = 0;
+ limit = 1 << kLenNumLowBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK
+ probLen = prob + LenChoice2;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK
+ probLen = prob + LenLow + GET_LEN_STATE + (1 << kLenNumLowBits);
+ offset = kLenNumLowSymbols;
+ limit = 1 << kLenNumLowBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols * 2;
+ limit = 1 << kLenNumHighBits;
+ }
+ }
+ TREE_DECODE_CHECK(probLen, limit, len)
+ len += offset;
+ }
+
+ if (state < 4)
+ {
+ unsigned posSlot;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates - 1 ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits);
+ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot)
+ if (posSlot >= kStartPosModelIndex)
+ {
+ unsigned numDirectBits = ((posSlot >> 1) - 1);
+
+ if (posSlot < kEndPosModelIndex)
+ {
+ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits);
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE_CHECK
+ range >>= 1;
+ code -= range & (((code - range) >> 31) - 1);
+ /* if (code >= range) code -= range; */
+ }
+ while (--numDirectBits);
+ prob = probs + Align;
+ numDirectBits = kNumAlignBits;
+ }
+ {
+ unsigned i = 1;
+ unsigned m = 1;
+ do
+ {
+ REV_BIT_CHECK(prob, i, m)
+ }
+ while (--numDirectBits);
+ }
+ }
+ }
+ }
+ break;
+ }
+ NORMALIZE_CHECK
+
+ *bufOut = buf;
+ return res;
+}
+
+void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState);
+void LzmaDec_InitDicAndState(CLzmaDec *p, BoolInt initDic, BoolInt initState)
+{
+ p->remainLen = kMatchSpecLenStart + 1;
+ p->tempBufSize = 0;
+
+ if (initDic)
+ {
+ p->processedPos = 0;
+ p->checkDicSize = 0;
+ p->remainLen = kMatchSpecLenStart + 2;
+ }
+ if (initState)
+ p->remainLen = kMatchSpecLenStart + 2;
+}
+
+void LzmaDec_Init(CLzmaDec *p)
+{
+ p->dicPos = 0;
+ LzmaDec_InitDicAndState(p, True, True);
+}
+
+
+/*
+LZMA supports optional end_marker.
+So the decoder can lookahead for one additional LZMA-Symbol to check end_marker.
+That additional LZMA-Symbol can require up to LZMA_REQUIRED_INPUT_MAX bytes in input stream.
+When the decoder reaches dicLimit, it looks (finishMode) parameter:
+ if (finishMode == LZMA_FINISH_ANY), the decoder doesn't lookahead
+ if (finishMode != LZMA_FINISH_ANY), the decoder lookahead, if end_marker is possible for current position
+
+When the decoder lookahead, and the lookahead symbol is not end_marker, we have two ways:
+ 1) Strict mode (default) : the decoder returns SZ_ERROR_DATA.
+ 2) The relaxed mode (alternative mode) : we could return SZ_OK, and the caller
+ must check (status) value. The caller can show the error,
+ if the end of stream is expected, and the (status) is noit
+ LZMA_STATUS_FINISHED_WITH_MARK or LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK.
+*/
+
+
+#define RETURN_NOT_FINISHED_FOR_FINISH \
+ *status = LZMA_STATUS_NOT_FINISHED; \
+ return SZ_ERROR_DATA; // for strict mode
+ // return SZ_OK; // for relaxed mode
+
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
+ ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT inSize = *srcLen;
+ (*srcLen) = 0;
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+
+ if (p->remainLen > kMatchSpecLenStart)
+ {
+ if (p->remainLen > kMatchSpecLenStart + 2)
+ return p->remainLen == kMatchSpecLen_Error_Fail ? SZ_ERROR_FAIL : SZ_ERROR_DATA;
+
+ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
+ p->tempBuf[p->tempBufSize++] = *src++;
+ if (p->tempBufSize != 0 && p->tempBuf[0] != 0)
+ return SZ_ERROR_DATA;
+ if (p->tempBufSize < RC_INIT_SIZE)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ p->code =
+ ((UInt32)p->tempBuf[1] << 24)
+ | ((UInt32)p->tempBuf[2] << 16)
+ | ((UInt32)p->tempBuf[3] << 8)
+ | ((UInt32)p->tempBuf[4]);
+
+ if (p->checkDicSize == 0
+ && p->processedPos == 0
+ && p->code >= kBadRepCode)
+ return SZ_ERROR_DATA;
+
+ p->range = 0xFFFFFFFF;
+ p->tempBufSize = 0;
+
+ if (p->remainLen > kMatchSpecLenStart + 1)
+ {
+ SizeT numProbs = LzmaProps_GetNumProbs(&p->prop);
+ SizeT i;
+ CLzmaProb *probs = p->probs;
+ for (i = 0; i < numProbs; i++)
+ probs[i] = kBitModelTotal >> 1;
+ p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
+ p->state = 0;
+ }
+
+ p->remainLen = 0;
+ }
+
+ for (;;)
+ {
+ if (p->remainLen == kMatchSpecLenStart)
+ {
+ if (p->code != 0)
+ return SZ_ERROR_DATA;
+ *status = LZMA_STATUS_FINISHED_WITH_MARK;
+ return SZ_OK;
+ }
+
+ LzmaDec_WriteRem(p, dicLimit);
+
+ {
+ // (p->remainLen == 0 || p->dicPos == dicLimit)
+
+ int checkEndMarkNow = 0;
+
+ if (p->dicPos >= dicLimit)
+ {
+ if (p->remainLen == 0 && p->code == 0)
+ {
+ *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
+ return SZ_OK;
+ }
+ if (finishMode == LZMA_FINISH_ANY)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_OK;
+ }
+ if (p->remainLen != 0)
+ {
+ RETURN_NOT_FINISHED_FOR_FINISH
+ }
+ checkEndMarkNow = 1;
+ }
+
+ // (p->remainLen == 0)
+
+ if (p->tempBufSize == 0)
+ {
+ const Byte *bufLimit;
+ int dummyProcessed = -1;
+
+ if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+ {
+ const Byte *bufOut = src + inSize;
+
+ ELzmaDummy dummyRes = LzmaDec_TryDummy(p, src, &bufOut);
+
+ if (dummyRes == DUMMY_INPUT_EOF)
+ {
+ size_t i;
+ if (inSize >= LZMA_REQUIRED_INPUT_MAX)
+ break;
+ (*srcLen) += inSize;
+ p->tempBufSize = (unsigned)inSize;
+ for (i = 0; i < inSize; i++)
+ p->tempBuf[i] = src[i];
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+
+ dummyProcessed = (int)(bufOut - src);
+ if ((unsigned)dummyProcessed > LZMA_REQUIRED_INPUT_MAX)
+ break;
+
+ if (checkEndMarkNow && !IS_DUMMY_END_MARKER_POSSIBLE(dummyRes))
+ {
+ unsigned i;
+ (*srcLen) += (unsigned)dummyProcessed;
+ p->tempBufSize = (unsigned)dummyProcessed;
+ for (i = 0; i < (unsigned)dummyProcessed; i++)
+ p->tempBuf[i] = src[i];
+ // p->remainLen = kMatchSpecLen_Error_Data;
+ RETURN_NOT_FINISHED_FOR_FINISH
+ }
+
+ bufLimit = src;
+ // we will decode only one iteration
+ }
+ else
+ bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
+
+ p->buf = src;
+
+ {
+ int res = LzmaDec_DecodeReal2(p, dicLimit, bufLimit);
+
+ SizeT processed = (SizeT)(p->buf - src);
+
+ if (dummyProcessed < 0)
+ {
+ if (processed > inSize)
+ break;
+ }
+ else if ((unsigned)dummyProcessed != processed)
+ break;
+
+ src += processed;
+ inSize -= processed;
+ (*srcLen) += processed;
+
+ if (res != SZ_OK)
+ {
+ p->remainLen = kMatchSpecLen_Error_Data;
+ return SZ_ERROR_DATA;
+ }
+ }
+ continue;
+ }
+
+ {
+ // we have some data in (p->tempBuf)
+ // in strict mode: tempBufSize is not enough for one Symbol decoding.
+ // in relaxed mode: tempBufSize not larger than required for one Symbol decoding.
+
+ unsigned rem = p->tempBufSize;
+ unsigned ahead = 0;
+ int dummyProcessed = -1;
+
+ while (rem < LZMA_REQUIRED_INPUT_MAX && ahead < inSize)
+ p->tempBuf[rem++] = src[ahead++];
+
+ // ahead - the size of new data copied from (src) to (p->tempBuf)
+ // rem - the size of temp buffer including new data from (src)
+
+ if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+ {
+ const Byte *bufOut = p->tempBuf + rem;
+
+ ELzmaDummy dummyRes = LzmaDec_TryDummy(p, p->tempBuf, &bufOut);
+
+ if (dummyRes == DUMMY_INPUT_EOF)
+ {
+ if (rem >= LZMA_REQUIRED_INPUT_MAX)
+ break;
+ p->tempBufSize = rem;
+ (*srcLen) += (SizeT)ahead;
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+
+ dummyProcessed = (int)(bufOut - p->tempBuf);
+
+ if ((unsigned)dummyProcessed < p->tempBufSize)
+ break;
+
+ if (checkEndMarkNow && !IS_DUMMY_END_MARKER_POSSIBLE(dummyRes))
+ {
+ (*srcLen) += (unsigned)dummyProcessed - p->tempBufSize;
+ p->tempBufSize = (unsigned)dummyProcessed;
+ // p->remainLen = kMatchSpecLen_Error_Data;
+ RETURN_NOT_FINISHED_FOR_FINISH
+ }
+ }
+
+ p->buf = p->tempBuf;
+
+ {
+ // we decode one symbol from (p->tempBuf) here, so the (bufLimit) is equal to (p->buf)
+ int res = LzmaDec_DecodeReal2(p, dicLimit, p->buf);
+
+ SizeT processed = (SizeT)(p->buf - p->tempBuf);
+ rem = p->tempBufSize;
+
+ if (dummyProcessed < 0)
+ {
+ if (processed > LZMA_REQUIRED_INPUT_MAX)
+ break;
+ if (processed < rem)
+ break;
+ }
+ else if ((unsigned)dummyProcessed != processed)
+ break;
+
+ processed -= rem;
+
+ src += processed;
+ inSize -= processed;
+ (*srcLen) += processed;
+ p->tempBufSize = 0;
+
+ if (res != SZ_OK)
+ {
+ p->remainLen = kMatchSpecLen_Error_Data;
+ return SZ_ERROR_DATA;
+ }
+ }
+ }
+ }
+ }
+
+ /* Some unexpected error: internal error of code, memory corruption or hardware failure */
+ p->remainLen = kMatchSpecLen_Error_Fail;
+ return SZ_ERROR_FAIL;
+}
+
+
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT outSize = *destLen;
+ SizeT inSize = *srcLen;
+ *srcLen = *destLen = 0;
+ for (;;)
+ {
+ SizeT inSizeCur = inSize, outSizeCur, dicPos;
+ ELzmaFinishMode curFinishMode;
+ SRes res;
+ if (p->dicPos == p->dicBufSize)
+ p->dicPos = 0;
+ dicPos = p->dicPos;
+ if (outSize > p->dicBufSize - dicPos)
+ {
+ outSizeCur = p->dicBufSize;
+ curFinishMode = LZMA_FINISH_ANY;
+ }
+ else
+ {
+ outSizeCur = dicPos + outSize;
+ curFinishMode = finishMode;
+ }
+
+ res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
+ src += inSizeCur;
+ inSize -= inSizeCur;
+ *srcLen += inSizeCur;
+ outSizeCur = p->dicPos - dicPos;
+ memcpy(dest, p->dic + dicPos, outSizeCur);
+ dest += outSizeCur;
+ outSize -= outSizeCur;
+ *destLen += outSizeCur;
+ if (res != 0)
+ return res;
+ if (outSizeCur == 0 || outSize == 0)
+ return SZ_OK;
+ }
+}
+
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->probs);
+ p->probs = NULL;
+}
+
+static void LzmaDec_FreeDict(CLzmaDec *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->dic);
+ p->dic = NULL;
+}
+
+void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc)
+{
+ LzmaDec_FreeProbs(p, alloc);
+ LzmaDec_FreeDict(p, alloc);
+}
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
+{
+ UInt32 dicSize;
+ Byte d;
+
+ if (size < LZMA_PROPS_SIZE)
+ return SZ_ERROR_UNSUPPORTED;
+ else
+ dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
+
+ if (dicSize < LZMA_DIC_MIN)
+ dicSize = LZMA_DIC_MIN;
+ p->dicSize = dicSize;
+
+ d = data[0];
+ if (d >= (9 * 5 * 5))
+ return SZ_ERROR_UNSUPPORTED;
+
+ p->lc = (Byte)(d % 9);
+ d /= 9;
+ p->pb = (Byte)(d / 5);
+ p->lp = (Byte)(d % 5);
+
+ return SZ_OK;
+}
+
+static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAllocPtr alloc)
+{
+ UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
+ if (!p->probs || numProbs != p->numProbs)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ p->probs = (CLzmaProb *)ISzAlloc_Alloc(alloc, numProbs * sizeof(CLzmaProb));
+ if (!p->probs)
+ return SZ_ERROR_MEM;
+ p->probs_1664 = p->probs + 1664;
+ p->numProbs = numProbs;
+ }
+ return SZ_OK;
+}
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc)
+{
+ CLzmaProps propNew;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize))
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc))
+ p->prop = propNew;
+ return SZ_OK;
+}
+
+SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc)
+{
+ CLzmaProps propNew;
+ SizeT dicBufSize;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize))
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc))
+
+ {
+ UInt32 dictSize = propNew.dicSize;
+ SizeT mask = ((UInt32)1 << 12) - 1;
+ if (dictSize >= ((UInt32)1 << 30)) mask = ((UInt32)1 << 22) - 1;
+ else if (dictSize >= ((UInt32)1 << 22)) mask = ((UInt32)1 << 20) - 1;
+ dicBufSize = ((SizeT)dictSize + mask) & ~mask;
+ if (dicBufSize < dictSize)
+ dicBufSize = dictSize;
+ }
+
+ if (!p->dic || dicBufSize != p->dicBufSize)
+ {
+ LzmaDec_FreeDict(p, alloc);
+ p->dic = (Byte *)ISzAlloc_Alloc(alloc, dicBufSize);
+ if (!p->dic)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ return SZ_ERROR_MEM;
+ }
+ }
+ p->dicBufSize = dicBufSize;
+ p->prop = propNew;
+ return SZ_OK;
+}
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAllocPtr alloc)
+{
+ CLzmaDec p;
+ SRes res;
+ SizeT outSize = *destLen, inSize = *srcLen;
+ *destLen = *srcLen = 0;
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+ if (inSize < RC_INIT_SIZE)
+ return SZ_ERROR_INPUT_EOF;
+ LzmaDec_CONSTRUCT(&p)
+ RINOK(LzmaDec_AllocateProbs(&p, propData, propSize, alloc))
+ p.dic = dest;
+ p.dicBufSize = outSize;
+ LzmaDec_Init(&p);
+ *srcLen = inSize;
+ res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
+ *destLen = p.dicPos;
+ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ res = SZ_ERROR_INPUT_EOF;
+ LzmaDec_FreeProbs(&p, alloc);
+ return res;
+}
diff --git a/C/LzmaDec.h b/C/LzmaDec.h
index 28ce60c..b0ce28f 100644
--- a/C/LzmaDec.h
+++ b/C/LzmaDec.h
@@ -1,234 +1,237 @@
-/* LzmaDec.h -- LZMA Decoder
-2018-04-21 : Igor Pavlov : Public domain */
-
-#ifndef __LZMA_DEC_H
-#define __LZMA_DEC_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-/* #define _LZMA_PROB32 */
-/* _LZMA_PROB32 can increase the speed on some CPUs,
- but memory usage for CLzmaDec::probs will be doubled in that case */
-
-typedef
-#ifdef _LZMA_PROB32
- UInt32
-#else
- UInt16
-#endif
- CLzmaProb;
-
-
-/* ---------- LZMA Properties ---------- */
-
-#define LZMA_PROPS_SIZE 5
-
-typedef struct _CLzmaProps
-{
- Byte lc;
- Byte lp;
- Byte pb;
- Byte _pad_;
- UInt32 dicSize;
-} CLzmaProps;
-
-/* LzmaProps_Decode - decodes properties
-Returns:
- SZ_OK
- SZ_ERROR_UNSUPPORTED - Unsupported properties
-*/
-
-SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
-
-
-/* ---------- LZMA Decoder state ---------- */
-
-/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
- Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
-
-#define LZMA_REQUIRED_INPUT_MAX 20
-
-typedef struct
-{
- /* Don't change this structure. ASM code can use it. */
- CLzmaProps prop;
- CLzmaProb *probs;
- CLzmaProb *probs_1664;
- Byte *dic;
- SizeT dicBufSize;
- SizeT dicPos;
- const Byte *buf;
- UInt32 range;
- UInt32 code;
- UInt32 processedPos;
- UInt32 checkDicSize;
- UInt32 reps[4];
- UInt32 state;
- UInt32 remainLen;
-
- UInt32 numProbs;
- unsigned tempBufSize;
- Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
-} CLzmaDec;
-
-#define LzmaDec_Construct(p) { (p)->dic = NULL; (p)->probs = NULL; }
-
-void LzmaDec_Init(CLzmaDec *p);
-
-/* There are two types of LZMA streams:
- - Stream with end mark. That end mark adds about 6 bytes to compressed size.
- - Stream without end mark. You must know exact uncompressed size to decompress such stream. */
-
-typedef enum
-{
- LZMA_FINISH_ANY, /* finish at any point */
- LZMA_FINISH_END /* block must be finished at the end */
-} ELzmaFinishMode;
-
-/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
-
- You must use LZMA_FINISH_END, when you know that current output buffer
- covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
-
- If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
- and output value of destLen will be less than output buffer size limit.
- You can check status result also.
-
- You can use multiple checks to test data integrity after full decompression:
- 1) Check Result and "status" variable.
- 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
- 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
- You must use correct finish mode in that case. */
-
-typedef enum
-{
- LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */
- LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
- LZMA_STATUS_NOT_FINISHED, /* stream was not finished */
- LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */
- LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */
-} ELzmaStatus;
-
-/* ELzmaStatus is used only as output value for function call */
-
-
-/* ---------- Interfaces ---------- */
-
-/* There are 3 levels of interfaces:
- 1) Dictionary Interface
- 2) Buffer Interface
- 3) One Call Interface
- You can select any of these interfaces, but don't mix functions from different
- groups for same object. */
-
-
-/* There are two variants to allocate state for Dictionary Interface:
- 1) LzmaDec_Allocate / LzmaDec_Free
- 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
- You can use variant 2, if you set dictionary buffer manually.
- For Buffer Interface you must always use variant 1.
-
-LzmaDec_Allocate* can return:
- SZ_OK
- SZ_ERROR_MEM - Memory allocation error
- SZ_ERROR_UNSUPPORTED - Unsupported properties
-*/
-
-SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc);
-void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc);
-
-SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc);
-void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc);
-
-/* ---------- Dictionary Interface ---------- */
-
-/* You can use it, if you want to eliminate the overhead for data copying from
- dictionary to some other external buffer.
- You must work with CLzmaDec variables directly in this interface.
-
- STEPS:
- LzmaDec_Construct()
- LzmaDec_Allocate()
- for (each new stream)
- {
- LzmaDec_Init()
- while (it needs more decompression)
- {
- LzmaDec_DecodeToDic()
- use data from CLzmaDec::dic and update CLzmaDec::dicPos
- }
- }
- LzmaDec_Free()
-*/
-
-/* LzmaDec_DecodeToDic
-
- The decoding to internal dictionary buffer (CLzmaDec::dic).
- You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
-
-finishMode:
- It has meaning only if the decoding reaches output limit (dicLimit).
- LZMA_FINISH_ANY - Decode just dicLimit bytes.
- LZMA_FINISH_END - Stream must be finished after dicLimit.
-
-Returns:
- SZ_OK
- status:
- LZMA_STATUS_FINISHED_WITH_MARK
- LZMA_STATUS_NOT_FINISHED
- LZMA_STATUS_NEEDS_MORE_INPUT
- LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
- SZ_ERROR_DATA - Data error
-*/
-
-SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
- const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
-
-
-/* ---------- Buffer Interface ---------- */
-
-/* It's zlib-like interface.
- See LzmaDec_DecodeToDic description for information about STEPS and return results,
- but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
- to work with CLzmaDec variables manually.
-
-finishMode:
- It has meaning only if the decoding reaches output limit (*destLen).
- LZMA_FINISH_ANY - Decode just destLen bytes.
- LZMA_FINISH_END - Stream must be finished after (*destLen).
-*/
-
-SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
- const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
-
-
-/* ---------- One Call Interface ---------- */
-
-/* LzmaDecode
-
-finishMode:
- It has meaning only if the decoding reaches output limit (*destLen).
- LZMA_FINISH_ANY - Decode just destLen bytes.
- LZMA_FINISH_END - Stream must be finished after (*destLen).
-
-Returns:
- SZ_OK
- status:
- LZMA_STATUS_FINISHED_WITH_MARK
- LZMA_STATUS_NOT_FINISHED
- LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
- SZ_ERROR_DATA - Data error
- SZ_ERROR_MEM - Memory allocation error
- SZ_ERROR_UNSUPPORTED - Unsupported properties
- SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
-*/
-
-SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
- const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
- ELzmaStatus *status, ISzAllocPtr alloc);
-
-EXTERN_C_END
-
-#endif
+/* LzmaDec.h -- LZMA Decoder
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_LZMA_DEC_H
+#define ZIP7_INC_LZMA_DEC_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+/* #define Z7_LZMA_PROB32 */
+/* Z7_LZMA_PROB32 can increase the speed on some CPUs,
+ but memory usage for CLzmaDec::probs will be doubled in that case */
+
+typedef
+#ifdef Z7_LZMA_PROB32
+ UInt32
+#else
+ UInt16
+#endif
+ CLzmaProb;
+
+
+/* ---------- LZMA Properties ---------- */
+
+#define LZMA_PROPS_SIZE 5
+
+typedef struct
+{
+ Byte lc;
+ Byte lp;
+ Byte pb;
+ Byte _pad_;
+ UInt32 dicSize;
+} CLzmaProps;
+
+/* LzmaProps_Decode - decodes properties
+Returns:
+ SZ_OK
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
+
+
+/* ---------- LZMA Decoder state ---------- */
+
+/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
+ Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
+
+#define LZMA_REQUIRED_INPUT_MAX 20
+
+typedef struct
+{
+ /* Don't change this structure. ASM code can use it. */
+ CLzmaProps prop;
+ CLzmaProb *probs;
+ CLzmaProb *probs_1664;
+ Byte *dic;
+ SizeT dicBufSize;
+ SizeT dicPos;
+ const Byte *buf;
+ UInt32 range;
+ UInt32 code;
+ UInt32 processedPos;
+ UInt32 checkDicSize;
+ UInt32 reps[4];
+ UInt32 state;
+ UInt32 remainLen;
+
+ UInt32 numProbs;
+ unsigned tempBufSize;
+ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
+} CLzmaDec;
+
+#define LzmaDec_CONSTRUCT(p) { (p)->dic = NULL; (p)->probs = NULL; }
+#define LzmaDec_Construct(p) LzmaDec_CONSTRUCT(p)
+
+void LzmaDec_Init(CLzmaDec *p);
+
+/* There are two types of LZMA streams:
+ - Stream with end mark. That end mark adds about 6 bytes to compressed size.
+ - Stream without end mark. You must know exact uncompressed size to decompress such stream. */
+
+typedef enum
+{
+ LZMA_FINISH_ANY, /* finish at any point */
+ LZMA_FINISH_END /* block must be finished at the end */
+} ELzmaFinishMode;
+
+/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
+
+ You must use LZMA_FINISH_END, when you know that current output buffer
+ covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
+
+ If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
+ and output value of destLen will be less than output buffer size limit.
+ You can check status result also.
+
+ You can use multiple checks to test data integrity after full decompression:
+ 1) Check Result and "status" variable.
+ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
+ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
+ You must use correct finish mode in that case. */
+
+typedef enum
+{
+ LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */
+ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
+ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */
+ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */
+} ELzmaStatus;
+
+/* ELzmaStatus is used only as output value for function call */
+
+
+/* ---------- Interfaces ---------- */
+
+/* There are 3 levels of interfaces:
+ 1) Dictionary Interface
+ 2) Buffer Interface
+ 3) One Call Interface
+ You can select any of these interfaces, but don't mix functions from different
+ groups for same object. */
+
+
+/* There are two variants to allocate state for Dictionary Interface:
+ 1) LzmaDec_Allocate / LzmaDec_Free
+ 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
+ You can use variant 2, if you set dictionary buffer manually.
+ For Buffer Interface you must always use variant 1.
+
+LzmaDec_Allocate* can return:
+ SZ_OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc);
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAllocPtr alloc);
+
+SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAllocPtr alloc);
+void LzmaDec_Free(CLzmaDec *p, ISzAllocPtr alloc);
+
+/* ---------- Dictionary Interface ---------- */
+
+/* You can use it, if you want to eliminate the overhead for data copying from
+ dictionary to some other external buffer.
+ You must work with CLzmaDec variables directly in this interface.
+
+ STEPS:
+ LzmaDec_Construct()
+ LzmaDec_Allocate()
+ for (each new stream)
+ {
+ LzmaDec_Init()
+ while (it needs more decompression)
+ {
+ LzmaDec_DecodeToDic()
+ use data from CLzmaDec::dic and update CLzmaDec::dicPos
+ }
+ }
+ LzmaDec_Free()
+*/
+
+/* LzmaDec_DecodeToDic
+
+ The decoding to internal dictionary buffer (CLzmaDec::dic).
+ You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (dicLimit).
+ LZMA_FINISH_ANY - Decode just dicLimit bytes.
+ LZMA_FINISH_END - Stream must be finished after dicLimit.
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_NEEDS_MORE_INPUT
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_FAIL - Some unexpected error: internal error of code, memory corruption or hardware failure
+*/
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- Buffer Interface ---------- */
+
+/* It's zlib-like interface.
+ See LzmaDec_DecodeToDic description for information about STEPS and return results,
+ but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
+ to work with CLzmaDec variables manually.
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+*/
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- One Call Interface ---------- */
+
+/* LzmaDecode
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+ SZ_ERROR_FAIL - Some unexpected error: internal error of code, memory corruption or hardware failure
+*/
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAllocPtr alloc);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/LzmaEnc.c b/C/LzmaEnc.c
index 14086fc..6d13cac 100644
--- a/C/LzmaEnc.c
+++ b/C/LzmaEnc.c
@@ -1,2976 +1,3144 @@
-/* LzmaEnc.c -- LZMA Encoder
-2019-01-10: Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include <string.h>
-
-/* #define SHOW_STAT */
-/* #define SHOW_STAT2 */
-
-#if defined(SHOW_STAT) || defined(SHOW_STAT2)
-#include <stdio.h>
-#endif
-
-#include "LzmaEnc.h"
-
-#include "LzFind.h"
-#ifndef _7ZIP_ST
-#include "LzFindMt.h"
-#endif
-
-#ifdef SHOW_STAT
-static unsigned g_STAT_OFFSET = 0;
-#endif
-
-#define kLzmaMaxHistorySize ((UInt32)3 << 29)
-/* #define kLzmaMaxHistorySize ((UInt32)7 << 29) */
-
-#define kNumTopBits 24
-#define kTopValue ((UInt32)1 << kNumTopBits)
-
-#define kNumBitModelTotalBits 11
-#define kBitModelTotal (1 << kNumBitModelTotalBits)
-#define kNumMoveBits 5
-#define kProbInitValue (kBitModelTotal >> 1)
-
-#define kNumMoveReducingBits 4
-#define kNumBitPriceShiftBits 4
-#define kBitPrice (1 << kNumBitPriceShiftBits)
-
-#define REP_LEN_COUNT 64
-
-void LzmaEncProps_Init(CLzmaEncProps *p)
-{
- p->level = 5;
- p->dictSize = p->mc = 0;
- p->reduceSize = (UInt64)(Int64)-1;
- p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1;
- p->writeEndMark = 0;
-}
-
-void LzmaEncProps_Normalize(CLzmaEncProps *p)
-{
- int level = p->level;
- if (level < 0) level = 5;
- p->level = level;
-
- if (p->dictSize == 0) p->dictSize = (level <= 5 ? (1 << (level * 2 + 14)) : (level <= 7 ? (1 << 25) : (1 << 26)));
- if (p->dictSize > p->reduceSize)
- {
- unsigned i;
- UInt32 reduceSize = (UInt32)p->reduceSize;
- for (i = 11; i <= 30; i++)
- {
- if (reduceSize <= ((UInt32)2 << i)) { p->dictSize = ((UInt32)2 << i); break; }
- if (reduceSize <= ((UInt32)3 << i)) { p->dictSize = ((UInt32)3 << i); break; }
- }
- }
-
- if (p->lc < 0) p->lc = 3;
- if (p->lp < 0) p->lp = 0;
- if (p->pb < 0) p->pb = 2;
-
- if (p->algo < 0) p->algo = (level < 5 ? 0 : 1);
- if (p->fb < 0) p->fb = (level < 7 ? 32 : 64);
- if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1);
- if (p->numHashBytes < 0) p->numHashBytes = 4;
- if (p->mc == 0) p->mc = (16 + (p->fb >> 1)) >> (p->btMode ? 0 : 1);
-
- if (p->numThreads < 0)
- p->numThreads =
- #ifndef _7ZIP_ST
- ((p->btMode && p->algo) ? 2 : 1);
- #else
- 1;
- #endif
-}
-
-UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
-{
- CLzmaEncProps props = *props2;
- LzmaEncProps_Normalize(&props);
- return props.dictSize;
-}
-
-#if (_MSC_VER >= 1400)
-/* BSR code is fast for some new CPUs */
-/* #define LZMA_LOG_BSR */
-#endif
-
-#ifdef LZMA_LOG_BSR
-
-#define kDicLogSizeMaxCompress 32
-
-#define BSR2_RET(pos, res) { unsigned long zz; _BitScanReverse(&zz, (pos)); res = (zz + zz) + ((pos >> (zz - 1)) & 1); }
-
-static unsigned GetPosSlot1(UInt32 pos)
-{
- unsigned res;
- BSR2_RET(pos, res);
- return res;
-}
-#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
-#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
-
-#else
-
-#define kNumLogBits (9 + sizeof(size_t) / 2)
-/* #define kNumLogBits (11 + sizeof(size_t) / 8 * 3) */
-
-#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
-
-static void LzmaEnc_FastPosInit(Byte *g_FastPos)
-{
- unsigned slot;
- g_FastPos[0] = 0;
- g_FastPos[1] = 1;
- g_FastPos += 2;
-
- for (slot = 2; slot < kNumLogBits * 2; slot++)
- {
- size_t k = ((size_t)1 << ((slot >> 1) - 1));
- size_t j;
- for (j = 0; j < k; j++)
- g_FastPos[j] = (Byte)slot;
- g_FastPos += k;
- }
-}
-
-/* we can use ((limit - pos) >> 31) only if (pos < ((UInt32)1 << 31)) */
-/*
-#define BSR2_RET(pos, res) { unsigned zz = 6 + ((kNumLogBits - 1) & \
- (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
- res = p->g_FastPos[pos >> zz] + (zz * 2); }
-*/
-
-/*
-#define BSR2_RET(pos, res) { unsigned zz = 6 + ((kNumLogBits - 1) & \
- (0 - (((((UInt32)1 << (kNumLogBits)) - 1) - (pos >> 6)) >> 31))); \
- res = p->g_FastPos[pos >> zz] + (zz * 2); }
-*/
-
-#define BSR2_RET(pos, res) { unsigned zz = (pos < (1 << (kNumLogBits + 6))) ? 6 : 6 + kNumLogBits - 1; \
- res = p->g_FastPos[pos >> zz] + (zz * 2); }
-
-/*
-#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
- p->g_FastPos[pos >> 6] + 12 : \
- p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
-*/
-
-#define GetPosSlot1(pos) p->g_FastPos[pos]
-#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
-#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos & (kNumFullDistances - 1)]; else BSR2_RET(pos, res); }
-
-#endif
-
-
-#define LZMA_NUM_REPS 4
-
-typedef UInt16 CState;
-typedef UInt16 CExtra;
-
-typedef struct
-{
- UInt32 price;
- CState state;
- CExtra extra;
- // 0 : normal
- // 1 : LIT : MATCH
- // > 1 : MATCH (extra-1) : LIT : REP0 (len)
- UInt32 len;
- UInt32 dist;
- UInt32 reps[LZMA_NUM_REPS];
-} COptimal;
-
-
-// 18.06
-#define kNumOpts (1 << 11)
-#define kPackReserve (kNumOpts * 8)
-// #define kNumOpts (1 << 12)
-// #define kPackReserve (1 + kNumOpts * 2)
-
-#define kNumLenToPosStates 4
-#define kNumPosSlotBits 6
-#define kDicLogSizeMin 0
-#define kDicLogSizeMax 32
-#define kDistTableSizeMax (kDicLogSizeMax * 2)
-
-#define kNumAlignBits 4
-#define kAlignTableSize (1 << kNumAlignBits)
-#define kAlignMask (kAlignTableSize - 1)
-
-#define kStartPosModelIndex 4
-#define kEndPosModelIndex 14
-#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
-
-typedef
-#ifdef _LZMA_PROB32
- UInt32
-#else
- UInt16
-#endif
- CLzmaProb;
-
-#define LZMA_PB_MAX 4
-#define LZMA_LC_MAX 8
-#define LZMA_LP_MAX 4
-
-#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX)
-
-#define kLenNumLowBits 3
-#define kLenNumLowSymbols (1 << kLenNumLowBits)
-#define kLenNumHighBits 8
-#define kLenNumHighSymbols (1 << kLenNumHighBits)
-#define kLenNumSymbolsTotal (kLenNumLowSymbols * 2 + kLenNumHighSymbols)
-
-#define LZMA_MATCH_LEN_MIN 2
-#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1)
-
-#define kNumStates 12
-
-
-typedef struct
-{
- CLzmaProb low[LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)];
- CLzmaProb high[kLenNumHighSymbols];
-} CLenEnc;
-
-
-typedef struct
-{
- unsigned tableSize;
- UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal];
- // UInt32 prices1[LZMA_NUM_PB_STATES_MAX][kLenNumLowSymbols * 2];
- // UInt32 prices2[kLenNumSymbolsTotal];
-} CLenPriceEnc;
-
-#define GET_PRICE_LEN(p, posState, len) \
- ((p)->prices[posState][(size_t)(len) - LZMA_MATCH_LEN_MIN])
-
-/*
-#define GET_PRICE_LEN(p, posState, len) \
- ((p)->prices2[(size_t)(len) - 2] + ((p)->prices1[posState][((len) - 2) & (kLenNumLowSymbols * 2 - 1)] & (((len) - 2 - kLenNumLowSymbols * 2) >> 9)))
-*/
-
-typedef struct
-{
- UInt32 range;
- unsigned cache;
- UInt64 low;
- UInt64 cacheSize;
- Byte *buf;
- Byte *bufLim;
- Byte *bufBase;
- ISeqOutStream *outStream;
- UInt64 processed;
- SRes res;
-} CRangeEnc;
-
-
-typedef struct
-{
- CLzmaProb *litProbs;
-
- unsigned state;
- UInt32 reps[LZMA_NUM_REPS];
-
- CLzmaProb posAlignEncoder[1 << kNumAlignBits];
- CLzmaProb isRep[kNumStates];
- CLzmaProb isRepG0[kNumStates];
- CLzmaProb isRepG1[kNumStates];
- CLzmaProb isRepG2[kNumStates];
- CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
- CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
-
- CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
- CLzmaProb posEncoders[kNumFullDistances];
-
- CLenEnc lenProbs;
- CLenEnc repLenProbs;
-
-} CSaveState;
-
-
-typedef UInt32 CProbPrice;
-
-
-typedef struct
-{
- void *matchFinderObj;
- IMatchFinder matchFinder;
-
- unsigned optCur;
- unsigned optEnd;
-
- unsigned longestMatchLen;
- unsigned numPairs;
- UInt32 numAvail;
-
- unsigned state;
- unsigned numFastBytes;
- unsigned additionalOffset;
- UInt32 reps[LZMA_NUM_REPS];
- unsigned lpMask, pbMask;
- CLzmaProb *litProbs;
- CRangeEnc rc;
-
- UInt32 backRes;
-
- unsigned lc, lp, pb;
- unsigned lclp;
-
- BoolInt fastMode;
- BoolInt writeEndMark;
- BoolInt finished;
- BoolInt multiThread;
- BoolInt needInit;
- // BoolInt _maxMode;
-
- UInt64 nowPos64;
-
- unsigned matchPriceCount;
- // unsigned alignPriceCount;
- int repLenEncCounter;
-
- unsigned distTableSize;
-
- UInt32 dictSize;
- SRes result;
-
- #ifndef _7ZIP_ST
- BoolInt mtMode;
- // begin of CMatchFinderMt is used in LZ thread
- CMatchFinderMt matchFinderMt;
- // end of CMatchFinderMt is used in BT and HASH threads
- #endif
-
- CMatchFinder matchFinderBase;
-
- #ifndef _7ZIP_ST
- Byte pad[128];
- #endif
-
- // LZ thread
- CProbPrice ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
-
- UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2 + 1];
-
- UInt32 alignPrices[kAlignTableSize];
- UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
- UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances];
-
- CLzmaProb posAlignEncoder[1 << kNumAlignBits];
- CLzmaProb isRep[kNumStates];
- CLzmaProb isRepG0[kNumStates];
- CLzmaProb isRepG1[kNumStates];
- CLzmaProb isRepG2[kNumStates];
- CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
- CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
- CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
- CLzmaProb posEncoders[kNumFullDistances];
-
- CLenEnc lenProbs;
- CLenEnc repLenProbs;
-
- #ifndef LZMA_LOG_BSR
- Byte g_FastPos[1 << kNumLogBits];
- #endif
-
- CLenPriceEnc lenEnc;
- CLenPriceEnc repLenEnc;
-
- COptimal opt[kNumOpts];
-
- CSaveState saveState;
-
- #ifndef _7ZIP_ST
- Byte pad2[128];
- #endif
-} CLzmaEnc;
-
-
-
-#define COPY_ARR(dest, src, arr) memcpy(dest->arr, src->arr, sizeof(src->arr));
-
-void LzmaEnc_SaveState(CLzmaEncHandle pp)
-{
- CLzmaEnc *p = (CLzmaEnc *)pp;
- CSaveState *dest = &p->saveState;
-
- dest->state = p->state;
-
- dest->lenProbs = p->lenProbs;
- dest->repLenProbs = p->repLenProbs;
-
- COPY_ARR(dest, p, reps);
-
- COPY_ARR(dest, p, posAlignEncoder);
- COPY_ARR(dest, p, isRep);
- COPY_ARR(dest, p, isRepG0);
- COPY_ARR(dest, p, isRepG1);
- COPY_ARR(dest, p, isRepG2);
- COPY_ARR(dest, p, isMatch);
- COPY_ARR(dest, p, isRep0Long);
- COPY_ARR(dest, p, posSlotEncoder);
- COPY_ARR(dest, p, posEncoders);
-
- memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << p->lclp) * sizeof(CLzmaProb));
-}
-
-
-void LzmaEnc_RestoreState(CLzmaEncHandle pp)
-{
- CLzmaEnc *dest = (CLzmaEnc *)pp;
- const CSaveState *p = &dest->saveState;
-
- dest->state = p->state;
-
- dest->lenProbs = p->lenProbs;
- dest->repLenProbs = p->repLenProbs;
-
- COPY_ARR(dest, p, reps);
-
- COPY_ARR(dest, p, posAlignEncoder);
- COPY_ARR(dest, p, isRep);
- COPY_ARR(dest, p, isRepG0);
- COPY_ARR(dest, p, isRepG1);
- COPY_ARR(dest, p, isRepG2);
- COPY_ARR(dest, p, isMatch);
- COPY_ARR(dest, p, isRep0Long);
- COPY_ARR(dest, p, posSlotEncoder);
- COPY_ARR(dest, p, posEncoders);
-
- memcpy(dest->litProbs, p->litProbs, ((UInt32)0x300 << dest->lclp) * sizeof(CLzmaProb));
-}
-
-
-
-SRes LzmaEnc_SetProps(CLzmaEncHandle pp, const CLzmaEncProps *props2)
-{
- CLzmaEnc *p = (CLzmaEnc *)pp;
- CLzmaEncProps props = *props2;
- LzmaEncProps_Normalize(&props);
-
- if (props.lc > LZMA_LC_MAX
- || props.lp > LZMA_LP_MAX
- || props.pb > LZMA_PB_MAX
- || props.dictSize > ((UInt64)1 << kDicLogSizeMaxCompress)
- || props.dictSize > kLzmaMaxHistorySize)
- return SZ_ERROR_PARAM;
-
- p->dictSize = props.dictSize;
- {
- unsigned fb = props.fb;
- if (fb < 5)
- fb = 5;
- if (fb > LZMA_MATCH_LEN_MAX)
- fb = LZMA_MATCH_LEN_MAX;
- p->numFastBytes = fb;
- }
- p->lc = props.lc;
- p->lp = props.lp;
- p->pb = props.pb;
- p->fastMode = (props.algo == 0);
- // p->_maxMode = True;
- p->matchFinderBase.btMode = (Byte)(props.btMode ? 1 : 0);
- {
- unsigned numHashBytes = 4;
- if (props.btMode)
- {
- if (props.numHashBytes < 2)
- numHashBytes = 2;
- else if (props.numHashBytes < 4)
- numHashBytes = props.numHashBytes;
- }
- p->matchFinderBase.numHashBytes = numHashBytes;
- }
-
- p->matchFinderBase.cutValue = props.mc;
-
- p->writeEndMark = props.writeEndMark;
-
- #ifndef _7ZIP_ST
- /*
- if (newMultiThread != _multiThread)
- {
- ReleaseMatchFinder();
- _multiThread = newMultiThread;
- }
- */
- p->multiThread = (props.numThreads > 1);
- #endif
-
- return SZ_OK;
-}
-
-
-void LzmaEnc_SetDataSize(CLzmaEncHandle pp, UInt64 expectedDataSiize)
-{
- CLzmaEnc *p = (CLzmaEnc *)pp;
- p->matchFinderBase.expectedDataSize = expectedDataSiize;
-}
-
-
-#define kState_Start 0
-#define kState_LitAfterMatch 4
-#define kState_LitAfterRep 5
-#define kState_MatchAfterLit 7
-#define kState_RepAfterLit 8
-
-static const Byte kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
-static const Byte kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
-static const Byte kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
-static const Byte kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
-
-#define IsLitState(s) ((s) < 7)
-#define GetLenToPosState2(len) (((len) < kNumLenToPosStates - 1) ? (len) : kNumLenToPosStates - 1)
-#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1)
-
-#define kInfinityPrice (1 << 30)
-
-static void RangeEnc_Construct(CRangeEnc *p)
-{
- p->outStream = NULL;
- p->bufBase = NULL;
-}
-
-#define RangeEnc_GetProcessed(p) ((p)->processed + ((p)->buf - (p)->bufBase) + (p)->cacheSize)
-#define RangeEnc_GetProcessed_sizet(p) ((size_t)(p)->processed + ((p)->buf - (p)->bufBase) + (size_t)(p)->cacheSize)
-
-#define RC_BUF_SIZE (1 << 16)
-
-static int RangeEnc_Alloc(CRangeEnc *p, ISzAllocPtr alloc)
-{
- if (!p->bufBase)
- {
- p->bufBase = (Byte *)ISzAlloc_Alloc(alloc, RC_BUF_SIZE);
- if (!p->bufBase)
- return 0;
- p->bufLim = p->bufBase + RC_BUF_SIZE;
- }
- return 1;
-}
-
-static void RangeEnc_Free(CRangeEnc *p, ISzAllocPtr alloc)
-{
- ISzAlloc_Free(alloc, p->bufBase);
- p->bufBase = 0;
-}
-
-static void RangeEnc_Init(CRangeEnc *p)
-{
- /* Stream.Init(); */
- p->range = 0xFFFFFFFF;
- p->cache = 0;
- p->low = 0;
- p->cacheSize = 0;
-
- p->buf = p->bufBase;
-
- p->processed = 0;
- p->res = SZ_OK;
-}
-
-MY_NO_INLINE static void RangeEnc_FlushStream(CRangeEnc *p)
-{
- size_t num;
- if (p->res != SZ_OK)
- return;
- num = p->buf - p->bufBase;
- if (num != ISeqOutStream_Write(p->outStream, p->bufBase, num))
- p->res = SZ_ERROR_WRITE;
- p->processed += num;
- p->buf = p->bufBase;
-}
-
-MY_NO_INLINE static void MY_FAST_CALL RangeEnc_ShiftLow(CRangeEnc *p)
-{
- UInt32 low = (UInt32)p->low;
- unsigned high = (unsigned)(p->low >> 32);
- p->low = (UInt32)(low << 8);
- if (low < (UInt32)0xFF000000 || high != 0)
- {
- {
- Byte *buf = p->buf;
- *buf++ = (Byte)(p->cache + high);
- p->cache = (unsigned)(low >> 24);
- p->buf = buf;
- if (buf == p->bufLim)
- RangeEnc_FlushStream(p);
- if (p->cacheSize == 0)
- return;
- }
- high += 0xFF;
- for (;;)
- {
- Byte *buf = p->buf;
- *buf++ = (Byte)(high);
- p->buf = buf;
- if (buf == p->bufLim)
- RangeEnc_FlushStream(p);
- if (--p->cacheSize == 0)
- return;
- }
- }
- p->cacheSize++;
-}
-
-static void RangeEnc_FlushData(CRangeEnc *p)
-{
- int i;
- for (i = 0; i < 5; i++)
- RangeEnc_ShiftLow(p);
-}
-
-#define RC_NORM(p) if (range < kTopValue) { range <<= 8; RangeEnc_ShiftLow(p); }
-
-#define RC_BIT_PRE(p, prob) \
- ttt = *(prob); \
- newBound = (range >> kNumBitModelTotalBits) * ttt;
-
-// #define _LZMA_ENC_USE_BRANCH
-
-#ifdef _LZMA_ENC_USE_BRANCH
-
-#define RC_BIT(p, prob, bit) { \
- RC_BIT_PRE(p, prob) \
- if (bit == 0) { range = newBound; ttt += (kBitModelTotal - ttt) >> kNumMoveBits; } \
- else { (p)->low += newBound; range -= newBound; ttt -= ttt >> kNumMoveBits; } \
- *(prob) = (CLzmaProb)ttt; \
- RC_NORM(p) \
- }
-
-#else
-
-#define RC_BIT(p, prob, bit) { \
- UInt32 mask; \
- RC_BIT_PRE(p, prob) \
- mask = 0 - (UInt32)bit; \
- range &= mask; \
- mask &= newBound; \
- range -= mask; \
- (p)->low += mask; \
- mask = (UInt32)bit - 1; \
- range += newBound & mask; \
- mask &= (kBitModelTotal - ((1 << kNumMoveBits) - 1)); \
- mask += ((1 << kNumMoveBits) - 1); \
- ttt += (Int32)(mask - ttt) >> kNumMoveBits; \
- *(prob) = (CLzmaProb)ttt; \
- RC_NORM(p) \
- }
-
-#endif
-
-
-
-
-#define RC_BIT_0_BASE(p, prob) \
- range = newBound; *(prob) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
-
-#define RC_BIT_1_BASE(p, prob) \
- range -= newBound; (p)->low += newBound; *(prob) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); \
-
-#define RC_BIT_0(p, prob) \
- RC_BIT_0_BASE(p, prob) \
- RC_NORM(p)
-
-#define RC_BIT_1(p, prob) \
- RC_BIT_1_BASE(p, prob) \
- RC_NORM(p)
-
-static void RangeEnc_EncodeBit_0(CRangeEnc *p, CLzmaProb *prob)
-{
- UInt32 range, ttt, newBound;
- range = p->range;
- RC_BIT_PRE(p, prob)
- RC_BIT_0(p, prob)
- p->range = range;
-}
-
-static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 sym)
-{
- UInt32 range = p->range;
- sym |= 0x100;
- do
- {
- UInt32 ttt, newBound;
- // RangeEnc_EncodeBit(p, probs + (sym >> 8), (sym >> 7) & 1);
- CLzmaProb *prob = probs + (sym >> 8);
- UInt32 bit = (sym >> 7) & 1;
- sym <<= 1;
- RC_BIT(p, prob, bit);
- }
- while (sym < 0x10000);
- p->range = range;
-}
-
-static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 sym, UInt32 matchByte)
-{
- UInt32 range = p->range;
- UInt32 offs = 0x100;
- sym |= 0x100;
- do
- {
- UInt32 ttt, newBound;
- CLzmaProb *prob;
- UInt32 bit;
- matchByte <<= 1;
- // RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (sym >> 8)), (sym >> 7) & 1);
- prob = probs + (offs + (matchByte & offs) + (sym >> 8));
- bit = (sym >> 7) & 1;
- sym <<= 1;
- offs &= ~(matchByte ^ sym);
- RC_BIT(p, prob, bit);
- }
- while (sym < 0x10000);
- p->range = range;
-}
-
-
-
-static void LzmaEnc_InitPriceTables(CProbPrice *ProbPrices)
-{
- UInt32 i;
- for (i = 0; i < (kBitModelTotal >> kNumMoveReducingBits); i++)
- {
- const unsigned kCyclesBits = kNumBitPriceShiftBits;
- UInt32 w = (i << kNumMoveReducingBits) + (1 << (kNumMoveReducingBits - 1));
- unsigned bitCount = 0;
- unsigned j;
- for (j = 0; j < kCyclesBits; j++)
- {
- w = w * w;
- bitCount <<= 1;
- while (w >= ((UInt32)1 << 16))
- {
- w >>= 1;
- bitCount++;
- }
- }
- ProbPrices[i] = (CProbPrice)((kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount);
- // printf("\n%3d: %5d", i, ProbPrices[i]);
- }
-}
-
-
-#define GET_PRICE(prob, bit) \
- p->ProbPrices[((prob) ^ (unsigned)(((-(int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
-
-#define GET_PRICEa(prob, bit) \
- ProbPrices[((prob) ^ (unsigned)((-((int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits];
-
-#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits]
-#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
-
-#define GET_PRICEa_0(prob) ProbPrices[(prob) >> kNumMoveReducingBits]
-#define GET_PRICEa_1(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
-
-
-static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 sym, const CProbPrice *ProbPrices)
-{
- UInt32 price = 0;
- sym |= 0x100;
- do
- {
- unsigned bit = sym & 1;
- sym >>= 1;
- price += GET_PRICEa(probs[sym], bit);
- }
- while (sym >= 2);
- return price;
-}
-
-
-static UInt32 LitEnc_Matched_GetPrice(const CLzmaProb *probs, UInt32 sym, UInt32 matchByte, const CProbPrice *ProbPrices)
-{
- UInt32 price = 0;
- UInt32 offs = 0x100;
- sym |= 0x100;
- do
- {
- matchByte <<= 1;
- price += GET_PRICEa(probs[offs + (matchByte & offs) + (sym >> 8)], (sym >> 7) & 1);
- sym <<= 1;
- offs &= ~(matchByte ^ sym);
- }
- while (sym < 0x10000);
- return price;
-}
-
-
-static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, unsigned numBits, unsigned sym)
-{
- UInt32 range = rc->range;
- unsigned m = 1;
- do
- {
- UInt32 ttt, newBound;
- unsigned bit = sym & 1;
- // RangeEnc_EncodeBit(rc, probs + m, bit);
- sym >>= 1;
- RC_BIT(rc, probs + m, bit);
- m = (m << 1) | bit;
- }
- while (--numBits);
- rc->range = range;
-}
-
-
-
-static void LenEnc_Init(CLenEnc *p)
-{
- unsigned i;
- for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)); i++)
- p->low[i] = kProbInitValue;
- for (i = 0; i < kLenNumHighSymbols; i++)
- p->high[i] = kProbInitValue;
-}
-
-static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, unsigned sym, unsigned posState)
-{
- UInt32 range, ttt, newBound;
- CLzmaProb *probs = p->low;
- range = rc->range;
- RC_BIT_PRE(rc, probs);
- if (sym >= kLenNumLowSymbols)
- {
- RC_BIT_1(rc, probs);
- probs += kLenNumLowSymbols;
- RC_BIT_PRE(rc, probs);
- if (sym >= kLenNumLowSymbols * 2)
- {
- RC_BIT_1(rc, probs);
- rc->range = range;
- // RcTree_Encode(rc, p->high, kLenNumHighBits, sym - kLenNumLowSymbols * 2);
- LitEnc_Encode(rc, p->high, sym - kLenNumLowSymbols * 2);
- return;
- }
- sym -= kLenNumLowSymbols;
- }
-
- // RcTree_Encode(rc, probs + (posState << kLenNumLowBits), kLenNumLowBits, sym);
- {
- unsigned m;
- unsigned bit;
- RC_BIT_0(rc, probs);
- probs += (posState << (1 + kLenNumLowBits));
- bit = (sym >> 2) ; RC_BIT(rc, probs + 1, bit); m = (1 << 1) + bit;
- bit = (sym >> 1) & 1; RC_BIT(rc, probs + m, bit); m = (m << 1) + bit;
- bit = sym & 1; RC_BIT(rc, probs + m, bit);
- rc->range = range;
- }
-}
-
-static void SetPrices_3(const CLzmaProb *probs, UInt32 startPrice, UInt32 *prices, const CProbPrice *ProbPrices)
-{
- unsigned i;
- for (i = 0; i < 8; i += 2)
- {
- UInt32 price = startPrice;
- UInt32 prob;
- price += GET_PRICEa(probs[1 ], (i >> 2));
- price += GET_PRICEa(probs[2 + (i >> 2)], (i >> 1) & 1);
- prob = probs[4 + (i >> 1)];
- prices[i ] = price + GET_PRICEa_0(prob);
- prices[i + 1] = price + GET_PRICEa_1(prob);
- }
-}
-
-
-MY_NO_INLINE static void MY_FAST_CALL LenPriceEnc_UpdateTables(
- CLenPriceEnc *p,
- unsigned numPosStates,
- const CLenEnc *enc,
- const CProbPrice *ProbPrices)
-{
- UInt32 b;
-
- {
- unsigned prob = enc->low[0];
- UInt32 a, c;
- unsigned posState;
- b = GET_PRICEa_1(prob);
- a = GET_PRICEa_0(prob);
- c = b + GET_PRICEa_0(enc->low[kLenNumLowSymbols]);
- for (posState = 0; posState < numPosStates; posState++)
- {
- UInt32 *prices = p->prices[posState];
- const CLzmaProb *probs = enc->low + (posState << (1 + kLenNumLowBits));
- SetPrices_3(probs, a, prices, ProbPrices);
- SetPrices_3(probs + kLenNumLowSymbols, c, prices + kLenNumLowSymbols, ProbPrices);
- }
- }
-
- /*
- {
- unsigned i;
- UInt32 b;
- a = GET_PRICEa_0(enc->low[0]);
- for (i = 0; i < kLenNumLowSymbols; i++)
- p->prices2[i] = a;
- a = GET_PRICEa_1(enc->low[0]);
- b = a + GET_PRICEa_0(enc->low[kLenNumLowSymbols]);
- for (i = kLenNumLowSymbols; i < kLenNumLowSymbols * 2; i++)
- p->prices2[i] = b;
- a += GET_PRICEa_1(enc->low[kLenNumLowSymbols]);
- }
- */
-
- // p->counter = numSymbols;
- // p->counter = 64;
-
- {
- unsigned i = p->tableSize;
-
- if (i > kLenNumLowSymbols * 2)
- {
- const CLzmaProb *probs = enc->high;
- UInt32 *prices = p->prices[0] + kLenNumLowSymbols * 2;
- i -= kLenNumLowSymbols * 2 - 1;
- i >>= 1;
- b += GET_PRICEa_1(enc->low[kLenNumLowSymbols]);
- do
- {
- /*
- p->prices2[i] = a +
- // RcTree_GetPrice(enc->high, kLenNumHighBits, i - kLenNumLowSymbols * 2, ProbPrices);
- LitEnc_GetPrice(probs, i - kLenNumLowSymbols * 2, ProbPrices);
- */
- // UInt32 price = a + RcTree_GetPrice(probs, kLenNumHighBits - 1, sym, ProbPrices);
- unsigned sym = --i + (1 << (kLenNumHighBits - 1));
- UInt32 price = b;
- do
- {
- unsigned bit = sym & 1;
- sym >>= 1;
- price += GET_PRICEa(probs[sym], bit);
- }
- while (sym >= 2);
-
- {
- unsigned prob = probs[(size_t)i + (1 << (kLenNumHighBits - 1))];
- prices[(size_t)i * 2 ] = price + GET_PRICEa_0(prob);
- prices[(size_t)i * 2 + 1] = price + GET_PRICEa_1(prob);
- }
- }
- while (i);
-
- {
- unsigned posState;
- size_t num = (p->tableSize - kLenNumLowSymbols * 2) * sizeof(p->prices[0][0]);
- for (posState = 1; posState < numPosStates; posState++)
- memcpy(p->prices[posState] + kLenNumLowSymbols * 2, p->prices[0] + kLenNumLowSymbols * 2, num);
- }
- }
- }
-}
-
-/*
- #ifdef SHOW_STAT
- g_STAT_OFFSET += num;
- printf("\n MovePos %u", num);
- #endif
-*/
-
-#define MOVE_POS(p, num) { \
- p->additionalOffset += (num); \
- p->matchFinder.Skip(p->matchFinderObj, (UInt32)(num)); }
-
-
-static unsigned ReadMatchDistances(CLzmaEnc *p, unsigned *numPairsRes)
-{
- unsigned numPairs;
-
- p->additionalOffset++;
- p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
- numPairs = p->matchFinder.GetMatches(p->matchFinderObj, p->matches);
- *numPairsRes = numPairs;
-
- #ifdef SHOW_STAT
- printf("\n i = %u numPairs = %u ", g_STAT_OFFSET, numPairs / 2);
- g_STAT_OFFSET++;
- {
- unsigned i;
- for (i = 0; i < numPairs; i += 2)
- printf("%2u %6u | ", p->matches[i], p->matches[i + 1]);
- }
- #endif
-
- if (numPairs == 0)
- return 0;
- {
- unsigned len = p->matches[(size_t)numPairs - 2];
- if (len != p->numFastBytes)
- return len;
- {
- UInt32 numAvail = p->numAvail;
- if (numAvail > LZMA_MATCH_LEN_MAX)
- numAvail = LZMA_MATCH_LEN_MAX;
- {
- const Byte *p1 = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
- const Byte *p2 = p1 + len;
- ptrdiff_t dif = (ptrdiff_t)-1 - p->matches[(size_t)numPairs - 1];
- const Byte *lim = p1 + numAvail;
- for (; p2 != lim && *p2 == p2[dif]; p2++)
- {}
- return (unsigned)(p2 - p1);
- }
- }
- }
-}
-
-#define MARK_LIT ((UInt32)(Int32)-1)
-
-#define MakeAs_Lit(p) { (p)->dist = MARK_LIT; (p)->extra = 0; }
-#define MakeAs_ShortRep(p) { (p)->dist = 0; (p)->extra = 0; }
-#define IsShortRep(p) ((p)->dist == 0)
-
-
-#define GetPrice_ShortRep(p, state, posState) \
- ( GET_PRICE_0(p->isRepG0[state]) + GET_PRICE_0(p->isRep0Long[state][posState]))
-
-#define GetPrice_Rep_0(p, state, posState) ( \
- GET_PRICE_1(p->isMatch[state][posState]) \
- + GET_PRICE_1(p->isRep0Long[state][posState])) \
- + GET_PRICE_1(p->isRep[state]) \
- + GET_PRICE_0(p->isRepG0[state])
-
-MY_FORCE_INLINE
-static UInt32 GetPrice_PureRep(const CLzmaEnc *p, unsigned repIndex, size_t state, size_t posState)
-{
- UInt32 price;
- UInt32 prob = p->isRepG0[state];
- if (repIndex == 0)
- {
- price = GET_PRICE_0(prob);
- price += GET_PRICE_1(p->isRep0Long[state][posState]);
- }
- else
- {
- price = GET_PRICE_1(prob);
- prob = p->isRepG1[state];
- if (repIndex == 1)
- price += GET_PRICE_0(prob);
- else
- {
- price += GET_PRICE_1(prob);
- price += GET_PRICE(p->isRepG2[state], repIndex - 2);
- }
- }
- return price;
-}
-
-
-static unsigned Backward(CLzmaEnc *p, unsigned cur)
-{
- unsigned wr = cur + 1;
- p->optEnd = wr;
-
- for (;;)
- {
- UInt32 dist = p->opt[cur].dist;
- unsigned len = (unsigned)p->opt[cur].len;
- unsigned extra = (unsigned)p->opt[cur].extra;
- cur -= len;
-
- if (extra)
- {
- wr--;
- p->opt[wr].len = (UInt32)len;
- cur -= extra;
- len = extra;
- if (extra == 1)
- {
- p->opt[wr].dist = dist;
- dist = MARK_LIT;
- }
- else
- {
- p->opt[wr].dist = 0;
- len--;
- wr--;
- p->opt[wr].dist = MARK_LIT;
- p->opt[wr].len = 1;
- }
- }
-
- if (cur == 0)
- {
- p->backRes = dist;
- p->optCur = wr;
- return len;
- }
-
- wr--;
- p->opt[wr].dist = dist;
- p->opt[wr].len = (UInt32)len;
- }
-}
-
-
-
-#define LIT_PROBS(pos, prevByte) \
- (p->litProbs + (UInt32)3 * (((((pos) << 8) + (prevByte)) & p->lpMask) << p->lc))
-
-
-static unsigned GetOptimum(CLzmaEnc *p, UInt32 position)
-{
- unsigned last, cur;
- UInt32 reps[LZMA_NUM_REPS];
- unsigned repLens[LZMA_NUM_REPS];
- UInt32 *matches;
-
- {
- UInt32 numAvail;
- unsigned numPairs, mainLen, repMaxIndex, i, posState;
- UInt32 matchPrice, repMatchPrice;
- const Byte *data;
- Byte curByte, matchByte;
-
- p->optCur = p->optEnd = 0;
-
- if (p->additionalOffset == 0)
- mainLen = ReadMatchDistances(p, &numPairs);
- else
- {
- mainLen = p->longestMatchLen;
- numPairs = p->numPairs;
- }
-
- numAvail = p->numAvail;
- if (numAvail < 2)
- {
- p->backRes = MARK_LIT;
- return 1;
- }
- if (numAvail > LZMA_MATCH_LEN_MAX)
- numAvail = LZMA_MATCH_LEN_MAX;
-
- data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
- repMaxIndex = 0;
-
- for (i = 0; i < LZMA_NUM_REPS; i++)
- {
- unsigned len;
- const Byte *data2;
- reps[i] = p->reps[i];
- data2 = data - reps[i];
- if (data[0] != data2[0] || data[1] != data2[1])
- {
- repLens[i] = 0;
- continue;
- }
- for (len = 2; len < numAvail && data[len] == data2[len]; len++)
- {}
- repLens[i] = len;
- if (len > repLens[repMaxIndex])
- repMaxIndex = i;
- }
-
- if (repLens[repMaxIndex] >= p->numFastBytes)
- {
- unsigned len;
- p->backRes = (UInt32)repMaxIndex;
- len = repLens[repMaxIndex];
- MOVE_POS(p, len - 1)
- return len;
- }
-
- matches = p->matches;
-
- if (mainLen >= p->numFastBytes)
- {
- p->backRes = matches[(size_t)numPairs - 1] + LZMA_NUM_REPS;
- MOVE_POS(p, mainLen - 1)
- return mainLen;
- }
-
- curByte = *data;
- matchByte = *(data - reps[0]);
-
- last = repLens[repMaxIndex];
- if (last <= mainLen)
- last = mainLen;
-
- if (last < 2 && curByte != matchByte)
- {
- p->backRes = MARK_LIT;
- return 1;
- }
-
- p->opt[0].state = (CState)p->state;
-
- posState = (position & p->pbMask);
-
- {
- const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
- p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) +
- (!IsLitState(p->state) ?
- LitEnc_Matched_GetPrice(probs, curByte, matchByte, p->ProbPrices) :
- LitEnc_GetPrice(probs, curByte, p->ProbPrices));
- }
-
- MakeAs_Lit(&p->opt[1]);
-
- matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]);
- repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]);
-
- // 18.06
- if (matchByte == curByte && repLens[0] == 0)
- {
- UInt32 shortRepPrice = repMatchPrice + GetPrice_ShortRep(p, p->state, posState);
- if (shortRepPrice < p->opt[1].price)
- {
- p->opt[1].price = shortRepPrice;
- MakeAs_ShortRep(&p->opt[1]);
- }
- if (last < 2)
- {
- p->backRes = p->opt[1].dist;
- return 1;
- }
- }
-
- p->opt[1].len = 1;
-
- p->opt[0].reps[0] = reps[0];
- p->opt[0].reps[1] = reps[1];
- p->opt[0].reps[2] = reps[2];
- p->opt[0].reps[3] = reps[3];
-
- // ---------- REP ----------
-
- for (i = 0; i < LZMA_NUM_REPS; i++)
- {
- unsigned repLen = repLens[i];
- UInt32 price;
- if (repLen < 2)
- continue;
- price = repMatchPrice + GetPrice_PureRep(p, i, p->state, posState);
- do
- {
- UInt32 price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState, repLen);
- COptimal *opt = &p->opt[repLen];
- if (price2 < opt->price)
- {
- opt->price = price2;
- opt->len = (UInt32)repLen;
- opt->dist = (UInt32)i;
- opt->extra = 0;
- }
- }
- while (--repLen >= 2);
- }
-
-
- // ---------- MATCH ----------
- {
- unsigned len = repLens[0] + 1;
- if (len <= mainLen)
- {
- unsigned offs = 0;
- UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]);
-
- if (len < 2)
- len = 2;
- else
- while (len > matches[offs])
- offs += 2;
-
- for (; ; len++)
- {
- COptimal *opt;
- UInt32 dist = matches[(size_t)offs + 1];
- UInt32 price = normalMatchPrice + GET_PRICE_LEN(&p->lenEnc, posState, len);
- unsigned lenToPosState = GetLenToPosState(len);
-
- if (dist < kNumFullDistances)
- price += p->distancesPrices[lenToPosState][dist & (kNumFullDistances - 1)];
- else
- {
- unsigned slot;
- GetPosSlot2(dist, slot);
- price += p->alignPrices[dist & kAlignMask];
- price += p->posSlotPrices[lenToPosState][slot];
- }
-
- opt = &p->opt[len];
-
- if (price < opt->price)
- {
- opt->price = price;
- opt->len = (UInt32)len;
- opt->dist = dist + LZMA_NUM_REPS;
- opt->extra = 0;
- }
-
- if (len == matches[offs])
- {
- offs += 2;
- if (offs == numPairs)
- break;
- }
- }
- }
- }
-
-
- cur = 0;
-
- #ifdef SHOW_STAT2
- /* if (position >= 0) */
- {
- unsigned i;
- printf("\n pos = %4X", position);
- for (i = cur; i <= last; i++)
- printf("\nprice[%4X] = %u", position - cur + i, p->opt[i].price);
- }
- #endif
- }
-
-
-
- // ---------- Optimal Parsing ----------
-
- for (;;)
- {
- unsigned numAvail;
- UInt32 numAvailFull;
- unsigned newLen, numPairs, prev, state, posState, startLen;
- UInt32 litPrice, matchPrice, repMatchPrice;
- BoolInt nextIsLit;
- Byte curByte, matchByte;
- const Byte *data;
- COptimal *curOpt, *nextOpt;
-
- if (++cur == last)
- break;
-
- // 18.06
- if (cur >= kNumOpts - 64)
- {
- unsigned j, best;
- UInt32 price = p->opt[cur].price;
- best = cur;
- for (j = cur + 1; j <= last; j++)
- {
- UInt32 price2 = p->opt[j].price;
- if (price >= price2)
- {
- price = price2;
- best = j;
- }
- }
- {
- unsigned delta = best - cur;
- if (delta != 0)
- {
- MOVE_POS(p, delta);
- }
- }
- cur = best;
- break;
- }
-
- newLen = ReadMatchDistances(p, &numPairs);
-
- if (newLen >= p->numFastBytes)
- {
- p->numPairs = numPairs;
- p->longestMatchLen = newLen;
- break;
- }
-
- curOpt = &p->opt[cur];
-
- position++;
-
- // we need that check here, if skip_items in p->opt are possible
- /*
- if (curOpt->price >= kInfinityPrice)
- continue;
- */
-
- prev = cur - curOpt->len;
-
- if (curOpt->len == 1)
- {
- state = (unsigned)p->opt[prev].state;
- if (IsShortRep(curOpt))
- state = kShortRepNextStates[state];
- else
- state = kLiteralNextStates[state];
- }
- else
- {
- const COptimal *prevOpt;
- UInt32 b0;
- UInt32 dist = curOpt->dist;
-
- if (curOpt->extra)
- {
- prev -= (unsigned)curOpt->extra;
- state = kState_RepAfterLit;
- if (curOpt->extra == 1)
- state = (dist < LZMA_NUM_REPS ? kState_RepAfterLit : kState_MatchAfterLit);
- }
- else
- {
- state = (unsigned)p->opt[prev].state;
- if (dist < LZMA_NUM_REPS)
- state = kRepNextStates[state];
- else
- state = kMatchNextStates[state];
- }
-
- prevOpt = &p->opt[prev];
- b0 = prevOpt->reps[0];
-
- if (dist < LZMA_NUM_REPS)
- {
- if (dist == 0)
- {
- reps[0] = b0;
- reps[1] = prevOpt->reps[1];
- reps[2] = prevOpt->reps[2];
- reps[3] = prevOpt->reps[3];
- }
- else
- {
- reps[1] = b0;
- b0 = prevOpt->reps[1];
- if (dist == 1)
- {
- reps[0] = b0;
- reps[2] = prevOpt->reps[2];
- reps[3] = prevOpt->reps[3];
- }
- else
- {
- reps[2] = b0;
- reps[0] = prevOpt->reps[dist];
- reps[3] = prevOpt->reps[dist ^ 1];
- }
- }
- }
- else
- {
- reps[0] = (dist - LZMA_NUM_REPS + 1);
- reps[1] = b0;
- reps[2] = prevOpt->reps[1];
- reps[3] = prevOpt->reps[2];
- }
- }
-
- curOpt->state = (CState)state;
- curOpt->reps[0] = reps[0];
- curOpt->reps[1] = reps[1];
- curOpt->reps[2] = reps[2];
- curOpt->reps[3] = reps[3];
-
- data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
- curByte = *data;
- matchByte = *(data - reps[0]);
-
- posState = (position & p->pbMask);
-
- /*
- The order of Price checks:
- < LIT
- <= SHORT_REP
- < LIT : REP_0
- < REP [ : LIT : REP_0 ]
- < MATCH [ : LIT : REP_0 ]
- */
-
- {
- UInt32 curPrice = curOpt->price;
- unsigned prob = p->isMatch[state][posState];
- matchPrice = curPrice + GET_PRICE_1(prob);
- litPrice = curPrice + GET_PRICE_0(prob);
- }
-
- nextOpt = &p->opt[(size_t)cur + 1];
- nextIsLit = False;
-
- // here we can allow skip_items in p->opt, if we don't check (nextOpt->price < kInfinityPrice)
- // 18.new.06
- if ((nextOpt->price < kInfinityPrice
- // && !IsLitState(state)
- && matchByte == curByte)
- || litPrice > nextOpt->price
- )
- litPrice = 0;
- else
- {
- const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
- litPrice += (!IsLitState(state) ?
- LitEnc_Matched_GetPrice(probs, curByte, matchByte, p->ProbPrices) :
- LitEnc_GetPrice(probs, curByte, p->ProbPrices));
-
- if (litPrice < nextOpt->price)
- {
- nextOpt->price = litPrice;
- nextOpt->len = 1;
- MakeAs_Lit(nextOpt);
- nextIsLit = True;
- }
- }
-
- repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]);
-
- numAvailFull = p->numAvail;
- {
- unsigned temp = kNumOpts - 1 - cur;
- if (numAvailFull > temp)
- numAvailFull = (UInt32)temp;
- }
-
- // 18.06
- // ---------- SHORT_REP ----------
- if (IsLitState(state)) // 18.new
- if (matchByte == curByte)
- if (repMatchPrice < nextOpt->price) // 18.new
- // if (numAvailFull < 2 || data[1] != *(data - reps[0] + 1))
- if (
- // nextOpt->price >= kInfinityPrice ||
- nextOpt->len < 2 // we can check nextOpt->len, if skip items are not allowed in p->opt
- || (nextOpt->dist != 0
- // && nextOpt->extra <= 1 // 17.old
- )
- )
- {
- UInt32 shortRepPrice = repMatchPrice + GetPrice_ShortRep(p, state, posState);
- // if (shortRepPrice <= nextOpt->price) // 17.old
- if (shortRepPrice < nextOpt->price) // 18.new
- {
- nextOpt->price = shortRepPrice;
- nextOpt->len = 1;
- MakeAs_ShortRep(nextOpt);
- nextIsLit = False;
- }
- }
-
- if (numAvailFull < 2)
- continue;
- numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes);
-
- // numAvail <= p->numFastBytes
-
- // ---------- LIT : REP_0 ----------
-
- if (!nextIsLit
- && litPrice != 0 // 18.new
- && matchByte != curByte
- && numAvailFull > 2)
- {
- const Byte *data2 = data - reps[0];
- if (data[1] == data2[1] && data[2] == data2[2])
- {
- unsigned len;
- unsigned limit = p->numFastBytes + 1;
- if (limit > numAvailFull)
- limit = numAvailFull;
- for (len = 3; len < limit && data[len] == data2[len]; len++)
- {}
-
- {
- unsigned state2 = kLiteralNextStates[state];
- unsigned posState2 = (position + 1) & p->pbMask;
- UInt32 price = litPrice + GetPrice_Rep_0(p, state2, posState2);
- {
- unsigned offset = cur + len;
-
- if (last < offset)
- last = offset;
-
- // do
- {
- UInt32 price2;
- COptimal *opt;
- len--;
- // price2 = price + GetPrice_Len_Rep_0(p, len, state2, posState2);
- price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len);
-
- opt = &p->opt[offset];
- // offset--;
- if (price2 < opt->price)
- {
- opt->price = price2;
- opt->len = (UInt32)len;
- opt->dist = 0;
- opt->extra = 1;
- }
- }
- // while (len >= 3);
- }
- }
- }
- }
-
- startLen = 2; /* speed optimization */
-
- {
- // ---------- REP ----------
- unsigned repIndex = 0; // 17.old
- // unsigned repIndex = IsLitState(state) ? 0 : 1; // 18.notused
- for (; repIndex < LZMA_NUM_REPS; repIndex++)
- {
- unsigned len;
- UInt32 price;
- const Byte *data2 = data - reps[repIndex];
- if (data[0] != data2[0] || data[1] != data2[1])
- continue;
-
- for (len = 2; len < numAvail && data[len] == data2[len]; len++)
- {}
-
- // if (len < startLen) continue; // 18.new: speed optimization
-
- {
- unsigned offset = cur + len;
- if (last < offset)
- last = offset;
- }
- {
- unsigned len2 = len;
- price = repMatchPrice + GetPrice_PureRep(p, repIndex, state, posState);
- do
- {
- UInt32 price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState, len2);
- COptimal *opt = &p->opt[cur + len2];
- if (price2 < opt->price)
- {
- opt->price = price2;
- opt->len = (UInt32)len2;
- opt->dist = (UInt32)repIndex;
- opt->extra = 0;
- }
- }
- while (--len2 >= 2);
- }
-
- if (repIndex == 0) startLen = len + 1; // 17.old
- // startLen = len + 1; // 18.new
-
- /* if (_maxMode) */
- {
- // ---------- REP : LIT : REP_0 ----------
- // numFastBytes + 1 + numFastBytes
-
- unsigned len2 = len + 1;
- unsigned limit = len2 + p->numFastBytes;
- if (limit > numAvailFull)
- limit = numAvailFull;
-
- len2 += 2;
- if (len2 <= limit)
- if (data[len2 - 2] == data2[len2 - 2])
- if (data[len2 - 1] == data2[len2 - 1])
- {
- unsigned state2 = kRepNextStates[state];
- unsigned posState2 = (position + len) & p->pbMask;
- price += GET_PRICE_LEN(&p->repLenEnc, posState, len)
- + GET_PRICE_0(p->isMatch[state2][posState2])
- + LitEnc_Matched_GetPrice(LIT_PROBS(position + len, data[(size_t)len - 1]),
- data[len], data2[len], p->ProbPrices);
-
- // state2 = kLiteralNextStates[state2];
- state2 = kState_LitAfterRep;
- posState2 = (posState2 + 1) & p->pbMask;
-
-
- price += GetPrice_Rep_0(p, state2, posState2);
-
- for (; len2 < limit && data[len2] == data2[len2]; len2++)
- {}
-
- len2 -= len;
- // if (len2 >= 3)
- {
- {
- unsigned offset = cur + len + len2;
-
- if (last < offset)
- last = offset;
- // do
- {
- UInt32 price2;
- COptimal *opt;
- len2--;
- // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2);
- price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len2);
-
- opt = &p->opt[offset];
- // offset--;
- if (price2 < opt->price)
- {
- opt->price = price2;
- opt->len = (UInt32)len2;
- opt->extra = (CExtra)(len + 1);
- opt->dist = (UInt32)repIndex;
- }
- }
- // while (len2 >= 3);
- }
- }
- }
- }
- }
- }
-
-
- // ---------- MATCH ----------
- /* for (unsigned len = 2; len <= newLen; len++) */
- if (newLen > numAvail)
- {
- newLen = numAvail;
- for (numPairs = 0; newLen > matches[numPairs]; numPairs += 2);
- matches[numPairs] = (UInt32)newLen;
- numPairs += 2;
- }
-
- // startLen = 2; /* speed optimization */
-
- if (newLen >= startLen)
- {
- UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]);
- UInt32 dist;
- unsigned offs, posSlot, len;
-
- {
- unsigned offset = cur + newLen;
- if (last < offset)
- last = offset;
- }
-
- offs = 0;
- while (startLen > matches[offs])
- offs += 2;
- dist = matches[(size_t)offs + 1];
-
- // if (dist >= kNumFullDistances)
- GetPosSlot2(dist, posSlot);
-
- for (len = /*2*/ startLen; ; len++)
- {
- UInt32 price = normalMatchPrice + GET_PRICE_LEN(&p->lenEnc, posState, len);
- {
- COptimal *opt;
- unsigned lenNorm = len - 2;
- lenNorm = GetLenToPosState2(lenNorm);
- if (dist < kNumFullDistances)
- price += p->distancesPrices[lenNorm][dist & (kNumFullDistances - 1)];
- else
- price += p->posSlotPrices[lenNorm][posSlot] + p->alignPrices[dist & kAlignMask];
-
- opt = &p->opt[cur + len];
- if (price < opt->price)
- {
- opt->price = price;
- opt->len = (UInt32)len;
- opt->dist = dist + LZMA_NUM_REPS;
- opt->extra = 0;
- }
- }
-
- if (len == matches[offs])
- {
- // if (p->_maxMode) {
- // MATCH : LIT : REP_0
-
- const Byte *data2 = data - dist - 1;
- unsigned len2 = len + 1;
- unsigned limit = len2 + p->numFastBytes;
- if (limit > numAvailFull)
- limit = numAvailFull;
-
- len2 += 2;
- if (len2 <= limit)
- if (data[len2 - 2] == data2[len2 - 2])
- if (data[len2 - 1] == data2[len2 - 1])
- {
- for (; len2 < limit && data[len2] == data2[len2]; len2++)
- {}
-
- len2 -= len;
-
- // if (len2 >= 3)
- {
- unsigned state2 = kMatchNextStates[state];
- unsigned posState2 = (position + len) & p->pbMask;
- unsigned offset;
- price += GET_PRICE_0(p->isMatch[state2][posState2]);
- price += LitEnc_Matched_GetPrice(LIT_PROBS(position + len, data[(size_t)len - 1]),
- data[len], data2[len], p->ProbPrices);
-
- // state2 = kLiteralNextStates[state2];
- state2 = kState_LitAfterMatch;
-
- posState2 = (posState2 + 1) & p->pbMask;
- price += GetPrice_Rep_0(p, state2, posState2);
-
- offset = cur + len + len2;
-
- if (last < offset)
- last = offset;
- // do
- {
- UInt32 price2;
- COptimal *opt;
- len2--;
- // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2);
- price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len2);
- opt = &p->opt[offset];
- // offset--;
- if (price2 < opt->price)
- {
- opt->price = price2;
- opt->len = (UInt32)len2;
- opt->extra = (CExtra)(len + 1);
- opt->dist = dist + LZMA_NUM_REPS;
- }
- }
- // while (len2 >= 3);
- }
-
- }
-
- offs += 2;
- if (offs == numPairs)
- break;
- dist = matches[(size_t)offs + 1];
- // if (dist >= kNumFullDistances)
- GetPosSlot2(dist, posSlot);
- }
- }
- }
- }
-
- do
- p->opt[last].price = kInfinityPrice;
- while (--last);
-
- return Backward(p, cur);
-}
-
-
-
-#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist))
-
-
-
-static unsigned GetOptimumFast(CLzmaEnc *p)
-{
- UInt32 numAvail, mainDist;
- unsigned mainLen, numPairs, repIndex, repLen, i;
- const Byte *data;
-
- if (p->additionalOffset == 0)
- mainLen = ReadMatchDistances(p, &numPairs);
- else
- {
- mainLen = p->longestMatchLen;
- numPairs = p->numPairs;
- }
-
- numAvail = p->numAvail;
- p->backRes = MARK_LIT;
- if (numAvail < 2)
- return 1;
- // if (mainLen < 2 && p->state == 0) return 1; // 18.06.notused
- if (numAvail > LZMA_MATCH_LEN_MAX)
- numAvail = LZMA_MATCH_LEN_MAX;
- data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
- repLen = repIndex = 0;
-
- for (i = 0; i < LZMA_NUM_REPS; i++)
- {
- unsigned len;
- const Byte *data2 = data - p->reps[i];
- if (data[0] != data2[0] || data[1] != data2[1])
- continue;
- for (len = 2; len < numAvail && data[len] == data2[len]; len++)
- {}
- if (len >= p->numFastBytes)
- {
- p->backRes = (UInt32)i;
- MOVE_POS(p, len - 1)
- return len;
- }
- if (len > repLen)
- {
- repIndex = i;
- repLen = len;
- }
- }
-
- if (mainLen >= p->numFastBytes)
- {
- p->backRes = p->matches[(size_t)numPairs - 1] + LZMA_NUM_REPS;
- MOVE_POS(p, mainLen - 1)
- return mainLen;
- }
-
- mainDist = 0; /* for GCC */
-
- if (mainLen >= 2)
- {
- mainDist = p->matches[(size_t)numPairs - 1];
- while (numPairs > 2)
- {
- UInt32 dist2;
- if (mainLen != p->matches[(size_t)numPairs - 4] + 1)
- break;
- dist2 = p->matches[(size_t)numPairs - 3];
- if (!ChangePair(dist2, mainDist))
- break;
- numPairs -= 2;
- mainLen--;
- mainDist = dist2;
- }
- if (mainLen == 2 && mainDist >= 0x80)
- mainLen = 1;
- }
-
- if (repLen >= 2)
- if ( repLen + 1 >= mainLen
- || (repLen + 2 >= mainLen && mainDist >= (1 << 9))
- || (repLen + 3 >= mainLen && mainDist >= (1 << 15)))
- {
- p->backRes = (UInt32)repIndex;
- MOVE_POS(p, repLen - 1)
- return repLen;
- }
-
- if (mainLen < 2 || numAvail <= 2)
- return 1;
-
- {
- unsigned len1 = ReadMatchDistances(p, &p->numPairs);
- p->longestMatchLen = len1;
-
- if (len1 >= 2)
- {
- UInt32 newDist = p->matches[(size_t)p->numPairs - 1];
- if ( (len1 >= mainLen && newDist < mainDist)
- || (len1 == mainLen + 1 && !ChangePair(mainDist, newDist))
- || (len1 > mainLen + 1)
- || (len1 + 1 >= mainLen && mainLen >= 3 && ChangePair(newDist, mainDist)))
- return 1;
- }
- }
-
- data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
-
- for (i = 0; i < LZMA_NUM_REPS; i++)
- {
- unsigned len, limit;
- const Byte *data2 = data - p->reps[i];
- if (data[0] != data2[0] || data[1] != data2[1])
- continue;
- limit = mainLen - 1;
- for (len = 2;; len++)
- {
- if (len >= limit)
- return 1;
- if (data[len] != data2[len])
- break;
- }
- }
-
- p->backRes = mainDist + LZMA_NUM_REPS;
- if (mainLen != 2)
- {
- MOVE_POS(p, mainLen - 2)
- }
- return mainLen;
-}
-
-
-
-
-static void WriteEndMarker(CLzmaEnc *p, unsigned posState)
-{
- UInt32 range;
- range = p->rc.range;
- {
- UInt32 ttt, newBound;
- CLzmaProb *prob = &p->isMatch[p->state][posState];
- RC_BIT_PRE(&p->rc, prob)
- RC_BIT_1(&p->rc, prob)
- prob = &p->isRep[p->state];
- RC_BIT_PRE(&p->rc, prob)
- RC_BIT_0(&p->rc, prob)
- }
- p->state = kMatchNextStates[p->state];
-
- p->rc.range = range;
- LenEnc_Encode(&p->lenProbs, &p->rc, 0, posState);
- range = p->rc.range;
-
- {
- // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[0], (1 << kNumPosSlotBits) - 1);
- CLzmaProb *probs = p->posSlotEncoder[0];
- unsigned m = 1;
- do
- {
- UInt32 ttt, newBound;
- RC_BIT_PRE(p, probs + m)
- RC_BIT_1(&p->rc, probs + m);
- m = (m << 1) + 1;
- }
- while (m < (1 << kNumPosSlotBits));
- }
- {
- // RangeEnc_EncodeDirectBits(&p->rc, ((UInt32)1 << (30 - kNumAlignBits)) - 1, 30 - kNumAlignBits); UInt32 range = p->range;
- unsigned numBits = 30 - kNumAlignBits;
- do
- {
- range >>= 1;
- p->rc.low += range;
- RC_NORM(&p->rc)
- }
- while (--numBits);
- }
-
- {
- // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
- CLzmaProb *probs = p->posAlignEncoder;
- unsigned m = 1;
- do
- {
- UInt32 ttt, newBound;
- RC_BIT_PRE(p, probs + m)
- RC_BIT_1(&p->rc, probs + m);
- m = (m << 1) + 1;
- }
- while (m < kAlignTableSize);
- }
- p->rc.range = range;
-}
-
-
-static SRes CheckErrors(CLzmaEnc *p)
-{
- if (p->result != SZ_OK)
- return p->result;
- if (p->rc.res != SZ_OK)
- p->result = SZ_ERROR_WRITE;
- if (p->matchFinderBase.result != SZ_OK)
- p->result = SZ_ERROR_READ;
- if (p->result != SZ_OK)
- p->finished = True;
- return p->result;
-}
-
-
-MY_NO_INLINE static SRes Flush(CLzmaEnc *p, UInt32 nowPos)
-{
- /* ReleaseMFStream(); */
- p->finished = True;
- if (p->writeEndMark)
- WriteEndMarker(p, nowPos & p->pbMask);
- RangeEnc_FlushData(&p->rc);
- RangeEnc_FlushStream(&p->rc);
- return CheckErrors(p);
-}
-
-
-MY_NO_INLINE static void FillAlignPrices(CLzmaEnc *p)
-{
- unsigned i;
- const CProbPrice *ProbPrices = p->ProbPrices;
- const CLzmaProb *probs = p->posAlignEncoder;
- // p->alignPriceCount = 0;
- for (i = 0; i < kAlignTableSize / 2; i++)
- {
- UInt32 price = 0;
- unsigned sym = i;
- unsigned m = 1;
- unsigned bit;
- UInt32 prob;
- bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit;
- bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit;
- bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit;
- prob = probs[m];
- p->alignPrices[i ] = price + GET_PRICEa_0(prob);
- p->alignPrices[i + 8] = price + GET_PRICEa_1(prob);
- // p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
- }
-}
-
-
-MY_NO_INLINE static void FillDistancesPrices(CLzmaEnc *p)
-{
- // int y; for (y = 0; y < 100; y++) {
-
- UInt32 tempPrices[kNumFullDistances];
- unsigned i, lps;
-
- const CProbPrice *ProbPrices = p->ProbPrices;
- p->matchPriceCount = 0;
-
- for (i = kStartPosModelIndex / 2; i < kNumFullDistances / 2; i++)
- {
- unsigned posSlot = GetPosSlot1(i);
- unsigned footerBits = (posSlot >> 1) - 1;
- unsigned base = ((2 | (posSlot & 1)) << footerBits);
- const CLzmaProb *probs = p->posEncoders + (size_t)base * 2;
- // tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base, footerBits, i - base, p->ProbPrices);
- UInt32 price = 0;
- unsigned m = 1;
- unsigned sym = i;
- unsigned offset = (unsigned)1 << footerBits;
- base += i;
-
- if (footerBits)
- do
- {
- unsigned bit = sym & 1;
- sym >>= 1;
- price += GET_PRICEa(probs[m], bit);
- m = (m << 1) + bit;
- }
- while (--footerBits);
-
- {
- unsigned prob = probs[m];
- tempPrices[base ] = price + GET_PRICEa_0(prob);
- tempPrices[base + offset] = price + GET_PRICEa_1(prob);
- }
- }
-
- for (lps = 0; lps < kNumLenToPosStates; lps++)
- {
- unsigned slot;
- unsigned distTableSize2 = (p->distTableSize + 1) >> 1;
- UInt32 *posSlotPrices = p->posSlotPrices[lps];
- const CLzmaProb *probs = p->posSlotEncoder[lps];
-
- for (slot = 0; slot < distTableSize2; slot++)
- {
- // posSlotPrices[slot] = RcTree_GetPrice(encoder, kNumPosSlotBits, slot, p->ProbPrices);
- UInt32 price;
- unsigned bit;
- unsigned sym = slot + (1 << (kNumPosSlotBits - 1));
- unsigned prob;
- bit = sym & 1; sym >>= 1; price = GET_PRICEa(probs[sym], bit);
- bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit);
- bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit);
- bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit);
- bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit);
- prob = probs[(size_t)slot + (1 << (kNumPosSlotBits - 1))];
- posSlotPrices[(size_t)slot * 2 ] = price + GET_PRICEa_0(prob);
- posSlotPrices[(size_t)slot * 2 + 1] = price + GET_PRICEa_1(prob);
- }
-
- {
- UInt32 delta = ((UInt32)((kEndPosModelIndex / 2 - 1) - kNumAlignBits) << kNumBitPriceShiftBits);
- for (slot = kEndPosModelIndex / 2; slot < distTableSize2; slot++)
- {
- posSlotPrices[(size_t)slot * 2 ] += delta;
- posSlotPrices[(size_t)slot * 2 + 1] += delta;
- delta += ((UInt32)1 << kNumBitPriceShiftBits);
- }
- }
-
- {
- UInt32 *dp = p->distancesPrices[lps];
-
- dp[0] = posSlotPrices[0];
- dp[1] = posSlotPrices[1];
- dp[2] = posSlotPrices[2];
- dp[3] = posSlotPrices[3];
-
- for (i = 4; i < kNumFullDistances; i += 2)
- {
- UInt32 slotPrice = posSlotPrices[GetPosSlot1(i)];
- dp[i ] = slotPrice + tempPrices[i];
- dp[i + 1] = slotPrice + tempPrices[i + 1];
- }
- }
- }
- // }
-}
-
-
-
-void LzmaEnc_Construct(CLzmaEnc *p)
-{
- RangeEnc_Construct(&p->rc);
- MatchFinder_Construct(&p->matchFinderBase);
-
- #ifndef _7ZIP_ST
- MatchFinderMt_Construct(&p->matchFinderMt);
- p->matchFinderMt.MatchFinder = &p->matchFinderBase;
- #endif
-
- {
- CLzmaEncProps props;
- LzmaEncProps_Init(&props);
- LzmaEnc_SetProps(p, &props);
- }
-
- #ifndef LZMA_LOG_BSR
- LzmaEnc_FastPosInit(p->g_FastPos);
- #endif
-
- LzmaEnc_InitPriceTables(p->ProbPrices);
- p->litProbs = NULL;
- p->saveState.litProbs = NULL;
-
-}
-
-CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc)
-{
- void *p;
- p = ISzAlloc_Alloc(alloc, sizeof(CLzmaEnc));
- if (p)
- LzmaEnc_Construct((CLzmaEnc *)p);
- return p;
-}
-
-void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAllocPtr alloc)
-{
- ISzAlloc_Free(alloc, p->litProbs);
- ISzAlloc_Free(alloc, p->saveState.litProbs);
- p->litProbs = NULL;
- p->saveState.litProbs = NULL;
-}
-
-void LzmaEnc_Destruct(CLzmaEnc *p, ISzAllocPtr alloc, ISzAllocPtr allocBig)
-{
- #ifndef _7ZIP_ST
- MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
- #endif
-
- MatchFinder_Free(&p->matchFinderBase, allocBig);
- LzmaEnc_FreeLits(p, alloc);
- RangeEnc_Free(&p->rc, alloc);
-}
-
-void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig)
-{
- LzmaEnc_Destruct((CLzmaEnc *)p, alloc, allocBig);
- ISzAlloc_Free(alloc, p);
-}
-
-
-static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, UInt32 maxPackSize, UInt32 maxUnpackSize)
-{
- UInt32 nowPos32, startPos32;
- if (p->needInit)
- {
- p->matchFinder.Init(p->matchFinderObj);
- p->needInit = 0;
- }
-
- if (p->finished)
- return p->result;
- RINOK(CheckErrors(p));
-
- nowPos32 = (UInt32)p->nowPos64;
- startPos32 = nowPos32;
-
- if (p->nowPos64 == 0)
- {
- unsigned numPairs;
- Byte curByte;
- if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
- return Flush(p, nowPos32);
- ReadMatchDistances(p, &numPairs);
- RangeEnc_EncodeBit_0(&p->rc, &p->isMatch[kState_Start][0]);
- // p->state = kLiteralNextStates[p->state];
- curByte = *(p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset);
- LitEnc_Encode(&p->rc, p->litProbs, curByte);
- p->additionalOffset--;
- nowPos32++;
- }
-
- if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0)
-
- for (;;)
- {
- UInt32 dist;
- unsigned len, posState;
- UInt32 range, ttt, newBound;
- CLzmaProb *probs;
-
- if (p->fastMode)
- len = GetOptimumFast(p);
- else
- {
- unsigned oci = p->optCur;
- if (p->optEnd == oci)
- len = GetOptimum(p, nowPos32);
- else
- {
- const COptimal *opt = &p->opt[oci];
- len = opt->len;
- p->backRes = opt->dist;
- p->optCur = oci + 1;
- }
- }
-
- posState = (unsigned)nowPos32 & p->pbMask;
- range = p->rc.range;
- probs = &p->isMatch[p->state][posState];
-
- RC_BIT_PRE(&p->rc, probs)
-
- dist = p->backRes;
-
- #ifdef SHOW_STAT2
- printf("\n pos = %6X, len = %3u pos = %6u", nowPos32, len, dist);
- #endif
-
- if (dist == MARK_LIT)
- {
- Byte curByte;
- const Byte *data;
- unsigned state;
-
- RC_BIT_0(&p->rc, probs);
- p->rc.range = range;
- data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
- probs = LIT_PROBS(nowPos32, *(data - 1));
- curByte = *data;
- state = p->state;
- p->state = kLiteralNextStates[state];
- if (IsLitState(state))
- LitEnc_Encode(&p->rc, probs, curByte);
- else
- LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0]));
- }
- else
- {
- RC_BIT_1(&p->rc, probs);
- probs = &p->isRep[p->state];
- RC_BIT_PRE(&p->rc, probs)
-
- if (dist < LZMA_NUM_REPS)
- {
- RC_BIT_1(&p->rc, probs);
- probs = &p->isRepG0[p->state];
- RC_BIT_PRE(&p->rc, probs)
- if (dist == 0)
- {
- RC_BIT_0(&p->rc, probs);
- probs = &p->isRep0Long[p->state][posState];
- RC_BIT_PRE(&p->rc, probs)
- if (len != 1)
- {
- RC_BIT_1_BASE(&p->rc, probs);
- }
- else
- {
- RC_BIT_0_BASE(&p->rc, probs);
- p->state = kShortRepNextStates[p->state];
- }
- }
- else
- {
- RC_BIT_1(&p->rc, probs);
- probs = &p->isRepG1[p->state];
- RC_BIT_PRE(&p->rc, probs)
- if (dist == 1)
- {
- RC_BIT_0_BASE(&p->rc, probs);
- dist = p->reps[1];
- }
- else
- {
- RC_BIT_1(&p->rc, probs);
- probs = &p->isRepG2[p->state];
- RC_BIT_PRE(&p->rc, probs)
- if (dist == 2)
- {
- RC_BIT_0_BASE(&p->rc, probs);
- dist = p->reps[2];
- }
- else
- {
- RC_BIT_1_BASE(&p->rc, probs);
- dist = p->reps[3];
- p->reps[3] = p->reps[2];
- }
- p->reps[2] = p->reps[1];
- }
- p->reps[1] = p->reps[0];
- p->reps[0] = dist;
- }
-
- RC_NORM(&p->rc)
-
- p->rc.range = range;
-
- if (len != 1)
- {
- LenEnc_Encode(&p->repLenProbs, &p->rc, len - LZMA_MATCH_LEN_MIN, posState);
- --p->repLenEncCounter;
- p->state = kRepNextStates[p->state];
- }
- }
- else
- {
- unsigned posSlot;
- RC_BIT_0(&p->rc, probs);
- p->rc.range = range;
- p->state = kMatchNextStates[p->state];
-
- LenEnc_Encode(&p->lenProbs, &p->rc, len - LZMA_MATCH_LEN_MIN, posState);
- // --p->lenEnc.counter;
-
- dist -= LZMA_NUM_REPS;
- p->reps[3] = p->reps[2];
- p->reps[2] = p->reps[1];
- p->reps[1] = p->reps[0];
- p->reps[0] = dist + 1;
-
- p->matchPriceCount++;
- GetPosSlot(dist, posSlot);
- // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], posSlot);
- {
- UInt32 sym = (UInt32)posSlot + (1 << kNumPosSlotBits);
- range = p->rc.range;
- probs = p->posSlotEncoder[GetLenToPosState(len)];
- do
- {
- CLzmaProb *prob = probs + (sym >> kNumPosSlotBits);
- UInt32 bit = (sym >> (kNumPosSlotBits - 1)) & 1;
- sym <<= 1;
- RC_BIT(&p->rc, prob, bit);
- }
- while (sym < (1 << kNumPosSlotBits * 2));
- p->rc.range = range;
- }
-
- if (dist >= kStartPosModelIndex)
- {
- unsigned footerBits = ((posSlot >> 1) - 1);
-
- if (dist < kNumFullDistances)
- {
- unsigned base = ((2 | (posSlot & 1)) << footerBits);
- RcTree_ReverseEncode(&p->rc, p->posEncoders + base, footerBits, (unsigned)(dist /* - base */));
- }
- else
- {
- UInt32 pos2 = (dist | 0xF) << (32 - footerBits);
- range = p->rc.range;
- // RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
- /*
- do
- {
- range >>= 1;
- p->rc.low += range & (0 - ((dist >> --footerBits) & 1));
- RC_NORM(&p->rc)
- }
- while (footerBits > kNumAlignBits);
- */
- do
- {
- range >>= 1;
- p->rc.low += range & (0 - (pos2 >> 31));
- pos2 += pos2;
- RC_NORM(&p->rc)
- }
- while (pos2 != 0xF0000000);
-
-
- // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
-
- {
- unsigned m = 1;
- unsigned bit;
- bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); m = (m << 1) + bit;
- bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); m = (m << 1) + bit;
- bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit); m = (m << 1) + bit;
- bit = dist & 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit);
- p->rc.range = range;
- // p->alignPriceCount++;
- }
- }
- }
- }
- }
-
- nowPos32 += (UInt32)len;
- p->additionalOffset -= len;
-
- if (p->additionalOffset == 0)
- {
- UInt32 processed;
-
- if (!p->fastMode)
- {
- /*
- if (p->alignPriceCount >= 16) // kAlignTableSize
- FillAlignPrices(p);
- if (p->matchPriceCount >= 128)
- FillDistancesPrices(p);
- if (p->lenEnc.counter <= 0)
- LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices);
- */
- if (p->matchPriceCount >= 64)
- {
- FillAlignPrices(p);
- // { int y; for (y = 0; y < 100; y++) {
- FillDistancesPrices(p);
- // }}
- LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices);
- }
- if (p->repLenEncCounter <= 0)
- {
- p->repLenEncCounter = REP_LEN_COUNT;
- LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, &p->repLenProbs, p->ProbPrices);
- }
- }
-
- if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
- break;
- processed = nowPos32 - startPos32;
-
- if (maxPackSize)
- {
- if (processed + kNumOpts + 300 >= maxUnpackSize
- || RangeEnc_GetProcessed_sizet(&p->rc) + kPackReserve >= maxPackSize)
- break;
- }
- else if (processed >= (1 << 17))
- {
- p->nowPos64 += nowPos32 - startPos32;
- return CheckErrors(p);
- }
- }
- }
-
- p->nowPos64 += nowPos32 - startPos32;
- return Flush(p, nowPos32);
-}
-
-
-
-#define kBigHashDicLimit ((UInt32)1 << 24)
-
-static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig)
-{
- UInt32 beforeSize = kNumOpts;
- if (!RangeEnc_Alloc(&p->rc, alloc))
- return SZ_ERROR_MEM;
-
- #ifndef _7ZIP_ST
- p->mtMode = (p->multiThread && !p->fastMode && (p->matchFinderBase.btMode != 0));
- #endif
-
- {
- unsigned lclp = p->lc + p->lp;
- if (!p->litProbs || !p->saveState.litProbs || p->lclp != lclp)
- {
- LzmaEnc_FreeLits(p, alloc);
- p->litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb));
- p->saveState.litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb));
- if (!p->litProbs || !p->saveState.litProbs)
- {
- LzmaEnc_FreeLits(p, alloc);
- return SZ_ERROR_MEM;
- }
- p->lclp = lclp;
- }
- }
-
- p->matchFinderBase.bigHash = (Byte)(p->dictSize > kBigHashDicLimit ? 1 : 0);
-
- if (beforeSize + p->dictSize < keepWindowSize)
- beforeSize = keepWindowSize - p->dictSize;
-
- #ifndef _7ZIP_ST
- if (p->mtMode)
- {
- RINOK(MatchFinderMt_Create(&p->matchFinderMt, p->dictSize, beforeSize, p->numFastBytes,
- LZMA_MATCH_LEN_MAX
- + 1 /* 18.04 */
- , allocBig));
- p->matchFinderObj = &p->matchFinderMt;
- p->matchFinderBase.bigHash = (Byte)(
- (p->dictSize > kBigHashDicLimit && p->matchFinderBase.hashMask >= 0xFFFFFF) ? 1 : 0);
- MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder);
- }
- else
- #endif
- {
- if (!MatchFinder_Create(&p->matchFinderBase, p->dictSize, beforeSize, p->numFastBytes, LZMA_MATCH_LEN_MAX, allocBig))
- return SZ_ERROR_MEM;
- p->matchFinderObj = &p->matchFinderBase;
- MatchFinder_CreateVTable(&p->matchFinderBase, &p->matchFinder);
- }
-
- return SZ_OK;
-}
-
-void LzmaEnc_Init(CLzmaEnc *p)
-{
- unsigned i;
- p->state = 0;
- p->reps[0] =
- p->reps[1] =
- p->reps[2] =
- p->reps[3] = 1;
-
- RangeEnc_Init(&p->rc);
-
- for (i = 0; i < (1 << kNumAlignBits); i++)
- p->posAlignEncoder[i] = kProbInitValue;
-
- for (i = 0; i < kNumStates; i++)
- {
- unsigned j;
- for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++)
- {
- p->isMatch[i][j] = kProbInitValue;
- p->isRep0Long[i][j] = kProbInitValue;
- }
- p->isRep[i] = kProbInitValue;
- p->isRepG0[i] = kProbInitValue;
- p->isRepG1[i] = kProbInitValue;
- p->isRepG2[i] = kProbInitValue;
- }
-
- {
- for (i = 0; i < kNumLenToPosStates; i++)
- {
- CLzmaProb *probs = p->posSlotEncoder[i];
- unsigned j;
- for (j = 0; j < (1 << kNumPosSlotBits); j++)
- probs[j] = kProbInitValue;
- }
- }
- {
- for (i = 0; i < kNumFullDistances; i++)
- p->posEncoders[i] = kProbInitValue;
- }
-
- {
- UInt32 num = (UInt32)0x300 << (p->lp + p->lc);
- UInt32 k;
- CLzmaProb *probs = p->litProbs;
- for (k = 0; k < num; k++)
- probs[k] = kProbInitValue;
- }
-
-
- LenEnc_Init(&p->lenProbs);
- LenEnc_Init(&p->repLenProbs);
-
- p->optEnd = 0;
- p->optCur = 0;
-
- {
- for (i = 0; i < kNumOpts; i++)
- p->opt[i].price = kInfinityPrice;
- }
-
- p->additionalOffset = 0;
-
- p->pbMask = (1 << p->pb) - 1;
- p->lpMask = ((UInt32)0x100 << p->lp) - ((unsigned)0x100 >> p->lc);
-}
-
-
-void LzmaEnc_InitPrices(CLzmaEnc *p)
-{
- if (!p->fastMode)
- {
- FillDistancesPrices(p);
- FillAlignPrices(p);
- }
-
- p->lenEnc.tableSize =
- p->repLenEnc.tableSize =
- p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN;
-
- p->repLenEncCounter = REP_LEN_COUNT;
-
- LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices);
- LenPriceEnc_UpdateTables(&p->repLenEnc, 1 << p->pb, &p->repLenProbs, p->ProbPrices);
-}
-
-static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig)
-{
- unsigned i;
- for (i = kEndPosModelIndex / 2; i < kDicLogSizeMax; i++)
- if (p->dictSize <= ((UInt32)1 << i))
- break;
- p->distTableSize = i * 2;
-
- p->finished = False;
- p->result = SZ_OK;
- RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig));
- LzmaEnc_Init(p);
- LzmaEnc_InitPrices(p);
- p->nowPos64 = 0;
- return SZ_OK;
-}
-
-static SRes LzmaEnc_Prepare(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream,
- ISzAllocPtr alloc, ISzAllocPtr allocBig)
-{
- CLzmaEnc *p = (CLzmaEnc *)pp;
- p->matchFinderBase.stream = inStream;
- p->needInit = 1;
- p->rc.outStream = outStream;
- return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
-}
-
-SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle pp,
- ISeqInStream *inStream, UInt32 keepWindowSize,
- ISzAllocPtr alloc, ISzAllocPtr allocBig)
-{
- CLzmaEnc *p = (CLzmaEnc *)pp;
- p->matchFinderBase.stream = inStream;
- p->needInit = 1;
- return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
-}
-
-static void LzmaEnc_SetInputBuf(CLzmaEnc *p, const Byte *src, SizeT srcLen)
-{
- p->matchFinderBase.directInput = 1;
- p->matchFinderBase.bufferBase = (Byte *)src;
- p->matchFinderBase.directInputRem = srcLen;
-}
-
-SRes LzmaEnc_MemPrepare(CLzmaEncHandle pp, const Byte *src, SizeT srcLen,
- UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig)
-{
- CLzmaEnc *p = (CLzmaEnc *)pp;
- LzmaEnc_SetInputBuf(p, src, srcLen);
- p->needInit = 1;
-
- LzmaEnc_SetDataSize(pp, srcLen);
- return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
-}
-
-void LzmaEnc_Finish(CLzmaEncHandle pp)
-{
- #ifndef _7ZIP_ST
- CLzmaEnc *p = (CLzmaEnc *)pp;
- if (p->mtMode)
- MatchFinderMt_ReleaseStream(&p->matchFinderMt);
- #else
- UNUSED_VAR(pp);
- #endif
-}
-
-
-typedef struct
-{
- ISeqOutStream vt;
- Byte *data;
- SizeT rem;
- BoolInt overflow;
-} CLzmaEnc_SeqOutStreamBuf;
-
-static size_t SeqOutStreamBuf_Write(const ISeqOutStream *pp, const void *data, size_t size)
-{
- CLzmaEnc_SeqOutStreamBuf *p = CONTAINER_FROM_VTBL(pp, CLzmaEnc_SeqOutStreamBuf, vt);
- if (p->rem < size)
- {
- size = p->rem;
- p->overflow = True;
- }
- memcpy(p->data, data, size);
- p->rem -= size;
- p->data += size;
- return size;
-}
-
-
-UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle pp)
-{
- const CLzmaEnc *p = (CLzmaEnc *)pp;
- return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
-}
-
-
-const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle pp)
-{
- const CLzmaEnc *p = (CLzmaEnc *)pp;
- return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
-}
-
-
-SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle pp, BoolInt reInit,
- Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
-{
- CLzmaEnc *p = (CLzmaEnc *)pp;
- UInt64 nowPos64;
- SRes res;
- CLzmaEnc_SeqOutStreamBuf outStream;
-
- outStream.vt.Write = SeqOutStreamBuf_Write;
- outStream.data = dest;
- outStream.rem = *destLen;
- outStream.overflow = False;
-
- p->writeEndMark = False;
- p->finished = False;
- p->result = SZ_OK;
-
- if (reInit)
- LzmaEnc_Init(p);
- LzmaEnc_InitPrices(p);
-
- nowPos64 = p->nowPos64;
- RangeEnc_Init(&p->rc);
- p->rc.outStream = &outStream.vt;
-
- if (desiredPackSize == 0)
- return SZ_ERROR_OUTPUT_EOF;
-
- res = LzmaEnc_CodeOneBlock(p, desiredPackSize, *unpackSize);
-
- *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
- *destLen -= outStream.rem;
- if (outStream.overflow)
- return SZ_ERROR_OUTPUT_EOF;
-
- return res;
-}
-
-
-static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgress *progress)
-{
- SRes res = SZ_OK;
-
- #ifndef _7ZIP_ST
- Byte allocaDummy[0x300];
- allocaDummy[0] = 0;
- allocaDummy[1] = allocaDummy[0];
- #endif
-
- for (;;)
- {
- res = LzmaEnc_CodeOneBlock(p, 0, 0);
- if (res != SZ_OK || p->finished)
- break;
- if (progress)
- {
- res = ICompressProgress_Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc));
- if (res != SZ_OK)
- {
- res = SZ_ERROR_PROGRESS;
- break;
- }
- }
- }
-
- LzmaEnc_Finish(p);
-
- /*
- if (res == SZ_OK && !Inline_MatchFinder_IsFinishedOK(&p->matchFinderBase))
- res = SZ_ERROR_FAIL;
- }
- */
-
- return res;
-}
-
-
-SRes LzmaEnc_Encode(CLzmaEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress,
- ISzAllocPtr alloc, ISzAllocPtr allocBig)
-{
- RINOK(LzmaEnc_Prepare(pp, outStream, inStream, alloc, allocBig));
- return LzmaEnc_Encode2((CLzmaEnc *)pp, progress);
-}
-
-
-SRes LzmaEnc_WriteProperties(CLzmaEncHandle pp, Byte *props, SizeT *size)
-{
- CLzmaEnc *p = (CLzmaEnc *)pp;
- unsigned i;
- UInt32 dictSize = p->dictSize;
- if (*size < LZMA_PROPS_SIZE)
- return SZ_ERROR_PARAM;
- *size = LZMA_PROPS_SIZE;
- props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc);
-
- if (dictSize >= ((UInt32)1 << 22))
- {
- UInt32 kDictMask = ((UInt32)1 << 20) - 1;
- if (dictSize < (UInt32)0xFFFFFFFF - kDictMask)
- dictSize = (dictSize + kDictMask) & ~kDictMask;
- }
- else for (i = 11; i <= 30; i++)
- {
- if (dictSize <= ((UInt32)2 << i)) { dictSize = (2 << i); break; }
- if (dictSize <= ((UInt32)3 << i)) { dictSize = (3 << i); break; }
- }
-
- for (i = 0; i < 4; i++)
- props[1 + i] = (Byte)(dictSize >> (8 * i));
- return SZ_OK;
-}
-
-
-unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle pp)
-{
- return ((CLzmaEnc *)pp)->writeEndMark;
-}
-
-
-SRes LzmaEnc_MemEncode(CLzmaEncHandle pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
- int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig)
-{
- SRes res;
- CLzmaEnc *p = (CLzmaEnc *)pp;
-
- CLzmaEnc_SeqOutStreamBuf outStream;
-
- outStream.vt.Write = SeqOutStreamBuf_Write;
- outStream.data = dest;
- outStream.rem = *destLen;
- outStream.overflow = False;
-
- p->writeEndMark = writeEndMark;
- p->rc.outStream = &outStream.vt;
-
- res = LzmaEnc_MemPrepare(pp, src, srcLen, 0, alloc, allocBig);
-
- if (res == SZ_OK)
- {
- res = LzmaEnc_Encode2(p, progress);
- if (res == SZ_OK && p->nowPos64 != srcLen)
- res = SZ_ERROR_FAIL;
- }
-
- *destLen -= outStream.rem;
- if (outStream.overflow)
- return SZ_ERROR_OUTPUT_EOF;
- return res;
-}
-
-
-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
- const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
- ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig)
-{
- CLzmaEnc *p = (CLzmaEnc *)LzmaEnc_Create(alloc);
- SRes res;
- if (!p)
- return SZ_ERROR_MEM;
-
- res = LzmaEnc_SetProps(p, props);
- if (res == SZ_OK)
- {
- res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
- if (res == SZ_OK)
- res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
- writeEndMark, progress, alloc, allocBig);
- }
-
- LzmaEnc_Destroy(p, alloc, allocBig);
- return res;
-}
+/* LzmaEnc.c -- LZMA Encoder
+2023-04-13: Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+/* #define SHOW_STAT */
+/* #define SHOW_STAT2 */
+
+#if defined(SHOW_STAT) || defined(SHOW_STAT2)
+#include <stdio.h>
+#endif
+
+#include "CpuArch.h"
+#include "LzmaEnc.h"
+
+#include "LzFind.h"
+#ifndef Z7_ST
+#include "LzFindMt.h"
+#endif
+
+/* the following LzmaEnc_* declarations is internal LZMA interface for LZMA2 encoder */
+
+SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle p, ISeqInStreamPtr inStream, UInt32 keepWindowSize,
+ ISzAllocPtr alloc, ISzAllocPtr allocBig);
+SRes LzmaEnc_MemPrepare(CLzmaEncHandle p, const Byte *src, SizeT srcLen,
+ UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig);
+SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle p, BoolInt reInit,
+ Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize);
+const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle p);
+void LzmaEnc_Finish(CLzmaEncHandle p);
+void LzmaEnc_SaveState(CLzmaEncHandle p);
+void LzmaEnc_RestoreState(CLzmaEncHandle p);
+
+#ifdef SHOW_STAT
+static unsigned g_STAT_OFFSET = 0;
+#endif
+
+/* for good normalization speed we still reserve 256 MB before 4 GB range */
+#define kLzmaMaxHistorySize ((UInt32)15 << 28)
+
+// #define kNumTopBits 24
+#define kTopValue ((UInt32)1 << 24)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+#define kProbInitValue (kBitModelTotal >> 1)
+
+#define kNumMoveReducingBits 4
+#define kNumBitPriceShiftBits 4
+// #define kBitPrice (1 << kNumBitPriceShiftBits)
+
+#define REP_LEN_COUNT 64
+
+void LzmaEncProps_Init(CLzmaEncProps *p)
+{
+ p->level = 5;
+ p->dictSize = p->mc = 0;
+ p->reduceSize = (UInt64)(Int64)-1;
+ p->lc = p->lp = p->pb = p->algo = p->fb = p->btMode = p->numHashBytes = p->numThreads = -1;
+ p->numHashOutBits = 0;
+ p->writeEndMark = 0;
+ p->affinity = 0;
+}
+
+void LzmaEncProps_Normalize(CLzmaEncProps *p)
+{
+ int level = p->level;
+ if (level < 0) level = 5;
+ p->level = level;
+
+ if (p->dictSize == 0)
+ p->dictSize =
+ ( level <= 3 ? ((UInt32)1 << (level * 2 + 16)) :
+ ( level <= 6 ? ((UInt32)1 << (level + 19)) :
+ ( level <= 7 ? ((UInt32)1 << 25) : ((UInt32)1 << 26)
+ )));
+
+ if (p->dictSize > p->reduceSize)
+ {
+ UInt32 v = (UInt32)p->reduceSize;
+ const UInt32 kReduceMin = ((UInt32)1 << 12);
+ if (v < kReduceMin)
+ v = kReduceMin;
+ if (p->dictSize > v)
+ p->dictSize = v;
+ }
+
+ if (p->lc < 0) p->lc = 3;
+ if (p->lp < 0) p->lp = 0;
+ if (p->pb < 0) p->pb = 2;
+
+ if (p->algo < 0) p->algo = (level < 5 ? 0 : 1);
+ if (p->fb < 0) p->fb = (level < 7 ? 32 : 64);
+ if (p->btMode < 0) p->btMode = (p->algo == 0 ? 0 : 1);
+ if (p->numHashBytes < 0) p->numHashBytes = (p->btMode ? 4 : 5);
+ if (p->mc == 0) p->mc = (16 + ((unsigned)p->fb >> 1)) >> (p->btMode ? 0 : 1);
+
+ if (p->numThreads < 0)
+ p->numThreads =
+ #ifndef Z7_ST
+ ((p->btMode && p->algo) ? 2 : 1);
+ #else
+ 1;
+ #endif
+}
+
+UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2)
+{
+ CLzmaEncProps props = *props2;
+ LzmaEncProps_Normalize(&props);
+ return props.dictSize;
+}
+
+
+/*
+x86/x64:
+
+BSR:
+ IF (SRC == 0) ZF = 1, DEST is undefined;
+ AMD : DEST is unchanged;
+ IF (SRC != 0) ZF = 0; DEST is index of top non-zero bit
+ BSR is slow in some processors
+
+LZCNT:
+ IF (SRC == 0) CF = 1, DEST is size_in_bits_of_register(src) (32 or 64)
+ IF (SRC != 0) CF = 0, DEST = num_lead_zero_bits
+ IF (DEST == 0) ZF = 1;
+
+LZCNT works only in new processors starting from Haswell.
+if LZCNT is not supported by processor, then it's executed as BSR.
+LZCNT can be faster than BSR, if supported.
+*/
+
+// #define LZMA_LOG_BSR
+
+#if defined(MY_CPU_ARM_OR_ARM64) /* || defined(MY_CPU_X86_OR_AMD64) */
+
+ #if (defined(__clang__) && (__clang_major__ >= 6)) \
+ || (defined(__GNUC__) && (__GNUC__ >= 6))
+ #define LZMA_LOG_BSR
+ #elif defined(_MSC_VER) && (_MSC_VER >= 1300)
+ // #if defined(MY_CPU_ARM_OR_ARM64)
+ #define LZMA_LOG_BSR
+ // #endif
+ #endif
+#endif
+
+// #include <intrin.h>
+
+#ifdef LZMA_LOG_BSR
+
+#if defined(__clang__) \
+ || defined(__GNUC__)
+
+/*
+ C code: : (30 - __builtin_clz(x))
+ gcc9/gcc10 for x64 /x86 : 30 - (bsr(x) xor 31)
+ clang10 for x64 : 31 + (bsr(x) xor -32)
+*/
+
+ #define MY_clz(x) ((unsigned)__builtin_clz(x))
+ // __lzcnt32
+ // __builtin_ia32_lzcnt_u32
+
+#else // #if defined(_MSC_VER)
+
+ #ifdef MY_CPU_ARM_OR_ARM64
+
+ #define MY_clz _CountLeadingZeros
+
+ #else // if defined(MY_CPU_X86_OR_AMD64)
+
+ // #define MY_clz __lzcnt // we can use lzcnt (unsupported by old CPU)
+ // _BitScanReverse code is not optimal for some MSVC compilers
+ #define BSR2_RET(pos, res) { unsigned long zz; _BitScanReverse(&zz, (pos)); zz--; \
+ res = (zz + zz) + (pos >> zz); }
+
+ #endif // MY_CPU_X86_OR_AMD64
+
+#endif // _MSC_VER
+
+
+#ifndef BSR2_RET
+
+ #define BSR2_RET(pos, res) { unsigned zz = 30 - MY_clz(pos); \
+ res = (zz + zz) + (pos >> zz); }
+
+#endif
+
+
+unsigned GetPosSlot1(UInt32 pos);
+unsigned GetPosSlot1(UInt32 pos)
+{
+ unsigned res;
+ BSR2_RET(pos, res);
+ return res;
+}
+#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
+#define GetPosSlot(pos, res) { if (pos < 2) res = pos; else BSR2_RET(pos, res); }
+
+
+#else // ! LZMA_LOG_BSR
+
+#define kNumLogBits (11 + sizeof(size_t) / 8 * 3)
+
+#define kDicLogSizeMaxCompress ((kNumLogBits - 1) * 2 + 7)
+
+static void LzmaEnc_FastPosInit(Byte *g_FastPos)
+{
+ unsigned slot;
+ g_FastPos[0] = 0;
+ g_FastPos[1] = 1;
+ g_FastPos += 2;
+
+ for (slot = 2; slot < kNumLogBits * 2; slot++)
+ {
+ size_t k = ((size_t)1 << ((slot >> 1) - 1));
+ size_t j;
+ for (j = 0; j < k; j++)
+ g_FastPos[j] = (Byte)slot;
+ g_FastPos += k;
+ }
+}
+
+/* we can use ((limit - pos) >> 31) only if (pos < ((UInt32)1 << 31)) */
+/*
+#define BSR2_RET(pos, res) { unsigned zz = 6 + ((kNumLogBits - 1) & \
+ (0 - (((((UInt32)1 << (kNumLogBits + 6)) - 1) - pos) >> 31))); \
+ res = p->g_FastPos[pos >> zz] + (zz * 2); }
+*/
+
+/*
+#define BSR2_RET(pos, res) { unsigned zz = 6 + ((kNumLogBits - 1) & \
+ (0 - (((((UInt32)1 << (kNumLogBits)) - 1) - (pos >> 6)) >> 31))); \
+ res = p->g_FastPos[pos >> zz] + (zz * 2); }
+*/
+
+#define BSR2_RET(pos, res) { unsigned zz = (pos < (1 << (kNumLogBits + 6))) ? 6 : 6 + kNumLogBits - 1; \
+ res = p->g_FastPos[pos >> zz] + (zz * 2); }
+
+/*
+#define BSR2_RET(pos, res) { res = (pos < (1 << (kNumLogBits + 6))) ? \
+ p->g_FastPos[pos >> 6] + 12 : \
+ p->g_FastPos[pos >> (6 + kNumLogBits - 1)] + (6 + (kNumLogBits - 1)) * 2; }
+*/
+
+#define GetPosSlot1(pos) p->g_FastPos[pos]
+#define GetPosSlot2(pos, res) { BSR2_RET(pos, res); }
+#define GetPosSlot(pos, res) { if (pos < kNumFullDistances) res = p->g_FastPos[pos & (kNumFullDistances - 1)]; else BSR2_RET(pos, res); }
+
+#endif // LZMA_LOG_BSR
+
+
+#define LZMA_NUM_REPS 4
+
+typedef UInt16 CState;
+typedef UInt16 CExtra;
+
+typedef struct
+{
+ UInt32 price;
+ CState state;
+ CExtra extra;
+ // 0 : normal
+ // 1 : LIT : MATCH
+ // > 1 : MATCH (extra-1) : LIT : REP0 (len)
+ UInt32 len;
+ UInt32 dist;
+ UInt32 reps[LZMA_NUM_REPS];
+} COptimal;
+
+
+// 18.06
+#define kNumOpts (1 << 11)
+#define kPackReserve (kNumOpts * 8)
+// #define kNumOpts (1 << 12)
+// #define kPackReserve (1 + kNumOpts * 2)
+
+#define kNumLenToPosStates 4
+#define kNumPosSlotBits 6
+// #define kDicLogSizeMin 0
+#define kDicLogSizeMax 32
+#define kDistTableSizeMax (kDicLogSizeMax * 2)
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+#define kAlignMask (kAlignTableSize - 1)
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+typedef
+#ifdef Z7_LZMA_PROB32
+ UInt32
+#else
+ UInt16
+#endif
+ CLzmaProb;
+
+#define LZMA_PB_MAX 4
+#define LZMA_LC_MAX 8
+#define LZMA_LP_MAX 4
+
+#define LZMA_NUM_PB_STATES_MAX (1 << LZMA_PB_MAX)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+#define kLenNumSymbolsTotal (kLenNumLowSymbols * 2 + kLenNumHighSymbols)
+
+#define LZMA_MATCH_LEN_MIN 2
+#define LZMA_MATCH_LEN_MAX (LZMA_MATCH_LEN_MIN + kLenNumSymbolsTotal - 1)
+
+#define kNumStates 12
+
+
+typedef struct
+{
+ CLzmaProb low[LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)];
+ CLzmaProb high[kLenNumHighSymbols];
+} CLenEnc;
+
+
+typedef struct
+{
+ unsigned tableSize;
+ UInt32 prices[LZMA_NUM_PB_STATES_MAX][kLenNumSymbolsTotal];
+ // UInt32 prices1[LZMA_NUM_PB_STATES_MAX][kLenNumLowSymbols * 2];
+ // UInt32 prices2[kLenNumSymbolsTotal];
+} CLenPriceEnc;
+
+#define GET_PRICE_LEN(p, posState, len) \
+ ((p)->prices[posState][(size_t)(len) - LZMA_MATCH_LEN_MIN])
+
+/*
+#define GET_PRICE_LEN(p, posState, len) \
+ ((p)->prices2[(size_t)(len) - 2] + ((p)->prices1[posState][((len) - 2) & (kLenNumLowSymbols * 2 - 1)] & (((len) - 2 - kLenNumLowSymbols * 2) >> 9)))
+*/
+
+typedef struct
+{
+ UInt32 range;
+ unsigned cache;
+ UInt64 low;
+ UInt64 cacheSize;
+ Byte *buf;
+ Byte *bufLim;
+ Byte *bufBase;
+ ISeqOutStreamPtr outStream;
+ UInt64 processed;
+ SRes res;
+} CRangeEnc;
+
+
+typedef struct
+{
+ CLzmaProb *litProbs;
+
+ unsigned state;
+ UInt32 reps[LZMA_NUM_REPS];
+
+ CLzmaProb posAlignEncoder[1 << kNumAlignBits];
+ CLzmaProb isRep[kNumStates];
+ CLzmaProb isRepG0[kNumStates];
+ CLzmaProb isRepG1[kNumStates];
+ CLzmaProb isRepG2[kNumStates];
+ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
+ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
+
+ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
+ CLzmaProb posEncoders[kNumFullDistances];
+
+ CLenEnc lenProbs;
+ CLenEnc repLenProbs;
+
+} CSaveState;
+
+
+typedef UInt32 CProbPrice;
+
+
+struct CLzmaEnc
+{
+ void *matchFinderObj;
+ IMatchFinder2 matchFinder;
+
+ unsigned optCur;
+ unsigned optEnd;
+
+ unsigned longestMatchLen;
+ unsigned numPairs;
+ UInt32 numAvail;
+
+ unsigned state;
+ unsigned numFastBytes;
+ unsigned additionalOffset;
+ UInt32 reps[LZMA_NUM_REPS];
+ unsigned lpMask, pbMask;
+ CLzmaProb *litProbs;
+ CRangeEnc rc;
+
+ UInt32 backRes;
+
+ unsigned lc, lp, pb;
+ unsigned lclp;
+
+ BoolInt fastMode;
+ BoolInt writeEndMark;
+ BoolInt finished;
+ BoolInt multiThread;
+ BoolInt needInit;
+ // BoolInt _maxMode;
+
+ UInt64 nowPos64;
+
+ unsigned matchPriceCount;
+ // unsigned alignPriceCount;
+ int repLenEncCounter;
+
+ unsigned distTableSize;
+
+ UInt32 dictSize;
+ SRes result;
+
+ #ifndef Z7_ST
+ BoolInt mtMode;
+ // begin of CMatchFinderMt is used in LZ thread
+ CMatchFinderMt matchFinderMt;
+ // end of CMatchFinderMt is used in BT and HASH threads
+ // #else
+ // CMatchFinder matchFinderBase;
+ #endif
+ CMatchFinder matchFinderBase;
+
+
+ // we suppose that we have 8-bytes alignment after CMatchFinder
+
+ #ifndef Z7_ST
+ Byte pad[128];
+ #endif
+
+ // LZ thread
+ CProbPrice ProbPrices[kBitModelTotal >> kNumMoveReducingBits];
+
+ // we want {len , dist} pairs to be 8-bytes aligned in matches array
+ UInt32 matches[LZMA_MATCH_LEN_MAX * 2 + 2];
+
+ // we want 8-bytes alignment here
+ UInt32 alignPrices[kAlignTableSize];
+ UInt32 posSlotPrices[kNumLenToPosStates][kDistTableSizeMax];
+ UInt32 distancesPrices[kNumLenToPosStates][kNumFullDistances];
+
+ CLzmaProb posAlignEncoder[1 << kNumAlignBits];
+ CLzmaProb isRep[kNumStates];
+ CLzmaProb isRepG0[kNumStates];
+ CLzmaProb isRepG1[kNumStates];
+ CLzmaProb isRepG2[kNumStates];
+ CLzmaProb isMatch[kNumStates][LZMA_NUM_PB_STATES_MAX];
+ CLzmaProb isRep0Long[kNumStates][LZMA_NUM_PB_STATES_MAX];
+ CLzmaProb posSlotEncoder[kNumLenToPosStates][1 << kNumPosSlotBits];
+ CLzmaProb posEncoders[kNumFullDistances];
+
+ CLenEnc lenProbs;
+ CLenEnc repLenProbs;
+
+ #ifndef LZMA_LOG_BSR
+ Byte g_FastPos[1 << kNumLogBits];
+ #endif
+
+ CLenPriceEnc lenEnc;
+ CLenPriceEnc repLenEnc;
+
+ COptimal opt[kNumOpts];
+
+ CSaveState saveState;
+
+ // BoolInt mf_Failure;
+ #ifndef Z7_ST
+ Byte pad2[128];
+ #endif
+};
+
+
+#define MFB (p->matchFinderBase)
+/*
+#ifndef Z7_ST
+#define MFB (p->matchFinderMt.MatchFinder)
+#endif
+*/
+
+// #define GET_CLzmaEnc_p CLzmaEnc *p = (CLzmaEnc*)(void *)p;
+// #define GET_const_CLzmaEnc_p const CLzmaEnc *p = (const CLzmaEnc*)(const void *)p;
+
+#define COPY_ARR(dest, src, arr) memcpy((dest)->arr, (src)->arr, sizeof((src)->arr));
+
+#define COPY_LZMA_ENC_STATE(d, s, p) \
+ (d)->state = (s)->state; \
+ COPY_ARR(d, s, reps) \
+ COPY_ARR(d, s, posAlignEncoder) \
+ COPY_ARR(d, s, isRep) \
+ COPY_ARR(d, s, isRepG0) \
+ COPY_ARR(d, s, isRepG1) \
+ COPY_ARR(d, s, isRepG2) \
+ COPY_ARR(d, s, isMatch) \
+ COPY_ARR(d, s, isRep0Long) \
+ COPY_ARR(d, s, posSlotEncoder) \
+ COPY_ARR(d, s, posEncoders) \
+ (d)->lenProbs = (s)->lenProbs; \
+ (d)->repLenProbs = (s)->repLenProbs; \
+ memcpy((d)->litProbs, (s)->litProbs, ((UInt32)0x300 << (p)->lclp) * sizeof(CLzmaProb));
+
+void LzmaEnc_SaveState(CLzmaEncHandle p)
+{
+ // GET_CLzmaEnc_p
+ CSaveState *v = &p->saveState;
+ COPY_LZMA_ENC_STATE(v, p, p)
+}
+
+void LzmaEnc_RestoreState(CLzmaEncHandle p)
+{
+ // GET_CLzmaEnc_p
+ const CSaveState *v = &p->saveState;
+ COPY_LZMA_ENC_STATE(p, v, p)
+}
+
+
+Z7_NO_INLINE
+SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props2)
+{
+ // GET_CLzmaEnc_p
+ CLzmaEncProps props = *props2;
+ LzmaEncProps_Normalize(&props);
+
+ if (props.lc > LZMA_LC_MAX
+ || props.lp > LZMA_LP_MAX
+ || props.pb > LZMA_PB_MAX)
+ return SZ_ERROR_PARAM;
+
+
+ if (props.dictSize > kLzmaMaxHistorySize)
+ props.dictSize = kLzmaMaxHistorySize;
+
+ #ifndef LZMA_LOG_BSR
+ {
+ const UInt64 dict64 = props.dictSize;
+ if (dict64 > ((UInt64)1 << kDicLogSizeMaxCompress))
+ return SZ_ERROR_PARAM;
+ }
+ #endif
+
+ p->dictSize = props.dictSize;
+ {
+ unsigned fb = (unsigned)props.fb;
+ if (fb < 5)
+ fb = 5;
+ if (fb > LZMA_MATCH_LEN_MAX)
+ fb = LZMA_MATCH_LEN_MAX;
+ p->numFastBytes = fb;
+ }
+ p->lc = (unsigned)props.lc;
+ p->lp = (unsigned)props.lp;
+ p->pb = (unsigned)props.pb;
+ p->fastMode = (props.algo == 0);
+ // p->_maxMode = True;
+ MFB.btMode = (Byte)(props.btMode ? 1 : 0);
+ // MFB.btMode = (Byte)(props.btMode);
+ {
+ unsigned numHashBytes = 4;
+ if (props.btMode)
+ {
+ if (props.numHashBytes < 2) numHashBytes = 2;
+ else if (props.numHashBytes < 4) numHashBytes = (unsigned)props.numHashBytes;
+ }
+ if (props.numHashBytes >= 5) numHashBytes = 5;
+
+ MFB.numHashBytes = numHashBytes;
+ // MFB.numHashBytes_Min = 2;
+ MFB.numHashOutBits = (Byte)props.numHashOutBits;
+ }
+
+ MFB.cutValue = props.mc;
+
+ p->writeEndMark = (BoolInt)props.writeEndMark;
+
+ #ifndef Z7_ST
+ /*
+ if (newMultiThread != _multiThread)
+ {
+ ReleaseMatchFinder();
+ _multiThread = newMultiThread;
+ }
+ */
+ p->multiThread = (props.numThreads > 1);
+ p->matchFinderMt.btSync.affinity =
+ p->matchFinderMt.hashSync.affinity = props.affinity;
+ #endif
+
+ return SZ_OK;
+}
+
+
+void LzmaEnc_SetDataSize(CLzmaEncHandle p, UInt64 expectedDataSiize)
+{
+ // GET_CLzmaEnc_p
+ MFB.expectedDataSize = expectedDataSiize;
+}
+
+
+#define kState_Start 0
+#define kState_LitAfterMatch 4
+#define kState_LitAfterRep 5
+#define kState_MatchAfterLit 7
+#define kState_RepAfterLit 8
+
+static const Byte kLiteralNextStates[kNumStates] = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
+static const Byte kMatchNextStates[kNumStates] = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
+static const Byte kRepNextStates[kNumStates] = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
+static const Byte kShortRepNextStates[kNumStates]= {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
+
+#define IsLitState(s) ((s) < 7)
+#define GetLenToPosState2(len) (((len) < kNumLenToPosStates - 1) ? (len) : kNumLenToPosStates - 1)
+#define GetLenToPosState(len) (((len) < kNumLenToPosStates + 1) ? (len) - 2 : kNumLenToPosStates - 1)
+
+#define kInfinityPrice (1 << 30)
+
+static void RangeEnc_Construct(CRangeEnc *p)
+{
+ p->outStream = NULL;
+ p->bufBase = NULL;
+}
+
+#define RangeEnc_GetProcessed(p) ( (p)->processed + (size_t)((p)->buf - (p)->bufBase) + (p)->cacheSize)
+#define RangeEnc_GetProcessed_sizet(p) ((size_t)(p)->processed + (size_t)((p)->buf - (p)->bufBase) + (size_t)(p)->cacheSize)
+
+#define RC_BUF_SIZE (1 << 16)
+
+static int RangeEnc_Alloc(CRangeEnc *p, ISzAllocPtr alloc)
+{
+ if (!p->bufBase)
+ {
+ p->bufBase = (Byte *)ISzAlloc_Alloc(alloc, RC_BUF_SIZE);
+ if (!p->bufBase)
+ return 0;
+ p->bufLim = p->bufBase + RC_BUF_SIZE;
+ }
+ return 1;
+}
+
+static void RangeEnc_Free(CRangeEnc *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->bufBase);
+ p->bufBase = NULL;
+}
+
+static void RangeEnc_Init(CRangeEnc *p)
+{
+ p->range = 0xFFFFFFFF;
+ p->cache = 0;
+ p->low = 0;
+ p->cacheSize = 0;
+
+ p->buf = p->bufBase;
+
+ p->processed = 0;
+ p->res = SZ_OK;
+}
+
+Z7_NO_INLINE static void RangeEnc_FlushStream(CRangeEnc *p)
+{
+ const size_t num = (size_t)(p->buf - p->bufBase);
+ if (p->res == SZ_OK)
+ {
+ if (num != ISeqOutStream_Write(p->outStream, p->bufBase, num))
+ p->res = SZ_ERROR_WRITE;
+ }
+ p->processed += num;
+ p->buf = p->bufBase;
+}
+
+Z7_NO_INLINE static void Z7_FASTCALL RangeEnc_ShiftLow(CRangeEnc *p)
+{
+ UInt32 low = (UInt32)p->low;
+ unsigned high = (unsigned)(p->low >> 32);
+ p->low = (UInt32)(low << 8);
+ if (low < (UInt32)0xFF000000 || high != 0)
+ {
+ {
+ Byte *buf = p->buf;
+ *buf++ = (Byte)(p->cache + high);
+ p->cache = (unsigned)(low >> 24);
+ p->buf = buf;
+ if (buf == p->bufLim)
+ RangeEnc_FlushStream(p);
+ if (p->cacheSize == 0)
+ return;
+ }
+ high += 0xFF;
+ for (;;)
+ {
+ Byte *buf = p->buf;
+ *buf++ = (Byte)(high);
+ p->buf = buf;
+ if (buf == p->bufLim)
+ RangeEnc_FlushStream(p);
+ if (--p->cacheSize == 0)
+ return;
+ }
+ }
+ p->cacheSize++;
+}
+
+static void RangeEnc_FlushData(CRangeEnc *p)
+{
+ int i;
+ for (i = 0; i < 5; i++)
+ RangeEnc_ShiftLow(p);
+}
+
+#define RC_NORM(p) if (range < kTopValue) { range <<= 8; RangeEnc_ShiftLow(p); }
+
+#define RC_BIT_PRE(p, prob) \
+ ttt = *(prob); \
+ newBound = (range >> kNumBitModelTotalBits) * ttt;
+
+// #define Z7_LZMA_ENC_USE_BRANCH
+
+#ifdef Z7_LZMA_ENC_USE_BRANCH
+
+#define RC_BIT(p, prob, bit) { \
+ RC_BIT_PRE(p, prob) \
+ if (bit == 0) { range = newBound; ttt += (kBitModelTotal - ttt) >> kNumMoveBits; } \
+ else { (p)->low += newBound; range -= newBound; ttt -= ttt >> kNumMoveBits; } \
+ *(prob) = (CLzmaProb)ttt; \
+ RC_NORM(p) \
+ }
+
+#else
+
+#define RC_BIT(p, prob, bit) { \
+ UInt32 mask; \
+ RC_BIT_PRE(p, prob) \
+ mask = 0 - (UInt32)bit; \
+ range &= mask; \
+ mask &= newBound; \
+ range -= mask; \
+ (p)->low += mask; \
+ mask = (UInt32)bit - 1; \
+ range += newBound & mask; \
+ mask &= (kBitModelTotal - ((1 << kNumMoveBits) - 1)); \
+ mask += ((1 << kNumMoveBits) - 1); \
+ ttt += (UInt32)((Int32)(mask - ttt) >> kNumMoveBits); \
+ *(prob) = (CLzmaProb)ttt; \
+ RC_NORM(p) \
+ }
+
+#endif
+
+
+
+
+#define RC_BIT_0_BASE(p, prob) \
+ range = newBound; *(prob) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
+
+#define RC_BIT_1_BASE(p, prob) \
+ range -= newBound; (p)->low += newBound; *(prob) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits)); \
+
+#define RC_BIT_0(p, prob) \
+ RC_BIT_0_BASE(p, prob) \
+ RC_NORM(p)
+
+#define RC_BIT_1(p, prob) \
+ RC_BIT_1_BASE(p, prob) \
+ RC_NORM(p)
+
+static void RangeEnc_EncodeBit_0(CRangeEnc *p, CLzmaProb *prob)
+{
+ UInt32 range, ttt, newBound;
+ range = p->range;
+ RC_BIT_PRE(p, prob)
+ RC_BIT_0(p, prob)
+ p->range = range;
+}
+
+static void LitEnc_Encode(CRangeEnc *p, CLzmaProb *probs, UInt32 sym)
+{
+ UInt32 range = p->range;
+ sym |= 0x100;
+ do
+ {
+ UInt32 ttt, newBound;
+ // RangeEnc_EncodeBit(p, probs + (sym >> 8), (sym >> 7) & 1);
+ CLzmaProb *prob = probs + (sym >> 8);
+ UInt32 bit = (sym >> 7) & 1;
+ sym <<= 1;
+ RC_BIT(p, prob, bit)
+ }
+ while (sym < 0x10000);
+ p->range = range;
+}
+
+static void LitEnc_EncodeMatched(CRangeEnc *p, CLzmaProb *probs, UInt32 sym, UInt32 matchByte)
+{
+ UInt32 range = p->range;
+ UInt32 offs = 0x100;
+ sym |= 0x100;
+ do
+ {
+ UInt32 ttt, newBound;
+ CLzmaProb *prob;
+ UInt32 bit;
+ matchByte <<= 1;
+ // RangeEnc_EncodeBit(p, probs + (offs + (matchByte & offs) + (sym >> 8)), (sym >> 7) & 1);
+ prob = probs + (offs + (matchByte & offs) + (sym >> 8));
+ bit = (sym >> 7) & 1;
+ sym <<= 1;
+ offs &= ~(matchByte ^ sym);
+ RC_BIT(p, prob, bit)
+ }
+ while (sym < 0x10000);
+ p->range = range;
+}
+
+
+
+static void LzmaEnc_InitPriceTables(CProbPrice *ProbPrices)
+{
+ UInt32 i;
+ for (i = 0; i < (kBitModelTotal >> kNumMoveReducingBits); i++)
+ {
+ const unsigned kCyclesBits = kNumBitPriceShiftBits;
+ UInt32 w = (i << kNumMoveReducingBits) + (1 << (kNumMoveReducingBits - 1));
+ unsigned bitCount = 0;
+ unsigned j;
+ for (j = 0; j < kCyclesBits; j++)
+ {
+ w = w * w;
+ bitCount <<= 1;
+ while (w >= ((UInt32)1 << 16))
+ {
+ w >>= 1;
+ bitCount++;
+ }
+ }
+ ProbPrices[i] = (CProbPrice)(((unsigned)kNumBitModelTotalBits << kCyclesBits) - 15 - bitCount);
+ // printf("\n%3d: %5d", i, ProbPrices[i]);
+ }
+}
+
+
+#define GET_PRICE(prob, bit) \
+ p->ProbPrices[((prob) ^ (unsigned)(((-(int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]
+
+#define GET_PRICEa(prob, bit) \
+ ProbPrices[((prob) ^ (unsigned)((-((int)(bit))) & (kBitModelTotal - 1))) >> kNumMoveReducingBits]
+
+#define GET_PRICE_0(prob) p->ProbPrices[(prob) >> kNumMoveReducingBits]
+#define GET_PRICE_1(prob) p->ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
+
+#define GET_PRICEa_0(prob) ProbPrices[(prob) >> kNumMoveReducingBits]
+#define GET_PRICEa_1(prob) ProbPrices[((prob) ^ (kBitModelTotal - 1)) >> kNumMoveReducingBits]
+
+
+static UInt32 LitEnc_GetPrice(const CLzmaProb *probs, UInt32 sym, const CProbPrice *ProbPrices)
+{
+ UInt32 price = 0;
+ sym |= 0x100;
+ do
+ {
+ unsigned bit = sym & 1;
+ sym >>= 1;
+ price += GET_PRICEa(probs[sym], bit);
+ }
+ while (sym >= 2);
+ return price;
+}
+
+
+static UInt32 LitEnc_Matched_GetPrice(const CLzmaProb *probs, UInt32 sym, UInt32 matchByte, const CProbPrice *ProbPrices)
+{
+ UInt32 price = 0;
+ UInt32 offs = 0x100;
+ sym |= 0x100;
+ do
+ {
+ matchByte <<= 1;
+ price += GET_PRICEa(probs[offs + (matchByte & offs) + (sym >> 8)], (sym >> 7) & 1);
+ sym <<= 1;
+ offs &= ~(matchByte ^ sym);
+ }
+ while (sym < 0x10000);
+ return price;
+}
+
+
+static void RcTree_ReverseEncode(CRangeEnc *rc, CLzmaProb *probs, unsigned numBits, unsigned sym)
+{
+ UInt32 range = rc->range;
+ unsigned m = 1;
+ do
+ {
+ UInt32 ttt, newBound;
+ unsigned bit = sym & 1;
+ // RangeEnc_EncodeBit(rc, probs + m, bit);
+ sym >>= 1;
+ RC_BIT(rc, probs + m, bit)
+ m = (m << 1) | bit;
+ }
+ while (--numBits);
+ rc->range = range;
+}
+
+
+
+static void LenEnc_Init(CLenEnc *p)
+{
+ unsigned i;
+ for (i = 0; i < (LZMA_NUM_PB_STATES_MAX << (kLenNumLowBits + 1)); i++)
+ p->low[i] = kProbInitValue;
+ for (i = 0; i < kLenNumHighSymbols; i++)
+ p->high[i] = kProbInitValue;
+}
+
+static void LenEnc_Encode(CLenEnc *p, CRangeEnc *rc, unsigned sym, unsigned posState)
+{
+ UInt32 range, ttt, newBound;
+ CLzmaProb *probs = p->low;
+ range = rc->range;
+ RC_BIT_PRE(rc, probs)
+ if (sym >= kLenNumLowSymbols)
+ {
+ RC_BIT_1(rc, probs)
+ probs += kLenNumLowSymbols;
+ RC_BIT_PRE(rc, probs)
+ if (sym >= kLenNumLowSymbols * 2)
+ {
+ RC_BIT_1(rc, probs)
+ rc->range = range;
+ // RcTree_Encode(rc, p->high, kLenNumHighBits, sym - kLenNumLowSymbols * 2);
+ LitEnc_Encode(rc, p->high, sym - kLenNumLowSymbols * 2);
+ return;
+ }
+ sym -= kLenNumLowSymbols;
+ }
+
+ // RcTree_Encode(rc, probs + (posState << kLenNumLowBits), kLenNumLowBits, sym);
+ {
+ unsigned m;
+ unsigned bit;
+ RC_BIT_0(rc, probs)
+ probs += (posState << (1 + kLenNumLowBits));
+ bit = (sym >> 2) ; RC_BIT(rc, probs + 1, bit) m = (1 << 1) + bit;
+ bit = (sym >> 1) & 1; RC_BIT(rc, probs + m, bit) m = (m << 1) + bit;
+ bit = sym & 1; RC_BIT(rc, probs + m, bit)
+ rc->range = range;
+ }
+}
+
+static void SetPrices_3(const CLzmaProb *probs, UInt32 startPrice, UInt32 *prices, const CProbPrice *ProbPrices)
+{
+ unsigned i;
+ for (i = 0; i < 8; i += 2)
+ {
+ UInt32 price = startPrice;
+ UInt32 prob;
+ price += GET_PRICEa(probs[1 ], (i >> 2));
+ price += GET_PRICEa(probs[2 + (i >> 2)], (i >> 1) & 1);
+ prob = probs[4 + (i >> 1)];
+ prices[i ] = price + GET_PRICEa_0(prob);
+ prices[i + 1] = price + GET_PRICEa_1(prob);
+ }
+}
+
+
+Z7_NO_INLINE static void Z7_FASTCALL LenPriceEnc_UpdateTables(
+ CLenPriceEnc *p,
+ unsigned numPosStates,
+ const CLenEnc *enc,
+ const CProbPrice *ProbPrices)
+{
+ UInt32 b;
+
+ {
+ unsigned prob = enc->low[0];
+ UInt32 a, c;
+ unsigned posState;
+ b = GET_PRICEa_1(prob);
+ a = GET_PRICEa_0(prob);
+ c = b + GET_PRICEa_0(enc->low[kLenNumLowSymbols]);
+ for (posState = 0; posState < numPosStates; posState++)
+ {
+ UInt32 *prices = p->prices[posState];
+ const CLzmaProb *probs = enc->low + (posState << (1 + kLenNumLowBits));
+ SetPrices_3(probs, a, prices, ProbPrices);
+ SetPrices_3(probs + kLenNumLowSymbols, c, prices + kLenNumLowSymbols, ProbPrices);
+ }
+ }
+
+ /*
+ {
+ unsigned i;
+ UInt32 b;
+ a = GET_PRICEa_0(enc->low[0]);
+ for (i = 0; i < kLenNumLowSymbols; i++)
+ p->prices2[i] = a;
+ a = GET_PRICEa_1(enc->low[0]);
+ b = a + GET_PRICEa_0(enc->low[kLenNumLowSymbols]);
+ for (i = kLenNumLowSymbols; i < kLenNumLowSymbols * 2; i++)
+ p->prices2[i] = b;
+ a += GET_PRICEa_1(enc->low[kLenNumLowSymbols]);
+ }
+ */
+
+ // p->counter = numSymbols;
+ // p->counter = 64;
+
+ {
+ unsigned i = p->tableSize;
+
+ if (i > kLenNumLowSymbols * 2)
+ {
+ const CLzmaProb *probs = enc->high;
+ UInt32 *prices = p->prices[0] + kLenNumLowSymbols * 2;
+ i -= kLenNumLowSymbols * 2 - 1;
+ i >>= 1;
+ b += GET_PRICEa_1(enc->low[kLenNumLowSymbols]);
+ do
+ {
+ /*
+ p->prices2[i] = a +
+ // RcTree_GetPrice(enc->high, kLenNumHighBits, i - kLenNumLowSymbols * 2, ProbPrices);
+ LitEnc_GetPrice(probs, i - kLenNumLowSymbols * 2, ProbPrices);
+ */
+ // UInt32 price = a + RcTree_GetPrice(probs, kLenNumHighBits - 1, sym, ProbPrices);
+ unsigned sym = --i + (1 << (kLenNumHighBits - 1));
+ UInt32 price = b;
+ do
+ {
+ unsigned bit = sym & 1;
+ sym >>= 1;
+ price += GET_PRICEa(probs[sym], bit);
+ }
+ while (sym >= 2);
+
+ {
+ unsigned prob = probs[(size_t)i + (1 << (kLenNumHighBits - 1))];
+ prices[(size_t)i * 2 ] = price + GET_PRICEa_0(prob);
+ prices[(size_t)i * 2 + 1] = price + GET_PRICEa_1(prob);
+ }
+ }
+ while (i);
+
+ {
+ unsigned posState;
+ size_t num = (p->tableSize - kLenNumLowSymbols * 2) * sizeof(p->prices[0][0]);
+ for (posState = 1; posState < numPosStates; posState++)
+ memcpy(p->prices[posState] + kLenNumLowSymbols * 2, p->prices[0] + kLenNumLowSymbols * 2, num);
+ }
+ }
+ }
+}
+
+/*
+ #ifdef SHOW_STAT
+ g_STAT_OFFSET += num;
+ printf("\n MovePos %u", num);
+ #endif
+*/
+
+#define MOVE_POS(p, num) { \
+ p->additionalOffset += (num); \
+ p->matchFinder.Skip(p->matchFinderObj, (UInt32)(num)); }
+
+
+static unsigned ReadMatchDistances(CLzmaEnc *p, unsigned *numPairsRes)
+{
+ unsigned numPairs;
+
+ p->additionalOffset++;
+ p->numAvail = p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
+ {
+ const UInt32 *d = p->matchFinder.GetMatches(p->matchFinderObj, p->matches);
+ // if (!d) { p->mf_Failure = True; *numPairsRes = 0; return 0; }
+ numPairs = (unsigned)(d - p->matches);
+ }
+ *numPairsRes = numPairs;
+
+ #ifdef SHOW_STAT
+ printf("\n i = %u numPairs = %u ", g_STAT_OFFSET, numPairs / 2);
+ g_STAT_OFFSET++;
+ {
+ unsigned i;
+ for (i = 0; i < numPairs; i += 2)
+ printf("%2u %6u | ", p->matches[i], p->matches[i + 1]);
+ }
+ #endif
+
+ if (numPairs == 0)
+ return 0;
+ {
+ const unsigned len = p->matches[(size_t)numPairs - 2];
+ if (len != p->numFastBytes)
+ return len;
+ {
+ UInt32 numAvail = p->numAvail;
+ if (numAvail > LZMA_MATCH_LEN_MAX)
+ numAvail = LZMA_MATCH_LEN_MAX;
+ {
+ const Byte *p1 = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ const Byte *p2 = p1 + len;
+ const ptrdiff_t dif = (ptrdiff_t)-1 - (ptrdiff_t)p->matches[(size_t)numPairs - 1];
+ const Byte *lim = p1 + numAvail;
+ for (; p2 != lim && *p2 == p2[dif]; p2++)
+ {}
+ return (unsigned)(p2 - p1);
+ }
+ }
+ }
+}
+
+#define MARK_LIT ((UInt32)(Int32)-1)
+
+#define MakeAs_Lit(p) { (p)->dist = MARK_LIT; (p)->extra = 0; }
+#define MakeAs_ShortRep(p) { (p)->dist = 0; (p)->extra = 0; }
+#define IsShortRep(p) ((p)->dist == 0)
+
+
+#define GetPrice_ShortRep(p, state, posState) \
+ ( GET_PRICE_0(p->isRepG0[state]) + GET_PRICE_0(p->isRep0Long[state][posState]))
+
+#define GetPrice_Rep_0(p, state, posState) ( \
+ GET_PRICE_1(p->isMatch[state][posState]) \
+ + GET_PRICE_1(p->isRep0Long[state][posState])) \
+ + GET_PRICE_1(p->isRep[state]) \
+ + GET_PRICE_0(p->isRepG0[state])
+
+Z7_FORCE_INLINE
+static UInt32 GetPrice_PureRep(const CLzmaEnc *p, unsigned repIndex, size_t state, size_t posState)
+{
+ UInt32 price;
+ UInt32 prob = p->isRepG0[state];
+ if (repIndex == 0)
+ {
+ price = GET_PRICE_0(prob);
+ price += GET_PRICE_1(p->isRep0Long[state][posState]);
+ }
+ else
+ {
+ price = GET_PRICE_1(prob);
+ prob = p->isRepG1[state];
+ if (repIndex == 1)
+ price += GET_PRICE_0(prob);
+ else
+ {
+ price += GET_PRICE_1(prob);
+ price += GET_PRICE(p->isRepG2[state], repIndex - 2);
+ }
+ }
+ return price;
+}
+
+
+static unsigned Backward(CLzmaEnc *p, unsigned cur)
+{
+ unsigned wr = cur + 1;
+ p->optEnd = wr;
+
+ for (;;)
+ {
+ UInt32 dist = p->opt[cur].dist;
+ unsigned len = (unsigned)p->opt[cur].len;
+ unsigned extra = (unsigned)p->opt[cur].extra;
+ cur -= len;
+
+ if (extra)
+ {
+ wr--;
+ p->opt[wr].len = (UInt32)len;
+ cur -= extra;
+ len = extra;
+ if (extra == 1)
+ {
+ p->opt[wr].dist = dist;
+ dist = MARK_LIT;
+ }
+ else
+ {
+ p->opt[wr].dist = 0;
+ len--;
+ wr--;
+ p->opt[wr].dist = MARK_LIT;
+ p->opt[wr].len = 1;
+ }
+ }
+
+ if (cur == 0)
+ {
+ p->backRes = dist;
+ p->optCur = wr;
+ return len;
+ }
+
+ wr--;
+ p->opt[wr].dist = dist;
+ p->opt[wr].len = (UInt32)len;
+ }
+}
+
+
+
+#define LIT_PROBS(pos, prevByte) \
+ (p->litProbs + (UInt32)3 * (((((pos) << 8) + (prevByte)) & p->lpMask) << p->lc))
+
+
+static unsigned GetOptimum(CLzmaEnc *p, UInt32 position)
+{
+ unsigned last, cur;
+ UInt32 reps[LZMA_NUM_REPS];
+ unsigned repLens[LZMA_NUM_REPS];
+ UInt32 *matches;
+
+ {
+ UInt32 numAvail;
+ unsigned numPairs, mainLen, repMaxIndex, i, posState;
+ UInt32 matchPrice, repMatchPrice;
+ const Byte *data;
+ Byte curByte, matchByte;
+
+ p->optCur = p->optEnd = 0;
+
+ if (p->additionalOffset == 0)
+ mainLen = ReadMatchDistances(p, &numPairs);
+ else
+ {
+ mainLen = p->longestMatchLen;
+ numPairs = p->numPairs;
+ }
+
+ numAvail = p->numAvail;
+ if (numAvail < 2)
+ {
+ p->backRes = MARK_LIT;
+ return 1;
+ }
+ if (numAvail > LZMA_MATCH_LEN_MAX)
+ numAvail = LZMA_MATCH_LEN_MAX;
+
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ repMaxIndex = 0;
+
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ unsigned len;
+ const Byte *data2;
+ reps[i] = p->reps[i];
+ data2 = data - reps[i];
+ if (data[0] != data2[0] || data[1] != data2[1])
+ {
+ repLens[i] = 0;
+ continue;
+ }
+ for (len = 2; len < numAvail && data[len] == data2[len]; len++)
+ {}
+ repLens[i] = len;
+ if (len > repLens[repMaxIndex])
+ repMaxIndex = i;
+ if (len == LZMA_MATCH_LEN_MAX) // 21.03 : optimization
+ break;
+ }
+
+ if (repLens[repMaxIndex] >= p->numFastBytes)
+ {
+ unsigned len;
+ p->backRes = (UInt32)repMaxIndex;
+ len = repLens[repMaxIndex];
+ MOVE_POS(p, len - 1)
+ return len;
+ }
+
+ matches = p->matches;
+ #define MATCHES matches
+ // #define MATCHES p->matches
+
+ if (mainLen >= p->numFastBytes)
+ {
+ p->backRes = MATCHES[(size_t)numPairs - 1] + LZMA_NUM_REPS;
+ MOVE_POS(p, mainLen - 1)
+ return mainLen;
+ }
+
+ curByte = *data;
+ matchByte = *(data - reps[0]);
+
+ last = repLens[repMaxIndex];
+ if (last <= mainLen)
+ last = mainLen;
+
+ if (last < 2 && curByte != matchByte)
+ {
+ p->backRes = MARK_LIT;
+ return 1;
+ }
+
+ p->opt[0].state = (CState)p->state;
+
+ posState = (position & p->pbMask);
+
+ {
+ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
+ p->opt[1].price = GET_PRICE_0(p->isMatch[p->state][posState]) +
+ (!IsLitState(p->state) ?
+ LitEnc_Matched_GetPrice(probs, curByte, matchByte, p->ProbPrices) :
+ LitEnc_GetPrice(probs, curByte, p->ProbPrices));
+ }
+
+ MakeAs_Lit(&p->opt[1])
+
+ matchPrice = GET_PRICE_1(p->isMatch[p->state][posState]);
+ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[p->state]);
+
+ // 18.06
+ if (matchByte == curByte && repLens[0] == 0)
+ {
+ UInt32 shortRepPrice = repMatchPrice + GetPrice_ShortRep(p, p->state, posState);
+ if (shortRepPrice < p->opt[1].price)
+ {
+ p->opt[1].price = shortRepPrice;
+ MakeAs_ShortRep(&p->opt[1])
+ }
+ if (last < 2)
+ {
+ p->backRes = p->opt[1].dist;
+ return 1;
+ }
+ }
+
+ p->opt[1].len = 1;
+
+ p->opt[0].reps[0] = reps[0];
+ p->opt[0].reps[1] = reps[1];
+ p->opt[0].reps[2] = reps[2];
+ p->opt[0].reps[3] = reps[3];
+
+ // ---------- REP ----------
+
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ unsigned repLen = repLens[i];
+ UInt32 price;
+ if (repLen < 2)
+ continue;
+ price = repMatchPrice + GetPrice_PureRep(p, i, p->state, posState);
+ do
+ {
+ UInt32 price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState, repLen);
+ COptimal *opt = &p->opt[repLen];
+ if (price2 < opt->price)
+ {
+ opt->price = price2;
+ opt->len = (UInt32)repLen;
+ opt->dist = (UInt32)i;
+ opt->extra = 0;
+ }
+ }
+ while (--repLen >= 2);
+ }
+
+
+ // ---------- MATCH ----------
+ {
+ unsigned len = repLens[0] + 1;
+ if (len <= mainLen)
+ {
+ unsigned offs = 0;
+ UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[p->state]);
+
+ if (len < 2)
+ len = 2;
+ else
+ while (len > MATCHES[offs])
+ offs += 2;
+
+ for (; ; len++)
+ {
+ COptimal *opt;
+ UInt32 dist = MATCHES[(size_t)offs + 1];
+ UInt32 price = normalMatchPrice + GET_PRICE_LEN(&p->lenEnc, posState, len);
+ unsigned lenToPosState = GetLenToPosState(len);
+
+ if (dist < kNumFullDistances)
+ price += p->distancesPrices[lenToPosState][dist & (kNumFullDistances - 1)];
+ else
+ {
+ unsigned slot;
+ GetPosSlot2(dist, slot)
+ price += p->alignPrices[dist & kAlignMask];
+ price += p->posSlotPrices[lenToPosState][slot];
+ }
+
+ opt = &p->opt[len];
+
+ if (price < opt->price)
+ {
+ opt->price = price;
+ opt->len = (UInt32)len;
+ opt->dist = dist + LZMA_NUM_REPS;
+ opt->extra = 0;
+ }
+
+ if (len == MATCHES[offs])
+ {
+ offs += 2;
+ if (offs == numPairs)
+ break;
+ }
+ }
+ }
+ }
+
+
+ cur = 0;
+
+ #ifdef SHOW_STAT2
+ /* if (position >= 0) */
+ {
+ unsigned i;
+ printf("\n pos = %4X", position);
+ for (i = cur; i <= last; i++)
+ printf("\nprice[%4X] = %u", position - cur + i, p->opt[i].price);
+ }
+ #endif
+ }
+
+
+
+ // ---------- Optimal Parsing ----------
+
+ for (;;)
+ {
+ unsigned numAvail;
+ UInt32 numAvailFull;
+ unsigned newLen, numPairs, prev, state, posState, startLen;
+ UInt32 litPrice, matchPrice, repMatchPrice;
+ BoolInt nextIsLit;
+ Byte curByte, matchByte;
+ const Byte *data;
+ COptimal *curOpt, *nextOpt;
+
+ if (++cur == last)
+ break;
+
+ // 18.06
+ if (cur >= kNumOpts - 64)
+ {
+ unsigned j, best;
+ UInt32 price = p->opt[cur].price;
+ best = cur;
+ for (j = cur + 1; j <= last; j++)
+ {
+ UInt32 price2 = p->opt[j].price;
+ if (price >= price2)
+ {
+ price = price2;
+ best = j;
+ }
+ }
+ {
+ unsigned delta = best - cur;
+ if (delta != 0)
+ {
+ MOVE_POS(p, delta)
+ }
+ }
+ cur = best;
+ break;
+ }
+
+ newLen = ReadMatchDistances(p, &numPairs);
+
+ if (newLen >= p->numFastBytes)
+ {
+ p->numPairs = numPairs;
+ p->longestMatchLen = newLen;
+ break;
+ }
+
+ curOpt = &p->opt[cur];
+
+ position++;
+
+ // we need that check here, if skip_items in p->opt are possible
+ /*
+ if (curOpt->price >= kInfinityPrice)
+ continue;
+ */
+
+ prev = cur - curOpt->len;
+
+ if (curOpt->len == 1)
+ {
+ state = (unsigned)p->opt[prev].state;
+ if (IsShortRep(curOpt))
+ state = kShortRepNextStates[state];
+ else
+ state = kLiteralNextStates[state];
+ }
+ else
+ {
+ const COptimal *prevOpt;
+ UInt32 b0;
+ UInt32 dist = curOpt->dist;
+
+ if (curOpt->extra)
+ {
+ prev -= (unsigned)curOpt->extra;
+ state = kState_RepAfterLit;
+ if (curOpt->extra == 1)
+ state = (dist < LZMA_NUM_REPS ? kState_RepAfterLit : kState_MatchAfterLit);
+ }
+ else
+ {
+ state = (unsigned)p->opt[prev].state;
+ if (dist < LZMA_NUM_REPS)
+ state = kRepNextStates[state];
+ else
+ state = kMatchNextStates[state];
+ }
+
+ prevOpt = &p->opt[prev];
+ b0 = prevOpt->reps[0];
+
+ if (dist < LZMA_NUM_REPS)
+ {
+ if (dist == 0)
+ {
+ reps[0] = b0;
+ reps[1] = prevOpt->reps[1];
+ reps[2] = prevOpt->reps[2];
+ reps[3] = prevOpt->reps[3];
+ }
+ else
+ {
+ reps[1] = b0;
+ b0 = prevOpt->reps[1];
+ if (dist == 1)
+ {
+ reps[0] = b0;
+ reps[2] = prevOpt->reps[2];
+ reps[3] = prevOpt->reps[3];
+ }
+ else
+ {
+ reps[2] = b0;
+ reps[0] = prevOpt->reps[dist];
+ reps[3] = prevOpt->reps[dist ^ 1];
+ }
+ }
+ }
+ else
+ {
+ reps[0] = (dist - LZMA_NUM_REPS + 1);
+ reps[1] = b0;
+ reps[2] = prevOpt->reps[1];
+ reps[3] = prevOpt->reps[2];
+ }
+ }
+
+ curOpt->state = (CState)state;
+ curOpt->reps[0] = reps[0];
+ curOpt->reps[1] = reps[1];
+ curOpt->reps[2] = reps[2];
+ curOpt->reps[3] = reps[3];
+
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ curByte = *data;
+ matchByte = *(data - reps[0]);
+
+ posState = (position & p->pbMask);
+
+ /*
+ The order of Price checks:
+ < LIT
+ <= SHORT_REP
+ < LIT : REP_0
+ < REP [ : LIT : REP_0 ]
+ < MATCH [ : LIT : REP_0 ]
+ */
+
+ {
+ UInt32 curPrice = curOpt->price;
+ unsigned prob = p->isMatch[state][posState];
+ matchPrice = curPrice + GET_PRICE_1(prob);
+ litPrice = curPrice + GET_PRICE_0(prob);
+ }
+
+ nextOpt = &p->opt[(size_t)cur + 1];
+ nextIsLit = False;
+
+ // here we can allow skip_items in p->opt, if we don't check (nextOpt->price < kInfinityPrice)
+ // 18.new.06
+ if ((nextOpt->price < kInfinityPrice
+ // && !IsLitState(state)
+ && matchByte == curByte)
+ || litPrice > nextOpt->price
+ )
+ litPrice = 0;
+ else
+ {
+ const CLzmaProb *probs = LIT_PROBS(position, *(data - 1));
+ litPrice += (!IsLitState(state) ?
+ LitEnc_Matched_GetPrice(probs, curByte, matchByte, p->ProbPrices) :
+ LitEnc_GetPrice(probs, curByte, p->ProbPrices));
+
+ if (litPrice < nextOpt->price)
+ {
+ nextOpt->price = litPrice;
+ nextOpt->len = 1;
+ MakeAs_Lit(nextOpt)
+ nextIsLit = True;
+ }
+ }
+
+ repMatchPrice = matchPrice + GET_PRICE_1(p->isRep[state]);
+
+ numAvailFull = p->numAvail;
+ {
+ unsigned temp = kNumOpts - 1 - cur;
+ if (numAvailFull > temp)
+ numAvailFull = (UInt32)temp;
+ }
+
+ // 18.06
+ // ---------- SHORT_REP ----------
+ if (IsLitState(state)) // 18.new
+ if (matchByte == curByte)
+ if (repMatchPrice < nextOpt->price) // 18.new
+ // if (numAvailFull < 2 || data[1] != *(data - reps[0] + 1))
+ if (
+ // nextOpt->price >= kInfinityPrice ||
+ nextOpt->len < 2 // we can check nextOpt->len, if skip items are not allowed in p->opt
+ || (nextOpt->dist != 0
+ // && nextOpt->extra <= 1 // 17.old
+ )
+ )
+ {
+ UInt32 shortRepPrice = repMatchPrice + GetPrice_ShortRep(p, state, posState);
+ // if (shortRepPrice <= nextOpt->price) // 17.old
+ if (shortRepPrice < nextOpt->price) // 18.new
+ {
+ nextOpt->price = shortRepPrice;
+ nextOpt->len = 1;
+ MakeAs_ShortRep(nextOpt)
+ nextIsLit = False;
+ }
+ }
+
+ if (numAvailFull < 2)
+ continue;
+ numAvail = (numAvailFull <= p->numFastBytes ? numAvailFull : p->numFastBytes);
+
+ // numAvail <= p->numFastBytes
+
+ // ---------- LIT : REP_0 ----------
+
+ if (!nextIsLit
+ && litPrice != 0 // 18.new
+ && matchByte != curByte
+ && numAvailFull > 2)
+ {
+ const Byte *data2 = data - reps[0];
+ if (data[1] == data2[1] && data[2] == data2[2])
+ {
+ unsigned len;
+ unsigned limit = p->numFastBytes + 1;
+ if (limit > numAvailFull)
+ limit = numAvailFull;
+ for (len = 3; len < limit && data[len] == data2[len]; len++)
+ {}
+
+ {
+ unsigned state2 = kLiteralNextStates[state];
+ unsigned posState2 = (position + 1) & p->pbMask;
+ UInt32 price = litPrice + GetPrice_Rep_0(p, state2, posState2);
+ {
+ unsigned offset = cur + len;
+
+ if (last < offset)
+ last = offset;
+
+ // do
+ {
+ UInt32 price2;
+ COptimal *opt;
+ len--;
+ // price2 = price + GetPrice_Len_Rep_0(p, len, state2, posState2);
+ price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len);
+
+ opt = &p->opt[offset];
+ // offset--;
+ if (price2 < opt->price)
+ {
+ opt->price = price2;
+ opt->len = (UInt32)len;
+ opt->dist = 0;
+ opt->extra = 1;
+ }
+ }
+ // while (len >= 3);
+ }
+ }
+ }
+ }
+
+ startLen = 2; /* speed optimization */
+
+ {
+ // ---------- REP ----------
+ unsigned repIndex = 0; // 17.old
+ // unsigned repIndex = IsLitState(state) ? 0 : 1; // 18.notused
+ for (; repIndex < LZMA_NUM_REPS; repIndex++)
+ {
+ unsigned len;
+ UInt32 price;
+ const Byte *data2 = data - reps[repIndex];
+ if (data[0] != data2[0] || data[1] != data2[1])
+ continue;
+
+ for (len = 2; len < numAvail && data[len] == data2[len]; len++)
+ {}
+
+ // if (len < startLen) continue; // 18.new: speed optimization
+
+ {
+ unsigned offset = cur + len;
+ if (last < offset)
+ last = offset;
+ }
+ {
+ unsigned len2 = len;
+ price = repMatchPrice + GetPrice_PureRep(p, repIndex, state, posState);
+ do
+ {
+ UInt32 price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState, len2);
+ COptimal *opt = &p->opt[cur + len2];
+ if (price2 < opt->price)
+ {
+ opt->price = price2;
+ opt->len = (UInt32)len2;
+ opt->dist = (UInt32)repIndex;
+ opt->extra = 0;
+ }
+ }
+ while (--len2 >= 2);
+ }
+
+ if (repIndex == 0) startLen = len + 1; // 17.old
+ // startLen = len + 1; // 18.new
+
+ /* if (_maxMode) */
+ {
+ // ---------- REP : LIT : REP_0 ----------
+ // numFastBytes + 1 + numFastBytes
+
+ unsigned len2 = len + 1;
+ unsigned limit = len2 + p->numFastBytes;
+ if (limit > numAvailFull)
+ limit = numAvailFull;
+
+ len2 += 2;
+ if (len2 <= limit)
+ if (data[len2 - 2] == data2[len2 - 2])
+ if (data[len2 - 1] == data2[len2 - 1])
+ {
+ unsigned state2 = kRepNextStates[state];
+ unsigned posState2 = (position + len) & p->pbMask;
+ price += GET_PRICE_LEN(&p->repLenEnc, posState, len)
+ + GET_PRICE_0(p->isMatch[state2][posState2])
+ + LitEnc_Matched_GetPrice(LIT_PROBS(position + len, data[(size_t)len - 1]),
+ data[len], data2[len], p->ProbPrices);
+
+ // state2 = kLiteralNextStates[state2];
+ state2 = kState_LitAfterRep;
+ posState2 = (posState2 + 1) & p->pbMask;
+
+
+ price += GetPrice_Rep_0(p, state2, posState2);
+
+ for (; len2 < limit && data[len2] == data2[len2]; len2++)
+ {}
+
+ len2 -= len;
+ // if (len2 >= 3)
+ {
+ {
+ unsigned offset = cur + len + len2;
+
+ if (last < offset)
+ last = offset;
+ // do
+ {
+ UInt32 price2;
+ COptimal *opt;
+ len2--;
+ // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2);
+ price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len2);
+
+ opt = &p->opt[offset];
+ // offset--;
+ if (price2 < opt->price)
+ {
+ opt->price = price2;
+ opt->len = (UInt32)len2;
+ opt->extra = (CExtra)(len + 1);
+ opt->dist = (UInt32)repIndex;
+ }
+ }
+ // while (len2 >= 3);
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ // ---------- MATCH ----------
+ /* for (unsigned len = 2; len <= newLen; len++) */
+ if (newLen > numAvail)
+ {
+ newLen = numAvail;
+ for (numPairs = 0; newLen > MATCHES[numPairs]; numPairs += 2);
+ MATCHES[numPairs] = (UInt32)newLen;
+ numPairs += 2;
+ }
+
+ // startLen = 2; /* speed optimization */
+
+ if (newLen >= startLen)
+ {
+ UInt32 normalMatchPrice = matchPrice + GET_PRICE_0(p->isRep[state]);
+ UInt32 dist;
+ unsigned offs, posSlot, len;
+
+ {
+ unsigned offset = cur + newLen;
+ if (last < offset)
+ last = offset;
+ }
+
+ offs = 0;
+ while (startLen > MATCHES[offs])
+ offs += 2;
+ dist = MATCHES[(size_t)offs + 1];
+
+ // if (dist >= kNumFullDistances)
+ GetPosSlot2(dist, posSlot)
+
+ for (len = /*2*/ startLen; ; len++)
+ {
+ UInt32 price = normalMatchPrice + GET_PRICE_LEN(&p->lenEnc, posState, len);
+ {
+ COptimal *opt;
+ unsigned lenNorm = len - 2;
+ lenNorm = GetLenToPosState2(lenNorm);
+ if (dist < kNumFullDistances)
+ price += p->distancesPrices[lenNorm][dist & (kNumFullDistances - 1)];
+ else
+ price += p->posSlotPrices[lenNorm][posSlot] + p->alignPrices[dist & kAlignMask];
+
+ opt = &p->opt[cur + len];
+ if (price < opt->price)
+ {
+ opt->price = price;
+ opt->len = (UInt32)len;
+ opt->dist = dist + LZMA_NUM_REPS;
+ opt->extra = 0;
+ }
+ }
+
+ if (len == MATCHES[offs])
+ {
+ // if (p->_maxMode) {
+ // MATCH : LIT : REP_0
+
+ const Byte *data2 = data - dist - 1;
+ unsigned len2 = len + 1;
+ unsigned limit = len2 + p->numFastBytes;
+ if (limit > numAvailFull)
+ limit = numAvailFull;
+
+ len2 += 2;
+ if (len2 <= limit)
+ if (data[len2 - 2] == data2[len2 - 2])
+ if (data[len2 - 1] == data2[len2 - 1])
+ {
+ for (; len2 < limit && data[len2] == data2[len2]; len2++)
+ {}
+
+ len2 -= len;
+
+ // if (len2 >= 3)
+ {
+ unsigned state2 = kMatchNextStates[state];
+ unsigned posState2 = (position + len) & p->pbMask;
+ unsigned offset;
+ price += GET_PRICE_0(p->isMatch[state2][posState2]);
+ price += LitEnc_Matched_GetPrice(LIT_PROBS(position + len, data[(size_t)len - 1]),
+ data[len], data2[len], p->ProbPrices);
+
+ // state2 = kLiteralNextStates[state2];
+ state2 = kState_LitAfterMatch;
+
+ posState2 = (posState2 + 1) & p->pbMask;
+ price += GetPrice_Rep_0(p, state2, posState2);
+
+ offset = cur + len + len2;
+
+ if (last < offset)
+ last = offset;
+ // do
+ {
+ UInt32 price2;
+ COptimal *opt;
+ len2--;
+ // price2 = price + GetPrice_Len_Rep_0(p, len2, state2, posState2);
+ price2 = price + GET_PRICE_LEN(&p->repLenEnc, posState2, len2);
+ opt = &p->opt[offset];
+ // offset--;
+ if (price2 < opt->price)
+ {
+ opt->price = price2;
+ opt->len = (UInt32)len2;
+ opt->extra = (CExtra)(len + 1);
+ opt->dist = dist + LZMA_NUM_REPS;
+ }
+ }
+ // while (len2 >= 3);
+ }
+
+ }
+
+ offs += 2;
+ if (offs == numPairs)
+ break;
+ dist = MATCHES[(size_t)offs + 1];
+ // if (dist >= kNumFullDistances)
+ GetPosSlot2(dist, posSlot)
+ }
+ }
+ }
+ }
+
+ do
+ p->opt[last].price = kInfinityPrice;
+ while (--last);
+
+ return Backward(p, cur);
+}
+
+
+
+#define ChangePair(smallDist, bigDist) (((bigDist) >> 7) > (smallDist))
+
+
+
+static unsigned GetOptimumFast(CLzmaEnc *p)
+{
+ UInt32 numAvail, mainDist;
+ unsigned mainLen, numPairs, repIndex, repLen, i;
+ const Byte *data;
+
+ if (p->additionalOffset == 0)
+ mainLen = ReadMatchDistances(p, &numPairs);
+ else
+ {
+ mainLen = p->longestMatchLen;
+ numPairs = p->numPairs;
+ }
+
+ numAvail = p->numAvail;
+ p->backRes = MARK_LIT;
+ if (numAvail < 2)
+ return 1;
+ // if (mainLen < 2 && p->state == 0) return 1; // 18.06.notused
+ if (numAvail > LZMA_MATCH_LEN_MAX)
+ numAvail = LZMA_MATCH_LEN_MAX;
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+ repLen = repIndex = 0;
+
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ unsigned len;
+ const Byte *data2 = data - p->reps[i];
+ if (data[0] != data2[0] || data[1] != data2[1])
+ continue;
+ for (len = 2; len < numAvail && data[len] == data2[len]; len++)
+ {}
+ if (len >= p->numFastBytes)
+ {
+ p->backRes = (UInt32)i;
+ MOVE_POS(p, len - 1)
+ return len;
+ }
+ if (len > repLen)
+ {
+ repIndex = i;
+ repLen = len;
+ }
+ }
+
+ if (mainLen >= p->numFastBytes)
+ {
+ p->backRes = p->matches[(size_t)numPairs - 1] + LZMA_NUM_REPS;
+ MOVE_POS(p, mainLen - 1)
+ return mainLen;
+ }
+
+ mainDist = 0; /* for GCC */
+
+ if (mainLen >= 2)
+ {
+ mainDist = p->matches[(size_t)numPairs - 1];
+ while (numPairs > 2)
+ {
+ UInt32 dist2;
+ if (mainLen != p->matches[(size_t)numPairs - 4] + 1)
+ break;
+ dist2 = p->matches[(size_t)numPairs - 3];
+ if (!ChangePair(dist2, mainDist))
+ break;
+ numPairs -= 2;
+ mainLen--;
+ mainDist = dist2;
+ }
+ if (mainLen == 2 && mainDist >= 0x80)
+ mainLen = 1;
+ }
+
+ if (repLen >= 2)
+ if ( repLen + 1 >= mainLen
+ || (repLen + 2 >= mainLen && mainDist >= (1 << 9))
+ || (repLen + 3 >= mainLen && mainDist >= (1 << 15)))
+ {
+ p->backRes = (UInt32)repIndex;
+ MOVE_POS(p, repLen - 1)
+ return repLen;
+ }
+
+ if (mainLen < 2 || numAvail <= 2)
+ return 1;
+
+ {
+ unsigned len1 = ReadMatchDistances(p, &p->numPairs);
+ p->longestMatchLen = len1;
+
+ if (len1 >= 2)
+ {
+ UInt32 newDist = p->matches[(size_t)p->numPairs - 1];
+ if ( (len1 >= mainLen && newDist < mainDist)
+ || (len1 == mainLen + 1 && !ChangePair(mainDist, newDist))
+ || (len1 > mainLen + 1)
+ || (len1 + 1 >= mainLen && mainLen >= 3 && ChangePair(newDist, mainDist)))
+ return 1;
+ }
+ }
+
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - 1;
+
+ for (i = 0; i < LZMA_NUM_REPS; i++)
+ {
+ unsigned len, limit;
+ const Byte *data2 = data - p->reps[i];
+ if (data[0] != data2[0] || data[1] != data2[1])
+ continue;
+ limit = mainLen - 1;
+ for (len = 2;; len++)
+ {
+ if (len >= limit)
+ return 1;
+ if (data[len] != data2[len])
+ break;
+ }
+ }
+
+ p->backRes = mainDist + LZMA_NUM_REPS;
+ if (mainLen != 2)
+ {
+ MOVE_POS(p, mainLen - 2)
+ }
+ return mainLen;
+}
+
+
+
+
+static void WriteEndMarker(CLzmaEnc *p, unsigned posState)
+{
+ UInt32 range;
+ range = p->rc.range;
+ {
+ UInt32 ttt, newBound;
+ CLzmaProb *prob = &p->isMatch[p->state][posState];
+ RC_BIT_PRE(&p->rc, prob)
+ RC_BIT_1(&p->rc, prob)
+ prob = &p->isRep[p->state];
+ RC_BIT_PRE(&p->rc, prob)
+ RC_BIT_0(&p->rc, prob)
+ }
+ p->state = kMatchNextStates[p->state];
+
+ p->rc.range = range;
+ LenEnc_Encode(&p->lenProbs, &p->rc, 0, posState);
+ range = p->rc.range;
+
+ {
+ // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[0], (1 << kNumPosSlotBits) - 1);
+ CLzmaProb *probs = p->posSlotEncoder[0];
+ unsigned m = 1;
+ do
+ {
+ UInt32 ttt, newBound;
+ RC_BIT_PRE(p, probs + m)
+ RC_BIT_1(&p->rc, probs + m)
+ m = (m << 1) + 1;
+ }
+ while (m < (1 << kNumPosSlotBits));
+ }
+ {
+ // RangeEnc_EncodeDirectBits(&p->rc, ((UInt32)1 << (30 - kNumAlignBits)) - 1, 30 - kNumAlignBits); UInt32 range = p->range;
+ unsigned numBits = 30 - kNumAlignBits;
+ do
+ {
+ range >>= 1;
+ p->rc.low += range;
+ RC_NORM(&p->rc)
+ }
+ while (--numBits);
+ }
+
+ {
+ // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, kAlignMask);
+ CLzmaProb *probs = p->posAlignEncoder;
+ unsigned m = 1;
+ do
+ {
+ UInt32 ttt, newBound;
+ RC_BIT_PRE(p, probs + m)
+ RC_BIT_1(&p->rc, probs + m)
+ m = (m << 1) + 1;
+ }
+ while (m < kAlignTableSize);
+ }
+ p->rc.range = range;
+}
+
+
+static SRes CheckErrors(CLzmaEnc *p)
+{
+ if (p->result != SZ_OK)
+ return p->result;
+ if (p->rc.res != SZ_OK)
+ p->result = SZ_ERROR_WRITE;
+
+ #ifndef Z7_ST
+ if (
+ // p->mf_Failure ||
+ (p->mtMode &&
+ ( // p->matchFinderMt.failure_LZ_LZ ||
+ p->matchFinderMt.failure_LZ_BT))
+ )
+ {
+ p->result = MY_HRES_ERROR_INTERNAL_ERROR;
+ // printf("\nCheckErrors p->matchFinderMt.failureLZ\n");
+ }
+ #endif
+
+ if (MFB.result != SZ_OK)
+ p->result = SZ_ERROR_READ;
+
+ if (p->result != SZ_OK)
+ p->finished = True;
+ return p->result;
+}
+
+
+Z7_NO_INLINE static SRes Flush(CLzmaEnc *p, UInt32 nowPos)
+{
+ /* ReleaseMFStream(); */
+ p->finished = True;
+ if (p->writeEndMark)
+ WriteEndMarker(p, nowPos & p->pbMask);
+ RangeEnc_FlushData(&p->rc);
+ RangeEnc_FlushStream(&p->rc);
+ return CheckErrors(p);
+}
+
+
+Z7_NO_INLINE static void FillAlignPrices(CLzmaEnc *p)
+{
+ unsigned i;
+ const CProbPrice *ProbPrices = p->ProbPrices;
+ const CLzmaProb *probs = p->posAlignEncoder;
+ // p->alignPriceCount = 0;
+ for (i = 0; i < kAlignTableSize / 2; i++)
+ {
+ UInt32 price = 0;
+ unsigned sym = i;
+ unsigned m = 1;
+ unsigned bit;
+ UInt32 prob;
+ bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit;
+ bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit;
+ bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[m], bit); m = (m << 1) + bit;
+ prob = probs[m];
+ p->alignPrices[i ] = price + GET_PRICEa_0(prob);
+ p->alignPrices[i + 8] = price + GET_PRICEa_1(prob);
+ // p->alignPrices[i] = RcTree_ReverseGetPrice(p->posAlignEncoder, kNumAlignBits, i, p->ProbPrices);
+ }
+}
+
+
+Z7_NO_INLINE static void FillDistancesPrices(CLzmaEnc *p)
+{
+ // int y; for (y = 0; y < 100; y++) {
+
+ UInt32 tempPrices[kNumFullDistances];
+ unsigned i, lps;
+
+ const CProbPrice *ProbPrices = p->ProbPrices;
+ p->matchPriceCount = 0;
+
+ for (i = kStartPosModelIndex / 2; i < kNumFullDistances / 2; i++)
+ {
+ unsigned posSlot = GetPosSlot1(i);
+ unsigned footerBits = (posSlot >> 1) - 1;
+ unsigned base = ((2 | (posSlot & 1)) << footerBits);
+ const CLzmaProb *probs = p->posEncoders + (size_t)base * 2;
+ // tempPrices[i] = RcTree_ReverseGetPrice(p->posEncoders + base, footerBits, i - base, p->ProbPrices);
+ UInt32 price = 0;
+ unsigned m = 1;
+ unsigned sym = i;
+ unsigned offset = (unsigned)1 << footerBits;
+ base += i;
+
+ if (footerBits)
+ do
+ {
+ unsigned bit = sym & 1;
+ sym >>= 1;
+ price += GET_PRICEa(probs[m], bit);
+ m = (m << 1) + bit;
+ }
+ while (--footerBits);
+
+ {
+ unsigned prob = probs[m];
+ tempPrices[base ] = price + GET_PRICEa_0(prob);
+ tempPrices[base + offset] = price + GET_PRICEa_1(prob);
+ }
+ }
+
+ for (lps = 0; lps < kNumLenToPosStates; lps++)
+ {
+ unsigned slot;
+ unsigned distTableSize2 = (p->distTableSize + 1) >> 1;
+ UInt32 *posSlotPrices = p->posSlotPrices[lps];
+ const CLzmaProb *probs = p->posSlotEncoder[lps];
+
+ for (slot = 0; slot < distTableSize2; slot++)
+ {
+ // posSlotPrices[slot] = RcTree_GetPrice(encoder, kNumPosSlotBits, slot, p->ProbPrices);
+ UInt32 price;
+ unsigned bit;
+ unsigned sym = slot + (1 << (kNumPosSlotBits - 1));
+ unsigned prob;
+ bit = sym & 1; sym >>= 1; price = GET_PRICEa(probs[sym], bit);
+ bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit);
+ bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit);
+ bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit);
+ bit = sym & 1; sym >>= 1; price += GET_PRICEa(probs[sym], bit);
+ prob = probs[(size_t)slot + (1 << (kNumPosSlotBits - 1))];
+ posSlotPrices[(size_t)slot * 2 ] = price + GET_PRICEa_0(prob);
+ posSlotPrices[(size_t)slot * 2 + 1] = price + GET_PRICEa_1(prob);
+ }
+
+ {
+ UInt32 delta = ((UInt32)((kEndPosModelIndex / 2 - 1) - kNumAlignBits) << kNumBitPriceShiftBits);
+ for (slot = kEndPosModelIndex / 2; slot < distTableSize2; slot++)
+ {
+ posSlotPrices[(size_t)slot * 2 ] += delta;
+ posSlotPrices[(size_t)slot * 2 + 1] += delta;
+ delta += ((UInt32)1 << kNumBitPriceShiftBits);
+ }
+ }
+
+ {
+ UInt32 *dp = p->distancesPrices[lps];
+
+ dp[0] = posSlotPrices[0];
+ dp[1] = posSlotPrices[1];
+ dp[2] = posSlotPrices[2];
+ dp[3] = posSlotPrices[3];
+
+ for (i = 4; i < kNumFullDistances; i += 2)
+ {
+ UInt32 slotPrice = posSlotPrices[GetPosSlot1(i)];
+ dp[i ] = slotPrice + tempPrices[i];
+ dp[i + 1] = slotPrice + tempPrices[i + 1];
+ }
+ }
+ }
+ // }
+}
+
+
+
+static void LzmaEnc_Construct(CLzmaEnc *p)
+{
+ RangeEnc_Construct(&p->rc);
+ MatchFinder_Construct(&MFB);
+
+ #ifndef Z7_ST
+ p->matchFinderMt.MatchFinder = &MFB;
+ MatchFinderMt_Construct(&p->matchFinderMt);
+ #endif
+
+ {
+ CLzmaEncProps props;
+ LzmaEncProps_Init(&props);
+ LzmaEnc_SetProps((CLzmaEncHandle)(void *)p, &props);
+ }
+
+ #ifndef LZMA_LOG_BSR
+ LzmaEnc_FastPosInit(p->g_FastPos);
+ #endif
+
+ LzmaEnc_InitPriceTables(p->ProbPrices);
+ p->litProbs = NULL;
+ p->saveState.litProbs = NULL;
+}
+
+CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc)
+{
+ void *p;
+ p = ISzAlloc_Alloc(alloc, sizeof(CLzmaEnc));
+ if (p)
+ LzmaEnc_Construct((CLzmaEnc *)p);
+ return p;
+}
+
+static void LzmaEnc_FreeLits(CLzmaEnc *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->litProbs);
+ ISzAlloc_Free(alloc, p->saveState.litProbs);
+ p->litProbs = NULL;
+ p->saveState.litProbs = NULL;
+}
+
+static void LzmaEnc_Destruct(CLzmaEnc *p, ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ #ifndef Z7_ST
+ MatchFinderMt_Destruct(&p->matchFinderMt, allocBig);
+ #endif
+
+ MatchFinder_Free(&MFB, allocBig);
+ LzmaEnc_FreeLits(p, alloc);
+ RangeEnc_Free(&p->rc, alloc);
+}
+
+void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ // GET_CLzmaEnc_p
+ LzmaEnc_Destruct(p, alloc, allocBig);
+ ISzAlloc_Free(alloc, p);
+}
+
+
+Z7_NO_INLINE
+static SRes LzmaEnc_CodeOneBlock(CLzmaEnc *p, UInt32 maxPackSize, UInt32 maxUnpackSize)
+{
+ UInt32 nowPos32, startPos32;
+ if (p->needInit)
+ {
+ #ifndef Z7_ST
+ if (p->mtMode)
+ {
+ RINOK(MatchFinderMt_InitMt(&p->matchFinderMt))
+ }
+ #endif
+ p->matchFinder.Init(p->matchFinderObj);
+ p->needInit = 0;
+ }
+
+ if (p->finished)
+ return p->result;
+ RINOK(CheckErrors(p))
+
+ nowPos32 = (UInt32)p->nowPos64;
+ startPos32 = nowPos32;
+
+ if (p->nowPos64 == 0)
+ {
+ unsigned numPairs;
+ Byte curByte;
+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
+ return Flush(p, nowPos32);
+ ReadMatchDistances(p, &numPairs);
+ RangeEnc_EncodeBit_0(&p->rc, &p->isMatch[kState_Start][0]);
+ // p->state = kLiteralNextStates[p->state];
+ curByte = *(p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset);
+ LitEnc_Encode(&p->rc, p->litProbs, curByte);
+ p->additionalOffset--;
+ nowPos32++;
+ }
+
+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) != 0)
+
+ for (;;)
+ {
+ UInt32 dist;
+ unsigned len, posState;
+ UInt32 range, ttt, newBound;
+ CLzmaProb *probs;
+
+ if (p->fastMode)
+ len = GetOptimumFast(p);
+ else
+ {
+ unsigned oci = p->optCur;
+ if (p->optEnd == oci)
+ len = GetOptimum(p, nowPos32);
+ else
+ {
+ const COptimal *opt = &p->opt[oci];
+ len = opt->len;
+ p->backRes = opt->dist;
+ p->optCur = oci + 1;
+ }
+ }
+
+ posState = (unsigned)nowPos32 & p->pbMask;
+ range = p->rc.range;
+ probs = &p->isMatch[p->state][posState];
+
+ RC_BIT_PRE(&p->rc, probs)
+
+ dist = p->backRes;
+
+ #ifdef SHOW_STAT2
+ printf("\n pos = %6X, len = %3u pos = %6u", nowPos32, len, dist);
+ #endif
+
+ if (dist == MARK_LIT)
+ {
+ Byte curByte;
+ const Byte *data;
+ unsigned state;
+
+ RC_BIT_0(&p->rc, probs)
+ p->rc.range = range;
+ data = p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
+ probs = LIT_PROBS(nowPos32, *(data - 1));
+ curByte = *data;
+ state = p->state;
+ p->state = kLiteralNextStates[state];
+ if (IsLitState(state))
+ LitEnc_Encode(&p->rc, probs, curByte);
+ else
+ LitEnc_EncodeMatched(&p->rc, probs, curByte, *(data - p->reps[0]));
+ }
+ else
+ {
+ RC_BIT_1(&p->rc, probs)
+ probs = &p->isRep[p->state];
+ RC_BIT_PRE(&p->rc, probs)
+
+ if (dist < LZMA_NUM_REPS)
+ {
+ RC_BIT_1(&p->rc, probs)
+ probs = &p->isRepG0[p->state];
+ RC_BIT_PRE(&p->rc, probs)
+ if (dist == 0)
+ {
+ RC_BIT_0(&p->rc, probs)
+ probs = &p->isRep0Long[p->state][posState];
+ RC_BIT_PRE(&p->rc, probs)
+ if (len != 1)
+ {
+ RC_BIT_1_BASE(&p->rc, probs)
+ }
+ else
+ {
+ RC_BIT_0_BASE(&p->rc, probs)
+ p->state = kShortRepNextStates[p->state];
+ }
+ }
+ else
+ {
+ RC_BIT_1(&p->rc, probs)
+ probs = &p->isRepG1[p->state];
+ RC_BIT_PRE(&p->rc, probs)
+ if (dist == 1)
+ {
+ RC_BIT_0_BASE(&p->rc, probs)
+ dist = p->reps[1];
+ }
+ else
+ {
+ RC_BIT_1(&p->rc, probs)
+ probs = &p->isRepG2[p->state];
+ RC_BIT_PRE(&p->rc, probs)
+ if (dist == 2)
+ {
+ RC_BIT_0_BASE(&p->rc, probs)
+ dist = p->reps[2];
+ }
+ else
+ {
+ RC_BIT_1_BASE(&p->rc, probs)
+ dist = p->reps[3];
+ p->reps[3] = p->reps[2];
+ }
+ p->reps[2] = p->reps[1];
+ }
+ p->reps[1] = p->reps[0];
+ p->reps[0] = dist;
+ }
+
+ RC_NORM(&p->rc)
+
+ p->rc.range = range;
+
+ if (len != 1)
+ {
+ LenEnc_Encode(&p->repLenProbs, &p->rc, len - LZMA_MATCH_LEN_MIN, posState);
+ --p->repLenEncCounter;
+ p->state = kRepNextStates[p->state];
+ }
+ }
+ else
+ {
+ unsigned posSlot;
+ RC_BIT_0(&p->rc, probs)
+ p->rc.range = range;
+ p->state = kMatchNextStates[p->state];
+
+ LenEnc_Encode(&p->lenProbs, &p->rc, len - LZMA_MATCH_LEN_MIN, posState);
+ // --p->lenEnc.counter;
+
+ dist -= LZMA_NUM_REPS;
+ p->reps[3] = p->reps[2];
+ p->reps[2] = p->reps[1];
+ p->reps[1] = p->reps[0];
+ p->reps[0] = dist + 1;
+
+ p->matchPriceCount++;
+ GetPosSlot(dist, posSlot)
+ // RcTree_Encode_PosSlot(&p->rc, p->posSlotEncoder[GetLenToPosState(len)], posSlot);
+ {
+ UInt32 sym = (UInt32)posSlot + (1 << kNumPosSlotBits);
+ range = p->rc.range;
+ probs = p->posSlotEncoder[GetLenToPosState(len)];
+ do
+ {
+ CLzmaProb *prob = probs + (sym >> kNumPosSlotBits);
+ UInt32 bit = (sym >> (kNumPosSlotBits - 1)) & 1;
+ sym <<= 1;
+ RC_BIT(&p->rc, prob, bit)
+ }
+ while (sym < (1 << kNumPosSlotBits * 2));
+ p->rc.range = range;
+ }
+
+ if (dist >= kStartPosModelIndex)
+ {
+ unsigned footerBits = ((posSlot >> 1) - 1);
+
+ if (dist < kNumFullDistances)
+ {
+ unsigned base = ((2 | (posSlot & 1)) << footerBits);
+ RcTree_ReverseEncode(&p->rc, p->posEncoders + base, footerBits, (unsigned)(dist /* - base */));
+ }
+ else
+ {
+ UInt32 pos2 = (dist | 0xF) << (32 - footerBits);
+ range = p->rc.range;
+ // RangeEnc_EncodeDirectBits(&p->rc, posReduced >> kNumAlignBits, footerBits - kNumAlignBits);
+ /*
+ do
+ {
+ range >>= 1;
+ p->rc.low += range & (0 - ((dist >> --footerBits) & 1));
+ RC_NORM(&p->rc)
+ }
+ while (footerBits > kNumAlignBits);
+ */
+ do
+ {
+ range >>= 1;
+ p->rc.low += range & (0 - (pos2 >> 31));
+ pos2 += pos2;
+ RC_NORM(&p->rc)
+ }
+ while (pos2 != 0xF0000000);
+
+
+ // RcTree_ReverseEncode(&p->rc, p->posAlignEncoder, kNumAlignBits, posReduced & kAlignMask);
+
+ {
+ unsigned m = 1;
+ unsigned bit;
+ bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit) m = (m << 1) + bit;
+ bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit) m = (m << 1) + bit;
+ bit = dist & 1; dist >>= 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit) m = (m << 1) + bit;
+ bit = dist & 1; RC_BIT(&p->rc, p->posAlignEncoder + m, bit)
+ p->rc.range = range;
+ // p->alignPriceCount++;
+ }
+ }
+ }
+ }
+ }
+
+ nowPos32 += (UInt32)len;
+ p->additionalOffset -= len;
+
+ if (p->additionalOffset == 0)
+ {
+ UInt32 processed;
+
+ if (!p->fastMode)
+ {
+ /*
+ if (p->alignPriceCount >= 16) // kAlignTableSize
+ FillAlignPrices(p);
+ if (p->matchPriceCount >= 128)
+ FillDistancesPrices(p);
+ if (p->lenEnc.counter <= 0)
+ LenPriceEnc_UpdateTables(&p->lenEnc, 1 << p->pb, &p->lenProbs, p->ProbPrices);
+ */
+ if (p->matchPriceCount >= 64)
+ {
+ FillAlignPrices(p);
+ // { int y; for (y = 0; y < 100; y++) {
+ FillDistancesPrices(p);
+ // }}
+ LenPriceEnc_UpdateTables(&p->lenEnc, (unsigned)1 << p->pb, &p->lenProbs, p->ProbPrices);
+ }
+ if (p->repLenEncCounter <= 0)
+ {
+ p->repLenEncCounter = REP_LEN_COUNT;
+ LenPriceEnc_UpdateTables(&p->repLenEnc, (unsigned)1 << p->pb, &p->repLenProbs, p->ProbPrices);
+ }
+ }
+
+ if (p->matchFinder.GetNumAvailableBytes(p->matchFinderObj) == 0)
+ break;
+ processed = nowPos32 - startPos32;
+
+ if (maxPackSize)
+ {
+ if (processed + kNumOpts + 300 >= maxUnpackSize
+ || RangeEnc_GetProcessed_sizet(&p->rc) + kPackReserve >= maxPackSize)
+ break;
+ }
+ else if (processed >= (1 << 17))
+ {
+ p->nowPos64 += nowPos32 - startPos32;
+ return CheckErrors(p);
+ }
+ }
+ }
+
+ p->nowPos64 += nowPos32 - startPos32;
+ return Flush(p, nowPos32);
+}
+
+
+
+#define kBigHashDicLimit ((UInt32)1 << 24)
+
+static SRes LzmaEnc_Alloc(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ UInt32 beforeSize = kNumOpts;
+ UInt32 dictSize;
+
+ if (!RangeEnc_Alloc(&p->rc, alloc))
+ return SZ_ERROR_MEM;
+
+ #ifndef Z7_ST
+ p->mtMode = (p->multiThread && !p->fastMode && (MFB.btMode != 0));
+ #endif
+
+ {
+ unsigned lclp = p->lc + p->lp;
+ if (!p->litProbs || !p->saveState.litProbs || p->lclp != lclp)
+ {
+ LzmaEnc_FreeLits(p, alloc);
+ p->litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb));
+ p->saveState.litProbs = (CLzmaProb *)ISzAlloc_Alloc(alloc, ((UInt32)0x300 << lclp) * sizeof(CLzmaProb));
+ if (!p->litProbs || !p->saveState.litProbs)
+ {
+ LzmaEnc_FreeLits(p, alloc);
+ return SZ_ERROR_MEM;
+ }
+ p->lclp = lclp;
+ }
+ }
+
+ MFB.bigHash = (Byte)(p->dictSize > kBigHashDicLimit ? 1 : 0);
+
+
+ dictSize = p->dictSize;
+ if (dictSize == ((UInt32)2 << 30) ||
+ dictSize == ((UInt32)3 << 30))
+ {
+ /* 21.03 : here we reduce the dictionary for 2 reasons:
+ 1) we don't want 32-bit back_distance matches in decoder for 2 GB dictionary.
+ 2) we want to elimate useless last MatchFinder_Normalize3() for corner cases,
+ where data size is aligned for 1 GB: 5/6/8 GB.
+ That reducing must be >= 1 for such corner cases. */
+ dictSize -= 1;
+ }
+
+ if (beforeSize + dictSize < keepWindowSize)
+ beforeSize = keepWindowSize - dictSize;
+
+ /* in worst case we can look ahead for
+ max(LZMA_MATCH_LEN_MAX, numFastBytes + 1 + numFastBytes) bytes.
+ we send larger value for (keepAfter) to MantchFinder_Create():
+ (numFastBytes + LZMA_MATCH_LEN_MAX + 1)
+ */
+
+ #ifndef Z7_ST
+ if (p->mtMode)
+ {
+ RINOK(MatchFinderMt_Create(&p->matchFinderMt, dictSize, beforeSize,
+ p->numFastBytes, LZMA_MATCH_LEN_MAX + 1 /* 18.04 */
+ , allocBig))
+ p->matchFinderObj = &p->matchFinderMt;
+ MFB.bigHash = (Byte)(MFB.hashMask >= 0xFFFFFF ? 1 : 0);
+ MatchFinderMt_CreateVTable(&p->matchFinderMt, &p->matchFinder);
+ }
+ else
+ #endif
+ {
+ if (!MatchFinder_Create(&MFB, dictSize, beforeSize,
+ p->numFastBytes, LZMA_MATCH_LEN_MAX + 1 /* 21.03 */
+ , allocBig))
+ return SZ_ERROR_MEM;
+ p->matchFinderObj = &MFB;
+ MatchFinder_CreateVTable(&MFB, &p->matchFinder);
+ }
+
+ return SZ_OK;
+}
+
+static void LzmaEnc_Init(CLzmaEnc *p)
+{
+ unsigned i;
+ p->state = 0;
+ p->reps[0] =
+ p->reps[1] =
+ p->reps[2] =
+ p->reps[3] = 1;
+
+ RangeEnc_Init(&p->rc);
+
+ for (i = 0; i < (1 << kNumAlignBits); i++)
+ p->posAlignEncoder[i] = kProbInitValue;
+
+ for (i = 0; i < kNumStates; i++)
+ {
+ unsigned j;
+ for (j = 0; j < LZMA_NUM_PB_STATES_MAX; j++)
+ {
+ p->isMatch[i][j] = kProbInitValue;
+ p->isRep0Long[i][j] = kProbInitValue;
+ }
+ p->isRep[i] = kProbInitValue;
+ p->isRepG0[i] = kProbInitValue;
+ p->isRepG1[i] = kProbInitValue;
+ p->isRepG2[i] = kProbInitValue;
+ }
+
+ {
+ for (i = 0; i < kNumLenToPosStates; i++)
+ {
+ CLzmaProb *probs = p->posSlotEncoder[i];
+ unsigned j;
+ for (j = 0; j < (1 << kNumPosSlotBits); j++)
+ probs[j] = kProbInitValue;
+ }
+ }
+ {
+ for (i = 0; i < kNumFullDistances; i++)
+ p->posEncoders[i] = kProbInitValue;
+ }
+
+ {
+ UInt32 num = (UInt32)0x300 << (p->lp + p->lc);
+ UInt32 k;
+ CLzmaProb *probs = p->litProbs;
+ for (k = 0; k < num; k++)
+ probs[k] = kProbInitValue;
+ }
+
+
+ LenEnc_Init(&p->lenProbs);
+ LenEnc_Init(&p->repLenProbs);
+
+ p->optEnd = 0;
+ p->optCur = 0;
+
+ {
+ for (i = 0; i < kNumOpts; i++)
+ p->opt[i].price = kInfinityPrice;
+ }
+
+ p->additionalOffset = 0;
+
+ p->pbMask = ((unsigned)1 << p->pb) - 1;
+ p->lpMask = ((UInt32)0x100 << p->lp) - ((unsigned)0x100 >> p->lc);
+
+ // p->mf_Failure = False;
+}
+
+
+static void LzmaEnc_InitPrices(CLzmaEnc *p)
+{
+ if (!p->fastMode)
+ {
+ FillDistancesPrices(p);
+ FillAlignPrices(p);
+ }
+
+ p->lenEnc.tableSize =
+ p->repLenEnc.tableSize =
+ p->numFastBytes + 1 - LZMA_MATCH_LEN_MIN;
+
+ p->repLenEncCounter = REP_LEN_COUNT;
+
+ LenPriceEnc_UpdateTables(&p->lenEnc, (unsigned)1 << p->pb, &p->lenProbs, p->ProbPrices);
+ LenPriceEnc_UpdateTables(&p->repLenEnc, (unsigned)1 << p->pb, &p->repLenProbs, p->ProbPrices);
+}
+
+static SRes LzmaEnc_AllocAndInit(CLzmaEnc *p, UInt32 keepWindowSize, ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ unsigned i;
+ for (i = kEndPosModelIndex / 2; i < kDicLogSizeMax; i++)
+ if (p->dictSize <= ((UInt32)1 << i))
+ break;
+ p->distTableSize = i * 2;
+
+ p->finished = False;
+ p->result = SZ_OK;
+ p->nowPos64 = 0;
+ p->needInit = 1;
+ RINOK(LzmaEnc_Alloc(p, keepWindowSize, alloc, allocBig))
+ LzmaEnc_Init(p);
+ LzmaEnc_InitPrices(p);
+ return SZ_OK;
+}
+
+static SRes LzmaEnc_Prepare(CLzmaEncHandle p,
+ ISeqOutStreamPtr outStream,
+ ISeqInStreamPtr inStream,
+ ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ // GET_CLzmaEnc_p
+ MatchFinder_SET_STREAM(&MFB, inStream)
+ p->rc.outStream = outStream;
+ return LzmaEnc_AllocAndInit(p, 0, alloc, allocBig);
+}
+
+SRes LzmaEnc_PrepareForLzma2(CLzmaEncHandle p,
+ ISeqInStreamPtr inStream, UInt32 keepWindowSize,
+ ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ // GET_CLzmaEnc_p
+ MatchFinder_SET_STREAM(&MFB, inStream)
+ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
+}
+
+SRes LzmaEnc_MemPrepare(CLzmaEncHandle p,
+ const Byte *src, SizeT srcLen,
+ UInt32 keepWindowSize,
+ ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ // GET_CLzmaEnc_p
+ MatchFinder_SET_DIRECT_INPUT_BUF(&MFB, src, srcLen)
+ LzmaEnc_SetDataSize(p, srcLen);
+ return LzmaEnc_AllocAndInit(p, keepWindowSize, alloc, allocBig);
+}
+
+void LzmaEnc_Finish(CLzmaEncHandle p)
+{
+ #ifndef Z7_ST
+ // GET_CLzmaEnc_p
+ if (p->mtMode)
+ MatchFinderMt_ReleaseStream(&p->matchFinderMt);
+ #else
+ UNUSED_VAR(p)
+ #endif
+}
+
+
+typedef struct
+{
+ ISeqOutStream vt;
+ Byte *data;
+ size_t rem;
+ BoolInt overflow;
+} CLzmaEnc_SeqOutStreamBuf;
+
+static size_t SeqOutStreamBuf_Write(ISeqOutStreamPtr pp, const void *data, size_t size)
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CLzmaEnc_SeqOutStreamBuf)
+ if (p->rem < size)
+ {
+ size = p->rem;
+ p->overflow = True;
+ }
+ if (size != 0)
+ {
+ memcpy(p->data, data, size);
+ p->rem -= size;
+ p->data += size;
+ }
+ return size;
+}
+
+
+/*
+UInt32 LzmaEnc_GetNumAvailableBytes(CLzmaEncHandle p)
+{
+ GET_const_CLzmaEnc_p
+ return p->matchFinder.GetNumAvailableBytes(p->matchFinderObj);
+}
+*/
+
+const Byte *LzmaEnc_GetCurBuf(CLzmaEncHandle p)
+{
+ // GET_const_CLzmaEnc_p
+ return p->matchFinder.GetPointerToCurrentPos(p->matchFinderObj) - p->additionalOffset;
+}
+
+
+// (desiredPackSize == 0) is not allowed
+SRes LzmaEnc_CodeOneMemBlock(CLzmaEncHandle p, BoolInt reInit,
+ Byte *dest, size_t *destLen, UInt32 desiredPackSize, UInt32 *unpackSize)
+{
+ // GET_CLzmaEnc_p
+ UInt64 nowPos64;
+ SRes res;
+ CLzmaEnc_SeqOutStreamBuf outStream;
+
+ outStream.vt.Write = SeqOutStreamBuf_Write;
+ outStream.data = dest;
+ outStream.rem = *destLen;
+ outStream.overflow = False;
+
+ p->writeEndMark = False;
+ p->finished = False;
+ p->result = SZ_OK;
+
+ if (reInit)
+ LzmaEnc_Init(p);
+ LzmaEnc_InitPrices(p);
+ RangeEnc_Init(&p->rc);
+ p->rc.outStream = &outStream.vt;
+ nowPos64 = p->nowPos64;
+
+ res = LzmaEnc_CodeOneBlock(p, desiredPackSize, *unpackSize);
+
+ *unpackSize = (UInt32)(p->nowPos64 - nowPos64);
+ *destLen -= outStream.rem;
+ if (outStream.overflow)
+ return SZ_ERROR_OUTPUT_EOF;
+
+ return res;
+}
+
+
+Z7_NO_INLINE
+static SRes LzmaEnc_Encode2(CLzmaEnc *p, ICompressProgressPtr progress)
+{
+ SRes res = SZ_OK;
+
+ #ifndef Z7_ST
+ Byte allocaDummy[0x300];
+ allocaDummy[0] = 0;
+ allocaDummy[1] = allocaDummy[0];
+ #endif
+
+ for (;;)
+ {
+ res = LzmaEnc_CodeOneBlock(p, 0, 0);
+ if (res != SZ_OK || p->finished)
+ break;
+ if (progress)
+ {
+ res = ICompressProgress_Progress(progress, p->nowPos64, RangeEnc_GetProcessed(&p->rc));
+ if (res != SZ_OK)
+ {
+ res = SZ_ERROR_PROGRESS;
+ break;
+ }
+ }
+ }
+
+ LzmaEnc_Finish((CLzmaEncHandle)(void *)p);
+
+ /*
+ if (res == SZ_OK && !Inline_MatchFinder_IsFinishedOK(&MFB))
+ res = SZ_ERROR_FAIL;
+ }
+ */
+
+ return res;
+}
+
+
+SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, ICompressProgressPtr progress,
+ ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ // GET_CLzmaEnc_p
+ RINOK(LzmaEnc_Prepare(p, outStream, inStream, alloc, allocBig))
+ return LzmaEnc_Encode2(p, progress);
+}
+
+
+SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *props, SizeT *size)
+{
+ if (*size < LZMA_PROPS_SIZE)
+ return SZ_ERROR_PARAM;
+ *size = LZMA_PROPS_SIZE;
+ {
+ // GET_CLzmaEnc_p
+ const UInt32 dictSize = p->dictSize;
+ UInt32 v;
+ props[0] = (Byte)((p->pb * 5 + p->lp) * 9 + p->lc);
+
+ // we write aligned dictionary value to properties for lzma decoder
+ if (dictSize >= ((UInt32)1 << 21))
+ {
+ const UInt32 kDictMask = ((UInt32)1 << 20) - 1;
+ v = (dictSize + kDictMask) & ~kDictMask;
+ if (v < dictSize)
+ v = dictSize;
+ }
+ else
+ {
+ unsigned i = 11 * 2;
+ do
+ {
+ v = (UInt32)(2 + (i & 1)) << (i >> 1);
+ i++;
+ }
+ while (v < dictSize);
+ }
+
+ SetUi32(props + 1, v)
+ return SZ_OK;
+ }
+}
+
+
+unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle p)
+{
+ // GET_CLzmaEnc_p
+ return (unsigned)p->writeEndMark;
+}
+
+
+SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ int writeEndMark, ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ SRes res;
+ // GET_CLzmaEnc_p
+
+ CLzmaEnc_SeqOutStreamBuf outStream;
+
+ outStream.vt.Write = SeqOutStreamBuf_Write;
+ outStream.data = dest;
+ outStream.rem = *destLen;
+ outStream.overflow = False;
+
+ p->writeEndMark = writeEndMark;
+ p->rc.outStream = &outStream.vt;
+
+ res = LzmaEnc_MemPrepare(p, src, srcLen, 0, alloc, allocBig);
+
+ if (res == SZ_OK)
+ {
+ res = LzmaEnc_Encode2(p, progress);
+ if (res == SZ_OK && p->nowPos64 != srcLen)
+ res = SZ_ERROR_FAIL;
+ }
+
+ *destLen -= (SizeT)outStream.rem;
+ if (outStream.overflow)
+ return SZ_ERROR_OUTPUT_EOF;
+ return res;
+}
+
+
+SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+ ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ CLzmaEncHandle p = LzmaEnc_Create(alloc);
+ SRes res;
+ if (!p)
+ return SZ_ERROR_MEM;
+
+ res = LzmaEnc_SetProps(p, props);
+ if (res == SZ_OK)
+ {
+ res = LzmaEnc_WriteProperties(p, propsEncoded, propsSize);
+ if (res == SZ_OK)
+ res = LzmaEnc_MemEncode(p, dest, destLen, src, srcLen,
+ writeEndMark, progress, alloc, allocBig);
+ }
+
+ LzmaEnc_Destroy(p, alloc, allocBig);
+ return res;
+}
+
+
+/*
+#ifndef Z7_ST
+void LzmaEnc_GetLzThreads(CLzmaEncHandle p, HANDLE lz_threads[2])
+{
+ GET_const_CLzmaEnc_p
+ lz_threads[0] = p->matchFinderMt.hashSync.thread;
+ lz_threads[1] = p->matchFinderMt.btSync.thread;
+}
+#endif
+*/
diff --git a/C/LzmaEnc.h b/C/LzmaEnc.h
index c9938f0..9f8039a 100644
--- a/C/LzmaEnc.h
+++ b/C/LzmaEnc.h
@@ -1,76 +1,83 @@
-/* LzmaEnc.h -- LZMA Encoder
-2017-07-27 : Igor Pavlov : Public domain */
-
-#ifndef __LZMA_ENC_H
-#define __LZMA_ENC_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-#define LZMA_PROPS_SIZE 5
-
-typedef struct _CLzmaEncProps
-{
- int level; /* 0 <= level <= 9 */
- UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
- (1 << 12) <= dictSize <= (3 << 29) for 64-bit version
- default = (1 << 24) */
- int lc; /* 0 <= lc <= 8, default = 3 */
- int lp; /* 0 <= lp <= 4, default = 0 */
- int pb; /* 0 <= pb <= 4, default = 2 */
- int algo; /* 0 - fast, 1 - normal, default = 1 */
- int fb; /* 5 <= fb <= 273, default = 32 */
- int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */
- int numHashBytes; /* 2, 3 or 4, default = 4 */
- UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */
- unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */
- int numThreads; /* 1 or 2, default = 2 */
-
- UInt64 reduceSize; /* estimated size of data that will be compressed. default = (UInt64)(Int64)-1.
- Encoder uses this value to reduce dictionary size */
-} CLzmaEncProps;
-
-void LzmaEncProps_Init(CLzmaEncProps *p);
-void LzmaEncProps_Normalize(CLzmaEncProps *p);
-UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
-
-
-/* ---------- CLzmaEncHandle Interface ---------- */
-
-/* LzmaEnc* functions can return the following exit codes:
-SRes:
- SZ_OK - OK
- SZ_ERROR_MEM - Memory allocation error
- SZ_ERROR_PARAM - Incorrect paramater in props
- SZ_ERROR_WRITE - ISeqOutStream write callback error
- SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output
- SZ_ERROR_PROGRESS - some break from progress callback
- SZ_ERROR_THREAD - error in multithreading functions (only for Mt version)
-*/
-
-typedef void * CLzmaEncHandle;
-
-CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc);
-void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig);
-
-SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
-void LzmaEnc_SetDataSize(CLzmaEncHandle p, UInt64 expectedDataSiize);
-SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
-unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle p);
-
-SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream,
- ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig);
-SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
- int writeEndMark, ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig);
-
-
-/* ---------- One Call Interface ---------- */
-
-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
- const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
- ICompressProgress *progress, ISzAllocPtr alloc, ISzAllocPtr allocBig);
-
-EXTERN_C_END
-
-#endif
+/* LzmaEnc.h -- LZMA Encoder
+2023-04-13 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_LZMA_ENC_H
+#define ZIP7_INC_LZMA_ENC_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define LZMA_PROPS_SIZE 5
+
+typedef struct
+{
+ int level; /* 0 <= level <= 9 */
+ UInt32 dictSize; /* (1 << 12) <= dictSize <= (1 << 27) for 32-bit version
+ (1 << 12) <= dictSize <= (3 << 29) for 64-bit version
+ default = (1 << 24) */
+ int lc; /* 0 <= lc <= 8, default = 3 */
+ int lp; /* 0 <= lp <= 4, default = 0 */
+ int pb; /* 0 <= pb <= 4, default = 2 */
+ int algo; /* 0 - fast, 1 - normal, default = 1 */
+ int fb; /* 5 <= fb <= 273, default = 32 */
+ int btMode; /* 0 - hashChain Mode, 1 - binTree mode - normal, default = 1 */
+ int numHashBytes; /* 2, 3 or 4, default = 4 */
+ unsigned numHashOutBits; /* default = ? */
+ UInt32 mc; /* 1 <= mc <= (1 << 30), default = 32 */
+ unsigned writeEndMark; /* 0 - do not write EOPM, 1 - write EOPM, default = 0 */
+ int numThreads; /* 1 or 2, default = 2 */
+
+ // int _pad;
+
+ UInt64 reduceSize; /* estimated size of data that will be compressed. default = (UInt64)(Int64)-1.
+ Encoder uses this value to reduce dictionary size */
+
+ UInt64 affinity;
+} CLzmaEncProps;
+
+void LzmaEncProps_Init(CLzmaEncProps *p);
+void LzmaEncProps_Normalize(CLzmaEncProps *p);
+UInt32 LzmaEncProps_GetDictSize(const CLzmaEncProps *props2);
+
+
+/* ---------- CLzmaEncHandle Interface ---------- */
+
+/* LzmaEnc* functions can return the following exit codes:
+SRes:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater in props
+ SZ_ERROR_WRITE - ISeqOutStream write callback error
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow - version with (Byte *) output
+ SZ_ERROR_PROGRESS - some break from progress callback
+ SZ_ERROR_THREAD - error in multithreading functions (only for Mt version)
+*/
+
+typedef struct CLzmaEnc CLzmaEnc;
+typedef CLzmaEnc * CLzmaEncHandle;
+// Z7_DECLARE_HANDLE(CLzmaEncHandle)
+
+CLzmaEncHandle LzmaEnc_Create(ISzAllocPtr alloc);
+void LzmaEnc_Destroy(CLzmaEncHandle p, ISzAllocPtr alloc, ISzAllocPtr allocBig);
+
+SRes LzmaEnc_SetProps(CLzmaEncHandle p, const CLzmaEncProps *props);
+void LzmaEnc_SetDataSize(CLzmaEncHandle p, UInt64 expectedDataSiize);
+SRes LzmaEnc_WriteProperties(CLzmaEncHandle p, Byte *properties, SizeT *size);
+unsigned LzmaEnc_IsWriteEndMark(CLzmaEncHandle p);
+
+SRes LzmaEnc_Encode(CLzmaEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream,
+ ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig);
+SRes LzmaEnc_MemEncode(CLzmaEncHandle p, Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ int writeEndMark, ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig);
+
+
+/* ---------- One Call Interface ---------- */
+
+SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+ ICompressProgressPtr progress, ISzAllocPtr alloc, ISzAllocPtr allocBig);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/LzmaLib.c b/C/LzmaLib.c
index c10cf1a..785e884 100644
--- a/C/LzmaLib.c
+++ b/C/LzmaLib.c
@@ -1,40 +1,42 @@
-/* LzmaLib.c -- LZMA library wrapper
-2015-06-13 : Igor Pavlov : Public domain */
-
-#include "Alloc.h"
-#include "LzmaDec.h"
-#include "LzmaEnc.h"
-#include "LzmaLib.h"
-
-MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen,
- unsigned char *outProps, size_t *outPropsSize,
- int level, /* 0 <= level <= 9, default = 5 */
- unsigned dictSize, /* use (1 << N) or (3 << N). 4 KB < dictSize <= 128 MB */
- int lc, /* 0 <= lc <= 8, default = 3 */
- int lp, /* 0 <= lp <= 4, default = 0 */
- int pb, /* 0 <= pb <= 4, default = 2 */
- int fb, /* 5 <= fb <= 273, default = 32 */
- int numThreads /* 1 or 2, default = 2 */
-)
-{
- CLzmaEncProps props;
- LzmaEncProps_Init(&props);
- props.level = level;
- props.dictSize = dictSize;
- props.lc = lc;
- props.lp = lp;
- props.pb = pb;
- props.fb = fb;
- props.numThreads = numThreads;
-
- return LzmaEncode(dest, destLen, src, srcLen, &props, outProps, outPropsSize, 0,
- NULL, &g_Alloc, &g_Alloc);
-}
-
-
-MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen,
- const unsigned char *props, size_t propsSize)
-{
- ELzmaStatus status;
- return LzmaDecode(dest, destLen, src, srcLen, props, (unsigned)propsSize, LZMA_FINISH_ANY, &status, &g_Alloc);
-}
+/* LzmaLib.c -- LZMA library wrapper
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Alloc.h"
+#include "LzmaDec.h"
+#include "LzmaEnc.h"
+#include "LzmaLib.h"
+
+Z7_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen,
+ unsigned char *outProps, size_t *outPropsSize,
+ int level, /* 0 <= level <= 9, default = 5 */
+ unsigned dictSize, /* use (1 << N) or (3 << N). 4 KB < dictSize <= 128 MB */
+ int lc, /* 0 <= lc <= 8, default = 3 */
+ int lp, /* 0 <= lp <= 4, default = 0 */
+ int pb, /* 0 <= pb <= 4, default = 2 */
+ int fb, /* 5 <= fb <= 273, default = 32 */
+ int numThreads /* 1 or 2, default = 2 */
+)
+{
+ CLzmaEncProps props;
+ LzmaEncProps_Init(&props);
+ props.level = level;
+ props.dictSize = dictSize;
+ props.lc = lc;
+ props.lp = lp;
+ props.pb = pb;
+ props.fb = fb;
+ props.numThreads = numThreads;
+
+ return LzmaEncode(dest, destLen, src, srcLen, &props, outProps, outPropsSize, 0,
+ NULL, &g_Alloc, &g_Alloc);
+}
+
+
+Z7_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t *srcLen,
+ const unsigned char *props, size_t propsSize)
+{
+ ELzmaStatus status;
+ return LzmaDecode(dest, destLen, src, srcLen, props, (unsigned)propsSize, LZMA_FINISH_ANY, &status, &g_Alloc);
+}
diff --git a/C/LzmaLib.h b/C/LzmaLib.h
index 5c35e53..d7c0724 100644
--- a/C/LzmaLib.h
+++ b/C/LzmaLib.h
@@ -1,131 +1,138 @@
-/* LzmaLib.h -- LZMA library interface
-2013-01-18 : Igor Pavlov : Public domain */
-
-#ifndef __LZMA_LIB_H
-#define __LZMA_LIB_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-#define MY_STDAPI int MY_STD_CALL
-
-#define LZMA_PROPS_SIZE 5
-
-/*
-RAM requirements for LZMA:
- for compression: (dictSize * 11.5 + 6 MB) + state_size
- for decompression: dictSize + state_size
- state_size = (4 + (1.5 << (lc + lp))) KB
- by default (lc=3, lp=0), state_size = 16 KB.
-
-LZMA properties (5 bytes) format
- Offset Size Description
- 0 1 lc, lp and pb in encoded form.
- 1 4 dictSize (little endian).
-*/
-
-/*
-LzmaCompress
-------------
-
-outPropsSize -
- In: the pointer to the size of outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5.
- Out: the pointer to the size of written properties in outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5.
-
- LZMA Encoder will use defult values for any parameter, if it is
- -1 for any from: level, loc, lp, pb, fb, numThreads
- 0 for dictSize
-
-level - compression level: 0 <= level <= 9;
-
- level dictSize algo fb
- 0: 16 KB 0 32
- 1: 64 KB 0 32
- 2: 256 KB 0 32
- 3: 1 MB 0 32
- 4: 4 MB 0 32
- 5: 16 MB 1 32
- 6: 32 MB 1 32
- 7+: 64 MB 1 64
-
- The default value for "level" is 5.
-
- algo = 0 means fast method
- algo = 1 means normal method
-
-dictSize - The dictionary size in bytes. The maximum value is
- 128 MB = (1 << 27) bytes for 32-bit version
- 1 GB = (1 << 30) bytes for 64-bit version
- The default value is 16 MB = (1 << 24) bytes.
- It's recommended to use the dictionary that is larger than 4 KB and
- that can be calculated as (1 << N) or (3 << N) sizes.
-
-lc - The number of literal context bits (high bits of previous literal).
- It can be in the range from 0 to 8. The default value is 3.
- Sometimes lc=4 gives the gain for big files.
-
-lp - The number of literal pos bits (low bits of current position for literals).
- It can be in the range from 0 to 4. The default value is 0.
- The lp switch is intended for periodical data when the period is equal to 2^lp.
- For example, for 32-bit (4 bytes) periodical data you can use lp=2. Often it's
- better to set lc=0, if you change lp switch.
-
-pb - The number of pos bits (low bits of current position).
- It can be in the range from 0 to 4. The default value is 2.
- The pb switch is intended for periodical data when the period is equal 2^pb.
-
-fb - Word size (the number of fast bytes).
- It can be in the range from 5 to 273. The default value is 32.
- Usually, a big number gives a little bit better compression ratio and
- slower compression process.
-
-numThreads - The number of thereads. 1 or 2. The default value is 2.
- Fast mode (algo = 0) can use only 1 thread.
-
-Out:
- destLen - processed output size
-Returns:
- SZ_OK - OK
- SZ_ERROR_MEM - Memory allocation error
- SZ_ERROR_PARAM - Incorrect paramater
- SZ_ERROR_OUTPUT_EOF - output buffer overflow
- SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
-*/
-
-MY_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen,
- unsigned char *outProps, size_t *outPropsSize, /* *outPropsSize must be = 5 */
- int level, /* 0 <= level <= 9, default = 5 */
- unsigned dictSize, /* default = (1 << 24) */
- int lc, /* 0 <= lc <= 8, default = 3 */
- int lp, /* 0 <= lp <= 4, default = 0 */
- int pb, /* 0 <= pb <= 4, default = 2 */
- int fb, /* 5 <= fb <= 273, default = 32 */
- int numThreads /* 1 or 2, default = 2 */
- );
-
-/*
-LzmaUncompress
---------------
-In:
- dest - output data
- destLen - output data size
- src - input data
- srcLen - input data size
-Out:
- destLen - processed output size
- srcLen - processed input size
-Returns:
- SZ_OK - OK
- SZ_ERROR_DATA - Data error
- SZ_ERROR_MEM - Memory allocation arror
- SZ_ERROR_UNSUPPORTED - Unsupported properties
- SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer (src)
-*/
-
-MY_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, SizeT *srcLen,
- const unsigned char *props, size_t propsSize);
-
-EXTERN_C_END
-
-#endif
+/* LzmaLib.h -- LZMA library interface
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_LZMA_LIB_H
+#define ZIP7_INC_LZMA_LIB_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define Z7_STDAPI int Z7_STDCALL
+
+#define LZMA_PROPS_SIZE 5
+
+/*
+RAM requirements for LZMA:
+ for compression: (dictSize * 11.5 + 6 MB) + state_size
+ for decompression: dictSize + state_size
+ state_size = (4 + (1.5 << (lc + lp))) KB
+ by default (lc=3, lp=0), state_size = 16 KB.
+
+LZMA properties (5 bytes) format
+ Offset Size Description
+ 0 1 lc, lp and pb in encoded form.
+ 1 4 dictSize (little endian).
+*/
+
+/*
+LzmaCompress
+------------
+
+outPropsSize -
+ In: the pointer to the size of outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5.
+ Out: the pointer to the size of written properties in outProps buffer; *outPropsSize = LZMA_PROPS_SIZE = 5.
+
+ LZMA Encoder will use defult values for any parameter, if it is
+ -1 for any from: level, loc, lp, pb, fb, numThreads
+ 0 for dictSize
+
+level - compression level: 0 <= level <= 9;
+
+ level dictSize algo fb
+ 0: 64 KB 0 32
+ 1: 256 KB 0 32
+ 2: 1 MB 0 32
+ 3: 4 MB 0 32
+ 4: 16 MB 0 32
+ 5: 16 MB 1 32
+ 6: 32 MB 1 32
+ 7: 32 MB 1 64
+ 8: 64 MB 1 64
+ 9: 64 MB 1 64
+
+ The default value for "level" is 5.
+
+ algo = 0 means fast method
+ algo = 1 means normal method
+
+dictSize - The dictionary size in bytes. The maximum value is
+ 128 MB = (1 << 27) bytes for 32-bit version
+ 1 GB = (1 << 30) bytes for 64-bit version
+ The default value is 16 MB = (1 << 24) bytes.
+ It's recommended to use the dictionary that is larger than 4 KB and
+ that can be calculated as (1 << N) or (3 << N) sizes.
+
+lc - The number of literal context bits (high bits of previous literal).
+ It can be in the range from 0 to 8. The default value is 3.
+ Sometimes lc=4 gives the gain for big files.
+
+lp - The number of literal pos bits (low bits of current position for literals).
+ It can be in the range from 0 to 4. The default value is 0.
+ The lp switch is intended for periodical data when the period is equal to 2^lp.
+ For example, for 32-bit (4 bytes) periodical data you can use lp=2. Often it's
+ better to set lc=0, if you change lp switch.
+
+pb - The number of pos bits (low bits of current position).
+ It can be in the range from 0 to 4. The default value is 2.
+ The pb switch is intended for periodical data when the period is equal 2^pb.
+
+fb - Word size (the number of fast bytes).
+ It can be in the range from 5 to 273. The default value is 32.
+ Usually, a big number gives a little bit better compression ratio and
+ slower compression process.
+
+numThreads - The number of thereads. 1 or 2. The default value is 2.
+ Fast mode (algo = 0) can use only 1 thread.
+
+In:
+ dest - output data buffer
+ destLen - output data buffer size
+ src - input data
+ srcLen - input data size
+Out:
+ destLen - processed output size
+Returns:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+*/
+
+Z7_STDAPI LzmaCompress(unsigned char *dest, size_t *destLen, const unsigned char *src, size_t srcLen,
+ unsigned char *outProps, size_t *outPropsSize, /* *outPropsSize must be = 5 */
+ int level, /* 0 <= level <= 9, default = 5 */
+ unsigned dictSize, /* default = (1 << 24) */
+ int lc, /* 0 <= lc <= 8, default = 3 */
+ int lp, /* 0 <= lp <= 4, default = 0 */
+ int pb, /* 0 <= pb <= 4, default = 2 */
+ int fb, /* 5 <= fb <= 273, default = 32 */
+ int numThreads /* 1 or 2, default = 2 */
+ );
+
+/*
+LzmaUncompress
+--------------
+In:
+ dest - output data buffer
+ destLen - output data buffer size
+ src - input data
+ srcLen - input data size
+Out:
+ destLen - processed output size
+ srcLen - processed input size
+Returns:
+ SZ_OK - OK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation arror
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - it needs more bytes in input buffer (src)
+*/
+
+Z7_STDAPI LzmaUncompress(unsigned char *dest, size_t *destLen, const unsigned char *src, SizeT *srcLen,
+ const unsigned char *props, size_t propsSize);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/MtCoder.c b/C/MtCoder.c
index 5667f2d..6f58abb 100644
--- a/C/MtCoder.c
+++ b/C/MtCoder.c
@@ -1,601 +1,571 @@
-/* MtCoder.c -- Multi-thread Coder
-2018-07-04 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "MtCoder.h"
-
-#ifndef _7ZIP_ST
-
-SRes MtProgressThunk_Progress(const ICompressProgress *pp, UInt64 inSize, UInt64 outSize)
-{
- CMtProgressThunk *thunk = CONTAINER_FROM_VTBL(pp, CMtProgressThunk, vt);
- UInt64 inSize2 = 0;
- UInt64 outSize2 = 0;
- if (inSize != (UInt64)(Int64)-1)
- {
- inSize2 = inSize - thunk->inSize;
- thunk->inSize = inSize;
- }
- if (outSize != (UInt64)(Int64)-1)
- {
- outSize2 = outSize - thunk->outSize;
- thunk->outSize = outSize;
- }
- return MtProgress_ProgressAdd(thunk->mtProgress, inSize2, outSize2);
-}
-
-
-void MtProgressThunk_CreateVTable(CMtProgressThunk *p)
-{
- p->vt.Progress = MtProgressThunk_Progress;
-}
-
-
-
-#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; }
-
-
-static WRes ArEvent_OptCreate_And_Reset(CEvent *p)
-{
- if (Event_IsCreated(p))
- return Event_Reset(p);
- return AutoResetEvent_CreateNotSignaled(p);
-}
-
-
-static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp);
-
-
-static SRes MtCoderThread_CreateAndStart(CMtCoderThread *t)
-{
- WRes wres = ArEvent_OptCreate_And_Reset(&t->startEvent);
- if (wres == 0)
- {
- t->stop = False;
- if (!Thread_WasCreated(&t->thread))
- wres = Thread_Create(&t->thread, ThreadFunc, t);
- if (wres == 0)
- wres = Event_Set(&t->startEvent);
- }
- if (wres == 0)
- return SZ_OK;
- return MY_SRes_HRESULT_FROM_WRes(wres);
-}
-
-
-static void MtCoderThread_Destruct(CMtCoderThread *t)
-{
- if (Thread_WasCreated(&t->thread))
- {
- t->stop = 1;
- Event_Set(&t->startEvent);
- Thread_Wait(&t->thread);
- Thread_Close(&t->thread);
- }
-
- Event_Close(&t->startEvent);
-
- if (t->inBuf)
- {
- ISzAlloc_Free(t->mtCoder->allocBig, t->inBuf);
- t->inBuf = NULL;
- }
-}
-
-
-
-static SRes FullRead(ISeqInStream *stream, Byte *data, size_t *processedSize)
-{
- size_t size = *processedSize;
- *processedSize = 0;
- while (size != 0)
- {
- size_t cur = size;
- SRes res = ISeqInStream_Read(stream, data, &cur);
- *processedSize += cur;
- data += cur;
- size -= cur;
- RINOK(res);
- if (cur == 0)
- return SZ_OK;
- }
- return SZ_OK;
-}
-
-
-/*
- ThreadFunc2() returns:
- SZ_OK - in all normal cases (even for stream error or memory allocation error)
- SZ_ERROR_THREAD - in case of failure in system synch function
-*/
-
-static SRes ThreadFunc2(CMtCoderThread *t)
-{
- CMtCoder *mtc = t->mtCoder;
-
- for (;;)
- {
- unsigned bi;
- SRes res;
- SRes res2;
- BoolInt finished;
- unsigned bufIndex;
- size_t size;
- const Byte *inData;
- UInt64 readProcessed = 0;
-
- RINOK_THREAD(Event_Wait(&mtc->readEvent))
-
- /* after Event_Wait(&mtc->readEvent) we must call Event_Set(&mtc->readEvent) in any case to unlock another threads */
-
- if (mtc->stopReading)
- {
- return Event_Set(&mtc->readEvent) == 0 ? SZ_OK : SZ_ERROR_THREAD;
- }
-
- res = MtProgress_GetError(&mtc->mtProgress);
-
- size = 0;
- inData = NULL;
- finished = True;
-
- if (res == SZ_OK)
- {
- size = mtc->blockSize;
- if (mtc->inStream)
- {
- if (!t->inBuf)
- {
- t->inBuf = (Byte *)ISzAlloc_Alloc(mtc->allocBig, mtc->blockSize);
- if (!t->inBuf)
- res = SZ_ERROR_MEM;
- }
- if (res == SZ_OK)
- {
- res = FullRead(mtc->inStream, t->inBuf, &size);
- readProcessed = mtc->readProcessed + size;
- mtc->readProcessed = readProcessed;
- }
- if (res != SZ_OK)
- {
- mtc->readRes = res;
- /* after reading error - we can stop encoding of previous blocks */
- MtProgress_SetError(&mtc->mtProgress, res);
- }
- else
- finished = (size != mtc->blockSize);
- }
- else
- {
- size_t rem;
- readProcessed = mtc->readProcessed;
- rem = mtc->inDataSize - (size_t)readProcessed;
- if (size > rem)
- size = rem;
- inData = mtc->inData + (size_t)readProcessed;
- readProcessed += size;
- mtc->readProcessed = readProcessed;
- finished = (mtc->inDataSize == (size_t)readProcessed);
- }
- }
-
- /* we must get some block from blocksSemaphore before Event_Set(&mtc->readEvent) */
-
- res2 = SZ_OK;
-
- if (Semaphore_Wait(&mtc->blocksSemaphore) != 0)
- {
- res2 = SZ_ERROR_THREAD;
- if (res == SZ_OK)
- {
- res = res2;
- // MtProgress_SetError(&mtc->mtProgress, res);
- }
- }
-
- bi = mtc->blockIndex;
-
- if (++mtc->blockIndex >= mtc->numBlocksMax)
- mtc->blockIndex = 0;
-
- bufIndex = (unsigned)(int)-1;
-
- if (res == SZ_OK)
- res = MtProgress_GetError(&mtc->mtProgress);
-
- if (res != SZ_OK)
- finished = True;
-
- if (!finished)
- {
- if (mtc->numStartedThreads < mtc->numStartedThreadsLimit
- && mtc->expectedDataSize != readProcessed)
- {
- res = MtCoderThread_CreateAndStart(&mtc->threads[mtc->numStartedThreads]);
- if (res == SZ_OK)
- mtc->numStartedThreads++;
- else
- {
- MtProgress_SetError(&mtc->mtProgress, res);
- finished = True;
- }
- }
- }
-
- if (finished)
- mtc->stopReading = True;
-
- RINOK_THREAD(Event_Set(&mtc->readEvent))
-
- if (res2 != SZ_OK)
- return res2;
-
- if (res == SZ_OK)
- {
- CriticalSection_Enter(&mtc->cs);
- bufIndex = mtc->freeBlockHead;
- mtc->freeBlockHead = mtc->freeBlockList[bufIndex];
- CriticalSection_Leave(&mtc->cs);
-
- res = mtc->mtCallback->Code(mtc->mtCallbackObject, t->index, bufIndex,
- mtc->inStream ? t->inBuf : inData, size, finished);
-
- // MtProgress_Reinit(&mtc->mtProgress, t->index);
-
- if (res != SZ_OK)
- MtProgress_SetError(&mtc->mtProgress, res);
- }
-
- {
- CMtCoderBlock *block = &mtc->blocks[bi];
- block->res = res;
- block->bufIndex = bufIndex;
- block->finished = finished;
- }
-
- #ifdef MTCODER__USE_WRITE_THREAD
- RINOK_THREAD(Event_Set(&mtc->writeEvents[bi]))
- #else
- {
- unsigned wi;
- {
- CriticalSection_Enter(&mtc->cs);
- wi = mtc->writeIndex;
- if (wi == bi)
- mtc->writeIndex = (unsigned)(int)-1;
- else
- mtc->ReadyBlocks[bi] = True;
- CriticalSection_Leave(&mtc->cs);
- }
-
- if (wi != bi)
- {
- if (res != SZ_OK || finished)
- return 0;
- continue;
- }
-
- if (mtc->writeRes != SZ_OK)
- res = mtc->writeRes;
-
- for (;;)
- {
- if (res == SZ_OK && bufIndex != (unsigned)(int)-1)
- {
- res = mtc->mtCallback->Write(mtc->mtCallbackObject, bufIndex);
- if (res != SZ_OK)
- {
- mtc->writeRes = res;
- MtProgress_SetError(&mtc->mtProgress, res);
- }
- }
-
- if (++wi >= mtc->numBlocksMax)
- wi = 0;
- {
- BoolInt isReady;
-
- CriticalSection_Enter(&mtc->cs);
-
- if (bufIndex != (unsigned)(int)-1)
- {
- mtc->freeBlockList[bufIndex] = mtc->freeBlockHead;
- mtc->freeBlockHead = bufIndex;
- }
-
- isReady = mtc->ReadyBlocks[wi];
-
- if (isReady)
- mtc->ReadyBlocks[wi] = False;
- else
- mtc->writeIndex = wi;
-
- CriticalSection_Leave(&mtc->cs);
-
- RINOK_THREAD(Semaphore_Release1(&mtc->blocksSemaphore))
-
- if (!isReady)
- break;
- }
-
- {
- CMtCoderBlock *block = &mtc->blocks[wi];
- if (res == SZ_OK && block->res != SZ_OK)
- res = block->res;
- bufIndex = block->bufIndex;
- finished = block->finished;
- }
- }
- }
- #endif
-
- if (finished || res != SZ_OK)
- return 0;
- }
-}
-
-
-static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp)
-{
- CMtCoderThread *t = (CMtCoderThread *)pp;
- for (;;)
- {
- if (Event_Wait(&t->startEvent) != 0)
- return SZ_ERROR_THREAD;
- if (t->stop)
- return 0;
- {
- SRes res = ThreadFunc2(t);
- CMtCoder *mtc = t->mtCoder;
- if (res != SZ_OK)
- {
- MtProgress_SetError(&mtc->mtProgress, res);
- }
-
- #ifndef MTCODER__USE_WRITE_THREAD
- {
- unsigned numFinished = (unsigned)InterlockedIncrement(&mtc->numFinishedThreads);
- if (numFinished == mtc->numStartedThreads)
- if (Event_Set(&mtc->finishedEvent) != 0)
- return SZ_ERROR_THREAD;
- }
- #endif
- }
- }
-}
-
-
-
-void MtCoder_Construct(CMtCoder *p)
-{
- unsigned i;
-
- p->blockSize = 0;
- p->numThreadsMax = 0;
- p->expectedDataSize = (UInt64)(Int64)-1;
-
- p->inStream = NULL;
- p->inData = NULL;
- p->inDataSize = 0;
-
- p->progress = NULL;
- p->allocBig = NULL;
-
- p->mtCallback = NULL;
- p->mtCallbackObject = NULL;
-
- p->allocatedBufsSize = 0;
-
- Event_Construct(&p->readEvent);
- Semaphore_Construct(&p->blocksSemaphore);
-
- for (i = 0; i < MTCODER__THREADS_MAX; i++)
- {
- CMtCoderThread *t = &p->threads[i];
- t->mtCoder = p;
- t->index = i;
- t->inBuf = NULL;
- t->stop = False;
- Event_Construct(&t->startEvent);
- Thread_Construct(&t->thread);
- }
-
- #ifdef MTCODER__USE_WRITE_THREAD
- for (i = 0; i < MTCODER__BLOCKS_MAX; i++)
- Event_Construct(&p->writeEvents[i]);
- #else
- Event_Construct(&p->finishedEvent);
- #endif
-
- CriticalSection_Init(&p->cs);
- CriticalSection_Init(&p->mtProgress.cs);
-}
-
-
-
-
-static void MtCoder_Free(CMtCoder *p)
-{
- unsigned i;
-
- /*
- p->stopReading = True;
- if (Event_IsCreated(&p->readEvent))
- Event_Set(&p->readEvent);
- */
-
- for (i = 0; i < MTCODER__THREADS_MAX; i++)
- MtCoderThread_Destruct(&p->threads[i]);
-
- Event_Close(&p->readEvent);
- Semaphore_Close(&p->blocksSemaphore);
-
- #ifdef MTCODER__USE_WRITE_THREAD
- for (i = 0; i < MTCODER__BLOCKS_MAX; i++)
- Event_Close(&p->writeEvents[i]);
- #else
- Event_Close(&p->finishedEvent);
- #endif
-}
-
-
-void MtCoder_Destruct(CMtCoder *p)
-{
- MtCoder_Free(p);
-
- CriticalSection_Delete(&p->cs);
- CriticalSection_Delete(&p->mtProgress.cs);
-}
-
-
-SRes MtCoder_Code(CMtCoder *p)
-{
- unsigned numThreads = p->numThreadsMax;
- unsigned numBlocksMax;
- unsigned i;
- SRes res = SZ_OK;
-
- if (numThreads > MTCODER__THREADS_MAX)
- numThreads = MTCODER__THREADS_MAX;
- numBlocksMax = MTCODER__GET_NUM_BLOCKS_FROM_THREADS(numThreads);
-
- if (p->blockSize < ((UInt32)1 << 26)) numBlocksMax++;
- if (p->blockSize < ((UInt32)1 << 24)) numBlocksMax++;
- if (p->blockSize < ((UInt32)1 << 22)) numBlocksMax++;
-
- if (numBlocksMax > MTCODER__BLOCKS_MAX)
- numBlocksMax = MTCODER__BLOCKS_MAX;
-
- if (p->blockSize != p->allocatedBufsSize)
- {
- for (i = 0; i < MTCODER__THREADS_MAX; i++)
- {
- CMtCoderThread *t = &p->threads[i];
- if (t->inBuf)
- {
- ISzAlloc_Free(p->allocBig, t->inBuf);
- t->inBuf = NULL;
- }
- }
- p->allocatedBufsSize = p->blockSize;
- }
-
- p->readRes = SZ_OK;
-
- MtProgress_Init(&p->mtProgress, p->progress);
-
- #ifdef MTCODER__USE_WRITE_THREAD
- for (i = 0; i < numBlocksMax; i++)
- {
- RINOK_THREAD(ArEvent_OptCreate_And_Reset(&p->writeEvents[i]));
- }
- #else
- RINOK_THREAD(ArEvent_OptCreate_And_Reset(&p->finishedEvent));
- #endif
-
- {
- RINOK_THREAD(ArEvent_OptCreate_And_Reset(&p->readEvent));
-
- if (Semaphore_IsCreated(&p->blocksSemaphore))
- {
- RINOK_THREAD(Semaphore_Close(&p->blocksSemaphore));
- }
- RINOK_THREAD(Semaphore_Create(&p->blocksSemaphore, numBlocksMax, numBlocksMax));
- }
-
- for (i = 0; i < MTCODER__BLOCKS_MAX - 1; i++)
- p->freeBlockList[i] = i + 1;
- p->freeBlockList[MTCODER__BLOCKS_MAX - 1] = (unsigned)(int)-1;
- p->freeBlockHead = 0;
-
- p->readProcessed = 0;
- p->blockIndex = 0;
- p->numBlocksMax = numBlocksMax;
- p->stopReading = False;
-
- #ifndef MTCODER__USE_WRITE_THREAD
- p->writeIndex = 0;
- p->writeRes = SZ_OK;
- for (i = 0; i < MTCODER__BLOCKS_MAX; i++)
- p->ReadyBlocks[i] = False;
- p->numFinishedThreads = 0;
- #endif
-
- p->numStartedThreadsLimit = numThreads;
- p->numStartedThreads = 0;
-
- // for (i = 0; i < numThreads; i++)
- {
- CMtCoderThread *nextThread = &p->threads[p->numStartedThreads++];
- RINOK(MtCoderThread_CreateAndStart(nextThread));
- }
-
- RINOK_THREAD(Event_Set(&p->readEvent))
-
- #ifdef MTCODER__USE_WRITE_THREAD
- {
- unsigned bi = 0;
-
- for (;; bi++)
- {
- if (bi >= numBlocksMax)
- bi = 0;
-
- RINOK_THREAD(Event_Wait(&p->writeEvents[bi]))
-
- {
- const CMtCoderBlock *block = &p->blocks[bi];
- unsigned bufIndex = block->bufIndex;
- BoolInt finished = block->finished;
- if (res == SZ_OK && block->res != SZ_OK)
- res = block->res;
-
- if (bufIndex != (unsigned)(int)-1)
- {
- if (res == SZ_OK)
- {
- res = p->mtCallback->Write(p->mtCallbackObject, bufIndex);
- if (res != SZ_OK)
- MtProgress_SetError(&p->mtProgress, res);
- }
-
- CriticalSection_Enter(&p->cs);
- {
- p->freeBlockList[bufIndex] = p->freeBlockHead;
- p->freeBlockHead = bufIndex;
- }
- CriticalSection_Leave(&p->cs);
- }
-
- RINOK_THREAD(Semaphore_Release1(&p->blocksSemaphore))
-
- if (finished)
- break;
- }
- }
- }
- #else
- {
- WRes wres = Event_Wait(&p->finishedEvent);
- res = MY_SRes_HRESULT_FROM_WRes(wres);
- }
- #endif
-
- if (res == SZ_OK)
- res = p->readRes;
-
- if (res == SZ_OK)
- res = p->mtProgress.res;
-
- #ifndef MTCODER__USE_WRITE_THREAD
- if (res == SZ_OK)
- res = p->writeRes;
- #endif
-
- if (res != SZ_OK)
- MtCoder_Free(p);
- return res;
-}
-
-#endif
+/* MtCoder.c -- Multi-thread Coder
+2023-04-13 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "MtCoder.h"
+
+#ifndef Z7_ST
+
+static SRes MtProgressThunk_Progress(ICompressProgressPtr pp, UInt64 inSize, UInt64 outSize)
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CMtProgressThunk)
+ UInt64 inSize2 = 0;
+ UInt64 outSize2 = 0;
+ if (inSize != (UInt64)(Int64)-1)
+ {
+ inSize2 = inSize - p->inSize;
+ p->inSize = inSize;
+ }
+ if (outSize != (UInt64)(Int64)-1)
+ {
+ outSize2 = outSize - p->outSize;
+ p->outSize = outSize;
+ }
+ return MtProgress_ProgressAdd(p->mtProgress, inSize2, outSize2);
+}
+
+
+void MtProgressThunk_CreateVTable(CMtProgressThunk *p)
+{
+ p->vt.Progress = MtProgressThunk_Progress;
+}
+
+
+
+#define RINOK_THREAD(x) { if ((x) != 0) return SZ_ERROR_THREAD; }
+
+
+static THREAD_FUNC_DECL ThreadFunc(void *pp);
+
+
+static SRes MtCoderThread_CreateAndStart(CMtCoderThread *t)
+{
+ WRes wres = AutoResetEvent_OptCreate_And_Reset(&t->startEvent);
+ if (wres == 0)
+ {
+ t->stop = False;
+ if (!Thread_WasCreated(&t->thread))
+ wres = Thread_Create(&t->thread, ThreadFunc, t);
+ if (wres == 0)
+ wres = Event_Set(&t->startEvent);
+ }
+ if (wres == 0)
+ return SZ_OK;
+ return MY_SRes_HRESULT_FROM_WRes(wres);
+}
+
+
+static void MtCoderThread_Destruct(CMtCoderThread *t)
+{
+ if (Thread_WasCreated(&t->thread))
+ {
+ t->stop = 1;
+ Event_Set(&t->startEvent);
+ Thread_Wait_Close(&t->thread);
+ }
+
+ Event_Close(&t->startEvent);
+
+ if (t->inBuf)
+ {
+ ISzAlloc_Free(t->mtCoder->allocBig, t->inBuf);
+ t->inBuf = NULL;
+ }
+}
+
+
+
+
+/*
+ ThreadFunc2() returns:
+ SZ_OK - in all normal cases (even for stream error or memory allocation error)
+ SZ_ERROR_THREAD - in case of failure in system synch function
+*/
+
+static SRes ThreadFunc2(CMtCoderThread *t)
+{
+ CMtCoder *mtc = t->mtCoder;
+
+ for (;;)
+ {
+ unsigned bi;
+ SRes res;
+ SRes res2;
+ BoolInt finished;
+ unsigned bufIndex;
+ size_t size;
+ const Byte *inData;
+ UInt64 readProcessed = 0;
+
+ RINOK_THREAD(Event_Wait(&mtc->readEvent))
+
+ /* after Event_Wait(&mtc->readEvent) we must call Event_Set(&mtc->readEvent) in any case to unlock another threads */
+
+ if (mtc->stopReading)
+ {
+ return Event_Set(&mtc->readEvent) == 0 ? SZ_OK : SZ_ERROR_THREAD;
+ }
+
+ res = MtProgress_GetError(&mtc->mtProgress);
+
+ size = 0;
+ inData = NULL;
+ finished = True;
+
+ if (res == SZ_OK)
+ {
+ size = mtc->blockSize;
+ if (mtc->inStream)
+ {
+ if (!t->inBuf)
+ {
+ t->inBuf = (Byte *)ISzAlloc_Alloc(mtc->allocBig, mtc->blockSize);
+ if (!t->inBuf)
+ res = SZ_ERROR_MEM;
+ }
+ if (res == SZ_OK)
+ {
+ res = SeqInStream_ReadMax(mtc->inStream, t->inBuf, &size);
+ readProcessed = mtc->readProcessed + size;
+ mtc->readProcessed = readProcessed;
+ }
+ if (res != SZ_OK)
+ {
+ mtc->readRes = res;
+ /* after reading error - we can stop encoding of previous blocks */
+ MtProgress_SetError(&mtc->mtProgress, res);
+ }
+ else
+ finished = (size != mtc->blockSize);
+ }
+ else
+ {
+ size_t rem;
+ readProcessed = mtc->readProcessed;
+ rem = mtc->inDataSize - (size_t)readProcessed;
+ if (size > rem)
+ size = rem;
+ inData = mtc->inData + (size_t)readProcessed;
+ readProcessed += size;
+ mtc->readProcessed = readProcessed;
+ finished = (mtc->inDataSize == (size_t)readProcessed);
+ }
+ }
+
+ /* we must get some block from blocksSemaphore before Event_Set(&mtc->readEvent) */
+
+ res2 = SZ_OK;
+
+ if (Semaphore_Wait(&mtc->blocksSemaphore) != 0)
+ {
+ res2 = SZ_ERROR_THREAD;
+ if (res == SZ_OK)
+ {
+ res = res2;
+ // MtProgress_SetError(&mtc->mtProgress, res);
+ }
+ }
+
+ bi = mtc->blockIndex;
+
+ if (++mtc->blockIndex >= mtc->numBlocksMax)
+ mtc->blockIndex = 0;
+
+ bufIndex = (unsigned)(int)-1;
+
+ if (res == SZ_OK)
+ res = MtProgress_GetError(&mtc->mtProgress);
+
+ if (res != SZ_OK)
+ finished = True;
+
+ if (!finished)
+ {
+ if (mtc->numStartedThreads < mtc->numStartedThreadsLimit
+ && mtc->expectedDataSize != readProcessed)
+ {
+ res = MtCoderThread_CreateAndStart(&mtc->threads[mtc->numStartedThreads]);
+ if (res == SZ_OK)
+ mtc->numStartedThreads++;
+ else
+ {
+ MtProgress_SetError(&mtc->mtProgress, res);
+ finished = True;
+ }
+ }
+ }
+
+ if (finished)
+ mtc->stopReading = True;
+
+ RINOK_THREAD(Event_Set(&mtc->readEvent))
+
+ if (res2 != SZ_OK)
+ return res2;
+
+ if (res == SZ_OK)
+ {
+ CriticalSection_Enter(&mtc->cs);
+ bufIndex = mtc->freeBlockHead;
+ mtc->freeBlockHead = mtc->freeBlockList[bufIndex];
+ CriticalSection_Leave(&mtc->cs);
+
+ res = mtc->mtCallback->Code(mtc->mtCallbackObject, t->index, bufIndex,
+ mtc->inStream ? t->inBuf : inData, size, finished);
+
+ // MtProgress_Reinit(&mtc->mtProgress, t->index);
+
+ if (res != SZ_OK)
+ MtProgress_SetError(&mtc->mtProgress, res);
+ }
+
+ {
+ CMtCoderBlock *block = &mtc->blocks[bi];
+ block->res = res;
+ block->bufIndex = bufIndex;
+ block->finished = finished;
+ }
+
+ #ifdef MTCODER_USE_WRITE_THREAD
+ RINOK_THREAD(Event_Set(&mtc->writeEvents[bi]))
+ #else
+ {
+ unsigned wi;
+ {
+ CriticalSection_Enter(&mtc->cs);
+ wi = mtc->writeIndex;
+ if (wi == bi)
+ mtc->writeIndex = (unsigned)(int)-1;
+ else
+ mtc->ReadyBlocks[bi] = True;
+ CriticalSection_Leave(&mtc->cs);
+ }
+
+ if (wi != bi)
+ {
+ if (res != SZ_OK || finished)
+ return 0;
+ continue;
+ }
+
+ if (mtc->writeRes != SZ_OK)
+ res = mtc->writeRes;
+
+ for (;;)
+ {
+ if (res == SZ_OK && bufIndex != (unsigned)(int)-1)
+ {
+ res = mtc->mtCallback->Write(mtc->mtCallbackObject, bufIndex);
+ if (res != SZ_OK)
+ {
+ mtc->writeRes = res;
+ MtProgress_SetError(&mtc->mtProgress, res);
+ }
+ }
+
+ if (++wi >= mtc->numBlocksMax)
+ wi = 0;
+ {
+ BoolInt isReady;
+
+ CriticalSection_Enter(&mtc->cs);
+
+ if (bufIndex != (unsigned)(int)-1)
+ {
+ mtc->freeBlockList[bufIndex] = mtc->freeBlockHead;
+ mtc->freeBlockHead = bufIndex;
+ }
+
+ isReady = mtc->ReadyBlocks[wi];
+
+ if (isReady)
+ mtc->ReadyBlocks[wi] = False;
+ else
+ mtc->writeIndex = wi;
+
+ CriticalSection_Leave(&mtc->cs);
+
+ RINOK_THREAD(Semaphore_Release1(&mtc->blocksSemaphore))
+
+ if (!isReady)
+ break;
+ }
+
+ {
+ CMtCoderBlock *block = &mtc->blocks[wi];
+ if (res == SZ_OK && block->res != SZ_OK)
+ res = block->res;
+ bufIndex = block->bufIndex;
+ finished = block->finished;
+ }
+ }
+ }
+ #endif
+
+ if (finished || res != SZ_OK)
+ return 0;
+ }
+}
+
+
+static THREAD_FUNC_DECL ThreadFunc(void *pp)
+{
+ CMtCoderThread *t = (CMtCoderThread *)pp;
+ for (;;)
+ {
+ if (Event_Wait(&t->startEvent) != 0)
+ return (THREAD_FUNC_RET_TYPE)SZ_ERROR_THREAD;
+ if (t->stop)
+ return 0;
+ {
+ SRes res = ThreadFunc2(t);
+ CMtCoder *mtc = t->mtCoder;
+ if (res != SZ_OK)
+ {
+ MtProgress_SetError(&mtc->mtProgress, res);
+ }
+
+ #ifndef MTCODER_USE_WRITE_THREAD
+ {
+ unsigned numFinished = (unsigned)InterlockedIncrement(&mtc->numFinishedThreads);
+ if (numFinished == mtc->numStartedThreads)
+ if (Event_Set(&mtc->finishedEvent) != 0)
+ return (THREAD_FUNC_RET_TYPE)SZ_ERROR_THREAD;
+ }
+ #endif
+ }
+ }
+}
+
+
+
+void MtCoder_Construct(CMtCoder *p)
+{
+ unsigned i;
+
+ p->blockSize = 0;
+ p->numThreadsMax = 0;
+ p->expectedDataSize = (UInt64)(Int64)-1;
+
+ p->inStream = NULL;
+ p->inData = NULL;
+ p->inDataSize = 0;
+
+ p->progress = NULL;
+ p->allocBig = NULL;
+
+ p->mtCallback = NULL;
+ p->mtCallbackObject = NULL;
+
+ p->allocatedBufsSize = 0;
+
+ Event_Construct(&p->readEvent);
+ Semaphore_Construct(&p->blocksSemaphore);
+
+ for (i = 0; i < MTCODER_THREADS_MAX; i++)
+ {
+ CMtCoderThread *t = &p->threads[i];
+ t->mtCoder = p;
+ t->index = i;
+ t->inBuf = NULL;
+ t->stop = False;
+ Event_Construct(&t->startEvent);
+ Thread_CONSTRUCT(&t->thread)
+ }
+
+ #ifdef MTCODER_USE_WRITE_THREAD
+ for (i = 0; i < MTCODER_BLOCKS_MAX; i++)
+ Event_Construct(&p->writeEvents[i]);
+ #else
+ Event_Construct(&p->finishedEvent);
+ #endif
+
+ CriticalSection_Init(&p->cs);
+ CriticalSection_Init(&p->mtProgress.cs);
+}
+
+
+
+
+static void MtCoder_Free(CMtCoder *p)
+{
+ unsigned i;
+
+ /*
+ p->stopReading = True;
+ if (Event_IsCreated(&p->readEvent))
+ Event_Set(&p->readEvent);
+ */
+
+ for (i = 0; i < MTCODER_THREADS_MAX; i++)
+ MtCoderThread_Destruct(&p->threads[i]);
+
+ Event_Close(&p->readEvent);
+ Semaphore_Close(&p->blocksSemaphore);
+
+ #ifdef MTCODER_USE_WRITE_THREAD
+ for (i = 0; i < MTCODER_BLOCKS_MAX; i++)
+ Event_Close(&p->writeEvents[i]);
+ #else
+ Event_Close(&p->finishedEvent);
+ #endif
+}
+
+
+void MtCoder_Destruct(CMtCoder *p)
+{
+ MtCoder_Free(p);
+
+ CriticalSection_Delete(&p->cs);
+ CriticalSection_Delete(&p->mtProgress.cs);
+}
+
+
+SRes MtCoder_Code(CMtCoder *p)
+{
+ unsigned numThreads = p->numThreadsMax;
+ unsigned numBlocksMax;
+ unsigned i;
+ SRes res = SZ_OK;
+
+ if (numThreads > MTCODER_THREADS_MAX)
+ numThreads = MTCODER_THREADS_MAX;
+ numBlocksMax = MTCODER_GET_NUM_BLOCKS_FROM_THREADS(numThreads);
+
+ if (p->blockSize < ((UInt32)1 << 26)) numBlocksMax++;
+ if (p->blockSize < ((UInt32)1 << 24)) numBlocksMax++;
+ if (p->blockSize < ((UInt32)1 << 22)) numBlocksMax++;
+
+ if (numBlocksMax > MTCODER_BLOCKS_MAX)
+ numBlocksMax = MTCODER_BLOCKS_MAX;
+
+ if (p->blockSize != p->allocatedBufsSize)
+ {
+ for (i = 0; i < MTCODER_THREADS_MAX; i++)
+ {
+ CMtCoderThread *t = &p->threads[i];
+ if (t->inBuf)
+ {
+ ISzAlloc_Free(p->allocBig, t->inBuf);
+ t->inBuf = NULL;
+ }
+ }
+ p->allocatedBufsSize = p->blockSize;
+ }
+
+ p->readRes = SZ_OK;
+
+ MtProgress_Init(&p->mtProgress, p->progress);
+
+ #ifdef MTCODER_USE_WRITE_THREAD
+ for (i = 0; i < numBlocksMax; i++)
+ {
+ RINOK_THREAD(AutoResetEvent_OptCreate_And_Reset(&p->writeEvents[i]))
+ }
+ #else
+ RINOK_THREAD(AutoResetEvent_OptCreate_And_Reset(&p->finishedEvent))
+ #endif
+
+ {
+ RINOK_THREAD(AutoResetEvent_OptCreate_And_Reset(&p->readEvent))
+ RINOK_THREAD(Semaphore_OptCreateInit(&p->blocksSemaphore, numBlocksMax, numBlocksMax))
+ }
+
+ for (i = 0; i < MTCODER_BLOCKS_MAX - 1; i++)
+ p->freeBlockList[i] = i + 1;
+ p->freeBlockList[MTCODER_BLOCKS_MAX - 1] = (unsigned)(int)-1;
+ p->freeBlockHead = 0;
+
+ p->readProcessed = 0;
+ p->blockIndex = 0;
+ p->numBlocksMax = numBlocksMax;
+ p->stopReading = False;
+
+ #ifndef MTCODER_USE_WRITE_THREAD
+ p->writeIndex = 0;
+ p->writeRes = SZ_OK;
+ for (i = 0; i < MTCODER_BLOCKS_MAX; i++)
+ p->ReadyBlocks[i] = False;
+ p->numFinishedThreads = 0;
+ #endif
+
+ p->numStartedThreadsLimit = numThreads;
+ p->numStartedThreads = 0;
+
+ // for (i = 0; i < numThreads; i++)
+ {
+ CMtCoderThread *nextThread = &p->threads[p->numStartedThreads++];
+ RINOK(MtCoderThread_CreateAndStart(nextThread))
+ }
+
+ RINOK_THREAD(Event_Set(&p->readEvent))
+
+ #ifdef MTCODER_USE_WRITE_THREAD
+ {
+ unsigned bi = 0;
+
+ for (;; bi++)
+ {
+ if (bi >= numBlocksMax)
+ bi = 0;
+
+ RINOK_THREAD(Event_Wait(&p->writeEvents[bi]))
+
+ {
+ const CMtCoderBlock *block = &p->blocks[bi];
+ unsigned bufIndex = block->bufIndex;
+ BoolInt finished = block->finished;
+ if (res == SZ_OK && block->res != SZ_OK)
+ res = block->res;
+
+ if (bufIndex != (unsigned)(int)-1)
+ {
+ if (res == SZ_OK)
+ {
+ res = p->mtCallback->Write(p->mtCallbackObject, bufIndex);
+ if (res != SZ_OK)
+ MtProgress_SetError(&p->mtProgress, res);
+ }
+
+ CriticalSection_Enter(&p->cs);
+ {
+ p->freeBlockList[bufIndex] = p->freeBlockHead;
+ p->freeBlockHead = bufIndex;
+ }
+ CriticalSection_Leave(&p->cs);
+ }
+
+ RINOK_THREAD(Semaphore_Release1(&p->blocksSemaphore))
+
+ if (finished)
+ break;
+ }
+ }
+ }
+ #else
+ {
+ WRes wres = Event_Wait(&p->finishedEvent);
+ res = MY_SRes_HRESULT_FROM_WRes(wres);
+ }
+ #endif
+
+ if (res == SZ_OK)
+ res = p->readRes;
+
+ if (res == SZ_OK)
+ res = p->mtProgress.res;
+
+ #ifndef MTCODER_USE_WRITE_THREAD
+ if (res == SZ_OK)
+ res = p->writeRes;
+ #endif
+
+ if (res != SZ_OK)
+ MtCoder_Free(p);
+ return res;
+}
+
+#endif
+
+#undef RINOK_THREAD
diff --git a/C/MtCoder.h b/C/MtCoder.h
index 603329d..1231d3c 100644
--- a/C/MtCoder.h
+++ b/C/MtCoder.h
@@ -1,141 +1,141 @@
-/* MtCoder.h -- Multi-thread Coder
-2018-07-04 : Igor Pavlov : Public domain */
-
-#ifndef __MT_CODER_H
-#define __MT_CODER_H
-
-#include "MtDec.h"
-
-EXTERN_C_BEGIN
-
-/*
- if ( defined MTCODER__USE_WRITE_THREAD) : main thread writes all data blocks to output stream
- if (not defined MTCODER__USE_WRITE_THREAD) : any coder thread can write data blocks to output stream
-*/
-/* #define MTCODER__USE_WRITE_THREAD */
-
-#ifndef _7ZIP_ST
- #define MTCODER__GET_NUM_BLOCKS_FROM_THREADS(numThreads) ((numThreads) + (numThreads) / 8 + 1)
- #define MTCODER__THREADS_MAX 64
- #define MTCODER__BLOCKS_MAX (MTCODER__GET_NUM_BLOCKS_FROM_THREADS(MTCODER__THREADS_MAX) + 3)
-#else
- #define MTCODER__THREADS_MAX 1
- #define MTCODER__BLOCKS_MAX 1
-#endif
-
-
-#ifndef _7ZIP_ST
-
-
-typedef struct
-{
- ICompressProgress vt;
- CMtProgress *mtProgress;
- UInt64 inSize;
- UInt64 outSize;
-} CMtProgressThunk;
-
-void MtProgressThunk_CreateVTable(CMtProgressThunk *p);
-
-#define MtProgressThunk_Init(p) { (p)->inSize = 0; (p)->outSize = 0; }
-
-
-struct _CMtCoder;
-
-
-typedef struct
-{
- struct _CMtCoder *mtCoder;
- unsigned index;
- int stop;
- Byte *inBuf;
-
- CAutoResetEvent startEvent;
- CThread thread;
-} CMtCoderThread;
-
-
-typedef struct
-{
- SRes (*Code)(void *p, unsigned coderIndex, unsigned outBufIndex,
- const Byte *src, size_t srcSize, int finished);
- SRes (*Write)(void *p, unsigned outBufIndex);
-} IMtCoderCallback2;
-
-
-typedef struct
-{
- SRes res;
- unsigned bufIndex;
- BoolInt finished;
-} CMtCoderBlock;
-
-
-typedef struct _CMtCoder
-{
- /* input variables */
-
- size_t blockSize; /* size of input block */
- unsigned numThreadsMax;
- UInt64 expectedDataSize;
-
- ISeqInStream *inStream;
- const Byte *inData;
- size_t inDataSize;
-
- ICompressProgress *progress;
- ISzAllocPtr allocBig;
-
- IMtCoderCallback2 *mtCallback;
- void *mtCallbackObject;
-
-
- /* internal variables */
-
- size_t allocatedBufsSize;
-
- CAutoResetEvent readEvent;
- CSemaphore blocksSemaphore;
-
- BoolInt stopReading;
- SRes readRes;
-
- #ifdef MTCODER__USE_WRITE_THREAD
- CAutoResetEvent writeEvents[MTCODER__BLOCKS_MAX];
- #else
- CAutoResetEvent finishedEvent;
- SRes writeRes;
- unsigned writeIndex;
- Byte ReadyBlocks[MTCODER__BLOCKS_MAX];
- LONG numFinishedThreads;
- #endif
-
- unsigned numStartedThreadsLimit;
- unsigned numStartedThreads;
-
- unsigned numBlocksMax;
- unsigned blockIndex;
- UInt64 readProcessed;
-
- CCriticalSection cs;
-
- unsigned freeBlockHead;
- unsigned freeBlockList[MTCODER__BLOCKS_MAX];
-
- CMtProgress mtProgress;
- CMtCoderBlock blocks[MTCODER__BLOCKS_MAX];
- CMtCoderThread threads[MTCODER__THREADS_MAX];
-} CMtCoder;
-
-
-void MtCoder_Construct(CMtCoder *p);
-void MtCoder_Destruct(CMtCoder *p);
-SRes MtCoder_Code(CMtCoder *p);
-
-
-#endif
-
-
-EXTERN_C_END
-
-#endif
+/* MtCoder.h -- Multi-thread Coder
+2023-04-13 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_MT_CODER_H
+#define ZIP7_INC_MT_CODER_H
+
+#include "MtDec.h"
+
+EXTERN_C_BEGIN
+
+/*
+ if ( defined MTCODER_USE_WRITE_THREAD) : main thread writes all data blocks to output stream
+ if (not defined MTCODER_USE_WRITE_THREAD) : any coder thread can write data blocks to output stream
+*/
+/* #define MTCODER_USE_WRITE_THREAD */
+
+#ifndef Z7_ST
+ #define MTCODER_GET_NUM_BLOCKS_FROM_THREADS(numThreads) ((numThreads) + (numThreads) / 8 + 1)
+ #define MTCODER_THREADS_MAX 64
+ #define MTCODER_BLOCKS_MAX (MTCODER_GET_NUM_BLOCKS_FROM_THREADS(MTCODER_THREADS_MAX) + 3)
+#else
+ #define MTCODER_THREADS_MAX 1
+ #define MTCODER_BLOCKS_MAX 1
+#endif
+
+
+#ifndef Z7_ST
+
+
+typedef struct
+{
+ ICompressProgress vt;
+ CMtProgress *mtProgress;
+ UInt64 inSize;
+ UInt64 outSize;
+} CMtProgressThunk;
+
+void MtProgressThunk_CreateVTable(CMtProgressThunk *p);
+
+#define MtProgressThunk_INIT(p) { (p)->inSize = 0; (p)->outSize = 0; }
+
+
+struct CMtCoder_;
+
+
+typedef struct
+{
+ struct CMtCoder_ *mtCoder;
+ unsigned index;
+ int stop;
+ Byte *inBuf;
+
+ CAutoResetEvent startEvent;
+ CThread thread;
+} CMtCoderThread;
+
+
+typedef struct
+{
+ SRes (*Code)(void *p, unsigned coderIndex, unsigned outBufIndex,
+ const Byte *src, size_t srcSize, int finished);
+ SRes (*Write)(void *p, unsigned outBufIndex);
+} IMtCoderCallback2;
+
+
+typedef struct
+{
+ SRes res;
+ unsigned bufIndex;
+ BoolInt finished;
+} CMtCoderBlock;
+
+
+typedef struct CMtCoder_
+{
+ /* input variables */
+
+ size_t blockSize; /* size of input block */
+ unsigned numThreadsMax;
+ UInt64 expectedDataSize;
+
+ ISeqInStreamPtr inStream;
+ const Byte *inData;
+ size_t inDataSize;
+
+ ICompressProgressPtr progress;
+ ISzAllocPtr allocBig;
+
+ IMtCoderCallback2 *mtCallback;
+ void *mtCallbackObject;
+
+
+ /* internal variables */
+
+ size_t allocatedBufsSize;
+
+ CAutoResetEvent readEvent;
+ CSemaphore blocksSemaphore;
+
+ BoolInt stopReading;
+ SRes readRes;
+
+ #ifdef MTCODER_USE_WRITE_THREAD
+ CAutoResetEvent writeEvents[MTCODER_BLOCKS_MAX];
+ #else
+ CAutoResetEvent finishedEvent;
+ SRes writeRes;
+ unsigned writeIndex;
+ Byte ReadyBlocks[MTCODER_BLOCKS_MAX];
+ LONG numFinishedThreads;
+ #endif
+
+ unsigned numStartedThreadsLimit;
+ unsigned numStartedThreads;
+
+ unsigned numBlocksMax;
+ unsigned blockIndex;
+ UInt64 readProcessed;
+
+ CCriticalSection cs;
+
+ unsigned freeBlockHead;
+ unsigned freeBlockList[MTCODER_BLOCKS_MAX];
+
+ CMtProgress mtProgress;
+ CMtCoderBlock blocks[MTCODER_BLOCKS_MAX];
+ CMtCoderThread threads[MTCODER_THREADS_MAX];
+} CMtCoder;
+
+
+void MtCoder_Construct(CMtCoder *p);
+void MtCoder_Destruct(CMtCoder *p);
+SRes MtCoder_Code(CMtCoder *p);
+
+
+#endif
+
+
+EXTERN_C_END
+
+#endif
diff --git a/C/MtDec.c b/C/MtDec.c
index 25a8b04..7820699 100644
--- a/C/MtDec.c
+++ b/C/MtDec.c
@@ -1,1138 +1,1114 @@
-/* MtDec.c -- Multi-thread Decoder
-2019-02-02 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-// #define SHOW_DEBUG_INFO
-
-// #include <stdio.h>
-
-#ifdef SHOW_DEBUG_INFO
-#include <stdio.h>
-#endif
-
-#ifdef SHOW_DEBUG_INFO
-#define PRF(x) x
-#else
-#define PRF(x)
-#endif
-
-#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d))
-
-#include "MtDec.h"
-
-#ifndef _7ZIP_ST
-
-void MtProgress_Init(CMtProgress *p, ICompressProgress *progress)
-{
- p->progress = progress;
- p->res = SZ_OK;
- p->totalInSize = 0;
- p->totalOutSize = 0;
-}
-
-
-SRes MtProgress_Progress_ST(CMtProgress *p)
-{
- if (p->res == SZ_OK && p->progress)
- if (ICompressProgress_Progress(p->progress, p->totalInSize, p->totalOutSize) != SZ_OK)
- p->res = SZ_ERROR_PROGRESS;
- return p->res;
-}
-
-
-SRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize)
-{
- SRes res;
- CriticalSection_Enter(&p->cs);
-
- p->totalInSize += inSize;
- p->totalOutSize += outSize;
- if (p->res == SZ_OK && p->progress)
- if (ICompressProgress_Progress(p->progress, p->totalInSize, p->totalOutSize) != SZ_OK)
- p->res = SZ_ERROR_PROGRESS;
- res = p->res;
-
- CriticalSection_Leave(&p->cs);
- return res;
-}
-
-
-SRes MtProgress_GetError(CMtProgress *p)
-{
- SRes res;
- CriticalSection_Enter(&p->cs);
- res = p->res;
- CriticalSection_Leave(&p->cs);
- return res;
-}
-
-
-void MtProgress_SetError(CMtProgress *p, SRes res)
-{
- CriticalSection_Enter(&p->cs);
- if (p->res == SZ_OK)
- p->res = res;
- CriticalSection_Leave(&p->cs);
-}
-
-
-#define RINOK_THREAD(x) RINOK(x)
-
-
-static WRes ArEvent_OptCreate_And_Reset(CEvent *p)
-{
- if (Event_IsCreated(p))
- return Event_Reset(p);
- return AutoResetEvent_CreateNotSignaled(p);
-}
-
-
-struct __CMtDecBufLink
-{
- struct __CMtDecBufLink *next;
- void *pad[3];
-};
-
-typedef struct __CMtDecBufLink CMtDecBufLink;
-
-#define MTDEC__LINK_DATA_OFFSET sizeof(CMtDecBufLink)
-#define MTDEC__DATA_PTR_FROM_LINK(link) ((Byte *)(link) + MTDEC__LINK_DATA_OFFSET)
-
-
-
-static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp);
-
-
-static WRes MtDecThread_CreateEvents(CMtDecThread *t)
-{
- WRes wres = ArEvent_OptCreate_And_Reset(&t->canWrite);
- if (wres == 0)
- {
- wres = ArEvent_OptCreate_And_Reset(&t->canRead);
- if (wres == 0)
- return SZ_OK;
- }
- return wres;
-}
-
-
-static SRes MtDecThread_CreateAndStart(CMtDecThread *t)
-{
- WRes wres = MtDecThread_CreateEvents(t);
- // wres = 17; // for test
- if (wres == 0)
- {
- if (Thread_WasCreated(&t->thread))
- return SZ_OK;
- wres = Thread_Create(&t->thread, ThreadFunc, t);
- if (wres == 0)
- return SZ_OK;
- }
- return MY_SRes_HRESULT_FROM_WRes(wres);
-}
-
-
-void MtDecThread_FreeInBufs(CMtDecThread *t)
-{
- if (t->inBuf)
- {
- void *link = t->inBuf;
- t->inBuf = NULL;
- do
- {
- void *next = ((CMtDecBufLink *)link)->next;
- ISzAlloc_Free(t->mtDec->alloc, link);
- link = next;
- }
- while (link);
- }
-}
-
-
-static void MtDecThread_CloseThread(CMtDecThread *t)
-{
- if (Thread_WasCreated(&t->thread))
- {
- Event_Set(&t->canWrite); /* we can disable it. There are no threads waiting canWrite in normal cases */
- Event_Set(&t->canRead);
- Thread_Wait(&t->thread);
- Thread_Close(&t->thread);
- }
-
- Event_Close(&t->canRead);
- Event_Close(&t->canWrite);
-}
-
-static void MtDec_CloseThreads(CMtDec *p)
-{
- unsigned i;
- for (i = 0; i < MTDEC__THREADS_MAX; i++)
- MtDecThread_CloseThread(&p->threads[i]);
-}
-
-static void MtDecThread_Destruct(CMtDecThread *t)
-{
- MtDecThread_CloseThread(t);
- MtDecThread_FreeInBufs(t);
-}
-
-
-
-static SRes FullRead(ISeqInStream *stream, Byte *data, size_t *processedSize)
-{
- size_t size = *processedSize;
- *processedSize = 0;
- while (size != 0)
- {
- size_t cur = size;
- SRes res = ISeqInStream_Read(stream, data, &cur);
- *processedSize += cur;
- data += cur;
- size -= cur;
- RINOK(res);
- if (cur == 0)
- return SZ_OK;
- }
- return SZ_OK;
-}
-
-
-static SRes MtDec_GetError_Spec(CMtDec *p, UInt64 interruptIndex, BoolInt *wasInterrupted)
-{
- SRes res;
- CriticalSection_Enter(&p->mtProgress.cs);
- *wasInterrupted = (p->needInterrupt && interruptIndex > p->interruptIndex);
- res = p->mtProgress.res;
- CriticalSection_Leave(&p->mtProgress.cs);
- return res;
-}
-
-static SRes MtDec_Progress_GetError_Spec(CMtDec *p, UInt64 inSize, UInt64 outSize, UInt64 interruptIndex, BoolInt *wasInterrupted)
-{
- SRes res;
- CriticalSection_Enter(&p->mtProgress.cs);
-
- p->mtProgress.totalInSize += inSize;
- p->mtProgress.totalOutSize += outSize;
- if (p->mtProgress.res == SZ_OK && p->mtProgress.progress)
- if (ICompressProgress_Progress(p->mtProgress.progress, p->mtProgress.totalInSize, p->mtProgress.totalOutSize) != SZ_OK)
- p->mtProgress.res = SZ_ERROR_PROGRESS;
-
- *wasInterrupted = (p->needInterrupt && interruptIndex > p->interruptIndex);
- res = p->mtProgress.res;
-
- CriticalSection_Leave(&p->mtProgress.cs);
-
- return res;
-}
-
-static void MtDec_Interrupt(CMtDec *p, UInt64 interruptIndex)
-{
- CriticalSection_Enter(&p->mtProgress.cs);
- if (!p->needInterrupt || interruptIndex < p->interruptIndex)
- {
- p->interruptIndex = interruptIndex;
- p->needInterrupt = True;
- }
- CriticalSection_Leave(&p->mtProgress.cs);
-}
-
-Byte *MtDec_GetCrossBuff(CMtDec *p)
-{
- Byte *cr = p->crossBlock;
- if (!cr)
- {
- cr = (Byte *)ISzAlloc_Alloc(p->alloc, MTDEC__LINK_DATA_OFFSET + p->inBufSize);
- if (!cr)
- return NULL;
- p->crossBlock = cr;
- }
- return MTDEC__DATA_PTR_FROM_LINK(cr);
-}
-
-
-/*
- ThreadFunc2() returns:
- 0 - in all normal cases (even for stream error or memory allocation error)
- (!= 0) - WRes error return by system threading function
-*/
-
-// #define MTDEC_ProgessStep (1 << 22)
-#define MTDEC_ProgessStep (1 << 0)
-
-static WRes ThreadFunc2(CMtDecThread *t)
-{
- CMtDec *p = t->mtDec;
-
- PRF_STR_INT("ThreadFunc2", t->index);
-
- // SetThreadAffinityMask(GetCurrentThread(), 1 << t->index);
-
- for (;;)
- {
- SRes res, codeRes;
- BoolInt wasInterrupted, isAllocError, overflow, finish;
- SRes threadingErrorSRes;
- BoolInt needCode, needWrite, needContinue;
-
- size_t inDataSize_Start;
- UInt64 inDataSize;
- // UInt64 inDataSize_Full;
-
- UInt64 blockIndex;
-
- UInt64 inPrev = 0;
- UInt64 outPrev = 0;
- UInt64 inCodePos;
- UInt64 outCodePos;
-
- Byte *afterEndData = NULL;
- size_t afterEndData_Size = 0;
-
- BoolInt canCreateNewThread = False;
- // CMtDecCallbackInfo parse;
- CMtDecThread *nextThread;
-
- PRF_STR_INT("Event_Wait(&t->canRead)", t->index);
-
- RINOK_THREAD(Event_Wait(&t->canRead));
- if (p->exitThread)
- return 0;
-
- PRF_STR_INT("after Event_Wait(&t->canRead)", t->index);
-
- // if (t->index == 3) return 19; // for test
-
- blockIndex = p->blockIndex++;
-
- // PRF(printf("\ncanRead\n"))
-
- res = MtDec_Progress_GetError_Spec(p, 0, 0, blockIndex, &wasInterrupted);
-
- finish = p->readWasFinished;
- needCode = False;
- needWrite = False;
- isAllocError = False;
- overflow = False;
-
- inDataSize_Start = 0;
- inDataSize = 0;
- // inDataSize_Full = 0;
-
- if (res == SZ_OK && !wasInterrupted)
- {
- // if (p->inStream)
- {
- CMtDecBufLink *prev = NULL;
- CMtDecBufLink *link = (CMtDecBufLink *)t->inBuf;
- size_t crossSize = p->crossEnd - p->crossStart;
-
- PRF(printf("\ncrossSize = %d\n", crossSize));
-
- for (;;)
- {
- if (!link)
- {
- link = (CMtDecBufLink *)ISzAlloc_Alloc(p->alloc, MTDEC__LINK_DATA_OFFSET + p->inBufSize);
- if (!link)
- {
- finish = True;
- // p->allocError_for_Read_BlockIndex = blockIndex;
- isAllocError = True;
- break;
- }
- link->next = NULL;
- if (prev)
- {
- // static unsigned g_num = 0;
- // printf("\n%6d : %x", ++g_num, (unsigned)(size_t)((Byte *)link - (Byte *)prev));
- prev->next = link;
- }
- else
- t->inBuf = (void *)link;
- }
-
- {
- Byte *data = MTDEC__DATA_PTR_FROM_LINK(link);
- Byte *parseData = data;
- size_t size;
-
- if (crossSize != 0)
- {
- inDataSize = crossSize;
- // inDataSize_Full = inDataSize;
- inDataSize_Start = crossSize;
- size = crossSize;
- parseData = MTDEC__DATA_PTR_FROM_LINK(p->crossBlock) + p->crossStart;
- PRF(printf("\ncross : crossStart = %7d crossEnd = %7d finish = %1d",
- (int)p->crossStart, (int)p->crossEnd, (int)finish));
- }
- else
- {
- size = p->inBufSize;
-
- res = FullRead(p->inStream, data, &size);
-
- // size = 10; // test
-
- inDataSize += size;
- // inDataSize_Full = inDataSize;
- if (!prev)
- inDataSize_Start = size;
-
- p->readProcessed += size;
- finish = (size != p->inBufSize);
- if (finish)
- p->readWasFinished = True;
-
- // res = E_INVALIDARG; // test
-
- if (res != SZ_OK)
- {
- // PRF(printf("\nRead error = %d\n", res))
- // we want to decode all data before error
- p->readRes = res;
- // p->readError_BlockIndex = blockIndex;
- p->readWasFinished = True;
- finish = True;
- res = SZ_OK;
- // break;
- }
-
- if (inDataSize - inPrev >= MTDEC_ProgessStep)
- {
- res = MtDec_Progress_GetError_Spec(p, 0, 0, blockIndex, &wasInterrupted);
- if (res != SZ_OK || wasInterrupted)
- break;
- inPrev = inDataSize;
- }
- }
-
- {
- CMtDecCallbackInfo parse;
-
- parse.startCall = (prev == NULL);
- parse.src = parseData;
- parse.srcSize = size;
- parse.srcFinished = finish;
- parse.canCreateNewThread = True;
-
- // PRF(printf("\nParse size = %d\n", (unsigned)size))
-
- p->mtCallback->Parse(p->mtCallbackObject, t->index, &parse);
-
- needWrite = True;
- canCreateNewThread = parse.canCreateNewThread;
-
- // printf("\n\n%12I64u %12I64u", (UInt64)p->mtProgress.totalInSize, (UInt64)p->mtProgress.totalOutSize);
-
- if (
- // parseRes != SZ_OK ||
- // inDataSize - (size - parse.srcSize) > p->inBlockMax
- // ||
- parse.state == MTDEC_PARSE_OVERFLOW
- // || wasInterrupted
- )
- {
- // Overflow or Parse error - switch from MT decoding to ST decoding
- finish = True;
- overflow = True;
-
- {
- PRF(printf("\n Overflow"));
- // PRF(printf("\nisBlockFinished = %d", (unsigned)parse.blockWasFinished));
- PRF(printf("\n inDataSize = %d", (unsigned)inDataSize));
- }
-
- if (crossSize != 0)
- memcpy(data, parseData, size);
- p->crossStart = 0;
- p->crossEnd = 0;
- break;
- }
-
- if (crossSize != 0)
- {
- memcpy(data, parseData, parse.srcSize);
- p->crossStart += parse.srcSize;
- }
-
- if (parse.state != MTDEC_PARSE_CONTINUE || finish)
- {
- // we don't need to parse in current thread anymore
-
- if (parse.state == MTDEC_PARSE_END)
- finish = True;
-
- needCode = True;
- // p->crossFinished = finish;
-
- if (parse.srcSize == size)
- {
- // full parsed - no cross transfer
- p->crossStart = 0;
- p->crossEnd = 0;
- break;
- }
-
- if (parse.state == MTDEC_PARSE_END)
- {
- p->crossStart = 0;
- p->crossEnd = 0;
-
- if (crossSize != 0)
- memcpy(data + parse.srcSize, parseData + parse.srcSize, size - parse.srcSize); // we need all data
- afterEndData_Size = size - parse.srcSize;
- afterEndData = parseData + parse.srcSize;
-
- // we reduce data size to required bytes (parsed only)
- inDataSize -= (size - parse.srcSize);
- if (!prev)
- inDataSize_Start = parse.srcSize;
- break;
- }
-
- {
- // partial parsed - need cross transfer
- if (crossSize != 0)
- inDataSize = parse.srcSize; // it's only parsed now
- else
- {
- // partial parsed - is not in initial cross block - we need to copy new data to cross block
- Byte *cr = MtDec_GetCrossBuff(p);
- if (!cr)
- {
- {
- PRF(printf("\ncross alloc error error\n"));
- // res = SZ_ERROR_MEM;
- finish = True;
- // p->allocError_for_Read_BlockIndex = blockIndex;
- isAllocError = True;
- break;
- }
- }
-
- {
- size_t crSize = size - parse.srcSize;
- inDataSize -= crSize;
- p->crossEnd = crSize;
- p->crossStart = 0;
- memcpy(cr, parseData + parse.srcSize, crSize);
- }
- }
-
- // inDataSize_Full = inDataSize;
- if (!prev)
- inDataSize_Start = parse.srcSize; // it's partial size (parsed only)
-
- finish = False;
- break;
- }
- }
-
- if (parse.srcSize != size)
- {
- res = SZ_ERROR_FAIL;
- PRF(printf("\nfinished error SZ_ERROR_FAIL = %d\n", res));
- break;
- }
- }
- }
-
- prev = link;
- link = link->next;
-
- if (crossSize != 0)
- {
- crossSize = 0;
- p->crossStart = 0;
- p->crossEnd = 0;
- }
- }
- }
-
- if (res == SZ_OK)
- res = MtDec_GetError_Spec(p, blockIndex, &wasInterrupted);
- }
-
- codeRes = SZ_OK;
-
- if (res == SZ_OK && needCode && !wasInterrupted)
- {
- codeRes = p->mtCallback->PreCode(p->mtCallbackObject, t->index);
- if (codeRes != SZ_OK)
- {
- needCode = False;
- finish = True;
- // SZ_ERROR_MEM is expected error here.
- // if (codeRes == SZ_ERROR_MEM) - we will try single-thread decoding later.
- // if (codeRes != SZ_ERROR_MEM) - we can stop decoding or try single-thread decoding.
- }
- }
-
- if (res != SZ_OK || wasInterrupted)
- finish = True;
-
- nextThread = NULL;
- threadingErrorSRes = SZ_OK;
-
- if (!finish)
- {
- if (p->numStartedThreads < p->numStartedThreads_Limit && canCreateNewThread)
- {
- SRes res2 = MtDecThread_CreateAndStart(&p->threads[p->numStartedThreads]);
- if (res2 == SZ_OK)
- {
- // if (p->numStartedThreads % 1000 == 0) PRF(printf("\n numStartedThreads=%d\n", p->numStartedThreads));
- p->numStartedThreads++;
- }
- else
- {
- PRF(printf("\nERROR: numStartedThreads=%d\n", p->numStartedThreads));
- if (p->numStartedThreads == 1)
- {
- // if only one thread is possible, we leave muti-threading code
- finish = True;
- needCode = False;
- threadingErrorSRes = res2;
- }
- else
- p->numStartedThreads_Limit = p->numStartedThreads;
- }
- }
-
- if (!finish)
- {
- unsigned nextIndex = t->index + 1;
- nextThread = &p->threads[nextIndex >= p->numStartedThreads ? 0 : nextIndex];
- RINOK_THREAD(Event_Set(&nextThread->canRead))
- // We have started executing for new iteration (with next thread)
- // And that next thread now is responsible for possible exit from decoding (threading_code)
- }
- }
-
- // each call of Event_Set(&nextThread->canRead) must be followed by call of Event_Set(&nextThread->canWrite)
- // if ( !finish ) we must call Event_Set(&nextThread->canWrite) in any case
- // if ( finish ) we switch to single-thread mode and there are 2 ways at the end of current iteration (current block):
- // - if (needContinue) after Write(&needContinue), we restore decoding with new iteration
- // - otherwise we stop decoding and exit from ThreadFunc2()
-
- // Don't change (finish) variable in the further code
-
-
- // ---------- CODE ----------
-
- inPrev = 0;
- outPrev = 0;
- inCodePos = 0;
- outCodePos = 0;
-
- if (res == SZ_OK && needCode && codeRes == SZ_OK)
- {
- BoolInt isStartBlock = True;
- CMtDecBufLink *link = (CMtDecBufLink *)t->inBuf;
-
- for (;;)
- {
- size_t inSize;
- int stop;
-
- if (isStartBlock)
- inSize = inDataSize_Start;
- else
- {
- UInt64 rem = inDataSize - inCodePos;
- inSize = p->inBufSize;
- if (inSize > rem)
- inSize = (size_t)rem;
- }
-
- inCodePos += inSize;
- stop = True;
-
- codeRes = p->mtCallback->Code(p->mtCallbackObject, t->index,
- (const Byte *)MTDEC__DATA_PTR_FROM_LINK(link), inSize,
- (inCodePos == inDataSize), // srcFinished
- &inCodePos, &outCodePos, &stop);
-
- if (codeRes != SZ_OK)
- {
- PRF(printf("\nCode Interrupt error = %x\n", codeRes));
- // we interrupt only later blocks
- MtDec_Interrupt(p, blockIndex);
- break;
- }
-
- if (stop || inCodePos == inDataSize)
- break;
-
- {
- const UInt64 inDelta = inCodePos - inPrev;
- const UInt64 outDelta = outCodePos - outPrev;
- if (inDelta >= MTDEC_ProgessStep || outDelta >= MTDEC_ProgessStep)
- {
- // Sleep(1);
- res = MtDec_Progress_GetError_Spec(p, inDelta, outDelta, blockIndex, &wasInterrupted);
- if (res != SZ_OK || wasInterrupted)
- break;
- inPrev = inCodePos;
- outPrev = outCodePos;
- }
- }
-
- link = link->next;
- isStartBlock = False;
- }
- }
-
-
- // ---------- WRITE ----------
-
- RINOK_THREAD(Event_Wait(&t->canWrite));
-
- {
- BoolInt isErrorMode = False;
- BoolInt canRecode = True;
- BoolInt needWriteToStream = needWrite;
-
- if (p->exitThread) return 0; // it's never executed in normal cases
-
- if (p->wasInterrupted)
- wasInterrupted = True;
- else
- {
- if (codeRes != SZ_OK) // || !needCode // check it !!!
- {
- p->wasInterrupted = True;
- p->codeRes = codeRes;
- if (codeRes == SZ_ERROR_MEM)
- isAllocError = True;
- }
-
- if (threadingErrorSRes)
- {
- p->wasInterrupted = True;
- p->threadingErrorSRes = threadingErrorSRes;
- needWriteToStream = False;
- }
- if (isAllocError)
- {
- p->wasInterrupted = True;
- p->isAllocError = True;
- needWriteToStream = False;
- }
- if (overflow)
- {
- p->wasInterrupted = True;
- p->overflow = True;
- needWriteToStream = False;
- }
- }
-
- if (needCode)
- {
- if (wasInterrupted)
- {
- inCodePos = 0;
- outCodePos = 0;
- }
- {
- const UInt64 inDelta = inCodePos - inPrev;
- const UInt64 outDelta = outCodePos - outPrev;
- // if (inDelta != 0 || outDelta != 0)
- res = MtProgress_ProgressAdd(&p->mtProgress, inDelta, outDelta);
- }
- }
-
- needContinue = (!finish);
-
- // if (res == SZ_OK && needWrite && !wasInterrupted)
- if (needWrite)
- {
- // p->inProcessed += inCodePos;
-
- res = p->mtCallback->Write(p->mtCallbackObject, t->index,
- res == SZ_OK && needWriteToStream && !wasInterrupted, // needWrite
- afterEndData, afterEndData_Size,
- &needContinue,
- &canRecode);
-
- // res= E_INVALIDARG; // for test
-
- PRF(printf("\nAfter Write needContinue = %d\n", (unsigned)needContinue));
- PRF(printf("\nprocessed = %d\n", (unsigned)p->inProcessed));
-
- if (res != SZ_OK)
- {
- PRF(printf("\nWrite error = %d\n", res));
- isErrorMode = True;
- p->wasInterrupted = True;
- }
- if (res != SZ_OK
- || (!needContinue && !finish))
- {
- PRF(printf("\nWrite Interrupt error = %x\n", res));
- MtDec_Interrupt(p, blockIndex);
- }
- }
-
- if (canRecode)
- if (!needCode
- || res != SZ_OK
- || p->wasInterrupted
- || codeRes != SZ_OK
- || wasInterrupted
- || p->numFilledThreads != 0
- || isErrorMode)
- {
- if (p->numFilledThreads == 0)
- p->filledThreadStart = t->index;
- if (inDataSize != 0 || !finish)
- {
- t->inDataSize_Start = inDataSize_Start;
- t->inDataSize = inDataSize;
- p->numFilledThreads++;
- }
- PRF(printf("\np->numFilledThreads = %d\n", p->numFilledThreads));
- PRF(printf("p->filledThreadStart = %d\n", p->filledThreadStart));
- }
-
- if (!finish)
- {
- RINOK_THREAD(Event_Set(&nextThread->canWrite));
- }
- else
- {
- if (needContinue)
- {
- // we restore decoding with new iteration
- RINOK_THREAD(Event_Set(&p->threads[0].canWrite));
- }
- else
- {
- // we exit from decoding
- if (t->index == 0)
- return SZ_OK;
- p->exitThread = True;
- }
- RINOK_THREAD(Event_Set(&p->threads[0].canRead));
- }
- }
- }
-}
-
-#ifdef _WIN32
-#define USE_ALLOCA
-#endif
-
-#ifdef USE_ALLOCA
-#ifdef _WIN32
-#include <malloc.h>
-#else
-#include <stdlib.h>
-#endif
-#endif
-
-
-static THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc1(void *pp)
-{
- WRes res;
-
- CMtDecThread *t = (CMtDecThread *)pp;
- CMtDec *p;
-
- // fprintf(stdout, "\n%d = %p\n", t->index, &t);
-
- res = ThreadFunc2(t);
- p = t->mtDec;
- if (res == 0)
- return p->exitThreadWRes;
- {
- // it's unexpected situation for some threading function error
- if (p->exitThreadWRes == 0)
- p->exitThreadWRes = res;
- PRF(printf("\nthread exit error = %d\n", res));
- p->exitThread = True;
- Event_Set(&p->threads[0].canRead);
- Event_Set(&p->threads[0].canWrite);
- MtProgress_SetError(&p->mtProgress, MY_SRes_HRESULT_FROM_WRes(res));
- }
- return res;
-}
-
-static MY_NO_INLINE THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE ThreadFunc(void *pp)
-{
- CMtDecThread *t = (CMtDecThread *)pp;
-
- // fprintf(stderr, "\n%d = %p - before", t->index, &t);
- #ifdef USE_ALLOCA
- t->allocaPtr = alloca(t->index * 128);
- #endif
- return ThreadFunc1(pp);
-}
-
-
-int MtDec_PrepareRead(CMtDec *p)
-{
- if (p->crossBlock && p->crossStart == p->crossEnd)
- {
- ISzAlloc_Free(p->alloc, p->crossBlock);
- p->crossBlock = NULL;
- }
-
- {
- unsigned i;
- for (i = 0; i < MTDEC__THREADS_MAX; i++)
- if (i > p->numStartedThreads
- || p->numFilledThreads <=
- (i >= p->filledThreadStart ?
- i - p->filledThreadStart :
- i + p->numStartedThreads - p->filledThreadStart))
- MtDecThread_FreeInBufs(&p->threads[i]);
- }
-
- return (p->numFilledThreads != 0) || (p->crossStart != p->crossEnd);
-}
-
-
-const Byte *MtDec_Read(CMtDec *p, size_t *inLim)
-{
- while (p->numFilledThreads != 0)
- {
- CMtDecThread *t = &p->threads[p->filledThreadStart];
-
- if (*inLim != 0)
- {
- {
- void *link = t->inBuf;
- void *next = ((CMtDecBufLink *)link)->next;
- ISzAlloc_Free(p->alloc, link);
- t->inBuf = next;
- }
-
- if (t->inDataSize == 0)
- {
- MtDecThread_FreeInBufs(t);
- if (--p->numFilledThreads == 0)
- break;
- if (++p->filledThreadStart == p->numStartedThreads)
- p->filledThreadStart = 0;
- t = &p->threads[p->filledThreadStart];
- }
- }
-
- {
- size_t lim = t->inDataSize_Start;
- if (lim != 0)
- t->inDataSize_Start = 0;
- else
- {
- UInt64 rem = t->inDataSize;
- lim = p->inBufSize;
- if (lim > rem)
- lim = (size_t)rem;
- }
- t->inDataSize -= lim;
- *inLim = lim;
- return (const Byte *)MTDEC__DATA_PTR_FROM_LINK(t->inBuf);
- }
- }
-
- {
- size_t crossSize = p->crossEnd - p->crossStart;
- if (crossSize != 0)
- {
- const Byte *data = MTDEC__DATA_PTR_FROM_LINK(p->crossBlock) + p->crossStart;
- *inLim = crossSize;
- p->crossStart = 0;
- p->crossEnd = 0;
- return data;
- }
- *inLim = 0;
- if (p->crossBlock)
- {
- ISzAlloc_Free(p->alloc, p->crossBlock);
- p->crossBlock = NULL;
- }
- return NULL;
- }
-}
-
-
-void MtDec_Construct(CMtDec *p)
-{
- unsigned i;
-
- p->inBufSize = (size_t)1 << 18;
-
- p->numThreadsMax = 0;
-
- p->inStream = NULL;
-
- // p->inData = NULL;
- // p->inDataSize = 0;
-
- p->crossBlock = NULL;
- p->crossStart = 0;
- p->crossEnd = 0;
-
- p->numFilledThreads = 0;
-
- p->progress = NULL;
- p->alloc = NULL;
-
- p->mtCallback = NULL;
- p->mtCallbackObject = NULL;
-
- p->allocatedBufsSize = 0;
-
- for (i = 0; i < MTDEC__THREADS_MAX; i++)
- {
- CMtDecThread *t = &p->threads[i];
- t->mtDec = p;
- t->index = i;
- t->inBuf = NULL;
- Event_Construct(&t->canRead);
- Event_Construct(&t->canWrite);
- Thread_Construct(&t->thread);
- }
-
- // Event_Construct(&p->finishedEvent);
-
- CriticalSection_Init(&p->mtProgress.cs);
-}
-
-
-static void MtDec_Free(CMtDec *p)
-{
- unsigned i;
-
- p->exitThread = True;
-
- for (i = 0; i < MTDEC__THREADS_MAX; i++)
- MtDecThread_Destruct(&p->threads[i]);
-
- // Event_Close(&p->finishedEvent);
-
- if (p->crossBlock)
- {
- ISzAlloc_Free(p->alloc, p->crossBlock);
- p->crossBlock = NULL;
- }
-}
-
-
-void MtDec_Destruct(CMtDec *p)
-{
- MtDec_Free(p);
-
- CriticalSection_Delete(&p->mtProgress.cs);
-}
-
-
-SRes MtDec_Code(CMtDec *p)
-{
- unsigned i;
-
- p->inProcessed = 0;
-
- p->blockIndex = 1; // it must be larger than not_defined index (0)
- p->isAllocError = False;
- p->overflow = False;
- p->threadingErrorSRes = SZ_OK;
-
- p->needContinue = True;
-
- p->readWasFinished = False;
- p->needInterrupt = False;
- p->interruptIndex = (UInt64)(Int64)-1;
-
- p->readProcessed = 0;
- p->readRes = SZ_OK;
- p->codeRes = SZ_OK;
- p->wasInterrupted = False;
-
- p->crossStart = 0;
- p->crossEnd = 0;
-
- p->filledThreadStart = 0;
- p->numFilledThreads = 0;
-
- {
- unsigned numThreads = p->numThreadsMax;
- if (numThreads > MTDEC__THREADS_MAX)
- numThreads = MTDEC__THREADS_MAX;
- p->numStartedThreads_Limit = numThreads;
- p->numStartedThreads = 0;
- }
-
- if (p->inBufSize != p->allocatedBufsSize)
- {
- for (i = 0; i < MTDEC__THREADS_MAX; i++)
- {
- CMtDecThread *t = &p->threads[i];
- if (t->inBuf)
- MtDecThread_FreeInBufs(t);
- }
- if (p->crossBlock)
- {
- ISzAlloc_Free(p->alloc, p->crossBlock);
- p->crossBlock = NULL;
- }
-
- p->allocatedBufsSize = p->inBufSize;
- }
-
- MtProgress_Init(&p->mtProgress, p->progress);
-
- // RINOK_THREAD(ArEvent_OptCreate_And_Reset(&p->finishedEvent));
- p->exitThread = False;
- p->exitThreadWRes = 0;
-
- {
- WRes wres;
- WRes sres;
- CMtDecThread *nextThread = &p->threads[p->numStartedThreads++];
- // wres = MtDecThread_CreateAndStart(nextThread);
- wres = MtDecThread_CreateEvents(nextThread);
- if (wres == 0) { wres = Event_Set(&nextThread->canWrite);
- if (wres == 0) { wres = Event_Set(&nextThread->canRead);
- if (wres == 0) { wres = ThreadFunc(nextThread);
- if (wres != 0)
- {
- p->needContinue = False;
- MtDec_CloseThreads(p);
- }}}}
-
- // wres = 17; // for test
- // wres = Event_Wait(&p->finishedEvent);
-
- sres = MY_SRes_HRESULT_FROM_WRes(wres);
-
- if (sres != 0)
- p->threadingErrorSRes = sres;
-
- if (
- // wres == 0
- // wres != 0
- // || p->mtc.codeRes == SZ_ERROR_MEM
- p->isAllocError
- || p->threadingErrorSRes != SZ_OK
- || p->overflow)
- {
- // p->needContinue = True;
- }
- else
- p->needContinue = False;
-
- if (p->needContinue)
- return SZ_OK;
-
- // if (sres != SZ_OK)
- return sres;
- // return E_FAIL;
- }
-}
-
-#endif
+/* MtDec.c -- Multi-thread Decoder
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+// #define SHOW_DEBUG_INFO
+
+// #include <stdio.h>
+#include <string.h>
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#endif
+
+#include "MtDec.h"
+
+#ifndef Z7_ST
+
+#ifdef SHOW_DEBUG_INFO
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d))
+
+void MtProgress_Init(CMtProgress *p, ICompressProgressPtr progress)
+{
+ p->progress = progress;
+ p->res = SZ_OK;
+ p->totalInSize = 0;
+ p->totalOutSize = 0;
+}
+
+
+SRes MtProgress_Progress_ST(CMtProgress *p)
+{
+ if (p->res == SZ_OK && p->progress)
+ if (ICompressProgress_Progress(p->progress, p->totalInSize, p->totalOutSize) != SZ_OK)
+ p->res = SZ_ERROR_PROGRESS;
+ return p->res;
+}
+
+
+SRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize)
+{
+ SRes res;
+ CriticalSection_Enter(&p->cs);
+
+ p->totalInSize += inSize;
+ p->totalOutSize += outSize;
+ if (p->res == SZ_OK && p->progress)
+ if (ICompressProgress_Progress(p->progress, p->totalInSize, p->totalOutSize) != SZ_OK)
+ p->res = SZ_ERROR_PROGRESS;
+ res = p->res;
+
+ CriticalSection_Leave(&p->cs);
+ return res;
+}
+
+
+SRes MtProgress_GetError(CMtProgress *p)
+{
+ SRes res;
+ CriticalSection_Enter(&p->cs);
+ res = p->res;
+ CriticalSection_Leave(&p->cs);
+ return res;
+}
+
+
+void MtProgress_SetError(CMtProgress *p, SRes res)
+{
+ CriticalSection_Enter(&p->cs);
+ if (p->res == SZ_OK)
+ p->res = res;
+ CriticalSection_Leave(&p->cs);
+}
+
+
+#define RINOK_THREAD(x) RINOK_WRes(x)
+
+
+struct CMtDecBufLink_
+{
+ struct CMtDecBufLink_ *next;
+ void *pad[3];
+};
+
+typedef struct CMtDecBufLink_ CMtDecBufLink;
+
+#define MTDEC__LINK_DATA_OFFSET sizeof(CMtDecBufLink)
+#define MTDEC__DATA_PTR_FROM_LINK(link) ((Byte *)(link) + MTDEC__LINK_DATA_OFFSET)
+
+
+
+static THREAD_FUNC_DECL MtDec_ThreadFunc(void *pp);
+
+
+static WRes MtDecThread_CreateEvents(CMtDecThread *t)
+{
+ WRes wres = AutoResetEvent_OptCreate_And_Reset(&t->canWrite);
+ if (wres == 0)
+ {
+ wres = AutoResetEvent_OptCreate_And_Reset(&t->canRead);
+ if (wres == 0)
+ return SZ_OK;
+ }
+ return wres;
+}
+
+
+static SRes MtDecThread_CreateAndStart(CMtDecThread *t)
+{
+ WRes wres = MtDecThread_CreateEvents(t);
+ // wres = 17; // for test
+ if (wres == 0)
+ {
+ if (Thread_WasCreated(&t->thread))
+ return SZ_OK;
+ wres = Thread_Create(&t->thread, MtDec_ThreadFunc, t);
+ if (wres == 0)
+ return SZ_OK;
+ }
+ return MY_SRes_HRESULT_FROM_WRes(wres);
+}
+
+
+void MtDecThread_FreeInBufs(CMtDecThread *t)
+{
+ if (t->inBuf)
+ {
+ void *link = t->inBuf;
+ t->inBuf = NULL;
+ do
+ {
+ void *next = ((CMtDecBufLink *)link)->next;
+ ISzAlloc_Free(t->mtDec->alloc, link);
+ link = next;
+ }
+ while (link);
+ }
+}
+
+
+static void MtDecThread_CloseThread(CMtDecThread *t)
+{
+ if (Thread_WasCreated(&t->thread))
+ {
+ Event_Set(&t->canWrite); /* we can disable it. There are no threads waiting canWrite in normal cases */
+ Event_Set(&t->canRead);
+ Thread_Wait_Close(&t->thread);
+ }
+
+ Event_Close(&t->canRead);
+ Event_Close(&t->canWrite);
+}
+
+static void MtDec_CloseThreads(CMtDec *p)
+{
+ unsigned i;
+ for (i = 0; i < MTDEC_THREADS_MAX; i++)
+ MtDecThread_CloseThread(&p->threads[i]);
+}
+
+static void MtDecThread_Destruct(CMtDecThread *t)
+{
+ MtDecThread_CloseThread(t);
+ MtDecThread_FreeInBufs(t);
+}
+
+
+
+static SRes MtDec_GetError_Spec(CMtDec *p, UInt64 interruptIndex, BoolInt *wasInterrupted)
+{
+ SRes res;
+ CriticalSection_Enter(&p->mtProgress.cs);
+ *wasInterrupted = (p->needInterrupt && interruptIndex > p->interruptIndex);
+ res = p->mtProgress.res;
+ CriticalSection_Leave(&p->mtProgress.cs);
+ return res;
+}
+
+static SRes MtDec_Progress_GetError_Spec(CMtDec *p, UInt64 inSize, UInt64 outSize, UInt64 interruptIndex, BoolInt *wasInterrupted)
+{
+ SRes res;
+ CriticalSection_Enter(&p->mtProgress.cs);
+
+ p->mtProgress.totalInSize += inSize;
+ p->mtProgress.totalOutSize += outSize;
+ if (p->mtProgress.res == SZ_OK && p->mtProgress.progress)
+ if (ICompressProgress_Progress(p->mtProgress.progress, p->mtProgress.totalInSize, p->mtProgress.totalOutSize) != SZ_OK)
+ p->mtProgress.res = SZ_ERROR_PROGRESS;
+
+ *wasInterrupted = (p->needInterrupt && interruptIndex > p->interruptIndex);
+ res = p->mtProgress.res;
+
+ CriticalSection_Leave(&p->mtProgress.cs);
+
+ return res;
+}
+
+static void MtDec_Interrupt(CMtDec *p, UInt64 interruptIndex)
+{
+ CriticalSection_Enter(&p->mtProgress.cs);
+ if (!p->needInterrupt || interruptIndex < p->interruptIndex)
+ {
+ p->interruptIndex = interruptIndex;
+ p->needInterrupt = True;
+ }
+ CriticalSection_Leave(&p->mtProgress.cs);
+}
+
+Byte *MtDec_GetCrossBuff(CMtDec *p)
+{
+ Byte *cr = p->crossBlock;
+ if (!cr)
+ {
+ cr = (Byte *)ISzAlloc_Alloc(p->alloc, MTDEC__LINK_DATA_OFFSET + p->inBufSize);
+ if (!cr)
+ return NULL;
+ p->crossBlock = cr;
+ }
+ return MTDEC__DATA_PTR_FROM_LINK(cr);
+}
+
+
+/*
+ MtDec_ThreadFunc2() returns:
+ 0 - in all normal cases (even for stream error or memory allocation error)
+ (!= 0) - WRes error return by system threading function
+*/
+
+// #define MTDEC_ProgessStep (1 << 22)
+#define MTDEC_ProgessStep (1 << 0)
+
+static WRes MtDec_ThreadFunc2(CMtDecThread *t)
+{
+ CMtDec *p = t->mtDec;
+
+ PRF_STR_INT("MtDec_ThreadFunc2", t->index)
+
+ // SetThreadAffinityMask(GetCurrentThread(), 1 << t->index);
+
+ for (;;)
+ {
+ SRes res, codeRes;
+ BoolInt wasInterrupted, isAllocError, overflow, finish;
+ SRes threadingErrorSRes;
+ BoolInt needCode, needWrite, needContinue;
+
+ size_t inDataSize_Start;
+ UInt64 inDataSize;
+ // UInt64 inDataSize_Full;
+
+ UInt64 blockIndex;
+
+ UInt64 inPrev = 0;
+ UInt64 outPrev = 0;
+ UInt64 inCodePos;
+ UInt64 outCodePos;
+
+ Byte *afterEndData = NULL;
+ size_t afterEndData_Size = 0;
+ BoolInt afterEndData_IsCross = False;
+
+ BoolInt canCreateNewThread = False;
+ // CMtDecCallbackInfo parse;
+ CMtDecThread *nextThread;
+
+ PRF_STR_INT("=============== Event_Wait(&t->canRead)", t->index)
+
+ RINOK_THREAD(Event_Wait(&t->canRead))
+ if (p->exitThread)
+ return 0;
+
+ PRF_STR_INT("after Event_Wait(&t->canRead)", t->index)
+
+ // if (t->index == 3) return 19; // for test
+
+ blockIndex = p->blockIndex++;
+
+ // PRF(printf("\ncanRead\n"))
+
+ res = MtDec_Progress_GetError_Spec(p, 0, 0, blockIndex, &wasInterrupted);
+
+ finish = p->readWasFinished;
+ needCode = False;
+ needWrite = False;
+ isAllocError = False;
+ overflow = False;
+
+ inDataSize_Start = 0;
+ inDataSize = 0;
+ // inDataSize_Full = 0;
+
+ if (res == SZ_OK && !wasInterrupted)
+ {
+ // if (p->inStream)
+ {
+ CMtDecBufLink *prev = NULL;
+ CMtDecBufLink *link = (CMtDecBufLink *)t->inBuf;
+ size_t crossSize = p->crossEnd - p->crossStart;
+
+ PRF(printf("\ncrossSize = %d\n", crossSize));
+
+ for (;;)
+ {
+ if (!link)
+ {
+ link = (CMtDecBufLink *)ISzAlloc_Alloc(p->alloc, MTDEC__LINK_DATA_OFFSET + p->inBufSize);
+ if (!link)
+ {
+ finish = True;
+ // p->allocError_for_Read_BlockIndex = blockIndex;
+ isAllocError = True;
+ break;
+ }
+ link->next = NULL;
+ if (prev)
+ {
+ // static unsigned g_num = 0;
+ // printf("\n%6d : %x", ++g_num, (unsigned)(size_t)((Byte *)link - (Byte *)prev));
+ prev->next = link;
+ }
+ else
+ t->inBuf = (void *)link;
+ }
+
+ {
+ Byte *data = MTDEC__DATA_PTR_FROM_LINK(link);
+ Byte *parseData = data;
+ size_t size;
+
+ if (crossSize != 0)
+ {
+ inDataSize = crossSize;
+ // inDataSize_Full = inDataSize;
+ inDataSize_Start = crossSize;
+ size = crossSize;
+ parseData = MTDEC__DATA_PTR_FROM_LINK(p->crossBlock) + p->crossStart;
+ PRF(printf("\ncross : crossStart = %7d crossEnd = %7d finish = %1d",
+ (int)p->crossStart, (int)p->crossEnd, (int)finish));
+ }
+ else
+ {
+ size = p->inBufSize;
+
+ res = SeqInStream_ReadMax(p->inStream, data, &size);
+
+ // size = 10; // test
+
+ inDataSize += size;
+ // inDataSize_Full = inDataSize;
+ if (!prev)
+ inDataSize_Start = size;
+
+ p->readProcessed += size;
+ finish = (size != p->inBufSize);
+ if (finish)
+ p->readWasFinished = True;
+
+ // res = E_INVALIDARG; // test
+
+ if (res != SZ_OK)
+ {
+ // PRF(printf("\nRead error = %d\n", res))
+ // we want to decode all data before error
+ p->readRes = res;
+ // p->readError_BlockIndex = blockIndex;
+ p->readWasFinished = True;
+ finish = True;
+ res = SZ_OK;
+ // break;
+ }
+
+ if (inDataSize - inPrev >= MTDEC_ProgessStep)
+ {
+ res = MtDec_Progress_GetError_Spec(p, 0, 0, blockIndex, &wasInterrupted);
+ if (res != SZ_OK || wasInterrupted)
+ break;
+ inPrev = inDataSize;
+ }
+ }
+
+ {
+ CMtDecCallbackInfo parse;
+
+ parse.startCall = (prev == NULL);
+ parse.src = parseData;
+ parse.srcSize = size;
+ parse.srcFinished = finish;
+ parse.canCreateNewThread = True;
+
+ PRF(printf("\nParse size = %d\n", (unsigned)size));
+
+ p->mtCallback->Parse(p->mtCallbackObject, t->index, &parse);
+
+ PRF(printf(" Parse processed = %d, state = %d \n", (unsigned)parse.srcSize, (unsigned)parse.state));
+
+ needWrite = True;
+ canCreateNewThread = parse.canCreateNewThread;
+
+ // printf("\n\n%12I64u %12I64u", (UInt64)p->mtProgress.totalInSize, (UInt64)p->mtProgress.totalOutSize);
+
+ if (
+ // parseRes != SZ_OK ||
+ // inDataSize - (size - parse.srcSize) > p->inBlockMax
+ // ||
+ parse.state == MTDEC_PARSE_OVERFLOW
+ // || wasInterrupted
+ )
+ {
+ // Overflow or Parse error - switch from MT decoding to ST decoding
+ finish = True;
+ overflow = True;
+
+ {
+ PRF(printf("\n Overflow"));
+ // PRF(printf("\nisBlockFinished = %d", (unsigned)parse.blockWasFinished));
+ PRF(printf("\n inDataSize = %d", (unsigned)inDataSize));
+ }
+
+ if (crossSize != 0)
+ memcpy(data, parseData, size);
+ p->crossStart = 0;
+ p->crossEnd = 0;
+ break;
+ }
+
+ if (crossSize != 0)
+ {
+ memcpy(data, parseData, parse.srcSize);
+ p->crossStart += parse.srcSize;
+ }
+
+ if (parse.state != MTDEC_PARSE_CONTINUE || finish)
+ {
+ // we don't need to parse in current thread anymore
+
+ if (parse.state == MTDEC_PARSE_END)
+ finish = True;
+
+ needCode = True;
+ // p->crossFinished = finish;
+
+ if (parse.srcSize == size)
+ {
+ // full parsed - no cross transfer
+ p->crossStart = 0;
+ p->crossEnd = 0;
+ break;
+ }
+
+ if (parse.state == MTDEC_PARSE_END)
+ {
+ afterEndData = parseData + parse.srcSize;
+ afterEndData_Size = size - parse.srcSize;
+ if (crossSize != 0)
+ afterEndData_IsCross = True;
+ // we reduce data size to required bytes (parsed only)
+ inDataSize -= afterEndData_Size;
+ if (!prev)
+ inDataSize_Start = parse.srcSize;
+ break;
+ }
+
+ {
+ // partial parsed - need cross transfer
+ if (crossSize != 0)
+ inDataSize = parse.srcSize; // it's only parsed now
+ else
+ {
+ // partial parsed - is not in initial cross block - we need to copy new data to cross block
+ Byte *cr = MtDec_GetCrossBuff(p);
+ if (!cr)
+ {
+ {
+ PRF(printf("\ncross alloc error error\n"));
+ // res = SZ_ERROR_MEM;
+ finish = True;
+ // p->allocError_for_Read_BlockIndex = blockIndex;
+ isAllocError = True;
+ break;
+ }
+ }
+
+ {
+ size_t crSize = size - parse.srcSize;
+ inDataSize -= crSize;
+ p->crossEnd = crSize;
+ p->crossStart = 0;
+ memcpy(cr, parseData + parse.srcSize, crSize);
+ }
+ }
+
+ // inDataSize_Full = inDataSize;
+ if (!prev)
+ inDataSize_Start = parse.srcSize; // it's partial size (parsed only)
+
+ finish = False;
+ break;
+ }
+ }
+
+ if (parse.srcSize != size)
+ {
+ res = SZ_ERROR_FAIL;
+ PRF(printf("\nfinished error SZ_ERROR_FAIL = %d\n", res));
+ break;
+ }
+ }
+ }
+
+ prev = link;
+ link = link->next;
+
+ if (crossSize != 0)
+ {
+ crossSize = 0;
+ p->crossStart = 0;
+ p->crossEnd = 0;
+ }
+ }
+ }
+
+ if (res == SZ_OK)
+ res = MtDec_GetError_Spec(p, blockIndex, &wasInterrupted);
+ }
+
+ codeRes = SZ_OK;
+
+ if (res == SZ_OK && needCode && !wasInterrupted)
+ {
+ codeRes = p->mtCallback->PreCode(p->mtCallbackObject, t->index);
+ if (codeRes != SZ_OK)
+ {
+ needCode = False;
+ finish = True;
+ // SZ_ERROR_MEM is expected error here.
+ // if (codeRes == SZ_ERROR_MEM) - we will try single-thread decoding later.
+ // if (codeRes != SZ_ERROR_MEM) - we can stop decoding or try single-thread decoding.
+ }
+ }
+
+ if (res != SZ_OK || wasInterrupted)
+ finish = True;
+
+ nextThread = NULL;
+ threadingErrorSRes = SZ_OK;
+
+ if (!finish)
+ {
+ if (p->numStartedThreads < p->numStartedThreads_Limit && canCreateNewThread)
+ {
+ SRes res2 = MtDecThread_CreateAndStart(&p->threads[p->numStartedThreads]);
+ if (res2 == SZ_OK)
+ {
+ // if (p->numStartedThreads % 1000 == 0) PRF(printf("\n numStartedThreads=%d\n", p->numStartedThreads));
+ p->numStartedThreads++;
+ }
+ else
+ {
+ PRF(printf("\nERROR: numStartedThreads=%d\n", p->numStartedThreads));
+ if (p->numStartedThreads == 1)
+ {
+ // if only one thread is possible, we leave muti-threading code
+ finish = True;
+ needCode = False;
+ threadingErrorSRes = res2;
+ }
+ else
+ p->numStartedThreads_Limit = p->numStartedThreads;
+ }
+ }
+
+ if (!finish)
+ {
+ unsigned nextIndex = t->index + 1;
+ nextThread = &p->threads[nextIndex >= p->numStartedThreads ? 0 : nextIndex];
+ RINOK_THREAD(Event_Set(&nextThread->canRead))
+ // We have started executing for new iteration (with next thread)
+ // And that next thread now is responsible for possible exit from decoding (threading_code)
+ }
+ }
+
+ // each call of Event_Set(&nextThread->canRead) must be followed by call of Event_Set(&nextThread->canWrite)
+ // if ( !finish ) we must call Event_Set(&nextThread->canWrite) in any case
+ // if ( finish ) we switch to single-thread mode and there are 2 ways at the end of current iteration (current block):
+ // - if (needContinue) after Write(&needContinue), we restore decoding with new iteration
+ // - otherwise we stop decoding and exit from MtDec_ThreadFunc2()
+
+ // Don't change (finish) variable in the further code
+
+
+ // ---------- CODE ----------
+
+ inPrev = 0;
+ outPrev = 0;
+ inCodePos = 0;
+ outCodePos = 0;
+
+ if (res == SZ_OK && needCode && codeRes == SZ_OK)
+ {
+ BoolInt isStartBlock = True;
+ CMtDecBufLink *link = (CMtDecBufLink *)t->inBuf;
+
+ for (;;)
+ {
+ size_t inSize;
+ int stop;
+
+ if (isStartBlock)
+ inSize = inDataSize_Start;
+ else
+ {
+ UInt64 rem = inDataSize - inCodePos;
+ inSize = p->inBufSize;
+ if (inSize > rem)
+ inSize = (size_t)rem;
+ }
+
+ inCodePos += inSize;
+ stop = True;
+
+ codeRes = p->mtCallback->Code(p->mtCallbackObject, t->index,
+ (const Byte *)MTDEC__DATA_PTR_FROM_LINK(link), inSize,
+ (inCodePos == inDataSize), // srcFinished
+ &inCodePos, &outCodePos, &stop);
+
+ if (codeRes != SZ_OK)
+ {
+ PRF(printf("\nCode Interrupt error = %x\n", codeRes));
+ // we interrupt only later blocks
+ MtDec_Interrupt(p, blockIndex);
+ break;
+ }
+
+ if (stop || inCodePos == inDataSize)
+ break;
+
+ {
+ const UInt64 inDelta = inCodePos - inPrev;
+ const UInt64 outDelta = outCodePos - outPrev;
+ if (inDelta >= MTDEC_ProgessStep || outDelta >= MTDEC_ProgessStep)
+ {
+ // Sleep(1);
+ res = MtDec_Progress_GetError_Spec(p, inDelta, outDelta, blockIndex, &wasInterrupted);
+ if (res != SZ_OK || wasInterrupted)
+ break;
+ inPrev = inCodePos;
+ outPrev = outCodePos;
+ }
+ }
+
+ link = link->next;
+ isStartBlock = False;
+ }
+ }
+
+
+ // ---------- WRITE ----------
+
+ RINOK_THREAD(Event_Wait(&t->canWrite))
+
+ {
+ BoolInt isErrorMode = False;
+ BoolInt canRecode = True;
+ BoolInt needWriteToStream = needWrite;
+
+ if (p->exitThread) return 0; // it's never executed in normal cases
+
+ if (p->wasInterrupted)
+ wasInterrupted = True;
+ else
+ {
+ if (codeRes != SZ_OK) // || !needCode // check it !!!
+ {
+ p->wasInterrupted = True;
+ p->codeRes = codeRes;
+ if (codeRes == SZ_ERROR_MEM)
+ isAllocError = True;
+ }
+
+ if (threadingErrorSRes)
+ {
+ p->wasInterrupted = True;
+ p->threadingErrorSRes = threadingErrorSRes;
+ needWriteToStream = False;
+ }
+ if (isAllocError)
+ {
+ p->wasInterrupted = True;
+ p->isAllocError = True;
+ needWriteToStream = False;
+ }
+ if (overflow)
+ {
+ p->wasInterrupted = True;
+ p->overflow = True;
+ needWriteToStream = False;
+ }
+ }
+
+ if (needCode)
+ {
+ if (wasInterrupted)
+ {
+ inCodePos = 0;
+ outCodePos = 0;
+ }
+ {
+ const UInt64 inDelta = inCodePos - inPrev;
+ const UInt64 outDelta = outCodePos - outPrev;
+ // if (inDelta != 0 || outDelta != 0)
+ res = MtProgress_ProgressAdd(&p->mtProgress, inDelta, outDelta);
+ }
+ }
+
+ needContinue = (!finish);
+
+ // if (res == SZ_OK && needWrite && !wasInterrupted)
+ if (needWrite)
+ {
+ // p->inProcessed += inCodePos;
+
+ PRF(printf("\n--Write afterSize = %d\n", (unsigned)afterEndData_Size));
+
+ res = p->mtCallback->Write(p->mtCallbackObject, t->index,
+ res == SZ_OK && needWriteToStream && !wasInterrupted, // needWrite
+ afterEndData, afterEndData_Size, afterEndData_IsCross,
+ &needContinue,
+ &canRecode);
+
+ // res = SZ_ERROR_FAIL; // for test
+
+ PRF(printf("\nAfter Write needContinue = %d\n", (unsigned)needContinue));
+ PRF(printf("\nprocessed = %d\n", (unsigned)p->inProcessed));
+
+ if (res != SZ_OK)
+ {
+ PRF(printf("\nWrite error = %d\n", res));
+ isErrorMode = True;
+ p->wasInterrupted = True;
+ }
+ if (res != SZ_OK
+ || (!needContinue && !finish))
+ {
+ PRF(printf("\nWrite Interrupt error = %x\n", res));
+ MtDec_Interrupt(p, blockIndex);
+ }
+ }
+
+ if (canRecode)
+ if (!needCode
+ || res != SZ_OK
+ || p->wasInterrupted
+ || codeRes != SZ_OK
+ || wasInterrupted
+ || p->numFilledThreads != 0
+ || isErrorMode)
+ {
+ if (p->numFilledThreads == 0)
+ p->filledThreadStart = t->index;
+ if (inDataSize != 0 || !finish)
+ {
+ t->inDataSize_Start = inDataSize_Start;
+ t->inDataSize = inDataSize;
+ p->numFilledThreads++;
+ }
+ PRF(printf("\np->numFilledThreads = %d\n", p->numFilledThreads));
+ PRF(printf("p->filledThreadStart = %d\n", p->filledThreadStart));
+ }
+
+ if (!finish)
+ {
+ RINOK_THREAD(Event_Set(&nextThread->canWrite))
+ }
+ else
+ {
+ if (needContinue)
+ {
+ // we restore decoding with new iteration
+ RINOK_THREAD(Event_Set(&p->threads[0].canWrite))
+ }
+ else
+ {
+ // we exit from decoding
+ if (t->index == 0)
+ return SZ_OK;
+ p->exitThread = True;
+ }
+ RINOK_THREAD(Event_Set(&p->threads[0].canRead))
+ }
+ }
+ }
+}
+
+#ifdef _WIN32
+#define USE_ALLOCA
+#endif
+
+#ifdef USE_ALLOCA
+#ifdef _WIN32
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+#endif
+
+
+static THREAD_FUNC_DECL MtDec_ThreadFunc1(void *pp)
+{
+ WRes res;
+
+ CMtDecThread *t = (CMtDecThread *)pp;
+ CMtDec *p;
+
+ // fprintf(stdout, "\n%d = %p\n", t->index, &t);
+
+ res = MtDec_ThreadFunc2(t);
+ p = t->mtDec;
+ if (res == 0)
+ return (THREAD_FUNC_RET_TYPE)(UINT_PTR)p->exitThreadWRes;
+ {
+ // it's unexpected situation for some threading function error
+ if (p->exitThreadWRes == 0)
+ p->exitThreadWRes = res;
+ PRF(printf("\nthread exit error = %d\n", res));
+ p->exitThread = True;
+ Event_Set(&p->threads[0].canRead);
+ Event_Set(&p->threads[0].canWrite);
+ MtProgress_SetError(&p->mtProgress, MY_SRes_HRESULT_FROM_WRes(res));
+ }
+ return (THREAD_FUNC_RET_TYPE)(UINT_PTR)res;
+}
+
+static Z7_NO_INLINE THREAD_FUNC_DECL MtDec_ThreadFunc(void *pp)
+{
+ #ifdef USE_ALLOCA
+ CMtDecThread *t = (CMtDecThread *)pp;
+ // fprintf(stderr, "\n%d = %p - before", t->index, &t);
+ t->allocaPtr = alloca(t->index * 128);
+ #endif
+ return MtDec_ThreadFunc1(pp);
+}
+
+
+int MtDec_PrepareRead(CMtDec *p)
+{
+ if (p->crossBlock && p->crossStart == p->crossEnd)
+ {
+ ISzAlloc_Free(p->alloc, p->crossBlock);
+ p->crossBlock = NULL;
+ }
+
+ {
+ unsigned i;
+ for (i = 0; i < MTDEC_THREADS_MAX; i++)
+ if (i > p->numStartedThreads
+ || p->numFilledThreads <=
+ (i >= p->filledThreadStart ?
+ i - p->filledThreadStart :
+ i + p->numStartedThreads - p->filledThreadStart))
+ MtDecThread_FreeInBufs(&p->threads[i]);
+ }
+
+ return (p->numFilledThreads != 0) || (p->crossStart != p->crossEnd);
+}
+
+
+const Byte *MtDec_Read(CMtDec *p, size_t *inLim)
+{
+ while (p->numFilledThreads != 0)
+ {
+ CMtDecThread *t = &p->threads[p->filledThreadStart];
+
+ if (*inLim != 0)
+ {
+ {
+ void *link = t->inBuf;
+ void *next = ((CMtDecBufLink *)link)->next;
+ ISzAlloc_Free(p->alloc, link);
+ t->inBuf = next;
+ }
+
+ if (t->inDataSize == 0)
+ {
+ MtDecThread_FreeInBufs(t);
+ if (--p->numFilledThreads == 0)
+ break;
+ if (++p->filledThreadStart == p->numStartedThreads)
+ p->filledThreadStart = 0;
+ t = &p->threads[p->filledThreadStart];
+ }
+ }
+
+ {
+ size_t lim = t->inDataSize_Start;
+ if (lim != 0)
+ t->inDataSize_Start = 0;
+ else
+ {
+ UInt64 rem = t->inDataSize;
+ lim = p->inBufSize;
+ if (lim > rem)
+ lim = (size_t)rem;
+ }
+ t->inDataSize -= lim;
+ *inLim = lim;
+ return (const Byte *)MTDEC__DATA_PTR_FROM_LINK(t->inBuf);
+ }
+ }
+
+ {
+ size_t crossSize = p->crossEnd - p->crossStart;
+ if (crossSize != 0)
+ {
+ const Byte *data = MTDEC__DATA_PTR_FROM_LINK(p->crossBlock) + p->crossStart;
+ *inLim = crossSize;
+ p->crossStart = 0;
+ p->crossEnd = 0;
+ return data;
+ }
+ *inLim = 0;
+ if (p->crossBlock)
+ {
+ ISzAlloc_Free(p->alloc, p->crossBlock);
+ p->crossBlock = NULL;
+ }
+ return NULL;
+ }
+}
+
+
+void MtDec_Construct(CMtDec *p)
+{
+ unsigned i;
+
+ p->inBufSize = (size_t)1 << 18;
+
+ p->numThreadsMax = 0;
+
+ p->inStream = NULL;
+
+ // p->inData = NULL;
+ // p->inDataSize = 0;
+
+ p->crossBlock = NULL;
+ p->crossStart = 0;
+ p->crossEnd = 0;
+
+ p->numFilledThreads = 0;
+
+ p->progress = NULL;
+ p->alloc = NULL;
+
+ p->mtCallback = NULL;
+ p->mtCallbackObject = NULL;
+
+ p->allocatedBufsSize = 0;
+
+ for (i = 0; i < MTDEC_THREADS_MAX; i++)
+ {
+ CMtDecThread *t = &p->threads[i];
+ t->mtDec = p;
+ t->index = i;
+ t->inBuf = NULL;
+ Event_Construct(&t->canRead);
+ Event_Construct(&t->canWrite);
+ Thread_CONSTRUCT(&t->thread)
+ }
+
+ // Event_Construct(&p->finishedEvent);
+
+ CriticalSection_Init(&p->mtProgress.cs);
+}
+
+
+static void MtDec_Free(CMtDec *p)
+{
+ unsigned i;
+
+ p->exitThread = True;
+
+ for (i = 0; i < MTDEC_THREADS_MAX; i++)
+ MtDecThread_Destruct(&p->threads[i]);
+
+ // Event_Close(&p->finishedEvent);
+
+ if (p->crossBlock)
+ {
+ ISzAlloc_Free(p->alloc, p->crossBlock);
+ p->crossBlock = NULL;
+ }
+}
+
+
+void MtDec_Destruct(CMtDec *p)
+{
+ MtDec_Free(p);
+
+ CriticalSection_Delete(&p->mtProgress.cs);
+}
+
+
+SRes MtDec_Code(CMtDec *p)
+{
+ unsigned i;
+
+ p->inProcessed = 0;
+
+ p->blockIndex = 1; // it must be larger than not_defined index (0)
+ p->isAllocError = False;
+ p->overflow = False;
+ p->threadingErrorSRes = SZ_OK;
+
+ p->needContinue = True;
+
+ p->readWasFinished = False;
+ p->needInterrupt = False;
+ p->interruptIndex = (UInt64)(Int64)-1;
+
+ p->readProcessed = 0;
+ p->readRes = SZ_OK;
+ p->codeRes = SZ_OK;
+ p->wasInterrupted = False;
+
+ p->crossStart = 0;
+ p->crossEnd = 0;
+
+ p->filledThreadStart = 0;
+ p->numFilledThreads = 0;
+
+ {
+ unsigned numThreads = p->numThreadsMax;
+ if (numThreads > MTDEC_THREADS_MAX)
+ numThreads = MTDEC_THREADS_MAX;
+ p->numStartedThreads_Limit = numThreads;
+ p->numStartedThreads = 0;
+ }
+
+ if (p->inBufSize != p->allocatedBufsSize)
+ {
+ for (i = 0; i < MTDEC_THREADS_MAX; i++)
+ {
+ CMtDecThread *t = &p->threads[i];
+ if (t->inBuf)
+ MtDecThread_FreeInBufs(t);
+ }
+ if (p->crossBlock)
+ {
+ ISzAlloc_Free(p->alloc, p->crossBlock);
+ p->crossBlock = NULL;
+ }
+
+ p->allocatedBufsSize = p->inBufSize;
+ }
+
+ MtProgress_Init(&p->mtProgress, p->progress);
+
+ // RINOK_THREAD(AutoResetEvent_OptCreate_And_Reset(&p->finishedEvent))
+ p->exitThread = False;
+ p->exitThreadWRes = 0;
+
+ {
+ WRes wres;
+ SRes sres;
+ CMtDecThread *nextThread = &p->threads[p->numStartedThreads++];
+ // wres = MtDecThread_CreateAndStart(nextThread);
+ wres = MtDecThread_CreateEvents(nextThread);
+ if (wres == 0) { wres = Event_Set(&nextThread->canWrite);
+ if (wres == 0) { wres = Event_Set(&nextThread->canRead);
+ if (wres == 0) { THREAD_FUNC_RET_TYPE res = MtDec_ThreadFunc(nextThread);
+ wres = (WRes)(UINT_PTR)res;
+ if (wres != 0)
+ {
+ p->needContinue = False;
+ MtDec_CloseThreads(p);
+ }}}}
+
+ // wres = 17; // for test
+ // wres = Event_Wait(&p->finishedEvent);
+
+ sres = MY_SRes_HRESULT_FROM_WRes(wres);
+
+ if (sres != 0)
+ p->threadingErrorSRes = sres;
+
+ if (
+ // wres == 0
+ // wres != 0
+ // || p->mtc.codeRes == SZ_ERROR_MEM
+ p->isAllocError
+ || p->threadingErrorSRes != SZ_OK
+ || p->overflow)
+ {
+ // p->needContinue = True;
+ }
+ else
+ p->needContinue = False;
+
+ if (p->needContinue)
+ return SZ_OK;
+
+ // if (sres != SZ_OK)
+ return sres;
+ // return SZ_ERROR_FAIL;
+ }
+}
+
+#endif
+
+#undef PRF
diff --git a/C/MtDec.h b/C/MtDec.h
index 9864cc8..c28e8d9 100644
--- a/C/MtDec.h
+++ b/C/MtDec.h
@@ -1,201 +1,202 @@
-/* MtDec.h -- Multi-thread Decoder
-2018-07-04 : Igor Pavlov : Public domain */
-
-#ifndef __MT_DEC_H
-#define __MT_DEC_H
-
-#include "7zTypes.h"
-
-#ifndef _7ZIP_ST
-#include "Threads.h"
-#endif
-
-EXTERN_C_BEGIN
-
-#ifndef _7ZIP_ST
-
-#ifndef _7ZIP_ST
- #define MTDEC__THREADS_MAX 32
-#else
- #define MTDEC__THREADS_MAX 1
-#endif
-
-
-typedef struct
-{
- ICompressProgress *progress;
- SRes res;
- UInt64 totalInSize;
- UInt64 totalOutSize;
- CCriticalSection cs;
-} CMtProgress;
-
-void MtProgress_Init(CMtProgress *p, ICompressProgress *progress);
-SRes MtProgress_Progress_ST(CMtProgress *p);
-SRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize);
-SRes MtProgress_GetError(CMtProgress *p);
-void MtProgress_SetError(CMtProgress *p, SRes res);
-
-struct _CMtDec;
-
-typedef struct
-{
- struct _CMtDec *mtDec;
- unsigned index;
- void *inBuf;
-
- size_t inDataSize_Start; // size of input data in start block
- UInt64 inDataSize; // total size of input data in all blocks
-
- CThread thread;
- CAutoResetEvent canRead;
- CAutoResetEvent canWrite;
- void *allocaPtr;
-} CMtDecThread;
-
-void MtDecThread_FreeInBufs(CMtDecThread *t);
-
-
-typedef enum
-{
- MTDEC_PARSE_CONTINUE, // continue this block with more input data
- MTDEC_PARSE_OVERFLOW, // MT buffers overflow, need switch to single-thread
- MTDEC_PARSE_NEW, // new block
- MTDEC_PARSE_END // end of block threading. But we still can return to threading after Write(&needContinue)
-} EMtDecParseState;
-
-typedef struct
-{
- // in
- int startCall;
- const Byte *src;
- size_t srcSize;
- // in : (srcSize == 0) is allowed
- // out : it's allowed to return less that actually was used ?
- int srcFinished;
-
- // out
- EMtDecParseState state;
- BoolInt canCreateNewThread;
- UInt64 outPos; // check it (size_t)
-} CMtDecCallbackInfo;
-
-
-typedef struct
-{
- void (*Parse)(void *p, unsigned coderIndex, CMtDecCallbackInfo *ci);
-
- // PreCode() and Code():
- // (SRes_return_result != SZ_OK) means stop decoding, no need another blocks
- SRes (*PreCode)(void *p, unsigned coderIndex);
- SRes (*Code)(void *p, unsigned coderIndex,
- const Byte *src, size_t srcSize, int srcFinished,
- UInt64 *inCodePos, UInt64 *outCodePos, int *stop);
- // stop - means stop another Code calls
-
-
- /* Write() must be called, if Parse() was called
- set (needWrite) if
- {
- && (was not interrupted by progress)
- && (was not interrupted in previous block)
- }
-
- out:
- if (*needContinue), decoder still need to continue decoding with new iteration,
- even after MTDEC_PARSE_END
- if (*canRecode), we didn't flush current block data, so we still can decode current block later.
- */
- SRes (*Write)(void *p, unsigned coderIndex,
- BoolInt needWriteToStream,
- const Byte *src, size_t srcSize,
- // int srcFinished,
- BoolInt *needContinue,
- BoolInt *canRecode);
-} IMtDecCallback;
-
-
-
-typedef struct _CMtDec
-{
- /* input variables */
-
- size_t inBufSize; /* size of input block */
- unsigned numThreadsMax;
- // size_t inBlockMax;
- unsigned numThreadsMax_2;
-
- ISeqInStream *inStream;
- // const Byte *inData;
- // size_t inDataSize;
-
- ICompressProgress *progress;
- ISzAllocPtr alloc;
-
- IMtDecCallback *mtCallback;
- void *mtCallbackObject;
-
-
- /* internal variables */
-
- size_t allocatedBufsSize;
-
- BoolInt exitThread;
- WRes exitThreadWRes;
-
- UInt64 blockIndex;
- BoolInt isAllocError;
- BoolInt overflow;
- SRes threadingErrorSRes;
-
- BoolInt needContinue;
-
- // CAutoResetEvent finishedEvent;
-
- SRes readRes;
- SRes codeRes;
-
- BoolInt wasInterrupted;
-
- unsigned numStartedThreads_Limit;
- unsigned numStartedThreads;
-
- Byte *crossBlock;
- size_t crossStart;
- size_t crossEnd;
- UInt64 readProcessed;
- BoolInt readWasFinished;
- UInt64 inProcessed;
-
- unsigned filledThreadStart;
- unsigned numFilledThreads;
-
- #ifndef _7ZIP_ST
- BoolInt needInterrupt;
- UInt64 interruptIndex;
- CMtProgress mtProgress;
- CMtDecThread threads[MTDEC__THREADS_MAX];
- #endif
-} CMtDec;
-
-
-void MtDec_Construct(CMtDec *p);
-void MtDec_Destruct(CMtDec *p);
-
-/*
-MtDec_Code() returns:
- SZ_OK - in most cases
- MY_SRes_HRESULT_FROM_WRes(WRes_error) - in case of unexpected error in threading function
-*/
-
-SRes MtDec_Code(CMtDec *p);
-Byte *MtDec_GetCrossBuff(CMtDec *p);
-
-int MtDec_PrepareRead(CMtDec *p);
-const Byte *MtDec_Read(CMtDec *p, size_t *inLim);
-
-#endif
-
-EXTERN_C_END
-
-#endif
+/* MtDec.h -- Multi-thread Decoder
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_MT_DEC_H
+#define ZIP7_INC_MT_DEC_H
+
+#include "7zTypes.h"
+
+#ifndef Z7_ST
+#include "Threads.h"
+#endif
+
+EXTERN_C_BEGIN
+
+#ifndef Z7_ST
+
+#ifndef Z7_ST
+ #define MTDEC_THREADS_MAX 32
+#else
+ #define MTDEC_THREADS_MAX 1
+#endif
+
+
+typedef struct
+{
+ ICompressProgressPtr progress;
+ SRes res;
+ UInt64 totalInSize;
+ UInt64 totalOutSize;
+ CCriticalSection cs;
+} CMtProgress;
+
+void MtProgress_Init(CMtProgress *p, ICompressProgressPtr progress);
+SRes MtProgress_Progress_ST(CMtProgress *p);
+SRes MtProgress_ProgressAdd(CMtProgress *p, UInt64 inSize, UInt64 outSize);
+SRes MtProgress_GetError(CMtProgress *p);
+void MtProgress_SetError(CMtProgress *p, SRes res);
+
+struct CMtDec;
+
+typedef struct
+{
+ struct CMtDec_ *mtDec;
+ unsigned index;
+ void *inBuf;
+
+ size_t inDataSize_Start; // size of input data in start block
+ UInt64 inDataSize; // total size of input data in all blocks
+
+ CThread thread;
+ CAutoResetEvent canRead;
+ CAutoResetEvent canWrite;
+ void *allocaPtr;
+} CMtDecThread;
+
+void MtDecThread_FreeInBufs(CMtDecThread *t);
+
+
+typedef enum
+{
+ MTDEC_PARSE_CONTINUE, // continue this block with more input data
+ MTDEC_PARSE_OVERFLOW, // MT buffers overflow, need switch to single-thread
+ MTDEC_PARSE_NEW, // new block
+ MTDEC_PARSE_END // end of block threading. But we still can return to threading after Write(&needContinue)
+} EMtDecParseState;
+
+typedef struct
+{
+ // in
+ int startCall;
+ const Byte *src;
+ size_t srcSize;
+ // in : (srcSize == 0) is allowed
+ // out : it's allowed to return less that actually was used ?
+ int srcFinished;
+
+ // out
+ EMtDecParseState state;
+ BoolInt canCreateNewThread;
+ UInt64 outPos; // check it (size_t)
+} CMtDecCallbackInfo;
+
+
+typedef struct
+{
+ void (*Parse)(void *p, unsigned coderIndex, CMtDecCallbackInfo *ci);
+
+ // PreCode() and Code():
+ // (SRes_return_result != SZ_OK) means stop decoding, no need another blocks
+ SRes (*PreCode)(void *p, unsigned coderIndex);
+ SRes (*Code)(void *p, unsigned coderIndex,
+ const Byte *src, size_t srcSize, int srcFinished,
+ UInt64 *inCodePos, UInt64 *outCodePos, int *stop);
+ // stop - means stop another Code calls
+
+
+ /* Write() must be called, if Parse() was called
+ set (needWrite) if
+ {
+ && (was not interrupted by progress)
+ && (was not interrupted in previous block)
+ }
+
+ out:
+ if (*needContinue), decoder still need to continue decoding with new iteration,
+ even after MTDEC_PARSE_END
+ if (*canRecode), we didn't flush current block data, so we still can decode current block later.
+ */
+ SRes (*Write)(void *p, unsigned coderIndex,
+ BoolInt needWriteToStream,
+ const Byte *src, size_t srcSize, BoolInt isCross,
+ // int srcFinished,
+ BoolInt *needContinue,
+ BoolInt *canRecode);
+
+} IMtDecCallback2;
+
+
+
+typedef struct CMtDec_
+{
+ /* input variables */
+
+ size_t inBufSize; /* size of input block */
+ unsigned numThreadsMax;
+ // size_t inBlockMax;
+ unsigned numThreadsMax_2;
+
+ ISeqInStreamPtr inStream;
+ // const Byte *inData;
+ // size_t inDataSize;
+
+ ICompressProgressPtr progress;
+ ISzAllocPtr alloc;
+
+ IMtDecCallback2 *mtCallback;
+ void *mtCallbackObject;
+
+
+ /* internal variables */
+
+ size_t allocatedBufsSize;
+
+ BoolInt exitThread;
+ WRes exitThreadWRes;
+
+ UInt64 blockIndex;
+ BoolInt isAllocError;
+ BoolInt overflow;
+ SRes threadingErrorSRes;
+
+ BoolInt needContinue;
+
+ // CAutoResetEvent finishedEvent;
+
+ SRes readRes;
+ SRes codeRes;
+
+ BoolInt wasInterrupted;
+
+ unsigned numStartedThreads_Limit;
+ unsigned numStartedThreads;
+
+ Byte *crossBlock;
+ size_t crossStart;
+ size_t crossEnd;
+ UInt64 readProcessed;
+ BoolInt readWasFinished;
+ UInt64 inProcessed;
+
+ unsigned filledThreadStart;
+ unsigned numFilledThreads;
+
+ #ifndef Z7_ST
+ BoolInt needInterrupt;
+ UInt64 interruptIndex;
+ CMtProgress mtProgress;
+ CMtDecThread threads[MTDEC_THREADS_MAX];
+ #endif
+} CMtDec;
+
+
+void MtDec_Construct(CMtDec *p);
+void MtDec_Destruct(CMtDec *p);
+
+/*
+MtDec_Code() returns:
+ SZ_OK - in most cases
+ MY_SRes_HRESULT_FROM_WRes(WRes_error) - in case of unexpected error in threading function
+*/
+
+SRes MtDec_Code(CMtDec *p);
+Byte *MtDec_GetCrossBuff(CMtDec *p);
+
+int MtDec_PrepareRead(CMtDec *p);
+const Byte *MtDec_Read(CMtDec *p, size_t *inLim);
+
+#endif
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Ppmd.h b/C/Ppmd.h
index 4b99415..66b2626 100644
--- a/C/Ppmd.h
+++ b/C/Ppmd.h
@@ -1,85 +1,169 @@
-/* Ppmd.h -- PPMD codec common code
-2017-04-03 : Igor Pavlov : Public domain
-This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
-
-#ifndef __PPMD_H
-#define __PPMD_H
-
-#include "CpuArch.h"
-
-EXTERN_C_BEGIN
-
-#ifdef MY_CPU_32BIT
- #define PPMD_32BIT
-#endif
-
-#define PPMD_INT_BITS 7
-#define PPMD_PERIOD_BITS 7
-#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS))
-
-#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift))
-#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2)
-#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob))
-#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob))
-
-#define PPMD_N1 4
-#define PPMD_N2 4
-#define PPMD_N3 4
-#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4)
-#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4)
-
-#pragma pack(push, 1)
-/* Most compilers works OK here even without #pragma pack(push, 1), but some GCC compilers need it. */
-
-/* SEE-contexts for PPM-contexts with masked symbols */
-typedef struct
-{
- UInt16 Summ; /* Freq */
- Byte Shift; /* Speed of Freq change; low Shift is for fast change */
- Byte Count; /* Count to next change of Shift */
-} CPpmd_See;
-
-#define Ppmd_See_Update(p) if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \
- { (p)->Summ <<= 1; (p)->Count = (Byte)(3 << (p)->Shift++); }
-
-typedef struct
-{
- Byte Symbol;
- Byte Freq;
- UInt16 SuccessorLow;
- UInt16 SuccessorHigh;
-} CPpmd_State;
-
-#pragma pack(pop)
-
-typedef
- #ifdef PPMD_32BIT
- CPpmd_State *
- #else
- UInt32
- #endif
- CPpmd_State_Ref;
-
-typedef
- #ifdef PPMD_32BIT
- void *
- #else
- UInt32
- #endif
- CPpmd_Void_Ref;
-
-typedef
- #ifdef PPMD_32BIT
- Byte *
- #else
- UInt32
- #endif
- CPpmd_Byte_Ref;
-
-#define PPMD_SetAllBitsIn256Bytes(p) \
- { size_t z; for (z = 0; z < 256 / sizeof(p[0]); z += 8) { \
- p[z+7] = p[z+6] = p[z+5] = p[z+4] = p[z+3] = p[z+2] = p[z+1] = p[z+0] = ~(size_t)0; }}
-
-EXTERN_C_END
-
-#endif
+/* Ppmd.h -- PPMD codec common code
+2023-03-05 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#ifndef ZIP7_INC_PPMD_H
+#define ZIP7_INC_PPMD_H
+
+#include "CpuArch.h"
+
+EXTERN_C_BEGIN
+
+#if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4)
+/*
+ PPMD code always uses 32-bit internal fields in PPMD structures to store internal references in main block.
+ if (PPMD_32BIT is defined), the PPMD code stores internal pointers to 32-bit reference fields.
+ if (PPMD_32BIT is NOT defined), the PPMD code stores internal UInt32 offsets to reference fields.
+ if (pointer size is 64-bit), then (PPMD_32BIT) mode is not allowed,
+ if (pointer size is 32-bit), then (PPMD_32BIT) mode is optional,
+ and it's allowed to disable PPMD_32BIT mode even if pointer is 32-bit.
+ PPMD code works slightly faster in (PPMD_32BIT) mode.
+*/
+ #define PPMD_32BIT
+#endif
+
+#define PPMD_INT_BITS 7
+#define PPMD_PERIOD_BITS 7
+#define PPMD_BIN_SCALE (1 << (PPMD_INT_BITS + PPMD_PERIOD_BITS))
+
+#define PPMD_GET_MEAN_SPEC(summ, shift, round) (((summ) + (1 << ((shift) - (round)))) >> (shift))
+#define PPMD_GET_MEAN(summ) PPMD_GET_MEAN_SPEC((summ), PPMD_PERIOD_BITS, 2)
+#define PPMD_UPDATE_PROB_0(prob) ((prob) + (1 << PPMD_INT_BITS) - PPMD_GET_MEAN(prob))
+#define PPMD_UPDATE_PROB_1(prob) ((prob) - PPMD_GET_MEAN(prob))
+
+#define PPMD_N1 4
+#define PPMD_N2 4
+#define PPMD_N3 4
+#define PPMD_N4 ((128 + 3 - 1 * PPMD_N1 - 2 * PPMD_N2 - 3 * PPMD_N3) / 4)
+#define PPMD_NUM_INDEXES (PPMD_N1 + PPMD_N2 + PPMD_N3 + PPMD_N4)
+
+MY_CPU_pragma_pack_push_1
+/* Most compilers works OK here even without #pragma pack(push, 1), but some GCC compilers need it. */
+
+/* SEE-contexts for PPM-contexts with masked symbols */
+typedef struct
+{
+ UInt16 Summ; /* Freq */
+ Byte Shift; /* Speed of Freq change; low Shift is for fast change */
+ Byte Count; /* Count to next change of Shift */
+} CPpmd_See;
+
+#define Ppmd_See_UPDATE(p) \
+ { if ((p)->Shift < PPMD_PERIOD_BITS && --(p)->Count == 0) \
+ { (p)->Summ = (UInt16)((p)->Summ << 1); \
+ (p)->Count = (Byte)(3 << (p)->Shift++); }}
+
+
+typedef struct
+{
+ Byte Symbol;
+ Byte Freq;
+ UInt16 Successor_0;
+ UInt16 Successor_1;
+} CPpmd_State;
+
+typedef struct CPpmd_State2_
+{
+ Byte Symbol;
+ Byte Freq;
+} CPpmd_State2;
+
+typedef struct CPpmd_State4_
+{
+ UInt16 Successor_0;
+ UInt16 Successor_1;
+} CPpmd_State4;
+
+MY_CPU_pragma_pop
+
+/*
+ PPMD code can write full CPpmd_State structure data to CPpmd*_Context
+ at (byte offset = 2) instead of some fields of original CPpmd*_Context structure.
+
+ If we use pointers to different types, but that point to shared
+ memory space, we can have aliasing problem (strict aliasing).
+
+ XLC compiler in -O2 mode can change the order of memory write instructions
+ in relation to read instructions, if we have use pointers to different types.
+
+ To solve that aliasing problem we use combined CPpmd*_Context structure
+ with unions that contain the fields from both structures:
+ the original CPpmd*_Context and CPpmd_State.
+ So we can access the fields from both structures via one pointer,
+ and the compiler doesn't change the order of write instructions
+ in relation to read instructions.
+
+ If we don't use memory write instructions to shared memory in
+ some local code, and we use only reading instructions (read only),
+ then probably it's safe to use pointers to different types for reading.
+*/
+
+
+
+#ifdef PPMD_32BIT
+
+ #define Ppmd_Ref_Type(type) type *
+ #define Ppmd_GetRef(p, ptr) (ptr)
+ #define Ppmd_GetPtr(p, ptr) (ptr)
+ #define Ppmd_GetPtr_Type(p, ptr, note_type) (ptr)
+
+#else
+
+ #define Ppmd_Ref_Type(type) UInt32
+ #define Ppmd_GetRef(p, ptr) ((UInt32)((Byte *)(ptr) - (p)->Base))
+ #define Ppmd_GetPtr(p, offs) ((void *)((p)->Base + (offs)))
+ #define Ppmd_GetPtr_Type(p, offs, type) ((type *)Ppmd_GetPtr(p, offs))
+
+#endif // PPMD_32BIT
+
+
+typedef Ppmd_Ref_Type(CPpmd_State) CPpmd_State_Ref;
+typedef Ppmd_Ref_Type(void) CPpmd_Void_Ref;
+typedef Ppmd_Ref_Type(Byte) CPpmd_Byte_Ref;
+
+
+/*
+#ifdef MY_CPU_LE_UNALIGN
+// the unaligned 32-bit access latency can be too large, if the data is not in L1 cache.
+#define Ppmd_GET_SUCCESSOR(p) ((CPpmd_Void_Ref)*(const UInt32 *)(const void *)&(p)->Successor_0)
+#define Ppmd_SET_SUCCESSOR(p, v) *(UInt32 *)(void *)(void *)&(p)->Successor_0 = (UInt32)(v)
+
+#else
+*/
+
+/*
+ We can write 16-bit halves to 32-bit (Successor) field in any selected order.
+ But the native order is more consistent way.
+ So we use the native order, if LE/BE order can be detected here at compile time.
+*/
+
+#ifdef MY_CPU_BE
+
+ #define Ppmd_GET_SUCCESSOR(p) \
+ ( (CPpmd_Void_Ref) (((UInt32)(p)->Successor_0 << 16) | (p)->Successor_1) )
+
+ #define Ppmd_SET_SUCCESSOR(p, v) { \
+ (p)->Successor_0 = (UInt16)(((UInt32)(v) >> 16) /* & 0xFFFF */); \
+ (p)->Successor_1 = (UInt16)((UInt32)(v) /* & 0xFFFF */); }
+
+#else
+
+ #define Ppmd_GET_SUCCESSOR(p) \
+ ( (CPpmd_Void_Ref) ((p)->Successor_0 | ((UInt32)(p)->Successor_1 << 16)) )
+
+ #define Ppmd_SET_SUCCESSOR(p, v) { \
+ (p)->Successor_0 = (UInt16)((UInt32)(v) /* & 0xFFFF */); \
+ (p)->Successor_1 = (UInt16)(((UInt32)(v) >> 16) /* & 0xFFFF */); }
+
+#endif
+
+// #endif
+
+
+#define PPMD_SetAllBitsIn256Bytes(p) \
+ { size_t z; for (z = 0; z < 256 / sizeof(p[0]); z += 8) { \
+ p[z+7] = p[z+6] = p[z+5] = p[z+4] = p[z+3] = p[z+2] = p[z+1] = p[z+0] = ~(size_t)0; }}
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Ppmd7.c b/C/Ppmd7.c
index 80e7de9..6e1307e 100644
--- a/C/Ppmd7.c
+++ b/C/Ppmd7.c
@@ -1,712 +1,1122 @@
-/* Ppmd7.c -- PPMdH codec
-2018-07-04 : Igor Pavlov : Public domain
-This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
-
-#include "Precomp.h"
-
-#include <string.h>
-
-#include "Ppmd7.h"
-
-const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
-static const UInt16 kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};
-
-#define MAX_FREQ 124
-#define UNIT_SIZE 12
-
-#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE)
-#define U2I(nu) (p->Units2Indx[(size_t)(nu) - 1])
-#define I2U(indx) (p->Indx2Units[indx])
-
-#ifdef PPMD_32BIT
- #define REF(ptr) (ptr)
-#else
- #define REF(ptr) ((UInt32)((Byte *)(ptr) - (p)->Base))
-#endif
-
-#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr))
-
-#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref))
-#define STATS(ctx) Ppmd7_GetStats(p, ctx)
-#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx)
-#define SUFFIX(ctx) CTX((ctx)->Suffix)
-
-typedef CPpmd7_Context * CTX_PTR;
-
-struct CPpmd7_Node_;
-
-typedef
- #ifdef PPMD_32BIT
- struct CPpmd7_Node_ *
- #else
- UInt32
- #endif
- CPpmd7_Node_Ref;
-
-typedef struct CPpmd7_Node_
-{
- UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */
- UInt16 NU;
- CPpmd7_Node_Ref Next; /* must be at offset >= 4 */
- CPpmd7_Node_Ref Prev;
-} CPpmd7_Node;
-
-#ifdef PPMD_32BIT
- #define NODE(ptr) (ptr)
-#else
- #define NODE(offs) ((CPpmd7_Node *)(p->Base + (offs)))
-#endif
-
-void Ppmd7_Construct(CPpmd7 *p)
-{
- unsigned i, k, m;
-
- p->Base = 0;
-
- for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++)
- {
- unsigned step = (i >= 12 ? 4 : (i >> 2) + 1);
- do { p->Units2Indx[k++] = (Byte)i; } while (--step);
- p->Indx2Units[i] = (Byte)k;
- }
-
- p->NS2BSIndx[0] = (0 << 1);
- p->NS2BSIndx[1] = (1 << 1);
- memset(p->NS2BSIndx + 2, (2 << 1), 9);
- memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11);
-
- for (i = 0; i < 3; i++)
- p->NS2Indx[i] = (Byte)i;
- for (m = i, k = 1; i < 256; i++)
- {
- p->NS2Indx[i] = (Byte)m;
- if (--k == 0)
- k = (++m) - 2;
- }
-
- memset(p->HB2Flag, 0, 0x40);
- memset(p->HB2Flag + 0x40, 8, 0x100 - 0x40);
-}
-
-void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc)
-{
- ISzAlloc_Free(alloc, p->Base);
- p->Size = 0;
- p->Base = 0;
-}
-
-BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc)
-{
- if (!p->Base || p->Size != size)
- {
- size_t size2;
- Ppmd7_Free(p, alloc);
- size2 = 0
- #ifndef PPMD_32BIT
- + UNIT_SIZE
- #endif
- ;
- p->AlignOffset =
- #ifdef PPMD_32BIT
- (4 - size) & 3;
- #else
- 4 - (size & 3);
- #endif
- if ((p->Base = (Byte *)ISzAlloc_Alloc(alloc, p->AlignOffset + size + size2)) == 0)
- return False;
- p->Size = size;
- }
- return True;
-}
-
-static void InsertNode(CPpmd7 *p, void *node, unsigned indx)
-{
- *((CPpmd_Void_Ref *)node) = p->FreeList[indx];
- p->FreeList[indx] = REF(node);
-}
-
-static void *RemoveNode(CPpmd7 *p, unsigned indx)
-{
- CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]);
- p->FreeList[indx] = *node;
- return node;
-}
-
-static void SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx)
-{
- unsigned i, nu = I2U(oldIndx) - I2U(newIndx);
- ptr = (Byte *)ptr + U2B(I2U(newIndx));
- if (I2U(i = U2I(nu)) != nu)
- {
- unsigned k = I2U(--i);
- InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1);
- }
- InsertNode(p, ptr, i);
-}
-
-static void GlueFreeBlocks(CPpmd7 *p)
-{
- #ifdef PPMD_32BIT
- CPpmd7_Node headItem;
- CPpmd7_Node_Ref head = &headItem;
- #else
- CPpmd7_Node_Ref head = p->AlignOffset + p->Size;
- #endif
-
- CPpmd7_Node_Ref n = head;
- unsigned i;
-
- p->GlueCount = 255;
-
- /* create doubly-linked list of free blocks */
- for (i = 0; i < PPMD_NUM_INDEXES; i++)
- {
- UInt16 nu = I2U(i);
- CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i];
- p->FreeList[i] = 0;
- while (next != 0)
- {
- CPpmd7_Node *node = NODE(next);
- node->Next = n;
- n = NODE(n)->Prev = next;
- next = *(const CPpmd7_Node_Ref *)node;
- node->Stamp = 0;
- node->NU = (UInt16)nu;
- }
- }
- NODE(head)->Stamp = 1;
- NODE(head)->Next = n;
- NODE(n)->Prev = head;
- if (p->LoUnit != p->HiUnit)
- ((CPpmd7_Node *)p->LoUnit)->Stamp = 1;
-
- /* Glue free blocks */
- while (n != head)
- {
- CPpmd7_Node *node = NODE(n);
- UInt32 nu = (UInt32)node->NU;
- for (;;)
- {
- CPpmd7_Node *node2 = NODE(n) + nu;
- nu += node2->NU;
- if (node2->Stamp != 0 || nu >= 0x10000)
- break;
- NODE(node2->Prev)->Next = node2->Next;
- NODE(node2->Next)->Prev = node2->Prev;
- node->NU = (UInt16)nu;
- }
- n = node->Next;
- }
-
- /* Fill lists of free blocks */
- for (n = NODE(head)->Next; n != head;)
- {
- CPpmd7_Node *node = NODE(n);
- unsigned nu;
- CPpmd7_Node_Ref next = node->Next;
- for (nu = node->NU; nu > 128; nu -= 128, node += 128)
- InsertNode(p, node, PPMD_NUM_INDEXES - 1);
- if (I2U(i = U2I(nu)) != nu)
- {
- unsigned k = I2U(--i);
- InsertNode(p, node + k, nu - k - 1);
- }
- InsertNode(p, node, i);
- n = next;
- }
-}
-
-static void *AllocUnitsRare(CPpmd7 *p, unsigned indx)
-{
- unsigned i;
- void *retVal;
- if (p->GlueCount == 0)
- {
- GlueFreeBlocks(p);
- if (p->FreeList[indx] != 0)
- return RemoveNode(p, indx);
- }
- i = indx;
- do
- {
- if (++i == PPMD_NUM_INDEXES)
- {
- UInt32 numBytes = U2B(I2U(indx));
- p->GlueCount--;
- return ((UInt32)(p->UnitsStart - p->Text) > numBytes) ? (p->UnitsStart -= numBytes) : (NULL);
- }
- }
- while (p->FreeList[i] == 0);
- retVal = RemoveNode(p, i);
- SplitBlock(p, retVal, i, indx);
- return retVal;
-}
-
-static void *AllocUnits(CPpmd7 *p, unsigned indx)
-{
- UInt32 numBytes;
- if (p->FreeList[indx] != 0)
- return RemoveNode(p, indx);
- numBytes = U2B(I2U(indx));
- if (numBytes <= (UInt32)(p->HiUnit - p->LoUnit))
- {
- void *retVal = p->LoUnit;
- p->LoUnit += numBytes;
- return retVal;
- }
- return AllocUnitsRare(p, indx);
-}
-
-#define MyMem12Cpy(dest, src, num) \
- { UInt32 *d = (UInt32 *)dest; const UInt32 *s = (const UInt32 *)src; UInt32 n = num; \
- do { d[0] = s[0]; d[1] = s[1]; d[2] = s[2]; s += 3; d += 3; } while (--n); }
-
-static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU)
-{
- unsigned i0 = U2I(oldNU);
- unsigned i1 = U2I(newNU);
- if (i0 == i1)
- return oldPtr;
- if (p->FreeList[i1] != 0)
- {
- void *ptr = RemoveNode(p, i1);
- MyMem12Cpy(ptr, oldPtr, newNU);
- InsertNode(p, oldPtr, i0);
- return ptr;
- }
- SplitBlock(p, oldPtr, i0, i1);
- return oldPtr;
-}
-
-#define SUCCESSOR(p) ((CPpmd_Void_Ref)((p)->SuccessorLow | ((UInt32)(p)->SuccessorHigh << 16)))
-
-static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)
-{
- (p)->SuccessorLow = (UInt16)((UInt32)(v) & 0xFFFF);
- (p)->SuccessorHigh = (UInt16)(((UInt32)(v) >> 16) & 0xFFFF);
-}
-
-static void RestartModel(CPpmd7 *p)
-{
- unsigned i, k, m;
-
- memset(p->FreeList, 0, sizeof(p->FreeList));
- p->Text = p->Base + p->AlignOffset;
- p->HiUnit = p->Text + p->Size;
- p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE;
- p->GlueCount = 0;
-
- p->OrderFall = p->MaxOrder;
- p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1;
- p->PrevSuccess = 0;
-
- p->MinContext = p->MaxContext = (CTX_PTR)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */
- p->MinContext->Suffix = 0;
- p->MinContext->NumStats = 256;
- p->MinContext->SummFreq = 256 + 1;
- p->FoundState = (CPpmd_State *)p->LoUnit; /* AllocUnits(p, PPMD_NUM_INDEXES - 1); */
- p->LoUnit += U2B(256 / 2);
- p->MinContext->Stats = REF(p->FoundState);
- for (i = 0; i < 256; i++)
- {
- CPpmd_State *s = &p->FoundState[i];
- s->Symbol = (Byte)i;
- s->Freq = 1;
- SetSuccessor(s, 0);
- }
-
- for (i = 0; i < 128; i++)
- for (k = 0; k < 8; k++)
- {
- UInt16 *dest = p->BinSumm[i] + k;
- UInt16 val = (UInt16)(PPMD_BIN_SCALE - kInitBinEsc[k] / (i + 2));
- for (m = 0; m < 64; m += 8)
- dest[m] = val;
- }
-
- for (i = 0; i < 25; i++)
- for (k = 0; k < 16; k++)
- {
- CPpmd_See *s = &p->See[i][k];
- s->Summ = (UInt16)((5 * i + 10) << (s->Shift = PPMD_PERIOD_BITS - 4));
- s->Count = 4;
- }
-}
-
-void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder)
-{
- p->MaxOrder = maxOrder;
- RestartModel(p);
- p->DummySee.Shift = PPMD_PERIOD_BITS;
- p->DummySee.Summ = 0; /* unused */
- p->DummySee.Count = 64; /* unused */
-}
-
-static CTX_PTR CreateSuccessors(CPpmd7 *p, BoolInt skip)
-{
- CPpmd_State upState;
- CTX_PTR c = p->MinContext;
- CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState);
- CPpmd_State *ps[PPMD7_MAX_ORDER];
- unsigned numPs = 0;
-
- if (!skip)
- ps[numPs++] = p->FoundState;
-
- while (c->Suffix)
- {
- CPpmd_Void_Ref successor;
- CPpmd_State *s;
- c = SUFFIX(c);
- if (c->NumStats != 1)
- {
- for (s = STATS(c); s->Symbol != p->FoundState->Symbol; s++);
- }
- else
- s = ONE_STATE(c);
- successor = SUCCESSOR(s);
- if (successor != upBranch)
- {
- c = CTX(successor);
- if (numPs == 0)
- return c;
- break;
- }
- ps[numPs++] = s;
- }
-
- upState.Symbol = *(const Byte *)Ppmd7_GetPtr(p, upBranch);
- SetSuccessor(&upState, upBranch + 1);
-
- if (c->NumStats == 1)
- upState.Freq = ONE_STATE(c)->Freq;
- else
- {
- UInt32 cf, s0;
- CPpmd_State *s;
- for (s = STATS(c); s->Symbol != upState.Symbol; s++);
- cf = s->Freq - 1;
- s0 = c->SummFreq - c->NumStats - cf;
- upState.Freq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((2 * cf + 3 * s0 - 1) / (2 * s0))));
- }
-
- do
- {
- /* Create Child */
- CTX_PTR c1; /* = AllocContext(p); */
- if (p->HiUnit != p->LoUnit)
- c1 = (CTX_PTR)(p->HiUnit -= UNIT_SIZE);
- else if (p->FreeList[0] != 0)
- c1 = (CTX_PTR)RemoveNode(p, 0);
- else
- {
- c1 = (CTX_PTR)AllocUnitsRare(p, 0);
- if (!c1)
- return NULL;
- }
- c1->NumStats = 1;
- *ONE_STATE(c1) = upState;
- c1->Suffix = REF(c);
- SetSuccessor(ps[--numPs], REF(c1));
- c = c1;
- }
- while (numPs != 0);
-
- return c;
-}
-
-static void SwapStates(CPpmd_State *t1, CPpmd_State *t2)
-{
- CPpmd_State tmp = *t1;
- *t1 = *t2;
- *t2 = tmp;
-}
-
-static void UpdateModel(CPpmd7 *p)
-{
- CPpmd_Void_Ref successor, fSuccessor = SUCCESSOR(p->FoundState);
- CTX_PTR c;
- unsigned s0, ns;
-
- if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0)
- {
- c = SUFFIX(p->MinContext);
-
- if (c->NumStats == 1)
- {
- CPpmd_State *s = ONE_STATE(c);
- if (s->Freq < 32)
- s->Freq++;
- }
- else
- {
- CPpmd_State *s = STATS(c);
- if (s->Symbol != p->FoundState->Symbol)
- {
- do { s++; } while (s->Symbol != p->FoundState->Symbol);
- if (s[0].Freq >= s[-1].Freq)
- {
- SwapStates(&s[0], &s[-1]);
- s--;
- }
- }
- if (s->Freq < MAX_FREQ - 9)
- {
- s->Freq += 2;
- c->SummFreq += 2;
- }
- }
- }
-
- if (p->OrderFall == 0)
- {
- p->MinContext = p->MaxContext = CreateSuccessors(p, True);
- if (p->MinContext == 0)
- {
- RestartModel(p);
- return;
- }
- SetSuccessor(p->FoundState, REF(p->MinContext));
- return;
- }
-
- *p->Text++ = p->FoundState->Symbol;
- successor = REF(p->Text);
- if (p->Text >= p->UnitsStart)
- {
- RestartModel(p);
- return;
- }
-
- if (fSuccessor)
- {
- if (fSuccessor <= successor)
- {
- CTX_PTR cs = CreateSuccessors(p, False);
- if (cs == NULL)
- {
- RestartModel(p);
- return;
- }
- fSuccessor = REF(cs);
- }
- if (--p->OrderFall == 0)
- {
- successor = fSuccessor;
- p->Text -= (p->MaxContext != p->MinContext);
- }
- }
- else
- {
- SetSuccessor(p->FoundState, successor);
- fSuccessor = REF(p->MinContext);
- }
-
- s0 = p->MinContext->SummFreq - (ns = p->MinContext->NumStats) - (p->FoundState->Freq - 1);
-
- for (c = p->MaxContext; c != p->MinContext; c = SUFFIX(c))
- {
- unsigned ns1;
- UInt32 cf, sf;
- if ((ns1 = c->NumStats) != 1)
- {
- if ((ns1 & 1) == 0)
- {
- /* Expand for one UNIT */
- unsigned oldNU = ns1 >> 1;
- unsigned i = U2I(oldNU);
- if (i != U2I((size_t)oldNU + 1))
- {
- void *ptr = AllocUnits(p, i + 1);
- void *oldPtr;
- if (!ptr)
- {
- RestartModel(p);
- return;
- }
- oldPtr = STATS(c);
- MyMem12Cpy(ptr, oldPtr, oldNU);
- InsertNode(p, oldPtr, i);
- c->Stats = STATS_REF(ptr);
- }
- }
- c->SummFreq = (UInt16)(c->SummFreq + (2 * ns1 < ns) + 2 * ((4 * ns1 <= ns) & (c->SummFreq <= 8 * ns1)));
- }
- else
- {
- CPpmd_State *s = (CPpmd_State*)AllocUnits(p, 0);
- if (!s)
- {
- RestartModel(p);
- return;
- }
- *s = *ONE_STATE(c);
- c->Stats = REF(s);
- if (s->Freq < MAX_FREQ / 4 - 1)
- s->Freq <<= 1;
- else
- s->Freq = MAX_FREQ - 4;
- c->SummFreq = (UInt16)(s->Freq + p->InitEsc + (ns > 3));
- }
- cf = 2 * (UInt32)p->FoundState->Freq * (c->SummFreq + 6);
- sf = (UInt32)s0 + c->SummFreq;
- if (cf < 6 * sf)
- {
- cf = 1 + (cf > sf) + (cf >= 4 * sf);
- c->SummFreq += 3;
- }
- else
- {
- cf = 4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf);
- c->SummFreq = (UInt16)(c->SummFreq + cf);
- }
- {
- CPpmd_State *s = STATS(c) + ns1;
- SetSuccessor(s, successor);
- s->Symbol = p->FoundState->Symbol;
- s->Freq = (Byte)cf;
- c->NumStats = (UInt16)(ns1 + 1);
- }
- }
- p->MaxContext = p->MinContext = CTX(fSuccessor);
-}
-
-static void Rescale(CPpmd7 *p)
-{
- unsigned i, adder, sumFreq, escFreq;
- CPpmd_State *stats = STATS(p->MinContext);
- CPpmd_State *s = p->FoundState;
- {
- CPpmd_State tmp = *s;
- for (; s != stats; s--)
- s[0] = s[-1];
- *s = tmp;
- }
- escFreq = p->MinContext->SummFreq - s->Freq;
- s->Freq += 4;
- adder = (p->OrderFall != 0);
- s->Freq = (Byte)((s->Freq + adder) >> 1);
- sumFreq = s->Freq;
-
- i = p->MinContext->NumStats - 1;
- do
- {
- escFreq -= (++s)->Freq;
- s->Freq = (Byte)((s->Freq + adder) >> 1);
- sumFreq += s->Freq;
- if (s[0].Freq > s[-1].Freq)
- {
- CPpmd_State *s1 = s;
- CPpmd_State tmp = *s1;
- do
- s1[0] = s1[-1];
- while (--s1 != stats && tmp.Freq > s1[-1].Freq);
- *s1 = tmp;
- }
- }
- while (--i);
-
- if (s->Freq == 0)
- {
- unsigned numStats = p->MinContext->NumStats;
- unsigned n0, n1;
- do { i++; } while ((--s)->Freq == 0);
- escFreq += i;
- p->MinContext->NumStats = (UInt16)(p->MinContext->NumStats - i);
- if (p->MinContext->NumStats == 1)
- {
- CPpmd_State tmp = *stats;
- do
- {
- tmp.Freq = (Byte)(tmp.Freq - (tmp.Freq >> 1));
- escFreq >>= 1;
- }
- while (escFreq > 1);
- InsertNode(p, stats, U2I(((numStats + 1) >> 1)));
- *(p->FoundState = ONE_STATE(p->MinContext)) = tmp;
- return;
- }
- n0 = (numStats + 1) >> 1;
- n1 = (p->MinContext->NumStats + 1) >> 1;
- if (n0 != n1)
- p->MinContext->Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1));
- }
- p->MinContext->SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1));
- p->FoundState = STATS(p->MinContext);
-}
-
-CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq)
-{
- CPpmd_See *see;
- unsigned nonMasked = p->MinContext->NumStats - numMasked;
- if (p->MinContext->NumStats != 256)
- {
- see = p->See[(unsigned)p->NS2Indx[(size_t)nonMasked - 1]] +
- (nonMasked < (unsigned)SUFFIX(p->MinContext)->NumStats - p->MinContext->NumStats) +
- 2 * (unsigned)(p->MinContext->SummFreq < 11 * p->MinContext->NumStats) +
- 4 * (unsigned)(numMasked > nonMasked) +
- p->HiBitsFlag;
- {
- unsigned r = (see->Summ >> see->Shift);
- see->Summ = (UInt16)(see->Summ - r);
- *escFreq = r + (r == 0);
- }
- }
- else
- {
- see = &p->DummySee;
- *escFreq = 1;
- }
- return see;
-}
-
-static void NextContext(CPpmd7 *p)
-{
- CTX_PTR c = CTX(SUCCESSOR(p->FoundState));
- if (p->OrderFall == 0 && (Byte *)c > p->Text)
- p->MinContext = p->MaxContext = c;
- else
- UpdateModel(p);
-}
-
-void Ppmd7_Update1(CPpmd7 *p)
-{
- CPpmd_State *s = p->FoundState;
- s->Freq += 4;
- p->MinContext->SummFreq += 4;
- if (s[0].Freq > s[-1].Freq)
- {
- SwapStates(&s[0], &s[-1]);
- p->FoundState = --s;
- if (s->Freq > MAX_FREQ)
- Rescale(p);
- }
- NextContext(p);
-}
-
-void Ppmd7_Update1_0(CPpmd7 *p)
-{
- p->PrevSuccess = (2 * p->FoundState->Freq > p->MinContext->SummFreq);
- p->RunLength += p->PrevSuccess;
- p->MinContext->SummFreq += 4;
- if ((p->FoundState->Freq += 4) > MAX_FREQ)
- Rescale(p);
- NextContext(p);
-}
-
-void Ppmd7_UpdateBin(CPpmd7 *p)
-{
- p->FoundState->Freq = (Byte)(p->FoundState->Freq + (p->FoundState->Freq < 128 ? 1: 0));
- p->PrevSuccess = 1;
- p->RunLength++;
- NextContext(p);
-}
-
-void Ppmd7_Update2(CPpmd7 *p)
-{
- p->MinContext->SummFreq += 4;
- if ((p->FoundState->Freq += 4) > MAX_FREQ)
- Rescale(p);
- p->RunLength = p->InitRL;
- UpdateModel(p);
-}
+/* Ppmd7.c -- PPMdH codec
+2023-04-02 : Igor Pavlov : Public domain
+This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#include "Ppmd7.h"
+
+/* define PPMD7_ORDER_0_SUPPPORT to suport order-0 mode, unsupported by orignal PPMd var.H. code */
+// #define PPMD7_ORDER_0_SUPPPORT
+
+MY_ALIGN(16)
+static const Byte PPMD7_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
+MY_ALIGN(16)
+static const UInt16 PPMD7_kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};
+
+#define MAX_FREQ 124
+#define UNIT_SIZE 12
+
+#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE)
+#define U2I(nu) (p->Units2Indx[(size_t)(nu) - 1])
+#define I2U(indx) ((unsigned)p->Indx2Units[indx])
+#define I2U_UInt16(indx) ((UInt16)p->Indx2Units[indx])
+
+#define REF(ptr) Ppmd_GetRef(p, ptr)
+
+#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr))
+
+#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref))
+#define STATS(ctx) Ppmd7_GetStats(p, ctx)
+#define ONE_STATE(ctx) Ppmd7Context_OneState(ctx)
+#define SUFFIX(ctx) CTX((ctx)->Suffix)
+
+typedef CPpmd7_Context * PPMD7_CTX_PTR;
+
+struct CPpmd7_Node_;
+
+typedef Ppmd_Ref_Type(struct CPpmd7_Node_) CPpmd7_Node_Ref;
+
+typedef struct CPpmd7_Node_
+{
+ UInt16 Stamp; /* must be at offset 0 as CPpmd7_Context::NumStats. Stamp=0 means free */
+ UInt16 NU;
+ CPpmd7_Node_Ref Next; /* must be at offset >= 4 */
+ CPpmd7_Node_Ref Prev;
+} CPpmd7_Node;
+
+#define NODE(r) Ppmd_GetPtr_Type(p, r, CPpmd7_Node)
+
+void Ppmd7_Construct(CPpmd7 *p)
+{
+ unsigned i, k, m;
+
+ p->Base = NULL;
+
+ for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ unsigned step = (i >= 12 ? 4 : (i >> 2) + 1);
+ do { p->Units2Indx[k++] = (Byte)i; } while (--step);
+ p->Indx2Units[i] = (Byte)k;
+ }
+
+ p->NS2BSIndx[0] = (0 << 1);
+ p->NS2BSIndx[1] = (1 << 1);
+ memset(p->NS2BSIndx + 2, (2 << 1), 9);
+ memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11);
+
+ for (i = 0; i < 3; i++)
+ p->NS2Indx[i] = (Byte)i;
+
+ for (m = i, k = 1; i < 256; i++)
+ {
+ p->NS2Indx[i] = (Byte)m;
+ if (--k == 0)
+ k = (++m) - 2;
+ }
+
+ memcpy(p->ExpEscape, PPMD7_kExpEscape, 16);
+}
+
+
+void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->Base);
+ p->Size = 0;
+ p->Base = NULL;
+}
+
+
+BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc)
+{
+ if (!p->Base || p->Size != size)
+ {
+ Ppmd7_Free(p, alloc);
+ p->AlignOffset = (4 - size) & 3;
+ if ((p->Base = (Byte *)ISzAlloc_Alloc(alloc, p->AlignOffset + size)) == NULL)
+ return False;
+ p->Size = size;
+ }
+ return True;
+}
+
+
+
+// ---------- Internal Memory Allocator ----------
+
+/* We can use CPpmd7_Node in list of free units (as in Ppmd8)
+ But we still need one additional list walk pass in Ppmd7_GlueFreeBlocks().
+ So we use simple CPpmd_Void_Ref instead of CPpmd7_Node in Ppmd7_InsertNode() / Ppmd7_RemoveNode()
+*/
+
+#define EMPTY_NODE 0
+
+
+static void Ppmd7_InsertNode(CPpmd7 *p, void *node, unsigned indx)
+{
+ *((CPpmd_Void_Ref *)node) = p->FreeList[indx];
+ // ((CPpmd7_Node *)node)->Next = (CPpmd7_Node_Ref)p->FreeList[indx];
+
+ p->FreeList[indx] = REF(node);
+
+}
+
+
+static void *Ppmd7_RemoveNode(CPpmd7 *p, unsigned indx)
+{
+ CPpmd_Void_Ref *node = (CPpmd_Void_Ref *)Ppmd7_GetPtr(p, p->FreeList[indx]);
+ p->FreeList[indx] = *node;
+ // CPpmd7_Node *node = NODE((CPpmd7_Node_Ref)p->FreeList[indx]);
+ // p->FreeList[indx] = node->Next;
+ return node;
+}
+
+
+static void Ppmd7_SplitBlock(CPpmd7 *p, void *ptr, unsigned oldIndx, unsigned newIndx)
+{
+ unsigned i, nu = I2U(oldIndx) - I2U(newIndx);
+ ptr = (Byte *)ptr + U2B(I2U(newIndx));
+ if (I2U(i = U2I(nu)) != nu)
+ {
+ unsigned k = I2U(--i);
+ Ppmd7_InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1);
+ }
+ Ppmd7_InsertNode(p, ptr, i);
+}
+
+
+/* we use CPpmd7_Node_Union union to solve XLC -O2 strict pointer aliasing problem */
+
+typedef union
+{
+ CPpmd7_Node Node;
+ CPpmd7_Node_Ref NextRef;
+} CPpmd7_Node_Union;
+
+/* Original PPmdH (Ppmd7) code uses doubly linked list in Ppmd7_GlueFreeBlocks()
+ we use single linked list similar to Ppmd8 code */
+
+
+static void Ppmd7_GlueFreeBlocks(CPpmd7 *p)
+{
+ /*
+ we use first UInt16 field of 12-bytes UNITs as record type stamp
+ CPpmd_State { Byte Symbol; Byte Freq; : Freq != 0
+ CPpmd7_Context { UInt16 NumStats; : NumStats != 0
+ CPpmd7_Node { UInt16 Stamp : Stamp == 0 for free record
+ : Stamp == 1 for head record and guard
+ Last 12-bytes UNIT in array is always contains 12-bytes order-0 CPpmd7_Context record.
+ */
+ CPpmd7_Node_Ref head, n = 0;
+
+ p->GlueCount = 255;
+
+
+ /* we set guard NODE at LoUnit */
+ if (p->LoUnit != p->HiUnit)
+ ((CPpmd7_Node *)(void *)p->LoUnit)->Stamp = 1;
+
+ {
+ /* Create list of free blocks.
+ We still need one additional list walk pass before Glue. */
+ unsigned i;
+ for (i = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ const UInt16 nu = I2U_UInt16(i);
+ CPpmd7_Node_Ref next = (CPpmd7_Node_Ref)p->FreeList[i];
+ p->FreeList[i] = 0;
+ while (next != 0)
+ {
+ /* Don't change the order of the following commands: */
+ CPpmd7_Node_Union *un = (CPpmd7_Node_Union *)NODE(next);
+ const CPpmd7_Node_Ref tmp = next;
+ next = un->NextRef;
+ un->Node.Stamp = EMPTY_NODE;
+ un->Node.NU = nu;
+ un->Node.Next = n;
+ n = tmp;
+ }
+ }
+ }
+
+ head = n;
+ /* Glue and Fill must walk the list in same direction */
+ {
+ /* Glue free blocks */
+ CPpmd7_Node_Ref *prev = &head;
+ while (n)
+ {
+ CPpmd7_Node *node = NODE(n);
+ UInt32 nu = node->NU;
+ n = node->Next;
+ if (nu == 0)
+ {
+ *prev = n;
+ continue;
+ }
+ prev = &node->Next;
+ for (;;)
+ {
+ CPpmd7_Node *node2 = node + nu;
+ nu += node2->NU;
+ if (node2->Stamp != EMPTY_NODE || nu >= 0x10000)
+ break;
+ node->NU = (UInt16)nu;
+ node2->NU = 0;
+ }
+ }
+ }
+
+ /* Fill lists of free blocks */
+ for (n = head; n != 0;)
+ {
+ CPpmd7_Node *node = NODE(n);
+ UInt32 nu = node->NU;
+ unsigned i;
+ n = node->Next;
+ if (nu == 0)
+ continue;
+ for (; nu > 128; nu -= 128, node += 128)
+ Ppmd7_InsertNode(p, node, PPMD_NUM_INDEXES - 1);
+ if (I2U(i = U2I(nu)) != nu)
+ {
+ unsigned k = I2U(--i);
+ Ppmd7_InsertNode(p, node + k, (unsigned)nu - k - 1);
+ }
+ Ppmd7_InsertNode(p, node, i);
+ }
+}
+
+
+Z7_NO_INLINE
+static void *Ppmd7_AllocUnitsRare(CPpmd7 *p, unsigned indx)
+{
+ unsigned i;
+
+ if (p->GlueCount == 0)
+ {
+ Ppmd7_GlueFreeBlocks(p);
+ if (p->FreeList[indx] != 0)
+ return Ppmd7_RemoveNode(p, indx);
+ }
+
+ i = indx;
+
+ do
+ {
+ if (++i == PPMD_NUM_INDEXES)
+ {
+ UInt32 numBytes = U2B(I2U(indx));
+ Byte *us = p->UnitsStart;
+ p->GlueCount--;
+ return ((UInt32)(us - p->Text) > numBytes) ? (p->UnitsStart = us - numBytes) : NULL;
+ }
+ }
+ while (p->FreeList[i] == 0);
+
+ {
+ void *block = Ppmd7_RemoveNode(p, i);
+ Ppmd7_SplitBlock(p, block, i, indx);
+ return block;
+ }
+}
+
+
+static void *Ppmd7_AllocUnits(CPpmd7 *p, unsigned indx)
+{
+ if (p->FreeList[indx] != 0)
+ return Ppmd7_RemoveNode(p, indx);
+ {
+ UInt32 numBytes = U2B(I2U(indx));
+ Byte *lo = p->LoUnit;
+ if ((UInt32)(p->HiUnit - lo) >= numBytes)
+ {
+ p->LoUnit = lo + numBytes;
+ return lo;
+ }
+ }
+ return Ppmd7_AllocUnitsRare(p, indx);
+}
+
+
+#define MEM_12_CPY(dest, src, num) \
+ { UInt32 *d = (UInt32 *)dest; const UInt32 *z = (const UInt32 *)src; UInt32 n = num; \
+ do { d[0] = z[0]; d[1] = z[1]; d[2] = z[2]; z += 3; d += 3; } while (--n); }
+
+
+/*
+static void *ShrinkUnits(CPpmd7 *p, void *oldPtr, unsigned oldNU, unsigned newNU)
+{
+ unsigned i0 = U2I(oldNU);
+ unsigned i1 = U2I(newNU);
+ if (i0 == i1)
+ return oldPtr;
+ if (p->FreeList[i1] != 0)
+ {
+ void *ptr = Ppmd7_RemoveNode(p, i1);
+ MEM_12_CPY(ptr, oldPtr, newNU)
+ Ppmd7_InsertNode(p, oldPtr, i0);
+ return ptr;
+ }
+ Ppmd7_SplitBlock(p, oldPtr, i0, i1);
+ return oldPtr;
+}
+*/
+
+
+#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p)
+static void SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)
+{
+ Ppmd_SET_SUCCESSOR(p, v)
+}
+
+
+
+Z7_NO_INLINE
+static
+void Ppmd7_RestartModel(CPpmd7 *p)
+{
+ unsigned i, k;
+
+ memset(p->FreeList, 0, sizeof(p->FreeList));
+
+ p->Text = p->Base + p->AlignOffset;
+ p->HiUnit = p->Text + p->Size;
+ p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE;
+ p->GlueCount = 0;
+
+ p->OrderFall = p->MaxOrder;
+ p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1;
+ p->PrevSuccess = 0;
+
+ {
+ CPpmd7_Context *mc = (PPMD7_CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */
+ CPpmd_State *s = (CPpmd_State *)p->LoUnit; /* Ppmd7_AllocUnits(p, PPMD_NUM_INDEXES - 1); */
+
+ p->LoUnit += U2B(256 / 2);
+ p->MaxContext = p->MinContext = mc;
+ p->FoundState = s;
+
+ mc->NumStats = 256;
+ mc->Union2.SummFreq = 256 + 1;
+ mc->Union4.Stats = REF(s);
+ mc->Suffix = 0;
+
+ for (i = 0; i < 256; i++, s++)
+ {
+ s->Symbol = (Byte)i;
+ s->Freq = 1;
+ SetSuccessor(s, 0);
+ }
+
+ #ifdef PPMD7_ORDER_0_SUPPPORT
+ if (p->MaxOrder == 0)
+ {
+ CPpmd_Void_Ref r = REF(mc);
+ s = p->FoundState;
+ for (i = 0; i < 256; i++, s++)
+ SetSuccessor(s, r);
+ return;
+ }
+ #endif
+ }
+
+ for (i = 0; i < 128; i++)
+
+
+
+ for (k = 0; k < 8; k++)
+ {
+ unsigned m;
+ UInt16 *dest = p->BinSumm[i] + k;
+ const UInt16 val = (UInt16)(PPMD_BIN_SCALE - PPMD7_kInitBinEsc[k] / (i + 2));
+ for (m = 0; m < 64; m += 8)
+ dest[m] = val;
+ }
+
+
+ for (i = 0; i < 25; i++)
+ {
+
+ CPpmd_See *s = p->See[i];
+
+
+
+ unsigned summ = ((5 * i + 10) << (PPMD_PERIOD_BITS - 4));
+ for (k = 0; k < 16; k++, s++)
+ {
+ s->Summ = (UInt16)summ;
+ s->Shift = (PPMD_PERIOD_BITS - 4);
+ s->Count = 4;
+ }
+ }
+
+ p->DummySee.Summ = 0; /* unused */
+ p->DummySee.Shift = PPMD_PERIOD_BITS;
+ p->DummySee.Count = 64; /* unused */
+}
+
+
+void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder)
+{
+ p->MaxOrder = maxOrder;
+
+ Ppmd7_RestartModel(p);
+}
+
+
+
+/*
+ Ppmd7_CreateSuccessors()
+ It's called when (FoundState->Successor) is RAW-Successor,
+ that is the link to position in Raw text.
+ So we create Context records and write the links to
+ FoundState->Successor and to identical RAW-Successors in suffix
+ contexts of MinContex.
+
+ The function returns:
+ if (OrderFall == 0) then MinContext is already at MAX order,
+ { return pointer to new or existing context of same MAX order }
+ else
+ { return pointer to new real context that will be (Order+1) in comparison with MinContext
+
+ also it can return pointer to real context of same order,
+*/
+
+Z7_NO_INLINE
+static PPMD7_CTX_PTR Ppmd7_CreateSuccessors(CPpmd7 *p)
+{
+ PPMD7_CTX_PTR c = p->MinContext;
+ CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState);
+ Byte newSym, newFreq;
+ unsigned numPs = 0;
+ CPpmd_State *ps[PPMD7_MAX_ORDER];
+
+ if (p->OrderFall != 0)
+ ps[numPs++] = p->FoundState;
+
+ while (c->Suffix)
+ {
+ CPpmd_Void_Ref successor;
+ CPpmd_State *s;
+ c = SUFFIX(c);
+
+
+ if (c->NumStats != 1)
+ {
+ Byte sym = p->FoundState->Symbol;
+ for (s = STATS(c); s->Symbol != sym; s++);
+
+ }
+ else
+ {
+ s = ONE_STATE(c);
+
+ }
+ successor = SUCCESSOR(s);
+ if (successor != upBranch)
+ {
+ // (c) is real record Context here,
+ c = CTX(successor);
+ if (numPs == 0)
+ {
+ // (c) is real record MAX Order Context here,
+ // So we don't need to create any new contexts.
+ return c;
+ }
+ break;
+ }
+ ps[numPs++] = s;
+ }
+
+ // All created contexts will have single-symbol with new RAW-Successor
+ // All new RAW-Successors will point to next position in RAW text
+ // after FoundState->Successor
+
+ newSym = *(const Byte *)Ppmd7_GetPtr(p, upBranch);
+ upBranch++;
+
+
+ if (c->NumStats == 1)
+ newFreq = ONE_STATE(c)->Freq;
+ else
+ {
+ UInt32 cf, s0;
+ CPpmd_State *s;
+ for (s = STATS(c); s->Symbol != newSym; s++);
+ cf = (UInt32)s->Freq - 1;
+ s0 = (UInt32)c->Union2.SummFreq - c->NumStats - cf;
+ /*
+ cf - is frequency of symbol that will be Successor in new context records.
+ s0 - is commulative frequency sum of another symbols from parent context.
+ max(newFreq)= (s->Freq + 1), when (s0 == 1)
+ we have requirement (Ppmd7Context_OneState()->Freq <= 128) in BinSumm[]
+ so (s->Freq < 128) - is requirement for multi-symbol contexts
+ */
+ newFreq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : (2 * cf + s0 - 1) / (2 * s0) + 1));
+ }
+
+ // Create new single-symbol contexts from low order to high order in loop
+
+ do
+ {
+ PPMD7_CTX_PTR c1;
+ /* = AllocContext(p); */
+ if (p->HiUnit != p->LoUnit)
+ c1 = (PPMD7_CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE);
+ else if (p->FreeList[0] != 0)
+ c1 = (PPMD7_CTX_PTR)Ppmd7_RemoveNode(p, 0);
+ else
+ {
+ c1 = (PPMD7_CTX_PTR)Ppmd7_AllocUnitsRare(p, 0);
+ if (!c1)
+ return NULL;
+ }
+
+ c1->NumStats = 1;
+ ONE_STATE(c1)->Symbol = newSym;
+ ONE_STATE(c1)->Freq = newFreq;
+ SetSuccessor(ONE_STATE(c1), upBranch);
+ c1->Suffix = REF(c);
+ SetSuccessor(ps[--numPs], REF(c1));
+ c = c1;
+ }
+ while (numPs != 0);
+
+ return c;
+}
+
+
+
+#define SWAP_STATES(s) \
+ { CPpmd_State tmp = s[0]; s[0] = s[-1]; s[-1] = tmp; }
+
+
+void Ppmd7_UpdateModel(CPpmd7 *p);
+Z7_NO_INLINE
+void Ppmd7_UpdateModel(CPpmd7 *p)
+{
+ CPpmd_Void_Ref maxSuccessor, minSuccessor;
+ PPMD7_CTX_PTR c, mc;
+ unsigned s0, ns;
+
+
+
+ if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0)
+ {
+ /* Update Freqs in Suffix Context */
+
+ c = SUFFIX(p->MinContext);
+
+ if (c->NumStats == 1)
+ {
+ CPpmd_State *s = ONE_STATE(c);
+ if (s->Freq < 32)
+ s->Freq++;
+ }
+ else
+ {
+ CPpmd_State *s = STATS(c);
+ Byte sym = p->FoundState->Symbol;
+
+ if (s->Symbol != sym)
+ {
+ do
+ {
+ // s++; if (s->Symbol == sym) break;
+ s++;
+ }
+ while (s->Symbol != sym);
+
+ if (s[0].Freq >= s[-1].Freq)
+ {
+ SWAP_STATES(s)
+ s--;
+ }
+ }
+
+ if (s->Freq < MAX_FREQ - 9)
+ {
+ s->Freq = (Byte)(s->Freq + 2);
+ c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 2);
+ }
+ }
+ }
+
+
+ if (p->OrderFall == 0)
+ {
+ /* MAX ORDER context */
+ /* (FoundState->Successor) is RAW-Successor. */
+ p->MaxContext = p->MinContext = Ppmd7_CreateSuccessors(p);
+ if (!p->MinContext)
+ {
+ Ppmd7_RestartModel(p);
+ return;
+ }
+ SetSuccessor(p->FoundState, REF(p->MinContext));
+ return;
+ }
+
+
+ /* NON-MAX ORDER context */
+
+ {
+ Byte *text = p->Text;
+ *text++ = p->FoundState->Symbol;
+ p->Text = text;
+ if (text >= p->UnitsStart)
+ {
+ Ppmd7_RestartModel(p);
+ return;
+ }
+ maxSuccessor = REF(text);
+ }
+
+ minSuccessor = SUCCESSOR(p->FoundState);
+
+ if (minSuccessor)
+ {
+ // there is Successor for FoundState in MinContext.
+ // So the next context will be one order higher than MinContext.
+
+ if (minSuccessor <= maxSuccessor)
+ {
+ // minSuccessor is RAW-Successor. So we will create real contexts records:
+ PPMD7_CTX_PTR cs = Ppmd7_CreateSuccessors(p);
+ if (!cs)
+ {
+ Ppmd7_RestartModel(p);
+ return;
+ }
+ minSuccessor = REF(cs);
+ }
+
+ // minSuccessor now is real Context pointer that points to existing (Order+1) context
+
+ if (--p->OrderFall == 0)
+ {
+ /*
+ if we move to MaxOrder context, then minSuccessor will be common Succesor for both:
+ MinContext that is (MaxOrder - 1)
+ MaxContext that is (MaxOrder)
+ so we don't need new RAW-Successor, and we can use real minSuccessor
+ as succssors for both MinContext and MaxContext.
+ */
+ maxSuccessor = minSuccessor;
+
+ /*
+ if (MaxContext != MinContext)
+ {
+ there was order fall from MaxOrder and we don't need current symbol
+ to transfer some RAW-Succesors to real contexts.
+ So we roll back pointer in raw data for one position.
+ }
+ */
+ p->Text -= (p->MaxContext != p->MinContext);
+ }
+ }
+ else
+ {
+ /*
+ FoundState has NULL-Successor here.
+ And only root 0-order context can contain NULL-Successors.
+ We change Successor in FoundState to RAW-Successor,
+ And next context will be same 0-order root Context.
+ */
+ SetSuccessor(p->FoundState, maxSuccessor);
+ minSuccessor = REF(p->MinContext);
+ }
+
+ mc = p->MinContext;
+ c = p->MaxContext;
+
+ p->MaxContext = p->MinContext = CTX(minSuccessor);
+
+ if (c == mc)
+ return;
+
+ // s0 : is pure Escape Freq
+ s0 = mc->Union2.SummFreq - (ns = mc->NumStats) - ((unsigned)p->FoundState->Freq - 1);
+
+ do
+ {
+ unsigned ns1;
+ UInt32 sum;
+
+ if ((ns1 = c->NumStats) != 1)
+ {
+ if ((ns1 & 1) == 0)
+ {
+ /* Expand for one UNIT */
+ unsigned oldNU = ns1 >> 1;
+ unsigned i = U2I(oldNU);
+ if (i != U2I((size_t)oldNU + 1))
+ {
+ void *ptr = Ppmd7_AllocUnits(p, i + 1);
+ void *oldPtr;
+ if (!ptr)
+ {
+ Ppmd7_RestartModel(p);
+ return;
+ }
+ oldPtr = STATS(c);
+ MEM_12_CPY(ptr, oldPtr, oldNU)
+ Ppmd7_InsertNode(p, oldPtr, i);
+ c->Union4.Stats = STATS_REF(ptr);
+ }
+ }
+ sum = c->Union2.SummFreq;
+ /* max increase of Escape_Freq is 3 here.
+ total increase of Union2.SummFreq for all symbols is less than 256 here */
+ sum += (UInt32)(2 * ns1 < ns) + 2 * ((unsigned)(4 * ns1 <= ns) & (sum <= 8 * ns1));
+ /* original PPMdH uses 16-bit variable for (sum) here.
+ But (sum < 0x9000). So we don't truncate (sum) to 16-bit */
+ // sum = (UInt16)sum;
+ }
+ else
+ {
+ // instead of One-symbol context we create 2-symbol context
+ CPpmd_State *s = (CPpmd_State*)Ppmd7_AllocUnits(p, 0);
+ if (!s)
+ {
+ Ppmd7_RestartModel(p);
+ return;
+ }
+ {
+ unsigned freq = c->Union2.State2.Freq;
+ // s = *ONE_STATE(c);
+ s->Symbol = c->Union2.State2.Symbol;
+ s->Successor_0 = c->Union4.State4.Successor_0;
+ s->Successor_1 = c->Union4.State4.Successor_1;
+ // SetSuccessor(s, c->Union4.Stats); // call it only for debug purposes to check the order of
+ // (Successor_0 and Successor_1) in LE/BE.
+ c->Union4.Stats = REF(s);
+ if (freq < MAX_FREQ / 4 - 1)
+ freq <<= 1;
+ else
+ freq = MAX_FREQ - 4;
+ // (max(s->freq) == 120), when we convert from 1-symbol into 2-symbol context
+ s->Freq = (Byte)freq;
+ // max(InitEsc = PPMD7_kExpEscape[*]) is 25. So the max(escapeFreq) is 26 here
+ sum = freq + p->InitEsc + (ns > 3);
+ }
+ }
+
+ {
+ CPpmd_State *s = STATS(c) + ns1;
+ UInt32 cf = 2 * (sum + 6) * (UInt32)p->FoundState->Freq;
+ UInt32 sf = (UInt32)s0 + sum;
+ s->Symbol = p->FoundState->Symbol;
+ c->NumStats = (UInt16)(ns1 + 1);
+ SetSuccessor(s, maxSuccessor);
+
+ if (cf < 6 * sf)
+ {
+ cf = (UInt32)1 + (cf > sf) + (cf >= 4 * sf);
+ sum += 3;
+ /* It can add (0, 1, 2) to Escape_Freq */
+ }
+ else
+ {
+ cf = (UInt32)4 + (cf >= 9 * sf) + (cf >= 12 * sf) + (cf >= 15 * sf);
+ sum += cf;
+ }
+
+ c->Union2.SummFreq = (UInt16)sum;
+ s->Freq = (Byte)cf;
+ }
+ c = SUFFIX(c);
+ }
+ while (c != mc);
+}
+
+
+
+Z7_NO_INLINE
+static void Ppmd7_Rescale(CPpmd7 *p)
+{
+ unsigned i, adder, sumFreq, escFreq;
+ CPpmd_State *stats = STATS(p->MinContext);
+ CPpmd_State *s = p->FoundState;
+
+ /* Sort the list by Freq */
+ if (s != stats)
+ {
+ CPpmd_State tmp = *s;
+ do
+ s[0] = s[-1];
+ while (--s != stats);
+ *s = tmp;
+ }
+
+ sumFreq = s->Freq;
+ escFreq = p->MinContext->Union2.SummFreq - sumFreq;
+
+ /*
+ if (p->OrderFall == 0), adder = 0 : it's allowed to remove symbol from MAX Order context
+ if (p->OrderFall != 0), adder = 1 : it's NOT allowed to remove symbol from NON-MAX Order context
+ */
+
+ adder = (p->OrderFall != 0);
+
+ #ifdef PPMD7_ORDER_0_SUPPPORT
+ adder |= (p->MaxOrder == 0); // we don't remove symbols from order-0 context
+ #endif
+
+ sumFreq = (sumFreq + 4 + adder) >> 1;
+ i = (unsigned)p->MinContext->NumStats - 1;
+ s->Freq = (Byte)sumFreq;
+
+ do
+ {
+ unsigned freq = (++s)->Freq;
+ escFreq -= freq;
+ freq = (freq + adder) >> 1;
+ sumFreq += freq;
+ s->Freq = (Byte)freq;
+ if (freq > s[-1].Freq)
+ {
+ CPpmd_State tmp = *s;
+ CPpmd_State *s1 = s;
+ do
+ {
+ s1[0] = s1[-1];
+ }
+ while (--s1 != stats && freq > s1[-1].Freq);
+ *s1 = tmp;
+ }
+ }
+ while (--i);
+
+ if (s->Freq == 0)
+ {
+ /* Remove all items with Freq == 0 */
+ CPpmd7_Context *mc;
+ unsigned numStats, numStatsNew, n0, n1;
+
+ i = 0; do { i++; } while ((--s)->Freq == 0);
+
+ /* We increase (escFreq) for the number of removed symbols.
+ So we will have (0.5) increase for Escape_Freq in avarage per
+ removed symbol after Escape_Freq halving */
+ escFreq += i;
+ mc = p->MinContext;
+ numStats = mc->NumStats;
+ numStatsNew = numStats - i;
+ mc->NumStats = (UInt16)(numStatsNew);
+ n0 = (numStats + 1) >> 1;
+
+ if (numStatsNew == 1)
+ {
+ /* Create Single-Symbol context */
+ unsigned freq = stats->Freq;
+
+ do
+ {
+ escFreq >>= 1;
+ freq = (freq + 1) >> 1;
+ }
+ while (escFreq > 1);
+
+ s = ONE_STATE(mc);
+ *s = *stats;
+ s->Freq = (Byte)freq; // (freq <= 260 / 4)
+ p->FoundState = s;
+ Ppmd7_InsertNode(p, stats, U2I(n0));
+ return;
+ }
+
+ n1 = (numStatsNew + 1) >> 1;
+ if (n0 != n1)
+ {
+ // p->MinContext->Union4.Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1));
+ unsigned i0 = U2I(n0);
+ unsigned i1 = U2I(n1);
+ if (i0 != i1)
+ {
+ if (p->FreeList[i1] != 0)
+ {
+ void *ptr = Ppmd7_RemoveNode(p, i1);
+ p->MinContext->Union4.Stats = STATS_REF(ptr);
+ MEM_12_CPY(ptr, (const void *)stats, n1)
+ Ppmd7_InsertNode(p, stats, i0);
+ }
+ else
+ Ppmd7_SplitBlock(p, stats, i0, i1);
+ }
+ }
+ }
+ {
+ CPpmd7_Context *mc = p->MinContext;
+ mc->Union2.SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1));
+ // Escape_Freq halving here
+ p->FoundState = STATS(mc);
+ }
+}
+
+
+CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *escFreq)
+{
+ CPpmd_See *see;
+ const CPpmd7_Context *mc = p->MinContext;
+ unsigned numStats = mc->NumStats;
+ if (numStats != 256)
+ {
+ unsigned nonMasked = numStats - numMasked;
+ see = p->See[(unsigned)p->NS2Indx[(size_t)nonMasked - 1]]
+ + (nonMasked < (unsigned)SUFFIX(mc)->NumStats - numStats)
+ + 2 * (unsigned)(mc->Union2.SummFreq < 11 * numStats)
+ + 4 * (unsigned)(numMasked > nonMasked) +
+ p->HiBitsFlag;
+ {
+ // if (see->Summ) field is larger than 16-bit, we need only low 16 bits of Summ
+ unsigned summ = (UInt16)see->Summ; // & 0xFFFF
+ unsigned r = (summ >> see->Shift);
+ see->Summ = (UInt16)(summ - r);
+ *escFreq = r + (r == 0);
+ }
+ }
+ else
+ {
+ see = &p->DummySee;
+ *escFreq = 1;
+ }
+ return see;
+}
+
+
+static void Ppmd7_NextContext(CPpmd7 *p)
+{
+ PPMD7_CTX_PTR c = CTX(SUCCESSOR(p->FoundState));
+ if (p->OrderFall == 0 && (const Byte *)c > p->Text)
+ p->MaxContext = p->MinContext = c;
+ else
+ Ppmd7_UpdateModel(p);
+}
+
+
+void Ppmd7_Update1(CPpmd7 *p)
+{
+ CPpmd_State *s = p->FoundState;
+ unsigned freq = s->Freq;
+ freq += 4;
+ p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4);
+ s->Freq = (Byte)freq;
+ if (freq > s[-1].Freq)
+ {
+ SWAP_STATES(s)
+ p->FoundState = --s;
+ if (freq > MAX_FREQ)
+ Ppmd7_Rescale(p);
+ }
+ Ppmd7_NextContext(p);
+}
+
+
+void Ppmd7_Update1_0(CPpmd7 *p)
+{
+ CPpmd_State *s = p->FoundState;
+ CPpmd7_Context *mc = p->MinContext;
+ unsigned freq = s->Freq;
+ unsigned summFreq = mc->Union2.SummFreq;
+ p->PrevSuccess = (2 * freq > summFreq);
+ p->RunLength += (int)p->PrevSuccess;
+ mc->Union2.SummFreq = (UInt16)(summFreq + 4);
+ freq += 4;
+ s->Freq = (Byte)freq;
+ if (freq > MAX_FREQ)
+ Ppmd7_Rescale(p);
+ Ppmd7_NextContext(p);
+}
+
+
+/*
+void Ppmd7_UpdateBin(CPpmd7 *p)
+{
+ unsigned freq = p->FoundState->Freq;
+ p->FoundState->Freq = (Byte)(freq + (freq < 128));
+ p->PrevSuccess = 1;
+ p->RunLength++;
+ Ppmd7_NextContext(p);
+}
+*/
+
+void Ppmd7_Update2(CPpmd7 *p)
+{
+ CPpmd_State *s = p->FoundState;
+ unsigned freq = s->Freq;
+ freq += 4;
+ p->RunLength = p->InitRL;
+ p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4);
+ s->Freq = (Byte)freq;
+ if (freq > MAX_FREQ)
+ Ppmd7_Rescale(p);
+ Ppmd7_UpdateModel(p);
+}
+
+
+
+/*
+PPMd Memory Map:
+{
+ [ 0 ] contains subset of original raw text, that is required to create context
+ records, Some symbols are not written, when max order context was reached
+ [ Text ] free area
+ [ UnitsStart ] CPpmd_State vectors and CPpmd7_Context records
+ [ LoUnit ] free area for CPpmd_State and CPpmd7_Context items
+[ HiUnit ] CPpmd7_Context records
+ [ Size ] end of array
+}
+
+These addresses don't cross at any time.
+And the following condtions is true for addresses:
+ (0 <= Text < UnitsStart <= LoUnit <= HiUnit <= Size)
+
+Raw text is BYTE--aligned.
+the data in block [ UnitsStart ... Size ] contains 12-bytes aligned UNITs.
+
+Last UNIT of array at offset (Size - 12) is root order-0 CPpmd7_Context record.
+The code can free UNITs memory blocks that were allocated to store CPpmd_State vectors.
+The code doesn't free UNITs allocated for CPpmd7_Context records.
+
+The code calls Ppmd7_RestartModel(), when there is no free memory for allocation.
+And Ppmd7_RestartModel() changes the state to orignal start state, with full free block.
+
+
+The code allocates UNITs with the following order:
+
+Allocation of 1 UNIT for Context record
+ - from free space (HiUnit) down to (LoUnit)
+ - from FreeList[0]
+ - Ppmd7_AllocUnitsRare()
+
+Ppmd7_AllocUnits() for CPpmd_State vectors:
+ - from FreeList[i]
+ - from free space (LoUnit) up to (HiUnit)
+ - Ppmd7_AllocUnitsRare()
+
+Ppmd7_AllocUnitsRare()
+ - if (GlueCount == 0)
+ { Glue lists, GlueCount = 255, allocate from FreeList[i]] }
+ - loop for all higher sized FreeList[...] lists
+ - from (UnitsStart - Text), GlueCount--
+ - ERROR
+
+
+Each Record with Context contains the CPpmd_State vector, where each
+CPpmd_State contains the link to Successor.
+There are 3 types of Successor:
+ 1) NULL-Successor - NULL pointer. NULL-Successor links can be stored
+ only in 0-order Root Context Record.
+ We use 0 value as NULL-Successor
+ 2) RAW-Successor - the link to position in raw text,
+ that "RAW-Successor" is being created after first
+ occurrence of new symbol for some existing context record.
+ (RAW-Successor > 0).
+ 3) RECORD-Successor - the link to CPpmd7_Context record of (Order+1),
+ that record is being created when we go via RAW-Successor again.
+
+For any successors at any time: the following condtions are true for Successor links:
+(NULL-Successor < RAW-Successor < UnitsStart <= RECORD-Successor)
+
+
+---------- Symbol Frequency, SummFreq and Range in Range_Coder ----------
+
+CPpmd7_Context::SummFreq = Sum(Stats[].Freq) + Escape_Freq
+
+The PPMd code tries to fulfill the condition:
+ (SummFreq <= (256 * 128 = RC::kBot))
+
+We have (Sum(Stats[].Freq) <= 256 * 124), because of (MAX_FREQ = 124)
+So (4 = 128 - 124) is average reserve for Escape_Freq for each symbol.
+If (CPpmd_State::Freq) is not aligned for 4, the reserve can be 5, 6 or 7.
+SummFreq and Escape_Freq can be changed in Ppmd7_Rescale() and *Update*() functions.
+Ppmd7_Rescale() can remove symbols only from max-order contexts. So Escape_Freq can increase after multiple calls of Ppmd7_Rescale() for
+max-order context.
+
+When the PPMd code still break (Total <= RC::Range) condition in range coder,
+we have two ways to resolve that problem:
+ 1) we can report error, if we want to keep compatibility with original PPMd code that has no fix for such cases.
+ 2) we can reduce (Total) value to (RC::Range) by reducing (Escape_Freq) part of (Total) value.
+*/
+
+#undef MAX_FREQ
+#undef UNIT_SIZE
+#undef U2B
+#undef U2I
+#undef I2U
+#undef I2U_UInt16
+#undef REF
+#undef STATS_REF
+#undef CTX
+#undef STATS
+#undef ONE_STATE
+#undef SUFFIX
+#undef NODE
+#undef EMPTY_NODE
+#undef MEM_12_CPY
+#undef SUCCESSOR
+#undef SWAP_STATES
diff --git a/C/Ppmd7.h b/C/Ppmd7.h
index cce93f1..d9eb326 100644
--- a/C/Ppmd7.h
+++ b/C/Ppmd7.h
@@ -1,142 +1,181 @@
-/* Ppmd7.h -- PPMdH compression codec
-2018-07-04 : Igor Pavlov : Public domain
-This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
-
-/* This code supports virtual RangeDecoder and includes the implementation
-of RangeCoder from 7z, instead of RangeCoder from original PPMd var.H.
-If you need the compatibility with original PPMd var.H, you can use external RangeDecoder */
-
-#ifndef __PPMD7_H
-#define __PPMD7_H
-
-#include "Ppmd.h"
-
-EXTERN_C_BEGIN
-
-#define PPMD7_MIN_ORDER 2
-#define PPMD7_MAX_ORDER 64
-
-#define PPMD7_MIN_MEM_SIZE (1 << 11)
-#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3)
-
-struct CPpmd7_Context_;
-
-typedef
- #ifdef PPMD_32BIT
- struct CPpmd7_Context_ *
- #else
- UInt32
- #endif
- CPpmd7_Context_Ref;
-
-typedef struct CPpmd7_Context_
-{
- UInt16 NumStats;
- UInt16 SummFreq;
- CPpmd_State_Ref Stats;
- CPpmd7_Context_Ref Suffix;
-} CPpmd7_Context;
-
-#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->SummFreq)
-
-typedef struct
-{
- CPpmd7_Context *MinContext, *MaxContext;
- CPpmd_State *FoundState;
- unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag;
- Int32 RunLength, InitRL; /* must be 32-bit at least */
-
- UInt32 Size;
- UInt32 GlueCount;
- Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart;
- UInt32 AlignOffset;
-
- Byte Indx2Units[PPMD_NUM_INDEXES];
- Byte Units2Indx[128];
- CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES];
- Byte NS2Indx[256], NS2BSIndx[256], HB2Flag[256];
- CPpmd_See DummySee, See[25][16];
- UInt16 BinSumm[128][64];
-} CPpmd7;
-
-void Ppmd7_Construct(CPpmd7 *p);
-BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc);
-void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc);
-void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder);
-#define Ppmd7_WasAllocated(p) ((p)->Base != NULL)
-
-
-/* ---------- Internal Functions ---------- */
-
-extern const Byte PPMD7_kExpEscape[16];
-
-#ifdef PPMD_32BIT
- #define Ppmd7_GetPtr(p, ptr) (ptr)
- #define Ppmd7_GetContext(p, ptr) (ptr)
- #define Ppmd7_GetStats(p, ctx) ((ctx)->Stats)
-#else
- #define Ppmd7_GetPtr(p, offs) ((void *)((p)->Base + (offs)))
- #define Ppmd7_GetContext(p, offs) ((CPpmd7_Context *)Ppmd7_GetPtr((p), (offs)))
- #define Ppmd7_GetStats(p, ctx) ((CPpmd_State *)Ppmd7_GetPtr((p), ((ctx)->Stats)))
-#endif
-
-void Ppmd7_Update1(CPpmd7 *p);
-void Ppmd7_Update1_0(CPpmd7 *p);
-void Ppmd7_Update2(CPpmd7 *p);
-void Ppmd7_UpdateBin(CPpmd7 *p);
-
-#define Ppmd7_GetBinSumm(p) \
- &p->BinSumm[(size_t)(unsigned)Ppmd7Context_OneState(p->MinContext)->Freq - 1][p->PrevSuccess + \
- p->NS2BSIndx[(size_t)Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] + \
- (p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol]) + \
- 2 * p->HB2Flag[(unsigned)Ppmd7Context_OneState(p->MinContext)->Symbol] + \
- ((p->RunLength >> 26) & 0x20)]
-
-CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale);
-
-
-/* ---------- Decode ---------- */
-
-typedef struct IPpmd7_RangeDec IPpmd7_RangeDec;
-
-struct IPpmd7_RangeDec
-{
- UInt32 (*GetThreshold)(const IPpmd7_RangeDec *p, UInt32 total);
- void (*Decode)(const IPpmd7_RangeDec *p, UInt32 start, UInt32 size);
- UInt32 (*DecodeBit)(const IPpmd7_RangeDec *p, UInt32 size0);
-};
-
-typedef struct
-{
- IPpmd7_RangeDec vt;
- UInt32 Range;
- UInt32 Code;
- IByteIn *Stream;
-} CPpmd7z_RangeDec;
-
-void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p);
-BoolInt Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p);
-#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
-
-int Ppmd7_DecodeSymbol(CPpmd7 *p, const IPpmd7_RangeDec *rc);
-
-
-/* ---------- Encode ---------- */
-
-typedef struct
-{
- UInt64 Low;
- UInt32 Range;
- Byte Cache;
- UInt64 CacheSize;
- IByteOut *Stream;
-} CPpmd7z_RangeEnc;
-
-void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p);
-void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p);
-
-void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol);
-
-EXTERN_C_END
-
-#endif
+/* Ppmd7.h -- Ppmd7 (PPMdH) compression codec
+2023-04-02 : Igor Pavlov : Public domain
+This code is based on:
+ PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+
+#ifndef ZIP7_INC_PPMD7_H
+#define ZIP7_INC_PPMD7_H
+
+#include "Ppmd.h"
+
+EXTERN_C_BEGIN
+
+#define PPMD7_MIN_ORDER 2
+#define PPMD7_MAX_ORDER 64
+
+#define PPMD7_MIN_MEM_SIZE (1 << 11)
+#define PPMD7_MAX_MEM_SIZE (0xFFFFFFFF - 12 * 3)
+
+struct CPpmd7_Context_;
+
+typedef Ppmd_Ref_Type(struct CPpmd7_Context_) CPpmd7_Context_Ref;
+
+// MY_CPU_pragma_pack_push_1
+
+typedef struct CPpmd7_Context_
+{
+ UInt16 NumStats;
+
+
+ union
+ {
+ UInt16 SummFreq;
+ CPpmd_State2 State2;
+ } Union2;
+
+ union
+ {
+ CPpmd_State_Ref Stats;
+ CPpmd_State4 State4;
+ } Union4;
+
+ CPpmd7_Context_Ref Suffix;
+} CPpmd7_Context;
+
+// MY_CPU_pragma_pop
+
+#define Ppmd7Context_OneState(p) ((CPpmd_State *)&(p)->Union2)
+
+
+
+
+typedef struct
+{
+ UInt32 Range;
+ UInt32 Code;
+ UInt32 Low;
+ IByteInPtr Stream;
+} CPpmd7_RangeDec;
+
+
+typedef struct
+{
+ UInt32 Range;
+ Byte Cache;
+ // Byte _dummy_[3];
+ UInt64 Low;
+ UInt64 CacheSize;
+ IByteOutPtr Stream;
+} CPpmd7z_RangeEnc;
+
+
+typedef struct
+{
+ CPpmd7_Context *MinContext, *MaxContext;
+ CPpmd_State *FoundState;
+ unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, HiBitsFlag;
+ Int32 RunLength, InitRL; /* must be 32-bit at least */
+
+ UInt32 Size;
+ UInt32 GlueCount;
+ UInt32 AlignOffset;
+ Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart;
+
+
+
+
+ union
+ {
+ CPpmd7_RangeDec dec;
+ CPpmd7z_RangeEnc enc;
+ } rc;
+
+ Byte Indx2Units[PPMD_NUM_INDEXES + 2]; // +2 for alignment
+ Byte Units2Indx[128];
+ CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES];
+
+ Byte NS2BSIndx[256], NS2Indx[256];
+ Byte ExpEscape[16];
+ CPpmd_See DummySee, See[25][16];
+ UInt16 BinSumm[128][64];
+ // int LastSymbol;
+} CPpmd7;
+
+
+void Ppmd7_Construct(CPpmd7 *p);
+BoolInt Ppmd7_Alloc(CPpmd7 *p, UInt32 size, ISzAllocPtr alloc);
+void Ppmd7_Free(CPpmd7 *p, ISzAllocPtr alloc);
+void Ppmd7_Init(CPpmd7 *p, unsigned maxOrder);
+#define Ppmd7_WasAllocated(p) ((p)->Base != NULL)
+
+
+/* ---------- Internal Functions ---------- */
+
+#define Ppmd7_GetPtr(p, ptr) Ppmd_GetPtr(p, ptr)
+#define Ppmd7_GetContext(p, ptr) Ppmd_GetPtr_Type(p, ptr, CPpmd7_Context)
+#define Ppmd7_GetStats(p, ctx) Ppmd_GetPtr_Type(p, (ctx)->Union4.Stats, CPpmd_State)
+
+void Ppmd7_Update1(CPpmd7 *p);
+void Ppmd7_Update1_0(CPpmd7 *p);
+void Ppmd7_Update2(CPpmd7 *p);
+
+#define PPMD7_HiBitsFlag_3(sym) ((((unsigned)sym + 0xC0) >> (8 - 3)) & (1 << 3))
+#define PPMD7_HiBitsFlag_4(sym) ((((unsigned)sym + 0xC0) >> (8 - 4)) & (1 << 4))
+// #define PPMD7_HiBitsFlag_3(sym) ((sym) < 0x40 ? 0 : (1 << 3))
+// #define PPMD7_HiBitsFlag_4(sym) ((sym) < 0x40 ? 0 : (1 << 4))
+
+#define Ppmd7_GetBinSumm(p) \
+ &p->BinSumm[(size_t)(unsigned)Ppmd7Context_OneState(p->MinContext)->Freq - 1] \
+ [ p->PrevSuccess + ((p->RunLength >> 26) & 0x20) \
+ + p->NS2BSIndx[(size_t)Ppmd7_GetContext(p, p->MinContext->Suffix)->NumStats - 1] \
+ + PPMD7_HiBitsFlag_4(Ppmd7Context_OneState(p->MinContext)->Symbol) \
+ + (p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol)) ]
+
+CPpmd_See *Ppmd7_MakeEscFreq(CPpmd7 *p, unsigned numMasked, UInt32 *scale);
+
+
+/*
+We support two versions of Ppmd7 (PPMdH) methods that use same CPpmd7 structure:
+ 1) Ppmd7a_*: original PPMdH
+ 2) Ppmd7z_*: modified PPMdH with 7z Range Coder
+Ppmd7_*: the structures and functions that are common for both versions of PPMd7 (PPMdH)
+*/
+
+/* ---------- Decode ---------- */
+
+#define PPMD7_SYM_END (-1)
+#define PPMD7_SYM_ERROR (-2)
+
+/*
+You must set (CPpmd7::rc.dec.Stream) before Ppmd7*_RangeDec_Init()
+
+Ppmd7*_DecodeSymbol()
+out:
+ >= 0 : decoded byte
+ -1 : PPMD7_SYM_END : End of payload marker
+ -2 : PPMD7_SYM_ERROR : Data error
+*/
+
+/* Ppmd7a_* : original PPMdH */
+BoolInt Ppmd7a_RangeDec_Init(CPpmd7_RangeDec *p);
+#define Ppmd7a_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
+int Ppmd7a_DecodeSymbol(CPpmd7 *p);
+
+/* Ppmd7z_* : modified PPMdH with 7z Range Coder */
+BoolInt Ppmd7z_RangeDec_Init(CPpmd7_RangeDec *p);
+#define Ppmd7z_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
+int Ppmd7z_DecodeSymbol(CPpmd7 *p);
+// Byte *Ppmd7z_DecodeSymbols(CPpmd7 *p, Byte *buf, const Byte *lim);
+
+
+/* ---------- Encode ---------- */
+
+void Ppmd7z_Init_RangeEnc(CPpmd7 *p);
+void Ppmd7z_Flush_RangeEnc(CPpmd7 *p);
+// void Ppmd7z_EncodeSymbol(CPpmd7 *p, int symbol);
+void Ppmd7z_EncodeSymbols(CPpmd7 *p, const Byte *buf, const Byte *lim);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Ppmd7Dec.c b/C/Ppmd7Dec.c
index 2026407..8323828 100644
--- a/C/Ppmd7Dec.c
+++ b/C/Ppmd7Dec.c
@@ -1,191 +1,312 @@
-/* Ppmd7Dec.c -- PPMdH Decoder
-2018-07-04 : Igor Pavlov : Public domain
-This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
-
-#include "Precomp.h"
-
-#include "Ppmd7.h"
-
-#define kTopValue (1 << 24)
-
-BoolInt Ppmd7z_RangeDec_Init(CPpmd7z_RangeDec *p)
-{
- unsigned i;
- p->Code = 0;
- p->Range = 0xFFFFFFFF;
- if (IByteIn_Read(p->Stream) != 0)
- return False;
- for (i = 0; i < 4; i++)
- p->Code = (p->Code << 8) | IByteIn_Read(p->Stream);
- return (p->Code < 0xFFFFFFFF);
-}
-
-#define GET_Ppmd7z_RangeDec CPpmd7z_RangeDec *p = CONTAINER_FROM_VTBL(pp, CPpmd7z_RangeDec, vt);
-
-static UInt32 Range_GetThreshold(const IPpmd7_RangeDec *pp, UInt32 total)
-{
- GET_Ppmd7z_RangeDec
- return p->Code / (p->Range /= total);
-}
-
-static void Range_Normalize(CPpmd7z_RangeDec *p)
-{
- if (p->Range < kTopValue)
- {
- p->Code = (p->Code << 8) | IByteIn_Read(p->Stream);
- p->Range <<= 8;
- if (p->Range < kTopValue)
- {
- p->Code = (p->Code << 8) | IByteIn_Read(p->Stream);
- p->Range <<= 8;
- }
- }
-}
-
-static void Range_Decode(const IPpmd7_RangeDec *pp, UInt32 start, UInt32 size)
-{
- GET_Ppmd7z_RangeDec
- p->Code -= start * p->Range;
- p->Range *= size;
- Range_Normalize(p);
-}
-
-static UInt32 Range_DecodeBit(const IPpmd7_RangeDec *pp, UInt32 size0)
-{
- GET_Ppmd7z_RangeDec
- UInt32 newBound = (p->Range >> 14) * size0;
- UInt32 symbol;
- if (p->Code < newBound)
- {
- symbol = 0;
- p->Range = newBound;
- }
- else
- {
- symbol = 1;
- p->Code -= newBound;
- p->Range -= newBound;
- }
- Range_Normalize(p);
- return symbol;
-}
-
-void Ppmd7z_RangeDec_CreateVTable(CPpmd7z_RangeDec *p)
-{
- p->vt.GetThreshold = Range_GetThreshold;
- p->vt.Decode = Range_Decode;
- p->vt.DecodeBit = Range_DecodeBit;
-}
-
-
-#define MASK(sym) ((signed char *)charMask)[sym]
-
-int Ppmd7_DecodeSymbol(CPpmd7 *p, const IPpmd7_RangeDec *rc)
-{
- size_t charMask[256 / sizeof(size_t)];
- if (p->MinContext->NumStats != 1)
- {
- CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
- unsigned i;
- UInt32 count, hiCnt;
- if ((count = rc->GetThreshold(rc, p->MinContext->SummFreq)) < (hiCnt = s->Freq))
- {
- Byte symbol;
- rc->Decode(rc, 0, s->Freq);
- p->FoundState = s;
- symbol = s->Symbol;
- Ppmd7_Update1_0(p);
- return symbol;
- }
- p->PrevSuccess = 0;
- i = p->MinContext->NumStats - 1;
- do
- {
- if ((hiCnt += (++s)->Freq) > count)
- {
- Byte symbol;
- rc->Decode(rc, hiCnt - s->Freq, s->Freq);
- p->FoundState = s;
- symbol = s->Symbol;
- Ppmd7_Update1(p);
- return symbol;
- }
- }
- while (--i);
- if (count >= p->MinContext->SummFreq)
- return -2;
- p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol];
- rc->Decode(rc, hiCnt, p->MinContext->SummFreq - hiCnt);
- PPMD_SetAllBitsIn256Bytes(charMask);
- MASK(s->Symbol) = 0;
- i = p->MinContext->NumStats - 1;
- do { MASK((--s)->Symbol) = 0; } while (--i);
- }
- else
- {
- UInt16 *prob = Ppmd7_GetBinSumm(p);
- if (rc->DecodeBit(rc, *prob) == 0)
- {
- Byte symbol;
- *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
- symbol = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol;
- Ppmd7_UpdateBin(p);
- return symbol;
- }
- *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
- p->InitEsc = PPMD7_kExpEscape[*prob >> 10];
- PPMD_SetAllBitsIn256Bytes(charMask);
- MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0;
- p->PrevSuccess = 0;
- }
- for (;;)
- {
- CPpmd_State *ps[256], *s;
- UInt32 freqSum, count, hiCnt;
- CPpmd_See *see;
- unsigned i, num, numMasked = p->MinContext->NumStats;
- do
- {
- p->OrderFall++;
- if (!p->MinContext->Suffix)
- return -1;
- p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix);
- }
- while (p->MinContext->NumStats == numMasked);
- hiCnt = 0;
- s = Ppmd7_GetStats(p, p->MinContext);
- i = 0;
- num = p->MinContext->NumStats - numMasked;
- do
- {
- int k = (int)(MASK(s->Symbol));
- hiCnt += (s->Freq & k);
- ps[i] = s++;
- i -= k;
- }
- while (i != num);
-
- see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum);
- freqSum += hiCnt;
- count = rc->GetThreshold(rc, freqSum);
-
- if (count < hiCnt)
- {
- Byte symbol;
- CPpmd_State **pps = ps;
- for (hiCnt = 0; (hiCnt += (*pps)->Freq) <= count; pps++);
- s = *pps;
- rc->Decode(rc, hiCnt - s->Freq, s->Freq);
- Ppmd_See_Update(see);
- p->FoundState = s;
- symbol = s->Symbol;
- Ppmd7_Update2(p);
- return symbol;
- }
- if (count >= freqSum)
- return -2;
- rc->Decode(rc, hiCnt, freqSum - hiCnt);
- see->Summ = (UInt16)(see->Summ + freqSum);
- do { MASK(ps[--i]->Symbol) = 0; } while (i != 0);
- }
-}
+/* Ppmd7Dec.c -- Ppmd7z (PPMdH with 7z Range Coder) Decoder
+2023-04-02 : Igor Pavlov : Public domain
+This code is based on:
+ PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+
+#include "Precomp.h"
+
+#include "Ppmd7.h"
+
+#define kTopValue ((UInt32)1 << 24)
+
+
+#define READ_BYTE(p) IByteIn_Read((p)->Stream)
+
+BoolInt Ppmd7z_RangeDec_Init(CPpmd7_RangeDec *p)
+{
+ unsigned i;
+ p->Code = 0;
+ p->Range = 0xFFFFFFFF;
+ if (READ_BYTE(p) != 0)
+ return False;
+ for (i = 0; i < 4; i++)
+ p->Code = (p->Code << 8) | READ_BYTE(p);
+ return (p->Code < 0xFFFFFFFF);
+}
+
+#define RC_NORM_BASE(p) if ((p)->Range < kTopValue) \
+ { (p)->Code = ((p)->Code << 8) | READ_BYTE(p); (p)->Range <<= 8;
+
+#define RC_NORM_1(p) RC_NORM_BASE(p) }
+#define RC_NORM(p) RC_NORM_BASE(p) RC_NORM_BASE(p) }}
+
+// we must use only one type of Normalization from two: LOCAL or REMOTE
+#define RC_NORM_LOCAL(p) // RC_NORM(p)
+#define RC_NORM_REMOTE(p) RC_NORM(p)
+
+#define R (&p->rc.dec)
+
+Z7_FORCE_INLINE
+// Z7_NO_INLINE
+static void Ppmd7z_RD_Decode(CPpmd7 *p, UInt32 start, UInt32 size)
+{
+
+
+ R->Code -= start * R->Range;
+ R->Range *= size;
+ RC_NORM_LOCAL(R)
+}
+
+#define RC_Decode(start, size) Ppmd7z_RD_Decode(p, start, size);
+#define RC_DecodeFinal(start, size) RC_Decode(start, size) RC_NORM_REMOTE(R)
+#define RC_GetThreshold(total) (R->Code / (R->Range /= (total)))
+
+
+#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref))
+// typedef CPpmd7_Context * CTX_PTR;
+#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p)
+void Ppmd7_UpdateModel(CPpmd7 *p);
+
+#define MASK(sym) ((unsigned char *)charMask)[sym]
+// Z7_FORCE_INLINE
+// static
+int Ppmd7z_DecodeSymbol(CPpmd7 *p)
+{
+ size_t charMask[256 / sizeof(size_t)];
+
+ if (p->MinContext->NumStats != 1)
+ {
+ CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
+ unsigned i;
+ UInt32 count, hiCnt;
+ const UInt32 summFreq = p->MinContext->Union2.SummFreq;
+
+
+
+
+ count = RC_GetThreshold(summFreq);
+ hiCnt = count;
+
+ if ((Int32)(count -= s->Freq) < 0)
+ {
+ Byte sym;
+ RC_DecodeFinal(0, s->Freq)
+ p->FoundState = s;
+ sym = s->Symbol;
+ Ppmd7_Update1_0(p);
+ return sym;
+ }
+
+ p->PrevSuccess = 0;
+ i = (unsigned)p->MinContext->NumStats - 1;
+
+ do
+ {
+ if ((Int32)(count -= (++s)->Freq) < 0)
+ {
+ Byte sym;
+ RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq)
+ p->FoundState = s;
+ sym = s->Symbol;
+ Ppmd7_Update1(p);
+ return sym;
+ }
+ }
+ while (--i);
+
+ if (hiCnt >= summFreq)
+ return PPMD7_SYM_ERROR;
+
+ hiCnt -= count;
+ RC_Decode(hiCnt, summFreq - hiCnt)
+
+ p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol);
+ PPMD_SetAllBitsIn256Bytes(charMask)
+ // i = p->MinContext->NumStats - 1;
+ // do { MASK((--s)->Symbol) = 0; } while (--i);
+ {
+ CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext);
+ MASK(s->Symbol) = 0;
+ do
+ {
+ unsigned sym0 = s2[0].Symbol;
+ unsigned sym1 = s2[1].Symbol;
+ s2 += 2;
+ MASK(sym0) = 0;
+ MASK(sym1) = 0;
+ }
+ while (s2 < s);
+ }
+ }
+ else
+ {
+ CPpmd_State *s = Ppmd7Context_OneState(p->MinContext);
+ UInt16 *prob = Ppmd7_GetBinSumm(p);
+ UInt32 pr = *prob;
+ UInt32 size0 = (R->Range >> 14) * pr;
+ pr = PPMD_UPDATE_PROB_1(pr);
+
+ if (R->Code < size0)
+ {
+ Byte sym;
+ *prob = (UInt16)(pr + (1 << PPMD_INT_BITS));
+
+ // RangeDec_DecodeBit0(size0);
+ R->Range = size0;
+ RC_NORM_1(R)
+ /* we can use single byte normalization here because of
+ (min(BinSumm[][]) = 95) > (1 << (14 - 8)) */
+
+ // sym = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol;
+ // Ppmd7_UpdateBin(p);
+ {
+ unsigned freq = s->Freq;
+ CPpmd7_Context *c = CTX(SUCCESSOR(s));
+ sym = s->Symbol;
+ p->FoundState = s;
+ p->PrevSuccess = 1;
+ p->RunLength++;
+ s->Freq = (Byte)(freq + (freq < 128));
+ // NextContext(p);
+ if (p->OrderFall == 0 && (const Byte *)c > p->Text)
+ p->MaxContext = p->MinContext = c;
+ else
+ Ppmd7_UpdateModel(p);
+ }
+ return sym;
+ }
+
+ *prob = (UInt16)pr;
+ p->InitEsc = p->ExpEscape[pr >> 10];
+
+ // RangeDec_DecodeBit1(size0);
+
+ R->Code -= size0;
+ R->Range -= size0;
+ RC_NORM_LOCAL(R)
+
+ PPMD_SetAllBitsIn256Bytes(charMask)
+ MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0;
+ p->PrevSuccess = 0;
+ }
+
+ for (;;)
+ {
+ CPpmd_State *s, *s2;
+ UInt32 freqSum, count, hiCnt;
+
+ CPpmd_See *see;
+ CPpmd7_Context *mc;
+ unsigned numMasked;
+ RC_NORM_REMOTE(R)
+ mc = p->MinContext;
+ numMasked = mc->NumStats;
+
+ do
+ {
+ p->OrderFall++;
+ if (!mc->Suffix)
+ return PPMD7_SYM_END;
+ mc = Ppmd7_GetContext(p, mc->Suffix);
+ }
+ while (mc->NumStats == numMasked);
+
+ s = Ppmd7_GetStats(p, mc);
+
+ {
+ unsigned num = mc->NumStats;
+ unsigned num2 = num / 2;
+
+ num &= 1;
+ hiCnt = (s->Freq & (unsigned)(MASK(s->Symbol))) & (0 - (UInt32)num);
+ s += num;
+ p->MinContext = mc;
+
+ do
+ {
+ unsigned sym0 = s[0].Symbol;
+ unsigned sym1 = s[1].Symbol;
+ s += 2;
+ hiCnt += (s[-2].Freq & (unsigned)(MASK(sym0)));
+ hiCnt += (s[-1].Freq & (unsigned)(MASK(sym1)));
+ }
+ while (--num2);
+ }
+
+ see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum);
+ freqSum += hiCnt;
+
+
+
+
+ count = RC_GetThreshold(freqSum);
+
+ if (count < hiCnt)
+ {
+ Byte sym;
+
+ s = Ppmd7_GetStats(p, p->MinContext);
+ hiCnt = count;
+ // count -= s->Freq & (unsigned)(MASK(s->Symbol));
+ // if ((Int32)count >= 0)
+ {
+ for (;;)
+ {
+ count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break;
+ // count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break;
+ }
+ }
+ s--;
+ RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq)
+
+ // new (see->Summ) value can overflow over 16-bits in some rare cases
+ Ppmd_See_UPDATE(see)
+ p->FoundState = s;
+ sym = s->Symbol;
+ Ppmd7_Update2(p);
+ return sym;
+ }
+
+ if (count >= freqSum)
+ return PPMD7_SYM_ERROR;
+
+ RC_Decode(hiCnt, freqSum - hiCnt)
+
+ // We increase (see->Summ) for sum of Freqs of all non_Masked symbols.
+ // new (see->Summ) value can overflow over 16-bits in some rare cases
+ see->Summ = (UInt16)(see->Summ + freqSum);
+
+ s = Ppmd7_GetStats(p, p->MinContext);
+ s2 = s + p->MinContext->NumStats;
+ do
+ {
+ MASK(s->Symbol) = 0;
+ s++;
+ }
+ while (s != s2);
+ }
+}
+
+/*
+Byte *Ppmd7z_DecodeSymbols(CPpmd7 *p, Byte *buf, const Byte *lim)
+{
+ int sym = 0;
+ if (buf != lim)
+ do
+ {
+ sym = Ppmd7z_DecodeSymbol(p);
+ if (sym < 0)
+ break;
+ *buf = (Byte)sym;
+ }
+ while (++buf < lim);
+ p->LastSymbol = sym;
+ return buf;
+}
+*/
+
+#undef kTopValue
+#undef READ_BYTE
+#undef RC_NORM_BASE
+#undef RC_NORM_1
+#undef RC_NORM
+#undef RC_NORM_LOCAL
+#undef RC_NORM_REMOTE
+#undef R
+#undef RC_Decode
+#undef RC_DecodeFinal
+#undef RC_GetThreshold
+#undef CTX
+#undef SUCCESSOR
+#undef MASK
diff --git a/C/Ppmd7Enc.c b/C/Ppmd7Enc.c
index a74d300..41106ba 100644
--- a/C/Ppmd7Enc.c
+++ b/C/Ppmd7Enc.c
@@ -1,187 +1,338 @@
-/* Ppmd7Enc.c -- PPMdH Encoder
-2017-04-03 : Igor Pavlov : Public domain
-This code is based on PPMd var.H (2001): Dmitry Shkarin : Public domain */
-
-#include "Precomp.h"
-
-#include "Ppmd7.h"
-
-#define kTopValue (1 << 24)
-
-void Ppmd7z_RangeEnc_Init(CPpmd7z_RangeEnc *p)
-{
- p->Low = 0;
- p->Range = 0xFFFFFFFF;
- p->Cache = 0;
- p->CacheSize = 1;
-}
-
-static void RangeEnc_ShiftLow(CPpmd7z_RangeEnc *p)
-{
- if ((UInt32)p->Low < (UInt32)0xFF000000 || (unsigned)(p->Low >> 32) != 0)
- {
- Byte temp = p->Cache;
- do
- {
- IByteOut_Write(p->Stream, (Byte)(temp + (Byte)(p->Low >> 32)));
- temp = 0xFF;
- }
- while (--p->CacheSize != 0);
- p->Cache = (Byte)((UInt32)p->Low >> 24);
- }
- p->CacheSize++;
- p->Low = (UInt32)p->Low << 8;
-}
-
-static void RangeEnc_Encode(CPpmd7z_RangeEnc *p, UInt32 start, UInt32 size, UInt32 total)
-{
- p->Low += start * (p->Range /= total);
- p->Range *= size;
- while (p->Range < kTopValue)
- {
- p->Range <<= 8;
- RangeEnc_ShiftLow(p);
- }
-}
-
-static void RangeEnc_EncodeBit_0(CPpmd7z_RangeEnc *p, UInt32 size0)
-{
- p->Range = (p->Range >> 14) * size0;
- while (p->Range < kTopValue)
- {
- p->Range <<= 8;
- RangeEnc_ShiftLow(p);
- }
-}
-
-static void RangeEnc_EncodeBit_1(CPpmd7z_RangeEnc *p, UInt32 size0)
-{
- UInt32 newBound = (p->Range >> 14) * size0;
- p->Low += newBound;
- p->Range -= newBound;
- while (p->Range < kTopValue)
- {
- p->Range <<= 8;
- RangeEnc_ShiftLow(p);
- }
-}
-
-void Ppmd7z_RangeEnc_FlushData(CPpmd7z_RangeEnc *p)
-{
- unsigned i;
- for (i = 0; i < 5; i++)
- RangeEnc_ShiftLow(p);
-}
-
-
-#define MASK(sym) ((signed char *)charMask)[sym]
-
-void Ppmd7_EncodeSymbol(CPpmd7 *p, CPpmd7z_RangeEnc *rc, int symbol)
-{
- size_t charMask[256 / sizeof(size_t)];
- if (p->MinContext->NumStats != 1)
- {
- CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
- UInt32 sum;
- unsigned i;
- if (s->Symbol == symbol)
- {
- RangeEnc_Encode(rc, 0, s->Freq, p->MinContext->SummFreq);
- p->FoundState = s;
- Ppmd7_Update1_0(p);
- return;
- }
- p->PrevSuccess = 0;
- sum = s->Freq;
- i = p->MinContext->NumStats - 1;
- do
- {
- if ((++s)->Symbol == symbol)
- {
- RangeEnc_Encode(rc, sum, s->Freq, p->MinContext->SummFreq);
- p->FoundState = s;
- Ppmd7_Update1(p);
- return;
- }
- sum += s->Freq;
- }
- while (--i);
-
- p->HiBitsFlag = p->HB2Flag[p->FoundState->Symbol];
- PPMD_SetAllBitsIn256Bytes(charMask);
- MASK(s->Symbol) = 0;
- i = p->MinContext->NumStats - 1;
- do { MASK((--s)->Symbol) = 0; } while (--i);
- RangeEnc_Encode(rc, sum, p->MinContext->SummFreq - sum, p->MinContext->SummFreq);
- }
- else
- {
- UInt16 *prob = Ppmd7_GetBinSumm(p);
- CPpmd_State *s = Ppmd7Context_OneState(p->MinContext);
- if (s->Symbol == symbol)
- {
- RangeEnc_EncodeBit_0(rc, *prob);
- *prob = (UInt16)PPMD_UPDATE_PROB_0(*prob);
- p->FoundState = s;
- Ppmd7_UpdateBin(p);
- return;
- }
- else
- {
- RangeEnc_EncodeBit_1(rc, *prob);
- *prob = (UInt16)PPMD_UPDATE_PROB_1(*prob);
- p->InitEsc = PPMD7_kExpEscape[*prob >> 10];
- PPMD_SetAllBitsIn256Bytes(charMask);
- MASK(s->Symbol) = 0;
- p->PrevSuccess = 0;
- }
- }
- for (;;)
- {
- UInt32 escFreq;
- CPpmd_See *see;
- CPpmd_State *s;
- UInt32 sum;
- unsigned i, numMasked = p->MinContext->NumStats;
- do
- {
- p->OrderFall++;
- if (!p->MinContext->Suffix)
- return; /* EndMarker (symbol = -1) */
- p->MinContext = Ppmd7_GetContext(p, p->MinContext->Suffix);
- }
- while (p->MinContext->NumStats == numMasked);
-
- see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq);
- s = Ppmd7_GetStats(p, p->MinContext);
- sum = 0;
- i = p->MinContext->NumStats;
- do
- {
- int cur = s->Symbol;
- if (cur == symbol)
- {
- UInt32 low = sum;
- CPpmd_State *s1 = s;
- do
- {
- sum += (s->Freq & (int)(MASK(s->Symbol)));
- s++;
- }
- while (--i);
- RangeEnc_Encode(rc, low, s1->Freq, sum + escFreq);
- Ppmd_See_Update(see);
- p->FoundState = s1;
- Ppmd7_Update2(p);
- return;
- }
- sum += (s->Freq & (int)(MASK(cur)));
- MASK(cur) = 0;
- s++;
- }
- while (--i);
-
- RangeEnc_Encode(rc, sum, escFreq, sum + escFreq);
- see->Summ = (UInt16)(see->Summ + sum + escFreq);
- }
-}
+/* Ppmd7Enc.c -- Ppmd7z (PPMdH with 7z Range Coder) Encoder
+2023-04-02 : Igor Pavlov : Public domain
+This code is based on:
+ PPMd var.H (2001): Dmitry Shkarin : Public domain */
+
+
+#include "Precomp.h"
+
+#include "Ppmd7.h"
+
+#define kTopValue ((UInt32)1 << 24)
+
+#define R (&p->rc.enc)
+
+void Ppmd7z_Init_RangeEnc(CPpmd7 *p)
+{
+ R->Low = 0;
+ R->Range = 0xFFFFFFFF;
+ R->Cache = 0;
+ R->CacheSize = 1;
+}
+
+Z7_NO_INLINE
+static void Ppmd7z_RangeEnc_ShiftLow(CPpmd7 *p)
+{
+ if ((UInt32)R->Low < (UInt32)0xFF000000 || (unsigned)(R->Low >> 32) != 0)
+ {
+ Byte temp = R->Cache;
+ do
+ {
+ IByteOut_Write(R->Stream, (Byte)(temp + (Byte)(R->Low >> 32)));
+ temp = 0xFF;
+ }
+ while (--R->CacheSize != 0);
+ R->Cache = (Byte)((UInt32)R->Low >> 24);
+ }
+ R->CacheSize++;
+ R->Low = (UInt32)((UInt32)R->Low << 8);
+}
+
+#define RC_NORM_BASE(p) if (R->Range < kTopValue) { R->Range <<= 8; Ppmd7z_RangeEnc_ShiftLow(p);
+#define RC_NORM_1(p) RC_NORM_BASE(p) }
+#define RC_NORM(p) RC_NORM_BASE(p) RC_NORM_BASE(p) }}
+
+// we must use only one type of Normalization from two: LOCAL or REMOTE
+#define RC_NORM_LOCAL(p) // RC_NORM(p)
+#define RC_NORM_REMOTE(p) RC_NORM(p)
+
+/*
+#define Ppmd7z_RangeEnc_Encode(p, start, _size_) \
+ { UInt32 size = _size_; \
+ R->Low += start * R->Range; \
+ R->Range *= size; \
+ RC_NORM_LOCAL(p); }
+*/
+
+Z7_FORCE_INLINE
+// Z7_NO_INLINE
+static void Ppmd7z_RangeEnc_Encode(CPpmd7 *p, UInt32 start, UInt32 size)
+{
+ R->Low += start * R->Range;
+ R->Range *= size;
+ RC_NORM_LOCAL(p)
+}
+
+void Ppmd7z_Flush_RangeEnc(CPpmd7 *p)
+{
+ unsigned i;
+ for (i = 0; i < 5; i++)
+ Ppmd7z_RangeEnc_ShiftLow(p);
+}
+
+
+
+#define RC_Encode(start, size) Ppmd7z_RangeEnc_Encode(p, start, size);
+#define RC_EncodeFinal(start, size) RC_Encode(start, size) RC_NORM_REMOTE(p)
+
+#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref))
+#define SUFFIX(ctx) CTX((ctx)->Suffix)
+// typedef CPpmd7_Context * CTX_PTR;
+#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p)
+
+void Ppmd7_UpdateModel(CPpmd7 *p);
+
+#define MASK(sym) ((unsigned char *)charMask)[sym]
+
+Z7_FORCE_INLINE
+static
+void Ppmd7z_EncodeSymbol(CPpmd7 *p, int symbol)
+{
+ size_t charMask[256 / sizeof(size_t)];
+
+ if (p->MinContext->NumStats != 1)
+ {
+ CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
+ UInt32 sum;
+ unsigned i;
+
+
+
+
+ R->Range /= p->MinContext->Union2.SummFreq;
+
+ if (s->Symbol == symbol)
+ {
+ // R->Range /= p->MinContext->Union2.SummFreq;
+ RC_EncodeFinal(0, s->Freq)
+ p->FoundState = s;
+ Ppmd7_Update1_0(p);
+ return;
+ }
+ p->PrevSuccess = 0;
+ sum = s->Freq;
+ i = (unsigned)p->MinContext->NumStats - 1;
+ do
+ {
+ if ((++s)->Symbol == symbol)
+ {
+ // R->Range /= p->MinContext->Union2.SummFreq;
+ RC_EncodeFinal(sum, s->Freq)
+ p->FoundState = s;
+ Ppmd7_Update1(p);
+ return;
+ }
+ sum += s->Freq;
+ }
+ while (--i);
+
+ // R->Range /= p->MinContext->Union2.SummFreq;
+ RC_Encode(sum, p->MinContext->Union2.SummFreq - sum)
+
+ p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol);
+ PPMD_SetAllBitsIn256Bytes(charMask)
+ // MASK(s->Symbol) = 0;
+ // i = p->MinContext->NumStats - 1;
+ // do { MASK((--s)->Symbol) = 0; } while (--i);
+ {
+ CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext);
+ MASK(s->Symbol) = 0;
+ do
+ {
+ unsigned sym0 = s2[0].Symbol;
+ unsigned sym1 = s2[1].Symbol;
+ s2 += 2;
+ MASK(sym0) = 0;
+ MASK(sym1) = 0;
+ }
+ while (s2 < s);
+ }
+ }
+ else
+ {
+ UInt16 *prob = Ppmd7_GetBinSumm(p);
+ CPpmd_State *s = Ppmd7Context_OneState(p->MinContext);
+ UInt32 pr = *prob;
+ const UInt32 bound = (R->Range >> 14) * pr;
+ pr = PPMD_UPDATE_PROB_1(pr);
+ if (s->Symbol == symbol)
+ {
+ *prob = (UInt16)(pr + (1 << PPMD_INT_BITS));
+ // RangeEnc_EncodeBit_0(p, bound);
+ R->Range = bound;
+ RC_NORM_1(p)
+
+ // p->FoundState = s;
+ // Ppmd7_UpdateBin(p);
+ {
+ const unsigned freq = s->Freq;
+ CPpmd7_Context *c = CTX(SUCCESSOR(s));
+ p->FoundState = s;
+ p->PrevSuccess = 1;
+ p->RunLength++;
+ s->Freq = (Byte)(freq + (freq < 128));
+ // NextContext(p);
+ if (p->OrderFall == 0 && (const Byte *)c > p->Text)
+ p->MaxContext = p->MinContext = c;
+ else
+ Ppmd7_UpdateModel(p);
+ }
+ return;
+ }
+
+ *prob = (UInt16)pr;
+ p->InitEsc = p->ExpEscape[pr >> 10];
+ // RangeEnc_EncodeBit_1(p, bound);
+ R->Low += bound;
+ R->Range -= bound;
+ RC_NORM_LOCAL(p)
+
+ PPMD_SetAllBitsIn256Bytes(charMask)
+ MASK(s->Symbol) = 0;
+ p->PrevSuccess = 0;
+ }
+
+ for (;;)
+ {
+ CPpmd_See *see;
+ CPpmd_State *s;
+ UInt32 sum, escFreq;
+ CPpmd7_Context *mc;
+ unsigned i, numMasked;
+
+ RC_NORM_REMOTE(p)
+
+ mc = p->MinContext;
+ numMasked = mc->NumStats;
+
+ do
+ {
+ p->OrderFall++;
+ if (!mc->Suffix)
+ return; /* EndMarker (symbol = -1) */
+ mc = Ppmd7_GetContext(p, mc->Suffix);
+ i = mc->NumStats;
+ }
+ while (i == numMasked);
+
+ p->MinContext = mc;
+
+ // see = Ppmd7_MakeEscFreq(p, numMasked, &escFreq);
+ {
+ if (i != 256)
+ {
+ unsigned nonMasked = i - numMasked;
+ see = p->See[(unsigned)p->NS2Indx[(size_t)nonMasked - 1]]
+ + p->HiBitsFlag
+ + (nonMasked < (unsigned)SUFFIX(mc)->NumStats - i)
+ + 2 * (unsigned)(mc->Union2.SummFreq < 11 * i)
+ + 4 * (unsigned)(numMasked > nonMasked);
+ {
+ // if (see->Summ) field is larger than 16-bit, we need only low 16 bits of Summ
+ unsigned summ = (UInt16)see->Summ; // & 0xFFFF
+ unsigned r = (summ >> see->Shift);
+ see->Summ = (UInt16)(summ - r);
+ escFreq = r + (r == 0);
+ }
+ }
+ else
+ {
+ see = &p->DummySee;
+ escFreq = 1;
+ }
+ }
+
+ s = Ppmd7_GetStats(p, mc);
+ sum = 0;
+ // i = mc->NumStats;
+
+ do
+ {
+ const unsigned cur = s->Symbol;
+ if ((int)cur == symbol)
+ {
+ const UInt32 low = sum;
+ const UInt32 freq = s->Freq;
+ unsigned num2;
+
+ Ppmd_See_UPDATE(see)
+ p->FoundState = s;
+ sum += escFreq;
+
+ num2 = i / 2;
+ i &= 1;
+ sum += freq & (0 - (UInt32)i);
+ if (num2 != 0)
+ {
+ s += i;
+ for (;;)
+ {
+ unsigned sym0 = s[0].Symbol;
+ unsigned sym1 = s[1].Symbol;
+ s += 2;
+ sum += (s[-2].Freq & (unsigned)(MASK(sym0)));
+ sum += (s[-1].Freq & (unsigned)(MASK(sym1)));
+ if (--num2 == 0)
+ break;
+ }
+ }
+
+
+ R->Range /= sum;
+ RC_EncodeFinal(low, freq)
+ Ppmd7_Update2(p);
+ return;
+ }
+ sum += (s->Freq & (unsigned)(MASK(cur)));
+ s++;
+ }
+ while (--i);
+
+ {
+ const UInt32 total = sum + escFreq;
+ see->Summ = (UInt16)(see->Summ + total);
+
+ R->Range /= total;
+ RC_Encode(sum, escFreq)
+ }
+
+ {
+ const CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext);
+ s--;
+ MASK(s->Symbol) = 0;
+ do
+ {
+ const unsigned sym0 = s2[0].Symbol;
+ const unsigned sym1 = s2[1].Symbol;
+ s2 += 2;
+ MASK(sym0) = 0;
+ MASK(sym1) = 0;
+ }
+ while (s2 < s);
+ }
+ }
+}
+
+
+void Ppmd7z_EncodeSymbols(CPpmd7 *p, const Byte *buf, const Byte *lim)
+{
+ for (; buf < lim; buf++)
+ {
+ Ppmd7z_EncodeSymbol(p, *buf);
+ }
+}
+
+#undef kTopValue
+#undef WRITE_BYTE
+#undef RC_NORM_BASE
+#undef RC_NORM_1
+#undef RC_NORM
+#undef RC_NORM_LOCAL
+#undef RC_NORM_REMOTE
+#undef R
+#undef RC_Encode
+#undef RC_EncodeFinal
+#undef SUFFIX
+#undef CTX
+#undef SUCCESSOR
+#undef MASK
diff --git a/C/Ppmd7aDec.c b/C/Ppmd7aDec.c
new file mode 100644
index 0000000..55e164e
--- /dev/null
+++ b/C/Ppmd7aDec.c
@@ -0,0 +1,295 @@
+/* Ppmd7aDec.c -- PPMd7a (PPMdH) Decoder
+2023-04-02 : Igor Pavlov : Public domain
+This code is based on:
+ PPMd var.H (2001): Dmitry Shkarin : Public domain
+ Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#include "Precomp.h"
+
+#include "Ppmd7.h"
+
+#define kTop ((UInt32)1 << 24)
+#define kBot ((UInt32)1 << 15)
+
+#define READ_BYTE(p) IByteIn_Read((p)->Stream)
+
+BoolInt Ppmd7a_RangeDec_Init(CPpmd7_RangeDec *p)
+{
+ unsigned i;
+ p->Code = 0;
+ p->Range = 0xFFFFFFFF;
+ p->Low = 0;
+
+ for (i = 0; i < 4; i++)
+ p->Code = (p->Code << 8) | READ_BYTE(p);
+ return (p->Code < 0xFFFFFFFF);
+}
+
+#define RC_NORM(p) \
+ while ((p->Low ^ (p->Low + p->Range)) < kTop \
+ || (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) { \
+ p->Code = (p->Code << 8) | READ_BYTE(p); \
+ p->Range <<= 8; p->Low <<= 8; }
+
+// we must use only one type of Normalization from two: LOCAL or REMOTE
+#define RC_NORM_LOCAL(p) // RC_NORM(p)
+#define RC_NORM_REMOTE(p) RC_NORM(p)
+
+#define R (&p->rc.dec)
+
+Z7_FORCE_INLINE
+// Z7_NO_INLINE
+static void Ppmd7a_RD_Decode(CPpmd7 *p, UInt32 start, UInt32 size)
+{
+ start *= R->Range;
+ R->Low += start;
+ R->Code -= start;
+ R->Range *= size;
+ RC_NORM_LOCAL(R)
+}
+
+#define RC_Decode(start, size) Ppmd7a_RD_Decode(p, start, size);
+#define RC_DecodeFinal(start, size) RC_Decode(start, size) RC_NORM_REMOTE(R)
+#define RC_GetThreshold(total) (R->Code / (R->Range /= (total)))
+
+
+#define CTX(ref) ((CPpmd7_Context *)Ppmd7_GetContext(p, ref))
+typedef CPpmd7_Context * CTX_PTR;
+#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p)
+void Ppmd7_UpdateModel(CPpmd7 *p);
+
+#define MASK(sym) ((unsigned char *)charMask)[sym]
+
+
+int Ppmd7a_DecodeSymbol(CPpmd7 *p)
+{
+ size_t charMask[256 / sizeof(size_t)];
+
+ if (p->MinContext->NumStats != 1)
+ {
+ CPpmd_State *s = Ppmd7_GetStats(p, p->MinContext);
+ unsigned i;
+ UInt32 count, hiCnt;
+ const UInt32 summFreq = p->MinContext->Union2.SummFreq;
+
+ if (summFreq > R->Range)
+ return PPMD7_SYM_ERROR;
+
+ count = RC_GetThreshold(summFreq);
+ hiCnt = count;
+
+ if ((Int32)(count -= s->Freq) < 0)
+ {
+ Byte sym;
+ RC_DecodeFinal(0, s->Freq)
+ p->FoundState = s;
+ sym = s->Symbol;
+ Ppmd7_Update1_0(p);
+ return sym;
+ }
+
+ p->PrevSuccess = 0;
+ i = (unsigned)p->MinContext->NumStats - 1;
+
+ do
+ {
+ if ((Int32)(count -= (++s)->Freq) < 0)
+ {
+ Byte sym;
+ RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq)
+ p->FoundState = s;
+ sym = s->Symbol;
+ Ppmd7_Update1(p);
+ return sym;
+ }
+ }
+ while (--i);
+
+ if (hiCnt >= summFreq)
+ return PPMD7_SYM_ERROR;
+
+ hiCnt -= count;
+ RC_Decode(hiCnt, summFreq - hiCnt)
+
+ p->HiBitsFlag = PPMD7_HiBitsFlag_3(p->FoundState->Symbol);
+ PPMD_SetAllBitsIn256Bytes(charMask)
+ // i = p->MinContext->NumStats - 1;
+ // do { MASK((--s)->Symbol) = 0; } while (--i);
+ {
+ CPpmd_State *s2 = Ppmd7_GetStats(p, p->MinContext);
+ MASK(s->Symbol) = 0;
+ do
+ {
+ unsigned sym0 = s2[0].Symbol;
+ unsigned sym1 = s2[1].Symbol;
+ s2 += 2;
+ MASK(sym0) = 0;
+ MASK(sym1) = 0;
+ }
+ while (s2 < s);
+ }
+ }
+ else
+ {
+ CPpmd_State *s = Ppmd7Context_OneState(p->MinContext);
+ UInt16 *prob = Ppmd7_GetBinSumm(p);
+ UInt32 pr = *prob;
+ UInt32 size0 = (R->Range >> 14) * pr;
+ pr = PPMD_UPDATE_PROB_1(pr);
+
+ if (R->Code < size0)
+ {
+ Byte sym;
+ *prob = (UInt16)(pr + (1 << PPMD_INT_BITS));
+
+ // RangeDec_DecodeBit0(size0);
+ R->Range = size0;
+ RC_NORM(R)
+
+
+
+ // sym = (p->FoundState = Ppmd7Context_OneState(p->MinContext))->Symbol;
+ // Ppmd7_UpdateBin(p);
+ {
+ unsigned freq = s->Freq;
+ CTX_PTR c = CTX(SUCCESSOR(s));
+ sym = s->Symbol;
+ p->FoundState = s;
+ p->PrevSuccess = 1;
+ p->RunLength++;
+ s->Freq = (Byte)(freq + (freq < 128));
+ // NextContext(p);
+ if (p->OrderFall == 0 && (const Byte *)c > p->Text)
+ p->MaxContext = p->MinContext = c;
+ else
+ Ppmd7_UpdateModel(p);
+ }
+ return sym;
+ }
+
+ *prob = (UInt16)pr;
+ p->InitEsc = p->ExpEscape[pr >> 10];
+
+ // RangeDec_DecodeBit1(size0);
+ R->Low += size0;
+ R->Code -= size0;
+ R->Range = (R->Range & ~((UInt32)PPMD_BIN_SCALE - 1)) - size0;
+ RC_NORM_LOCAL(R)
+
+ PPMD_SetAllBitsIn256Bytes(charMask)
+ MASK(Ppmd7Context_OneState(p->MinContext)->Symbol) = 0;
+ p->PrevSuccess = 0;
+ }
+
+ for (;;)
+ {
+ CPpmd_State *s, *s2;
+ UInt32 freqSum, count, hiCnt;
+
+ CPpmd_See *see;
+ CPpmd7_Context *mc;
+ unsigned numMasked;
+ RC_NORM_REMOTE(R)
+ mc = p->MinContext;
+ numMasked = mc->NumStats;
+
+ do
+ {
+ p->OrderFall++;
+ if (!mc->Suffix)
+ return PPMD7_SYM_END;
+ mc = Ppmd7_GetContext(p, mc->Suffix);
+ }
+ while (mc->NumStats == numMasked);
+
+ s = Ppmd7_GetStats(p, mc);
+
+ {
+ unsigned num = mc->NumStats;
+ unsigned num2 = num / 2;
+
+ num &= 1;
+ hiCnt = (s->Freq & (unsigned)(MASK(s->Symbol))) & (0 - (UInt32)num);
+ s += num;
+ p->MinContext = mc;
+
+ do
+ {
+ unsigned sym0 = s[0].Symbol;
+ unsigned sym1 = s[1].Symbol;
+ s += 2;
+ hiCnt += (s[-2].Freq & (unsigned)(MASK(sym0)));
+ hiCnt += (s[-1].Freq & (unsigned)(MASK(sym1)));
+ }
+ while (--num2);
+ }
+
+ see = Ppmd7_MakeEscFreq(p, numMasked, &freqSum);
+ freqSum += hiCnt;
+
+ if (freqSum > R->Range)
+ return PPMD7_SYM_ERROR;
+
+ count = RC_GetThreshold(freqSum);
+
+ if (count < hiCnt)
+ {
+ Byte sym;
+
+ s = Ppmd7_GetStats(p, p->MinContext);
+ hiCnt = count;
+ // count -= s->Freq & (unsigned)(MASK(s->Symbol));
+ // if ((Int32)count >= 0)
+ {
+ for (;;)
+ {
+ count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break;
+ // count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break;
+ }
+ }
+ s--;
+ RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq)
+
+ // new (see->Summ) value can overflow over 16-bits in some rare cases
+ Ppmd_See_UPDATE(see)
+ p->FoundState = s;
+ sym = s->Symbol;
+ Ppmd7_Update2(p);
+ return sym;
+ }
+
+ if (count >= freqSum)
+ return PPMD7_SYM_ERROR;
+
+ RC_Decode(hiCnt, freqSum - hiCnt)
+
+ // We increase (see->Summ) for sum of Freqs of all non_Masked symbols.
+ // new (see->Summ) value can overflow over 16-bits in some rare cases
+ see->Summ = (UInt16)(see->Summ + freqSum);
+
+ s = Ppmd7_GetStats(p, p->MinContext);
+ s2 = s + p->MinContext->NumStats;
+ do
+ {
+ MASK(s->Symbol) = 0;
+ s++;
+ }
+ while (s != s2);
+ }
+}
+
+#undef kTop
+#undef kBot
+#undef READ_BYTE
+#undef RC_NORM_BASE
+#undef RC_NORM_1
+#undef RC_NORM
+#undef RC_NORM_LOCAL
+#undef RC_NORM_REMOTE
+#undef R
+#undef RC_Decode
+#undef RC_DecodeFinal
+#undef RC_GetThreshold
+#undef CTX
+#undef SUCCESSOR
+#undef MASK
diff --git a/C/Ppmd8.c b/C/Ppmd8.c
new file mode 100644
index 0000000..28abf27
--- /dev/null
+++ b/C/Ppmd8.c
@@ -0,0 +1,1565 @@
+/* Ppmd8.c -- PPMdI codec
+2023-04-02 : Igor Pavlov : Public domain
+This code is based on PPMd var.I (2002): Dmitry Shkarin : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#include "Ppmd8.h"
+
+
+
+
+MY_ALIGN(16)
+static const Byte PPMD8_kExpEscape[16] = { 25, 14, 9, 7, 5, 5, 4, 4, 4, 3, 3, 3, 2, 2, 2, 2 };
+MY_ALIGN(16)
+static const UInt16 PPMD8_kInitBinEsc[] = { 0x3CDD, 0x1F3F, 0x59BF, 0x48F3, 0x64A1, 0x5ABC, 0x6632, 0x6051};
+
+#define MAX_FREQ 124
+#define UNIT_SIZE 12
+
+#define U2B(nu) ((UInt32)(nu) * UNIT_SIZE)
+#define U2I(nu) (p->Units2Indx[(size_t)(nu) - 1])
+#define I2U(indx) ((unsigned)p->Indx2Units[indx])
+
+
+#define REF(ptr) Ppmd_GetRef(p, ptr)
+
+#define STATS_REF(ptr) ((CPpmd_State_Ref)REF(ptr))
+
+#define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref))
+#define STATS(ctx) Ppmd8_GetStats(p, ctx)
+#define ONE_STATE(ctx) Ppmd8Context_OneState(ctx)
+#define SUFFIX(ctx) CTX((ctx)->Suffix)
+
+typedef CPpmd8_Context * PPMD8_CTX_PTR;
+
+struct CPpmd8_Node_;
+
+typedef Ppmd_Ref_Type(struct CPpmd8_Node_) CPpmd8_Node_Ref;
+
+typedef struct CPpmd8_Node_
+{
+ UInt32 Stamp;
+
+ CPpmd8_Node_Ref Next;
+ UInt32 NU;
+} CPpmd8_Node;
+
+#define NODE(r) Ppmd_GetPtr_Type(p, r, CPpmd8_Node)
+
+void Ppmd8_Construct(CPpmd8 *p)
+{
+ unsigned i, k, m;
+
+ p->Base = NULL;
+
+ for (i = 0, k = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ unsigned step = (i >= 12 ? 4 : (i >> 2) + 1);
+ do { p->Units2Indx[k++] = (Byte)i; } while (--step);
+ p->Indx2Units[i] = (Byte)k;
+ }
+
+ p->NS2BSIndx[0] = (0 << 1);
+ p->NS2BSIndx[1] = (1 << 1);
+ memset(p->NS2BSIndx + 2, (2 << 1), 9);
+ memset(p->NS2BSIndx + 11, (3 << 1), 256 - 11);
+
+ for (i = 0; i < 5; i++)
+ p->NS2Indx[i] = (Byte)i;
+
+ for (m = i, k = 1; i < 260; i++)
+ {
+ p->NS2Indx[i] = (Byte)m;
+ if (--k == 0)
+ k = (++m) - 4;
+ }
+
+ memcpy(p->ExpEscape, PPMD8_kExpEscape, 16);
+}
+
+
+void Ppmd8_Free(CPpmd8 *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->Base);
+ p->Size = 0;
+ p->Base = NULL;
+}
+
+
+BoolInt Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAllocPtr alloc)
+{
+ if (!p->Base || p->Size != size)
+ {
+ Ppmd8_Free(p, alloc);
+ p->AlignOffset = (4 - size) & 3;
+ if ((p->Base = (Byte *)ISzAlloc_Alloc(alloc, p->AlignOffset + size)) == NULL)
+ return False;
+ p->Size = size;
+ }
+ return True;
+}
+
+
+
+// ---------- Internal Memory Allocator ----------
+
+
+
+
+
+
+#define EMPTY_NODE 0xFFFFFFFF
+
+
+static void Ppmd8_InsertNode(CPpmd8 *p, void *node, unsigned indx)
+{
+ ((CPpmd8_Node *)node)->Stamp = EMPTY_NODE;
+ ((CPpmd8_Node *)node)->Next = (CPpmd8_Node_Ref)p->FreeList[indx];
+ ((CPpmd8_Node *)node)->NU = I2U(indx);
+ p->FreeList[indx] = REF(node);
+ p->Stamps[indx]++;
+}
+
+
+static void *Ppmd8_RemoveNode(CPpmd8 *p, unsigned indx)
+{
+ CPpmd8_Node *node = NODE((CPpmd8_Node_Ref)p->FreeList[indx]);
+ p->FreeList[indx] = node->Next;
+ p->Stamps[indx]--;
+
+ return node;
+}
+
+
+static void Ppmd8_SplitBlock(CPpmd8 *p, void *ptr, unsigned oldIndx, unsigned newIndx)
+{
+ unsigned i, nu = I2U(oldIndx) - I2U(newIndx);
+ ptr = (Byte *)ptr + U2B(I2U(newIndx));
+ if (I2U(i = U2I(nu)) != nu)
+ {
+ unsigned k = I2U(--i);
+ Ppmd8_InsertNode(p, ((Byte *)ptr) + U2B(k), nu - k - 1);
+ }
+ Ppmd8_InsertNode(p, ptr, i);
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+static void Ppmd8_GlueFreeBlocks(CPpmd8 *p)
+{
+ /*
+ we use first UInt32 field of 12-bytes UNITs as record type stamp
+ CPpmd_State { Byte Symbol; Byte Freq; : Freq != 0xFF
+ CPpmd8_Context { Byte NumStats; Byte Flags; UInt16 SummFreq; : Flags != 0xFF ???
+ CPpmd8_Node { UInt32 Stamp : Stamp == 0xFFFFFFFF for free record
+ : Stamp == 0 for guard
+ Last 12-bytes UNIT in array is always contains 12-bytes order-0 CPpmd8_Context record
+ */
+ CPpmd8_Node_Ref n;
+
+ p->GlueCount = 1 << 13;
+ memset(p->Stamps, 0, sizeof(p->Stamps));
+
+ /* we set guard NODE at LoUnit */
+ if (p->LoUnit != p->HiUnit)
+ ((CPpmd8_Node *)(void *)p->LoUnit)->Stamp = 0;
+
+ {
+ /* Glue free blocks */
+ CPpmd8_Node_Ref *prev = &n;
+ unsigned i;
+ for (i = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+
+ CPpmd8_Node_Ref next = (CPpmd8_Node_Ref)p->FreeList[i];
+ p->FreeList[i] = 0;
+ while (next != 0)
+ {
+ CPpmd8_Node *node = NODE(next);
+ UInt32 nu = node->NU;
+ *prev = next;
+ next = node->Next;
+ if (nu != 0)
+ {
+ CPpmd8_Node *node2;
+ prev = &(node->Next);
+ while ((node2 = node + nu)->Stamp == EMPTY_NODE)
+ {
+ nu += node2->NU;
+ node2->NU = 0;
+ node->NU = nu;
+ }
+ }
+ }
+ }
+
+ *prev = 0;
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ /* Fill lists of free blocks */
+ while (n != 0)
+ {
+ CPpmd8_Node *node = NODE(n);
+ UInt32 nu = node->NU;
+ unsigned i;
+ n = node->Next;
+ if (nu == 0)
+ continue;
+ for (; nu > 128; nu -= 128, node += 128)
+ Ppmd8_InsertNode(p, node, PPMD_NUM_INDEXES - 1);
+ if (I2U(i = U2I(nu)) != nu)
+ {
+ unsigned k = I2U(--i);
+ Ppmd8_InsertNode(p, node + k, (unsigned)nu - k - 1);
+ }
+ Ppmd8_InsertNode(p, node, i);
+ }
+}
+
+
+Z7_NO_INLINE
+static void *Ppmd8_AllocUnitsRare(CPpmd8 *p, unsigned indx)
+{
+ unsigned i;
+
+ if (p->GlueCount == 0)
+ {
+ Ppmd8_GlueFreeBlocks(p);
+ if (p->FreeList[indx] != 0)
+ return Ppmd8_RemoveNode(p, indx);
+ }
+
+ i = indx;
+
+ do
+ {
+ if (++i == PPMD_NUM_INDEXES)
+ {
+ UInt32 numBytes = U2B(I2U(indx));
+ Byte *us = p->UnitsStart;
+ p->GlueCount--;
+ return ((UInt32)(us - p->Text) > numBytes) ? (p->UnitsStart = us - numBytes) : (NULL);
+ }
+ }
+ while (p->FreeList[i] == 0);
+
+ {
+ void *block = Ppmd8_RemoveNode(p, i);
+ Ppmd8_SplitBlock(p, block, i, indx);
+ return block;
+ }
+}
+
+
+static void *Ppmd8_AllocUnits(CPpmd8 *p, unsigned indx)
+{
+ if (p->FreeList[indx] != 0)
+ return Ppmd8_RemoveNode(p, indx);
+ {
+ UInt32 numBytes = U2B(I2U(indx));
+ Byte *lo = p->LoUnit;
+ if ((UInt32)(p->HiUnit - lo) >= numBytes)
+ {
+ p->LoUnit = lo + numBytes;
+ return lo;
+ }
+ }
+ return Ppmd8_AllocUnitsRare(p, indx);
+}
+
+
+#define MEM_12_CPY(dest, src, num) \
+ { UInt32 *d = (UInt32 *)dest; const UInt32 *z = (const UInt32 *)src; UInt32 n = num; \
+ do { d[0] = z[0]; d[1] = z[1]; d[2] = z[2]; z += 3; d += 3; } while (--n); }
+
+
+
+static void *ShrinkUnits(CPpmd8 *p, void *oldPtr, unsigned oldNU, unsigned newNU)
+{
+ unsigned i0 = U2I(oldNU);
+ unsigned i1 = U2I(newNU);
+ if (i0 == i1)
+ return oldPtr;
+ if (p->FreeList[i1] != 0)
+ {
+ void *ptr = Ppmd8_RemoveNode(p, i1);
+ MEM_12_CPY(ptr, oldPtr, newNU)
+ Ppmd8_InsertNode(p, oldPtr, i0);
+ return ptr;
+ }
+ Ppmd8_SplitBlock(p, oldPtr, i0, i1);
+ return oldPtr;
+}
+
+
+static void FreeUnits(CPpmd8 *p, void *ptr, unsigned nu)
+{
+ Ppmd8_InsertNode(p, ptr, U2I(nu));
+}
+
+
+static void SpecialFreeUnit(CPpmd8 *p, void *ptr)
+{
+ if ((Byte *)ptr != p->UnitsStart)
+ Ppmd8_InsertNode(p, ptr, 0);
+ else
+ {
+ #ifdef PPMD8_FREEZE_SUPPORT
+ *(UInt32 *)ptr = EMPTY_NODE; /* it's used for (Flags == 0xFF) check in RemoveBinContexts() */
+ #endif
+ p->UnitsStart += UNIT_SIZE;
+ }
+}
+
+
+/*
+static void *MoveUnitsUp(CPpmd8 *p, void *oldPtr, unsigned nu)
+{
+ unsigned indx = U2I(nu);
+ void *ptr;
+ if ((Byte *)oldPtr > p->UnitsStart + (1 << 14) || REF(oldPtr) > p->FreeList[indx])
+ return oldPtr;
+ ptr = Ppmd8_RemoveNode(p, indx);
+ MEM_12_CPY(ptr, oldPtr, nu)
+ if ((Byte *)oldPtr != p->UnitsStart)
+ Ppmd8_InsertNode(p, oldPtr, indx);
+ else
+ p->UnitsStart += U2B(I2U(indx));
+ return ptr;
+}
+*/
+
+static void ExpandTextArea(CPpmd8 *p)
+{
+ UInt32 count[PPMD_NUM_INDEXES];
+ unsigned i;
+
+ memset(count, 0, sizeof(count));
+ if (p->LoUnit != p->HiUnit)
+ ((CPpmd8_Node *)(void *)p->LoUnit)->Stamp = 0;
+
+ {
+ CPpmd8_Node *node = (CPpmd8_Node *)(void *)p->UnitsStart;
+ while (node->Stamp == EMPTY_NODE)
+ {
+ UInt32 nu = node->NU;
+ node->Stamp = 0;
+ count[U2I(nu)]++;
+ node += nu;
+ }
+ p->UnitsStart = (Byte *)node;
+ }
+
+ for (i = 0; i < PPMD_NUM_INDEXES; i++)
+ {
+ UInt32 cnt = count[i];
+ if (cnt == 0)
+ continue;
+ {
+ CPpmd8_Node_Ref *prev = (CPpmd8_Node_Ref *)&p->FreeList[i];
+ CPpmd8_Node_Ref n = *prev;
+ p->Stamps[i] -= cnt;
+ for (;;)
+ {
+ CPpmd8_Node *node = NODE(n);
+ n = node->Next;
+ if (node->Stamp != 0)
+ {
+ prev = &node->Next;
+ continue;
+ }
+ *prev = n;
+ if (--cnt == 0)
+ break;
+ }
+ }
+ }
+}
+
+
+#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p)
+static void Ppmd8State_SetSuccessor(CPpmd_State *p, CPpmd_Void_Ref v)
+{
+ Ppmd_SET_SUCCESSOR(p, v)
+}
+
+#define RESET_TEXT(offs) { p->Text = p->Base + p->AlignOffset + (offs); }
+
+Z7_NO_INLINE
+static
+void Ppmd8_RestartModel(CPpmd8 *p)
+{
+ unsigned i, k, m;
+
+ memset(p->FreeList, 0, sizeof(p->FreeList));
+ memset(p->Stamps, 0, sizeof(p->Stamps));
+ RESET_TEXT(0)
+ p->HiUnit = p->Text + p->Size;
+ p->LoUnit = p->UnitsStart = p->HiUnit - p->Size / 8 / UNIT_SIZE * 7 * UNIT_SIZE;
+ p->GlueCount = 0;
+
+ p->OrderFall = p->MaxOrder;
+ p->RunLength = p->InitRL = -(Int32)((p->MaxOrder < 12) ? p->MaxOrder : 12) - 1;
+ p->PrevSuccess = 0;
+
+ {
+ CPpmd8_Context *mc = (PPMD8_CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE); /* AllocContext(p); */
+ CPpmd_State *s = (CPpmd_State *)p->LoUnit; /* Ppmd8_AllocUnits(p, PPMD_NUM_INDEXES - 1); */
+
+ p->LoUnit += U2B(256 / 2);
+ p->MaxContext = p->MinContext = mc;
+ p->FoundState = s;
+ mc->Flags = 0;
+ mc->NumStats = 256 - 1;
+ mc->Union2.SummFreq = 256 + 1;
+ mc->Union4.Stats = REF(s);
+ mc->Suffix = 0;
+
+ for (i = 0; i < 256; i++, s++)
+ {
+ s->Symbol = (Byte)i;
+ s->Freq = 1;
+ Ppmd8State_SetSuccessor(s, 0);
+ }
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+ for (i = m = 0; m < 25; m++)
+ {
+ while (p->NS2Indx[i] == m)
+ i++;
+ for (k = 0; k < 8; k++)
+ {
+ unsigned r;
+ UInt16 *dest = p->BinSumm[m] + k;
+ const UInt16 val = (UInt16)(PPMD_BIN_SCALE - PPMD8_kInitBinEsc[k] / (i + 1));
+ for (r = 0; r < 64; r += 8)
+ dest[r] = val;
+ }
+ }
+
+ for (i = m = 0; m < 24; m++)
+ {
+ unsigned summ;
+ CPpmd_See *s;
+ while (p->NS2Indx[(size_t)i + 3] == m + 3)
+ i++;
+ s = p->See[m];
+ summ = ((2 * i + 5) << (PPMD_PERIOD_BITS - 4));
+ for (k = 0; k < 32; k++, s++)
+ {
+ s->Summ = (UInt16)summ;
+ s->Shift = (PPMD_PERIOD_BITS - 4);
+ s->Count = 7;
+ }
+ }
+
+ p->DummySee.Summ = 0; /* unused */
+ p->DummySee.Shift = PPMD_PERIOD_BITS;
+ p->DummySee.Count = 64; /* unused */
+}
+
+
+void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod)
+{
+ p->MaxOrder = maxOrder;
+ p->RestoreMethod = restoreMethod;
+ Ppmd8_RestartModel(p);
+}
+
+
+#define FLAG_RESCALED (1 << 2)
+// #define FLAG_SYM_HIGH (1 << 3)
+#define FLAG_PREV_HIGH (1 << 4)
+
+#define HiBits_Prepare(sym) ((unsigned)(sym) + 0xC0)
+
+#define HiBits_Convert_3(flags) (((flags) >> (8 - 3)) & (1 << 3))
+#define HiBits_Convert_4(flags) (((flags) >> (8 - 4)) & (1 << 4))
+
+#define PPMD8_HiBitsFlag_3(sym) HiBits_Convert_3(HiBits_Prepare(sym))
+#define PPMD8_HiBitsFlag_4(sym) HiBits_Convert_4(HiBits_Prepare(sym))
+
+// #define PPMD8_HiBitsFlag_3(sym) (0x08 * ((sym) >= 0x40))
+// #define PPMD8_HiBitsFlag_4(sym) (0x10 * ((sym) >= 0x40))
+
+/*
+Refresh() is called when we remove some symbols (successors) in context.
+It increases Escape_Freq for sum of all removed symbols.
+*/
+
+static void Refresh(CPpmd8 *p, PPMD8_CTX_PTR ctx, unsigned oldNU, unsigned scale)
+{
+ unsigned i = ctx->NumStats, escFreq, sumFreq, flags;
+ CPpmd_State *s = (CPpmd_State *)ShrinkUnits(p, STATS(ctx), oldNU, (i + 2) >> 1);
+ ctx->Union4.Stats = REF(s);
+
+ // #ifdef PPMD8_FREEZE_SUPPORT
+ /*
+ (ctx->Union2.SummFreq >= ((UInt32)1 << 15)) can be in FREEZE mode for some files.
+ It's not good for range coder. So new versions of support fix:
+ - original PPMdI code rev.1
+ + original PPMdI code rev.2
+ - 7-Zip default ((PPMD8_FREEZE_SUPPORT is not defined)
+ + 7-Zip (p->RestoreMethod >= PPMD8_RESTORE_METHOD_FREEZE)
+ if we use that fixed line, we can lose compatibility with some files created before fix
+ if we don't use that fixed line, the program can work incorrectly in FREEZE mode in rare case.
+ */
+ // if (p->RestoreMethod >= PPMD8_RESTORE_METHOD_FREEZE)
+ {
+ scale |= (ctx->Union2.SummFreq >= ((UInt32)1 << 15));
+ }
+ // #endif
+
+
+
+ flags = HiBits_Prepare(s->Symbol);
+ {
+ unsigned freq = s->Freq;
+ escFreq = ctx->Union2.SummFreq - freq;
+ freq = (freq + scale) >> scale;
+ sumFreq = freq;
+ s->Freq = (Byte)freq;
+ }
+
+ do
+ {
+ unsigned freq = (++s)->Freq;
+ escFreq -= freq;
+ freq = (freq + scale) >> scale;
+ sumFreq += freq;
+ s->Freq = (Byte)freq;
+ flags |= HiBits_Prepare(s->Symbol);
+ }
+ while (--i);
+
+ ctx->Union2.SummFreq = (UInt16)(sumFreq + ((escFreq + scale) >> scale));
+ ctx->Flags = (Byte)((ctx->Flags & (FLAG_PREV_HIGH + FLAG_RESCALED * scale)) + HiBits_Convert_3(flags));
+}
+
+
+static void SWAP_STATES(CPpmd_State *t1, CPpmd_State *t2)
+{
+ CPpmd_State tmp = *t1;
+ *t1 = *t2;
+ *t2 = tmp;
+}
+
+
+/*
+CutOff() reduces contexts:
+ It conversts Successors at MaxOrder to another Contexts to NULL-Successors
+ It removes RAW-Successors and NULL-Successors that are not Order-0
+ and it removes contexts when it has no Successors.
+ if the (Union4.Stats) is close to (UnitsStart), it moves it up.
+*/
+
+static CPpmd_Void_Ref CutOff(CPpmd8 *p, PPMD8_CTX_PTR ctx, unsigned order)
+{
+ int ns = ctx->NumStats;
+ unsigned nu;
+ CPpmd_State *stats;
+
+ if (ns == 0)
+ {
+ CPpmd_State *s = ONE_STATE(ctx);
+ CPpmd_Void_Ref successor = SUCCESSOR(s);
+ if ((Byte *)Ppmd8_GetPtr(p, successor) >= p->UnitsStart)
+ {
+ if (order < p->MaxOrder)
+ successor = CutOff(p, CTX(successor), order + 1);
+ else
+ successor = 0;
+ Ppmd8State_SetSuccessor(s, successor);
+ if (successor || order <= 9) /* O_BOUND */
+ return REF(ctx);
+ }
+ SpecialFreeUnit(p, ctx);
+ return 0;
+ }
+
+ nu = ((unsigned)ns + 2) >> 1;
+ // ctx->Union4.Stats = STATS_REF(MoveUnitsUp(p, STATS(ctx), nu));
+ {
+ unsigned indx = U2I(nu);
+ stats = STATS(ctx);
+
+ if ((UInt32)((Byte *)stats - p->UnitsStart) <= (1 << 14)
+ && (CPpmd_Void_Ref)ctx->Union4.Stats <= p->FreeList[indx])
+ {
+ void *ptr = Ppmd8_RemoveNode(p, indx);
+ ctx->Union4.Stats = STATS_REF(ptr);
+ MEM_12_CPY(ptr, (const void *)stats, nu)
+ if ((Byte *)stats != p->UnitsStart)
+ Ppmd8_InsertNode(p, stats, indx);
+ else
+ p->UnitsStart += U2B(I2U(indx));
+ stats = ptr;
+ }
+ }
+
+ {
+ CPpmd_State *s = stats + (unsigned)ns;
+ do
+ {
+ CPpmd_Void_Ref successor = SUCCESSOR(s);
+ if ((Byte *)Ppmd8_GetPtr(p, successor) < p->UnitsStart)
+ {
+ CPpmd_State *s2 = stats + (unsigned)(ns--);
+ if (order)
+ {
+ if (s != s2)
+ *s = *s2;
+ }
+ else
+ {
+ SWAP_STATES(s, s2);
+ Ppmd8State_SetSuccessor(s2, 0);
+ }
+ }
+ else
+ {
+ if (order < p->MaxOrder)
+ Ppmd8State_SetSuccessor(s, CutOff(p, CTX(successor), order + 1));
+ else
+ Ppmd8State_SetSuccessor(s, 0);
+ }
+ }
+ while (--s >= stats);
+ }
+
+ if (ns != ctx->NumStats && order)
+ {
+ if (ns < 0)
+ {
+ FreeUnits(p, stats, nu);
+ SpecialFreeUnit(p, ctx);
+ return 0;
+ }
+ ctx->NumStats = (Byte)ns;
+ if (ns == 0)
+ {
+ const Byte sym = stats->Symbol;
+ ctx->Flags = (Byte)((ctx->Flags & FLAG_PREV_HIGH) + PPMD8_HiBitsFlag_3(sym));
+ // *ONE_STATE(ctx) = *stats;
+ ctx->Union2.State2.Symbol = sym;
+ ctx->Union2.State2.Freq = (Byte)(((unsigned)stats->Freq + 11) >> 3);
+ ctx->Union4.State4.Successor_0 = stats->Successor_0;
+ ctx->Union4.State4.Successor_1 = stats->Successor_1;
+ FreeUnits(p, stats, nu);
+ }
+ else
+ {
+ Refresh(p, ctx, nu, ctx->Union2.SummFreq > 16 * (unsigned)ns);
+ }
+ }
+
+ return REF(ctx);
+}
+
+
+
+#ifdef PPMD8_FREEZE_SUPPORT
+
+/*
+RemoveBinContexts()
+ It conversts Successors at MaxOrder to another Contexts to NULL-Successors
+ It changes RAW-Successors to NULL-Successors
+ removes Bin Context without Successor, if suffix of that context is also binary.
+*/
+
+static CPpmd_Void_Ref RemoveBinContexts(CPpmd8 *p, PPMD8_CTX_PTR ctx, unsigned order)
+{
+ if (!ctx->NumStats)
+ {
+ CPpmd_State *s = ONE_STATE(ctx);
+ CPpmd_Void_Ref successor = SUCCESSOR(s);
+ if ((Byte *)Ppmd8_GetPtr(p, successor) >= p->UnitsStart && order < p->MaxOrder)
+ successor = RemoveBinContexts(p, CTX(successor), order + 1);
+ else
+ successor = 0;
+ Ppmd8State_SetSuccessor(s, successor);
+ /* Suffix context can be removed already, since different (high-order)
+ Successors may refer to same context. So we check Flags == 0xFF (Stamp == EMPTY_NODE) */
+ if (!successor && (!SUFFIX(ctx)->NumStats || SUFFIX(ctx)->Flags == 0xFF))
+ {
+ FreeUnits(p, ctx, 1);
+ return 0;
+ }
+ }
+ else
+ {
+ CPpmd_State *s = STATS(ctx) + ctx->NumStats;
+ do
+ {
+ CPpmd_Void_Ref successor = SUCCESSOR(s);
+ if ((Byte *)Ppmd8_GetPtr(p, successor) >= p->UnitsStart && order < p->MaxOrder)
+ Ppmd8State_SetSuccessor(s, RemoveBinContexts(p, CTX(successor), order + 1));
+ else
+ Ppmd8State_SetSuccessor(s, 0);
+ }
+ while (--s >= STATS(ctx));
+ }
+
+ return REF(ctx);
+}
+
+#endif
+
+
+
+static UInt32 GetUsedMemory(const CPpmd8 *p)
+{
+ UInt32 v = 0;
+ unsigned i;
+ for (i = 0; i < PPMD_NUM_INDEXES; i++)
+ v += p->Stamps[i] * I2U(i);
+ return p->Size - (UInt32)(p->HiUnit - p->LoUnit) - (UInt32)(p->UnitsStart - p->Text) - U2B(v);
+}
+
+#ifdef PPMD8_FREEZE_SUPPORT
+ #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1, fSuccessor)
+#else
+ #define RESTORE_MODEL(c1, fSuccessor) RestoreModel(p, c1)
+#endif
+
+
+static void RestoreModel(CPpmd8 *p, PPMD8_CTX_PTR ctxError
+ #ifdef PPMD8_FREEZE_SUPPORT
+ , PPMD8_CTX_PTR fSuccessor
+ #endif
+ )
+{
+ PPMD8_CTX_PTR c;
+ CPpmd_State *s;
+ RESET_TEXT(0)
+
+ // we go here in cases of error of allocation for context (c1)
+ // Order(MinContext) < Order(ctxError) <= Order(MaxContext)
+
+ // We remove last symbol from each of contexts [p->MaxContext ... ctxError) contexts
+ // So we rollback all created (symbols) before error.
+ for (c = p->MaxContext; c != ctxError; c = SUFFIX(c))
+ if (--(c->NumStats) == 0)
+ {
+ s = STATS(c);
+ c->Flags = (Byte)((c->Flags & FLAG_PREV_HIGH) + PPMD8_HiBitsFlag_3(s->Symbol));
+ // *ONE_STATE(c) = *s;
+ c->Union2.State2.Symbol = s->Symbol;
+ c->Union2.State2.Freq = (Byte)(((unsigned)s->Freq + 11) >> 3);
+ c->Union4.State4.Successor_0 = s->Successor_0;
+ c->Union4.State4.Successor_1 = s->Successor_1;
+
+ SpecialFreeUnit(p, s);
+ }
+ else
+ {
+ /* Refresh() can increase Escape_Freq on value of Freq of last symbol, that was added before error.
+ so the largest possible increase for Escape_Freq is (8) from value before ModelUpoadet() */
+ Refresh(p, c, ((unsigned)c->NumStats + 3) >> 1, 0);
+ }
+
+ // increase Escape Freq for context [ctxError ... p->MinContext)
+ for (; c != p->MinContext; c = SUFFIX(c))
+ if (c->NumStats == 0)
+ {
+ // ONE_STATE(c)
+ c->Union2.State2.Freq = (Byte)(((unsigned)c->Union2.State2.Freq + 1) >> 1);
+ }
+ else if ((c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 4)) > 128 + 4 * c->NumStats)
+ Refresh(p, c, ((unsigned)c->NumStats + 2) >> 1, 1);
+
+ #ifdef PPMD8_FREEZE_SUPPORT
+ if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
+ {
+ p->MaxContext = fSuccessor;
+ p->GlueCount += !(p->Stamps[1] & 1); // why?
+ }
+ else if (p->RestoreMethod == PPMD8_RESTORE_METHOD_FREEZE)
+ {
+ while (p->MaxContext->Suffix)
+ p->MaxContext = SUFFIX(p->MaxContext);
+ RemoveBinContexts(p, p->MaxContext, 0);
+ // we change the current mode to (PPMD8_RESTORE_METHOD_FREEZE + 1)
+ p->RestoreMethod = PPMD8_RESTORE_METHOD_FREEZE + 1;
+ p->GlueCount = 0;
+ p->OrderFall = p->MaxOrder;
+ }
+ else
+ #endif
+ if (p->RestoreMethod == PPMD8_RESTORE_METHOD_RESTART || GetUsedMemory(p) < (p->Size >> 1))
+ Ppmd8_RestartModel(p);
+ else
+ {
+ while (p->MaxContext->Suffix)
+ p->MaxContext = SUFFIX(p->MaxContext);
+ do
+ {
+ CutOff(p, p->MaxContext, 0);
+ ExpandTextArea(p);
+ }
+ while (GetUsedMemory(p) > 3 * (p->Size >> 2));
+ p->GlueCount = 0;
+ p->OrderFall = p->MaxOrder;
+ }
+ p->MinContext = p->MaxContext;
+}
+
+
+
+Z7_NO_INLINE
+static PPMD8_CTX_PTR Ppmd8_CreateSuccessors(CPpmd8 *p, BoolInt skip, CPpmd_State *s1, PPMD8_CTX_PTR c)
+{
+
+ CPpmd_Byte_Ref upBranch = (CPpmd_Byte_Ref)SUCCESSOR(p->FoundState);
+ Byte newSym, newFreq, flags;
+ unsigned numPs = 0;
+ CPpmd_State *ps[PPMD8_MAX_ORDER + 1]; /* fixed over Shkarin's code. Maybe it could work without + 1 too. */
+
+ if (!skip)
+ ps[numPs++] = p->FoundState;
+
+ while (c->Suffix)
+ {
+ CPpmd_Void_Ref successor;
+ CPpmd_State *s;
+ c = SUFFIX(c);
+
+ if (s1) { s = s1; s1 = NULL; }
+ else if (c->NumStats != 0)
+ {
+ Byte sym = p->FoundState->Symbol;
+ for (s = STATS(c); s->Symbol != sym; s++);
+ if (s->Freq < MAX_FREQ - 9) { s->Freq++; c->Union2.SummFreq++; }
+ }
+ else
+ {
+ s = ONE_STATE(c);
+ s->Freq = (Byte)(s->Freq + (!SUFFIX(c)->NumStats & (s->Freq < 24)));
+ }
+ successor = SUCCESSOR(s);
+ if (successor != upBranch)
+ {
+
+ c = CTX(successor);
+ if (numPs == 0)
+ {
+
+
+ return c;
+ }
+ break;
+ }
+ ps[numPs++] = s;
+ }
+
+
+
+
+
+ newSym = *(const Byte *)Ppmd8_GetPtr(p, upBranch);
+ upBranch++;
+ flags = (Byte)(PPMD8_HiBitsFlag_4(p->FoundState->Symbol) + PPMD8_HiBitsFlag_3(newSym));
+
+ if (c->NumStats == 0)
+ newFreq = c->Union2.State2.Freq;
+ else
+ {
+ UInt32 cf, s0;
+ CPpmd_State *s;
+ for (s = STATS(c); s->Symbol != newSym; s++);
+ cf = (UInt32)s->Freq - 1;
+ s0 = (UInt32)c->Union2.SummFreq - c->NumStats - cf;
+ /*
+
+
+ max(newFreq)= (s->Freq - 1), when (s0 == 1)
+
+
+ */
+ newFreq = (Byte)(1 + ((2 * cf <= s0) ? (5 * cf > s0) : ((cf + 2 * s0 - 3) / s0)));
+ }
+
+
+
+ do
+ {
+ PPMD8_CTX_PTR c1;
+ /* = AllocContext(p); */
+ if (p->HiUnit != p->LoUnit)
+ c1 = (PPMD8_CTX_PTR)(void *)(p->HiUnit -= UNIT_SIZE);
+ else if (p->FreeList[0] != 0)
+ c1 = (PPMD8_CTX_PTR)Ppmd8_RemoveNode(p, 0);
+ else
+ {
+ c1 = (PPMD8_CTX_PTR)Ppmd8_AllocUnitsRare(p, 0);
+ if (!c1)
+ return NULL;
+ }
+ c1->Flags = flags;
+ c1->NumStats = 0;
+ c1->Union2.State2.Symbol = newSym;
+ c1->Union2.State2.Freq = newFreq;
+ Ppmd8State_SetSuccessor(ONE_STATE(c1), upBranch);
+ c1->Suffix = REF(c);
+ Ppmd8State_SetSuccessor(ps[--numPs], REF(c1));
+ c = c1;
+ }
+ while (numPs != 0);
+
+ return c;
+}
+
+
+static PPMD8_CTX_PTR ReduceOrder(CPpmd8 *p, CPpmd_State *s1, PPMD8_CTX_PTR c)
+{
+ CPpmd_State *s = NULL;
+ PPMD8_CTX_PTR c1 = c;
+ CPpmd_Void_Ref upBranch = REF(p->Text);
+
+ #ifdef PPMD8_FREEZE_SUPPORT
+ /* The BUG in Shkarin's code was fixed: ps could overflow in CUT_OFF mode. */
+ CPpmd_State *ps[PPMD8_MAX_ORDER + 1];
+ unsigned numPs = 0;
+ ps[numPs++] = p->FoundState;
+ #endif
+
+ Ppmd8State_SetSuccessor(p->FoundState, upBranch);
+ p->OrderFall++;
+
+ for (;;)
+ {
+ if (s1)
+ {
+ c = SUFFIX(c);
+ s = s1;
+ s1 = NULL;
+ }
+ else
+ {
+ if (!c->Suffix)
+ {
+ #ifdef PPMD8_FREEZE_SUPPORT
+ if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
+ {
+ do { Ppmd8State_SetSuccessor(ps[--numPs], REF(c)); } while (numPs);
+ RESET_TEXT(1)
+ p->OrderFall = 1;
+ }
+ #endif
+ return c;
+ }
+ c = SUFFIX(c);
+ if (c->NumStats)
+ {
+ if ((s = STATS(c))->Symbol != p->FoundState->Symbol)
+ do { s++; } while (s->Symbol != p->FoundState->Symbol);
+ if (s->Freq < MAX_FREQ - 9)
+ {
+ s->Freq = (Byte)(s->Freq + 2);
+ c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 2);
+ }
+ }
+ else
+ {
+ s = ONE_STATE(c);
+ s->Freq = (Byte)(s->Freq + (s->Freq < 32));
+ }
+ }
+ if (SUCCESSOR(s))
+ break;
+ #ifdef PPMD8_FREEZE_SUPPORT
+ ps[numPs++] = s;
+ #endif
+ Ppmd8State_SetSuccessor(s, upBranch);
+ p->OrderFall++;
+ }
+
+ #ifdef PPMD8_FREEZE_SUPPORT
+ if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
+ {
+ c = CTX(SUCCESSOR(s));
+ do { Ppmd8State_SetSuccessor(ps[--numPs], REF(c)); } while (numPs);
+ RESET_TEXT(1)
+ p->OrderFall = 1;
+ return c;
+ }
+ else
+ #endif
+ if (SUCCESSOR(s) <= upBranch)
+ {
+ PPMD8_CTX_PTR successor;
+ CPpmd_State *s2 = p->FoundState;
+ p->FoundState = s;
+
+ successor = Ppmd8_CreateSuccessors(p, False, NULL, c);
+ if (!successor)
+ Ppmd8State_SetSuccessor(s, 0);
+ else
+ Ppmd8State_SetSuccessor(s, REF(successor));
+ p->FoundState = s2;
+ }
+
+ {
+ CPpmd_Void_Ref successor = SUCCESSOR(s);
+ if (p->OrderFall == 1 && c1 == p->MaxContext)
+ {
+ Ppmd8State_SetSuccessor(p->FoundState, successor);
+ p->Text--;
+ }
+ if (successor == 0)
+ return NULL;
+ return CTX(successor);
+ }
+}
+
+
+
+void Ppmd8_UpdateModel(CPpmd8 *p);
+Z7_NO_INLINE
+void Ppmd8_UpdateModel(CPpmd8 *p)
+{
+ CPpmd_Void_Ref maxSuccessor, minSuccessor = SUCCESSOR(p->FoundState);
+ PPMD8_CTX_PTR c;
+ unsigned s0, ns, fFreq = p->FoundState->Freq;
+ Byte flag, fSymbol = p->FoundState->Symbol;
+ {
+ CPpmd_State *s = NULL;
+ if (p->FoundState->Freq < MAX_FREQ / 4 && p->MinContext->Suffix != 0)
+ {
+ /* Update Freqs in Suffix Context */
+
+ c = SUFFIX(p->MinContext);
+
+ if (c->NumStats == 0)
+ {
+ s = ONE_STATE(c);
+ if (s->Freq < 32)
+ s->Freq++;
+ }
+ else
+ {
+ Byte sym = p->FoundState->Symbol;
+ s = STATS(c);
+
+ if (s->Symbol != sym)
+ {
+ do
+ {
+
+ s++;
+ }
+ while (s->Symbol != sym);
+
+ if (s[0].Freq >= s[-1].Freq)
+ {
+ SWAP_STATES(&s[0], &s[-1]);
+ s--;
+ }
+ }
+
+ if (s->Freq < MAX_FREQ - 9)
+ {
+ s->Freq = (Byte)(s->Freq + 2);
+ c->Union2.SummFreq = (UInt16)(c->Union2.SummFreq + 2);
+ }
+ }
+ }
+
+ c = p->MaxContext;
+ if (p->OrderFall == 0 && minSuccessor)
+ {
+ PPMD8_CTX_PTR cs = Ppmd8_CreateSuccessors(p, True, s, p->MinContext);
+ if (!cs)
+ {
+ Ppmd8State_SetSuccessor(p->FoundState, 0);
+ RESTORE_MODEL(c, CTX(minSuccessor));
+ return;
+ }
+ Ppmd8State_SetSuccessor(p->FoundState, REF(cs));
+ p->MinContext = p->MaxContext = cs;
+ return;
+ }
+
+
+
+
+ {
+ Byte *text = p->Text;
+ *text++ = p->FoundState->Symbol;
+ p->Text = text;
+ if (text >= p->UnitsStart)
+ {
+ RESTORE_MODEL(c, CTX(minSuccessor)); /* check it */
+ return;
+ }
+ maxSuccessor = REF(text);
+ }
+
+ if (!minSuccessor)
+ {
+ PPMD8_CTX_PTR cs = ReduceOrder(p, s, p->MinContext);
+ if (!cs)
+ {
+ RESTORE_MODEL(c, NULL);
+ return;
+ }
+ minSuccessor = REF(cs);
+ }
+ else if ((Byte *)Ppmd8_GetPtr(p, minSuccessor) < p->UnitsStart)
+ {
+ PPMD8_CTX_PTR cs = Ppmd8_CreateSuccessors(p, False, s, p->MinContext);
+ if (!cs)
+ {
+ RESTORE_MODEL(c, NULL);
+ return;
+ }
+ minSuccessor = REF(cs);
+ }
+
+ if (--p->OrderFall == 0)
+ {
+ maxSuccessor = minSuccessor;
+ p->Text -= (p->MaxContext != p->MinContext);
+ }
+ #ifdef PPMD8_FREEZE_SUPPORT
+ else if (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE)
+ {
+ maxSuccessor = minSuccessor;
+ RESET_TEXT(0)
+ p->OrderFall = 0;
+ }
+ #endif
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ flag = (Byte)(PPMD8_HiBitsFlag_3(fSymbol));
+ s0 = p->MinContext->Union2.SummFreq - (ns = p->MinContext->NumStats) - fFreq;
+
+ for (; c != p->MinContext; c = SUFFIX(c))
+ {
+ unsigned ns1;
+ UInt32 sum;
+
+ if ((ns1 = c->NumStats) != 0)
+ {
+ if ((ns1 & 1) != 0)
+ {
+ /* Expand for one UNIT */
+ unsigned oldNU = (ns1 + 1) >> 1;
+ unsigned i = U2I(oldNU);
+ if (i != U2I((size_t)oldNU + 1))
+ {
+ void *ptr = Ppmd8_AllocUnits(p, i + 1);
+ void *oldPtr;
+ if (!ptr)
+ {
+ RESTORE_MODEL(c, CTX(minSuccessor));
+ return;
+ }
+ oldPtr = STATS(c);
+ MEM_12_CPY(ptr, oldPtr, oldNU)
+ Ppmd8_InsertNode(p, oldPtr, i);
+ c->Union4.Stats = STATS_REF(ptr);
+ }
+ }
+ sum = c->Union2.SummFreq;
+ /* max increase of Escape_Freq is 1 here.
+ an average increase is 1/3 per symbol */
+ sum += (3 * ns1 + 1 < ns);
+ /* original PPMdH uses 16-bit variable for (sum) here.
+ But (sum < ???). Do we need to truncate (sum) to 16-bit */
+ // sum = (UInt16)sum;
+ }
+ else
+ {
+
+ CPpmd_State *s = (CPpmd_State*)Ppmd8_AllocUnits(p, 0);
+ if (!s)
+ {
+ RESTORE_MODEL(c, CTX(minSuccessor));
+ return;
+ }
+ {
+ unsigned freq = c->Union2.State2.Freq;
+ // s = *ONE_STATE(c);
+ s->Symbol = c->Union2.State2.Symbol;
+ s->Successor_0 = c->Union4.State4.Successor_0;
+ s->Successor_1 = c->Union4.State4.Successor_1;
+ // Ppmd8State_SetSuccessor(s, c->Union4.Stats); // call it only for debug purposes to check the order of
+ // (Successor_0 and Successor_1) in LE/BE.
+ c->Union4.Stats = REF(s);
+ if (freq < MAX_FREQ / 4 - 1)
+ freq <<= 1;
+ else
+ freq = MAX_FREQ - 4;
+
+ s->Freq = (Byte)freq;
+
+ sum = freq + p->InitEsc + (ns > 2); // Ppmd8 (> 2)
+ }
+ }
+
+ {
+ CPpmd_State *s = STATS(c) + ns1 + 1;
+ UInt32 cf = 2 * (sum + 6) * (UInt32)fFreq;
+ UInt32 sf = (UInt32)s0 + sum;
+ s->Symbol = fSymbol;
+ c->NumStats = (Byte)(ns1 + 1);
+ Ppmd8State_SetSuccessor(s, maxSuccessor);
+ c->Flags |= flag;
+ if (cf < 6 * sf)
+ {
+ cf = (unsigned)1 + (cf > sf) + (cf >= 4 * sf);
+ sum += 4;
+ /* It can add (1, 2, 3) to Escape_Freq */
+ }
+ else
+ {
+ cf = (unsigned)4 + (cf > 9 * sf) + (cf > 12 * sf) + (cf > 15 * sf);
+ sum += cf;
+ }
+
+ c->Union2.SummFreq = (UInt16)sum;
+ s->Freq = (Byte)cf;
+ }
+
+ }
+ p->MaxContext = p->MinContext = CTX(minSuccessor);
+}
+
+
+
+Z7_NO_INLINE
+static void Ppmd8_Rescale(CPpmd8 *p)
+{
+ unsigned i, adder, sumFreq, escFreq;
+ CPpmd_State *stats = STATS(p->MinContext);
+ CPpmd_State *s = p->FoundState;
+
+ /* Sort the list by Freq */
+ if (s != stats)
+ {
+ CPpmd_State tmp = *s;
+ do
+ s[0] = s[-1];
+ while (--s != stats);
+ *s = tmp;
+ }
+
+ sumFreq = s->Freq;
+ escFreq = p->MinContext->Union2.SummFreq - sumFreq;
+
+
+
+
+
+
+ adder = (p->OrderFall != 0);
+
+ #ifdef PPMD8_FREEZE_SUPPORT
+ adder |= (p->RestoreMethod > PPMD8_RESTORE_METHOD_FREEZE);
+ #endif
+
+ sumFreq = (sumFreq + 4 + adder) >> 1;
+ i = p->MinContext->NumStats;
+ s->Freq = (Byte)sumFreq;
+
+ do
+ {
+ unsigned freq = (++s)->Freq;
+ escFreq -= freq;
+ freq = (freq + adder) >> 1;
+ sumFreq += freq;
+ s->Freq = (Byte)freq;
+ if (freq > s[-1].Freq)
+ {
+ CPpmd_State tmp = *s;
+ CPpmd_State *s1 = s;
+ do
+ {
+ s1[0] = s1[-1];
+ }
+ while (--s1 != stats && freq > s1[-1].Freq);
+ *s1 = tmp;
+ }
+ }
+ while (--i);
+
+ if (s->Freq == 0)
+ {
+ /* Remove all items with Freq == 0 */
+ CPpmd8_Context *mc;
+ unsigned numStats, numStatsNew, n0, n1;
+
+ i = 0; do { i++; } while ((--s)->Freq == 0);
+
+
+
+
+ escFreq += i;
+ mc = p->MinContext;
+ numStats = mc->NumStats;
+ numStatsNew = numStats - i;
+ mc->NumStats = (Byte)(numStatsNew);
+ n0 = (numStats + 2) >> 1;
+
+ if (numStatsNew == 0)
+ {
+
+ unsigned freq = (2 * (unsigned)stats->Freq + escFreq - 1) / escFreq;
+ if (freq > MAX_FREQ / 3)
+ freq = MAX_FREQ / 3;
+ mc->Flags = (Byte)((mc->Flags & FLAG_PREV_HIGH) + PPMD8_HiBitsFlag_3(stats->Symbol));
+
+
+
+
+
+ s = ONE_STATE(mc);
+ *s = *stats;
+ s->Freq = (Byte)freq;
+ p->FoundState = s;
+ Ppmd8_InsertNode(p, stats, U2I(n0));
+ return;
+ }
+
+ n1 = (numStatsNew + 2) >> 1;
+ if (n0 != n1)
+ mc->Union4.Stats = STATS_REF(ShrinkUnits(p, stats, n0, n1));
+ {
+ // here we are for max order only. So Ppmd8_MakeEscFreq() doesn't use mc->Flags
+ // but we still need current (Flags & FLAG_PREV_HIGH), if we will convert context to 1-symbol context later.
+ /*
+ unsigned flags = HiBits_Prepare((s = STATS(mc))->Symbol);
+ i = mc->NumStats;
+ do { flags |= HiBits_Prepare((++s)->Symbol); } while (--i);
+ mc->Flags = (Byte)((mc->Flags & ~FLAG_SYM_HIGH) + HiBits_Convert_3(flags));
+ */
+ }
+ }
+
+
+
+
+
+
+ {
+ CPpmd8_Context *mc = p->MinContext;
+ mc->Union2.SummFreq = (UInt16)(sumFreq + escFreq - (escFreq >> 1));
+ mc->Flags |= FLAG_RESCALED;
+ p->FoundState = STATS(mc);
+ }
+}
+
+
+CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked1, UInt32 *escFreq)
+{
+ CPpmd_See *see;
+ const CPpmd8_Context *mc = p->MinContext;
+ unsigned numStats = mc->NumStats;
+ if (numStats != 0xFF)
+ {
+ // (3 <= numStats + 2 <= 256) (3 <= NS2Indx[3] and NS2Indx[256] === 26)
+ see = p->See[(size_t)(unsigned)p->NS2Indx[(size_t)numStats + 2] - 3]
+ + (mc->Union2.SummFreq > 11 * (numStats + 1))
+ + 2 * (unsigned)(2 * numStats < ((unsigned)SUFFIX(mc)->NumStats + numMasked1))
+ + mc->Flags;
+
+ {
+ // if (see->Summ) field is larger than 16-bit, we need only low 16 bits of Summ
+ unsigned summ = (UInt16)see->Summ; // & 0xFFFF
+ unsigned r = (summ >> see->Shift);
+ see->Summ = (UInt16)(summ - r);
+ *escFreq = r + (r == 0);
+ }
+ }
+ else
+ {
+ see = &p->DummySee;
+ *escFreq = 1;
+ }
+ return see;
+}
+
+
+static void Ppmd8_NextContext(CPpmd8 *p)
+{
+ PPMD8_CTX_PTR c = CTX(SUCCESSOR(p->FoundState));
+ if (p->OrderFall == 0 && (const Byte *)c >= p->UnitsStart)
+ p->MaxContext = p->MinContext = c;
+ else
+ Ppmd8_UpdateModel(p);
+}
+
+
+void Ppmd8_Update1(CPpmd8 *p)
+{
+ CPpmd_State *s = p->FoundState;
+ unsigned freq = s->Freq;
+ freq += 4;
+ p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4);
+ s->Freq = (Byte)freq;
+ if (freq > s[-1].Freq)
+ {
+ SWAP_STATES(s, &s[-1]);
+ p->FoundState = --s;
+ if (freq > MAX_FREQ)
+ Ppmd8_Rescale(p);
+ }
+ Ppmd8_NextContext(p);
+}
+
+
+void Ppmd8_Update1_0(CPpmd8 *p)
+{
+ CPpmd_State *s = p->FoundState;
+ CPpmd8_Context *mc = p->MinContext;
+ unsigned freq = s->Freq;
+ unsigned summFreq = mc->Union2.SummFreq;
+ p->PrevSuccess = (2 * freq >= summFreq); // Ppmd8 (>=)
+ p->RunLength += (int)p->PrevSuccess;
+ mc->Union2.SummFreq = (UInt16)(summFreq + 4);
+ freq += 4;
+ s->Freq = (Byte)freq;
+ if (freq > MAX_FREQ)
+ Ppmd8_Rescale(p);
+ Ppmd8_NextContext(p);
+}
+
+
+/*
+void Ppmd8_UpdateBin(CPpmd8 *p)
+{
+ unsigned freq = p->FoundState->Freq;
+ p->FoundState->Freq = (Byte)(freq + (freq < 196)); // Ppmd8 (196)
+ p->PrevSuccess = 1;
+ p->RunLength++;
+ Ppmd8_NextContext(p);
+}
+*/
+
+void Ppmd8_Update2(CPpmd8 *p)
+{
+ CPpmd_State *s = p->FoundState;
+ unsigned freq = s->Freq;
+ freq += 4;
+ p->RunLength = p->InitRL;
+ p->MinContext->Union2.SummFreq = (UInt16)(p->MinContext->Union2.SummFreq + 4);
+ s->Freq = (Byte)freq;
+ if (freq > MAX_FREQ)
+ Ppmd8_Rescale(p);
+ Ppmd8_UpdateModel(p);
+}
+
+/* H->I changes:
+ NS2Indx
+ GlueCount, and Glue method
+ BinSum
+ See / EscFreq
+ Ppmd8_CreateSuccessors updates more suffix contexts
+ Ppmd8_UpdateModel consts.
+ PrevSuccess Update
+
+Flags:
+ (1 << 2) - the Context was Rescaled
+ (1 << 3) - there is symbol in Stats with (sym >= 0x40) in
+ (1 << 4) - main symbol of context is (sym >= 0x40)
+*/
+
+#undef RESET_TEXT
+#undef FLAG_RESCALED
+#undef FLAG_PREV_HIGH
+#undef HiBits_Prepare
+#undef HiBits_Convert_3
+#undef HiBits_Convert_4
+#undef PPMD8_HiBitsFlag_3
+#undef PPMD8_HiBitsFlag_4
+#undef RESTORE_MODEL
+
+#undef MAX_FREQ
+#undef UNIT_SIZE
+#undef U2B
+#undef U2I
+#undef I2U
+
+#undef REF
+#undef STATS_REF
+#undef CTX
+#undef STATS
+#undef ONE_STATE
+#undef SUFFIX
+#undef NODE
+#undef EMPTY_NODE
+#undef MEM_12_CPY
+#undef SUCCESSOR
+#undef SWAP_STATES
diff --git a/C/Ppmd8.h b/C/Ppmd8.h
new file mode 100644
index 0000000..d5bb57e
--- /dev/null
+++ b/C/Ppmd8.h
@@ -0,0 +1,181 @@
+/* Ppmd8.h -- Ppmd8 (PPMdI) compression codec
+2023-04-02 : Igor Pavlov : Public domain
+This code is based on:
+ PPMd var.I (2002): Dmitry Shkarin : Public domain
+ Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#ifndef ZIP7_INC_PPMD8_H
+#define ZIP7_INC_PPMD8_H
+
+#include "Ppmd.h"
+
+EXTERN_C_BEGIN
+
+#define PPMD8_MIN_ORDER 2
+#define PPMD8_MAX_ORDER 16
+
+
+
+
+struct CPpmd8_Context_;
+
+typedef Ppmd_Ref_Type(struct CPpmd8_Context_) CPpmd8_Context_Ref;
+
+// MY_CPU_pragma_pack_push_1
+
+typedef struct CPpmd8_Context_
+{
+ Byte NumStats;
+ Byte Flags;
+
+ union
+ {
+ UInt16 SummFreq;
+ CPpmd_State2 State2;
+ } Union2;
+
+ union
+ {
+ CPpmd_State_Ref Stats;
+ CPpmd_State4 State4;
+ } Union4;
+
+ CPpmd8_Context_Ref Suffix;
+} CPpmd8_Context;
+
+// MY_CPU_pragma_pop
+
+#define Ppmd8Context_OneState(p) ((CPpmd_State *)&(p)->Union2)
+
+/* PPMdI code rev.2 contains the fix over PPMdI code rev.1.
+ But the code PPMdI.2 is not compatible with PPMdI.1 for some files compressed
+ in FREEZE mode. So we disable FREEZE mode support. */
+
+// #define PPMD8_FREEZE_SUPPORT
+
+enum
+{
+ PPMD8_RESTORE_METHOD_RESTART,
+ PPMD8_RESTORE_METHOD_CUT_OFF
+ #ifdef PPMD8_FREEZE_SUPPORT
+ , PPMD8_RESTORE_METHOD_FREEZE
+ #endif
+ , PPMD8_RESTORE_METHOD_UNSUPPPORTED
+};
+
+
+
+
+
+
+
+
+typedef struct
+{
+ CPpmd8_Context *MinContext, *MaxContext;
+ CPpmd_State *FoundState;
+ unsigned OrderFall, InitEsc, PrevSuccess, MaxOrder, RestoreMethod;
+ Int32 RunLength, InitRL; /* must be 32-bit at least */
+
+ UInt32 Size;
+ UInt32 GlueCount;
+ UInt32 AlignOffset;
+ Byte *Base, *LoUnit, *HiUnit, *Text, *UnitsStart;
+
+ UInt32 Range;
+ UInt32 Code;
+ UInt32 Low;
+ union
+ {
+ IByteInPtr In;
+ IByteOutPtr Out;
+ } Stream;
+
+ Byte Indx2Units[PPMD_NUM_INDEXES + 2]; // +2 for alignment
+ Byte Units2Indx[128];
+ CPpmd_Void_Ref FreeList[PPMD_NUM_INDEXES];
+ UInt32 Stamps[PPMD_NUM_INDEXES];
+ Byte NS2BSIndx[256], NS2Indx[260];
+ Byte ExpEscape[16];
+ CPpmd_See DummySee, See[24][32];
+ UInt16 BinSumm[25][64];
+
+} CPpmd8;
+
+
+void Ppmd8_Construct(CPpmd8 *p);
+BoolInt Ppmd8_Alloc(CPpmd8 *p, UInt32 size, ISzAllocPtr alloc);
+void Ppmd8_Free(CPpmd8 *p, ISzAllocPtr alloc);
+void Ppmd8_Init(CPpmd8 *p, unsigned maxOrder, unsigned restoreMethod);
+#define Ppmd8_WasAllocated(p) ((p)->Base != NULL)
+
+
+/* ---------- Internal Functions ---------- */
+
+#define Ppmd8_GetPtr(p, ptr) Ppmd_GetPtr(p, ptr)
+#define Ppmd8_GetContext(p, ptr) Ppmd_GetPtr_Type(p, ptr, CPpmd8_Context)
+#define Ppmd8_GetStats(p, ctx) Ppmd_GetPtr_Type(p, (ctx)->Union4.Stats, CPpmd_State)
+
+void Ppmd8_Update1(CPpmd8 *p);
+void Ppmd8_Update1_0(CPpmd8 *p);
+void Ppmd8_Update2(CPpmd8 *p);
+
+
+
+
+
+
+#define Ppmd8_GetBinSumm(p) \
+ &p->BinSumm[p->NS2Indx[(size_t)Ppmd8Context_OneState(p->MinContext)->Freq - 1]] \
+ [ p->PrevSuccess + ((p->RunLength >> 26) & 0x20) \
+ + p->NS2BSIndx[Ppmd8_GetContext(p, p->MinContext->Suffix)->NumStats] + \
+ + p->MinContext->Flags ]
+
+
+CPpmd_See *Ppmd8_MakeEscFreq(CPpmd8 *p, unsigned numMasked, UInt32 *scale);
+
+
+/* 20.01: the original PPMdI encoder and decoder probably could work incorrectly in some rare cases,
+ where the original PPMdI code can give "Divide by Zero" operation.
+ We use the following fix to allow correct working of encoder and decoder in any cases.
+ We correct (Escape_Freq) and (_sum_), if (_sum_) is larger than p->Range) */
+#define PPMD8_CORRECT_SUM_RANGE(p, _sum_) if (_sum_ > p->Range /* /1 */) _sum_ = p->Range;
+
+
+/* ---------- Decode ---------- */
+
+#define PPMD8_SYM_END (-1)
+#define PPMD8_SYM_ERROR (-2)
+
+/*
+You must set (CPpmd8::Stream.In) before Ppmd8_RangeDec_Init()
+
+Ppmd8_DecodeSymbol()
+out:
+ >= 0 : decoded byte
+ -1 : PPMD8_SYM_END : End of payload marker
+ -2 : PPMD8_SYM_ERROR : Data error
+*/
+
+
+BoolInt Ppmd8_Init_RangeDec(CPpmd8 *p);
+#define Ppmd8_RangeDec_IsFinishedOK(p) ((p)->Code == 0)
+int Ppmd8_DecodeSymbol(CPpmd8 *p);
+
+
+
+
+
+
+
+
+/* ---------- Encode ---------- */
+
+#define Ppmd8_Init_RangeEnc(p) { (p)->Low = 0; (p)->Range = 0xFFFFFFFF; }
+void Ppmd8_Flush_RangeEnc(CPpmd8 *p);
+void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol);
+
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Ppmd8Dec.c b/C/Ppmd8Dec.c
new file mode 100644
index 0000000..72d3626
--- /dev/null
+++ b/C/Ppmd8Dec.c
@@ -0,0 +1,295 @@
+/* Ppmd8Dec.c -- Ppmd8 (PPMdI) Decoder
+2023-04-02 : Igor Pavlov : Public domain
+This code is based on:
+ PPMd var.I (2002): Dmitry Shkarin : Public domain
+ Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#include "Precomp.h"
+
+#include "Ppmd8.h"
+
+#define kTop ((UInt32)1 << 24)
+#define kBot ((UInt32)1 << 15)
+
+#define READ_BYTE(p) IByteIn_Read((p)->Stream.In)
+
+BoolInt Ppmd8_Init_RangeDec(CPpmd8 *p)
+{
+ unsigned i;
+ p->Code = 0;
+ p->Range = 0xFFFFFFFF;
+ p->Low = 0;
+
+ for (i = 0; i < 4; i++)
+ p->Code = (p->Code << 8) | READ_BYTE(p);
+ return (p->Code < 0xFFFFFFFF);
+}
+
+#define RC_NORM(p) \
+ while ((p->Low ^ (p->Low + p->Range)) < kTop \
+ || (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) { \
+ p->Code = (p->Code << 8) | READ_BYTE(p); \
+ p->Range <<= 8; p->Low <<= 8; }
+
+// we must use only one type of Normalization from two: LOCAL or REMOTE
+#define RC_NORM_LOCAL(p) // RC_NORM(p)
+#define RC_NORM_REMOTE(p) RC_NORM(p)
+
+#define R p
+
+Z7_FORCE_INLINE
+// Z7_NO_INLINE
+static void Ppmd8_RD_Decode(CPpmd8 *p, UInt32 start, UInt32 size)
+{
+ start *= R->Range;
+ R->Low += start;
+ R->Code -= start;
+ R->Range *= size;
+ RC_NORM_LOCAL(R)
+}
+
+#define RC_Decode(start, size) Ppmd8_RD_Decode(p, start, size);
+#define RC_DecodeFinal(start, size) RC_Decode(start, size) RC_NORM_REMOTE(R)
+#define RC_GetThreshold(total) (R->Code / (R->Range /= (total)))
+
+
+#define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref))
+// typedef CPpmd8_Context * CTX_PTR;
+#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p)
+void Ppmd8_UpdateModel(CPpmd8 *p);
+
+#define MASK(sym) ((unsigned char *)charMask)[sym]
+
+
+int Ppmd8_DecodeSymbol(CPpmd8 *p)
+{
+ size_t charMask[256 / sizeof(size_t)];
+
+ if (p->MinContext->NumStats != 0)
+ {
+ CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext);
+ unsigned i;
+ UInt32 count, hiCnt;
+ UInt32 summFreq = p->MinContext->Union2.SummFreq;
+
+ PPMD8_CORRECT_SUM_RANGE(p, summFreq)
+
+
+ count = RC_GetThreshold(summFreq);
+ hiCnt = count;
+
+ if ((Int32)(count -= s->Freq) < 0)
+ {
+ Byte sym;
+ RC_DecodeFinal(0, s->Freq)
+ p->FoundState = s;
+ sym = s->Symbol;
+ Ppmd8_Update1_0(p);
+ return sym;
+ }
+
+ p->PrevSuccess = 0;
+ i = p->MinContext->NumStats;
+
+ do
+ {
+ if ((Int32)(count -= (++s)->Freq) < 0)
+ {
+ Byte sym;
+ RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq)
+ p->FoundState = s;
+ sym = s->Symbol;
+ Ppmd8_Update1(p);
+ return sym;
+ }
+ }
+ while (--i);
+
+ if (hiCnt >= summFreq)
+ return PPMD8_SYM_ERROR;
+
+ hiCnt -= count;
+ RC_Decode(hiCnt, summFreq - hiCnt)
+
+
+ PPMD_SetAllBitsIn256Bytes(charMask)
+ // i = p->MinContext->NumStats - 1;
+ // do { MASK((--s)->Symbol) = 0; } while (--i);
+ {
+ CPpmd_State *s2 = Ppmd8_GetStats(p, p->MinContext);
+ MASK(s->Symbol) = 0;
+ do
+ {
+ unsigned sym0 = s2[0].Symbol;
+ unsigned sym1 = s2[1].Symbol;
+ s2 += 2;
+ MASK(sym0) = 0;
+ MASK(sym1) = 0;
+ }
+ while (s2 < s);
+ }
+ }
+ else
+ {
+ CPpmd_State *s = Ppmd8Context_OneState(p->MinContext);
+ UInt16 *prob = Ppmd8_GetBinSumm(p);
+ UInt32 pr = *prob;
+ UInt32 size0 = (R->Range >> 14) * pr;
+ pr = PPMD_UPDATE_PROB_1(pr);
+
+ if (R->Code < size0)
+ {
+ Byte sym;
+ *prob = (UInt16)(pr + (1 << PPMD_INT_BITS));
+
+ // RangeDec_DecodeBit0(size0);
+ R->Range = size0;
+ RC_NORM(R)
+
+
+
+ // sym = (p->FoundState = Ppmd8Context_OneState(p->MinContext))->Symbol;
+ // Ppmd8_UpdateBin(p);
+ {
+ unsigned freq = s->Freq;
+ CPpmd8_Context *c = CTX(SUCCESSOR(s));
+ sym = s->Symbol;
+ p->FoundState = s;
+ p->PrevSuccess = 1;
+ p->RunLength++;
+ s->Freq = (Byte)(freq + (freq < 196));
+ // NextContext(p);
+ if (p->OrderFall == 0 && (const Byte *)c >= p->UnitsStart)
+ p->MaxContext = p->MinContext = c;
+ else
+ Ppmd8_UpdateModel(p);
+ }
+ return sym;
+ }
+
+ *prob = (UInt16)pr;
+ p->InitEsc = p->ExpEscape[pr >> 10];
+
+ // RangeDec_DecodeBit1(rc2, size0);
+ R->Low += size0;
+ R->Code -= size0;
+ R->Range = (R->Range & ~((UInt32)PPMD_BIN_SCALE - 1)) - size0;
+ RC_NORM_LOCAL(R)
+
+ PPMD_SetAllBitsIn256Bytes(charMask)
+ MASK(Ppmd8Context_OneState(p->MinContext)->Symbol) = 0;
+ p->PrevSuccess = 0;
+ }
+
+ for (;;)
+ {
+ CPpmd_State *s, *s2;
+ UInt32 freqSum, count, hiCnt;
+ UInt32 freqSum2;
+ CPpmd_See *see;
+ CPpmd8_Context *mc;
+ unsigned numMasked;
+ RC_NORM_REMOTE(R)
+ mc = p->MinContext;
+ numMasked = mc->NumStats;
+
+ do
+ {
+ p->OrderFall++;
+ if (!mc->Suffix)
+ return PPMD8_SYM_END;
+ mc = Ppmd8_GetContext(p, mc->Suffix);
+ }
+ while (mc->NumStats == numMasked);
+
+ s = Ppmd8_GetStats(p, mc);
+
+ {
+ unsigned num = (unsigned)mc->NumStats + 1;
+ unsigned num2 = num / 2;
+
+ num &= 1;
+ hiCnt = (s->Freq & (unsigned)(MASK(s->Symbol))) & (0 - (UInt32)num);
+ s += num;
+ p->MinContext = mc;
+
+ do
+ {
+ unsigned sym0 = s[0].Symbol;
+ unsigned sym1 = s[1].Symbol;
+ s += 2;
+ hiCnt += (s[-2].Freq & (unsigned)(MASK(sym0)));
+ hiCnt += (s[-1].Freq & (unsigned)(MASK(sym1)));
+ }
+ while (--num2);
+ }
+
+ see = Ppmd8_MakeEscFreq(p, numMasked, &freqSum);
+ freqSum += hiCnt;
+ freqSum2 = freqSum;
+ PPMD8_CORRECT_SUM_RANGE(R, freqSum2)
+
+
+ count = RC_GetThreshold(freqSum2);
+
+ if (count < hiCnt)
+ {
+ Byte sym;
+ // Ppmd_See_UPDATE(see) // new (see->Summ) value can overflow over 16-bits in some rare cases
+ s = Ppmd8_GetStats(p, p->MinContext);
+ hiCnt = count;
+
+
+ {
+ for (;;)
+ {
+ count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break;
+ // count -= s->Freq & (unsigned)(MASK((s)->Symbol)); s++; if ((Int32)count < 0) break;
+ }
+ }
+ s--;
+ RC_DecodeFinal((hiCnt - count) - s->Freq, s->Freq)
+
+ // new (see->Summ) value can overflow over 16-bits in some rare cases
+ Ppmd_See_UPDATE(see)
+ p->FoundState = s;
+ sym = s->Symbol;
+ Ppmd8_Update2(p);
+ return sym;
+ }
+
+ if (count >= freqSum2)
+ return PPMD8_SYM_ERROR;
+
+ RC_Decode(hiCnt, freqSum2 - hiCnt)
+
+ // We increase (see->Summ) for sum of Freqs of all non_Masked symbols.
+ // new (see->Summ) value can overflow over 16-bits in some rare cases
+ see->Summ = (UInt16)(see->Summ + freqSum);
+
+ s = Ppmd8_GetStats(p, p->MinContext);
+ s2 = s + p->MinContext->NumStats + 1;
+ do
+ {
+ MASK(s->Symbol) = 0;
+ s++;
+ }
+ while (s != s2);
+ }
+}
+
+#undef kTop
+#undef kBot
+#undef READ_BYTE
+#undef RC_NORM_BASE
+#undef RC_NORM_1
+#undef RC_NORM
+#undef RC_NORM_LOCAL
+#undef RC_NORM_REMOTE
+#undef R
+#undef RC_Decode
+#undef RC_DecodeFinal
+#undef RC_GetThreshold
+#undef CTX
+#undef SUCCESSOR
+#undef MASK
diff --git a/C/Ppmd8Enc.c b/C/Ppmd8Enc.c
new file mode 100644
index 0000000..9e29ef7
--- /dev/null
+++ b/C/Ppmd8Enc.c
@@ -0,0 +1,338 @@
+/* Ppmd8Enc.c -- Ppmd8 (PPMdI) Encoder
+2023-04-02 : Igor Pavlov : Public domain
+This code is based on:
+ PPMd var.I (2002): Dmitry Shkarin : Public domain
+ Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#include "Precomp.h"
+
+#include "Ppmd8.h"
+
+#define kTop ((UInt32)1 << 24)
+#define kBot ((UInt32)1 << 15)
+
+#define WRITE_BYTE(p) IByteOut_Write(p->Stream.Out, (Byte)(p->Low >> 24))
+
+void Ppmd8_Flush_RangeEnc(CPpmd8 *p)
+{
+ unsigned i;
+ for (i = 0; i < 4; i++, p->Low <<= 8 )
+ WRITE_BYTE(p);
+}
+
+
+
+
+
+
+#define RC_NORM(p) \
+ while ((p->Low ^ (p->Low + p->Range)) < kTop \
+ || (p->Range < kBot && ((p->Range = (0 - p->Low) & (kBot - 1)), 1))) \
+ { WRITE_BYTE(p); p->Range <<= 8; p->Low <<= 8; }
+
+
+
+
+
+
+
+
+
+
+
+
+
+// we must use only one type of Normalization from two: LOCAL or REMOTE
+#define RC_NORM_LOCAL(p) // RC_NORM(p)
+#define RC_NORM_REMOTE(p) RC_NORM(p)
+
+// #define RC_PRE(total) p->Range /= total;
+// #define RC_PRE(total)
+
+#define R p
+
+
+
+
+Z7_FORCE_INLINE
+// Z7_NO_INLINE
+static void Ppmd8_RangeEnc_Encode(CPpmd8 *p, UInt32 start, UInt32 size, UInt32 total)
+{
+ R->Low += start * (R->Range /= total);
+ R->Range *= size;
+ RC_NORM_LOCAL(R)
+}
+
+
+
+
+
+
+
+
+
+
+#define RC_Encode(start, size, total) Ppmd8_RangeEnc_Encode(p, start, size, total);
+#define RC_EncodeFinal(start, size, total) RC_Encode(start, size, total) RC_NORM_REMOTE(p)
+
+#define CTX(ref) ((CPpmd8_Context *)Ppmd8_GetContext(p, ref))
+
+// typedef CPpmd8_Context * CTX_PTR;
+#define SUCCESSOR(p) Ppmd_GET_SUCCESSOR(p)
+
+void Ppmd8_UpdateModel(CPpmd8 *p);
+
+#define MASK(sym) ((unsigned char *)charMask)[sym]
+
+// Z7_FORCE_INLINE
+// static
+void Ppmd8_EncodeSymbol(CPpmd8 *p, int symbol)
+{
+ size_t charMask[256 / sizeof(size_t)];
+
+ if (p->MinContext->NumStats != 0)
+ {
+ CPpmd_State *s = Ppmd8_GetStats(p, p->MinContext);
+ UInt32 sum;
+ unsigned i;
+ UInt32 summFreq = p->MinContext->Union2.SummFreq;
+
+ PPMD8_CORRECT_SUM_RANGE(p, summFreq)
+
+ // RC_PRE(summFreq);
+
+ if (s->Symbol == symbol)
+ {
+
+ RC_EncodeFinal(0, s->Freq, summFreq)
+ p->FoundState = s;
+ Ppmd8_Update1_0(p);
+ return;
+ }
+ p->PrevSuccess = 0;
+ sum = s->Freq;
+ i = p->MinContext->NumStats;
+ do
+ {
+ if ((++s)->Symbol == symbol)
+ {
+
+ RC_EncodeFinal(sum, s->Freq, summFreq)
+ p->FoundState = s;
+ Ppmd8_Update1(p);
+ return;
+ }
+ sum += s->Freq;
+ }
+ while (--i);
+
+
+ RC_Encode(sum, summFreq - sum, summFreq)
+
+
+ PPMD_SetAllBitsIn256Bytes(charMask)
+ // MASK(s->Symbol) = 0;
+ // i = p->MinContext->NumStats;
+ // do { MASK((--s)->Symbol) = 0; } while (--i);
+ {
+ CPpmd_State *s2 = Ppmd8_GetStats(p, p->MinContext);
+ MASK(s->Symbol) = 0;
+ do
+ {
+ unsigned sym0 = s2[0].Symbol;
+ unsigned sym1 = s2[1].Symbol;
+ s2 += 2;
+ MASK(sym0) = 0;
+ MASK(sym1) = 0;
+ }
+ while (s2 < s);
+ }
+ }
+ else
+ {
+ UInt16 *prob = Ppmd8_GetBinSumm(p);
+ CPpmd_State *s = Ppmd8Context_OneState(p->MinContext);
+ UInt32 pr = *prob;
+ const UInt32 bound = (R->Range >> 14) * pr;
+ pr = PPMD_UPDATE_PROB_1(pr);
+ if (s->Symbol == symbol)
+ {
+ *prob = (UInt16)(pr + (1 << PPMD_INT_BITS));
+ // RangeEnc_EncodeBit_0(p, bound);
+ R->Range = bound;
+ RC_NORM(R)
+
+ // p->FoundState = s;
+ // Ppmd8_UpdateBin(p);
+ {
+ const unsigned freq = s->Freq;
+ CPpmd8_Context *c = CTX(SUCCESSOR(s));
+ p->FoundState = s;
+ p->PrevSuccess = 1;
+ p->RunLength++;
+ s->Freq = (Byte)(freq + (freq < 196)); // Ppmd8 (196)
+ // NextContext(p);
+ if (p->OrderFall == 0 && (const Byte *)c >= p->UnitsStart)
+ p->MaxContext = p->MinContext = c;
+ else
+ Ppmd8_UpdateModel(p);
+ }
+ return;
+ }
+
+ *prob = (UInt16)pr;
+ p->InitEsc = p->ExpEscape[pr >> 10];
+ // RangeEnc_EncodeBit_1(p, bound);
+ R->Low += bound;
+ R->Range = (R->Range & ~((UInt32)PPMD_BIN_SCALE - 1)) - bound;
+ RC_NORM_LOCAL(R)
+
+ PPMD_SetAllBitsIn256Bytes(charMask)
+ MASK(s->Symbol) = 0;
+ p->PrevSuccess = 0;
+ }
+
+ for (;;)
+ {
+ CPpmd_See *see;
+ CPpmd_State *s;
+ UInt32 sum, escFreq;
+ CPpmd8_Context *mc;
+ unsigned i, numMasked;
+
+ RC_NORM_REMOTE(p)
+
+ mc = p->MinContext;
+ numMasked = mc->NumStats;
+
+ do
+ {
+ p->OrderFall++;
+ if (!mc->Suffix)
+ return; /* EndMarker (symbol = -1) */
+ mc = Ppmd8_GetContext(p, mc->Suffix);
+
+ }
+ while (mc->NumStats == numMasked);
+
+ p->MinContext = mc;
+
+ see = Ppmd8_MakeEscFreq(p, numMasked, &escFreq);
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ s = Ppmd8_GetStats(p, p->MinContext);
+ sum = 0;
+ i = (unsigned)p->MinContext->NumStats + 1;
+
+ do
+ {
+ const unsigned cur = s->Symbol;
+ if ((int)cur == symbol)
+ {
+ const UInt32 low = sum;
+ const UInt32 freq = s->Freq;
+ unsigned num2;
+
+ Ppmd_See_UPDATE(see)
+ p->FoundState = s;
+ sum += escFreq;
+
+ num2 = i / 2;
+ i &= 1;
+ sum += freq & (0 - (UInt32)i);
+ if (num2 != 0)
+ {
+ s += i;
+ for (;;)
+ {
+ unsigned sym0 = s[0].Symbol;
+ unsigned sym1 = s[1].Symbol;
+ s += 2;
+ sum += (s[-2].Freq & (unsigned)(MASK(sym0)));
+ sum += (s[-1].Freq & (unsigned)(MASK(sym1)));
+ if (--num2 == 0)
+ break;
+ }
+ }
+
+ PPMD8_CORRECT_SUM_RANGE(p, sum)
+
+ RC_EncodeFinal(low, freq, sum)
+ Ppmd8_Update2(p);
+ return;
+ }
+ sum += (s->Freq & (unsigned)(MASK(cur)));
+ s++;
+ }
+ while (--i);
+
+ {
+ UInt32 total = sum + escFreq;
+ see->Summ = (UInt16)(see->Summ + total);
+ PPMD8_CORRECT_SUM_RANGE(p, total)
+
+ RC_Encode(sum, total - sum, total)
+ }
+
+ {
+ const CPpmd_State *s2 = Ppmd8_GetStats(p, p->MinContext);
+ s--;
+ MASK(s->Symbol) = 0;
+ do
+ {
+ const unsigned sym0 = s2[0].Symbol;
+ const unsigned sym1 = s2[1].Symbol;
+ s2 += 2;
+ MASK(sym0) = 0;
+ MASK(sym1) = 0;
+ }
+ while (s2 < s);
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+#undef kTop
+#undef kBot
+#undef WRITE_BYTE
+#undef RC_NORM_BASE
+#undef RC_NORM_1
+#undef RC_NORM
+#undef RC_NORM_LOCAL
+#undef RC_NORM_REMOTE
+#undef R
+#undef RC_Encode
+#undef RC_EncodeFinal
+
+#undef CTX
+#undef SUCCESSOR
+#undef MASK
diff --git a/C/Precomp.h b/C/Precomp.h
index edb5814..69afb2f 100644
--- a/C/Precomp.h
+++ b/C/Precomp.h
@@ -1,10 +1,10 @@
-/* Precomp.h -- StdAfx
-2013-11-12 : Igor Pavlov : Public domain */
-
-#ifndef __7Z_PRECOMP_H
-#define __7Z_PRECOMP_H
-
-#include "Compiler.h"
-/* #include "7zTypes.h" */
-
-#endif
+/* Precomp.h -- StdAfx
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_PRECOMP_H
+#define ZIP7_INC_PRECOMP_H
+
+#include "Compiler.h"
+/* #include "7zTypes.h" */
+
+#endif
diff --git a/C/RotateDefs.h b/C/RotateDefs.h
index 6c790e7..c16b4f8 100644
--- a/C/RotateDefs.h
+++ b/C/RotateDefs.h
@@ -1,30 +1,50 @@
-/* RotateDefs.h -- Rotate functions
-2015-03-25 : Igor Pavlov : Public domain */
-
-#ifndef __ROTATE_DEFS_H
-#define __ROTATE_DEFS_H
-
-#ifdef _MSC_VER
-
-#include <stdlib.h>
-
-/* don't use _rotl with MINGW. It can insert slow call to function. */
-
-/* #if (_MSC_VER >= 1200) */
-#pragma intrinsic(_rotl)
-#pragma intrinsic(_rotr)
-/* #endif */
-
-#define rotlFixed(x, n) _rotl((x), (n))
-#define rotrFixed(x, n) _rotr((x), (n))
-
-#else
-
-/* new compilers can translate these macros to fast commands. */
-
-#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
-#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
-
-#endif
-
-#endif
+/* RotateDefs.h -- Rotate functions
+2023-06-18 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_ROTATE_DEFS_H
+#define ZIP7_INC_ROTATE_DEFS_H
+
+#ifdef _MSC_VER
+
+#include <stdlib.h>
+
+/* don't use _rotl with old MINGW. It can insert slow call to function. */
+
+/* #if (_MSC_VER >= 1200) */
+#pragma intrinsic(_rotl)
+#pragma intrinsic(_rotr)
+/* #endif */
+
+#define rotlFixed(x, n) _rotl((x), (n))
+#define rotrFixed(x, n) _rotr((x), (n))
+
+#if (_MSC_VER >= 1300)
+#define Z7_ROTL64(x, n) _rotl64((x), (n))
+#define Z7_ROTR64(x, n) _rotr64((x), (n))
+#else
+#define Z7_ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n))))
+#define Z7_ROTR64(x, n) (((x) >> (n)) | ((x) << (64 - (n))))
+#endif
+
+#else
+
+/* new compilers can translate these macros to fast commands. */
+
+#if defined(__clang__) && (__clang_major__ >= 4) \
+ || defined(__GNUC__) && (__GNUC__ >= 5)
+/* GCC 4.9.0 and clang 3.5 can recognize more correct version: */
+#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (-(n) & 31)))
+#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (-(n) & 31)))
+#define Z7_ROTL64(x, n) (((x) << (n)) | ((x) >> (-(n) & 63)))
+#define Z7_ROTR64(x, n) (((x) >> (n)) | ((x) << (-(n) & 63)))
+#else
+/* for old GCC / clang: */
+#define rotlFixed(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+#define rotrFixed(x, n) (((x) >> (n)) | ((x) << (32 - (n))))
+#define Z7_ROTL64(x, n) (((x) << (n)) | ((x) >> (64 - (n))))
+#define Z7_ROTR64(x, n) (((x) >> (n)) | ((x) << (64 - (n))))
+#endif
+
+#endif
+
+#endif
diff --git a/C/Sha1.c b/C/Sha1.c
new file mode 100644
index 0000000..fd6c018
--- /dev/null
+++ b/C/Sha1.c
@@ -0,0 +1,498 @@
+/* Sha1.c -- SHA-1 Hash
+2023-04-02 : Igor Pavlov : Public domain
+This code is based on public domain code of Steve Reid from Wei Dai's Crypto++ library. */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#include "CpuArch.h"
+#include "RotateDefs.h"
+#include "Sha1.h"
+
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+// #define USE_MY_MM
+#endif
+
+#ifdef MY_CPU_X86_OR_AMD64
+ #ifdef _MSC_VER
+ #if _MSC_VER >= 1200
+ #define Z7_COMPILER_SHA1_SUPPORTED
+ #endif
+ #elif defined(__clang__)
+ #if (__clang_major__ >= 8) // fix that check
+ #define Z7_COMPILER_SHA1_SUPPORTED
+ #endif
+ #elif defined(__GNUC__)
+ #if (__GNUC__ >= 8) // fix that check
+ #define Z7_COMPILER_SHA1_SUPPORTED
+ #endif
+ #elif defined(__INTEL_COMPILER)
+ #if (__INTEL_COMPILER >= 1800) // fix that check
+ #define Z7_COMPILER_SHA1_SUPPORTED
+ #endif
+ #endif
+#elif defined(MY_CPU_ARM_OR_ARM64)
+ #ifdef _MSC_VER
+ #if _MSC_VER >= 1910 && _MSC_VER >= 1929 && _MSC_FULL_VER >= 192930037
+ #define Z7_COMPILER_SHA1_SUPPORTED
+ #endif
+ #elif defined(__clang__)
+ #if (__clang_major__ >= 8) // fix that check
+ #define Z7_COMPILER_SHA1_SUPPORTED
+ #endif
+ #elif defined(__GNUC__)
+ #if (__GNUC__ >= 6) // fix that check
+ #define Z7_COMPILER_SHA1_SUPPORTED
+ #endif
+ #endif
+#endif
+
+void Z7_FASTCALL Sha1_UpdateBlocks(UInt32 state[5], const Byte *data, size_t numBlocks);
+
+#ifdef Z7_COMPILER_SHA1_SUPPORTED
+ void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks);
+
+ static SHA1_FUNC_UPDATE_BLOCKS g_SHA1_FUNC_UPDATE_BLOCKS = Sha1_UpdateBlocks;
+ static SHA1_FUNC_UPDATE_BLOCKS g_SHA1_FUNC_UPDATE_BLOCKS_HW;
+
+ #define SHA1_UPDATE_BLOCKS(p) p->func_UpdateBlocks
+#else
+ #define SHA1_UPDATE_BLOCKS(p) Sha1_UpdateBlocks
+#endif
+
+
+BoolInt Sha1_SetFunction(CSha1 *p, unsigned algo)
+{
+ SHA1_FUNC_UPDATE_BLOCKS func = Sha1_UpdateBlocks;
+
+ #ifdef Z7_COMPILER_SHA1_SUPPORTED
+ if (algo != SHA1_ALGO_SW)
+ {
+ if (algo == SHA1_ALGO_DEFAULT)
+ func = g_SHA1_FUNC_UPDATE_BLOCKS;
+ else
+ {
+ if (algo != SHA1_ALGO_HW)
+ return False;
+ func = g_SHA1_FUNC_UPDATE_BLOCKS_HW;
+ if (!func)
+ return False;
+ }
+ }
+ #else
+ if (algo > 1)
+ return False;
+ #endif
+
+ p->func_UpdateBlocks = func;
+ return True;
+}
+
+
+/* define it for speed optimization */
+// #define Z7_SHA1_UNROLL
+
+// allowed unroll steps: (1, 2, 4, 5, 20)
+
+#undef Z7_SHA1_BIG_W
+#ifdef Z7_SHA1_UNROLL
+ #define STEP_PRE 20
+ #define STEP_MAIN 20
+#else
+ #define Z7_SHA1_BIG_W
+ #define STEP_PRE 5
+ #define STEP_MAIN 5
+#endif
+
+
+#ifdef Z7_SHA1_BIG_W
+ #define kNumW 80
+ #define w(i) W[i]
+#else
+ #define kNumW 16
+ #define w(i) W[(i)&15]
+#endif
+
+#define w0(i) (W[i] = GetBe32(data + (size_t)(i) * 4))
+#define w1(i) (w(i) = rotlFixed(w((size_t)(i)-3) ^ w((size_t)(i)-8) ^ w((size_t)(i)-14) ^ w((size_t)(i)-16), 1))
+
+#define f0(x,y,z) ( 0x5a827999 + (z^(x&(y^z))) )
+#define f1(x,y,z) ( 0x6ed9eba1 + (x^y^z) )
+#define f2(x,y,z) ( 0x8f1bbcdc + ((x&y)|(z&(x|y))) )
+#define f3(x,y,z) ( 0xca62c1d6 + (x^y^z) )
+
+/*
+#define T1(fx, ww) \
+ tmp = e + fx(b,c,d) + ww + rotlFixed(a, 5); \
+ e = d; \
+ d = c; \
+ c = rotlFixed(b, 30); \
+ b = a; \
+ a = tmp; \
+*/
+
+#define T5(a,b,c,d,e, fx, ww) \
+ e += fx(b,c,d) + ww + rotlFixed(a, 5); \
+ b = rotlFixed(b, 30); \
+
+
+/*
+#define R1(i, fx, wx) \
+ T1 ( fx, wx(i)); \
+
+#define R2(i, fx, wx) \
+ R1 ( (i) , fx, wx); \
+ R1 ( (i) + 1, fx, wx); \
+
+#define R4(i, fx, wx) \
+ R2 ( (i) , fx, wx); \
+ R2 ( (i) + 2, fx, wx); \
+*/
+
+#define M5(i, fx, wx0, wx1) \
+ T5 ( a,b,c,d,e, fx, wx0((i) ) ) \
+ T5 ( e,a,b,c,d, fx, wx1((i)+1) ) \
+ T5 ( d,e,a,b,c, fx, wx1((i)+2) ) \
+ T5 ( c,d,e,a,b, fx, wx1((i)+3) ) \
+ T5 ( b,c,d,e,a, fx, wx1((i)+4) ) \
+
+#define R5(i, fx, wx) \
+ M5 ( i, fx, wx, wx) \
+
+
+#if STEP_PRE > 5
+
+ #define R20_START \
+ R5 ( 0, f0, w0) \
+ R5 ( 5, f0, w0) \
+ R5 ( 10, f0, w0) \
+ M5 ( 15, f0, w0, w1) \
+
+ #elif STEP_PRE == 5
+
+ #define R20_START \
+ { size_t i; for (i = 0; i < 15; i += STEP_PRE) \
+ { R5(i, f0, w0) } } \
+ M5 ( 15, f0, w0, w1) \
+
+#else
+
+ #if STEP_PRE == 1
+ #define R_PRE R1
+ #elif STEP_PRE == 2
+ #define R_PRE R2
+ #elif STEP_PRE == 4
+ #define R_PRE R4
+ #endif
+
+ #define R20_START \
+ { size_t i; for (i = 0; i < 16; i += STEP_PRE) \
+ { R_PRE(i, f0, w0) } } \
+ R4 ( 16, f0, w1) \
+
+#endif
+
+
+
+#if STEP_MAIN > 5
+
+ #define R20(ii, fx) \
+ R5 ( (ii) , fx, w1) \
+ R5 ( (ii) + 5 , fx, w1) \
+ R5 ( (ii) + 10, fx, w1) \
+ R5 ( (ii) + 15, fx, w1) \
+
+#else
+
+ #if STEP_MAIN == 1
+ #define R_MAIN R1
+ #elif STEP_MAIN == 2
+ #define R_MAIN R2
+ #elif STEP_MAIN == 4
+ #define R_MAIN R4
+ #elif STEP_MAIN == 5
+ #define R_MAIN R5
+ #endif
+
+ #define R20(ii, fx) \
+ { size_t i; for (i = (ii); i < (ii) + 20; i += STEP_MAIN) \
+ { R_MAIN(i, fx, w1) } } \
+
+#endif
+
+
+
+void Sha1_InitState(CSha1 *p)
+{
+ p->count = 0;
+ p->state[0] = 0x67452301;
+ p->state[1] = 0xEFCDAB89;
+ p->state[2] = 0x98BADCFE;
+ p->state[3] = 0x10325476;
+ p->state[4] = 0xC3D2E1F0;
+}
+
+void Sha1_Init(CSha1 *p)
+{
+ p->func_UpdateBlocks =
+ #ifdef Z7_COMPILER_SHA1_SUPPORTED
+ g_SHA1_FUNC_UPDATE_BLOCKS;
+ #else
+ NULL;
+ #endif
+ Sha1_InitState(p);
+}
+
+
+Z7_NO_INLINE
+void Z7_FASTCALL Sha1_UpdateBlocks(UInt32 state[5], const Byte *data, size_t numBlocks)
+{
+ UInt32 a, b, c, d, e;
+ UInt32 W[kNumW];
+ // if (numBlocks != 0x1264378347) return;
+ if (numBlocks == 0)
+ return;
+
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+
+ do
+ {
+ #if STEP_PRE < 5 || STEP_MAIN < 5
+ UInt32 tmp;
+ #endif
+
+ R20_START
+ R20(20, f1)
+ R20(40, f2)
+ R20(60, f3)
+
+ a += state[0];
+ b += state[1];
+ c += state[2];
+ d += state[3];
+ e += state[4];
+
+ state[0] = a;
+ state[1] = b;
+ state[2] = c;
+ state[3] = d;
+ state[4] = e;
+
+ data += 64;
+ }
+ while (--numBlocks);
+}
+
+
+#define Sha1_UpdateBlock(p) SHA1_UPDATE_BLOCKS(p)(p->state, p->buffer, 1)
+
+void Sha1_Update(CSha1 *p, const Byte *data, size_t size)
+{
+ if (size == 0)
+ return;
+
+ {
+ unsigned pos = (unsigned)p->count & 0x3F;
+ unsigned num;
+
+ p->count += size;
+
+ num = 64 - pos;
+ if (num > size)
+ {
+ memcpy(p->buffer + pos, data, size);
+ return;
+ }
+
+ if (pos != 0)
+ {
+ size -= num;
+ memcpy(p->buffer + pos, data, num);
+ data += num;
+ Sha1_UpdateBlock(p);
+ }
+ }
+ {
+ size_t numBlocks = size >> 6;
+ SHA1_UPDATE_BLOCKS(p)(p->state, data, numBlocks);
+ size &= 0x3F;
+ if (size == 0)
+ return;
+ data += (numBlocks << 6);
+ memcpy(p->buffer, data, size);
+ }
+}
+
+
+void Sha1_Final(CSha1 *p, Byte *digest)
+{
+ unsigned pos = (unsigned)p->count & 0x3F;
+
+
+ p->buffer[pos++] = 0x80;
+
+ if (pos > (64 - 8))
+ {
+ while (pos != 64) { p->buffer[pos++] = 0; }
+ // memset(&p->buf.buffer[pos], 0, 64 - pos);
+ Sha1_UpdateBlock(p);
+ pos = 0;
+ }
+
+ /*
+ if (pos & 3)
+ {
+ p->buffer[pos] = 0;
+ p->buffer[pos + 1] = 0;
+ p->buffer[pos + 2] = 0;
+ pos += 3;
+ pos &= ~3;
+ }
+ {
+ for (; pos < 64 - 8; pos += 4)
+ *(UInt32 *)(&p->buffer[pos]) = 0;
+ }
+ */
+
+ memset(&p->buffer[pos], 0, (64 - 8) - pos);
+
+ {
+ const UInt64 numBits = (p->count << 3);
+ SetBe32(p->buffer + 64 - 8, (UInt32)(numBits >> 32))
+ SetBe32(p->buffer + 64 - 4, (UInt32)(numBits))
+ }
+
+ Sha1_UpdateBlock(p);
+
+ SetBe32(digest, p->state[0])
+ SetBe32(digest + 4, p->state[1])
+ SetBe32(digest + 8, p->state[2])
+ SetBe32(digest + 12, p->state[3])
+ SetBe32(digest + 16, p->state[4])
+
+
+
+
+ Sha1_InitState(p);
+}
+
+
+void Sha1_PrepareBlock(const CSha1 *p, Byte *block, unsigned size)
+{
+ const UInt64 numBits = (p->count + size) << 3;
+ SetBe32(&((UInt32 *)(void *)block)[SHA1_NUM_BLOCK_WORDS - 2], (UInt32)(numBits >> 32))
+ SetBe32(&((UInt32 *)(void *)block)[SHA1_NUM_BLOCK_WORDS - 1], (UInt32)(numBits))
+ // SetBe32((UInt32 *)(block + size), 0x80000000);
+ SetUi32((UInt32 *)(void *)(block + size), 0x80)
+ size += 4;
+ while (size != (SHA1_NUM_BLOCK_WORDS - 2) * 4)
+ {
+ *((UInt32 *)(void *)(block + size)) = 0;
+ size += 4;
+ }
+}
+
+void Sha1_GetBlockDigest(const CSha1 *p, const Byte *data, Byte *destDigest)
+{
+ MY_ALIGN (16)
+ UInt32 st[SHA1_NUM_DIGEST_WORDS];
+
+ st[0] = p->state[0];
+ st[1] = p->state[1];
+ st[2] = p->state[2];
+ st[3] = p->state[3];
+ st[4] = p->state[4];
+
+ SHA1_UPDATE_BLOCKS(p)(st, data, 1);
+
+ SetBe32(destDigest + 0 , st[0])
+ SetBe32(destDigest + 1 * 4, st[1])
+ SetBe32(destDigest + 2 * 4, st[2])
+ SetBe32(destDigest + 3 * 4, st[3])
+ SetBe32(destDigest + 4 * 4, st[4])
+}
+
+
+void Sha1Prepare(void)
+{
+ #ifdef Z7_COMPILER_SHA1_SUPPORTED
+ SHA1_FUNC_UPDATE_BLOCKS f, f_hw;
+ f = Sha1_UpdateBlocks;
+ f_hw = NULL;
+ #ifdef MY_CPU_X86_OR_AMD64
+ #ifndef USE_MY_MM
+ if (CPU_IsSupported_SHA()
+ && CPU_IsSupported_SSSE3()
+ // && CPU_IsSupported_SSE41()
+ )
+ #endif
+ #else
+ if (CPU_IsSupported_SHA1())
+ #endif
+ {
+ // printf("\n========== HW SHA1 ======== \n");
+ #if defined(MY_CPU_ARM_OR_ARM64) && defined(_MSC_VER)
+ /* there was bug in MSVC compiler for ARM64 -O2 before version VS2019 16.10 (19.29.30037).
+ It generated incorrect SHA-1 code.
+ 21.03 : we test sha1-hardware code at runtime initialization */
+
+ #pragma message("== SHA1 code: MSC compiler : failure-check code was inserted")
+
+ UInt32 state[5] = { 0, 1, 2, 3, 4 } ;
+ Byte data[64];
+ unsigned i;
+ for (i = 0; i < sizeof(data); i += 2)
+ {
+ data[i ] = (Byte)(i);
+ data[i + 1] = (Byte)(i + 1);
+ }
+
+ Sha1_UpdateBlocks_HW(state, data, sizeof(data) / 64);
+
+ if ( state[0] != 0x9acd7297
+ || state[1] != 0x4624d898
+ || state[2] != 0x0bf079f0
+ || state[3] != 0x031e61b3
+ || state[4] != 0x8323fe20)
+ {
+ // printf("\n========== SHA-1 hardware version failure ======== \n");
+ }
+ else
+ #endif
+ {
+ f = f_hw = Sha1_UpdateBlocks_HW;
+ }
+ }
+ g_SHA1_FUNC_UPDATE_BLOCKS = f;
+ g_SHA1_FUNC_UPDATE_BLOCKS_HW = f_hw;
+ #endif
+}
+
+#undef kNumW
+#undef w
+#undef w0
+#undef w1
+#undef f0
+#undef f1
+#undef f2
+#undef f3
+#undef T1
+#undef T5
+#undef M5
+#undef R1
+#undef R2
+#undef R4
+#undef R5
+#undef R20_START
+#undef R_PRE
+#undef R_MAIN
+#undef STEP_PRE
+#undef STEP_MAIN
+#undef Z7_SHA1_BIG_W
+#undef Z7_SHA1_UNROLL
+#undef Z7_COMPILER_SHA1_SUPPORTED
diff --git a/C/Sha1.h b/C/Sha1.h
new file mode 100644
index 0000000..fecd9d3
--- /dev/null
+++ b/C/Sha1.h
@@ -0,0 +1,76 @@
+/* Sha1.h -- SHA-1 Hash
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_SHA1_H
+#define ZIP7_INC_SHA1_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define SHA1_NUM_BLOCK_WORDS 16
+#define SHA1_NUM_DIGEST_WORDS 5
+
+#define SHA1_BLOCK_SIZE (SHA1_NUM_BLOCK_WORDS * 4)
+#define SHA1_DIGEST_SIZE (SHA1_NUM_DIGEST_WORDS * 4)
+
+typedef void (Z7_FASTCALL *SHA1_FUNC_UPDATE_BLOCKS)(UInt32 state[5], const Byte *data, size_t numBlocks);
+
+/*
+ if (the system supports different SHA1 code implementations)
+ {
+ (CSha1::func_UpdateBlocks) will be used
+ (CSha1::func_UpdateBlocks) can be set by
+ Sha1_Init() - to default (fastest)
+ Sha1_SetFunction() - to any algo
+ }
+ else
+ {
+ (CSha1::func_UpdateBlocks) is ignored.
+ }
+*/
+
+typedef struct
+{
+ SHA1_FUNC_UPDATE_BLOCKS func_UpdateBlocks;
+ UInt64 count;
+ UInt64 _pad_2[2];
+ UInt32 state[SHA1_NUM_DIGEST_WORDS];
+ UInt32 _pad_3[3];
+ Byte buffer[SHA1_BLOCK_SIZE];
+} CSha1;
+
+
+#define SHA1_ALGO_DEFAULT 0
+#define SHA1_ALGO_SW 1
+#define SHA1_ALGO_HW 2
+
+/*
+Sha1_SetFunction()
+return:
+ 0 - (algo) value is not supported, and func_UpdateBlocks was not changed
+ 1 - func_UpdateBlocks was set according (algo) value.
+*/
+
+BoolInt Sha1_SetFunction(CSha1 *p, unsigned algo);
+
+void Sha1_InitState(CSha1 *p);
+void Sha1_Init(CSha1 *p);
+void Sha1_Update(CSha1 *p, const Byte *data, size_t size);
+void Sha1_Final(CSha1 *p, Byte *digest);
+
+void Sha1_PrepareBlock(const CSha1 *p, Byte *block, unsigned size);
+void Sha1_GetBlockDigest(const CSha1 *p, const Byte *data, Byte *destDigest);
+
+// void Z7_FASTCALL Sha1_UpdateBlocks(UInt32 state[5], const Byte *data, size_t numBlocks);
+
+/*
+call Sha1Prepare() once at program start.
+It prepares all supported implementations, and detects the fastest implementation.
+*/
+
+void Sha1Prepare(void);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Sha1Opt.c b/C/Sha1Opt.c
new file mode 100644
index 0000000..27796aa
--- /dev/null
+++ b/C/Sha1Opt.c
@@ -0,0 +1,386 @@
+/* Sha1Opt.c -- SHA-1 optimized code for SHA-1 hardware instructions
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+#include "Compiler.h"
+#include "CpuArch.h"
+
+#if defined(_MSC_VER)
+#if (_MSC_VER < 1900) && (_MSC_VER >= 1200)
+// #define USE_MY_MM
+#endif
+#endif
+
+#ifdef MY_CPU_X86_OR_AMD64
+ #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1600) // fix that check
+ #define USE_HW_SHA
+ #elif defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30800) \
+ || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 50100) \
+ || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900)
+ #define USE_HW_SHA
+ #if !defined(_INTEL_COMPILER)
+ // icc defines __GNUC__, but icc doesn't support __attribute__(__target__)
+ #if !defined(__SHA__) || !defined(__SSSE3__)
+ #define ATTRIB_SHA __attribute__((__target__("sha,ssse3")))
+ #endif
+ #endif
+ #elif defined(_MSC_VER)
+ #ifdef USE_MY_MM
+ #define USE_VER_MIN 1300
+ #else
+ #define USE_VER_MIN 1900
+ #endif
+ #if (_MSC_VER >= USE_VER_MIN)
+ #define USE_HW_SHA
+ #endif
+ #endif
+// #endif // MY_CPU_X86_OR_AMD64
+
+#ifdef USE_HW_SHA
+
+// #pragma message("Sha1 HW")
+
+// sse/sse2/ssse3:
+#include <tmmintrin.h>
+// sha*:
+#include <immintrin.h>
+
+#if defined (__clang__) && defined(_MSC_VER)
+ // #if !defined(__SSSE3__)
+ // #endif
+ #if !defined(__SHA__)
+ #include <shaintrin.h>
+ #endif
+#else
+
+#ifdef USE_MY_MM
+#include "My_mm.h"
+#endif
+
+#endif
+
+/*
+SHA1 uses:
+SSE2:
+ _mm_loadu_si128
+ _mm_storeu_si128
+ _mm_set_epi32
+ _mm_add_epi32
+ _mm_shuffle_epi32 / pshufd
+ _mm_xor_si128
+ _mm_cvtsi128_si32
+ _mm_cvtsi32_si128
+SSSE3:
+ _mm_shuffle_epi8 / pshufb
+
+SHA:
+ _mm_sha1*
+*/
+
+
+#define XOR_SI128(dest, src) dest = _mm_xor_si128(dest, src);
+#define SHUFFLE_EPI8(dest, mask) dest = _mm_shuffle_epi8(dest, mask);
+#define SHUFFLE_EPI32(dest, mask) dest = _mm_shuffle_epi32(dest, mask);
+#ifdef __clang__
+#define SHA1_RNDS4_RET_TYPE_CAST (__m128i)
+#else
+#define SHA1_RNDS4_RET_TYPE_CAST
+#endif
+#define SHA1_RND4(abcd, e0, f) abcd = SHA1_RNDS4_RET_TYPE_CAST _mm_sha1rnds4_epu32(abcd, e0, f);
+#define SHA1_NEXTE(e, m) e = _mm_sha1nexte_epu32(e, m);
+#define ADD_EPI32(dest, src) dest = _mm_add_epi32(dest, src);
+#define SHA1_MSG1(dest, src) dest = _mm_sha1msg1_epu32(dest, src);
+#define SHA1_MSG2(dest, src) dest = _mm_sha1msg2_epu32(dest, src);
+
+
+#define LOAD_SHUFFLE(m, k) \
+ m = _mm_loadu_si128((const __m128i *)(const void *)(data + (k) * 16)); \
+ SHUFFLE_EPI8(m, mask) \
+
+#define SM1(m0, m1, m2, m3) \
+ SHA1_MSG1(m0, m1) \
+
+#define SM2(m0, m1, m2, m3) \
+ XOR_SI128(m3, m1) \
+ SHA1_MSG2(m3, m2) \
+
+#define SM3(m0, m1, m2, m3) \
+ XOR_SI128(m3, m1) \
+ SM1(m0, m1, m2, m3) \
+ SHA1_MSG2(m3, m2) \
+
+#define NNN(m0, m1, m2, m3)
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#define R4(k, e0, e1, m0, m1, m2, m3, OP) \
+ e1 = abcd; \
+ SHA1_RND4(abcd, e0, (k) / 5) \
+ SHA1_NEXTE(e1, m1) \
+ OP(m0, m1, m2, m3) \
+
+#define R16(k, mx, OP0, OP1, OP2, OP3) \
+ R4 ( (k)*4+0, e0,e1, m0,m1,m2,m3, OP0 ) \
+ R4 ( (k)*4+1, e1,e0, m1,m2,m3,m0, OP1 ) \
+ R4 ( (k)*4+2, e0,e1, m2,m3,m0,m1, OP2 ) \
+ R4 ( (k)*4+3, e1,e0, m3,mx,m1,m2, OP3 ) \
+
+#define PREPARE_STATE \
+ SHUFFLE_EPI32 (abcd, 0x1B) \
+ SHUFFLE_EPI32 (e0, 0x1B) \
+
+
+
+
+
+void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks);
+#ifdef ATTRIB_SHA
+ATTRIB_SHA
+#endif
+void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks)
+{
+ const __m128i mask = _mm_set_epi32(0x00010203, 0x04050607, 0x08090a0b, 0x0c0d0e0f);
+
+ __m128i abcd, e0;
+
+ if (numBlocks == 0)
+ return;
+
+ abcd = _mm_loadu_si128((const __m128i *) (const void *) &state[0]); // dbca
+ e0 = _mm_cvtsi32_si128((int)state[4]); // 000e
+
+ PREPARE_STATE
+
+ do
+ {
+ __m128i abcd_save, e2;
+ __m128i m0, m1, m2, m3;
+ __m128i e1;
+
+
+ abcd_save = abcd;
+ e2 = e0;
+
+ LOAD_SHUFFLE (m0, 0)
+ LOAD_SHUFFLE (m1, 1)
+ LOAD_SHUFFLE (m2, 2)
+ LOAD_SHUFFLE (m3, 3)
+
+ ADD_EPI32(e0, m0)
+
+ R16 ( 0, m0, SM1, SM3, SM3, SM3 )
+ R16 ( 1, m0, SM3, SM3, SM3, SM3 )
+ R16 ( 2, m0, SM3, SM3, SM3, SM3 )
+ R16 ( 3, m0, SM3, SM3, SM3, SM3 )
+ R16 ( 4, e2, SM2, NNN, NNN, NNN )
+
+ ADD_EPI32(abcd, abcd_save)
+
+ data += 64;
+ }
+ while (--numBlocks);
+
+ PREPARE_STATE
+
+ _mm_storeu_si128((__m128i *) (void *) state, abcd);
+ *(state+4) = (UInt32)_mm_cvtsi128_si32(e0);
+}
+
+#endif // USE_HW_SHA
+
+#elif defined(MY_CPU_ARM_OR_ARM64)
+
+ #if defined(__clang__)
+ #if (__clang_major__ >= 8) // fix that check
+ #define USE_HW_SHA
+ #endif
+ #elif defined(__GNUC__)
+ #if (__GNUC__ >= 6) // fix that check
+ #define USE_HW_SHA
+ #endif
+ #elif defined(_MSC_VER)
+ #if _MSC_VER >= 1910
+ #define USE_HW_SHA
+ #endif
+ #endif
+
+#ifdef USE_HW_SHA
+
+// #pragma message("=== Sha1 HW === ")
+
+#if defined(__clang__) || defined(__GNUC__)
+ #ifdef MY_CPU_ARM64
+ #define ATTRIB_SHA __attribute__((__target__("+crypto")))
+ #else
+ #define ATTRIB_SHA __attribute__((__target__("fpu=crypto-neon-fp-armv8")))
+ #endif
+#else
+ // _MSC_VER
+ // for arm32
+ #define _ARM_USE_NEW_NEON_INTRINSICS
+#endif
+
+#if defined(_MSC_VER) && defined(MY_CPU_ARM64)
+#include <arm64_neon.h>
+#else
+#include <arm_neon.h>
+#endif
+
+typedef uint32x4_t v128;
+// typedef __n128 v128; // MSVC
+
+#ifdef MY_CPU_BE
+ #define MY_rev32_for_LE(x)
+#else
+ #define MY_rev32_for_LE(x) x = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(x)))
+#endif
+
+#define LOAD_128(_p) (*(const v128 *)(const void *)(_p))
+#define STORE_128(_p, _v) *(v128 *)(void *)(_p) = (_v)
+
+#define LOAD_SHUFFLE(m, k) \
+ m = LOAD_128((data + (k) * 16)); \
+ MY_rev32_for_LE(m); \
+
+#define SU0(dest, src2, src3) dest = vsha1su0q_u32(dest, src2, src3);
+#define SU1(dest, src) dest = vsha1su1q_u32(dest, src);
+#define C(e) abcd = vsha1cq_u32(abcd, e, t);
+#define P(e) abcd = vsha1pq_u32(abcd, e, t);
+#define M(e) abcd = vsha1mq_u32(abcd, e, t);
+#define H(e) e = vsha1h_u32(vgetq_lane_u32(abcd, 0))
+#define T(m, c) t = vaddq_u32(m, c)
+
+void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks);
+#ifdef ATTRIB_SHA
+ATTRIB_SHA
+#endif
+void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks)
+{
+ v128 abcd;
+ v128 c0, c1, c2, c3;
+ uint32_t e0;
+
+ if (numBlocks == 0)
+ return;
+
+ c0 = vdupq_n_u32(0x5a827999);
+ c1 = vdupq_n_u32(0x6ed9eba1);
+ c2 = vdupq_n_u32(0x8f1bbcdc);
+ c3 = vdupq_n_u32(0xca62c1d6);
+
+ abcd = LOAD_128(&state[0]);
+ e0 = state[4];
+
+ do
+ {
+ v128 abcd_save;
+ v128 m0, m1, m2, m3;
+ v128 t;
+ uint32_t e0_save, e1;
+
+ abcd_save = abcd;
+ e0_save = e0;
+
+ LOAD_SHUFFLE (m0, 0)
+ LOAD_SHUFFLE (m1, 1)
+ LOAD_SHUFFLE (m2, 2)
+ LOAD_SHUFFLE (m3, 3)
+
+ T(m0, c0); H(e1); C(e0);
+ T(m1, c0); SU0(m0, m1, m2); H(e0); C(e1);
+ T(m2, c0); SU0(m1, m2, m3); SU1(m0, m3); H(e1); C(e0);
+ T(m3, c0); SU0(m2, m3, m0); SU1(m1, m0); H(e0); C(e1);
+ T(m0, c0); SU0(m3, m0, m1); SU1(m2, m1); H(e1); C(e0);
+ T(m1, c1); SU0(m0, m1, m2); SU1(m3, m2); H(e0); P(e1);
+ T(m2, c1); SU0(m1, m2, m3); SU1(m0, m3); H(e1); P(e0);
+ T(m3, c1); SU0(m2, m3, m0); SU1(m1, m0); H(e0); P(e1);
+ T(m0, c1); SU0(m3, m0, m1); SU1(m2, m1); H(e1); P(e0);
+ T(m1, c1); SU0(m0, m1, m2); SU1(m3, m2); H(e0); P(e1);
+ T(m2, c2); SU0(m1, m2, m3); SU1(m0, m3); H(e1); M(e0);
+ T(m3, c2); SU0(m2, m3, m0); SU1(m1, m0); H(e0); M(e1);
+ T(m0, c2); SU0(m3, m0, m1); SU1(m2, m1); H(e1); M(e0);
+ T(m1, c2); SU0(m0, m1, m2); SU1(m3, m2); H(e0); M(e1);
+ T(m2, c2); SU0(m1, m2, m3); SU1(m0, m3); H(e1); M(e0);
+ T(m3, c3); SU0(m2, m3, m0); SU1(m1, m0); H(e0); P(e1);
+ T(m0, c3); SU0(m3, m0, m1); SU1(m2, m1); H(e1); P(e0);
+ T(m1, c3); SU1(m3, m2); H(e0); P(e1);
+ T(m2, c3); H(e1); P(e0);
+ T(m3, c3); H(e0); P(e1);
+
+ abcd = vaddq_u32(abcd, abcd_save);
+ e0 += e0_save;
+
+ data += 64;
+ }
+ while (--numBlocks);
+
+ STORE_128(&state[0], abcd);
+ state[4] = e0;
+}
+
+#endif // USE_HW_SHA
+
+#endif // MY_CPU_ARM_OR_ARM64
+
+
+#ifndef USE_HW_SHA
+
+// #error Stop_Compiling_UNSUPPORTED_SHA
+// #include <stdlib.h>
+
+// #include "Sha1.h"
+void Z7_FASTCALL Sha1_UpdateBlocks(UInt32 state[5], const Byte *data, size_t numBlocks);
+
+#pragma message("Sha1 HW-SW stub was used")
+
+void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks);
+void Z7_FASTCALL Sha1_UpdateBlocks_HW(UInt32 state[5], const Byte *data, size_t numBlocks)
+{
+ Sha1_UpdateBlocks(state, data, numBlocks);
+ /*
+ UNUSED_VAR(state);
+ UNUSED_VAR(data);
+ UNUSED_VAR(numBlocks);
+ exit(1);
+ return;
+ */
+}
+
+#endif
+
+#undef SU0
+#undef SU1
+#undef C
+#undef P
+#undef M
+#undef H
+#undef T
+#undef MY_rev32_for_LE
+#undef NNN
+#undef LOAD_128
+#undef STORE_128
+#undef LOAD_SHUFFLE
+#undef SM1
+#undef SM2
+#undef SM3
+#undef NNN
+#undef R4
+#undef R16
+#undef PREPARE_STATE
+#undef USE_HW_SHA
+#undef ATTRIB_SHA
+#undef USE_VER_MIN
diff --git a/C/Sha256.c b/C/Sha256.c
index 90994e5..018cf6f 100644
--- a/C/Sha256.c
+++ b/C/Sha256.c
@@ -1,248 +1,516 @@
-/* Crypto/Sha256.c -- SHA-256 Hash
-2017-04-03 : Igor Pavlov : Public domain
-This code is based on public domain code from Wei Dai's Crypto++ library. */
-
-#include "Precomp.h"
-
-#include <string.h>
-
-#include "CpuArch.h"
-#include "RotateDefs.h"
-#include "Sha256.h"
-
-/* define it for speed optimization */
-#ifndef _SFX
-#define _SHA256_UNROLL
-#define _SHA256_UNROLL2
-#endif
-
-/* #define _SHA256_UNROLL2 */
-
-void Sha256_Init(CSha256 *p)
-{
- p->state[0] = 0x6a09e667;
- p->state[1] = 0xbb67ae85;
- p->state[2] = 0x3c6ef372;
- p->state[3] = 0xa54ff53a;
- p->state[4] = 0x510e527f;
- p->state[5] = 0x9b05688c;
- p->state[6] = 0x1f83d9ab;
- p->state[7] = 0x5be0cd19;
- p->count = 0;
-}
-
-#define S0(x) (rotrFixed(x, 2) ^ rotrFixed(x,13) ^ rotrFixed(x, 22))
-#define S1(x) (rotrFixed(x, 6) ^ rotrFixed(x,11) ^ rotrFixed(x, 25))
-#define s0(x) (rotrFixed(x, 7) ^ rotrFixed(x,18) ^ (x >> 3))
-#define s1(x) (rotrFixed(x,17) ^ rotrFixed(x,19) ^ (x >> 10))
-
-#define blk0(i) (W[i])
-#define blk2(i) (W[i] += s1(W[((i)-2)&15]) + W[((i)-7)&15] + s0(W[((i)-15)&15]))
-
-#define Ch(x,y,z) (z^(x&(y^z)))
-#define Maj(x,y,z) ((x&y)|(z&(x|y)))
-
-#ifdef _SHA256_UNROLL2
-
-#define R(a,b,c,d,e,f,g,h, i) \
- h += S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + (j ? blk2(i) : blk0(i)); \
- d += h; \
- h += S0(a) + Maj(a, b, c)
-
-#define RX_8(i) \
- R(a,b,c,d,e,f,g,h, i); \
- R(h,a,b,c,d,e,f,g, i+1); \
- R(g,h,a,b,c,d,e,f, i+2); \
- R(f,g,h,a,b,c,d,e, i+3); \
- R(e,f,g,h,a,b,c,d, i+4); \
- R(d,e,f,g,h,a,b,c, i+5); \
- R(c,d,e,f,g,h,a,b, i+6); \
- R(b,c,d,e,f,g,h,a, i+7)
-
-#define RX_16 RX_8(0); RX_8(8);
-
-#else
-
-#define a(i) T[(0-(i))&7]
-#define b(i) T[(1-(i))&7]
-#define c(i) T[(2-(i))&7]
-#define d(i) T[(3-(i))&7]
-#define e(i) T[(4-(i))&7]
-#define f(i) T[(5-(i))&7]
-#define g(i) T[(6-(i))&7]
-#define h(i) T[(7-(i))&7]
-
-#define R(i) \
- h(i) += S1(e(i)) + Ch(e(i),f(i),g(i)) + K[(i)+(size_t)(j)] + (j ? blk2(i) : blk0(i)); \
- d(i) += h(i); \
- h(i) += S0(a(i)) + Maj(a(i), b(i), c(i)) \
-
-#ifdef _SHA256_UNROLL
-
-#define RX_8(i) R(i+0); R(i+1); R(i+2); R(i+3); R(i+4); R(i+5); R(i+6); R(i+7);
-#define RX_16 RX_8(0); RX_8(8);
-
-#else
-
-#define RX_16 unsigned i; for (i = 0; i < 16; i++) { R(i); }
-
-#endif
-
-#endif
-
-static const UInt32 K[64] = {
- 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
- 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
- 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
- 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
- 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
- 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
- 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
- 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
- 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
- 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
- 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
- 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
- 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
- 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
- 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
- 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
-};
-
-static void Sha256_WriteByteBlock(CSha256 *p)
-{
- UInt32 W[16];
- unsigned j;
- UInt32 *state;
-
- #ifdef _SHA256_UNROLL2
- UInt32 a,b,c,d,e,f,g,h;
- #else
- UInt32 T[8];
- #endif
-
- for (j = 0; j < 16; j += 4)
- {
- const Byte *ccc = p->buffer + j * 4;
- W[j ] = GetBe32(ccc);
- W[j + 1] = GetBe32(ccc + 4);
- W[j + 2] = GetBe32(ccc + 8);
- W[j + 3] = GetBe32(ccc + 12);
- }
-
- state = p->state;
-
- #ifdef _SHA256_UNROLL2
- a = state[0];
- b = state[1];
- c = state[2];
- d = state[3];
- e = state[4];
- f = state[5];
- g = state[6];
- h = state[7];
- #else
- for (j = 0; j < 8; j++)
- T[j] = state[j];
- #endif
-
- for (j = 0; j < 64; j += 16)
- {
- RX_16
- }
-
- #ifdef _SHA256_UNROLL2
- state[0] += a;
- state[1] += b;
- state[2] += c;
- state[3] += d;
- state[4] += e;
- state[5] += f;
- state[6] += g;
- state[7] += h;
- #else
- for (j = 0; j < 8; j++)
- state[j] += T[j];
- #endif
-
- /* Wipe variables */
- /* memset(W, 0, sizeof(W)); */
- /* memset(T, 0, sizeof(T)); */
-}
-
-#undef S0
-#undef S1
-#undef s0
-#undef s1
-
-void Sha256_Update(CSha256 *p, const Byte *data, size_t size)
-{
- if (size == 0)
- return;
-
- {
- unsigned pos = (unsigned)p->count & 0x3F;
- unsigned num;
-
- p->count += size;
-
- num = 64 - pos;
- if (num > size)
- {
- memcpy(p->buffer + pos, data, size);
- return;
- }
-
- size -= num;
- memcpy(p->buffer + pos, data, num);
- data += num;
- }
-
- for (;;)
- {
- Sha256_WriteByteBlock(p);
- if (size < 64)
- break;
- size -= 64;
- memcpy(p->buffer, data, 64);
- data += 64;
- }
-
- if (size != 0)
- memcpy(p->buffer, data, size);
-}
-
-void Sha256_Final(CSha256 *p, Byte *digest)
-{
- unsigned pos = (unsigned)p->count & 0x3F;
- unsigned i;
-
- p->buffer[pos++] = 0x80;
-
- while (pos != (64 - 8))
- {
- pos &= 0x3F;
- if (pos == 0)
- Sha256_WriteByteBlock(p);
- p->buffer[pos++] = 0;
- }
-
- {
- UInt64 numBits = (p->count << 3);
- SetBe32(p->buffer + 64 - 8, (UInt32)(numBits >> 32));
- SetBe32(p->buffer + 64 - 4, (UInt32)(numBits));
- }
-
- Sha256_WriteByteBlock(p);
-
- for (i = 0; i < 8; i += 2)
- {
- UInt32 v0 = p->state[i];
- UInt32 v1 = p->state[i + 1];
- SetBe32(digest , v0);
- SetBe32(digest + 4, v1);
- digest += 8;
- }
-
- Sha256_Init(p);
-}
+/* Sha256.c -- SHA-256 Hash
+2023-04-02 : Igor Pavlov : Public domain
+This code is based on public domain code from Wei Dai's Crypto++ library. */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#include "CpuArch.h"
+#include "RotateDefs.h"
+#include "Sha256.h"
+
+#if defined(_MSC_VER) && (_MSC_VER < 1900)
+// #define USE_MY_MM
+#endif
+
+#ifdef MY_CPU_X86_OR_AMD64
+ #ifdef _MSC_VER
+ #if _MSC_VER >= 1200
+ #define Z7_COMPILER_SHA256_SUPPORTED
+ #endif
+ #elif defined(__clang__)
+ #if (__clang_major__ >= 8) // fix that check
+ #define Z7_COMPILER_SHA256_SUPPORTED
+ #endif
+ #elif defined(__GNUC__)
+ #if (__GNUC__ >= 8) // fix that check
+ #define Z7_COMPILER_SHA256_SUPPORTED
+ #endif
+ #elif defined(__INTEL_COMPILER)
+ #if (__INTEL_COMPILER >= 1800) // fix that check
+ #define Z7_COMPILER_SHA256_SUPPORTED
+ #endif
+ #endif
+#elif defined(MY_CPU_ARM_OR_ARM64)
+ #ifdef _MSC_VER
+ #if _MSC_VER >= 1910
+ #define Z7_COMPILER_SHA256_SUPPORTED
+ #endif
+ #elif defined(__clang__)
+ #if (__clang_major__ >= 8) // fix that check
+ #define Z7_COMPILER_SHA256_SUPPORTED
+ #endif
+ #elif defined(__GNUC__)
+ #if (__GNUC__ >= 6) // fix that check
+ #define Z7_COMPILER_SHA256_SUPPORTED
+ #endif
+ #endif
+#endif
+
+void Z7_FASTCALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks);
+
+#ifdef Z7_COMPILER_SHA256_SUPPORTED
+ void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks);
+
+ static SHA256_FUNC_UPDATE_BLOCKS g_SHA256_FUNC_UPDATE_BLOCKS = Sha256_UpdateBlocks;
+ static SHA256_FUNC_UPDATE_BLOCKS g_SHA256_FUNC_UPDATE_BLOCKS_HW;
+
+ #define SHA256_UPDATE_BLOCKS(p) p->func_UpdateBlocks
+#else
+ #define SHA256_UPDATE_BLOCKS(p) Sha256_UpdateBlocks
+#endif
+
+
+BoolInt Sha256_SetFunction(CSha256 *p, unsigned algo)
+{
+ SHA256_FUNC_UPDATE_BLOCKS func = Sha256_UpdateBlocks;
+
+ #ifdef Z7_COMPILER_SHA256_SUPPORTED
+ if (algo != SHA256_ALGO_SW)
+ {
+ if (algo == SHA256_ALGO_DEFAULT)
+ func = g_SHA256_FUNC_UPDATE_BLOCKS;
+ else
+ {
+ if (algo != SHA256_ALGO_HW)
+ return False;
+ func = g_SHA256_FUNC_UPDATE_BLOCKS_HW;
+ if (!func)
+ return False;
+ }
+ }
+ #else
+ if (algo > 1)
+ return False;
+ #endif
+
+ p->func_UpdateBlocks = func;
+ return True;
+}
+
+
+/* define it for speed optimization */
+
+#ifdef Z7_SFX
+ #define STEP_PRE 1
+ #define STEP_MAIN 1
+#else
+ #define STEP_PRE 2
+ #define STEP_MAIN 4
+ // #define Z7_SHA256_UNROLL
+#endif
+
+#undef Z7_SHA256_BIG_W
+#if STEP_MAIN != 16
+ #define Z7_SHA256_BIG_W
+#endif
+
+
+
+
+void Sha256_InitState(CSha256 *p)
+{
+ p->count = 0;
+ p->state[0] = 0x6a09e667;
+ p->state[1] = 0xbb67ae85;
+ p->state[2] = 0x3c6ef372;
+ p->state[3] = 0xa54ff53a;
+ p->state[4] = 0x510e527f;
+ p->state[5] = 0x9b05688c;
+ p->state[6] = 0x1f83d9ab;
+ p->state[7] = 0x5be0cd19;
+}
+
+void Sha256_Init(CSha256 *p)
+{
+ p->func_UpdateBlocks =
+ #ifdef Z7_COMPILER_SHA256_SUPPORTED
+ g_SHA256_FUNC_UPDATE_BLOCKS;
+ #else
+ NULL;
+ #endif
+ Sha256_InitState(p);
+}
+
+#define S0(x) (rotrFixed(x, 2) ^ rotrFixed(x,13) ^ rotrFixed(x, 22))
+#define S1(x) (rotrFixed(x, 6) ^ rotrFixed(x,11) ^ rotrFixed(x, 25))
+#define s0(x) (rotrFixed(x, 7) ^ rotrFixed(x,18) ^ (x >> 3))
+#define s1(x) (rotrFixed(x,17) ^ rotrFixed(x,19) ^ (x >> 10))
+
+#define Ch(x,y,z) (z^(x&(y^z)))
+#define Maj(x,y,z) ((x&y)|(z&(x|y)))
+
+
+#define W_PRE(i) (W[(i) + (size_t)(j)] = GetBe32(data + ((size_t)(j) + i) * 4))
+
+#define blk2_main(j, i) s1(w(j, (i)-2)) + w(j, (i)-7) + s0(w(j, (i)-15))
+
+#ifdef Z7_SHA256_BIG_W
+ // we use +i instead of +(i) to change the order to solve CLANG compiler warning for signed/unsigned.
+ #define w(j, i) W[(size_t)(j) + i]
+ #define blk2(j, i) (w(j, i) = w(j, (i)-16) + blk2_main(j, i))
+#else
+ #if STEP_MAIN == 16
+ #define w(j, i) W[(i) & 15]
+ #else
+ #define w(j, i) W[((size_t)(j) + (i)) & 15]
+ #endif
+ #define blk2(j, i) (w(j, i) += blk2_main(j, i))
+#endif
+
+#define W_MAIN(i) blk2(j, i)
+
+
+#define T1(wx, i) \
+ tmp = h + S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \
+ h = g; \
+ g = f; \
+ f = e; \
+ e = d + tmp; \
+ tmp += S0(a) + Maj(a, b, c); \
+ d = c; \
+ c = b; \
+ b = a; \
+ a = tmp; \
+
+#define R1_PRE(i) T1( W_PRE, i)
+#define R1_MAIN(i) T1( W_MAIN, i)
+
+#if (!defined(Z7_SHA256_UNROLL) || STEP_MAIN < 8) && (STEP_MAIN >= 4)
+#define R2_MAIN(i) \
+ R1_MAIN(i) \
+ R1_MAIN(i + 1) \
+
+#endif
+
+
+
+#if defined(Z7_SHA256_UNROLL) && STEP_MAIN >= 8
+
+#define T4( a,b,c,d,e,f,g,h, wx, i) \
+ h += S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \
+ tmp = h; \
+ h += d; \
+ d = tmp + S0(a) + Maj(a, b, c); \
+
+#define R4( wx, i) \
+ T4 ( a,b,c,d,e,f,g,h, wx, (i )); \
+ T4 ( d,a,b,c,h,e,f,g, wx, (i+1)); \
+ T4 ( c,d,a,b,g,h,e,f, wx, (i+2)); \
+ T4 ( b,c,d,a,f,g,h,e, wx, (i+3)); \
+
+#define R4_PRE(i) R4( W_PRE, i)
+#define R4_MAIN(i) R4( W_MAIN, i)
+
+
+#define T8( a,b,c,d,e,f,g,h, wx, i) \
+ h += S1(e) + Ch(e,f,g) + K[(i)+(size_t)(j)] + wx(i); \
+ d += h; \
+ h += S0(a) + Maj(a, b, c); \
+
+#define R8( wx, i) \
+ T8 ( a,b,c,d,e,f,g,h, wx, i ); \
+ T8 ( h,a,b,c,d,e,f,g, wx, i+1); \
+ T8 ( g,h,a,b,c,d,e,f, wx, i+2); \
+ T8 ( f,g,h,a,b,c,d,e, wx, i+3); \
+ T8 ( e,f,g,h,a,b,c,d, wx, i+4); \
+ T8 ( d,e,f,g,h,a,b,c, wx, i+5); \
+ T8 ( c,d,e,f,g,h,a,b, wx, i+6); \
+ T8 ( b,c,d,e,f,g,h,a, wx, i+7); \
+
+#define R8_PRE(i) R8( W_PRE, i)
+#define R8_MAIN(i) R8( W_MAIN, i)
+
+#endif
+
+void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks);
+
+// static
+extern MY_ALIGN(64)
+const UInt32 SHA256_K_ARRAY[64];
+
+MY_ALIGN(64)
+const UInt32 SHA256_K_ARRAY[64] = {
+ 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
+ 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
+ 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
+ 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
+ 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
+ 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
+ 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
+ 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
+ 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
+ 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
+ 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
+ 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
+ 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
+ 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
+ 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
+ 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
+};
+
+#define K SHA256_K_ARRAY
+
+
+Z7_NO_INLINE
+void Z7_FASTCALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks)
+{
+ UInt32 W
+ #ifdef Z7_SHA256_BIG_W
+ [64];
+ #else
+ [16];
+ #endif
+
+ unsigned j;
+
+ UInt32 a,b,c,d,e,f,g,h;
+
+ #if !defined(Z7_SHA256_UNROLL) || (STEP_MAIN <= 4) || (STEP_PRE <= 4)
+ UInt32 tmp;
+ #endif
+
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+ f = state[5];
+ g = state[6];
+ h = state[7];
+
+ while (numBlocks)
+ {
+
+ for (j = 0; j < 16; j += STEP_PRE)
+ {
+ #if STEP_PRE > 4
+
+ #if STEP_PRE < 8
+ R4_PRE(0);
+ #else
+ R8_PRE(0);
+ #if STEP_PRE == 16
+ R8_PRE(8);
+ #endif
+ #endif
+
+ #else
+
+ R1_PRE(0)
+ #if STEP_PRE >= 2
+ R1_PRE(1)
+ #if STEP_PRE >= 4
+ R1_PRE(2)
+ R1_PRE(3)
+ #endif
+ #endif
+
+ #endif
+ }
+
+ for (j = 16; j < 64; j += STEP_MAIN)
+ {
+ #if defined(Z7_SHA256_UNROLL) && STEP_MAIN >= 8
+
+ #if STEP_MAIN < 8
+ R4_MAIN(0)
+ #else
+ R8_MAIN(0)
+ #if STEP_MAIN == 16
+ R8_MAIN(8)
+ #endif
+ #endif
+
+ #else
+
+ R1_MAIN(0)
+ #if STEP_MAIN >= 2
+ R1_MAIN(1)
+ #if STEP_MAIN >= 4
+ R2_MAIN(2)
+ #if STEP_MAIN >= 8
+ R2_MAIN(4)
+ R2_MAIN(6)
+ #if STEP_MAIN >= 16
+ R2_MAIN(8)
+ R2_MAIN(10)
+ R2_MAIN(12)
+ R2_MAIN(14)
+ #endif
+ #endif
+ #endif
+ #endif
+ #endif
+ }
+
+ a += state[0]; state[0] = a;
+ b += state[1]; state[1] = b;
+ c += state[2]; state[2] = c;
+ d += state[3]; state[3] = d;
+ e += state[4]; state[4] = e;
+ f += state[5]; state[5] = f;
+ g += state[6]; state[6] = g;
+ h += state[7]; state[7] = h;
+
+ data += 64;
+ numBlocks--;
+ }
+
+ /* Wipe variables */
+ /* memset(W, 0, sizeof(W)); */
+}
+
+#undef S0
+#undef S1
+#undef s0
+#undef s1
+#undef K
+
+#define Sha256_UpdateBlock(p) SHA256_UPDATE_BLOCKS(p)(p->state, p->buffer, 1)
+
+void Sha256_Update(CSha256 *p, const Byte *data, size_t size)
+{
+ if (size == 0)
+ return;
+
+ {
+ unsigned pos = (unsigned)p->count & 0x3F;
+ unsigned num;
+
+ p->count += size;
+
+ num = 64 - pos;
+ if (num > size)
+ {
+ memcpy(p->buffer + pos, data, size);
+ return;
+ }
+
+ if (pos != 0)
+ {
+ size -= num;
+ memcpy(p->buffer + pos, data, num);
+ data += num;
+ Sha256_UpdateBlock(p);
+ }
+ }
+ {
+ size_t numBlocks = size >> 6;
+ SHA256_UPDATE_BLOCKS(p)(p->state, data, numBlocks);
+ size &= 0x3F;
+ if (size == 0)
+ return;
+ data += (numBlocks << 6);
+ memcpy(p->buffer, data, size);
+ }
+}
+
+
+void Sha256_Final(CSha256 *p, Byte *digest)
+{
+ unsigned pos = (unsigned)p->count & 0x3F;
+ unsigned i;
+
+ p->buffer[pos++] = 0x80;
+
+ if (pos > (64 - 8))
+ {
+ while (pos != 64) { p->buffer[pos++] = 0; }
+ // memset(&p->buf.buffer[pos], 0, 64 - pos);
+ Sha256_UpdateBlock(p);
+ pos = 0;
+ }
+
+ /*
+ if (pos & 3)
+ {
+ p->buffer[pos] = 0;
+ p->buffer[pos + 1] = 0;
+ p->buffer[pos + 2] = 0;
+ pos += 3;
+ pos &= ~3;
+ }
+ {
+ for (; pos < 64 - 8; pos += 4)
+ *(UInt32 *)(&p->buffer[pos]) = 0;
+ }
+ */
+
+ memset(&p->buffer[pos], 0, (64 - 8) - pos);
+
+ {
+ UInt64 numBits = (p->count << 3);
+ SetBe32(p->buffer + 64 - 8, (UInt32)(numBits >> 32))
+ SetBe32(p->buffer + 64 - 4, (UInt32)(numBits))
+ }
+
+ Sha256_UpdateBlock(p);
+
+ for (i = 0; i < 8; i += 2)
+ {
+ UInt32 v0 = p->state[i];
+ UInt32 v1 = p->state[(size_t)i + 1];
+ SetBe32(digest , v0)
+ SetBe32(digest + 4, v1)
+ digest += 8;
+ }
+
+ Sha256_InitState(p);
+}
+
+
+void Sha256Prepare(void)
+{
+ #ifdef Z7_COMPILER_SHA256_SUPPORTED
+ SHA256_FUNC_UPDATE_BLOCKS f, f_hw;
+ f = Sha256_UpdateBlocks;
+ f_hw = NULL;
+ #ifdef MY_CPU_X86_OR_AMD64
+ #ifndef USE_MY_MM
+ if (CPU_IsSupported_SHA()
+ && CPU_IsSupported_SSSE3()
+ // && CPU_IsSupported_SSE41()
+ )
+ #endif
+ #else
+ if (CPU_IsSupported_SHA2())
+ #endif
+ {
+ // printf("\n========== HW SHA256 ======== \n");
+ f = f_hw = Sha256_UpdateBlocks_HW;
+ }
+ g_SHA256_FUNC_UPDATE_BLOCKS = f;
+ g_SHA256_FUNC_UPDATE_BLOCKS_HW = f_hw;
+ #endif
+}
+
+#undef S0
+#undef S1
+#undef s0
+#undef s1
+#undef Ch
+#undef Maj
+#undef W_MAIN
+#undef W_PRE
+#undef w
+#undef blk2_main
+#undef blk2
+#undef T1
+#undef T4
+#undef T8
+#undef R1_PRE
+#undef R1_MAIN
+#undef R2_MAIN
+#undef R4
+#undef R4_PRE
+#undef R4_MAIN
+#undef R8
+#undef R8_PRE
+#undef R8_MAIN
+#undef STEP_PRE
+#undef STEP_MAIN
+#undef Z7_SHA256_BIG_W
+#undef Z7_SHA256_UNROLL
+#undef Z7_COMPILER_SHA256_SUPPORTED
diff --git a/C/Sha256.h b/C/Sha256.h
index 7f17ccf..9e04223 100644
--- a/C/Sha256.h
+++ b/C/Sha256.h
@@ -1,26 +1,76 @@
-/* Sha256.h -- SHA-256 Hash
-2013-01-18 : Igor Pavlov : Public domain */
-
-#ifndef __CRYPTO_SHA256_H
-#define __CRYPTO_SHA256_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-#define SHA256_DIGEST_SIZE 32
-
-typedef struct
-{
- UInt32 state[8];
- UInt64 count;
- Byte buffer[64];
-} CSha256;
-
-void Sha256_Init(CSha256 *p);
-void Sha256_Update(CSha256 *p, const Byte *data, size_t size);
-void Sha256_Final(CSha256 *p, Byte *digest);
-
-EXTERN_C_END
-
-#endif
+/* Sha256.h -- SHA-256 Hash
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_SHA256_H
+#define ZIP7_INC_SHA256_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#define SHA256_NUM_BLOCK_WORDS 16
+#define SHA256_NUM_DIGEST_WORDS 8
+
+#define SHA256_BLOCK_SIZE (SHA256_NUM_BLOCK_WORDS * 4)
+#define SHA256_DIGEST_SIZE (SHA256_NUM_DIGEST_WORDS * 4)
+
+typedef void (Z7_FASTCALL *SHA256_FUNC_UPDATE_BLOCKS)(UInt32 state[8], const Byte *data, size_t numBlocks);
+
+/*
+ if (the system supports different SHA256 code implementations)
+ {
+ (CSha256::func_UpdateBlocks) will be used
+ (CSha256::func_UpdateBlocks) can be set by
+ Sha256_Init() - to default (fastest)
+ Sha256_SetFunction() - to any algo
+ }
+ else
+ {
+ (CSha256::func_UpdateBlocks) is ignored.
+ }
+*/
+
+typedef struct
+{
+ SHA256_FUNC_UPDATE_BLOCKS func_UpdateBlocks;
+ UInt64 count;
+ UInt64 _pad_2[2];
+ UInt32 state[SHA256_NUM_DIGEST_WORDS];
+
+ Byte buffer[SHA256_BLOCK_SIZE];
+} CSha256;
+
+
+#define SHA256_ALGO_DEFAULT 0
+#define SHA256_ALGO_SW 1
+#define SHA256_ALGO_HW 2
+
+/*
+Sha256_SetFunction()
+return:
+ 0 - (algo) value is not supported, and func_UpdateBlocks was not changed
+ 1 - func_UpdateBlocks was set according (algo) value.
+*/
+
+BoolInt Sha256_SetFunction(CSha256 *p, unsigned algo);
+
+void Sha256_InitState(CSha256 *p);
+void Sha256_Init(CSha256 *p);
+void Sha256_Update(CSha256 *p, const Byte *data, size_t size);
+void Sha256_Final(CSha256 *p, Byte *digest);
+
+
+
+
+// void Z7_FASTCALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks);
+
+/*
+call Sha256Prepare() once at program start.
+It prepares all supported implementations, and detects the fastest implementation.
+*/
+
+void Sha256Prepare(void);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Sha256Opt.c b/C/Sha256Opt.c
new file mode 100644
index 0000000..e4465e3
--- /dev/null
+++ b/C/Sha256Opt.c
@@ -0,0 +1,386 @@
+/* Sha256Opt.c -- SHA-256 optimized code for SHA-256 hardware instructions
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+#include "Compiler.h"
+#include "CpuArch.h"
+
+#if defined(_MSC_VER)
+#if (_MSC_VER < 1900) && (_MSC_VER >= 1200)
+// #define USE_MY_MM
+#endif
+#endif
+
+#ifdef MY_CPU_X86_OR_AMD64
+ #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1600) // fix that check
+ #define USE_HW_SHA
+ #elif defined(Z7_LLVM_CLANG_VERSION) && (Z7_LLVM_CLANG_VERSION >= 30800) \
+ || defined(Z7_APPLE_CLANG_VERSION) && (Z7_APPLE_CLANG_VERSION >= 50100) \
+ || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40900)
+ #define USE_HW_SHA
+ #if !defined(_INTEL_COMPILER)
+ // icc defines __GNUC__, but icc doesn't support __attribute__(__target__)
+ #if !defined(__SHA__) || !defined(__SSSE3__)
+ #define ATTRIB_SHA __attribute__((__target__("sha,ssse3")))
+ #endif
+ #endif
+ #elif defined(_MSC_VER)
+ #ifdef USE_MY_MM
+ #define USE_VER_MIN 1300
+ #else
+ #define USE_VER_MIN 1900
+ #endif
+ #if (_MSC_VER >= USE_VER_MIN)
+ #define USE_HW_SHA
+ #endif
+ #endif
+// #endif // MY_CPU_X86_OR_AMD64
+
+#ifdef USE_HW_SHA
+
+// #pragma message("Sha256 HW")
+
+// sse/sse2/ssse3:
+#include <tmmintrin.h>
+// sha*:
+#include <immintrin.h>
+
+#if defined (__clang__) && defined(_MSC_VER)
+ // #if !defined(__SSSE3__)
+ // #endif
+ #if !defined(__SHA__)
+ #include <shaintrin.h>
+ #endif
+#else
+
+#ifdef USE_MY_MM
+#include "My_mm.h"
+#endif
+
+#endif
+
+/*
+SHA256 uses:
+SSE2:
+ _mm_loadu_si128
+ _mm_storeu_si128
+ _mm_set_epi32
+ _mm_add_epi32
+ _mm_shuffle_epi32 / pshufd
+
+
+
+SSSE3:
+ _mm_shuffle_epi8 / pshufb
+ _mm_alignr_epi8
+SHA:
+ _mm_sha256*
+*/
+
+// K array must be aligned for 16-bytes at least.
+// The compiler can look align attribute and selects
+// movdqu - for code without align attribute
+// movdqa - for code with align attribute
+extern
+MY_ALIGN(64)
+const UInt32 SHA256_K_ARRAY[64];
+
+#define K SHA256_K_ARRAY
+
+
+#define ADD_EPI32(dest, src) dest = _mm_add_epi32(dest, src);
+#define SHA256_MSG1(dest, src) dest = _mm_sha256msg1_epu32(dest, src);
+#define SHA25G_MSG2(dest, src) dest = _mm_sha256msg2_epu32(dest, src);
+
+
+#define LOAD_SHUFFLE(m, k) \
+ m = _mm_loadu_si128((const __m128i *)(const void *)(data + (k) * 16)); \
+ m = _mm_shuffle_epi8(m, mask); \
+
+#define SM1(g0, g1, g2, g3) \
+ SHA256_MSG1(g3, g0); \
+
+#define SM2(g0, g1, g2, g3) \
+ tmp = _mm_alignr_epi8(g1, g0, 4); \
+ ADD_EPI32(g2, tmp) \
+ SHA25G_MSG2(g2, g1); \
+
+// #define LS0(k, g0, g1, g2, g3) LOAD_SHUFFLE(g0, k)
+// #define LS1(k, g0, g1, g2, g3) LOAD_SHUFFLE(g1, k+1)
+
+
+#define NNN(g0, g1, g2, g3)
+
+
+#define RND2(t0, t1) \
+ t0 = _mm_sha256rnds2_epu32(t0, t1, msg);
+
+#define RND2_0(m, k) \
+ msg = _mm_add_epi32(m, *(const __m128i *) (const void *) &K[(k) * 4]); \
+ RND2(state0, state1); \
+ msg = _mm_shuffle_epi32(msg, 0x0E); \
+
+
+#define RND2_1 \
+ RND2(state1, state0); \
+
+
+// We use scheme with 3 rounds ahead for SHA256_MSG1 / 2 rounds ahead for SHA256_MSG2
+
+#define R4(k, g0, g1, g2, g3, OP0, OP1) \
+ RND2_0(g0, k) \
+ OP0(g0, g1, g2, g3) \
+ RND2_1 \
+ OP1(g0, g1, g2, g3) \
+
+#define R16(k, OP0, OP1, OP2, OP3, OP4, OP5, OP6, OP7) \
+ R4 ( (k)*4+0, m0,m1,m2,m3, OP0, OP1 ) \
+ R4 ( (k)*4+1, m1,m2,m3,m0, OP2, OP3 ) \
+ R4 ( (k)*4+2, m2,m3,m0,m1, OP4, OP5 ) \
+ R4 ( (k)*4+3, m3,m0,m1,m2, OP6, OP7 ) \
+
+#define PREPARE_STATE \
+ tmp = _mm_shuffle_epi32(state0, 0x1B); /* abcd */ \
+ state0 = _mm_shuffle_epi32(state1, 0x1B); /* efgh */ \
+ state1 = state0; \
+ state0 = _mm_unpacklo_epi64(state0, tmp); /* cdgh */ \
+ state1 = _mm_unpackhi_epi64(state1, tmp); /* abef */ \
+
+
+void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks);
+#ifdef ATTRIB_SHA
+ATTRIB_SHA
+#endif
+void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks)
+{
+ const __m128i mask = _mm_set_epi32(0x0c0d0e0f, 0x08090a0b, 0x04050607, 0x00010203);
+ __m128i tmp;
+ __m128i state0, state1;
+
+ if (numBlocks == 0)
+ return;
+
+ state0 = _mm_loadu_si128((const __m128i *) (const void *) &state[0]);
+ state1 = _mm_loadu_si128((const __m128i *) (const void *) &state[4]);
+
+ PREPARE_STATE
+
+ do
+ {
+ __m128i state0_save, state1_save;
+ __m128i m0, m1, m2, m3;
+ __m128i msg;
+ // #define msg tmp
+
+ state0_save = state0;
+ state1_save = state1;
+
+ LOAD_SHUFFLE (m0, 0)
+ LOAD_SHUFFLE (m1, 1)
+ LOAD_SHUFFLE (m2, 2)
+ LOAD_SHUFFLE (m3, 3)
+
+
+
+ R16 ( 0, NNN, NNN, SM1, NNN, SM1, SM2, SM1, SM2 )
+ R16 ( 1, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 )
+ R16 ( 2, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 )
+ R16 ( 3, SM1, SM2, NNN, SM2, NNN, NNN, NNN, NNN )
+
+ ADD_EPI32(state0, state0_save)
+ ADD_EPI32(state1, state1_save)
+
+ data += 64;
+ }
+ while (--numBlocks);
+
+ PREPARE_STATE
+
+ _mm_storeu_si128((__m128i *) (void *) &state[0], state0);
+ _mm_storeu_si128((__m128i *) (void *) &state[4], state1);
+}
+
+#endif // USE_HW_SHA
+
+#elif defined(MY_CPU_ARM_OR_ARM64)
+
+ #if defined(__clang__)
+ #if (__clang_major__ >= 8) // fix that check
+ #define USE_HW_SHA
+ #endif
+ #elif defined(__GNUC__)
+ #if (__GNUC__ >= 6) // fix that check
+ #define USE_HW_SHA
+ #endif
+ #elif defined(_MSC_VER)
+ #if _MSC_VER >= 1910
+ #define USE_HW_SHA
+ #endif
+ #endif
+
+#ifdef USE_HW_SHA
+
+// #pragma message("=== Sha256 HW === ")
+
+#if defined(__clang__) || defined(__GNUC__)
+ #ifdef MY_CPU_ARM64
+ #define ATTRIB_SHA __attribute__((__target__("+crypto")))
+ #else
+ #define ATTRIB_SHA __attribute__((__target__("fpu=crypto-neon-fp-armv8")))
+ #endif
+#else
+ // _MSC_VER
+ // for arm32
+ #define _ARM_USE_NEW_NEON_INTRINSICS
+#endif
+
+#if defined(_MSC_VER) && defined(MY_CPU_ARM64)
+#include <arm64_neon.h>
+#else
+#include <arm_neon.h>
+#endif
+
+typedef uint32x4_t v128;
+// typedef __n128 v128; // MSVC
+
+#ifdef MY_CPU_BE
+ #define MY_rev32_for_LE(x)
+#else
+ #define MY_rev32_for_LE(x) x = vreinterpretq_u32_u8(vrev32q_u8(vreinterpretq_u8_u32(x)))
+#endif
+
+#define LOAD_128(_p) (*(const v128 *)(const void *)(_p))
+#define STORE_128(_p, _v) *(v128 *)(void *)(_p) = (_v)
+
+#define LOAD_SHUFFLE(m, k) \
+ m = LOAD_128((data + (k) * 16)); \
+ MY_rev32_for_LE(m); \
+
+// K array must be aligned for 16-bytes at least.
+extern
+MY_ALIGN(64)
+const UInt32 SHA256_K_ARRAY[64];
+
+#define K SHA256_K_ARRAY
+
+
+#define SHA256_SU0(dest, src) dest = vsha256su0q_u32(dest, src);
+#define SHA25G_SU1(dest, src2, src3) dest = vsha256su1q_u32(dest, src2, src3);
+
+#define SM1(g0, g1, g2, g3) SHA256_SU0(g3, g0)
+#define SM2(g0, g1, g2, g3) SHA25G_SU1(g2, g0, g1)
+#define NNN(g0, g1, g2, g3)
+
+
+#define R4(k, g0, g1, g2, g3, OP0, OP1) \
+ msg = vaddq_u32(g0, *(const v128 *) (const void *) &K[(k) * 4]); \
+ tmp = state0; \
+ state0 = vsha256hq_u32( state0, state1, msg ); \
+ state1 = vsha256h2q_u32( state1, tmp, msg ); \
+ OP0(g0, g1, g2, g3); \
+ OP1(g0, g1, g2, g3); \
+
+
+#define R16(k, OP0, OP1, OP2, OP3, OP4, OP5, OP6, OP7) \
+ R4 ( (k)*4+0, m0, m1, m2, m3, OP0, OP1 ) \
+ R4 ( (k)*4+1, m1, m2, m3, m0, OP2, OP3 ) \
+ R4 ( (k)*4+2, m2, m3, m0, m1, OP4, OP5 ) \
+ R4 ( (k)*4+3, m3, m0, m1, m2, OP6, OP7 ) \
+
+
+void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks);
+#ifdef ATTRIB_SHA
+ATTRIB_SHA
+#endif
+void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks)
+{
+ v128 state0, state1;
+
+ if (numBlocks == 0)
+ return;
+
+ state0 = LOAD_128(&state[0]);
+ state1 = LOAD_128(&state[4]);
+
+ do
+ {
+ v128 state0_save, state1_save;
+ v128 m0, m1, m2, m3;
+ v128 msg, tmp;
+
+ state0_save = state0;
+ state1_save = state1;
+
+ LOAD_SHUFFLE (m0, 0)
+ LOAD_SHUFFLE (m1, 1)
+ LOAD_SHUFFLE (m2, 2)
+ LOAD_SHUFFLE (m3, 3)
+
+ R16 ( 0, NNN, NNN, SM1, NNN, SM1, SM2, SM1, SM2 );
+ R16 ( 1, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 );
+ R16 ( 2, SM1, SM2, SM1, SM2, SM1, SM2, SM1, SM2 );
+ R16 ( 3, SM1, SM2, NNN, SM2, NNN, NNN, NNN, NNN );
+
+ state0 = vaddq_u32(state0, state0_save);
+ state1 = vaddq_u32(state1, state1_save);
+
+ data += 64;
+ }
+ while (--numBlocks);
+
+ STORE_128(&state[0], state0);
+ STORE_128(&state[4], state1);
+}
+
+#endif // USE_HW_SHA
+
+#endif // MY_CPU_ARM_OR_ARM64
+
+
+#ifndef USE_HW_SHA
+
+// #error Stop_Compiling_UNSUPPORTED_SHA
+// #include <stdlib.h>
+
+// #include "Sha256.h"
+void Z7_FASTCALL Sha256_UpdateBlocks(UInt32 state[8], const Byte *data, size_t numBlocks);
+
+#pragma message("Sha256 HW-SW stub was used")
+
+void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks);
+void Z7_FASTCALL Sha256_UpdateBlocks_HW(UInt32 state[8], const Byte *data, size_t numBlocks)
+{
+ Sha256_UpdateBlocks(state, data, numBlocks);
+ /*
+ UNUSED_VAR(state);
+ UNUSED_VAR(data);
+ UNUSED_VAR(numBlocks);
+ exit(1);
+ return;
+ */
+}
+
+#endif
+
+
+
+#undef K
+#undef RND2
+#undef RND2_0
+#undef RND2_1
+
+#undef MY_rev32_for_LE
+#undef NNN
+#undef LOAD_128
+#undef STORE_128
+#undef LOAD_SHUFFLE
+#undef SM1
+#undef SM2
+
+#undef NNN
+#undef R4
+#undef R16
+#undef PREPARE_STATE
+#undef USE_HW_SHA
+#undef ATTRIB_SHA
+#undef USE_VER_MIN
diff --git a/C/Sort.c b/C/Sort.c
index 73dcbf0..e1097e3 100644
--- a/C/Sort.c
+++ b/C/Sort.c
@@ -1,141 +1,141 @@
-/* Sort.c -- Sort functions
-2014-04-05 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "Sort.h"
-
-#define HeapSortDown(p, k, size, temp) \
- { for (;;) { \
- size_t s = (k << 1); \
- if (s > size) break; \
- if (s < size && p[s + 1] > p[s]) s++; \
- if (temp >= p[s]) break; \
- p[k] = p[s]; k = s; \
- } p[k] = temp; }
-
-void HeapSort(UInt32 *p, size_t size)
-{
- if (size <= 1)
- return;
- p--;
- {
- size_t i = size / 2;
- do
- {
- UInt32 temp = p[i];
- size_t k = i;
- HeapSortDown(p, k, size, temp)
- }
- while (--i != 0);
- }
- /*
- do
- {
- size_t k = 1;
- UInt32 temp = p[size];
- p[size--] = p[1];
- HeapSortDown(p, k, size, temp)
- }
- while (size > 1);
- */
- while (size > 3)
- {
- UInt32 temp = p[size];
- size_t k = (p[3] > p[2]) ? 3 : 2;
- p[size--] = p[1];
- p[1] = p[k];
- HeapSortDown(p, k, size, temp)
- }
- {
- UInt32 temp = p[size];
- p[size] = p[1];
- if (size > 2 && p[2] < temp)
- {
- p[1] = p[2];
- p[2] = temp;
- }
- else
- p[1] = temp;
- }
-}
-
-void HeapSort64(UInt64 *p, size_t size)
-{
- if (size <= 1)
- return;
- p--;
- {
- size_t i = size / 2;
- do
- {
- UInt64 temp = p[i];
- size_t k = i;
- HeapSortDown(p, k, size, temp)
- }
- while (--i != 0);
- }
- /*
- do
- {
- size_t k = 1;
- UInt64 temp = p[size];
- p[size--] = p[1];
- HeapSortDown(p, k, size, temp)
- }
- while (size > 1);
- */
- while (size > 3)
- {
- UInt64 temp = p[size];
- size_t k = (p[3] > p[2]) ? 3 : 2;
- p[size--] = p[1];
- p[1] = p[k];
- HeapSortDown(p, k, size, temp)
- }
- {
- UInt64 temp = p[size];
- p[size] = p[1];
- if (size > 2 && p[2] < temp)
- {
- p[1] = p[2];
- p[2] = temp;
- }
- else
- p[1] = temp;
- }
-}
-
-/*
-#define HeapSortRefDown(p, vals, n, size, temp) \
- { size_t k = n; UInt32 val = vals[temp]; for (;;) { \
- size_t s = (k << 1); \
- if (s > size) break; \
- if (s < size && vals[p[s + 1]] > vals[p[s]]) s++; \
- if (val >= vals[p[s]]) break; \
- p[k] = p[s]; k = s; \
- } p[k] = temp; }
-
-void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size)
-{
- if (size <= 1)
- return;
- p--;
- {
- size_t i = size / 2;
- do
- {
- UInt32 temp = p[i];
- HeapSortRefDown(p, vals, i, size, temp);
- }
- while (--i != 0);
- }
- do
- {
- UInt32 temp = p[size];
- p[size--] = p[1];
- HeapSortRefDown(p, vals, 1, size, temp);
- }
- while (size > 1);
-}
-*/
+/* Sort.c -- Sort functions
+2014-04-05 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Sort.h"
+
+#define HeapSortDown(p, k, size, temp) \
+ { for (;;) { \
+ size_t s = (k << 1); \
+ if (s > size) break; \
+ if (s < size && p[s + 1] > p[s]) s++; \
+ if (temp >= p[s]) break; \
+ p[k] = p[s]; k = s; \
+ } p[k] = temp; }
+
+void HeapSort(UInt32 *p, size_t size)
+{
+ if (size <= 1)
+ return;
+ p--;
+ {
+ size_t i = size / 2;
+ do
+ {
+ UInt32 temp = p[i];
+ size_t k = i;
+ HeapSortDown(p, k, size, temp)
+ }
+ while (--i != 0);
+ }
+ /*
+ do
+ {
+ size_t k = 1;
+ UInt32 temp = p[size];
+ p[size--] = p[1];
+ HeapSortDown(p, k, size, temp)
+ }
+ while (size > 1);
+ */
+ while (size > 3)
+ {
+ UInt32 temp = p[size];
+ size_t k = (p[3] > p[2]) ? 3 : 2;
+ p[size--] = p[1];
+ p[1] = p[k];
+ HeapSortDown(p, k, size, temp)
+ }
+ {
+ UInt32 temp = p[size];
+ p[size] = p[1];
+ if (size > 2 && p[2] < temp)
+ {
+ p[1] = p[2];
+ p[2] = temp;
+ }
+ else
+ p[1] = temp;
+ }
+}
+
+void HeapSort64(UInt64 *p, size_t size)
+{
+ if (size <= 1)
+ return;
+ p--;
+ {
+ size_t i = size / 2;
+ do
+ {
+ UInt64 temp = p[i];
+ size_t k = i;
+ HeapSortDown(p, k, size, temp)
+ }
+ while (--i != 0);
+ }
+ /*
+ do
+ {
+ size_t k = 1;
+ UInt64 temp = p[size];
+ p[size--] = p[1];
+ HeapSortDown(p, k, size, temp)
+ }
+ while (size > 1);
+ */
+ while (size > 3)
+ {
+ UInt64 temp = p[size];
+ size_t k = (p[3] > p[2]) ? 3 : 2;
+ p[size--] = p[1];
+ p[1] = p[k];
+ HeapSortDown(p, k, size, temp)
+ }
+ {
+ UInt64 temp = p[size];
+ p[size] = p[1];
+ if (size > 2 && p[2] < temp)
+ {
+ p[1] = p[2];
+ p[2] = temp;
+ }
+ else
+ p[1] = temp;
+ }
+}
+
+/*
+#define HeapSortRefDown(p, vals, n, size, temp) \
+ { size_t k = n; UInt32 val = vals[temp]; for (;;) { \
+ size_t s = (k << 1); \
+ if (s > size) break; \
+ if (s < size && vals[p[s + 1]] > vals[p[s]]) s++; \
+ if (val >= vals[p[s]]) break; \
+ p[k] = p[s]; k = s; \
+ } p[k] = temp; }
+
+void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size)
+{
+ if (size <= 1)
+ return;
+ p--;
+ {
+ size_t i = size / 2;
+ do
+ {
+ UInt32 temp = p[i];
+ HeapSortRefDown(p, vals, i, size, temp);
+ }
+ while (--i != 0);
+ }
+ do
+ {
+ UInt32 temp = p[size];
+ p[size--] = p[1];
+ HeapSortRefDown(p, vals, 1, size, temp);
+ }
+ while (size > 1);
+}
+*/
diff --git a/C/Sort.h b/C/Sort.h
index 7209d78..1817b65 100644
--- a/C/Sort.h
+++ b/C/Sort.h
@@ -1,18 +1,18 @@
-/* Sort.h -- Sort functions
-2014-04-05 : Igor Pavlov : Public domain */
-
-#ifndef __7Z_SORT_H
-#define __7Z_SORT_H
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-void HeapSort(UInt32 *p, size_t size);
-void HeapSort64(UInt64 *p, size_t size);
-
-/* void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size); */
-
-EXTERN_C_END
-
-#endif
+/* Sort.h -- Sort functions
+2023-03-05 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_SORT_H
+#define ZIP7_INC_SORT_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+void HeapSort(UInt32 *p, size_t size);
+void HeapSort64(UInt64 *p, size_t size);
+
+/* void HeapSortRef(UInt32 *p, UInt32 *vals, size_t size); */
+
+EXTERN_C_END
+
+#endif
diff --git a/C/SwapBytes.c b/C/SwapBytes.c
new file mode 100644
index 0000000..7901bba
--- /dev/null
+++ b/C/SwapBytes.c
@@ -0,0 +1,800 @@
+/* SwapBytes.c -- Byte Swap conversion filter
+2023-04-07 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "Compiler.h"
+#include "CpuArch.h"
+#include "RotateDefs.h"
+#include "SwapBytes.h"
+
+typedef UInt16 CSwapUInt16;
+typedef UInt32 CSwapUInt32;
+
+// #define k_SwapBytes_Mode_BASE 0
+
+#ifdef MY_CPU_X86_OR_AMD64
+
+#define k_SwapBytes_Mode_SSE2 1
+#define k_SwapBytes_Mode_SSSE3 2
+#define k_SwapBytes_Mode_AVX2 3
+
+ // #if defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 1900)
+ #if defined(__clang__) && (__clang_major__ >= 4) \
+ || defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40701)
+ #define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_AVX2
+ #define SWAP_ATTRIB_SSE2 __attribute__((__target__("sse2")))
+ #define SWAP_ATTRIB_SSSE3 __attribute__((__target__("ssse3")))
+ #define SWAP_ATTRIB_AVX2 __attribute__((__target__("avx2")))
+ #elif defined(_MSC_VER)
+ #if (_MSC_VER == 1900)
+ #pragma warning(disable : 4752) // found Intel(R) Advanced Vector Extensions; consider using /arch:AVX
+ #endif
+ #if (_MSC_VER >= 1900)
+ #define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_AVX2
+ #elif (_MSC_VER >= 1500) // (VS2008)
+ #define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_SSSE3
+ #elif (_MSC_VER >= 1310) // (VS2003)
+ #define k_SwapBytes_Mode_MAX k_SwapBytes_Mode_SSE2
+ #endif
+ #endif // _MSC_VER
+
+/*
+// for debug
+#ifdef k_SwapBytes_Mode_MAX
+#undef k_SwapBytes_Mode_MAX
+#endif
+*/
+
+#ifndef k_SwapBytes_Mode_MAX
+#define k_SwapBytes_Mode_MAX 0
+#endif
+
+#if (k_SwapBytes_Mode_MAX != 0) && defined(MY_CPU_AMD64)
+ #define k_SwapBytes_Mode_MIN k_SwapBytes_Mode_SSE2
+#else
+ #define k_SwapBytes_Mode_MIN 0
+#endif
+
+#if (k_SwapBytes_Mode_MAX >= k_SwapBytes_Mode_AVX2)
+ #define USE_SWAP_AVX2
+#endif
+#if (k_SwapBytes_Mode_MAX >= k_SwapBytes_Mode_SSSE3)
+ #define USE_SWAP_SSSE3
+#endif
+#if (k_SwapBytes_Mode_MAX >= k_SwapBytes_Mode_SSE2)
+ #define USE_SWAP_128
+#endif
+
+#if k_SwapBytes_Mode_MAX <= k_SwapBytes_Mode_MIN || !defined(USE_SWAP_128)
+#define FORCE_SWAP_MODE
+#endif
+
+
+#ifdef USE_SWAP_128
+/*
+ <mmintrin.h> MMX
+<xmmintrin.h> SSE
+<emmintrin.h> SSE2
+<pmmintrin.h> SSE3
+<tmmintrin.h> SSSE3
+<smmintrin.h> SSE4.1
+<nmmintrin.h> SSE4.2
+<ammintrin.h> SSE4A
+<wmmintrin.h> AES
+<immintrin.h> AVX, AVX2, FMA
+*/
+
+#include <emmintrin.h> // sse2
+// typedef __m128i v128;
+
+#define SWAP2_128(i) { \
+ const __m128i v = *(const __m128i *)(const void *)(items + (i) * 8); \
+ *( __m128i *)( void *)(items + (i) * 8) = \
+ _mm_or_si128( \
+ _mm_slli_epi16(v, 8), \
+ _mm_srli_epi16(v, 8)); }
+// _mm_or_si128() has more ports to execute than _mm_add_epi16().
+
+static
+#ifdef SWAP_ATTRIB_SSE2
+SWAP_ATTRIB_SSE2
+#endif
+void
+Z7_FASTCALL
+SwapBytes2_128(CSwapUInt16 *items, const CSwapUInt16 *lim)
+{
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ do
+ {
+ SWAP2_128(0) SWAP2_128(1) items += 2 * 8;
+ SWAP2_128(0) SWAP2_128(1) items += 2 * 8;
+ }
+ while (items != lim);
+}
+
+/*
+// sse2
+#define SWAP4_128_pack(i) { \
+ __m128i v = *(const __m128i *)(const void *)(items + (i) * 4); \
+ __m128i v0 = _mm_unpacklo_epi8(v, mask); \
+ __m128i v1 = _mm_unpackhi_epi8(v, mask); \
+ v0 = _mm_shufflelo_epi16(v0, 0x1b); \
+ v1 = _mm_shufflelo_epi16(v1, 0x1b); \
+ v0 = _mm_shufflehi_epi16(v0, 0x1b); \
+ v1 = _mm_shufflehi_epi16(v1, 0x1b); \
+ *(__m128i *)(void *)(items + (i) * 4) = _mm_packus_epi16(v0, v1); }
+
+static
+#ifdef SWAP_ATTRIB_SSE2
+SWAP_ATTRIB_SSE2
+#endif
+void
+Z7_FASTCALL
+SwapBytes4_128_pack(CSwapUInt32 *items, const CSwapUInt32 *lim)
+{
+ const __m128i mask = _mm_setzero_si128();
+ // const __m128i mask = _mm_set_epi16(0, 0, 0, 0, 0, 0, 0, 0);
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ do
+ {
+ SWAP4_128_pack(0); items += 1 * 4;
+ // SWAP4_128_pack(0); SWAP4_128_pack(1); items += 2 * 4;
+ }
+ while (items != lim);
+}
+
+// sse2
+#define SWAP4_128_shift(i) { \
+ __m128i v = *(const __m128i *)(const void *)(items + (i) * 4); \
+ __m128i v2; \
+ v2 = _mm_or_si128( \
+ _mm_slli_si128(_mm_and_si128(v, mask), 1), \
+ _mm_and_si128(_mm_srli_si128(v, 1), mask)); \
+ v = _mm_or_si128( \
+ _mm_slli_epi32(v, 24), \
+ _mm_srli_epi32(v, 24)); \
+ *(__m128i *)(void *)(items + (i) * 4) = _mm_or_si128(v2, v); }
+
+static
+#ifdef SWAP_ATTRIB_SSE2
+SWAP_ATTRIB_SSE2
+#endif
+void
+Z7_FASTCALL
+SwapBytes4_128_shift(CSwapUInt32 *items, const CSwapUInt32 *lim)
+{
+ #define M1 0xff00
+ const __m128i mask = _mm_set_epi32(M1, M1, M1, M1);
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ do
+ {
+ // SWAP4_128_shift(0) SWAP4_128_shift(1) items += 2 * 4;
+ // SWAP4_128_shift(0) SWAP4_128_shift(1) items += 2 * 4;
+ SWAP4_128_shift(0); items += 1 * 4;
+ }
+ while (items != lim);
+}
+*/
+
+
+#if defined(USE_SWAP_SSSE3) || defined(USE_SWAP_AVX2)
+
+#define SWAP_SHUF_REV_SEQ_2_VALS(v) (v)+1, (v)
+#define SWAP_SHUF_REV_SEQ_4_VALS(v) (v)+3, (v)+2, (v)+1, (v)
+
+#define SWAP2_SHUF_MASK_16_BYTES \
+ SWAP_SHUF_REV_SEQ_2_VALS (0 * 2), \
+ SWAP_SHUF_REV_SEQ_2_VALS (1 * 2), \
+ SWAP_SHUF_REV_SEQ_2_VALS (2 * 2), \
+ SWAP_SHUF_REV_SEQ_2_VALS (3 * 2), \
+ SWAP_SHUF_REV_SEQ_2_VALS (4 * 2), \
+ SWAP_SHUF_REV_SEQ_2_VALS (5 * 2), \
+ SWAP_SHUF_REV_SEQ_2_VALS (6 * 2), \
+ SWAP_SHUF_REV_SEQ_2_VALS (7 * 2)
+
+#define SWAP4_SHUF_MASK_16_BYTES \
+ SWAP_SHUF_REV_SEQ_4_VALS (0 * 4), \
+ SWAP_SHUF_REV_SEQ_4_VALS (1 * 4), \
+ SWAP_SHUF_REV_SEQ_4_VALS (2 * 4), \
+ SWAP_SHUF_REV_SEQ_4_VALS (3 * 4)
+
+#if defined(USE_SWAP_AVX2)
+/* if we use 256_BIT_INIT_MASK, each static array mask will be larger for 16 bytes */
+// #define SWAP_USE_256_BIT_INIT_MASK
+#endif
+
+#if defined(SWAP_USE_256_BIT_INIT_MASK) && defined(USE_SWAP_AVX2)
+#define SWAP_MASK_INIT_SIZE 32
+#else
+#define SWAP_MASK_INIT_SIZE 16
+#endif
+
+MY_ALIGN(SWAP_MASK_INIT_SIZE)
+static const Byte k_ShufMask_Swap2[] =
+{
+ SWAP2_SHUF_MASK_16_BYTES
+ #if SWAP_MASK_INIT_SIZE > 16
+ , SWAP2_SHUF_MASK_16_BYTES
+ #endif
+};
+
+MY_ALIGN(SWAP_MASK_INIT_SIZE)
+static const Byte k_ShufMask_Swap4[] =
+{
+ SWAP4_SHUF_MASK_16_BYTES
+ #if SWAP_MASK_INIT_SIZE > 16
+ , SWAP4_SHUF_MASK_16_BYTES
+ #endif
+};
+
+
+#ifdef USE_SWAP_SSSE3
+
+#include <tmmintrin.h> // ssse3
+
+#define SHUF_128(i) *(items + (i)) = \
+ _mm_shuffle_epi8(*(items + (i)), mask); // SSSE3
+
+// Z7_NO_INLINE
+static
+#ifdef SWAP_ATTRIB_SSSE3
+SWAP_ATTRIB_SSSE3
+#endif
+Z7_ATTRIB_NO_VECTORIZE
+void
+Z7_FASTCALL
+ShufBytes_128(void *items8, const void *lim8, const void *mask128_ptr)
+{
+ __m128i *items = (__m128i *)items8;
+ const __m128i *lim = (const __m128i *)lim8;
+ // const __m128i mask = _mm_set_epi8(SHUF_SWAP2_MASK_16_VALS);
+ // const __m128i mask = _mm_set_epi8(SHUF_SWAP4_MASK_16_VALS);
+ // const __m128i mask = _mm_load_si128((const __m128i *)(const void *)&(k_ShufMask_Swap4[0]));
+ // const __m128i mask = _mm_load_si128((const __m128i *)(const void *)&(k_ShufMask_Swap4[0]));
+ // const __m128i mask = *(const __m128i *)(const void *)&(k_ShufMask_Swap4[0]);
+ const __m128i mask = *(const __m128i *)mask128_ptr;
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ do
+ {
+ SHUF_128(0) SHUF_128(1) items += 2;
+ SHUF_128(0) SHUF_128(1) items += 2;
+ }
+ while (items != lim);
+}
+
+#endif // USE_SWAP_SSSE3
+
+
+
+#ifdef USE_SWAP_AVX2
+
+#include <immintrin.h> // avx, avx2
+#if defined(__clang__)
+#include <avxintrin.h>
+#include <avx2intrin.h>
+#endif
+
+#define SHUF_256(i) *(items + (i)) = \
+ _mm256_shuffle_epi8(*(items + (i)), mask); // AVX2
+
+// Z7_NO_INLINE
+static
+#ifdef SWAP_ATTRIB_AVX2
+SWAP_ATTRIB_AVX2
+#endif
+Z7_ATTRIB_NO_VECTORIZE
+void
+Z7_FASTCALL
+ShufBytes_256(void *items8, const void *lim8, const void *mask128_ptr)
+{
+ __m256i *items = (__m256i *)items8;
+ const __m256i *lim = (const __m256i *)lim8;
+ /*
+ UNUSED_VAR(mask128_ptr)
+ __m256i mask =
+ for Swap4: _mm256_setr_epi8(SWAP4_SHUF_MASK_16_BYTES, SWAP4_SHUF_MASK_16_BYTES);
+ for Swap2: _mm256_setr_epi8(SWAP2_SHUF_MASK_16_BYTES, SWAP2_SHUF_MASK_16_BYTES);
+ */
+ const __m256i mask =
+ #if SWAP_MASK_INIT_SIZE > 16
+ *(const __m256i *)(const void *)mask128_ptr;
+ #else
+ /* msvc: broadcastsi128() version reserves the stack for no reason
+ msvc 19.29-: _mm256_insertf128_si256() / _mm256_set_m128i)) versions use non-avx movdqu xmm0,XMMWORD PTR [r8]
+ msvc 19.30+ (VS2022): replaces _mm256_set_m128i(m,m) to vbroadcastf128(m) as we want
+ */
+ // _mm256_broadcastsi128_si256(*mask128_ptr);
+ /*
+ #define MY_mm256_set_m128i(hi, lo) _mm256_insertf128_si256(_mm256_castsi128_si256(lo), (hi), 1)
+ MY_mm256_set_m128i
+ */
+ _mm256_set_m128i(
+ *(const __m128i *)mask128_ptr,
+ *(const __m128i *)mask128_ptr);
+ #endif
+
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ do
+ {
+ SHUF_256(0) SHUF_256(1) items += 2;
+ SHUF_256(0) SHUF_256(1) items += 2;
+ }
+ while (items != lim);
+}
+
+#endif // USE_SWAP_AVX2
+#endif // USE_SWAP_SSSE3 || USE_SWAP_AVX2
+#endif // USE_SWAP_128
+
+
+
+// compile message "NEON intrinsics not available with the soft-float ABI"
+#elif defined(MY_CPU_ARM_OR_ARM64) || \
+ (defined(__ARM_ARCH) && (__ARM_ARCH >= 7))
+// #elif defined(MY_CPU_ARM64)
+
+ #if defined(__clang__) && (__clang_major__ >= 8) \
+ || defined(__GNUC__) && (__GNUC__ >= 8)
+ #if (defined(__ARM_ARCH) && (__ARM_ARCH >= 7)) \
+ || defined(MY_CPU_ARM64)
+ #define USE_SWAP_128
+ #endif
+ #ifdef MY_CPU_ARM64
+ // #define SWAP_ATTRIB_NEON __attribute__((__target__("")))
+ #else
+ // #define SWAP_ATTRIB_NEON __attribute__((__target__("fpu=crypto-neon-fp-armv8")))
+ #endif
+ #elif defined(_MSC_VER)
+ #if (_MSC_VER >= 1910)
+ #define USE_SWAP_128
+ #endif
+ #endif
+
+ #if defined(_MSC_VER) && defined(MY_CPU_ARM64)
+ #include <arm64_neon.h>
+ #else
+ #include <arm_neon.h>
+ #endif
+
+#ifndef USE_SWAP_128
+ #define FORCE_SWAP_MODE
+#else
+
+#ifdef MY_CPU_ARM64
+ // for debug : comment it
+ #define FORCE_SWAP_MODE
+#else
+ #define k_SwapBytes_Mode_NEON 1
+#endif
+// typedef uint8x16_t v128;
+#define SWAP2_128(i) *(uint8x16_t *) (void *)(items + (i) * 8) = \
+ vrev16q_u8(*(const uint8x16_t *)(const void *)(items + (i) * 8));
+#define SWAP4_128(i) *(uint8x16_t *) (void *)(items + (i) * 4) = \
+ vrev32q_u8(*(const uint8x16_t *)(const void *)(items + (i) * 4));
+
+// Z7_NO_INLINE
+static
+#ifdef SWAP_ATTRIB_NEON
+SWAP_ATTRIB_NEON
+#endif
+Z7_ATTRIB_NO_VECTORIZE
+void
+Z7_FASTCALL
+SwapBytes2_128(CSwapUInt16 *items, const CSwapUInt16 *lim)
+{
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ do
+ {
+ SWAP2_128(0) SWAP2_128(1) items += 2 * 8;
+ SWAP2_128(0) SWAP2_128(1) items += 2 * 8;
+ }
+ while (items != lim);
+}
+
+// Z7_NO_INLINE
+static
+#ifdef SWAP_ATTRIB_NEON
+SWAP_ATTRIB_NEON
+#endif
+Z7_ATTRIB_NO_VECTORIZE
+void
+Z7_FASTCALL
+SwapBytes4_128(CSwapUInt32 *items, const CSwapUInt32 *lim)
+{
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ do
+ {
+ SWAP4_128(0) SWAP4_128(1) items += 2 * 4;
+ SWAP4_128(0) SWAP4_128(1) items += 2 * 4;
+ }
+ while (items != lim);
+}
+
+#endif // USE_SWAP_128
+
+#else // MY_CPU_ARM_OR_ARM64
+#define FORCE_SWAP_MODE
+#endif // MY_CPU_ARM_OR_ARM64
+
+
+
+
+
+
+#if defined(Z7_MSC_VER_ORIGINAL) && defined(MY_CPU_X86)
+ /* _byteswap_ushort() in MSVC x86 32-bit works via slow { mov dh, al; mov dl, ah }
+ So we use own versions of byteswap function */
+ #if (_MSC_VER < 1400 ) // old MSVC-X86 without _rotr16() support
+ #define SWAP2_16(i) { UInt32 v = items[i]; v += (v << 16); v >>= 8; items[i] = (CSwapUInt16)v; }
+ #else // is new MSVC-X86 with fast _rotr16()
+ #include <intrin.h>
+ #define SWAP2_16(i) { items[i] = _rotr16(items[i], 8); }
+ #endif
+#else // is not MSVC-X86
+ #define SWAP2_16(i) { CSwapUInt16 v = items[i]; items[i] = Z7_BSWAP16(v); }
+#endif // MSVC-X86
+
+#if defined(Z7_CPU_FAST_BSWAP_SUPPORTED)
+ #define SWAP4_32(i) { CSwapUInt32 v = items[i]; items[i] = Z7_BSWAP32(v); }
+#else
+ #define SWAP4_32(i) \
+ { UInt32 v = items[i]; \
+ v = ((v & 0xff00ff) << 8) + ((v >> 8) & 0xff00ff); \
+ v = rotlFixed(v, 16); \
+ items[i] = v; }
+#endif
+
+
+
+
+#if defined(FORCE_SWAP_MODE) && defined(USE_SWAP_128)
+ #define DEFAULT_Swap2 SwapBytes2_128
+ #if !defined(MY_CPU_X86_OR_AMD64)
+ #define DEFAULT_Swap4 SwapBytes4_128
+ #endif
+#endif
+
+#if !defined(DEFAULT_Swap2) || !defined(DEFAULT_Swap4)
+
+#define SWAP_BASE_FUNCS_PREFIXES \
+Z7_FORCE_INLINE \
+static \
+Z7_ATTRIB_NO_VECTOR \
+void Z7_FASTCALL
+
+
+#ifdef MY_CPU_64BIT
+
+#if defined(MY_CPU_ARM64) \
+ && defined(__ARM_ARCH) && (__ARM_ARCH >= 8) \
+ && ( (defined(__GNUC__) && (__GNUC__ >= 4)) \
+ || (defined(__clang__) && (__clang_major__ >= 4)))
+
+ #define SWAP2_64_VAR(v) asm ("rev16 %x0,%x0" : "+r" (v));
+ #define SWAP4_64_VAR(v) asm ("rev32 %x0,%x0" : "+r" (v));
+
+#else // is not ARM64-GNU
+
+#if !defined(MY_CPU_X86_OR_AMD64) || (k_SwapBytes_Mode_MIN == 0) || !defined(USE_SWAP_128)
+ #define SWAP2_64_VAR(v) \
+ v = ( 0x00ff00ff00ff00ff & (v >> 8)) \
+ + ((0x00ff00ff00ff00ff & v) << 8);
+ /* plus gives faster code in MSVC */
+#endif
+
+#ifdef Z7_CPU_FAST_BSWAP_SUPPORTED
+ #define SWAP4_64_VAR(v) \
+ v = Z7_BSWAP64(v); \
+ v = Z7_ROTL64(v, 32);
+#else
+ #define SWAP4_64_VAR(v) \
+ v = ( 0x000000ff000000ff & (v >> 24)) \
+ + ((0x000000ff000000ff & v) << 24 ) \
+ + ( 0x0000ff000000ff00 & (v >> 8)) \
+ + ((0x0000ff000000ff00 & v) << 8 ) \
+ ;
+#endif
+
+#endif // ARM64-GNU
+
+
+#ifdef SWAP2_64_VAR
+
+#define SWAP2_64(i) { \
+ UInt64 v = *(const UInt64 *)(const void *)(items + (i) * 4); \
+ SWAP2_64_VAR(v) \
+ *(UInt64 *)(void *)(items + (i) * 4) = v; }
+
+SWAP_BASE_FUNCS_PREFIXES
+SwapBytes2_64(CSwapUInt16 *items, const CSwapUInt16 *lim)
+{
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ do
+ {
+ SWAP2_64(0) SWAP2_64(1) items += 2 * 4;
+ SWAP2_64(0) SWAP2_64(1) items += 2 * 4;
+ }
+ while (items != lim);
+}
+
+ #define DEFAULT_Swap2 SwapBytes2_64
+ #if !defined(FORCE_SWAP_MODE)
+ #define SWAP2_DEFAULT_MODE 0
+ #endif
+#else // !defined(SWAP2_64_VAR)
+ #define DEFAULT_Swap2 SwapBytes2_128
+ #if !defined(FORCE_SWAP_MODE)
+ #define SWAP2_DEFAULT_MODE 1
+ #endif
+#endif // SWAP2_64_VAR
+
+
+#define SWAP4_64(i) { \
+ UInt64 v = *(const UInt64 *)(const void *)(items + (i) * 2); \
+ SWAP4_64_VAR(v) \
+ *(UInt64 *)(void *)(items + (i) * 2) = v; }
+
+SWAP_BASE_FUNCS_PREFIXES
+SwapBytes4_64(CSwapUInt32 *items, const CSwapUInt32 *lim)
+{
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ do
+ {
+ SWAP4_64(0) SWAP4_64(1) items += 2 * 2;
+ SWAP4_64(0) SWAP4_64(1) items += 2 * 2;
+ }
+ while (items != lim);
+}
+
+#define DEFAULT_Swap4 SwapBytes4_64
+
+#else // is not 64BIT
+
+
+#if defined(MY_CPU_ARM_OR_ARM64) \
+ && defined(__ARM_ARCH) && (__ARM_ARCH >= 6) \
+ && ( (defined(__GNUC__) && (__GNUC__ >= 4)) \
+ || (defined(__clang__) && (__clang_major__ >= 4)))
+
+#ifdef MY_CPU_64BIT
+ #define SWAP2_32_VAR(v) asm ("rev16 %w0,%w0" : "+r" (v));
+#else
+ #define SWAP2_32_VAR(v) asm ("rev16 %0,%0" : "+r" (v)); // for clang/gcc
+ // asm ("rev16 %r0,%r0" : "+r" (a)); // for gcc
+#endif
+
+#elif defined(_MSC_VER) && (_MSC_VER < 1300) && defined(MY_CPU_X86) \
+ || !defined(Z7_CPU_FAST_BSWAP_SUPPORTED) \
+ || !defined(Z7_CPU_FAST_ROTATE_SUPPORTED)
+ // old msvc doesn't support _byteswap_ulong()
+ #define SWAP2_32_VAR(v) \
+ v = ((v & 0xff00ff) << 8) + ((v >> 8) & 0xff00ff);
+
+#else // is not ARM and is not old-MSVC-X86 and fast BSWAP/ROTATE are supported
+ #define SWAP2_32_VAR(v) \
+ v = Z7_BSWAP32(v); \
+ v = rotlFixed(v, 16);
+
+#endif // GNU-ARM*
+
+#define SWAP2_32(i) { \
+ UInt32 v = *(const UInt32 *)(const void *)(items + (i) * 2); \
+ SWAP2_32_VAR(v); \
+ *(UInt32 *)(void *)(items + (i) * 2) = v; }
+
+
+SWAP_BASE_FUNCS_PREFIXES
+SwapBytes2_32(CSwapUInt16 *items, const CSwapUInt16 *lim)
+{
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ do
+ {
+ SWAP2_32(0) SWAP2_32(1) items += 2 * 2;
+ SWAP2_32(0) SWAP2_32(1) items += 2 * 2;
+ }
+ while (items != lim);
+}
+
+
+SWAP_BASE_FUNCS_PREFIXES
+SwapBytes4_32(CSwapUInt32 *items, const CSwapUInt32 *lim)
+{
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ do
+ {
+ SWAP4_32(0) SWAP4_32(1) items += 2;
+ SWAP4_32(0) SWAP4_32(1) items += 2;
+ }
+ while (items != lim);
+}
+
+#define DEFAULT_Swap2 SwapBytes2_32
+#define DEFAULT_Swap4 SwapBytes4_32
+#if !defined(FORCE_SWAP_MODE)
+ #define SWAP2_DEFAULT_MODE 0
+#endif
+
+#endif // MY_CPU_64BIT
+#endif // if !defined(DEFAULT_Swap2) || !defined(DEFAULT_Swap4)
+
+
+
+#if !defined(FORCE_SWAP_MODE)
+static unsigned g_SwapBytes_Mode;
+#endif
+
+/* size of largest unrolled loop iteration: 128 bytes = 4 * 32 bytes (AVX). */
+#define SWAP_ITERATION_BLOCK_SIZE_MAX (1 << 7)
+
+// 32 bytes for (AVX) or 2 * 16-bytes for NEON.
+#define SWAP_VECTOR_ALIGN_SIZE (1 << 5)
+
+Z7_NO_INLINE
+void z7_SwapBytes2(CSwapUInt16 *items, size_t numItems)
+{
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ for (; numItems != 0 && ((unsigned)(ptrdiff_t)items & (SWAP_VECTOR_ALIGN_SIZE - 1)) != 0; numItems--)
+ {
+ SWAP2_16(0)
+ items++;
+ }
+ {
+ const size_t k_Align_Mask = SWAP_ITERATION_BLOCK_SIZE_MAX / sizeof(CSwapUInt16) - 1;
+ size_t numItems2 = numItems;
+ CSwapUInt16 *lim;
+ numItems &= k_Align_Mask;
+ numItems2 &= ~(size_t)k_Align_Mask;
+ lim = items + numItems2;
+ if (numItems2 != 0)
+ {
+ #if !defined(FORCE_SWAP_MODE)
+ #ifdef MY_CPU_X86_OR_AMD64
+ #ifdef USE_SWAP_AVX2
+ if (g_SwapBytes_Mode > k_SwapBytes_Mode_SSSE3)
+ ShufBytes_256((__m256i *)(void *)items,
+ (const __m256i *)(const void *)lim,
+ (const __m128i *)(const void *)&(k_ShufMask_Swap2[0]));
+ else
+ #endif
+ #ifdef USE_SWAP_SSSE3
+ if (g_SwapBytes_Mode >= k_SwapBytes_Mode_SSSE3)
+ ShufBytes_128((__m128i *)(void *)items,
+ (const __m128i *)(const void *)lim,
+ (const __m128i *)(const void *)&(k_ShufMask_Swap2[0]));
+ else
+ #endif
+ #endif // MY_CPU_X86_OR_AMD64
+ #if SWAP2_DEFAULT_MODE == 0
+ if (g_SwapBytes_Mode != 0)
+ SwapBytes2_128(items, lim);
+ else
+ #endif
+ #endif // FORCE_SWAP_MODE
+ DEFAULT_Swap2(items, lim);
+ }
+ items = lim;
+ }
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ for (; numItems != 0; numItems--)
+ {
+ SWAP2_16(0)
+ items++;
+ }
+}
+
+
+Z7_NO_INLINE
+void z7_SwapBytes4(CSwapUInt32 *items, size_t numItems)
+{
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ for (; numItems != 0 && ((unsigned)(ptrdiff_t)items & (SWAP_VECTOR_ALIGN_SIZE - 1)) != 0; numItems--)
+ {
+ SWAP4_32(0)
+ items++;
+ }
+ {
+ const size_t k_Align_Mask = SWAP_ITERATION_BLOCK_SIZE_MAX / sizeof(CSwapUInt32) - 1;
+ size_t numItems2 = numItems;
+ CSwapUInt32 *lim;
+ numItems &= k_Align_Mask;
+ numItems2 &= ~(size_t)k_Align_Mask;
+ lim = items + numItems2;
+ if (numItems2 != 0)
+ {
+ #if !defined(FORCE_SWAP_MODE)
+ #ifdef MY_CPU_X86_OR_AMD64
+ #ifdef USE_SWAP_AVX2
+ if (g_SwapBytes_Mode > k_SwapBytes_Mode_SSSE3)
+ ShufBytes_256((__m256i *)(void *)items,
+ (const __m256i *)(const void *)lim,
+ (const __m128i *)(const void *)&(k_ShufMask_Swap4[0]));
+ else
+ #endif
+ #ifdef USE_SWAP_SSSE3
+ if (g_SwapBytes_Mode >= k_SwapBytes_Mode_SSSE3)
+ ShufBytes_128((__m128i *)(void *)items,
+ (const __m128i *)(const void *)lim,
+ (const __m128i *)(const void *)&(k_ShufMask_Swap4[0]));
+ else
+ #endif
+ #else // MY_CPU_X86_OR_AMD64
+
+ if (g_SwapBytes_Mode != 0)
+ SwapBytes4_128(items, lim);
+ else
+ #endif // MY_CPU_X86_OR_AMD64
+ #endif // FORCE_SWAP_MODE
+ DEFAULT_Swap4(items, lim);
+ }
+ items = lim;
+ }
+ Z7_PRAGMA_OPT_DISABLE_LOOP_UNROLL_VECTORIZE
+ for (; numItems != 0; numItems--)
+ {
+ SWAP4_32(0)
+ items++;
+ }
+}
+
+
+// #define SHOW_HW_STATUS
+
+#ifdef SHOW_HW_STATUS
+#include <stdio.h>
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+void z7_SwapBytesPrepare(void)
+{
+#ifndef FORCE_SWAP_MODE
+ unsigned mode = 0; // k_SwapBytes_Mode_BASE;
+
+#ifdef MY_CPU_ARM_OR_ARM64
+ {
+ if (CPU_IsSupported_NEON())
+ {
+ // #pragma message ("=== SwapBytes NEON")
+ PRF(printf("\n=== SwapBytes NEON\n");)
+ mode = k_SwapBytes_Mode_NEON;
+ }
+ }
+#else // MY_CPU_ARM_OR_ARM64
+ {
+ #ifdef USE_SWAP_AVX2
+ if (CPU_IsSupported_AVX2())
+ {
+ // #pragma message ("=== SwapBytes AVX2")
+ PRF(printf("\n=== SwapBytes AVX2\n");)
+ mode = k_SwapBytes_Mode_AVX2;
+ }
+ else
+ #endif
+ #ifdef USE_SWAP_SSSE3
+ if (CPU_IsSupported_SSSE3())
+ {
+ // #pragma message ("=== SwapBytes SSSE3")
+ PRF(printf("\n=== SwapBytes SSSE3\n");)
+ mode = k_SwapBytes_Mode_SSSE3;
+ }
+ else
+ #endif
+ #if !defined(MY_CPU_AMD64)
+ if (CPU_IsSupported_SSE2())
+ #endif
+ {
+ // #pragma message ("=== SwapBytes SSE2")
+ PRF(printf("\n=== SwapBytes SSE2\n");)
+ mode = k_SwapBytes_Mode_SSE2;
+ }
+ }
+#endif // MY_CPU_ARM_OR_ARM64
+ g_SwapBytes_Mode = mode;
+ // g_SwapBytes_Mode = 0; // for debug
+#endif // FORCE_SWAP_MODE
+ PRF(printf("\n=== SwapBytesPrepare\n");)
+}
+
+#undef PRF
diff --git a/C/SwapBytes.h b/C/SwapBytes.h
new file mode 100644
index 0000000..d442467
--- /dev/null
+++ b/C/SwapBytes.h
@@ -0,0 +1,17 @@
+/* SwapBytes.h -- Byte Swap conversion filter
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_SWAP_BYTES_H
+#define ZIP7_INC_SWAP_BYTES_H
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+void z7_SwapBytes2(UInt16 *data, size_t numItems);
+void z7_SwapBytes4(UInt32 *data, size_t numItems);
+void z7_SwapBytesPrepare(void);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Threads.c b/C/Threads.c
index 8fd86f2..cf52bd3 100644
--- a/C/Threads.c
+++ b/C/Threads.c
@@ -1,95 +1,562 @@
-/* Threads.c -- multithreading library
-2017-06-26 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#ifndef UNDER_CE
-#include <process.h>
-#endif
-
-#include "Threads.h"
-
-static WRes GetError()
-{
- DWORD res = GetLastError();
- return res ? (WRes)res : 1;
-}
-
-static WRes HandleToWRes(HANDLE h) { return (h != NULL) ? 0 : GetError(); }
-static WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); }
-
-WRes HandlePtr_Close(HANDLE *p)
-{
- if (*p != NULL)
- {
- if (!CloseHandle(*p))
- return GetError();
- *p = NULL;
- }
- return 0;
-}
-
-WRes Handle_WaitObject(HANDLE h) { return (WRes)WaitForSingleObject(h, INFINITE); }
-
-WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
-{
- /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
-
- #ifdef UNDER_CE
-
- DWORD threadId;
- *p = CreateThread(0, 0, func, param, 0, &threadId);
-
- #else
-
- unsigned threadId;
- *p = (HANDLE)_beginthreadex(NULL, 0, func, param, 0, &threadId);
-
- #endif
-
- /* maybe we must use errno here, but probably GetLastError() is also OK. */
- return HandleToWRes(*p);
-}
-
-static WRes Event_Create(CEvent *p, BOOL manualReset, int signaled)
-{
- *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL);
- return HandleToWRes(*p);
-}
-
-WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); }
-WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); }
-
-WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); }
-WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); }
-WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); }
-WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); }
-
-
-WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
-{
- *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL);
- return HandleToWRes(*p);
-}
-
-static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount)
- { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); }
-WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num)
- { return Semaphore_Release(p, (LONG)num, NULL); }
-WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); }
-
-WRes CriticalSection_Init(CCriticalSection *p)
-{
- /* InitializeCriticalSection can raise only STATUS_NO_MEMORY exception */
- #ifdef _MSC_VER
- __try
- #endif
- {
- InitializeCriticalSection(p);
- /* InitializeCriticalSectionAndSpinCount(p, 0); */
- }
- #ifdef _MSC_VER
- __except (EXCEPTION_EXECUTE_HANDLER) { return 1; }
- #endif
- return 0;
-}
+/* Threads.c -- multithreading library
+2023-03-04 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#ifdef _WIN32
+
+#ifndef USE_THREADS_CreateThread
+#include <process.h>
+#endif
+
+#include "Threads.h"
+
+static WRes GetError(void)
+{
+ const DWORD res = GetLastError();
+ return res ? (WRes)res : 1;
+}
+
+static WRes HandleToWRes(HANDLE h) { return (h != NULL) ? 0 : GetError(); }
+static WRes BOOLToWRes(BOOL v) { return v ? 0 : GetError(); }
+
+WRes HandlePtr_Close(HANDLE *p)
+{
+ if (*p != NULL)
+ {
+ if (!CloseHandle(*p))
+ return GetError();
+ *p = NULL;
+ }
+ return 0;
+}
+
+WRes Handle_WaitObject(HANDLE h)
+{
+ DWORD dw = WaitForSingleObject(h, INFINITE);
+ /*
+ (dw) result:
+ WAIT_OBJECT_0 // 0
+ WAIT_ABANDONED // 0x00000080 : is not compatible with Win32 Error space
+ WAIT_TIMEOUT // 0x00000102 : is compatible with Win32 Error space
+ WAIT_FAILED // 0xFFFFFFFF
+ */
+ if (dw == WAIT_FAILED)
+ {
+ dw = GetLastError();
+ if (dw == 0)
+ return WAIT_FAILED;
+ }
+ return (WRes)dw;
+}
+
+#define Thread_Wait(p) Handle_WaitObject(*(p))
+
+WRes Thread_Wait_Close(CThread *p)
+{
+ WRes res = Thread_Wait(p);
+ WRes res2 = Thread_Close(p);
+ return (res != 0 ? res : res2);
+}
+
+WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
+{
+ /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
+
+ #ifdef USE_THREADS_CreateThread
+
+ DWORD threadId;
+ *p = CreateThread(NULL, 0, func, param, 0, &threadId);
+
+ #else
+
+ unsigned threadId;
+ *p = (HANDLE)(_beginthreadex(NULL, 0, func, param, 0, &threadId));
+
+ #endif
+
+ /* maybe we must use errno here, but probably GetLastError() is also OK. */
+ return HandleToWRes(*p);
+}
+
+
+WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity)
+{
+ #ifdef USE_THREADS_CreateThread
+
+ UNUSED_VAR(affinity)
+ return Thread_Create(p, func, param);
+
+ #else
+
+ /* Windows Me/98/95: threadId parameter may not be NULL in _beginthreadex/CreateThread functions */
+ HANDLE h;
+ WRes wres;
+ unsigned threadId;
+ h = (HANDLE)(_beginthreadex(NULL, 0, func, param, CREATE_SUSPENDED, &threadId));
+ *p = h;
+ wres = HandleToWRes(h);
+ if (h)
+ {
+ {
+ // DWORD_PTR prevMask =
+ SetThreadAffinityMask(h, (DWORD_PTR)affinity);
+ /*
+ if (prevMask == 0)
+ {
+ // affinity change is non-critical error, so we can ignore it
+ // wres = GetError();
+ }
+ */
+ }
+ {
+ DWORD prevSuspendCount = ResumeThread(h);
+ /* ResumeThread() returns:
+ 0 : was_not_suspended
+ 1 : was_resumed
+ -1 : error
+ */
+ if (prevSuspendCount == (DWORD)-1)
+ wres = GetError();
+ }
+ }
+
+ /* maybe we must use errno here, but probably GetLastError() is also OK. */
+ return wres;
+
+ #endif
+}
+
+
+static WRes Event_Create(CEvent *p, BOOL manualReset, int signaled)
+{
+ *p = CreateEvent(NULL, manualReset, (signaled ? TRUE : FALSE), NULL);
+ return HandleToWRes(*p);
+}
+
+WRes Event_Set(CEvent *p) { return BOOLToWRes(SetEvent(*p)); }
+WRes Event_Reset(CEvent *p) { return BOOLToWRes(ResetEvent(*p)); }
+
+WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled) { return Event_Create(p, TRUE, signaled); }
+WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled) { return Event_Create(p, FALSE, signaled); }
+WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p) { return ManualResetEvent_Create(p, 0); }
+WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p) { return AutoResetEvent_Create(p, 0); }
+
+
+WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
+{
+ // negative ((LONG)maxCount) is not supported in WIN32::CreateSemaphore()
+ *p = CreateSemaphore(NULL, (LONG)initCount, (LONG)maxCount, NULL);
+ return HandleToWRes(*p);
+}
+
+WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
+{
+ // if (Semaphore_IsCreated(p))
+ {
+ WRes wres = Semaphore_Close(p);
+ if (wres != 0)
+ return wres;
+ }
+ return Semaphore_Create(p, initCount, maxCount);
+}
+
+static WRes Semaphore_Release(CSemaphore *p, LONG releaseCount, LONG *previousCount)
+ { return BOOLToWRes(ReleaseSemaphore(*p, releaseCount, previousCount)); }
+WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num)
+ { return Semaphore_Release(p, (LONG)num, NULL); }
+WRes Semaphore_Release1(CSemaphore *p) { return Semaphore_ReleaseN(p, 1); }
+
+WRes CriticalSection_Init(CCriticalSection *p)
+{
+ /* InitializeCriticalSection() can raise exception:
+ Windows XP, 2003 : can raise a STATUS_NO_MEMORY exception
+ Windows Vista+ : no exceptions */
+ #ifdef _MSC_VER
+ #ifdef __clang__
+ #pragma GCC diagnostic ignored "-Wlanguage-extension-token"
+ #endif
+ __try
+ #endif
+ {
+ InitializeCriticalSection(p);
+ /* InitializeCriticalSectionAndSpinCount(p, 0); */
+ }
+ #ifdef _MSC_VER
+ __except (EXCEPTION_EXECUTE_HANDLER) { return ERROR_NOT_ENOUGH_MEMORY; }
+ #endif
+ return 0;
+}
+
+
+
+
+#else // _WIN32
+
+// ---------- POSIX ----------
+
+#ifndef __APPLE__
+#ifndef Z7_AFFINITY_DISABLE
+// _GNU_SOURCE can be required for pthread_setaffinity_np() / CPU_ZERO / CPU_SET
+// clang < 3.6 : unknown warning group '-Wreserved-id-macro'
+// clang 3.6 - 12.01 : gives warning "macro name is a reserved identifier"
+// clang >= 13 : do not give warning
+#if !defined(_GNU_SOURCE)
+ #if defined(__clang__) && (__clang_major__ >= 4) && (__clang_major__ <= 12)
+ #pragma GCC diagnostic ignored "-Wreserved-id-macro"
+ #endif
+#define _GNU_SOURCE
+#endif // !defined(_GNU_SOURCE)
+#endif // Z7_AFFINITY_DISABLE
+#endif // __APPLE__
+
+#include "Threads.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef Z7_AFFINITY_SUPPORTED
+// #include <sched.h>
+#endif
+
+
+// #include <stdio.h>
+// #define PRF(p) p
+#define PRF(p)
+#define Print(s) PRF(printf("\n%s\n", s);)
+
+WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet)
+{
+ // new thread in Posix probably inherits affinity from parrent thread
+ Print("Thread_Create_With_CpuSet")
+
+ pthread_attr_t attr;
+ int ret;
+ // int ret2;
+
+ p->_created = 0;
+
+ RINOK(pthread_attr_init(&attr))
+
+ ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+
+ if (!ret)
+ {
+ if (cpuSet)
+ {
+ #ifdef Z7_AFFINITY_SUPPORTED
+
+ /*
+ printf("\n affinity :");
+ unsigned i;
+ for (i = 0; i < sizeof(*cpuSet) && i < 8; i++)
+ {
+ Byte b = *((const Byte *)cpuSet + i);
+ char temp[32];
+ #define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))))
+ temp[0] = GET_HEX_CHAR((b & 0xF));
+ temp[1] = GET_HEX_CHAR((b >> 4));
+ // temp[0] = GET_HEX_CHAR((b >> 4)); // big-endian
+ // temp[1] = GET_HEX_CHAR((b & 0xF)); // big-endian
+ temp[2] = 0;
+ printf("%s", temp);
+ }
+ printf("\n");
+ */
+
+ // ret2 =
+ pthread_attr_setaffinity_np(&attr, sizeof(*cpuSet), cpuSet);
+ // if (ret2) ret = ret2;
+ #endif
+ }
+
+ ret = pthread_create(&p->_tid, &attr, func, param);
+
+ if (!ret)
+ {
+ p->_created = 1;
+ /*
+ if (cpuSet)
+ {
+ // ret2 =
+ pthread_setaffinity_np(p->_tid, sizeof(*cpuSet), cpuSet);
+ // if (ret2) ret = ret2;
+ }
+ */
+ }
+ }
+ // ret2 =
+ pthread_attr_destroy(&attr);
+ // if (ret2 != 0) ret = ret2;
+ return ret;
+}
+
+
+WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param)
+{
+ return Thread_Create_With_CpuSet(p, func, param, NULL);
+}
+
+
+WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity)
+{
+ Print("Thread_Create_WithAffinity")
+ CCpuSet cs;
+ unsigned i;
+ CpuSet_Zero(&cs);
+ for (i = 0; i < sizeof(affinity) * 8; i++)
+ {
+ if (affinity == 0)
+ break;
+ if (affinity & 1)
+ {
+ CpuSet_Set(&cs, i);
+ }
+ affinity >>= 1;
+ }
+ return Thread_Create_With_CpuSet(p, func, param, &cs);
+}
+
+
+WRes Thread_Close(CThread *p)
+{
+ // Print("Thread_Close")
+ int ret;
+ if (!p->_created)
+ return 0;
+
+ ret = pthread_detach(p->_tid);
+ p->_tid = 0;
+ p->_created = 0;
+ return ret;
+}
+
+
+WRes Thread_Wait_Close(CThread *p)
+{
+ // Print("Thread_Wait_Close")
+ void *thread_return;
+ int ret;
+ if (!p->_created)
+ return EINVAL;
+
+ ret = pthread_join(p->_tid, &thread_return);
+ // probably we can't use that (_tid) after pthread_join(), so we close thread here
+ p->_created = 0;
+ p->_tid = 0;
+ return ret;
+}
+
+
+
+static WRes Event_Create(CEvent *p, int manualReset, int signaled)
+{
+ RINOK(pthread_mutex_init(&p->_mutex, NULL))
+ RINOK(pthread_cond_init(&p->_cond, NULL))
+ p->_manual_reset = manualReset;
+ p->_state = (signaled ? True : False);
+ p->_created = 1;
+ return 0;
+}
+
+WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled)
+ { return Event_Create(p, True, signaled); }
+WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p)
+ { return ManualResetEvent_Create(p, 0); }
+WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled)
+ { return Event_Create(p, False, signaled); }
+WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p)
+ { return AutoResetEvent_Create(p, 0); }
+
+
+WRes Event_Set(CEvent *p)
+{
+ RINOK(pthread_mutex_lock(&p->_mutex))
+ p->_state = True;
+ int res1 = pthread_cond_broadcast(&p->_cond);
+ int res2 = pthread_mutex_unlock(&p->_mutex);
+ return (res2 ? res2 : res1);
+}
+
+WRes Event_Reset(CEvent *p)
+{
+ RINOK(pthread_mutex_lock(&p->_mutex))
+ p->_state = False;
+ return pthread_mutex_unlock(&p->_mutex);
+}
+
+WRes Event_Wait(CEvent *p)
+{
+ RINOK(pthread_mutex_lock(&p->_mutex))
+ while (p->_state == False)
+ {
+ // ETIMEDOUT
+ // ret =
+ pthread_cond_wait(&p->_cond, &p->_mutex);
+ // if (ret != 0) break;
+ }
+ if (p->_manual_reset == False)
+ {
+ p->_state = False;
+ }
+ return pthread_mutex_unlock(&p->_mutex);
+}
+
+WRes Event_Close(CEvent *p)
+{
+ if (!p->_created)
+ return 0;
+ p->_created = 0;
+ {
+ int res1 = pthread_mutex_destroy(&p->_mutex);
+ int res2 = pthread_cond_destroy(&p->_cond);
+ return (res1 ? res1 : res2);
+ }
+}
+
+
+WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
+{
+ if (initCount > maxCount || maxCount < 1)
+ return EINVAL;
+ RINOK(pthread_mutex_init(&p->_mutex, NULL))
+ RINOK(pthread_cond_init(&p->_cond, NULL))
+ p->_count = initCount;
+ p->_maxCount = maxCount;
+ p->_created = 1;
+ return 0;
+}
+
+
+WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount)
+{
+ if (Semaphore_IsCreated(p))
+ {
+ /*
+ WRes wres = Semaphore_Close(p);
+ if (wres != 0)
+ return wres;
+ */
+ if (initCount > maxCount || maxCount < 1)
+ return EINVAL;
+ // return EINVAL; // for debug
+ p->_count = initCount;
+ p->_maxCount = maxCount;
+ return 0;
+ }
+ return Semaphore_Create(p, initCount, maxCount);
+}
+
+
+WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 releaseCount)
+{
+ UInt32 newCount;
+ int ret;
+
+ if (releaseCount < 1)
+ return EINVAL;
+
+ RINOK(pthread_mutex_lock(&p->_mutex))
+
+ newCount = p->_count + releaseCount;
+ if (newCount > p->_maxCount)
+ ret = ERROR_TOO_MANY_POSTS; // EINVAL;
+ else
+ {
+ p->_count = newCount;
+ ret = pthread_cond_broadcast(&p->_cond);
+ }
+ RINOK(pthread_mutex_unlock(&p->_mutex))
+ return ret;
+}
+
+WRes Semaphore_Wait(CSemaphore *p)
+{
+ RINOK(pthread_mutex_lock(&p->_mutex))
+ while (p->_count < 1)
+ {
+ pthread_cond_wait(&p->_cond, &p->_mutex);
+ }
+ p->_count--;
+ return pthread_mutex_unlock(&p->_mutex);
+}
+
+WRes Semaphore_Close(CSemaphore *p)
+{
+ if (!p->_created)
+ return 0;
+ p->_created = 0;
+ {
+ int res1 = pthread_mutex_destroy(&p->_mutex);
+ int res2 = pthread_cond_destroy(&p->_cond);
+ return (res1 ? res1 : res2);
+ }
+}
+
+
+
+WRes CriticalSection_Init(CCriticalSection *p)
+{
+ // Print("CriticalSection_Init")
+ if (!p)
+ return EINTR;
+ return pthread_mutex_init(&p->_mutex, NULL);
+}
+
+void CriticalSection_Enter(CCriticalSection *p)
+{
+ // Print("CriticalSection_Enter")
+ if (p)
+ {
+ // int ret =
+ pthread_mutex_lock(&p->_mutex);
+ }
+}
+
+void CriticalSection_Leave(CCriticalSection *p)
+{
+ // Print("CriticalSection_Leave")
+ if (p)
+ {
+ // int ret =
+ pthread_mutex_unlock(&p->_mutex);
+ }
+}
+
+void CriticalSection_Delete(CCriticalSection *p)
+{
+ // Print("CriticalSection_Delete")
+ if (p)
+ {
+ // int ret =
+ pthread_mutex_destroy(&p->_mutex);
+ }
+}
+
+LONG InterlockedIncrement(LONG volatile *addend)
+{
+ // Print("InterlockedIncrement")
+ #ifdef USE_HACK_UNSAFE_ATOMIC
+ LONG val = *addend + 1;
+ *addend = val;
+ return val;
+ #else
+
+ #if defined(__clang__) && (__clang_major__ >= 8)
+ #pragma GCC diagnostic ignored "-Watomic-implicit-seq-cst"
+ #endif
+ return __sync_add_and_fetch(addend, 1);
+ #endif
+}
+
+#endif // _WIN32
+
+WRes AutoResetEvent_OptCreate_And_Reset(CAutoResetEvent *p)
+{
+ if (Event_IsCreated(p))
+ return Event_Reset(p);
+ return AutoResetEvent_CreateNotSignaled(p);
+}
+
+#undef PRF
+#undef Print
diff --git a/C/Threads.h b/C/Threads.h
index f913241..4028464 100644
--- a/C/Threads.h
+++ b/C/Threads.h
@@ -1,68 +1,240 @@
-/* Threads.h -- multithreading library
-2017-06-18 : Igor Pavlov : Public domain */
-
-#ifndef __7Z_THREADS_H
-#define __7Z_THREADS_H
-
-#ifdef _WIN32
-#include <windows.h>
-#endif
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-WRes HandlePtr_Close(HANDLE *h);
-WRes Handle_WaitObject(HANDLE h);
-
-typedef HANDLE CThread;
-#define Thread_Construct(p) *(p) = NULL
-#define Thread_WasCreated(p) (*(p) != NULL)
-#define Thread_Close(p) HandlePtr_Close(p)
-#define Thread_Wait(p) Handle_WaitObject(*(p))
-
-typedef
-#ifdef UNDER_CE
- DWORD
-#else
- unsigned
-#endif
- THREAD_FUNC_RET_TYPE;
-
-#define THREAD_FUNC_CALL_TYPE MY_STD_CALL
-#define THREAD_FUNC_DECL THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE
-typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *);
-WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param);
-
-typedef HANDLE CEvent;
-typedef CEvent CAutoResetEvent;
-typedef CEvent CManualResetEvent;
-#define Event_Construct(p) *(p) = NULL
-#define Event_IsCreated(p) (*(p) != NULL)
-#define Event_Close(p) HandlePtr_Close(p)
-#define Event_Wait(p) Handle_WaitObject(*(p))
-WRes Event_Set(CEvent *p);
-WRes Event_Reset(CEvent *p);
-WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled);
-WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p);
-WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled);
-WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p);
-
-typedef HANDLE CSemaphore;
-#define Semaphore_Construct(p) *(p) = NULL
-#define Semaphore_IsCreated(p) (*(p) != NULL)
-#define Semaphore_Close(p) HandlePtr_Close(p)
-#define Semaphore_Wait(p) Handle_WaitObject(*(p))
-WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
-WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num);
-WRes Semaphore_Release1(CSemaphore *p);
-
-typedef CRITICAL_SECTION CCriticalSection;
-WRes CriticalSection_Init(CCriticalSection *p);
-#define CriticalSection_Delete(p) DeleteCriticalSection(p)
-#define CriticalSection_Enter(p) EnterCriticalSection(p)
-#define CriticalSection_Leave(p) LeaveCriticalSection(p)
-
-EXTERN_C_END
-
-#endif
+/* Threads.h -- multithreading library
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_THREADS_H
+#define ZIP7_INC_THREADS_H
+
+#ifdef _WIN32
+#include "7zWindows.h"
+
+#else
+
+#if defined(__linux__)
+#if !defined(__APPLE__) && !defined(_AIX) && !defined(__ANDROID__)
+#ifndef Z7_AFFINITY_DISABLE
+#define Z7_AFFINITY_SUPPORTED
+// #pragma message(" ==== Z7_AFFINITY_SUPPORTED")
+// #define _GNU_SOURCE
+#endif
+#endif
+#endif
+
+#include <pthread.h>
+
+#endif
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+#ifdef _WIN32
+
+WRes HandlePtr_Close(HANDLE *h);
+WRes Handle_WaitObject(HANDLE h);
+
+typedef HANDLE CThread;
+
+#define Thread_CONSTRUCT(p) { *(p) = NULL; }
+#define Thread_WasCreated(p) (*(p) != NULL)
+#define Thread_Close(p) HandlePtr_Close(p)
+// #define Thread_Wait(p) Handle_WaitObject(*(p))
+
+#ifdef UNDER_CE
+ // if (USE_THREADS_CreateThread is defined), we use _beginthreadex()
+ // if (USE_THREADS_CreateThread is not definned), we use CreateThread()
+ #define USE_THREADS_CreateThread
+#endif
+
+typedef
+ #ifdef USE_THREADS_CreateThread
+ DWORD
+ #else
+ unsigned
+ #endif
+ THREAD_FUNC_RET_TYPE;
+
+#define THREAD_FUNC_RET_ZERO 0
+
+typedef DWORD_PTR CAffinityMask;
+typedef DWORD_PTR CCpuSet;
+
+#define CpuSet_Zero(p) *(p) = (0)
+#define CpuSet_Set(p, cpu) *(p) |= ((DWORD_PTR)1 << (cpu))
+
+#else // _WIN32
+
+typedef struct
+{
+ pthread_t _tid;
+ int _created;
+} CThread;
+
+#define Thread_CONSTRUCT(p) { (p)->_tid = 0; (p)->_created = 0; }
+#define Thread_WasCreated(p) ((p)->_created != 0)
+WRes Thread_Close(CThread *p);
+// #define Thread_Wait Thread_Wait_Close
+
+typedef void * THREAD_FUNC_RET_TYPE;
+#define THREAD_FUNC_RET_ZERO NULL
+
+
+typedef UInt64 CAffinityMask;
+
+#ifdef Z7_AFFINITY_SUPPORTED
+
+typedef cpu_set_t CCpuSet;
+#define CpuSet_Zero(p) CPU_ZERO(p)
+#define CpuSet_Set(p, cpu) CPU_SET(cpu, p)
+#define CpuSet_IsSet(p, cpu) CPU_ISSET(cpu, p)
+
+#else
+
+typedef UInt64 CCpuSet;
+#define CpuSet_Zero(p) *(p) = (0)
+#define CpuSet_Set(p, cpu) *(p) |= ((UInt64)1 << (cpu))
+#define CpuSet_IsSet(p, cpu) ((*(p) & ((UInt64)1 << (cpu))) != 0)
+
+#endif
+
+
+#endif // _WIN32
+
+
+#define THREAD_FUNC_CALL_TYPE Z7_STDCALL
+
+#if defined(_WIN32) && defined(__GNUC__)
+/* GCC compiler for x86 32-bit uses the rule:
+ the stack is 16-byte aligned before CALL instruction for function calling.
+ But only root function main() contains instructions that
+ set 16-byte alignment for stack pointer. And another functions
+ just keep alignment, if it was set in some parent function.
+
+ The problem:
+ if we create new thread in MinGW (GCC) 32-bit x86 via _beginthreadex() or CreateThread(),
+ the root function of thread doesn't set 16-byte alignment.
+ And stack frames in all child functions also will be unaligned in that case.
+
+ Here we set (force_align_arg_pointer) attribute for root function of new thread.
+ Do we need (force_align_arg_pointer) also for another systems? */
+
+ #define THREAD_FUNC_ATTRIB_ALIGN_ARG __attribute__((force_align_arg_pointer))
+ // #define THREAD_FUNC_ATTRIB_ALIGN_ARG // for debug : bad alignment in SSE functions
+#else
+ #define THREAD_FUNC_ATTRIB_ALIGN_ARG
+#endif
+
+#define THREAD_FUNC_DECL THREAD_FUNC_ATTRIB_ALIGN_ARG THREAD_FUNC_RET_TYPE THREAD_FUNC_CALL_TYPE
+
+typedef THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE * THREAD_FUNC_TYPE)(void *);
+WRes Thread_Create(CThread *p, THREAD_FUNC_TYPE func, LPVOID param);
+WRes Thread_Create_With_Affinity(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, CAffinityMask affinity);
+WRes Thread_Wait_Close(CThread *p);
+
+#ifdef _WIN32
+#define Thread_Create_With_CpuSet(p, func, param, cs) \
+ Thread_Create_With_Affinity(p, func, param, *cs)
+#else
+WRes Thread_Create_With_CpuSet(CThread *p, THREAD_FUNC_TYPE func, LPVOID param, const CCpuSet *cpuSet);
+#endif
+
+
+#ifdef _WIN32
+
+typedef HANDLE CEvent;
+typedef CEvent CAutoResetEvent;
+typedef CEvent CManualResetEvent;
+#define Event_Construct(p) *(p) = NULL
+#define Event_IsCreated(p) (*(p) != NULL)
+#define Event_Close(p) HandlePtr_Close(p)
+#define Event_Wait(p) Handle_WaitObject(*(p))
+WRes Event_Set(CEvent *p);
+WRes Event_Reset(CEvent *p);
+WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled);
+WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p);
+WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled);
+WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p);
+
+typedef HANDLE CSemaphore;
+#define Semaphore_Construct(p) *(p) = NULL
+#define Semaphore_IsCreated(p) (*(p) != NULL)
+#define Semaphore_Close(p) HandlePtr_Close(p)
+#define Semaphore_Wait(p) Handle_WaitObject(*(p))
+WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
+WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
+WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num);
+WRes Semaphore_Release1(CSemaphore *p);
+
+typedef CRITICAL_SECTION CCriticalSection;
+WRes CriticalSection_Init(CCriticalSection *p);
+#define CriticalSection_Delete(p) DeleteCriticalSection(p)
+#define CriticalSection_Enter(p) EnterCriticalSection(p)
+#define CriticalSection_Leave(p) LeaveCriticalSection(p)
+
+
+#else // _WIN32
+
+typedef struct _CEvent
+{
+ int _created;
+ int _manual_reset;
+ int _state;
+ pthread_mutex_t _mutex;
+ pthread_cond_t _cond;
+} CEvent;
+
+typedef CEvent CAutoResetEvent;
+typedef CEvent CManualResetEvent;
+
+#define Event_Construct(p) (p)->_created = 0
+#define Event_IsCreated(p) ((p)->_created)
+
+WRes ManualResetEvent_Create(CManualResetEvent *p, int signaled);
+WRes ManualResetEvent_CreateNotSignaled(CManualResetEvent *p);
+WRes AutoResetEvent_Create(CAutoResetEvent *p, int signaled);
+WRes AutoResetEvent_CreateNotSignaled(CAutoResetEvent *p);
+
+WRes Event_Set(CEvent *p);
+WRes Event_Reset(CEvent *p);
+WRes Event_Wait(CEvent *p);
+WRes Event_Close(CEvent *p);
+
+
+typedef struct _CSemaphore
+{
+ int _created;
+ UInt32 _count;
+ UInt32 _maxCount;
+ pthread_mutex_t _mutex;
+ pthread_cond_t _cond;
+} CSemaphore;
+
+#define Semaphore_Construct(p) (p)->_created = 0
+#define Semaphore_IsCreated(p) ((p)->_created)
+
+WRes Semaphore_Create(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
+WRes Semaphore_OptCreateInit(CSemaphore *p, UInt32 initCount, UInt32 maxCount);
+WRes Semaphore_ReleaseN(CSemaphore *p, UInt32 num);
+#define Semaphore_Release1(p) Semaphore_ReleaseN(p, 1)
+WRes Semaphore_Wait(CSemaphore *p);
+WRes Semaphore_Close(CSemaphore *p);
+
+
+typedef struct _CCriticalSection
+{
+ pthread_mutex_t _mutex;
+} CCriticalSection;
+
+WRes CriticalSection_Init(CCriticalSection *p);
+void CriticalSection_Delete(CCriticalSection *cs);
+void CriticalSection_Enter(CCriticalSection *cs);
+void CriticalSection_Leave(CCriticalSection *cs);
+
+LONG InterlockedIncrement(LONG volatile *addend);
+
+#endif // _WIN32
+
+WRes AutoResetEvent_OptCreate_And_Reset(CAutoResetEvent *p);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/Util/7z/7z.dsp b/C/Util/7z/7z.dsp
index d3bf0fe..11e1b03 100644
--- a/C/Util/7z/7z.dsp
+++ b/C/Util/7z/7z.dsp
@@ -1,241 +1,245 @@
-# Microsoft Developer Studio Project File - Name="7z" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Console Application" 0x0103
-
-CFG=7z - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "7z.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "7z.mak" CFG="7z - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "7z - Win32 Release" (based on "Win32 (x86) Console Application")
-!MESSAGE "7z - Win32 Debug" (based on "Win32 (x86) Console Application")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "7z - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /MD /W4 /WX /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /FAcs /Yu"Precomp.h" /FD /c
-# ADD BASE RSC /l 0x419 /d "NDEBUG"
-# ADD RSC /l 0x419 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\util\7zDec.exe" /opt:NOWIN98
-# SUBTRACT LINK32 /pdb:none
-
-!ELSEIF "$(CFG)" == "7z - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
-# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_SZ_ALLOC_DEBUG2" /D "_SZ_NO_INT_64_A" /D "WIN32" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Yu"Precomp.h" /FD /GZ /c
-# ADD BASE RSC /l 0x419 /d "_DEBUG"
-# ADD RSC /l 0x419 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\util\7zDec.exe" /pdbtype:sept
-
-!ENDIF
-
-# Begin Target
-
-# Name "7z - Win32 Release"
-# Name "7z - Win32 Debug"
-# Begin Group "Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\7z.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zAlloc.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zAlloc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zArcIn.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zBuf.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zBuf.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zCrc.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zCrc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zCrcOpt.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zDec.c
-# ADD CPP /D "_7ZIP_PPMD_SUPPPORT"
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zFile.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zFile.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zStream.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zTypes.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Bcj2.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Bcj2.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Bra.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Bra.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Bra86.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\BraIA64.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\CpuArch.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\CpuArch.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Delta.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Delta.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Lzma2Dec.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Lzma2Dec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzmaDec.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzmaDec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Ppmd.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Ppmd7.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Ppmd7.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Ppmd7Dec.c
-# End Source File
-# End Group
-# Begin Group "Spec"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Compiler.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\Precomp.c
-# ADD CPP /Yc"Precomp.h"
-# End Source File
-# Begin Source File
-
-SOURCE=.\Precomp.h
-# End Source File
-# End Group
-# Begin Source File
-
-SOURCE=.\7zMain.c
-# End Source File
-# End Target
-# End Project
+# Microsoft Developer Studio Project File - Name="7z" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=7z - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "7z.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "7z.mak" CFG="7z - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "7z - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "7z - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MD /W4 /WX /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /D "Z7_PPMD_SUPPORT" /FAcs /Yu"Precomp.h" /FD /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\util\7zDec.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_SZ_ALLOC_DEBUG2" /D "_SZ_NO_INT_64_A" /D "WIN32" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /D "Z7_PPMD_SUPPORT" /Yu"Precomp.h" /FD /GZ /c
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\util\7zDec.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "7z - Win32 Release"
+# Name "7z - Win32 Debug"
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\7z.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zAlloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zAlloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zArcIn.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zBuf.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zBuf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zCrc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zCrcOpt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zDec.c
+# ADD CPP /D "_7ZIP_PPMD_SUPPPORT"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zFile.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zFile.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zStream.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Bcj2.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Bcj2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Bra.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Bra.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Bra86.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\BraIA64.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\CpuArch.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\CpuArch.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Delta.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Delta.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Lzma2Dec.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Lzma2Dec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzmaDec.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzmaDec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Ppmd.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Ppmd7.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Ppmd7.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Ppmd7Dec.c
+# End Source File
+# End Group
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Precomp.c
+# ADD CPP /Yc"Precomp.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\Precomp.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\7zMain.c
+# End Source File
+# End Target
+# End Project
diff --git a/C/Util/7z/7z.dsw b/C/Util/7z/7z.dsw
index 23089fb..848d13c 100644
--- a/C/Util/7z/7z.dsw
+++ b/C/Util/7z/7z.dsw
@@ -1,29 +1,29 @@
-Microsoft Developer Studio Workspace File, Format Version 6.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "7z"=.\7z.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
-
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "7z"=.\7z.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/C/Util/7z/7zMain.c b/C/Util/7z/7zMain.c
index 1c02b48..547920a 100644
--- a/C/Util/7z/7zMain.c
+++ b/C/Util/7z/7zMain.c
@@ -1,686 +1,888 @@
-/* 7zMain.c - Test application for 7z Decoder
-2019-02-02 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include <stdio.h>
-#include <string.h>
-
-#include "../../CpuArch.h"
-
-#include "../../7z.h"
-#include "../../7zAlloc.h"
-#include "../../7zBuf.h"
-#include "../../7zCrc.h"
-#include "../../7zFile.h"
-#include "../../7zVersion.h"
-
-#ifndef USE_WINDOWS_FILE
-/* for mkdir */
-#ifdef _WIN32
-#include <direct.h>
-#else
-#include <sys/stat.h>
-#include <errno.h>
-#endif
-#endif
-
-
-#define kInputBufSize ((size_t)1 << 18)
-
-static const ISzAlloc g_Alloc = { SzAlloc, SzFree };
-
-
-static void Print(const char *s)
-{
- fputs(s, stdout);
-}
-
-
-static int Buf_EnsureSize(CBuf *dest, size_t size)
-{
- if (dest->size >= size)
- return 1;
- Buf_Free(dest, &g_Alloc);
- return Buf_Create(dest, size, &g_Alloc);
-}
-
-#ifndef _WIN32
-#define _USE_UTF8
-#endif
-
-/* #define _USE_UTF8 */
-
-#ifdef _USE_UTF8
-
-#define _UTF8_START(n) (0x100 - (1 << (7 - (n))))
-
-#define _UTF8_RANGE(n) (((UInt32)1) << ((n) * 5 + 6))
-
-#define _UTF8_HEAD(n, val) ((Byte)(_UTF8_START(n) + (val >> (6 * (n)))))
-#define _UTF8_CHAR(n, val) ((Byte)(0x80 + (((val) >> (6 * (n))) & 0x3F)))
-
-static size_t Utf16_To_Utf8_Calc(const UInt16 *src, const UInt16 *srcLim)
-{
- size_t size = 0;
- for (;;)
- {
- UInt32 val;
- if (src == srcLim)
- return size;
-
- size++;
- val = *src++;
-
- if (val < 0x80)
- continue;
-
- if (val < _UTF8_RANGE(1))
- {
- size++;
- continue;
- }
-
- if (val >= 0xD800 && val < 0xDC00 && src != srcLim)
- {
- UInt32 c2 = *src;
- if (c2 >= 0xDC00 && c2 < 0xE000)
- {
- src++;
- size += 3;
- continue;
- }
- }
-
- size += 2;
- }
-}
-
-static Byte *Utf16_To_Utf8(Byte *dest, const UInt16 *src, const UInt16 *srcLim)
-{
- for (;;)
- {
- UInt32 val;
- if (src == srcLim)
- return dest;
-
- val = *src++;
-
- if (val < 0x80)
- {
- *dest++ = (char)val;
- continue;
- }
-
- if (val < _UTF8_RANGE(1))
- {
- dest[0] = _UTF8_HEAD(1, val);
- dest[1] = _UTF8_CHAR(0, val);
- dest += 2;
- continue;
- }
-
- if (val >= 0xD800 && val < 0xDC00 && src != srcLim)
- {
- UInt32 c2 = *src;
- if (c2 >= 0xDC00 && c2 < 0xE000)
- {
- src++;
- val = (((val - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
- dest[0] = _UTF8_HEAD(3, val);
- dest[1] = _UTF8_CHAR(2, val);
- dest[2] = _UTF8_CHAR(1, val);
- dest[3] = _UTF8_CHAR(0, val);
- dest += 4;
- continue;
- }
- }
-
- dest[0] = _UTF8_HEAD(2, val);
- dest[1] = _UTF8_CHAR(1, val);
- dest[2] = _UTF8_CHAR(0, val);
- dest += 3;
- }
-}
-
-static SRes Utf16_To_Utf8Buf(CBuf *dest, const UInt16 *src, size_t srcLen)
-{
- size_t destLen = Utf16_To_Utf8_Calc(src, src + srcLen);
- destLen += 1;
- if (!Buf_EnsureSize(dest, destLen))
- return SZ_ERROR_MEM;
- *Utf16_To_Utf8(dest->data, src, src + srcLen) = 0;
- return SZ_OK;
-}
-
-#endif
-
-static SRes Utf16_To_Char(CBuf *buf, const UInt16 *s
- #ifndef _USE_UTF8
- , UINT codePage
- #endif
- )
-{
- unsigned len = 0;
- for (len = 0; s[len] != 0; len++);
-
- #ifndef _USE_UTF8
- {
- unsigned size = len * 3 + 100;
- if (!Buf_EnsureSize(buf, size))
- return SZ_ERROR_MEM;
- {
- buf->data[0] = 0;
- if (len != 0)
- {
- char defaultChar = '_';
- BOOL defUsed;
- unsigned numChars = 0;
- numChars = WideCharToMultiByte(codePage, 0, (LPCWSTR)s, len, (char *)buf->data, size, &defaultChar, &defUsed);
- if (numChars == 0 || numChars >= size)
- return SZ_ERROR_FAIL;
- buf->data[numChars] = 0;
- }
- return SZ_OK;
- }
- }
- #else
- return Utf16_To_Utf8Buf(buf, s, len);
- #endif
-}
-
-#ifdef _WIN32
- #ifndef USE_WINDOWS_FILE
- static UINT g_FileCodePage = CP_ACP;
- #endif
- #define MY_FILE_CODE_PAGE_PARAM ,g_FileCodePage
-#else
- #define MY_FILE_CODE_PAGE_PARAM
-#endif
-
-static WRes MyCreateDir(const UInt16 *name)
-{
- #ifdef USE_WINDOWS_FILE
-
- return CreateDirectoryW((LPCWSTR)name, NULL) ? 0 : GetLastError();
-
- #else
-
- CBuf buf;
- WRes res;
- Buf_Init(&buf);
- RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM));
-
- res =
- #ifdef _WIN32
- _mkdir((const char *)buf.data)
- #else
- mkdir((const char *)buf.data, 0777)
- #endif
- == 0 ? 0 : errno;
- Buf_Free(&buf, &g_Alloc);
- return res;
-
- #endif
-}
-
-static WRes OutFile_OpenUtf16(CSzFile *p, const UInt16 *name)
-{
- #ifdef USE_WINDOWS_FILE
- return OutFile_OpenW(p, (LPCWSTR)name);
- #else
- CBuf buf;
- WRes res;
- Buf_Init(&buf);
- RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM));
- res = OutFile_Open(p, (const char *)buf.data);
- Buf_Free(&buf, &g_Alloc);
- return res;
- #endif
-}
-
-
-static SRes PrintString(const UInt16 *s)
-{
- CBuf buf;
- SRes res;
- Buf_Init(&buf);
- res = Utf16_To_Char(&buf, s
- #ifndef _USE_UTF8
- , CP_OEMCP
- #endif
- );
- if (res == SZ_OK)
- Print((const char *)buf.data);
- Buf_Free(&buf, &g_Alloc);
- return res;
-}
-
-static void UInt64ToStr(UInt64 value, char *s, int numDigits)
-{
- char temp[32];
- int pos = 0;
- do
- {
- temp[pos++] = (char)('0' + (unsigned)(value % 10));
- value /= 10;
- }
- while (value != 0);
-
- for (numDigits -= pos; numDigits > 0; numDigits--)
- *s++ = ' ';
-
- do
- *s++ = temp[--pos];
- while (pos);
- *s = '\0';
-}
-
-static char *UIntToStr(char *s, unsigned value, int numDigits)
-{
- char temp[16];
- int pos = 0;
- do
- temp[pos++] = (char)('0' + (value % 10));
- while (value /= 10);
-
- for (numDigits -= pos; numDigits > 0; numDigits--)
- *s++ = '0';
-
- do
- *s++ = temp[--pos];
- while (pos);
- *s = '\0';
- return s;
-}
-
-static void UIntToStr_2(char *s, unsigned value)
-{
- s[0] = (char)('0' + (value / 10));
- s[1] = (char)('0' + (value % 10));
-}
-
-#define PERIOD_4 (4 * 365 + 1)
-#define PERIOD_100 (PERIOD_4 * 25 - 1)
-#define PERIOD_400 (PERIOD_100 * 4 + 1)
-
-static void ConvertFileTimeToString(const CNtfsFileTime *nt, char *s)
-{
- unsigned year, mon, hour, min, sec;
- Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
- unsigned t;
- UInt32 v;
- UInt64 v64 = nt->Low | ((UInt64)nt->High << 32);
- v64 /= 10000000;
- sec = (unsigned)(v64 % 60); v64 /= 60;
- min = (unsigned)(v64 % 60); v64 /= 60;
- hour = (unsigned)(v64 % 24); v64 /= 24;
-
- v = (UInt32)v64;
-
- year = (unsigned)(1601 + v / PERIOD_400 * 400);
- v %= PERIOD_400;
-
- t = v / PERIOD_100; if (t == 4) t = 3; year += t * 100; v -= t * PERIOD_100;
- t = v / PERIOD_4; if (t == 25) t = 24; year += t * 4; v -= t * PERIOD_4;
- t = v / 365; if (t == 4) t = 3; year += t; v -= t * 365;
-
- if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
- ms[1] = 29;
- for (mon = 0;; mon++)
- {
- unsigned d = ms[mon];
- if (v < d)
- break;
- v -= d;
- }
- s = UIntToStr(s, year, 4); *s++ = '-';
- UIntToStr_2(s, mon + 1); s[2] = '-'; s += 3;
- UIntToStr_2(s, (unsigned)v + 1); s[2] = ' '; s += 3;
- UIntToStr_2(s, hour); s[2] = ':'; s += 3;
- UIntToStr_2(s, min); s[2] = ':'; s += 3;
- UIntToStr_2(s, sec); s[2] = 0;
-}
-
-static void PrintLF()
-{
- Print("\n");
-}
-
-static void PrintError(char *s)
-{
- Print("\nERROR: ");
- Print(s);
- PrintLF();
-}
-
-static void GetAttribString(UInt32 wa, BoolInt isDir, char *s)
-{
- #ifdef USE_WINDOWS_FILE
- s[0] = (char)(((wa & FILE_ATTRIBUTE_DIRECTORY) != 0 || isDir) ? 'D' : '.');
- s[1] = (char)(((wa & FILE_ATTRIBUTE_READONLY ) != 0) ? 'R': '.');
- s[2] = (char)(((wa & FILE_ATTRIBUTE_HIDDEN ) != 0) ? 'H': '.');
- s[3] = (char)(((wa & FILE_ATTRIBUTE_SYSTEM ) != 0) ? 'S': '.');
- s[4] = (char)(((wa & FILE_ATTRIBUTE_ARCHIVE ) != 0) ? 'A': '.');
- s[5] = 0;
- #else
- s[0] = (char)(((wa & (1 << 4)) != 0 || isDir) ? 'D' : '.');
- s[1] = 0;
- #endif
-}
-
-
-// #define NUM_PARENTS_MAX 128
-
-int MY_CDECL main(int numargs, char *args[])
-{
- ISzAlloc allocImp;
- ISzAlloc allocTempImp;
-
- CFileInStream archiveStream;
- CLookToRead2 lookStream;
- CSzArEx db;
- SRes res;
- UInt16 *temp = NULL;
- size_t tempSize = 0;
- // UInt32 parents[NUM_PARENTS_MAX];
-
- Print("\n7z Decoder " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n\n");
-
- if (numargs == 1)
- {
- Print(
- "Usage: 7zDec <command> <archive_name>\n\n"
- "<Commands>\n"
- " e: Extract files from archive (without using directory names)\n"
- " l: List contents of archive\n"
- " t: Test integrity of archive\n"
- " x: eXtract files with full paths\n");
- return 0;
- }
-
- if (numargs < 3)
- {
- PrintError("incorrect command");
- return 1;
- }
-
- #if defined(_WIN32) && !defined(USE_WINDOWS_FILE) && !defined(UNDER_CE)
- g_FileCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
- #endif
-
-
- allocImp = g_Alloc;
- allocTempImp = g_Alloc;
-
- #ifdef UNDER_CE
- if (InFile_OpenW(&archiveStream.file, L"\test.7z"))
- #else
- if (InFile_Open(&archiveStream.file, args[2]))
- #endif
- {
- PrintError("can not open input file");
- return 1;
- }
-
- FileInStream_CreateVTable(&archiveStream);
- LookToRead2_CreateVTable(&lookStream, False);
- lookStream.buf = NULL;
-
- res = SZ_OK;
-
- {
- lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize);
- if (!lookStream.buf)
- res = SZ_ERROR_MEM;
- else
- {
- lookStream.bufSize = kInputBufSize;
- lookStream.realStream = &archiveStream.vt;
- LookToRead2_Init(&lookStream);
- }
- }
-
- CrcGenerateTable();
-
- SzArEx_Init(&db);
-
- if (res == SZ_OK)
- {
- res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp);
- }
-
- if (res == SZ_OK)
- {
- char *command = args[1];
- int listCommand = 0, testCommand = 0, fullPaths = 0;
-
- if (strcmp(command, "l") == 0) listCommand = 1;
- else if (strcmp(command, "t") == 0) testCommand = 1;
- else if (strcmp(command, "e") == 0) { }
- else if (strcmp(command, "x") == 0) { fullPaths = 1; }
- else
- {
- PrintError("incorrect command");
- res = SZ_ERROR_FAIL;
- }
-
- if (res == SZ_OK)
- {
- UInt32 i;
-
- /*
- if you need cache, use these 3 variables.
- if you use external function, you can make these variable as static.
- */
- UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */
- Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */
- size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */
-
- for (i = 0; i < db.NumFiles; i++)
- {
- size_t offset = 0;
- size_t outSizeProcessed = 0;
- // const CSzFileItem *f = db.Files + i;
- size_t len;
- unsigned isDir = SzArEx_IsDir(&db, i);
- if (listCommand == 0 && isDir && !fullPaths)
- continue;
- len = SzArEx_GetFileNameUtf16(&db, i, NULL);
- // len = SzArEx_GetFullNameLen(&db, i);
-
- if (len > tempSize)
- {
- SzFree(NULL, temp);
- tempSize = len;
- temp = (UInt16 *)SzAlloc(NULL, tempSize * sizeof(temp[0]));
- if (!temp)
- {
- res = SZ_ERROR_MEM;
- break;
- }
- }
-
- SzArEx_GetFileNameUtf16(&db, i, temp);
- /*
- if (SzArEx_GetFullNameUtf16_Back(&db, i, temp + len) != temp)
- {
- res = SZ_ERROR_FAIL;
- break;
- }
- */
-
- if (listCommand)
- {
- char attr[8], s[32], t[32];
- UInt64 fileSize;
-
- GetAttribString(SzBitWithVals_Check(&db.Attribs, i) ? db.Attribs.Vals[i] : 0, isDir, attr);
-
- fileSize = SzArEx_GetFileSize(&db, i);
- UInt64ToStr(fileSize, s, 10);
-
- if (SzBitWithVals_Check(&db.MTime, i))
- ConvertFileTimeToString(&db.MTime.Vals[i], t);
- else
- {
- size_t j;
- for (j = 0; j < 19; j++)
- t[j] = ' ';
- t[j] = '\0';
- }
-
- Print(t);
- Print(" ");
- Print(attr);
- Print(" ");
- Print(s);
- Print(" ");
- res = PrintString(temp);
- if (res != SZ_OK)
- break;
- if (isDir)
- Print("/");
- PrintLF();
- continue;
- }
-
- Print(testCommand ?
- "Testing ":
- "Extracting ");
- res = PrintString(temp);
- if (res != SZ_OK)
- break;
-
- if (isDir)
- Print("/");
- else
- {
- res = SzArEx_Extract(&db, &lookStream.vt, i,
- &blockIndex, &outBuffer, &outBufferSize,
- &offset, &outSizeProcessed,
- &allocImp, &allocTempImp);
- if (res != SZ_OK)
- break;
- }
-
- if (!testCommand)
- {
- CSzFile outFile;
- size_t processedSize;
- size_t j;
- UInt16 *name = (UInt16 *)temp;
- const UInt16 *destPath = (const UInt16 *)name;
-
- for (j = 0; name[j] != 0; j++)
- if (name[j] == '/')
- {
- if (fullPaths)
- {
- name[j] = 0;
- MyCreateDir(name);
- name[j] = CHAR_PATH_SEPARATOR;
- }
- else
- destPath = name + j + 1;
- }
-
- if (isDir)
- {
- MyCreateDir(destPath);
- PrintLF();
- continue;
- }
- else if (OutFile_OpenUtf16(&outFile, destPath))
- {
- PrintError("can not open output file");
- res = SZ_ERROR_FAIL;
- break;
- }
-
- processedSize = outSizeProcessed;
-
- if (File_Write(&outFile, outBuffer + offset, &processedSize) != 0 || processedSize != outSizeProcessed)
- {
- PrintError("can not write output file");
- res = SZ_ERROR_FAIL;
- break;
- }
-
- #ifdef USE_WINDOWS_FILE
- {
- FILETIME mtime, ctime;
- FILETIME *mtimePtr = NULL;
- FILETIME *ctimePtr = NULL;
-
- if (SzBitWithVals_Check(&db.MTime, i))
- {
- const CNtfsFileTime *t = &db.MTime.Vals[i];
- mtime.dwLowDateTime = (DWORD)(t->Low);
- mtime.dwHighDateTime = (DWORD)(t->High);
- mtimePtr = &mtime;
- }
- if (SzBitWithVals_Check(&db.CTime, i))
- {
- const CNtfsFileTime *t = &db.CTime.Vals[i];
- ctime.dwLowDateTime = (DWORD)(t->Low);
- ctime.dwHighDateTime = (DWORD)(t->High);
- ctimePtr = &ctime;
- }
- if (mtimePtr || ctimePtr)
- SetFileTime(outFile.handle, ctimePtr, NULL, mtimePtr);
- }
- #endif
-
- if (File_Close(&outFile))
- {
- PrintError("can not close output file");
- res = SZ_ERROR_FAIL;
- break;
- }
-
- #ifdef USE_WINDOWS_FILE
- if (SzBitWithVals_Check(&db.Attribs, i))
- {
- UInt32 attrib = db.Attribs.Vals[i];
- /* p7zip stores posix attributes in high 16 bits and adds 0x8000 as marker.
- We remove posix bits, if we detect posix mode field */
- if ((attrib & 0xF0000000) != 0)
- attrib &= 0x7FFF;
- SetFileAttributesW((LPCWSTR)destPath, attrib);
- }
- #endif
- }
- PrintLF();
- }
- ISzAlloc_Free(&allocImp, outBuffer);
- }
- }
-
- SzFree(NULL, temp);
- SzArEx_Free(&db, &allocImp);
- ISzAlloc_Free(&allocImp, lookStream.buf);
-
- File_Close(&archiveStream.file);
-
- if (res == SZ_OK)
- {
- Print("\nEverything is Ok\n");
- return 0;
- }
-
- if (res == SZ_ERROR_UNSUPPORTED)
- PrintError("decoder doesn't support this archive");
- else if (res == SZ_ERROR_MEM)
- PrintError("can not allocate memory");
- else if (res == SZ_ERROR_CRC)
- PrintError("CRC error");
- else
- {
- char s[32];
- UInt64ToStr(res, s, 0);
- PrintError(s);
- }
-
- return 1;
-}
+/* 7zMain.c - Test application for 7z Decoder
+2023-04-04 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <stdio.h>
+#include <string.h>
+
+#include "../../CpuArch.h"
+
+#include "../../7z.h"
+#include "../../7zAlloc.h"
+#include "../../7zBuf.h"
+#include "../../7zCrc.h"
+#include "../../7zFile.h"
+#include "../../7zVersion.h"
+
+#ifndef USE_WINDOWS_FILE
+/* for mkdir */
+#ifdef _WIN32
+#include <direct.h>
+#else
+#include <stdlib.h>
+#include <time.h>
+#ifdef __GNUC__
+#include <sys/time.h>
+#endif
+#include <fcntl.h>
+// #include <utime.h>
+#include <sys/stat.h>
+#include <errno.h>
+#endif
+#endif
+
+#define kInputBufSize ((size_t)1 << 18)
+
+static const ISzAlloc g_Alloc = { SzAlloc, SzFree };
+// static const ISzAlloc g_Alloc_temp = { SzAllocTemp, SzFreeTemp };
+
+
+static void Print(const char *s)
+{
+ fputs(s, stdout);
+}
+
+
+static int Buf_EnsureSize(CBuf *dest, size_t size)
+{
+ if (dest->size >= size)
+ return 1;
+ Buf_Free(dest, &g_Alloc);
+ return Buf_Create(dest, size, &g_Alloc);
+}
+
+#ifndef _WIN32
+#define MY_USE_UTF8
+#endif
+
+/* #define MY_USE_UTF8 */
+
+#ifdef MY_USE_UTF8
+
+#define MY_UTF8_START(n) (0x100 - (1 << (7 - (n))))
+
+#define MY_UTF8_RANGE(n) (((UInt32)1) << ((n) * 5 + 6))
+
+#define MY_UTF8_HEAD(n, val) ((Byte)(MY_UTF8_START(n) + (val >> (6 * (n)))))
+#define MY_UTF8_CHAR(n, val) ((Byte)(0x80 + (((val) >> (6 * (n))) & 0x3F)))
+
+static size_t Utf16_To_Utf8_Calc(const UInt16 *src, const UInt16 *srcLim)
+{
+ size_t size = 0;
+ for (;;)
+ {
+ UInt32 val;
+ if (src == srcLim)
+ return size;
+
+ size++;
+ val = *src++;
+
+ if (val < 0x80)
+ continue;
+
+ if (val < MY_UTF8_RANGE(1))
+ {
+ size++;
+ continue;
+ }
+
+ if (val >= 0xD800 && val < 0xDC00 && src != srcLim)
+ {
+ const UInt32 c2 = *src;
+ if (c2 >= 0xDC00 && c2 < 0xE000)
+ {
+ src++;
+ size += 3;
+ continue;
+ }
+ }
+
+ size += 2;
+ }
+}
+
+static Byte *Utf16_To_Utf8(Byte *dest, const UInt16 *src, const UInt16 *srcLim)
+{
+ for (;;)
+ {
+ UInt32 val;
+ if (src == srcLim)
+ return dest;
+
+ val = *src++;
+
+ if (val < 0x80)
+ {
+ *dest++ = (Byte)val;
+ continue;
+ }
+
+ if (val < MY_UTF8_RANGE(1))
+ {
+ dest[0] = MY_UTF8_HEAD(1, val);
+ dest[1] = MY_UTF8_CHAR(0, val);
+ dest += 2;
+ continue;
+ }
+
+ if (val >= 0xD800 && val < 0xDC00 && src != srcLim)
+ {
+ const UInt32 c2 = *src;
+ if (c2 >= 0xDC00 && c2 < 0xE000)
+ {
+ src++;
+ val = (((val - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
+ dest[0] = MY_UTF8_HEAD(3, val);
+ dest[1] = MY_UTF8_CHAR(2, val);
+ dest[2] = MY_UTF8_CHAR(1, val);
+ dest[3] = MY_UTF8_CHAR(0, val);
+ dest += 4;
+ continue;
+ }
+ }
+
+ dest[0] = MY_UTF8_HEAD(2, val);
+ dest[1] = MY_UTF8_CHAR(1, val);
+ dest[2] = MY_UTF8_CHAR(0, val);
+ dest += 3;
+ }
+}
+
+static SRes Utf16_To_Utf8Buf(CBuf *dest, const UInt16 *src, size_t srcLen)
+{
+ size_t destLen = Utf16_To_Utf8_Calc(src, src + srcLen);
+ destLen += 1;
+ if (!Buf_EnsureSize(dest, destLen))
+ return SZ_ERROR_MEM;
+ *Utf16_To_Utf8(dest->data, src, src + srcLen) = 0;
+ return SZ_OK;
+}
+
+#endif
+
+static SRes Utf16_To_Char(CBuf *buf, const UInt16 *s
+ #ifndef MY_USE_UTF8
+ , UINT codePage
+ #endif
+ )
+{
+ unsigned len = 0;
+ for (len = 0; s[len] != 0; len++) {}
+
+ #ifndef MY_USE_UTF8
+ {
+ const unsigned size = len * 3 + 100;
+ if (!Buf_EnsureSize(buf, size))
+ return SZ_ERROR_MEM;
+ {
+ buf->data[0] = 0;
+ if (len != 0)
+ {
+ const char defaultChar = '_';
+ BOOL defUsed;
+ const unsigned numChars = (unsigned)WideCharToMultiByte(
+ codePage, 0, (LPCWSTR)s, (int)len, (char *)buf->data, (int)size, &defaultChar, &defUsed);
+ if (numChars == 0 || numChars >= size)
+ return SZ_ERROR_FAIL;
+ buf->data[numChars] = 0;
+ }
+ return SZ_OK;
+ }
+ }
+ #else
+ return Utf16_To_Utf8Buf(buf, s, len);
+ #endif
+}
+
+#ifdef _WIN32
+ #ifndef USE_WINDOWS_FILE
+ static UINT g_FileCodePage = CP_ACP;
+ #define MY_FILE_CODE_PAGE_PARAM ,g_FileCodePage
+ #endif
+#else
+ #define MY_FILE_CODE_PAGE_PARAM
+#endif
+
+static WRes MyCreateDir(const UInt16 *name)
+{
+ #ifdef USE_WINDOWS_FILE
+
+ return CreateDirectoryW((LPCWSTR)name, NULL) ? 0 : GetLastError();
+
+ #else
+
+ CBuf buf;
+ WRes res;
+ Buf_Init(&buf);
+ RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM))
+
+ res =
+ #ifdef _WIN32
+ _mkdir((const char *)buf.data)
+ #else
+ mkdir((const char *)buf.data, 0777)
+ #endif
+ == 0 ? 0 : errno;
+ Buf_Free(&buf, &g_Alloc);
+ return res;
+
+ #endif
+}
+
+static WRes OutFile_OpenUtf16(CSzFile *p, const UInt16 *name)
+{
+ #ifdef USE_WINDOWS_FILE
+ return OutFile_OpenW(p, (LPCWSTR)name);
+ #else
+ CBuf buf;
+ WRes res;
+ Buf_Init(&buf);
+ RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM))
+ res = OutFile_Open(p, (const char *)buf.data);
+ Buf_Free(&buf, &g_Alloc);
+ return res;
+ #endif
+}
+
+
+static SRes PrintString(const UInt16 *s)
+{
+ CBuf buf;
+ SRes res;
+ Buf_Init(&buf);
+ res = Utf16_To_Char(&buf, s
+ #ifndef MY_USE_UTF8
+ , CP_OEMCP
+ #endif
+ );
+ if (res == SZ_OK)
+ Print((const char *)buf.data);
+ Buf_Free(&buf, &g_Alloc);
+ return res;
+}
+
+static void UInt64ToStr(UInt64 value, char *s, int numDigits)
+{
+ char temp[32];
+ int pos = 0;
+ do
+ {
+ temp[pos++] = (char)('0' + (unsigned)(value % 10));
+ value /= 10;
+ }
+ while (value != 0);
+
+ for (numDigits -= pos; numDigits > 0; numDigits--)
+ *s++ = ' ';
+
+ do
+ *s++ = temp[--pos];
+ while (pos);
+ *s = '\0';
+}
+
+static char *UIntToStr(char *s, unsigned value, int numDigits)
+{
+ char temp[16];
+ int pos = 0;
+ do
+ temp[pos++] = (char)('0' + (value % 10));
+ while (value /= 10);
+
+ for (numDigits -= pos; numDigits > 0; numDigits--)
+ *s++ = '0';
+
+ do
+ *s++ = temp[--pos];
+ while (pos);
+ *s = '\0';
+ return s;
+}
+
+static void UIntToStr_2(char *s, unsigned value)
+{
+ s[0] = (char)('0' + (value / 10));
+ s[1] = (char)('0' + (value % 10));
+}
+
+
+#define PERIOD_4 (4 * 365 + 1)
+#define PERIOD_100 (PERIOD_4 * 25 - 1)
+#define PERIOD_400 (PERIOD_100 * 4 + 1)
+
+
+
+#ifndef _WIN32
+
+// MS uses long for BOOL, but long is 32-bit in MS. So we use int.
+// typedef long BOOL;
+typedef int BOOL;
+
+typedef struct _FILETIME
+{
+ DWORD dwLowDateTime;
+ DWORD dwHighDateTime;
+} FILETIME;
+
+static LONG TIME_GetBias()
+{
+ const time_t utc = time(NULL);
+ struct tm *ptm = localtime(&utc);
+ const int localdaylight = ptm->tm_isdst; /* daylight for local timezone */
+ ptm = gmtime(&utc);
+ ptm->tm_isdst = localdaylight; /* use local daylight, not that of Greenwich */
+ const LONG bias = (int)(mktime(ptm) - utc);
+ return bias;
+}
+
+#define TICKS_PER_SEC 10000000
+
+#define GET_TIME_64(pft) ((pft)->dwLowDateTime | ((UInt64)(pft)->dwHighDateTime << 32))
+
+#define SET_FILETIME(ft, v64) \
+ (ft)->dwLowDateTime = (DWORD)v64; \
+ (ft)->dwHighDateTime = (DWORD)(v64 >> 32);
+
+#define WINAPI
+#define TRUE 1
+
+static BOOL WINAPI FileTimeToLocalFileTime(const FILETIME *fileTime, FILETIME *localFileTime)
+{
+ UInt64 v = GET_TIME_64(fileTime);
+ v = (UInt64)((Int64)v - (Int64)TIME_GetBias() * TICKS_PER_SEC);
+ SET_FILETIME(localFileTime, v)
+ return TRUE;
+}
+
+static const UInt32 kNumTimeQuantumsInSecond = 10000000;
+static const UInt32 kFileTimeStartYear = 1601;
+static const UInt32 kUnixTimeStartYear = 1970;
+static const UInt64 kUnixTimeOffset =
+ (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear));
+
+static Int64 Time_FileTimeToUnixTime64(const FILETIME *ft)
+{
+ const UInt64 winTime = GET_TIME_64(ft);
+ return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset;
+}
+
+#if defined(_AIX)
+ #define MY_ST_TIMESPEC st_timespec
+#else
+ #define MY_ST_TIMESPEC timespec
+#endif
+
+static void FILETIME_To_timespec(const FILETIME *ft, struct MY_ST_TIMESPEC *ts)
+{
+ if (ft)
+ {
+ const Int64 sec = Time_FileTimeToUnixTime64(ft);
+ // time_t is long
+ const time_t sec2 = (time_t)sec;
+ if (sec2 == sec)
+ {
+ ts->tv_sec = sec2;
+ const UInt64 winTime = GET_TIME_64(ft);
+ ts->tv_nsec = (long)((winTime % 10000000) * 100);
+ return;
+ }
+ }
+ // else
+ {
+ ts->tv_sec = 0;
+ // ts.tv_nsec = UTIME_NOW; // set to the current time
+ ts->tv_nsec = UTIME_OMIT; // keep old timesptamp
+ }
+}
+
+static WRes Set_File_FILETIME(const UInt16 *name, const FILETIME *mTime)
+{
+ struct timespec times[2];
+
+ const int flags = 0; // follow link
+ // = AT_SYMLINK_NOFOLLOW; // don't follow link
+
+ CBuf buf;
+ int res;
+ Buf_Init(&buf);
+ RINOK(Utf16_To_Char(&buf, name MY_FILE_CODE_PAGE_PARAM))
+ FILETIME_To_timespec(NULL, &times[0]);
+ FILETIME_To_timespec(mTime, &times[1]);
+ res = utimensat(AT_FDCWD, (const char *)buf.data, times, flags);
+ Buf_Free(&buf, &g_Alloc);
+ if (res == 0)
+ return 0;
+ return errno;
+}
+
+#endif
+
+static void NtfsFileTime_to_FILETIME(const CNtfsFileTime *t, FILETIME *ft)
+{
+ ft->dwLowDateTime = (DWORD)(t->Low);
+ ft->dwHighDateTime = (DWORD)(t->High);
+}
+
+static void ConvertFileTimeToString(const CNtfsFileTime *nTime, char *s)
+{
+ unsigned year, mon, hour, min, sec;
+ Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ unsigned t;
+ UInt32 v;
+ // UInt64 v64 = nt->Low | ((UInt64)nt->High << 32);
+ UInt64 v64;
+ {
+ FILETIME fileTime, locTime;
+ NtfsFileTime_to_FILETIME(nTime, &fileTime);
+ if (!FileTimeToLocalFileTime(&fileTime, &locTime))
+ {
+ locTime.dwHighDateTime =
+ locTime.dwLowDateTime = 0;
+ }
+ v64 = locTime.dwLowDateTime | ((UInt64)locTime.dwHighDateTime << 32);
+ }
+ v64 /= 10000000;
+ sec = (unsigned)(v64 % 60); v64 /= 60;
+ min = (unsigned)(v64 % 60); v64 /= 60;
+ hour = (unsigned)(v64 % 24); v64 /= 24;
+
+ v = (UInt32)v64;
+
+ year = (unsigned)(1601 + v / PERIOD_400 * 400);
+ v %= PERIOD_400;
+
+ t = v / PERIOD_100; if (t == 4) t = 3; year += t * 100; v -= t * PERIOD_100;
+ t = v / PERIOD_4; if (t == 25) t = 24; year += t * 4; v -= t * PERIOD_4;
+ t = v / 365; if (t == 4) t = 3; year += t; v -= t * 365;
+
+ if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
+ ms[1] = 29;
+ for (mon = 0;; mon++)
+ {
+ const unsigned d = ms[mon];
+ if (v < d)
+ break;
+ v -= d;
+ }
+ s = UIntToStr(s, year, 4); *s++ = '-';
+ UIntToStr_2(s, mon + 1); s[2] = '-'; s += 3;
+ UIntToStr_2(s, (unsigned)v + 1); s[2] = ' '; s += 3;
+ UIntToStr_2(s, hour); s[2] = ':'; s += 3;
+ UIntToStr_2(s, min); s[2] = ':'; s += 3;
+ UIntToStr_2(s, sec); s[2] = 0;
+}
+
+static void PrintLF(void)
+{
+ Print("\n");
+}
+
+static void PrintError(char *s)
+{
+ Print("\nERROR: ");
+ Print(s);
+ PrintLF();
+}
+
+static void PrintError_WRes(const char *message, WRes wres)
+{
+ Print("\nERROR: ");
+ Print(message);
+ PrintLF();
+ {
+ char s[32];
+ UIntToStr(s, (unsigned)wres, 1);
+ Print("System error code: ");
+ Print(s);
+ }
+ // sprintf(buffer + strlen(buffer), "\nSystem error code: %d", (unsigned)wres);
+ #ifdef _WIN32
+ {
+ char *s = NULL;
+ if (FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, wres, 0, (LPSTR) &s, 0, NULL) != 0 && s)
+ {
+ Print(" : ");
+ Print(s);
+ LocalFree(s);
+ }
+ }
+ #else
+ {
+ const char *s = strerror(wres);
+ if (s)
+ {
+ Print(" : ");
+ Print(s);
+ }
+ }
+ #endif
+ PrintLF();
+}
+
+static void GetAttribString(UInt32 wa, BoolInt isDir, char *s)
+{
+ #ifdef USE_WINDOWS_FILE
+ s[0] = (char)(((wa & FILE_ATTRIBUTE_DIRECTORY) != 0 || isDir) ? 'D' : '.');
+ s[1] = (char)(((wa & FILE_ATTRIBUTE_READONLY ) != 0) ? 'R': '.');
+ s[2] = (char)(((wa & FILE_ATTRIBUTE_HIDDEN ) != 0) ? 'H': '.');
+ s[3] = (char)(((wa & FILE_ATTRIBUTE_SYSTEM ) != 0) ? 'S': '.');
+ s[4] = (char)(((wa & FILE_ATTRIBUTE_ARCHIVE ) != 0) ? 'A': '.');
+ s[5] = 0;
+ #else
+ s[0] = (char)(((wa & (1 << 4)) != 0 || isDir) ? 'D' : '.');
+ s[1] = 0;
+ #endif
+}
+
+
+// #define NUM_PARENTS_MAX 128
+
+int Z7_CDECL main(int numargs, char *args[])
+{
+ ISzAlloc allocImp;
+ ISzAlloc allocTempImp;
+
+ CFileInStream archiveStream;
+ CLookToRead2 lookStream;
+ CSzArEx db;
+ SRes res;
+ UInt16 *temp = NULL;
+ size_t tempSize = 0;
+ // UInt32 parents[NUM_PARENTS_MAX];
+
+ Print("\n7z Decoder " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n\n");
+
+ if (numargs == 1)
+ {
+ Print(
+ "Usage: 7zDec <command> <archive_name>\n\n"
+ "<Commands>\n"
+ " e: Extract files from archive (without using directory names)\n"
+ " l: List contents of archive\n"
+ " t: Test integrity of archive\n"
+ " x: eXtract files with full paths\n");
+ return 0;
+ }
+
+ if (numargs < 3)
+ {
+ PrintError("incorrect command");
+ return 1;
+ }
+
+ #if defined(_WIN32) && !defined(USE_WINDOWS_FILE) && !defined(UNDER_CE)
+ g_FileCodePage = AreFileApisANSI() ? CP_ACP : CP_OEMCP;
+ #endif
+
+
+ allocImp = g_Alloc;
+ allocTempImp = g_Alloc;
+ // allocTempImp = g_Alloc_temp;
+
+ {
+ WRes wres =
+ #ifdef UNDER_CE
+ InFile_OpenW(&archiveStream.file, L"\test.7z"); // change it
+ #else
+ InFile_Open(&archiveStream.file, args[2]);
+ #endif
+ if (wres != 0)
+ {
+ PrintError_WRes("cannot open input file", wres);
+ return 1;
+ }
+ }
+
+ FileInStream_CreateVTable(&archiveStream);
+ archiveStream.wres = 0;
+ LookToRead2_CreateVTable(&lookStream, False);
+ lookStream.buf = NULL;
+
+ res = SZ_OK;
+
+ {
+ lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize);
+ if (!lookStream.buf)
+ res = SZ_ERROR_MEM;
+ else
+ {
+ lookStream.bufSize = kInputBufSize;
+ lookStream.realStream = &archiveStream.vt;
+ LookToRead2_INIT(&lookStream)
+ }
+ }
+
+ CrcGenerateTable();
+
+ SzArEx_Init(&db);
+
+ if (res == SZ_OK)
+ {
+ res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp);
+ }
+
+ if (res == SZ_OK)
+ {
+ char *command = args[1];
+ int listCommand = 0, testCommand = 0, fullPaths = 0;
+
+ if (strcmp(command, "l") == 0) listCommand = 1;
+ else if (strcmp(command, "t") == 0) testCommand = 1;
+ else if (strcmp(command, "e") == 0) { }
+ else if (strcmp(command, "x") == 0) { fullPaths = 1; }
+ else
+ {
+ PrintError("incorrect command");
+ res = SZ_ERROR_FAIL;
+ }
+
+ if (res == SZ_OK)
+ {
+ UInt32 i;
+
+ /*
+ if you need cache, use these 3 variables.
+ if you use external function, you can make these variable as static.
+ */
+ UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */
+ Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */
+ size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */
+
+ for (i = 0; i < db.NumFiles; i++)
+ {
+ size_t offset = 0;
+ size_t outSizeProcessed = 0;
+ // const CSzFileItem *f = db.Files + i;
+ size_t len;
+ const BoolInt isDir = SzArEx_IsDir(&db, i);
+ if (listCommand == 0 && isDir && !fullPaths)
+ continue;
+ len = SzArEx_GetFileNameUtf16(&db, i, NULL);
+ // len = SzArEx_GetFullNameLen(&db, i);
+
+ if (len > tempSize)
+ {
+ SzFree(NULL, temp);
+ tempSize = len;
+ temp = (UInt16 *)SzAlloc(NULL, tempSize * sizeof(temp[0]));
+ if (!temp)
+ {
+ res = SZ_ERROR_MEM;
+ break;
+ }
+ }
+
+ SzArEx_GetFileNameUtf16(&db, i, temp);
+ /*
+ if (SzArEx_GetFullNameUtf16_Back(&db, i, temp + len) != temp)
+ {
+ res = SZ_ERROR_FAIL;
+ break;
+ }
+ */
+
+ if (listCommand)
+ {
+ char attr[8], s[32], t[32];
+ UInt64 fileSize;
+
+ GetAttribString(SzBitWithVals_Check(&db.Attribs, i) ? db.Attribs.Vals[i] : 0, isDir, attr);
+
+ fileSize = SzArEx_GetFileSize(&db, i);
+ UInt64ToStr(fileSize, s, 10);
+
+ if (SzBitWithVals_Check(&db.MTime, i))
+ ConvertFileTimeToString(&db.MTime.Vals[i], t);
+ else
+ {
+ size_t j;
+ for (j = 0; j < 19; j++)
+ t[j] = ' ';
+ t[j] = '\0';
+ }
+
+ Print(t);
+ Print(" ");
+ Print(attr);
+ Print(" ");
+ Print(s);
+ Print(" ");
+ res = PrintString(temp);
+ if (res != SZ_OK)
+ break;
+ if (isDir)
+ Print("/");
+ PrintLF();
+ continue;
+ }
+
+ Print(testCommand ?
+ "T ":
+ "- ");
+ res = PrintString(temp);
+ if (res != SZ_OK)
+ break;
+
+ if (isDir)
+ Print("/");
+ else
+ {
+ res = SzArEx_Extract(&db, &lookStream.vt, i,
+ &blockIndex, &outBuffer, &outBufferSize,
+ &offset, &outSizeProcessed,
+ &allocImp, &allocTempImp);
+ if (res != SZ_OK)
+ break;
+ }
+
+ if (!testCommand)
+ {
+ CSzFile outFile;
+ size_t processedSize;
+ size_t j;
+ UInt16 *name = (UInt16 *)temp;
+ const UInt16 *destPath = (const UInt16 *)name;
+
+ for (j = 0; name[j] != 0; j++)
+ if (name[j] == '/')
+ {
+ if (fullPaths)
+ {
+ name[j] = 0;
+ MyCreateDir(name);
+ name[j] = CHAR_PATH_SEPARATOR;
+ }
+ else
+ destPath = name + j + 1;
+ }
+
+ if (isDir)
+ {
+ MyCreateDir(destPath);
+ PrintLF();
+ continue;
+ }
+ else
+ {
+ const WRes wres = OutFile_OpenUtf16(&outFile, destPath);
+ if (wres != 0)
+ {
+ PrintError_WRes("cannot open output file", wres);
+ res = SZ_ERROR_FAIL;
+ break;
+ }
+ }
+
+ processedSize = outSizeProcessed;
+
+ {
+ const WRes wres = File_Write(&outFile, outBuffer + offset, &processedSize);
+ if (wres != 0 || processedSize != outSizeProcessed)
+ {
+ PrintError_WRes("cannot write output file", wres);
+ res = SZ_ERROR_FAIL;
+ break;
+ }
+ }
+
+ {
+ FILETIME mtime;
+ FILETIME *mtimePtr = NULL;
+
+ #ifdef USE_WINDOWS_FILE
+ FILETIME ctime;
+ FILETIME *ctimePtr = NULL;
+ #endif
+
+ if (SzBitWithVals_Check(&db.MTime, i))
+ {
+ const CNtfsFileTime *t = &db.MTime.Vals[i];
+ mtime.dwLowDateTime = (DWORD)(t->Low);
+ mtime.dwHighDateTime = (DWORD)(t->High);
+ mtimePtr = &mtime;
+ }
+
+ #ifdef USE_WINDOWS_FILE
+ if (SzBitWithVals_Check(&db.CTime, i))
+ {
+ const CNtfsFileTime *t = &db.CTime.Vals[i];
+ ctime.dwLowDateTime = (DWORD)(t->Low);
+ ctime.dwHighDateTime = (DWORD)(t->High);
+ ctimePtr = &ctime;
+ }
+
+ if (mtimePtr || ctimePtr)
+ SetFileTime(outFile.handle, ctimePtr, NULL, mtimePtr);
+ #endif
+
+ {
+ const WRes wres = File_Close(&outFile);
+ if (wres != 0)
+ {
+ PrintError_WRes("cannot close output file", wres);
+ res = SZ_ERROR_FAIL;
+ break;
+ }
+ }
+
+ #ifndef USE_WINDOWS_FILE
+ #ifdef _WIN32
+ mtimePtr = mtimePtr;
+ #else
+ if (mtimePtr)
+ Set_File_FILETIME(destPath, mtimePtr);
+ #endif
+ #endif
+ }
+
+ #ifdef USE_WINDOWS_FILE
+ if (SzBitWithVals_Check(&db.Attribs, i))
+ {
+ UInt32 attrib = db.Attribs.Vals[i];
+ /* p7zip stores posix attributes in high 16 bits and adds 0x8000 as marker.
+ We remove posix bits, if we detect posix mode field */
+ if ((attrib & 0xF0000000) != 0)
+ attrib &= 0x7FFF;
+ SetFileAttributesW((LPCWSTR)destPath, attrib);
+ }
+ #endif
+ }
+ PrintLF();
+ }
+ ISzAlloc_Free(&allocImp, outBuffer);
+ }
+ }
+
+ SzFree(NULL, temp);
+ SzArEx_Free(&db, &allocImp);
+ ISzAlloc_Free(&allocImp, lookStream.buf);
+
+ File_Close(&archiveStream.file);
+
+ if (res == SZ_OK)
+ {
+ Print("\nEverything is Ok\n");
+ return 0;
+ }
+
+ if (res == SZ_ERROR_UNSUPPORTED)
+ PrintError("decoder doesn't support this archive");
+ else if (res == SZ_ERROR_MEM)
+ PrintError("cannot allocate memory");
+ else if (res == SZ_ERROR_CRC)
+ PrintError("CRC error");
+ else if (res == SZ_ERROR_READ /* || archiveStream.Res != 0 */)
+ PrintError_WRes("Read Error", archiveStream.wres);
+ else
+ {
+ char s[32];
+ UInt64ToStr((unsigned)res, s, 0);
+ PrintError(s);
+ }
+
+ return 1;
+}
diff --git a/C/Util/7z/Precomp.c b/C/Util/7z/Precomp.c
index 34b60f8..01605e3 100644
--- a/C/Util/7z/Precomp.c
+++ b/C/Util/7z/Precomp.c
@@ -1,4 +1,4 @@
-/* Precomp.c -- StdAfx
-2013-01-21 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
+/* Precomp.c -- StdAfx
+2013-01-21 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
diff --git a/C/Util/7z/Precomp.h b/C/Util/7z/Precomp.h
index 9f398d0..bc8fa21 100644
--- a/C/Util/7z/Precomp.h
+++ b/C/Util/7z/Precomp.h
@@ -1,10 +1,14 @@
-/* Precomp.h -- StdAfx
-2013-06-16 : Igor Pavlov : Public domain */
-
-#ifndef __7Z_PRECOMP_H
-#define __7Z_PRECOMP_H
-
-#include "../../Compiler.h"
-#include "../../7zTypes.h"
-
-#endif
+/* Precomp.h -- StdAfx
+2023-03-04 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_PRECOMP_H
+#define ZIP7_INC_PRECOMP_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+
+#include "../../Compiler.h"
+#include "../../7zTypes.h"
+
+#endif
diff --git a/C/Util/7z/makefile b/C/Util/7z/makefile
index f4a54af..dfc560e 100644
--- a/C/Util/7z/makefile
+++ b/C/Util/7z/makefile
@@ -1,40 +1,40 @@
-CFLAGS = $(CFLAGS) -D_7ZIP_PPMD_SUPPPORT
-
-PROG = 7zDec.exe
-
-C_OBJS = \
- $O\7zAlloc.obj \
- $O\7zBuf.obj \
- $O\7zCrc.obj \
- $O\7zCrcOpt.obj \
- $O\7zFile.obj \
- $O\7zDec.obj \
- $O\7zArcIn.obj \
- $O\7zStream.obj \
- $O\Bcj2.obj \
- $O\Bra.obj \
- $O\Bra86.obj \
- $O\BraIA64.obj \
- $O\CpuArch.obj \
- $O\Delta.obj \
- $O\Lzma2Dec.obj \
- $O\LzmaDec.obj \
- $O\Ppmd7.obj \
- $O\Ppmd7Dec.obj \
-
-7Z_OBJS = \
- $O\7zMain.obj \
-
-OBJS = \
- $O\Precomp.obj \
- $(7Z_OBJS) \
- $(C_OBJS) \
-
-!include "../../../CPP/Build.mak"
-
-$(7Z_OBJS): $(*B).c
- $(CCOMPL_USE)
-$(C_OBJS): ../../$(*B).c
- $(CCOMPL_USE)
-$O\Precomp.obj: Precomp.c
- $(CCOMPL_PCH)
+CFLAGS = $(CFLAGS) -DZ7_PPMD_SUPPORT -DZ7_EXTRACT_ONLY
+
+PROG = 7zDec.exe
+
+C_OBJS = \
+ $O\7zAlloc.obj \
+ $O\7zBuf.obj \
+ $O\7zCrc.obj \
+ $O\7zCrcOpt.obj \
+ $O\7zFile.obj \
+ $O\7zDec.obj \
+ $O\7zArcIn.obj \
+ $O\7zStream.obj \
+ $O\Bcj2.obj \
+ $O\Bra.obj \
+ $O\Bra86.obj \
+ $O\BraIA64.obj \
+ $O\CpuArch.obj \
+ $O\Delta.obj \
+ $O\Lzma2Dec.obj \
+ $O\LzmaDec.obj \
+ $O\Ppmd7.obj \
+ $O\Ppmd7Dec.obj \
+
+7Z_OBJS = \
+ $O\7zMain.obj \
+
+OBJS = \
+ $O\Precomp.obj \
+ $(7Z_OBJS) \
+ $(C_OBJS) \
+
+!include "../../../CPP/Build.mak"
+
+$(7Z_OBJS): $(*B).c
+ $(CCOMPL_USE)
+$(C_OBJS): ../../$(*B).c
+ $(CCOMPL_USE)
+$O\Precomp.obj: Precomp.c
+ $(CCOMPL_PCH)
diff --git a/C/Util/7z/makefile.gcc b/C/Util/7z/makefile.gcc
index f707935..f48d362 100644
--- a/C/Util/7z/makefile.gcc
+++ b/C/Util/7z/makefile.gcc
@@ -1,75 +1,32 @@
-PROG = 7zDec
-CXX = gcc
-LIB =
-RM = rm -f
-CFLAGS = -c -O2 -Wall
-
-OBJS = 7zMain.o 7zAlloc.o 7zArcIn.o 7zBuf.o 7zBuf2.o 7zCrc.o 7zCrcOpt.o 7zDec.o CpuArch.o Delta.o LzmaDec.o Lzma2Dec.o Bra.o Bra86.o BraIA64.o Bcj2.o Ppmd7.o Ppmd7Dec.o 7zFile.o 7zStream.o
-
-all: $(PROG)
-
-$(PROG): $(OBJS)
- $(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB)
-
-7zMain.o: 7zMain.c
- $(CXX) $(CFLAGS) 7zMain.c
-
-7zAlloc.o: ../../7zAlloc.c
- $(CXX) $(CFLAGS) ../../7zAlloc.c
-
-7zArcIn.o: ../../7zArcIn.c
- $(CXX) $(CFLAGS) ../../7zArcIn.c
-
-7zBuf.o: ../../7zBuf.c
- $(CXX) $(CFLAGS) ../../7zBuf.c
-
-7zBuf2.o: ../../7zBuf2.c
- $(CXX) $(CFLAGS) ../../7zBuf2.c
-
-7zCrc.o: ../../7zCrc.c
- $(CXX) $(CFLAGS) ../../7zCrc.c
-
-7zCrcOpt.o: ../../7zCrc.c
- $(CXX) $(CFLAGS) ../../7zCrcOpt.c
-
-7zDec.o: ../../7zDec.c
- $(CXX) $(CFLAGS) -D_7ZIP_PPMD_SUPPPORT ../../7zDec.c
-
-CpuArch.o: ../../CpuArch.c
- $(CXX) $(CFLAGS) ../../CpuArch.c
-
-Delta.o: ../../Delta.c
- $(CXX) $(CFLAGS) ../../Delta.c
-
-LzmaDec.o: ../../LzmaDec.c
- $(CXX) $(CFLAGS) ../../LzmaDec.c
-
-Lzma2Dec.o: ../../Lzma2Dec.c
- $(CXX) $(CFLAGS) ../../Lzma2Dec.c
-
-Bra.o: ../../Bra.c
- $(CXX) $(CFLAGS) ../../Bra.c
-
-Bra86.o: ../../Bra86.c
- $(CXX) $(CFLAGS) ../../Bra86.c
-
-BraIA64.o: ../../BraIA64.c
- $(CXX) $(CFLAGS) ../../BraIA64.c
-
-Bcj2.o: ../../Bcj2.c
- $(CXX) $(CFLAGS) ../../Bcj2.c
-
-Ppmd7.o: ../../Ppmd7.c
- $(CXX) $(CFLAGS) ../../Ppmd7.c
-
-Ppmd7Dec.o: ../../Ppmd7Dec.c
- $(CXX) $(CFLAGS) ../../Ppmd7Dec.c
-
-7zFile.o: ../../7zFile.c
- $(CXX) $(CFLAGS) ../../7zFile.c
-
-7zStream.o: ../../7zStream.c
- $(CXX) $(CFLAGS) ../../7zStream.c
-
-clean:
- -$(RM) $(PROG) $(OBJS)
+PROG = 7zdec
+
+LOCAL_FLAGS = -DZ7_PPMD_SUPPORT -DZ7_EXTRACT_ONLY
+
+include ../../../CPP/7zip/LzmaDec_gcc.mak
+
+
+OBJS = \
+ $(LZMA_DEC_OPT_OBJS) \
+ $O/Bcj2.o \
+ $O/Bra.o \
+ $O/Bra86.o \
+ $O/BraIA64.o \
+ $O/CpuArch.o \
+ $O/Delta.o \
+ $O/Lzma2Dec.o \
+ $O/LzmaDec.o \
+ $O/Ppmd7.o \
+ $O/Ppmd7Dec.o \
+ $O/7zCrc.o \
+ $O/7zCrcOpt.o \
+ $O/7zAlloc.o \
+ $O/7zArcIn.o \
+ $O/7zBuf.o \
+ $O/7zBuf2.o \
+ $O/7zDec.o \
+ $O/7zMain.o \
+ $O/7zFile.o \
+ $O/7zStream.o \
+
+
+include ../../7zip_gcc_c.mak
diff --git a/C/Util/7zipInstall/7zip.ico b/C/Util/7zipInstall/7zip.ico
new file mode 100644
index 0000000..47ffb78
--- /dev/null
+++ b/C/Util/7zipInstall/7zip.ico
Binary files differ
diff --git a/C/Util/7zipInstall/7zipInstall.c b/C/Util/7zipInstall/7zipInstall.c
new file mode 100644
index 0000000..7f5fd19
--- /dev/null
+++ b/C/Util/7zipInstall/7zipInstall.c
@@ -0,0 +1,1699 @@
+/* 7zipInstall.c - 7-Zip Installer
+2023-04-04 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#define SZ_ERROR_ABORT 100
+
+#include "../../7zWindows.h"
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
+#endif
+
+#ifdef Z7_OLD_WIN_SDK
+struct IShellView;
+#define SHFOLDERAPI EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE
+SHFOLDERAPI SHGetFolderPathW(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath);
+#define BIF_NEWDIALOGSTYLE 0x0040 // Use the new dialog layout with the ability to resize
+typedef enum {
+ SHGFP_TYPE_CURRENT = 0, // current value for user, verify it exists
+ SHGFP_TYPE_DEFAULT = 1, // default value, may not exist
+} SHGFP_TYPE;
+#endif
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <shlobj.h>
+#else
+#include <ShlObj.h>
+#endif
+
+#include "../../7z.h"
+#include "../../7zAlloc.h"
+#include "../../7zCrc.h"
+#include "../../7zFile.h"
+#include "../../7zVersion.h"
+#include "../../CpuArch.h"
+#include "../../DllSecur.h"
+
+#include "resource.h"
+
+#if (defined(__GNUC__) && (__GNUC__ >= 8)) || defined(__clang__)
+ // #pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+
+#if defined(__clang__) || defined(__GNUC__)
+typedef void (*Z7_voidFunction)(void);
+#define MY_CAST_FUNC (Z7_voidFunction)
+#elif defined(_MSC_VER) && _MSC_VER > 1920
+#define MY_CAST_FUNC (void *)
+// #pragma warning(disable : 4191) // 'type cast': unsafe conversion from 'FARPROC' to 'void (__cdecl *)()'
+#else
+#define MY_CAST_FUNC
+#endif
+
+#define LLL_(quote) L##quote
+#define LLL(quote) LLL_(quote)
+
+#define wcscat lstrcatW
+#define wcslen (size_t)lstrlenW
+#define wcscpy lstrcpyW
+// wcsncpy() and lstrcpynW() work differently. We don't use them.
+
+#define kInputBufSize ((size_t)1 << 18)
+
+#define Z7_7ZIP_CUR_VER ((MY_VER_MAJOR << 16) | MY_VER_MINOR)
+#define Z7_7ZIP_DLL_VER_COMPAT ((16 << 16) | 3)
+
+static LPCSTR const k_7zip = "7-Zip";
+
+static LPCWSTR const k_Reg_Software_7zip = L"Software\\7-Zip";
+
+// #define Z7_64BIT_INSTALLER 1
+
+#ifdef _WIN64
+ #define Z7_64BIT_INSTALLER 1
+#endif
+
+#define k_7zip_with_Ver_base L"7-Zip " LLL(MY_VERSION)
+
+#ifdef Z7_64BIT_INSTALLER
+
+ // #define USE_7ZIP_32_DLL
+
+ #if defined(_M_ARM64) || defined(_M_ARM)
+ #define k_Postfix L" (arm64)"
+ #else
+ #define k_Postfix L" (x64)"
+ #define USE_7ZIP_32_DLL
+ #endif
+#else
+ #if defined(_M_ARM64) || defined(_M_ARM)
+ #define k_Postfix L" (arm)"
+ #else
+ // #define k_Postfix L" (x86)"
+ #define k_Postfix
+ #endif
+#endif
+
+#define k_7zip_with_Ver k_7zip_with_Ver_base k_Postfix
+
+
+static LPCWSTR const k_7zip_with_Ver_str = k_7zip_with_Ver;
+
+static LPCWSTR const k_7zip_Setup = k_7zip_with_Ver L" Setup";
+
+static LPCWSTR const k_Reg_Path = L"Path";
+
+static LPCWSTR const k_Reg_Path32 = L"Path"
+ #ifdef Z7_64BIT_INSTALLER
+ L"64"
+ #else
+ L"32"
+ #endif
+ ;
+
+#if defined(Z7_64BIT_INSTALLER) && !defined(_WIN64)
+ #define k_Reg_WOW_Flag KEY_WOW64_64KEY
+#else
+ #define k_Reg_WOW_Flag 0
+#endif
+
+#ifdef _WIN64
+ #define k_Reg_WOW_Flag_32 KEY_WOW64_32KEY
+#else
+ #define k_Reg_WOW_Flag_32 0
+#endif
+
+#define k_7zip_CLSID L"{23170F69-40C1-278A-1000-000100020000}"
+
+static LPCWSTR const k_Reg_CLSID_7zip = L"CLSID\\" k_7zip_CLSID;
+static LPCWSTR const k_Reg_CLSID_7zip_Inproc = L"CLSID\\" k_7zip_CLSID L"\\InprocServer32";
+
+#define g_AllUsers True
+
+static BoolInt g_Install_was_Pressed;
+static BoolInt g_Finished;
+static BoolInt g_SilentMode;
+
+static HWND g_HWND;
+static HWND g_Path_HWND;
+static HWND g_InfoLine_HWND;
+static HWND g_Progress_HWND;
+
+static DWORD g_TotalSize;
+
+static WCHAR cmd[MAX_PATH + 4];
+static WCHAR cmdError[MAX_PATH + 4];
+static WCHAR path[MAX_PATH * 2 + 40];
+
+
+
+static void CpyAscii(wchar_t *dest, const char *s)
+{
+ for (;;)
+ {
+ Byte b = (Byte)*s++;
+ *dest++ = b;
+ if (b == 0)
+ return;
+ }
+}
+
+static void CatAscii(wchar_t *dest, const char *s)
+{
+ dest += wcslen(dest);
+ CpyAscii(dest, s);
+}
+
+static void PrintErrorMessage(const char *s1, const wchar_t *s2)
+{
+ WCHAR m[MAX_PATH + 512];
+ m[0] = 0;
+ CatAscii(m, "ERROR:");
+ if (s1)
+ {
+ CatAscii(m, "\n");
+ CatAscii(m, s1);
+ }
+ if (s2)
+ {
+ CatAscii(m, "\n");
+ wcscat(m, s2);
+ }
+ MessageBoxW(g_HWND, m, k_7zip_with_Ver_str, MB_ICONERROR | MB_OK);
+}
+
+
+typedef DWORD (WINAPI * Func_GetFileVersionInfoSizeW)(LPCWSTR lptstrFilename, LPDWORD lpdwHandle);
+typedef BOOL (WINAPI * Func_GetFileVersionInfoW)(LPCWSTR lptstrFilename, DWORD dwHandle, DWORD dwLen, LPVOID lpData);
+typedef BOOL (WINAPI * Func_VerQueryValueW)(const LPVOID pBlock, LPWSTR lpSubBlock, LPVOID * lplpBuffer, PUINT puLen);
+
+static HMODULE g_version_dll_hModule;
+
+static DWORD GetFileVersion(LPCWSTR s)
+{
+ DWORD size = 0;
+ void *vi = NULL;
+ DWORD version = 0;
+
+ Func_GetFileVersionInfoSizeW my_GetFileVersionInfoSizeW;
+ Func_GetFileVersionInfoW my_GetFileVersionInfoW;
+ Func_VerQueryValueW my_VerQueryValueW;
+
+ if (!g_version_dll_hModule)
+ {
+ wchar_t buf[MAX_PATH + 100];
+ {
+ unsigned len = GetSystemDirectoryW(buf, MAX_PATH + 2);
+ if (len == 0 || len > MAX_PATH)
+ return 0;
+ }
+ {
+ unsigned pos = (unsigned)lstrlenW(buf);
+ if (buf[pos - 1] != '\\')
+ buf[pos++] = '\\';
+ lstrcpyW(buf + pos, L"version.dll");
+ }
+ g_version_dll_hModule = LoadLibraryW(buf);
+ if (!g_version_dll_hModule)
+ return 0;
+ }
+
+ my_GetFileVersionInfoSizeW = (Func_GetFileVersionInfoSizeW) MY_CAST_FUNC GetProcAddress(g_version_dll_hModule,
+ "GetFileVersionInfoSizeW");
+ my_GetFileVersionInfoW = (Func_GetFileVersionInfoW) MY_CAST_FUNC GetProcAddress(g_version_dll_hModule,
+ "GetFileVersionInfoW");
+ my_VerQueryValueW = (Func_VerQueryValueW) MY_CAST_FUNC GetProcAddress(g_version_dll_hModule,
+ "VerQueryValueW");
+
+ if (!my_GetFileVersionInfoSizeW
+ || !my_GetFileVersionInfoW
+ || !my_VerQueryValueW)
+ return 0;
+
+ size = my_GetFileVersionInfoSizeW(s, NULL);
+ if (size == 0)
+ return 0;
+
+ vi = malloc(size);
+ if (!vi)
+ return 0;
+
+ if (my_GetFileVersionInfoW(s, 0, size, vi))
+ {
+ VS_FIXEDFILEINFO *fi = NULL;
+ UINT fiLen = 0;
+ if (my_VerQueryValueW(vi, L"\\", (LPVOID *)&fi, &fiLen))
+ version = fi->dwFileVersionMS;
+ }
+
+ free(vi);
+ return version;
+}
+
+
+static WRes MyCreateDir(LPCWSTR name)
+{
+ return CreateDirectoryW(name, NULL) ? 0 : GetLastError();
+}
+
+#define IS_SEPAR(c) (c == WCHAR_PATH_SEPARATOR)
+#define IS_LETTER_CHAR(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
+#define IS_DRIVE_PATH(s) (IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]))
+
+static int ReverseFind_PathSepar(const wchar_t *s)
+{
+ int separ = -1;
+ int i;
+ for (i = 0;; i++)
+ {
+ wchar_t c = s[i];
+ if (c == 0)
+ return separ;
+ if (IS_SEPAR(c))
+ separ = i;
+ }
+}
+
+static WRes CreateComplexDir(void)
+{
+ WCHAR s[MAX_PATH + 10];
+
+ unsigned prefixSize = 0;
+ WRes wres;
+
+ {
+ size_t len = wcslen(path);
+ if (len > MAX_PATH)
+ return ERROR_INVALID_NAME;
+ wcscpy(s, path);
+ }
+
+ if (IS_DRIVE_PATH(s))
+ prefixSize = 3;
+ else if (IS_SEPAR(s[0]) && IS_SEPAR(s[1]))
+ prefixSize = 2;
+ else
+ return ERROR_INVALID_NAME;
+
+ {
+ DWORD attrib = GetFileAttributesW(s);
+ if (attrib != INVALID_FILE_ATTRIBUTES)
+ return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ? 0 : ERROR_ALREADY_EXISTS;
+ }
+
+ wres = MyCreateDir(s);
+ if (wres == 0 || wres == ERROR_ALREADY_EXISTS)
+ return 0;
+
+ {
+ size_t len = wcslen(s);
+ {
+ const int pos = ReverseFind_PathSepar(s);
+ if (pos < 0)
+ return wres;
+ if ((unsigned)pos < prefixSize)
+ return wres;
+ if ((unsigned)pos == len - 1)
+ {
+ if (len == 1)
+ return 0;
+ s[pos] = 0;
+ len = (unsigned)pos;
+ }
+ }
+
+ for (;;)
+ {
+ int pos;
+ wres = MyCreateDir(s);
+ if (wres == 0)
+ break;
+ if (wres == ERROR_ALREADY_EXISTS)
+ {
+ const DWORD attrib = GetFileAttributesW(s);
+ if (attrib != INVALID_FILE_ATTRIBUTES)
+ if ((attrib & FILE_ATTRIBUTE_DIRECTORY) == 0)
+ return ERROR_ALREADY_EXISTS;
+ break;
+ }
+ pos = ReverseFind_PathSepar(s);
+ if (pos < 0 || pos == 0 || (unsigned)pos < prefixSize)
+ return wres;
+ s[pos] = 0;
+ }
+
+ for (;;)
+ {
+ const size_t pos = wcslen(s);
+ if (pos >= len)
+ return 0;
+ s[pos] = CHAR_PATH_SEPARATOR;
+ wres = MyCreateDir(s);
+ if (wres != 0)
+ return wres;
+ }
+ }
+}
+
+
+static int MyRegistry_QueryString(HKEY hKey, LPCWSTR name, LPWSTR dest)
+{
+ DWORD cnt = MAX_PATH * sizeof(name[0]);
+ DWORD type = 0;
+ const LONG res = RegQueryValueExW(hKey, name, NULL, &type, (LPBYTE)dest, &cnt);
+ if (type != REG_SZ)
+ return False;
+ return res == ERROR_SUCCESS;
+}
+
+static int MyRegistry_QueryString2(HKEY hKey, LPCWSTR keyName, LPCWSTR valName, LPWSTR dest)
+{
+ HKEY key = 0;
+ const LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag, &key);
+ if (res != ERROR_SUCCESS)
+ return False;
+ {
+ const BoolInt res2 = MyRegistry_QueryString(key, valName, dest);
+ RegCloseKey(key);
+ return res2;
+ }
+}
+
+static LONG MyRegistry_SetString(HKEY hKey, LPCWSTR name, LPCWSTR val)
+{
+ return RegSetValueExW(hKey, name, 0, REG_SZ,
+ (const BYTE *)val, (DWORD)(wcslen(val) + 1) * sizeof(val[0]));
+}
+
+static LONG MyRegistry_SetDWORD(HKEY hKey, LPCWSTR name, DWORD val)
+{
+ return RegSetValueExW(hKey, name, 0, REG_DWORD, (const BYTE *)&val, sizeof(DWORD));
+}
+
+
+static LONG MyRegistry_CreateKey(HKEY parentKey, LPCWSTR name, HKEY *destKey)
+{
+ return RegCreateKeyExW(parentKey, name, 0, NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS | k_Reg_WOW_Flag,
+ NULL, destKey, NULL);
+}
+
+static LONG MyRegistry_CreateKeyAndVal(HKEY parentKey, LPCWSTR keyName, LPCWSTR valName, LPCWSTR val)
+{
+ HKEY destKey = 0;
+ LONG res = MyRegistry_CreateKey(parentKey, keyName, &destKey);
+ if (res == ERROR_SUCCESS)
+ {
+ res = MyRegistry_SetString(destKey, valName, val);
+ /* res = */ RegCloseKey(destKey);
+ }
+ return res;
+}
+
+
+#ifdef USE_7ZIP_32_DLL
+
+static LONG MyRegistry_CreateKey_32(HKEY parentKey, LPCWSTR name, HKEY *destKey)
+{
+ return RegCreateKeyExW(parentKey, name, 0, NULL,
+ REG_OPTION_NON_VOLATILE,
+ KEY_ALL_ACCESS | k_Reg_WOW_Flag_32,
+ NULL, destKey, NULL);
+}
+
+static LONG MyRegistry_CreateKeyAndVal_32(HKEY parentKey, LPCWSTR keyName, LPCWSTR valName, LPCWSTR val)
+{
+ HKEY destKey = 0;
+ LONG res = MyRegistry_CreateKey_32(parentKey, keyName, &destKey);
+ if (res == ERROR_SUCCESS)
+ {
+ res = MyRegistry_SetString(destKey, valName, val);
+ /* res = */ RegCloseKey(destKey);
+ }
+ return res;
+}
+
+#endif
+
+
+
+#ifdef UNDER_CE
+ #define kBufSize (1 << 13)
+#else
+ #define kBufSize (1 << 15)
+#endif
+
+#define kSignatureSearchLimit (1 << 22)
+
+static BoolInt FindSignature(CSzFile *stream, UInt64 *resPos)
+{
+ Byte buf[kBufSize];
+ size_t numPrevBytes = 0;
+ *resPos = 0;
+
+ for (;;)
+ {
+ size_t processed, pos;
+ if (*resPos > kSignatureSearchLimit)
+ return False;
+ processed = kBufSize - numPrevBytes;
+ if (File_Read(stream, buf + numPrevBytes, &processed) != 0)
+ return False;
+ processed += numPrevBytes;
+ if (processed < k7zStartHeaderSize ||
+ (processed == k7zStartHeaderSize && numPrevBytes != 0))
+ return False;
+ processed -= k7zStartHeaderSize;
+ for (pos = 0; pos <= processed; pos++)
+ {
+ for (; pos <= processed && buf[pos] != '7'; pos++);
+ if (pos > processed)
+ break;
+ if (memcmp(buf + pos, k7zSignature, k7zSignatureSize) == 0)
+ if (CrcCalc(buf + pos + 12, 20) == GetUi32(buf + pos + 8))
+ {
+ *resPos += pos;
+ return True;
+ }
+ }
+ *resPos += processed;
+ numPrevBytes = k7zStartHeaderSize;
+ memmove(buf, buf + processed, k7zStartHeaderSize);
+ }
+}
+
+static void HexToString(UInt32 val, WCHAR *s)
+{
+ UInt64 v = val;
+ unsigned i;
+ for (i = 1;; i++)
+ {
+ v >>= 4;
+ if (v == 0)
+ break;
+ }
+ s[i] = 0;
+ do
+ {
+ unsigned t = (unsigned)((val & 0xF));
+ val >>= 4;
+ s[--i] = (WCHAR)(unsigned)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
+ }
+ while (i);
+}
+
+
+#ifndef UNDER_CE
+
+static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM lp, LPARAM data)
+{
+ UNUSED_VAR(lp)
+ UNUSED_VAR(data)
+ UNUSED_VAR(hwnd)
+
+ switch (uMsg)
+ {
+ case BFFM_INITIALIZED:
+ {
+ SendMessage(hwnd, BFFM_SETSELECTIONW, TRUE, data);
+ break;
+ }
+ case BFFM_SELCHANGED:
+ {
+ // show selected path for BIF_STATUSTEXT
+ WCHAR dir[MAX_PATH];
+ if (!SHGetPathFromIDListW((LPITEMIDLIST)lp, dir))
+ dir[0] = 0;
+ SendMessage(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)dir);
+ break;
+ }
+ default:
+ break;
+ }
+ return 0;
+}
+
+static BoolInt MyBrowseForFolder(HWND owner, LPCWSTR title, UINT ulFlags,
+ LPCWSTR initialFolder, LPWSTR resultPath)
+{
+ WCHAR displayName[MAX_PATH];
+ BROWSEINFOW browseInfo;
+
+ displayName[0] = 0;
+ browseInfo.hwndOwner = owner;
+ browseInfo.pidlRoot = NULL;
+
+ // there are Unicode/Astring problems in some WinCE SDK ?
+ browseInfo.pszDisplayName = displayName;
+ browseInfo.lpszTitle = title;
+ browseInfo.ulFlags = ulFlags;
+ browseInfo.lpfn = (initialFolder != NULL) ? BrowseCallbackProc : NULL;
+ browseInfo.lParam = (LPARAM)initialFolder;
+ {
+ LPITEMIDLIST idlist = SHBrowseForFolderW(&browseInfo);
+ if (idlist)
+ {
+ SHGetPathFromIDListW(idlist, resultPath);
+ // free idlist
+ // CoTaskMemFree(idlist);
+ return True;
+ }
+ return False;
+ }
+}
+
+#endif
+
+static void NormalizePrefix(WCHAR *s)
+{
+ size_t i = 0;
+
+ for (;; i++)
+ {
+ const wchar_t c = s[i];
+ if (c == 0)
+ break;
+ if (c == '/')
+ s[i] = WCHAR_PATH_SEPARATOR;
+ }
+
+ if (i != 0 && s[i - 1] != WCHAR_PATH_SEPARATOR)
+ {
+ s[i] = WCHAR_PATH_SEPARATOR;
+ s[i + 1] = 0;
+ }
+}
+
+static char MyCharLower_Ascii(char c)
+{
+ if (c >= 'A' && c <= 'Z')
+ return (char)((unsigned char)c + 0x20);
+ return c;
+}
+
+static wchar_t MyWCharLower_Ascii(wchar_t c)
+{
+ if (c >= 'A' && c <= 'Z')
+ return (wchar_t)(c + 0x20);
+ return c;
+}
+
+static LPCWSTR FindSubString(LPCWSTR s1, const char *s2)
+{
+ for (;;)
+ {
+ unsigned i;
+ if (*s1 == 0)
+ return NULL;
+ for (i = 0;; i++)
+ {
+ const char b = s2[i];
+ if (b == 0)
+ return s1;
+ if (MyWCharLower_Ascii(s1[i]) != (Byte)MyCharLower_Ascii(b))
+ {
+ s1++;
+ break;
+ }
+ }
+ }
+}
+
+static void Set7zipPostfix(WCHAR *s)
+{
+ NormalizePrefix(s);
+ if (FindSubString(s, "7-Zip"))
+ return;
+ CatAscii(s, "7-Zip\\");
+}
+
+
+static int Install(void);
+
+static void OnClose(void)
+{
+ if (g_Install_was_Pressed && !g_Finished)
+ {
+ if (MessageBoxW(g_HWND,
+ L"Do you want to cancel " k_7zip_with_Ver L" installation?",
+ k_7zip_with_Ver,
+ MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES)
+ return;
+ }
+ DestroyWindow(g_HWND);
+ g_HWND = NULL;
+}
+
+static
+#ifdef Z7_OLD_WIN_SDK
+ BOOL
+#else
+ INT_PTR
+#endif
+CALLBACK MyDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ // UNUSED_VAR(hwnd)
+ UNUSED_VAR(lParam)
+
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ g_Path_HWND = GetDlgItem(hwnd, IDE_EXTRACT_PATH);
+ g_InfoLine_HWND = GetDlgItem(hwnd, IDT_CUR_FILE);
+ g_Progress_HWND = GetDlgItem(hwnd, IDC_PROGRESS);
+
+ SetWindowTextW(hwnd, k_7zip_Setup);
+ SetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, path);
+
+ ShowWindow(g_Progress_HWND, SW_HIDE);
+ ShowWindow(g_InfoLine_HWND, SW_HIDE);
+
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ {
+ if (g_Finished)
+ {
+ OnClose();
+ break;
+ }
+ if (!g_Install_was_Pressed)
+ {
+ SendMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(hwnd, IDCANCEL), TRUE);
+
+ EnableWindow(g_Path_HWND, FALSE);
+ EnableWindow(GetDlgItem(hwnd, IDB_EXTRACT_SET_PATH), FALSE);
+ EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
+
+ g_Install_was_Pressed = True;
+ return TRUE;
+ }
+ break;
+ }
+
+ case IDCANCEL:
+ {
+ OnClose();
+ break;
+ }
+
+ case IDB_EXTRACT_SET_PATH:
+ {
+ #ifndef UNDER_CE
+
+ WCHAR s[MAX_PATH];
+ WCHAR s2[MAX_PATH];
+ GetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, s, MAX_PATH);
+ if (MyBrowseForFolder(hwnd, L"Select the folder for installation:" ,
+ 0
+ | BIF_NEWDIALOGSTYLE // 5.0 of ?.dll ?
+ | BIF_RETURNONLYFSDIRS
+ // | BIF_STATUSTEXT // doesn't work for BIF_NEWDIALOGSTYLE
+ , s, s2))
+ {
+ Set7zipPostfix(s2);
+ SetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, s2);
+ }
+
+ #endif
+ break;
+ }
+
+ default: return FALSE;
+ }
+ break;
+
+ case WM_CLOSE:
+ OnClose();
+ break;
+ /*
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return TRUE;
+ */
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+
+static LONG SetRegKey_Path2(HKEY parentKey)
+{
+ HKEY destKey = 0;
+ LONG res = MyRegistry_CreateKey(parentKey, k_Reg_Software_7zip, &destKey);
+ if (res == ERROR_SUCCESS)
+ {
+ res = MyRegistry_SetString(destKey, k_Reg_Path32, path);
+ /* res = */ MyRegistry_SetString(destKey, k_Reg_Path, path);
+ /* res = */ RegCloseKey(destKey);
+ }
+ return res;
+}
+
+static void SetRegKey_Path(void)
+{
+ SetRegKey_Path2(HKEY_CURRENT_USER);
+ SetRegKey_Path2(HKEY_LOCAL_MACHINE);
+}
+
+
+static HRESULT CreateShellLink(LPCWSTR srcPath, LPCWSTR targetPath)
+{
+ IShellLinkW* sl;
+
+ // CoInitialize has already been called.
+ HRESULT hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&sl);
+
+ if (SUCCEEDED(hres))
+ {
+ IPersistFile* pf;
+
+ sl->lpVtbl->SetPath(sl, targetPath);
+ // sl->lpVtbl->SetDescription(sl, description);
+ hres = sl->lpVtbl->QueryInterface(sl, &IID_IPersistFile, (LPVOID*)&pf);
+
+ if (SUCCEEDED(hres))
+ {
+ hres = pf->lpVtbl->Save(pf, srcPath, TRUE);
+ pf->lpVtbl->Release(pf);
+ }
+ sl->lpVtbl->Release(sl);
+ }
+
+ return hres;
+}
+
+static void SetShellProgramsGroup(HWND hwndOwner)
+{
+ #ifdef UNDER_CE
+
+ // CpyAscii(link, "\\Program Files\\");
+ UNUSED_VAR(hwndOwner)
+
+ #else
+
+ unsigned i = (g_AllUsers ? 0 : 2);
+
+ for (; i < 3; i++)
+ {
+ BoolInt isOK = True;
+ WCHAR link[MAX_PATH + 40];
+ WCHAR destPath[MAX_PATH + 40];
+
+ link[0] = 0;
+
+ if (SHGetFolderPathW(hwndOwner,
+ i == 1 ? CSIDL_COMMON_PROGRAMS : CSIDL_PROGRAMS,
+ NULL, SHGFP_TYPE_CURRENT, link) != S_OK)
+ continue;
+
+ NormalizePrefix(link);
+ CatAscii(link, k_7zip);
+ // CatAscii(link, "2");
+
+ if (i != 0)
+ MyCreateDir(link);
+
+ NormalizePrefix(link);
+
+ {
+ unsigned baseLen = (unsigned)wcslen(link);
+ unsigned k;
+
+ for (k = 0; k < 2; k++)
+ {
+ CpyAscii(link + baseLen, k == 0 ?
+ "7-Zip File Manager.lnk" :
+ "7-Zip Help.lnk"
+ );
+ wcscpy(destPath, path);
+ CatAscii(destPath, k == 0 ?
+ "7zFM.exe" :
+ "7-zip.chm");
+
+ if (i == 0)
+ DeleteFileW(link);
+ else if (CreateShellLink(link, destPath) != S_OK)
+ isOK = False;
+ }
+ }
+
+ if (i != 0 && isOK)
+ break;
+ }
+
+ #endif
+}
+
+static LPCWSTR const k_Shell_Approved = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved";
+static LPCWSTR const k_7zip_ShellExtension = L"7-Zip Shell Extension";
+
+static void WriteCLSID(void)
+{
+ HKEY destKey;
+ LONG res;
+
+ #ifdef USE_7ZIP_32_DLL
+
+ MyRegistry_CreateKeyAndVal_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip, NULL, k_7zip_ShellExtension);
+
+ res = MyRegistry_CreateKey_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, &destKey);
+
+ if (res == ERROR_SUCCESS)
+ {
+ WCHAR destPath[MAX_PATH + 40];
+ wcscpy(destPath, path);
+ CatAscii(destPath, "7-zip32.dll");
+ /* res = */ MyRegistry_SetString(destKey, NULL, destPath);
+ /* res = */ MyRegistry_SetString(destKey, L"ThreadingModel", L"Apartment");
+ // DeleteRegValue(destKey, L"InprocServer32");
+ /* res = */ RegCloseKey(destKey);
+ }
+
+ #endif
+
+
+ MyRegistry_CreateKeyAndVal(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip, NULL, k_7zip_ShellExtension);
+
+ destKey = 0;
+ res = MyRegistry_CreateKey(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, &destKey);
+
+ if (res == ERROR_SUCCESS)
+ {
+ WCHAR destPath[MAX_PATH + 40];
+ wcscpy(destPath, path);
+ CatAscii(destPath, "7-zip.dll");
+ /* res = */ MyRegistry_SetString(destKey, NULL, destPath);
+ /* res = */ MyRegistry_SetString(destKey, L"ThreadingModel", L"Apartment");
+ // DeleteRegValue(destKey, L"InprocServer32");
+ /* res = */ RegCloseKey(destKey);
+ }
+}
+
+static LPCSTR const k_ShellEx_Items[] =
+{
+ "*\\shellex\\ContextMenuHandlers"
+ , "Directory\\shellex\\ContextMenuHandlers"
+ , "Folder\\shellex\\ContextMenuHandlers"
+ , "Directory\\shellex\\DragDropHandlers"
+ , "Drive\\shellex\\DragDropHandlers"
+};
+
+static void WriteShellEx(void)
+{
+ unsigned i;
+ WCHAR destPath[MAX_PATH + 40];
+
+ for (i = 0; i < Z7_ARRAY_SIZE(k_ShellEx_Items); i++)
+ {
+ CpyAscii(destPath, k_ShellEx_Items[i]);
+ CatAscii(destPath, "\\7-Zip");
+
+ #ifdef USE_7ZIP_32_DLL
+ MyRegistry_CreateKeyAndVal_32(HKEY_CLASSES_ROOT, destPath, NULL, k_7zip_CLSID);
+ #endif
+ MyRegistry_CreateKeyAndVal (HKEY_CLASSES_ROOT, destPath, NULL, k_7zip_CLSID);
+ }
+
+ #ifdef USE_7ZIP_32_DLL
+ MyRegistry_CreateKeyAndVal_32(HKEY_LOCAL_MACHINE, k_Shell_Approved, k_7zip_CLSID, k_7zip_ShellExtension);
+ #endif
+ MyRegistry_CreateKeyAndVal (HKEY_LOCAL_MACHINE, k_Shell_Approved, k_7zip_CLSID, k_7zip_ShellExtension);
+
+
+ wcscpy(destPath, path);
+ CatAscii(destPath, "7zFM.exe");
+
+ {
+ HKEY destKey = 0;
+ LONG res = MyRegistry_CreateKey(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\7zFM.exe", &destKey);
+ if (res == ERROR_SUCCESS)
+ {
+ MyRegistry_SetString(destKey, NULL, destPath);
+ MyRegistry_SetString(destKey, L"Path", path);
+ RegCloseKey(destKey);
+ }
+
+ }
+
+ {
+ HKEY destKey = 0;
+ LONG res = MyRegistry_CreateKey(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\7-Zip", &destKey);
+ if (res == ERROR_SUCCESS)
+ {
+ MyRegistry_SetString(destKey, L"DisplayName", k_7zip_with_Ver_str);
+ MyRegistry_SetString(destKey, L"DisplayVersion", LLL(MY_VERSION_NUMBERS));
+ MyRegistry_SetString(destKey, L"DisplayIcon", destPath);
+ MyRegistry_SetString(destKey, L"InstallLocation", path);
+
+ destPath[0] = '\"';
+ wcscpy(destPath + 1, path);
+ CatAscii(destPath, "Uninstall.exe\"");
+ MyRegistry_SetString(destKey, L"UninstallString", destPath);
+
+ CatAscii(destPath, " /S");
+ MyRegistry_SetString(destKey, L"QuietUninstallString", destPath);
+
+ MyRegistry_SetDWORD(destKey, L"NoModify", 1);
+ MyRegistry_SetDWORD(destKey, L"NoRepair", 1);
+
+ MyRegistry_SetDWORD(destKey, L"EstimatedSize", g_TotalSize >> 10);
+
+ MyRegistry_SetDWORD(destKey, L"VersionMajor", MY_VER_MAJOR);
+ MyRegistry_SetDWORD(destKey, L"VersionMinor", MY_VER_MINOR);
+
+ MyRegistry_SetString(destKey, L"Publisher", LLL(MY_AUTHOR_NAME));
+
+ // MyRegistry_SetString(destKey, L"HelpLink", L"http://www.7-zip.org/support.html");
+ // MyRegistry_SetString(destKey, L"URLInfoAbout", L"http://www.7-zip.org/");
+ // MyRegistry_SetString(destKey, L"URLUpdateInfo", L"http://www.7-zip.org/");
+
+ RegCloseKey(destKey);
+ }
+ }
+}
+
+
+static const wchar_t *GetCmdParam(const wchar_t *s)
+{
+ unsigned pos = 0;
+ BoolInt quoteMode = False;
+ for (;; s++)
+ {
+ wchar_t c = *s;
+ if (c == 0 || (c == L' ' && !quoteMode))
+ break;
+ if (c == L'\"')
+ {
+ quoteMode = !quoteMode;
+ continue;
+ }
+ if (pos >= Z7_ARRAY_SIZE(cmd) - 1)
+ exit(1);
+ cmd[pos++] = c;
+ }
+ cmd[pos] = 0;
+ return s;
+}
+
+
+static void RemoveQuotes(wchar_t *s)
+{
+ const wchar_t *src = s;
+ for (;;)
+ {
+ wchar_t c = *src++;
+ if (c == '\"')
+ continue;
+ *s++ = c;
+ if (c == 0)
+ return;
+ }
+}
+
+// #define IS_LIMIT_CHAR(c) (c == 0 || c == ' ')
+
+
+typedef BOOL (WINAPI *Func_IsWow64Process)(HANDLE, PBOOL);
+
+int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+ #ifdef UNDER_CE
+ LPWSTR
+ #else
+ LPSTR
+ #endif
+ lpCmdLine, int nCmdShow)
+{
+
+ UNUSED_VAR(hPrevInstance)
+ UNUSED_VAR(lpCmdLine)
+ UNUSED_VAR(nCmdShow)
+
+ #ifndef UNDER_CE
+ LoadSecurityDlls();
+ CoInitialize(NULL);
+ #endif
+
+ CrcGenerateTable();
+
+ {
+ const wchar_t *s = GetCommandLineW();
+
+ #ifndef UNDER_CE
+ s = GetCmdParam(s);
+ #endif
+
+ for (;;)
+ {
+ {
+ const wchar_t c = *s;
+ if (c == 0)
+ break;
+ if (c == ' ')
+ {
+ s++;
+ continue;
+ }
+ }
+
+ {
+ const wchar_t *s2 = GetCmdParam(s);
+ BoolInt error = True;
+ if (cmd[0] == '/')
+ {
+ if (cmd[1] == 'S')
+ {
+ if (cmd[2] == 0)
+ {
+ g_SilentMode = True;
+ error = False;
+ }
+ }
+ else if (cmd[1] == 'D' && cmd[2] == '=')
+ {
+ wcscpy(path, cmd + 3);
+ // RemoveQuotes(path);
+ error = False;
+ }
+ }
+ s = s2;
+ if (error && cmdError[0] == 0)
+ wcscpy(cmdError, cmd);
+ }
+ }
+
+ if (cmdError[0] != 0)
+ {
+ if (!g_SilentMode)
+ PrintErrorMessage("Unsupported command:", cmdError);
+ return 1;
+ }
+ }
+
+ #if defined(Z7_64BIT_INSTALLER) && !defined(_WIN64)
+ {
+ BOOL isWow64 = FALSE;
+ const Func_IsWow64Process func_IsWow64Process = (Func_IsWow64Process)
+ MY_CAST_FUNC GetProcAddress(GetModuleHandleW(L"kernel32.dll"),
+ "IsWow64Process");
+
+ if (func_IsWow64Process)
+ func_IsWow64Process(GetCurrentProcess(), &isWow64);
+
+ if (!isWow64)
+ {
+ if (!g_SilentMode)
+ PrintErrorMessage("This installation requires Windows " MY_CPU_NAME, NULL);
+ return 1;
+ }
+ }
+ #endif
+
+
+ if (path[0] == 0)
+ {
+ HKEY key = 0;
+ BoolInt ok = False;
+ const LONG res = RegOpenKeyExW(HKEY_CURRENT_USER, k_Reg_Software_7zip, 0, KEY_READ | k_Reg_WOW_Flag, &key);
+ if (res == ERROR_SUCCESS)
+ {
+ ok = MyRegistry_QueryString(key, k_Reg_Path32, path);
+ // ok = MyRegistry_QueryString(key, k_Reg_Path, path);
+ RegCloseKey(key);
+ }
+
+ // ok = False;
+ if (!ok)
+ {
+ /*
+ #ifdef UNDER_CE
+ CpyAscii(path, "\\Program Files\\");
+ #else
+
+ #ifdef Z7_64BIT_INSTALLER
+ {
+ DWORD ttt = GetEnvironmentVariableW(L"ProgramW6432", path, MAX_PATH);
+ if (ttt == 0 || ttt > MAX_PATH)
+ CpyAscii(path, "C:\\");
+ }
+ #else
+ if (!SHGetSpecialFolderPathW(0, path, CSIDL_PROGRAM_FILES, FALSE))
+ CpyAscii(path, "C:\\");
+ #endif
+ #endif
+ */
+ if (!MyRegistry_QueryString2(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows\\CurrentVersion", L"ProgramFilesDir", path))
+ CpyAscii(path,
+ #ifdef UNDER_CE
+ "\\Program Files\\"
+ #else
+ "C:\\"
+ #endif
+ );
+
+ Set7zipPostfix(path);
+ }
+ }
+
+ NormalizePrefix(path);
+
+ if (g_SilentMode)
+ return Install();
+
+ {
+ int retCode = 1;
+ // INT_PTR res = DialogBox(
+ g_HWND = CreateDialog(
+ hInstance,
+ // GetModuleHandle(NULL),
+ MAKEINTRESOURCE(IDD_INSTALL), NULL, MyDlgProc);
+ if (!g_HWND)
+ return 1;
+
+ {
+ const HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
+ // SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
+ SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon);
+ }
+
+
+ {
+ BOOL bRet;
+ MSG msg;
+
+ // we need messages for all thread windows (including EDITTEXT window in dialog)
+ while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
+ {
+ if (bRet == -1)
+ return retCode;
+ if (!g_HWND)
+ return retCode;
+
+ if (!IsDialogMessage(g_HWND, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ if (!g_HWND)
+ return retCode;
+
+ if (g_Install_was_Pressed && !g_Finished)
+ {
+ retCode = Install();
+ g_Finished = True;
+ if (retCode != 0)
+ break;
+ if (!g_HWND)
+ break;
+ {
+ SetDlgItemTextW(g_HWND, IDOK, L"Close");
+ EnableWindow(GetDlgItem(g_HWND, IDOK), TRUE);
+ EnableWindow(GetDlgItem(g_HWND, IDCANCEL), FALSE);
+ SendMessage(g_HWND, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(g_HWND, IDOK), TRUE);
+ }
+ }
+ }
+
+ if (g_HWND)
+ {
+ DestroyWindow(g_HWND);
+ g_HWND = NULL;
+ }
+ }
+
+ return retCode;
+ }
+}
+
+
+static BoolInt GetErrorMessage(DWORD errorCode, WCHAR *message)
+{
+ LPWSTR msgBuf;
+ if (FormatMessageW(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER
+ | FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, errorCode, 0, (LPWSTR) &msgBuf, 0, NULL) == 0)
+ return False;
+ wcscpy(message, msgBuf);
+ LocalFree(msgBuf);
+ return True;
+}
+
+
+
+static int Install(void)
+{
+ CFileInStream archiveStream;
+ CLookToRead2 lookStream;
+ CSzArEx db;
+
+ SRes res = SZ_OK;
+ WRes winRes = 0;
+ const char *errorMessage = NULL;
+
+ ISzAlloc allocImp;
+ ISzAlloc allocTempImp;
+ WCHAR sfxPath[MAX_PATH + 2];
+
+ int needRebootLevel = 0;
+
+ allocImp.Alloc = SzAlloc;
+ allocImp.Free = SzFree;
+
+ allocTempImp.Alloc = SzAllocTemp;
+ allocTempImp.Free = SzFreeTemp;
+
+ {
+ const DWORD len = GetModuleFileNameW(NULL, sfxPath, MAX_PATH);
+ if (len == 0 || len > MAX_PATH)
+ return 1;
+ }
+
+ winRes = InFile_OpenW(&archiveStream.file, sfxPath);
+
+ if (winRes == 0)
+ {
+ UInt64 pos = 0;
+ if (!FindSignature(&archiveStream.file, &pos))
+ errorMessage = "Can't find 7z archive";
+ else
+ winRes = File_Seek(&archiveStream.file, (Int64 *)&pos, SZ_SEEK_SET);
+ }
+
+ if (winRes != 0)
+ res = SZ_ERROR_FAIL;
+
+ if (errorMessage)
+ res = SZ_ERROR_FAIL;
+
+if (res == SZ_OK)
+{
+ size_t pathLen;
+ if (!g_SilentMode)
+ {
+ GetDlgItemTextW(g_HWND, IDE_EXTRACT_PATH, path, MAX_PATH);
+ }
+
+ FileInStream_CreateVTable(&archiveStream);
+ LookToRead2_CreateVTable(&lookStream, False);
+ lookStream.buf = NULL;
+
+ RemoveQuotes(path);
+ {
+ // Remove post spaces
+ unsigned endPos = 0;
+ unsigned i = 0;
+
+ for (;;)
+ {
+ const wchar_t c = path[i++];
+ if (c == 0)
+ break;
+ if (c != ' ')
+ endPos = i;
+ }
+
+ path[endPos] = 0;
+ if (path[0] == 0)
+ {
+ PrintErrorMessage("Incorrect path", NULL);
+ return 1;
+ }
+ }
+
+ NormalizePrefix(path);
+ winRes = CreateComplexDir();
+
+ if (winRes != 0)
+ res = SZ_ERROR_FAIL;
+
+ pathLen = wcslen(path);
+
+ if (res == SZ_OK)
+ {
+ lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize);
+ if (!lookStream.buf)
+ res = SZ_ERROR_MEM;
+ else
+ {
+ lookStream.bufSize = kInputBufSize;
+ lookStream.realStream = &archiveStream.vt;
+ LookToRead2_INIT(&lookStream)
+ }
+ }
+
+ SzArEx_Init(&db);
+
+ if (res == SZ_OK)
+ {
+ res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp);
+ }
+
+ if (res == SZ_OK)
+ {
+ UInt32 i;
+ UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call, if (!outBuf) */
+ Byte *outBuf = NULL; /* it must be NULL before first call for each new archive. */
+ size_t outBufSize = 0; /* it can have any value before first call, if (!outBuf) */
+
+ g_TotalSize = 0;
+
+ if (!g_SilentMode)
+ {
+ ShowWindow(g_Progress_HWND, SW_SHOW);
+ ShowWindow(g_InfoLine_HWND, SW_SHOW);
+ SendMessage(g_Progress_HWND, PBM_SETRANGE32, 0, db.NumFiles);
+ }
+
+ for (i = 0; i < db.NumFiles; i++)
+ {
+ size_t offset = 0;
+ size_t outSizeProcessed = 0;
+ WCHAR *temp;
+
+ if (!g_SilentMode)
+ {
+ MSG msg;
+
+ // g_HWND
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ if (!IsDialogMessage(g_HWND, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ if (!g_HWND)
+ return 1;
+ }
+
+ // Sleep(10);
+ SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0);
+ }
+
+ {
+ const size_t len = SzArEx_GetFileNameUtf16(&db, i, NULL);
+ if (len >= MAX_PATH)
+ {
+ res = SZ_ERROR_FAIL;
+ break;
+ }
+ }
+
+ temp = path + pathLen;
+
+ SzArEx_GetFileNameUtf16(&db, i, (UInt16 *)temp);
+
+ if (!g_SilentMode)
+ SetWindowTextW(g_InfoLine_HWND, temp);
+
+ {
+ res = SzArEx_Extract(&db, &lookStream.vt, i,
+ &blockIndex, &outBuf, &outBufSize,
+ &offset, &outSizeProcessed,
+ &allocImp, &allocTempImp);
+ if (res != SZ_OK)
+ break;
+ }
+
+ {
+ CSzFile outFile;
+ size_t processedSize;
+ size_t j;
+ // size_t nameStartPos = 0;
+ UInt32 tempIndex = 0;
+ int fileLevel = 1 << 2;
+ WCHAR origPath[MAX_PATH * 2 + 10];
+
+ for (j = 0; temp[j] != 0; j++)
+ {
+ if (temp[j] == '/')
+ {
+ temp[j] = 0;
+ MyCreateDir(path);
+ temp[j] = CHAR_PATH_SEPARATOR;
+ // nameStartPos = j + 1;
+ }
+ }
+
+ if (SzArEx_IsDir(&db, i))
+ {
+ MyCreateDir(path);
+ continue;
+ }
+
+ {
+ // BoolInt skipFile = False;
+
+ wcscpy(origPath, path);
+
+ for (;;)
+ {
+ WRes openRes;
+
+ if (tempIndex != 0)
+ {
+ if (tempIndex > 100)
+ {
+ res = SZ_ERROR_FAIL;
+ break;
+ }
+ wcscpy(path, origPath);
+ CatAscii(path, ".tmp");
+ if (tempIndex > 1)
+ HexToString(tempIndex, path + wcslen(path));
+ if (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES)
+ {
+ tempIndex++;
+ continue;
+ }
+ }
+
+ {
+ SetFileAttributesW(path, 0);
+ openRes = OutFile_OpenW(&outFile, path);
+ if (openRes == 0)
+ break;
+ }
+
+ if (tempIndex != 0)
+ {
+ tempIndex++;
+ continue;
+ }
+
+ if (FindSubString(temp, "7-zip.dll")
+ #ifdef USE_7ZIP_32_DLL
+ || FindSubString(temp, "7-zip32.dll")
+ #endif
+ )
+ {
+ const DWORD ver = GetFileVersion(path);
+ fileLevel = ((ver < Z7_7ZIP_DLL_VER_COMPAT || ver > Z7_7ZIP_CUR_VER) ? 2 : 1);
+ tempIndex++;
+ continue;
+ }
+
+ if (g_SilentMode)
+ {
+ tempIndex++;
+ continue;
+ }
+ {
+ WCHAR message[MAX_PATH * 3 + 100];
+ int mbRes;
+
+ CpyAscii(message, "Can't open file\n");
+ wcscat(message, path);
+ CatAscii(message, "\n");
+
+ GetErrorMessage(openRes, message + wcslen(message));
+
+ mbRes = MessageBoxW(g_HWND, message, L"Error", MB_ICONERROR | MB_ABORTRETRYIGNORE | MB_DEFBUTTON3);
+ if (mbRes == IDABORT)
+ {
+ res = SZ_ERROR_ABORT;
+ tempIndex = 0;
+ break;
+ }
+ if (mbRes == IDIGNORE)
+ {
+ // skipFile = True;
+ tempIndex++;
+ }
+ }
+ }
+
+ if (res != SZ_OK)
+ break;
+
+ /*
+ if (skipFile)
+ continue;
+ */
+ }
+
+ // if (res == SZ_OK)
+ {
+ processedSize = outSizeProcessed;
+ winRes = File_Write(&outFile, outBuf + offset, &processedSize);
+ if (winRes != 0 || processedSize != outSizeProcessed)
+ {
+ errorMessage = "Can't write output file";
+ res = SZ_ERROR_FAIL;
+ }
+
+ g_TotalSize += (DWORD)outSizeProcessed;
+
+ #ifdef USE_WINDOWS_FILE
+ if (SzBitWithVals_Check(&db.MTime, i))
+ {
+ const CNtfsFileTime *t = db.MTime.Vals + i;
+ FILETIME mTime;
+ mTime.dwLowDateTime = t->Low;
+ mTime.dwHighDateTime = t->High;
+ SetFileTime(outFile.handle, NULL, NULL, &mTime);
+ }
+ #endif
+
+ {
+ const WRes winRes2 = File_Close(&outFile);
+ if (res != SZ_OK)
+ break;
+ if (winRes2 != 0)
+ {
+ winRes = winRes2;
+ break;
+ }
+ }
+
+ #ifdef USE_WINDOWS_FILE
+ if (SzBitWithVals_Check(&db.Attribs, i))
+ SetFileAttributesW(path, db.Attribs.Vals[i]);
+ #endif
+ }
+
+ if (tempIndex != 0)
+ {
+ // is it supported at win2000 ?
+ #ifndef UNDER_CE
+ if (!MoveFileExW(path, origPath, MOVEFILE_DELAY_UNTIL_REBOOT | MOVEFILE_REPLACE_EXISTING))
+ {
+ winRes = GetLastError();
+ break;
+ }
+ needRebootLevel |= fileLevel;
+ #endif
+ }
+
+ }
+ }
+
+ ISzAlloc_Free(&allocImp, outBuf);
+
+ if (!g_SilentMode)
+ SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0);
+
+ path[pathLen] = 0;
+
+ if (i == db.NumFiles)
+ {
+ SetRegKey_Path();
+ WriteCLSID();
+ WriteShellEx();
+
+ SetShellProgramsGroup(g_HWND);
+ if (!g_SilentMode)
+ SetWindowTextW(g_InfoLine_HWND, k_7zip_with_Ver L" is installed");
+ }
+ }
+
+ SzArEx_Free(&db, &allocImp);
+
+ ISzAlloc_Free(&allocImp, lookStream.buf);
+
+ File_Close(&archiveStream.file);
+
+}
+
+ if (winRes != 0)
+ res = SZ_ERROR_FAIL;
+
+ if (res == SZ_OK)
+ {
+ if (!g_SilentMode && needRebootLevel > 1)
+ {
+ if (MessageBoxW(g_HWND, L"You must restart your system to complete the installation.\nRestart now?",
+ k_7zip_Setup, MB_YESNO | MB_DEFBUTTON2) == IDYES)
+ {
+ #ifndef UNDER_CE
+
+ // Get a token for this process.
+ HANDLE hToken;
+
+ if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, &hToken))
+ {
+ TOKEN_PRIVILEGES tkp;
+ // Get the LUID for the shutdown privilege.
+ LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &tkp.Privileges[0].Luid);
+ tkp.PrivilegeCount = 1; // one privilege to set
+ tkp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+ // Get the shutdown privilege for this process.
+ AdjustTokenPrivileges(hToken, FALSE, &tkp, 0, (PTOKEN_PRIVILEGES)NULL, 0);
+
+ if (GetLastError() == ERROR_SUCCESS)
+ {
+ if (!ExitWindowsEx(EWX_REBOOT, 0))
+ {
+ }
+ }
+ }
+
+ #endif
+ }
+ }
+
+ if (res == SZ_OK)
+ return 0;
+ }
+
+ if (!g_SilentMode)
+ {
+ if (winRes != 0)
+ {
+ WCHAR m[MAX_PATH + 100];
+ m[0] = 0;
+ GetErrorMessage(winRes, m);
+ PrintErrorMessage(NULL, m);
+ }
+ else
+ {
+ if (res == SZ_ERROR_ABORT)
+ return 2;
+
+ if (res == SZ_ERROR_UNSUPPORTED)
+ errorMessage = "Decoder doesn't support this archive";
+ else if (res == SZ_ERROR_MEM)
+ errorMessage = "Can't allocate required memory";
+ else if (res == SZ_ERROR_CRC)
+ errorMessage = "CRC error";
+ else if (res == SZ_ERROR_DATA)
+ errorMessage = "Data error";
+
+ if (!errorMessage)
+ errorMessage = "ERROR";
+ PrintErrorMessage(errorMessage, NULL);
+ }
+ }
+
+ return 1;
+}
diff --git a/C/Util/7zipInstall/7zipInstall.dsp b/C/Util/7zipInstall/7zipInstall.dsp
new file mode 100644
index 0000000..4c6ea4d
--- /dev/null
+++ b/C/Util/7zipInstall/7zipInstall.dsp
@@ -0,0 +1,248 @@
+# Microsoft Developer Studio Project File - Name="7zipInstall" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=7zipInstall - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "7zipInstall.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "7zipInstall.mak" CFG="7zipInstall - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "7zipInstall - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "7zipInstall - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "7zipInstall - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE2" /D "UNICODE2" /Yu"Precomp.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib version.lib /nologo /subsystem:windows /machine:I386
+
+!ELSEIF "$(CFG)" == "7zipInstall - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE2" /D "UNICODE2" /Yu"Precomp.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib version.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "7zipInstall - Win32 Release"
+# Name "7zipInstall - Win32 Debug"
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\7z.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zAlloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zAlloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zArcIn.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zBuf.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zBuf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zCrc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zCrcOpt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zDec.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zFile.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zFile.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zStream.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zVersion.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Bcj2.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Bcj2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Bra.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Bra.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Bra86.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\BraIA64.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\CpuArch.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\CpuArch.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Delta.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Delta.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\DllSecur.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\DllSecur.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Lzma2Dec.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Lzma2Dec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzmaDec.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzmaDec.h
+# End Source File
+# End Group
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Precomp.c
+# ADD CPP /Yc"Precomp.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\Precomp.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\7zipInstall.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# End Target
+# End Project
diff --git a/C/Util/7zipInstall/7zipInstall.dsw b/C/Util/7zipInstall/7zipInstall.dsw
new file mode 100644
index 0000000..b7db73f
--- /dev/null
+++ b/C/Util/7zipInstall/7zipInstall.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "7zipInstall"=.\7zipInstall.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/C/Util/7zipInstall/7zipInstall.manifest b/C/Util/7zipInstall/7zipInstall.manifest
new file mode 100644
index 0000000..f5c3ae5
--- /dev/null
+++ b/C/Util/7zipInstall/7zipInstall.manifest
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="7-Zip.7-Zip.7zipInstall" type="win32"/>
+<description>7-Zip Installer</description>
+<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"><security><requestedPrivileges>
+ <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
+</requestedPrivileges></security></trustInfo>
+<dependency><dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/></dependentAssembly></dependency>
+<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application>
+<!-- Vista --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+<!-- Win 7 --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+<!-- Win 8 --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+<!-- Win 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+<!-- Win 10 --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+</application></compatibility>
+<asmv3:application><asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+<dpiAware>true</dpiAware></asmv3:windowsSettings></asmv3:application>
+</assembly>
diff --git a/C/Util/7zipInstall/Precomp.c b/C/Util/7zipInstall/Precomp.c
new file mode 100644
index 0000000..01605e3
--- /dev/null
+++ b/C/Util/7zipInstall/Precomp.c
@@ -0,0 +1,4 @@
+/* Precomp.c -- StdAfx
+2013-01-21 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
diff --git a/C/Util/7zipInstall/Precomp.h b/C/Util/7zipInstall/Precomp.h
new file mode 100644
index 0000000..bc8fa21
--- /dev/null
+++ b/C/Util/7zipInstall/Precomp.h
@@ -0,0 +1,14 @@
+/* Precomp.h -- StdAfx
+2023-03-04 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_PRECOMP_H
+#define ZIP7_INC_PRECOMP_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+
+#include "../../Compiler.h"
+#include "../../7zTypes.h"
+
+#endif
diff --git a/C/Util/7zipInstall/makefile b/C/Util/7zipInstall/makefile
new file mode 100644
index 0000000..18e2783
--- /dev/null
+++ b/C/Util/7zipInstall/makefile
@@ -0,0 +1,44 @@
+PROG = 7zipInstall.exe
+MY_FIXED = 1
+
+!IFDEF Z7_64BIT_INSTALLER
+CFLAGS = $(CFLAGS) -DZ7_64BIT_INSTALLER
+!ENDIF
+
+CFLAGS = $(CFLAGS) \
+ -DZ7_LZMA_SIZE_OPT \
+ -DZ7_NO_METHOD_LZMA2 \
+ -DZ7_NO_METHODS_FILTERS \
+ -DZ7_USE_NATIVE_BRANCH_FILTER \
+ -DZ7_EXTRACT_ONLY \
+
+MAIN_OBJS = \
+ $O\7zipInstall.obj \
+
+C_OBJS = \
+ $O\7zAlloc.obj \
+ $O\7zArcIn.obj \
+ $O\7zBuf.obj \
+ $O\7zBuf2.obj \
+ $O\7zCrc.obj \
+ $O\7zCrcOpt.obj \
+ $O\7zFile.obj \
+ $O\7zDec.obj \
+ $O\7zStream.obj \
+ $O\Bcj2.obj \
+ $O\Bra.obj \
+ $O\CpuArch.obj \
+ $O\DllSecur.obj \
+ $O\LzmaDec.obj \
+
+OBJS = \
+ $(MAIN_OBJS) \
+ $(C_OBJS) \
+ $O\resource.res
+
+!include "../../../CPP/Build.mak"
+
+$(MAIN_OBJS): $(*B).c
+ $(COMPL_O1)
+$(C_OBJS): ../../$(*B).c
+ $(COMPL_O1)
diff --git a/C/Util/7zipInstall/resource.h b/C/Util/7zipInstall/resource.h
new file mode 100644
index 0000000..63c6b4c
--- /dev/null
+++ b/C/Util/7zipInstall/resource.h
@@ -0,0 +1,9 @@
+#define IDD_INSTALL 100
+
+#define IDT_EXTRACT_EXTRACT_TO 110
+#define IDE_EXTRACT_PATH 111
+#define IDB_EXTRACT_SET_PATH 112
+#define IDT_CUR_FILE 113
+#define IDC_PROGRESS 114
+
+#define IDI_ICON 1
diff --git a/C/Util/7zipInstall/resource.rc b/C/Util/7zipInstall/resource.rc
new file mode 100644
index 0000000..df6474e
--- /dev/null
+++ b/C/Util/7zipInstall/resource.rc
@@ -0,0 +1,47 @@
+#include <winnt.h>
+#include <WinUser.h>
+#include <CommCtrl.h>
+
+#define USE_COPYRIGHT_CR
+#include "../../7zVersion.rc"
+#include "resource.h"
+
+MY_VERSION_INFO(MY_VFT_APP, "7-Zip Installer", "7zipInstall", "7zipInstall.exe")
+
+1 ICON "7zip.ico"
+
+#define xc 184
+#define yc 96
+
+#define m 8
+#define bxs 64
+#define bys 16
+#define bxsDots 20
+
+#define xs (xc + m + m)
+#define ys (yc + m + m)
+
+#define bx1 (xs - m - bxs)
+#define bx2 (bx1 - m - bxs)
+
+#define by (ys - m - bys)
+
+IDD_INSTALL DIALOG 0, 0, xs, ys
+STYLE DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
+CAPTION "Install 7-Zip"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Destination folder:", IDT_EXTRACT_EXTRACT_TO, m, m, xc, 8
+ EDITTEXT IDE_EXTRACT_PATH, m, 21, xc - bxsDots - 12, 14, ES_AUTOHSCROLL
+ PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, 20, bxsDots, bys, WS_GROUP
+
+ LTEXT "", IDT_CUR_FILE, m, 50, xc, 8
+ CONTROL "", IDC_PROGRESS, "msctls_progress32", WS_BORDER, m, 64, xc, 10
+
+ DEFPUSHBUTTON "&Install", IDOK, bx2, by, bxs, bys, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys
+END
+
+#ifndef UNDER_CE
+1 24 MOVEABLE PURE "7zipInstall.manifest"
+#endif
diff --git a/C/Util/7zipUninstall/7zipUninstall.c b/C/Util/7zipUninstall/7zipUninstall.c
new file mode 100644
index 0000000..8bc18b3
--- /dev/null
+++ b/C/Util/7zipUninstall/7zipUninstall.c
@@ -0,0 +1,1217 @@
+/* 7zipUninstall.c - 7-Zip Uninstaller
+2022-07-15 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+// #define SZ_ERROR_ABORT 100
+
+#include "../../7zWindows.h"
+
+#if defined(_MSC_VER) && _MSC_VER < 1600
+#pragma warning(disable : 4201) // nonstandard extension used : nameless struct/union
+#endif
+
+#ifdef Z7_OLD_WIN_SDK
+struct IShellView;
+#define SHFOLDERAPI EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE
+SHFOLDERAPI SHGetFolderPathW(HWND hwnd, int csidl, HANDLE hToken, DWORD dwFlags, LPWSTR pszPath);
+#define BIF_NEWDIALOGSTYLE 0x0040 // Use the new dialog layout with the ability to resize
+typedef enum {
+ SHGFP_TYPE_CURRENT = 0, // current value for user, verify it exists
+ SHGFP_TYPE_DEFAULT = 1, // default value, may not exist
+} SHGFP_TYPE;
+#endif
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <shlobj.h>
+#else
+#include <ShlObj.h>
+#endif
+
+#include "../../7zVersion.h"
+
+#include "resource.h"
+
+#if (defined(__GNUC__) && (__GNUC__ >= 8)) || defined(__clang__)
+ // #pragma GCC diagnostic ignored "-Wcast-function-type"
+#endif
+
+#if defined(_MSC_VER) && _MSC_VER > 1920
+#define MY_CAST_FUNC (void *)
+// #pragma warning(disable : 4191) // 'type cast': unsafe conversion from 'FARPROC' to 'void (__cdecl *)()'
+#else
+#define MY_CAST_FUNC
+#endif
+
+
+#define LLL_(quote) L##quote
+#define LLL(quote) LLL_(quote)
+
+#define wcscat lstrcatW
+#define wcslen (size_t)lstrlenW
+#define wcscpy lstrcpyW
+
+// static LPCWSTR const k_7zip = L"7-Zip";
+
+// #define Z7_64BIT_INSTALLER 1
+
+#ifdef _WIN64
+ #define Z7_64BIT_INSTALLER 1
+#endif
+
+#define k_7zip_with_Ver_base L"7-Zip " LLL(MY_VERSION)
+
+#ifdef Z7_64BIT_INSTALLER
+
+ // #define USE_7ZIP_32_DLL
+
+ #if defined(_M_ARM64) || defined(_M_ARM)
+ #define k_Postfix L" (arm64)"
+ #else
+ #define k_Postfix L" (x64)"
+ #define USE_7ZIP_32_DLL
+ #endif
+#else
+ #if defined(_M_ARM64) || defined(_M_ARM)
+ #define k_Postfix L" (arm)"
+ #else
+ // #define k_Postfix L" (x86)"
+ #define k_Postfix
+ #endif
+#endif
+
+#define k_7zip_with_Ver k_7zip_with_Ver_base k_Postfix
+
+static LPCWSTR const k_7zip_with_Ver_Uninstall = k_7zip_with_Ver L" Uninstall";
+
+static LPCWSTR const k_Reg_Software_7zip = L"Software\\7-Zip";
+
+static LPCWSTR const k_Reg_Path = L"Path";
+
+static LPCWSTR const k_Reg_Path32 = L"Path"
+ #ifdef Z7_64BIT_INSTALLER
+ L"64"
+ #else
+ L"32"
+ #endif
+ ;
+
+#if defined(Z7_64BIT_INSTALLER) && !defined(_WIN64)
+ #define k_Reg_WOW_Flag KEY_WOW64_64KEY
+#else
+ #define k_Reg_WOW_Flag 0
+#endif
+
+#ifdef _WIN64
+ #define k_Reg_WOW_Flag_32 KEY_WOW64_32KEY
+#else
+ #define k_Reg_WOW_Flag_32 0
+#endif
+
+#define k_7zip_CLSID L"{23170F69-40C1-278A-1000-000100020000}"
+
+static LPCWSTR const k_Reg_CLSID_7zip = L"CLSID\\" k_7zip_CLSID;
+static LPCWSTR const k_Reg_CLSID_7zip_Inproc = L"CLSID\\" k_7zip_CLSID L"\\InprocServer32";
+
+
+#define g_AllUsers True
+
+static BoolInt g_Install_was_Pressed;
+static BoolInt g_Finished;
+static BoolInt g_SilentMode;
+
+static HWND g_HWND;
+static HWND g_Path_HWND;
+static HWND g_InfoLine_HWND;
+static HWND g_Progress_HWND;
+
+// WINADVAPI
+typedef LONG (APIENTRY *Func_RegDeleteKeyExW)(HKEY hKey, LPCWSTR lpSubKey, REGSAM samDesired, DWORD Reserved);
+static Func_RegDeleteKeyExW func_RegDeleteKeyExW;
+
+static WCHAR cmd[MAX_PATH + 4];
+static WCHAR cmdError[MAX_PATH + 4];
+static WCHAR path[MAX_PATH * 2 + 40];
+static WCHAR workDir[MAX_PATH + 10];
+static WCHAR modulePath[MAX_PATH + 10];
+static WCHAR modulePrefix[MAX_PATH + 10];
+static WCHAR tempPath[MAX_PATH * 2 + 40];
+static WCHAR cmdLine[MAX_PATH * 3 + 40];
+static WCHAR copyPath[MAX_PATH * 2 + 40];
+
+static LPCWSTR const kUninstallExe = L"Uninstall.exe";
+
+#define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) - 0x20 : (c)))
+
+
+static void CpyAscii(wchar_t *dest, const char *s)
+{
+ for (;;)
+ {
+ const Byte b = (Byte)*s++;
+ *dest++ = b;
+ if (b == 0)
+ return;
+ }
+}
+
+static void CatAscii(wchar_t *dest, const char *s)
+{
+ dest += wcslen(dest);
+ CpyAscii(dest, s);
+}
+
+static void PrintErrorMessage(const char *s1, const wchar_t *s2)
+{
+ WCHAR m[MAX_PATH + 512];
+ m[0] = 0;
+ CatAscii(m, "ERROR:");
+ if (s1)
+ {
+ CatAscii(m, "\n");
+ CatAscii(m, s1);
+ }
+ if (s2)
+ {
+ CatAscii(m, "\n");
+ wcscat(m, s2);
+ }
+ MessageBoxW(g_HWND, m, k_7zip_with_Ver_Uninstall, MB_ICONERROR | MB_OK);
+}
+
+
+static BoolInt AreStringsEqual_NoCase(const wchar_t *s1, const wchar_t *s2)
+{
+ for (;;)
+ {
+ wchar_t c1 = *s1++;
+ wchar_t c2 = *s2++;
+ if (c1 != c2 && MAKE_CHAR_UPPER(c1) != MAKE_CHAR_UPPER(c2))
+ return False;
+ if (c2 == 0)
+ return True;
+ }
+}
+
+static BoolInt IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2)
+{
+ for (;;)
+ {
+ wchar_t c1;
+ const wchar_t c2 = *s2++;
+ if (c2 == 0)
+ return True;
+ c1 = *s1++;
+ if (c1 != c2 && MAKE_CHAR_UPPER(c1) != MAKE_CHAR_UPPER(c2))
+ return False;
+ }
+}
+
+static void NormalizePrefix(WCHAR *s)
+{
+ const size_t len = wcslen(s);
+ if (len != 0)
+ if (s[len - 1] != WCHAR_PATH_SEPARATOR)
+ {
+ s[len] = WCHAR_PATH_SEPARATOR;
+ s[len + 1] = 0;
+ }
+}
+
+static int MyRegistry_QueryString(HKEY hKey, LPCWSTR name, LPWSTR dest)
+{
+ DWORD cnt = MAX_PATH * sizeof(name[0]);
+ DWORD type = 0;
+ const LONG res = RegQueryValueExW(hKey, name, NULL, &type, (LPBYTE)dest, &cnt);
+ if (type != REG_SZ)
+ return False;
+ return res == ERROR_SUCCESS;
+}
+
+static int MyRegistry_QueryString2(HKEY hKey, LPCWSTR keyName, LPCWSTR valName, LPWSTR dest)
+{
+ HKEY key = 0;
+ const LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag, &key);
+ if (res != ERROR_SUCCESS)
+ return False;
+ {
+ const BoolInt res2 = MyRegistry_QueryString(key, valName, dest);
+ RegCloseKey(key);
+ return res2;
+ }
+}
+
+static LONG MyRegistry_OpenKey_ReadWrite(HKEY parentKey, LPCWSTR name, HKEY *destKey)
+{
+ return RegOpenKeyExW(parentKey, name, 0, KEY_READ | KEY_WRITE | k_Reg_WOW_Flag, destKey);
+}
+
+static LONG MyRegistry_DeleteKey(HKEY parentKey, LPCWSTR name)
+{
+ #if k_Reg_WOW_Flag != 0
+ if (func_RegDeleteKeyExW)
+ return func_RegDeleteKeyExW(parentKey, name, k_Reg_WOW_Flag, 0);
+ return E_FAIL;
+ #else
+ return RegDeleteKeyW(parentKey, name);
+ #endif
+}
+
+#ifdef USE_7ZIP_32_DLL
+
+static int MyRegistry_QueryString2_32(HKEY hKey, LPCWSTR keyName, LPCWSTR valName, LPWSTR dest)
+{
+ HKEY key = 0;
+ const LONG res = RegOpenKeyExW(hKey, keyName, 0, KEY_READ | k_Reg_WOW_Flag_32, &key);
+ if (res != ERROR_SUCCESS)
+ return False;
+ {
+ const BoolInt res2 = MyRegistry_QueryString(key, valName, dest);
+ RegCloseKey(key);
+ return res2;
+ }
+}
+
+static LONG MyRegistry_OpenKey_ReadWrite_32(HKEY parentKey, LPCWSTR name, HKEY *destKey)
+{
+ return RegOpenKeyExW(parentKey, name, 0, KEY_READ | KEY_WRITE | k_Reg_WOW_Flag_32, destKey);
+}
+
+static LONG MyRegistry_DeleteKey_32(HKEY parentKey, LPCWSTR name)
+{
+ #if k_Reg_WOW_Flag_32 != 0
+ if (func_RegDeleteKeyExW)
+ return func_RegDeleteKeyExW(parentKey, name, k_Reg_WOW_Flag_32, 0);
+ return E_FAIL;
+ #else
+ return RegDeleteKeyW(parentKey, name);
+ #endif
+}
+
+#endif
+
+
+
+
+static void MyReg_DeleteVal_Path_if_Equal(HKEY hKey, LPCWSTR name)
+{
+ WCHAR s[MAX_PATH + 10];
+ if (MyRegistry_QueryString(hKey, name, s))
+ {
+ NormalizePrefix(s);
+ if (AreStringsEqual_NoCase(s, path))
+ RegDeleteValueW(hKey, name);
+ }
+}
+
+static void SetRegKey_Path2(HKEY parentKey)
+{
+ HKEY key = 0;
+ const LONG res = MyRegistry_OpenKey_ReadWrite(parentKey, k_Reg_Software_7zip, &key);
+ if (res == ERROR_SUCCESS)
+ {
+ MyReg_DeleteVal_Path_if_Equal(key, k_Reg_Path32);
+ MyReg_DeleteVal_Path_if_Equal(key, k_Reg_Path);
+
+ RegCloseKey(key);
+ // MyRegistry_DeleteKey(parentKey, k_Reg_Software_7zip);
+ }
+}
+
+static void SetRegKey_Path(void)
+{
+ SetRegKey_Path2(HKEY_CURRENT_USER);
+ SetRegKey_Path2(HKEY_LOCAL_MACHINE);
+}
+
+static HRESULT CreateShellLink(LPCWSTR srcPath, LPCWSTR targetPath)
+{
+ IShellLinkW *sl;
+
+ // CoInitialize has already been called.
+ HRESULT hres = CoCreateInstance(&CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, &IID_IShellLinkW, (LPVOID*)&sl);
+
+ if (SUCCEEDED(hres))
+ {
+ IPersistFile *pf;
+
+ hres = sl->lpVtbl->QueryInterface(sl, &IID_IPersistFile, (LPVOID *)&pf);
+
+ if (SUCCEEDED(hres))
+ {
+ WCHAR s[MAX_PATH + 10];
+ hres = pf->lpVtbl->Load(pf, srcPath, TRUE);
+ pf->lpVtbl->Release(pf);
+
+ if (SUCCEEDED(hres))
+ {
+ hres = sl->lpVtbl->GetPath(sl, s, MAX_PATH, NULL, 0); // SLGP_RAWPATH
+ if (!AreStringsEqual_NoCase(s, targetPath))
+ hres = S_FALSE;
+ }
+ }
+
+ sl->lpVtbl->Release(sl);
+ }
+
+ return hres;
+}
+
+static void SetShellProgramsGroup(HWND hwndOwner)
+{
+ #ifdef UNDER_CE
+
+ UNUSED_VAR(hwndOwner)
+
+ #else
+
+ unsigned i = (g_AllUsers ? 1 : 2);
+
+ for (; i < 3; i++)
+ {
+ // BoolInt isOK = True;
+ WCHAR link[MAX_PATH + 40];
+ WCHAR destPath[MAX_PATH + 40];
+
+ link[0] = 0;
+
+ if (SHGetFolderPathW(hwndOwner,
+ i == 1 ? CSIDL_COMMON_PROGRAMS : CSIDL_PROGRAMS,
+ NULL, SHGFP_TYPE_CURRENT, link) != S_OK)
+ continue;
+
+ NormalizePrefix(link);
+ CatAscii(link, "7-Zip\\");
+
+ {
+ const size_t baseLen = wcslen(link);
+ unsigned k;
+ BoolInt needDelete = False;
+
+ for (k = 0; k < 2; k++)
+ {
+ CpyAscii(link + baseLen, k == 0 ?
+ "7-Zip File Manager.lnk" :
+ "7-Zip Help.lnk");
+ wcscpy(destPath, path);
+ CatAscii(destPath, k == 0 ?
+ "7zFM.exe" :
+ "7-zip.chm");
+
+ if (CreateShellLink(link, destPath) == S_OK)
+ {
+ needDelete = True;
+ DeleteFileW(link);
+ }
+ }
+
+ if (needDelete)
+ {
+ link[baseLen] = 0;
+ RemoveDirectoryW(link);
+ }
+ }
+ }
+
+ #endif
+}
+
+
+static LPCSTR const k_ShellEx_Items[] =
+{
+ "*\\shellex\\ContextMenuHandlers"
+ , "Directory\\shellex\\ContextMenuHandlers"
+ , "Folder\\shellex\\ContextMenuHandlers"
+ , "Directory\\shellex\\DragDropHandlers"
+ , "Drive\\shellex\\DragDropHandlers"
+};
+
+static LPCWSTR const k_Shell_Approved = L"Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved";
+
+static LPCWSTR const k_AppPaths_7zFm = L"Software\\Microsoft\\Windows\\CurrentVersion\\App Paths\\7zFM.exe";
+#define k_REG_Uninstall L"Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"
+static LPCWSTR const k_Uninstall_7zip = k_REG_Uninstall L"7-Zip";
+
+
+static void RemoveQuotes(wchar_t *s)
+{
+ const size_t len = wcslen(s);
+ size_t i;
+ if (len == 0 || s[0] != '\"' || s[len - 1] != '\"')
+ return;
+ for (i = 0; i < len; i++)
+ s[i] = s[i + 1];
+ s[len - 2] = 0;
+}
+
+static BoolInt AreEqual_Path_PrefixName(const wchar_t *s, const wchar_t *prefix, const wchar_t *name)
+{
+ if (!IsString1PrefixedByString2_NoCase(s, prefix))
+ return False;
+ return AreStringsEqual_NoCase(s + wcslen(prefix), name);
+}
+
+static void WriteCLSID(void)
+{
+ WCHAR s[MAX_PATH + 30];
+
+ if (MyRegistry_QueryString2(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, NULL, s))
+ {
+ if (AreEqual_Path_PrefixName(s, path, L"7-zip.dll"))
+ {
+ {
+ const LONG res = MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc);
+ if (res == ERROR_SUCCESS)
+ MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip);
+ }
+
+ {
+ unsigned i;
+ for (i = 0; i < Z7_ARRAY_SIZE(k_ShellEx_Items); i++)
+ {
+ WCHAR destPath[MAX_PATH];
+ CpyAscii(destPath, k_ShellEx_Items[i]);
+ CatAscii(destPath, "\\7-Zip");
+
+ MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, destPath);
+ }
+ }
+
+ {
+ HKEY destKey = 0;
+ const LONG res = MyRegistry_OpenKey_ReadWrite(HKEY_LOCAL_MACHINE, k_Shell_Approved, &destKey);
+ if (res == ERROR_SUCCESS)
+ {
+ RegDeleteValueW(destKey, k_7zip_CLSID);
+ /* res = */ RegCloseKey(destKey);
+ }
+ }
+ }
+ }
+
+
+ #ifdef USE_7ZIP_32_DLL
+
+ if (MyRegistry_QueryString2_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc, NULL, s))
+ {
+ if (AreEqual_Path_PrefixName(s, path, L"7-zip32.dll"))
+ {
+ {
+ const LONG res = MyRegistry_DeleteKey_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip_Inproc);
+ if (res == ERROR_SUCCESS)
+ MyRegistry_DeleteKey_32(HKEY_CLASSES_ROOT, k_Reg_CLSID_7zip);
+ }
+
+ {
+ unsigned i;
+ for (i = 0; i < Z7_ARRAY_SIZE(k_ShellEx_Items); i++)
+ {
+ WCHAR destPath[MAX_PATH];
+ CpyAscii(destPath, k_ShellEx_Items[i]);
+ CatAscii(destPath, "\\7-Zip");
+
+ MyRegistry_DeleteKey_32(HKEY_CLASSES_ROOT, destPath);
+ }
+ }
+
+ {
+ HKEY destKey = 0;
+ const LONG res = MyRegistry_OpenKey_ReadWrite_32(HKEY_LOCAL_MACHINE, k_Shell_Approved, &destKey);
+ if (res == ERROR_SUCCESS)
+ {
+ RegDeleteValueW(destKey, k_7zip_CLSID);
+ /* res = */ RegCloseKey(destKey);
+ }
+ }
+ }
+ }
+
+ #endif
+
+
+ if (MyRegistry_QueryString2(HKEY_LOCAL_MACHINE, k_AppPaths_7zFm, NULL, s))
+ {
+ // RemoveQuotes(s);
+ if (AreEqual_Path_PrefixName(s, path, L"7zFM.exe"))
+ MyRegistry_DeleteKey(HKEY_LOCAL_MACHINE, k_AppPaths_7zFm);
+ }
+
+ if (MyRegistry_QueryString2(HKEY_LOCAL_MACHINE, k_Uninstall_7zip, L"UninstallString", s))
+ {
+ RemoveQuotes(s);
+ if (AreEqual_Path_PrefixName(s, path, kUninstallExe))
+ MyRegistry_DeleteKey(HKEY_LOCAL_MACHINE, k_Uninstall_7zip);
+ }
+}
+
+
+static const wchar_t *GetCmdParam(const wchar_t *s)
+{
+ unsigned pos = 0;
+ BoolInt quoteMode = False;
+ for (;; s++)
+ {
+ const wchar_t c = *s;
+ if (c == 0 || (c == L' ' && !quoteMode))
+ break;
+ if (c == L'\"')
+ {
+ quoteMode = !quoteMode;
+ continue;
+ }
+ if (pos >= Z7_ARRAY_SIZE(cmd) - 1)
+ exit(1);
+ cmd[pos++] = c;
+ }
+ cmd[pos] = 0;
+ return s;
+}
+
+/*
+static void RemoveQuotes(wchar_t *s)
+{
+ const wchar_t *src = s;
+ for (;;)
+ {
+ wchar_t c = *src++;
+ if (c == '\"')
+ continue;
+ *s++ = c;
+ if (c == 0)
+ return;
+ }
+}
+*/
+
+static BoolInt DoesFileOrDirExist(void)
+{
+ return (GetFileAttributesW(path) != INVALID_FILE_ATTRIBUTES);
+}
+
+static BOOL RemoveFileAfterReboot2(const WCHAR *s)
+{
+ #ifndef UNDER_CE
+ return MoveFileExW(s, NULL, MOVEFILE_DELAY_UNTIL_REBOOT);
+ #else
+ UNUSED_VAR(s)
+ return TRUE;
+ #endif
+}
+
+static BOOL RemoveFileAfterReboot(void)
+{
+ return RemoveFileAfterReboot2(path);
+}
+
+// #define IS_LIMIT_CHAR(c) (c == 0 || c == ' ')
+
+static BoolInt IsThereSpace(const wchar_t *s)
+{
+ for (;;)
+ {
+ const wchar_t c = *s++;
+ if (c == 0)
+ return False;
+ if (c == ' ')
+ return True;
+ }
+}
+
+static void AddPathParam(wchar_t *dest, const wchar_t *src)
+{
+ const BoolInt needQuote = IsThereSpace(src);
+ if (needQuote)
+ CatAscii(dest, "\"");
+ wcscat(dest, src);
+ if (needQuote)
+ CatAscii(dest, "\"");
+}
+
+
+
+static BoolInt GetErrorMessage(DWORD errorCode, WCHAR *message)
+{
+ LPWSTR msgBuf;
+ if (FormatMessageW(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER
+ | FORMAT_MESSAGE_FROM_SYSTEM
+ | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, errorCode, 0, (LPWSTR) &msgBuf, 0, NULL) == 0)
+ return False;
+ wcscpy(message, msgBuf);
+ LocalFree(msgBuf);
+ return True;
+}
+
+static BOOL RemoveDir(void)
+{
+ const DWORD attrib = GetFileAttributesW(path);
+ if (attrib == INVALID_FILE_ATTRIBUTES)
+ return TRUE;
+ if (RemoveDirectoryW(path))
+ return TRUE;
+ return RemoveFileAfterReboot();
+}
+
+
+
+
+
+#define k_Lang "Lang"
+
+// NUM_LANG_TXT_FILES files are placed before en.ttt
+#define NUM_LANG_TXT_FILES 92
+
+#ifdef USE_7ZIP_32_DLL
+ #define NUM_EXTRA_FILES_64BIT 1
+#else
+ #define NUM_EXTRA_FILES_64BIT 0
+#endif
+
+#define NUM_FILES (NUM_LANG_TXT_FILES + 1 + 13 + NUM_EXTRA_FILES_64BIT)
+
+static const char * const k_Names =
+ "af an ar ast az ba be bg bn br ca co cs cy da de el eo es et eu ext"
+ " fa fi fr fur fy ga gl gu he hi hr hu hy id io is it ja ka kaa kab kk ko ku ku-ckb ky"
+ " lij lt lv mk mn mng mng2 mr ms nb ne nl nn pa-in pl ps pt pt-br ro ru"
+ " sa si sk sl sq sr-spc sr-spl sv sw ta tg th tk tr tt ug uk uz uz-cyrl va vi yo zh-cn zh-tw"
+ " en.ttt"
+ " descript.ion"
+ " History.txt"
+ " License.txt"
+ " readme.txt"
+ " 7-zip.chm"
+ " 7z.sfx"
+ " 7zCon.sfx"
+ " 7z.exe"
+ " 7zG.exe"
+ " 7z.dll"
+ " 7zFM.exe"
+ #ifdef USE_7ZIP_32_DLL
+ " 7-zip32.dll"
+ #endif
+ " 7-zip.dll"
+ " Uninstall.exe";
+
+
+
+static int Install(void)
+{
+ SRes res = SZ_OK;
+ WRes winRes = 0;
+
+ // BoolInt needReboot = False;
+ const size_t pathLen = wcslen(path);
+
+ if (!g_SilentMode)
+ {
+ ShowWindow(g_Progress_HWND, SW_SHOW);
+ ShowWindow(g_InfoLine_HWND, SW_SHOW);
+ SendMessage(g_Progress_HWND, PBM_SETRANGE32, 0, NUM_FILES);
+ }
+
+ {
+ unsigned i;
+ const char *curName = k_Names;
+
+ for (i = 0; *curName != 0; i++)
+ {
+ WCHAR *temp;
+
+ if (!g_SilentMode)
+ {
+ MSG msg;
+
+ // g_HWND
+ while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
+ {
+ if (!IsDialogMessage(g_HWND, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ if (!g_HWND)
+ return 1;
+ }
+
+ // Sleep(1);
+ SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0);
+ }
+
+ path[pathLen] = 0;
+ temp = path + pathLen;
+
+ if (i <= NUM_LANG_TXT_FILES)
+ CpyAscii(temp, k_Lang "\\");
+
+ {
+ WCHAR *dest = temp + wcslen(temp);
+
+ for (;;)
+ {
+ const char c = *curName;
+ if (c == 0)
+ break;
+ curName++;
+ if (c == ' ')
+ break;
+ *dest++ = (Byte)c;
+ }
+
+ *dest = 0;
+ }
+
+ if (i < NUM_LANG_TXT_FILES)
+ CatAscii(temp, ".txt");
+
+ if (!g_SilentMode)
+ SetWindowTextW(g_InfoLine_HWND, temp);
+
+ {
+ const DWORD attrib = GetFileAttributesW(path);
+ if (attrib == INVALID_FILE_ATTRIBUTES)
+ continue;
+ if (attrib & FILE_ATTRIBUTE_READONLY)
+ SetFileAttributesW(path, 0);
+ if (!DeleteFileW(path))
+ {
+ if (!RemoveFileAfterReboot())
+ {
+ winRes = GetLastError();
+ }
+ /*
+ else
+ needReboot = True;
+ */
+ }
+ }
+ }
+
+ CpyAscii(path + pathLen, k_Lang);
+ RemoveDir();
+
+ path[pathLen] = 0;
+ RemoveDir();
+
+ if (!g_SilentMode)
+ SendMessage(g_Progress_HWND, PBM_SETPOS, i, 0);
+
+ if (*curName == 0)
+ {
+ SetRegKey_Path();
+ WriteCLSID();
+ SetShellProgramsGroup(g_HWND);
+ if (!g_SilentMode)
+ SetWindowTextW(g_InfoLine_HWND, k_7zip_with_Ver L" is uninstalled");
+ }
+ }
+
+ if (winRes != 0)
+ res = SZ_ERROR_FAIL;
+
+ if (res == SZ_OK)
+ {
+ // if (!g_SilentMode && needReboot);
+ return 0;
+ }
+
+ if (!g_SilentMode)
+ {
+ WCHAR m[MAX_PATH + 100];
+ m[0] = 0;
+ if (winRes == 0 || !GetErrorMessage(winRes, m))
+ CpyAscii(m, "ERROR");
+ PrintErrorMessage("System ERROR:", m);
+ }
+
+ return 1;
+}
+
+
+static void OnClose(void)
+{
+ if (g_Install_was_Pressed && !g_Finished)
+ {
+ if (MessageBoxW(g_HWND,
+ L"Do you want to cancel uninstallation?",
+ k_7zip_with_Ver_Uninstall,
+ MB_ICONQUESTION | MB_YESNO | MB_DEFBUTTON2) != IDYES)
+ return;
+ }
+ DestroyWindow(g_HWND);
+ g_HWND = NULL;
+}
+
+static
+#ifdef Z7_OLD_WIN_SDK
+ BOOL
+#else
+ INT_PTR
+#endif
+CALLBACK MyDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ UNUSED_VAR(lParam)
+
+ switch (message)
+ {
+ case WM_INITDIALOG:
+ g_Path_HWND = GetDlgItem(hwnd, IDE_EXTRACT_PATH);
+ g_InfoLine_HWND = GetDlgItem(hwnd, IDT_CUR_FILE);
+ g_Progress_HWND = GetDlgItem(hwnd, IDC_PROGRESS);
+
+ SetWindowTextW(hwnd, k_7zip_with_Ver_Uninstall);
+ SetDlgItemTextW(hwnd, IDE_EXTRACT_PATH, path);
+
+ ShowWindow(g_Progress_HWND, SW_HIDE);
+ ShowWindow(g_InfoLine_HWND, SW_HIDE);
+
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam))
+ {
+ case IDOK:
+ {
+ if (g_Finished)
+ {
+ OnClose();
+ break;
+ }
+ if (!g_Install_was_Pressed)
+ {
+ SendMessage(hwnd, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(hwnd, IDCANCEL), TRUE);
+
+ EnableWindow(g_Path_HWND, FALSE);
+ EnableWindow(GetDlgItem(hwnd, IDOK), FALSE);
+
+ g_Install_was_Pressed = True;
+ return TRUE;
+ }
+ break;
+ }
+
+ case IDCANCEL:
+ {
+ OnClose();
+ break;
+ }
+
+ default: return FALSE;
+ }
+ break;
+
+ case WM_CLOSE:
+ OnClose();
+ break;
+ /*
+ case WM_DESTROY:
+ PostQuitMessage(0);
+ return TRUE;
+ */
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+ #ifdef UNDER_CE
+ LPWSTR
+ #else
+ LPSTR
+ #endif
+ lpCmdLine, int nCmdShow)
+{
+ const wchar_t *cmdParams;
+ BoolInt useTemp = True;
+
+ UNUSED_VAR(hPrevInstance)
+ UNUSED_VAR(lpCmdLine)
+ UNUSED_VAR(nCmdShow)
+
+ #ifndef UNDER_CE
+ CoInitialize(NULL);
+ #endif
+
+ #ifndef UNDER_CE
+ func_RegDeleteKeyExW = (Func_RegDeleteKeyExW) MY_CAST_FUNC
+ GetProcAddress(GetModuleHandleW(L"advapi32.dll"), "RegDeleteKeyExW");
+ #endif
+
+ {
+ const wchar_t *s = GetCommandLineW();
+
+ #ifndef UNDER_CE
+ s = GetCmdParam(s);
+ #endif
+
+ cmdParams = s;
+
+ for (;;)
+ {
+ {
+ wchar_t c = *s;
+ if (c == 0)
+ break;
+ if (c == ' ')
+ {
+ s++;
+ continue;
+ }
+ }
+
+ {
+ const wchar_t *s2 = GetCmdParam(s);
+ BoolInt error = True;
+ if (cmd[0] == '/')
+ {
+ if (cmd[1] == 'S')
+ {
+ if (cmd[2] == 0)
+ {
+ g_SilentMode = True;
+ error = False;
+ }
+ }
+ else if (cmd[1] == 'N')
+ {
+ if (cmd[2] == 0)
+ {
+ useTemp = False;
+ error = False;
+ }
+ }
+ else if (cmd[1] == 'D' && cmd[2] == '=')
+ {
+ wcscpy(workDir, cmd + 3);
+ // RemoveQuotes(workDir);
+ useTemp = False;
+ error = False;
+ }
+ }
+ s = s2;
+ if (error && cmdError[0] == 0)
+ wcscpy(cmdError, cmd);
+ }
+ }
+
+ if (cmdError[0] != 0)
+ {
+ if (!g_SilentMode)
+ PrintErrorMessage("Unsupported command:", cmdError);
+ return 1;
+ }
+ }
+
+ {
+ wchar_t *name;
+ const DWORD len = GetModuleFileNameW(NULL, modulePath, MAX_PATH);
+ if (len == 0 || len > MAX_PATH)
+ return 1;
+
+ name = NULL;
+ wcscpy(modulePrefix, modulePath);
+
+ {
+ wchar_t *s = modulePrefix;
+ for (;;)
+ {
+ const wchar_t c = *s++;
+ if (c == 0)
+ break;
+ if (c == WCHAR_PATH_SEPARATOR)
+ name = s;
+ }
+ }
+
+ if (!name)
+ return 1;
+
+ if (!AreStringsEqual_NoCase(name, kUninstallExe))
+ useTemp = False;
+
+ *name = 0; // keep only prefix for modulePrefix
+ }
+
+
+ if (useTemp)
+ {
+ DWORD winRes = GetTempPathW(MAX_PATH, path);
+
+ // GetTempPath: the returned string ends with a backslash
+ /*
+ {
+ WCHAR s[MAX_PATH + 1];
+ wcscpy(s, path);
+ GetLongPathNameW(s, path, MAX_PATH);
+ }
+ */
+
+ if (winRes != 0 && winRes <= MAX_PATH + 1
+ && !IsString1PrefixedByString2_NoCase(modulePrefix, path))
+ {
+ unsigned i;
+ DWORD d;
+
+ const size_t pathLen = wcslen(path);
+ d = (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId();
+
+ for (i = 0; i < 100; i++, d += GetTickCount())
+ {
+ CpyAscii(path + pathLen, "7z");
+
+ {
+ wchar_t *s = path + wcslen(path);
+ UInt32 value = d;
+ unsigned k;
+ for (k = 0; k < 8; k++)
+ {
+ const unsigned t = value & 0xF;
+ value >>= 4;
+ s[7 - k] = (wchar_t)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
+ }
+ s[k] = 0;
+ }
+
+ if (DoesFileOrDirExist())
+ continue;
+ if (CreateDirectoryW(path, NULL))
+ {
+ CatAscii(path, STRING_PATH_SEPARATOR);
+ wcscpy(tempPath, path);
+ break;
+ }
+ if (GetLastError() != ERROR_ALREADY_EXISTS)
+ break;
+ }
+
+ if (tempPath[0] != 0)
+ {
+ wcscpy(copyPath, tempPath);
+ CatAscii(copyPath, "Uninst.exe"); // we need not "Uninstall.exe" here
+
+ if (CopyFileW(modulePath, copyPath, TRUE))
+ {
+ RemoveFileAfterReboot2(copyPath);
+ RemoveFileAfterReboot2(tempPath);
+
+ {
+ STARTUPINFOW si;
+ PROCESS_INFORMATION pi;
+ cmdLine[0] = 0;
+
+ // maybe CreateProcess supports path with spaces even without quotes.
+ AddPathParam(cmdLine, copyPath);
+ CatAscii(cmdLine, " /N /D=");
+ AddPathParam(cmdLine, modulePrefix);
+
+ if (cmdParams[0] != 0 && wcslen(cmdParams) < MAX_PATH * 2 + 10)
+ wcscat(cmdLine, cmdParams);
+
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+
+ if (CreateProcessW(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, tempPath, &si, &pi))
+ {
+ CloseHandle(pi.hThread);
+ if (pi.hProcess)
+ {
+ CloseHandle(pi.hProcess);
+ return 0;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ wcscpy(path, modulePrefix);
+
+ if (workDir[0] != 0)
+ {
+ wcscpy(path, workDir);
+ NormalizePrefix(path);
+ }
+
+ /*
+ if (path[0] == 0)
+ {
+ HKEY key = 0;
+ BoolInt ok = False;
+ LONG res = RegOpenKeyExW(HKEY_CURRENT_USER, k_Reg_Software_7zip, 0, KEY_READ | k_Reg_WOW_Flag, &key);
+ if (res == ERROR_SUCCESS)
+ {
+ ok = MyRegistry_QueryString(key, k_Reg_Path32, path);
+ // ok = MyRegistry_QueryString(key, k_Reg_Path, path);
+ RegCloseKey(key);
+ }
+ }
+ */
+
+
+ if (g_SilentMode)
+ return Install();
+
+ {
+ int retCode = 1;
+ g_HWND = CreateDialog(
+ hInstance,
+ // GetModuleHandle(NULL),
+ MAKEINTRESOURCE(IDD_INSTALL), NULL, MyDlgProc);
+ if (!g_HWND)
+ return 1;
+
+ {
+ const HICON hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON));
+ // SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_SMALL, (LPARAM)hIcon);
+ SendMessage(g_HWND, WM_SETICON, (WPARAM)ICON_BIG, (LPARAM)hIcon);
+ }
+
+ {
+ BOOL bRet;
+ MSG msg;
+
+ while ((bRet = GetMessage(&msg, NULL, 0, 0)) != 0)
+ {
+ if (bRet == -1)
+ return retCode;
+ if (!g_HWND)
+ return retCode;
+
+ if (!IsDialogMessage(g_HWND, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ if (!g_HWND)
+ return retCode;
+
+ if (g_Install_was_Pressed && !g_Finished)
+ {
+ retCode = Install();
+ g_Finished = True;
+ if (retCode != 0)
+ break;
+ if (!g_HWND)
+ break;
+ {
+ SetDlgItemTextW(g_HWND, IDOK, L"Close");
+ EnableWindow(GetDlgItem(g_HWND, IDOK), TRUE);
+ EnableWindow(GetDlgItem(g_HWND, IDCANCEL), FALSE);
+ SendMessage(g_HWND, WM_NEXTDLGCTL, (WPARAM)(void *)GetDlgItem(g_HWND, IDOK), TRUE);
+ }
+ }
+ }
+
+ if (g_HWND)
+ {
+ DestroyWindow(g_HWND);
+ g_HWND = NULL;
+ }
+ }
+
+ return retCode;
+ }
+}
diff --git a/C/Util/7zipUninstall/7zipUninstall.dsp b/C/Util/7zipUninstall/7zipUninstall.dsp
new file mode 100644
index 0000000..bb7473f
--- /dev/null
+++ b/C/Util/7zipUninstall/7zipUninstall.dsp
@@ -0,0 +1,132 @@
+# Microsoft Developer Studio Project File - Name="7zipUninstall" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=7zipUninstall - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "7zipUninstall.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "7zipUninstall.mak" CFG="7zipUninstall - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "7zipUninstall - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "7zipUninstall - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "7zipUninstall - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE2" /D "UNICODE2" /FAcs /Yu"Precomp.h" /FD /GF /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"Release/Uninstall.exe"
+
+!ELSEIF "$(CFG)" == "7zipUninstall - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE2" /D "UNICODE2" /Yu"Precomp.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"Debug/Uninstall.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "7zipUninstall - Win32 Release"
+# Name "7zipUninstall - Win32 Debug"
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zVersion.h
+# End Source File
+# End Group
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Precomp.c
+# ADD CPP /Yc"Precomp.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\Precomp.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\7zipUninstall.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# End Target
+# End Project
diff --git a/C/Util/7zipUninstall/7zipUninstall.dsw b/C/Util/7zipUninstall/7zipUninstall.dsw
new file mode 100644
index 0000000..2873eda
--- /dev/null
+++ b/C/Util/7zipUninstall/7zipUninstall.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "7zipUninstall"=.\7zipUninstall.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/C/Util/7zipUninstall/7zipUninstall.ico b/C/Util/7zipUninstall/7zipUninstall.ico
new file mode 100644
index 0000000..19eb20c
--- /dev/null
+++ b/C/Util/7zipUninstall/7zipUninstall.ico
Binary files differ
diff --git a/C/Util/7zipUninstall/7zipUninstall.manifest b/C/Util/7zipUninstall/7zipUninstall.manifest
new file mode 100644
index 0000000..a601443
--- /dev/null
+++ b/C/Util/7zipUninstall/7zipUninstall.manifest
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="7-Zip.7-Zip.Uninstall" type="win32"/>
+<description>7-Zip Uninstaller</description>
+<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2"><security><requestedPrivileges>
+ <requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
+</requestedPrivileges></security></trustInfo>
+<dependency><dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/></dependentAssembly></dependency>
+<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application>
+<!-- Vista --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+<!-- Win 7 --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+<!-- Win 8 --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+<!-- Win 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+<!-- Win 10 --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+</application></compatibility>
+<asmv3:application><asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+<dpiAware>true</dpiAware></asmv3:windowsSettings></asmv3:application>
+</assembly>
diff --git a/C/Util/7zipUninstall/Precomp.c b/C/Util/7zipUninstall/Precomp.c
new file mode 100644
index 0000000..01605e3
--- /dev/null
+++ b/C/Util/7zipUninstall/Precomp.c
@@ -0,0 +1,4 @@
+/* Precomp.c -- StdAfx
+2013-01-21 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
diff --git a/C/Util/7zipUninstall/Precomp.h b/C/Util/7zipUninstall/Precomp.h
new file mode 100644
index 0000000..bc8fa21
--- /dev/null
+++ b/C/Util/7zipUninstall/Precomp.h
@@ -0,0 +1,14 @@
+/* Precomp.h -- StdAfx
+2023-03-04 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_PRECOMP_H
+#define ZIP7_INC_PRECOMP_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+
+#include "../../Compiler.h"
+#include "../../7zTypes.h"
+
+#endif
diff --git a/C/Util/7zipUninstall/makefile b/C/Util/7zipUninstall/makefile
new file mode 100644
index 0000000..9d8aafc
--- /dev/null
+++ b/C/Util/7zipUninstall/makefile
@@ -0,0 +1,18 @@
+PROG = 7zipUninstall.exe
+MY_FIXED = 1
+
+!IFDEF Z7_64BIT_INSTALLER
+CFLAGS = $(CFLAGS) -DZ7_64BIT_INSTALLER
+!ENDIF
+
+MAIN_OBJS = \
+ $O\7zipUninstall.obj \
+
+OBJS = \
+ $(MAIN_OBJS) \
+ $O\resource.res
+
+!include "../../../CPP/Build.mak"
+
+$(MAIN_OBJS): $(*B).c
+ $(COMPL_O1)
diff --git a/C/Util/7zipUninstall/resource.h b/C/Util/7zipUninstall/resource.h
new file mode 100644
index 0000000..b5c33ff
--- /dev/null
+++ b/C/Util/7zipUninstall/resource.h
@@ -0,0 +1,9 @@
+#define IDD_INSTALL 100
+
+#define IDT_EXTRACT_EXTRACT_TO 110
+#define IDE_EXTRACT_PATH 111
+
+#define IDT_CUR_FILE 113
+#define IDC_PROGRESS 114
+
+#define IDI_ICON 1
diff --git a/C/Util/7zipUninstall/resource.rc b/C/Util/7zipUninstall/resource.rc
new file mode 100644
index 0000000..00bdcc0
--- /dev/null
+++ b/C/Util/7zipUninstall/resource.rc
@@ -0,0 +1,47 @@
+#include <winnt.h>
+#include <WinUser.h>
+#include <CommCtrl.h>
+
+#define USE_COPYRIGHT_CR
+#include "../../7zVersion.rc"
+#include "resource.h"
+
+MY_VERSION_INFO(MY_VFT_APP, "7-Zip Uninstaller", "Uninstall", "Uninstall.exe")
+
+1 ICON "7zipUninstall.ico"
+
+#define xc 184
+#define yc 96
+
+#define m 8
+#define bxs 64
+#define bys 16
+
+
+#define xs (xc + m + m)
+#define ys (yc + m + m)
+
+#define bx1 (xs - m - bxs)
+#define bx2 (bx1 - m - bxs)
+
+#define by (ys - m - bys)
+
+IDD_INSTALL DIALOG 0, 0, xs, ys
+STYLE DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU | WS_VISIBLE
+CAPTION "Uninstall 7-Zip"
+FONT 8, "MS Shell Dlg"
+BEGIN
+ LTEXT "Uninstall from:", IDT_EXTRACT_EXTRACT_TO, m, m, xc, 8
+ EDITTEXT IDE_EXTRACT_PATH, m, 21, xc, 14, ES_AUTOHSCROLL | WS_DISABLED
+
+
+ LTEXT "", IDT_CUR_FILE, m, 50, xc, 8
+ CONTROL "", IDC_PROGRESS, "msctls_progress32", WS_BORDER, m, 64, xc, 10
+
+ DEFPUSHBUTTON "&Uninstall", IDOK, bx2, by, bxs, bys, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys
+END
+
+#ifndef UNDER_CE
+1 24 MOVEABLE PURE "7zipUninstall.manifest"
+#endif
diff --git a/C/Util/Lzma/LzmaUtil.c b/C/Util/Lzma/LzmaUtil.c
index 82130e8..b9b974b 100644
--- a/C/Util/Lzma/LzmaUtil.c
+++ b/C/Util/Lzma/LzmaUtil.c
@@ -1,258 +1,313 @@
-/* LzmaUtil.c -- Test application for LZMA compression
-2018-07-04 : Igor Pavlov : Public domain */
-
-#include "../../Precomp.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "../../CpuArch.h"
-
-#include "../../Alloc.h"
-#include "../../7zFile.h"
-#include "../../7zVersion.h"
-#include "../../LzmaDec.h"
-#include "../../LzmaEnc.h"
-
-static const char * const kCantReadMessage = "Can not read input file";
-static const char * const kCantWriteMessage = "Can not write output file";
-static const char * const kCantAllocateMessage = "Can not allocate memory";
-static const char * const kDataErrorMessage = "Data error";
-
-static void PrintHelp(char *buffer)
-{
- strcat(buffer,
- "\nLZMA-C " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n\n"
- "Usage: lzma <e|d> inputFile outputFile\n"
- " e: encode file\n"
- " d: decode file\n");
-}
-
-static int PrintError(char *buffer, const char *message)
-{
- strcat(buffer, "\nError: ");
- strcat(buffer, message);
- strcat(buffer, "\n");
- return 1;
-}
-
-static int PrintErrorNumber(char *buffer, SRes val)
-{
- sprintf(buffer + strlen(buffer), "\nError code: %x\n", (unsigned)val);
- return 1;
-}
-
-static int PrintUserError(char *buffer)
-{
- return PrintError(buffer, "Incorrect command");
-}
-
-
-#define IN_BUF_SIZE (1 << 16)
-#define OUT_BUF_SIZE (1 << 16)
-
-
-static SRes Decode2(CLzmaDec *state, ISeqOutStream *outStream, ISeqInStream *inStream,
- UInt64 unpackSize)
-{
- int thereIsSize = (unpackSize != (UInt64)(Int64)-1);
- Byte inBuf[IN_BUF_SIZE];
- Byte outBuf[OUT_BUF_SIZE];
- size_t inPos = 0, inSize = 0, outPos = 0;
- LzmaDec_Init(state);
- for (;;)
- {
- if (inPos == inSize)
- {
- inSize = IN_BUF_SIZE;
- RINOK(inStream->Read(inStream, inBuf, &inSize));
- inPos = 0;
- }
- {
- SRes res;
- SizeT inProcessed = inSize - inPos;
- SizeT outProcessed = OUT_BUF_SIZE - outPos;
- ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
- ELzmaStatus status;
- if (thereIsSize && outProcessed > unpackSize)
- {
- outProcessed = (SizeT)unpackSize;
- finishMode = LZMA_FINISH_END;
- }
-
- res = LzmaDec_DecodeToBuf(state, outBuf + outPos, &outProcessed,
- inBuf + inPos, &inProcessed, finishMode, &status);
- inPos += inProcessed;
- outPos += outProcessed;
- unpackSize -= outProcessed;
-
- if (outStream)
- if (outStream->Write(outStream, outBuf, outPos) != outPos)
- return SZ_ERROR_WRITE;
-
- outPos = 0;
-
- if (res != SZ_OK || (thereIsSize && unpackSize == 0))
- return res;
-
- if (inProcessed == 0 && outProcessed == 0)
- {
- if (thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK)
- return SZ_ERROR_DATA;
- return res;
- }
- }
- }
-}
-
-
-static SRes Decode(ISeqOutStream *outStream, ISeqInStream *inStream)
-{
- UInt64 unpackSize;
- int i;
- SRes res = 0;
-
- CLzmaDec state;
-
- /* header: 5 bytes of LZMA properties and 8 bytes of uncompressed size */
- unsigned char header[LZMA_PROPS_SIZE + 8];
-
- /* Read and parse header */
-
- RINOK(SeqInStream_Read(inStream, header, sizeof(header)));
-
- unpackSize = 0;
- for (i = 0; i < 8; i++)
- unpackSize += (UInt64)header[LZMA_PROPS_SIZE + i] << (i * 8);
-
- LzmaDec_Construct(&state);
- RINOK(LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc));
- res = Decode2(&state, outStream, inStream, unpackSize);
- LzmaDec_Free(&state, &g_Alloc);
- return res;
-}
-
-static SRes Encode(ISeqOutStream *outStream, ISeqInStream *inStream, UInt64 fileSize, char *rs)
-{
- CLzmaEncHandle enc;
- SRes res;
- CLzmaEncProps props;
-
- UNUSED_VAR(rs);
-
- enc = LzmaEnc_Create(&g_Alloc);
- if (enc == 0)
- return SZ_ERROR_MEM;
-
- LzmaEncProps_Init(&props);
- res = LzmaEnc_SetProps(enc, &props);
-
- if (res == SZ_OK)
- {
- Byte header[LZMA_PROPS_SIZE + 8];
- size_t headerSize = LZMA_PROPS_SIZE;
- int i;
-
- res = LzmaEnc_WriteProperties(enc, header, &headerSize);
- for (i = 0; i < 8; i++)
- header[headerSize++] = (Byte)(fileSize >> (8 * i));
- if (outStream->Write(outStream, header, headerSize) != headerSize)
- res = SZ_ERROR_WRITE;
- else
- {
- if (res == SZ_OK)
- res = LzmaEnc_Encode(enc, outStream, inStream, NULL, &g_Alloc, &g_Alloc);
- }
- }
- LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
- return res;
-}
-
-
-static int main2(int numArgs, const char *args[], char *rs)
-{
- CFileSeqInStream inStream;
- CFileOutStream outStream;
- char c;
- int res;
- int encodeMode;
- BoolInt useOutFile = False;
-
- FileSeqInStream_CreateVTable(&inStream);
- File_Construct(&inStream.file);
-
- FileOutStream_CreateVTable(&outStream);
- File_Construct(&outStream.file);
-
- if (numArgs == 1)
- {
- PrintHelp(rs);
- return 0;
- }
-
- if (numArgs < 3 || numArgs > 4 || strlen(args[1]) != 1)
- return PrintUserError(rs);
-
- c = args[1][0];
- encodeMode = (c == 'e' || c == 'E');
- if (!encodeMode && c != 'd' && c != 'D')
- return PrintUserError(rs);
-
- {
- size_t t4 = sizeof(UInt32);
- size_t t8 = sizeof(UInt64);
- if (t4 != 4 || t8 != 8)
- return PrintError(rs, "Incorrect UInt32 or UInt64");
- }
-
- if (InFile_Open(&inStream.file, args[2]) != 0)
- return PrintError(rs, "Can not open input file");
-
- if (numArgs > 3)
- {
- useOutFile = True;
- if (OutFile_Open(&outStream.file, args[3]) != 0)
- return PrintError(rs, "Can not open output file");
- }
- else if (encodeMode)
- PrintUserError(rs);
-
- if (encodeMode)
- {
- UInt64 fileSize;
- File_GetLength(&inStream.file, &fileSize);
- res = Encode(&outStream.vt, &inStream.vt, fileSize, rs);
- }
- else
- {
- res = Decode(&outStream.vt, useOutFile ? &inStream.vt : NULL);
- }
-
- if (useOutFile)
- File_Close(&outStream.file);
- File_Close(&inStream.file);
-
- if (res != SZ_OK)
- {
- if (res == SZ_ERROR_MEM)
- return PrintError(rs, kCantAllocateMessage);
- else if (res == SZ_ERROR_DATA)
- return PrintError(rs, kDataErrorMessage);
- else if (res == SZ_ERROR_WRITE)
- return PrintError(rs, kCantWriteMessage);
- else if (res == SZ_ERROR_READ)
- return PrintError(rs, kCantReadMessage);
- return PrintErrorNumber(rs, res);
- }
- return 0;
-}
-
-
-int MY_CDECL main(int numArgs, const char *args[])
-{
- char rs[800] = { 0 };
- int res = main2(numArgs, args, rs);
- fputs(rs, stdout);
- return res;
-}
+/* LzmaUtil.c -- Test application for LZMA compression
+2023-03-07 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../../CpuArch.h"
+
+#include "../../Alloc.h"
+#include "../../7zFile.h"
+#include "../../7zVersion.h"
+#include "../../LzFind.h"
+#include "../../LzmaDec.h"
+#include "../../LzmaEnc.h"
+
+static const char * const kCantReadMessage = "Cannot read input file";
+static const char * const kCantWriteMessage = "Cannot write output file";
+static const char * const kCantAllocateMessage = "Cannot allocate memory";
+static const char * const kDataErrorMessage = "Data error";
+
+static void Print(const char *s)
+{
+ fputs(s, stdout);
+}
+
+static void PrintHelp(void)
+{
+ Print(
+ "\n" "LZMA-C " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE
+ "\n"
+ "\n" "Usage: lzma <e|d> inputFile outputFile"
+ "\n" " e: encode file"
+ "\n" " d: decode file"
+ "\n");
+}
+
+static int PrintError(const char *message)
+{
+ Print("\nError: ");
+ Print(message);
+ Print("\n");
+ return 1;
+}
+
+#define CONVERT_INT_TO_STR(charType, tempSize) \
+ unsigned char temp[tempSize]; unsigned i = 0; \
+ while (val >= 10) { temp[i++] = (unsigned char)('0' + (unsigned)(val % 10)); val /= 10; } \
+ *s++ = (charType)('0' + (unsigned)val); \
+ while (i != 0) { i--; *s++ = (charType)temp[i]; } \
+ *s = 0; \
+ return s;
+
+static char * Convert_unsigned_To_str(unsigned val, char *s)
+{
+ CONVERT_INT_TO_STR(char, 32)
+}
+
+static void Print_unsigned(unsigned code)
+{
+ char str[32];
+ Convert_unsigned_To_str(code, str);
+ Print(str);
+}
+
+static int PrintError_WRes(const char *message, WRes wres)
+{
+ PrintError(message);
+ Print("\nSystem error code: ");
+ Print_unsigned((unsigned)wres);
+ #ifndef _WIN32
+ {
+ const char *s = strerror(wres);
+ if (s)
+ {
+ Print(" : ");
+ Print(s);
+ }
+ }
+ #endif
+ Print("\n");
+ return 1;
+}
+
+static int PrintErrorNumber(SRes val)
+{
+ Print("\n7-Zip error code: ");
+ Print_unsigned((unsigned)val);
+ Print("\n");
+ return 1;
+}
+
+static int PrintUserError(void)
+{
+ return PrintError("Incorrect command");
+}
+
+
+#define IN_BUF_SIZE (1 << 16)
+#define OUT_BUF_SIZE (1 << 16)
+
+
+static SRes Decode2(CLzmaDec *state, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream,
+ UInt64 unpackSize)
+{
+ const int thereIsSize = (unpackSize != (UInt64)(Int64)-1);
+ Byte inBuf[IN_BUF_SIZE];
+ Byte outBuf[OUT_BUF_SIZE];
+ size_t inPos = 0, inSize = 0, outPos = 0;
+ LzmaDec_Init(state);
+ for (;;)
+ {
+ if (inPos == inSize)
+ {
+ inSize = IN_BUF_SIZE;
+ RINOK(inStream->Read(inStream, inBuf, &inSize))
+ inPos = 0;
+ }
+ {
+ SRes res;
+ SizeT inProcessed = inSize - inPos;
+ SizeT outProcessed = OUT_BUF_SIZE - outPos;
+ ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
+ ELzmaStatus status;
+ if (thereIsSize && outProcessed > unpackSize)
+ {
+ outProcessed = (SizeT)unpackSize;
+ finishMode = LZMA_FINISH_END;
+ }
+
+ res = LzmaDec_DecodeToBuf(state, outBuf + outPos, &outProcessed,
+ inBuf + inPos, &inProcessed, finishMode, &status);
+ inPos += inProcessed;
+ outPos += outProcessed;
+ unpackSize -= outProcessed;
+
+ if (outStream)
+ if (outStream->Write(outStream, outBuf, outPos) != outPos)
+ return SZ_ERROR_WRITE;
+
+ outPos = 0;
+
+ if (res != SZ_OK || (thereIsSize && unpackSize == 0))
+ return res;
+
+ if (inProcessed == 0 && outProcessed == 0)
+ {
+ if (thereIsSize || status != LZMA_STATUS_FINISHED_WITH_MARK)
+ return SZ_ERROR_DATA;
+ return res;
+ }
+ }
+ }
+}
+
+
+static SRes Decode(ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream)
+{
+ UInt64 unpackSize;
+ int i;
+ SRes res = 0;
+
+ CLzmaDec state;
+
+ /* header: 5 bytes of LZMA properties and 8 bytes of uncompressed size */
+ unsigned char header[LZMA_PROPS_SIZE + 8];
+
+ /* Read and parse header */
+
+ {
+ size_t size = sizeof(header);
+ RINOK(SeqInStream_ReadMax(inStream, header, &size))
+ if (size != sizeof(header))
+ return SZ_ERROR_INPUT_EOF;
+ }
+ unpackSize = 0;
+ for (i = 0; i < 8; i++)
+ unpackSize += (UInt64)header[LZMA_PROPS_SIZE + i] << (i * 8);
+
+ LzmaDec_CONSTRUCT(&state)
+ RINOK(LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc))
+ res = Decode2(&state, outStream, inStream, unpackSize);
+ LzmaDec_Free(&state, &g_Alloc);
+ return res;
+}
+
+static SRes Encode(ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, UInt64 fileSize)
+{
+ CLzmaEncHandle enc;
+ SRes res;
+ CLzmaEncProps props;
+
+ enc = LzmaEnc_Create(&g_Alloc);
+ if (enc == 0)
+ return SZ_ERROR_MEM;
+
+ LzmaEncProps_Init(&props);
+ res = LzmaEnc_SetProps(enc, &props);
+
+ if (res == SZ_OK)
+ {
+ Byte header[LZMA_PROPS_SIZE + 8];
+ size_t headerSize = LZMA_PROPS_SIZE;
+ int i;
+
+ res = LzmaEnc_WriteProperties(enc, header, &headerSize);
+ for (i = 0; i < 8; i++)
+ header[headerSize++] = (Byte)(fileSize >> (8 * i));
+ if (outStream->Write(outStream, header, headerSize) != headerSize)
+ res = SZ_ERROR_WRITE;
+ else
+ {
+ if (res == SZ_OK)
+ res = LzmaEnc_Encode(enc, outStream, inStream, NULL, &g_Alloc, &g_Alloc);
+ }
+ }
+ LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
+ return res;
+}
+
+
+int Z7_CDECL main(int numArgs, const char *args[])
+{
+ CFileSeqInStream inStream;
+ CFileOutStream outStream;
+ char c;
+ int res;
+ int encodeMode;
+ BoolInt useOutFile = False;
+
+ LzFindPrepare();
+
+ FileSeqInStream_CreateVTable(&inStream);
+ File_Construct(&inStream.file);
+ inStream.wres = 0;
+
+ FileOutStream_CreateVTable(&outStream);
+ File_Construct(&outStream.file);
+ outStream.wres = 0;
+
+ if (numArgs == 1)
+ {
+ PrintHelp();
+ return 0;
+ }
+
+ if (numArgs < 3 || numArgs > 4 || strlen(args[1]) != 1)
+ return PrintUserError();
+
+ c = args[1][0];
+ encodeMode = (c == 'e' || c == 'E');
+ if (!encodeMode && c != 'd' && c != 'D')
+ return PrintUserError();
+
+ /*
+ {
+ size_t t4 = sizeof(UInt32);
+ size_t t8 = sizeof(UInt64);
+ if (t4 != 4 || t8 != 8)
+ return PrintError("Incorrect UInt32 or UInt64");
+ }
+ */
+
+ {
+ const WRes wres = InFile_Open(&inStream.file, args[2]);
+ if (wres != 0)
+ return PrintError_WRes("Cannot open input file", wres);
+ }
+
+ if (numArgs > 3)
+ {
+ WRes wres;
+ useOutFile = True;
+ wres = OutFile_Open(&outStream.file, args[3]);
+ if (wres != 0)
+ return PrintError_WRes("Cannot open output file", wres);
+ }
+ else if (encodeMode)
+ PrintUserError();
+
+ if (encodeMode)
+ {
+ UInt64 fileSize;
+ const WRes wres = File_GetLength(&inStream.file, &fileSize);
+ if (wres != 0)
+ return PrintError_WRes("Cannot get file length", wres);
+ res = Encode(&outStream.vt, &inStream.vt, fileSize);
+ }
+ else
+ {
+ res = Decode(&outStream.vt, useOutFile ? &inStream.vt : NULL);
+ }
+
+ if (useOutFile)
+ File_Close(&outStream.file);
+ File_Close(&inStream.file);
+
+ if (res != SZ_OK)
+ {
+ if (res == SZ_ERROR_MEM)
+ return PrintError(kCantAllocateMessage);
+ else if (res == SZ_ERROR_DATA)
+ return PrintError(kDataErrorMessage);
+ else if (res == SZ_ERROR_WRITE)
+ return PrintError_WRes(kCantWriteMessage, outStream.wres);
+ else if (res == SZ_ERROR_READ)
+ return PrintError_WRes(kCantReadMessage, inStream.wres);
+ return PrintErrorNumber(res);
+ }
+ return 0;
+}
diff --git a/C/Util/Lzma/LzmaUtil.dsp b/C/Util/Lzma/LzmaUtil.dsp
index eedde07..e2e7d42 100644
--- a/C/Util/Lzma/LzmaUtil.dsp
+++ b/C/Util/Lzma/LzmaUtil.dsp
@@ -1,168 +1,188 @@
-# Microsoft Developer Studio Project File - Name="LzmaUtil" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Console Application" 0x0103
-
-CFG=LzmaUtil - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "LzmaUtil.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "LzmaUtil.mak" CFG="LzmaUtil - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "LzmaUtil - Win32 Release" (based on "Win32 (x86) Console Application")
-!MESSAGE "LzmaUtil - Win32 Debug" (based on "Win32 (x86) Console Application")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "LzmaUtil - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /MT /W4 /WX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c
-# SUBTRACT CPP /YX
-# ADD BASE RSC /l 0x419 /d "NDEBUG"
-# ADD RSC /l 0x419 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\util\7lzma.exe"
-
-!ELSEIF "$(CFG)" == "LzmaUtil - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W4 /WX /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
-# SUBTRACT CPP /YX
-# ADD BASE RSC /l 0x419 /d "_DEBUG"
-# ADD RSC /l 0x419 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\util\7lzma.exe" /pdbtype:sept
-
-!ENDIF
-
-# Begin Target
-
-# Name "LzmaUtil - Win32 Release"
-# Name "LzmaUtil - Win32 Debug"
-# Begin Source File
-
-SOURCE=..\..\7zFile.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zFile.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zStream.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zTypes.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zVersion.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Alloc.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Alloc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\CpuArch.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzFind.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzFind.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzFindMt.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzFindMt.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzHash.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzmaDec.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzmaDec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzmaEnc.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzmaEnc.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\LzmaUtil.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Threads.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Threads.h
-# End Source File
-# End Target
-# End Project
+# Microsoft Developer Studio Project File - Name="LzmaUtil" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=LzmaUtil - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "LzmaUtil.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "LzmaUtil.mak" CFG="LzmaUtil - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "LzmaUtil - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "LzmaUtil - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "LzmaUtil - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /MT /W4 /WX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\util\7lzma.exe"
+
+!ELSEIF "$(CFG)" == "LzmaUtil - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W4 /WX /Gm /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\util\7lzma.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "LzmaUtil - Win32 Release"
+# Name "LzmaUtil - Win32 Debug"
+# Begin Source File
+
+SOURCE=..\..\7zFile.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zFile.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zStream.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zVersion.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Alloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\CpuArch.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzFind.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzFindMt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzFindMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzFindOpt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzHash.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzmaDec.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzmaDec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzmaEnc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzmaEnc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\LzmaUtil.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Precomp.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Precomp.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Threads.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Threads.h
+# End Source File
+# End Target
+# End Project
diff --git a/C/Util/Lzma/LzmaUtil.dsw b/C/Util/Lzma/LzmaUtil.dsw
index f435487..c52eaf6 100644
--- a/C/Util/Lzma/LzmaUtil.dsw
+++ b/C/Util/Lzma/LzmaUtil.dsw
@@ -1,29 +1,29 @@
-Microsoft Developer Studio Workspace File, Format Version 6.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "LzmaUtil"=.\LzmaUtil.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
-
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "LzmaUtil"=.\LzmaUtil.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/C/Util/Lzma/Precomp.h b/C/Util/Lzma/Precomp.h
new file mode 100644
index 0000000..bc8fa21
--- /dev/null
+++ b/C/Util/Lzma/Precomp.h
@@ -0,0 +1,14 @@
+/* Precomp.h -- StdAfx
+2023-03-04 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_PRECOMP_H
+#define ZIP7_INC_PRECOMP_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+
+#include "../../Compiler.h"
+#include "../../7zTypes.h"
+
+#endif
diff --git a/C/Util/Lzma/makefile b/C/Util/Lzma/makefile
index 3b825f2..7813bdb 100644
--- a/C/Util/Lzma/makefile
+++ b/C/Util/Lzma/makefile
@@ -1,28 +1,30 @@
-# MY_STATIC_LINK=1
-PROG = LZMAc.exe
-
-CFLAGS = $(CFLAGS) \
-
-LIB_OBJS = \
- $O\LzmaUtil.obj \
-
-C_OBJS = \
- $O\Alloc.obj \
- $O\LzFind.obj \
- $O\LzFindMt.obj \
- $O\LzmaDec.obj \
- $O\LzmaEnc.obj \
- $O\7zFile.obj \
- $O\7zStream.obj \
- $O\Threads.obj \
-
-OBJS = \
- $(LIB_OBJS) \
- $(C_OBJS) \
-
-!include "../../../CPP/Build.mak"
-
-$(LIB_OBJS): $(*B).c
- $(COMPL_O2)
-$(C_OBJS): ../../$(*B).c
- $(COMPL_O2)
+# MY_STATIC_LINK=1
+PROG = LZMAc.exe
+
+CFLAGS = $(CFLAGS) \
+
+LIB_OBJS = \
+ $O\LzmaUtil.obj \
+
+C_OBJS = \
+ $O\Alloc.obj \
+ $O\CpuArch.obj \
+ $O\LzFind.obj \
+ $O\LzFindMt.obj \
+ $O\LzFindOpt.obj \
+ $O\LzmaDec.obj \
+ $O\LzmaEnc.obj \
+ $O\7zFile.obj \
+ $O\7zStream.obj \
+ $O\Threads.obj \
+
+OBJS = \
+ $(LIB_OBJS) \
+ $(C_OBJS) \
+
+!include "../../../CPP/Build.mak"
+
+$(LIB_OBJS): $(*B).c
+ $(COMPL_O2)
+$(C_OBJS): ../../$(*B).c
+ $(COMPL_O2)
diff --git a/C/Util/Lzma/makefile.gcc b/C/Util/Lzma/makefile.gcc
index 12a72bb..2acb0b8 100644
--- a/C/Util/Lzma/makefile.gcc
+++ b/C/Util/Lzma/makefile.gcc
@@ -1,44 +1,21 @@
-PROG = lzma
-CXX = g++
-LIB =
-RM = rm -f
-CFLAGS = -c -O2 -Wall -D_7ZIP_ST
-
-OBJS = \
- LzmaUtil.o \
- Alloc.o \
- LzFind.o \
- LzmaDec.o \
- LzmaEnc.o \
- 7zFile.o \
- 7zStream.o \
-
-
-all: $(PROG)
-
-$(PROG): $(OBJS)
- $(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB) $(LIB2)
-
-LzmaUtil.o: LzmaUtil.c
- $(CXX) $(CFLAGS) LzmaUtil.c
-
-Alloc.o: ../../Alloc.c
- $(CXX) $(CFLAGS) ../../Alloc.c
-
-LzFind.o: ../../LzFind.c
- $(CXX) $(CFLAGS) ../../LzFind.c
-
-LzmaDec.o: ../../LzmaDec.c
- $(CXX) $(CFLAGS) ../../LzmaDec.c
-
-LzmaEnc.o: ../../LzmaEnc.c
- $(CXX) $(CFLAGS) ../../LzmaEnc.c
-
-7zFile.o: ../../7zFile.c
- $(CXX) $(CFLAGS) ../../7zFile.c
-
-7zStream.o: ../../7zStream.c
- $(CXX) $(CFLAGS) ../../7zStream.c
-
-clean:
- -$(RM) $(PROG) $(OBJS)
+PROG = 7lzma
+
+include ../../../CPP/7zip/LzmaDec_gcc.mak
+
+
+OBJS = \
+ $(LZMA_DEC_OPT_OBJS) \
+ $O/7zFile.o \
+ $O/7zStream.o \
+ $O/Alloc.o \
+ $O/CpuArch.o \
+ $O/LzFind.o \
+ $O/LzFindMt.o \
+ $O/LzFindOpt.o \
+ $O/LzmaDec.o \
+ $O/LzmaEnc.o \
+ $O/LzmaUtil.o \
+ $O/Threads.o \
+
+
+include ../../7zip_gcc_c.mak
diff --git a/C/Util/LzmaLib/LzmaLib.def b/C/Util/LzmaLib/LzmaLib.def
index 43b9597..8bc6add 100644
--- a/C/Util/LzmaLib/LzmaLib.def
+++ b/C/Util/LzmaLib/LzmaLib.def
@@ -1,4 +1,4 @@
-EXPORTS
- LzmaCompress
- LzmaUncompress
-
+EXPORTS
+ LzmaCompress
+ LzmaUncompress
+
diff --git a/C/Util/LzmaLib/LzmaLib.dsp b/C/Util/LzmaLib/LzmaLib.dsp
index 0d4c981..bacd967 100644
--- a/C/Util/LzmaLib/LzmaLib.dsp
+++ b/C/Util/LzmaLib/LzmaLib.dsp
@@ -1,178 +1,202 @@
-# Microsoft Developer Studio Project File - Name="LzmaLib" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
-
-CFG=LzmaLib - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "LzmaLib.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "LzmaLib.mak" CFG="LzmaLib - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "LzmaLib - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE "LzmaLib - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "LzmaLib - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /YX /FD /c
-# ADD CPP /nologo /Gr /MT /W3 /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /FD /c
-# SUBTRACT CPP /YX
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x419 /d "NDEBUG"
-# ADD RSC /l 0x419 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Util\LZMA.dll" /opt:NOWIN98
-# SUBTRACT LINK32 /pdb:none
-
-!ELSEIF "$(CFG)" == "LzmaLib - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /YX /FD /GZ /c
-# ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /D "COMPRESS_MF_MT" /FD /GZ /c
-# SUBTRACT CPP /YX
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x419 /d "_DEBUG"
-# ADD RSC /l 0x419 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\LZMA.dll" /pdbtype:sept
-
-!ENDIF
-
-# Begin Target
-
-# Name "LzmaLib - Win32 Release"
-# Name "LzmaLib - Win32 Debug"
-# Begin Group "Spec"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=.\LzmaLib.def
-# End Source File
-# Begin Source File
-
-SOURCE=.\LzmaLibExports.c
-# End Source File
-# End Group
-# Begin Source File
-
-SOURCE=..\..\7zTypes.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Alloc.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Alloc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\IStream.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzFind.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzFind.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzFindMt.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzFindMt.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzHash.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzmaDec.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzmaDec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzmaEnc.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzmaEnc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzmaLib.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzmaLib.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\resource.rc
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Threads.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Threads.h
-# End Source File
-# End Target
-# End Project
+# Microsoft Developer Studio Project File - Name="LzmaLib" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=LzmaLib - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "LzmaLib.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "LzmaLib.mak" CFG="LzmaLib - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "LzmaLib - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "LzmaLib - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "LzmaLib - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /Gr /MT /W3 /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /FD /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Util\LZMA.dll" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "LzmaLib - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /MTd /W3 /Gm /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "LZMALIB_EXPORTS" /D "COMPRESS_MF_MT" /FD /GZ /c
+# SUBTRACT CPP /YX
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\LZMA.dll" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "LzmaLib - Win32 Release"
+# Name "LzmaLib - Win32 Debug"
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\LzmaLib.def
+# End Source File
+# Begin Source File
+
+SOURCE=.\LzmaLibExports.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\Precomp.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Alloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\CpuArch.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzFind.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzFindMt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzFindMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzFindOpt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzHash.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzmaDec.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzmaDec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzmaEnc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzmaEnc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzmaLib.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzmaLib.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Precomp.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Threads.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Threads.h
+# End Source File
+# End Target
+# End Project
diff --git a/C/Util/LzmaLib/LzmaLib.dsw b/C/Util/LzmaLib/LzmaLib.dsw
index f6c5559..6faf333 100644
--- a/C/Util/LzmaLib/LzmaLib.dsw
+++ b/C/Util/LzmaLib/LzmaLib.dsw
@@ -1,29 +1,29 @@
-Microsoft Developer Studio Workspace File, Format Version 6.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "LzmaLib"=.\LzmaLib.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
-
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "LzmaLib"=.\LzmaLib.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/C/Util/LzmaLib/LzmaLibExports.c b/C/Util/LzmaLib/LzmaLibExports.c
index 02600c7..a46c9a8 100644
--- a/C/Util/LzmaLib/LzmaLibExports.c
+++ b/C/Util/LzmaLib/LzmaLibExports.c
@@ -1,14 +1,15 @@
-/* LzmaLibExports.c -- LZMA library DLL Entry point
-2015-11-08 : Igor Pavlov : Public domain */
-
-#include "../../Precomp.h"
-
-#include <windows.h>
-
-BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
-{
- UNUSED_VAR(hInstance);
- UNUSED_VAR(dwReason);
- UNUSED_VAR(lpReserved);
- return TRUE;
-}
+/* LzmaLibExports.c -- LZMA library DLL Entry point
+2023-03-05 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "../../7zWindows.h"
+
+BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved);
+BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID lpReserved)
+{
+ UNUSED_VAR(hInstance)
+ UNUSED_VAR(dwReason)
+ UNUSED_VAR(lpReserved)
+ return TRUE;
+}
diff --git a/C/Util/LzmaLib/Precomp.c b/C/Util/LzmaLib/Precomp.c
new file mode 100644
index 0000000..01605e3
--- /dev/null
+++ b/C/Util/LzmaLib/Precomp.c
@@ -0,0 +1,4 @@
+/* Precomp.c -- StdAfx
+2013-01-21 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
diff --git a/C/Util/LzmaLib/Precomp.h b/C/Util/LzmaLib/Precomp.h
new file mode 100644
index 0000000..bc8fa21
--- /dev/null
+++ b/C/Util/LzmaLib/Precomp.h
@@ -0,0 +1,14 @@
+/* Precomp.h -- StdAfx
+2023-03-04 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_PRECOMP_H
+#define ZIP7_INC_PRECOMP_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+
+#include "../../Compiler.h"
+#include "../../7zTypes.h"
+
+#endif
diff --git a/C/Util/LzmaLib/makefile b/C/Util/LzmaLib/makefile
index e0f3114..b8e054e 100644
--- a/C/Util/LzmaLib/makefile
+++ b/C/Util/LzmaLib/makefile
@@ -1,34 +1,54 @@
-MY_STATIC_LINK=1
-SLIB = sLZMA.lib
-PROG = LZMA.dll
-SLIBPATH = $O\$(SLIB)
-
-DEF_FILE = LzmaLib.def
-CFLAGS = $(CFLAGS) \
-
-LIB_OBJS = \
- $O\LzmaLibExports.obj \
-
-C_OBJS = \
- $O\Alloc.obj \
- $O\LzFind.obj \
- $O\LzFindMt.obj \
- $O\LzmaDec.obj \
- $O\LzmaEnc.obj \
- $O\LzmaLib.obj \
- $O\Threads.obj \
-
-OBJS = \
- $(LIB_OBJS) \
- $(C_OBJS) \
- $O\resource.res
-
-!include "../../../CPP/Build.mak"
-
-$(SLIBPATH): $O $(OBJS)
- lib -out:$(SLIBPATH) $(OBJS) $(LIBS)
-
-$(LIB_OBJS): $(*B).c
- $(COMPL_O2)
-$(C_OBJS): ../../$(*B).c
- $(COMPL_O2)
+MY_STATIC_LINK=1
+SLIB = sLZMA.lib
+PROG = LZMA.dll
+SLIBPATH = $O\$(SLIB)
+
+DEF_FILE = LzmaLib.def
+CFLAGS = $(CFLAGS) \
+
+LIB_OBJS = \
+ $O\LzmaLibExports.obj \
+
+C_OBJS = \
+ $O\Alloc.obj \
+ $O\CpuArch.obj \
+ $O\LzFind.obj \
+ $O\LzFindMt.obj \
+ $O\LzFindOpt.obj \
+ $O\LzmaDec.obj \
+ $O\LzmaEnc.obj \
+ $O\LzmaLib.obj \
+ $O\Threads.obj \
+
+OBJS = \
+ $O\Precomp.obj \
+ $(LIB_OBJS) \
+ $(C_OBJS) \
+ $O\resource.res
+
+!include "../../../CPP/Build.mak"
+
+$(SLIBPATH): $O $(OBJS)
+ lib -out:$(SLIBPATH) $(OBJS) $(LIBS)
+
+
+MAK_SINGLE_FILE = 1
+
+$O\Precomp.obj: Precomp.c
+ $(CCOMPL_PCH)
+
+!IFDEF MAK_SINGLE_FILE
+
+$(LIB_OBJS): $(*B).c
+ $(CCOMPL_USE)
+$(C_OBJS): ../../$(*B).c
+ $(CCOMPL_USE)
+
+!ELSE
+
+{.}.c{$O}.obj::
+ $(CCOMPLB_USE)
+{../../../C}.c{$O}.obj::
+ $(CCOMPLB_USE)
+
+!ENDIF
diff --git a/C/Util/LzmaLib/resource.rc b/C/Util/LzmaLib/resource.rc
index d95e3f3..674832e 100644
--- a/C/Util/LzmaLib/resource.rc
+++ b/C/Util/LzmaLib/resource.rc
@@ -1,3 +1,3 @@
-#include "../../7zVersion.rc"
-
-MY_VERSION_INFO_DLL("LZMA library", "LZMA")
+#include "../../7zVersion.rc"
+
+MY_VERSION_INFO_DLL("LZMA library", "LZMA")
diff --git a/C/Util/SfxSetup/Precomp.c b/C/Util/SfxSetup/Precomp.c
index 34b60f8..01605e3 100644
--- a/C/Util/SfxSetup/Precomp.c
+++ b/C/Util/SfxSetup/Precomp.c
@@ -1,4 +1,4 @@
-/* Precomp.c -- StdAfx
-2013-01-21 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
+/* Precomp.c -- StdAfx
+2013-01-21 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
diff --git a/C/Util/SfxSetup/Precomp.h b/C/Util/SfxSetup/Precomp.h
index 9f398d0..bc8fa21 100644
--- a/C/Util/SfxSetup/Precomp.h
+++ b/C/Util/SfxSetup/Precomp.h
@@ -1,10 +1,14 @@
-/* Precomp.h -- StdAfx
-2013-06-16 : Igor Pavlov : Public domain */
-
-#ifndef __7Z_PRECOMP_H
-#define __7Z_PRECOMP_H
-
-#include "../../Compiler.h"
-#include "../../7zTypes.h"
-
-#endif
+/* Precomp.h -- StdAfx
+2023-03-04 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_PRECOMP_H
+#define ZIP7_INC_PRECOMP_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+
+#include "../../Compiler.h"
+#include "../../7zTypes.h"
+
+#endif
diff --git a/C/Util/SfxSetup/SfxSetup.c b/C/Util/SfxSetup/SfxSetup.c
index 394369a..7304a0b 100644
--- a/C/Util/SfxSetup/SfxSetup.c
+++ b/C/Util/SfxSetup/SfxSetup.c
@@ -1,640 +1,656 @@
-/* SfxSetup.c - 7z SFX Setup
-2019-02-02 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#ifndef UNICODE
-#define UNICODE
-#endif
-
-#ifndef _UNICODE
-#define _UNICODE
-#endif
-
-#ifdef _CONSOLE
-#include <stdio.h>
-#endif
-
-#include "../../7z.h"
-#include "../../7zAlloc.h"
-#include "../../7zCrc.h"
-#include "../../7zFile.h"
-#include "../../CpuArch.h"
-#include "../../DllSecur.h"
-
-#define k_EXE_ExtIndex 2
-
-#define kInputBufSize ((size_t)1 << 18)
-
-static const char * const kExts[] =
-{
- "bat"
- , "cmd"
- , "exe"
- , "inf"
- , "msi"
- #ifdef UNDER_CE
- , "cab"
- #endif
- , "html"
- , "htm"
-};
-
-static const char * const kNames[] =
-{
- "setup"
- , "install"
- , "run"
- , "start"
-};
-
-static unsigned FindExt(const wchar_t *s, unsigned *extLen)
-{
- unsigned len = (unsigned)wcslen(s);
- unsigned i;
- for (i = len; i > 0; i--)
- {
- if (s[i - 1] == '.')
- {
- *extLen = len - i;
- return i - 1;
- }
- }
- *extLen = 0;
- return len;
-}
-
-#define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) -= 0x20 : (c)))
-
-static unsigned FindItem(const char * const *items, unsigned num, const wchar_t *s, unsigned len)
-{
- unsigned i;
- for (i = 0; i < num; i++)
- {
- const char *item = items[i];
- unsigned itemLen = (unsigned)strlen(item);
- unsigned j;
- if (len != itemLen)
- continue;
- for (j = 0; j < len; j++)
- {
- unsigned c = (Byte)item[j];
- if (c != s[j] && MAKE_CHAR_UPPER(c) != s[j])
- break;
- }
- if (j == len)
- return i;
- }
- return i;
-}
-
-#ifdef _CONSOLE
-static BOOL WINAPI HandlerRoutine(DWORD ctrlType)
-{
- UNUSED_VAR(ctrlType);
- return TRUE;
-}
-#endif
-
-static void PrintErrorMessage(const char *message)
-{
- #ifdef _CONSOLE
- printf("\n7-Zip Error: %s\n", message);
- #else
- #ifdef UNDER_CE
- WCHAR messageW[256 + 4];
- unsigned i;
- for (i = 0; i < 256 && message[i] != 0; i++)
- messageW[i] = message[i];
- messageW[i] = 0;
- MessageBoxW(0, messageW, L"7-Zip Error", MB_ICONERROR);
- #else
- MessageBoxA(0, message, "7-Zip Error", MB_ICONERROR);
- #endif
- #endif
-}
-
-static WRes MyCreateDir(const WCHAR *name)
-{
- return CreateDirectoryW(name, NULL) ? 0 : GetLastError();
-}
-
-#ifdef UNDER_CE
-#define kBufferSize (1 << 13)
-#else
-#define kBufferSize (1 << 15)
-#endif
-
-#define kSignatureSearchLimit (1 << 22)
-
-static BoolInt FindSignature(CSzFile *stream, UInt64 *resPos)
-{
- Byte buf[kBufferSize];
- size_t numPrevBytes = 0;
- *resPos = 0;
- for (;;)
- {
- size_t processed, pos;
- if (*resPos > kSignatureSearchLimit)
- return False;
- processed = kBufferSize - numPrevBytes;
- if (File_Read(stream, buf + numPrevBytes, &processed) != 0)
- return False;
- processed += numPrevBytes;
- if (processed < k7zStartHeaderSize ||
- (processed == k7zStartHeaderSize && numPrevBytes != 0))
- return False;
- processed -= k7zStartHeaderSize;
- for (pos = 0; pos <= processed; pos++)
- {
- for (; pos <= processed && buf[pos] != '7'; pos++);
- if (pos > processed)
- break;
- if (memcmp(buf + pos, k7zSignature, k7zSignatureSize) == 0)
- if (CrcCalc(buf + pos + 12, 20) == GetUi32(buf + pos + 8))
- {
- *resPos += pos;
- return True;
- }
- }
- *resPos += processed;
- numPrevBytes = k7zStartHeaderSize;
- memmove(buf, buf + processed, k7zStartHeaderSize);
- }
-}
-
-static BoolInt DoesFileOrDirExist(const WCHAR *path)
-{
- WIN32_FIND_DATAW fd;
- HANDLE handle;
- handle = FindFirstFileW(path, &fd);
- if (handle == INVALID_HANDLE_VALUE)
- return False;
- FindClose(handle);
- return True;
-}
-
-static WRes RemoveDirWithSubItems(WCHAR *path)
-{
- WIN32_FIND_DATAW fd;
- HANDLE handle;
- WRes res = 0;
- size_t len = wcslen(path);
- wcscpy(path + len, L"*");
- handle = FindFirstFileW(path, &fd);
- path[len] = L'\0';
- if (handle == INVALID_HANDLE_VALUE)
- return GetLastError();
-
- for (;;)
- {
- if (wcscmp(fd.cFileName, L".") != 0 &&
- wcscmp(fd.cFileName, L"..") != 0)
- {
- wcscpy(path + len, fd.cFileName);
- if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
- {
- wcscat(path, WSTRING_PATH_SEPARATOR);
- res = RemoveDirWithSubItems(path);
- }
- else
- {
- SetFileAttributesW(path, 0);
- if (DeleteFileW(path) == 0)
- res = GetLastError();
- }
-
- if (res != 0)
- break;
- }
-
- if (!FindNextFileW(handle, &fd))
- {
- res = GetLastError();
- if (res == ERROR_NO_MORE_FILES)
- res = 0;
- break;
- }
- }
-
- path[len] = L'\0';
- FindClose(handle);
- if (res == 0)
- {
- if (!RemoveDirectoryW(path))
- res = GetLastError();
- }
- return res;
-}
-
-#ifdef _CONSOLE
-int MY_CDECL main()
-#else
-int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
- #ifdef UNDER_CE
- LPWSTR
- #else
- LPSTR
- #endif
- lpCmdLine, int nCmdShow)
-#endif
-{
- CFileInStream archiveStream;
- CLookToRead2 lookStream;
- CSzArEx db;
- SRes res = SZ_OK;
- ISzAlloc allocImp;
- ISzAlloc allocTempImp;
- WCHAR sfxPath[MAX_PATH + 2];
- WCHAR path[MAX_PATH * 3 + 2];
- #ifndef UNDER_CE
- WCHAR workCurDir[MAX_PATH + 32];
- #endif
- size_t pathLen;
- DWORD winRes;
- const wchar_t *cmdLineParams;
- const char *errorMessage = NULL;
- BoolInt useShellExecute = True;
- DWORD exitCode = 0;
-
- LoadSecurityDlls();
-
- #ifdef _CONSOLE
- SetConsoleCtrlHandler(HandlerRoutine, TRUE);
- #else
- UNUSED_VAR(hInstance);
- UNUSED_VAR(hPrevInstance);
- UNUSED_VAR(lpCmdLine);
- UNUSED_VAR(nCmdShow);
- #endif
-
- CrcGenerateTable();
-
- allocImp.Alloc = SzAlloc;
- allocImp.Free = SzFree;
-
- allocTempImp.Alloc = SzAllocTemp;
- allocTempImp.Free = SzFreeTemp;
-
- FileInStream_CreateVTable(&archiveStream);
- LookToRead2_CreateVTable(&lookStream, False);
- lookStream.buf = NULL;
-
- winRes = GetModuleFileNameW(NULL, sfxPath, MAX_PATH);
- if (winRes == 0 || winRes > MAX_PATH)
- return 1;
- {
- cmdLineParams = GetCommandLineW();
- #ifndef UNDER_CE
- {
- BoolInt quoteMode = False;
- for (;; cmdLineParams++)
- {
- wchar_t c = *cmdLineParams;
- if (c == L'\"')
- quoteMode = !quoteMode;
- else if (c == 0 || (c == L' ' && !quoteMode))
- break;
- }
- }
- #endif
- }
-
- {
- unsigned i;
- DWORD d;
- winRes = GetTempPathW(MAX_PATH, path);
- if (winRes == 0 || winRes > MAX_PATH)
- return 1;
- pathLen = wcslen(path);
- d = (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId();
-
- for (i = 0;; i++, d += GetTickCount())
- {
- if (i >= 100)
- {
- res = SZ_ERROR_FAIL;
- break;
- }
- wcscpy(path + pathLen, L"7z");
-
- {
- wchar_t *s = path + wcslen(path);
- UInt32 value = d;
- unsigned k;
- for (k = 0; k < 8; k++)
- {
- unsigned t = value & 0xF;
- value >>= 4;
- s[7 - k] = (wchar_t)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
- }
- s[k] = '\0';
- }
-
- if (DoesFileOrDirExist(path))
- continue;
- if (CreateDirectoryW(path, NULL))
- {
- wcscat(path, WSTRING_PATH_SEPARATOR);
- pathLen = wcslen(path);
- break;
- }
- if (GetLastError() != ERROR_ALREADY_EXISTS)
- {
- res = SZ_ERROR_FAIL;
- break;
- }
- }
-
- #ifndef UNDER_CE
- wcscpy(workCurDir, path);
- #endif
- if (res != SZ_OK)
- errorMessage = "Can't create temp folder";
- }
-
- if (res != SZ_OK)
- {
- if (!errorMessage)
- errorMessage = "Error";
- PrintErrorMessage(errorMessage);
- return 1;
- }
-
- if (InFile_OpenW(&archiveStream.file, sfxPath) != 0)
- {
- errorMessage = "can not open input file";
- res = SZ_ERROR_FAIL;
- }
- else
- {
- UInt64 pos = 0;
- if (!FindSignature(&archiveStream.file, &pos))
- res = SZ_ERROR_FAIL;
- else if (File_Seek(&archiveStream.file, (Int64 *)&pos, SZ_SEEK_SET) != 0)
- res = SZ_ERROR_FAIL;
- if (res != 0)
- errorMessage = "Can't find 7z archive";
- }
-
- if (res == SZ_OK)
- {
- lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize);
- if (!lookStream.buf)
- res = SZ_ERROR_MEM;
- else
- {
- lookStream.bufSize = kInputBufSize;
- lookStream.realStream = &archiveStream.vt;
- LookToRead2_Init(&lookStream);
- }
- }
-
- SzArEx_Init(&db);
-
- if (res == SZ_OK)
- {
- res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp);
- }
-
- if (res == SZ_OK)
- {
- UInt32 executeFileIndex = (UInt32)(Int32)-1;
- UInt32 minPrice = 1 << 30;
- UInt32 i;
- UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */
- Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */
- size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */
-
- for (i = 0; i < db.NumFiles; i++)
- {
- size_t offset = 0;
- size_t outSizeProcessed = 0;
- WCHAR *temp;
-
- if (SzArEx_GetFileNameUtf16(&db, i, NULL) >= MAX_PATH)
- {
- res = SZ_ERROR_FAIL;
- break;
- }
-
- temp = path + pathLen;
-
- SzArEx_GetFileNameUtf16(&db, i, (UInt16 *)temp);
- {
- res = SzArEx_Extract(&db, &lookStream.vt, i,
- &blockIndex, &outBuffer, &outBufferSize,
- &offset, &outSizeProcessed,
- &allocImp, &allocTempImp);
- if (res != SZ_OK)
- break;
- }
- {
- CSzFile outFile;
- size_t processedSize;
- size_t j;
- size_t nameStartPos = 0;
- for (j = 0; temp[j] != 0; j++)
- {
- if (temp[j] == '/')
- {
- temp[j] = 0;
- MyCreateDir(path);
- temp[j] = CHAR_PATH_SEPARATOR;
- nameStartPos = j + 1;
- }
- }
-
- if (SzArEx_IsDir(&db, i))
- {
- MyCreateDir(path);
- continue;
- }
- else
- {
- unsigned extLen;
- const WCHAR *name = temp + nameStartPos;
- unsigned len = (unsigned)wcslen(name);
- unsigned nameLen = FindExt(temp + nameStartPos, &extLen);
- unsigned extPrice = FindItem(kExts, sizeof(kExts) / sizeof(kExts[0]), name + len - extLen, extLen);
- unsigned namePrice = FindItem(kNames, sizeof(kNames) / sizeof(kNames[0]), name, nameLen);
-
- unsigned price = namePrice + extPrice * 64 + (nameStartPos == 0 ? 0 : (1 << 12));
- if (minPrice > price)
- {
- minPrice = price;
- executeFileIndex = i;
- useShellExecute = (extPrice != k_EXE_ExtIndex);
- }
-
- if (DoesFileOrDirExist(path))
- {
- errorMessage = "Duplicate file";
- res = SZ_ERROR_FAIL;
- break;
- }
- if (OutFile_OpenW(&outFile, path))
- {
- errorMessage = "Can't open output file";
- res = SZ_ERROR_FAIL;
- break;
- }
- }
-
- processedSize = outSizeProcessed;
- if (File_Write(&outFile, outBuffer + offset, &processedSize) != 0 || processedSize != outSizeProcessed)
- {
- errorMessage = "Can't write output file";
- res = SZ_ERROR_FAIL;
- }
-
- #ifdef USE_WINDOWS_FILE
- if (SzBitWithVals_Check(&db.MTime, i))
- {
- const CNtfsFileTime *t = db.MTime.Vals + i;
- FILETIME mTime;
- mTime.dwLowDateTime = t->Low;
- mTime.dwHighDateTime = t->High;
- SetFileTime(outFile.handle, NULL, NULL, &mTime);
- }
- #endif
-
- {
- SRes res2 = File_Close(&outFile);
- if (res != SZ_OK)
- break;
- if (res2 != SZ_OK)
- {
- res = res2;
- break;
- }
- }
- #ifdef USE_WINDOWS_FILE
- if (SzBitWithVals_Check(&db.Attribs, i))
- SetFileAttributesW(path, db.Attribs.Vals[i]);
- #endif
- }
- }
-
- if (res == SZ_OK)
- {
- if (executeFileIndex == (UInt32)(Int32)-1)
- {
- errorMessage = "There is no file to execute";
- res = SZ_ERROR_FAIL;
- }
- else
- {
- WCHAR *temp = path + pathLen;
- UInt32 j;
- SzArEx_GetFileNameUtf16(&db, executeFileIndex, (UInt16 *)temp);
- for (j = 0; temp[j] != 0; j++)
- if (temp[j] == '/')
- temp[j] = CHAR_PATH_SEPARATOR;
- }
- }
- ISzAlloc_Free(&allocImp, outBuffer);
- }
-
- SzArEx_Free(&db, &allocImp);
-
- ISzAlloc_Free(&allocImp, lookStream.buf);
-
- File_Close(&archiveStream.file);
-
- if (res == SZ_OK)
- {
- HANDLE hProcess = 0;
-
- #ifndef UNDER_CE
- WCHAR oldCurDir[MAX_PATH + 2];
- oldCurDir[0] = 0;
- {
- DWORD needLen = GetCurrentDirectory(MAX_PATH + 1, oldCurDir);
- if (needLen == 0 || needLen > MAX_PATH)
- oldCurDir[0] = 0;
- SetCurrentDirectory(workCurDir);
- }
- #endif
-
- if (useShellExecute)
- {
- SHELLEXECUTEINFO ei;
- UINT32 executeRes;
- BOOL success;
-
- memset(&ei, 0, sizeof(ei));
- ei.cbSize = sizeof(ei);
- ei.lpFile = path;
- ei.fMask = SEE_MASK_NOCLOSEPROCESS
- #ifndef UNDER_CE
- | SEE_MASK_FLAG_DDEWAIT
- #endif
- /* | SEE_MASK_NO_CONSOLE */
- ;
- if (wcslen(cmdLineParams) != 0)
- ei.lpParameters = cmdLineParams;
- ei.nShow = SW_SHOWNORMAL; /* SW_HIDE; */
- success = ShellExecuteEx(&ei);
- executeRes = (UINT32)(UINT_PTR)ei.hInstApp;
- if (!success || (executeRes <= 32 && executeRes != 0)) /* executeRes = 0 in Windows CE */
- res = SZ_ERROR_FAIL;
- else
- hProcess = ei.hProcess;
- }
- else
- {
- STARTUPINFOW si;
- PROCESS_INFORMATION pi;
- WCHAR cmdLine[MAX_PATH * 3];
-
- wcscpy(cmdLine, path);
- wcscat(cmdLine, cmdLineParams);
- memset(&si, 0, sizeof(si));
- si.cb = sizeof(si);
- if (CreateProcessW(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) == 0)
- res = SZ_ERROR_FAIL;
- else
- {
- CloseHandle(pi.hThread);
- hProcess = pi.hProcess;
- }
- }
-
- if (hProcess != 0)
- {
- WaitForSingleObject(hProcess, INFINITE);
- if (!GetExitCodeProcess(hProcess, &exitCode))
- exitCode = 1;
- CloseHandle(hProcess);
- }
-
- #ifndef UNDER_CE
- SetCurrentDirectory(oldCurDir);
- #endif
- }
-
- path[pathLen] = L'\0';
- RemoveDirWithSubItems(path);
-
- if (res == SZ_OK)
- return (int)exitCode;
-
- {
- if (res == SZ_ERROR_UNSUPPORTED)
- errorMessage = "Decoder doesn't support this archive";
- else if (res == SZ_ERROR_MEM)
- errorMessage = "Can't allocate required memory";
- else if (res == SZ_ERROR_CRC)
- errorMessage = "CRC error";
- else
- {
- if (!errorMessage)
- errorMessage = "ERROR";
- }
-
- if (errorMessage)
- PrintErrorMessage(errorMessage);
- }
- return 1;
-}
+/* SfxSetup.c - 7z SFX Setup
+2019-02-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#ifndef UNICODE
+#define UNICODE
+#endif
+
+#ifndef _UNICODE
+#define _UNICODE
+#endif
+
+#ifdef _CONSOLE
+#include <stdio.h>
+#endif
+
+#include "../../7z.h"
+#include "../../7zAlloc.h"
+#include "../../7zCrc.h"
+#include "../../7zFile.h"
+#include "../../CpuArch.h"
+#include "../../DllSecur.h"
+
+#define k_EXE_ExtIndex 2
+
+#define kInputBufSize ((size_t)1 << 18)
+
+
+#define wcscat lstrcatW
+#define wcslen (size_t)lstrlenW
+#define wcscpy lstrcpyW
+// wcsncpy() and lstrcpynW() work differently. We don't use them.
+
+static const char * const kExts[] =
+{
+ "bat"
+ , "cmd"
+ , "exe"
+ , "inf"
+ , "msi"
+ #ifdef UNDER_CE
+ , "cab"
+ #endif
+ , "html"
+ , "htm"
+};
+
+static const char * const kNames[] =
+{
+ "setup"
+ , "install"
+ , "run"
+ , "start"
+};
+
+static unsigned FindExt(const wchar_t *s, unsigned *extLen)
+{
+ unsigned len = (unsigned)wcslen(s);
+ unsigned i;
+ for (i = len; i > 0; i--)
+ {
+ if (s[i - 1] == '.')
+ {
+ *extLen = len - i;
+ return i - 1;
+ }
+ }
+ *extLen = 0;
+ return len;
+}
+
+#define MAKE_CHAR_UPPER(c) ((((c) >= 'a' && (c) <= 'z') ? (c) - 0x20 : (c)))
+
+static unsigned FindItem(const char * const *items, unsigned num, const wchar_t *s, unsigned len)
+{
+ unsigned i;
+ for (i = 0; i < num; i++)
+ {
+ const char *item = items[i];
+ const unsigned itemLen = (unsigned)strlen(item);
+ unsigned j;
+ if (len != itemLen)
+ continue;
+ for (j = 0; j < len; j++)
+ {
+ const unsigned c = (Byte)item[j];
+ if (c != s[j] && MAKE_CHAR_UPPER(c) != s[j])
+ break;
+ }
+ if (j == len)
+ return i;
+ }
+ return i;
+}
+
+#ifdef _CONSOLE
+static BOOL WINAPI HandlerRoutine(DWORD ctrlType)
+{
+ UNUSED_VAR(ctrlType);
+ return TRUE;
+}
+#endif
+
+
+#ifdef _CONSOLE
+static void PrintStr(const char *s)
+{
+ fputs(s, stdout);
+}
+#endif
+
+static void PrintErrorMessage(const char *message)
+{
+ #ifdef _CONSOLE
+ PrintStr("\n7-Zip Error: ");
+ PrintStr(message);
+ PrintStr("\n");
+ #else
+ #ifdef UNDER_CE
+ WCHAR messageW[256 + 4];
+ unsigned i;
+ for (i = 0; i < 256 && message[i] != 0; i++)
+ messageW[i] = message[i];
+ messageW[i] = 0;
+ MessageBoxW(0, messageW, L"7-Zip Error", MB_ICONERROR);
+ #else
+ MessageBoxA(0, message, "7-Zip Error", MB_ICONERROR);
+ #endif
+ #endif
+}
+
+static WRes MyCreateDir(const WCHAR *name)
+{
+ return CreateDirectoryW(name, NULL) ? 0 : GetLastError();
+}
+
+#ifdef UNDER_CE
+#define kBufferSize (1 << 13)
+#else
+#define kBufferSize (1 << 15)
+#endif
+
+#define kSignatureSearchLimit (1 << 22)
+
+static BoolInt FindSignature(CSzFile *stream, UInt64 *resPos)
+{
+ Byte buf[kBufferSize];
+ size_t numPrevBytes = 0;
+ *resPos = 0;
+ for (;;)
+ {
+ size_t processed, pos;
+ if (*resPos > kSignatureSearchLimit)
+ return False;
+ processed = kBufferSize - numPrevBytes;
+ if (File_Read(stream, buf + numPrevBytes, &processed) != 0)
+ return False;
+ processed += numPrevBytes;
+ if (processed < k7zStartHeaderSize ||
+ (processed == k7zStartHeaderSize && numPrevBytes != 0))
+ return False;
+ processed -= k7zStartHeaderSize;
+ for (pos = 0; pos <= processed; pos++)
+ {
+ for (; pos <= processed && buf[pos] != '7'; pos++);
+ if (pos > processed)
+ break;
+ if (memcmp(buf + pos, k7zSignature, k7zSignatureSize) == 0)
+ if (CrcCalc(buf + pos + 12, 20) == GetUi32(buf + pos + 8))
+ {
+ *resPos += pos;
+ return True;
+ }
+ }
+ *resPos += processed;
+ numPrevBytes = k7zStartHeaderSize;
+ memmove(buf, buf + processed, k7zStartHeaderSize);
+ }
+}
+
+static BoolInt DoesFileOrDirExist(const WCHAR *path)
+{
+ WIN32_FIND_DATAW fd;
+ HANDLE handle;
+ handle = FindFirstFileW(path, &fd);
+ if (handle == INVALID_HANDLE_VALUE)
+ return False;
+ FindClose(handle);
+ return True;
+}
+
+static WRes RemoveDirWithSubItems(WCHAR *path)
+{
+ WIN32_FIND_DATAW fd;
+ HANDLE handle;
+ WRes res = 0;
+ const size_t len = wcslen(path);
+ wcscpy(path + len, L"*");
+ handle = FindFirstFileW(path, &fd);
+ path[len] = L'\0';
+ if (handle == INVALID_HANDLE_VALUE)
+ return GetLastError();
+
+ for (;;)
+ {
+ if (wcscmp(fd.cFileName, L".") != 0 &&
+ wcscmp(fd.cFileName, L"..") != 0)
+ {
+ wcscpy(path + len, fd.cFileName);
+ if ((fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ {
+ wcscat(path, WSTRING_PATH_SEPARATOR);
+ res = RemoveDirWithSubItems(path);
+ }
+ else
+ {
+ SetFileAttributesW(path, 0);
+ if (DeleteFileW(path) == 0)
+ res = GetLastError();
+ }
+
+ if (res != 0)
+ break;
+ }
+
+ if (!FindNextFileW(handle, &fd))
+ {
+ res = GetLastError();
+ if (res == ERROR_NO_MORE_FILES)
+ res = 0;
+ break;
+ }
+ }
+
+ path[len] = L'\0';
+ FindClose(handle);
+ if (res == 0)
+ {
+ if (!RemoveDirectoryW(path))
+ res = GetLastError();
+ }
+ return res;
+}
+
+#ifdef _CONSOLE
+int Z7_CDECL main(void)
+#else
+int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
+ #ifdef UNDER_CE
+ LPWSTR
+ #else
+ LPSTR
+ #endif
+ lpCmdLine, int nCmdShow)
+#endif
+{
+ CFileInStream archiveStream;
+ CLookToRead2 lookStream;
+ CSzArEx db;
+ SRes res = SZ_OK;
+ ISzAlloc allocImp;
+ ISzAlloc allocTempImp;
+ WCHAR sfxPath[MAX_PATH + 2];
+ WCHAR path[MAX_PATH * 3 + 2];
+ #ifndef UNDER_CE
+ WCHAR workCurDir[MAX_PATH + 32];
+ #endif
+ size_t pathLen;
+ DWORD winRes;
+ const wchar_t *cmdLineParams;
+ const char *errorMessage = NULL;
+ BoolInt useShellExecute = True;
+ DWORD exitCode = 0;
+
+ LoadSecurityDlls();
+
+ #ifdef _CONSOLE
+ SetConsoleCtrlHandler(HandlerRoutine, TRUE);
+ #else
+ UNUSED_VAR(hInstance);
+ UNUSED_VAR(hPrevInstance);
+ UNUSED_VAR(lpCmdLine);
+ UNUSED_VAR(nCmdShow);
+ #endif
+
+ CrcGenerateTable();
+
+ allocImp.Alloc = SzAlloc;
+ allocImp.Free = SzFree;
+
+ allocTempImp.Alloc = SzAllocTemp;
+ allocTempImp.Free = SzFreeTemp;
+
+ FileInStream_CreateVTable(&archiveStream);
+ LookToRead2_CreateVTable(&lookStream, False);
+ lookStream.buf = NULL;
+
+ winRes = GetModuleFileNameW(NULL, sfxPath, MAX_PATH);
+ if (winRes == 0 || winRes > MAX_PATH)
+ return 1;
+ {
+ cmdLineParams = GetCommandLineW();
+ #ifndef UNDER_CE
+ {
+ BoolInt quoteMode = False;
+ for (;; cmdLineParams++)
+ {
+ const wchar_t c = *cmdLineParams;
+ if (c == L'\"')
+ quoteMode = !quoteMode;
+ else if (c == 0 || (c == L' ' && !quoteMode))
+ break;
+ }
+ }
+ #endif
+ }
+
+ {
+ unsigned i;
+ DWORD d;
+ winRes = GetTempPathW(MAX_PATH, path);
+ if (winRes == 0 || winRes > MAX_PATH)
+ return 1;
+ pathLen = wcslen(path);
+ d = (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId();
+
+ for (i = 0;; i++, d += GetTickCount())
+ {
+ if (i >= 100)
+ {
+ res = SZ_ERROR_FAIL;
+ break;
+ }
+ wcscpy(path + pathLen, L"7z");
+
+ {
+ wchar_t *s = path + wcslen(path);
+ UInt32 value = d;
+ unsigned k;
+ for (k = 0; k < 8; k++)
+ {
+ const unsigned t = value & 0xF;
+ value >>= 4;
+ s[7 - k] = (wchar_t)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
+ }
+ s[k] = '\0';
+ }
+
+ if (DoesFileOrDirExist(path))
+ continue;
+ if (CreateDirectoryW(path, NULL))
+ {
+ wcscat(path, WSTRING_PATH_SEPARATOR);
+ pathLen = wcslen(path);
+ break;
+ }
+ if (GetLastError() != ERROR_ALREADY_EXISTS)
+ {
+ res = SZ_ERROR_FAIL;
+ break;
+ }
+ }
+
+ #ifndef UNDER_CE
+ wcscpy(workCurDir, path);
+ #endif
+ if (res != SZ_OK)
+ errorMessage = "Can't create temp folder";
+ }
+
+ if (res != SZ_OK)
+ {
+ if (!errorMessage)
+ errorMessage = "Error";
+ PrintErrorMessage(errorMessage);
+ return 1;
+ }
+
+ if (InFile_OpenW(&archiveStream.file, sfxPath) != 0)
+ {
+ errorMessage = "can not open input file";
+ res = SZ_ERROR_FAIL;
+ }
+ else
+ {
+ UInt64 pos = 0;
+ if (!FindSignature(&archiveStream.file, &pos))
+ res = SZ_ERROR_FAIL;
+ else if (File_Seek(&archiveStream.file, (Int64 *)&pos, SZ_SEEK_SET) != 0)
+ res = SZ_ERROR_FAIL;
+ if (res != 0)
+ errorMessage = "Can't find 7z archive";
+ }
+
+ if (res == SZ_OK)
+ {
+ lookStream.buf = (Byte *)ISzAlloc_Alloc(&allocImp, kInputBufSize);
+ if (!lookStream.buf)
+ res = SZ_ERROR_MEM;
+ else
+ {
+ lookStream.bufSize = kInputBufSize;
+ lookStream.realStream = &archiveStream.vt;
+ LookToRead2_INIT(&lookStream)
+ }
+ }
+
+ SzArEx_Init(&db);
+
+ if (res == SZ_OK)
+ {
+ res = SzArEx_Open(&db, &lookStream.vt, &allocImp, &allocTempImp);
+ }
+
+ if (res == SZ_OK)
+ {
+ UInt32 executeFileIndex = (UInt32)(Int32)-1;
+ UInt32 minPrice = 1 << 30;
+ UInt32 i;
+ UInt32 blockIndex = 0xFFFFFFFF; /* it can have any value before first call (if outBuffer = 0) */
+ Byte *outBuffer = 0; /* it must be 0 before first call for each new archive. */
+ size_t outBufferSize = 0; /* it can have any value before first call (if outBuffer = 0) */
+
+ for (i = 0; i < db.NumFiles; i++)
+ {
+ size_t offset = 0;
+ size_t outSizeProcessed = 0;
+ WCHAR *temp;
+
+ if (SzArEx_GetFileNameUtf16(&db, i, NULL) >= MAX_PATH)
+ {
+ res = SZ_ERROR_FAIL;
+ break;
+ }
+
+ temp = path + pathLen;
+
+ SzArEx_GetFileNameUtf16(&db, i, (UInt16 *)temp);
+ {
+ res = SzArEx_Extract(&db, &lookStream.vt, i,
+ &blockIndex, &outBuffer, &outBufferSize,
+ &offset, &outSizeProcessed,
+ &allocImp, &allocTempImp);
+ if (res != SZ_OK)
+ break;
+ }
+ {
+ CSzFile outFile;
+ size_t processedSize;
+ size_t j;
+ size_t nameStartPos = 0;
+ for (j = 0; temp[j] != 0; j++)
+ {
+ if (temp[j] == '/')
+ {
+ temp[j] = 0;
+ MyCreateDir(path);
+ temp[j] = CHAR_PATH_SEPARATOR;
+ nameStartPos = j + 1;
+ }
+ }
+
+ if (SzArEx_IsDir(&db, i))
+ {
+ MyCreateDir(path);
+ continue;
+ }
+ else
+ {
+ unsigned extLen;
+ const WCHAR *name = temp + nameStartPos;
+ unsigned len = (unsigned)wcslen(name);
+ const unsigned nameLen = FindExt(temp + nameStartPos, &extLen);
+ const unsigned extPrice = FindItem(kExts, sizeof(kExts) / sizeof(kExts[0]), name + len - extLen, extLen);
+ const unsigned namePrice = FindItem(kNames, sizeof(kNames) / sizeof(kNames[0]), name, nameLen);
+
+ const unsigned price = namePrice + extPrice * 64 + (nameStartPos == 0 ? 0 : (1 << 12));
+ if (minPrice > price)
+ {
+ minPrice = price;
+ executeFileIndex = i;
+ useShellExecute = (extPrice != k_EXE_ExtIndex);
+ }
+
+ if (DoesFileOrDirExist(path))
+ {
+ errorMessage = "Duplicate file";
+ res = SZ_ERROR_FAIL;
+ break;
+ }
+ if (OutFile_OpenW(&outFile, path))
+ {
+ errorMessage = "Can't open output file";
+ res = SZ_ERROR_FAIL;
+ break;
+ }
+ }
+
+ processedSize = outSizeProcessed;
+ if (File_Write(&outFile, outBuffer + offset, &processedSize) != 0 || processedSize != outSizeProcessed)
+ {
+ errorMessage = "Can't write output file";
+ res = SZ_ERROR_FAIL;
+ }
+
+ #ifdef USE_WINDOWS_FILE
+ if (SzBitWithVals_Check(&db.MTime, i))
+ {
+ const CNtfsFileTime *t = db.MTime.Vals + i;
+ FILETIME mTime;
+ mTime.dwLowDateTime = t->Low;
+ mTime.dwHighDateTime = t->High;
+ SetFileTime(outFile.handle, NULL, NULL, &mTime);
+ }
+ #endif
+
+ {
+ const SRes res2 = File_Close(&outFile);
+ if (res != SZ_OK)
+ break;
+ if (res2 != SZ_OK)
+ {
+ res = res2;
+ break;
+ }
+ }
+ #ifdef USE_WINDOWS_FILE
+ if (SzBitWithVals_Check(&db.Attribs, i))
+ SetFileAttributesW(path, db.Attribs.Vals[i]);
+ #endif
+ }
+ }
+
+ if (res == SZ_OK)
+ {
+ if (executeFileIndex == (UInt32)(Int32)-1)
+ {
+ errorMessage = "There is no file to execute";
+ res = SZ_ERROR_FAIL;
+ }
+ else
+ {
+ WCHAR *temp = path + pathLen;
+ UInt32 j;
+ SzArEx_GetFileNameUtf16(&db, executeFileIndex, (UInt16 *)temp);
+ for (j = 0; temp[j] != 0; j++)
+ if (temp[j] == '/')
+ temp[j] = CHAR_PATH_SEPARATOR;
+ }
+ }
+ ISzAlloc_Free(&allocImp, outBuffer);
+ }
+
+ SzArEx_Free(&db, &allocImp);
+
+ ISzAlloc_Free(&allocImp, lookStream.buf);
+
+ File_Close(&archiveStream.file);
+
+ if (res == SZ_OK)
+ {
+ HANDLE hProcess = 0;
+
+ #ifndef UNDER_CE
+ WCHAR oldCurDir[MAX_PATH + 2];
+ oldCurDir[0] = 0;
+ {
+ const DWORD needLen = GetCurrentDirectory(MAX_PATH + 1, oldCurDir);
+ if (needLen == 0 || needLen > MAX_PATH)
+ oldCurDir[0] = 0;
+ SetCurrentDirectory(workCurDir);
+ }
+ #endif
+
+ if (useShellExecute)
+ {
+ SHELLEXECUTEINFO ei;
+ UINT32 executeRes;
+ BOOL success;
+
+ memset(&ei, 0, sizeof(ei));
+ ei.cbSize = sizeof(ei);
+ ei.lpFile = path;
+ ei.fMask = SEE_MASK_NOCLOSEPROCESS
+ #ifndef UNDER_CE
+ | SEE_MASK_FLAG_DDEWAIT
+ #endif
+ /* | SEE_MASK_NO_CONSOLE */
+ ;
+ if (wcslen(cmdLineParams) != 0)
+ ei.lpParameters = cmdLineParams;
+ ei.nShow = SW_SHOWNORMAL; /* SW_HIDE; */
+ success = ShellExecuteEx(&ei);
+ executeRes = (UINT32)(UINT_PTR)ei.hInstApp;
+ if (!success || (executeRes <= 32 && executeRes != 0)) /* executeRes = 0 in Windows CE */
+ res = SZ_ERROR_FAIL;
+ else
+ hProcess = ei.hProcess;
+ }
+ else
+ {
+ STARTUPINFOW si;
+ PROCESS_INFORMATION pi;
+ WCHAR cmdLine[MAX_PATH * 3];
+
+ wcscpy(cmdLine, path);
+ wcscat(cmdLine, cmdLineParams);
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ if (CreateProcessW(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi) == 0)
+ res = SZ_ERROR_FAIL;
+ else
+ {
+ CloseHandle(pi.hThread);
+ hProcess = pi.hProcess;
+ }
+ }
+
+ if (hProcess != 0)
+ {
+ WaitForSingleObject(hProcess, INFINITE);
+ if (!GetExitCodeProcess(hProcess, &exitCode))
+ exitCode = 1;
+ CloseHandle(hProcess);
+ }
+
+ #ifndef UNDER_CE
+ SetCurrentDirectory(oldCurDir);
+ #endif
+ }
+
+ path[pathLen] = L'\0';
+ RemoveDirWithSubItems(path);
+
+ if (res == SZ_OK)
+ return (int)exitCode;
+
+ {
+ if (res == SZ_ERROR_UNSUPPORTED)
+ errorMessage = "Decoder doesn't support this archive";
+ else if (res == SZ_ERROR_MEM)
+ errorMessage = "Can't allocate required memory";
+ else if (res == SZ_ERROR_CRC)
+ errorMessage = "CRC error";
+ else
+ {
+ if (!errorMessage)
+ errorMessage = "ERROR";
+ }
+
+ if (errorMessage)
+ PrintErrorMessage(errorMessage);
+ }
+ return 1;
+}
diff --git a/C/Util/SfxSetup/SfxSetup.dsp b/C/Util/SfxSetup/SfxSetup.dsp
index be9de6d..60439a6 100644
--- a/C/Util/SfxSetup/SfxSetup.dsp
+++ b/C/Util/SfxSetup/SfxSetup.dsp
@@ -1,231 +1,231 @@
-# Microsoft Developer Studio Project File - Name="SfxSetup" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Application" 0x0101
-
-CFG=SfxSetup - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "SfxSetup.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "SfxSetup.mak" CFG="SfxSetup - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "SfxSetup - Win32 Release" (based on "Win32 (x86) Application")
-!MESSAGE "SfxSetup - Win32 Debug" (based on "Win32 (x86) Application")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "SfxSetup - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /W4 /WX /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /Yu"Precomp.h" /FD /c
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x419 /d "NDEBUG"
-# ADD RSC /l 0x419 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
-
-!ELSEIF "$(CFG)" == "SfxSetup - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
-# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /Yu"Precomp.h" /FD /GZ /c
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x419 /d "_DEBUG"
-# ADD RSC /l 0x419 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
-
-!ENDIF
-
-# Begin Target
-
-# Name "SfxSetup - Win32 Release"
-# Name "SfxSetup - Win32 Debug"
-# Begin Group "Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\7z.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zAlloc.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zAlloc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zArcIn.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zBuf.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zBuf.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zCrc.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zCrc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zCrcOpt.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zDec.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zFile.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zFile.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zStream.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\7zTypes.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Bcj2.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Bcj2.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Bra.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Bra.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Bra86.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\BraIA64.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\CpuArch.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\CpuArch.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Delta.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Delta.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\DllSecur.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\DllSecur.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Lzma2Dec.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Lzma2Dec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzmaDec.c
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\LzmaDec.h
-# End Source File
-# End Group
-# Begin Group "Spec"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=.\Precomp.c
-# ADD CPP /Yc"Precomp.h"
-# End Source File
-# Begin Source File
-
-SOURCE=.\Precomp.h
-# End Source File
-# End Group
-# Begin Source File
-
-SOURCE=.\SfxSetup.c
-# End Source File
-# End Target
-# End Project
+# Microsoft Developer Studio Project File - Name="SfxSetup" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=SfxSetup - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "SfxSetup.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "SfxSetup.mak" CFG="SfxSetup - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "SfxSetup - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "SfxSetup - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "SfxSetup - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /W4 /WX /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /Yu"Precomp.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+
+!ELSEIF "$(CFG)" == "SfxSetup - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_UNICODE" /D "UNICODE" /Yu"Precomp.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "SfxSetup - Win32 Release"
+# Name "SfxSetup - Win32 Debug"
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\7z.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zAlloc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zAlloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zArcIn.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zBuf.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zBuf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zCrc.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zCrcOpt.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zDec.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zFile.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zFile.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zStream.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Bcj2.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Bcj2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Bra.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Bra.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Bra86.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\BraIA64.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\CpuArch.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\CpuArch.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Delta.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Delta.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\DllSecur.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\DllSecur.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Lzma2Dec.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Lzma2Dec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzmaDec.c
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\LzmaDec.h
+# End Source File
+# End Group
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\Precomp.c
+# ADD CPP /Yc"Precomp.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\Precomp.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\SfxSetup.c
+# End Source File
+# End Target
+# End Project
diff --git a/C/Util/SfxSetup/SfxSetup.dsw b/C/Util/SfxSetup/SfxSetup.dsw
index 128fcdd..ea23111 100644
--- a/C/Util/SfxSetup/SfxSetup.dsw
+++ b/C/Util/SfxSetup/SfxSetup.dsw
@@ -1,29 +1,29 @@
-Microsoft Developer Studio Workspace File, Format Version 6.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "SfxSetup"=.\SfxSetup.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
-
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "SfxSetup"=.\SfxSetup.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/C/Util/SfxSetup/makefile b/C/Util/SfxSetup/makefile
index c9f59cc..bc0cf8b 100644
--- a/C/Util/SfxSetup/makefile
+++ b/C/Util/SfxSetup/makefile
@@ -1,37 +1,40 @@
-PROG = 7zS2.sfx
-MY_FIXED = 1
-
-C_OBJS = \
- $O\7zAlloc.obj \
- $O\7zArcIn.obj \
- $O\7zBuf.obj \
- $O\7zBuf2.obj \
- $O\7zCrc.obj \
- $O\7zCrcOpt.obj \
- $O\7zFile.obj \
- $O\7zDec.obj \
- $O\7zStream.obj \
- $O\Bcj2.obj \
- $O\Bra.obj \
- $O\Bra86.obj \
- $O\BraIA64.obj \
- $O\CpuArch.obj \
- $O\Delta.obj \
- $O\DllSecur.obj \
- $O\Lzma2Dec.obj \
- $O\LzmaDec.obj \
-
-7Z_OBJS = \
- $O\SfxSetup.obj \
-
-OBJS = \
- $(7Z_OBJS) \
- $(C_OBJS) \
- $O\resource.res
-
-!include "../../../CPP/Build.mak"
-
-$(7Z_OBJS): $(*B).c
- $(COMPL_O1)
-$(C_OBJS): ../../$(*B).c
- $(COMPL_O1)
+PROG = 7zS2.sfx
+MY_FIXED = 1
+
+CFLAGS = $(CFLAGS) \
+ -DZ7_EXTRACT_ONLY \
+
+C_OBJS = \
+ $O\7zAlloc.obj \
+ $O\7zArcIn.obj \
+ $O\7zBuf.obj \
+ $O\7zBuf2.obj \
+ $O\7zCrc.obj \
+ $O\7zCrcOpt.obj \
+ $O\7zFile.obj \
+ $O\7zDec.obj \
+ $O\7zStream.obj \
+ $O\Bcj2.obj \
+ $O\Bra.obj \
+ $O\Bra86.obj \
+ $O\BraIA64.obj \
+ $O\CpuArch.obj \
+ $O\Delta.obj \
+ $O\DllSecur.obj \
+ $O\Lzma2Dec.obj \
+ $O\LzmaDec.obj \
+
+7Z_OBJS = \
+ $O\SfxSetup.obj \
+
+OBJS = \
+ $(7Z_OBJS) \
+ $(C_OBJS) \
+ $O\resource.res
+
+!include "../../../CPP/Build.mak"
+
+$(7Z_OBJS): $(*B).c
+ $(COMPL_O1)
+$(C_OBJS): ../../$(*B).c
+ $(COMPL_O1)
diff --git a/C/Util/SfxSetup/makefile_con b/C/Util/SfxSetup/makefile_con
index 6f604ed..9f4b916 100644
--- a/C/Util/SfxSetup/makefile_con
+++ b/C/Util/SfxSetup/makefile_con
@@ -1,38 +1,40 @@
-PROG = 7zS2con.sfx
-MY_FIXED = 1
-CFLAGS = $(CFLAGS) -D_CONSOLE
-
-C_OBJS = \
- $O\7zAlloc.obj \
- $O\7zArcIn.obj \
- $O\7zBuf.obj \
- $O\7zBuf2.obj \
- $O\7zCrc.obj \
- $O\7zCrcOpt.obj \
- $O\7zFile.obj \
- $O\7zDec.obj \
- $O\7zStream.obj \
- $O\Bcj2.obj \
- $O\Bra.obj \
- $O\Bra86.obj \
- $O\BraIA64.obj \
- $O\CpuArch.obj \
- $O\Delta.obj \
- $O\DllSecur.obj \
- $O\Lzma2Dec.obj \
- $O\LzmaDec.obj \
-
-7Z_OBJS = \
- $O\SfxSetup.obj \
-
-OBJS = \
- $(7Z_OBJS) \
- $(C_OBJS) \
- $O\resource.res
-
-!include "../../../CPP/Build.mak"
-
-$(7Z_OBJS): $(*B).c
- $(COMPL_O1)
-$(C_OBJS): ../../$(*B).c
- $(COMPL_O1)
+PROG = 7zS2con.sfx
+MY_FIXED = 1
+
+CFLAGS = $(CFLAGS) -D_CONSOLE \
+ -DZ7_EXTRACT_ONLY \
+
+C_OBJS = \
+ $O\7zAlloc.obj \
+ $O\7zArcIn.obj \
+ $O\7zBuf.obj \
+ $O\7zBuf2.obj \
+ $O\7zCrc.obj \
+ $O\7zCrcOpt.obj \
+ $O\7zFile.obj \
+ $O\7zDec.obj \
+ $O\7zStream.obj \
+ $O\Bcj2.obj \
+ $O\Bra.obj \
+ $O\Bra86.obj \
+ $O\BraIA64.obj \
+ $O\CpuArch.obj \
+ $O\Delta.obj \
+ $O\DllSecur.obj \
+ $O\Lzma2Dec.obj \
+ $O\LzmaDec.obj \
+
+7Z_OBJS = \
+ $O\SfxSetup.obj \
+
+OBJS = \
+ $(7Z_OBJS) \
+ $(C_OBJS) \
+ $O\resource.res
+
+!include "../../../CPP/Build.mak"
+
+$(7Z_OBJS): $(*B).c
+ $(COMPL_O1)
+$(C_OBJS): ../../$(*B).c
+ $(COMPL_O1)
diff --git a/C/Util/SfxSetup/resource.rc b/C/Util/SfxSetup/resource.rc
index 64f4e2c..0c1637f 100644
--- a/C/Util/SfxSetup/resource.rc
+++ b/C/Util/SfxSetup/resource.rc
@@ -1,5 +1,5 @@
-#include "../../7zVersion.rc"
-
-MY_VERSION_INFO_APP("7z Setup SFX small", "7zS2.sfx")
-
-1 ICON "setup.ico"
+#include "../../7zVersion.rc"
+
+MY_VERSION_INFO_APP("7z Setup SFX small", "7zS2.sfx")
+
+1 ICON "setup.ico"
diff --git a/C/Xz.c b/C/Xz.c
index 7e061d6..4ad0710 100644
--- a/C/Xz.c
+++ b/C/Xz.c
@@ -1,90 +1,90 @@
-/* Xz.c - Xz
-2017-05-12 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "7zCrc.h"
-#include "CpuArch.h"
-#include "Xz.h"
-#include "XzCrc64.h"
-
-const Byte XZ_SIG[XZ_SIG_SIZE] = { 0xFD, '7', 'z', 'X', 'Z', 0 };
-/* const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE] = { 'Y', 'Z' }; */
-
-unsigned Xz_WriteVarInt(Byte *buf, UInt64 v)
-{
- unsigned i = 0;
- do
- {
- buf[i++] = (Byte)((v & 0x7F) | 0x80);
- v >>= 7;
- }
- while (v != 0);
- buf[(size_t)i - 1] &= 0x7F;
- return i;
-}
-
-void Xz_Construct(CXzStream *p)
-{
- p->numBlocks = 0;
- p->blocks = NULL;
- p->flags = 0;
-}
-
-void Xz_Free(CXzStream *p, ISzAllocPtr alloc)
-{
- ISzAlloc_Free(alloc, p->blocks);
- p->numBlocks = 0;
- p->blocks = NULL;
-}
-
-unsigned XzFlags_GetCheckSize(CXzStreamFlags f)
-{
- unsigned t = XzFlags_GetCheckType(f);
- return (t == 0) ? 0 : (4 << ((t - 1) / 3));
-}
-
-void XzCheck_Init(CXzCheck *p, unsigned mode)
-{
- p->mode = mode;
- switch (mode)
- {
- case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break;
- case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break;
- case XZ_CHECK_SHA256: Sha256_Init(&p->sha); break;
- }
-}
-
-void XzCheck_Update(CXzCheck *p, const void *data, size_t size)
-{
- switch (p->mode)
- {
- case XZ_CHECK_CRC32: p->crc = CrcUpdate(p->crc, data, size); break;
- case XZ_CHECK_CRC64: p->crc64 = Crc64Update(p->crc64, data, size); break;
- case XZ_CHECK_SHA256: Sha256_Update(&p->sha, (const Byte *)data, size); break;
- }
-}
-
-int XzCheck_Final(CXzCheck *p, Byte *digest)
-{
- switch (p->mode)
- {
- case XZ_CHECK_CRC32:
- SetUi32(digest, CRC_GET_DIGEST(p->crc));
- break;
- case XZ_CHECK_CRC64:
- {
- int i;
- UInt64 v = CRC64_GET_DIGEST(p->crc64);
- for (i = 0; i < 8; i++, v >>= 8)
- digest[i] = (Byte)(v & 0xFF);
- break;
- }
- case XZ_CHECK_SHA256:
- Sha256_Final(&p->sha, digest);
- break;
- default:
- return 0;
- }
- return 1;
-}
+/* Xz.c - Xz
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "7zCrc.h"
+#include "CpuArch.h"
+#include "Xz.h"
+#include "XzCrc64.h"
+
+const Byte XZ_SIG[XZ_SIG_SIZE] = { 0xFD, '7', 'z', 'X', 'Z', 0 };
+/* const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE] = { 'Y', 'Z' }; */
+
+unsigned Xz_WriteVarInt(Byte *buf, UInt64 v)
+{
+ unsigned i = 0;
+ do
+ {
+ buf[i++] = (Byte)((v & 0x7F) | 0x80);
+ v >>= 7;
+ }
+ while (v != 0);
+ buf[(size_t)i - 1] &= 0x7F;
+ return i;
+}
+
+void Xz_Construct(CXzStream *p)
+{
+ p->numBlocks = 0;
+ p->blocks = NULL;
+ p->flags = 0;
+}
+
+void Xz_Free(CXzStream *p, ISzAllocPtr alloc)
+{
+ ISzAlloc_Free(alloc, p->blocks);
+ p->numBlocks = 0;
+ p->blocks = NULL;
+}
+
+unsigned XzFlags_GetCheckSize(CXzStreamFlags f)
+{
+ unsigned t = XzFlags_GetCheckType(f);
+ return (t == 0) ? 0 : ((unsigned)4 << ((t - 1) / 3));
+}
+
+void XzCheck_Init(CXzCheck *p, unsigned mode)
+{
+ p->mode = mode;
+ switch (mode)
+ {
+ case XZ_CHECK_CRC32: p->crc = CRC_INIT_VAL; break;
+ case XZ_CHECK_CRC64: p->crc64 = CRC64_INIT_VAL; break;
+ case XZ_CHECK_SHA256: Sha256_Init(&p->sha); break;
+ }
+}
+
+void XzCheck_Update(CXzCheck *p, const void *data, size_t size)
+{
+ switch (p->mode)
+ {
+ case XZ_CHECK_CRC32: p->crc = CrcUpdate(p->crc, data, size); break;
+ case XZ_CHECK_CRC64: p->crc64 = Crc64Update(p->crc64, data, size); break;
+ case XZ_CHECK_SHA256: Sha256_Update(&p->sha, (const Byte *)data, size); break;
+ }
+}
+
+int XzCheck_Final(CXzCheck *p, Byte *digest)
+{
+ switch (p->mode)
+ {
+ case XZ_CHECK_CRC32:
+ SetUi32(digest, CRC_GET_DIGEST(p->crc))
+ break;
+ case XZ_CHECK_CRC64:
+ {
+ int i;
+ UInt64 v = CRC64_GET_DIGEST(p->crc64);
+ for (i = 0; i < 8; i++, v >>= 8)
+ digest[i] = (Byte)(v & 0xFF);
+ break;
+ }
+ case XZ_CHECK_SHA256:
+ Sha256_Final(&p->sha, digest);
+ break;
+ default:
+ return 0;
+ }
+ return 1;
+}
diff --git a/C/Xz.h b/C/Xz.h
index fad56a3..d5001f6 100644
--- a/C/Xz.h
+++ b/C/Xz.h
@@ -1,460 +1,535 @@
-/* Xz.h - Xz interface
-2018-07-04 : Igor Pavlov : Public domain */
-
-#ifndef __XZ_H
-#define __XZ_H
-
-#include "Sha256.h"
-
-EXTERN_C_BEGIN
-
-#define XZ_ID_Subblock 1
-#define XZ_ID_Delta 3
-#define XZ_ID_X86 4
-#define XZ_ID_PPC 5
-#define XZ_ID_IA64 6
-#define XZ_ID_ARM 7
-#define XZ_ID_ARMT 8
-#define XZ_ID_SPARC 9
-#define XZ_ID_LZMA2 0x21
-
-unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value);
-unsigned Xz_WriteVarInt(Byte *buf, UInt64 v);
-
-/* ---------- xz block ---------- */
-
-#define XZ_BLOCK_HEADER_SIZE_MAX 1024
-
-#define XZ_NUM_FILTERS_MAX 4
-#define XZ_BF_NUM_FILTERS_MASK 3
-#define XZ_BF_PACK_SIZE (1 << 6)
-#define XZ_BF_UNPACK_SIZE (1 << 7)
-
-#define XZ_FILTER_PROPS_SIZE_MAX 20
-
-typedef struct
-{
- UInt64 id;
- UInt32 propsSize;
- Byte props[XZ_FILTER_PROPS_SIZE_MAX];
-} CXzFilter;
-
-typedef struct
-{
- UInt64 packSize;
- UInt64 unpackSize;
- Byte flags;
- CXzFilter filters[XZ_NUM_FILTERS_MAX];
-} CXzBlock;
-
-#define XzBlock_GetNumFilters(p) (((p)->flags & XZ_BF_NUM_FILTERS_MASK) + 1)
-#define XzBlock_HasPackSize(p) (((p)->flags & XZ_BF_PACK_SIZE) != 0)
-#define XzBlock_HasUnpackSize(p) (((p)->flags & XZ_BF_UNPACK_SIZE) != 0)
-#define XzBlock_HasUnsupportedFlags(p) (((p)->flags & ~(XZ_BF_NUM_FILTERS_MASK | XZ_BF_PACK_SIZE | XZ_BF_UNPACK_SIZE)) != 0)
-
-SRes XzBlock_Parse(CXzBlock *p, const Byte *header);
-SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, BoolInt *isIndex, UInt32 *headerSizeRes);
-
-/* ---------- xz stream ---------- */
-
-#define XZ_SIG_SIZE 6
-#define XZ_FOOTER_SIG_SIZE 2
-
-extern const Byte XZ_SIG[XZ_SIG_SIZE];
-
-/*
-extern const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE];
-*/
-
-#define XZ_FOOTER_SIG_0 'Y'
-#define XZ_FOOTER_SIG_1 'Z'
-
-#define XZ_STREAM_FLAGS_SIZE 2
-#define XZ_STREAM_CRC_SIZE 4
-
-#define XZ_STREAM_HEADER_SIZE (XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE)
-#define XZ_STREAM_FOOTER_SIZE (XZ_FOOTER_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE + 4)
-
-#define XZ_CHECK_MASK 0xF
-#define XZ_CHECK_NO 0
-#define XZ_CHECK_CRC32 1
-#define XZ_CHECK_CRC64 4
-#define XZ_CHECK_SHA256 10
-
-typedef struct
-{
- unsigned mode;
- UInt32 crc;
- UInt64 crc64;
- CSha256 sha;
-} CXzCheck;
-
-void XzCheck_Init(CXzCheck *p, unsigned mode);
-void XzCheck_Update(CXzCheck *p, const void *data, size_t size);
-int XzCheck_Final(CXzCheck *p, Byte *digest);
-
-typedef UInt16 CXzStreamFlags;
-
-#define XzFlags_IsSupported(f) ((f) <= XZ_CHECK_MASK)
-#define XzFlags_GetCheckType(f) ((f) & XZ_CHECK_MASK)
-#define XzFlags_HasDataCrc32(f) (Xz_GetCheckType(f) == XZ_CHECK_CRC32)
-unsigned XzFlags_GetCheckSize(CXzStreamFlags f);
-
-SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf);
-SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream);
-
-typedef struct
-{
- UInt64 unpackSize;
- UInt64 totalSize;
-} CXzBlockSizes;
-
-typedef struct
-{
- CXzStreamFlags flags;
- size_t numBlocks;
- CXzBlockSizes *blocks;
- UInt64 startOffset;
-} CXzStream;
-
-void Xz_Construct(CXzStream *p);
-void Xz_Free(CXzStream *p, ISzAllocPtr alloc);
-
-#define XZ_SIZE_OVERFLOW ((UInt64)(Int64)-1)
-
-UInt64 Xz_GetUnpackSize(const CXzStream *p);
-UInt64 Xz_GetPackSize(const CXzStream *p);
-
-typedef struct
-{
- size_t num;
- size_t numAllocated;
- CXzStream *streams;
-} CXzs;
-
-void Xzs_Construct(CXzs *p);
-void Xzs_Free(CXzs *p, ISzAllocPtr alloc);
-SRes Xzs_ReadBackward(CXzs *p, ILookInStream *inStream, Int64 *startOffset, ICompressProgress *progress, ISzAllocPtr alloc);
-
-UInt64 Xzs_GetNumBlocks(const CXzs *p);
-UInt64 Xzs_GetUnpackSize(const CXzs *p);
-
-
-// ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder
-
-typedef enum
-{
- CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */
- CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
- CODER_STATUS_NOT_FINISHED, /* stream was not finished */
- CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */
-} ECoderStatus;
-
-
-// ECoderFinishMode values are identical to ELzmaFinishMode
-
-typedef enum
-{
- CODER_FINISH_ANY, /* finish at any point */
- CODER_FINISH_END /* block must be finished at the end */
-} ECoderFinishMode;
-
-
-typedef struct _IStateCoder
-{
- void *p;
- void (*Free)(void *p, ISzAllocPtr alloc);
- SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAllocPtr alloc);
- void (*Init)(void *p);
- SRes (*Code2)(void *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
- int srcWasFinished, ECoderFinishMode finishMode,
- // int *wasFinished,
- ECoderStatus *status);
- SizeT (*Filter)(void *p, Byte *data, SizeT size);
-} IStateCoder;
-
-
-
-#define MIXCODER_NUM_FILTERS_MAX 4
-
-typedef struct
-{
- ISzAllocPtr alloc;
- Byte *buf;
- unsigned numCoders;
-
- Byte *outBuf;
- size_t outBufSize;
- size_t outWritten; // is equal to lzmaDecoder.dicPos (in outBuf mode)
- BoolInt wasFinished;
- SRes res;
- ECoderStatus status;
- // BoolInt SingleBufMode;
-
- int finished[MIXCODER_NUM_FILTERS_MAX - 1];
- size_t pos[MIXCODER_NUM_FILTERS_MAX - 1];
- size_t size[MIXCODER_NUM_FILTERS_MAX - 1];
- UInt64 ids[MIXCODER_NUM_FILTERS_MAX];
- SRes results[MIXCODER_NUM_FILTERS_MAX];
- IStateCoder coders[MIXCODER_NUM_FILTERS_MAX];
-} CMixCoder;
-
-
-typedef enum
-{
- XZ_STATE_STREAM_HEADER,
- XZ_STATE_STREAM_INDEX,
- XZ_STATE_STREAM_INDEX_CRC,
- XZ_STATE_STREAM_FOOTER,
- XZ_STATE_STREAM_PADDING,
- XZ_STATE_BLOCK_HEADER,
- XZ_STATE_BLOCK,
- XZ_STATE_BLOCK_FOOTER
-} EXzState;
-
-
-typedef struct
-{
- EXzState state;
- UInt32 pos;
- unsigned alignPos;
- unsigned indexPreSize;
-
- CXzStreamFlags streamFlags;
-
- UInt32 blockHeaderSize;
- UInt64 packSize;
- UInt64 unpackSize;
-
- UInt64 numBlocks; // number of finished blocks in current stream
- UInt64 indexSize;
- UInt64 indexPos;
- UInt64 padSize;
-
- UInt64 numStartedStreams;
- UInt64 numFinishedStreams;
- UInt64 numTotalBlocks;
-
- UInt32 crc;
- CMixCoder decoder;
- CXzBlock block;
- CXzCheck check;
- CSha256 sha;
-
- BoolInt parseMode;
- BoolInt headerParsedOk;
- BoolInt decodeToStreamSignature;
- unsigned decodeOnlyOneBlock;
-
- Byte *outBuf;
- size_t outBufSize;
- size_t outDataWritten; // the size of data in (outBuf) that were fully unpacked
-
- Byte shaDigest[SHA256_DIGEST_SIZE];
- Byte buf[XZ_BLOCK_HEADER_SIZE_MAX];
-} CXzUnpacker;
-
-/* alloc : aligned for cache line allocation is better */
-void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc);
-void XzUnpacker_Init(CXzUnpacker *p);
-void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize);
-void XzUnpacker_Free(CXzUnpacker *p);
-
-/*
- XzUnpacker
- The sequence for decoding functions:
- {
- XzUnpacker_Construct()
- [Decoding_Calls]
- XzUnpacker_Free()
- }
-
- [Decoding_Calls]
-
- There are 3 types of interfaces for [Decoding_Calls] calls:
-
- Interface-1 : Partial output buffers:
- {
- XzUnpacker_Init()
- for()
- XzUnpacker_Code();
- }
-
- Interface-2 : Direct output buffer:
- Use it, if you know exact size of decoded data, and you need
- whole xz unpacked data in one output buffer.
- xz unpacker doesn't allocate additional buffer for lzma2 dictionary in that mode.
- {
- XzUnpacker_Init()
- XzUnpacker_SetOutBufMode(); // to set output buffer and size
- for()
- XzUnpacker_Code(); // (dest = NULL) in XzUnpacker_Code()
- }
-
- Interface-3 : Direct output buffer : One call full decoding
- It unpacks whole input buffer to output buffer in one call.
- It uses Interface-2 internally.
- {
- XzUnpacker_CodeFull()
- }
-*/
-
-/*
-finishMode:
- It has meaning only if the decoding reaches output limit (*destLen).
- CODER_FINISH_ANY - use smallest number of input bytes
- CODER_FINISH_END - read EndOfStream marker after decoding
-
-Returns:
- SZ_OK
- status:
- CODER_STATUS_NOT_FINISHED,
- CODER_STATUS_NEEDS_MORE_INPUT - maybe there are more xz streams,
- call XzUnpacker_IsStreamWasFinished to check that current stream was finished
- SZ_ERROR_MEM - Memory allocation error
- SZ_ERROR_DATA - Data error
- SZ_ERROR_UNSUPPORTED - Unsupported method or method properties
- SZ_ERROR_CRC - CRC error
- // SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
-
- SZ_ERROR_NO_ARCHIVE - the error with xz Stream Header with one of the following reasons:
- - xz Stream Signature failure
- - CRC32 of xz Stream Header is failed
- - The size of Stream padding is not multiple of four bytes.
- It's possible to get that error, if xz stream was finished and the stream
- contains some another data. In that case you can call XzUnpacker_GetExtraSize()
- function to get real size of xz stream.
-*/
-
-
-SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
- const Byte *src, SizeT *srcLen, int srcFinished,
- ECoderFinishMode finishMode, ECoderStatus *status);
-
-SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen,
- const Byte *src, SizeT *srcLen,
- ECoderFinishMode finishMode, ECoderStatus *status);
-
-BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p);
-
-/*
-XzUnpacker_GetExtraSize() returns then number of uncofirmed bytes,
- if it's in (XZ_STATE_STREAM_HEADER) state or in (XZ_STATE_STREAM_PADDING) state.
-These bytes can be some bytes after xz archive, or
-it can be start of new xz stream.
-
-Call XzUnpacker_GetExtraSize() after XzUnpacker_Code() function to detect real size of
-xz stream in two cases, if XzUnpacker_Code() returns:
- res == SZ_OK && status == CODER_STATUS_NEEDS_MORE_INPUT
- res == SZ_ERROR_NO_ARCHIVE
-*/
-
-UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p);
-
-
-/*
- for random block decoding:
- XzUnpacker_Init();
- set CXzUnpacker::streamFlags
- XzUnpacker_PrepareToRandomBlockDecoding()
- loop
- {
- XzUnpacker_Code()
- XzUnpacker_IsBlockFinished()
- }
-*/
-
-void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p);
-BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p);
-
-#define XzUnpacker_GetPackSizeForIndex(p) ((p)->packSize + (p)->blockHeaderSize + XzFlags_GetCheckSize((p)->streamFlags))
-
-
-
-/* ---------- Multi Threading Decoding ---------- */
-
-
-typedef struct
-{
- size_t inBufSize_ST;
- size_t outStep_ST;
- BoolInt ignoreErrors;
-
- #ifndef _7ZIP_ST
- unsigned numThreads;
- size_t inBufSize_MT;
- size_t memUseMax;
- #endif
-} CXzDecMtProps;
-
-void XzDecMtProps_Init(CXzDecMtProps *p);
-
-
-typedef void * CXzDecMtHandle;
-
-/*
- alloc : XzDecMt uses CAlignOffsetAlloc for addresses allocated by (alloc).
- allocMid : for big allocations, aligned allocation is better
-*/
-
-CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid);
-void XzDecMt_Destroy(CXzDecMtHandle p);
-
-
-typedef struct
-{
- Byte UnpackSize_Defined;
- Byte NumStreams_Defined;
- Byte NumBlocks_Defined;
-
- Byte DataAfterEnd;
- Byte DecodingTruncated; // Decoding was Truncated, we need only partial output data
-
- UInt64 InSize; // pack size processed
- UInt64 OutSize;
-
- UInt64 NumStreams;
- UInt64 NumBlocks;
-
- SRes DecodeRes;
- SRes ReadRes;
- SRes ProgressRes;
- SRes CombinedRes;
- SRes CombinedRes_Type;
-
-} CXzStatInfo;
-
-void XzStatInfo_Clear(CXzStatInfo *p);
-
-/*
-XzDecMt_Decode()
-SRes:
- SZ_OK - OK
- SZ_ERROR_MEM - Memory allocation error
- SZ_ERROR_NO_ARCHIVE - is not xz archive
- SZ_ERROR_ARCHIVE - Headers error
- SZ_ERROR_DATA - Data Error
- SZ_ERROR_CRC - CRC Error
- SZ_ERROR_INPUT_EOF - it needs more input data
- SZ_ERROR_WRITE - ISeqOutStream error
- (SZ_ERROR_READ) - ISeqInStream errors
- (SZ_ERROR_PROGRESS) - ICompressProgress errors
- // SZ_ERROR_THREAD - error in multi-threading functions
- MY_SRes_HRESULT_FROM_WRes(WRes_error) - error in multi-threading function
-*/
-
-SRes XzDecMt_Decode(CXzDecMtHandle p,
- const CXzDecMtProps *props,
- const UInt64 *outDataSize, // NULL means undefined
- int finishMode, // 0 - partial unpacking is allowed, 1 - xz stream(s) must be finished
- ISeqOutStream *outStream,
- // Byte *outBuf, size_t *outBufSize,
- ISeqInStream *inStream,
- // const Byte *inData, size_t inDataSize,
- CXzStatInfo *stat,
- int *isMT, // 0 means that ST (Single-Thread) version was used
- ICompressProgress *progress);
-
-EXTERN_C_END
-
-#endif
+/* Xz.h - Xz interface
+2023-04-13 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_XZ_H
+#define ZIP7_INC_XZ_H
+
+#include "Sha256.h"
+#include "Delta.h"
+
+EXTERN_C_BEGIN
+
+#define XZ_ID_Subblock 1
+#define XZ_ID_Delta 3
+#define XZ_ID_X86 4
+#define XZ_ID_PPC 5
+#define XZ_ID_IA64 6
+#define XZ_ID_ARM 7
+#define XZ_ID_ARMT 8
+#define XZ_ID_SPARC 9
+#define XZ_ID_ARM64 0xa
+#define XZ_ID_LZMA2 0x21
+
+unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value);
+unsigned Xz_WriteVarInt(Byte *buf, UInt64 v);
+
+/* ---------- xz block ---------- */
+
+#define XZ_BLOCK_HEADER_SIZE_MAX 1024
+
+#define XZ_NUM_FILTERS_MAX 4
+#define XZ_BF_NUM_FILTERS_MASK 3
+#define XZ_BF_PACK_SIZE (1 << 6)
+#define XZ_BF_UNPACK_SIZE (1 << 7)
+
+#define XZ_FILTER_PROPS_SIZE_MAX 20
+
+typedef struct
+{
+ UInt64 id;
+ UInt32 propsSize;
+ Byte props[XZ_FILTER_PROPS_SIZE_MAX];
+} CXzFilter;
+
+typedef struct
+{
+ UInt64 packSize;
+ UInt64 unpackSize;
+ Byte flags;
+ CXzFilter filters[XZ_NUM_FILTERS_MAX];
+} CXzBlock;
+
+#define XzBlock_GetNumFilters(p) (((unsigned)(p)->flags & XZ_BF_NUM_FILTERS_MASK) + 1)
+#define XzBlock_HasPackSize(p) (((p)->flags & XZ_BF_PACK_SIZE) != 0)
+#define XzBlock_HasUnpackSize(p) (((p)->flags & XZ_BF_UNPACK_SIZE) != 0)
+#define XzBlock_HasUnsupportedFlags(p) (((p)->flags & ~(XZ_BF_NUM_FILTERS_MASK | XZ_BF_PACK_SIZE | XZ_BF_UNPACK_SIZE)) != 0)
+
+SRes XzBlock_Parse(CXzBlock *p, const Byte *header);
+SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStreamPtr inStream, BoolInt *isIndex, UInt32 *headerSizeRes);
+
+/* ---------- xz stream ---------- */
+
+#define XZ_SIG_SIZE 6
+#define XZ_FOOTER_SIG_SIZE 2
+
+extern const Byte XZ_SIG[XZ_SIG_SIZE];
+
+/*
+extern const Byte XZ_FOOTER_SIG[XZ_FOOTER_SIG_SIZE];
+*/
+
+#define XZ_FOOTER_SIG_0 'Y'
+#define XZ_FOOTER_SIG_1 'Z'
+
+#define XZ_STREAM_FLAGS_SIZE 2
+#define XZ_STREAM_CRC_SIZE 4
+
+#define XZ_STREAM_HEADER_SIZE (XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE)
+#define XZ_STREAM_FOOTER_SIZE (XZ_FOOTER_SIG_SIZE + XZ_STREAM_FLAGS_SIZE + XZ_STREAM_CRC_SIZE + 4)
+
+#define XZ_CHECK_MASK 0xF
+#define XZ_CHECK_NO 0
+#define XZ_CHECK_CRC32 1
+#define XZ_CHECK_CRC64 4
+#define XZ_CHECK_SHA256 10
+
+typedef struct
+{
+ unsigned mode;
+ UInt32 crc;
+ UInt64 crc64;
+ CSha256 sha;
+} CXzCheck;
+
+void XzCheck_Init(CXzCheck *p, unsigned mode);
+void XzCheck_Update(CXzCheck *p, const void *data, size_t size);
+int XzCheck_Final(CXzCheck *p, Byte *digest);
+
+typedef UInt16 CXzStreamFlags;
+
+#define XzFlags_IsSupported(f) ((f) <= XZ_CHECK_MASK)
+#define XzFlags_GetCheckType(f) ((f) & XZ_CHECK_MASK)
+#define XzFlags_HasDataCrc32(f) (Xz_GetCheckType(f) == XZ_CHECK_CRC32)
+unsigned XzFlags_GetCheckSize(CXzStreamFlags f);
+
+SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf);
+SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStreamPtr inStream);
+
+typedef struct
+{
+ UInt64 unpackSize;
+ UInt64 totalSize;
+} CXzBlockSizes;
+
+typedef struct
+{
+ CXzStreamFlags flags;
+ // Byte _pad[6];
+ size_t numBlocks;
+ CXzBlockSizes *blocks;
+ UInt64 startOffset;
+} CXzStream;
+
+void Xz_Construct(CXzStream *p);
+void Xz_Free(CXzStream *p, ISzAllocPtr alloc);
+
+#define XZ_SIZE_OVERFLOW ((UInt64)(Int64)-1)
+
+UInt64 Xz_GetUnpackSize(const CXzStream *p);
+UInt64 Xz_GetPackSize(const CXzStream *p);
+
+typedef struct
+{
+ size_t num;
+ size_t numAllocated;
+ CXzStream *streams;
+} CXzs;
+
+void Xzs_Construct(CXzs *p);
+void Xzs_Free(CXzs *p, ISzAllocPtr alloc);
+SRes Xzs_ReadBackward(CXzs *p, ILookInStreamPtr inStream, Int64 *startOffset, ICompressProgressPtr progress, ISzAllocPtr alloc);
+
+UInt64 Xzs_GetNumBlocks(const CXzs *p);
+UInt64 Xzs_GetUnpackSize(const CXzs *p);
+
+
+// ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder
+
+typedef enum
+{
+ CODER_STATUS_NOT_SPECIFIED, /* use main error code instead */
+ CODER_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
+ CODER_STATUS_NOT_FINISHED, /* stream was not finished */
+ CODER_STATUS_NEEDS_MORE_INPUT /* you must provide more input bytes */
+} ECoderStatus;
+
+
+// ECoderFinishMode values are identical to ELzmaFinishMode
+
+typedef enum
+{
+ CODER_FINISH_ANY, /* finish at any point */
+ CODER_FINISH_END /* block must be finished at the end */
+} ECoderFinishMode;
+
+
+typedef struct
+{
+ void *p; // state object;
+ void (*Free)(void *p, ISzAllocPtr alloc);
+ SRes (*SetProps)(void *p, const Byte *props, size_t propSize, ISzAllocPtr alloc);
+ void (*Init)(void *p);
+ SRes (*Code2)(void *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ int srcWasFinished, ECoderFinishMode finishMode,
+ // int *wasFinished,
+ ECoderStatus *status);
+ SizeT (*Filter)(void *p, Byte *data, SizeT size);
+} IStateCoder;
+
+
+typedef struct
+{
+ UInt32 methodId;
+ UInt32 delta;
+ UInt32 ip;
+ UInt32 X86_State;
+ Byte delta_State[DELTA_STATE_SIZE];
+} CXzBcFilterStateBase;
+
+typedef SizeT (*Xz_Func_BcFilterStateBase_Filter)(CXzBcFilterStateBase *p, Byte *data, SizeT size);
+
+SRes Xz_StateCoder_Bc_SetFromMethod_Func(IStateCoder *p, UInt64 id,
+ Xz_Func_BcFilterStateBase_Filter func, ISzAllocPtr alloc);
+
+
+#define MIXCODER_NUM_FILTERS_MAX 4
+
+typedef struct
+{
+ ISzAllocPtr alloc;
+ Byte *buf;
+ unsigned numCoders;
+
+ Byte *outBuf;
+ size_t outBufSize;
+ size_t outWritten; // is equal to lzmaDecoder.dicPos (in outBuf mode)
+ BoolInt wasFinished;
+ SRes res;
+ ECoderStatus status;
+ // BoolInt SingleBufMode;
+
+ int finished[MIXCODER_NUM_FILTERS_MAX - 1];
+ size_t pos[MIXCODER_NUM_FILTERS_MAX - 1];
+ size_t size[MIXCODER_NUM_FILTERS_MAX - 1];
+ UInt64 ids[MIXCODER_NUM_FILTERS_MAX];
+ SRes results[MIXCODER_NUM_FILTERS_MAX];
+ IStateCoder coders[MIXCODER_NUM_FILTERS_MAX];
+} CMixCoder;
+
+
+typedef enum
+{
+ XZ_STATE_STREAM_HEADER,
+ XZ_STATE_STREAM_INDEX,
+ XZ_STATE_STREAM_INDEX_CRC,
+ XZ_STATE_STREAM_FOOTER,
+ XZ_STATE_STREAM_PADDING,
+ XZ_STATE_BLOCK_HEADER,
+ XZ_STATE_BLOCK,
+ XZ_STATE_BLOCK_FOOTER
+} EXzState;
+
+
+typedef struct
+{
+ EXzState state;
+ UInt32 pos;
+ unsigned alignPos;
+ unsigned indexPreSize;
+
+ CXzStreamFlags streamFlags;
+
+ UInt32 blockHeaderSize;
+ UInt64 packSize;
+ UInt64 unpackSize;
+
+ UInt64 numBlocks; // number of finished blocks in current stream
+ UInt64 indexSize;
+ UInt64 indexPos;
+ UInt64 padSize;
+
+ UInt64 numStartedStreams;
+ UInt64 numFinishedStreams;
+ UInt64 numTotalBlocks;
+
+ UInt32 crc;
+ CMixCoder decoder;
+ CXzBlock block;
+ CXzCheck check;
+ CSha256 sha;
+
+ BoolInt parseMode;
+ BoolInt headerParsedOk;
+ BoolInt decodeToStreamSignature;
+ unsigned decodeOnlyOneBlock;
+
+ Byte *outBuf;
+ size_t outBufSize;
+ size_t outDataWritten; // the size of data in (outBuf) that were fully unpacked
+
+ Byte shaDigest[SHA256_DIGEST_SIZE];
+ Byte buf[XZ_BLOCK_HEADER_SIZE_MAX];
+} CXzUnpacker;
+
+/* alloc : aligned for cache line allocation is better */
+void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc);
+void XzUnpacker_Init(CXzUnpacker *p);
+void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize);
+void XzUnpacker_Free(CXzUnpacker *p);
+
+/*
+ XzUnpacker
+ The sequence for decoding functions:
+ {
+ XzUnpacker_Construct()
+ [Decoding_Calls]
+ XzUnpacker_Free()
+ }
+
+ [Decoding_Calls]
+
+ There are 3 types of interfaces for [Decoding_Calls] calls:
+
+ Interface-1 : Partial output buffers:
+ {
+ XzUnpacker_Init()
+ for()
+ {
+ XzUnpacker_Code();
+ }
+ XzUnpacker_IsStreamWasFinished()
+ }
+
+ Interface-2 : Direct output buffer:
+ Use it, if you know exact size of decoded data, and you need
+ whole xz unpacked data in one output buffer.
+ xz unpacker doesn't allocate additional buffer for lzma2 dictionary in that mode.
+ {
+ XzUnpacker_Init()
+ XzUnpacker_SetOutBufMode(); // to set output buffer and size
+ for()
+ {
+ XzUnpacker_Code(); // (dest = NULL) in XzUnpacker_Code()
+ }
+ XzUnpacker_IsStreamWasFinished()
+ }
+
+ Interface-3 : Direct output buffer : One call full decoding
+ It unpacks whole input buffer to output buffer in one call.
+ It uses Interface-2 internally.
+ {
+ XzUnpacker_CodeFull()
+ XzUnpacker_IsStreamWasFinished()
+ }
+*/
+
+/*
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ CODER_FINISH_ANY - use smallest number of input bytes
+ CODER_FINISH_END - read EndOfStream marker after decoding
+
+Returns:
+ SZ_OK
+ status:
+ CODER_STATUS_NOT_FINISHED,
+ CODER_STATUS_NEEDS_MORE_INPUT - the decoder can return it in two cases:
+ 1) it needs more input data to finish current xz stream
+ 2) xz stream was finished successfully. But the decoder supports multiple
+ concatented xz streams. So it expects more input data for new xz streams.
+ Call XzUnpacker_IsStreamWasFinished() to check that latest xz stream was finished successfully.
+
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_UNSUPPORTED - Unsupported method or method properties
+ SZ_ERROR_CRC - CRC error
+ // SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+
+ SZ_ERROR_NO_ARCHIVE - the error with xz Stream Header with one of the following reasons:
+ - xz Stream Signature failure
+ - CRC32 of xz Stream Header is failed
+ - The size of Stream padding is not multiple of four bytes.
+ It's possible to get that error, if xz stream was finished and the stream
+ contains some another data. In that case you can call XzUnpacker_GetExtraSize()
+ function to get real size of xz stream.
+*/
+
+
+SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, int srcFinished,
+ ECoderFinishMode finishMode, ECoderStatus *status);
+
+SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen,
+ ECoderFinishMode finishMode, ECoderStatus *status);
+
+/*
+If you decode full xz stream(s), then you can call XzUnpacker_IsStreamWasFinished()
+after successful XzUnpacker_CodeFull() or after last call of XzUnpacker_Code().
+*/
+
+BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p);
+
+/*
+XzUnpacker_GetExtraSize() returns then number of unconfirmed bytes,
+ if it's in (XZ_STATE_STREAM_HEADER) state or in (XZ_STATE_STREAM_PADDING) state.
+These bytes can be some data after xz archive, or
+it can be start of new xz stream.
+
+Call XzUnpacker_GetExtraSize() after XzUnpacker_Code() function to detect real size of
+xz stream in two cases, if XzUnpacker_Code() returns:
+ res == SZ_OK && status == CODER_STATUS_NEEDS_MORE_INPUT
+ res == SZ_ERROR_NO_ARCHIVE
+*/
+
+UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p);
+
+
+/*
+ for random block decoding:
+ XzUnpacker_Init();
+ set CXzUnpacker::streamFlags
+ XzUnpacker_PrepareToRandomBlockDecoding()
+ loop
+ {
+ XzUnpacker_Code()
+ XzUnpacker_IsBlockFinished()
+ }
+*/
+
+void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p);
+BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p);
+
+#define XzUnpacker_GetPackSizeForIndex(p) ((p)->packSize + (p)->blockHeaderSize + XzFlags_GetCheckSize((p)->streamFlags))
+
+
+
+
+
+
+/* ---- Single-Thread and Multi-Thread xz Decoding with Input/Output Streams ---- */
+
+/*
+ if (CXzDecMtProps::numThreads > 1), the decoder can try to use
+ Multi-Threading. The decoder analyses xz block header, and if
+ there are pack size and unpack size values stored in xz block header,
+ the decoder reads compressed data of block to internal buffers,
+ and then it can start parallel decoding, if there are another blocks.
+ The decoder can switch back to Single-Thread decoding after some conditions.
+
+ The sequence of calls for xz decoding with in/out Streams:
+ {
+ XzDecMt_Create()
+ XzDecMtProps_Init(XzDecMtProps) to set default values of properties
+ // then you can change some XzDecMtProps parameters with required values
+ // here you can set the number of threads and (memUseMax) - the maximum
+ Memory usage for multithreading decoding.
+ for()
+ {
+ XzDecMt_Decode() // one call per one file
+ }
+ XzDecMt_Destroy()
+ }
+*/
+
+
+typedef struct
+{
+ size_t inBufSize_ST; // size of input buffer for Single-Thread decoding
+ size_t outStep_ST; // size of output buffer for Single-Thread decoding
+ BoolInt ignoreErrors; // if set to 1, the decoder can ignore some errors and it skips broken parts of data.
+
+ #ifndef Z7_ST
+ unsigned numThreads; // the number of threads for Multi-Thread decoding. if (umThreads == 1) it will use Single-thread decoding
+ size_t inBufSize_MT; // size of small input data buffers for Multi-Thread decoding. Big number of such small buffers can be created
+ size_t memUseMax; // the limit of total memory usage for Multi-Thread decoding.
+ // it's recommended to set (memUseMax) manually to value that is smaller of total size of RAM in computer.
+ #endif
+} CXzDecMtProps;
+
+void XzDecMtProps_Init(CXzDecMtProps *p);
+
+typedef struct CXzDecMt CXzDecMt;
+typedef CXzDecMt * CXzDecMtHandle;
+// Z7_DECLARE_HANDLE(CXzDecMtHandle)
+
+/*
+ alloc : XzDecMt uses CAlignOffsetAlloc internally for addresses allocated by (alloc).
+ allocMid : for big allocations, aligned allocation is better
+*/
+
+CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid);
+void XzDecMt_Destroy(CXzDecMtHandle p);
+
+
+typedef struct
+{
+ Byte UnpackSize_Defined;
+ Byte NumStreams_Defined;
+ Byte NumBlocks_Defined;
+
+ Byte DataAfterEnd; // there are some additional data after good xz streams, and that data is not new xz stream.
+ Byte DecodingTruncated; // Decoding was Truncated, we need only partial output data
+
+ UInt64 InSize; // pack size processed. That value doesn't include the data after
+ // end of xz stream, if that data was not correct
+ UInt64 OutSize;
+
+ UInt64 NumStreams;
+ UInt64 NumBlocks;
+
+ SRes DecodeRes; // the error code of xz streams data decoding
+ SRes ReadRes; // error code from ISeqInStream:Read()
+ SRes ProgressRes; // error code from ICompressProgress:Progress()
+
+ SRes CombinedRes; // Combined result error code that shows main rusult
+ // = S_OK, if there is no error.
+ // but check also (DataAfterEnd) that can show additional minor errors.
+
+ SRes CombinedRes_Type; // = SZ_ERROR_READ, if error from ISeqInStream
+ // = SZ_ERROR_PROGRESS, if error from ICompressProgress
+ // = SZ_ERROR_WRITE, if error from ISeqOutStream
+ // = SZ_ERROR_* codes for decoding
+} CXzStatInfo;
+
+void XzStatInfo_Clear(CXzStatInfo *p);
+
+/*
+
+XzDecMt_Decode()
+SRes: it's combined decoding result. It also is equal to stat->CombinedRes.
+
+ SZ_OK - no error
+ check also output value in (stat->DataAfterEnd)
+ that can show additional possible error
+
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_NO_ARCHIVE - is not xz archive
+ SZ_ERROR_ARCHIVE - Headers error
+ SZ_ERROR_DATA - Data Error
+ SZ_ERROR_UNSUPPORTED - Unsupported method or method properties
+ SZ_ERROR_CRC - CRC Error
+ SZ_ERROR_INPUT_EOF - it needs more input data
+ SZ_ERROR_WRITE - ISeqOutStream error
+ (SZ_ERROR_READ) - ISeqInStream errors
+ (SZ_ERROR_PROGRESS) - ICompressProgress errors
+ // SZ_ERROR_THREAD - error in multi-threading functions
+ MY_SRes_HRESULT_FROM_WRes(WRes_error) - error in multi-threading function
+*/
+
+SRes XzDecMt_Decode(CXzDecMtHandle p,
+ const CXzDecMtProps *props,
+ const UInt64 *outDataSize, // NULL means undefined
+ int finishMode, // 0 - partial unpacking is allowed, 1 - xz stream(s) must be finished
+ ISeqOutStreamPtr outStream,
+ // Byte *outBuf, size_t *outBufSize,
+ ISeqInStreamPtr inStream,
+ // const Byte *inData, size_t inDataSize,
+ CXzStatInfo *stat, // out: decoding results and statistics
+ int *isMT, // out: 0 means that ST (Single-Thread) version was used
+ // 1 means that MT (Multi-Thread) version was used
+ ICompressProgressPtr progress);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/XzCrc64.c b/C/XzCrc64.c
index e9ca9ec..c2fad6c 100644
--- a/C/XzCrc64.c
+++ b/C/XzCrc64.c
@@ -1,86 +1,80 @@
-/* XzCrc64.c -- CRC64 calculation
-2017-05-23 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "XzCrc64.h"
-#include "CpuArch.h"
-
-#define kCrc64Poly UINT64_CONST(0xC96C5795D7870F42)
-
-#ifdef MY_CPU_LE
- #define CRC64_NUM_TABLES 4
-#else
- #define CRC64_NUM_TABLES 5
- #define CRC_UINT64_SWAP(v) \
- ((v >> 56) \
- | ((v >> 40) & ((UInt64)0xFF << 8)) \
- | ((v >> 24) & ((UInt64)0xFF << 16)) \
- | ((v >> 8) & ((UInt64)0xFF << 24)) \
- | ((v << 8) & ((UInt64)0xFF << 32)) \
- | ((v << 24) & ((UInt64)0xFF << 40)) \
- | ((v << 40) & ((UInt64)0xFF << 48)) \
- | ((v << 56)))
-
- UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table);
-#endif
-
-#ifndef MY_CPU_BE
- UInt64 MY_FAST_CALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table);
-#endif
-
-typedef UInt64 (MY_FAST_CALL *CRC64_FUNC)(UInt64 v, const void *data, size_t size, const UInt64 *table);
-
-static CRC64_FUNC g_Crc64Update;
-UInt64 g_Crc64Table[256 * CRC64_NUM_TABLES];
-
-UInt64 MY_FAST_CALL Crc64Update(UInt64 v, const void *data, size_t size)
-{
- return g_Crc64Update(v, data, size, g_Crc64Table);
-}
-
-UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size)
-{
- return g_Crc64Update(CRC64_INIT_VAL, data, size, g_Crc64Table) ^ CRC64_INIT_VAL;
-}
-
-void MY_FAST_CALL Crc64GenerateTable()
-{
- UInt32 i;
- for (i = 0; i < 256; i++)
- {
- UInt64 r = i;
- unsigned j;
- for (j = 0; j < 8; j++)
- r = (r >> 1) ^ (kCrc64Poly & ((UInt64)0 - (r & 1)));
- g_Crc64Table[i] = r;
- }
- for (i = 256; i < 256 * CRC64_NUM_TABLES; i++)
- {
- UInt64 r = g_Crc64Table[(size_t)i - 256];
- g_Crc64Table[i] = g_Crc64Table[r & 0xFF] ^ (r >> 8);
- }
-
- #ifdef MY_CPU_LE
-
- g_Crc64Update = XzCrc64UpdateT4;
-
- #else
- {
- #ifndef MY_CPU_BE
- UInt32 k = 1;
- if (*(const Byte *)&k == 1)
- g_Crc64Update = XzCrc64UpdateT4;
- else
- #endif
- {
- for (i = 256 * CRC64_NUM_TABLES - 1; i >= 256; i--)
- {
- UInt64 x = g_Crc64Table[(size_t)i - 256];
- g_Crc64Table[i] = CRC_UINT64_SWAP(x);
- }
- g_Crc64Update = XzCrc64UpdateT1_BeT4;
- }
- }
- #endif
-}
+/* XzCrc64.c -- CRC64 calculation
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "XzCrc64.h"
+#include "CpuArch.h"
+
+#define kCrc64Poly UINT64_CONST(0xC96C5795D7870F42)
+
+#ifdef MY_CPU_LE
+ #define CRC64_NUM_TABLES 4
+#else
+ #define CRC64_NUM_TABLES 5
+
+ UInt64 Z7_FASTCALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table);
+#endif
+
+#ifndef MY_CPU_BE
+ UInt64 Z7_FASTCALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table);
+#endif
+
+typedef UInt64 (Z7_FASTCALL *CRC64_FUNC)(UInt64 v, const void *data, size_t size, const UInt64 *table);
+
+static CRC64_FUNC g_Crc64Update;
+UInt64 g_Crc64Table[256 * CRC64_NUM_TABLES];
+
+UInt64 Z7_FASTCALL Crc64Update(UInt64 v, const void *data, size_t size)
+{
+ return g_Crc64Update(v, data, size, g_Crc64Table);
+}
+
+UInt64 Z7_FASTCALL Crc64Calc(const void *data, size_t size)
+{
+ return g_Crc64Update(CRC64_INIT_VAL, data, size, g_Crc64Table) ^ CRC64_INIT_VAL;
+}
+
+void Z7_FASTCALL Crc64GenerateTable(void)
+{
+ UInt32 i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt64 r = i;
+ unsigned j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (kCrc64Poly & ((UInt64)0 - (r & 1)));
+ g_Crc64Table[i] = r;
+ }
+ for (i = 256; i < 256 * CRC64_NUM_TABLES; i++)
+ {
+ const UInt64 r = g_Crc64Table[(size_t)i - 256];
+ g_Crc64Table[i] = g_Crc64Table[r & 0xFF] ^ (r >> 8);
+ }
+
+ #ifdef MY_CPU_LE
+
+ g_Crc64Update = XzCrc64UpdateT4;
+
+ #else
+ {
+ #ifndef MY_CPU_BE
+ UInt32 k = 1;
+ if (*(const Byte *)&k == 1)
+ g_Crc64Update = XzCrc64UpdateT4;
+ else
+ #endif
+ {
+ for (i = 256 * CRC64_NUM_TABLES - 1; i >= 256; i--)
+ {
+ const UInt64 x = g_Crc64Table[(size_t)i - 256];
+ g_Crc64Table[i] = Z7_BSWAP64(x);
+ }
+ g_Crc64Update = XzCrc64UpdateT1_BeT4;
+ }
+ }
+ #endif
+}
+
+#undef kCrc64Poly
+#undef CRC64_NUM_TABLES
diff --git a/C/XzCrc64.h b/C/XzCrc64.h
index 71b10d5..ca46869 100644
--- a/C/XzCrc64.h
+++ b/C/XzCrc64.h
@@ -1,26 +1,26 @@
-/* XzCrc64.h -- CRC64 calculation
-2013-01-18 : Igor Pavlov : Public domain */
-
-#ifndef __XZ_CRC64_H
-#define __XZ_CRC64_H
-
-#include <stddef.h>
-
-#include "7zTypes.h"
-
-EXTERN_C_BEGIN
-
-extern UInt64 g_Crc64Table[];
-
-void MY_FAST_CALL Crc64GenerateTable(void);
-
-#define CRC64_INIT_VAL UINT64_CONST(0xFFFFFFFFFFFFFFFF)
-#define CRC64_GET_DIGEST(crc) ((crc) ^ CRC64_INIT_VAL)
-#define CRC64_UPDATE_BYTE(crc, b) (g_Crc64Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
-
-UInt64 MY_FAST_CALL Crc64Update(UInt64 crc, const void *data, size_t size);
-UInt64 MY_FAST_CALL Crc64Calc(const void *data, size_t size);
-
-EXTERN_C_END
-
-#endif
+/* XzCrc64.h -- CRC64 calculation
+2023-04-02 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_XZ_CRC64_H
+#define ZIP7_INC_XZ_CRC64_H
+
+#include <stddef.h>
+
+#include "7zTypes.h"
+
+EXTERN_C_BEGIN
+
+extern UInt64 g_Crc64Table[];
+
+void Z7_FASTCALL Crc64GenerateTable(void);
+
+#define CRC64_INIT_VAL UINT64_CONST(0xFFFFFFFFFFFFFFFF)
+#define CRC64_GET_DIGEST(crc) ((crc) ^ CRC64_INIT_VAL)
+#define CRC64_UPDATE_BYTE(crc, b) (g_Crc64Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt64 Z7_FASTCALL Crc64Update(UInt64 crc, const void *data, size_t size);
+UInt64 Z7_FASTCALL Crc64Calc(const void *data, size_t size);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/XzCrc64Opt.c b/C/XzCrc64Opt.c
index 9273465..d03374c 100644
--- a/C/XzCrc64Opt.c
+++ b/C/XzCrc64Opt.c
@@ -1,69 +1,61 @@
-/* XzCrc64Opt.c -- CRC64 calculation
-2017-06-30 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include "CpuArch.h"
-
-#ifndef MY_CPU_BE
-
-#define CRC64_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
-
-UInt64 MY_FAST_CALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table)
-{
- const Byte *p = (const Byte *)data;
- for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
- v = CRC64_UPDATE_BYTE_2(v, *p);
- for (; size >= 4; size -= 4, p += 4)
- {
- UInt32 d = (UInt32)v ^ *(const UInt32 *)p;
- v = (v >> 32)
- ^ (table + 0x300)[((d ) & 0xFF)]
- ^ (table + 0x200)[((d >> 8) & 0xFF)]
- ^ (table + 0x100)[((d >> 16) & 0xFF)]
- ^ (table + 0x000)[((d >> 24))];
- }
- for (; size > 0; size--, p++)
- v = CRC64_UPDATE_BYTE_2(v, *p);
- return v;
-}
-
-#endif
-
-
-#ifndef MY_CPU_LE
-
-#define CRC_UINT64_SWAP(v) \
- ((v >> 56) \
- | ((v >> 40) & ((UInt64)0xFF << 8)) \
- | ((v >> 24) & ((UInt64)0xFF << 16)) \
- | ((v >> 8) & ((UInt64)0xFF << 24)) \
- | ((v << 8) & ((UInt64)0xFF << 32)) \
- | ((v << 24) & ((UInt64)0xFF << 40)) \
- | ((v << 40) & ((UInt64)0xFF << 48)) \
- | ((v << 56)))
-
-#define CRC64_UPDATE_BYTE_2_BE(crc, b) (table[(Byte)((crc) >> 56) ^ (b)] ^ ((crc) << 8))
-
-UInt64 MY_FAST_CALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table)
-{
- const Byte *p = (const Byte *)data;
- table += 0x100;
- v = CRC_UINT64_SWAP(v);
- for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
- v = CRC64_UPDATE_BYTE_2_BE(v, *p);
- for (; size >= 4; size -= 4, p += 4)
- {
- UInt32 d = (UInt32)(v >> 32) ^ *(const UInt32 *)p;
- v = (v << 32)
- ^ (table + 0x000)[((d ) & 0xFF)]
- ^ (table + 0x100)[((d >> 8) & 0xFF)]
- ^ (table + 0x200)[((d >> 16) & 0xFF)]
- ^ (table + 0x300)[((d >> 24))];
- }
- for (; size > 0; size--, p++)
- v = CRC64_UPDATE_BYTE_2_BE(v, *p);
- return CRC_UINT64_SWAP(v);
-}
-
-#endif
+/* XzCrc64Opt.c -- CRC64 calculation
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include "CpuArch.h"
+
+#ifndef MY_CPU_BE
+
+#define CRC64_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt64 Z7_FASTCALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table);
+UInt64 Z7_FASTCALL XzCrc64UpdateT4(UInt64 v, const void *data, size_t size, const UInt64 *table)
+{
+ const Byte *p = (const Byte *)data;
+ for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
+ v = CRC64_UPDATE_BYTE_2(v, *p);
+ for (; size >= 4; size -= 4, p += 4)
+ {
+ const UInt32 d = (UInt32)v ^ *(const UInt32 *)(const void *)p;
+ v = (v >> 32)
+ ^ (table + 0x300)[((d ) & 0xFF)]
+ ^ (table + 0x200)[((d >> 8) & 0xFF)]
+ ^ (table + 0x100)[((d >> 16) & 0xFF)]
+ ^ (table + 0x000)[((d >> 24))];
+ }
+ for (; size > 0; size--, p++)
+ v = CRC64_UPDATE_BYTE_2(v, *p);
+ return v;
+}
+
+#endif
+
+
+#ifndef MY_CPU_LE
+
+#define CRC64_UPDATE_BYTE_2_BE(crc, b) (table[(Byte)((crc) >> 56) ^ (b)] ^ ((crc) << 8))
+
+UInt64 Z7_FASTCALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table);
+UInt64 Z7_FASTCALL XzCrc64UpdateT1_BeT4(UInt64 v, const void *data, size_t size, const UInt64 *table)
+{
+ const Byte *p = (const Byte *)data;
+ table += 0x100;
+ v = Z7_BSWAP64(v);
+ for (; size > 0 && ((unsigned)(ptrdiff_t)p & 3) != 0; size--, p++)
+ v = CRC64_UPDATE_BYTE_2_BE(v, *p);
+ for (; size >= 4; size -= 4, p += 4)
+ {
+ const UInt32 d = (UInt32)(v >> 32) ^ *(const UInt32 *)(const void *)p;
+ v = (v << 32)
+ ^ (table + 0x000)[((d ) & 0xFF)]
+ ^ (table + 0x100)[((d >> 8) & 0xFF)]
+ ^ (table + 0x200)[((d >> 16) & 0xFF)]
+ ^ (table + 0x300)[((d >> 24))];
+ }
+ for (; size > 0; size--, p++)
+ v = CRC64_UPDATE_BYTE_2_BE(v, *p);
+ return Z7_BSWAP64(v);
+}
+
+#endif
diff --git a/C/XzDec.c b/C/XzDec.c
index 4f53272..a5f7039 100644
--- a/C/XzDec.c
+++ b/C/XzDec.c
@@ -1,2766 +1,2875 @@
-/* XzDec.c -- Xz Decode
-2019-02-02 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-// #include <stdio.h>
-
-// #define XZ_DUMP
-
-/* #define XZ_DUMP */
-
-#ifdef XZ_DUMP
-#include <stdio.h>
-#endif
-
-// #define SHOW_DEBUG_INFO
-
-#ifdef SHOW_DEBUG_INFO
-#include <stdio.h>
-#endif
-
-#ifdef SHOW_DEBUG_INFO
-#define PRF(x) x
-#else
-#define PRF(x)
-#endif
-
-#define PRF_STR(s) PRF(printf("\n" s "\n"))
-#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d))
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "7zCrc.h"
-#include "Alloc.h"
-#include "Bra.h"
-#include "CpuArch.h"
-#include "Delta.h"
-#include "Lzma2Dec.h"
-
-// #define USE_SUBBLOCK
-
-#ifdef USE_SUBBLOCK
-#include "Bcj3Dec.c"
-#include "SbDec.h"
-#endif
-
-#include "Xz.h"
-
-#define XZ_CHECK_SIZE_MAX 64
-
-#define CODER_BUF_SIZE ((size_t)1 << 17)
-
-unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value)
-{
- unsigned i, limit;
- *value = 0;
- limit = (maxSize > 9) ? 9 : (unsigned)maxSize;
-
- for (i = 0; i < limit;)
- {
- Byte b = p[i];
- *value |= (UInt64)(b & 0x7F) << (7 * i++);
- if ((b & 0x80) == 0)
- return (b == 0 && i != 1) ? 0 : i;
- }
- return 0;
-}
-
-/* ---------- BraState ---------- */
-
-#define BRA_BUF_SIZE (1 << 14)
-
-typedef struct
-{
- size_t bufPos;
- size_t bufConv;
- size_t bufTotal;
-
- int encodeMode;
-
- UInt32 methodId;
- UInt32 delta;
- UInt32 ip;
- UInt32 x86State;
- Byte deltaState[DELTA_STATE_SIZE];
-
- Byte buf[BRA_BUF_SIZE];
-} CBraState;
-
-static void BraState_Free(void *pp, ISzAllocPtr alloc)
-{
- ISzAlloc_Free(alloc, pp);
-}
-
-static SRes BraState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc)
-{
- CBraState *p = ((CBraState *)pp);
- UNUSED_VAR(alloc);
- p->ip = 0;
- if (p->methodId == XZ_ID_Delta)
- {
- if (propSize != 1)
- return SZ_ERROR_UNSUPPORTED;
- p->delta = (unsigned)props[0] + 1;
- }
- else
- {
- if (propSize == 4)
- {
- UInt32 v = GetUi32(props);
- switch (p->methodId)
- {
- case XZ_ID_PPC:
- case XZ_ID_ARM:
- case XZ_ID_SPARC:
- if ((v & 3) != 0)
- return SZ_ERROR_UNSUPPORTED;
- break;
- case XZ_ID_ARMT:
- if ((v & 1) != 0)
- return SZ_ERROR_UNSUPPORTED;
- break;
- case XZ_ID_IA64:
- if ((v & 0xF) != 0)
- return SZ_ERROR_UNSUPPORTED;
- break;
- }
- p->ip = v;
- }
- else if (propSize != 0)
- return SZ_ERROR_UNSUPPORTED;
- }
- return SZ_OK;
-}
-
-static void BraState_Init(void *pp)
-{
- CBraState *p = ((CBraState *)pp);
- p->bufPos = p->bufConv = p->bufTotal = 0;
- x86_Convert_Init(p->x86State);
- if (p->methodId == XZ_ID_Delta)
- Delta_Init(p->deltaState);
-}
-
-
-#define CASE_BRA_CONV(isa) case XZ_ID_ ## isa: size = isa ## _Convert(data, size, p->ip, p->encodeMode); break;
-
-static SizeT BraState_Filter(void *pp, Byte *data, SizeT size)
-{
- CBraState *p = ((CBraState *)pp);
- switch (p->methodId)
- {
- case XZ_ID_Delta:
- if (p->encodeMode)
- Delta_Encode(p->deltaState, p->delta, data, size);
- else
- Delta_Decode(p->deltaState, p->delta, data, size);
- break;
- case XZ_ID_X86:
- size = x86_Convert(data, size, p->ip, &p->x86State, p->encodeMode);
- break;
- CASE_BRA_CONV(PPC)
- CASE_BRA_CONV(IA64)
- CASE_BRA_CONV(ARM)
- CASE_BRA_CONV(ARMT)
- CASE_BRA_CONV(SPARC)
- }
- p->ip += (UInt32)size;
- return size;
-}
-
-
-static SRes BraState_Code2(void *pp,
- Byte *dest, SizeT *destLen,
- const Byte *src, SizeT *srcLen, int srcWasFinished,
- ECoderFinishMode finishMode,
- // int *wasFinished
- ECoderStatus *status)
-{
- CBraState *p = ((CBraState *)pp);
- SizeT destRem = *destLen;
- SizeT srcRem = *srcLen;
- UNUSED_VAR(finishMode);
-
- *destLen = 0;
- *srcLen = 0;
- // *wasFinished = False;
- *status = CODER_STATUS_NOT_FINISHED;
-
- while (destRem > 0)
- {
- if (p->bufPos != p->bufConv)
- {
- size_t size = p->bufConv - p->bufPos;
- if (size > destRem)
- size = destRem;
- memcpy(dest, p->buf + p->bufPos, size);
- p->bufPos += size;
- *destLen += size;
- dest += size;
- destRem -= size;
- continue;
- }
-
- p->bufTotal -= p->bufPos;
- memmove(p->buf, p->buf + p->bufPos, p->bufTotal);
- p->bufPos = 0;
- p->bufConv = 0;
- {
- size_t size = BRA_BUF_SIZE - p->bufTotal;
- if (size > srcRem)
- size = srcRem;
- memcpy(p->buf + p->bufTotal, src, size);
- *srcLen += size;
- src += size;
- srcRem -= size;
- p->bufTotal += size;
- }
- if (p->bufTotal == 0)
- break;
-
- p->bufConv = BraState_Filter(pp, p->buf, p->bufTotal);
-
- if (p->bufConv == 0)
- {
- if (!srcWasFinished)
- break;
- p->bufConv = p->bufTotal;
- }
- }
-
- if (p->bufTotal == p->bufPos && srcRem == 0 && srcWasFinished)
- {
- *status = CODER_STATUS_FINISHED_WITH_MARK;
- // *wasFinished = 1;
- }
-
- return SZ_OK;
-}
-
-
-SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc)
-{
- CBraState *decoder;
- if (id < XZ_ID_Delta || id > XZ_ID_SPARC)
- return SZ_ERROR_UNSUPPORTED;
- decoder = (CBraState *)p->p;
- if (!decoder)
- {
- decoder = (CBraState *)ISzAlloc_Alloc(alloc, sizeof(CBraState));
- if (!decoder)
- return SZ_ERROR_MEM;
- p->p = decoder;
- p->Free = BraState_Free;
- p->SetProps = BraState_SetProps;
- p->Init = BraState_Init;
- p->Code2 = BraState_Code2;
- p->Filter = BraState_Filter;
- }
- decoder->methodId = (UInt32)id;
- decoder->encodeMode = encodeMode;
- return SZ_OK;
-}
-
-
-
-/* ---------- SbState ---------- */
-
-#ifdef USE_SUBBLOCK
-
-static void SbState_Free(void *pp, ISzAllocPtr alloc)
-{
- CSbDec *p = (CSbDec *)pp;
- SbDec_Free(p);
- ISzAlloc_Free(alloc, pp);
-}
-
-static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc)
-{
- UNUSED_VAR(pp);
- UNUSED_VAR(props);
- UNUSED_VAR(alloc);
- return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
-}
-
-static void SbState_Init(void *pp)
-{
- SbDec_Init((CSbDec *)pp);
-}
-
-static SRes SbState_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
- int srcWasFinished, ECoderFinishMode finishMode,
- // int *wasFinished
- ECoderStatus *status)
-{
- CSbDec *p = (CSbDec *)pp;
- SRes res;
- UNUSED_VAR(srcWasFinished);
- p->dest = dest;
- p->destLen = *destLen;
- p->src = src;
- p->srcLen = *srcLen;
- p->finish = finishMode; /* change it */
- res = SbDec_Decode((CSbDec *)pp);
- *destLen -= p->destLen;
- *srcLen -= p->srcLen;
- // *wasFinished = (*destLen == 0 && *srcLen == 0); /* change it */
- *status = (*destLen == 0 && *srcLen == 0) ?
- CODER_STATUS_FINISHED_WITH_MARK :
- CODER_STATUS_NOT_FINISHED;
- return res;
-}
-
-static SRes SbState_SetFromMethod(IStateCoder *p, ISzAllocPtr alloc)
-{
- CSbDec *decoder = (CSbDec *)p->p;
- if (!decoder)
- {
- decoder = (CSbDec *)ISzAlloc_Alloc(alloc, sizeof(CSbDec));
- if (!decoder)
- return SZ_ERROR_MEM;
- p->p = decoder;
- p->Free = SbState_Free;
- p->SetProps = SbState_SetProps;
- p->Init = SbState_Init;
- p->Code2 = SbState_Code2;
- p->Filter = NULL;
- }
- SbDec_Construct(decoder);
- SbDec_SetAlloc(decoder, alloc);
- return SZ_OK;
-}
-
-#endif
-
-
-
-/* ---------- Lzma2 ---------- */
-
-typedef struct
-{
- CLzma2Dec decoder;
- BoolInt outBufMode;
-} CLzma2Dec_Spec;
-
-
-static void Lzma2State_Free(void *pp, ISzAllocPtr alloc)
-{
- CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp;
- if (p->outBufMode)
- Lzma2Dec_FreeProbs(&p->decoder, alloc);
- else
- Lzma2Dec_Free(&p->decoder, alloc);
- ISzAlloc_Free(alloc, pp);
-}
-
-static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc)
-{
- if (propSize != 1)
- return SZ_ERROR_UNSUPPORTED;
- {
- CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp;
- if (p->outBufMode)
- return Lzma2Dec_AllocateProbs(&p->decoder, props[0], alloc);
- else
- return Lzma2Dec_Allocate(&p->decoder, props[0], alloc);
- }
-}
-
-static void Lzma2State_Init(void *pp)
-{
- Lzma2Dec_Init(&((CLzma2Dec_Spec *)pp)->decoder);
-}
-
-
-/*
- if (outBufMode), then (dest) is not used. Use NULL.
- Data is unpacked to (spec->decoder.decoder.dic) output buffer.
-*/
-
-static SRes Lzma2State_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
- int srcWasFinished, ECoderFinishMode finishMode,
- // int *wasFinished,
- ECoderStatus *status)
-{
- CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)pp;
- ELzmaStatus status2;
- /* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */
- SRes res;
- UNUSED_VAR(srcWasFinished);
- if (spec->outBufMode)
- {
- SizeT dicPos = spec->decoder.decoder.dicPos;
- SizeT dicLimit = dicPos + *destLen;
- res = Lzma2Dec_DecodeToDic(&spec->decoder, dicLimit, src, srcLen, (ELzmaFinishMode)finishMode, &status2);
- *destLen = spec->decoder.decoder.dicPos - dicPos;
- }
- else
- res = Lzma2Dec_DecodeToBuf(&spec->decoder, dest, destLen, src, srcLen, (ELzmaFinishMode)finishMode, &status2);
- // *wasFinished = (status2 == LZMA_STATUS_FINISHED_WITH_MARK);
- // ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder
- *status = (ECoderStatus)status2;
- return res;
-}
-
-
-static SRes Lzma2State_SetFromMethod(IStateCoder *p, Byte *outBuf, size_t outBufSize, ISzAllocPtr alloc)
-{
- CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p;
- if (!spec)
- {
- spec = (CLzma2Dec_Spec *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Dec_Spec));
- if (!spec)
- return SZ_ERROR_MEM;
- p->p = spec;
- p->Free = Lzma2State_Free;
- p->SetProps = Lzma2State_SetProps;
- p->Init = Lzma2State_Init;
- p->Code2 = Lzma2State_Code2;
- p->Filter = NULL;
- Lzma2Dec_Construct(&spec->decoder);
- }
- spec->outBufMode = False;
- if (outBuf)
- {
- spec->outBufMode = True;
- spec->decoder.decoder.dic = outBuf;
- spec->decoder.decoder.dicBufSize = outBufSize;
- }
- return SZ_OK;
-}
-
-
-static SRes Lzma2State_ResetOutBuf(IStateCoder *p, Byte *outBuf, size_t outBufSize)
-{
- CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p;
- if ((spec->outBufMode && !outBuf) || (!spec->outBufMode && outBuf))
- return SZ_ERROR_FAIL;
- if (outBuf)
- {
- spec->decoder.decoder.dic = outBuf;
- spec->decoder.decoder.dicBufSize = outBufSize;
- }
- return SZ_OK;
-}
-
-
-
-static void MixCoder_Construct(CMixCoder *p, ISzAllocPtr alloc)
-{
- unsigned i;
- p->alloc = alloc;
- p->buf = NULL;
- p->numCoders = 0;
-
- p->outBufSize = 0;
- p->outBuf = NULL;
- // p->SingleBufMode = False;
-
- for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++)
- p->coders[i].p = NULL;
-}
-
-
-static void MixCoder_Free(CMixCoder *p)
-{
- unsigned i;
- p->numCoders = 0;
- for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++)
- {
- IStateCoder *sc = &p->coders[i];
- if (sc->p)
- {
- sc->Free(sc->p, p->alloc);
- sc->p = NULL;
- }
- }
- if (p->buf)
- {
- ISzAlloc_Free(p->alloc, p->buf);
- p->buf = NULL; /* 9.31: the BUG was fixed */
- }
-}
-
-static void MixCoder_Init(CMixCoder *p)
-{
- unsigned i;
- for (i = 0; i < MIXCODER_NUM_FILTERS_MAX - 1; i++)
- {
- p->size[i] = 0;
- p->pos[i] = 0;
- p->finished[i] = 0;
- }
- for (i = 0; i < p->numCoders; i++)
- {
- IStateCoder *coder = &p->coders[i];
- coder->Init(coder->p);
- p->results[i] = SZ_OK;
- }
- p->outWritten = 0;
- p->wasFinished = False;
- p->res = SZ_OK;
- p->status = CODER_STATUS_NOT_SPECIFIED;
-}
-
-
-static SRes MixCoder_SetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize)
-{
- IStateCoder *sc = &p->coders[coderIndex];
- p->ids[coderIndex] = methodId;
- switch (methodId)
- {
- case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, outBuf, outBufSize, p->alloc);
- #ifdef USE_SUBBLOCK
- case XZ_ID_Subblock: return SbState_SetFromMethod(sc, p->alloc);
- #endif
- }
- if (coderIndex == 0)
- return SZ_ERROR_UNSUPPORTED;
- return BraState_SetFromMethod(sc, methodId, 0, p->alloc);
-}
-
-
-static SRes MixCoder_ResetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize)
-{
- IStateCoder *sc = &p->coders[coderIndex];
- switch (methodId)
- {
- case XZ_ID_LZMA2: return Lzma2State_ResetOutBuf(sc, outBuf, outBufSize);
- }
- return SZ_ERROR_UNSUPPORTED;
-}
-
-
-
-/*
- if (destFinish) - then unpack data block is finished at (*destLen) position,
- and we can return data that were not processed by filter
-
-output (status) can be :
- CODER_STATUS_NOT_FINISHED
- CODER_STATUS_FINISHED_WITH_MARK
- CODER_STATUS_NEEDS_MORE_INPUT - not implemented still
-*/
-
-static SRes MixCoder_Code(CMixCoder *p,
- Byte *dest, SizeT *destLen, int destFinish,
- const Byte *src, SizeT *srcLen, int srcWasFinished,
- ECoderFinishMode finishMode)
-{
- SizeT destLenOrig = *destLen;
- SizeT srcLenOrig = *srcLen;
-
- *destLen = 0;
- *srcLen = 0;
-
- if (p->wasFinished)
- return p->res;
-
- p->status = CODER_STATUS_NOT_FINISHED;
-
- // if (p->SingleBufMode)
- if (p->outBuf)
- {
- SRes res;
- SizeT destLen2, srcLen2;
- int wasFinished;
-
- PRF_STR("------- MixCoder Single ----------");
-
- srcLen2 = srcLenOrig;
- destLen2 = destLenOrig;
-
- {
- IStateCoder *coder = &p->coders[0];
- res = coder->Code2(coder->p, NULL, &destLen2, src, &srcLen2, srcWasFinished, finishMode,
- // &wasFinished,
- &p->status);
- wasFinished = (p->status == CODER_STATUS_FINISHED_WITH_MARK);
- }
-
- p->res = res;
-
- /*
- if (wasFinished)
- p->status = CODER_STATUS_FINISHED_WITH_MARK;
- else
- {
- if (res == SZ_OK)
- if (destLen2 != destLenOrig)
- p->status = CODER_STATUS_NEEDS_MORE_INPUT;
- }
- */
-
-
- *srcLen = srcLen2;
- src += srcLen2;
- p->outWritten += destLen2;
-
- if (res != SZ_OK || srcWasFinished || wasFinished)
- p->wasFinished = True;
-
- if (p->numCoders == 1)
- *destLen = destLen2;
- else if (p->wasFinished)
- {
- unsigned i;
- size_t processed = p->outWritten;
-
- for (i = 1; i < p->numCoders; i++)
- {
- IStateCoder *coder = &p->coders[i];
- processed = coder->Filter(coder->p, p->outBuf, processed);
- if (wasFinished || (destFinish && p->outWritten == destLenOrig))
- processed = p->outWritten;
- PRF_STR_INT("filter", i);
- }
- *destLen = processed;
- }
- return res;
- }
-
- PRF_STR("standard mix");
-
- if (p->numCoders != 1)
- {
- if (!p->buf)
- {
- p->buf = (Byte *)ISzAlloc_Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1));
- if (!p->buf)
- return SZ_ERROR_MEM;
- }
-
- finishMode = CODER_FINISH_ANY;
- }
-
- for (;;)
- {
- BoolInt processed = False;
- BoolInt allFinished = True;
- SRes resMain = SZ_OK;
- unsigned i;
-
- p->status = CODER_STATUS_NOT_FINISHED;
- /*
- if (p->numCoders == 1 && *destLen == destLenOrig && finishMode == LZMA_FINISH_ANY)
- break;
- */
-
- for (i = 0; i < p->numCoders; i++)
- {
- SRes res;
- IStateCoder *coder = &p->coders[i];
- Byte *dest2;
- SizeT destLen2, srcLen2; // destLen2_Orig;
- const Byte *src2;
- int srcFinished2;
- int encodingWasFinished;
- ECoderStatus status2;
-
- if (i == 0)
- {
- src2 = src;
- srcLen2 = srcLenOrig - *srcLen;
- srcFinished2 = srcWasFinished;
- }
- else
- {
- size_t k = i - 1;
- src2 = p->buf + (CODER_BUF_SIZE * k) + p->pos[k];
- srcLen2 = p->size[k] - p->pos[k];
- srcFinished2 = p->finished[k];
- }
-
- if (i == p->numCoders - 1)
- {
- dest2 = dest;
- destLen2 = destLenOrig - *destLen;
- }
- else
- {
- if (p->pos[i] != p->size[i])
- continue;
- dest2 = p->buf + (CODER_BUF_SIZE * i);
- destLen2 = CODER_BUF_SIZE;
- }
-
- // destLen2_Orig = destLen2;
-
- if (p->results[i] != SZ_OK)
- {
- if (resMain == SZ_OK)
- resMain = p->results[i];
- continue;
- }
-
- res = coder->Code2(coder->p,
- dest2, &destLen2,
- src2, &srcLen2, srcFinished2,
- finishMode,
- // &encodingWasFinished,
- &status2);
-
- if (res != SZ_OK)
- {
- p->results[i] = res;
- if (resMain == SZ_OK)
- resMain = res;
- }
-
- encodingWasFinished = (status2 == CODER_STATUS_FINISHED_WITH_MARK);
-
- if (!encodingWasFinished)
- {
- allFinished = False;
- if (p->numCoders == 1 && res == SZ_OK)
- p->status = status2;
- }
-
- if (i == 0)
- {
- *srcLen += srcLen2;
- src += srcLen2;
- }
- else
- p->pos[(size_t)i - 1] += srcLen2;
-
- if (i == p->numCoders - 1)
- {
- *destLen += destLen2;
- dest += destLen2;
- }
- else
- {
- p->size[i] = destLen2;
- p->pos[i] = 0;
- p->finished[i] = encodingWasFinished;
- }
-
- if (destLen2 != 0 || srcLen2 != 0)
- processed = True;
- }
-
- if (!processed)
- {
- if (allFinished)
- p->status = CODER_STATUS_FINISHED_WITH_MARK;
- return resMain;
- }
- }
-}
-
-
-SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf)
-{
- *p = (CXzStreamFlags)GetBe16(buf + XZ_SIG_SIZE);
- if (CrcCalc(buf + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE) !=
- GetUi32(buf + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE))
- return SZ_ERROR_NO_ARCHIVE;
- return XzFlags_IsSupported(*p) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
-}
-
-static BoolInt Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf)
-{
- return indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2)
- && GetUi32(buf) == CrcCalc(buf + 4, 6)
- && flags == GetBe16(buf + 8)
- && buf[10] == XZ_FOOTER_SIG_0
- && buf[11] == XZ_FOOTER_SIG_1;
-}
-
-#define READ_VARINT_AND_CHECK(buf, pos, size, res) \
- { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \
- if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; }
-
-
-static BoolInt XzBlock_AreSupportedFilters(const CXzBlock *p)
-{
- unsigned numFilters = XzBlock_GetNumFilters(p) - 1;
- unsigned i;
- {
- const CXzFilter *f = &p->filters[numFilters];
- if (f->id != XZ_ID_LZMA2 || f->propsSize != 1 || f->props[0] > 40)
- return False;
- }
-
- for (i = 0; i < numFilters; i++)
- {
- const CXzFilter *f = &p->filters[i];
- if (f->id == XZ_ID_Delta)
- {
- if (f->propsSize != 1)
- return False;
- }
- else if (f->id < XZ_ID_Delta
- || f->id > XZ_ID_SPARC
- || (f->propsSize != 0 && f->propsSize != 4))
- return False;
- }
- return True;
-}
-
-
-SRes XzBlock_Parse(CXzBlock *p, const Byte *header)
-{
- unsigned pos;
- unsigned numFilters, i;
- unsigned headerSize = (unsigned)header[0] << 2;
-
- /* (headerSize != 0) : another code checks */
-
- if (CrcCalc(header, headerSize) != GetUi32(header + headerSize))
- return SZ_ERROR_ARCHIVE;
-
- pos = 1;
- p->flags = header[pos++];
-
- p->packSize = (UInt64)(Int64)-1;
- if (XzBlock_HasPackSize(p))
- {
- READ_VARINT_AND_CHECK(header, pos, headerSize, &p->packSize);
- if (p->packSize == 0 || p->packSize + headerSize >= (UInt64)1 << 63)
- return SZ_ERROR_ARCHIVE;
- }
-
- p->unpackSize = (UInt64)(Int64)-1;
- if (XzBlock_HasUnpackSize(p))
- READ_VARINT_AND_CHECK(header, pos, headerSize, &p->unpackSize);
-
- numFilters = XzBlock_GetNumFilters(p);
- for (i = 0; i < numFilters; i++)
- {
- CXzFilter *filter = p->filters + i;
- UInt64 size;
- READ_VARINT_AND_CHECK(header, pos, headerSize, &filter->id);
- READ_VARINT_AND_CHECK(header, pos, headerSize, &size);
- if (size > headerSize - pos || size > XZ_FILTER_PROPS_SIZE_MAX)
- return SZ_ERROR_ARCHIVE;
- filter->propsSize = (UInt32)size;
- memcpy(filter->props, header + pos, (size_t)size);
- pos += (unsigned)size;
-
- #ifdef XZ_DUMP
- printf("\nf[%u] = %2X: ", i, (unsigned)filter->id);
- {
- unsigned i;
- for (i = 0; i < size; i++)
- printf(" %2X", filter->props[i]);
- }
- #endif
- }
-
- if (XzBlock_HasUnsupportedFlags(p))
- return SZ_ERROR_UNSUPPORTED;
-
- while (pos < headerSize)
- if (header[pos++] != 0)
- return SZ_ERROR_ARCHIVE;
- return SZ_OK;
-}
-
-
-
-
-static SRes XzDecMix_Init(CMixCoder *p, const CXzBlock *block, Byte *outBuf, size_t outBufSize)
-{
- unsigned i;
- BoolInt needReInit = True;
- unsigned numFilters = XzBlock_GetNumFilters(block);
-
- if (numFilters == p->numCoders && ((p->outBuf && outBuf) || (!p->outBuf && !outBuf)))
- {
- needReInit = False;
- for (i = 0; i < numFilters; i++)
- if (p->ids[i] != block->filters[numFilters - 1 - i].id)
- {
- needReInit = True;
- break;
- }
- }
-
- // p->SingleBufMode = (outBuf != NULL);
- p->outBuf = outBuf;
- p->outBufSize = outBufSize;
-
- // p->SingleBufMode = False;
- // outBuf = NULL;
-
- if (needReInit)
- {
- MixCoder_Free(p);
- for (i = 0; i < numFilters; i++)
- {
- RINOK(MixCoder_SetFromMethod(p, i, block->filters[numFilters - 1 - i].id, outBuf, outBufSize));
- }
- p->numCoders = numFilters;
- }
- else
- {
- RINOK(MixCoder_ResetFromMethod(p, 0, block->filters[numFilters - 1].id, outBuf, outBufSize));
- }
-
- for (i = 0; i < numFilters; i++)
- {
- const CXzFilter *f = &block->filters[numFilters - 1 - i];
- IStateCoder *sc = &p->coders[i];
- RINOK(sc->SetProps(sc->p, f->props, f->propsSize, p->alloc));
- }
-
- MixCoder_Init(p);
- return SZ_OK;
-}
-
-
-
-void XzUnpacker_Init(CXzUnpacker *p)
-{
- p->state = XZ_STATE_STREAM_HEADER;
- p->pos = 0;
- p->numStartedStreams = 0;
- p->numFinishedStreams = 0;
- p->numTotalBlocks = 0;
- p->padSize = 0;
- p->decodeOnlyOneBlock = 0;
-
- p->parseMode = False;
- p->decodeToStreamSignature = False;
-
- // p->outBuf = NULL;
- // p->outBufSize = 0;
- p->outDataWritten = 0;
-}
-
-
-void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize)
-{
- p->outBuf = outBuf;
- p->outBufSize = outBufSize;
-}
-
-
-void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc)
-{
- MixCoder_Construct(&p->decoder, alloc);
- p->outBuf = NULL;
- p->outBufSize = 0;
- XzUnpacker_Init(p);
-}
-
-
-void XzUnpacker_Free(CXzUnpacker *p)
-{
- MixCoder_Free(&p->decoder);
-}
-
-
-void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p)
-{
- p->indexSize = 0;
- p->numBlocks = 0;
- Sha256_Init(&p->sha);
- p->state = XZ_STATE_BLOCK_HEADER;
- p->pos = 0;
- p->decodeOnlyOneBlock = 1;
-}
-
-
-static void XzUnpacker_UpdateIndex(CXzUnpacker *p, UInt64 packSize, UInt64 unpackSize)
-{
- Byte temp[32];
- unsigned num = Xz_WriteVarInt(temp, packSize);
- num += Xz_WriteVarInt(temp + num, unpackSize);
- Sha256_Update(&p->sha, temp, num);
- p->indexSize += num;
- p->numBlocks++;
-}
-
-
-
-SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
- const Byte *src, SizeT *srcLen, int srcFinished,
- ECoderFinishMode finishMode, ECoderStatus *status)
-{
- SizeT destLenOrig = *destLen;
- SizeT srcLenOrig = *srcLen;
- *destLen = 0;
- *srcLen = 0;
- *status = CODER_STATUS_NOT_SPECIFIED;
-
- for (;;)
- {
- SizeT srcRem;
-
- if (p->state == XZ_STATE_BLOCK)
- {
- SizeT destLen2 = destLenOrig - *destLen;
- SizeT srcLen2 = srcLenOrig - *srcLen;
- SRes res;
-
- ECoderFinishMode finishMode2 = finishMode;
- BoolInt srcFinished2 = srcFinished;
- BoolInt destFinish = False;
-
- if (p->block.packSize != (UInt64)(Int64)-1)
- {
- UInt64 rem = p->block.packSize - p->packSize;
- if (srcLen2 >= rem)
- {
- srcFinished2 = True;
- srcLen2 = (SizeT)rem;
- }
- if (rem == 0 && p->block.unpackSize == p->unpackSize)
- return SZ_ERROR_DATA;
- }
-
- if (p->block.unpackSize != (UInt64)(Int64)-1)
- {
- UInt64 rem = p->block.unpackSize - p->unpackSize;
- if (destLen2 >= rem)
- {
- destFinish = True;
- finishMode2 = CODER_FINISH_END;
- destLen2 = (SizeT)rem;
- }
- }
-
- /*
- if (srcLen2 == 0 && destLen2 == 0)
- {
- *status = CODER_STATUS_NOT_FINISHED;
- return SZ_OK;
- }
- */
-
- {
- res = MixCoder_Code(&p->decoder,
- (p->outBuf ? NULL : dest), &destLen2, destFinish,
- src, &srcLen2, srcFinished2,
- finishMode2);
-
- *status = p->decoder.status;
- XzCheck_Update(&p->check, (p->outBuf ? p->outBuf + p->outDataWritten : dest), destLen2);
- if (!p->outBuf)
- dest += destLen2;
- p->outDataWritten += destLen2;
- }
-
- (*srcLen) += srcLen2;
- src += srcLen2;
- p->packSize += srcLen2;
- (*destLen) += destLen2;
- p->unpackSize += destLen2;
-
- RINOK(res);
-
- if (*status != CODER_STATUS_FINISHED_WITH_MARK)
- {
- if (p->block.packSize == p->packSize
- && *status == CODER_STATUS_NEEDS_MORE_INPUT)
- {
- PRF_STR("CODER_STATUS_NEEDS_MORE_INPUT");
- *status = CODER_STATUS_NOT_SPECIFIED;
- return SZ_ERROR_DATA;
- }
-
- return SZ_OK;
- }
- {
- XzUnpacker_UpdateIndex(p, XzUnpacker_GetPackSizeForIndex(p), p->unpackSize);
- p->state = XZ_STATE_BLOCK_FOOTER;
- p->pos = 0;
- p->alignPos = 0;
- *status = CODER_STATUS_NOT_SPECIFIED;
-
- if ((p->block.packSize != (UInt64)(Int64)-1 && p->block.packSize != p->packSize)
- || (p->block.unpackSize != (UInt64)(Int64)-1 && p->block.unpackSize != p->unpackSize))
- {
- PRF_STR("ERROR: block.size mismatch");
- return SZ_ERROR_DATA;
- }
- }
- // continue;
- }
-
- srcRem = srcLenOrig - *srcLen;
-
- // XZ_STATE_BLOCK_FOOTER can transit to XZ_STATE_BLOCK_HEADER without input bytes
- if (srcRem == 0 && p->state != XZ_STATE_BLOCK_FOOTER)
- {
- *status = CODER_STATUS_NEEDS_MORE_INPUT;
- return SZ_OK;
- }
-
- switch (p->state)
- {
- case XZ_STATE_STREAM_HEADER:
- {
- if (p->pos < XZ_STREAM_HEADER_SIZE)
- {
- if (p->pos < XZ_SIG_SIZE && *src != XZ_SIG[p->pos])
- return SZ_ERROR_NO_ARCHIVE;
- if (p->decodeToStreamSignature)
- return SZ_OK;
- p->buf[p->pos++] = *src++;
- (*srcLen)++;
- }
- else
- {
- RINOK(Xz_ParseHeader(&p->streamFlags, p->buf));
- p->numStartedStreams++;
- p->indexSize = 0;
- p->numBlocks = 0;
- Sha256_Init(&p->sha);
- p->state = XZ_STATE_BLOCK_HEADER;
- p->pos = 0;
- }
- break;
- }
-
- case XZ_STATE_BLOCK_HEADER:
- {
- if (p->pos == 0)
- {
- p->buf[p->pos++] = *src++;
- (*srcLen)++;
- if (p->buf[0] == 0)
- {
- if (p->decodeOnlyOneBlock)
- return SZ_ERROR_DATA;
- p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks);
- p->indexPos = p->indexPreSize;
- p->indexSize += p->indexPreSize;
- Sha256_Final(&p->sha, p->shaDigest);
- Sha256_Init(&p->sha);
- p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize);
- p->state = XZ_STATE_STREAM_INDEX;
- break;
- }
- p->blockHeaderSize = ((UInt32)p->buf[0] << 2) + 4;
- break;
- }
-
- if (p->pos != p->blockHeaderSize)
- {
- UInt32 cur = p->blockHeaderSize - p->pos;
- if (cur > srcRem)
- cur = (UInt32)srcRem;
- memcpy(p->buf + p->pos, src, cur);
- p->pos += cur;
- (*srcLen) += cur;
- src += cur;
- }
- else
- {
- RINOK(XzBlock_Parse(&p->block, p->buf));
- if (!XzBlock_AreSupportedFilters(&p->block))
- return SZ_ERROR_UNSUPPORTED;
- p->numTotalBlocks++;
- p->state = XZ_STATE_BLOCK;
- p->packSize = 0;
- p->unpackSize = 0;
- XzCheck_Init(&p->check, XzFlags_GetCheckType(p->streamFlags));
- if (p->parseMode)
- {
- p->headerParsedOk = True;
- return SZ_OK;
- }
- RINOK(XzDecMix_Init(&p->decoder, &p->block, p->outBuf, p->outBufSize));
- }
- break;
- }
-
- case XZ_STATE_BLOCK_FOOTER:
- {
- if ((((unsigned)p->packSize + p->alignPos) & 3) != 0)
- {
- if (srcRem == 0)
- {
- *status = CODER_STATUS_NEEDS_MORE_INPUT;
- return SZ_OK;
- }
- (*srcLen)++;
- p->alignPos++;
- if (*src++ != 0)
- return SZ_ERROR_CRC;
- }
- else
- {
- UInt32 checkSize = XzFlags_GetCheckSize(p->streamFlags);
- UInt32 cur = checkSize - p->pos;
- if (cur != 0)
- {
- if (srcRem == 0)
- {
- *status = CODER_STATUS_NEEDS_MORE_INPUT;
- return SZ_OK;
- }
- if (cur > srcRem)
- cur = (UInt32)srcRem;
- memcpy(p->buf + p->pos, src, cur);
- p->pos += cur;
- (*srcLen) += cur;
- src += cur;
- if (checkSize != p->pos)
- break;
- }
- {
- Byte digest[XZ_CHECK_SIZE_MAX];
- p->state = XZ_STATE_BLOCK_HEADER;
- p->pos = 0;
- if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0)
- return SZ_ERROR_CRC;
- if (p->decodeOnlyOneBlock)
- {
- *status = CODER_STATUS_FINISHED_WITH_MARK;
- return SZ_OK;
- }
- }
- }
- break;
- }
-
- case XZ_STATE_STREAM_INDEX:
- {
- if (p->pos < p->indexPreSize)
- {
- (*srcLen)++;
- if (*src++ != p->buf[p->pos++])
- return SZ_ERROR_CRC;
- }
- else
- {
- if (p->indexPos < p->indexSize)
- {
- UInt64 cur = p->indexSize - p->indexPos;
- if (srcRem > cur)
- srcRem = (SizeT)cur;
- p->crc = CrcUpdate(p->crc, src, srcRem);
- Sha256_Update(&p->sha, src, srcRem);
- (*srcLen) += srcRem;
- src += srcRem;
- p->indexPos += srcRem;
- }
- else if ((p->indexPos & 3) != 0)
- {
- Byte b = *src++;
- p->crc = CRC_UPDATE_BYTE(p->crc, b);
- (*srcLen)++;
- p->indexPos++;
- p->indexSize++;
- if (b != 0)
- return SZ_ERROR_CRC;
- }
- else
- {
- Byte digest[SHA256_DIGEST_SIZE];
- p->state = XZ_STATE_STREAM_INDEX_CRC;
- p->indexSize += 4;
- p->pos = 0;
- Sha256_Final(&p->sha, digest);
- if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0)
- return SZ_ERROR_CRC;
- }
- }
- break;
- }
-
- case XZ_STATE_STREAM_INDEX_CRC:
- {
- if (p->pos < 4)
- {
- (*srcLen)++;
- p->buf[p->pos++] = *src++;
- }
- else
- {
- p->state = XZ_STATE_STREAM_FOOTER;
- p->pos = 0;
- if (CRC_GET_DIGEST(p->crc) != GetUi32(p->buf))
- return SZ_ERROR_CRC;
- }
- break;
- }
-
- case XZ_STATE_STREAM_FOOTER:
- {
- UInt32 cur = XZ_STREAM_FOOTER_SIZE - p->pos;
- if (cur > srcRem)
- cur = (UInt32)srcRem;
- memcpy(p->buf + p->pos, src, cur);
- p->pos += cur;
- (*srcLen) += cur;
- src += cur;
- if (p->pos == XZ_STREAM_FOOTER_SIZE)
- {
- p->state = XZ_STATE_STREAM_PADDING;
- p->numFinishedStreams++;
- p->padSize = 0;
- if (!Xz_CheckFooter(p->streamFlags, p->indexSize, p->buf))
- return SZ_ERROR_CRC;
- }
- break;
- }
-
- case XZ_STATE_STREAM_PADDING:
- {
- if (*src != 0)
- {
- if (((UInt32)p->padSize & 3) != 0)
- return SZ_ERROR_NO_ARCHIVE;
- p->pos = 0;
- p->state = XZ_STATE_STREAM_HEADER;
- }
- else
- {
- (*srcLen)++;
- src++;
- p->padSize++;
- }
- break;
- }
-
- case XZ_STATE_BLOCK: break; /* to disable GCC warning */
- }
- }
- /*
- if (p->state == XZ_STATE_FINISHED)
- *status = CODER_STATUS_FINISHED_WITH_MARK;
- return SZ_OK;
- */
-}
-
-
-SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen,
- const Byte *src, SizeT *srcLen,
- ECoderFinishMode finishMode, ECoderStatus *status)
-{
- XzUnpacker_Init(p);
- XzUnpacker_SetOutBuf(p, dest, *destLen);
-
- return XzUnpacker_Code(p,
- NULL, destLen,
- src, srcLen, True,
- finishMode, status);
-}
-
-
-BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p)
-{
- return (p->state == XZ_STATE_BLOCK_HEADER) && (p->pos == 0);
-}
-
-BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p)
-{
- return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0);
-}
-
-UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p)
-{
- UInt64 num = 0;
- if (p->state == XZ_STATE_STREAM_PADDING)
- num = p->padSize;
- else if (p->state == XZ_STATE_STREAM_HEADER)
- num = p->padSize + p->pos;
- return num;
-}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-#ifndef _7ZIP_ST
-#include "MtDec.h"
-#endif
-
-
-void XzDecMtProps_Init(CXzDecMtProps *p)
-{
- p->inBufSize_ST = 1 << 18;
- p->outStep_ST = 1 << 20;
- p->ignoreErrors = False;
-
- #ifndef _7ZIP_ST
- p->numThreads = 1;
- p->inBufSize_MT = 1 << 18;
- p->memUseMax = sizeof(size_t) << 28;
- #endif
-}
-
-
-
-#ifndef _7ZIP_ST
-
-/* ---------- CXzDecMtThread ---------- */
-
-typedef struct
-{
- Byte *outBuf;
- size_t outBufSize;
- size_t outPreSize;
- size_t inPreSize;
- size_t inPreHeaderSize;
- size_t blockPackSize_for_Index; // including block header and checksum.
- size_t blockPackTotal; // including stream header, block header and checksum.
- size_t inCodeSize;
- size_t outCodeSize;
- ECoderStatus status;
- SRes codeRes;
- BoolInt skipMode;
- // BoolInt finishedWithMark;
- EMtDecParseState parseState;
- BoolInt parsing_Truncated;
- BoolInt atBlockHeader;
- CXzStreamFlags streamFlags;
- // UInt64 numFinishedStreams
- UInt64 numStreams;
- UInt64 numTotalBlocks;
- UInt64 numBlocks;
-
- BoolInt dec_created;
- CXzUnpacker dec;
-
- Byte mtPad[1 << 7];
-} CXzDecMtThread;
-
-#endif
-
-
-/* ---------- CXzDecMt ---------- */
-
-typedef struct
-{
- CAlignOffsetAlloc alignOffsetAlloc;
- ISzAllocPtr allocMid;
-
- CXzDecMtProps props;
- size_t unpackBlockMaxSize;
-
- ISeqInStream *inStream;
- ISeqOutStream *outStream;
- ICompressProgress *progress;
- // CXzStatInfo *stat;
-
- BoolInt finishMode;
- BoolInt outSize_Defined;
- UInt64 outSize;
-
- UInt64 outProcessed;
- UInt64 inProcessed;
- UInt64 readProcessed;
- BoolInt readWasFinished;
- SRes readRes;
- SRes writeRes;
-
- Byte *outBuf;
- size_t outBufSize;
- Byte *inBuf;
- size_t inBufSize;
-
- CXzUnpacker dec;
-
- ECoderStatus status;
- SRes codeRes;
-
- #ifndef _7ZIP_ST
- BoolInt mainDecoderWasCalled;
- // int statErrorDefined;
- int finishedDecoderIndex;
-
- // global values that are used in Parse stage
- CXzStreamFlags streamFlags;
- // UInt64 numFinishedStreams
- UInt64 numStreams;
- UInt64 numTotalBlocks;
- UInt64 numBlocks;
-
- // UInt64 numBadBlocks;
- SRes mainErrorCode;
-
- BoolInt isBlockHeaderState_Parse;
- BoolInt isBlockHeaderState_Write;
- UInt64 outProcessed_Parse;
- BoolInt parsing_Truncated;
-
- BoolInt mtc_WasConstructed;
- CMtDec mtc;
- CXzDecMtThread coders[MTDEC__THREADS_MAX];
- #endif
-
-} CXzDecMt;
-
-
-
-CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid)
-{
- CXzDecMt *p = (CXzDecMt *)ISzAlloc_Alloc(alloc, sizeof(CXzDecMt));
- if (!p)
- return NULL;
-
- AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc);
- p->alignOffsetAlloc.baseAlloc = alloc;
- p->alignOffsetAlloc.numAlignBits = 7;
- p->alignOffsetAlloc.offset = 0;
-
- p->allocMid = allocMid;
-
- p->outBuf = NULL;
- p->outBufSize = 0;
- p->inBuf = NULL;
- p->inBufSize = 0;
-
- XzUnpacker_Construct(&p->dec, &p->alignOffsetAlloc.vt);
-
- p->unpackBlockMaxSize = 0;
-
- XzDecMtProps_Init(&p->props);
-
- #ifndef _7ZIP_ST
- p->mtc_WasConstructed = False;
- {
- unsigned i;
- for (i = 0; i < MTDEC__THREADS_MAX; i++)
- {
- CXzDecMtThread *coder = &p->coders[i];
- coder->dec_created = False;
- coder->outBuf = NULL;
- coder->outBufSize = 0;
- }
- }
- #endif
-
- return p;
-}
-
-
-#ifndef _7ZIP_ST
-
-static void XzDecMt_FreeOutBufs(CXzDecMt *p)
-{
- unsigned i;
- for (i = 0; i < MTDEC__THREADS_MAX; i++)
- {
- CXzDecMtThread *coder = &p->coders[i];
- if (coder->outBuf)
- {
- ISzAlloc_Free(p->allocMid, coder->outBuf);
- coder->outBuf = NULL;
- coder->outBufSize = 0;
- }
- }
- p->unpackBlockMaxSize = 0;
-}
-
-#endif
-
-
-
-static void XzDecMt_FreeSt(CXzDecMt *p)
-{
- XzUnpacker_Free(&p->dec);
-
- if (p->outBuf)
- {
- ISzAlloc_Free(p->allocMid, p->outBuf);
- p->outBuf = NULL;
- }
- p->outBufSize = 0;
-
- if (p->inBuf)
- {
- ISzAlloc_Free(p->allocMid, p->inBuf);
- p->inBuf = NULL;
- }
- p->inBufSize = 0;
-}
-
-
-void XzDecMt_Destroy(CXzDecMtHandle pp)
-{
- CXzDecMt *p = (CXzDecMt *)pp;
-
- XzDecMt_FreeSt(p);
-
- #ifndef _7ZIP_ST
-
- if (p->mtc_WasConstructed)
- {
- MtDec_Destruct(&p->mtc);
- p->mtc_WasConstructed = False;
- }
- {
- unsigned i;
- for (i = 0; i < MTDEC__THREADS_MAX; i++)
- {
- CXzDecMtThread *t = &p->coders[i];
- if (t->dec_created)
- {
- // we don't need to free dict here
- XzUnpacker_Free(&t->dec);
- t->dec_created = False;
- }
- }
- }
- XzDecMt_FreeOutBufs(p);
-
- #endif
-
- ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, pp);
-}
-
-
-
-#ifndef _7ZIP_ST
-
-static void XzDecMt_Callback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc)
-{
- CXzDecMt *me = (CXzDecMt *)obj;
- CXzDecMtThread *coder = &me->coders[coderIndex];
- size_t srcSize = cc->srcSize;
-
- cc->srcSize = 0;
- cc->outPos = 0;
- cc->state = MTDEC_PARSE_CONTINUE;
-
- cc->canCreateNewThread = True;
-
- if (cc->startCall)
- {
- coder->outPreSize = 0;
- coder->inPreSize = 0;
- coder->inPreHeaderSize = 0;
- coder->parseState = MTDEC_PARSE_CONTINUE;
- coder->parsing_Truncated = False;
- coder->skipMode = False;
- coder->codeRes = SZ_OK;
- coder->status = CODER_STATUS_NOT_SPECIFIED;
- coder->inCodeSize = 0;
- coder->outCodeSize = 0;
-
- coder->numStreams = me->numStreams;
- coder->numTotalBlocks = me->numTotalBlocks;
- coder->numBlocks = me->numBlocks;
-
- if (!coder->dec_created)
- {
- XzUnpacker_Construct(&coder->dec, &me->alignOffsetAlloc.vt);
- coder->dec_created = True;
- }
-
- XzUnpacker_Init(&coder->dec);
-
- if (me->isBlockHeaderState_Parse)
- {
- coder->dec.streamFlags = me->streamFlags;
- coder->atBlockHeader = True;
- XzUnpacker_PrepareToRandomBlockDecoding(&coder->dec);
- }
- else
- {
- coder->atBlockHeader = False;
- me->isBlockHeaderState_Parse = True;
- }
-
- coder->dec.numStartedStreams = me->numStreams;
- coder->dec.numTotalBlocks = me->numTotalBlocks;
- coder->dec.numBlocks = me->numBlocks;
- }
-
- while (!coder->skipMode)
- {
- ECoderStatus status;
- SRes res;
- size_t srcSize2 = srcSize;
- size_t destSize = (size_t)0 - 1;
-
- coder->dec.parseMode = True;
- coder->dec.headerParsedOk = False;
-
- PRF_STR_INT("Parse", srcSize2);
-
- res = XzUnpacker_Code(&coder->dec,
- NULL, &destSize,
- cc->src, &srcSize2, cc->srcFinished,
- CODER_FINISH_END, &status);
-
- // PRF(printf(" res = %d, srcSize2 = %d", res, (unsigned)srcSize2));
-
- coder->codeRes = res;
- coder->status = status;
- cc->srcSize += srcSize2;
- srcSize -= srcSize2;
- coder->inPreHeaderSize += srcSize2;
- coder->inPreSize = coder->inPreHeaderSize;
-
- if (res != SZ_OK)
- {
- cc->state =
- coder->parseState = MTDEC_PARSE_END;
- /*
- if (res == SZ_ERROR_MEM)
- return res;
- return SZ_OK;
- */
- return; // res;
- }
-
- if (coder->dec.headerParsedOk)
- {
- const CXzBlock *block = &coder->dec.block;
- if (XzBlock_HasUnpackSize(block)
- // && block->unpackSize <= me->props.outBlockMax
- && XzBlock_HasPackSize(block))
- {
- {
- if (block->unpackSize * 2 * me->mtc.numStartedThreads > me->props.memUseMax)
- {
- cc->state = MTDEC_PARSE_OVERFLOW;
- return; // SZ_OK;
- }
- }
- {
- UInt64 packSize = block->packSize;
- UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3);
- UInt32 checkSize = XzFlags_GetCheckSize(coder->dec.streamFlags);
- UInt64 blockPackSum = coder->inPreSize + packSizeAligned + checkSize;
- // if (blockPackSum <= me->props.inBlockMax)
- // unpackBlockMaxSize
- {
- coder->blockPackSize_for_Index = (size_t)(coder->dec.blockHeaderSize + packSize + checkSize);
- coder->blockPackTotal = (size_t)blockPackSum;
- coder->outPreSize = (size_t)block->unpackSize;
- coder->streamFlags = coder->dec.streamFlags;
- me->streamFlags = coder->dec.streamFlags;
- coder->skipMode = True;
- break;
- }
- }
- }
- }
- else
- // if (coder->inPreSize <= me->props.inBlockMax)
- {
- if (!cc->srcFinished)
- return; // SZ_OK;
- cc->state =
- coder->parseState = MTDEC_PARSE_END;
- return; // SZ_OK;
- }
- cc->state = MTDEC_PARSE_OVERFLOW;
- return; // SZ_OK;
- }
-
- // ---------- skipMode ----------
- {
- UInt64 rem = coder->blockPackTotal - coder->inPreSize;
- size_t cur = srcSize;
- if (cur > rem)
- cur = (size_t)rem;
- cc->srcSize += cur;
- coder->inPreSize += cur;
- srcSize -= cur;
-
- if (coder->inPreSize == coder->blockPackTotal)
- {
- if (srcSize == 0)
- {
- if (!cc->srcFinished)
- return; // SZ_OK;
- cc->state = MTDEC_PARSE_END;
- }
- else if ((cc->src)[cc->srcSize] == 0) // we check control byte of next block
- cc->state = MTDEC_PARSE_END;
- else
- {
- cc->state = MTDEC_PARSE_NEW;
-
- {
- size_t blockMax = me->unpackBlockMaxSize;
- if (blockMax < coder->outPreSize)
- blockMax = coder->outPreSize;
- {
- UInt64 required = (UInt64)blockMax * (me->mtc.numStartedThreads + 1) * 2;
- if (me->props.memUseMax < required)
- cc->canCreateNewThread = False;
- }
- }
-
- if (me->outSize_Defined)
- {
- // next block can be zero size
- const UInt64 rem2 = me->outSize - me->outProcessed_Parse;
- if (rem2 < coder->outPreSize)
- {
- coder->parsing_Truncated = True;
- cc->state = MTDEC_PARSE_END;
- }
- me->outProcessed_Parse += coder->outPreSize;
- }
- }
- }
- else if (cc->srcFinished)
- cc->state = MTDEC_PARSE_END;
- else
- return; // SZ_OK;
-
- coder->parseState = cc->state;
- cc->outPos = coder->outPreSize;
-
- me->numStreams = coder->dec.numStartedStreams;
- me->numTotalBlocks = coder->dec.numTotalBlocks;
- me->numBlocks = coder->dec.numBlocks + 1;
- return; // SZ_OK;
- }
-}
-
-
-static SRes XzDecMt_Callback_PreCode(void *pp, unsigned coderIndex)
-{
- CXzDecMt *me = (CXzDecMt *)pp;
- CXzDecMtThread *coder = &me->coders[coderIndex];
- Byte *dest;
-
- if (!coder->dec.headerParsedOk)
- return SZ_OK;
-
- dest = coder->outBuf;
-
- if (!dest || coder->outBufSize < coder->outPreSize)
- {
- if (dest)
- {
- ISzAlloc_Free(me->allocMid, dest);
- coder->outBuf = NULL;
- coder->outBufSize = 0;
- }
- {
- size_t outPreSize = coder->outPreSize;
- if (outPreSize == 0)
- outPreSize = 1;
- dest = (Byte *)ISzAlloc_Alloc(me->allocMid, outPreSize);
- }
- if (!dest)
- return SZ_ERROR_MEM;
- coder->outBuf = dest;
- coder->outBufSize = coder->outPreSize;
-
- if (coder->outBufSize > me->unpackBlockMaxSize)
- me->unpackBlockMaxSize = coder->outBufSize;
- }
-
- // return SZ_ERROR_MEM;
-
- XzUnpacker_SetOutBuf(&coder->dec, coder->outBuf, coder->outBufSize);
-
- {
- SRes res = XzDecMix_Init(&coder->dec.decoder, &coder->dec.block, coder->outBuf, coder->outBufSize);
- // res = SZ_ERROR_UNSUPPORTED; // to test
- coder->codeRes = res;
- if (res != SZ_OK)
- {
- // if (res == SZ_ERROR_MEM) return res;
- if (me->props.ignoreErrors && res != SZ_ERROR_MEM)
- return S_OK;
- return res;
- }
- }
-
- return SZ_OK;
-}
-
-
-static SRes XzDecMt_Callback_Code(void *pp, unsigned coderIndex,
- const Byte *src, size_t srcSize, int srcFinished,
- // int finished, int blockFinished,
- UInt64 *inCodePos, UInt64 *outCodePos, int *stop)
-{
- CXzDecMt *me = (CXzDecMt *)pp;
- CXzDecMtThread *coder = &me->coders[coderIndex];
-
- *inCodePos = coder->inCodeSize;
- *outCodePos = coder->outCodeSize;
- *stop = True;
-
- if (coder->inCodeSize < coder->inPreHeaderSize)
- {
- UInt64 rem = coder->inPreHeaderSize - coder->inCodeSize;
- size_t step = srcSize;
- if (step > rem)
- step = (size_t)rem;
- src += step;
- srcSize -= step;
- coder->inCodeSize += step;
- if (coder->inCodeSize < coder->inPreHeaderSize)
- {
- *stop = False;
- return SZ_OK;
- }
- }
-
- if (!coder->dec.headerParsedOk)
- return SZ_OK;
- if (!coder->outBuf)
- return SZ_OK;
-
- if (coder->codeRes == SZ_OK)
- {
- ECoderStatus status;
- SRes res;
- size_t srcProcessed = srcSize;
- size_t outSizeCur = coder->outPreSize - coder->dec.outDataWritten;
-
- // PRF(printf("\nCallback_Code: Code %d %d\n", (unsigned)srcSize, (unsigned)outSizeCur));
-
- res = XzUnpacker_Code(&coder->dec,
- NULL, &outSizeCur,
- src, &srcProcessed, srcFinished,
- // coder->finishedWithMark ? CODER_FINISH_END : CODER_FINISH_ANY,
- CODER_FINISH_END,
- &status);
-
- // PRF(printf(" res = %d, srcSize2 = %d, outSizeCur = %d", res, (unsigned)srcProcessed, (unsigned)outSizeCur));
-
- coder->codeRes = res;
- coder->status = status;
- coder->inCodeSize += srcProcessed;
- coder->outCodeSize = coder->dec.outDataWritten;
- *inCodePos = coder->inCodeSize;
- *outCodePos = coder->outCodeSize;
-
- if (res == SZ_OK)
- {
- if (srcProcessed == srcSize)
- *stop = False;
- return SZ_OK;
- }
- }
-
- if (me->props.ignoreErrors && coder->codeRes != SZ_ERROR_MEM)
- {
- *inCodePos = coder->inPreSize;
- *outCodePos = coder->outPreSize;
- return S_OK;
- }
- return coder->codeRes;
-}
-
-
-#define XZDECMT_STREAM_WRITE_STEP (1 << 24)
-
-static SRes XzDecMt_Callback_Write(void *pp, unsigned coderIndex,
- BoolInt needWriteToStream,
- const Byte *src, size_t srcSize,
- // int srcFinished,
- BoolInt *needContinue,
- BoolInt *canRecode)
-{
- CXzDecMt *me = (CXzDecMt *)pp;
- const CXzDecMtThread *coder = &me->coders[coderIndex];
-
- // PRF(printf("\nWrite processed = %d srcSize = %d\n", (unsigned)me->mtc.inProcessed, (unsigned)srcSize));
-
- *needContinue = False;
- *canRecode = True;
-
- if (!needWriteToStream)
- return SZ_OK;
-
- if (!coder->dec.headerParsedOk || !coder->outBuf)
- {
- if (me->finishedDecoderIndex < 0)
- me->finishedDecoderIndex = coderIndex;
- return SZ_OK;
- }
-
- if (me->finishedDecoderIndex >= 0)
- return SZ_OK;
-
- me->mtc.inProcessed += coder->inCodeSize;
-
- *canRecode = False;
-
- {
- SRes res;
- size_t size = coder->outCodeSize;
- Byte *data = coder->outBuf;
-
- // we use in me->dec: sha, numBlocks, indexSize
-
- if (!me->isBlockHeaderState_Write)
- {
- XzUnpacker_PrepareToRandomBlockDecoding(&me->dec);
- me->dec.decodeOnlyOneBlock = False;
- me->dec.numStartedStreams = coder->dec.numStartedStreams;
- me->dec.streamFlags = coder->streamFlags;
-
- me->isBlockHeaderState_Write = True;
- }
-
- me->dec.numTotalBlocks = coder->dec.numTotalBlocks;
- XzUnpacker_UpdateIndex(&me->dec, coder->blockPackSize_for_Index, coder->outPreSize);
-
- if (coder->outPreSize != size)
- {
- if (me->props.ignoreErrors)
- {
- memset(data + size, 0, coder->outPreSize - size);
- size = coder->outPreSize;
- }
- // me->numBadBlocks++;
- if (me->mainErrorCode == SZ_OK)
- {
- if ((int)coder->status == LZMA_STATUS_NEEDS_MORE_INPUT)
- me->mainErrorCode = SZ_ERROR_INPUT_EOF;
- else
- me->mainErrorCode = SZ_ERROR_DATA;
- }
- }
-
- if (me->writeRes != SZ_OK)
- return me->writeRes;
-
- res = SZ_OK;
- {
- if (me->outSize_Defined)
- {
- const UInt64 rem = me->outSize - me->outProcessed;
- if (size > rem)
- size = (SizeT)rem;
- }
-
- for (;;)
- {
- size_t cur = size;
- size_t written;
- if (cur > XZDECMT_STREAM_WRITE_STEP)
- cur = XZDECMT_STREAM_WRITE_STEP;
-
- written = ISeqOutStream_Write(me->outStream, data, cur);
-
- // PRF(printf("\nWritten ask = %d written = %d\n", (unsigned)cur, (unsigned)written));
-
- me->outProcessed += written;
- if (written != cur)
- {
- me->writeRes = SZ_ERROR_WRITE;
- res = me->writeRes;
- break;
- }
- data += cur;
- size -= cur;
- // PRF_STR_INT("Written size =", size);
- if (size == 0)
- break;
- res = MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0);
- if (res != SZ_OK)
- break;
- }
- }
-
- if (coder->codeRes != SZ_OK)
- if (!me->props.ignoreErrors)
- {
- me->finishedDecoderIndex = coderIndex;
- return res;
- }
-
- RINOK(res);
-
- if (coder->inPreSize != coder->inCodeSize
- || coder->blockPackTotal != coder->inCodeSize)
- {
- me->finishedDecoderIndex = coderIndex;
- return SZ_OK;
- }
-
- if (coder->parseState != MTDEC_PARSE_END)
- {
- *needContinue = True;
- return SZ_OK;
- }
- }
-
- // (coder->state == MTDEC_PARSE_END) means that there are no other working threads
- // so we can use mtc variables without lock
-
- PRF_STR_INT("Write MTDEC_PARSE_END", me->mtc.inProcessed);
-
- me->mtc.mtProgress.totalInSize = me->mtc.inProcessed;
- {
- CXzUnpacker *dec = &me->dec;
-
- PRF_STR_INT("PostSingle", srcSize);
-
- {
- size_t srcProcessed = srcSize;
- ECoderStatus status;
- size_t outSizeCur = 0;
- SRes res;
-
- // dec->decodeOnlyOneBlock = False;
- dec->decodeToStreamSignature = True;
-
- me->mainDecoderWasCalled = True;
-
- if (coder->parsing_Truncated)
- {
- me->parsing_Truncated = True;
- return SZ_OK;
- }
-
- res = XzUnpacker_Code(dec,
- NULL, &outSizeCur,
- src, &srcProcessed,
- me->mtc.readWasFinished, // srcFinished
- CODER_FINISH_END, // CODER_FINISH_ANY,
- &status);
-
- me->status = status;
- me->codeRes = res;
-
- me->mtc.inProcessed += srcProcessed;
- me->mtc.mtProgress.totalInSize = me->mtc.inProcessed;
-
- if (res != SZ_OK)
- {
- return S_OK;
- // return res;
- }
-
- if (dec->state == XZ_STATE_STREAM_HEADER)
- {
- *needContinue = True;
- me->isBlockHeaderState_Parse = False;
- me->isBlockHeaderState_Write = False;
- {
- Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc);
- if (!crossBuf)
- return SZ_ERROR_MEM;
- memcpy(crossBuf, src + srcProcessed, srcSize - srcProcessed);
- }
- me->mtc.crossStart = 0;
- me->mtc.crossEnd = srcSize - srcProcessed;
- return SZ_OK;
- }
-
- if (status != CODER_STATUS_NEEDS_MORE_INPUT)
- {
- return E_FAIL;
- }
-
- if (me->mtc.readWasFinished)
- {
- return SZ_OK;
- }
- }
-
- {
- size_t inPos;
- size_t inLim;
- const Byte *inData;
- UInt64 inProgressPrev = me->mtc.inProcessed;
-
- // XzDecMt_Prepare_InBuf_ST(p);
- Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc);
- if (!crossBuf)
- return SZ_ERROR_MEM;
-
- inPos = 0;
- inLim = 0;
- // outProcessed = 0;
-
- inData = crossBuf;
-
- for (;;)
- {
- SizeT inProcessed;
- SizeT outProcessed;
- ECoderStatus status;
- SRes res;
-
- if (inPos == inLim)
- {
- if (!me->mtc.readWasFinished)
- {
- inPos = 0;
- inLim = me->mtc.inBufSize;
- me->mtc.readRes = ISeqInStream_Read(me->inStream, (void *)inData, &inLim);
- me->mtc.readProcessed += inLim;
- if (inLim == 0 || me->mtc.readRes != SZ_OK)
- me->mtc.readWasFinished = True;
- }
- }
-
- inProcessed = inLim - inPos;
- outProcessed = 0;
-
- res = XzUnpacker_Code(dec,
- NULL, &outProcessed,
- inData + inPos, &inProcessed,
- (inProcessed == 0), // srcFinished
- CODER_FINISH_END, &status);
-
- me->codeRes = res;
- me->status = status;
- inPos += inProcessed;
- me->mtc.inProcessed += inProcessed;
- me->mtc.mtProgress.totalInSize = me->mtc.inProcessed;
-
- if (res != SZ_OK)
- {
- return S_OK;
- // return res;
- }
-
- if (dec->state == XZ_STATE_STREAM_HEADER)
- {
- *needContinue = True;
- me->mtc.crossStart = inPos;
- me->mtc.crossEnd = inLim;
- me->isBlockHeaderState_Parse = False;
- me->isBlockHeaderState_Write = False;
- return SZ_OK;
- }
-
- if (status != CODER_STATUS_NEEDS_MORE_INPUT)
- return E_FAIL;
-
- if (me->mtc.progress)
- {
- UInt64 inDelta = me->mtc.inProcessed - inProgressPrev;
- if (inDelta >= (1 << 22))
- {
- RINOK(MtProgress_Progress_ST(&me->mtc.mtProgress));
- inProgressPrev = me->mtc.inProcessed;
- }
- }
- if (me->mtc.readWasFinished)
- return SZ_OK;
- }
- }
- }
-}
-
-
-#endif
-
-
-
-void XzStatInfo_Clear(CXzStatInfo *p)
-{
- p->InSize = 0;
- p->OutSize = 0;
-
- p->NumStreams = 0;
- p->NumBlocks = 0;
-
- p->UnpackSize_Defined = False;
-
- p->NumStreams_Defined = False;
- p->NumBlocks_Defined = False;
-
- // p->IsArc = False;
- // p->UnexpectedEnd = False;
- // p->Unsupported = False;
- // p->HeadersError = False;
- // p->DataError = False;
- // p->CrcError = False;
-
- p->DataAfterEnd = False;
- p->DecodingTruncated = False;
-
- p->DecodeRes = SZ_OK;
- p->ReadRes = SZ_OK;
- p->ProgressRes = SZ_OK;
-
- p->CombinedRes = SZ_OK;
- p->CombinedRes_Type = SZ_OK;
-}
-
-
-
-
-static SRes XzDecMt_Decode_ST(CXzDecMt *p
- #ifndef _7ZIP_ST
- , BoolInt tMode
- #endif
- , CXzStatInfo *stat)
-{
- size_t outPos;
- size_t inPos, inLim;
- const Byte *inData;
- UInt64 inPrev, outPrev;
-
- CXzUnpacker *dec;
-
- #ifndef _7ZIP_ST
- if (tMode)
- {
- XzDecMt_FreeOutBufs(p);
- tMode = MtDec_PrepareRead(&p->mtc);
- }
- #endif
-
- if (!p->outBuf || p->outBufSize != p->props.outStep_ST)
- {
- ISzAlloc_Free(p->allocMid, p->outBuf);
- p->outBufSize = 0;
- p->outBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.outStep_ST);
- if (!p->outBuf)
- return SZ_ERROR_MEM;
- p->outBufSize = p->props.outStep_ST;
- }
-
- if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST)
- {
- ISzAlloc_Free(p->allocMid, p->inBuf);
- p->inBufSize = 0;
- p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST);
- if (!p->inBuf)
- return SZ_ERROR_MEM;
- p->inBufSize = p->props.inBufSize_ST;
- }
-
- dec = &p->dec;
- dec->decodeToStreamSignature = False;
- // dec->decodeOnlyOneBlock = False;
-
- XzUnpacker_SetOutBuf(dec, NULL, 0);
-
- inPrev = p->inProcessed;
- outPrev = p->outProcessed;
-
- inPos = 0;
- inLim = 0;
- inData = NULL;
- outPos = 0;
-
- for (;;)
- {
- SizeT outSize;
- BoolInt finished;
- ECoderFinishMode finishMode;
- SizeT inProcessed;
- ECoderStatus status;
- SRes res;
-
- SizeT outProcessed;
-
-
-
- if (inPos == inLim)
- {
- #ifndef _7ZIP_ST
- if (tMode)
- {
- inData = MtDec_Read(&p->mtc, &inLim);
- inPos = 0;
- if (inData)
- continue;
- tMode = False;
- inLim = 0;
- }
- #endif
-
- if (!p->readWasFinished)
- {
- inPos = 0;
- inLim = p->inBufSize;
- inData = p->inBuf;
- p->readRes = ISeqInStream_Read(p->inStream, (void *)inData, &inLim);
- p->readProcessed += inLim;
- if (inLim == 0 || p->readRes != SZ_OK)
- p->readWasFinished = True;
- }
- }
-
- outSize = p->props.outStep_ST - outPos;
-
- finishMode = CODER_FINISH_ANY;
- if (p->outSize_Defined)
- {
- const UInt64 rem = p->outSize - p->outProcessed;
- if (outSize >= rem)
- {
- outSize = (SizeT)rem;
- if (p->finishMode)
- finishMode = CODER_FINISH_END;
- }
- }
-
- inProcessed = inLim - inPos;
- outProcessed = outSize;
-
- res = XzUnpacker_Code(dec, p->outBuf + outPos, &outProcessed,
- inData + inPos, &inProcessed,
- (inPos == inLim), // srcFinished
- finishMode, &status);
-
- p->codeRes = res;
- p->status = status;
-
- inPos += inProcessed;
- outPos += outProcessed;
- p->inProcessed += inProcessed;
- p->outProcessed += outProcessed;
-
- finished = ((inProcessed == 0 && outProcessed == 0) || res != SZ_OK);
-
- if (finished || outProcessed >= outSize)
- if (outPos != 0)
- {
- size_t written = ISeqOutStream_Write(p->outStream, p->outBuf, outPos);
- p->outProcessed += written;
- if (written != outPos)
- {
- stat->CombinedRes_Type = SZ_ERROR_WRITE;
- return SZ_ERROR_WRITE;
- }
- outPos = 0;
- }
-
- if (p->progress && res == SZ_OK)
- {
- UInt64 inDelta = p->inProcessed - inPrev;
- UInt64 outDelta = p->outProcessed - outPrev;
- if (inDelta >= (1 << 22) || outDelta >= (1 << 22))
- {
- res = ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed);
- if (res != SZ_OK)
- {
- stat->CombinedRes_Type = SZ_ERROR_PROGRESS;
- stat->ProgressRes = res;
- return res;
- }
- inPrev = p->inProcessed;
- outPrev = p->outProcessed;
- }
- }
-
- if (finished)
- return res;
- }
-}
-
-static SRes XzStatInfo_SetStat(const CXzUnpacker *dec,
- int finishMode,
- UInt64 readProcessed, UInt64 inProcessed,
- SRes res, ECoderStatus status,
- BoolInt decodingTruncated,
- CXzStatInfo *stat)
-{
- UInt64 extraSize;
-
- stat->DecodingTruncated = (Byte)(decodingTruncated ? 1 : 0);
- stat->InSize = inProcessed;
- stat->NumStreams = dec->numStartedStreams;
- stat->NumBlocks = dec->numTotalBlocks;
-
- stat->UnpackSize_Defined = True;
- stat->NumStreams_Defined = True;
- stat->NumBlocks_Defined = True;
-
- extraSize = XzUnpacker_GetExtraSize(dec);
-
- if (res == SZ_OK)
- {
- if (status == CODER_STATUS_NEEDS_MORE_INPUT)
- {
- // CODER_STATUS_NEEDS_MORE_INPUT is expected status for correct xz streams
- extraSize = 0;
- if (!XzUnpacker_IsStreamWasFinished(dec))
- res = SZ_ERROR_INPUT_EOF;
- }
- else if (!decodingTruncated || finishMode) // (status == CODER_STATUS_NOT_FINISHED)
- res = SZ_ERROR_DATA;
- }
- else if (res == SZ_ERROR_NO_ARCHIVE)
- {
- /*
- SZ_ERROR_NO_ARCHIVE is possible for 2 states:
- XZ_STATE_STREAM_HEADER - if bad signature or bad CRC
- XZ_STATE_STREAM_PADDING - if non-zero padding data
- extraSize / inProcessed don't include "bad" byte
- */
- if (inProcessed != extraSize) // if good streams before error
- if (extraSize != 0 || readProcessed != inProcessed)
- {
- stat->DataAfterEnd = True;
- // there is some good xz stream before. So we set SZ_OK
- res = SZ_OK;
- }
- }
-
- stat->DecodeRes = res;
-
- stat->InSize -= extraSize;
- return res;
-}
-
-
-SRes XzDecMt_Decode(CXzDecMtHandle pp,
- const CXzDecMtProps *props,
- const UInt64 *outDataSize, int finishMode,
- ISeqOutStream *outStream,
- // Byte *outBuf, size_t *outBufSize,
- ISeqInStream *inStream,
- // const Byte *inData, size_t inDataSize,
- CXzStatInfo *stat,
- int *isMT,
- ICompressProgress *progress)
-{
- CXzDecMt *p = (CXzDecMt *)pp;
- #ifndef _7ZIP_ST
- BoolInt tMode;
- #endif
-
- XzStatInfo_Clear(stat);
-
- p->props = *props;
-
- p->inStream = inStream;
- p->outStream = outStream;
- p->progress = progress;
- // p->stat = stat;
-
- p->outSize = 0;
- p->outSize_Defined = False;
- if (outDataSize)
- {
- p->outSize_Defined = True;
- p->outSize = *outDataSize;
- }
-
- p->finishMode = finishMode;
-
- // p->outSize = 457; p->outSize_Defined = True; p->finishMode = False; // for test
-
- p->writeRes = SZ_OK;
- p->outProcessed = 0;
- p->inProcessed = 0;
- p->readProcessed = 0;
- p->readWasFinished = False;
-
- p->codeRes = 0;
- p->status = CODER_STATUS_NOT_SPECIFIED;
-
- XzUnpacker_Init(&p->dec);
-
- *isMT = False;
-
- /*
- p->outBuf = NULL;
- p->outBufSize = 0;
- if (!outStream)
- {
- p->outBuf = outBuf;
- p->outBufSize = *outBufSize;
- *outBufSize = 0;
- }
- */
-
-
- #ifndef _7ZIP_ST
-
- p->isBlockHeaderState_Parse = False;
- p->isBlockHeaderState_Write = False;
- // p->numBadBlocks = 0;
- p->mainErrorCode = SZ_OK;
- p->mainDecoderWasCalled = False;
-
- tMode = False;
-
- if (p->props.numThreads > 1)
- {
- IMtDecCallback vt;
-
- // we just free ST buffers here
- // but we still keep state variables, that was set in XzUnpacker_Init()
- XzDecMt_FreeSt(p);
-
- p->outProcessed_Parse = 0;
- p->parsing_Truncated = False;
-
- p->numStreams = 0;
- p->numTotalBlocks = 0;
- p->numBlocks = 0;
- p->finishedDecoderIndex = -1;
-
- if (!p->mtc_WasConstructed)
- {
- p->mtc_WasConstructed = True;
- MtDec_Construct(&p->mtc);
- }
-
- p->mtc.mtCallback = &vt;
- p->mtc.mtCallbackObject = p;
-
- p->mtc.progress = progress;
- p->mtc.inStream = inStream;
- p->mtc.alloc = &p->alignOffsetAlloc.vt;
- // p->mtc.inData = inData;
- // p->mtc.inDataSize = inDataSize;
- p->mtc.inBufSize = p->props.inBufSize_MT;
- // p->mtc.inBlockMax = p->props.inBlockMax;
- p->mtc.numThreadsMax = p->props.numThreads;
-
- *isMT = True;
-
- vt.Parse = XzDecMt_Callback_Parse;
- vt.PreCode = XzDecMt_Callback_PreCode;
- vt.Code = XzDecMt_Callback_Code;
- vt.Write = XzDecMt_Callback_Write;
-
- {
- BoolInt needContinue;
-
- SRes res = MtDec_Code(&p->mtc);
-
- stat->InSize = p->mtc.inProcessed;
-
- p->inProcessed = p->mtc.inProcessed;
- p->readRes = p->mtc.readRes;
- p->readWasFinished = p->mtc.readWasFinished;
- p->readProcessed = p->mtc.readProcessed;
-
- tMode = True;
- needContinue = False;
-
- if (res == SZ_OK)
- {
- if (p->mtc.mtProgress.res != SZ_OK)
- {
- res = p->mtc.mtProgress.res;
- stat->ProgressRes = res;
- stat->CombinedRes_Type = SZ_ERROR_PROGRESS;
- }
- else
- needContinue = p->mtc.needContinue;
- }
-
- if (!needContinue)
- {
- SRes codeRes;
- BoolInt truncated = False;
- ECoderStatus status;
- CXzUnpacker *dec;
-
- stat->OutSize = p->outProcessed;
-
- if (p->finishedDecoderIndex >= 0)
- {
- CXzDecMtThread *coder = &p->coders[(unsigned)p->finishedDecoderIndex];
- codeRes = coder->codeRes;
- dec = &coder->dec;
- status = coder->status;
- }
- else if (p->mainDecoderWasCalled)
- {
- codeRes = p->codeRes;
- dec = &p->dec;
- status = p->status;
- truncated = p->parsing_Truncated;
- }
- else
- return E_FAIL;
-
- XzStatInfo_SetStat(dec, p->finishMode,
- p->mtc.readProcessed, p->mtc.inProcessed,
- codeRes, status,
- truncated,
- stat);
-
- if (res == SZ_OK)
- {
- if (p->writeRes != SZ_OK)
- {
- res = p->writeRes;
- stat->CombinedRes_Type = SZ_ERROR_WRITE;
- }
- else if (p->mtc.readRes != SZ_OK && p->mtc.inProcessed == p->mtc.readProcessed)
- {
- res = p->mtc.readRes;
- stat->ReadRes = res;
- stat->CombinedRes_Type = SZ_ERROR_READ;
- }
- else if (p->mainErrorCode != SZ_OK)
- {
- res = p->mainErrorCode;
- }
- }
-
- stat->CombinedRes = res;
- if (stat->CombinedRes_Type == SZ_OK)
- stat->CombinedRes_Type = res;
- return res;
- }
-
- PRF_STR("----- decoding ST -----");
- }
- }
-
- #endif
-
-
- *isMT = False;
-
- {
- SRes res = XzDecMt_Decode_ST(p
- #ifndef _7ZIP_ST
- , tMode
- #endif
- , stat
- );
-
- XzStatInfo_SetStat(&p->dec,
- p->finishMode,
- p->readProcessed, p->inProcessed,
- p->codeRes, p->status,
- False, // truncated
- stat);
-
- if (res == SZ_OK)
- {
- /*
- if (p->writeRes != SZ_OK)
- {
- res = p->writeRes;
- stat->CombinedRes_Type = SZ_ERROR_WRITE;
- }
- else
- */
- if (p->readRes != SZ_OK && p->inProcessed == p->readProcessed)
- {
- res = p->readRes;
- stat->ReadRes = res;
- stat->CombinedRes_Type = SZ_ERROR_READ;
- }
- #ifndef _7ZIP_ST
- else if (p->mainErrorCode != SZ_OK)
- res = p->mainErrorCode;
- #endif
- }
-
- stat->CombinedRes = res;
- if (stat->CombinedRes_Type == SZ_OK)
- stat->CombinedRes_Type = res;
- return res;
- }
-}
+/* XzDec.c -- Xz Decode
+2023-04-13 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+// #include <stdio.h>
+
+// #define XZ_DUMP
+
+/* #define XZ_DUMP */
+
+#ifdef XZ_DUMP
+#include <stdio.h>
+#endif
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#endif
+
+#ifdef SHOW_DEBUG_INFO
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#define PRF_STR(s) PRF(printf("\n" s "\n"))
+#define PRF_STR_INT(s, d) PRF(printf("\n" s " %d\n", (unsigned)d))
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "7zCrc.h"
+#include "Alloc.h"
+#include "Bra.h"
+#include "CpuArch.h"
+#include "Delta.h"
+#include "Lzma2Dec.h"
+
+// #define USE_SUBBLOCK
+
+#ifdef USE_SUBBLOCK
+#include "Bcj3Dec.c"
+#include "SbDec.h"
+#endif
+
+#include "Xz.h"
+
+#define XZ_CHECK_SIZE_MAX 64
+
+#define CODER_BUF_SIZE ((size_t)1 << 17)
+
+unsigned Xz_ReadVarInt(const Byte *p, size_t maxSize, UInt64 *value)
+{
+ unsigned i, limit;
+ *value = 0;
+ limit = (maxSize > 9) ? 9 : (unsigned)maxSize;
+
+ for (i = 0; i < limit;)
+ {
+ Byte b = p[i];
+ *value |= (UInt64)(b & 0x7F) << (7 * i++);
+ if ((b & 0x80) == 0)
+ return (b == 0 && i != 1) ? 0 : i;
+ }
+ return 0;
+}
+
+
+/* ---------- XzBcFilterState ---------- */
+
+#define BRA_BUF_SIZE (1 << 14)
+
+typedef struct
+{
+ size_t bufPos;
+ size_t bufConv;
+ size_t bufTotal;
+ Byte *buf; // must be aligned for 4 bytes
+ Xz_Func_BcFilterStateBase_Filter filter_func;
+ // int encodeMode;
+ CXzBcFilterStateBase base;
+ // Byte buf[BRA_BUF_SIZE];
+} CXzBcFilterState;
+
+
+static void XzBcFilterState_Free(void *pp, ISzAllocPtr alloc)
+{
+ if (pp)
+ {
+ CXzBcFilterState *p = ((CXzBcFilterState *)pp);
+ ISzAlloc_Free(alloc, p->buf);
+ ISzAlloc_Free(alloc, pp);
+ }
+}
+
+
+static SRes XzBcFilterState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc)
+{
+ CXzBcFilterStateBase *p = &((CXzBcFilterState *)pp)->base;
+ UNUSED_VAR(alloc)
+ p->ip = 0;
+ if (p->methodId == XZ_ID_Delta)
+ {
+ if (propSize != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ p->delta = (unsigned)props[0] + 1;
+ }
+ else
+ {
+ if (propSize == 4)
+ {
+ UInt32 v = GetUi32(props);
+ switch (p->methodId)
+ {
+ case XZ_ID_PPC:
+ case XZ_ID_ARM:
+ case XZ_ID_SPARC:
+ case XZ_ID_ARM64:
+ if ((v & 3) != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ break;
+ case XZ_ID_ARMT:
+ if ((v & 1) != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ break;
+ case XZ_ID_IA64:
+ if ((v & 0xF) != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ break;
+ }
+ p->ip = v;
+ }
+ else if (propSize != 0)
+ return SZ_ERROR_UNSUPPORTED;
+ }
+ return SZ_OK;
+}
+
+
+static void XzBcFilterState_Init(void *pp)
+{
+ CXzBcFilterState *p = ((CXzBcFilterState *)pp);
+ p->bufPos = p->bufConv = p->bufTotal = 0;
+ p->base.X86_State = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL;
+ if (p->base.methodId == XZ_ID_Delta)
+ Delta_Init(p->base.delta_State);
+}
+
+
+static const z7_Func_BranchConv g_Funcs_BranchConv_RISC_Dec[] =
+{
+ Z7_BRANCH_CONV_DEC(PPC),
+ Z7_BRANCH_CONV_DEC(IA64),
+ Z7_BRANCH_CONV_DEC(ARM),
+ Z7_BRANCH_CONV_DEC(ARMT),
+ Z7_BRANCH_CONV_DEC(SPARC),
+ Z7_BRANCH_CONV_DEC(ARM64)
+};
+
+static SizeT XzBcFilterStateBase_Filter_Dec(CXzBcFilterStateBase *p, Byte *data, SizeT size)
+{
+ switch (p->methodId)
+ {
+ case XZ_ID_Delta:
+ Delta_Decode(p->delta_State, p->delta, data, size);
+ break;
+ case XZ_ID_X86:
+ size = (SizeT)(z7_BranchConvSt_X86_Dec(data, size, p->ip, &p->X86_State) - data);
+ break;
+ default:
+ if (p->methodId >= XZ_ID_PPC)
+ {
+ const UInt32 i = p->methodId - XZ_ID_PPC;
+ if (i < Z7_ARRAY_SIZE(g_Funcs_BranchConv_RISC_Dec))
+ size = (SizeT)(g_Funcs_BranchConv_RISC_Dec[i](data, size, p->ip) - data);
+ }
+ break;
+ }
+ p->ip += (UInt32)size;
+ return size;
+}
+
+
+static SizeT XzBcFilterState_Filter(void *pp, Byte *data, SizeT size)
+{
+ CXzBcFilterState *p = ((CXzBcFilterState *)pp);
+ return p->filter_func(&p->base, data, size);
+}
+
+
+static SRes XzBcFilterState_Code2(void *pp,
+ Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, int srcWasFinished,
+ ECoderFinishMode finishMode,
+ // int *wasFinished
+ ECoderStatus *status)
+{
+ CXzBcFilterState *p = ((CXzBcFilterState *)pp);
+ SizeT destRem = *destLen;
+ SizeT srcRem = *srcLen;
+ UNUSED_VAR(finishMode)
+
+ *destLen = 0;
+ *srcLen = 0;
+ // *wasFinished = False;
+ *status = CODER_STATUS_NOT_FINISHED;
+
+ while (destRem != 0)
+ {
+ {
+ size_t size = p->bufConv - p->bufPos;
+ if (size)
+ {
+ if (size > destRem)
+ size = destRem;
+ memcpy(dest, p->buf + p->bufPos, size);
+ p->bufPos += size;
+ *destLen += size;
+ dest += size;
+ destRem -= size;
+ continue;
+ }
+ }
+
+ p->bufTotal -= p->bufPos;
+ memmove(p->buf, p->buf + p->bufPos, p->bufTotal);
+ p->bufPos = 0;
+ p->bufConv = 0;
+ {
+ size_t size = BRA_BUF_SIZE - p->bufTotal;
+ if (size > srcRem)
+ size = srcRem;
+ memcpy(p->buf + p->bufTotal, src, size);
+ *srcLen += size;
+ src += size;
+ srcRem -= size;
+ p->bufTotal += size;
+ }
+ if (p->bufTotal == 0)
+ break;
+
+ p->bufConv = p->filter_func(&p->base, p->buf, p->bufTotal);
+
+ if (p->bufConv == 0)
+ {
+ if (!srcWasFinished)
+ break;
+ p->bufConv = p->bufTotal;
+ }
+ }
+
+ if (p->bufTotal == p->bufPos && srcRem == 0 && srcWasFinished)
+ {
+ *status = CODER_STATUS_FINISHED_WITH_MARK;
+ // *wasFinished = 1;
+ }
+
+ return SZ_OK;
+}
+
+
+#define XZ_IS_SUPPORTED_FILTER_ID(id) \
+ ((id) >= XZ_ID_Delta && (id) <= XZ_ID_ARM64)
+
+SRes Xz_StateCoder_Bc_SetFromMethod_Func(IStateCoder *p, UInt64 id,
+ Xz_Func_BcFilterStateBase_Filter func, ISzAllocPtr alloc)
+{
+ CXzBcFilterState *decoder;
+ if (!XZ_IS_SUPPORTED_FILTER_ID(id))
+ return SZ_ERROR_UNSUPPORTED;
+ decoder = (CXzBcFilterState *)p->p;
+ if (!decoder)
+ {
+ decoder = (CXzBcFilterState *)ISzAlloc_Alloc(alloc, sizeof(CXzBcFilterState));
+ if (!decoder)
+ return SZ_ERROR_MEM;
+ decoder->buf = ISzAlloc_Alloc(alloc, BRA_BUF_SIZE);
+ if (!decoder->buf)
+ {
+ ISzAlloc_Free(alloc, decoder);
+ return SZ_ERROR_MEM;
+ }
+ p->p = decoder;
+ p->Free = XzBcFilterState_Free;
+ p->SetProps = XzBcFilterState_SetProps;
+ p->Init = XzBcFilterState_Init;
+ p->Code2 = XzBcFilterState_Code2;
+ p->Filter = XzBcFilterState_Filter;
+ decoder->filter_func = func;
+ }
+ decoder->base.methodId = (UInt32)id;
+ // decoder->encodeMode = encodeMode;
+ return SZ_OK;
+}
+
+
+
+/* ---------- SbState ---------- */
+
+#ifdef USE_SUBBLOCK
+
+static void SbState_Free(void *pp, ISzAllocPtr alloc)
+{
+ CSbDec *p = (CSbDec *)pp;
+ SbDec_Free(p);
+ ISzAlloc_Free(alloc, pp);
+}
+
+static SRes SbState_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc)
+{
+ UNUSED_VAR(pp)
+ UNUSED_VAR(props)
+ UNUSED_VAR(alloc)
+ return (propSize == 0) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
+}
+
+static void SbState_Init(void *pp)
+{
+ SbDec_Init((CSbDec *)pp);
+}
+
+static SRes SbState_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ int srcWasFinished, ECoderFinishMode finishMode,
+ // int *wasFinished
+ ECoderStatus *status)
+{
+ CSbDec *p = (CSbDec *)pp;
+ SRes res;
+ UNUSED_VAR(srcWasFinished)
+ p->dest = dest;
+ p->destLen = *destLen;
+ p->src = src;
+ p->srcLen = *srcLen;
+ p->finish = finishMode; /* change it */
+ res = SbDec_Decode((CSbDec *)pp);
+ *destLen -= p->destLen;
+ *srcLen -= p->srcLen;
+ // *wasFinished = (*destLen == 0 && *srcLen == 0); /* change it */
+ *status = (*destLen == 0 && *srcLen == 0) ?
+ CODER_STATUS_FINISHED_WITH_MARK :
+ CODER_STATUS_NOT_FINISHED;
+ return res;
+}
+
+static SRes SbState_SetFromMethod(IStateCoder *p, ISzAllocPtr alloc)
+{
+ CSbDec *decoder = (CSbDec *)p->p;
+ if (!decoder)
+ {
+ decoder = (CSbDec *)ISzAlloc_Alloc(alloc, sizeof(CSbDec));
+ if (!decoder)
+ return SZ_ERROR_MEM;
+ p->p = decoder;
+ p->Free = SbState_Free;
+ p->SetProps = SbState_SetProps;
+ p->Init = SbState_Init;
+ p->Code2 = SbState_Code2;
+ p->Filter = NULL;
+ }
+ SbDec_Construct(decoder);
+ SbDec_SetAlloc(decoder, alloc);
+ return SZ_OK;
+}
+
+#endif
+
+
+
+/* ---------- Lzma2 ---------- */
+
+typedef struct
+{
+ CLzma2Dec decoder;
+ BoolInt outBufMode;
+} CLzma2Dec_Spec;
+
+
+static void Lzma2State_Free(void *pp, ISzAllocPtr alloc)
+{
+ CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp;
+ if (p->outBufMode)
+ Lzma2Dec_FreeProbs(&p->decoder, alloc);
+ else
+ Lzma2Dec_Free(&p->decoder, alloc);
+ ISzAlloc_Free(alloc, pp);
+}
+
+static SRes Lzma2State_SetProps(void *pp, const Byte *props, size_t propSize, ISzAllocPtr alloc)
+{
+ if (propSize != 1)
+ return SZ_ERROR_UNSUPPORTED;
+ {
+ CLzma2Dec_Spec *p = (CLzma2Dec_Spec *)pp;
+ if (p->outBufMode)
+ return Lzma2Dec_AllocateProbs(&p->decoder, props[0], alloc);
+ else
+ return Lzma2Dec_Allocate(&p->decoder, props[0], alloc);
+ }
+}
+
+static void Lzma2State_Init(void *pp)
+{
+ Lzma2Dec_Init(&((CLzma2Dec_Spec *)pp)->decoder);
+}
+
+
+/*
+ if (outBufMode), then (dest) is not used. Use NULL.
+ Data is unpacked to (spec->decoder.decoder.dic) output buffer.
+*/
+
+static SRes Lzma2State_Code2(void *pp, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ int srcWasFinished, ECoderFinishMode finishMode,
+ // int *wasFinished,
+ ECoderStatus *status)
+{
+ CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)pp;
+ ELzmaStatus status2;
+ /* ELzmaFinishMode fm = (finishMode == LZMA_FINISH_ANY) ? LZMA_FINISH_ANY : LZMA_FINISH_END; */
+ SRes res;
+ UNUSED_VAR(srcWasFinished)
+ if (spec->outBufMode)
+ {
+ SizeT dicPos = spec->decoder.decoder.dicPos;
+ SizeT dicLimit = dicPos + *destLen;
+ res = Lzma2Dec_DecodeToDic(&spec->decoder, dicLimit, src, srcLen, (ELzmaFinishMode)finishMode, &status2);
+ *destLen = spec->decoder.decoder.dicPos - dicPos;
+ }
+ else
+ res = Lzma2Dec_DecodeToBuf(&spec->decoder, dest, destLen, src, srcLen, (ELzmaFinishMode)finishMode, &status2);
+ // *wasFinished = (status2 == LZMA_STATUS_FINISHED_WITH_MARK);
+ // ECoderStatus values are identical to ELzmaStatus values of LZMA2 decoder
+ *status = (ECoderStatus)status2;
+ return res;
+}
+
+
+static SRes Lzma2State_SetFromMethod(IStateCoder *p, Byte *outBuf, size_t outBufSize, ISzAllocPtr alloc)
+{
+ CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p;
+ if (!spec)
+ {
+ spec = (CLzma2Dec_Spec *)ISzAlloc_Alloc(alloc, sizeof(CLzma2Dec_Spec));
+ if (!spec)
+ return SZ_ERROR_MEM;
+ p->p = spec;
+ p->Free = Lzma2State_Free;
+ p->SetProps = Lzma2State_SetProps;
+ p->Init = Lzma2State_Init;
+ p->Code2 = Lzma2State_Code2;
+ p->Filter = NULL;
+ Lzma2Dec_CONSTRUCT(&spec->decoder)
+ }
+ spec->outBufMode = False;
+ if (outBuf)
+ {
+ spec->outBufMode = True;
+ spec->decoder.decoder.dic = outBuf;
+ spec->decoder.decoder.dicBufSize = outBufSize;
+ }
+ return SZ_OK;
+}
+
+
+static SRes Lzma2State_ResetOutBuf(IStateCoder *p, Byte *outBuf, size_t outBufSize)
+{
+ CLzma2Dec_Spec *spec = (CLzma2Dec_Spec *)p->p;
+ if ((spec->outBufMode && !outBuf) || (!spec->outBufMode && outBuf))
+ return SZ_ERROR_FAIL;
+ if (outBuf)
+ {
+ spec->decoder.decoder.dic = outBuf;
+ spec->decoder.decoder.dicBufSize = outBufSize;
+ }
+ return SZ_OK;
+}
+
+
+
+static void MixCoder_Construct(CMixCoder *p, ISzAllocPtr alloc)
+{
+ unsigned i;
+ p->alloc = alloc;
+ p->buf = NULL;
+ p->numCoders = 0;
+
+ p->outBufSize = 0;
+ p->outBuf = NULL;
+ // p->SingleBufMode = False;
+
+ for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++)
+ p->coders[i].p = NULL;
+}
+
+
+static void MixCoder_Free(CMixCoder *p)
+{
+ unsigned i;
+ p->numCoders = 0;
+ for (i = 0; i < MIXCODER_NUM_FILTERS_MAX; i++)
+ {
+ IStateCoder *sc = &p->coders[i];
+ if (sc->p)
+ {
+ sc->Free(sc->p, p->alloc);
+ sc->p = NULL;
+ }
+ }
+ if (p->buf)
+ {
+ ISzAlloc_Free(p->alloc, p->buf);
+ p->buf = NULL; /* 9.31: the BUG was fixed */
+ }
+}
+
+static void MixCoder_Init(CMixCoder *p)
+{
+ unsigned i;
+ for (i = 0; i < MIXCODER_NUM_FILTERS_MAX - 1; i++)
+ {
+ p->size[i] = 0;
+ p->pos[i] = 0;
+ p->finished[i] = 0;
+ }
+ for (i = 0; i < p->numCoders; i++)
+ {
+ IStateCoder *coder = &p->coders[i];
+ coder->Init(coder->p);
+ p->results[i] = SZ_OK;
+ }
+ p->outWritten = 0;
+ p->wasFinished = False;
+ p->res = SZ_OK;
+ p->status = CODER_STATUS_NOT_SPECIFIED;
+}
+
+
+static SRes MixCoder_SetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize)
+{
+ IStateCoder *sc = &p->coders[coderIndex];
+ p->ids[coderIndex] = methodId;
+ switch (methodId)
+ {
+ case XZ_ID_LZMA2: return Lzma2State_SetFromMethod(sc, outBuf, outBufSize, p->alloc);
+ #ifdef USE_SUBBLOCK
+ case XZ_ID_Subblock: return SbState_SetFromMethod(sc, p->alloc);
+ #endif
+ }
+ if (coderIndex == 0)
+ return SZ_ERROR_UNSUPPORTED;
+ return Xz_StateCoder_Bc_SetFromMethod_Func(sc, methodId,
+ XzBcFilterStateBase_Filter_Dec, p->alloc);
+}
+
+
+static SRes MixCoder_ResetFromMethod(CMixCoder *p, unsigned coderIndex, UInt64 methodId, Byte *outBuf, size_t outBufSize)
+{
+ IStateCoder *sc = &p->coders[coderIndex];
+ switch (methodId)
+ {
+ case XZ_ID_LZMA2: return Lzma2State_ResetOutBuf(sc, outBuf, outBufSize);
+ }
+ return SZ_ERROR_UNSUPPORTED;
+}
+
+
+
+/*
+ if (destFinish) - then unpack data block is finished at (*destLen) position,
+ and we can return data that were not processed by filter
+
+output (status) can be :
+ CODER_STATUS_NOT_FINISHED
+ CODER_STATUS_FINISHED_WITH_MARK
+ CODER_STATUS_NEEDS_MORE_INPUT - not implemented still
+*/
+
+static SRes MixCoder_Code(CMixCoder *p,
+ Byte *dest, SizeT *destLen, int destFinish,
+ const Byte *src, SizeT *srcLen, int srcWasFinished,
+ ECoderFinishMode finishMode)
+{
+ SizeT destLenOrig = *destLen;
+ SizeT srcLenOrig = *srcLen;
+
+ *destLen = 0;
+ *srcLen = 0;
+
+ if (p->wasFinished)
+ return p->res;
+
+ p->status = CODER_STATUS_NOT_FINISHED;
+
+ // if (p->SingleBufMode)
+ if (p->outBuf)
+ {
+ SRes res;
+ SizeT destLen2, srcLen2;
+ int wasFinished;
+
+ PRF_STR("------- MixCoder Single ----------")
+
+ srcLen2 = srcLenOrig;
+ destLen2 = destLenOrig;
+
+ {
+ IStateCoder *coder = &p->coders[0];
+ res = coder->Code2(coder->p, NULL, &destLen2, src, &srcLen2, srcWasFinished, finishMode,
+ // &wasFinished,
+ &p->status);
+ wasFinished = (p->status == CODER_STATUS_FINISHED_WITH_MARK);
+ }
+
+ p->res = res;
+
+ /*
+ if (wasFinished)
+ p->status = CODER_STATUS_FINISHED_WITH_MARK;
+ else
+ {
+ if (res == SZ_OK)
+ if (destLen2 != destLenOrig)
+ p->status = CODER_STATUS_NEEDS_MORE_INPUT;
+ }
+ */
+
+
+ *srcLen = srcLen2;
+ src += srcLen2;
+ p->outWritten += destLen2;
+
+ if (res != SZ_OK || srcWasFinished || wasFinished)
+ p->wasFinished = True;
+
+ if (p->numCoders == 1)
+ *destLen = destLen2;
+ else if (p->wasFinished)
+ {
+ unsigned i;
+ size_t processed = p->outWritten;
+
+ for (i = 1; i < p->numCoders; i++)
+ {
+ IStateCoder *coder = &p->coders[i];
+ processed = coder->Filter(coder->p, p->outBuf, processed);
+ if (wasFinished || (destFinish && p->outWritten == destLenOrig))
+ processed = p->outWritten;
+ PRF_STR_INT("filter", i)
+ }
+ *destLen = processed;
+ }
+ return res;
+ }
+
+ PRF_STR("standard mix")
+
+ if (p->numCoders != 1)
+ {
+ if (!p->buf)
+ {
+ p->buf = (Byte *)ISzAlloc_Alloc(p->alloc, CODER_BUF_SIZE * (MIXCODER_NUM_FILTERS_MAX - 1));
+ if (!p->buf)
+ return SZ_ERROR_MEM;
+ }
+
+ finishMode = CODER_FINISH_ANY;
+ }
+
+ for (;;)
+ {
+ BoolInt processed = False;
+ BoolInt allFinished = True;
+ SRes resMain = SZ_OK;
+ unsigned i;
+
+ p->status = CODER_STATUS_NOT_FINISHED;
+ /*
+ if (p->numCoders == 1 && *destLen == destLenOrig && finishMode == LZMA_FINISH_ANY)
+ break;
+ */
+
+ for (i = 0; i < p->numCoders; i++)
+ {
+ SRes res;
+ IStateCoder *coder = &p->coders[i];
+ Byte *dest2;
+ SizeT destLen2, srcLen2; // destLen2_Orig;
+ const Byte *src2;
+ int srcFinished2;
+ int encodingWasFinished;
+ ECoderStatus status2;
+
+ if (i == 0)
+ {
+ src2 = src;
+ srcLen2 = srcLenOrig - *srcLen;
+ srcFinished2 = srcWasFinished;
+ }
+ else
+ {
+ size_t k = i - 1;
+ src2 = p->buf + (CODER_BUF_SIZE * k) + p->pos[k];
+ srcLen2 = p->size[k] - p->pos[k];
+ srcFinished2 = p->finished[k];
+ }
+
+ if (i == p->numCoders - 1)
+ {
+ dest2 = dest;
+ destLen2 = destLenOrig - *destLen;
+ }
+ else
+ {
+ if (p->pos[i] != p->size[i])
+ continue;
+ dest2 = p->buf + (CODER_BUF_SIZE * i);
+ destLen2 = CODER_BUF_SIZE;
+ }
+
+ // destLen2_Orig = destLen2;
+
+ if (p->results[i] != SZ_OK)
+ {
+ if (resMain == SZ_OK)
+ resMain = p->results[i];
+ continue;
+ }
+
+ res = coder->Code2(coder->p,
+ dest2, &destLen2,
+ src2, &srcLen2, srcFinished2,
+ finishMode,
+ // &encodingWasFinished,
+ &status2);
+
+ if (res != SZ_OK)
+ {
+ p->results[i] = res;
+ if (resMain == SZ_OK)
+ resMain = res;
+ }
+
+ encodingWasFinished = (status2 == CODER_STATUS_FINISHED_WITH_MARK);
+
+ if (!encodingWasFinished)
+ {
+ allFinished = False;
+ if (p->numCoders == 1 && res == SZ_OK)
+ p->status = status2;
+ }
+
+ if (i == 0)
+ {
+ *srcLen += srcLen2;
+ src += srcLen2;
+ }
+ else
+ p->pos[(size_t)i - 1] += srcLen2;
+
+ if (i == p->numCoders - 1)
+ {
+ *destLen += destLen2;
+ dest += destLen2;
+ }
+ else
+ {
+ p->size[i] = destLen2;
+ p->pos[i] = 0;
+ p->finished[i] = encodingWasFinished;
+ }
+
+ if (destLen2 != 0 || srcLen2 != 0)
+ processed = True;
+ }
+
+ if (!processed)
+ {
+ if (allFinished)
+ p->status = CODER_STATUS_FINISHED_WITH_MARK;
+ return resMain;
+ }
+ }
+}
+
+
+SRes Xz_ParseHeader(CXzStreamFlags *p, const Byte *buf)
+{
+ *p = (CXzStreamFlags)GetBe16(buf + XZ_SIG_SIZE);
+ if (CrcCalc(buf + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE) !=
+ GetUi32(buf + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE))
+ return SZ_ERROR_NO_ARCHIVE;
+ return XzFlags_IsSupported(*p) ? SZ_OK : SZ_ERROR_UNSUPPORTED;
+}
+
+static BoolInt Xz_CheckFooter(CXzStreamFlags flags, UInt64 indexSize, const Byte *buf)
+{
+ return indexSize == (((UInt64)GetUi32(buf + 4) + 1) << 2)
+ && GetUi32(buf) == CrcCalc(buf + 4, 6)
+ && flags == GetBe16(buf + 8)
+ && buf[10] == XZ_FOOTER_SIG_0
+ && buf[11] == XZ_FOOTER_SIG_1;
+}
+
+#define READ_VARINT_AND_CHECK(buf, pos, size, res) \
+ { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \
+ if (s == 0) return SZ_ERROR_ARCHIVE; \
+ pos += s; }
+
+
+static BoolInt XzBlock_AreSupportedFilters(const CXzBlock *p)
+{
+ const unsigned numFilters = XzBlock_GetNumFilters(p) - 1;
+ unsigned i;
+ {
+ const CXzFilter *f = &p->filters[numFilters];
+ if (f->id != XZ_ID_LZMA2 || f->propsSize != 1 || f->props[0] > 40)
+ return False;
+ }
+
+ for (i = 0; i < numFilters; i++)
+ {
+ const CXzFilter *f = &p->filters[i];
+ if (f->id == XZ_ID_Delta)
+ {
+ if (f->propsSize != 1)
+ return False;
+ }
+ else if (!XZ_IS_SUPPORTED_FILTER_ID(f->id)
+ || (f->propsSize != 0 && f->propsSize != 4))
+ return False;
+ }
+ return True;
+}
+
+
+SRes XzBlock_Parse(CXzBlock *p, const Byte *header)
+{
+ unsigned pos;
+ unsigned numFilters, i;
+ unsigned headerSize = (unsigned)header[0] << 2;
+
+ /* (headerSize != 0) : another code checks */
+
+ if (CrcCalc(header, headerSize) != GetUi32(header + headerSize))
+ return SZ_ERROR_ARCHIVE;
+
+ pos = 1;
+ p->flags = header[pos++];
+
+ p->packSize = (UInt64)(Int64)-1;
+ if (XzBlock_HasPackSize(p))
+ {
+ READ_VARINT_AND_CHECK(header, pos, headerSize, &p->packSize)
+ if (p->packSize == 0 || p->packSize + headerSize >= (UInt64)1 << 63)
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ p->unpackSize = (UInt64)(Int64)-1;
+ if (XzBlock_HasUnpackSize(p))
+ {
+ READ_VARINT_AND_CHECK(header, pos, headerSize, &p->unpackSize)
+ }
+
+ numFilters = XzBlock_GetNumFilters(p);
+ for (i = 0; i < numFilters; i++)
+ {
+ CXzFilter *filter = p->filters + i;
+ UInt64 size;
+ READ_VARINT_AND_CHECK(header, pos, headerSize, &filter->id)
+ READ_VARINT_AND_CHECK(header, pos, headerSize, &size)
+ if (size > headerSize - pos || size > XZ_FILTER_PROPS_SIZE_MAX)
+ return SZ_ERROR_ARCHIVE;
+ filter->propsSize = (UInt32)size;
+ memcpy(filter->props, header + pos, (size_t)size);
+ pos += (unsigned)size;
+
+ #ifdef XZ_DUMP
+ printf("\nf[%u] = %2X: ", i, (unsigned)filter->id);
+ {
+ unsigned i;
+ for (i = 0; i < size; i++)
+ printf(" %2X", filter->props[i]);
+ }
+ #endif
+ }
+
+ if (XzBlock_HasUnsupportedFlags(p))
+ return SZ_ERROR_UNSUPPORTED;
+
+ while (pos < headerSize)
+ if (header[pos++] != 0)
+ return SZ_ERROR_ARCHIVE;
+ return SZ_OK;
+}
+
+
+
+
+static SRes XzDecMix_Init(CMixCoder *p, const CXzBlock *block, Byte *outBuf, size_t outBufSize)
+{
+ unsigned i;
+ BoolInt needReInit = True;
+ unsigned numFilters = XzBlock_GetNumFilters(block);
+
+ if (numFilters == p->numCoders && ((p->outBuf && outBuf) || (!p->outBuf && !outBuf)))
+ {
+ needReInit = False;
+ for (i = 0; i < numFilters; i++)
+ if (p->ids[i] != block->filters[numFilters - 1 - i].id)
+ {
+ needReInit = True;
+ break;
+ }
+ }
+
+ // p->SingleBufMode = (outBuf != NULL);
+ p->outBuf = outBuf;
+ p->outBufSize = outBufSize;
+
+ // p->SingleBufMode = False;
+ // outBuf = NULL;
+
+ if (needReInit)
+ {
+ MixCoder_Free(p);
+ for (i = 0; i < numFilters; i++)
+ {
+ RINOK(MixCoder_SetFromMethod(p, i, block->filters[numFilters - 1 - i].id, outBuf, outBufSize))
+ }
+ p->numCoders = numFilters;
+ }
+ else
+ {
+ RINOK(MixCoder_ResetFromMethod(p, 0, block->filters[numFilters - 1].id, outBuf, outBufSize))
+ }
+
+ for (i = 0; i < numFilters; i++)
+ {
+ const CXzFilter *f = &block->filters[numFilters - 1 - i];
+ IStateCoder *sc = &p->coders[i];
+ RINOK(sc->SetProps(sc->p, f->props, f->propsSize, p->alloc))
+ }
+
+ MixCoder_Init(p);
+ return SZ_OK;
+}
+
+
+
+void XzUnpacker_Init(CXzUnpacker *p)
+{
+ p->state = XZ_STATE_STREAM_HEADER;
+ p->pos = 0;
+ p->numStartedStreams = 0;
+ p->numFinishedStreams = 0;
+ p->numTotalBlocks = 0;
+ p->padSize = 0;
+ p->decodeOnlyOneBlock = 0;
+
+ p->parseMode = False;
+ p->decodeToStreamSignature = False;
+
+ // p->outBuf = NULL;
+ // p->outBufSize = 0;
+ p->outDataWritten = 0;
+}
+
+
+void XzUnpacker_SetOutBuf(CXzUnpacker *p, Byte *outBuf, size_t outBufSize)
+{
+ p->outBuf = outBuf;
+ p->outBufSize = outBufSize;
+}
+
+
+void XzUnpacker_Construct(CXzUnpacker *p, ISzAllocPtr alloc)
+{
+ MixCoder_Construct(&p->decoder, alloc);
+ p->outBuf = NULL;
+ p->outBufSize = 0;
+ XzUnpacker_Init(p);
+}
+
+
+void XzUnpacker_Free(CXzUnpacker *p)
+{
+ MixCoder_Free(&p->decoder);
+}
+
+
+void XzUnpacker_PrepareToRandomBlockDecoding(CXzUnpacker *p)
+{
+ p->indexSize = 0;
+ p->numBlocks = 0;
+ Sha256_Init(&p->sha);
+ p->state = XZ_STATE_BLOCK_HEADER;
+ p->pos = 0;
+ p->decodeOnlyOneBlock = 1;
+}
+
+
+static void XzUnpacker_UpdateIndex(CXzUnpacker *p, UInt64 packSize, UInt64 unpackSize)
+{
+ Byte temp[32];
+ unsigned num = Xz_WriteVarInt(temp, packSize);
+ num += Xz_WriteVarInt(temp + num, unpackSize);
+ Sha256_Update(&p->sha, temp, num);
+ p->indexSize += num;
+ p->numBlocks++;
+}
+
+
+
+SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, int srcFinished,
+ ECoderFinishMode finishMode, ECoderStatus *status)
+{
+ SizeT destLenOrig = *destLen;
+ SizeT srcLenOrig = *srcLen;
+ *destLen = 0;
+ *srcLen = 0;
+ *status = CODER_STATUS_NOT_SPECIFIED;
+
+ for (;;)
+ {
+ SizeT srcRem;
+
+ if (p->state == XZ_STATE_BLOCK)
+ {
+ SizeT destLen2 = destLenOrig - *destLen;
+ SizeT srcLen2 = srcLenOrig - *srcLen;
+ SRes res;
+
+ ECoderFinishMode finishMode2 = finishMode;
+ BoolInt srcFinished2 = srcFinished;
+ BoolInt destFinish = False;
+
+ if (p->block.packSize != (UInt64)(Int64)-1)
+ {
+ UInt64 rem = p->block.packSize - p->packSize;
+ if (srcLen2 >= rem)
+ {
+ srcFinished2 = True;
+ srcLen2 = (SizeT)rem;
+ }
+ if (rem == 0 && p->block.unpackSize == p->unpackSize)
+ return SZ_ERROR_DATA;
+ }
+
+ if (p->block.unpackSize != (UInt64)(Int64)-1)
+ {
+ UInt64 rem = p->block.unpackSize - p->unpackSize;
+ if (destLen2 >= rem)
+ {
+ destFinish = True;
+ finishMode2 = CODER_FINISH_END;
+ destLen2 = (SizeT)rem;
+ }
+ }
+
+ /*
+ if (srcLen2 == 0 && destLen2 == 0)
+ {
+ *status = CODER_STATUS_NOT_FINISHED;
+ return SZ_OK;
+ }
+ */
+
+ {
+ res = MixCoder_Code(&p->decoder,
+ (p->outBuf ? NULL : dest), &destLen2, destFinish,
+ src, &srcLen2, srcFinished2,
+ finishMode2);
+
+ *status = p->decoder.status;
+ XzCheck_Update(&p->check, (p->outBuf ? p->outBuf + p->outDataWritten : dest), destLen2);
+ if (!p->outBuf)
+ dest += destLen2;
+ p->outDataWritten += destLen2;
+ }
+
+ (*srcLen) += srcLen2;
+ src += srcLen2;
+ p->packSize += srcLen2;
+ (*destLen) += destLen2;
+ p->unpackSize += destLen2;
+
+ RINOK(res)
+
+ if (*status != CODER_STATUS_FINISHED_WITH_MARK)
+ {
+ if (p->block.packSize == p->packSize
+ && *status == CODER_STATUS_NEEDS_MORE_INPUT)
+ {
+ PRF_STR("CODER_STATUS_NEEDS_MORE_INPUT")
+ *status = CODER_STATUS_NOT_SPECIFIED;
+ return SZ_ERROR_DATA;
+ }
+
+ return SZ_OK;
+ }
+ {
+ XzUnpacker_UpdateIndex(p, XzUnpacker_GetPackSizeForIndex(p), p->unpackSize);
+ p->state = XZ_STATE_BLOCK_FOOTER;
+ p->pos = 0;
+ p->alignPos = 0;
+ *status = CODER_STATUS_NOT_SPECIFIED;
+
+ if ((p->block.packSize != (UInt64)(Int64)-1 && p->block.packSize != p->packSize)
+ || (p->block.unpackSize != (UInt64)(Int64)-1 && p->block.unpackSize != p->unpackSize))
+ {
+ PRF_STR("ERROR: block.size mismatch")
+ return SZ_ERROR_DATA;
+ }
+ }
+ // continue;
+ }
+
+ srcRem = srcLenOrig - *srcLen;
+
+ // XZ_STATE_BLOCK_FOOTER can transit to XZ_STATE_BLOCK_HEADER without input bytes
+ if (srcRem == 0 && p->state != XZ_STATE_BLOCK_FOOTER)
+ {
+ *status = CODER_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+
+ switch (p->state)
+ {
+ case XZ_STATE_STREAM_HEADER:
+ {
+ if (p->pos < XZ_STREAM_HEADER_SIZE)
+ {
+ if (p->pos < XZ_SIG_SIZE && *src != XZ_SIG[p->pos])
+ return SZ_ERROR_NO_ARCHIVE;
+ if (p->decodeToStreamSignature)
+ return SZ_OK;
+ p->buf[p->pos++] = *src++;
+ (*srcLen)++;
+ }
+ else
+ {
+ RINOK(Xz_ParseHeader(&p->streamFlags, p->buf))
+ p->numStartedStreams++;
+ p->indexSize = 0;
+ p->numBlocks = 0;
+ Sha256_Init(&p->sha);
+ p->state = XZ_STATE_BLOCK_HEADER;
+ p->pos = 0;
+ }
+ break;
+ }
+
+ case XZ_STATE_BLOCK_HEADER:
+ {
+ if (p->pos == 0)
+ {
+ p->buf[p->pos++] = *src++;
+ (*srcLen)++;
+ if (p->buf[0] == 0)
+ {
+ if (p->decodeOnlyOneBlock)
+ return SZ_ERROR_DATA;
+ p->indexPreSize = 1 + Xz_WriteVarInt(p->buf + 1, p->numBlocks);
+ p->indexPos = p->indexPreSize;
+ p->indexSize += p->indexPreSize;
+ Sha256_Final(&p->sha, p->shaDigest);
+ Sha256_Init(&p->sha);
+ p->crc = CrcUpdate(CRC_INIT_VAL, p->buf, p->indexPreSize);
+ p->state = XZ_STATE_STREAM_INDEX;
+ break;
+ }
+ p->blockHeaderSize = ((UInt32)p->buf[0] << 2) + 4;
+ break;
+ }
+
+ if (p->pos != p->blockHeaderSize)
+ {
+ UInt32 cur = p->blockHeaderSize - p->pos;
+ if (cur > srcRem)
+ cur = (UInt32)srcRem;
+ memcpy(p->buf + p->pos, src, cur);
+ p->pos += cur;
+ (*srcLen) += cur;
+ src += cur;
+ }
+ else
+ {
+ RINOK(XzBlock_Parse(&p->block, p->buf))
+ if (!XzBlock_AreSupportedFilters(&p->block))
+ return SZ_ERROR_UNSUPPORTED;
+ p->numTotalBlocks++;
+ p->state = XZ_STATE_BLOCK;
+ p->packSize = 0;
+ p->unpackSize = 0;
+ XzCheck_Init(&p->check, XzFlags_GetCheckType(p->streamFlags));
+ if (p->parseMode)
+ {
+ p->headerParsedOk = True;
+ return SZ_OK;
+ }
+ RINOK(XzDecMix_Init(&p->decoder, &p->block, p->outBuf, p->outBufSize))
+ }
+ break;
+ }
+
+ case XZ_STATE_BLOCK_FOOTER:
+ {
+ if ((((unsigned)p->packSize + p->alignPos) & 3) != 0)
+ {
+ if (srcRem == 0)
+ {
+ *status = CODER_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ (*srcLen)++;
+ p->alignPos++;
+ if (*src++ != 0)
+ return SZ_ERROR_CRC;
+ }
+ else
+ {
+ UInt32 checkSize = XzFlags_GetCheckSize(p->streamFlags);
+ UInt32 cur = checkSize - p->pos;
+ if (cur != 0)
+ {
+ if (srcRem == 0)
+ {
+ *status = CODER_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (cur > srcRem)
+ cur = (UInt32)srcRem;
+ memcpy(p->buf + p->pos, src, cur);
+ p->pos += cur;
+ (*srcLen) += cur;
+ src += cur;
+ if (checkSize != p->pos)
+ break;
+ }
+ {
+ Byte digest[XZ_CHECK_SIZE_MAX];
+ p->state = XZ_STATE_BLOCK_HEADER;
+ p->pos = 0;
+ if (XzCheck_Final(&p->check, digest) && memcmp(digest, p->buf, checkSize) != 0)
+ return SZ_ERROR_CRC;
+ if (p->decodeOnlyOneBlock)
+ {
+ *status = CODER_STATUS_FINISHED_WITH_MARK;
+ return SZ_OK;
+ }
+ }
+ }
+ break;
+ }
+
+ case XZ_STATE_STREAM_INDEX:
+ {
+ if (p->pos < p->indexPreSize)
+ {
+ (*srcLen)++;
+ if (*src++ != p->buf[p->pos++])
+ return SZ_ERROR_CRC;
+ }
+ else
+ {
+ if (p->indexPos < p->indexSize)
+ {
+ UInt64 cur = p->indexSize - p->indexPos;
+ if (srcRem > cur)
+ srcRem = (SizeT)cur;
+ p->crc = CrcUpdate(p->crc, src, srcRem);
+ Sha256_Update(&p->sha, src, srcRem);
+ (*srcLen) += srcRem;
+ src += srcRem;
+ p->indexPos += srcRem;
+ }
+ else if ((p->indexPos & 3) != 0)
+ {
+ Byte b = *src++;
+ p->crc = CRC_UPDATE_BYTE(p->crc, b);
+ (*srcLen)++;
+ p->indexPos++;
+ p->indexSize++;
+ if (b != 0)
+ return SZ_ERROR_CRC;
+ }
+ else
+ {
+ Byte digest[SHA256_DIGEST_SIZE];
+ p->state = XZ_STATE_STREAM_INDEX_CRC;
+ p->indexSize += 4;
+ p->pos = 0;
+ Sha256_Final(&p->sha, digest);
+ if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0)
+ return SZ_ERROR_CRC;
+ }
+ }
+ break;
+ }
+
+ case XZ_STATE_STREAM_INDEX_CRC:
+ {
+ if (p->pos < 4)
+ {
+ (*srcLen)++;
+ p->buf[p->pos++] = *src++;
+ }
+ else
+ {
+ const Byte *ptr = p->buf;
+ p->state = XZ_STATE_STREAM_FOOTER;
+ p->pos = 0;
+ if (CRC_GET_DIGEST(p->crc) != GetUi32(ptr))
+ return SZ_ERROR_CRC;
+ }
+ break;
+ }
+
+ case XZ_STATE_STREAM_FOOTER:
+ {
+ UInt32 cur = XZ_STREAM_FOOTER_SIZE - p->pos;
+ if (cur > srcRem)
+ cur = (UInt32)srcRem;
+ memcpy(p->buf + p->pos, src, cur);
+ p->pos += cur;
+ (*srcLen) += cur;
+ src += cur;
+ if (p->pos == XZ_STREAM_FOOTER_SIZE)
+ {
+ p->state = XZ_STATE_STREAM_PADDING;
+ p->numFinishedStreams++;
+ p->padSize = 0;
+ if (!Xz_CheckFooter(p->streamFlags, p->indexSize, p->buf))
+ return SZ_ERROR_CRC;
+ }
+ break;
+ }
+
+ case XZ_STATE_STREAM_PADDING:
+ {
+ if (*src != 0)
+ {
+ if (((UInt32)p->padSize & 3) != 0)
+ return SZ_ERROR_NO_ARCHIVE;
+ p->pos = 0;
+ p->state = XZ_STATE_STREAM_HEADER;
+ }
+ else
+ {
+ (*srcLen)++;
+ src++;
+ p->padSize++;
+ }
+ break;
+ }
+
+ case XZ_STATE_BLOCK: break; /* to disable GCC warning */
+ }
+ }
+ /*
+ if (p->state == XZ_STATE_FINISHED)
+ *status = CODER_STATUS_FINISHED_WITH_MARK;
+ return SZ_OK;
+ */
+}
+
+
+SRes XzUnpacker_CodeFull(CXzUnpacker *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen,
+ ECoderFinishMode finishMode, ECoderStatus *status)
+{
+ XzUnpacker_Init(p);
+ XzUnpacker_SetOutBuf(p, dest, *destLen);
+
+ return XzUnpacker_Code(p,
+ NULL, destLen,
+ src, srcLen, True,
+ finishMode, status);
+}
+
+
+BoolInt XzUnpacker_IsBlockFinished(const CXzUnpacker *p)
+{
+ return (p->state == XZ_STATE_BLOCK_HEADER) && (p->pos == 0);
+}
+
+BoolInt XzUnpacker_IsStreamWasFinished(const CXzUnpacker *p)
+{
+ return (p->state == XZ_STATE_STREAM_PADDING) && (((UInt32)p->padSize & 3) == 0);
+}
+
+UInt64 XzUnpacker_GetExtraSize(const CXzUnpacker *p)
+{
+ UInt64 num = 0;
+ if (p->state == XZ_STATE_STREAM_PADDING)
+ num = p->padSize;
+ else if (p->state == XZ_STATE_STREAM_HEADER)
+ num = p->padSize + p->pos;
+ return num;
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#ifndef Z7_ST
+#include "MtDec.h"
+#endif
+
+
+void XzDecMtProps_Init(CXzDecMtProps *p)
+{
+ p->inBufSize_ST = 1 << 18;
+ p->outStep_ST = 1 << 20;
+ p->ignoreErrors = False;
+
+ #ifndef Z7_ST
+ p->numThreads = 1;
+ p->inBufSize_MT = 1 << 18;
+ p->memUseMax = sizeof(size_t) << 28;
+ #endif
+}
+
+
+
+#ifndef Z7_ST
+
+/* ---------- CXzDecMtThread ---------- */
+
+typedef struct
+{
+ Byte *outBuf;
+ size_t outBufSize;
+ size_t outPreSize;
+ size_t inPreSize;
+ size_t inPreHeaderSize;
+ size_t blockPackSize_for_Index; // including block header and checksum.
+ size_t blockPackTotal; // including stream header, block header and checksum.
+ size_t inCodeSize;
+ size_t outCodeSize;
+ ECoderStatus status;
+ SRes codeRes;
+ BoolInt skipMode;
+ // BoolInt finishedWithMark;
+ EMtDecParseState parseState;
+ BoolInt parsing_Truncated;
+ BoolInt atBlockHeader;
+ CXzStreamFlags streamFlags;
+ // UInt64 numFinishedStreams
+ UInt64 numStreams;
+ UInt64 numTotalBlocks;
+ UInt64 numBlocks;
+
+ BoolInt dec_created;
+ CXzUnpacker dec;
+
+ Byte mtPad[1 << 7];
+} CXzDecMtThread;
+
+#endif
+
+
+/* ---------- CXzDecMt ---------- */
+
+struct CXzDecMt
+{
+ CAlignOffsetAlloc alignOffsetAlloc;
+ ISzAllocPtr allocMid;
+
+ CXzDecMtProps props;
+ size_t unpackBlockMaxSize;
+
+ ISeqInStreamPtr inStream;
+ ISeqOutStreamPtr outStream;
+ ICompressProgressPtr progress;
+
+ BoolInt finishMode;
+ BoolInt outSize_Defined;
+ UInt64 outSize;
+
+ UInt64 outProcessed;
+ UInt64 inProcessed;
+ UInt64 readProcessed;
+ BoolInt readWasFinished;
+ SRes readRes;
+ SRes writeRes;
+
+ Byte *outBuf;
+ size_t outBufSize;
+ Byte *inBuf;
+ size_t inBufSize;
+
+ CXzUnpacker dec;
+
+ ECoderStatus status;
+ SRes codeRes;
+
+ #ifndef Z7_ST
+ BoolInt mainDecoderWasCalled;
+ // int statErrorDefined;
+ int finishedDecoderIndex;
+
+ // global values that are used in Parse stage
+ CXzStreamFlags streamFlags;
+ // UInt64 numFinishedStreams
+ UInt64 numStreams;
+ UInt64 numTotalBlocks;
+ UInt64 numBlocks;
+
+ // UInt64 numBadBlocks;
+ SRes mainErrorCode; // it's set to error code, if the size Code() output doesn't patch the size from Parsing stage
+ // it can be = SZ_ERROR_INPUT_EOF
+ // it can be = SZ_ERROR_DATA, in some another cases
+ BoolInt isBlockHeaderState_Parse;
+ BoolInt isBlockHeaderState_Write;
+ UInt64 outProcessed_Parse;
+ BoolInt parsing_Truncated;
+
+ BoolInt mtc_WasConstructed;
+ CMtDec mtc;
+ CXzDecMtThread coders[MTDEC_THREADS_MAX];
+ #endif
+};
+
+
+
+CXzDecMtHandle XzDecMt_Create(ISzAllocPtr alloc, ISzAllocPtr allocMid)
+{
+ CXzDecMt *p = (CXzDecMt *)ISzAlloc_Alloc(alloc, sizeof(CXzDecMt));
+ if (!p)
+ return NULL;
+
+ AlignOffsetAlloc_CreateVTable(&p->alignOffsetAlloc);
+ p->alignOffsetAlloc.baseAlloc = alloc;
+ p->alignOffsetAlloc.numAlignBits = 7;
+ p->alignOffsetAlloc.offset = 0;
+
+ p->allocMid = allocMid;
+
+ p->outBuf = NULL;
+ p->outBufSize = 0;
+ p->inBuf = NULL;
+ p->inBufSize = 0;
+
+ XzUnpacker_Construct(&p->dec, &p->alignOffsetAlloc.vt);
+
+ p->unpackBlockMaxSize = 0;
+
+ XzDecMtProps_Init(&p->props);
+
+ #ifndef Z7_ST
+ p->mtc_WasConstructed = False;
+ {
+ unsigned i;
+ for (i = 0; i < MTDEC_THREADS_MAX; i++)
+ {
+ CXzDecMtThread *coder = &p->coders[i];
+ coder->dec_created = False;
+ coder->outBuf = NULL;
+ coder->outBufSize = 0;
+ }
+ }
+ #endif
+
+ return (CXzDecMtHandle)p;
+}
+
+
+#ifndef Z7_ST
+
+static void XzDecMt_FreeOutBufs(CXzDecMt *p)
+{
+ unsigned i;
+ for (i = 0; i < MTDEC_THREADS_MAX; i++)
+ {
+ CXzDecMtThread *coder = &p->coders[i];
+ if (coder->outBuf)
+ {
+ ISzAlloc_Free(p->allocMid, coder->outBuf);
+ coder->outBuf = NULL;
+ coder->outBufSize = 0;
+ }
+ }
+ p->unpackBlockMaxSize = 0;
+}
+
+#endif
+
+
+
+static void XzDecMt_FreeSt(CXzDecMt *p)
+{
+ XzUnpacker_Free(&p->dec);
+
+ if (p->outBuf)
+ {
+ ISzAlloc_Free(p->allocMid, p->outBuf);
+ p->outBuf = NULL;
+ }
+ p->outBufSize = 0;
+
+ if (p->inBuf)
+ {
+ ISzAlloc_Free(p->allocMid, p->inBuf);
+ p->inBuf = NULL;
+ }
+ p->inBufSize = 0;
+}
+
+
+// #define GET_CXzDecMt_p CXzDecMt *p = pp;
+
+void XzDecMt_Destroy(CXzDecMtHandle p)
+{
+ // GET_CXzDecMt_p
+
+ XzDecMt_FreeSt(p);
+
+ #ifndef Z7_ST
+
+ if (p->mtc_WasConstructed)
+ {
+ MtDec_Destruct(&p->mtc);
+ p->mtc_WasConstructed = False;
+ }
+ {
+ unsigned i;
+ for (i = 0; i < MTDEC_THREADS_MAX; i++)
+ {
+ CXzDecMtThread *t = &p->coders[i];
+ if (t->dec_created)
+ {
+ // we don't need to free dict here
+ XzUnpacker_Free(&t->dec);
+ t->dec_created = False;
+ }
+ }
+ }
+ XzDecMt_FreeOutBufs(p);
+
+ #endif
+
+ ISzAlloc_Free(p->alignOffsetAlloc.baseAlloc, p);
+}
+
+
+
+#ifndef Z7_ST
+
+static void XzDecMt_Callback_Parse(void *obj, unsigned coderIndex, CMtDecCallbackInfo *cc)
+{
+ CXzDecMt *me = (CXzDecMt *)obj;
+ CXzDecMtThread *coder = &me->coders[coderIndex];
+ size_t srcSize = cc->srcSize;
+
+ cc->srcSize = 0;
+ cc->outPos = 0;
+ cc->state = MTDEC_PARSE_CONTINUE;
+
+ cc->canCreateNewThread = True;
+
+ if (cc->startCall)
+ {
+ coder->outPreSize = 0;
+ coder->inPreSize = 0;
+ coder->inPreHeaderSize = 0;
+ coder->parseState = MTDEC_PARSE_CONTINUE;
+ coder->parsing_Truncated = False;
+ coder->skipMode = False;
+ coder->codeRes = SZ_OK;
+ coder->status = CODER_STATUS_NOT_SPECIFIED;
+ coder->inCodeSize = 0;
+ coder->outCodeSize = 0;
+
+ coder->numStreams = me->numStreams;
+ coder->numTotalBlocks = me->numTotalBlocks;
+ coder->numBlocks = me->numBlocks;
+
+ if (!coder->dec_created)
+ {
+ XzUnpacker_Construct(&coder->dec, &me->alignOffsetAlloc.vt);
+ coder->dec_created = True;
+ }
+
+ XzUnpacker_Init(&coder->dec);
+
+ if (me->isBlockHeaderState_Parse)
+ {
+ coder->dec.streamFlags = me->streamFlags;
+ coder->atBlockHeader = True;
+ XzUnpacker_PrepareToRandomBlockDecoding(&coder->dec);
+ }
+ else
+ {
+ coder->atBlockHeader = False;
+ me->isBlockHeaderState_Parse = True;
+ }
+
+ coder->dec.numStartedStreams = me->numStreams;
+ coder->dec.numTotalBlocks = me->numTotalBlocks;
+ coder->dec.numBlocks = me->numBlocks;
+ }
+
+ while (!coder->skipMode)
+ {
+ ECoderStatus status;
+ SRes res;
+ size_t srcSize2 = srcSize;
+ size_t destSize = (size_t)0 - 1;
+
+ coder->dec.parseMode = True;
+ coder->dec.headerParsedOk = False;
+
+ PRF_STR_INT("Parse", srcSize2)
+
+ res = XzUnpacker_Code(&coder->dec,
+ NULL, &destSize,
+ cc->src, &srcSize2, cc->srcFinished,
+ CODER_FINISH_END, &status);
+
+ // PRF(printf(" res = %d, srcSize2 = %d", res, (unsigned)srcSize2));
+
+ coder->codeRes = res;
+ coder->status = status;
+ cc->srcSize += srcSize2;
+ srcSize -= srcSize2;
+ coder->inPreHeaderSize += srcSize2;
+ coder->inPreSize = coder->inPreHeaderSize;
+
+ if (res != SZ_OK)
+ {
+ cc->state =
+ coder->parseState = MTDEC_PARSE_END;
+ /*
+ if (res == SZ_ERROR_MEM)
+ return res;
+ return SZ_OK;
+ */
+ return; // res;
+ }
+
+ if (coder->dec.headerParsedOk)
+ {
+ const CXzBlock *block = &coder->dec.block;
+ if (XzBlock_HasUnpackSize(block)
+ // && block->unpackSize <= me->props.outBlockMax
+ && XzBlock_HasPackSize(block))
+ {
+ {
+ if (block->unpackSize * 2 * me->mtc.numStartedThreads > me->props.memUseMax)
+ {
+ cc->state = MTDEC_PARSE_OVERFLOW;
+ return; // SZ_OK;
+ }
+ }
+ {
+ UInt64 packSize = block->packSize;
+ UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3);
+ UInt32 checkSize = XzFlags_GetCheckSize(coder->dec.streamFlags);
+ UInt64 blockPackSum = coder->inPreSize + packSizeAligned + checkSize;
+ // if (blockPackSum <= me->props.inBlockMax)
+ // unpackBlockMaxSize
+ {
+ coder->blockPackSize_for_Index = (size_t)(coder->dec.blockHeaderSize + packSize + checkSize);
+ coder->blockPackTotal = (size_t)blockPackSum;
+ coder->outPreSize = (size_t)block->unpackSize;
+ coder->streamFlags = coder->dec.streamFlags;
+ me->streamFlags = coder->dec.streamFlags;
+ coder->skipMode = True;
+ break;
+ }
+ }
+ }
+ }
+ else
+ // if (coder->inPreSize <= me->props.inBlockMax)
+ {
+ if (!cc->srcFinished)
+ return; // SZ_OK;
+ cc->state =
+ coder->parseState = MTDEC_PARSE_END;
+ return; // SZ_OK;
+ }
+ cc->state = MTDEC_PARSE_OVERFLOW;
+ return; // SZ_OK;
+ }
+
+ // ---------- skipMode ----------
+ {
+ UInt64 rem = coder->blockPackTotal - coder->inPreSize;
+ size_t cur = srcSize;
+ if (cur > rem)
+ cur = (size_t)rem;
+ cc->srcSize += cur;
+ coder->inPreSize += cur;
+ srcSize -= cur;
+
+ if (coder->inPreSize == coder->blockPackTotal)
+ {
+ if (srcSize == 0)
+ {
+ if (!cc->srcFinished)
+ return; // SZ_OK;
+ cc->state = MTDEC_PARSE_END;
+ }
+ else if ((cc->src)[cc->srcSize] == 0) // we check control byte of next block
+ cc->state = MTDEC_PARSE_END;
+ else
+ {
+ cc->state = MTDEC_PARSE_NEW;
+
+ {
+ size_t blockMax = me->unpackBlockMaxSize;
+ if (blockMax < coder->outPreSize)
+ blockMax = coder->outPreSize;
+ {
+ UInt64 required = (UInt64)blockMax * (me->mtc.numStartedThreads + 1) * 2;
+ if (me->props.memUseMax < required)
+ cc->canCreateNewThread = False;
+ }
+ }
+
+ if (me->outSize_Defined)
+ {
+ // next block can be zero size
+ const UInt64 rem2 = me->outSize - me->outProcessed_Parse;
+ if (rem2 < coder->outPreSize)
+ {
+ coder->parsing_Truncated = True;
+ cc->state = MTDEC_PARSE_END;
+ }
+ me->outProcessed_Parse += coder->outPreSize;
+ }
+ }
+ }
+ else if (cc->srcFinished)
+ cc->state = MTDEC_PARSE_END;
+ else
+ return; // SZ_OK;
+
+ coder->parseState = cc->state;
+ cc->outPos = coder->outPreSize;
+
+ me->numStreams = coder->dec.numStartedStreams;
+ me->numTotalBlocks = coder->dec.numTotalBlocks;
+ me->numBlocks = coder->dec.numBlocks + 1;
+ return; // SZ_OK;
+ }
+}
+
+
+static SRes XzDecMt_Callback_PreCode(void *pp, unsigned coderIndex)
+{
+ CXzDecMt *me = (CXzDecMt *)pp;
+ CXzDecMtThread *coder = &me->coders[coderIndex];
+ Byte *dest;
+
+ if (!coder->dec.headerParsedOk)
+ return SZ_OK;
+
+ dest = coder->outBuf;
+
+ if (!dest || coder->outBufSize < coder->outPreSize)
+ {
+ if (dest)
+ {
+ ISzAlloc_Free(me->allocMid, dest);
+ coder->outBuf = NULL;
+ coder->outBufSize = 0;
+ }
+ {
+ size_t outPreSize = coder->outPreSize;
+ if (outPreSize == 0)
+ outPreSize = 1;
+ dest = (Byte *)ISzAlloc_Alloc(me->allocMid, outPreSize);
+ }
+ if (!dest)
+ return SZ_ERROR_MEM;
+ coder->outBuf = dest;
+ coder->outBufSize = coder->outPreSize;
+
+ if (coder->outBufSize > me->unpackBlockMaxSize)
+ me->unpackBlockMaxSize = coder->outBufSize;
+ }
+
+ // return SZ_ERROR_MEM;
+
+ XzUnpacker_SetOutBuf(&coder->dec, coder->outBuf, coder->outBufSize);
+
+ {
+ SRes res = XzDecMix_Init(&coder->dec.decoder, &coder->dec.block, coder->outBuf, coder->outBufSize);
+ // res = SZ_ERROR_UNSUPPORTED; // to test
+ coder->codeRes = res;
+ if (res != SZ_OK)
+ {
+ // if (res == SZ_ERROR_MEM) return res;
+ if (me->props.ignoreErrors && res != SZ_ERROR_MEM)
+ return SZ_OK;
+ return res;
+ }
+ }
+
+ return SZ_OK;
+}
+
+
+static SRes XzDecMt_Callback_Code(void *pp, unsigned coderIndex,
+ const Byte *src, size_t srcSize, int srcFinished,
+ // int finished, int blockFinished,
+ UInt64 *inCodePos, UInt64 *outCodePos, int *stop)
+{
+ CXzDecMt *me = (CXzDecMt *)pp;
+ CXzDecMtThread *coder = &me->coders[coderIndex];
+
+ *inCodePos = coder->inCodeSize;
+ *outCodePos = coder->outCodeSize;
+ *stop = True;
+
+ if (srcSize > coder->inPreSize - coder->inCodeSize)
+ return SZ_ERROR_FAIL;
+
+ if (coder->inCodeSize < coder->inPreHeaderSize)
+ {
+ size_t step = coder->inPreHeaderSize - coder->inCodeSize;
+ if (step > srcSize)
+ step = srcSize;
+ src += step;
+ srcSize -= step;
+ coder->inCodeSize += step;
+ *inCodePos = coder->inCodeSize;
+ if (coder->inCodeSize < coder->inPreHeaderSize)
+ {
+ *stop = False;
+ return SZ_OK;
+ }
+ }
+
+ if (!coder->dec.headerParsedOk)
+ return SZ_OK;
+ if (!coder->outBuf)
+ return SZ_OK;
+
+ if (coder->codeRes == SZ_OK)
+ {
+ ECoderStatus status;
+ SRes res;
+ size_t srcProcessed = srcSize;
+ size_t outSizeCur = coder->outPreSize - coder->dec.outDataWritten;
+
+ // PRF(printf("\nCallback_Code: Code %d %d\n", (unsigned)srcSize, (unsigned)outSizeCur));
+
+ res = XzUnpacker_Code(&coder->dec,
+ NULL, &outSizeCur,
+ src, &srcProcessed, srcFinished,
+ // coder->finishedWithMark ? CODER_FINISH_END : CODER_FINISH_ANY,
+ CODER_FINISH_END,
+ &status);
+
+ // PRF(printf(" res = %d, srcSize2 = %d, outSizeCur = %d", res, (unsigned)srcProcessed, (unsigned)outSizeCur));
+
+ coder->codeRes = res;
+ coder->status = status;
+ coder->inCodeSize += srcProcessed;
+ coder->outCodeSize = coder->dec.outDataWritten;
+ *inCodePos = coder->inCodeSize;
+ *outCodePos = coder->outCodeSize;
+
+ if (res == SZ_OK)
+ {
+ if (srcProcessed == srcSize)
+ *stop = False;
+ return SZ_OK;
+ }
+ }
+
+ if (me->props.ignoreErrors && coder->codeRes != SZ_ERROR_MEM)
+ {
+ *inCodePos = coder->inPreSize;
+ *outCodePos = coder->outPreSize;
+ return SZ_OK;
+ }
+ return coder->codeRes;
+}
+
+
+#define XZDECMT_STREAM_WRITE_STEP (1 << 24)
+
+static SRes XzDecMt_Callback_Write(void *pp, unsigned coderIndex,
+ BoolInt needWriteToStream,
+ const Byte *src, size_t srcSize, BoolInt isCross,
+ // int srcFinished,
+ BoolInt *needContinue,
+ BoolInt *canRecode)
+{
+ CXzDecMt *me = (CXzDecMt *)pp;
+ const CXzDecMtThread *coder = &me->coders[coderIndex];
+
+ // PRF(printf("\nWrite processed = %d srcSize = %d\n", (unsigned)me->mtc.inProcessed, (unsigned)srcSize));
+
+ *needContinue = False;
+ *canRecode = True;
+
+ if (!needWriteToStream)
+ return SZ_OK;
+
+ if (!coder->dec.headerParsedOk || !coder->outBuf)
+ {
+ if (me->finishedDecoderIndex < 0)
+ me->finishedDecoderIndex = (int)coderIndex;
+ return SZ_OK;
+ }
+
+ if (me->finishedDecoderIndex >= 0)
+ return SZ_OK;
+
+ me->mtc.inProcessed += coder->inCodeSize;
+
+ *canRecode = False;
+
+ {
+ SRes res;
+ size_t size = coder->outCodeSize;
+ Byte *data = coder->outBuf;
+
+ // we use in me->dec: sha, numBlocks, indexSize
+
+ if (!me->isBlockHeaderState_Write)
+ {
+ XzUnpacker_PrepareToRandomBlockDecoding(&me->dec);
+ me->dec.decodeOnlyOneBlock = False;
+ me->dec.numStartedStreams = coder->dec.numStartedStreams;
+ me->dec.streamFlags = coder->streamFlags;
+
+ me->isBlockHeaderState_Write = True;
+ }
+
+ me->dec.numTotalBlocks = coder->dec.numTotalBlocks;
+ XzUnpacker_UpdateIndex(&me->dec, coder->blockPackSize_for_Index, coder->outPreSize);
+
+ if (coder->outPreSize != size)
+ {
+ if (me->props.ignoreErrors)
+ {
+ memset(data + size, 0, coder->outPreSize - size);
+ size = coder->outPreSize;
+ }
+ // me->numBadBlocks++;
+ if (me->mainErrorCode == SZ_OK)
+ {
+ if ((int)coder->status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ me->mainErrorCode = SZ_ERROR_INPUT_EOF;
+ else
+ me->mainErrorCode = SZ_ERROR_DATA;
+ }
+ }
+
+ if (me->writeRes != SZ_OK)
+ return me->writeRes;
+
+ res = SZ_OK;
+ {
+ if (me->outSize_Defined)
+ {
+ const UInt64 rem = me->outSize - me->outProcessed;
+ if (size > rem)
+ size = (SizeT)rem;
+ }
+
+ for (;;)
+ {
+ size_t cur = size;
+ size_t written;
+ if (cur > XZDECMT_STREAM_WRITE_STEP)
+ cur = XZDECMT_STREAM_WRITE_STEP;
+
+ written = ISeqOutStream_Write(me->outStream, data, cur);
+
+ // PRF(printf("\nWritten ask = %d written = %d\n", (unsigned)cur, (unsigned)written));
+
+ me->outProcessed += written;
+ if (written != cur)
+ {
+ me->writeRes = SZ_ERROR_WRITE;
+ res = me->writeRes;
+ break;
+ }
+ data += cur;
+ size -= cur;
+ // PRF_STR_INT("Written size =", size)
+ if (size == 0)
+ break;
+ res = MtProgress_ProgressAdd(&me->mtc.mtProgress, 0, 0);
+ if (res != SZ_OK)
+ break;
+ }
+ }
+
+ if (coder->codeRes != SZ_OK)
+ if (!me->props.ignoreErrors)
+ {
+ me->finishedDecoderIndex = (int)coderIndex;
+ return res;
+ }
+
+ RINOK(res)
+
+ if (coder->inPreSize != coder->inCodeSize
+ || coder->blockPackTotal != coder->inCodeSize)
+ {
+ me->finishedDecoderIndex = (int)coderIndex;
+ return SZ_OK;
+ }
+
+ if (coder->parseState != MTDEC_PARSE_END)
+ {
+ *needContinue = True;
+ return SZ_OK;
+ }
+ }
+
+ // (coder->state == MTDEC_PARSE_END) means that there are no other working threads
+ // so we can use mtc variables without lock
+
+ PRF_STR_INT("Write MTDEC_PARSE_END", me->mtc.inProcessed)
+
+ me->mtc.mtProgress.totalInSize = me->mtc.inProcessed;
+ {
+ CXzUnpacker *dec = &me->dec;
+
+ PRF_STR_INT("PostSingle", srcSize)
+
+ {
+ size_t srcProcessed = srcSize;
+ ECoderStatus status;
+ size_t outSizeCur = 0;
+ SRes res;
+
+ // dec->decodeOnlyOneBlock = False;
+ dec->decodeToStreamSignature = True;
+
+ me->mainDecoderWasCalled = True;
+
+ if (coder->parsing_Truncated)
+ {
+ me->parsing_Truncated = True;
+ return SZ_OK;
+ }
+
+ /*
+ We have processed all xz-blocks of stream,
+ And xz unpacker is at XZ_STATE_BLOCK_HEADER state, where
+ (src) is a pointer to xz-Index structure.
+ We finish reading of current xz-Stream, including Zero padding after xz-Stream.
+ We exit, if we reach extra byte (first byte of new-Stream or another data).
+ But we don't update input stream pointer for that new extra byte.
+ If extra byte is not correct first byte of xz-signature,
+ we have SZ_ERROR_NO_ARCHIVE error here.
+ */
+
+ res = XzUnpacker_Code(dec,
+ NULL, &outSizeCur,
+ src, &srcProcessed,
+ me->mtc.readWasFinished, // srcFinished
+ CODER_FINISH_END, // CODER_FINISH_ANY,
+ &status);
+
+ // res = SZ_ERROR_ARCHIVE; // for failure test
+
+ me->status = status;
+ me->codeRes = res;
+
+ if (isCross)
+ me->mtc.crossStart += srcProcessed;
+
+ me->mtc.inProcessed += srcProcessed;
+ me->mtc.mtProgress.totalInSize = me->mtc.inProcessed;
+
+ srcSize -= srcProcessed;
+ src += srcProcessed;
+
+ if (res != SZ_OK)
+ {
+ return SZ_OK;
+ // return res;
+ }
+
+ if (dec->state == XZ_STATE_STREAM_HEADER)
+ {
+ *needContinue = True;
+ me->isBlockHeaderState_Parse = False;
+ me->isBlockHeaderState_Write = False;
+
+ if (!isCross)
+ {
+ Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc);
+ if (!crossBuf)
+ return SZ_ERROR_MEM;
+ if (srcSize != 0)
+ memcpy(crossBuf, src, srcSize);
+ me->mtc.crossStart = 0;
+ me->mtc.crossEnd = srcSize;
+ }
+
+ PRF_STR_INT("XZ_STATE_STREAM_HEADER crossEnd = ", (unsigned)me->mtc.crossEnd)
+
+ return SZ_OK;
+ }
+
+ if (status != CODER_STATUS_NEEDS_MORE_INPUT || srcSize != 0)
+ {
+ return SZ_ERROR_FAIL;
+ }
+
+ if (me->mtc.readWasFinished)
+ {
+ return SZ_OK;
+ }
+ }
+
+ {
+ size_t inPos;
+ size_t inLim;
+ // const Byte *inData;
+ UInt64 inProgressPrev = me->mtc.inProcessed;
+
+ // XzDecMt_Prepare_InBuf_ST(p);
+ Byte *crossBuf = MtDec_GetCrossBuff(&me->mtc);
+ if (!crossBuf)
+ return SZ_ERROR_MEM;
+
+ inPos = 0;
+ inLim = 0;
+
+ // inData = crossBuf;
+
+ for (;;)
+ {
+ SizeT inProcessed;
+ SizeT outProcessed;
+ ECoderStatus status;
+ SRes res;
+
+ if (inPos == inLim)
+ {
+ if (!me->mtc.readWasFinished)
+ {
+ inPos = 0;
+ inLim = me->mtc.inBufSize;
+ me->mtc.readRes = ISeqInStream_Read(me->inStream, (void *)crossBuf, &inLim);
+ me->mtc.readProcessed += inLim;
+ if (inLim == 0 || me->mtc.readRes != SZ_OK)
+ me->mtc.readWasFinished = True;
+ }
+ }
+
+ inProcessed = inLim - inPos;
+ outProcessed = 0;
+
+ res = XzUnpacker_Code(dec,
+ NULL, &outProcessed,
+ crossBuf + inPos, &inProcessed,
+ (inProcessed == 0), // srcFinished
+ CODER_FINISH_END, &status);
+
+ me->codeRes = res;
+ me->status = status;
+ inPos += inProcessed;
+ me->mtc.inProcessed += inProcessed;
+ me->mtc.mtProgress.totalInSize = me->mtc.inProcessed;
+
+ if (res != SZ_OK)
+ {
+ return SZ_OK;
+ // return res;
+ }
+
+ if (dec->state == XZ_STATE_STREAM_HEADER)
+ {
+ *needContinue = True;
+ me->mtc.crossStart = inPos;
+ me->mtc.crossEnd = inLim;
+ me->isBlockHeaderState_Parse = False;
+ me->isBlockHeaderState_Write = False;
+ return SZ_OK;
+ }
+
+ if (status != CODER_STATUS_NEEDS_MORE_INPUT)
+ return SZ_ERROR_FAIL;
+
+ if (me->mtc.progress)
+ {
+ UInt64 inDelta = me->mtc.inProcessed - inProgressPrev;
+ if (inDelta >= (1 << 22))
+ {
+ RINOK(MtProgress_Progress_ST(&me->mtc.mtProgress))
+ inProgressPrev = me->mtc.inProcessed;
+ }
+ }
+ if (me->mtc.readWasFinished)
+ return SZ_OK;
+ }
+ }
+ }
+}
+
+
+#endif
+
+
+
+void XzStatInfo_Clear(CXzStatInfo *p)
+{
+ p->InSize = 0;
+ p->OutSize = 0;
+
+ p->NumStreams = 0;
+ p->NumBlocks = 0;
+
+ p->UnpackSize_Defined = False;
+
+ p->NumStreams_Defined = False;
+ p->NumBlocks_Defined = False;
+
+ p->DataAfterEnd = False;
+ p->DecodingTruncated = False;
+
+ p->DecodeRes = SZ_OK;
+ p->ReadRes = SZ_OK;
+ p->ProgressRes = SZ_OK;
+
+ p->CombinedRes = SZ_OK;
+ p->CombinedRes_Type = SZ_OK;
+}
+
+
+
+/*
+ XzDecMt_Decode_ST() can return SZ_OK or the following errors
+ - SZ_ERROR_MEM for memory allocation error
+ - error from XzUnpacker_Code() function
+ - SZ_ERROR_WRITE for ISeqOutStream::Write(). stat->CombinedRes_Type = SZ_ERROR_WRITE in that case
+ - ICompressProgress::Progress() error, stat->CombinedRes_Type = SZ_ERROR_PROGRESS.
+ But XzDecMt_Decode_ST() doesn't return ISeqInStream::Read() errors.
+ ISeqInStream::Read() result is set to p->readRes.
+ also it can set stat->CombinedRes_Type to SZ_ERROR_WRITE or SZ_ERROR_PROGRESS.
+*/
+
+static SRes XzDecMt_Decode_ST(CXzDecMt *p
+ #ifndef Z7_ST
+ , BoolInt tMode
+ #endif
+ , CXzStatInfo *stat)
+{
+ size_t outPos;
+ size_t inPos, inLim;
+ const Byte *inData;
+ UInt64 inPrev, outPrev;
+
+ CXzUnpacker *dec;
+
+ #ifndef Z7_ST
+ if (tMode)
+ {
+ XzDecMt_FreeOutBufs(p);
+ tMode = MtDec_PrepareRead(&p->mtc);
+ }
+ #endif
+
+ if (!p->outBuf || p->outBufSize != p->props.outStep_ST)
+ {
+ ISzAlloc_Free(p->allocMid, p->outBuf);
+ p->outBufSize = 0;
+ p->outBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.outStep_ST);
+ if (!p->outBuf)
+ return SZ_ERROR_MEM;
+ p->outBufSize = p->props.outStep_ST;
+ }
+
+ if (!p->inBuf || p->inBufSize != p->props.inBufSize_ST)
+ {
+ ISzAlloc_Free(p->allocMid, p->inBuf);
+ p->inBufSize = 0;
+ p->inBuf = (Byte *)ISzAlloc_Alloc(p->allocMid, p->props.inBufSize_ST);
+ if (!p->inBuf)
+ return SZ_ERROR_MEM;
+ p->inBufSize = p->props.inBufSize_ST;
+ }
+
+ dec = &p->dec;
+ dec->decodeToStreamSignature = False;
+ // dec->decodeOnlyOneBlock = False;
+
+ XzUnpacker_SetOutBuf(dec, NULL, 0);
+
+ inPrev = p->inProcessed;
+ outPrev = p->outProcessed;
+
+ inPos = 0;
+ inLim = 0;
+ inData = NULL;
+ outPos = 0;
+
+ for (;;)
+ {
+ SizeT outSize;
+ BoolInt finished;
+ ECoderFinishMode finishMode;
+ SizeT inProcessed;
+ ECoderStatus status;
+ SRes res;
+
+ SizeT outProcessed;
+
+
+
+ if (inPos == inLim)
+ {
+ #ifndef Z7_ST
+ if (tMode)
+ {
+ inData = MtDec_Read(&p->mtc, &inLim);
+ inPos = 0;
+ if (inData)
+ continue;
+ tMode = False;
+ inLim = 0;
+ }
+ #endif
+
+ if (!p->readWasFinished)
+ {
+ inPos = 0;
+ inLim = p->inBufSize;
+ inData = p->inBuf;
+ p->readRes = ISeqInStream_Read(p->inStream, (void *)p->inBuf, &inLim);
+ p->readProcessed += inLim;
+ if (inLim == 0 || p->readRes != SZ_OK)
+ p->readWasFinished = True;
+ }
+ }
+
+ outSize = p->props.outStep_ST - outPos;
+
+ finishMode = CODER_FINISH_ANY;
+ if (p->outSize_Defined)
+ {
+ const UInt64 rem = p->outSize - p->outProcessed;
+ if (outSize >= rem)
+ {
+ outSize = (SizeT)rem;
+ if (p->finishMode)
+ finishMode = CODER_FINISH_END;
+ }
+ }
+
+ inProcessed = inLim - inPos;
+ outProcessed = outSize;
+
+ res = XzUnpacker_Code(dec, p->outBuf + outPos, &outProcessed,
+ inData + inPos, &inProcessed,
+ (inPos == inLim), // srcFinished
+ finishMode, &status);
+
+ p->codeRes = res;
+ p->status = status;
+
+ inPos += inProcessed;
+ outPos += outProcessed;
+ p->inProcessed += inProcessed;
+ p->outProcessed += outProcessed;
+
+ finished = ((inProcessed == 0 && outProcessed == 0) || res != SZ_OK);
+
+ if (finished || outProcessed >= outSize)
+ if (outPos != 0)
+ {
+ const size_t written = ISeqOutStream_Write(p->outStream, p->outBuf, outPos);
+ // p->outProcessed += written; // 21.01: BUG fixed
+ if (written != outPos)
+ {
+ stat->CombinedRes_Type = SZ_ERROR_WRITE;
+ return SZ_ERROR_WRITE;
+ }
+ outPos = 0;
+ }
+
+ if (p->progress && res == SZ_OK)
+ {
+ if (p->inProcessed - inPrev >= (1 << 22) ||
+ p->outProcessed - outPrev >= (1 << 22))
+ {
+ res = ICompressProgress_Progress(p->progress, p->inProcessed, p->outProcessed);
+ if (res != SZ_OK)
+ {
+ stat->CombinedRes_Type = SZ_ERROR_PROGRESS;
+ stat->ProgressRes = res;
+ return res;
+ }
+ inPrev = p->inProcessed;
+ outPrev = p->outProcessed;
+ }
+ }
+
+ if (finished)
+ {
+ // p->codeRes is preliminary error from XzUnpacker_Code.
+ // and it can be corrected later as final result
+ // so we return SZ_OK here instead of (res);
+ return SZ_OK;
+ // return res;
+ }
+ }
+}
+
+
+
+/*
+XzStatInfo_SetStat() transforms
+ CXzUnpacker return code and status to combined CXzStatInfo results.
+ it can convert SZ_OK to SZ_ERROR_INPUT_EOF
+ it can convert SZ_ERROR_NO_ARCHIVE to SZ_OK and (DataAfterEnd = 1)
+*/
+
+static void XzStatInfo_SetStat(const CXzUnpacker *dec,
+ int finishMode,
+ // UInt64 readProcessed,
+ UInt64 inProcessed,
+ SRes res, // it's result from CXzUnpacker unpacker
+ ECoderStatus status,
+ BoolInt decodingTruncated,
+ CXzStatInfo *stat)
+{
+ UInt64 extraSize;
+
+ stat->DecodingTruncated = (Byte)(decodingTruncated ? 1 : 0);
+ stat->InSize = inProcessed;
+ stat->NumStreams = dec->numStartedStreams;
+ stat->NumBlocks = dec->numTotalBlocks;
+
+ stat->UnpackSize_Defined = True;
+ stat->NumStreams_Defined = True;
+ stat->NumBlocks_Defined = True;
+
+ extraSize = XzUnpacker_GetExtraSize(dec);
+
+ if (res == SZ_OK)
+ {
+ if (status == CODER_STATUS_NEEDS_MORE_INPUT)
+ {
+ // CODER_STATUS_NEEDS_MORE_INPUT is expected status for correct xz streams
+ // any extra data is part of correct data
+ extraSize = 0;
+ // if xz stream was not finished, then we need more data
+ if (!XzUnpacker_IsStreamWasFinished(dec))
+ res = SZ_ERROR_INPUT_EOF;
+ }
+ else
+ {
+ // CODER_STATUS_FINISHED_WITH_MARK is not possible for multi stream xz decoding
+ // so he we have (status == CODER_STATUS_NOT_FINISHED)
+ // if (status != CODER_STATUS_FINISHED_WITH_MARK)
+ if (!decodingTruncated || finishMode)
+ res = SZ_ERROR_DATA;
+ }
+ }
+ else if (res == SZ_ERROR_NO_ARCHIVE)
+ {
+ /*
+ SZ_ERROR_NO_ARCHIVE is possible for 2 states:
+ XZ_STATE_STREAM_HEADER - if bad signature or bad CRC
+ XZ_STATE_STREAM_PADDING - if non-zero padding data
+ extraSize and inProcessed don't include "bad" byte
+ */
+ // if (inProcessed == extraSize), there was no any good xz stream header, and we keep error
+ if (inProcessed != extraSize) // if there were good xz streams before error
+ {
+ // if (extraSize != 0 || readProcessed != inProcessed)
+ {
+ // he we suppose that all xz streams were finsihed OK, and we have
+ // some extra data after all streams
+ stat->DataAfterEnd = True;
+ res = SZ_OK;
+ }
+ }
+ }
+
+ if (stat->DecodeRes == SZ_OK)
+ stat->DecodeRes = res;
+
+ stat->InSize -= extraSize;
+}
+
+
+
+SRes XzDecMt_Decode(CXzDecMtHandle p,
+ const CXzDecMtProps *props,
+ const UInt64 *outDataSize, int finishMode,
+ ISeqOutStreamPtr outStream,
+ // Byte *outBuf, size_t *outBufSize,
+ ISeqInStreamPtr inStream,
+ // const Byte *inData, size_t inDataSize,
+ CXzStatInfo *stat,
+ int *isMT,
+ ICompressProgressPtr progress)
+{
+ // GET_CXzDecMt_p
+ #ifndef Z7_ST
+ BoolInt tMode;
+ #endif
+
+ XzStatInfo_Clear(stat);
+
+ p->props = *props;
+
+ p->inStream = inStream;
+ p->outStream = outStream;
+ p->progress = progress;
+ // p->stat = stat;
+
+ p->outSize = 0;
+ p->outSize_Defined = False;
+ if (outDataSize)
+ {
+ p->outSize_Defined = True;
+ p->outSize = *outDataSize;
+ }
+
+ p->finishMode = finishMode;
+
+ // p->outSize = 457; p->outSize_Defined = True; p->finishMode = False; // for test
+
+ p->writeRes = SZ_OK;
+ p->outProcessed = 0;
+ p->inProcessed = 0;
+ p->readProcessed = 0;
+ p->readWasFinished = False;
+ p->readRes = SZ_OK;
+
+ p->codeRes = SZ_OK;
+ p->status = CODER_STATUS_NOT_SPECIFIED;
+
+ XzUnpacker_Init(&p->dec);
+
+ *isMT = False;
+
+ /*
+ p->outBuf = NULL;
+ p->outBufSize = 0;
+ if (!outStream)
+ {
+ p->outBuf = outBuf;
+ p->outBufSize = *outBufSize;
+ *outBufSize = 0;
+ }
+ */
+
+
+ #ifndef Z7_ST
+
+ p->isBlockHeaderState_Parse = False;
+ p->isBlockHeaderState_Write = False;
+ // p->numBadBlocks = 0;
+ p->mainErrorCode = SZ_OK;
+ p->mainDecoderWasCalled = False;
+
+ tMode = False;
+
+ if (p->props.numThreads > 1)
+ {
+ IMtDecCallback2 vt;
+ BoolInt needContinue;
+ SRes res;
+ // we just free ST buffers here
+ // but we still keep state variables, that was set in XzUnpacker_Init()
+ XzDecMt_FreeSt(p);
+
+ p->outProcessed_Parse = 0;
+ p->parsing_Truncated = False;
+
+ p->numStreams = 0;
+ p->numTotalBlocks = 0;
+ p->numBlocks = 0;
+ p->finishedDecoderIndex = -1;
+
+ if (!p->mtc_WasConstructed)
+ {
+ p->mtc_WasConstructed = True;
+ MtDec_Construct(&p->mtc);
+ }
+
+ p->mtc.mtCallback = &vt;
+ p->mtc.mtCallbackObject = p;
+
+ p->mtc.progress = progress;
+ p->mtc.inStream = inStream;
+ p->mtc.alloc = &p->alignOffsetAlloc.vt;
+ // p->mtc.inData = inData;
+ // p->mtc.inDataSize = inDataSize;
+ p->mtc.inBufSize = p->props.inBufSize_MT;
+ // p->mtc.inBlockMax = p->props.inBlockMax;
+ p->mtc.numThreadsMax = p->props.numThreads;
+
+ *isMT = True;
+
+ vt.Parse = XzDecMt_Callback_Parse;
+ vt.PreCode = XzDecMt_Callback_PreCode;
+ vt.Code = XzDecMt_Callback_Code;
+ vt.Write = XzDecMt_Callback_Write;
+
+
+ res = MtDec_Code(&p->mtc);
+
+
+ stat->InSize = p->mtc.inProcessed;
+
+ p->inProcessed = p->mtc.inProcessed;
+ p->readRes = p->mtc.readRes;
+ p->readWasFinished = p->mtc.readWasFinished;
+ p->readProcessed = p->mtc.readProcessed;
+
+ tMode = True;
+ needContinue = False;
+
+ if (res == SZ_OK)
+ {
+ if (p->mtc.mtProgress.res != SZ_OK)
+ {
+ res = p->mtc.mtProgress.res;
+ stat->ProgressRes = res;
+ stat->CombinedRes_Type = SZ_ERROR_PROGRESS;
+ }
+ else
+ needContinue = p->mtc.needContinue;
+ }
+
+ if (!needContinue)
+ {
+ {
+ SRes codeRes;
+ BoolInt truncated = False;
+ ECoderStatus status;
+ const CXzUnpacker *dec;
+
+ stat->OutSize = p->outProcessed;
+
+ if (p->finishedDecoderIndex >= 0)
+ {
+ const CXzDecMtThread *coder = &p->coders[(unsigned)p->finishedDecoderIndex];
+ codeRes = coder->codeRes;
+ dec = &coder->dec;
+ status = coder->status;
+ }
+ else if (p->mainDecoderWasCalled)
+ {
+ codeRes = p->codeRes;
+ dec = &p->dec;
+ status = p->status;
+ truncated = p->parsing_Truncated;
+ }
+ else
+ return SZ_ERROR_FAIL;
+
+ if (p->mainErrorCode != SZ_OK)
+ stat->DecodeRes = p->mainErrorCode;
+
+ XzStatInfo_SetStat(dec, p->finishMode,
+ // p->mtc.readProcessed,
+ p->mtc.inProcessed,
+ codeRes, status,
+ truncated,
+ stat);
+ }
+
+ if (res == SZ_OK)
+ {
+ stat->ReadRes = p->mtc.readRes;
+
+ if (p->writeRes != SZ_OK)
+ {
+ res = p->writeRes;
+ stat->CombinedRes_Type = SZ_ERROR_WRITE;
+ }
+ else if (p->mtc.readRes != SZ_OK
+ // && p->mtc.inProcessed == p->mtc.readProcessed
+ && stat->DecodeRes == SZ_ERROR_INPUT_EOF)
+ {
+ res = p->mtc.readRes;
+ stat->CombinedRes_Type = SZ_ERROR_READ;
+ }
+ else if (stat->DecodeRes != SZ_OK)
+ res = stat->DecodeRes;
+ }
+
+ stat->CombinedRes = res;
+ if (stat->CombinedRes_Type == SZ_OK)
+ stat->CombinedRes_Type = res;
+ return res;
+ }
+
+ PRF_STR("----- decoding ST -----")
+ }
+
+ #endif
+
+
+ *isMT = False;
+
+ {
+ SRes res = XzDecMt_Decode_ST(p
+ #ifndef Z7_ST
+ , tMode
+ #endif
+ , stat
+ );
+
+ #ifndef Z7_ST
+ // we must set error code from MT decoding at first
+ if (p->mainErrorCode != SZ_OK)
+ stat->DecodeRes = p->mainErrorCode;
+ #endif
+
+ XzStatInfo_SetStat(&p->dec,
+ p->finishMode,
+ // p->readProcessed,
+ p->inProcessed,
+ p->codeRes, p->status,
+ False, // truncated
+ stat);
+
+ stat->ReadRes = p->readRes;
+
+ if (res == SZ_OK)
+ {
+ if (p->readRes != SZ_OK
+ // && p->inProcessed == p->readProcessed
+ && stat->DecodeRes == SZ_ERROR_INPUT_EOF)
+ {
+ // we set read error as combined error, only if that error was the reason
+ // of decoding problem
+ res = p->readRes;
+ stat->CombinedRes_Type = SZ_ERROR_READ;
+ }
+ else if (stat->DecodeRes != SZ_OK)
+ res = stat->DecodeRes;
+ }
+
+ stat->CombinedRes = res;
+ if (stat->CombinedRes_Type == SZ_OK)
+ stat->CombinedRes_Type = res;
+ return res;
+ }
+}
+
+#undef PRF
+#undef PRF_STR
+#undef PRF_STR_INT_2
diff --git a/C/XzEnc.c b/C/XzEnc.c
index 309eca9..22408e2 100644
--- a/C/XzEnc.c
+++ b/C/XzEnc.c
@@ -1,1329 +1,1362 @@
-/* XzEnc.c -- Xz Encode
-2019-02-02 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "7zCrc.h"
-#include "Bra.h"
-#include "CpuArch.h"
-
-#ifdef USE_SUBBLOCK
-#include "Bcj3Enc.c"
-#include "SbFind.c"
-#include "SbEnc.c"
-#endif
-
-#include "XzEnc.h"
-
-// #define _7ZIP_ST
-
-#ifndef _7ZIP_ST
-#include "MtCoder.h"
-#else
-#define MTCODER__THREADS_MAX 1
-#define MTCODER__BLOCKS_MAX 1
-#endif
-
-#define XZ_GET_PAD_SIZE(dataSize) ((4 - ((unsigned)(dataSize) & 3)) & 3)
-
-/* max pack size for LZMA2 block + check-64bytrs: */
-#define XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize) ((unpackSize) + ((unpackSize) >> 10) + 16 + 64)
-
-#define XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(unpackSize) (XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize))
-
-
-#define XzBlock_ClearFlags(p) (p)->flags = 0;
-#define XzBlock_SetNumFilters(p, n) (p)->flags |= ((n) - 1);
-#define XzBlock_SetHasPackSize(p) (p)->flags |= XZ_BF_PACK_SIZE;
-#define XzBlock_SetHasUnpackSize(p) (p)->flags |= XZ_BF_UNPACK_SIZE;
-
-
-static SRes WriteBytes(ISeqOutStream *s, const void *buf, size_t size)
-{
- return (ISeqOutStream_Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE;
-}
-
-static SRes WriteBytesUpdateCrc(ISeqOutStream *s, const void *buf, size_t size, UInt32 *crc)
-{
- *crc = CrcUpdate(*crc, buf, size);
- return WriteBytes(s, buf, size);
-}
-
-
-static SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStream *s)
-{
- UInt32 crc;
- Byte header[XZ_STREAM_HEADER_SIZE];
- memcpy(header, XZ_SIG, XZ_SIG_SIZE);
- header[XZ_SIG_SIZE] = (Byte)(f >> 8);
- header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF);
- crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE);
- SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc);
- return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE);
-}
-
-
-static SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStream *s)
-{
- Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
-
- unsigned pos = 1;
- unsigned numFilters, i;
- header[pos++] = p->flags;
-
- if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize);
- if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize);
- numFilters = XzBlock_GetNumFilters(p);
-
- for (i = 0; i < numFilters; i++)
- {
- const CXzFilter *f = &p->filters[i];
- pos += Xz_WriteVarInt(header + pos, f->id);
- pos += Xz_WriteVarInt(header + pos, f->propsSize);
- memcpy(header + pos, f->props, f->propsSize);
- pos += f->propsSize;
- }
-
- while ((pos & 3) != 0)
- header[pos++] = 0;
-
- header[0] = (Byte)(pos >> 2);
- SetUi32(header + pos, CrcCalc(header, pos));
- return WriteBytes(s, header, pos + 4);
-}
-
-
-
-
-typedef struct
-{
- size_t numBlocks;
- size_t size;
- size_t allocated;
- Byte *blocks;
-} CXzEncIndex;
-
-
-static void XzEncIndex_Construct(CXzEncIndex *p)
-{
- p->numBlocks = 0;
- p->size = 0;
- p->allocated = 0;
- p->blocks = NULL;
-}
-
-static void XzEncIndex_Init(CXzEncIndex *p)
-{
- p->numBlocks = 0;
- p->size = 0;
-}
-
-static void XzEncIndex_Free(CXzEncIndex *p, ISzAllocPtr alloc)
-{
- if (p->blocks)
- {
- ISzAlloc_Free(alloc, p->blocks);
- p->blocks = NULL;
- }
- p->numBlocks = 0;
- p->size = 0;
- p->allocated = 0;
-}
-
-
-static SRes XzEncIndex_ReAlloc(CXzEncIndex *p, size_t newSize, ISzAllocPtr alloc)
-{
- Byte *blocks = (Byte *)ISzAlloc_Alloc(alloc, newSize);
- if (!blocks)
- return SZ_ERROR_MEM;
- if (p->size != 0)
- memcpy(blocks, p->blocks, p->size);
- if (p->blocks)
- ISzAlloc_Free(alloc, p->blocks);
- p->blocks = blocks;
- p->allocated = newSize;
- return SZ_OK;
-}
-
-
-static SRes XzEncIndex_PreAlloc(CXzEncIndex *p, UInt64 numBlocks, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc)
-{
- UInt64 pos;
- {
- Byte buf[32];
- unsigned pos2 = Xz_WriteVarInt(buf, totalSize);
- pos2 += Xz_WriteVarInt(buf + pos2, unpackSize);
- pos = numBlocks * pos2;
- }
-
- if (pos <= p->allocated - p->size)
- return SZ_OK;
- {
- UInt64 newSize64 = p->size + pos;
- size_t newSize = (size_t)newSize64;
- if (newSize != newSize64)
- return SZ_ERROR_MEM;
- return XzEncIndex_ReAlloc(p, newSize, alloc);
- }
-}
-
-
-static SRes XzEncIndex_AddIndexRecord(CXzEncIndex *p, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc)
-{
- Byte buf[32];
- unsigned pos = Xz_WriteVarInt(buf, totalSize);
- pos += Xz_WriteVarInt(buf + pos, unpackSize);
-
- if (pos > p->allocated - p->size)
- {
- size_t newSize = p->allocated * 2 + 16 * 2;
- if (newSize < p->size + pos)
- return SZ_ERROR_MEM;
- RINOK(XzEncIndex_ReAlloc(p, newSize, alloc));
- }
- memcpy(p->blocks + p->size, buf, pos);
- p->size += pos;
- p->numBlocks++;
- return SZ_OK;
-}
-
-
-static SRes XzEncIndex_WriteFooter(const CXzEncIndex *p, CXzStreamFlags flags, ISeqOutStream *s)
-{
- Byte buf[32];
- UInt64 globalPos;
- UInt32 crc = CRC_INIT_VAL;
- unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks);
-
- globalPos = pos;
- buf[0] = 0;
- RINOK(WriteBytesUpdateCrc(s, buf, pos, &crc));
- RINOK(WriteBytesUpdateCrc(s, p->blocks, p->size, &crc));
- globalPos += p->size;
-
- pos = XZ_GET_PAD_SIZE(globalPos);
- buf[1] = 0;
- buf[2] = 0;
- buf[3] = 0;
- globalPos += pos;
-
- crc = CrcUpdate(crc, buf + 4 - pos, pos);
- SetUi32(buf + 4, CRC_GET_DIGEST(crc));
-
- SetUi32(buf + 8 + 4, (UInt32)(globalPos >> 2));
- buf[8 + 8] = (Byte)(flags >> 8);
- buf[8 + 9] = (Byte)(flags & 0xFF);
- SetUi32(buf + 8, CrcCalc(buf + 8 + 4, 6));
- buf[8 + 10] = XZ_FOOTER_SIG_0;
- buf[8 + 11] = XZ_FOOTER_SIG_1;
-
- return WriteBytes(s, buf + 4 - pos, pos + 4 + 12);
-}
-
-
-
-/* ---------- CSeqCheckInStream ---------- */
-
-typedef struct
-{
- ISeqInStream vt;
- ISeqInStream *realStream;
- const Byte *data;
- UInt64 limit;
- UInt64 processed;
- int realStreamFinished;
- CXzCheck check;
-} CSeqCheckInStream;
-
-static void SeqCheckInStream_Init(CSeqCheckInStream *p, unsigned checkMode)
-{
- p->limit = (UInt64)(Int64)-1;
- p->processed = 0;
- p->realStreamFinished = 0;
- XzCheck_Init(&p->check, checkMode);
-}
-
-static void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest)
-{
- XzCheck_Final(&p->check, digest);
-}
-
-static SRes SeqCheckInStream_Read(const ISeqInStream *pp, void *data, size_t *size)
-{
- CSeqCheckInStream *p = CONTAINER_FROM_VTBL(pp, CSeqCheckInStream, vt);
- size_t size2 = *size;
- SRes res = SZ_OK;
-
- if (p->limit != (UInt64)(Int64)-1)
- {
- UInt64 rem = p->limit - p->processed;
- if (size2 > rem)
- size2 = (size_t)rem;
- }
- if (size2 != 0)
- {
- if (p->realStream)
- {
- res = ISeqInStream_Read(p->realStream, data, &size2);
- p->realStreamFinished = (size2 == 0) ? 1 : 0;
- }
- else
- memcpy(data, p->data + (size_t)p->processed, size2);
- XzCheck_Update(&p->check, data, size2);
- p->processed += size2;
- }
- *size = size2;
- return res;
-}
-
-
-/* ---------- CSeqSizeOutStream ---------- */
-
-typedef struct
-{
- ISeqOutStream vt;
- ISeqOutStream *realStream;
- Byte *outBuf;
- size_t outBufLimit;
- UInt64 processed;
-} CSeqSizeOutStream;
-
-static size_t SeqSizeOutStream_Write(const ISeqOutStream *pp, const void *data, size_t size)
-{
- CSeqSizeOutStream *p = CONTAINER_FROM_VTBL(pp, CSeqSizeOutStream, vt);
- if (p->realStream)
- size = ISeqOutStream_Write(p->realStream, data, size);
- else
- {
- if (size > p->outBufLimit - (size_t)p->processed)
- return 0;
- memcpy(p->outBuf + (size_t)p->processed, data, size);
- }
- p->processed += size;
- return size;
-}
-
-
-/* ---------- CSeqInFilter ---------- */
-
-#define FILTER_BUF_SIZE (1 << 20)
-
-typedef struct
-{
- ISeqInStream p;
- ISeqInStream *realStream;
- IStateCoder StateCoder;
- Byte *buf;
- size_t curPos;
- size_t endPos;
- int srcWasFinished;
-} CSeqInFilter;
-
-
-SRes BraState_SetFromMethod(IStateCoder *p, UInt64 id, int encodeMode, ISzAllocPtr alloc);
-
-static SRes SeqInFilter_Init(CSeqInFilter *p, const CXzFilter *props, ISzAllocPtr alloc)
-{
- if (!p->buf)
- {
- p->buf = (Byte *)ISzAlloc_Alloc(alloc, FILTER_BUF_SIZE);
- if (!p->buf)
- return SZ_ERROR_MEM;
- }
- p->curPos = p->endPos = 0;
- p->srcWasFinished = 0;
- RINOK(BraState_SetFromMethod(&p->StateCoder, props->id, 1, alloc));
- RINOK(p->StateCoder.SetProps(p->StateCoder.p, props->props, props->propsSize, alloc));
- p->StateCoder.Init(p->StateCoder.p);
- return SZ_OK;
-}
-
-
-static SRes SeqInFilter_Read(const ISeqInStream *pp, void *data, size_t *size)
-{
- CSeqInFilter *p = CONTAINER_FROM_VTBL(pp, CSeqInFilter, p);
- size_t sizeOriginal = *size;
- if (sizeOriginal == 0)
- return SZ_OK;
- *size = 0;
-
- for (;;)
- {
- if (!p->srcWasFinished && p->curPos == p->endPos)
- {
- p->curPos = 0;
- p->endPos = FILTER_BUF_SIZE;
- RINOK(ISeqInStream_Read(p->realStream, p->buf, &p->endPos));
- if (p->endPos == 0)
- p->srcWasFinished = 1;
- }
- {
- SizeT srcLen = p->endPos - p->curPos;
- ECoderStatus status;
- SRes res;
- *size = sizeOriginal;
- res = p->StateCoder.Code2(p->StateCoder.p,
- (Byte *)data, size,
- p->buf + p->curPos, &srcLen,
- p->srcWasFinished, CODER_FINISH_ANY,
- &status);
- p->curPos += srcLen;
- if (*size != 0 || srcLen == 0 || res != SZ_OK)
- return res;
- }
- }
-}
-
-static void SeqInFilter_Construct(CSeqInFilter *p)
-{
- p->buf = NULL;
- p->StateCoder.p = NULL;
- p->p.Read = SeqInFilter_Read;
-}
-
-static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc)
-{
- if (p->StateCoder.p)
- {
- p->StateCoder.Free(p->StateCoder.p, alloc);
- p->StateCoder.p = NULL;
- }
- if (p->buf)
- {
- ISzAlloc_Free(alloc, p->buf);
- p->buf = NULL;
- }
-}
-
-
-/* ---------- CSbEncInStream ---------- */
-
-#ifdef USE_SUBBLOCK
-
-typedef struct
-{
- ISeqInStream vt;
- ISeqInStream *inStream;
- CSbEnc enc;
-} CSbEncInStream;
-
-static SRes SbEncInStream_Read(const ISeqInStream *pp, void *data, size_t *size)
-{
- CSbEncInStream *p = CONTAINER_FROM_VTBL(pp, CSbEncInStream, vt);
- size_t sizeOriginal = *size;
- if (sizeOriginal == 0)
- return SZ_OK;
-
- for (;;)
- {
- if (p->enc.needRead && !p->enc.readWasFinished)
- {
- size_t processed = p->enc.needReadSizeMax;
- RINOK(p->inStream->Read(p->inStream, p->enc.buf + p->enc.readPos, &processed));
- p->enc.readPos += processed;
- if (processed == 0)
- {
- p->enc.readWasFinished = True;
- p->enc.isFinalFinished = True;
- }
- p->enc.needRead = False;
- }
-
- *size = sizeOriginal;
- RINOK(SbEnc_Read(&p->enc, data, size));
- if (*size != 0 || !p->enc.needRead)
- return SZ_OK;
- }
-}
-
-void SbEncInStream_Construct(CSbEncInStream *p, ISzAllocPtr alloc)
-{
- SbEnc_Construct(&p->enc, alloc);
- p->vt.Read = SbEncInStream_Read;
-}
-
-SRes SbEncInStream_Init(CSbEncInStream *p)
-{
- return SbEnc_Init(&p->enc);
-}
-
-void SbEncInStream_Free(CSbEncInStream *p)
-{
- SbEnc_Free(&p->enc);
-}
-
-#endif
-
-
-
-/* ---------- CXzProps ---------- */
-
-
-void XzFilterProps_Init(CXzFilterProps *p)
-{
- p->id = 0;
- p->delta = 0;
- p->ip = 0;
- p->ipDefined = False;
-}
-
-void XzProps_Init(CXzProps *p)
-{
- p->checkId = XZ_CHECK_CRC32;
- p->blockSize = XZ_PROPS__BLOCK_SIZE__AUTO;
- p->numBlockThreads_Reduced = -1;
- p->numBlockThreads_Max = -1;
- p->numTotalThreads = -1;
- p->reduceSize = (UInt64)(Int64)-1;
- p->forceWriteSizesInHeader = 0;
- // p->forceWriteSizesInHeader = 1;
-
- XzFilterProps_Init(&p->filterProps);
- Lzma2EncProps_Init(&p->lzma2Props);
-}
-
-
-static void XzEncProps_Normalize_Fixed(CXzProps *p)
-{
- UInt64 fileSize;
- int t1, t1n, t2, t2r, t3;
- {
- CLzma2EncProps tp = p->lzma2Props;
- if (tp.numTotalThreads <= 0)
- tp.numTotalThreads = p->numTotalThreads;
- Lzma2EncProps_Normalize(&tp);
- t1n = tp.numTotalThreads;
- }
-
- t1 = p->lzma2Props.numTotalThreads;
- t2 = p->numBlockThreads_Max;
- t3 = p->numTotalThreads;
-
- if (t2 > MTCODER__THREADS_MAX)
- t2 = MTCODER__THREADS_MAX;
-
- if (t3 <= 0)
- {
- if (t2 <= 0)
- t2 = 1;
- t3 = t1n * t2;
- }
- else if (t2 <= 0)
- {
- t2 = t3 / t1n;
- if (t2 == 0)
- {
- t1 = 1;
- t2 = t3;
- }
- if (t2 > MTCODER__THREADS_MAX)
- t2 = MTCODER__THREADS_MAX;
- }
- else if (t1 <= 0)
- {
- t1 = t3 / t2;
- if (t1 == 0)
- t1 = 1;
- }
- else
- t3 = t1n * t2;
-
- p->lzma2Props.numTotalThreads = t1;
-
- t2r = t2;
-
- fileSize = p->reduceSize;
-
- if ((p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1))
- p->lzma2Props.lzmaProps.reduceSize = p->blockSize;
-
- Lzma2EncProps_Normalize(&p->lzma2Props);
-
- t1 = p->lzma2Props.numTotalThreads;
-
- {
- if (t2 > 1 && fileSize != (UInt64)(Int64)-1)
- {
- UInt64 numBlocks = fileSize / p->blockSize;
- if (numBlocks * p->blockSize != fileSize)
- numBlocks++;
- if (numBlocks < (unsigned)t2)
- {
- t2r = (unsigned)numBlocks;
- if (t2r == 0)
- t2r = 1;
- t3 = t1 * t2r;
- }
- }
- }
-
- p->numBlockThreads_Max = t2;
- p->numBlockThreads_Reduced = t2r;
- p->numTotalThreads = t3;
-}
-
-
-static void XzProps_Normalize(CXzProps *p)
-{
- /* we normalize xzProps properties, but we normalize only some of CXzProps::lzma2Props properties.
- Lzma2Enc_SetProps() will normalize lzma2Props later. */
-
- if (p->blockSize == XZ_PROPS__BLOCK_SIZE__SOLID)
- {
- p->lzma2Props.lzmaProps.reduceSize = p->reduceSize;
- p->numBlockThreads_Reduced = 1;
- p->numBlockThreads_Max = 1;
- if (p->lzma2Props.numTotalThreads <= 0)
- p->lzma2Props.numTotalThreads = p->numTotalThreads;
- return;
- }
- else
- {
- CLzma2EncProps *lzma2 = &p->lzma2Props;
- if (p->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO)
- {
- // xz-auto
- p->lzma2Props.lzmaProps.reduceSize = p->reduceSize;
-
- if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID)
- {
- // if (xz-auto && lzma2-solid) - we use solid for both
- p->blockSize = XZ_PROPS__BLOCK_SIZE__SOLID;
- p->numBlockThreads_Reduced = 1;
- p->numBlockThreads_Max = 1;
- if (p->lzma2Props.numTotalThreads <= 0)
- p->lzma2Props.numTotalThreads = p->numTotalThreads;
- }
- else
- {
- // if (xz-auto && (lzma2-auto || lzma2-fixed_)
- // we calculate block size for lzma2 and use that block size for xz, lzma2 uses single-chunk per block
- CLzma2EncProps tp = p->lzma2Props;
- if (tp.numTotalThreads <= 0)
- tp.numTotalThreads = p->numTotalThreads;
-
- Lzma2EncProps_Normalize(&tp);
-
- p->blockSize = tp.blockSize; // fixed or solid
- p->numBlockThreads_Reduced = tp.numBlockThreads_Reduced;
- p->numBlockThreads_Max = tp.numBlockThreads_Max;
- if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO)
- lzma2->blockSize = tp.blockSize; // fixed or solid, LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID
- if (lzma2->lzmaProps.reduceSize > tp.blockSize && tp.blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID)
- lzma2->lzmaProps.reduceSize = tp.blockSize;
- lzma2->numBlockThreads_Reduced = 1;
- lzma2->numBlockThreads_Max = 1;
- return;
- }
- }
- else
- {
- // xz-fixed
- // we can use xz::reduceSize or xz::blockSize as base for lzmaProps::reduceSize
-
- p->lzma2Props.lzmaProps.reduceSize = p->reduceSize;
- {
- UInt64 r = p->reduceSize;
- if (r > p->blockSize || r == (UInt64)(Int64)-1)
- r = p->blockSize;
- lzma2->lzmaProps.reduceSize = r;
- }
- if (lzma2->blockSize == LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO)
- lzma2->blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID;
- else if (lzma2->blockSize > p->blockSize && lzma2->blockSize != LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID)
- lzma2->blockSize = p->blockSize;
-
- XzEncProps_Normalize_Fixed(p);
- }
- }
-}
-
-
-/* ---------- CLzma2WithFilters ---------- */
-
-typedef struct
-{
- CLzma2EncHandle lzma2;
- CSeqInFilter filter;
-
- #ifdef USE_SUBBLOCK
- CSbEncInStream sb;
- #endif
-} CLzma2WithFilters;
-
-
-static void Lzma2WithFilters_Construct(CLzma2WithFilters *p)
-{
- p->lzma2 = NULL;
- SeqInFilter_Construct(&p->filter);
-
- #ifdef USE_SUBBLOCK
- SbEncInStream_Construct(&p->sb, alloc);
- #endif
-}
-
-
-static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p, ISzAllocPtr alloc, ISzAllocPtr bigAlloc)
-{
- if (!p->lzma2)
- {
- p->lzma2 = Lzma2Enc_Create(alloc, bigAlloc);
- if (!p->lzma2)
- return SZ_ERROR_MEM;
- }
- return SZ_OK;
-}
-
-
-static void Lzma2WithFilters_Free(CLzma2WithFilters *p, ISzAllocPtr alloc)
-{
- #ifdef USE_SUBBLOCK
- SbEncInStream_Free(&p->sb);
- #endif
-
- SeqInFilter_Free(&p->filter, alloc);
- if (p->lzma2)
- {
- Lzma2Enc_Destroy(p->lzma2);
- p->lzma2 = NULL;
- }
-}
-
-
-typedef struct
-{
- UInt64 unpackSize;
- UInt64 totalSize;
- size_t headerSize;
-} CXzEncBlockInfo;
-
-
-static SRes Xz_CompressBlock(
- CLzma2WithFilters *lzmaf,
-
- ISeqOutStream *outStream,
- Byte *outBufHeader,
- Byte *outBufData, size_t outBufDataLimit,
-
- ISeqInStream *inStream,
- // UInt64 expectedSize,
- const Byte *inBuf, // used if (!inStream)
- size_t inBufSize, // used if (!inStream), it's block size, props->blockSize is ignored
-
- const CXzProps *props,
- ICompressProgress *progress,
- int *inStreamFinished, /* only for inStream version */
- CXzEncBlockInfo *blockSizes,
- ISzAllocPtr alloc,
- ISzAllocPtr allocBig)
-{
- CSeqCheckInStream checkInStream;
- CSeqSizeOutStream seqSizeOutStream;
- CXzBlock block;
- unsigned filterIndex = 0;
- CXzFilter *filter = NULL;
- const CXzFilterProps *fp = &props->filterProps;
- if (fp->id == 0)
- fp = NULL;
-
- *inStreamFinished = False;
-
- RINOK(Lzma2WithFilters_Create(lzmaf, alloc, allocBig));
-
- RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, &props->lzma2Props));
-
- XzBlock_ClearFlags(&block);
- XzBlock_SetNumFilters(&block, 1 + (fp ? 1 : 0));
-
- if (fp)
- {
- filter = &block.filters[filterIndex++];
- filter->id = fp->id;
- filter->propsSize = 0;
-
- if (fp->id == XZ_ID_Delta)
- {
- filter->props[0] = (Byte)(fp->delta - 1);
- filter->propsSize = 1;
- }
- else if (fp->ipDefined)
- {
- SetUi32(filter->props, fp->ip);
- filter->propsSize = 4;
- }
- }
-
- {
- CXzFilter *f = &block.filters[filterIndex++];
- f->id = XZ_ID_LZMA2;
- f->propsSize = 1;
- f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2);
- }
-
- seqSizeOutStream.vt.Write = SeqSizeOutStream_Write;
- seqSizeOutStream.realStream = outStream;
- seqSizeOutStream.outBuf = outBufData;
- seqSizeOutStream.outBufLimit = outBufDataLimit;
- seqSizeOutStream.processed = 0;
-
- /*
- if (expectedSize != (UInt64)(Int64)-1)
- {
- block.unpackSize = expectedSize;
- if (props->blockSize != (UInt64)(Int64)-1)
- if (expectedSize > props->blockSize)
- block.unpackSize = props->blockSize;
- XzBlock_SetHasUnpackSize(&block);
- }
- */
-
- if (outStream)
- {
- RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt));
- }
-
- checkInStream.vt.Read = SeqCheckInStream_Read;
- SeqCheckInStream_Init(&checkInStream, props->checkId);
-
- checkInStream.realStream = inStream;
- checkInStream.data = inBuf;
- checkInStream.limit = props->blockSize;
- if (!inStream)
- checkInStream.limit = inBufSize;
-
- if (fp)
- {
- #ifdef USE_SUBBLOCK
- if (fp->id == XZ_ID_Subblock)
- {
- lzmaf->sb.inStream = &checkInStream.vt;
- RINOK(SbEncInStream_Init(&lzmaf->sb));
- }
- else
- #endif
- {
- lzmaf->filter.realStream = &checkInStream.vt;
- RINOK(SeqInFilter_Init(&lzmaf->filter, filter, alloc));
- }
- }
-
- {
- SRes res;
- Byte *outBuf = NULL;
- size_t outSize = 0;
- BoolInt useStream = (fp || inStream);
- // useStream = True;
-
- if (!useStream)
- {
- XzCheck_Update(&checkInStream.check, inBuf, inBufSize);
- checkInStream.processed = inBufSize;
- }
-
- if (!outStream)
- {
- outBuf = seqSizeOutStream.outBuf; // + (size_t)seqSizeOutStream.processed;
- outSize = seqSizeOutStream.outBufLimit; // - (size_t)seqSizeOutStream.processed;
- }
-
- res = Lzma2Enc_Encode2(lzmaf->lzma2,
- outBuf ? NULL : &seqSizeOutStream.vt,
- outBuf,
- outBuf ? &outSize : NULL,
-
- useStream ?
- (fp ?
- (
- #ifdef USE_SUBBLOCK
- (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.vt:
- #endif
- &lzmaf->filter.p) :
- &checkInStream.vt) : NULL,
-
- useStream ? NULL : inBuf,
- useStream ? 0 : inBufSize,
-
- progress);
-
- if (outBuf)
- seqSizeOutStream.processed += outSize;
-
- RINOK(res);
- blockSizes->unpackSize = checkInStream.processed;
- }
- {
- Byte buf[4 + 64];
- unsigned padSize = XZ_GET_PAD_SIZE(seqSizeOutStream.processed);
- UInt64 packSize = seqSizeOutStream.processed;
-
- buf[0] = 0;
- buf[1] = 0;
- buf[2] = 0;
- buf[3] = 0;
-
- SeqCheckInStream_GetDigest(&checkInStream, buf + 4);
- RINOK(WriteBytes(&seqSizeOutStream.vt, buf + (4 - padSize), padSize + XzFlags_GetCheckSize((CXzStreamFlags)props->checkId)));
-
- blockSizes->totalSize = seqSizeOutStream.processed - padSize;
-
- if (!outStream)
- {
- seqSizeOutStream.outBuf = outBufHeader;
- seqSizeOutStream.outBufLimit = XZ_BLOCK_HEADER_SIZE_MAX;
- seqSizeOutStream.processed = 0;
-
- block.unpackSize = blockSizes->unpackSize;
- XzBlock_SetHasUnpackSize(&block);
-
- block.packSize = packSize;
- XzBlock_SetHasPackSize(&block);
-
- RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt));
-
- blockSizes->headerSize = (size_t)seqSizeOutStream.processed;
- blockSizes->totalSize += seqSizeOutStream.processed;
- }
- }
-
- if (inStream)
- *inStreamFinished = checkInStream.realStreamFinished;
- else
- {
- *inStreamFinished = False;
- if (checkInStream.processed != inBufSize)
- return SZ_ERROR_FAIL;
- }
-
- return SZ_OK;
-}
-
-
-
-typedef struct
-{
- ICompressProgress vt;
- ICompressProgress *progress;
- UInt64 inOffset;
- UInt64 outOffset;
-} CCompressProgress_XzEncOffset;
-
-
-static SRes CompressProgress_XzEncOffset_Progress(const ICompressProgress *pp, UInt64 inSize, UInt64 outSize)
-{
- const CCompressProgress_XzEncOffset *p = CONTAINER_FROM_VTBL(pp, CCompressProgress_XzEncOffset, vt);
- inSize += p->inOffset;
- outSize += p->outOffset;
- return ICompressProgress_Progress(p->progress, inSize, outSize);
-}
-
-
-
-
-typedef struct
-{
- ISzAllocPtr alloc;
- ISzAllocPtr allocBig;
-
- CXzProps xzProps;
- UInt64 expectedDataSize;
-
- CXzEncIndex xzIndex;
-
- CLzma2WithFilters lzmaf_Items[MTCODER__THREADS_MAX];
-
- size_t outBufSize; /* size of allocated outBufs[i] */
- Byte *outBufs[MTCODER__BLOCKS_MAX];
-
- #ifndef _7ZIP_ST
- unsigned checkType;
- ISeqOutStream *outStream;
- BoolInt mtCoder_WasConstructed;
- CMtCoder mtCoder;
- CXzEncBlockInfo EncBlocks[MTCODER__BLOCKS_MAX];
- #endif
-
-} CXzEnc;
-
-
-static void XzEnc_Construct(CXzEnc *p)
-{
- unsigned i;
-
- XzEncIndex_Construct(&p->xzIndex);
-
- for (i = 0; i < MTCODER__THREADS_MAX; i++)
- Lzma2WithFilters_Construct(&p->lzmaf_Items[i]);
-
- #ifndef _7ZIP_ST
- p->mtCoder_WasConstructed = False;
- {
- for (i = 0; i < MTCODER__BLOCKS_MAX; i++)
- p->outBufs[i] = NULL;
- p->outBufSize = 0;
- }
- #endif
-}
-
-
-static void XzEnc_FreeOutBufs(CXzEnc *p)
-{
- unsigned i;
- for (i = 0; i < MTCODER__BLOCKS_MAX; i++)
- if (p->outBufs[i])
- {
- ISzAlloc_Free(p->alloc, p->outBufs[i]);
- p->outBufs[i] = NULL;
- }
- p->outBufSize = 0;
-}
-
-
-static void XzEnc_Free(CXzEnc *p, ISzAllocPtr alloc)
-{
- unsigned i;
-
- XzEncIndex_Free(&p->xzIndex, alloc);
-
- for (i = 0; i < MTCODER__THREADS_MAX; i++)
- Lzma2WithFilters_Free(&p->lzmaf_Items[i], alloc);
-
- #ifndef _7ZIP_ST
- if (p->mtCoder_WasConstructed)
- {
- MtCoder_Destruct(&p->mtCoder);
- p->mtCoder_WasConstructed = False;
- }
- XzEnc_FreeOutBufs(p);
- #endif
-}
-
-
-CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig)
-{
- CXzEnc *p = (CXzEnc *)ISzAlloc_Alloc(alloc, sizeof(CXzEnc));
- if (!p)
- return NULL;
- XzEnc_Construct(p);
- XzProps_Init(&p->xzProps);
- XzProps_Normalize(&p->xzProps);
- p->expectedDataSize = (UInt64)(Int64)-1;
- p->alloc = alloc;
- p->allocBig = allocBig;
- return p;
-}
-
-
-void XzEnc_Destroy(CXzEncHandle pp)
-{
- CXzEnc *p = (CXzEnc *)pp;
- XzEnc_Free(p, p->alloc);
- ISzAlloc_Free(p->alloc, p);
-}
-
-
-SRes XzEnc_SetProps(CXzEncHandle pp, const CXzProps *props)
-{
- CXzEnc *p = (CXzEnc *)pp;
- p->xzProps = *props;
- XzProps_Normalize(&p->xzProps);
- return SZ_OK;
-}
-
-
-void XzEnc_SetDataSize(CXzEncHandle pp, UInt64 expectedDataSiize)
-{
- CXzEnc *p = (CXzEnc *)pp;
- p->expectedDataSize = expectedDataSiize;
-}
-
-
-
-
-#ifndef _7ZIP_ST
-
-static SRes XzEnc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex,
- const Byte *src, size_t srcSize, int finished)
-{
- CXzEnc *me = (CXzEnc *)pp;
- SRes res;
- CMtProgressThunk progressThunk;
-
- Byte *dest = me->outBufs[outBufIndex];
-
- UNUSED_VAR(finished)
-
- {
- CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex];
- bInfo->totalSize = 0;
- bInfo->unpackSize = 0;
- bInfo->headerSize = 0;
- }
-
- if (!dest)
- {
- dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize);
- if (!dest)
- return SZ_ERROR_MEM;
- me->outBufs[outBufIndex] = dest;
- }
-
- MtProgressThunk_CreateVTable(&progressThunk);
- progressThunk.mtProgress = &me->mtCoder.mtProgress;
- MtProgressThunk_Init(&progressThunk);
-
- {
- CXzEncBlockInfo blockSizes;
- int inStreamFinished;
-
- res = Xz_CompressBlock(
- &me->lzmaf_Items[coderIndex],
-
- NULL,
- dest,
- dest + XZ_BLOCK_HEADER_SIZE_MAX, me->outBufSize - XZ_BLOCK_HEADER_SIZE_MAX,
-
- NULL,
- // srcSize, // expectedSize
- src, srcSize,
-
- &me->xzProps,
- &progressThunk.vt,
- &inStreamFinished,
- &blockSizes,
- me->alloc,
- me->allocBig);
-
- if (res == SZ_OK)
- me->EncBlocks[outBufIndex] = blockSizes;
-
- return res;
- }
-}
-
-
-static SRes XzEnc_MtCallback_Write(void *pp, unsigned outBufIndex)
-{
- CXzEnc *me = (CXzEnc *)pp;
-
- const CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex];
- const Byte *data = me->outBufs[outBufIndex];
-
- RINOK(WriteBytes(me->outStream, data, bInfo->headerSize));
-
- {
- UInt64 totalPackFull = bInfo->totalSize + XZ_GET_PAD_SIZE(bInfo->totalSize);
- RINOK(WriteBytes(me->outStream, data + XZ_BLOCK_HEADER_SIZE_MAX, (size_t)totalPackFull - bInfo->headerSize));
- }
-
- return XzEncIndex_AddIndexRecord(&me->xzIndex, bInfo->unpackSize, bInfo->totalSize, me->alloc);
-}
-
-#endif
-
-
-
-SRes XzEnc_Encode(CXzEncHandle pp, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress)
-{
- CXzEnc *p = (CXzEnc *)pp;
-
- const CXzProps *props = &p->xzProps;
-
- XzEncIndex_Init(&p->xzIndex);
- {
- UInt64 numBlocks = 1;
- UInt64 blockSize = props->blockSize;
-
- if (blockSize != XZ_PROPS__BLOCK_SIZE__SOLID
- && props->reduceSize != (UInt64)(Int64)-1)
- {
- numBlocks = props->reduceSize / blockSize;
- if (numBlocks * blockSize != props->reduceSize)
- numBlocks++;
- }
- else
- blockSize = (UInt64)1 << 62;
-
- RINOK(XzEncIndex_PreAlloc(&p->xzIndex, numBlocks, blockSize, XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(blockSize), p->alloc));
- }
-
- RINOK(Xz_WriteHeader((CXzStreamFlags)props->checkId, outStream));
-
-
- #ifndef _7ZIP_ST
- if (props->numBlockThreads_Reduced > 1)
- {
- IMtCoderCallback2 vt;
-
- if (!p->mtCoder_WasConstructed)
- {
- p->mtCoder_WasConstructed = True;
- MtCoder_Construct(&p->mtCoder);
- }
-
- vt.Code = XzEnc_MtCallback_Code;
- vt.Write = XzEnc_MtCallback_Write;
-
- p->checkType = props->checkId;
- p->xzProps = *props;
-
- p->outStream = outStream;
-
- p->mtCoder.allocBig = p->allocBig;
- p->mtCoder.progress = progress;
- p->mtCoder.inStream = inStream;
- p->mtCoder.inData = NULL;
- p->mtCoder.inDataSize = 0;
- p->mtCoder.mtCallback = &vt;
- p->mtCoder.mtCallbackObject = p;
-
- if ( props->blockSize == XZ_PROPS__BLOCK_SIZE__SOLID
- || props->blockSize == XZ_PROPS__BLOCK_SIZE__AUTO)
- return SZ_ERROR_FAIL;
-
- p->mtCoder.blockSize = (size_t)props->blockSize;
- if (p->mtCoder.blockSize != props->blockSize)
- return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */
-
- {
- size_t destBlockSize = XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(p->mtCoder.blockSize);
- if (destBlockSize < p->mtCoder.blockSize)
- return SZ_ERROR_PARAM;
- if (p->outBufSize != destBlockSize)
- XzEnc_FreeOutBufs(p);
- p->outBufSize = destBlockSize;
- }
-
- p->mtCoder.numThreadsMax = props->numBlockThreads_Max;
- p->mtCoder.expectedDataSize = p->expectedDataSize;
-
- RINOK(MtCoder_Code(&p->mtCoder));
- }
- else
- #endif
- {
- int writeStartSizes;
- CCompressProgress_XzEncOffset progress2;
- Byte *bufData = NULL;
- size_t bufSize = 0;
-
- progress2.vt.Progress = CompressProgress_XzEncOffset_Progress;
- progress2.inOffset = 0;
- progress2.outOffset = 0;
- progress2.progress = progress;
-
- writeStartSizes = 0;
-
- if (props->blockSize != XZ_PROPS__BLOCK_SIZE__SOLID)
- {
- writeStartSizes = (props->forceWriteSizesInHeader > 0);
-
- if (writeStartSizes)
- {
- size_t t2;
- size_t t = (size_t)props->blockSize;
- if (t != props->blockSize)
- return SZ_ERROR_PARAM;
- t = XZ_GET_MAX_BLOCK_PACK_SIZE(t);
- if (t < props->blockSize)
- return SZ_ERROR_PARAM;
- t2 = XZ_BLOCK_HEADER_SIZE_MAX + t;
- if (!p->outBufs[0] || t2 != p->outBufSize)
- {
- XzEnc_FreeOutBufs(p);
- p->outBufs[0] = (Byte *)ISzAlloc_Alloc(p->alloc, t2);
- if (!p->outBufs[0])
- return SZ_ERROR_MEM;
- p->outBufSize = t2;
- }
- bufData = p->outBufs[0] + XZ_BLOCK_HEADER_SIZE_MAX;
- bufSize = t;
- }
- }
-
- for (;;)
- {
- CXzEncBlockInfo blockSizes;
- int inStreamFinished;
-
- /*
- UInt64 rem = (UInt64)(Int64)-1;
- if (props->reduceSize != (UInt64)(Int64)-1
- && props->reduceSize >= progress2.inOffset)
- rem = props->reduceSize - progress2.inOffset;
- */
-
- blockSizes.headerSize = 0; // for GCC
-
- RINOK(Xz_CompressBlock(
- &p->lzmaf_Items[0],
-
- writeStartSizes ? NULL : outStream,
- writeStartSizes ? p->outBufs[0] : NULL,
- bufData, bufSize,
-
- inStream,
- // rem,
- NULL, 0,
-
- props,
- progress ? &progress2.vt : NULL,
- &inStreamFinished,
- &blockSizes,
- p->alloc,
- p->allocBig));
-
- {
- UInt64 totalPackFull = blockSizes.totalSize + XZ_GET_PAD_SIZE(blockSizes.totalSize);
-
- if (writeStartSizes)
- {
- RINOK(WriteBytes(outStream, p->outBufs[0], blockSizes.headerSize));
- RINOK(WriteBytes(outStream, bufData, (size_t)totalPackFull - blockSizes.headerSize));
- }
-
- RINOK(XzEncIndex_AddIndexRecord(&p->xzIndex, blockSizes.unpackSize, blockSizes.totalSize, p->alloc));
-
- progress2.inOffset += blockSizes.unpackSize;
- progress2.outOffset += totalPackFull;
- }
-
- if (inStreamFinished)
- break;
- }
- }
-
- return XzEncIndex_WriteFooter(&p->xzIndex, (CXzStreamFlags)props->checkId, outStream);
-}
-
-
-#include "Alloc.h"
-
-SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream,
- const CXzProps *props, ICompressProgress *progress)
-{
- SRes res;
- CXzEncHandle xz = XzEnc_Create(&g_Alloc, &g_BigAlloc);
- if (!xz)
- return SZ_ERROR_MEM;
- res = XzEnc_SetProps(xz, props);
- if (res == SZ_OK)
- res = XzEnc_Encode(xz, outStream, inStream, progress);
- XzEnc_Destroy(xz);
- return res;
-}
-
-
-SRes Xz_EncodeEmpty(ISeqOutStream *outStream)
-{
- SRes res;
- CXzEncIndex xzIndex;
- XzEncIndex_Construct(&xzIndex);
- res = Xz_WriteHeader((CXzStreamFlags)0, outStream);
- if (res == SZ_OK)
- res = XzEncIndex_WriteFooter(&xzIndex, (CXzStreamFlags)0, outStream);
- XzEncIndex_Free(&xzIndex, NULL); // g_Alloc
- return res;
-}
+/* XzEnc.c -- Xz Encode
+2023-04-13 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "7zCrc.h"
+#include "Bra.h"
+#include "CpuArch.h"
+
+#ifdef USE_SUBBLOCK
+#include "Bcj3Enc.c"
+#include "SbFind.c"
+#include "SbEnc.c"
+#endif
+
+#include "XzEnc.h"
+
+// #define Z7_ST
+
+#ifndef Z7_ST
+#include "MtCoder.h"
+#else
+#define MTCODER_THREADS_MAX 1
+#define MTCODER_BLOCKS_MAX 1
+#endif
+
+#define XZ_GET_PAD_SIZE(dataSize) ((4 - ((unsigned)(dataSize) & 3)) & 3)
+
+/* max pack size for LZMA2 block + check-64bytrs: */
+#define XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize) ((unpackSize) + ((unpackSize) >> 10) + 16 + 64)
+
+#define XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(unpackSize) (XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(unpackSize))
+
+
+// #define XzBlock_ClearFlags(p) (p)->flags = 0;
+#define XzBlock_ClearFlags_SetNumFilters(p, n) (p)->flags = (Byte)((n) - 1);
+#define XzBlock_SetHasPackSize(p) (p)->flags |= XZ_BF_PACK_SIZE;
+#define XzBlock_SetHasUnpackSize(p) (p)->flags |= XZ_BF_UNPACK_SIZE;
+
+
+static SRes WriteBytes(ISeqOutStreamPtr s, const void *buf, size_t size)
+{
+ return (ISeqOutStream_Write(s, buf, size) == size) ? SZ_OK : SZ_ERROR_WRITE;
+}
+
+static SRes WriteBytes_UpdateCrc(ISeqOutStreamPtr s, const void *buf, size_t size, UInt32 *crc)
+{
+ *crc = CrcUpdate(*crc, buf, size);
+ return WriteBytes(s, buf, size);
+}
+
+
+static SRes Xz_WriteHeader(CXzStreamFlags f, ISeqOutStreamPtr s)
+{
+ UInt32 crc;
+ Byte header[XZ_STREAM_HEADER_SIZE];
+ memcpy(header, XZ_SIG, XZ_SIG_SIZE);
+ header[XZ_SIG_SIZE] = (Byte)(f >> 8);
+ header[XZ_SIG_SIZE + 1] = (Byte)(f & 0xFF);
+ crc = CrcCalc(header + XZ_SIG_SIZE, XZ_STREAM_FLAGS_SIZE);
+ SetUi32(header + XZ_SIG_SIZE + XZ_STREAM_FLAGS_SIZE, crc)
+ return WriteBytes(s, header, XZ_STREAM_HEADER_SIZE);
+}
+
+
+static SRes XzBlock_WriteHeader(const CXzBlock *p, ISeqOutStreamPtr s)
+{
+ Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
+
+ unsigned pos = 1;
+ unsigned numFilters, i;
+ header[pos++] = p->flags;
+
+ if (XzBlock_HasPackSize(p)) pos += Xz_WriteVarInt(header + pos, p->packSize);
+ if (XzBlock_HasUnpackSize(p)) pos += Xz_WriteVarInt(header + pos, p->unpackSize);
+ numFilters = XzBlock_GetNumFilters(p);
+
+ for (i = 0; i < numFilters; i++)
+ {
+ const CXzFilter *f = &p->filters[i];
+ pos += Xz_WriteVarInt(header + pos, f->id);
+ pos += Xz_WriteVarInt(header + pos, f->propsSize);
+ memcpy(header + pos, f->props, f->propsSize);
+ pos += f->propsSize;
+ }
+
+ while ((pos & 3) != 0)
+ header[pos++] = 0;
+
+ header[0] = (Byte)(pos >> 2);
+ SetUi32(header + pos, CrcCalc(header, pos))
+ return WriteBytes(s, header, pos + 4);
+}
+
+
+
+
+typedef struct
+{
+ size_t numBlocks;
+ size_t size;
+ size_t allocated;
+ Byte *blocks;
+} CXzEncIndex;
+
+
+static void XzEncIndex_Construct(CXzEncIndex *p)
+{
+ p->numBlocks = 0;
+ p->size = 0;
+ p->allocated = 0;
+ p->blocks = NULL;
+}
+
+static void XzEncIndex_Init(CXzEncIndex *p)
+{
+ p->numBlocks = 0;
+ p->size = 0;
+}
+
+static void XzEncIndex_Free(CXzEncIndex *p, ISzAllocPtr alloc)
+{
+ if (p->blocks)
+ {
+ ISzAlloc_Free(alloc, p->blocks);
+ p->blocks = NULL;
+ }
+ p->numBlocks = 0;
+ p->size = 0;
+ p->allocated = 0;
+}
+
+
+static SRes XzEncIndex_ReAlloc(CXzEncIndex *p, size_t newSize, ISzAllocPtr alloc)
+{
+ Byte *blocks = (Byte *)ISzAlloc_Alloc(alloc, newSize);
+ if (!blocks)
+ return SZ_ERROR_MEM;
+ if (p->size != 0)
+ memcpy(blocks, p->blocks, p->size);
+ if (p->blocks)
+ ISzAlloc_Free(alloc, p->blocks);
+ p->blocks = blocks;
+ p->allocated = newSize;
+ return SZ_OK;
+}
+
+
+static SRes XzEncIndex_PreAlloc(CXzEncIndex *p, UInt64 numBlocks, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc)
+{
+ UInt64 pos;
+ {
+ Byte buf[32];
+ unsigned pos2 = Xz_WriteVarInt(buf, totalSize);
+ pos2 += Xz_WriteVarInt(buf + pos2, unpackSize);
+ pos = numBlocks * pos2;
+ }
+
+ if (pos <= p->allocated - p->size)
+ return SZ_OK;
+ {
+ UInt64 newSize64 = p->size + pos;
+ size_t newSize = (size_t)newSize64;
+ if (newSize != newSize64)
+ return SZ_ERROR_MEM;
+ return XzEncIndex_ReAlloc(p, newSize, alloc);
+ }
+}
+
+
+static SRes XzEncIndex_AddIndexRecord(CXzEncIndex *p, UInt64 unpackSize, UInt64 totalSize, ISzAllocPtr alloc)
+{
+ Byte buf[32];
+ unsigned pos = Xz_WriteVarInt(buf, totalSize);
+ pos += Xz_WriteVarInt(buf + pos, unpackSize);
+
+ if (pos > p->allocated - p->size)
+ {
+ size_t newSize = p->allocated * 2 + 16 * 2;
+ if (newSize < p->size + pos)
+ return SZ_ERROR_MEM;
+ RINOK(XzEncIndex_ReAlloc(p, newSize, alloc))
+ }
+ memcpy(p->blocks + p->size, buf, pos);
+ p->size += pos;
+ p->numBlocks++;
+ return SZ_OK;
+}
+
+
+static SRes XzEncIndex_WriteFooter(const CXzEncIndex *p, CXzStreamFlags flags, ISeqOutStreamPtr s)
+{
+ Byte buf[32];
+ UInt64 globalPos;
+ UInt32 crc = CRC_INIT_VAL;
+ unsigned pos = 1 + Xz_WriteVarInt(buf + 1, p->numBlocks);
+
+ globalPos = pos;
+ buf[0] = 0;
+ RINOK(WriteBytes_UpdateCrc(s, buf, pos, &crc))
+ RINOK(WriteBytes_UpdateCrc(s, p->blocks, p->size, &crc))
+ globalPos += p->size;
+
+ pos = XZ_GET_PAD_SIZE(globalPos);
+ buf[1] = 0;
+ buf[2] = 0;
+ buf[3] = 0;
+ globalPos += pos;
+
+ crc = CrcUpdate(crc, buf + 4 - pos, pos);
+ SetUi32(buf + 4, CRC_GET_DIGEST(crc))
+
+ SetUi32(buf + 8 + 4, (UInt32)(globalPos >> 2))
+ buf[8 + 8] = (Byte)(flags >> 8);
+ buf[8 + 9] = (Byte)(flags & 0xFF);
+ SetUi32(buf + 8, CrcCalc(buf + 8 + 4, 6))
+ buf[8 + 10] = XZ_FOOTER_SIG_0;
+ buf[8 + 11] = XZ_FOOTER_SIG_1;
+
+ return WriteBytes(s, buf + 4 - pos, pos + 4 + 12);
+}
+
+
+
+/* ---------- CSeqCheckInStream ---------- */
+
+typedef struct
+{
+ ISeqInStream vt;
+ ISeqInStreamPtr realStream;
+ const Byte *data;
+ UInt64 limit;
+ UInt64 processed;
+ int realStreamFinished;
+ CXzCheck check;
+} CSeqCheckInStream;
+
+static void SeqCheckInStream_Init(CSeqCheckInStream *p, unsigned checkMode)
+{
+ p->limit = (UInt64)(Int64)-1;
+ p->processed = 0;
+ p->realStreamFinished = 0;
+ XzCheck_Init(&p->check, checkMode);
+}
+
+static void SeqCheckInStream_GetDigest(CSeqCheckInStream *p, Byte *digest)
+{
+ XzCheck_Final(&p->check, digest);
+}
+
+static SRes SeqCheckInStream_Read(ISeqInStreamPtr pp, void *data, size_t *size)
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqCheckInStream)
+ size_t size2 = *size;
+ SRes res = SZ_OK;
+
+ if (p->limit != (UInt64)(Int64)-1)
+ {
+ UInt64 rem = p->limit - p->processed;
+ if (size2 > rem)
+ size2 = (size_t)rem;
+ }
+ if (size2 != 0)
+ {
+ if (p->realStream)
+ {
+ res = ISeqInStream_Read(p->realStream, data, &size2);
+ p->realStreamFinished = (size2 == 0) ? 1 : 0;
+ }
+ else
+ memcpy(data, p->data + (size_t)p->processed, size2);
+ XzCheck_Update(&p->check, data, size2);
+ p->processed += size2;
+ }
+ *size = size2;
+ return res;
+}
+
+
+/* ---------- CSeqSizeOutStream ---------- */
+
+typedef struct
+{
+ ISeqOutStream vt;
+ ISeqOutStreamPtr realStream;
+ Byte *outBuf;
+ size_t outBufLimit;
+ UInt64 processed;
+} CSeqSizeOutStream;
+
+static size_t SeqSizeOutStream_Write(ISeqOutStreamPtr pp, const void *data, size_t size)
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqSizeOutStream)
+ if (p->realStream)
+ size = ISeqOutStream_Write(p->realStream, data, size);
+ else
+ {
+ if (size > p->outBufLimit - (size_t)p->processed)
+ return 0;
+ memcpy(p->outBuf + (size_t)p->processed, data, size);
+ }
+ p->processed += size;
+ return size;
+}
+
+
+/* ---------- CSeqInFilter ---------- */
+
+#define FILTER_BUF_SIZE (1 << 20)
+
+typedef struct
+{
+ ISeqInStream vt;
+ ISeqInStreamPtr realStream;
+ IStateCoder StateCoder;
+ Byte *buf;
+ size_t curPos;
+ size_t endPos;
+ int srcWasFinished;
+} CSeqInFilter;
+
+
+static const z7_Func_BranchConv g_Funcs_BranchConv_RISC_Enc[] =
+{
+ Z7_BRANCH_CONV_ENC(PPC),
+ Z7_BRANCH_CONV_ENC(IA64),
+ Z7_BRANCH_CONV_ENC(ARM),
+ Z7_BRANCH_CONV_ENC(ARMT),
+ Z7_BRANCH_CONV_ENC(SPARC),
+ Z7_BRANCH_CONV_ENC(ARM64)
+};
+
+static SizeT XzBcFilterStateBase_Filter_Enc(CXzBcFilterStateBase *p, Byte *data, SizeT size)
+{
+ switch (p->methodId)
+ {
+ case XZ_ID_Delta:
+ Delta_Encode(p->delta_State, p->delta, data, size);
+ break;
+ case XZ_ID_X86:
+ size = (SizeT)(z7_BranchConvSt_X86_Enc(data, size, p->ip, &p->X86_State) - data);
+ break;
+ default:
+ if (p->methodId >= XZ_ID_PPC)
+ {
+ const UInt32 i = p->methodId - XZ_ID_PPC;
+ if (i < Z7_ARRAY_SIZE(g_Funcs_BranchConv_RISC_Enc))
+ size = (SizeT)(g_Funcs_BranchConv_RISC_Enc[i](data, size, p->ip) - data);
+ }
+ break;
+ }
+ p->ip += (UInt32)size;
+ return size;
+}
+
+
+static SRes SeqInFilter_Init(CSeqInFilter *p, const CXzFilter *props, ISzAllocPtr alloc)
+{
+ if (!p->buf)
+ {
+ p->buf = (Byte *)ISzAlloc_Alloc(alloc, FILTER_BUF_SIZE);
+ if (!p->buf)
+ return SZ_ERROR_MEM;
+ }
+ p->curPos = p->endPos = 0;
+ p->srcWasFinished = 0;
+ RINOK(Xz_StateCoder_Bc_SetFromMethod_Func(&p->StateCoder, props->id, XzBcFilterStateBase_Filter_Enc, alloc))
+ RINOK(p->StateCoder.SetProps(p->StateCoder.p, props->props, props->propsSize, alloc))
+ p->StateCoder.Init(p->StateCoder.p);
+ return SZ_OK;
+}
+
+
+static SRes SeqInFilter_Read(ISeqInStreamPtr pp, void *data, size_t *size)
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqInFilter)
+ const size_t sizeOriginal = *size;
+ if (sizeOriginal == 0)
+ return SZ_OK;
+ *size = 0;
+
+ for (;;)
+ {
+ if (!p->srcWasFinished && p->curPos == p->endPos)
+ {
+ p->curPos = 0;
+ p->endPos = FILTER_BUF_SIZE;
+ RINOK(ISeqInStream_Read(p->realStream, p->buf, &p->endPos))
+ if (p->endPos == 0)
+ p->srcWasFinished = 1;
+ }
+ {
+ SizeT srcLen = p->endPos - p->curPos;
+ ECoderStatus status;
+ SRes res;
+ *size = sizeOriginal;
+ res = p->StateCoder.Code2(p->StateCoder.p,
+ (Byte *)data, size,
+ p->buf + p->curPos, &srcLen,
+ p->srcWasFinished, CODER_FINISH_ANY,
+ &status);
+ p->curPos += srcLen;
+ if (*size != 0 || srcLen == 0 || res != SZ_OK)
+ return res;
+ }
+ }
+}
+
+static void SeqInFilter_Construct(CSeqInFilter *p)
+{
+ p->buf = NULL;
+ p->StateCoder.p = NULL;
+ p->vt.Read = SeqInFilter_Read;
+}
+
+static void SeqInFilter_Free(CSeqInFilter *p, ISzAllocPtr alloc)
+{
+ if (p->StateCoder.p)
+ {
+ p->StateCoder.Free(p->StateCoder.p, alloc);
+ p->StateCoder.p = NULL;
+ }
+ if (p->buf)
+ {
+ ISzAlloc_Free(alloc, p->buf);
+ p->buf = NULL;
+ }
+}
+
+
+/* ---------- CSbEncInStream ---------- */
+
+#ifdef USE_SUBBLOCK
+
+typedef struct
+{
+ ISeqInStream vt;
+ ISeqInStreamPtr inStream;
+ CSbEnc enc;
+} CSbEncInStream;
+
+static SRes SbEncInStream_Read(ISeqInStreamPtr pp, void *data, size_t *size)
+{
+ CSbEncInStream *p = Z7_CONTAINER_FROM_VTBL(pp, CSbEncInStream, vt);
+ size_t sizeOriginal = *size;
+ if (sizeOriginal == 0)
+ return SZ_OK;
+
+ for (;;)
+ {
+ if (p->enc.needRead && !p->enc.readWasFinished)
+ {
+ size_t processed = p->enc.needReadSizeMax;
+ RINOK(p->inStream->Read(p->inStream, p->enc.buf + p->enc.readPos, &processed))
+ p->enc.readPos += processed;
+ if (processed == 0)
+ {
+ p->enc.readWasFinished = True;
+ p->enc.isFinalFinished = True;
+ }
+ p->enc.needRead = False;
+ }
+
+ *size = sizeOriginal;
+ RINOK(SbEnc_Read(&p->enc, data, size))
+ if (*size != 0 || !p->enc.needRead)
+ return SZ_OK;
+ }
+}
+
+void SbEncInStream_Construct(CSbEncInStream *p, ISzAllocPtr alloc)
+{
+ SbEnc_Construct(&p->enc, alloc);
+ p->vt.Read = SbEncInStream_Read;
+}
+
+SRes SbEncInStream_Init(CSbEncInStream *p)
+{
+ return SbEnc_Init(&p->enc);
+}
+
+void SbEncInStream_Free(CSbEncInStream *p)
+{
+ SbEnc_Free(&p->enc);
+}
+
+#endif
+
+
+
+/* ---------- CXzProps ---------- */
+
+
+void XzFilterProps_Init(CXzFilterProps *p)
+{
+ p->id = 0;
+ p->delta = 0;
+ p->ip = 0;
+ p->ipDefined = False;
+}
+
+void XzProps_Init(CXzProps *p)
+{
+ p->checkId = XZ_CHECK_CRC32;
+ p->blockSize = XZ_PROPS_BLOCK_SIZE_AUTO;
+ p->numBlockThreads_Reduced = -1;
+ p->numBlockThreads_Max = -1;
+ p->numTotalThreads = -1;
+ p->reduceSize = (UInt64)(Int64)-1;
+ p->forceWriteSizesInHeader = 0;
+ // p->forceWriteSizesInHeader = 1;
+
+ XzFilterProps_Init(&p->filterProps);
+ Lzma2EncProps_Init(&p->lzma2Props);
+}
+
+
+static void XzEncProps_Normalize_Fixed(CXzProps *p)
+{
+ UInt64 fileSize;
+ int t1, t1n, t2, t2r, t3;
+ {
+ CLzma2EncProps tp = p->lzma2Props;
+ if (tp.numTotalThreads <= 0)
+ tp.numTotalThreads = p->numTotalThreads;
+ Lzma2EncProps_Normalize(&tp);
+ t1n = tp.numTotalThreads;
+ }
+
+ t1 = p->lzma2Props.numTotalThreads;
+ t2 = p->numBlockThreads_Max;
+ t3 = p->numTotalThreads;
+
+ if (t2 > MTCODER_THREADS_MAX)
+ t2 = MTCODER_THREADS_MAX;
+
+ if (t3 <= 0)
+ {
+ if (t2 <= 0)
+ t2 = 1;
+ t3 = t1n * t2;
+ }
+ else if (t2 <= 0)
+ {
+ t2 = t3 / t1n;
+ if (t2 == 0)
+ {
+ t1 = 1;
+ t2 = t3;
+ }
+ if (t2 > MTCODER_THREADS_MAX)
+ t2 = MTCODER_THREADS_MAX;
+ }
+ else if (t1 <= 0)
+ {
+ t1 = t3 / t2;
+ if (t1 == 0)
+ t1 = 1;
+ }
+ else
+ t3 = t1n * t2;
+
+ p->lzma2Props.numTotalThreads = t1;
+
+ t2r = t2;
+
+ fileSize = p->reduceSize;
+
+ if ((p->blockSize < fileSize || fileSize == (UInt64)(Int64)-1))
+ p->lzma2Props.lzmaProps.reduceSize = p->blockSize;
+
+ Lzma2EncProps_Normalize(&p->lzma2Props);
+
+ t1 = p->lzma2Props.numTotalThreads;
+
+ {
+ if (t2 > 1 && fileSize != (UInt64)(Int64)-1)
+ {
+ UInt64 numBlocks = fileSize / p->blockSize;
+ if (numBlocks * p->blockSize != fileSize)
+ numBlocks++;
+ if (numBlocks < (unsigned)t2)
+ {
+ t2r = (int)numBlocks;
+ if (t2r == 0)
+ t2r = 1;
+ t3 = t1 * t2r;
+ }
+ }
+ }
+
+ p->numBlockThreads_Max = t2;
+ p->numBlockThreads_Reduced = t2r;
+ p->numTotalThreads = t3;
+}
+
+
+static void XzProps_Normalize(CXzProps *p)
+{
+ /* we normalize xzProps properties, but we normalize only some of CXzProps::lzma2Props properties.
+ Lzma2Enc_SetProps() will normalize lzma2Props later. */
+
+ if (p->blockSize == XZ_PROPS_BLOCK_SIZE_SOLID)
+ {
+ p->lzma2Props.lzmaProps.reduceSize = p->reduceSize;
+ p->numBlockThreads_Reduced = 1;
+ p->numBlockThreads_Max = 1;
+ if (p->lzma2Props.numTotalThreads <= 0)
+ p->lzma2Props.numTotalThreads = p->numTotalThreads;
+ return;
+ }
+ else
+ {
+ CLzma2EncProps *lzma2 = &p->lzma2Props;
+ if (p->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO)
+ {
+ // xz-auto
+ p->lzma2Props.lzmaProps.reduceSize = p->reduceSize;
+
+ if (lzma2->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID)
+ {
+ // if (xz-auto && lzma2-solid) - we use solid for both
+ p->blockSize = XZ_PROPS_BLOCK_SIZE_SOLID;
+ p->numBlockThreads_Reduced = 1;
+ p->numBlockThreads_Max = 1;
+ if (p->lzma2Props.numTotalThreads <= 0)
+ p->lzma2Props.numTotalThreads = p->numTotalThreads;
+ }
+ else
+ {
+ // if (xz-auto && (lzma2-auto || lzma2-fixed_)
+ // we calculate block size for lzma2 and use that block size for xz, lzma2 uses single-chunk per block
+ CLzma2EncProps tp = p->lzma2Props;
+ if (tp.numTotalThreads <= 0)
+ tp.numTotalThreads = p->numTotalThreads;
+
+ Lzma2EncProps_Normalize(&tp);
+
+ p->blockSize = tp.blockSize; // fixed or solid
+ p->numBlockThreads_Reduced = tp.numBlockThreads_Reduced;
+ p->numBlockThreads_Max = tp.numBlockThreads_Max;
+ if (lzma2->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO)
+ lzma2->blockSize = tp.blockSize; // fixed or solid, LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID
+ if (lzma2->lzmaProps.reduceSize > tp.blockSize && tp.blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID)
+ lzma2->lzmaProps.reduceSize = tp.blockSize;
+ lzma2->numBlockThreads_Reduced = 1;
+ lzma2->numBlockThreads_Max = 1;
+ return;
+ }
+ }
+ else
+ {
+ // xz-fixed
+ // we can use xz::reduceSize or xz::blockSize as base for lzmaProps::reduceSize
+
+ p->lzma2Props.lzmaProps.reduceSize = p->reduceSize;
+ {
+ UInt64 r = p->reduceSize;
+ if (r > p->blockSize || r == (UInt64)(Int64)-1)
+ r = p->blockSize;
+ lzma2->lzmaProps.reduceSize = r;
+ }
+ if (lzma2->blockSize == LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO)
+ lzma2->blockSize = LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID;
+ else if (lzma2->blockSize > p->blockSize && lzma2->blockSize != LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID)
+ lzma2->blockSize = p->blockSize;
+
+ XzEncProps_Normalize_Fixed(p);
+ }
+ }
+}
+
+
+/* ---------- CLzma2WithFilters ---------- */
+
+typedef struct
+{
+ CLzma2EncHandle lzma2;
+ CSeqInFilter filter;
+
+ #ifdef USE_SUBBLOCK
+ CSbEncInStream sb;
+ #endif
+} CLzma2WithFilters;
+
+
+static void Lzma2WithFilters_Construct(CLzma2WithFilters *p)
+{
+ p->lzma2 = NULL;
+ SeqInFilter_Construct(&p->filter);
+
+ #ifdef USE_SUBBLOCK
+ SbEncInStream_Construct(&p->sb, alloc);
+ #endif
+}
+
+
+static SRes Lzma2WithFilters_Create(CLzma2WithFilters *p, ISzAllocPtr alloc, ISzAllocPtr bigAlloc)
+{
+ if (!p->lzma2)
+ {
+ p->lzma2 = Lzma2Enc_Create(alloc, bigAlloc);
+ if (!p->lzma2)
+ return SZ_ERROR_MEM;
+ }
+ return SZ_OK;
+}
+
+
+static void Lzma2WithFilters_Free(CLzma2WithFilters *p, ISzAllocPtr alloc)
+{
+ #ifdef USE_SUBBLOCK
+ SbEncInStream_Free(&p->sb);
+ #endif
+
+ SeqInFilter_Free(&p->filter, alloc);
+ if (p->lzma2)
+ {
+ Lzma2Enc_Destroy(p->lzma2);
+ p->lzma2 = NULL;
+ }
+}
+
+
+typedef struct
+{
+ UInt64 unpackSize;
+ UInt64 totalSize;
+ size_t headerSize;
+} CXzEncBlockInfo;
+
+
+static SRes Xz_CompressBlock(
+ CLzma2WithFilters *lzmaf,
+
+ ISeqOutStreamPtr outStream,
+ Byte *outBufHeader,
+ Byte *outBufData, size_t outBufDataLimit,
+
+ ISeqInStreamPtr inStream,
+ // UInt64 expectedSize,
+ const Byte *inBuf, // used if (!inStream)
+ size_t inBufSize, // used if (!inStream), it's block size, props->blockSize is ignored
+
+ const CXzProps *props,
+ ICompressProgressPtr progress,
+ int *inStreamFinished, /* only for inStream version */
+ CXzEncBlockInfo *blockSizes,
+ ISzAllocPtr alloc,
+ ISzAllocPtr allocBig)
+{
+ CSeqCheckInStream checkInStream;
+ CSeqSizeOutStream seqSizeOutStream;
+ CXzBlock block;
+ unsigned filterIndex = 0;
+ CXzFilter *filter = NULL;
+ const CXzFilterProps *fp = &props->filterProps;
+ if (fp->id == 0)
+ fp = NULL;
+
+ *inStreamFinished = False;
+
+ RINOK(Lzma2WithFilters_Create(lzmaf, alloc, allocBig))
+
+ RINOK(Lzma2Enc_SetProps(lzmaf->lzma2, &props->lzma2Props))
+
+ // XzBlock_ClearFlags(&block)
+ XzBlock_ClearFlags_SetNumFilters(&block, 1 + (fp ? 1 : 0))
+
+ if (fp)
+ {
+ filter = &block.filters[filterIndex++];
+ filter->id = fp->id;
+ filter->propsSize = 0;
+
+ if (fp->id == XZ_ID_Delta)
+ {
+ filter->props[0] = (Byte)(fp->delta - 1);
+ filter->propsSize = 1;
+ }
+ else if (fp->ipDefined)
+ {
+ Byte *ptr = filter->props;
+ SetUi32(ptr, fp->ip)
+ filter->propsSize = 4;
+ }
+ }
+
+ {
+ CXzFilter *f = &block.filters[filterIndex++];
+ f->id = XZ_ID_LZMA2;
+ f->propsSize = 1;
+ f->props[0] = Lzma2Enc_WriteProperties(lzmaf->lzma2);
+ }
+
+ seqSizeOutStream.vt.Write = SeqSizeOutStream_Write;
+ seqSizeOutStream.realStream = outStream;
+ seqSizeOutStream.outBuf = outBufData;
+ seqSizeOutStream.outBufLimit = outBufDataLimit;
+ seqSizeOutStream.processed = 0;
+
+ /*
+ if (expectedSize != (UInt64)(Int64)-1)
+ {
+ block.unpackSize = expectedSize;
+ if (props->blockSize != (UInt64)(Int64)-1)
+ if (expectedSize > props->blockSize)
+ block.unpackSize = props->blockSize;
+ XzBlock_SetHasUnpackSize(&block)
+ }
+ */
+
+ if (outStream)
+ {
+ RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt))
+ }
+
+ checkInStream.vt.Read = SeqCheckInStream_Read;
+ SeqCheckInStream_Init(&checkInStream, props->checkId);
+
+ checkInStream.realStream = inStream;
+ checkInStream.data = inBuf;
+ checkInStream.limit = props->blockSize;
+ if (!inStream)
+ checkInStream.limit = inBufSize;
+
+ if (fp)
+ {
+ #ifdef USE_SUBBLOCK
+ if (fp->id == XZ_ID_Subblock)
+ {
+ lzmaf->sb.inStream = &checkInStream.vt;
+ RINOK(SbEncInStream_Init(&lzmaf->sb))
+ }
+ else
+ #endif
+ {
+ lzmaf->filter.realStream = &checkInStream.vt;
+ RINOK(SeqInFilter_Init(&lzmaf->filter, filter, alloc))
+ }
+ }
+
+ {
+ SRes res;
+ Byte *outBuf = NULL;
+ size_t outSize = 0;
+ BoolInt useStream = (fp || inStream);
+ // useStream = True;
+
+ if (!useStream)
+ {
+ XzCheck_Update(&checkInStream.check, inBuf, inBufSize);
+ checkInStream.processed = inBufSize;
+ }
+
+ if (!outStream)
+ {
+ outBuf = seqSizeOutStream.outBuf; // + (size_t)seqSizeOutStream.processed;
+ outSize = seqSizeOutStream.outBufLimit; // - (size_t)seqSizeOutStream.processed;
+ }
+
+ res = Lzma2Enc_Encode2(lzmaf->lzma2,
+ outBuf ? NULL : &seqSizeOutStream.vt,
+ outBuf,
+ outBuf ? &outSize : NULL,
+
+ useStream ?
+ (fp ?
+ (
+ #ifdef USE_SUBBLOCK
+ (fp->id == XZ_ID_Subblock) ? &lzmaf->sb.vt:
+ #endif
+ &lzmaf->filter.vt) :
+ &checkInStream.vt) : NULL,
+
+ useStream ? NULL : inBuf,
+ useStream ? 0 : inBufSize,
+
+ progress);
+
+ if (outBuf)
+ seqSizeOutStream.processed += outSize;
+
+ RINOK(res)
+ blockSizes->unpackSize = checkInStream.processed;
+ }
+ {
+ Byte buf[4 + 64];
+ unsigned padSize = XZ_GET_PAD_SIZE(seqSizeOutStream.processed);
+ UInt64 packSize = seqSizeOutStream.processed;
+
+ buf[0] = 0;
+ buf[1] = 0;
+ buf[2] = 0;
+ buf[3] = 0;
+
+ SeqCheckInStream_GetDigest(&checkInStream, buf + 4);
+ RINOK(WriteBytes(&seqSizeOutStream.vt, buf + (4 - padSize), padSize + XzFlags_GetCheckSize((CXzStreamFlags)props->checkId)))
+
+ blockSizes->totalSize = seqSizeOutStream.processed - padSize;
+
+ if (!outStream)
+ {
+ seqSizeOutStream.outBuf = outBufHeader;
+ seqSizeOutStream.outBufLimit = XZ_BLOCK_HEADER_SIZE_MAX;
+ seqSizeOutStream.processed = 0;
+
+ block.unpackSize = blockSizes->unpackSize;
+ XzBlock_SetHasUnpackSize(&block)
+
+ block.packSize = packSize;
+ XzBlock_SetHasPackSize(&block)
+
+ RINOK(XzBlock_WriteHeader(&block, &seqSizeOutStream.vt))
+
+ blockSizes->headerSize = (size_t)seqSizeOutStream.processed;
+ blockSizes->totalSize += seqSizeOutStream.processed;
+ }
+ }
+
+ if (inStream)
+ *inStreamFinished = checkInStream.realStreamFinished;
+ else
+ {
+ *inStreamFinished = False;
+ if (checkInStream.processed != inBufSize)
+ return SZ_ERROR_FAIL;
+ }
+
+ return SZ_OK;
+}
+
+
+
+typedef struct
+{
+ ICompressProgress vt;
+ ICompressProgressPtr progress;
+ UInt64 inOffset;
+ UInt64 outOffset;
+} CCompressProgress_XzEncOffset;
+
+
+static SRes CompressProgress_XzEncOffset_Progress(ICompressProgressPtr pp, UInt64 inSize, UInt64 outSize)
+{
+ const CCompressProgress_XzEncOffset *p = Z7_CONTAINER_FROM_VTBL_CONST(pp, CCompressProgress_XzEncOffset, vt);
+ inSize += p->inOffset;
+ outSize += p->outOffset;
+ return ICompressProgress_Progress(p->progress, inSize, outSize);
+}
+
+
+
+
+struct CXzEnc
+{
+ ISzAllocPtr alloc;
+ ISzAllocPtr allocBig;
+
+ CXzProps xzProps;
+ UInt64 expectedDataSize;
+
+ CXzEncIndex xzIndex;
+
+ CLzma2WithFilters lzmaf_Items[MTCODER_THREADS_MAX];
+
+ size_t outBufSize; /* size of allocated outBufs[i] */
+ Byte *outBufs[MTCODER_BLOCKS_MAX];
+
+ #ifndef Z7_ST
+ unsigned checkType;
+ ISeqOutStreamPtr outStream;
+ BoolInt mtCoder_WasConstructed;
+ CMtCoder mtCoder;
+ CXzEncBlockInfo EncBlocks[MTCODER_BLOCKS_MAX];
+ #endif
+};
+
+
+static void XzEnc_Construct(CXzEnc *p)
+{
+ unsigned i;
+
+ XzEncIndex_Construct(&p->xzIndex);
+
+ for (i = 0; i < MTCODER_THREADS_MAX; i++)
+ Lzma2WithFilters_Construct(&p->lzmaf_Items[i]);
+
+ #ifndef Z7_ST
+ p->mtCoder_WasConstructed = False;
+ {
+ for (i = 0; i < MTCODER_BLOCKS_MAX; i++)
+ p->outBufs[i] = NULL;
+ p->outBufSize = 0;
+ }
+ #endif
+}
+
+
+static void XzEnc_FreeOutBufs(CXzEnc *p)
+{
+ unsigned i;
+ for (i = 0; i < MTCODER_BLOCKS_MAX; i++)
+ if (p->outBufs[i])
+ {
+ ISzAlloc_Free(p->alloc, p->outBufs[i]);
+ p->outBufs[i] = NULL;
+ }
+ p->outBufSize = 0;
+}
+
+
+static void XzEnc_Free(CXzEnc *p, ISzAllocPtr alloc)
+{
+ unsigned i;
+
+ XzEncIndex_Free(&p->xzIndex, alloc);
+
+ for (i = 0; i < MTCODER_THREADS_MAX; i++)
+ Lzma2WithFilters_Free(&p->lzmaf_Items[i], alloc);
+
+ #ifndef Z7_ST
+ if (p->mtCoder_WasConstructed)
+ {
+ MtCoder_Destruct(&p->mtCoder);
+ p->mtCoder_WasConstructed = False;
+ }
+ XzEnc_FreeOutBufs(p);
+ #endif
+}
+
+
+CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig)
+{
+ CXzEnc *p = (CXzEnc *)ISzAlloc_Alloc(alloc, sizeof(CXzEnc));
+ if (!p)
+ return NULL;
+ XzEnc_Construct(p);
+ XzProps_Init(&p->xzProps);
+ XzProps_Normalize(&p->xzProps);
+ p->expectedDataSize = (UInt64)(Int64)-1;
+ p->alloc = alloc;
+ p->allocBig = allocBig;
+ return (CXzEncHandle)p;
+}
+
+// #define GET_CXzEnc_p CXzEnc *p = (CXzEnc *)(void *)pp;
+
+void XzEnc_Destroy(CXzEncHandle p)
+{
+ // GET_CXzEnc_p
+ XzEnc_Free(p, p->alloc);
+ ISzAlloc_Free(p->alloc, p);
+}
+
+
+SRes XzEnc_SetProps(CXzEncHandle p, const CXzProps *props)
+{
+ // GET_CXzEnc_p
+ p->xzProps = *props;
+ XzProps_Normalize(&p->xzProps);
+ return SZ_OK;
+}
+
+
+void XzEnc_SetDataSize(CXzEncHandle p, UInt64 expectedDataSiize)
+{
+ // GET_CXzEnc_p
+ p->expectedDataSize = expectedDataSiize;
+}
+
+
+
+
+#ifndef Z7_ST
+
+static SRes XzEnc_MtCallback_Code(void *pp, unsigned coderIndex, unsigned outBufIndex,
+ const Byte *src, size_t srcSize, int finished)
+{
+ CXzEnc *me = (CXzEnc *)pp;
+ SRes res;
+ CMtProgressThunk progressThunk;
+
+ Byte *dest = me->outBufs[outBufIndex];
+
+ UNUSED_VAR(finished)
+
+ {
+ CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex];
+ bInfo->totalSize = 0;
+ bInfo->unpackSize = 0;
+ bInfo->headerSize = 0;
+ }
+
+ if (!dest)
+ {
+ dest = (Byte *)ISzAlloc_Alloc(me->alloc, me->outBufSize);
+ if (!dest)
+ return SZ_ERROR_MEM;
+ me->outBufs[outBufIndex] = dest;
+ }
+
+ MtProgressThunk_CreateVTable(&progressThunk);
+ progressThunk.mtProgress = &me->mtCoder.mtProgress;
+ MtProgressThunk_INIT(&progressThunk)
+
+ {
+ CXzEncBlockInfo blockSizes;
+ int inStreamFinished;
+
+ res = Xz_CompressBlock(
+ &me->lzmaf_Items[coderIndex],
+
+ NULL,
+ dest,
+ dest + XZ_BLOCK_HEADER_SIZE_MAX, me->outBufSize - XZ_BLOCK_HEADER_SIZE_MAX,
+
+ NULL,
+ // srcSize, // expectedSize
+ src, srcSize,
+
+ &me->xzProps,
+ &progressThunk.vt,
+ &inStreamFinished,
+ &blockSizes,
+ me->alloc,
+ me->allocBig);
+
+ if (res == SZ_OK)
+ me->EncBlocks[outBufIndex] = blockSizes;
+
+ return res;
+ }
+}
+
+
+static SRes XzEnc_MtCallback_Write(void *pp, unsigned outBufIndex)
+{
+ CXzEnc *me = (CXzEnc *)pp;
+
+ const CXzEncBlockInfo *bInfo = &me->EncBlocks[outBufIndex];
+ const Byte *data = me->outBufs[outBufIndex];
+
+ RINOK(WriteBytes(me->outStream, data, bInfo->headerSize))
+
+ {
+ UInt64 totalPackFull = bInfo->totalSize + XZ_GET_PAD_SIZE(bInfo->totalSize);
+ RINOK(WriteBytes(me->outStream, data + XZ_BLOCK_HEADER_SIZE_MAX, (size_t)totalPackFull - bInfo->headerSize))
+ }
+
+ return XzEncIndex_AddIndexRecord(&me->xzIndex, bInfo->unpackSize, bInfo->totalSize, me->alloc);
+}
+
+#endif
+
+
+
+SRes XzEnc_Encode(CXzEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, ICompressProgressPtr progress)
+{
+ // GET_CXzEnc_p
+
+ const CXzProps *props = &p->xzProps;
+
+ XzEncIndex_Init(&p->xzIndex);
+ {
+ UInt64 numBlocks = 1;
+ UInt64 blockSize = props->blockSize;
+
+ if (blockSize != XZ_PROPS_BLOCK_SIZE_SOLID
+ && props->reduceSize != (UInt64)(Int64)-1)
+ {
+ numBlocks = props->reduceSize / blockSize;
+ if (numBlocks * blockSize != props->reduceSize)
+ numBlocks++;
+ }
+ else
+ blockSize = (UInt64)1 << 62;
+
+ RINOK(XzEncIndex_PreAlloc(&p->xzIndex, numBlocks, blockSize, XZ_GET_ESTIMATED_BLOCK_TOTAL_PACK_SIZE(blockSize), p->alloc))
+ }
+
+ RINOK(Xz_WriteHeader((CXzStreamFlags)props->checkId, outStream))
+
+
+ #ifndef Z7_ST
+ if (props->numBlockThreads_Reduced > 1)
+ {
+ IMtCoderCallback2 vt;
+
+ if (!p->mtCoder_WasConstructed)
+ {
+ p->mtCoder_WasConstructed = True;
+ MtCoder_Construct(&p->mtCoder);
+ }
+
+ vt.Code = XzEnc_MtCallback_Code;
+ vt.Write = XzEnc_MtCallback_Write;
+
+ p->checkType = props->checkId;
+ p->xzProps = *props;
+
+ p->outStream = outStream;
+
+ p->mtCoder.allocBig = p->allocBig;
+ p->mtCoder.progress = progress;
+ p->mtCoder.inStream = inStream;
+ p->mtCoder.inData = NULL;
+ p->mtCoder.inDataSize = 0;
+ p->mtCoder.mtCallback = &vt;
+ p->mtCoder.mtCallbackObject = p;
+
+ if ( props->blockSize == XZ_PROPS_BLOCK_SIZE_SOLID
+ || props->blockSize == XZ_PROPS_BLOCK_SIZE_AUTO)
+ return SZ_ERROR_FAIL;
+
+ p->mtCoder.blockSize = (size_t)props->blockSize;
+ if (p->mtCoder.blockSize != props->blockSize)
+ return SZ_ERROR_PARAM; /* SZ_ERROR_MEM */
+
+ {
+ size_t destBlockSize = XZ_BLOCK_HEADER_SIZE_MAX + XZ_GET_MAX_BLOCK_PACK_SIZE(p->mtCoder.blockSize);
+ if (destBlockSize < p->mtCoder.blockSize)
+ return SZ_ERROR_PARAM;
+ if (p->outBufSize != destBlockSize)
+ XzEnc_FreeOutBufs(p);
+ p->outBufSize = destBlockSize;
+ }
+
+ p->mtCoder.numThreadsMax = (unsigned)props->numBlockThreads_Max;
+ p->mtCoder.expectedDataSize = p->expectedDataSize;
+
+ RINOK(MtCoder_Code(&p->mtCoder))
+ }
+ else
+ #endif
+ {
+ int writeStartSizes;
+ CCompressProgress_XzEncOffset progress2;
+ Byte *bufData = NULL;
+ size_t bufSize = 0;
+
+ progress2.vt.Progress = CompressProgress_XzEncOffset_Progress;
+ progress2.inOffset = 0;
+ progress2.outOffset = 0;
+ progress2.progress = progress;
+
+ writeStartSizes = 0;
+
+ if (props->blockSize != XZ_PROPS_BLOCK_SIZE_SOLID)
+ {
+ writeStartSizes = (props->forceWriteSizesInHeader > 0);
+
+ if (writeStartSizes)
+ {
+ size_t t2;
+ size_t t = (size_t)props->blockSize;
+ if (t != props->blockSize)
+ return SZ_ERROR_PARAM;
+ t = XZ_GET_MAX_BLOCK_PACK_SIZE(t);
+ if (t < props->blockSize)
+ return SZ_ERROR_PARAM;
+ t2 = XZ_BLOCK_HEADER_SIZE_MAX + t;
+ if (!p->outBufs[0] || t2 != p->outBufSize)
+ {
+ XzEnc_FreeOutBufs(p);
+ p->outBufs[0] = (Byte *)ISzAlloc_Alloc(p->alloc, t2);
+ if (!p->outBufs[0])
+ return SZ_ERROR_MEM;
+ p->outBufSize = t2;
+ }
+ bufData = p->outBufs[0] + XZ_BLOCK_HEADER_SIZE_MAX;
+ bufSize = t;
+ }
+ }
+
+ for (;;)
+ {
+ CXzEncBlockInfo blockSizes;
+ int inStreamFinished;
+
+ /*
+ UInt64 rem = (UInt64)(Int64)-1;
+ if (props->reduceSize != (UInt64)(Int64)-1
+ && props->reduceSize >= progress2.inOffset)
+ rem = props->reduceSize - progress2.inOffset;
+ */
+
+ blockSizes.headerSize = 0; // for GCC
+
+ RINOK(Xz_CompressBlock(
+ &p->lzmaf_Items[0],
+
+ writeStartSizes ? NULL : outStream,
+ writeStartSizes ? p->outBufs[0] : NULL,
+ bufData, bufSize,
+
+ inStream,
+ // rem,
+ NULL, 0,
+
+ props,
+ progress ? &progress2.vt : NULL,
+ &inStreamFinished,
+ &blockSizes,
+ p->alloc,
+ p->allocBig))
+
+ {
+ UInt64 totalPackFull = blockSizes.totalSize + XZ_GET_PAD_SIZE(blockSizes.totalSize);
+
+ if (writeStartSizes)
+ {
+ RINOK(WriteBytes(outStream, p->outBufs[0], blockSizes.headerSize))
+ RINOK(WriteBytes(outStream, bufData, (size_t)totalPackFull - blockSizes.headerSize))
+ }
+
+ RINOK(XzEncIndex_AddIndexRecord(&p->xzIndex, blockSizes.unpackSize, blockSizes.totalSize, p->alloc))
+
+ progress2.inOffset += blockSizes.unpackSize;
+ progress2.outOffset += totalPackFull;
+ }
+
+ if (inStreamFinished)
+ break;
+ }
+ }
+
+ return XzEncIndex_WriteFooter(&p->xzIndex, (CXzStreamFlags)props->checkId, outStream);
+}
+
+
+#include "Alloc.h"
+
+SRes Xz_Encode(ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream,
+ const CXzProps *props, ICompressProgressPtr progress)
+{
+ SRes res;
+ CXzEncHandle xz = XzEnc_Create(&g_Alloc, &g_BigAlloc);
+ if (!xz)
+ return SZ_ERROR_MEM;
+ res = XzEnc_SetProps(xz, props);
+ if (res == SZ_OK)
+ res = XzEnc_Encode(xz, outStream, inStream, progress);
+ XzEnc_Destroy(xz);
+ return res;
+}
+
+
+SRes Xz_EncodeEmpty(ISeqOutStreamPtr outStream)
+{
+ SRes res;
+ CXzEncIndex xzIndex;
+ XzEncIndex_Construct(&xzIndex);
+ res = Xz_WriteHeader((CXzStreamFlags)0, outStream);
+ if (res == SZ_OK)
+ res = XzEncIndex_WriteFooter(&xzIndex, (CXzStreamFlags)0, outStream);
+ XzEncIndex_Free(&xzIndex, NULL); // g_Alloc
+ return res;
+}
diff --git a/C/XzEnc.h b/C/XzEnc.h
index 529ac3f..77b78c0 100644
--- a/C/XzEnc.h
+++ b/C/XzEnc.h
@@ -1,60 +1,61 @@
-/* XzEnc.h -- Xz Encode
-2017-06-27 : Igor Pavlov : Public domain */
-
-#ifndef __XZ_ENC_H
-#define __XZ_ENC_H
-
-#include "Lzma2Enc.h"
-
-#include "Xz.h"
-
-EXTERN_C_BEGIN
-
-
-#define XZ_PROPS__BLOCK_SIZE__AUTO LZMA2_ENC_PROPS__BLOCK_SIZE__AUTO
-#define XZ_PROPS__BLOCK_SIZE__SOLID LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID
-
-
-typedef struct
-{
- UInt32 id;
- UInt32 delta;
- UInt32 ip;
- int ipDefined;
-} CXzFilterProps;
-
-void XzFilterProps_Init(CXzFilterProps *p);
-
-
-typedef struct
-{
- CLzma2EncProps lzma2Props;
- CXzFilterProps filterProps;
- unsigned checkId;
- UInt64 blockSize;
- int numBlockThreads_Reduced;
- int numBlockThreads_Max;
- int numTotalThreads;
- int forceWriteSizesInHeader;
- UInt64 reduceSize;
-} CXzProps;
-
-void XzProps_Init(CXzProps *p);
-
-
-typedef void * CXzEncHandle;
-
-CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig);
-void XzEnc_Destroy(CXzEncHandle p);
-SRes XzEnc_SetProps(CXzEncHandle p, const CXzProps *props);
-void XzEnc_SetDataSize(CXzEncHandle p, UInt64 expectedDataSiize);
-SRes XzEnc_Encode(CXzEncHandle p, ISeqOutStream *outStream, ISeqInStream *inStream, ICompressProgress *progress);
-
-SRes Xz_Encode(ISeqOutStream *outStream, ISeqInStream *inStream,
- const CXzProps *props, ICompressProgress *progress);
-
-SRes Xz_EncodeEmpty(ISeqOutStream *outStream);
-
-EXTERN_C_END
-
-#endif
+/* XzEnc.h -- Xz Encode
+2023-04-13 : Igor Pavlov : Public domain */
+
+#ifndef ZIP7_INC_XZ_ENC_H
+#define ZIP7_INC_XZ_ENC_H
+
+#include "Lzma2Enc.h"
+
+#include "Xz.h"
+
+EXTERN_C_BEGIN
+
+
+#define XZ_PROPS_BLOCK_SIZE_AUTO LZMA2_ENC_PROPS_BLOCK_SIZE_AUTO
+#define XZ_PROPS_BLOCK_SIZE_SOLID LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID
+
+
+typedef struct
+{
+ UInt32 id;
+ UInt32 delta;
+ UInt32 ip;
+ int ipDefined;
+} CXzFilterProps;
+
+void XzFilterProps_Init(CXzFilterProps *p);
+
+
+typedef struct
+{
+ CLzma2EncProps lzma2Props;
+ CXzFilterProps filterProps;
+ unsigned checkId;
+ UInt64 blockSize;
+ int numBlockThreads_Reduced;
+ int numBlockThreads_Max;
+ int numTotalThreads;
+ int forceWriteSizesInHeader;
+ UInt64 reduceSize;
+} CXzProps;
+
+void XzProps_Init(CXzProps *p);
+
+typedef struct CXzEnc CXzEnc;
+typedef CXzEnc * CXzEncHandle;
+// Z7_DECLARE_HANDLE(CXzEncHandle)
+
+CXzEncHandle XzEnc_Create(ISzAllocPtr alloc, ISzAllocPtr allocBig);
+void XzEnc_Destroy(CXzEncHandle p);
+SRes XzEnc_SetProps(CXzEncHandle p, const CXzProps *props);
+void XzEnc_SetDataSize(CXzEncHandle p, UInt64 expectedDataSiize);
+SRes XzEnc_Encode(CXzEncHandle p, ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream, ICompressProgressPtr progress);
+
+SRes Xz_Encode(ISeqOutStreamPtr outStream, ISeqInStreamPtr inStream,
+ const CXzProps *props, ICompressProgressPtr progress);
+
+SRes Xz_EncodeEmpty(ISeqOutStreamPtr outStream);
+
+EXTERN_C_END
+
+#endif
diff --git a/C/XzIn.c b/C/XzIn.c
index 792a617..d0fc763 100644
--- a/C/XzIn.c
+++ b/C/XzIn.c
@@ -1,319 +1,340 @@
-/* XzIn.c - Xz input
-2018-07-04 : Igor Pavlov : Public domain */
-
-#include "Precomp.h"
-
-#include <string.h>
-
-#include "7zCrc.h"
-#include "CpuArch.h"
-#include "Xz.h"
-
-/*
-#define XZ_FOOTER_SIG_CHECK(p) (memcmp((p), XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0)
-*/
-#define XZ_FOOTER_SIG_CHECK(p) ((p)[0] == XZ_FOOTER_SIG_0 && (p)[1] == XZ_FOOTER_SIG_1)
-
-
-SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStream *inStream)
-{
- Byte sig[XZ_STREAM_HEADER_SIZE];
- RINOK(SeqInStream_Read2(inStream, sig, XZ_STREAM_HEADER_SIZE, SZ_ERROR_NO_ARCHIVE));
- if (memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0)
- return SZ_ERROR_NO_ARCHIVE;
- return Xz_ParseHeader(p, sig);
-}
-
-#define READ_VARINT_AND_CHECK(buf, pos, size, res) \
- { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \
- if (s == 0) return SZ_ERROR_ARCHIVE; pos += s; }
-
-SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStream *inStream, BoolInt *isIndex, UInt32 *headerSizeRes)
-{
- Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
- unsigned headerSize;
- *headerSizeRes = 0;
- RINOK(SeqInStream_ReadByte(inStream, &header[0]));
- headerSize = (unsigned)header[0];
- if (headerSize == 0)
- {
- *headerSizeRes = 1;
- *isIndex = True;
- return SZ_OK;
- }
-
- *isIndex = False;
- headerSize = (headerSize << 2) + 4;
- *headerSizeRes = headerSize;
- RINOK(SeqInStream_Read(inStream, header + 1, headerSize - 1));
- return XzBlock_Parse(p, header);
-}
-
-#define ADD_SIZE_CHECK(size, val) \
- { UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; }
-
-UInt64 Xz_GetUnpackSize(const CXzStream *p)
-{
- UInt64 size = 0;
- size_t i;
- for (i = 0; i < p->numBlocks; i++)
- ADD_SIZE_CHECK(size, p->blocks[i].unpackSize);
- return size;
-}
-
-UInt64 Xz_GetPackSize(const CXzStream *p)
-{
- UInt64 size = 0;
- size_t i;
- for (i = 0; i < p->numBlocks; i++)
- ADD_SIZE_CHECK(size, (p->blocks[i].totalSize + 3) & ~(UInt64)3);
- return size;
-}
-
-/*
-SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStream *inStream)
-{
- return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f));
-}
-*/
-
-static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAllocPtr alloc)
-{
- size_t numBlocks, pos = 1;
- UInt32 crc;
-
- if (size < 5 || buf[0] != 0)
- return SZ_ERROR_ARCHIVE;
-
- size -= 4;
- crc = CrcCalc(buf, size);
- if (crc != GetUi32(buf + size))
- return SZ_ERROR_ARCHIVE;
-
- {
- UInt64 numBlocks64;
- READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64);
- numBlocks = (size_t)numBlocks64;
- if (numBlocks != numBlocks64 || numBlocks * 2 > size)
- return SZ_ERROR_ARCHIVE;
- }
-
- Xz_Free(p, alloc);
- if (numBlocks != 0)
- {
- size_t i;
- p->numBlocks = numBlocks;
- p->blocks = (CXzBlockSizes *)ISzAlloc_Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks);
- if (!p->blocks)
- return SZ_ERROR_MEM;
- for (i = 0; i < numBlocks; i++)
- {
- CXzBlockSizes *block = &p->blocks[i];
- READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize);
- READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize);
- if (block->totalSize == 0)
- return SZ_ERROR_ARCHIVE;
- }
- }
- while ((pos & 3) != 0)
- if (buf[pos++] != 0)
- return SZ_ERROR_ARCHIVE;
- return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
-}
-
-static SRes Xz_ReadIndex(CXzStream *p, ILookInStream *stream, UInt64 indexSize, ISzAllocPtr alloc)
-{
- SRes res;
- size_t size;
- Byte *buf;
- if (indexSize > ((UInt32)1 << 31))
- return SZ_ERROR_UNSUPPORTED;
- size = (size_t)indexSize;
- if (size != indexSize)
- return SZ_ERROR_UNSUPPORTED;
- buf = (Byte *)ISzAlloc_Alloc(alloc, size);
- if (!buf)
- return SZ_ERROR_MEM;
- res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED);
- if (res == SZ_OK)
- res = Xz_ReadIndex2(p, buf, size, alloc);
- ISzAlloc_Free(alloc, buf);
- return res;
-}
-
-static SRes LookInStream_SeekRead_ForArc(ILookInStream *stream, UInt64 offset, void *buf, size_t size)
-{
- RINOK(LookInStream_SeekTo(stream, offset));
- return LookInStream_Read(stream, buf, size);
- /* return LookInStream_Read2(stream, buf, size, SZ_ERROR_NO_ARCHIVE); */
-}
-
-static SRes Xz_ReadBackward(CXzStream *p, ILookInStream *stream, Int64 *startOffset, ISzAllocPtr alloc)
-{
- UInt64 indexSize;
- Byte buf[XZ_STREAM_FOOTER_SIZE];
- UInt64 pos = *startOffset;
-
- if ((pos & 3) != 0 || pos < XZ_STREAM_FOOTER_SIZE)
- return SZ_ERROR_NO_ARCHIVE;
-
- pos -= XZ_STREAM_FOOTER_SIZE;
- RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE));
-
- if (!XZ_FOOTER_SIG_CHECK(buf + 10))
- {
- UInt32 total = 0;
- pos += XZ_STREAM_FOOTER_SIZE;
-
- for (;;)
- {
- size_t i;
- #define TEMP_BUF_SIZE (1 << 10)
- Byte temp[TEMP_BUF_SIZE];
-
- i = (pos > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)pos;
- pos -= i;
- RINOK(LookInStream_SeekRead_ForArc(stream, pos, temp, i));
- total += (UInt32)i;
- for (; i != 0; i--)
- if (temp[i - 1] != 0)
- break;
- if (i != 0)
- {
- if ((i & 3) != 0)
- return SZ_ERROR_NO_ARCHIVE;
- pos += i;
- break;
- }
- if (pos < XZ_STREAM_FOOTER_SIZE || total > (1 << 16))
- return SZ_ERROR_NO_ARCHIVE;
- }
-
- if (pos < XZ_STREAM_FOOTER_SIZE)
- return SZ_ERROR_NO_ARCHIVE;
- pos -= XZ_STREAM_FOOTER_SIZE;
- RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE));
- if (!XZ_FOOTER_SIG_CHECK(buf + 10))
- return SZ_ERROR_NO_ARCHIVE;
- }
-
- p->flags = (CXzStreamFlags)GetBe16(buf + 8);
-
- if (!XzFlags_IsSupported(p->flags))
- return SZ_ERROR_UNSUPPORTED;
-
- if (GetUi32(buf) != CrcCalc(buf + 4, 6))
- return SZ_ERROR_ARCHIVE;
-
- indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2;
-
- if (pos < indexSize)
- return SZ_ERROR_ARCHIVE;
-
- pos -= indexSize;
- RINOK(LookInStream_SeekTo(stream, pos));
- RINOK(Xz_ReadIndex(p, stream, indexSize, alloc));
-
- {
- UInt64 totalSize = Xz_GetPackSize(p);
- if (totalSize == XZ_SIZE_OVERFLOW
- || totalSize >= ((UInt64)1 << 63)
- || pos < totalSize + XZ_STREAM_HEADER_SIZE)
- return SZ_ERROR_ARCHIVE;
- pos -= (totalSize + XZ_STREAM_HEADER_SIZE);
- RINOK(LookInStream_SeekTo(stream, pos));
- *startOffset = pos;
- }
- {
- CXzStreamFlags headerFlags;
- CSecToRead secToRead;
- SecToRead_CreateVTable(&secToRead);
- secToRead.realStream = stream;
-
- RINOK(Xz_ReadHeader(&headerFlags, &secToRead.vt));
- return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE;
- }
-}
-
-
-/* ---------- Xz Streams ---------- */
-
-void Xzs_Construct(CXzs *p)
-{
- p->num = p->numAllocated = 0;
- p->streams = 0;
-}
-
-void Xzs_Free(CXzs *p, ISzAllocPtr alloc)
-{
- size_t i;
- for (i = 0; i < p->num; i++)
- Xz_Free(&p->streams[i], alloc);
- ISzAlloc_Free(alloc, p->streams);
- p->num = p->numAllocated = 0;
- p->streams = 0;
-}
-
-UInt64 Xzs_GetNumBlocks(const CXzs *p)
-{
- UInt64 num = 0;
- size_t i;
- for (i = 0; i < p->num; i++)
- num += p->streams[i].numBlocks;
- return num;
-}
-
-UInt64 Xzs_GetUnpackSize(const CXzs *p)
-{
- UInt64 size = 0;
- size_t i;
- for (i = 0; i < p->num; i++)
- ADD_SIZE_CHECK(size, Xz_GetUnpackSize(&p->streams[i]));
- return size;
-}
-
-/*
-UInt64 Xzs_GetPackSize(const CXzs *p)
-{
- UInt64 size = 0;
- size_t i;
- for (i = 0; i < p->num; i++)
- ADD_SIZE_CHECK(size, Xz_GetTotalSize(&p->streams[i]));
- return size;
-}
-*/
-
-SRes Xzs_ReadBackward(CXzs *p, ILookInStream *stream, Int64 *startOffset, ICompressProgress *progress, ISzAllocPtr alloc)
-{
- Int64 endOffset = 0;
- RINOK(ILookInStream_Seek(stream, &endOffset, SZ_SEEK_END));
- *startOffset = endOffset;
- for (;;)
- {
- CXzStream st;
- SRes res;
- Xz_Construct(&st);
- res = Xz_ReadBackward(&st, stream, startOffset, alloc);
- st.startOffset = *startOffset;
- RINOK(res);
- if (p->num == p->numAllocated)
- {
- size_t newNum = p->num + p->num / 4 + 1;
- Byte *data = (Byte *)ISzAlloc_Alloc(alloc, newNum * sizeof(CXzStream));
- if (!data)
- return SZ_ERROR_MEM;
- p->numAllocated = newNum;
- if (p->num != 0)
- memcpy(data, p->streams, p->num * sizeof(CXzStream));
- ISzAlloc_Free(alloc, p->streams);
- p->streams = (CXzStream *)data;
- }
- p->streams[p->num++] = st;
- if (*startOffset == 0)
- break;
- RINOK(LookInStream_SeekTo(stream, *startOffset));
- if (progress && ICompressProgress_Progress(progress, endOffset - *startOffset, (UInt64)(Int64)-1) != SZ_OK)
- return SZ_ERROR_PROGRESS;
- }
- return SZ_OK;
-}
+/* XzIn.c - Xz input
+2023-04-02 : Igor Pavlov : Public domain */
+
+#include "Precomp.h"
+
+#include <string.h>
+
+#include "7zCrc.h"
+#include "CpuArch.h"
+#include "Xz.h"
+
+/*
+#define XZ_FOOTER_SIG_CHECK(p) (memcmp((p), XZ_FOOTER_SIG, XZ_FOOTER_SIG_SIZE) == 0)
+*/
+#define XZ_FOOTER_SIG_CHECK(p) ((p)[0] == XZ_FOOTER_SIG_0 && (p)[1] == XZ_FOOTER_SIG_1)
+
+
+SRes Xz_ReadHeader(CXzStreamFlags *p, ISeqInStreamPtr inStream)
+{
+ Byte sig[XZ_STREAM_HEADER_SIZE];
+ size_t processedSize = XZ_STREAM_HEADER_SIZE;
+ RINOK(SeqInStream_ReadMax(inStream, sig, &processedSize))
+ if (processedSize != XZ_STREAM_HEADER_SIZE
+ || memcmp(sig, XZ_SIG, XZ_SIG_SIZE) != 0)
+ return SZ_ERROR_NO_ARCHIVE;
+ return Xz_ParseHeader(p, sig);
+}
+
+#define READ_VARINT_AND_CHECK(buf, pos, size, res) \
+ { unsigned s = Xz_ReadVarInt(buf + pos, size - pos, res); \
+ if (s == 0) return SZ_ERROR_ARCHIVE; \
+ pos += s; }
+
+SRes XzBlock_ReadHeader(CXzBlock *p, ISeqInStreamPtr inStream, BoolInt *isIndex, UInt32 *headerSizeRes)
+{
+ Byte header[XZ_BLOCK_HEADER_SIZE_MAX];
+ unsigned headerSize;
+ *headerSizeRes = 0;
+ RINOK(SeqInStream_ReadByte(inStream, &header[0]))
+ headerSize = (unsigned)header[0];
+ if (headerSize == 0)
+ {
+ *headerSizeRes = 1;
+ *isIndex = True;
+ return SZ_OK;
+ }
+
+ *isIndex = False;
+ headerSize = (headerSize << 2) + 4;
+ *headerSizeRes = headerSize;
+ {
+ size_t processedSize = headerSize - 1;
+ RINOK(SeqInStream_ReadMax(inStream, header + 1, &processedSize))
+ if (processedSize != headerSize - 1)
+ return SZ_ERROR_INPUT_EOF;
+ }
+ return XzBlock_Parse(p, header);
+}
+
+#define ADD_SIZE_CHECK(size, val) \
+ { UInt64 newSize = size + (val); if (newSize < size) return XZ_SIZE_OVERFLOW; size = newSize; }
+
+UInt64 Xz_GetUnpackSize(const CXzStream *p)
+{
+ UInt64 size = 0;
+ size_t i;
+ for (i = 0; i < p->numBlocks; i++)
+ {
+ ADD_SIZE_CHECK(size, p->blocks[i].unpackSize)
+ }
+ return size;
+}
+
+UInt64 Xz_GetPackSize(const CXzStream *p)
+{
+ UInt64 size = 0;
+ size_t i;
+ for (i = 0; i < p->numBlocks; i++)
+ {
+ ADD_SIZE_CHECK(size, (p->blocks[i].totalSize + 3) & ~(UInt64)3)
+ }
+ return size;
+}
+
+/*
+SRes XzBlock_ReadFooter(CXzBlock *p, CXzStreamFlags f, ISeqInStreamPtr inStream)
+{
+ return SeqInStream_Read(inStream, p->check, XzFlags_GetCheckSize(f));
+}
+*/
+
+static SRes Xz_ReadIndex2(CXzStream *p, const Byte *buf, size_t size, ISzAllocPtr alloc)
+{
+ size_t numBlocks, pos = 1;
+ UInt32 crc;
+
+ if (size < 5 || buf[0] != 0)
+ return SZ_ERROR_ARCHIVE;
+
+ size -= 4;
+ crc = CrcCalc(buf, size);
+ if (crc != GetUi32(buf + size))
+ return SZ_ERROR_ARCHIVE;
+
+ {
+ UInt64 numBlocks64;
+ READ_VARINT_AND_CHECK(buf, pos, size, &numBlocks64)
+ numBlocks = (size_t)numBlocks64;
+ if (numBlocks != numBlocks64 || numBlocks * 2 > size)
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ Xz_Free(p, alloc);
+ if (numBlocks != 0)
+ {
+ size_t i;
+ p->numBlocks = numBlocks;
+ p->blocks = (CXzBlockSizes *)ISzAlloc_Alloc(alloc, sizeof(CXzBlockSizes) * numBlocks);
+ if (!p->blocks)
+ return SZ_ERROR_MEM;
+ for (i = 0; i < numBlocks; i++)
+ {
+ CXzBlockSizes *block = &p->blocks[i];
+ READ_VARINT_AND_CHECK(buf, pos, size, &block->totalSize)
+ READ_VARINT_AND_CHECK(buf, pos, size, &block->unpackSize)
+ if (block->totalSize == 0)
+ return SZ_ERROR_ARCHIVE;
+ }
+ }
+ while ((pos & 3) != 0)
+ if (buf[pos++] != 0)
+ return SZ_ERROR_ARCHIVE;
+ return (pos == size) ? SZ_OK : SZ_ERROR_ARCHIVE;
+}
+
+static SRes Xz_ReadIndex(CXzStream *p, ILookInStreamPtr stream, UInt64 indexSize, ISzAllocPtr alloc)
+{
+ SRes res;
+ size_t size;
+ Byte *buf;
+ if (indexSize > ((UInt32)1 << 31))
+ return SZ_ERROR_UNSUPPORTED;
+ size = (size_t)indexSize;
+ if (size != indexSize)
+ return SZ_ERROR_UNSUPPORTED;
+ buf = (Byte *)ISzAlloc_Alloc(alloc, size);
+ if (!buf)
+ return SZ_ERROR_MEM;
+ res = LookInStream_Read2(stream, buf, size, SZ_ERROR_UNSUPPORTED);
+ if (res == SZ_OK)
+ res = Xz_ReadIndex2(p, buf, size, alloc);
+ ISzAlloc_Free(alloc, buf);
+ return res;
+}
+
+static SRes LookInStream_SeekRead_ForArc(ILookInStreamPtr stream, UInt64 offset, void *buf, size_t size)
+{
+ RINOK(LookInStream_SeekTo(stream, offset))
+ return LookInStream_Read(stream, buf, size);
+ /* return LookInStream_Read2(stream, buf, size, SZ_ERROR_NO_ARCHIVE); */
+}
+
+static SRes Xz_ReadBackward(CXzStream *p, ILookInStreamPtr stream, Int64 *startOffset, ISzAllocPtr alloc)
+{
+ UInt64 indexSize;
+ Byte buf[XZ_STREAM_FOOTER_SIZE];
+ UInt64 pos = (UInt64)*startOffset;
+
+ if ((pos & 3) != 0 || pos < XZ_STREAM_FOOTER_SIZE)
+ return SZ_ERROR_NO_ARCHIVE;
+
+ pos -= XZ_STREAM_FOOTER_SIZE;
+ RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE))
+
+ if (!XZ_FOOTER_SIG_CHECK(buf + 10))
+ {
+ UInt32 total = 0;
+ pos += XZ_STREAM_FOOTER_SIZE;
+
+ for (;;)
+ {
+ size_t i;
+ #define TEMP_BUF_SIZE (1 << 10)
+ Byte temp[TEMP_BUF_SIZE];
+
+ i = (pos > TEMP_BUF_SIZE) ? TEMP_BUF_SIZE : (size_t)pos;
+ pos -= i;
+ RINOK(LookInStream_SeekRead_ForArc(stream, pos, temp, i))
+ total += (UInt32)i;
+ for (; i != 0; i--)
+ if (temp[i - 1] != 0)
+ break;
+ if (i != 0)
+ {
+ if ((i & 3) != 0)
+ return SZ_ERROR_NO_ARCHIVE;
+ pos += i;
+ break;
+ }
+ if (pos < XZ_STREAM_FOOTER_SIZE || total > (1 << 16))
+ return SZ_ERROR_NO_ARCHIVE;
+ }
+
+ if (pos < XZ_STREAM_FOOTER_SIZE)
+ return SZ_ERROR_NO_ARCHIVE;
+ pos -= XZ_STREAM_FOOTER_SIZE;
+ RINOK(LookInStream_SeekRead_ForArc(stream, pos, buf, XZ_STREAM_FOOTER_SIZE))
+ if (!XZ_FOOTER_SIG_CHECK(buf + 10))
+ return SZ_ERROR_NO_ARCHIVE;
+ }
+
+ p->flags = (CXzStreamFlags)GetBe16(buf + 8);
+
+ if (!XzFlags_IsSupported(p->flags))
+ return SZ_ERROR_UNSUPPORTED;
+
+ {
+ /* to eliminate GCC 6.3 warning:
+ dereferencing type-punned pointer will break strict-aliasing rules */
+ const Byte *buf_ptr = buf;
+ if (GetUi32(buf_ptr) != CrcCalc(buf + 4, 6))
+ return SZ_ERROR_ARCHIVE;
+ }
+
+ indexSize = ((UInt64)GetUi32(buf + 4) + 1) << 2;
+
+ if (pos < indexSize)
+ return SZ_ERROR_ARCHIVE;
+
+ pos -= indexSize;
+ RINOK(LookInStream_SeekTo(stream, pos))
+ RINOK(Xz_ReadIndex(p, stream, indexSize, alloc))
+
+ {
+ UInt64 totalSize = Xz_GetPackSize(p);
+ if (totalSize == XZ_SIZE_OVERFLOW
+ || totalSize >= ((UInt64)1 << 63)
+ || pos < totalSize + XZ_STREAM_HEADER_SIZE)
+ return SZ_ERROR_ARCHIVE;
+ pos -= (totalSize + XZ_STREAM_HEADER_SIZE);
+ RINOK(LookInStream_SeekTo(stream, pos))
+ *startOffset = (Int64)pos;
+ }
+ {
+ CXzStreamFlags headerFlags;
+ CSecToRead secToRead;
+ SecToRead_CreateVTable(&secToRead);
+ secToRead.realStream = stream;
+
+ RINOK(Xz_ReadHeader(&headerFlags, &secToRead.vt))
+ return (p->flags == headerFlags) ? SZ_OK : SZ_ERROR_ARCHIVE;
+ }
+}
+
+
+/* ---------- Xz Streams ---------- */
+
+void Xzs_Construct(CXzs *p)
+{
+ p->num = p->numAllocated = 0;
+ p->streams = 0;
+}
+
+void Xzs_Free(CXzs *p, ISzAllocPtr alloc)
+{
+ size_t i;
+ for (i = 0; i < p->num; i++)
+ Xz_Free(&p->streams[i], alloc);
+ ISzAlloc_Free(alloc, p->streams);
+ p->num = p->numAllocated = 0;
+ p->streams = 0;
+}
+
+UInt64 Xzs_GetNumBlocks(const CXzs *p)
+{
+ UInt64 num = 0;
+ size_t i;
+ for (i = 0; i < p->num; i++)
+ num += p->streams[i].numBlocks;
+ return num;
+}
+
+UInt64 Xzs_GetUnpackSize(const CXzs *p)
+{
+ UInt64 size = 0;
+ size_t i;
+ for (i = 0; i < p->num; i++)
+ {
+ ADD_SIZE_CHECK(size, Xz_GetUnpackSize(&p->streams[i]))
+ }
+ return size;
+}
+
+/*
+UInt64 Xzs_GetPackSize(const CXzs *p)
+{
+ UInt64 size = 0;
+ size_t i;
+ for (i = 0; i < p->num; i++)
+ {
+ ADD_SIZE_CHECK(size, Xz_GetTotalSize(&p->streams[i]))
+ }
+ return size;
+}
+*/
+
+SRes Xzs_ReadBackward(CXzs *p, ILookInStreamPtr stream, Int64 *startOffset, ICompressProgressPtr progress, ISzAllocPtr alloc)
+{
+ Int64 endOffset = 0;
+ RINOK(ILookInStream_Seek(stream, &endOffset, SZ_SEEK_END))
+ *startOffset = endOffset;
+ for (;;)
+ {
+ CXzStream st;
+ SRes res;
+ Xz_Construct(&st);
+ res = Xz_ReadBackward(&st, stream, startOffset, alloc);
+ st.startOffset = (UInt64)*startOffset;
+ RINOK(res)
+ if (p->num == p->numAllocated)
+ {
+ const size_t newNum = p->num + p->num / 4 + 1;
+ void *data = ISzAlloc_Alloc(alloc, newNum * sizeof(CXzStream));
+ if (!data)
+ return SZ_ERROR_MEM;
+ p->numAllocated = newNum;
+ if (p->num != 0)
+ memcpy(data, p->streams, p->num * sizeof(CXzStream));
+ ISzAlloc_Free(alloc, p->streams);
+ p->streams = (CXzStream *)data;
+ }
+ p->streams[p->num++] = st;
+ if (*startOffset == 0)
+ break;
+ RINOK(LookInStream_SeekTo(stream, (UInt64)*startOffset))
+ if (progress && ICompressProgress_Progress(progress, (UInt64)(endOffset - *startOffset), (UInt64)(Int64)-1) != SZ_OK)
+ return SZ_ERROR_PROGRESS;
+ }
+ return SZ_OK;
+}
diff --git a/C/var_clang.mak b/C/var_clang.mak
new file mode 100644
index 0000000..a6df26e
--- /dev/null
+++ b/C/var_clang.mak
@@ -0,0 +1,11 @@
+PLATFORM=
+O=b/c
+IS_X64=
+IS_X86=
+IS_ARM64=
+CROSS_COMPILE=
+MY_ARCH=
+USE_ASM=
+CC=$(CROSS_COMPILE)clang
+CXX=$(CROSS_COMPILE)clang++
+USE_CLANG=1
diff --git a/C/var_clang_arm64.mak b/C/var_clang_arm64.mak
new file mode 100644
index 0000000..4b35409
--- /dev/null
+++ b/C/var_clang_arm64.mak
@@ -0,0 +1,11 @@
+PLATFORM=arm64
+O=b/c_$(PLATFORM)
+IS_X64=
+IS_X86=
+IS_ARM64=1
+CROSS_COMPILE=
+MY_ARCH=
+USE_ASM=1
+CC=$(CROSS_COMPILE)clang
+CXX=$(CROSS_COMPILE)clang++
+USE_CLANG=1
diff --git a/C/var_clang_x64.mak b/C/var_clang_x64.mak
new file mode 100644
index 0000000..34e1b49
--- /dev/null
+++ b/C/var_clang_x64.mak
@@ -0,0 +1,11 @@
+PLATFORM=x64
+O=b/c_$(PLATFORM)
+IS_X64=1
+IS_X86=
+IS_ARM64=
+CROSS_COMPILE=
+MY_ARCH=
+USE_ASM=1
+CC=$(CROSS_COMPILE)clang
+CXX=$(CROSS_COMPILE)clang++
+USE_CLANG=1
diff --git a/C/var_clang_x86.mak b/C/var_clang_x86.mak
new file mode 100644
index 0000000..bd2317c
--- /dev/null
+++ b/C/var_clang_x86.mak
@@ -0,0 +1,11 @@
+PLATFORM=x86
+O=b/c_$(PLATFORM)
+IS_X64=
+IS_X86=1
+IS_ARM64=
+CROSS_COMPILE=
+MY_ARCH=-m32
+USE_ASM=1
+CC=$(CROSS_COMPILE)clang
+CXX=$(CROSS_COMPILE)clang++
+USE_CLANG=1
diff --git a/C/var_gcc.mak b/C/var_gcc.mak
new file mode 100644
index 0000000..664491c
--- /dev/null
+++ b/C/var_gcc.mak
@@ -0,0 +1,12 @@
+PLATFORM=
+O=b/g
+IS_X64=
+IS_X86=
+IS_ARM64=
+CROSS_COMPILE=
+MY_ARCH=
+USE_ASM=
+CC=$(CROSS_COMPILE)gcc
+CXX=$(CROSS_COMPILE)g++
+
+# -march=armv8-a+crc+crypto
diff --git a/C/var_gcc_arm64.mak b/C/var_gcc_arm64.mak
new file mode 100644
index 0000000..4bbb687
--- /dev/null
+++ b/C/var_gcc_arm64.mak
@@ -0,0 +1,12 @@
+PLATFORM=arm64
+O=b/g_$(PLATFORM)
+IS_X64=
+IS_X86=
+IS_ARM64=1
+CROSS_COMPILE=
+MY_ARCH=-mtune=cortex-a53
+USE_ASM=1
+CC=$(CROSS_COMPILE)gcc
+CXX=$(CROSS_COMPILE)g++
+
+# -march=armv8-a+crc+crypto
diff --git a/C/var_gcc_x64.mak b/C/var_gcc_x64.mak
new file mode 100644
index 0000000..1acf604
--- /dev/null
+++ b/C/var_gcc_x64.mak
@@ -0,0 +1,10 @@
+PLATFORM=x64
+O=b/g_$(PLATFORM)
+IS_X64=1
+IS_X86=
+IS_ARM64=
+CROSS_COMPILE=
+MY_ARCH=
+USE_ASM=1
+CC=$(CROSS_COMPILE)gcc
+CXX=$(CROSS_COMPILE)g++
diff --git a/C/var_gcc_x86.mak b/C/var_gcc_x86.mak
new file mode 100644
index 0000000..f0718ec
--- /dev/null
+++ b/C/var_gcc_x86.mak
@@ -0,0 +1,10 @@
+PLATFORM=x86
+O=b/g_$(PLATFORM)
+IS_X64=
+IS_X86=1
+IS_ARM64=
+CROSS_COMPILE=
+MY_ARCH=-m32
+USE_ASM=1
+CC=$(CROSS_COMPILE)gcc
+CXX=$(CROSS_COMPILE)g++
diff --git a/C/var_mac_arm64.mak b/C/var_mac_arm64.mak
new file mode 100644
index 0000000..adf5fa1
--- /dev/null
+++ b/C/var_mac_arm64.mak
@@ -0,0 +1,11 @@
+PLATFORM=arm64
+O=b/m_$(PLATFORM)
+IS_X64=
+IS_X86=
+IS_ARM64=1
+CROSS_COMPILE=
+MY_ARCH=-arch arm64
+USE_ASM=1
+CC=$(CROSS_COMPILE)clang
+CXX=$(CROSS_COMPILE)clang++
+USE_CLANG=1
diff --git a/C/var_mac_x64.mak b/C/var_mac_x64.mak
new file mode 100644
index 0000000..13d7aa7
--- /dev/null
+++ b/C/var_mac_x64.mak
@@ -0,0 +1,11 @@
+PLATFORM=x64
+O=b/m_$(PLATFORM)
+IS_X64=1
+IS_X86=
+IS_ARM64=
+CROSS_COMPILE=
+MY_ARCH=-arch x86_64
+USE_ASM=
+CC=$(CROSS_COMPILE)clang
+CXX=$(CROSS_COMPILE)clang++
+USE_CLANG=1
diff --git a/C/warn_clang.mak b/C/warn_clang.mak
new file mode 100644
index 0000000..0d6446d
--- /dev/null
+++ b/C/warn_clang.mak
@@ -0,0 +1 @@
+CFLAGS_WARN = -Weverything -Wfatal-errors
diff --git a/C/warn_clang_mac.mak b/C/warn_clang_mac.mak
new file mode 100644
index 0000000..44afc53
--- /dev/null
+++ b/C/warn_clang_mac.mak
@@ -0,0 +1 @@
+CFLAGS_WARN = -Weverything -Wfatal-errors -Wno-poison-system-directories
diff --git a/C/warn_gcc.mak b/C/warn_gcc.mak
new file mode 100644
index 0000000..7aab7a4
--- /dev/null
+++ b/C/warn_gcc.mak
@@ -0,0 +1,51 @@
+CFLAGS_WARN_GCC_4_5 = \
+
+CFLAGS_WARN_GCC_6 = \
+ -Waddress \
+ -Waggressive-loop-optimizations \
+ -Wattributes \
+ -Wbool-compare \
+ -Wcast-align \
+ -Wcomment \
+ -Wdiv-by-zero \
+ -Wduplicated-cond \
+ -Wformat-contains-nul \
+ -Winit-self \
+ -Wint-to-pointer-cast \
+ -Wunused \
+ -Wunused-macros \
+
+# -Wno-strict-aliasing
+
+CFLAGS_WARN_GCC_9 = \
+ -Waddress \
+ -Waddress-of-packed-member \
+ -Waggressive-loop-optimizations \
+ -Wattributes \
+ -Wbool-compare \
+ -Wbool-operation \
+ -Wcast-align \
+ -Wcast-align=strict \
+ -Wcomment \
+ -Wdangling-else \
+ -Wdiv-by-zero \
+ -Wduplicated-branches \
+ -Wduplicated-cond \
+ -Wformat-contains-nul \
+ -Wimplicit-fallthrough=5 \
+ -Winit-self \
+ -Wint-in-bool-context \
+ -Wint-to-pointer-cast \
+ -Wunused \
+ -Wunused-macros \
+ -Wconversion \
+
+# -Wno-sign-conversion \
+
+CFLAGS_WARN_GCC_PPMD_UNALIGNED = \
+ -Wno-strict-aliasing \
+
+
+CFLAGS_WARN = $(CFLAGS_WARN_GCC_9) \
+
+# $(CFLAGS_WARN_GCC_PPMD_UNALIGNED)
diff --git a/CPP/7zip/7zip.mak b/CPP/7zip/7zip.mak
index 7fec27c..6f4a0a1 100644
--- a/CPP/7zip/7zip.mak
+++ b/CPP/7zip/7zip.mak
@@ -1,240 +1,240 @@
-OBJS = \
- $O\StdAfx.obj \
- $(CURRENT_OBJS) \
- $(COMMON_OBJS) \
- $(WIN_OBJS) \
- $(WIN_CTRL_OBJS) \
- $(7ZIP_COMMON_OBJS) \
- $(AR_OBJS) \
- $(AR_COMMON_OBJS) \
- $(UI_COMMON_OBJS) \
- $(AGENT_OBJS) \
- $(CONSOLE_OBJS) \
- $(EXPLORER_OBJS) \
- $(FM_OBJS) \
- $(GUI_OBJS) \
- $(7Z_OBJS) \
- $(CAB_OBJS) \
- $(CHM_OBJS) \
- $(COM_OBJS) \
- $(ISO_OBJS) \
- $(NSIS_OBJS) \
- $(RAR_OBJS) \
- $(TAR_OBJS) \
- $(UDF_OBJS) \
- $(WIM_OBJS) \
- $(ZIP_OBJS) \
- $(COMPRESS_OBJS) \
- $(CRYPTO_OBJS) \
- $(C_OBJS) \
- $(ASM_OBJS) \
- $O\resource.res \
-
-!include "../../../Build.mak"
-
-# MAK_SINGLE_FILE = 1
-
-!IFDEF MAK_SINGLE_FILE
-
-!IFDEF CURRENT_OBJS
-$(CURRENT_OBJS): ./$(*B).cpp
- $(COMPL)
-!ENDIF
-
-
-!IFDEF COMMON_OBJS
-$(COMMON_OBJS): ../../../Common/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF WIN_OBJS
-$(WIN_OBJS): ../../../Windows/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF WIN_CTRL_OBJS
-$(WIN_CTRL_OBJS): ../../../Windows/Control/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF 7ZIP_COMMON_OBJS
-$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF AR_OBJS
-$(AR_OBJS): ../../Archive/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF AR_COMMON_OBJS
-$(AR_COMMON_OBJS): ../../Archive/Common/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF 7Z_OBJS
-$(7Z_OBJS): ../../Archive/7z/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF CAB_OBJS
-$(CAB_OBJS): ../../Archive/Cab/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF CHM_OBJS
-$(CHM_OBJS): ../../Archive/Chm/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF COM_OBJS
-$(COM_OBJS): ../../Archive/Com/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF ISO_OBJS
-$(ISO_OBJS): ../../Archive/Iso/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF NSIS_OBJS
-$(NSIS_OBJS): ../../Archive/Nsis/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF RAR_OBJS
-$(RAR_OBJS): ../../Archive/Rar/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF TAR_OBJS
-$(TAR_OBJS): ../../Archive/Tar/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF UDF_OBJS
-$(UDF_OBJS): ../../Archive/Udf/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF WIM_OBJS
-$(WIM_OBJS): ../../Archive/Wim/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF ZIP_OBJS
-$(ZIP_OBJS): ../../Archive/Zip/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF COMPRESS_OBJS
-$(COMPRESS_OBJS): ../../Compress/$(*B).cpp
- $(COMPL_O2)
-!ENDIF
-
-!IFDEF CRYPTO_OBJS
-$(CRYPTO_OBJS): ../../Crypto/$(*B).cpp
- $(COMPL_O2)
-!ENDIF
-
-!IFDEF UI_COMMON_OBJS
-$(UI_COMMON_OBJS): ../../UI/Common/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF AGENT_OBJS
-$(AGENT_OBJS): ../../UI/Agent/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF CONSOLE_OBJS
-$(CONSOLE_OBJS): ../../UI/Console/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF EXPLORER_OBJS
-$(EXPLORER_OBJS): ../../UI/Explorer/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF FM_OBJS
-$(FM_OBJS): ../../UI/FileManager/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF GUI_OBJS
-$(GUI_OBJS): ../../UI/GUI/$(*B).cpp
- $(COMPL)
-!ENDIF
-
-!IFDEF C_OBJS
-$(C_OBJS): ../../../../C/$(*B).c
- $(COMPL_O2)
-!ENDIF
-
-
-!ELSE
-
-{.}.cpp{$O}.obj::
- $(COMPLB)
-{../../../Common}.cpp{$O}.obj::
- $(COMPLB)
-{../../../Windows}.cpp{$O}.obj::
- $(COMPLB)
-{../../../Windows/Control}.cpp{$O}.obj::
- $(COMPLB)
-{../../Common}.cpp{$O}.obj::
- $(COMPLB)
-
-{../../UI/Common}.cpp{$O}.obj::
- $(COMPLB)
-{../../UI/Agent}.cpp{$O}.obj::
- $(COMPLB)
-{../../UI/Console}.cpp{$O}.obj::
- $(COMPLB)
-{../../UI/Explorer}.cpp{$O}.obj::
- $(COMPLB)
-{../../UI/FileManager}.cpp{$O}.obj::
- $(COMPLB)
-{../../UI/GUI}.cpp{$O}.obj::
- $(COMPLB)
-
-
-{../../Archive}.cpp{$O}.obj::
- $(COMPLB)
-{../../Archive/Common}.cpp{$O}.obj::
- $(COMPLB)
-
-{../../Archive/7z}.cpp{$O}.obj::
- $(COMPLB)
-{../../Archive/Cab}.cpp{$O}.obj::
- $(COMPLB)
-{../../Archive/Chm}.cpp{$O}.obj::
- $(COMPLB)
-{../../Archive/Com}.cpp{$O}.obj::
- $(COMPLB)
-{../../Archive/Iso}.cpp{$O}.obj::
- $(COMPLB)
-{../../Archive/Nsis}.cpp{$O}.obj::
- $(COMPLB)
-{../../Archive/Rar}.cpp{$O}.obj::
- $(COMPLB)
-{../../Archive/Tar}.cpp{$O}.obj::
- $(COMPLB)
-{../../Archive/Udf}.cpp{$O}.obj::
- $(COMPLB)
-{../../Archive/Wim}.cpp{$O}.obj::
- $(COMPLB)
-{../../Archive/Zip}.cpp{$O}.obj::
- $(COMPLB)
-
-{../../Compress}.cpp{$O}.obj::
- $(COMPLB_O2)
-{../../Crypto}.cpp{$O}.obj::
- $(COMPLB_O2)
-{../../../../C}.c{$O}.obj::
- $(CCOMPLB)
-
-!ENDIF
-
-!include "Asm.mak"
+OBJS = \
+ $O\StdAfx.obj \
+ $(CURRENT_OBJS) \
+ $(COMMON_OBJS) \
+ $(WIN_OBJS) \
+ $(WIN_CTRL_OBJS) \
+ $(7ZIP_COMMON_OBJS) \
+ $(UI_COMMON_OBJS) \
+ $(AGENT_OBJS) \
+ $(CONSOLE_OBJS) \
+ $(EXPLORER_OBJS) \
+ $(FM_OBJS) \
+ $(GUI_OBJS) \
+ $(AR_COMMON_OBJS) \
+ $(AR_OBJS) \
+ $(7Z_OBJS) \
+ $(CAB_OBJS) \
+ $(CHM_OBJS) \
+ $(COM_OBJS) \
+ $(ISO_OBJS) \
+ $(NSIS_OBJS) \
+ $(RAR_OBJS) \
+ $(TAR_OBJS) \
+ $(UDF_OBJS) \
+ $(WIM_OBJS) \
+ $(ZIP_OBJS) \
+ $(COMPRESS_OBJS) \
+ $(CRYPTO_OBJS) \
+ $(C_OBJS) \
+ $(ASM_OBJS) \
+ $O\resource.res \
+
+!include "../../../Build.mak"
+
+# MAK_SINGLE_FILE = 1
+
+!IFDEF MAK_SINGLE_FILE
+
+!IFDEF CURRENT_OBJS
+$(CURRENT_OBJS): ./$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+
+!IFDEF COMMON_OBJS
+$(COMMON_OBJS): ../../../Common/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF WIN_OBJS
+$(WIN_OBJS): ../../../Windows/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF WIN_CTRL_OBJS
+$(WIN_CTRL_OBJS): ../../../Windows/Control/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF 7ZIP_COMMON_OBJS
+$(7ZIP_COMMON_OBJS): ../../Common/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF AR_OBJS
+$(AR_OBJS): ../../Archive/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF AR_COMMON_OBJS
+$(AR_COMMON_OBJS): ../../Archive/Common/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF 7Z_OBJS
+$(7Z_OBJS): ../../Archive/7z/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF CAB_OBJS
+$(CAB_OBJS): ../../Archive/Cab/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF CHM_OBJS
+$(CHM_OBJS): ../../Archive/Chm/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF COM_OBJS
+$(COM_OBJS): ../../Archive/Com/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF ISO_OBJS
+$(ISO_OBJS): ../../Archive/Iso/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF NSIS_OBJS
+$(NSIS_OBJS): ../../Archive/Nsis/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF RAR_OBJS
+$(RAR_OBJS): ../../Archive/Rar/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF TAR_OBJS
+$(TAR_OBJS): ../../Archive/Tar/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF UDF_OBJS
+$(UDF_OBJS): ../../Archive/Udf/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF WIM_OBJS
+$(WIM_OBJS): ../../Archive/Wim/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF ZIP_OBJS
+$(ZIP_OBJS): ../../Archive/Zip/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF COMPRESS_OBJS
+$(COMPRESS_OBJS): ../../Compress/$(*B).cpp
+ $(COMPL_O2)
+!ENDIF
+
+!IFDEF CRYPTO_OBJS
+$(CRYPTO_OBJS): ../../Crypto/$(*B).cpp
+ $(COMPL_O2)
+!ENDIF
+
+!IFDEF UI_COMMON_OBJS
+$(UI_COMMON_OBJS): ../../UI/Common/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF AGENT_OBJS
+$(AGENT_OBJS): ../../UI/Agent/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF CONSOLE_OBJS
+$(CONSOLE_OBJS): ../../UI/Console/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF EXPLORER_OBJS
+$(EXPLORER_OBJS): ../../UI/Explorer/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF FM_OBJS
+$(FM_OBJS): ../../UI/FileManager/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF GUI_OBJS
+$(GUI_OBJS): ../../UI/GUI/$(*B).cpp
+ $(COMPL)
+!ENDIF
+
+!IFDEF C_OBJS
+$(C_OBJS): ../../../../C/$(*B).c
+ $(COMPL_O2)
+!ENDIF
+
+
+!ELSE
+
+{.}.cpp{$O}.obj::
+ $(COMPLB)
+{../../../Common}.cpp{$O}.obj::
+ $(COMPLB)
+{../../../Windows}.cpp{$O}.obj::
+ $(COMPLB)
+{../../../Windows/Control}.cpp{$O}.obj::
+ $(COMPLB)
+{../../Common}.cpp{$O}.obj::
+ $(COMPLB)
+
+{../../UI/Common}.cpp{$O}.obj::
+ $(COMPLB)
+{../../UI/Agent}.cpp{$O}.obj::
+ $(COMPLB)
+{../../UI/Console}.cpp{$O}.obj::
+ $(COMPLB)
+{../../UI/Explorer}.cpp{$O}.obj::
+ $(COMPLB)
+{../../UI/FileManager}.cpp{$O}.obj::
+ $(COMPLB)
+{../../UI/GUI}.cpp{$O}.obj::
+ $(COMPLB)
+
+
+{../../Archive}.cpp{$O}.obj::
+ $(COMPLB)
+{../../Archive/Common}.cpp{$O}.obj::
+ $(COMPLB)
+
+{../../Archive/7z}.cpp{$O}.obj::
+ $(COMPLB)
+{../../Archive/Cab}.cpp{$O}.obj::
+ $(COMPLB)
+{../../Archive/Chm}.cpp{$O}.obj::
+ $(COMPLB)
+{../../Archive/Com}.cpp{$O}.obj::
+ $(COMPLB)
+{../../Archive/Iso}.cpp{$O}.obj::
+ $(COMPLB)
+{../../Archive/Nsis}.cpp{$O}.obj::
+ $(COMPLB)
+{../../Archive/Rar}.cpp{$O}.obj::
+ $(COMPLB)
+{../../Archive/Tar}.cpp{$O}.obj::
+ $(COMPLB)
+{../../Archive/Udf}.cpp{$O}.obj::
+ $(COMPLB)
+{../../Archive/Wim}.cpp{$O}.obj::
+ $(COMPLB)
+{../../Archive/Zip}.cpp{$O}.obj::
+ $(COMPLB)
+
+{../../Compress}.cpp{$O}.obj::
+ $(COMPLB_O2)
+{../../Crypto}.cpp{$O}.obj::
+ $(COMPLB_O2)
+{../../../../C}.c{$O}.obj::
+ $(CCOMPLB)
+
+!ENDIF
+
+!include "Asm.mak"
diff --git a/CPP/7zip/7zip_gcc.mak b/CPP/7zip/7zip_gcc.mak
new file mode 100644
index 0000000..8bf0594
--- /dev/null
+++ b/CPP/7zip/7zip_gcc.mak
@@ -0,0 +1,1294 @@
+# USE_CLANG=1
+# USE_ASM = 1
+# IS_X64 = 1
+# MY_ARCH =
+# USE_ASM=
+# USE_JWASM=1
+
+MY_ARCH_2 = $(MY_ARCH)
+
+MY_ASM = asmc
+ifdef USE_JWASM
+MY_ASM = jwasm
+endif
+
+ifndef RC
+RC=windres.exe --target=pe-x86-64
+RC=windres.exe -F pe-i386
+RC=windres.exe
+endif
+
+
+PROGPATH = $(O)/$(PROG)
+PROGPATH_STATIC = $(O)/$(PROG)s
+
+
+ifneq ($(CC), xlc)
+CFLAGS_WARN_WALL = -Werror -Wall -Wextra
+endif
+
+# for object file
+# -Wa,-aln=test.s
+# -save-temps
+CFLAGS_BASE_LIST = -c
+# CFLAGS_BASE_LIST = -S
+CFLAGS_BASE = -O2 $(CFLAGS_BASE_LIST) $(CFLAGS_WARN_WALL) $(CFLAGS_WARN) \
+ -DNDEBUG -D_REENTRANT -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE \
+ -fPIC
+
+FLAGS_FLTO = -ffunction-sections
+FLAGS_FLTO = -flto
+FLAGS_FLTO =
+#
+# -DZ7_AFFINITY_DISABLE
+
+
+ifdef SystemDrive
+IS_MINGW = 1
+else
+ifdef SYSTEMDRIVE
+# ifdef OS
+IS_MINGW = 1
+endif
+endif
+
+ifdef IS_MINGW
+LDFLAGS_STATIC_2 = -static
+else
+ifndef DEF_FILE
+ifndef IS_NOT_STANDALONE
+ifndef MY_DYNAMIC_LINK
+ifneq ($(CC), clang)
+LDFLAGS_STATIC_2 =
+# -static
+# -static-libstdc++ -static-libgcc
+endif
+endif
+endif
+endif
+endif
+
+LDFLAGS_STATIC = -DNDEBUG $(LDFLAGS_STATIC_2)
+
+ifndef O
+ ifdef IS_MINGW
+ O=_o
+ else
+ O=_o
+ endif
+endif
+
+
+ifdef DEF_FILE
+
+
+ifdef IS_MINGW
+SHARED_EXT=.dll
+LDFLAGS = -shared -DEF $(DEF_FILE) $(LDFLAGS_STATIC)
+else
+SHARED_EXT=.so
+LDFLAGS = -shared -fPIC $(LDFLAGS_STATIC)
+CC_SHARED=-fPIC
+endif
+
+
+else
+
+LDFLAGS = $(LDFLAGS_STATIC)
+# -s is not required for clang, do we need it for GCC ???
+
+#-static -static-libgcc -static-libstdc++
+
+ifdef IS_MINGW
+SHARED_EXT=.exe
+else
+SHARED_EXT=
+endif
+
+endif
+
+
+PROGPATH = $(O)/$(PROG)$(SHARED_EXT)
+PROGPATH_STATIC = $(O)/$(PROG)s$(SHARED_EXT)
+
+ifdef IS_MINGW
+
+ifdef MSYSTEM
+RM = rm -f
+MY_MKDIR=mkdir -p
+DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS)
+LIB_HTMLHELP=-lhtmlhelp
+else
+RM = del
+MY_MKDIR=mkdir
+DEL_OBJ_EXE = -$(RM) $(O)\*.o $(O)\$(PROG).exe $(O)\$(PROG).dll
+endif
+
+LIB2_GUI = -lOle32 -lGdi32 -lComctl32 -lComdlg32 -lShell32 $(LIB_HTMLHELP)
+LIB2 = -loleaut32 -luuid -ladvapi32 -lUser32 $(LIB2_GUI)
+
+CXXFLAGS_EXTRA = -DUNICODE -D_UNICODE
+# -Wno-delete-non-virtual-dtor
+
+
+else
+
+RM = rm -f
+MY_MKDIR=mkdir -p
+DEL_OBJ_EXE = -$(RM) $(PROGPATH) $(PROGPATH_STATIC) $(OBJS)
+
+# CFLAGS_BASE := $(CFLAGS_BASE) -DZ7_ST
+# CXXFLAGS_EXTRA = -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE
+
+# LOCAL_LIBS=-lpthread
+# LOCAL_LIBS_DLL=$(LOCAL_LIBS) -ldl
+LIB2 = -lpthread -ldl
+
+
+endif
+
+
+
+CFLAGS = $(MY_ARCH_2) $(LOCAL_FLAGS) $(CFLAGS_BASE2) $(CFLAGS_BASE) $(FLAGS_FLTO) $(CC_SHARED) -o $@
+
+
+ifdef IS_MINGW
+
+ifdef IS_X64
+AFLAGS_ABI = -win64
+else
+AFLAGS_ABI = -coff -DABI_CDECL
+# -DABI_CDECL
+# -DABI_LINUX
+# -DABI_CDECL
+endif
+AFLAGS = -nologo $(AFLAGS_ABI) -Fo$(O)/$(basename $(<F)).o
+
+else # IS_MINGW
+
+ifdef IS_X64
+AFLAGS_ABI = -elf64 -DABI_LINUX
+else
+AFLAGS_ABI = -elf -DABI_LINUX -DABI_CDECL
+# -DABI_CDECL
+# -DABI_LINUX
+# -DABI_CDECL
+endif
+AFLAGS = -nologo $(AFLAGS_ABI) -Fo$(O)/
+
+endif # IS_MINGW
+
+
+
+ifdef USE_ASM
+CONSOLE_ASM_FLAGS=-DZ7_7ZIP_ASM
+else
+CONSOLE_ASM_FLAGS=
+endif
+
+CXX_WARN_FLAGS =
+#-Wno-invalid-offsetof
+#-Wno-reorder
+
+CXXFLAGS = $(MY_ARCH_2) $(LOCAL_FLAGS) $(CXXFLAGS_BASE2) $(CFLAGS_BASE) $(FLAGS_FLTO) $(CXXFLAGS_EXTRA) $(CC_SHARED) $(CXX_WARN_FLAGS) $(CXX_STD_FLAGS) -o $@
+
+STATIC_TARGET=
+ifdef COMPL_STATIC
+STATIC_TARGET=$(PROGPATH_STATIC)
+endif
+
+
+all: $(O) $(PROGPATH) $(STATIC_TARGET)
+
+$(O):
+ $(MY_MKDIR) $(O)
+
+# LDFLAGS3= -flto
+# LDFLAGS3= -Wl,--gc-sections
+# -Wl,--print-gc-sections
+
+ifneq ($(CC), $(CROSS_COMPILE)clang)
+LFLAGS_STRIP = -s
+endif
+
+LFLAGS_ALL = $(LFLAGS_STRIP) $(MY_ARCH_2) $(LDFLAGS) $(FLAGS_FLTO) $(LD_arch) $(OBJS) $(MY_LIBS) $(LIB2)
+
+# -s : GCC : Remove all symbol table and relocation information from the executable.
+# -s : CLANG : unsupported
+# -s
+
+$(PROGPATH): $(OBJS)
+ $(CXX) -o $(PROGPATH) $(LFLAGS_ALL)
+
+$(PROGPATH_STATIC): $(OBJS)
+ $(CXX) -static -o $(PROGPATH_STATIC) $(LFLAGS_ALL)
+
+# -s strips debug sections from executable in GCC
+
+
+
+
+ifndef NO_DEFAULT_RES
+$O/resource.o: resource.rc
+ $(RC) $(RFLAGS) resource.rc $@
+
+# windres.exe : in old version mingw:
+# $(RFLAGS) resource.rc $O/resource.o
+# windres.exe : in new version mingw:
+# $(RC) $(RFLAGS) resource.rc -FO $@
+
+
+endif
+
+$O/LzmaAlone.o: LzmaAlone.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+$O/CommandLineParser.o: ../../../Common/CommandLineParser.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/CRC.o: ../../../Common/CRC.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+$O/CrcReg.o: ../../../Common/CrcReg.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+$O/DynLimBuf.o: ../../../Common/DynLimBuf.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/IntToString.o: ../../../Common/IntToString.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Lang.o: ../../../Common/Lang.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ListFileUtils.o: ../../../Common/ListFileUtils.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/LzFindPrepare.o: ../../../Common/LzFindPrepare.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MyMap.o: ../../../Common/MyMap.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MyString.o: ../../../Common/MyString.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MyVector.o: ../../../Common/MyVector.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MyWindows.o: ../../../Common/MyWindows.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MyWindows2.o: ../../../Common/MyWindows2.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MyXml.o: ../../../Common/MyXml.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/NewHandler.o: ../../../Common/NewHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Random.o: ../../../Common/Random.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Sha1Prepare.o: ../../../Common/Sha1Prepare.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Sha1Reg.o: ../../../Common/Sha1Reg.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Sha256Prepare.o: ../../../Common/Sha256Prepare.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Sha256Reg.o: ../../../Common/Sha256Reg.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/StdInStream.o: ../../../Common/StdInStream.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/StdOutStream.o: ../../../Common/StdOutStream.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/StringConvert.o: ../../../Common/StringConvert.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/StringToInt.o: ../../../Common/StringToInt.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/TextConfig.o: ../../../Common/TextConfig.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/UTFConvert.o: ../../../Common/UTFConvert.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Wildcard.o: ../../../Common/Wildcard.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/XzCrc64Init.o: ../../../Common/XzCrc64Init.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/XzCrc64Reg.o: ../../../Common/XzCrc64Reg.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+
+$O/Clipboard.o: ../../../Windows/Clipboard.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/COM.o: ../../../Windows/COM.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/CommonDialog.o: ../../../Windows/CommonDialog.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Console.o: ../../../Windows/Console.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/DLL.o: ../../../Windows/DLL.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ErrorMsg.o: ../../../Windows/ErrorMsg.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FileDir.o: ../../../Windows/FileDir.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FileFind.o: ../../../Windows/FileFind.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+$O/FileIO.o: ../../../Windows/FileIO.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+$O/FileLink.o: ../../../Windows/FileLink.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FileMapping.o: ../../../Windows/FileMapping.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FileName.o: ../../../Windows/FileName.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FileSystem.o: ../../../Windows/FileSystem.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MemoryGlobal.o: ../../../Windows/MemoryGlobal.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MemoryLock.o: ../../../Windows/MemoryLock.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Menu.o: ../../../Windows/Menu.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/NationalTime.o: ../../../Windows/NationalTime.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Net.o: ../../../Windows/Net.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ProcessMessages.o: ../../../Windows/ProcessMessages.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ProcessUtils.o: ../../../Windows/ProcessUtils.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PropVariant.o: ../../../Windows/PropVariant.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PropVariantConv.o: ../../../Windows/PropVariantConv.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PropVariantUtils.o: ../../../Windows/PropVariantUtils.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Registry.o: ../../../Windows/Registry.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ResourceString.o: ../../../Windows/ResourceString.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/SecurityUtils.o: ../../../Windows/SecurityUtils.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Shell.o: ../../../Windows/Shell.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Synchronization.o: ../../../Windows/Synchronization.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/System.o: ../../../Windows/System.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/SystemInfo.o: ../../../Windows/SystemInfo.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/TimeUtils.o: ../../../Windows/TimeUtils.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Window.o: ../../../Windows/Window.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+
+$O/ComboBox.o: ../../../Windows/Control/ComboBox.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Dialog.o: ../../../Windows/Control/Dialog.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ImageList.o: ../../../Windows/Control/ImageList.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ListView.o: ../../../Windows/Control/ListView.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PropertyPage.o: ../../../Windows/Control/PropertyPage.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Window2.o: ../../../Windows/Control/Window2.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+$O/CreateCoder.o: ../../Common/CreateCoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/CWrappers.o: ../../Common/CWrappers.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FilePathAutoRename.o: ../../Common/FilePathAutoRename.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FileStreams.o: ../../Common/FileStreams.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FilterCoder.o: ../../Common/FilterCoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/InBuffer.o: ../../Common/InBuffer.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/InOutTempBuffer.o: ../../Common/InOutTempBuffer.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/LimitedStreams.o: ../../Common/LimitedStreams.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/LockedStream.o: ../../Common/LockedStream.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MemBlocks.o: ../../Common/MemBlocks.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MethodId.o: ../../Common/MethodId.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MethodProps.o: ../../Common/MethodProps.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MultiOutStream.o: ../../Common/MultiOutStream.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/OffsetStream.o: ../../Common/OffsetStream.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/OutBuffer.o: ../../Common/OutBuffer.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/OutMemStream.o: ../../Common/OutMemStream.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ProgressMt.o: ../../Common/ProgressMt.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ProgressUtils.o: ../../Common/ProgressUtils.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PropId.o: ../../Common/PropId.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/StreamBinder.o: ../../Common/StreamBinder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/StreamObjects.o: ../../Common/StreamObjects.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/StreamUtils.o: ../../Common/StreamUtils.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/UniqBlocks.o: ../../Common/UniqBlocks.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/VirtThread.o: ../../Common/VirtThread.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+$O/ApfsHandler.o: ../../Archive/ApfsHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ApmHandler.o: ../../Archive/ApmHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ArchiveExports.o: ../../Archive/ArchiveExports.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ArHandler.o: ../../Archive/ArHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ArjHandler.o: ../../Archive/ArjHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/AvbHandler.o: ../../Archive/AvbHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Base64Handler.o: ../../Archive/Base64Handler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Bz2Handler.o: ../../Archive/Bz2Handler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ComHandler.o: ../../Archive/ComHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/CpioHandler.o: ../../Archive/CpioHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/CramfsHandler.o: ../../Archive/CramfsHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/DeflateProps.o: ../../Archive/DeflateProps.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/DllExports.o: ../../Archive/DllExports.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/DllExports2.o: ../../Archive/DllExports2.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/DmgHandler.o: ../../Archive/DmgHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ElfHandler.o: ../../Archive/ElfHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ExtHandler.o: ../../Archive/ExtHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FatHandler.o: ../../Archive/FatHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FlvHandler.o: ../../Archive/FlvHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/GptHandler.o: ../../Archive/GptHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/GzHandler.o: ../../Archive/GzHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/HandlerCont.o: ../../Archive/HandlerCont.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/HfsHandler.o: ../../Archive/HfsHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/IhexHandler.o: ../../Archive/IhexHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/LpHandler.o: ../../Archive/LpHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/LzhHandler.o: ../../Archive/LzhHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/LzmaHandler.o: ../../Archive/LzmaHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MachoHandler.o: ../../Archive/MachoHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MbrHandler.o: ../../Archive/MbrHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MslzHandler.o: ../../Archive/MslzHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MubHandler.o: ../../Archive/MubHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/NtfsHandler.o: ../../Archive/NtfsHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PeHandler.o: ../../Archive/PeHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PpmdHandler.o: ../../Archive/PpmdHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/QcowHandler.o: ../../Archive/QcowHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/RpmHandler.o: ../../Archive/RpmHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/SparseHandler.o: ../../Archive/SparseHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/SplitHandler.o: ../../Archive/SplitHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/SquashfsHandler.o: ../../Archive/SquashfsHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/SwfHandler.o: ../../Archive/SwfHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/UefiHandler.o: ../../Archive/UefiHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/VdiHandler.o: ../../Archive/VdiHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/VhdHandler.o: ../../Archive/VhdHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/VhdxHandler.o: ../../Archive/VhdxHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/VmdkHandler.o: ../../Archive/VmdkHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/XarHandler.o: ../../Archive/XarHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/XzHandler.o: ../../Archive/XzHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ZHandler.o: ../../Archive/ZHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+$O/7zCompressionMode.o: ../../Archive/7z/7zCompressionMode.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/7zDecode.o: ../../Archive/7z/7zDecode.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/7zEncode.o: ../../Archive/7z/7zEncode.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/7zExtract.o: ../../Archive/7z/7zExtract.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/7zFolderInStream.o: ../../Archive/7z/7zFolderInStream.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/7zHandler.o: ../../Archive/7z/7zHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/7zHandlerOut.o: ../../Archive/7z/7zHandlerOut.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/7zHeader.o: ../../Archive/7z/7zHeader.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/7zIn.o: ../../Archive/7z/7zIn.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/7zOut.o: ../../Archive/7z/7zOut.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/7zProperties.o: ../../Archive/7z/7zProperties.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/7zRegister.o: ../../Archive/7z/7zRegister.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/7zSpecStream.o: ../../Archive/7z/7zSpecStream.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/7zUpdate.o: ../../Archive/7z/7zUpdate.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+$O/CabBlockInStream.o: ../../Archive/Cab/CabBlockInStream.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/CabHandler.o: ../../Archive/Cab/CabHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/CabHeader.o: ../../Archive/Cab/CabHeader.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/CabIn.o: ../../Archive/Cab/CabIn.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/CabRegister.o: ../../Archive/Cab/CabRegister.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+$O/ChmHandler.o: ../../Archive/Chm/ChmHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ChmIn.o: ../../Archive/Chm/ChmIn.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+$O/IsoHandler.o: ../../Archive/Iso/IsoHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/IsoHeader.o: ../../Archive/Iso/IsoHeader.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/IsoIn.o: ../../Archive/Iso/IsoIn.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/IsoRegister.o: ../../Archive/Iso/IsoRegister.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+$O/NsisDecode.o: ../../Archive/Nsis/NsisDecode.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/NsisHandler.o: ../../Archive/Nsis/NsisHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/NsisIn.o: ../../Archive/Nsis/NsisIn.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/NsisRegister.o: ../../Archive/Nsis/NsisRegister.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+$O/Rar5Handler.o: ../../Archive/Rar/Rar5Handler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/RarHandler.o: ../../Archive/Rar/RarHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+$O/TarHandler.o: ../../Archive/Tar/TarHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/TarHandlerOut.o: ../../Archive/Tar/TarHandlerOut.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/TarHeader.o: ../../Archive/Tar/TarHeader.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/TarIn.o: ../../Archive/Tar/TarIn.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/TarOut.o: ../../Archive/Tar/TarOut.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/TarRegister.o: ../../Archive/Tar/TarRegister.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/TarUpdate.o: ../../Archive/Tar/TarUpdate.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+$O/UdfHandler.o: ../../Archive/Udf/UdfHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/UdfIn.o: ../../Archive/Udf/UdfIn.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+$O/WimHandler.o: ../../Archive/Wim/WimHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/WimHandlerOut.o: ../../Archive/Wim/WimHandlerOut.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/WimIn.o: ../../Archive/Wim/WimIn.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/WimRegister.o: ../../Archive/Wim/WimRegister.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+$O/ZipAddCommon.o: ../../Archive/Zip/ZipAddCommon.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ZipHandler.o: ../../Archive/Zip/ZipHandler.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ZipHandlerOut.o: ../../Archive/Zip/ZipHandlerOut.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ZipIn.o: ../../Archive/Zip/ZipIn.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ZipItem.o: ../../Archive/Zip/ZipItem.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ZipOut.o: ../../Archive/Zip/ZipOut.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ZipUpdate.o: ../../Archive/Zip/ZipUpdate.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ZipRegister.o: ../../Archive/Zip/ZipRegister.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+$O/Bcj2Coder.o: ../../Compress/Bcj2Coder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Bcj2Register.o: ../../Compress/Bcj2Register.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/BcjCoder.o: ../../Compress/BcjCoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/BcjRegister.o: ../../Compress/BcjRegister.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/BitlDecoder.o: ../../Compress/BitlDecoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/BranchMisc.o: ../../Compress/BranchMisc.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/BranchRegister.o: ../../Compress/BranchRegister.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ByteSwap.o: ../../Compress/ByteSwap.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/BZip2Crc.o: ../../Compress/BZip2Crc.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/BZip2Decoder.o: ../../Compress/BZip2Decoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/BZip2Encoder.o: ../../Compress/BZip2Encoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/BZip2Register.o: ../../Compress/BZip2Register.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/CodecExports.o: ../../Compress/CodecExports.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/CopyCoder.o: ../../Compress/CopyCoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/CopyRegister.o: ../../Compress/CopyRegister.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Deflate64Register.o: ../../Compress/Deflate64Register.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/DeflateDecoder.o: ../../Compress/DeflateDecoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/DeflateEncoder.o: ../../Compress/DeflateEncoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/DeflateRegister.o: ../../Compress/DeflateRegister.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/DeltaFilter.o: ../../Compress/DeltaFilter.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/DllExports2Compress.o: ../../Compress/DllExports2Compress.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/DllExportsCompress.o: ../../Compress/DllExportsCompress.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ImplodeDecoder.o: ../../Compress/ImplodeDecoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ImplodeHuffmanDecoder.o: ../../Compress/ImplodeHuffmanDecoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/LzfseDecoder.o: ../../Compress/LzfseDecoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/LzhDecoder.o: ../../Compress/LzhDecoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Lzma2Decoder.o: ../../Compress/Lzma2Decoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Lzma2Encoder.o: ../../Compress/Lzma2Encoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Lzma2Register.o: ../../Compress/Lzma2Register.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/LzmaDecoder.o: ../../Compress/LzmaDecoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/LzmaEncoder.o: ../../Compress/LzmaEncoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/LzmaRegister.o: ../../Compress/LzmaRegister.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/LzmsDecoder.o: ../../Compress/LzmsDecoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/LzOutWindow.o: ../../Compress/LzOutWindow.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/LzxDecoder.o: ../../Compress/LzxDecoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PpmdDecoder.o: ../../Compress/PpmdDecoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PpmdEncoder.o: ../../Compress/PpmdEncoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PpmdRegister.o: ../../Compress/PpmdRegister.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PpmdZip.o: ../../Compress/PpmdZip.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/QuantumDecoder.o: ../../Compress/QuantumDecoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Rar1Decoder.o: ../../Compress/Rar1Decoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Rar2Decoder.o: ../../Compress/Rar2Decoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Rar3Decoder.o: ../../Compress/Rar3Decoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Rar3Vm.o: ../../Compress/Rar3Vm.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Rar5Decoder.o: ../../Compress/Rar5Decoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/RarCodecsRegister.o: ../../Compress/RarCodecsRegister.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ShrinkDecoder.o: ../../Compress/ShrinkDecoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/XpressDecoder.o: ../../Compress/XpressDecoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/XzDecoder.o: ../../Compress/XzDecoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/XzEncoder.o: ../../Compress/XzEncoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ZDecoder.o: ../../Compress/ZDecoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ZlibDecoder.o: ../../Compress/ZlibDecoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ZlibEncoder.o: ../../Compress/ZlibEncoder.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+$O/7zAes.o: ../../Crypto/7zAes.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/7zAesRegister.o: ../../Crypto/7zAesRegister.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/HmacSha1.o: ../../Crypto/HmacSha1.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/HmacSha256.o: ../../Crypto/HmacSha256.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MyAes.o: ../../Crypto/MyAes.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MyAesReg.o: ../../Crypto/MyAesReg.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Pbkdf2HmacSha1.o: ../../Crypto/Pbkdf2HmacSha1.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/RandGen.o: ../../Crypto/RandGen.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Rar20Crypto.o: ../../Crypto/Rar20Crypto.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Rar5Aes.o: ../../Crypto/Rar5Aes.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/RarAes.o: ../../Crypto/RarAes.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/WzAes.o: ../../Crypto/WzAes.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ZipCrypto.o: ../../Crypto/ZipCrypto.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ZipStrong.o: ../../Crypto/ZipStrong.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+
+$O/CoderMixer2.o: ../../Archive/Common/CoderMixer2.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/DummyOutStream.o: ../../Archive/Common/DummyOutStream.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FindSignature.o: ../../Archive/Common/FindSignature.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/HandlerOut.o: ../../Archive/Common/HandlerOut.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/InStreamWithCRC.o: ../../Archive/Common/InStreamWithCRC.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ItemNameUtils.o: ../../Archive/Common/ItemNameUtils.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MultiStream.o: ../../Archive/Common/MultiStream.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/OutStreamWithCRC.o: ../../Archive/Common/OutStreamWithCRC.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/OutStreamWithSha1.o: ../../Archive/Common/OutStreamWithSha1.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ParseProperties.o: ../../Archive/Common/ParseProperties.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+
+
+$O/ArchiveCommandLine.o: ../../UI/Common/ArchiveCommandLine.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ArchiveExtractCallback.o: ../../UI/Common/ArchiveExtractCallback.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ArchiveName.o: ../../UI/Common/ArchiveName.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ArchiveOpenCallback.o: ../../UI/Common/ArchiveOpenCallback.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Bench.o: ../../UI/Common/Bench.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/CompressCall.o: ../../UI/Common/CompressCall.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/CompressCall2.o: ../../UI/Common/CompressCall2.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/DefaultName.o: ../../UI/Common/DefaultName.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/EnumDirItems.o: ../../UI/Common/EnumDirItems.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Extract.o: ../../UI/Common/Extract.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ExtractingFilePath.o: ../../UI/Common/ExtractingFilePath.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/HashCalc.o: ../../UI/Common/HashCalc.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/LoadCodecs.o: ../../UI/Common/LoadCodecs.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/OpenArchive.o: ../../UI/Common/OpenArchive.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PropIDUtils.o: ../../UI/Common/PropIDUtils.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/SetProperties.o: ../../UI/Common/SetProperties.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/SortUtils.o: ../../UI/Common/SortUtils.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/TempFiles.o: ../../UI/Common/TempFiles.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Update.o: ../../UI/Common/Update.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/UpdateAction.o: ../../UI/Common/UpdateAction.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/UpdateCallback.o: ../../UI/Common/UpdateCallback.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/UpdatePair.o: ../../UI/Common/UpdatePair.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/UpdateProduce.o: ../../UI/Common/UpdateProduce.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/WorkDir.o: ../../UI/Common/WorkDir.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ZipRegistry.o: ../../UI/Common/ZipRegistry.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+$O/Agent.o: ../../UI/Agent/Agent.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/AgentOut.o: ../../UI/Agent/AgentOut.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/AgentProxy.o: ../../UI/Agent/AgentProxy.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ArchiveFolder.o: ../../UI/Agent/ArchiveFolder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ArchiveFolderOpen.o: ../../UI/Agent/ArchiveFolderOpen.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ArchiveFolderOut.o: ../../UI/Agent/ArchiveFolderOut.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/UpdateCallbackAgent.o: ../../UI/Agent/UpdateCallbackAgent.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+$O/Client7z.o: ../../UI/Client7z/Client7z.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+$O/BenchCon.o: ../../UI/Console/BenchCon.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ConsoleClose.o: ../../UI/Console/ConsoleClose.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ExtractCallbackConsole.o: ../../UI/Console/ExtractCallbackConsole.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/HashCon.o: ../../UI/Console/HashCon.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/List.o: ../../UI/Console/List.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Main.o: ../../UI/Console/Main.cpp ../../../../C/7zVersion.h
+ $(CXX) $(CXXFLAGS) $(CONSOLE_VARIANT_FLAGS) $(CONSOLE_ASM_FLAGS) $<
+$O/MainAr.o: ../../UI/Console/MainAr.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/OpenCallbackConsole.o: ../../UI/Console/OpenCallbackConsole.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PercentPrinter.o: ../../UI/Console/PercentPrinter.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/UpdateCallbackConsole.o: ../../UI/Console/UpdateCallbackConsole.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/UserInputUtils.o: ../../UI/Console/UserInputUtils.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+$O/BenchmarkDialog.o: ../../UI/GUI/BenchmarkDialog.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/CompressDialog.o: ../../UI/GUI/CompressDialog.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ExtractDialog.o: ../../UI/GUI/ExtractDialog.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ExtractGUI.o: ../../UI/GUI/ExtractGUI.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/GUI.o: ../../UI/GUI/GUI.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/HashGUI.o: ../../UI/GUI/HashGUI.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/UpdateCallbackGUI.o: ../../UI/GUI/UpdateCallbackGUI.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/UpdateCallbackGUI2.o: ../../UI/GUI/UpdateCallbackGUI2.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/UpdateGUI.o: ../../UI/GUI/UpdateGUI.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+$O/MyMessages.o: ../../UI/Explorer/MyMessages.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ContextMenu.o: ../../UI/Explorer/ContextMenu.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/DllExportsExplorer.o: ../../UI/Explorer/DllExportsExplorer.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/RegistryContextMenu.o: ../../UI/Explorer/RegistryContextMenu.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+
+$O/AboutDialog.o: ../../UI/FileManager/AboutDialog.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/AltStreamsFolder.o: ../../UI/FileManager/AltStreamsFolder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/App.o: ../../UI/FileManager/App.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/BrowseDialog.o: ../../UI/FileManager/BrowseDialog.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ClassDefs.o: ../../UI/FileManager/ClassDefs.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ComboDialog.o: ../../UI/FileManager/ComboDialog.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/CopyDialog.o: ../../UI/FileManager/CopyDialog.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/EditDialog.o: ../../UI/FileManager/EditDialog.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/EditPage.o: ../../UI/FileManager/EditPage.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/EnumFormatEtc.o: ../../UI/FileManager/EnumFormatEtc.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ExtractCallback.o: ../../UI/FileManager/ExtractCallback.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FileFolderPluginOpen.o: ../../UI/FileManager/FileFolderPluginOpen.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FilePlugins.o: ../../UI/FileManager/FilePlugins.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FM.o: ../../UI/FileManager/FM.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FoldersPage.o: ../../UI/FileManager/FoldersPage.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FormatUtils.o: ../../UI/FileManager/FormatUtils.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FSDrives.o: ../../UI/FileManager/FSDrives.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FSFolder.o: ../../UI/FileManager/FSFolder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/FSFolderCopy.o: ../../UI/FileManager/FSFolderCopy.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/HelpUtils.o: ../../UI/FileManager/HelpUtils.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/LangPage.o: ../../UI/FileManager/LangPage.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/LangUtils.o: ../../UI/FileManager/LangUtils.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/LinkDialog.o: ../../UI/FileManager/LinkDialog.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ListViewDialog.o: ../../UI/FileManager/ListViewDialog.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MenuPage.o: ../../UI/FileManager/MenuPage.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MessagesDialog.o: ../../UI/FileManager/MessagesDialog.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/MyLoadMenu.o: ../../UI/FileManager/MyLoadMenu.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/NetFolder.o: ../../UI/FileManager/NetFolder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/OpenCallback.o: ../../UI/FileManager/OpenCallback.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/OptionsDialog.o: ../../UI/FileManager/OptionsDialog.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/OverwriteDialog.o: ../../UI/FileManager/OverwriteDialog.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/Panel.o: ../../UI/FileManager/Panel.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PanelCopy.o: ../../UI/FileManager/PanelCopy.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PanelCrc.o: ../../UI/FileManager/PanelCrc.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PanelDrag.o: ../../UI/FileManager/PanelDrag.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PanelFolderChange.o: ../../UI/FileManager/PanelFolderChange.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PanelItemOpen.o: ../../UI/FileManager/PanelItemOpen.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PanelItems.o: ../../UI/FileManager/PanelItems.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PanelKey.o: ../../UI/FileManager/PanelKey.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PanelListNotify.o: ../../UI/FileManager/PanelListNotify.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PanelMenu.o: ../../UI/FileManager/PanelMenu.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PanelOperations.o: ../../UI/FileManager/PanelOperations.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PanelSelect.o: ../../UI/FileManager/PanelSelect.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PanelSort.o: ../../UI/FileManager/PanelSort.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PanelSplitFile.o: ../../UI/FileManager/PanelSplitFile.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PasswordDialog.o: ../../UI/FileManager/PasswordDialog.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ProgramLocation.o: ../../UI/FileManager/ProgramLocation.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ProgressDialog.o: ../../UI/FileManager/ProgressDialog.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ProgressDialog2.o: ../../UI/FileManager/ProgressDialog2.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/PropertyName.o: ../../UI/FileManager/PropertyName.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/RegistryAssociations.o: ../../UI/FileManager/RegistryAssociations.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/RegistryPlugins.o: ../../UI/FileManager/RegistryPlugins.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/RegistryUtils.o: ../../UI/FileManager/RegistryUtils.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/RootFolder.o: ../../UI/FileManager/RootFolder.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/SettingsPage.o: ../../UI/FileManager/SettingsPage.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/SplitDialog.o: ../../UI/FileManager/SplitDialog.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/SplitUtils.o: ../../UI/FileManager/SplitUtils.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/StringUtils.o: ../../UI/FileManager/StringUtils.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/SysIconUtils.o: ../../UI/FileManager/SysIconUtils.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/SystemPage.o: ../../UI/FileManager/SystemPage.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/TextPairs.o: ../../UI/FileManager/TextPairs.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/UpdateCallback100.o: ../../UI/FileManager/UpdateCallback100.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/VerCtrl.o: ../../UI/FileManager/VerCtrl.cpp
+ $(CXX) $(CXXFLAGS) $<
+$O/ViewSettings.o: ../../UI/FileManager/ViewSettings.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+$O/SfxCon.o: ../../Bundles/SFXCon/SfxCon.cpp
+ $(CXX) $(CXXFLAGS) $<
+
+$O/$(FILE_IO).o: ../../../$(FILE_IO_2).cpp
+ $(CXX) $(CXXFLAGS) $<
+
+
+
+
+
+
+$O/7zAlloc.o: ../../../../C/7zAlloc.c
+ $(CC) $(CFLAGS) $<
+$O/7zArcIn.o: ../../../../C/7zArcIn.c
+ $(CC) $(CFLAGS) $<
+$O/7zBuf.o: ../../../../C/7zBuf.c
+ $(CC) $(CFLAGS) $<
+$O/7zBuf2.o: ../../../../C/7zBuf2.c
+ $(CC) $(CFLAGS) $<
+$O/7zCrc.o: ../../../../C/7zCrc.c
+ $(CC) $(CFLAGS) $<
+$O/7zDec.o: ../../../../C/7zDec.c
+ $(CC) $(CFLAGS) $<
+$O/7zFile.o: ../../../../C/7zFile.c
+ $(CC) $(CFLAGS) $<
+$O/7zStream.o: ../../../../C/7zStream.c
+ $(CC) $(CFLAGS) $<
+$O/Aes.o: ../../../../C/Aes.c
+ $(CC) $(CFLAGS) $<
+$O/Alloc.o: ../../../../C/Alloc.c
+ $(CC) $(CFLAGS) $<
+$O/Bcj2.o: ../../../../C/Bcj2.c
+ $(CC) $(CFLAGS) $<
+$O/Bcj2Enc.o: ../../../../C/Bcj2Enc.c
+ $(CC) $(CFLAGS) $<
+$O/Blake2s.o: ../../../../C/Blake2s.c
+ $(CC) $(CFLAGS) $<
+$O/Bra.o: ../../../../C/Bra.c
+ $(CC) $(CFLAGS) $<
+$O/Bra86.o: ../../../../C/Bra86.c
+ $(CC) $(CFLAGS) $<
+$O/BraIA64.o: ../../../../C/BraIA64.c
+ $(CC) $(CFLAGS) $<
+$O/BwtSort.o: ../../../../C/BwtSort.c
+ $(CC) $(CFLAGS) $<
+
+$O/CpuArch.o: ../../../../C/CpuArch.c
+ $(CC) $(CFLAGS) $<
+$O/Delta.o: ../../../../C/Delta.c
+ $(CC) $(CFLAGS) $<
+$O/DllSecur.o: ../../../../C/DllSecur.c
+ $(CC) $(CFLAGS) $<
+$O/HuffEnc.o: ../../../../C/HuffEnc.c
+ $(CC) $(CFLAGS) $<
+$O/LzFind.o: ../../../../C/LzFind.c
+ $(CC) $(CFLAGS) $<
+
+# ifdef MT_FILES
+$O/LzFindMt.o: ../../../../C/LzFindMt.c
+ $(CC) $(CFLAGS) $<
+
+$O/Threads.o: ../../../../C/Threads.c
+ $(CC) $(CFLAGS) $<
+# endif
+
+$O/LzmaEnc.o: ../../../../C/LzmaEnc.c
+ $(CC) $(CFLAGS) $<
+$O/Lzma86Dec.o: ../../../../C/Lzma86Dec.c
+ $(CC) $(CFLAGS) $<
+$O/Lzma86Enc.o: ../../../../C/Lzma86Enc.c
+ $(CC) $(CFLAGS) $<
+$O/Lzma2Dec.o: ../../../../C/Lzma2Dec.c
+ $(CC) $(CFLAGS) $<
+$O/Lzma2DecMt.o: ../../../../C/Lzma2DecMt.c
+ $(CC) $(CFLAGS) $<
+$O/Lzma2Enc.o: ../../../../C/Lzma2Enc.c
+ $(CC) $(CFLAGS) $<
+$O/LzmaLib.o: ../../../../C/LzmaLib.c
+ $(CC) $(CFLAGS) $<
+$O/MtCoder.o: ../../../../C/MtCoder.c
+ $(CC) $(CFLAGS) $<
+$O/MtDec.o: ../../../../C/MtDec.c
+ $(CC) $(CFLAGS) $<
+$O/Ppmd7.o: ../../../../C/Ppmd7.c
+ $(CC) $(CFLAGS) $<
+$O/Ppmd7aDec.o: ../../../../C/Ppmd7aDec.c
+ $(CC) $(CFLAGS) $<
+$O/Ppmd7Dec.o: ../../../../C/Ppmd7Dec.c
+ $(CC) $(CFLAGS) $<
+$O/Ppmd7Enc.o: ../../../../C/Ppmd7Enc.c
+ $(CC) $(CFLAGS) $<
+$O/Ppmd8.o: ../../../../C/Ppmd8.c
+ $(CC) $(CFLAGS) $<
+$O/Ppmd8Dec.o: ../../../../C/Ppmd8Dec.c
+ $(CC) $(CFLAGS) $<
+$O/Ppmd8Enc.o: ../../../../C/Ppmd8Enc.c
+ $(CC) $(CFLAGS) $<
+$O/Sha1.o: ../../../../C/Sha1.c
+ $(CC) $(CFLAGS) $<
+$O/Sha256.o: ../../../../C/Sha256.c
+ $(CC) $(CFLAGS) $<
+$O/Sort.o: ../../../../C/Sort.c
+ $(CC) $(CFLAGS) $<
+$O/SwapBytes.o: ../../../../C/SwapBytes.c
+ $(CC) $(CFLAGS) $<
+$O/Xz.o: ../../../../C/Xz.c
+ $(CC) $(CFLAGS) $<
+$O/XzCrc64.o: ../../../../C/XzCrc64.c
+ $(CC) $(CFLAGS) $<
+$O/XzDec.o: ../../../../C/XzDec.c
+ $(CC) $(CFLAGS) $<
+$O/XzEnc.o: ../../../../C/XzEnc.c
+ $(CC) $(CFLAGS) $<
+$O/XzIn.o: ../../../../C/XzIn.c
+ $(CC) $(CFLAGS) $<
+
+
+ifdef USE_ASM
+ifdef IS_X64
+USE_X86_ASM=1
+USE_X64_ASM=1
+else
+ifdef IS_X86
+USE_X86_ASM=1
+endif
+endif
+endif
+
+ifdef USE_X86_ASM
+$O/7zCrcOpt.o: ../../../../Asm/x86/7zCrcOpt.asm
+ $(MY_ASM) $(AFLAGS) $<
+$O/XzCrc64Opt.o: ../../../../Asm/x86/XzCrc64Opt.asm
+ $(MY_ASM) $(AFLAGS) $<
+$O/Sha1Opt.o: ../../../../Asm/x86/Sha1Opt.asm
+ $(MY_ASM) $(AFLAGS) $<
+$O/Sha256Opt.o: ../../../../Asm/x86/Sha256Opt.asm
+ $(MY_ASM) $(AFLAGS) $<
+
+ifndef USE_JWASM
+USE_X86_ASM_AES=1
+endif
+
+else
+$O/7zCrcOpt.o: ../../../../C/7zCrcOpt.c
+ $(CC) $(CFLAGS) $<
+$O/XzCrc64Opt.o: ../../../../C/XzCrc64Opt.c
+ $(CC) $(CFLAGS) $<
+$O/Sha1Opt.o: ../../../../C/Sha1Opt.c
+ $(CC) $(CFLAGS) $<
+$O/Sha256Opt.o: ../../../../C/Sha256Opt.c
+ $(CC) $(CFLAGS) $<
+endif
+
+
+ifdef USE_X86_ASM_AES
+$O/AesOpt.o: ../../../../Asm/x86/AesOpt.asm
+ $(MY_ASM) $(AFLAGS) $<
+else
+$O/AesOpt.o: ../../../../C/AesOpt.c
+ $(CC) $(CFLAGS) $<
+endif
+
+
+ifdef USE_X64_ASM
+$O/LzFindOpt.o: ../../../../Asm/x86/LzFindOpt.asm
+ $(MY_ASM) $(AFLAGS) $<
+else
+$O/LzFindOpt.o: ../../../../C/LzFindOpt.c
+ $(CC) $(CFLAGS) $<
+endif
+
+ifdef USE_LZMA_DEC_ASM
+
+ifdef IS_X64
+$O/LzmaDecOpt.o: ../../../../Asm/x86/LzmaDecOpt.asm
+ $(MY_ASM) $(AFLAGS) $<
+endif
+
+ifdef IS_ARM64
+$O/LzmaDecOpt.o: ../../../../Asm/arm64/LzmaDecOpt.S ../../../../Asm/arm64/7zAsm.S
+ $(CC) $(CFLAGS) $<
+endif
+
+$O/LzmaDec.o: ../../../../C/LzmaDec.c
+ $(CC) $(CFLAGS) -DZ7_LZMA_DEC_OPT $<
+
+else
+
+$O/LzmaDec.o: ../../../../C/LzmaDec.c
+ $(CC) $(CFLAGS) $<
+
+endif
+
+
+
+
+$O/7zMain.o: ../../../../C/Util/7z/7zMain.c
+ $(CC) $(CFLAGS) $<
+$O/LzmaUtil.o: ../../../../C/Util/Lzma/LzmaUtil.c
+ $(CC) $(CFLAGS) $<
+
+ifneq ($(CC), xlc)
+SHOW_PREDEF=-dM
+else
+SHOW_PREDEF= -qshowmacros=pre
+endif
+
+predef_cc:
+ $(CC) $(CFLAGS) -E $(SHOW_PREDEF) ../../../../C/CpuArch.c > predef_cc_log
+# $(CC) $(CFLAGS) -E -dM - < /dev/null
+predef_cxx:
+ $(CXX) $(CFLAGS) -E $(SHOW_PREDEF) ../../../Common/CrcReg.cpp > predef_cxx_log
+
+predef: predef_cc predef_cxx
+
+
+clean:
+ -$(DEL_OBJ_EXE)
diff --git a/CPP/7zip/Aes.mak b/CPP/7zip/Aes.mak
index 3d0d877..7d8da2d 100644
--- a/CPP/7zip/Aes.mak
+++ b/CPP/7zip/Aes.mak
@@ -1,7 +1,10 @@
-C_OBJS = $(C_OBJS) \
- $O\Aes.obj
-
-!IF "$(PLATFORM)" != "ia64" && "$(PLATFORM)" != "mips" && "$(PLATFORM)" != "arm" && "$(PLATFORM)" != "arm64"
-ASM_OBJS = $(ASM_OBJS) \
- $O\AesOpt.obj
-!ENDIF
+C_OBJS = $(C_OBJS) \
+ $O\Aes.obj
+
+!IF defined(USE_C_AES) || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64"
+C_OBJS = $(C_OBJS) \
+ $O\AesOpt.obj
+!ELSEIF "$(PLATFORM)" != "ia64" && "$(PLATFORM)" != "mips" && "$(PLATFORM)" != "arm" && "$(PLATFORM)" != "arm64"
+ASM_OBJS = $(ASM_OBJS) \
+ $O\AesOpt.obj
+!ENDIF
diff --git a/CPP/7zip/Archive/7z/7z.dsp b/CPP/7zip/Archive/7z/7z.dsp
new file mode 100644
index 0000000..2c3e144
--- /dev/null
+++ b/CPP/7zip/Archive/7z/7z.dsp
@@ -0,0 +1,638 @@
+# Microsoft Developer Studio Project File - Name="7z" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=7z - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "7z.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "7z.mak" CFG="7z - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "7z - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "7z - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /Gz /MD /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /D "Z7_EXTERNAL_CODECS" /Yu"StdAfx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Util\Formats\7z.dll" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /Gz /MTd /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /D "Z7_EXTERNAL_CODECS" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\Formats\7z.dll" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "7z - Win32 Release"
+# Name "7z - Win32 Debug"
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\Archive.def
+# End Source File
+# Begin Source File
+
+SOURCE=..\ArchiveExports.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CodecExports.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\DllExports2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"StdAfx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "Engine"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\7zCompressionMode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zCompressionMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zDecode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zEncode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zEncode.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zExtract.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zFolderInStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zFolderInStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zHandlerOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zHeader.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zOut.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zProperties.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zSpecStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zSpecStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zUpdate.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zUpdate.h
+# End Source File
+# End Group
+# Begin Group "Interface"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\IArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ICoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IMyUnknown.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IPassword.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IProgress.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\PropID.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\Buffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynamicBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.h
+# End Source File
+# End Group
+# Begin Group "Archive Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\Common\CoderMixer2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\CoderMixer2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\HandlerOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\HandlerOut.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\InStreamWithCRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\InStreamWithCRC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ItemNameUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ItemNameUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\MultiStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\MultiStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\OutStreamWithCRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\OutStreamWithCRC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ParseProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ParseProperties.h
+# End Source File
+# End Group
+# Begin Group "7-Zip Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InOutTempBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InOutTempBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LockedStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LockedStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodId.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodId.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\PropId.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\RegisterArc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\RegisterCodec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamBinder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamBinder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\VirtThread.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\VirtThread.h
+# End Source File
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Handle.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Thread.h
+# End Source File
+# End Group
+# Begin Group "Compress"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.h
+# End Source File
+# End Group
+# Begin Group "C"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrcOpt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/CPP/7zip/Archive/7z/7z.dsw b/CPP/7zip/Archive/7z/7z.dsw
new file mode 100644
index 0000000..702a86c
--- /dev/null
+++ b/CPP/7zip/Archive/7z/7z.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "7z"=".\7z.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/Archive/7z/7zCompressionMode.cpp b/CPP/7zip/Archive/7z/7zCompressionMode.cpp
index 232c638..6774fc4 100644
--- a/CPP/7zip/Archive/7z/7zCompressionMode.cpp
+++ b/CPP/7zip/Archive/7z/7zCompressionMode.cpp
@@ -1,3 +1,3 @@
-// CompressionMethod.cpp
-
-#include "StdAfx.h"
+// CompressionMethod.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Archive/7z/7zCompressionMode.h b/CPP/7zip/Archive/7z/7zCompressionMode.h
index 2360017..ac1f6ad 100644
--- a/CPP/7zip/Archive/7z/7zCompressionMode.h
+++ b/CPP/7zip/Archive/7z/7zCompressionMode.h
@@ -1,76 +1,91 @@
-// 7zCompressionMode.h
-
-#ifndef __7Z_COMPRESSION_MODE_H
-#define __7Z_COMPRESSION_MODE_H
-
-#include "../../Common/MethodId.h"
-#include "../../Common/MethodProps.h"
-
-namespace NArchive {
-namespace N7z {
-
-struct CMethodFull: public CMethodProps
-{
- CMethodId Id;
- UInt32 NumStreams;
- int CodecIndex;
-
- CMethodFull(): CodecIndex(-1) {}
- bool IsSimpleCoder() const { return NumStreams == 1; }
-};
-
-struct CBond2
-{
- UInt32 OutCoder;
- UInt32 OutStream;
- UInt32 InCoder;
-};
-
-struct CCompressionMethodMode
-{
- /*
- if (Bonds.Empty()), then default bonds must be created
- if (Filter_was_Inserted)
- {
- Methods[0] is filter method
- Bonds don't contain bonds for filter (these bonds must be created)
- }
- */
-
- CObjectVector<CMethodFull> Methods;
- CRecordVector<CBond2> Bonds;
-
- bool IsThereBond_to_Coder(unsigned coderIndex) const
- {
- FOR_VECTOR(i, Bonds)
- if (Bonds[i].InCoder == coderIndex)
- return true;
- return false;
- }
-
- bool DefaultMethod_was_Inserted;
- bool Filter_was_Inserted;
-
- #ifndef _7ZIP_ST
- UInt32 NumThreads;
- bool MultiThreadMixer;
- #endif
-
- bool PasswordIsDefined;
- UString Password;
-
- bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); }
- CCompressionMethodMode():
- DefaultMethod_was_Inserted(false),
- Filter_was_Inserted(false),
- PasswordIsDefined(false)
- #ifndef _7ZIP_ST
- , NumThreads(1)
- , MultiThreadMixer(true)
- #endif
- {}
-};
-
-}}
-
-#endif
+// 7zCompressionMode.h
+
+#ifndef ZIP7_INC_7Z_COMPRESSION_MODE_H
+#define ZIP7_INC_7Z_COMPRESSION_MODE_H
+
+#include "../../Common/MethodId.h"
+#include "../../Common/MethodProps.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CMethodFull: public CMethodProps
+{
+ CMethodId Id;
+ UInt32 NumStreams;
+ int CodecIndex;
+ UInt32 NumThreads;
+ bool Set_NumThreads;
+
+ CMethodFull(): CodecIndex(-1), NumThreads(1), Set_NumThreads(false) {}
+ bool IsSimpleCoder() const { return NumStreams == 1; }
+};
+
+struct CBond2
+{
+ UInt32 OutCoder;
+ UInt32 OutStream;
+ UInt32 InCoder;
+};
+
+struct CCompressionMethodMode
+{
+ /*
+ if (Bonds.Empty()), then default bonds must be created
+ if (Filter_was_Inserted)
+ {
+ Methods[0] is filter method
+ Bonds don't contain bonds for filter (these bonds must be created)
+ }
+ */
+
+ CObjectVector<CMethodFull> Methods;
+ CRecordVector<CBond2> Bonds;
+
+ bool IsThereBond_to_Coder(unsigned coderIndex) const
+ {
+ FOR_VECTOR(i, Bonds)
+ if (Bonds[i].InCoder == coderIndex)
+ return true;
+ return false;
+ }
+
+ bool DefaultMethod_was_Inserted;
+ bool Filter_was_Inserted;
+
+ #ifndef Z7_ST
+ UInt32 NumThreads;
+ bool NumThreads_WasForced;
+ bool MultiThreadMixer;
+ #endif
+
+ UInt64 MemoryUsageLimit;
+ bool MemoryUsageLimit_WasSet;
+
+ bool PasswordIsDefined;
+ UString Password; // _Wipe
+
+ bool IsEmpty() const { return (Methods.IsEmpty() && !PasswordIsDefined); }
+ CCompressionMethodMode():
+ DefaultMethod_was_Inserted(false)
+ , Filter_was_Inserted(false)
+ #ifndef Z7_ST
+ , NumThreads(1)
+ , NumThreads_WasForced(false)
+ , MultiThreadMixer(true)
+ #endif
+ , MemoryUsageLimit((UInt64)1 << 30)
+ , MemoryUsageLimit_WasSet(false)
+ , PasswordIsDefined(false)
+ {}
+
+#ifdef Z7_CPP_IS_SUPPORTED_default
+ CCompressionMethodMode(const CCompressionMethodMode &) = default;
+ CCompressionMethodMode& operator =(const CCompressionMethodMode &) = default;
+#endif
+ ~CCompressionMethodMode() { Password.Wipe_and_Empty(); }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/7z/7zDecode.cpp b/CPP/7zip/Archive/7z/7zDecode.cpp
index f61ad4a..5420dce 100644
--- a/CPP/7zip/Archive/7z/7zDecode.cpp
+++ b/CPP/7zip/Archive/7z/7zDecode.cpp
@@ -1,569 +1,599 @@
-// 7zDecode.cpp
-
-#include "StdAfx.h"
-
-#include "../../Common/LimitedStreams.h"
-#include "../../Common/ProgressUtils.h"
-#include "../../Common/StreamObjects.h"
-
-#include "7zDecode.h"
-
-namespace NArchive {
-namespace N7z {
-
-class CDecProgress:
- public ICompressProgressInfo,
- public CMyUnknownImp
-{
- CMyComPtr<ICompressProgressInfo> _progress;
-public:
- CDecProgress(ICompressProgressInfo *progress): _progress(progress) {}
-
- MY_UNKNOWN_IMP1(ICompressProgressInfo)
- STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
-};
-
-STDMETHODIMP CDecProgress::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 *outSize)
-{
- return _progress->SetRatioInfo(NULL, outSize);
-}
-
-static void Convert_FolderInfo_to_BindInfo(const CFolderEx &folder, CBindInfoEx &bi)
-{
- bi.Clear();
-
- bi.Bonds.ClearAndSetSize(folder.Bonds.Size());
- unsigned i;
- for (i = 0; i < folder.Bonds.Size(); i++)
- {
- NCoderMixer2::CBond &bond = bi.Bonds[i];
- const N7z::CBond &folderBond = folder.Bonds[i];
- bond.PackIndex = folderBond.PackIndex;
- bond.UnpackIndex = folderBond.UnpackIndex;
- }
-
- bi.Coders.ClearAndSetSize(folder.Coders.Size());
- bi.CoderMethodIDs.ClearAndSetSize(folder.Coders.Size());
- for (i = 0; i < folder.Coders.Size(); i++)
- {
- const CCoderInfo &coderInfo = folder.Coders[i];
- bi.Coders[i].NumStreams = coderInfo.NumStreams;
- bi.CoderMethodIDs[i] = coderInfo.MethodID;
- }
-
- /*
- if (!bi.SetUnpackCoder())
- throw 1112;
- */
- bi.UnpackCoder = folder.UnpackCoder;
- bi.PackStreams.ClearAndSetSize(folder.PackStreams.Size());
- for (i = 0; i < folder.PackStreams.Size(); i++)
- bi.PackStreams[i] = folder.PackStreams[i];
-}
-
-static inline bool AreCodersEqual(
- const NCoderMixer2::CCoderStreamsInfo &a1,
- const NCoderMixer2::CCoderStreamsInfo &a2)
-{
- return (a1.NumStreams == a2.NumStreams);
-}
-
-static inline bool AreBondsEqual(
- const NCoderMixer2::CBond &a1,
- const NCoderMixer2::CBond &a2)
-{
- return
- (a1.PackIndex == a2.PackIndex) &&
- (a1.UnpackIndex == a2.UnpackIndex);
-}
-
-static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2)
-{
- if (a1.Coders.Size() != a2.Coders.Size())
- return false;
- unsigned i;
- for (i = 0; i < a1.Coders.Size(); i++)
- if (!AreCodersEqual(a1.Coders[i], a2.Coders[i]))
- return false;
-
- if (a1.Bonds.Size() != a2.Bonds.Size())
- return false;
- for (i = 0; i < a1.Bonds.Size(); i++)
- if (!AreBondsEqual(a1.Bonds[i], a2.Bonds[i]))
- return false;
-
- for (i = 0; i < a1.CoderMethodIDs.Size(); i++)
- if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i])
- return false;
-
- if (a1.PackStreams.Size() != a2.PackStreams.Size())
- return false;
- for (i = 0; i < a1.PackStreams.Size(); i++)
- if (a1.PackStreams[i] != a2.PackStreams[i])
- return false;
-
- /*
- if (a1.UnpackCoder != a2.UnpackCoder)
- return false;
- */
- return true;
-}
-
-CDecoder::CDecoder(bool useMixerMT):
- _bindInfoPrev_Defined(false),
- _useMixerMT(useMixerMT)
-{}
-
-
-struct CLockedInStream:
- public IUnknown,
- public CMyUnknownImp
-{
- CMyComPtr<IInStream> Stream;
- UInt64 Pos;
-
- MY_UNKNOWN_IMP
-
- #ifdef USE_MIXER_MT
- NWindows::NSynchronization::CCriticalSection CriticalSection;
- #endif
-};
-
-
-#ifdef USE_MIXER_MT
-
-class CLockedSequentialInStreamMT:
- public ISequentialInStream,
- public CMyUnknownImp
-{
- CLockedInStream *_glob;
- UInt64 _pos;
- CMyComPtr<IUnknown> _globRef;
-public:
- void Init(CLockedInStream *lockedInStream, UInt64 startPos)
- {
- _globRef = lockedInStream;
- _glob = lockedInStream;
- _pos = startPos;
- }
-
- MY_UNKNOWN_IMP1(ISequentialInStream)
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
-};
-
-STDMETHODIMP CLockedSequentialInStreamMT::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- NWindows::NSynchronization::CCriticalSectionLock lock(_glob->CriticalSection);
-
- if (_pos != _glob->Pos)
- {
- RINOK(_glob->Stream->Seek(_pos, STREAM_SEEK_SET, NULL));
- _glob->Pos = _pos;
- }
-
- UInt32 realProcessedSize = 0;
- HRESULT res = _glob->Stream->Read(data, size, &realProcessedSize);
- _pos += realProcessedSize;
- _glob->Pos = _pos;
- if (processedSize)
- *processedSize = realProcessedSize;
- return res;
-}
-
-#endif
-
-
-#ifdef USE_MIXER_ST
-
-class CLockedSequentialInStreamST:
- public ISequentialInStream,
- public CMyUnknownImp
-{
- CLockedInStream *_glob;
- UInt64 _pos;
- CMyComPtr<IUnknown> _globRef;
-public:
- void Init(CLockedInStream *lockedInStream, UInt64 startPos)
- {
- _globRef = lockedInStream;
- _glob = lockedInStream;
- _pos = startPos;
- }
-
- MY_UNKNOWN_IMP1(ISequentialInStream)
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
-};
-
-STDMETHODIMP CLockedSequentialInStreamST::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- if (_pos != _glob->Pos)
- {
- RINOK(_glob->Stream->Seek(_pos, STREAM_SEEK_SET, NULL));
- _glob->Pos = _pos;
- }
-
- UInt32 realProcessedSize = 0;
- HRESULT res = _glob->Stream->Read(data, size, &realProcessedSize);
- _pos += realProcessedSize;
- _glob->Pos = _pos;
- if (processedSize)
- *processedSize = realProcessedSize;
- return res;
-}
-
-#endif
-
-
-
-HRESULT CDecoder::Decode(
- DECL_EXTERNAL_CODECS_LOC_VARS
- IInStream *inStream,
- UInt64 startPos,
- const CFolders &folders, unsigned folderIndex,
- const UInt64 *unpackSize
-
- , ISequentialOutStream *outStream
- , ICompressProgressInfo *compressProgress
-
- , ISequentialInStream **
- #ifdef USE_MIXER_ST
- inStreamMainRes
- #endif
-
- , bool &dataAfterEnd_Error
-
- _7Z_DECODER_CRYPRO_VARS_DECL
-
- #if !defined(_7ZIP_ST)
- , bool mtMode, UInt32 numThreads, UInt64 memUsage
- #endif
- )
-{
- dataAfterEnd_Error = false;
-
- const UInt64 *packPositions = &folders.PackPositions[folders.FoStartPackStreamIndex[folderIndex]];
- CFolderEx folderInfo;
- folders.ParseFolderEx(folderIndex, folderInfo);
-
- if (!folderInfo.IsDecodingSupported())
- return E_NOTIMPL;
-
- CBindInfoEx bindInfo;
- Convert_FolderInfo_to_BindInfo(folderInfo, bindInfo);
- if (!bindInfo.CalcMapsAndCheck())
- return E_NOTIMPL;
-
- UInt64 folderUnpackSize = folders.GetFolderUnpackSize(folderIndex);
- bool fullUnpack = true;
- if (unpackSize)
- {
- if (*unpackSize > folderUnpackSize)
- return E_FAIL;
- fullUnpack = (*unpackSize == folderUnpackSize);
- }
-
- /*
- We don't need to init isEncrypted and passwordIsDefined
- We must upgrade them only
-
- #ifndef _NO_CRYPTO
- isEncrypted = false;
- passwordIsDefined = false;
- #endif
- */
-
- if (!_bindInfoPrev_Defined || !AreBindInfoExEqual(bindInfo, _bindInfoPrev))
- {
- _mixerRef.Release();
-
- #ifdef USE_MIXER_MT
- #ifdef USE_MIXER_ST
- if (_useMixerMT)
- #endif
- {
- _mixerMT = new NCoderMixer2::CMixerMT(false);
- _mixerRef = _mixerMT;
- _mixer = _mixerMT;
- }
- #ifdef USE_MIXER_ST
- else
- #endif
- #endif
- {
- #ifdef USE_MIXER_ST
- _mixerST = new NCoderMixer2::CMixerST(false);
- _mixerRef = _mixerST;
- _mixer = _mixerST;
- #endif
- }
-
- RINOK(_mixer->SetBindInfo(bindInfo));
-
- FOR_VECTOR(i, folderInfo.Coders)
- {
- const CCoderInfo &coderInfo = folderInfo.Coders[i];
-
- #ifndef _SFX
- // we don't support RAR codecs here
- if ((coderInfo.MethodID >> 8) == 0x403)
- return E_NOTIMPL;
- #endif
-
- CCreatedCoder cod;
- RINOK(CreateCoder_Id(
- EXTERNAL_CODECS_LOC_VARS
- coderInfo.MethodID, false, cod));
-
- if (coderInfo.IsSimpleCoder())
- {
- if (!cod.Coder)
- return E_NOTIMPL;
- // CMethodId m = coderInfo.MethodID;
- // isFilter = (IsFilterMethod(m) || m == k_AES);
- }
- else
- {
- if (!cod.Coder2 || cod.NumStreams != coderInfo.NumStreams)
- return E_NOTIMPL;
- }
- _mixer->AddCoder(cod);
-
- // now there is no codec that uses another external codec
- /*
- #ifdef EXTERNAL_CODECS
- CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
- decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
- if (setCompressCodecsInfo)
- {
- // we must use g_ExternalCodecs also
- RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs));
- }
- #endif
- */
- }
-
- _bindInfoPrev = bindInfo;
- _bindInfoPrev_Defined = true;
- }
-
- _mixer->ReInit();
-
- UInt32 packStreamIndex = 0;
- UInt32 unpackStreamIndexStart = folders.FoToCoderUnpackSizes[folderIndex];
-
- unsigned i;
-
- #if !defined(_7ZIP_ST)
- bool mt_wasUsed = false;
- #endif
-
- for (i = 0; i < folderInfo.Coders.Size(); i++)
- {
- const CCoderInfo &coderInfo = folderInfo.Coders[i];
- IUnknown *decoder = _mixer->GetCoder(i).GetUnknown();
-
- #if !defined(_7ZIP_ST)
- if (!mt_wasUsed)
- {
- if (mtMode)
- {
- CMyComPtr<ICompressSetCoderMt> setCoderMt;
- decoder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt);
- if (setCoderMt)
- {
- mt_wasUsed = true;
- RINOK(setCoderMt->SetNumberOfThreads(numThreads));
- }
- }
- // if (memUsage != 0)
- {
- CMyComPtr<ICompressSetMemLimit> setMemLimit;
- decoder->QueryInterface(IID_ICompressSetMemLimit, (void **)&setMemLimit);
- if (setMemLimit)
- {
- mt_wasUsed = true;
- RINOK(setMemLimit->SetMemLimit(memUsage));
- }
- }
- }
- #endif
-
- {
- CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
- decoder->QueryInterface(IID_ICompressSetDecoderProperties2, (void **)&setDecoderProperties);
- if (setDecoderProperties)
- {
- const CByteBuffer &props = coderInfo.Props;
- size_t size = props.Size();
- if (size > 0xFFFFFFFF)
- return E_NOTIMPL;
- HRESULT res = setDecoderProperties->SetDecoderProperties2((const Byte *)props, (UInt32)size);
- if (res == E_INVALIDARG)
- res = E_NOTIMPL;
- RINOK(res);
- }
- }
-
- #ifndef _NO_CRYPTO
- {
- CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
- decoder->QueryInterface(IID_ICryptoSetPassword, (void **)&cryptoSetPassword);
- if (cryptoSetPassword)
- {
- isEncrypted = true;
- if (!getTextPassword)
- return E_NOTIMPL;
- CMyComBSTR passwordBSTR;
- RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR));
- passwordIsDefined = true;
- password.Empty();
- size_t len = 0;
- if (passwordBSTR)
- {
- password = passwordBSTR;
- len = password.Len();
- }
- CByteBuffer buffer(len * 2);
- for (size_t k = 0; k < len; k++)
- {
- wchar_t c = passwordBSTR[k];
- ((Byte *)buffer)[k * 2] = (Byte)c;
- ((Byte *)buffer)[k * 2 + 1] = (Byte)(c >> 8);
- }
- RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size()));
- }
- }
- #endif
-
- bool finishMode = false;
- {
- CMyComPtr<ICompressSetFinishMode> setFinishMode;
- decoder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode);
- if (setFinishMode)
- {
- finishMode = fullUnpack;
- RINOK(setFinishMode->SetFinishMode(BoolToInt(finishMode)));
- }
- }
-
- UInt32 numStreams = (UInt32)coderInfo.NumStreams;
-
- CObjArray<UInt64> packSizes(numStreams);
- CObjArray<const UInt64 *> packSizesPointers(numStreams);
-
- for (UInt32 j = 0; j < numStreams; j++, packStreamIndex++)
- {
- int bond = folderInfo.FindBond_for_PackStream(packStreamIndex);
-
- if (bond >= 0)
- packSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndexStart + folderInfo.Bonds[(unsigned)bond].UnpackIndex];
- else
- {
- int index = folderInfo.Find_in_PackStreams(packStreamIndex);
- if (index < 0)
- return E_NOTIMPL;
- packSizes[j] = packPositions[(unsigned)index + 1] - packPositions[(unsigned)index];
- packSizesPointers[j] = &packSizes[j];
- }
- }
-
- const UInt64 *unpackSizesPointer =
- (unpackSize && i == bindInfo.UnpackCoder) ?
- unpackSize :
- &folders.CoderUnpackSizes[unpackStreamIndexStart + i];
-
- _mixer->SetCoderInfo(i, unpackSizesPointer, packSizesPointers, finishMode);
- }
-
- if (outStream)
- {
- _mixer->SelectMainCoder(!fullUnpack);
- }
-
- CObjectVector< CMyComPtr<ISequentialInStream> > inStreams;
-
- CLockedInStream *lockedInStreamSpec = new CLockedInStream;
- CMyComPtr<IUnknown> lockedInStream = lockedInStreamSpec;
-
- bool needMtLock = false;
-
- if (folderInfo.PackStreams.Size() > 1)
- {
- // lockedInStream.Pos = (UInt64)(Int64)-1;
- // RINOK(inStream->Seek(0, STREAM_SEEK_CUR, &lockedInStream.Pos));
- RINOK(inStream->Seek(startPos + packPositions[0], STREAM_SEEK_SET, &lockedInStreamSpec->Pos));
- lockedInStreamSpec->Stream = inStream;
-
- #ifdef USE_MIXER_ST
- if (_mixer->IsThere_ExternalCoder_in_PackTree(_mixer->MainCoderIndex))
- #endif
- needMtLock = true;
- }
-
- for (unsigned j = 0; j < folderInfo.PackStreams.Size(); j++)
- {
- CMyComPtr<ISequentialInStream> packStream;
- UInt64 packPos = startPos + packPositions[j];
-
- if (folderInfo.PackStreams.Size() == 1)
- {
- RINOK(inStream->Seek(packPos, STREAM_SEEK_SET, NULL));
- packStream = inStream;
- }
- else
- {
- #ifdef USE_MIXER_MT
- #ifdef USE_MIXER_ST
- if (_useMixerMT || needMtLock)
- #endif
- {
- CLockedSequentialInStreamMT *lockedStreamImpSpec = new CLockedSequentialInStreamMT;
- packStream = lockedStreamImpSpec;
- lockedStreamImpSpec->Init(lockedInStreamSpec, packPos);
- }
- #ifdef USE_MIXER_ST
- else
- #endif
- #endif
- {
- #ifdef USE_MIXER_ST
- CLockedSequentialInStreamST *lockedStreamImpSpec = new CLockedSequentialInStreamST;
- packStream = lockedStreamImpSpec;
- lockedStreamImpSpec->Init(lockedInStreamSpec, packPos);
- #endif
- }
- }
-
- CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
- inStreams.AddNew() = streamSpec;
- streamSpec->SetStream(packStream);
- streamSpec->Init(packPositions[j + 1] - packPositions[j]);
- }
-
- unsigned num = inStreams.Size();
- CObjArray<ISequentialInStream *> inStreamPointers(num);
- for (i = 0; i < num; i++)
- inStreamPointers[i] = inStreams[i];
-
- if (outStream)
- {
- CMyComPtr<ICompressProgressInfo> progress2;
- if (compressProgress && !_mixer->Is_PackSize_Correct_for_Coder(_mixer->MainCoderIndex))
- progress2 = new CDecProgress(compressProgress);
-
- ISequentialOutStream *outStreamPointer = outStream;
- return _mixer->Code(inStreamPointers, &outStreamPointer,
- progress2 ? (ICompressProgressInfo *)progress2 : compressProgress,
- dataAfterEnd_Error);
- }
-
- #ifdef USE_MIXER_ST
- return _mixerST->GetMainUnpackStream(inStreamPointers, inStreamMainRes);
- #else
- return E_FAIL;
- #endif
-}
-
-}}
+// 7zDecode.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+
+#include "7zDecode.h"
+
+namespace NArchive {
+namespace N7z {
+
+Z7_CLASS_IMP_COM_1(
+ CDecProgress
+ , ICompressProgressInfo
+)
+ CMyComPtr<ICompressProgressInfo> _progress;
+public:
+ CDecProgress(ICompressProgressInfo *progress): _progress(progress) {}
+};
+
+Z7_COM7F_IMF(CDecProgress::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 *outSize))
+{
+ return _progress->SetRatioInfo(NULL, outSize);
+}
+
+static void Convert_FolderInfo_to_BindInfo(const CFolderEx &folder, CBindInfoEx &bi)
+{
+ bi.Clear();
+
+ bi.Bonds.ClearAndSetSize(folder.Bonds.Size());
+ unsigned i;
+ for (i = 0; i < folder.Bonds.Size(); i++)
+ {
+ NCoderMixer2::CBond &bond = bi.Bonds[i];
+ const N7z::CBond &folderBond = folder.Bonds[i];
+ bond.PackIndex = folderBond.PackIndex;
+ bond.UnpackIndex = folderBond.UnpackIndex;
+ }
+
+ bi.Coders.ClearAndSetSize(folder.Coders.Size());
+ bi.CoderMethodIDs.ClearAndSetSize(folder.Coders.Size());
+ for (i = 0; i < folder.Coders.Size(); i++)
+ {
+ const CCoderInfo &coderInfo = folder.Coders[i];
+ bi.Coders[i].NumStreams = coderInfo.NumStreams;
+ bi.CoderMethodIDs[i] = coderInfo.MethodID;
+ }
+
+ /*
+ if (!bi.SetUnpackCoder())
+ throw 1112;
+ */
+ bi.UnpackCoder = folder.UnpackCoder;
+ bi.PackStreams.ClearAndSetSize(folder.PackStreams.Size());
+ for (i = 0; i < folder.PackStreams.Size(); i++)
+ bi.PackStreams[i] = folder.PackStreams[i];
+}
+
+static inline bool AreCodersEqual(
+ const NCoderMixer2::CCoderStreamsInfo &a1,
+ const NCoderMixer2::CCoderStreamsInfo &a2)
+{
+ return (a1.NumStreams == a2.NumStreams);
+}
+
+static inline bool AreBondsEqual(
+ const NCoderMixer2::CBond &a1,
+ const NCoderMixer2::CBond &a2)
+{
+ return
+ (a1.PackIndex == a2.PackIndex) &&
+ (a1.UnpackIndex == a2.UnpackIndex);
+}
+
+static bool AreBindInfoExEqual(const CBindInfoEx &a1, const CBindInfoEx &a2)
+{
+ if (a1.Coders.Size() != a2.Coders.Size())
+ return false;
+ unsigned i;
+ for (i = 0; i < a1.Coders.Size(); i++)
+ if (!AreCodersEqual(a1.Coders[i], a2.Coders[i]))
+ return false;
+
+ if (a1.Bonds.Size() != a2.Bonds.Size())
+ return false;
+ for (i = 0; i < a1.Bonds.Size(); i++)
+ if (!AreBondsEqual(a1.Bonds[i], a2.Bonds[i]))
+ return false;
+
+ for (i = 0; i < a1.CoderMethodIDs.Size(); i++)
+ if (a1.CoderMethodIDs[i] != a2.CoderMethodIDs[i])
+ return false;
+
+ if (a1.PackStreams.Size() != a2.PackStreams.Size())
+ return false;
+ for (i = 0; i < a1.PackStreams.Size(); i++)
+ if (a1.PackStreams[i] != a2.PackStreams[i])
+ return false;
+
+ /*
+ if (a1.UnpackCoder != a2.UnpackCoder)
+ return false;
+ */
+ return true;
+}
+
+CDecoder::CDecoder(bool useMixerMT):
+ _bindInfoPrev_Defined(false)
+{
+ #if defined(USE_MIXER_ST) && defined(USE_MIXER_MT)
+ _useMixerMT = useMixerMT;
+ #else
+ UNUSED_VAR(useMixerMT)
+ #endif
+}
+
+
+Z7_CLASS_IMP_COM_0(
+ CLockedInStream
+)
+public:
+ CMyComPtr<IInStream> Stream;
+ UInt64 Pos;
+
+ #ifdef USE_MIXER_MT
+ NWindows::NSynchronization::CCriticalSection CriticalSection;
+ #endif
+};
+
+
+#ifdef USE_MIXER_MT
+
+Z7_CLASS_IMP_COM_1(
+ CLockedSequentialInStreamMT
+ , ISequentialInStream
+)
+ CLockedInStream *_glob;
+ UInt64 _pos;
+ CMyComPtr<IUnknown> _globRef;
+public:
+ void Init(CLockedInStream *lockedInStream, UInt64 startPos)
+ {
+ _globRef = lockedInStream;
+ _glob = lockedInStream;
+ _pos = startPos;
+ }
+};
+
+Z7_COM7F_IMF(CLockedSequentialInStreamMT::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ NWindows::NSynchronization::CCriticalSectionLock lock(_glob->CriticalSection);
+
+ if (_pos != _glob->Pos)
+ {
+ RINOK(InStream_SeekSet(_glob->Stream, _pos))
+ _glob->Pos = _pos;
+ }
+
+ UInt32 realProcessedSize = 0;
+ const HRESULT res = _glob->Stream->Read(data, size, &realProcessedSize);
+ _pos += realProcessedSize;
+ _glob->Pos = _pos;
+ if (processedSize)
+ *processedSize = realProcessedSize;
+ return res;
+}
+
+#endif
+
+
+#ifdef USE_MIXER_ST
+
+Z7_CLASS_IMP_COM_1(
+ CLockedSequentialInStreamST
+ , ISequentialInStream
+)
+ CLockedInStream *_glob;
+ UInt64 _pos;
+ CMyComPtr<IUnknown> _globRef;
+public:
+ void Init(CLockedInStream *lockedInStream, UInt64 startPos)
+ {
+ _globRef = lockedInStream;
+ _glob = lockedInStream;
+ _pos = startPos;
+ }
+};
+
+Z7_COM7F_IMF(CLockedSequentialInStreamST::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (_pos != _glob->Pos)
+ {
+ RINOK(InStream_SeekSet(_glob->Stream, _pos))
+ _glob->Pos = _pos;
+ }
+
+ UInt32 realProcessedSize = 0;
+ const HRESULT res = _glob->Stream->Read(data, size, &realProcessedSize);
+ _pos += realProcessedSize;
+ _glob->Pos = _pos;
+ if (processedSize)
+ *processedSize = realProcessedSize;
+ return res;
+}
+
+#endif
+
+
+
+HRESULT CDecoder::Decode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream,
+ UInt64 startPos,
+ const CFolders &folders, unsigned folderIndex,
+ const UInt64 *unpackSize
+
+ , ISequentialOutStream *outStream
+ , ICompressProgressInfo *compressProgress
+
+ , ISequentialInStream **
+ #ifdef USE_MIXER_ST
+ inStreamMainRes
+ #endif
+
+ , bool &dataAfterEnd_Error
+
+ Z7_7Z_DECODER_CRYPRO_VARS_DECL
+
+ #if !defined(Z7_ST)
+ , bool mtMode, UInt32 numThreads, UInt64 memUsage
+ #endif
+ )
+{
+ dataAfterEnd_Error = false;
+
+ const UInt64 *packPositions = &folders.PackPositions[folders.FoStartPackStreamIndex[folderIndex]];
+ CFolderEx folderInfo;
+ folders.ParseFolderEx(folderIndex, folderInfo);
+
+ if (!folderInfo.IsDecodingSupported())
+ return E_NOTIMPL;
+
+ CBindInfoEx bindInfo;
+ Convert_FolderInfo_to_BindInfo(folderInfo, bindInfo);
+ if (!bindInfo.CalcMapsAndCheck())
+ return E_NOTIMPL;
+
+ UInt64 folderUnpackSize = folders.GetFolderUnpackSize(folderIndex);
+ bool fullUnpack = true;
+ if (unpackSize)
+ {
+ if (*unpackSize > folderUnpackSize)
+ return E_FAIL;
+ fullUnpack = (*unpackSize == folderUnpackSize);
+ }
+
+ /*
+ We don't need to init isEncrypted and passwordIsDefined
+ We must upgrade them only
+
+ #ifndef Z7_NO_CRYPTO
+ isEncrypted = false;
+ passwordIsDefined = false;
+ #endif
+ */
+
+ if (!_bindInfoPrev_Defined || !AreBindInfoExEqual(bindInfo, _bindInfoPrev))
+ {
+ _bindInfoPrev_Defined = false;
+ _mixerRef.Release();
+
+ #ifdef USE_MIXER_MT
+ #ifdef USE_MIXER_ST
+ if (_useMixerMT)
+ #endif
+ {
+ _mixerMT = new NCoderMixer2::CMixerMT(false);
+ _mixerRef = _mixerMT;
+ _mixer = _mixerMT;
+ }
+ #ifdef USE_MIXER_ST
+ else
+ #endif
+ #endif
+ {
+ #ifdef USE_MIXER_ST
+ _mixerST = new NCoderMixer2::CMixerST(false);
+ _mixerRef = _mixerST;
+ _mixer = _mixerST;
+ #endif
+ }
+
+ RINOK(_mixer->SetBindInfo(bindInfo))
+
+ FOR_VECTOR(i, folderInfo.Coders)
+ {
+ const CCoderInfo &coderInfo = folderInfo.Coders[i];
+
+ #ifndef Z7_SFX
+ // we don't support RAR codecs here
+ if ((coderInfo.MethodID >> 8) == 0x403)
+ return E_NOTIMPL;
+ #endif
+
+ CCreatedCoder cod;
+ RINOK(CreateCoder_Id(
+ EXTERNAL_CODECS_LOC_VARS
+ coderInfo.MethodID, false, cod))
+
+ if (coderInfo.IsSimpleCoder())
+ {
+ if (!cod.Coder)
+ return E_NOTIMPL;
+ // CMethodId m = coderInfo.MethodID;
+ // isFilter = (IsFilterMethod(m) || m == k_AES);
+ }
+ else
+ {
+ if (!cod.Coder2 || cod.NumStreams != coderInfo.NumStreams)
+ return E_NOTIMPL;
+ }
+ _mixer->AddCoder(cod);
+
+ // now there is no codec that uses another external codec
+ /*
+ #ifdef Z7_EXTERNAL_CODECS
+ CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+ decoderUnknown.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+ if (setCompressCodecsInfo)
+ {
+ // we must use g_ExternalCodecs also
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(_externalCodecs->GetCodecs));
+ }
+ #endif
+ */
+ }
+
+ _bindInfoPrev = bindInfo;
+ _bindInfoPrev_Defined = true;
+ }
+
+ RINOK(_mixer->ReInit2())
+
+ UInt32 packStreamIndex = 0;
+ UInt32 unpackStreamIndexStart = folders.FoToCoderUnpackSizes[folderIndex];
+
+ unsigned i;
+
+ #if !defined(Z7_ST)
+ bool mt_wasUsed = false;
+ #endif
+
+ for (i = 0; i < folderInfo.Coders.Size(); i++)
+ {
+ const CCoderInfo &coderInfo = folderInfo.Coders[i];
+ IUnknown *decoder = _mixer->GetCoder(i).GetUnknown();
+
+ // now there is no codec that uses another external codec
+ /*
+ #ifdef Z7_EXTERNAL_CODECS
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(ISetCompressCodecsInfo,
+ setCompressCodecsInfo, decoder)
+ if (setCompressCodecsInfo)
+ {
+ // we must use g_ExternalCodecs also
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(_externalCodecs->GetCodecs))
+ }
+ }
+ #endif
+ */
+
+ #if !defined(Z7_ST)
+ if (!mt_wasUsed)
+ {
+ if (mtMode)
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(ICompressSetCoderMt,
+ setCoderMt, decoder)
+ if (setCoderMt)
+ {
+ mt_wasUsed = true;
+ RINOK(setCoderMt->SetNumberOfThreads(numThreads))
+ }
+ }
+ // if (memUsage != 0)
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(ICompressSetMemLimit,
+ setMemLimit, decoder)
+ if (setMemLimit)
+ {
+ mt_wasUsed = true;
+ RINOK(setMemLimit->SetMemLimit(memUsage))
+ }
+ }
+ }
+ #endif
+
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ ICompressSetDecoderProperties2,
+ setDecoderProperties, decoder)
+ const CByteBuffer &props = coderInfo.Props;
+ const UInt32 size32 = (UInt32)props.Size();
+ if (props.Size() != size32)
+ return E_NOTIMPL;
+ if (setDecoderProperties)
+ {
+ HRESULT res = setDecoderProperties->SetDecoderProperties2((const Byte *)props, size32);
+ if (res == E_INVALIDARG)
+ res = E_NOTIMPL;
+ RINOK(res)
+ }
+ else if (size32 != 0)
+ {
+ // v23: we fail, if decoder doesn't support properties
+ return E_NOTIMPL;
+ }
+ }
+
+ #ifndef Z7_NO_CRYPTO
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ ICryptoSetPassword,
+ cryptoSetPassword, decoder)
+ if (cryptoSetPassword)
+ {
+ isEncrypted = true;
+ if (!getTextPassword)
+ return E_NOTIMPL;
+ CMyComBSTR_Wipe passwordBSTR;
+ RINOK(getTextPassword->CryptoGetTextPassword(&passwordBSTR))
+ passwordIsDefined = true;
+ password.Wipe_and_Empty();
+ size_t len = 0;
+ if (passwordBSTR)
+ {
+ password = passwordBSTR;
+ len = password.Len();
+ }
+ CByteBuffer_Wipe buffer(len * 2);
+ for (size_t k = 0; k < len; k++)
+ {
+ const wchar_t c = passwordBSTR[k];
+ ((Byte *)buffer)[k * 2] = (Byte)c;
+ ((Byte *)buffer)[k * 2 + 1] = (Byte)(c >> 8);
+ }
+ RINOK(cryptoSetPassword->CryptoSetPassword((const Byte *)buffer, (UInt32)buffer.Size()))
+ }
+ }
+ #endif
+
+ bool finishMode = false;
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ ICompressSetFinishMode,
+ setFinishMode, decoder)
+ if (setFinishMode)
+ {
+ finishMode = fullUnpack;
+ RINOK(setFinishMode->SetFinishMode(BoolToUInt(finishMode)))
+ }
+ }
+
+ UInt32 numStreams = (UInt32)coderInfo.NumStreams;
+
+ CObjArray<UInt64> packSizes(numStreams);
+ CObjArray<const UInt64 *> packSizesPointers(numStreams);
+
+ for (UInt32 j = 0; j < numStreams; j++, packStreamIndex++)
+ {
+ int bond = folderInfo.FindBond_for_PackStream(packStreamIndex);
+
+ if (bond >= 0)
+ packSizesPointers[j] = &folders.CoderUnpackSizes[unpackStreamIndexStart + folderInfo.Bonds[(unsigned)bond].UnpackIndex];
+ else
+ {
+ int index = folderInfo.Find_in_PackStreams(packStreamIndex);
+ if (index < 0)
+ return E_NOTIMPL;
+ packSizes[j] = packPositions[(unsigned)index + 1] - packPositions[(unsigned)index];
+ packSizesPointers[j] = &packSizes[j];
+ }
+ }
+
+ const UInt64 *unpackSizesPointer =
+ (unpackSize && i == bindInfo.UnpackCoder) ?
+ unpackSize :
+ &folders.CoderUnpackSizes[unpackStreamIndexStart + i];
+
+ _mixer->SetCoderInfo(i, unpackSizesPointer, packSizesPointers, finishMode);
+ }
+
+ if (outStream)
+ {
+ _mixer->SelectMainCoder(!fullUnpack);
+ }
+
+ CObjectVector< CMyComPtr<ISequentialInStream> > inStreams;
+
+ CLockedInStream *lockedInStreamSpec = new CLockedInStream;
+ CMyComPtr<IUnknown> lockedInStream = lockedInStreamSpec;
+
+ #ifdef USE_MIXER_MT
+ #ifdef USE_MIXER_ST
+ bool needMtLock = _useMixerMT;
+ #endif
+ #endif
+
+ if (folderInfo.PackStreams.Size() > 1)
+ {
+ // lockedInStream.Pos = (UInt64)(Int64)-1;
+ // RINOK(InStream_GetPos(inStream, lockedInStream.Pos))
+ RINOK(inStream->Seek((Int64)(startPos + packPositions[0]), STREAM_SEEK_SET, &lockedInStreamSpec->Pos))
+ lockedInStreamSpec->Stream = inStream;
+
+ #ifdef USE_MIXER_MT
+ #ifdef USE_MIXER_ST
+ /*
+ For ST-mixer mode:
+ If parallel input stream reading from pack streams is possible,
+ we must use MT-lock for packed streams.
+ Internal decoders in 7-Zip will not read pack streams in parallel in ST-mixer mode.
+ So we force to needMtLock mode only if there is unknown (external) decoder.
+ */
+ if (!needMtLock && _mixer->IsThere_ExternalCoder_in_PackTree(_mixer->MainCoderIndex))
+ needMtLock = true;
+ #endif
+ #endif
+ }
+
+ for (unsigned j = 0; j < folderInfo.PackStreams.Size(); j++)
+ {
+ CMyComPtr<ISequentialInStream> packStream;
+ const UInt64 packPos = startPos + packPositions[j];
+
+ if (folderInfo.PackStreams.Size() == 1)
+ {
+ RINOK(InStream_SeekSet(inStream, packPos))
+ packStream = inStream;
+ }
+ else
+ {
+ #ifdef USE_MIXER_MT
+ #ifdef USE_MIXER_ST
+ if (needMtLock)
+ #endif
+ {
+ CLockedSequentialInStreamMT *lockedStreamImpSpec = new CLockedSequentialInStreamMT;
+ packStream = lockedStreamImpSpec;
+ lockedStreamImpSpec->Init(lockedInStreamSpec, packPos);
+ }
+ #ifdef USE_MIXER_ST
+ else
+ #endif
+ #endif
+ {
+ #ifdef USE_MIXER_ST
+ CLockedSequentialInStreamST *lockedStreamImpSpec = new CLockedSequentialInStreamST;
+ packStream = lockedStreamImpSpec;
+ lockedStreamImpSpec->Init(lockedInStreamSpec, packPos);
+ #endif
+ }
+ }
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ inStreams.AddNew() = streamSpec;
+ streamSpec->SetStream(packStream);
+ streamSpec->Init(packPositions[j + 1] - packPositions[j]);
+ }
+
+ const unsigned num = inStreams.Size();
+ CObjArray<ISequentialInStream *> inStreamPointers(num);
+ for (i = 0; i < num; i++)
+ inStreamPointers[i] = inStreams[i];
+
+ if (outStream)
+ {
+ CMyComPtr<ICompressProgressInfo> progress2;
+ if (compressProgress && !_mixer->Is_PackSize_Correct_for_Coder(_mixer->MainCoderIndex))
+ progress2 = new CDecProgress(compressProgress);
+
+ ISequentialOutStream *outStreamPointer = outStream;
+ return _mixer->Code(inStreamPointers, &outStreamPointer,
+ progress2 ? (ICompressProgressInfo *)progress2 : compressProgress,
+ dataAfterEnd_Error);
+ }
+
+ #ifdef USE_MIXER_ST
+ return _mixerST->GetMainUnpackStream(inStreamPointers, inStreamMainRes);
+ #else
+ return E_FAIL;
+ #endif
+}
+
+}}
diff --git a/CPP/7zip/Archive/7z/7zDecode.h b/CPP/7zip/Archive/7z/7zDecode.h
index 944f8a3..ee9d9c2 100644
--- a/CPP/7zip/Archive/7z/7zDecode.h
+++ b/CPP/7zip/Archive/7z/7zDecode.h
@@ -1,70 +1,73 @@
-// 7zDecode.h
-
-#ifndef __7Z_DECODE_H
-#define __7Z_DECODE_H
-
-#include "../Common/CoderMixer2.h"
-
-#include "7zIn.h"
-
-namespace NArchive {
-namespace N7z {
-
-struct CBindInfoEx: public NCoderMixer2::CBindInfo
-{
- CRecordVector<CMethodId> CoderMethodIDs;
-
- void Clear()
- {
- CBindInfo::Clear();
- CoderMethodIDs.Clear();
- }
-};
-
-class CDecoder
-{
- bool _bindInfoPrev_Defined;
- CBindInfoEx _bindInfoPrev;
-
- bool _useMixerMT;
-
- #ifdef USE_MIXER_ST
- NCoderMixer2::CMixerST *_mixerST;
- #endif
-
- #ifdef USE_MIXER_MT
- NCoderMixer2::CMixerMT *_mixerMT;
- #endif
-
- NCoderMixer2::CMixer *_mixer;
- CMyComPtr<IUnknown> _mixerRef;
-
-public:
-
- CDecoder(bool useMixerMT);
-
- HRESULT Decode(
- DECL_EXTERNAL_CODECS_LOC_VARS
- IInStream *inStream,
- UInt64 startPos,
- const CFolders &folders, unsigned folderIndex,
- const UInt64 *unpackSize // if (!unpackSize), then full folder is required
- // if (unpackSize), then only *unpackSize bytes from folder are required
-
- , ISequentialOutStream *outStream
- , ICompressProgressInfo *compressProgress
-
- , ISequentialInStream **inStreamMainRes
- , bool &dataAfterEnd_Error
-
- _7Z_DECODER_CRYPRO_VARS_DECL
-
- #if !defined(_7ZIP_ST)
- , bool mtMode, UInt32 numThreads, UInt64 memUsage
- #endif
- );
-};
-
-}}
-
-#endif
+// 7zDecode.h
+
+#ifndef ZIP7_INC_7Z_DECODE_H
+#define ZIP7_INC_7Z_DECODE_H
+
+#include "../Common/CoderMixer2.h"
+
+#include "7zIn.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CBindInfoEx: public NCoderMixer2::CBindInfo
+{
+ CRecordVector<CMethodId> CoderMethodIDs;
+
+ void Clear()
+ {
+ CBindInfo::Clear();
+ CoderMethodIDs.Clear();
+ }
+};
+
+class CDecoder
+{
+ bool _bindInfoPrev_Defined;
+ #ifdef USE_MIXER_ST
+ #ifdef USE_MIXER_MT
+ bool _useMixerMT;
+ #endif
+ #endif
+ CBindInfoEx _bindInfoPrev;
+
+ #ifdef USE_MIXER_ST
+ NCoderMixer2::CMixerST *_mixerST;
+ #endif
+
+ #ifdef USE_MIXER_MT
+ NCoderMixer2::CMixerMT *_mixerMT;
+ #endif
+
+ NCoderMixer2::CMixer *_mixer;
+ CMyComPtr<IUnknown> _mixerRef;
+
+public:
+
+ CDecoder(bool useMixerMT);
+
+ HRESULT Decode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream,
+ UInt64 startPos,
+ const CFolders &folders, unsigned folderIndex,
+ const UInt64 *unpackSize // if (!unpackSize), then full folder is required
+ // if (unpackSize), then only *unpackSize bytes from folder are required
+
+ , ISequentialOutStream *outStream
+ , ICompressProgressInfo *compressProgress
+
+ , ISequentialInStream **inStreamMainRes
+ , bool &dataAfterEnd_Error
+
+ Z7_7Z_DECODER_CRYPRO_VARS_DECL
+
+ #if !defined(Z7_ST)
+ , bool mtMode, UInt32 numThreads, UInt64 memUsage
+ #endif
+ );
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/7z/7zEncode.cpp b/CPP/7zip/Archive/7z/7zEncode.cpp
index 4c0d221..78c91cf 100644
--- a/CPP/7zip/Archive/7z/7zEncode.cpp
+++ b/CPP/7zip/Archive/7z/7zEncode.cpp
@@ -1,678 +1,725 @@
-// 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"
-
-namespace NArchive {
-namespace N7z {
-
-void CEncoder::InitBindConv()
-{
- unsigned numIn = _bindInfo.Coders.Size();
-
- _SrcIn_to_DestOut.ClearAndSetSize(numIn);
- _DestOut_to_SrcIn.ClearAndSetSize(numIn);
-
- unsigned numOut = _bindInfo.GetNum_Bonds_and_PackStreams();
- _SrcOut_to_DestIn.ClearAndSetSize(numOut);
- // _DestIn_to_SrcOut.ClearAndSetSize(numOut);
-
- UInt32 destIn = 0;
- UInt32 destOut = 0;
-
- for (unsigned i = _bindInfo.Coders.Size(); i != 0;)
- {
- i--;
-
- const NCoderMixer2::CCoderStreamsInfo &coder = _bindInfo.Coders[i];
-
- numIn--;
- numOut -= coder.NumStreams;
-
- _SrcIn_to_DestOut[numIn] = destOut;
- _DestOut_to_SrcIn[destOut] = numIn;
-
- destOut++;
-
- for (UInt32 j = 0; j < coder.NumStreams; j++, destIn++)
- {
- UInt32 index = numOut + j;
- _SrcOut_to_DestIn[index] = destIn;
- // _DestIn_to_SrcOut[destIn] = index;
- }
- }
-}
-
-void CEncoder::SetFolder(CFolder &folder)
-{
- folder.Bonds.SetSize(_bindInfo.Bonds.Size());
-
- unsigned i;
-
- for (i = 0; i < _bindInfo.Bonds.Size(); i++)
- {
- CBond &fb = folder.Bonds[i];
- const NCoderMixer2::CBond &mixerBond = _bindInfo.Bonds[_bindInfo.Bonds.Size() - 1 - i];
- fb.PackIndex = _SrcOut_to_DestIn[mixerBond.PackIndex];
- fb.UnpackIndex = _SrcIn_to_DestOut[mixerBond.UnpackIndex];
- }
-
- folder.Coders.SetSize(_bindInfo.Coders.Size());
-
- for (i = 0; i < _bindInfo.Coders.Size(); i++)
- {
- CCoderInfo &coderInfo = folder.Coders[i];
- const NCoderMixer2::CCoderStreamsInfo &coderStreamsInfo = _bindInfo.Coders[_bindInfo.Coders.Size() - 1 - i];
-
- coderInfo.NumStreams = coderStreamsInfo.NumStreams;
- coderInfo.MethodID = _decompressionMethods[i];
- // we don't free coderInfo.Props here. So coderInfo.Props can be non-empty.
- }
-
- folder.PackStreams.SetSize(_bindInfo.PackStreams.Size());
-
- for (i = 0; i < _bindInfo.PackStreams.Size(); i++)
- folder.PackStreams[i] = _SrcOut_to_DestIn[_bindInfo.PackStreams[i]];
-}
-
-
-
-static HRESULT SetCoderProps2(const CProps &props, const UInt64 *dataSizeReduce, IUnknown *coder)
-{
- CMyComPtr<ICompressSetCoderProperties> setCoderProperties;
- coder->QueryInterface(IID_ICompressSetCoderProperties, (void **)&setCoderProperties);
- if (setCoderProperties)
- return props.SetCoderProps(setCoderProperties, dataSizeReduce);
- return props.AreThereNonOptionalProps() ? E_INVALIDARG : S_OK;
-}
-
-
-
-void CMtEncMultiProgress::Init(ICompressProgressInfo *progress)
-{
- _progress = progress;
- OutSize = 0;
-}
-
-STDMETHODIMP CMtEncMultiProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)
-{
- UInt64 outSize2;
- {
- #ifndef _7ZIP_ST
- NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
- #endif
- outSize2 = OutSize;
- }
-
- if (_progress)
- return _progress->SetRatioInfo(inSize, &outSize2);
-
- return S_OK;
-}
-
-
-
-HRESULT CEncoder::CreateMixerCoder(
- DECL_EXTERNAL_CODECS_LOC_VARS
- const UInt64 *inSizeForReduce)
-{
- #ifdef USE_MIXER_MT
- #ifdef USE_MIXER_ST
- if (_options.MultiThreadMixer)
- #endif
- {
- _mixerMT = new NCoderMixer2::CMixerMT(true);
- _mixerRef = _mixerMT;
- _mixer = _mixerMT;
- }
- #ifdef USE_MIXER_ST
- else
- #endif
- #endif
- {
- #ifdef USE_MIXER_ST
- _mixerST = new NCoderMixer2::CMixerST(true);
- _mixerRef = _mixerST;
- _mixer = _mixerST;
- #endif
- }
-
- RINOK(_mixer->SetBindInfo(_bindInfo));
-
- FOR_VECTOR (m, _options.Methods)
- {
- const CMethodFull &methodFull = _options.Methods[m];
-
- CCreatedCoder cod;
-
- if (methodFull.CodecIndex >= 0)
- {
- RINOK(CreateCoder_Index(
- EXTERNAL_CODECS_LOC_VARS
- methodFull.CodecIndex, true, cod));
- }
- else
- {
- RINOK(CreateCoder_Id(
- EXTERNAL_CODECS_LOC_VARS
- methodFull.Id, true, cod));
- }
-
- if (cod.NumStreams != methodFull.NumStreams)
- return E_FAIL;
- if (!cod.Coder && !cod.Coder2)
- return E_FAIL;
-
- CMyComPtr<IUnknown> encoderCommon = cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2;
-
- #ifndef _7ZIP_ST
- {
- CMyComPtr<ICompressSetCoderMt> setCoderMt;
- encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
- if (setCoderMt)
- {
- RINOK(setCoderMt->SetNumberOfThreads(_options.NumThreads));
- }
- }
- #endif
-
- RINOK(SetCoderProps2(methodFull, inSizeForReduce, encoderCommon));
-
- /*
- CMyComPtr<ICryptoResetSalt> resetSalt;
- encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt);
- if (resetSalt)
- {
- resetSalt->ResetSalt();
- }
- */
-
- // now there is no codec that uses another external codec
- /*
- #ifdef EXTERNAL_CODECS
- CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
- encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
- if (setCompressCodecsInfo)
- {
- // we must use g_ExternalCodecs also
- RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(__externalCodecs->GetCodecs));
- }
- #endif
- */
-
- CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
- encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
-
- if (cryptoSetPassword)
- {
- const unsigned sizeInBytes = _options.Password.Len() * 2;
- CByteBuffer buffer(sizeInBytes);
- for (unsigned i = 0; i < _options.Password.Len(); 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, (UInt32)sizeInBytes));
- }
-
- _mixer->AddCoder(cod);
- }
- return S_OK;
-}
-
-
-
-class CSequentialOutTempBufferImp2:
- public ISequentialOutStream,
- public CMyUnknownImp
-{
- CInOutTempBuffer *_buf;
-public:
- CMtEncMultiProgress *_mtProgresSpec;
-
- CSequentialOutTempBufferImp2(): _buf(0), _mtProgresSpec(NULL) {}
- void Init(CInOutTempBuffer *buffer) { _buf = buffer; }
- MY_UNKNOWN_IMP1(ISequentialOutStream)
-
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
-};
-
-STDMETHODIMP CSequentialOutTempBufferImp2::Write(const void *data, UInt32 size, UInt32 *processed)
-{
- if (!_buf->Write(data, size))
- {
- if (processed)
- *processed = 0;
- return E_FAIL;
- }
- if (processed)
- *processed = size;
- if (_mtProgresSpec)
- _mtProgresSpec->AddOutSize(size);
- return S_OK;
-}
-
-
-class CSequentialOutMtNotify:
- public ISequentialOutStream,
- public CMyUnknownImp
-{
-public:
- CMyComPtr<ISequentialOutStream> _stream;
- CMtEncMultiProgress *_mtProgresSpec;
-
- CSequentialOutMtNotify(): _mtProgresSpec(NULL) {}
- MY_UNKNOWN_IMP1(ISequentialOutStream)
-
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
-};
-
-STDMETHODIMP CSequentialOutMtNotify::Write(const void *data, UInt32 size, UInt32 *processed)
-{
- UInt32 realProcessed = 0;
- HRESULT res = _stream->Write(data, size, &realProcessed);
- if (processed)
- *processed = realProcessed;
- if (_mtProgresSpec)
- _mtProgresSpec->AddOutSize(size);
- return res;
-}
-
-
-
-HRESULT CEncoder::Encode(
- DECL_EXTERNAL_CODECS_LOC_VARS
- ISequentialInStream *inStream,
- // const UInt64 *inStreamSize,
- const UInt64 *inSizeForReduce,
- CFolder &folderItem,
- CRecordVector<UInt64> &coderUnpackSizes,
- UInt64 &unpackSize,
- ISequentialOutStream *outStream,
- CRecordVector<UInt64> &packSizes,
- ICompressProgressInfo *compressProgress)
-{
- RINOK(EncoderConstr());
-
- if (!_mixerRef)
- {
- RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce));
- }
-
- _mixer->ReInit();
-
- CMtEncMultiProgress *mtProgressSpec = NULL;
- CMyComPtr<ICompressProgressInfo> mtProgress;
-
- CSequentialOutMtNotify *mtOutStreamNotifySpec = NULL;
- CMyComPtr<ISequentialOutStream> mtOutStreamNotify;
-
- CObjectVector<CInOutTempBuffer> inOutTempBuffers;
- CObjectVector<CSequentialOutTempBufferImp2 *> tempBufferSpecs;
- CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers;
-
- unsigned numMethods = _bindInfo.Coders.Size();
-
- unsigned i;
-
- for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
- {
- CInOutTempBuffer &iotb = inOutTempBuffers.AddNew();
- iotb.Create();
- iotb.InitWriting();
- }
-
- for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
- {
- CSequentialOutTempBufferImp2 *tempBufferSpec = new CSequentialOutTempBufferImp2;
- CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec;
- tempBufferSpec->Init(&inOutTempBuffers[i - 1]);
- tempBuffers.Add(tempBuffer);
- tempBufferSpecs.Add(tempBufferSpec);
- }
-
- for (i = 0; i < numMethods; i++)
- _mixer->SetCoderInfo(i, NULL, NULL, false);
-
-
- /* inStreamSize can be used by BCJ2 to set optimal range of conversion.
- But current BCJ2 encoder uses also another way to check exact size of current file.
- So inStreamSize is not required. */
-
- /*
- if (inStreamSize)
- _mixer->SetCoderInfo(_bindInfo.UnpackCoder, inStreamSize, NULL);
- */
-
-
- CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2;
- CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
-
- CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL;
- CMyComPtr<ISequentialOutStream> outStreamSizeCount;
-
- inStreamSizeCountSpec->Init(inStream);
-
- ISequentialInStream *inStreamPointer = inStreamSizeCount;
- CRecordVector<ISequentialOutStream *> outStreamPointers;
-
- SetFolder(folderItem);
-
- for (i = 0; i < numMethods; i++)
- {
- IUnknown *coder = _mixer->GetCoder(i).GetUnknown();
-
- CMyComPtr<ICryptoResetInitVector> resetInitVector;
- coder->QueryInterface(IID_ICryptoResetInitVector, (void **)&resetInitVector);
- if (resetInitVector)
- {
- resetInitVector->ResetInitVector();
- }
-
- {
- CMyComPtr<ICompressSetCoderPropertiesOpt> optProps;
- coder->QueryInterface(IID_ICompressSetCoderPropertiesOpt, (void **)&optProps);
- if (optProps)
- {
- PROPID propID = NCoderPropID::kExpectedDataSize;
- NWindows::NCOM::CPropVariant prop = (UInt64)unpackSize;
- RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1));
- }
- }
-
- CMyComPtr<ICompressWriteCoderProperties> writeCoderProperties;
- coder->QueryInterface(IID_ICompressWriteCoderProperties, (void **)&writeCoderProperties);
-
- CByteBuffer &props = folderItem.Coders[numMethods - 1 - i].Props;
-
- if (writeCoderProperties)
- {
- CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream;
- CMyComPtr<ISequentialOutStream> dynOutStream(outStreamSpec);
- outStreamSpec->Init();
- RINOK(writeCoderProperties->WriteCoderProperties(dynOutStream));
- outStreamSpec->CopyToBuffer(props);
- }
- else
- props.Free();
- }
-
- _mixer->SelectMainCoder(false);
- UInt32 mainCoder = _mixer->MainCoderIndex;
-
- bool useMtProgress = false;
- if (!_mixer->Is_PackSize_Correct_for_Coder(mainCoder))
- {
- #ifdef _7ZIP_ST
- if (!_mixer->IsThere_ExternalCoder_in_PackTree(mainCoder))
- #endif
- useMtProgress = true;
- }
-
- if (useMtProgress)
- {
- mtProgressSpec = new CMtEncMultiProgress;
- mtProgress = mtProgressSpec;
- mtProgressSpec->Init(compressProgress);
-
- mtOutStreamNotifySpec = new CSequentialOutMtNotify;
- mtOutStreamNotify = mtOutStreamNotifySpec;
- mtOutStreamNotifySpec->_stream = outStream;
- mtOutStreamNotifySpec->_mtProgresSpec = mtProgressSpec;
-
- FOR_VECTOR(t, tempBufferSpecs)
- {
- tempBufferSpecs[t]->_mtProgresSpec = mtProgressSpec;
- }
- }
-
-
- if (_bindInfo.PackStreams.Size() != 0)
- {
- outStreamSizeCountSpec = new CSequentialOutStreamSizeCount;
- outStreamSizeCount = outStreamSizeCountSpec;
- outStreamSizeCountSpec->SetStream(mtOutStreamNotify ? (ISequentialOutStream *)mtOutStreamNotify : outStream);
- outStreamSizeCountSpec->Init();
- outStreamPointers.Add(outStreamSizeCount);
- }
-
- for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
- outStreamPointers.Add(tempBuffers[i - 1]);
-
- bool dataAfterEnd_Error;
-
- RINOK(_mixer->Code(
- &inStreamPointer,
- &outStreamPointers.Front(),
- mtProgress ? (ICompressProgressInfo *)mtProgress : compressProgress, dataAfterEnd_Error));
-
- if (_bindInfo.PackStreams.Size() != 0)
- packSizes.Add(outStreamSizeCountSpec->GetSize());
-
- for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
- {
- CInOutTempBuffer &inOutTempBuffer = inOutTempBuffers[i - 1];
- RINOK(inOutTempBuffer.WriteToStream(outStream));
- packSizes.Add(inOutTempBuffer.GetDataSize());
- }
-
- unpackSize = 0;
-
- for (i = 0; i < _bindInfo.Coders.Size(); i++)
- {
- int bond = _bindInfo.FindBond_for_UnpackStream(_DestOut_to_SrcIn[i]);
- UInt64 streamSize;
- if (bond < 0)
- {
- streamSize = inStreamSizeCountSpec->GetSize();
- unpackSize = streamSize;
- }
- else
- streamSize = _mixer->GetBondStreamSize(bond);
- coderUnpackSizes.Add(streamSize);
- }
-
- return S_OK;
-}
-
-
-CEncoder::CEncoder(const CCompressionMethodMode &options):
- _constructed(false)
-{
- if (options.IsEmpty())
- throw 1;
-
- _options = options;
-
- #ifdef USE_MIXER_ST
- _mixerST = NULL;
- #endif
-
- #ifdef USE_MIXER_MT
- _mixerMT = NULL;
- #endif
-
- _mixer = 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.Bonds.IsEmpty())
- throw 1;
-
- CMethodFull method;
- method.Id = k_AES;
- method.NumStreams = 1;
- _options.Methods.Add(method);
-
- NCoderMixer2::CCoderStreamsInfo coderStreamsInfo;
- coderStreamsInfo.NumStreams = 1;
- _bindInfo.Coders.Add(coderStreamsInfo);
-
- _bindInfo.PackStreams.Add(0);
- _bindInfo.UnpackCoder = 0;
- }
- else
- {
-
- UInt32 numOutStreams = 0;
- unsigned i;
-
- for (i = 0; i < _options.Methods.Size(); i++)
- {
- const CMethodFull &methodFull = _options.Methods[i];
- NCoderMixer2::CCoderStreamsInfo cod;
-
- cod.NumStreams = methodFull.NumStreams;
-
- if (_options.Bonds.IsEmpty())
- {
- // if there are no bonds in options, we create bonds via first streams of coders
- if (i != _options.Methods.Size() - 1)
- {
- NCoderMixer2::CBond bond;
- bond.PackIndex = numOutStreams;
- bond.UnpackIndex = i + 1; // it's next coder
- _bindInfo.Bonds.Add(bond);
- }
- else if (cod.NumStreams != 0)
- _bindInfo.PackStreams.Insert(0, numOutStreams);
-
- for (UInt32 j = 1; j < cod.NumStreams; j++)
- _bindInfo.PackStreams.Add(numOutStreams + j);
- }
-
- numOutStreams += cod.NumStreams;
-
- _bindInfo.Coders.Add(cod);
- }
-
- if (!_options.Bonds.IsEmpty())
- {
- for (i = 0; i < _options.Bonds.Size(); i++)
- {
- NCoderMixer2::CBond mixerBond;
- const CBond2 &bond = _options.Bonds[i];
- if (bond.InCoder >= _bindInfo.Coders.Size()
- || bond.OutCoder >= _bindInfo.Coders.Size()
- || bond.OutStream >= _bindInfo.Coders[bond.OutCoder].NumStreams)
- return E_INVALIDARG;
- mixerBond.PackIndex = _bindInfo.GetStream_for_Coder(bond.OutCoder) + bond.OutStream;
- mixerBond.UnpackIndex = bond.InCoder;
- _bindInfo.Bonds.Add(mixerBond);
- }
-
- for (i = 0; i < numOutStreams; i++)
- if (_bindInfo.FindBond_for_PackStream(i) == -1)
- _bindInfo.PackStreams.Add(i);
- }
-
- if (!_bindInfo.SetUnpackCoder())
- return E_INVALIDARG;
-
- if (!_bindInfo.CalcMapsAndCheck())
- return E_INVALIDARG;
-
- if (_bindInfo.PackStreams.Size() != 1)
- {
- /* main_PackStream is pack stream of main path of coders tree.
- We find main_PackStream, and place to start of list of out streams.
- It allows to use more optimal memory usage for temp buffers,
- if main_PackStream is largest stream. */
-
- UInt32 ci = _bindInfo.UnpackCoder;
-
- for (;;)
- {
- if (_bindInfo.Coders[ci].NumStreams == 0)
- break;
-
- UInt32 outIndex = _bindInfo.Coder_to_Stream[ci];
- int bond = _bindInfo.FindBond_for_PackStream(outIndex);
- if (bond >= 0)
- {
- ci = _bindInfo.Bonds[bond].UnpackIndex;
- continue;
- }
-
- int si = _bindInfo.FindStream_in_PackStreams(outIndex);
- if (si >= 0)
- _bindInfo.PackStreams.MoveToFront(si);
- break;
- }
- }
-
- if (_options.PasswordIsDefined)
- {
- unsigned numCryptoStreams = _bindInfo.PackStreams.Size();
-
- unsigned numInStreams = _bindInfo.Coders.Size();
-
- for (i = 0; i < numCryptoStreams; i++)
- {
- NCoderMixer2::CBond bond;
- bond.UnpackIndex = numInStreams + i;
- bond.PackIndex = _bindInfo.PackStreams[i];
- _bindInfo.Bonds.Add(bond);
- }
- _bindInfo.PackStreams.Clear();
-
- /*
- if (numCryptoStreams == 0)
- numCryptoStreams = 1;
- */
-
- for (i = 0; i < numCryptoStreams; i++)
- {
- CMethodFull method;
- method.NumStreams = 1;
- method.Id = k_AES;
- _options.Methods.Add(method);
-
- NCoderMixer2::CCoderStreamsInfo cod;
- cod.NumStreams = 1;
- _bindInfo.Coders.Add(cod);
-
- _bindInfo.PackStreams.Add(numOutStreams++);
- }
- }
-
- }
-
- for (unsigned i = _options.Methods.Size(); i != 0;)
- _decompressionMethods.Add(_options.Methods[--i].Id);
-
- if (_bindInfo.Coders.Size() > 16)
- return E_INVALIDARG;
- if (_bindInfo.GetNum_Bonds_and_PackStreams() > 16)
- return E_INVALIDARG;
-
- if (!_bindInfo.CalcMapsAndCheck())
- return E_INVALIDARG;
-
- InitBindConv();
- _constructed = true;
- return S_OK;
-}
-
-CEncoder::~CEncoder() {}
-
-}}
+// 7zEncode.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/ComTry.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"
+
+namespace NArchive {
+namespace N7z {
+
+void CEncoder::InitBindConv()
+{
+ unsigned numIn = _bindInfo.Coders.Size();
+
+ SrcIn_to_DestOut.ClearAndSetSize(numIn);
+ DestOut_to_SrcIn.ClearAndSetSize(numIn);
+
+ unsigned numOut = _bindInfo.GetNum_Bonds_and_PackStreams();
+ SrcOut_to_DestIn.ClearAndSetSize(numOut);
+ // _DestIn_to_SrcOut.ClearAndSetSize(numOut);
+
+ UInt32 destIn = 0;
+ UInt32 destOut = 0;
+
+ for (unsigned i = _bindInfo.Coders.Size(); i != 0;)
+ {
+ i--;
+
+ const NCoderMixer2::CCoderStreamsInfo &coder = _bindInfo.Coders[i];
+
+ numIn--;
+ numOut -= coder.NumStreams;
+
+ SrcIn_to_DestOut[numIn] = destOut;
+ DestOut_to_SrcIn[destOut] = numIn;
+
+ destOut++;
+
+ for (UInt32 j = 0; j < coder.NumStreams; j++, destIn++)
+ {
+ UInt32 index = numOut + j;
+ SrcOut_to_DestIn[index] = destIn;
+ // _DestIn_to_SrcOut[destIn] = index;
+ }
+ }
+}
+
+void CEncoder::SetFolder(CFolder &folder)
+{
+ folder.Bonds.SetSize(_bindInfo.Bonds.Size());
+
+ unsigned i;
+
+ for (i = 0; i < _bindInfo.Bonds.Size(); i++)
+ {
+ CBond &fb = folder.Bonds[i];
+ const NCoderMixer2::CBond &mixerBond = _bindInfo.Bonds[_bindInfo.Bonds.Size() - 1 - i];
+ fb.PackIndex = SrcOut_to_DestIn[mixerBond.PackIndex];
+ fb.UnpackIndex = SrcIn_to_DestOut[mixerBond.UnpackIndex];
+ }
+
+ folder.Coders.SetSize(_bindInfo.Coders.Size());
+
+ for (i = 0; i < _bindInfo.Coders.Size(); i++)
+ {
+ CCoderInfo &coderInfo = folder.Coders[i];
+ const NCoderMixer2::CCoderStreamsInfo &coderStreamsInfo = _bindInfo.Coders[_bindInfo.Coders.Size() - 1 - i];
+
+ coderInfo.NumStreams = coderStreamsInfo.NumStreams;
+ coderInfo.MethodID = _decompressionMethods[i];
+ // we don't free coderInfo.Props here. So coderInfo.Props can be non-empty.
+ }
+
+ folder.PackStreams.SetSize(_bindInfo.PackStreams.Size());
+
+ for (i = 0; i < _bindInfo.PackStreams.Size(); i++)
+ folder.PackStreams[i] = SrcOut_to_DestIn[_bindInfo.PackStreams[i]];
+}
+
+
+
+static HRESULT SetCoderProps2(const CProps &props, const UInt64 *dataSizeReduce, IUnknown *coder)
+{
+ Z7_DECL_CMyComPtr_QI_FROM(
+ ICompressSetCoderProperties,
+ setCoderProperties, coder)
+ if (setCoderProperties)
+ return props.SetCoderProps(setCoderProperties, dataSizeReduce);
+ return props.AreThereNonOptionalProps() ? E_INVALIDARG : S_OK;
+}
+
+
+
+void CMtEncMultiProgress::Init(ICompressProgressInfo *progress)
+{
+ _progress = progress;
+ OutSize = 0;
+}
+
+Z7_COM7F_IMF(CMtEncMultiProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */))
+{
+ UInt64 outSize2;
+ {
+ #ifndef Z7_ST
+ NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
+ #endif
+ outSize2 = OutSize;
+ }
+
+ if (_progress)
+ return _progress->SetRatioInfo(inSize, &outSize2);
+
+ return S_OK;
+}
+
+
+
+HRESULT CEncoder::CreateMixerCoder(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const UInt64 *inSizeForReduce)
+{
+ #ifdef USE_MIXER_MT
+ #ifdef USE_MIXER_ST
+ if (_options.MultiThreadMixer)
+ #endif
+ {
+ _mixerMT = new NCoderMixer2::CMixerMT(true);
+ _mixerRef = _mixerMT;
+ _mixer = _mixerMT;
+ }
+ #ifdef USE_MIXER_ST
+ else
+ #endif
+ #endif
+ {
+ #ifdef USE_MIXER_ST
+ _mixerST = new NCoderMixer2::CMixerST(true);
+ _mixerRef = _mixerST;
+ _mixer = _mixerST;
+ #endif
+ }
+
+ RINOK(_mixer->SetBindInfo(_bindInfo))
+
+ FOR_VECTOR (m, _options.Methods)
+ {
+ const CMethodFull &methodFull = _options.Methods[m];
+
+ CCreatedCoder cod;
+
+ if (methodFull.CodecIndex >= 0)
+ {
+ RINOK(CreateCoder_Index(
+ EXTERNAL_CODECS_LOC_VARS
+ (unsigned)methodFull.CodecIndex, true, cod))
+ }
+ else
+ {
+ RINOK(CreateCoder_Id(
+ EXTERNAL_CODECS_LOC_VARS
+ methodFull.Id, true, cod))
+ }
+
+ if (!cod.Coder && !cod.Coder2)
+ {
+ return E_NOTIMPL; // unsupported method, if encoder
+ // return E_FAIL;
+ }
+
+ if (cod.NumStreams != methodFull.NumStreams)
+ return E_FAIL;
+
+ CMyComPtr<IUnknown> encoderCommon = cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2;
+
+ #ifndef Z7_ST
+ if (methodFull.Set_NumThreads)
+ {
+ CMyComPtr<ICompressSetCoderMt> setCoderMt;
+ encoderCommon.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
+ if (setCoderMt)
+ {
+ RINOK(setCoderMt->SetNumberOfThreads(
+ /* _options.NumThreads */
+ methodFull.NumThreads
+ ))
+ }
+ }
+ #endif
+
+ RINOK(SetCoderProps2(methodFull, inSizeForReduce, encoderCommon))
+
+ /*
+ CMyComPtr<ICryptoResetSalt> resetSalt;
+ encoderCommon.QueryInterface(IID_ICryptoResetSalt, (void **)&resetSalt);
+ if (resetSalt)
+ {
+ resetSalt->ResetSalt();
+ }
+ */
+
+ // now there is no codec that uses another external codec
+ /*
+ #ifdef Z7_EXTERNAL_CODECS
+ CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+ encoderCommon.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+ if (setCompressCodecsInfo)
+ {
+ // we must use g_ExternalCodecs also
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(_externalCodecs->GetCodecs));
+ }
+ #endif
+ */
+
+ CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+ encoderCommon.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword);
+
+ if (cryptoSetPassword)
+ {
+ const unsigned sizeInBytes = _options.Password.Len() * 2;
+ CByteBuffer_Wipe buffer(sizeInBytes);
+ for (unsigned i = 0; i < _options.Password.Len(); 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, (UInt32)sizeInBytes))
+ }
+
+ _mixer->AddCoder(cod);
+ }
+ return S_OK;
+}
+
+
+
+Z7_CLASS_IMP_COM_1(
+ CSequentialOutTempBufferImp2
+ , ISequentialOutStream
+)
+public:
+ CInOutTempBuffer TempBuffer;
+ CMtEncMultiProgress *_mtProgressSpec;
+
+ CSequentialOutTempBufferImp2(): _mtProgressSpec(NULL) {}
+};
+
+Z7_COM7F_IMF(CSequentialOutTempBufferImp2::Write(const void *data, UInt32 size, UInt32 *processed))
+{
+ COM_TRY_BEGIN
+ if (processed)
+ *processed = 0;
+ RINOK(TempBuffer.Write_HRESULT(data, size))
+ if (processed)
+ *processed = size;
+ if (_mtProgressSpec)
+ _mtProgressSpec->AddOutSize(size);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_CLASS_IMP_COM_1(
+ CSequentialOutMtNotify
+ , ISequentialOutStream
+)
+public:
+ CMyComPtr<ISequentialOutStream> _stream;
+ CMtEncMultiProgress *_mtProgressSpec;
+
+ CSequentialOutMtNotify(): _mtProgressSpec(NULL) {}
+};
+
+Z7_COM7F_IMF(CSequentialOutMtNotify::Write(const void *data, UInt32 size, UInt32 *processed))
+{
+ UInt32 realProcessed = 0;
+ HRESULT res = _stream->Write(data, size, &realProcessed);
+ if (processed)
+ *processed = realProcessed;
+ if (_mtProgressSpec)
+ _mtProgressSpec->AddOutSize(size);
+ return res;
+}
+
+
+static HRESULT FillProps_from_Coder(IUnknown *coder, CByteBuffer &props)
+{
+ Z7_DECL_CMyComPtr_QI_FROM(
+ ICompressWriteCoderProperties,
+ writeCoderProperties, coder)
+ if (writeCoderProperties)
+ {
+ CDynBufSeqOutStream *outStreamSpec = new CDynBufSeqOutStream;
+ CMyComPtr<ISequentialOutStream> dynOutStream(outStreamSpec);
+ outStreamSpec->Init();
+ RINOK(writeCoderProperties->WriteCoderProperties(dynOutStream))
+ outStreamSpec->CopyToBuffer(props);
+ }
+ else
+ props.Free();
+ return S_OK;
+}
+
+HRESULT CEncoder::Encode1(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ ISequentialInStream *inStream,
+ // const UInt64 *inStreamSize,
+ const UInt64 *inSizeForReduce,
+ UInt64 expectedDataSize,
+ CFolder &folderItem,
+ // CRecordVector<UInt64> &coderUnpackSizes,
+ // UInt64 &unpackSize,
+ ISequentialOutStream *outStream,
+ CRecordVector<UInt64> &packSizes,
+ ICompressProgressInfo *compressProgress)
+{
+ RINOK(EncoderConstr())
+
+ if (!_mixerRef)
+ {
+ RINOK(CreateMixerCoder(EXTERNAL_CODECS_LOC_VARS inSizeForReduce))
+ }
+
+ RINOK(_mixer->ReInit2())
+
+ CMtEncMultiProgress *mtProgressSpec = NULL;
+ CMyComPtr<ICompressProgressInfo> mtProgress;
+
+ CSequentialOutMtNotify *mtOutStreamNotifySpec = NULL;
+ CMyComPtr<ISequentialOutStream> mtOutStreamNotify;
+
+ CRecordVector<CSequentialOutTempBufferImp2 *> tempBufferSpecs;
+ CObjectVector<CMyComPtr<ISequentialOutStream> > tempBuffers;
+
+ unsigned i;
+
+ for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
+ {
+ CSequentialOutTempBufferImp2 *tempBufferSpec = new CSequentialOutTempBufferImp2();
+ CMyComPtr<ISequentialOutStream> tempBuffer = tempBufferSpec;
+ tempBufferSpecs.Add(tempBufferSpec);
+ tempBuffers.Add(tempBuffer);
+ }
+
+ const unsigned numMethods = _bindInfo.Coders.Size();
+
+ for (i = 0; i < numMethods; i++)
+ _mixer->SetCoderInfo(i, NULL, NULL, false);
+
+
+ /* inStreamSize can be used by BCJ2 to set optimal range of conversion.
+ But current BCJ2 encoder uses also another way to check exact size of current file.
+ So inStreamSize is not required. */
+
+ /*
+ if (inStreamSize)
+ _mixer->SetCoderInfo(_bindInfo.UnpackCoder, inStreamSize, NULL);
+ */
+
+
+ /*
+ CSequentialInStreamSizeCount2 *inStreamSizeCountSpec = new CSequentialInStreamSizeCount2;
+ CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
+ */
+
+ CSequentialOutStreamSizeCount *outStreamSizeCountSpec = NULL;
+ CMyComPtr<ISequentialOutStream> outStreamSizeCount;
+
+ // inStreamSizeCountSpec->Init(inStream);
+
+ // ISequentialInStream *inStreamPointer = inStreamSizeCount;
+ ISequentialInStream *inStreamPointer = inStream;
+
+ CRecordVector<ISequentialOutStream *> outStreamPointers;
+
+ SetFolder(folderItem);
+
+ for (i = 0; i < numMethods; i++)
+ {
+ IUnknown *coder = _mixer->GetCoder(i).GetUnknown();
+ /*
+ {
+ CEncoder *sfEncoder = NULL;
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IGetSfEncoderInternal,
+ sf, coder)
+ if (sf)
+ {
+ RINOK(sf->GetSfEncoder(&sfEncoder));
+ if (!sfEncoder)
+ return E_FAIL;
+
+ }
+ }
+ */
+ /*
+ #ifdef Z7_EXTERNAL_CODECS
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ ISetCompressCodecsInfo,
+ setCompressCodecsInfo, coder)
+ if (setCompressCodecsInfo)
+ {
+ // we must use g_ExternalCodecs also
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(_externalCodecs->GetCodecs))
+ }
+ }
+ #endif
+ */
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ ICryptoResetInitVector,
+ resetInitVector, coder)
+ if (resetInitVector)
+ {
+ RINOK(resetInitVector->ResetInitVector())
+ }
+ }
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ ICompressSetCoderPropertiesOpt,
+ optProps, coder)
+ if (optProps)
+ {
+ const PROPID propID = NCoderPropID::kExpectedDataSize;
+ NWindows::NCOM::CPropVariant prop = (UInt64)expectedDataSize;
+ RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1))
+ }
+ }
+ // we must write properties from coder after ResetInitVector()
+ RINOK(FillProps_from_Coder(coder, folderItem.Coders[numMethods - 1 - i].Props))
+ }
+
+ _mixer->SelectMainCoder(false);
+ const UInt32 mainCoder = _mixer->MainCoderIndex;
+
+ bool useMtProgress = false;
+ if (!_mixer->Is_PackSize_Correct_for_Coder(mainCoder))
+ {
+ #ifdef Z7_ST
+ if (!_mixer->IsThere_ExternalCoder_in_PackTree(mainCoder))
+ #endif
+ useMtProgress = true;
+ }
+
+ if (useMtProgress)
+ {
+ mtProgressSpec = new CMtEncMultiProgress;
+ mtProgress = mtProgressSpec;
+ mtProgressSpec->Init(compressProgress);
+
+ mtOutStreamNotifySpec = new CSequentialOutMtNotify;
+ mtOutStreamNotify = mtOutStreamNotifySpec;
+ mtOutStreamNotifySpec->_stream = outStream;
+ mtOutStreamNotifySpec->_mtProgressSpec = mtProgressSpec;
+
+ FOR_VECTOR (t, tempBufferSpecs)
+ {
+ tempBufferSpecs[t]->_mtProgressSpec = mtProgressSpec;
+ }
+ }
+
+
+ if (_bindInfo.PackStreams.Size() != 0)
+ {
+ outStreamSizeCountSpec = new CSequentialOutStreamSizeCount;
+ outStreamSizeCount = outStreamSizeCountSpec;
+ outStreamSizeCountSpec->SetStream(mtOutStreamNotify ? (ISequentialOutStream *)mtOutStreamNotify : outStream);
+ outStreamSizeCountSpec->Init();
+ outStreamPointers.Add(outStreamSizeCount);
+ }
+
+ for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
+ outStreamPointers.Add(tempBuffers[i - 1]);
+
+ bool dataAfterEnd_Error;
+
+ RINOK(_mixer->Code(
+ &inStreamPointer,
+ &outStreamPointers.Front(),
+ mtProgress ? (ICompressProgressInfo *)mtProgress : compressProgress, dataAfterEnd_Error))
+
+ if (_bindInfo.PackStreams.Size() != 0)
+ packSizes.Add(outStreamSizeCountSpec->GetSize());
+
+ for (i = 1; i < _bindInfo.PackStreams.Size(); i++)
+ {
+ CInOutTempBuffer &iotb = tempBufferSpecs[i - 1]->TempBuffer;
+ RINOK(iotb.WriteToStream(outStream))
+ packSizes.Add(iotb.GetDataSize());
+ }
+
+ /* Code() in some future codec can change properties.
+ v23: so we fill properties again after Code() */
+ for (i = 0; i < numMethods; i++)
+ {
+ IUnknown *coder = _mixer->GetCoder(i).GetUnknown();
+ RINOK(FillProps_from_Coder(coder, folderItem.Coders[numMethods - 1 - i].Props))
+ }
+
+ return S_OK;
+}
+
+
+void CEncoder::Encode_Post(
+ UInt64 unpackSize,
+ CRecordVector<UInt64> &coderUnpackSizes)
+{
+ // unpackSize = 0;
+ for (unsigned i = 0; i < _bindInfo.Coders.Size(); i++)
+ {
+ const int bond = _bindInfo.FindBond_for_UnpackStream(DestOut_to_SrcIn[i]);
+ UInt64 streamSize;
+ if (bond < 0)
+ {
+ // streamSize = inStreamSizeCountSpec->GetSize();
+ // unpackSize = streamSize;
+ streamSize = unpackSize;
+ }
+ else
+ streamSize = _mixer->GetBondStreamSize((unsigned)bond);
+ coderUnpackSizes.Add(streamSize);
+ }
+}
+
+
+CEncoder::CEncoder(const CCompressionMethodMode &options):
+ _constructed(false)
+{
+ if (options.IsEmpty())
+ throw 1;
+
+ _options = options;
+
+ #ifdef USE_MIXER_ST
+ _mixerST = NULL;
+ #endif
+
+ #ifdef USE_MIXER_MT
+ _mixerMT = NULL;
+ #endif
+
+ _mixer = 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.Bonds.IsEmpty())
+ throw 1;
+
+ CMethodFull method;
+ method.Id = k_AES;
+ method.NumStreams = 1;
+ _options.Methods.Add(method);
+
+ NCoderMixer2::CCoderStreamsInfo coderStreamsInfo;
+ coderStreamsInfo.NumStreams = 1;
+ _bindInfo.Coders.Add(coderStreamsInfo);
+
+ _bindInfo.PackStreams.Add(0);
+ _bindInfo.UnpackCoder = 0;
+ }
+ else
+ {
+
+ UInt32 numOutStreams = 0;
+ unsigned i;
+
+ for (i = 0; i < _options.Methods.Size(); i++)
+ {
+ const CMethodFull &methodFull = _options.Methods[i];
+ NCoderMixer2::CCoderStreamsInfo cod;
+
+ cod.NumStreams = methodFull.NumStreams;
+
+ if (_options.Bonds.IsEmpty())
+ {
+ // if there are no bonds in options, we create bonds via first streams of coders
+ if (i != _options.Methods.Size() - 1)
+ {
+ NCoderMixer2::CBond bond;
+ bond.PackIndex = numOutStreams;
+ bond.UnpackIndex = i + 1; // it's next coder
+ _bindInfo.Bonds.Add(bond);
+ }
+ else if (cod.NumStreams != 0)
+ _bindInfo.PackStreams.Insert(0, numOutStreams);
+
+ for (UInt32 j = 1; j < cod.NumStreams; j++)
+ _bindInfo.PackStreams.Add(numOutStreams + j);
+ }
+
+ numOutStreams += cod.NumStreams;
+
+ _bindInfo.Coders.Add(cod);
+ }
+
+ if (!_options.Bonds.IsEmpty())
+ {
+ for (i = 0; i < _options.Bonds.Size(); i++)
+ {
+ NCoderMixer2::CBond mixerBond;
+ const CBond2 &bond = _options.Bonds[i];
+ if (bond.InCoder >= _bindInfo.Coders.Size()
+ || bond.OutCoder >= _bindInfo.Coders.Size()
+ || bond.OutStream >= _bindInfo.Coders[bond.OutCoder].NumStreams)
+ return E_INVALIDARG;
+ mixerBond.PackIndex = _bindInfo.GetStream_for_Coder(bond.OutCoder) + bond.OutStream;
+ mixerBond.UnpackIndex = bond.InCoder;
+ _bindInfo.Bonds.Add(mixerBond);
+ }
+
+ for (i = 0; i < numOutStreams; i++)
+ if (_bindInfo.FindBond_for_PackStream(i) == -1)
+ _bindInfo.PackStreams.Add(i);
+ }
+
+ if (!_bindInfo.SetUnpackCoder())
+ return E_INVALIDARG;
+
+ if (!_bindInfo.CalcMapsAndCheck())
+ return E_INVALIDARG;
+
+ if (_bindInfo.PackStreams.Size() != 1)
+ {
+ /* main_PackStream is pack stream of main path of coders tree.
+ We find main_PackStream, and place to start of list of out streams.
+ It allows to use more optimal memory usage for temp buffers,
+ if main_PackStream is largest stream. */
+
+ UInt32 ci = _bindInfo.UnpackCoder;
+
+ for (;;)
+ {
+ if (_bindInfo.Coders[ci].NumStreams == 0)
+ break;
+
+ const UInt32 outIndex = _bindInfo.Coder_to_Stream[ci];
+ const int bond = _bindInfo.FindBond_for_PackStream(outIndex);
+ if (bond >= 0)
+ {
+ ci = _bindInfo.Bonds[(unsigned)bond].UnpackIndex;
+ continue;
+ }
+
+ const int si = _bindInfo.FindStream_in_PackStreams(outIndex);
+ if (si >= 0)
+ _bindInfo.PackStreams.MoveToFront((unsigned)si);
+ break;
+ }
+ }
+
+ if (_options.PasswordIsDefined)
+ {
+ unsigned numCryptoStreams = _bindInfo.PackStreams.Size();
+
+ unsigned numInStreams = _bindInfo.Coders.Size();
+
+ for (i = 0; i < numCryptoStreams; i++)
+ {
+ NCoderMixer2::CBond bond;
+ bond.UnpackIndex = numInStreams + i;
+ bond.PackIndex = _bindInfo.PackStreams[i];
+ _bindInfo.Bonds.Add(bond);
+ }
+ _bindInfo.PackStreams.Clear();
+
+ /*
+ if (numCryptoStreams == 0)
+ numCryptoStreams = 1;
+ */
+
+ for (i = 0; i < numCryptoStreams; i++)
+ {
+ CMethodFull method;
+ method.NumStreams = 1;
+ method.Id = k_AES;
+ _options.Methods.Add(method);
+
+ NCoderMixer2::CCoderStreamsInfo cod;
+ cod.NumStreams = 1;
+ _bindInfo.Coders.Add(cod);
+
+ _bindInfo.PackStreams.Add(numOutStreams++);
+ }
+ }
+
+ }
+
+ for (unsigned i = _options.Methods.Size(); i != 0;)
+ _decompressionMethods.Add(_options.Methods[--i].Id);
+
+ if (_bindInfo.Coders.Size() > 16)
+ return E_INVALIDARG;
+ if (_bindInfo.GetNum_Bonds_and_PackStreams() > 16)
+ return E_INVALIDARG;
+
+ if (!_bindInfo.CalcMapsAndCheck())
+ return E_INVALIDARG;
+
+ InitBindConv();
+ _constructed = true;
+ return S_OK;
+}
+
+CEncoder::~CEncoder() {}
+
+}}
diff --git a/CPP/7zip/Archive/7z/7zEncode.h b/CPP/7zip/Archive/7z/7zEncode.h
index 434cbec..849ac63 100644
--- a/CPP/7zip/Archive/7z/7zEncode.h
+++ b/CPP/7zip/Archive/7z/7zEncode.h
@@ -1,92 +1,95 @@
-// 7zEncode.h
-
-#ifndef __7Z_ENCODE_H
-#define __7Z_ENCODE_H
-
-#include "7zCompressionMode.h"
-
-#include "../Common/CoderMixer2.h"
-
-#include "7zItem.h"
-
-namespace NArchive {
-namespace N7z {
-
-class CMtEncMultiProgress:
- public ICompressProgressInfo,
- public CMyUnknownImp
-{
- CMyComPtr<ICompressProgressInfo> _progress;
- #ifndef _7ZIP_ST
- NWindows::NSynchronization::CCriticalSection CriticalSection;
- #endif
-
-public:
- UInt64 OutSize;
-
- CMtEncMultiProgress(): OutSize(0) {}
-
- void Init(ICompressProgressInfo *progress);
-
- void AddOutSize(UInt64 addOutSize)
- {
- #ifndef _7ZIP_ST
- NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
- #endif
- OutSize += addOutSize;
- }
-
- MY_UNKNOWN_IMP1(ICompressProgressInfo)
-
- STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
-};
-
-class CEncoder
-{
- #ifdef USE_MIXER_ST
- NCoderMixer2::CMixerST *_mixerST;
- #endif
- #ifdef USE_MIXER_MT
- NCoderMixer2::CMixerMT *_mixerMT;
- #endif
-
- NCoderMixer2::CMixer *_mixer;
- CMyComPtr<IUnknown> _mixerRef;
-
- CCompressionMethodMode _options;
- NCoderMixer2::CBindInfo _bindInfo;
- CRecordVector<CMethodId> _decompressionMethods;
-
- CRecordVector<UInt32> _SrcIn_to_DestOut;
- CRecordVector<UInt32> _SrcOut_to_DestIn;
- // CRecordVector<UInt32> _DestIn_to_SrcOut;
- CRecordVector<UInt32> _DestOut_to_SrcIn;
-
- void InitBindConv();
- void SetFolder(CFolder &folder);
-
- 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,
- CRecordVector<UInt64> &coderUnpackSizes,
- UInt64 &unpackSize,
- ISequentialOutStream *outStream,
- CRecordVector<UInt64> &packSizes,
- ICompressProgressInfo *compressProgress);
-};
-
-}}
-
-#endif
+// 7zEncode.h
+
+#ifndef ZIP7_INC_7Z_ENCODE_H
+#define ZIP7_INC_7Z_ENCODE_H
+
+#include "7zCompressionMode.h"
+
+#include "../Common/CoderMixer2.h"
+
+#include "7zItem.h"
+
+namespace NArchive {
+namespace N7z {
+
+Z7_CLASS_IMP_COM_1(
+ CMtEncMultiProgress,
+ ICompressProgressInfo
+)
+ CMyComPtr<ICompressProgressInfo> _progress;
+ #ifndef Z7_ST
+ NWindows::NSynchronization::CCriticalSection CriticalSection;
+ #endif
+
+public:
+ UInt64 OutSize;
+
+ CMtEncMultiProgress(): OutSize(0) {}
+
+ void Init(ICompressProgressInfo *progress);
+
+ void AddOutSize(UInt64 addOutSize)
+ {
+ #ifndef Z7_ST
+ NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
+ #endif
+ OutSize += addOutSize;
+ }
+};
+
+
+class CEncoder Z7_final MY_UNCOPYABLE
+{
+ #ifdef USE_MIXER_ST
+ NCoderMixer2::CMixerST *_mixerST;
+ #endif
+ #ifdef USE_MIXER_MT
+ NCoderMixer2::CMixerMT *_mixerMT;
+ #endif
+
+ NCoderMixer2::CMixer *_mixer;
+ CMyComPtr<IUnknown> _mixerRef;
+
+ CCompressionMethodMode _options;
+ NCoderMixer2::CBindInfo _bindInfo;
+ CRecordVector<CMethodId> _decompressionMethods;
+
+ CRecordVector<UInt32> SrcIn_to_DestOut;
+ CRecordVector<UInt32> SrcOut_to_DestIn;
+ // CRecordVector<UInt32> DestIn_to_SrcOut;
+ CRecordVector<UInt32> DestOut_to_SrcIn;
+
+ void InitBindConv();
+ void SetFolder(CFolder &folder);
+
+ HRESULT CreateMixerCoder(DECL_EXTERNAL_CODECS_LOC_VARS
+ const UInt64 *inSizeForReduce);
+
+ bool _constructed;
+public:
+
+ CEncoder(const CCompressionMethodMode &options);
+ ~CEncoder();
+ HRESULT EncoderConstr();
+ HRESULT Encode1(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ ISequentialInStream *inStream,
+ // const UInt64 *inStreamSize,
+ const UInt64 *inSizeForReduce,
+ UInt64 expectedDataSize,
+ CFolder &folderItem,
+ // CRecordVector<UInt64> &coderUnpackSizes,
+ // UInt64 &unpackSize,
+ ISequentialOutStream *outStream,
+ CRecordVector<UInt64> &packSizes,
+ ICompressProgressInfo *compressProgress);
+
+ void Encode_Post(
+ UInt64 unpackSize,
+ CRecordVector<UInt64> &coderUnpackSizes);
+
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/7z/7zExtract.cpp b/CPP/7zip/Archive/7z/7zExtract.cpp
index 075644f..5498c59 100644
--- a/CPP/7zip/Archive/7z/7zExtract.cpp
+++ b/CPP/7zip/Archive/7z/7zExtract.cpp
@@ -1,423 +1,445 @@
-// 7zExtract.cpp
-
-#include "StdAfx.h"
-
-#include "../../../../C/7zCrc.h"
-
-#include "../../../Common/ComTry.h"
-
-#include "../../Common/ProgressUtils.h"
-
-#include "7zDecode.h"
-#include "7zHandler.h"
-
-// EXTERN_g_ExternalCodecs
-
-namespace NArchive {
-namespace N7z {
-
-class CFolderOutStream:
- public ISequentialOutStream,
- public CMyUnknownImp
-{
- CMyComPtr<ISequentialOutStream> _stream;
-public:
- bool TestMode;
- bool CheckCrc;
-private:
- bool _fileIsOpen;
- bool _calcCrc;
- UInt32 _crc;
- UInt64 _rem;
-
- const UInt32 *_indexes;
- unsigned _numFiles;
- unsigned _fileIndex;
-
- HRESULT OpenFile(bool isCorrupted = false);
- HRESULT CloseFile_and_SetResult(Int32 res);
- HRESULT CloseFile();
- HRESULT ProcessEmptyFiles();
-
-public:
- MY_UNKNOWN_IMP1(ISequentialOutStream)
-
- const CDbEx *_db;
- CMyComPtr<IArchiveExtractCallback> ExtractCallback;
-
- bool ExtraWriteWasCut;
-
- CFolderOutStream():
- TestMode(false),
- CheckCrc(true)
- {}
-
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
-
- HRESULT Init(unsigned startIndex, const UInt32 *indexes, unsigned numFiles);
- HRESULT FlushCorrupted(Int32 callbackOperationResult);
-
- bool WasWritingFinished() const { return _numFiles == 0; }
-};
-
-
-HRESULT CFolderOutStream::Init(unsigned startIndex, const UInt32 *indexes, unsigned numFiles)
-{
- _fileIndex = startIndex;
- _indexes = indexes;
- _numFiles = numFiles;
-
- _fileIsOpen = false;
- ExtraWriteWasCut = false;
-
- return ProcessEmptyFiles();
-}
-
-HRESULT CFolderOutStream::OpenFile(bool isCorrupted)
-{
- const CFileItem &fi = _db->Files[_fileIndex];
- UInt32 nextFileIndex = (_indexes ? *_indexes : _fileIndex);
- Int32 askMode = (_fileIndex == nextFileIndex) ?
- (TestMode ?
- NExtract::NAskMode::kTest :
- NExtract::NAskMode::kExtract) :
- NExtract::NAskMode::kSkip;
-
- if (isCorrupted
- && askMode == NExtract::NAskMode::kExtract
- && !_db->IsItemAnti(_fileIndex)
- && !fi.IsDir)
- askMode = NExtract::NAskMode::kTest;
-
- CMyComPtr<ISequentialOutStream> realOutStream;
- RINOK(ExtractCallback->GetStream(_fileIndex, &realOutStream, askMode));
-
- _stream = realOutStream;
- _crc = CRC_INIT_VAL;
- _calcCrc = (CheckCrc && fi.CrcDefined && !fi.IsDir);
-
- _fileIsOpen = true;
- _rem = fi.Size;
-
- if (askMode == NExtract::NAskMode::kExtract
- && !realOutStream
- && !_db->IsItemAnti(_fileIndex)
- && !fi.IsDir)
- askMode = NExtract::NAskMode::kSkip;
- return ExtractCallback->PrepareOperation(askMode);
-}
-
-HRESULT CFolderOutStream::CloseFile_and_SetResult(Int32 res)
-{
- _stream.Release();
- _fileIsOpen = false;
-
- if (!_indexes)
- _numFiles--;
- else if (*_indexes == _fileIndex)
- {
- _indexes++;
- _numFiles--;
- }
-
- _fileIndex++;
- return ExtractCallback->SetOperationResult(res);
-}
-
-HRESULT CFolderOutStream::CloseFile()
-{
- const CFileItem &fi = _db->Files[_fileIndex];
- return CloseFile_and_SetResult((!_calcCrc || fi.Crc == CRC_GET_DIGEST(_crc)) ?
- NExtract::NOperationResult::kOK :
- NExtract::NOperationResult::kCRCError);
-}
-
-HRESULT CFolderOutStream::ProcessEmptyFiles()
-{
- while (_numFiles != 0 && _db->Files[_fileIndex].Size == 0)
- {
- RINOK(OpenFile());
- RINOK(CloseFile());
- }
- return S_OK;
-}
-
-STDMETHODIMP CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
-
- while (size != 0)
- {
- if (_fileIsOpen)
- {
- UInt32 cur = (size < _rem ? size : (UInt32)_rem);
- if (_calcCrc)
- {
- const UInt32 k_Step = (UInt32)1 << 20;
- if (cur > k_Step)
- cur = k_Step;
- }
- HRESULT result = S_OK;
- if (_stream)
- result = _stream->Write(data, cur, &cur);
- if (_calcCrc)
- _crc = CrcUpdate(_crc, data, cur);
- if (processedSize)
- *processedSize += cur;
- data = (const Byte *)data + cur;
- size -= cur;
- _rem -= cur;
- if (_rem == 0)
- {
- RINOK(CloseFile());
- RINOK(ProcessEmptyFiles());
- }
- RINOK(result);
- if (cur == 0)
- break;
- continue;
- }
-
- RINOK(ProcessEmptyFiles());
- if (_numFiles == 0)
- {
- // we support partial extracting
- /*
- if (processedSize)
- *processedSize += size;
- break;
- */
- ExtraWriteWasCut = true;
- // return S_FALSE;
- return k_My_HRESULT_WritingWasCut;
- }
- RINOK(OpenFile());
- }
-
- return S_OK;
-}
-
-HRESULT CFolderOutStream::FlushCorrupted(Int32 callbackOperationResult)
-{
- while (_numFiles != 0)
- {
- if (_fileIsOpen)
- {
- RINOK(CloseFile_and_SetResult(callbackOperationResult));
- }
- else
- {
- RINOK(OpenFile(true));
- }
- }
- return S_OK;
-}
-
-STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
- Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec)
-{
- COM_TRY_BEGIN
-
- CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
-
- UInt64 importantTotalUnpacked = 0;
-
- // numItems = (UInt32)(Int32)-1;
-
- bool allFilesMode = (numItems == (UInt32)(Int32)-1);
- if (allFilesMode)
- numItems = _db.Files.Size();
-
- if (numItems == 0)
- return S_OK;
-
- {
- CNum prevFolder = kNumNoIndex;
- UInt32 nextFile = 0;
-
- UInt32 i;
-
- for (i = 0; i < numItems; i++)
- {
- UInt32 fileIndex = allFilesMode ? i : indices[i];
- CNum folderIndex = _db.FileIndexToFolderIndexMap[fileIndex];
- if (folderIndex == kNumNoIndex)
- continue;
- if (folderIndex != prevFolder || fileIndex < nextFile)
- nextFile = _db.FolderStartFileIndex[folderIndex];
- for (CNum index = nextFile; index <= fileIndex; index++)
- importantTotalUnpacked += _db.Files[index].Size;
- nextFile = fileIndex + 1;
- prevFolder = folderIndex;
- }
- }
-
- RINOK(extractCallback->SetTotal(importantTotalUnpacked));
-
- CLocalProgress *lps = new CLocalProgress;
- CMyComPtr<ICompressProgressInfo> progress = lps;
- lps->Init(extractCallback, false);
-
- CDecoder decoder(
- #if !defined(USE_MIXER_MT)
- false
- #elif !defined(USE_MIXER_ST)
- true
- #elif !defined(__7Z_SET_PROPERTIES)
- #ifdef _7ZIP_ST
- false
- #else
- true
- #endif
- #else
- _useMultiThreadMixer
- #endif
- );
-
- UInt64 curPacked, curUnpacked;
-
- CMyComPtr<IArchiveExtractCallbackMessage> callbackMessage;
- extractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage, &callbackMessage);
-
- CFolderOutStream *folderOutStream = new CFolderOutStream;
- CMyComPtr<ISequentialOutStream> outStream(folderOutStream);
-
- folderOutStream->_db = &_db;
- folderOutStream->ExtractCallback = extractCallback;
- folderOutStream->TestMode = (testModeSpec != 0);
- folderOutStream->CheckCrc = (_crcSize != 0);
-
- for (UInt32 i = 0;; lps->OutSize += curUnpacked, lps->InSize += curPacked)
- {
- RINOK(lps->SetCur());
-
- if (i >= numItems)
- break;
-
- curUnpacked = 0;
- curPacked = 0;
-
- UInt32 fileIndex = allFilesMode ? i : indices[i];
- CNum folderIndex = _db.FileIndexToFolderIndexMap[fileIndex];
-
- UInt32 numSolidFiles = 1;
-
- if (folderIndex != kNumNoIndex)
- {
- curPacked = _db.GetFolderFullPackSize(folderIndex);
- UInt32 nextFile = fileIndex + 1;
- fileIndex = _db.FolderStartFileIndex[folderIndex];
- UInt32 k;
-
- for (k = i + 1; k < numItems; k++)
- {
- UInt32 fileIndex2 = allFilesMode ? k : indices[k];
- if (_db.FileIndexToFolderIndexMap[fileIndex2] != folderIndex
- || fileIndex2 < nextFile)
- break;
- nextFile = fileIndex2 + 1;
- }
-
- numSolidFiles = k - i;
-
- for (k = fileIndex; k < nextFile; k++)
- curUnpacked += _db.Files[k].Size;
- }
-
- {
- HRESULT result = folderOutStream->Init(fileIndex,
- allFilesMode ? NULL : indices + i,
- numSolidFiles);
-
- i += numSolidFiles;
-
- RINOK(result);
- }
-
- // to test solid block with zero unpacked size we disable that code
- if (folderOutStream->WasWritingFinished())
- continue;
-
- #ifndef _NO_CRYPTO
- CMyComPtr<ICryptoGetTextPassword> getTextPassword;
- if (extractCallback)
- extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
- #endif
-
- try
- {
- #ifndef _NO_CRYPTO
- bool isEncrypted = false;
- bool passwordIsDefined = false;
- UString password;
- #endif
-
-
- bool dataAfterEnd_Error = false;
-
- HRESULT result = decoder.Decode(
- EXTERNAL_CODECS_VARS
- _inStream,
- _db.ArcInfo.DataStartPosition,
- _db, folderIndex,
- &curUnpacked,
-
- outStream,
- progress,
- NULL // *inStreamMainRes
- , dataAfterEnd_Error
-
- _7Z_DECODER_CRYPRO_VARS
- #if !defined(_7ZIP_ST)
- , true, _numThreads, _memUsage
- #endif
- );
-
- if (result == S_FALSE || result == E_NOTIMPL || dataAfterEnd_Error)
- {
- bool wasFinished = folderOutStream->WasWritingFinished();
-
- int resOp = NExtract::NOperationResult::kDataError;
-
- if (result != S_FALSE)
- {
- if (result == E_NOTIMPL)
- resOp = NExtract::NOperationResult::kUnsupportedMethod;
- else if (wasFinished && dataAfterEnd_Error)
- resOp = NExtract::NOperationResult::kDataAfterEnd;
- }
-
- RINOK(folderOutStream->FlushCorrupted(resOp));
-
- if (wasFinished)
- {
- // we don't show error, if it's after required files
- if (/* !folderOutStream->ExtraWriteWasCut && */ callbackMessage)
- {
- RINOK(callbackMessage->ReportExtractResult(NEventIndexType::kBlockIndex, folderIndex, resOp));
- }
- }
- continue;
- }
-
- if (result != S_OK)
- return result;
-
- RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError));
- continue;
- }
- catch(...)
- {
- RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError));
- // continue;
- return E_FAIL;
- }
- }
-
- return S_OK;
-
- COM_TRY_END
-}
-
-}}
+// 7zExtract.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/7zCrc.h"
+
+#include "../../../Common/ComTry.h"
+
+#include "../../Common/ProgressUtils.h"
+
+#include "7zDecode.h"
+#include "7zHandler.h"
+
+// EXTERN_g_ExternalCodecs
+
+namespace NArchive {
+namespace N7z {
+
+Z7_CLASS_IMP_COM_1(
+ CFolderOutStream
+ , ISequentialOutStream
+ /* , ICompressGetSubStreamSize */
+)
+ CMyComPtr<ISequentialOutStream> _stream;
+public:
+ bool TestMode;
+ bool CheckCrc;
+private:
+ bool _fileIsOpen;
+ bool _calcCrc;
+ UInt32 _crc;
+ UInt64 _rem;
+
+ const UInt32 *_indexes;
+ // unsigned _startIndex;
+ unsigned _numFiles;
+ unsigned _fileIndex;
+
+ HRESULT OpenFile(bool isCorrupted = false);
+ HRESULT CloseFile_and_SetResult(Int32 res);
+ HRESULT CloseFile();
+ HRESULT ProcessEmptyFiles();
+
+public:
+ const CDbEx *_db;
+ CMyComPtr<IArchiveExtractCallback> ExtractCallback;
+
+ bool ExtraWriteWasCut;
+
+ CFolderOutStream():
+ TestMode(false),
+ CheckCrc(true)
+ {}
+
+ HRESULT Init(unsigned startIndex, const UInt32 *indexes, unsigned numFiles);
+ HRESULT FlushCorrupted(Int32 callbackOperationResult);
+
+ bool WasWritingFinished() const { return _numFiles == 0; }
+};
+
+
+HRESULT CFolderOutStream::Init(unsigned startIndex, const UInt32 *indexes, unsigned numFiles)
+{
+ // _startIndex = startIndex;
+ _fileIndex = startIndex;
+ _indexes = indexes;
+ _numFiles = numFiles;
+
+ _fileIsOpen = false;
+ ExtraWriteWasCut = false;
+
+ return ProcessEmptyFiles();
+}
+
+HRESULT CFolderOutStream::OpenFile(bool isCorrupted)
+{
+ const CFileItem &fi = _db->Files[_fileIndex];
+ const UInt32 nextFileIndex = (_indexes ? *_indexes : _fileIndex);
+ Int32 askMode = (_fileIndex == nextFileIndex) ? TestMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract :
+ NExtract::NAskMode::kSkip;
+
+ if (isCorrupted
+ && askMode == NExtract::NAskMode::kExtract
+ && !_db->IsItemAnti(_fileIndex)
+ && !fi.IsDir)
+ askMode = NExtract::NAskMode::kTest;
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ RINOK(ExtractCallback->GetStream(_fileIndex, &realOutStream, askMode))
+
+ _stream = realOutStream;
+ _crc = CRC_INIT_VAL;
+ _calcCrc = (CheckCrc && fi.CrcDefined && !fi.IsDir);
+
+ _fileIsOpen = true;
+ _rem = fi.Size;
+
+ if (askMode == NExtract::NAskMode::kExtract
+ && !realOutStream
+ && !_db->IsItemAnti(_fileIndex)
+ && !fi.IsDir)
+ askMode = NExtract::NAskMode::kSkip;
+ return ExtractCallback->PrepareOperation(askMode);
+}
+
+HRESULT CFolderOutStream::CloseFile_and_SetResult(Int32 res)
+{
+ _stream.Release();
+ _fileIsOpen = false;
+
+ if (!_indexes)
+ _numFiles--;
+ else if (*_indexes == _fileIndex)
+ {
+ _indexes++;
+ _numFiles--;
+ }
+
+ _fileIndex++;
+ return ExtractCallback->SetOperationResult(res);
+}
+
+HRESULT CFolderOutStream::CloseFile()
+{
+ const CFileItem &fi = _db->Files[_fileIndex];
+ return CloseFile_and_SetResult((!_calcCrc || fi.Crc == CRC_GET_DIGEST(_crc)) ?
+ NExtract::NOperationResult::kOK :
+ NExtract::NOperationResult::kCRCError);
+}
+
+HRESULT CFolderOutStream::ProcessEmptyFiles()
+{
+ while (_numFiles != 0 && _db->Files[_fileIndex].Size == 0)
+ {
+ RINOK(OpenFile())
+ RINOK(CloseFile())
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+
+ while (size != 0)
+ {
+ if (_fileIsOpen)
+ {
+ UInt32 cur = (size < _rem ? size : (UInt32)_rem);
+ if (_calcCrc)
+ {
+ const UInt32 k_Step = (UInt32)1 << 20;
+ if (cur > k_Step)
+ cur = k_Step;
+ }
+ HRESULT result = S_OK;
+ if (_stream)
+ result = _stream->Write(data, cur, &cur);
+ if (_calcCrc)
+ _crc = CrcUpdate(_crc, data, cur);
+ if (processedSize)
+ *processedSize += cur;
+ data = (const Byte *)data + cur;
+ size -= cur;
+ _rem -= cur;
+ if (_rem == 0)
+ {
+ RINOK(CloseFile())
+ RINOK(ProcessEmptyFiles())
+ }
+ RINOK(result)
+ if (cur == 0)
+ break;
+ continue;
+ }
+
+ RINOK(ProcessEmptyFiles())
+ if (_numFiles == 0)
+ {
+ // we support partial extracting
+ /*
+ if (processedSize)
+ *processedSize += size;
+ break;
+ */
+ ExtraWriteWasCut = true;
+ // return S_FALSE;
+ return k_My_HRESULT_WritingWasCut;
+ }
+ RINOK(OpenFile())
+ }
+
+ return S_OK;
+}
+
+HRESULT CFolderOutStream::FlushCorrupted(Int32 callbackOperationResult)
+{
+ while (_numFiles != 0)
+ {
+ if (_fileIsOpen)
+ {
+ RINOK(CloseFile_and_SetResult(callbackOperationResult))
+ }
+ else
+ {
+ RINOK(OpenFile(true))
+ }
+ }
+ return S_OK;
+}
+
+/*
+Z7_COM7F_IMF(CFolderOutStream::GetSubStreamSize(UInt64 subStream, UInt64 *value))
+{
+ *value = 0;
+ // const unsigned numFiles_Original = _numFiles + _fileIndex - _startIndex;
+ const unsigned numFiles_Original = _numFiles;
+ if (subStream >= numFiles_Original)
+ return S_FALSE; // E_FAIL;
+ *value = _db->Files[_startIndex + (unsigned)subStream].Size;
+ return S_OK;
+}
+*/
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testModeSpec, IArchiveExtractCallback *extractCallbackSpec))
+{
+ // for GCC
+ // CFolderOutStream *folderOutStream = new CFolderOutStream;
+ // CMyComPtr<ISequentialOutStream> outStream(folderOutStream);
+
+ COM_TRY_BEGIN
+
+ CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
+
+ UInt64 importantTotalUnpacked = 0;
+
+ // numItems = (UInt32)(Int32)-1;
+
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _db.Files.Size();
+
+ if (numItems == 0)
+ return S_OK;
+
+ {
+ CNum prevFolder = kNumNoIndex;
+ UInt32 nextFile = 0;
+
+ UInt32 i;
+
+ for (i = 0; i < numItems; i++)
+ {
+ const UInt32 fileIndex = allFilesMode ? i : indices[i];
+ const CNum folderIndex = _db.FileIndexToFolderIndexMap[fileIndex];
+ if (folderIndex == kNumNoIndex)
+ continue;
+ if (folderIndex != prevFolder || fileIndex < nextFile)
+ nextFile = _db.FolderStartFileIndex[folderIndex];
+ for (CNum index = nextFile; index <= fileIndex; index++)
+ importantTotalUnpacked += _db.Files[index].Size;
+ nextFile = fileIndex + 1;
+ prevFolder = folderIndex;
+ }
+ }
+
+ RINOK(extractCallback->SetTotal(importantTotalUnpacked))
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CDecoder decoder(
+ #if !defined(USE_MIXER_MT)
+ false
+ #elif !defined(USE_MIXER_ST)
+ true
+ #elif !defined(Z7_7Z_SET_PROPERTIES)
+ #ifdef Z7_ST
+ false
+ #else
+ true
+ #endif
+ #else
+ _useMultiThreadMixer
+ #endif
+ );
+
+ UInt64 curPacked, curUnpacked;
+
+ CMyComPtr<IArchiveExtractCallbackMessage2> callbackMessage;
+ extractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage2, &callbackMessage);
+
+ CFolderOutStream *folderOutStream = new CFolderOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(folderOutStream);
+
+ folderOutStream->_db = &_db;
+ folderOutStream->ExtractCallback = extractCallback;
+ folderOutStream->TestMode = (testModeSpec != 0);
+ folderOutStream->CheckCrc = (_crcSize != 0);
+
+ for (UInt32 i = 0;; lps->OutSize += curUnpacked, lps->InSize += curPacked)
+ {
+ RINOK(lps->SetCur())
+
+ if (i >= numItems)
+ break;
+
+ curUnpacked = 0;
+ curPacked = 0;
+
+ UInt32 fileIndex = allFilesMode ? i : indices[i];
+ const CNum folderIndex = _db.FileIndexToFolderIndexMap[fileIndex];
+
+ UInt32 numSolidFiles = 1;
+
+ if (folderIndex != kNumNoIndex)
+ {
+ curPacked = _db.GetFolderFullPackSize(folderIndex);
+ UInt32 nextFile = fileIndex + 1;
+ fileIndex = _db.FolderStartFileIndex[folderIndex];
+ UInt32 k;
+
+ for (k = i + 1; k < numItems; k++)
+ {
+ const UInt32 fileIndex2 = allFilesMode ? k : indices[k];
+ if (_db.FileIndexToFolderIndexMap[fileIndex2] != folderIndex
+ || fileIndex2 < nextFile)
+ break;
+ nextFile = fileIndex2 + 1;
+ }
+
+ numSolidFiles = k - i;
+
+ for (k = fileIndex; k < nextFile; k++)
+ curUnpacked += _db.Files[k].Size;
+ }
+
+ {
+ const HRESULT result = folderOutStream->Init(fileIndex,
+ allFilesMode ? NULL : indices + i,
+ numSolidFiles);
+
+ i += numSolidFiles;
+
+ RINOK(result)
+ }
+
+ if (folderOutStream->WasWritingFinished())
+ {
+ // for debug: to test zero size stream unpacking
+ // if (folderIndex == kNumNoIndex) // enable this check for debug
+ continue;
+ }
+
+ if (folderIndex == kNumNoIndex)
+ return E_FAIL;
+
+ #ifndef Z7_NO_CRYPTO
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ if (extractCallback)
+ extractCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
+ #endif
+
+ try
+ {
+ #ifndef Z7_NO_CRYPTO
+ bool isEncrypted = false;
+ bool passwordIsDefined = false;
+ UString_Wipe password;
+ #endif
+
+ bool dataAfterEnd_Error = false;
+
+ const HRESULT result = decoder.Decode(
+ EXTERNAL_CODECS_VARS
+ _inStream,
+ _db.ArcInfo.DataStartPosition,
+ _db, folderIndex,
+ &curUnpacked,
+
+ outStream,
+ progress,
+ NULL // *inStreamMainRes
+ , dataAfterEnd_Error
+
+ Z7_7Z_DECODER_CRYPRO_VARS
+ #if !defined(Z7_ST)
+ , true, _numThreads, _memUsage_Decompress
+ #endif
+ );
+
+ if (result == S_FALSE || result == E_NOTIMPL || dataAfterEnd_Error)
+ {
+ const bool wasFinished = folderOutStream->WasWritingFinished();
+
+ int resOp = NExtract::NOperationResult::kDataError;
+
+ if (result != S_FALSE)
+ {
+ if (result == E_NOTIMPL)
+ resOp = NExtract::NOperationResult::kUnsupportedMethod;
+ else if (wasFinished && dataAfterEnd_Error)
+ resOp = NExtract::NOperationResult::kDataAfterEnd;
+ }
+
+ RINOK(folderOutStream->FlushCorrupted(resOp))
+
+ if (wasFinished)
+ {
+ // we don't show error, if it's after required files
+ if (/* !folderOutStream->ExtraWriteWasCut && */ callbackMessage)
+ {
+ RINOK(callbackMessage->ReportExtractResult(NEventIndexType::kBlockIndex, folderIndex, resOp))
+ }
+ }
+ continue;
+ }
+
+ if (result != S_OK)
+ return result;
+
+ RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError))
+ continue;
+ }
+ catch(...)
+ {
+ RINOK(folderOutStream->FlushCorrupted(NExtract::NOperationResult::kDataError))
+ // continue;
+ // return E_FAIL;
+ throw;
+ }
+ }
+
+ return S_OK;
+
+ COM_TRY_END
+}
+
+}}
diff --git a/CPP/7zip/Archive/7z/7zFolderInStream.cpp b/CPP/7zip/Archive/7z/7zFolderInStream.cpp
index eee11a0..0823189 100644
--- a/CPP/7zip/Archive/7z/7zFolderInStream.cpp
+++ b/CPP/7zip/Archive/7z/7zFolderInStream.cpp
@@ -1,139 +1,264 @@
-// 7zFolderInStream.cpp
-
-#include "StdAfx.h"
-
-#include "7zFolderInStream.h"
-
-namespace NArchive {
-namespace N7z {
-
-void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback,
- const UInt32 *indexes, unsigned numFiles)
-{
- _updateCallback = updateCallback;
- _indexes = indexes;
- _numFiles = numFiles;
- _index = 0;
-
- Processed.ClearAndReserve(numFiles);
- CRCs.ClearAndReserve(numFiles);
- Sizes.ClearAndReserve(numFiles);
-
- _pos = 0;
- _crc = CRC_INIT_VAL;
- _size_Defined = false;
- _size = 0;
-
- _stream.Release();
-}
-
-HRESULT CFolderInStream::OpenStream()
-{
- _pos = 0;
- _crc = CRC_INIT_VAL;
- _size_Defined = false;
- _size = 0;
-
- while (_index < _numFiles)
- {
- CMyComPtr<ISequentialInStream> stream;
- HRESULT result = _updateCallback->GetStream(_indexes[_index], &stream);
- if (result != S_OK)
- {
- if (result != S_FALSE)
- return result;
- }
-
- _stream = stream;
-
- if (stream)
- {
- CMyComPtr<IStreamGetSize> streamGetSize;
- stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
- if (streamGetSize)
- {
- if (streamGetSize->GetSize(&_size) == S_OK)
- _size_Defined = true;
- }
- return S_OK;
- }
-
- _index++;
- RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
- AddFileInfo(result == S_OK);
- }
- return S_OK;
-}
-
-void CFolderInStream::AddFileInfo(bool isProcessed)
-{
- Processed.Add(isProcessed);
- Sizes.Add(_pos);
- CRCs.Add(CRC_GET_DIGEST(_crc));
-}
-
-STDMETHODIMP CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
- while (size != 0)
- {
- if (_stream)
- {
- UInt32 cur = size;
- const UInt32 kMax = (UInt32)1 << 20;
- if (cur > kMax)
- cur = kMax;
- RINOK(_stream->Read(data, cur, &cur));
- if (cur != 0)
- {
- _crc = CrcUpdate(_crc, data, cur);
- _pos += cur;
- if (processedSize)
- *processedSize = cur;
- return S_OK;
- }
-
- _stream.Release();
- _index++;
- AddFileInfo(true);
-
- _pos = 0;
- _crc = CRC_INIT_VAL;
- _size_Defined = false;
- _size = 0;
-
- RINOK(_updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
- }
-
- if (_index >= _numFiles)
- break;
- RINOK(OpenStream());
- }
- return S_OK;
-}
-
-STDMETHODIMP CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value)
-{
- *value = 0;
- if (subStream > Sizes.Size())
- return S_FALSE; // E_FAIL;
-
- unsigned index = (unsigned)subStream;
- if (index < Sizes.Size())
- {
- *value = Sizes[index];
- return S_OK;
- }
-
- if (!_size_Defined)
- {
- *value = _pos;
- return S_FALSE;
- }
-
- *value = (_pos > _size ? _pos : _size);
- return S_OK;
-}
-
-}}
+// 7zFolderInStream.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Windows/TimeUtils.h"
+
+#include "7zFolderInStream.h"
+
+namespace NArchive {
+namespace N7z {
+
+void CFolderInStream::Init(IArchiveUpdateCallback *updateCallback,
+ const UInt32 *indexes, unsigned numFiles)
+{
+ _updateCallback = updateCallback;
+ _indexes = indexes;
+ _numFiles = numFiles;
+
+ _totalSize_for_Coder = 0;
+ ClearFileInfo();
+
+ Processed.ClearAndReserve(numFiles);
+ Sizes.ClearAndReserve(numFiles);
+ CRCs.ClearAndReserve(numFiles);
+ TimesDefined.ClearAndReserve(numFiles);
+ MTimes.ClearAndReserve(Need_MTime ? numFiles : (unsigned)0);
+ CTimes.ClearAndReserve(Need_CTime ? numFiles : (unsigned)0);
+ ATimes.ClearAndReserve(Need_ATime ? numFiles : (unsigned)0);
+ Attribs.ClearAndReserve(Need_Attrib ? numFiles : (unsigned)0);
+
+ // FolderCrc = CRC_INIT_VAL;
+ _stream.Release();
+}
+
+void CFolderInStream::ClearFileInfo()
+{
+ _pos = 0;
+ _crc = CRC_INIT_VAL;
+ _size_Defined = false;
+ _times_Defined = false;
+ _size = 0;
+ FILETIME_Clear(_mTime);
+ FILETIME_Clear(_cTime);
+ FILETIME_Clear(_aTime);
+ _attrib = 0;
+}
+
+HRESULT CFolderInStream::OpenStream()
+{
+ while (Processed.Size() < _numFiles)
+ {
+ CMyComPtr<ISequentialInStream> stream;
+ const HRESULT result = _updateCallback->GetStream(_indexes[Processed.Size()], &stream);
+ if (result != S_OK && result != S_FALSE)
+ return result;
+
+ _stream = stream;
+
+ if (stream)
+ {
+ {
+ CMyComPtr<IStreamGetProps> getProps;
+ stream.QueryInterface(IID_IStreamGetProps, (void **)&getProps);
+ if (getProps)
+ {
+ // access could be changed in first myx pass
+ if (getProps->GetProps(&_size,
+ Need_CTime ? &_cTime : NULL,
+ Need_ATime ? &_aTime : NULL,
+ Need_MTime ? &_mTime : NULL,
+ Need_Attrib ? &_attrib : NULL)
+ == S_OK)
+ {
+ _size_Defined = true;
+ _times_Defined = true;
+ }
+ return S_OK;
+ }
+ }
+ {
+ CMyComPtr<IStreamGetSize> streamGetSize;
+ stream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
+ if (streamGetSize)
+ {
+ if (streamGetSize->GetSize(&_size) == S_OK)
+ _size_Defined = true;
+ }
+ return S_OK;
+ }
+ }
+
+ RINOK(AddFileInfo(result == S_OK))
+ }
+ return S_OK;
+}
+
+static void AddFt(CRecordVector<UInt64> &vec, const FILETIME &ft)
+{
+ vec.AddInReserved(FILETIME_To_UInt64(ft));
+}
+
+/*
+HRESULT ReportItemProps(IArchiveUpdateCallbackArcProp *reportArcProp,
+ UInt32 index, UInt64 size, const UInt32 *crc)
+{
+ PROPVARIANT prop;
+ prop.vt = VT_EMPTY;
+ prop.wReserved1 = 0;
+
+ NWindows::NCOM::PropVarEm_Set_UInt64(&prop, size);
+ RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidSize, &prop));
+ if (crc)
+ {
+ NWindows::NCOM::PropVarEm_Set_UInt32(&prop, *crc);
+ RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidCRC, &prop));
+ }
+ return reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, index, NUpdate::NOperationResult::kOK);
+}
+*/
+
+HRESULT CFolderInStream::AddFileInfo(bool isProcessed)
+{
+ // const UInt32 index = _indexes[Processed.Size()];
+ Processed.AddInReserved(isProcessed);
+ Sizes.AddInReserved(_pos);
+ CRCs.AddInReserved(CRC_GET_DIGEST(_crc));
+ if (Need_Attrib) Attribs.AddInReserved(_attrib);
+ TimesDefined.AddInReserved(_times_Defined);
+ if (Need_MTime) AddFt(MTimes, _mTime);
+ if (Need_CTime) AddFt(CTimes, _cTime);
+ if (Need_ATime) AddFt(ATimes, _aTime);
+ ClearFileInfo();
+ /*
+ if (isProcessed && _reportArcProp)
+ RINOK(ReportItemProps(_reportArcProp, index, _pos, &crc))
+ */
+ return _updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
+}
+
+Z7_COM7F_IMF(CFolderInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ while (size != 0)
+ {
+ if (_stream)
+ {
+ /*
+ if (_pos == 0)
+ {
+ const UInt32 align = (UInt32)1 << AlignLog;
+ const UInt32 offset = (UInt32)_totalSize_for_Coder & (align - 1);
+ if (offset != 0)
+ {
+ UInt32 cur = align - offset;
+ if (cur > size)
+ cur = size;
+ memset(data, 0, cur);
+ data = (Byte *)data + cur;
+ size -= cur;
+ // _pos += cur; // for debug
+ _totalSize_for_Coder += cur;
+ if (processedSize)
+ *processedSize += cur;
+ continue;
+ }
+ }
+ */
+ UInt32 cur = size;
+ const UInt32 kMax = (UInt32)1 << 20;
+ if (cur > kMax)
+ cur = kMax;
+ RINOK(_stream->Read(data, cur, &cur))
+ if (cur != 0)
+ {
+ // if (Need_Crc)
+ _crc = CrcUpdate(_crc, data, cur);
+ /*
+ if (FolderCrc)
+ FolderCrc = CrcUpdate(FolderCrc, data, cur);
+ */
+ _pos += cur;
+ _totalSize_for_Coder += cur;
+ if (processedSize)
+ *processedSize = cur; // use +=cur, if continue is possible in loop
+ return S_OK;
+ }
+
+ _stream.Release();
+ RINOK(AddFileInfo(true))
+ }
+
+ if (Processed.Size() >= _numFiles)
+ break;
+ RINOK(OpenStream())
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFolderInStream::GetSubStreamSize(UInt64 subStream, UInt64 *value))
+{
+ *value = 0;
+ if (subStream > Sizes.Size())
+ return S_FALSE; // E_FAIL;
+
+ const unsigned index = (unsigned)subStream;
+ if (index < Sizes.Size())
+ {
+ *value = Sizes[index];
+ return S_OK;
+ }
+
+ if (!_size_Defined)
+ {
+ *value = _pos;
+ return S_FALSE;
+ }
+
+ *value = (_pos > _size ? _pos : _size);
+ return S_OK;
+}
+
+
+/*
+HRESULT CFolderInStream::CloseCrcStream()
+{
+ if (!_crcStream)
+ return S_OK;
+ if (!_crcStream_Spec->WasFinished())
+ return E_FAIL;
+ _crc = _crcStream_Spec->GetCRC() ^ CRC_INIT_VAL; // change it
+ const UInt64 size = _crcStream_Spec->GetSize();
+ _pos = size;
+ _totalSize_for_Coder += size;
+ _crcStream.Release();
+ // _crcStream->ReleaseStream();
+ _stream.Release();
+ return AddFileInfo(true);
+}
+
+Z7_COM7F_IMF(CFolderInStream::GetNextInSubStream(UInt64 *streamIndexRes, ISequentialInStream **stream)
+{
+ RINOK(CloseCrcStream())
+ *stream = NULL;
+ *streamIndexRes = Processed.Size();
+ if (Processed.Size() >= _numFiles)
+ return S_OK;
+ RINOK(OpenStream());
+ if (!_stream)
+ return S_OK;
+ if (!_crcStream)
+ {
+ _crcStream_Spec = new CSequentialInStreamWithCRC;
+ _crcStream = _crcStream_Spec;
+ }
+ _crcStream_Spec->Init();
+ _crcStream_Spec->SetStream(_stream);
+ *stream = _crcStream;
+ _crcStream->AddRef();
+ return S_OK;
+}
+*/
+
+}}
diff --git a/CPP/7zip/Archive/7z/7zFolderInStream.h b/CPP/7zip/Archive/7z/7zFolderInStream.h
index f2b1c59..6447b25 100644
--- a/CPP/7zip/Archive/7z/7zFolderInStream.h
+++ b/CPP/7zip/Archive/7z/7zFolderInStream.h
@@ -1,61 +1,101 @@
-// 7zFolderInStream.h
-
-#ifndef __7Z_FOLDER_IN_STREAM_H
-#define __7Z_FOLDER_IN_STREAM_H
-
-#include "../../../../C/7zCrc.h"
-
-#include "../../../Common/MyCom.h"
-#include "../../../Common/MyVector.h"
-
-#include "../../ICoder.h"
-#include "../IArchive.h"
-
-namespace NArchive {
-namespace N7z {
-
-class CFolderInStream:
- public ISequentialInStream,
- public ICompressGetSubStreamSize,
- public CMyUnknownImp
-{
- CMyComPtr<ISequentialInStream> _stream;
- UInt64 _pos;
- UInt32 _crc;
- bool _size_Defined;
- UInt64 _size;
-
- const UInt32 *_indexes;
- unsigned _numFiles;
- unsigned _index;
-
- CMyComPtr<IArchiveUpdateCallback> _updateCallback;
-
- HRESULT OpenStream();
- void AddFileInfo(bool isProcessed);
-
-public:
- CRecordVector<bool> Processed;
- CRecordVector<UInt32> CRCs;
- CRecordVector<UInt64> Sizes;
-
- MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize)
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
-
- void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *indexes, unsigned numFiles);
-
- bool WasFinished() const { return _index == _numFiles; }
-
- UInt64 GetFullSize() const
- {
- UInt64 size = 0;
- FOR_VECTOR (i, Sizes)
- size += Sizes[i];
- return size;
- }
-};
-
-}}
-
-#endif
+// 7zFolderInStream.h
+
+#ifndef ZIP7_INC_7Z_FOLDER_IN_STREAM_H
+#define ZIP7_INC_7Z_FOLDER_IN_STREAM_H
+
+#include "../../../../C/7zCrc.h"
+
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyVector.h"
+// #include "../Common/InStreamWithCRC.h"
+
+#include "../../ICoder.h"
+#include "../IArchive.h"
+
+namespace NArchive {
+namespace N7z {
+
+Z7_CLASS_IMP_COM_2(
+ CFolderInStream
+ , ISequentialInStream
+ , ICompressGetSubStreamSize
+)
+ /*
+ Z7_COM7F_IMP(GetNextStream(UInt64 *streamIndex))
+ Z7_IFACE_COM7_IMP(ICompressInSubStreams)
+ */
+
+ CMyComPtr<ISequentialInStream> _stream;
+ UInt64 _totalSize_for_Coder;
+ UInt64 _pos;
+ UInt32 _crc;
+ bool _size_Defined;
+ bool _times_Defined;
+ UInt64 _size;
+ FILETIME _mTime;
+ FILETIME _cTime;
+ FILETIME _aTime;
+ UInt32 _attrib;
+
+ unsigned _numFiles;
+ const UInt32 *_indexes;
+
+ CMyComPtr<IArchiveUpdateCallback> _updateCallback;
+
+ void ClearFileInfo();
+ HRESULT OpenStream();
+ HRESULT AddFileInfo(bool isProcessed);
+ // HRESULT CloseCrcStream();
+public:
+ bool Need_MTime;
+ bool Need_CTime;
+ bool Need_ATime;
+ bool Need_Attrib;
+ // bool Need_Crc;
+ // bool Need_FolderCrc;
+ // unsigned AlignLog;
+
+ CRecordVector<bool> Processed;
+ CRecordVector<UInt64> Sizes;
+ CRecordVector<UInt32> CRCs;
+ CRecordVector<UInt32> Attribs;
+ CRecordVector<bool> TimesDefined;
+ CRecordVector<UInt64> MTimes;
+ CRecordVector<UInt64> CTimes;
+ CRecordVector<UInt64> ATimes;
+ // UInt32 FolderCrc;
+
+ // UInt32 GetFolderCrc() const { return CRC_GET_DIGEST(FolderCrc); }
+ // CSequentialInStreamWithCRC *_crcStream_Spec;
+ // CMyComPtr<ISequentialInStream> _crcStream;
+ // CMyComPtr<IArchiveUpdateCallbackArcProp> _reportArcProp;
+
+ void Init(IArchiveUpdateCallback *updateCallback, const UInt32 *indexes, unsigned numFiles);
+
+ bool WasFinished() const { return Processed.Size() == _numFiles; }
+
+ UInt64 Get_TotalSize_for_Coder() const { return _totalSize_for_Coder; }
+ /*
+ UInt64 GetFullSize() const
+ {
+ UInt64 size = 0;
+ FOR_VECTOR (i, Sizes)
+ size += Sizes[i];
+ return size;
+ }
+ */
+
+ CFolderInStream():
+ Need_MTime(false),
+ Need_CTime(false),
+ Need_ATime(false),
+ Need_Attrib(false)
+ // , Need_Crc(true)
+ // , Need_FolderCrc(false)
+ // , AlignLog(0)
+ {}
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/7z/7zHandler.cpp b/CPP/7zip/Archive/7z/7zHandler.cpp
index 45dda9c..23d3a9d 100644
--- a/CPP/7zip/Archive/7z/7zHandler.cpp
+++ b/CPP/7zip/Archive/7z/7zHandler.cpp
@@ -1,763 +1,793 @@
-// 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;
-using namespace NCOM;
-
-namespace NArchive {
-namespace N7z {
-
-CHandler::CHandler()
-{
- #ifndef _NO_CRYPTO
- _isEncrypted = false;
- _passwordIsDefined = false;
- #endif
-
- #ifdef EXTRACT_ONLY
-
- _crcSize = 4;
-
- #ifdef __7Z_SET_PROPERTIES
- _useMultiThreadMixer = true;
- #endif
-
- #endif
-}
-
-STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
-{
- *numItems = _db.Files.Size();
- return S_OK;
-}
-
-#ifdef _SFX
-
-IMP_IInArchive_ArcProps_NO_Table
-
-STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps)
-{
- *numProps = 0;
- return S_OK;
-}
-
-STDMETHODIMP CHandler::GetPropertyInfo(UInt32 /* index */,
- BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */)
-{
- return E_NOTIMPL;
-}
-
-#else
-
-static const Byte kArcProps[] =
-{
- kpidHeadersSize,
- kpidMethod,
- kpidSolid,
- kpidNumBlocks
- // , kpidIsTree
-};
-
-IMP_IInArchive_ArcProps
-
-static inline char GetHex(unsigned value)
-{
- return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
-}
-
-static unsigned ConvertMethodIdToString_Back(char *s, UInt64 id)
-{
- int len = 0;
- do
- {
- s[--len] = GetHex((unsigned)id & 0xF); id >>= 4;
- s[--len] = GetHex((unsigned)id & 0xF); id >>= 4;
- }
- while (id != 0);
- return (unsigned)-len;
-}
-
-static void ConvertMethodIdToString(AString &res, UInt64 id)
-{
- const unsigned kLen = 32;
- char s[kLen];
- unsigned len = kLen - 1;
- s[len] = 0;
- res += s + len - ConvertMethodIdToString_Back(s + len, id);
-}
-
-static unsigned GetStringForSizeValue(char *s, UInt32 val)
-{
- unsigned i;
- for (i = 0; i <= 31; i++)
- if (((UInt32)1 << i) == val)
- {
- if (i < 10)
- {
- s[0] = (char)('0' + i);
- s[1] = 0;
- return 1;
- }
- if (i < 20) { s[0] = '1'; s[1] = (char)('0' + i - 10); }
- else if (i < 30) { s[0] = '2'; s[1] = (char)('0' + i - 20); }
- else { s[0] = '3'; s[1] = (char)('0' + i - 30); }
- s[2] = 0;
- return 2;
- }
- char c = 'b';
- if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; }
- else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; }
- ::ConvertUInt32ToString(val, s);
- unsigned pos = MyStringLen(s);
- s[pos++] = c;
- s[pos] = 0;
- return pos;
-}
-
-/*
-static inline void AddHexToString(UString &res, Byte value)
-{
- res += GetHex((Byte)(value >> 4));
- res += GetHex((Byte)(value & 0xF));
-}
-*/
-
-static char *AddProp32(char *s, const char *name, UInt32 v)
-{
- *s++ = ':';
- s = MyStpCpy(s, name);
- ::ConvertUInt32ToString(v, s);
- return s + MyStringLen(s);
-}
-
-void CHandler::AddMethodName(AString &s, UInt64 id)
-{
- AString name;
- FindMethod(EXTERNAL_CODECS_VARS id, name);
- if (name.IsEmpty())
- ConvertMethodIdToString(s, id);
- else
- s += name;
-}
-
-#endif
-
-STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
-{
- #ifndef _SFX
- COM_TRY_BEGIN
- #endif
- NCOM::CPropVariant prop;
- switch (propID)
- {
- #ifndef _SFX
- case kpidMethod:
- {
- AString s;
- const CParsedMethods &pm = _db.ParsedMethods;
- FOR_VECTOR (i, pm.IDs)
- {
- UInt64 id = pm.IDs[i];
- s.Add_Space_if_NotEmpty();
- char temp[16];
- if (id == k_LZMA2)
- {
- s += "LZMA2:";
- if ((pm.Lzma2Prop & 1) == 0)
- ConvertUInt32ToString((pm.Lzma2Prop >> 1) + 12, temp);
- else
- GetStringForSizeValue(temp, 3 << ((pm.Lzma2Prop >> 1) + 11));
- s += temp;
- }
- else if (id == k_LZMA)
- {
- s += "LZMA:";
- GetStringForSizeValue(temp, pm.LzmaDic);
- s += temp;
- }
- else
- AddMethodName(s, id);
- }
- prop = s;
- break;
- }
- case kpidSolid: prop = _db.IsSolid(); break;
- case kpidNumBlocks: prop = (UInt32)_db.NumFolders; break;
- case kpidHeadersSize: prop = _db.HeadersSize; break;
- case kpidPhySize: prop = _db.PhySize; break;
- case kpidOffset: if (_db.ArcInfo.StartPosition != 0) prop = _db.ArcInfo.StartPosition; break;
- /*
- case kpidIsTree: if (_db.IsTree) prop = true; break;
- case kpidIsAltStream: if (_db.ThereAreAltStreams) prop = true; break;
- case kpidIsAux: if (_db.IsTree) prop = true; break;
- */
- // case kpidError: if (_db.ThereIsHeaderError) prop = "Header error"; break;
- #endif
-
- case kpidWarningFlags:
- {
- UInt32 v = 0;
- if (_db.StartHeaderWasRecovered) v |= kpv_ErrorFlags_HeadersError;
- if (_db.UnsupportedFeatureWarning) v |= kpv_ErrorFlags_UnsupportedFeature;
- if (v != 0)
- prop = v;
- break;
- }
-
- case kpidErrorFlags:
- {
- UInt32 v = 0;
- if (!_db.IsArc) v |= kpv_ErrorFlags_IsNotArc;
- if (_db.ThereIsHeaderError) v |= kpv_ErrorFlags_HeadersError;
- if (_db.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
- // if (_db.UnsupportedVersion) v |= kpv_ErrorFlags_Unsupported;
- if (_db.UnsupportedFeatureError) v |= kpv_ErrorFlags_UnsupportedFeature;
- prop = v;
- break;
- }
-
- case kpidReadOnly:
- {
- if (!_db.CanUpdate())
- prop = true;
- break;
- }
- }
- prop.Detach(value);
- return S_OK;
- #ifndef _SFX
- COM_TRY_END
- #endif
-}
-
-static void SetFileTimeProp_From_UInt64Def(PROPVARIANT *prop, const CUInt64DefVector &v, int index)
-{
- UInt64 value;
- if (v.GetItem(index, value))
- PropVarEm_Set_FileTime64(prop, value);
-}
-
-bool CHandler::IsFolderEncrypted(CNum folderIndex) const
-{
- if (folderIndex == kNumNoIndex)
- return false;
- size_t startPos = _db.FoCodersDataOffset[folderIndex];
- const Byte *p = _db.CodersData + startPos;
- size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos;
- CInByte2 inByte;
- inByte.Init(p, size);
-
- CNum numCoders = inByte.ReadNum();
- for (; numCoders != 0; numCoders--)
- {
- Byte mainByte = inByte.ReadByte();
- unsigned idSize = (mainByte & 0xF);
- const Byte *longID = inByte.GetPtr();
- UInt64 id64 = 0;
- for (unsigned j = 0; j < idSize; j++)
- id64 = ((id64 << 8) | longID[j]);
- inByte.SkipDataNoCheck(idSize);
- if (id64 == k_AES)
- return true;
- if ((mainByte & 0x20) != 0)
- inByte.SkipDataNoCheck(inByte.ReadNum());
- }
- return false;
-}
-
-STDMETHODIMP CHandler::GetNumRawProps(UInt32 *numProps)
-{
- *numProps = 0;
- return S_OK;
-}
-
-STDMETHODIMP CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)
-{
- *name = NULL;
- *propID = kpidNtSecure;
- return S_OK;
-}
-
-STDMETHODIMP CHandler::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType)
-{
- /*
- const CFileItem &file = _db.Files[index];
- *parentType = (file.IsAltStream ? NParentType::kAltStream : NParentType::kDir);
- *parent = (UInt32)(Int32)file.Parent;
- */
- *parentType = NParentType::kDir;
- *parent = (UInt32)(Int32)-1;
- return S_OK;
-}
-
-STDMETHODIMP CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)
-{
- *data = NULL;
- *dataSize = 0;
- *propType = 0;
-
- if (/* _db.IsTree && propID == kpidName ||
- !_db.IsTree && */ propID == kpidPath)
- {
- if (_db.NameOffsets && _db.NamesBuf)
- {
- size_t offset = _db.NameOffsets[index];
- size_t size = (_db.NameOffsets[index + 1] - offset) * 2;
- if (size < ((UInt32)1 << 31))
- {
- *data = (const void *)(_db.NamesBuf + offset * 2);
- *dataSize = (UInt32)size;
- *propType = NPropDataType::kUtf16z;
- }
- }
- return S_OK;
- }
- /*
- if (propID == kpidNtSecure)
- {
- if (index < (UInt32)_db.SecureIDs.Size())
- {
- int id = _db.SecureIDs[index];
- size_t offs = _db.SecureOffsets[id];
- size_t size = _db.SecureOffsets[id + 1] - offs;
- if (size >= 0)
- {
- *data = _db.SecureBuf + offs;
- *dataSize = (UInt32)size;
- *propType = NPropDataType::kRaw;
- }
- }
- }
- */
- return S_OK;
-}
-
-#ifndef _SFX
-
-HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const
-{
- PropVariant_Clear(prop);
- if (folderIndex == kNumNoIndex)
- return S_OK;
- // for (int ttt = 0; ttt < 1; ttt++) {
- const unsigned kTempSize = 256;
- char temp[kTempSize];
- unsigned pos = kTempSize;
- temp[--pos] = 0;
-
- size_t startPos = _db.FoCodersDataOffset[folderIndex];
- const Byte *p = _db.CodersData + startPos;
- size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos;
- CInByte2 inByte;
- inByte.Init(p, size);
-
- // numCoders == 0 ???
- CNum numCoders = inByte.ReadNum();
- bool needSpace = false;
-
- for (; numCoders != 0; numCoders--, needSpace = true)
- {
- if (pos < 32) // max size of property
- break;
- Byte mainByte = inByte.ReadByte();
- unsigned idSize = (mainByte & 0xF);
- const Byte *longID = inByte.GetPtr();
- UInt64 id64 = 0;
- for (unsigned j = 0; j < idSize; j++)
- id64 = ((id64 << 8) | longID[j]);
- inByte.SkipDataNoCheck(idSize);
-
- if ((mainByte & 0x10) != 0)
- {
- inByte.ReadNum(); // NumInStreams
- inByte.ReadNum(); // NumOutStreams
- }
-
- CNum propsSize = 0;
- const Byte *props = NULL;
- if ((mainByte & 0x20) != 0)
- {
- propsSize = inByte.ReadNum();
- props = inByte.GetPtr();
- inByte.SkipDataNoCheck(propsSize);
- }
-
- const char *name = NULL;
- char s[32];
- s[0] = 0;
-
- if (id64 <= (UInt32)0xFFFFFFFF)
- {
- UInt32 id = (UInt32)id64;
- if (id == k_LZMA)
- {
- name = "LZMA";
- if (propsSize == 5)
- {
- UInt32 dicSize = GetUi32((const Byte *)props + 1);
- char *dest = s + GetStringForSizeValue(s, dicSize);
- UInt32 d = props[0];
- if (d != 0x5D)
- {
- UInt32 lc = d % 9;
- d /= 9;
- UInt32 pb = d / 5;
- UInt32 lp = d % 5;
- if (lc != 3) dest = AddProp32(dest, "lc", lc);
- if (lp != 0) dest = AddProp32(dest, "lp", lp);
- if (pb != 2) dest = AddProp32(dest, "pb", pb);
- }
- }
- }
- else if (id == k_LZMA2)
- {
- name = "LZMA2";
- if (propsSize == 1)
- {
- Byte d = props[0];
- if ((d & 1) == 0)
- ConvertUInt32ToString((UInt32)((d >> 1) + 12), s);
- else
- GetStringForSizeValue(s, 3 << ((d >> 1) + 11));
- }
- }
- else if (id == k_PPMD)
- {
- name = "PPMD";
- if (propsSize == 5)
- {
- Byte order = *props;
- char *dest = s;
- *dest++ = 'o';
- ConvertUInt32ToString(order, dest);
- dest += MyStringLen(dest);
- dest = MyStpCpy(dest, ":mem");
- GetStringForSizeValue(dest, GetUi32(props + 1));
- }
- }
- else if (id == k_Delta)
- {
- name = "Delta";
- if (propsSize == 1)
- ConvertUInt32ToString((UInt32)props[0] + 1, s);
- }
- else if (id == k_BCJ2) name = "BCJ2";
- else if (id == k_BCJ) name = "BCJ";
- else if (id == k_AES)
- {
- name = "7zAES";
- if (propsSize >= 1)
- {
- Byte firstByte = props[0];
- UInt32 numCyclesPower = firstByte & 0x3F;
- ConvertUInt32ToString(numCyclesPower, s);
- }
- }
- }
-
- if (name)
- {
- unsigned nameLen = MyStringLen(name);
- unsigned propsLen = MyStringLen(s);
- unsigned totalLen = nameLen + propsLen;
- if (propsLen != 0)
- totalLen++;
- if (needSpace)
- totalLen++;
- if (totalLen + 5 >= pos)
- break;
- pos -= totalLen;
- MyStringCopy(temp + pos, name);
- if (propsLen != 0)
- {
- char *dest = temp + pos + nameLen;
- *dest++ = ':';
- MyStringCopy(dest, s);
- }
- if (needSpace)
- temp[pos + totalLen - 1] = ' ';
- }
- else
- {
- AString methodName;
- FindMethod(EXTERNAL_CODECS_VARS id64, methodName);
- if (needSpace)
- temp[--pos] = ' ';
- if (methodName.IsEmpty())
- pos -= ConvertMethodIdToString_Back(temp + pos, id64);
- else
- {
- unsigned len = methodName.Len();
- if (len + 5 > pos)
- break;
- pos -= len;
- for (unsigned i = 0; i < len; i++)
- temp[pos + i] = methodName[i];
- }
- }
- }
-
- if (numCoders != 0 && pos >= 4)
- {
- temp[--pos] = ' ';
- temp[--pos] = '.';
- temp[--pos] = '.';
- temp[--pos] = '.';
- }
-
- return PropVarEm_Set_Str(prop, temp + pos);
- // }
-}
-
-#endif
-
-STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
-{
- PropVariant_Clear(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];
- const UInt32 index2 = index;
-
- switch (propID)
- {
- case kpidIsDir: PropVarEm_Set_Bool(value, item.IsDir); break;
- case kpidSize:
- {
- PropVarEm_Set_UInt64(value, 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)
- PropVarEm_Set_UInt64(value, _db.GetFolderFullPackSize(folderIndex));
- /*
- else
- PropVarEm_Set_UInt64(value, 0);
- */
- }
- else
- PropVarEm_Set_UInt64(value, 0);
- }
- break;
- }
- // case kpidIsAux: prop = _db.IsItemAux(index2); break;
- case kpidPosition: { UInt64 v; if (_db.StartPos.GetItem(index2, v)) PropVarEm_Set_UInt64(value, v); break; }
- case kpidCTime: SetFileTimeProp_From_UInt64Def(value, _db.CTime, index2); break;
- case kpidATime: SetFileTimeProp_From_UInt64Def(value, _db.ATime, index2); break;
- case kpidMTime: SetFileTimeProp_From_UInt64Def(value, _db.MTime, index2); break;
- case kpidAttrib: if (_db.Attrib.ValidAndDefined(index2)) PropVarEm_Set_UInt32(value, _db.Attrib.Vals[index2]); break;
- case kpidCRC: if (item.CrcDefined) PropVarEm_Set_UInt32(value, item.Crc); break;
- case kpidEncrypted: PropVarEm_Set_Bool(value, IsFolderEncrypted(_db.FileIndexToFolderIndexMap[index2])); break;
- case kpidIsAnti: PropVarEm_Set_Bool(value, _db.IsItemAnti(index2)); break;
- /*
- case kpidIsAltStream: prop = item.IsAltStream; break;
- case kpidNtSecure:
- {
- int id = _db.SecureIDs[index];
- size_t offs = _db.SecureOffsets[id];
- size_t size = _db.SecureOffsets[id + 1] - offs;
- if (size >= 0)
- {
- prop.SetBlob(_db.SecureBuf + offs, (ULONG)size);
- }
- break;
- }
- */
-
- case kpidPath: return _db.GetPath_Prop(index, value);
-
- #ifndef _SFX
-
- case kpidMethod: return SetMethodToProp(_db.FileIndexToFolderIndexMap[index2], value);
- case kpidBlock:
- {
- CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
- if (folderIndex != kNumNoIndex)
- PropVarEm_Set_UInt32(value, (UInt32)folderIndex);
- }
- break;
- /*
- case kpidPackedSize0:
- case kpidPackedSize1:
- case kpidPackedSize2:
- case kpidPackedSize3:
- case kpidPackedSize4:
- {
- CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
- if (folderIndex != kNumNoIndex)
- {
- if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2 &&
- _db.FoStartPackStreamIndex[folderIndex + 1] -
- _db.FoStartPackStreamIndex[folderIndex] > (propID - kpidPackedSize0))
- {
- PropVarEm_Set_UInt64(value, _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0));
- }
- }
- else
- PropVarEm_Set_UInt64(value, 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(
- #ifdef __7Z_SET_PROPERTIES
- _useMultiThreadMixer
- #else
- true
- #endif
- );
- _db.IsArc = false;
- RINOK(archive.Open(stream, maxCheckStartPosition));
- _db.IsArc = true;
-
- HRESULT result = archive.ReadDatabase(
- EXTERNAL_CODECS_VARS
- _db
- #ifndef _NO_CRYPTO
- , getTextPassword, _isEncrypted, _passwordIsDefined, _password
- #endif
- );
- RINOK(result);
-
- _inStream = stream;
- }
- catch(...)
- {
- Close();
- // return E_INVALIDARG;
- // return S_FALSE;
- // we must return out_of_memory here
- return E_OUTOFMEMORY;
- }
- // _inStream = stream;
- #ifndef _SFX
- FillPopIDs();
- #endif
- return S_OK;
- COM_TRY_END
-}
-
-STDMETHODIMP CHandler::Close()
-{
- COM_TRY_BEGIN
- _inStream.Release();
- _db.Clear();
- #ifndef _NO_CRYPTO
- _isEncrypted = false;
- _passwordIsDefined = false;
- _password.Empty();
- #endif
- return S_OK;
- COM_TRY_END
-}
-
-#ifdef __7Z_SET_PROPERTIES
-#ifdef EXTRACT_ONLY
-
-STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
-{
- COM_TRY_BEGIN
-
- InitCommon();
- _useMultiThreadMixer = true;
-
- for (UInt32 i = 0; i < numProps; i++)
- {
- UString name = names[i];
- name.MakeLower_Ascii();
- if (name.IsEmpty())
- return E_INVALIDARG;
- const PROPVARIANT &value = values[i];
- UInt32 number;
- unsigned index = ParseStringToUInt32(name, number);
- if (index == 0)
- {
- if (name.IsEqualTo("mtf"))
- {
- RINOK(PROPVARIANT_to_bool(value, _useMultiThreadMixer));
- continue;
- }
- {
- HRESULT hres;
- if (SetCommonProperty(name, value, hres))
- {
- RINOK(hres);
- continue;
- }
- }
- return E_INVALIDARG;
- }
- }
- return S_OK;
- COM_TRY_END
-}
-
-#endif
-#endif
-
-IMPL_ISetCompressCodecsInfo
-
-}}
+// 7zHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+
+#ifndef Z7_7Z_SET_PROPERTIES
+#include "../../../Windows/System.h"
+#endif
+
+#include "../Common/ItemNameUtils.h"
+
+#include "7zHandler.h"
+#include "7zProperties.h"
+
+#ifdef Z7_7Z_SET_PROPERTIES
+#ifdef Z7_EXTRACT_ONLY
+#include "../Common/ParseProperties.h"
+#endif
+#endif
+
+using namespace NWindows;
+using namespace NCOM;
+
+namespace NArchive {
+namespace N7z {
+
+CHandler::CHandler()
+{
+ #ifndef Z7_NO_CRYPTO
+ _isEncrypted = false;
+ _passwordIsDefined = false;
+ #endif
+
+ #ifdef Z7_EXTRACT_ONLY
+
+ _crcSize = 4;
+
+ #ifdef Z7_7Z_SET_PROPERTIES
+ _useMultiThreadMixer = true;
+ #endif
+
+ #endif
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _db.Files.Size();
+ return S_OK;
+}
+
+#ifdef Z7_SFX
+
+IMP_IInArchive_ArcProps_NO_Table
+
+Z7_COM7F_IMF(CHandler::GetNumberOfProperties(UInt32 *numProps))
+{
+ *numProps = 0;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetPropertyInfo(UInt32 /* index */,
+ BSTR * /* name */, PROPID * /* propID */, VARTYPE * /* varType */))
+{
+ return E_NOTIMPL;
+}
+
+#else
+
+static const Byte kArcProps[] =
+{
+ kpidHeadersSize,
+ kpidMethod,
+ kpidSolid,
+ kpidNumBlocks
+ // , kpidIsTree
+};
+
+IMP_IInArchive_ArcProps
+
+static inline char GetHex(unsigned value)
+{
+ return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+}
+
+static unsigned ConvertMethodIdToString_Back(char *s, UInt64 id)
+{
+ int len = 0;
+ do
+ {
+ s[--len] = GetHex((unsigned)id & 0xF); id >>= 4;
+ s[--len] = GetHex((unsigned)id & 0xF); id >>= 4;
+ }
+ while (id != 0);
+ return (unsigned)-len;
+}
+
+static void ConvertMethodIdToString(AString &res, UInt64 id)
+{
+ const unsigned kLen = 32;
+ char s[kLen];
+ unsigned len = kLen - 1;
+ s[len] = 0;
+ res += s + len - ConvertMethodIdToString_Back(s + len, id);
+}
+
+
+static char *GetStringForSizeValue(char *s, UInt32 val)
+{
+ for (unsigned i = 0; i < 32; i++)
+ if (((UInt32)1 << i) == val)
+ {
+ if (i >= 10)
+ {
+ *s++= (char)('0' + i / 10);
+ i %= 10;
+ }
+ *s++ = (char)('0' + i);
+ *s = 0;
+ return s;
+ }
+
+ char c = 'b';
+ if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; }
+ else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; }
+ s = ConvertUInt32ToString(val, s);
+ *s++ = c;
+ *s = 0;
+ return s;
+}
+
+
+static void GetLzma2String(char *s, unsigned d)
+{
+ if (d > 40)
+ {
+ *s = 0;
+ return;
+ // s = MyStpCpy(s, "unsup");
+ }
+ else if ((d & 1) == 0)
+ d = (d >> 1) + 12;
+ else
+ {
+ // s = GetStringForSizeValue(s, (UInt32)3 << ((d >> 1) + 11));
+ d = (d >> 1) + 1;
+ char c = 'k';
+ if (d >= 10)
+ {
+ c = 'm';
+ d -= 10;
+ }
+ s = ConvertUInt32ToString((UInt32)3 << d, s);
+ *s++ = c;
+ *s = 0;
+ return;
+ }
+ ConvertUInt32ToString(d, s);
+}
+
+
+/*
+static inline void AddHexToString(UString &res, Byte value)
+{
+ res += GetHex((Byte)(value >> 4));
+ res += GetHex((Byte)(value & 0xF));
+}
+*/
+
+static char *AddProp32(char *s, const char *name, UInt32 v)
+{
+ *s++ = ':';
+ s = MyStpCpy(s, name);
+ return ConvertUInt32ToString(v, s);
+}
+
+void CHandler::AddMethodName(AString &s, UInt64 id)
+{
+ AString name;
+ FindMethod(EXTERNAL_CODECS_VARS id, name);
+ if (name.IsEmpty())
+ ConvertMethodIdToString(s, id);
+ else
+ s += name;
+}
+
+#endif
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ #ifndef Z7_SFX
+ COM_TRY_BEGIN
+ #endif
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ #ifndef Z7_SFX
+ case kpidMethod:
+ {
+ AString s;
+ const CParsedMethods &pm = _db.ParsedMethods;
+ FOR_VECTOR (i, pm.IDs)
+ {
+ UInt64 id = pm.IDs[i];
+ s.Add_Space_if_NotEmpty();
+ char temp[16];
+ if (id == k_LZMA2)
+ {
+ s += "LZMA2:";
+ GetLzma2String(temp, pm.Lzma2Prop);
+ s += temp;
+ }
+ else if (id == k_LZMA)
+ {
+ s += "LZMA:";
+ GetStringForSizeValue(temp, pm.LzmaDic);
+ s += temp;
+ }
+ /*
+ else if (id == k_ZSTD)
+ {
+ s += "ZSTD";
+ }
+ */
+ else
+ AddMethodName(s, id);
+ }
+ prop = s;
+ break;
+ }
+ case kpidSolid: prop = _db.IsSolid(); break;
+ case kpidNumBlocks: prop = (UInt32)_db.NumFolders; break;
+ case kpidHeadersSize: prop = _db.HeadersSize; break;
+ case kpidPhySize: prop = _db.PhySize; break;
+ case kpidOffset: if (_db.ArcInfo.StartPosition != 0) prop = _db.ArcInfo.StartPosition; break;
+ /*
+ case kpidIsTree: if (_db.IsTree) prop = true; break;
+ case kpidIsAltStream: if (_db.ThereAreAltStreams) prop = true; break;
+ case kpidIsAux: if (_db.IsTree) prop = true; break;
+ */
+ // case kpidError: if (_db.ThereIsHeaderError) prop = "Header error"; break;
+ #endif
+
+ case kpidWarningFlags:
+ {
+ UInt32 v = 0;
+ if (_db.StartHeaderWasRecovered) v |= kpv_ErrorFlags_HeadersError;
+ if (_db.UnsupportedFeatureWarning) v |= kpv_ErrorFlags_UnsupportedFeature;
+ if (v != 0)
+ prop = v;
+ break;
+ }
+
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_db.IsArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (_db.ThereIsHeaderError) v |= kpv_ErrorFlags_HeadersError;
+ if (_db.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
+ // if (_db.UnsupportedVersion) v |= kpv_ErrorFlags_Unsupported;
+ if (_db.UnsupportedFeatureError) v |= kpv_ErrorFlags_UnsupportedFeature;
+ prop = v;
+ break;
+ }
+
+ case kpidReadOnly:
+ {
+ if (!_db.CanUpdate())
+ prop = true;
+ break;
+ }
+ }
+ return prop.Detach(value);
+ #ifndef Z7_SFX
+ COM_TRY_END
+ #endif
+}
+
+static void SetFileTimeProp_From_UInt64Def(PROPVARIANT *prop, const CUInt64DefVector &v, unsigned index)
+{
+ UInt64 value;
+ if (v.GetItem(index, value))
+ PropVarEm_Set_FileTime64_Prec(prop, value, k_PropVar_TimePrec_100ns);
+}
+
+bool CHandler::IsFolderEncrypted(CNum folderIndex) const
+{
+ if (folderIndex == kNumNoIndex)
+ return false;
+ const size_t startPos = _db.FoCodersDataOffset[folderIndex];
+ const Byte *p = _db.CodersData + startPos;
+ const size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos;
+ CInByte2 inByte;
+ inByte.Init(p, size);
+
+ CNum numCoders = inByte.ReadNum();
+ for (; numCoders != 0; numCoders--)
+ {
+ const Byte mainByte = inByte.ReadByte();
+ const unsigned idSize = (mainByte & 0xF);
+ const Byte *longID = inByte.GetPtr();
+ UInt64 id64 = 0;
+ for (unsigned j = 0; j < idSize; j++)
+ id64 = ((id64 << 8) | longID[j]);
+ inByte.SkipDataNoCheck(idSize);
+ if (id64 == k_AES)
+ return true;
+ if ((mainByte & 0x20) != 0)
+ inByte.SkipDataNoCheck(inByte.ReadNum());
+ }
+ return false;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps))
+{
+ *numProps = 0;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID))
+{
+ *name = NULL;
+ *propID = kpidNtSecure;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType))
+{
+ /*
+ const CFileItem &file = _db.Files[index];
+ *parentType = (file.IsAltStream ? NParentType::kAltStream : NParentType::kDir);
+ *parent = (UInt32)(Int32)file.Parent;
+ */
+ *parentType = NParentType::kDir;
+ *parent = (UInt32)(Int32)-1;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
+{
+ *data = NULL;
+ *dataSize = 0;
+ *propType = 0;
+
+ if (/* _db.IsTree && propID == kpidName ||
+ !_db.IsTree && */ propID == kpidPath)
+ {
+ if (_db.NameOffsets && _db.NamesBuf)
+ {
+ size_t offset = _db.NameOffsets[index];
+ size_t size = (_db.NameOffsets[index + 1] - offset) * 2;
+ if (size < ((UInt32)1 << 31))
+ {
+ *data = (const void *)(_db.NamesBuf + offset * 2);
+ *dataSize = (UInt32)size;
+ *propType = NPropDataType::kUtf16z;
+ }
+ }
+ return S_OK;
+ }
+ /*
+ if (propID == kpidNtSecure)
+ {
+ if (index < (UInt32)_db.SecureIDs.Size())
+ {
+ int id = _db.SecureIDs[index];
+ size_t offs = _db.SecureOffsets[id];
+ size_t size = _db.SecureOffsets[id + 1] - offs;
+ if (size >= 0)
+ {
+ *data = _db.SecureBuf + offs;
+ *dataSize = (UInt32)size;
+ *propType = NPropDataType::kRaw;
+ }
+ }
+ }
+ */
+ return S_OK;
+}
+
+#ifndef Z7_SFX
+
+HRESULT CHandler::SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const
+{
+ PropVariant_Clear(prop);
+ if (folderIndex == kNumNoIndex)
+ return S_OK;
+ // for (int ttt = 0; ttt < 1; ttt++) {
+ const unsigned kTempSize = 256;
+ char temp[kTempSize];
+ unsigned pos = kTempSize;
+ temp[--pos] = 0;
+
+ const size_t startPos = _db.FoCodersDataOffset[folderIndex];
+ const Byte *p = _db.CodersData + startPos;
+ const size_t size = _db.FoCodersDataOffset[folderIndex + 1] - startPos;
+ CInByte2 inByte;
+ inByte.Init(p, size);
+
+ // numCoders == 0 ???
+ CNum numCoders = inByte.ReadNum();
+ bool needSpace = false;
+
+ for (; numCoders != 0; numCoders--, needSpace = true)
+ {
+ if (pos < 32) // max size of property
+ break;
+ const Byte mainByte = inByte.ReadByte();
+ UInt64 id64 = 0;
+ const unsigned idSize = (mainByte & 0xF);
+ const Byte *longID = inByte.GetPtr();
+ for (unsigned j = 0; j < idSize; j++)
+ id64 = ((id64 << 8) | longID[j]);
+ inByte.SkipDataNoCheck(idSize);
+
+ if ((mainByte & 0x10) != 0)
+ {
+ inByte.ReadNum(); // NumInStreams
+ inByte.ReadNum(); // NumOutStreams
+ }
+
+ CNum propsSize = 0;
+ const Byte *props = NULL;
+ if ((mainByte & 0x20) != 0)
+ {
+ propsSize = inByte.ReadNum();
+ props = inByte.GetPtr();
+ inByte.SkipDataNoCheck(propsSize);
+ }
+
+ const char *name = NULL;
+ char s[32];
+ s[0] = 0;
+
+ if (id64 <= (UInt32)0xFFFFFFFF)
+ {
+ const UInt32 id = (UInt32)id64;
+ if (id == k_LZMA)
+ {
+ name = "LZMA";
+ if (propsSize == 5)
+ {
+ const UInt32 dicSize = GetUi32((const Byte *)props + 1);
+ char *dest = GetStringForSizeValue(s, dicSize);
+ UInt32 d = props[0];
+ if (d != 0x5D)
+ {
+ const UInt32 lc = d % 9;
+ d /= 9;
+ const UInt32 pb = d / 5;
+ const UInt32 lp = d % 5;
+ if (lc != 3) dest = AddProp32(dest, "lc", lc);
+ if (lp != 0) dest = AddProp32(dest, "lp", lp);
+ if (pb != 2) dest = AddProp32(dest, "pb", pb);
+ }
+ }
+ }
+ else if (id == k_LZMA2)
+ {
+ name = "LZMA2";
+ if (propsSize == 1)
+ GetLzma2String(s, props[0]);
+ }
+ else if (id == k_PPMD)
+ {
+ name = "PPMD";
+ if (propsSize == 5)
+ {
+ char *dest = s;
+ *dest++ = 'o';
+ dest = ConvertUInt32ToString(*props, dest);
+ dest = MyStpCpy(dest, ":mem");
+ GetStringForSizeValue(dest, GetUi32(props + 1));
+ }
+ }
+ else if (id == k_Delta)
+ {
+ name = "Delta";
+ if (propsSize == 1)
+ ConvertUInt32ToString((UInt32)props[0] + 1, s);
+ }
+ else if (id == k_ARM64)
+ {
+ name = "ARM64";
+ if (propsSize == 4)
+ ConvertUInt32ToString(GetUi32(props), s);
+ /*
+ else if (propsSize != 0)
+ MyStringCopy(s, "unsupported");
+ */
+ }
+ else if (id == k_BCJ2) name = "BCJ2";
+ else if (id == k_BCJ) name = "BCJ";
+ else if (id == k_AES)
+ {
+ name = "7zAES";
+ if (propsSize >= 1)
+ {
+ const Byte firstByte = props[0];
+ const UInt32 numCyclesPower = firstByte & 0x3F;
+ ConvertUInt32ToString(numCyclesPower, s);
+ }
+ }
+ }
+
+ if (name)
+ {
+ const unsigned nameLen = MyStringLen(name);
+ const unsigned propsLen = MyStringLen(s);
+ unsigned totalLen = nameLen + propsLen;
+ if (propsLen != 0)
+ totalLen++;
+ if (needSpace)
+ totalLen++;
+ if (totalLen + 5 >= pos)
+ break;
+ pos -= totalLen;
+ MyStringCopy(temp + pos, name);
+ if (propsLen != 0)
+ {
+ char *dest = temp + pos + nameLen;
+ *dest++ = ':';
+ MyStringCopy(dest, s);
+ }
+ if (needSpace)
+ temp[pos + totalLen - 1] = ' ';
+ }
+ else
+ {
+ AString methodName;
+ FindMethod(EXTERNAL_CODECS_VARS id64, methodName);
+ if (needSpace)
+ temp[--pos] = ' ';
+ if (methodName.IsEmpty())
+ pos -= ConvertMethodIdToString_Back(temp + pos, id64);
+ else
+ {
+ const unsigned len = methodName.Len();
+ if (len + 5 > pos)
+ break;
+ pos -= len;
+ for (unsigned i = 0; i < len; i++)
+ temp[pos + i] = methodName[i];
+ }
+ }
+ }
+
+ if (numCoders != 0 && pos >= 4)
+ {
+ temp[--pos] = ' ';
+ temp[--pos] = '.';
+ temp[--pos] = '.';
+ temp[--pos] = '.';
+ }
+
+ return PropVarEm_Set_Str(prop, temp + pos);
+ // }
+}
+
+#endif
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ RINOK(PropVariant_Clear(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];
+ const UInt32 index2 = index;
+
+ switch (propID)
+ {
+ case kpidIsDir: PropVarEm_Set_Bool(value, item.IsDir); break;
+ case kpidSize:
+ {
+ PropVarEm_Set_UInt64(value, item.Size);
+ // prop = ref2.Size;
+ break;
+ }
+ case kpidPackSize:
+ {
+ // prop = ref2.PackSize;
+ {
+ const CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
+ if (folderIndex != kNumNoIndex)
+ {
+ if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2)
+ PropVarEm_Set_UInt64(value, _db.GetFolderFullPackSize(folderIndex));
+ /*
+ else
+ PropVarEm_Set_UInt64(value, 0);
+ */
+ }
+ else
+ PropVarEm_Set_UInt64(value, 0);
+ }
+ break;
+ }
+ // case kpidIsAux: prop = _db.IsItemAux(index2); break;
+ case kpidPosition: { UInt64 v; if (_db.StartPos.GetItem(index2, v)) PropVarEm_Set_UInt64(value, v); break; }
+ case kpidCTime: SetFileTimeProp_From_UInt64Def(value, _db.CTime, index2); break;
+ case kpidATime: SetFileTimeProp_From_UInt64Def(value, _db.ATime, index2); break;
+ case kpidMTime: SetFileTimeProp_From_UInt64Def(value, _db.MTime, index2); break;
+ case kpidAttrib: if (_db.Attrib.ValidAndDefined(index2)) PropVarEm_Set_UInt32(value, _db.Attrib.Vals[index2]); break;
+ case kpidCRC: if (item.CrcDefined) PropVarEm_Set_UInt32(value, item.Crc); break;
+ case kpidEncrypted: PropVarEm_Set_Bool(value, IsFolderEncrypted(_db.FileIndexToFolderIndexMap[index2])); break;
+ case kpidIsAnti: PropVarEm_Set_Bool(value, _db.IsItemAnti(index2)); break;
+ /*
+ case kpidIsAltStream: prop = item.IsAltStream; break;
+ case kpidNtSecure:
+ {
+ int id = _db.SecureIDs[index];
+ size_t offs = _db.SecureOffsets[id];
+ size_t size = _db.SecureOffsets[id + 1] - offs;
+ if (size >= 0)
+ {
+ prop.SetBlob(_db.SecureBuf + offs, (ULONG)size);
+ }
+ break;
+ }
+ */
+
+ case kpidPath: return _db.GetPath_Prop(index, value);
+
+ #ifndef Z7_SFX
+
+ case kpidMethod: return SetMethodToProp(_db.FileIndexToFolderIndexMap[index2], value);
+ case kpidBlock:
+ {
+ const CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
+ if (folderIndex != kNumNoIndex)
+ PropVarEm_Set_UInt32(value, (UInt32)folderIndex);
+ }
+ break;
+ #ifdef Z7_7Z_SHOW_PACK_STREAMS_SIZES
+ case kpidPackedSize0:
+ case kpidPackedSize1:
+ case kpidPackedSize2:
+ case kpidPackedSize3:
+ case kpidPackedSize4:
+ {
+ const CNum folderIndex = _db.FileIndexToFolderIndexMap[index2];
+ if (folderIndex != kNumNoIndex)
+ {
+ if (_db.FolderStartFileIndex[folderIndex] == (CNum)index2 &&
+ _db.FoStartPackStreamIndex[folderIndex + 1] -
+ _db.FoStartPackStreamIndex[folderIndex] > (propID - kpidPackedSize0))
+ {
+ PropVarEm_Set_UInt64(value, _db.GetFolderPackStreamSize(folderIndex, propID - kpidPackedSize0));
+ }
+ }
+ else
+ PropVarEm_Set_UInt64(value, 0);
+ }
+ break;
+ #endif
+
+ #endif
+ }
+ // return prop.Detach(value);
+ return S_OK;
+ // COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *openArchiveCallback))
+{
+ COM_TRY_BEGIN
+ Close();
+ #ifndef Z7_SFX
+ _fileInfoPopIDs.Clear();
+ #endif
+
+ try
+ {
+ CMyComPtr<IArchiveOpenCallback> openArchiveCallbackTemp = openArchiveCallback;
+
+ #ifndef Z7_NO_CRYPTO
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ if (openArchiveCallback)
+ openArchiveCallbackTemp.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
+ #endif
+
+ CInArchive archive(
+ #ifdef Z7_7Z_SET_PROPERTIES
+ _useMultiThreadMixer
+ #else
+ true
+ #endif
+ );
+ _db.IsArc = false;
+ RINOK(archive.Open(stream, maxCheckStartPosition))
+ _db.IsArc = true;
+
+ HRESULT result = archive.ReadDatabase(
+ EXTERNAL_CODECS_VARS
+ _db
+ #ifndef Z7_NO_CRYPTO
+ , getTextPassword, _isEncrypted, _passwordIsDefined, _password
+ #endif
+ );
+ RINOK(result)
+
+ _inStream = stream;
+ }
+ catch(...)
+ {
+ Close();
+ // return E_INVALIDARG;
+ // return S_FALSE;
+ // we must return out_of_memory here
+ return E_OUTOFMEMORY;
+ }
+ // _inStream = stream;
+ #ifndef Z7_SFX
+ FillPopIDs();
+ #endif
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ COM_TRY_BEGIN
+ _inStream.Release();
+ _db.Clear();
+ #ifndef Z7_NO_CRYPTO
+ _isEncrypted = false;
+ _passwordIsDefined = false;
+ _password.Wipe_and_Empty();
+ #endif
+ return S_OK;
+ COM_TRY_END
+}
+
+#ifdef Z7_7Z_SET_PROPERTIES
+#ifdef Z7_EXTRACT_ONLY
+
+Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
+{
+ COM_TRY_BEGIN
+
+ InitCommon();
+ _useMultiThreadMixer = true;
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ UString name = names[i];
+ name.MakeLower_Ascii();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+ const PROPVARIANT &value = values[i];
+ UInt32 number;
+ const unsigned index = ParseStringToUInt32(name, number);
+ if (index == 0)
+ {
+ if (name.IsEqualTo("mtf"))
+ {
+ RINOK(PROPVARIANT_to_bool(value, _useMultiThreadMixer))
+ continue;
+ }
+ {
+ HRESULT hres;
+ if (SetCommonProperty(name, value, hres))
+ {
+ RINOK(hres)
+ continue;
+ }
+ }
+ return E_INVALIDARG;
+ }
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+#endif
+#endif
+
+IMPL_ISetCompressCodecsInfo
+
+}}
diff --git a/CPP/7zip/Archive/7z/7zHandler.h b/CPP/7zip/Archive/7z/7zHandler.h
index 7d5a5f0..b1c0466 100644
--- a/CPP/7zip/Archive/7z/7zHandler.h
+++ b/CPP/7zip/Archive/7z/7zHandler.h
@@ -1,181 +1,176 @@
-// 7z/Handler.h
-
-#ifndef __7Z_HANDLER_H
-#define __7Z_HANDLER_H
-
-#include "../../ICoder.h"
-#include "../IArchive.h"
-
-#include "../../Common/CreateCoder.h"
-
-#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
-
-// #ifdef __7Z_SET_PROPERTIES
-#include "../Common/HandlerOut.h"
-// #endif
-
-#include "7zCompressionMode.h"
-#include "7zIn.h"
-
-namespace NArchive {
-namespace N7z {
-
-
-#ifndef EXTRACT_ONLY
-
-class COutHandler: public CMultiMethodProps
-{
- HRESULT SetSolidFromString(const UString &s);
- HRESULT SetSolidFromPROPVARIANT(const PROPVARIANT &value);
-public:
- UInt64 _numSolidFiles;
- UInt64 _numSolidBytes;
- bool _numSolidBytesDefined;
- bool _solidExtension;
- bool _useTypeSorting;
-
- bool _compressHeaders;
- bool _encryptHeadersSpecified;
- bool _encryptHeaders;
- // bool _useParents; 9.26
-
- CBoolPair Write_CTime;
- CBoolPair Write_ATime;
- CBoolPair Write_MTime;
- CBoolPair Write_Attrib;
-
- bool _useMultiThreadMixer;
-
- bool _removeSfxBlock;
-
- // bool _volumeMode;
-
- void InitSolidFiles() { _numSolidFiles = (UInt64)(Int64)(-1); }
- void InitSolidSize() { _numSolidBytes = (UInt64)(Int64)(-1); }
- void InitSolid()
- {
- InitSolidFiles();
- InitSolidSize();
- _solidExtension = false;
- _numSolidBytesDefined = false;
- }
-
- void InitProps7z();
- void InitProps();
-
- COutHandler() { InitProps7z(); }
-
- HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value);
-};
-
-#endif
-
-class CHandler:
- public IInArchive,
- public IArchiveGetRawProps,
-
- #ifdef __7Z_SET_PROPERTIES
- public ISetProperties,
- #endif
-
- #ifndef EXTRACT_ONLY
- public IOutArchive,
- #endif
-
- PUBLIC_ISetCompressCodecsInfo
-
- public CMyUnknownImp,
-
- #ifndef EXTRACT_ONLY
- public COutHandler
- #else
- public CCommonMethodProps
- #endif
-{
-public:
- MY_QUERYINTERFACE_BEGIN2(IInArchive)
- MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps)
- #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(;)
- INTERFACE_IArchiveGetRawProps(;)
-
- #ifdef __7Z_SET_PROPERTIES
- STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
- #endif
-
- #ifndef EXTRACT_ONLY
- INTERFACE_IOutArchive(;)
- #endif
-
- DECL_ISetCompressCodecsInfo
-
- CHandler();
-
-private:
- CMyComPtr<IInStream> _inStream;
- NArchive::N7z::CDbEx _db;
-
- #ifndef _NO_CRYPTO
- bool _isEncrypted;
- bool _passwordIsDefined;
- UString _password;
- #endif
-
- #ifdef EXTRACT_ONLY
-
- #ifdef __7Z_SET_PROPERTIES
- bool _useMultiThreadMixer;
- #endif
-
- UInt32 _crcSize;
-
- #else
-
- CRecordVector<CBond2> _bonds;
-
- HRESULT PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m);
- HRESULT SetHeaderMethod(CCompressionMethodMode &headerMethod);
- HRESULT SetMainMethod(CCompressionMethodMode &method
- #ifndef _7ZIP_ST
- , UInt32 numThreads
- #endif
- );
-
-
- #endif
-
- bool IsFolderEncrypted(CNum folderIndex) const;
- #ifndef _SFX
-
- CRecordVector<UInt64> _fileInfoPopIDs;
- void FillPopIDs();
- void AddMethodName(AString &s, UInt64 id);
- HRESULT SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const;
-
- #endif
-
- DECL_EXTERNAL_CODECS_VARS
-};
-
-}}
-
-#endif
+// 7z/Handler.h
+
+#ifndef ZIP7_7Z_HANDLER_H
+#define ZIP7_7Z_HANDLER_H
+
+#include "../../ICoder.h"
+#include "../IArchive.h"
+
+#include "../../Common/CreateCoder.h"
+
+#ifndef Z7_7Z_SET_PROPERTIES
+
+#ifdef Z7_EXTRACT_ONLY
+ #if !defined(Z7_ST) && !defined(Z7_SFX)
+ #define Z7_7Z_SET_PROPERTIES
+ #endif
+#else
+ #define Z7_7Z_SET_PROPERTIES
+#endif
+
+#endif
+
+// #ifdef Z7_7Z_SET_PROPERTIES
+#include "../Common/HandlerOut.h"
+// #endif
+
+#include "7zCompressionMode.h"
+#include "7zIn.h"
+
+namespace NArchive {
+namespace N7z {
+
+
+#ifndef Z7_EXTRACT_ONLY
+
+class COutHandler: public CMultiMethodProps
+{
+ HRESULT SetSolidFromString(const UString &s);
+ HRESULT SetSolidFromPROPVARIANT(const PROPVARIANT &value);
+public:
+ UInt64 _numSolidFiles;
+ UInt64 _numSolidBytes;
+ bool _numSolidBytesDefined;
+ bool _solidExtension;
+ bool _useTypeSorting;
+
+ bool _compressHeaders;
+ bool _encryptHeadersSpecified;
+ bool _encryptHeaders;
+ // bool _useParents; 9.26
+
+ CHandlerTimeOptions TimeOptions;
+
+ CBoolPair Write_Attrib;
+
+ bool _useMultiThreadMixer;
+
+ bool _removeSfxBlock;
+
+ // bool _volumeMode;
+
+ void InitSolidFiles() { _numSolidFiles = (UInt64)(Int64)(-1); }
+ void InitSolidSize() { _numSolidBytes = (UInt64)(Int64)(-1); }
+ void InitSolid()
+ {
+ InitSolidFiles();
+ InitSolidSize();
+ _solidExtension = false;
+ _numSolidBytesDefined = false;
+ }
+
+ void InitProps7z();
+ void InitProps();
+
+ COutHandler() { InitProps7z(); }
+
+ HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value);
+};
+
+#endif
+
+class CHandler Z7_final:
+ public IInArchive,
+ public IArchiveGetRawProps,
+
+ #ifdef Z7_7Z_SET_PROPERTIES
+ public ISetProperties,
+ #endif
+
+ #ifndef Z7_EXTRACT_ONLY
+ public IOutArchive,
+ #endif
+
+ Z7_PUBLIC_ISetCompressCodecsInfo_IFEC
+
+ public CMyUnknownImp,
+
+ #ifndef Z7_EXTRACT_ONLY
+ public COutHandler
+ #else
+ public CCommonMethodProps
+ #endif
+{
+ Z7_COM_QI_BEGIN2(IInArchive)
+ Z7_COM_QI_ENTRY(IArchiveGetRawProps)
+ #ifdef Z7_7Z_SET_PROPERTIES
+ Z7_COM_QI_ENTRY(ISetProperties)
+ #endif
+ #ifndef Z7_EXTRACT_ONLY
+ Z7_COM_QI_ENTRY(IOutArchive)
+ #endif
+ Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(IInArchive)
+ Z7_IFACE_COM7_IMP(IArchiveGetRawProps)
+ #ifdef Z7_7Z_SET_PROPERTIES
+ Z7_IFACE_COM7_IMP(ISetProperties)
+ #endif
+ #ifndef Z7_EXTRACT_ONLY
+ Z7_IFACE_COM7_IMP(IOutArchive)
+ #endif
+ DECL_ISetCompressCodecsInfo
+
+private:
+ CMyComPtr<IInStream> _inStream;
+ NArchive::N7z::CDbEx _db;
+
+ #ifndef Z7_NO_CRYPTO
+ bool _isEncrypted;
+ bool _passwordIsDefined;
+ UString _password; // _Wipe
+ #endif
+
+ #ifdef Z7_EXTRACT_ONLY
+
+ #ifdef Z7_7Z_SET_PROPERTIES
+ bool _useMultiThreadMixer;
+ #endif
+
+ UInt32 _crcSize;
+
+ #else
+
+ CRecordVector<CBond2> _bonds;
+
+ HRESULT PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m);
+ HRESULT SetHeaderMethod(CCompressionMethodMode &headerMethod);
+ HRESULT SetMainMethod(CCompressionMethodMode &method);
+
+ #endif
+
+ bool IsFolderEncrypted(CNum folderIndex) const;
+ #ifndef Z7_SFX
+
+ CRecordVector<UInt64> _fileInfoPopIDs;
+ void FillPopIDs();
+ void AddMethodName(AString &s, UInt64 id);
+ HRESULT SetMethodToProp(CNum folderIndex, PROPVARIANT *prop) const;
+
+ #endif
+
+ DECL_EXTERNAL_CODECS_VARS
+
+public:
+ CHandler();
+ ~CHandler()
+ {
+ Close();
+ }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/7z/7zHandlerOut.cpp b/CPP/7zip/Archive/7z/7zHandlerOut.cpp
index 62587e8..ff8735f 100644
--- a/CPP/7zip/Archive/7z/7zHandlerOut.cpp
+++ b/CPP/7zip/Archive/7z/7zHandlerOut.cpp
@@ -1,942 +1,1086 @@
-// 7zHandlerOut.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/ComTry.h"
-#include "../../../Common/StringToInt.h"
-#include "../../../Common/Wildcard.h"
-
-#include "../Common/ItemNameUtils.h"
-#include "../Common/ParseProperties.h"
-
-#include "7zHandler.h"
-#include "7zOut.h"
-#include "7zUpdate.h"
-
-#ifndef EXTRACT_ONLY
-
-using namespace NWindows;
-
-namespace NArchive {
-namespace N7z {
-
-#define k_LZMA_Name "LZMA"
-#define kDefaultMethodName "LZMA2"
-#define k_Copy_Name "Copy"
-
-#define k_MatchFinder_ForHeaders "BT2"
-
-static const UInt32 k_NumFastBytes_ForHeaders = 273;
-static const UInt32 k_Level_ForHeaders = 5;
-static const UInt32 k_Dictionary_ForHeaders =
- #ifdef UNDER_CE
- 1 << 18;
- #else
- 1 << 20;
- #endif
-
-STDMETHODIMP CHandler::GetFileTimeType(UInt32 *type)
-{
- *type = NFileTimeType::kWindows;
- return S_OK;
-}
-
-HRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m)
-{
- dest.CodecIndex = FindMethod_Index(
- EXTERNAL_CODECS_VARS
- m.MethodName, true,
- dest.Id, dest.NumStreams);
- if (dest.CodecIndex < 0)
- return E_INVALIDARG;
- (CProps &)dest = (CProps &)m;
- return S_OK;
-}
-
-HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod)
-{
- if (!_compressHeaders)
- return S_OK;
- COneMethodInfo m;
- m.MethodName = k_LZMA_Name;
- m.AddProp_Ascii(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders);
- m.AddProp_Level(k_Level_ForHeaders);
- m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders);
- m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders);
- m.AddProp_NumThreads(1);
-
- CMethodFull &methodFull = headerMethod.Methods.AddNew();
- return PropsMethod_To_FullMethod(methodFull, m);
-}
-
-HRESULT CHandler::SetMainMethod(
- CCompressionMethodMode &methodMode
- #ifndef _7ZIP_ST
- , UInt32 numThreads
- #endif
- )
-{
- methodMode.Bonds = _bonds;
-
- CObjectVector<COneMethodInfo> methods = _methods;
-
- {
- FOR_VECTOR (i, methods)
- {
- AString &methodName = methods[i].MethodName;
- if (methodName.IsEmpty())
- methodName = kDefaultMethodName;
- }
- if (methods.IsEmpty())
- {
- COneMethodInfo &m = methods.AddNew();
- m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName);
- methodMode.DefaultMethod_was_Inserted = true;
- }
- }
-
- if (!_filterMethod.MethodName.IsEmpty())
- {
- // if (methodMode.Bonds.IsEmpty())
- {
- FOR_VECTOR (k, methodMode.Bonds)
- {
- CBond2 &bond = methodMode.Bonds[k];
- bond.InCoder++;
- bond.OutCoder++;
- }
- methods.Insert(0, _filterMethod);
- methodMode.Filter_was_Inserted = true;
- }
- }
-
- const UInt64 kSolidBytes_Min = (1 << 24);
- const UInt64 kSolidBytes_Max = ((UInt64)1 << 32) - 1;
-
- bool needSolid = false;
-
- FOR_VECTOR (i, methods)
- {
- COneMethodInfo &oneMethodInfo = methods[i];
-
- SetGlobalLevelTo(oneMethodInfo);
- #ifndef _7ZIP_ST
- CMultiMethodProps::SetMethodThreadsTo(oneMethodInfo, numThreads);
- #endif
-
- CMethodFull &methodFull = methodMode.Methods.AddNew();
- RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo));
-
- if (methodFull.Id != k_Copy)
- needSolid = true;
-
- if (_numSolidBytesDefined)
- continue;
-
- UInt32 dicSize;
- switch (methodFull.Id)
- {
- case k_LZMA:
- case k_LZMA2: dicSize = oneMethodInfo.Get_Lzma_DicSize(); break;
- case k_PPMD: dicSize = oneMethodInfo.Get_Ppmd_MemSize(); break;
- case k_Deflate: dicSize = (UInt32)1 << 15; break;
- case k_BZip2: dicSize = oneMethodInfo.Get_BZip2_BlockSize(); break;
- default: continue;
- }
-
- _numSolidBytes = (UInt64)dicSize << 7;
- if (_numSolidBytes < kSolidBytes_Min) _numSolidBytes = kSolidBytes_Min;
- if (_numSolidBytes > kSolidBytes_Max) _numSolidBytes = kSolidBytes_Max;
- _numSolidBytesDefined = true;
- }
-
- if (!_numSolidBytesDefined)
- if (needSolid)
- _numSolidBytes = kSolidBytes_Max;
- else
- _numSolidBytes = 0;
- _numSolidBytesDefined = true;
- return S_OK;
-}
-
-static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, int index, PROPID propID, UInt64 &ft, bool &ftDefined)
-{
- // ft = 0;
- // ftDefined = false;
- 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;
- else
- {
- ft = 0;
- ftDefined = false;
- }
- return S_OK;
-}
-
-/*
-
-#ifdef _WIN32
-static const wchar_t kDirDelimiter1 = L'\\';
-#endif
-static const wchar_t kDirDelimiter2 = L'/';
-
-static inline bool IsCharDirLimiter(wchar_t c)
-{
- return (
- #ifdef _WIN32
- c == kDirDelimiter1 ||
- #endif
- c == kDirDelimiter2);
-}
-
-static int FillSortIndex(CObjectVector<CTreeFolder> &treeFolders, int cur, int curSortIndex)
-{
- CTreeFolder &tf = treeFolders[cur];
- tf.SortIndex = curSortIndex++;
- for (int i = 0; i < tf.SubFolders.Size(); i++)
- curSortIndex = FillSortIndex(treeFolders, tf.SubFolders[i], curSortIndex);
- tf.SortIndexEnd = curSortIndex;
- return curSortIndex;
-}
-
-static int FindSubFolder(const CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name, int &insertPos)
-{
- const CIntVector &subFolders = treeFolders[cur].SubFolders;
- int left = 0, right = subFolders.Size();
- insertPos = -1;
- for (;;)
- {
- if (left == right)
- {
- insertPos = left;
- return -1;
- }
- int mid = (left + right) / 2;
- int midFolder = subFolders[mid];
- int compare = CompareFileNames(name, treeFolders[midFolder].Name);
- if (compare == 0)
- return midFolder;
- if (compare < 0)
- right = mid;
- else
- left = mid + 1;
- }
-}
-
-static int AddFolder(CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name)
-{
- int insertPos;
- int folderIndex = FindSubFolder(treeFolders, cur, name, insertPos);
- if (folderIndex < 0)
- {
- folderIndex = treeFolders.Size();
- CTreeFolder &newFolder = treeFolders.AddNew();
- newFolder.Parent = cur;
- newFolder.Name = name;
- treeFolders[cur].SubFolders.Insert(insertPos, folderIndex);
- }
- // else if (treeFolders[folderIndex].IsAltStreamFolder != isAltStreamFolder) throw 1123234234;
- return folderIndex;
-}
-*/
-
-STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
- IArchiveUpdateCallback *updateCallback)
-{
- COM_TRY_BEGIN
-
- const CDbEx *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
-
- if (db && !db->CanUpdate())
- return E_NOTIMPL;
-
- /*
- CMyComPtr<IArchiveGetRawProps> getRawProps;
- updateCallback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps);
-
- CUniqBlocks secureBlocks;
- secureBlocks.AddUniq(NULL, 0);
-
- CObjectVector<CTreeFolder> treeFolders;
- {
- CTreeFolder folder;
- folder.Parent = -1;
- treeFolders.Add(folder);
- }
- */
-
- CObjectVector<CUpdateItem> updateItems;
-
- bool need_CTime = (Write_CTime.Def && Write_CTime.Val);
- bool need_ATime = (Write_ATime.Def && Write_ATime.Val);
- bool need_MTime = (Write_MTime.Def && Write_MTime.Val || !Write_MTime.Def);
- bool need_Attrib = (Write_Attrib.Def && Write_Attrib.Val || !Write_Attrib.Def);
-
- if (db && !db->Files.IsEmpty())
- {
- if (!Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty();
- if (!Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty();
- if (!Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty();
- if (!Write_Attrib.Def) need_Attrib = !db->Attrib.Defs.IsEmpty();
- }
-
- // UString s;
- UString name;
-
- 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;
-
- name.Empty();
- // bool isAltStream = false;
- if (ui.IndexInArchive != -1)
- {
- if (db == 0 || (unsigned)ui.IndexInArchive >= db->Files.Size())
- return E_INVALIDARG;
- const CFileItem &fi = db->Files[ui.IndexInArchive];
- if (!ui.NewProps)
- {
- _db.GetPath(ui.IndexInArchive, name);
- }
- ui.IsDir = fi.IsDir;
- ui.Size = fi.Size;
- // isAltStream = fi.IsAltStream;
- ui.IsAnti = db->IsItemAnti(ui.IndexInArchive);
-
- if (!ui.NewProps)
- {
- 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 folderStatusIsDefined;
- if (need_Attrib)
- {
- 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.
- if (need_CTime) RINOK(GetTime(updateCallback, i, kpidCTime, ui.CTime, ui.CTimeDefined));
- if (need_ATime) RINOK(GetTime(updateCallback, i, kpidATime, ui.ATime, ui.ATimeDefined));
- if (need_MTime) RINOK(GetTime(updateCallback, i, kpidMTime, ui.MTime, ui.MTimeDefined));
-
- /*
- if (getRawProps)
- {
- const void *data;
- UInt32 dataSize;
- UInt32 propType;
-
- getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType);
- if (dataSize != 0 && propType != NPropDataType::kRaw)
- return E_FAIL;
- ui.SecureIndex = secureBlocks.AddUniq((const Byte *)data, dataSize);
- }
- */
-
- {
- NCOM::CPropVariant prop;
- RINOK(updateCallback->GetProperty(i, kpidPath, &prop));
- if (prop.vt == VT_EMPTY)
- {
- }
- else if (prop.vt != VT_BSTR)
- return E_INVALIDARG;
- else
- {
- name = prop.bstrVal;
- NItemName::ReplaceSlashes_OsToUnix(name);
- }
- }
- {
- 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);
- }
-
- /*
- {
- NCOM::CPropVariant prop;
- RINOK(updateCallback->GetProperty(i, kpidIsAltStream, &prop));
- if (prop.vt == VT_EMPTY)
- isAltStream = false;
- else if (prop.vt != VT_BOOL)
- return E_INVALIDARG;
- else
- isAltStream = (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();
- }
- else
- {
- /*
- if (_db.SecureIDs.IsEmpty())
- ui.SecureIndex = secureBlocks.AddUniq(NULL, 0);
- else
- {
- int id = _db.SecureIDs[ui.IndexInArchive];
- size_t offs = _db.SecureOffsets[id];
- size_t size = _db.SecureOffsets[id + 1] - offs;
- ui.SecureIndex = secureBlocks.AddUniq(_db.SecureBuf + offs, size);
- }
- */
- }
-
- /*
- {
- int folderIndex = 0;
- if (_useParents)
- {
- int j;
- s.Empty();
- for (j = 0; j < name.Len(); j++)
- {
- wchar_t c = name[j];
- if (IsCharDirLimiter(c))
- {
- folderIndex = AddFolder(treeFolders, folderIndex, s);
- s.Empty();
- continue;
- }
- s += c;
- }
- if (isAltStream)
- {
- int colonPos = s.Find(':');
- if (colonPos < 0)
- {
- // isAltStream = false;
- return E_INVALIDARG;
- }
- UString mainName = s.Left(colonPos);
- int newFolderIndex = AddFolder(treeFolders, folderIndex, mainName);
- if (treeFolders[newFolderIndex].UpdateItemIndex < 0)
- {
- for (int j = updateItems.Size() - 1; j >= 0; j--)
- {
- CUpdateItem &ui2 = updateItems[j];
- if (ui2.ParentFolderIndex == folderIndex
- && ui2.Name == mainName)
- {
- ui2.TreeFolderIndex = newFolderIndex;
- treeFolders[newFolderIndex].UpdateItemIndex = j;
- }
- }
- }
- folderIndex = newFolderIndex;
- s.Delete(0, colonPos + 1);
- }
- ui.Name = s;
- }
- else
- ui.Name = name;
- ui.IsAltStream = isAltStream;
- ui.ParentFolderIndex = folderIndex;
- ui.TreeFolderIndex = -1;
- if (ui.IsDir && !s.IsEmpty())
- {
- ui.TreeFolderIndex = AddFolder(treeFolders, folderIndex, s);
- treeFolders[ui.TreeFolderIndex].UpdateItemIndex = updateItems.Size();
- }
- }
- */
- ui.Name = name;
-
- if (ui.NewData)
- {
- ui.Size = 0;
- if (!ui.IsDir)
- {
- 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);
- }
-
- /*
- FillSortIndex(treeFolders, 0, 0);
- for (i = 0; i < (UInt32)updateItems.Size(); i++)
- {
- CUpdateItem &ui = updateItems[i];
- ui.ParentSortIndex = treeFolders[ui.ParentFolderIndex].SortIndex;
- ui.ParentSortIndexEnd = treeFolders[ui.ParentFolderIndex].SortIndexEnd;
- }
- */
-
- CCompressionMethodMode methodMode, headerMethod;
-
- HRESULT res = SetMainMethod(methodMode
- #ifndef _7ZIP_ST
- , _numThreads
- #endif
- );
- RINOK(res);
-
- RINOK(SetHeaderMethod(headerMethod));
-
- #ifndef _7ZIP_ST
- methodMode.NumThreads = _numThreads;
- methodMode.MultiThreadMixer = _useMultiThreadMixer;
- headerMethod.NumThreads = 1;
- headerMethod.MultiThreadMixer = _useMultiThreadMixer;
- #endif
-
- CMyComPtr<ICryptoGetTextPassword2> getPassword2;
- updateCallback->QueryInterface(IID_ICryptoGetTextPassword2, (void **)&getPassword2);
-
- methodMode.PasswordIsDefined = false;
- methodMode.Password.Empty();
- if (getPassword2)
- {
- CMyComBSTR password;
- Int32 passwordIsDefined;
- RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password));
- methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
- if (methodMode.PasswordIsDefined && password)
- methodMode.Password = password;
- }
-
- bool compressMainHeader = _compressHeaders; // check it
-
- bool encryptHeaders = false;
-
- #ifndef _NO_CRYPTO
- if (!methodMode.PasswordIsDefined && _passwordIsDefined)
- {
- // if header is compressed, we use that password for updated archive
- methodMode.PasswordIsDefined = true;
- methodMode.Password = _password;
- }
- #endif
-
- 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;
-
- int level = GetLevel();
-
- CUpdateOptions options;
- options.Method = &methodMode;
- options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL;
- options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted);
- options.MaxFilter = (level >= 8);
- options.AnalysisLevel = GetAnalysisLevel();
-
- options.HeaderOptions.CompressMainHeader = compressMainHeader;
- /*
- options.HeaderOptions.WriteCTime = Write_CTime;
- options.HeaderOptions.WriteATime = Write_ATime;
- options.HeaderOptions.WriteMTime = Write_MTime;
- options.HeaderOptions.WriteAttrib = Write_Attrib;
- */
-
- options.NumSolidFiles = _numSolidFiles;
- options.NumSolidBytes = _numSolidBytes;
- options.SolidExtension = _solidExtension;
- options.UseTypeSorting = _useTypeSorting;
-
- options.RemoveSfxBlock = _removeSfxBlock;
- // options.VolumeMode = _volumeMode;
-
- options.MultiThreadMixer = _useMultiThreadMixer;
-
- COutArchive archive;
- CArchiveDatabaseOut newDatabase;
-
- CMyComPtr<ICryptoGetTextPassword> getPassword;
- updateCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getPassword);
-
- /*
- if (secureBlocks.Sorted.Size() > 1)
- {
- secureBlocks.GetReverseMap();
- for (int i = 0; i < updateItems.Size(); i++)
- {
- int &secureIndex = updateItems[i].SecureIndex;
- secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex];
- }
- }
- */
-
- res = Update(
- EXTERNAL_CODECS_VARS
- #ifdef _7Z_VOL
- volume ? volume->Stream: 0,
- volume ? db : 0,
- #else
- _inStream,
- db,
- #endif
- updateItems,
- // treeFolders,
- // secureBlocks,
- 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 ParseBond(UString &srcString, UInt32 &coder, UInt32 &stream)
-{
- stream = 0;
- {
- unsigned index = ParseStringToUInt32(srcString, coder);
- if (index == 0)
- return E_INVALIDARG;
- srcString.DeleteFrontal(index);
- }
- if (srcString[0] == 's')
- {
- srcString.Delete(0);
- unsigned index = ParseStringToUInt32(srcString, stream);
- if (index == 0)
- return E_INVALIDARG;
- srcString.DeleteFrontal(index);
- }
- return S_OK;
-}
-
-void COutHandler::InitProps7z()
-{
- _removeSfxBlock = false;
- _compressHeaders = true;
- _encryptHeadersSpecified = false;
- _encryptHeaders = false;
- // _useParents = false;
-
- Write_CTime.Init();
- Write_ATime.Init();
- Write_MTime.Init();
- Write_Attrib.Init();
-
- _useMultiThreadMixer = true;
-
- // _volumeMode = false;
-
- InitSolid();
- _useTypeSorting = false;
-}
-
-void COutHandler::InitProps()
-{
- CMultiMethodProps::Init();
- InitProps7z();
-}
-
-
-
-HRESULT COutHandler::SetSolidFromString(const UString &s)
-{
- UString s2 = s;
- s2.MakeLower_Ascii();
- for (unsigned i = 0; i < s2.Len();)
- {
- const wchar_t *start = ((const wchar_t *)s2) + i;
- const wchar_t *end;
- UInt64 v = ConvertStringToUInt64(start, &end);
- if (start == end)
- {
- if (s2[i++] != 'e')
- return E_INVALIDARG;
- _solidExtension = true;
- continue;
- }
- i += (int)(end - start);
- if (i == s2.Len())
- return E_INVALIDARG;
- wchar_t c = s2[i++];
- if (c == 'f')
- {
- if (v < 1)
- v = 1;
- _numSolidFiles = v;
- }
- else
- {
- unsigned numBits;
- switch (c)
- {
- case 'b': numBits = 0; break;
- case 'k': numBits = 10; break;
- case 'm': numBits = 20; break;
- case 'g': numBits = 30; break;
- case 't': numBits = 40; break;
- default: return E_INVALIDARG;
- }
- _numSolidBytes = (v << numBits);
- _numSolidBytesDefined = true;
- /*
- if (_numSolidBytes == 0)
- _numSolidFiles = 1;
- */
- }
- }
- return S_OK;
-}
-
-HRESULT COutHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value)
-{
- bool isSolid;
- switch (value.vt)
- {
- case VT_EMPTY: isSolid = true; break;
- case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break;
- case VT_BSTR:
- if (StringToBool(value.bstrVal, isSolid))
- break;
- return SetSolidFromString(value.bstrVal);
- default: return E_INVALIDARG;
- }
- if (isSolid)
- InitSolid();
- else
- _numSolidFiles = 1;
- return S_OK;
-}
-
-static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest)
-{
- RINOK(PROPVARIANT_to_bool(prop, dest.Val));
- dest.Def = true;
- return S_OK;
-}
-
-HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
-{
- UString name = nameSpec;
- name.MakeLower_Ascii();
- if (name.IsEmpty())
- return E_INVALIDARG;
-
- if (name[0] == L's')
- {
- name.Delete(0);
- if (name.IsEmpty())
- return SetSolidFromPROPVARIANT(value);
- if (value.vt != VT_EMPTY)
- return E_INVALIDARG;
- return SetSolidFromString(name);
- }
-
- UInt32 number;
- int index = ParseStringToUInt32(name, number);
- // UString realName = name.Ptr(index);
- if (index == 0)
- {
- if (name.IsEqualTo("rsfx")) return PROPVARIANT_to_bool(value, _removeSfxBlock);
- if (name.IsEqualTo("hc")) return PROPVARIANT_to_bool(value, _compressHeaders);
- // if (name.IsEqualToNoCase(L"HS")) return PROPVARIANT_to_bool(value, _useParents);
-
- if (name.IsEqualTo("hcf"))
- {
- bool compressHeadersFull = true;
- RINOK(PROPVARIANT_to_bool(value, compressHeadersFull));
- return compressHeadersFull ? S_OK: E_INVALIDARG;
- }
-
- if (name.IsEqualTo("he"))
- {
- RINOK(PROPVARIANT_to_bool(value, _encryptHeaders));
- _encryptHeadersSpecified = true;
- return S_OK;
- }
-
- if (name.IsEqualTo("tc")) return PROPVARIANT_to_BoolPair(value, Write_CTime);
- if (name.IsEqualTo("ta")) return PROPVARIANT_to_BoolPair(value, Write_ATime);
- if (name.IsEqualTo("tm")) return PROPVARIANT_to_BoolPair(value, Write_MTime);
-
- if (name.IsEqualTo("tr")) return PROPVARIANT_to_BoolPair(value, Write_Attrib);
-
- if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer);
-
- if (name.IsEqualTo("qs")) return PROPVARIANT_to_bool(value, _useTypeSorting);
-
- // if (name.IsEqualTo("v")) return PROPVARIANT_to_bool(value, _volumeMode);
- }
- return CMultiMethodProps::SetProperty(name, value);
-}
-
-STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
-{
- COM_TRY_BEGIN
- _bonds.Clear();
- InitProps();
-
- for (UInt32 i = 0; i < numProps; i++)
- {
- UString name = names[i];
- name.MakeLower_Ascii();
- if (name.IsEmpty())
- return E_INVALIDARG;
-
- const PROPVARIANT &value = values[i];
-
- if (name[0] == 'b')
- {
- if (value.vt != VT_EMPTY)
- return E_INVALIDARG;
- name.Delete(0);
-
- CBond2 bond;
- RINOK(ParseBond(name, bond.OutCoder, bond.OutStream));
- if (name[0] != ':')
- return E_INVALIDARG;
- name.Delete(0);
- UInt32 inStream = 0;
- RINOK(ParseBond(name, bond.InCoder, inStream));
- if (inStream != 0)
- return E_INVALIDARG;
- if (!name.IsEmpty())
- return E_INVALIDARG;
- _bonds.Add(bond);
- continue;
- }
-
- RINOK(SetProperty(name, value));
- }
-
- unsigned numEmptyMethods = GetNumEmptyMethods();
- if (numEmptyMethods > 0)
- {
- unsigned k;
- for (k = 0; k < _bonds.Size(); k++)
- {
- const CBond2 &bond = _bonds[k];
- if (bond.InCoder < (UInt32)numEmptyMethods ||
- bond.OutCoder < (UInt32)numEmptyMethods)
- return E_INVALIDARG;
- }
- for (k = 0; k < _bonds.Size(); k++)
- {
- CBond2 &bond = _bonds[k];
- bond.InCoder -= (UInt32)numEmptyMethods;
- bond.OutCoder -= (UInt32)numEmptyMethods;
- }
- _methods.DeleteFrontal(numEmptyMethods);
- }
-
- FOR_VECTOR (k, _bonds)
- {
- const CBond2 &bond = _bonds[k];
- if (bond.InCoder >= (UInt32)_methods.Size() ||
- bond.OutCoder >= (UInt32)_methods.Size())
- return E_INVALIDARG;
- }
-
- return S_OK;
- COM_TRY_END
-}
-
-}}
-
-#endif
+// 7zHandlerOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/StringToInt.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../Common/ItemNameUtils.h"
+#include "../Common/ParseProperties.h"
+
+#include "7zHandler.h"
+#include "7zOut.h"
+#include "7zUpdate.h"
+
+#ifndef Z7_EXTRACT_ONLY
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace N7z {
+
+#define k_LZMA_Name "LZMA"
+#define kDefaultMethodName "LZMA2"
+#define k_Copy_Name "Copy"
+
+#define k_MatchFinder_ForHeaders "BT2"
+
+static const UInt32 k_NumFastBytes_ForHeaders = 273;
+static const UInt32 k_Level_ForHeaders = 5;
+static const UInt32 k_Dictionary_ForHeaders =
+ #ifdef UNDER_CE
+ 1 << 18;
+ #else
+ 1 << 20;
+ #endif
+
+Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *type))
+{
+ *type = NFileTimeType::kWindows;
+ return S_OK;
+}
+
+HRESULT CHandler::PropsMethod_To_FullMethod(CMethodFull &dest, const COneMethodInfo &m)
+{
+ bool isFilter;
+ dest.CodecIndex = FindMethod_Index(
+ EXTERNAL_CODECS_VARS
+ m.MethodName, true,
+ dest.Id, dest.NumStreams, isFilter);
+ if (dest.CodecIndex < 0)
+ return E_INVALIDARG;
+ (CProps &)dest = (CProps &)m;
+ return S_OK;
+}
+
+HRESULT CHandler::SetHeaderMethod(CCompressionMethodMode &headerMethod)
+{
+ if (!_compressHeaders)
+ return S_OK;
+ COneMethodInfo m;
+ m.MethodName = k_LZMA_Name;
+ m.AddProp_Ascii(NCoderPropID::kMatchFinder, k_MatchFinder_ForHeaders);
+ m.AddProp_Level(k_Level_ForHeaders);
+ m.AddProp32(NCoderPropID::kNumFastBytes, k_NumFastBytes_ForHeaders);
+ m.AddProp32(NCoderPropID::kDictionarySize, k_Dictionary_ForHeaders);
+ m.AddProp_NumThreads(1);
+
+ CMethodFull &methodFull = headerMethod.Methods.AddNew();
+ return PropsMethod_To_FullMethod(methodFull, m);
+}
+
+
+HRESULT CHandler::SetMainMethod(CCompressionMethodMode &methodMode)
+{
+ methodMode.Bonds = _bonds;
+
+ // we create local copy of _methods. So we can modify it.
+ CObjectVector<COneMethodInfo> methods = _methods;
+
+ {
+ FOR_VECTOR (i, methods)
+ {
+ AString &methodName = methods[i].MethodName;
+ if (methodName.IsEmpty())
+ methodName = kDefaultMethodName;
+ }
+ if (methods.IsEmpty())
+ {
+ COneMethodInfo &m = methods.AddNew();
+ m.MethodName = (GetLevel() == 0 ? k_Copy_Name : kDefaultMethodName);
+ methodMode.DefaultMethod_was_Inserted = true;
+ }
+ }
+
+ if (!_filterMethod.MethodName.IsEmpty())
+ {
+ // if (methodMode.Bonds.IsEmpty())
+ {
+ FOR_VECTOR (k, methodMode.Bonds)
+ {
+ CBond2 &bond = methodMode.Bonds[k];
+ bond.InCoder++;
+ bond.OutCoder++;
+ }
+ methods.Insert(0, _filterMethod);
+ methodMode.Filter_was_Inserted = true;
+ }
+ }
+
+ const UInt64 kSolidBytes_Min = (1 << 24);
+ const UInt64 kSolidBytes_Max = ((UInt64)1 << 32);
+
+ bool needSolid = false;
+
+ FOR_VECTOR (i, methods)
+ {
+ COneMethodInfo &oneMethodInfo = methods[i];
+
+ SetGlobalLevelTo(oneMethodInfo);
+
+ #ifndef Z7_ST
+ const bool numThreads_WasSpecifiedInMethod = (oneMethodInfo.Get_NumThreads() >= 0);
+ if (!numThreads_WasSpecifiedInMethod)
+ {
+ // here we set the (NCoderPropID::kNumThreads) property in each method, only if there is no such property already
+ CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, methodMode.NumThreads);
+ }
+ #endif
+
+ CMethodFull &methodFull = methodMode.Methods.AddNew();
+ RINOK(PropsMethod_To_FullMethod(methodFull, oneMethodInfo))
+
+ #ifndef Z7_ST
+ methodFull.Set_NumThreads = true;
+ methodFull.NumThreads = methodMode.NumThreads;
+ #endif
+
+ if (methodFull.Id != k_Copy)
+ needSolid = true;
+
+ UInt64 dicSize;
+ switch (methodFull.Id)
+ {
+ case k_LZMA:
+ case k_LZMA2: dicSize = oneMethodInfo.Get_Lzma_DicSize(); break;
+ case k_PPMD: dicSize = oneMethodInfo.Get_Ppmd_MemSize(); break;
+ case k_Deflate: dicSize = (UInt32)1 << 15; break;
+ case k_Deflate64: dicSize = (UInt32)1 << 16; break;
+ case k_BZip2: dicSize = oneMethodInfo.Get_BZip2_BlockSize(); break;
+ // case k_ZSTD: dicSize = 1 << 23; break;
+ default: continue;
+ }
+
+ UInt64 numSolidBytes;
+
+ /*
+ if (methodFull.Id == k_ZSTD)
+ {
+ // continue;
+ NCompress::NZstd::CEncoderProps encoderProps;
+ RINOK(oneMethodInfo.Set_PropsTo_zstd(encoderProps));
+ CZstdEncProps &zstdProps = encoderProps.EncProps;
+ ZstdEncProps_NormalizeFull(&zstdProps);
+ UInt64 cs = (UInt64)(zstdProps.jobSize);
+ UInt32 winSize = (UInt32)(1 << zstdProps.windowLog);
+ if (cs < winSize)
+ cs = winSize;
+ numSolidBytes = cs << 6;
+ const UInt64 kSolidBytes_Zstd_Max = ((UInt64)1 << 34);
+ if (numSolidBytes > kSolidBytes_Zstd_Max)
+ numSolidBytes = kSolidBytes_Zstd_Max;
+
+ methodFull.Set_NumThreads = false; // we don't use ICompressSetCoderMt::SetNumberOfThreads() for LZMA2 encoder
+
+ #ifndef Z7_ST
+ if (!numThreads_WasSpecifiedInMethod
+ && !methodMode.NumThreads_WasForced
+ && methodMode.MemoryUsageLimit_WasSet
+ )
+ {
+ const UInt32 numThreads_Original = methodMode.NumThreads;
+ const UInt32 numThreads_New = ZstdEncProps_GetNumThreads_for_MemUsageLimit(
+ &zstdProps,
+ methodMode.MemoryUsageLimit,
+ numThreads_Original);
+ if (numThreads_Original != numThreads_New)
+ {
+ CMultiMethodProps::SetMethodThreadsTo_Replace(methodFull, numThreads_New);
+ }
+ }
+ #endif
+ }
+ else
+ */
+ if (methodFull.Id == k_LZMA2)
+ {
+ // he we calculate default chunk Size for LZMA2 as defined in LZMA2 encoder code
+ /* lzma2 code use dictionary up to fake 4 GiB to calculate ChunkSize.
+ So we do same */
+ UInt64 cs = (UInt64)dicSize << 2;
+ const UInt32 kMinSize = (UInt32)1 << 20;
+ const UInt32 kMaxSize = (UInt32)1 << 28;
+ if (cs < kMinSize) cs = kMinSize;
+ if (cs > kMaxSize) cs = kMaxSize;
+ if (cs < dicSize) cs = dicSize;
+ cs += (kMinSize - 1);
+ cs &= ~(UInt64)(kMinSize - 1);
+ // we want to use at least 64 chunks (threads) per one solid block.
+
+ // here we don't use chunkSize property
+ numSolidBytes = cs << 6;
+
+ // here we get real chunkSize
+ cs = oneMethodInfo.Get_Xz_BlockSize();
+ if (dicSize > cs)
+ dicSize = cs;
+
+ const UInt64 kSolidBytes_Lzma2_Max = ((UInt64)1 << 34);
+ if (numSolidBytes > kSolidBytes_Lzma2_Max)
+ numSolidBytes = kSolidBytes_Lzma2_Max;
+
+ methodFull.Set_NumThreads = false; // we don't use ICompressSetCoderMt::SetNumberOfThreads() for LZMA2 encoder
+
+ #ifndef Z7_ST
+ if (!numThreads_WasSpecifiedInMethod
+ && !methodMode.NumThreads_WasForced
+ && methodMode.MemoryUsageLimit_WasSet
+ )
+ {
+ const UInt32 lzmaThreads = oneMethodInfo.Get_Lzma_NumThreads();
+ const UInt32 numBlockThreads_Original = methodMode.NumThreads / lzmaThreads;
+
+ if (numBlockThreads_Original > 1)
+ {
+ /*
+ const UInt32 kNumThreads_Max = 1024;
+ if (numBlockThreads > kNumMaxThreads)
+ numBlockThreads = kNumMaxThreads;
+ */
+
+ UInt32 numBlockThreads = numBlockThreads_Original;
+ const UInt64 lzmaMemUsage = oneMethodInfo.Get_Lzma_MemUsage(false); // solid
+
+ for (; numBlockThreads > 1; numBlockThreads--)
+ {
+ UInt64 size = numBlockThreads * (lzmaMemUsage + cs);
+ UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1;
+ if (cs < ((UInt32)1 << 26)) numPackChunks++;
+ if (cs < ((UInt32)1 << 24)) numPackChunks++;
+ if (cs < ((UInt32)1 << 22)) numPackChunks++;
+ size += numPackChunks * cs;
+ // printf("\nnumBlockThreads = %d, size = %d\n", (unsigned)(numBlockThreads), (unsigned)(size >> 20));
+ if (size <= methodMode.MemoryUsageLimit)
+ break;
+ }
+
+ if (numBlockThreads == 0)
+ numBlockThreads = 1;
+ if (numBlockThreads != numBlockThreads_Original)
+ {
+ const UInt32 numThreads_New = numBlockThreads * lzmaThreads;
+ CMultiMethodProps::SetMethodThreadsTo_Replace(methodFull, numThreads_New);
+ }
+ }
+ }
+ #endif
+ }
+ else
+ {
+ numSolidBytes = (UInt64)dicSize << 7;
+ if (numSolidBytes > kSolidBytes_Max)
+ numSolidBytes = kSolidBytes_Max;
+ }
+
+ if (_numSolidBytesDefined)
+ continue;
+
+ if (numSolidBytes < kSolidBytes_Min)
+ numSolidBytes = kSolidBytes_Min;
+ _numSolidBytes = numSolidBytes;
+ _numSolidBytesDefined = true;
+ }
+
+ if (!_numSolidBytesDefined)
+ {
+ if (needSolid)
+ _numSolidBytes = kSolidBytes_Max;
+ else
+ _numSolidBytes = 0;
+ }
+ _numSolidBytesDefined = true;
+
+
+ return S_OK;
+}
+
+
+
+static HRESULT GetTime(IArchiveUpdateCallback *updateCallback, unsigned index, PROPID propID, UInt64 &ft, bool &ftDefined)
+{
+ // ft = 0;
+ // ftDefined = false;
+ 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;
+ else
+ {
+ ft = 0;
+ ftDefined = false;
+ }
+ return S_OK;
+}
+
+/*
+
+#ifdef _WIN32
+static const wchar_t kDirDelimiter1 = L'\\';
+#endif
+static const wchar_t kDirDelimiter2 = L'/';
+
+static inline bool IsCharDirLimiter(wchar_t c)
+{
+ return (
+ #ifdef _WIN32
+ c == kDirDelimiter1 ||
+ #endif
+ c == kDirDelimiter2);
+}
+
+static int FillSortIndex(CObjectVector<CTreeFolder> &treeFolders, int cur, int curSortIndex)
+{
+ CTreeFolder &tf = treeFolders[cur];
+ tf.SortIndex = curSortIndex++;
+ for (int i = 0; i < tf.SubFolders.Size(); i++)
+ curSortIndex = FillSortIndex(treeFolders, tf.SubFolders[i], curSortIndex);
+ tf.SortIndexEnd = curSortIndex;
+ return curSortIndex;
+}
+
+static int FindSubFolder(const CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name, int &insertPos)
+{
+ const CIntVector &subFolders = treeFolders[cur].SubFolders;
+ int left = 0, right = subFolders.Size();
+ insertPos = -1;
+ for (;;)
+ {
+ if (left == right)
+ {
+ insertPos = left;
+ return -1;
+ }
+ int mid = (left + right) / 2;
+ int midFolder = subFolders[mid];
+ int compare = CompareFileNames(name, treeFolders[midFolder].Name);
+ if (compare == 0)
+ return midFolder;
+ if (compare < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+}
+
+static int AddFolder(CObjectVector<CTreeFolder> &treeFolders, int cur, const UString &name)
+{
+ int insertPos;
+ int folderIndex = FindSubFolder(treeFolders, cur, name, insertPos);
+ if (folderIndex < 0)
+ {
+ folderIndex = treeFolders.Size();
+ CTreeFolder &newFolder = treeFolders.AddNew();
+ newFolder.Parent = cur;
+ newFolder.Name = name;
+ treeFolders[cur].SubFolders.Insert(insertPos, folderIndex);
+ }
+ // else if (treeFolders[folderIndex].IsAltStreamFolder != isAltStreamFolder) throw 1123234234;
+ return folderIndex;
+}
+*/
+
+Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *updateCallback))
+{
+ COM_TRY_BEGIN
+
+ const CDbEx *db = NULL;
+ #ifdef Z7_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)
+ db = &_db;
+ #endif
+
+ if (db && !db->CanUpdate())
+ return E_NOTIMPL;
+
+ /*
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IArchiveGetRawProps,
+ getRawProps, updateCallback)
+
+ CUniqBlocks secureBlocks;
+ secureBlocks.AddUniq(NULL, 0);
+
+ CObjectVector<CTreeFolder> treeFolders;
+ {
+ CTreeFolder folder;
+ folder.Parent = -1;
+ treeFolders.Add(folder);
+ }
+ */
+
+ CObjectVector<CUpdateItem> updateItems;
+
+ bool need_CTime = (TimeOptions.Write_CTime.Def && TimeOptions.Write_CTime.Val);
+ bool need_ATime = (TimeOptions.Write_ATime.Def && TimeOptions.Write_ATime.Val);
+ bool need_MTime = (TimeOptions.Write_MTime.Def ? TimeOptions.Write_MTime.Val : true);
+ bool need_Attrib = (Write_Attrib.Def ? Write_Attrib.Val : true);
+
+ if (db && !db->Files.IsEmpty())
+ {
+ if (!TimeOptions.Write_CTime.Def) need_CTime = !db->CTime.Defs.IsEmpty();
+ if (!TimeOptions.Write_ATime.Def) need_ATime = !db->ATime.Defs.IsEmpty();
+ if (!TimeOptions.Write_MTime.Def) need_MTime = !db->MTime.Defs.IsEmpty();
+ if (!Write_Attrib.Def) need_Attrib = !db->Attrib.Defs.IsEmpty();
+ }
+
+ // UString s;
+ UString name;
+
+ 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 = (int)indexInArchive;
+ ui.IndexInClient = i;
+ ui.IsAnti = false;
+ ui.Size = 0;
+
+ name.Empty();
+ // bool isAltStream = false;
+ if (ui.IndexInArchive != -1)
+ {
+ if (!db || (unsigned)ui.IndexInArchive >= db->Files.Size())
+ return E_INVALIDARG;
+ const CFileItem &fi = db->Files[(unsigned)ui.IndexInArchive];
+ if (!ui.NewProps)
+ {
+ _db.GetPath((unsigned)ui.IndexInArchive, name);
+ }
+ ui.IsDir = fi.IsDir;
+ ui.Size = fi.Size;
+ // isAltStream = fi.IsAltStream;
+ ui.IsAnti = db->IsItemAnti((unsigned)ui.IndexInArchive);
+
+ if (!ui.NewProps)
+ {
+ ui.CTimeDefined = db->CTime.GetItem((unsigned)ui.IndexInArchive, ui.CTime);
+ ui.ATimeDefined = db->ATime.GetItem((unsigned)ui.IndexInArchive, ui.ATime);
+ ui.MTimeDefined = db->MTime.GetItem((unsigned)ui.IndexInArchive, ui.MTime);
+ }
+ }
+
+ if (ui.NewProps)
+ {
+ bool folderStatusIsDefined;
+ if (need_Attrib)
+ {
+ 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.
+ if (need_CTime) RINOK(GetTime(updateCallback, i, kpidCTime, ui.CTime, ui.CTimeDefined))
+ if (need_ATime) RINOK(GetTime(updateCallback, i, kpidATime, ui.ATime, ui.ATimeDefined))
+ if (need_MTime) RINOK(GetTime(updateCallback, i, kpidMTime, ui.MTime, ui.MTimeDefined))
+
+ /*
+ if (getRawProps)
+ {
+ const void *data;
+ UInt32 dataSize;
+ UInt32 propType;
+
+ getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType);
+ if (dataSize != 0 && propType != NPropDataType::kRaw)
+ return E_FAIL;
+ ui.SecureIndex = secureBlocks.AddUniq((const Byte *)data, dataSize);
+ }
+ */
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(i, kpidPath, &prop))
+ if (prop.vt == VT_EMPTY)
+ {
+ }
+ else if (prop.vt != VT_BSTR)
+ return E_INVALIDARG;
+ else
+ {
+ name = prop.bstrVal;
+ NItemName::ReplaceSlashes_OsToUnix(name);
+ }
+ }
+ {
+ 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);
+ }
+
+ /*
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(i, kpidIsAltStream, &prop));
+ if (prop.vt == VT_EMPTY)
+ isAltStream = false;
+ else if (prop.vt != VT_BOOL)
+ return E_INVALIDARG;
+ else
+ isAltStream = (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();
+ }
+ else
+ {
+ /*
+ if (_db.SecureIDs.IsEmpty())
+ ui.SecureIndex = secureBlocks.AddUniq(NULL, 0);
+ else
+ {
+ int id = _db.SecureIDs[ui.IndexInArchive];
+ size_t offs = _db.SecureOffsets[id];
+ size_t size = _db.SecureOffsets[id + 1] - offs;
+ ui.SecureIndex = secureBlocks.AddUniq(_db.SecureBuf + offs, size);
+ }
+ */
+ }
+
+ /*
+ {
+ int folderIndex = 0;
+ if (_useParents)
+ {
+ int j;
+ s.Empty();
+ for (j = 0; j < name.Len(); j++)
+ {
+ wchar_t c = name[j];
+ if (IsCharDirLimiter(c))
+ {
+ folderIndex = AddFolder(treeFolders, folderIndex, s);
+ s.Empty();
+ continue;
+ }
+ s += c;
+ }
+ if (isAltStream)
+ {
+ int colonPos = s.Find(':');
+ if (colonPos < 0)
+ {
+ // isAltStream = false;
+ return E_INVALIDARG;
+ }
+ UString mainName = s.Left(colonPos);
+ int newFolderIndex = AddFolder(treeFolders, folderIndex, mainName);
+ if (treeFolders[newFolderIndex].UpdateItemIndex < 0)
+ {
+ for (int j = updateItems.Size() - 1; j >= 0; j--)
+ {
+ CUpdateItem &ui2 = updateItems[j];
+ if (ui2.ParentFolderIndex == folderIndex
+ && ui2.Name == mainName)
+ {
+ ui2.TreeFolderIndex = newFolderIndex;
+ treeFolders[newFolderIndex].UpdateItemIndex = j;
+ }
+ }
+ }
+ folderIndex = newFolderIndex;
+ s.Delete(0, colonPos + 1);
+ }
+ ui.Name = s;
+ }
+ else
+ ui.Name = name;
+ ui.IsAltStream = isAltStream;
+ ui.ParentFolderIndex = folderIndex;
+ ui.TreeFolderIndex = -1;
+ if (ui.IsDir && !s.IsEmpty())
+ {
+ ui.TreeFolderIndex = AddFolder(treeFolders, folderIndex, s);
+ treeFolders[ui.TreeFolderIndex].UpdateItemIndex = updateItems.Size();
+ }
+ }
+ */
+ ui.Name = name;
+
+ if (ui.NewData)
+ {
+ ui.Size = 0;
+ if (!ui.IsDir)
+ {
+ 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);
+ }
+
+ /*
+ FillSortIndex(treeFolders, 0, 0);
+ for (i = 0; i < (UInt32)updateItems.Size(); i++)
+ {
+ CUpdateItem &ui = updateItems[i];
+ ui.ParentSortIndex = treeFolders[ui.ParentFolderIndex].SortIndex;
+ ui.ParentSortIndexEnd = treeFolders[ui.ParentFolderIndex].SortIndexEnd;
+ }
+ */
+
+ CCompressionMethodMode methodMode, headerMethod;
+
+ methodMode.MemoryUsageLimit = _memUsage_Compress;
+ methodMode.MemoryUsageLimit_WasSet = _memUsage_WasSet;
+
+ #ifndef Z7_ST
+ {
+ UInt32 numThreads = _numThreads;
+ const UInt32 kNumThreads_Max = 1024;
+ if (numThreads > kNumThreads_Max)
+ numThreads = kNumThreads_Max;
+ methodMode.NumThreads = numThreads;
+ methodMode.NumThreads_WasForced = _numThreads_WasForced;
+ methodMode.MultiThreadMixer = _useMultiThreadMixer;
+ // headerMethod.NumThreads = 1;
+ headerMethod.MultiThreadMixer = _useMultiThreadMixer;
+ }
+ #endif
+
+ const HRESULT res = SetMainMethod(methodMode);
+ RINOK(res)
+
+ RINOK(SetHeaderMethod(headerMethod))
+
+ Z7_DECL_CMyComPtr_QI_FROM(
+ ICryptoGetTextPassword2,
+ getPassword2, updateCallback)
+
+ methodMode.PasswordIsDefined = false;
+ methodMode.Password.Wipe_and_Empty();
+ if (getPassword2)
+ {
+ CMyComBSTR_Wipe password;
+ Int32 passwordIsDefined;
+ RINOK(getPassword2->CryptoGetTextPassword2(&passwordIsDefined, &password))
+ methodMode.PasswordIsDefined = IntToBool(passwordIsDefined);
+ if (methodMode.PasswordIsDefined && password)
+ methodMode.Password = password;
+ }
+
+ bool compressMainHeader = _compressHeaders; // check it
+
+ bool encryptHeaders = false;
+
+ #ifndef Z7_NO_CRYPTO
+ if (!methodMode.PasswordIsDefined && _passwordIsDefined)
+ {
+ // if header is compressed, we use that password for updated archive
+ methodMode.PasswordIsDefined = true;
+ methodMode.Password = _password;
+ }
+ #endif
+
+ if (methodMode.PasswordIsDefined)
+ {
+ if (_encryptHeadersSpecified)
+ encryptHeaders = _encryptHeaders;
+ #ifndef Z7_NO_CRYPTO
+ else
+ encryptHeaders = _passwordIsDefined;
+ #endif
+ compressMainHeader = true;
+ if (encryptHeaders)
+ {
+ headerMethod.PasswordIsDefined = methodMode.PasswordIsDefined;
+ headerMethod.Password = methodMode.Password;
+ }
+ }
+
+ if (numItems < 2)
+ compressMainHeader = false;
+
+ const int level = GetLevel();
+
+ CUpdateOptions options;
+ options.Need_CTime = need_CTime;
+ options.Need_ATime = need_ATime;
+ options.Need_MTime = need_MTime;
+ options.Need_Attrib = need_Attrib;
+ // options.Need_Crc = (_crcSize != 0); // for debug
+
+ options.Method = &methodMode;
+ options.HeaderMethod = (_compressHeaders || encryptHeaders) ? &headerMethod : NULL;
+ options.UseFilters = (level != 0 && _autoFilter && !methodMode.Filter_was_Inserted);
+ options.MaxFilter = (level >= 8);
+ options.AnalysisLevel = GetAnalysisLevel();
+
+ options.HeaderOptions.CompressMainHeader = compressMainHeader;
+ /*
+ options.HeaderOptions.WriteCTime = Write_CTime;
+ options.HeaderOptions.WriteATime = Write_ATime;
+ options.HeaderOptions.WriteMTime = Write_MTime;
+ options.HeaderOptions.WriteAttrib = Write_Attrib;
+ */
+
+ options.NumSolidFiles = _numSolidFiles;
+ options.NumSolidBytes = _numSolidBytes;
+ options.SolidExtension = _solidExtension;
+ options.UseTypeSorting = _useTypeSorting;
+
+ options.RemoveSfxBlock = _removeSfxBlock;
+ // options.VolumeMode = _volumeMode;
+
+ options.MultiThreadMixer = _useMultiThreadMixer;
+
+ /*
+ if (secureBlocks.Sorted.Size() > 1)
+ {
+ secureBlocks.GetReverseMap();
+ for (int i = 0; i < updateItems.Size(); i++)
+ {
+ int &secureIndex = updateItems[i].SecureIndex;
+ secureIndex = secureBlocks.BufIndexToSortedIndex[secureIndex];
+ }
+ }
+ */
+
+ return Update(
+ EXTERNAL_CODECS_VARS
+ #ifdef Z7_7Z_VOL
+ volume ? volume->Stream: 0,
+ volume ? db : 0,
+ #else
+ _inStream,
+ db,
+ #endif
+ updateItems,
+ // treeFolders,
+ // secureBlocks,
+ outStream, updateCallback, options);
+
+ COM_TRY_END
+}
+
+static HRESULT ParseBond(UString &srcString, UInt32 &coder, UInt32 &stream)
+{
+ stream = 0;
+ {
+ const unsigned index = ParseStringToUInt32(srcString, coder);
+ if (index == 0)
+ return E_INVALIDARG;
+ srcString.DeleteFrontal(index);
+ }
+ if (srcString[0] == 's')
+ {
+ srcString.Delete(0);
+ const unsigned index = ParseStringToUInt32(srcString, stream);
+ if (index == 0)
+ return E_INVALIDARG;
+ srcString.DeleteFrontal(index);
+ }
+ return S_OK;
+}
+
+void COutHandler::InitProps7z()
+{
+ _removeSfxBlock = false;
+ _compressHeaders = true;
+ _encryptHeadersSpecified = false;
+ _encryptHeaders = false;
+ // _useParents = false;
+
+ TimeOptions.Init();
+ Write_Attrib.Init();
+
+ _useMultiThreadMixer = true;
+
+ // _volumeMode = false;
+
+ InitSolid();
+ _useTypeSorting = false;
+}
+
+void COutHandler::InitProps()
+{
+ CMultiMethodProps::Init();
+ InitProps7z();
+}
+
+
+
+HRESULT COutHandler::SetSolidFromString(const UString &s)
+{
+ UString s2 = s;
+ s2.MakeLower_Ascii();
+ for (unsigned i = 0; i < s2.Len();)
+ {
+ const wchar_t *start = ((const wchar_t *)s2) + i;
+ const wchar_t *end;
+ UInt64 v = ConvertStringToUInt64(start, &end);
+ if (start == end)
+ {
+ if (s2[i++] != 'e')
+ return E_INVALIDARG;
+ _solidExtension = true;
+ continue;
+ }
+ i += (unsigned)(end - start);
+ if (i == s2.Len())
+ return E_INVALIDARG;
+ const wchar_t c = s2[i++];
+ if (c == 'f')
+ {
+ if (v < 1)
+ v = 1;
+ _numSolidFiles = v;
+ }
+ else
+ {
+ unsigned numBits;
+ switch (c)
+ {
+ case 'b': numBits = 0; break;
+ case 'k': numBits = 10; break;
+ case 'm': numBits = 20; break;
+ case 'g': numBits = 30; break;
+ case 't': numBits = 40; break;
+ default: return E_INVALIDARG;
+ }
+ _numSolidBytes = (v << numBits);
+ _numSolidBytesDefined = true;
+ /*
+ if (_numSolidBytes == 0)
+ _numSolidFiles = 1;
+ */
+ }
+ }
+ return S_OK;
+}
+
+HRESULT COutHandler::SetSolidFromPROPVARIANT(const PROPVARIANT &value)
+{
+ bool isSolid;
+ switch (value.vt)
+ {
+ case VT_EMPTY: isSolid = true; break;
+ case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break;
+ case VT_BSTR:
+ if (StringToBool(value.bstrVal, isSolid))
+ break;
+ return SetSolidFromString(value.bstrVal);
+ default: return E_INVALIDARG;
+ }
+ if (isSolid)
+ InitSolid();
+ else
+ _numSolidFiles = 1;
+ return S_OK;
+}
+
+static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest)
+{
+ RINOK(PROPVARIANT_to_bool(prop, dest.Val))
+ dest.Def = true;
+ return S_OK;
+}
+
+HRESULT COutHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
+{
+ UString name = nameSpec;
+ name.MakeLower_Ascii();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+
+ if (name[0] == L's')
+ {
+ name.Delete(0);
+ if (name.IsEmpty())
+ return SetSolidFromPROPVARIANT(value);
+ if (value.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ return SetSolidFromString(name);
+ }
+
+ UInt32 number;
+ const unsigned index = ParseStringToUInt32(name, number);
+ // UString realName = name.Ptr(index);
+ if (index == 0)
+ {
+ if (name.IsEqualTo("rsfx")) return PROPVARIANT_to_bool(value, _removeSfxBlock);
+ if (name.IsEqualTo("hc")) return PROPVARIANT_to_bool(value, _compressHeaders);
+ // if (name.IsEqualToNoCase(L"HS")) return PROPVARIANT_to_bool(value, _useParents);
+
+ if (name.IsEqualTo("hcf"))
+ {
+ bool compressHeadersFull = true;
+ RINOK(PROPVARIANT_to_bool(value, compressHeadersFull))
+ return compressHeadersFull ? S_OK: E_INVALIDARG;
+ }
+
+ if (name.IsEqualTo("he"))
+ {
+ RINOK(PROPVARIANT_to_bool(value, _encryptHeaders))
+ _encryptHeadersSpecified = true;
+ return S_OK;
+ }
+
+ {
+ bool processed;
+ RINOK(TimeOptions.Parse(name, value, processed))
+ if (processed)
+ {
+ if ( TimeOptions.Prec != (UInt32)(Int32)-1
+ && TimeOptions.Prec != k_PropVar_TimePrec_0
+ && TimeOptions.Prec != k_PropVar_TimePrec_HighPrec
+ && TimeOptions.Prec != k_PropVar_TimePrec_100ns)
+ return E_INVALIDARG;
+ return S_OK;
+ }
+ }
+
+ if (name.IsEqualTo("tr")) return PROPVARIANT_to_BoolPair(value, Write_Attrib);
+
+ if (name.IsEqualTo("mtf")) return PROPVARIANT_to_bool(value, _useMultiThreadMixer);
+
+ if (name.IsEqualTo("qs")) return PROPVARIANT_to_bool(value, _useTypeSorting);
+
+ // if (name.IsEqualTo("v")) return PROPVARIANT_to_bool(value, _volumeMode);
+ }
+ return CMultiMethodProps::SetProperty(name, value);
+}
+
+Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
+{
+ COM_TRY_BEGIN
+ _bonds.Clear();
+ InitProps();
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ UString name = names[i];
+ name.MakeLower_Ascii();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+
+ const PROPVARIANT &value = values[i];
+
+ if (name.Find(L':') >= 0) // 'b' was used as NCoderPropID::kBlockSize2 before v23
+ if (name[0] == 'b')
+ {
+ if (value.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ name.Delete(0);
+
+ CBond2 bond;
+ RINOK(ParseBond(name, bond.OutCoder, bond.OutStream))
+ if (name[0] != ':')
+ return E_INVALIDARG;
+ name.Delete(0);
+ UInt32 inStream = 0;
+ RINOK(ParseBond(name, bond.InCoder, inStream))
+ if (inStream != 0)
+ return E_INVALIDARG;
+ if (!name.IsEmpty())
+ return E_INVALIDARG;
+ _bonds.Add(bond);
+ continue;
+ }
+
+ RINOK(SetProperty(name, value))
+ }
+
+ unsigned numEmptyMethods = GetNumEmptyMethods();
+ if (numEmptyMethods > 0)
+ {
+ unsigned k;
+ for (k = 0; k < _bonds.Size(); k++)
+ {
+ const CBond2 &bond = _bonds[k];
+ if (bond.InCoder < (UInt32)numEmptyMethods ||
+ bond.OutCoder < (UInt32)numEmptyMethods)
+ return E_INVALIDARG;
+ }
+ for (k = 0; k < _bonds.Size(); k++)
+ {
+ CBond2 &bond = _bonds[k];
+ bond.InCoder -= (UInt32)numEmptyMethods;
+ bond.OutCoder -= (UInt32)numEmptyMethods;
+ }
+ _methods.DeleteFrontal(numEmptyMethods);
+ }
+
+ FOR_VECTOR (k, _bonds)
+ {
+ const CBond2 &bond = _bonds[k];
+ if (bond.InCoder >= (UInt32)_methods.Size() ||
+ bond.OutCoder >= (UInt32)_methods.Size())
+ return E_INVALIDARG;
+ }
+
+ return S_OK;
+ COM_TRY_END
+}
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/7z/7zHeader.cpp b/CPP/7zip/Archive/7z/7zHeader.cpp
index de39909..d5f9497 100644
--- a/CPP/7zip/Archive/7z/7zHeader.cpp
+++ b/CPP/7zip/Archive/7z/7zHeader.cpp
@@ -1,19 +1,19 @@
-// 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
-
-// We can change signature. So file doesn't contain correct signature.
-// struct SignatureInitializer { SignatureInitializer() { kSignature[0]--; } };
-// static SignatureInitializer g_SignatureInitializer;
-
-}}
+// 7zHeader.cpp
+
+#include "StdAfx.h"
+
+#include "7zHeader.h"
+
+namespace NArchive {
+namespace N7z {
+
+Byte kSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
+#ifdef Z7_7Z_VOL
+Byte kFinishSignature[kSignatureSize] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C + 1};
+#endif
+
+// We can change signature. So file doesn't contain correct signature.
+// struct SignatureInitializer { SignatureInitializer() { kSignature[0]--; } };
+// static SignatureInitializer g_SignatureInitializer;
+
+}}
diff --git a/CPP/7zip/Archive/7z/7zHeader.h b/CPP/7zip/Archive/7z/7zHeader.h
index 7de6eee..bd96ca3 100644
--- a/CPP/7zip/Archive/7z/7zHeader.h
+++ b/CPP/7zip/Archive/7z/7zHeader.h
@@ -1,148 +1,153 @@
-// 7z/7zHeader.h
-
-#ifndef __7Z_HEADER_H
-#define __7Z_HEADER_H
-
-#include "../../../Common/MyTypes.h"
-
-namespace NArchive {
-namespace N7z {
-
-const unsigned 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,
- kWinAttrib,
- kComment,
-
- kEncodedHeader,
-
- kStartPos,
- kDummy
-
- // kNtSecure,
- // kParent,
- // kIsAux
- };
-}
-
-
-const UInt32 k_Copy = 0;
-const UInt32 k_Delta = 3;
-
-const UInt32 k_LZMA2 = 0x21;
-
-const UInt32 k_SWAP2 = 0x20302;
-const UInt32 k_SWAP4 = 0x20304;
-
-const UInt32 k_LZMA = 0x30101;
-const UInt32 k_PPMD = 0x30401;
-
-const UInt32 k_Deflate = 0x40108;
-const UInt32 k_BZip2 = 0x40202;
-
-const UInt32 k_BCJ = 0x3030103;
-const UInt32 k_BCJ2 = 0x303011B;
-const UInt32 k_PPC = 0x3030205;
-const UInt32 k_IA64 = 0x3030401;
-const UInt32 k_ARM = 0x3030501;
-const UInt32 k_ARMT = 0x3030701;
-const UInt32 k_SPARC = 0x3030805;
-
-const UInt32 k_AES = 0x6F10701;
-
-
-static inline bool IsFilterMethod(UInt64 m)
-{
- if (m > (UInt64)0xFFFFFFFF)
- return false;
- switch ((UInt32)m)
- {
- case k_Delta:
- case k_BCJ:
- case k_BCJ2:
- case k_PPC:
- case k_IA64:
- case k_ARM:
- case k_ARMT:
- case k_SPARC:
- case k_SWAP2:
- case k_SWAP4:
- return true;
- }
- return false;
-}
-
-}}
-
-#endif
+// 7z/7zHeader.h
+
+#ifndef ZIP7_INC_7Z_HEADER_H
+#define ZIP7_INC_7Z_HEADER_H
+
+#include "../../../Common/MyTypes.h"
+
+namespace NArchive {
+namespace N7z {
+
+const unsigned kSignatureSize = 6;
+extern Byte kSignature[kSignatureSize];
+
+// #define Z7_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 Z7_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 Z7_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,
+ kWinAttrib,
+ kComment,
+
+ kEncodedHeader,
+
+ kStartPos,
+ kDummy
+
+ // kNtSecure,
+ // kParent,
+ // kIsAux
+ };
+}
+
+
+const UInt32 k_Copy = 0;
+const UInt32 k_Delta = 3;
+const UInt32 k_ARM64 = 0xa;
+
+const UInt32 k_LZMA2 = 0x21;
+
+const UInt32 k_SWAP2 = 0x20302;
+const UInt32 k_SWAP4 = 0x20304;
+
+const UInt32 k_LZMA = 0x30101;
+const UInt32 k_PPMD = 0x30401;
+
+const UInt32 k_Deflate = 0x40108;
+const UInt32 k_Deflate64 = 0x40109;
+const UInt32 k_BZip2 = 0x40202;
+
+const UInt32 k_BCJ = 0x3030103;
+const UInt32 k_BCJ2 = 0x303011B;
+const UInt32 k_PPC = 0x3030205;
+const UInt32 k_IA64 = 0x3030401;
+const UInt32 k_ARM = 0x3030501;
+const UInt32 k_ARMT = 0x3030701;
+const UInt32 k_SPARC = 0x3030805;
+
+const UInt32 k_AES = 0x6F10701;
+
+// const UInt32 k_ZSTD = 0x4015D; // winzip zstd
+// 0x4F71101, 7z-zstd
+
+static inline bool IsFilterMethod(UInt64 m)
+{
+ if (m > (UInt32)0xFFFFFFFF)
+ return false;
+ switch ((UInt32)m)
+ {
+ case k_Delta:
+ case k_ARM64:
+ case k_BCJ:
+ case k_BCJ2:
+ case k_PPC:
+ case k_IA64:
+ case k_ARM:
+ case k_ARMT:
+ case k_SPARC:
+ case k_SWAP2:
+ case k_SWAP4:
+ return true;
+ }
+ return false;
+}
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/7z/7zIn.cpp b/CPP/7zip/Archive/7z/7zIn.cpp
index ae5ff19..4defd27 100644
--- a/CPP/7zip/Archive/7z/7zIn.cpp
+++ b/CPP/7zip/Archive/7z/7zIn.cpp
@@ -1,1666 +1,1757 @@
-// 7zIn.cpp
-
-#include "StdAfx.h"
-
-#ifdef _WIN32
-#include <wchar.h>
-#else
-#include <ctype.h>
-#endif
-
-#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
-
-using namespace NWindows;
-using namespace NCOM;
-
-namespace NArchive {
-namespace N7z {
-
-unsigned BoolVector_CountSum(const CBoolVector &v)
-{
- unsigned sum = 0;
- const unsigned size = v.Size();
- for (unsigned i = 0; i < size; i++)
- if (v[i])
- sum++;
- return sum;
-}
-
-static inline bool BoolVector_Item_IsValidAndTrue(const CBoolVector &v, unsigned i)
-{
- return (i < v.Size() ? v[i] : false);
-}
-
-static void BoolVector_Fill_False(CBoolVector &v, unsigned size)
-{
- v.ClearAndSetSize(size);
- bool *p = &v[0];
- for (unsigned i = 0; i < size; i++)
- p[i] = false;
-}
-
-
-class CInArchiveException {};
-class CUnsupportedFeatureException: public CInArchiveException {};
-
-static void ThrowException() { throw CInArchiveException(); }
-static inline void ThrowEndOfData() { ThrowException(); }
-static inline void ThrowUnsupported() { throw CUnsupportedFeatureException(); }
-static inline void ThrowIncorrect() { ThrowException(); }
-
-class CStreamSwitch
-{
- CInArchive *_archive;
- bool _needRemove;
- bool _needUpdatePos;
-public:
- CStreamSwitch(): _needRemove(false), _needUpdatePos(false) {}
- ~CStreamSwitch() { Remove(); }
- void Remove();
- void Set(CInArchive *archive, const Byte *data, size_t size, bool needUpdatePos);
- void Set(CInArchive *archive, const CByteBuffer &byteBuffer);
- void Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector);
-};
-
-void CStreamSwitch::Remove()
-{
- if (_needRemove)
- {
- if (_archive->_inByteBack->GetRem() != 0)
- _archive->ThereIsHeaderError = true;
- _archive->DeleteByteStream(_needUpdatePos);
- _needRemove = false;
- }
-}
-
-void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size, bool needUpdatePos)
-{
- Remove();
- _archive = archive;
- _archive->AddByteStream(data, size);
- _needRemove = true;
- _needUpdatePos = needUpdatePos;
-}
-
-void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer)
-{
- Set(archive, byteBuffer, byteBuffer.Size(), false);
-}
-
-void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector)
-{
- Remove();
- Byte external = archive->ReadByte();
- if (external != 0)
- {
- if (!dataVector)
- ThrowIncorrect();
- CNum dataIndex = archive->ReadNum();
- if (dataIndex >= dataVector->Size())
- ThrowIncorrect();
- Set(archive, (*dataVector)[dataIndex]);
- }
-}
-
-void CInArchive::AddByteStream(const Byte *buf, size_t size)
-{
- if (_numInByteBufs == kNumBufLevelsMax)
- ThrowIncorrect();
- _inByteBack = &_inByteVector[_numInByteBufs++];
- _inByteBack->Init(buf, size);
-}
-
-
-Byte CInByte2::ReadByte()
-{
- if (_pos >= _size)
- ThrowEndOfData();
- return _buffer[_pos++];
-}
-
-void CInByte2::ReadBytes(Byte *data, size_t size)
-{
- if (size == 0)
- return;
- if (size > _size - _pos)
- ThrowEndOfData();
- memcpy(data, _buffer + _pos, size);
- _pos += size;
-}
-
-void CInByte2::SkipData(UInt64 size)
-{
- if (size > _size - _pos)
- ThrowEndOfData();
- _pos += (size_t)size;
-}
-
-void CInByte2::SkipData()
-{
- SkipData(ReadNumber());
-}
-
-static UInt64 ReadNumberSpec(const Byte *p, size_t size, size_t &processed)
-{
- if (size == 0)
- {
- processed = 0;
- return 0;
- }
-
- unsigned b = *p++;
- size--;
-
- if ((b & 0x80) == 0)
- {
- processed = 1;
- return b;
- }
-
- if (size == 0)
- {
- processed = 0;
- return 0;
- }
-
- UInt64 value = (UInt64)*p;
- p++;
- size--;
-
- for (unsigned i = 1; i < 8; i++)
- {
- unsigned mask = (unsigned)0x80 >> i;
- if ((b & mask) == 0)
- {
- UInt64 high = b & (mask - 1);
- value |= (high << (i * 8));
- processed = i + 1;
- return value;
- }
-
- if (size == 0)
- {
- processed = 0;
- return 0;
- }
-
- value |= ((UInt64)*p << (i * 8));
- p++;
- size--;
- }
-
- processed = 9;
- return value;
-}
-
-UInt64 CInByte2::ReadNumber()
-{
- size_t processed;
- UInt64 res = ReadNumberSpec(_buffer + _pos, _size - _pos, processed);
- if (processed == 0)
- ThrowEndOfData();
- _pos += processed;
- return res;
-}
-
-CNum CInByte2::ReadNum()
-{
- /*
- if (_pos < _size)
- {
- Byte val = _buffer[_pos];
- if ((unsigned)val < 0x80)
- {
- _pos++;
- return (unsigned)val;
- }
- }
- */
- 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;
-}
-
-#define CHECK_SIGNATURE if (p[0] != '7' || p[1] != 'z' || p[2] != 0xBC || p[3] != 0xAF || p[4] != 0x27 || p[5] != 0x1C) return false;
-
-static inline bool TestSignature(const Byte *p)
-{
- CHECK_SIGNATURE
- return CrcCalc(p + 12, 20) == Get32(p + 8);
-}
-
-#ifdef FORMAT_7Z_RECOVERY
-static inline bool TestSignature2(const Byte *p)
-{
- CHECK_SIGNATURE;
- if (CrcCalc(p + 12, 20) == Get32(p + 8))
- return true;
- for (unsigned 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;
- if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0)
- return S_FALSE;
-
- const UInt32 kBufSize = 1 << 15;
- CByteArr buf(kBufSize);
- memcpy(buf, _header, kHeaderSize);
- UInt64 offset = 0;
-
- for (;;)
- {
- UInt32 readSize = kBufSize - kHeaderSize;
- if (searchHeaderSizeLimit)
- {
- UInt64 rem = *searchHeaderSizeLimit - offset;
- if (readSize > rem)
- readSize = (UInt32)rem;
- if (readSize == 0)
- return S_FALSE;
- }
-
- UInt32 processed = 0;
- RINOK(stream->Read(buf + kHeaderSize, readSize, &processed));
- if (processed == 0)
- return S_FALSE;
-
- for (UInt32 pos = 0;;)
- {
- const Byte *p = buf + pos + 1;
- const Byte *lim = buf + processed;
- for (; p <= lim; p += 4)
- {
- if (p[0] == '7') break;
- if (p[1] == '7') { p += 1; break; }
- if (p[2] == '7') { p += 2; break; }
- if (p[3] == '7') { p += 3; break; }
- };
- if (p > lim)
- break;
- pos = (UInt32)(p - buf);
- if (TestSignature(p))
- {
- memcpy(_header, p, kHeaderSize);
- _arhiveBeginStreamPosition += offset + pos;
- return stream->Seek(_arhiveBeginStreamPosition + kHeaderSize, STREAM_SEEK_SET, NULL);
- }
- }
-
- offset += processed;
- memmove(buf, buf + processed, kHeaderSize);
- }
-}
-
-// 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(stream->Seek(0, STREAM_SEEK_END, &_fileEndPosition))
- RINOK(stream->Seek(_arhiveBeginStreamPosition, STREAM_SEEK_SET, NULL))
- RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit));
- _stream = stream;
- return S_OK;
-}
-
-void CInArchive::Close()
-{
- _numInByteBufs = 0;
- _stream.Release();
- ThereIsHeaderError = false;
-}
-
-void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */)
-{
- for (;;)
- {
- if (ReadID() == NID::kEnd)
- break;
- SkipData();
- }
-}
-
-// CFolder &folder can be non empty. So we must set all fields
-
-void CInByte2::ParseFolder(CFolder &folder)
-{
- UInt32 numCoders = ReadNum();
-
- if (numCoders == 0)
- ThrowUnsupported();
-
- folder.Coders.SetSize(numCoders);
-
- UInt32 numInStreams = 0;
- UInt32 i;
- for (i = 0; i < numCoders; i++)
- {
- CCoderInfo &coder = folder.Coders[i];
- {
- Byte mainByte = ReadByte();
- if ((mainByte & 0xC0) != 0)
- ThrowUnsupported();
- unsigned idSize = (mainByte & 0xF);
- if (idSize > 8 || idSize > GetRem())
- ThrowUnsupported();
- const Byte *longID = GetPtr();
- UInt64 id = 0;
- for (unsigned j = 0; j < idSize; j++)
- id = ((id << 8) | longID[j]);
- SkipDataNoCheck(idSize);
- coder.MethodID = id;
-
- if ((mainByte & 0x10) != 0)
- {
- coder.NumStreams = ReadNum();
- /* numOutStreams = */ ReadNum();
- }
- else
- {
- coder.NumStreams = 1;
- }
-
- if ((mainByte & 0x20) != 0)
- {
- CNum propsSize = ReadNum();
- coder.Props.Alloc((size_t)propsSize);
- ReadBytes((Byte *)coder.Props, (size_t)propsSize);
- }
- else
- coder.Props.Free();
- }
- numInStreams += coder.NumStreams;
- }
-
- UInt32 numBonds = numCoders - 1;
- folder.Bonds.SetSize(numBonds);
- for (i = 0; i < numBonds; i++)
- {
- CBond &bp = folder.Bonds[i];
- bp.PackIndex = ReadNum();
- bp.UnpackIndex = ReadNum();
- }
-
- if (numInStreams < numBonds)
- ThrowUnsupported();
- UInt32 numPackStreams = numInStreams - numBonds;
- folder.PackStreams.SetSize(numPackStreams);
-
- if (numPackStreams == 1)
- {
- for (i = 0; i < numInStreams; i++)
- if (folder.FindBond_for_PackStream(i) < 0)
- {
- folder.PackStreams[0] = i;
- break;
- }
- if (i == numInStreams)
- ThrowUnsupported();
- }
- else
- for (i = 0; i < numPackStreams; i++)
- folder.PackStreams[i] = ReadNum();
-}
-
-void CFolders::ParseFolderInfo(unsigned folderIndex, CFolder &folder) const
-{
- size_t startPos = FoCodersDataOffset[folderIndex];
- CInByte2 inByte;
- inByte.Init(CodersData + startPos, FoCodersDataOffset[folderIndex + 1] - startPos);
- inByte.ParseFolder(folder);
- if (inByte.GetRem() != 0)
- throw 20120424;
-}
-
-
-void CDatabase::GetPath(unsigned index, UString &path) const
-{
- path.Empty();
- if (!NameOffsets || !NamesBuf)
- return;
-
- size_t offset = NameOffsets[index];
- size_t size = NameOffsets[index + 1] - offset;
-
- if (size >= (1 << 28))
- return;
-
- wchar_t *s = path.GetBuf((unsigned)size - 1);
-
- const Byte *p = ((const Byte *)NamesBuf + offset * 2);
-
- #if defined(_WIN32) && defined(MY_CPU_LE)
-
- wmemcpy(s, (const wchar_t *)p, size);
-
- #else
-
- for (size_t i = 0; i < size; i++)
- {
- *s = Get16(p);
- p += 2;
- s++;
- }
-
- #endif
-
- path.ReleaseBuf_SetLen((unsigned)size - 1);
-}
-
-HRESULT CDatabase::GetPath_Prop(unsigned index, PROPVARIANT *path) const throw()
-{
- PropVariant_Clear(path);
- if (!NameOffsets || !NamesBuf)
- return S_OK;
-
- size_t offset = NameOffsets[index];
- size_t size = NameOffsets[index + 1] - offset;
-
- if (size >= (1 << 14))
- return S_OK;
-
- RINOK(PropVarEm_Alloc_Bstr(path, (unsigned)size - 1));
- wchar_t *s = path->bstrVal;
-
- const Byte *p = ((const Byte *)NamesBuf + offset * 2);
-
- for (size_t i = 0; i < size; i++)
- {
- wchar_t c = Get16(p);
- p += 2;
- #if WCHAR_PATH_SEPARATOR != L'/'
- if (c == L'/')
- c = WCHAR_PATH_SEPARATOR;
- #endif
- *s++ = c;
- }
-
- return S_OK;
-
- /*
- unsigned cur = index;
- unsigned size = 0;
-
- for (int i = 0;; i++)
- {
- size_t len = NameOffsets[cur + 1] - NameOffsets[cur];
- size += (unsigned)len;
- if (i > 256 || len > (1 << 14) || size > (1 << 14))
- return PropVarEm_Set_Str(path, "[TOO-LONG]");
- cur = Files[cur].Parent;
- if (cur < 0)
- break;
- }
- size--;
-
- RINOK(PropVarEm_Alloc_Bstr(path, size));
- wchar_t *s = path->bstrVal;
- s += size;
- *s = 0;
- cur = index;
-
- for (;;)
- {
- unsigned len = (unsigned)(NameOffsets[cur + 1] - NameOffsets[cur] - 1);
- const Byte *p = (const Byte *)NamesBuf + (NameOffsets[cur + 1] * 2) - 2;
- for (; len != 0; len--)
- {
- p -= 2;
- --s;
- wchar_t c = Get16(p);
- if (c == '/')
- c = WCHAR_PATH_SEPARATOR;
- *s = c;
- }
-
- const CFileItem &file = Files[cur];
- cur = file.Parent;
- if (cur < 0)
- return S_OK;
- *(--s) = (file.IsAltStream ? ':' : WCHAR_PATH_SEPARATOR);
- }
- */
-}
-
-void CInArchive::WaitId(UInt64 id)
-{
- for (;;)
- {
- UInt64 type = ReadID();
- if (type == id)
- return;
- if (type == NID::kEnd)
- ThrowIncorrect();
- SkipData();
- }
-}
-
-
-void CInArchive::Read_UInt32_Vector(CUInt32DefVector &v)
-{
- unsigned numItems = v.Defs.Size();
- v.Vals.ClearAndSetSize(numItems);
- UInt32 *p = &v.Vals[0];
- const bool *defs = &v.Defs[0];
- for (unsigned i = 0; i < numItems; i++)
- {
- UInt32 a = 0;
- if (defs[i])
- a = ReadUInt32();
- p[i] = a;
- }
-}
-
-
-void CInArchive::ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs)
-{
- ReadBoolVector2(numItems, crcs.Defs);
- Read_UInt32_Vector(crcs);
-}
-
-
-#define k_Scan_NumCoders_MAX 64
-#define k_Scan_NumCodersStreams_in_Folder_MAX 64
-
-void CInArchive::ReadPackInfo(CFolders &f)
-{
- CNum numPackStreams = ReadNum();
-
- WaitId(NID::kSize);
- f.PackPositions.Alloc(numPackStreams + 1);
- f.NumPackStreams = numPackStreams;
- UInt64 sum = 0;
- for (CNum i = 0; i < numPackStreams; i++)
- {
- f.PackPositions[i] = sum;
- UInt64 packSize = ReadNumber();
- sum += packSize;
- if (sum < packSize)
- ThrowIncorrect();
- }
- f.PackPositions[numPackStreams] = sum;
-
- UInt64 type;
- for (;;)
- {
- type = ReadID();
- if (type == NID::kEnd)
- return;
- if (type == NID::kCRC)
- {
- CUInt32DefVector PackCRCs;
- ReadHashDigests(numPackStreams, PackCRCs);
- continue;
- }
- SkipData();
- }
-}
-
-void CInArchive::ReadUnpackInfo(
- const CObjectVector<CByteBuffer> *dataVector,
- CFolders &folders)
-{
- WaitId(NID::kFolder);
- CNum numFolders = ReadNum();
-
- CNum numCodersOutStreams = 0;
- {
- CStreamSwitch streamSwitch;
- streamSwitch.Set(this, dataVector);
- const Byte *startBufPtr = _inByteBack->GetPtr();
- folders.NumFolders = numFolders;
-
- folders.FoStartPackStreamIndex.Alloc(numFolders + 1);
- folders.FoToMainUnpackSizeIndex.Alloc(numFolders);
- folders.FoCodersDataOffset.Alloc(numFolders + 1);
- folders.FoToCoderUnpackSizes.Alloc(numFolders + 1);
-
- CBoolVector StreamUsed;
- CBoolVector CoderUsed;
-
- CNum packStreamIndex = 0;
- CNum fo;
- CInByte2 *inByte = _inByteBack;
-
- for (fo = 0; fo < numFolders; fo++)
- {
- UInt32 indexOfMainStream = 0;
- UInt32 numPackStreams = 0;
- folders.FoCodersDataOffset[fo] = _inByteBack->GetPtr() - startBufPtr;
-
- CNum numInStreams = 0;
- CNum numCoders = inByte->ReadNum();
-
- if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX)
- ThrowUnsupported();
-
- for (CNum ci = 0; ci < numCoders; ci++)
- {
- Byte mainByte = inByte->ReadByte();
- if ((mainByte & 0xC0) != 0)
- ThrowUnsupported();
-
- unsigned idSize = (mainByte & 0xF);
- if (idSize > 8)
- ThrowUnsupported();
- if (idSize > inByte->GetRem())
- ThrowEndOfData();
- const Byte *longID = inByte->GetPtr();
- UInt64 id = 0;
- for (unsigned j = 0; j < idSize; j++)
- id = ((id << 8) | longID[j]);
- inByte->SkipDataNoCheck(idSize);
- if (folders.ParsedMethods.IDs.Size() < 128)
- folders.ParsedMethods.IDs.AddToUniqueSorted(id);
-
- CNum coderInStreams = 1;
- if ((mainByte & 0x10) != 0)
- {
- coderInStreams = inByte->ReadNum();
- if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX)
- ThrowUnsupported();
- if (inByte->ReadNum() != 1)
- ThrowUnsupported();
- }
-
- numInStreams += coderInStreams;
- if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX)
- ThrowUnsupported();
-
- if ((mainByte & 0x20) != 0)
- {
- CNum propsSize = inByte->ReadNum();
- if (propsSize > inByte->GetRem())
- ThrowEndOfData();
- if (id == k_LZMA2 && propsSize == 1)
- {
- Byte v = *_inByteBack->GetPtr();
- if (folders.ParsedMethods.Lzma2Prop < v)
- folders.ParsedMethods.Lzma2Prop = v;
- }
- else if (id == k_LZMA && propsSize == 5)
- {
- UInt32 dicSize = GetUi32(_inByteBack->GetPtr() + 1);
- if (folders.ParsedMethods.LzmaDic < dicSize)
- folders.ParsedMethods.LzmaDic = dicSize;
- }
- inByte->SkipDataNoCheck((size_t)propsSize);
- }
- }
-
- if (numCoders == 1 && numInStreams == 1)
- {
- indexOfMainStream = 0;
- numPackStreams = 1;
- }
- else
- {
- UInt32 i;
- CNum numBonds = numCoders - 1;
- if (numInStreams < numBonds)
- ThrowUnsupported();
-
- BoolVector_Fill_False(StreamUsed, numInStreams);
- BoolVector_Fill_False(CoderUsed, numCoders);
-
- for (i = 0; i < numBonds; i++)
- {
- CNum index = ReadNum();
- if (index >= numInStreams || StreamUsed[index])
- ThrowUnsupported();
- StreamUsed[index] = true;
-
- index = ReadNum();
- if (index >= numCoders || CoderUsed[index])
- ThrowUnsupported();
- CoderUsed[index] = true;
- }
-
- numPackStreams = numInStreams - numBonds;
-
- if (numPackStreams != 1)
- for (i = 0; i < numPackStreams; i++)
- {
- CNum index = inByte->ReadNum(); // PackStreams
- if (index >= numInStreams || StreamUsed[index])
- ThrowUnsupported();
- StreamUsed[index] = true;
- }
-
- for (i = 0; i < numCoders; i++)
- if (!CoderUsed[i])
- {
- indexOfMainStream = i;
- break;
- }
-
- if (i == numCoders)
- ThrowUnsupported();
- }
-
- folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams;
- numCodersOutStreams += numCoders;
- folders.FoStartPackStreamIndex[fo] = packStreamIndex;
- if (numPackStreams > folders.NumPackStreams - packStreamIndex)
- ThrowIncorrect();
- packStreamIndex += numPackStreams;
- folders.FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream;
- }
-
- size_t dataSize = _inByteBack->GetPtr() - startBufPtr;
- folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams;
- folders.FoStartPackStreamIndex[fo] = packStreamIndex;
- folders.FoCodersDataOffset[fo] = _inByteBack->GetPtr() - startBufPtr;
- folders.CodersData.CopyFrom(startBufPtr, dataSize);
-
- // if (folders.NumPackStreams != packStreamIndex) ThrowUnsupported();
- }
-
- WaitId(NID::kCodersUnpackSize);
- folders.CoderUnpackSizes.Alloc(numCodersOutStreams);
- for (CNum i = 0; i < numCodersOutStreams; i++)
- folders.CoderUnpackSizes[i] = ReadNumber();
-
- for (;;)
- {
- UInt64 type = ReadID();
- if (type == NID::kEnd)
- return;
- if (type == NID::kCRC)
- {
- ReadHashDigests(numFolders, folders.FolderCRCs);
- continue;
- }
- SkipData();
- }
-}
-
-void CInArchive::ReadSubStreamsInfo(
- CFolders &folders,
- CRecordVector<UInt64> &unpackSizes,
- CUInt32DefVector &digests)
-{
- folders.NumUnpackStreamsVector.Alloc(folders.NumFolders);
- CNum i;
- for (i = 0; i < folders.NumFolders; i++)
- folders.NumUnpackStreamsVector[i] = 1;
-
- UInt64 type;
-
- for (;;)
- {
- type = ReadID();
- if (type == NID::kNumUnpackStream)
- {
- for (i = 0; i < folders.NumFolders; i++)
- folders.NumUnpackStreamsVector[i] = ReadNum();
- continue;
- }
- if (type == NID::kCRC || type == NID::kSize || type == NID::kEnd)
- break;
- SkipData();
- }
-
- if (type == NID::kSize)
- {
- for (i = 0; i < folders.NumFolders; i++)
- {
- // v3.13 incorrectly worked with empty folders
- // v4.07: we check that folder is empty
- CNum numSubstreams = folders.NumUnpackStreamsVector[i];
- if (numSubstreams == 0)
- continue;
- UInt64 sum = 0;
- for (CNum j = 1; j < numSubstreams; j++)
- {
- UInt64 size = ReadNumber();
- unpackSizes.Add(size);
- sum += size;
- if (sum < size)
- ThrowIncorrect();
- }
- UInt64 folderUnpackSize = folders.GetFolderUnpackSize(i);
- if (folderUnpackSize < sum)
- ThrowIncorrect();
- unpackSizes.Add(folderUnpackSize - sum);
- }
- type = ReadID();
- }
- else
- {
- for (i = 0; i < folders.NumFolders; i++)
- {
- /* v9.26 - v9.29 incorrectly worked:
- if (folders.NumUnpackStreamsVector[i] == 0), it threw error */
- CNum val = folders.NumUnpackStreamsVector[i];
- if (val > 1)
- ThrowIncorrect();
- if (val == 1)
- unpackSizes.Add(folders.GetFolderUnpackSize(i));
- }
- }
-
- unsigned numDigests = 0;
- for (i = 0; i < folders.NumFolders; i++)
- {
- CNum numSubstreams = folders.NumUnpackStreamsVector[i];
- if (numSubstreams != 1 || !folders.FolderCRCs.ValidAndDefined(i))
- numDigests += numSubstreams;
- }
-
- for (;;)
- {
- if (type == NID::kEnd)
- break;
- if (type == NID::kCRC)
- {
- // CUInt32DefVector digests2;
- // ReadHashDigests(numDigests, digests2);
- CBoolVector digests2;
- ReadBoolVector2(numDigests, digests2);
-
- digests.ClearAndSetSize(unpackSizes.Size());
-
- unsigned k = 0;
- unsigned k2 = 0;
-
- for (i = 0; i < folders.NumFolders; i++)
- {
- CNum numSubstreams = folders.NumUnpackStreamsVector[i];
- if (numSubstreams == 1 && folders.FolderCRCs.ValidAndDefined(i))
- {
- digests.Defs[k] = true;
- digests.Vals[k] = folders.FolderCRCs.Vals[i];
- k++;
- }
- else for (CNum j = 0; j < numSubstreams; j++)
- {
- bool defined = digests2[k2++];
- digests.Defs[k] = defined;
- UInt32 crc = 0;
- if (defined)
- crc = ReadUInt32();
- digests.Vals[k] = crc;
- k++;
- }
- }
- // if (k != unpackSizes.Size()) throw 1234567;
- }
- else
- SkipData();
-
- type = ReadID();
- }
-
- if (digests.Defs.Size() != unpackSizes.Size())
- {
- digests.ClearAndSetSize(unpackSizes.Size());
- unsigned k = 0;
- for (i = 0; i < folders.NumFolders; i++)
- {
- CNum numSubstreams = folders.NumUnpackStreamsVector[i];
- if (numSubstreams == 1 && folders.FolderCRCs.ValidAndDefined(i))
- {
- digests.Defs[k] = true;
- digests.Vals[k] = folders.FolderCRCs.Vals[i];
- k++;
- }
- else for (CNum j = 0; j < numSubstreams; j++)
- {
- digests.Defs[k] = false;
- digests.Vals[k] = 0;
- k++;
- }
- }
- }
-}
-
-void CInArchive::ReadStreamsInfo(
- const CObjectVector<CByteBuffer> *dataVector,
- UInt64 &dataOffset,
- CFolders &folders,
- CRecordVector<UInt64> &unpackSizes,
- CUInt32DefVector &digests)
-{
- UInt64 type = ReadID();
-
- if (type == NID::kPackInfo)
- {
- dataOffset = ReadNumber();
- ReadPackInfo(folders);
- type = ReadID();
- }
-
- if (type == NID::kUnpackInfo)
- {
- ReadUnpackInfo(dataVector, folders);
- type = ReadID();
- }
-
- if (folders.NumFolders != 0 && !folders.PackPositions)
- {
- // if there are folders, we need PackPositions also
- folders.PackPositions.Alloc(1);
- folders.PackPositions[0] = 0;
- }
-
- if (type == NID::kSubStreamsInfo)
- {
- ReadSubStreamsInfo(folders, unpackSizes, digests);
- type = ReadID();
- }
- else
- {
- folders.NumUnpackStreamsVector.Alloc(folders.NumFolders);
- /* If digests.Defs.Size() == 0, it means that there are no crcs.
- So we don't need to fill digests with values. */
- // digests.Vals.ClearAndSetSize(folders.NumFolders);
- // BoolVector_Fill_False(digests.Defs, folders.NumFolders);
- for (CNum i = 0; i < folders.NumFolders; i++)
- {
- folders.NumUnpackStreamsVector[i] = 1;
- unpackSizes.Add(folders.GetFolderUnpackSize(i));
- // digests.Vals[i] = 0;
- }
- }
-
- if (type != NID::kEnd)
- ThrowIncorrect();
-}
-
-void CInArchive::ReadBoolVector(unsigned numItems, CBoolVector &v)
-{
- v.ClearAndSetSize(numItems);
- Byte b = 0;
- Byte mask = 0;
- bool *p = &v[0];
- for (unsigned i = 0; i < numItems; i++)
- {
- if (mask == 0)
- {
- b = ReadByte();
- mask = 0x80;
- }
- p[i] = ((b & mask) != 0);
- mask >>= 1;
- }
-}
-
-void CInArchive::ReadBoolVector2(unsigned numItems, CBoolVector &v)
-{
- Byte allAreDefined = ReadByte();
- if (allAreDefined == 0)
- {
- ReadBoolVector(numItems, v);
- return;
- }
- v.ClearAndSetSize(numItems);
- bool *p = &v[0];
- for (unsigned i = 0; i < numItems; i++)
- p[i] = true;
-}
-
-void CInArchive::ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector,
- CUInt64DefVector &v, unsigned numItems)
-{
- ReadBoolVector2(numItems, v.Defs);
-
- CStreamSwitch streamSwitch;
- streamSwitch.Set(this, &dataVector);
-
- v.Vals.ClearAndSetSize(numItems);
- UInt64 *p = &v.Vals[0];
- const bool *defs = &v.Defs[0];
-
- for (unsigned i = 0; i < numItems; i++)
- {
- UInt64 t = 0;
- if (defs[i])
- t = ReadUInt64();
- p[i] = t;
- }
-}
-
-HRESULT CInArchive::ReadAndDecodePackedStreams(
- DECL_EXTERNAL_CODECS_LOC_VARS
- UInt64 baseOffset,
- UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector
- _7Z_DECODER_CRYPRO_VARS_DECL
- )
-{
- CFolders folders;
- CRecordVector<UInt64> unpackSizes;
- CUInt32DefVector digests;
-
- ReadStreamsInfo(NULL,
- dataOffset,
- folders,
- unpackSizes,
- digests);
-
- CDecoder decoder(_useMixerMT);
-
- for (CNum i = 0; i < folders.NumFolders; i++)
- {
- CByteBuffer &data = dataVector.AddNew();
- UInt64 unpackSize64 = folders.GetFolderUnpackSize(i);
- size_t unpackSize = (size_t)unpackSize64;
- if (unpackSize != unpackSize64)
- ThrowUnsupported();
- data.Alloc(unpackSize);
-
- CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;
- CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
- outStreamSpec->Init(data, unpackSize);
-
- bool dataAfterEnd_Error = false;
-
- HRESULT result = decoder.Decode(
- EXTERNAL_CODECS_LOC_VARS
- _stream, baseOffset + dataOffset,
- folders, i,
- NULL, // *unpackSize
-
- outStream,
- NULL, // *compressProgress
-
- NULL // **inStreamMainRes
- , dataAfterEnd_Error
-
- _7Z_DECODER_CRYPRO_VARS
- #if !defined(_7ZIP_ST)
- , false // mtMode
- , 1 // numThreads
- , 0 // memUsage
- #endif
- );
-
- RINOK(result);
-
- if (dataAfterEnd_Error)
- ThereIsHeaderError = true;
-
- if (folders.FolderCRCs.ValidAndDefined(i))
- if (CrcCalc(data, unpackSize) != folders.FolderCRCs.Vals[i])
- ThrowIncorrect();
- }
-
- if (folders.PackPositions)
- HeadersSize += folders.PackPositions[folders.NumPackStreams];
-
- return S_OK;
-}
-
-HRESULT CInArchive::ReadHeader(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CDbEx &db
- _7Z_DECODER_CRYPRO_VARS_DECL
- )
-{
- UInt64 type = ReadID();
-
- if (type == NID::kArchiveProperties)
- {
- ReadArchiveProperties(db.ArcInfo);
- type = ReadID();
- }
-
- CObjectVector<CByteBuffer> dataVector;
-
- if (type == NID::kAdditionalStreamsInfo)
- {
- HRESULT result = ReadAndDecodePackedStreams(
- EXTERNAL_CODECS_LOC_VARS
- db.ArcInfo.StartPositionAfterHeader,
- db.ArcInfo.DataStartPosition2,
- dataVector
- _7Z_DECODER_CRYPRO_VARS
- );
- RINOK(result);
- db.ArcInfo.DataStartPosition2 += db.ArcInfo.StartPositionAfterHeader;
- type = ReadID();
- }
-
- CRecordVector<UInt64> unpackSizes;
- CUInt32DefVector digests;
-
- if (type == NID::kMainStreamsInfo)
- {
- ReadStreamsInfo(&dataVector,
- db.ArcInfo.DataStartPosition,
- (CFolders &)db,
- unpackSizes,
- digests);
- db.ArcInfo.DataStartPosition += db.ArcInfo.StartPositionAfterHeader;
- type = ReadID();
- }
-
- if (type == NID::kFilesInfo)
- {
-
- const CNum numFiles = ReadNum();
-
- db.ArcInfo.FileInfoPopIDs.Add(NID::kSize);
- // if (!db.PackSizes.IsEmpty())
- db.ArcInfo.FileInfoPopIDs.Add(NID::kPackInfo);
- if (numFiles > 0 && !digests.Defs.IsEmpty())
- db.ArcInfo.FileInfoPopIDs.Add(NID::kCRC);
-
- CBoolVector emptyStreamVector;
- CBoolVector emptyFileVector;
- CBoolVector antiFileVector;
- CNum numEmptyStreams = 0;
-
- for (;;)
- {
- const UInt64 type2 = ReadID();
- if (type2 == NID::kEnd)
- break;
- UInt64 size = ReadNumber();
- if (size > _inByteBack->GetRem())
- ThrowIncorrect();
- CStreamSwitch switchProp;
- switchProp.Set(this, _inByteBack->GetPtr(), (size_t)size, true);
- bool addPropIdToList = true;
- bool isKnownType = true;
- if (type2 > ((UInt32)1 << 30))
- isKnownType = false;
- else switch ((UInt32)type2)
- {
- case NID::kName:
- {
- CStreamSwitch streamSwitch;
- streamSwitch.Set(this, &dataVector);
- size_t rem = _inByteBack->GetRem();
- db.NamesBuf.Alloc(rem);
- ReadBytes(db.NamesBuf, rem);
- db.NameOffsets.Alloc(numFiles + 1);
- size_t pos = 0;
- unsigned i;
- for (i = 0; i < numFiles; i++)
- {
- size_t curRem = (rem - pos) / 2;
- const UInt16 *buf = (const UInt16 *)(db.NamesBuf + pos);
- size_t j;
- for (j = 0; j < curRem && buf[j] != 0; j++);
- if (j == curRem)
- ThrowEndOfData();
- db.NameOffsets[i] = pos / 2;
- pos += j * 2 + 2;
- }
- db.NameOffsets[i] = pos / 2;
- if (pos != rem)
- ThereIsHeaderError = true;
- break;
- }
-
- case NID::kWinAttrib:
- {
- ReadBoolVector2(numFiles, db.Attrib.Defs);
- CStreamSwitch streamSwitch;
- streamSwitch.Set(this, &dataVector);
- Read_UInt32_Vector(db.Attrib);
- break;
- }
-
- /*
- case NID::kIsAux:
- {
- ReadBoolVector(numFiles, db.IsAux);
- break;
- }
- case NID::kParent:
- {
- db.IsTree = true;
- // CBoolVector boolVector;
- // ReadBoolVector2(numFiles, boolVector);
- // CStreamSwitch streamSwitch;
- // streamSwitch.Set(this, &dataVector);
- CBoolVector boolVector;
- ReadBoolVector2(numFiles, boolVector);
-
- db.ThereAreAltStreams = false;
- for (i = 0; i < numFiles; i++)
- {
- CFileItem &file = db.Files[i];
- // file.Parent = -1;
- // if (boolVector[i])
- file.Parent = (int)ReadUInt32();
- file.IsAltStream = !boolVector[i];
- if (file.IsAltStream)
- db.ThereAreAltStreams = true;
- }
- break;
- }
- */
- case NID::kEmptyStream:
- {
- ReadBoolVector(numFiles, emptyStreamVector);
- numEmptyStreams = BoolVector_CountSum(emptyStreamVector);
- emptyFileVector.Clear();
- antiFileVector.Clear();
- break;
- }
- case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); break;
- case NID::kAnti: ReadBoolVector(numEmptyStreams, antiFileVector); break;
- case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (unsigned)numFiles); break;
- case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (unsigned)numFiles); break;
- case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (unsigned)numFiles); break;
- case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (unsigned)numFiles); break;
- case NID::kDummy:
- {
- for (UInt64 j = 0; j < size; j++)
- if (ReadByte() != 0)
- ThereIsHeaderError = true;
- addPropIdToList = false;
- break;
- }
- /*
- case NID::kNtSecure:
- {
- try
- {
- {
- CStreamSwitch streamSwitch;
- streamSwitch.Set(this, &dataVector);
- UInt32 numDescriptors = ReadUInt32();
- size_t offset = 0;
- db.SecureOffsets.Clear();
- for (i = 0; i < numDescriptors; i++)
- {
- UInt32 size = ReadUInt32();
- db.SecureOffsets.Add(offset);
- offset += size;
- }
- // ThrowIncorrect();;
- db.SecureOffsets.Add(offset);
- db.SecureBuf.SetCapacity(offset);
- for (i = 0; i < numDescriptors; i++)
- {
- offset = db.SecureOffsets[i];
- ReadBytes(db.SecureBuf + offset, db.SecureOffsets[i + 1] - offset);
- }
- db.SecureIDs.Clear();
- for (unsigned i = 0; i < numFiles; i++)
- {
- db.SecureIDs.Add(ReadNum());
- // db.SecureIDs.Add(ReadUInt32());
- }
- // ReadUInt32();
- if (_inByteBack->GetRem() != 0)
- ThrowIncorrect();;
- }
- }
- catch(CInArchiveException &)
- {
- ThereIsHeaderError = true;
- addPropIdToList = isKnownType = false;
- db.ClearSecure();
- }
- break;
- }
- */
- default:
- addPropIdToList = isKnownType = false;
- }
- if (isKnownType)
- {
- if (addPropIdToList)
- db.ArcInfo.FileInfoPopIDs.Add(type2);
- }
- else
- {
- db.UnsupportedFeatureWarning = true;
- _inByteBack->SkipRem();
- }
- // SkipData worked incorrectly in some versions before v4.59 (7zVer <= 0.02)
- if (_inByteBack->GetRem() != 0)
- ThrowIncorrect();
- }
-
- type = ReadID(); // Read (NID::kEnd) end of headers
-
- if (numFiles - numEmptyStreams != unpackSizes.Size())
- ThrowUnsupported();
-
- CNum emptyFileIndex = 0;
- CNum sizeIndex = 0;
-
- const CNum numAntiItems = BoolVector_CountSum(antiFileVector);
-
- if (numAntiItems != 0)
- db.IsAnti.ClearAndSetSize(numFiles);
-
- db.Files.ClearAndSetSize(numFiles);
-
- for (CNum i = 0; i < numFiles; i++)
- {
- CFileItem &file = db.Files[i];
- bool isAnti;
- file.Crc = 0;
- if (!BoolVector_Item_IsValidAndTrue(emptyStreamVector, i))
- {
- file.HasStream = true;
- file.IsDir = false;
- isAnti = false;
- file.Size = unpackSizes[sizeIndex];
- file.CrcDefined = digests.ValidAndDefined(sizeIndex);
- if (file.CrcDefined)
- file.Crc = digests.Vals[sizeIndex];
- sizeIndex++;
- }
- else
- {
- file.HasStream = false;
- file.IsDir = !BoolVector_Item_IsValidAndTrue(emptyFileVector, emptyFileIndex);
- isAnti = BoolVector_Item_IsValidAndTrue(antiFileVector, emptyFileIndex);
- emptyFileIndex++;
- file.Size = 0;
- file.CrcDefined = false;
- }
- if (numAntiItems != 0)
- db.IsAnti[i] = isAnti;
- }
-
- }
-
- db.FillLinks();
-
- if (type != NID::kEnd || _inByteBack->GetRem() != 0)
- {
- db.UnsupportedFeatureWarning = true;
- // ThrowIncorrect();
- }
-
- return S_OK;
-}
-
-
-void CDbEx::FillLinks()
-{
- FolderStartFileIndex.Alloc(NumFolders);
- FileIndexToFolderIndexMap.Alloc(Files.Size());
-
- CNum folderIndex = 0;
- CNum indexInFolder = 0;
- unsigned i;
-
- for (i = 0; i < Files.Size(); i++)
- {
- bool emptyStream = !Files[i].HasStream;
- if (indexInFolder == 0)
- {
- if (emptyStream)
- {
- FileIndexToFolderIndexMap[i] = kNumNoIndex;
- continue;
- }
- // v3.13 incorrectly worked with empty folders
- // v4.07: we skip empty folders
- for (;;)
- {
- if (folderIndex >= NumFolders)
- ThrowIncorrect();
- FolderStartFileIndex[folderIndex] = i;
- if (NumUnpackStreamsVector[folderIndex] != 0)
- break;
- folderIndex++;
- }
- }
- FileIndexToFolderIndexMap[i] = folderIndex;
- if (emptyStream)
- continue;
- if (++indexInFolder >= NumUnpackStreamsVector[folderIndex])
- {
- folderIndex++;
- indexInFolder = 0;
- }
- }
-
- if (indexInFolder != 0)
- {
- folderIndex++;
- // 18.06
- ThereIsHeaderError = true;
- // ThrowIncorrect();
- }
-
- for (;;)
- {
- if (folderIndex >= NumFolders)
- return;
- FolderStartFileIndex[folderIndex] = i;
- if (NumUnpackStreamsVector[folderIndex] != 0)
- {
- // 18.06
- ThereIsHeaderError = true;
- // ThrowIncorrect();
- }
- folderIndex++;
- }
-}
-
-
-HRESULT CInArchive::ReadDatabase2(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CDbEx &db
- _7Z_DECODER_CRYPRO_VARS_DECL
- )
-{
- db.Clear();
- db.ArcInfo.StartPosition = _arhiveBeginStreamPosition;
-
- db.ArcInfo.Version.Major = _header[6];
- db.ArcInfo.Version.Minor = _header[7];
-
- if (db.ArcInfo.Version.Major != kMajorVersion)
- {
- // db.UnsupportedVersion = true;
- return S_FALSE;
- }
-
- UInt64 nextHeaderOffset = Get64(_header + 12);
- UInt64 nextHeaderSize = Get64(_header + 20);
- UInt32 nextHeaderCRC = Get32(_header + 28);
-
- #ifdef FORMAT_7Z_RECOVERY
- UInt32 crcFromArc = Get32(_header + 8);
- if (crcFromArc == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)
- {
- UInt64 cur, fileSize;
- RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &cur));
- const unsigned kCheckSize = 512;
- Byte buf[kCheckSize];
- RINOK(_stream->Seek(0, STREAM_SEEK_END, &fileSize));
- UInt64 rem = fileSize - cur;
- unsigned checkSize = kCheckSize;
- if (rem < kCheckSize)
- checkSize = (unsigned)(rem);
- if (checkSize < 3)
- return S_FALSE;
- RINOK(_stream->Seek(fileSize - checkSize, STREAM_SEEK_SET, NULL));
- RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize));
-
- if (buf[checkSize - 1] != 0)
- return S_FALSE;
-
- unsigned i;
- for (i = checkSize - 2;; i--)
- {
- if (buf[i] == NID::kEncodedHeader && buf[i + 1] == NID::kPackInfo ||
- buf[i] == NID::kHeader && buf[i + 1] == NID::kMainStreamsInfo)
- break;
- if (i == 0)
- return S_FALSE;
- }
- nextHeaderSize = checkSize - i;
- nextHeaderOffset = rem - nextHeaderSize;
- nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize);
- RINOK(_stream->Seek(cur, STREAM_SEEK_SET, NULL));
- db.StartHeaderWasRecovered = true;
- }
- else
- #endif
- {
- // Crc was tested already at signature check
- // if (CrcCalc(_header + 12, 20) != crcFromArchive) ThrowIncorrect();
- }
-
- db.ArcInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;
- db.PhySize = kHeaderSize;
-
- db.IsArc = false;
- if ((Int64)nextHeaderOffset < 0 ||
- nextHeaderSize > ((UInt64)1 << 62))
- return S_FALSE;
- if (nextHeaderSize == 0)
- {
- if (nextHeaderOffset != 0)
- return S_FALSE;
- db.IsArc = true;
- return S_OK;
- }
-
- if (!db.StartHeaderWasRecovered)
- db.IsArc = true;
-
- HeadersSize += kHeaderSize + nextHeaderSize;
- db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize;
- if (_fileEndPosition - db.ArcInfo.StartPositionAfterHeader < nextHeaderOffset + nextHeaderSize)
- {
- db.UnexpectedEnd = true;
- return S_FALSE;
- }
- RINOK(_stream->Seek(nextHeaderOffset, STREAM_SEEK_CUR, NULL));
-
- size_t nextHeaderSize_t = (size_t)nextHeaderSize;
- if (nextHeaderSize_t != nextHeaderSize)
- return E_OUTOFMEMORY;
- CByteBuffer buffer2(nextHeaderSize_t);
-
- RINOK(ReadStream_FALSE(_stream, buffer2, nextHeaderSize_t));
-
- if (CrcCalc(buffer2, nextHeaderSize_t) != nextHeaderCRC)
- ThrowIncorrect();
-
- if (!db.StartHeaderWasRecovered)
- db.PhySizeWasConfirmed = true;
-
- 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.ArcInfo.StartPositionAfterHeader,
- db.ArcInfo.DataStartPosition2,
- dataVector
- _7Z_DECODER_CRYPRO_VARS
- );
- 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.IsArc = true;
-
- db.HeadersSize = HeadersSize;
-
- return ReadHeader(
- EXTERNAL_CODECS_LOC_VARS
- db
- _7Z_DECODER_CRYPRO_VARS
- );
-}
-
-
-HRESULT CInArchive::ReadDatabase(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CDbEx &db
- _7Z_DECODER_CRYPRO_VARS_DECL
- )
-{
- try
- {
- HRESULT res = ReadDatabase2(
- EXTERNAL_CODECS_LOC_VARS db
- _7Z_DECODER_CRYPRO_VARS
- );
- if (ThereIsHeaderError)
- db.ThereIsHeaderError = true;
- if (res == E_NOTIMPL)
- ThrowUnsupported();
- return res;
- }
- catch(CUnsupportedFeatureException &)
- {
- db.UnsupportedFeatureError = true;
- return S_FALSE;
- }
- catch(CInArchiveException &)
- {
- db.ThereIsHeaderError = true;
- return S_FALSE;
- }
-}
-
-}}
+// 7zIn.cpp
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#include <wchar.h>
+#else
+#include <ctype.h>
+#endif
+
+#include "../../../../C/7zCrc.h"
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/MyBuffer2.h"
+// #include "../../../Common/UTFConvert.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 Z7_SFX
+#define FORMAT_7Z_RECOVERY
+#endif
+
+using namespace NWindows;
+using namespace NCOM;
+
+namespace NArchive {
+namespace N7z {
+
+#define k_Scan_NumCoders_MAX 64
+#define k_Scan_NumCodersStreams_in_Folder_MAX 64
+
+unsigned BoolVector_CountSum(const CBoolVector &v);
+unsigned BoolVector_CountSum(const CBoolVector &v)
+{
+ unsigned sum = 0;
+ const unsigned size = v.Size();
+ for (unsigned i = 0; i < size; i++)
+ if (v[i])
+ sum++;
+ return sum;
+}
+
+static inline bool BoolVector_Item_IsValidAndTrue(const CBoolVector &v, unsigned i)
+{
+ return (i < v.Size() ? v[i] : false);
+}
+
+static void BoolVector_Fill_False(CBoolVector &v, unsigned size)
+{
+ v.ClearAndSetSize(size);
+ bool *p = &v[0];
+ for (unsigned i = 0; i < size; i++)
+ p[i] = false;
+}
+
+
+class CInArchiveException {};
+class CUnsupportedFeatureException: public CInArchiveException {};
+
+Z7_ATTR_NORETURN
+static void ThrowException() { throw CInArchiveException(); }
+Z7_ATTR_NORETURN
+static inline void ThrowEndOfData() { ThrowException(); }
+Z7_ATTR_NORETURN
+static inline void ThrowUnsupported() { throw CUnsupportedFeatureException(); }
+Z7_ATTR_NORETURN
+static inline void ThrowIncorrect() { ThrowException(); }
+
+class CStreamSwitch
+{
+ CInArchive *_archive;
+ bool _needRemove;
+ bool _needUpdatePos;
+public:
+ CStreamSwitch(): _needRemove(false), _needUpdatePos(false) {}
+ ~CStreamSwitch() { Remove(); }
+ void Remove();
+ void Set(CInArchive *archive, const Byte *data, size_t size, bool needUpdatePos);
+ void Set(CInArchive *archive, const CByteBuffer &byteBuffer);
+ void Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector);
+};
+
+void CStreamSwitch::Remove()
+{
+ if (_needRemove)
+ {
+ if (_archive->_inByteBack->GetRem() != 0)
+ _archive->ThereIsHeaderError = true;
+ _archive->DeleteByteStream(_needUpdatePos);
+ _needRemove = false;
+ }
+}
+
+void CStreamSwitch::Set(CInArchive *archive, const Byte *data, size_t size, bool needUpdatePos)
+{
+ Remove();
+ _archive = archive;
+ _archive->AddByteStream(data, size);
+ _needRemove = true;
+ _needUpdatePos = needUpdatePos;
+}
+
+void CStreamSwitch::Set(CInArchive *archive, const CByteBuffer &byteBuffer)
+{
+ Set(archive, byteBuffer, byteBuffer.Size(), false);
+}
+
+void CStreamSwitch::Set(CInArchive *archive, const CObjectVector<CByteBuffer> *dataVector)
+{
+ Remove();
+ const Byte external = archive->ReadByte();
+ if (external != 0)
+ {
+ if (!dataVector)
+ ThrowIncorrect();
+ const CNum dataIndex = archive->ReadNum();
+ if (dataIndex >= dataVector->Size())
+ ThrowIncorrect();
+ Set(archive, (*dataVector)[dataIndex]);
+ }
+}
+
+void CInArchive::AddByteStream(const Byte *buf, size_t size)
+{
+ if (_numInByteBufs == kNumBufLevelsMax)
+ ThrowIncorrect();
+ _inByteBack = &_inByteVector[_numInByteBufs++];
+ _inByteBack->Init(buf, size);
+}
+
+
+Byte CInByte2::ReadByte()
+{
+ if (_pos >= _size)
+ ThrowEndOfData();
+ return _buffer[_pos++];
+}
+
+void CInByte2::ReadBytes(Byte *data, size_t size)
+{
+ if (size == 0)
+ return;
+ if (size > _size - _pos)
+ ThrowEndOfData();
+ memcpy(data, _buffer + _pos, size);
+ _pos += size;
+}
+
+void CInByte2::SkipData(UInt64 size)
+{
+ if (size > _size - _pos)
+ ThrowEndOfData();
+ _pos += (size_t)size;
+}
+
+void CInByte2::SkipData()
+{
+ SkipData(ReadNumber());
+}
+
+static UInt64 ReadNumberSpec(const Byte *p, size_t size, size_t &processed)
+{
+ if (size == 0)
+ {
+ processed = 0;
+ return 0;
+ }
+
+ const unsigned b = *p++;
+ size--;
+
+ if ((b & 0x80) == 0)
+ {
+ processed = 1;
+ return b;
+ }
+
+ if (size == 0)
+ {
+ processed = 0;
+ return 0;
+ }
+
+ UInt64 value = (UInt64)*p;
+ p++;
+ size--;
+
+ for (unsigned i = 1; i < 8; i++)
+ {
+ const unsigned mask = (unsigned)0x80 >> i;
+ if ((b & mask) == 0)
+ {
+ const UInt64 high = b & (mask - 1);
+ value |= (high << (i * 8));
+ processed = i + 1;
+ return value;
+ }
+
+ if (size == 0)
+ {
+ processed = 0;
+ return 0;
+ }
+
+ value |= ((UInt64)*p << (i * 8));
+ p++;
+ size--;
+ }
+
+ processed = 9;
+ return value;
+}
+
+UInt64 CInByte2::ReadNumber()
+{
+ size_t processed;
+ const UInt64 res = ReadNumberSpec(_buffer + _pos, _size - _pos, processed);
+ if (processed == 0)
+ ThrowEndOfData();
+ _pos += processed;
+ return res;
+}
+
+CNum CInByte2::ReadNum()
+{
+ /*
+ if (_pos < _size)
+ {
+ Byte val = _buffer[_pos];
+ if ((unsigned)val < 0x80)
+ {
+ _pos++;
+ return (unsigned)val;
+ }
+ }
+ */
+ const UInt64 value = ReadNumber();
+ if (value > kNumMax)
+ ThrowUnsupported();
+ return (CNum)value;
+}
+
+UInt32 CInByte2::ReadUInt32()
+{
+ if (_pos + 4 > _size)
+ ThrowEndOfData();
+ const UInt32 res = Get32(_buffer + _pos);
+ _pos += 4;
+ return res;
+}
+
+UInt64 CInByte2::ReadUInt64()
+{
+ if (_pos + 8 > _size)
+ ThrowEndOfData();
+ const UInt64 res = Get64(_buffer + _pos);
+ _pos += 8;
+ return res;
+}
+
+#define Y0 '7'
+#define Y1 'z'
+#define Y2 0xBC
+#define Y3 0xAF
+#define Y4 0x27
+#define Y5 0x1C
+
+#define IS_SIGNATURE(p)( \
+ (p)[2] == Y2 && \
+ (p)[3] == Y3 && \
+ (p)[5] == Y5 && \
+ (p)[4] == Y4 && \
+ (p)[1] == Y1 && \
+ (p)[0] == Y0)
+
+/* FindSignature_10() is allowed to access data up to and including &limit[9].
+ limit[10] access is not allowed.
+ return:
+ (return_ptr < limit) : signature was found at (return_ptr)
+ (return_ptr >= limit) : limit was reached or crossed. So no signature found before limit
+*/
+Z7_NO_INLINE
+static const Byte *FindSignature_10(const Byte *p, const Byte *limit)
+{
+ for (;;)
+ {
+ for (;;)
+ {
+ if (p >= limit)
+ return limit;
+ const Byte b = p[5];
+ p += 6;
+ if (b == Y0) { break; }
+ if (b == Y1) { p -= 1; break; }
+ if (b == Y2) { p -= 2; break; }
+ if (b == Y3) { p -= 3; break; }
+ if (b == Y4) { p -= 4; break; }
+ if (b == Y5) { p -= 5; break; }
+ }
+ if (IS_SIGNATURE(p - 1))
+ return p - 1;
+ }
+}
+
+
+static inline bool TestStartCrc(const Byte *p)
+{
+ return CrcCalc(p + 12, 20) == Get32(p + 8);
+}
+
+static inline bool TestSignature2(const Byte *p)
+{
+ if (!IS_SIGNATURE(p))
+ return false;
+ #ifdef FORMAT_7Z_RECOVERY
+ if (TestStartCrc(p))
+ return true;
+ for (unsigned i = 8; i < kHeaderSize; i++)
+ if (p[i] != 0)
+ return false;
+ return (p[6] != 0 || p[7] != 0);
+ #else
+ return TestStartCrc(p);
+ #endif
+}
+
+
+HRESULT CInArchive::FindAndReadSignature(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+ RINOK(ReadStream_FALSE(stream, _header, kHeaderSize))
+
+ if (TestSignature2(_header))
+ return S_OK;
+ if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0)
+ return S_FALSE;
+
+ const UInt32 kBufSize = (1 << 15) + kHeaderSize; // must be > (kHeaderSize * 2)
+ CAlignedBuffer1 buf(kBufSize);
+ memcpy(buf, _header, kHeaderSize);
+ UInt64 offset = 0;
+
+ for (;;)
+ {
+ UInt32 readSize =
+ (offset == 0) ?
+ kBufSize - kHeaderSize - kHeaderSize :
+ kBufSize - kHeaderSize;
+ if (searchHeaderSizeLimit)
+ {
+ const UInt64 rem = *searchHeaderSizeLimit - offset;
+ if (readSize > rem)
+ readSize = (UInt32)rem;
+ if (readSize == 0)
+ return S_FALSE;
+ }
+
+ UInt32 processed = 0;
+ RINOK(stream->Read(buf + kHeaderSize, readSize, &processed))
+ if (processed == 0)
+ return S_FALSE;
+
+ /* &buf[0] was already tested for signature before.
+ So first search here will be for &buf[1] */
+
+ for (UInt32 pos = 0;;)
+ {
+ const Byte *p = buf + pos + 1;
+ const Byte *lim = buf + processed + 1;
+ /* we have (kHeaderSize - 1 = 31) filled bytes starting from (lim),
+ and it's safe to access just 10 bytes in that reserved area */
+ p = FindSignature_10(p, lim);
+ if (p >= lim)
+ break;
+ pos = (UInt32)(p - buf);
+ if (TestStartCrc(p))
+ {
+ memcpy(_header, p, kHeaderSize);
+ _arhiveBeginStreamPosition += offset + pos;
+ return InStream_SeekSet(stream, _arhiveBeginStreamPosition + kHeaderSize);
+ }
+ }
+
+ offset += processed;
+ memmove(buf, buf + processed, kHeaderSize);
+ }
+}
+
+// S_FALSE means that file is not archive
+HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+ HeadersSize = 0;
+ Close();
+ RINOK(InStream_GetPos_GetSize(stream, _arhiveBeginStreamPosition, _fileEndPosition))
+ RINOK(FindAndReadSignature(stream, searchHeaderSizeLimit))
+ _stream = stream;
+ return S_OK;
+}
+
+void CInArchive::Close()
+{
+ _numInByteBufs = 0;
+ _stream.Release();
+ ThereIsHeaderError = false;
+}
+
+void CInArchive::ReadArchiveProperties(CInArchiveInfo & /* archiveInfo */)
+{
+ for (;;)
+ {
+ if (ReadID() == NID::kEnd)
+ break;
+ SkipData();
+ }
+}
+
+// CFolder &folder can be non empty. So we must set all fields
+
+void CInByte2::ParseFolder(CFolder &folder)
+{
+ const UInt32 numCoders = ReadNum();
+
+ if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX)
+ ThrowUnsupported();
+
+ folder.Coders.SetSize(numCoders);
+
+ UInt32 numInStreams = 0;
+ UInt32 i;
+ for (i = 0; i < numCoders; i++)
+ {
+ CCoderInfo &coder = folder.Coders[i];
+ {
+ const Byte mainByte = ReadByte();
+ if ((mainByte & 0xC0) != 0)
+ ThrowUnsupported();
+ const unsigned idSize = (mainByte & 0xF);
+ if (idSize > 8 || idSize > GetRem())
+ ThrowUnsupported();
+ const Byte *longID = GetPtr();
+ UInt64 id = 0;
+ for (unsigned j = 0; j < idSize; j++)
+ id = ((id << 8) | longID[j]);
+ SkipDataNoCheck(idSize);
+ coder.MethodID = id;
+
+ if ((mainByte & 0x10) != 0)
+ {
+ coder.NumStreams = ReadNum();
+ // if (coder.NumStreams > k_Scan_NumCodersStreams_in_Folder_MAX) ThrowUnsupported();
+ /* numOutStreams = */ ReadNum();
+ // if (ReadNum() != 1) // numOutStreams ThrowUnsupported();
+ }
+ else
+ {
+ coder.NumStreams = 1;
+ }
+
+ if ((mainByte & 0x20) != 0)
+ {
+ const CNum propsSize = ReadNum();
+ coder.Props.Alloc((size_t)propsSize);
+ ReadBytes((Byte *)coder.Props, (size_t)propsSize);
+ }
+ else
+ coder.Props.Free();
+ }
+ numInStreams += coder.NumStreams;
+ }
+
+ const UInt32 numBonds = numCoders - 1;
+ folder.Bonds.SetSize(numBonds);
+ for (i = 0; i < numBonds; i++)
+ {
+ CBond &bp = folder.Bonds[i];
+ bp.PackIndex = ReadNum();
+ bp.UnpackIndex = ReadNum();
+ }
+
+ if (numInStreams < numBonds)
+ ThrowUnsupported();
+ const UInt32 numPackStreams = numInStreams - numBonds;
+ folder.PackStreams.SetSize(numPackStreams);
+
+ if (numPackStreams == 1)
+ {
+ for (i = 0; i < numInStreams; i++)
+ if (folder.FindBond_for_PackStream(i) < 0)
+ {
+ folder.PackStreams[0] = i;
+ break;
+ }
+ if (i == numInStreams)
+ ThrowUnsupported();
+ }
+ else
+ for (i = 0; i < numPackStreams; i++)
+ folder.PackStreams[i] = ReadNum();
+}
+
+void CFolders::ParseFolderInfo(unsigned folderIndex, CFolder &folder) const
+{
+ const size_t startPos = FoCodersDataOffset[folderIndex];
+ CInByte2 inByte;
+ inByte.Init(CodersData + startPos, FoCodersDataOffset[folderIndex + 1] - startPos);
+ inByte.ParseFolder(folder);
+ if (inByte.GetRem() != 0)
+ throw 20120424;
+}
+
+
+void CDatabase::GetPath(unsigned index, UString &path) const
+{
+ path.Empty();
+ if (!NameOffsets || !NamesBuf)
+ return;
+
+ const size_t offset = NameOffsets[index];
+ const size_t size = NameOffsets[index + 1] - offset;
+
+ if (size >= (1 << 28))
+ return;
+
+ wchar_t *s = path.GetBuf((unsigned)size - 1);
+
+ const Byte *p = ((const Byte *)NamesBuf + offset * 2);
+
+ #if defined(_WIN32) && defined(MY_CPU_LE)
+
+ wmemcpy(s, (const wchar_t *)(const void *)p, size);
+
+ #else
+
+ for (size_t i = 0; i < size; i++)
+ {
+ *s = Get16(p);
+ p += 2;
+ s++;
+ }
+
+ #endif
+
+ path.ReleaseBuf_SetLen((unsigned)size - 1);
+}
+
+HRESULT CDatabase::GetPath_Prop(unsigned index, PROPVARIANT *path) const throw()
+{
+ PropVariant_Clear(path);
+ if (!NameOffsets || !NamesBuf)
+ return S_OK;
+
+ const size_t offset = NameOffsets[index];
+ const size_t size = NameOffsets[index + 1] - offset;
+
+ if (size >= (1 << 14))
+ return S_OK;
+
+ // (size) includes null terminator
+
+ /*
+ #if WCHAR_MAX > 0xffff
+
+ const Byte *p = ((const Byte *)NamesBuf + offset * 2);
+ size = Utf16LE__Get_Num_WCHARs(p, size - 1);
+ // (size) doesn't include null terminator
+ RINOK(PropVarEm_Alloc_Bstr(path, (unsigned)size));
+ wchar_t *s = path->bstrVal;
+ wchar_t *sEnd = Utf16LE__To_WCHARs_Sep(p, size, s);
+ *sEnd = 0;
+ if (s + size != sEnd) return E_FAIL;
+
+ #else
+ */
+
+ RINOK(PropVarEm_Alloc_Bstr(path, (unsigned)size - 1))
+ wchar_t *s = path->bstrVal;
+ const Byte *p = ((const Byte *)NamesBuf + offset * 2);
+ // Utf16LE__To_WCHARs_Sep(p, size, s);
+
+ for (size_t i = 0; i < size; i++)
+ {
+ wchar_t c = Get16(p);
+ p += 2;
+ #if WCHAR_PATH_SEPARATOR != L'/'
+ if (c == L'/')
+ c = WCHAR_PATH_SEPARATOR;
+ else if (c == L'\\')
+ c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme
+ #endif
+ *s++ = c;
+ }
+
+ // #endif
+
+ return S_OK;
+
+ /*
+ unsigned cur = index;
+ unsigned size = 0;
+
+ for (int i = 0;; i++)
+ {
+ size_t len = NameOffsets[cur + 1] - NameOffsets[cur];
+ size += (unsigned)len;
+ if (i > 256 || len > (1 << 14) || size > (1 << 14))
+ return PropVarEm_Set_Str(path, "[TOO-LONG]");
+ cur = Files[cur].Parent;
+ if (cur < 0)
+ break;
+ }
+ size--;
+
+ RINOK(PropVarEm_Alloc_Bstr(path, size));
+ wchar_t *s = path->bstrVal;
+ s += size;
+ *s = 0;
+ cur = index;
+
+ for (;;)
+ {
+ unsigned len = (unsigned)(NameOffsets[cur + 1] - NameOffsets[cur] - 1);
+ const Byte *p = (const Byte *)NamesBuf + (NameOffsets[cur + 1] * 2) - 2;
+ for (; len != 0; len--)
+ {
+ p -= 2;
+ --s;
+ wchar_t c = Get16(p);
+ if (c == '/')
+ c = WCHAR_PATH_SEPARATOR;
+ *s = c;
+ }
+
+ const CFileItem &file = Files[cur];
+ cur = file.Parent;
+ if (cur < 0)
+ return S_OK;
+ *(--s) = (file.IsAltStream ? ':' : WCHAR_PATH_SEPARATOR);
+ }
+ */
+}
+
+void CInArchive::WaitId(UInt64 id)
+{
+ for (;;)
+ {
+ const UInt64 type = ReadID();
+ if (type == id)
+ return;
+ if (type == NID::kEnd)
+ ThrowIncorrect();
+ SkipData();
+ }
+}
+
+
+void CInArchive::Read_UInt32_Vector(CUInt32DefVector &v)
+{
+ const unsigned numItems = v.Defs.Size();
+ v.Vals.ClearAndSetSize(numItems);
+ UInt32 *p = &v.Vals[0];
+ const bool *defs = &v.Defs[0];
+ for (unsigned i = 0; i < numItems; i++)
+ {
+ UInt32 a = 0;
+ if (defs[i])
+ a = ReadUInt32();
+ p[i] = a;
+ }
+}
+
+
+void CInArchive::ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs)
+{
+ ReadBoolVector2(numItems, crcs.Defs);
+ Read_UInt32_Vector(crcs);
+}
+
+
+void CInArchive::ReadPackInfo(CFolders &f)
+{
+ const CNum numPackStreams = ReadNum();
+
+ WaitId(NID::kSize);
+ f.PackPositions.Alloc(numPackStreams + 1);
+ f.NumPackStreams = numPackStreams;
+ UInt64 sum = 0;
+ for (CNum i = 0; i < numPackStreams; i++)
+ {
+ f.PackPositions[i] = sum;
+ const UInt64 packSize = ReadNumber();
+ sum += packSize;
+ if (sum < packSize)
+ ThrowIncorrect();
+ }
+ f.PackPositions[numPackStreams] = sum;
+
+ UInt64 type;
+ for (;;)
+ {
+ type = ReadID();
+ if (type == NID::kEnd)
+ return;
+ if (type == NID::kCRC)
+ {
+ CUInt32DefVector PackCRCs;
+ ReadHashDigests(numPackStreams, PackCRCs);
+ continue;
+ }
+ SkipData();
+ }
+}
+
+void CInArchive::ReadUnpackInfo(
+ const CObjectVector<CByteBuffer> *dataVector,
+ CFolders &folders)
+{
+ WaitId(NID::kFolder);
+ const CNum numFolders = ReadNum();
+
+ CNum numCodersOutStreams = 0;
+ {
+ CStreamSwitch streamSwitch;
+ streamSwitch.Set(this, dataVector);
+ const Byte *startBufPtr = _inByteBack->GetPtr();
+ folders.NumFolders = numFolders;
+
+ folders.FoStartPackStreamIndex.Alloc(numFolders + 1);
+ folders.FoToMainUnpackSizeIndex.Alloc(numFolders);
+ folders.FoCodersDataOffset.Alloc(numFolders + 1);
+ folders.FoToCoderUnpackSizes.Alloc(numFolders + 1);
+
+ CBoolVector StreamUsed;
+ CBoolVector CoderUsed;
+
+ CNum packStreamIndex = 0;
+ CNum fo;
+ CInByte2 *inByte = _inByteBack;
+
+ for (fo = 0; fo < numFolders; fo++)
+ {
+ UInt32 indexOfMainStream = 0;
+ UInt32 numPackStreams = 0;
+ folders.FoCodersDataOffset[fo] = (size_t)(_inByteBack->GetPtr() - startBufPtr);
+
+ CNum numInStreams = 0;
+ const CNum numCoders = inByte->ReadNum();
+
+ if (numCoders == 0 || numCoders > k_Scan_NumCoders_MAX)
+ ThrowUnsupported();
+
+ for (CNum ci = 0; ci < numCoders; ci++)
+ {
+ const Byte mainByte = inByte->ReadByte();
+ if ((mainByte & 0xC0) != 0)
+ ThrowUnsupported();
+
+ const unsigned idSize = (mainByte & 0xF);
+ if (idSize > 8)
+ ThrowUnsupported();
+ if (idSize > inByte->GetRem())
+ ThrowEndOfData();
+ const Byte *longID = inByte->GetPtr();
+ UInt64 id = 0;
+ for (unsigned j = 0; j < idSize; j++)
+ id = ((id << 8) | longID[j]);
+ inByte->SkipDataNoCheck(idSize);
+ if (folders.ParsedMethods.IDs.Size() < 128)
+ folders.ParsedMethods.IDs.AddToUniqueSorted(id);
+
+ CNum coderInStreams = 1;
+ if ((mainByte & 0x10) != 0)
+ {
+ coderInStreams = inByte->ReadNum();
+ if (coderInStreams > k_Scan_NumCodersStreams_in_Folder_MAX)
+ ThrowUnsupported();
+ if (inByte->ReadNum() != 1)
+ ThrowUnsupported();
+ }
+
+ numInStreams += coderInStreams;
+ if (numInStreams > k_Scan_NumCodersStreams_in_Folder_MAX)
+ ThrowUnsupported();
+
+ if ((mainByte & 0x20) != 0)
+ {
+ const CNum propsSize = inByte->ReadNum();
+ if (propsSize > inByte->GetRem())
+ ThrowEndOfData();
+ if (id == k_LZMA2 && propsSize == 1)
+ {
+ const Byte v = *_inByteBack->GetPtr();
+ if (folders.ParsedMethods.Lzma2Prop < v)
+ folders.ParsedMethods.Lzma2Prop = v;
+ }
+ else if (id == k_LZMA && propsSize == 5)
+ {
+ const UInt32 dicSize = GetUi32(_inByteBack->GetPtr() + 1);
+ if (folders.ParsedMethods.LzmaDic < dicSize)
+ folders.ParsedMethods.LzmaDic = dicSize;
+ }
+ inByte->SkipDataNoCheck((size_t)propsSize);
+ }
+ }
+
+ if (numCoders == 1 && numInStreams == 1)
+ {
+ indexOfMainStream = 0;
+ numPackStreams = 1;
+ }
+ else
+ {
+ UInt32 i;
+ const CNum numBonds = numCoders - 1;
+ if (numInStreams < numBonds)
+ ThrowUnsupported();
+
+ BoolVector_Fill_False(StreamUsed, numInStreams);
+ BoolVector_Fill_False(CoderUsed, numCoders);
+
+ for (i = 0; i < numBonds; i++)
+ {
+ CNum index = ReadNum();
+ if (index >= numInStreams || StreamUsed[index])
+ ThrowUnsupported();
+ StreamUsed[index] = true;
+
+ index = ReadNum();
+ if (index >= numCoders || CoderUsed[index])
+ ThrowUnsupported();
+ CoderUsed[index] = true;
+ }
+
+ numPackStreams = numInStreams - numBonds;
+
+ if (numPackStreams != 1)
+ for (i = 0; i < numPackStreams; i++)
+ {
+ const CNum index = inByte->ReadNum(); // PackStreams
+ if (index >= numInStreams || StreamUsed[index])
+ ThrowUnsupported();
+ StreamUsed[index] = true;
+ }
+
+ for (i = 0; i < numCoders; i++)
+ if (!CoderUsed[i])
+ {
+ indexOfMainStream = i;
+ break;
+ }
+
+ if (i == numCoders)
+ ThrowUnsupported();
+ }
+
+ folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams;
+ numCodersOutStreams += numCoders;
+ folders.FoStartPackStreamIndex[fo] = packStreamIndex;
+ if (numPackStreams > folders.NumPackStreams - packStreamIndex)
+ ThrowIncorrect();
+ packStreamIndex += numPackStreams;
+ folders.FoToMainUnpackSizeIndex[fo] = (Byte)indexOfMainStream;
+ }
+
+ const size_t dataSize = (size_t)(_inByteBack->GetPtr() - startBufPtr);
+ folders.FoToCoderUnpackSizes[fo] = numCodersOutStreams;
+ folders.FoStartPackStreamIndex[fo] = packStreamIndex;
+ folders.FoCodersDataOffset[fo] = (size_t)(_inByteBack->GetPtr() - startBufPtr);
+ folders.CodersData.CopyFrom(startBufPtr, dataSize);
+
+ // if (folders.NumPackStreams != packStreamIndex) ThrowUnsupported();
+ }
+
+ WaitId(NID::kCodersUnpackSize);
+ folders.CoderUnpackSizes.Alloc(numCodersOutStreams);
+ for (CNum i = 0; i < numCodersOutStreams; i++)
+ folders.CoderUnpackSizes[i] = ReadNumber();
+
+ for (;;)
+ {
+ const UInt64 type = ReadID();
+ if (type == NID::kEnd)
+ return;
+ if (type == NID::kCRC)
+ {
+ ReadHashDigests(numFolders, folders.FolderCRCs);
+ continue;
+ }
+ SkipData();
+ }
+}
+
+void CInArchive::ReadSubStreamsInfo(
+ CFolders &folders,
+ CRecordVector<UInt64> &unpackSizes,
+ CUInt32DefVector &digests)
+{
+ folders.NumUnpackStreamsVector.Alloc(folders.NumFolders);
+ CNum i;
+ for (i = 0; i < folders.NumFolders; i++)
+ folders.NumUnpackStreamsVector[i] = 1;
+
+ UInt64 type;
+
+ for (;;)
+ {
+ type = ReadID();
+ if (type == NID::kNumUnpackStream)
+ {
+ for (i = 0; i < folders.NumFolders; i++)
+ folders.NumUnpackStreamsVector[i] = ReadNum();
+ continue;
+ }
+ if (type == NID::kCRC || type == NID::kSize || type == NID::kEnd)
+ break;
+ SkipData();
+ }
+
+ if (type == NID::kSize)
+ {
+ for (i = 0; i < folders.NumFolders; i++)
+ {
+ // v3.13 incorrectly worked with empty folders
+ // v4.07: we check that folder is empty
+ const CNum numSubstreams = folders.NumUnpackStreamsVector[i];
+ if (numSubstreams == 0)
+ continue;
+ UInt64 sum = 0;
+ for (CNum j = 1; j < numSubstreams; j++)
+ {
+ const UInt64 size = ReadNumber();
+ unpackSizes.Add(size);
+ sum += size;
+ if (sum < size)
+ ThrowIncorrect();
+ }
+ const UInt64 folderUnpackSize = folders.GetFolderUnpackSize(i);
+ if (folderUnpackSize < sum)
+ ThrowIncorrect();
+ unpackSizes.Add(folderUnpackSize - sum);
+ }
+ type = ReadID();
+ }
+ else
+ {
+ for (i = 0; i < folders.NumFolders; i++)
+ {
+ /* v9.26 - v9.29 incorrectly worked:
+ if (folders.NumUnpackStreamsVector[i] == 0), it threw error */
+ const CNum val = folders.NumUnpackStreamsVector[i];
+ if (val > 1)
+ ThrowIncorrect();
+ if (val == 1)
+ unpackSizes.Add(folders.GetFolderUnpackSize(i));
+ }
+ }
+
+ unsigned numDigests = 0;
+ for (i = 0; i < folders.NumFolders; i++)
+ {
+ const CNum numSubstreams = folders.NumUnpackStreamsVector[i];
+ if (numSubstreams != 1 || !folders.FolderCRCs.ValidAndDefined(i))
+ numDigests += numSubstreams;
+ }
+
+ for (;;)
+ {
+ if (type == NID::kEnd)
+ break;
+ if (type == NID::kCRC)
+ {
+ // CUInt32DefVector digests2;
+ // ReadHashDigests(numDigests, digests2);
+ CBoolVector digests2;
+ ReadBoolVector2(numDigests, digests2);
+
+ digests.ClearAndSetSize(unpackSizes.Size());
+
+ unsigned k = 0;
+ unsigned k2 = 0;
+
+ for (i = 0; i < folders.NumFolders; i++)
+ {
+ const CNum numSubstreams = folders.NumUnpackStreamsVector[i];
+ if (numSubstreams == 1 && folders.FolderCRCs.ValidAndDefined(i))
+ {
+ digests.Defs[k] = true;
+ digests.Vals[k] = folders.FolderCRCs.Vals[i];
+ k++;
+ }
+ else for (CNum j = 0; j < numSubstreams; j++)
+ {
+ bool defined = digests2[k2++];
+ digests.Defs[k] = defined;
+ UInt32 crc = 0;
+ if (defined)
+ crc = ReadUInt32();
+ digests.Vals[k] = crc;
+ k++;
+ }
+ }
+ // if (k != unpackSizes.Size()) throw 1234567;
+ }
+ else
+ SkipData();
+
+ type = ReadID();
+ }
+
+ if (digests.Defs.Size() != unpackSizes.Size())
+ {
+ digests.ClearAndSetSize(unpackSizes.Size());
+ unsigned k = 0;
+ for (i = 0; i < folders.NumFolders; i++)
+ {
+ const CNum numSubstreams = folders.NumUnpackStreamsVector[i];
+ if (numSubstreams == 1 && folders.FolderCRCs.ValidAndDefined(i))
+ {
+ digests.Defs[k] = true;
+ digests.Vals[k] = folders.FolderCRCs.Vals[i];
+ k++;
+ }
+ else for (CNum j = 0; j < numSubstreams; j++)
+ {
+ digests.Defs[k] = false;
+ digests.Vals[k] = 0;
+ k++;
+ }
+ }
+ }
+}
+
+
+
+void CInArchive::ReadStreamsInfo(
+ const CObjectVector<CByteBuffer> *dataVector,
+ UInt64 &dataOffset,
+ CFolders &folders,
+ CRecordVector<UInt64> &unpackSizes,
+ CUInt32DefVector &digests)
+{
+ UInt64 type = ReadID();
+
+ if (type == NID::kPackInfo)
+ {
+ dataOffset = ReadNumber();
+ if (dataOffset > _rangeLimit)
+ ThrowIncorrect();
+ ReadPackInfo(folders);
+ if (folders.PackPositions[folders.NumPackStreams] > _rangeLimit - dataOffset)
+ ThrowIncorrect();
+ type = ReadID();
+ }
+
+ if (type == NID::kUnpackInfo)
+ {
+ ReadUnpackInfo(dataVector, folders);
+ type = ReadID();
+ }
+
+ if (folders.NumFolders != 0 && !folders.PackPositions)
+ {
+ // if there are folders, we need PackPositions also
+ folders.PackPositions.Alloc(1);
+ folders.PackPositions[0] = 0;
+ }
+
+ if (type == NID::kSubStreamsInfo)
+ {
+ ReadSubStreamsInfo(folders, unpackSizes, digests);
+ type = ReadID();
+ }
+ else
+ {
+ folders.NumUnpackStreamsVector.Alloc(folders.NumFolders);
+ /* If digests.Defs.Size() == 0, it means that there are no crcs.
+ So we don't need to fill digests with values. */
+ // digests.Vals.ClearAndSetSize(folders.NumFolders);
+ // BoolVector_Fill_False(digests.Defs, folders.NumFolders);
+ for (CNum i = 0; i < folders.NumFolders; i++)
+ {
+ folders.NumUnpackStreamsVector[i] = 1;
+ unpackSizes.Add(folders.GetFolderUnpackSize(i));
+ // digests.Vals[i] = 0;
+ }
+ }
+
+ if (type != NID::kEnd)
+ ThrowIncorrect();
+}
+
+void CInArchive::ReadBoolVector(unsigned numItems, CBoolVector &v)
+{
+ v.ClearAndSetSize(numItems);
+ Byte b = 0;
+ Byte mask = 0;
+ bool *p = &v[0];
+ for (unsigned i = 0; i < numItems; i++)
+ {
+ if (mask == 0)
+ {
+ b = ReadByte();
+ mask = 0x80;
+ }
+ p[i] = ((b & mask) != 0);
+ mask = (Byte)(mask >> 1);
+ }
+}
+
+void CInArchive::ReadBoolVector2(unsigned numItems, CBoolVector &v)
+{
+ const Byte allAreDefined = ReadByte();
+ if (allAreDefined == 0)
+ {
+ ReadBoolVector(numItems, v);
+ return;
+ }
+ v.ClearAndSetSize(numItems);
+ bool *p = &v[0];
+ for (unsigned i = 0; i < numItems; i++)
+ p[i] = true;
+}
+
+void CInArchive::ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector,
+ CUInt64DefVector &v, unsigned numItems)
+{
+ ReadBoolVector2(numItems, v.Defs);
+
+ CStreamSwitch streamSwitch;
+ streamSwitch.Set(this, &dataVector);
+
+ v.Vals.ClearAndSetSize(numItems);
+ UInt64 *p = &v.Vals[0];
+ const bool *defs = &v.Defs[0];
+
+ for (unsigned i = 0; i < numItems; i++)
+ {
+ UInt64 t = 0;
+ if (defs[i])
+ t = ReadUInt64();
+ p[i] = t;
+ }
+}
+
+HRESULT CInArchive::ReadAndDecodePackedStreams(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ UInt64 baseOffset,
+ UInt64 &dataOffset, CObjectVector<CByteBuffer> &dataVector
+ Z7_7Z_DECODER_CRYPRO_VARS_DECL
+ )
+{
+ CFolders folders;
+ CRecordVector<UInt64> unpackSizes;
+ CUInt32DefVector digests;
+
+ ReadStreamsInfo(NULL,
+ dataOffset,
+ folders,
+ unpackSizes,
+ digests);
+
+ CDecoder decoder(_useMixerMT);
+
+ for (CNum i = 0; i < folders.NumFolders; i++)
+ {
+ CByteBuffer &data = dataVector.AddNew();
+ const UInt64 unpackSize64 = folders.GetFolderUnpackSize(i);
+ const size_t unpackSize = (size_t)unpackSize64;
+ if (unpackSize != unpackSize64)
+ ThrowUnsupported();
+ data.Alloc(unpackSize);
+
+ CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;
+ CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+ outStreamSpec->Init(data, unpackSize);
+
+ bool dataAfterEnd_Error = false;
+
+ HRESULT result = decoder.Decode(
+ EXTERNAL_CODECS_LOC_VARS
+ _stream, baseOffset + dataOffset,
+ folders, i,
+ NULL, // &unpackSize64
+
+ outStream,
+ NULL, // *compressProgress
+
+ NULL // **inStreamMainRes
+ , dataAfterEnd_Error
+
+ Z7_7Z_DECODER_CRYPRO_VARS
+ #if !defined(Z7_ST)
+ , false // mtMode
+ , 1 // numThreads
+ , 0 // memUsage
+ #endif
+ );
+
+ RINOK(result)
+
+ if (dataAfterEnd_Error)
+ ThereIsHeaderError = true;
+
+ if (unpackSize != outStreamSpec->GetPos())
+ ThrowIncorrect();
+
+ if (folders.FolderCRCs.ValidAndDefined(i))
+ if (CrcCalc(data, unpackSize) != folders.FolderCRCs.Vals[i])
+ ThrowIncorrect();
+ }
+
+ if (folders.PackPositions)
+ HeadersSize += folders.PackPositions[folders.NumPackStreams];
+
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadHeader(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CDbEx &db
+ Z7_7Z_DECODER_CRYPRO_VARS_DECL
+ )
+{
+ UInt64 type = ReadID();
+
+ if (type == NID::kArchiveProperties)
+ {
+ ReadArchiveProperties(db.ArcInfo);
+ type = ReadID();
+ }
+
+ CObjectVector<CByteBuffer> dataVector;
+
+ if (type == NID::kAdditionalStreamsInfo)
+ {
+ const HRESULT result = ReadAndDecodePackedStreams(
+ EXTERNAL_CODECS_LOC_VARS
+ db.ArcInfo.StartPositionAfterHeader,
+ db.ArcInfo.DataStartPosition2,
+ dataVector
+ Z7_7Z_DECODER_CRYPRO_VARS
+ );
+ RINOK(result)
+ db.ArcInfo.DataStartPosition2 += db.ArcInfo.StartPositionAfterHeader;
+ type = ReadID();
+ }
+
+ CRecordVector<UInt64> unpackSizes;
+ CUInt32DefVector digests;
+
+ if (type == NID::kMainStreamsInfo)
+ {
+ ReadStreamsInfo(&dataVector,
+ db.ArcInfo.DataStartPosition,
+ (CFolders &)db,
+ unpackSizes,
+ digests);
+ db.ArcInfo.DataStartPosition += db.ArcInfo.StartPositionAfterHeader;
+ type = ReadID();
+ }
+
+ if (type == NID::kFilesInfo)
+ {
+
+ const CNum numFiles = ReadNum();
+
+ db.ArcInfo.FileInfoPopIDs.Add(NID::kSize);
+ // if (!db.PackSizes.IsEmpty())
+ db.ArcInfo.FileInfoPopIDs.Add(NID::kPackInfo);
+ if (numFiles > 0 && !digests.Defs.IsEmpty())
+ db.ArcInfo.FileInfoPopIDs.Add(NID::kCRC);
+
+ CBoolVector emptyStreamVector;
+ CBoolVector emptyFileVector;
+ CBoolVector antiFileVector;
+ CNum numEmptyStreams = 0;
+
+ for (;;)
+ {
+ const UInt64 type2 = ReadID();
+ if (type2 == NID::kEnd)
+ break;
+ const UInt64 size = ReadNumber();
+ if (size > _inByteBack->GetRem())
+ ThrowIncorrect();
+ CStreamSwitch switchProp;
+ switchProp.Set(this, _inByteBack->GetPtr(), (size_t)size, true);
+ bool addPropIdToList = true;
+ bool isKnownType = true;
+ if (type2 > ((UInt32)1 << 30))
+ isKnownType = false;
+ else switch ((UInt32)type2)
+ {
+ case NID::kName:
+ {
+ CStreamSwitch streamSwitch;
+ streamSwitch.Set(this, &dataVector);
+ const size_t rem = _inByteBack->GetRem();
+ db.NamesBuf.Alloc(rem);
+ ReadBytes(db.NamesBuf, rem);
+ db.NameOffsets.Alloc(numFiles + 1);
+ size_t pos = 0;
+ unsigned i;
+ for (i = 0; i < numFiles; i++)
+ {
+ const size_t curRem = (rem - pos) / 2;
+ const UInt16 *buf = (const UInt16 *)(const void *)(db.NamesBuf + pos);
+ size_t j;
+ for (j = 0; j < curRem && buf[j] != 0; j++);
+ if (j == curRem)
+ ThrowEndOfData();
+ db.NameOffsets[i] = pos / 2;
+ pos += j * 2 + 2;
+ }
+ db.NameOffsets[i] = pos / 2;
+ if (pos != rem)
+ ThereIsHeaderError = true;
+ break;
+ }
+
+ case NID::kWinAttrib:
+ {
+ ReadBoolVector2(numFiles, db.Attrib.Defs);
+ CStreamSwitch streamSwitch;
+ streamSwitch.Set(this, &dataVector);
+ Read_UInt32_Vector(db.Attrib);
+ break;
+ }
+
+ /*
+ case NID::kIsAux:
+ {
+ ReadBoolVector(numFiles, db.IsAux);
+ break;
+ }
+ case NID::kParent:
+ {
+ db.IsTree = true;
+ // CBoolVector boolVector;
+ // ReadBoolVector2(numFiles, boolVector);
+ // CStreamSwitch streamSwitch;
+ // streamSwitch.Set(this, &dataVector);
+ CBoolVector boolVector;
+ ReadBoolVector2(numFiles, boolVector);
+
+ db.ThereAreAltStreams = false;
+ for (i = 0; i < numFiles; i++)
+ {
+ CFileItem &file = db.Files[i];
+ // file.Parent = -1;
+ // if (boolVector[i])
+ file.Parent = (int)ReadUInt32();
+ file.IsAltStream = !boolVector[i];
+ if (file.IsAltStream)
+ db.ThereAreAltStreams = true;
+ }
+ break;
+ }
+ */
+ case NID::kEmptyStream:
+ {
+ ReadBoolVector(numFiles, emptyStreamVector);
+ numEmptyStreams = BoolVector_CountSum(emptyStreamVector);
+ emptyFileVector.Clear();
+ antiFileVector.Clear();
+ break;
+ }
+ case NID::kEmptyFile: ReadBoolVector(numEmptyStreams, emptyFileVector); break;
+ case NID::kAnti: ReadBoolVector(numEmptyStreams, antiFileVector); break;
+ case NID::kStartPos: ReadUInt64DefVector(dataVector, db.StartPos, (unsigned)numFiles); break;
+ case NID::kCTime: ReadUInt64DefVector(dataVector, db.CTime, (unsigned)numFiles); break;
+ case NID::kATime: ReadUInt64DefVector(dataVector, db.ATime, (unsigned)numFiles); break;
+ case NID::kMTime: ReadUInt64DefVector(dataVector, db.MTime, (unsigned)numFiles); break;
+ case NID::kDummy:
+ {
+ for (UInt64 j = 0; j < size; j++)
+ if (ReadByte() != 0)
+ ThereIsHeaderError = true;
+ addPropIdToList = false;
+ break;
+ }
+ /*
+ case NID::kNtSecure:
+ {
+ try
+ {
+ {
+ CStreamSwitch streamSwitch;
+ streamSwitch.Set(this, &dataVector);
+ UInt32 numDescriptors = ReadUInt32();
+ size_t offset = 0;
+ db.SecureOffsets.Clear();
+ for (i = 0; i < numDescriptors; i++)
+ {
+ UInt32 size = ReadUInt32();
+ db.SecureOffsets.Add(offset);
+ offset += size;
+ }
+ // ThrowIncorrect();;
+ db.SecureOffsets.Add(offset);
+ db.SecureBuf.SetCapacity(offset);
+ for (i = 0; i < numDescriptors; i++)
+ {
+ offset = db.SecureOffsets[i];
+ ReadBytes(db.SecureBuf + offset, db.SecureOffsets[i + 1] - offset);
+ }
+ db.SecureIDs.Clear();
+ for (unsigned i = 0; i < numFiles; i++)
+ {
+ db.SecureIDs.Add(ReadNum());
+ // db.SecureIDs.Add(ReadUInt32());
+ }
+ // ReadUInt32();
+ if (_inByteBack->GetRem() != 0)
+ ThrowIncorrect();;
+ }
+ }
+ catch(CInArchiveException &)
+ {
+ ThereIsHeaderError = true;
+ addPropIdToList = isKnownType = false;
+ db.ClearSecure();
+ }
+ break;
+ }
+ */
+ default:
+ addPropIdToList = isKnownType = false;
+ }
+ if (isKnownType)
+ {
+ if (addPropIdToList)
+ db.ArcInfo.FileInfoPopIDs.Add(type2);
+ }
+ else
+ {
+ db.UnsupportedFeatureWarning = true;
+ _inByteBack->SkipRem();
+ }
+ // SkipData worked incorrectly in some versions before v4.59 (7zVer <= 0.02)
+ if (_inByteBack->GetRem() != 0)
+ ThrowIncorrect();
+ }
+
+ type = ReadID(); // Read (NID::kEnd) end of headers
+
+ if (numFiles - numEmptyStreams != unpackSizes.Size())
+ ThrowUnsupported();
+
+ CNum emptyFileIndex = 0;
+ CNum sizeIndex = 0;
+
+ const CNum numAntiItems = BoolVector_CountSum(antiFileVector);
+
+ if (numAntiItems != 0)
+ db.IsAnti.ClearAndSetSize(numFiles);
+
+ db.Files.ClearAndSetSize(numFiles);
+
+ for (CNum i = 0; i < numFiles; i++)
+ {
+ CFileItem &file = db.Files[i];
+ bool isAnti;
+ file.Crc = 0;
+ if (!BoolVector_Item_IsValidAndTrue(emptyStreamVector, i))
+ {
+ file.HasStream = true;
+ file.IsDir = false;
+ isAnti = false;
+ file.Size = unpackSizes[sizeIndex];
+ file.CrcDefined = digests.ValidAndDefined(sizeIndex);
+ if (file.CrcDefined)
+ file.Crc = digests.Vals[sizeIndex];
+ sizeIndex++;
+ }
+ else
+ {
+ file.HasStream = false;
+ file.IsDir = !BoolVector_Item_IsValidAndTrue(emptyFileVector, emptyFileIndex);
+ isAnti = BoolVector_Item_IsValidAndTrue(antiFileVector, emptyFileIndex);
+ emptyFileIndex++;
+ file.Size = 0;
+ file.CrcDefined = false;
+ }
+ if (numAntiItems != 0)
+ db.IsAnti[i] = isAnti;
+ }
+
+ }
+
+ db.FillLinks();
+
+ if (type != NID::kEnd || _inByteBack->GetRem() != 0)
+ {
+ db.UnsupportedFeatureWarning = true;
+ // ThrowIncorrect();
+ }
+
+ return S_OK;
+}
+
+
+void CDbEx::FillLinks()
+{
+ FolderStartFileIndex.Alloc(NumFolders);
+ FileIndexToFolderIndexMap.Alloc(Files.Size());
+
+ CNum folderIndex = 0;
+ CNum indexInFolder = 0;
+ unsigned i;
+
+ for (i = 0; i < Files.Size(); i++)
+ {
+ const bool emptyStream = !Files[i].HasStream;
+ if (indexInFolder == 0)
+ {
+ if (emptyStream)
+ {
+ FileIndexToFolderIndexMap[i] = kNumNoIndex;
+ continue;
+ }
+ // v3.13 incorrectly worked with empty folders
+ // v4.07: we skip empty folders
+ for (;;)
+ {
+ if (folderIndex >= NumFolders)
+ ThrowIncorrect();
+ FolderStartFileIndex[folderIndex] = i;
+ if (NumUnpackStreamsVector[folderIndex] != 0)
+ break;
+ folderIndex++;
+ }
+ }
+ FileIndexToFolderIndexMap[i] = folderIndex;
+ if (emptyStream)
+ continue;
+ if (++indexInFolder >= NumUnpackStreamsVector[folderIndex])
+ {
+ folderIndex++;
+ indexInFolder = 0;
+ }
+ }
+
+ if (indexInFolder != 0)
+ {
+ folderIndex++;
+ // 18.06
+ ThereIsHeaderError = true;
+ // ThrowIncorrect();
+ }
+
+ for (;;)
+ {
+ if (folderIndex >= NumFolders)
+ return;
+ FolderStartFileIndex[folderIndex] = i;
+ if (NumUnpackStreamsVector[folderIndex] != 0)
+ {
+ // 18.06
+ ThereIsHeaderError = true;
+ // ThrowIncorrect();
+ }
+ folderIndex++;
+ }
+}
+
+
+HRESULT CInArchive::ReadDatabase2(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CDbEx &db
+ Z7_7Z_DECODER_CRYPRO_VARS_DECL
+ )
+{
+ db.Clear();
+ db.ArcInfo.StartPosition = _arhiveBeginStreamPosition;
+
+ db.ArcInfo.Version.Major = _header[6];
+ db.ArcInfo.Version.Minor = _header[7];
+
+ if (db.ArcInfo.Version.Major != kMajorVersion)
+ {
+ // db.UnsupportedVersion = true;
+ return S_FALSE;
+ }
+
+ UInt64 nextHeaderOffset = Get64(_header + 12);
+ UInt64 nextHeaderSize = Get64(_header + 20);
+ UInt32 nextHeaderCRC = Get32(_header + 28);
+
+ #ifdef FORMAT_7Z_RECOVERY
+ const UInt32 crcFromArc = Get32(_header + 8);
+ if (crcFromArc == 0 && nextHeaderOffset == 0 && nextHeaderSize == 0 && nextHeaderCRC == 0)
+ {
+ UInt64 cur, fileSize;
+ RINOK(InStream_GetPos(_stream, cur))
+ const unsigned kCheckSize = 512;
+ Byte buf[kCheckSize];
+ RINOK(InStream_GetSize_SeekToEnd(_stream, fileSize))
+ const UInt64 rem = fileSize - cur;
+ unsigned checkSize = kCheckSize;
+ if (rem < kCheckSize)
+ checkSize = (unsigned)(rem);
+ if (checkSize < 3)
+ return S_FALSE;
+ RINOK(InStream_SeekSet(_stream, fileSize - checkSize))
+ RINOK(ReadStream_FALSE(_stream, buf, (size_t)checkSize))
+
+ if (buf[checkSize - 1] != 0)
+ return S_FALSE;
+
+ unsigned i;
+ for (i = checkSize - 2;; i--)
+ {
+ if ((buf[i] == NID::kEncodedHeader && buf[i + 1] == NID::kPackInfo) ||
+ (buf[i] == NID::kHeader && buf[i + 1] == NID::kMainStreamsInfo))
+ break;
+ if (i == 0)
+ return S_FALSE;
+ }
+ nextHeaderSize = checkSize - i;
+ nextHeaderOffset = rem - nextHeaderSize;
+ nextHeaderCRC = CrcCalc(buf + i, (size_t)nextHeaderSize);
+ RINOK(InStream_SeekSet(_stream, cur))
+ db.StartHeaderWasRecovered = true;
+ }
+ else
+ #endif
+ {
+ // Crc was tested already at signature check
+ // if (CrcCalc(_header + 12, 20) != crcFromArchive) ThrowIncorrect();
+ }
+
+ db.ArcInfo.StartPositionAfterHeader = _arhiveBeginStreamPosition + kHeaderSize;
+ db.PhySize = kHeaderSize;
+
+ db.IsArc = false;
+ if ((Int64)nextHeaderOffset < 0 ||
+ nextHeaderSize > ((UInt64)1 << 62))
+ return S_FALSE;
+
+ HeadersSize = kHeaderSize;
+
+ if (nextHeaderSize == 0)
+ {
+ if (nextHeaderOffset != 0)
+ return S_FALSE;
+ db.IsArc = true;
+ db.HeadersSize = HeadersSize;
+ return S_OK;
+ }
+
+ if (!db.StartHeaderWasRecovered)
+ db.IsArc = true;
+
+ HeadersSize += nextHeaderSize;
+ // db.EndHeaderOffset = nextHeaderOffset;
+ _rangeLimit = nextHeaderOffset;
+
+ db.PhySize = kHeaderSize + nextHeaderOffset + nextHeaderSize;
+ if (_fileEndPosition - db.ArcInfo.StartPositionAfterHeader < nextHeaderOffset + nextHeaderSize)
+ {
+ db.UnexpectedEnd = true;
+ return S_FALSE;
+ }
+ RINOK(_stream->Seek((Int64)nextHeaderOffset, STREAM_SEEK_CUR, NULL))
+
+ const size_t nextHeaderSize_t = (size_t)nextHeaderSize;
+ if (nextHeaderSize_t != nextHeaderSize)
+ return E_OUTOFMEMORY;
+ CByteBuffer buffer2(nextHeaderSize_t);
+
+ RINOK(ReadStream_FALSE(_stream, buffer2, nextHeaderSize_t))
+
+ if (CrcCalc(buffer2, nextHeaderSize_t) != nextHeaderCRC)
+ ThrowIncorrect();
+
+ if (!db.StartHeaderWasRecovered)
+ db.PhySizeWasConfirmed = true;
+
+ CStreamSwitch streamSwitch;
+ streamSwitch.Set(this, buffer2);
+
+ CObjectVector<CByteBuffer> dataVector;
+
+ const UInt64 type = ReadID();
+ if (type != NID::kHeader)
+ {
+ if (type != NID::kEncodedHeader)
+ ThrowIncorrect();
+ const HRESULT result = ReadAndDecodePackedStreams(
+ EXTERNAL_CODECS_LOC_VARS
+ db.ArcInfo.StartPositionAfterHeader,
+ db.ArcInfo.DataStartPosition2,
+ dataVector
+ Z7_7Z_DECODER_CRYPRO_VARS
+ );
+ 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.IsArc = true;
+
+ db.HeadersSize = HeadersSize;
+
+ return ReadHeader(
+ EXTERNAL_CODECS_LOC_VARS
+ db
+ Z7_7Z_DECODER_CRYPRO_VARS
+ );
+}
+
+
+HRESULT CInArchive::ReadDatabase(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CDbEx &db
+ Z7_7Z_DECODER_CRYPRO_VARS_DECL
+ )
+{
+ try
+ {
+ const HRESULT res = ReadDatabase2(
+ EXTERNAL_CODECS_LOC_VARS db
+ Z7_7Z_DECODER_CRYPRO_VARS
+ );
+ if (ThereIsHeaderError)
+ db.ThereIsHeaderError = true;
+ if (res == E_NOTIMPL)
+ ThrowUnsupported();
+ return res;
+ }
+ catch(CUnsupportedFeatureException &)
+ {
+ db.UnsupportedFeatureError = true;
+ return S_FALSE;
+ }
+ catch(CInArchiveException &)
+ {
+ db.ThereIsHeaderError = true;
+ return S_FALSE;
+ }
+}
+
+}}
diff --git a/CPP/7zip/Archive/7z/7zIn.h b/CPP/7zip/Archive/7z/7zIn.h
index bb0e474..a9c14fb 100644
--- a/CPP/7zip/Archive/7z/7zIn.h
+++ b/CPP/7zip/Archive/7z/7zIn.h
@@ -1,445 +1,451 @@
-// 7zIn.h
-
-#ifndef __7Z_IN_H
-#define __7Z_IN_H
-
-#include "../../../Common/MyCom.h"
-
-#include "../../../Windows/PropVariant.h"
-
-#include "../../IPassword.h"
-#include "../../IStream.h"
-
-#include "../../Common/CreateCoder.h"
-#include "../../Common/InBuffer.h"
-
-#include "7zItem.h"
-
-namespace NArchive {
-namespace N7z {
-
-/*
- We don't need to init isEncrypted and passwordIsDefined
- We must upgrade them only */
-
-#ifdef _NO_CRYPTO
-#define _7Z_DECODER_CRYPRO_VARS_DECL
-#define _7Z_DECODER_CRYPRO_VARS
-#else
-#define _7Z_DECODER_CRYPRO_VARS_DECL , ICryptoGetTextPassword *getTextPassword, bool &isEncrypted, bool &passwordIsDefined, UString &password
-#define _7Z_DECODER_CRYPRO_VARS , getTextPassword, isEncrypted, passwordIsDefined, password
-#endif
-
-struct CParsedMethods
-{
- Byte Lzma2Prop;
- UInt32 LzmaDic;
- CRecordVector<UInt64> IDs;
-
- CParsedMethods(): Lzma2Prop(0), LzmaDic(0) {}
-};
-
-struct CFolderEx: public CFolder
-{
- unsigned UnpackCoder;
-};
-
-struct CFolders
-{
- CNum NumPackStreams;
- CNum NumFolders;
-
- CObjArray<UInt64> PackPositions; // NumPackStreams + 1
- // CUInt32DefVector PackCRCs; // we don't use PackCRCs now
-
- CUInt32DefVector FolderCRCs; // NumFolders
- CObjArray<CNum> NumUnpackStreamsVector; // NumFolders
-
- CObjArray<UInt64> CoderUnpackSizes; // including unpack sizes of bond coders
- CObjArray<CNum> FoToCoderUnpackSizes; // NumFolders + 1
- CObjArray<CNum> FoStartPackStreamIndex; // NumFolders + 1
- CObjArray<Byte> FoToMainUnpackSizeIndex; // NumFolders
-
- CObjArray<size_t> FoCodersDataOffset; // NumFolders + 1
- CByteBuffer CodersData;
-
- CParsedMethods ParsedMethods;
-
- void ParseFolderInfo(unsigned folderIndex, CFolder &folder) const;
- void ParseFolderEx(unsigned folderIndex, CFolderEx &folder) const
- {
- ParseFolderInfo(folderIndex, folder);
- folder.UnpackCoder = FoToMainUnpackSizeIndex[folderIndex];
- }
-
- unsigned GetNumFolderUnpackSizes(unsigned folderIndex) const
- {
- return (unsigned)(FoToCoderUnpackSizes[folderIndex + 1] - FoToCoderUnpackSizes[folderIndex]);
- }
-
- UInt64 GetFolderUnpackSize(unsigned folderIndex) const
- {
- return CoderUnpackSizes[FoToCoderUnpackSizes[folderIndex] + FoToMainUnpackSizeIndex[folderIndex]];
- }
-
- UInt64 GetStreamPackSize(unsigned index) const
- {
- return PackPositions[index + 1] - PackPositions[index];
- }
-
- CFolders(): NumPackStreams(0), NumFolders(0) {}
-
- void Clear()
- {
- NumPackStreams = 0;
- PackPositions.Free();
- // PackCRCs.Clear();
-
- NumFolders = 0;
- FolderCRCs.Clear();
- NumUnpackStreamsVector.Free();
- CoderUnpackSizes.Free();
- FoToCoderUnpackSizes.Free();
- FoStartPackStreamIndex.Free();
- FoToMainUnpackSizeIndex.Free();
- FoCodersDataOffset.Free();
- CodersData.Free();
- }
-};
-
-struct CDatabase: public CFolders
-{
- CRecordVector<CFileItem> Files;
-
- CUInt64DefVector CTime;
- CUInt64DefVector ATime;
- CUInt64DefVector MTime;
- CUInt64DefVector StartPos;
- CUInt32DefVector Attrib;
- CBoolVector IsAnti;
- /*
- CBoolVector IsAux;
- CByteBuffer SecureBuf;
- CRecordVector<UInt32> SecureIDs;
- */
-
- CByteBuffer NamesBuf;
- CObjArray<size_t> NameOffsets; // numFiles + 1, offsets of utf-16 symbols
-
- /*
- void ClearSecure()
- {
- SecureBuf.Free();
- SecureIDs.Clear();
- }
- */
-
- void Clear()
- {
- CFolders::Clear();
- // ClearSecure();
-
- NamesBuf.Free();
- NameOffsets.Free();
-
- Files.Clear();
- CTime.Clear();
- ATime.Clear();
- MTime.Clear();
- StartPos.Clear();
- Attrib.Clear();
- IsAnti.Clear();
- // IsAux.Clear();
- }
-
- bool IsSolid() const
- {
- for (CNum i = 0; i < NumFolders; i++)
- if (NumUnpackStreamsVector[i] > 1)
- return true;
- return false;
- }
- bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); }
- // bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); }
-
- /*
- const void* GetName(unsigned index) const
- {
- if (!NameOffsets || !NamesBuf)
- return NULL;
- return (void *)((const Byte *)NamesBuf + NameOffsets[index] * 2);
- };
- */
- void GetPath(unsigned index, UString &path) const;
- HRESULT GetPath_Prop(unsigned index, PROPVARIANT *path) const throw();
-};
-
-struct CInArchiveInfo
-{
- CArchiveVersion Version;
- UInt64 StartPosition;
- UInt64 StartPositionAfterHeader;
- UInt64 DataStartPosition;
- UInt64 DataStartPosition2;
- CRecordVector<UInt64> FileInfoPopIDs;
-
- void Clear()
- {
- StartPosition = 0;
- StartPositionAfterHeader = 0;
- DataStartPosition = 0;
- DataStartPosition2 = 0;
- FileInfoPopIDs.Clear();
- }
-};
-
-struct CDbEx: public CDatabase
-{
- CInArchiveInfo ArcInfo;
-
- CObjArray<CNum> FolderStartFileIndex;
- CObjArray<CNum> FileIndexToFolderIndexMap;
-
- UInt64 HeadersSize;
- UInt64 PhySize;
-
- /*
- CRecordVector<size_t> SecureOffsets;
- bool IsTree;
- bool ThereAreAltStreams;
- */
-
- bool IsArc;
- bool PhySizeWasConfirmed;
-
- bool ThereIsHeaderError;
- bool UnexpectedEnd;
- // bool UnsupportedVersion;
-
- bool StartHeaderWasRecovered;
- bool UnsupportedFeatureWarning;
- bool UnsupportedFeatureError;
-
- /*
- void ClearSecureEx()
- {
- ClearSecure();
- SecureOffsets.Clear();
- }
- */
-
- void Clear()
- {
- IsArc = false;
- PhySizeWasConfirmed = false;
-
- ThereIsHeaderError = false;
- UnexpectedEnd = false;
- // UnsupportedVersion = false;
-
- StartHeaderWasRecovered = false;
- UnsupportedFeatureError = false;
- UnsupportedFeatureWarning = false;
-
- /*
- IsTree = false;
- ThereAreAltStreams = false;
- */
-
- CDatabase::Clear();
-
- // SecureOffsets.Clear();
- ArcInfo.Clear();
- FolderStartFileIndex.Free();
- FileIndexToFolderIndexMap.Free();
-
- HeadersSize = 0;
- PhySize = 0;
- }
-
- bool CanUpdate() const
- {
- if (ThereIsHeaderError
- || UnexpectedEnd
- || StartHeaderWasRecovered
- || UnsupportedFeatureError)
- return false;
- return true;
- }
-
- void FillLinks();
-
- UInt64 GetFolderStreamPos(CNum folderIndex, unsigned indexInFolder) const
- {
- return ArcInfo.DataStartPosition +
- PackPositions[FoStartPackStreamIndex[folderIndex] + indexInFolder];
- }
-
- UInt64 GetFolderFullPackSize(CNum folderIndex) const
- {
- return
- PackPositions[FoStartPackStreamIndex[folderIndex + 1]] -
- PackPositions[FoStartPackStreamIndex[folderIndex]];
- }
-
- UInt64 GetFolderPackStreamSize(CNum folderIndex, unsigned streamIndex) const
- {
- size_t i = FoStartPackStreamIndex[folderIndex] + streamIndex;
- return PackPositions[i + 1] - PackPositions[i];
- }
-
- UInt64 GetFilePackSize(CNum fileIndex) const
- {
- CNum folderIndex = FileIndexToFolderIndexMap[fileIndex];
- if (folderIndex != kNumNoIndex)
- if (FolderStartFileIndex[folderIndex] == fileIndex)
- return GetFolderFullPackSize(folderIndex);
- return 0;
- }
-};
-
-const unsigned kNumBufLevelsMax = 4;
-
-struct CInByte2
-{
- const Byte *_buffer;
-public:
- size_t _size;
- size_t _pos;
-
- size_t GetRem() const { return _size - _pos; }
- const Byte *GetPtr() const { return _buffer + _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 SkipDataNoCheck(UInt64 size) { _pos += (size_t)size; }
- void SkipData(UInt64 size);
-
- void SkipData();
- void SkipRem() { _pos = _size; }
- UInt64 ReadNumber();
- CNum ReadNum();
- UInt32 ReadUInt32();
- UInt64 ReadUInt64();
-
- void ParseFolder(CFolder &folder);
-};
-
-class CStreamSwitch;
-
-const UInt32 kHeaderSize = 32;
-
-class CInArchive
-{
- friend class CStreamSwitch;
-
- CMyComPtr<IInStream> _stream;
-
- unsigned _numInByteBufs;
- CInByte2 _inByteVector[kNumBufLevelsMax];
-
- CInByte2 *_inByteBack;
- bool ThereIsHeaderError;
-
- UInt64 _arhiveBeginStreamPosition;
- UInt64 _fileEndPosition;
-
- Byte _header[kHeaderSize];
-
- UInt64 HeadersSize;
-
- bool _useMixerMT;
-
- void AddByteStream(const Byte *buffer, size_t size);
-
- void DeleteByteStream(bool needUpdatePos)
- {
- _numInByteBufs--;
- if (_numInByteBufs > 0)
- {
- _inByteBack = &_inByteVector[_numInByteBufs - 1];
- if (needUpdatePos)
- _inByteBack->_pos += _inByteVector[_numInByteBufs]._pos;
- }
- }
-
- 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 WaitId(UInt64 id);
-
- void Read_UInt32_Vector(CUInt32DefVector &v);
-
- void ReadArchiveProperties(CInArchiveInfo &archiveInfo);
- void ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs);
-
- void ReadPackInfo(CFolders &f);
-
- void ReadUnpackInfo(
- const CObjectVector<CByteBuffer> *dataVector,
- CFolders &folders);
-
- void ReadSubStreamsInfo(
- CFolders &folders,
- CRecordVector<UInt64> &unpackSizes,
- CUInt32DefVector &digests);
-
- void ReadStreamsInfo(
- const CObjectVector<CByteBuffer> *dataVector,
- UInt64 &dataOffset,
- CFolders &folders,
- CRecordVector<UInt64> &unpackSizes,
- CUInt32DefVector &digests);
-
- void ReadBoolVector(unsigned numItems, CBoolVector &v);
- void ReadBoolVector2(unsigned numItems, CBoolVector &v);
- void ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector,
- CUInt64DefVector &v, unsigned numItems);
- HRESULT ReadAndDecodePackedStreams(
- DECL_EXTERNAL_CODECS_LOC_VARS
- UInt64 baseOffset, UInt64 &dataOffset,
- CObjectVector<CByteBuffer> &dataVector
- _7Z_DECODER_CRYPRO_VARS_DECL
- );
- HRESULT ReadHeader(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CDbEx &db
- _7Z_DECODER_CRYPRO_VARS_DECL
- );
- HRESULT ReadDatabase2(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CDbEx &db
- _7Z_DECODER_CRYPRO_VARS_DECL
- );
-public:
- CInArchive(bool useMixerMT):
- _numInByteBufs(0),
- _useMixerMT(useMixerMT)
- {}
-
- HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive
- void Close();
-
- HRESULT ReadDatabase(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CDbEx &db
- _7Z_DECODER_CRYPRO_VARS_DECL
- );
-};
-
-}}
-
-#endif
+// 7zIn.h
+
+#ifndef ZIP7_INC_7Z_IN_H
+#define ZIP7_INC_7Z_IN_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#include "../../IPassword.h"
+#include "../../IStream.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/InBuffer.h"
+
+#include "7zItem.h"
+
+namespace NArchive {
+namespace N7z {
+
+/*
+ We don't need to init isEncrypted and passwordIsDefined
+ We must upgrade them only */
+
+#ifdef Z7_NO_CRYPTO
+#define Z7_7Z_DECODER_CRYPRO_VARS_DECL
+#define Z7_7Z_DECODER_CRYPRO_VARS
+#else
+#define Z7_7Z_DECODER_CRYPRO_VARS_DECL , ICryptoGetTextPassword *getTextPassword, bool &isEncrypted, bool &passwordIsDefined, UString &password
+#define Z7_7Z_DECODER_CRYPRO_VARS , getTextPassword, isEncrypted, passwordIsDefined, password
+#endif
+
+struct CParsedMethods
+{
+ Byte Lzma2Prop;
+ UInt32 LzmaDic;
+ CRecordVector<UInt64> IDs;
+
+ CParsedMethods(): Lzma2Prop(0), LzmaDic(0) {}
+};
+
+struct CFolderEx: public CFolder
+{
+ unsigned UnpackCoder;
+};
+
+struct CFolders
+{
+ CNum NumPackStreams;
+ CNum NumFolders;
+
+ CObjArray<UInt64> PackPositions; // NumPackStreams + 1
+ // CUInt32DefVector PackCRCs; // we don't use PackCRCs now
+
+ CUInt32DefVector FolderCRCs; // NumFolders
+ CObjArray<CNum> NumUnpackStreamsVector; // NumFolders
+
+ CObjArray<UInt64> CoderUnpackSizes; // including unpack sizes of bond coders
+ CObjArray<CNum> FoToCoderUnpackSizes; // NumFolders + 1
+ CObjArray<CNum> FoStartPackStreamIndex; // NumFolders + 1
+ CObjArray<Byte> FoToMainUnpackSizeIndex; // NumFolders
+
+ CObjArray<size_t> FoCodersDataOffset; // NumFolders + 1
+ CByteBuffer CodersData;
+
+ CParsedMethods ParsedMethods;
+
+ void ParseFolderInfo(unsigned folderIndex, CFolder &folder) const;
+ void ParseFolderEx(unsigned folderIndex, CFolderEx &folder) const
+ {
+ ParseFolderInfo(folderIndex, folder);
+ folder.UnpackCoder = FoToMainUnpackSizeIndex[folderIndex];
+ }
+
+ unsigned GetNumFolderUnpackSizes(unsigned folderIndex) const
+ {
+ return (unsigned)(FoToCoderUnpackSizes[folderIndex + 1] - FoToCoderUnpackSizes[folderIndex]);
+ }
+
+ UInt64 GetFolderUnpackSize(unsigned folderIndex) const
+ {
+ return CoderUnpackSizes[FoToCoderUnpackSizes[folderIndex] + FoToMainUnpackSizeIndex[folderIndex]];
+ }
+
+ UInt64 GetStreamPackSize(unsigned index) const
+ {
+ return PackPositions[index + 1] - PackPositions[index];
+ }
+
+ CFolders(): NumPackStreams(0), NumFolders(0) {}
+
+ void Clear()
+ {
+ NumPackStreams = 0;
+ PackPositions.Free();
+ // PackCRCs.Clear();
+
+ NumFolders = 0;
+ FolderCRCs.Clear();
+ NumUnpackStreamsVector.Free();
+ CoderUnpackSizes.Free();
+ FoToCoderUnpackSizes.Free();
+ FoStartPackStreamIndex.Free();
+ FoToMainUnpackSizeIndex.Free();
+ FoCodersDataOffset.Free();
+ CodersData.Free();
+ }
+};
+
+struct CDatabase: public CFolders
+{
+ CRecordVector<CFileItem> Files;
+
+ CUInt64DefVector CTime;
+ CUInt64DefVector ATime;
+ CUInt64DefVector MTime;
+ CUInt64DefVector StartPos;
+ CUInt32DefVector Attrib;
+ CBoolVector IsAnti;
+ /*
+ CBoolVector IsAux;
+ CByteBuffer SecureBuf;
+ CRecordVector<UInt32> SecureIDs;
+ */
+
+ CByteBuffer NamesBuf;
+ CObjArray<size_t> NameOffsets; // numFiles + 1, offsets of utf-16 symbols
+
+ /*
+ void ClearSecure()
+ {
+ SecureBuf.Free();
+ SecureIDs.Clear();
+ }
+ */
+
+ void Clear()
+ {
+ CFolders::Clear();
+ // ClearSecure();
+
+ NamesBuf.Free();
+ NameOffsets.Free();
+
+ Files.Clear();
+ CTime.Clear();
+ ATime.Clear();
+ MTime.Clear();
+ StartPos.Clear();
+ Attrib.Clear();
+ IsAnti.Clear();
+ // IsAux.Clear();
+ }
+
+ bool IsSolid() const
+ {
+ for (CNum i = 0; i < NumFolders; i++)
+ if (NumUnpackStreamsVector[i] > 1)
+ return true;
+ return false;
+ }
+ bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); }
+ // bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); }
+
+ /*
+ const void* GetName(unsigned index) const
+ {
+ if (!NameOffsets || !NamesBuf)
+ return NULL;
+ return (void *)((const Byte *)NamesBuf + NameOffsets[index] * 2);
+ };
+ */
+ void GetPath(unsigned index, UString &path) const;
+ HRESULT GetPath_Prop(unsigned index, PROPVARIANT *path) const throw();
+};
+
+
+struct CInArchiveInfo
+{
+ CArchiveVersion Version;
+ UInt64 StartPosition; // in stream
+ UInt64 StartPositionAfterHeader; // in stream
+ UInt64 DataStartPosition; // in stream
+ UInt64 DataStartPosition2; // in stream. it's for headers
+ CRecordVector<UInt64> FileInfoPopIDs;
+
+ void Clear()
+ {
+ StartPosition = 0;
+ StartPositionAfterHeader = 0;
+ DataStartPosition = 0;
+ DataStartPosition2 = 0;
+ FileInfoPopIDs.Clear();
+ }
+};
+
+
+struct CDbEx: public CDatabase
+{
+ CInArchiveInfo ArcInfo;
+
+ CObjArray<CNum> FolderStartFileIndex;
+ CObjArray<CNum> FileIndexToFolderIndexMap;
+
+ UInt64 HeadersSize;
+ UInt64 PhySize;
+ // UInt64 EndHeaderOffset; // relative to position after StartHeader (32 bytes)
+
+ /*
+ CRecordVector<size_t> SecureOffsets;
+ bool IsTree;
+ bool ThereAreAltStreams;
+ */
+
+ bool IsArc;
+ bool PhySizeWasConfirmed;
+
+ bool ThereIsHeaderError;
+ bool UnexpectedEnd;
+ // bool UnsupportedVersion;
+
+ bool StartHeaderWasRecovered;
+ bool UnsupportedFeatureWarning;
+ bool UnsupportedFeatureError;
+
+ /*
+ void ClearSecureEx()
+ {
+ ClearSecure();
+ SecureOffsets.Clear();
+ }
+ */
+
+ void Clear()
+ {
+ IsArc = false;
+ PhySizeWasConfirmed = false;
+
+ ThereIsHeaderError = false;
+ UnexpectedEnd = false;
+ // UnsupportedVersion = false;
+
+ StartHeaderWasRecovered = false;
+ UnsupportedFeatureError = false;
+ UnsupportedFeatureWarning = false;
+
+ /*
+ IsTree = false;
+ ThereAreAltStreams = false;
+ */
+
+ CDatabase::Clear();
+
+ // SecureOffsets.Clear();
+ ArcInfo.Clear();
+ FolderStartFileIndex.Free();
+ FileIndexToFolderIndexMap.Free();
+
+ HeadersSize = 0;
+ PhySize = 0;
+ // EndHeaderOffset = 0;
+ }
+
+ bool CanUpdate() const
+ {
+ if (ThereIsHeaderError
+ || UnexpectedEnd
+ || StartHeaderWasRecovered
+ || UnsupportedFeatureError)
+ return false;
+ return true;
+ }
+
+ void FillLinks();
+
+ UInt64 GetFolderStreamPos(CNum folderIndex, unsigned indexInFolder) const
+ {
+ return ArcInfo.DataStartPosition +
+ PackPositions[FoStartPackStreamIndex[folderIndex] + indexInFolder];
+ }
+
+ UInt64 GetFolderFullPackSize(CNum folderIndex) const
+ {
+ return
+ PackPositions[FoStartPackStreamIndex[folderIndex + 1]] -
+ PackPositions[FoStartPackStreamIndex[folderIndex]];
+ }
+
+ UInt64 GetFolderPackStreamSize(CNum folderIndex, unsigned streamIndex) const
+ {
+ size_t i = FoStartPackStreamIndex[folderIndex] + streamIndex;
+ return PackPositions[i + 1] - PackPositions[i];
+ }
+
+ UInt64 GetFilePackSize(CNum fileIndex) const
+ {
+ CNum folderIndex = FileIndexToFolderIndexMap[fileIndex];
+ if (folderIndex != kNumNoIndex)
+ if (FolderStartFileIndex[folderIndex] == fileIndex)
+ return GetFolderFullPackSize(folderIndex);
+ return 0;
+ }
+};
+
+const unsigned kNumBufLevelsMax = 4;
+
+struct CInByte2
+{
+ const Byte *_buffer;
+public:
+ size_t _size;
+ size_t _pos;
+
+ size_t GetRem() const { return _size - _pos; }
+ const Byte *GetPtr() const { return _buffer + _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 SkipDataNoCheck(UInt64 size) { _pos += (size_t)size; }
+ void SkipData(UInt64 size);
+
+ void SkipData();
+ void SkipRem() { _pos = _size; }
+ UInt64 ReadNumber();
+ CNum ReadNum();
+ UInt32 ReadUInt32();
+ UInt64 ReadUInt64();
+
+ void ParseFolder(CFolder &folder);
+};
+
+class CStreamSwitch;
+
+const UInt32 kHeaderSize = 32;
+
+class CInArchive
+{
+ friend class CStreamSwitch;
+
+ CMyComPtr<IInStream> _stream;
+
+ unsigned _numInByteBufs;
+ CInByte2 _inByteVector[kNumBufLevelsMax];
+
+ CInByte2 *_inByteBack;
+ bool ThereIsHeaderError;
+
+ UInt64 _arhiveBeginStreamPosition;
+ UInt64 _fileEndPosition;
+
+ UInt64 _rangeLimit; // relative to position after StartHeader (32 bytes)
+
+ Byte _header[kHeaderSize];
+
+ UInt64 HeadersSize;
+
+ bool _useMixerMT;
+
+ void AddByteStream(const Byte *buffer, size_t size);
+
+ void DeleteByteStream(bool needUpdatePos)
+ {
+ _numInByteBufs--;
+ if (_numInByteBufs > 0)
+ {
+ _inByteBack = &_inByteVector[_numInByteBufs - 1];
+ if (needUpdatePos)
+ _inByteBack->_pos += _inByteVector[_numInByteBufs]._pos;
+ }
+ }
+
+ 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 WaitId(UInt64 id);
+
+ void Read_UInt32_Vector(CUInt32DefVector &v);
+
+ void ReadArchiveProperties(CInArchiveInfo &archiveInfo);
+ void ReadHashDigests(unsigned numItems, CUInt32DefVector &crcs);
+
+ void ReadPackInfo(CFolders &f);
+
+ void ReadUnpackInfo(
+ const CObjectVector<CByteBuffer> *dataVector,
+ CFolders &folders);
+
+ void ReadSubStreamsInfo(
+ CFolders &folders,
+ CRecordVector<UInt64> &unpackSizes,
+ CUInt32DefVector &digests);
+
+ void ReadStreamsInfo(
+ const CObjectVector<CByteBuffer> *dataVector,
+ UInt64 &dataOffset,
+ CFolders &folders,
+ CRecordVector<UInt64> &unpackSizes,
+ CUInt32DefVector &digests);
+
+ void ReadBoolVector(unsigned numItems, CBoolVector &v);
+ void ReadBoolVector2(unsigned numItems, CBoolVector &v);
+ void ReadUInt64DefVector(const CObjectVector<CByteBuffer> &dataVector,
+ CUInt64DefVector &v, unsigned numItems);
+ HRESULT ReadAndDecodePackedStreams(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ UInt64 baseOffset, UInt64 &dataOffset,
+ CObjectVector<CByteBuffer> &dataVector
+ Z7_7Z_DECODER_CRYPRO_VARS_DECL
+ );
+ HRESULT ReadHeader(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CDbEx &db
+ Z7_7Z_DECODER_CRYPRO_VARS_DECL
+ );
+ HRESULT ReadDatabase2(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CDbEx &db
+ Z7_7Z_DECODER_CRYPRO_VARS_DECL
+ );
+public:
+ CInArchive(bool useMixerMT):
+ _numInByteBufs(0),
+ _useMixerMT(useMixerMT)
+ {}
+
+ HRESULT Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit); // S_FALSE means is not archive
+ void Close();
+
+ HRESULT ReadDatabase(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CDbEx &db
+ Z7_7Z_DECODER_CRYPRO_VARS_DECL
+ );
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/7z/7zItem.h b/CPP/7zip/Archive/7z/7zItem.h
index 90cf98c..e8c68be 100644
--- a/CPP/7zip/Archive/7z/7zItem.h
+++ b/CPP/7zip/Archive/7z/7zItem.h
@@ -1,202 +1,207 @@
-// 7zItem.h
-
-#ifndef __7Z_ITEM_H
-#define __7Z_ITEM_H
-
-#include "../../../Common/MyBuffer.h"
-#include "../../../Common/MyString.h"
-
-#include "../../Common/MethodId.h"
-
-#include "7zHeader.h"
-
-namespace NArchive {
-namespace N7z {
-
-typedef UInt32 CNum;
-const CNum kNumMax = 0x7FFFFFFF;
-const CNum kNumNoIndex = 0xFFFFFFFF;
-
-struct CCoderInfo
-{
- CMethodId MethodID;
- CByteBuffer Props;
- UInt32 NumStreams;
-
- bool IsSimpleCoder() const { return NumStreams == 1; }
-};
-
-
-struct CBond
-{
- UInt32 PackIndex;
- UInt32 UnpackIndex;
-};
-
-
-struct CFolder
-{
- CLASS_NO_COPY(CFolder)
-public:
- CObjArray2<CCoderInfo> Coders;
- CObjArray2<CBond> Bonds;
- CObjArray2<UInt32> PackStreams;
-
- CFolder() {}
-
- bool IsDecodingSupported() const { return Coders.Size() <= 32; }
-
- int Find_in_PackStreams(UInt32 packStream) const
- {
- FOR_VECTOR(i, PackStreams)
- if (PackStreams[i] == packStream)
- return i;
- return -1;
- }
-
- int FindBond_for_PackStream(UInt32 packStream) const
- {
- FOR_VECTOR(i, Bonds)
- if (Bonds[i].PackIndex == packStream)
- return i;
- return -1;
- }
-
- /*
- int FindBond_for_UnpackStream(UInt32 unpackStream) const
- {
- FOR_VECTOR(i, Bonds)
- if (Bonds[i].UnpackIndex == unpackStream)
- return i;
- return -1;
- }
-
- int FindOutCoder() const
- {
- for (int i = (int)Coders.Size() - 1; i >= 0; i--)
- if (FindBond_for_UnpackStream(i) < 0)
- return i;
- return -1;
- }
- */
-
- bool IsEncrypted() const
- {
- FOR_VECTOR(i, Coders)
- if (Coders[i].MethodID == k_AES)
- return true;
- return false;
- }
-};
-
-
-struct CUInt32DefVector
-{
- CBoolVector Defs;
- CRecordVector<UInt32> Vals;
-
- void ClearAndSetSize(unsigned newSize)
- {
- Defs.ClearAndSetSize(newSize);
- Vals.ClearAndSetSize(newSize);
- }
-
- void Clear()
- {
- Defs.Clear();
- Vals.Clear();
- }
-
- void ReserveDown()
- {
- Defs.ReserveDown();
- Vals.ReserveDown();
- }
-
- bool GetItem(unsigned index, UInt32 &value) const
- {
- if (index < Defs.Size() && Defs[index])
- {
- value = Vals[index];
- return true;
- }
- value = 0;
- return false;
- }
-
- bool ValidAndDefined(unsigned i) const { return i < Defs.Size() && Defs[i]; }
-
- bool CheckSize(unsigned size) const { return Defs.Size() == size || Defs.Size() == 0; }
-
- void SetItem(unsigned index, bool defined, UInt32 value);
-};
-
-
-struct CUInt64DefVector
-{
- CBoolVector Defs;
- CRecordVector<UInt64> Vals;
-
- void Clear()
- {
- Defs.Clear();
- Vals.Clear();
- }
-
- void ReserveDown()
- {
- Defs.ReserveDown();
- Vals.ReserveDown();
- }
-
- bool GetItem(unsigned index, UInt64 &value) const
- {
- if (index < Defs.Size() && Defs[index])
- {
- value = Vals[index];
- return true;
- }
- value = 0;
- return false;
- }
-
- bool CheckSize(unsigned size) const { return Defs.Size() == size || Defs.Size() == 0; }
-
- void SetItem(unsigned index, bool defined, UInt64 value);
-};
-
-
-struct CFileItem
-{
- UInt64 Size;
- UInt32 Crc;
- /*
- int Parent;
- bool IsAltStream;
- */
- bool HasStream; // Test it !!! it means that there is
- // stream in some folder. It can be empty stream
- bool IsDir;
- bool CrcDefined;
-
- /*
- void Clear()
- {
- HasStream = true;
- IsDir = false;
- CrcDefined = false;
- }
-
- CFileItem():
- // Parent(-1),
- // IsAltStream(false),
- HasStream(true),
- IsDir(false),
- CrcDefined(false),
- {}
- */
-};
-
-}}
-
-#endif
+// 7zItem.h
+
+#ifndef ZIP7_INC_7Z_ITEM_H
+#define ZIP7_INC_7Z_ITEM_H
+
+#include "../../../Common/MyBuffer.h"
+#include "../../../Common/MyString.h"
+
+#include "../../Common/MethodId.h"
+
+#include "7zHeader.h"
+
+namespace NArchive {
+namespace N7z {
+
+typedef UInt32 CNum;
+const CNum kNumMax = 0x7FFFFFFF;
+const CNum kNumNoIndex = 0xFFFFFFFF;
+
+struct CCoderInfo
+{
+ CMethodId MethodID;
+ CByteBuffer Props;
+ UInt32 NumStreams;
+
+ bool IsSimpleCoder() const { return NumStreams == 1; }
+};
+
+
+struct CBond
+{
+ UInt32 PackIndex;
+ UInt32 UnpackIndex;
+};
+
+
+struct CFolder
+{
+ Z7_CLASS_NO_COPY(CFolder)
+public:
+ CObjArray2<CCoderInfo> Coders;
+ CObjArray2<CBond> Bonds;
+ CObjArray2<UInt32> PackStreams;
+
+ CFolder() {}
+
+ bool IsDecodingSupported() const { return Coders.Size() <= 32; }
+
+ int Find_in_PackStreams(UInt32 packStream) const
+ {
+ FOR_VECTOR(i, PackStreams)
+ if (PackStreams[i] == packStream)
+ return (int)i;
+ return -1;
+ }
+
+ int FindBond_for_PackStream(UInt32 packStream) const
+ {
+ FOR_VECTOR(i, Bonds)
+ if (Bonds[i].PackIndex == packStream)
+ return (int)i;
+ return -1;
+ }
+
+ /*
+ int FindBond_for_UnpackStream(UInt32 unpackStream) const
+ {
+ FOR_VECTOR(i, Bonds)
+ if (Bonds[i].UnpackIndex == unpackStream)
+ return i;
+ return -1;
+ }
+
+ int FindOutCoder() const
+ {
+ for (int i = (int)Coders.Size() - 1; i >= 0; i--)
+ if (FindBond_for_UnpackStream(i) < 0)
+ return i;
+ return -1;
+ }
+ */
+
+ bool IsEncrypted() const
+ {
+ FOR_VECTOR(i, Coders)
+ if (Coders[i].MethodID == k_AES)
+ return true;
+ return false;
+ }
+};
+
+
+struct CUInt32DefVector
+{
+ CBoolVector Defs;
+ CRecordVector<UInt32> Vals;
+
+ void ClearAndSetSize(unsigned newSize)
+ {
+ Defs.ClearAndSetSize(newSize);
+ Vals.ClearAndSetSize(newSize);
+ }
+
+ void Clear()
+ {
+ Defs.Clear();
+ Vals.Clear();
+ }
+
+ void ReserveDown()
+ {
+ Defs.ReserveDown();
+ Vals.ReserveDown();
+ }
+
+ bool GetItem(unsigned index, UInt32 &value) const
+ {
+ if (index < Defs.Size() && Defs[index])
+ {
+ value = Vals[index];
+ return true;
+ }
+ value = 0;
+ return false;
+ }
+
+ bool ValidAndDefined(unsigned i) const { return i < Defs.Size() && Defs[i]; }
+
+ bool CheckSize(unsigned size) const { return Defs.Size() == size || Defs.Size() == 0; }
+
+ void SetItem(unsigned index, bool defined, UInt32 value);
+ void if_NonEmpty_FillResedue_with_false(unsigned numItems)
+ {
+ if (Defs.Size() != 0 && Defs.Size() < numItems)
+ SetItem(numItems - 1, false, 0);
+ }
+};
+
+
+struct CUInt64DefVector
+{
+ CBoolVector Defs;
+ CRecordVector<UInt64> Vals;
+
+ void Clear()
+ {
+ Defs.Clear();
+ Vals.Clear();
+ }
+
+ void ReserveDown()
+ {
+ Defs.ReserveDown();
+ Vals.ReserveDown();
+ }
+
+ bool GetItem(unsigned index, UInt64 &value) const
+ {
+ if (index < Defs.Size() && Defs[index])
+ {
+ value = Vals[index];
+ return true;
+ }
+ value = 0;
+ return false;
+ }
+
+ bool CheckSize(unsigned size) const { return Defs.Size() == size || Defs.Size() == 0; }
+
+ void SetItem(unsigned index, bool defined, UInt64 value);
+};
+
+
+struct CFileItem
+{
+ UInt64 Size;
+ UInt32 Crc;
+ /*
+ int Parent;
+ bool IsAltStream;
+ */
+ bool HasStream; // Test it !!! it means that there is
+ // stream in some folder. It can be empty stream
+ bool IsDir;
+ bool CrcDefined;
+
+ /*
+ void Clear()
+ {
+ HasStream = true;
+ IsDir = false;
+ CrcDefined = false;
+ }
+
+ CFileItem():
+ // Parent(-1),
+ // IsAltStream(false),
+ HasStream(true),
+ IsDir(false),
+ CrcDefined(false),
+ {}
+ */
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/7z/7zOut.cpp b/CPP/7zip/Archive/7z/7zOut.cpp
index 5bd3a41..7f8fa5b 100644
--- a/CPP/7zip/Archive/7z/7zOut.cpp
+++ b/CPP/7zip/Archive/7z/7zOut.cpp
@@ -1,901 +1,955 @@
-// 7zOut.cpp
-
-#include "StdAfx.h"
-
-#include "../../../../C/7zCrc.h"
-
-#include "../../../Common/AutoPtr.h"
-
-#include "../../Common/StreamObjects.h"
-
-#include "7zOut.h"
-
-namespace NArchive {
-namespace N7z {
-
-HRESULT COutArchive::WriteSignature()
-{
- Byte buf[8];
- memcpy(buf, kSignature, kSignatureSize);
- buf[kSignatureSize] = kMajorVersion;
- buf[kSignatureSize + 1] = 4;
- 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
- Byte buf[24];
- memset(buf, 0, 24);
- return WriteDirect(buf, 24);
-}
-
-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());
- unsigned i;
-
- for (i = 0; i < folder.Coders.Size(); i++)
- {
- const CCoderInfo &coder = folder.Coders[i];
- {
- UInt64 id = coder.MethodID;
- unsigned idSize;
- for (idSize = 1; idSize < sizeof(id); idSize++)
- if ((id >> (8 * idSize)) == 0)
- break;
- idSize &= 0xF;
- Byte temp[16];
- for (unsigned t = idSize; t != 0; t--, id >>= 8)
- temp[t] = (Byte)(id & 0xFF);
-
- Byte b = (Byte)(idSize);
- bool isComplex = !coder.IsSimpleCoder();
- b |= (isComplex ? 0x10 : 0);
-
- size_t propsSize = coder.Props.Size();
- b |= ((propsSize != 0) ? 0x20 : 0);
- temp[0] = b;
- WriteBytes(temp, idSize + 1);
- if (isComplex)
- {
- WriteNumber(coder.NumStreams);
- WriteNumber(1); // NumOutStreams;
- }
- if (propsSize == 0)
- continue;
- WriteNumber(propsSize);
- WriteBytes(coder.Props, propsSize);
- }
- }
-
- for (i = 0; i < folder.Bonds.Size(); i++)
- {
- const CBond &bond = folder.Bonds[i];
- WriteNumber(bond.PackIndex);
- WriteNumber(bond.UnpackIndex);
- }
-
- 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_VECTOR (i, boolVector)
- {
- if (boolVector[i])
- b |= mask;
- mask >>= 1;
- if (mask == 0)
- {
- WriteByte(b);
- mask = 0x80;
- b = 0;
- }
- }
- if (mask != 0x80)
- WriteByte(b);
-}
-
-static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; }
-
-void COutArchive::WritePropBoolVector(Byte id, const CBoolVector &boolVector)
-{
- WriteByte(id);
- WriteNumber(Bv_GetSizeInBytes(boolVector));
- WriteBoolVector(boolVector);
-}
-
-unsigned BoolVector_CountSum(const CBoolVector &v);
-
-void COutArchive::WriteHashDigests(const CUInt32DefVector &digests)
-{
- const unsigned numDefined = BoolVector_CountSum(digests.Defs);
- if (numDefined == 0)
- return;
-
- WriteByte(NID::kCRC);
- if (numDefined == digests.Defs.Size())
- WriteByte(1);
- else
- {
- WriteByte(0);
- WriteBoolVector(digests.Defs);
- }
-
- for (unsigned i = 0; i < digests.Defs.Size(); i++)
- if (digests.Defs[i])
- WriteUInt32(digests.Vals[i]);
-}
-
-void COutArchive::WritePackInfo(
- UInt64 dataOffset,
- const CRecordVector<UInt64> &packSizes,
- const CUInt32DefVector &packCRCs)
-{
- if (packSizes.IsEmpty())
- return;
- WriteByte(NID::kPackInfo);
- WriteNumber(dataOffset);
- WriteNumber(packSizes.Size());
- WriteByte(NID::kSize);
- FOR_VECTOR (i, packSizes)
- WriteNumber(packSizes[i]);
-
- WriteHashDigests(packCRCs);
-
- WriteByte(NID::kEnd);
-}
-
-void COutArchive::WriteUnpackInfo(const CObjectVector<CFolder> &folders, const COutFolders &outFolders)
-{
- if (folders.IsEmpty())
- return;
-
- WriteByte(NID::kUnpackInfo);
-
- WriteByte(NID::kFolder);
- WriteNumber(folders.Size());
- {
- WriteByte(0);
- FOR_VECTOR (i, folders)
- WriteFolder(folders[i]);
- }
-
- WriteByte(NID::kCodersUnpackSize);
- FOR_VECTOR (i, outFolders.CoderUnpackSizes)
- WriteNumber(outFolders.CoderUnpackSizes[i]);
-
- WriteHashDigests(outFolders.FolderUnpackCRCs);
-
- WriteByte(NID::kEnd);
-}
-
-void COutArchive::WriteSubStreamsInfo(const CObjectVector<CFolder> &folders,
- const COutFolders &outFolders,
- const CRecordVector<UInt64> &unpackSizes,
- const CUInt32DefVector &digests)
-{
- const CRecordVector<CNum> &numUnpackStreamsInFolders = outFolders.NumUnpackStreamsVector;
- WriteByte(NID::kSubStreamsInfo);
-
- unsigned 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;
- }
-
- for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
- if (numUnpackStreamsInFolders[i] > 1)
- {
- WriteByte(NID::kSize);
- CNum index = 0;
- for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
- {
- CNum num = numUnpackStreamsInFolders[i];
- for (CNum j = 0; j < num; j++)
- {
- if (j + 1 != num)
- WriteNumber(unpackSizes[index]);
- index++;
- }
- }
- break;
- }
-
- CUInt32DefVector digests2;
-
- unsigned digestIndex = 0;
- for (i = 0; i < folders.Size(); i++)
- {
- unsigned numSubStreams = (unsigned)numUnpackStreamsInFolders[i];
- if (numSubStreams == 1 && outFolders.FolderUnpackCRCs.ValidAndDefined(i))
- digestIndex++;
- else
- for (unsigned j = 0; j < numSubStreams; j++, digestIndex++)
- {
- digests2.Defs.Add(digests.Defs[digestIndex]);
- digests2.Vals.Add(digests.Vals[digestIndex]);
- }
- }
- WriteHashDigests(digests2);
- WriteByte(NID::kEnd);
-}
-
-// 7-Zip 4.50 - 4.58 contain BUG, so they do not support .7z archives with Unknown field.
-
-void COutArchive::SkipToAligned(unsigned pos, unsigned alignShifts)
-{
- if (!_useAlign)
- return;
-
- const unsigned alignSize = (unsigned)1 << alignShifts;
- 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);
-}
-
-void COutArchive::WriteAlignedBools(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSizeShifts)
-{
- const unsigned bvSize = (numDefined == v.Size()) ? 0 : Bv_GetSizeInBytes(v);
- const UInt64 dataSize = ((UInt64)numDefined << itemSizeShifts) + bvSize + 2;
- SkipToAligned(3 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), itemSizeShifts);
-
- WriteByte(type);
- WriteNumber(dataSize);
- if (numDefined == v.Size())
- WriteByte(1);
- else
- {
- WriteByte(0);
- WriteBoolVector(v);
- }
- WriteByte(0); // 0 means no switching to external stream
-}
-
-void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type)
-{
- const unsigned numDefined = BoolVector_CountSum(v.Defs);
- if (numDefined == 0)
- return;
-
- WriteAlignedBools(v.Defs, numDefined, type, 3);
-
- for (unsigned i = 0; i < v.Defs.Size(); i++)
- if (v.Defs[i])
- WriteUInt64(v.Vals[i]);
-}
-
-HRESULT COutArchive::EncodeStream(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CEncoder &encoder, const CByteBuffer &data,
- CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders, COutFolders &outFolders)
-{
- CBufInStream *streamSpec = new CBufInStream;
- CMyComPtr<ISequentialInStream> stream = streamSpec;
- streamSpec->Init(data, data.Size());
- outFolders.FolderUnpackCRCs.Defs.Add(true);
- outFolders.FolderUnpackCRCs.Vals.Add(CrcCalc(data, data.Size()));
- // outFolders.NumUnpackStreamsVector.Add(1);
- UInt64 dataSize64 = data.Size();
- UInt64 unpackSize = data.Size();
- RINOK(encoder.Encode(
- EXTERNAL_CODECS_LOC_VARS
- stream,
- // NULL,
- &dataSize64,
- folders.AddNew(), outFolders.CoderUnpackSizes, unpackSize, SeqStream, packSizes, NULL))
- return S_OK;
-}
-
-void COutArchive::WriteHeader(
- const CArchiveDatabaseOut &db,
- // const CHeaderOptions &headerOptions,
- UInt64 &headerOffset)
-{
- /*
- bool thereIsSecure = (db.SecureBuf.Size() != 0);
- */
- _useAlign = true;
-
- {
- UInt64 packSize = 0;
- FOR_VECTOR (i, db.PackSizes)
- packSize += db.PackSizes[i];
- headerOffset = packSize;
- }
-
-
- WriteByte(NID::kHeader);
-
- // Archive Properties
-
- if (db.Folders.Size() > 0)
- {
- WriteByte(NID::kMainStreamsInfo);
- WritePackInfo(0, db.PackSizes, db.PackCRCs);
- WriteUnpackInfo(db.Folders, (const COutFolders &)db);
-
- CRecordVector<UInt64> unpackSizes;
- CUInt32DefVector digests;
- FOR_VECTOR (i, db.Files)
- {
- const CFileItem &file = db.Files[i];
- if (!file.HasStream)
- continue;
- unpackSizes.Add(file.Size);
- digests.Defs.Add(file.CrcDefined);
- digests.Vals.Add(file.Crc);
- }
-
- WriteSubStreamsInfo(db.Folders, (const COutFolders &)db, unpackSizes, digests);
- WriteByte(NID::kEnd);
- }
-
- if (db.Files.IsEmpty())
- {
- WriteByte(NID::kEnd);
- return;
- }
-
- WriteByte(NID::kFilesInfo);
- WriteNumber(db.Files.Size());
-
- {
- /* ---------- Empty Streams ---------- */
- CBoolVector emptyStreamVector;
- emptyStreamVector.ClearAndSetSize(db.Files.Size());
- unsigned numEmptyStreams = 0;
- {
- FOR_VECTOR (i, db.Files)
- if (db.Files[i].HasStream)
- emptyStreamVector[i] = false;
- else
- {
- emptyStreamVector[i] = true;
- numEmptyStreams++;
- }
- }
-
- if (numEmptyStreams != 0)
- {
- WritePropBoolVector(NID::kEmptyStream, emptyStreamVector);
-
- CBoolVector emptyFileVector, antiVector;
- emptyFileVector.ClearAndSetSize(numEmptyStreams);
- antiVector.ClearAndSetSize(numEmptyStreams);
- bool thereAreEmptyFiles = false, thereAreAntiItems = false;
- unsigned cur = 0;
-
- FOR_VECTOR (i, db.Files)
- {
- const CFileItem &file = db.Files[i];
- if (file.HasStream)
- continue;
- emptyFileVector[cur] = !file.IsDir;
- if (!file.IsDir)
- thereAreEmptyFiles = true;
- bool isAnti = db.IsItemAnti(i);
- antiVector[cur] = isAnti;
- if (isAnti)
- thereAreAntiItems = true;
- cur++;
- }
-
- if (thereAreEmptyFiles)
- WritePropBoolVector(NID::kEmptyFile, emptyFileVector);
- if (thereAreAntiItems)
- WritePropBoolVector(NID::kAnti, antiVector);
- }
- }
-
-
- {
- /* ---------- Names ---------- */
-
- unsigned numDefined = 0;
- size_t namesDataSize = 0;
- FOR_VECTOR (i, db.Files)
- {
- const UString &name = db.Names[i];
- if (!name.IsEmpty())
- numDefined++;
- namesDataSize += (name.Len() + 1) * 2;
- }
-
- if (numDefined > 0)
- {
- namesDataSize++;
- SkipToAligned(2 + GetBigNumberSize(namesDataSize), 4);
-
- WriteByte(NID::kName);
- WriteNumber(namesDataSize);
- WriteByte(0);
- FOR_VECTOR (i, db.Files)
- {
- const UString &name = db.Names[i];
- for (unsigned t = 0; t <= name.Len(); 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 ---------- */
- const unsigned numDefined = BoolVector_CountSum(db.Attrib.Defs);
-
- if (numDefined != 0)
- {
- WriteAlignedBools(db.Attrib.Defs, numDefined, NID::kWinAttrib, 2);
- FOR_VECTOR (i, db.Attrib.Defs)
- {
- if (db.Attrib.Defs[i])
- WriteUInt32(db.Attrib.Vals[i]);
- }
- }
- }
-
- /*
- {
- // ---------- Write IsAux ----------
- if (BoolVector_CountSum(db.IsAux) != 0)
- WritePropBoolVector(NID::kIsAux, db.IsAux);
- }
-
- {
- // ---------- Write Parent ----------
- CBoolVector boolVector;
- boolVector.Reserve(db.Files.Size());
- unsigned numIsDir = 0;
- unsigned numParentLinks = 0;
- for (i = 0; i < db.Files.Size(); i++)
- {
- const CFileItem &file = db.Files[i];
- bool defined = !file.IsAltStream;
- boolVector.Add(defined);
- if (defined)
- numIsDir++;
- if (file.Parent >= 0)
- numParentLinks++;
- }
- if (numParentLinks > 0)
- {
- // WriteAlignedBools(boolVector, numDefined, NID::kParent, 2);
- const unsigned bvSize = (numIsDir == boolVector.Size()) ? 0 : Bv_GetSizeInBytes(boolVector);
- const UInt64 dataSize = (UInt64)db.Files.Size() * 4 + bvSize + 1;
- SkipToAligned(2 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), 2);
-
- WriteByte(NID::kParent);
- WriteNumber(dataSize);
- if (numIsDir == boolVector.Size())
- WriteByte(1);
- else
- {
- WriteByte(0);
- WriteBoolVector(boolVector);
- }
- for (i = 0; i < db.Files.Size(); i++)
- {
- const CFileItem &file = db.Files[i];
- // if (file.Parent >= 0)
- WriteUInt32(file.Parent);
- }
- }
- }
-
- if (thereIsSecure)
- {
- UInt64 secureDataSize = 1 + 4 +
- db.SecureBuf.Size() +
- db.SecureSizes.Size() * 4;
- // secureDataSize += db.SecureIDs.Size() * 4;
- for (i = 0; i < db.SecureIDs.Size(); i++)
- secureDataSize += GetBigNumberSize(db.SecureIDs[i]);
- SkipToAligned(2 + GetBigNumberSize(secureDataSize), 2);
- WriteByte(NID::kNtSecure);
- WriteNumber(secureDataSize);
- WriteByte(0);
- WriteUInt32(db.SecureSizes.Size());
- for (i = 0; i < db.SecureSizes.Size(); i++)
- WriteUInt32(db.SecureSizes[i]);
- WriteBytes(db.SecureBuf, db.SecureBuf.Size());
- for (i = 0; i < db.SecureIDs.Size(); i++)
- {
- WriteNumber(db.SecureIDs[i]);
- // WriteUInt32(db.SecureIDs[i]);
- }
- }
- */
-
- WriteByte(NID::kEnd); // for files
- WriteByte(NID::kEnd); // for headers
-}
-
-HRESULT COutArchive::WriteDatabase(
- DECL_EXTERNAL_CODECS_LOC_VARS
- const CArchiveDatabaseOut &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(_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;
- COutFolders outFolders;
-
- RINOK(EncodeStream(
- EXTERNAL_CODECS_LOC_VARS
- encoder, buf,
- packSizes, folders, outFolders));
-
- _writeToStream = true;
-
- if (folders.Size() == 0)
- throw 1;
-
- WriteID(NID::kEncodedHeader);
- WritePackInfo(headerOffset, packSizes, CUInt32DefVector());
- WriteUnpackInfo(folders, outFolders);
- WriteByte(NID::kEnd);
- FOR_VECTOR (i, packSizes)
- 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 CUInt32DefVector::SetItem(unsigned index, bool defined, UInt32 value)
-{
- while (index >= Defs.Size())
- Defs.Add(false);
- Defs[index] = defined;
- if (!defined)
- return;
- while (index >= Vals.Size())
- Vals.Add(0);
- Vals[index] = value;
-}
-
-void CUInt64DefVector::SetItem(unsigned index, bool defined, UInt64 value)
-{
- while (index >= Defs.Size())
- Defs.Add(false);
- Defs[index] = defined;
- if (!defined)
- return;
- while (index >= Vals.Size())
- Vals.Add(0);
- Vals[index] = value;
-}
-
-void CArchiveDatabaseOut::AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name)
-{
- unsigned 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);
- Attrib.SetItem(index, file2.AttribDefined, file2.Attrib);
- SetItem_Anti(index, file2.IsAnti);
- // SetItem_Aux(index, file2.IsAux);
- Names.Add(name);
- Files.Add(file);
-}
-
-}}
+// 7zOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/7zCrc.h"
+
+#include "../../../Common/AutoPtr.h"
+// #include "../../../Common/UTFConvert.h"
+
+#include "../../Common/StreamObjects.h"
+
+#include "7zOut.h"
+
+namespace NArchive {
+namespace N7z {
+
+static void FillSignature(Byte *buf)
+{
+ memcpy(buf, kSignature, kSignatureSize);
+ buf[kSignatureSize] = kMajorVersion;
+ buf[kSignatureSize + 1] = 4;
+}
+
+#ifdef Z7_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[32];
+ FillSignature(buf);
+ SetUInt64(buf + 8 + 4, h.NextHeaderOffset);
+ SetUInt64(buf + 8 + 12, h.NextHeaderSize);
+ SetUInt32(buf + 8 + 20, h.NextHeaderCRC);
+ SetUInt32(buf + 8, CrcCalc(buf + 8 + 4, 20));
+ return WriteDirect(buf, sizeof(buf));
+}
+
+#ifdef Z7_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_and_WriteStartPrefix(ISequentialOutStream *stream /* , bool endMarker */)
+{
+ Close();
+ #ifdef Z7_7Z_VOL
+ // endMarker = false;
+ _endMarker = endMarker;
+ #endif
+ SeqStream = stream;
+ // if (!endMarker)
+ {
+ SeqStream.QueryInterface(IID_IOutStream, &Stream);
+ if (!Stream)
+ {
+ return E_NOTIMPL;
+ // endMarker = true;
+ }
+ RINOK(Stream->Seek(0, STREAM_SEEK_CUR, &_signatureHeaderPos))
+ Byte buf[32];
+ FillSignature(buf);
+ memset(&buf[8], 0, 32 - 8);
+ return WriteDirect(buf, sizeof(buf));
+ }
+ #ifdef Z7_7Z_VOL
+ if (endMarker)
+ {
+ /*
+ CStartHeader sh;
+ sh.NextHeaderOffset = (UInt32)(Int32)-1;
+ sh.NextHeaderSize = (UInt32)(Int32)-1;
+ sh.NextHeaderCRC = 0;
+ WriteStartHeader(sh);
+ return S_OK;
+ */
+ }
+ #endif
+}
+
+void COutArchive::Close()
+{
+ SeqStream.Release();
+ Stream.Release();
+}
+
+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 = (Byte)(mask >> 1);
+ }
+ WriteByte(firstByte);
+ for (; i > 0; i--)
+ {
+ WriteByte((Byte)value);
+ value >>= 8;
+ }
+}
+
+static unsigned GetBigNumberSize(UInt64 value)
+{
+ unsigned i;
+ for (i = 1; i < 9; i++)
+ if (value < (((UInt64)1 << (i * 7))))
+ break;
+ return i;
+}
+
+#ifdef Z7_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());
+ unsigned i;
+
+ for (i = 0; i < folder.Coders.Size(); i++)
+ {
+ const CCoderInfo &coder = folder.Coders[i];
+ {
+ UInt64 id = coder.MethodID;
+ unsigned idSize;
+ for (idSize = 1; idSize < sizeof(id); idSize++)
+ if ((id >> (8 * idSize)) == 0)
+ break;
+ // idSize &= 0xF; // idSize is smaller than 16 already
+ Byte temp[16];
+ for (unsigned t = idSize; t != 0; t--, id >>= 8)
+ temp[t] = (Byte)(id & 0xFF);
+
+ unsigned b = idSize;
+ const bool isComplex = !coder.IsSimpleCoder();
+ b |= (isComplex ? 0x10 : 0);
+
+ const size_t propsSize = coder.Props.Size();
+ b |= ((propsSize != 0) ? 0x20 : 0);
+ temp[0] = (Byte)b;
+ WriteBytes(temp, idSize + 1);
+ if (isComplex)
+ {
+ WriteNumber(coder.NumStreams);
+ WriteNumber(1); // NumOutStreams;
+ }
+ if (propsSize == 0)
+ continue;
+ WriteNumber(propsSize);
+ WriteBytes(coder.Props, propsSize);
+ }
+ }
+
+ for (i = 0; i < folder.Bonds.Size(); i++)
+ {
+ const CBond &bond = folder.Bonds[i];
+ WriteNumber(bond.PackIndex);
+ WriteNumber(bond.UnpackIndex);
+ }
+
+ 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_VECTOR (i, boolVector)
+ {
+ if (boolVector[i])
+ b |= mask;
+ mask = (Byte)(mask >> 1);
+ if (mask == 0)
+ {
+ WriteByte(b);
+ mask = 0x80;
+ b = 0;
+ }
+ }
+ if (mask != 0x80)
+ WriteByte(b);
+}
+
+static inline unsigned Bv_GetSizeInBytes(const CBoolVector &v) { return ((unsigned)v.Size() + 7) / 8; }
+
+void COutArchive::WritePropBoolVector(Byte id, const CBoolVector &boolVector)
+{
+ WriteByte(id);
+ WriteNumber(Bv_GetSizeInBytes(boolVector));
+ WriteBoolVector(boolVector);
+}
+
+unsigned BoolVector_CountSum(const CBoolVector &v);
+
+void COutArchive::WriteHashDigests(const CUInt32DefVector &digests)
+{
+ const unsigned numDefined = BoolVector_CountSum(digests.Defs);
+ if (numDefined == 0)
+ return;
+
+ WriteByte(NID::kCRC);
+ if (numDefined == digests.Defs.Size())
+ WriteByte(1);
+ else
+ {
+ WriteByte(0);
+ WriteBoolVector(digests.Defs);
+ }
+
+ for (unsigned i = 0; i < digests.Defs.Size(); i++)
+ if (digests.Defs[i])
+ WriteUInt32(digests.Vals[i]);
+}
+
+void COutArchive::WritePackInfo(
+ UInt64 dataOffset,
+ const CRecordVector<UInt64> &packSizes,
+ const CUInt32DefVector &packCRCs)
+{
+ if (packSizes.IsEmpty())
+ return;
+ WriteByte(NID::kPackInfo);
+ WriteNumber(dataOffset);
+ WriteNumber(packSizes.Size());
+ WriteByte(NID::kSize);
+ FOR_VECTOR (i, packSizes)
+ WriteNumber(packSizes[i]);
+
+ WriteHashDigests(packCRCs);
+
+ WriteByte(NID::kEnd);
+}
+
+void COutArchive::WriteUnpackInfo(const CObjectVector<CFolder> &folders, const COutFolders &outFolders)
+{
+ if (folders.IsEmpty())
+ return;
+
+ WriteByte(NID::kUnpackInfo);
+
+ WriteByte(NID::kFolder);
+ WriteNumber(folders.Size());
+ {
+ WriteByte(0);
+ FOR_VECTOR (i, folders)
+ WriteFolder(folders[i]);
+ }
+
+ WriteByte(NID::kCodersUnpackSize);
+ FOR_VECTOR (i, outFolders.CoderUnpackSizes)
+ WriteNumber(outFolders.CoderUnpackSizes[i]);
+
+ WriteHashDigests(outFolders.FolderUnpackCRCs);
+
+ WriteByte(NID::kEnd);
+}
+
+void COutArchive::WriteSubStreamsInfo(const CObjectVector<CFolder> &folders,
+ const COutFolders &outFolders,
+ const CRecordVector<UInt64> &unpackSizes,
+ const CUInt32DefVector &digests)
+{
+ const CRecordVector<CNum> &numUnpackStreamsInFolders = outFolders.NumUnpackStreamsVector;
+ WriteByte(NID::kSubStreamsInfo);
+
+ unsigned 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;
+ }
+
+ for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
+ if (numUnpackStreamsInFolders[i] > 1)
+ {
+ WriteByte(NID::kSize);
+ CNum index = 0;
+ for (i = 0; i < numUnpackStreamsInFolders.Size(); i++)
+ {
+ CNum num = numUnpackStreamsInFolders[i];
+ for (CNum j = 0; j < num; j++)
+ {
+ if (j + 1 != num)
+ WriteNumber(unpackSizes[index]);
+ index++;
+ }
+ }
+ break;
+ }
+
+ CUInt32DefVector digests2;
+
+ unsigned digestIndex = 0;
+ for (i = 0; i < folders.Size(); i++)
+ {
+ unsigned numSubStreams = (unsigned)numUnpackStreamsInFolders[i];
+ if (numSubStreams == 1 && outFolders.FolderUnpackCRCs.ValidAndDefined(i))
+ digestIndex++;
+ else
+ for (unsigned j = 0; j < numSubStreams; j++, digestIndex++)
+ {
+ digests2.Defs.Add(digests.Defs[digestIndex]);
+ digests2.Vals.Add(digests.Vals[digestIndex]);
+ }
+ }
+ WriteHashDigests(digests2);
+ WriteByte(NID::kEnd);
+}
+
+// 7-Zip 4.50 - 4.58 contain BUG, so they do not support .7z archives with Unknown field.
+
+void COutArchive::SkipToAligned(unsigned pos, unsigned alignShifts)
+{
+ if (!_useAlign)
+ return;
+
+ const unsigned alignSize = (unsigned)1 << alignShifts;
+ 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);
+}
+
+void COutArchive::WriteAlignedBools(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSizeShifts)
+{
+ const unsigned bvSize = (numDefined == v.Size()) ? 0 : Bv_GetSizeInBytes(v);
+ const UInt64 dataSize = ((UInt64)numDefined << itemSizeShifts) + bvSize + 2;
+ SkipToAligned(3 + bvSize + GetBigNumberSize(dataSize), itemSizeShifts);
+
+ WriteByte(type);
+ WriteNumber(dataSize);
+ if (numDefined == v.Size())
+ WriteByte(1);
+ else
+ {
+ WriteByte(0);
+ WriteBoolVector(v);
+ }
+ WriteByte(0); // 0 means no switching to external stream
+}
+
+void COutArchive::WriteUInt64DefVector(const CUInt64DefVector &v, Byte type)
+{
+ const unsigned numDefined = BoolVector_CountSum(v.Defs);
+ if (numDefined == 0)
+ return;
+
+ WriteAlignedBools(v.Defs, numDefined, type, 3);
+
+ for (unsigned i = 0; i < v.Defs.Size(); i++)
+ if (v.Defs[i])
+ WriteUInt64(v.Vals[i]);
+}
+
+HRESULT COutArchive::EncodeStream(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CEncoder &encoder, const CByteBuffer &data,
+ CRecordVector<UInt64> &packSizes, CObjectVector<CFolder> &folders, COutFolders &outFolders)
+{
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> stream = streamSpec;
+ streamSpec->Init(data, data.Size());
+ outFolders.FolderUnpackCRCs.Defs.Add(true);
+ outFolders.FolderUnpackCRCs.Vals.Add(CrcCalc(data, data.Size()));
+ // outFolders.NumUnpackStreamsVector.Add(1);
+ const UInt64 dataSize64 = data.Size();
+ const UInt64 expectSize = data.Size();
+ RINOK(encoder.Encode1(
+ EXTERNAL_CODECS_LOC_VARS
+ stream,
+ // NULL,
+ &dataSize64, // inSizeForReduce
+ expectSize,
+ folders.AddNew(),
+ // outFolders.CoderUnpackSizes, unpackSize,
+ SeqStream, packSizes, NULL))
+ if (!streamSpec->WasFinished())
+ return E_FAIL;
+ encoder.Encode_Post(dataSize64, outFolders.CoderUnpackSizes);
+ return S_OK;
+}
+
+void COutArchive::WriteHeader(
+ const CArchiveDatabaseOut &db,
+ // const CHeaderOptions &headerOptions,
+ UInt64 &headerOffset)
+{
+ /*
+ bool thereIsSecure = (db.SecureBuf.Size() != 0);
+ */
+ _useAlign = true;
+
+ {
+ UInt64 packSize = 0;
+ FOR_VECTOR (i, db.PackSizes)
+ packSize += db.PackSizes[i];
+ headerOffset = packSize;
+ }
+
+
+ WriteByte(NID::kHeader);
+
+ /*
+ {
+ // It's example for per archive properies writing
+
+ WriteByte(NID::kArchiveProperties);
+
+ // you must use random 40-bit number that will identify you
+ // then you can use same kDeveloperID for any properties and methods
+ const UInt64 kDeveloperID = 0x123456789A; // change that value to real random 40-bit number
+
+ #define GENERATE_7Z_ID(developerID, subID) (((UInt64)0x3F << 56) | ((UInt64)developerID << 16) | subID)
+
+ {
+ const UInt64 kSubID = 0x1; // you can use small number for subID
+ const UInt64 kID = GENERATE_7Z_ID(kDeveloperID, kSubID);
+ WriteNumber(kID);
+ const unsigned kPropsSize = 3; // it's example size
+ WriteNumber(kPropsSize);
+ for (unsigned i = 0; i < kPropsSize; i++)
+ WriteByte((Byte)(i & 0xFF));
+ }
+ {
+ const UInt64 kSubID = 0x2; // you can use small number for subID
+ const UInt64 kID = GENERATE_7Z_ID(kDeveloperID, kSubID);
+ WriteNumber(kID);
+ const unsigned kPropsSize = 5; // it's example size
+ WriteNumber(kPropsSize);
+ for (unsigned i = 0; i < kPropsSize; i++)
+ WriteByte((Byte)(i + 16));
+ }
+ WriteByte(NID::kEnd);
+ }
+ */
+
+ if (db.Folders.Size() > 0)
+ {
+ WriteByte(NID::kMainStreamsInfo);
+ WritePackInfo(0, db.PackSizes, db.PackCRCs);
+ WriteUnpackInfo(db.Folders, (const COutFolders &)db);
+
+ CRecordVector<UInt64> unpackSizes;
+ CUInt32DefVector digests;
+ FOR_VECTOR (i, db.Files)
+ {
+ const CFileItem &file = db.Files[i];
+ if (!file.HasStream)
+ continue;
+ unpackSizes.Add(file.Size);
+ digests.Defs.Add(file.CrcDefined);
+ digests.Vals.Add(file.Crc);
+ }
+
+ WriteSubStreamsInfo(db.Folders, (const COutFolders &)db, unpackSizes, digests);
+ WriteByte(NID::kEnd);
+ }
+
+ if (db.Files.IsEmpty())
+ {
+ WriteByte(NID::kEnd);
+ return;
+ }
+
+ WriteByte(NID::kFilesInfo);
+ WriteNumber(db.Files.Size());
+
+ {
+ /* ---------- Empty Streams ---------- */
+ CBoolVector emptyStreamVector;
+ emptyStreamVector.ClearAndSetSize(db.Files.Size());
+ unsigned numEmptyStreams = 0;
+ {
+ FOR_VECTOR (i, db.Files)
+ if (db.Files[i].HasStream)
+ emptyStreamVector[i] = false;
+ else
+ {
+ emptyStreamVector[i] = true;
+ numEmptyStreams++;
+ }
+ }
+
+ if (numEmptyStreams != 0)
+ {
+ WritePropBoolVector(NID::kEmptyStream, emptyStreamVector);
+
+ CBoolVector emptyFileVector, antiVector;
+ emptyFileVector.ClearAndSetSize(numEmptyStreams);
+ antiVector.ClearAndSetSize(numEmptyStreams);
+ bool thereAreEmptyFiles = false, thereAreAntiItems = false;
+ unsigned cur = 0;
+
+ FOR_VECTOR (i, db.Files)
+ {
+ const CFileItem &file = db.Files[i];
+ if (file.HasStream)
+ continue;
+ emptyFileVector[cur] = !file.IsDir;
+ if (!file.IsDir)
+ thereAreEmptyFiles = true;
+ bool isAnti = db.IsItemAnti(i);
+ antiVector[cur] = isAnti;
+ if (isAnti)
+ thereAreAntiItems = true;
+ cur++;
+ }
+
+ if (thereAreEmptyFiles)
+ WritePropBoolVector(NID::kEmptyFile, emptyFileVector);
+ if (thereAreAntiItems)
+ WritePropBoolVector(NID::kAnti, antiVector);
+ }
+ }
+
+
+ {
+ /* ---------- Names ---------- */
+
+ unsigned numDefined = 0;
+ size_t namesDataSize = 0;
+ FOR_VECTOR (i, db.Files)
+ {
+ const UString &name = db.Names[i];
+ if (!name.IsEmpty())
+ numDefined++;
+ const size_t numUtfChars =
+ /*
+ #if WCHAR_MAX > 0xffff
+ Get_Num_Utf16_chars_from_wchar_string(name.Ptr());
+ #else
+ */
+ name.Len();
+ // #endif
+ namesDataSize += (numUtfChars + 1) * 2;
+ }
+
+ if (numDefined > 0)
+ {
+ namesDataSize++;
+ SkipToAligned(2 + GetBigNumberSize(namesDataSize), 4);
+
+ WriteByte(NID::kName);
+ WriteNumber(namesDataSize);
+ WriteByte(0);
+ FOR_VECTOR (i, db.Files)
+ {
+ const UString &name = db.Names[i];
+ for (unsigned t = 0; t <= name.Len(); t++)
+ {
+ wchar_t c = name[t];
+
+ /*
+ #if WCHAR_MAX > 0xffff
+ if (c >= 0x10000)
+ {
+ c -= 0x10000;
+ if (c < (1 << 20))
+ {
+ unsigned c0 = 0xd800 + ((c >> 10) & 0x3FF);
+ WriteByte((Byte)c0);
+ WriteByte((Byte)(c0 >> 8));
+ c = 0xdc00 + (c & 0x3FF);
+ }
+ else
+ c = '_'; // we change character unsupported by UTF16
+ }
+ #endif
+ */
+
+ 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 ---------- */
+ const unsigned numDefined = BoolVector_CountSum(db.Attrib.Defs);
+
+ if (numDefined != 0)
+ {
+ WriteAlignedBools(db.Attrib.Defs, numDefined, NID::kWinAttrib, 2);
+ FOR_VECTOR (i, db.Attrib.Defs)
+ {
+ if (db.Attrib.Defs[i])
+ WriteUInt32(db.Attrib.Vals[i]);
+ }
+ }
+ }
+
+ /*
+ {
+ // ---------- Write IsAux ----------
+ if (BoolVector_CountSum(db.IsAux) != 0)
+ WritePropBoolVector(NID::kIsAux, db.IsAux);
+ }
+
+ {
+ // ---------- Write Parent ----------
+ CBoolVector boolVector;
+ boolVector.Reserve(db.Files.Size());
+ unsigned numIsDir = 0;
+ unsigned numParentLinks = 0;
+ for (i = 0; i < db.Files.Size(); i++)
+ {
+ const CFileItem &file = db.Files[i];
+ bool defined = !file.IsAltStream;
+ boolVector.Add(defined);
+ if (defined)
+ numIsDir++;
+ if (file.Parent >= 0)
+ numParentLinks++;
+ }
+ if (numParentLinks > 0)
+ {
+ // WriteAlignedBools(boolVector, numDefined, NID::kParent, 2);
+ const unsigned bvSize = (numIsDir == boolVector.Size()) ? 0 : Bv_GetSizeInBytes(boolVector);
+ const UInt64 dataSize = (UInt64)db.Files.Size() * 4 + bvSize + 1;
+ SkipToAligned(2 + (unsigned)bvSize + (unsigned)GetBigNumberSize(dataSize), 2);
+
+ WriteByte(NID::kParent);
+ WriteNumber(dataSize);
+ if (numIsDir == boolVector.Size())
+ WriteByte(1);
+ else
+ {
+ WriteByte(0);
+ WriteBoolVector(boolVector);
+ }
+ for (i = 0; i < db.Files.Size(); i++)
+ {
+ const CFileItem &file = db.Files[i];
+ // if (file.Parent >= 0)
+ WriteUInt32(file.Parent);
+ }
+ }
+ }
+
+ if (thereIsSecure)
+ {
+ UInt64 secureDataSize = 1 + 4 +
+ db.SecureBuf.Size() +
+ db.SecureSizes.Size() * 4;
+ // secureDataSize += db.SecureIDs.Size() * 4;
+ for (i = 0; i < db.SecureIDs.Size(); i++)
+ secureDataSize += GetBigNumberSize(db.SecureIDs[i]);
+ SkipToAligned(2 + GetBigNumberSize(secureDataSize), 2);
+ WriteByte(NID::kNtSecure);
+ WriteNumber(secureDataSize);
+ WriteByte(0);
+ WriteUInt32(db.SecureSizes.Size());
+ for (i = 0; i < db.SecureSizes.Size(); i++)
+ WriteUInt32(db.SecureSizes[i]);
+ WriteBytes(db.SecureBuf, db.SecureBuf.Size());
+ for (i = 0; i < db.SecureIDs.Size(); i++)
+ {
+ WriteNumber(db.SecureIDs[i]);
+ // WriteUInt32(db.SecureIDs[i]);
+ }
+ }
+ */
+
+ WriteByte(NID::kEnd); // for files
+ WriteByte(NID::kEnd); // for headers
+}
+
+HRESULT COutArchive::WriteDatabase(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const CArchiveDatabaseOut &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(NULL, 0);
+ }
+ else
+ {
+ bool encodeHeaders = false;
+ if (options)
+ if (options->IsEmpty())
+ options = NULL;
+ if (options)
+ 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(_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;
+ COutFolders outFolders;
+
+ RINOK(EncodeStream(
+ EXTERNAL_CODECS_LOC_VARS
+ encoder, buf,
+ packSizes, folders, outFolders))
+
+ _writeToStream = true;
+
+ if (folders.Size() == 0)
+ throw 1;
+
+ WriteID(NID::kEncodedHeader);
+ WritePackInfo(headerOffset, packSizes, CUInt32DefVector());
+ WriteUnpackInfo(folders, outFolders);
+ WriteByte(NID::kEnd);
+ FOR_VECTOR (i, packSizes)
+ headerOffset += packSizes[i];
+ }
+ RINOK(_outByte.Flush())
+ headerCRC = CRC_GET_DIGEST(_crc);
+ headerSize = _outByte.GetProcessedSize();
+ }
+ #ifdef Z7_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
+ if (Stream)
+ {
+ CStartHeader h;
+ h.NextHeaderSize = headerSize;
+ h.NextHeaderCRC = headerCRC;
+ h.NextHeaderOffset = headerOffset;
+ RINOK(Stream->Seek((Int64)_signatureHeaderPos, STREAM_SEEK_SET, NULL))
+ return WriteStartHeader(h);
+ }
+ return S_OK;
+}
+
+void CUInt32DefVector::SetItem(unsigned index, bool defined, UInt32 value)
+{
+ while (index >= Defs.Size())
+ Defs.Add(false);
+ Defs[index] = defined;
+ if (!defined)
+ return;
+ while (index >= Vals.Size())
+ Vals.Add(0);
+ Vals[index] = value;
+}
+
+void CUInt64DefVector::SetItem(unsigned index, bool defined, UInt64 value)
+{
+ while (index >= Defs.Size())
+ Defs.Add(false);
+ Defs[index] = defined;
+ if (!defined)
+ return;
+ while (index >= Vals.Size())
+ Vals.Add(0);
+ Vals[index] = value;
+}
+
+void CArchiveDatabaseOut::AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name)
+{
+ unsigned 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);
+ Attrib.SetItem(index, file2.AttribDefined, file2.Attrib);
+ SetItem_Anti(index, file2.IsAnti);
+ // SetItem_Aux(index, file2.IsAux);
+ Names.Add(name);
+ Files.Add(file);
+}
+
+}}
diff --git a/CPP/7zip/Archive/7z/7zOut.h b/CPP/7zip/Archive/7z/7zOut.h
index 12e965f..940cafc 100644
--- a/CPP/7zip/Archive/7z/7zOut.h
+++ b/CPP/7zip/Archive/7z/7zOut.h
@@ -1,335 +1,330 @@
-// 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"
-#include "../../Common/StreamUtils.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 == 0)
- return;
- 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)
- */
- {}
-};
-
-
-struct CFileItem2
-{
- UInt64 CTime;
- UInt64 ATime;
- UInt64 MTime;
- UInt64 StartPos;
- UInt32 Attrib;
-
- bool CTimeDefined;
- bool ATimeDefined;
- bool MTimeDefined;
- bool StartPosDefined;
- bool AttribDefined;
- bool IsAnti;
- // bool IsAux;
-
- /*
- void Init()
- {
- CTimeDefined = false;
- ATimeDefined = false;
- MTimeDefined = false;
- StartPosDefined = false;
- AttribDefined = false;
- IsAnti = false;
- // IsAux = false;
- }
- */
-};
-
-
-struct COutFolders
-{
- CUInt32DefVector FolderUnpackCRCs; // Now we use it for headers only.
-
- CRecordVector<CNum> NumUnpackStreamsVector;
- CRecordVector<UInt64> CoderUnpackSizes; // including unpack sizes of bond coders
-
- void OutFoldersClear()
- {
- FolderUnpackCRCs.Clear();
- NumUnpackStreamsVector.Clear();
- CoderUnpackSizes.Clear();
- }
-
- void OutFoldersReserveDown()
- {
- FolderUnpackCRCs.ReserveDown();
- NumUnpackStreamsVector.ReserveDown();
- CoderUnpackSizes.ReserveDown();
- }
-};
-
-
-struct CArchiveDatabaseOut: public COutFolders
-{
- CRecordVector<UInt64> PackSizes;
- CUInt32DefVector PackCRCs;
- CObjectVector<CFolder> Folders;
-
- CRecordVector<CFileItem> Files;
- UStringVector Names;
- CUInt64DefVector CTime;
- CUInt64DefVector ATime;
- CUInt64DefVector MTime;
- CUInt64DefVector StartPos;
- CUInt32DefVector Attrib;
- CBoolVector IsAnti;
-
- /*
- CBoolVector IsAux;
-
- CByteBuffer SecureBuf;
- CRecordVector<UInt32> SecureSizes;
- CRecordVector<UInt32> SecureIDs;
-
- void ClearSecure()
- {
- SecureBuf.Free();
- SecureSizes.Clear();
- SecureIDs.Clear();
- }
- */
-
- void Clear()
- {
- OutFoldersClear();
-
- PackSizes.Clear();
- PackCRCs.Clear();
- Folders.Clear();
-
- Files.Clear();
- Names.Clear();
- CTime.Clear();
- ATime.Clear();
- MTime.Clear();
- StartPos.Clear();
- Attrib.Clear();
- IsAnti.Clear();
-
- /*
- IsAux.Clear();
- ClearSecure();
- */
- }
-
- void ReserveDown()
- {
- OutFoldersReserveDown();
-
- PackSizes.ReserveDown();
- PackCRCs.ReserveDown();
- Folders.ReserveDown();
-
- Files.ReserveDown();
- Names.ReserveDown();
- CTime.ReserveDown();
- ATime.ReserveDown();
- MTime.ReserveDown();
- StartPos.ReserveDown();
- Attrib.ReserveDown();
- IsAnti.ReserveDown();
-
- /*
- IsAux.ReserveDown();
- */
- }
-
- bool IsEmpty() const
- {
- return (
- PackSizes.IsEmpty() &&
- NumUnpackStreamsVector.IsEmpty() &&
- Folders.IsEmpty() &&
- Files.IsEmpty());
- }
-
- bool CheckNumFiles() const
- {
- unsigned size = Files.Size();
- return (
- CTime.CheckSize(size)
- && ATime.CheckSize(size)
- && MTime.CheckSize(size)
- && StartPos.CheckSize(size)
- && Attrib.CheckSize(size)
- && (size == IsAnti.Size() || IsAnti.Size() == 0));
- }
-
- bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); }
- // bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); }
-
- void SetItem_Anti(unsigned index, bool isAnti)
- {
- while (index >= IsAnti.Size())
- IsAnti.Add(false);
- IsAnti[index] = isAnti;
- }
- /*
- void SetItem_Aux(unsigned index, bool isAux)
- {
- while (index >= IsAux.Size())
- IsAux.Add(false);
- IsAux[index] = isAux;
- }
- */
-
- void AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name);
-};
-
-
-class COutArchive
-{
- UInt64 _prefixHeaderPos;
-
- HRESULT WriteDirect(const void *data, UInt32 size) { return WriteStream(SeqStream, data, size); }
-
- UInt64 GetPos() const;
- void WriteBytes(const void *data, size_t size);
- void WriteBytes(const CByteBuffer &data) { WriteBytes(data, data.Size()); }
- 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 WritePropBoolVector(Byte id, const CBoolVector &boolVector);
-
- void WriteHashDigests(const CUInt32DefVector &digests);
-
- void WritePackInfo(
- UInt64 dataOffset,
- const CRecordVector<UInt64> &packSizes,
- const CUInt32DefVector &packCRCs);
-
- void WriteUnpackInfo(
- const CObjectVector<CFolder> &folders,
- const COutFolders &outFolders);
-
- void WriteSubStreamsInfo(
- const CObjectVector<CFolder> &folders,
- const COutFolders &outFolders,
- const CRecordVector<UInt64> &unpackSizes,
- const CUInt32DefVector &digests);
-
- void SkipToAligned(unsigned pos, unsigned alignShifts);
- void WriteAlignedBools(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSizeShifts);
- 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, COutFolders &outFolders);
- void WriteHeader(
- const CArchiveDatabaseOut &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
-
- bool _useAlign;
-
- 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 CArchiveDatabaseOut &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
+// 7zOut.h
+
+#ifndef ZIP7_INC_7Z_OUT_H
+#define ZIP7_INC_7Z_OUT_H
+
+#include "7zCompressionMode.h"
+#include "7zEncode.h"
+#include "7zHeader.h"
+#include "7zItem.h"
+
+#include "../../Common/OutBuffer.h"
+#include "../../Common/StreamUtils.h"
+
+namespace NArchive {
+namespace N7z {
+
+const unsigned k_StartHeadersRewriteSize = 32;
+
+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 == 0)
+ return;
+ 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)
+ */
+ {}
+};
+
+
+struct CFileItem2
+{
+ UInt64 CTime;
+ UInt64 ATime;
+ UInt64 MTime;
+ UInt64 StartPos;
+ UInt32 Attrib;
+
+ bool CTimeDefined;
+ bool ATimeDefined;
+ bool MTimeDefined;
+ bool StartPosDefined;
+ bool AttribDefined;
+ bool IsAnti;
+ // bool IsAux;
+
+ /*
+ void Init()
+ {
+ CTimeDefined = false;
+ ATimeDefined = false;
+ MTimeDefined = false;
+ StartPosDefined = false;
+ AttribDefined = false;
+ IsAnti = false;
+ // IsAux = false;
+ }
+ */
+};
+
+
+struct COutFolders
+{
+ CUInt32DefVector FolderUnpackCRCs; // Now we use it for headers only.
+
+ CRecordVector<CNum> NumUnpackStreamsVector;
+ CRecordVector<UInt64> CoderUnpackSizes; // including unpack sizes of bond coders
+
+ void OutFoldersClear()
+ {
+ FolderUnpackCRCs.Clear();
+ NumUnpackStreamsVector.Clear();
+ CoderUnpackSizes.Clear();
+ }
+
+ void OutFoldersReserveDown()
+ {
+ FolderUnpackCRCs.ReserveDown();
+ NumUnpackStreamsVector.ReserveDown();
+ CoderUnpackSizes.ReserveDown();
+ }
+};
+
+
+struct CArchiveDatabaseOut: public COutFolders
+{
+ CRecordVector<UInt64> PackSizes;
+ CUInt32DefVector PackCRCs;
+ CObjectVector<CFolder> Folders;
+
+ CRecordVector<CFileItem> Files;
+ UStringVector Names;
+ CUInt64DefVector CTime;
+ CUInt64DefVector ATime;
+ CUInt64DefVector MTime;
+ CUInt64DefVector StartPos;
+ CUInt32DefVector Attrib;
+ CBoolVector IsAnti;
+
+ /*
+ CBoolVector IsAux;
+
+ CByteBuffer SecureBuf;
+ CRecordVector<UInt32> SecureSizes;
+ CRecordVector<UInt32> SecureIDs;
+
+ void ClearSecure()
+ {
+ SecureBuf.Free();
+ SecureSizes.Clear();
+ SecureIDs.Clear();
+ }
+ */
+
+ void Clear()
+ {
+ OutFoldersClear();
+
+ PackSizes.Clear();
+ PackCRCs.Clear();
+ Folders.Clear();
+
+ Files.Clear();
+ Names.Clear();
+ CTime.Clear();
+ ATime.Clear();
+ MTime.Clear();
+ StartPos.Clear();
+ Attrib.Clear();
+ IsAnti.Clear();
+
+ /*
+ IsAux.Clear();
+ ClearSecure();
+ */
+ }
+
+ void ReserveDown()
+ {
+ OutFoldersReserveDown();
+
+ PackSizes.ReserveDown();
+ PackCRCs.ReserveDown();
+ Folders.ReserveDown();
+
+ Files.ReserveDown();
+ Names.ReserveDown();
+ CTime.ReserveDown();
+ ATime.ReserveDown();
+ MTime.ReserveDown();
+ StartPos.ReserveDown();
+ Attrib.ReserveDown();
+ IsAnti.ReserveDown();
+
+ /*
+ IsAux.ReserveDown();
+ */
+ }
+
+ bool IsEmpty() const
+ {
+ return (
+ PackSizes.IsEmpty() &&
+ NumUnpackStreamsVector.IsEmpty() &&
+ Folders.IsEmpty() &&
+ Files.IsEmpty());
+ }
+
+ bool CheckNumFiles() const
+ {
+ unsigned size = Files.Size();
+ return (
+ CTime.CheckSize(size)
+ && ATime.CheckSize(size)
+ && MTime.CheckSize(size)
+ && StartPos.CheckSize(size)
+ && Attrib.CheckSize(size)
+ && (size == IsAnti.Size() || IsAnti.Size() == 0));
+ }
+
+ bool IsItemAnti(unsigned index) const { return (index < IsAnti.Size() && IsAnti[index]); }
+ // bool IsItemAux(unsigned index) const { return (index < IsAux.Size() && IsAux[index]); }
+
+ void SetItem_Anti(unsigned index, bool isAnti)
+ {
+ while (index >= IsAnti.Size())
+ IsAnti.Add(false);
+ IsAnti[index] = isAnti;
+ }
+ /*
+ void SetItem_Aux(unsigned index, bool isAux)
+ {
+ while (index >= IsAux.Size())
+ IsAux.Add(false);
+ IsAux[index] = isAux;
+ }
+ */
+
+ void AddFile(const CFileItem &file, const CFileItem2 &file2, const UString &name);
+};
+
+
+class COutArchive
+{
+ HRESULT WriteDirect(const void *data, UInt32 size) { return WriteStream(SeqStream, data, size); }
+
+ UInt64 GetPos() const;
+ void WriteBytes(const void *data, size_t size);
+ void WriteBytes(const CByteBuffer &data) { WriteBytes(data, data.Size()); }
+ 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 WritePropBoolVector(Byte id, const CBoolVector &boolVector);
+
+ void WriteHashDigests(const CUInt32DefVector &digests);
+
+ void WritePackInfo(
+ UInt64 dataOffset,
+ const CRecordVector<UInt64> &packSizes,
+ const CUInt32DefVector &packCRCs);
+
+ void WriteUnpackInfo(
+ const CObjectVector<CFolder> &folders,
+ const COutFolders &outFolders);
+
+ void WriteSubStreamsInfo(
+ const CObjectVector<CFolder> &folders,
+ const COutFolders &outFolders,
+ const CRecordVector<UInt64> &unpackSizes,
+ const CUInt32DefVector &digests);
+
+ void SkipToAligned(unsigned pos, unsigned alignShifts);
+ void WriteAlignedBools(const CBoolVector &v, unsigned numDefined, Byte type, unsigned itemSizeShifts);
+ 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, COutFolders &outFolders);
+ void WriteHeader(
+ const CArchiveDatabaseOut &db,
+ // const CHeaderOptions &headerOptions,
+ UInt64 &headerOffset);
+
+ bool _countMode;
+ bool _writeToStream;
+ bool _useAlign;
+ #ifdef Z7_7Z_VOL
+ bool _endMarker;
+ #endif
+ UInt32 _crc;
+ size_t _countSize;
+ CWriteBufferLoc _outByte2;
+ COutBuffer _outByte;
+ UInt64 _signatureHeaderPos;
+ CMyComPtr<IOutStream> Stream;
+
+ #ifdef Z7_7Z_VOL
+ HRESULT WriteFinishSignature();
+ HRESULT WriteFinishHeader(const CFinishHeader &h);
+ #endif
+ HRESULT WriteStartHeader(const CStartHeader &h);
+
+public:
+ CMyComPtr<ISequentialOutStream> SeqStream;
+
+ COutArchive() { _outByte.Create(1 << 16); }
+ HRESULT Create_and_WriteStartPrefix(ISequentialOutStream *stream /* , bool endMarker */);
+ void Close();
+ HRESULT WriteDatabase(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const CArchiveDatabaseOut &db,
+ const CCompressionMethodMode *options,
+ const CHeaderOptions &headerOptions);
+
+ #ifdef Z7_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/CPP/7zip/Archive/7z/7zProperties.cpp b/CPP/7zip/Archive/7z/7zProperties.cpp
index 388ac76..d3b3cbe 100644
--- a/CPP/7zip/Archive/7z/7zProperties.cpp
+++ b/CPP/7zip/Archive/7z/7zProperties.cpp
@@ -1,174 +1,182 @@
-// 7zProperties.cpp
-
-#include "StdAfx.h"
-
-#include "7zProperties.h"
-#include "7zHeader.h"
-#include "7zHandler.h"
-
-// #define _MULTI_PACK
-
-namespace NArchive {
-namespace N7z {
-
-struct CPropMap
-{
- UInt32 FilePropID;
- CStatProp StatProp;
-};
-
-static const CPropMap kPropMap[] =
-{
- { NID::kName, { NULL, kpidPath, VT_BSTR } },
- { NID::kSize, { NULL, kpidSize, VT_UI8 } },
- { NID::kPackInfo, { NULL, kpidPackSize, VT_UI8 } },
-
- #ifdef _MULTI_PACK
- { 100, { "Pack0", kpidPackedSize0, VT_UI8 } },
- { 101, { "Pack1", kpidPackedSize1, VT_UI8 } },
- { 102, { "Pack2", kpidPackedSize2, VT_UI8 } },
- { 103, { "Pack3", kpidPackedSize3, VT_UI8 } },
- { 104, { "Pack4", kpidPackedSize4, VT_UI8 } },
- #endif
-
- { NID::kCTime, { NULL, kpidCTime, VT_FILETIME } },
- { NID::kMTime, { NULL, kpidMTime, VT_FILETIME } },
- { NID::kATime, { NULL, kpidATime, VT_FILETIME } },
- { NID::kWinAttrib, { NULL, kpidAttrib, VT_UI4 } },
- { NID::kStartPos, { NULL, kpidPosition, VT_UI8 } },
-
- { NID::kCRC, { NULL, kpidCRC, VT_UI4 } },
-
-// { NID::kIsAux, { NULL, kpidIsAux, VT_BOOL } },
- { 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 void CopyOneItem(CRecordVector<UInt64> &src,
- CRecordVector<UInt64> &dest, UInt32 item)
-{
- FOR_VECTOR (i, src)
- if (src[i] == item)
- {
- dest.Add(item);
- src.Delete(i);
- return;
- }
-}
-
-static void RemoveOneItem(CRecordVector<UInt64> &src, UInt32 item)
-{
- FOR_VECTOR (i, src)
- if (src[i] == item)
- {
- src.Delete(i);
- return;
- }
-}
-
-static void InsertToHead(CRecordVector<UInt64> &dest, UInt32 item)
-{
- FOR_VECTOR (i, dest)
- if (dest[i] == item)
- {
- dest.Delete(i);
- break;
- }
- dest.Insert(0, item);
-}
-
-#define COPY_ONE_ITEM(id) CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::id);
-
-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.ArcInfo.FileInfoPopIDs;
-
- RemoveOneItem(fileInfoPopIDs, NID::kEmptyStream);
- RemoveOneItem(fileInfoPopIDs, NID::kEmptyFile);
- /*
- RemoveOneItem(fileInfoPopIDs, NID::kParent);
- RemoveOneItem(fileInfoPopIDs, NID::kNtSecure);
- */
-
- COPY_ONE_ITEM(kName);
- COPY_ONE_ITEM(kAnti);
- COPY_ONE_ITEM(kSize);
- COPY_ONE_ITEM(kPackInfo);
- COPY_ONE_ITEM(kCTime);
- COPY_ONE_ITEM(kMTime);
- COPY_ONE_ITEM(kATime);
- COPY_ONE_ITEM(kWinAttrib);
- COPY_ONE_ITEM(kCRC);
- COPY_ONE_ITEM(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 *numProps)
-{
- *numProps = _fileInfoPopIDs.Size();
- return S_OK;
-}
-
-STDMETHODIMP CHandler::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)
-{
- if (index >= _fileInfoPopIDs.Size())
- return E_INVALIDARG;
- UInt64 id = _fileInfoPopIDs[index];
- for (unsigned i = 0; i < ARRAY_SIZE(kPropMap); i++)
- {
- const CPropMap &pr = kPropMap[i];
- if (pr.FilePropID == id)
- {
- const CStatProp &st = pr.StatProp;
- *propID = st.PropID;
- *varType = st.vt;
- /*
- if (st.lpwstrName)
- *name = ::SysAllocString(st.lpwstrName);
- else
- */
- *name = NULL;
- return S_OK;
- }
- }
- return E_INVALIDARG;
-}
-
-}}
+// 7zProperties.cpp
+
+#include "StdAfx.h"
+
+#include "7zHandler.h"
+#include "7zProperties.h"
+
+namespace NArchive {
+namespace N7z {
+
+struct CPropMap
+{
+ Byte FilePropID;
+ // CStatProp StatProp;
+ VARTYPE vt;
+ UInt32 StatPropID;
+};
+
+// #define STAT_PROP(name, id, vt) { name, id, vt }
+#define STAT_PROP(name, id, vt) vt, id
+
+#define STAT_PROP2(id, vt) STAT_PROP(NULL, id, vt)
+
+#define k_7z_id_Encrypted 97
+#define k_7z_id_Method 98
+#define k_7z_id_Block 99
+
+static const CPropMap kPropMap[] =
+{
+ { NID::kName, STAT_PROP2(kpidPath, VT_BSTR) },
+ { NID::kSize, STAT_PROP2(kpidSize, VT_UI8) },
+ { NID::kPackInfo, STAT_PROP2(kpidPackSize, VT_UI8) },
+
+ #ifdef Z7_7Z_SHOW_PACK_STREAMS_SIZES
+#define k_7z_id_PackedSize0 100
+ { k_7z_id_PackedSize0 + 0, STAT_PROP("Pack0", kpidPackedSize0, VT_UI8) },
+ { k_7z_id_PackedSize0 + 1, STAT_PROP("Pack1", kpidPackedSize1, VT_UI8) },
+ { k_7z_id_PackedSize0 + 2, STAT_PROP("Pack2", kpidPackedSize2, VT_UI8) },
+ { k_7z_id_PackedSize0 + 3, STAT_PROP("Pack3", kpidPackedSize3, VT_UI8) },
+ { k_7z_id_PackedSize0 + 4, STAT_PROP("Pack4", kpidPackedSize4, VT_UI8) },
+ #endif
+
+ { NID::kCTime, STAT_PROP2(kpidCTime, VT_FILETIME) },
+ { NID::kMTime, STAT_PROP2(kpidMTime, VT_FILETIME) },
+ { NID::kATime, STAT_PROP2(kpidATime, VT_FILETIME) },
+ { NID::kWinAttrib, STAT_PROP2(kpidAttrib, VT_UI4) },
+ { NID::kStartPos, STAT_PROP2(kpidPosition, VT_UI8) },
+
+ { NID::kCRC, STAT_PROP2(kpidCRC, VT_UI4) },
+ // { NID::kIsAux, STAT_PROP2(kpidIsAux, VT_BOOL) },
+ { NID::kAnti, STAT_PROP2(kpidIsAnti, VT_BOOL) }
+
+ #ifndef Z7_SFX
+ , { k_7z_id_Encrypted, STAT_PROP2(kpidEncrypted, VT_BOOL) }
+ , { k_7z_id_Method, STAT_PROP2(kpidMethod, VT_BSTR) }
+ , { k_7z_id_Block, STAT_PROP2(kpidBlock, VT_UI4) }
+ #endif
+};
+
+static void CopyOneItem(CRecordVector<UInt64> &src,
+ CRecordVector<UInt64> &dest, const UInt32 item)
+{
+ FOR_VECTOR (i, src)
+ if (src[i] == item)
+ {
+ dest.Add(item);
+ src.Delete(i);
+ return;
+ }
+}
+
+static void RemoveOneItem(CRecordVector<UInt64> &src, const UInt32 item)
+{
+ FOR_VECTOR (i, src)
+ if (src[i] == item)
+ {
+ src.Delete(i);
+ return;
+ }
+}
+
+static void InsertToHead(CRecordVector<UInt64> &dest, const UInt32 item)
+{
+ FOR_VECTOR (i, dest)
+ if (dest[i] == item)
+ {
+ dest.Delete(i);
+ break;
+ }
+ dest.Insert(0, item);
+}
+
+#define COPY_ONE_ITEM(id) CopyOneItem(fileInfoPopIDs, _fileInfoPopIDs, NID::id);
+
+void CHandler::FillPopIDs()
+{
+ _fileInfoPopIDs.Clear();
+
+ #ifdef Z7_7Z_VOL
+ if (_volumes.Size() < 1)
+ return;
+ const CVolume &volume = _volumes.Front();
+ const CArchiveDatabaseEx &_db = volume.Database;
+ #endif
+
+ CRecordVector<UInt64> fileInfoPopIDs = _db.ArcInfo.FileInfoPopIDs;
+
+ RemoveOneItem(fileInfoPopIDs, NID::kEmptyStream);
+ RemoveOneItem(fileInfoPopIDs, NID::kEmptyFile);
+ /*
+ RemoveOneItem(fileInfoPopIDs, NID::kParent);
+ RemoveOneItem(fileInfoPopIDs, NID::kNtSecure);
+ */
+
+ COPY_ONE_ITEM(kName)
+ COPY_ONE_ITEM(kAnti)
+ COPY_ONE_ITEM(kSize)
+ COPY_ONE_ITEM(kPackInfo)
+ COPY_ONE_ITEM(kCTime)
+ COPY_ONE_ITEM(kMTime)
+ COPY_ONE_ITEM(kATime)
+ COPY_ONE_ITEM(kWinAttrib)
+ COPY_ONE_ITEM(kCRC)
+ COPY_ONE_ITEM(kComment)
+
+ _fileInfoPopIDs += fileInfoPopIDs;
+
+ #ifndef Z7_SFX
+ _fileInfoPopIDs.Add(k_7z_id_Encrypted);
+ _fileInfoPopIDs.Add(k_7z_id_Method);
+ _fileInfoPopIDs.Add(k_7z_id_Block);
+ #endif
+
+ #ifdef Z7_7Z_SHOW_PACK_STREAMS_SIZES
+ for (unsigned i = 0; i < 5; i++)
+ _fileInfoPopIDs.Add(k_7z_id_PackedSize0 + i);
+ #endif
+
+ #ifndef Z7_SFX
+ InsertToHead(_fileInfoPopIDs, NID::kMTime);
+ InsertToHead(_fileInfoPopIDs, NID::kPackInfo);
+ InsertToHead(_fileInfoPopIDs, NID::kSize);
+ InsertToHead(_fileInfoPopIDs, NID::kName);
+ #endif
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfProperties(UInt32 *numProps))
+{
+ *numProps = _fileInfoPopIDs.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType))
+{
+ if (index >= _fileInfoPopIDs.Size())
+ return E_INVALIDARG;
+ const UInt64 id = _fileInfoPopIDs[index];
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(kPropMap); i++)
+ {
+ const CPropMap &pr = kPropMap[i];
+ if (pr.FilePropID == id)
+ {
+ *propID = pr.StatPropID;
+ *varType = pr.vt;
+ /*
+ const CStatProp &st = pr.StatProp;
+ *propID = st.PropID;
+ *varType = st.vt;
+ */
+ /*
+ if (st.lpwstrName)
+ *name = ::SysAllocString(st.lpwstrName);
+ else
+ */
+ *name = NULL;
+ return S_OK;
+ }
+ }
+ return E_INVALIDARG;
+}
+
+}}
diff --git a/CPP/7zip/Archive/7z/7zProperties.h b/CPP/7zip/Archive/7z/7zProperties.h
index 7b78130..091c39b 100644
--- a/CPP/7zip/Archive/7z/7zProperties.h
+++ b/CPP/7zip/Archive/7z/7zProperties.h
@@ -1,22 +1,26 @@
-// 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
+// 7zProperties.h
+
+#ifndef ZIP7_INC_7Z_PROPERTIES_H
+#define ZIP7_INC_7Z_PROPERTIES_H
+
+#include "../../PropID.h"
+
+namespace NArchive {
+namespace N7z {
+
+// #define Z7_7Z_SHOW_PACK_STREAMS_SIZES // for debug
+
+#ifdef Z7_7Z_SHOW_PACK_STREAMS_SIZES
+enum
+{
+ kpidPackedSize0 = kpidUserDefined,
+ kpidPackedSize1,
+ kpidPackedSize2,
+ kpidPackedSize3,
+ kpidPackedSize4
+};
+#endif
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/7z/7zRegister.cpp b/CPP/7zip/Archive/7z/7zRegister.cpp
index 3e8cfb6..1f11079 100644
--- a/CPP/7zip/Archive/7z/7zRegister.cpp
+++ b/CPP/7zip/Archive/7z/7zRegister.cpp
@@ -1,21 +1,27 @@
-// 7zRegister.cpp
-
-#include "StdAfx.h"
-
-#include "../../Common/RegisterArc.h"
-
-#include "7zHandler.h"
-
-namespace NArchive {
-namespace N7z {
-
-static Byte k_Signature_Dec[kSignatureSize] = {'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C};
-
-REGISTER_ARC_IO_DECREMENT_SIG(
- "7z", "7z", NULL, 7,
- k_Signature_Dec,
- 0,
- NArcInfoFlags::kFindSignature,
- NULL);
-
-}}
+// 7zRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "7zHandler.h"
+
+namespace NArchive {
+namespace N7z {
+
+static Byte k_Signature_Dec[kSignatureSize] = {'7' + 1, 'z', 0xBC, 0xAF, 0x27, 0x1C};
+
+REGISTER_ARC_IO_DECREMENT_SIG(
+ "7z", "7z", NULL, 7,
+ k_Signature_Dec,
+ 0,
+ NArcInfoFlags::kFindSignature
+ | NArcInfoFlags::kCTime
+ | NArcInfoFlags::kATime
+ | NArcInfoFlags::kMTime
+ | NArcInfoFlags::kMTime_Default
+ , TIME_PREC_TO_ARC_FLAGS_MASK(NFileTimeType::kWindows)
+ | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT(NFileTimeType::kWindows)
+ , NULL)
+
+}}
diff --git a/CPP/7zip/Archive/7z/7zSpecStream.cpp b/CPP/7zip/Archive/7z/7zSpecStream.cpp
index e9671a8..8b531bc 100644
--- a/CPP/7zip/Archive/7z/7zSpecStream.cpp
+++ b/CPP/7zip/Archive/7z/7zSpecStream.cpp
@@ -1,22 +1,31 @@
-// 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)
- *processedSize = realProcessedSize;
- return result;
-}
-
-STDMETHODIMP CSequentialInStreamSizeCount2::GetSubStreamSize(UInt64 subStream, UInt64 *value)
-{
- if (!_getSubStreamSize)
- return E_NOTIMPL;
- return _getSubStreamSize->GetSubStreamSize(subStream, value);
-}
+// 7zSpecStream.cpp
+
+#include "StdAfx.h"
+
+#include "7zSpecStream.h"
+
+/*
+Z7_COM7F_IMF(CSequentialInStreamSizeCount2::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ UInt32 realProcessedSize;
+ const HRESULT result = _stream->Read(data, size, &realProcessedSize);
+ _size += realProcessedSize;
+ if (processedSize)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+Z7_COM7F_IMF(CSequentialInStreamSizeCount2::GetSubStreamSize(UInt64 subStream, UInt64 *value))
+{
+ if (!_getSubStreamSize)
+ return E_NOTIMPL;
+ return _getSubStreamSize->GetSubStreamSize(subStream, value);
+}
+
+Z7_COM7F_IMF(CSequentialInStreamSizeCount2::GetNextInSubStream(UInt64 *streamIndexRes, ISequentialInStream **stream))
+{
+ if (!_compressGetSubStreamSize)
+ return E_NOTIMPL;
+ return _compressGetSubStreamSize->GetNextInSubStream(streamIndexRes, stream);
+}
+*/
diff --git a/CPP/7zip/Archive/7z/7zSpecStream.h b/CPP/7zip/Archive/7z/7zSpecStream.h
index 0994128..78f631e 100644
--- a/CPP/7zip/Archive/7z/7zSpecStream.h
+++ b/CPP/7zip/Archive/7z/7zSpecStream.h
@@ -1,35 +1,49 @@
-// 7zSpecStream.h
-
-#ifndef __7Z_SPEC_STREAM_H
-#define __7Z_SPEC_STREAM_H
-
-#include "../../../Common/MyCom.h"
-
-#include "../../ICoder.h"
-
-class CSequentialInStreamSizeCount2:
- public ISequentialInStream,
- public ICompressGetSubStreamSize,
- public CMyUnknownImp
-{
- CMyComPtr<ISequentialInStream> _stream;
- CMyComPtr<ICompressGetSubStreamSize> _getSubStreamSize;
- UInt64 _size;
-public:
- void Init(ISequentialInStream *stream)
- {
- _size = 0;
- _getSubStreamSize.Release();
- _stream = stream;
- _stream.QueryInterface(IID_ICompressGetSubStreamSize, &_getSubStreamSize);
- }
- UInt64 GetSize() const { return _size; }
-
- MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize)
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
-
- STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
-};
-
-#endif
+// 7zSpecStream.h
+
+#ifndef ZIP7_INC_7Z_SPEC_STREAM_H
+#define ZIP7_INC_7Z_SPEC_STREAM_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../ICoder.h"
+
+/*
+#define Z7_COM_QI_ENTRY_AG_2(i, sub0, sub) else if (iid == IID_ ## i) \
+ { if (!sub) RINOK(sub0->QueryInterface(IID_ ## i, (void **)&sub)) \
+ { i *ti = this; *outObject = ti; } }
+
+class CSequentialInStreamSizeCount2 Z7_final:
+ public ISequentialInStream,
+ public ICompressGetSubStreamSize,
+ public ICompressInSubStreams,
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(ISequentialInStream)
+ Z7_COM_QI_ENTRY(ICompressGetSubStreamSize)
+ Z7_COM_QI_ENTRY_AG_2(ISequentialInStream, _stream, _compressGetSubStreamSize)
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+ Z7_IFACE_COM7_IMP(ICompressGetSubStreamSize)
+ Z7_IFACE_COM7_IMP(ICompressInSubStreams)
+
+ CMyComPtr<ISequentialInStream> _stream;
+ CMyComPtr<ICompressGetSubStreamSize> _getSubStreamSize;
+ CMyComPtr<ICompressInSubStreams> _compressGetSubStreamSize;
+ UInt64 _size;
+public:
+ void Init(ISequentialInStream *stream)
+ {
+ _size = 0;
+ _getSubStreamSize.Release();
+ _compressGetSubStreamSize.Release();
+ _stream = stream;
+ _stream.QueryInterface(IID_ICompressGetSubStreamSize, &_getSubStreamSize);
+ _stream.QueryInterface(IID_ICompressInSubStreams, &_compressGetSubStreamSize);
+ }
+ UInt64 GetSize() const { return _size; }
+};
+*/
+
+#endif
diff --git a/CPP/7zip/Archive/7z/7zUpdate.cpp b/CPP/7zip/Archive/7z/7zUpdate.cpp
index 5b156be..4e9ea5d 100644
--- a/CPP/7zip/Archive/7z/7zUpdate.cpp
+++ b/CPP/7zip/Archive/7z/7zUpdate.cpp
@@ -1,2500 +1,2991 @@
-// 7zUpdate.cpp
-
-#include "StdAfx.h"
-
-#include "../../../../C/CpuArch.h"
-
-#include "../../../Common/Wildcard.h"
-
-#include "../../Common/CreateCoder.h"
-#include "../../Common/LimitedStreams.h"
-#include "../../Common/ProgressUtils.h"
-
-#include "../../Compress/CopyCoder.h"
-
-#include "../Common/ItemNameUtils.h"
-
-#include "7zDecode.h"
-#include "7zEncode.h"
-#include "7zFolderInStream.h"
-#include "7zHandler.h"
-#include "7zOut.h"
-#include "7zUpdate.h"
-
-namespace NArchive {
-namespace N7z {
-
-
-#define k_X86 k_BCJ
-
-struct CFilterMode
-{
- UInt32 Id;
- UInt32 Delta;
-
- CFilterMode(): Id(0), Delta(0) {}
-
- void SetDelta()
- {
- if (Id == k_IA64)
- Delta = 16;
- else if (Id == k_ARM || Id == k_PPC || Id == k_SPARC)
- Delta = 4;
- else if (Id == k_ARMT)
- Delta = 2;
- else
- Delta = 0;
- }
-};
-
-
-/* ---------- PE ---------- */
-
-#define MZ_SIG 0x5A4D
-
-#define PE_SIG 0x00004550
-#define PE_OptHeader_Magic_32 0x10B
-#define PE_OptHeader_Magic_64 0x20B
-#define PE_SectHeaderSize 40
-#define PE_SECT_EXECUTE 0x20000000
-
-static int Parse_EXE(const Byte *buf, size_t size, CFilterMode *filterMode)
-{
- if (size < 512 || GetUi16(buf) != MZ_SIG)
- return 0;
-
- const Byte *p;
- UInt32 peOffset, optHeaderSize, filterId;
-
- peOffset = GetUi32(buf + 0x3C);
- if (peOffset >= 0x1000 || peOffset + 512 > size || (peOffset & 7) != 0)
- return 0;
- p = buf + peOffset;
- if (GetUi32(p) != PE_SIG)
- return 0;
- p += 4;
-
- switch (GetUi16(p))
- {
- case 0x014C:
- case 0x8664: filterId = k_X86; break;
-
- /*
- IMAGE_FILE_MACHINE_ARM 0x01C0 // ARM LE
- IMAGE_FILE_MACHINE_THUMB 0x01C2 // ARM Thumb / Thumb-2 LE
- IMAGE_FILE_MACHINE_ARMNT 0x01C4 // ARM Thumb-2, LE
- Note: We use ARM filter for 0x01C2. (WinCE 5 - 0x01C2) files mostly contain ARM code (not Thumb/Thumb-2).
- */
-
- case 0x01C0: // WinCE old
- case 0x01C2: filterId = k_ARM; break; // WinCE new
- case 0x01C4: filterId = k_ARMT; break; // WinRT
-
- case 0x0200: filterId = k_IA64; break;
- default: return 0;
- }
-
- optHeaderSize = GetUi16(p + 16);
- if (optHeaderSize > (1 << 10))
- return 0;
-
- p += 20; /* headerSize */
-
- switch (GetUi16(p))
- {
- case PE_OptHeader_Magic_32:
- case PE_OptHeader_Magic_64:
- break;
- default:
- return 0;
- }
-
- filterMode->Id = filterId;
- return 1;
-}
-
-
-/* ---------- ELF ---------- */
-
-#define ELF_SIG 0x464C457F
-
-#define ELF_CLASS_32 1
-#define ELF_CLASS_64 2
-
-#define ELF_DATA_2LSB 1
-#define ELF_DATA_2MSB 2
-
-static UInt16 Get16(const Byte *p, BoolInt be) { if (be) return (UInt16)GetBe16(p); return (UInt16)GetUi16(p); }
-static UInt32 Get32(const Byte *p, BoolInt be) { if (be) return GetBe32(p); return GetUi32(p); }
-// static UInt64 Get64(const Byte *p, BoolInt be) { if (be) return GetBe64(p); return GetUi64(p); }
-
-static int Parse_ELF(const Byte *buf, size_t size, CFilterMode *filterMode)
-{
- BoolInt /* is32, */ be;
- UInt32 filterId;
-
- if (size < 512 || buf[6] != 1) /* ver */
- return 0;
-
- if (GetUi32(buf) != ELF_SIG)
- return 0;
-
- switch (buf[4])
- {
- case ELF_CLASS_32: /* is32 = True; */ break;
- case ELF_CLASS_64: /* is32 = False; */ break;
- default: return 0;
- }
-
- switch (buf[5])
- {
- case ELF_DATA_2LSB: be = False; break;
- case ELF_DATA_2MSB: be = True; break;
- default: return 0;
- }
-
- switch (Get16(buf + 0x12, be))
- {
- case 3:
- case 6:
- case 62: filterId = k_X86; break;
- case 2:
- case 18:
- case 43: filterId = k_SPARC; break;
- case 20:
- case 21: if (!be) return 0; filterId = k_PPC; break;
- case 40: if ( be) return 0; filterId = k_ARM; break;
-
- /* Some IA-64 ELF exacutable have size that is not aligned for 16 bytes.
- So we don't use IA-64 filter for IA-64 ELF */
- // case 50: if ( be) return 0; filterId = k_IA64; break;
-
- default: return 0;
- }
-
- filterMode->Id = filterId;
- return 1;
-}
-
-
-
-/* ---------- Mach-O ---------- */
-
-#define MACH_SIG_BE_32 0xCEFAEDFE
-#define MACH_SIG_BE_64 0xCFFAEDFE
-#define MACH_SIG_LE_32 0xFEEDFACE
-#define MACH_SIG_LE_64 0xFEEDFACF
-
-#define MACH_ARCH_ABI64 (1 << 24)
-#define MACH_MACHINE_386 7
-#define MACH_MACHINE_ARM 12
-#define MACH_MACHINE_SPARC 14
-#define MACH_MACHINE_PPC 18
-#define MACH_MACHINE_PPC64 (MACH_ARCH_ABI64 | MACH_MACHINE_PPC)
-#define MACH_MACHINE_AMD64 (MACH_ARCH_ABI64 | MACH_MACHINE_386)
-
-static unsigned Parse_MACH(const Byte *buf, size_t size, CFilterMode *filterMode)
-{
- UInt32 filterId, numCommands, commandsSize;
-
- if (size < 512)
- return 0;
-
- BoolInt /* mode64, */ be;
- switch (GetUi32(buf))
- {
- case MACH_SIG_BE_32: /* mode64 = False; */ be = True; break;
- case MACH_SIG_BE_64: /* mode64 = True; */ be = True; break;
- case MACH_SIG_LE_32: /* mode64 = False; */ be = False; break;
- case MACH_SIG_LE_64: /* mode64 = True; */ be = False; break;
- default: return 0;
- }
-
- switch (Get32(buf + 4, be))
- {
- case MACH_MACHINE_386:
- case MACH_MACHINE_AMD64: filterId = k_X86; break;
- case MACH_MACHINE_ARM: if ( be) return 0; filterId = k_ARM; break;
- case MACH_MACHINE_SPARC: if (!be) return 0; filterId = k_SPARC; break;
- case MACH_MACHINE_PPC:
- case MACH_MACHINE_PPC64: if (!be) return 0; filterId = k_PPC; break;
- default: return 0;
- }
-
- numCommands = Get32(buf + 0x10, be);
- commandsSize = Get32(buf + 0x14, be);
-
- if (commandsSize > (1 << 24) || numCommands > (1 << 18))
- return 0;
-
- filterMode->Id = filterId;
- return 1;
-}
-
-
-/* ---------- WAV ---------- */
-
-#define WAV_SUBCHUNK_fmt 0x20746D66
-#define WAV_SUBCHUNK_data 0x61746164
-
-#define RIFF_SIG 0x46464952
-
-static BoolInt Parse_WAV(const Byte *buf, size_t size, CFilterMode *filterMode)
-{
- UInt32 subChunkSize, pos;
- if (size < 0x2C)
- return False;
-
- if (GetUi32(buf + 0) != RIFF_SIG ||
- GetUi32(buf + 8) != 0x45564157 || // WAVE
- GetUi32(buf + 0xC) != WAV_SUBCHUNK_fmt)
- return False;
- subChunkSize = GetUi32(buf + 0x10);
- /* [0x14 = format] = 1 (PCM) */
- if (subChunkSize < 0x10 || subChunkSize > 0x12 || GetUi16(buf + 0x14) != 1)
- return False;
-
- unsigned numChannels = GetUi16(buf + 0x16);
- unsigned bitsPerSample = GetUi16(buf + 0x22);
-
- if ((bitsPerSample & 0x7) != 0 || bitsPerSample >= 256 || numChannels >= 256)
- return False;
-
- pos = 0x14 + subChunkSize;
-
- const int kNumSubChunksTests = 10;
- // Do we need to scan more than 3 sub-chunks?
- for (int i = 0; i < kNumSubChunksTests; i++)
- {
- if (pos + 8 > size)
- return False;
- subChunkSize = GetUi32(buf + pos + 4);
- if (GetUi32(buf + pos) == WAV_SUBCHUNK_data)
- {
- unsigned delta = numChannels * (bitsPerSample >> 3);
- if (delta >= 256)
- return False;
- filterMode->Id = k_Delta;
- filterMode->Delta = delta;
- return True;
- }
- if (subChunkSize > (1 << 16))
- return False;
- pos += subChunkSize + 8;
- }
- return False;
-}
-
-static BoolInt ParseFile(const Byte *buf, size_t size, CFilterMode *filterMode)
-{
- filterMode->Id = 0;
- filterMode->Delta = 0;
-
- if (Parse_EXE(buf, size, filterMode)) return True;
- if (Parse_ELF(buf, size, filterMode)) return True;
- if (Parse_MACH(buf, size, filterMode)) return True;
- return Parse_WAV(buf, size, filterMode);
-}
-
-
-
-
-struct CFilterMode2: public CFilterMode
-{
- bool Encrypted;
- unsigned GroupIndex;
-
- CFilterMode2(): Encrypted(false) {}
-
- int Compare(const CFilterMode2 &m) const
- {
- if (!Encrypted)
- {
- if (m.Encrypted)
- return -1;
- }
- else if (!m.Encrypted)
- return 1;
-
- if (Id < m.Id) return -1;
- if (Id > m.Id) return 1;
-
- if (Delta < m.Delta) return -1;
- if (Delta > m.Delta) return 1;
-
- return 0;
- }
-
- bool operator ==(const CFilterMode2 &m) const
- {
- return Id == m.Id && Delta == m.Delta && Encrypted == m.Encrypted;
- }
-};
-
-static unsigned GetGroup(CRecordVector<CFilterMode2> &filters, const CFilterMode2 &m)
-{
- unsigned i;
- for (i = 0; i < filters.Size(); i++)
- {
- const CFilterMode2 &m2 = filters[i];
- if (m == m2)
- return i;
- /*
- if (m.Encrypted != m2.Encrypted)
- {
- if (!m.Encrypted)
- break;
- continue;
- }
-
- if (m.Id < m2.Id) break;
- if (m.Id != m2.Id) continue;
-
- if (m.Delta < m2.Delta) break;
- if (m.Delta != m2.Delta) continue;
- */
- }
- // filters.Insert(i, m);
- // return i;
- return filters.Add(m);
-}
-
-static inline bool Is86Filter(CMethodId m)
-{
- return (m == k_BCJ || m == k_BCJ2);
-}
-
-static inline bool IsExeFilter(CMethodId m)
-{
- switch (m)
- {
- case k_BCJ:
- case k_BCJ2:
- case k_ARM:
- case k_ARMT:
- case k_PPC:
- case k_SPARC:
- case k_IA64:
- return true;
- }
- return false;
-}
-
-static unsigned Get_FilterGroup_for_Folder(
- CRecordVector<CFilterMode2> &filters, const CFolderEx &f, bool extractFilter)
-{
- CFilterMode2 m;
- m.Id = 0;
- m.Delta = 0;
- m.Encrypted = f.IsEncrypted();
-
- if (extractFilter)
- {
- const CCoderInfo &coder = f.Coders[f.UnpackCoder];
-
- if (coder.MethodID == k_Delta)
- {
- if (coder.Props.Size() == 1)
- {
- m.Delta = (unsigned)coder.Props[0] + 1;
- m.Id = k_Delta;
- }
- }
- else if (IsExeFilter(coder.MethodID))
- {
- m.Id = (UInt32)coder.MethodID;
- if (m.Id == k_BCJ2)
- m.Id = k_BCJ;
- m.SetDelta();
- }
- }
-
- return GetGroup(filters, m);
-}
-
-
-
-
-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);
-}
-
-/*
-unsigned CUpdateItem::GetExtensionPos() const
-{
- int slashPos = Name.ReverseFind_PathSepar();
- int dotPos = Name.ReverseFind_Dot();
- if (dotPos <= slashPos)
- return Name.Len();
- return dotPos + 1;
-}
-
-UString CUpdateItem::GetExtension() const
-{
- return Name.Ptr(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 CompareBonds(const CBond &b1, const CBond &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.Bonds.Size();
- s2 = f2.Bonds.Size();
- RINOZ_COMP(s1, s2);
- for (i = 0; i < s1; i++)
- RINOZ(CompareBonds(f1.Bonds[i], f2.Bonds[i]));
- return 0;
-}
-*/
-
-/*
-static int CompareFiles(const CFileItem &f1, const CFileItem &f2)
-{
- return CompareFileNames(f1.Name, f2.Name);
-}
-*/
-
-struct CFolderRepack
-{
- unsigned FolderIndex;
- CNum NumCopyFiles;
-};
-
-/*
-static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void *)
-{
- int i1 = p1->FolderIndex;
- int i2 = p2->FolderIndex;
- // In that version we don't want to parse folders here, so we don't compare folders
- // probably it must be improved in future
- // const CDbEx &db = *(const CDbEx *)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]]);
-}
-*/
-
-/*
- we sort empty files and dirs in such order:
- - Dir.NonAnti (name sorted)
- - File.NonAnti (name sorted)
- - File.Anti (name sorted)
- - Dir.Anti (reverse name sorted)
-*/
-
-static int CompareEmptyItems(const unsigned *p1, const unsigned *p2, void *param)
-{
- const CObjectVector<CUpdateItem> &updateItems = *(const CObjectVector<CUpdateItem> *)param;
- const CUpdateItem &u1 = updateItems[*p1];
- const CUpdateItem &u2 = updateItems[*p2];
- // NonAnti < Anti
- if (u1.IsAnti != u2.IsAnti)
- return (u1.IsAnti ? 1 : -1);
- if (u1.IsDir != u2.IsDir)
- {
- // Dir.NonAnti < File < Dir.Anti
- if (u1.IsDir)
- return (u1.IsAnti ? 1 : -1);
- return (u2.IsAnti ? -1 : 1);
- }
- int n = CompareFileNames(u1.Name, u2.Name);
- return (u1.IsDir && u1.IsAnti) ? -n : n;
-}
-
-static const char *g_Exts =
- " 7z xz lzma ace arc arj bz tbz bz2 tbz2 cab deb gz tgz ha lha lzh lzo lzx pak rar rpm sit 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 m mm go swift"
- " rc java cs rs pas bas vb cls ctl frm dlg def"
- " f77 f f90 f95"
- " asm s"
- " sql manifest dep"
- " mak clw csproj vcproj sln dsp dsw"
- " class"
- " bat cmd bash sh"
- " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml"
- " awk sed hta js json php php3 php4 php5 phptml pl pm py pyo rb tcl ts 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";
-
-static unsigned GetExtIndex(const char *ext)
-{
- unsigned extIndex = 1;
- const char *p = g_Exts;
- for (;;)
- {
- char c = *p++;
- if (c == 0)
- return extIndex;
- if (c == ' ')
- continue;
- unsigned 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;
- unsigned ExtensionPos;
- unsigned NamePos;
- unsigned ExtensionIndex;
-
- CRefItem() {};
- CRefItem(UInt32 index, const CUpdateItem &ui, bool sortByType):
- UpdateItem(&ui),
- Index(index),
- ExtensionPos(0),
- NamePos(0),
- ExtensionIndex(0)
- {
- if (sortByType)
- {
- int slashPos = ui.Name.ReverseFind_PathSepar();
- NamePos = slashPos + 1;
- int dotPos = ui.Name.ReverseFind_Dot();
- if (dotPos <= slashPos)
- ExtensionPos = ui.Name.Len();
- else
- {
- ExtensionPos = dotPos + 1;
- if (ExtensionPos != ui.Name.Len())
- {
- AString s;
- for (unsigned pos = ExtensionPos;; pos++)
- {
- wchar_t c = ui.Name[pos];
- if (c >= 0x80)
- break;
- if (c == 0)
- {
- ExtensionIndex = GetExtIndex(s);
- break;
- }
- s += (char)MyCharLower_Ascii((char)c);
- }
- }
- }
- }
- }
-};
-
-struct CSortParam
-{
- // const CObjectVector<CTreeFolder> *TreeFolders;
- bool SortByType;
-};
-
-/*
- we sort files in such order:
- - Dir.NonAnti (name sorted)
- - alt streams
- - Dirs
- - Dir.Anti (reverse name sorted)
-*/
-
-
-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;
-
- /*
- if (u1.IsAltStream != u2.IsAltStream)
- return u1.IsAltStream ? 1 : -1;
- */
-
- // Actually there are no dirs that time. They were stored in other steps
- // So that code is unused?
- 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 = CompareFileNames(u1.Name, u2.Name);
- return -n;
- }
-
- // bool sortByType = *(bool *)param;
- const CSortParam *sortParam = (const CSortParam *)param;
- bool sortByType = sortParam->SortByType;
- if (sortByType)
- {
- RINOZ_COMP(a1.ExtensionIndex, a2.ExtensionIndex);
- RINOZ(CompareFileNames(u1.Name.Ptr(a1.ExtensionPos), u2.Name.Ptr(a2.ExtensionPos)));
- RINOZ(CompareFileNames(u1.Name.Ptr(a1.NamePos), u2.Name.Ptr(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);
- }
- /*
- int par1 = a1.UpdateItem->ParentFolderIndex;
- int par2 = a2.UpdateItem->ParentFolderIndex;
- const CTreeFolder &tf1 = (*sortParam->TreeFolders)[par1];
- const CTreeFolder &tf2 = (*sortParam->TreeFolders)[par2];
-
- int b1 = tf1.SortIndex, e1 = tf1.SortIndexEnd;
- int b2 = tf2.SortIndex, e2 = tf2.SortIndexEnd;
- if (b1 < b2)
- {
- if (e1 <= b2)
- return -1;
- // p2 in p1
- int par = par2;
- for (;;)
- {
- const CTreeFolder &tf = (*sortParam->TreeFolders)[par];
- par = tf.Parent;
- if (par == par1)
- {
- RINOZ(CompareFileNames(u1.Name, tf.Name));
- break;
- }
- }
- }
- else if (b2 < b1)
- {
- if (e2 <= b1)
- return 1;
- // p1 in p2
- int par = par1;
- for (;;)
- {
- const CTreeFolder &tf = (*sortParam->TreeFolders)[par];
- par = tf.Parent;
- if (par == par2)
- {
- RINOZ(CompareFileNames(tf.Name, u2.Name));
- break;
- }
- }
- }
- */
- // RINOZ_COMP(a1.UpdateItem->ParentSortIndex, a2.UpdateItem->ParentSortIndex);
- RINOK(CompareFileNames(u1.Name, u2.Name));
- RINOZ_COMP(a1.UpdateItem->IndexInClient, a2.UpdateItem->IndexInClient);
- RINOZ_COMP(a1.UpdateItem->IndexInArchive, a2.UpdateItem->IndexInArchive);
- return 0;
-}
-
-struct CSolidGroup
-{
- CRecordVector<UInt32> Indices;
-
- CRecordVector<CFolderRepack> folderRefs;
-};
-
-static const char * const g_ExeExts[] =
-{
- "dll"
- , "exe"
- , "ocx"
- , "sfx"
- , "sys"
-};
-
-static bool IsExeExt(const wchar_t *ext)
-{
- for (unsigned i = 0; i < ARRAY_SIZE(g_ExeExts); i++)
- if (StringsAreEqualNoCase_Ascii(ext, g_ExeExts[i]))
- return true;
- return false;
-}
-
-struct CAnalysis
-{
- CMyComPtr<IArchiveUpdateCallbackFile> Callback;
- CByteBuffer Buffer;
-
- bool ParseWav;
- bool ParseExe;
- bool ParseAll;
-
- CAnalysis():
- ParseWav(true),
- ParseExe(false),
- ParseAll(false)
- {}
-
- HRESULT GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode);
-};
-
-static const size_t kAnalysisBufSize = 1 << 14;
-
-HRESULT CAnalysis::GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode)
-{
- filterMode.Id = 0;
- filterMode.Delta = 0;
-
- CFilterMode filterModeTemp = filterMode;
-
- int slashPos = ui.Name.ReverseFind_PathSepar();
- int dotPos = ui.Name.ReverseFind_Dot();
-
- // if (dotPos > slashPos)
- {
- bool needReadFile = ParseAll;
-
- bool probablyIsSameIsa = false;
-
- if (!needReadFile || !Callback)
- {
- const wchar_t *ext;
- if (dotPos > slashPos)
- ext = ui.Name.Ptr(dotPos + 1);
- else
- ext = ui.Name.RightPtr(0);
-
- // p7zip uses the trick to store posix attributes in high 16 bits
- if (ui.Attrib & 0x8000)
- {
- unsigned st_mode = ui.Attrib >> 16;
- // st_mode = 00111;
- if ((st_mode & 00111) && (ui.Size >= 2048))
- {
- #ifndef _WIN32
- probablyIsSameIsa = true;
- #endif
- needReadFile = true;
- }
- }
-
- if (IsExeExt(ext))
- {
- needReadFile = true;
- #ifdef _WIN32
- probablyIsSameIsa = true;
- needReadFile = ParseExe;
- #endif
- }
- else if (StringsAreEqualNoCase_Ascii(ext, "wav"))
- {
- needReadFile = ParseWav;
- }
- /*
- else if (!needReadFile && ParseUnixExt)
- {
- if (StringsAreEqualNoCase_Ascii(ext, "so")
- || StringsAreEqualNoCase_Ascii(ext, ""))
-
- needReadFile = true;
- }
- */
- }
-
- if (needReadFile && Callback)
- {
- if (Buffer.Size() != kAnalysisBufSize)
- {
- Buffer.Alloc(kAnalysisBufSize);
- }
- {
- CMyComPtr<ISequentialInStream> stream;
- HRESULT result = Callback->GetStream2(index, &stream, NUpdateNotifyOp::kAnalyze);
- if (result == S_OK && stream)
- {
- size_t size = kAnalysisBufSize;
- result = ReadStream(stream, Buffer, &size);
- stream.Release();
- // RINOK(Callback->SetOperationResult2(index, NUpdate::NOperationResult::kOK));
- if (result == S_OK)
- {
- BoolInt parseRes = ParseFile(Buffer, size, &filterModeTemp);
- if (parseRes && filterModeTemp.Delta == 0)
- {
- filterModeTemp.SetDelta();
- if (filterModeTemp.Delta != 0 && filterModeTemp.Id != k_Delta)
- {
- if (ui.Size % filterModeTemp.Delta != 0)
- {
- parseRes = false;
- }
- }
- }
- if (!parseRes)
- {
- filterModeTemp.Id = 0;
- filterModeTemp.Delta = 0;
- }
- }
- }
- }
- }
- else if ((needReadFile && !Callback) || probablyIsSameIsa)
- {
- #ifdef MY_CPU_X86_OR_AMD64
- if (probablyIsSameIsa)
- filterModeTemp.Id = k_X86;
- #endif
- }
- }
-
- filterMode = filterModeTemp;
- return S_OK;
-}
-
-static inline void GetMethodFull(UInt64 methodID, UInt32 numStreams, CMethodFull &m)
-{
- m.Id = methodID;
- m.NumStreams = numStreams;
-}
-
-static HRESULT AddBondForFilter(CCompressionMethodMode &mode)
-{
- for (unsigned c = 1; c < mode.Methods.Size(); c++)
- {
- if (!mode.IsThereBond_to_Coder(c))
- {
- CBond2 bond;
- bond.OutCoder = 0;
- bond.OutStream = 0;
- bond.InCoder = c;
- mode.Bonds.Add(bond);
- return S_OK;
- }
- }
- return E_INVALIDARG;
-}
-
-static HRESULT AddFilterBond(CCompressionMethodMode &mode)
-{
- if (!mode.Bonds.IsEmpty())
- return AddBondForFilter(mode);
- return S_OK;
-}
-
-static HRESULT AddBcj2Methods(CCompressionMethodMode &mode)
-{
- // mode.Methods[0] must be k_BCJ2 method !
-
- CMethodFull m;
- GetMethodFull(k_LZMA, 1, m);
-
- m.AddProp32(NCoderPropID::kDictionarySize, 1 << 20);
- m.AddProp32(NCoderPropID::kNumFastBytes, 128);
- m.AddProp32(NCoderPropID::kNumThreads, 1);
- m.AddProp32(NCoderPropID::kLitPosBits, 2);
- m.AddProp32(NCoderPropID::kLitContextBits, 0);
- // m.AddProp_Ascii(NCoderPropID::kMatchFinder, "BT2");
-
- unsigned methodIndex = mode.Methods.Size();
-
- if (mode.Bonds.IsEmpty())
- {
- for (unsigned i = 1; i + 1 < mode.Methods.Size(); i++)
- {
- CBond2 bond;
- bond.OutCoder = i;
- bond.OutStream = 0;
- bond.InCoder = i + 1;
- mode.Bonds.Add(bond);
- }
- }
-
- mode.Methods.Add(m);
- mode.Methods.Add(m);
-
- RINOK(AddBondForFilter(mode));
- CBond2 bond;
- bond.OutCoder = 0;
- bond.InCoder = methodIndex; bond.OutStream = 1; mode.Bonds.Add(bond);
- bond.InCoder = methodIndex + 1; bond.OutStream = 2; mode.Bonds.Add(bond);
- return S_OK;
-}
-
-static HRESULT MakeExeMethod(CCompressionMethodMode &mode,
- const CFilterMode &filterMode, /* bool addFilter, */ bool bcj2Filter)
-{
- if (mode.Filter_was_Inserted)
- {
- const CMethodFull &m = mode.Methods[0];
- CMethodId id = m.Id;
- if (id == k_BCJ2)
- return AddBcj2Methods(mode);
- if (!m.IsSimpleCoder())
- return E_NOTIMPL;
- // if (Bonds.IsEmpty()) we can create bonds later
- return AddFilterBond(mode);
- }
-
- if (filterMode.Id == 0)
- return S_OK;
-
- CMethodFull &m = mode.Methods.InsertNew(0);
-
- {
- FOR_VECTOR(k, mode.Bonds)
- {
- CBond2 &bond = mode.Bonds[k];
- bond.InCoder++;
- bond.OutCoder++;
- }
- }
-
- HRESULT res;
-
- if (bcj2Filter && Is86Filter(filterMode.Id))
- {
- GetMethodFull(k_BCJ2, 4, m);
- res = AddBcj2Methods(mode);
- }
- else
- {
- GetMethodFull(filterMode.Id, 1, m);
- if (filterMode.Id == k_Delta)
- m.AddProp32(NCoderPropID::kDefaultProp, filterMode.Delta);
- res = AddFilterBond(mode);
-
- int alignBits = -1;
- if (filterMode.Id == k_Delta || filterMode.Delta != 0)
- {
- if (filterMode.Delta == 1) alignBits = 0;
- else if (filterMode.Delta == 2) alignBits = 1;
- else if (filterMode.Delta == 4) alignBits = 2;
- else if (filterMode.Delta == 8) alignBits = 3;
- else if (filterMode.Delta == 16) alignBits = 4;
- }
- else
- {
- // alignBits = GetAlignForFilterMethod(filterMode.Id);
- }
-
- if (res == S_OK && alignBits >= 0)
- {
- unsigned nextCoder = 1;
- if (!mode.Bonds.IsEmpty())
- {
- nextCoder = mode.Bonds.Back().InCoder;
- }
- if (nextCoder < mode.Methods.Size())
- {
- CMethodFull &nextMethod = mode.Methods[nextCoder];
- if (nextMethod.Id == k_LZMA || nextMethod.Id == k_LZMA2)
- {
- if (!nextMethod.Are_Lzma_Model_Props_Defined())
- {
- if (alignBits != 0)
- {
- if (alignBits > 2 || filterMode.Id == k_Delta)
- nextMethod.AddProp32(NCoderPropID::kPosStateBits, alignBits);
- unsigned lc = 0;
- if (alignBits < 3)
- lc = 3 - alignBits;
- nextMethod.AddProp32(NCoderPropID::kLitContextBits, lc);
- nextMethod.AddProp32(NCoderPropID::kLitPosBits, alignBits);
- }
- }
- }
- }
- }
- }
-
- return res;
-}
-
-
-static void UpdateItem_To_FileItem2(const CUpdateItem &ui, CFileItem2 &file2)
-{
- file2.Attrib = ui.Attrib; file2.AttribDefined = ui.AttribDefined;
- 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.IsAux = false;
- file2.StartPosDefined = false;
- // file2.StartPos = 0;
-}
-
-
-static void UpdateItem_To_FileItem(const CUpdateItem &ui,
- CFileItem &file, CFileItem2 &file2)
-{
- UpdateItem_To_FileItem2(ui, file2);
-
- file.Size = ui.Size;
- file.IsDir = ui.IsDir;
- file.HasStream = ui.HasStream();
- // file.IsAltStream = ui.IsAltStream;
-}
-
-
-
-class CRepackInStreamWithSizes:
- public ISequentialInStream,
- public ICompressGetSubStreamSize,
- public CMyUnknownImp
-{
- CMyComPtr<ISequentialInStream> _stream;
- // UInt64 _size;
- const CBoolVector *_extractStatuses;
- UInt32 _startIndex;
-public:
- const CDbEx *_db;
-
- void Init(ISequentialInStream *stream, UInt32 startIndex, const CBoolVector *extractStatuses)
- {
- _startIndex = startIndex;
- _extractStatuses = extractStatuses;
- // _size = 0;
- _stream = stream;
- }
- // UInt64 GetSize() const { return _size; }
-
- MY_UNKNOWN_IMP2(ISequentialInStream, ICompressGetSubStreamSize)
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
-
- STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value);
-};
-
-STDMETHODIMP CRepackInStreamWithSizes::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- return _stream->Read(data, size, processedSize);
- /*
- UInt32 realProcessedSize;
- HRESULT result = _stream->Read(data, size, &realProcessedSize);
- _size += realProcessedSize;
- if (processedSize)
- *processedSize = realProcessedSize;
- return result;
- */
-}
-
-STDMETHODIMP CRepackInStreamWithSizes::GetSubStreamSize(UInt64 subStream, UInt64 *value)
-{
- *value = 0;
- if (subStream >= _extractStatuses->Size())
- return S_FALSE; // E_FAIL;
- unsigned index = (unsigned)subStream;
- if ((*_extractStatuses)[index])
- {
- const CFileItem &fi = _db->Files[_startIndex + index];
- if (fi.HasStream)
- *value = fi.Size;
- }
- return S_OK;
-}
-
-
-class CRepackStreamBase
-{
-protected:
- bool _needWrite;
- bool _fileIsOpen;
- bool _calcCrc;
- UInt32 _crc;
- UInt64 _rem;
-
- const CBoolVector *_extractStatuses;
- UInt32 _startIndex;
- unsigned _currentIndex;
-
- HRESULT OpenFile();
- HRESULT CloseFile();
- HRESULT ProcessEmptyFiles();
-
-public:
- const CDbEx *_db;
- CMyComPtr<IArchiveUpdateCallbackFile> _opCallback;
- CMyComPtr<IArchiveExtractCallbackMessage> _extractCallback;
-
- HRESULT Init(UInt32 startIndex, const CBoolVector *extractStatuses);
- HRESULT CheckFinishedState() const { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; }
-};
-
-HRESULT CRepackStreamBase::Init(UInt32 startIndex, const CBoolVector *extractStatuses)
-{
- _startIndex = startIndex;
- _extractStatuses = extractStatuses;
-
- _currentIndex = 0;
- _fileIsOpen = false;
-
- return ProcessEmptyFiles();
-}
-
-HRESULT CRepackStreamBase::OpenFile()
-{
- UInt32 arcIndex = _startIndex + _currentIndex;
- const CFileItem &fi = _db->Files[arcIndex];
-
- _needWrite = (*_extractStatuses)[_currentIndex];
- if (_opCallback)
- {
- RINOK(_opCallback->ReportOperation(
- NEventIndexType::kInArcIndex, arcIndex,
- _needWrite ?
- NUpdateNotifyOp::kRepack :
- NUpdateNotifyOp::kSkip));
- }
-
- _crc = CRC_INIT_VAL;
- _calcCrc = (fi.CrcDefined && !fi.IsDir);
-
- _fileIsOpen = true;
- _rem = fi.Size;
- return S_OK;
-}
-
-const HRESULT k_My_HRESULT_CRC_ERROR = 0x20000002;
-
-HRESULT CRepackStreamBase::CloseFile()
-{
- UInt32 arcIndex = _startIndex + _currentIndex;
- const CFileItem &fi = _db->Files[arcIndex];
- _fileIsOpen = false;
- _currentIndex++;
- if (!_calcCrc || fi.Crc == CRC_GET_DIGEST(_crc))
- return S_OK;
-
- if (_extractCallback)
- {
- RINOK(_extractCallback->ReportExtractResult(
- NEventIndexType::kInArcIndex, arcIndex,
- NExtract::NOperationResult::kCRCError));
- }
- // return S_FALSE;
- return k_My_HRESULT_CRC_ERROR;
-}
-
-HRESULT CRepackStreamBase::ProcessEmptyFiles()
-{
- while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0)
- {
- RINOK(OpenFile());
- RINOK(CloseFile());
- }
- return S_OK;
-}
-
-
-
-#ifndef _7ZIP_ST
-
-class CFolderOutStream2:
- public CRepackStreamBase,
- public ISequentialOutStream,
- public CMyUnknownImp
-{
-public:
- CMyComPtr<ISequentialOutStream> _stream;
-
- MY_UNKNOWN_IMP
-
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
-};
-
-STDMETHODIMP CFolderOutStream2::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
-
- while (size != 0)
- {
- if (_fileIsOpen)
- {
- UInt32 cur = (size < _rem ? size : (UInt32)_rem);
- HRESULT result = S_OK;
- if (_needWrite)
- result = _stream->Write(data, cur, &cur);
- if (_calcCrc)
- _crc = CrcUpdate(_crc, data, cur);
- if (processedSize)
- *processedSize += cur;
- data = (const Byte *)data + cur;
- size -= cur;
- _rem -= cur;
- if (_rem == 0)
- {
- RINOK(CloseFile());
- RINOK(ProcessEmptyFiles());
- }
- RINOK(result);
- if (cur == 0)
- break;
- continue;
- }
-
- RINOK(ProcessEmptyFiles());
- if (_currentIndex == _extractStatuses->Size())
- {
- // we don't support write cut here
- return E_FAIL;
- }
- RINOK(OpenFile());
- }
-
- return S_OK;
-}
-
-#endif
-
-
-
-static const UInt32 kTempBufSize = 1 << 16;
-
-class CFolderInStream2:
- public CRepackStreamBase,
- public ISequentialInStream,
- public CMyUnknownImp
-{
- Byte *_buf;
-public:
- CMyComPtr<ISequentialInStream> _inStream;
- HRESULT Result;
-
- MY_UNKNOWN_IMP
-
- CFolderInStream2():
- Result(S_OK)
- {
- _buf = new Byte[kTempBufSize];
- }
-
- ~CFolderInStream2()
- {
- delete []_buf;
- }
-
- void Init() { Result = S_OK; }
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
-};
-
-STDMETHODIMP CFolderInStream2::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
-
- while (size != 0)
- {
- if (_fileIsOpen)
- {
- UInt32 cur = (size < _rem ? size : (UInt32)_rem);
-
- void *buf;
- if (_needWrite)
- buf = data;
- else
- {
- buf = _buf;
- if (cur > kTempBufSize)
- cur = kTempBufSize;
- }
-
- HRESULT result = _inStream->Read(buf, cur, &cur);
- _crc = CrcUpdate(_crc, buf, cur);
- _rem -= cur;
-
- if (_needWrite)
- {
- data = (Byte *)data + cur;
- size -= cur;
- if (processedSize)
- *processedSize += cur;
- }
-
- if (result != S_OK)
- Result = result;
-
- if (_rem == 0)
- {
- RINOK(CloseFile());
- RINOK(ProcessEmptyFiles());
- }
-
- RINOK(result);
-
- if (cur == 0)
- return E_FAIL;
-
- continue;
- }
-
- RINOK(ProcessEmptyFiles());
- if (_currentIndex == _extractStatuses->Size())
- {
- return S_OK;
- }
- RINOK(OpenFile());
- }
-
- return S_OK;
-}
-
-
-class CThreadDecoder
- #ifndef _7ZIP_ST
- : public CVirtThread
- #endif
-{
-public:
- CDecoder Decoder;
-
- CThreadDecoder(bool multiThreadMixer):
- Decoder(multiThreadMixer)
- {
- #ifndef _7ZIP_ST
- if (multiThreadMixer)
- {
- MtMode = false;
- NumThreads = 1;
- FosSpec = new CFolderOutStream2;
- Fos = FosSpec;
- Result = E_FAIL;
- }
- #endif
- // UnpackSize = 0;
- // send_UnpackSize = false;
- }
-
- #ifndef _7ZIP_ST
-
- bool dataAfterEnd_Error;
- HRESULT Result;
- CMyComPtr<IInStream> InStream;
-
- CFolderOutStream2 *FosSpec;
- CMyComPtr<ISequentialOutStream> Fos;
-
- UInt64 StartPos;
- const CFolders *Folders;
- int FolderIndex;
-
- // bool send_UnpackSize;
- // UInt64 UnpackSize;
-
- #ifndef _NO_CRYPTO
- CMyComPtr<ICryptoGetTextPassword> getTextPassword;
- #endif
-
- DECL_EXTERNAL_CODECS_LOC_VARS2;
-
- #ifndef _7ZIP_ST
- bool MtMode;
- UInt32 NumThreads;
- #endif
-
-
- ~CThreadDecoder() { CVirtThread::WaitThreadFinish(); }
- virtual void Execute();
-
- #endif
-};
-
-#ifndef _7ZIP_ST
-
-void CThreadDecoder::Execute()
-{
- try
- {
- #ifndef _NO_CRYPTO
- bool isEncrypted = false;
- bool passwordIsDefined = false;
- UString password;
- #endif
-
- dataAfterEnd_Error = false;
-
- Result = Decoder.Decode(
- EXTERNAL_CODECS_LOC_VARS
- InStream,
- StartPos,
- *Folders, FolderIndex,
-
- // send_UnpackSize ? &UnpackSize : NULL,
- NULL, // unpackSize : FULL unpack
-
- Fos,
- NULL, // compressProgress
-
- NULL // *inStreamMainRes
- , dataAfterEnd_Error
-
- _7Z_DECODER_CRYPRO_VARS
- #ifndef _7ZIP_ST
- , MtMode, NumThreads,
- 0 // MemUsage
- #endif
-
- );
- }
- catch(...)
- {
- Result = E_FAIL;
- }
-
- /*
- if (Result == S_OK)
- Result = FosSpec->CheckFinishedState();
- */
- FosSpec->_stream.Release();
-}
-
-#endif
-
-#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 void GetFile(const CDatabase &inDb, unsigned index, CFileItem &file, CFileItem2 &file2)
-{
- file = inDb.Files[index];
- file2.CTimeDefined = inDb.CTime.GetItem(index, file2.CTime);
- file2.ATimeDefined = inDb.ATime.GetItem(index, file2.ATime);
- file2.MTimeDefined = inDb.MTime.GetItem(index, file2.MTime);
- file2.StartPosDefined = inDb.StartPos.GetItem(index, file2.StartPos);
- file2.AttribDefined = inDb.Attrib.GetItem(index, file2.Attrib);
- file2.IsAnti = inDb.IsItemAnti(index);
- // file2.IsAux = inDb.IsItemAux(index);
-}
-
-HRESULT Update(
- DECL_EXTERNAL_CODECS_LOC_VARS
- IInStream *inStream,
- const CDbEx *db,
- const CObjectVector<CUpdateItem> &updateItems,
- // const CObjectVector<CTreeFolder> &treeFolders,
- // const CUniqBlocks &secureBlocks,
- COutArchive &archive,
- CArchiveDatabaseOut &newDatabase,
- ISequentialOutStream *seqOutStream,
- IArchiveUpdateCallback *updateCallback,
- const CUpdateOptions &options
- #ifndef _NO_CRYPTO
- , ICryptoGetTextPassword *getDecoderPassword
- #endif
- )
-{
- UInt64 numSolidFiles = options.NumSolidFiles;
- if (numSolidFiles == 0)
- numSolidFiles = 1;
-
- CMyComPtr<IArchiveUpdateCallbackFile> opCallback;
- updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
-
- CMyComPtr<IArchiveExtractCallbackMessage> extractCallback;
- updateCallback->QueryInterface(IID_IArchiveExtractCallbackMessage, (void **)&extractCallback);
-
- // size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes();
-
- /*
- CMyComPtr<IOutStream> outStream;
- RINOK(seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStream));
- if (!outStream)
- return E_NOTIMPL;
- */
-
- UInt64 startBlockSize = db ? db->ArcInfo.StartPosition: 0;
- if (startBlockSize > 0 && !options.RemoveSfxBlock)
- {
- RINOK(WriteRange(inStream, seqOutStream, 0, startBlockSize, NULL));
- }
-
- CIntArr fileIndexToUpdateIndexMap;
- UInt64 complexity = 0;
- UInt64 inSizeForReduce2 = 0;
- bool needEncryptedRepack = false;
-
- CRecordVector<CFilterMode2> filters;
- CObjectVector<CSolidGroup> groups;
- bool thereAreRepacks = false;
-
- bool useFilters = options.UseFilters;
- if (useFilters)
- {
- const CCompressionMethodMode &method = *options.Method;
-
- FOR_VECTOR (i, method.Methods)
- if (IsFilterMethod(method.Methods[i].Id))
- {
- useFilters = false;
- break;
- }
- }
-
- if (db)
- {
- fileIndexToUpdateIndexMap.Alloc(db->Files.Size());
- unsigned i;
-
- for (i = 0; i < db->Files.Size(); i++)
- fileIndexToUpdateIndexMap[i] = -1;
-
- for (i = 0; i < updateItems.Size(); i++)
- {
- int index = updateItems[i].IndexInArchive;
- if (index != -1)
- fileIndexToUpdateIndexMap[(unsigned)index] = i;
- }
-
- for (i = 0; i < db->NumFolders; i++)
- {
- CNum indexInFolder = 0;
- CNum numCopyItems = 0;
- CNum numUnpackStreams = db->NumUnpackStreamsVector[i];
- UInt64 repackSize = 0;
-
- for (CNum fi = db->FolderStartFileIndex[i]; indexInFolder < numUnpackStreams; fi++)
- {
- if (fi >= db->Files.Size())
- return E_FAIL;
-
- 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;
- CFolderEx f;
- db->ParseFolderEx(i, f);
-
- const bool isEncrypted = f.IsEncrypted();
- const bool needCopy = (numCopyItems == numUnpackStreams);
- const bool extractFilter = (useFilters || needCopy);
-
- unsigned groupIndex = Get_FilterGroup_for_Folder(filters, f, extractFilter);
-
- while (groupIndex >= groups.Size())
- groups.AddNew();
-
- groups[groupIndex].folderRefs.Add(rep);
-
- if (needCopy)
- complexity += db->GetFolderFullPackSize(i);
- else
- {
- thereAreRepacks = true;
- complexity += repackSize;
- if (inSizeForReduce2 < repackSize)
- inSizeForReduce2 = repackSize;
- if (isEncrypted)
- needEncryptedRepack = true;
- }
- }
- }
-
- UInt64 inSizeForReduce = 0;
- {
- bool isSolid = (numSolidFiles > 1 && options.NumSolidBytes != 0);
- FOR_VECTOR (i, updateItems)
- {
- const CUpdateItem &ui = updateItems[i];
- if (ui.NewData)
- {
- complexity += ui.Size;
- if (isSolid)
- inSizeForReduce += ui.Size;
- else if (inSizeForReduce < ui.Size)
- inSizeForReduce = ui.Size;
- }
- }
- }
-
- if (inSizeForReduce < inSizeForReduce2)
- inSizeForReduce = inSizeForReduce2;
-
- RINOK(updateCallback->SetTotal(complexity));
-
- CLocalProgress *lps = new CLocalProgress;
- CMyComPtr<ICompressProgressInfo> progress = lps;
- lps->Init(updateCallback, true);
-
- #ifndef _7ZIP_ST
-
- CStreamBinder sb;
- if (options.MultiThreadMixer)
- {
- RINOK(sb.CreateEvents());
- }
-
- #endif
-
- CThreadDecoder threadDecoder(options.MultiThreadMixer);
-
- #ifndef _7ZIP_ST
- if (options.MultiThreadMixer && thereAreRepacks)
- {
- #ifdef EXTERNAL_CODECS
- threadDecoder.__externalCodecs = __externalCodecs;
- #endif
- RINOK(threadDecoder.Create());
- }
- #endif
-
- {
- CAnalysis analysis;
- if (options.AnalysisLevel == 0)
- {
- analysis.ParseWav = false;
- analysis.ParseExe = false;
- analysis.ParseAll = false;
- }
- else
- {
- analysis.Callback = opCallback;
- if (options.AnalysisLevel > 0)
- {
- analysis.ParseWav = true;
- if (options.AnalysisLevel >= 7)
- {
- analysis.ParseExe = true;
- if (options.AnalysisLevel >= 9)
- analysis.ParseAll = true;
- }
- }
- }
-
- // ---------- Split files to groups ----------
-
- const CCompressionMethodMode &method = *options.Method;
-
- FOR_VECTOR (i, updateItems)
- {
- const CUpdateItem &ui = updateItems[i];
- if (!ui.NewData || !ui.HasStream())
- continue;
-
- CFilterMode2 fm;
- if (useFilters)
- {
- RINOK(analysis.GetFilterGroup(i, ui, fm));
- }
- fm.Encrypted = method.PasswordIsDefined;
-
- unsigned groupIndex = GetGroup(filters, fm);
- while (groupIndex >= groups.Size())
- groups.AddNew();
- groups[groupIndex].Indices.Add(i);
- }
- }
-
-
- #ifndef _NO_CRYPTO
-
- CCryptoGetTextPassword *getPasswordSpec = NULL;
- CMyComPtr<ICryptoGetTextPassword> getTextPassword;
- if (needEncryptedRepack)
- {
- getPasswordSpec = new CCryptoGetTextPassword;
- getTextPassword = getPasswordSpec;
-
- #ifndef _7ZIP_ST
- threadDecoder.getTextPassword = getPasswordSpec;
- #endif
-
- if (options.Method->PasswordIsDefined)
- getPasswordSpec->Password = options.Method->Password;
- else
- {
- if (!getDecoderPassword)
- return E_NOTIMPL;
- CMyComBSTR password;
- RINOK(getDecoderPassword->CryptoGetTextPassword(&password));
- if (password)
- getPasswordSpec->Password = password;
- }
- }
-
- #endif
-
-
- // ---------- Compress ----------
-
- RINOK(archive.Create(seqOutStream, false));
- RINOK(archive.SkipPrefixArchiveHeader());
-
- /*
- CIntVector treeFolderToArcIndex;
- treeFolderToArcIndex.Reserve(treeFolders.Size());
- for (i = 0; i < treeFolders.Size(); i++)
- treeFolderToArcIndex.Add(-1);
- // ---------- Write Tree (only AUX dirs) ----------
- for (i = 1; i < treeFolders.Size(); i++)
- {
- const CTreeFolder &treeFolder = treeFolders[i];
- CFileItem file;
- CFileItem2 file2;
- file2.Init();
- int secureID = 0;
- if (treeFolder.UpdateItemIndex < 0)
- {
- // we can store virtual dir item wuthout attrib, but we want all items have attrib.
- file.SetAttrib(FILE_ATTRIBUTE_DIRECTORY);
- file2.IsAux = true;
- }
- else
- {
- const CUpdateItem &ui = updateItems[treeFolder.UpdateItemIndex];
- // if item is not dir, then it's parent for alt streams.
- // we will write such items later
- if (!ui.IsDir)
- continue;
- secureID = ui.SecureIndex;
- if (ui.NewProps)
- UpdateItem_To_FileItem(ui, file, file2);
- else
- GetFile(*db, ui.IndexInArchive, file, file2);
- }
- file.Size = 0;
- file.HasStream = false;
- file.IsDir = true;
- file.Parent = treeFolder.Parent;
-
- treeFolderToArcIndex[i] = newDatabase.Files.Size();
- newDatabase.AddFile(file, file2, treeFolder.Name);
-
- if (totalSecureDataSize != 0)
- newDatabase.SecureIDs.Add(secureID);
- }
- */
-
- {
- /* ---------- Write non-AUX dirs and Empty files ---------- */
- CUIntVector emptyRefs;
-
- unsigned i;
-
- 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;
- /*
- if (ui.TreeFolderIndex >= 0)
- 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;
- UString name;
- if (ui.NewProps)
- {
- UpdateItem_To_FileItem(ui, file, file2);
- file.CrcDefined = false;
- name = ui.Name;
- }
- else
- {
- GetFile(*db, ui.IndexInArchive, file, file2);
- db->GetPath(ui.IndexInArchive, name);
- }
-
- /*
- if (totalSecureDataSize != 0)
- newDatabase.SecureIDs.Add(ui.SecureIndex);
- file.Parent = ui.ParentFolderIndex;
- */
- newDatabase.AddFile(file, file2, name);
- }
- }
-
- lps->ProgressOffset = 0;
-
- {
- // ---------- Sort Filters ----------
-
- FOR_VECTOR (i, filters)
- {
- filters[i].GroupIndex = i;
- }
- filters.Sort2();
- }
-
- for (unsigned groupIndex = 0; groupIndex < filters.Size(); groupIndex++)
- {
- const CFilterMode2 &filterMode = filters[groupIndex];
-
- CCompressionMethodMode method = *options.Method;
- {
- HRESULT res = MakeExeMethod(method, filterMode,
- #ifdef _7ZIP_ST
- false
- #else
- options.MaxFilter && options.MultiThreadMixer
- #endif
- );
-
- RINOK(res);
- }
-
- if (filterMode.Encrypted)
- {
- 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);
-
- // ---------- Repack and copy old solid blocks ----------
-
- const CSolidGroup &group = groups[filterMode.GroupIndex];
-
- FOR_VECTOR(folderRefIndex, group.folderRefs)
- {
- const CFolderRepack &rep = group.folderRefs[folderRefIndex];
-
- unsigned folderIndex = rep.FolderIndex;
-
- CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex];
-
- if (rep.NumCopyFiles == numUnpackStreams)
- {
- if (opCallback)
- {
- RINOK(opCallback->ReportOperation(
- NEventIndexType::kBlockIndex, (UInt32)folderIndex,
- NUpdateNotifyOp::kReplicate));
-
- // ---------- Copy old solid block ----------
- {
- CNum indexInFolder = 0;
- for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++)
- {
- if (db->Files[fi].HasStream)
- {
- indexInFolder++;
- RINOK(opCallback->ReportOperation(
- NEventIndexType::kInArcIndex, (UInt32)fi,
- NUpdateNotifyOp::kReplicate));
- }
- }
- }
- }
-
- UInt64 packSize = db->GetFolderFullPackSize(folderIndex);
- RINOK(WriteRange(inStream, archive.SeqStream,
- db->GetFolderStreamPos(folderIndex, 0), packSize, progress));
- lps->ProgressOffset += packSize;
-
- CFolder &folder = newDatabase.Folders.AddNew();
- db->ParseFolderInfo(folderIndex, folder);
- CNum startIndex = db->FoStartPackStreamIndex[folderIndex];
- FOR_VECTOR(j, folder.PackStreams)
- {
- newDatabase.PackSizes.Add(db->GetStreamPackSize(startIndex + j));
- // newDatabase.PackCRCsDefined.Add(db.PackCRCsDefined[startIndex + j]);
- // newDatabase.PackCRCs.Add(db.PackCRCs[startIndex + j]);
- }
-
- size_t indexStart = db->FoToCoderUnpackSizes[folderIndex];
- size_t indexEnd = db->FoToCoderUnpackSizes[folderIndex + 1];
- for (; indexStart < indexEnd; indexStart++)
- newDatabase.CoderUnpackSizes.Add(db->CoderUnpackSizes[indexStart]);
- }
- else
- {
- // ---------- Repack old solid block ----------
-
- CBoolVector extractStatuses;
-
- CNum indexInFolder = 0;
-
- if (opCallback)
- {
- RINOK(opCallback->ReportOperation(
- NEventIndexType::kBlockIndex, (UInt32)folderIndex,
- NUpdateNotifyOp::kRepack))
- }
-
- /* We could reduce data size of decoded folder, if we don't need to repack
- last files in folder. But the gain in speed is small in most cases.
- So we unpack full folder. */
-
- UInt64 sizeToEncode = 0;
-
- /*
- UInt64 importantUnpackSize = 0;
- unsigned numImportantFiles = 0;
- UInt64 decodeSize = 0;
- */
-
- for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++)
- {
- bool needExtract = false;
- const CFileItem &file = db->Files[fi];
-
- if (file.HasStream)
- {
- indexInFolder++;
- int updateIndex = fileIndexToUpdateIndexMap[fi];
- if (updateIndex >= 0 && !updateItems[updateIndex].NewData)
- needExtract = true;
- // decodeSize += file.Size;
- }
-
- extractStatuses.Add(needExtract);
- if (needExtract)
- {
- sizeToEncode += file.Size;
- /*
- numImportantFiles = extractStatuses.Size();
- importantUnpackSize = decodeSize;
- */
- }
- }
-
- // extractStatuses.DeleteFrom(numImportantFiles);
-
- unsigned startPackIndex = newDatabase.PackSizes.Size();
- UInt64 curUnpackSize;
- {
-
- CMyComPtr<ISequentialInStream> sbInStream;
- CRepackStreamBase *repackBase;
- CFolderInStream2 *FosSpec2 = NULL;
-
- CRepackInStreamWithSizes *inStreamSizeCountSpec = new CRepackInStreamWithSizes;
- CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
- {
- #ifndef _7ZIP_ST
- if (options.MultiThreadMixer)
- {
- repackBase = threadDecoder.FosSpec;
- CMyComPtr<ISequentialOutStream> sbOutStream;
- sb.CreateStreams(&sbInStream, &sbOutStream);
- sb.ReInit();
-
- threadDecoder.FosSpec->_stream = sbOutStream;
-
- threadDecoder.InStream = inStream;
- threadDecoder.StartPos = db->ArcInfo.DataStartPosition; // db->GetFolderStreamPos(folderIndex, 0);
- threadDecoder.Folders = (const CFolders *)db;
- threadDecoder.FolderIndex = folderIndex;
-
- // threadDecoder.UnpackSize = importantUnpackSize;
- // threadDecoder.send_UnpackSize = true;
- }
- else
- #endif
- {
- FosSpec2 = new CFolderInStream2;
- FosSpec2->Init();
- sbInStream = FosSpec2;
- repackBase = FosSpec2;
-
- #ifndef _NO_CRYPTO
- bool isEncrypted = false;
- bool passwordIsDefined = false;
- UString password;
- #endif
-
- CMyComPtr<ISequentialInStream> decodedStream;
- bool dataAfterEnd_Error = false;
-
- HRESULT res = threadDecoder.Decoder.Decode(
- EXTERNAL_CODECS_LOC_VARS
- inStream,
- db->ArcInfo.DataStartPosition, // db->GetFolderStreamPos(folderIndex, 0);,
- *db, folderIndex,
- // &importantUnpackSize, // *unpackSize
- NULL, // *unpackSize : FULL unpack
-
- NULL, // *outStream
- NULL, // *compressProgress
-
- &decodedStream
- , dataAfterEnd_Error
-
- _7Z_DECODER_CRYPRO_VARS
- #ifndef _7ZIP_ST
- , false // mtMode
- , 1 // numThreads
- , 0 // memUsage
- #endif
- );
-
- RINOK(res);
- if (!decodedStream)
- return E_FAIL;
-
- FosSpec2->_inStream = decodedStream;
- }
-
- repackBase->_db = db;
- repackBase->_opCallback = opCallback;
- repackBase->_extractCallback = extractCallback;
-
- UInt32 startIndex = db->FolderStartFileIndex[folderIndex];
- RINOK(repackBase->Init(startIndex, &extractStatuses));
-
- inStreamSizeCountSpec->_db = db;
- inStreamSizeCountSpec->Init(sbInStream, startIndex, &extractStatuses);
-
- #ifndef _7ZIP_ST
- if (options.MultiThreadMixer)
- {
- threadDecoder.Start();
- }
- #endif
- }
-
- curUnpackSize = sizeToEncode;
-
- HRESULT encodeRes = encoder.Encode(
- EXTERNAL_CODECS_LOC_VARS
- inStreamSizeCount,
- // NULL,
- &inSizeForReduce,
- newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curUnpackSize,
- archive.SeqStream, newDatabase.PackSizes, progress);
-
- if (encodeRes == k_My_HRESULT_CRC_ERROR)
- return E_FAIL;
-
- #ifndef _7ZIP_ST
- if (options.MultiThreadMixer)
- {
- // 16.00: hang was fixed : for case if decoding was not finished.
- // We close CBinderInStream and it calls CStreamBinder::CloseRead()
- inStreamSizeCount.Release();
- sbInStream.Release();
-
- threadDecoder.WaitExecuteFinish();
-
- HRESULT decodeRes = threadDecoder.Result;
- // if (res == k_My_HRESULT_CRC_ERROR)
- if (decodeRes == S_FALSE || threadDecoder.dataAfterEnd_Error)
- {
- if (extractCallback)
- {
- RINOK(extractCallback->ReportExtractResult(
- NEventIndexType::kInArcIndex, db->FolderStartFileIndex[folderIndex],
- // NEventIndexType::kBlockIndex, (UInt32)folderIndex,
- (decodeRes != S_OK ?
- NExtract::NOperationResult::kDataError :
- NExtract::NOperationResult::kDataAfterEnd)));
- }
- if (decodeRes != S_OK)
- return E_FAIL;
- }
- RINOK(decodeRes);
- if (encodeRes == S_OK)
- if (sb.ProcessedSize != sizeToEncode)
- encodeRes = E_FAIL;
- }
- else
- #endif
- {
- if (FosSpec2->Result == S_FALSE)
- {
- if (extractCallback)
- {
- RINOK(extractCallback->ReportExtractResult(
- NEventIndexType::kBlockIndex, (UInt32)folderIndex,
- NExtract::NOperationResult::kDataError));
- }
- return E_FAIL;
- }
- RINOK(FosSpec2->Result);
- }
-
- RINOK(encodeRes);
- RINOK(repackBase->CheckFinishedState());
-
- if (curUnpackSize != sizeToEncode)
- return E_FAIL;
- }
-
- for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
- lps->OutSize += newDatabase.PackSizes[startPackIndex];
- lps->InSize += curUnpackSize;
- }
-
- newDatabase.NumUnpackStreamsVector.Add(rep.NumCopyFiles);
-
- CNum indexInFolder = 0;
- for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++)
- {
- if (db->Files[fi].HasStream)
- {
- indexInFolder++;
- int updateIndex = fileIndexToUpdateIndexMap[fi];
- if (updateIndex >= 0)
- {
- const CUpdateItem &ui = updateItems[updateIndex];
- if (ui.NewData)
- continue;
-
- UString name;
- CFileItem file;
- CFileItem2 file2;
- GetFile(*db, fi, file, file2);
-
- if (ui.NewProps)
- {
- UpdateItem_To_FileItem2(ui, file2);
- file.IsDir = ui.IsDir;
- name = ui.Name;
- }
- else
- db->GetPath(fi, name);
-
- /*
- file.Parent = ui.ParentFolderIndex;
- if (ui.TreeFolderIndex >= 0)
- treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size();
- if (totalSecureDataSize != 0)
- newDatabase.SecureIDs.Add(ui.SecureIndex);
- */
- newDatabase.AddFile(file, file2, name);
- }
- }
- }
- }
-
-
- // ---------- Compress files to new solid blocks ----------
-
- unsigned numFiles = group.Indices.Size();
- if (numFiles == 0)
- continue;
- CRecordVector<CRefItem> refItems;
- refItems.ClearAndSetSize(numFiles);
- // bool sortByType = (options.UseTypeSorting && isSoid); // numSolidFiles > 1
- bool sortByType = options.UseTypeSorting;
-
- unsigned i;
-
- for (i = 0; i < numFiles; i++)
- refItems[i] = CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType);
-
- CSortParam sortParam;
- // sortParam.TreeFolders = &treeFolders;
- sortParam.SortByType = sortByType;
- refItems.Sort(CompareUpdateItems, (void *)&sortParam);
-
- CObjArray<UInt32> indices(numFiles);
-
- for (i = 0; i < numFiles; i++)
- {
- UInt32 index = refItems[i].Index;
- indices[i] = index;
- /*
- const CUpdateItem &ui = updateItems[index];
- CFileItem file;
- if (ui.NewProps)
- UpdateItem_To_FileItem(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;
- unsigned numSubFiles;
-
- const wchar_t *prevExtension = NULL;
-
- 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)
- {
- int slashPos = ui.Name.ReverseFind_PathSepar();
- int dotPos = ui.Name.ReverseFind_Dot();
- const wchar_t *ext = ui.Name.Ptr(dotPos <= slashPos ? ui.Name.Len() : dotPos + 1);
- if (numSubFiles == 0)
- prevExtension = ext;
- else if (!StringsAreEqualNoCase(ext, prevExtension))
- break;
- }
- }
-
- if (numSubFiles < 1)
- numSubFiles = 1;
-
- RINOK(lps->SetCur());
-
- CFolderInStream *inStreamSpec = new CFolderInStream;
- CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec);
- inStreamSpec->Init(updateCallback, &indices[i], numSubFiles);
-
- unsigned startPackIndex = newDatabase.PackSizes.Size();
- UInt64 curFolderUnpackSize = totalSize;
- // curFolderUnpackSize = (UInt64)(Int64)-1;
-
- RINOK(encoder.Encode(
- EXTERNAL_CODECS_LOC_VARS
- solidInStream,
- // NULL,
- &inSizeForReduce,
- newDatabase.Folders.AddNew(), newDatabase.CoderUnpackSizes, curFolderUnpackSize,
- archive.SeqStream, newDatabase.PackSizes, progress));
-
- if (!inStreamSpec->WasFinished())
- return E_FAIL;
-
- for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
- lps->OutSize += newDatabase.PackSizes[startPackIndex];
-
- lps->InSize += curFolderUnpackSize;
- // for ()
- // newDatabase.PackCRCsDefined.Add(false);
- // newDatabase.PackCRCs.Add(0);
-
- CNum numUnpackStreams = 0;
- UInt64 skippedSize = 0;
-
- for (unsigned subIndex = 0; subIndex < numSubFiles; subIndex++)
- {
- const CUpdateItem &ui = updateItems[indices[i + subIndex]];
- CFileItem file;
- CFileItem2 file2;
- UString name;
- if (ui.NewProps)
- {
- UpdateItem_To_FileItem(ui, file, file2);
- name = ui.Name;
- }
- else
- {
- GetFile(*db, ui.IndexInArchive, file, file2);
- db->GetPath(ui.IndexInArchive, name);
- }
- if (file2.IsAnti || file.IsDir)
- return E_FAIL;
-
- /*
- CFileItem &file = newDatabase.Files[
- startFileIndexInDatabase + i + subIndex];
- */
- if (!inStreamSpec->Processed[subIndex])
- {
- skippedSize += ui.Size;
- continue;
- // file.Name += ".locked";
- }
-
- file.Crc = inStreamSpec->CRCs[subIndex];
- file.Size = inStreamSpec->Sizes[subIndex];
-
- // if (file.Size >= 0) // test purposes
- if (file.Size != 0)
- {
- file.CrcDefined = true;
- file.HasStream = true;
- numUnpackStreams++;
- }
- else
- {
- file.CrcDefined = false;
- file.HasStream = false;
- }
-
- /*
- file.Parent = ui.ParentFolderIndex;
- if (ui.TreeFolderIndex >= 0)
- treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size();
- if (totalSecureDataSize != 0)
- newDatabase.SecureIDs.Add(ui.SecureIndex);
- */
- newDatabase.AddFile(file, file2, name);
- }
-
- // numUnpackStreams = 0 is very bad case for locked files
- // v3.13 doesn't understand it.
- newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams);
- i += numSubFiles;
-
- if (skippedSize != 0 && complexity >= skippedSize)
- {
- complexity -= skippedSize;
- RINOK(updateCallback->SetTotal(complexity));
- }
- }
- }
-
- RINOK(lps->SetCur());
-
- /*
- fileIndexToUpdateIndexMap.ClearAndFree();
- groups.ClearAndFree();
- */
-
- /*
- for (i = 0; i < newDatabase.Files.Size(); i++)
- {
- CFileItem &file = newDatabase.Files[i];
- file.Parent = treeFolderToArcIndex[file.Parent];
- }
-
- if (totalSecureDataSize != 0)
- {
- newDatabase.SecureBuf.SetCapacity(totalSecureDataSize);
- size_t pos = 0;
- newDatabase.SecureSizes.Reserve(secureBlocks.Sorted.Size());
- for (i = 0; i < secureBlocks.Sorted.Size(); i++)
- {
- const CByteBuffer &buf = secureBlocks.Bufs[secureBlocks.Sorted[i]];
- size_t size = buf.GetCapacity();
- if (size != 0)
- memcpy(newDatabase.SecureBuf + pos, buf, size);
- newDatabase.SecureSizes.Add((UInt32)size);
- pos += size;
- }
- }
- */
- newDatabase.ReserveDown();
-
- if (opCallback)
- RINOK(opCallback->ReportOperation(NEventIndexType::kNoIndex, (UInt32)(Int32)-1, NUpdateNotifyOp::kHeader));
-
- return S_OK;
-}
-
-}}
+// 7zUpdate.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/MyLinux.h"
+#include "../../../Common/StringToInt.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../Common/ItemNameUtils.h"
+
+#include "7zDecode.h"
+#include "7zEncode.h"
+#include "7zFolderInStream.h"
+#include "7zHandler.h"
+#include "7zOut.h"
+#include "7zUpdate.h"
+
+namespace NArchive {
+namespace N7z {
+
+#define k_X86 k_BCJ
+
+struct CFilterMode
+{
+ UInt32 Id;
+ UInt32 Delta; // required File Size alignment, if Id is not k_Delta.
+ // (Delta == 0) means unknown alignment
+ UInt32 Offset; // for k_ARM64
+ // UInt32 AlignSizeOpt; // for k_ARM64
+
+ CFilterMode():
+ Id(0),
+ Delta(0),
+ Offset(0)
+ // , AlignSizeOpt(0)
+ {}
+
+ void ClearFilterMode()
+ {
+ Id = 0;
+ Delta = 0;
+ Offset = 0;
+ // AlignSizeOpt = 0;
+ }
+
+ // it sets Delta as Align value, if Id is exe filter
+ // in another cases it sets Delta = 0, that
+ void SetDelta()
+ {
+ if (Id == k_IA64)
+ Delta = 16;
+ else if (Id == k_ARM64 || Id == k_ARM || Id == k_PPC || Id == k_SPARC)
+ Delta = 4;
+ else if (Id == k_ARMT)
+ Delta = 2;
+ else if (Id == k_BCJ || Id == k_BCJ2)
+ Delta = 1; // do we need it?
+ else
+ Delta = 0;
+ }
+};
+
+
+/* ---------- PE ---------- */
+
+#define MZ_SIG 0x5A4D
+
+#define PE_SIG 0x00004550
+#define PE_OptHeader_Magic_32 0x10B
+#define PE_OptHeader_Magic_64 0x20B
+// #define PE_SectHeaderSize 40
+// #define PE_SECT_EXECUTE 0x20000000
+
+static int Parse_EXE(const Byte *buf, size_t size, CFilterMode *filterMode)
+{
+ if (size < 512 || GetUi16(buf) != MZ_SIG)
+ return 0;
+
+ const Byte *p;
+ UInt32 peOffset, optHeaderSize, filterId;
+
+ peOffset = GetUi32(buf + 0x3C);
+ if (peOffset >= 0x1000 || peOffset + 512 > size || (peOffset & 7) != 0)
+ return 0;
+ p = buf + peOffset;
+ if (GetUi32(p) != PE_SIG)
+ return 0;
+ p += 4;
+
+ switch (GetUi16(p))
+ {
+ case 0x014C:
+ case 0x8664: filterId = k_X86; break;
+ case 0xAA64: filterId = k_ARM64; break;
+
+ /*
+ IMAGE_FILE_MACHINE_ARM 0x01C0 // ARM LE
+ IMAGE_FILE_MACHINE_THUMB 0x01C2 // ARM Thumb / Thumb-2 LE
+ IMAGE_FILE_MACHINE_ARMNT 0x01C4 // ARM Thumb-2, LE
+ Note: We use ARM filter for 0x01C2. (WinCE 5 - 0x01C2) files mostly contain ARM code (not Thumb/Thumb-2).
+ */
+
+ case 0x01C0: // WinCE old
+ case 0x01C2: filterId = k_ARM; break; // WinCE new
+ case 0x01C4: filterId = k_ARMT; break; // WinRT
+
+ case 0x0200: filterId = k_IA64; break;
+ default: return 0;
+ }
+
+ // const UInt32 numSections = GetUi16(p + 2);
+ optHeaderSize = GetUi16(p + 16);
+ if (optHeaderSize > (1 << 10))
+ return 0;
+
+ p += 20; /* headerSize */
+
+ switch (GetUi16(p))
+ {
+ case PE_OptHeader_Magic_32:
+ case PE_OptHeader_Magic_64:
+ break;
+ default:
+ return 0;
+ }
+
+ /*
+ // Windows exe file sizes are not aligned for 4 KiB.
+ // So we can't use (CFilterMode::Offset != 0) in solid archives.
+ // So we just don't set Offset here.
+#define NUM_SCAN_SECTIONS_MAX (1 << 6)
+#define EXE_SECTION_OFFSET_MAX (1 << 27)
+#define EXE_SECTION_SIZE_MIN (1 << 8)
+#define EXE_SECTION_SIZE_MAX (1 << 27)
+#define PE_SectHeaderSize 40
+#define PE_SECT_EXECUTE 0x20000000
+
+ if (numSections > NUM_SCAN_SECTIONS_MAX)
+ return 0;
+
+ p += optHeaderSize;
+ // UInt32 numExeSections = 0;
+ // bool execute_finded = false;
+ // UInt32 sect_va = 0;
+ // UInt32 sect_size = 0;
+ // UInt32 sect_offset = 0;
+
+ for (UInt32 i = 0; i < numSections
+ // && numExeSections < numSectionsMax
+ ; i++, p += PE_SectHeaderSize)
+ {
+ UInt32 characts, rawSize, offset;
+ if ((UInt32)(p - buf) + PE_SectHeaderSize > size)
+ return 0;
+ rawSize = GetUi32(p + 16);
+ offset = GetUi32(p + 20);
+ characts = GetUi32(p + 36);
+ if (rawSize >= EXE_SECTION_SIZE_MIN &&
+ rawSize <= EXE_SECTION_SIZE_MAX &&
+ offset <= EXE_SECTION_OFFSET_MAX &&
+ // offset < limit &&
+ offset > 0)
+ {
+ if ((characts & PE_SECT_EXECUTE) != 0)
+ {
+ // execute_finded = true;
+ // sect_va = GetUi32(p + 12);
+ // sect_size = rawSize;
+ // sect_offset = offset;
+ break;
+ }
+ }
+ }
+
+ filterMode->Offset = 0;
+ if (filterId == k_ARM64)
+ {
+ // filterMode->AlignSizeOpt = (1 << 12);
+ // const UInt32 offs = (sect_va - sect_offset) & 0xFFF;
+ // if (offs != 0)
+ // filterMode->Offset = offs; // change it
+ }
+ */
+ filterMode->Id = filterId;
+ return 1;
+}
+
+
+/* ---------- ELF ---------- */
+
+#define ELF_SIG 0x464C457F
+
+#define ELF_CLASS_32 1
+#define ELF_CLASS_64 2
+
+#define ELF_DATA_2LSB 1
+#define ELF_DATA_2MSB 2
+
+static UInt16 Get16(const Byte *p, BoolInt be) { if (be) return (UInt16)GetBe16(p); return (UInt16)GetUi16(p); }
+static UInt32 Get32(const Byte *p, BoolInt be) { if (be) return GetBe32(p); return GetUi32(p); }
+// static UInt64 Get64(const Byte *p, BoolInt be) { if (be) return GetBe64(p); return GetUi64(p); }
+
+static int Parse_ELF(const Byte *buf, size_t size, CFilterMode *filterMode)
+{
+ BoolInt /* is32, */ be;
+ UInt32 filterId;
+
+ if (size < 512 || buf[6] != 1) /* ver */
+ return 0;
+
+ if (GetUi32(buf) != ELF_SIG)
+ return 0;
+
+ switch (buf[4])
+ {
+ case ELF_CLASS_32: /* is32 = True; */ break;
+ case ELF_CLASS_64: /* is32 = False; */ break;
+ default: return 0;
+ }
+
+ switch (buf[5])
+ {
+ case ELF_DATA_2LSB: be = False; break;
+ case ELF_DATA_2MSB: be = True; break;
+ default: return 0;
+ }
+
+ switch (Get16(buf + 0x12, be))
+ {
+ case 3:
+ case 6:
+ case 62: filterId = k_X86; break;
+ case 2:
+ case 18:
+ case 43: filterId = k_SPARC; break;
+ case 20:
+ case 21: if (!be) return 0; filterId = k_PPC; break;
+ case 40: if ( be) return 0; filterId = k_ARM; break;
+ case 183: if (be) return 0; filterId = k_ARM64; break;
+
+ /* Some IA-64 ELF executables have size that is not aligned for 16 bytes.
+ So we don't use IA-64 filter for IA-64 ELF */
+ // case 50: if ( be) return 0; filterId = k_IA64; break;
+
+ default: return 0;
+ }
+
+ filterMode->Id = filterId;
+ return 1;
+}
+
+
+
+/* ---------- Mach-O ---------- */
+
+#define MACH_SIG_BE_32 0xCEFAEDFE
+#define MACH_SIG_BE_64 0xCFFAEDFE
+#define MACH_SIG_LE_32 0xFEEDFACE
+#define MACH_SIG_LE_64 0xFEEDFACF
+
+#define MACH_ARCH_ABI64 (1 << 24)
+#define MACH_MACHINE_386 7
+#define MACH_MACHINE_ARM 12
+#define MACH_MACHINE_SPARC 14
+#define MACH_MACHINE_PPC 18
+#define MACH_MACHINE_PPC64 (MACH_ARCH_ABI64 | MACH_MACHINE_PPC)
+#define MACH_MACHINE_AMD64 (MACH_ARCH_ABI64 | MACH_MACHINE_386)
+#define MACH_MACHINE_ARM64 (MACH_ARCH_ABI64 | MACH_MACHINE_ARM)
+
+static unsigned Parse_MACH(const Byte *buf, size_t size, CFilterMode *filterMode)
+{
+ UInt32 filterId, numCommands, commandsSize;
+
+ if (size < 512)
+ return 0;
+
+ BoolInt /* mode64, */ be;
+ switch (GetUi32(buf))
+ {
+ case MACH_SIG_BE_32: /* mode64 = False; */ be = True; break;
+ case MACH_SIG_BE_64: /* mode64 = True; */ be = True; break;
+ case MACH_SIG_LE_32: /* mode64 = False; */ be = False; break;
+ case MACH_SIG_LE_64: /* mode64 = True; */ be = False; break;
+ default: return 0;
+ }
+
+ switch (Get32(buf + 4, be))
+ {
+ case MACH_MACHINE_386:
+ case MACH_MACHINE_AMD64: filterId = k_X86; break;
+ case MACH_MACHINE_ARM: if ( be) return 0; filterId = k_ARM; break;
+ case MACH_MACHINE_SPARC: if (!be) return 0; filterId = k_SPARC; break;
+ case MACH_MACHINE_PPC:
+ case MACH_MACHINE_PPC64: if (!be) return 0; filterId = k_PPC; break;
+ case MACH_MACHINE_ARM64: if ( be) return 0; filterId = k_ARM64; break;
+ default: return 0;
+ }
+
+ numCommands = Get32(buf + 0x10, be);
+ commandsSize = Get32(buf + 0x14, be);
+
+ if (commandsSize > (1 << 24) || numCommands > (1 << 18))
+ return 0;
+
+ filterMode->Id = filterId;
+ return 1;
+}
+
+
+/* ---------- WAV ---------- */
+
+#define WAV_SUBCHUNK_fmt 0x20746D66
+#define WAV_SUBCHUNK_data 0x61746164
+
+#define RIFF_SIG 0x46464952
+
+static BoolInt Parse_WAV(const Byte *buf, size_t size, CFilterMode *filterMode)
+{
+ UInt32 subChunkSize, pos;
+ if (size < 0x2C)
+ return False;
+
+ if (GetUi32(buf + 0) != RIFF_SIG ||
+ GetUi32(buf + 8) != 0x45564157 || // WAVE
+ GetUi32(buf + 0xC) != WAV_SUBCHUNK_fmt)
+ return False;
+ subChunkSize = GetUi32(buf + 0x10);
+ /* [0x14 = format] = 1 (PCM) */
+ if (subChunkSize < 0x10 || subChunkSize > 0x12 || GetUi16(buf + 0x14) != 1)
+ return False;
+
+ const unsigned numChannels = GetUi16(buf + 0x16);
+ const unsigned bitsPerSample = GetUi16(buf + 0x22);
+ if ((bitsPerSample & 0x7) != 0)
+ return False;
+ const UInt32 delta = (UInt32)numChannels * (bitsPerSample >> 3);
+ if (delta == 0 || delta > 256)
+ return False;
+
+ pos = 0x14 + subChunkSize;
+
+ const int kNumSubChunksTests = 10;
+ // Do we need to scan more than 3 sub-chunks?
+ for (int i = 0; i < kNumSubChunksTests; i++)
+ {
+ if (pos + 8 > size)
+ return False;
+ subChunkSize = GetUi32(buf + pos + 4);
+ if (GetUi32(buf + pos) == WAV_SUBCHUNK_data)
+ {
+ filterMode->Id = k_Delta;
+ filterMode->Delta = delta;
+ return True;
+ }
+ if (subChunkSize > (1 << 16))
+ return False;
+ pos += subChunkSize + 8;
+ }
+ return False;
+}
+
+
+/*
+ filterMode->Delta will be set as:
+ = delta value : [1, 256] : for k_Delta
+ = 0 for another filters (branch filters)
+*/
+static BoolInt ParseFile(const Byte *buf, size_t size, CFilterMode *filterMode)
+{
+ filterMode->ClearFilterMode();
+
+ if (Parse_EXE(buf, size, filterMode)) return True;
+ if (Parse_ELF(buf, size, filterMode)) return True;
+ if (Parse_MACH(buf, size, filterMode)) return True;
+ return Parse_WAV(buf, size, filterMode);
+}
+
+
+
+
+struct CFilterMode2: public CFilterMode
+{
+ bool Encrypted;
+ unsigned GroupIndex;
+
+ CFilterMode2(): Encrypted(false) {}
+
+ int Compare(const CFilterMode2 &m) const
+ {
+ if (!Encrypted)
+ {
+ if (m.Encrypted)
+ return -1;
+ }
+ else if (!m.Encrypted)
+ return 1;
+
+ const UInt32 id1 = Id;
+ const UInt32 id2 = m.Id;
+ /*
+ // we can change the order to place k_ARM64 files close to another exe files
+ if (id1 <= k_SPARC &&
+ id2 <= k_SPARC)
+ {
+ #define k_ARM64_FOR_SORT 0x3030901
+ if (id1 == k_ARM64) id1 = k_ARM64_FOR_SORT;
+ if (id2 == k_ARM64) id2 = k_ARM64_FOR_SORT;
+ }
+ */
+ if (id1 < id2) return -1;
+ if (id1 > id2) return 1;
+
+ if (Delta < m.Delta) return -1;
+ if (Delta > m.Delta) return 1;
+
+ if (Offset < m.Offset) return -1;
+ if (Offset > m.Offset) return 1;
+
+ /* we don't go here, because GetGroup()
+ and operator ==(const CFilterMode2 &m)
+ add only unique CFilterMode2:: { Id, Delta, Offset, Encrypted } items.
+ */
+ /*
+ if (GroupIndex < m.GroupIndex) return -1;
+ if (GroupIndex > m.GroupIndex) return 1;
+ */
+ return 0;
+ }
+
+ bool operator ==(const CFilterMode2 &m) const
+ {
+ return Id == m.Id
+ && Delta == m.Delta
+ && Offset == m.Offset
+ && Encrypted == m.Encrypted;
+ }
+};
+
+static unsigned GetGroup(CRecordVector<CFilterMode2> &filters, const CFilterMode2 &m)
+{
+ unsigned i;
+ for (i = 0; i < filters.Size(); i++)
+ {
+ const CFilterMode2 &m2 = filters[i];
+ if (m == m2)
+ return i;
+ /*
+ if (m.Encrypted != m2.Encrypted)
+ {
+ if (!m.Encrypted)
+ break;
+ continue;
+ }
+
+ if (m.Id < m2.Id) break;
+ if (m.Id != m2.Id) continue;
+
+ if (m.Delta < m2.Delta) break;
+ if (m.Delta != m2.Delta) continue;
+ */
+ }
+ // filters.Insert(i, m);
+ // return i;
+ return filters.Add(m);
+}
+
+static inline bool Is86Filter(CMethodId m)
+{
+ return (m == k_BCJ || m == k_BCJ2);
+}
+
+static inline bool IsExeFilter(CMethodId m)
+{
+ switch (m)
+ {
+ case k_ARM64:
+ case k_BCJ:
+ case k_BCJ2:
+ case k_ARM:
+ case k_ARMT:
+ case k_PPC:
+ case k_SPARC:
+ case k_IA64:
+ return true;
+ }
+ return false;
+}
+
+static unsigned Get_FilterGroup_for_Folder(
+ CRecordVector<CFilterMode2> &filters, const CFolderEx &f, bool extractFilter)
+{
+ CFilterMode2 m;
+ // m.Id = 0;
+ // m.Delta = 0;
+ // m.Offset = 0;
+ m.Encrypted = f.IsEncrypted();
+
+ if (extractFilter)
+ {
+ const CCoderInfo &coder = f.Coders[f.UnpackCoder];
+
+ if (coder.MethodID == k_Delta)
+ {
+ if (coder.Props.Size() == 1)
+ {
+ m.Delta = (unsigned)coder.Props[0] + 1;
+ m.Id = k_Delta;
+ }
+ }
+ else if (IsExeFilter(coder.MethodID))
+ {
+ m.Id = (UInt32)coder.MethodID;
+ if (m.Id == k_BCJ2)
+ m.Id = k_BCJ;
+ m.SetDelta();
+ if (m.Id == k_ARM64)
+ if (coder.Props.Size() == 4)
+ m.Offset = GetUi32(coder.Props);
+ }
+ }
+
+ return GetGroup(filters, m);
+}
+
+
+
+
+static HRESULT WriteRange(IInStream *inStream, ISequentialOutStream *outStream,
+ UInt64 position, UInt64 size, ICompressProgressInfo *progress)
+{
+ RINOK(InStream_SeekSet(inStream, position))
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> 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);
+}
+
+/*
+unsigned CUpdateItem::GetExtensionPos() const
+{
+ int slashPos = Name.ReverseFind_PathSepar();
+ int dotPos = Name.ReverseFind_Dot();
+ if (dotPos <= slashPos)
+ return Name.Len();
+ return dotPos + 1;
+}
+
+UString CUpdateItem::GetExtension() const
+{
+ return Name.Ptr(GetExtensionPos());
+}
+*/
+
+#define RINOZ(x) { const int _t_ = (x); if (_t_ != 0) return _t_; }
+
+#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 CompareBonds(const CBond &b1, const CBond &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.Bonds.Size();
+ s2 = f2.Bonds.Size();
+ RINOZ_COMP(s1, s2);
+ for (i = 0; i < s1; i++)
+ RINOZ(CompareBonds(f1.Bonds[i], f2.Bonds[i]));
+ return 0;
+}
+*/
+
+/*
+static int CompareFiles(const CFileItem &f1, const CFileItem &f2)
+{
+ return CompareFileNames(f1.Name, f2.Name);
+}
+*/
+
+struct CFolderRepack
+{
+ unsigned FolderIndex;
+ CNum NumCopyFiles;
+};
+
+/*
+static int CompareFolderRepacks(const CFolderRepack *p1, const CFolderRepack *p2, void *)
+{
+ int i1 = p1->FolderIndex;
+ int i2 = p2->FolderIndex;
+ // In that version we don't want to parse folders here, so we don't compare folders
+ // probably it must be improved in future
+ // const CDbEx &db = *(const CDbEx *)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]]);
+}
+*/
+
+/*
+ we sort empty files and dirs in such order:
+ - Dir.NonAnti (name sorted)
+ - File.NonAnti (name sorted)
+ - File.Anti (name sorted)
+ - Dir.Anti (reverse name sorted)
+*/
+
+static int CompareEmptyItems(const unsigned *p1, const unsigned *p2, void *param)
+{
+ const CObjectVector<CUpdateItem> &updateItems = *(const CObjectVector<CUpdateItem> *)param;
+ const CUpdateItem &u1 = updateItems[*p1];
+ const CUpdateItem &u2 = updateItems[*p2];
+ // NonAnti < Anti
+ if (u1.IsAnti != u2.IsAnti)
+ return (u1.IsAnti ? 1 : -1);
+ if (u1.IsDir != u2.IsDir)
+ {
+ // Dir.NonAnti < File < Dir.Anti
+ if (u1.IsDir)
+ return (u1.IsAnti ? 1 : -1);
+ return (u2.IsAnti ? -1 : 1);
+ }
+ int n = CompareFileNames(u1.Name, u2.Name);
+ return (u1.IsDir && u1.IsAnti) ? -n : n;
+}
+
+static const char *g_Exts =
+ " 7z xz lzma ace arc arj bz tbz bz2 tbz2 cab deb gz tgz ha lha lzh lzo lzx pak rar rpm sit 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 m mm go swift"
+ " rc java cs rs pas bas vb cls ctl frm dlg def"
+ " f77 f f90 f95"
+ " asm s"
+ " sql manifest dep"
+ " mak clw csproj vcproj sln dsp dsw"
+ " class"
+ " bat cmd bash sh"
+ " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml"
+ " awk sed hta js json php php3 php4 php5 phptml pl pm py pyo rb tcl ts 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";
+
+static unsigned GetExtIndex(const char *ext)
+{
+ unsigned extIndex = 1;
+ const char *p = g_Exts;
+ for (;;)
+ {
+ char c = *p++;
+ if (c == 0)
+ return extIndex;
+ if (c == ' ')
+ continue;
+ unsigned 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;
+ unsigned ExtensionPos;
+ unsigned NamePos;
+ unsigned ExtensionIndex;
+
+ CRefItem() {}
+ CRefItem(UInt32 index, const CUpdateItem &ui, bool sortByType):
+ UpdateItem(&ui),
+ Index(index),
+ ExtensionPos(0),
+ NamePos(0),
+ ExtensionIndex(0)
+ {
+ if (sortByType)
+ {
+ int slashPos = ui.Name.ReverseFind_PathSepar();
+ NamePos = (unsigned)(slashPos + 1);
+ int dotPos = ui.Name.ReverseFind_Dot();
+ if (dotPos <= slashPos)
+ ExtensionPos = ui.Name.Len();
+ else
+ {
+ ExtensionPos = (unsigned)(dotPos + 1);
+ if (ExtensionPos != ui.Name.Len())
+ {
+ AString s;
+ for (unsigned pos = ExtensionPos;; pos++)
+ {
+ wchar_t c = ui.Name[pos];
+ if (c >= 0x80)
+ break;
+ if (c == 0)
+ {
+ ExtensionIndex = GetExtIndex(s);
+ break;
+ }
+ s += (char)MyCharLower_Ascii((char)c);
+ }
+ }
+ }
+ }
+ }
+};
+
+struct CSortParam
+{
+ // const CObjectVector<CTreeFolder> *TreeFolders;
+ bool SortByType;
+};
+
+/*
+ we sort files in such order:
+ - Dir.NonAnti (name sorted)
+ - alt streams
+ - Dirs
+ - Dir.Anti (reverse name sorted)
+*/
+
+
+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;
+
+ /*
+ if (u1.IsAltStream != u2.IsAltStream)
+ return u1.IsAltStream ? 1 : -1;
+ */
+
+ // Actually there are no dirs that time. They were stored in other steps
+ // So that code is unused?
+ 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 = CompareFileNames(u1.Name, u2.Name);
+ return -n;
+ }
+
+ // bool sortByType = *(bool *)param;
+ const CSortParam *sortParam = (const CSortParam *)param;
+ const bool sortByType = sortParam->SortByType;
+ if (sortByType)
+ {
+ RINOZ_COMP(a1.ExtensionIndex, a2.ExtensionIndex)
+ RINOZ(CompareFileNames(u1.Name.Ptr(a1.ExtensionPos), u2.Name.Ptr(a2.ExtensionPos)))
+ RINOZ(CompareFileNames(u1.Name.Ptr(a1.NamePos), u2.Name.Ptr(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)
+ }
+ /*
+ int par1 = a1.UpdateItem->ParentFolderIndex;
+ int par2 = a2.UpdateItem->ParentFolderIndex;
+ const CTreeFolder &tf1 = (*sortParam->TreeFolders)[par1];
+ const CTreeFolder &tf2 = (*sortParam->TreeFolders)[par2];
+
+ int b1 = tf1.SortIndex, e1 = tf1.SortIndexEnd;
+ int b2 = tf2.SortIndex, e2 = tf2.SortIndexEnd;
+ if (b1 < b2)
+ {
+ if (e1 <= b2)
+ return -1;
+ // p2 in p1
+ int par = par2;
+ for (;;)
+ {
+ const CTreeFolder &tf = (*sortParam->TreeFolders)[par];
+ par = tf.Parent;
+ if (par == par1)
+ {
+ RINOZ(CompareFileNames(u1.Name, tf.Name));
+ break;
+ }
+ }
+ }
+ else if (b2 < b1)
+ {
+ if (e2 <= b1)
+ return 1;
+ // p1 in p2
+ int par = par1;
+ for (;;)
+ {
+ const CTreeFolder &tf = (*sortParam->TreeFolders)[par];
+ par = tf.Parent;
+ if (par == par2)
+ {
+ RINOZ(CompareFileNames(tf.Name, u2.Name));
+ break;
+ }
+ }
+ }
+ */
+ // RINOZ_COMP(a1.UpdateItem->ParentSortIndex, a2.UpdateItem->ParentSortIndex);
+ RINOK(CompareFileNames(u1.Name, u2.Name))
+ RINOZ_COMP(a1.UpdateItem->IndexInClient, a2.UpdateItem->IndexInClient)
+ RINOZ_COMP(a1.UpdateItem->IndexInArchive, a2.UpdateItem->IndexInArchive)
+ return 0;
+}
+
+struct CSolidGroup
+{
+ CRecordVector<UInt32> Indices;
+
+ CRecordVector<CFolderRepack> folderRefs;
+};
+
+static const char * const g_Exe_Exts[] =
+{
+ "dll"
+ , "exe"
+ , "ocx"
+ , "sfx"
+ , "sys"
+};
+
+static const char * const g_ExeUnix_Exts[] =
+{
+ "so"
+ , "dylib"
+};
+
+static bool IsExt_Exe(const wchar_t *ext)
+{
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Exe_Exts); i++)
+ if (StringsAreEqualNoCase_Ascii(ext, g_Exe_Exts[i]))
+ return true;
+ return false;
+}
+
+/*
+static bool IsExt_ExeUnix(const wchar_t *ext)
+{
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ExeUnix_Exts); i++)
+ if (StringsAreEqualNoCase_Ascii(ext, g_ExeUnix_Exts[i]))
+ return true;
+ return false;
+}
+*/
+
+// we try to find "so" extension in such name: libstdc++.so.6.0.29
+static bool IsExt_ExeUnix_NumericAllowed(const UString &path)
+{
+ unsigned pos = path.Len();
+ unsigned dotPos = pos;
+ for (;;)
+ {
+ if (pos == 0)
+ return false;
+ const wchar_t c = path[--pos];
+ if (IS_PATH_SEPAR(c))
+ return false;
+ if (c == '.')
+ {
+ const unsigned num = (dotPos - pos) - 1;
+ if (num < 1)
+ return false;
+ const wchar_t *cur = path.Ptr(pos + 1);
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ExeUnix_Exts); i++)
+ {
+ const char *ext = g_ExeUnix_Exts[i];
+ if (num == MyStringLen(ext))
+ if (IsString1PrefixedByString2_NoCase_Ascii(cur, ext))
+ return true;
+ }
+ const wchar_t *end;
+ ConvertStringToUInt32(cur, &end);
+ if ((size_t)(end - cur) != num)
+ return false;
+ dotPos = pos;
+ }
+ }
+}
+
+
+struct CAnalysis
+{
+ CMyComPtr<IArchiveUpdateCallbackFile> Callback;
+ CByteBuffer Buffer;
+
+ bool ParseWav;
+ bool ParseExe;
+ bool ParseExeUnix;
+ bool ParseNoExt;
+ bool ParseAll;
+
+ /*
+ bool Need_ATime;
+ bool ATime_Defined;
+ FILETIME ATime;
+ */
+
+ CAnalysis():
+ ParseWav(false),
+ ParseExe(false),
+ ParseExeUnix(false),
+ ParseNoExt(false),
+ ParseAll(false)
+ /*
+ , Need_ATime(false)
+ , ATime_Defined(false)
+ */
+ {}
+
+ HRESULT GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode);
+};
+
+static const size_t kAnalysisBufSize = 1 << 14;
+
+HRESULT CAnalysis::GetFilterGroup(UInt32 index, const CUpdateItem &ui, CFilterMode &filterMode)
+{
+ filterMode.Id = 0;
+ filterMode.Delta = 0;
+ filterMode.Offset = 0;
+
+ CFilterMode filterModeTemp = filterMode;
+
+ const int slashPos = ui.Name.ReverseFind_PathSepar();
+ const int dotPos = ui.Name.ReverseFind_Dot();
+
+ // if (dotPos > slashPos)
+ {
+ bool needReadFile = ParseAll;
+ /* if (Callback) is not supported by client,
+ we still try to use file name extension to detect executable file */
+ bool probablyIsSameIsa = false;
+
+ if (!needReadFile || !Callback)
+ {
+ const wchar_t *ext = NULL;
+ if (dotPos > slashPos)
+ ext = ui.Name.Ptr((unsigned)(dotPos + 1));
+ // 7-zip stores posix attributes in high 16 bits and sets (0x8000) flag
+ if (ui.Attrib & 0x8000)
+ {
+ const unsigned st_mode = ui.Attrib >> 16;
+ /* note: executable ".so" can be without execute permission,
+ and symbolic link to such ".so" file is possible */
+ // st_mode = 00111; // for debug
+ /* in Linux we expect such permissions:
+ 0755 : for most executables
+ 0644 : for some ".so" files
+ 0777 : in WSL for all files.
+ We can try to exclude some such 0777 cases from analysis,
+ if there is non-executable extension.
+ */
+
+ if ((st_mode & (
+ MY_LIN_S_IXUSR |
+ MY_LIN_S_IXGRP |
+ MY_LIN_S_IXOTH)) != 0
+ && MY_LIN_S_ISREG(st_mode)
+ && (ui.Size >= (1u << 11)))
+ {
+ #ifndef _WIN32
+ probablyIsSameIsa = true;
+ #endif
+ needReadFile = true;
+ }
+ }
+
+ if (!needReadFile)
+ {
+ if (!ext)
+ needReadFile = ParseNoExt;
+ else
+ {
+ bool isUnixExt = false;
+ if (ParseExeUnix)
+ isUnixExt = IsExt_ExeUnix_NumericAllowed(ui.Name);
+ if (isUnixExt)
+ {
+ needReadFile = true;
+ #ifndef _WIN32
+ probablyIsSameIsa = true;
+ #endif
+ }
+ else if (IsExt_Exe(ext))
+ {
+ needReadFile = ParseExe;
+ #ifdef _WIN32
+ probablyIsSameIsa = true;
+ #endif
+ }
+ else if (StringsAreEqualNoCase_Ascii(ext, "wav"))
+ {
+ if (!needReadFile)
+ needReadFile = ParseWav;
+ }
+ }
+ }
+ }
+
+ if (needReadFile)
+ {
+ BoolInt parseRes = false;
+ if (Callback)
+ {
+ if (Buffer.Size() != kAnalysisBufSize)
+ Buffer.Alloc(kAnalysisBufSize);
+ CMyComPtr<ISequentialInStream> stream;
+ HRESULT result = Callback->GetStream2(index, &stream, NUpdateNotifyOp::kAnalyze);
+ if (result == S_OK && stream)
+ {
+ /*
+ if (Need_ATime)
+ {
+ // access time could be changed in analysis pass
+ CMyComPtr<IStreamGetProps> getProps;
+ stream.QueryInterface(IID_IStreamGetProps, (void **)&getProps);
+ if (getProps)
+ if (getProps->GetProps(NULL, NULL, &ATime, NULL, NULL) == S_OK)
+ ATime_Defined = true;
+ }
+ */
+ size_t size = kAnalysisBufSize;
+ result = ReadStream(stream, Buffer, &size);
+ stream.Release();
+ // RINOK(Callback->SetOperationResult2(index, NUpdate::NOperationResult::kOK));
+ if (result == S_OK)
+ {
+ parseRes = ParseFile(Buffer, size, &filterModeTemp);
+ }
+ }
+ } // Callback
+ else if (probablyIsSameIsa)
+ {
+ #ifdef MY_CPU_X86_OR_AMD64
+ filterModeTemp.Id = k_X86;
+ #endif
+ #ifdef MY_CPU_ARM64
+ filterModeTemp.Id = k_ARM64;
+ #endif
+ parseRes = true;
+ }
+
+ if (parseRes
+ && filterModeTemp.Id != k_Delta
+ && filterModeTemp.Delta == 0)
+ {
+ /* ParseFile() sets (filterModeTemp.Delta == 0) for all
+ methods except of k_Delta. */
+ // it's not k_Delta
+ // So we call SetDelta() to set Delta
+ filterModeTemp.SetDelta();
+ if (filterModeTemp.Delta > 1)
+ {
+ /* If file Size is not aligned, then branch filter
+ will not work for next file in solid block.
+ Maybe we should allow filter for non-aligned-size file in non-solid archives ?
+ */
+ if (ui.Size % filterModeTemp.Delta != 0)
+ parseRes = false;
+ // windows exe files are not aligned for 4 KiB.
+ /*
+ else if (filterModeTemp.Id == k_ARM64 && filterModeTemp.Offset != 0)
+ {
+ if (ui.Size % (1 << 12) != 0)
+ {
+ // If Size is not aligned for 4 KiB, then Offset will not work for next file in solid block.
+ // so we place such file in group with (Offset==0).
+ filterModeTemp.Offset = 0;
+ }
+ }
+ */
+ }
+ }
+ if (!parseRes)
+ filterModeTemp.ClearFilterMode();
+ }
+ }
+
+ filterMode = filterModeTemp;
+ return S_OK;
+}
+
+static inline void GetMethodFull(UInt64 methodID, UInt32 numStreams, CMethodFull &m)
+{
+ m.Id = methodID;
+ m.NumStreams = numStreams;
+}
+
+static HRESULT AddBondForFilter(CCompressionMethodMode &mode)
+{
+ for (unsigned c = 1; c < mode.Methods.Size(); c++)
+ {
+ if (!mode.IsThereBond_to_Coder(c))
+ {
+ CBond2 bond;
+ bond.OutCoder = 0;
+ bond.OutStream = 0;
+ bond.InCoder = c;
+ mode.Bonds.Add(bond);
+ return S_OK;
+ }
+ }
+ return E_INVALIDARG;
+}
+
+static HRESULT AddFilterBond(CCompressionMethodMode &mode)
+{
+ if (!mode.Bonds.IsEmpty())
+ return AddBondForFilter(mode);
+ return S_OK;
+}
+
+static HRESULT AddBcj2Methods(CCompressionMethodMode &mode)
+{
+ // mode.Methods[0] must be k_BCJ2 method !
+
+ CMethodFull m;
+ GetMethodFull(k_LZMA, 1, m);
+
+ m.AddProp32(NCoderPropID::kDictionarySize, 1 << 20);
+ m.AddProp32(NCoderPropID::kNumFastBytes, 128);
+ m.AddProp32(NCoderPropID::kNumThreads, 1);
+ m.AddProp32(NCoderPropID::kLitPosBits, 2);
+ m.AddProp32(NCoderPropID::kLitContextBits, 0);
+ // m.AddProp_Ascii(NCoderPropID::kMatchFinder, "BT2");
+
+ unsigned methodIndex = mode.Methods.Size();
+
+ if (mode.Bonds.IsEmpty())
+ {
+ for (unsigned i = 1; i + 1 < mode.Methods.Size(); i++)
+ {
+ CBond2 bond;
+ bond.OutCoder = i;
+ bond.OutStream = 0;
+ bond.InCoder = i + 1;
+ mode.Bonds.Add(bond);
+ }
+ }
+
+ mode.Methods.Add(m);
+ mode.Methods.Add(m);
+
+ RINOK(AddBondForFilter(mode))
+ CBond2 bond;
+ bond.OutCoder = 0;
+ bond.InCoder = methodIndex; bond.OutStream = 1; mode.Bonds.Add(bond);
+ bond.InCoder = methodIndex + 1; bond.OutStream = 2; mode.Bonds.Add(bond);
+ return S_OK;
+}
+
+static HRESULT MakeExeMethod(CCompressionMethodMode &mode,
+ const CFilterMode &filterMode, /* bool addFilter, */ bool bcj2Filter)
+{
+ if (mode.Filter_was_Inserted)
+ {
+ const CMethodFull &m = mode.Methods[0];
+ const CMethodId id = m.Id;
+ if (id == k_BCJ2)
+ return AddBcj2Methods(mode);
+ if (!m.IsSimpleCoder())
+ return E_NOTIMPL;
+ // if (Bonds.IsEmpty()) we can create bonds later
+ return AddFilterBond(mode);
+ }
+
+ if (filterMode.Id == 0)
+ return S_OK;
+
+ CMethodFull &m = mode.Methods.InsertNew(0);
+
+ {
+ FOR_VECTOR (k, mode.Bonds)
+ {
+ CBond2 &bond = mode.Bonds[k];
+ bond.InCoder++;
+ bond.OutCoder++;
+ }
+ }
+
+ HRESULT res;
+
+ if (bcj2Filter && Is86Filter(filterMode.Id))
+ {
+ GetMethodFull(k_BCJ2, 4, m);
+ res = AddBcj2Methods(mode);
+ }
+ else
+ {
+ GetMethodFull(filterMode.Id, 1, m);
+ if (filterMode.Id == k_Delta)
+ m.AddProp32(NCoderPropID::kDefaultProp, filterMode.Delta);
+ else if (filterMode.Id == k_ARM64)
+ {
+ // if (filterMode.Offset != 0)
+ m.AddProp32(
+ NCoderPropID::kDefaultProp,
+ // NCoderPropID::kBranchOffset,
+ filterMode.Offset);
+ }
+ res = AddFilterBond(mode);
+
+ int alignBits = -1;
+ {
+ const UInt32 delta = filterMode.Delta;
+ if (delta == 0 || delta > 16)
+ {
+ // if (delta == 0) alignBits = GetAlignForFilterMethod(filterMode.Id);
+ }
+ else if ((delta & ((1 << 4) - 1)) == 0) alignBits = 4;
+ else if ((delta & ((1 << 3) - 1)) == 0) alignBits = 3;
+ else if ((delta & ((1 << 2) - 1)) == 0) alignBits = 2;
+ else if ((delta & ((1 << 1) - 1)) == 0) alignBits = 1;
+ // else alignBits = 0;
+ /* alignBits=0 is default mode for lzma/lzma2.
+ So we don't set alignBits=0 here. */
+ }
+ if (res == S_OK && alignBits > 0)
+ {
+ unsigned nextCoder = 1;
+ if (!mode.Bonds.IsEmpty())
+ {
+ nextCoder = mode.Bonds.Back().InCoder;
+ }
+ if (nextCoder < mode.Methods.Size())
+ {
+ CMethodFull &nextMethod = mode.Methods[nextCoder];
+ if (nextMethod.Id == k_LZMA || nextMethod.Id == k_LZMA2)
+ {
+ if (!nextMethod.Are_Lzma_Model_Props_Defined())
+ {
+ if (alignBits != 0)
+ {
+ if (alignBits > 2 || filterMode.Id == k_Delta)
+ nextMethod.AddProp32(NCoderPropID::kPosStateBits, (unsigned)alignBits);
+ unsigned lc = 0;
+ if (alignBits < 3)
+ lc = (unsigned)(3 - alignBits);
+ nextMethod.AddProp32(NCoderPropID::kLitContextBits, lc);
+ nextMethod.AddProp32(NCoderPropID::kLitPosBits, (unsigned)alignBits);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return res;
+}
+
+
+static void UpdateItem_To_FileItem2(const CUpdateItem &ui, CFileItem2 &file2)
+{
+ file2.Attrib = ui.Attrib; file2.AttribDefined = ui.AttribDefined;
+ 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.IsAux = false;
+ file2.StartPosDefined = false;
+ // file2.StartPos = 0;
+}
+
+
+static void UpdateItem_To_FileItem(const CUpdateItem &ui,
+ CFileItem &file, CFileItem2 &file2)
+{
+ UpdateItem_To_FileItem2(ui, file2);
+
+ file.Size = ui.Size;
+ file.IsDir = ui.IsDir;
+ file.HasStream = ui.HasStream();
+ // file.IsAltStream = ui.IsAltStream;
+}
+
+
+
+Z7_CLASS_IMP_COM_2(
+ CRepackInStreamWithSizes
+ , ISequentialInStream
+ , ICompressGetSubStreamSize
+)
+ CMyComPtr<ISequentialInStream> _stream;
+ UInt64 _size;
+ const CBoolVector *_extractStatuses;
+ UInt32 _startIndex;
+public:
+ const CDbEx *_db;
+
+ void Init(ISequentialInStream *stream, UInt32 startIndex, const CBoolVector *extractStatuses)
+ {
+ _startIndex = startIndex;
+ _extractStatuses = extractStatuses;
+ _size = 0;
+ _stream = stream;
+ }
+ UInt64 GetSize() const { return _size; }
+};
+
+Z7_COM7F_IMF(CRepackInStreamWithSizes::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ UInt32 realProcessedSize;
+ const HRESULT result = _stream->Read(data, size, &realProcessedSize);
+ _size += realProcessedSize;
+ if (processedSize)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+Z7_COM7F_IMF(CRepackInStreamWithSizes::GetSubStreamSize(UInt64 subStream, UInt64 *value))
+{
+ *value = 0;
+ if (subStream >= _extractStatuses->Size())
+ return S_FALSE; // E_FAIL;
+ const unsigned index = (unsigned)subStream;
+ if ((*_extractStatuses)[index])
+ {
+ const CFileItem &fi = _db->Files[_startIndex + index];
+ if (fi.HasStream)
+ *value = fi.Size;
+ }
+ return S_OK;
+}
+
+
+class CRepackStreamBase
+{
+protected:
+ bool _needWrite;
+ bool _fileIsOpen;
+ bool _calcCrc;
+ UInt32 _crc;
+ UInt64 _rem;
+
+ const CBoolVector *_extractStatuses;
+ UInt32 _startIndex;
+ unsigned _currentIndex;
+
+ HRESULT OpenFile();
+ HRESULT CloseFile();
+ HRESULT ProcessEmptyFiles();
+
+public:
+ const CDbEx *_db;
+ CMyComPtr<IArchiveUpdateCallbackFile> _opCallback;
+ CMyComPtr<IArchiveExtractCallbackMessage2> _extractCallback;
+
+ HRESULT Init(UInt32 startIndex, const CBoolVector *extractStatuses);
+ HRESULT CheckFinishedState() const { return (_currentIndex == _extractStatuses->Size()) ? S_OK: E_FAIL; }
+};
+
+HRESULT CRepackStreamBase::Init(UInt32 startIndex, const CBoolVector *extractStatuses)
+{
+ _startIndex = startIndex;
+ _extractStatuses = extractStatuses;
+
+ _currentIndex = 0;
+ _fileIsOpen = false;
+
+ return ProcessEmptyFiles();
+}
+
+HRESULT CRepackStreamBase::OpenFile()
+{
+ UInt32 arcIndex = _startIndex + _currentIndex;
+ const CFileItem &fi = _db->Files[arcIndex];
+
+ _needWrite = (*_extractStatuses)[_currentIndex];
+ if (_opCallback)
+ {
+ RINOK(_opCallback->ReportOperation(
+ NEventIndexType::kInArcIndex, arcIndex,
+ _needWrite ?
+ NUpdateNotifyOp::kRepack :
+ NUpdateNotifyOp::kSkip))
+ }
+
+ _crc = CRC_INIT_VAL;
+ _calcCrc = (fi.CrcDefined && !fi.IsDir);
+
+ _fileIsOpen = true;
+ _rem = fi.Size;
+ return S_OK;
+}
+
+const HRESULT k_My_HRESULT_CRC_ERROR = 0x20000002;
+
+HRESULT CRepackStreamBase::CloseFile()
+{
+ UInt32 arcIndex = _startIndex + _currentIndex;
+ const CFileItem &fi = _db->Files[arcIndex];
+ _fileIsOpen = false;
+ _currentIndex++;
+ if (!_calcCrc || fi.Crc == CRC_GET_DIGEST(_crc))
+ return S_OK;
+
+ if (_extractCallback)
+ {
+ RINOK(_extractCallback->ReportExtractResult(
+ NEventIndexType::kInArcIndex, arcIndex,
+ NExtract::NOperationResult::kCRCError))
+ }
+ // return S_FALSE;
+ return k_My_HRESULT_CRC_ERROR;
+}
+
+HRESULT CRepackStreamBase::ProcessEmptyFiles()
+{
+ while (_currentIndex < _extractStatuses->Size() && _db->Files[_startIndex + _currentIndex].Size == 0)
+ {
+ RINOK(OpenFile())
+ RINOK(CloseFile())
+ }
+ return S_OK;
+}
+
+
+
+#ifndef Z7_ST
+
+class CFolderOutStream2 Z7_final:
+ public CRepackStreamBase,
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_0
+ Z7_IFACE_COM7_IMP(ISequentialOutStream)
+public:
+ CMyComPtr<ISequentialOutStream> _stream;
+};
+
+Z7_COM7F_IMF(CFolderOutStream2::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+
+ while (size != 0)
+ {
+ if (_fileIsOpen)
+ {
+ UInt32 cur = (size < _rem ? size : (UInt32)_rem);
+ HRESULT result = S_OK;
+ if (_needWrite)
+ result = _stream->Write(data, cur, &cur);
+ if (_calcCrc)
+ _crc = CrcUpdate(_crc, data, cur);
+ if (processedSize)
+ *processedSize += cur;
+ data = (const Byte *)data + cur;
+ size -= cur;
+ _rem -= cur;
+ if (_rem == 0)
+ {
+ RINOK(CloseFile())
+ RINOK(ProcessEmptyFiles())
+ }
+ RINOK(result)
+ if (cur == 0)
+ break;
+ continue;
+ }
+
+ RINOK(ProcessEmptyFiles())
+ if (_currentIndex == _extractStatuses->Size())
+ {
+ // we don't support write cut here
+ return E_FAIL;
+ }
+ RINOK(OpenFile())
+ }
+
+ return S_OK;
+}
+
+#endif
+
+
+
+static const UInt32 kTempBufSize = 1 << 16;
+
+class CFolderInStream2 Z7_final:
+ public CRepackStreamBase,
+ public ISequentialInStream,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_0
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+
+ Byte *_buf;
+public:
+ CMyComPtr<ISequentialInStream> _inStream;
+ HRESULT Result;
+
+ CFolderInStream2():
+ Result(S_OK)
+ {
+ _buf = new Byte[kTempBufSize];
+ }
+
+ ~CFolderInStream2()
+ {
+ delete []_buf;
+ }
+
+ void Init() { Result = S_OK; }
+};
+
+Z7_COM7F_IMF(CFolderInStream2::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+
+ while (size != 0)
+ {
+ if (_fileIsOpen)
+ {
+ UInt32 cur = (size < _rem ? size : (UInt32)_rem);
+
+ void *buf;
+ if (_needWrite)
+ buf = data;
+ else
+ {
+ buf = _buf;
+ if (cur > kTempBufSize)
+ cur = kTempBufSize;
+ }
+
+ const HRESULT result = _inStream->Read(buf, cur, &cur);
+ _crc = CrcUpdate(_crc, buf, cur);
+ _rem -= cur;
+
+ if (_needWrite)
+ {
+ data = (Byte *)data + cur;
+ size -= cur;
+ if (processedSize)
+ *processedSize += cur;
+ }
+
+ if (result != S_OK)
+ Result = result;
+
+ if (_rem == 0)
+ {
+ RINOK(CloseFile())
+ RINOK(ProcessEmptyFiles())
+ }
+
+ RINOK(result)
+
+ if (cur == 0)
+ return E_FAIL;
+
+ continue;
+ }
+
+ RINOK(ProcessEmptyFiles())
+ if (_currentIndex == _extractStatuses->Size())
+ {
+ return S_OK;
+ }
+ RINOK(OpenFile())
+ }
+
+ return S_OK;
+}
+
+
+class CThreadDecoder Z7_final
+ #ifndef Z7_ST
+ : public CVirtThread
+ #endif
+{
+public:
+ CDecoder Decoder;
+
+ CThreadDecoder(bool multiThreadMixer):
+ Decoder(multiThreadMixer)
+ {
+ #ifndef Z7_ST
+ if (multiThreadMixer)
+ {
+ MtMode = false;
+ NumThreads = 1;
+ FosSpec = new CFolderOutStream2;
+ Fos = FosSpec;
+ Result = E_FAIL;
+ }
+ #endif
+ // UnpackSize = 0;
+ // send_UnpackSize = false;
+ }
+
+ #ifndef Z7_ST
+
+ bool dataAfterEnd_Error;
+ HRESULT Result;
+ CMyComPtr<IInStream> InStream;
+
+ CFolderOutStream2 *FosSpec;
+ CMyComPtr<ISequentialOutStream> Fos;
+
+ UInt64 StartPos;
+ const CFolders *Folders;
+ unsigned FolderIndex;
+
+ // bool send_UnpackSize;
+ // UInt64 UnpackSize;
+
+ #ifndef Z7_NO_CRYPTO
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ #endif
+
+ DECL_EXTERNAL_CODECS_LOC_VARS_DECL
+
+ #ifndef Z7_ST
+ bool MtMode;
+ UInt32 NumThreads;
+ #endif
+
+
+ ~CThreadDecoder() Z7_DESTRUCTOR_override
+ {
+ /* WaitThreadFinish() will be called in ~CVirtThread().
+ But we need WaitThreadFinish() call before
+ destructors of this class members.
+ */
+ CVirtThread::WaitThreadFinish();
+ }
+private:
+ virtual void Execute() Z7_override;
+
+ #endif
+};
+
+#ifndef Z7_ST
+
+void CThreadDecoder::Execute()
+{
+ try
+ {
+ #ifndef Z7_NO_CRYPTO
+ bool isEncrypted = false;
+ bool passwordIsDefined = false;
+ UString password;
+ #endif
+
+ dataAfterEnd_Error = false;
+
+ Result = Decoder.Decode(
+ EXTERNAL_CODECS_LOC_VARS
+ InStream,
+ StartPos,
+ *Folders, FolderIndex,
+
+ // send_UnpackSize ? &UnpackSize : NULL,
+ NULL, // unpackSize : FULL unpack
+
+ Fos,
+ NULL, // compressProgress
+
+ NULL // *inStreamMainRes
+ , dataAfterEnd_Error
+
+ Z7_7Z_DECODER_CRYPRO_VARS
+ #ifndef Z7_ST
+ , MtMode, NumThreads,
+ 0 // MemUsage
+ #endif
+
+ );
+ }
+ catch(...)
+ {
+ Result = E_FAIL;
+ }
+
+ /*
+ if (Result == S_OK)
+ Result = FosSpec->CheckFinishedState();
+ */
+ FosSpec->_stream.Release();
+}
+
+#endif
+
+#ifndef Z7_NO_CRYPTO
+
+Z7_CLASS_IMP_NOQIB_1(
+ CCryptoGetTextPassword
+ , ICryptoGetTextPassword
+)
+public:
+ UString Password;
+};
+
+Z7_COM7F_IMF(CCryptoGetTextPassword::CryptoGetTextPassword(BSTR *password))
+{
+ return StringToBstr(Password, password);
+}
+
+#endif
+
+
+static void GetFile(const CDatabase &inDb, unsigned index, CFileItem &file, CFileItem2 &file2)
+{
+ file = inDb.Files[index];
+ file2.CTimeDefined = inDb.CTime.GetItem(index, file2.CTime);
+ file2.ATimeDefined = inDb.ATime.GetItem(index, file2.ATime);
+ file2.MTimeDefined = inDb.MTime.GetItem(index, file2.MTime);
+ file2.StartPosDefined = inDb.StartPos.GetItem(index, file2.StartPos);
+ file2.AttribDefined = inDb.Attrib.GetItem(index, file2.Attrib);
+ file2.IsAnti = inDb.IsItemAnti(index);
+ // file2.IsAux = inDb.IsItemAux(index);
+}
+
+HRESULT Update(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream,
+ const CDbEx *db,
+ CObjectVector<CUpdateItem> &updateItems,
+ // const CObjectVector<CTreeFolder> &treeFolders,
+ // const CUniqBlocks &secureBlocks,
+ ISequentialOutStream *seqOutStream,
+ IArchiveUpdateCallback *updateCallback,
+ const CUpdateOptions &options)
+{
+ UInt64 numSolidFiles = options.NumSolidFiles;
+ if (numSolidFiles == 0)
+ numSolidFiles = 1;
+
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IArchiveUpdateCallbackFile,
+ opCallback, updateCallback)
+
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IArchiveExtractCallbackMessage2,
+ extractCallback, updateCallback)
+
+ /*
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IArchiveUpdateCallbackArcProp,
+ reportArcProp, updateCallback)
+ */
+
+ // size_t totalSecureDataSize = (size_t)secureBlocks.GetTotalSizeInBytes();
+
+ CMyComPtr<IStreamSetRestriction> v_StreamSetRestriction;
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IOutStream,
+ outStream, seqOutStream)
+ if (!outStream)
+ return E_NOTIMPL;
+ const UInt64 sfxBlockSize = (db && !options.RemoveSfxBlock) ?
+ db->ArcInfo.StartPosition: 0;
+ seqOutStream->QueryInterface(IID_IStreamSetRestriction, (void **)&v_StreamSetRestriction);
+ if (v_StreamSetRestriction)
+ {
+ UInt64 offset = 0;
+ RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &offset))
+ RINOK(v_StreamSetRestriction->SetRestriction(
+ outStream ? offset + sfxBlockSize : 0,
+ outStream ? offset + sfxBlockSize + k_StartHeadersRewriteSize : 0))
+ }
+ outStream.Release();
+ if (sfxBlockSize != 0)
+ {
+ RINOK(WriteRange(inStream, seqOutStream, 0, sfxBlockSize, NULL))
+ }
+ }
+
+ CIntArr fileIndexToUpdateIndexMap;
+ UInt64 complexity = 0;
+ UInt64 inSizeForReduce2 = 0;
+
+ #ifndef Z7_NO_CRYPTO
+ bool needEncryptedRepack = false;
+ #endif
+
+ CRecordVector<CFilterMode2> filters;
+ CObjectVector<CSolidGroup> groups;
+
+ #ifndef Z7_ST
+ bool thereAreRepacks = false;
+ #endif
+
+ bool useFilters = options.UseFilters;
+ if (useFilters)
+ {
+ const CCompressionMethodMode &method = *options.Method;
+
+ FOR_VECTOR (i, method.Methods)
+ {
+ /* IsFilterMethod() knows only built-in codecs
+ FIXME: we should check IsFilter status for external filters too */
+ if (IsFilterMethod(method.Methods[i].Id))
+ {
+ useFilters = false;
+ break;
+ }
+ }
+ }
+
+ if (db)
+ {
+ fileIndexToUpdateIndexMap.Alloc(db->Files.Size());
+ unsigned i;
+
+ for (i = 0; i < db->Files.Size(); i++)
+ fileIndexToUpdateIndexMap[i] = -1;
+
+ for (i = 0; i < updateItems.Size(); i++)
+ {
+ int index = updateItems[i].IndexInArchive;
+ if (index != -1)
+ fileIndexToUpdateIndexMap[(unsigned)index] = (int)i;
+ }
+
+ for (i = 0; i < db->NumFolders; i++)
+ {
+ CNum indexInFolder = 0;
+ CNum numCopyItems = 0;
+ const CNum numUnpackStreams = db->NumUnpackStreamsVector[i];
+ UInt64 repackSize = 0;
+
+ for (CNum fi = db->FolderStartFileIndex[i]; indexInFolder < numUnpackStreams; fi++)
+ {
+ if (fi >= db->Files.Size())
+ return E_FAIL;
+
+ const CFileItem &file = db->Files[fi];
+ if (file.HasStream)
+ {
+ indexInFolder++;
+ const int updateIndex = fileIndexToUpdateIndexMap[fi];
+ if (updateIndex >= 0 && !updateItems[(unsigned)updateIndex].NewData)
+ {
+ numCopyItems++;
+ repackSize += file.Size;
+ }
+ }
+ }
+
+ if (numCopyItems == 0)
+ continue;
+
+ CFolderRepack rep;
+ rep.FolderIndex = i;
+ rep.NumCopyFiles = numCopyItems;
+ CFolderEx f;
+ db->ParseFolderEx(i, f);
+
+ #ifndef Z7_NO_CRYPTO
+ const bool isEncrypted = f.IsEncrypted();
+ #endif
+ const bool needCopy = (numCopyItems == numUnpackStreams);
+ const bool extractFilter = (useFilters || needCopy);
+
+ const unsigned groupIndex = Get_FilterGroup_for_Folder(filters, f, extractFilter);
+
+ while (groupIndex >= groups.Size())
+ groups.AddNew();
+
+ groups[groupIndex].folderRefs.Add(rep);
+
+ if (needCopy)
+ complexity += db->GetFolderFullPackSize(i);
+ else
+ {
+ #ifndef Z7_ST
+ thereAreRepacks = true;
+ #endif
+ complexity += repackSize;
+ if (inSizeForReduce2 < repackSize)
+ inSizeForReduce2 = repackSize;
+ #ifndef Z7_NO_CRYPTO
+ if (isEncrypted)
+ needEncryptedRepack = true;
+ #endif
+ }
+ }
+ }
+
+ UInt64 inSizeForReduce = 0;
+ {
+ bool isSolid = (numSolidFiles > 1 && options.NumSolidBytes != 0);
+ FOR_VECTOR (i, updateItems)
+ {
+ const CUpdateItem &ui = updateItems[i];
+ if (ui.NewData)
+ {
+ complexity += ui.Size;
+ if (isSolid)
+ inSizeForReduce += ui.Size;
+ else if (inSizeForReduce < ui.Size)
+ inSizeForReduce = ui.Size;
+ }
+ }
+ }
+
+ if (inSizeForReduce < inSizeForReduce2)
+ inSizeForReduce = inSizeForReduce2;
+
+ RINOK(updateCallback->SetTotal(complexity))
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ #ifndef Z7_ST
+
+ CStreamBinder sb;
+ /*
+ if (options.MultiThreadMixer)
+ {
+ RINOK(sb.CreateEvents());
+ }
+ */
+
+ #endif
+
+ CThreadDecoder threadDecoder(options.MultiThreadMixer);
+
+ #ifndef Z7_ST
+ if (options.MultiThreadMixer && thereAreRepacks)
+ {
+ #ifdef Z7_EXTERNAL_CODECS
+ threadDecoder._externalCodecs = _externalCodecs;
+ #endif
+ const WRes wres = threadDecoder.Create();
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ }
+ #endif
+
+ {
+ CAnalysis analysis;
+ // analysis.Need_ATime = options.Need_ATime;
+ int analysisLevel = options.AnalysisLevel;
+ // (analysisLevel < 0) means default level (5)
+ if (analysisLevel < 0)
+ analysisLevel = 5;
+ if (analysisLevel != 0)
+ {
+ analysis.Callback = opCallback;
+ analysis.ParseWav = true;
+ if (analysisLevel >= 5)
+ {
+ analysis.ParseExe = true;
+ analysis.ParseExeUnix = true;
+ // analysis.ParseNoExt = true;
+ if (analysisLevel >= 7)
+ {
+ analysis.ParseNoExt = true;
+ if (analysisLevel >= 9)
+ analysis.ParseAll = true;
+ }
+ }
+ }
+
+ // ---------- Split files to groups ----------
+
+ const CCompressionMethodMode &method = *options.Method;
+
+ FOR_VECTOR (i, updateItems)
+ {
+ const CUpdateItem &ui = updateItems[i];
+ if (!ui.NewData || !ui.HasStream())
+ continue;
+
+ CFilterMode2 fm;
+ if (useFilters)
+ {
+ // analysis.ATime_Defined = false;
+ RINOK(analysis.GetFilterGroup(i, ui, fm))
+ /*
+ if (analysis.ATime_Defined)
+ {
+ ui.ATime = FILETIME_To_UInt64(analysis.ATime);
+ ui.ATime_WasReadByAnalysis = true;
+ }
+ */
+ }
+ fm.Encrypted = method.PasswordIsDefined;
+
+ const unsigned groupIndex = GetGroup(filters, fm);
+ while (groupIndex >= groups.Size())
+ groups.AddNew();
+ groups[groupIndex].Indices.Add(i);
+ }
+ }
+
+
+ #ifndef Z7_NO_CRYPTO
+
+ CCryptoGetTextPassword *getPasswordSpec = NULL;
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ if (needEncryptedRepack)
+ {
+ getPasswordSpec = new CCryptoGetTextPassword;
+ getTextPassword = getPasswordSpec;
+
+ #ifndef Z7_ST
+ threadDecoder.getTextPassword = getPasswordSpec;
+ #endif
+
+ if (options.Method->PasswordIsDefined)
+ getPasswordSpec->Password = options.Method->Password;
+ else
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ ICryptoGetTextPassword,
+ getDecoderPassword, updateCallback)
+ if (!getDecoderPassword)
+ return E_NOTIMPL;
+ CMyComBSTR password;
+ RINOK(getDecoderPassword->CryptoGetTextPassword(&password))
+ if (password)
+ getPasswordSpec->Password = password;
+ }
+ }
+
+ #endif
+
+ // ---------- Compress ----------
+
+ COutArchive archive;
+ CArchiveDatabaseOut newDatabase;
+
+ RINOK(archive.Create_and_WriteStartPrefix(seqOutStream))
+
+ /*
+ CIntVector treeFolderToArcIndex;
+ treeFolderToArcIndex.Reserve(treeFolders.Size());
+ for (i = 0; i < treeFolders.Size(); i++)
+ treeFolderToArcIndex.Add(-1);
+ // ---------- Write Tree (only AUX dirs) ----------
+ for (i = 1; i < treeFolders.Size(); i++)
+ {
+ const CTreeFolder &treeFolder = treeFolders[i];
+ CFileItem file;
+ CFileItem2 file2;
+ file2.Init();
+ int secureID = 0;
+ if (treeFolder.UpdateItemIndex < 0)
+ {
+ // we can store virtual dir item wuthout attrib, but we want all items have attrib.
+ file.SetAttrib(FILE_ATTRIBUTE_DIRECTORY);
+ file2.IsAux = true;
+ }
+ else
+ {
+ const CUpdateItem &ui = updateItems[treeFolder.UpdateItemIndex];
+ // if item is not dir, then it's parent for alt streams.
+ // we will write such items later
+ if (!ui.IsDir)
+ continue;
+ secureID = ui.SecureIndex;
+ if (ui.NewProps)
+ UpdateItem_To_FileItem(ui, file, file2);
+ else
+ GetFile(*db, ui.IndexInArchive, file, file2);
+ }
+ file.Size = 0;
+ file.HasStream = false;
+ file.IsDir = true;
+ file.Parent = treeFolder.Parent;
+
+ treeFolderToArcIndex[i] = newDatabase.Files.Size();
+ newDatabase.AddFile(file, file2, treeFolder.Name);
+
+ if (totalSecureDataSize != 0)
+ newDatabase.SecureIDs.Add(secureID);
+ }
+ */
+
+ {
+ /* ---------- Write non-AUX dirs and Empty files ---------- */
+ CUIntVector emptyRefs;
+
+ unsigned i;
+
+ 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[(unsigned)ui.IndexInArchive].HasStream)
+ continue;
+ /*
+ if (ui.TreeFolderIndex >= 0)
+ 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;
+ UString name;
+ if (ui.NewProps)
+ {
+ UpdateItem_To_FileItem(ui, file, file2);
+ file.CrcDefined = false;
+ name = ui.Name;
+ }
+ else
+ {
+ GetFile(*db, (unsigned)ui.IndexInArchive, file, file2);
+ db->GetPath((unsigned)ui.IndexInArchive, name);
+ }
+
+ /*
+ if (totalSecureDataSize != 0)
+ newDatabase.SecureIDs.Add(ui.SecureIndex);
+ file.Parent = ui.ParentFolderIndex;
+ */
+ newDatabase.AddFile(file, file2, name);
+ }
+ }
+
+ lps->ProgressOffset = 0;
+
+ {
+ // ---------- Sort Filters ----------
+ FOR_VECTOR (i, filters)
+ {
+ filters[i].GroupIndex = i;
+ }
+ filters.Sort2();
+ }
+
+ for (unsigned groupIndex = 0; groupIndex < filters.Size(); groupIndex++)
+ {
+ const CFilterMode2 &filterMode = filters[groupIndex];
+
+ CCompressionMethodMode method = *options.Method;
+ {
+ const HRESULT res = MakeExeMethod(method, filterMode,
+ #ifdef Z7_ST
+ false
+ #else
+ options.MaxFilter && options.MultiThreadMixer
+ #endif
+ );
+
+ RINOK(res)
+ }
+
+ if (filterMode.Encrypted)
+ {
+ if (!method.PasswordIsDefined)
+ {
+ #ifndef Z7_NO_CRYPTO
+ if (getPasswordSpec)
+ method.Password = getPasswordSpec->Password;
+ #endif
+ method.PasswordIsDefined = true;
+ }
+ }
+ else
+ {
+ method.PasswordIsDefined = false;
+ method.Password.Empty();
+ }
+
+ CEncoder encoder(method);
+
+ // ---------- Repack and copy old solid blocks ----------
+
+ const CSolidGroup &group = groups[filterMode.GroupIndex];
+
+ FOR_VECTOR (folderRefIndex, group.folderRefs)
+ {
+ const CFolderRepack &rep = group.folderRefs[folderRefIndex];
+
+ const unsigned folderIndex = rep.FolderIndex;
+
+ const CNum numUnpackStreams = db->NumUnpackStreamsVector[folderIndex];
+
+ if (rep.NumCopyFiles == numUnpackStreams)
+ {
+ if (opCallback)
+ {
+ RINOK(opCallback->ReportOperation(
+ NEventIndexType::kBlockIndex, (UInt32)folderIndex,
+ NUpdateNotifyOp::kReplicate))
+
+ // ---------- Copy old solid block ----------
+ {
+ CNum indexInFolder = 0;
+ for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++)
+ {
+ if (db->Files[fi].HasStream)
+ {
+ indexInFolder++;
+ RINOK(opCallback->ReportOperation(
+ NEventIndexType::kInArcIndex, (UInt32)fi,
+ NUpdateNotifyOp::kReplicate))
+ }
+ }
+ }
+ }
+
+ const UInt64 packSize = db->GetFolderFullPackSize(folderIndex);
+ RINOK(WriteRange(inStream, archive.SeqStream,
+ db->GetFolderStreamPos(folderIndex, 0), packSize, progress))
+ lps->ProgressOffset += packSize;
+
+ const unsigned folderIndex_New = newDatabase.Folders.Size();
+ CFolder &folder = newDatabase.Folders.AddNew();
+ // v23.01: we copy FolderCrc, if FolderCrc was used
+ if (db->FolderCRCs.ValidAndDefined(folderIndex))
+ newDatabase.FolderUnpackCRCs.SetItem(folderIndex_New,
+ true, db->FolderCRCs.Vals[folderIndex]);
+
+ db->ParseFolderInfo(folderIndex, folder);
+ const CNum startIndex = db->FoStartPackStreamIndex[folderIndex];
+ FOR_VECTOR (j, folder.PackStreams)
+ {
+ newDatabase.PackSizes.Add(db->GetStreamPackSize(startIndex + j));
+ // newDatabase.PackCRCsDefined.Add(db.PackCRCsDefined[startIndex + j]);
+ // newDatabase.PackCRCs.Add(db.PackCRCs[startIndex + j]);
+ }
+
+ size_t indexStart = db->FoToCoderUnpackSizes[folderIndex];
+ const size_t indexEnd = db->FoToCoderUnpackSizes[folderIndex + 1];
+ for (; indexStart < indexEnd; indexStart++)
+ newDatabase.CoderUnpackSizes.Add(db->CoderUnpackSizes[indexStart]);
+ }
+ else
+ {
+ // ---------- Repack old solid block ----------
+
+ CBoolVector extractStatuses;
+
+ CNum indexInFolder = 0;
+
+ if (opCallback)
+ {
+ RINOK(opCallback->ReportOperation(
+ NEventIndexType::kBlockIndex, (UInt32)folderIndex,
+ NUpdateNotifyOp::kRepack))
+ }
+
+ /* We could reduce data size of decoded folder, if we don't need to repack
+ last files in folder. But the gain in speed is small in most cases.
+ So we unpack full folder. */
+
+ UInt64 sizeToEncode = 0;
+
+ /*
+ UInt64 importantUnpackSize = 0;
+ unsigned numImportantFiles = 0;
+ UInt64 decodeSize = 0;
+ */
+
+ for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++)
+ {
+ bool needExtract = false;
+ const CFileItem &file = db->Files[fi];
+
+ if (file.HasStream)
+ {
+ indexInFolder++;
+ const int updateIndex = fileIndexToUpdateIndexMap[fi];
+ if (updateIndex >= 0 && !updateItems[(unsigned)updateIndex].NewData)
+ needExtract = true;
+ // decodeSize += file.Size;
+ }
+
+ extractStatuses.Add(needExtract);
+ if (needExtract)
+ {
+ sizeToEncode += file.Size;
+ /*
+ numImportantFiles = extractStatuses.Size();
+ importantUnpackSize = decodeSize;
+ */
+ }
+ }
+
+ // extractStatuses.DeleteFrom(numImportantFiles);
+
+ unsigned startPackIndex = newDatabase.PackSizes.Size();
+ UInt64 curUnpackSize;
+ {
+ CMyComPtr<ISequentialInStream> sbInStream;
+ CRepackStreamBase *repackBase;
+ CFolderInStream2 *FosSpec2 = NULL;
+
+ CRepackInStreamWithSizes *inStreamSizeCountSpec = new CRepackInStreamWithSizes;
+ CMyComPtr<ISequentialInStream> inStreamSizeCount = inStreamSizeCountSpec;
+ {
+ #ifndef Z7_ST
+ if (options.MultiThreadMixer)
+ {
+ repackBase = threadDecoder.FosSpec;
+ CMyComPtr<ISequentialOutStream> sbOutStream;
+ sb.CreateStreams2(sbInStream, sbOutStream);
+ RINOK(sb.Create_ReInit())
+
+ threadDecoder.FosSpec->_stream = sbOutStream;
+
+ threadDecoder.InStream = inStream;
+ threadDecoder.StartPos = db->ArcInfo.DataStartPosition; // db->GetFolderStreamPos(folderIndex, 0);
+ threadDecoder.Folders = (const CFolders *)db;
+ threadDecoder.FolderIndex = folderIndex;
+
+ // threadDecoder.UnpackSize = importantUnpackSize;
+ // threadDecoder.send_UnpackSize = true;
+ }
+ else
+ #endif
+ {
+ FosSpec2 = new CFolderInStream2;
+ FosSpec2->Init();
+ sbInStream = FosSpec2;
+ repackBase = FosSpec2;
+
+ #ifndef Z7_NO_CRYPTO
+ bool isEncrypted = false;
+ bool passwordIsDefined = false;
+ UString password;
+ #endif
+
+ CMyComPtr<ISequentialInStream> decodedStream;
+ bool dataAfterEnd_Error = false;
+
+ const HRESULT res = threadDecoder.Decoder.Decode(
+ EXTERNAL_CODECS_LOC_VARS
+ inStream,
+ db->ArcInfo.DataStartPosition, // db->GetFolderStreamPos(folderIndex, 0);,
+ *db, folderIndex,
+ // &importantUnpackSize, // *unpackSize
+ NULL, // *unpackSize : FULL unpack
+
+ NULL, // *outStream
+ NULL, // *compressProgress
+
+ &decodedStream
+ , dataAfterEnd_Error
+
+ Z7_7Z_DECODER_CRYPRO_VARS
+ #ifndef Z7_ST
+ , false // mtMode
+ , 1 // numThreads
+ , 0 // memUsage
+ #endif
+ );
+
+ RINOK(res)
+ if (!decodedStream)
+ return E_FAIL;
+
+ FosSpec2->_inStream = decodedStream;
+ }
+
+ repackBase->_db = db;
+ repackBase->_opCallback = opCallback;
+ repackBase->_extractCallback = extractCallback;
+
+ UInt32 startIndex = db->FolderStartFileIndex[folderIndex];
+ RINOK(repackBase->Init(startIndex, &extractStatuses))
+
+ inStreamSizeCountSpec->_db = db;
+ inStreamSizeCountSpec->Init(sbInStream, startIndex, &extractStatuses);
+
+ #ifndef Z7_ST
+ if (options.MultiThreadMixer)
+ {
+ WRes wres = threadDecoder.Start();
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ }
+ #endif
+ }
+
+ // curUnpackSize = sizeToEncode;
+
+ HRESULT encodeRes = encoder.Encode1(
+ EXTERNAL_CODECS_LOC_VARS
+ inStreamSizeCount,
+ // NULL,
+ &inSizeForReduce,
+ sizeToEncode, // expectedDataSize
+ newDatabase.Folders.AddNew(),
+ // newDatabase.CoderUnpackSizes, curUnpackSize,
+ archive.SeqStream, newDatabase.PackSizes, progress);
+
+ if (encodeRes == k_My_HRESULT_CRC_ERROR)
+ return E_FAIL;
+
+ curUnpackSize = inStreamSizeCountSpec->GetSize();
+
+ if (encodeRes == S_OK)
+ {
+ encoder.Encode_Post(curUnpackSize, newDatabase.CoderUnpackSizes);
+ }
+
+ #ifndef Z7_ST
+ if (options.MultiThreadMixer)
+ {
+ // 16.00: hang was fixed : for case if decoding was not finished.
+ // We close CBinderInStream and it calls CStreamBinder::CloseRead()
+ inStreamSizeCount.Release();
+ sbInStream.Release();
+
+ {
+ const WRes wres = threadDecoder.WaitExecuteFinish();
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ }
+
+ const HRESULT decodeRes = threadDecoder.Result;
+ // if (res == k_My_HRESULT_CRC_ERROR)
+ if (decodeRes == S_FALSE || threadDecoder.dataAfterEnd_Error)
+ {
+ if (extractCallback)
+ {
+ RINOK(extractCallback->ReportExtractResult(
+ NEventIndexType::kInArcIndex, db->FolderStartFileIndex[folderIndex],
+ // NEventIndexType::kBlockIndex, (UInt32)folderIndex,
+ (decodeRes != S_OK ?
+ NExtract::NOperationResult::kDataError :
+ NExtract::NOperationResult::kDataAfterEnd)))
+ }
+ if (decodeRes != S_OK)
+ return E_FAIL;
+ }
+ RINOK(decodeRes)
+ if (encodeRes == S_OK)
+ if (sb.ProcessedSize != sizeToEncode)
+ encodeRes = E_FAIL;
+ }
+ else
+ #endif
+ {
+ if (FosSpec2->Result == S_FALSE)
+ {
+ if (extractCallback)
+ {
+ RINOK(extractCallback->ReportExtractResult(
+ NEventIndexType::kBlockIndex, (UInt32)folderIndex,
+ NExtract::NOperationResult::kDataError))
+ }
+ return E_FAIL;
+ }
+ RINOK(FosSpec2->Result)
+ }
+
+ RINOK(encodeRes)
+ RINOK(repackBase->CheckFinishedState())
+
+ if (curUnpackSize != sizeToEncode)
+ return E_FAIL;
+ }
+
+ for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
+ lps->OutSize += newDatabase.PackSizes[startPackIndex];
+ lps->InSize += curUnpackSize;
+ }
+
+ newDatabase.NumUnpackStreamsVector.Add(rep.NumCopyFiles);
+
+ CNum indexInFolder = 0;
+ for (CNum fi = db->FolderStartFileIndex[folderIndex]; indexInFolder < numUnpackStreams; fi++)
+ {
+ if (db->Files[fi].HasStream)
+ {
+ indexInFolder++;
+ const int updateIndex = fileIndexToUpdateIndexMap[fi];
+ if (updateIndex >= 0)
+ {
+ const CUpdateItem &ui = updateItems[(unsigned)updateIndex];
+ if (ui.NewData)
+ continue;
+
+ UString name;
+ CFileItem file;
+ CFileItem2 file2;
+ GetFile(*db, fi, file, file2);
+
+ if (ui.NewProps)
+ {
+ UpdateItem_To_FileItem2(ui, file2);
+ file.IsDir = ui.IsDir;
+ name = ui.Name;
+ }
+ else
+ db->GetPath(fi, name);
+
+ /*
+ file.Parent = ui.ParentFolderIndex;
+ if (ui.TreeFolderIndex >= 0)
+ treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size();
+ if (totalSecureDataSize != 0)
+ newDatabase.SecureIDs.Add(ui.SecureIndex);
+ */
+ newDatabase.AddFile(file, file2, name);
+ }
+ }
+ }
+ }
+
+
+ // ---------- Compress files to new solid blocks ----------
+
+ const unsigned numFiles = group.Indices.Size();
+ if (numFiles == 0)
+ continue;
+ CRecordVector<CRefItem> refItems;
+ refItems.ClearAndSetSize(numFiles);
+ // bool sortByType = (options.UseTypeSorting && isSoid); // numSolidFiles > 1
+ const bool sortByType = options.UseTypeSorting;
+
+ unsigned i;
+
+ for (i = 0; i < numFiles; i++)
+ refItems[i] = CRefItem(group.Indices[i], updateItems[group.Indices[i]], sortByType);
+
+ CSortParam sortParam;
+ // sortParam.TreeFolders = &treeFolders;
+ sortParam.SortByType = sortByType;
+ refItems.Sort(CompareUpdateItems, (void *)&sortParam);
+
+ CObjArray<UInt32> indices(numFiles);
+
+ for (i = 0; i < numFiles; i++)
+ {
+ const UInt32 index = refItems[i].Index;
+ indices[i] = index;
+ /*
+ const CUpdateItem &ui = updateItems[index];
+ CFileItem file;
+ if (ui.NewProps)
+ UpdateItem_To_FileItem(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;
+ unsigned numSubFiles;
+
+ const wchar_t *prevExtension = NULL;
+
+ 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)
+ {
+ const int slashPos = ui.Name.ReverseFind_PathSepar();
+ const int dotPos = ui.Name.ReverseFind_Dot();
+ const wchar_t *ext = ui.Name.Ptr(dotPos <= slashPos ? ui.Name.Len() : (unsigned)(dotPos + 1));
+ if (numSubFiles == 0)
+ prevExtension = ext;
+ else if (!StringsAreEqualNoCase(ext, prevExtension))
+ break;
+ }
+ }
+
+ if (numSubFiles < 1)
+ numSubFiles = 1;
+
+ RINOK(lps->SetCur())
+
+ /*
+ const unsigned folderIndex = newDatabase.NumUnpackStreamsVector.Size();
+
+ if (opCallback)
+ {
+ RINOK(opCallback->ReportOperation(
+ NEventIndexType::kBlockIndex, (UInt32)folderIndex,
+ NUpdateNotifyOp::kAdd));
+ }
+ */
+
+
+ CFolderInStream *inStreamSpec = new CFolderInStream;
+ CMyComPtr<ISequentialInStream> solidInStream(inStreamSpec);
+
+ // inStreamSpec->_reportArcProp = reportArcProp;
+
+ inStreamSpec->Need_CTime = options.Need_CTime;
+ inStreamSpec->Need_ATime = options.Need_ATime;
+ inStreamSpec->Need_MTime = options.Need_MTime;
+ inStreamSpec->Need_Attrib = options.Need_Attrib;
+ // inStreamSpec->Need_Crc = options.Need_Crc;
+
+ inStreamSpec->Init(updateCallback, &indices[i], numSubFiles);
+
+ unsigned startPackIndex = newDatabase.PackSizes.Size();
+ // UInt64 curFolderUnpackSize = totalSize;
+ // curFolderUnpackSize = (UInt64)(Int64)-1; // for debug
+ const UInt64 expectedDataSize = totalSize;
+
+ // const unsigned folderIndex_New = newDatabase.Folders.Size();
+
+ RINOK(encoder.Encode1(
+ EXTERNAL_CODECS_LOC_VARS
+ solidInStream,
+ // NULL,
+ &inSizeForReduce,
+ expectedDataSize, // expected size
+ newDatabase.Folders.AddNew(),
+ // newDatabase.CoderUnpackSizes, curFolderUnpackSize,
+ archive.SeqStream, newDatabase.PackSizes, progress))
+
+ if (!inStreamSpec->WasFinished())
+ return E_FAIL;
+
+ /*
+ if (inStreamSpec->Need_FolderCrc)
+ newDatabase.FolderUnpackCRCs.SetItem(folderIndex_New,
+ true, inStreamSpec->GetFolderCrc());
+ */
+
+ const UInt64 curFolderUnpackSize = inStreamSpec->Get_TotalSize_for_Coder();
+ encoder.Encode_Post(curFolderUnpackSize, newDatabase.CoderUnpackSizes);
+
+ UInt64 packSize = 0;
+ // const UInt32 numStreams = newDatabase.PackSizes.Size() - startPackIndex;
+ for (; startPackIndex < newDatabase.PackSizes.Size(); startPackIndex++)
+ packSize += newDatabase.PackSizes[startPackIndex];
+ lps->OutSize += packSize;
+
+ // for ()
+ // newDatabase.PackCRCsDefined.Add(false);
+ // newDatabase.PackCRCs.Add(0);
+
+ CNum numUnpackStreams = 0;
+ UInt64 skippedSize = 0;
+ UInt64 procSize = 0;
+ // unsigned numProcessedFiles = 0;
+
+ for (unsigned subIndex = 0; subIndex < numSubFiles; subIndex++)
+ {
+ const CUpdateItem &ui = updateItems[indices[i + subIndex]];
+ CFileItem file;
+ CFileItem2 file2;
+ UString name;
+ if (ui.NewProps)
+ {
+ UpdateItem_To_FileItem(ui, file, file2);
+ name = ui.Name;
+ }
+ else
+ {
+ GetFile(*db, (unsigned)ui.IndexInArchive, file, file2);
+ db->GetPath((unsigned)ui.IndexInArchive, name);
+ }
+ if (file2.IsAnti || file.IsDir)
+ return E_FAIL;
+
+ /*
+ CFileItem &file = newDatabase.Files[
+ startFileIndexInDatabase + i + subIndex];
+ */
+ if (!inStreamSpec->Processed[subIndex])
+ {
+ // we don't add file here
+ skippedSize += ui.Size;
+ continue; // comment it for debug
+ // name += ".locked"; // for debug
+ }
+
+ // if (inStreamSpec->Need_Crc)
+ file.Crc = inStreamSpec->CRCs[subIndex];
+ file.Size = inStreamSpec->Sizes[subIndex];
+
+ procSize += file.Size;
+ // if (file.Size >= 0) // for debug: test purposes
+ if (file.Size != 0)
+ {
+ file.CrcDefined = true; // inStreamSpec->Need_Crc;
+ file.HasStream = true;
+ numUnpackStreams++;
+ }
+ else
+ {
+ file.CrcDefined = false;
+ file.HasStream = false;
+ }
+
+ if (inStreamSpec->TimesDefined[subIndex])
+ {
+ if (inStreamSpec->Need_CTime)
+ { file2.CTimeDefined = true; file2.CTime = inStreamSpec->CTimes[subIndex]; }
+ if (inStreamSpec->Need_ATime
+ // && !ui.ATime_WasReadByAnalysis
+ )
+ { file2.ATimeDefined = true; file2.ATime = inStreamSpec->ATimes[subIndex]; }
+ if (inStreamSpec->Need_MTime)
+ { file2.MTimeDefined = true; file2.MTime = inStreamSpec->MTimes[subIndex]; }
+ if (inStreamSpec->Need_Attrib)
+ {
+ file2.AttribDefined = true;
+ file2.Attrib = inStreamSpec->Attribs[subIndex];
+ }
+ }
+
+ /*
+ file.Parent = ui.ParentFolderIndex;
+ if (ui.TreeFolderIndex >= 0)
+ treeFolderToArcIndex[ui.TreeFolderIndex] = newDatabase.Files.Size();
+ if (totalSecureDataSize != 0)
+ newDatabase.SecureIDs.Add(ui.SecureIndex);
+ */
+ /*
+ if (reportArcProp)
+ {
+ RINOK(ReportItemProps(reportArcProp, ui.IndexInClient, file.Size,
+ file.CrcDefined ? &file.Crc : NULL))
+ }
+ */
+
+ // numProcessedFiles++;
+ newDatabase.AddFile(file, file2, name);
+ }
+
+ /*
+ // for debug:
+ // we can write crc to folders area, if folder contains only one file
+ if (numUnpackStreams == 1 && numSubFiles == 1)
+ {
+ const CFileItem &file = newDatabase.Files.Back();
+ if (file.CrcDefined)
+ newDatabase.FolderUnpackCRCs.SetItem(folderIndex_New, true, file.Crc);
+ }
+ */
+
+ /*
+ // it's optional check to ensure that sizes are correct
+ if (inStreamSpec->TotalSize_for_Coder != curFolderUnpackSize)
+ return E_FAIL;
+ */
+ // if (inStreamSpec->AlignLog == 0)
+ {
+ if (procSize != curFolderUnpackSize)
+ return E_FAIL;
+ }
+ // else
+ {
+ /*
+ {
+ const CFolder &old = newDatabase.Folders.Back();
+ CFolder &folder = newDatabase.Folders.AddNew();
+ {
+ const unsigned numBonds = old.Bonds.Size();
+ folder.Bonds.SetSize(numBonds + 1);
+ for (unsigned k = 0; k < numBonds; k++)
+ folder.Bonds[k] = old.Bonds[k];
+ CBond &bond = folder.Bonds[numBonds];
+ bond.PackIndex = 0;
+ bond.UnpackIndex = 0;
+ }
+ {
+ const unsigned numCoders = old.Coders.Size();
+ folder.Coders.SetSize(numCoders + 1);
+ for (unsigned k = 0; k < numCoders; k++)
+ folder.Coders[k] = old.Coders[k];
+ CCoderInfo &cod = folder.Coders[numCoders];
+ cod.Props.Alloc(1);
+ cod.Props[0] = (Byte)inStreamSpec->AlignLog;
+ cod.NumStreams = 1;
+ }
+ {
+ const unsigned numPackStreams = old.Coders.Size();
+ folder.Coders.SetSize(numPackStreams);
+ for (unsigned k = 0; k < numPackStreams; k++)
+ folder.PackStreams[k] = old.PackStreams[k];
+ }
+ }
+ newDatabase.Folders.Delete(newDatabase.Folders.Size() - 2);
+ */
+ }
+
+
+ lps->InSize += procSize;
+ // lps->InSize += curFolderUnpackSize;
+
+ // numUnpackStreams = 0 is very bad case for locked files
+ // v3.13 doesn't understand it.
+ newDatabase.NumUnpackStreamsVector.Add(numUnpackStreams);
+ i += numSubFiles;
+
+ if (skippedSize != 0 && complexity >= skippedSize)
+ {
+ complexity -= skippedSize;
+ RINOK(updateCallback->SetTotal(complexity))
+ }
+
+ /*
+ if (reportArcProp)
+ {
+ PROPVARIANT prop;
+ prop.vt = VT_EMPTY;
+ prop.wReserved1 = 0;
+ {
+ NWindows::NCOM::PropVarEm_Set_UInt32(&prop, numProcessedFiles);
+ RINOK(reportArcProp->ReportProp(
+ NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidNumSubFiles, &prop));
+ }
+ {
+ NWindows::NCOM::PropVarEm_Set_UInt64(&prop, curFolderUnpackSize);
+ RINOK(reportArcProp->ReportProp(
+ NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidSize, &prop));
+ }
+ {
+ NWindows::NCOM::PropVarEm_Set_UInt64(&prop, packSize);
+ RINOK(reportArcProp->ReportProp(
+ NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidPackSize, &prop));
+ }
+ {
+ NWindows::NCOM::PropVarEm_Set_UInt32(&prop, numStreams);
+ RINOK(reportArcProp->ReportProp(
+ NEventIndexType::kBlockIndex, (UInt32)folderIndex, kpidNumStreams, &prop));
+ }
+ RINOK(reportArcProp->ReportFinished(NEventIndexType::kBlockIndex, (UInt32)folderIndex, NUpdate::NOperationResult::kOK));
+ }
+ */
+ /*
+ if (opCallback)
+ {
+ RINOK(opCallback->ReportOperation(
+ NEventIndexType::kBlockIndex, (UInt32)folderIndex,
+ NUpdateNotifyOp::kOpFinished));
+ }
+ */
+ }
+ }
+
+ RINOK(lps->SetCur())
+
+ /*
+ fileIndexToUpdateIndexMap.ClearAndFree();
+ groups.ClearAndFree();
+ */
+
+ /*
+ for (i = 0; i < newDatabase.Files.Size(); i++)
+ {
+ CFileItem &file = newDatabase.Files[i];
+ file.Parent = treeFolderToArcIndex[file.Parent];
+ }
+
+ if (totalSecureDataSize != 0)
+ {
+ newDatabase.SecureBuf.SetCapacity(totalSecureDataSize);
+ size_t pos = 0;
+ newDatabase.SecureSizes.Reserve(secureBlocks.Sorted.Size());
+ for (i = 0; i < secureBlocks.Sorted.Size(); i++)
+ {
+ const CByteBuffer &buf = secureBlocks.Bufs[secureBlocks.Sorted[i]];
+ size_t size = buf.GetCapacity();
+ if (size != 0)
+ memcpy(newDatabase.SecureBuf + pos, buf, size);
+ newDatabase.SecureSizes.Add((UInt32)size);
+ pos += size;
+ }
+ }
+ */
+
+ {
+ const unsigned numFolders = newDatabase.Folders.Size();
+ if (newDatabase.NumUnpackStreamsVector.Size() != numFolders
+ || newDatabase.FolderUnpackCRCs.Defs.Size() > numFolders)
+ return E_FAIL;
+ newDatabase.FolderUnpackCRCs.if_NonEmpty_FillResedue_with_false(numFolders);
+ }
+
+ updateItems.ClearAndFree();
+ newDatabase.ReserveDown();
+
+ if (opCallback)
+ RINOK(opCallback->ReportOperation(NEventIndexType::kNoIndex, (UInt32)(Int32)-1, NUpdateNotifyOp::kHeader))
+
+ RINOK(archive.WriteDatabase(EXTERNAL_CODECS_LOC_VARS
+ newDatabase, options.HeaderMethod, options.HeaderOptions))
+
+ if (v_StreamSetRestriction)
+ RINOK(v_StreamSetRestriction->SetRestriction(0, 0))
+
+ return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Archive/7z/7zUpdate.h b/CPP/7zip/Archive/7z/7zUpdate.h
index 06a0b05..de4117a 100644
--- a/CPP/7zip/Archive/7z/7zUpdate.h
+++ b/CPP/7zip/Archive/7z/7zUpdate.h
@@ -1,139 +1,146 @@
-// 7zUpdate.h
-
-#ifndef __7Z_UPDATE_H
-#define __7Z_UPDATE_H
-
-#include "../IArchive.h"
-
-// #include "../../Common/UniqBlocks.h"
-
-#include "7zCompressionMode.h"
-#include "7zIn.h"
-#include "7zOut.h"
-
-namespace NArchive {
-namespace N7z {
-
-/*
-struct CTreeFolder
-{
- UString Name;
- int Parent;
- CIntVector SubFolders;
- int UpdateItemIndex;
- int SortIndex;
- int SortIndexEnd;
-
- CTreeFolder(): UpdateItemIndex(-1) {}
-};
-*/
-
-struct CUpdateItem
-{
- int IndexInArchive;
- int IndexInClient;
-
- UInt64 CTime;
- UInt64 ATime;
- UInt64 MTime;
-
- UInt64 Size;
- UString Name;
- /*
- bool IsAltStream;
- int ParentFolderIndex;
- int TreeFolderIndex;
- */
-
- // that code is not used in 9.26
- // int ParentSortIndex;
- // int ParentSortIndexEnd;
-
- UInt32 Attrib;
-
- bool NewData;
- bool NewProps;
-
- bool IsAnti;
- bool IsDir;
-
- bool AttribDefined;
- bool CTimeDefined;
- bool ATimeDefined;
- bool MTimeDefined;
-
- // int SecureIndex; // 0 means (no_security)
-
- bool HasStream() const { return !IsDir && !IsAnti && Size != 0; }
- // bool HasStream() const { return !IsDir && !IsAnti /* && Size != 0 */; } // for test purposes
-
- CUpdateItem():
- // ParentSortIndex(-1),
- // IsAltStream(false),
- IsAnti(false),
- IsDir(false),
- AttribDefined(false),
- CTimeDefined(false),
- ATimeDefined(false),
- MTimeDefined(false)
- // SecureIndex(0)
- {}
- void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); }
-
- // unsigned GetExtensionPos() const;
- // UString GetExtension() const;
-};
-
-struct CUpdateOptions
-{
- const CCompressionMethodMode *Method;
- const CCompressionMethodMode *HeaderMethod;
- bool UseFilters; // use additional filters for some files
- bool MaxFilter; // use BCJ2 filter instead of BCJ
- int AnalysisLevel;
-
- CHeaderOptions HeaderOptions;
-
- UInt64 NumSolidFiles;
- UInt64 NumSolidBytes;
- bool SolidExtension;
-
- bool UseTypeSorting;
-
- bool RemoveSfxBlock;
- bool MultiThreadMixer;
-
- CUpdateOptions():
- Method(NULL),
- HeaderMethod(NULL),
- UseFilters(false),
- MaxFilter(false),
- AnalysisLevel(-1),
- NumSolidFiles((UInt64)(Int64)(-1)),
- NumSolidBytes((UInt64)(Int64)(-1)),
- SolidExtension(false),
- UseTypeSorting(true),
- RemoveSfxBlock(false),
- MultiThreadMixer(true)
- {}
-};
-
-HRESULT Update(
- DECL_EXTERNAL_CODECS_LOC_VARS
- IInStream *inStream,
- const CDbEx *db,
- const CObjectVector<CUpdateItem> &updateItems,
- // const CObjectVector<CTreeFolder> &treeFolders, // treeFolders[0] is root
- // const CUniqBlocks &secureBlocks,
- COutArchive &archive,
- CArchiveDatabaseOut &newDatabase,
- ISequentialOutStream *seqOutStream,
- IArchiveUpdateCallback *updateCallback,
- const CUpdateOptions &options
- #ifndef _NO_CRYPTO
- , ICryptoGetTextPassword *getDecoderPassword
- #endif
- );
-}}
-
-#endif
+// 7zUpdate.h
+
+#ifndef ZIP7_INC_7Z_UPDATE_H
+#define ZIP7_INC_7Z_UPDATE_H
+
+#include "../IArchive.h"
+
+// #include "../../Common/UniqBlocks.h"
+
+#include "7zCompressionMode.h"
+#include "7zIn.h"
+
+namespace NArchive {
+namespace N7z {
+
+/*
+struct CTreeFolder
+{
+ UString Name;
+ int Parent;
+ CIntVector SubFolders;
+ int UpdateItemIndex;
+ int SortIndex;
+ int SortIndexEnd;
+
+ CTreeFolder(): UpdateItemIndex(-1) {}
+};
+*/
+
+struct CUpdateItem
+{
+ int IndexInArchive;
+ unsigned IndexInClient;
+
+ UInt64 CTime;
+ UInt64 ATime;
+ UInt64 MTime;
+
+ UInt64 Size;
+ UString Name;
+ /*
+ bool IsAltStream;
+ int ParentFolderIndex;
+ int TreeFolderIndex;
+ */
+
+ // that code is not used in 9.26
+ // int ParentSortIndex;
+ // int ParentSortIndexEnd;
+
+ UInt32 Attrib;
+
+ bool NewData;
+ bool NewProps;
+
+ bool IsAnti;
+ bool IsDir;
+
+ bool AttribDefined;
+ bool CTimeDefined;
+ bool ATimeDefined;
+ bool MTimeDefined;
+
+ // bool ATime_WasReadByAnalysis;
+
+ // int SecureIndex; // 0 means (no_security)
+
+ bool HasStream() const { return !IsDir && !IsAnti && Size != 0; }
+ // bool HasStream() const { return !IsDir && !IsAnti /* && Size != 0 */; } // for test purposes
+
+ CUpdateItem():
+ // ParentSortIndex(-1),
+ // IsAltStream(false),
+ IsAnti(false),
+ IsDir(false),
+ AttribDefined(false),
+ CTimeDefined(false),
+ ATimeDefined(false),
+ MTimeDefined(false)
+ // , ATime_WasReadByAnalysis(false)
+ // SecureIndex(0)
+ {}
+ void SetDirStatusFromAttrib() { IsDir = ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0); }
+
+ // unsigned GetExtensionPos() const;
+ // UString GetExtension() const;
+};
+
+struct CUpdateOptions
+{
+ const CCompressionMethodMode *Method;
+ const CCompressionMethodMode *HeaderMethod;
+ bool UseFilters; // use additional filters for some files
+ bool MaxFilter; // use BCJ2 filter instead of BCJ
+ int AnalysisLevel;
+
+ UInt64 NumSolidFiles;
+ UInt64 NumSolidBytes;
+ bool SolidExtension;
+
+ bool UseTypeSorting;
+
+ bool RemoveSfxBlock;
+ bool MultiThreadMixer;
+
+ bool Need_CTime;
+ bool Need_ATime;
+ bool Need_MTime;
+ bool Need_Attrib;
+ // bool Need_Crc;
+
+ CHeaderOptions HeaderOptions;
+
+ CUpdateOptions():
+ Method(NULL),
+ HeaderMethod(NULL),
+ UseFilters(false),
+ MaxFilter(false),
+ AnalysisLevel(-1),
+ NumSolidFiles((UInt64)(Int64)(-1)),
+ NumSolidBytes((UInt64)(Int64)(-1)),
+ SolidExtension(false),
+ UseTypeSorting(true),
+ RemoveSfxBlock(false),
+ MultiThreadMixer(true),
+ Need_CTime(false),
+ Need_ATime(false),
+ Need_MTime(false),
+ Need_Attrib(false)
+ // , Need_Crc(true)
+ {}
+};
+
+HRESULT Update(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IInStream *inStream,
+ const CDbEx *db,
+ CObjectVector<CUpdateItem> &updateItems,
+ // const CObjectVector<CTreeFolder> &treeFolders, // treeFolders[0] is root
+ // const CUniqBlocks &secureBlocks,
+ ISequentialOutStream *seqOutStream,
+ IArchiveUpdateCallback *updateCallback,
+ const CUpdateOptions &options);
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/7z/StdAfx.cpp b/CPP/7zip/Archive/7z/StdAfx.cpp
index c6d3b1f..d0feea8 100644
--- a/CPP/7zip/Archive/7z/StdAfx.cpp
+++ b/CPP/7zip/Archive/7z/StdAfx.cpp
@@ -1,3 +1,3 @@
-// StdAfx.cpp
-
-#include "StdAfx.h"
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Archive/7z/StdAfx.h b/CPP/7zip/Archive/7z/StdAfx.h
index 59d9ac1..035267c 100644
--- a/CPP/7zip/Archive/7z/StdAfx.h
+++ b/CPP/7zip/Archive/7z/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "../../../Common/Common.h"
-
-#endif
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Archive/7z/makefile b/CPP/7zip/Archive/7z/makefile
new file mode 100644
index 0000000..ff60e4d
--- /dev/null
+++ b/CPP/7zip/Archive/7z/makefile
@@ -0,0 +1,81 @@
+PROG = 7z.dll
+DEF_FILE = ../Archive.def
+CFLAGS = $(CFLAGS) \
+ -DZ7_EXTERNAL_CODECS \
+
+AR_OBJS = \
+ $O\ArchiveExports.obj \
+ $O\DllExports2.obj \
+
+7Z_OBJS = \
+ $O\7zCompressionMode.obj \
+ $O\7zDecode.obj \
+ $O\7zEncode.obj \
+ $O\7zExtract.obj \
+ $O\7zFolderInStream.obj \
+ $O\7zHandler.obj \
+ $O\7zHandlerOut.obj \
+ $O\7zHeader.obj \
+ $O\7zIn.obj \
+ $O\7zOut.obj \
+ $O\7zProperties.obj \
+ $O\7zSpecStream.obj \
+ $O\7zUpdate.obj \
+ $O\7zRegister.obj \
+
+COMMON_OBJS = \
+ $O\CRC.obj \
+ $O\IntToString.obj \
+ $O\NewHandler.obj \
+ $O\MyString.obj \
+ $O\StringConvert.obj \
+ $O\StringToInt.obj \
+ $O\MyVector.obj \
+ $O\Wildcard.obj \
+
+WIN_OBJS = \
+ $O\FileDir.obj \
+ $O\FileFind.obj \
+ $O\FileIO.obj \
+ $O\FileName.obj \
+ $O\PropVariant.obj \
+ $O\Synchronization.obj \
+ $O\System.obj \
+
+7ZIP_COMMON_OBJS = \
+ $O\CreateCoder.obj \
+ $O\InOutTempBuffer.obj \
+ $O\FilterCoder.obj \
+ $O\LimitedStreams.obj \
+ $O\LockedStream.obj \
+ $O\MethodId.obj \
+ $O\MethodProps.obj \
+ $O\OutBuffer.obj \
+ $O\ProgressUtils.obj \
+ $O\PropId.obj \
+ $O\StreamBinder.obj \
+ $O\StreamObjects.obj \
+ $O\StreamUtils.obj \
+ $O\VirtThread.obj \
+
+COMPRESS_OBJS = \
+ $O\CopyCoder.obj \
+ $O\CodecExports.obj \
+
+AR_COMMON_OBJS = \
+ $O\CoderMixer2.obj \
+ $O\HandlerOut.obj \
+ $O\InStreamWithCRC.obj \
+ $O\ItemNameUtils.obj \
+ $O\MultiStream.obj \
+ $O\OutStreamWithCRC.obj \
+ $O\ParseProperties.obj \
+
+C_OBJS = \
+ $O\Alloc.obj \
+ $O\CpuArch.obj \
+ $O\Threads.obj \
+
+!include "../../Crc.mak"
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/Archive/7z/resource.rc b/CPP/7zip/Archive/7z/resource.rc
new file mode 100644
index 0000000..f79dac0
--- /dev/null
+++ b/CPP/7zip/Archive/7z/resource.rc
@@ -0,0 +1,11 @@
+#include "../../MyVersionInfo.rc"
+
+MY_VERSION_INFO_DLL("7z Plugin", "7z")
+
+0 ICON "../Icons/7z.ico"
+
+STRINGTABLE
+BEGIN
+ 100 "7z:0"
+END
+
diff --git a/CPP/7zip/Archive/ApfsHandler.cpp b/CPP/7zip/Archive/ApfsHandler.cpp
new file mode 100644
index 0000000..5fb7e0a
--- /dev/null
+++ b/CPP/7zip/Archive/ApfsHandler.cpp
@@ -0,0 +1,4482 @@
+// ApfsHandler.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#include "../../../C/CpuArch.h"
+#include "../../../C/Sha256.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer2.h"
+#include "../../Common/MyLinux.h"
+#include "../../Common/UTFConvert.h"
+
+#include "../../Windows/PropVariantConv.h"
+#include "../../Windows/PropVariantUtils.h"
+#include "../../Windows/TimeUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "Common/ItemNameUtils.h"
+
+#include "HfsHandler.h"
+
+// if APFS_SHOW_ALT_STREAMS is defined, the handler will show attribute files.
+#define APFS_SHOW_ALT_STREAMS
+
+#define VI_MINUS1 ((unsigned)(int)-1)
+#define IsViDef(x) ((int)(x) != -1)
+#define IsViNotDef(x) ((int)(x) == -1)
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+#define G16(_offs_, dest) dest = Get16(p + (_offs_));
+#define G32(_offs_, dest) dest = Get32(p + (_offs_));
+#define G64(_offs_, dest) dest = Get64(p + (_offs_));
+
+namespace NArchive {
+namespace NApfs {
+
+#define ValToHex(t) ((char)(((t) < 10) ? ('0' + (t)) : ('a' + ((t) - 10))))
+
+static void ConvertByteToHex(unsigned val, char *s)
+{
+ unsigned t;
+ t = val >> 4;
+ s[0] = ValToHex(t);
+ t = val & 0xF;
+ s[1] = ValToHex(t);
+}
+
+struct CUuid
+{
+ Byte Data[16];
+
+ void SetHex_To_str(char *s) const
+ {
+ for (unsigned i = 0; i < 16; i++)
+ ConvertByteToHex(Data[i], s + i * 2);
+ s[32] = 0;
+ }
+
+ void AddHexToString(UString &dest) const
+ {
+ char temp[32 + 4];
+ SetHex_To_str(temp);
+ dest += temp;
+ }
+
+ void SetFrom(const Byte *p) { memcpy(Data, p, 16); }
+};
+
+
+typedef UInt64 oid_t;
+typedef UInt64 xid_t;
+// typedef Int64 paddr_t;
+typedef UInt64 paddr_t_unsigned;
+
+#define G64o G64
+#define G64x G64
+// #define G64a G64
+
+/*
+struct prange_t
+{
+ paddr_t start_paddr;
+ UInt64 block_count;
+
+ void Parse(const Byte *p)
+ {
+ G64a (0, start_paddr);
+ G64 (8, block_count);
+ }
+};
+*/
+
+#define OBJECT_TYPE_NX_SUPERBLOCK 0x1
+#define OBJECT_TYPE_BTREE 0x2
+#define OBJECT_TYPE_BTREE_NODE 0x3
+/*
+#define OBJECT_TYPE_SPACEMAN 0x5
+#define OBJECT_TYPE_SPACEMAN_CAB 0x6
+#define OBJECT_TYPE_SPACEMAN_CIB 0x7
+#define OBJECT_TYPE_SPACEMAN_BITMAP 0x8
+#define OBJECT_TYPE_SPACEMAN_FREE_QUEUE 0x9
+#define OBJECT_TYPE_EXTENT_LIST_TREE 0xa
+*/
+#define OBJECT_TYPE_OMAP 0xb
+/*
+#define OBJECT_TYPE_CHECKPOINT_MAP 0xc
+*/
+#define OBJECT_TYPE_FS 0xd
+#define OBJECT_TYPE_FSTREE 0xe
+/*
+#define OBJECT_TYPE_BLOCKREFTREE 0xf
+#define OBJECT_TYPE_SNAPMETATREE 0x10
+#define OBJECT_TYPE_NX_REAPER 0x11
+#define OBJECT_TYPE_NX_REAP_LIST 0x12
+#define OBJECT_TYPE_OMAP_SNAPSHOT 0x13
+#define OBJECT_TYPE_EFI_JUMPSTART 0x14
+#define OBJECT_TYPE_FUSION_MIDDLE_TREE 0x15
+#define OBJECT_TYPE_NX_FUSION_WBC 0x16
+#define OBJECT_TYPE_NX_FUSION_WBC_LIST 0x17
+#define OBJECT_TYPE_ER_STATE 0x18
+#define OBJECT_TYPE_GBITMAP 0x19
+#define OBJECT_TYPE_GBITMAP_TREE 0x1a
+#define OBJECT_TYPE_GBITMAP_BLOCK 0x1b
+#define OBJECT_TYPE_ER_RECOVERY_BLOCK 0x1c
+#define OBJECT_TYPE_SNAP_META_EXT 0x1d
+*/
+#define OBJECT_TYPE_INTEGRITY_META 0x1e
+#define OBJECT_TYPE_FEXT_TREE 0x1f
+/*
+#define OBJECT_TYPE_RESERVED_20 0x20
+
+#define OBJECT_TYPE_INVALID 0x0
+#define OBJECT_TYPE_TEST 0xff
+#define OBJECT_TYPE_CONTAINER_KEYBAG 'keys'
+#define OBJECT_TYPE_VOLUME_KEYBAG 'recs'
+#define OBJECT_TYPE_MEDIA_KEYBAG 'mkey'
+
+#define OBJ_VIRTUAL 0x0
+#define OBJ_EPHEMERAL 0x80000000
+*/
+#define OBJ_PHYSICAL 0x40000000
+/*
+#define OBJ_NOHEADER 0x20000000
+#define OBJ_ENCRYPTED 0x10000000
+#define OBJ_NONPERSISTENT 0x08000000
+*/
+#define OBJECT_TYPE_MASK 0x0000ffff
+/*
+#define OBJECT_TYPE_FLAGS_MASK 0xffff0000
+#define OBJ_STORAGETYPE_MASK 0xc0000000
+#define OBJECT_TYPE_FLAGS_DEFINED_MASK 0xf8000000
+*/
+
+// #define MAX_CKSUM_SIZE 8
+
+static const unsigned k_obj_phys_Size = 0x20;
+
+// obj_phys_t
+struct CPhys
+{
+ // Byte cksum[MAX_CKSUM_SIZE];
+ oid_t oid;
+ xid_t xid;
+ UInt32 type;
+ UInt32 subtype;
+
+ UInt32 GetType() const { return type & OBJECT_TYPE_MASK; }
+ void Parse(const Byte *p);
+};
+
+void CPhys::Parse(const Byte *p)
+{
+ // memcpy(cksum, p, MAX_CKSUM_SIZE);
+ G64o (8, oid)
+ G64x (0x10, xid)
+ G32 (0x18, type)
+ G32 (0x1C, subtype)
+}
+
+#define NX_MAX_FILE_SYSTEMS 100
+/*
+#define NX_EPH_INFO_COUNT 4
+#define NX_EPH_MIN_BLOCK_COUNT 8
+#define NX_MAX_FILE_SYSTEM_EPH_STRUCTS 4
+#define NX_TX_MIN_CHECKPOINT_COUNT 4
+#define NX_EPH_INFO_VERSION_1 1
+*/
+
+/*
+typedef enum
+{
+ NX_CNTR_OBJ_CKSUM_SET = 0,
+ NX_CNTR_OBJ_CKSUM_FAIL = 1,
+ NX_NUM_COUNTERS = 32
+} counter_id_t;
+*/
+
+/* Incompatible volume feature flags */
+#define APFS_INCOMPAT_CASE_INSENSITIVE (1 << 0)
+/*
+#define APFS_INCOMPAT_DATALESS_SNAPS (1 << 1)
+#define APFS_INCOMPAT_ENC_ROLLED (1 << 2)
+*/
+#define APFS_INCOMPAT_NORMALIZATION_INSENSITIVE (1 << 3)
+/*
+#define APFS_INCOMPAT_INCOMPLETE_RESTORE (1 << 4)
+*/
+#define APFS_INCOMPAT_SEALED_VOLUME (1 << 5)
+/*
+#define APFS_INCOMPAT_RESERVED_40 (1 << 6)
+*/
+
+static const char * const g_APFS_INCOMPAT_Flags[] =
+{
+ "CASE_INSENSITIVE"
+ , "DATALESS_SNAPS"
+ , "ENC_ROLLED"
+ , "NORMALIZATION_INSENSITIVE"
+ , "INCOMPLETE_RESTORE"
+ , "SEALED_VOLUME"
+};
+
+/*
+#define APFS_SUPPORTED_INCOMPAT_MASK \
+ ( APFS_INCOMPAT_CASE_INSENSITIVE \
+ | APFS_INCOMPAT_DATALESS_SNAPS \
+ | APFS_INCOMPAT_ENC_ROLLED \
+ | APFS_INCOMPAT_NORMALIZATION_INSENSITIVE \
+ | APFS_INCOMPAT_INCOMPLETE_RESTORE \
+ | APFS_INCOMPAT_SEALED_VOLUME \
+ | APFS_INCOMPAT_RESERVED_40 \
+)
+*/
+
+// superblock_t
+struct CSuperBlock
+{
+ // CPhys o;
+ // UInt32 magic;
+ UInt32 block_size;
+ unsigned block_size_Log;
+ UInt64 block_count;
+ // UInt64 features;
+ // UInt64 readonly_compatible_features;
+ // UInt64 incompatible_features;
+ CUuid uuid;
+ /*
+ oid_t next_oid;
+ xid_t next_xid;
+ UInt32 xp_desc_blocks;
+ UInt32 xp_data_blocks;
+ paddr_t xp_desc_base;
+ paddr_t xp_data_base;
+ UInt32 xp_desc_next;
+ UInt32 xp_data_next;
+ UInt32 xp_desc_index;
+ UInt32 xp_desc_len;
+ UInt32 xp_data_index;
+ UInt32 xp_data_len;
+ oid_t spaceman_oid;
+ */
+ oid_t omap_oid;
+ // oid_t reaper_oid;
+ // UInt32 test_type;
+ UInt32 max_file_systems;
+ // oid_t fs_oid[NX_MAX_FILE_SYSTEMS];
+ /*
+ UInt64 counters[NX_NUM_COUNTERS]; // counter_id_t
+ prange_t blocked_out_prange;
+ oid_t evict_mapping_tree_oid;
+ UInt64 flags;
+ paddr_t efi_jumpstart;
+ CUuid fusion_uuid;
+ prange_t keylocker;
+ UInt64 ephemeral_info[NX_EPH_INFO_COUNT];
+ oid_t test_oid;
+ oid_t fusion_mt_oid;
+ oid_t fusion_wbc_oid;
+ prange_t fusion_wbc;
+ UInt64 newest_mounted_version;
+ prange_t mkb_locker;
+ */
+
+ bool Parse(const Byte *p);
+};
+
+struct CSuperBlock2
+{
+ oid_t fs_oid[NX_MAX_FILE_SYSTEMS];
+ void Parse(const Byte *p)
+ {
+ for (unsigned i = 0; i < NX_MAX_FILE_SYSTEMS; i++)
+ {
+ G64o (0xb8 + i * 8, fs_oid[i])
+ }
+ }
+};
+
+
+// we include one additional byte of next field (block_size)
+static const unsigned k_SignatureOffset = 32;
+static const Byte k_Signature[] = { 'N', 'X', 'S', 'B', 0 };
+
+// size must be 4 bytes aligned
+static UInt64 Fletcher64(const Byte *data, size_t size)
+{
+ const UInt32 kMax32 = 0xffffffff;
+ const UInt64 val = 0; // startVal
+ UInt64 a = val & kMax32;
+ UInt64 b = (val >> 32) & kMax32;
+ for (size_t i = 0; i < size; i += 4)
+ {
+ a += GetUi32(data + i);
+ b += a;
+ }
+ a %= kMax32;
+ b %= kMax32;
+ b = (UInt32)(kMax32 - ((a + b) % kMax32));
+ a = (UInt32)(kMax32 - ((a + b) % kMax32));
+ return (a << 32) | b;
+}
+
+static bool CheckFletcher64(const Byte *p, size_t size)
+{
+ const UInt64 calculated_checksum = Fletcher64(p + 8, size - 8);
+ const UInt64 stored_checksum = Get64(p);
+ return (stored_checksum == calculated_checksum);
+}
+
+
+static unsigned GetLogSize(UInt32 size)
+{
+ unsigned k;
+ for (k = 0; k < 32; k++)
+ if (((UInt32)1 << k) == size)
+ return k;
+ return k;
+}
+
+static const unsigned kApfsHeaderSize = 1 << 12;
+
+// #define OID_INVALID 0
+#define OID_NX_SUPERBLOCK 1
+// #define OID_RESERVED_COUNT 1024
+// This range of identifiers is reserved for physical, virtual, and ephemeral objects
+
+bool CSuperBlock::Parse(const Byte *p)
+{
+ CPhys o;
+ o.Parse(p);
+ if (o.oid != OID_NX_SUPERBLOCK)
+ return false;
+ if (o.GetType() != OBJECT_TYPE_NX_SUPERBLOCK)
+ return false;
+ if (o.subtype != 0)
+ return false;
+ if (memcmp(p + k_SignatureOffset, k_Signature, 4) != 0)
+ return false;
+ if (!CheckFletcher64(p, kApfsHeaderSize))
+ return false;
+
+ G32 (0x24, block_size)
+ {
+ const unsigned logSize = GetLogSize(block_size);
+ // don't change it. Some code requires (block_size <= 16)
+ if (logSize < 12 || logSize > 16)
+ return false;
+ block_size_Log = logSize;
+ }
+
+ G64 (0x28, block_count)
+
+ const UInt64 kArcSize_MAX = (UInt64)1 << 62;
+ if (block_count > (kArcSize_MAX >> block_size_Log))
+ return false;
+
+ // G64 (0x30, features);
+ // G64 (0x38, readonly_compatible_features);
+ // G64 (0x40, incompatible_features);
+ uuid.SetFrom(p + 0x48);
+ /*
+ G64o (0x58, next_oid);
+ G64x (0x60, next_xid);
+ G32 (0x68, xp_desc_blocks);
+ G32 (0x6c, xp_data_blocks);
+ G64a (0x70, xp_desc_base);
+ G64a (0x78, xp_data_base);
+ G32 (0x80, xp_desc_next);
+ G32 (0x84, xp_data_next);
+ G32 (0x88, xp_desc_index);
+ G32 (0x8c, xp_desc_len);
+ G32 (0x90, xp_data_index);
+ G32 (0x94, xp_data_len);
+ G64o (0x98, spaceman_oid);
+ */
+ G64o (0xa0, omap_oid)
+ // G64o (0xa8, reaper_oid);
+ // G32 (0xb0, test_type);
+ G32 (0xb4, max_file_systems)
+ if (max_file_systems > NX_MAX_FILE_SYSTEMS)
+ return false;
+ /*
+ {
+ for (unsigned i = 0; i < NX_MAX_FILE_SYSTEMS; i++)
+ {
+ G64o (0xb8 + i * 8, fs_oid[i]);
+ }
+ }
+ */
+ /*
+ {
+ for (unsigned i = 0; i < NX_NUM_COUNTERS; i++)
+ {
+ G64 (0x3d8 + i * 8, counters[i]);
+ }
+ }
+ blocked_out_prange.Parse(p + 0x4d8);
+ G64o (0x4e8, evict_mapping_tree_oid);
+ #define NX_CRYPTO_SW 0x00000004LL
+ G64 (0x4f0, flags);
+ G64a (0x4f8, efi_jumpstart);
+ fusion_uuid.SetFrom(p + 0x500);
+ keylocker.Parse(p + 0x510);
+ {
+ for (unsigned i = 0; i < NX_EPH_INFO_COUNT; i++)
+ {
+ G64 (0x520 + i * 8, ephemeral_info[i]);
+ }
+ }
+ G64o (0x540, test_oid);
+ G64o (0x548, fusion_mt_oid);
+ G64o (0x550, fusion_wbc_oid);
+ fusion_wbc.Parse(p + 0x558);
+ G64 (0x568, newest_mounted_version); // decimal 1412141 001 000 000
+ mkb_locker.Parse(p + 0x570);
+ */
+
+ return true;
+}
+
+
+enum apfs_hash_type_t
+{
+ APFS_HASH_INVALID = 0,
+ APFS_HASH_SHA256 = 1,
+ APFS_HASH_SHA512_256 = 2,
+ APFS_HASH_SHA384 = 3,
+ APFS_HASH_SHA512 = 4,
+
+ APFS_HASH_MIN = APFS_HASH_SHA256,
+ APFS_HASH_MAX = APFS_HASH_SHA512,
+
+ APFS_HASH_DEFAULT = APFS_HASH_SHA256
+};
+
+static unsigned GetHashSize(unsigned hashType)
+{
+ if (hashType > APFS_HASH_MAX) return 0;
+ if (hashType < APFS_HASH_MIN) return 0;
+ if (hashType == APFS_HASH_SHA256) return 32;
+ return hashType * 16;
+}
+
+#define APFS_HASH_MAX_SIZE 64
+
+static const char * const g_hash_types[] =
+{
+ NULL
+ , "SHA256"
+ , "SHA512_256"
+ , "SHA384"
+ , "SHA512"
+};
+
+
+struct C_integrity_meta_phys
+{
+ // CPhys im_o;
+ // UInt32 im_version;
+ UInt32 im_flags;
+ // apfs_hash_type_t
+ UInt32 im_hash_type;
+ // UInt32 im_root_hash_offset;
+ // xid_t im_broken_xid;
+ // UInt64 im_reserved[9];
+
+ unsigned HashSize;
+ Byte Hash[APFS_HASH_MAX_SIZE];
+
+ bool Is_SHA256() const { return im_hash_type == APFS_HASH_SHA256; }
+
+ C_integrity_meta_phys()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+ bool Parse(const Byte *p, size_t size, oid_t oid);
+};
+
+bool C_integrity_meta_phys::Parse(const Byte *p, size_t size, oid_t oid)
+{
+ CPhys o;
+ if (!CheckFletcher64(p, size))
+ return false;
+ o.Parse(p);
+ if (o.GetType() != OBJECT_TYPE_INTEGRITY_META)
+ return false;
+ if (o.oid != oid)
+ return false;
+ // G32 (0x20, im_version);
+ G32 (0x24, im_flags)
+ G32 (0x28, im_hash_type)
+ UInt32 im_root_hash_offset;
+ G32 (0x2C, im_root_hash_offset)
+ // G64x (0x30, im_broken_xid);
+ const unsigned hashSize = GetHashSize(im_hash_type);
+ HashSize = hashSize;
+ if (im_root_hash_offset >= size || size - im_root_hash_offset < hashSize)
+ return false;
+ memcpy(Hash, p + im_root_hash_offset, hashSize);
+ return true;
+}
+
+
+struct C_omap_phys
+{
+ // om_ prefix
+ // CPhys o;
+ /*
+ UInt32 flags;
+ UInt32 snap_count;
+ UInt32 tree_type;
+ UInt32 snapshot_tree_type;
+ */
+ oid_t tree_oid;
+ /*
+ oid_t snapshot_tree_oid;
+ xid_t most_recent_snap;
+ xid_t pending_revert_min;
+ xid_t pending_revert_max;
+ */
+ bool Parse(const Byte *p, size_t size, oid_t oid);
+};
+
+bool C_omap_phys::Parse(const Byte *p, size_t size, oid_t oid)
+{
+ CPhys o;
+ if (!CheckFletcher64(p, size))
+ return false;
+ o.Parse(p);
+ if (o.GetType() != OBJECT_TYPE_OMAP)
+ return false;
+ if (o.oid != oid)
+ return false;
+ /*
+ G32 (0x20, flags);
+ G32 (0x24, snap_count);
+ G32 (0x28, tree_type);
+ G32 (0x2C, snapshot_tree_type);
+ */
+ G64o (0x30, tree_oid)
+ /*
+ G64o (0x38, snapshot_tree_oid);
+ G64x (0x40, most_recent_snap);
+ G64x (0x48, pending_revert_min);
+ G64x (0x50, pending_revert_max);
+ */
+ return true;
+}
+
+
+// #define BTOFF_INVALID 0xffff
+/* This value is stored in the off field of nloc_t to indicate that
+there's no offset. For example, the last entry in a free
+list has no entry after it, so it uses this value for its off field. */
+
+// A location within a B-tree node
+struct nloc
+{
+ UInt16 off;
+ UInt16 len;
+
+ void Parse(const Byte *p)
+ {
+ G16 (0, off)
+ G16 (2, len)
+ }
+ UInt32 GetEnd() const { return (UInt32)off + len; }
+ bool CheckOverLimit(UInt32 limit)
+ {
+ return off < limit && len <= limit - off;
+ }
+};
+
+
+// The location, within a B-tree node, of a key and value
+struct kvloc
+{
+ nloc k;
+ nloc v;
+
+ void Parse(const Byte *p)
+ {
+ k.Parse(p);
+ v.Parse(p + 4);
+ }
+};
+
+
+// The location, within a B-tree node, of a fixed-size key and value
+struct kvoff
+{
+ UInt16 k;
+ UInt16 v;
+
+ void Parse(const Byte *p)
+ {
+ G16 (0, k)
+ G16 (2, v)
+ }
+};
+
+
+#define BTNODE_ROOT (1 << 0)
+#define BTNODE_LEAF (1 << 1)
+#define BTNODE_FIXED_KV_SIZE (1 << 2)
+#define BTNODE_HASHED (1 << 3)
+#define BTNODE_NOHEADER (1 << 4)
+/*
+#define BTNODE_CHECK_KOFF_INVAL (1 << 15)
+*/
+
+static const unsigned k_Toc_offset = 0x38;
+
+// btree_node_phys
+struct CBTreeNodePhys
+{
+ // btn_ prefix
+ CPhys ophys;
+ UInt16 flags;
+ UInt16 level; // the number of child levels below this node. 0 - for a leaf node, 1 for the immediate parent of a leaf node
+ UInt32 nkeys; // The number of keys stored in this node.
+ nloc table_space;
+ /*
+ nloc free_space;
+ nloc key_free_list;
+ nloc val_free_list;
+ */
+
+ bool Is_FIXED_KV_SIZE() const { return (flags & BTNODE_FIXED_KV_SIZE) != 0; }
+ bool Is_NOHEADER() const { return (flags & BTNODE_NOHEADER) != 0; }
+ bool Is_HASHED() const { return (flags & BTNODE_HASHED) != 0; }
+
+ bool Parse(const Byte *p, size_t size, bool noHeader = false)
+ {
+ G16 (0x20, flags)
+ G16 (0x22, level)
+ G32 (0x24, nkeys)
+ table_space.Parse(p + 0x28);
+ /*
+ free_space.Parse(p + 0x2C);
+ key_free_list.Parse(p + 0x30);
+ val_free_list.Parse(p + 0x34);
+ */
+ memset(&ophys, 0, sizeof(ophys));
+ if (noHeader)
+ {
+ for (unsigned i = 0; i < k_obj_phys_Size; i++)
+ if (p[i] != 0)
+ return false;
+ }
+ else
+ {
+ if (!CheckFletcher64(p, size))
+ return false;
+ ophys.Parse(p);
+ }
+ if (Is_NOHEADER() != noHeader)
+ return false;
+ return true;
+ }
+};
+
+/*
+#define BTREE_UINT64_KEYS (1 << 0)
+#define BTREE_SEQUENTIAL_INSERT (1 << 1)
+#define BTREE_ALLOW_GHOSTS (1 << 2)
+*/
+#define BTREE_EPHEMERAL (1 << 3)
+#define BTREE_PHYSICAL (1 << 4)
+/*
+#define BTREE_NONPERSISTENT (1 << 5)
+#define BTREE_KV_NONALIGNED (1 << 6)
+#define BTREE_HASHED (1 << 7)
+*/
+#define BTREE_NOHEADER (1 << 8)
+
+/*
+ BTREE_EPHEMERAL: The nodes in the B-tree use ephemeral object identifiers to link to child nodes
+ BTREE_PHYSICAL : The nodes in the B-tree use physical object identifiers to link to child nodes.
+ If neither flag is set, nodes in the B-tree use virtual object
+ identifiers to link to their child nodes.
+*/
+
+// Static information about a B-tree.
+struct btree_info_fixed
+{
+ UInt32 flags;
+ UInt32 node_size;
+ UInt32 key_size;
+ UInt32 val_size;
+
+ void Parse(const Byte *p)
+ {
+ G32 (0, flags)
+ G32 (4, node_size)
+ G32 (8, key_size)
+ G32 (12, val_size)
+ }
+};
+
+static const unsigned k_btree_info_Size = 0x28;
+
+struct btree_info
+{
+ btree_info_fixed fixed;
+ UInt32 longest_key;
+ UInt32 longest_val;
+ UInt64 key_count;
+ UInt64 node_count;
+
+ bool Is_EPHEMERAL() const { return (fixed.flags & BTREE_EPHEMERAL) != 0; }
+ bool Is_PHYSICAL() const { return (fixed.flags & BTREE_PHYSICAL) != 0; }
+ bool Is_NOHEADER() const { return (fixed.flags & BTREE_NOHEADER) != 0; }
+
+ void Parse(const Byte *p)
+ {
+ fixed.Parse(p);
+ G32 (0x10, longest_key)
+ G32 (0x14, longest_val)
+ G64 (0x18, key_count)
+ G64 (0x20, node_count)
+ }
+};
+
+
+/*
+typedef UInt32 cp_key_class_t;
+typedef UInt32 cp_key_os_version_t;
+typedef UInt16 cp_key_revision_t;
+typedef UInt32 crypto_flags_t;
+
+struct wrapped_meta_crypto_state
+{
+ UInt16 major_version;
+ UInt16 minor_version;
+ crypto_flags_t cpflags;
+ cp_key_class_t persistent_class;
+ cp_key_os_version_t key_os_version;
+ cp_key_revision_t key_revision;
+ // UInt16 unused;
+
+ void Parse(const Byte *p)
+ {
+ G16 (0, major_version);
+ G16 (2, minor_version);
+ G32 (4, cpflags);
+ G32 (8, persistent_class);
+ G32 (12, key_os_version);
+ G16 (16, key_revision);
+ }
+};
+*/
+
+
+#define APFS_MODIFIED_NAMELEN 32
+#define sizeof_apfs_modified_by_t (APFS_MODIFIED_NAMELEN + 16)
+
+struct apfs_modified_by_t
+{
+ Byte id[APFS_MODIFIED_NAMELEN];
+ UInt64 timestamp;
+ xid_t last_xid;
+
+ void Parse(const Byte *p)
+ {
+ memcpy(id, p, APFS_MODIFIED_NAMELEN);
+ p += APFS_MODIFIED_NAMELEN;
+ G64 (0, timestamp)
+ G64x (8, last_xid)
+ }
+};
+
+
+#define APFS_MAX_HIST 8
+#define APFS_VOLNAME_LEN 256
+
+struct CApfs
+{
+ // apfs_
+ CPhys o;
+ // UInt32 magic;
+ UInt32 fs_index; // index of the object identifier for this volume's file system in the container's array of file systems.
+ // UInt64 features;
+ // UInt64 readonly_compatible_features;
+ UInt64 incompatible_features;
+ UInt64 unmount_time;
+ // UInt64 fs_reserve_block_count;
+ // UInt64 fs_quota_block_count;
+ UInt64 fs_alloc_count;
+ // wrapped_meta_crypto_state meta_crypto;
+ // UInt32 root_tree_type;
+ /* The type of the root file-system tree.
+ The value is typically OBJ_VIRTUAL | OBJECT_TYPE_BTREE,
+ with a subtype of OBJECT_TYPE_FSTREE */
+
+ // UInt32 extentref_tree_type;
+ // UInt32 snap_meta_tree_type;
+ oid_t omap_oid;
+ oid_t root_tree_oid;
+ /*
+ oid_t extentref_tree_oid;
+ oid_t snap_meta_tree_oid;
+ xid_t revert_to_xid;
+ oid_t revert_to_sblock_oid;
+ UInt64 next_obj_id;
+ */
+ UInt64 num_files;
+ UInt64 num_directories;
+ UInt64 num_symlinks;
+ UInt64 num_other_fsobjects;
+ UInt64 num_snapshots;
+ UInt64 total_blocks_alloced;
+ UInt64 total_blocks_freed;
+ CUuid vol_uuid;
+ UInt64 last_mod_time;
+ UInt64 fs_flags;
+ apfs_modified_by_t formatted_by;
+ apfs_modified_by_t modified_by[APFS_MAX_HIST];
+ Byte volname[APFS_VOLNAME_LEN];
+ /*
+ UInt32 next_doc_id;
+ UInt16 role; // APFS_VOL_ROLE_NONE APFS_VOL_ROLE_SYSTEM ....
+ UInt16 reserved;
+ xid_t root_to_xid;
+ oid_t er_state_oid;
+ UInt64 cloneinfo_id_epoch;
+ UInt64 cloneinfo_xid;
+ oid_t snap_meta_ext_oid;
+ CUuid volume_group_id;
+ */
+ oid_t integrity_meta_oid; // virtual object identifier of the integrity metadata object
+ oid_t fext_tree_oid; // virtual object identifier of the file extent tree.
+ UInt32 fext_tree_type; // The type of the file extent tree.
+ /*
+ UInt32 reserved_type;
+ oid_t reserved_oid;
+ */
+
+ UInt64 GetTotalItems() const
+ {
+ return num_files + num_directories + num_symlinks + num_other_fsobjects;
+ }
+
+ bool IsHashedName() const
+ {
+ return
+ (incompatible_features & APFS_INCOMPAT_CASE_INSENSITIVE) != 0 ||
+ (incompatible_features & APFS_INCOMPAT_NORMALIZATION_INSENSITIVE) != 0;
+ }
+
+ bool Parse(const Byte *p, size_t size);
+};
+
+
+bool CApfs::Parse(const Byte *p, size_t size)
+{
+ o.Parse(p);
+ if (Get32(p + 32) != 0x42535041) // { 'A', 'P', 'S', 'B' };
+ return false;
+ if (o.GetType() != OBJECT_TYPE_FS)
+ return false;
+ if (!CheckFletcher64(p, size))
+ return false;
+ // if (o.GetType() != OBJECT_TYPE_NX_SUPERBLOCK) return false;
+
+ G32 (0x24, fs_index)
+ // G64 (0x28, features);
+ // G64 (0x30, readonly_compatible_features);
+ G64 (0x38, incompatible_features)
+ G64 (0x40, unmount_time)
+ // G64 (0x48, fs_reserve_block_count);
+ // G64 (0x50, fs_quota_block_count);
+ G64 (0x58, fs_alloc_count)
+ // meta_crypto.Parse(p + 0x60);
+ // G32 (0x74, root_tree_type);
+ // G32 (0x78, extentref_tree_type);
+ // G32 (0x7C, snap_meta_tree_type);
+
+ G64o (0x80, omap_oid)
+ G64o (0x88, root_tree_oid)
+ /*
+ G64o (0x90, extentref_tree_oid);
+ G64o (0x98, snap_meta_tree_oid);
+ G64x (0xa0, revert_to_xid);
+ G64o (0xa8, revert_to_sblock_oid);
+ G64 (0xb0, next_obj_id);
+ */
+ G64 (0xb8, num_files)
+ G64 (0xc0, num_directories)
+ G64 (0xc8, num_symlinks)
+ G64 (0xd0, num_other_fsobjects)
+ G64 (0xd8, num_snapshots)
+ G64 (0xe0, total_blocks_alloced)
+ G64 (0xe8, total_blocks_freed)
+ vol_uuid.SetFrom(p + 0xf0);
+ G64 (0x100, last_mod_time)
+ G64 (0x108, fs_flags)
+ p += 0x110;
+ formatted_by.Parse(p);
+ p += sizeof_apfs_modified_by_t;
+ for (unsigned i = 0; i < APFS_MAX_HIST; i++)
+ {
+ modified_by[i].Parse(p);
+ p += sizeof_apfs_modified_by_t;
+ }
+ memcpy(volname, p, APFS_VOLNAME_LEN);
+ p += APFS_VOLNAME_LEN;
+ /*
+ G32 (0, next_doc_id);
+ G16 (4, role);
+ G16 (6, reserved);
+ G64x (8, root_to_xid);
+ G64o (0x10, er_state_oid);
+ G64 (0x18, cloneinfo_id_epoch);
+ G64 (0x20, cloneinfo_xid);
+ G64o (0x28, snap_meta_ext_oid);
+ volume_group_id.SetFrom(p + 0x30);
+ */
+ G64o (0x40, integrity_meta_oid)
+ G64o (0x48, fext_tree_oid)
+ G32 (0x50, fext_tree_type)
+ /*
+ G32 (0x54, reserved_type);
+ G64o (0x58, reserved_oid);
+ */
+ return true;
+}
+
+
+#define OBJ_ID_MASK 0x0fffffffffffffff
+/*
+#define OBJ_TYPE_MASK 0xf000000000000000
+#define SYSTEM_OBJ_ID_MARK 0x0fffffff00000000
+*/
+#define OBJ_TYPE_SHIFT 60
+
+typedef enum
+{
+ APFS_TYPE_ANY = 0,
+ APFS_TYPE_SNAP_METADATA = 1,
+ APFS_TYPE_EXTENT = 2,
+ APFS_TYPE_INODE = 3,
+ APFS_TYPE_XATTR = 4,
+ APFS_TYPE_SIBLING_LINK = 5,
+ APFS_TYPE_DSTREAM_ID = 6,
+ APFS_TYPE_CRYPTO_STATE = 7,
+ APFS_TYPE_FILE_EXTENT = 8,
+ APFS_TYPE_DIR_REC = 9,
+ APFS_TYPE_DIR_STATS = 10,
+ APFS_TYPE_SNAP_NAME = 11,
+ APFS_TYPE_SIBLING_MAP = 12,
+ APFS_TYPE_FILE_INFO = 13,
+ APFS_TYPE_MAX_VALID = 13,
+ APFS_TYPE_MAX = 15,
+ APFS_TYPE_INVALID = 15
+} j_obj_types;
+
+
+struct j_key_t
+{
+ UInt64 obj_id_and_type;
+
+ void Parse(const Byte *p) { G64(0, obj_id_and_type) }
+ unsigned GetType() const { return (unsigned)(obj_id_and_type >> OBJ_TYPE_SHIFT); }
+ UInt64 GetID() const { return obj_id_and_type & OBJ_ID_MASK; }
+};
+
+
+
+#define J_DREC_LEN_MASK 0x000003ff
+/*
+#define J_DREC_HASH_MASK 0xfffff400
+#define J_DREC_HASH_SHIFT 10
+*/
+
+static const unsigned k_SizeOf_j_drec_val = 0x12;
+
+struct j_drec_val
+{
+ UInt64 file_id;
+ UInt64 date_added; /* The time that this directory entry was added to the directory.
+ It's not updated when modifying the directory entry for example,
+ by renaming a file without moving it to a different directory. */
+ UInt16 flags;
+
+ // bool IsFlags_File() const { return flags == MY_LIN_DT_REG; }
+ bool IsFlags_Unknown() const { return flags == MY_LIN_DT_UNKNOWN; }
+ bool IsFlags_Dir() const { return flags == MY_LIN_DT_DIR; }
+
+ // uint8_t xfields[];
+ void Parse(const Byte *p)
+ {
+ G64 (0, file_id)
+ G64 (8, date_added)
+ G16 (0x10, flags)
+ }
+};
+
+
+struct CItem
+{
+ // j_key_t hdr;
+ UInt64 ParentId;
+ AString Name;
+ j_drec_val Val;
+
+ unsigned ParentItemIndex;
+ unsigned RefIndex;
+ // unsigned iNode_Index;
+
+ void Clear()
+ {
+ Name.Empty();
+ ParentItemIndex = VI_MINUS1;
+ RefIndex = VI_MINUS1;
+ }
+};
+
+
+/*
+#define INVALID_INO_NUM 0
+#define ROOT_DIR_PARENT 1 // parent for "root" and "private-dir", there's no inode on disk with this inode number.
+*/
+#define ROOT_DIR_INO_NUM 2 // "root" - parent for all main files
+#define PRIV_DIR_INO_NUM 3 // "private-dir"
+/*
+#define SNAP_DIR_INO_NUM 6 // the directory where snapshot metadata is stored. Snapshot inodes are stored in the snapshot metedata tree.
+#define PURGEABLE_DIR_INO_NUM 7
+#define MIN_USER_INO_NUM 16
+
+#define UNIFIED_ID_SPACE_MARK 0x0800000000000000
+*/
+
+//typedef enum
+// {
+/*
+INODE_IS_APFS_PRIVATE = 0x00000001,
+INODE_MAINTAIN_DIR_STATS = 0x00000002,
+INODE_DIR_STATS_ORIGIN = 0x00000004,
+INODE_PROT_CLASS_EXPLICIT = 0x00000008,
+INODE_WAS_CLONED = 0x00000010,
+INODE_FLAG_UNUSED = 0x00000020,
+INODE_HAS_SECURITY_EA = 0x00000040,
+INODE_BEING_TRUNCATED = 0x00000080,
+INODE_HAS_FINDER_INFO = 0x00000100,
+INODE_IS_SPARSE = 0x00000200,
+INODE_WAS_EVER_CLONED = 0x00000400,
+INODE_ACTIVE_FILE_TRIMMED = 0x00000800,
+INODE_PINNED_TO_MAIN = 0x00001000,
+INODE_PINNED_TO_TIER2 = 0x00002000,
+*/
+// INODE_HAS_RSRC_FORK = 0x00004000,
+/*
+INODE_NO_RSRC_FORK = 0x00008000,
+INODE_ALLOCATION_SPILLEDOVER = 0x00010000,
+INODE_FAST_PROMOTE = 0x00020000,
+*/
+#define INODE_HAS_UNCOMPRESSED_SIZE 0x00040000
+/*
+INODE_IS_PURGEABLE = 0x00080000,
+INODE_WANTS_TO_BE_PURGEABLE = 0x00100000,
+INODE_IS_SYNC_ROOT = 0x00200000,
+INODE_SNAPSHOT_COW_EXEMPTION = 0x00400000,
+
+
+INODE_INHERITED_INTERNAL_FLAGS = \
+ ( INODE_MAINTAIN_DIR_STATS \
+ | INODE_SNAPSHOT_COW_EXEMPTION),
+
+INODE_CLONED_INTERNAL_FLAGS = \
+ ( INODE_HAS_RSRC_FORK \
+ | INODE_NO_RSRC_FORK \
+ | INODE_HAS_FINDER_INFO \
+ | INODE_SNAPSHOT_COW_EXEMPTION),
+*/
+// }
+// j_inode_flags;
+
+
+/*
+#define APFS_VALID_INTERNAL_INODE_FLAGS \
+( INODE_IS_APFS_PRIVATE \
+| INODE_MAINTAIN_DIR_STATS \
+| INODE_DIR_STATS_ORIGIN \
+| INODE_PROT_CLASS_EXPLICIT \
+| INODE_WAS_CLONED \
+| INODE_HAS_SECURITY_EA \
+| INODE_BEING_TRUNCATED \
+| INODE_HAS_FINDER_INFO \
+| INODE_IS_SPARSE \
+| INODE_WAS_EVER_CLONED \
+| INODE_ACTIVE_FILE_TRIMMED \
+| INODE_PINNED_TO_MAIN \
+| INODE_PINNED_TO_TIER2 \
+| INODE_HAS_RSRC_FORK \
+| INODE_NO_RSRC_FORK \
+| INODE_ALLOCATION_SPILLEDOVER \
+| INODE_FAST_PROMOTE \
+| INODE_HAS_UNCOMPRESSED_SIZE \
+| INODE_IS_PURGEABLE \
+| INODE_WANTS_TO_BE_PURGEABLE \
+| INODE_IS_SYNC_ROOT \
+| INODE_SNAPSHOT_COW_EXEMPTION)
+
+#define APFS_INODE_PINNED_MASK (INODE_PINNED_TO_MAIN | INODE_PINNED_TO_TIER2)
+*/
+
+static const char * const g_INODE_Flags[] =
+{
+ "IS_APFS_PRIVATE"
+ , "MAINTAIN_DIR_STATS"
+ , "DIR_STATS_ORIGIN"
+ , "PROT_CLASS_EXPLICIT"
+ , "WAS_CLONED"
+ , "FLAG_UNUSED"
+ , "HAS_SECURITY_EA"
+ , "BEING_TRUNCATED"
+ , "HAS_FINDER_INFO"
+ , "IS_SPARSE"
+ , "WAS_EVER_CLONED"
+ , "ACTIVE_FILE_TRIMMED"
+ , "PINNED_TO_MAIN"
+ , "PINNED_TO_TIER2"
+ , "HAS_RSRC_FORK"
+ , "NO_RSRC_FORK"
+ , "ALLOCATION_SPILLEDOVER"
+ , "FAST_PROMOTE"
+ , "HAS_UNCOMPRESSED_SIZE"
+ , "IS_PURGEABLE"
+ , "WANTS_TO_BE_PURGEABLE"
+ , "IS_SYNC_ROOT"
+ , "SNAPSHOT_COW_EXEMPTION"
+};
+
+
+// bsd stat.h
+/*
+#define MY_UF_SETTABLE 0x0000ffff // mask of owner changeable flags
+#define MY_UF_NODUMP 0x00000001 // do not dump file
+#define MY_UF_IMMUTABLE 0x00000002 // file may not be changed
+#define MY_UF_APPEND 0x00000004 // writes to file may only append
+#define MY_UF_OPAQUE 0x00000008 // directory is opaque wrt. union
+#define MY_UF_NOUNLINK 0x00000010 // file entry may not be removed or renamed Not implement in MacOS
+#define MY_UF_COMPRESSED 0x00000020 // file entry is compressed
+#define MY_UF_TRACKED 0x00000040 // notify about file entry changes
+#define MY_UF_DATAVAULT 0x00000080 // entitlement required for reading and writing
+#define MY_UF_HIDDEN 0x00008000 // file entry is hidden
+
+#define MY_SF_SETTABLE 0xffff0000 // mask of superuser changeable flags
+#define MY_SF_ARCHIVED 0x00010000 // file is archived
+#define MY_SF_IMMUTABLE 0x00020000 // file may not be changed
+#define MY_SF_APPEND 0x00040000 // writes to file may only append
+#define MY_SF_RESTRICTED 0x00080000 // entitlement required for writing
+#define MY_SF_NOUNLINK 0x00100000 // file entry may not be removed, renamed or used as mount point
+#define MY_SF_SNAPSHOT 0x00200000 // snapshot inode
+Not implement in MacOS
+*/
+
+static const char * const g_INODE_BSD_Flags[] =
+{
+ "UF_NODUMP"
+ , "UF_IMMUTABLE"
+ , "UF_APPEND"
+ , "UF_OPAQUE"
+ , "UF_NOUNLINK"
+ , "UF_COMPRESSED"
+ , "UF_TRACKED"
+ , "UF_DATAVAULT"
+ , NULL, NULL, NULL, NULL
+ , NULL, NULL, NULL
+ , "UF_HIDDEN"
+
+ , "SF_ARCHIVE"
+ , "SF_IMMUTABLE"
+ , "SF_APPEND"
+ , "SF_RESTRICTED"
+ , "SF_NOUNLINK"
+ , "SF_SNAPSHOT"
+};
+
+/*
+#define INO_EXT_TYPE_SNAP_XID 1
+#define INO_EXT_TYPE_DELTA_TREE_OID 2
+#define INO_EXT_TYPE_DOCUMENT_ID 3
+*/
+#define INO_EXT_TYPE_NAME 4
+/*
+#define INO_EXT_TYPE_PREV_FSIZE 5
+#define INO_EXT_TYPE_RESERVED_6 6
+#define INO_EXT_TYPE_FINDER_INFO 7
+*/
+#define INO_EXT_TYPE_DSTREAM 8
+/*
+#define INO_EXT_TYPE_RESERVED_9 9
+#define INO_EXT_TYPE_DIR_STATS_KEY 10
+#define INO_EXT_TYPE_FS_UUID 11
+#define INO_EXT_TYPE_RESERVED_12 12
+#define INO_EXT_TYPE_SPARSE_BYTES 13
+#define INO_EXT_TYPE_RDEV 14
+#define INO_EXT_TYPE_PURGEABLE_FLAGS 15
+#define INO_EXT_TYPE_ORIG_SYNC_ROOT_ID 16
+*/
+
+
+static const unsigned k_SizeOf_j_dstream = 8 * 5;
+
+struct j_dstream
+{
+ UInt64 size;
+ UInt64 alloced_size;
+ UInt64 default_crypto_id;
+ UInt64 total_bytes_written;
+ UInt64 total_bytes_read;
+
+ void Parse(const Byte *p)
+ {
+ G64 (0, size)
+ G64 (0x8, alloced_size)
+ G64 (0x10, default_crypto_id)
+ G64 (0x18, total_bytes_written)
+ G64 (0x20, total_bytes_read)
+ }
+};
+
+static const unsigned k_SizeOf_j_file_extent_val = 8 * 3;
+
+#define J_FILE_EXTENT_LEN_MASK 0x00ffffffffffffffU
+// #define J_FILE_EXTENT_FLAG_MASK 0xff00000000000000U
+// #define J_FILE_EXTENT_FLAG_SHIFT 56
+
+#define EXTENT_GET_LEN(x) ((x) & J_FILE_EXTENT_LEN_MASK)
+
+struct j_file_extent_val
+{
+ UInt64 len_and_flags; // The length must be a multiple of the block size defined by the nx_block_size field of nx_superblock_t.
+ // There are currently no flags defined
+ UInt64 phys_block_num; // The physical block address that the extent starts at
+ // UInt64 crypto_id; // The encryption key or the encryption tweak used in this extent.
+
+ void Parse(const Byte *p)
+ {
+ G64 (0, len_and_flags)
+ G64 (0x8, phys_block_num)
+ // G64 (0x10, crypto_id);
+ }
+};
+
+
+struct CExtent
+{
+ UInt64 logical_offset;
+ UInt64 len_and_flags; // The length must be a multiple of the block size defined by the nx_block_size field of nx_superblock_t.
+ // There are currently no flags defined
+ UInt64 phys_block_num; // The physical block address that the extent starts at
+
+ UInt64 GetEndOffset() const { return logical_offset + EXTENT_GET_LEN(len_and_flags); }
+};
+
+
+typedef UInt32 MY_uid_t;
+typedef UInt32 MY_gid_t;
+typedef UInt16 MY_mode_t;
+
+
+typedef enum
+{
+ XATTR_DATA_STREAM = 1 << 0,
+ XATTR_DATA_EMBEDDED = 1 << 1,
+ XATTR_FILE_SYSTEM_OWNED = 1 << 2,
+ XATTR_RESERVED_8 = 1 << 3
+} j_xattr_flags;
+
+
+struct CAttr
+{
+ AString Name;
+ UInt32 flags;
+ bool dstream_defined;
+ bool NeedShow;
+ CByteBuffer Data;
+
+ j_dstream dstream;
+ UInt64 Id;
+
+ bool Is_dstream_OK_for_SymLink() const
+ {
+ return dstream_defined && dstream.size <= (1 << 12) && dstream.size != 0;
+ }
+
+ UInt64 GetSize() const
+ {
+ if (dstream_defined) // dstream has more priority
+ return dstream.size;
+ return Data.Size();
+ }
+
+ void Clear()
+ {
+ dstream_defined = false;
+ NeedShow = true;
+ Data.Free();
+ Name.Empty();
+ }
+
+ bool Is_STREAM() const { return (flags & XATTR_DATA_STREAM) != 0; }
+ bool Is_EMBEDDED() const { return (flags & XATTR_DATA_EMBEDDED) != 0; }
+};
+
+
+// j_inode_val_t
+struct CNode
+{
+ unsigned ItemIndex; // index to CItem. We set it only if Node is directory.
+ unsigned NumCalcedLinks; // Num links to that node
+ // unsigned NumItems; // Num Items in that node
+
+ UInt64 parent_id; // The identifier of the file system record for the parent directory.
+ UInt64 private_id;
+ UInt64 create_time;
+ UInt64 mod_time;
+ UInt64 change_time;
+ UInt64 access_time;
+ UInt64 internal_flags;
+ union
+ {
+ UInt32 nchildren; /* The number of directory entries.
+ is valid only if the inode is a directory */
+ UInt32 nlink; /* The number of hard links whose target is this inode.
+ is valid only if the inode isn't a directory.
+ Inodes with multiple hard links (nlink > 1)
+ - The parent_id field refers to the parent directory of the primary link.
+ - The name field contains the name of the primary link.
+ - The INO_EXT_TYPE_NAME extended field contains the name of this link.
+ */
+ };
+ // cp_key_class_t default_protection_class;
+ UInt32 write_generation_counter;
+ UInt32 bsd_flags;
+ MY_uid_t owner;
+ MY_gid_t group;
+ MY_mode_t mode;
+ UInt16 pad1;
+ UInt64 uncompressed_size;
+
+ j_dstream dstream;
+ AString PrimaryName;
+
+ bool dstream_defined;
+ bool refcnt_defined;
+
+ UInt32 refcnt; // j_dstream_id_val_t
+ CRecordVector<CExtent> Extents;
+ CObjectVector<CAttr> Attrs;
+ unsigned SymLinkIndex; // index in Attrs
+ unsigned DecmpfsIndex; // index in Attrs
+ unsigned ResourceIndex; // index in Attrs
+
+ NHfs::CCompressHeader CompressHeader;
+
+ CNode():
+ ItemIndex(VI_MINUS1),
+ NumCalcedLinks(0),
+ // NumItems(0),
+ dstream_defined(false),
+ refcnt_defined(false),
+ SymLinkIndex(VI_MINUS1),
+ DecmpfsIndex(VI_MINUS1),
+ ResourceIndex(VI_MINUS1)
+ {}
+
+ bool IsDir() const { return MY_LIN_S_ISDIR(mode); }
+ bool IsSymLink() const { return MY_LIN_S_ISLNK(mode); }
+
+ bool Has_UNCOMPRESSED_SIZE() const { return (internal_flags & INODE_HAS_UNCOMPRESSED_SIZE) != 0; }
+
+ unsigned Get_Type_From_mode() const { return mode >> 12; }
+
+ bool GetSize(unsigned attrIndex, UInt64 &size) const
+ {
+ if (IsViNotDef(attrIndex))
+ {
+ if (dstream_defined)
+ {
+ size = dstream.size;
+ return true;
+ }
+ size = 0;
+ if (Has_UNCOMPRESSED_SIZE())
+ {
+ size = uncompressed_size;
+ return true;
+ }
+ if (!IsSymLink())
+ return false;
+ attrIndex = SymLinkIndex;
+ if (IsViNotDef(attrIndex))
+ return false;
+ }
+ const CAttr &attr = Attrs[(unsigned)attrIndex];
+ if (attr.dstream_defined)
+ size = attr.dstream.size;
+ else
+ size = attr.Data.Size();
+ return true;
+ }
+
+ bool GetPackSize(unsigned attrIndex, UInt64 &size) const
+ {
+ if (IsViNotDef(attrIndex))
+ {
+ if (dstream_defined)
+ {
+ size = dstream.alloced_size;
+ return true;
+ }
+ size = 0;
+
+ if (IsSymLink())
+ attrIndex = SymLinkIndex;
+ else
+ {
+ if (!CompressHeader.IsCorrect ||
+ !CompressHeader.IsSupported)
+ return false;
+ const CAttr &attr = Attrs[DecmpfsIndex];
+ if (!CompressHeader.IsMethod_Resource())
+ {
+ size = attr.Data.Size() - CompressHeader.DataPos;
+ return true;
+ }
+ attrIndex = ResourceIndex;
+ }
+ if (IsViNotDef(attrIndex))
+ return false;
+ }
+ const CAttr &attr = Attrs[(unsigned)attrIndex];
+ if (attr.dstream_defined)
+ size = attr.dstream.alloced_size;
+ else
+ size = attr.Data.Size();
+ return true;
+ }
+
+ void Parse(const Byte *p);
+};
+
+
+// it's used for Attr streams
+struct CSmallNode
+{
+ CRecordVector<CExtent> Extents;
+ // UInt32 NumLinks;
+ // CSmallNode(): NumLinks(0) {}
+};
+
+static const unsigned k_SizeOf_j_inode_val = 0x5c;
+
+void CNode::Parse(const Byte *p)
+{
+ G64 (0, parent_id)
+ G64 (0x8, private_id)
+ G64 (0x10, create_time)
+ G64 (0x18, mod_time)
+ G64 (0x20, change_time)
+ G64 (0x28, access_time)
+ G64 (0x30, internal_flags)
+ {
+ G32 (0x38, nchildren)
+ // G32 (0x38, nlink);
+ }
+ // G32 (0x3c, default_protection_class);
+ G32 (0x40, write_generation_counter)
+ G32 (0x44, bsd_flags)
+ G32 (0x48, owner)
+ G32 (0x4c, group)
+ G16 (0x50, mode)
+ // G16 (0x52, pad1);
+ G64 (0x54, uncompressed_size)
+}
+
+
+struct CRef
+{
+ unsigned ItemIndex;
+ unsigned NodeIndex;
+ unsigned ParentRefIndex;
+
+ #ifdef APFS_SHOW_ALT_STREAMS
+ unsigned AttrIndex;
+ bool IsAltStream() const { return IsViDef(AttrIndex); }
+ unsigned GetAttrIndex() const { return AttrIndex; }
+ #else
+ // bool IsAltStream() const { return false; }
+ unsigned GetAttrIndex() const { return VI_MINUS1; }
+ #endif
+};
+
+
+struct CRef2
+{
+ unsigned VolIndex;
+ unsigned RefIndex;
+};
+
+
+struct CHashChunk
+{
+ UInt64 lba;
+ UInt32 hashed_len; // the value is UInt16
+ Byte hash[APFS_HASH_MAX_SIZE];
+};
+
+typedef CRecordVector<CHashChunk> CStreamHashes;
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ COutStreamWithHash
+ , ISequentialOutStream
+)
+ bool _hashError;
+ CAlignedBuffer1 _sha;
+ CMyComPtr<ISequentialOutStream> _stream;
+ const CStreamHashes *_hashes;
+ unsigned _blockSizeLog;
+ unsigned _chunkIndex;
+ UInt32 _offsetInChunk;
+ // UInt64 _size;
+
+ CSha256 *Sha() { return (CSha256 *)(void *)(Byte *)_sha; }
+public:
+ COutStreamWithHash(): _sha(sizeof(CSha256)) {}
+
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ // void ReleaseStream() { _stream.Release(); }
+ void Init(const CStreamHashes *hashes, unsigned blockSizeLog)
+ {
+ _hashes = hashes;
+ _blockSizeLog = blockSizeLog;
+ _chunkIndex = 0;
+ _offsetInChunk = 0;
+ _hashError = false;
+ // _size = 0;
+ }
+ // UInt64 GetSize() const { return _size; }
+ bool FinalCheck();
+};
+
+
+static bool Sha256_Final_and_CheckDigest(CSha256 *sha256, const Byte *digest)
+{
+ MY_ALIGN (16)
+ UInt32 temp[SHA256_NUM_DIGEST_WORDS];
+ Sha256_Final(sha256, (Byte *)temp);
+ return memcmp(temp, digest, SHA256_DIGEST_SIZE) == 0;
+}
+
+
+Z7_COM7F_IMF(COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ HRESULT result = S_OK;
+ if (_stream)
+ result = _stream->Write(data, size, &size);
+ if (processedSize)
+ *processedSize = size;
+ while (size != 0)
+ {
+ if (_hashError)
+ break;
+ if (_chunkIndex >= _hashes->Size())
+ {
+ _hashError = true;
+ break;
+ }
+ if (_offsetInChunk == 0)
+ Sha256_Init(Sha());
+ const CHashChunk &chunk = (*_hashes)[_chunkIndex];
+ /* (_blockSizeLog <= 16) && chunk.hashed_len is 16-bit.
+ so we can use 32-bit chunkSize here */
+ const UInt32 chunkSize = ((UInt32)chunk.hashed_len << _blockSizeLog);
+ const UInt32 rem = chunkSize - _offsetInChunk;
+ UInt32 cur = size;
+ if (cur > rem)
+ cur = (UInt32)rem;
+ Sha256_Update(Sha(), (const Byte *)data, cur);
+ data = (const void *)((const Byte *)data + cur);
+ size -= cur;
+ // _size += cur;
+ _offsetInChunk += cur;
+ if (chunkSize == _offsetInChunk)
+ {
+ if (!Sha256_Final_and_CheckDigest(Sha(), chunk.hash))
+ _hashError = true;
+ _offsetInChunk = 0;
+ _chunkIndex++;
+ }
+ }
+ return result;
+}
+
+
+bool COutStreamWithHash::FinalCheck()
+{
+ if (_hashError)
+ return false;
+
+ if (_offsetInChunk != 0)
+ {
+ const CHashChunk &chunk = (*_hashes)[_chunkIndex];
+ {
+ const UInt32 chunkSize = ((UInt32)chunk.hashed_len << _blockSizeLog);
+ const UInt32 rem = chunkSize - _offsetInChunk;
+ Byte b = 0;
+ for (UInt32 i = 0; i < rem; i++)
+ Sha256_Update(Sha(), &b, 1);
+ }
+ if (!Sha256_Final_and_CheckDigest(Sha(), chunk.hash))
+ _hashError = true;
+ _offsetInChunk = 0;
+ _chunkIndex++;
+ }
+ if (_chunkIndex != _hashes->Size())
+ _hashError = true;
+ return !_hashError;
+}
+
+
+
+struct CVol
+{
+ CObjectVector<CNode> Nodes;
+ CRecordVector<UInt64> NodeIDs;
+ CObjectVector<CItem> Items;
+ CRecordVector<CRef> Refs;
+
+ CObjectVector<CSmallNode> SmallNodes;
+ CRecordVector<UInt64> SmallNodeIDs;
+
+ CObjectVector<CSmallNode> FEXT_Nodes;
+ CRecordVector<UInt64> FEXT_NodeIDs;
+
+ CObjectVector<CStreamHashes> Hash_Vectors;
+ CRecordVector<UInt64> Hash_IDs;
+
+ unsigned StartRef2Index; // ref2_Index for Refs[0] item
+ unsigned RootRef2Index; // ref2_Index of virtual root folder (Volume1)
+ CApfs apfs;
+ C_integrity_meta_phys integrity;
+
+ bool NodeNotFound;
+ bool ThereAreUnlinkedNodes;
+ bool WrongInodeLink;
+ bool UnsupportedFeature;
+ bool UnsupportedMethod;
+
+ unsigned NumItems_In_PrivateDir;
+ unsigned NumAltStreams;
+
+ UString RootName;
+
+ bool ThereAreErrors() const
+ {
+ return NodeNotFound || ThereAreUnlinkedNodes || WrongInodeLink;
+ }
+
+ void AddComment(UString &s) const;
+
+ HRESULT FillRefs();
+
+ CVol():
+ StartRef2Index(0),
+ RootRef2Index(VI_MINUS1),
+ NodeNotFound(false),
+ ThereAreUnlinkedNodes(false),
+ WrongInodeLink(false),
+ UnsupportedFeature(false),
+ UnsupportedMethod(false),
+ NumItems_In_PrivateDir(0),
+ NumAltStreams(0)
+ {}
+};
+
+
+static void ApfsTimeToFileTime(UInt64 apfsTime, FILETIME &ft, UInt32 &ns100)
+{
+ const UInt64 s = apfsTime / 1000000000;
+ const UInt32 ns = (UInt32)(apfsTime % 1000000000);
+ ns100 = (ns % 100);
+ const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64((Int64)s) + ns / 100;
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+}
+
+static void AddComment_Name(UString &s, const char *name)
+{
+ s += name;
+ s += ": ";
+}
+
+/*
+static void AddComment_Bool(UString &s, const char *name, bool val)
+{
+ AddComment_Name(s, name);
+ s += val ? "+" : "-";
+ s.Add_LF();
+}
+*/
+
+static void AddComment_UInt64(UString &s, const char *name, UInt64 v)
+{
+ AddComment_Name(s, name);
+ s.Add_UInt64(v);
+ s.Add_LF();
+}
+
+
+static void AddComment_Time(UString &s, const char *name, UInt64 v)
+{
+ AddComment_Name(s, name);
+
+ FILETIME ft;
+ UInt32 ns100;
+ ApfsTimeToFileTime(v, ft, ns100);
+ char temp[64];
+ ConvertUtcFileTimeToString2(ft, ns100, temp
+ // , kTimestampPrintLevel_SEC);
+ , kTimestampPrintLevel_NS);
+ s += temp;
+ s.Add_LF();
+}
+
+
+static void AddComment_modified_by_t(UString &s, const char *name, const apfs_modified_by_t &v)
+{
+ AddComment_Name(s, name);
+ AString s2;
+ s2.SetFrom_CalcLen((const char *)v.id, sizeof(v.id));
+ s += s2;
+ s.Add_LF();
+ s += " ";
+ AddComment_Time(s, "timestamp", v.timestamp);
+ s += " ";
+ AddComment_UInt64(s, "last_xid", v.last_xid);
+}
+
+
+static void AddVolInternalName_toString(UString &s, const CApfs &apfs)
+{
+ AString temp;
+ temp.SetFrom_CalcLen((const char *)apfs.volname, sizeof(apfs.volname));
+ UString unicode;
+ ConvertUTF8ToUnicode(temp, unicode);
+ s += unicode;
+}
+
+
+void CVol::AddComment(UString &s) const
+{
+ AddComment_UInt64(s, "fs_index", apfs.fs_index);
+ {
+ AddComment_Name(s, "volume_name");
+ AddVolInternalName_toString(s, apfs);
+ s.Add_LF();
+ }
+ AddComment_Name(s, "vol_uuid");
+ apfs.vol_uuid.AddHexToString(s);
+ s.Add_LF();
+
+ AddComment_Name(s, "incompatible_features");
+ s += FlagsToString(g_APFS_INCOMPAT_Flags,
+ Z7_ARRAY_SIZE(g_APFS_INCOMPAT_Flags),
+ (UInt32)apfs.incompatible_features);
+ s.Add_LF();
+
+
+ if (apfs.integrity_meta_oid != 0)
+ {
+ /*
+ AddComment_Name(s, "im_version");
+ s.Add_UInt32(integrity.im_version);
+ s.Add_LF();
+ */
+ AddComment_Name(s, "im_flags");
+ s.Add_UInt32(integrity.im_flags);
+ s.Add_LF();
+ AddComment_Name(s, "im_hash_type");
+ const char *p = NULL;
+ if (integrity.im_hash_type < Z7_ARRAY_SIZE(g_hash_types))
+ p = g_hash_types[integrity.im_hash_type];
+ if (p)
+ s += p;
+ else
+ s.Add_UInt32(integrity.im_hash_type);
+ s.Add_LF();
+ }
+
+
+ // AddComment_UInt64(s, "reserve_block_count", apfs.fs_reserve_block_count, false);
+ // AddComment_UInt64(s, "quota_block_count", apfs.fs_quota_block_count);
+ AddComment_UInt64(s, "fs_alloc_count", apfs.fs_alloc_count);
+
+ AddComment_UInt64(s, "num_files", apfs.num_files);
+ AddComment_UInt64(s, "num_directories", apfs.num_directories);
+ AddComment_UInt64(s, "num_symlinks", apfs.num_symlinks);
+ AddComment_UInt64(s, "num_other_fsobjects", apfs.num_other_fsobjects);
+
+ AddComment_UInt64(s, "Num_Attr_Streams", NumAltStreams);
+
+ AddComment_UInt64(s, "num_snapshots", apfs.num_snapshots);
+ AddComment_UInt64(s, "total_blocks_alloced", apfs.total_blocks_alloced);
+ AddComment_UInt64(s, "total_blocks_freed", apfs.total_blocks_freed);
+
+ AddComment_Time(s, "unmounted", apfs.unmount_time);
+ AddComment_Time(s, "last_modified", apfs.last_mod_time);
+ AddComment_modified_by_t(s, "formatted_by", apfs.formatted_by);
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(apfs.modified_by); i++)
+ {
+ const apfs_modified_by_t &v = apfs.modified_by[i];
+ if (v.last_xid == 0 && v.timestamp == 0 && v.id[0] == 0)
+ continue;
+ AString name ("modified_by[");
+ name.Add_UInt32(i);
+ name += ']';
+ AddComment_modified_by_t(s, name.Ptr(), v);
+ }
+}
+
+
+
+struct CKeyValPair
+{
+ CByteBuffer Key;
+ CByteBuffer Val;
+ // unsigned ValPos; // for alognment
+};
+
+
+struct omap_key
+{
+ oid_t oid; // The object identifier
+ xid_t xid; // The transaction identifier
+ void Parse(const Byte *p)
+ {
+ G64o (0, oid)
+ G64x (8, xid)
+ }
+};
+
+/*
+#define OMAP_VAL_DELETED (1 << 0)
+#define OMAP_VAL_SAVED (1 << 1)
+#define OMAP_VAL_ENCRYPTED (1 << 2)
+*/
+#define OMAP_VAL_NOHEADER (1 << 3)
+/*
+#define OMAP_VAL_CRYPTO_GENERATION (1 << 4)
+*/
+
+struct omap_val
+{
+ UInt32 flags;
+ UInt32 size;
+ // paddr_t paddr;
+ paddr_t_unsigned paddr;
+
+ bool IsFlag_NoHeader() const { return (flags & OMAP_VAL_NOHEADER) != 0; }
+
+ void Parse(const Byte *p)
+ {
+ G32 (0, flags)
+ G32 (4, size)
+ G64 (8, paddr)
+ }
+};
+
+
+struct CObjectMap
+{
+ CRecordVector<UInt64> Keys;
+ CRecordVector<omap_val> Vals;
+
+ bool Parse(const CObjectVector<CKeyValPair> &pairs);
+ int FindKey(UInt64 id) const { return Keys.FindInSorted(id); }
+};
+
+bool CObjectMap::Parse(const CObjectVector<CKeyValPair> &pairs)
+{
+ omap_key prev;
+ prev.oid = 0;
+ prev.xid = 0;
+ FOR_VECTOR (i, pairs)
+ {
+ const CKeyValPair &pair = pairs[i];
+ if (pair.Key.Size() != 16 || pair.Val.Size() != 16)
+ return false;
+ omap_key key;
+ key.Parse(pair.Key);
+ omap_val val;
+ val.Parse(pair.Val);
+ /* Object map B-trees are sorted by object identifier and then by transaction identifier
+ but it's possible to have identical Ids in map ?
+ do we need to look transaction id ?
+ and search key with largest transaction id? */
+ if (key.oid <= prev.oid)
+ return false;
+ prev = key;
+ Keys.Add(key.oid);
+ Vals.Add(val);
+ }
+ return true;
+}
+
+
+struct CMap
+{
+ CObjectVector<CKeyValPair> Pairs;
+
+ CObjectMap Omap;
+ btree_info bti;
+ UInt64 NumNodes;
+
+ // we use thnese options to check:
+ UInt32 Subtype;
+ bool IsPhysical;
+
+ bool CheckAtFinish() const
+ {
+ return NumNodes == bti.node_count && Pairs.Size() == bti.key_count;
+ }
+
+ CMap():
+ NumNodes(0),
+ Subtype(0),
+ IsPhysical(true)
+ {}
+};
+
+
+
+struct CDatabase
+{
+ CRecordVector<CRef2> Refs2;
+ CObjectVector<CVol> Vols;
+
+ bool HeadersError;
+ bool ThereAreAltStreams;
+ bool UnsupportedFeature;
+ bool UnsupportedMethod;
+
+ CSuperBlock sb;
+
+ IInStream *OpenInStream;
+ IArchiveOpenCallback *OpenCallback;
+ UInt64 ProgressVal_Cur;
+ UInt64 ProgressVal_Prev;
+ UInt64 ProgressVal_NumFilesTotal;
+ CObjectVector<CByteBuffer> Buffers;
+
+ UInt32 MethodsMask;
+ UInt64 GetSize(const UInt32 index) const;
+
+ void Clear()
+ {
+ HeadersError = false;
+ ThereAreAltStreams = false;
+ UnsupportedFeature = false;
+ UnsupportedMethod = false;
+
+ ProgressVal_Cur = 0;
+ ProgressVal_Prev = 0;
+ ProgressVal_NumFilesTotal = 0;
+
+ MethodsMask = 0;
+
+ Vols.Clear();
+ Refs2.Clear();
+ Buffers.Clear();
+ }
+
+ HRESULT SeekReadBlock_FALSE(UInt64 oid, void *data);
+ void GetItemPath(unsigned index, const CNode *inode, NWindows::NCOM::CPropVariant &path) const;
+ HRESULT ReadMap(UInt64 oid, bool noHeader, CVol *vol, const Byte *hash,
+ CMap &map, unsigned recurseLevel);
+ HRESULT ReadObjectMap(UInt64 oid, CVol *vol, CObjectMap &map);
+ HRESULT OpenVolume(const CObjectMap &omap, const oid_t fs_oid);
+ HRESULT Open2();
+
+ HRESULT GetAttrStream(IInStream *apfsInStream, const CVol &vol,
+ const CAttr &attr, ISequentialInStream **stream);
+
+ HRESULT GetAttrStream_dstream(IInStream *apfsInStream, const CVol &vol,
+ const CAttr &attr, ISequentialInStream **stream);
+
+ HRESULT GetStream2(
+ IInStream *apfsInStream,
+ const CRecordVector<CExtent> *extents, UInt64 rem,
+ ISequentialInStream **stream);
+};
+
+
+HRESULT CDatabase::SeekReadBlock_FALSE(UInt64 oid, void *data)
+{
+ if (OpenCallback)
+ {
+ if (ProgressVal_Cur - ProgressVal_Prev >= (1 << 22))
+ {
+ RINOK(OpenCallback->SetCompleted(NULL, &ProgressVal_Cur))
+ ProgressVal_Prev = ProgressVal_Cur;
+ }
+ ProgressVal_Cur += sb.block_size;
+ }
+ if (oid == 0 || oid >= sb.block_count)
+ return S_FALSE;
+ RINOK(InStream_SeekSet(OpenInStream, oid << sb.block_size_Log))
+ return ReadStream_FALSE(OpenInStream, data, sb.block_size);
+}
+
+
+
+API_FUNC_static_IsArc IsArc_APFS(const Byte *p, size_t size)
+{
+ if (size < kApfsHeaderSize)
+ return k_IsArc_Res_NEED_MORE;
+ CSuperBlock sb;
+ if (!sb.Parse(p))
+ return k_IsArc_Res_NO;
+ return k_IsArc_Res_YES;
+}
+}
+
+
+static bool CheckHash(unsigned hashAlgo, const Byte *data, size_t size, const Byte *digest)
+{
+ if (hashAlgo == APFS_HASH_SHA256)
+ {
+ MY_ALIGN (16)
+ CSha256 sha;
+ Sha256_Init(&sha);
+ Sha256_Update(&sha, data, size);
+ return Sha256_Final_and_CheckDigest(&sha, digest);
+ }
+ return true;
+}
+
+
+HRESULT CDatabase::ReadMap(UInt64 oid, bool noHeader,
+ CVol *vol, const Byte *hash,
+ CMap &map, unsigned recurseLevel)
+{
+ // is it allowed to use big number of levels ?
+ if (recurseLevel > (1 << 10))
+ return S_FALSE;
+
+ const UInt32 blockSize = sb.block_size;
+ if (Buffers.Size() <= recurseLevel)
+ {
+ Buffers.AddNew();
+ if (Buffers.Size() <= recurseLevel)
+ throw 123;
+ Buffers.Back().Alloc(blockSize);
+ }
+ const Byte *buf;
+ {
+ CByteBuffer &buf2 = Buffers[recurseLevel];
+ RINOK(SeekReadBlock_FALSE(oid, buf2))
+ buf = buf2;
+ }
+
+ if (hash && vol)
+ if (!CheckHash(vol->integrity.im_hash_type, buf, blockSize, hash))
+ return S_FALSE;
+
+ CBTreeNodePhys bt;
+ if (!bt.Parse(buf, blockSize, noHeader))
+ return S_FALSE;
+
+ map.NumNodes++;
+
+ /* Specification: All values are stored in leaf nodes, which
+ makes these B+ trees, and the values in nonleaf nodes are object
+ identifiers of child nodes.
+
+ The entries in the table of contents are sorted by key. The comparison function used for sorting depends on the keys type
+ - Object map B-trees are sorted by object identifier and then by transaction identifier.
+ - Free queue B-trees are sorted by transaction identifier and then by physical address.
+ - File-system records are sorted according to the rules listed in File-System Objects.
+ */
+
+ if (!noHeader)
+ if (bt.ophys.subtype != map.Subtype)
+ return S_FALSE;
+
+ unsigned endLimit = blockSize;
+
+ if (recurseLevel == 0)
+ {
+ if (!noHeader)
+ if (bt.ophys.GetType() != OBJECT_TYPE_BTREE)
+ return S_FALSE;
+ if ((bt.flags & BTNODE_ROOT) == 0)
+ return S_FALSE;
+ endLimit -= k_btree_info_Size;
+ map.bti.Parse(buf + endLimit);
+ btree_info &bti = map.bti;
+ if (bti.fixed.key_size >= blockSize)
+ return S_FALSE;
+ if (bti.Is_EPHEMERAL() &&
+ bti.Is_PHYSICAL())
+ return S_FALSE;
+ if (bti.Is_PHYSICAL() != map.IsPhysical)
+ return S_FALSE;
+ if (bti.Is_NOHEADER() != noHeader)
+ return S_FALSE;
+ // we don't allow volumes with big number of Keys
+ const UInt32 kNumItemsMax = k_VectorSizeMax;
+ if (map.bti.node_count > kNumItemsMax)
+ return S_FALSE;
+ if (map.bti.key_count > kNumItemsMax)
+ return S_FALSE;
+ }
+ else
+ {
+ if (!noHeader)
+ if (bt.ophys.GetType() != OBJECT_TYPE_BTREE_NODE)
+ return S_FALSE;
+ if ((bt.flags & BTNODE_ROOT) != 0)
+ return S_FALSE;
+ if (map.NumNodes > map.bti.node_count
+ || map.Pairs.Size() > map.bti.key_count)
+ return S_FALSE;
+ }
+
+ const bool isLeaf = (bt.flags & BTNODE_LEAF) != 0;
+
+ if (isLeaf)
+ {
+ if (bt.level != 0)
+ return S_FALSE;
+ }
+ else
+ {
+ if (bt.level == 0)
+ return S_FALSE;
+ }
+
+ if (!bt.table_space.CheckOverLimit(endLimit - k_Toc_offset))
+ return S_FALSE;
+
+ const unsigned tableEnd = k_Toc_offset + bt.table_space.GetEnd();
+ const unsigned keyValRange = endLimit - tableEnd;
+ const unsigned tocEntrySize = bt.Is_FIXED_KV_SIZE() ? 4 : 8;
+ if (bt.table_space.len / tocEntrySize < bt.nkeys)
+ return S_FALSE;
+
+ for (unsigned i = 0; i < bt.nkeys; i++)
+ {
+ const Byte *p = buf + k_Toc_offset + bt.table_space.off + i * tocEntrySize;
+ if (bt.Is_FIXED_KV_SIZE())
+ {
+ kvoff a;
+ a.Parse(p);
+ if (a.k + map.bti.fixed.key_size > keyValRange
+ || a.v > keyValRange)
+ return S_FALSE;
+ {
+ CKeyValPair pair;
+
+ const Byte *p2 = buf + k_Toc_offset + bt.table_space.len;
+ p2 += a.k;
+ pair.Key.CopyFrom(p2, map.bti.fixed.key_size);
+
+ p2 = buf + endLimit;
+ p2 -= a.v;
+ if (isLeaf)
+ {
+ if (a.v < map.bti.fixed.val_size)
+ return S_FALSE;
+ pair.Val.CopyFrom(p2, map.bti.fixed.val_size);
+ // pair.ValPos = endLimit - a.v;
+ map.Pairs.Add(pair);
+ continue;
+ }
+ {
+ if (a.v < 8)
+ return S_FALSE;
+ // value is only 64-bit for non leaf.
+ const oid_t oidNext = Get64(p2);
+ if (map.bti.Is_PHYSICAL())
+ {
+ RINOK(ReadMap(oidNext, noHeader, vol,
+ NULL, /* hash */
+ map, recurseLevel + 1))
+ continue;
+ }
+ else
+ {
+ // fixme
+ return S_FALSE;
+ }
+ }
+ }
+ }
+ else
+ {
+ kvloc a;
+ a.Parse(p);
+ if (!a.k.CheckOverLimit(keyValRange)
+ || a.v.off > keyValRange
+ || a.v.len > a.v.off)
+ return S_FALSE;
+ {
+ CKeyValPair pair;
+ const Byte *p2 = buf + k_Toc_offset + bt.table_space.len;
+ p2 += a.k.off;
+ pair.Key.CopyFrom(p2, a.k.len);
+
+ p2 = buf + endLimit;
+ p2 -= a.v.off;
+ if (isLeaf)
+ {
+ pair.Val.CopyFrom(p2, a.v.len);
+ // pair.ValPos = endLimit - a.v.off;
+ map.Pairs.Add(pair);
+ continue;
+ }
+ {
+ if (a.v.len < 8)
+ return S_FALSE;
+
+ const Byte *hashNew = NULL;
+ oid_t oidNext = Get64(p2);
+
+ if (bt.Is_HASHED())
+ {
+ if (!vol)
+ return S_FALSE;
+ /*
+ struct btn_index_node_val {
+ oid_t binv_child_oid;
+ uint8_t binv_child_hash[BTREE_NODE_HASH_SIZE_MAX];
+ };
+ */
+ /* (a.v.len == 40) is possible if Is_HASHED()
+ so there is hash (for example, 256-bit) after 64-bit id) */
+ if (a.v.len != 8 + vol->integrity.HashSize)
+ return S_FALSE;
+ hashNew = p2 + 8;
+ /* we need to add root_tree_oid here,
+ but where it's defined in apfs specification ? */
+ oidNext += vol->apfs.root_tree_oid;
+ }
+ else
+ {
+ if (a.v.len != 8)
+ return S_FALSE;
+ }
+
+ // value is only 64-bit for non leaf.
+
+ if (map.bti.Is_PHYSICAL())
+ {
+ return S_FALSE;
+ // the code was not tested:
+ // RINOK(ReadMap(oidNext, map, recurseLevel + 1));
+ // continue;
+ }
+ /*
+ else if (map.bti.Is_EPHEMERAL())
+ {
+ // Ephemeral objects are stored in memory while the container is mounted and in a checkpoint when the container isn't mounted
+ // the code was not tested:
+ return S_FALSE;
+ }
+ */
+ else
+ {
+ /* nodes in the B-tree use virtual object identifiers to link to their child nodes. */
+ const int index = map.Omap.FindKey(oidNext);
+ if (index == -1)
+ return S_FALSE;
+ const omap_val &ov = map.Omap.Vals[(unsigned)index];
+ if (ov.size != blockSize) // change it : it must be multiple of
+ return S_FALSE;
+ RINOK(ReadMap(ov.paddr, ov.IsFlag_NoHeader(), vol, hashNew,
+ map, recurseLevel + 1))
+ continue;
+ }
+ }
+ }
+ }
+ }
+
+ if (recurseLevel == 0)
+ if (!map.CheckAtFinish())
+ return S_FALSE;
+ return S_OK;
+}
+
+
+
+HRESULT CDatabase::ReadObjectMap(UInt64 oid, CVol *vol, CObjectMap &omap)
+{
+ CByteBuffer buf;
+ const size_t blockSize = sb.block_size;
+ buf.Alloc(blockSize);
+ RINOK(SeekReadBlock_FALSE(oid, buf))
+ C_omap_phys op;
+ if (!op.Parse(buf, blockSize, oid))
+ return S_FALSE;
+ CMap map;
+ map.Subtype = OBJECT_TYPE_OMAP;
+ map.IsPhysical = true;
+ RINOK(ReadMap(op.tree_oid,
+ false /* noHeader */,
+ vol,
+ NULL, /* hash */
+ map, 0))
+ if (!omap.Parse(map.Pairs))
+ return S_FALSE;
+ return S_OK;
+}
+
+
+
+HRESULT CDatabase::Open2()
+{
+ Clear();
+ CSuperBlock2 sb2;
+ {
+ Byte buf[kApfsHeaderSize];
+ RINOK(ReadStream_FALSE(OpenInStream, buf, kApfsHeaderSize))
+ if (!sb.Parse(buf))
+ return S_FALSE;
+ sb2.Parse(buf);
+ }
+
+ {
+ CObjectMap omap;
+ RINOK(ReadObjectMap(sb.omap_oid,
+ NULL, /* CVol */
+ omap))
+ unsigned numRefs = 0;
+ for (unsigned i = 0; i < sb.max_file_systems; i++)
+ {
+ const oid_t oid = sb2.fs_oid[i];
+ if (oid == 0)
+ continue;
+ // for (unsigned k = 0; k < 1; k++) // for debug
+ RINOK(OpenVolume(omap, oid))
+ const unsigned a = Vols.Back().Refs.Size();
+ numRefs += a;
+ if (numRefs < a)
+ return S_FALSE; // overflow
+ }
+ }
+
+ const bool needVolumePrefix = (Vols.Size() > 1);
+ // const bool needVolumePrefix = true; // for debug
+ {
+ unsigned numRefs = 0;
+ FOR_VECTOR (i, Vols)
+ {
+ const unsigned a = Vols[i].Refs.Size();
+ numRefs += a;
+ if (numRefs < a)
+ return S_FALSE; // overflow
+ }
+ numRefs += Vols.Size();
+ if (numRefs < Vols.Size())
+ return S_FALSE; // overflow
+ Refs2.Reserve(numRefs);
+ }
+ {
+ FOR_VECTOR (i, Vols)
+ {
+ CVol &vol = Vols[i];
+
+ CRef2 ref2;
+ ref2.VolIndex = i;
+
+ if (needVolumePrefix)
+ {
+ vol.RootName = "Volume";
+ vol.RootName.Add_UInt32(1 + (UInt32)i);
+ vol.RootRef2Index = Refs2.Size();
+ ref2.RefIndex = VI_MINUS1;
+ Refs2.Add(ref2);
+ }
+
+ vol.StartRef2Index = Refs2.Size();
+ const unsigned numItems = vol.Refs.Size();
+ for (unsigned k = 0; k < numItems; k++)
+ {
+ ref2.RefIndex = k;
+ Refs2.Add(ref2);
+ }
+ }
+ }
+ return S_OK;
+}
+
+
+HRESULT CDatabase::OpenVolume(const CObjectMap &omap, const oid_t fs_oid)
+{
+ const size_t blockSize = sb.block_size;
+ CByteBuffer buf;
+ {
+ const int index = omap.FindKey(fs_oid);
+ if (index == -1)
+ return S_FALSE;
+ const omap_val &ov = omap.Vals[(unsigned)index];
+ if (ov.size != blockSize) // change it : it must be multiple of
+ return S_FALSE;
+ buf.Alloc(blockSize);
+ RINOK(SeekReadBlock_FALSE(ov.paddr, buf))
+ }
+
+ CVol &vol = Vols.AddNew();
+ CApfs &apfs = vol.apfs;
+
+ if (!apfs.Parse(buf, blockSize))
+ return S_FALSE;
+
+ if (apfs.fext_tree_oid != 0)
+ {
+ if ((apfs.incompatible_features & APFS_INCOMPAT_SEALED_VOLUME) == 0)
+ return S_FALSE;
+ if ((apfs.fext_tree_type & OBJ_PHYSICAL) == 0)
+ return S_FALSE;
+ if ((apfs.fext_tree_type & OBJECT_TYPE_MASK) != OBJECT_TYPE_BTREE)
+ return S_FALSE;
+
+ CMap map2;
+ map2.Subtype = OBJECT_TYPE_FEXT_TREE;
+ map2.IsPhysical = true;
+
+ RINOK(ReadMap(apfs.fext_tree_oid,
+ false /* noHeader */,
+ &vol,
+ NULL, /* hash */
+ map2, 0))
+
+ UInt64 prevId = 1;
+
+ FOR_VECTOR (i, map2.Pairs)
+ {
+ if (OpenCallback && (i & 0xffff) == 1)
+ {
+ const UInt64 numFiles = ProgressVal_NumFilesTotal +
+ (vol.Items.Size() + vol.Nodes.Size()) / 2;
+ RINOK(OpenCallback->SetCompleted(&numFiles, &ProgressVal_Cur))
+ }
+ // The key half of a record from a file extent tree.
+ // struct fext_tree_key
+ const CKeyValPair &pair = map2.Pairs[i];
+ if (pair.Key.Size() != 16)
+ return S_FALSE;
+ const Byte *p = pair.Key;
+ const UInt64 id = GetUi64(p);
+ if (id < prevId)
+ return S_FALSE; // IDs must be sorted
+ prevId = id;
+
+ CExtent ext;
+ ext.logical_offset = GetUi64(p + 8);
+ {
+ if (pair.Val.Size() != 16)
+ return S_FALSE;
+ const Byte *p2 = pair.Val;
+ ext.len_and_flags = GetUi64(p2);
+ ext.phys_block_num = GetUi64(p2 + 8);
+ }
+
+ PRF(printf("\n%6d: id=%6d logical_addr = %2d len_and_flags=%5x phys_block_num = %5d",
+ i, (unsigned)id,
+ (unsigned)ext.logical_offset,
+ (unsigned)ext.len_and_flags,
+ (unsigned)ext.phys_block_num));
+
+ if (vol.FEXT_NodeIDs.IsEmpty() ||
+ vol.FEXT_NodeIDs.Back() != id)
+ {
+ vol.FEXT_NodeIDs.Add(id);
+ vol.FEXT_Nodes.AddNew();
+ }
+ CRecordVector<CExtent> &extents = vol.FEXT_Nodes.Back().Extents;
+ if (!extents.IsEmpty())
+ if (ext.logical_offset != extents.Back().GetEndOffset())
+ return S_FALSE;
+ extents.Add(ext);
+ continue;
+ }
+
+ PRF(printf("\n\n"));
+ }
+
+ /* For each volume, read the root file system tree's virtual object
+ identifier from the apfs_root_tree_oid field,
+ and then look it up in the volume object map indicated
+ by the omap_oid field. */
+
+ CMap map;
+ ReadObjectMap(apfs.omap_oid, &vol, map.Omap);
+
+ const Byte *hash_for_root = NULL;
+
+ if (apfs.integrity_meta_oid != 0)
+ {
+ if ((apfs.incompatible_features & APFS_INCOMPAT_SEALED_VOLUME) == 0)
+ return S_FALSE;
+ const int index = map.Omap.FindKey(apfs.integrity_meta_oid);
+ if (index == -1)
+ return S_FALSE;
+ const omap_val &ov = map.Omap.Vals[(unsigned)index];
+ if (ov.size != blockSize)
+ return S_FALSE;
+ RINOK(SeekReadBlock_FALSE(ov.paddr, buf))
+ if (!vol.integrity.Parse(buf, blockSize, apfs.integrity_meta_oid))
+ return S_FALSE;
+ if (vol.integrity.im_hash_type != 0)
+ hash_for_root = vol.integrity.Hash;
+ }
+
+ {
+ const int index = map.Omap.FindKey(apfs.root_tree_oid);
+ if (index == -1)
+ return S_FALSE;
+ const omap_val &ov = map.Omap.Vals[(unsigned)index];
+ if (ov.size != blockSize) // change it : it must be multiple of
+ return S_FALSE;
+ map.Subtype = OBJECT_TYPE_FSTREE;
+ map.IsPhysical = false;
+ RINOK(ReadMap(ov.paddr, ov.IsFlag_NoHeader(),
+ &vol, hash_for_root,
+ map, 0))
+ }
+
+ bool needParseAttr = false;
+
+ {
+ const bool isHashed = apfs.IsHashedName();
+ UInt64 prevId = 1;
+
+ {
+ const UInt64 numApfsItems = vol.apfs.GetTotalItems()
+ + 2; // we will have 2 additional hidden directories: root and private-dir
+ const UInt64 numApfsItems_Reserve = numApfsItems
+ + 16; // we reserve 16 for some possible unexpected items
+ if (numApfsItems_Reserve < map.Pairs.Size())
+ {
+ vol.Items.ClearAndReserve((unsigned)numApfsItems_Reserve);
+ vol.Nodes.ClearAndReserve((unsigned)numApfsItems_Reserve);
+ vol.NodeIDs.ClearAndReserve((unsigned)numApfsItems_Reserve);
+ }
+ if (OpenCallback)
+ {
+ const UInt64 numFiles = ProgressVal_NumFilesTotal + numApfsItems;
+ RINOK(OpenCallback->SetTotal(&numFiles, NULL))
+ }
+ }
+
+ CAttr attr;
+ CItem item;
+
+ FOR_VECTOR (i, map.Pairs)
+ {
+ if (OpenCallback && (i & 0xffff) == 1)
+ {
+ const UInt64 numFiles = ProgressVal_NumFilesTotal +
+ (vol.Items.Size() + vol.Nodes.Size()) / 2;
+ RINOK(OpenCallback->SetCompleted(&numFiles, &ProgressVal_Cur))
+ }
+
+ const CKeyValPair &pair = map.Pairs[i];
+ j_key_t jkey;
+ if (pair.Key.Size() < 8)
+ return S_FALSE;
+ const Byte *p = pair.Key;
+ jkey.Parse(p);
+ const unsigned type = jkey.GetType();
+ const UInt64 id = jkey.GetID();
+ if (id < prevId)
+ return S_FALSE; // IDs must be sorted
+ prevId = id;
+
+ PRF(printf("\n%6d: id=%6d type = %2d ", i, (unsigned)id, type));
+
+ if (type == APFS_TYPE_INODE)
+ {
+ PRF(printf("INODE"));
+ if (pair.Key.Size() != 8 ||
+ pair.Val.Size() < k_SizeOf_j_inode_val)
+ return S_FALSE;
+
+ CNode inode;
+ inode.Parse(pair.Val);
+
+ if (inode.private_id != id)
+ {
+ /* private_id : The unique identifier used by this file's data stream.
+ This identifier appears in the owning_obj_id field of j_phys_ext_val_t
+ records that describe the extents where the data is stored.
+ For an inode that doesn't have data, the value of this
+ field is the file-system object's identifier.
+ */
+ // APFS_TYPE_EXTENT allow to link physical address extents.
+ // we don't support case (private_id != id)
+ UnsupportedFeature = true;
+ // return S_FALSE;
+ }
+ const UInt32 extraSize = (UInt32)pair.Val.Size() - k_SizeOf_j_inode_val;
+ if (extraSize != 0)
+ {
+ if (extraSize < 4)
+ return S_FALSE;
+ /*
+ struct xf_blob
+ {
+ uint16_t xf_num_exts;
+ uint16_t xf_used_data;
+ uint8_t xf_data[];
+ };
+ */
+ const Byte *p2 = pair.Val + k_SizeOf_j_inode_val;
+ const UInt32 xf_num_exts = Get16(p2);
+ const UInt32 xf_used_data = Get16(p2 + 2);
+ UInt32 offset = 4 + (UInt32)xf_num_exts * 4;
+ if (offset + xf_used_data != extraSize)
+ return S_FALSE;
+
+ PRF(printf(" parent_id = %d", (unsigned)inode.parent_id));
+
+ for (unsigned k = 0; k < xf_num_exts; k++)
+ {
+ // struct x_field
+ const Byte *p3 = p2 + 4 + k * 4;
+ const Byte x_type = p3[0];
+ // const Byte x_flags = p3[1];
+ const UInt32 x_size = Get16(p3 + 2);
+ const UInt32 x_size_ceil = (x_size + 7) & ~(UInt32)7;
+ if (offset + x_size_ceil > extraSize)
+ return S_FALSE;
+ const Byte *p4 = p2 + offset;
+ if (x_type == INO_EXT_TYPE_NAME)
+ {
+ if (x_size < 2)
+ return S_FALSE;
+ inode.PrimaryName.SetFrom_CalcLen((const char *)p4, x_size);
+ PRF(printf(" PrimaryName = %s", inode.PrimaryName.Ptr()));
+ if (inode.PrimaryName.Len() != x_size - 1)
+ HeadersError = true;
+ // return S_FALSE;
+ }
+ else if (x_type == INO_EXT_TYPE_DSTREAM)
+ {
+ if (x_size != k_SizeOf_j_dstream)
+ return S_FALSE;
+ if (inode.dstream_defined)
+ return S_FALSE;
+ inode.dstream.Parse(p4);
+ inode.dstream_defined = true;
+ }
+ else
+ {
+ // UnsupportedFeature = true;
+ // return S_FALSE;
+ }
+ offset += x_size_ceil;
+ }
+ if (offset != extraSize)
+ return S_FALSE;
+ }
+
+ if (!vol.NodeIDs.IsEmpty())
+ if (id <= vol.NodeIDs.Back())
+ return S_FALSE;
+ vol.Nodes.Add(inode);
+ vol.NodeIDs.Add(id);
+ continue;
+ }
+
+ if (type == APFS_TYPE_XATTR)
+ {
+ PRF(printf(" XATTR"));
+
+ /*
+ struct j_xattr_key
+ {
+ j_key_t hdr;
+ uint16_t name_len;
+ uint8_t name[0];
+ }
+ */
+
+ UInt32 len;
+ unsigned nameOffset;
+ {
+ nameOffset = 8 + 2;
+ if (pair.Key.Size() < nameOffset + 1)
+ return S_FALSE;
+ len = Get16(p + 8);
+ }
+ if (nameOffset + len != pair.Key.Size())
+ return S_FALSE;
+
+ attr.Clear();
+ attr.Name.SetFrom_CalcLen((const char *)p + nameOffset, len);
+ if (attr.Name.Len() != len - 1)
+ return S_FALSE;
+
+ PRF(printf(" name=%s", attr.Name.Ptr()));
+
+ const unsigned k_SizeOf_j_xattr_val = 4;
+ if (pair.Val.Size() < k_SizeOf_j_xattr_val)
+ return S_FALSE;
+ /*
+ struct j_xattr_val
+ {
+ uint16_t flags;
+ uint16_t xdata_len;
+ uint8_t xdata[0];
+ }
+ */
+ attr.flags = Get16(pair.Val);
+ const UInt32 xdata_len = Get16(pair.Val + 2);
+
+ PRF(printf(" flags=%x xdata_len = %d",
+ (unsigned)attr.flags,
+ (unsigned)xdata_len));
+
+ const Byte *p4 = pair.Val + 4;
+
+ if (k_SizeOf_j_xattr_val + xdata_len != pair.Val.Size())
+ return S_FALSE;
+ if (attr.Is_EMBEDDED())
+ attr.Data.CopyFrom(p4, xdata_len);
+ else if (attr.Is_STREAM())
+ {
+ // why (attr.flags == 0x11) here? (0x11 is undocummented flag)
+ if (k_SizeOf_j_xattr_val + 8 + k_SizeOf_j_dstream != pair.Val.Size())
+ return S_FALSE;
+ attr.Id = Get64(p4);
+ attr.dstream.Parse(p4 + 8);
+ attr.dstream_defined = true;
+ PRF(printf(" streamID=%d streamSize=%d", (unsigned)attr.Id, (unsigned)attr.dstream.size));
+ }
+ else
+ {
+ // unknown attribute
+ // UnsupportedFeature = true;
+ // return S_FALSE;
+ }
+
+ if (vol.NodeIDs.IsEmpty() ||
+ vol.NodeIDs.Back() != id)
+ {
+ return S_FALSE;
+ // UnsupportedFeature = true;
+ // continue;
+ }
+
+ CNode &inode = vol.Nodes.Back();
+
+ if (attr.Name.IsEqualTo("com.apple.fs.symlink"))
+ {
+ inode.SymLinkIndex = inode.Attrs.Size();
+ if (attr.Is_dstream_OK_for_SymLink())
+ needParseAttr = true;
+ }
+ else if (attr.Name.IsEqualTo("com.apple.decmpfs"))
+ {
+ inode.DecmpfsIndex = inode.Attrs.Size();
+ // if (attr.dstream_defined)
+ needParseAttr = true;
+ }
+ else if (attr.Name.IsEqualTo("com.apple.ResourceFork"))
+ {
+ inode.ResourceIndex = inode.Attrs.Size();
+ }
+ inode.Attrs.Add(attr);
+ continue;
+ }
+
+ if (type == APFS_TYPE_DSTREAM_ID)
+ {
+ PRF(printf(" DSTREAM_ID"));
+ if (pair.Key.Size() != 8)
+ return S_FALSE;
+ // j_dstream_id_val_t
+ if (pair.Val.Size() != 4)
+ return S_FALSE;
+ const UInt32 refcnt = Get32(pair.Val);
+
+ // The data stream record can be deleted when its reference count reaches zero.
+ PRF(printf(" refcnt = %d", (unsigned)refcnt));
+
+ if (vol.NodeIDs.IsEmpty())
+ return S_FALSE;
+
+ if (vol.NodeIDs.Back() != id)
+ {
+ // is it possible ?
+ // continue;
+ return S_FALSE;
+ }
+
+ CNode &inode = vol.Nodes.Back();
+
+ if (inode.refcnt_defined)
+ return S_FALSE;
+
+ inode.refcnt = refcnt;
+ inode.refcnt_defined = true;
+ if (inode.refcnt != (UInt32)inode.nlink)
+ {
+ PRF(printf(" refcnt != nlink"));
+ // is it possible ?
+ // return S_FALSE;
+ }
+ continue;
+ }
+
+ if (type == APFS_TYPE_FILE_EXTENT)
+ {
+ PRF(printf(" FILE_EXTENT"));
+ /*
+ struct j_file_extent_key
+ {
+ j_key_t hdr;
+ uint64_t logical_addr;
+ }
+ */
+ if (pair.Key.Size() != 16)
+ return S_FALSE;
+ // The offset within the file's data, in bytes, for the data stored in this extent
+ const UInt64 logical_addr = Get64(p + 8);
+
+ j_file_extent_val eval;
+ if (pair.Val.Size() != k_SizeOf_j_file_extent_val)
+ return S_FALSE;
+ eval.Parse(pair.Val);
+
+ if (logical_addr != 0)
+ {
+ PRF(printf(" logical_addr = %d", (unsigned)logical_addr));
+ }
+ PRF(printf(" len = %8d pos = %8d",
+ (unsigned)eval.len_and_flags,
+ (unsigned)eval.phys_block_num
+ ));
+
+ CExtent ext;
+ ext.logical_offset = logical_addr;
+ ext.len_and_flags = eval.len_and_flags;
+ ext.phys_block_num = eval.phys_block_num;
+
+ if (vol.NodeIDs.IsEmpty())
+ return S_FALSE;
+ if (vol.NodeIDs.Back() != id)
+ {
+ // extents for Attributs;
+ if (vol.SmallNodeIDs.IsEmpty() ||
+ vol.SmallNodeIDs.Back() != id)
+ {
+ vol.SmallNodeIDs.Add(id);
+ vol.SmallNodes.AddNew();
+ }
+ vol.SmallNodes.Back().Extents.Add(ext);
+ continue;
+ // return S_FALSE;
+ }
+
+ CNode &inode = vol.Nodes.Back();
+ inode.Extents.Add(ext);
+ continue;
+ }
+
+ if (type == APFS_TYPE_DIR_REC)
+ {
+ UInt32 len;
+ unsigned nameOffset;
+
+ if (isHashed)
+ {
+ /*
+ struct j_drec_hashed_key
+ {
+ j_key_t hdr;
+ UInt32 name_len_and_hash;
+ uint8_t name[0];
+ }
+ */
+ nameOffset = 8 + 4;
+ if (pair.Key.Size() < nameOffset + 1)
+ return S_FALSE;
+ const UInt32 name_len_and_hash = Get32(p + 8);
+ len = name_len_and_hash & J_DREC_LEN_MASK;
+ }
+ else
+ {
+ /*
+ struct j_drec_key
+ {
+ j_key_t hdr;
+ UInt16 name_len; // The length of the name, including the final null character
+ uint8_t name[0]; // The name, represented as a null-terminated UTF-8 string
+ }
+ */
+ nameOffset = 8 + 2;
+ if (pair.Key.Size() < nameOffset + 1)
+ return S_FALSE;
+ len = Get16(p + 8);
+ }
+ if (nameOffset + len != pair.Key.Size())
+ return S_FALSE;
+
+ // CItem item;
+ item.Clear();
+
+ item.ParentId = id;
+ item.Name.SetFrom_CalcLen((const char *)p + nameOffset, len);
+ if (item.Name.Len() != len - 1)
+ return S_FALSE;
+
+ if (pair.Val.Size() < k_SizeOf_j_drec_val)
+ return S_FALSE;
+
+ item.Val.Parse(pair.Val);
+
+ if (pair.Val.Size() > k_SizeOf_j_drec_val)
+ {
+ // fixme: parse extra fields;
+ // UnsupportedFeature = true;
+ // return S_FALSE;
+ }
+
+ vol.Items.Add(item);
+
+ /*
+ if (!vol.NodeIDs.IsEmpty() && vol.NodeIDs.Back() == id)
+ vol.Nodes.Back().NumItems++;
+ */
+ if (id == PRIV_DIR_INO_NUM)
+ vol.NumItems_In_PrivateDir++;
+
+ PRF(printf(" DIR_REC next=%6d flags=%2x %s",
+ (unsigned)item.Val.file_id,
+ (unsigned)item.Val.flags,
+ item.Name.Ptr()));
+ continue;
+ }
+
+ if (type == APFS_TYPE_FILE_INFO)
+ {
+ if (pair.Key.Size() != 16)
+ return S_FALSE;
+ // j_file_info_key
+ const UInt64 info_and_lba = Get64(p + 8);
+
+ #define J_FILE_INFO_LBA_MASK 0x00ffffffffffffffUL
+ // #define J_FILE_INFO_TYPE_MASK 0xff00000000000000UL
+ #define J_FILE_INFO_TYPE_SHIFT 56
+ #define APFS_FILE_INFO_DATA_HASH 1
+
+ const unsigned infoType = (unsigned)(info_and_lba >> J_FILE_INFO_TYPE_SHIFT);
+ // address is a paddr_t
+ const UInt64 lba = info_and_lba & J_FILE_INFO_LBA_MASK;
+ // j_file_data_hash_val_t
+ /* Use this field of the union if the type stored in the info_and_lba field of j_file_info_val_t is
+ APFS_FILE_INFO_DATA_HASH */
+ if (infoType != APFS_FILE_INFO_DATA_HASH)
+ return S_FALSE;
+ if (pair.Val.Size() != 3 + vol.integrity.HashSize)
+ return S_FALSE;
+ /*
+ struct j_file_data_hash_val
+ {
+ UInt16 hashed_len; // The length, in blocks, of the data segment that was hashed.
+ UInt8 hash_size; // must be consistent with integrity_meta_phys_t::im_hash_type
+ UInt8 hash[0];
+ }
+ */
+
+ const unsigned hash_size = pair.Val[2];
+ if (hash_size != vol.integrity.HashSize)
+ return S_FALSE;
+
+ CHashChunk hr;
+ hr.hashed_len = GetUi16(pair.Val);
+ if (hr.hashed_len == 0)
+ return S_FALSE;
+ memcpy(hr.hash, (const Byte *)pair.Val + 3, vol.integrity.HashSize);
+ // (hashed_len <= 4) : we have seen
+ hr.lba = lba;
+
+ PRF(printf(" FILE_INFO lba = %6x, hashed_len=%6d",
+ (unsigned)lba,
+ (unsigned)hr.hashed_len));
+
+ if (vol.Hash_IDs.IsEmpty() || vol.Hash_IDs.Back() != id)
+ {
+ vol.Hash_Vectors.AddNew();
+ vol.Hash_IDs.Add(id);
+ }
+ CStreamHashes &hashes = vol.Hash_Vectors.Back();
+ if (hashes.Size() != 0)
+ {
+ const CHashChunk &hr_Back = hashes.Back();
+ if (lba != hr_Back.lba + ((UInt64)hr_Back.hashed_len << sb.block_size_Log))
+ return S_FALSE;
+ }
+ hashes.Add(hr);
+ continue;
+ }
+
+ if (type == APFS_TYPE_SNAP_METADATA)
+ {
+ if (pair.Key.Size() != 8)
+ return S_FALSE;
+ PRF(printf(" SNAP_METADATA"));
+ // continue;
+ }
+
+ /* SIBLING items are used, if there are more than one hard link to some inode
+ key : value
+ parent_id_1 DIR_REC : inode_id, name_1
+ parent_id_2 DIR_REC : inode_id, name_2
+ inode_id INODE : parent_id_1, name_1
+ inode_id SIBLING_LINK sibling_id_1 : parent_id_1, name_1
+ inode_id SIBLING_LINK sibling_id_2 : parent_id_2, name_2
+ sibling_id_1 SIBLING_MAP : inode_id
+ sibling_id_2 SIBLING_MAP : inode_id
+ */
+
+ if (type == APFS_TYPE_SIBLING_LINK)
+ {
+ if (pair.Key.Size() != 16)
+ return S_FALSE;
+ if (pair.Val.Size() < 10 + 1)
+ return S_FALSE;
+ /*
+ // struct j_sibling_key
+ // The sibling's unique identifier.
+ // This value matches the object identifier for the sibling map record
+ const UInt64 sibling_id = Get64(p + 8);
+ // struct j_sibling_val
+ const Byte *v = pair.Val;
+ const UInt64 parent_id = Get64(v); // The object identifier for the inode that's the parent directory.
+ const unsigned name_len = Get16(v + 8); // len including the final null character
+ if (10 + name_len != pair.Val.Size())
+ return S_FALSE;
+ if (v[10 + name_len - 1] != 0)
+ return S_FALSE;
+ AString name ((const char *)(v + 10));
+ if (name.Len() != name_len - 1)
+ return S_FALSE;
+ PRF(printf(" SIBLING_LINK sibling_id = %6d : parent_id=%6d %s",
+ (unsigned)sibling_id, (unsigned)parent_id, name.Ptr()));
+ */
+ continue;
+ }
+
+ if (type == APFS_TYPE_SIBLING_MAP)
+ {
+ // struct j_sibling_map_key
+ // The object identifier in the header is the sibling's unique identifier
+ if (pair.Key.Size() != 8 || pair.Val.Size() != 8)
+ return S_FALSE;
+ /*
+ // j_sibling_map_val
+ // The inode number of the underlying file
+ const UInt64 file_id = Get64(pair.Val);
+ PRF(printf(" SIBLING_MAP : file_id = %d", (unsigned)file_id));
+ */
+ continue;
+ }
+
+ UnsupportedFeature = true;
+ // return S_FALSE;
+ }
+ ProgressVal_NumFilesTotal += vol.Items.Size();
+ }
+
+
+ if (needParseAttr)
+ {
+ /* we read external streams for attributes
+ So we can get SymLink for GetProperty(kpidSymLink) later */
+ FOR_VECTOR (i, vol.Nodes)
+ {
+ CNode &node = vol.Nodes[i];
+
+ FOR_VECTOR (a, node.Attrs)
+ {
+ CAttr &attr = node.Attrs[a];
+ if (attr.Data.Size() != 0 || !attr.dstream_defined)
+ continue;
+ if (a == node.SymLinkIndex)
+ {
+ if (!attr.Is_dstream_OK_for_SymLink())
+ continue;
+ }
+ else
+ {
+ if (a != node.DecmpfsIndex
+ // && a != node.ResourceIndex
+ )
+ continue;
+ }
+ // we don't expect big streams here
+ // largest dstream for Decmpfs attribute is (2Kib+17)
+ if (attr.dstream.size > ((UInt32)1 << 16))
+ continue;
+ CMyComPtr<ISequentialInStream> inStream;
+ const HRESULT res = GetAttrStream_dstream(OpenInStream, vol, attr, &inStream);
+ if (res == S_OK && inStream)
+ {
+ CByteBuffer buf2;
+ const size_t size = (size_t)attr.dstream.size;
+ buf2.Alloc(size);
+ if (ReadStream_FAIL(inStream, buf2, size) == S_OK)
+ attr.Data = buf2;
+
+ ProgressVal_Cur += size;
+ if (OpenCallback)
+ if (ProgressVal_Cur - ProgressVal_Prev >= (1 << 22))
+ {
+
+ RINOK(OpenCallback->SetCompleted(
+ &ProgressVal_NumFilesTotal,
+ &ProgressVal_Cur))
+ ProgressVal_Prev = ProgressVal_Cur;
+ }
+ }
+ }
+
+ if (node.Has_UNCOMPRESSED_SIZE())
+ if (IsViDef(node.DecmpfsIndex))
+ {
+ CAttr &attr = node.Attrs[node.DecmpfsIndex];
+ node.CompressHeader.Parse(attr.Data, attr.Data.Size());
+
+ if (node.CompressHeader.IsCorrect)
+ if (node.CompressHeader.Method < sizeof(MethodsMask) * 8)
+ MethodsMask |= ((UInt32)1 << node.CompressHeader.Method);
+
+ if (node.CompressHeader.IsCorrect
+ && node.CompressHeader.IsSupported
+ && node.CompressHeader.UnpackSize == node.uncompressed_size)
+ {
+ attr.NeedShow = false;
+ if (node.CompressHeader.IsMethod_Resource()
+ && IsViDef(node.ResourceIndex))
+ node.Attrs[node.ResourceIndex].NeedShow = false;
+ }
+ else
+ {
+ vol.UnsupportedMethod = true;
+ }
+ }
+ }
+ }
+
+ const HRESULT res = vol.FillRefs();
+
+ if (vol.ThereAreErrors())
+ HeadersError = true;
+ if (vol.UnsupportedFeature)
+ UnsupportedFeature = true;
+ if (vol.UnsupportedMethod)
+ UnsupportedMethod = true;
+ if (vol.NumAltStreams != 0)
+ ThereAreAltStreams = true;
+
+ return res;
+}
+
+
+
+HRESULT CVol::FillRefs()
+{
+ {
+ Refs.Reserve(Items.Size());
+ // we fill Refs[*]
+ // we
+ // and set Nodes[*].ItemIndex for Nodes that are directories;
+ FOR_VECTOR (i, Items)
+ {
+ CItem &item = Items[i];
+ const UInt64 id = item.Val.file_id;
+ // if (item.Id == ROOT_DIR_PARENT) continue;
+ /* for two root folders items
+ we don't set Node.ItemIndex; */
+ // so nodes
+ if (id == ROOT_DIR_INO_NUM)
+ continue;
+ if (id == PRIV_DIR_INO_NUM)
+ if (NumItems_In_PrivateDir == 0) // if (inode.NumItems == 0)
+ continue;
+
+ CRef ref;
+ ref.ItemIndex = i;
+ // ref.NodeIndex = VI_MINUS1;
+ ref.ParentRefIndex = VI_MINUS1;
+ #ifdef APFS_SHOW_ALT_STREAMS
+ ref.AttrIndex = VI_MINUS1;
+ #endif
+ const int index = NodeIDs.FindInSorted(id);
+ // const int index = -1; // for debug
+ ref.NodeIndex = (unsigned)index;
+ item.RefIndex = Refs.Size();
+ Refs.Add(ref);
+
+ if (index == -1)
+ {
+ NodeNotFound = true;
+ continue;
+ // return S_FALSE;
+ }
+
+ // item.iNode_Index = index;
+ CNode &inode = Nodes[(unsigned)index];
+ if (!item.Val.IsFlags_Unknown()
+ && inode.Get_Type_From_mode() != item.Val.flags)
+ {
+ Refs.Back().NodeIndex = VI_MINUS1;
+ WrongInodeLink = true;
+ continue;
+ // return S_FALSE;
+ }
+
+ const bool isDir = inode.IsDir();
+ if (isDir)
+ {
+ if (IsViDef(inode.ItemIndex))
+ {
+ // hard links to dirs are not supported
+ Refs.Back().NodeIndex = VI_MINUS1;
+ WrongInodeLink = true;
+ continue;
+ }
+ inode.ItemIndex = i;
+ }
+ inode.NumCalcedLinks++;
+
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (!isDir)
+ {
+ // we use alt streams only for files
+ const unsigned numAttrs = inode.Attrs.Size();
+ if (numAttrs != 0)
+ {
+ ref.ParentRefIndex = item.RefIndex;
+ for (unsigned k = 0; k < numAttrs; k++)
+ {
+ // comment it for debug
+ const CAttr &attr = inode.Attrs[k];
+ if (!attr.NeedShow)
+ continue;
+
+ if (k == inode.SymLinkIndex)
+ continue;
+ ref.AttrIndex = k;
+ NumAltStreams++;
+ Refs.Add(ref);
+ /*
+ if (attr.dstream_defined)
+ {
+ const int idIndex = SmallNodeIDs.FindInSorted(attr.Id);
+ if (idIndex != -1)
+ SmallNodes[(unsigned)idIndex].NumLinks++; // for debug
+ }
+ */
+ }
+ }
+ }
+ #endif
+ }
+ }
+
+
+ {
+ // fill ghost nodes
+ CRef ref;
+ ref.ItemIndex = VI_MINUS1;
+ ref.ParentRefIndex = VI_MINUS1;
+ #ifdef APFS_SHOW_ALT_STREAMS
+ ref.AttrIndex = VI_MINUS1;
+ #endif
+ FOR_VECTOR (i, Nodes)
+ {
+ if (Nodes[i].NumCalcedLinks != 0)
+ continue;
+ const UInt64 id = NodeIDs[i];
+ if (id == ROOT_DIR_INO_NUM ||
+ id == PRIV_DIR_INO_NUM)
+ continue;
+ ThereAreUnlinkedNodes = true;
+ ref.NodeIndex = i;
+ Refs.Add(ref);
+ }
+ }
+
+ /* if want to create Refs for ghost data streams,
+ we need additional CRef::SmallNodeIndex field */
+
+ {
+ /* all Nodes[*].ItemIndex were already filled for directory Nodes,
+ except of "root" and "private-dir" Nodes. */
+
+ // now we fill Items[*].ParentItemIndex and Refs[*].ParentRefIndex
+
+ UInt64 prev_ID = (UInt64)(Int64)-1;
+ unsigned prev_ParentItemIndex = VI_MINUS1;
+
+ FOR_VECTOR (i, Items)
+ {
+ CItem &item = Items[i];
+ const UInt64 id = item.ParentId; // it's id of parent NODE
+ if (id != prev_ID)
+ {
+ prev_ID = id;
+ prev_ParentItemIndex = VI_MINUS1;
+ const int index = NodeIDs.FindInSorted(id);
+ if (index == -1)
+ continue;
+ prev_ParentItemIndex = Nodes[(unsigned)index].ItemIndex;
+ }
+
+ if (IsViNotDef(prev_ParentItemIndex))
+ continue;
+ item.ParentItemIndex = prev_ParentItemIndex;
+ if (IsViNotDef(item.RefIndex))
+ {
+ // RefIndex is not set for 2 Items (root folders)
+ // but there is no node for them usually
+ continue;
+ }
+ CRef &ref = Refs[item.RefIndex];
+
+ /*
+ // it's optional check that parent_id is set correclty
+ if (IsViDef(ref.NodeIndex))
+ {
+ const CNode &node = Nodes[ref.NodeIndex];
+ if (node.IsDir() && node.parent_id != id)
+ return S_FALSE;
+ }
+ */
+
+ /*
+ if (id == ROOT_DIR_INO_NUM)
+ {
+ // ItemIndex in Node for ROOT_DIR_INO_NUM was not set bofere
+ // probably unused now.
+ ref.ParentRefIndex = VI_MINUS1;
+ }
+ else
+ */
+ ref.ParentRefIndex = Items[prev_ParentItemIndex].RefIndex;
+ }
+ }
+
+ {
+ // check for loops
+ const unsigned numItems = Items.Size();
+ if (numItems + 1 == 0)
+ return S_FALSE;
+ CUIntArr arr;
+ arr.Alloc(numItems);
+ {
+ for (unsigned i = 0; i < numItems; i++)
+ arr[i] = 0;
+ }
+ for (unsigned i = 0; i < numItems;)
+ {
+ unsigned k = i++;
+ for (;;)
+ {
+ const unsigned a = arr[k];
+ if (a != 0)
+ {
+ if (a == i)
+ return S_FALSE;
+ break;
+ }
+ arr[k] = i;
+ k = Items[k].ParentItemIndex;
+ if (IsViNotDef(k))
+ break;
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+Z7_class_CHandler_final:
+ public IInArchive,
+ public IArchiveGetRawProps,
+ public IInArchiveGetStream,
+ public CMyUnknownImp,
+ public CDatabase
+{
+ Z7_IFACES_IMP_UNK_3(
+ IInArchive,
+ IArchiveGetRawProps,
+ IInArchiveGetStream)
+
+ CMyComPtr<IInStream> _stream;
+ int FindHashIndex_for_Item(UInt32 index);
+};
+
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ Close();
+ OpenInStream = inStream;
+ OpenCallback = callback;
+ RINOK(Open2())
+ _stream = inStream;
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _stream.Release();
+ Clear();
+ return S_OK;
+}
+
+
+enum
+{
+ kpidBytesWritten = kpidUserDefined,
+ kpidBytesRead,
+ kpidPrimeName,
+ kpidParentINode,
+ kpidAddTime,
+ kpidGeneration,
+ kpidBsdFlags
+ // kpidUncompressedSize
+};
+
+static const CStatProp kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR },
+ { NULL, kpidSize, VT_UI8 },
+ { NULL, kpidPackSize, VT_UI8 },
+ { NULL, kpidPosixAttrib, VT_UI4 },
+ { NULL, kpidMTime, VT_FILETIME },
+ { NULL, kpidCTime, VT_FILETIME },
+ { NULL, kpidATime, VT_FILETIME },
+ { NULL, kpidChangeTime, VT_FILETIME },
+ { "Added Time", kpidAddTime, VT_FILETIME },
+ { NULL, kpidMethod, VT_BSTR },
+ { NULL, kpidINode, VT_UI8 },
+ { NULL, kpidLinks, VT_UI4 },
+ { NULL, kpidSymLink, VT_BSTR },
+ { NULL, kpidUserId, VT_UI4 },
+ { NULL, kpidGroupId, VT_UI4 },
+ { NULL, kpidCharacts, VT_BSTR },
+ #ifdef APFS_SHOW_ALT_STREAMS
+ { NULL, kpidIsAltStream, VT_BOOL },
+ #endif
+ { "Parent iNode", kpidParentINode, VT_UI8 },
+ { "Primary Name", kpidPrimeName, VT_BSTR },
+ { "Generation", kpidGeneration, VT_UI4 },
+ { "Written Size", kpidBytesWritten, VT_UI8 },
+ { "Read Size", kpidBytesRead, VT_UI8 },
+ { "BSD Flags", kpidBsdFlags, VT_UI4 }
+ // , { "Uncompressed Size", kpidUncompressedSize, VT_UI8 }
+};
+
+
+static const Byte kArcProps[] =
+{
+ kpidName,
+ kpidCharacts,
+ kpidId,
+ kpidClusterSize,
+ kpidCTime,
+ kpidMTime,
+ kpidComment
+};
+
+IMP_IInArchive_Props_WITH_NAME
+IMP_IInArchive_ArcProps
+
+
+static void ApfsTimeToProp(UInt64 hfsTime, NWindows::NCOM::CPropVariant &prop)
+{
+ if (hfsTime == 0)
+ return;
+ FILETIME ft;
+ UInt32 ns100;
+ ApfsTimeToFileTime(hfsTime, ft, ns100);
+ prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, ns100);
+}
+
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CApfs *apfs = NULL;
+ if (Vols.Size() == 1)
+ apfs = &Vols[0].apfs;
+ switch (propID)
+ {
+ case kpidPhySize:
+ prop = (UInt64)sb.block_count << sb.block_size_Log;
+ break;
+ case kpidClusterSize: prop = (UInt32)(sb.block_size); break;
+ case kpidCharacts: NHfs::MethodsMaskToProp(MethodsMask, prop); break;
+ case kpidMTime:
+ if (apfs)
+ ApfsTimeToProp(apfs->modified_by[0].timestamp, prop);
+ break;
+ case kpidCTime:
+ if (apfs)
+ ApfsTimeToProp(apfs->formatted_by.timestamp, prop);
+ break;
+ case kpidIsTree: prop = true; break;
+ case kpidErrorFlags:
+ {
+ UInt32 flags = 0;
+ if (HeadersError) flags |= kpv_ErrorFlags_HeadersError;
+ if (flags != 0)
+ prop = flags;
+ break;
+ }
+ case kpidWarningFlags:
+ {
+ UInt32 flags = 0;
+ if (UnsupportedFeature) flags |= kpv_ErrorFlags_UnsupportedFeature;
+ if (UnsupportedMethod) flags |= kpv_ErrorFlags_UnsupportedMethod;
+ if (flags != 0)
+ prop = flags;
+ break;
+ }
+
+ case kpidName:
+ {
+ if (apfs)
+ {
+ UString s;
+ AddVolInternalName_toString(s, *apfs);
+ s += ".apfs";
+ prop = s;
+ }
+ break;
+ }
+
+ case kpidId:
+ {
+ char s[32 + 4];
+ sb.uuid.SetHex_To_str(s);
+ prop = s;
+ break;
+ }
+
+ case kpidComment:
+ {
+ UString s;
+ {
+ AddComment_UInt64(s, "block_size", sb.block_size);
+
+ FOR_VECTOR (i, Vols)
+ {
+ if (Vols.Size() > 1)
+ {
+ if (i != 0)
+ {
+ s += "----";
+ s.Add_LF();
+ }
+ AddComment_UInt64(s, "Volume", i + 1);
+ }
+ Vols[i].AddComment(s);
+ }
+ }
+ prop = s;
+ break;
+ }
+
+ #ifdef APFS_SHOW_ALT_STREAMS
+ case kpidIsAltStream:
+ prop = ThereAreAltStreams;
+ // prop = false; // for debug
+ break;
+ #endif
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps))
+{
+ *numProps = 0;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID))
+{
+ *name = NULL;
+ *propID = 0;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType))
+{
+ *parentType = NParentType::kDir;
+
+ const CRef2 &ref2 = Refs2[index];
+ const CVol &vol = Vols[ref2.VolIndex];
+ UInt32 parentIndex = (UInt32)(Int32)-1;
+
+ if (IsViDef(ref2.RefIndex))
+ {
+ const CRef &ref = vol.Refs[ref2.RefIndex];
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (ref.IsAltStream())
+ *parentType = NParentType::kAltStream;
+ #endif
+ if (IsViDef(ref.ParentRefIndex))
+ parentIndex = (UInt32)(ref.ParentRefIndex + vol.StartRef2Index);
+ else if (index != vol.RootRef2Index && IsViDef(vol.RootRef2Index))
+ parentIndex = (UInt32)vol.RootRef2Index;
+ }
+
+ *parent = parentIndex;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
+{
+ *data = NULL;
+ *dataSize = 0;
+ *propType = 0;
+ UNUSED_VAR(index)
+ UNUSED_VAR(propID)
+ return S_OK;
+}
+
+
+static void Utf8Name_to_InterName(const AString &src, UString &dest)
+{
+ ConvertUTF8ToUnicode(src, dest);
+ NItemName::NormalizeSlashes_in_FileName_for_OsPath(dest);
+}
+
+
+static void AddNodeName(UString &s, const CNode &inode, UInt64 id)
+{
+ s += "node";
+ s.Add_UInt64(id);
+ if (!inode.PrimaryName.IsEmpty())
+ {
+ s.Add_Dot();
+ UString s2;
+ Utf8Name_to_InterName(inode.PrimaryName, s2);
+ s += s2;
+ }
+}
+
+
+void CDatabase::GetItemPath(unsigned index, const CNode *inode, NWindows::NCOM::CPropVariant &path) const
+{
+ const unsigned kNumLevelsMax = (1 << 10);
+ const unsigned kLenMax = (1 << 12);
+ UString s;
+ const CRef2 &ref2 = Refs2[index];
+ const CVol &vol = Vols[ref2.VolIndex];
+
+ if (IsViDef(ref2.RefIndex))
+ {
+ const CRef &ref = vol.Refs[ref2.RefIndex];
+ unsigned cur = ref.ItemIndex;
+ UString s2;
+ if (IsViNotDef(cur))
+ {
+ if (inode)
+ AddNodeName(s, *inode, vol.NodeIDs[ref.NodeIndex]);
+ }
+ else
+ {
+ for (unsigned i = 0;; i++)
+ {
+ if (i >= kNumLevelsMax || s.Len() > kLenMax)
+ {
+ s.Insert(0, UString("[LONG_PATH]"));
+ break;
+ }
+ const CItem &item = vol.Items[(unsigned)cur];
+ Utf8Name_to_InterName(item.Name, s2);
+ // s2 += "a\\b"; // for debug
+ s.Insert(0, s2);
+ cur = item.ParentItemIndex;
+ if (IsViNotDef(cur))
+ break;
+ // ParentItemIndex was not set for such items
+ // if (item.ParentId == ROOT_DIR_INO_NUM) break;
+ s.InsertAtFront(WCHAR_PATH_SEPARATOR);
+ }
+ }
+
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (IsViDef(ref.AttrIndex) && inode)
+ {
+ s += ':';
+ Utf8Name_to_InterName(inode->Attrs[(unsigned)ref.AttrIndex].Name, s2);
+ // s2 += "a\\b"; // for debug
+ s += s2;
+ }
+ #endif
+ }
+
+ if (!vol.RootName.IsEmpty())
+ {
+ if (IsViDef(ref2.RefIndex))
+ s.InsertAtFront(WCHAR_PATH_SEPARATOR);
+ s.Insert(0, vol.RootName);
+ }
+
+ path = s;
+}
+
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+
+ const CRef2 &ref2 = Refs2[index];
+ const CVol &vol = Vols[ref2.VolIndex];
+
+ if (IsViNotDef(ref2.RefIndex))
+ {
+ switch (propID)
+ {
+ case kpidName:
+ case kpidPath:
+ GetItemPath(index, NULL, prop);
+ break;
+ case kpidIsDir:
+ prop = true;
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ }
+
+ const CRef &ref = vol.Refs[ref2.RefIndex];
+
+ const CItem *item = NULL;
+ if (IsViDef(ref.ItemIndex))
+ item = &vol.Items[ref.ItemIndex];
+
+ const CNode *inode = NULL;
+ if (IsViDef(ref.NodeIndex))
+ inode = &vol.Nodes[ref.NodeIndex];
+
+ switch (propID)
+ {
+ case kpidPath:
+ GetItemPath(index, inode, prop);
+ break;
+ case kpidPrimeName:
+ {
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (!ref.IsAltStream())
+ #endif
+ if (inode && !inode->PrimaryName.IsEmpty())
+ {
+ UString s;
+ ConvertUTF8ToUnicode(inode->PrimaryName, s);
+ /*
+ // for debug:
+ if (inode.PrimaryName != item.Name) throw 123456;
+ */
+ prop = s;
+ }
+ break;
+ }
+
+ case kpidName:
+ {
+ UString s;
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (ref.IsAltStream())
+ {
+ // if (inode)
+ {
+ const CAttr &attr = inode->Attrs[(unsigned)ref.AttrIndex];
+ ConvertUTF8ToUnicode(attr.Name, s);
+ }
+ }
+ else
+ #endif
+ {
+ if (item)
+ ConvertUTF8ToUnicode(item->Name, s);
+ else if (inode)
+ AddNodeName(s, *inode, vol.NodeIDs[ref.NodeIndex]);
+ else
+ break;
+ }
+ // s += "s/1bs\\2"; // for debug:
+ prop = s;
+ break;
+ }
+
+ case kpidSymLink:
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (!ref.IsAltStream())
+ #endif
+ if (inode)
+ {
+ if (inode->IsSymLink() && IsViDef(inode->SymLinkIndex))
+ {
+ const CByteBuffer &buf = inode->Attrs[(unsigned)inode->SymLinkIndex].Data;
+ if (buf.Size() != 0)
+ {
+ AString s;
+ s.SetFrom_CalcLen((const char *)(const Byte *)buf, (unsigned)buf.Size());
+ if (s.Len() == buf.Size() - 1)
+ {
+ UString u;
+ ConvertUTF8ToUnicode(s, u);
+ prop = u;
+ }
+ }
+ }
+ }
+ break;
+
+ case kpidSize:
+ if (inode)
+ {
+ UInt64 size = 0;
+ if (inode->GetSize(ref.GetAttrIndex(), size) ||
+ !inode->IsDir())
+ prop = size;
+ }
+ break;
+
+ case kpidPackSize:
+ if (inode)
+ {
+ UInt64 size;
+ if (inode->GetPackSize(ref.GetAttrIndex(), size) ||
+ !inode->IsDir())
+ prop = size;
+ }
+ break;
+
+ case kpidMethod:
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (!ref.IsAltStream())
+ #endif
+ if (inode)
+ {
+ if (inode->CompressHeader.IsCorrect)
+ inode->CompressHeader.MethodToProp(prop);
+ else if (IsViDef(inode->DecmpfsIndex))
+ prop = "decmpfs";
+ else if (!inode->IsDir() && !inode->dstream_defined)
+ {
+ if (inode->IsSymLink())
+ {
+ if (IsViDef(inode->SymLinkIndex))
+ prop = "symlink";
+ }
+ // else prop = "no_dstream";
+ }
+ }
+ break;
+
+ /*
+ case kpidUncompressedSize:
+ if (inode && inode->Has_UNCOMPRESSED_SIZE())
+ prop = inode->uncompressed_size;
+ break;
+ */
+
+ case kpidIsDir:
+ {
+ bool isDir = false;
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (!ref.IsAltStream())
+ #endif
+ {
+ if (inode)
+ isDir = inode->IsDir();
+ else if (item)
+ isDir = item->Val.IsFlags_Dir();
+ }
+ prop = isDir;
+ break;
+ }
+
+ case kpidPosixAttrib:
+ {
+ if (inode)
+ {
+ UInt32 mode = inode->mode;
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (ref.IsAltStream())
+ {
+ mode &= 0666; // we disable execution
+ mode |= MY_LIN_S_IFREG;
+ }
+ #endif
+ prop = (UInt32)mode;
+ }
+ else if (item && !item->Val.IsFlags_Unknown())
+ prop = (UInt32)(item->Val.flags << 12);
+ break;
+ }
+
+ case kpidCTime: if (inode) ApfsTimeToProp(inode->create_time, prop); break;
+ case kpidMTime: if (inode) ApfsTimeToProp(inode->mod_time, prop); break;
+ case kpidATime: if (inode) ApfsTimeToProp(inode->access_time, prop); break;
+ case kpidChangeTime: if (inode) ApfsTimeToProp(inode->change_time, prop); break;
+ case kpidAddTime: if (item) ApfsTimeToProp(item->Val.date_added, prop); break;
+
+ case kpidBytesWritten:
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (!ref.IsAltStream())
+ #endif
+ if (inode && inode->dstream_defined)
+ prop = inode->dstream.total_bytes_written;
+ break;
+ case kpidBytesRead:
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (!ref.IsAltStream())
+ #endif
+ if (inode && inode->dstream_defined)
+ prop = inode->dstream.total_bytes_read;
+ break;
+
+ #ifdef APFS_SHOW_ALT_STREAMS
+ case kpidIsAltStream:
+ prop = ref.IsAltStream();
+ break;
+ #endif
+
+ case kpidCharacts:
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (!ref.IsAltStream())
+ #endif
+ if (inode)
+ {
+ FLAGS_TO_PROP(g_INODE_Flags, (UInt32)inode->internal_flags, prop);
+ }
+ break;
+
+ case kpidBsdFlags:
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (!ref.IsAltStream())
+ #endif
+ if (inode)
+ {
+ FLAGS_TO_PROP(g_INODE_BSD_Flags, inode->bsd_flags, prop);
+ }
+ break;
+
+ case kpidGeneration:
+ #ifdef APFS_SHOW_ALT_STREAMS
+ // if (!ref.IsAltStream())
+ #endif
+ if (inode)
+ prop = inode->write_generation_counter;
+ break;
+
+ case kpidUserId:
+ if (inode)
+ prop = (UInt32)inode->owner;
+ break;
+
+ case kpidGroupId:
+ if (inode)
+ prop = (UInt32)inode->group;
+ break;
+
+ case kpidLinks:
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (!ref.IsAltStream())
+ #endif
+ if (inode && !inode->IsDir())
+ prop = (UInt32)inode->nlink;
+ break;
+
+ case kpidINode:
+ #ifdef APFS_SHOW_ALT_STREAMS
+ // here we can disable iNode for alt stream.
+ if (!ref.IsAltStream())
+ #endif
+ if (IsViDef(ref.NodeIndex))
+ prop = (UInt32)vol.NodeIDs[ref.NodeIndex];
+ break;
+
+ case kpidParentINode:
+ #ifdef APFS_SHOW_ALT_STREAMS
+ if (!ref.IsAltStream())
+ #endif
+ if (inode)
+ prop = (UInt32)inode->parent_id;
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+UInt64 CDatabase::GetSize(const UInt32 index) const
+{
+ const CRef2 &ref2 = Refs2[index];
+ const CVol &vol = Vols[ref2.VolIndex];
+ if (IsViNotDef(ref2.RefIndex))
+ return 0;
+ const CRef &ref = vol.Refs[ref2.RefIndex];
+ if (IsViNotDef(ref.NodeIndex))
+ return 0;
+ const CNode &inode = vol.Nodes[ref.NodeIndex];
+ UInt64 size;
+ if (inode.GetSize(ref.GetAttrIndex(), size))
+ return size;
+ return 0;
+}
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = Refs2.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt32 i;
+
+ {
+ UInt64 totalSize = 0;
+ for (i = 0; i < numItems; i++)
+ {
+ const UInt32 index = allFilesMode ? i : indices[i];
+ totalSize += GetSize(index);
+ }
+ RINOK(extractCallback->SetTotal(totalSize))
+ }
+
+ UInt64 currentTotalSize = 0, currentItemSize = 0;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ NHfs::CDecoder decoder;
+
+ for (i = 0;; i++, currentTotalSize += currentItemSize)
+ {
+ lps->InSize = currentTotalSize;
+ lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur())
+
+ if (i >= numItems)
+ break;
+
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CRef2 &ref2 = Refs2[index];
+ const CVol &vol = Vols[ref2.VolIndex];
+
+ currentItemSize = GetSize(index);
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+ if (IsViNotDef(ref2.RefIndex))
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+
+ const CRef &ref = vol.Refs[ref2.RefIndex];
+ bool isDir = false;
+ if (IsViDef(ref.NodeIndex))
+ isDir = vol.Nodes[ref.NodeIndex].IsDir();
+ else if (IsViDef(ref.ItemIndex))
+ isDir =
+ #ifdef APFS_SHOW_ALT_STREAMS
+ !ref.IsAltStream() &&
+ #endif
+ vol.Items[ref.ItemIndex].Val.IsFlags_Dir();
+
+ if (isDir)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode))
+ int opRes = NExtract::NOperationResult::kDataError;
+
+ if (IsViDef(ref.NodeIndex))
+ {
+ const CNode &inode = vol.Nodes[ref.NodeIndex];
+ if (
+ #ifdef APFS_SHOW_ALT_STREAMS
+ !ref.IsAltStream() &&
+ #endif
+ !inode.dstream_defined
+ && inode.Extents.IsEmpty()
+ && inode.Has_UNCOMPRESSED_SIZE()
+ && inode.uncompressed_size == inode.CompressHeader.UnpackSize)
+ {
+ if (inode.CompressHeader.IsSupported)
+ {
+ CMyComPtr<ISequentialInStream> inStreamFork;
+ UInt64 forkSize = 0;
+ const CByteBuffer *decmpfs_Data = NULL;
+
+ if (inode.CompressHeader.IsMethod_Resource())
+ {
+ if (IsViDef(inode.ResourceIndex))
+ {
+ const CAttr &attr = inode.Attrs[inode.ResourceIndex];
+ forkSize = attr.GetSize();
+ GetAttrStream(_stream, vol, attr, &inStreamFork);
+ }
+ }
+ else
+ {
+ const CAttr &attr = inode.Attrs[inode.DecmpfsIndex];
+ decmpfs_Data = &attr.Data;
+ }
+
+ if (inStreamFork || decmpfs_Data)
+ {
+ const HRESULT hres = decoder.Extract(
+ inStreamFork, realOutStream,
+ forkSize,
+ inode.CompressHeader,
+ decmpfs_Data,
+ currentTotalSize, extractCallback,
+ opRes);
+ if (hres != S_FALSE && hres != S_OK)
+ return hres;
+ }
+ }
+ else
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ }
+ else
+ {
+ CMyComPtr<ISequentialInStream> inStream;
+ if (GetStream(index, &inStream) == S_OK && inStream)
+ {
+ COutStreamWithHash *hashStreamSpec = NULL;
+ CMyComPtr<ISequentialOutStream> hashStream;
+
+ if (vol.integrity.Is_SHA256())
+ {
+ const int hashIndex = FindHashIndex_for_Item(index);
+ if (hashIndex != -1)
+ {
+ hashStreamSpec = new COutStreamWithHash;
+ hashStream = hashStreamSpec;
+ hashStreamSpec->SetStream(realOutStream);
+ hashStreamSpec->Init(&(vol.Hash_Vectors[(unsigned)hashIndex]), sb.block_size_Log);
+ }
+ }
+
+ RINOK(copyCoder->Code(inStream,
+ hashStream ? hashStream : realOutStream, NULL, NULL, progress))
+ opRes = NExtract::NOperationResult::kDataError;
+ if (copyCoderSpec->TotalSize == currentItemSize)
+ {
+ opRes = NExtract::NOperationResult::kOK;
+ if (hashStream)
+ if (!hashStreamSpec->FinalCheck())
+ opRes = NExtract::NOperationResult::kCRCError;
+ }
+ else if (copyCoderSpec->TotalSize < currentItemSize)
+ opRes = NExtract::NOperationResult::kUnexpectedEnd;
+ }
+ }
+ }
+
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = Refs2.Size();
+ return S_OK;
+}
+
+
+int CHandler::FindHashIndex_for_Item(UInt32 index)
+{
+ const CRef2 &ref2 = Refs2[index];
+ const CVol &vol = Vols[ref2.VolIndex];
+ if (IsViNotDef(ref2.RefIndex))
+ return -1;
+
+ const CRef &ref = vol.Refs[ref2.RefIndex];
+ if (IsViNotDef(ref.NodeIndex))
+ return -1;
+ const CNode &inode = vol.Nodes[ref.NodeIndex];
+
+ unsigned attrIndex = ref.GetAttrIndex();
+
+ if (IsViNotDef(attrIndex)
+ && !inode.dstream_defined
+ && inode.IsSymLink())
+ {
+ attrIndex = inode.SymLinkIndex;
+ if (IsViNotDef(attrIndex))
+ return -1;
+ }
+
+ if (IsViDef(attrIndex))
+ {
+ /* we have seen examples, where hash available for "com.apple.ResourceFork" stream.
+ these hashes for "com.apple.ResourceFork" stream are for unpacked data.
+ but the caller here needs packed data of stream. So we don't use hashes */
+ return -1;
+ }
+ else
+ {
+ if (!inode.dstream_defined)
+ return -1;
+ const UInt64 id = vol.NodeIDs[ref.NodeIndex];
+ return vol.Hash_IDs.FindInSorted(id);
+ }
+}
+
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ *stream = NULL;
+
+ const CRef2 &ref2 = Refs2[index];
+ const CVol &vol = Vols[ref2.VolIndex];
+ if (IsViNotDef(ref2.RefIndex))
+ return S_FALSE;
+
+ const CRef &ref = vol.Refs[ref2.RefIndex];
+ if (IsViNotDef(ref.NodeIndex))
+ return S_FALSE;
+ const CNode &inode = vol.Nodes[ref.NodeIndex];
+
+ const CRecordVector<CExtent> *extents;
+ UInt64 rem = 0;
+
+ unsigned attrIndex = ref.GetAttrIndex();
+
+ if (IsViNotDef(attrIndex)
+ && !inode.dstream_defined
+ && inode.IsSymLink())
+ {
+ attrIndex = inode.SymLinkIndex;
+ if (IsViNotDef(attrIndex))
+ return S_FALSE;
+ }
+
+ if (IsViDef(attrIndex))
+ {
+ const CAttr &attr = inode.Attrs[(unsigned)attrIndex];
+ if (!attr.dstream_defined)
+ {
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->Init(attr.Data, attr.Data.Size(), (IInArchive *)this);
+ *stream = streamTemp.Detach();
+ return S_OK;
+ }
+ const int idIndex = vol.SmallNodeIDs.FindInSorted(attr.Id);
+ if (idIndex != -1)
+ extents = &vol.SmallNodes[(unsigned)idIndex].Extents;
+ else
+ {
+ const int fext_Index = vol.FEXT_NodeIDs.FindInSorted(attr.Id);
+ if (fext_Index == -1)
+ return S_FALSE;
+ extents = &vol.FEXT_Nodes[(unsigned)fext_Index].Extents;
+ }
+ rem = attr.dstream.size;
+ }
+ else
+ {
+ if (IsViDef(ref.ItemIndex))
+ if (vol.Items[ref.ItemIndex].Val.IsFlags_Dir())
+ return S_FALSE;
+ if (inode.IsDir())
+ return S_FALSE;
+ extents = &inode.Extents;
+ if (inode.dstream_defined)
+ {
+ rem = inode.dstream.size;
+ if (inode.Extents.Size() == 0)
+ {
+ const int fext_Index = vol.FEXT_NodeIDs.FindInSorted(vol.NodeIDs[ref.NodeIndex]);
+ if (fext_Index != -1)
+ extents = &vol.FEXT_Nodes[(unsigned)fext_Index].Extents;
+ }
+ }
+ else
+ {
+ // return S_FALSE; // check it !!! How zero size files are stored with dstream_defined?
+ }
+ }
+ return GetStream2(_stream, extents, rem, stream);
+}
+
+
+
+HRESULT CDatabase::GetAttrStream(IInStream *apfsInStream, const CVol &vol,
+ const CAttr &attr, ISequentialInStream **stream)
+{
+ *stream = NULL;
+ if (!attr.dstream_defined)
+ {
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->Init(attr.Data, attr.Data.Size(), (IInArchive *)this);
+ *stream = streamTemp.Detach();
+ return S_OK;
+ }
+ return GetAttrStream_dstream(apfsInStream, vol, attr, stream);
+}
+
+
+HRESULT CDatabase::GetAttrStream_dstream( IInStream *apfsInStream, const CVol &vol,
+ const CAttr &attr, ISequentialInStream **stream)
+{
+ const CRecordVector<CExtent> *extents;
+ {
+ const int idIndex = vol.SmallNodeIDs.FindInSorted(attr.Id);
+ if (idIndex != -1)
+ extents = &vol.SmallNodes[(unsigned)idIndex].Extents;
+ else
+ {
+ const int fext_Index = vol.FEXT_NodeIDs.FindInSorted(attr.Id);
+ if (fext_Index == -1)
+ return S_FALSE;
+ extents = &vol.FEXT_Nodes[(unsigned)fext_Index].Extents;
+ }
+ }
+ return GetStream2(apfsInStream, extents, attr.dstream.size, stream);
+}
+
+
+HRESULT CDatabase::GetStream2(
+ IInStream *apfsInStream,
+ const CRecordVector<CExtent> *extents, UInt64 rem,
+ ISequentialInStream **stream)
+{
+ CExtentsStream *extentStreamSpec = new CExtentsStream();
+ CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec;
+
+ UInt64 virt = 0;
+ FOR_VECTOR (i, *extents)
+ {
+ const CExtent &e = (*extents)[i];
+ if (virt != e.logical_offset)
+ return S_FALSE;
+ const UInt64 len = EXTENT_GET_LEN(e.len_and_flags);
+ if (len == 0)
+ {
+ return S_FALSE;
+ // continue;
+ }
+ if (rem == 0)
+ return S_FALSE;
+ UInt64 cur = len;
+ if (cur > rem)
+ cur = rem;
+ CSeekExtent se;
+ se.Phy = (UInt64)e.phys_block_num << sb.block_size_Log;
+ se.Virt = virt;
+ virt += cur;
+ rem -= cur;
+ extentStreamSpec->Extents.Add(se);
+ if (rem == 0)
+ if (i != extents->Size() - 1)
+ return S_FALSE;
+ }
+
+ if (rem != 0)
+ return S_FALSE;
+
+ CSeekExtent se;
+ se.Phy = 0;
+ se.Virt = virt;
+ extentStreamSpec->Extents.Add(se);
+ extentStreamSpec->Stream = apfsInStream;
+ extentStreamSpec->Init();
+ *stream = extentStream.Detach();
+ return S_OK;
+}
+
+
+REGISTER_ARC_I(
+ "APFS", "apfs img", NULL, 0xc3,
+ k_Signature,
+ k_SignatureOffset,
+ 0,
+ IsArc_APFS)
+
+}}
diff --git a/CPP/7zip/Archive/ApmHandler.cpp b/CPP/7zip/Archive/ApmHandler.cpp
new file mode 100644
index 0000000..6770301
--- /dev/null
+++ b/CPP/7zip/Archive/ApmHandler.cpp
@@ -0,0 +1,314 @@
+// ApmHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/Defs.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "HandlerCont.h"
+
+#define Get16(p) GetBe16(p)
+#define Get32(p) GetBe32(p)
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NApm {
+
+static const Byte kSig0 = 'E';
+static const Byte kSig1 = 'R';
+
+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)
+ {
+ numBlocksInMap = Get32(p + 4);
+ StartBlock = Get32(p + 8);
+ NumBlocks = Get32(p + 0xC);
+ memcpy(Name, p + 0x10, 32);
+ memcpy(Type, p + 0x30, 32);
+ if (p[0] != 0x50 || p[1] != 0x4D || p[2] != 0 || p[3] != 0)
+ return false;
+ /*
+ 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;
+ }
+};
+
+Z7_class_CHandler_final: public CHandlerCont
+{
+ Z7_IFACE_COM7_IMP(IInArchive_Cont)
+
+ CRecordVector<CItem> _items;
+ unsigned _blockSizeLog;
+ UInt32 _numBlocks;
+ UInt64 _phySize;
+ bool _isArc;
+
+ HRESULT ReadTables(IInStream *stream);
+ UInt64 BlocksToBytes(UInt32 i) const { return (UInt64)i << _blockSizeLog; }
+
+ virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override
+ {
+ const CItem &item = _items[index];
+ pos = BlocksToBytes(item.StartBlock);
+ size = BlocksToBytes(item.NumBlocks);
+ return NExtract::NOperationResult::kOK;
+ }
+};
+
+static const UInt32 kSectorSize = 512;
+
+API_FUNC_static_IsArc IsArc_Apm(const Byte *p, size_t size)
+{
+ if (size < kSectorSize)
+ return k_IsArc_Res_NEED_MORE;
+ if (p[0] != kSig0 || p[1] != kSig1)
+ return k_IsArc_Res_NO;
+ unsigned i;
+ for (i = 8; i < 16; i++)
+ if (p[i] != 0)
+ return k_IsArc_Res_NO;
+ UInt32 blockSize = Get16(p + 2);
+ for (i = 9; ((UInt32)1 << i) != blockSize; i++)
+ if (i >= 12)
+ return k_IsArc_Res_NO;
+ return k_IsArc_Res_YES;
+}
+}
+
+HRESULT CHandler::ReadTables(IInStream *stream)
+{
+ Byte buf[kSectorSize];
+ {
+ RINOK(ReadStream_FALSE(stream, buf, kSectorSize))
+ if (buf[0] != kSig0 || buf[1] != kSig1)
+ return S_FALSE;
+ UInt32 blockSize = Get16(buf + 2);
+ unsigned i;
+ for (i = 9; ((UInt32)1 << i) != blockSize; i++)
+ if (i >= 12)
+ return S_FALSE;
+ _blockSizeLog = i;
+ _numBlocks = Get32(buf + 4);
+ for (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 = 0;
+ 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;
+ }
+
+ _phySize = BlocksToBytes(_numBlocks);
+ _isArc = true;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */))
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(ReadTables(stream))
+ _stream = stream;
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _isArc = false;
+ _phySize = 0;
+ _items.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidOffset
+};
+
+static const Byte kArcProps[] =
+{
+ kpidClusterSize
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static AString GetString(const char *s)
+{
+ AString res;
+ for (unsigned i = 0; i < 32 && s[i] != 0; i++)
+ res += s[i];
+ return res;
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidMainSubfile:
+ {
+ int mainIndex = -1;
+ FOR_VECTOR (i, _items)
+ {
+ AString s (GetString(_items[i].Type));
+ if (s != "Apple_Free" &&
+ s != "Apple_partition_map")
+ {
+ if (mainIndex >= 0)
+ {
+ mainIndex = -1;
+ break;
+ }
+ mainIndex = (int)i;
+ }
+ }
+ if (mainIndex >= 0)
+ prop = (UInt32)(Int32)mainIndex;
+ break;
+ }
+ case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break;
+ case kpidPhySize: prop = _phySize; break;
+
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
+ prop = v;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(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())
+ s.Add_UInt32(index);
+ AString type (GetString(item.Type));
+ if (type == "Apple_HFS")
+ type = "hfs";
+ if (!type.IsEmpty())
+ {
+ s.Add_Dot();
+ s += type;
+ }
+ prop = s;
+ break;
+ }
+ case kpidSize:
+ case kpidPackSize:
+ prop = BlocksToBytes(item.NumBlocks);
+ break;
+ case kpidOffset: prop = BlocksToBytes(item.StartBlock); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+static const Byte k_Signature[] = { kSig0, kSig1 };
+
+REGISTER_ARC_I(
+ "APM", "apm", NULL, 0xD4,
+ k_Signature,
+ 0,
+ 0,
+ IsArc_Apm)
+
+}}
diff --git a/CPP/7zip/Archive/ArHandler.cpp b/CPP/7zip/Archive/ArHandler.cpp
new file mode 100644
index 0000000..07ecec6
--- /dev/null
+++ b/CPP/7zip/Archive/ArHandler.cpp
@@ -0,0 +1,843 @@
+// ArHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/StringConvert.h"
+#include "../../Common/StringToInt.h"
+
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/TimeUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "Common/ItemNameUtils.h"
+
+using namespace NWindows;
+using namespace NTime;
+
+namespace NArchive {
+namespace NAr {
+
+/*
+The end of each file member (including last file in archive) is 2-bytes aligned.
+It uses 0xA padding if required.
+
+File Names:
+
+GNU/SVR4 variant (.a static library):
+ / - archive symbol table
+ // - the list of the long filenames, separated by one or more LF characters.
+ /N - the reference to name string in long filenames list
+ name/ - the name
+
+Microsoft variant (.lib static library):
+ / - First linker file (archive symbol table)
+ / - Second linker file
+ // - the list of the long filenames, null-terminated. Each string begins
+ immediately after the null byte in the previous string.
+ /N - the reference to name string in long filenames list
+ name/ - the name
+
+BSD (Mac OS X) variant:
+ "__.SYMDEF" - archive symbol table
+ or
+ "__.SYMDEF SORTED" - archive symbol table
+ #1/N - the real filename of length N is appended to the file header.
+*/
+
+static const unsigned kSignatureLen = 8;
+static const Byte kSignature[kSignatureLen] =
+ { '!', '<', 'a', 'r', 'c', 'h', '>', 0x0A };
+
+static const unsigned kNameSize = 16;
+static const unsigned kTimeSize = 12;
+static const unsigned kUserSize = 6;
+static const unsigned kModeSize = 8;
+static const unsigned kSizeSize = 10;
+
+static const unsigned kHeaderSize = kNameSize + kTimeSize + kUserSize * 2 + kModeSize + kSizeSize + 1 + 1;
+
+enum EType
+{
+ kType_Ar,
+ kType_ALib,
+ kType_Deb,
+ kType_Lib
+};
+
+static const char * const k_TypeExtionsions[] =
+{
+ "ar"
+ , "a"
+ , "deb"
+ , "lib"
+};
+
+enum ESubType
+{
+ kSubType_None,
+ kSubType_BSD
+};
+
+/*
+struct CHeader
+{
+ char Name[kNameSize];
+ char MTime[kTimeSize];
+ char User[kUserSize];
+ char Group[kUserSize];
+ char Mode[kModeSize];
+ char Size[kSizeSize];
+ char Quote;
+ char NewLine;
+};
+*/
+
+struct CItem
+{
+ AString Name;
+ UInt64 Size;
+ UInt32 MTime;
+ UInt32 User;
+ UInt32 Group;
+ UInt32 Mode;
+
+ UInt64 HeaderPos;
+ UInt64 HeaderSize;
+
+ int TextFileIndex;
+ int SameNameIndex;
+
+ CItem(): TextFileIndex(-1), SameNameIndex(-1) {}
+ UInt64 GetDataPos() const { return HeaderPos + HeaderSize; }
+};
+
+class CInArchive
+{
+ CMyComPtr<IInStream> m_Stream;
+
+public:
+ UInt64 Position;
+ ESubType SubType;
+
+ HRESULT GetNextItem(CItem &itemInfo, bool &filled);
+ HRESULT Open(IInStream *inStream);
+ HRESULT SkipData(UInt64 dataSize)
+ {
+ return m_Stream->Seek((Int64)(dataSize + (dataSize & 1)), STREAM_SEEK_CUR, &Position);
+ }
+};
+
+HRESULT CInArchive::Open(IInStream *inStream)
+{
+ SubType = kSubType_None;
+ RINOK(InStream_GetPos(inStream, Position))
+ char signature[kSignatureLen];
+ RINOK(ReadStream_FALSE(inStream, signature, kSignatureLen))
+ Position += kSignatureLen;
+ if (memcmp(signature, kSignature, kSignatureLen) != 0)
+ return S_FALSE;
+ m_Stream = inStream;
+ return S_OK;
+}
+
+static unsigned RemoveTailSpaces(char *dest, const char *s, unsigned size)
+{
+ memcpy(dest, s, size);
+ for (; size != 0; size--)
+ {
+ if (dest[size - 1] != ' ')
+ break;
+ }
+ dest[size] = 0;
+ return size;
+}
+
+static bool OctalToNumber32(const char *s, unsigned size, UInt32 &res)
+{
+ res = 0;
+ char sz[32];
+ size = RemoveTailSpaces(sz, s, size);
+ if (size == 0 || strcmp(sz, "-1") == 0)
+ return true; // some items don't contain any numbers
+ const char *end;
+ UInt64 res64 = ConvertOctStringToUInt64(sz, &end);
+ if ((unsigned)(end - sz) != size)
+ return false;
+ res = (UInt32)res64;
+ return (res64 <= 0xFFFFFFFF);
+}
+
+static bool DecimalToNumber(const char *s, unsigned size, UInt64 &res)
+{
+ res = 0;
+ char sz[32];
+ size = RemoveTailSpaces(sz, s, size);
+ if (size == 0 || strcmp(sz, "-1") == 0)
+ return true; // some items don't contain any numbers
+ const char *end;
+ res = ConvertStringToUInt64(sz, &end);
+ return ((unsigned)(end - sz) == size);
+}
+
+static bool DecimalToNumber32(const char *s, unsigned size, UInt32 &res)
+{
+ UInt64 res64;
+ if (!DecimalToNumber(s, size, res64))
+ return false;
+ res = (UInt32)res64;
+ return (res64 <= 0xFFFFFFFF);
+}
+
+#define RIF(x) { if (!(x)) return S_FALSE; }
+
+
+HRESULT CInArchive::GetNextItem(CItem &item, bool &filled)
+{
+ filled = false;
+
+ char header[kHeaderSize];
+ const char *cur = header;
+
+ {
+ size_t processedSize = sizeof(header);
+ item.HeaderPos = Position;
+ item.HeaderSize = kHeaderSize;
+ RINOK(ReadStream(m_Stream, header, &processedSize))
+ if (processedSize != sizeof(header))
+ return S_OK;
+ if (header[kHeaderSize - 2] != 0x60 ||
+ header[kHeaderSize - 1] != 0x0A)
+ return S_OK;
+ for (unsigned i = 0; i < kHeaderSize - 2; i++)
+ // if (header[i] < 0x20)
+ if (header[i] == 0)
+ return S_OK;
+ Position += processedSize;
+ }
+
+ UInt32 longNameLen = 0;
+ if (cur[0] == '#' &&
+ cur[1] == '1' &&
+ cur[2] == '/' &&
+ cur[3] != 0)
+ {
+ // BSD variant
+ RIF(DecimalToNumber32(cur + 3, kNameSize - 3 , longNameLen))
+ if (longNameLen >= (1 << 12))
+ longNameLen = 0;
+ }
+ else
+ {
+ char tempString[kNameSize + 1];
+ RemoveTailSpaces(tempString, cur, kNameSize);
+ item.Name = tempString;
+ }
+ cur += kNameSize;
+
+ RIF(DecimalToNumber32(cur, kTimeSize, item.MTime)) cur += kTimeSize;
+ RIF(DecimalToNumber32(cur, kUserSize, item.User)) cur += kUserSize;
+ RIF(DecimalToNumber32(cur, kUserSize, item.Group)) cur += kUserSize;
+ RIF(OctalToNumber32(cur, kModeSize, item.Mode)) cur += kModeSize;
+ RIF(DecimalToNumber(cur, kSizeSize, item.Size)) cur += kSizeSize;
+
+ if (longNameLen != 0 && longNameLen <= item.Size)
+ {
+ SubType = kSubType_BSD;
+ size_t processedSize = longNameLen;
+ char *s = item.Name.GetBuf(longNameLen);
+ HRESULT res = ReadStream(m_Stream, s, &processedSize);
+ item.Name.ReleaseBuf_CalcLen(longNameLen);
+ RINOK(res)
+ if (processedSize != longNameLen)
+ return S_OK;
+ item.Size -= longNameLen;
+ item.HeaderSize += longNameLen;
+ Position += processedSize;
+ }
+
+ filled = true;
+ return S_OK;
+}
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IInArchiveGetStream
+)
+ CObjectVector<CItem> _items;
+ CMyComPtr<IInStream> _stream;
+ Int32 _mainSubfile;
+ UInt64 _phySize;
+
+ EType _type;
+ ESubType _subType;
+ int _longNames_FileIndex;
+ AString _libFiles[2];
+ unsigned _numLibFiles;
+ AString _errorMessage;
+ bool _isArc;
+
+ void UpdateErrorMessage(const char *s);
+
+ HRESULT ParseLongNames(IInStream *stream);
+ void ChangeDuplicateNames();
+ int FindItem(UInt32 offset) const;
+ HRESULT AddFunc(UInt32 offset, const Byte *data, size_t size, size_t &pos);
+ HRESULT ParseLibSymbols(IInStream *stream, unsigned fileIndex);
+};
+
+void CHandler::UpdateErrorMessage(const char *s)
+{
+ if (!_errorMessage.IsEmpty())
+ _errorMessage += '\n';
+ _errorMessage += s;
+}
+
+static const Byte kArcProps[] =
+{
+ kpidSubType
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidMTime,
+ kpidPosixAttrib,
+ kpidUserId,
+ kpidGroupId
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+HRESULT CHandler::ParseLongNames(IInStream *stream)
+{
+ unsigned i;
+ for (i = 0; i < _items.Size(); i++)
+ if (_items[i].Name == "//")
+ break;
+ if (i == _items.Size())
+ return S_OK;
+
+ unsigned fileIndex = i;
+ const CItem &item = _items[fileIndex];
+ if (item.Size > ((UInt32)1 << 30))
+ return S_FALSE;
+ RINOK(InStream_SeekSet(stream, item.GetDataPos()))
+ const size_t size = (size_t)item.Size;
+
+ CByteArr p(size);
+ RINOK(ReadStream_FALSE(stream, p, size))
+
+ for (i = 0; i < _items.Size(); i++)
+ {
+ CItem &item2 = _items[i];
+ if (item2.Name[0] != '/')
+ continue;
+ const char *ptr = item2.Name.Ptr(1);
+ const char *end;
+ UInt32 pos = ConvertStringToUInt32(ptr, &end);
+ if (*end != 0 || end == ptr)
+ continue;
+ if (pos >= size)
+ continue;
+ UInt32 start = pos;
+ for (;;)
+ {
+ if (pos >= size)
+ return S_FALSE;
+ const Byte c = p[pos];
+ if (c == 0 || c == 0x0A)
+ break;
+ pos++;
+ }
+ item2.Name.SetFrom((const char *)(p + start), (unsigned)(pos - start));
+ }
+
+ _longNames_FileIndex = (int)fileIndex;
+ return S_OK;
+}
+
+void CHandler::ChangeDuplicateNames()
+{
+ unsigned i;
+ for (i = 1; i < _items.Size(); i++)
+ {
+ CItem &item = _items[i];
+ if (item.Name[0] == '/')
+ continue;
+ CItem &prev = _items[i - 1];
+ if (item.Name == prev.Name)
+ {
+ if (prev.SameNameIndex < 0)
+ prev.SameNameIndex = 0;
+ item.SameNameIndex = prev.SameNameIndex + 1;
+ }
+ }
+ for (i = 0; i < _items.Size(); i++)
+ {
+ CItem &item = _items[i];
+ if (item.SameNameIndex < 0)
+ continue;
+ char sz[32];
+ ConvertUInt32ToString((unsigned)item.SameNameIndex + 1, sz);
+ unsigned len = MyStringLen(sz);
+ sz[len++] = '.';
+ sz[len] = 0;
+ item.Name.Insert(0, sz);
+ }
+}
+
+int CHandler::FindItem(UInt32 offset) const
+{
+ unsigned left = 0, right = _items.Size();
+ while (left != right)
+ {
+ const unsigned mid = (left + right) / 2;
+ const UInt64 midVal = _items[mid].HeaderPos;
+ if (offset == midVal)
+ return (int)mid;
+ if (offset < midVal)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+}
+
+HRESULT CHandler::AddFunc(UInt32 offset, const Byte *data, size_t size, size_t &pos)
+{
+ const int fileIndex = FindItem(offset);
+ if (fileIndex < (int)0)
+ return S_FALSE;
+
+ size_t i = pos;
+ do
+ {
+ if (i >= size)
+ return S_FALSE;
+ }
+ while (data[i++] != 0);
+
+ AString &s = _libFiles[_numLibFiles];
+ const AString &name = _items[(unsigned)fileIndex].Name;
+ s += name;
+ if (!name.IsEmpty() && name.Back() == '/')
+ s.DeleteBack();
+ s += " ";
+ s += (const char *)(data + pos);
+ s += (char)0xD;
+ s += (char)0xA;
+ pos = i;
+ return S_OK;
+}
+
+static UInt32 Get32(const Byte *p, unsigned be) { if (be) return GetBe32(p); return GetUi32(p); }
+
+HRESULT CHandler::ParseLibSymbols(IInStream *stream, unsigned fileIndex)
+{
+ CItem &item = _items[fileIndex];
+ if (item.Name != "/" &&
+ item.Name != "__.SYMDEF" &&
+ item.Name != "__.SYMDEF SORTED")
+ return S_OK;
+ if (item.Size > ((UInt32)1 << 30) ||
+ item.Size < 4)
+ return S_OK;
+ RINOK(InStream_SeekSet(stream, item.GetDataPos()))
+ size_t size = (size_t)item.Size;
+ CByteArr p(size);
+ RINOK(ReadStream_FALSE(stream, p, size))
+
+ size_t pos = 0;
+
+ if (item.Name != "/")
+ {
+ // "__.SYMDEF" parsing (BSD)
+ unsigned be;
+ for (be = 0; be < 2; be++)
+ {
+ const UInt32 tableSize = Get32(p, be);
+ pos = 4;
+ if (size - pos < tableSize || (tableSize & 7) != 0)
+ continue;
+ size_t namesStart = pos + tableSize;
+ const UInt32 namesSize = Get32(p + namesStart, be);
+ namesStart += 4;
+ if (namesStart > size || namesStart + namesSize != size)
+ continue;
+
+ const UInt32 numSymbols = tableSize >> 3;
+ UInt32 i;
+ for (i = 0; i < numSymbols; i++, pos += 8)
+ {
+ size_t namePos = Get32(p + pos, be);
+ const UInt32 offset = Get32(p + pos + 4, be);
+ if (AddFunc(offset, p + namesStart, namesSize, namePos) != S_OK)
+ break;
+ }
+ if (i == numSymbols)
+ {
+ pos = size;
+ _type = kType_ALib;
+ _subType = kSubType_BSD;
+ break;
+ }
+ }
+ if (be == 2)
+ return S_FALSE;
+ }
+ else if (_numLibFiles == 0)
+ {
+ // archive symbol table (GNU)
+ const UInt32 numSymbols = GetBe32(p);
+ pos = 4;
+ if (numSymbols > (size - pos) / 4)
+ return S_FALSE;
+ pos += 4 * numSymbols;
+
+ for (UInt32 i = 0; i < numSymbols; i++)
+ {
+ const UInt32 offset = GetBe32(p + 4 + i * 4);
+ RINOK(AddFunc(offset, p, size, pos))
+ }
+ _type = kType_ALib;
+ }
+ else
+ {
+ // Second linker file (Microsoft .lib)
+ const UInt32 numMembers = GetUi32(p);
+ pos = 4;
+ if (numMembers > (size - pos) / 4)
+ return S_FALSE;
+ pos += 4 * numMembers;
+
+ if (size - pos < 4)
+ return S_FALSE;
+ const UInt32 numSymbols = GetUi32(p + pos);
+ pos += 4;
+ if (numSymbols > (size - pos) / 2)
+ return S_FALSE;
+ size_t indexStart = pos;
+ pos += 2 * numSymbols;
+
+ for (UInt32 i = 0; i < numSymbols; i++)
+ {
+ // index is 1-based. So 32-bit numSymbols field works as item[0]
+ const UInt32 index = GetUi16(p + indexStart + i * 2);
+ if (index == 0 || index > numMembers)
+ return S_FALSE;
+ const UInt32 offset = GetUi32(p + index * 4);
+ RINOK(AddFunc(offset, p, size, pos))
+ }
+ _type = kType_Lib;
+ }
+ // size can be 2-byte aligned in linux files
+ if (pos != size && pos + (pos & 1) != size)
+ return S_FALSE;
+ item.TextFileIndex = (int)(_numLibFiles++);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+
+ UInt64 fileSize;
+ RINOK(InStream_AtBegin_GetSize(stream, fileSize))
+
+ CInArchive arc;
+ RINOK(arc.Open(stream))
+
+ if (callback)
+ {
+ RINOK(callback->SetTotal(NULL, &fileSize))
+ const UInt64 numFiles = _items.Size();
+ RINOK(callback->SetCompleted(&numFiles, &arc.Position))
+ }
+
+ CItem item;
+ for (;;)
+ {
+ bool filled;
+ RINOK(arc.GetNextItem(item, filled))
+ if (!filled)
+ break;
+ _items.Add(item);
+ arc.SkipData(item.Size);
+ if (callback && (_items.Size() & 0xFF) == 0)
+ {
+ UInt64 numFiles = _items.Size();
+ RINOK(callback->SetCompleted(&numFiles, &arc.Position))
+ }
+ }
+
+ if (_items.IsEmpty())
+ {
+ // we don't need false empty archives (8-bytes signature only)
+ if (arc.Position != fileSize)
+ return S_FALSE;
+ }
+
+ _isArc = true;
+
+ _subType = arc.SubType;
+
+ if (ParseLongNames(stream) != S_OK)
+ UpdateErrorMessage("Long file names parsing error");
+ if (_longNames_FileIndex >= 0)
+ _items.Delete((unsigned)_longNames_FileIndex);
+
+ if (!_items.IsEmpty() && _items[0].Name == "debian-binary")
+ {
+ _type = kType_Deb;
+ _items.DeleteFrontal(1);
+ for (unsigned i = 0; i < _items.Size(); i++)
+ if (_items[i].Name.IsPrefixedBy("data.tar."))
+ {
+ if (_mainSubfile < 0)
+ _mainSubfile = (int)i;
+ else
+ {
+ _mainSubfile = -1;
+ break;
+ }
+ }
+ }
+ else
+ {
+ ChangeDuplicateNames();
+ bool error = false;
+ for (unsigned li = 0; li < 2 && li < _items.Size(); li++)
+ if (ParseLibSymbols(stream, li) != S_OK)
+ error = true;
+ if (error)
+ UpdateErrorMessage("Library symbols information error");
+ }
+
+ _stream = stream;
+ _phySize = arc.Position;
+
+ /*
+ if (fileSize < _phySize)
+ UpdateErrorMessage("Unexpected end of archive");
+ */
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _isArc = false;
+ _phySize = 0;
+
+ _errorMessage.Empty();
+ _stream.Release();
+ _items.Clear();
+
+ _type = kType_Ar;
+ _subType = kSubType_None;
+ _mainSubfile = -1;
+ _longNames_FileIndex = -1;
+
+ _numLibFiles = 0;
+ _libFiles[0].Empty();
+ _libFiles[1].Empty();
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySize: prop = _phySize; break;
+ case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
+ case kpidExtension: prop = k_TypeExtionsions[(unsigned)_type]; break;
+ case kpidShortComment:
+ case kpidSubType:
+ {
+ AString s (k_TypeExtionsions[(unsigned)_type]);
+ if (_subType == kSubType_BSD)
+ s += ":BSD";
+ prop = s;
+ break;
+ }
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
+ prop = v;
+ break;
+ }
+ case kpidWarning: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
+ case kpidIsNotArcType: if (_type != kType_Deb) prop = true; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
+ switch (propID)
+ {
+ case kpidPath:
+ if (item.TextFileIndex >= 0)
+ prop = (item.TextFileIndex == 0) ? "1.txt" : "2.txt";
+ else
+ prop = (const wchar_t *)NItemName::GetOsPath_Remove_TailSlash(MultiByteToUnicodeString(item.Name, CP_OEMCP));
+ break;
+ case kpidSize:
+ case kpidPackSize:
+ if (item.TextFileIndex >= 0)
+ prop = (UInt64)_libFiles[(unsigned)item.TextFileIndex].Len();
+ else
+ prop = item.Size;
+ break;
+ case kpidMTime:
+ {
+ if (item.MTime != 0)
+ PropVariant_SetFrom_UnixTime(prop, item.MTime);
+ break;
+ }
+ case kpidUserId: if (item.User != 0) prop = item.User; break;
+ case kpidGroupId: if (item.Group != 0) prop = item.Group; break;
+ case kpidPosixAttrib:
+ if (item.TextFileIndex < 0)
+ prop = item.Mode;
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItem &item = _items[allFilesMode ? i : indices[i]];
+ totalSize +=
+ (item.TextFileIndex >= 0) ?
+ (UInt64)_libFiles[(unsigned)item.TextFileIndex].Len() : item.Size;
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur())
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _items[index];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+ currentTotalSize += (item.TextFileIndex >= 0) ?
+ (UInt64)_libFiles[(unsigned)item.TextFileIndex].Len() : item.Size;
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode))
+ if (testMode)
+ {
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+ bool isOk = true;
+ if (item.TextFileIndex >= 0)
+ {
+ const AString &f = _libFiles[(unsigned)item.TextFileIndex];
+ if (realOutStream)
+ RINOK(WriteStream(realOutStream, f, f.Len()))
+ }
+ else
+ {
+ RINOK(InStream_SeekSet(_stream, item.GetDataPos()))
+ streamSpec->Init(item.Size);
+ RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress))
+ isOk = (copyCoderSpec->TotalSize == item.Size);
+ }
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(isOk ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ const CItem &item = _items[index];
+ if (item.TextFileIndex >= 0)
+ {
+ const AString &f = _libFiles[(unsigned)item.TextFileIndex];
+ Create_BufInStream_WithNewBuffer((const void *)(const char *)f, f.Len(), stream);
+ return S_OK;
+ }
+ else
+ return CreateLimitedInStream(_stream, item.GetDataPos(), item.Size, stream);
+ COM_TRY_END
+}
+
+REGISTER_ARC_I(
+ "Ar", "ar a deb udeb lib", NULL, 0xEC,
+ kSignature,
+ 0,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/Archive.def b/CPP/7zip/Archive/Archive.def
index a3fe6dd..2ed6246 100644
--- a/CPP/7zip/Archive/Archive.def
+++ b/CPP/7zip/Archive/Archive.def
@@ -1,12 +1,14 @@
-EXPORTS
- CreateObject PRIVATE
-
- GetHandlerProperty PRIVATE
- GetNumberOfFormats PRIVATE
- GetHandlerProperty2 PRIVATE
- GetIsArc PRIVATE
-
- SetCodecs PRIVATE
-
- SetLargePageMode PRIVATE
- SetCaseSensitive PRIVATE
+EXPORTS
+ CreateObject PRIVATE
+
+ GetHandlerProperty PRIVATE
+ GetNumberOfFormats PRIVATE
+ GetHandlerProperty2 PRIVATE
+ GetIsArc PRIVATE
+
+ SetCodecs PRIVATE
+
+ SetLargePageMode PRIVATE
+ SetCaseSensitive PRIVATE
+
+ GetModuleProp PRIVATE
diff --git a/CPP/7zip/Archive/Archive2.def b/CPP/7zip/Archive/Archive2.def
index de744b5..f891ad3 100644
--- a/CPP/7zip/Archive/Archive2.def
+++ b/CPP/7zip/Archive/Archive2.def
@@ -1,19 +1,21 @@
-EXPORTS
- CreateObject PRIVATE
-
- GetHandlerProperty PRIVATE
- GetNumberOfFormats PRIVATE
- GetHandlerProperty2 PRIVATE
- GetIsArc PRIVATE
-
- GetNumberOfMethods PRIVATE
- GetMethodProperty PRIVATE
- CreateDecoder PRIVATE
- CreateEncoder PRIVATE
-
- GetHashers PRIVATE
-
- SetCodecs PRIVATE
-
- SetLargePageMode PRIVATE
- SetCaseSensitive PRIVATE
+EXPORTS
+ CreateObject PRIVATE
+
+ GetHandlerProperty PRIVATE
+ GetNumberOfFormats PRIVATE
+ GetHandlerProperty2 PRIVATE
+ GetIsArc PRIVATE
+
+ GetNumberOfMethods PRIVATE
+ GetMethodProperty PRIVATE
+ CreateDecoder PRIVATE
+ CreateEncoder PRIVATE
+
+ GetHashers PRIVATE
+
+ SetCodecs PRIVATE
+
+ SetLargePageMode PRIVATE
+ SetCaseSensitive PRIVATE
+
+ GetModuleProp PRIVATE
diff --git a/CPP/7zip/Archive/ArchiveExports.cpp b/CPP/7zip/Archive/ArchiveExports.cpp
index 94f2fff..4735fcf 100644
--- a/CPP/7zip/Archive/ArchiveExports.cpp
+++ b/CPP/7zip/Archive/ArchiveExports.cpp
@@ -1,151 +1,158 @@
-// ArchiveExports.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/7zVersion.h"
-
-#include "../../Common/ComTry.h"
-
-#include "../../Windows/PropVariant.h"
-
-#include "../Common/RegisterArc.h"
-
-static const unsigned kNumArcsMax = 64;
-static unsigned g_NumArcs = 0;
-static unsigned g_DefaultArcIndex = 0;
-static const CArcInfo *g_Arcs[kNumArcsMax];
-
-void RegisterArc(const CArcInfo *arcInfo) throw()
-{
- if (g_NumArcs < kNumArcsMax)
- {
- const char *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,
- k_7zip_GUID_Data1,
- k_7zip_GUID_Data2,
- k_7zip_GUID_Data3_Common,
- 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
-
-#define CLS_ARC_ID_ITEM(cls) ((cls).Data4[5])
-
-static inline HRESULT SetPropStrFromBin(const char *s, unsigned 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 SetPropStrFromBin((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]->Id == 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
- NWindows::NCOM::PropVariant_Clear(value);
- if (formatIndex >= g_NumArcs)
- return E_INVALIDARG;
- const CArcInfo &arc = *g_Arcs[formatIndex];
- NWindows::NCOM::CPropVariant prop;
- switch (propID)
- {
- case NArchive::NHandlerPropID::kName: prop = arc.Name; break;
- case NArchive::NHandlerPropID::kClassID:
- {
- GUID clsId = CLSID_CArchiveHandler;
- CLS_ARC_ID_ITEM(clsId) = arc.Id;
- return SetPropGUID(clsId, value);
- }
- case NArchive::NHandlerPropID::kExtension: if (arc.Ext) prop = arc.Ext; break;
- case NArchive::NHandlerPropID::kAddExtension: if (arc.AddExt) prop = arc.AddExt; break;
- case NArchive::NHandlerPropID::kUpdate: prop = (bool)(arc.CreateOutArchive != NULL); break;
- case NArchive::NHandlerPropID::kKeepName: prop = ((arc.Flags & NArcInfoFlags::kKeepName) != 0); break;
- case NArchive::NHandlerPropID::kAltStreams: prop = ((arc.Flags & NArcInfoFlags::kAltStreams) != 0); break;
- case NArchive::NHandlerPropID::kNtSecure: prop = ((arc.Flags & NArcInfoFlags::kNtSecure) != 0); break;
- case NArchive::NHandlerPropID::kFlags: prop = (UInt32)arc.Flags; break;
- case NArchive::NHandlerPropID::kSignatureOffset: prop = (UInt32)arc.SignatureOffset; break;
- // case NArchive::NHandlerPropID::kVersion: prop = (UInt32)MY_VER_MIX; break;
-
- case NArchive::NHandlerPropID::kSignature:
- if (arc.SignatureSize != 0 && !arc.IsMultiSignature())
- return SetPropStrFromBin((const char *)arc.Signature, arc.SignatureSize, value);
- break;
- case NArchive::NHandlerPropID::kMultiSignature:
- if (arc.SignatureSize != 0 && arc.IsMultiSignature())
- return SetPropStrFromBin((const char *)arc.Signature, arc.SignatureSize, value);
- break;
- }
- 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;
-}
-
-STDAPI GetIsArc(UInt32 formatIndex, Func_IsArc *isArc)
-{
- *isArc = NULL;
- if (formatIndex >= g_NumArcs)
- return E_INVALIDARG;
- *isArc = g_Arcs[formatIndex]->IsArc;
- return S_OK;
-}
+// ArchiveExports.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zVersion.h"
+
+#include "../../Common/ComTry.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/RegisterArc.h"
+
+static const unsigned kNumArcsMax = 72;
+static unsigned g_NumArcs = 0;
+static unsigned g_DefaultArcIndex = 0;
+static const CArcInfo *g_Arcs[kNumArcsMax];
+
+void RegisterArc(const CArcInfo *arcInfo) throw()
+{
+ if (g_NumArcs < kNumArcsMax)
+ {
+ const char *p = arcInfo->Name;
+ if (p[0] == '7' && p[1] == 'z' && p[2] == 0)
+ g_DefaultArcIndex = g_NumArcs;
+ g_Arcs[g_NumArcs++] = arcInfo;
+ }
+ // else throw 1;
+}
+
+Z7_DEFINE_GUID(CLSID_CArchiveHandler,
+ k_7zip_GUID_Data1,
+ k_7zip_GUID_Data2,
+ k_7zip_GUID_Data3_Common,
+ 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
+
+#define CLS_ARC_ID_ITEM(cls) ((cls).Data4[5])
+
+static inline HRESULT SetPropStrFromBin(const char *s, unsigned size, PROPVARIANT *value)
+{
+ if ((value->bstrVal = ::SysAllocStringByteLen(s, size)) != NULL)
+ value->vt = VT_BSTR;
+ return S_OK;
+}
+
+static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value)
+{
+ return SetPropStrFromBin((const char *)&guid, sizeof(guid), value);
+}
+
+static int FindFormatCalssId(const GUID *clsid)
+{
+ GUID cls = *clsid;
+ CLS_ARC_ID_ITEM(cls) = 0;
+ if (cls != CLSID_CArchiveHandler)
+ return -1;
+ const Byte id = CLS_ARC_ID_ITEM(*clsid);
+ for (unsigned i = 0; i < g_NumArcs; i++)
+ if (g_Arcs[i]->Id == id)
+ return (int)i;
+ return -1;
+}
+
+STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject);
+STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject)
+{
+ COM_TRY_BEGIN
+ {
+ const int needIn = (*iid == IID_IInArchive);
+ const int needOut = (*iid == IID_IOutArchive);
+ if (!needIn && !needOut)
+ return E_NOINTERFACE;
+ const 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);
+STDAPI GetHandlerProperty2(UInt32 formatIndex, PROPID propID, PROPVARIANT *value)
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::PropVariant_Clear(value);
+ if (formatIndex >= g_NumArcs)
+ return E_INVALIDARG;
+ const CArcInfo &arc = *g_Arcs[formatIndex];
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case NArchive::NHandlerPropID::kName: prop = arc.Name; break;
+ case NArchive::NHandlerPropID::kClassID:
+ {
+ GUID clsId = CLSID_CArchiveHandler;
+ CLS_ARC_ID_ITEM(clsId) = arc.Id;
+ return SetPropGUID(clsId, value);
+ }
+ case NArchive::NHandlerPropID::kExtension: if (arc.Ext) prop = arc.Ext; break;
+ case NArchive::NHandlerPropID::kAddExtension: if (arc.AddExt) prop = arc.AddExt; break;
+ case NArchive::NHandlerPropID::kUpdate: prop = (bool)(arc.CreateOutArchive != NULL); break;
+ case NArchive::NHandlerPropID::kKeepName: prop = ((arc.Flags & NArcInfoFlags::kKeepName) != 0); break;
+ case NArchive::NHandlerPropID::kAltStreams: prop = ((arc.Flags & NArcInfoFlags::kAltStreams) != 0); break;
+ case NArchive::NHandlerPropID::kNtSecure: prop = ((arc.Flags & NArcInfoFlags::kNtSecure) != 0); break;
+ case NArchive::NHandlerPropID::kFlags: prop = (UInt32)arc.Flags; break;
+ case NArchive::NHandlerPropID::kTimeFlags: prop = (UInt32)arc.TimeFlags; break;
+ case NArchive::NHandlerPropID::kSignatureOffset: prop = (UInt32)arc.SignatureOffset; break;
+ // case NArchive::NHandlerPropID::kVersion: prop = (UInt32)MY_VER_MIX; break;
+
+ case NArchive::NHandlerPropID::kSignature:
+ if (arc.SignatureSize != 0 && !arc.IsMultiSignature())
+ return SetPropStrFromBin((const char *)arc.Signature, arc.SignatureSize, value);
+ break;
+ case NArchive::NHandlerPropID::kMultiSignature:
+ if (arc.SignatureSize != 0 && arc.IsMultiSignature())
+ return SetPropStrFromBin((const char *)arc.Signature, arc.SignatureSize, value);
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+STDAPI GetHandlerProperty(PROPID propID, PROPVARIANT *value);
+STDAPI GetHandlerProperty(PROPID propID, PROPVARIANT *value)
+{
+ return GetHandlerProperty2(g_DefaultArcIndex, propID, value);
+}
+
+STDAPI GetNumberOfFormats(UINT32 *numFormats);
+STDAPI GetNumberOfFormats(UINT32 *numFormats)
+{
+ *numFormats = g_NumArcs;
+ return S_OK;
+}
+
+STDAPI GetIsArc(UInt32 formatIndex, Func_IsArc *isArc);
+STDAPI GetIsArc(UInt32 formatIndex, Func_IsArc *isArc)
+{
+ *isArc = NULL;
+ if (formatIndex >= g_NumArcs)
+ return E_INVALIDARG;
+ *isArc = g_Arcs[formatIndex]->IsArc;
+ return S_OK;
+}
diff --git a/CPP/7zip/Archive/ArjHandler.cpp b/CPP/7zip/Archive/ArjHandler.cpp
new file mode 100644
index 0000000..2f982c4
--- /dev/null
+++ b/CPP/7zip/Archive/ArjHandler.cpp
@@ -0,0 +1,1009 @@
+// ArjHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/StringConvert.h"
+
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/PropVariantUtils.h"
+#include "../../Windows/TimeUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+#include "../Compress/LzhDecoder.h"
+
+#include "Common/ItemNameUtils.h"
+#include "Common/OutStreamWithCRC.h"
+
+namespace NCompress {
+namespace NArj {
+namespace NDecoder {
+
+static const unsigned kMatchMinLen = 3;
+
+static const UInt32 kWindowSize = 1 << 15; // must be >= (1 << 14)
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ CCoder
+ , ICompressCoder
+)
+ CLzOutWindow _outWindow;
+ NBitm::CDecoder<CInBuffer> _inBitStream;
+
+ class CCoderReleaser
+ {
+ CCoder *_coder;
+ public:
+ CCoderReleaser(CCoder *coder): _coder(coder) {}
+ void Disable() { _coder = NULL; }
+ ~CCoderReleaser() { if (_coder) _coder->_outWindow.Flush(); }
+ };
+ friend class CCoderReleaser;
+
+ HRESULT CodeReal(UInt64 outSize, ICompressProgressInfo *progress);
+public:
+ bool FinishMode;
+
+ CCoder(): FinishMode(false) {}
+ UInt64 GetInputProcessedSize() const { return _inBitStream.GetProcessedSize(); }
+};
+
+
+HRESULT CCoder::CodeReal(UInt64 rem, ICompressProgressInfo *progress)
+{
+ const UInt32 kStep = 1 << 20;
+ UInt64 next = 0;
+ if (rem > kStep && progress)
+ next = rem - kStep;
+
+ while (rem != 0)
+ {
+ if (rem <= next)
+ {
+ if (_inBitStream.ExtraBitsWereRead())
+ return S_FALSE;
+
+ UInt64 packSize = _inBitStream.GetProcessedSize();
+ UInt64 pos = _outWindow.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &pos))
+ next = 0;
+ if (rem > kStep)
+ next = rem - kStep;
+ }
+
+ UInt32 len;
+
+ {
+ const unsigned kNumBits = 7 + 7;
+ UInt32 val = _inBitStream.GetValue(kNumBits);
+
+ if ((val & (1 << (kNumBits - 1))) == 0)
+ {
+ _outWindow.PutByte((Byte)(val >> 5));
+ _inBitStream.MovePos(1 + 8);
+ rem--;
+ continue;
+ }
+
+ UInt32 mask = 1 << (kNumBits - 2);
+ unsigned w;
+
+ for (w = 1; w < 7; w++, mask >>= 1)
+ if ((val & mask) == 0)
+ break;
+
+ unsigned readBits = (w != 7 ? 1 : 0);
+ readBits += w + w;
+ len = (1 << w) - 1 + kMatchMinLen - 1 +
+ (((val >> (kNumBits - readBits)) & ((1 << w) - 1)));
+ _inBitStream.MovePos(readBits);
+ }
+
+ {
+ const unsigned kNumBits = 4 + 13;
+ UInt32 val = _inBitStream.GetValue(kNumBits);
+
+ unsigned readBits = 1;
+ unsigned w;
+
+ if ((val & ((UInt32)1 << 16)) == 0) w = 9;
+ else if ((val & ((UInt32)1 << 15)) == 0) w = 10;
+ else if ((val & ((UInt32)1 << 14)) == 0) w = 11;
+ else if ((val & ((UInt32)1 << 13)) == 0) w = 12;
+ else { w = 13; readBits = 0; }
+
+ readBits += w + w - 9;
+
+ UInt32 dist = ((UInt32)1 << w) - (1 << 9) +
+ (((val >> (kNumBits - readBits)) & ((1 << w) - 1)));
+ _inBitStream.MovePos(readBits);
+
+ if (len > rem)
+ len = (UInt32)rem;
+
+ if (!_outWindow.CopyBlock(dist, len))
+ return S_FALSE;
+ rem -= len;
+ }
+ }
+
+ if (FinishMode)
+ {
+ if (_inBitStream.ReadAlignBits() != 0)
+ return S_FALSE;
+ }
+
+ if (_inBitStream.ExtraBitsWereRead())
+ return S_FALSE;
+
+ return S_OK;
+}
+
+
+
+Z7_COM7F_IMF(CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ try
+ {
+ if (!outSize)
+ return E_INVALIDARG;
+
+ if (!_outWindow.Create(kWindowSize))
+ return E_OUTOFMEMORY;
+ if (!_inBitStream.Create(1 << 17))
+ return E_OUTOFMEMORY;
+
+ _outWindow.SetStream(outStream);
+ _outWindow.Init(false);
+ _inBitStream.SetStream(inStream);
+ _inBitStream.Init();
+
+ CCoderReleaser coderReleaser(this);
+ HRESULT res;
+ {
+ res = CodeReal(*outSize, progress);
+ if (res != S_OK)
+ return res;
+ }
+
+ coderReleaser.Disable();
+ return _outWindow.Flush();
+ }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+}}}
+
+
+
+
+using namespace NWindows;
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
+namespace NArchive {
+namespace NArj {
+
+static const unsigned kBlockSizeMin = 30;
+static const unsigned kBlockSizeMax = 2600;
+
+static const Byte kSig0 = 0x60;
+static const Byte kSig1 = 0xEA;
+
+namespace NCompressionMethod
+{
+ enum
+ {
+ kStored = 0,
+ kCompressed1a = 1,
+ kCompressed1b = 2,
+ kCompressed1c = 3,
+ kCompressed2 = 4,
+ kNoDataNoCRC = 8,
+ kNoData = 9
+ };
+}
+
+namespace NFileType
+{
+ enum
+ {
+ kBinary = 0,
+ k7BitText,
+ kArchiveHeader,
+ kDirectory,
+ kVolumeLablel,
+ kChapterLabel
+ };
+}
+
+namespace NFlags
+{
+ const Byte kGarbled = 1 << 0;
+ // const Byte kAnsiPage = 1 << 1; // or (OLD_SECURED_FLAG) obsolete
+ const Byte kVolume = 1 << 2;
+ const Byte kExtFile = 1 << 3;
+ // const Byte kPathSym = 1 << 4;
+ // const Byte kBackup = 1 << 5; // obsolete
+ // const Byte kSecured = 1 << 6;
+ // const Byte kDualName = 1 << 7;
+}
+
+namespace NHostOS
+{
+ enum EEnum
+ {
+ kMSDOS = 0, // MS-DOS, OS/2, Win32, pkarj 2.50 (FAT / VFAT / FAT32)
+ kPRIMOS,
+ kUnix,
+ kAMIGA,
+ kMac,
+ kOS_2,
+ kAPPLE_GS,
+ kAtari_ST,
+ kNext,
+ kVAX_VMS,
+ kWIN95
+ };
+}
+
+static const char * const kHostOS[] =
+{
+ "MSDOS"
+ , "PRIMOS"
+ , "UNIX"
+ , "AMIGA"
+ , "MAC"
+ , "OS/2"
+ , "APPLE GS"
+ , "ATARI ST"
+ , "NEXT"
+ , "VAX VMS"
+ , "WIN95"
+};
+
+struct CArcHeader
+{
+ // Byte ArchiverVersion;
+ // Byte ExtractVersion;
+ Byte HostOS;
+ // Byte Flags;
+ // Byte SecuryVersion;
+ // Byte FileType;
+ // Byte Reserved;
+ UInt32 CTime;
+ UInt32 MTime;
+ UInt32 ArchiveSize;
+ // UInt32 SecurPos;
+ // UInt16 FilespecPosInFilename;
+ UInt16 SecurSize;
+ // Byte EncryptionVersion;
+ // Byte LastChapter;
+ AString Name;
+ AString Comment;
+
+ HRESULT Parse(const Byte *p, unsigned size);
+};
+
+API_FUNC_static_IsArc IsArc_Arj(const Byte *p, size_t size)
+{
+ if (size < kBlockSizeMin + 4)
+ return k_IsArc_Res_NEED_MORE;
+ if (p[0] != kSig0 || p[1] != kSig1)
+ return k_IsArc_Res_NO;
+ UInt32 blockSize = Get16(p + 2);
+ if (blockSize < kBlockSizeMin ||
+ blockSize > kBlockSizeMax)
+ return k_IsArc_Res_NO;
+
+ p += 4;
+ size -= 4;
+
+ Byte headerSize = p[0];
+ if (headerSize < kBlockSizeMin ||
+ headerSize > blockSize ||
+ p[6] != NFileType::kArchiveHeader ||
+ p[28] > 8) // EncryptionVersion
+ return k_IsArc_Res_NO;
+
+ if (blockSize + 4 <= size)
+ if (Get32(p + blockSize) != CrcCalc(p, blockSize))
+ return k_IsArc_Res_NO;
+
+ return k_IsArc_Res_YES;
+}
+}
+
+static HRESULT ReadString(const Byte *p, unsigned &size, AString &res)
+{
+ unsigned num = size;
+ for (unsigned i = 0; i < num;)
+ {
+ if (p[i++] == 0)
+ {
+ size = i;
+ res = (const char *)p;
+ return S_OK;
+ }
+ }
+ return S_FALSE;
+}
+
+HRESULT CArcHeader::Parse(const Byte *p, unsigned size)
+{
+ Byte headerSize = p[0];
+ if (headerSize < kBlockSizeMin || headerSize > size)
+ return S_FALSE;
+ // ArchiverVersion = p[1];
+ // ExtractVersion = p[2];
+ HostOS = p[3];
+ // Flags = p[4];
+ // SecuryVersion = p[5];
+ if (p[6] != NFileType::kArchiveHeader)
+ return S_FALSE;
+ // Reserved = p[7];
+ CTime = Get32(p + 8);
+ MTime = Get32(p + 12);
+ ArchiveSize = Get32(p + 16); // it can be zero. (currently used only for secured archives)
+ // SecurPos = Get32(p + 20);
+ // UInt16 filespecPositionInFilename = Get16(p + 24);
+ SecurSize = Get16(p + 26);
+ // EncryptionVersion = p[28];
+ // LastChapter = p[29];
+ unsigned pos = headerSize;
+ 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 CExtendedInfo
+{
+ UInt64 Size;
+ bool CrcError;
+
+ void Clear()
+ {
+ Size = 0;
+ CrcError = false;
+ }
+ void ParseToPropVar(NCOM::CPropVariant &prop) const
+ {
+ if (Size != 0)
+ {
+ AString s;
+ s += "Extended:";
+ s.Add_UInt32((UInt32)Size);
+ if (CrcError)
+ s += ":CRC_ERROR";
+ prop = s;
+ }
+ }
+};
+
+
+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 FilespecPosInFilename;
+ UInt16 FileAccessMode;
+ // Byte FirstChapter;
+ // Byte LastChapter;
+
+ UInt64 DataPosition;
+
+ CExtendedInfo ExtendedInfo;
+
+ bool IsEncrypted() const { return (Flags & NFlags::kGarbled) != 0; }
+ bool IsDir() const { return (FileType == NFileType::kDirectory); }
+ bool IsSplitAfter() const { return (Flags & NFlags::kVolume) != 0; }
+ bool IsSplitBefore() const { return (Flags & NFlags::kExtFile) != 0; }
+ UInt32 GetWinAttrib() const
+ {
+ UInt32 atrrib = 0;
+ switch (HostOS)
+ {
+ case NHostOS::kMSDOS:
+ case NHostOS::kWIN95:
+ atrrib = FileAccessMode;
+ break;
+ }
+ if (IsDir())
+ atrrib |= FILE_ATTRIBUTE_DIRECTORY;
+ return atrrib;
+ }
+
+ HRESULT Parse(const Byte *p, unsigned size);
+};
+
+HRESULT CItem::Parse(const Byte *p, unsigned size)
+{
+ Byte headerSize = p[0];
+ if (headerSize < kBlockSizeMin || headerSize > size)
+ return S_FALSE;
+ 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);
+ // FilespecPosInFilename = Get16(p + 24);
+ FileAccessMode = Get16(p + 26);
+ // FirstChapter = p[28];
+ // FirstChapter = p[29];
+
+ SplitPos = 0;
+ if (IsSplitBefore() && headerSize >= 34)
+ SplitPos = Get32(p + 30);
+
+ unsigned pos = headerSize;
+ 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;
+}
+
+enum EErrorType
+{
+ k_ErrorType_OK,
+ k_ErrorType_Corrupted,
+ k_ErrorType_UnexpectedEnd
+};
+
+class CArc
+{
+public:
+ UInt64 Processed;
+ EErrorType Error;
+ bool IsArc;
+ IInStream *Stream;
+ IArchiveOpenCallback *Callback;
+ UInt64 NumFiles;
+ CArcHeader Header;
+
+ CExtendedInfo ExtendedInfo;
+
+ HRESULT Open();
+ HRESULT GetNextItem(CItem &item, bool &filled);
+ void Close()
+ {
+ IsArc = false;
+ Error = k_ErrorType_OK;
+ ExtendedInfo.Clear();
+ }
+private:
+ unsigned _blockSize;
+ CByteBuffer _block;
+
+ HRESULT ReadBlock(bool &filled, CExtendedInfo *extendedInfo);
+ HRESULT SkipExtendedHeaders(CExtendedInfo &extendedInfo);
+ HRESULT Read(void *data, size_t *size);
+};
+
+HRESULT CArc::Read(void *data, size_t *size)
+{
+ HRESULT res = ReadStream(Stream, data, size);
+ Processed += *size;
+ return res;
+}
+
+#define READ_STREAM(_dest_, _size_) \
+ { size_t _processed_ = (_size_); RINOK(Read(_dest_, &_processed_)); \
+ if (_processed_ != (_size_)) { Error = k_ErrorType_UnexpectedEnd; return S_OK; } }
+
+HRESULT CArc::ReadBlock(bool &filled, CExtendedInfo *extendedInfo)
+{
+ Error = k_ErrorType_OK;
+ filled = false;
+ Byte buf[4];
+ const unsigned signSize = extendedInfo ? 0 : 2;
+ READ_STREAM(buf, signSize + 2)
+ if (!extendedInfo)
+ if (buf[0] != kSig0 || buf[1] != kSig1)
+ {
+ Error = k_ErrorType_Corrupted;
+ return S_OK;
+ }
+ _blockSize = Get16(buf + signSize);
+ if (_blockSize == 0) // end of archive
+ return S_OK;
+
+ if (!extendedInfo)
+ if (_blockSize < kBlockSizeMin || _blockSize > kBlockSizeMax)
+ {
+ Error = k_ErrorType_Corrupted;
+ return S_OK;
+ }
+
+ const size_t readSize = _blockSize + 4;
+ if (readSize > _block.Size())
+ {
+ // extended data size is limited by (64 KB)
+ // _blockSize is less than 64 KB
+ const size_t upSize = (_blockSize > kBlockSizeMax ? (1 << 16) : kBlockSizeMax);
+ _block.Alloc(upSize + 4);
+ }
+
+ if (extendedInfo)
+ extendedInfo->Size += _blockSize;
+
+ READ_STREAM(_block, readSize)
+ if (Get32(_block + _blockSize) != CrcCalc(_block, _blockSize))
+ {
+ if (extendedInfo)
+ extendedInfo->CrcError = true;
+ else
+ {
+ Error = k_ErrorType_Corrupted;
+ return S_OK;
+ }
+ }
+ filled = true;
+ return S_OK;
+}
+
+HRESULT CArc::SkipExtendedHeaders(CExtendedInfo &extendedInfo)
+{
+ extendedInfo.Clear();
+ for (UInt32 i = 0;; i++)
+ {
+ bool filled;
+ RINOK(ReadBlock(filled, &extendedInfo))
+ if (!filled)
+ return S_OK;
+ if (Callback && (i & 0xFF) == 0)
+ RINOK(Callback->SetCompleted(&NumFiles, &Processed))
+ }
+}
+
+HRESULT CArc::Open()
+{
+ bool filled;
+ RINOK(ReadBlock(filled, NULL)) // (extendedInfo = NULL)
+ if (!filled)
+ return S_FALSE;
+ RINOK(Header.Parse(_block, _blockSize))
+ IsArc = true;
+ return SkipExtendedHeaders(ExtendedInfo);
+}
+
+HRESULT CArc::GetNextItem(CItem &item, bool &filled)
+{
+ RINOK(ReadBlock(filled, NULL)) // (extendedInfo = NULL)
+ if (!filled)
+ return S_OK;
+ filled = false;
+ if (item.Parse(_block, _blockSize) != S_OK)
+ {
+ Error = k_ErrorType_Corrupted;
+ return S_OK;
+ }
+ /*
+ UInt32 extraData;
+ if ((header.Flags & NFlags::kExtFile) != 0)
+ extraData = GetUi32(_block + pos);
+ */
+
+ RINOK(SkipExtendedHeaders(item.ExtendedInfo))
+ filled = true;
+ return S_OK;
+}
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_0
+
+ CObjectVector<CItem> _items;
+ CMyComPtr<IInStream> _stream;
+ UInt64 _phySize;
+ CArc _arc;
+
+ HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *callback);
+};
+
+static const Byte kArcProps[] =
+{
+ kpidName,
+ kpidCTime,
+ kpidMTime,
+ kpidHostOS,
+ kpidComment,
+ kpidCharacts
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPosition,
+ kpidPackSize,
+ kpidMTime,
+ kpidAttrib,
+ kpidEncrypted,
+ kpidCRC,
+ kpidMethod,
+ kpidHostOS,
+ kpidComment,
+ kpidCharacts
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static void SetTime(UInt32 dosTime, NCOM::CPropVariant &prop)
+{
+ if (dosTime == 0)
+ return;
+ PropVariant_SetFrom_DosTime(prop, dosTime);
+}
+
+static void SetHostOS(Byte hostOS, NCOM::CPropVariant &prop)
+{
+ TYPE_TO_PROP(kHostOS, hostOS, prop);
+}
+
+static void SetUnicodeString(const AString &s, NCOM::CPropVariant &prop)
+{
+ if (!s.IsEmpty())
+ prop = MultiByteToUnicodeString(s, CP_OEMCP);
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySize: prop = _phySize; break;
+ case kpidName: SetUnicodeString(_arc.Header.Name, prop); break;
+ case kpidCTime: SetTime(_arc.Header.CTime, prop); break;
+ case kpidMTime: SetTime(_arc.Header.MTime, prop); break;
+ case kpidHostOS: SetHostOS(_arc.Header.HostOS, prop); break;
+ case kpidComment: SetUnicodeString(_arc.Header.Comment, prop); break;
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_arc.IsArc) v |= kpv_ErrorFlags_IsNotArc;
+ switch (_arc.Error)
+ {
+ case k_ErrorType_UnexpectedEnd: v |= kpv_ErrorFlags_UnexpectedEnd; break;
+ case k_ErrorType_Corrupted: v |= kpv_ErrorFlags_HeadersError; break;
+ case k_ErrorType_OK:
+ // default:
+ break;
+ }
+ prop = v;
+ break;
+ }
+ case kpidCharacts: _arc.ExtendedInfo.ParseToPropVar(prop); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
+ switch (propID)
+ {
+ case kpidPath: prop = NItemName::GetOsPath(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.GetWinAttrib(); 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;
+ case kpidCharacts: item.ExtendedInfo.ParseToPropVar(prop); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CHandler::Open2(IInStream *inStream, IArchiveOpenCallback *callback)
+{
+ Close();
+
+ UInt64 endPos;
+ RINOK(InStream_AtBegin_GetSize(inStream, endPos))
+
+ _arc.Stream = inStream;
+ _arc.Callback = callback;
+ _arc.NumFiles = 0;
+ _arc.Processed = 0;
+
+ RINOK(_arc.Open())
+
+ _phySize = _arc.Processed;
+ if (_arc.Header.ArchiveSize != 0)
+ _phySize = (UInt64)_arc.Header.ArchiveSize + _arc.Header.SecurSize;
+
+ for (;;)
+ {
+ CItem item;
+ bool filled;
+
+ _arc.Error = k_ErrorType_OK;
+ RINOK(_arc.GetNextItem(item, filled))
+
+ if (_arc.Error != k_ErrorType_OK)
+ break;
+
+ if (!filled)
+ {
+ if (_arc.Error == k_ErrorType_OK)
+ if (_arc.Header.ArchiveSize == 0)
+ _phySize = _arc.Processed;
+ break;
+ }
+ item.DataPosition = _arc.Processed;
+ _items.Add(item);
+
+ UInt64 pos = item.DataPosition + item.PackSize;
+ if (_arc.Header.ArchiveSize == 0)
+ _phySize = pos;
+ if (pos > endPos)
+ {
+ _arc.Error = k_ErrorType_UnexpectedEnd;
+ break;
+ }
+
+ RINOK(InStream_SeekSet(inStream, pos))
+ _arc.NumFiles = _items.Size();
+ _arc.Processed = pos;
+
+ if (callback && (_items.Size() & 0xFF) == 0)
+ {
+ RINOK(callback->SetCompleted(&_arc.NumFiles, &_arc.Processed))
+ }
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ HRESULT res;
+ {
+ res = Open2(inStream, callback);
+ if (res == S_OK)
+ {
+ _stream = inStream;
+ return S_OK;
+ }
+ }
+ return res;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _arc.Close();
+ _phySize = 0;
+ _items.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ UInt64 totalUnpacked = 0, totalPacked = 0;
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-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;
+
+ NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = NULL;
+ CMyComPtr<ICompressCoder> lzhDecoder;
+
+ NCompress::NArj::NDecoder::CCoder *arjDecoderSpec = NULL;
+ CMyComPtr<ICompressCoder> arjDecoder;
+
+ 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;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 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);
+
+ RINOK(InStream_SeekSet(_stream, item.DataPosition))
+
+ HRESULT result = S_OK;
+ Int32 opRes = NExtract::NOperationResult::kOK;
+
+ if (item.IsEncrypted())
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ else
+ {
+ switch (item.Method)
+ {
+ case NCompressionMethod::kStored:
+ {
+ result = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ if (result == S_OK && copyCoderSpec->TotalSize != item.PackSize)
+ result = S_FALSE;
+ break;
+ }
+ case NCompressionMethod::kCompressed1a:
+ case NCompressionMethod::kCompressed1b:
+ case NCompressionMethod::kCompressed1c:
+ {
+ if (!lzhDecoder)
+ {
+ lzhDecoderSpec = new NCompress::NLzh::NDecoder::CCoder;
+ lzhDecoder = lzhDecoderSpec;
+ }
+ lzhDecoderSpec->FinishMode = true;
+ const UInt32 kHistorySize = 26624;
+ lzhDecoderSpec->SetDictSize(kHistorySize);
+ result = lzhDecoder->Code(inStream, outStream, NULL, &curUnpacked, progress);
+ if (result == S_OK && lzhDecoderSpec->GetInputProcessedSize() != item.PackSize)
+ result = S_FALSE;
+ break;
+ }
+ case NCompressionMethod::kCompressed2:
+ {
+ if (!arjDecoder)
+ {
+ arjDecoderSpec = new NCompress::NArj::NDecoder::CCoder;
+ arjDecoder = arjDecoderSpec;
+ }
+ arjDecoderSpec->FinishMode = true;
+ result = arjDecoder->Code(inStream, outStream, NULL, &curUnpacked, progress);
+ if (result == S_OK && arjDecoderSpec->GetInputProcessedSize() != item.PackSize)
+ result = S_FALSE;
+ 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 const Byte k_Signature[] = { kSig0, kSig1 };
+
+REGISTER_ARC_I(
+ "Arj", "arj", NULL, 4,
+ k_Signature,
+ 0,
+ 0,
+ IsArc_Arj)
+
+}}
diff --git a/CPP/7zip/Archive/Base64Handler.cpp b/CPP/7zip/Archive/Base64Handler.cpp
new file mode 100644
index 0000000..5b06051
--- /dev/null
+++ b/CPP/7zip/Archive/Base64Handler.cpp
@@ -0,0 +1,505 @@
+// Base64Handler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyVector.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+#include "../Common/InBuffer.h"
+
+/*
+spaces:
+ 9(TAB),10(LF),13(CR),32(SPACE)
+ Non-breaking space:
+ 0xa0 : Unicode, Windows code pages 1250-1258
+ 0xff (unused): DOS code pages
+
+end of stream markers: '=' (0x3d):
+ "=" , if numBytes (% 3 == 2)
+ "==" , if numBytes (% 3 == 1)
+*/
+
+
+static const Byte k_Base64Table[256] =
+{
+ 66,77,77,77,77,77,77,77,77,65,65,77,77,65,77,77,
+ 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,
+ 65,77,77,77,77,77,77,77,77,77,77,62,77,77,77,63,
+ 52,53,54,55,56,57,58,59,60,61,77,77,77,64,77,77,
+ 77, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,
+ 15,16,17,18,19,20,21,22,23,24,25,77,77,77,77,77,
+ 77,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,
+ 41,42,43,44,45,46,47,48,49,50,51,77,77,77,77,77,
+ 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,
+ 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,
+ 65,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,
+ 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,
+ 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,
+ 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,
+ 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,
+ 77,77,77,77,77,77,77,77,77,77,77,77,77,77,77,77
+};
+
+static const unsigned k_Code_Equals = 64;
+static const unsigned k_Code_Space = 65;
+static const unsigned k_Code_Zero = 66;
+
+API_FUNC_static_IsArc IsArc_Base64(const Byte *p, size_t size)
+{
+ size_t num = 0;
+ size_t firstSpace = 0;
+
+ for (;;)
+ {
+ if (size == 0)
+ return k_IsArc_Res_NEED_MORE;
+ UInt32 c = k_Base64Table[(Byte)(*p++)];
+ size--;
+ if (c < 64)
+ {
+ num++;
+ continue;
+ }
+
+ if (c == k_Code_Space)
+ {
+ if (p[-1] == ' ' && firstSpace == 0)
+ firstSpace = num;
+ continue;
+ }
+
+ if (c != k_Code_Equals)
+ return k_IsArc_Res_NO;
+ break;
+ }
+
+ {
+ // we try to redece false positive detection here.
+ // we don't expect space character in starting base64 line
+ const unsigned kNumExpectedNonSpaceSyms = 20;
+ if (firstSpace != 0 && firstSpace < num && firstSpace < kNumExpectedNonSpaceSyms)
+ return k_IsArc_Res_NO;
+ }
+
+ num &= 3;
+
+ if (num <= 1)
+ return k_IsArc_Res_NO;
+ if (num != 3)
+ {
+ if (size == 0)
+ return k_IsArc_Res_NEED_MORE;
+ UInt32 c = k_Base64Table[(Byte)(*p++)];
+ size--;
+ if (c != k_Code_Equals)
+ return k_IsArc_Res_NO;
+ }
+
+ for (;;)
+ {
+ if (size == 0)
+ return k_IsArc_Res_YES;
+ UInt32 c = k_Base64Table[(Byte)(*p++)];
+ size--;
+ if (c == k_Code_Space)
+ continue;
+ return k_IsArc_Res_NO;
+ }
+}
+}
+
+
+enum EBase64Res
+{
+ k_Base64_RES_MaybeFinished,
+ k_Base64_RES_Finished,
+ k_Base64_RES_NeedMoreInput,
+ k_Base64_RES_UnexpectedChar
+};
+
+
+static EBase64Res Base64ToBin(Byte *p, size_t size, const Byte **srcEnd, Byte **destEnd)
+{
+ Byte *dest = p;
+ UInt32 val = 1;
+ EBase64Res res = k_Base64_RES_NeedMoreInput;
+
+ for (;;)
+ {
+ if (size == 0)
+ {
+ if (val == 1)
+ res = k_Base64_RES_MaybeFinished;
+ break;
+ }
+ UInt32 c = k_Base64Table[(Byte)(*p++)];
+ size--;
+ if (c < 64)
+ {
+ val = (val << 6) | c;
+ if ((val & ((UInt32)1 << 24)) == 0)
+ continue;
+ dest[0] = (Byte)(val >> 16);
+ dest[1] = (Byte)(val >> 8);
+ dest[2] = (Byte)(val);
+ dest += 3;
+ val = 1;
+ continue;
+ }
+
+ if (c == k_Code_Space)
+ continue;
+
+ if (c == k_Code_Equals)
+ {
+ if (val >= (1 << 12))
+ {
+ if (val & (1 << 18))
+ {
+ res = k_Base64_RES_Finished;
+ break;
+ }
+ if (size == 0)
+ break;
+ c = k_Base64Table[(Byte)(*p++)];
+ size--;
+ if (c == k_Code_Equals)
+ {
+ res = k_Base64_RES_Finished;
+ break;
+ }
+ }
+ }
+
+ p--;
+ res = k_Base64_RES_UnexpectedChar;
+ break;
+ }
+
+ if (val >= ((UInt32)1 << 12))
+ {
+ if (val & (1 << 18))
+ {
+ *dest++ = (Byte)(val >> 10);
+ val <<= 2;
+ }
+ *dest++ = (Byte)(val >> 4);
+ }
+
+ *srcEnd = p;
+ *destEnd = dest;
+ return res;
+}
+
+
+static const Byte *Base64_SkipSpaces(const Byte *p, size_t size)
+{
+ for (;;)
+ {
+ if (size == 0)
+ return p;
+ const UInt32 c = k_Base64Table[(Byte)(*p++)];
+ size--;
+ if (c == k_Code_Space)
+ continue;
+ return p - 1;
+ }
+}
+
+
+// the following function is used by DmgHandler.cpp
+
+Byte *Base64ToBin(Byte *dest, const char *src);
+Byte *Base64ToBin(Byte *dest, const char *src)
+{
+ UInt32 val = 1;
+
+ for (;;)
+ {
+ const UInt32 c = k_Base64Table[(Byte)(*src++)];
+
+ if (c < 64)
+ {
+ val = (val << 6) | c;
+ if ((val & ((UInt32)1 << 24)) == 0)
+ continue;
+ dest[0] = (Byte)(val >> 16);
+ dest[1] = (Byte)(val >> 8);
+ dest[2] = (Byte)(val);
+ dest += 3;
+ val = 1;
+ continue;
+ }
+
+ if (c == k_Code_Space)
+ continue;
+
+ if (c == k_Code_Equals)
+ break;
+
+ if (c == k_Code_Zero && val == 1) // end of string
+ return dest;
+
+ return NULL;
+ }
+
+ if (val < (1 << 12))
+ return NULL;
+
+ if (val & (1 << 18))
+ {
+ *dest++ = (Byte)(val >> 10);
+ val <<= 2;
+ }
+ else if (k_Base64Table[(Byte)(*src++)] != k_Code_Equals)
+ return NULL;
+ *dest++ = (Byte)(val >> 4);
+
+ for (;;)
+ {
+ const Byte c = k_Base64Table[(Byte)(*src++)];
+ if (c == k_Code_Space)
+ continue;
+ if (c == k_Code_Zero)
+ return dest;
+ return NULL;
+ }
+}
+
+
+namespace NArchive {
+namespace NBase64 {
+
+Z7_CLASS_IMP_CHandler_IInArchive_0
+
+ bool _isArc;
+ UInt64 _phySize;
+ size_t _size;
+ EBase64Res _sres;
+ CByteBuffer _data;
+};
+
+static const Byte kProps[] =
+{
+ kpidSize,
+ kpidPackSize,
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySize: if (_phySize != 0) prop = _phySize; break;
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (_sres == k_Base64_RES_NeedMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
+ if (v != 0)
+ prop = v;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
+{
+ // COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidSize: prop = (UInt64)_size; break;
+ case kpidPackSize: prop = _phySize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ // COM_TRY_END
+}
+
+
+static HRESULT ReadStream_OpenProgress(ISequentialInStream *stream, void *data, size_t size, IArchiveOpenCallback *openCallback) throw()
+{
+ UInt64 bytes = 0;
+ while (size != 0)
+ {
+ const UInt32 kBlockSize = ((UInt32)1 << 24);
+ const UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize;
+ UInt32 processedSizeLoc;
+ RINOK(stream->Read(data, curSize, &processedSizeLoc))
+ if (processedSizeLoc == 0)
+ return E_FAIL;
+ data = (void *)((Byte *)data + processedSizeLoc);
+ size -= processedSizeLoc;
+ bytes += processedSizeLoc;
+ const UInt64 files = 1;
+ RINOK(openCallback->SetCompleted(&files, &bytes))
+ }
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback))
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ {
+ const unsigned kStartSize = 1 << 12;
+ _data.Alloc(kStartSize);
+ size_t size = kStartSize;
+ RINOK(ReadStream(stream, _data, &size))
+ UInt32 isArcRes = IsArc_Base64(_data, size);
+ if (isArcRes == k_IsArc_Res_NO)
+ return S_FALSE;
+ }
+ _isArc = true;
+
+ UInt64 packSize64;
+ RINOK(InStream_GetSize_SeekToEnd(stream, packSize64))
+
+ if (packSize64 == 0)
+ return S_FALSE;
+
+ size_t curSize = 1 << 16;
+ if (curSize > packSize64)
+ curSize = (size_t)packSize64;
+ const unsigned kLogStep = 4;
+
+ for (;;)
+ {
+ RINOK(InStream_SeekSet(stream, 0))
+
+ _data.Alloc(curSize);
+ RINOK(ReadStream_OpenProgress(stream, _data, curSize, openCallback))
+
+ const Byte *srcEnd;
+ Byte *dest;
+ _sres = Base64ToBin(_data, curSize, &srcEnd, &dest);
+ _size = (size_t)(dest - _data);
+ const size_t mainSize = (size_t)(srcEnd - _data);
+ _phySize = mainSize;
+ if (_sres == k_Base64_RES_UnexpectedChar)
+ break;
+ if (curSize != mainSize)
+ {
+ const Byte *end2 = Base64_SkipSpaces(srcEnd, curSize - mainSize);
+ if ((size_t)(end2 - _data) != curSize)
+ break;
+ _phySize = curSize;
+ }
+
+ if (curSize == packSize64)
+ break;
+
+ UInt64 curSize64 = packSize64;
+ if (curSize < (packSize64 >> kLogStep))
+ curSize64 = (UInt64)curSize << kLogStep;
+ curSize = (size_t)curSize64;
+ if (curSize != curSize64)
+ return E_OUTOFMEMORY;
+ }
+ if (_size == 0)
+ return S_FALSE;
+ return S_OK;
+ }
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _phySize = 0;
+ _size = 0;
+ _isArc = false;
+ _sres = k_Base64_RES_MaybeFinished;
+ _data.Free();
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ RINOK(extractCallback->SetTotal(_size))
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ {
+ lps->InSize = lps->OutSize = 0;
+ RINOK(lps->SetCur())
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode))
+
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ if (realOutStream)
+ {
+ RINOK(WriteStream(realOutStream, (const Byte *)_data, _size))
+ realOutStream.Release();
+ }
+
+ Int32 opRes = NExtract::NOperationResult::kOK;
+
+ if (_sres != k_Base64_RES_Finished)
+ {
+ if (_sres == k_Base64_RES_NeedMoreInput)
+ opRes = NExtract::NOperationResult::kUnexpectedEnd;
+ else if (_sres == k_Base64_RES_UnexpectedChar)
+ opRes = NExtract::NOperationResult::kDataError;
+ }
+
+ RINOK(extractCallback->SetOperationResult(opRes))
+ }
+
+ lps->InSize = _phySize;
+ lps->OutSize = _size;
+ return lps->SetCur();
+
+ COM_TRY_END
+}
+
+REGISTER_ARC_I_NO_SIG(
+ "Base64", "b64", NULL, 0xC5,
+ 0,
+ NArcInfoFlags::kKeepName
+ | NArcInfoFlags::kStartOpen
+ | NArcInfoFlags::kByExtOnlyOpen,
+ IsArc_Base64)
+
+}}
diff --git a/CPP/7zip/Archive/Bz2Handler.cpp b/CPP/7zip/Archive/Bz2Handler.cpp
new file mode 100644
index 0000000..994b1ad
--- /dev/null
+++ b/CPP/7zip/Archive/Bz2Handler.cpp
@@ -0,0 +1,478 @@
+// Bz2Handler.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/ComTry.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/HandlerOut.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NBz2 {
+
+Z7_CLASS_IMP_CHandler_IInArchive_3(
+ IArchiveOpenSeq,
+ IOutArchive,
+ ISetProperties
+)
+ CMyComPtr<IInStream> _stream;
+ CMyComPtr<ISequentialInStream> _seqStream;
+
+ bool _isArc;
+ bool _needSeekToStart;
+ bool _dataAfterEnd;
+ bool _needMoreInput;
+
+ bool _packSize_Defined;
+ bool _unpackSize_Defined;
+ bool _numStreams_Defined;
+ bool _numBlocks_Defined;
+
+ UInt64 _packSize;
+ UInt64 _unpackSize;
+ UInt64 _numStreams;
+ UInt64 _numBlocks;
+
+ CSingleMethodProps _props;
+};
+
+static const Byte kProps[] =
+{
+ kpidSize,
+ kpidPackSize
+};
+
+static const Byte kArcProps[] =
+{
+ kpidNumStreams,
+ kpidNumBlocks
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySize: if (_packSize_Defined) prop = _packSize; break;
+ case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break;
+ case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break;
+ case kpidNumBlocks: if (_numBlocks_Defined) prop = _numBlocks; break;
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
+ if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
+ prop = v;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPackSize: if (_packSize_Defined) prop = _packSize; break;
+ case kpidSize: if (_unpackSize_Defined) prop = _unpackSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+static const unsigned kSignatureCheckSize = 10;
+
+API_FUNC_static_IsArc IsArc_BZip2(const Byte *p, size_t size)
+{
+ if (size < kSignatureCheckSize)
+ return k_IsArc_Res_NEED_MORE;
+ if (p[0] != 'B' || p[1] != 'Z' || p[2] != 'h' || p[3] < '1' || p[3] > '9')
+ return k_IsArc_Res_NO;
+ p += 4;
+ if (NCompress::NBZip2::IsBlockSig(p))
+ return k_IsArc_Res_YES;
+ if (NCompress::NBZip2::IsEndSig(p))
+ return k_IsArc_Res_YES;
+ return k_IsArc_Res_NO;
+}
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *))
+{
+ COM_TRY_BEGIN
+ Close();
+ {
+ Byte buf[kSignatureCheckSize];
+ RINOK(ReadStream_FALSE(stream, buf, kSignatureCheckSize))
+ if (IsArc_BZip2(buf, kSignatureCheckSize) == k_IsArc_Res_NO)
+ return S_FALSE;
+ _isArc = true;
+ _stream = stream;
+ _seqStream = stream;
+ _needSeekToStart = true;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream))
+{
+ Close();
+ _isArc = true;
+ _seqStream = stream;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _isArc = false;
+ _needSeekToStart = false;
+ _dataAfterEnd = false;
+ _needMoreInput = false;
+
+ _packSize_Defined = false;
+ _unpackSize_Defined = false;
+ _numStreams_Defined = false;
+ _numBlocks_Defined = false;
+
+ _packSize = 0;
+
+ _seqStream.Release();
+ _stream.Release();
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ if (_packSize_Defined)
+ extractCallback->SetTotal(_packSize);
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode))
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ if (_needSeekToStart)
+ {
+ if (!_stream)
+ return E_FAIL;
+ RINOK(InStream_SeekToBegin(_stream))
+ }
+ else
+ _needSeekToStart = true;
+
+ // try {
+
+ NCompress::NBZip2::CDecoder *decoderSpec = new NCompress::NBZip2::CDecoder;
+ CMyComPtr<ICompressCoder> decoder = decoderSpec;
+
+ #ifndef Z7_ST
+ RINOK(decoderSpec->SetNumberOfThreads(_props._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);
+
+ decoderSpec->FinishMode = true;
+ decoderSpec->Base.DecodeAllStreams = true;
+
+ _dataAfterEnd = false;
+ _needMoreInput = false;
+
+ lps->InSize = 0;
+ lps->OutSize = 0;
+
+ HRESULT result = decoder->Code(_seqStream, outStream, NULL, NULL, progress);
+
+ if (result != S_FALSE && result != S_OK)
+ return result;
+
+ if (decoderSpec->Base.NumStreams == 0)
+ {
+ _isArc = false;
+ result = S_FALSE;
+ }
+ else
+ {
+ const UInt64 inProcessedSize = decoderSpec->GetInputProcessedSize();
+ UInt64 packSize = inProcessedSize;
+
+ if (decoderSpec->Base.NeedMoreInput)
+ _needMoreInput = true;
+
+ if (!decoderSpec->Base.IsBz)
+ {
+ packSize = decoderSpec->Base.FinishedPackSize;
+ if (packSize != inProcessedSize)
+ _dataAfterEnd = true;
+ }
+
+ _packSize = packSize;
+ _unpackSize = decoderSpec->GetOutProcessedSize();
+ _numStreams = decoderSpec->Base.NumStreams;
+ _numBlocks = decoderSpec->GetNumBlocks();
+
+ _packSize_Defined = true;
+ _unpackSize_Defined = true;
+ _numStreams_Defined = true;
+ _numBlocks_Defined = true;
+ }
+
+ outStream.Release();
+
+ Int32 opRes;
+
+ if (!_isArc)
+ opRes = NExtract::NOperationResult::kIsNotArc;
+ else if (_needMoreInput)
+ opRes = NExtract::NOperationResult::kUnexpectedEnd;
+ else if (decoderSpec->GetCrcError())
+ opRes = NExtract::NOperationResult::kCRCError;
+ else if (_dataAfterEnd)
+ opRes = NExtract::NOperationResult::kDataAfterEnd;
+ else if (result == S_FALSE)
+ opRes = NExtract::NOperationResult::kDataError;
+ else if (decoderSpec->Base.MinorError)
+ opRes = NExtract::NOperationResult::kDataError;
+ else if (result == S_OK)
+ opRes = NExtract::NOperationResult::kOK;
+ else
+ return result;
+
+ return extractCallback->SetOperationResult(opRes);
+
+ // } catch(...) { return E_FAIL; }
+
+ COM_TRY_END
+}
+
+
+/*
+static HRESULT ReportItemProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value)
+{
+ return reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, 0, propID, value);
+}
+
+static HRESULT ReportArcProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value)
+{
+ return reportArcProp->ReportProp(NEventIndexType::kArcProp, 0, propID, value);
+}
+
+static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp,
+ const UInt64 *unpackSize,
+ const UInt64 *numBlocks)
+{
+ NCOM::CPropVariant sizeProp;
+ if (unpackSize)
+ {
+ sizeProp = *unpackSize;
+ RINOK(ReportItemProp(reportArcProp, kpidSize, &sizeProp));
+ RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, 0, NArchive::NUpdate::NOperationResult::kOK));
+ }
+
+ if (unpackSize)
+ {
+ RINOK(ReportArcProp(reportArcProp, kpidSize, &sizeProp));
+ }
+ if (numBlocks)
+ {
+ NCOM::CPropVariant prop;
+ prop = *numBlocks;
+ RINOK(ReportArcProp(reportArcProp, kpidNumBlocks, &prop));
+ }
+ return S_OK;
+}
+*/
+
+static HRESULT UpdateArchive(
+ UInt64 unpackSize,
+ ISequentialOutStream *outStream,
+ const CProps &props,
+ IArchiveUpdateCallback *updateCallback
+ // , ArchiveUpdateCallbackArcProp *reportArcProp
+ )
+{
+ {
+ CMyComPtr<ISequentialInStream> fileInStream;
+ RINOK(updateCallback->GetStream(0, &fileInStream))
+ if (!fileInStream)
+ return S_FALSE;
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IStreamGetSize,
+ streamGetSize, fileInStream)
+ if (streamGetSize)
+ {
+ UInt64 size;
+ if (streamGetSize->GetSize(&size) == S_OK)
+ unpackSize = size;
+ }
+ }
+ RINOK(updateCallback->SetTotal(unpackSize))
+ CLocalProgress *localProgressSpec = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> localProgress = localProgressSpec;
+ localProgressSpec->Init(updateCallback, true);
+ {
+ NCompress::NBZip2::CEncoder *encoderSpec = new NCompress::NBZip2::CEncoder;
+ CMyComPtr<ICompressCoder> encoder = encoderSpec;
+ RINOK(props.SetCoderProps(encoderSpec, NULL))
+ RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, localProgress))
+ /*
+ if (reportArcProp)
+ {
+ unpackSize = encoderSpec->GetInProcessedSize();
+ RINOK(ReportArcProps(reportArcProp, &unpackSize, &encoderSpec->NumBlocks));
+ }
+ */
+ }
+ }
+ return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
+}
+
+Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType))
+{
+ *timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType;
+ // *timeType = NFileTimeType::kUnix;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *updateCallback))
+{
+ COM_TRY_BEGIN
+
+ if (numItems != 1)
+ return E_INVALIDARG;
+
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IStreamSetRestriction,
+ setRestriction, outStream)
+ if (setRestriction)
+ RINOK(setRestriction->SetRestriction(0, 0))
+ }
+
+ Int32 newData, newProps;
+ UInt32 indexInArchive;
+ if (!updateCallback)
+ return E_FAIL;
+ RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive))
+
+ // Z7_DECL_CMyComPtr_QI_FROM(IArchiveUpdateCallbackArcProp, reportArcProp, updateCallback)
+
+ if (IntToBool(newProps))
+ {
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop))
+ if (prop.vt != VT_EMPTY)
+ if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE)
+ return E_INVALIDARG;
+ }
+ }
+
+ if (IntToBool(newData))
+ {
+ UInt64 size;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidSize, &prop))
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ }
+
+ CMethodProps props2 = _props;
+ #ifndef Z7_ST
+ props2.AddProp_NumThreads(_props._numThreads);
+ #endif
+
+ return UpdateArchive(size, outStream, props2, updateCallback);
+ }
+
+ if (indexInArchive != 0)
+ return E_INVALIDARG;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IArchiveUpdateCallbackFile,
+ opCallback, updateCallback)
+ if (opCallback)
+ {
+ RINOK(opCallback->ReportOperation(
+ NEventIndexType::kInArcIndex, 0,
+ NUpdateNotifyOp::kReplicate))
+ }
+
+ if (_stream)
+ RINOK(InStream_SeekToBegin(_stream))
+
+ return NCompress::CopyStream(_stream, outStream, progress);
+
+ // return ReportArcProps(reportArcProp, NULL, NULL);
+
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
+{
+ return _props.SetProperties(names, values, numProps);
+}
+
+static const Byte k_Signature[] = { 'B', 'Z', 'h' };
+
+REGISTER_ARC_IO(
+ "bzip2", "bz2 bzip2 tbz2 tbz", "* * .tar .tar", 2,
+ k_Signature,
+ 0,
+ NArcInfoFlags::kKeepName
+ , 0
+ , IsArc_BZip2)
+
+}}
diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.cpp b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp
new file mode 100644
index 0000000..dc767a4
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabBlockInStream.cpp
@@ -0,0 +1,100 @@
+// CabBlockInStream.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Alloc.h"
+#include "../../../../C/CpuArch.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "CabBlockInStream.h"
+
+namespace NArchive {
+namespace NCab {
+
+static const UInt32 kBlockSize = (1 << 16);
+
+bool CCabBlockInStream::Create()
+{
+ if (!_buf)
+ _buf = (Byte *)::MyAlloc(kBlockSize);
+ return _buf != NULL;
+}
+
+CCabBlockInStream::~CCabBlockInStream()
+{
+ ::MyFree(_buf);
+}
+
+static UInt32 CheckSum(const Byte *p, UInt32 size)
+{
+ UInt32 sum = 0;
+
+ for (; size >= 8; size -= 8)
+ {
+ sum ^= GetUi32(p) ^ GetUi32(p + 4);
+ p += 8;
+ }
+
+ if (size >= 4)
+ {
+ sum ^= GetUi32(p);
+ p += 4;
+ }
+
+ size &= 3;
+ if (size > 2) sum ^= (UInt32)(*p++) << 16;
+ if (size > 1) sum ^= (UInt32)(*p++) << 8;
+ if (size > 0) sum ^= (UInt32)(*p++);
+
+ return sum;
+}
+
+HRESULT CCabBlockInStream::PreRead(ISequentialInStream *stream, UInt32 &packSize, UInt32 &unpackSize)
+{
+ const UInt32 kHeaderSize = 8;
+ const UInt32 kReservedMax = 256;
+ Byte header[kHeaderSize + kReservedMax];
+ RINOK(ReadStream_FALSE(stream, header, kHeaderSize + ReservedSize))
+ packSize = GetUi16(header + 4);
+ unpackSize = GetUi16(header + 6);
+ if (packSize > kBlockSize - _size)
+ return S_FALSE;
+ RINOK(ReadStream_FALSE(stream, _buf + _size, packSize))
+
+ if (MsZip)
+ {
+ if (_size == 0)
+ {
+ if (packSize < 2 || _buf[0] != 0x43 || _buf[1] != 0x4B)
+ return S_FALSE;
+ _pos = 2;
+ }
+ if (_size + packSize > ((UInt32)1 << 15) + 12) /* v9.31 fix. MSZIP specification */
+ return S_FALSE;
+ }
+
+ if (GetUi32(header) != 0) // checkSum
+ if (CheckSum(header, kHeaderSize + ReservedSize) != CheckSum(_buf + _size, packSize))
+ return S_FALSE;
+
+ _size += packSize;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CCabBlockInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (size != 0)
+ {
+ UInt32 rem = _size - _pos;
+ if (size > rem)
+ size = rem;
+ memcpy(data, _buf + _pos, size);
+ _pos += size;
+ }
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Cab/CabBlockInStream.h b/CPP/7zip/Archive/Cab/CabBlockInStream.h
new file mode 100644
index 0000000..d14fff8
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabBlockInStream.h
@@ -0,0 +1,39 @@
+// CabBlockInStream.h
+
+#ifndef ZIP7_INC_CAB_BLOCK_IN_STREAM_H
+#define ZIP7_INC_CAB_BLOCK_IN_STREAM_H
+
+#include "../../../Common/MyCom.h"
+#include "../../IStream.h"
+
+namespace NArchive {
+namespace NCab {
+
+Z7_CLASS_IMP_NOQIB_1(
+ CCabBlockInStream
+ , ISequentialInStream
+)
+ Byte *_buf;
+ UInt32 _size;
+ UInt32 _pos;
+
+public:
+ UInt32 ReservedSize; // < 256
+ bool MsZip;
+
+ CCabBlockInStream(): _buf(NULL), ReservedSize(0), MsZip(false) {}
+ ~CCabBlockInStream();
+
+ bool Create();
+
+ void InitForNewBlock() { _size = 0; _pos = 0; }
+
+ HRESULT PreRead(ISequentialInStream *stream, UInt32 &packSize, UInt32 &unpackSize);
+
+ UInt32 GetPackSizeAvail() const { return _size - _pos; }
+ const Byte *GetData() const { return _buf + _pos; }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Cab/CabHandler.cpp b/CPP/7zip/Archive/Cab/CabHandler.cpp
new file mode 100644
index 0000000..f015145
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabHandler.cpp
@@ -0,0 +1,1261 @@
+// CabHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../../C/Alloc.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/UTFConvert.h"
+
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/TimeUtils.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 const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidMTime,
+ kpidAttrib,
+ kpidMethod,
+ kpidBlock
+ #ifdef CAB_DETAILS
+ ,
+ // kpidBlockReal, // L"BlockReal",
+ kpidOffset,
+ kpidVolume
+ #endif
+};
+
+static const Byte kArcProps[] =
+{
+ kpidTotalPhySize,
+ kpidMethod,
+ // kpidSolid,
+ kpidNumBlocks,
+ kpidNumVolumes,
+ kpidVolumeIndex,
+ kpidId
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static const char * const kMethods[] =
+{
+ "None"
+ , "MSZip"
+ , "Quantum"
+ , "LZX"
+};
+
+static const unsigned kMethodNameBufSize = 32; // "Quantum:255"
+
+static void SetMethodName(char *s, unsigned method, unsigned param)
+{
+ if (method < Z7_ARRAY_SIZE(kMethods))
+ {
+ s = MyStpCpy(s, kMethods[method]);
+ if (method != NHeader::NMethod::kLZX &&
+ method != NHeader::NMethod::kQuantum)
+ return;
+ *s++ = ':';
+ method = param;
+ }
+ ConvertUInt32ToString(method, s);
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidMethod:
+ {
+ UInt32 mask = 0;
+ UInt32 params[2] = { 0, 0 };
+ {
+ FOR_VECTOR (v, m_Database.Volumes)
+ {
+ const CRecordVector<CFolder> &folders = m_Database.Volumes[v].Folders;
+ FOR_VECTOR (i, folders)
+ {
+ const CFolder &folder = folders[i];
+ unsigned method = folder.GetMethod();
+ mask |= ((UInt32)1 << method);
+ if (method == NHeader::NMethod::kLZX ||
+ method == NHeader::NMethod::kQuantum)
+ {
+ unsigned di = (method == NHeader::NMethod::kQuantum) ? 0 : 1;
+ if (params[di] < folder.MethodMinor)
+ params[di] = folder.MethodMinor;
+ }
+ }
+ }
+ }
+
+ AString s;
+
+ for (unsigned i = 0; i < kNumMethodsMax; i++)
+ {
+ if ((mask & (1 << i)) == 0)
+ continue;
+ s.Add_Space_if_NotEmpty();
+ char temp[kMethodNameBufSize];
+ SetMethodName(temp, i, params[i == NHeader::NMethod::kQuantum ? 0 : 1]);
+ s += temp;
+ }
+
+ prop = s;
+ break;
+ }
+ // case kpidSolid: prop = _database.IsSolid(); break;
+ case kpidNumBlocks:
+ {
+ UInt32 numFolders = 0;
+ FOR_VECTOR (v, m_Database.Volumes)
+ numFolders += m_Database.Volumes[v].Folders.Size();
+ prop = numFolders;
+ break;
+ }
+
+ case kpidTotalPhySize:
+ {
+ if (m_Database.Volumes.Size() > 1)
+ {
+ UInt64 sum = 0;
+ FOR_VECTOR (v, m_Database.Volumes)
+ sum += m_Database.Volumes[v].ArcInfo.Size;
+ prop = sum;
+ }
+ break;
+ }
+
+ case kpidNumVolumes:
+ prop = (UInt32)m_Database.Volumes.Size();
+ break;
+
+ case kpidVolumeIndex:
+ {
+ if (!m_Database.Volumes.IsEmpty())
+ {
+ const CDatabaseEx &db = m_Database.Volumes[0];
+ const CInArcInfo &ai = db.ArcInfo;
+ prop = (UInt32)ai.CabinetNumber;
+ }
+ break;
+ }
+
+ case kpidId:
+ {
+ if (m_Database.Volumes.Size() != 0)
+ {
+ prop = (UInt32)m_Database.Volumes[0].ArcInfo.SetID;
+ }
+ break;
+ }
+
+ case kpidOffset:
+ /*
+ if (m_Database.Volumes.Size() == 1)
+ prop = m_Database.Volumes[0].StartPosition;
+ */
+ prop = _offset;
+ break;
+
+ case kpidPhySize:
+ /*
+ if (m_Database.Volumes.Size() == 1)
+ prop = (UInt64)m_Database.Volumes[0].ArcInfo.Size;
+ */
+ prop = (UInt64)_phySize;
+ break;
+
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (_errorInHeaders) v |= kpv_ErrorFlags_HeadersError;
+ if (_unexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
+ prop = v;
+ break;
+ }
+
+ case kpidError:
+ if (!_errorMessage.IsEmpty())
+ prop = _errorMessage;
+ break;
+
+ case kpidName:
+ {
+ if (m_Database.Volumes.Size() == 1)
+ {
+ const CDatabaseEx &db = m_Database.Volumes[0];
+ const CInArcInfo &ai = db.ArcInfo;
+ if (ai.SetID != 0)
+ {
+ AString s;
+ s.Add_UInt32(ai.SetID);
+ s += '_';
+ s.Add_UInt32(ai.CabinetNumber + 1);
+ s += ".cab";
+ prop = s;
+ }
+ /*
+ // that code is incomplete. It gcan give accurate name of volume
+ char s[32];
+ ConvertUInt32ToString(ai.CabinetNumber + 2, s);
+ unsigned len = MyStringLen(s);
+ if (ai.IsThereNext())
+ {
+ AString fn = ai.NextArc.FileName;
+ if (fn.Len() > 4 && StringsAreEqualNoCase_Ascii(fn.RightPtr(4), ".cab"))
+ fn.DeleteFrom(fn.Len() - 4);
+ if (len < fn.Len())
+ {
+ if (strcmp(s, fn.RightPtr(len)) == 0)
+ {
+ AString s2 = fn;
+ s2.DeleteFrom(fn.Len() - len);
+ ConvertUInt32ToString(ai.CabinetNumber + 1, s);
+ s2 += s;
+ s2 += ".cab";
+ prop = GetUnicodeString(s2);
+ }
+ }
+ }
+ */
+ }
+ break;
+ }
+
+ // case kpidShortComment:
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ const CMvItem &mvItem = m_Database.Items[index];
+ const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex];
+ unsigned 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::WinPathToOsPath(unicodeName);
+ break;
+ }
+
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: prop = item.Size; break;
+ case kpidAttrib: prop = item.GetWinAttrib(); break;
+
+ case kpidMTime:
+ {
+ PropVariant_SetFrom_DosTime(prop, item.Time);
+ break;
+ }
+
+ case kpidMethod:
+ {
+ const int realFolderIndex = item.GetFolderIndex(db.Folders.Size());
+ if (realFolderIndex >= 0)
+ {
+ const CFolder &folder = db.Folders[(unsigned)realFolderIndex];
+ char s[kMethodNameBufSize];
+ SetMethodName(s, folder.GetMethod(), folder.MethodMinor);
+ prop = s;
+ }
+ break;
+ }
+
+ case kpidBlock: prop.Set_Int32((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
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ Close();
+
+ CInArchive archive;
+ CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+ if (callback)
+ callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
+
+ CMyComPtr<IInStream> nextStream = inStream;
+ bool prevChecked = false;
+ UString startVolName;
+ bool startVolName_was_Requested = false;
+ UInt64 numItems = 0;
+ unsigned numTempVolumes = 0;
+ // try
+ {
+ while (nextStream)
+ {
+ CDatabaseEx db;
+ db.Stream = nextStream;
+
+ HRESULT res = archive.Open(db, maxCheckStartPosition);
+
+ _errorInHeaders |= archive.HeaderError;
+ _errorInHeaders |= archive.ErrorInNames;
+ _unexpectedEnd |= archive.UnexpectedEnd;
+
+ if (res == S_OK && !m_Database.Volumes.IsEmpty())
+ {
+ const CArchInfo &lastArc = m_Database.Volumes.Back().ArcInfo;
+ unsigned cabNumber = db.ArcInfo.CabinetNumber;
+ if (lastArc.SetID != db.ArcInfo.SetID)
+ res = S_FALSE;
+ else if (prevChecked)
+ {
+ if (cabNumber != lastArc.CabinetNumber + 1)
+ res = S_FALSE;
+ }
+ else if (cabNumber >= lastArc.CabinetNumber)
+ res = S_FALSE;
+ else if (numTempVolumes != 0)
+ {
+ const CArchInfo &prevArc = m_Database.Volumes[numTempVolumes - 1].ArcInfo;
+ if (cabNumber != prevArc.CabinetNumber + 1)
+ res = S_FALSE;
+ }
+ }
+
+ if (archive.IsArc || res == S_OK)
+ {
+ _isArc = true;
+ if (m_Database.Volumes.IsEmpty())
+ {
+ _offset = db.StartPosition;
+ _phySize = db.ArcInfo.Size;
+ }
+ }
+
+ if (res == S_OK)
+ {
+ numItems += db.Items.Size();
+ m_Database.Volumes.Insert(prevChecked ? m_Database.Volumes.Size() : numTempVolumes, db);
+ if (!prevChecked && m_Database.Volumes.Size() > 1)
+ {
+ numTempVolumes++;
+ if (db.ArcInfo.CabinetNumber + 1 == m_Database.Volumes[numTempVolumes].ArcInfo.CabinetNumber)
+ numTempVolumes = 0;
+ }
+ }
+ else
+ {
+ if (res != S_FALSE)
+ return res;
+ if (m_Database.Volumes.IsEmpty())
+ return S_FALSE;
+ if (prevChecked)
+ break;
+ prevChecked = true;
+ if (numTempVolumes != 0)
+ {
+ m_Database.Volumes.DeleteFrontal(numTempVolumes);
+ numTempVolumes = 0;
+ }
+ }
+
+ if (callback)
+ {
+ RINOK(callback->SetCompleted(&numItems, NULL))
+ }
+
+ nextStream = NULL;
+
+ for (;;)
+ {
+ const COtherArc *otherArc = NULL;
+
+ if (!prevChecked)
+ {
+ if (numTempVolumes == 0)
+ {
+ const CInArcInfo &ai = m_Database.Volumes[0].ArcInfo;
+ if (ai.IsTherePrev())
+ otherArc = &ai.PrevArc;
+ else
+ prevChecked = true;
+ }
+ else
+ {
+ const CInArcInfo &ai = m_Database.Volumes[numTempVolumes - 1].ArcInfo;
+ if (ai.IsThereNext())
+ otherArc = &ai.NextArc;
+ else
+ {
+ prevChecked = true;
+ m_Database.Volumes.DeleteFrontal(numTempVolumes);
+ numTempVolumes = 0;
+ }
+ }
+ }
+
+ if (!otherArc)
+ {
+ const CInArcInfo &ai = m_Database.Volumes.Back().ArcInfo;
+ if (ai.IsThereNext())
+ otherArc = &ai.NextArc;
+ }
+
+ if (!otherArc)
+ break;
+ if (!openVolumeCallback)
+ break;
+ // printf("\n%s", otherArc->FileName);
+ const UString fullName = MultiByteToUnicodeString(otherArc->FileName, CP_ACP);
+
+ if (!startVolName_was_Requested)
+ {
+ // some "bad" cab example can contain the link to itself.
+ startVolName_was_Requested = true;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(openVolumeCallback->GetProperty(kpidName, &prop))
+ if (prop.vt == VT_BSTR)
+ startVolName = prop.bstrVal;
+ }
+ if (fullName == startVolName)
+ break;
+ }
+
+ HRESULT result = openVolumeCallback->GetStream(fullName, &nextStream);
+ if (result == S_OK)
+ break;
+ if (result != S_FALSE)
+ return result;
+
+ if (!_errorMessage.IsEmpty())
+ _errorMessage.Add_LF();
+ _errorMessage += "Can't open volume: ";
+ _errorMessage += fullName;
+
+ if (prevChecked)
+ break;
+ prevChecked = true;
+ if (numTempVolumes != 0)
+ {
+ m_Database.Volumes.DeleteFrontal(numTempVolumes);
+ numTempVolumes = 0;
+ }
+ }
+
+ } // read nextStream iteration
+
+ if (numTempVolumes != 0)
+ {
+ m_Database.Volumes.DeleteFrontal(numTempVolumes);
+ numTempVolumes = 0;
+ }
+ if (m_Database.Volumes.IsEmpty())
+ return S_FALSE;
+ else
+ {
+ m_Database.FillSortAndShrink();
+ if (!m_Database.Check())
+ return S_FALSE;
+ }
+ }
+ COM_TRY_END
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _errorMessage.Empty();
+ _isArc = false;
+ _errorInHeaders = false;
+ _unexpectedEnd = false;
+ // _mainVolIndex = -1;
+ _phySize = 0;
+ _offset = 0;
+
+ m_Database.Clear();
+ return S_OK;
+}
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ CFolderOutStream
+ , ISequentialOutStream
+)
+ const CMvDatabaseEx *m_Database;
+ const CRecordVector<bool> *m_ExtractStatuses;
+
+ Byte *TempBuf;
+ UInt32 TempBufSize;
+ UInt32 TempBufWritten;
+ unsigned NumIdenticalFiles;
+ bool TempBufMode;
+
+ unsigned m_StartIndex;
+ unsigned 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();
+public:
+ HRESULT WriteEmptyFiles();
+
+ CFolderOutStream(): TempBuf(NULL) {}
+ ~CFolderOutStream() { FreeTempBuf(); }
+ void Init(
+ const CMvDatabaseEx *database,
+ const CRecordVector<bool> *extractStatuses,
+ unsigned startIndex,
+ UInt64 folderSize,
+ IArchiveExtractCallback *extractCallback,
+ bool testMode);
+ HRESULT FlushCorrupted(unsigned folderIndex);
+ HRESULT Unsupported();
+
+ bool NeedMoreWrite() const { return (m_FolderSize > m_PosInFolder); }
+ UInt64 GetRemain() const { return m_FolderSize - m_PosInFolder; }
+ UInt64 GetPosInFolder() const { return m_PosInFolder; }
+};
+
+
+void CFolderOutStream::Init(
+ const CMvDatabaseEx *database,
+ const CRecordVector<bool> *extractStatuses,
+ unsigned 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];
+ unsigned numExtractItems = 0;
+ unsigned 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)
+ return E_OUTOFMEMORY;
+ }
+ TempBufMode = true;
+ TempBufWritten = 0;
+ }
+ 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;
+}
+
+
+Z7_COM7F_IMF(CFolderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ // (data == NULL) means Error_Data for solid folder flushing
+ COM_TRY_BEGIN
+
+ UInt32 realProcessed = 0;
+ if (processedSize)
+ *processedSize = 0;
+
+ while (size != 0)
+ {
+ if (m_FileIsOpen)
+ {
+ UInt32 numBytesToWrite = MyMin(m_RemainFileSize, size);
+ HRESULT res = S_OK;
+ if (numBytesToWrite != 0)
+ {
+ if (!data)
+ m_IsOk = false;
+
+ if (m_RealOutStream)
+ {
+ UInt32 processedSizeLocal = 0;
+ // 18.01 : we don't want ZEROs instead of missing data
+ if (data)
+ res = m_RealOutStream->Write((const Byte *)data, numBytesToWrite, &processedSizeLocal);
+ else
+ processedSizeLocal = numBytesToWrite;
+ numBytesToWrite = processedSizeLocal;
+ }
+
+ if (TempBufMode && TempBuf)
+ {
+ if (data)
+ {
+ memcpy(TempBuf + TempBufWritten, data, numBytesToWrite);
+ TempBufWritten += numBytesToWrite;
+ }
+ }
+ }
+ realProcessed += numBytesToWrite;
+ if (processedSize)
+ *processedSize = realProcessed;
+ if (data)
+ 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, TempBufWritten);
+
+ 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())
+ {
+ // we ignore extra data;
+ realProcessed += size;
+ if (processedSize)
+ *processedSize = realProcessed;
+ m_PosInFolder += size;
+ return S_OK;
+ // 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)
+ *processedSize = realProcessed;
+ if (data)
+ 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
+}
+
+
+HRESULT CFolderOutStream::FlushCorrupted(unsigned folderIndex)
+{
+ if (!NeedMoreWrite())
+ {
+ CMyComPtr<IArchiveExtractCallbackMessage2> callbackMessage;
+ m_ExtractCallback.QueryInterface(IID_IArchiveExtractCallbackMessage2, &callbackMessage);
+ if (callbackMessage)
+ {
+ RINOK(callbackMessage->ReportExtractResult(NEventIndexType::kBlockIndex, folderIndex, NExtract::NOperationResult::kDataError))
+ }
+ return S_OK;
+ }
+
+ for (;;)
+ {
+ if (!NeedMoreWrite())
+ return S_OK;
+ UInt64 remain = GetRemain();
+ UInt32 size = (UInt32)1 << 20;
+ if (size > remain)
+ size = (UInt32)remain;
+ UInt32 processedSizeLocal = 0;
+ RINOK(Write(NULL, size, &processedSizeLocal))
+ }
+}
+
+
+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;
+}
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testModeSpec, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-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++)
+ {
+ unsigned 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<IUnknown> lzxDecoder;
+
+ NCompress::NQuantum::CDecoder *quantumDecoderSpec = NULL;
+ CMyComPtr<IUnknown> quantumDecoder;
+
+ CCabBlockInStream *cabBlockInStreamSpec = new CCabBlockInStream();
+ CMyComPtr<ISequentialInStream> cabBlockInStream = cabBlockInStreamSpec;
+ if (!cabBlockInStreamSpec->Create())
+ return E_OUTOFMEMORY;
+
+ CRecordVector<bool> extractStatuses;
+
+ for (i = 0;;)
+ {
+ lps->OutSize = totalUnPacked;
+ lps->InSize = totalPacked;
+ RINOK(lps->SetCur())
+
+ if (i >= numItems)
+ break;
+
+ const unsigned index = allFilesMode ? i : indices[i];
+
+ const CMvItem &mvItem = m_Database.Items[index];
+ const CDatabaseEx &db = m_Database.Volumes[mvItem.VolumeIndex];
+ const unsigned itemIndex = mvItem.ItemIndex;
+ const CItem &item = db.Items[itemIndex];
+
+ i++;
+ if (item.IsDir())
+ {
+ const 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;
+ }
+
+ const int folderIndex = m_Database.GetFolderIndex(&mvItem);
+
+ if (folderIndex < 0)
+ {
+ // If we need previous archive
+ const 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;
+ }
+
+ const unsigned startIndex2 = m_Database.FolderStartFileIndex[(unsigned)folderIndex];
+ unsigned startIndex = startIndex2;
+ extractStatuses.Clear();
+ for (; startIndex < index; startIndex++)
+ extractStatuses.Add(false);
+ extractStatuses.Add(true);
+ startIndex++;
+ UInt64 curUnpack = item.GetEndOffset();
+
+ for (; i < numItems; i++)
+ {
+ const unsigned indexNext = allFilesMode ? i : indices[i];
+ const CMvItem &mvItem2 = m_Database.Items[indexNext];
+ const CItem &item2 = m_Database.Volumes[mvItem2.VolumeIndex].Items[mvItem2.ItemIndex];
+ if (item2.IsDir())
+ continue;
+ const int newFolderIndex = m_Database.GetFolderIndex(&mvItem2);
+
+ if (newFolderIndex != folderIndex)
+ break;
+ for (; startIndex < indexNext; startIndex++)
+ extractStatuses.Add(false);
+ extractStatuses.Add(true);
+ startIndex++;
+ curUnpack = item2.GetEndOffset();
+ }
+
+ CFolderOutStream *cabFolderOutStream = new CFolderOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(cabFolderOutStream);
+
+ const int folderIndex2 = item.GetFolderIndex(db.Folders.Size());
+ if (folderIndex2 < 0)
+ return E_FAIL;
+ const CFolder &folder = db.Folders[(unsigned)folderIndex2];
+
+ cabFolderOutStream->Init(&m_Database, &extractStatuses, startIndex2,
+ curUnpack, extractCallback, testMode);
+
+ cabBlockInStreamSpec->MsZip = false;
+ HRESULT res = S_OK;
+
+ switch (folder.GetMethod())
+ {
+ case NHeader::NMethod::kNone:
+ break;
+
+ case NHeader::NMethod::kMSZip:
+ if (!deflateDecoder)
+ {
+ deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder;
+ deflateDecoder = deflateDecoderSpec;
+ }
+ cabBlockInStreamSpec->MsZip = true;
+ break;
+
+ case NHeader::NMethod::kLZX:
+ if (!lzxDecoder)
+ {
+ lzxDecoderSpec = new NCompress::NLzx::CDecoder;
+ lzxDecoder = lzxDecoderSpec;
+ }
+ res = lzxDecoderSpec->SetParams_and_Alloc(folder.MethodMinor);
+ break;
+
+ case NHeader::NMethod::kQuantum:
+ if (!quantumDecoder)
+ {
+ quantumDecoderSpec = new NCompress::NQuantum::CDecoder;
+ quantumDecoder = quantumDecoderSpec;
+ }
+ res = quantumDecoderSpec->SetParams(folder.MethodMinor);
+ break;
+
+ default:
+ res = E_INVALIDARG;
+ break;
+ }
+
+ if (res == E_INVALIDARG)
+ {
+ RINOK(cabFolderOutStream->Unsupported())
+ totalUnPacked += curUnpack;
+ continue;
+ }
+ RINOK(res)
+
+ {
+ unsigned volIndex = mvItem.VolumeIndex;
+ int locFolderIndex = item.GetFolderIndex(db.Folders.Size());
+ bool keepHistory = false;
+ bool keepInputBuffer = false;
+ bool thereWasNotAlignedChunk = false;
+
+ for (UInt32 bl = 0; cabFolderOutStream->NeedMoreWrite();)
+ {
+ if (volIndex >= m_Database.Volumes.Size())
+ {
+ res = S_FALSE;
+ break;
+ }
+
+ const CDatabaseEx &db2 = m_Database.Volumes[volIndex];
+ if (locFolderIndex < 0)
+ return E_FAIL;
+ const CFolder &folder2 = db2.Folders[(unsigned)locFolderIndex];
+
+ if (bl == 0)
+ {
+ cabBlockInStreamSpec->ReservedSize = db2.ArcInfo.GetDataBlockReserveSize();
+ RINOK(InStream_SeekSet(db2.Stream, db2.StartPosition + folder2.DataStart))
+ }
+
+ if (bl == folder2.NumDataBlocks)
+ {
+ /*
+ CFolder::NumDataBlocks (CFFOLDER::cCFData in CAB specification) is 16-bit.
+ But there are some big CAB archives from MS that contain more
+ than (0xFFFF) CFDATA blocks in folder.
+ Old cab extracting software can show error (or ask next volume)
+ but cab extracting library in new Windows ignores this error.
+ 15.00 : We also try to ignore such error, if archive is not multi-volume.
+ */
+ if (m_Database.Volumes.Size() > 1)
+ {
+ volIndex++;
+ locFolderIndex = 0;
+ bl = 0;
+ continue;
+ }
+ }
+
+ bl++;
+
+ if (!keepInputBuffer)
+ cabBlockInStreamSpec->InitForNewBlock();
+
+ UInt32 packSize, unpackSize;
+ res = cabBlockInStreamSpec->PreRead(db2.Stream, 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())
+
+ const UInt32 kBlockSizeMax = (1 << 15);
+
+ /* We don't try to reduce last block.
+ Note that LZX converts data with x86 filter.
+ and filter needs larger input data than reduced size.
+ It's simpler to decompress full chunk here.
+ also we need full block for quantum for more integrity checks */
+
+ if (unpackSize > kBlockSizeMax)
+ {
+ res = S_FALSE;
+ break;
+ }
+
+ if (unpackSize != kBlockSizeMax)
+ {
+ if (thereWasNotAlignedChunk)
+ {
+ res = S_FALSE;
+ break;
+ }
+ thereWasNotAlignedChunk = true;
+ }
+
+ UInt64 unpackSize64 = unpackSize;
+ UInt32 packSizeChunk = cabBlockInStreamSpec->GetPackSizeAvail();
+
+ switch (folder2.GetMethod())
+ {
+ case NHeader::NMethod::kNone:
+ res = copyCoder->Code(cabBlockInStream, outStream, NULL, &unpackSize64, NULL);
+ break;
+
+ case NHeader::NMethod::kMSZip:
+ deflateDecoderSpec->Set_KeepHistory(keepHistory);
+ /* v9.31: now we follow MSZIP specification that requires to finish deflate stream at the end of each block.
+ But PyCabArc can create CAB archives that doesn't have finish marker at the end of block.
+ Cabarc probably ignores such errors in cab archives.
+ Maybe we also should ignore that error?
+ Or we should extract full file and show the warning? */
+ deflateDecoderSpec->Set_NeedFinishInput(true);
+ res = deflateDecoder->Code(cabBlockInStream, outStream, NULL, &unpackSize64, NULL);
+ if (res == S_OK)
+ {
+ if (!deflateDecoderSpec->IsFinished())
+ res = S_FALSE;
+ if (!deflateDecoderSpec->IsFinalBlock())
+ res = S_FALSE;
+ }
+ break;
+
+ case NHeader::NMethod::kLZX:
+ lzxDecoderSpec->SetKeepHistory(keepHistory);
+ lzxDecoderSpec->KeepHistoryForNext = true;
+
+ res = lzxDecoderSpec->Code(cabBlockInStreamSpec->GetData(), packSizeChunk, unpackSize);
+
+ if (res == S_OK)
+ res = WriteStream(outStream,
+ lzxDecoderSpec->GetUnpackData(),
+ lzxDecoderSpec->GetUnpackSize());
+ break;
+
+ case NHeader::NMethod::kQuantum:
+ res = quantumDecoderSpec->Code(cabBlockInStreamSpec->GetData(),
+ packSizeChunk, outStream, unpackSize, keepHistory);
+ 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->NeedMoreWrite())
+ {
+ RINOK(cabFolderOutStream->FlushCorrupted((unsigned)folderIndex2))
+ }
+
+ totalUnPacked += curUnpack;
+ }
+
+ return S_OK;
+
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = m_Database.Items.Size();
+ return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Cab/CabHandler.h b/CPP/7zip/Archive/Cab/CabHandler.h
new file mode 100644
index 0000000..1e1811f
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabHandler.h
@@ -0,0 +1,29 @@
+// CabHandler.h
+
+#ifndef ZIP7_INC_CAB_HANDLER_H
+#define ZIP7_INC_CAB_HANDLER_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../IArchive.h"
+
+#include "CabIn.h"
+
+namespace NArchive {
+namespace NCab {
+
+Z7_CLASS_IMP_CHandler_IInArchive_0
+
+ CMvDatabaseEx m_Database;
+ UString _errorMessage;
+ bool _isArc;
+ bool _errorInHeaders;
+ bool _unexpectedEnd;
+ // int _mainVolIndex;
+ UInt32 _phySize;
+ UInt64 _offset;
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Cab/CabHeader.cpp b/CPP/7zip/Archive/Cab/CabHeader.cpp
new file mode 100644
index 0000000..370a2f1
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabHeader.cpp
@@ -0,0 +1,15 @@
+// CabHeader.cpp
+
+#include "StdAfx.h"
+
+#include "CabHeader.h"
+
+namespace NArchive {
+namespace NCab {
+namespace NHeader {
+
+const Byte kMarker[kMarkerSize] = {'M', 'S', 'C', 'F', 0, 0, 0, 0 };
+
+// struct CSignatureInitializer { CSignatureInitializer() { kMarker[0]--; } } g_SignatureInitializer;
+
+}}}
diff --git a/CPP/7zip/Archive/Cab/CabHeader.h b/CPP/7zip/Archive/Cab/CabHeader.h
new file mode 100644
index 0000000..ecb9a87
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabHeader.h
@@ -0,0 +1,41 @@
+// Archive/CabHeader.h
+
+#ifndef ZIP7_INC_ARCHIVE_CAB_HEADER_H
+#define ZIP7_INC_ARCHIVE_CAB_HEADER_H
+
+#include "../../../Common/MyTypes.h"
+
+namespace NArchive {
+namespace NCab {
+namespace NHeader {
+
+const unsigned kMarkerSize = 8;
+extern const Byte kMarker[kMarkerSize];
+
+namespace NArcFlags
+{
+ const unsigned kPrevCabinet = 1;
+ const unsigned kNextCabinet = 2;
+ const unsigned kReservePresent = 4;
+}
+
+namespace NMethod
+{
+ const Byte kNone = 0;
+ const Byte kMSZip = 1;
+ const Byte kQuantum = 2;
+ const Byte kLZX = 3;
+}
+
+const unsigned kFileNameIsUtf8_Mask = 0x80;
+
+namespace NFolderIndex
+{
+ const unsigned kContinuedFromPrev = 0xFFFD;
+ const unsigned kContinuedToNext = 0xFFFE;
+ const unsigned kContinuedPrevAndNext = 0xFFFF;
+}
+
+}}}
+
+#endif
diff --git a/CPP/7zip/Archive/Cab/CabIn.cpp b/CPP/7zip/Archive/Cab/CabIn.cpp
new file mode 100644
index 0000000..fb69643
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabIn.cpp
@@ -0,0 +1,491 @@
+// Archive/CabIn.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/StreamUtils.h"
+
+#include "CabIn.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
+namespace NArchive {
+namespace NCab {
+
+struct CUnexpectedEndException {};
+
+void CInArchive::Skip(unsigned size)
+{
+ if (_inBuffer.Skip(size) != size)
+ throw CUnexpectedEndException();
+}
+
+void CInArchive::Read(Byte *data, unsigned size)
+{
+ if (_inBuffer.ReadBytes(data, size) != size)
+ throw CUnexpectedEndException();
+}
+
+void CInArchive::ReadName(AString &s)
+{
+ for (size_t i = 0; i < ((size_t)1 << 13); i++)
+ {
+ Byte b;
+ if (!_inBuffer.ReadByte(b))
+ throw CUnexpectedEndException();
+ if (b == 0)
+ {
+ s.SetFrom((const char *)(const Byte *)_tempBuf, (unsigned)i);
+ return;
+ }
+ if (_tempBuf.Size() == i)
+ _tempBuf.ChangeSize_KeepData(i * 2, i);
+ _tempBuf[i] = b;
+ }
+
+ for (;;)
+ {
+ Byte b;
+ if (!_inBuffer.ReadByte(b))
+ throw CUnexpectedEndException();
+ if (b == 0)
+ break;
+ }
+
+ ErrorInNames = true;
+ s = "[ERROR-LONG-PATH]";
+}
+
+void CInArchive::ReadOtherArc(COtherArc &oa)
+{
+ ReadName(oa.FileName);
+ ReadName(oa.DiskName);
+}
+
+
+struct CSignatureFinder
+{
+ Byte *Buf;
+ UInt32 Pos;
+ UInt32 End;
+ const Byte *Signature;
+ UInt32 SignatureSize;
+
+ UInt32 _headerSize;
+ UInt32 _alignSize;
+ UInt32 _bufUseCapacity;
+
+ ISequentialInStream *Stream;
+ UInt64 Processed; // Global offset of start of Buf
+
+ const UInt64 *SearchLimit;
+
+ UInt32 GetTotalCapacity(UInt32 basicSize, UInt32 headerSize)
+ {
+ _headerSize = headerSize;
+ for (_alignSize = (1 << 5); _alignSize < _headerSize; _alignSize <<= 1);
+ _bufUseCapacity = basicSize + _alignSize;
+ return _bufUseCapacity + 16;
+ }
+
+ /*
+ returns:
+ S_OK - signature found (at Pos)
+ S_FALSE - signature not found
+ */
+ HRESULT Find();
+};
+
+
+HRESULT CSignatureFinder::Find()
+{
+ for (;;)
+ {
+ Buf[End] = Signature[0]; // it's for fast search;
+
+ while (End - Pos >= _headerSize)
+ {
+ const Byte *p = Buf + Pos;
+ Byte b = Signature[0];
+ for (;;)
+ {
+ if (*p == b) { break; } p++;
+ if (*p == b) { break; } p++;
+ }
+ Pos = (UInt32)(p - Buf);
+ if (End - Pos < _headerSize)
+ {
+ Pos = End - _headerSize + 1;
+ break;
+ }
+ UInt32 i;
+ for (i = 1; i < SignatureSize && p[i] == Signature[i]; i++);
+ if (i == SignatureSize)
+ return S_OK;
+ Pos++;
+ }
+
+ if (Pos >= _alignSize)
+ {
+ UInt32 num = (Pos & ~(_alignSize - 1));
+ Processed += num;
+ Pos -= num;
+ End -= num;
+ memmove(Buf, Buf + num, End);
+ }
+ UInt32 rem = _bufUseCapacity - End;
+ if (SearchLimit)
+ {
+ if (Processed + Pos > *SearchLimit)
+ return S_FALSE;
+ UInt64 rem2 = *SearchLimit - (Processed + End) + _headerSize;
+ if (rem > rem2)
+ rem = (UInt32)rem2;
+ }
+
+ UInt32 processedSize;
+ if (Processed == 0 && rem == _bufUseCapacity - _headerSize)
+ rem -= _alignSize; // to make reads more aligned.
+ RINOK(Stream->Read(Buf + End, rem, &processedSize))
+ if (processedSize == 0)
+ return S_FALSE;
+ End += processedSize;
+ }
+}
+
+
+bool CInArcInfo::Parse(const Byte *p)
+{
+ if (Get32(p + 0x0C) != 0 ||
+ Get32(p + 0x14) != 0)
+ return false;
+ Size = Get32(p + 8);
+ if (Size < 36)
+ return false;
+ Flags = Get16(p + 0x1E);
+ if (Flags > 7)
+ return false;
+ FileHeadersOffset = Get32(p + 0x10);
+ if (FileHeadersOffset != 0 && FileHeadersOffset > Size)
+ return false;
+ VersionMinor = p[0x18];
+ VersionMajor = p[0x19];
+ NumFolders = Get16(p + 0x1A);
+ NumFiles = Get16(p + 0x1C);
+ return true;
+}
+
+
+HRESULT CInArchive::Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit)
+{
+ IsArc = false;
+ ErrorInNames = false;
+ UnexpectedEnd = false;
+ HeaderError = false;
+
+ db.Clear();
+ RINOK(InStream_GetPos(db.Stream, db.StartPosition))
+ // UInt64 temp = db.StartPosition;
+
+ CByteBuffer buffer;
+ CInArcInfo &ai = db.ArcInfo;
+ UInt64 startInBuf = 0;
+
+ CLimitedSequentialInStream *limitedStreamSpec = NULL;
+ CMyComPtr<ISequentialInStream> limitedStream;
+
+ // for (int iii = 0; iii < 10000; iii++)
+ {
+ // db.StartPosition = temp; RINOK(InStream_SeekSet(db.Stream, db.StartPosition))
+
+ const UInt32 kMainHeaderSize = 32;
+ Byte header[kMainHeaderSize];
+ const UInt32 kBufSize = 1 << 15;
+ RINOK(ReadStream_FALSE(db.Stream, header, kMainHeaderSize))
+ if (memcmp(header, NHeader::kMarker, NHeader::kMarkerSize) == 0 && ai.Parse(header))
+ {
+ limitedStreamSpec = new CLimitedSequentialInStream;
+ limitedStream = limitedStreamSpec;
+ limitedStreamSpec->SetStream(db.Stream);
+ limitedStreamSpec->Init(ai.Size - NHeader::kMarkerSize);
+ buffer.Alloc(kBufSize);
+ memcpy(buffer, header, kMainHeaderSize);
+ UInt32 numProcessedBytes;
+ RINOK(limitedStream->Read(buffer + kMainHeaderSize, kBufSize - kMainHeaderSize, &numProcessedBytes))
+ _inBuffer.SetBuf(buffer, (UInt32)kBufSize, kMainHeaderSize + numProcessedBytes, kMainHeaderSize);
+ }
+ else
+ {
+ if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0)
+ return S_FALSE;
+
+ CSignatureFinder finder;
+
+ finder.Stream = db.Stream;
+ finder.Signature = NHeader::kMarker;
+ finder.SignatureSize = NHeader::kMarkerSize;
+ finder.SearchLimit = searchHeaderSizeLimit;
+
+ buffer.Alloc(finder.GetTotalCapacity(kBufSize, kMainHeaderSize));
+ finder.Buf = buffer;
+
+ memcpy(buffer, header, kMainHeaderSize);
+ finder.Processed = db.StartPosition;
+ finder.End = kMainHeaderSize;
+ finder.Pos = 1;
+
+ for (;;)
+ {
+ RINOK(finder.Find())
+ if (ai.Parse(finder.Buf + finder.Pos))
+ {
+ db.StartPosition = finder.Processed + finder.Pos;
+ limitedStreamSpec = new CLimitedSequentialInStream;
+ limitedStreamSpec->SetStream(db.Stream);
+ limitedStream = limitedStreamSpec;
+ UInt32 remInFinder = finder.End - finder.Pos;
+ if (ai.Size <= remInFinder)
+ {
+ limitedStreamSpec->Init(0);
+ finder.End = finder.Pos + ai.Size;
+ }
+ else
+ limitedStreamSpec->Init(ai.Size - remInFinder);
+
+ startInBuf = finder.Pos;
+ _inBuffer.SetBuf(buffer, (UInt32)kBufSize, finder.End, finder.Pos + kMainHeaderSize);
+ break;
+ }
+ finder.Pos++;
+ }
+ }
+ }
+
+ IsArc = true;
+
+ _inBuffer.SetStream(limitedStream);
+ if (_tempBuf.Size() == 0)
+ _tempBuf.Alloc(1 << 12);
+
+ Byte p[16];
+ unsigned nextSize = 4 + (ai.ReserveBlockPresent() ? 4 : 0);
+ Read(p, nextSize);
+ ai.SetID = Get16(p);
+ ai.CabinetNumber = Get16(p + 2);
+
+ if (ai.ReserveBlockPresent())
+ {
+ ai.PerCabinet_AreaSize = Get16(p + 4);
+ ai.PerFolder_AreaSize = p[6];
+ ai.PerDataBlock_AreaSize = p[7];
+ Skip(ai.PerCabinet_AreaSize);
+ }
+
+ if (ai.IsTherePrev()) ReadOtherArc(ai.PrevArc);
+ if (ai.IsThereNext()) ReadOtherArc(ai.NextArc);
+
+ UInt32 i;
+
+ db.Folders.ClearAndReserve(ai.NumFolders);
+
+ for (i = 0; i < ai.NumFolders; i++)
+ {
+ Read(p, 8);
+ CFolder folder;
+ folder.DataStart = Get32(p);
+ folder.NumDataBlocks = Get16(p + 4);
+ folder.MethodMajor = p[6];
+ folder.MethodMinor = p[7];
+ Skip(ai.PerFolder_AreaSize);
+ db.Folders.AddInReserved(folder);
+ }
+
+ // for (int iii = 0; iii < 10000; iii++) {
+
+ if (_inBuffer.GetProcessedSize() - startInBuf != ai.FileHeadersOffset)
+ {
+ // printf("\n!!! Seek Error !!!!\n");
+ // fflush(stdout);
+ RINOK(InStream_SeekSet(db.Stream, db.StartPosition + ai.FileHeadersOffset))
+ limitedStreamSpec->Init(ai.Size - ai.FileHeadersOffset);
+ _inBuffer.Init();
+ }
+
+ db.Items.ClearAndReserve(ai.NumFiles);
+
+ for (i = 0; i < ai.NumFiles; i++)
+ {
+ Read(p, 16);
+ CItem &item = db.Items.AddNewInReserved();
+ item.Size = Get32(p);
+ item.Offset = Get32(p + 4);
+ item.FolderIndex = Get16(p + 8);
+ UInt16 pureDate = Get16(p + 10);
+ UInt16 pureTime = Get16(p + 12);
+ item.Time = (((UInt32)pureDate << 16)) | pureTime;
+ item.Attributes = Get16(p + 14);
+
+ ReadName(item.Name);
+
+ if (item.GetFolderIndex(db.Folders.Size()) >= (int)db.Folders.Size())
+ {
+ HeaderError = true;
+ return S_FALSE;
+ }
+ }
+
+ // }
+
+ return S_OK;
+}
+
+
+HRESULT CInArchive::Open(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit)
+{
+ try
+ {
+ return Open2(db, searchHeaderSizeLimit);
+ }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(CUnexpectedEndException &) { UnexpectedEnd = true; return S_FALSE; }
+}
+
+
+
+#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(unsigned i1, unsigned 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_VECTOR (v, Volumes)
+ {
+ const CDatabaseEx &db = Volumes[v];
+ int curOffset = offset;
+ if (db.IsTherePrevFolder())
+ curOffset--;
+ StartFolderOfVol.Add(curOffset);
+ offset += db.GetNumberOfNewFolders();
+
+ CMvItem mvItem;
+ mvItem.VolumeIndex = v;
+ FOR_VECTOR (i, db.Items)
+ {
+ mvItem.ItemIndex = i;
+ Items.Add(mvItem);
+ }
+ }
+
+ if (Items.Size() > 1)
+ {
+ Items.Sort(CompareMvItems, (void *)this);
+ unsigned j = 1;
+ unsigned i = 1;
+ for (; i < Items.Size(); i++)
+ if (!AreItemsEqual(i, i - 1))
+ Items[j++] = Items[i];
+ Items.DeleteFrom(j);
+ }
+
+ FOR_VECTOR (i, Items)
+ {
+ int folderIndex = GetFolderIndex(&Items[i]);
+ while (folderIndex >= (int)FolderStartFileIndex.Size())
+ FolderStartFileIndex.Add(i);
+ }
+}
+
+
+bool CMvDatabaseEx::Check()
+{
+ for (unsigned 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.MethodMajor != f1.MethodMajor ||
+ f0.MethodMinor != f1.MethodMinor)
+ return false;
+ }
+ }
+
+ UInt32 beginPos = 0;
+ UInt64 endPos = 0;
+ int prevFolder = -2;
+
+ FOR_VECTOR (i, Items)
+ {
+ const CMvItem &mvItem = Items[i];
+ int fIndex = GetFolderIndex(&mvItem);
+ if (fIndex >= (int)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/CPP/7zip/Archive/Cab/CabIn.h b/CPP/7zip/Archive/Cab/CabIn.h
new file mode 100644
index 0000000..06aa34c
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabIn.h
@@ -0,0 +1,176 @@
+// Archive/CabIn.h
+
+#ifndef ZIP7_INC_ARCHIVE_CAB_IN_H
+#define ZIP7_INC_ARCHIVE_CAB_IN_H
+
+#include "../../../Common/MyBuffer.h"
+#include "../../../Common/MyCom.h"
+
+#include "../../Common/InBuffer.h"
+
+#include "CabItem.h"
+
+namespace NArchive {
+namespace NCab {
+
+struct COtherArc
+{
+ AString FileName;
+ AString DiskName;
+
+ void Clear()
+ {
+ FileName.Empty();
+ DiskName.Empty();
+ }
+};
+
+
+struct CArchInfo
+{
+ Byte VersionMinor; // cabinet file format version, minor
+ Byte VersionMajor; // cabinet file format version, major
+ UInt32 NumFolders; // number of CFFOLDER entries in this cabinet
+ UInt32 NumFiles; // number of CFFILE entries in this cabinet
+ UInt32 Flags; // cabinet file option indicators
+ UInt32 SetID; // must be the same for all cabinets in a set
+ UInt32 CabinetNumber; // number of this cabinet file in a set
+
+ UInt16 PerCabinet_AreaSize; // (optional) size of per-cabinet reserved area
+ Byte PerFolder_AreaSize; // (optional) size of per-folder reserved area
+ Byte PerDataBlock_AreaSize; // (optional) size of per-datablock reserved area
+
+ COtherArc PrevArc; // prev link can skip some volumes !!!
+ COtherArc NextArc;
+
+ bool ReserveBlockPresent() const { return (Flags & NHeader::NArcFlags::kReservePresent) != 0; }
+ bool IsTherePrev() const { return (Flags & NHeader::NArcFlags::kPrevCabinet) != 0; }
+ bool IsThereNext() const { return (Flags & NHeader::NArcFlags::kNextCabinet) != 0; }
+ Byte GetDataBlockReserveSize() const { return (Byte)(ReserveBlockPresent() ? PerDataBlock_AreaSize : 0); }
+
+ CArchInfo()
+ {
+ PerCabinet_AreaSize = 0;
+ PerFolder_AreaSize = 0;
+ PerDataBlock_AreaSize = 0;
+ }
+
+ void Clear()
+ {
+ PerCabinet_AreaSize = 0;
+ PerFolder_AreaSize = 0;
+ PerDataBlock_AreaSize = 0;
+
+ PrevArc.Clear();
+ NextArc.Clear();
+ }
+};
+
+
+struct CInArcInfo: public CArchInfo
+{
+ UInt32 Size; // size of this cabinet file in bytes
+ UInt32 FileHeadersOffset; // offset of the first CFFILE entry
+
+ bool Parse(const Byte *p);
+};
+
+
+struct CDatabase
+{
+ CRecordVector<CFolder> Folders;
+ CObjectVector<CItem> Items;
+ UInt64 StartPosition;
+ CInArcInfo ArcInfo;
+
+ void Clear()
+ {
+ ArcInfo.Clear();
+ Folders.Clear();
+ Items.Clear();
+ }
+
+ bool IsTherePrevFolder() const
+ {
+ FOR_VECTOR (i, Items)
+ if (Items[i].ContinuedFromPrev())
+ return true;
+ return false;
+ }
+
+ int GetNumberOfNewFolders() const
+ {
+ int res = (int)Folders.Size();
+ if (IsTherePrevFolder())
+ res--;
+ return res;
+ }
+};
+
+
+struct CDatabaseEx: public CDatabase
+{
+ CMyComPtr<IInStream> Stream;
+};
+
+
+struct CMvItem
+{
+ unsigned VolumeIndex;
+ unsigned ItemIndex;
+};
+
+
+class CMvDatabaseEx
+{
+ bool AreItemsEqual(unsigned i1, unsigned i2);
+
+public:
+ CObjectVector<CDatabaseEx> Volumes;
+ CRecordVector<CMvItem> Items;
+ CRecordVector<int> StartFolderOfVol; // can be negative
+ CRecordVector<unsigned> 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
+{
+ CInBufferBase _inBuffer;
+ CByteBuffer _tempBuf;
+
+ void Skip(unsigned size);
+ void Read(Byte *data, unsigned size);
+ void ReadName(AString &s);
+ void ReadOtherArc(COtherArc &oa);
+ HRESULT Open2(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit);
+
+public:
+ bool IsArc;
+ bool ErrorInNames;
+ bool UnexpectedEnd;
+ bool HeaderError;
+
+ HRESULT Open(CDatabaseEx &db, const UInt64 *searchHeaderSizeLimit);
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Cab/CabItem.h b/CPP/7zip/Archive/Cab/CabItem.h
new file mode 100644
index 0000000..b7e07d1
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabItem.h
@@ -0,0 +1,66 @@
+// Archive/CabItem.h
+
+#ifndef ZIP7_INC_ARCHIVE_CAB_ITEM_H
+#define ZIP7_INC_ARCHIVE_CAB_ITEM_H
+
+#include "../../../Common/MyString.h"
+
+#include "CabHeader.h"
+
+namespace NArchive {
+namespace NCab {
+
+const unsigned kNumMethodsMax = 16;
+
+struct CFolder
+{
+ UInt32 DataStart; // offset of the first CFDATA block in this folder
+ UInt16 NumDataBlocks; // number of CFDATA blocks in this folder
+ Byte MethodMajor;
+ Byte MethodMinor;
+
+ Byte GetMethod() const { return (Byte)(MethodMajor & 0xF); }
+};
+
+struct CItem
+{
+ AString Name;
+ UInt32 Offset;
+ UInt32 Size;
+ UInt32 Time;
+ UInt32 FolderIndex;
+ UInt16 Flags;
+ UInt16 Attributes;
+
+ UInt64 GetEndOffset() const { return (UInt64)Offset + Size; }
+ UInt32 GetWinAttrib() const { return (UInt32)Attributes & ~(UInt32)NHeader::kFileNameIsUtf8_Mask; }
+ bool IsNameUTF() const { return (Attributes & NHeader::kFileNameIsUtf8_Mask) != 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(unsigned numFolders) const
+ {
+ if (ContinuedFromPrev())
+ return 0;
+ if (ContinuedToNext())
+ return (int)numFolders - 1;
+ return (int)FolderIndex;
+ }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Cab/CabRegister.cpp b/CPP/7zip/Archive/Cab/CabRegister.cpp
new file mode 100644
index 0000000..8f4f323
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/CabRegister.cpp
@@ -0,0 +1,19 @@
+// CabRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "CabHandler.h"
+
+namespace NArchive {
+namespace NCab {
+
+REGISTER_ARC_I(
+ "Cab", "cab", NULL, 8,
+ NHeader::kMarker,
+ 0,
+ NArcInfoFlags::kFindSignature,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/Cab/StdAfx.h b/CPP/7zip/Archive/Cab/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Archive/Cab/StdAfx.h
@@ -0,0 +1,11 @@
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Archive/Chm/ChmHandler.cpp b/CPP/7zip/Archive/Chm/ChmHandler.cpp
new file mode 100644
index 0000000..38e2543
--- /dev/null
+++ b/CPP/7zip/Archive/Chm/ChmHandler.cpp
@@ -0,0 +1,800 @@
+// ChmHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/UTFConvert.h"
+
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/TimeUtils.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamUtils.h"
+#include "../../Common/RegisterArc.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
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidMethod,
+ kpidBlock
+
+ #ifdef CHM_DETAILS
+ ,
+ L"Section", kpidSection,
+ kpidOffset
+ #endif
+};
+
+/*
+static const Byte kArcProps[] =
+{
+ // kpidNumBlocks,
+};
+*/
+
+IMP_IInArchive_Props
+
+IMP_IInArchive_ArcProps_NO_Table
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ // COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ /*
+ case kpidNumBlocks:
+ {
+ UInt64 numBlocks = 0;
+ FOR_VECTOR(i, m_Database.Sections)
+ {
+ const CSectionInfo &s = m_Database.Sections[i];
+ FOR_VECTOR(j, s.Methods)
+ {
+ const CMethodInfo &m = s.Methods[j];
+ if (m.IsLzx())
+ numBlocks += m.LzxInfo.ResetTable.GetNumBlocks();
+ }
+ }
+ prop = numBlocks;
+ break;
+ }
+ */
+ case kpidOffset: prop = m_Database.StartPosition; break;
+ case kpidPhySize: prop = m_Database.PhySize; break;
+
+ case kpidErrorFlags: prop = m_ErrorFlags; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ // COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ if (m_Database.NewFormat)
+ {
+ switch (propID)
+ {
+ case kpidSize:
+ prop = (UInt64)m_Database.NewFormatString.Len();
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ }
+
+ unsigned 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.Len() > 1 && us[0] == L'/')
+ us.Delete(0);
+ }
+ NItemName::ReplaceToOsSlashes_Remove_TailSlash(us);
+ prop = us;
+ }
+ break;
+ }
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: prop = item.Size; break;
+ case kpidMethod:
+ {
+ if (!item.IsDir())
+ {
+ if (item.Section == 0)
+ prop = "Copy";
+ else if (item.Section < m_Database.Sections.Size())
+ prop = m_Database.Sections[(unsigned)item.Section].GetMethodName();
+ }
+ break;
+ }
+ case kpidBlock:
+ if (m_Database.LowLevel)
+ prop = item.Section;
+ else if (item.Section != 0 && item.Section < m_Database.Sections.Size())
+ 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
+}
+
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback * /* openArchiveCallback */))
+{
+ COM_TRY_BEGIN
+ Close();
+ try
+ {
+ CInArchive archive(_help2);
+ // CProgressImp progressImp(openArchiveCallback);
+ const HRESULT res = archive.Open(inStream, maxCheckStartPosition, m_Database);
+ if (!archive.IsArc) m_ErrorFlags |= kpv_ErrorFlags_IsNotArc;
+ if (archive.HeadersError) m_ErrorFlags |= kpv_ErrorFlags_HeadersError;
+ if (archive.UnexpectedEnd) m_ErrorFlags |= kpv_ErrorFlags_UnexpectedEnd;
+ if (archive.UnsupportedFeature) m_ErrorFlags |= kpv_ErrorFlags_UnsupportedFeature;
+
+ RINOK(res)
+ /*
+ if (m_Database.LowLevel)
+ return S_FALSE;
+ */
+ m_Stream = inStream;
+ }
+ catch(...)
+ {
+ return S_FALSE;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ m_ErrorFlags = 0;
+ m_Database.Clear();
+ m_Stream.Release();
+ return S_OK;
+}
+
+Z7_CLASS_IMP_NOQIB_1(
+ CChmFolderOutStream
+ , ISequentialOutStream
+)
+ bool m_TestMode;
+ bool m_IsOk;
+ bool m_FileIsOpen;
+ const CFilesDatabase *m_Database;
+ CMyComPtr<IArchiveExtractCallback> m_ExtractCallback;
+ CMyComPtr<ISequentialOutStream> m_RealOutStream;
+ UInt64 m_RemainFileSize;
+
+ HRESULT OpenFile();
+ HRESULT WriteEmptyFiles();
+ HRESULT Write2(const void *data, UInt32 size, UInt32 *processedSize, bool isOK);
+public:
+
+ UInt64 m_FolderSize;
+ UInt64 m_PosInFolder;
+ UInt64 m_PosInSection;
+ const CRecordVector<bool> *m_ExtractStatuses;
+ unsigned m_StartIndex;
+ unsigned m_CurrentIndex;
+ unsigned m_NumFiles;
+
+ 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++)
+ {
+ const UInt64 fileSize = m_Database->GetFileSize(m_StartIndex + m_CurrentIndex);
+ if (fileSize != 0)
+ return S_OK;
+ const 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)
+ *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)
+ *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)
+ {
+ realProcessed += size;
+ if (processedSize)
+ *processedSize = realProcessed;
+ return S_OK;
+ // return E_FAIL;
+ }
+
+ unsigned 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)
+ *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();
+}
+
+Z7_COM7F_IMF(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 (unsigned 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;
+}
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testModeSpec, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-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.Len();
+ 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;
+ const Int32 askMode= testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 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.Len();
+ 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(InStream_SeekSet(m_Stream, m_Database.ContentOffset + item.Offset))
+ 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++)
+ {
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CItem &item = m_Database.Items[m_Database.Indices[index]];
+ const UInt64 sectionIndex = item.Section;
+ if (item.IsDir() || item.Size == 0)
+ continue;
+ if (sectionIndex == 0)
+ {
+ currentTotalSize += item.Size;
+ continue;
+ }
+
+ if (sectionIndex >= m_Database.Sections.Size())
+ continue;
+
+ const CSectionInfo &section = m_Database.Sections[(unsigned)sectionIndex];
+ 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 = NULL;
+ CMyComPtr<IUnknown> lzxDecoder;
+ CChmFolderOutStream *chmFolderOutStream = NULL;
+ CMyComPtr<ISequentialOutStream> outStream;
+
+ currentTotalSize = 0;
+
+ CRecordVector<bool> extractStatuses;
+
+ CByteBuffer packBuf;
+
+ for (i = 0;;)
+ {
+ RINOK(extractCallback->SetCompleted(&currentTotalSize))
+
+ if (i >= numItems)
+ break;
+
+ UInt32 index = allFilesMode ? i : indices[i];
+ i++;
+ const CItem &item = m_Database.Items[m_Database.Indices[index]];
+ const 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(InStream_SeekSet(m_Stream, m_Database.ContentOffset + item.Offset))
+ 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;
+ }
+
+ if (sectionIndex >= m_Database.Sections.Size())
+ {
+ // we must report error here;
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kHeadersError))
+ continue;
+ }
+
+ const CSectionInfo &section = m_Database.Sections[(unsigned)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)
+ {
+ chmFolderOutStream = new CChmFolderOutStream;
+ outStream = chmFolderOutStream;
+ }
+
+ chmFolderOutStream->Init(&m_Database, extractCallback, testMode);
+
+ if (!lzxDecoderSpec)
+ {
+ lzxDecoderSpec = new NCompress::NLzx::CDecoder;
+ lzxDecoder = lzxDecoderSpec;
+ }
+
+ UInt64 folderIndex = m_Database.GetFolder(index);
+
+ const UInt64 compressedPos = m_Database.ContentOffset + section.Offset;
+ RINOK(lzxDecoderSpec->SetParams_and_Alloc(lzxInfo.GetNumDictBits()))
+
+ 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++)
+ {
+ const UInt32 nextIndex = allFilesMode ? i : indices[i];
+ const CItem &nextItem = m_Database.Items[m_Database.Indices[nextIndex]];
+ if (nextItem.Section != sectionIndex)
+ break;
+ const 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[(unsigned)bCur];
+ UInt64 compressedSize;
+ rt.GetCompressedSizeOfBlock(bCur, compressedSize);
+
+ // chm writes full blocks. So we don't need to use reduced size for last block
+
+ RINOK(InStream_SeekSet(m_Stream, compressedPos + offset))
+ streamSpec->SetStream(m_Stream);
+ streamSpec->Init(compressedSize);
+
+ lzxDecoderSpec->SetKeepHistory(b > 0);
+
+ size_t compressedSizeT = (size_t)compressedSize;
+ if (compressedSizeT != compressedSize)
+ throw 2;
+ packBuf.AllocAtLeast(compressedSizeT);
+
+ HRESULT res = ReadStream_FALSE(inStream, packBuf, compressedSizeT);
+
+ if (res == S_OK)
+ {
+ lzxDecoderSpec->KeepHistoryForNext = true;
+ res = lzxDecoderSpec->Code(packBuf, compressedSizeT, kBlockSize); // rt.BlockSize;
+ if (res == S_OK)
+ res = WriteStream(chmFolderOutStream,
+ lzxDecoderSpec->GetUnpackData(),
+ lzxDecoderSpec->GetUnpackSize());
+ }
+
+ 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
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = m_Database.NewFormat ? 1:
+ (m_Database.LowLevel ?
+ m_Database.Items.Size():
+ m_Database.Indices.Size());
+ return S_OK;
+}
+
+namespace NChm {
+
+static const Byte k_Signature[] = { 'I', 'T', 'S', 'F', 3, 0, 0, 0, 0x60, 0, 0, 0 };
+
+REGISTER_ARC_I_CLS(
+ CHandler(false),
+ "Chm", "chm chi chq chw", NULL, 0xE9,
+ k_Signature,
+ 0,
+ 0,
+ NULL)
+
+}
+
+namespace NHxs {
+
+static const Byte k_Signature[] = { 'I', 'T', 'O', 'L', 'I', 'T', 'L', 'S', 1, 0, 0, 0, 0x28, 0, 0, 0 };
+
+REGISTER_ARC_I_CLS(
+ CHandler(true),
+ "Hxs", "hxs hxi hxr hxq hxw lit", NULL, 0xCE,
+ k_Signature,
+ 0,
+ NArcInfoFlags::kFindSignature,
+ NULL)
+
+}
+
+}}
diff --git a/CPP/7zip/Archive/Chm/ChmHandler.h b/CPP/7zip/Archive/Chm/ChmHandler.h
new file mode 100644
index 0000000..94821b2
--- /dev/null
+++ b/CPP/7zip/Archive/Chm/ChmHandler.h
@@ -0,0 +1,27 @@
+// ChmHandler.h
+
+#ifndef ZIP7_INC_ARCHIVE_CHM_HANDLER_H
+#define ZIP7_INC_ARCHIVE_CHM_HANDLER_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../IArchive.h"
+
+#include "ChmIn.h"
+
+namespace NArchive {
+namespace NChm {
+
+Z7_CLASS_IMP_CHandler_IInArchive_0
+
+ CFilesDatabase m_Database;
+ CMyComPtr<IInStream> m_Stream;
+ bool _help2;
+ UInt32 m_ErrorFlags;
+public:
+ CHandler(bool help2): _help2(help2) {}
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Chm/ChmIn.cpp b/CPP/7zip/Archive/Chm/ChmIn.cpp
new file mode 100644
index 0000000..28d512d
--- /dev/null
+++ b/CPP/7zip/Archive/Chm/ChmIn.cpp
@@ -0,0 +1,1018 @@
+// Archive/ChmIn.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/UTFConvert.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/StreamUtils.h"
+
+#include "ChmIn.h"
+
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+namespace NArchive {
+namespace NChm {
+
+static const UInt32 kSignature_ITSP = 0x50535449;
+static const UInt32 kSignature_PMGL = 0x4C474D50;
+static const UInt32 kSignature_LZXC = 0x43585A4C;
+
+static const UInt32 kSignature_IFCM = 0x4D434649;
+static const UInt32 kSignature_AOLL = 0x4C4C4F41;
+static const UInt32 kSignature_CAOL = 0x4C4F4143;
+
+static const UInt32 kSignature_ITSF = 0x46535449;
+static const UInt32 kSignature_ITOL = 0x4C4F5449;
+static const UInt32 kSignature_ITLS = 0x534C5449;
+
+struct CEnexpectedEndException {};
+struct CHeaderErrorException {};
+
+// define CHM_LOW, if you want to see low level items
+// #define CHM_LOW
+
+static const Byte kChmLzxGuid[16] = { 0x40, 0x89, 0xC2, 0x7F, 0x31, 0x9D, 0xD0, 0x11, 0x9B, 0x27, 0x00, 0xA0, 0xC9, 0x1E, 0x9C, 0x7C };
+static const Byte kHelp2LzxGuid[16] = { 0xC6, 0x07, 0x90, 0x0A, 0x76, 0x40, 0xD3, 0x11, 0x87, 0x89, 0x00, 0x00, 0xF8, 0x10, 0x57, 0x54 };
+static const Byte kDesGuid[16] = { 0xA2, 0xE4, 0xF6, 0x67, 0xBF, 0x60, 0xD3, 0x11, 0x85, 0x40, 0x00, 0xC0, 0x4F, 0x58, 0xC3, 0xCF };
+
+static bool inline AreGuidsEqual(const Byte *g1, const Byte *g2)
+{
+ return memcmp(g1, g2, 16) == 0;
+}
+
+static char GetHex(unsigned v)
+{
+ return (char)((v < 10) ? ('0' + v) : ('A' + (v - 10)));
+}
+
+static void PrintByte(Byte b, AString &s)
+{
+ s += GetHex(b >> 4);
+ s += GetHex(b & 0xF);
+}
+
+AString CMethodInfo::GetGuidString() const
+{
+ char s[48];
+ RawLeGuidToString_Braced(Guid, s);
+ // MyStringUpper_Ascii(s);
+ return (AString)s;
+}
+
+bool CMethodInfo::IsLzx() const
+{
+ if (AreGuidsEqual(Guid, kChmLzxGuid))
+ return true;
+ return AreGuidsEqual(Guid, kHelp2LzxGuid);
+}
+
+bool CMethodInfo::IsDes() const
+{
+ return AreGuidsEqual(Guid, kDesGuid);
+}
+
+AString CMethodInfo::GetName() const
+{
+ AString s;
+ if (IsLzx())
+ {
+ s = "LZX:";
+ s.Add_UInt32(LzxInfo.GetNumDictBits());
+ }
+ else
+ {
+ if (IsDes())
+ s = "DES";
+ else
+ {
+ s = GetGuidString();
+ if (ControlData.Size() > 0)
+ {
+ s += ':';
+ for (size_t i = 0; i < ControlData.Size(); i++)
+ PrintByte(ControlData[i], 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;
+ ConvertUTF8ToUnicode(Name, temp);
+ s += temp;
+ s += ": ";
+ }
+ FOR_VECTOR (i, Methods)
+ {
+ if (i != 0)
+ s.Add_Space();
+ s += Methods[i].GetName();
+ }
+ return s;
+}
+
+Byte CInArchive::ReadByte()
+{
+ Byte b;
+ if (!_inBuffer.ReadByte(b))
+ throw CEnexpectedEndException();
+ return b;
+}
+
+void CInArchive::Skip(size_t size)
+{
+ if (_inBuffer.Skip(size) != size)
+ throw CEnexpectedEndException();
+}
+
+void CInArchive::ReadBytes(Byte *data, UInt32 size)
+{
+ if (_inBuffer.ReadBytes(data, size) != size)
+ throw CEnexpectedEndException();
+}
+
+UInt16 CInArchive::ReadUInt16()
+{
+ Byte b0, b1;
+ if (!_inBuffer.ReadByte(b0)) throw CEnexpectedEndException();
+ if (!_inBuffer.ReadByte(b1)) throw CEnexpectedEndException();
+ return (UInt16)(((UInt16)b1 << 8) | b0);
+}
+
+UInt32 CInArchive::ReadUInt32()
+{
+ Byte p[4];
+ ReadBytes(p, 4);
+ return Get32(p);
+}
+
+UInt64 CInArchive::ReadUInt64()
+{
+ Byte p[8];
+ ReadBytes(p, 8);
+ return Get64(p);
+}
+
+UInt64 CInArchive::ReadEncInt()
+{
+ UInt64 val = 0;
+ for (int i = 0; i < 9; i++)
+ {
+ Byte b = ReadByte();
+ val |= (b & 0x7F);
+ if (b < 0x80)
+ return val;
+ val <<= 7;
+ }
+ throw CHeaderErrorException();
+}
+
+void CInArchive::ReadGUID(Byte *g)
+{
+ ReadBytes(g, 16);
+}
+
+void CInArchive::ReadString(unsigned size, AString &s)
+{
+ s.Empty();
+ if (size != 0)
+ {
+ ReadBytes((Byte *)s.GetBuf(size), size);
+ s.ReleaseBuf_CalcLen(size);
+ }
+}
+
+void CInArchive::ReadUString(unsigned 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_SeekSet(inStream, pos))
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> limitedStream(streamSpec);
+ streamSpec->SetStream(inStream);
+ streamSpec->Init(size);
+ m_InStreamRef = limitedStream;
+ _inBuffer.SetStream(limitedStream);
+ _inBuffer.Init();
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadDirEntry(CDatabase &database)
+{
+ CItem item;
+ UInt64 nameLen = ReadEncInt();
+ if (nameLen == 0 || nameLen > (1 << 13))
+ return S_FALSE;
+ ReadString((unsigned)nameLen, 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;
+ database.PhySize = headerSize;
+
+ UInt32 unknown1 = ReadUInt32();
+ if (unknown1 != 0 && unknown1 != 1) // it's 0 in one .sll file
+ return S_FALSE;
+
+ IsArc = true;
+
+ /* 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();
+ Byte g[16];
+ ReadGUID(g); // {7C01FD10-7BAA-11D0-9E0C-00A0-C922-E6EC}
+ ReadGUID(g); // {7C01FD11-7BAA-11D0-9E0C-00A0-C922-E6EC}
+ const unsigned kNumSections = 2;
+ UInt64 sectionOffsets[kNumSections];
+ UInt64 sectionSizes[kNumSections];
+ unsigned i;
+ for (i = 0; i < kNumSections; i++)
+ {
+ sectionOffsets[i] = ReadUInt64();
+ sectionSizes[i] = ReadUInt64();
+ UInt64 end = sectionOffsets[i] + sectionSizes[i];
+ database.UpdatePhySize(end);
+ }
+ // if (chmVersion == 3)
+ database.ContentOffset = ReadUInt64();
+ /*
+ else
+ database.ContentOffset = database.StartPosition + 0x58
+ */
+
+ // Section 0
+ ReadChunk(inStream, sectionOffsets[0], sectionSizes[0]);
+ if (sectionSizes[0] < 0x18)
+ return S_FALSE;
+ if (ReadUInt32() != 0x01FE)
+ return S_FALSE;
+ ReadUInt32(); // unknown: 0
+ UInt64 fileSize = ReadUInt64();
+ database.UpdatePhySize(fileSize);
+ ReadUInt32(); // unknown: 0
+ ReadUInt32(); // unknown: 0
+
+ // Section 1: The Directory Listing
+ ReadChunk(inStream, sectionOffsets[1], sectionSizes[1]);
+ if (ReadUInt32() != kSignature_ITSP)
+ 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() == kSignature_PMGL)
+ {
+ // 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(); // Len 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)
+ unsigned 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);
+
+ unsigned rrr = ReadUInt16();
+ if (rrr != numItems)
+ {
+ // Lazarus 9-26-2 chm contains 0 here.
+ if (rrr != 0)
+ 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 unsigned kNumHeaderSectionsMax = 5;
+ if (numHeaderSections != kNumHeaderSectionsMax)
+ return S_FALSE;
+
+ IsArc = true;
+
+ ReadUInt32(); // Len of post-header table
+ Byte g[16];
+ 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();
+ UInt64 end = sectionOffsets[i] + sectionSizes[i];
+ database.UpdatePhySize(end);
+ }
+
+ // 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() != kSignature_CAOL)
+ return S_FALSE;
+ if (ReadUInt32() != 2) // (Most likely a version number)
+ return S_FALSE;
+ UInt32 caolLength = ReadUInt32(); // $50 (Len 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)
+ {
+ // fprintf(stdout, "\n !!!NewFormat\n");
+ // fflush(stdout);
+ database.ContentOffset = 0; // maybe we must add database.StartPosition here?
+ database.NewFormat = true;
+ }
+ else if (caolLength == 0x50)
+ {
+ ReadUInt32(); // 0 (Unknown)
+ if (ReadUInt32() != kSignature_ITSF)
+ 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 = database.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, database.StartPosition + sectionOffsets[0], sectionSizes[0]);
+ if (sectionSizes[0] < 0x18)
+ return S_FALSE;
+ if (ReadUInt32() != 0x01FE)
+ return S_FALSE;
+ ReadUInt32(); // unknown: 0
+ UInt64 fileSize = ReadUInt64();
+ database.UpdatePhySize(fileSize);
+ ReadUInt32(); // unknown: 0
+ ReadUInt32(); // unknown: 0
+
+ // Section 1: The Directory Listing
+ ReadChunk(inStream, database.StartPosition + sectionOffsets[1], sectionSizes[1]);
+ if (ReadUInt32() != kSignature_IFCM)
+ 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() == kSignature_AOLL)
+ {
+ UInt32 quickrefLength = ReadUInt32(); // Len 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)
+
+ unsigned 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 nameLen = ReadUInt16();
+ if (nameLen == 0)
+ return S_FALSE;
+ UString name;
+ ReadUString((unsigned)nameLen, name);
+ AString s;
+ ConvertUnicodeToUTF8(name, s);
+ Byte b = ReadByte();
+ s.Add_Space();
+ PrintByte(b, s);
+ s.Add_Space();
+ 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/"
+#define kNameList DATA_SPACE "NameList"
+#define kStorage DATA_SPACE "Storage/"
+#define kContent "Content"
+#define kControlData "ControlData"
+#define kSpanInfo "SpanInfo"
+#define kTransform "Transform/"
+#define kResetTable "/InstanceData/ResetTable"
+#define kTransformList "List"
+
+static AString GetSectionPrefix(const AString &name)
+{
+ AString s (kStorage);
+ s += name;
+ s += '/';
+ return s;
+}
+
+#define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; }
+
+static int CompareFiles(const unsigned *p1, const unsigned *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 1;
+ }
+ else
+ {
+ 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_VECTOR (i, Items)
+ {
+ const CItem &item = Items[i];
+ if (item.IsUserItem() && item.Name.Len() != 1)
+ Indices.Add(i);
+ }
+}
+
+void CFilesDatabase::Sort()
+{
+ Indices.Sort(CompareFiles, (void *)&Items);
+}
+
+bool CFilesDatabase::Check()
+{
+ UInt64 maxPos = 0;
+ UInt64 prevSection = 0;
+ FOR_VECTOR (i, Indices)
+ {
+ 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;
+}
+
+bool CFilesDatabase::CheckSectionRefs()
+{
+ FOR_VECTOR (i, Indices)
+ {
+ const CItem &item = Items[Indices[i]];
+ if (item.Section == 0 || item.IsDir())
+ continue;
+ if (item.Section >= Sections.Size())
+ return false;
+ }
+ return true;
+}
+
+static int inline GetLog(UInt32 num)
+{
+ for (int i = 0; i < 32; i++)
+ if (((UInt32)1 << i) == num)
+ return i;
+ return -1;
+}
+
+HRESULT CInArchive::OpenHighLevel(IInStream *inStream, CFilesDatabase &database)
+{
+ {
+ // The NameList file
+ RINOK(DecompressStream(inStream, database, (AString)kNameList))
+ /* UInt16 length = */ ReadUInt16();
+ UInt16 numSections = ReadUInt16();
+ for (unsigned i = 0; i < numSections; i++)
+ {
+ CSectionInfo section;
+ UInt16 nameLen = ReadUInt16();
+ UString name;
+ ReadUString(nameLen, name);
+ if (ReadUInt16() != 0)
+ return S_FALSE;
+ ConvertUnicodeToUTF8(name, section.Name);
+ // if (!ConvertUnicodeToUTF8(name, section.Name)) return S_FALSE;
+ database.Sections.Add(section);
+ }
+ }
+
+ unsigned si;
+ for (si = 1; si < database.Sections.Size(); si++)
+ {
+ CSectionInfo &section = database.Sections[si];
+ 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;
+ unsigned numGuids = (unsigned)(_chunkSize / 0x10);
+ if (numGuids < 1)
+ return S_FALSE;
+ for (unsigned i = 0; i < numGuids; i++)
+ {
+ CMethodInfo method;
+ ReadGUID(method.Guid);
+ section.Methods.Add(method);
+ }
+ }
+ else
+ {
+ CMethodInfo method;
+ memcpy(method.Guid, kChmLzxGuid, 16);
+ section.Methods.Add(method);
+ }
+
+ {
+ // Control Data
+ RINOK(DecompressStream(inStream, database, sectionPrefix + kControlData))
+
+ FOR_VECTOR (mi, section.Methods)
+ {
+ CMethodInfo &method = section.Methods[mi];
+ UInt32 numDWORDS = ReadUInt32();
+ if (method.IsLzx())
+ {
+ if (numDWORDS < 5)
+ return S_FALSE;
+ if (ReadUInt32() != kSignature_LZXC)
+ return S_FALSE;
+ CLzxInfo &li = method.LzxInfo;
+ li.Version = ReadUInt32();
+ if (li.Version != 2 && li.Version != 3)
+ return S_FALSE;
+
+ {
+ // There is bug in VC6, if we use function call as parameter for inline function
+ const UInt32 val32 = ReadUInt32();
+ const int n = GetLog(val32);
+ if (n < 0 || n > 16)
+ return S_FALSE;
+ li.ResetIntervalBits = (unsigned)n;
+ }
+
+ {
+ const UInt32 val32 = ReadUInt32();
+ const int n = GetLog(val32);
+ if (n < 0 || n > 16)
+ return S_FALSE;
+ li.WindowSizeBits = (unsigned)n;
+ }
+
+ li.CacheSize = ReadUInt32();
+ numDWORDS -= 5;
+ while (numDWORDS-- != 0)
+ ReadUInt32();
+ }
+ else
+ {
+ UInt32 numBytes = numDWORDS * 4;
+ method.ControlData.Alloc(numBytes);
+ ReadBytes(method.ControlData, numBytes);
+ }
+ }
+ }
+
+ {
+ // SpanInfo
+ RINOK(DecompressStream(inStream, database, sectionPrefix + kSpanInfo))
+ section.UncompressedSize = ReadUInt64();
+ }
+
+ // read ResetTable for LZX
+ FOR_VECTOR (mi, section.Methods)
+ {
+ 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();
+ const unsigned kEntrySize = 8;
+ if (ReadUInt32() != kEntrySize)
+ return S_FALSE;
+ const unsigned kRtHeaderSize = 4 * 4 + 8 * 3;
+ if (ReadUInt32() != kRtHeaderSize)
+ return S_FALSE;
+ if (kRtHeaderSize + kEntrySize * (UInt64)numEntries != _chunkSize)
+ return S_FALSE;
+
+ rt.UncompressedSize = ReadUInt64();
+ rt.CompressedSize = ReadUInt64();
+ UInt64 blockSize = ReadUInt64();
+ if (blockSize != kBlockSize)
+ return S_FALSE;
+ UInt64 numBlocks = (rt.UncompressedSize + kBlockSize + 1) / kBlockSize;
+ if (numEntries != numBlocks &&
+ numEntries != numBlocks + 1)
+ return S_FALSE;
+
+ rt.ResetOffsets.ClearAndReserve(numEntries);
+
+ for (UInt32 i = 0; i < numEntries; i++)
+ {
+ UInt64 v = ReadUInt64();
+ if (i != 0 && v < rt.ResetOffsets[i - 1])
+ return S_FALSE;
+ rt.ResetOffsets.AddInReserved(v);
+ }
+
+ if (numEntries != 0)
+ if (rt.ResetOffsets[0] != 0)
+ return S_FALSE;
+
+ if (numEntries == numBlocks + 1)
+ {
+ // Lazarus 9-26-2 chm contains additional entty
+ if (rt.ResetOffsets.Back() != rt.CompressedSize)
+ return S_FALSE;
+ }
+ }
+ }
+ }
+ }
+
+ database.SetIndices();
+ database.Sort();
+ return database.Check() ? S_OK : S_FALSE;
+}
+
+HRESULT CInArchive::Open2(IInStream *inStream,
+ const UInt64 *searchHeaderSizeLimit,
+ CFilesDatabase &database)
+{
+ IsArc = false;
+ HeadersError = false;
+ UnexpectedEnd = false;
+ UnsupportedFeature = false;
+
+ database.Clear();
+ database.Help2Format = _help2;
+ const UInt32 chmVersion = 3;
+
+ RINOK(InStream_GetPos(inStream, database.StartPosition))
+
+ if (!_inBuffer.Create(1 << 14))
+ return E_OUTOFMEMORY;
+ _inBuffer.SetStream(inStream);
+ _inBuffer.Init();
+
+ if (_help2)
+ {
+ const unsigned kSignatureSize = 8;
+ const UInt64 signature = ((UInt64)kSignature_ITLS << 32) | kSignature_ITOL;
+ UInt64 limit = 1 << 18;
+
+ if (searchHeaderSizeLimit)
+ if (limit > *searchHeaderSizeLimit)
+ limit = *searchHeaderSizeLimit;
+
+ UInt64 val = 0;
+
+ for (;;)
+ {
+ Byte b;
+ if (!_inBuffer.ReadByte(b))
+ return S_FALSE;
+ val >>= 8;
+ val |= ((UInt64)b) << ((kSignatureSize - 1) * 8);
+ if (_inBuffer.GetProcessedSize() >= kSignatureSize)
+ {
+ if (val == signature)
+ break;
+ if (_inBuffer.GetProcessedSize() > limit)
+ return S_FALSE;
+ }
+ }
+
+ database.StartPosition += _inBuffer.GetProcessedSize() - kSignatureSize;
+ RINOK(OpenHelp2(inStream, database))
+ if (database.NewFormat)
+ return S_OK;
+ }
+ else
+ {
+ if (ReadUInt32() != kSignature_ITSF)
+ return S_FALSE;
+ if (ReadUInt32() != chmVersion)
+ return S_FALSE;
+ RINOK(OpenChm(inStream, database))
+ }
+
+
+ #ifndef CHM_LOW
+
+ try
+ {
+ try
+ {
+ HRESULT res = OpenHighLevel(inStream, database);
+ if (res == S_FALSE)
+ {
+ UnsupportedFeature = true;
+ database.HighLevelClear();
+ return S_OK;
+ }
+ RINOK(res)
+ if (!database.CheckSectionRefs())
+ HeadersError = true;
+ database.LowLevel = false;
+ }
+ catch(...)
+ {
+ database.HighLevelClear();
+ throw;
+ }
+ }
+ // catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(CEnexpectedEndException &) { UnexpectedEnd = true; }
+ catch(CHeaderErrorException &) { HeadersError = true; }
+ catch(...) { throw; }
+
+ #endif
+
+ return S_OK;
+}
+
+HRESULT CInArchive::Open(IInStream *inStream,
+ const UInt64 *searchHeaderSizeLimit,
+ CFilesDatabase &database)
+{
+ try
+ {
+ try
+ {
+ HRESULT res = Open2(inStream, searchHeaderSizeLimit, database);
+ m_InStreamRef.Release();
+ return res;
+ }
+ catch(...)
+ {
+ m_InStreamRef.Release();
+ throw;
+ }
+ }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(CEnexpectedEndException &) { UnexpectedEnd = true; }
+ catch(CHeaderErrorException &) { HeadersError = true; }
+ return S_FALSE;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Chm/ChmIn.h b/CPP/7zip/Archive/Chm/ChmIn.h
new file mode 100644
index 0000000..c01ef4d
--- /dev/null
+++ b/CPP/7zip/Archive/Chm/ChmIn.h
@@ -0,0 +1,282 @@
+// Archive/ChmIn.h
+
+#ifndef ZIP7_INC_ARCHIVE_CHM_IN_H
+#define ZIP7_INC_ARCHIVE_CHM_IN_H
+
+#include "../../../Common/MyBuffer.h"
+#include "../../../Common/MyString.h"
+
+#include "../../IStream.h"
+
+#include "../../Common/InBuffer.h"
+
+namespace NArchive {
+namespace NChm {
+
+struct CItem
+{
+ UInt64 Section;
+ UInt64 Offset;
+ UInt64 Size;
+ AString Name;
+
+ bool IsFormatRelatedItem() const
+ {
+ if (Name.Len() < 2)
+ return false;
+ return Name[0] == ':' && Name[1] == ':';
+ }
+
+ bool IsUserItem() const
+ {
+ if (Name.Len() < 2)
+ return false;
+ return Name[0] == '/';
+ }
+
+ bool IsDir() const
+ {
+ if (Name.IsEmpty())
+ return false;
+ return (Name.Back() == '/');
+ }
+};
+
+
+struct CDatabase
+{
+ UInt64 StartPosition;
+ UInt64 ContentOffset;
+ CObjectVector<CItem> Items;
+ AString NewFormatString;
+ bool Help2Format;
+ bool NewFormat;
+ UInt64 PhySize;
+
+ void UpdatePhySize(UInt64 v) { if (PhySize < v) PhySize = v; }
+
+ int FindItem(const AString &name) const
+ {
+ FOR_VECTOR (i, Items)
+ if (Items[i].Name == name)
+ return (int)i;
+ return -1;
+ }
+
+ void Clear()
+ {
+ NewFormat = false;
+ NewFormatString.Empty();
+ Help2Format = false;
+ Items.Clear();
+ StartPosition = 0;
+ PhySize = 0;
+ }
+};
+
+
+const UInt32 kBlockSize = 1 << 15;
+
+struct CResetTable
+{
+ UInt64 UncompressedSize;
+ UInt64 CompressedSize;
+ // unsigned BlockSizeBits;
+ CRecordVector<UInt64> ResetOffsets;
+
+ CResetTable():
+ UncompressedSize(0),
+ CompressedSize(0)
+ {}
+
+ bool GetCompressedSizeOfBlocks(UInt64 blockIndex, UInt32 numBlocks, UInt64 &size) const
+ {
+ if (blockIndex >= ResetOffsets.Size())
+ return false;
+ UInt64 startPos = ResetOffsets[(unsigned)blockIndex];
+ if (blockIndex + numBlocks >= ResetOffsets.Size())
+ size = CompressedSize - startPos;
+ else
+ size = ResetOffsets[(unsigned)(blockIndex + numBlocks)] - startPos;
+ return true;
+ }
+
+ bool GetCompressedSizeOfBlock(UInt64 blockIndex, UInt64 &size) const
+ {
+ return GetCompressedSizeOfBlocks(blockIndex, 1, size);
+ }
+
+ UInt64 GetNumBlocks(UInt64 size) const
+ {
+ return (size + kBlockSize - 1) / kBlockSize;
+ }
+};
+
+
+struct CLzxInfo
+{
+ UInt32 Version;
+
+ unsigned ResetIntervalBits;
+ unsigned WindowSizeBits;
+ UInt32 CacheSize;
+
+ CResetTable ResetTable;
+
+ CLzxInfo():
+ Version(0),
+ ResetIntervalBits(0),
+ WindowSizeBits(0),
+ CacheSize(0)
+ {}
+
+ unsigned GetNumDictBits() const
+ {
+ if (Version == 2 || Version == 3)
+ return 15 + WindowSizeBits;
+ return 0;
+ }
+
+ UInt64 GetFolderSize() const { return kBlockSize << ResetIntervalBits; }
+ UInt64 GetFolder(UInt64 offset) const { return offset / GetFolderSize(); }
+ UInt64 GetFolderPos(UInt64 folderIndex) const { return folderIndex * GetFolderSize(); }
+ UInt64 GetBlockIndexFromFolderIndex(UInt64 folderIndex) const { return folderIndex << ResetIntervalBits; }
+
+ bool GetOffsetOfFolder(UInt64 folderIndex, UInt64 &offset) const
+ {
+ UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex);
+ if (blockIndex >= ResetTable.ResetOffsets.Size())
+ return false;
+ offset = ResetTable.ResetOffsets[(unsigned)blockIndex];
+ return true;
+ }
+
+ bool GetCompressedSizeOfFolder(UInt64 folderIndex, UInt64 &size) const
+ {
+ UInt64 blockIndex = GetBlockIndexFromFolderIndex(folderIndex);
+ return ResetTable.GetCompressedSizeOfBlocks(blockIndex, (UInt32)1 << ResetIntervalBits, size);
+ }
+};
+
+
+struct CMethodInfo
+{
+ Byte Guid[16];
+ CByteBuffer ControlData;
+ CLzxInfo LzxInfo;
+
+ bool IsLzx() const;
+ bool IsDes() const;
+ AString GetGuidString() const;
+ AString 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;
+ CUIntVector Indices;
+ CObjectVector<CSectionInfo> Sections;
+
+ UInt64 GetFileSize(unsigned fileIndex) const { return Items[Indices[fileIndex]].Size; }
+ UInt64 GetFileOffset(unsigned fileIndex) const { return Items[Indices[fileIndex]].Offset; }
+
+ UInt64 GetFolder(unsigned fileIndex) const
+ {
+ const CItem &item = Items[Indices[fileIndex]];
+ if (item.Section < Sections.Size())
+ {
+ const CSectionInfo &section = Sections[(unsigned)item.Section];
+ if (section.IsLzx())
+ return section.Methods[0].LzxInfo.GetFolder(item.Offset);
+ }
+ return 0;
+ }
+
+ UInt64 GetLastFolder(unsigned fileIndex) const
+ {
+ const CItem &item = Items[Indices[fileIndex]];
+ if (item.Section < Sections.Size())
+ {
+ const CSectionInfo &section = Sections[(unsigned)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();
+ bool CheckSectionRefs();
+};
+
+
+class CInArchive
+{
+ CMyComPtr<ISequentialInStream> m_InStreamRef;
+ ::CInBuffer _inBuffer;
+ UInt64 _chunkSize;
+ bool _help2;
+
+ Byte ReadByte();
+ void ReadBytes(Byte *data, UInt32 size);
+ void Skip(size_t size);
+ UInt16 ReadUInt16();
+ UInt32 ReadUInt32();
+ UInt64 ReadUInt64();
+ UInt64 ReadEncInt();
+ void ReadString(unsigned size, AString &s);
+ void ReadUString(unsigned size, UString &s);
+ void ReadGUID(Byte *g);
+
+ HRESULT ReadChunk(IInStream *inStream, UInt64 pos, UInt64 size);
+
+ HRESULT ReadDirEntry(CDatabase &database);
+ HRESULT DecompressStream(IInStream *inStream, const CDatabase &database, const AString &name);
+
+public:
+ bool IsArc;
+ bool HeadersError;
+ bool UnexpectedEnd;
+ bool UnsupportedFeature;
+
+ CInArchive(bool help2) { _help2 = help2; }
+
+ 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/CPP/7zip/Archive/Chm/StdAfx.h b/CPP/7zip/Archive/Chm/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Archive/Chm/StdAfx.h
@@ -0,0 +1,11 @@
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Archive/ComHandler.cpp b/CPP/7zip/Archive/ComHandler.cpp
new file mode 100644
index 0000000..7aabd65
--- /dev/null
+++ b/CPP/7zip/Archive/ComHandler.cpp
@@ -0,0 +1,896 @@
+// ComHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/IntToString.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/MyCom.h"
+#include "../../Common/MyBuffer.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) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
+namespace NArchive {
+namespace NCom {
+
+static const Byte kSignature[] =
+ { 0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1 };
+
+enum EType
+{
+ k_Type_Common,
+ k_Type_Msi,
+ k_Type_Msp,
+ k_Type_Doc,
+ k_Type_Ppt,
+ k_Type_Xls
+};
+
+static const char * const kExtensions[] =
+{
+ "compound"
+ , "msi"
+ , "msp"
+ , "doc"
+ , "ppt"
+ , "xls"
+};
+
+namespace NFatID
+{
+ // static const UInt32 kFree = 0xFFFFFFFF;
+ static const UInt32 kEndOfChain = 0xFFFFFFFE;
+ // static const UInt32 kFatSector = 0xFFFFFFFD;
+ // static const UInt32 kMatSector = 0xFFFFFFFC;
+ static const UInt32 kMaxValue = 0xFFFFFFFA;
+}
+
+namespace NItemType
+{
+ static const Byte kEmpty = 0;
+ static const Byte kStorage = 1;
+ // static const Byte kStream = 2;
+ // static const Byte kLockBytes = 3;
+ // static const Byte kProperty = 4;
+ static const Byte kRootStorage = 5;
+}
+
+static 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;
+ CObjArray<UInt32> MiniSids;
+
+ HRESULT AddNode(int parent, UInt32 did);
+public:
+
+ CObjArray<UInt32> Fat;
+ UInt32 FatSize;
+
+ CObjArray<UInt32> Mat;
+ UInt32 MatSize;
+
+ CObjectVector<CItem> Items;
+ CRecordVector<CRef> Refs;
+
+ UInt32 LongStreamMinSize;
+ unsigned SectorSizeBits;
+ unsigned MiniSectorSizeBits;
+
+ Int32 MainSubfile;
+
+ UInt64 PhySize;
+ UInt64 PhySize_Aligned;
+ EType Type;
+
+ bool IsNotArcType() const
+ {
+ return
+ Type != k_Type_Msi &&
+ Type != k_Type_Msp;
+ }
+
+ void UpdatePhySize(UInt64 val, UInt64 val_Aligned)
+ {
+ if (PhySize < val)
+ PhySize = val;
+ if (PhySize_Aligned < val_Aligned)
+ PhySize_Aligned = val_Aligned;
+ }
+ HRESULT ReadSector(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid);
+ HRESULT ReadIDs(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid, UInt32 *dest);
+
+ HRESULT Update_PhySize_WithItem(unsigned index);
+
+ 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
+ {
+ unsigned 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);
+};
+
+
+HRESULT CDatabase::ReadSector(IInStream *inStream, Byte *buf, unsigned sectorSizeBits, UInt32 sid)
+{
+ const UInt64 end = ((UInt64)sid + 2) << sectorSizeBits;
+ UpdatePhySize(end, end);
+ RINOK(InStream_SeekSet(inStream, (((UInt64)sid + 1) << sectorSizeBits)))
+ return ReadStream_FALSE(inStream, buf, (size_t)1 << sectorSizeBits);
+}
+
+HRESULT CDatabase::ReadIDs(IInStream *inStream, Byte *buf, unsigned 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()
+{
+ PhySize = 0;
+ PhySize_Aligned = 0;
+
+ 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;
+ const unsigned 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((int)index, item.SonDid))
+ }
+ return S_OK;
+}
+
+static UString CompoundNameToFileName(const UString &s)
+{
+ UString res;
+ for (unsigned i = 0; i < s.Len(); i++)
+ {
+ const wchar_t c = s[i];
+ if ((unsigned)(int)c < 0x20)
+ {
+ res += '[';
+ res.Add_UInt32((UInt32)(unsigned)(int)c);
+ res += ']';
+ }
+ else
+ res += c;
+ }
+ return res;
+}
+
+static const char k_Msi_Chars[] =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._";
+
+// static const char * const k_Msi_ID = ""; // "{msi}";
+static const char k_Msi_SpecChar = '!';
+
+static const unsigned k_Msi_NumBits = 6;
+static const unsigned k_Msi_NumChars = 1 << k_Msi_NumBits;
+static const unsigned k_Msi_CharMask = k_Msi_NumChars - 1;
+static const unsigned k_Msi_StartUnicodeChar = 0x3800;
+static const unsigned k_Msi_UnicodeRange = k_Msi_NumChars * (k_Msi_NumChars + 1);
+
+
+static bool IsMsiName(const Byte *p)
+{
+ UInt32 c = Get16(p);
+ return
+ c >= k_Msi_StartUnicodeChar &&
+ c <= k_Msi_StartUnicodeChar + k_Msi_UnicodeRange;
+}
+
+static bool AreEqualNames(const Byte *rawName, const char *asciiName)
+{
+ for (unsigned i = 0; i < kNameSizeMax / 2; i++)
+ {
+ wchar_t c = Get16(rawName + i * 2);
+ wchar_t c2 = (Byte)asciiName[i];
+ if (c != c2)
+ return false;
+ if (c == 0)
+ return true;
+ }
+ return false;
+}
+
+static bool CompoundMsiNameToFileName(const UString &name, UString &res)
+{
+ res.Empty();
+ for (unsigned i = 0; i < name.Len(); i++)
+ {
+ wchar_t c = name[i];
+ if (c < (wchar_t)k_Msi_StartUnicodeChar || c > (wchar_t)(k_Msi_StartUnicodeChar + k_Msi_UnicodeRange))
+ return false;
+ /*
+ if (i == 0)
+ res += k_Msi_ID;
+ */
+ c -= k_Msi_StartUnicodeChar;
+
+ unsigned c0 = (unsigned)c & k_Msi_CharMask;
+ unsigned c1 = (unsigned)c >> k_Msi_NumBits;
+
+ if (c1 <= k_Msi_NumChars)
+ {
+ res += k_Msi_Chars[c0];
+ if (c1 == k_Msi_NumChars)
+ break;
+ res += k_Msi_Chars[c1];
+ }
+ else
+ res += k_Msi_SpecChar;
+ }
+ return true;
+}
+
+static UString ConvertName(const Byte *p, bool &isMsi)
+{
+ isMsi = false;
+ UString s;
+
+ for (unsigned i = 0; i < kNameSizeMax; i += 2)
+ {
+ wchar_t c = Get16(p + i);
+ 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.InsertAtFront(WCHAR_PATH_SEPARATOR);
+ s.Insert(0, ConvertName(item.Name));
+ index = (unsigned)ref.Parent;
+ }
+ return s;
+}
+
+HRESULT CDatabase::Update_PhySize_WithItem(unsigned index)
+{
+ const CItem &item = Items[index];
+ bool isLargeStream = (index == 0 || IsLargeStream(item.Size));
+ if (!isLargeStream)
+ return S_OK;
+ const unsigned bsLog = isLargeStream ? SectorSizeBits : MiniSectorSizeBits;
+ // streamSpec->Size = item.Size;
+
+ const UInt32 clusterSize = (UInt32)1 << bsLog;
+ const UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog;
+ if (numClusters64 >= ((UInt32)1 << 31))
+ return S_FALSE;
+ UInt32 sid = item.Sid;
+ UInt64 size = item.Size;
+
+ if (size != 0)
+ {
+ for (;; size -= clusterSize)
+ {
+ // if (isLargeStream)
+ {
+ if (sid >= FatSize)
+ return S_FALSE;
+ UInt64 end = ((UInt64)sid + 1) << bsLog;
+ const UInt64 end_Aligned = end + clusterSize;
+ if (size < clusterSize)
+ end += size;
+ else
+ end = end_Aligned;
+ UpdatePhySize(end, end_Aligned);
+ sid = Fat[sid];
+ }
+ if (size <= clusterSize)
+ break;
+ }
+ }
+ if (sid != NFatID::kEndOfChain)
+ return S_FALSE;
+ return S_OK;
+}
+
+// There is name "[!]MsiPatchSequence" in msp files
+static const unsigned kMspSequence_Size = 18;
+static const Byte kMspSequence[kMspSequence_Size] =
+ { 0x40, 0x48, 0x96, 0x45, 0x6C, 0x3E, 0xE4, 0x45,
+ 0xE6, 0x42, 0x16, 0x42, 0x37, 0x41, 0x27, 0x41,
+ 0x37, 0x41 };
+
+HRESULT CDatabase::Open(IInStream *inStream)
+{
+ MainSubfile = -1;
+ Type = k_Type_Common;
+ const UInt32 kHeaderSize = 512;
+ Byte p[kHeaderSize];
+ PhySize = kHeaderSize;
+ RINOK(ReadStream_FALSE(inStream, p, kHeaderSize))
+ if (memcmp(p, kSignature, Z7_ARRAY_SIZE(kSignature)) != 0)
+ return S_FALSE;
+ if (Get16(p + 0x1A) > 4) // majorVer
+ return S_FALSE;
+ if (Get16(p + 0x1C) != 0xFFFE) // Little-endian
+ return S_FALSE;
+ unsigned sectorSizeBits = Get16(p + 0x1E);
+ bool mode64bit = (sectorSizeBits >= 12);
+ unsigned miniSectorSizeBits = Get16(p + 0x20);
+ SectorSizeBits = sectorSizeBits;
+ MiniSectorSizeBits = miniSectorSizeBits;
+
+ if (sectorSizeBits > 24 ||
+ sectorSizeBits < 7 ||
+ miniSectorSizeBits > 24 ||
+ miniSectorSizeBits < 2 ||
+ miniSectorSizeBits > sectorSizeBits)
+ return S_FALSE;
+ UInt32 numSectorsForFAT = Get32(p + 0x2C); // SAT
+ LongStreamMinSize = Get32(p + 0x38);
+
+ UInt32 sectSize = (UInt32)1 << sectorSizeBits;
+
+ CByteBuffer sect(sectSize);
+
+ unsigned ssb2 = sectorSizeBits - 2;
+ UInt32 numSidsInSec = (UInt32)1 << ssb2;
+ UInt32 numFatItems = numSectorsForFAT << ssb2;
+ if ((numFatItems >> ssb2) != numSectorsForFAT)
+ return S_FALSE;
+ FatSize = numFatItems;
+
+ {
+ UInt32 numSectorsForBat = Get32(p + 0x48); // master sector allocation table
+ const UInt32 kNumHeaderBatItems = 109;
+ UInt32 numBatItems = kNumHeaderBatItems + (numSectorsForBat << ssb2);
+ if (numBatItems < kNumHeaderBatItems || ((numBatItems - kNumHeaderBatItems) >> ssb2) != numSectorsForBat)
+ return S_FALSE;
+ CObjArray<UInt32> bat(numBatItems);
+ 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;
+
+ Fat.Alloc(numFatItems);
+ 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))
+ }
+ FatSize = numFatItems = i;
+ }
+
+ UInt32 numMatItems;
+ {
+ UInt32 numSectorsForMat = Get32(p + 0x40);
+ numMatItems = (UInt32)numSectorsForMat << ssb2;
+ if ((numMatItems >> ssb2) != numSectorsForMat)
+ return S_FALSE;
+ Mat.Alloc(numMatItems);
+ UInt32 i;
+ UInt32 sid = Get32(p + 0x3C); // short-sector table SID
+ 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;
+ }
+
+ {
+ CByteBuffer used(numFatItems);
+ for (UInt32 i = 0; i < numFatItems; i++)
+ used[i] = 0;
+ UInt32 sid = Get32(p + 0x30); // directory stream SID
+ for (;;)
+ {
+ if (sid >= numFatItems)
+ return S_FALSE;
+ if (used[sid])
+ return S_FALSE;
+ used[sid] = 1;
+ 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;
+ }
+ }
+
+ const 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;
+ MiniSids.Alloc(numSectorsInMiniStream);
+ {
+ 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_VECTOR (i, Refs)
+ {
+ const CItem &item = Items[Refs[i].Did];
+ if (item.IsDir() || numCabs > 1)
+ continue;
+ bool isMsiName;
+ const UString msiName = ConvertName(item.Name, isMsiName);
+ if (isMsiName && !msiName.IsEmpty())
+ {
+ // bool isThereExt = (msiName.Find(L'.') >= 0);
+ bool isMsiSpec = (msiName[0] == k_Msi_SpecChar);
+ if ((msiName.Len() >= 4 && StringsAreEqualNoCase_Ascii(msiName.RightPtr(4), ".cab"))
+ || (!isMsiSpec && msiName.Len() >= 3 && StringsAreEqualNoCase_Ascii(msiName.RightPtr(3), "exe"))
+ // || (!isMsiSpec && !isThereExt)
+ )
+ {
+ numCabs++;
+ MainSubfile = (int)i;
+ }
+ }
+ }
+
+ if (numCabs > 1)
+ MainSubfile = -1;
+
+ {
+ FOR_VECTOR (t, Items)
+ {
+ Update_PhySize_WithItem(t);
+ }
+ }
+ {
+ if (PhySize != PhySize_Aligned)
+ {
+ /* some msi (in rare cases) have unaligned size of archive,
+ where there is no padding data after payload data in last cluster of archive */
+ UInt64 fileSize;
+ RINOK(InStream_GetSize_SeekToEnd(inStream, fileSize))
+ if (PhySize != fileSize)
+ PhySize = PhySize_Aligned;
+ }
+ }
+ {
+ FOR_VECTOR (t, Items)
+ {
+ const CItem &item = Items[t];
+
+ if (IsMsiName(item.Name))
+ {
+ Type = k_Type_Msi;
+ if (memcmp(item.Name, kMspSequence, kMspSequence_Size) == 0)
+ {
+ Type = k_Type_Msp;
+ break;
+ }
+ continue;
+ }
+ if (AreEqualNames(item.Name, "WordDocument"))
+ {
+ Type = k_Type_Doc;
+ break;
+ }
+ if (AreEqualNames(item.Name, "PowerPoint Document"))
+ {
+ Type = k_Type_Ppt;
+ break;
+ }
+ if (AreEqualNames(item.Name, "Workbook"))
+ {
+ Type = k_Type_Xls;
+ break;
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IInArchiveGetStream
+)
+ CMyComPtr<IInStream> _stream;
+ CDatabase _db;
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
+ kpidCTime,
+ kpidMTime
+};
+
+static const Byte kArcProps[] =
+{
+ kpidExtension,
+ kpidClusterSize,
+ kpidSectorSize
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidExtension: prop = kExtensions[(unsigned)_db.Type]; break;
+ case kpidPhySize: prop = _db.PhySize; break;
+ 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;
+ case kpidIsNotArcType: if (_db.IsNotArcType()) prop = true; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(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
+}
+
+Z7_COM7F_IMF(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
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _db.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-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())
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _db.Items[_db.Refs[index].Did];
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ const 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
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _db.Refs.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ *stream = NULL;
+ const UInt32 itemIndex = _db.Refs[index].Did;
+ const CItem &item = _db.Items[itemIndex];
+ CClusterInStream *streamSpec = new CClusterInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->Stream = _stream;
+ streamSpec->StartOffset = 0;
+
+ const bool isLargeStream = (itemIndex == 0 || _db.IsLargeStream(item.Size));
+ const unsigned bsLog = isLargeStream ? _db.SectorSizeBits : _db.MiniSectorSizeBits;
+ streamSpec->BlockSizeLog = bsLog;
+ streamSpec->Size = item.Size;
+
+ const UInt32 clusterSize = (UInt32)1 << bsLog;
+ const UInt64 numClusters64 = (item.Size + clusterSize - 1) >> bsLog;
+ if (numClusters64 >= ((UInt32)1 << 31))
+ return E_NOTIMPL;
+ streamSpec->Vector.ClearAndReserve((unsigned)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.AddInReserved(sid + 1);
+ sid = _db.Fat[sid];
+ }
+ else
+ {
+ UInt64 val = 0;
+ if (sid >= _db.MatSize || !_db.GetMiniCluster(sid, val) || val >= (UInt64)1 << 32)
+ return S_FALSE;
+ streamSpec->Vector.AddInReserved((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
+}
+
+REGISTER_ARC_I(
+ "Compound", "msi msp doc xls ppt", NULL, 0xE5,
+ kSignature,
+ 0,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/Common/CoderMixer2.cpp b/CPP/7zip/Archive/Common/CoderMixer2.cpp
index baddddf..b6ddeb8 100644
--- a/CPP/7zip/Archive/Common/CoderMixer2.cpp
+++ b/CPP/7zip/Archive/Common/CoderMixer2.cpp
@@ -1,1125 +1,1144 @@
-// CoderMixer2.cpp
-
-#include "StdAfx.h"
-
-#include "CoderMixer2.h"
-
-#ifdef USE_MIXER_ST
-
-STDMETHODIMP CSequentialInStreamCalcSize::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- UInt32 realProcessed = 0;
- HRESULT result = S_OK;
- if (_stream)
- result = _stream->Read(data, size, &realProcessed);
- _size += realProcessed;
- if (size != 0 && realProcessed == 0)
- _wasFinished = true;
- if (processedSize)
- *processedSize = realProcessed;
- return result;
-}
-
-
-STDMETHODIMP COutStreamCalcSize::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- HRESULT result = S_OK;
- if (_stream)
- result = _stream->Write(data, size, &size);
- _size += size;
- if (processedSize)
- *processedSize = size;
- return result;
-}
-
-STDMETHODIMP COutStreamCalcSize::OutStreamFinish()
-{
- HRESULT result = S_OK;
- if (_stream)
- {
- CMyComPtr<IOutStreamFinish> outStreamFinish;
- _stream.QueryInterface(IID_IOutStreamFinish, &outStreamFinish);
- if (outStreamFinish)
- result = outStreamFinish->OutStreamFinish();
- }
- return result;
-}
-
-#endif
-
-
-
-
-namespace NCoderMixer2 {
-
-static void BoolVector_Fill_False(CBoolVector &v, unsigned size)
-{
- v.ClearAndSetSize(size);
- bool *p = &v[0];
- for (unsigned i = 0; i < size; i++)
- p[i] = false;
-}
-
-
-HRESULT CCoder::CheckDataAfterEnd(bool &dataAfterEnd_Error /* , bool &InternalPackSizeError */) const
-{
- if (Coder)
- {
- if (PackSizePointers.IsEmpty() || !PackSizePointers[0])
- return S_OK;
- CMyComPtr<ICompressGetInStreamProcessedSize> getInStreamProcessedSize;
- Coder.QueryInterface(IID_ICompressGetInStreamProcessedSize, (void **)&getInStreamProcessedSize);
- // if (!getInStreamProcessedSize) return E_FAIL;
- if (getInStreamProcessedSize)
- {
- UInt64 processed;
- RINOK(getInStreamProcessedSize->GetInStreamProcessedSize(&processed));
- if (processed != (UInt64)(Int64)-1)
- {
- const UInt64 size = PackSizes[0];
- if (processed < size && Finish)
- dataAfterEnd_Error = true;
- if (processed > size)
- {
- // InternalPackSizeError = true;
- // return S_FALSE;
- }
- }
- }
- }
- else if (Coder2)
- {
- CMyComPtr<ICompressGetInStreamProcessedSize2> getInStreamProcessedSize2;
- Coder2.QueryInterface(IID_ICompressGetInStreamProcessedSize2, (void **)&getInStreamProcessedSize2);
- if (getInStreamProcessedSize2)
- FOR_VECTOR (i, PackSizePointers)
- {
- if (!PackSizePointers[i])
- continue;
- UInt64 processed;
- RINOK(getInStreamProcessedSize2->GetInStreamProcessedSize2(i, &processed));
- if (processed != (UInt64)(Int64)-1)
- {
- const UInt64 size = PackSizes[i];
- if (processed < size && Finish)
- dataAfterEnd_Error = true;
- else if (processed > size)
- {
- // InternalPackSizeError = true;
- // return S_FALSE;
- }
- }
- }
- }
-
- return S_OK;
-}
-
-
-
-class CBondsChecks
-{
- CBoolVector _coderUsed;
-
- bool Init();
- bool CheckCoder(unsigned coderIndex);
-public:
- const CBindInfo *BindInfo;
-
- bool Check();
-};
-
-bool CBondsChecks::CheckCoder(unsigned coderIndex)
-{
- const CCoderStreamsInfo &coder = BindInfo->Coders[coderIndex];
-
- if (coderIndex >= _coderUsed.Size() || _coderUsed[coderIndex])
- return false;
- _coderUsed[coderIndex] = true;
-
- UInt32 start = BindInfo->Coder_to_Stream[coderIndex];
-
- for (unsigned i = 0; i < coder.NumStreams; i++)
- {
- UInt32 ind = start + i;
-
- if (BindInfo->IsStream_in_PackStreams(ind))
- continue;
-
- int bond = BindInfo->FindBond_for_PackStream(ind);
- if (bond < 0)
- return false;
- if (!CheckCoder(BindInfo->Bonds[bond].UnpackIndex))
- return false;
- }
-
- return true;
-}
-
-bool CBondsChecks::Check()
-{
- BoolVector_Fill_False(_coderUsed, BindInfo->Coders.Size());
-
- if (!CheckCoder(BindInfo->UnpackCoder))
- return false;
-
- FOR_VECTOR(i, _coderUsed)
- if (!_coderUsed[i])
- return false;
-
- return true;
-}
-
-void CBindInfo::ClearMaps()
-{
- Coder_to_Stream.Clear();
- Stream_to_Coder.Clear();
-}
-
-bool CBindInfo::CalcMapsAndCheck()
-{
- ClearMaps();
-
- UInt32 numStreams = 0;
-
- if (Coders.Size() == 0)
- return false;
- if (Coders.Size() - 1 != Bonds.Size())
- return false;
-
- FOR_VECTOR(i, Coders)
- {
- Coder_to_Stream.Add(numStreams);
-
- const CCoderStreamsInfo &c = Coders[i];
-
- for (unsigned j = 0; j < c.NumStreams; j++)
- Stream_to_Coder.Add(i);
-
- numStreams += c.NumStreams;
- }
-
- if (numStreams != GetNum_Bonds_and_PackStreams())
- return false;
-
- CBondsChecks bc;
- bc.BindInfo = this;
- return bc.Check();
-}
-
-
-void CCoder::SetCoderInfo(const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish)
-{
- Finish = finish;
-
- if (unpackSize)
- {
- UnpackSize = *unpackSize;
- UnpackSizePointer = &UnpackSize;
- }
- else
- {
- UnpackSize = 0;
- UnpackSizePointer = NULL;
- }
-
- PackSizes.ClearAndSetSize((unsigned)NumStreams);
- PackSizePointers.ClearAndSetSize((unsigned)NumStreams);
-
- for (unsigned i = 0; i < NumStreams; i++)
- {
- if (packSizes && packSizes[i])
- {
- PackSizes[i] = *(packSizes[i]);
- PackSizePointers[i] = &PackSizes[i];
- }
- else
- {
- PackSizes[i] = 0;
- PackSizePointers[i] = NULL;
- }
- }
-}
-
-bool CMixer::Is_UnpackSize_Correct_for_Coder(UInt32 coderIndex)
-{
- if (coderIndex == _bi.UnpackCoder)
- return true;
-
- int bond = _bi.FindBond_for_UnpackStream(coderIndex);
- if (bond < 0)
- throw 20150213;
-
- /*
- UInt32 coderIndex, coderStreamIndex;
- _bi.GetCoder_for_Stream(_bi.Bonds[bond].PackIndex, coderIndex, coderStreamIndex);
- */
- UInt32 nextCoder = _bi.Stream_to_Coder[_bi.Bonds[bond].PackIndex];
-
- if (!IsFilter_Vector[nextCoder])
- return false;
-
- return Is_UnpackSize_Correct_for_Coder(nextCoder);
-}
-
-bool CMixer::Is_PackSize_Correct_for_Stream(UInt32 streamIndex)
-{
- if (_bi.IsStream_in_PackStreams(streamIndex))
- return true;
-
- int bond = _bi.FindBond_for_PackStream(streamIndex);
- if (bond < 0)
- throw 20150213;
-
- UInt32 nextCoder = _bi.Bonds[bond].UnpackIndex;
-
- if (!IsFilter_Vector[nextCoder])
- return false;
-
- return Is_PackSize_Correct_for_Coder(nextCoder);
-}
-
-bool CMixer::Is_PackSize_Correct_for_Coder(UInt32 coderIndex)
-{
- UInt32 startIndex = _bi.Coder_to_Stream[coderIndex];
- UInt32 numStreams = _bi.Coders[coderIndex].NumStreams;
- for (UInt32 i = 0; i < numStreams; i++)
- if (!Is_PackSize_Correct_for_Stream(startIndex + i))
- return false;
- return true;
-}
-
-bool CMixer::IsThere_ExternalCoder_in_PackTree(UInt32 coderIndex)
-{
- if (IsExternal_Vector[coderIndex])
- return true;
- UInt32 startIndex = _bi.Coder_to_Stream[coderIndex];
- UInt32 numStreams = _bi.Coders[coderIndex].NumStreams;
- for (UInt32 i = 0; i < numStreams; i++)
- {
- UInt32 si = startIndex + i;
- if (_bi.IsStream_in_PackStreams(si))
- continue;
-
- int bond = _bi.FindBond_for_PackStream(si);
- if (bond < 0)
- throw 20150213;
-
- if (IsThere_ExternalCoder_in_PackTree(_bi.Bonds[bond].UnpackIndex))
- return true;
- }
- return false;
-}
-
-
-
-
-#ifdef USE_MIXER_ST
-
-CMixerST::CMixerST(bool encodeMode):
- CMixer(encodeMode)
- {}
-
-CMixerST::~CMixerST() {}
-
-void CMixerST::AddCoder(const CCreatedCoder &cod)
-{
- IsFilter_Vector.Add(cod.IsFilter);
- IsExternal_Vector.Add(cod.IsExternal);
- // const CCoderStreamsInfo &c = _bi.Coders[_coders.Size()];
- CCoderST &c2 = _coders.AddNew();
- c2.NumStreams = cod.NumStreams;
- c2.Coder = cod.Coder;
- c2.Coder2 = cod.Coder2;
-
- /*
- if (isFilter)
- {
- c2.CanRead = true;
- c2.CanWrite = true;
- }
- else
- */
- {
- IUnknown *unk = (cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2);
- {
- CMyComPtr<ISequentialInStream> s;
- unk->QueryInterface(IID_ISequentialInStream, (void**)&s);
- c2.CanRead = (s != NULL);
- }
- {
- CMyComPtr<ISequentialOutStream> s;
- unk->QueryInterface(IID_ISequentialOutStream, (void**)&s);
- c2.CanWrite = (s != NULL);
- }
- }
-}
-
-CCoder &CMixerST::GetCoder(unsigned index)
-{
- return _coders[index];
-}
-
-void CMixerST::ReInit() {}
-
-HRESULT CMixerST::GetInStream2(
- ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */
- UInt32 outStreamIndex, ISequentialInStream **inStreamRes)
-{
- UInt32 coderIndex = outStreamIndex, coderStreamIndex = 0;
-
- if (EncodeMode)
- {
- _bi.GetCoder_for_Stream(outStreamIndex, coderIndex, coderStreamIndex);
- if (coderStreamIndex != 0)
- return E_NOTIMPL;
- }
-
- const CCoder &coder = _coders[coderIndex];
-
- CMyComPtr<ISequentialInStream> seqInStream;
- coder.QueryInterface(IID_ISequentialInStream, (void **)&seqInStream);
- if (!seqInStream)
- return E_NOTIMPL;
-
- UInt32 numInStreams = EncodeMode ? 1 : coder.NumStreams;
- UInt32 startIndex = EncodeMode ? coderIndex : _bi.Coder_to_Stream[coderIndex];
-
- bool isSet = false;
-
- if (numInStreams == 1)
- {
- CMyComPtr<ICompressSetInStream> setStream;
- coder.QueryInterface(IID_ICompressSetInStream, (void **)&setStream);
- if (setStream)
- {
- CMyComPtr<ISequentialInStream> seqInStream2;
- RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + 0, &seqInStream2));
- RINOK(setStream->SetInStream(seqInStream2));
- isSet = true;
- }
- }
-
- if (!isSet && numInStreams != 0)
- {
- CMyComPtr<ICompressSetInStream2> setStream2;
- coder.QueryInterface(IID_ICompressSetInStream2, (void **)&setStream2);
- if (!setStream2)
- return E_NOTIMPL;
-
- for (UInt32 i = 0; i < numInStreams; i++)
- {
- CMyComPtr<ISequentialInStream> seqInStream2;
- RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + i, &seqInStream2));
- RINOK(setStream2->SetInStream2(i, seqInStream2));
- }
- }
-
- *inStreamRes = seqInStream.Detach();
- return S_OK;
-}
-
-
-HRESULT CMixerST::GetInStream(
- ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */
- UInt32 inStreamIndex, ISequentialInStream **inStreamRes)
-{
- CMyComPtr<ISequentialInStream> seqInStream;
-
- {
- int index = -1;
- if (EncodeMode)
- {
- if (_bi.UnpackCoder == inStreamIndex)
- index = 0;
- }
- else
- index = _bi.FindStream_in_PackStreams(inStreamIndex);
-
- if (index >= 0)
- {
- seqInStream = inStreams[(unsigned)index];
- *inStreamRes = seqInStream.Detach();
- return S_OK;
- }
- }
-
- int bond = FindBond_for_Stream(
- true, // forInputStream
- inStreamIndex);
- if (bond < 0)
- return E_INVALIDARG;
-
- RINOK(GetInStream2(inStreams, /* inSizes, */
- _bi.Bonds[bond].Get_OutIndex(EncodeMode), &seqInStream));
-
- while (_binderStreams.Size() <= (unsigned)bond)
- _binderStreams.AddNew();
- CStBinderStream &bs = _binderStreams[bond];
-
- if (bs.StreamRef || bs.InStreamSpec)
- return E_NOTIMPL;
-
- CSequentialInStreamCalcSize *spec = new CSequentialInStreamCalcSize;
- bs.StreamRef = spec;
- bs.InStreamSpec = spec;
-
- spec->SetStream(seqInStream);
- spec->Init();
-
- seqInStream = bs.InStreamSpec;
-
- *inStreamRes = seqInStream.Detach();
- return S_OK;
-}
-
-
-HRESULT CMixerST::GetOutStream(
- ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */
- UInt32 outStreamIndex, ISequentialOutStream **outStreamRes)
-{
- CMyComPtr<ISequentialOutStream> seqOutStream;
-
- {
- int index = -1;
- if (!EncodeMode)
- {
- if (_bi.UnpackCoder == outStreamIndex)
- index = 0;
- }
- else
- index = _bi.FindStream_in_PackStreams(outStreamIndex);
-
- if (index >= 0)
- {
- seqOutStream = outStreams[(unsigned)index];
- *outStreamRes = seqOutStream.Detach();
- return S_OK;
- }
- }
-
- int bond = FindBond_for_Stream(
- false, // forInputStream
- outStreamIndex);
- if (bond < 0)
- return E_INVALIDARG;
-
- UInt32 inStreamIndex = _bi.Bonds[bond].Get_InIndex(EncodeMode);
-
- UInt32 coderIndex = inStreamIndex;
- UInt32 coderStreamIndex = 0;
-
- if (!EncodeMode)
- _bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex);
-
- CCoder &coder = _coders[coderIndex];
-
- /*
- if (!coder.Coder)
- return E_NOTIMPL;
- */
-
- coder.QueryInterface(IID_ISequentialOutStream, (void **)&seqOutStream);
- if (!seqOutStream)
- return E_NOTIMPL;
-
- UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1;
- UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex;
-
- bool isSet = false;
-
- if (numOutStreams == 1)
- {
- CMyComPtr<ICompressSetOutStream> setOutStream;
- coder.Coder.QueryInterface(IID_ICompressSetOutStream, &setOutStream);
- if (setOutStream)
- {
- CMyComPtr<ISequentialOutStream> seqOutStream2;
- RINOK(GetOutStream(outStreams, /* outSizes, */ startIndex + 0, &seqOutStream2));
- RINOK(setOutStream->SetOutStream(seqOutStream2));
- isSet = true;
- }
- }
-
- if (!isSet && numOutStreams != 0)
- {
- return E_NOTIMPL;
- /*
- CMyComPtr<ICompressSetOutStream2> setStream2;
- coder.QueryInterface(IID_ICompressSetOutStream2, (void **)&setStream2);
- if (!setStream2)
- return E_NOTIMPL;
- for (UInt32 i = 0; i < numOutStreams; i++)
- {
- CMyComPtr<ISequentialOutStream> seqOutStream2;
- RINOK(GetOutStream(outStreams, startIndex + i, &seqOutStream2));
- RINOK(setStream2->SetOutStream2(i, seqOutStream2));
- }
- */
- }
-
- while (_binderStreams.Size() <= (unsigned)bond)
- _binderStreams.AddNew();
- CStBinderStream &bs = _binderStreams[bond];
-
- if (bs.StreamRef || bs.OutStreamSpec)
- return E_NOTIMPL;
-
- COutStreamCalcSize *spec = new COutStreamCalcSize;
- bs.StreamRef = (ISequentialOutStream *)spec;
- bs.OutStreamSpec = spec;
-
- spec->SetStream(seqOutStream);
- spec->Init();
-
- seqOutStream = bs.OutStreamSpec;
-
- *outStreamRes = seqOutStream.Detach();
- return S_OK;
-}
-
-
-static HRESULT GetError(HRESULT res, HRESULT res2)
-{
- if (res == res2)
- return res;
- if (res == S_OK)
- return res2;
- if (res == k_My_HRESULT_WritingWasCut)
- {
- if (res2 != S_OK)
- return res2;
- }
- return res;
-}
-
-
-HRESULT CMixerST::FinishStream(UInt32 streamIndex)
-{
- {
- int index = -1;
- if (!EncodeMode)
- {
- if (_bi.UnpackCoder == streamIndex)
- index = 0;
- }
- else
- index = _bi.FindStream_in_PackStreams(streamIndex);
-
- if (index >= 0)
- return S_OK;
- }
-
- int bond = FindBond_for_Stream(
- false, // forInputStream
- streamIndex);
- if (bond < 0)
- return E_INVALIDARG;
-
- UInt32 inStreamIndex = _bi.Bonds[bond].Get_InIndex(EncodeMode);
-
- UInt32 coderIndex = inStreamIndex;
- UInt32 coderStreamIndex = 0;
- if (!EncodeMode)
- _bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex);
-
- CCoder &coder = _coders[coderIndex];
- CMyComPtr<IOutStreamFinish> finish;
- coder.QueryInterface(IID_IOutStreamFinish, (void **)&finish);
- HRESULT res = S_OK;
- if (finish)
- {
- res = finish->OutStreamFinish();
- }
- return GetError(res, FinishCoder(coderIndex));
-}
-
-
-HRESULT CMixerST::FinishCoder(UInt32 coderIndex)
-{
- CCoder &coder = _coders[coderIndex];
-
- UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1;
- UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex;
-
- HRESULT res = S_OK;
- for (unsigned i = 0; i < numOutStreams; i++)
- res = GetError(res, FinishStream(startIndex + i));
- return res;
-}
-
-
-void CMixerST::SelectMainCoder(bool useFirst)
-{
- unsigned ci = _bi.UnpackCoder;
-
- int firstNonFilter = -1;
- int firstAllowed = ci;
-
- for (;;)
- {
- const CCoderST &coder = _coders[ci];
- // break;
-
- if (ci != _bi.UnpackCoder)
- if (EncodeMode ? !coder.CanWrite : !coder.CanRead)
- {
- firstAllowed = ci;
- firstNonFilter = -2;
- }
-
- if (coder.NumStreams != 1)
- break;
-
- UInt32 st = _bi.Coder_to_Stream[ci];
- if (_bi.IsStream_in_PackStreams(st))
- break;
- int bond = _bi.FindBond_for_PackStream(st);
- if (bond < 0)
- throw 20150213;
-
- if (EncodeMode ? !coder.CanRead : !coder.CanWrite)
- break;
-
- if (firstNonFilter == -1 && !IsFilter_Vector[ci])
- firstNonFilter = ci;
-
- ci = _bi.Bonds[bond].UnpackIndex;
- }
-
- if (useFirst)
- ci = firstAllowed;
- else if (firstNonFilter >= 0)
- ci = firstNonFilter;
-
- MainCoderIndex = ci;
-}
-
-
-HRESULT CMixerST::Code(
- ISequentialInStream * const *inStreams,
- ISequentialOutStream * const *outStreams,
- ICompressProgressInfo *progress,
- bool &dataAfterEnd_Error)
-{
- // InternalPackSizeError = false;
- dataAfterEnd_Error = false;
-
- _binderStreams.Clear();
- unsigned ci = MainCoderIndex;
-
- const CCoder &mainCoder = _coders[MainCoderIndex];
-
- CObjectVector< CMyComPtr<ISequentialInStream> > seqInStreams;
- CObjectVector< CMyComPtr<ISequentialOutStream> > seqOutStreams;
-
- UInt32 numInStreams = EncodeMode ? 1 : mainCoder.NumStreams;
- UInt32 numOutStreams = !EncodeMode ? 1 : mainCoder.NumStreams;
-
- UInt32 startInIndex = EncodeMode ? ci : _bi.Coder_to_Stream[ci];
- UInt32 startOutIndex = !EncodeMode ? ci : _bi.Coder_to_Stream[ci];
-
- UInt32 i;
-
- for (i = 0; i < numInStreams; i++)
- {
- CMyComPtr<ISequentialInStream> seqInStream;
- RINOK(GetInStream(inStreams, /* inSizes, */ startInIndex + i, &seqInStream));
- seqInStreams.Add(seqInStream);
- }
-
- for (i = 0; i < 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 < numInStreams; i++)
- seqInStreamsSpec.Add(seqInStreams[i]);
- for (i = 0; i < numOutStreams; i++)
- seqOutStreamsSpec.Add(seqOutStreams[i]);
-
- for (i = 0; i < _coders.Size(); i++)
- {
- if (i == ci)
- continue;
-
- CCoder &coder = _coders[i];
-
- if (EncodeMode)
- {
- CMyComPtr<ICompressInitEncoder> initEncoder;
- coder.QueryInterface(IID_ICompressInitEncoder, (void **)&initEncoder);
- if (initEncoder)
- RINOK(initEncoder->InitEncoder());
- }
- else
- {
- CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize;
- coder.QueryInterface(IID_ICompressSetOutStreamSize, (void **)&setOutStreamSize);
- if (setOutStreamSize)
- RINOK(setOutStreamSize->SetOutStreamSize(
- EncodeMode ? coder.PackSizePointers[0] : coder.UnpackSizePointer));
- }
- }
-
- const UInt64 * const *isSizes2 = EncodeMode ? &mainCoder.UnpackSizePointer : &mainCoder.PackSizePointers.Front();
- const UInt64 * const *outSizes2 = EncodeMode ? &mainCoder.PackSizePointers.Front() : &mainCoder.UnpackSizePointer;
-
- HRESULT res;
- if (mainCoder.Coder)
- {
- res = mainCoder.Coder->Code(
- seqInStreamsSpec[0], seqOutStreamsSpec[0],
- isSizes2[0], outSizes2[0],
- progress);
- }
- else
- {
- res = mainCoder.Coder2->Code(
- &seqInStreamsSpec.Front(), isSizes2, numInStreams,
- &seqOutStreamsSpec.Front(), outSizes2, numOutStreams,
- progress);
- }
-
- if (res == k_My_HRESULT_WritingWasCut)
- res = S_OK;
-
- if (res == S_OK || res == S_FALSE)
- {
- res = GetError(res, FinishCoder(ci));
- }
-
- for (i = 0; i < _binderStreams.Size(); i++)
- {
- const CStBinderStream &bs = _binderStreams[i];
- if (bs.InStreamSpec)
- bs.InStreamSpec->ReleaseStream();
- else
- bs.OutStreamSpec->ReleaseStream();
- }
-
- if (res == k_My_HRESULT_WritingWasCut)
- res = S_OK;
-
- if (res != S_OK)
- return res;
-
- for (i = 0; i < _coders.Size(); i++)
- {
- RINOK(_coders[i].CheckDataAfterEnd(dataAfterEnd_Error /*, InternalPackSizeError */));
- }
-
- return S_OK;
-}
-
-
-HRESULT CMixerST::GetMainUnpackStream(
- ISequentialInStream * const *inStreams,
- ISequentialInStream **inStreamRes)
-{
- CMyComPtr<ISequentialInStream> seqInStream;
-
- RINOK(GetInStream2(inStreams, /* inSizes, */
- _bi.UnpackCoder, &seqInStream))
-
- FOR_VECTOR (i, _coders)
- {
- CCoder &coder = _coders[i];
- CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize;
- coder.QueryInterface(IID_ICompressSetOutStreamSize, (void **)&setOutStreamSize);
- if (setOutStreamSize)
- {
- RINOK(setOutStreamSize->SetOutStreamSize(coder.UnpackSizePointer));
- }
- }
-
- *inStreamRes = seqInStream.Detach();
- return S_OK;
-}
-
-
-UInt64 CMixerST::GetBondStreamSize(unsigned bondIndex) const
-{
- const CStBinderStream &bs = _binderStreams[bondIndex];
- if (bs.InStreamSpec)
- return bs.InStreamSpec->GetSize();
- return bs.OutStreamSpec->GetSize();
-}
-
-#endif
-
-
-
-
-
-
-#ifdef USE_MIXER_MT
-
-
-void CCoderMT::Execute()
-{
- try
- {
- Code(NULL);
- }
- catch(...)
- {
- Result = E_FAIL;
- }
-}
-
-void CCoderMT::Code(ICompressProgressInfo *progress)
-{
- unsigned numInStreams = EncodeMode ? 1 : NumStreams;
- unsigned numOutStreams = EncodeMode ? NumStreams : 1;
-
- InStreamPointers.ClearAndReserve(numInStreams);
- OutStreamPointers.ClearAndReserve(numOutStreams);
-
- unsigned i;
-
- for (i = 0; i < numInStreams; i++)
- InStreamPointers.AddInReserved((ISequentialInStream *)InStreams[i]);
-
- for (i = 0; i < numOutStreams; i++)
- OutStreamPointers.AddInReserved((ISequentialOutStream *)OutStreams[i]);
-
- // we suppose that UnpackSizePointer and PackSizePointers contain correct pointers.
- /*
- if (UnpackSizePointer)
- UnpackSizePointer = &UnpackSize;
- for (i = 0; i < NumStreams; i++)
- if (PackSizePointers[i])
- PackSizePointers[i] = &PackSizes[i];
- */
-
- CReleaser releaser(*this);
-
- if (Coder)
- Result = Coder->Code(InStreamPointers[0], OutStreamPointers[0],
- EncodeMode ? UnpackSizePointer : PackSizePointers[0],
- EncodeMode ? PackSizePointers[0] : UnpackSizePointer,
- progress);
- else
- Result = Coder2->Code(
- &InStreamPointers.Front(), EncodeMode ? &UnpackSizePointer : &PackSizePointers.Front(), numInStreams,
- &OutStreamPointers.Front(), EncodeMode ? &PackSizePointers.Front(): &UnpackSizePointer, numOutStreams,
- progress);
-}
-
-HRESULT CMixerMT::SetBindInfo(const CBindInfo &bindInfo)
-{
- CMixer::SetBindInfo(bindInfo);
-
- _streamBinders.Clear();
- FOR_VECTOR (i, _bi.Bonds)
- {
- RINOK(_streamBinders.AddNew().CreateEvents());
- }
- return S_OK;
-}
-
-void CMixerMT::AddCoder(const CCreatedCoder &cod)
-{
- IsFilter_Vector.Add(cod.IsFilter);
- IsExternal_Vector.Add(cod.IsExternal);
- // const CCoderStreamsInfo &c = _bi.Coders[_coders.Size()];
- CCoderMT &c2 = _coders.AddNew();
- c2.NumStreams = cod.NumStreams;
- c2.Coder = cod.Coder;
- c2.Coder2 = cod.Coder2;
- c2.EncodeMode = EncodeMode;
-}
-
-CCoder &CMixerMT::GetCoder(unsigned index)
-{
- return _coders[index];
-}
-
-void CMixerMT::ReInit()
-{
- FOR_VECTOR (i, _streamBinders)
- _streamBinders[i].ReInit();
-}
-
-void CMixerMT::SelectMainCoder(bool useFirst)
-{
- unsigned ci = _bi.UnpackCoder;
-
- if (!useFirst)
- for (;;)
- {
- if (_coders[ci].NumStreams != 1)
- break;
- if (!IsFilter_Vector[ci])
- break;
-
- UInt32 st = _bi.Coder_to_Stream[ci];
- if (_bi.IsStream_in_PackStreams(st))
- break;
- int bond = _bi.FindBond_for_PackStream(st);
- if (bond < 0)
- throw 20150213;
- ci = _bi.Bonds[bond].UnpackIndex;
- }
-
- MainCoderIndex = ci;
-}
-
-HRESULT CMixerMT::Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams)
-{
- unsigned i;
-
- for (i = 0; i < _coders.Size(); i++)
- {
- CCoderMT &coderInfo = _coders[i];
- const CCoderStreamsInfo &csi = _bi.Coders[i];
-
- UInt32 j;
-
- unsigned numInStreams = EncodeMode ? 1 : csi.NumStreams;
- unsigned numOutStreams = EncodeMode ? csi.NumStreams : 1;
-
- coderInfo.InStreams.Clear();
- for (j = 0; j < numInStreams; j++)
- coderInfo.InStreams.AddNew();
-
- coderInfo.OutStreams.Clear();
- for (j = 0; j < numOutStreams; j++)
- coderInfo.OutStreams.AddNew();
- }
-
- for (i = 0; i < _bi.Bonds.Size(); i++)
- {
- const CBond &bond = _bi.Bonds[i];
-
- UInt32 inCoderIndex, inCoderStreamIndex;
- UInt32 outCoderIndex, outCoderStreamIndex;
-
- {
- UInt32 coderIndex, coderStreamIndex;
- _bi.GetCoder_for_Stream(bond.PackIndex, coderIndex, coderStreamIndex);
-
- inCoderIndex = EncodeMode ? bond.UnpackIndex : coderIndex;
- outCoderIndex = EncodeMode ? coderIndex : bond.UnpackIndex;
-
- inCoderStreamIndex = EncodeMode ? 0 : coderStreamIndex;
- outCoderStreamIndex = EncodeMode ? coderStreamIndex : 0;
- }
-
- _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);
- }
- }
-
- {
- CCoderMT &cod = _coders[_bi.UnpackCoder];
- if (EncodeMode)
- cod.InStreams[0] = inStreams[0];
- else
- cod.OutStreams[0] = outStreams[0];
- }
-
- for (i = 0; i < _bi.PackStreams.Size(); i++)
- {
- UInt32 coderIndex, coderStreamIndex;
- _bi.GetCoder_for_Stream(_bi.PackStreams[i], coderIndex, coderStreamIndex);
- CCoderMT &cod = _coders[coderIndex];
- if (EncodeMode)
- cod.OutStreams[coderStreamIndex] = outStreams[i];
- else
- cod.InStreams[coderStreamIndex] = inStreams[i];
- }
-
- return S_OK;
-}
-
-HRESULT CMixerMT::ReturnIfError(HRESULT code)
-{
- FOR_VECTOR (i, _coders)
- if (_coders[i].Result == code)
- return code;
- return S_OK;
-}
-
-HRESULT CMixerMT::Code(
- ISequentialInStream * const *inStreams,
- ISequentialOutStream * const *outStreams,
- ICompressProgressInfo *progress,
- bool &dataAfterEnd_Error)
-{
- // InternalPackSizeError = false;
- dataAfterEnd_Error = false;
-
- Init(inStreams, outStreams);
-
- unsigned i;
- for (i = 0; i < _coders.Size(); i++)
- if (i != MainCoderIndex)
- {
- RINOK(_coders[i].Create());
- }
-
- for (i = 0; i < _coders.Size(); i++)
- if (i != MainCoderIndex)
- _coders[i].Start();
-
- _coders[MainCoderIndex].Code(progress);
-
- for (i = 0; i < _coders.Size(); i++)
- if (i != MainCoderIndex)
- _coders[i].WaitExecuteFinish();
-
- 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 != k_My_HRESULT_WritingWasCut
- && result != S_FALSE
- && result != E_FAIL)
- return result;
- }
-
- RINOK(ReturnIfError(S_FALSE));
-
- for (i = 0; i < _coders.Size(); i++)
- {
- HRESULT result = _coders[i].Result;
- if (result != S_OK && result != k_My_HRESULT_WritingWasCut)
- return result;
- }
-
- for (i = 0; i < _coders.Size(); i++)
- {
- RINOK(_coders[i].CheckDataAfterEnd(dataAfterEnd_Error /* , InternalPackSizeError */));
- }
-
- return S_OK;
-}
-
-UInt64 CMixerMT::GetBondStreamSize(unsigned bondIndex) const
-{
- return _streamBinders[bondIndex].ProcessedSize;
-}
-
-#endif
-
-}
+// CoderMixer2.cpp
+
+#include "StdAfx.h"
+
+#include "CoderMixer2.h"
+
+#ifdef USE_MIXER_ST
+
+Z7_COM7F_IMF(CSequentialInStreamCalcSize::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ UInt32 realProcessed = 0;
+ HRESULT result = S_OK;
+ if (_stream)
+ result = _stream->Read(data, size, &realProcessed);
+ _size += realProcessed;
+ if (size != 0 && realProcessed == 0)
+ _wasFinished = true;
+ if (processedSize)
+ *processedSize = realProcessed;
+ return result;
+}
+
+
+Z7_COM7F_IMF(COutStreamCalcSize::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ HRESULT result = S_OK;
+ if (_stream)
+ result = _stream->Write(data, size, &size);
+ _size += size;
+ if (processedSize)
+ *processedSize = size;
+ return result;
+}
+
+Z7_COM7F_IMF(COutStreamCalcSize::OutStreamFinish())
+{
+ HRESULT result = S_OK;
+ if (_stream)
+ {
+ CMyComPtr<IOutStreamFinish> outStreamFinish;
+ _stream.QueryInterface(IID_IOutStreamFinish, &outStreamFinish);
+ if (outStreamFinish)
+ result = outStreamFinish->OutStreamFinish();
+ }
+ return result;
+}
+
+#endif
+
+
+
+
+namespace NCoderMixer2 {
+
+static void BoolVector_Fill_False(CBoolVector &v, unsigned size)
+{
+ v.ClearAndSetSize(size);
+ bool *p = &v[0];
+ for (unsigned i = 0; i < size; i++)
+ p[i] = false;
+}
+
+
+HRESULT CCoder::CheckDataAfterEnd(bool &dataAfterEnd_Error /* , bool &InternalPackSizeError */) const
+{
+ if (Coder)
+ {
+ if (PackSizePointers.IsEmpty() || !PackSizePointers[0])
+ return S_OK;
+ CMyComPtr<ICompressGetInStreamProcessedSize> getInStreamProcessedSize;
+ Coder.QueryInterface(IID_ICompressGetInStreamProcessedSize, (void **)&getInStreamProcessedSize);
+ // if (!getInStreamProcessedSize) return E_FAIL;
+ if (getInStreamProcessedSize)
+ {
+ UInt64 processed;
+ RINOK(getInStreamProcessedSize->GetInStreamProcessedSize(&processed))
+ if (processed != (UInt64)(Int64)-1)
+ {
+ const UInt64 size = PackSizes[0];
+ if (processed < size && Finish)
+ dataAfterEnd_Error = true;
+ if (processed > size)
+ {
+ // InternalPackSizeError = true;
+ // return S_FALSE;
+ }
+ }
+ }
+ }
+ else if (Coder2)
+ {
+ CMyComPtr<ICompressGetInStreamProcessedSize2> getInStreamProcessedSize2;
+ Coder2.QueryInterface(IID_ICompressGetInStreamProcessedSize2, (void **)&getInStreamProcessedSize2);
+ if (getInStreamProcessedSize2)
+ FOR_VECTOR (i, PackSizePointers)
+ {
+ if (!PackSizePointers[i])
+ continue;
+ UInt64 processed;
+ RINOK(getInStreamProcessedSize2->GetInStreamProcessedSize2(i, &processed))
+ if (processed != (UInt64)(Int64)-1)
+ {
+ const UInt64 size = PackSizes[i];
+ if (processed < size && Finish)
+ dataAfterEnd_Error = true;
+ else if (processed > size)
+ {
+ // InternalPackSizeError = true;
+ // return S_FALSE;
+ }
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+class CBondsChecks
+{
+ CBoolVector _coderUsed;
+
+ bool Init();
+ bool CheckCoder(unsigned coderIndex);
+public:
+ const CBindInfo *BindInfo;
+
+ bool Check();
+};
+
+bool CBondsChecks::CheckCoder(unsigned coderIndex)
+{
+ const CCoderStreamsInfo &coder = BindInfo->Coders[coderIndex];
+
+ if (coderIndex >= _coderUsed.Size() || _coderUsed[coderIndex])
+ return false;
+ _coderUsed[coderIndex] = true;
+
+ const UInt32 start = BindInfo->Coder_to_Stream[coderIndex];
+
+ for (unsigned i = 0; i < coder.NumStreams; i++)
+ {
+ UInt32 ind = start + i;
+
+ if (BindInfo->IsStream_in_PackStreams(ind))
+ continue;
+
+ const int bond = BindInfo->FindBond_for_PackStream(ind);
+ if (bond < 0)
+ return false;
+ if (!CheckCoder(BindInfo->Bonds[(unsigned)bond].UnpackIndex))
+ return false;
+ }
+
+ return true;
+}
+
+bool CBondsChecks::Check()
+{
+ BoolVector_Fill_False(_coderUsed, BindInfo->Coders.Size());
+
+ if (!CheckCoder(BindInfo->UnpackCoder))
+ return false;
+
+ FOR_VECTOR(i, _coderUsed)
+ if (!_coderUsed[i])
+ return false;
+
+ return true;
+}
+
+void CBindInfo::ClearMaps()
+{
+ Coder_to_Stream.Clear();
+ Stream_to_Coder.Clear();
+}
+
+bool CBindInfo::CalcMapsAndCheck()
+{
+ ClearMaps();
+
+ UInt32 numStreams = 0;
+
+ if (Coders.Size() == 0)
+ return false;
+ if (Coders.Size() - 1 != Bonds.Size())
+ return false;
+
+ FOR_VECTOR(i, Coders)
+ {
+ Coder_to_Stream.Add(numStreams);
+
+ const CCoderStreamsInfo &c = Coders[i];
+
+ for (unsigned j = 0; j < c.NumStreams; j++)
+ Stream_to_Coder.Add(i);
+
+ numStreams += c.NumStreams;
+ }
+
+ if (numStreams != GetNum_Bonds_and_PackStreams())
+ return false;
+
+ CBondsChecks bc;
+ bc.BindInfo = this;
+ return bc.Check();
+}
+
+
+void CCoder::SetCoderInfo(const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish)
+{
+ Finish = finish;
+
+ if (unpackSize)
+ {
+ UnpackSize = *unpackSize;
+ UnpackSizePointer = &UnpackSize;
+ }
+ else
+ {
+ UnpackSize = 0;
+ UnpackSizePointer = NULL;
+ }
+
+ PackSizes.ClearAndSetSize((unsigned)NumStreams);
+ PackSizePointers.ClearAndSetSize((unsigned)NumStreams);
+
+ for (unsigned i = 0; i < NumStreams; i++)
+ {
+ if (packSizes && packSizes[i])
+ {
+ PackSizes[i] = *(packSizes[i]);
+ PackSizePointers[i] = &PackSizes[i];
+ }
+ else
+ {
+ PackSizes[i] = 0;
+ PackSizePointers[i] = NULL;
+ }
+ }
+}
+
+bool CMixer::Is_UnpackSize_Correct_for_Coder(UInt32 coderIndex)
+{
+ if (coderIndex == _bi.UnpackCoder)
+ return true;
+
+ const int bond = _bi.FindBond_for_UnpackStream(coderIndex);
+ if (bond < 0)
+ throw 20150213;
+
+ /*
+ UInt32 coderIndex, coderStreamIndex;
+ _bi.GetCoder_for_Stream(_bi.Bonds[(unsigned)bond].PackIndex, coderIndex, coderStreamIndex);
+ */
+ const UInt32 nextCoder = _bi.Stream_to_Coder[_bi.Bonds[(unsigned)bond].PackIndex];
+
+ if (!IsFilter_Vector[nextCoder])
+ return false;
+
+ return Is_UnpackSize_Correct_for_Coder(nextCoder);
+}
+
+bool CMixer::Is_PackSize_Correct_for_Stream(UInt32 streamIndex)
+{
+ if (_bi.IsStream_in_PackStreams(streamIndex))
+ return true;
+
+ const int bond = _bi.FindBond_for_PackStream(streamIndex);
+ if (bond < 0)
+ throw 20150213;
+
+ const UInt32 nextCoder = _bi.Bonds[(unsigned)bond].UnpackIndex;
+
+ if (!IsFilter_Vector[nextCoder])
+ return false;
+
+ return Is_PackSize_Correct_for_Coder(nextCoder);
+}
+
+bool CMixer::Is_PackSize_Correct_for_Coder(UInt32 coderIndex)
+{
+ const UInt32 startIndex = _bi.Coder_to_Stream[coderIndex];
+ const UInt32 numStreams = _bi.Coders[coderIndex].NumStreams;
+ for (UInt32 i = 0; i < numStreams; i++)
+ if (!Is_PackSize_Correct_for_Stream(startIndex + i))
+ return false;
+ return true;
+}
+
+bool CMixer::IsThere_ExternalCoder_in_PackTree(UInt32 coderIndex)
+{
+ if (IsExternal_Vector[coderIndex])
+ return true;
+ const UInt32 startIndex = _bi.Coder_to_Stream[coderIndex];
+ const UInt32 numStreams = _bi.Coders[coderIndex].NumStreams;
+ for (UInt32 i = 0; i < numStreams; i++)
+ {
+ const UInt32 si = startIndex + i;
+ if (_bi.IsStream_in_PackStreams(si))
+ continue;
+
+ const int bond = _bi.FindBond_for_PackStream(si);
+ if (bond < 0)
+ throw 20150213;
+
+ if (IsThere_ExternalCoder_in_PackTree(_bi.Bonds[(unsigned)bond].UnpackIndex))
+ return true;
+ }
+ return false;
+}
+
+
+
+
+#ifdef USE_MIXER_ST
+
+CMixerST::CMixerST(bool encodeMode):
+ CMixer(encodeMode)
+ {}
+
+CMixerST::~CMixerST() {}
+
+void CMixerST::AddCoder(const CCreatedCoder &cod)
+{
+ IsFilter_Vector.Add(cod.IsFilter);
+ IsExternal_Vector.Add(cod.IsExternal);
+ // const CCoderStreamsInfo &c = _bi.Coders[_coders.Size()];
+ CCoderST &c2 = _coders.AddNew();
+ c2.NumStreams = cod.NumStreams;
+ c2.Coder = cod.Coder;
+ c2.Coder2 = cod.Coder2;
+
+ /*
+ if (isFilter)
+ {
+ c2.CanRead = true;
+ c2.CanWrite = true;
+ }
+ else
+ */
+ {
+ IUnknown *unk = (cod.Coder ? (IUnknown *)cod.Coder : (IUnknown *)cod.Coder2);
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(ISequentialInStream, s, unk)
+ c2.CanRead = (s != NULL);
+ }
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(ISequentialOutStream, s, unk)
+ c2.CanWrite = (s != NULL);
+ }
+ }
+}
+
+CCoder &CMixerST::GetCoder(unsigned index)
+{
+ return _coders[index];
+}
+
+HRESULT CMixerST::ReInit2() { return S_OK; }
+
+HRESULT CMixerST::GetInStream2(
+ ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */
+ UInt32 outStreamIndex, ISequentialInStream **inStreamRes)
+{
+ UInt32 coderIndex = outStreamIndex, coderStreamIndex = 0;
+
+ if (EncodeMode)
+ {
+ _bi.GetCoder_for_Stream(outStreamIndex, coderIndex, coderStreamIndex);
+ if (coderStreamIndex != 0)
+ return E_NOTIMPL;
+ }
+
+ const CCoder &coder = _coders[coderIndex];
+
+ CMyComPtr<ISequentialInStream> seqInStream;
+ coder.QueryInterface(IID_ISequentialInStream, (void **)&seqInStream);
+ if (!seqInStream)
+ return E_NOTIMPL;
+
+ const UInt32 numInStreams = EncodeMode ? 1 : coder.NumStreams;
+ const UInt32 startIndex = EncodeMode ? coderIndex : _bi.Coder_to_Stream[coderIndex];
+
+ bool isSet = false;
+
+ if (numInStreams == 1)
+ {
+ CMyComPtr<ICompressSetInStream> setStream;
+ coder.QueryInterface(IID_ICompressSetInStream, (void **)&setStream);
+ if (setStream)
+ {
+ CMyComPtr<ISequentialInStream> seqInStream2;
+ RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + 0, &seqInStream2))
+ RINOK(setStream->SetInStream(seqInStream2))
+ isSet = true;
+ }
+ }
+
+ if (!isSet && numInStreams != 0)
+ {
+ CMyComPtr<ICompressSetInStream2> setStream2;
+ coder.QueryInterface(IID_ICompressSetInStream2, (void **)&setStream2);
+ if (!setStream2)
+ return E_NOTIMPL;
+
+ for (UInt32 i = 0; i < numInStreams; i++)
+ {
+ CMyComPtr<ISequentialInStream> seqInStream2;
+ RINOK(GetInStream(inStreams, /* inSizes, */ startIndex + i, &seqInStream2))
+ RINOK(setStream2->SetInStream2(i, seqInStream2))
+ }
+ }
+
+ *inStreamRes = seqInStream.Detach();
+ return S_OK;
+}
+
+
+HRESULT CMixerST::GetInStream(
+ ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */
+ UInt32 inStreamIndex, ISequentialInStream **inStreamRes)
+{
+ CMyComPtr<ISequentialInStream> seqInStream;
+
+ {
+ int index = -1;
+ if (EncodeMode)
+ {
+ if (_bi.UnpackCoder == inStreamIndex)
+ index = 0;
+ }
+ else
+ index = _bi.FindStream_in_PackStreams(inStreamIndex);
+
+ if (index >= 0)
+ {
+ seqInStream = inStreams[(unsigned)index];
+ *inStreamRes = seqInStream.Detach();
+ return S_OK;
+ }
+ }
+
+ const int bond = FindBond_for_Stream(
+ true, // forInputStream
+ inStreamIndex);
+ if (bond < 0)
+ return E_INVALIDARG;
+
+ RINOK(GetInStream2(inStreams, /* inSizes, */
+ _bi.Bonds[(unsigned)bond].Get_OutIndex(EncodeMode), &seqInStream))
+
+ while (_binderStreams.Size() <= (unsigned)bond)
+ _binderStreams.AddNew();
+ CStBinderStream &bs = _binderStreams[(unsigned)bond];
+
+ if (bs.StreamRef || bs.InStreamSpec)
+ return E_NOTIMPL;
+
+ CSequentialInStreamCalcSize *spec = new CSequentialInStreamCalcSize;
+ bs.StreamRef = spec;
+ bs.InStreamSpec = spec;
+
+ spec->SetStream(seqInStream);
+ spec->Init();
+
+ seqInStream = bs.InStreamSpec;
+
+ *inStreamRes = seqInStream.Detach();
+ return S_OK;
+}
+
+
+HRESULT CMixerST::GetOutStream(
+ ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */
+ UInt32 outStreamIndex, ISequentialOutStream **outStreamRes)
+{
+ CMyComPtr<ISequentialOutStream> seqOutStream;
+
+ {
+ int index = -1;
+ if (!EncodeMode)
+ {
+ if (_bi.UnpackCoder == outStreamIndex)
+ index = 0;
+ }
+ else
+ index = _bi.FindStream_in_PackStreams(outStreamIndex);
+
+ if (index >= 0)
+ {
+ seqOutStream = outStreams[(unsigned)index];
+ *outStreamRes = seqOutStream.Detach();
+ return S_OK;
+ }
+ }
+
+ const int bond = FindBond_for_Stream(
+ false, // forInputStream
+ outStreamIndex);
+ if (bond < 0)
+ return E_INVALIDARG;
+
+ const UInt32 inStreamIndex = _bi.Bonds[(unsigned)bond].Get_InIndex(EncodeMode);
+
+ UInt32 coderIndex = inStreamIndex;
+ UInt32 coderStreamIndex = 0;
+
+ if (!EncodeMode)
+ _bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex);
+
+ CCoder &coder = _coders[coderIndex];
+
+ /*
+ if (!coder.Coder)
+ return E_NOTIMPL;
+ */
+
+ coder.QueryInterface(IID_ISequentialOutStream, (void **)&seqOutStream);
+ if (!seqOutStream)
+ return E_NOTIMPL;
+
+ const UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1;
+ const UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex;
+
+ bool isSet = false;
+
+ if (numOutStreams == 1)
+ {
+ CMyComPtr<ICompressSetOutStream> setOutStream;
+ coder.Coder.QueryInterface(IID_ICompressSetOutStream, &setOutStream);
+ if (setOutStream)
+ {
+ CMyComPtr<ISequentialOutStream> seqOutStream2;
+ RINOK(GetOutStream(outStreams, /* outSizes, */ startIndex + 0, &seqOutStream2))
+ RINOK(setOutStream->SetOutStream(seqOutStream2))
+ isSet = true;
+ }
+ }
+
+ if (!isSet && numOutStreams != 0)
+ {
+ return E_NOTIMPL;
+ /*
+ CMyComPtr<ICompressSetOutStream2> setStream2;
+ coder.QueryInterface(IID_ICompressSetOutStream2, (void **)&setStream2);
+ if (!setStream2)
+ return E_NOTIMPL;
+ for (UInt32 i = 0; i < numOutStreams; i++)
+ {
+ CMyComPtr<ISequentialOutStream> seqOutStream2;
+ RINOK(GetOutStream(outStreams, startIndex + i, &seqOutStream2))
+ RINOK(setStream2->SetOutStream2(i, seqOutStream2))
+ }
+ */
+ }
+
+ while (_binderStreams.Size() <= (unsigned)bond)
+ _binderStreams.AddNew();
+ CStBinderStream &bs = _binderStreams[(unsigned)bond];
+
+ if (bs.StreamRef || bs.OutStreamSpec)
+ return E_NOTIMPL;
+
+ COutStreamCalcSize *spec = new COutStreamCalcSize;
+ bs.StreamRef = (ISequentialOutStream *)spec;
+ bs.OutStreamSpec = spec;
+
+ spec->SetStream(seqOutStream);
+ spec->Init();
+
+ seqOutStream = bs.OutStreamSpec;
+
+ *outStreamRes = seqOutStream.Detach();
+ return S_OK;
+}
+
+
+static HRESULT GetError(HRESULT res, HRESULT res2)
+{
+ if (res == res2)
+ return res;
+ if (res == S_OK)
+ return res2;
+ if (res == k_My_HRESULT_WritingWasCut)
+ {
+ if (res2 != S_OK)
+ return res2;
+ }
+ return res;
+}
+
+
+HRESULT CMixerST::FinishStream(UInt32 streamIndex)
+{
+ {
+ int index = -1;
+ if (!EncodeMode)
+ {
+ if (_bi.UnpackCoder == streamIndex)
+ index = 0;
+ }
+ else
+ index = _bi.FindStream_in_PackStreams(streamIndex);
+
+ if (index >= 0)
+ return S_OK;
+ }
+
+ const int bond = FindBond_for_Stream(
+ false, // forInputStream
+ streamIndex);
+ if (bond < 0)
+ return E_INVALIDARG;
+
+ const UInt32 inStreamIndex = _bi.Bonds[(unsigned)bond].Get_InIndex(EncodeMode);
+
+ UInt32 coderIndex = inStreamIndex;
+ UInt32 coderStreamIndex = 0;
+ if (!EncodeMode)
+ _bi.GetCoder_for_Stream(inStreamIndex, coderIndex, coderStreamIndex);
+
+ CCoder &coder = _coders[coderIndex];
+ CMyComPtr<IOutStreamFinish> finish;
+ coder.QueryInterface(IID_IOutStreamFinish, (void **)&finish);
+ HRESULT res = S_OK;
+ if (finish)
+ {
+ res = finish->OutStreamFinish();
+ }
+ return GetError(res, FinishCoder(coderIndex));
+}
+
+
+HRESULT CMixerST::FinishCoder(UInt32 coderIndex)
+{
+ CCoder &coder = _coders[coderIndex];
+
+ const UInt32 numOutStreams = EncodeMode ? coder.NumStreams : 1;
+ const UInt32 startIndex = EncodeMode ? _bi.Coder_to_Stream[coderIndex]: coderIndex;
+
+ HRESULT res = S_OK;
+ for (unsigned i = 0; i < numOutStreams; i++)
+ res = GetError(res, FinishStream(startIndex + i));
+ return res;
+}
+
+
+void CMixerST::SelectMainCoder(bool useFirst)
+{
+ unsigned ci = _bi.UnpackCoder;
+
+ int firstNonFilter = -1;
+ unsigned firstAllowed = ci;
+
+ for (;;)
+ {
+ const CCoderST &coder = _coders[ci];
+ // break;
+
+ if (ci != _bi.UnpackCoder)
+ if (EncodeMode ? !coder.CanWrite : !coder.CanRead)
+ {
+ firstAllowed = ci;
+ firstNonFilter = -2;
+ }
+
+ if (coder.NumStreams != 1)
+ break;
+
+ const UInt32 st = _bi.Coder_to_Stream[ci];
+ if (_bi.IsStream_in_PackStreams(st))
+ break;
+ const int bond = _bi.FindBond_for_PackStream(st);
+ if (bond < 0)
+ throw 20150213;
+
+ if (EncodeMode ? !coder.CanRead : !coder.CanWrite)
+ break;
+
+ if (firstNonFilter == -1 && !IsFilter_Vector[ci])
+ firstNonFilter = (int)ci;
+
+ ci = _bi.Bonds[(unsigned)bond].UnpackIndex;
+ }
+
+ if (useFirst)
+ ci = firstAllowed;
+ else if (firstNonFilter >= 0)
+ ci = (unsigned)firstNonFilter;
+
+ MainCoderIndex = ci;
+}
+
+
+HRESULT CMixerST::Code(
+ ISequentialInStream * const *inStreams,
+ ISequentialOutStream * const *outStreams,
+ ICompressProgressInfo *progress,
+ bool &dataAfterEnd_Error)
+{
+ // InternalPackSizeError = false;
+ dataAfterEnd_Error = false;
+
+ _binderStreams.Clear();
+ const unsigned ci = MainCoderIndex;
+
+ const CCoder &mainCoder = _coders[MainCoderIndex];
+
+ CObjectVector< CMyComPtr<ISequentialInStream> > seqInStreams;
+ CObjectVector< CMyComPtr<ISequentialOutStream> > seqOutStreams;
+
+ const UInt32 numInStreams = EncodeMode ? 1 : mainCoder.NumStreams;
+ const UInt32 numOutStreams = !EncodeMode ? 1 : mainCoder.NumStreams;
+
+ const UInt32 startInIndex = EncodeMode ? ci : _bi.Coder_to_Stream[ci];
+ const UInt32 startOutIndex = !EncodeMode ? ci : _bi.Coder_to_Stream[ci];
+
+ UInt32 i;
+
+ for (i = 0; i < numInStreams; i++)
+ {
+ CMyComPtr<ISequentialInStream> seqInStream;
+ RINOK(GetInStream(inStreams, /* inSizes, */ startInIndex + i, &seqInStream))
+ seqInStreams.Add(seqInStream);
+ }
+
+ for (i = 0; i < 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 < numInStreams; i++)
+ seqInStreamsSpec.Add(seqInStreams[i]);
+ for (i = 0; i < numOutStreams; i++)
+ seqOutStreamsSpec.Add(seqOutStreams[i]);
+
+ for (i = 0; i < _coders.Size(); i++)
+ {
+ if (i == ci)
+ continue;
+
+ CCoder &coder = _coders[i];
+
+ if (EncodeMode)
+ {
+ CMyComPtr<ICompressInitEncoder> initEncoder;
+ coder.QueryInterface(IID_ICompressInitEncoder, (void **)&initEncoder);
+ if (initEncoder)
+ {
+ RINOK(initEncoder->InitEncoder())
+ }
+ }
+ else
+ {
+ CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize;
+ coder.QueryInterface(IID_ICompressSetOutStreamSize, (void **)&setOutStreamSize);
+ if (setOutStreamSize)
+ {
+ RINOK(setOutStreamSize->SetOutStreamSize(
+ EncodeMode ? coder.PackSizePointers[0] : coder.UnpackSizePointer))
+ }
+ }
+ }
+
+ const UInt64 * const *isSizes2 = EncodeMode ? &mainCoder.UnpackSizePointer : &mainCoder.PackSizePointers.Front();
+ const UInt64 * const *outSizes2 = EncodeMode ? &mainCoder.PackSizePointers.Front() : &mainCoder.UnpackSizePointer;
+
+ HRESULT res;
+ if (mainCoder.Coder)
+ {
+ res = mainCoder.Coder->Code(
+ seqInStreamsSpec[0], seqOutStreamsSpec[0],
+ isSizes2[0], outSizes2[0],
+ progress);
+ }
+ else
+ {
+ res = mainCoder.Coder2->Code(
+ &seqInStreamsSpec.Front(), isSizes2, numInStreams,
+ &seqOutStreamsSpec.Front(), outSizes2, numOutStreams,
+ progress);
+ }
+
+ if (res == k_My_HRESULT_WritingWasCut)
+ res = S_OK;
+
+ if (res == S_OK || res == S_FALSE)
+ {
+ res = GetError(res, FinishCoder(ci));
+ }
+
+ for (i = 0; i < _binderStreams.Size(); i++)
+ {
+ const CStBinderStream &bs = _binderStreams[i];
+ if (bs.InStreamSpec)
+ bs.InStreamSpec->ReleaseStream();
+ else
+ bs.OutStreamSpec->ReleaseStream();
+ }
+
+ if (res == k_My_HRESULT_WritingWasCut)
+ res = S_OK;
+
+ if (res != S_OK)
+ return res;
+
+ for (i = 0; i < _coders.Size(); i++)
+ {
+ RINOK(_coders[i].CheckDataAfterEnd(dataAfterEnd_Error /*, InternalPackSizeError */))
+ }
+
+ return S_OK;
+}
+
+
+HRESULT CMixerST::GetMainUnpackStream(
+ ISequentialInStream * const *inStreams,
+ ISequentialInStream **inStreamRes)
+{
+ CMyComPtr<ISequentialInStream> seqInStream;
+
+ RINOK(GetInStream2(inStreams, /* inSizes, */
+ _bi.UnpackCoder, &seqInStream))
+
+ FOR_VECTOR (i, _coders)
+ {
+ CCoder &coder = _coders[i];
+ CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize;
+ coder.QueryInterface(IID_ICompressSetOutStreamSize, (void **)&setOutStreamSize);
+ if (setOutStreamSize)
+ {
+ RINOK(setOutStreamSize->SetOutStreamSize(coder.UnpackSizePointer))
+ }
+ }
+
+ *inStreamRes = seqInStream.Detach();
+ return S_OK;
+}
+
+
+UInt64 CMixerST::GetBondStreamSize(unsigned bondIndex) const
+{
+ const CStBinderStream &bs = _binderStreams[bondIndex];
+ if (bs.InStreamSpec)
+ return bs.InStreamSpec->GetSize();
+ return bs.OutStreamSpec->GetSize();
+}
+
+#endif
+
+
+
+
+
+
+#ifdef USE_MIXER_MT
+
+
+void CCoderMT::Execute()
+{
+ try
+ {
+ Code(NULL);
+ }
+ catch(...)
+ {
+ Result = E_FAIL;
+ }
+}
+
+void CCoderMT::Code(ICompressProgressInfo *progress)
+{
+ unsigned numInStreams = EncodeMode ? 1 : NumStreams;
+ unsigned numOutStreams = EncodeMode ? NumStreams : 1;
+
+ InStreamPointers.ClearAndReserve(numInStreams);
+ OutStreamPointers.ClearAndReserve(numOutStreams);
+
+ unsigned i;
+
+ for (i = 0; i < numInStreams; i++)
+ InStreamPointers.AddInReserved((ISequentialInStream *)InStreams[i]);
+
+ for (i = 0; i < numOutStreams; i++)
+ OutStreamPointers.AddInReserved((ISequentialOutStream *)OutStreams[i]);
+
+ // we suppose that UnpackSizePointer and PackSizePointers contain correct pointers.
+ /*
+ if (UnpackSizePointer)
+ UnpackSizePointer = &UnpackSize;
+ for (i = 0; i < NumStreams; i++)
+ if (PackSizePointers[i])
+ PackSizePointers[i] = &PackSizes[i];
+ */
+
+ CReleaser releaser(*this);
+
+ if (Coder)
+ Result = Coder->Code(InStreamPointers[0], OutStreamPointers[0],
+ EncodeMode ? UnpackSizePointer : PackSizePointers[0],
+ EncodeMode ? PackSizePointers[0] : UnpackSizePointer,
+ progress);
+ else
+ Result = Coder2->Code(
+ &InStreamPointers.Front(), EncodeMode ? &UnpackSizePointer : &PackSizePointers.Front(), numInStreams,
+ &OutStreamPointers.Front(), EncodeMode ? &PackSizePointers.Front(): &UnpackSizePointer, numOutStreams,
+ progress);
+}
+
+HRESULT CMixerMT::SetBindInfo(const CBindInfo &bindInfo)
+{
+ CMixer::SetBindInfo(bindInfo);
+
+ _streamBinders.Clear();
+ FOR_VECTOR (i, _bi.Bonds)
+ {
+ // RINOK(_streamBinders.AddNew().CreateEvents())
+ _streamBinders.AddNew();
+ }
+ return S_OK;
+}
+
+void CMixerMT::AddCoder(const CCreatedCoder &cod)
+{
+ IsFilter_Vector.Add(cod.IsFilter);
+ IsExternal_Vector.Add(cod.IsExternal);
+ // const CCoderStreamsInfo &c = _bi.Coders[_coders.Size()];
+ CCoderMT &c2 = _coders.AddNew();
+ c2.NumStreams = cod.NumStreams;
+ c2.Coder = cod.Coder;
+ c2.Coder2 = cod.Coder2;
+ c2.EncodeMode = EncodeMode;
+}
+
+CCoder &CMixerMT::GetCoder(unsigned index)
+{
+ return _coders[index];
+}
+
+HRESULT CMixerMT::ReInit2()
+{
+ FOR_VECTOR (i, _streamBinders)
+ {
+ RINOK(_streamBinders[i].Create_ReInit())
+ }
+ return S_OK;
+}
+
+void CMixerMT::SelectMainCoder(bool useFirst)
+{
+ unsigned ci = _bi.UnpackCoder;
+
+ if (!useFirst)
+ for (;;)
+ {
+ if (_coders[ci].NumStreams != 1)
+ break;
+ if (!IsFilter_Vector[ci])
+ break;
+
+ UInt32 st = _bi.Coder_to_Stream[ci];
+ if (_bi.IsStream_in_PackStreams(st))
+ break;
+ const int bond = _bi.FindBond_for_PackStream(st);
+ if (bond < 0)
+ throw 20150213;
+ ci = _bi.Bonds[(unsigned)bond].UnpackIndex;
+ }
+
+ MainCoderIndex = ci;
+}
+
+HRESULT CMixerMT::Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams)
+{
+ unsigned i;
+
+ for (i = 0; i < _coders.Size(); i++)
+ {
+ CCoderMT &coderInfo = _coders[i];
+ const CCoderStreamsInfo &csi = _bi.Coders[i];
+
+ UInt32 j;
+
+ const unsigned numInStreams = EncodeMode ? 1 : csi.NumStreams;
+ const unsigned numOutStreams = EncodeMode ? csi.NumStreams : 1;
+
+ coderInfo.InStreams.Clear();
+ for (j = 0; j < numInStreams; j++)
+ coderInfo.InStreams.AddNew();
+
+ coderInfo.OutStreams.Clear();
+ for (j = 0; j < numOutStreams; j++)
+ coderInfo.OutStreams.AddNew();
+ }
+
+ for (i = 0; i < _bi.Bonds.Size(); i++)
+ {
+ const CBond &bond = _bi.Bonds[i];
+
+ UInt32 inCoderIndex, inCoderStreamIndex;
+ UInt32 outCoderIndex, outCoderStreamIndex;
+
+ {
+ UInt32 coderIndex, coderStreamIndex;
+ _bi.GetCoder_for_Stream(bond.PackIndex, coderIndex, coderStreamIndex);
+
+ inCoderIndex = EncodeMode ? bond.UnpackIndex : coderIndex;
+ outCoderIndex = EncodeMode ? coderIndex : bond.UnpackIndex;
+
+ inCoderStreamIndex = EncodeMode ? 0 : coderStreamIndex;
+ outCoderStreamIndex = EncodeMode ? coderStreamIndex : 0;
+ }
+
+ _streamBinders[i].CreateStreams2(
+ _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);
+ }
+ }
+
+ {
+ CCoderMT &cod = _coders[_bi.UnpackCoder];
+ if (EncodeMode)
+ cod.InStreams[0] = inStreams[0];
+ else
+ cod.OutStreams[0] = outStreams[0];
+ }
+
+ for (i = 0; i < _bi.PackStreams.Size(); i++)
+ {
+ UInt32 coderIndex, coderStreamIndex;
+ _bi.GetCoder_for_Stream(_bi.PackStreams[i], coderIndex, coderStreamIndex);
+ CCoderMT &cod = _coders[coderIndex];
+ if (EncodeMode)
+ cod.OutStreams[coderStreamIndex] = outStreams[i];
+ else
+ cod.InStreams[coderStreamIndex] = inStreams[i];
+ }
+
+ return S_OK;
+}
+
+HRESULT CMixerMT::ReturnIfError(HRESULT code)
+{
+ FOR_VECTOR (i, _coders)
+ if (_coders[i].Result == code)
+ return code;
+ return S_OK;
+}
+
+HRESULT CMixerMT::Code(
+ ISequentialInStream * const *inStreams,
+ ISequentialOutStream * const *outStreams,
+ ICompressProgressInfo *progress,
+ bool &dataAfterEnd_Error)
+{
+ // InternalPackSizeError = false;
+ dataAfterEnd_Error = false;
+
+ Init(inStreams, outStreams);
+
+ unsigned i;
+ for (i = 0; i < _coders.Size(); i++)
+ if (i != MainCoderIndex)
+ {
+ const WRes wres = _coders[i].Create();
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ }
+
+ for (i = 0; i < _coders.Size(); i++)
+ if (i != MainCoderIndex)
+ {
+ const WRes wres = _coders[i].Start();
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ }
+
+ _coders[MainCoderIndex].Code(progress);
+
+ WRes wres = 0;
+ for (i = 0; i < _coders.Size(); i++)
+ if (i != MainCoderIndex)
+ {
+ WRes wres2 = _coders[i].WaitExecuteFinish();
+ if (wres == 0)
+ wres = wres2;
+ }
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+
+ 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 != k_My_HRESULT_WritingWasCut
+ && result != S_FALSE
+ && result != E_FAIL)
+ return result;
+ }
+
+ RINOK(ReturnIfError(S_FALSE))
+
+ for (i = 0; i < _coders.Size(); i++)
+ {
+ HRESULT result = _coders[i].Result;
+ if (result != S_OK && result != k_My_HRESULT_WritingWasCut)
+ return result;
+ }
+
+ for (i = 0; i < _coders.Size(); i++)
+ {
+ RINOK(_coders[i].CheckDataAfterEnd(dataAfterEnd_Error /* , InternalPackSizeError */))
+ }
+
+ return S_OK;
+}
+
+UInt64 CMixerMT::GetBondStreamSize(unsigned bondIndex) const
+{
+ return _streamBinders[bondIndex].ProcessedSize;
+}
+
+#endif
+
+}
diff --git a/CPP/7zip/Archive/Common/CoderMixer2.h b/CPP/7zip/Archive/Common/CoderMixer2.h
index 4bd6418..484a608 100644
--- a/CPP/7zip/Archive/Common/CoderMixer2.h
+++ b/CPP/7zip/Archive/Common/CoderMixer2.h
@@ -1,447 +1,447 @@
-// CoderMixer2.h
-
-#ifndef __CODER_MIXER2_H
-#define __CODER_MIXER2_H
-
-#include "../../../Common/MyCom.h"
-#include "../../../Common/MyVector.h"
-
-#include "../../ICoder.h"
-
-#include "../../Common/CreateCoder.h"
-
-#ifdef _7ZIP_ST
- #define USE_MIXER_ST
-#else
- #define USE_MIXER_MT
- #ifndef _SFX
- #define USE_MIXER_ST
- #endif
-#endif
-
-#ifdef USE_MIXER_MT
-#include "../../Common/StreamBinder.h"
-#include "../../Common/VirtThread.h"
-#endif
-
-
-
-#ifdef USE_MIXER_ST
-
-class CSequentialInStreamCalcSize:
- public ISequentialInStream,
- public CMyUnknownImp
-{
-public:
- MY_UNKNOWN_IMP1(ISequentialInStream)
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
-private:
- CMyComPtr<ISequentialInStream> _stream;
- UInt64 _size;
- bool _wasFinished;
-public:
- void SetStream(ISequentialInStream *stream) { _stream = stream; }
- void Init()
- {
- _size = 0;
- _wasFinished = false;
- }
- void ReleaseStream() { _stream.Release(); }
- UInt64 GetSize() const { return _size; }
- bool WasFinished() const { return _wasFinished; }
-};
-
-
-class COutStreamCalcSize:
- public ISequentialOutStream,
- public IOutStreamFinish,
- public CMyUnknownImp
-{
- CMyComPtr<ISequentialOutStream> _stream;
- UInt64 _size;
-public:
- MY_UNKNOWN_IMP2(ISequentialOutStream, IOutStreamFinish)
-
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(OutStreamFinish)();
-
- void SetStream(ISequentialOutStream *stream) { _stream = stream; }
- void ReleaseStream() { _stream.Release(); }
- void Init() { _size = 0; }
- UInt64 GetSize() const { return _size; }
-};
-
-#endif
-
-
-
-namespace NCoderMixer2 {
-
-struct CBond
-{
- UInt32 PackIndex;
- UInt32 UnpackIndex;
-
- UInt32 Get_InIndex(bool encodeMode) const { return encodeMode ? UnpackIndex : PackIndex; }
- UInt32 Get_OutIndex(bool encodeMode) const { return encodeMode ? PackIndex : UnpackIndex; }
-};
-
-
-struct CCoderStreamsInfo
-{
- UInt32 NumStreams;
-};
-
-
-struct CBindInfo
-{
- CRecordVector<CCoderStreamsInfo> Coders;
- CRecordVector<CBond> Bonds;
- CRecordVector<UInt32> PackStreams;
- unsigned UnpackCoder;
-
- unsigned GetNum_Bonds_and_PackStreams() const { return Bonds.Size() + PackStreams.Size(); }
-
- int FindBond_for_PackStream(UInt32 packStream) const
- {
- FOR_VECTOR (i, Bonds)
- if (Bonds[i].PackIndex == packStream)
- return i;
- return -1;
- }
-
- int FindBond_for_UnpackStream(UInt32 unpackStream) const
- {
- FOR_VECTOR (i, Bonds)
- if (Bonds[i].UnpackIndex == unpackStream)
- return i;
- return -1;
- }
-
- bool SetUnpackCoder()
- {
- bool isOk = false;
- FOR_VECTOR(i, Coders)
- {
- if (FindBond_for_UnpackStream(i) < 0)
- {
- if (isOk)
- return false;
- UnpackCoder = i;
- isOk = true;
- }
- }
- return isOk;
- }
-
- bool IsStream_in_PackStreams(UInt32 streamIndex) const
- {
- return FindStream_in_PackStreams(streamIndex) >= 0;
- }
-
- int FindStream_in_PackStreams(UInt32 streamIndex) const
- {
- FOR_VECTOR(i, PackStreams)
- if (PackStreams[i] == streamIndex)
- return i;
- return -1;
- }
-
-
- // that function is used before Maps is calculated
-
- UInt32 GetStream_for_Coder(UInt32 coderIndex) const
- {
- UInt32 streamIndex = 0;
- for (UInt32 i = 0; i < coderIndex; i++)
- streamIndex += Coders[i].NumStreams;
- return streamIndex;
- }
-
- // ---------- Maps Section ----------
-
- CRecordVector<UInt32> Coder_to_Stream;
- CRecordVector<UInt32> Stream_to_Coder;
-
- void ClearMaps();
- bool CalcMapsAndCheck();
-
- // ---------- End of Maps Section ----------
-
- void Clear()
- {
- Coders.Clear();
- Bonds.Clear();
- PackStreams.Clear();
-
- ClearMaps();
- }
-
- void GetCoder_for_Stream(UInt32 streamIndex, UInt32 &coderIndex, UInt32 &coderStreamIndex) const
- {
- coderIndex = Stream_to_Coder[streamIndex];
- coderStreamIndex = streamIndex - Coder_to_Stream[coderIndex];
- }
-};
-
-
-
-class CCoder
-{
- CLASS_NO_COPY(CCoder);
-public:
- CMyComPtr<ICompressCoder> Coder;
- CMyComPtr<ICompressCoder2> Coder2;
- UInt32 NumStreams;
-
- UInt64 UnpackSize;
- const UInt64 *UnpackSizePointer;
-
- CRecordVector<UInt64> PackSizes;
- CRecordVector<const UInt64 *> PackSizePointers;
-
- bool Finish;
-
- CCoder(): Finish(false) {}
-
- void SetCoderInfo(const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish);
-
- HRESULT CheckDataAfterEnd(bool &dataAfterEnd_Error /* , bool &InternalPackSizeError */) const;
-
- IUnknown *GetUnknown() const
- {
- return Coder ? (IUnknown *)Coder : (IUnknown *)Coder2;
- }
-
- HRESULT QueryInterface(REFGUID iid, void** pp) const
- {
- return GetUnknown()->QueryInterface(iid, pp);
- }
-};
-
-
-
-class CMixer
-{
- bool Is_PackSize_Correct_for_Stream(UInt32 streamIndex);
-
-protected:
- CBindInfo _bi;
-
- int FindBond_for_Stream(bool forInputStream, UInt32 streamIndex) const
- {
- if (EncodeMode == forInputStream)
- return _bi.FindBond_for_UnpackStream(streamIndex);
- else
- return _bi.FindBond_for_PackStream(streamIndex);
- }
-
- CBoolVector IsFilter_Vector;
- CBoolVector IsExternal_Vector;
- bool EncodeMode;
-public:
- unsigned MainCoderIndex;
-
- // bool InternalPackSizeError;
-
- CMixer(bool encodeMode):
- EncodeMode(encodeMode),
- MainCoderIndex(0)
- // , InternalPackSizeError(false)
- {}
-
- /*
- Sequence of calling:
-
- SetBindInfo();
- for each coder
- AddCoder();
- SelectMainCoder();
-
- for each file
- {
- ReInit()
- for each coder
- SetCoderInfo();
- Code();
- }
- */
-
- virtual HRESULT SetBindInfo(const CBindInfo &bindInfo)
- {
- _bi = bindInfo;
- IsFilter_Vector.Clear();
- MainCoderIndex = 0;
- return S_OK;
- }
-
- virtual void AddCoder(const CCreatedCoder &cod) = 0;
- virtual CCoder &GetCoder(unsigned index) = 0;
- virtual void SelectMainCoder(bool useFirst) = 0;
- virtual void ReInit() = 0;
- virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) = 0;
- virtual HRESULT Code(
- ISequentialInStream * const *inStreams,
- ISequentialOutStream * const *outStreams,
- ICompressProgressInfo *progress,
- bool &dataAfterEnd_Error) = 0;
- virtual UInt64 GetBondStreamSize(unsigned bondIndex) const = 0;
-
- bool Is_UnpackSize_Correct_for_Coder(UInt32 coderIndex);
- bool Is_PackSize_Correct_for_Coder(UInt32 coderIndex);
- bool IsThere_ExternalCoder_in_PackTree(UInt32 coderIndex);
-};
-
-
-
-
-#ifdef USE_MIXER_ST
-
-struct CCoderST: public CCoder
-{
- bool CanRead;
- bool CanWrite;
-
- CCoderST(): CanRead(false), CanWrite(false) {}
-};
-
-
-struct CStBinderStream
-{
- CSequentialInStreamCalcSize *InStreamSpec;
- COutStreamCalcSize *OutStreamSpec;
- CMyComPtr<IUnknown> StreamRef;
-
- CStBinderStream(): InStreamSpec(NULL), OutStreamSpec(NULL) {}
-};
-
-
-class CMixerST:
- public IUnknown,
- public CMixer,
- public CMyUnknownImp
-{
- HRESULT GetInStream2(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */
- UInt32 outStreamIndex, ISequentialInStream **inStreamRes);
- HRESULT GetInStream(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */
- UInt32 inStreamIndex, ISequentialInStream **inStreamRes);
- HRESULT GetOutStream(ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */
- UInt32 outStreamIndex, ISequentialOutStream **outStreamRes);
-
- HRESULT FinishStream(UInt32 streamIndex);
- HRESULT FinishCoder(UInt32 coderIndex);
-
-public:
- CObjectVector<CCoderST> _coders;
-
- CObjectVector<CStBinderStream> _binderStreams;
-
- MY_UNKNOWN_IMP
-
- CMixerST(bool encodeMode);
- ~CMixerST();
-
- virtual void AddCoder(const CCreatedCoder &cod);
- virtual CCoder &GetCoder(unsigned index);
- virtual void SelectMainCoder(bool useFirst);
- virtual void ReInit();
- virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish)
- { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes, finish); }
- virtual HRESULT Code(
- ISequentialInStream * const *inStreams,
- ISequentialOutStream * const *outStreams,
- ICompressProgressInfo *progress,
- bool &dataAfterEnd_Error);
- virtual UInt64 GetBondStreamSize(unsigned bondIndex) const;
-
- HRESULT GetMainUnpackStream(
- ISequentialInStream * const *inStreams,
- ISequentialInStream **inStreamRes);
-};
-
-#endif
-
-
-
-
-#ifdef USE_MIXER_MT
-
-class CCoderMT: public CCoder, public CVirtThread
-{
- CLASS_NO_COPY(CCoderMT)
- CRecordVector<ISequentialInStream*> InStreamPointers;
- CRecordVector<ISequentialOutStream*> OutStreamPointers;
-
-private:
- void Execute();
-public:
- bool EncodeMode;
- HRESULT Result;
- CObjectVector< CMyComPtr<ISequentialInStream> > InStreams;
- CObjectVector< CMyComPtr<ISequentialOutStream> > OutStreams;
-
- void Release()
- {
- InStreamPointers.Clear();
- OutStreamPointers.Clear();
- unsigned i;
- for (i = 0; i < InStreams.Size(); i++)
- InStreams[i].Release();
- for (i = 0; i < OutStreams.Size(); i++)
- OutStreams[i].Release();
- }
-
- class CReleaser
- {
- CLASS_NO_COPY(CReleaser)
- CCoderMT &_c;
- public:
- CReleaser(CCoderMT &c): _c(c) {}
- ~CReleaser() { _c.Release(); }
- };
-
- CCoderMT(): EncodeMode(false) {}
- ~CCoderMT() { CVirtThread::WaitThreadFinish(); }
-
- void Code(ICompressProgressInfo *progress);
-};
-
-
-class CMixerMT:
- public IUnknown,
- public CMixer,
- public CMyUnknownImp
-{
- CObjectVector<CStreamBinder> _streamBinders;
-
- HRESULT Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams);
- HRESULT ReturnIfError(HRESULT code);
-
-public:
- CObjectVector<CCoderMT> _coders;
-
- MY_UNKNOWN_IMP
-
- virtual HRESULT SetBindInfo(const CBindInfo &bindInfo);
- virtual void AddCoder(const CCreatedCoder &cod);
- virtual CCoder &GetCoder(unsigned index);
- virtual void SelectMainCoder(bool useFirst);
- virtual void ReInit();
- virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish)
- { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes, finish); }
- virtual HRESULT Code(
- ISequentialInStream * const *inStreams,
- ISequentialOutStream * const *outStreams,
- ICompressProgressInfo *progress,
- bool &dataAfterEnd_Error);
- virtual UInt64 GetBondStreamSize(unsigned bondIndex) const;
-
- CMixerMT(bool encodeMode): CMixer(encodeMode) {}
-};
-
-#endif
-
-}
-
-#endif
+// CoderMixer2.h
+
+#ifndef ZIP7_INC_CODER_MIXER2_H
+#define ZIP7_INC_CODER_MIXER2_H
+
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyVector.h"
+
+#include "../../ICoder.h"
+
+#include "../../Common/CreateCoder.h"
+
+#ifdef Z7_ST
+ #define USE_MIXER_ST
+#else
+ #define USE_MIXER_MT
+ #ifndef Z7_SFX
+ #define USE_MIXER_ST
+ #endif
+#endif
+
+#ifdef USE_MIXER_MT
+#include "../../Common/StreamBinder.h"
+#include "../../Common/VirtThread.h"
+#endif
+
+
+
+#ifdef USE_MIXER_ST
+
+Z7_CLASS_IMP_COM_1(
+ CSequentialInStreamCalcSize
+ , ISequentialInStream
+)
+ bool _wasFinished;
+ CMyComPtr<ISequentialInStream> _stream;
+ UInt64 _size;
+public:
+ void SetStream(ISequentialInStream *stream) { _stream = stream; }
+ void Init()
+ {
+ _size = 0;
+ _wasFinished = false;
+ }
+ void ReleaseStream() { _stream.Release(); }
+ UInt64 GetSize() const { return _size; }
+ bool WasFinished() const { return _wasFinished; }
+};
+
+
+Z7_CLASS_IMP_COM_2(
+ COutStreamCalcSize
+ , ISequentialOutStream
+ , IOutStreamFinish
+)
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+public:
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init() { _size = 0; }
+ UInt64 GetSize() const { return _size; }
+};
+
+#endif
+
+
+
+namespace NCoderMixer2 {
+
+struct CBond
+{
+ UInt32 PackIndex;
+ UInt32 UnpackIndex;
+
+ UInt32 Get_InIndex(bool encodeMode) const { return encodeMode ? UnpackIndex : PackIndex; }
+ UInt32 Get_OutIndex(bool encodeMode) const { return encodeMode ? PackIndex : UnpackIndex; }
+};
+
+
+struct CCoderStreamsInfo
+{
+ UInt32 NumStreams;
+};
+
+
+struct CBindInfo
+{
+ CRecordVector<CCoderStreamsInfo> Coders;
+ CRecordVector<CBond> Bonds;
+ CRecordVector<UInt32> PackStreams;
+ unsigned UnpackCoder;
+
+ unsigned GetNum_Bonds_and_PackStreams() const { return Bonds.Size() + PackStreams.Size(); }
+
+ int FindBond_for_PackStream(UInt32 packStream) const
+ {
+ FOR_VECTOR (i, Bonds)
+ if (Bonds[i].PackIndex == packStream)
+ return (int)i;
+ return -1;
+ }
+
+ int FindBond_for_UnpackStream(UInt32 unpackStream) const
+ {
+ FOR_VECTOR (i, Bonds)
+ if (Bonds[i].UnpackIndex == unpackStream)
+ return (int)i;
+ return -1;
+ }
+
+ bool SetUnpackCoder()
+ {
+ bool isOk = false;
+ FOR_VECTOR (i, Coders)
+ {
+ if (FindBond_for_UnpackStream(i) < 0)
+ {
+ if (isOk)
+ return false;
+ UnpackCoder = i;
+ isOk = true;
+ }
+ }
+ return isOk;
+ }
+
+ bool IsStream_in_PackStreams(UInt32 streamIndex) const
+ {
+ return FindStream_in_PackStreams(streamIndex) >= 0;
+ }
+
+ int FindStream_in_PackStreams(UInt32 streamIndex) const
+ {
+ FOR_VECTOR (i, PackStreams)
+ if (PackStreams[i] == streamIndex)
+ return (int)i;
+ return -1;
+ }
+
+
+ // that function is used before Maps is calculated
+
+ UInt32 GetStream_for_Coder(UInt32 coderIndex) const
+ {
+ UInt32 streamIndex = 0;
+ for (UInt32 i = 0; i < coderIndex; i++)
+ streamIndex += Coders[i].NumStreams;
+ return streamIndex;
+ }
+
+ // ---------- Maps Section ----------
+
+ CRecordVector<UInt32> Coder_to_Stream;
+ CRecordVector<UInt32> Stream_to_Coder;
+
+ void ClearMaps();
+ bool CalcMapsAndCheck();
+
+ // ---------- End of Maps Section ----------
+
+ void Clear()
+ {
+ Coders.Clear();
+ Bonds.Clear();
+ PackStreams.Clear();
+
+ ClearMaps();
+ }
+
+ void GetCoder_for_Stream(UInt32 streamIndex, UInt32 &coderIndex, UInt32 &coderStreamIndex) const
+ {
+ coderIndex = Stream_to_Coder[streamIndex];
+ coderStreamIndex = streamIndex - Coder_to_Stream[coderIndex];
+ }
+};
+
+
+
+class CCoder
+{
+ Z7_CLASS_NO_COPY(CCoder)
+public:
+ CMyComPtr<ICompressCoder> Coder;
+ CMyComPtr<ICompressCoder2> Coder2;
+ UInt32 NumStreams;
+ bool Finish;
+
+ UInt64 UnpackSize;
+ const UInt64 *UnpackSizePointer;
+
+ CRecordVector<UInt64> PackSizes;
+ CRecordVector<const UInt64 *> PackSizePointers;
+
+ CCoder(): Finish(false) {}
+
+ void SetCoderInfo(const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish);
+
+ HRESULT CheckDataAfterEnd(bool &dataAfterEnd_Error /* , bool &InternalPackSizeError */) const;
+
+ IUnknown *GetUnknown() const
+ {
+ return Coder ? (IUnknown *)Coder : (IUnknown *)Coder2;
+ }
+
+ HRESULT QueryInterface(REFGUID iid, void** pp) const
+ {
+ return GetUnknown()->QueryInterface(iid, pp);
+ }
+};
+
+
+
+class CMixer
+{
+ bool Is_PackSize_Correct_for_Stream(UInt32 streamIndex);
+
+protected:
+ CBindInfo _bi;
+
+ int FindBond_for_Stream(bool forInputStream, UInt32 streamIndex) const
+ {
+ if (EncodeMode == forInputStream)
+ return _bi.FindBond_for_UnpackStream(streamIndex);
+ else
+ return _bi.FindBond_for_PackStream(streamIndex);
+ }
+
+ CBoolVector IsFilter_Vector;
+ CBoolVector IsExternal_Vector;
+ bool EncodeMode;
+public:
+ unsigned MainCoderIndex;
+
+ // bool InternalPackSizeError;
+
+ CMixer(bool encodeMode):
+ EncodeMode(encodeMode),
+ MainCoderIndex(0)
+ // , InternalPackSizeError(false)
+ {}
+
+ virtual ~CMixer() {}
+ /*
+ Sequence of calling:
+
+ SetBindInfo();
+ for each coder
+ AddCoder();
+ SelectMainCoder();
+
+ for each file
+ {
+ ReInit()
+ for each coder
+ SetCoderInfo();
+ Code();
+ }
+ */
+
+ virtual HRESULT SetBindInfo(const CBindInfo &bindInfo)
+ {
+ _bi = bindInfo;
+ IsFilter_Vector.Clear();
+ MainCoderIndex = 0;
+ return S_OK;
+ }
+
+ virtual void AddCoder(const CCreatedCoder &cod) = 0;
+ virtual CCoder &GetCoder(unsigned index) = 0;
+ virtual void SelectMainCoder(bool useFirst) = 0;
+ virtual HRESULT ReInit2() = 0;
+ virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) = 0;
+ virtual HRESULT Code(
+ ISequentialInStream * const *inStreams,
+ ISequentialOutStream * const *outStreams,
+ ICompressProgressInfo *progress,
+ bool &dataAfterEnd_Error) = 0;
+ virtual UInt64 GetBondStreamSize(unsigned bondIndex) const = 0;
+
+ bool Is_UnpackSize_Correct_for_Coder(UInt32 coderIndex);
+ bool Is_PackSize_Correct_for_Coder(UInt32 coderIndex);
+ bool IsThere_ExternalCoder_in_PackTree(UInt32 coderIndex);
+};
+
+
+
+
+#ifdef USE_MIXER_ST
+
+struct CCoderST: public CCoder
+{
+ bool CanRead;
+ bool CanWrite;
+
+ CCoderST(): CanRead(false), CanWrite(false) {}
+};
+
+
+struct CStBinderStream
+{
+ CSequentialInStreamCalcSize *InStreamSpec;
+ COutStreamCalcSize *OutStreamSpec;
+ CMyComPtr<IUnknown> StreamRef;
+
+ CStBinderStream(): InStreamSpec(NULL), OutStreamSpec(NULL) {}
+};
+
+
+class CMixerST:
+ public IUnknown,
+ public CMixer,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_0
+ Z7_CLASS_NO_COPY(CMixerST)
+
+ HRESULT GetInStream2(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */
+ UInt32 outStreamIndex, ISequentialInStream **inStreamRes);
+ HRESULT GetInStream(ISequentialInStream * const *inStreams, /* const UInt64 * const *inSizes, */
+ UInt32 inStreamIndex, ISequentialInStream **inStreamRes);
+ HRESULT GetOutStream(ISequentialOutStream * const *outStreams, /* const UInt64 * const *outSizes, */
+ UInt32 outStreamIndex, ISequentialOutStream **outStreamRes);
+
+ HRESULT FinishStream(UInt32 streamIndex);
+ HRESULT FinishCoder(UInt32 coderIndex);
+
+public:
+ CObjectVector<CCoderST> _coders;
+
+ CObjectVector<CStBinderStream> _binderStreams;
+
+ CMixerST(bool encodeMode);
+ ~CMixerST() Z7_DESTRUCTOR_override;
+
+ virtual void AddCoder(const CCreatedCoder &cod) Z7_override;
+ virtual CCoder &GetCoder(unsigned index) Z7_override;
+ virtual void SelectMainCoder(bool useFirst) Z7_override;
+ virtual HRESULT ReInit2() Z7_override;
+ virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) Z7_override
+ { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes, finish); }
+ virtual HRESULT Code(
+ ISequentialInStream * const *inStreams,
+ ISequentialOutStream * const *outStreams,
+ ICompressProgressInfo *progress,
+ bool &dataAfterEnd_Error) Z7_override;
+ virtual UInt64 GetBondStreamSize(unsigned bondIndex) const Z7_override;
+
+ HRESULT GetMainUnpackStream(
+ ISequentialInStream * const *inStreams,
+ ISequentialInStream **inStreamRes);
+};
+
+#endif
+
+
+
+
+#ifdef USE_MIXER_MT
+
+class CCoderMT: public CCoder, public CVirtThread
+{
+ Z7_CLASS_NO_COPY(CCoderMT)
+ CRecordVector<ISequentialInStream*> InStreamPointers;
+ CRecordVector<ISequentialOutStream*> OutStreamPointers;
+
+private:
+ virtual void Execute() Z7_override;
+public:
+ bool EncodeMode;
+ HRESULT Result;
+ CObjectVector< CMyComPtr<ISequentialInStream> > InStreams;
+ CObjectVector< CMyComPtr<ISequentialOutStream> > OutStreams;
+
+ void Release()
+ {
+ InStreamPointers.Clear();
+ OutStreamPointers.Clear();
+ unsigned i;
+ for (i = 0; i < InStreams.Size(); i++)
+ InStreams[i].Release();
+ for (i = 0; i < OutStreams.Size(); i++)
+ OutStreams[i].Release();
+ }
+
+ class CReleaser
+ {
+ Z7_CLASS_NO_COPY(CReleaser)
+ CCoderMT &_c;
+ public:
+ CReleaser(CCoderMT &c): _c(c) {}
+ ~CReleaser() { _c.Release(); }
+ };
+
+ CCoderMT(): EncodeMode(false) {}
+ ~CCoderMT() Z7_DESTRUCTOR_override
+ {
+ /* WaitThreadFinish() will be called in ~CVirtThread().
+ But we need WaitThreadFinish() call before CCoder destructor,
+ and before destructors of this class members.
+ */
+ CVirtThread::WaitThreadFinish();
+ }
+
+ void Code(ICompressProgressInfo *progress);
+};
+
+
+class CMixerMT:
+ public IUnknown,
+ public CMixer,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_0
+ Z7_CLASS_NO_COPY(CMixerMT)
+
+ CObjectVector<CStreamBinder> _streamBinders;
+
+ HRESULT Init(ISequentialInStream * const *inStreams, ISequentialOutStream * const *outStreams);
+ HRESULT ReturnIfError(HRESULT code);
+
+ // virtual ~CMixerMT() {}
+public:
+ CObjectVector<CCoderMT> _coders;
+
+ virtual HRESULT SetBindInfo(const CBindInfo &bindInfo) Z7_override;
+ virtual void AddCoder(const CCreatedCoder &cod) Z7_override;
+ virtual CCoder &GetCoder(unsigned index) Z7_override;
+ virtual void SelectMainCoder(bool useFirst) Z7_override;
+ virtual HRESULT ReInit2() Z7_override;
+ virtual void SetCoderInfo(unsigned coderIndex, const UInt64 *unpackSize, const UInt64 * const *packSizes, bool finish) Z7_override
+ { _coders[coderIndex].SetCoderInfo(unpackSize, packSizes, finish); }
+ virtual HRESULT Code(
+ ISequentialInStream * const *inStreams,
+ ISequentialOutStream * const *outStreams,
+ ICompressProgressInfo *progress,
+ bool &dataAfterEnd_Error) Z7_override;
+ virtual UInt64 GetBondStreamSize(unsigned bondIndex) const Z7_override;
+
+ CMixerMT(bool encodeMode): CMixer(encodeMode) {}
+};
+
+#endif
+
+}
+
+#endif
diff --git a/CPP/7zip/Archive/Common/DummyOutStream.cpp b/CPP/7zip/Archive/Common/DummyOutStream.cpp
index c7d45e7..f48c32f 100644
--- a/CPP/7zip/Archive/Common/DummyOutStream.cpp
+++ b/CPP/7zip/Archive/Common/DummyOutStream.cpp
@@ -1,17 +1,17 @@
-// DummyOutStream.cpp
-
-#include "StdAfx.h"
-
-#include "DummyOutStream.h"
-
-STDMETHODIMP CDummyOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- UInt32 realProcessedSize = size;
- HRESULT res = S_OK;
- if (_stream)
- res = _stream->Write(data, size, &realProcessedSize);
- _size += realProcessedSize;
- if (processedSize)
- *processedSize = realProcessedSize;
- return res;
-}
+// DummyOutStream.cpp
+
+#include "StdAfx.h"
+
+#include "DummyOutStream.h"
+
+Z7_COM7F_IMF(CDummyOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ UInt32 realProcessedSize = size;
+ HRESULT res = S_OK;
+ if (_stream)
+ res = _stream->Write(data, size, &realProcessedSize);
+ _size += realProcessedSize;
+ if (processedSize)
+ *processedSize = realProcessedSize;
+ return res;
+}
diff --git a/CPP/7zip/Archive/Common/DummyOutStream.h b/CPP/7zip/Archive/Common/DummyOutStream.h
index 30e84c5..f884e13 100644
--- a/CPP/7zip/Archive/Common/DummyOutStream.h
+++ b/CPP/7zip/Archive/Common/DummyOutStream.h
@@ -1,25 +1,23 @@
-// DummyOutStream.h
-
-#ifndef __DUMMY_OUT_STREAM_H
-#define __DUMMY_OUT_STREAM_H
-
-#include "../../../Common/MyCom.h"
-
-#include "../../IStream.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
+// DummyOutStream.h
+
+#ifndef ZIP7_INC_DUMMY_OUT_STREAM_H
+#define ZIP7_INC_DUMMY_OUT_STREAM_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../IStream.h"
+
+Z7_CLASS_IMP_NOQIB_1(
+ CDummyOutStream
+ , ISequentialOutStream
+)
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+public:
+ void SetStream(ISequentialOutStream *outStream) { _stream = outStream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init() { _size = 0; }
+ UInt64 GetSize() const { return _size; }
+};
+
+#endif
diff --git a/CPP/7zip/Archive/Common/FindSignature.cpp b/CPP/7zip/Archive/Common/FindSignature.cpp
new file mode 100644
index 0000000..6c6740f
--- /dev/null
+++ b/CPP/7zip/Archive/Common/FindSignature.cpp
@@ -0,0 +1,62 @@
+// FindSignature.cpp
+
+#include "StdAfx.h"
+
+#include <string.h>
+
+#include "../../../Common/MyBuffer.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "FindSignature.h"
+
+HRESULT FindSignatureInStream(ISequentialInStream *stream,
+ const Byte *signature, unsigned signatureSize,
+ const UInt64 *limit, UInt64 &resPos)
+{
+ resPos = 0;
+ CByteBuffer byteBuffer2(signatureSize);
+ RINOK(ReadStream_FALSE(stream, byteBuffer2, signatureSize))
+
+ if (memcmp(byteBuffer2, signature, signatureSize) == 0)
+ return S_OK;
+
+ const UInt32 kBufferSize = (1 << 16);
+ CByteBuffer byteBuffer(kBufferSize);
+ Byte *buffer = byteBuffer;
+ UInt32 numPrevBytes = signatureSize - 1;
+ memcpy(buffer, (const Byte *)byteBuffer2 + 1, numPrevBytes);
+ resPos = 1;
+ for (;;)
+ {
+ if (limit)
+ if (resPos > *limit)
+ return S_FALSE;
+ do
+ {
+ const UInt32 numReadBytes = kBufferSize - numPrevBytes;
+ UInt32 processedSize;
+ RINOK(stream->Read(buffer + numPrevBytes, numReadBytes, &processedSize))
+ numPrevBytes += processedSize;
+ if (processedSize == 0)
+ return S_FALSE;
+ }
+ while (numPrevBytes < signatureSize);
+ const UInt32 numTests = numPrevBytes - signatureSize + 1;
+ for (UInt32 pos = 0; pos < numTests; pos++)
+ {
+ const Byte b = signature[0];
+ for (; buffer[pos] != b && pos < numTests; pos++);
+ if (pos == numTests)
+ break;
+ if (memcmp(buffer + pos, signature, signatureSize) == 0)
+ {
+ resPos += pos;
+ return S_OK;
+ }
+ }
+ resPos += numTests;
+ numPrevBytes -= numTests;
+ memmove(buffer, buffer + numTests, numPrevBytes);
+ }
+}
diff --git a/CPP/7zip/Archive/Common/FindSignature.h b/CPP/7zip/Archive/Common/FindSignature.h
new file mode 100644
index 0000000..f0e6cdd
--- /dev/null
+++ b/CPP/7zip/Archive/Common/FindSignature.h
@@ -0,0 +1,12 @@
+// FindSignature.h
+
+#ifndef ZIP7_INC_FIND_SIGNATURE_H
+#define ZIP7_INC_FIND_SIGNATURE_H
+
+#include "../../IStream.h"
+
+HRESULT FindSignatureInStream(ISequentialInStream *stream,
+ const Byte *signature, unsigned signatureSize,
+ const UInt64 *limit, UInt64 &resPos);
+
+#endif
diff --git a/CPP/7zip/Archive/Common/HandlerOut.cpp b/CPP/7zip/Archive/Common/HandlerOut.cpp
index 41762d9..17fed67 100644
--- a/CPP/7zip/Archive/Common/HandlerOut.cpp
+++ b/CPP/7zip/Archive/Common/HandlerOut.cpp
@@ -1,232 +1,311 @@
-// HandlerOut.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/StringToInt.h"
-
-#include "../Common/ParseProperties.h"
-
-#include "HandlerOut.h"
-
-namespace NArchive {
-
-bool ParseSizeString(const wchar_t *s, const PROPVARIANT &prop, UInt64 percentsBase, UInt64 &res)
-{
- if (*s == 0)
- {
- switch (prop.vt)
- {
- case VT_UI4: res = prop.ulVal; return true;
- case VT_UI8: res = prop.uhVal.QuadPart; return true;
- case VT_BSTR:
- s = prop.bstrVal;
- break;
- default: return false;
- }
- }
- else if (prop.vt != VT_EMPTY)
- return false;
-
- const wchar_t *end;
- UInt64 v = ConvertStringToUInt64(s, &end);
- if (s == end)
- return false;
- wchar_t c = *end;
- if (c == 0)
- {
- res = v;
- return true;
- }
- if (end[1] != 0)
- return false;
-
- if (c == '%')
- {
- res = percentsBase / 100 * v;
- return true;
- }
-
- unsigned numBits;
- switch (MyCharLower_Ascii(c))
- {
- case 'b': numBits = 0; break;
- case 'k': numBits = 10; break;
- case 'm': numBits = 20; break;
- case 'g': numBits = 30; break;
- case 't': numBits = 40; break;
- default: return false;
- }
- UInt64 val2 = v << numBits;
- if ((val2 >> numBits) != v)
- return false;
- res = val2;
- return true;
-}
-
-bool CCommonMethodProps::SetCommonProperty(const UString &name, const PROPVARIANT &value, HRESULT &hres)
-{
- hres = S_OK;
-
- if (name.IsPrefixedBy_Ascii_NoCase("mt"))
- {
- #ifndef _7ZIP_ST
- hres = ParseMtProp(name.Ptr(2), value, _numProcessors, _numThreads);
- #endif
- return true;
- }
-
- if (name.IsPrefixedBy_Ascii_NoCase("memuse"))
- {
- if (!ParseSizeString(name.Ptr(6), value, _memAvail, _memUsage))
- hres = E_INVALIDARG;
- return true;
- }
-
- return false;
-}
-
-
-#ifndef EXTRACT_ONLY
-
-static void SetMethodProp32(COneMethodInfo &m, PROPID propID, UInt32 value)
-{
- if (m.FindProp(propID) < 0)
- m.AddProp32(propID, value);
-}
-
-void CMultiMethodProps::SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const
-{
- UInt32 level = _level;
- if (level != (UInt32)(Int32)-1)
- SetMethodProp32(oneMethodInfo, NCoderPropID::kLevel, (UInt32)level);
-}
-
-#ifndef _7ZIP_ST
-void CMultiMethodProps::SetMethodThreadsTo(COneMethodInfo &oneMethodInfo, UInt32 numThreads)
-{
- SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
-}
-#endif
-
-void CMultiMethodProps::InitMulti()
-{
- _level = (UInt32)(Int32)-1;
- _analysisLevel = -1;
- _crcSize = 4;
- _autoFilter = true;
-}
-
-void CMultiMethodProps::Init()
-{
- InitCommon();
- InitMulti();
- _methods.Clear();
- _filterMethod.Clear();
-}
-
-
-HRESULT CMultiMethodProps::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
-{
- UString name = nameSpec;
- name.MakeLower_Ascii();
- if (name.IsEmpty())
- return E_INVALIDARG;
-
- if (name[0] == 'x')
- {
- name.Delete(0);
- _level = 9;
- return ParsePropToUInt32(name, value, _level);
- }
-
- if (name.IsPrefixedBy_Ascii_NoCase("yx"))
- {
- name.Delete(0, 2);
- UInt32 v = 9;
- RINOK(ParsePropToUInt32(name, value, v));
- _analysisLevel = (int)v;
- return S_OK;
- }
-
- if (name.IsPrefixedBy_Ascii_NoCase("crc"))
- {
- name.Delete(0, 3);
- _crcSize = 4;
- return ParsePropToUInt32(name, value, _crcSize);
- }
-
- {
- HRESULT hres;
- if (SetCommonProperty(name, value, hres))
- return hres;
- }
-
- UInt32 number;
- unsigned index = ParseStringToUInt32(name, number);
- UString realName = name.Ptr(index);
- if (index == 0)
- {
- if (name.IsEqualTo("f"))
- {
- HRESULT res = PROPVARIANT_to_bool(value, _autoFilter);
- if (res == S_OK)
- return res;
- if (value.vt != VT_BSTR)
- return E_INVALIDARG;
- return _filterMethod.ParseMethodFromPROPVARIANT(UString(), value);
- }
- number = 0;
- }
- if (number > 64)
- return E_FAIL;
- for (int j = _methods.Size(); j <= (int)number; j++)
- _methods.Add(COneMethodInfo());
- return _methods[number].ParseMethodFromPROPVARIANT(realName, value);
-}
-
-
-
-void CSingleMethodProps::Init()
-{
- InitCommon();
- InitSingle();
- Clear();
-}
-
-
-HRESULT CSingleMethodProps::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
-{
- Init();
-
- for (UInt32 i = 0; i < numProps; i++)
- {
- UString name = names[i];
- name.MakeLower_Ascii();
- if (name.IsEmpty())
- return E_INVALIDARG;
- const PROPVARIANT &value = values[i];
- if (name[0] == L'x')
- {
- UInt32 a = 9;
- RINOK(ParsePropToUInt32(name.Ptr(1), value, a));
- _level = a;
- AddProp_Level(a);
- continue;
- }
- {
- HRESULT hres;
- if (SetCommonProperty(name, value, hres))
- {
- RINOK(hres)
- continue;
- }
- }
- RINOK(ParseMethodFromPROPVARIANT(names[i], value));
- }
-
- return S_OK;
-}
-
-#endif
-
-}
+// HandlerOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/StringToInt.h"
+
+#include "../Common/ParseProperties.h"
+
+#include "HandlerOut.h"
+
+namespace NArchive {
+
+bool ParseSizeString(const wchar_t *s, const PROPVARIANT &prop, UInt64 percentsBase, UInt64 &res)
+{
+ if (*s == 0)
+ {
+ switch (prop.vt)
+ {
+ case VT_UI4: res = prop.ulVal; return true;
+ case VT_UI8: res = prop.uhVal.QuadPart; return true;
+ case VT_BSTR:
+ s = prop.bstrVal;
+ break;
+ default: return false;
+ }
+ }
+ else if (prop.vt != VT_EMPTY)
+ return false;
+
+ bool percentMode = false;
+ {
+ const wchar_t c = *s;
+ if (MyCharLower_Ascii(c) == 'p')
+ {
+ percentMode = true;
+ s++;
+ }
+ }
+
+ const wchar_t *end;
+ const UInt64 v = ConvertStringToUInt64(s, &end);
+ if (s == end)
+ return false;
+ const wchar_t c = *end;
+
+ if (percentMode)
+ {
+ if (c != 0)
+ return false;
+ res = Calc_From_Val_Percents(percentsBase, v);
+ return true;
+ }
+
+ if (c == 0)
+ {
+ res = v;
+ return true;
+ }
+ if (end[1] != 0)
+ return false;
+
+ if (c == '%')
+ {
+ res = Calc_From_Val_Percents(percentsBase, v);
+ return true;
+ }
+
+ unsigned numBits;
+ switch (MyCharLower_Ascii(c))
+ {
+ case 'b': numBits = 0; break;
+ case 'k': numBits = 10; break;
+ case 'm': numBits = 20; break;
+ case 'g': numBits = 30; break;
+ case 't': numBits = 40; break;
+ default: return false;
+ }
+ const UInt64 val2 = v << numBits;
+ if ((val2 >> numBits) != v)
+ return false;
+ res = val2;
+ return true;
+}
+
+bool CCommonMethodProps::SetCommonProperty(const UString &name, const PROPVARIANT &value, HRESULT &hres)
+{
+ hres = S_OK;
+
+ if (name.IsPrefixedBy_Ascii_NoCase("mt"))
+ {
+ #ifndef Z7_ST
+ _numThreads = _numProcessors;
+ _numThreads_WasForced = false;
+ hres = ParseMtProp2(name.Ptr(2), value, _numThreads, _numThreads_WasForced);
+ // "mt" means "_numThreads_WasForced = false" here
+ #endif
+ return true;
+ }
+
+ if (name.IsPrefixedBy_Ascii_NoCase("memuse"))
+ {
+ UInt64 v;
+ if (!ParseSizeString(name.Ptr(6), value, _memAvail, v))
+ hres = E_INVALIDARG;
+ _memUsage_Decompress = v;
+ _memUsage_Compress = v;
+ _memUsage_WasSet = true;
+ return true;
+ }
+
+ return false;
+}
+
+
+#ifndef Z7_EXTRACT_ONLY
+
+static void SetMethodProp32(CMethodProps &m, PROPID propID, UInt32 value)
+{
+ if (m.FindProp(propID) < 0)
+ m.AddProp32(propID, value);
+}
+
+void CMultiMethodProps::SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const
+{
+ UInt32 level = _level;
+ if (level != (UInt32)(Int32)-1)
+ SetMethodProp32(oneMethodInfo, NCoderPropID::kLevel, (UInt32)level);
+}
+
+#ifndef Z7_ST
+
+static void SetMethodProp32_Replace(CMethodProps &m, PROPID propID, UInt32 value)
+{
+ const int i = m.FindProp(propID);
+ if (i >= 0)
+ {
+ NWindows::NCOM::CPropVariant &val = m.Props[(unsigned)i].Value;
+ val = (UInt32)value;
+ return;
+ }
+ m.AddProp32(propID, value);
+}
+
+void CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(CMethodProps &oneMethodInfo, UInt32 numThreads)
+{
+ SetMethodProp32(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
+}
+
+void CMultiMethodProps::SetMethodThreadsTo_Replace(CMethodProps &oneMethodInfo, UInt32 numThreads)
+{
+ SetMethodProp32_Replace(oneMethodInfo, NCoderPropID::kNumThreads, numThreads);
+}
+
+#endif // Z7_ST
+
+
+void CMultiMethodProps::InitMulti()
+{
+ _level = (UInt32)(Int32)-1;
+ _analysisLevel = -1;
+ _crcSize = 4;
+ _autoFilter = true;
+}
+
+void CMultiMethodProps::Init()
+{
+ InitCommon();
+ InitMulti();
+ _methods.Clear();
+ _filterMethod.Clear();
+}
+
+
+HRESULT CMultiMethodProps::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
+{
+ UString name = nameSpec;
+ name.MakeLower_Ascii();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+
+ if (name[0] == 'x')
+ {
+ name.Delete(0);
+ _level = 9;
+ return ParsePropToUInt32(name, value, _level);
+ }
+
+ if (name.IsPrefixedBy_Ascii_NoCase("yx"))
+ {
+ name.Delete(0, 2);
+ UInt32 v = 9;
+ RINOK(ParsePropToUInt32(name, value, v))
+ _analysisLevel = (int)v;
+ return S_OK;
+ }
+
+ if (name.IsPrefixedBy_Ascii_NoCase("crc"))
+ {
+ name.Delete(0, 3);
+ _crcSize = 4;
+ return ParsePropToUInt32(name, value, _crcSize);
+ }
+
+ {
+ HRESULT hres;
+ if (SetCommonProperty(name, value, hres))
+ return hres;
+ }
+
+ UInt32 number;
+ const unsigned index = ParseStringToUInt32(name, number);
+ const UString realName = name.Ptr(index);
+ if (index == 0)
+ {
+ if (name.IsEqualTo("f"))
+ {
+ const HRESULT res = PROPVARIANT_to_bool(value, _autoFilter);
+ if (res == S_OK)
+ return res;
+ if (value.vt != VT_BSTR)
+ return E_INVALIDARG;
+ return _filterMethod.ParseMethodFromPROPVARIANT(UString(), value);
+ }
+ number = 0;
+ }
+ if (number > 64)
+ return E_INVALIDARG;
+ for (unsigned j = _methods.Size(); j <= number; j++)
+ _methods.AddNew();
+ return _methods[number].ParseMethodFromPROPVARIANT(realName, value);
+}
+
+
+
+void CSingleMethodProps::Init()
+{
+ InitCommon();
+ InitSingle();
+ Clear();
+}
+
+
+HRESULT CSingleMethodProps::SetProperty(const wchar_t *name2, const PROPVARIANT &value)
+{
+ // processed = false;
+ UString name = name2;
+ name.MakeLower_Ascii();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+ if (name.IsPrefixedBy_Ascii_NoCase("x"))
+ {
+ UInt32 a = 9;
+ RINOK(ParsePropToUInt32(name.Ptr(1), value, a))
+ _level = a;
+ AddProp_Level(a);
+ // processed = true;
+ return S_OK;
+ }
+ {
+ HRESULT hres;
+ if (SetCommonProperty(name, value, hres))
+ {
+ // processed = true;
+ return S_OK;
+ }
+ }
+ RINOK(ParseMethodFromPROPVARIANT(name, value))
+ return S_OK;
+}
+
+
+HRESULT CSingleMethodProps::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
+{
+ Init();
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ RINOK(SetProperty(names[i], values[i]))
+ }
+
+ return S_OK;
+}
+
+#endif
+
+
+static HRESULT PROPVARIANT_to_BoolPair(const PROPVARIANT &prop, CBoolPair &dest)
+{
+ RINOK(PROPVARIANT_to_bool(prop, dest.Val))
+ dest.Def = true;
+ return S_OK;
+}
+
+HRESULT CHandlerTimeOptions::Parse(const UString &name, const PROPVARIANT &prop, bool &processed)
+{
+ processed = true;
+ if (name.IsEqualTo_Ascii_NoCase("tm")) { return PROPVARIANT_to_BoolPair(prop, Write_MTime); }
+ if (name.IsEqualTo_Ascii_NoCase("ta")) { return PROPVARIANT_to_BoolPair(prop, Write_ATime); }
+ if (name.IsEqualTo_Ascii_NoCase("tc")) { return PROPVARIANT_to_BoolPair(prop, Write_CTime); }
+ if (name.IsPrefixedBy_Ascii_NoCase("tp"))
+ {
+ UInt32 v = 0;
+ RINOK(ParsePropToUInt32(name.Ptr(2), prop, v))
+ Prec = v;
+ return S_OK;
+ }
+ processed = false;
+ return S_OK;
+}
+
+}
diff --git a/CPP/7zip/Archive/Common/HandlerOut.h b/CPP/7zip/Archive/Common/HandlerOut.h
index 90b000a..cfba46e 100644
--- a/CPP/7zip/Archive/Common/HandlerOut.h
+++ b/CPP/7zip/Archive/Common/HandlerOut.h
@@ -1,110 +1,154 @@
-// HandlerOut.h
-
-#ifndef __HANDLER_OUT_H
-#define __HANDLER_OUT_H
-
-#include "../../../Windows/System.h"
-
-#include "../../Common/MethodProps.h"
-
-namespace NArchive {
-
-bool ParseSizeString(const wchar_t *name, const PROPVARIANT &prop, UInt64 percentsBase, UInt64 &res);
-
-class CCommonMethodProps
-{
-protected:
- void InitCommon()
- {
- #ifndef _7ZIP_ST
- _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors();
- #endif
-
- UInt64 memAvail = (UInt64)(sizeof(size_t)) << 28;
- _memAvail = memAvail;
- _memUsage = memAvail;
- if (NWindows::NSystem::GetRamSize(memAvail))
- {
- _memAvail = memAvail;
- _memUsage = memAvail / 32 * 17;
- }
- }
-
-public:
- #ifndef _7ZIP_ST
- UInt32 _numThreads;
- UInt32 _numProcessors;
- #endif
-
- UInt64 _memUsage;
- UInt64 _memAvail;
-
- bool SetCommonProperty(const UString &name, const PROPVARIANT &value, HRESULT &hres);
-
- CCommonMethodProps() { InitCommon(); }
-};
-
-
-#ifndef EXTRACT_ONLY
-
-class CMultiMethodProps: public CCommonMethodProps
-{
- UInt32 _level;
- int _analysisLevel;
-
- void InitMulti();
-public:
- UInt32 _crcSize;
- CObjectVector<COneMethodInfo> _methods;
- COneMethodInfo _filterMethod;
- bool _autoFilter;
-
-
- void SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const;
-
- #ifndef _7ZIP_ST
- static void SetMethodThreadsTo(COneMethodInfo &oneMethodInfo, UInt32 numThreads);
- #endif
-
-
- unsigned GetNumEmptyMethods() const
- {
- unsigned i;
- for (i = 0; i < _methods.Size(); i++)
- if (!_methods[i].IsEmpty())
- break;
- return i;
- }
-
- int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; }
- int GetAnalysisLevel() const { return _analysisLevel; }
-
- void Init();
- CMultiMethodProps() { InitMulti(); }
-
- HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value);
-};
-
-
-class CSingleMethodProps: public COneMethodInfo, public CCommonMethodProps
-{
- UInt32 _level;
-
- void InitSingle()
- {
- _level = (UInt32)(Int32)-1;
- }
-
-public:
- void Init();
- CSingleMethodProps() { InitSingle(); }
-
- int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; }
- HRESULT SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
-};
-
-#endif
-
-}
-
-#endif
+// HandlerOut.h
+
+#ifndef ZIP7_INC_HANDLER_OUT_H
+#define ZIP7_INC_HANDLER_OUT_H
+
+#include "../../../Windows/System.h"
+
+#include "../../Common/MethodProps.h"
+
+namespace NArchive {
+
+bool ParseSizeString(const wchar_t *name, const PROPVARIANT &prop, UInt64 percentsBase, UInt64 &res);
+
+class CCommonMethodProps
+{
+protected:
+ void InitCommon()
+ {
+ // _Write_MTime = true;
+ #ifndef Z7_ST
+ _numProcessors = _numThreads = NWindows::NSystem::GetNumberOfProcessors();
+ _numThreads_WasForced = false;
+ #endif
+
+ UInt64 memAvail = (UInt64)(sizeof(size_t)) << 28;
+ _memAvail = memAvail;
+ _memUsage_Compress = memAvail;
+ _memUsage_Decompress = memAvail;
+ _memUsage_WasSet = NWindows::NSystem::GetRamSize(memAvail);
+ if (_memUsage_WasSet)
+ {
+ _memAvail = memAvail;
+ unsigned bits = sizeof(size_t) * 8;
+ if (bits == 32)
+ {
+ const UInt32 limit2 = (UInt32)7 << 28;
+ if (memAvail > limit2)
+ memAvail = limit2;
+ }
+ // 80% - is auto usage limit in handlers
+ // _memUsage_Compress = memAvail * 4 / 5;
+ // _memUsage_Compress = Calc_From_Val_Percents(memAvail, 80);
+ _memUsage_Compress = Calc_From_Val_Percents_Less100(memAvail, 80);
+ _memUsage_Decompress = memAvail / 32 * 17;
+ }
+ }
+
+public:
+ #ifndef Z7_ST
+ UInt32 _numThreads;
+ UInt32 _numProcessors;
+ bool _numThreads_WasForced;
+ #endif
+
+ bool _memUsage_WasSet;
+ UInt64 _memUsage_Compress;
+ UInt64 _memUsage_Decompress;
+ UInt64 _memAvail;
+
+ bool SetCommonProperty(const UString &name, const PROPVARIANT &value, HRESULT &hres);
+
+ CCommonMethodProps() { InitCommon(); }
+};
+
+
+#ifndef Z7_EXTRACT_ONLY
+
+class CMultiMethodProps: public CCommonMethodProps
+{
+ UInt32 _level;
+ int _analysisLevel;
+
+ void InitMulti();
+public:
+ UInt32 _crcSize;
+ CObjectVector<COneMethodInfo> _methods;
+ COneMethodInfo _filterMethod;
+ bool _autoFilter;
+
+
+ void SetGlobalLevelTo(COneMethodInfo &oneMethodInfo) const;
+
+ #ifndef Z7_ST
+ static void SetMethodThreadsTo_IfNotFinded(CMethodProps &props, UInt32 numThreads);
+ static void SetMethodThreadsTo_Replace(CMethodProps &props, UInt32 numThreads);
+ #endif
+
+
+ unsigned GetNumEmptyMethods() const
+ {
+ unsigned i;
+ for (i = 0; i < _methods.Size(); i++)
+ if (!_methods[i].IsEmpty())
+ break;
+ return i;
+ }
+
+ int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; }
+ int GetAnalysisLevel() const { return _analysisLevel; }
+
+ void Init();
+ CMultiMethodProps() { InitMulti(); }
+
+ HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value);
+};
+
+
+class CSingleMethodProps: public COneMethodInfo, public CCommonMethodProps
+{
+ UInt32 _level;
+
+ void InitSingle()
+ {
+ _level = (UInt32)(Int32)-1;
+ }
+
+public:
+ void Init();
+ CSingleMethodProps() { InitSingle(); }
+
+ int GetLevel() const { return _level == (UInt32)(Int32)-1 ? 5 : (int)_level; }
+ HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &values);
+ HRESULT SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
+};
+
+#endif
+
+struct CHandlerTimeOptions
+{
+ CBoolPair Write_MTime;
+ CBoolPair Write_ATime;
+ CBoolPair Write_CTime;
+ UInt32 Prec;
+
+ void Init()
+ {
+ Write_MTime.Init();
+ Write_MTime.Val = true;
+ Write_ATime.Init();
+ Write_CTime.Init();
+ Prec = (UInt32)(Int32)-1;
+ }
+
+ CHandlerTimeOptions()
+ {
+ Init();
+ }
+
+ HRESULT Parse(const UString &name, const PROPVARIANT &prop, bool &processed);
+};
+
+}
+
+#endif
diff --git a/CPP/7zip/Archive/Common/InStreamWithCRC.cpp b/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
index cddc083..735d5d1 100644
--- a/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
+++ b/CPP/7zip/Archive/Common/InStreamWithCRC.cpp
@@ -1,46 +1,57 @@
-// InStreamWithCRC.cpp
-
-#include "StdAfx.h"
-
-#include "InStreamWithCRC.h"
-
-STDMETHODIMP CSequentialInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- UInt32 realProcessed = 0;
- HRESULT result = S_OK;
- if (_stream)
- result = _stream->Read(data, size, &realProcessed);
- _size += realProcessed;
- if (size != 0 && realProcessed == 0)
- _wasFinished = true;
- _crc = CrcUpdate(_crc, data, realProcessed);
- if (processedSize)
- *processedSize = realProcessed;
- return result;
-}
-
-STDMETHODIMP CInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- UInt32 realProcessed = 0;
- HRESULT result = S_OK;
- if (_stream)
- result = _stream->Read(data, size, &realProcessed);
- _size += realProcessed;
- /*
- if (size != 0 && realProcessed == 0)
- _wasFinished = true;
- */
- _crc = CrcUpdate(_crc, data, realProcessed);
- if (processedSize)
- *processedSize = realProcessed;
- return result;
-}
-
-STDMETHODIMP CInStreamWithCRC::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- if (seekOrigin != STREAM_SEEK_SET || offset != 0)
- return E_FAIL;
- _size = 0;
- _crc = CRC_INIT_VAL;
- return _stream->Seek(offset, seekOrigin, newPosition);
-}
+// InStreamWithCRC.cpp
+
+#include "StdAfx.h"
+
+#include "InStreamWithCRC.h"
+
+Z7_COM7F_IMF(CSequentialInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ UInt32 realProcessed = 0;
+ HRESULT result = S_OK;
+ if (size != 0)
+ {
+ if (_stream)
+ result = _stream->Read(data, size, &realProcessed);
+ _size += realProcessed;
+ if (realProcessed == 0)
+ _wasFinished = true;
+ else
+ _crc = CrcUpdate(_crc, data, realProcessed);
+ }
+ if (processedSize)
+ *processedSize = realProcessed;
+ return result;
+}
+
+Z7_COM7F_IMF(CSequentialInStreamWithCRC::GetSize(UInt64 *size))
+{
+ *size = _fullSize;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CInStreamWithCRC::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ UInt32 realProcessed = 0;
+ HRESULT result = S_OK;
+ if (_stream)
+ result = _stream->Read(data, size, &realProcessed);
+ _size += realProcessed;
+ /*
+ if (size != 0 && realProcessed == 0)
+ _wasFinished = true;
+ */
+ _crc = CrcUpdate(_crc, data, realProcessed);
+ if (processedSize)
+ *processedSize = realProcessed;
+ return result;
+}
+
+Z7_COM7F_IMF(CInStreamWithCRC::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ if (seekOrigin != STREAM_SEEK_SET || offset != 0)
+ return E_FAIL;
+ _size = 0;
+ _crc = CRC_INIT_VAL;
+ return _stream->Seek(offset, seekOrigin, newPosition);
+}
diff --git a/CPP/7zip/Archive/Common/InStreamWithCRC.h b/CPP/7zip/Archive/Common/InStreamWithCRC.h
index 1a4b2c9..2a91d76 100644
--- a/CPP/7zip/Archive/Common/InStreamWithCRC.h
+++ b/CPP/7zip/Archive/Common/InStreamWithCRC.h
@@ -1,67 +1,67 @@
-// InStreamWithCRC.h
-
-#ifndef __IN_STREAM_WITH_CRC_H
-#define __IN_STREAM_WITH_CRC_H
-
-#include "../../../../C/7zCrc.h"
-
-#include "../../../Common/MyCom.h"
-
-#include "../../IStream.h"
-
-class CSequentialInStreamWithCRC:
- public ISequentialInStream,
- public CMyUnknownImp
-{
-public:
- MY_UNKNOWN_IMP
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
-private:
- CMyComPtr<ISequentialInStream> _stream;
- UInt64 _size;
- UInt32 _crc;
- bool _wasFinished;
-public:
- void SetStream(ISequentialInStream *stream) { _stream = stream; }
- void Init()
- {
- _size = 0;
- _wasFinished = false;
- _crc = CRC_INIT_VAL;
- }
- void ReleaseStream() { _stream.Release(); }
- UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
- UInt64 GetSize() const { return _size; }
- bool WasFinished() const { return _wasFinished; }
-};
-
-class CInStreamWithCRC:
- public IInStream,
- public CMyUnknownImp
-{
-public:
- MY_UNKNOWN_IMP1(IInStream)
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
-private:
- CMyComPtr<IInStream> _stream;
- UInt64 _size;
- UInt32 _crc;
- // bool _wasFinished;
-public:
- void SetStream(IInStream *stream) { _stream = stream; }
- void Init()
- {
- _size = 0;
- // _wasFinished = false;
- _crc = CRC_INIT_VAL;
- }
- void ReleaseStream() { _stream.Release(); }
- UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
- UInt64 GetSize() const { return _size; }
- // bool WasFinished() const { return _wasFinished; }
-};
-
-#endif
+// InStreamWithCRC.h
+
+#ifndef ZIP7_INC_IN_STREAM_WITH_CRC_H
+#define ZIP7_INC_IN_STREAM_WITH_CRC_H
+
+#include "../../../../C/7zCrc.h"
+
+#include "../../../Common/MyCom.h"
+
+#include "../../IStream.h"
+
+Z7_CLASS_IMP_NOQIB_2(
+ CSequentialInStreamWithCRC
+ , ISequentialInStream
+ , IStreamGetSize
+)
+ CMyComPtr<ISequentialInStream> _stream;
+ UInt64 _size;
+ UInt32 _crc;
+ bool _wasFinished;
+ UInt64 _fullSize;
+public:
+
+ CSequentialInStreamWithCRC():
+ _fullSize((UInt64)(Int64)-1)
+ {}
+
+ void SetStream(ISequentialInStream *stream) { _stream = stream; }
+ void SetFullSize(UInt64 fullSize) { _fullSize = fullSize; }
+ void Init()
+ {
+ _size = 0;
+ _crc = CRC_INIT_VAL;
+ _wasFinished = false;
+ }
+ void ReleaseStream() { _stream.Release(); }
+ UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
+ UInt64 GetSize() const { return _size; }
+ bool WasFinished() const { return _wasFinished; }
+};
+
+
+Z7_CLASS_IMP_COM_1(
+ CInStreamWithCRC,
+ IInStream
+)
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+
+ CMyComPtr<IInStream> _stream;
+ UInt64 _size;
+ UInt32 _crc;
+ // bool _wasFinished;
+public:
+ void SetStream(IInStream *stream) { _stream = stream; }
+ void Init()
+ {
+ _size = 0;
+ // _wasFinished = false;
+ _crc = CRC_INIT_VAL;
+ }
+ void ReleaseStream() { _stream.Release(); }
+ UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
+ UInt64 GetSize() const { return _size; }
+ // bool WasFinished() const { return _wasFinished; }
+};
+
+#endif
diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.cpp b/CPP/7zip/Archive/Common/ItemNameUtils.cpp
index e0c35a9..8caf1d1 100644
--- a/CPP/7zip/Archive/Common/ItemNameUtils.cpp
+++ b/CPP/7zip/Archive/Common/ItemNameUtils.cpp
@@ -1,88 +1,135 @@
-// Archive/Common/ItemNameUtils.cpp
-
-#include "StdAfx.h"
-
-#include "ItemNameUtils.h"
-
-namespace NArchive {
-namespace NItemName {
-
-static const wchar_t kOsPathSepar = WCHAR_PATH_SEPARATOR;
-static const wchar_t kUnixPathSepar = L'/';
-
-void ReplaceSlashes_OsToUnix
-#if WCHAR_PATH_SEPARATOR != L'/'
- (UString &name)
- {
- name.Replace(kOsPathSepar, kUnixPathSepar);
- }
-#else
- (UString &) {}
-#endif
-
-
-UString GetOsPath(const UString &name)
-{
- #if WCHAR_PATH_SEPARATOR != L'/'
- UString newName = name;
- newName.Replace(kUnixPathSepar, kOsPathSepar);
- return newName;
- #else
- return name;
- #endif
-}
-
-
-UString GetOsPath_Remove_TailSlash(const UString &name)
-{
- if (name.IsEmpty())
- return UString();
- UString newName = GetOsPath(name);
- if (newName.Back() == kOsPathSepar)
- newName.DeleteBack();
- return newName;
-}
-
-
-void ReplaceToOsSlashes_Remove_TailSlash(UString &name)
-{
- if (!name.IsEmpty())
- {
- #if WCHAR_PATH_SEPARATOR != L'/'
- name.Replace(kUnixPathSepar, kOsPathSepar);
- #endif
-
- if (name.Back() == kOsPathSepar)
- name.DeleteBack();
- }
-}
-
-
-bool HasTailSlash(const AString &name, UINT
- #if defined(_WIN32) && !defined(UNDER_CE)
- codePage
- #endif
- )
-{
- if (name.IsEmpty())
- return false;
- char c =
- #if defined(_WIN32) && !defined(UNDER_CE)
- *CharPrevExA((WORD)codePage, name, name.Ptr(name.Len()), 0);
- #else
- name.Back();
- #endif
- return (c == '/');
-}
-
-
-#ifndef _WIN32
-UString WinPathToOsPath(const UString &name)
-{
- UString newName = name;
- newName.Replace(L'\\', WCHAR_PATH_SEPARATOR);
- return newName;
-}
-#endif
-
-}}
+// Archive/Common/ItemNameUtils.cpp
+
+#include "StdAfx.h"
+
+#include "ItemNameUtils.h"
+
+namespace NArchive {
+namespace NItemName {
+
+static const wchar_t kOsPathSepar = WCHAR_PATH_SEPARATOR;
+
+#if WCHAR_PATH_SEPARATOR != L'/'
+static const wchar_t kUnixPathSepar = L'/';
+#endif
+
+void ReplaceSlashes_OsToUnix
+#if WCHAR_PATH_SEPARATOR != L'/'
+ (UString &name)
+ {
+ name.Replace(kOsPathSepar, kUnixPathSepar);
+ }
+#else
+ (UString &) {}
+#endif
+
+
+UString GetOsPath(const UString &name)
+{
+ #if WCHAR_PATH_SEPARATOR != L'/'
+ UString newName = name;
+ newName.Replace(kUnixPathSepar, kOsPathSepar);
+ return newName;
+ #else
+ return name;
+ #endif
+}
+
+
+UString GetOsPath_Remove_TailSlash(const UString &name)
+{
+ if (name.IsEmpty())
+ return UString();
+ UString newName = GetOsPath(name);
+ if (newName.Back() == kOsPathSepar)
+ newName.DeleteBack();
+ return newName;
+}
+
+
+void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool
+ #if WCHAR_PATH_SEPARATOR != L'/'
+ useBackslashReplacement
+ #endif
+ )
+{
+ if (name.IsEmpty())
+ return;
+
+ #if WCHAR_PATH_SEPARATOR != L'/'
+ {
+ // name.Replace(kUnixPathSepar, kOsPathSepar);
+ const unsigned len = name.Len();
+ for (unsigned i = 0; i < len; i++)
+ {
+ wchar_t c = name[i];
+ if (c == L'/')
+ c = WCHAR_PATH_SEPARATOR;
+ else if (useBackslashReplacement && c == L'\\')
+ c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme
+ else
+ continue;
+ name.ReplaceOneCharAtPos(i, c);
+ }
+ }
+ #endif
+
+ if (name.Back() == kOsPathSepar)
+ name.DeleteBack();
+}
+
+
+void NormalizeSlashes_in_FileName_for_OsPath(wchar_t *name, unsigned len)
+{
+ for (unsigned i = 0; i < len; i++)
+ {
+ wchar_t c = name[i];
+ if (c == L'/')
+ c = L'_';
+ #if WCHAR_PATH_SEPARATOR != L'/'
+ else if (c == L'\\')
+ c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme
+ #endif
+ else
+ continue;
+ name[i] = c;
+ }
+}
+
+void NormalizeSlashes_in_FileName_for_OsPath(UString &name)
+{
+ NormalizeSlashes_in_FileName_for_OsPath(name.GetBuf(), name.Len());
+}
+
+
+bool HasTailSlash(const AString &name, UINT
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ codePage
+ #endif
+ )
+{
+ if (name.IsEmpty())
+ return false;
+ char c;
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (codePage != CP_UTF8)
+ c = *CharPrevExA((WORD)codePage, name, name.Ptr(name.Len()), 0);
+ else
+ #endif
+ {
+ c = name.Back();
+ }
+ return (c == '/');
+}
+
+
+#ifndef _WIN32
+UString WinPathToOsPath(const UString &name)
+{
+ UString newName = name;
+ newName.Replace(L'\\', WCHAR_PATH_SEPARATOR);
+ return newName;
+}
+#endif
+
+}}
diff --git a/CPP/7zip/Archive/Common/ItemNameUtils.h b/CPP/7zip/Archive/Common/ItemNameUtils.h
index 404fce4..8ab9b61 100644
--- a/CPP/7zip/Archive/Common/ItemNameUtils.h
+++ b/CPP/7zip/Archive/Common/ItemNameUtils.h
@@ -1,28 +1,30 @@
-// Archive/Common/ItemNameUtils.h
-
-#ifndef __ARCHIVE_ITEM_NAME_UTILS_H
-#define __ARCHIVE_ITEM_NAME_UTILS_H
-
-#include "../../../Common/MyString.h"
-
-namespace NArchive {
-namespace NItemName {
-
-void ReplaceSlashes_OsToUnix(UString &name);
-
-UString GetOsPath(const UString &name);
-UString GetOsPath_Remove_TailSlash(const UString &name);
-
-void ReplaceToOsSlashes_Remove_TailSlash(UString &name);
-
-bool HasTailSlash(const AString &name, UINT codePage);
-
-#ifdef _WIN32
- inline UString WinPathToOsPath(const UString &name) { return name; }
-#else
- UString WinPathToOsPath(const UString &name);
-#endif
-
-}}
-
-#endif
+// Archive/Common/ItemNameUtils.h
+
+#ifndef ZIP7_INC_ARCHIVE_ITEM_NAME_UTILS_H
+#define ZIP7_INC_ARCHIVE_ITEM_NAME_UTILS_H
+
+#include "../../../Common/MyString.h"
+
+namespace NArchive {
+namespace NItemName {
+
+void ReplaceSlashes_OsToUnix(UString &name);
+
+UString GetOsPath(const UString &name);
+UString GetOsPath_Remove_TailSlash(const UString &name);
+
+void ReplaceToOsSlashes_Remove_TailSlash(UString &name, bool useBackslashReplacement = false);
+void NormalizeSlashes_in_FileName_for_OsPath(wchar_t *s, unsigned len);
+void NormalizeSlashes_in_FileName_for_OsPath(UString &name);
+
+bool HasTailSlash(const AString &name, UINT codePage);
+
+#ifdef _WIN32
+ inline UString WinPathToOsPath(const UString &name) { return name; }
+#else
+ UString WinPathToOsPath(const UString &name);
+#endif
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Common/MultiStream.cpp b/CPP/7zip/Archive/Common/MultiStream.cpp
index 39d1521..5d357af 100644
--- a/CPP/7zip/Archive/Common/MultiStream.cpp
+++ b/CPP/7zip/Archive/Common/MultiStream.cpp
@@ -1,191 +1,193 @@
-// MultiStream.cpp
-
-#include "StdAfx.h"
-
-#include "MultiStream.h"
-
-STDMETHODIMP CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
- if (size == 0)
- return S_OK;
- if (_pos >= _totalLength)
- return S_OK;
-
- {
- unsigned left = 0, mid = _streamIndex, right = Streams.Size();
- for (;;)
- {
- CSubStreamInfo &m = Streams[mid];
- if (_pos < m.GlobalOffset)
- right = mid;
- else if (_pos >= m.GlobalOffset + m.Size)
- left = mid + 1;
- else
- {
- _streamIndex = mid;
- break;
- }
- mid = (left + right) / 2;
- }
- _streamIndex = mid;
- }
-
- CSubStreamInfo &s = Streams[_streamIndex];
- UInt64 localPos = _pos - s.GlobalOffset;
- if (localPos != s.LocalPos)
- {
- RINOK(s.Stream->Seek(localPos, STREAM_SEEK_SET, &s.LocalPos));
- }
- UInt64 rem = s.Size - localPos;
- if (size > rem)
- size = (UInt32)rem;
- HRESULT result = s.Stream->Read(data, size, &size);
- _pos += size;
- s.LocalPos += size;
- if (processedSize)
- *processedSize = size;
- return result;
-}
-
-STDMETHODIMP CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- switch (seekOrigin)
- {
- case STREAM_SEEK_SET: break;
- case STREAM_SEEK_CUR: offset += _pos; break;
- case STREAM_SEEK_END: offset += _totalLength; break;
- default: return STG_E_INVALIDFUNCTION;
- }
- if (offset < 0)
- return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
- _pos = offset;
- if (newPosition)
- *newPosition = offset;
- return S_OK;
-}
-
-
-/*
-class COutVolumeStream:
- public ISequentialOutStream,
- public CMyUnknownImp
-{
- unsigned _volIndex;
- UInt64 _volSize;
- UInt64 _curPos;
- CMyComPtr<ISequentialOutStream> _volumeStream;
- COutArchive _archive;
- CCRC _crc;
-
-public:
- MY_UNKNOWN_IMP
-
- CFileItem _file;
- CUpdateOptions _options;
- CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
- void Init(IArchiveUpdateCallback2 *volumeCallback,
- const UString &name)
- {
- _file.Name = name;
- _file.IsStartPosDefined = true;
- _file.StartPos = 0;
-
- VolumeCallback = volumeCallback;
- _volIndex = 0;
- _volSize = 0;
- }
-
- HRESULT Flush();
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
-};
-
-HRESULT COutVolumeStream::Flush()
-{
- if (_volumeStream)
- {
- _file.UnPackSize = _curPos;
- _file.FileCRC = _crc.GetDigest();
- RINOK(WriteVolumeHeader(_archive, _file, _options));
- _archive.Close();
- _volumeStream.Release();
- _file.StartPos += _file.UnPackSize;
- }
- return S_OK;
-}
-*/
-
-/*
-STDMETHODIMP COutMultiStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
- while (size > 0)
- {
- if (_streamIndex >= Streams.Size())
- {
- CSubStreamInfo subStream;
- RINOK(VolumeCallback->GetVolumeSize(Streams.Size(), &subStream.Size));
- RINOK(VolumeCallback->GetVolumeStream(Streams.Size(), &subStream.Stream));
- subStream.Pos = 0;
- Streams.Add(subStream);
- continue;
- }
- CSubStreamInfo &subStream = Streams[_streamIndex];
- if (_offsetPos >= subStream.Size)
- {
- _offsetPos -= subStream.Size;
- _streamIndex++;
- continue;
- }
- if (_offsetPos != subStream.Pos)
- {
- CMyComPtr<IOutStream> outStream;
- RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream));
- RINOK(outStream->Seek(_offsetPos, STREAM_SEEK_SET, NULL));
- subStream.Pos = _offsetPos;
- }
-
- UInt32 curSize = (UInt32)MyMin((UInt64)size, subStream.Size - subStream.Pos);
- UInt32 realProcessed;
- RINOK(subStream.Stream->Write(data, curSize, &realProcessed));
- data = (void *)((Byte *)data + realProcessed);
- size -= realProcessed;
- subStream.Pos += realProcessed;
- _offsetPos += realProcessed;
- _absPos += realProcessed;
- if (_absPos > _length)
- _length = _absPos;
- if (processedSize)
- *processedSize += realProcessed;
- if (subStream.Pos == subStream.Size)
- {
- _streamIndex++;
- _offsetPos = 0;
- }
- if (realProcessed != curSize && realProcessed == 0)
- return E_FAIL;
- }
- return S_OK;
-}
-
-STDMETHODIMP COutMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- switch (seekOrigin)
- {
- case STREAM_SEEK_SET: break;
- case STREAM_SEEK_CUR: offset += _absPos; break;
- case STREAM_SEEK_END: offset += _length; break;
- default: return STG_E_INVALIDFUNCTION;
- }
- if (offset < 0)
- return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
- _absPos = offset;
- _offsetPos = _absPos;
- _streamIndex = 0;
- if (newPosition)
- *newPosition = offset;
- return S_OK;
-}
-*/
+// MultiStream.cpp
+
+#include "StdAfx.h"
+
+#include "MultiStream.h"
+
+Z7_COM7F_IMF(CMultiStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ if (_pos >= _totalLength)
+ return S_OK;
+
+ {
+ unsigned left = 0, mid = _streamIndex, right = Streams.Size();
+ for (;;)
+ {
+ CSubStreamInfo &m = Streams[mid];
+ if (_pos < m.GlobalOffset)
+ right = mid;
+ else if (_pos >= m.GlobalOffset + m.Size)
+ left = mid + 1;
+ else
+ break;
+ mid = (left + right) / 2;
+ }
+ _streamIndex = mid;
+ }
+
+ CSubStreamInfo &s = Streams[_streamIndex];
+ UInt64 localPos = _pos - s.GlobalOffset;
+ if (localPos != s.LocalPos)
+ {
+ RINOK(s.Stream->Seek((Int64)localPos, STREAM_SEEK_SET, &s.LocalPos))
+ }
+ {
+ const UInt64 rem = s.Size - localPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+ const HRESULT result = s.Stream->Read(data, size, &size);
+ _pos += size;
+ s.LocalPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return result;
+}
+
+Z7_COM7F_IMF(CMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _pos; break;
+ case STREAM_SEEK_END: offset += _totalLength; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _pos = (UInt64)offset;
+ if (newPosition)
+ *newPosition = (UInt64)offset;
+ return S_OK;
+}
+
+
+/*
+class COutVolumeStream:
+ public ISequentialOutStream,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_0
+ Z7_IFACE_COM7_IMP(ISequentialOutStream)
+
+ unsigned _volIndex;
+ UInt64 _volSize;
+ UInt64 _curPos;
+ CMyComPtr<ISequentialOutStream> _volumeStream;
+ COutArchive _archive;
+ CCRC _crc;
+
+public:
+ CFileItem _file;
+ CUpdateOptions _options;
+ CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
+ void Init(IArchiveUpdateCallback2 *volumeCallback,
+ const UString &name)
+ {
+ _file.Name = name;
+ _file.IsStartPosDefined = true;
+ _file.StartPos = 0;
+
+ VolumeCallback = volumeCallback;
+ _volIndex = 0;
+ _volSize = 0;
+ }
+
+ HRESULT Flush();
+};
+
+HRESULT COutVolumeStream::Flush()
+{
+ if (_volumeStream)
+ {
+ _file.UnPackSize = _curPos;
+ _file.FileCRC = _crc.GetDigest();
+ RINOK(WriteVolumeHeader(_archive, _file, _options))
+ _archive.Close();
+ _volumeStream.Release();
+ _file.StartPos += _file.UnPackSize;
+ }
+ return S_OK;
+}
+*/
+
+/*
+
+#include "../../../Common/Defs.h"
+
+Z7_COM7F_IMF(COutMultiStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ while (size > 0)
+ {
+ if (_streamIndex >= Streams.Size())
+ {
+ CSubStreamInfo subStream;
+ RINOK(VolumeCallback->GetVolumeSize(Streams.Size(), &subStream.Size))
+ RINOK(VolumeCallback->GetVolumeStream(Streams.Size(), &subStream.Stream))
+ subStream.Pos = 0;
+ Streams.Add(subStream);
+ continue;
+ }
+ CSubStreamInfo &subStream = Streams[_streamIndex];
+ if (_offsetPos >= subStream.Size)
+ {
+ _offsetPos -= subStream.Size;
+ _streamIndex++;
+ continue;
+ }
+ if (_offsetPos != subStream.Pos)
+ {
+ CMyComPtr<IOutStream> outStream;
+ RINOK(subStream.Stream.QueryInterface(IID_IOutStream, &outStream))
+ RINOK(outStream->Seek((Int64)_offsetPos, STREAM_SEEK_SET, NULL))
+ subStream.Pos = _offsetPos;
+ }
+
+ const UInt32 curSize = (UInt32)MyMin((UInt64)size, subStream.Size - subStream.Pos);
+ UInt32 realProcessed;
+ RINOK(subStream.Stream->Write(data, curSize, &realProcessed))
+ data = (const void *)((const Byte *)data + realProcessed);
+ size -= realProcessed;
+ subStream.Pos += realProcessed;
+ _offsetPos += realProcessed;
+ _absPos += realProcessed;
+ if (_absPos > _length)
+ _length = _absPos;
+ if (processedSize)
+ *processedSize += realProcessed;
+ if (subStream.Pos == subStream.Size)
+ {
+ _streamIndex++;
+ _offsetPos = 0;
+ }
+ if (realProcessed != curSize && realProcessed == 0)
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(COutMultiStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _absPos; break;
+ case STREAM_SEEK_END: offset += _length; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _absPos = (UInt64)offset;
+ _offsetPos = _absPos;
+ _streamIndex = 0;
+ if (newPosition)
+ *newPosition = (UInt64)offset;
+ return S_OK;
+}
+*/
diff --git a/CPP/7zip/Archive/Common/MultiStream.h b/CPP/7zip/Archive/Common/MultiStream.h
index 39e041d..e3096f5 100644
--- a/CPP/7zip/Archive/Common/MultiStream.h
+++ b/CPP/7zip/Archive/Common/MultiStream.h
@@ -1,89 +1,88 @@
-// MultiStream.h
-
-#ifndef __MULTI_STREAM_H
-#define __MULTI_STREAM_H
-
-#include "../../../Common/MyCom.h"
-#include "../../../Common/MyVector.h"
-
-#include "../../IStream.h"
-
-class CMultiStream:
- public IInStream,
- public CMyUnknownImp
-{
- UInt64 _pos;
- UInt64 _totalLength;
- unsigned _streamIndex;
-
-public:
-
- struct CSubStreamInfo
- {
- CMyComPtr<IInStream> Stream;
- UInt64 Size;
- UInt64 GlobalOffset;
- UInt64 LocalPos;
-
- CSubStreamInfo(): Size(0), GlobalOffset(0), LocalPos(0) {}
- };
-
- CObjectVector<CSubStreamInfo> Streams;
-
- HRESULT Init()
- {
- UInt64 total = 0;
- FOR_VECTOR (i, Streams)
- {
- CSubStreamInfo &s = Streams[i];
- s.GlobalOffset = total;
- total += Streams[i].Size;
- RINOK(s.Stream->Seek(0, STREAM_SEEK_CUR, &s.LocalPos));
- }
- _totalLength = total;
- _pos = 0;
- _streamIndex = 0;
- return S_OK;
- }
-
- MY_UNKNOWN_IMP1(IInStream)
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
-};
-
-/*
-class COutMultiStream:
- public IOutStream,
- public CMyUnknownImp
-{
- unsigned _streamIndex; // required stream
- UInt64 _offsetPos; // offset from start of _streamIndex index
- UInt64 _absPos;
- UInt64 _length;
-
- struct CSubStreamInfo
- {
- CMyComPtr<ISequentialOutStream> Stream;
- UInt64 Size;
- UInt64 Pos;
- };
- CObjectVector<CSubStreamInfo> Streams;
-public:
- CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
- void Init()
- {
- _streamIndex = 0;
- _offsetPos = 0;
- _absPos = 0;
- _length = 0;
- }
-
- MY_UNKNOWN_IMP1(IOutStream)
-
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
-};
-*/
-
-#endif
+// MultiStream.h
+
+#ifndef ZIP7_INC_MULTI_STREAM_H
+#define ZIP7_INC_MULTI_STREAM_H
+
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyVector.h"
+
+#include "../../IStream.h"
+#include "../../Archive/IArchive.h"
+
+Z7_CLASS_IMP_COM_1(
+ CMultiStream
+ , IInStream
+)
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+
+ unsigned _streamIndex;
+ UInt64 _pos;
+ UInt64 _totalLength;
+
+public:
+
+ struct CSubStreamInfo
+ {
+ CMyComPtr<IInStream> Stream;
+ UInt64 Size;
+ UInt64 GlobalOffset;
+ UInt64 LocalPos;
+ CSubStreamInfo(): Size(0), GlobalOffset(0), LocalPos(0) {}
+ };
+
+ CMyComPtr<IArchiveUpdateCallbackFile> updateCallbackFile;
+ CObjectVector<CSubStreamInfo> Streams;
+
+ HRESULT Init()
+ {
+ UInt64 total = 0;
+ FOR_VECTOR (i, Streams)
+ {
+ CSubStreamInfo &s = Streams[i];
+ s.GlobalOffset = total;
+ total += s.Size;
+ s.LocalPos = 0;
+ {
+ // it was already set to start
+ // RINOK(InStream_GetPos(s.Stream, s.LocalPos));
+ }
+ }
+ _totalLength = total;
+ _pos = 0;
+ _streamIndex = 0;
+ return S_OK;
+ }
+};
+
+/*
+Z7_CLASS_IMP_COM_1(
+ COutMultiStream,
+ IOutStream
+)
+ Z7_IFACE_COM7_IMP(ISequentialOutStream)
+
+ unsigned _streamIndex; // required stream
+ UInt64 _offsetPos; // offset from start of _streamIndex index
+ UInt64 _absPos;
+ UInt64 _length;
+
+ struct CSubStreamInfo
+ {
+ CMyComPtr<ISequentialOutStream> Stream;
+ UInt64 Size;
+ UInt64 Pos;
+ };
+ CObjectVector<CSubStreamInfo> Streams;
+public:
+ CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
+ void Init()
+ {
+ _streamIndex = 0;
+ _offsetPos = 0;
+ _absPos = 0;
+ _length = 0;
+ }
+};
+*/
+
+#endif
diff --git a/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp b/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
index e0d3894..7dcd44a 100644
--- a/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
+++ b/CPP/7zip/Archive/Common/OutStreamWithCRC.cpp
@@ -1,18 +1,18 @@
-// OutStreamWithCRC.cpp
-
-#include "StdAfx.h"
-
-#include "OutStreamWithCRC.h"
-
-STDMETHODIMP COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- HRESULT result = S_OK;
- if (_stream)
- result = _stream->Write(data, size, &size);
- if (_calculate)
- _crc = CrcUpdate(_crc, data, size);
- _size += size;
- if (processedSize != NULL)
- *processedSize = size;
- return result;
-}
+// OutStreamWithCRC.cpp
+
+#include "StdAfx.h"
+
+#include "OutStreamWithCRC.h"
+
+Z7_COM7F_IMF(COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ HRESULT result = S_OK;
+ if (_stream)
+ result = _stream->Write(data, size, &size);
+ if (_calculate)
+ _crc = CrcUpdate(_crc, data, size);
+ _size += size;
+ if (processedSize)
+ *processedSize = size;
+ return result;
+}
diff --git a/CPP/7zip/Archive/Common/OutStreamWithCRC.h b/CPP/7zip/Archive/Common/OutStreamWithCRC.h
index 0cc9a85..845146a 100644
--- a/CPP/7zip/Archive/Common/OutStreamWithCRC.h
+++ b/CPP/7zip/Archive/Common/OutStreamWithCRC.h
@@ -1,37 +1,35 @@
-// OutStreamWithCRC.h
-
-#ifndef __OUT_STREAM_WITH_CRC_H
-#define __OUT_STREAM_WITH_CRC_H
-
-#include "../../../../C/7zCrc.h"
-
-#include "../../../Common/MyCom.h"
-
-#include "../../IStream.h"
-
-class COutStreamWithCRC:
- public ISequentialOutStream,
- public CMyUnknownImp
-{
- CMyComPtr<ISequentialOutStream> _stream;
- UInt64 _size;
- UInt32 _crc;
- bool _calculate;
-public:
- MY_UNKNOWN_IMP
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
- void SetStream(ISequentialOutStream *stream) { _stream = stream; }
- void ReleaseStream() { _stream.Release(); }
- void Init(bool calculate = true)
- {
- _size = 0;
- _calculate = calculate;
- _crc = CRC_INIT_VAL;
- }
- void EnableCalc(bool calculate) { _calculate = calculate; }
- void InitCRC() { _crc = CRC_INIT_VAL; }
- UInt64 GetSize() const { return _size; }
- UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
-};
-
-#endif
+// OutStreamWithCRC.h
+
+#ifndef ZIP7_INC_OUT_STREAM_WITH_CRC_H
+#define ZIP7_INC_OUT_STREAM_WITH_CRC_H
+
+#include "../../../../C/7zCrc.h"
+
+#include "../../../Common/MyCom.h"
+
+#include "../../IStream.h"
+
+Z7_CLASS_IMP_NOQIB_1(
+ COutStreamWithCRC
+ , ISequentialOutStream
+)
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+ UInt32 _crc;
+ bool _calculate;
+public:
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init(bool calculate = true)
+ {
+ _size = 0;
+ _calculate = calculate;
+ _crc = CRC_INIT_VAL;
+ }
+ void EnableCalc(bool calculate) { _calculate = calculate; }
+ void InitCRC() { _crc = CRC_INIT_VAL; }
+ UInt64 GetSize() const { return _size; }
+ UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
+};
+
+#endif
diff --git a/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp b/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp
new file mode 100644
index 0000000..57c18ec
--- /dev/null
+++ b/CPP/7zip/Archive/Common/OutStreamWithSha1.cpp
@@ -0,0 +1,18 @@
+// OutStreamWithSha1.cpp
+
+#include "StdAfx.h"
+
+#include "OutStreamWithSha1.h"
+
+Z7_COM7F_IMF(COutStreamWithSha1::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ HRESULT result = S_OK;
+ if (_stream)
+ result = _stream->Write(data, size, &size);
+ if (_calculate)
+ Sha1_Update(Sha(), (const Byte *)data, size);
+ _size += size;
+ if (processedSize)
+ *processedSize = size;
+ return result;
+}
diff --git a/CPP/7zip/Archive/Common/OutStreamWithSha1.h b/CPP/7zip/Archive/Common/OutStreamWithSha1.h
new file mode 100644
index 0000000..74bc53c
--- /dev/null
+++ b/CPP/7zip/Archive/Common/OutStreamWithSha1.h
@@ -0,0 +1,39 @@
+// OutStreamWithSha1.h
+
+#ifndef ZIP7_INC_OUT_STREAM_WITH_SHA1_H
+#define ZIP7_INC_OUT_STREAM_WITH_SHA1_H
+
+#include "../../../../C/Sha1.h"
+
+#include "../../../Common/MyBuffer2.h"
+#include "../../../Common/MyCom.h"
+
+#include "../../IStream.h"
+
+Z7_CLASS_IMP_NOQIB_1(
+ COutStreamWithSha1
+ , ISequentialOutStream
+)
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+ // CSha1 _sha;
+ bool _calculate;
+ CAlignedBuffer1 _sha;
+
+ CSha1 *Sha() { return (CSha1 *)(void *)(Byte *)_sha; }
+public:
+ COutStreamWithSha1(): _sha(sizeof(CSha1)) {}
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init(bool calculate = true)
+ {
+ _size = 0;
+ _calculate = calculate;
+ Sha1_Init(Sha());
+ }
+ void InitSha1() { Sha1_Init(Sha()); }
+ UInt64 GetSize() const { return _size; }
+ void Final(Byte *digest) { Sha1_Final(Sha(), digest); }
+};
+
+#endif
diff --git a/CPP/7zip/Archive/Common/ParseProperties.cpp b/CPP/7zip/Archive/Common/ParseProperties.cpp
index 0fe89b3..63e4f3e 100644
--- a/CPP/7zip/Archive/Common/ParseProperties.cpp
+++ b/CPP/7zip/Archive/Common/ParseProperties.cpp
@@ -1,3 +1,3 @@
-// ParseProperties.cpp
-
-#include "StdAfx.h"
+// ParseProperties.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Archive/Common/ParseProperties.h b/CPP/7zip/Archive/Common/ParseProperties.h
index f4367a7..4ec2e48 100644
--- a/CPP/7zip/Archive/Common/ParseProperties.h
+++ b/CPP/7zip/Archive/Common/ParseProperties.h
@@ -1,6 +1,6 @@
-// ParseProperties.h
-
-#ifndef __PARSE_PROPERTIES_H
-#define __PARSE_PROPERTIES_H
-
-#endif
+// ParseProperties.h
+
+#ifndef ZIP7_INC_PARSE_PROPERTIES_H
+#define ZIP7_INC_PARSE_PROPERTIES_H
+
+#endif
diff --git a/CPP/7zip/Archive/Common/StdAfx.h b/CPP/7zip/Archive/Common/StdAfx.h
index 59d9ac1..035267c 100644
--- a/CPP/7zip/Archive/Common/StdAfx.h
+++ b/CPP/7zip/Archive/Common/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "../../../Common/Common.h"
-
-#endif
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Archive/CpioHandler.cpp b/CPP/7zip/Archive/CpioHandler.cpp
new file mode 100644
index 0000000..872cea7
--- /dev/null
+++ b/CPP/7zip/Archive/CpioHandler.cpp
@@ -0,0 +1,1099 @@
+// CpioHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/MyLinux.h"
+#include "../../Common/StringConvert.h"
+#include "../../Common/StringToInt.h"
+#include "../../Common/UTFConvert.h"
+
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/TimeUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "Common/ItemNameUtils.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NCpio {
+
+static const Byte kMagicBin0 = 0xC7;
+static const Byte kMagicBin1 = 0x71;
+
+// #define MAGIC_ASCII { '0', '7', '0', '7', '0' }
+
+static const Byte kMagicHex = '1'; // New ASCII Format
+static const Byte kMagicHexCrc = '2'; // New CRC Format
+static const Byte kMagicOct = '7'; // Portable ASCII Format
+
+static const char * const kName_TRAILER = "TRAILER!!!";
+
+static const unsigned k_BinRecord_Size = 2 + 8 * 2 + 2 * 4;
+static const unsigned k_OctRecord_Size = 6 + 8 * 6 + 2 * 11;
+static const unsigned k_HexRecord_Size = 6 + 13 * 8;
+
+static const unsigned k_RecordSize_Max = k_HexRecord_Size;
+
+enum EType
+{
+ k_Type_BinLe,
+ k_Type_BinBe,
+ k_Type_Oct,
+ k_Type_Hex,
+ k_Type_HexCrc
+};
+
+static const char * const k_Types[] =
+{
+ "Binary LE"
+ , "Binary BE"
+ , "Portable ASCII"
+ , "New ASCII"
+ , "New CRC"
+};
+
+struct CItem
+{
+ UInt32 inode;
+ unsigned MainIndex_ForInode;
+ UInt32 Mode;
+ UInt32 MTime;
+ UInt32 DevMajor;
+ UInt32 DevMinor;
+ UInt64 Size;
+ AString Name;
+ UInt32 NumLinks;
+ UInt32 UID;
+ UInt32 GID;
+ UInt32 RDevMajor;
+ UInt32 RDevMinor;
+ UInt32 ChkSum;
+
+ UInt32 AlignMask;
+ EType Type;
+
+ UInt32 HeaderSize;
+ UInt64 HeaderPos;
+
+ CByteBuffer Data; // for symlink
+
+
+ UInt32 GetAlignedSize(UInt32 size) const
+ {
+ return (size + AlignMask) & ~(UInt32)AlignMask;
+ }
+
+ UInt64 GetPackSize() const
+ {
+ const UInt64 alignMask64 = AlignMask;
+ return (Size + alignMask64) & ~(UInt64)alignMask64;
+ }
+
+ bool IsSame_inode_Dev(const CItem &item) const
+ {
+ return inode == item.inode
+ && DevMajor == item.DevMajor
+ && DevMinor == item.DevMinor;
+ }
+
+ bool IsBin() const { return Type == k_Type_BinLe || Type == k_Type_BinBe; }
+ bool IsCrcFormat() const { return Type == k_Type_HexCrc; }
+ bool IsDir() const { return MY_LIN_S_ISDIR(Mode); }
+ bool Is_SymLink() const { return MY_LIN_S_ISLNK(Mode); }
+ bool IsTrailer() const { return strcmp(Name, kName_TRAILER) == 0; }
+ UInt64 GetDataPosition() const { return HeaderPos + HeaderSize; }
+};
+
+
+enum EErrorType
+{
+ k_ErrorType_OK,
+ k_ErrorType_BadSignature,
+ k_ErrorType_Corrupted,
+ k_ErrorType_UnexpectedEnd
+};
+
+
+struct CInArchive
+{
+ EErrorType errorType;
+ ISequentialInStream *Stream;
+ UInt64 Processed;
+ CItem item;
+
+ HRESULT Read(void *data, size_t *size);
+ HRESULT GetNextItem();
+};
+
+HRESULT CInArchive::Read(void *data, size_t *size)
+{
+ const HRESULT res = ReadStream(Stream, data, size);
+ Processed += *size;
+ return res;
+}
+
+
+static bool CheckOctRecord(const Byte *p)
+{
+ for (unsigned i = 6; i < k_OctRecord_Size; i++)
+ {
+ const Byte c = p[i];
+ if (c < '0' || c > '7')
+ return false;
+ }
+ return true;
+}
+
+static bool CheckHexRecord(const Byte *p)
+{
+ for (unsigned i = 6; i < k_HexRecord_Size; i++)
+ {
+ const Byte c = p[i];
+ if ((c < '0' || c > '9') &&
+ (c < 'A' || c > 'F') &&
+ (c < 'a' || c > 'f'))
+ return false;
+ }
+ return true;
+}
+
+static UInt32 ReadHex(const Byte *p)
+{
+ char sz[16];
+ memcpy(sz, p, 8);
+ sz[8] = 0;
+ const char *end;
+ return ConvertHexStringToUInt32(sz, &end);
+}
+
+static UInt32 ReadOct6(const Byte *p)
+{
+ char sz[16];
+ memcpy(sz, p, 6);
+ sz[6] = 0;
+ const char *end;
+ return ConvertOctStringToUInt32(sz, &end);
+}
+
+static UInt64 ReadOct11(const Byte *p)
+{
+ char sz[16];
+ memcpy(sz, p, 11);
+ sz[11] = 0;
+ const char *end;
+ return ConvertOctStringToUInt64(sz, &end);
+}
+
+
+#define READ_HEX( y, dest) dest = ReadHex (p + 6 + (y) * 8);
+#define READ_OCT_6( y, dest) dest = ReadOct6 (p + 6 + (y));
+#define READ_OCT_11( y, dest) dest = ReadOct11(p + 6 + (y));
+
+#define Get32spec(p) (((UInt32)GetUi16(p) << 16) + GetUi16(p + 2))
+#define G16(offs, v) v = GetUi16(p + (offs))
+#define G32(offs, v) v = Get32spec(p + (offs))
+
+static const unsigned kNameSizeMax = 1 << 12;
+
+
+API_FUNC_static_IsArc IsArc_Cpio(const Byte *p, size_t size)
+{
+ if (size < k_BinRecord_Size)
+ return k_IsArc_Res_NEED_MORE;
+
+ UInt32 namePos;
+ UInt32 nameSize;
+ UInt32 mode;
+ UInt32 rDevMinor;
+ UInt32 rDevMajor = 0;
+
+ if (p[0] == '0')
+ {
+ if (p[1] != '7' ||
+ p[2] != '0' ||
+ p[3] != '7' ||
+ p[4] != '0')
+ return k_IsArc_Res_NO;
+ if (p[5] == kMagicOct)
+ {
+ if (size < k_OctRecord_Size)
+ return k_IsArc_Res_NEED_MORE;
+ if (!CheckOctRecord(p))
+ return k_IsArc_Res_NO;
+ READ_OCT_6 (2 * 6, mode)
+ READ_OCT_6 (6 * 6, rDevMinor)
+ READ_OCT_6 (7 * 6 + 11, nameSize)
+ namePos = k_OctRecord_Size;
+ }
+ else if (p[5] == kMagicHex || p[5] == kMagicHexCrc)
+ {
+ if (size < k_HexRecord_Size)
+ return k_IsArc_Res_NEED_MORE;
+ if (!CheckHexRecord(p))
+ return k_IsArc_Res_NO;
+ READ_HEX (1, mode)
+ READ_HEX (9, rDevMajor)
+ READ_HEX (10, rDevMinor)
+ READ_HEX (11, nameSize)
+ namePos = k_HexRecord_Size;
+ }
+ else
+ return k_IsArc_Res_NO;
+ }
+ else
+ {
+ if (p[0] == kMagicBin0 && p[1] == kMagicBin1)
+ {
+ mode = GetUi16(p + 6);
+ rDevMinor = GetUi16(p + 14);
+ nameSize = GetUi16(p + 20);
+ }
+ else if (p[0] == kMagicBin1 && p[1] == kMagicBin0)
+ {
+ mode = GetBe16(p + 6);
+ rDevMinor = GetBe16(p + 14);
+ nameSize = GetBe16(p + 20);
+ }
+ else
+ return k_IsArc_Res_NO;
+ namePos = k_BinRecord_Size;
+ }
+
+ if (mode >= (1 << 16))
+ return k_IsArc_Res_NO;
+
+ if (rDevMajor != 0 ||
+ rDevMinor != 0)
+ {
+ if (!MY_LIN_S_ISCHR(mode) &&
+ !MY_LIN_S_ISBLK(mode))
+ return k_IsArc_Res_NO;
+ }
+
+ // nameSize must include the null byte
+ if (nameSize == 0 || nameSize > kNameSizeMax)
+ return k_IsArc_Res_NO;
+ {
+ unsigned lim = namePos + nameSize - 1;
+ if (lim >= size)
+ lim = (unsigned)size;
+ else if (p[lim] != 0)
+ return k_IsArc_Res_NO;
+ for (unsigned i = namePos; i < lim; i++)
+ if (p[i] == 0)
+ return k_IsArc_Res_NO;
+ }
+
+ return k_IsArc_Res_YES;
+}
+}
+
+
+#define READ_STREAM(_dest_, _size_) \
+ { size_t processed = (_size_); RINOK(Read(_dest_, &processed)); \
+if (processed != (_size_)) { errorType = k_ErrorType_UnexpectedEnd; return S_OK; } }
+
+HRESULT CInArchive::GetNextItem()
+{
+ errorType = k_ErrorType_BadSignature;
+
+ Byte p[k_RecordSize_Max];
+
+ READ_STREAM(p, k_BinRecord_Size)
+
+ UInt32 nameSize;
+ UInt32 namePos;
+
+ /* we try to reduce probability of false detection,
+ so we check some fields for unuxpected values */
+
+ if (p[0] != '0')
+ {
+ if (p[0] == kMagicBin0 && p[1] == kMagicBin1) { item.Type = k_Type_BinLe; }
+ else if (p[0] == kMagicBin1 && p[1] == kMagicBin0)
+ {
+ for (unsigned i = 2; i < k_BinRecord_Size; i += 2)
+ {
+ const Byte b = p[i];
+ p[i] = p[i + 1];
+ p[i + 1] = b;
+ }
+ item.Type = k_Type_BinBe;
+ }
+ else
+ return S_OK;
+
+ errorType = k_ErrorType_Corrupted;
+
+ item.AlignMask = 2 - 1;
+ item.DevMajor = 0;
+ item.RDevMajor = 0;
+ item.ChkSum = 0;
+
+ G16(2, item.DevMinor);
+ G16(4, item.inode);
+ G16(6, item.Mode);
+ G16(8, item.UID);
+ G16(10, item.GID);
+ G16(12, item.NumLinks);
+ G16(14, item.RDevMinor);
+ G32(16, item.MTime);
+ G16(20, nameSize);
+ G32(22, item.Size);
+
+ namePos = k_BinRecord_Size;
+ }
+ else
+ {
+ if (p[1] != '7' ||
+ p[2] != '0' ||
+ p[3] != '7' ||
+ p[4] != '0')
+ return S_OK;
+ if (p[5] == kMagicOct)
+ {
+ errorType = k_ErrorType_Corrupted;
+
+ item.Type = k_Type_Oct;
+ READ_STREAM(p + k_BinRecord_Size, k_OctRecord_Size - k_BinRecord_Size)
+ item.AlignMask = 1 - 1;
+ item.DevMajor = 0;
+ item.RDevMajor = 0;
+ item.ChkSum = 0;
+
+ if (!CheckOctRecord(p))
+ return S_OK;
+
+ READ_OCT_6 (0, item.DevMinor)
+ READ_OCT_6 (1 * 6, item.inode)
+ READ_OCT_6 (2 * 6, item.Mode)
+ READ_OCT_6 (3 * 6, item.UID)
+ READ_OCT_6 (4 * 6, item.GID)
+ READ_OCT_6 (5 * 6, item.NumLinks)
+ READ_OCT_6 (6 * 6, item.RDevMinor)
+ {
+ UInt64 mTime64;
+ READ_OCT_11 (7 * 6, mTime64)
+ item.MTime = 0;
+ if (mTime64 <= (UInt32)(Int32)-1)
+ item.MTime = (UInt32)mTime64;
+ }
+ READ_OCT_6 (7 * 6 + 11, nameSize)
+ READ_OCT_11 (8 * 6 + 11, item.Size) // ?????
+
+ namePos = k_OctRecord_Size;
+ }
+ else
+ {
+ if (p[5] == kMagicHex) item.Type = k_Type_Hex;
+ else if (p[5] == kMagicHexCrc) item.Type = k_Type_HexCrc;
+ else return S_OK;
+
+ errorType = k_ErrorType_Corrupted;
+
+ READ_STREAM(p + k_BinRecord_Size, k_HexRecord_Size - k_BinRecord_Size)
+
+ if (!CheckHexRecord(p))
+ return S_OK;
+
+ item.AlignMask = 4 - 1;
+ READ_HEX (0, item.inode)
+ READ_HEX (1, item.Mode)
+ READ_HEX (2, item.UID)
+ READ_HEX (3, item.GID)
+ READ_HEX (4, item.NumLinks)
+ READ_HEX (5, item.MTime)
+ READ_HEX (6, item.Size)
+ READ_HEX (7, item.DevMajor)
+ READ_HEX (8, item.DevMinor)
+ READ_HEX (9, item.RDevMajor)
+ READ_HEX (10, item.RDevMinor)
+ READ_HEX (11, nameSize)
+ READ_HEX (12, item.ChkSum)
+
+ if (item.Type == k_Type_Hex && item.ChkSum != 0)
+ return S_OK;
+
+ namePos = k_HexRecord_Size;
+ }
+ }
+
+ if (item.Mode >= (1 << 16))
+ return S_OK;
+
+ if (item.RDevMinor != 0 ||
+ item.RDevMajor != 0)
+ {
+ if (!MY_LIN_S_ISCHR(item.Mode) &&
+ !MY_LIN_S_ISBLK(item.Mode))
+ return S_OK;
+ }
+
+ // Size must be 0 for FIFOs and directories
+ if (item.IsDir() || MY_LIN_S_ISFIFO(item.Mode))
+ if (item.Size != 0)
+ return S_OK;
+
+ // nameSize must include the null byte
+ if (nameSize == 0 || nameSize > kNameSizeMax)
+ return S_OK;
+ item.HeaderSize = item.GetAlignedSize(namePos + nameSize);
+ const UInt32 rem = item.HeaderSize - namePos;
+ char *s = item.Name.GetBuf(rem);
+ size_t processedSize = rem;
+ RINOK(Read(s, &processedSize))
+ if (processedSize != rem)
+ {
+ item.Name.ReleaseBuf_SetEnd(0);
+ errorType = k_ErrorType_UnexpectedEnd;
+ return S_OK;
+ }
+ bool pad_error = false;
+ for (size_t i = nameSize; i < processedSize; i++)
+ if (s[i] != 0)
+ pad_error = true;
+ item.Name.ReleaseBuf_CalcLen(nameSize);
+ if (item.Name.Len() + 1 != nameSize || pad_error)
+ return S_OK;
+ errorType = k_ErrorType_OK;
+ return S_OK;
+}
+
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IInArchiveGetStream
+)
+ CObjectVector<CItem> _items;
+ CMyComPtr<IInStream> _stream;
+ UInt64 _phySize;
+ EType _type;
+ EErrorType _error;
+ bool _isArc;
+ bool _moreThanOneHardLinks_Error;
+ bool _numLinks_Error;
+ bool _pad_Error;
+ bool _symLink_Error;
+};
+
+static const Byte kArcProps[] =
+{
+ kpidSubType
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidPosixAttrib,
+ kpidLinks,
+ kpidINode,
+ kpidUserId,
+ kpidGroupId,
+ kpidDevMajor,
+ kpidDevMinor,
+ kpidDeviceMajor,
+ kpidDeviceMinor,
+ kpidChecksum,
+ kpidSymLink,
+ kpidStreamId, // for debug
+ kpidOffset
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidSubType: prop = k_Types[(unsigned)_type]; break;
+ case kpidPhySize: prop = _phySize; break;
+ case kpidINode: prop = true; break;
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc)
+ v |= kpv_ErrorFlags_IsNotArc;
+ switch (_error)
+ {
+ case k_ErrorType_UnexpectedEnd: v |= kpv_ErrorFlags_UnexpectedEnd; break;
+ case k_ErrorType_Corrupted: v |= kpv_ErrorFlags_HeadersError; break;
+ case k_ErrorType_OK:
+ case k_ErrorType_BadSignature:
+ // default:
+ break;
+ }
+ prop = v;
+ break;
+ }
+ case kpidWarningFlags:
+ {
+ UInt32 v = 0;
+ if (_moreThanOneHardLinks_Error)
+ v |= kpv_ErrorFlags_UnsupportedFeature; // kpv_ErrorFlags_HeadersError
+ if (_numLinks_Error
+ || _pad_Error
+ || _symLink_Error)
+ v |= kpv_ErrorFlags_HeadersError;
+ if (v != 0)
+ prop = v;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+static int CompareItems(const unsigned *p1, const unsigned *p2, void *param)
+{
+ const CObjectVector<CItem> &items = *(const CObjectVector<CItem> *)param;
+ const unsigned index1 = *p1;
+ const unsigned index2 = *p2;
+ const CItem &i1 = items[index1];
+ const CItem &i2 = items[index2];
+ if (i1.DevMajor < i2.DevMajor) return -1;
+ if (i1.DevMajor > i2.DevMajor) return 1;
+ if (i1.DevMinor < i2.DevMinor) return -1;
+ if (i1.DevMinor > i2.DevMinor) return 1;
+ if (i1.inode < i2.inode) return -1;
+ if (i1.inode > i2.inode) return 1;
+ if (i1.IsDir())
+ {
+ if (!i2.IsDir())
+ return -1;
+ }
+ else if (i2.IsDir())
+ return 1;
+ return MyCompare(index1, index2);
+}
+
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+
+ UInt64 endPos;
+ RINOK(InStream_AtBegin_GetSize(stream, endPos))
+ if (callback)
+ {
+ RINOK(callback->SetTotal(NULL, &endPos))
+ }
+
+ CInArchive arc;
+
+ arc.Stream = stream;
+ arc.Processed = 0;
+
+ for (;;)
+ {
+ CItem &item = arc.item;
+ item.HeaderPos = arc.Processed;
+
+ RINOK(arc.GetNextItem())
+
+ _error = arc.errorType;
+
+ if (_error != k_ErrorType_OK)
+ {
+ if (_error == k_ErrorType_BadSignature ||
+ _error == k_ErrorType_Corrupted)
+ arc.Processed = item.HeaderPos;
+ break;
+ }
+
+ if (_items.IsEmpty())
+ _type = item.Type;
+ else if (_items.Back().Type != item.Type)
+ {
+ _error = k_ErrorType_Corrupted;
+ arc.Processed = item.HeaderPos;
+ break;
+ }
+
+ if (item.IsTrailer())
+ break;
+
+ item.MainIndex_ForInode = _items.Size();
+ _items.Add(item);
+
+ const UInt64 dataSize = item.GetPackSize();
+ arc.Processed += dataSize;
+ if (arc.Processed > endPos)
+ {
+ _error = k_ErrorType_UnexpectedEnd;
+ break;
+ }
+
+ if (item.Is_SymLink() && dataSize <= (1 << 12) && item.Size != 0)
+ {
+ size_t cur = (size_t)dataSize;
+ CByteBuffer buf;
+ buf.Alloc(cur);
+ RINOK(ReadStream(stream, buf, &cur))
+ if (cur != dataSize)
+ {
+ _error = k_ErrorType_UnexpectedEnd;
+ break;
+ }
+ size_t i;
+
+ for (i = (size_t)item.Size; i < dataSize; i++)
+ if (buf[i] != 0)
+ break;
+ if (i != dataSize)
+ _pad_Error = true;
+
+ for (i = 0; i < (size_t)item.Size; i++)
+ if (buf[i] == 0)
+ break;
+ if (i != (size_t)item.Size)
+ _symLink_Error = true;
+ else
+ _items.Back().Data.CopyFrom(buf, (size_t)item.Size);
+ }
+ else if (dataSize != 0)
+ {
+ UInt64 newPos;
+ RINOK(stream->Seek((Int64)dataSize, STREAM_SEEK_CUR, &newPos))
+ if (arc.Processed != newPos)
+ return E_FAIL;
+ }
+
+ if (callback && (_items.Size() & 0xFFF) == 0)
+ {
+ const UInt64 numFiles = _items.Size();
+ RINOK(callback->SetCompleted(&numFiles, &item.HeaderPos))
+ }
+ }
+
+ _phySize = arc.Processed;
+ }
+
+ {
+ if (_error != k_ErrorType_OK)
+ {
+ // we try to reduce probability of false detection
+ if (_items.Size() == 0)
+ return S_FALSE;
+ // bin file uses small signature. So we do additional check for single item case.
+ if (_items.Size() == 1 && _items[0].IsBin())
+ return S_FALSE;
+ }
+ else
+ {
+ // Read tailing zeros.
+ // Most of cpio files use 512-bytes aligned zeros
+ // rare case: 4K/8K aligment is possible also
+ const unsigned kTailSize_MAX = 1 << 9;
+ Byte buf[kTailSize_MAX];
+
+ unsigned pos = (unsigned)_phySize & (kTailSize_MAX - 1);
+ if (pos != 0) // use this check to support 512 bytes alignment only
+ for (;;)
+ {
+ const unsigned rem = kTailSize_MAX - pos;
+ size_t processed = rem;
+ RINOK(ReadStream(stream, buf + pos, &processed))
+ if (processed != rem)
+ break;
+ for (; pos < kTailSize_MAX && buf[pos] == 0; pos++)
+ {}
+ if (pos != kTailSize_MAX)
+ break;
+ _phySize += processed;
+ pos = 0;
+
+ // use break to support 512 bytes alignment zero tail
+ // don't use break to support 512*n bytes alignment zero tail
+ break;
+ }
+ }
+ }
+
+ {
+ /* there was such cpio archive example with hard links:
+ {
+ all hard links (same dev/inode) are stored in neighboring items, and
+ (item.Size == 0) for non last hard link items
+ (item.Size != 0) for last hard link item
+ }
+ but here we sort items by (dev/inode) to support cases
+ where hard links (same dev/inode) are not stored in neighboring items.
+
+ // note: some cpio files have (numLinks == 0) ??
+ */
+
+ CUIntVector indices;
+ {
+ const unsigned numItems = _items.Size();
+ indices.ClearAndSetSize(numItems);
+ if (numItems != 0)
+ {
+ unsigned *vals = &indices[0];
+ for (unsigned i = 0; i < numItems; i++)
+ vals[i] = i;
+ indices.Sort(CompareItems, (void *)&_items);
+ }
+ }
+
+ /* Note: if cpio archive (maybe incorrect) contains
+ more then one non empty streams with identical inode number,
+ we want to extract all such data streams too.
+
+ So we place items with identical inode to groups:
+ all items in group will have same MainIndex_ForInode,
+ that is index of last item in group with (Size != 0).
+ Another (non last) items in group have (Size == 0).
+ If there are another hard links with same inode number
+ after (Size != 0) item, we place them to another next group(s).
+
+ Check it: maybe we should use single group for items
+ with identical inode instead, and ignore some extra data streams ?
+ */
+
+ for (unsigned i = 0; i < indices.Size();)
+ {
+ unsigned k;
+ {
+ const CItem &item_Base = _items[indices[i]];
+
+ if (item_Base.IsDir())
+ {
+ i++;
+ continue;
+ }
+
+ if (i != 0)
+ {
+ const CItem &item_Prev = _items[indices[i - 1]];
+ if (!item_Prev.IsDir())
+ if (item_Base.IsSame_inode_Dev(item_Prev))
+ _moreThanOneHardLinks_Error = true;
+ }
+
+ if (item_Base.Size != 0)
+ {
+ if (item_Base.NumLinks != 1)
+ _numLinks_Error = true;
+ i++;
+ continue;
+ }
+
+ for (k = i + 1; k < indices.Size();)
+ {
+ const CItem &item = _items[indices[k]];
+ if (item.IsDir())
+ break;
+ if (!item.IsSame_inode_Dev(item_Base))
+ break;
+ k++;
+ if (item.Size != 0)
+ break;
+ }
+ }
+
+ const unsigned numLinks = k - i;
+ for (;;)
+ {
+ CItem &item = _items[indices[i]];
+ if (item.NumLinks != numLinks)
+ _numLinks_Error = true;
+ if (++i == k)
+ break;
+ // if (item.Size == 0)
+ item.MainIndex_ForInode = indices[k - 1];
+ }
+ }
+ }
+
+ _isArc = true;
+ _stream = stream;
+
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _items.Clear();
+ _stream.Release();
+ _phySize = 0;
+ _type = k_Type_BinLe;
+ _isArc = false;
+ _moreThanOneHardLinks_Error = false;
+ _numLinks_Error = false;
+ _pad_Error = false;
+ _symLink_Error = false;
+ _error = k_ErrorType_OK;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
+
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ UString res;
+ bool needConvert = true;
+ #ifdef _WIN32
+ // if (
+ ConvertUTF8ToUnicode(item.Name, res);
+ // )
+ needConvert = false;
+ #endif
+ if (needConvert)
+ res = MultiByteToUnicodeString(item.Name, CP_OEMCP);
+ prop = NItemName::GetOsPath(res);
+ break;
+ }
+ case kpidIsDir: prop = item.IsDir(); break;
+
+ case kpidSize:
+ prop = (UInt64)_items[item.MainIndex_ForInode].Size;
+ break;
+
+ case kpidPackSize:
+ prop = (UInt64)item.GetPackSize();
+ break;
+
+ case kpidMTime:
+ {
+ if (item.MTime != 0)
+ PropVariant_SetFrom_UnixTime(prop, item.MTime);
+ break;
+ }
+ case kpidPosixAttrib: prop = item.Mode; break;
+ case kpidINode: prop = item.inode; break;
+ case kpidStreamId:
+ if (!item.IsDir())
+ prop = (UInt32)item.MainIndex_ForInode;
+ break;
+ case kpidDevMajor: prop = (UInt32)item.DevMajor; break;
+ case kpidDevMinor: prop = (UInt32)item.DevMinor; break;
+
+ case kpidUserId: prop = item.UID; break;
+ case kpidGroupId: prop = item.GID; break;
+
+ case kpidSymLink:
+ if (item.Is_SymLink() && item.Data.Size() != 0)
+ {
+ AString s;
+ s.SetFrom_CalcLen((const char *)(const void *)(const Byte *)item.Data, (unsigned)item.Data.Size());
+ if (s.Len() == item.Data.Size())
+ {
+ UString u;
+ bool needConvert = true;
+ #ifdef _WIN32
+ // if (
+ ConvertUTF8ToUnicode(item.Name, u);
+ // )
+ needConvert = false;
+ #endif
+ if (needConvert)
+ u = MultiByteToUnicodeString(s, CP_OEMCP);
+ prop = u;
+ }
+ }
+ break;
+
+ case kpidLinks: prop = item.NumLinks; break;
+ case kpidDeviceMajor:
+ // if (item.RDevMajor != 0)
+ prop = (UInt32)item.RDevMajor;
+ break;
+ case kpidDeviceMinor:
+ // if (item.RDevMinor != 0)
+ prop = (UInt32)item.RDevMinor;
+ break;
+ case kpidChecksum:
+ if (item.IsCrcFormat())
+ prop = item.ChkSum;
+ break;
+ case kpidOffset: prop = item.GetDataPosition(); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ COutStreamWithSum
+ , ISequentialOutStream
+)
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+ UInt32 _crc;
+ bool _calculate;
+public:
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init(bool calculate = true)
+ {
+ _size = 0;
+ _calculate = calculate;
+ _crc = 0;
+ }
+ void EnableCalc(bool calculate) { _calculate = calculate; }
+ void InitCRC() { _crc = 0; }
+ UInt64 GetSize() const { return _size; }
+ UInt32 GetCRC() const { return _crc; }
+};
+
+Z7_COM7F_IMF(COutStreamWithSum::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ HRESULT result = S_OK;
+ if (_stream)
+ result = _stream->Write(data, size, &size);
+ if (_calculate)
+ {
+ UInt32 crc = 0;
+ for (UInt32 i = 0; i < size; i++)
+ crc += (UInt32)(((const Byte *)data)[i]);
+ _crc += crc;
+ }
+ if (processedSize)
+ *processedSize = size;
+ return result;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CItem &item2 = _items[index];
+ const CItem &item = _items[item2.MainIndex_ForInode];
+ totalSize += item.Size;
+ }
+ RINOK(extractCallback->SetTotal(totalSize))
+
+ 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);
+
+ COutStreamWithSum *outStreamSumSpec = new COutStreamWithSum;
+ CMyComPtr<ISequentialOutStream> outStreamSum(outStreamSumSpec);
+
+ UInt64 total_PackSize = 0;
+ UInt64 total_UnpackSize = 0;
+
+ for (i = 0;; i++)
+ {
+ lps->InSize = total_PackSize;
+ lps->OutSize = total_UnpackSize;
+ RINOK(lps->SetCur())
+ if (i >= numItems)
+ break;
+ CMyComPtr<ISequentialOutStream> outStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CItem &item2 = _items[index];
+ const CItem &item = _items[item2.MainIndex_ForInode];
+ RINOK(extractCallback->GetStream(index, &outStream, askMode))
+
+ total_PackSize += item2.GetPackSize();
+ total_UnpackSize += item.Size;
+
+ if (item2.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+ if (!testMode && !outStream)
+ continue;
+ outStreamSumSpec->Init(item.IsCrcFormat());
+ outStreamSumSpec->SetStream(outStream);
+ outStream.Release();
+
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(InStream_SeekSet(_stream, item.GetDataPosition()))
+ streamSpec->Init(item.Size);
+ RINOK(copyCoder->Code(inStream, outStreamSum, NULL, NULL, progress))
+ outStreamSumSpec->ReleaseStream();
+ Int32 res = NExtract::NOperationResult::kDataError;
+ if (copyCoderSpec->TotalSize == item.Size)
+ {
+ res = NExtract::NOperationResult::kOK;
+ if (item.IsCrcFormat() && item.ChkSum != outStreamSumSpec->GetCRC())
+ res = NExtract::NOperationResult::kCRCError;
+ }
+ RINOK(extractCallback->SetOperationResult(res))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ const CItem &item2 = _items[index];
+ const CItem &item = _items[item2.MainIndex_ForInode];
+ return CreateLimitedInStream(_stream, item.GetDataPosition(), item.Size, stream);
+ COM_TRY_END
+}
+
+static const Byte k_Signature[] = {
+ 5, '0', '7', '0', '7', '0',
+ 2, kMagicBin0, kMagicBin1,
+ 2, kMagicBin1, kMagicBin0 };
+
+REGISTER_ARC_I(
+ "Cpio", "cpio", NULL, 0xED,
+ k_Signature,
+ 0,
+ NArcInfoFlags::kMultiSignature,
+ IsArc_Cpio)
+
+}}
diff --git a/CPP/7zip/Archive/CramfsHandler.cpp b/CPP/7zip/Archive/CramfsHandler.cpp
new file mode 100644
index 0000000..fd83f71
--- /dev/null
+++ b/CPP/7zip/Archive/CramfsHandler.cpp
@@ -0,0 +1,784 @@
+// CramfsHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+#include "../../../C/Alloc.h"
+#include "../../../C/CpuArch.h"
+#include "../../../C/LzmaDec.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/MyLinux.h"
+#include "../../Common/StringConvert.h"
+
+#include "../../Windows/PropVariantUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+#include "../Compress/ZlibDecoder.h"
+
+namespace NArchive {
+namespace NCramfs {
+
+static const Byte kSignature[] =
+ { 'C','o','m','p','r','e','s','s','e','d',' ','R','O','M','F','S' };
+
+static const UInt32 kArcSizeMax = (256 + 16) << 20;
+static const UInt32 kNumFilesMax = (1 << 19);
+static const unsigned kNumDirLevelsMax = (1 << 8);
+
+static const UInt32 kHeaderSize = 0x40;
+static const unsigned kHeaderNameSize = 16;
+static const UInt32 kNodeSize = 12;
+
+static const UInt32 kFlag_FsVer2 = (1 << 0);
+
+static const unsigned k_Flags_BlockSize_Shift = 11;
+static const unsigned k_Flags_BlockSize_Mask = 7;
+static const unsigned k_Flags_Method_Shift = 14;
+static const unsigned k_Flags_Method_Mask = 3;
+
+/*
+ There is possible collision in flags:
+ - Original CramFS writes 0 in method field. But it uses ZLIB.
+ - Modified CramFS writes 0 in method field for "NONE" compression?
+ How to solve that collision?
+*/
+
+#define k_Flags_Method_NONE 0
+#define k_Flags_Method_ZLIB 1
+#define k_Flags_Method_LZMA 2
+
+static const char * const k_Methods[] =
+{
+ "Copy"
+ , "ZLIB"
+ , "LZMA"
+ , "Unknown"
+};
+
+static const CUInt32PCharPair k_Flags[] =
+{
+ { 0, "Ver2" },
+ { 1, "SortedDirs" },
+ { 8, "Holes" },
+ { 9, "WrongSignature" },
+ { 10, "ShiftedRootOffset" }
+};
+
+static const unsigned kBlockSizeLog = 12;
+
+/*
+struct CNode
+{
+ UInt16 Mode;
+ UInt16 Uid;
+ UInt32 Size;
+ Byte Gid;
+ UInt32 NameLen;
+ UInt32 Offset;
+
+ void Parse(const Byte *p)
+ {
+ Mode = GetUi16(p);
+ Uid = GetUi16(p + 2);
+ Size = Get32(p + 4) & 0xFFFFFF;
+ Gid = p[7];
+ NameLen = p[8] & 0x3F;
+ Offset = Get32(p + 8) >> 6;
+ }
+};
+*/
+
+#define Get32(p) (be ? GetBe32(p) : GetUi32(p))
+
+static UInt32 GetMode(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); }
+static bool IsDir(const Byte *p, bool be) { return MY_LIN_S_ISDIR(GetMode(p, be)); }
+
+static UInt32 GetSize(const Byte *p, bool be)
+{
+ if (be)
+ return GetBe32(p + 4) >> 8;
+ else
+ return GetUi32(p + 4) & 0xFFFFFF;
+}
+
+static UInt32 GetNameLen(const Byte *p, bool be)
+{
+ if (be)
+ return (p[8] & 0xFC);
+ else
+ return ((UInt32)p[8] & (UInt32)0x3F) << 2;
+}
+
+static UInt32 GetOffset(const Byte *p, bool be)
+{
+ if (be)
+ return (GetBe32(p + 8) & 0x03FFFFFF) << 2;
+ else
+ return GetUi32(p + 8) >> 6 << 2;
+}
+
+struct CItem
+{
+ UInt32 Offset;
+ int Parent;
+};
+
+struct CHeader
+{
+ bool be;
+ UInt32 Size;
+ UInt32 Flags;
+ // UInt32 Future;
+ UInt32 Crc;
+ // UInt32 Edition;
+ UInt32 NumBlocks;
+ UInt32 NumFiles;
+ char Name[kHeaderNameSize];
+
+ bool Parse(const Byte *p)
+ {
+ if (memcmp(p + 16, kSignature, Z7_ARRAY_SIZE(kSignature)) != 0)
+ return false;
+ switch (GetUi32(p))
+ {
+ case 0x28CD3D45: be = false; break;
+ case 0x453DCD28: be = true; break;
+ default: return false;
+ }
+ Size = Get32(p + 4);
+ Flags = Get32(p + 8);
+ // Future = Get32(p + 0xC);
+ Crc = Get32(p + 0x20);
+ // Edition = Get32(p + 0x24);
+ NumBlocks = Get32(p + 0x28);
+ NumFiles = Get32(p + 0x2C);
+ memcpy(Name, p + 0x30, kHeaderNameSize);
+ return true;
+ }
+
+ bool IsVer2() const { return (Flags & kFlag_FsVer2) != 0; }
+ unsigned GetBlockSizeShift() const { return (unsigned)(Flags >> k_Flags_BlockSize_Shift) & k_Flags_BlockSize_Mask; }
+ unsigned GetMethod() const { return (unsigned)(Flags >> k_Flags_Method_Shift) & k_Flags_Method_Mask; }
+};
+
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IInArchiveGetStream
+)
+ CRecordVector<CItem> _items;
+ CMyComPtr<IInStream> _stream;
+ Byte *_data;
+ UInt32 _size;
+ UInt32 _headersSize;
+
+ UInt32 _errorFlags;
+ bool _isArc;
+
+ CHeader _h;
+ UInt32 _phySize;
+
+ unsigned _method;
+ unsigned _blockSizeLog;
+
+ // Current file
+
+ NCompress::NZlib::CDecoder *_zlibDecoderSpec;
+ CMyComPtr<ICompressCoder> _zlibDecoder;
+
+ CBufInStream *_inStreamSpec;
+ CMyComPtr<ISequentialInStream> _inStream;
+
+ CBufPtrSeqOutStream *_outStreamSpec;
+ CMyComPtr<ISequentialOutStream> _outStream;
+
+ UInt32 _curBlocksOffset;
+ UInt32 _curNumBlocks;
+
+ HRESULT OpenDir(int parent, UInt32 baseOffsetBase, unsigned level);
+ HRESULT Open2(IInStream *inStream);
+ AString GetPath(unsigned index) const;
+ bool GetPackSize(unsigned index, UInt32 &res) const;
+ void Free();
+
+ UInt32 GetNumBlocks(UInt32 size) const
+ {
+ return (size + ((UInt32)1 << _blockSizeLog) - 1) >> _blockSizeLog;
+ }
+
+ void UpdatePhySize(UInt32 s)
+ {
+ if (_phySize < s)
+ _phySize = s;
+ }
+
+public:
+ CHandler(): _data(NULL) {}
+ ~CHandler() { Free(); }
+ HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidPosixAttrib
+ // kpidOffset
+};
+
+static const Byte kArcProps[] =
+{
+ kpidVolumeName,
+ kpidBigEndian,
+ kpidCharacts,
+ kpidClusterSize,
+ kpidMethod,
+ kpidHeadersSize,
+ kpidNumSubFiles,
+ kpidNumBlocks
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+HRESULT CHandler::OpenDir(int parent, UInt32 baseOffset, unsigned level)
+{
+ const Byte *p = _data + baseOffset;
+ bool be = _h.be;
+ if (!IsDir(p, be))
+ return S_OK;
+ UInt32 offset = GetOffset(p, be);
+ UInt32 size = GetSize(p, be);
+ if (offset == 0 && size == 0)
+ return S_OK;
+ UInt32 end = offset + size;
+ if (offset < kHeaderSize || end > _size || level > kNumDirLevelsMax)
+ return S_FALSE;
+ UpdatePhySize(end);
+ if (end > _headersSize)
+ _headersSize = end;
+
+ unsigned startIndex = _items.Size();
+
+ while (size != 0)
+ {
+ if (size < kNodeSize || (UInt32)_items.Size() >= kNumFilesMax)
+ return S_FALSE;
+ CItem item;
+ item.Parent = parent;
+ item.Offset = offset;
+ _items.Add(item);
+ UInt32 nodeLen = kNodeSize + GetNameLen(_data + offset, be);
+ if (size < nodeLen)
+ return S_FALSE;
+ offset += nodeLen;
+ size -= nodeLen;
+ }
+
+ unsigned endIndex = _items.Size();
+ for (unsigned i = startIndex; i < endIndex; i++)
+ {
+ RINOK(OpenDir((int)i, _items[i].Offset, level + 1))
+ }
+ return S_OK;
+}
+
+HRESULT CHandler::Open2(IInStream *inStream)
+{
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize))
+ if (!_h.Parse(buf))
+ return S_FALSE;
+ _method = k_Flags_Method_ZLIB;
+ _blockSizeLog = kBlockSizeLog;
+ _phySize = kHeaderSize;
+ if (_h.IsVer2())
+ {
+ _method = _h.GetMethod();
+ // FIT IT. Now we don't know correct way to work with collision in method field.
+ if (_method == k_Flags_Method_NONE)
+ _method = k_Flags_Method_ZLIB;
+ _blockSizeLog = kBlockSizeLog + _h.GetBlockSizeShift();
+ if (_h.Size < kHeaderSize || _h.Size > kArcSizeMax || _h.NumFiles > kNumFilesMax)
+ return S_FALSE;
+ _phySize = _h.Size;
+ }
+ else
+ {
+ UInt64 size;
+ RINOK(InStream_GetSize_SeekToEnd(inStream, size))
+ if (size > kArcSizeMax)
+ size = kArcSizeMax;
+ _h.Size = (UInt32)size;
+ RINOK(InStream_SeekSet(inStream, kHeaderSize))
+ }
+ _data = (Byte *)MidAlloc(_h.Size);
+ if (!_data)
+ return E_OUTOFMEMORY;
+ memcpy(_data, buf, kHeaderSize);
+ size_t processed = _h.Size - kHeaderSize;
+ RINOK(ReadStream(inStream, _data + kHeaderSize, &processed))
+ if (processed < kNodeSize)
+ return S_FALSE;
+ _size = kHeaderSize + (UInt32)processed;
+ if (_h.IsVer2())
+ {
+ if (_size != _h.Size)
+ _errorFlags = kpv_ErrorFlags_UnexpectedEnd;
+ else
+ {
+ SetUi32(_data + 0x20, 0)
+ if (CrcCalc(_data, _h.Size) != _h.Crc)
+ {
+ _errorFlags = kpv_ErrorFlags_HeadersError;
+ // _errorMessage = "CRC error";
+ }
+ }
+ if (_h.NumFiles >= 1)
+ _items.ClearAndReserve(_h.NumFiles - 1);
+ }
+
+ RINOK(OpenDir(-1, kHeaderSize, 0))
+
+ if (!_h.IsVer2())
+ {
+ FOR_VECTOR (i, _items)
+ {
+ const CItem &item = _items[i];
+ const Byte *p = _data + item.Offset;
+ bool be = _h.be;
+ if (IsDir(p, be))
+ continue;
+ UInt32 offset = GetOffset(p, be);
+ if (offset < kHeaderSize)
+ continue;
+ UInt32 numBlocks = GetNumBlocks(GetSize(p, be));
+ if (numBlocks == 0)
+ continue;
+ UInt32 start = offset + numBlocks * 4;
+ if (start > _size)
+ continue;
+ UInt32 end = Get32(_data + start - 4);
+ if (end >= start)
+ UpdatePhySize(end);
+ }
+
+ // Read tailing zeros. Most cramfs archives use 4096-bytes aligned zeros
+ const UInt32 kTailSize_MAX = 1 << 12;
+ UInt32 endPos = (_phySize + kTailSize_MAX - 1) & ~(kTailSize_MAX - 1);
+ if (endPos > _size)
+ endPos = _size;
+ UInt32 pos;
+ for (pos = _phySize; pos < endPos && _data[pos] == 0; pos++);
+ if (pos == endPos)
+ _phySize = endPos;
+ }
+ return S_OK;
+}
+
+AString CHandler::GetPath(unsigned index) const
+{
+ unsigned len = 0;
+ unsigned indexMem = index;
+ for (;;)
+ {
+ const CItem &item = _items[index];
+ const Byte *p = _data + item.Offset;
+ unsigned size = GetNameLen(p, _h.be);
+ p += kNodeSize;
+ unsigned i;
+ for (i = 0; i < size && p[i]; i++);
+ len += i + 1;
+ index = (unsigned)item.Parent;
+ if (item.Parent < 0)
+ break;
+ }
+ len--;
+
+ AString path;
+ char *dest = path.GetBuf_SetEnd(len) + len;
+ index = indexMem;
+ for (;;)
+ {
+ const CItem &item = _items[index];
+ const Byte *p = _data + item.Offset;
+ unsigned size = GetNameLen(p, _h.be);
+ p += kNodeSize;
+ unsigned i;
+ for (i = 0; i < size && p[i]; i++);
+ dest -= i;
+ memcpy(dest, p, i);
+ index = (unsigned)item.Parent;
+ if (item.Parent < 0)
+ break;
+ *(--dest) = CHAR_PATH_SEPARATOR;
+ }
+ return path;
+}
+
+bool CHandler::GetPackSize(unsigned index, UInt32 &res) const
+{
+ res = 0;
+ const CItem &item = _items[index];
+ const Byte *p = _data + item.Offset;
+ const bool be = _h.be;
+ const UInt32 offset = GetOffset(p, be);
+ if (offset < kHeaderSize)
+ return false;
+ const UInt32 numBlocks = GetNumBlocks(GetSize(p, be));
+ if (numBlocks == 0)
+ return true;
+ const UInt32 start = offset + numBlocks * 4;
+ if (start > _size)
+ return false;
+ const UInt32 end = Get32(_data + start - 4);
+ if (end < start)
+ return false;
+ res = end - start;
+ return true;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* callback */))
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ RINOK(Open2(stream))
+ _isArc = true;
+ _stream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+void CHandler::Free()
+{
+ MidFree(_data);
+ _data = NULL;
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _isArc = false;
+ _phySize = 0;
+ _errorFlags = 0;
+ _headersSize = 0;
+ _items.Clear();
+ _stream.Release();
+ Free();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidVolumeName:
+ {
+ char dest[kHeaderNameSize + 4];
+ memcpy(dest, _h.Name, kHeaderNameSize);
+ dest[kHeaderNameSize] = 0;
+ prop = dest;
+ break;
+ }
+ case kpidBigEndian: prop = _h.be; break;
+ case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break;
+ case kpidMethod: prop = k_Methods[_method]; break;
+ case kpidClusterSize: prop = (UInt32)1 << _blockSizeLog; break;
+ case kpidNumBlocks: if (_h.IsVer2()) prop = _h.NumBlocks; break;
+ case kpidNumSubFiles: if (_h.IsVer2()) prop = _h.NumFiles; break;
+ case kpidPhySize: prop = _phySize; break;
+ case kpidHeadersSize: prop = _headersSize; break;
+ case kpidErrorFlags:
+ {
+ UInt32 v = _errorFlags;
+ if (!_isArc)
+ v |= kpv_ErrorFlags_IsNotArc;
+ prop = v;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
+ const Byte *p = _data + item.Offset;
+ bool be = _h.be;
+ bool isDir = IsDir(p, be);
+ switch (propID)
+ {
+ case kpidPath: prop = MultiByteToUnicodeString(GetPath(index), CP_OEMCP); break;
+ case kpidIsDir: prop = isDir; break;
+ // case kpidOffset: prop = (UInt32)GetOffset(p, be); break;
+ case kpidSize: if (!isDir) prop = GetSize(p, be); break;
+ case kpidPackSize:
+ if (!isDir)
+ {
+ UInt32 size;
+ if (GetPackSize(index, size))
+ prop = size;
+ }
+ break;
+ case kpidPosixAttrib: prop = (UInt32)GetMode(p, be); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CCramfsInStream: public CCachedInStream
+{
+ HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) Z7_override;
+public:
+ CHandler *Handler;
+};
+
+HRESULT CCramfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
+{
+ return Handler->ReadBlock(blockIndex, dest, blockSize);
+}
+
+HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
+{
+ if (_method == k_Flags_Method_ZLIB)
+ {
+ if (!_zlibDecoder)
+ {
+ _zlibDecoderSpec = new NCompress::NZlib::CDecoder();
+ _zlibDecoder = _zlibDecoderSpec;
+ }
+ }
+ else
+ {
+ if (_method != k_Flags_Method_LZMA)
+ {
+ // probably we must support no-compression archives here.
+ return E_NOTIMPL;
+ }
+ }
+
+ const bool be = _h.be;
+ const Byte *p2 = _data + (_curBlocksOffset + (UInt32)blockIndex * 4);
+ const UInt32 start = (blockIndex == 0 ? _curBlocksOffset + _curNumBlocks * 4: Get32(p2 - 4));
+ const UInt32 end = Get32(p2);
+ if (end < start || end > _size)
+ return S_FALSE;
+ const UInt32 inSize = end - start;
+
+ if (_method == k_Flags_Method_LZMA)
+ {
+ const unsigned kLzmaHeaderSize = LZMA_PROPS_SIZE + 4;
+ if (inSize < kLzmaHeaderSize)
+ return S_FALSE;
+ const Byte *p = _data + start;
+ UInt32 destSize32 = GetUi32(p + LZMA_PROPS_SIZE);
+ if (destSize32 > blockSize)
+ return S_FALSE;
+ SizeT destLen = destSize32;
+ SizeT srcLen = inSize - kLzmaHeaderSize;
+ ELzmaStatus status;
+ SRes res = LzmaDecode(dest, &destLen, p + kLzmaHeaderSize, &srcLen,
+ p, LZMA_PROPS_SIZE, LZMA_FINISH_END, &status, &g_Alloc);
+ if (res != SZ_OK
+ || (status != LZMA_STATUS_FINISHED_WITH_MARK &&
+ status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
+ || destLen != destSize32
+ || srcLen != inSize - kLzmaHeaderSize)
+ return S_FALSE;
+ return S_OK;
+ }
+
+ if (!_inStream)
+ {
+ _inStreamSpec = new CBufInStream();
+ _inStream = _inStreamSpec;
+ }
+ if (!_outStream)
+ {
+ _outStreamSpec = new CBufPtrSeqOutStream();
+ _outStream = _outStreamSpec;
+ }
+ _inStreamSpec->Init(_data + start, inSize);
+ _outStreamSpec->Init(dest, blockSize);
+ RINOK(_zlibDecoder->Code(_inStream, _outStream, NULL, NULL, NULL))
+ return (inSize == _zlibDecoderSpec->GetInputProcessedSize() &&
+ _outStreamSpec->GetPos() == blockSize) ? S_OK : S_FALSE;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ bool be = _h.be;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const Byte *p = _data + _items[allFilesMode ? i : indices[i]].Offset;
+ if (!IsDir(p, be))
+ totalSize += GetSize(p, be);
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur())
+ CMyComPtr<ISequentialOutStream> outStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _items[index];
+ RINOK(extractCallback->GetStream(index, &outStream, askMode))
+ const Byte *p = _data + item.Offset;
+
+ if (IsDir(p, be))
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+ UInt32 curSize = GetSize(p, be);
+ totalSize += curSize;
+ UInt32 packSize;
+ if (GetPackSize(index, packSize))
+ totalPackSize += packSize;
+
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode))
+
+ UInt32 offset = GetOffset(p, be);
+ if (offset < kHeaderSize)
+ curSize = 0;
+
+ int res = NExtract::NOperationResult::kDataError;
+ {
+ CMyComPtr<ISequentialInStream> inSeqStream;
+ HRESULT hres = GetStream(index, &inSeqStream);
+ if (hres == E_OUTOFMEMORY)
+ return E_OUTOFMEMORY;
+ if (hres == S_FALSE || !inSeqStream)
+ res = NExtract::NOperationResult::kUnsupportedMethod;
+ else
+ {
+ RINOK(hres)
+ {
+ hres = copyCoder->Code(inSeqStream, outStream, NULL, NULL, progress);
+ if (hres == S_OK)
+ {
+ if (copyCoderSpec->TotalSize == curSize)
+ res = NExtract::NOperationResult::kOK;
+ }
+ else if (hres == E_NOTIMPL)
+ res = NExtract::NOperationResult::kUnsupportedMethod;
+ else if (hres != S_FALSE)
+ return hres;
+ }
+ }
+ }
+ RINOK(extractCallback->SetOperationResult(res))
+ }
+
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+
+ const CItem &item = _items[index];
+ const Byte *p = _data + item.Offset;
+
+ bool be = _h.be;
+ if (IsDir(p, be))
+ return E_FAIL;
+
+ UInt32 size = GetSize(p, be);
+ UInt32 numBlocks = GetNumBlocks(size);
+ UInt32 offset = GetOffset(p, be);
+ if (offset < kHeaderSize)
+ {
+ if (offset != 0)
+ return S_FALSE;
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ streamSpec->Init(NULL, 0);
+ *stream = streamTemp.Detach();
+ return S_OK;
+ }
+
+ if (offset + numBlocks * 4 > _size)
+ return S_FALSE;
+ UInt32 prev = offset;
+ for (UInt32 i = 0; i < numBlocks; i++)
+ {
+ UInt32 next = Get32(_data + offset + i * 4);
+ if (next < prev || next > _size)
+ return S_FALSE;
+ prev = next;
+ }
+
+ CCramfsInStream *streamSpec = new CCramfsInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ _curNumBlocks = numBlocks;
+ _curBlocksOffset = offset;
+ streamSpec->Handler = this;
+ if (!streamSpec->Alloc(_blockSizeLog, 21 - _blockSizeLog))
+ return E_OUTOFMEMORY;
+ streamSpec->Init(size);
+ *stream = streamTemp.Detach();
+
+ return S_OK;
+ COM_TRY_END
+}
+
+REGISTER_ARC_I(
+ "CramFS", "cramfs", NULL, 0xD3,
+ kSignature,
+ 16,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/DeflateProps.cpp b/CPP/7zip/Archive/DeflateProps.cpp
new file mode 100644
index 0000000..ca3dc6f
--- /dev/null
+++ b/CPP/7zip/Archive/DeflateProps.cpp
@@ -0,0 +1,3 @@
+// DeflateProps.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Archive/DeflateProps.h b/CPP/7zip/Archive/DeflateProps.h
new file mode 100644
index 0000000..666fb39
--- /dev/null
+++ b/CPP/7zip/Archive/DeflateProps.h
@@ -0,0 +1,6 @@
+// DeflateProps.h
+
+#ifndef ZIP7_INC_DEFLATE_PROPS_H
+#define ZIP7_INC_DEFLATE_PROPS_H
+
+#endif
diff --git a/CPP/7zip/Archive/DllExports.cpp b/CPP/7zip/Archive/DllExports.cpp
new file mode 100644
index 0000000..9def208
--- /dev/null
+++ b/CPP/7zip/Archive/DllExports.cpp
@@ -0,0 +1,96 @@
+// DLLExports.cpp
+
+#include "StdAfx.h"
+
+#if defined(Z7_LARGE_PAGES)
+#include "../../../C/Alloc.h"
+#endif
+
+#include "../../Common/MyWindows.h"
+#include "../../Common/MyInitGuid.h"
+
+#include "../../Common/ComTry.h"
+
+#include "../../Windows/NtCheck.h"
+#include "../../Windows/PropVariant.h"
+
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+#include "../Common/CreateCoder.h"
+
+#include "IArchive.h"
+
+static
+HINSTANCE g_hInstance;
+
+#define NT_CHECK_FAIL_ACTION return FALSE;
+
+extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/);
+extern "C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
+{
+ if (dwReason == DLL_PROCESS_ATTACH)
+ {
+ g_hInstance = hInstance;
+ NT_CHECK
+ }
+ return TRUE;
+}
+
+Z7_DEFINE_GUID(CLSID_CArchiveHandler,
+ k_7zip_GUID_Data1,
+ k_7zip_GUID_Data2,
+ k_7zip_GUID_Data3_Common,
+ 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
+
+STDAPI CreateArchiver(const GUID *classID, const GUID *iid, void **outObject);
+
+STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
+{
+ return CreateArchiver(clsid, iid, outObject);
+}
+
+STDAPI SetLargePageMode()
+{
+ #if defined(Z7_LARGE_PAGES)
+ SetLargePageSize();
+ #endif
+ return S_OK;
+}
+
+extern bool g_CaseSensitive;
+
+STDAPI SetCaseSensitive(Int32 caseSensitive)
+{
+ g_CaseSensitive = (caseSensitive != 0);
+ return S_OK;
+}
+
+#ifdef Z7_EXTERNAL_CODECS
+
+CExternalCodecs g_ExternalCodecs;
+
+STDAPI SetCodecs(ICompressCodecsInfo *compressCodecsInfo)
+{
+ COM_TRY_BEGIN
+
+ // OutputDebugStringA(compressCodecsInfo ? "SetCodecs" : "SetCodecs NULL");
+ if (compressCodecsInfo)
+ {
+ g_ExternalCodecs.GetCodecs = compressCodecsInfo;
+ return g_ExternalCodecs.Load();
+ }
+ g_ExternalCodecs.ClearAndRelease();
+ return S_OK;
+
+ COM_TRY_END
+}
+
+#else
+
+STDAPI SetCodecs(ICompressCodecsInfo *)
+{
+ return S_OK;
+}
+
+#endif
diff --git a/CPP/7zip/Archive/DllExports2.cpp b/CPP/7zip/Archive/DllExports2.cpp
index c43e72a..ae8d8ac 100644
--- a/CPP/7zip/Archive/DllExports2.cpp
+++ b/CPP/7zip/Archive/DllExports2.cpp
@@ -1,122 +1,175 @@
-// DLLExports2.cpp
-
-#include "StdAfx.h"
-
-#include "../../Common/MyWindows.h"
-
-#include "../../Common/MyInitGuid.h"
-
-#if defined(_7ZIP_LARGE_PAGES)
-#include "../../../C/Alloc.h"
-#endif
-
-#include "../../Common/ComTry.h"
-
-#include "../../Windows/NtCheck.h"
-#include "../../Windows/PropVariant.h"
-
-#include "../ICoder.h"
-#include "../IPassword.h"
-
-#include "../Common/CreateCoder.h"
-
-#include "IArchive.h"
-
-HINSTANCE g_hInstance;
-
-#define NT_CHECK_FAIL_ACTION return FALSE;
-
-#ifdef _WIN32
-extern "C"
-BOOL WINAPI DllMain(
- #ifdef UNDER_CE
- HANDLE
- #else
- HINSTANCE
- #endif
- hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
-{
- if (dwReason == DLL_PROCESS_ATTACH)
- {
- // OutputDebugStringA("7z.dll DLL_PROCESS_ATTACH");
- g_hInstance = (HINSTANCE)hInstance;
- NT_CHECK;
- }
- /*
- if (dwReason == DLL_PROCESS_DETACH)
- {
- OutputDebugStringA("7z.dll DLL_PROCESS_DETACH");
- }
- */
- return TRUE;
-}
-#endif
-
-DEFINE_GUID(CLSID_CArchiveHandler,
- k_7zip_GUID_Data1,
- k_7zip_GUID_Data2,
- k_7zip_GUID_Data3_Common,
- 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
-
-STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject);
-STDAPI CreateHasher(const GUID *clsid, IHasher **hasher);
-STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject);
-
-STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
-{
- // COM_TRY_BEGIN
- *outObject = 0;
- if (*iid == IID_ICompressCoder ||
- *iid == IID_ICompressCoder2 ||
- *iid == IID_ICompressFilter)
- return CreateCoder(clsid, iid, outObject);
- if (*iid == IID_IHasher)
- return CreateHasher(clsid, (IHasher **)outObject);
- return CreateArchiver(clsid, iid, outObject);
- // COM_TRY_END
-}
-
-STDAPI SetLargePageMode()
-{
- #if defined(_7ZIP_LARGE_PAGES)
- SetLargePageSize();
- #endif
- return S_OK;
-}
-
-extern bool g_CaseSensitive;
-
-STDAPI SetCaseSensitive(Int32 caseSensitive)
-{
- g_CaseSensitive = (caseSensitive != 0);
- return S_OK;
-}
-
-#ifdef EXTERNAL_CODECS
-
-CExternalCodecs g_ExternalCodecs;
-
-STDAPI SetCodecs(ICompressCodecsInfo *compressCodecsInfo)
-{
- COM_TRY_BEGIN
-
- // OutputDebugStringA(compressCodecsInfo ? "SetCodecs" : "SetCodecs NULL");
- if (compressCodecsInfo)
- {
- g_ExternalCodecs.GetCodecs = compressCodecsInfo;
- return g_ExternalCodecs.Load();
- }
- g_ExternalCodecs.ClearAndRelease();
- return S_OK;
-
- COM_TRY_END
-}
-
-#else
-
-STDAPI SetCodecs(ICompressCodecsInfo *)
-{
- return S_OK;
-}
-
-#endif
+// DLLExports2.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyWindows.h"
+#include "../../Common/MyInitGuid.h"
+
+#if defined(Z7_LARGE_PAGES)
+#include "../../../C/Alloc.h"
+#endif
+
+#include "../../Common/ComTry.h"
+
+#include "../../Windows/NtCheck.h"
+#include "../../Windows/PropVariant.h"
+
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+#include "../Common/CreateCoder.h"
+
+#include "IArchive.h"
+
+
+#ifdef _WIN32
+
+#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE)
+#define NT_CHECK_FAIL_ACTION return FALSE;
+#endif
+
+static
+HINSTANCE g_hInstance;
+
+extern "C"
+BOOL WINAPI DllMain(
+ #ifdef UNDER_CE
+ HANDLE
+ #else
+ HINSTANCE
+ #endif
+ hInstance, DWORD dwReason, LPVOID /*lpReserved*/);
+
+extern "C"
+BOOL WINAPI DllMain(
+ #ifdef UNDER_CE
+ HANDLE
+ #else
+ HINSTANCE
+ #endif
+ hInstance, DWORD dwReason, LPVOID /*lpReserved*/)
+{
+ if (dwReason == DLL_PROCESS_ATTACH)
+ {
+ // OutputDebugStringA("7z.dll DLL_PROCESS_ATTACH");
+ g_hInstance = (HINSTANCE)hInstance;
+ NT_CHECK
+ }
+ /*
+ if (dwReason == DLL_PROCESS_DETACH)
+ {
+ OutputDebugStringA("7z.dll DLL_PROCESS_DETACH");
+ }
+ */
+ return TRUE;
+}
+
+#else // _WIN32
+
+#include "../../Common/StringConvert.h"
+// #include <stdio.h>
+
+// STDAPI LibStartup();
+static __attribute__((constructor)) void Init_ForceToUTF8();
+static __attribute__((constructor)) void Init_ForceToUTF8()
+{
+ g_ForceToUTF8 = IsNativeUTF8();
+ // printf("\nDLLExports2.cpp::Init_ForceToUTF8 =%d\n", g_ForceToUTF8 ? 1 : 0);
+}
+
+#endif // _WIN32
+
+
+Z7_DEFINE_GUID(CLSID_CArchiveHandler,
+ k_7zip_GUID_Data1,
+ k_7zip_GUID_Data2,
+ k_7zip_GUID_Data3_Common,
+ 0x10, 0x00, 0x00, 0x01, 0x10, 0x00, 0x00, 0x00);
+
+STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject);
+STDAPI CreateHasher(const GUID *clsid, IHasher **hasher);
+STDAPI CreateArchiver(const GUID *clsid, const GUID *iid, void **outObject);
+
+STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject);
+STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
+{
+ // COM_TRY_BEGIN
+ *outObject = NULL;
+ if (*iid == IID_ICompressCoder ||
+ *iid == IID_ICompressCoder2 ||
+ *iid == IID_ICompressFilter)
+ return CreateCoder(clsid, iid, outObject);
+ if (*iid == IID_IHasher)
+ return CreateHasher(clsid, (IHasher **)outObject);
+ return CreateArchiver(clsid, iid, outObject);
+ // COM_TRY_END
+}
+
+STDAPI SetLargePageMode();
+STDAPI SetLargePageMode()
+{
+ #if defined(Z7_LARGE_PAGES)
+ #ifdef _WIN32
+ SetLargePageSize();
+ #endif
+ #endif
+ return S_OK;
+}
+
+extern bool g_CaseSensitive;
+
+STDAPI SetCaseSensitive(Int32 caseSensitive);
+STDAPI SetCaseSensitive(Int32 caseSensitive)
+{
+ g_CaseSensitive = (caseSensitive != 0);
+ return S_OK;
+}
+
+/*
+UInt32 g_ClientVersion;
+STDAPI SetClientVersion(UInt32 version);
+STDAPI SetClientVersion(UInt32 version)
+{
+ g_ClientVersion = version;
+ return S_OK;
+}
+*/
+
+/*
+STDAPI SetProperty(Int32 id, const PROPVARIANT *value);
+STDAPI SetProperty(Int32 id, const PROPVARIANT *value)
+{
+ return S_OK;
+}
+*/
+
+#ifdef Z7_EXTERNAL_CODECS
+
+CExternalCodecs g_ExternalCodecs;
+
+STDAPI SetCodecs(ICompressCodecsInfo *compressCodecsInfo);
+STDAPI SetCodecs(ICompressCodecsInfo *compressCodecsInfo)
+{
+ COM_TRY_BEGIN
+
+ // OutputDebugStringA(compressCodecsInfo ? "SetCodecs" : "SetCodecs NULL");
+ if (compressCodecsInfo)
+ {
+ g_ExternalCodecs.GetCodecs = compressCodecsInfo;
+ return g_ExternalCodecs.Load();
+ }
+ g_ExternalCodecs.ClearAndRelease();
+ return S_OK;
+
+ COM_TRY_END
+}
+
+#else
+
+STDAPI SetCodecs(ICompressCodecsInfo *);
+STDAPI SetCodecs(ICompressCodecsInfo *)
+{
+ return S_OK;
+}
+
+#endif
diff --git a/CPP/7zip/Archive/DmgHandler.cpp b/CPP/7zip/Archive/DmgHandler.cpp
new file mode 100644
index 0000000..4bcb904
--- /dev/null
+++ b/CPP/7zip/Archive/DmgHandler.cpp
@@ -0,0 +1,1771 @@
+// DmgHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyXml.h"
+#include "../../Common/UTFConvert.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/BZip2Decoder.h"
+#include "../Compress/CopyCoder.h"
+#include "../Compress/LzfseDecoder.h"
+#include "../Compress/ZlibDecoder.h"
+
+#include "Common/OutStreamWithCRC.h"
+
+// #define DMG_SHOW_RAW
+
+// #include <stdio.h>
+#define PRF(x) // x
+
+#define Get16(p) GetBe16(p)
+#define Get32(p) GetBe32(p)
+#define Get64(p) GetBe64(p)
+
+Byte *Base64ToBin(Byte *dest, const char *src);
+
+namespace NArchive {
+namespace NDmg {
+
+
+static const UInt32 METHOD_ZERO_0 = 0;
+static const UInt32 METHOD_COPY = 1;
+static const UInt32 METHOD_ZERO_2 = 2; // without file CRC calculation
+static const UInt32 METHOD_ADC = 0x80000004;
+static const UInt32 METHOD_ZLIB = 0x80000005;
+static const UInt32 METHOD_BZIP2 = 0x80000006;
+static const UInt32 METHOD_LZFSE = 0x80000007;
+static const UInt32 METHOD_COMMENT = 0x7FFFFFFE; // is used to comment "+beg" and "+end" in extra field.
+static const UInt32 METHOD_END = 0xFFFFFFFF;
+
+
+struct CBlock
+{
+ UInt32 Type;
+ UInt64 UnpPos;
+ UInt64 UnpSize;
+ UInt64 PackPos;
+ UInt64 PackSize;
+
+ UInt64 GetNextPackOffset() const { return PackPos + PackSize; }
+ UInt64 GetNextUnpPos() const { return UnpPos + UnpSize; }
+
+ bool IsZeroMethod() const { return Type == METHOD_ZERO_0 || Type == METHOD_ZERO_2; }
+ bool ThereAreDataInBlock() const { return Type != METHOD_COMMENT && Type != METHOD_END; }
+};
+
+static const UInt32 kCheckSumType_CRC = 2;
+
+static const size_t kChecksumSize_Max = 0x80;
+
+struct CChecksum
+{
+ UInt32 Type;
+ UInt32 NumBits;
+ Byte Data[kChecksumSize_Max];
+
+ bool IsCrc32() const { return Type == kCheckSumType_CRC && NumBits == 32; }
+ UInt32 GetCrc32() const { return Get32(Data); }
+ void Parse(const Byte *p);
+};
+
+void CChecksum::Parse(const Byte *p)
+{
+ Type = Get32(p);
+ NumBits = Get32(p + 4);
+ memcpy(Data, p + 8, kChecksumSize_Max);
+}
+
+struct CFile
+{
+ UInt64 Size;
+ UInt64 PackSize;
+ UInt64 StartPos;
+ AString Name;
+ CRecordVector<CBlock> Blocks;
+ CChecksum Checksum;
+ bool FullFileChecksum;
+
+ HRESULT Parse(const Byte *p, UInt32 size);
+};
+
+#ifdef DMG_SHOW_RAW
+struct CExtraFile
+{
+ CByteBuffer Data;
+ AString Name;
+};
+#endif
+
+
+struct CForkPair
+{
+ UInt64 Offset;
+ UInt64 Len;
+
+ void Parse(const Byte *p)
+ {
+ Offset = Get64(p);
+ Len = Get64(p + 8);
+ }
+
+ bool UpdateTop(UInt64 limit, UInt64 &top)
+ {
+ if (Offset > limit || Len > limit - Offset)
+ return false;
+ UInt64 top2 = Offset + Len;
+ if (top <= top2)
+ top = top2;
+ return true;
+ }
+};
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IInArchiveGetStream
+)
+ CMyComPtr<IInStream> _inStream;
+ CObjectVector<CFile> _files;
+ bool _masterCrcError;
+ bool _headersError;
+
+ UInt32 _dataStartOffset;
+ UInt64 _startPos;
+ UInt64 _phySize;
+
+ AString _name;
+
+ #ifdef DMG_SHOW_RAW
+ CObjectVector<CExtraFile> _extras;
+ #endif
+
+ HRESULT ReadData(IInStream *stream, const CForkPair &pair, CByteBuffer &buf);
+ bool ParseBlob(const CByteBuffer &data);
+ HRESULT Open2(IInStream *stream);
+ HRESULT Extract(IInStream *stream);
+};
+
+// that limit can be increased, if there are such dmg files
+static const size_t kXmlSizeMax = 0xFFFF0000; // 4 GB - 64 KB;
+
+struct CMethods
+{
+ CRecordVector<UInt32> Types;
+ CRecordVector<UInt32> ChecksumTypes;
+
+ void Update(const CFile &file);
+ void GetString(AString &s) const;
+};
+
+void CMethods::Update(const CFile &file)
+{
+ ChecksumTypes.AddToUniqueSorted(file.Checksum.Type);
+ FOR_VECTOR (i, file.Blocks)
+ Types.AddToUniqueSorted(file.Blocks[i].Type);
+}
+
+void CMethods::GetString(AString &res) const
+{
+ res.Empty();
+
+ unsigned i;
+
+ for (i = 0; i < Types.Size(); i++)
+ {
+ const UInt32 type = Types[i];
+ if (type == METHOD_COMMENT || type == METHOD_END)
+ continue;
+ char buf[16];
+ const char *s;
+ switch (type)
+ {
+ case METHOD_ZERO_0: s = "Zero0"; break;
+ case METHOD_ZERO_2: s = "Zero2"; break;
+ case METHOD_COPY: s = "Copy"; break;
+ case METHOD_ADC: s = "ADC"; break;
+ case METHOD_ZLIB: s = "ZLIB"; break;
+ case METHOD_BZIP2: s = "BZip2"; break;
+ case METHOD_LZFSE: s = "LZFSE"; break;
+ default: ConvertUInt32ToString(type, buf); s = buf;
+ }
+ res.Add_OptSpaced(s);
+ }
+
+ for (i = 0; i < ChecksumTypes.Size(); i++)
+ {
+ res.Add_Space_if_NotEmpty();
+ UInt32 type = ChecksumTypes[i];
+ switch (type)
+ {
+ case kCheckSumType_CRC: res += "CRC"; break;
+ default:
+ res += "Check";
+ res.Add_UInt32(type);
+ }
+ }
+}
+
+struct CAppleName
+{
+ bool IsFs;
+ const char *Ext;
+ const char *AppleName;
+};
+
+static const CAppleName k_Names[] =
+{
+ { true, "hfs", "Apple_HFS" },
+ { true, "hfsx", "Apple_HFSX" },
+ { true, "ufs", "Apple_UFS" },
+ { true, "apfs", "Apple_APFS" },
+
+ // efi_sys partition is FAT32, but it's not main file. So we use (IsFs = false)
+ { false, "efi_sys", "C12A7328-F81F-11D2-BA4B-00A0C93EC93B" },
+
+ { false, "free", "Apple_Free" },
+ { false, "ddm", "DDM" },
+ { false, NULL, "Apple_partition_map" },
+ { false, NULL, " GPT " },
+ { false, NULL, "MBR" },
+ { false, NULL, "Driver" },
+ { false, NULL, "Patches" }
+};
+
+static const unsigned kNumAppleNames = Z7_ARRAY_SIZE(k_Names);
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
+ kpidCRC,
+ kpidComment,
+ kpidMethod
+ // kpidOffset
+};
+
+IMP_IInArchive_Props
+
+static const Byte kArcProps[] =
+{
+ kpidMethod,
+ kpidNumBlocks,
+ kpidComment
+};
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidMethod:
+ {
+ CMethods m;
+ FOR_VECTOR (i, _files)
+ m.Update(_files[i]);
+ AString s;
+ m.GetString(s);
+ if (!s.IsEmpty())
+ prop = s;
+ break;
+ }
+ case kpidNumBlocks:
+ {
+ UInt64 numBlocks = 0;
+ FOR_VECTOR (i, _files)
+ numBlocks += _files[i].Blocks.Size();
+ prop = numBlocks;
+ break;
+ }
+ case kpidMainSubfile:
+ {
+ int mainIndex = -1;
+ unsigned numFS = 0;
+ unsigned numUnknown = 0;
+ FOR_VECTOR (i, _files)
+ {
+ const AString &name = _files[i].Name;
+ unsigned n;
+ for (n = 0; n < kNumAppleNames; n++)
+ {
+ const CAppleName &appleName = k_Names[n];
+ // if (name.Find(appleName.AppleName) >= 0)
+ if (strstr(name, appleName.AppleName))
+ {
+ if (appleName.IsFs)
+ {
+ numFS++;
+ mainIndex = (int)i;
+ }
+ break;
+ }
+ }
+ if (n == kNumAppleNames)
+ {
+ mainIndex = (int)i;
+ numUnknown++;
+ }
+ }
+ if (numFS + numUnknown == 1)
+ prop = (UInt32)(Int32)mainIndex;
+ break;
+ }
+ case kpidWarning:
+ if (_masterCrcError)
+ prop = "Master CRC error";
+ break;
+
+ case kpidWarningFlags:
+ {
+ UInt32 v = 0;
+ if (_headersError) v |= kpv_ErrorFlags_HeadersError;
+ if (v != 0)
+ prop = v;
+ break;
+ }
+
+ case kpidOffset: prop = _startPos; break;
+ case kpidPhySize: prop = _phySize; break;
+
+ case kpidComment:
+ if (!_name.IsEmpty() && _name.Len() < 256)
+ prop = _name;
+ break;
+
+ case kpidName:
+ if (!_name.IsEmpty() && _name.Len() < 256)
+ {
+ prop = _name + ".dmg";
+ }
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+IMP_IInArchive_ArcProps
+
+HRESULT CFile::Parse(const Byte *p, UInt32 size)
+{
+ const UInt32 kHeadSize = 0xCC;
+ if (size < kHeadSize)
+ return S_FALSE;
+ if (Get32(p) != 0x6D697368) // "mish" signature
+ return S_FALSE;
+ if (Get32(p + 4) != 1) // version
+ return S_FALSE;
+ // UInt64 firstSectorNumber = Get64(p + 8);
+ UInt64 numSectors = Get64(p + 0x10);
+
+ StartPos = Get64(p + 0x18);
+
+ // UInt32 decompressedBufRequested = Get32(p + 0x20); // ???
+ // UInt32 blocksDescriptor = Get32(p + 0x24); // number starting from -1?
+ // char Reserved1[24];
+
+ Checksum.Parse(p + 0x40);
+ PRF(printf("\n\nChecksum Type = %2d", Checksum.Type));
+
+ UInt32 numBlocks = Get32(p + 0xC8);
+ if (numBlocks > ((UInt32)1 << 28))
+ return S_FALSE;
+
+ const UInt32 kRecordSize = 40;
+ if (numBlocks * kRecordSize + kHeadSize != size)
+ return S_FALSE;
+
+ PackSize = 0;
+ Size = 0;
+ Blocks.ClearAndReserve(numBlocks);
+ FullFileChecksum = true;
+
+ p += kHeadSize;
+ UInt32 i;
+
+ for (i = 0; i < numBlocks; i++, p += kRecordSize)
+ {
+ CBlock b;
+ b.Type = Get32(p);
+ b.UnpPos = Get64(p + 0x08) << 9;
+ b.UnpSize = Get64(p + 0x10) << 9;
+ b.PackPos = Get64(p + 0x18);
+ b.PackSize = Get64(p + 0x20);
+
+ // b.PackPos can be 0 for some types. So we don't check it
+ if (!Blocks.IsEmpty())
+ if (b.UnpPos != Blocks.Back().GetNextUnpPos())
+ return S_FALSE;
+
+ PRF(printf("\nType=%8x m[1]=%8x uPos=%8x uSize=%7x pPos=%8x pSize=%7x",
+ b.Type, Get32(p + 4), (UInt32)b.UnpPos, (UInt32)b.UnpSize, (UInt32)b.PackPos, (UInt32)b.PackSize));
+
+ if (b.Type == METHOD_COMMENT)
+ continue;
+ if (b.Type == METHOD_END)
+ break;
+ PackSize += b.PackSize;
+
+ if (b.UnpSize != 0)
+ {
+ if (b.Type == METHOD_ZERO_2)
+ FullFileChecksum = false;
+ Blocks.AddInReserved(b);
+ }
+ }
+
+ if (i != numBlocks - 1)
+ return S_FALSE;
+ if (!Blocks.IsEmpty())
+ Size = Blocks.Back().GetNextUnpPos();
+ if (Size != (numSectors << 9))
+ return S_FALSE;
+
+ return S_OK;
+}
+
+static int FindKeyPair(const CXmlItem &item, const char *key, const char *nextTag)
+{
+ for (unsigned i = 0; i + 1 < item.SubItems.Size(); i++)
+ {
+ const CXmlItem &si = item.SubItems[i];
+ if (si.IsTagged("key") && si.GetSubString() == key && item.SubItems[i + 1].IsTagged(nextTag))
+ return (int)(i + 1);
+ }
+ return -1;
+}
+
+static const AString *GetStringFromKeyPair(const CXmlItem &item, const char *key, const char *nextTag)
+{
+ int index = FindKeyPair(item, key, nextTag);
+ if (index >= 0)
+ return item.SubItems[index].GetSubStringPtr();
+ return NULL;
+}
+
+static const unsigned HEADER_SIZE = 0x200;
+
+static const Byte k_Signature[] = { 'k','o','l','y', 0, 0, 0, 4, 0, 0, 2, 0 };
+
+static inline bool IsKoly(const Byte *p)
+{
+ return memcmp(p, k_Signature, Z7_ARRAY_SIZE(k_Signature)) == 0;
+ /*
+ if (Get32(p) != 0x6B6F6C79) // "koly" signature
+ return false;
+ if (Get32(p + 4) != 4) // version
+ return false;
+ if (Get32(p + 8) != HEADER_SIZE)
+ return false;
+ return true;
+ */
+}
+
+
+HRESULT CHandler::ReadData(IInStream *stream, const CForkPair &pair, CByteBuffer &buf)
+{
+ size_t size = (size_t)pair.Len;
+ if (size != pair.Len)
+ return E_OUTOFMEMORY;
+ buf.Alloc(size);
+ RINOK(InStream_SeekSet(stream, _startPos + pair.Offset))
+ return ReadStream_FALSE(stream, buf, size);
+}
+
+
+bool CHandler::ParseBlob(const CByteBuffer &data)
+{
+ if (data.Size() < 12)
+ return false;
+ const Byte *p = (const Byte *)data;
+ if (Get32(p) != 0xFADE0CC0)
+ return true;
+ const UInt32 size = Get32(p + 4);
+ if (size != data.Size())
+ return false;
+ const UInt32 num = Get32(p + 8);
+ if (num > (size - 12) / 8)
+ return false;
+
+ for (UInt32 i = 0; i < num; i++)
+ {
+ // UInt32 type = Get32(p + i * 8 + 12);
+ UInt32 offset = Get32(p + i * 8 + 12 + 4);
+ if (size - offset < 8)
+ return false;
+ const Byte *p2 = (const Byte *)data + offset;
+ const UInt32 magic = Get32(p2);
+ const UInt32 len = Get32(p2 + 4);
+ if (size - offset < len || len < 8)
+ return false;
+
+ #ifdef DMG_SHOW_RAW
+ CExtraFile &extra = _extras.AddNew();
+ extra.Name = "_blob_";
+ extra.Data.CopyFrom(p2, len);
+ #endif
+
+ if (magic == 0xFADE0C02)
+ {
+ #ifdef DMG_SHOW_RAW
+ extra.Name += "codedir";
+ #endif
+
+ if (len < 11 * 4)
+ return false;
+ UInt32 idOffset = Get32(p2 + 0x14);
+ if (idOffset >= len)
+ return false;
+ UInt32 len2 = len - idOffset;
+ if (len2 < (1 << 10))
+ _name.SetFrom_CalcLen((const char *)(p2 + idOffset), len2);
+ }
+ #ifdef DMG_SHOW_RAW
+ else if (magic == 0xFADE0C01)
+ extra.Name += "requirements";
+ else if (magic == 0xFADE0B01)
+ extra.Name += "signed";
+ else
+ {
+ char temp[16];
+ ConvertUInt32ToHex8Digits(magic, temp);
+ extra.Name += temp;
+ }
+ #endif
+ }
+
+ return true;
+}
+
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+ /*
+ - usual dmg contains Koly Header at the end:
+ - rare case dmg contains Koly Header at the start.
+ */
+
+ _dataStartOffset = 0;
+ UInt64 fileSize;
+ RINOK(InStream_GetPos_GetSize(stream, _startPos, fileSize))
+
+ Byte buf[HEADER_SIZE];
+ RINOK(ReadStream_FALSE(stream, buf, HEADER_SIZE))
+
+ UInt64 headerPos;
+ bool startKolyMode = false;
+
+ if (IsKoly(buf))
+ {
+ // it can be normal koly-at-the-end or koly-at-the-start
+ headerPos = _startPos;
+ if (_startPos <= (1 << 8))
+ {
+ // we want to support startKolyMode, even if there is
+ // some data before dmg file, like 128 bytes MacBin header
+ _dataStartOffset = HEADER_SIZE;
+ startKolyMode = true;
+ }
+ }
+ else
+ {
+ // we check only koly-at-the-end
+ headerPos = fileSize;
+ if (headerPos < HEADER_SIZE)
+ return S_FALSE;
+ headerPos -= HEADER_SIZE;
+ RINOK(InStream_SeekSet(stream, headerPos))
+ RINOK(ReadStream_FALSE(stream, buf, HEADER_SIZE))
+ if (!IsKoly(buf))
+ return S_FALSE;
+ }
+
+ // UInt32 flags = Get32(buf + 12);
+ // UInt64 runningDataForkOffset = Get64(buf + 0x10);
+
+ CForkPair dataForkPair, rsrcPair, xmlPair, blobPair;
+
+ dataForkPair.Parse(buf + 0x18);
+ rsrcPair.Parse(buf + 0x28);
+ xmlPair.Parse(buf + 0xD8);
+ blobPair.Parse(buf + 0x128);
+
+ // UInt32 segmentNumber = Get32(buf + 0x38);
+ // UInt32 segmentCount = Get32(buf + 0x3C);
+ // Byte segmentGUID[16];
+ // CChecksum dataForkChecksum;
+ // dataForkChecksum.Parse(buf + 0x50);
+
+ UInt64 top = 0;
+ UInt64 limit = startKolyMode ? fileSize : headerPos;
+
+ if (!dataForkPair.UpdateTop(limit, top)) return S_FALSE;
+ if (!xmlPair.UpdateTop(limit, top)) return S_FALSE;
+ if (!rsrcPair.UpdateTop(limit, top)) return S_FALSE;
+
+ /* Some old dmg files contain garbage data in blobPair field.
+ So we need to ignore such garbage case;
+ And we still need to detect offset of start of archive for "parser" mode. */
+
+ bool useBlob = blobPair.UpdateTop(limit, top);
+
+
+ if (startKolyMode)
+ _phySize = top;
+ else
+ {
+ _phySize = headerPos + HEADER_SIZE;
+ _startPos = 0;
+ if (top != headerPos)
+ {
+ /*
+ if expected absolute offset is not equal to real header offset,
+ 2 cases are possible:
+ - additional (unknown) headers
+ - archive with offset.
+ So we try to read XML with absolute offset to select from these two ways.
+ */
+ CForkPair xmlPair2 = xmlPair;
+ const char *sz = "<?xml version";
+ const unsigned len = (unsigned)strlen(sz);
+ if (xmlPair2.Len > len)
+ xmlPair2.Len = len;
+ CByteBuffer buf2;
+ if (xmlPair2.Len < len
+ || ReadData(stream, xmlPair2, buf2) != S_OK
+ || memcmp(buf2, sz, len) != 0)
+ {
+ // if absolute offset is not OK, probably it's archive with offset
+ _startPos = headerPos - top;
+ _phySize = top + HEADER_SIZE;
+ }
+ }
+ }
+
+ // Byte reserved[0x78]
+
+ if (useBlob && blobPair.Len != 0)
+ {
+ #ifdef DMG_SHOW_RAW
+ CExtraFile &extra = _extras.AddNew();
+ extra.Name = "_blob.bin";
+ CByteBuffer &blobBuf = extra.Data;
+ #else
+ CByteBuffer blobBuf;
+ #endif
+ RINOK(ReadData(stream, blobPair, blobBuf))
+ if (!ParseBlob(blobBuf))
+ _headersError = true;
+ }
+
+
+ CChecksum masterChecksum;
+ masterChecksum.Parse(buf + 0x160);
+
+ // UInt32 imageVariant = Get32(buf + 0x1E8);
+ // UInt64 numSectors = Get64(buf + 0x1EC);
+ // Byte reserved[0x12]
+
+ const UInt32 RSRC_HEAD_SIZE = 0x100;
+
+ // We don't know the size of the field "offset" in rsrc.
+ // We suppose that it uses 24 bits. So we use Rsrc, only if the rsrcLen < (1 << 24).
+ bool useRsrc = (rsrcPair.Len > RSRC_HEAD_SIZE && rsrcPair.Len < ((UInt32)1 << 24));
+ // useRsrc = false;
+
+ if (useRsrc)
+ {
+ #ifdef DMG_SHOW_RAW
+ CExtraFile &extra = _extras.AddNew();
+ extra.Name = "rsrc.bin";
+ CByteBuffer &rsrcBuf = extra.Data;
+ #else
+ CByteBuffer rsrcBuf;
+ #endif
+
+ RINOK(ReadData(stream, rsrcPair, rsrcBuf))
+
+ const Byte *p = rsrcBuf;
+ UInt32 headSize = Get32(p + 0);
+ UInt32 footerOffset = Get32(p + 4);
+ UInt32 mainDataSize = Get32(p + 8);
+ UInt32 footerSize = Get32(p + 12);
+ if (headSize != RSRC_HEAD_SIZE
+ || footerOffset >= rsrcPair.Len
+ || mainDataSize >= rsrcPair.Len
+ || footerOffset < mainDataSize
+ || footerOffset != headSize + mainDataSize)
+ return S_FALSE;
+
+ const UInt32 footerEnd = footerOffset + footerSize;
+ if (footerEnd != rsrcPair.Len)
+ {
+ // there is rare case dmg example, where there are 4 additional bytes
+ UInt64 rem = rsrcPair.Len - footerOffset;
+ if (rem < footerSize
+ || rem - footerSize != 4
+ || Get32(p + footerEnd) != 0)
+ return S_FALSE;
+ }
+
+ if (footerSize < 16)
+ return S_FALSE;
+ if (memcmp(p, p + footerOffset, 16) != 0)
+ return S_FALSE;
+
+ p += footerOffset;
+
+ if ((UInt32)Get16(p + 0x18) != 0x1C)
+ return S_FALSE;
+ const UInt32 namesOffset = Get16(p + 0x1A);
+ if (namesOffset > footerSize)
+ return S_FALSE;
+
+ UInt32 numItems = (UInt32)Get16(p + 0x1C) + 1;
+ if (numItems * 8 + 0x1E > namesOffset)
+ return S_FALSE;
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ const Byte *p2 = p + 0x1E + i * 8;
+
+ const UInt32 typeId = Get32(p2);
+
+ #ifndef DMG_SHOW_RAW
+ if (typeId != 0x626C6B78) // blkx
+ continue;
+ #endif
+
+ const UInt32 numFiles = (UInt32)Get16(p2 + 4) + 1;
+ const UInt32 offs = Get16(p2 + 6);
+ if (0x1C + offs + 12 * numFiles > namesOffset)
+ return S_FALSE;
+
+ for (UInt32 k = 0; k < numFiles; k++)
+ {
+ const Byte *p3 = p + 0x1C + offs + k * 12;
+ // UInt32 id = Get16(p3);
+ const UInt32 namePos = Get16(p3 + 2);
+ // Byte attributes = p3[4]; // = 0x50 for blkx
+ // we don't know how many bits we can use. So we use 24 bits only
+ UInt32 blockOffset = Get32(p3 + 4);
+ blockOffset &= (((UInt32)1 << 24) - 1);
+ // UInt32 unknown2 = Get32(p3 + 8); // ???
+ if (blockOffset + 4 >= mainDataSize)
+ return S_FALSE;
+ const Byte *pBlock = rsrcBuf + headSize + blockOffset;
+ const UInt32 blockSize = Get32(pBlock);
+ if (mainDataSize - (blockOffset + 4) < blockSize)
+ return S_FALSE;
+
+ AString name;
+
+ if (namePos != 0xFFFF)
+ {
+ UInt32 namesBlockSize = footerSize - namesOffset;
+ if (namePos >= namesBlockSize)
+ return S_FALSE;
+ const Byte *namePtr = p + namesOffset + namePos;
+ UInt32 nameLen = *namePtr;
+ if (namesBlockSize - namePos <= nameLen)
+ return S_FALSE;
+ for (UInt32 r = 1; r <= nameLen; r++)
+ {
+ Byte c = namePtr[r];
+ if (c < 0x20 || c >= 0x80)
+ break;
+ name += (char)c;
+ }
+ }
+
+ if (typeId == 0x626C6B78) // blkx
+ {
+ CFile &file = _files.AddNew();
+ file.Name = name;
+ RINOK(file.Parse(pBlock + 4, blockSize))
+ }
+
+ #ifdef DMG_SHOW_RAW
+ {
+ AString name2;
+
+ name2.Add_UInt32(i);
+ name2 += '_';
+
+ {
+ char temp[4 + 1] = { 0 };
+ memcpy(temp, p2, 4);
+ name2 += temp;
+ }
+ name2.Trim();
+ name2 += '_';
+ name2.Add_UInt32(k);
+
+ if (!name.IsEmpty())
+ {
+ name2 += '_';
+ name2 += name;
+ }
+
+ CExtraFile &extra = _extras.AddNew();
+ extra.Name = name2;
+ extra.Data.CopyFrom(pBlock + 4, blockSize);
+ }
+ #endif
+ }
+ }
+ }
+ else
+ {
+ if (xmlPair.Len >= kXmlSizeMax || xmlPair.Len == 0)
+ return S_FALSE;
+ size_t size = (size_t)xmlPair.Len;
+ if (size != xmlPair.Len)
+ return S_FALSE;
+
+ RINOK(InStream_SeekSet(stream, _startPos + xmlPair.Offset))
+
+ CXml xml;
+ {
+ CObjArray<char> xmlStr(size + 1);
+ RINOK(ReadStream_FALSE(stream, xmlStr, size))
+ xmlStr[size] = 0;
+ // if (strlen(xmlStr) != size) return S_FALSE;
+ if (!xml.Parse(xmlStr))
+ return S_FALSE;
+
+ #ifdef DMG_SHOW_RAW
+ CExtraFile &extra = _extras.AddNew();
+ extra.Name = "a.xml";
+ extra.Data.CopyFrom((const Byte *)(const char *)xmlStr, size);
+ #endif
+ }
+
+ if (xml.Root.Name != "plist")
+ return S_FALSE;
+
+ int dictIndex = xml.Root.FindSubTag("dict");
+ if (dictIndex < 0)
+ return S_FALSE;
+
+ const CXmlItem &dictItem = xml.Root.SubItems[dictIndex];
+ int rfDictIndex = FindKeyPair(dictItem, "resource-fork", "dict");
+ if (rfDictIndex < 0)
+ return S_FALSE;
+
+ const CXmlItem &rfDictItem = dictItem.SubItems[rfDictIndex];
+ int arrIndex = FindKeyPair(rfDictItem, "blkx", "array");
+ if (arrIndex < 0)
+ return S_FALSE;
+
+ const CXmlItem &arrItem = rfDictItem.SubItems[arrIndex];
+
+ FOR_VECTOR (i, arrItem.SubItems)
+ {
+ const CXmlItem &item = arrItem.SubItems[i];
+ if (!item.IsTagged("dict"))
+ continue;
+
+ CByteBuffer rawBuf;
+ unsigned destLen = 0;
+ {
+ const AString *dataString = GetStringFromKeyPair(item, "Data", "data");
+ if (!dataString)
+ return S_FALSE;
+ destLen = dataString->Len() / 4 * 3 + 4;
+ rawBuf.Alloc(destLen);
+ {
+ const Byte *endPtr = Base64ToBin(rawBuf, *dataString);
+ if (!endPtr)
+ return S_FALSE;
+ destLen = (unsigned)(endPtr - (const Byte *)rawBuf);
+ }
+
+ #ifdef DMG_SHOW_RAW
+ CExtraFile &extra = _extras.AddNew();
+ extra.Name.Add_UInt32(_files.Size());
+ extra.Data.CopyFrom(rawBuf, destLen);
+ #endif
+ }
+ CFile &file = _files.AddNew();
+ {
+ const AString *name = GetStringFromKeyPair(item, "Name", "string");
+ if (!name || name->IsEmpty())
+ name = GetStringFromKeyPair(item, "CFName", "string");
+ if (name)
+ file.Name = *name;
+ }
+ RINOK(file.Parse(rawBuf, destLen))
+ }
+ }
+
+ if (masterChecksum.IsCrc32())
+ {
+ UInt32 crc = CRC_INIT_VAL;
+ unsigned i;
+ for (i = 0; i < _files.Size(); i++)
+ {
+ const CChecksum &cs = _files[i].Checksum;
+ if ((cs.NumBits & 0x7) != 0)
+ break;
+ UInt32 len = cs.NumBits >> 3;
+ if (len > kChecksumSize_Max)
+ break;
+ crc = CrcUpdate(crc, cs.Data, (size_t)len);
+ }
+ if (i == _files.Size())
+ _masterCrcError = (CRC_GET_DIGEST(crc) != masterChecksum.GetCrc32());
+ }
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */))
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ if (Open2(stream) != S_OK)
+ return S_FALSE;
+ _inStream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _phySize = 0;
+ _inStream.Release();
+ _files.Clear();
+ _masterCrcError = false;
+ _headersError = false;
+ _name.Empty();
+ #ifdef DMG_SHOW_RAW
+ _extras.Clear();
+ #endif
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _files.Size()
+ #ifdef DMG_SHOW_RAW
+ + _extras.Size()
+ #endif
+ ;
+ return S_OK;
+}
+
+#ifdef DMG_SHOW_RAW
+#define RAW_PREFIX "raw" STRING_PATH_SEPARATOR
+#endif
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+
+ #ifdef DMG_SHOW_RAW
+ if (index >= _files.Size())
+ {
+ const CExtraFile &extra = _extras[index - _files.Size()];
+ switch (propID)
+ {
+ case kpidPath:
+ prop = (AString)RAW_PREFIX + extra.Name;
+ break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)extra.Data.Size();
+ break;
+ }
+ }
+ else
+ #endif
+ {
+ const CFile &item = _files[index];
+ switch (propID)
+ {
+ case kpidSize: prop = item.Size; break;
+ case kpidPackSize: prop = item.PackSize; break;
+ case kpidCRC:
+ {
+ if (item.Checksum.IsCrc32() && item.FullFileChecksum)
+ prop = item.Checksum.GetCrc32();
+ break;
+ }
+
+ /*
+ case kpidOffset:
+ {
+ prop = item.StartPos;
+ break;
+ }
+ */
+
+ case kpidMethod:
+ {
+ CMethods m;
+ m.Update(item);
+ AString s;
+ m.GetString(s);
+ if (!s.IsEmpty())
+ prop = s;
+ break;
+ }
+
+ case kpidPath:
+ {
+ UString name;
+ name.Add_UInt32(index);
+ unsigned num = 10;
+ unsigned numDigits;
+ for (numDigits = 1; num < _files.Size(); numDigits++)
+ num *= 10;
+ while (name.Len() < numDigits)
+ name.InsertAtFront(L'0');
+
+ AString subName;
+ int pos1 = item.Name.Find('(');
+ if (pos1 >= 0)
+ {
+ pos1++;
+ const int pos2 = item.Name.Find(')', pos1);
+ if (pos2 >= 0)
+ {
+ subName.SetFrom(item.Name.Ptr(pos1), pos2 - pos1);
+ pos1 = subName.Find(':');
+ if (pos1 >= 0)
+ subName.DeleteFrom(pos1);
+ }
+ }
+ else
+ subName = item.Name; // new apfs dmg can be without braces
+ subName.Trim();
+ if (!subName.IsEmpty())
+ {
+ for (unsigned n = 0; n < kNumAppleNames; n++)
+ {
+ const CAppleName &appleName = k_Names[n];
+ if (appleName.Ext)
+ {
+ if (subName == appleName.AppleName)
+ {
+ subName = appleName.Ext;
+ break;
+ }
+ }
+ }
+ UString name2;
+ ConvertUTF8ToUnicode(subName, name2);
+ name.Add_Dot();
+ name += name2;
+ }
+ else
+ {
+ UString name2;
+ ConvertUTF8ToUnicode(item.Name, name2);
+ if (!name2.IsEmpty())
+ name += "_";
+ name += name2;
+ }
+ prop = name;
+ break;
+ }
+
+ case kpidComment:
+ {
+ UString name;
+ ConvertUTF8ToUnicode(item.Name, name);
+ prop = name;
+ break;
+ }
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ CAdcDecoder
+ , ICompressCoder
+)
+ CLzOutWindow m_OutWindowStream;
+ CInBuffer m_InStream;
+
+ /*
+ void ReleaseStreams()
+ {
+ m_OutWindowStream.ReleaseStream();
+ m_InStream.ReleaseStream();
+ }
+ */
+
+ class CCoderReleaser Z7_final
+ {
+ CAdcDecoder *m_Coder;
+ public:
+ bool NeedFlush;
+ CCoderReleaser(CAdcDecoder *coder): m_Coder(coder), NeedFlush(true) {}
+ ~CCoderReleaser()
+ {
+ if (NeedFlush)
+ m_Coder->m_OutWindowStream.Flush();
+ // m_Coder->ReleaseStreams();
+ }
+ };
+ friend class CCoderReleaser;
+
+public:
+ HRESULT CodeReal(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress);
+};
+
+HRESULT CAdcDecoder::CodeReal(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress)
+{
+ if (!m_OutWindowStream.Create(1 << 18))
+ return E_OUTOFMEMORY;
+ if (!m_InStream.Create(1 << 18))
+ return E_OUTOFMEMORY;
+
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(false);
+ m_InStream.SetStream(inStream);
+ m_InStream.Init();
+
+ CCoderReleaser coderReleaser(this);
+
+ const UInt32 kStep = (1 << 20);
+ UInt64 nextLimit = kStep;
+
+ UInt64 pos = 0;
+ while (pos < *outSize)
+ {
+ if (pos > nextLimit && progress)
+ {
+ UInt64 packSize = m_InStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &pos))
+ nextLimit += kStep;
+ }
+ Byte b;
+ if (!m_InStream.ReadByte(b))
+ return S_FALSE;
+ UInt64 rem = *outSize - pos;
+ if (b & 0x80)
+ {
+ unsigned num = (b & 0x7F) + 1;
+ if (num > rem)
+ return S_FALSE;
+ for (unsigned i = 0; i < num; i++)
+ {
+ if (!m_InStream.ReadByte(b))
+ return S_FALSE;
+ m_OutWindowStream.PutByte(b);
+ }
+ pos += num;
+ continue;
+ }
+ Byte b1;
+ if (!m_InStream.ReadByte(b1))
+ return S_FALSE;
+
+ UInt32 len, distance;
+
+ if (b & 0x40)
+ {
+ len = ((UInt32)b & 0x3F) + 4;
+ Byte b2;
+ if (!m_InStream.ReadByte(b2))
+ return S_FALSE;
+ distance = ((UInt32)b1 << 8) + b2;
+ }
+ else
+ {
+ b &= 0x3F;
+ len = ((UInt32)b >> 2) + 3;
+ distance = (((UInt32)b & 3) << 8) + b1;
+ }
+
+ if (distance >= pos || len > rem)
+ return S_FALSE;
+ m_OutWindowStream.CopyBlock(distance, len);
+ pos += len;
+ }
+ if (*inSize != m_InStream.GetProcessedSize())
+ return S_FALSE;
+ coderReleaser.NeedFlush = false;
+ return m_OutWindowStream.Flush();
+}
+
+Z7_COM7F_IMF(CAdcDecoder::Code(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream, const UInt64 *inSize, const UInt64 *outSize,
+ ICompressProgressInfo *progress))
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress);}
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+
+
+
+
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _files.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 index = (allFilesMode ? i : indices[i]);
+ #ifdef DMG_SHOW_RAW
+ if (index >= _files.Size())
+ totalSize += _extras[index - _files.Size()].Data.Size();
+ else
+ #endif
+ totalSize += _files[index].Size;
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentPackTotal = 0;
+ UInt64 currentUnpTotal = 0;
+ UInt64 currentPackSize = 0;
+ UInt64 currentUnpSize = 0;
+
+ const UInt32 kZeroBufSize = (1 << 14);
+ CByteBuffer zeroBuf(kZeroBufSize);
+ memset(zeroBuf, 0, kZeroBufSize);
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ NCompress::NBZip2::CDecoder *bzip2CoderSpec = new NCompress::NBZip2::CDecoder();
+ CMyComPtr<ICompressCoder> bzip2Coder = bzip2CoderSpec;
+
+ NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
+ CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;
+
+ CAdcDecoder *adcCoderSpec = new CAdcDecoder();
+ CMyComPtr<ICompressCoder> adcCoder = adcCoderSpec;
+
+ NCompress::NLzfse::CDecoder *lzfseCoderSpec = new NCompress::NLzfse::CDecoder();
+ CMyComPtr<ICompressCoder> lzfseCoder = lzfseCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_inStream);
+
+ for (i = 0; i < numItems; i++, currentPackTotal += currentPackSize, currentUnpTotal += currentUnpSize)
+ {
+ lps->InSize = currentPackTotal;
+ lps->OutSize = currentUnpTotal;
+ currentPackSize = 0;
+ currentUnpSize = 0;
+ RINOK(lps->SetCur())
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode))
+
+
+ COutStreamWithCRC *outCrcStreamSpec = new COutStreamWithCRC;
+ CMyComPtr<ISequentialOutStream> outCrcStream = outCrcStreamSpec;
+ outCrcStreamSpec->SetStream(realOutStream);
+ bool needCrc = false;
+ outCrcStreamSpec->Init(needCrc);
+
+ CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(outCrcStream);
+
+ realOutStream.Release();
+
+ Int32 opRes = NExtract::NOperationResult::kOK;
+ #ifdef DMG_SHOW_RAW
+ if (index >= _files.Size())
+ {
+ const CByteBuffer &buf = _extras[index - _files.Size()].Data;
+ outStreamSpec->Init(buf.Size());
+ RINOK(WriteStream(outStream, buf, buf.Size()));
+ currentPackSize = currentUnpSize = buf.Size();
+ }
+ else
+ #endif
+ {
+ const CFile &item = _files[index];
+ currentPackSize = item.PackSize;
+ currentUnpSize = item.Size;
+
+ needCrc = item.Checksum.IsCrc32();
+
+ UInt64 unpPos = 0;
+ UInt64 packPos = 0;
+ {
+ FOR_VECTOR (j, item.Blocks)
+ {
+ lps->InSize = currentPackTotal + packPos;
+ lps->OutSize = currentUnpTotal + unpPos;
+ RINOK(lps->SetCur())
+
+ const CBlock &block = item.Blocks[j];
+ if (!block.ThereAreDataInBlock())
+ continue;
+
+ packPos += block.PackSize;
+ if (block.UnpPos != unpPos)
+ {
+ opRes = NExtract::NOperationResult::kDataError;
+ break;
+ }
+
+ RINOK(InStream_SeekSet(_inStream, _startPos + _dataStartOffset + item.StartPos + block.PackPos))
+ streamSpec->Init(block.PackSize);
+ bool realMethod = true;
+ outStreamSpec->Init(block.UnpSize);
+ HRESULT res = S_OK;
+
+ outCrcStreamSpec->EnableCalc(needCrc);
+
+ switch (block.Type)
+ {
+ case METHOD_ZERO_0:
+ case METHOD_ZERO_2:
+ realMethod = false;
+ if (block.PackSize != 0)
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ outCrcStreamSpec->EnableCalc(block.Type == METHOD_ZERO_0);
+ break;
+
+ case METHOD_COPY:
+ if (block.UnpSize != block.PackSize)
+ {
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ break;
+ }
+ res = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ break;
+
+ case METHOD_ADC:
+ {
+ res = adcCoder->Code(inStream, outStream, &block.PackSize, &block.UnpSize, progress);
+ break;
+ }
+
+ case METHOD_ZLIB:
+ {
+ res = zlibCoder->Code(inStream, outStream, NULL, NULL, progress);
+ if (res == S_OK)
+ if (zlibCoderSpec->GetInputProcessedSize() != block.PackSize)
+ opRes = NExtract::NOperationResult::kDataError;
+ break;
+ }
+
+ case METHOD_BZIP2:
+ {
+ res = bzip2Coder->Code(inStream, outStream, NULL, NULL, progress);
+ if (res == S_OK)
+ if (bzip2CoderSpec->GetInputProcessedSize() != block.PackSize)
+ opRes = NExtract::NOperationResult::kDataError;
+ break;
+ }
+
+ case METHOD_LZFSE:
+ {
+ res = lzfseCoder->Code(inStream, outStream, &block.PackSize, &block.UnpSize, progress);
+ break;
+ }
+
+ default:
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ break;
+ }
+
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ return res;
+ if (opRes == NExtract::NOperationResult::kOK)
+ opRes = NExtract::NOperationResult::kDataError;
+ }
+
+ unpPos += block.UnpSize;
+
+ if (!outStreamSpec->IsFinishedOK())
+ {
+ if (realMethod && opRes == NExtract::NOperationResult::kOK)
+ opRes = NExtract::NOperationResult::kDataError;
+
+ while (outStreamSpec->GetRem() != 0)
+ {
+ UInt64 rem = outStreamSpec->GetRem();
+ UInt32 size = (UInt32)MyMin(rem, (UInt64)kZeroBufSize);
+ RINOK(WriteStream(outStream, zeroBuf, size))
+ }
+ }
+ }
+ }
+
+ if (needCrc && opRes == NExtract::NOperationResult::kOK)
+ {
+ if (outCrcStreamSpec->GetCRC() != item.Checksum.GetCrc32())
+ opRes = NExtract::NOperationResult::kCRCError;
+ }
+ }
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes))
+ }
+
+ return S_OK;
+ COM_TRY_END
+}
+
+struct CChunk
+{
+ int BlockIndex;
+ UInt64 AccessMark;
+ CByteBuffer Buf;
+};
+
+
+Z7_CLASS_IMP_COM_1(
+ CInStream
+ , IInStream
+)
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+
+ UInt64 _virtPos;
+ int _latestChunk;
+ int _latestBlock;
+ UInt64 _accessMark;
+ CObjectVector<CChunk> _chunks;
+
+ NCompress::NBZip2::CDecoder *bzip2CoderSpec;
+ CMyComPtr<ICompressCoder> bzip2Coder;
+
+ NCompress::NZlib::CDecoder *zlibCoderSpec;
+ CMyComPtr<ICompressCoder> zlibCoder;
+
+ CAdcDecoder *adcCoderSpec;
+ CMyComPtr<ICompressCoder> adcCoder;
+
+ NCompress::NLzfse::CDecoder *lzfseCoderSpec;
+ CMyComPtr<ICompressCoder> lzfseCoder;
+
+ CBufPtrSeqOutStream *outStreamSpec;
+ CMyComPtr<ISequentialOutStream> outStream;
+
+ CLimitedSequentialInStream *limitedStreamSpec;
+ CMyComPtr<ISequentialInStream> inStream;
+
+public:
+ CMyComPtr<IInStream> Stream;
+ UInt64 Size;
+ const CFile *File;
+ UInt64 _startPos;
+
+ HRESULT InitAndSeek(UInt64 startPos)
+ {
+ _startPos = startPos;
+ _virtPos = 0;
+ _latestChunk = -1;
+ _latestBlock = -1;
+ _accessMark = 0;
+
+ limitedStreamSpec = new CLimitedSequentialInStream;
+ inStream = limitedStreamSpec;
+ limitedStreamSpec->SetStream(Stream);
+
+ outStreamSpec = new CBufPtrSeqOutStream;
+ outStream = outStreamSpec;
+ return S_OK;
+ }
+};
+
+
+static unsigned FindBlock(const CRecordVector<CBlock> &blocks, UInt64 pos)
+{
+ unsigned left = 0, right = blocks.Size();
+ for (;;)
+ {
+ unsigned mid = (left + right) / 2;
+ if (mid == left)
+ return left;
+ if (pos < blocks[mid].UnpPos)
+ right = mid;
+ else
+ left = mid;
+ }
+}
+
+Z7_COM7F_IMF(CInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ COM_TRY_BEGIN
+
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ if (_virtPos >= Size)
+ return S_OK; // (Size == _virtPos) ? S_OK: E_FAIL;
+ {
+ UInt64 rem = Size - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ if (_latestBlock >= 0)
+ {
+ const CBlock &block = File->Blocks[(unsigned)_latestBlock];
+ if (_virtPos < block.UnpPos || (_virtPos - block.UnpPos) >= block.UnpSize)
+ _latestBlock = -1;
+ }
+
+ if (_latestBlock < 0)
+ {
+ _latestChunk = -1;
+ unsigned blockIndex = FindBlock(File->Blocks, _virtPos);
+ const CBlock &block = File->Blocks[blockIndex];
+
+ if (!block.IsZeroMethod() && block.Type != METHOD_COPY)
+ {
+ unsigned i;
+ for (i = 0; i < _chunks.Size(); i++)
+ if (_chunks[i].BlockIndex == (int)blockIndex)
+ break;
+
+ if (i != _chunks.Size())
+ _latestChunk = (int)i;
+ else
+ {
+ const unsigned kNumChunksMax = 128;
+ unsigned chunkIndex;
+
+ if (_chunks.Size() != kNumChunksMax)
+ chunkIndex = _chunks.Add(CChunk());
+ else
+ {
+ chunkIndex = 0;
+ for (i = 0; i < _chunks.Size(); i++)
+ if (_chunks[i].AccessMark < _chunks[chunkIndex].AccessMark)
+ chunkIndex = i;
+ }
+
+ CChunk &chunk = _chunks[chunkIndex];
+ chunk.BlockIndex = -1;
+ chunk.AccessMark = 0;
+
+ if (chunk.Buf.Size() < block.UnpSize)
+ {
+ chunk.Buf.Free();
+ if (block.UnpSize > ((UInt32)1 << 31))
+ return E_FAIL;
+ chunk.Buf.Alloc((size_t)block.UnpSize);
+ }
+
+ outStreamSpec->Init(chunk.Buf, (size_t)block.UnpSize);
+
+ RINOK(InStream_SeekSet(Stream, _startPos + File->StartPos + block.PackPos))
+
+ limitedStreamSpec->Init(block.PackSize);
+ HRESULT res = S_OK;
+
+ switch (block.Type)
+ {
+ case METHOD_COPY:
+ if (block.PackSize != block.UnpSize)
+ return E_FAIL;
+ res = ReadStream_FAIL(inStream, chunk.Buf, (size_t)block.UnpSize);
+ break;
+
+ case METHOD_ADC:
+ if (!adcCoder)
+ {
+ adcCoderSpec = new CAdcDecoder();
+ adcCoder = adcCoderSpec;
+ }
+ res = adcCoder->Code(inStream, outStream, &block.PackSize, &block.UnpSize, NULL);
+ break;
+
+ case METHOD_ZLIB:
+ if (!zlibCoder)
+ {
+ zlibCoderSpec = new NCompress::NZlib::CDecoder();
+ zlibCoder = zlibCoderSpec;
+ }
+ res = zlibCoder->Code(inStream, outStream, NULL, NULL, NULL);
+ if (res == S_OK && zlibCoderSpec->GetInputProcessedSize() != block.PackSize)
+ res = S_FALSE;
+ break;
+
+ case METHOD_BZIP2:
+ if (!bzip2Coder)
+ {
+ bzip2CoderSpec = new NCompress::NBZip2::CDecoder();
+ bzip2Coder = bzip2CoderSpec;
+ }
+ res = bzip2Coder->Code(inStream, outStream, NULL, NULL, NULL);
+ if (res == S_OK && bzip2CoderSpec->GetInputProcessedSize() != block.PackSize)
+ res = S_FALSE;
+ break;
+
+ case METHOD_LZFSE:
+ if (!lzfseCoder)
+ {
+ lzfseCoderSpec = new NCompress::NLzfse::CDecoder();
+ lzfseCoder = lzfseCoderSpec;
+ }
+ res = lzfseCoder->Code(inStream, outStream, &block.PackSize, &block.UnpSize, NULL);
+ break;
+
+ default:
+ return E_FAIL;
+ }
+
+ if (res != S_OK)
+ return res;
+ if (block.Type != METHOD_COPY && outStreamSpec->GetPos() != block.UnpSize)
+ return E_FAIL;
+ chunk.BlockIndex = (int)blockIndex;
+ _latestChunk = (int)chunkIndex;
+ }
+
+ _chunks[_latestChunk].AccessMark = _accessMark++;
+ }
+
+ _latestBlock = (int)blockIndex;
+ }
+
+ const CBlock &block = File->Blocks[(unsigned)_latestBlock];
+ const UInt64 offset = _virtPos - block.UnpPos;
+ const UInt64 rem = block.UnpSize - offset;
+ if (size > rem)
+ size = (UInt32)rem;
+
+ HRESULT res = S_OK;
+
+ if (block.Type == METHOD_COPY)
+ {
+ RINOK(InStream_SeekSet(Stream, _startPos + File->StartPos + block.PackPos + offset))
+ res = Stream->Read(data, size, &size);
+ }
+ else if (block.IsZeroMethod())
+ memset(data, 0, size);
+ else if (size != 0)
+ memcpy(data, _chunks[_latestChunk].Buf + (size_t)offset, size);
+
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+
+ return res;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += Size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _virtPos = (UInt64)offset;
+ if (newPosition)
+ *newPosition = (UInt64)offset;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+
+ #ifdef DMG_SHOW_RAW
+ if (index >= (UInt32)_files.Size())
+ return S_FALSE;
+ #endif
+
+ CInStream *spec = new CInStream;
+ CMyComPtr<ISequentialInStream> specStream = spec;
+ spec->File = &_files[index];
+ const CFile &file = *spec->File;
+
+ FOR_VECTOR (i, file.Blocks)
+ {
+ const CBlock &block = file.Blocks[i];
+ switch (block.Type)
+ {
+ case METHOD_ZERO_0:
+ case METHOD_ZERO_2:
+ case METHOD_COPY:
+ case METHOD_ADC:
+ case METHOD_ZLIB:
+ case METHOD_BZIP2:
+ case METHOD_LZFSE:
+ case METHOD_END:
+ break;
+ default:
+ return S_FALSE;
+ }
+ }
+
+ spec->Stream = _inStream;
+ spec->Size = spec->File->Size;
+ RINOK(spec->InitAndSeek(_startPos + _dataStartOffset))
+ *stream = specStream.Detach();
+ return S_OK;
+
+ COM_TRY_END
+}
+
+REGISTER_ARC_I(
+ "Dmg", "dmg", NULL, 0xE4,
+ k_Signature,
+ 0,
+ NArcInfoFlags::kBackwardOpen |
+ NArcInfoFlags::kUseGlobalOffset,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/ElfHandler.cpp b/CPP/7zip/Archive/ElfHandler.cpp
new file mode 100644
index 0000000..7e1facc
--- /dev/null
+++ b/CPP/7zip/Archive/ElfHandler.cpp
@@ -0,0 +1,1108 @@
+// ElfHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer.h"
+
+#include "../../Windows/PropVariantUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+using namespace NWindows;
+
+static UInt16 Get16(const Byte *p, bool be) { if (be) return GetBe16(p); return GetUi16(p); }
+static UInt32 Get32(const Byte *p, bool be) { if (be) return GetBe32(p); return GetUi32(p); }
+static UInt64 Get64(const Byte *p, bool be) { if (be) return GetBe64(p); return GetUi64(p); }
+
+#define G16(offs, v) v = Get16(p + (offs), be)
+#define G32(offs, v) v = Get32(p + (offs), be)
+#define G64(offs, v) v = Get64(p + (offs), be)
+
+namespace NArchive {
+namespace NElf {
+
+/*
+ ELF Structure for most files (real order can be different):
+ Header
+ Program (segment) header table (used at runtime)
+ Segment1 (Section ... Section)
+ Segment2
+ ...
+ SegmentN
+ Section header table (the data for linking and relocation)
+*/
+
+#define ELF_CLASS_32 1
+#define ELF_CLASS_64 2
+
+#define ELF_DATA_2LSB 1
+#define ELF_DATA_2MSB 2
+
+static const UInt32 kHeaderSize32 = 0x34;
+static const UInt32 kHeaderSize64 = 0x40;
+
+static const UInt32 kSegmentSize32 = 0x20;
+static const UInt32 kSegmentSize64 = 0x38;
+
+static const UInt32 kSectionSize32 = 0x28;
+static const UInt32 kSectionSize64 = 0x40;
+
+struct CHeader
+{
+ bool Mode64;
+ bool Be;
+ Byte Os;
+ Byte AbiVer;
+
+ UInt16 Type;
+ UInt16 Machine;
+ // UInt32 Version;
+
+ // UInt64 EntryVa;
+ UInt64 ProgOffset;
+ UInt64 SectOffset;
+ UInt32 Flags;
+ UInt16 HeaderSize;
+ UInt16 SegmentEntrySize;
+ UInt16 NumSegments;
+ UInt16 SectionEntrySize;
+ UInt16 NumSections;
+ UInt16 NamesSectIndex;
+
+ bool Parse(const Byte *buf);
+
+ UInt64 GetHeadersSize() const { return (UInt64)HeaderSize +
+ (UInt32)NumSegments * SegmentEntrySize +
+ (UInt32)NumSections * SectionEntrySize; }
+};
+
+bool CHeader::Parse(const Byte *p)
+{
+ switch (p[4])
+ {
+ case ELF_CLASS_32: Mode64 = false; break;
+ case ELF_CLASS_64: Mode64 = true; break;
+ default: return false;
+ }
+ bool be;
+ switch (p[5])
+ {
+ case ELF_DATA_2LSB: be = false; break;
+ case ELF_DATA_2MSB: be = true; break;
+ default: return false;
+ }
+ Be = be;
+ if (p[6] != 1) // Version
+ return false;
+ Os = p[7];
+ AbiVer = p[8];
+ for (int i = 9; i < 16; i++)
+ if (p[i] != 0)
+ return false;
+
+ G16(0x10, Type);
+ G16(0x12, Machine);
+ if (Get32(p + 0x14, be) != 1) // Version
+ return false;
+
+ if (Mode64)
+ {
+ // G64(0x18, EntryVa);
+ G64(0x20, ProgOffset);
+ G64(0x28, SectOffset);
+ p += 0x30;
+ }
+ else
+ {
+ // G32(0x18, EntryVa);
+ G32(0x1C, ProgOffset);
+ G32(0x20, SectOffset);
+ p += 0x24;
+ }
+
+ G32(0, Flags);
+ G16(4, HeaderSize);
+ if (HeaderSize != (Mode64 ? kHeaderSize64 : kHeaderSize32))
+ return false;
+
+ G16(6, SegmentEntrySize);
+ G16(8, NumSegments);
+ G16(10, SectionEntrySize);
+ G16(12, NumSections);
+ G16(14, NamesSectIndex);
+
+ if (ProgOffset < HeaderSize && (ProgOffset != 0 || NumSegments != 0)) return false;
+ if (SectOffset < HeaderSize && (SectOffset != 0 || NumSections != 0)) return false;
+
+ if (SegmentEntrySize == 0) { if (NumSegments != 0) return false; }
+ else if (SegmentEntrySize != (Mode64 ? kSegmentSize64 : kSegmentSize32)) return false;
+
+ if (SectionEntrySize == 0) { if (NumSections != 0) return false; }
+ else if (SectionEntrySize != (Mode64 ? kSectionSize64 : kSectionSize32)) return false;
+
+ return true;
+}
+
+// The program header table itself.
+
+#define PT_PHDR 6
+
+static const CUInt32PCharPair g_SegnmentTypes[] =
+{
+ { 0, "Unused" },
+ { 1, "Loadable segment" },
+ { 2, "Dynamic linking tables" },
+ { 3, "Program interpreter path name" },
+ { 4, "Note section" },
+ { 5, "SHLIB" },
+ { 6, "Program header table" },
+ { 7, "TLS" },
+ { 0x6474e550, "GNU_EH_FRAME" },
+ { 0x6474e551, "GNU_STACK" },
+ { 0x6474e552, "GNU_RELRO" }
+};
+
+
+static const char * const g_SegmentFlags[] =
+{
+ "Execute"
+ , "Write"
+ , "Read"
+};
+
+struct CSegment
+{
+ UInt32 Type;
+ UInt32 Flags;
+ UInt64 Offset;
+ UInt64 Va;
+ // UInt64 Pa;
+ UInt64 Size;
+ UInt64 VSize;
+ UInt64 Align;
+
+ void UpdateTotalSize(UInt64 &totalSize)
+ {
+ UInt64 t = Offset + Size;
+ if (totalSize < t)
+ totalSize = t;
+ }
+ void Parse(const Byte *p, bool mode64, bool be);
+};
+
+void CSegment::Parse(const Byte *p, bool mode64, bool be)
+{
+ G32(0, Type);
+ if (mode64)
+ {
+ G32(4, Flags);
+ G64(8, Offset);
+ G64(0x10, Va);
+ // G64(0x18, Pa);
+ G64(0x20, Size);
+ G64(0x28, VSize);
+ G64(0x30, Align);
+ }
+ else
+ {
+ G32(4, Offset);
+ G32(8, Va);
+ // G32(0x0C, Pa);
+ G32(0x10, Size);
+ G32(0x14, VSize);
+ G32(0x18, Flags);
+ G32(0x1C, Align);
+ }
+}
+
+// Section_index = 0 means NO section
+
+#define SHN_UNDEF 0
+
+// Section types
+
+/*
+#define SHT_NULL 0
+#define SHT_PROGBITS 1
+#define SHT_SYMTAB 2
+#define SHT_STRTAB 3
+#define SHT_RELA 4
+#define SHT_HASH 5
+#define SHT_DYNAMIC 6
+#define SHT_NOTE 7
+*/
+#define SHT_NOBITS 8
+/*
+#define SHT_REL 9
+#define SHT_SHLIB 10
+#define SHT_DYNSYM 11
+#define SHT_UNKNOWN12 12
+#define SHT_UNKNOWN13 13
+#define SHT_INIT_ARRAY 14
+#define SHT_FINI_ARRAY 15
+#define SHT_PREINIT_ARRAY 16
+#define SHT_GROUP 17
+#define SHT_SYMTAB_SHNDX 18
+*/
+
+static const CUInt32PCharPair g_SectTypes[] =
+{
+ { 0, "NULL" },
+ { 1, "PROGBITS" },
+ { 2, "SYMTAB" },
+ { 3, "STRTAB" },
+ { 4, "RELA" },
+ { 5, "HASH" },
+ { 6, "DYNAMIC" },
+ { 7, "NOTE" },
+ { 8, "NOBITS" },
+ { 9, "REL" },
+ { 10, "SHLIB" },
+ { 11, "DYNSYM" },
+ { 12, "UNKNOWN12" },
+ { 13, "UNKNOWN13" },
+ { 14, "INIT_ARRAY" },
+ { 15, "FINI_ARRAY" },
+ { 16, "PREINIT_ARRAY" },
+ { 17, "GROUP" },
+ { 18, "SYMTAB_SHNDX" },
+
+ { 0x6ffffff5, "GNU_ATTRIBUTES" },
+ { 0x6ffffff6, "GNU_HASH" },
+ { 0x6ffffffd, "GNU_verdef" },
+ { 0x6ffffffe, "GNU_verneed" },
+ { 0x6fffffff, "GNU_versym" },
+ // { 0x70000001, "X86_64_UNWIND" },
+ { 0x70000001, "ARM_EXIDX" },
+ { 0x70000002, "ARM_PREEMPTMAP" },
+ { 0x70000003, "ARM_ATTRIBUTES" },
+ { 0x70000004, "ARM_DEBUGOVERLAY" },
+ { 0x70000005, "ARM_OVERLAYSECTION" }
+};
+
+static const CUInt32PCharPair g_SectionFlags[] =
+{
+ { 0, "WRITE" },
+ { 1, "ALLOC" },
+ { 2, "EXECINSTR" },
+
+ { 4, "MERGE" },
+ { 5, "STRINGS" },
+ { 6, "INFO_LINK" },
+ { 7, "LINK_ORDER" },
+ { 8, "OS_NONCONFORMING" },
+ { 9, "GROUP" },
+ { 10, "TLS" },
+ { 11, "CP_SECTION" },
+ { 12, "DP_SECTION" },
+ { 13, "XCORE_SHF_CP_SECTION" },
+ { 28, "64_LARGE" },
+};
+
+struct CSection
+{
+ UInt32 Name;
+ UInt32 Type;
+ UInt64 Flags;
+ UInt64 Va;
+ UInt64 Offset;
+ UInt64 VSize;
+ UInt32 Link;
+ UInt32 Info;
+ UInt64 AddrAlign;
+ UInt64 EntSize;
+
+ UInt64 GetSize() const { return Type == SHT_NOBITS ? 0 : VSize; }
+
+ void UpdateTotalSize(UInt64 &totalSize)
+ {
+ UInt64 t = Offset + GetSize();
+ if (totalSize < t)
+ totalSize = t;
+ }
+ bool Parse(const Byte *p, bool mode64, bool be);
+};
+
+bool CSection::Parse(const Byte *p, bool mode64, bool be)
+{
+ G32(0, Name);
+ G32(4, Type);
+ if (mode64)
+ {
+ G64(0x08, Flags);
+ G64(0x10, Va);
+ G64(0x18, Offset);
+ G64(0x20, VSize);
+ G32(0x28, Link);
+ G32(0x2C, Info);
+ G64(0x30, AddrAlign);
+ G64(0x38, EntSize);
+ }
+ else
+ {
+ G32(0x08, Flags);
+ G32(0x0C, Va);
+ G32(0x10, Offset);
+ G32(0x14, VSize);
+ G32(0x18, Link);
+ G32(0x1C, Info);
+ G32(0x20, AddrAlign);
+ G32(0x24, EntSize);
+ }
+ if (EntSize >= ((UInt32)1 << 31))
+ return false;
+ if (EntSize >= ((UInt32)1 << 10) &&
+ EntSize >= VSize &&
+ VSize != 0)
+ return false;
+ return true;
+}
+
+
+static const char * const g_Machines[] =
+{
+ "None"
+ , "AT&T WE 32100"
+ , "SPARC"
+ , "Intel 386"
+ , "Motorola 68000"
+ , "Motorola 88000"
+ , "Intel 486"
+ , "Intel i860"
+ , "MIPS"
+ , "IBM S/370"
+ , "MIPS RS3000 LE"
+ , "RS6000"
+ , NULL
+ , NULL
+ , NULL
+ , "PA-RISC"
+ , "nCUBE"
+ , "Fujitsu VPP500"
+ , "SPARC 32+"
+ , "Intel i960"
+ , "PowerPC"
+ , "PowerPC 64-bit"
+ , "IBM S/390"
+ , "SPU"
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , "NEX v800"
+ , "Fujitsu FR20"
+ , "TRW RH-32"
+ , "Motorola RCE"
+ , "ARM"
+ , "Alpha"
+ , "Hitachi SH"
+ , "SPARC-V9"
+ , "Siemens Tricore"
+ , "ARC"
+ , "H8/300"
+ , "H8/300H"
+ , "H8S"
+ , "H8/500"
+ , "IA-64"
+ , "Stanford MIPS-X"
+ , "Motorola ColdFire"
+ , "M68HC12"
+ , "Fujitsu MMA"
+ , "Siemens PCP"
+ , "Sony nCPU"
+ , "Denso NDR1"
+ , "Motorola StarCore"
+ , "Toyota ME16"
+ , "ST100"
+ , "Advanced Logic TinyJ"
+ , "AMD64"
+ , "Sony DSP"
+ , NULL
+ , NULL
+ , "Siemens FX66"
+ , "ST9+"
+ , "ST7"
+ , "MC68HC16"
+ , "MC68HC11"
+ , "MC68HC08"
+ , "MC68HC05"
+ , "Silicon Graphics SVx"
+ , "ST19"
+ , "Digital VAX"
+ , "Axis CRIS"
+ , "Infineon JAVELIN"
+ , "Element 14 FirePath"
+ , "LSI ZSP"
+ , "MMIX"
+ , "HUANY"
+ , "SiTera Prism"
+ , "Atmel AVR"
+ , "Fujitsu FR30"
+ , "Mitsubishi D10V"
+ , "Mitsubishi D30V"
+ , "NEC v850"
+ , "Mitsubishi M32R"
+ , "Matsushita MN10300"
+ , "Matsushita MN10200"
+ , "picoJava"
+ , "OpenRISC"
+ , "ARC Tangent-A5"
+ , "Tensilica Xtensa"
+ , "Alphamosaic VideoCore"
+ , "Thompson MM GPP"
+ , "National Semiconductor 32K"
+ , "Tenor Network TPC"
+ , "Trebia SNP 1000"
+ , "ST200"
+ , "Ubicom IP2xxx"
+ , "MAX"
+ , "NS CompactRISC"
+ , "Fujitsu F2MC16"
+ , "TI msp430"
+ , "Blackfin (DSP)"
+ , "SE S1C33"
+ , "Sharp embedded"
+ , "Arca RISC"
+ , "Unicore"
+ , "eXcess"
+ , "DXP"
+ , "Altera Nios II"
+ , "NS CRX"
+ , "Motorola XGATE"
+ , "Infineon C16x/XC16x"
+ , "Renesas M16C"
+ , "Microchip Technology dsPIC30F"
+ , "Freescale CE"
+ , "Renesas M32C"
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , "Altium TSK3000"
+ , "Freescale RS08"
+ , "Analog Devices SHARC"
+ , "Cyan Technology eCOG2"
+ , "Sunplus S+core7 RISC"
+ , "NJR 24-bit DSP"
+ , "Broadcom VideoCore III"
+ , "Lattice FPGA"
+ , "SE C17"
+ , "TI TMS320C6000"
+ , "TI TMS320C2000"
+ , "TI TMS320C55x"
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , "STM 64bit VLIW Data Signal"
+ , "Cypress M8C"
+ , "Renesas R32C"
+ , "NXP TriMedia"
+ , "Qualcomm Hexagon"
+ , "Intel 8051"
+ , "STMicroelectronics STxP7x"
+ , "Andes"
+ , "Cyan Technology eCOG1X"
+ , "Dallas Semiconductor MAXQ30"
+ , "NJR 16-bit DSP"
+ , "M2000"
+ , "Cray NV2"
+ , "Renesas RX"
+ , "Imagination Technologies META"
+ , "MCST Elbrus"
+ , "Cyan Technology eCOG16"
+ , "National Semiconductor CR16"
+ , "Freescale ETPUnit"
+ , "Infineon SLE9X"
+ , "Intel L10M"
+ , "Intel K10M"
+ , NULL
+ , "ARM64"
+ , NULL
+ , "Atmel AVR32"
+ , "STM8"
+ , "Tilera TILE64"
+ , "Tilera TILEPro"
+ , "Xilinx MicroBlaze"
+ , "NVIDIA CUDA"
+ , "Tilera TILE-Gx"
+ , "CloudShield"
+ , "KIPO-KAIST Core-A 1st"
+ , "KIPO-KAIST Core-A 2nd"
+ , "Synopsys ARCompact V2"
+ , "Open8"
+ , "Renesas RL78"
+ , "Broadcom VideoCore V"
+ , "Renesas 78KOR"
+ , "Freescale 56800EX" // 200
+};
+
+static const CUInt32PCharPair g_MachinePairs[] =
+{
+ { 243, "RISC-V" },
+ { 47787, "Xilinx MicroBlaze" }
+ // { 0x9026, "Alpha" }
+};
+
+static const CUInt32PCharPair g_OS[] =
+{
+ { 0, "None" },
+ { 1, "HP-UX" },
+ { 2, "NetBSD" },
+ { 3, "Linux" },
+ { 4, "Hurd" },
+
+ { 6, "Solaris" },
+ { 7, "AIX" },
+ { 8, "IRIX" },
+ { 9, "FreeBSD" },
+ { 10, "TRU64" },
+ { 11, "Novell Modesto" },
+ { 12, "OpenBSD" },
+ { 13, "OpenVMS" },
+ { 14, "HP NSK" },
+ { 15, "AROS" },
+ { 16, "FenixOS" },
+ { 64, "Bare-metal TMS320C6000" },
+ { 65, "Linux TMS320C6000" },
+ { 97, "ARM" },
+ { 255, "Standalone" }
+};
+
+#define k_Machine_MIPS 8
+#define k_Machine_ARM 40
+
+/*
+#define EF_ARM_ABIMASK 0xFF000000
+#define EF_ARM_BE8 0x00800000
+#define EF_ARM_GCCMASK 0x00400FFF
+#define EF_ARM_ABI_FLOAT_SOFT 0x00000200
+#define EF_ARM_ABI_FLOAT_HARD 0x00000400
+*/
+
+static const CUInt32PCharPair g_ARM_Flags[] =
+{
+ { 1, "HasEntry" },
+ { 9, "SF" },
+ { 10, "HF" },
+ { 23, "BE8" }
+};
+
+
+static const CUInt32PCharPair g_MIPS_Flags[] =
+{
+ { 0, "NOREORDER" },
+ { 1, "PIC" },
+ { 2, "CPIC" },
+ { 3, "XGOT" },
+ { 4, "64BIT_WHIRL" },
+ { 5, "ABI2" },
+ { 6, "ABI_ON32" },
+ { 10, "NAN2008" },
+ { 25, "MicroMIPS" },
+ { 26, "M16" },
+ { 27, "MDMX" }
+};
+
+
+// #define ET_NONE 0
+#define ET_REL 1
+// #define ET_EXEC 2
+#define ET_DYN 3
+// #define ET_CORE 4
+
+static const char * const g_Types[] =
+{
+ "None"
+ , "Relocatable file"
+ , "Executable file"
+ , "Shared object file"
+ , "Core file"
+};
+
+
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IArchiveAllowTail
+)
+ CRecordVector<CSegment> _segments;
+ CRecordVector<CSection> _sections;
+ CByteBuffer _namesData;
+ CMyComPtr<IInStream> _inStream;
+ UInt64 _totalSize;
+ CHeader _header;
+ bool _headersError;
+ bool _allowTail;
+
+ void GetSectionName(UInt32 index, NCOM::CPropVariant &prop, bool showNULL) const;
+ HRESULT Open2(IInStream *stream);
+public:
+ CHandler(): _allowTail(false) {}
+};
+
+void CHandler::GetSectionName(UInt32 index, NCOM::CPropVariant &prop, bool showNULL) const
+{
+ if (index >= _sections.Size())
+ return;
+ const CSection &section = _sections[index];
+ const UInt32 offset = section.Name;
+ if (index == SHN_UNDEF /* && section.Type == SHT_NULL && offset == 0 */)
+ {
+ if (showNULL)
+ prop = "NULL";
+ return;
+ }
+ const Byte *p = _namesData;
+ size_t size = _namesData.Size();
+ for (size_t i = offset; i < size; i++)
+ if (p[i] == 0)
+ {
+ prop = (const char *)(p + offset);
+ return;
+ }
+}
+
+static const Byte kArcProps[] =
+{
+ kpidCpu,
+ kpidBit64,
+ kpidBigEndian,
+ kpidHostOS,
+ kpidCharacts,
+ kpidHeadersSize
+};
+
+enum
+{
+ kpidLinkSection = kpidUserDefined,
+ kpidInfoSection
+};
+
+static const CStatProp kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR },
+ { NULL, kpidSize, VT_UI8 },
+ { NULL, kpidVirtualSize, VT_UI8 },
+ { NULL, kpidOffset, VT_UI8 },
+ { NULL, kpidVa, VT_UI8 },
+ { NULL, kpidType, VT_BSTR },
+ { NULL, kpidCharacts, VT_BSTR }
+ , { "Link Section", kpidLinkSection, VT_BSTR}
+ , { "Info Section", kpidInfoSection, VT_BSTR}
+};
+
+IMP_IInArchive_Props_WITH_NAME
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySize: prop = _totalSize; break;
+ case kpidHeadersSize: prop = _header.GetHeadersSize(); break;
+ case kpidBit64: if (_header.Mode64) prop = _header.Mode64; break;
+ case kpidBigEndian: if (_header.Be) prop = _header.Be; break;
+ case kpidShortComment:
+
+ case kpidCpu:
+ {
+ AString s;
+ if (_header.Machine < Z7_ARRAY_SIZE(g_Machines))
+ {
+ const char *name = g_Machines[_header.Machine];
+ if (name)
+ s = name;
+ }
+ if (s.IsEmpty())
+ s = TypePairToString(g_MachinePairs, Z7_ARRAY_SIZE(g_MachinePairs), _header.Machine);
+ UInt32 flags = _header.Flags;
+ if (flags != 0)
+ {
+ s.Add_Space();
+ if (_header.Machine == k_Machine_ARM)
+ {
+ s += FlagsToString(g_ARM_Flags, Z7_ARRAY_SIZE(g_ARM_Flags), flags & (((UInt32)1 << 24) - 1));
+ s += " ABI:";
+ s.Add_UInt32(flags >> 24);
+ }
+ else if (_header.Machine == k_Machine_MIPS)
+ {
+ const UInt32 ver = flags >> 28;
+ s += "v";
+ s.Add_UInt32(ver);
+ flags &= (((UInt32)1 << 28) - 1);
+
+ UInt32 abi = (flags >> 12) & 7;
+ if (abi != 0)
+ {
+ s += " ABI:";
+ s.Add_UInt32(abi);
+ }
+ flags &= ~((UInt32)7 << 12);
+
+ s.Add_Space();
+ s += FlagsToString(g_MIPS_Flags, Z7_ARRAY_SIZE(g_MIPS_Flags), flags);
+ }
+ else
+ {
+ char sz[16];
+ ConvertUInt32ToHex(flags, sz);
+ s += sz;
+ }
+ }
+ prop = s;
+ break;
+ }
+
+ case kpidHostOS: PAIR_TO_PROP(g_OS, _header.Os, prop); break;
+ case kpidCharacts: TYPE_TO_PROP(g_Types, _header.Type, prop); break;
+ case kpidExtension:
+ {
+ const char *s = NULL;
+ if (_header.Type == ET_DYN)
+ s = "so";
+ else if (_header.Type == ET_REL)
+ s = "o";
+ if (s)
+ prop = s;
+ break;
+ }
+ // case kpidIsSelfExe: prop = (_header.Type != ET_DYN) && (_header.Type == ET_REL); break;
+ case kpidErrorFlags:
+ {
+ UInt32 flags = 0;
+ if (_headersError) flags |= kpv_ErrorFlags_HeadersError;
+ if (flags != 0)
+ prop = flags;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ if (index < _segments.Size())
+ {
+ const CSegment &item = _segments[index];
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ char sz[16];
+ ConvertUInt32ToString(index, sz);
+ prop = sz;
+ break;
+ }
+ case kpidOffset: prop = item.Offset; break;
+ case kpidVa: prop = item.Va; break;
+ case kpidSize:
+ case kpidPackSize: prop = (UInt64)item.Size; break;
+ case kpidVirtualSize: prop = (UInt64)item.VSize; break;
+ case kpidType: PAIR_TO_PROP(g_SegnmentTypes, item.Type, prop); break;
+ case kpidCharacts: FLAGS_TO_PROP(g_SegmentFlags, item.Flags, prop); break;
+
+ }
+ }
+ else
+ {
+ index -= _segments.Size();
+ const CSection &item = _sections[index];
+ switch (propID)
+ {
+ case kpidPath: GetSectionName(index, prop, true); break;
+ case kpidOffset: prop = item.Offset; break;
+ case kpidVa: prop = item.Va; break;
+ case kpidSize:
+ case kpidPackSize: prop = (UInt64)(item.Type == SHT_NOBITS ? 0 : item.VSize); break;
+ case kpidVirtualSize: prop = item.GetSize(); break;
+ case kpidType: PAIR_TO_PROP(g_SectTypes, item.Type, prop); break;
+ case kpidCharacts: FLAGS_TO_PROP(g_SectionFlags, (UInt32)item.Flags, prop); break;
+ case kpidLinkSection: GetSectionName(item.Link, prop, false); break;
+ case kpidInfoSection: GetSectionName(item.Info, prop, false); break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+ const UInt32 kStartSize = kHeaderSize64;
+ Byte h[kStartSize];
+ RINOK(ReadStream_FALSE(stream, h, kStartSize))
+ if (h[0] != 0x7F || h[1] != 'E' || h[2] != 'L' || h[3] != 'F')
+ return S_FALSE;
+ if (!_header.Parse(h))
+ return S_FALSE;
+
+ _totalSize = _header.HeaderSize;
+
+ bool addSegments = false;
+ bool addSections = false;
+
+ if (_header.NumSections > 1)
+ addSections = true;
+ else
+ addSegments = true;
+
+ if (_header.NumSegments != 0)
+ {
+ if (_header.ProgOffset > (UInt64)1 << 60) return S_FALSE;
+ RINOK(InStream_SeekSet(stream, _header.ProgOffset))
+ const size_t size = (size_t)_header.SegmentEntrySize * _header.NumSegments;
+
+ CByteArr buf(size);
+
+ RINOK(ReadStream_FALSE(stream, buf, size))
+
+ const UInt64 total = _header.ProgOffset + size;
+ if (_totalSize < total)
+ _totalSize = total;
+
+ const Byte *p = buf;
+
+ if (addSegments)
+ _segments.ClearAndReserve(_header.NumSegments);
+ for (unsigned i = 0; i < _header.NumSegments; i++, p += _header.SegmentEntrySize)
+ {
+ CSegment seg;
+ seg.Parse(p, _header.Mode64, _header.Be);
+ seg.UpdateTotalSize(_totalSize);
+ if (addSegments)
+ if (seg.Type != PT_PHDR)
+ _segments.AddInReserved(seg);
+ }
+ }
+
+ if (_header.NumSections != 0)
+ {
+ if (_header.SectOffset > (UInt64)1 << 60) return S_FALSE;
+ RINOK(InStream_SeekSet(stream, _header.SectOffset))
+ size_t size = (size_t)_header.SectionEntrySize * _header.NumSections;
+
+ CByteArr buf(size);
+
+ RINOK(ReadStream_FALSE(stream, buf, size))
+
+ UInt64 total = _header.SectOffset + size;
+ if (_totalSize < total)
+ _totalSize = total;
+
+ const Byte *p = buf;
+
+ if (addSections)
+ _sections.ClearAndReserve(_header.NumSections);
+ for (unsigned i = 0; i < _header.NumSections; i++, p += _header.SectionEntrySize)
+ {
+ CSection sect;
+ if (!sect.Parse(p, _header.Mode64, _header.Be))
+ {
+ _headersError = true;
+ return S_FALSE;
+ }
+ sect.UpdateTotalSize(_totalSize);
+ if (addSections)
+ _sections.AddInReserved(sect);
+ }
+ }
+
+ if (addSections)
+ {
+ if (_header.NamesSectIndex < _sections.Size())
+ {
+ const CSection &sect = _sections[_header.NamesSectIndex];
+ const UInt64 size = sect.GetSize();
+ if (size != 0
+ && size < ((UInt64)1 << 31)
+ && (Int64)sect.Offset >= 0)
+ {
+ _namesData.Alloc((size_t)size);
+ RINOK(InStream_SeekSet(stream, sect.Offset))
+ RINOK(ReadStream_FALSE(stream, _namesData, (size_t)size))
+ }
+ }
+
+ /*
+ // we will not delete NULL sections, since we have links to section via indexes
+ for (int i = _sections.Size() - 1; i >= 0; i--)
+ if (_sections[i].Type == SHT_NULL)
+ _items.Delete(i);
+ */
+ }
+
+ if (!_allowTail)
+ {
+ UInt64 fileSize;
+ RINOK(InStream_GetSize_SeekToEnd(stream, fileSize))
+ if (fileSize > _totalSize)
+ return S_FALSE;
+ }
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */))
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(Open2(inStream))
+ _inStream = inStream;
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _totalSize = 0;
+ _headersError = false;
+
+ _inStream.Release();
+ _segments.Clear();
+ _sections.Clear();
+ _namesData.Free();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _segments.Size() + _sections.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _segments.Size() + _sections.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const UInt32 index = allFilesMode ? i : indices[i];
+ totalSize += (index < _segments.Size()) ?
+ _segments[index].Size :
+ _sections[index - _segments.Size()].GetSize();
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+ UInt64 currentItemSize;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_inStream);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur())
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ UInt64 offset;
+ if (index < _segments.Size())
+ {
+ const CSegment &item = _segments[index];
+ currentItemSize = item.Size;
+ offset = item.Offset;
+ }
+ else
+ {
+ const CSection &item = _sections[index - _segments.Size()];
+ currentItemSize = item.GetSize();
+ offset = item.Offset;
+ }
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ RINOK(extractCallback->GetStream(index, &outStream, askMode))
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(InStream_SeekSet(_inStream, offset))
+ streamSpec->Init(currentItemSize);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress))
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::AllowTail(Int32 allowTail))
+{
+ _allowTail = IntToBool(allowTail);
+ return S_OK;
+}
+
+static const Byte k_Signature[] = { 0x7F, 'E', 'L', 'F' };
+
+REGISTER_ARC_I(
+ "ELF", "elf", NULL, 0xDE,
+ k_Signature,
+ 0,
+ NArcInfoFlags::kPreArc,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/ExtHandler.cpp b/CPP/7zip/Archive/ExtHandler.cpp
new file mode 100644
index 0000000..f309485
--- /dev/null
+++ b/CPP/7zip/Archive/ExtHandler.cpp
@@ -0,0 +1,2869 @@
+// ExtHandler.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+// #include <stdio.h>
+// #define PRF2(x) x
+
+#define PRF2(x)
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#include "../../../C/Alloc.h"
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/MyLinux.h"
+#include "../../Common/StringConvert.h"
+#include "../../Common/UTFConvert.h"
+
+#include "../../Windows/PropVariantUtils.h"
+#include "../../Windows/TimeUtils.h"
+
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+using namespace NWindows;
+
+UInt32 LzhCrc16Update(UInt32 crc, const void *data, size_t size);
+
+namespace NArchive {
+namespace NExt {
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+#define LE_16(offs, dest) dest = Get16(p + (offs));
+#define LE_32(offs, dest) dest = Get32(p + (offs));
+#define LE_64(offs, dest) dest = Get64(p + (offs));
+
+#define HI_16(offs, dest) dest |= (((UInt32)Get16(p + (offs))) << 16);
+#define HI_32(offs, dest) dest |= (((UInt64)Get32(p + (offs))) << 32);
+
+/*
+static UInt32 g_Crc32CTable[256];
+
+static struct CInitCrc32C
+{
+ CInitCrc32C()
+ {
+ for (unsigned i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ unsigned j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (0x82F63B78 & ~((r & 1) - 1));
+ g_Crc32CTable[i] = r;
+ }
+ }
+} g_InitCrc32C;
+
+#define CRC32C_INIT_VAL 0xFFFFFFFF
+#define CRC32C_GET_DIGEST(crc) ((crc) ^ CRC_INIT_VAL)
+#define CRC32C_UPDATE_BYTE(crc, b) (g_Crc32CTable[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+static UInt32 Crc32C_Update(UInt32 crc, Byte const *data, size_t size)
+{
+ for (size_t i = 0; i < size; i++)
+ crc = CRC32C_UPDATE_BYTE(crc, data[i]);
+ return crc;
+}
+
+static UInt32 Crc32C_Calc(Byte const *data, size_t size)
+{
+ return Crc32C_Update(CRC32C_INIT_VAL, data, size);
+}
+*/
+
+
+#define CRC16_INIT_VAL 0xFFFF
+
+#define Crc16Update(crc, data, size) LzhCrc16Update(crc, data, size)
+
+static UInt32 Crc16Calc(Byte const *data, size_t size)
+{
+ return Crc16Update(CRC16_INIT_VAL, data, size);
+}
+
+
+#define EXT4_GOOD_OLD_INODE_SIZE 128
+#define EXT_NODE_SIZE_MIN 128
+
+
+// inodes numbers
+
+// #define k_INODE_BAD 1 // Bad blocks
+#define k_INODE_ROOT 2 // Root dir
+// #define k_INODE_USR_QUOTA 3 // User quota
+// #define k_INODE_GRP_QUOTA 4 // Group quota
+// #define k_INODE_BOOT_LOADER 5 // Boot loader
+// #define k_INODE_UNDEL_DIR 6 // Undelete dir
+#define k_INODE_RESIZE 7 // Reserved group descriptors
+// #define k_INODE_JOURNAL 8 // Journal
+
+// First non-reserved inode for old ext4 filesystems
+#define k_INODE_GOOD_OLD_FIRST 11
+
+static const char * const k_SysInode_Names[] =
+{
+ "0"
+ , "Bad"
+ , "Root"
+ , "UserQuota"
+ , "GroupQuota"
+ , "BootLoader"
+ , "Undelete"
+ , "Resize"
+ , "Journal"
+ , "Exclude"
+ , "Replica"
+};
+
+static const char * const kHostOS[] =
+{
+ "Linux"
+ , "Hurd"
+ , "Masix"
+ , "FreeBSD"
+ , "Lites"
+};
+
+static const char * const g_FeatureCompat_Flags[] =
+{
+ "DIR_PREALLOC"
+ , "IMAGIC_INODES"
+ , "HAS_JOURNAL"
+ , "EXT_ATTR"
+ , "RESIZE_INODE"
+ , "DIR_INDEX"
+ , "LAZY_BG" // not in Linux
+ , NULL // { 7, "EXCLUDE_INODE" // not used
+ , NULL // { 8, "EXCLUDE_BITMAP" // not in kernel
+ , "SPARSE_SUPER2"
+};
+
+
+#define EXT4_FEATURE_INCOMPAT_FILETYPE (1 << 1)
+#define EXT4_FEATURE_INCOMPAT_64BIT (1 << 7)
+
+static const char * const g_FeatureIncompat_Flags[] =
+{
+ "COMPRESSION"
+ , "FILETYPE"
+ , "RECOVER" /* Needs recovery */
+ , "JOURNAL_DEV" /* Journal device */
+ , "META_BG"
+ , NULL
+ , "EXTENTS" /* extents support */
+ , "64BIT"
+ , "MMP"
+ , "FLEX_BG"
+ , "EA_INODE" /* EA in inode */
+ , NULL
+ , "DIRDATA" /* data in dirent */
+ , "BG_USE_META_CSUM" /* use crc32c for bg */
+ , "LARGEDIR" /* >2GB or 3-lvl htree */
+ , "INLINE_DATA" /* data in inode */
+ , "ENCRYPT" // 16
+};
+
+
+static const UInt32 RO_COMPAT_GDT_CSUM = 1 << 4;
+static const UInt32 RO_COMPAT_METADATA_CSUM = 1 << 10;
+
+static const char * const g_FeatureRoCompat_Flags[] =
+{
+ "SPARSE_SUPER"
+ , "LARGE_FILE"
+ , "BTREE_DIR"
+ , "HUGE_FILE"
+ , "GDT_CSUM"
+ , "DIR_NLINK"
+ , "EXTRA_ISIZE"
+ , "HAS_SNAPSHOT"
+ , "QUOTA"
+ , "BIGALLOC"
+ , "METADATA_CSUM"
+ , "REPLICA"
+ , "READONLY" // 12
+};
+
+
+
+static const UInt32 k_NodeFlags_HUGE = (UInt32)1 << 18;
+static const UInt32 k_NodeFlags_EXTENTS = (UInt32)1 << 19;
+
+
+static const char * const g_NodeFlags[] =
+{
+ "SECRM"
+ , "UNRM"
+ , "COMPR"
+ , "SYNC"
+ , "IMMUTABLE"
+ , "APPEND"
+ , "NODUMP"
+ , "NOATIME"
+ , "DIRTY"
+ , "COMPRBLK"
+ , "NOCOMPR"
+ , "ENCRYPT"
+ , "INDEX"
+ , "IMAGIC"
+ , "JOURNAL_DATA"
+ , "NOTAIL"
+ , "DIRSYNC"
+ , "TOPDIR"
+ , "HUGE_FILE"
+ , "EXTENTS"
+ , NULL
+ , "EA_INODE"
+ , "EOFBLOCKS"
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , "INLINE_DATA" // 28
+};
+
+
+static inline char GetHex(unsigned t) { return (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))); }
+
+static inline void PrintHex(unsigned v, char *s)
+{
+ s[0] = GetHex((v >> 4) & 0xF);
+ s[1] = GetHex(v & 0xF);
+}
+
+
+enum
+{
+ k_Type_UNKNOWN,
+ k_Type_REG_FILE,
+ k_Type_DIR,
+ k_Type_CHRDEV,
+ k_Type_BLKDEV,
+ k_Type_FIFO,
+ k_Type_SOCK,
+ k_Type_SYMLINK
+};
+
+static const UInt16 k_TypeToMode[] =
+{
+ 0,
+ MY_LIN_S_IFREG,
+ MY_LIN_S_IFDIR,
+ MY_LIN_S_IFCHR,
+ MY_LIN_S_IFBLK,
+ MY_LIN_S_IFIFO,
+ MY_LIN_S_IFSOCK,
+ MY_LIN_S_IFLNK
+};
+
+
+#define EXT4_GOOD_OLD_REV 0 // old (original) format
+// #define EXT4_DYNAMIC_REV 1 // V2 format with dynamic inode sizes
+
+struct CHeader
+{
+ unsigned BlockBits;
+ unsigned ClusterBits;
+
+ UInt32 NumInodes;
+ UInt64 NumBlocks;
+ // UInt64 NumBlocksSuper;
+ UInt64 NumFreeBlocks;
+ UInt32 NumFreeInodes;
+ // UInt32 FirstDataBlock;
+
+ UInt32 BlocksPerGroup;
+ UInt32 ClustersPerGroup;
+ UInt32 InodesPerGroup;
+
+ UInt32 MountTime;
+ UInt32 WriteTime;
+
+ // UInt16 NumMounts;
+ // UInt16 NumMountsMax;
+
+ // UInt16 State;
+ // UInt16 Errors;
+ // UInt16 MinorRevLevel;
+
+ UInt32 LastCheckTime;
+ // UInt32 CheckInterval;
+ UInt32 CreatorOs;
+ UInt32 RevLevel;
+
+ // UInt16 DefResUid;
+ // UInt16 DefResGid;
+
+ UInt32 FirstInode;
+ UInt16 InodeSize;
+ UInt16 BlockGroupNr;
+ UInt32 FeatureCompat;
+ UInt32 FeatureIncompat;
+ UInt32 FeatureRoCompat;
+ Byte Uuid[16];
+ char VolName[16];
+ char LastMount[64];
+ // UInt32 BitmapAlgo;
+
+ UInt32 JournalInode;
+ UInt16 GdSize; // = 64 if 64-bit();
+ UInt32 CTime;
+ UInt16 MinExtraISize;
+ // UInt16 WantExtraISize;
+ // UInt32 Flags;
+ // Byte LogGroupsPerFlex;
+ // Byte ChecksumType;
+
+ UInt64 WrittenKB;
+
+ bool IsOldRev() const { return RevLevel == EXT4_GOOD_OLD_REV; }
+
+ UInt64 GetNumGroups() const { return (NumBlocks + BlocksPerGroup - 1) / BlocksPerGroup; }
+ UInt64 GetNumGroups2() const { return ((UInt64)NumInodes + InodesPerGroup - 1) / InodesPerGroup; }
+
+ bool IsThereFileType() const { return (FeatureIncompat & EXT4_FEATURE_INCOMPAT_FILETYPE) != 0; }
+ bool Is64Bit() const { return (FeatureIncompat & EXT4_FEATURE_INCOMPAT_64BIT) != 0; }
+ bool UseGdtChecksum() const { return (FeatureRoCompat & RO_COMPAT_GDT_CSUM) != 0; }
+ bool UseMetadataChecksum() const { return (FeatureRoCompat & RO_COMPAT_METADATA_CSUM) != 0; }
+
+ UInt64 GetPhySize() const { return NumBlocks << BlockBits; }
+
+ bool Parse(const Byte *p);
+};
+
+
+static int inline GetLog(UInt32 num)
+{
+ for (unsigned i = 0; i < 32; i++)
+ if (((UInt32)1 << i) == num)
+ return (int)i;
+ return -1;
+}
+
+static bool inline IsEmptyData(const Byte *data, unsigned size)
+{
+ for (unsigned i = 0; i < size; i++)
+ if (data[i] != 0)
+ return false;
+ return true;
+}
+
+
+bool CHeader::Parse(const Byte *p)
+{
+ if (GetUi16(p + 0x38) != 0xEF53)
+ return false;
+
+ LE_32 (0x18, BlockBits)
+ LE_32 (0x1C, ClusterBits)
+
+ if (ClusterBits != 0 && BlockBits != ClusterBits)
+ return false;
+
+ if (BlockBits > 16 - 10)
+ return false;
+ BlockBits += 10;
+
+ LE_32 (0x00, NumInodes)
+ LE_32 (0x04, NumBlocks)
+ // LE_32 (0x08, NumBlocksSuper);
+ LE_32 (0x0C, NumFreeBlocks)
+ LE_32 (0x10, NumFreeInodes)
+
+ if (NumInodes < 2 || NumInodes <= NumFreeInodes)
+ return false;
+
+ UInt32 FirstDataBlock;
+ LE_32 (0x14, FirstDataBlock)
+ if (FirstDataBlock != (unsigned)(BlockBits == 10 ? 1 : 0))
+ return false;
+
+ LE_32 (0x20, BlocksPerGroup)
+ LE_32 (0x24, ClustersPerGroup)
+
+ if (BlocksPerGroup != ClustersPerGroup)
+ return false;
+ if (BlocksPerGroup == 0)
+ return false;
+ if (BlocksPerGroup != ((UInt32)1 << (BlockBits + 3)))
+ {
+ // it's allowed in ext2
+ // return false;
+ }
+
+ LE_32 (0x28, InodesPerGroup)
+
+ if (InodesPerGroup < 1 || InodesPerGroup > NumInodes)
+ return false;
+
+ LE_32 (0x2C, MountTime)
+ LE_32 (0x30, WriteTime)
+
+ // LE_16 (0x34, NumMounts);
+ // LE_16 (0x36, NumMountsMax);
+
+ // LE_16 (0x3A, State);
+ // LE_16 (0x3C, Errors);
+ // LE_16 (0x3E, MinorRevLevel);
+
+ LE_32 (0x40, LastCheckTime)
+ // LE_32 (0x44, CheckInterval);
+ LE_32 (0x48, CreatorOs)
+ LE_32 (0x4C, RevLevel)
+
+ // LE_16 (0x50, DefResUid);
+ // LE_16 (0x52, DefResGid);
+
+ FirstInode = k_INODE_GOOD_OLD_FIRST;
+ InodeSize = EXT4_GOOD_OLD_INODE_SIZE;
+
+ if (!IsOldRev())
+ {
+ LE_32 (0x54, FirstInode)
+ LE_16 (0x58, InodeSize)
+ if (FirstInode < k_INODE_GOOD_OLD_FIRST)
+ return false;
+ if (InodeSize > ((UInt32)1 << BlockBits)
+ || InodeSize < EXT_NODE_SIZE_MIN
+ || GetLog(InodeSize) < 0)
+ return false;
+ }
+
+ LE_16 (0x5A, BlockGroupNr)
+ LE_32 (0x5C, FeatureCompat)
+ LE_32 (0x60, FeatureIncompat)
+ LE_32 (0x64, FeatureRoCompat)
+
+ memcpy(Uuid, p + 0x68, sizeof(Uuid));
+ memcpy(VolName, p + 0x78, sizeof(VolName));
+ memcpy(LastMount, p + 0x88, sizeof(LastMount));
+
+ // LE_32 (0xC8, BitmapAlgo);
+
+ LE_32 (0xE0, JournalInode)
+
+ LE_16 (0xFE, GdSize)
+
+ LE_32 (0x108, CTime)
+
+ if (Is64Bit())
+ {
+ HI_32(0x150, NumBlocks)
+ // HI_32(0x154, NumBlocksSuper);
+ HI_32(0x158, NumFreeBlocks)
+ }
+
+ if (NumBlocks >= (UInt64)1 << (63 - BlockBits))
+ return false;
+
+
+ LE_16(0x15C, MinExtraISize)
+ // LE_16(0x15E, WantExtraISize);
+ // LE_32(0x160, Flags);
+ // LE_16(0x164, RaidStride);
+ // LE_16(0x166, MmpInterval);
+ // LE_64(0x168, MmpBlock);
+
+ // LogGroupsPerFlex = p[0x174];
+ // ChecksumType = p[0x175];
+
+ LE_64 (0x178, WrittenKB)
+
+ // LE_32(0x194, ErrorCount);
+ // LE_32(0x198, ErrorTime);
+ // LE_32(0x19C, ErrorINode);
+ // LE_32(0x1A0, ErrorBlock);
+
+ if (NumBlocks < 1)
+ return false;
+ if (NumFreeBlocks > NumBlocks)
+ return false;
+
+ if (GetNumGroups() != GetNumGroups2())
+ return false;
+
+ return true;
+}
+
+
+struct CGroupDescriptor
+{
+ UInt64 BlockBitmap;
+ UInt64 InodeBitmap;
+ UInt64 InodeTable;
+ UInt32 NumFreeBlocks;
+ UInt32 NumFreeInodes;
+ UInt32 DirCount;
+
+ UInt16 Flags;
+
+ UInt64 ExcludeBitmap;
+ UInt32 BlockBitmap_Checksum;
+ UInt32 InodeBitmap_Checksum;
+ UInt32 UnusedCount;
+ UInt16 Checksum;
+
+ void Parse(const Byte *p, unsigned size);
+};
+
+void CGroupDescriptor::Parse(const Byte *p, unsigned size)
+{
+ LE_32 (0x00, BlockBitmap)
+ LE_32 (0x04, InodeBitmap)
+ LE_32 (0x08, InodeTable)
+ LE_16 (0x0C, NumFreeBlocks)
+ LE_16 (0x0E, NumFreeInodes)
+ LE_16 (0x10, DirCount)
+ LE_16 (0x12, Flags)
+ LE_32 (0x14, ExcludeBitmap)
+ LE_16 (0x18, BlockBitmap_Checksum)
+ LE_16 (0x1A, InodeBitmap_Checksum)
+ LE_16 (0x1C, UnusedCount)
+ LE_16 (0x1E, Checksum)
+
+ if (size >= 64)
+ {
+ p += 0x20;
+ HI_32 (0x00, BlockBitmap)
+ HI_32 (0x04, InodeBitmap)
+ HI_32 (0x08, InodeTable)
+ HI_16 (0x0C, NumFreeBlocks)
+ HI_16 (0x0E, NumFreeInodes)
+ HI_16 (0x10, DirCount)
+ HI_16 (0x12, UnusedCount) // instead of Flags
+ HI_32 (0x14, ExcludeBitmap)
+ HI_16 (0x18, BlockBitmap_Checksum)
+ HI_16 (0x1A, InodeBitmap_Checksum)
+ // HI_16 (0x1C, Reserved);
+ }
+}
+
+
+static const unsigned kNodeBlockFieldSize = 60;
+
+struct CExtentTreeHeader
+{
+ UInt16 NumEntries;
+ UInt16 MaxEntries;
+ UInt16 Depth;
+ // UInt32 Generation;
+
+ bool Parse(const Byte *p)
+ {
+ LE_16 (0x02, NumEntries)
+ LE_16 (0x04, MaxEntries)
+ LE_16 (0x06, Depth)
+ // LE_32 (0x08, Generation);
+ return Get16(p) == 0xF30A; // magic
+ }
+};
+
+struct CExtentIndexNode
+{
+ UInt32 VirtBlock;
+ UInt64 PhyLeaf;
+
+ void Parse(const Byte *p)
+ {
+ LE_32 (0x00, VirtBlock)
+ LE_32 (0x04, PhyLeaf)
+ PhyLeaf |= (((UInt64)Get16(p + 8)) << 32);
+ // unused 16-bit field (at offset 0x0A) can be not zero in some cases. Why?
+ }
+};
+
+struct CExtent
+{
+ UInt32 VirtBlock;
+ UInt16 Len;
+ bool IsInited;
+ UInt64 PhyStart;
+
+ UInt32 GetVirtEnd() const { return VirtBlock + Len; }
+ bool IsLenOK() const { return VirtBlock + Len >= VirtBlock; }
+
+ void Parse(const Byte *p)
+ {
+ LE_32 (0x00, VirtBlock)
+ LE_16 (0x04, Len)
+ IsInited = true;
+ if (Len > (UInt32)0x8000)
+ {
+ IsInited = false;
+ Len = (UInt16)(Len - (UInt32)0x8000);
+ }
+ LE_32 (0x08, PhyStart)
+ UInt16 hi;
+ LE_16 (0x06, hi)
+ PhyStart |= ((UInt64)hi << 32);
+ }
+};
+
+
+
+struct CExtTime
+{
+ UInt32 Val;
+ UInt32 Extra;
+};
+
+struct CNode
+{
+ Int32 ParentNode; // in _refs[], -1 if not dir
+ int ItemIndex; // in _items[] , (set as >=0 only for if (IsDir())
+ int SymLinkIndex; // in _symLinks[]
+ int DirIndex; // in _dirs[]
+
+ UInt16 Mode;
+ UInt32 Uid; // fixed 21.02
+ UInt32 Gid; // fixed 21.02
+ // UInt16 Checksum;
+
+ UInt64 FileSize;
+ CExtTime MTime;
+ CExtTime ATime;
+ CExtTime CTime;
+ CExtTime ChangeTime;
+ // CExtTime DTime;
+
+ UInt64 NumBlocks;
+ UInt32 NumLinks;
+ UInt32 Flags;
+
+ UInt32 NumLinksCalced;
+
+ Byte Block[kNodeBlockFieldSize];
+
+ CNode():
+ ParentNode(-1),
+ ItemIndex(-1),
+ SymLinkIndex(-1),
+ DirIndex(-1),
+ NumLinksCalced(0)
+ {}
+
+ bool IsFlags_HUGE() const { return (Flags & k_NodeFlags_HUGE) != 0; }
+ bool IsFlags_EXTENTS() const { return (Flags & k_NodeFlags_EXTENTS) != 0; }
+
+ bool IsDir() const { return MY_LIN_S_ISDIR(Mode); }
+ bool IsRegular() const { return MY_LIN_S_ISREG(Mode); }
+ bool IsLink() const { return MY_LIN_S_ISLNK(Mode); }
+
+ bool Parse(const Byte *p, const CHeader &_h);
+};
+
+
+bool CNode::Parse(const Byte *p, const CHeader &_h)
+{
+ MTime.Extra = 0;
+ ATime.Extra = 0;
+ CTime.Extra = 0;
+ CTime.Val = 0;
+ ChangeTime.Extra = 0;
+ // DTime.Extra = 0;
+
+ LE_16 (0x00, Mode)
+ LE_16 (0x02, Uid)
+ LE_32 (0x04, FileSize)
+ LE_32 (0x08, ATime.Val)
+ LE_32 (0x0C, ChangeTime.Val)
+ LE_32 (0x10, MTime.Val)
+ // LE_32 (0x14, DTime.Val);
+ LE_16 (0x18, Gid)
+ LE_16 (0x1A, NumLinks)
+
+ LE_32 (0x1C, NumBlocks)
+ LE_32 (0x20, Flags)
+ // LE_32 (0x24, Union osd1);
+
+ memcpy(Block, p + 0x28, kNodeBlockFieldSize);
+
+ // LE_32 (0x64, Generation); // File version (for NFS)
+ // LE_32 (0x68, ACL);
+
+ {
+ UInt32 highSize;
+ LE_32 (0x6C, highSize) // In ext2/3 this field was named i_dir_acl
+
+ if (IsRegular()) // do we need that check ?
+ FileSize |= ((UInt64)highSize << 32);
+ }
+
+ // UInt32 fragmentAddress;
+ // LE_32 (0x70, fragmentAddress);
+
+ // osd2
+ {
+ // Linux;
+ // ext2:
+ // Byte FragmentNumber = p[0x74];
+ // Byte FragmentSize = p[0x74 + 1];
+
+ // ext4:
+ UInt32 numBlocksHigh;
+ LE_16 (0x74, numBlocksHigh)
+ NumBlocks |= (UInt64)numBlocksHigh << 32;
+
+ HI_16 (0x74 + 4, Uid)
+ HI_16 (0x74 + 6, Gid)
+ /*
+ UInt32 checksum;
+ LE_16 (0x74 + 8, checksum);
+ checksum = checksum;
+ */
+ }
+
+ // 0x74: Byte Union osd2[12];
+
+ if (_h.InodeSize > 128)
+ {
+ // InodeSize is power of 2, so the following check is not required:
+ // if (_h.InodeSize < 128 + 2) return false;
+ UInt16 extra_isize;
+ LE_16 (0x80, extra_isize)
+ if (128 + extra_isize > _h.InodeSize)
+ return false;
+ if (extra_isize >= 0x1C)
+ {
+ // UInt16 checksumUpper;
+ // LE_16 (0x82, checksumUpper);
+ LE_32 (0x84, ChangeTime.Extra)
+ LE_32 (0x88, MTime.Extra)
+ LE_32 (0x8C, ATime.Extra)
+ LE_32 (0x90, CTime.Val)
+ LE_32 (0x94, CTime.Extra)
+ // LE_32 (0x98, VersionHi)
+ }
+ }
+
+ PRF(printf("size = %5d", (unsigned)FileSize));
+
+ return true;
+}
+
+
+struct CItem
+{
+ unsigned Node; // in _refs[]
+ int ParentNode; // in _refs[]
+ int SymLinkItemIndex; // in _items[], if the Node contains SymLink to existing dir
+ Byte Type;
+
+ AString Name;
+
+ CItem():
+ Node(0),
+ ParentNode(-1),
+ SymLinkItemIndex(-1),
+ Type(k_Type_UNKNOWN)
+ {}
+
+ void Clear()
+ {
+ Node = 0;
+ ParentNode = -1;
+ SymLinkItemIndex = -1;
+ Type = k_Type_UNKNOWN;
+ Name.Empty();
+ }
+
+ bool IsDir() const { return Type == k_Type_DIR; }
+ // bool IsNotDir() const { return Type != k_Type_DIR && Type != k_Type_UNKNOWN; }
+};
+
+
+
+static const unsigned kNumTreeLevelsMax = 6; // must be >= 3
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_2(
+ IArchiveGetRawProps,
+ IInArchiveGetStream
+)
+ CObjectVector<CItem> _items;
+ CIntVector _refs; // iNode -> (index in _nodes). if (_refs[iNode] < 0), that node is not filled
+ CRecordVector<CNode> _nodes;
+ CObjectVector<CUIntVector> _dirs; // each CUIntVector contains indexes in _items[] only for dir items;
+ AStringVector _symLinks;
+ AStringVector _auxItems;
+ int _auxSysIndex;
+ int _auxUnknownIndex;
+
+ CMyComPtr<IInStream> _stream;
+ UInt64 _phySize;
+ bool _isArc;
+ bool _headersError;
+ bool _headersWarning;
+ bool _linksError;
+
+ bool _isUTF;
+
+ CHeader _h;
+
+ IArchiveOpenCallback *_openCallback;
+ UInt64 _totalRead;
+ UInt64 _totalReadPrev;
+
+ CByteBuffer _tempBufs[kNumTreeLevelsMax];
+
+
+ HRESULT CheckProgress2()
+ {
+ const UInt64 numFiles = _items.Size();
+ return _openCallback->SetCompleted(&numFiles, &_totalRead);
+ }
+
+ HRESULT CheckProgress()
+ {
+ HRESULT res = S_OK;
+ if (_openCallback)
+ {
+ if (_totalRead - _totalReadPrev >= ((UInt32)1 << 20))
+ {
+ _totalReadPrev = _totalRead;
+ res = CheckProgress2();
+ }
+ }
+ return res;
+ }
+
+
+ int GetParentAux(const CItem &item) const
+ {
+ if (item.Node < _h.FirstInode && _auxSysIndex >= 0)
+ return _auxSysIndex;
+ return _auxUnknownIndex;
+ }
+
+ HRESULT SeekAndRead(IInStream *inStream, UInt64 block, Byte *data, size_t size);
+ HRESULT ParseDir(const Byte *data, size_t size, unsigned iNodeDir);
+ int FindTargetItem_for_SymLink(unsigned dirNode, const AString &path) const;
+
+ HRESULT FillFileBlocks2(UInt32 block, unsigned level, unsigned numBlocks, CRecordVector<UInt32> &blocks);
+ HRESULT FillFileBlocks(const Byte *p, unsigned numBlocks, CRecordVector<UInt32> &blocks);
+ HRESULT FillExtents(const Byte *p, size_t size, CRecordVector<CExtent> &extents, int parentDepth);
+
+ HRESULT GetStream_Node(unsigned nodeIndex, ISequentialInStream **stream);
+ HRESULT ExtractNode(unsigned nodeIndex, CByteBuffer &data);
+
+ void ClearRefs();
+ HRESULT Open2(IInStream *inStream);
+
+ void GetPath(unsigned index, AString &s) const;
+ bool GetPackSize(unsigned index, UInt64 &res) const;
+};
+
+
+
+HRESULT CHandler::ParseDir(const Byte *p, size_t size, unsigned iNodeDir)
+{
+ bool isThereSelfLink = false;
+
+ PRF(printf("\n\n========= node = %5d size = %5d", (unsigned)iNodeDir, (unsigned)size));
+
+ CNode &nodeDir = _nodes[_refs[iNodeDir]];
+ nodeDir.DirIndex = (int)_dirs.Size();
+ CUIntVector &dir = _dirs.AddNew();
+ int parentNode = -1;
+
+ CItem item;
+
+ for (;;)
+ {
+ if (size == 0)
+ break;
+ if (size < 8)
+ return S_FALSE;
+ UInt32 iNode;
+ LE_32 (0x00, iNode)
+ unsigned recLen;
+ LE_16 (0x04, recLen)
+ const unsigned nameLen = p[6];
+ const Byte type = p[7];
+
+ if (recLen > size)
+ return S_FALSE;
+ if (nameLen + 8 > recLen)
+ return S_FALSE;
+
+ if (iNode >= _refs.Size())
+ return S_FALSE;
+
+ item.Clear();
+
+ if (_h.IsThereFileType())
+ item.Type = type;
+ else if (type != 0)
+ return S_FALSE;
+
+ item.ParentNode = (int)iNodeDir;
+ item.Node = iNode;
+ item.Name.SetFrom_CalcLen((const char *)(p + 8), nameLen);
+
+ p += recLen;
+ size -= recLen;
+
+ if (item.Name.Len() != nameLen)
+ return S_FALSE;
+
+ if (_isUTF)
+ {
+ // 21.07 : we force UTF8
+ // _isUTF = CheckUTF8_AString(item.Name);
+ }
+
+ if (iNode == 0)
+ {
+ /*
+ ext3 deleted??
+ if (item.Name.Len() != 0)
+ return S_FALSE;
+ */
+
+ PRF(printf("\n EMPTY %6d %d %s", (unsigned)recLen, (unsigned)type, (const char *)item.Name));
+ if (type == 0xDE)
+ {
+ // checksum
+ }
+ continue;
+ }
+
+ const int nodeIndex = _refs[iNode];
+ if (nodeIndex < 0)
+ return S_FALSE;
+ CNode &node = _nodes[nodeIndex];
+
+ if (_h.IsThereFileType() && type != 0)
+ {
+ if (type >= Z7_ARRAY_SIZE(k_TypeToMode))
+ return S_FALSE;
+ if (k_TypeToMode[type] != (node.Mode & MY_LIN_S_IFMT))
+ return S_FALSE;
+ }
+
+ node.NumLinksCalced++;
+
+ PRF(printf("\n%s %6d %s", item.IsDir() ? "DIR " : " ", (unsigned)item.Node, (const char *)item.Name));
+
+ if (item.Name[0] == '.')
+ {
+ if (item.Name[1] == 0)
+ {
+ if (isThereSelfLink)
+ return S_FALSE;
+ isThereSelfLink = true;
+ if (iNode != iNodeDir)
+ return S_FALSE;
+ continue;
+ }
+
+ if (item.Name[1] == '.' && item.Name[2] == 0)
+ {
+ if (parentNode >= 0)
+ return S_FALSE;
+ if (!node.IsDir())
+ return S_FALSE;
+ if (iNode == iNodeDir && iNode != k_INODE_ROOT)
+ return S_FALSE;
+
+ parentNode = (int)iNode;
+
+ if (nodeDir.ParentNode < 0)
+ nodeDir.ParentNode = (int)iNode;
+ else if ((unsigned)nodeDir.ParentNode != iNode)
+ return S_FALSE;
+
+ continue;
+ }
+ }
+
+ if (iNode == iNodeDir)
+ return S_FALSE;
+
+ if (parentNode < 0)
+ return S_FALSE;
+
+ if (node.IsDir())
+ {
+ if (node.ParentNode < 0)
+ node.ParentNode = (int)iNodeDir;
+ else if ((unsigned)node.ParentNode != iNodeDir)
+ return S_FALSE;
+ const unsigned itemIndex = _items.Size();
+ dir.Add(itemIndex);
+ node.ItemIndex = (int)itemIndex;
+ }
+
+ _items.Add(item);
+ }
+
+ if (parentNode < 0 || !isThereSelfLink)
+ return S_FALSE;
+
+ return S_OK;
+}
+
+
+static int CompareItemsNames(const unsigned *p1, const unsigned *p2, void *param)
+{
+ const CObjectVector<CItem> &items = *(const CObjectVector<CItem> *)param;
+ return strcmp(items[*p1].Name, items[*p2].Name);
+}
+
+
+int CHandler::FindTargetItem_for_SymLink(unsigned iNode, const AString &path) const
+{
+ unsigned pos = 0;
+
+ if (path.IsEmpty())
+ return -1;
+
+ if (path[0] == '/')
+ {
+ iNode = k_INODE_ROOT;
+ if (iNode >= _refs.Size())
+ return -1;
+ pos = 1;
+ }
+
+ AString s;
+
+ while (pos != path.Len())
+ {
+ const CNode &node = _nodes[_refs[iNode]];
+ const int slash = path.Find('/', pos);
+
+ if (slash < 0)
+ {
+ s = path.Ptr(pos);
+ pos = path.Len();
+ }
+ else
+ {
+ s.SetFrom(path.Ptr(pos), (unsigned)slash - pos);
+ pos = (unsigned)slash + 1;
+ }
+
+ if (s[0] == '.')
+ {
+ if (s[1] == 0)
+ continue;
+ else if (s[1] == '.' && s[2] == 0)
+ {
+ if (node.ParentNode < 0)
+ return -1;
+ if (iNode == k_INODE_ROOT)
+ return -1;
+ iNode = (unsigned)node.ParentNode;
+ continue;
+ }
+ }
+
+ if (node.DirIndex < 0)
+ return -1;
+
+ const CUIntVector &dir = _dirs[node.DirIndex];
+
+ /*
+ for (unsigned i = 0;; i++)
+ {
+ if (i >= dir.Size())
+ return -1;
+ const CItem &item = _items[dir[i]];
+ if (item.Name == s)
+ {
+ iNode = item.Node;
+ break;
+ }
+ }
+ */
+
+ unsigned left = 0, right = dir.Size();
+ for (;;)
+ {
+ if (left == right)
+ return -1;
+ const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const CItem &item = _items[dir[mid]];
+ const int comp = strcmp(s, item.Name);
+ if (comp == 0)
+ {
+ iNode = item.Node;
+ break;
+ }
+ if (comp < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ }
+
+ return _nodes[_refs[iNode]].ItemIndex;
+}
+
+
+HRESULT CHandler::SeekAndRead(IInStream *inStream, UInt64 block, Byte *data, size_t size)
+{
+ if (block == 0 || block >= _h.NumBlocks)
+ return S_FALSE;
+ if (((size + ((size_t)1 << _h.BlockBits) - 1) >> _h.BlockBits) > _h.NumBlocks - block)
+ return S_FALSE;
+ RINOK(InStream_SeekSet(inStream, (UInt64)block << _h.BlockBits))
+ _totalRead += size;
+ return ReadStream_FALSE(inStream, data, size);
+}
+
+
+static const unsigned kHeaderSize = 2 * 1024;
+static const unsigned kHeaderDataOffset = 1024;
+
+HRESULT CHandler::Open2(IInStream *inStream)
+{
+ {
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize))
+ if (!_h.Parse(buf + kHeaderDataOffset))
+ return S_FALSE;
+ if (_h.BlockGroupNr != 0)
+ return S_FALSE; // it's just copy of super block
+ }
+
+ {
+ // ---------- Read groups and nodes ----------
+
+ unsigned numGroups;
+ {
+ const UInt64 numGroups64 = _h.GetNumGroups();
+ if (numGroups64 > (UInt32)1 << 31)
+ return S_FALSE;
+ numGroups = (unsigned)numGroups64;
+ }
+
+ unsigned gdBits = 5;
+ if (_h.Is64Bit())
+ {
+ if (_h.GdSize != 64)
+ return S_FALSE;
+ gdBits = 6;
+ }
+
+ _isArc = true;
+ _phySize = _h.GetPhySize();
+
+ if (_openCallback)
+ {
+ RINOK(_openCallback->SetTotal(NULL, &_phySize))
+ }
+
+ UInt64 fileSize = 0;
+ RINOK(InStream_GetSize_SeekToEnd(inStream, fileSize))
+
+ CRecordVector<CGroupDescriptor> groups;
+
+ {
+ // ---------- Read groups ----------
+
+ CByteBuffer gdBuf;
+ const size_t gdBufSize = (size_t)numGroups << gdBits;
+ if ((gdBufSize >> gdBits) != numGroups)
+ return S_FALSE;
+ gdBuf.Alloc(gdBufSize);
+ RINOK(SeekAndRead(inStream, (_h.BlockBits <= 10 ? 2 : 1), gdBuf, gdBufSize))
+
+ for (unsigned i = 0; i < numGroups; i++)
+ {
+ CGroupDescriptor gd;
+
+ const Byte *p = gdBuf + ((size_t)i << gdBits);
+ const unsigned gd_Size = (unsigned)1 << gdBits;
+ gd.Parse(p, gd_Size);
+
+ if (_h.UseMetadataChecksum())
+ {
+ // use CRC32c
+ }
+ else if (_h.UseGdtChecksum())
+ {
+ UInt32 crc = Crc16Calc(_h.Uuid, sizeof(_h.Uuid));
+ Byte i_le[4];
+ SetUi32(i_le, i)
+ crc = Crc16Update(crc, i_le, 4);
+ crc = Crc16Update(crc, p, 32 - 2);
+ if (gd_Size != 32)
+ crc = Crc16Update(crc, p + 32, gd_Size - 32);
+ if (crc != gd.Checksum)
+ return S_FALSE;
+ }
+
+ groups.Add(gd);
+ }
+ }
+
+ {
+ // ---------- Read nodes ----------
+
+ if (_h.NumInodes < _h.NumFreeInodes)
+ return S_FALSE;
+
+ UInt32 numNodes = _h.InodesPerGroup;
+ if (numNodes > _h.NumInodes)
+ numNodes = _h.NumInodes;
+ const size_t nodesDataSize = (size_t)numNodes * _h.InodeSize;
+
+ if (nodesDataSize / _h.InodeSize != numNodes)
+ return S_FALSE;
+
+ // that code to reduce false detecting cases
+ if (nodesDataSize > fileSize)
+ {
+ if (numNodes > (1 << 24))
+ return S_FALSE;
+ }
+
+ const UInt32 numReserveInodes = _h.NumInodes - _h.NumFreeInodes + 1;
+ // numReserveInodes = _h.NumInodes + 1;
+ if (numReserveInodes != 0)
+ {
+ _nodes.Reserve(numReserveInodes);
+ _refs.Reserve(numReserveInodes);
+ }
+
+ CByteBuffer nodesData;
+ nodesData.Alloc(nodesDataSize);
+
+ CByteBuffer nodesMap;
+ const size_t blockSize = (size_t)1 << _h.BlockBits;
+ nodesMap.Alloc(blockSize);
+
+ unsigned globalNodeIndex = 0;
+ // unsigned numEmpty = 0;
+ unsigned numEmpty_in_Maps = 0;
+
+ FOR_VECTOR (gi, groups)
+ {
+ if (globalNodeIndex >= _h.NumInodes)
+ break;
+
+ const CGroupDescriptor &gd = groups[gi];
+
+ PRF(printf("\n\ng%6d block = %6x\n", gi, (unsigned)gd.InodeTable));
+
+ RINOK(SeekAndRead(inStream, gd.InodeBitmap, nodesMap, blockSize))
+ RINOK(SeekAndRead(inStream, gd.InodeTable, nodesData, nodesDataSize))
+
+ unsigned numEmpty_in_Map = 0;
+
+ for (size_t n = 0; n < numNodes && globalNodeIndex < _h.NumInodes; n++, globalNodeIndex++)
+ {
+ if ((nodesMap[n >> 3] & ((unsigned)1 << (n & 7))) == 0)
+ {
+ numEmpty_in_Map++;
+ continue;
+ }
+
+ const Byte *p = nodesData + (size_t)n * _h.InodeSize;
+ if (IsEmptyData(p, _h.InodeSize))
+ {
+ if (globalNodeIndex + 1 >= _h.FirstInode)
+ {
+ _headersError = true;
+ // return S_FALSE;
+ }
+ continue;
+ }
+
+ CNode node;
+
+ PRF(printf("\nnode = %5d ", (unsigned)n));
+
+ if (!node.Parse(p, _h))
+ return S_FALSE;
+
+ // PRF(printf("\n %6d", (unsigned)n));
+ /*
+ SetUi32(p + 0x7C, 0)
+ SetUi32(p + 0x82, 0)
+
+ UInt32 crc = Crc32C_Calc(_h.Uuid, sizeof(_h.Uuid));
+ Byte i_le[4];
+ SetUi32(i_le, n);
+ crc = Crc32C_Update(crc, i_le, 4);
+ crc = Crc32C_Update(crc, p, _h.InodeSize);
+ if (crc != node.Checksum) return S_FALSE;
+ */
+
+ while (_refs.Size() < globalNodeIndex + 1)
+ {
+ // numEmpty++;
+ _refs.Add(-1);
+ }
+
+ _refs.Add((int)_nodes.Add(node));
+ }
+
+
+ numEmpty_in_Maps += numEmpty_in_Map;
+
+ if (numEmpty_in_Map != gd.NumFreeInodes)
+ {
+ _headersWarning = true;
+ // return S_FALSE;
+ }
+ }
+
+ if (numEmpty_in_Maps != _h.NumFreeInodes)
+ {
+ // some ext2 examples has incorrect value in _h.NumFreeInodes.
+ // so we disable check;
+ _headersWarning = true;
+ }
+
+ if (_refs.Size() <= k_INODE_ROOT)
+ return S_FALSE;
+
+ // printf("\n numReserveInodes = %6d, _refs.Size() = %d, numEmpty = %7d\n", numReserveInodes, _refs.Size(), (unsigned)numEmpty);
+ }
+ }
+
+ _stream = inStream; // we need stream for dir nodes
+
+ {
+ // ---------- Read Dirs ----------
+
+ CByteBuffer dataBuf;
+
+ FOR_VECTOR (i, _refs)
+ {
+ const int nodeIndex = _refs[i];
+ {
+ if (nodeIndex < 0)
+ continue;
+ const CNode &node = _nodes[nodeIndex];
+ if (!node.IsDir())
+ continue;
+ }
+ RINOK(ExtractNode((unsigned)nodeIndex, dataBuf))
+ if (dataBuf.Size() == 0)
+ {
+ // _headersError = true;
+ return S_FALSE;
+ }
+ else
+ {
+ RINOK(ParseDir(dataBuf, dataBuf.Size(), i))
+ }
+ RINOK(CheckProgress())
+ }
+
+ const int ref = _refs[k_INODE_ROOT];
+ if (ref < 0 || _nodes[ref].ParentNode != k_INODE_ROOT)
+ return S_FALSE;
+ }
+
+ {
+ // ---------- Check NumLinks and unreferenced dir nodes ----------
+
+ FOR_VECTOR (i, _refs)
+ {
+ int nodeIndex = _refs[i];
+ if (nodeIndex < 0)
+ continue;
+ const CNode &node = _nodes[nodeIndex];
+
+ if (node.NumLinks != node.NumLinksCalced)
+ {
+ if (node.NumLinks != 1 || node.NumLinksCalced != 0
+ // ) && i >= _h.FirstInode
+ )
+ {
+ _linksError = true;
+ // return S_FALSE;
+ }
+ }
+
+ if (!node.IsDir())
+ continue;
+
+ if (node.ParentNode < 0)
+ {
+ if (i >= _h.FirstInode)
+ return S_FALSE;
+ continue;
+ }
+ }
+ }
+
+ {
+ // ---------- Check that there is no loops in parents list ----------
+
+ unsigned numNodes = _refs.Size();
+ CIntArr UsedByNode(numNodes);
+ {
+ {
+ for (unsigned i = 0; i < numNodes; i++)
+ UsedByNode[i] = -1;
+ }
+ }
+
+ FOR_VECTOR (i, _refs)
+ {
+ {
+ int nodeIndex = _refs[i];
+ if (nodeIndex < 0)
+ continue;
+ const CNode &node = _nodes[nodeIndex];
+ if (node.ParentNode < 0 // not dir
+ || i == k_INODE_ROOT)
+ continue;
+ }
+
+ unsigned c = i;
+
+ for (;;)
+ {
+ const int nodeIndex = _refs[c];
+ if (nodeIndex < 0)
+ return S_FALSE;
+ CNode &node = _nodes[nodeIndex];
+
+ if (UsedByNode[c] != -1)
+ {
+ if ((unsigned)UsedByNode[c] == i)
+ return S_FALSE;
+ break;
+ }
+
+ UsedByNode[c] = (int)i;
+ if (node.ParentNode < 0 || node.ParentNode == k_INODE_ROOT)
+ break;
+ if ((unsigned)node.ParentNode == i)
+ return S_FALSE;
+ c = (unsigned)node.ParentNode;
+ }
+ }
+ }
+
+ {
+ // ---------- Fill SymLinks data ----------
+
+ AString s;
+ CByteBuffer data;
+
+ unsigned i;
+ for (i = 0; i < _refs.Size(); i++)
+ {
+ const int nodeIndex = _refs[i];
+ if (nodeIndex < 0)
+ continue;
+ CNode &node = _nodes[nodeIndex];
+ if (!node.IsLink())
+ continue;
+ if (node.FileSize > ((UInt32)1 << 14))
+ continue;
+ if (ExtractNode((unsigned)nodeIndex, data) == S_OK && data.Size() != 0)
+ {
+ s.SetFrom_CalcLen((const char *)(const Byte *)data, (unsigned)data.Size());
+ if (s.Len() == data.Size())
+ node.SymLinkIndex = (int)_symLinks.Add(s);
+ RINOK(CheckProgress())
+ }
+ }
+
+ for (i = 0; i < _dirs.Size(); i++)
+ {
+ _dirs[i].Sort(CompareItemsNames, (void *)&_items);
+ }
+
+ unsigned prev = 0;
+ unsigned complex = 0;
+
+ for (i = 0; i < _items.Size(); i++)
+ {
+ CItem &item = _items[i];
+ const int sym = _nodes[_refs[item.Node]].SymLinkIndex;
+ if (sym >= 0 && item.ParentNode >= 0)
+ {
+ item.SymLinkItemIndex = FindTargetItem_for_SymLink((unsigned)item.ParentNode, _symLinks[sym]);
+ if (_openCallback)
+ {
+ complex++;
+ if (complex - prev >= (1 << 10))
+ {
+ prev = complex;
+ RINOK(CheckProgress2())
+ }
+ }
+ }
+ }
+ }
+
+ {
+ // ---------- Add items and aux folders for unreferenced files ----------
+
+ bool useSys = false;
+ bool useUnknown = false;
+
+ FOR_VECTOR (i, _refs)
+ {
+ const int nodeIndex = _refs[i];
+ if (nodeIndex < 0)
+ continue;
+ const CNode &node = _nodes[nodeIndex];
+
+ if (node.NumLinksCalced == 0 /* || i > 100 && i < 150 */) // for debug
+ {
+ CItem item;
+ item.Node = i;
+
+ // we don't know how to work with k_INODE_RESIZE node (strange FileSize and Block values).
+ // so we ignore it;
+
+ if (i == k_INODE_RESIZE)
+ continue;
+
+ if (node.FileSize == 0)
+ continue;
+
+ if (i < _h.FirstInode)
+ {
+ if (item.Node < Z7_ARRAY_SIZE(k_SysInode_Names))
+ item.Name = k_SysInode_Names[item.Node];
+ useSys = true;
+ }
+ else
+ useUnknown = true;
+
+ if (item.Name.IsEmpty())
+ item.Name.Add_UInt32(item.Node);
+
+ _items.Add(item);
+ }
+ }
+
+ if (useSys)
+ _auxSysIndex = (int)_auxItems.Add((AString)"[SYS]");
+ if (useUnknown)
+ _auxUnknownIndex = (int)_auxItems.Add((AString)"[UNKNOWN]");
+ }
+
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ HRESULT res;
+ try
+ {
+ _openCallback = callback;
+ res = Open2(stream);
+ }
+ catch(...)
+ {
+ ClearRefs();
+ throw;
+ }
+
+ if (res != S_OK)
+ {
+ ClearRefs();
+ return res;
+ }
+ _stream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+
+void CHandler::ClearRefs()
+{
+ _stream.Release();
+ _items.Clear();
+ _nodes.Clear();
+ _refs.Clear();
+ _auxItems.Clear();
+ _symLinks.Clear();
+ _dirs.Clear();
+ _auxSysIndex = -1;
+ _auxUnknownIndex = -1;
+}
+
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _totalRead = 0;
+ _totalReadPrev = 0;
+ _phySize = 0;
+ _isArc = false;
+ _headersError = false;
+ _headersWarning = false;
+ _linksError = false;
+ _isUTF = true;
+
+ ClearRefs();
+ return S_OK;
+}
+
+
+static void ChangeSeparatorsInName(char *s, unsigned num)
+{
+ for (unsigned i = 0; i < num; i++)
+ {
+ char c = s[i];
+ if (c == CHAR_PATH_SEPARATOR || c == '/')
+ s[i] = '_';
+ }
+}
+
+
+void CHandler::GetPath(unsigned index, AString &s) const
+{
+ s.Empty();
+
+ if (index >= _items.Size())
+ {
+ s = _auxItems[index - _items.Size()];
+ return;
+ }
+
+ for (;;)
+ {
+ const CItem &item = _items[index];
+ if (!s.IsEmpty())
+ s.InsertAtFront(CHAR_PATH_SEPARATOR);
+ s.Insert(0, item.Name);
+ // 18.06
+ ChangeSeparatorsInName(s.GetBuf(), item.Name.Len());
+
+ if (item.ParentNode == k_INODE_ROOT)
+ return;
+
+ if (item.ParentNode < 0)
+ {
+ int aux = GetParentAux(item);
+ if (aux < 0)
+ break;
+ s.InsertAtFront(CHAR_PATH_SEPARATOR);
+ s.Insert(0, _auxItems[aux]);
+ return;
+ }
+
+ const CNode &node = _nodes[_refs[item.ParentNode]];
+ if (node.ItemIndex < 0)
+ return;
+ index = (unsigned)node.ItemIndex;
+
+ if (s.Len() > ((UInt32)1 << 16))
+ {
+ s.Insert(0, "[LONG]" STRING_PATH_SEPARATOR);
+ return;
+ }
+ }
+}
+
+
+bool CHandler::GetPackSize(unsigned index, UInt64 &totalPack) const
+{
+ if (index >= _items.Size())
+ {
+ totalPack = 0;
+ return false;
+ }
+
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[_refs[item.Node]];
+
+ // if (!node.IsFlags_EXTENTS())
+ {
+ totalPack = (UInt64)node.NumBlocks << (node.IsFlags_HUGE() ? _h.BlockBits : 9);
+ return true;
+ }
+
+ /*
+ CExtentTreeHeader eth;
+ if (!eth.Parse(node.Block))
+ return false;
+ if (eth.NumEntries > 3)
+ return false;
+ if (!eth.Depth == 0)
+ return false;
+
+ UInt64 numBlocks = 0;
+ {
+ for (unsigned i = 0; i < eth.NumEntries; i++)
+ {
+ CExtent e;
+ e.Parse(node.Block + 12 + i * 12);
+ // const CExtent &e = node.leafs[i];
+ if (e.IsInited)
+ numBlocks += e.Len;
+ }
+ }
+
+ totalPack = numBlocks << _h.BlockBits;
+ return true;
+ */
+}
+
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _items.Size() + _auxItems.Size();
+ return S_OK;
+}
+
+enum
+{
+ kpidMountTime = kpidUserDefined,
+ kpidLastCheckTime,
+ kpidRevision,
+ kpidINodeSize,
+ kpidLastMount,
+ kpidFeatureIncompat,
+ kpidFeatureRoCompat,
+ kpidWrittenKB
+
+ // kpidGroupSize,
+
+ // kpidChangeTime = kpidUserDefined + 256,
+ // kpidDTime
+};
+
+static const UInt32 kProps[] =
+{
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidPosixAttrib,
+ kpidMTime,
+ kpidCTime,
+ kpidATime,
+ // kpidChangeTime,
+ // kpidDTime,
+ kpidINode,
+ kpidLinks,
+ kpidSymLink,
+ kpidCharacts,
+ kpidUserId,
+ kpidGroupId
+};
+
+
+static const CStatProp kArcProps[] =
+{
+ { NULL, kpidHeadersSize, VT_BSTR },
+ // { NULL, kpidFileSystem, VT_BSTR },
+ // kpidMethod,
+ { NULL, kpidClusterSize, VT_UI4 },
+ // { "Group Size", kpidGroupSize, VT_UI8 },
+ { NULL, kpidFreeSpace, VT_UI8 },
+
+ { NULL, kpidMTime, VT_FILETIME },
+ { NULL, kpidCTime, VT_FILETIME },
+ { "Mount Time", kpidMountTime, VT_FILETIME },
+ { "Last Check Time", kpidLastCheckTime, VT_FILETIME },
+
+ { NULL, kpidHostOS, VT_BSTR},
+ { "Revision", kpidRevision, VT_UI4},
+ { "inode Size", kpidINodeSize, VT_UI4},
+ { NULL, kpidCodePage, VT_BSTR},
+ { NULL, kpidVolumeName, VT_BSTR},
+ { "Last Mounted", kpidLastMount, VT_BSTR},
+ { NULL, kpidId, VT_BSTR},
+ { NULL, kpidCharacts, VT_BSTR },
+ { "Incompatible Features", kpidFeatureIncompat, VT_BSTR },
+ { "Readonly-compatible Features", kpidFeatureRoCompat, VT_BSTR },
+ { "Written KiB", kpidWrittenKB, VT_UI8 }
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_WITH_NAME
+
+static void StringToProp(bool isUTF, const char *s, unsigned size, NCOM::CPropVariant &prop)
+{
+ UString u;
+ AString a;
+ a.SetFrom_CalcLen(s, size);
+ if (!isUTF || !ConvertUTF8ToUnicode(a, u))
+ MultiByteToUnicodeString2(u, a);
+ prop = u;
+}
+
+static void UnixTimeToProp(UInt32 val, NCOM::CPropVariant &prop)
+{
+ if (val != 0)
+ PropVariant_SetFrom_UnixTime(prop, val);
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+
+ NCOM::CPropVariant prop;
+
+ switch (propID)
+ {
+ /*
+ case kpidFileSystem:
+ {
+ AString res = "Ext4";
+ prop = res;
+ break;
+ }
+ */
+
+ case kpidIsTree: prop = true; break;
+ case kpidIsAux: prop = true; break;
+ case kpidINode: prop = true; break;
+
+ case kpidClusterSize: prop = (UInt32)1 << _h.BlockBits; break;
+ // case kpidGroupSize: prop = (UInt64)_h.BlocksPerGroup << _h.BlockBits; break;
+
+ case kpidFreeSpace: prop = (UInt64)_h.NumFreeBlocks << _h.BlockBits; break;
+
+ case kpidCTime: UnixTimeToProp(_h.CTime, prop); break;
+ case kpidMTime: UnixTimeToProp(_h.WriteTime, prop); break;
+ case kpidMountTime: UnixTimeToProp(_h.MountTime, prop); break;
+ case kpidLastCheckTime: UnixTimeToProp(_h.LastCheckTime, prop); break;
+
+ case kpidHostOS:
+ {
+ TYPE_TO_PROP(kHostOS, _h.CreatorOs, prop);
+ break;
+ }
+
+ case kpidRevision: prop = _h.RevLevel; break;
+
+ case kpidINodeSize: prop = (UInt32)_h.InodeSize; break;
+
+ case kpidId:
+ {
+ if (!IsEmptyData(_h.Uuid, 16))
+ {
+ char s[16 * 2 + 2];
+ for (unsigned i = 0; i < 16; i++)
+ PrintHex(_h.Uuid[i], s + i * 2);
+ s[16 * 2] = 0;
+ prop = s;
+ }
+ break;
+ }
+
+ case kpidCodePage: if (_isUTF) prop = "UTF-8"; break;
+
+ case kpidShortComment:
+ case kpidVolumeName:
+ StringToProp(_isUTF, _h.VolName, sizeof(_h.VolName), prop); break;
+
+ case kpidLastMount: StringToProp(_isUTF, _h.LastMount, sizeof(_h.LastMount), prop); break;
+
+ case kpidCharacts: FLAGS_TO_PROP(g_FeatureCompat_Flags, _h.FeatureCompat, prop); break;
+ case kpidFeatureIncompat: FLAGS_TO_PROP(g_FeatureIncompat_Flags, _h.FeatureIncompat, prop); break;
+ case kpidFeatureRoCompat: FLAGS_TO_PROP(g_FeatureRoCompat_Flags, _h.FeatureRoCompat, prop); break;
+ case kpidWrittenKB: if (_h.WrittenKB != 0) prop = _h.WrittenKB; break;
+
+ case kpidPhySize: prop = _phySize; break;
+
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (_linksError) v |= kpv_ErrorFlags_HeadersError;
+ if (_headersError) v |= kpv_ErrorFlags_HeadersError;
+ if (!_stream && v == 0 && _isArc)
+ v = kpv_ErrorFlags_HeadersError;
+ if (v != 0)
+ prop = v;
+ break;
+ }
+
+ case kpidWarningFlags:
+ {
+ UInt32 v = 0;
+ if (_headersWarning) v |= kpv_ErrorFlags_HeadersError;
+ if (v != 0)
+ prop = v;
+ break;
+ }
+ }
+
+ prop.Detach(value);
+ return S_OK;
+
+ COM_TRY_END
+}
+
+
+/*
+static const Byte kRawProps[] =
+{
+ // kpidSha1,
+};
+*/
+
+Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps))
+{
+ // *numProps = Z7_ARRAY_SIZE(kRawProps);
+ *numProps = 0;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID))
+{
+ // *propID = kRawProps[index];
+ *propID = 0;
+ *name = NULL;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType))
+{
+ *parentType = NParentType::kDir;
+ *parent = (UInt32)(Int32)-1;
+
+ if (index >= _items.Size())
+ return S_OK;
+
+ const CItem &item = _items[index];
+
+ if (item.ParentNode < 0)
+ {
+ const int aux = GetParentAux(item);
+ if (aux >= 0)
+ *parent = _items.Size() + (unsigned)aux;
+ }
+ else
+ {
+ const int itemIndex = _nodes[_refs[item.ParentNode]].ItemIndex;
+ if (itemIndex >= 0)
+ *parent = (unsigned)itemIndex;
+ }
+
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
+{
+ *data = NULL;
+ *dataSize = 0;
+ *propType = 0;
+
+ if (propID == kpidName && _isUTF)
+ {
+ if (index < _items.Size())
+ {
+ const AString &s = _items[index].Name;
+ if (!s.IsEmpty())
+ {
+ *data = (void *)(const char *)s;
+ *dataSize = (UInt32)s.Len() + 1;
+ *propType = NPropDataType::kUtf8z;
+ }
+ return S_OK;
+ }
+ else
+ {
+ const AString &s = _auxItems[index - _items.Size()];
+ {
+ *data = (void *)(const char *)s;
+ *dataSize = (UInt32)s.Len() + 1;
+ *propType = NPropDataType::kUtf8z;
+ }
+ return S_OK;
+ }
+ }
+
+ return S_OK;
+}
+
+
+static void ExtTimeToProp(const CExtTime &t, NCOM::CPropVariant &prop)
+{
+ if (t.Val == 0 && t.Extra == 0)
+ return;
+
+ FILETIME ft;
+ unsigned low100ns = 0;
+ // if (t.Extra != 0)
+ {
+ // 1901-2446 :
+ Int64 v = (Int64)(Int32)t.Val;
+ v += (UInt64)(t.Extra & 3) << 32; // 2 low bits are offset for main timestamp
+ UInt64 ft64 = NTime::UnixTime64_To_FileTime64(v);
+ const UInt32 ns = (t.Extra >> 2);
+ if (ns < 1000000000)
+ {
+ ft64 += ns / 100;
+ low100ns = (unsigned)(ns % 100);
+ }
+ ft.dwLowDateTime = (DWORD)ft64;
+ ft.dwHighDateTime = (DWORD)(ft64 >> 32);
+ }
+ /*
+ else
+ {
+ // 1901-2038 : that code is good for ext4 and compatibility with Extra
+ NTime::UnixTime64ToFileTime((Int32)t.Val, ft); // for
+
+ // 1970-2106 : that code is good if timestamp is used as unsigned 32-bit
+ // are there such systems?
+ // NTime::UnixTimeToFileTime(t.Val, ft); // for
+ }
+ */
+ prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, low100ns);
+}
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ if (index >= _items.Size())
+ {
+ switch (propID)
+ {
+ case kpidPath:
+ case kpidName:
+ {
+ prop = _auxItems[index - _items.Size()];
+ break;
+ }
+ case kpidIsDir: prop = true; break;
+ case kpidIsAux: prop = true; break;
+ }
+ }
+ else
+ {
+
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[_refs[item.Node]];
+ bool isDir = node.IsDir();
+
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ UString u;
+ {
+ AString s;
+ GetPath(index, s);
+ if (!_isUTF || !ConvertUTF8ToUnicode(s, u))
+ MultiByteToUnicodeString2(u, s);
+ }
+ prop = u;
+ break;
+ }
+
+ case kpidName:
+ {
+ {
+ UString u;
+ {
+ if (!_isUTF || !ConvertUTF8ToUnicode(item.Name, u))
+ MultiByteToUnicodeString2(u, item.Name);
+ }
+ prop = u;
+ }
+ break;
+ }
+
+ case kpidIsDir:
+ {
+ bool isDir2 = isDir;
+ if (item.SymLinkItemIndex >= 0)
+ isDir2 = _nodes[_refs[_items[item.SymLinkItemIndex].Node]].IsDir();
+ prop = isDir2;
+ break;
+ }
+
+ case kpidSize: if (!isDir) prop = node.FileSize; break;
+
+ case kpidPackSize:
+ if (!isDir)
+ {
+ UInt64 size;
+ if (GetPackSize(index, size))
+ prop = size;
+ }
+ break;
+
+ case kpidPosixAttrib:
+ {
+ /*
+ if (node.Type != 0 && node.Type < Z7_ARRAY_SIZE(k_TypeToMode))
+ prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type];
+ */
+ prop = (UInt32)(node.Mode);
+ break;
+ }
+
+ case kpidMTime: ExtTimeToProp(node.MTime, prop); break;
+ case kpidCTime: ExtTimeToProp(node.CTime, prop); break;
+ case kpidATime: ExtTimeToProp(node.ATime, prop); break;
+ // case kpidDTime: ExtTimeToProp(node.DTime, prop); break;
+ case kpidChangeTime: ExtTimeToProp(node.ChangeTime, prop); break;
+ case kpidUserId: prop = (UInt32)node.Uid; break;
+ case kpidGroupId: prop = (UInt32)node.Gid; break;
+ case kpidLinks: prop = node.NumLinks; break;
+ case kpidINode: prop = (UInt32)item.Node; break;
+ case kpidStreamId: if (!isDir) prop = (UInt32)item.Node; break;
+ case kpidCharacts: FLAGS_TO_PROP(g_NodeFlags, (UInt32)node.Flags, prop); break;
+
+ case kpidSymLink:
+ {
+ if (node.SymLinkIndex >= 0)
+ {
+ UString u;
+ {
+ const AString &s = _symLinks[node.SymLinkIndex];
+ if (!_isUTF || !ConvertUTF8ToUnicode(s, u))
+ MultiByteToUnicodeString2(u, s);
+ }
+ prop = u;
+ }
+ break;
+ }
+ }
+
+ }
+
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_CLASS_IMP_IInStream(CClusterInStream2
+)
+ UInt64 _virtPos;
+ UInt64 _physPos;
+ UInt32 _curRem;
+public:
+ unsigned BlockBits;
+ UInt64 Size;
+ CMyComPtr<IInStream> Stream;
+ CRecordVector<UInt32> Vector;
+
+ HRESULT SeekToPhys() { return InStream_SeekSet(Stream, _physPos); }
+
+ HRESULT InitAndSeek()
+ {
+ _curRem = 0;
+ _virtPos = 0;
+ _physPos = 0;
+ if (Vector.Size() > 0)
+ {
+ _physPos = (Vector[0] << BlockBits);
+ return SeekToPhys();
+ }
+ return S_OK;
+ }
+};
+
+
+Z7_COM7F_IMF(CClusterInStream2::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (_virtPos >= Size)
+ return S_OK;
+ {
+ UInt64 rem = Size - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+ if (size == 0)
+ return S_OK;
+
+ if (_curRem == 0)
+ {
+ const UInt32 blockSize = (UInt32)1 << BlockBits;
+ const UInt32 virtBlock = (UInt32)(_virtPos >> BlockBits);
+ const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
+ const UInt32 phyBlock = Vector[virtBlock];
+
+ if (phyBlock == 0)
+ {
+ UInt32 cur = blockSize - offsetInBlock;
+ if (cur > size)
+ cur = size;
+ memset(data, 0, cur);
+ _virtPos += cur;
+ if (processedSize)
+ *processedSize = cur;
+ return S_OK;
+ }
+
+ UInt64 newPos = ((UInt64)phyBlock << BlockBits) + offsetInBlock;
+ if (newPos != _physPos)
+ {
+ _physPos = newPos;
+ RINOK(SeekToPhys())
+ }
+
+ _curRem = blockSize - offsetInBlock;
+
+ for (unsigned i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++)
+ _curRem += (UInt32)1 << BlockBits;
+ }
+
+ if (size > _curRem)
+ size = _curRem;
+ HRESULT res = Stream->Read(data, size, &size);
+ if (processedSize)
+ *processedSize = size;
+ _physPos += size;
+ _virtPos += size;
+ _curRem -= size;
+ return res;
+}
+
+Z7_COM7F_IMF(CClusterInStream2::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += Size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ if (_virtPos != (UInt64)offset)
+ _curRem = 0;
+ _virtPos = (UInt64)offset;
+ if (newPosition)
+ *newPosition = (UInt64)offset;
+ return S_OK;
+}
+
+
+Z7_CLASS_IMP_IInStream(
+ CExtInStream
+)
+ UInt64 _virtPos;
+ UInt64 _phyPos;
+public:
+ unsigned BlockBits;
+ UInt64 Size;
+ CMyComPtr<IInStream> Stream;
+ CRecordVector<CExtent> Extents;
+
+ HRESULT StartSeek()
+ {
+ _virtPos = 0;
+ _phyPos = 0;
+ return InStream_SeekSet(Stream, _phyPos);
+ }
+};
+
+Z7_COM7F_IMF(CExtInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (_virtPos >= Size)
+ return S_OK;
+ {
+ UInt64 rem = Size - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+ if (size == 0)
+ return S_OK;
+
+ UInt32 blockIndex = (UInt32)(_virtPos >> BlockBits);
+
+ unsigned left = 0, right = Extents.Size();
+ for (;;)
+ {
+ unsigned mid = (left + right) / 2;
+ if (mid == left)
+ break;
+ if (blockIndex < Extents[mid].VirtBlock)
+ right = mid;
+ else
+ left = mid;
+ }
+
+ {
+ const CExtent &extent = Extents[left];
+ if (blockIndex < extent.VirtBlock)
+ return E_FAIL;
+ UInt32 bo = blockIndex - extent.VirtBlock;
+ if (bo >= extent.Len)
+ return E_FAIL;
+
+ UInt32 offset = ((UInt32)_virtPos & (((UInt32)1 << BlockBits) - 1));
+ UInt32 remBlocks = extent.Len - bo;
+ UInt64 remBytes = ((UInt64)remBlocks << BlockBits);
+ remBytes -= offset;
+
+ if (size > remBytes)
+ size = (UInt32)remBytes;
+
+ if (!extent.IsInited)
+ {
+ memset(data, 0, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ }
+
+ const UInt64 phyBlock = extent.PhyStart + bo;
+ const UInt64 phy = (phyBlock << BlockBits) + offset;
+
+ if (phy != _phyPos)
+ {
+ RINOK(InStream_SeekSet(Stream, phy))
+ _phyPos = phy;
+ }
+
+ UInt32 realProcessSize = 0;
+
+ const HRESULT res = Stream->Read(data, size, &realProcessSize);
+
+ _phyPos += realProcessSize;
+ _virtPos += realProcessSize;
+ if (processedSize)
+ *processedSize = realProcessSize;
+ return res;
+ }
+}
+
+
+Z7_COM7F_IMF(CExtInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += Size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _virtPos = (UInt64)offset;
+ if (newPosition)
+ *newPosition = (UInt64)offset;
+ return S_OK;
+}
+
+
+
+HRESULT CHandler::FillFileBlocks2(UInt32 block, unsigned level, unsigned numBlocks, CRecordVector<UInt32> &blocks)
+{
+ const size_t blockSize = (size_t)1 << _h.BlockBits;
+ CByteBuffer &tempBuf = _tempBufs[level];
+ tempBuf.Alloc(blockSize);
+
+ PRF2(printf("\n level = %d, block = %7d", level, (unsigned)block));
+
+ RINOK(SeekAndRead(_stream, block, tempBuf, blockSize))
+
+ const Byte *p = tempBuf;
+ size_t num = (size_t)1 << (_h.BlockBits - 2);
+
+ for (size_t i = 0; i < num; i++)
+ {
+ if (blocks.Size() == numBlocks)
+ break;
+ UInt32 val = GetUi32(p + 4 * i);
+ if (val >= _h.NumBlocks)
+ return S_FALSE;
+
+ if (level != 0)
+ {
+ if (val == 0)
+ {
+ /*
+ size_t num = (size_t)1 << ((_h.BlockBits - 2) * (level));
+ PRF2(printf("\n num empty = %3d", (unsigned)num));
+ for (size_t k = 0; k < num; k++)
+ {
+ blocks.Add(0);
+ if (blocks.Size() == numBlocks)
+ return S_OK;
+ }
+ continue;
+ */
+ return S_FALSE;
+ }
+
+ RINOK(FillFileBlocks2(val, level - 1, numBlocks, blocks))
+ continue;
+ }
+
+ PRF2(printf("\n i = %3d, blocks.Size() = %6d, block = %5d ", i, blocks.Size(), (unsigned)val));
+
+ PRF(printf("\n i = %3d, start = %5d ", (unsigned)i, (unsigned)val));
+
+ blocks.Add(val);
+ }
+
+ return S_OK;
+}
+
+
+static const unsigned kNumDirectNodeBlocks = 12;
+
+HRESULT CHandler::FillFileBlocks(const Byte *p, unsigned numBlocks, CRecordVector<UInt32> &blocks)
+{
+ // ext2 supports zero blocks (blockIndex == 0).
+
+ blocks.ClearAndReserve(numBlocks);
+
+ for (unsigned i = 0; i < kNumDirectNodeBlocks; i++)
+ {
+ if (i == numBlocks)
+ return S_OK;
+ UInt32 val = GetUi32(p + 4 * i);
+ if (val >= _h.NumBlocks)
+ return S_FALSE;
+ blocks.Add(val);
+ }
+
+ for (unsigned level = 0; level < 3; level++)
+ {
+ if (blocks.Size() == numBlocks)
+ break;
+ UInt32 val = GetUi32(p + 4 * (kNumDirectNodeBlocks + level));
+ if (val >= _h.NumBlocks)
+ return S_FALSE;
+
+ if (val == 0)
+ {
+ /*
+ size_t num = (size_t)1 << ((_h.BlockBits - 2) * (level + 1));
+ for (size_t k = 0; k < num; k++)
+ {
+ blocks.Add(0);
+ if (blocks.Size() == numBlocks)
+ return S_OK;
+ }
+ continue;
+ */
+ return S_FALSE;
+ }
+
+ RINOK(FillFileBlocks2(val, level, numBlocks, blocks))
+ }
+
+ return S_OK;
+}
+
+
+static void AddSkipExtents(CRecordVector<CExtent> &extents, UInt32 virtBlock, UInt32 numBlocks)
+{
+ while (numBlocks != 0)
+ {
+ UInt32 len = numBlocks;
+ const UInt32 kLenMax = (UInt32)1 << 15;
+ if (len > kLenMax)
+ len = kLenMax;
+ CExtent e;
+ e.VirtBlock = virtBlock;
+ e.Len = (UInt16)len;
+ e.IsInited = false;
+ e.PhyStart = 0;
+ extents.Add(e);
+ virtBlock += len;
+ numBlocks -= len;
+ }
+}
+
+static bool UpdateExtents(CRecordVector<CExtent> &extents, UInt32 block)
+{
+ if (extents.IsEmpty())
+ {
+ if (block == 0)
+ return true;
+ AddSkipExtents(extents, 0, block);
+ return true;
+ }
+
+ const CExtent &prev = extents.Back();
+ if (block < prev.VirtBlock)
+ return false;
+ UInt32 prevEnd = prev.GetVirtEnd();
+ if (block == prevEnd)
+ return true;
+ AddSkipExtents(extents, prevEnd, block - prevEnd);
+ return true;
+}
+
+
+HRESULT CHandler::FillExtents(const Byte *p, size_t size, CRecordVector<CExtent> &extents, int parentDepth)
+{
+ CExtentTreeHeader eth;
+ if (!eth.Parse(p))
+ return S_FALSE;
+
+ if (parentDepth >= 0 && eth.Depth != parentDepth - 1) // (eth.Depth >= parentDepth)
+ return S_FALSE;
+
+ if (12 + 12 * (size_t)eth.NumEntries > size)
+ return S_FALSE;
+
+ if (eth.Depth >= kNumTreeLevelsMax)
+ return S_FALSE;
+
+ if (eth.Depth == 0)
+ {
+ for (unsigned i = 0; i < eth.NumEntries; i++)
+ {
+ CExtent e;
+ e.Parse(p + 12 + i * 12);
+ if (e.PhyStart == 0
+ || e.PhyStart > _h.NumBlocks
+ || e.PhyStart + e.Len > _h.NumBlocks
+ || !e.IsLenOK())
+ return S_FALSE;
+ if (!UpdateExtents(extents, e.VirtBlock))
+ return S_FALSE;
+ extents.Add(e);
+ }
+
+ return S_OK;
+ }
+
+ const size_t blockSize = (size_t)1 << _h.BlockBits;
+ CByteBuffer &tempBuf = _tempBufs[eth.Depth];
+ tempBuf.Alloc(blockSize);
+
+ for (unsigned i = 0; i < eth.NumEntries; i++)
+ {
+ CExtentIndexNode e;
+ e.Parse(p + 12 + i * 12);
+
+ if (e.PhyLeaf == 0 || e.PhyLeaf >= _h.NumBlocks)
+ return S_FALSE;
+
+ if (!UpdateExtents(extents, e.VirtBlock))
+ return S_FALSE;
+
+ RINOK(SeekAndRead(_stream, e.PhyLeaf, tempBuf, blockSize))
+ RINOK(FillExtents(tempBuf, blockSize, extents, eth.Depth))
+ }
+
+ return S_OK;
+}
+
+
+HRESULT CHandler::GetStream_Node(unsigned nodeIndex, ISequentialInStream **stream)
+{
+ COM_TRY_BEGIN
+
+ *stream = NULL;
+
+ const CNode &node = _nodes[nodeIndex];
+
+ if (!node.IsFlags_EXTENTS())
+ {
+ // maybe sparse file can have (node.NumBlocks == 0) ?
+
+ /* The following code doesn't work correctly for some CentOS images,
+ where there are nodes with inline data and (node.NumBlocks != 0).
+ If you know better way to detect inline data, please notify 7-Zip developers. */
+
+ if (node.NumBlocks == 0 && node.FileSize < kNodeBlockFieldSize)
+ {
+ Create_BufInStream_WithNewBuffer(node.Block, (size_t)node.FileSize, stream);
+ return S_OK;
+ }
+ }
+
+ if (node.FileSize >= ((UInt64)1 << 63))
+ return S_FALSE;
+
+ CMyComPtr<IInStream> streamTemp;
+
+ UInt64 numBlocks64 = (node.FileSize + (UInt64)(((UInt32)1 << _h.BlockBits) - 1)) >> _h.BlockBits;
+
+ if (node.IsFlags_EXTENTS())
+ {
+ if ((UInt32)numBlocks64 != numBlocks64)
+ return S_FALSE;
+
+ CExtInStream *streamSpec = new CExtInStream;
+ streamTemp = streamSpec;
+
+ streamSpec->BlockBits = _h.BlockBits;
+ streamSpec->Size = node.FileSize;
+ streamSpec->Stream = _stream;
+
+ RINOK(FillExtents(node.Block, kNodeBlockFieldSize, streamSpec->Extents, -1))
+
+ UInt32 end = 0;
+ if (!streamSpec->Extents.IsEmpty())
+ end = streamSpec->Extents.Back().GetVirtEnd();
+ if (end < numBlocks64)
+ {
+ AddSkipExtents(streamSpec->Extents, end, (UInt32)(numBlocks64 - end));
+ // return S_FALSE;
+ }
+
+ RINOK(streamSpec->StartSeek())
+ }
+ else
+ {
+ {
+ UInt64 numBlocks2 = numBlocks64;
+
+ if (numBlocks64 > kNumDirectNodeBlocks)
+ {
+ UInt64 rem = numBlocks64 - kNumDirectNodeBlocks;
+ const unsigned refBits = (_h.BlockBits - 2);
+ const size_t numRefsInBlocks = (size_t)1 << refBits;
+ numBlocks2++;
+ if (rem > numRefsInBlocks)
+ {
+ numBlocks2++;
+ const UInt64 numL2 = (rem - 1) >> refBits;
+ numBlocks2 += numL2;
+ if (numL2 > numRefsInBlocks)
+ {
+ numBlocks2++;
+ numBlocks2 += (numL2 - 1) >> refBits;
+ }
+ }
+ }
+
+ const unsigned specBits = (node.IsFlags_HUGE() ? 0 : _h.BlockBits - 9);
+ const UInt32 specMask = ((UInt32)1 << specBits) - 1;
+ if ((node.NumBlocks & specMask) != 0)
+ return S_FALSE;
+ const UInt64 numBlocks64_from_header = node.NumBlocks >> specBits;
+ if (numBlocks64_from_header < numBlocks2)
+ {
+ // why (numBlocks64_from_header > numBlocks2) in some cases?
+ // return S_FALSE;
+ }
+ }
+
+ unsigned numBlocks = (unsigned)numBlocks64;
+ if (numBlocks != numBlocks64)
+ return S_FALSE;
+
+ CClusterInStream2 *streamSpec = new CClusterInStream2;
+ streamTemp = streamSpec;
+
+ streamSpec->BlockBits = _h.BlockBits;
+ streamSpec->Size = node.FileSize;
+ streamSpec->Stream = _stream;
+
+ RINOK(FillFileBlocks(node.Block, numBlocks, streamSpec->Vector))
+ streamSpec->InitAndSeek();
+ }
+
+ *stream = streamTemp.Detach();
+
+ return S_OK;
+
+ COM_TRY_END
+}
+
+
+HRESULT CHandler::ExtractNode(unsigned nodeIndex, CByteBuffer &data)
+{
+ data.Free();
+ const CNode &node = _nodes[nodeIndex];
+ size_t size = (size_t)node.FileSize;
+ if (size != node.FileSize)
+ return S_FALSE;
+ CMyComPtr<ISequentialInStream> inSeqStream;
+ RINOK(GetStream_Node(nodeIndex, &inSeqStream))
+ if (!inSeqStream)
+ return S_FALSE;
+ data.Alloc(size);
+ _totalRead += size;
+ return ReadStream_FALSE(inSeqStream, data, size);
+}
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _items.Size() + _auxItems.Size();
+ if (numItems == 0)
+ return S_OK;
+
+ UInt64 totalSize = 0;
+ UInt32 i;
+
+ for (i = 0; i < numItems; i++)
+ {
+ const UInt32 index = allFilesMode ? i : indices[i];
+ if (index >= _items.Size())
+ continue;
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[_refs[item.Node]];
+ if (!node.IsDir())
+ totalSize += node.FileSize;
+ }
+
+ 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++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur())
+
+ if (i == numItems)
+ break;
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+
+ const UInt32 index = allFilesMode ? i : indices[i];
+
+ RINOK(extractCallback->GetStream(index, &outStream, askMode))
+
+ if (index >= _items.Size())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[_refs[item.Node]];
+
+ if (node.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+
+ UInt64 unpackSize = node.FileSize;
+ totalSize += unpackSize;
+ UInt64 packSize;
+ if (GetPackSize(index, packSize))
+ totalPackSize += packSize;
+
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode))
+
+ int res = NExtract::NOperationResult::kDataError;
+ {
+ CMyComPtr<ISequentialInStream> inSeqStream;
+ HRESULT hres = GetStream(index, &inSeqStream);
+ if (hres == S_FALSE || !inSeqStream)
+ {
+ if (hres == E_OUTOFMEMORY)
+ return hres;
+ res = NExtract::NOperationResult::kUnsupportedMethod;
+ }
+ else
+ {
+ RINOK(hres)
+ {
+ hres = copyCoder->Code(inSeqStream, outStream, NULL, NULL, progress);
+ if (hres == S_OK)
+ {
+ if (copyCoderSpec->TotalSize == unpackSize)
+ res = NExtract::NOperationResult::kOK;
+ }
+ else if (hres == E_NOTIMPL)
+ {
+ res = NExtract::NOperationResult::kUnsupportedMethod;
+ }
+ else if (hres != S_FALSE)
+ {
+ RINOK(hres)
+ }
+ }
+ }
+ }
+ RINOK(extractCallback->SetOperationResult(res))
+ }
+
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ *stream = NULL;
+ if (index >= _items.Size())
+ return S_FALSE;
+ return GetStream_Node((unsigned)_refs[_items[index].Node], stream);
+}
+
+
+API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize);
+API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize)
+{
+ if (phySize)
+ *phySize = 0;
+ if (size < kHeaderSize)
+ return k_IsArc_Res_NEED_MORE;
+ CHeader h;
+ if (!h.Parse(p + kHeaderDataOffset))
+ return k_IsArc_Res_NO;
+ if (phySize)
+ *phySize = h.GetPhySize();
+ return k_IsArc_Res_YES;
+}
+
+
+API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size);
+API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size)
+{
+ return IsArc_Ext_PhySize(p, size, NULL);
+}
+
+
+static const Byte k_Signature[] = { 0x53, 0xEF };
+
+REGISTER_ARC_I(
+ "Ext", "ext ext2 ext3 ext4 img", NULL, 0xC7,
+ k_Signature,
+ 0x438,
+ 0,
+ IsArc_Ext)
+
+}}
diff --git a/CPP/7zip/Archive/FatHandler.cpp b/CPP/7zip/Archive/FatHandler.cpp
new file mode 100644
index 0000000..4a843a8
--- /dev/null
+++ b/CPP/7zip/Archive/FatHandler.cpp
@@ -0,0 +1,1068 @@
+// FatHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/MyCom.h"
+#include "../../Common/StringConvert.h"
+
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/TimeUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "Common/DummyOutStream.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
+#define PRF(x) /* x */
+
+namespace NArchive {
+namespace NFat {
+
+static const UInt32 kFatItemUsedByDirMask = (UInt32)1 << 31;
+
+struct CHeader
+{
+ UInt32 NumSectors;
+ UInt16 NumReservedSectors;
+ Byte NumFats;
+ UInt32 NumFatSectors;
+ UInt32 RootDirSector;
+ UInt32 NumRootDirSectors;
+ UInt32 DataSector;
+
+ UInt32 FatSize;
+ UInt32 BadCluster;
+
+ Byte NumFatBits;
+ Byte SectorSizeLog;
+ Byte SectorsPerClusterLog;
+ Byte ClusterSizeLog;
+
+ UInt16 SectorsPerTrack;
+ UInt16 NumHeads;
+ UInt32 NumHiddenSectors;
+
+ bool VolFieldsDefined;
+
+ UInt32 VolId;
+ // Byte VolName[11];
+ // Byte FileSys[8];
+
+ // Byte OemName[5];
+ Byte MediaType;
+
+ // 32-bit FAT
+ UInt16 Flags;
+ UInt16 FsInfoSector;
+ UInt32 RootCluster;
+
+ bool IsFat32() const { return NumFatBits == 32; }
+ UInt64 GetPhySize() const { return (UInt64)NumSectors << SectorSizeLog; }
+ UInt32 SectorSize() const { return (UInt32)1 << SectorSizeLog; }
+ UInt32 ClusterSize() const { return (UInt32)1 << ClusterSizeLog; }
+ UInt32 ClusterToSector(UInt32 c) const { return DataSector + ((c - 2) << SectorsPerClusterLog); }
+ UInt32 IsEoc(UInt32 c) const { return c > BadCluster; }
+ UInt32 IsEocAndUnused(UInt32 c) const { return c > BadCluster && (c & kFatItemUsedByDirMask) == 0; }
+ UInt32 IsValidCluster(UInt32 c) const { return c >= 2 && c < FatSize; }
+ UInt32 SizeToSectors(UInt32 size) const { return (size + SectorSize() - 1) >> SectorSizeLog; }
+ UInt32 CalcFatSizeInSectors() const { return SizeToSectors((FatSize * (NumFatBits / 4) + 1) / 2); }
+
+ UInt32 GetFatSector() const
+ {
+ UInt32 index = (IsFat32() && (Flags & 0x80) != 0) ? (Flags & 0xF) : 0;
+ if (index > NumFats)
+ index = 0;
+ return NumReservedSectors + index * NumFatSectors;
+ }
+
+ UInt64 GetFilePackSize(UInt32 unpackSize) const
+ {
+ UInt64 mask = ClusterSize() - 1;
+ return (unpackSize + mask) & ~mask;
+ }
+
+ UInt32 GetNumClusters(UInt32 size) const
+ { return (UInt32)(((UInt64)size + ClusterSize() - 1) >> ClusterSizeLog); }
+
+ bool Parse(const Byte *p);
+};
+
+static int GetLog(UInt32 num)
+{
+ for (int i = 0; i < 31; i++)
+ if (((UInt32)1 << i) == num)
+ return i;
+ return -1;
+}
+
+static const UInt32 kHeaderSize = 512;
+
+API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size);
+API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size)
+{
+ if (size < kHeaderSize)
+ return k_IsArc_Res_NEED_MORE;
+ CHeader h;
+ return h.Parse(p) ? k_IsArc_Res_YES : k_IsArc_Res_NO;
+}
+
+bool CHeader::Parse(const Byte *p)
+{
+ if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA)
+ return false;
+
+ int codeOffset = 0;
+ switch (p[0])
+ {
+ case 0xE9: codeOffset = 3 + (Int16)Get16(p + 1); break;
+ case 0xEB: if (p[2] != 0x90) return false; codeOffset = 2 + (signed char)p[1]; break;
+ default: return false;
+ }
+ {
+ {
+ const UInt32 val32 = Get16(p + 11);
+ const int s = GetLog(val32);
+ if (s < 9 || s > 12)
+ return false;
+ SectorSizeLog = (Byte)s;
+ }
+ {
+ const UInt32 val32 = p[13];
+ const int s = GetLog(val32);
+ if (s < 0)
+ return false;
+ SectorsPerClusterLog = (Byte)s;
+ }
+ ClusterSizeLog = (Byte)(SectorSizeLog + SectorsPerClusterLog);
+ if (ClusterSizeLog > 24)
+ return false;
+ }
+
+ NumReservedSectors = Get16(p + 14);
+ if (NumReservedSectors == 0)
+ return false;
+
+ NumFats = p[16];
+ if (NumFats < 1 || NumFats > 4)
+ return false;
+
+ // we also support images that contain 0 in offset field.
+ const bool isOkOffset = (codeOffset == 0)
+ || (codeOffset == (p[0] == 0xEB ? 2 : 3));
+
+ const UInt16 numRootDirEntries = Get16(p + 17);
+ if (numRootDirEntries == 0)
+ {
+ if (codeOffset < 90 && !isOkOffset)
+ return false;
+ NumFatBits = 32;
+ NumRootDirSectors = 0;
+ }
+ else
+ {
+ // Some FAT12s don't contain VolFields
+ if (codeOffset < 62 - 24 && !isOkOffset)
+ return false;
+ NumFatBits = 0;
+ const UInt32 mask = (1 << (SectorSizeLog - 5)) - 1;
+ if ((numRootDirEntries & mask) != 0)
+ return false;
+ NumRootDirSectors = (numRootDirEntries + mask) >> (SectorSizeLog - 5);
+ }
+
+ NumSectors = Get16(p + 19);
+ if (NumSectors == 0)
+ NumSectors = Get32(p + 32);
+ /*
+ // mkfs.fat could create fat32 image with 16-bit number of sectors.
+ // v23: we allow 16-bit value for number of sectors in fat32.
+ else if (IsFat32())
+ return false;
+ */
+
+ MediaType = p[21];
+ NumFatSectors = Get16(p + 22);
+ SectorsPerTrack = Get16(p + 24);
+ NumHeads = Get16(p + 26);
+ NumHiddenSectors = Get32(p + 28);
+
+ // memcpy(OemName, p + 3, 5);
+
+ int curOffset = 36;
+ p += 36;
+ if (IsFat32())
+ {
+ if (NumFatSectors != 0)
+ return false;
+ NumFatSectors = Get32(p);
+ if (NumFatSectors >= (1 << 24))
+ return false;
+
+ Flags = Get16(p + 4);
+ if (Get16(p + 6) != 0)
+ return false;
+ RootCluster = Get32(p + 8);
+ FsInfoSector = Get16(p + 12);
+ for (int i = 16; i < 28; i++)
+ if (p[i] != 0)
+ return false;
+ p += 28;
+ curOffset += 28;
+ }
+
+ // DriveNumber = p[0];
+ VolFieldsDefined = false;
+ if (codeOffset >= curOffset + 3)
+ {
+ VolFieldsDefined = (p[2] == 0x29); // ExtendedBootSig
+ if (VolFieldsDefined)
+ {
+ if (codeOffset < curOffset + 26)
+ return false;
+ VolId = Get32(p + 3);
+ // memcpy(VolName, p + 7, 11);
+ // memcpy(FileSys, p + 18, 8);
+ }
+ }
+
+ if (NumFatSectors == 0)
+ return false;
+ RootDirSector = NumReservedSectors + NumFatSectors * NumFats;
+ DataSector = RootDirSector + NumRootDirSectors;
+ if (NumSectors < DataSector)
+ return false;
+ const UInt32 numDataSectors = NumSectors - DataSector;
+ const UInt32 numClusters = numDataSectors >> SectorsPerClusterLog;
+
+ BadCluster = 0x0FFFFFF7;
+ // v23: we support unusual (< 0xFFF5) numClusters values in fat32 systems
+ if (NumFatBits != 32)
+ {
+ if (numClusters >= 0xFFF5)
+ return false;
+ NumFatBits = (Byte)(numClusters < 0xFF5 ? 12 : 16);
+ BadCluster &= ((1 << NumFatBits) - 1);
+ }
+
+ FatSize = numClusters + 2;
+ if (FatSize > BadCluster || CalcFatSizeInSectors() > NumFatSectors)
+ return false;
+ return true;
+}
+
+struct CItem
+{
+ UString UName;
+ char DosName[11];
+ Byte CTime2;
+ UInt32 CTime;
+ UInt32 MTime;
+ UInt16 ADate;
+ Byte Attrib;
+ Byte Flags;
+ UInt32 Size;
+ UInt32 Cluster;
+ Int32 Parent;
+
+ // NT uses Flags to store Low Case status
+ bool NameIsLow() const { return (Flags & 0x8) != 0; }
+ bool ExtIsLow() const { return (Flags & 0x10) != 0; }
+ bool IsDir() const { return (Attrib & 0x10) != 0; }
+ UString GetShortName() const;
+ UString GetName() const;
+ UString GetVolName() const;
+};
+
+static unsigned CopyAndTrim(char *dest, const char *src, unsigned size, bool toLower)
+{
+ memcpy(dest, src, size);
+ if (toLower)
+ {
+ for (unsigned i = 0; i < size; i++)
+ {
+ char c = dest[i];
+ if (c >= 'A' && c <= 'Z')
+ dest[i] = (char)(c + 0x20);
+ }
+ }
+
+ for (unsigned i = size;;)
+ {
+ if (i == 0)
+ return 0;
+ if (dest[i - 1] != ' ')
+ return i;
+ i--;
+ }
+}
+
+static UString FatStringToUnicode(const char *s)
+{
+ return MultiByteToUnicodeString(s, CP_OEMCP);
+}
+
+UString CItem::GetShortName() const
+{
+ char s[16];
+ unsigned i = CopyAndTrim(s, DosName, 8, NameIsLow());
+ s[i++] = '.';
+ unsigned j = CopyAndTrim(s + i, DosName + 8, 3, ExtIsLow());
+ if (j == 0)
+ i--;
+ s[i + j] = 0;
+ return FatStringToUnicode(s);
+}
+
+UString CItem::GetName() const
+{
+ if (!UName.IsEmpty())
+ return UName;
+ return GetShortName();
+}
+
+UString CItem::GetVolName() const
+{
+ if (!UName.IsEmpty())
+ return UName;
+ char s[12];
+ unsigned i = CopyAndTrim(s, DosName, 11, false);
+ s[i] = 0;
+ return FatStringToUnicode(s);
+}
+
+struct CDatabase
+{
+ CHeader Header;
+ CObjectVector<CItem> Items;
+ UInt32 *Fat;
+ CMyComPtr<IInStream> InStream;
+ IArchiveOpenCallback *OpenCallback;
+
+ UInt32 NumFreeClusters;
+ bool VolItemDefined;
+ CItem VolItem;
+ UInt32 NumDirClusters;
+ CByteBuffer ByteBuf;
+ UInt64 NumCurUsedBytes;
+
+ UInt64 PhySize;
+
+ CDatabase(): Fat(NULL) {}
+ ~CDatabase() { ClearAndClose(); }
+
+ void Clear();
+ void ClearAndClose();
+ HRESULT OpenProgressFat(bool changeTotal = true);
+ HRESULT OpenProgress();
+
+ UString GetItemPath(UInt32 index) const;
+ HRESULT Open();
+ HRESULT ReadDir(Int32 parent, UInt32 cluster, unsigned level);
+
+ UInt64 GetHeadersSize() const
+ {
+ return (UInt64)(Header.DataSector + (NumDirClusters << Header.SectorsPerClusterLog)) << Header.SectorSizeLog;
+ }
+ HRESULT SeekToSector(UInt32 sector);
+ HRESULT SeekToCluster(UInt32 cluster) { return SeekToSector(Header.ClusterToSector(cluster)); }
+};
+
+HRESULT CDatabase::SeekToSector(UInt32 sector)
+{
+ return InStream_SeekSet(InStream, (UInt64)sector << Header.SectorSizeLog);
+}
+
+void CDatabase::Clear()
+{
+ PhySize = 0;
+ VolItemDefined = false;
+ NumDirClusters = 0;
+ NumCurUsedBytes = 0;
+
+ Items.Clear();
+ delete []Fat;
+ Fat = NULL;
+}
+
+void CDatabase::ClearAndClose()
+{
+ Clear();
+ InStream.Release();
+}
+
+HRESULT CDatabase::OpenProgressFat(bool changeTotal)
+{
+ if (!OpenCallback)
+ return S_OK;
+ if (changeTotal)
+ {
+ UInt64 numTotalBytes = (Header.CalcFatSizeInSectors() << Header.SectorSizeLog) +
+ ((UInt64)(Header.FatSize - NumFreeClusters) << Header.ClusterSizeLog);
+ RINOK(OpenCallback->SetTotal(NULL, &numTotalBytes))
+ }
+ return OpenCallback->SetCompleted(NULL, &NumCurUsedBytes);
+}
+
+HRESULT CDatabase::OpenProgress()
+{
+ if (!OpenCallback)
+ return S_OK;
+ UInt64 numItems = Items.Size();
+ return OpenCallback->SetCompleted(&numItems, &NumCurUsedBytes);
+}
+
+UString CDatabase::GetItemPath(UInt32 index) const
+{
+ const CItem *item = &Items[index];
+ UString name = item->GetName();
+ for (;;)
+ {
+ index = (UInt32)item->Parent;
+ if (item->Parent < 0)
+ return name;
+ item = &Items[index];
+ name.InsertAtFront(WCHAR_PATH_SEPARATOR);
+ if (item->UName.IsEmpty())
+ name.Insert(0, item->GetShortName());
+ else
+ name.Insert(0, item->UName);
+ }
+}
+
+static wchar_t *AddSubStringToName(wchar_t *dest, const Byte *p, unsigned numChars)
+{
+ for (unsigned i = 0; i < numChars; i++)
+ {
+ wchar_t c = Get16(p + i * 2);
+ if (c != 0 && c != 0xFFFF)
+ *dest++ = c;
+ }
+ *dest = 0;
+ return dest;
+}
+
+HRESULT CDatabase::ReadDir(Int32 parent, UInt32 cluster, unsigned level)
+{
+ unsigned startIndex = Items.Size();
+ if (startIndex >= (1 << 30) || level > 256)
+ return S_FALSE;
+
+ UInt32 sectorIndex = 0;
+ UInt32 blockSize = Header.ClusterSize();
+ bool clusterMode = (Header.IsFat32() || parent >= 0);
+ if (!clusterMode)
+ {
+ blockSize = Header.SectorSize();
+ RINOK(SeekToSector(Header.RootDirSector))
+ }
+
+ ByteBuf.Alloc(blockSize);
+ UString curName;
+ int checkSum = -1;
+ int numLongRecords = -1;
+
+ for (UInt32 pos = blockSize;; pos += 32)
+ {
+ if (pos == blockSize)
+ {
+ pos = 0;
+
+ if ((NumDirClusters & 0xFF) == 0)
+ {
+ RINOK(OpenProgress())
+ }
+
+ if (clusterMode)
+ {
+ if (Header.IsEoc(cluster))
+ break;
+ if (!Header.IsValidCluster(cluster))
+ return S_FALSE;
+ PRF(printf("\nCluster = %4X", cluster));
+ RINOK(SeekToCluster(cluster))
+ UInt32 newCluster = Fat[cluster];
+ if ((newCluster & kFatItemUsedByDirMask) != 0)
+ return S_FALSE;
+ Fat[cluster] |= kFatItemUsedByDirMask;
+ cluster = newCluster;
+ NumDirClusters++;
+ NumCurUsedBytes += Header.ClusterSize();
+ }
+ else if (sectorIndex++ >= Header.NumRootDirSectors)
+ break;
+
+ RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize))
+ }
+
+ const Byte *p = ByteBuf + pos;
+
+ if (p[0] == 0)
+ {
+ /*
+ // FreeDOS formats FAT partition with cluster chain longer than required.
+ if (clusterMode && !Header.IsEoc(cluster))
+ return S_FALSE;
+ */
+ break;
+ }
+
+ if (p[0] == 0xE5)
+ {
+ if (numLongRecords > 0)
+ return S_FALSE;
+ continue;
+ }
+
+ Byte attrib = p[11];
+ if ((attrib & 0x3F) == 0xF)
+ {
+ if (p[0] > 0x7F || Get16(p + 26) != 0)
+ return S_FALSE;
+ int longIndex = p[0] & 0x3F;
+ if (longIndex == 0)
+ return S_FALSE;
+ bool isLast = (p[0] & 0x40) != 0;
+ if (numLongRecords < 0)
+ {
+ if (!isLast)
+ return S_FALSE;
+ numLongRecords = longIndex;
+ }
+ else if (isLast || numLongRecords != longIndex)
+ return S_FALSE;
+
+ numLongRecords--;
+
+ if (p[12] == 0)
+ {
+ wchar_t nameBuf[14];
+ wchar_t *dest;
+
+ dest = AddSubStringToName(nameBuf, p + 1, 5);
+ dest = AddSubStringToName(dest, p + 14, 6);
+ AddSubStringToName(dest, p + 28, 2);
+ curName = nameBuf + curName;
+ if (isLast)
+ checkSum = p[13];
+ if (checkSum != p[13])
+ return S_FALSE;
+ }
+ }
+ else
+ {
+ if (numLongRecords > 0)
+ return S_FALSE;
+ CItem item;
+ memcpy(item.DosName, p, 11);
+
+ if (checkSum >= 0)
+ {
+ Byte sum = 0;
+ for (unsigned i = 0; i < 11; i++)
+ sum = (Byte)(((sum & 1) ? 0x80 : 0) + (sum >> 1) + (Byte)item.DosName[i]);
+ if (sum == checkSum)
+ item.UName = curName;
+ }
+
+ if (item.DosName[0] == 5)
+ item.DosName[0] = (char)(Byte)0xE5;
+ item.Attrib = attrib;
+ item.Flags = p[12];
+ item.Size = Get32(p + 28);
+ item.Cluster = Get16(p + 26);
+ if (Header.NumFatBits > 16)
+ item.Cluster |= ((UInt32)Get16(p + 20) << 16);
+ else
+ {
+ // OS/2 and WinNT probably can store EA (extended atributes) in that field.
+ }
+
+ item.CTime = Get32(p + 14);
+ item.CTime2 = p[13];
+ item.ADate = Get16(p + 18);
+ item.MTime = Get32(p + 22);
+ item.Parent = parent;
+
+ if (attrib == 8)
+ {
+ VolItem = item;
+ VolItemDefined = true;
+ }
+ else
+ if (memcmp(item.DosName, ". ", 11) != 0 &&
+ memcmp(item.DosName, ".. ", 11) != 0)
+ {
+ if (!item.IsDir())
+ NumCurUsedBytes += Header.GetFilePackSize(item.Size);
+ Items.Add(item);
+ PRF(printf("\n%7d: %S", Items.Size(), GetItemPath(Items.Size() - 1)));
+ }
+ numLongRecords = -1;
+ curName.Empty();
+ checkSum = -1;
+ }
+ }
+
+ unsigned finishIndex = Items.Size();
+ for (unsigned i = startIndex; i < finishIndex; i++)
+ {
+ const CItem &item = Items[i];
+ if (item.IsDir())
+ {
+ PRF(printf("\n%S", GetItemPath(i)));
+ RINOK(CDatabase::ReadDir((int)i, item.Cluster, level + 1))
+ }
+ }
+ return S_OK;
+}
+
+HRESULT CDatabase::Open()
+{
+ Clear();
+ bool numFreeClustersDefined = false;
+ {
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize))
+ if (!Header.Parse(buf))
+ return S_FALSE;
+ UInt64 fileSize;
+ RINOK(InStream_GetSize_SeekToEnd(InStream, fileSize))
+
+ /* we comment that check to support truncated images */
+ /*
+ if (fileSize < Header.GetPhySize())
+ return S_FALSE;
+ */
+
+ if (Header.IsFat32())
+ {
+ SeekToSector(Header.FsInfoSector);
+ RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize))
+ if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA)
+ return S_FALSE;
+ if (Get32(buf) == 0x41615252 && Get32(buf + 484) == 0x61417272)
+ {
+ NumFreeClusters = Get32(buf + 488);
+ numFreeClustersDefined = (NumFreeClusters <= Header.FatSize);
+ }
+ }
+ }
+
+ // numFreeClustersDefined = false; // to recalculate NumFreeClusters
+ if (!numFreeClustersDefined)
+ NumFreeClusters = 0;
+
+ CByteBuffer byteBuf;
+ Fat = new UInt32[Header.FatSize];
+
+ RINOK(OpenProgressFat())
+ RINOK(SeekToSector(Header.GetFatSector()))
+ if (Header.NumFatBits == 32)
+ {
+ const UInt32 kBufSize = (1 << 15);
+ byteBuf.Alloc(kBufSize);
+ for (UInt32 i = 0; i < Header.FatSize;)
+ {
+ UInt32 size = Header.FatSize - i;
+ const UInt32 kBufSize32 = kBufSize / 4;
+ if (size > kBufSize32)
+ size = kBufSize32;
+ UInt32 readSize = Header.SizeToSectors(size * 4) << Header.SectorSizeLog;
+ RINOK(ReadStream_FALSE(InStream, byteBuf, readSize))
+ NumCurUsedBytes += readSize;
+
+ const UInt32 *src = (const UInt32 *)(const void *)(const Byte *)byteBuf;
+ UInt32 *dest = Fat + i;
+ if (numFreeClustersDefined)
+ for (UInt32 j = 0; j < size; j++)
+ dest[j] = Get32(src + j) & 0x0FFFFFFF;
+ else
+ {
+ UInt32 numFreeClusters = 0;
+ for (UInt32 j = 0; j < size; j++)
+ {
+ UInt32 v = Get32(src + j) & 0x0FFFFFFF;
+ numFreeClusters += (UInt32)(v - 1) >> 31;
+ dest[j] = v;
+ }
+ NumFreeClusters += numFreeClusters;
+ }
+ i += size;
+ if ((i & 0xFFFFF) == 0)
+ {
+ RINOK(OpenProgressFat(!numFreeClustersDefined))
+ }
+ }
+ }
+ else
+ {
+ const UInt32 kBufSize = (UInt32)Header.CalcFatSizeInSectors() << Header.SectorSizeLog;
+ NumCurUsedBytes += kBufSize;
+ byteBuf.Alloc(kBufSize);
+ Byte *p = byteBuf;
+ RINOK(ReadStream_FALSE(InStream, p, kBufSize))
+ UInt32 fatSize = Header.FatSize;
+ UInt32 *fat = &Fat[0];
+ if (Header.NumFatBits == 16)
+ for (UInt32 j = 0; j < fatSize; j++)
+ fat[j] = Get16(p + j * 2);
+ else
+ for (UInt32 j = 0; j < fatSize; j++)
+ fat[j] = (Get16(p + j * 3 / 2) >> ((j & 1) << 2)) & 0xFFF;
+
+ if (!numFreeClustersDefined)
+ {
+ UInt32 numFreeClusters = 0;
+ for (UInt32 i = 0; i < fatSize; i++)
+ numFreeClusters += (UInt32)(fat[i] - 1) >> 31;
+ NumFreeClusters = numFreeClusters;
+ }
+ }
+
+ RINOK(OpenProgressFat())
+
+ if ((Fat[0] & 0xFF) != Header.MediaType)
+ {
+ // that case can mean error in FAT,
+ // but xdf file: (MediaType == 0xF0 && Fat[0] == 0xFF9)
+ // 19.00: so we use non-strict check
+ if ((Fat[0] & 0xFF) < 0xF0)
+ return S_FALSE;
+ }
+
+ RINOK(ReadDir(-1, Header.RootCluster, 0))
+
+ PhySize = Header.GetPhySize();
+ return S_OK;
+}
+
+
+
+Z7_class_CHandler_final:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp,
+ CDatabase
+{
+ Z7_IFACES_IMP_UNK_2(IInArchive, IInArchiveGetStream)
+};
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ *stream = NULL;
+ const CItem &item = Items[index];
+ CClusterInStream *streamSpec = new CClusterInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->Stream = InStream;
+ streamSpec->StartOffset = Header.DataSector << Header.SectorSizeLog;
+ streamSpec->BlockSizeLog = Header.ClusterSizeLog;
+ streamSpec->Size = item.Size;
+
+ UInt32 numClusters = Header.GetNumClusters(item.Size);
+ streamSpec->Vector.ClearAndReserve(numClusters);
+ UInt32 cluster = item.Cluster;
+ UInt32 size = item.Size;
+
+ if (size == 0)
+ {
+ if (cluster != 0)
+ return S_FALSE;
+ }
+ else
+ {
+ UInt32 clusterSize = Header.ClusterSize();
+ for (;; size -= clusterSize)
+ {
+ if (!Header.IsValidCluster(cluster))
+ return S_FALSE;
+ streamSpec->Vector.AddInReserved(cluster - 2);
+ cluster = Fat[cluster];
+ if (size <= clusterSize)
+ break;
+ }
+ if (!Header.IsEocAndUnused(cluster))
+ return S_FALSE;
+ }
+ RINOK(streamSpec->InitAndSeek())
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidCTime,
+ kpidATime,
+ kpidAttrib,
+ kpidShortName
+};
+
+enum
+{
+ kpidNumFats = kpidUserDefined
+ // kpidOemName,
+ // kpidVolName,
+ // kpidFileSysType
+};
+
+static const CStatProp kArcProps[] =
+{
+ { NULL, kpidFileSystem, VT_BSTR},
+ { NULL, kpidClusterSize, VT_UI4},
+ { NULL, kpidFreeSpace, VT_UI8},
+ { NULL, kpidHeadersSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidVolumeName, VT_BSTR},
+
+ { "FATs", kpidNumFats, VT_UI4},
+ { NULL, kpidSectorSize, VT_UI4},
+ { NULL, kpidId, VT_UI4},
+ // { "OEM Name", kpidOemName, VT_BSTR},
+ // { "Volume Name", kpidVolName, VT_BSTR},
+ // { "File System Type", kpidFileSysType, VT_BSTR}
+ // { NULL, kpidSectorsPerTrack, VT_UI4},
+ // { NULL, kpidNumHeads, VT_UI4},
+ // { NULL, kpidHiddenSectors, VT_UI4}
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_WITH_NAME
+
+
+static void FatTimeToProp(UInt32 dosTime, UInt32 ms10, NWindows::NCOM::CPropVariant &prop)
+{
+ FILETIME localFileTime, utc;
+ if (NWindows::NTime::DosTime_To_FileTime(dosTime, localFileTime))
+ if (LocalFileTimeToFileTime(&localFileTime, &utc))
+ {
+ UInt64 t64 = (((UInt64)utc.dwHighDateTime) << 32) + utc.dwLowDateTime;
+ t64 += ms10 * 100000;
+ utc.dwLowDateTime = (DWORD)t64;
+ utc.dwHighDateTime = (DWORD)(t64 >> 32);
+ prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_Base + 2);
+ }
+}
+
+/*
+static void StringToProp(const Byte *src, unsigned size, NWindows::NCOM::CPropVariant &prop)
+{
+ char dest[32];
+ memcpy(dest, src, size);
+ dest[size] = 0;
+ prop = FatStringToUnicode(dest);
+}
+
+#define STRING_TO_PROP(s, p) StringToProp(s, sizeof(s), prop)
+*/
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidFileSystem:
+ {
+ char s[16];
+ s[0] = 'F';
+ s[1] = 'A';
+ s[2] = 'T';
+ ConvertUInt32ToString(Header.NumFatBits, s + 3);
+ prop = s;
+ break;
+ }
+ case kpidClusterSize: prop = Header.ClusterSize(); break;
+ case kpidPhySize: prop = PhySize; break;
+ case kpidFreeSpace: prop = (UInt64)NumFreeClusters << Header.ClusterSizeLog; break;
+ case kpidHeadersSize: prop = GetHeadersSize(); break;
+ case kpidMTime: if (VolItemDefined) PropVariant_SetFrom_DosTime(prop, VolItem.MTime); break;
+ case kpidShortComment:
+ case kpidVolumeName: if (VolItemDefined) prop = VolItem.GetVolName(); break;
+ case kpidNumFats: if (Header.NumFats != 2) prop = Header.NumFats; break;
+ case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break;
+ // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break;
+ // case kpidNumHeads: prop = Header.NumHeads; break;
+ // case kpidOemName: STRING_TO_PROP(Header.OemName, prop); break;
+ case kpidId: if (Header.VolFieldsDefined) prop = Header.VolId; break;
+ // case kpidVolName: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.VolName, prop); break;
+ // case kpidFileSysType: if (Header.VolFieldsDefined) STRING_TO_PROP(Header.FileSys, prop); break;
+ // case kpidHiddenSectors: prop = Header.NumHiddenSectors; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = Items[index];
+ switch (propID)
+ {
+ case kpidPath: prop = GetItemPath(index); break;
+ case kpidShortName: prop = item.GetShortName(); break;
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidMTime: PropVariant_SetFrom_DosTime(prop, item.MTime); break;
+ case kpidCTime: FatTimeToProp(item.CTime, item.CTime2, prop); break;
+ case kpidATime: PropVariant_SetFrom_DosTime(prop, ((UInt32)item.ADate << 16)); break;
+ case kpidAttrib: prop = (UInt32)item.Attrib; break;
+ case kpidSize: if (!item.IsDir()) prop = item.Size; break;
+ case kpidPackSize: if (!item.IsDir()) prop = Header.GetFilePackSize(item.Size); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ {
+ OpenCallback = callback;
+ InStream = stream;
+ HRESULT res;
+ try
+ {
+ res = CDatabase::Open();
+ if (res == S_OK)
+ return S_OK;
+ }
+ catch(...)
+ {
+ Close();
+ throw;
+ }
+ Close();
+ return res;
+ }
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ ClearAndClose();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = Items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt32 i;
+ UInt64 totalSize = 0;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItem &item = Items[allFilesMode ? i : indices[i]];
+ if (!item.IsDir())
+ totalSize += item.Size;
+ }
+ RINOK(extractCallback->SetTotal(totalSize))
+
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+ for (i = 0;; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur())
+ if (i == numItems)
+ break;
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CItem &item = Items[index];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+
+ totalPackSize += Header.GetFilePackSize(item.Size);
+ totalSize += item.Size;
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode))
+
+ outStreamSpec->SetStream(realOutStream);
+ realOutStream.Release();
+ outStreamSpec->Init();
+
+ int res = NExtract::NOperationResult::kDataError;
+ CMyComPtr<ISequentialInStream> inStream;
+ HRESULT hres = GetStream(index, &inStream);
+ if (hres != S_FALSE)
+ {
+ RINOK(hres)
+ if (inStream)
+ {
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress))
+ if (copyCoderSpec->TotalSize == item.Size)
+ res = NExtract::NOperationResult::kOK;
+ }
+ }
+ outStreamSpec->ReleaseStream();
+ RINOK(extractCallback->SetOperationResult(res))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = Items.Size();
+ return S_OK;
+}
+
+static const Byte k_Signature[] = { 0x55, 0xAA };
+
+REGISTER_ARC_I(
+ "FAT", "fat img", NULL, 0xDA,
+ k_Signature,
+ 0x1FE,
+ 0,
+ IsArc_Fat)
+
+}}
diff --git a/CPP/7zip/Archive/FlvHandler.cpp b/CPP/7zip/Archive/FlvHandler.cpp
new file mode 100644
index 0000000..1f746aa
--- /dev/null
+++ b/CPP/7zip/Archive/FlvHandler.cpp
@@ -0,0 +1,521 @@
+// FlvHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/MyString.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#define GetBe24(p) ( \
+ ((UInt32)((const Byte *)(p))[0] << 16) | \
+ ((UInt32)((const Byte *)(p))[1] << 8) | \
+ ((const Byte *)(p))[2] )
+
+// #define Get16(p) GetBe16(p)
+#define Get24(p) GetBe24(p)
+#define Get32(p) GetBe32(p)
+
+namespace NArchive {
+namespace NFlv {
+
+// static const UInt32 kFileSizeMax = (UInt32)1 << 30;
+static const UInt32 kNumChunksMax = (UInt32)1 << 23;
+
+static const UInt32 kTagHeaderSize = 11;
+
+static const Byte kFlag_Video = 1;
+static const Byte kFlag_Audio = 4;
+
+static const Byte kType_Audio = 8;
+static const Byte kType_Video = 9;
+static const Byte kType_Meta = 18;
+static const unsigned kNumTypes = 19;
+
+struct CItem
+{
+ CByteBuffer Data;
+ Byte Type;
+};
+
+struct CItem2
+{
+ Byte Type;
+ Byte SubType;
+ Byte Props;
+ bool SameSubTypes;
+ unsigned NumChunks;
+ size_t Size;
+
+ CReferenceBuf *BufSpec;
+ CMyComPtr<IUnknown> RefBuf;
+
+ bool IsAudio() const { return Type == kType_Audio; }
+};
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IInArchiveGetStream
+)
+ CMyComPtr<IInStream> _stream;
+ CObjectVector<CItem2> _items2;
+ CByteBuffer _metadata;
+ bool _isRaw;
+ UInt64 _phySize;
+
+ HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
+ // AString GetComment();
+};
+
+static const Byte kProps[] =
+{
+ kpidSize,
+ kpidNumBlocks,
+ kpidComment
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+static const char * const g_AudioTypes[16] =
+{
+ "pcm"
+ , "adpcm"
+ , "mp3"
+ , "pcm_le"
+ , "nellymoser16"
+ , "nellymoser8"
+ , "nellymoser"
+ , "g711a"
+ , "g711m"
+ , "audio9"
+ , "aac"
+ , "speex"
+ , "audio12"
+ , "audio13"
+ , "mp3"
+ , "audio15"
+};
+
+static const char * const g_VideoTypes[16] =
+{
+ "video0"
+ , "jpeg"
+ , "h263"
+ , "screen"
+ , "vp6"
+ , "vp6alpha"
+ , "screen2"
+ , "avc"
+ , "video8"
+ , "video9"
+ , "video10"
+ , "video11"
+ , "video12"
+ , "video13"
+ , "video14"
+ , "video15"
+};
+
+static const char * const g_Rates[4] =
+{
+ "5.5 kHz"
+ , "11 kHz"
+ , "22 kHz"
+ , "44 kHz"
+};
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ NWindows::NCOM::CPropVariant prop;
+ const CItem2 &item = _items2[index];
+ switch (propID)
+ {
+ case kpidExtension:
+ prop = _isRaw ?
+ (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) :
+ (item.IsAudio() ? "audio.flv" : "video.flv");
+ break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)item.Size;
+ break;
+ case kpidNumBlocks: prop = (UInt32)item.NumChunks; break;
+ case kpidComment:
+ {
+ char sz[64];
+ char *s = MyStpCpy(sz, (item.IsAudio() ? g_AudioTypes[item.SubType] : g_VideoTypes[item.SubType]) );
+ if (item.IsAudio())
+ {
+ *s++ = ' ';
+ s = MyStpCpy(s, g_Rates[(item.Props >> 2) & 3]);
+ s = MyStpCpy(s, (item.Props & 2) ? " 16-bit" : " 8-bit");
+ s = MyStpCpy(s, (item.Props & 1) ? " stereo" : " mono");
+ }
+ prop = sz;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+/*
+AString CHandler::GetComment()
+{
+ const Byte *p = _metadata;
+ size_t size = _metadata.Size();
+ AString res;
+ if (size > 0)
+ {
+ p++;
+ size--;
+ for (;;)
+ {
+ if (size < 2)
+ break;
+ int len = Get16(p);
+ p += 2;
+ size -= 2;
+ if (len == 0 || (size_t)len > size)
+ break;
+ {
+ AString temp;
+ temp.SetFrom_CalcLen((const char *)p, len);
+ if (!res.IsEmpty())
+ res += '\n';
+ res += temp;
+ }
+ p += len;
+ size -= len;
+ if (size < 1)
+ break;
+ Byte type = *p++;
+ size--;
+ bool ok = false;
+ switch (type)
+ {
+ case 0:
+ {
+ if (size < 8)
+ break;
+ ok = true;
+ Byte reverse[8];
+ for (int i = 0; i < 8; i++)
+ {
+ bool little_endian = 1;
+ if (little_endian)
+ reverse[i] = p[7 - i];
+ else
+ reverse[i] = p[i];
+ }
+ double d = *(double *)reverse;
+ char temp[32];
+ sprintf(temp, " = %.3f", d);
+ res += temp;
+ p += 8;
+ size -= 8;
+ break;
+ }
+ case 8:
+ {
+ if (size < 4)
+ break;
+ ok = true;
+ // UInt32 numItems = Get32(p);
+ p += 4;
+ size -= 4;
+ break;
+ }
+ }
+ if (!ok)
+ break;
+ }
+ }
+ return res;
+}
+*/
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ // COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ // case kpidComment: prop = GetComment(); break;
+ case kpidPhySize: prop = (UInt64)_phySize; break;
+ case kpidIsNotArcType: prop = true; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ // COM_TRY_END
+}
+
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
+{
+ const UInt32 kHeaderSize = 13;
+ Byte header[kHeaderSize];
+ RINOK(ReadStream_FALSE(stream, header, kHeaderSize))
+ if (header[0] != 'F' ||
+ header[1] != 'L' ||
+ header[2] != 'V' ||
+ header[3] != 1 ||
+ (header[4] & 0xFA) != 0)
+ return S_FALSE;
+ UInt64 offset = Get32(header + 5);
+ if (offset != 9 || Get32(header + 9) != 0)
+ return S_FALSE;
+ offset = kHeaderSize;
+
+ CInBuffer inBuf;
+ if (!inBuf.Create(1 << 15))
+ return E_OUTOFMEMORY;
+ inBuf.SetStream(stream);
+
+ CObjectVector<CItem> items;
+ int lasts[kNumTypes];
+ unsigned i;
+ for (i = 0; i < kNumTypes; i++)
+ lasts[i] = -1;
+
+ _phySize = offset;
+ for (;;)
+ {
+ Byte buf[kTagHeaderSize];
+ CItem item;
+ if (inBuf.ReadBytes(buf, kTagHeaderSize) != kTagHeaderSize)
+ break;
+ item.Type = buf[0];
+ UInt32 size = Get24(buf + 1);
+ if (size < 1)
+ break;
+ // item.Time = Get24(buf + 4);
+ // item.Time |= (UInt32)buf[7] << 24;
+ if (Get24(buf + 8) != 0) // streamID
+ break;
+
+ UInt32 curSize = kTagHeaderSize + size + 4;
+ item.Data.Alloc(curSize);
+ memcpy(item.Data, buf, kTagHeaderSize);
+ if (inBuf.ReadBytes(item.Data + kTagHeaderSize, size) != size)
+ break;
+ if (inBuf.ReadBytes(item.Data + kTagHeaderSize + size, 4) != 4)
+ break;
+
+ if (Get32(item.Data + kTagHeaderSize + size) != kTagHeaderSize + size)
+ break;
+
+ offset += curSize;
+
+ // printf("\noffset = %6X type = %2d time = %6d size = %6d", (UInt32)offset, item.Type, item.Time, item.Size);
+
+ if (item.Type == kType_Meta)
+ {
+ // _metadata = item.Buf;
+ }
+ else
+ {
+ if (item.Type != kType_Audio && item.Type != kType_Video)
+ break;
+ if (items.Size() >= kNumChunksMax)
+ return S_FALSE;
+ Byte firstByte = item.Data[kTagHeaderSize];
+ Byte subType, props;
+ if (item.Type == kType_Audio)
+ {
+ subType = (Byte)(firstByte >> 4);
+ props = (Byte)(firstByte & 0xF);
+ }
+ else
+ {
+ subType = (Byte)(firstByte & 0xF);
+ props = (Byte)(firstByte >> 4);
+ }
+ int last = lasts[item.Type];
+ if (last < 0)
+ {
+ CItem2 item2;
+ item2.RefBuf = item2.BufSpec = new CReferenceBuf;
+ item2.Size = curSize;
+ item2.Type = item.Type;
+ item2.SubType = subType;
+ item2.Props = props;
+ item2.NumChunks = 1;
+ item2.SameSubTypes = true;
+ lasts[item.Type] = (int)_items2.Add(item2);
+ }
+ else
+ {
+ CItem2 &item2 = _items2[last];
+ if (subType != item2.SubType)
+ item2.SameSubTypes = false;
+ item2.Size += curSize;
+ item2.NumChunks++;
+ }
+ items.Add(item);
+ }
+ _phySize = offset;
+ if (callback && (items.Size() & 0xFF) == 0)
+ {
+ RINOK(callback->SetCompleted(NULL, &offset))
+ }
+ }
+ if (items.IsEmpty())
+ return S_FALSE;
+
+ _isRaw = (_items2.Size() == 1);
+ for (i = 0; i < _items2.Size(); i++)
+ {
+ CItem2 &item2 = _items2[i];
+ CByteBuffer &itemBuf = item2.BufSpec->Buf;
+ if (_isRaw)
+ {
+ if (!item2.SameSubTypes)
+ return S_FALSE;
+ itemBuf.Alloc((size_t)item2.Size - (size_t)(kTagHeaderSize + 4 + 1) * item2.NumChunks);
+ item2.Size = 0;
+ }
+ else
+ {
+ itemBuf.Alloc(kHeaderSize + (size_t)item2.Size);
+ memcpy(itemBuf, header, kHeaderSize);
+ itemBuf[4] = item2.IsAudio() ? kFlag_Audio : kFlag_Video;
+ item2.Size = kHeaderSize;
+ }
+ }
+
+ for (i = 0; i < items.Size(); i++)
+ {
+ const CItem &item = items[i];
+ CItem2 &item2 = _items2[lasts[item.Type]];
+ size_t size = item.Data.Size();
+ const Byte *src = item.Data;
+ if (_isRaw)
+ {
+ src += kTagHeaderSize + 1;
+ size -= (kTagHeaderSize + 4 + 1);
+ }
+ if (size != 0)
+ {
+ memcpy(item2.BufSpec->Buf + item2.Size, src, size);
+ item2.Size += size;
+ }
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ Close();
+ HRESULT res;
+ try
+ {
+ res = Open2(inStream, callback);
+ if (res == S_OK)
+ _stream = inStream;
+ }
+ catch(...) { res = S_FALSE; }
+ if (res != S_OK)
+ {
+ Close();
+ return S_FALSE;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _phySize = 0;
+ _stream.Release();
+ _items2.Clear();
+ // _metadata.SetCapacity(0);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _items2.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _items2.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _items2[allFilesMode ? i : indices[i]].Size;
+ extractCallback->SetTotal(totalSize);
+
+ totalSize = 0;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = totalSize;
+ RINOK(lps->SetCur())
+ CMyComPtr<ISequentialOutStream> outStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CItem2 &item = _items2[index];
+ RINOK(extractCallback->GetStream(index, &outStream, askMode))
+ totalSize += item.Size;
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode))
+ if (outStream)
+ {
+ RINOK(WriteStream(outStream, item.BufSpec->Buf, item.BufSpec->Buf.Size()))
+ }
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ *stream = NULL;
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->Init(_items2[index].BufSpec);
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+static const Byte k_Signature[] = { 'F', 'L', 'V', 1, };
+
+REGISTER_ARC_I(
+ "FLV", "flv", NULL, 0xD6,
+ k_Signature,
+ 0,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/GptHandler.cpp b/CPP/7zip/Archive/GptHandler.cpp
new file mode 100644
index 0000000..78c76cf
--- /dev/null
+++ b/CPP/7zip/Archive/GptHandler.cpp
@@ -0,0 +1,472 @@
+// GptHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer.h"
+
+#include "../../Windows/PropVariantUtils.h"
+
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "HandlerCont.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+using namespace NWindows;
+
+namespace NArchive {
+
+namespace NFat {
+API_FUNC_IsArc IsArc_Fat(const Byte *p, size_t size);
+}
+
+namespace NGpt {
+
+static const unsigned k_SignatureSize = 12;
+static const Byte k_Signature[k_SignatureSize] =
+ { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T', 0, 0, 1, 0 };
+
+static const UInt32 kSectorSize = 512;
+
+static const CUInt32PCharPair g_PartitionFlags[] =
+{
+ { 0, "Sys" },
+ { 1, "Ignore" },
+ { 2, "Legacy" },
+ { 60, "Win-Read-only" },
+ { 62, "Win-Hidden" },
+ { 63, "Win-Not-Automount" }
+};
+
+static const unsigned kNameLen = 36;
+
+struct CPartition
+{
+ Byte Type[16];
+ Byte Id[16];
+ UInt64 FirstLba;
+ UInt64 LastLba;
+ UInt64 Flags;
+ const char *Ext; // detected later
+ Byte Name[kNameLen * 2];
+
+ bool IsUnused() const
+ {
+ for (unsigned i = 0; i < 16; i++)
+ if (Type[i] != 0)
+ return false;
+ return true;
+ }
+
+ UInt64 GetSize() const { return (LastLba - FirstLba + 1) * kSectorSize; }
+ UInt64 GetPos() const { return FirstLba * kSectorSize; }
+ UInt64 GetEnd() const { return (LastLba + 1) * kSectorSize; }
+
+ void Parse(const Byte *p)
+ {
+ memcpy(Type, p, 16);
+ memcpy(Id, p + 16, 16);
+ FirstLba = Get64(p + 32);
+ LastLba = Get64(p + 40);
+ Flags = Get64(p + 48);
+ memcpy(Name, p + 56, kNameLen * 2);
+ Ext = NULL;
+ }
+};
+
+
+struct CPartType
+{
+ UInt32 Id;
+ const char *Ext;
+ const char *Type;
+};
+
+static const CPartType kPartTypes[] =
+{
+ // { 0x0, NULL, "Unused" },
+
+ { 0x21686148, NULL, "BIOS Boot" },
+
+ { 0xC12A7328, NULL, "EFI System" },
+ { 0x024DEE41, NULL, "MBR" },
+
+ { 0xE3C9E316, NULL, "Windows MSR" },
+ { 0xEBD0A0A2, NULL, "Windows BDP" },
+ { 0x5808C8AA, NULL, "Windows LDM Metadata" },
+ { 0xAF9B60A0, NULL, "Windows LDM Data" },
+ { 0xDE94BBA4, NULL, "Windows Recovery" },
+ // { 0x37AFFC90, NULL, "IBM GPFS" },
+ // { 0xE75CAF8F, NULL, "Windows Storage Spaces" },
+
+ { 0x0FC63DAF, NULL, "Linux Data" },
+ { 0x0657FD6D, NULL, "Linux Swap" },
+
+ { 0x83BD6B9D, NULL, "FreeBSD Boot" },
+ { 0x516E7CB4, NULL, "FreeBSD Data" },
+ { 0x516E7CB5, NULL, "FreeBSD Swap" },
+ { 0x516E7CB6, "ufs", "FreeBSD UFS" },
+ { 0x516E7CB8, NULL, "FreeBSD Vinum" },
+ { 0x516E7CB8, "zfs", "FreeBSD ZFS" },
+
+ { 0x48465300, "hfsx", "HFS+" },
+ { 0x7C3457EF, "apfs", "APFS" },
+};
+
+static int FindPartType(const Byte *guid)
+{
+ const UInt32 val = Get32(guid);
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(kPartTypes); i++)
+ if (kPartTypes[i].Id == val)
+ return (int)i;
+ return -1;
+}
+
+
+static void RawLeGuidToString_Upper(const Byte *g, char *s)
+{
+ RawLeGuidToString(g, s);
+ // MyStringUpper_Ascii(s);
+}
+
+
+Z7_class_CHandler_final: public CHandlerCont
+{
+ Z7_IFACE_COM7_IMP(IInArchive_Cont)
+
+ CRecordVector<CPartition> _items;
+ UInt64 _totalSize;
+ Byte Guid[16];
+
+ CByteBuffer _buffer;
+
+ HRESULT Open2(IInStream *stream);
+
+ virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override
+ {
+ const CPartition &item = _items[index];
+ pos = item.GetPos();
+ size = item.GetSize();
+ return NExtract::NOperationResult::kOK;
+ }
+};
+
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+ _buffer.Alloc(kSectorSize * 2);
+ RINOK(ReadStream_FALSE(stream, _buffer, kSectorSize * 2))
+
+ const Byte *buf = _buffer;
+ if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA)
+ return S_FALSE;
+
+ buf += kSectorSize;
+ if (memcmp(buf, k_Signature, k_SignatureSize) != 0)
+ return S_FALSE;
+ {
+ // if (Get32(buf + 8) != 0x10000) return S_FALSE; // revision
+ UInt32 headerSize = Get32(buf + 12); // = 0x5C usually
+ if (headerSize > kSectorSize)
+ return S_FALSE;
+ UInt32 crc = Get32(buf + 0x10);
+ SetUi32(_buffer + kSectorSize + 0x10, 0)
+ if (CrcCalc(_buffer + kSectorSize, headerSize) != crc)
+ return S_FALSE;
+ }
+ // UInt32 reserved = Get32(buf + 0x14);
+ const UInt64 curLba = Get64(buf + 0x18);
+ if (curLba != 1)
+ return S_FALSE;
+ const UInt64 backupLba = Get64(buf + 0x20);
+ // UInt64 firstUsableLba = Get64(buf + 0x28);
+ // UInt64 lastUsableLba = Get64(buf + 0x30);
+ memcpy(Guid, buf + 0x38, 16);
+ const UInt64 tableLba = Get64(buf + 0x48);
+ if (tableLba < 2)
+ return S_FALSE;
+ const UInt32 numEntries = Get32(buf + 0x50);
+ const UInt32 entrySize = Get32(buf + 0x54); // = 128 usually
+ const UInt32 entriesCrc = Get32(buf + 0x58);
+
+ if (entrySize < 128
+ || entrySize > (1 << 12)
+ || numEntries > (1 << 16)
+ || tableLba < 2
+ || tableLba >= ((UInt64)1 << (64 - 10)))
+ return S_FALSE;
+
+ const UInt32 tableSize = entrySize * numEntries;
+ const UInt32 tableSizeAligned = (tableSize + kSectorSize - 1) & ~(kSectorSize - 1);
+ _buffer.Alloc(tableSizeAligned);
+ const UInt64 tableOffset = tableLba * kSectorSize;
+ RINOK(InStream_SeekSet(stream, tableOffset))
+ RINOK(ReadStream_FALSE(stream, _buffer, tableSizeAligned))
+
+ if (CrcCalc(_buffer, tableSize) != entriesCrc)
+ return S_FALSE;
+
+ _totalSize = tableOffset + tableSizeAligned;
+
+ for (UInt32 i = 0; i < numEntries; i++)
+ {
+ CPartition item;
+ item.Parse(_buffer + i * entrySize);
+ if (item.IsUnused())
+ continue;
+ UInt64 endPos = item.GetEnd();
+ if (_totalSize < endPos)
+ _totalSize = endPos;
+ _items.Add(item);
+ }
+
+ {
+ const UInt64 end = (backupLba + 1) * kSectorSize;
+ if (_totalSize < end)
+ _totalSize = end;
+ }
+
+ {
+ UInt64 fileEnd;
+ RINOK(InStream_GetSize_SeekToEnd(stream, fileEnd))
+
+ if (_totalSize < fileEnd)
+ {
+ const UInt64 rem = fileEnd - _totalSize;
+ const UInt64 kRemMax = 1 << 22;
+ if (rem <= kRemMax)
+ {
+ RINOK(InStream_SeekSet(stream, _totalSize))
+ bool areThereNonZeros = false;
+ UInt64 numZeros = 0;
+ if (ReadZeroTail(stream, areThereNonZeros, numZeros, kRemMax) == S_OK)
+ if (!areThereNonZeros)
+ _totalSize += numZeros;
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+static const unsigned k_Ntfs_Fat_HeaderSize = 512;
+
+static const Byte k_NtfsSignature[] = { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 };
+
+static bool IsNtfs(const Byte *p)
+{
+ if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA)
+ return false;
+ if (memcmp(p + 3, k_NtfsSignature, Z7_ARRAY_SIZE(k_NtfsSignature)) != 0)
+ return false;
+ switch (p[0])
+ {
+ case 0xE9: /* codeOffset = 3 + (Int16)Get16(p + 1); */ break;
+ case 0xEB: if (p[2] != 0x90) return false; /* codeOffset = 2 + (int)(signed char)p[1]; */ break;
+ default: return false;
+ }
+ return true;
+}
+
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */))
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(Open2(stream))
+ _stream = stream;
+
+ FOR_VECTOR (fileIndex, _items)
+ {
+ CPartition &item = _items[fileIndex];
+ const int typeIndex = FindPartType(item.Type);
+ if (typeIndex < 0)
+ continue;
+ const CPartType &t = kPartTypes[(unsigned)typeIndex];
+ if (t.Ext)
+ {
+ item.Ext = t.Ext;
+ continue;
+ }
+ if (t.Type && IsString1PrefixedByString2_NoCase_Ascii(t.Type, "Windows"))
+ {
+ CMyComPtr<ISequentialInStream> inStream;
+ if (
+ // ((IInArchiveGetStream *)this)->
+ GetStream(fileIndex, &inStream) == S_OK && inStream)
+ {
+ Byte temp[k_Ntfs_Fat_HeaderSize];
+ if (ReadStream_FAIL(inStream, temp, k_Ntfs_Fat_HeaderSize) == S_OK)
+ {
+ if (IsNtfs(temp))
+ {
+ item.Ext = "ntfs";
+ continue;
+ }
+ if (NFat::IsArc_Fat(temp, k_Ntfs_Fat_HeaderSize) == k_IsArc_Res_YES)
+ {
+ item.Ext = "fat";
+ continue;
+ }
+ }
+ }
+ }
+ }
+
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _totalSize = 0;
+ memset(Guid, 0, sizeof(Guid));
+ _items.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidFileSystem,
+ kpidCharacts,
+ kpidOffset,
+ kpidId
+};
+
+static const Byte kArcProps[] =
+{
+ kpidId
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidMainSubfile:
+ {
+ if (_items.Size() == 1)
+ prop = (UInt32)0;
+ break;
+ }
+ case kpidPhySize: prop = _totalSize; break;
+ case kpidId:
+ {
+ char s[48];
+ RawLeGuidToString_Upper(Guid, s);
+ prop = s;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ const CPartition &item = _items[index];
+
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ // Windows BDP partitions can have identical names.
+ // So we add the partition number at front
+ UString s;
+ s.Add_UInt32(index);
+ {
+ UString s2;
+ for (unsigned i = 0; i < kNameLen; i++)
+ {
+ wchar_t c = (wchar_t)Get16(item.Name + i * 2);
+ if (c == 0)
+ break;
+ s2 += c;
+ }
+ if (!s2.IsEmpty())
+ {
+ s.Add_Dot();
+ s += s2;
+ }
+ }
+ {
+ s.Add_Dot();
+ s += (item.Ext ? item.Ext : "img");
+ }
+ prop = s;
+ break;
+ }
+
+ case kpidSize:
+ case kpidPackSize: prop = item.GetSize(); break;
+ case kpidOffset: prop = item.GetPos(); break;
+
+ case kpidFileSystem:
+ {
+ char s[48];
+ const char *res;
+ const int typeIndex = FindPartType(item.Type);
+ if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Type)
+ res = kPartTypes[(unsigned)typeIndex].Type;
+ else
+ {
+ RawLeGuidToString_Upper(item.Type, s);
+ res = s;
+ }
+ prop = res;
+ break;
+ }
+
+ case kpidId:
+ {
+ char s[48];
+ RawLeGuidToString_Upper(item.Id, s);
+ prop = s;
+ break;
+ }
+
+ case kpidCharacts: FLAGS64_TO_PROP(g_PartitionFlags, item.Flags, prop); break;
+ }
+
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+REGISTER_ARC_I(
+ "GPT", "gpt mbr", NULL, 0xCB,
+ k_Signature,
+ kSectorSize,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/GzHandler.cpp b/CPP/7zip/Archive/GzHandler.cpp
new file mode 100644
index 0000000..ad9a074
--- /dev/null
+++ b/CPP/7zip/Archive/GzHandler.cpp
@@ -0,0 +1,1210 @@
+// GzHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/Defs.h"
+#include "../../Common/StringConvert.h"
+
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/PropVariantUtils.h"
+#include "../../Windows/TimeUtils.h"
+
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+#include "../Compress/DeflateDecoder.h"
+#include "../Compress/DeflateEncoder.h"
+
+#include "Common/HandlerOut.h"
+#include "Common/InStreamWithCRC.h"
+#include "Common/OutStreamWithCRC.h"
+
+#define Get32(p) GetUi32(p)
+
+using namespace NWindows;
+
+using namespace NCompress;
+using namespace NDeflate;
+
+namespace NArchive {
+namespace NGz {
+
+ static const Byte kSignature_0 = 0x1F;
+ static const Byte kSignature_1 = 0x8B;
+ static const Byte kSignature_2 = 8; // NCompressionMethod::kDeflate
+
+ // Latest versions of gzip program don't write comment field to gz archive.
+ // We also don't write comment field to gz archive.
+
+ namespace NFlags
+ {
+ // const Byte kIsText = 1 << 0;
+ const Byte kCrc = 1 << 1;
+ const Byte kExtra = 1 << 2;
+ const Byte kName = 1 << 3;
+ const Byte kComment = 1 << 4;
+ const Byte kReserved = 0xE0;
+ }
+
+ namespace NExtraFlags
+ {
+ const Byte kMaximum = 2;
+ const Byte kFastest = 4;
+ }
+
+ namespace NHostOS
+ {
+ enum EEnum
+ {
+ kFAT = 0,
+ kAMIGA,
+ kVMS,
+ kUnix,
+ kVM_CMS,
+ kAtari,
+ kHPFS,
+ kMac,
+ kZ_System,
+ kCPM,
+ kTOPS20,
+ kNTFS,
+ kQDOS,
+ kAcorn,
+ kVFAT,
+ kMVS,
+ kBeOS,
+ kTandem,
+
+ kUnknown = 255
+ };
+ }
+
+static const char * const kHostOSes[] =
+{
+ "FAT"
+ , "AMIGA"
+ , "VMS"
+ , "Unix"
+ , "VM/CMS"
+ , "Atari"
+ , "HPFS"
+ , "Macintosh"
+ , "Z-System"
+ , "CP/M"
+ , "TOPS-20"
+ , "NTFS"
+ , "SMS/QDOS"
+ , "Acorn"
+ , "VFAT"
+ , "MVS"
+ , "BeOS"
+ , "Tandem"
+ , "OS/400"
+ , "OS/X"
+};
+
+
+class CItem
+{
+ bool TestFlag(Byte flag) const { return (Flags & flag) != 0; }
+public:
+ Byte Flags;
+ Byte ExtraFlags;
+ Byte HostOS;
+ UInt32 Time;
+ UInt32 Crc;
+ UInt32 Size32;
+
+ AString Name;
+ AString Comment;
+ // CByteBuffer Extra;
+
+ CItem():
+ Flags(0),
+ ExtraFlags(0),
+ HostOS(0),
+ Time(0),
+ Crc(0),
+ Size32(0) {}
+
+ void Clear()
+ {
+ Name.Empty();
+ Comment.Empty();
+ // Extra.Free();
+ }
+
+ void CopyMetaPropsFrom(const CItem &a)
+ {
+ Flags = a.Flags;
+ HostOS = a.HostOS;
+ Time = a.Time;
+ Name = a.Name;
+ Comment = a.Comment;
+ // Extra = a.Extra;
+ }
+
+ void CopyDataPropsFrom(const CItem &a)
+ {
+ ExtraFlags = a.ExtraFlags;
+ Crc = a.Crc;
+ Size32 = a.Size32;
+ }
+
+ // bool IsText() const { return TestFlag(NFlags::kIsText); }
+ bool HeaderCrcIsPresent() const { return TestFlag(NFlags::kCrc); }
+ bool ExtraFieldIsPresent() const { return TestFlag(NFlags::kExtra); }
+ bool NameIsPresent() const { return TestFlag(NFlags::kName); }
+ bool CommentIsPresent() const { return TestFlag(NFlags::kComment); }
+ bool IsSupported() const { return (Flags & NFlags::kReserved) == 0; }
+
+ HRESULT ReadHeader(NDecoder::CCOMCoder *stream);
+ HRESULT ReadFooter1(NDecoder::CCOMCoder *stream);
+ HRESULT ReadFooter2(ISequentialInStream *stream);
+
+ HRESULT WriteHeader(ISequentialOutStream *stream);
+ HRESULT WriteFooter(ISequentialOutStream *stream);
+};
+
+static HRESULT ReadBytes(NDecoder::CCOMCoder *stream, Byte *data, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ data[i] = stream->ReadAlignedByte();
+ return stream->InputEofError() ? S_FALSE : S_OK;
+}
+
+static HRESULT SkipBytes(NDecoder::CCOMCoder *stream, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ stream->ReadAlignedByte();
+ return stream->InputEofError() ? S_FALSE : S_OK;
+}
+
+static HRESULT ReadUInt16(NDecoder::CCOMCoder *stream, UInt32 &value /* , UInt32 &crc */)
+{
+ value = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ Byte b = stream->ReadAlignedByte();
+ if (stream->InputEofError())
+ return S_FALSE;
+ // crc = CRC_UPDATE_BYTE(crc, b);
+ value |= ((UInt32)(b) << (8 * i));
+ }
+ return S_OK;
+}
+
+static HRESULT ReadString(NDecoder::CCOMCoder *stream, AString &s, size_t limit /* , UInt32 &crc */)
+{
+ s.Empty();
+ for (size_t i = 0; i < limit; i++)
+ {
+ Byte b = stream->ReadAlignedByte();
+ if (stream->InputEofError())
+ return S_FALSE;
+ // crc = CRC_UPDATE_BYTE(crc, b);
+ if (b == 0)
+ return S_OK;
+ s += (char)b;
+ }
+ return S_FALSE;
+}
+
+static UInt32 Is_Deflate(const Byte *p, size_t size)
+{
+ if (size < 1)
+ return k_IsArc_Res_NEED_MORE;
+ Byte b = *p;
+ p++;
+ size--;
+ unsigned type = ((unsigned)b >> 1) & 3;
+ if (type == 3)
+ return k_IsArc_Res_NO;
+ if (type == 0)
+ {
+ // Stored (uncompreessed data)
+ if ((b >> 3) != 0)
+ return k_IsArc_Res_NO;
+ if (size < 4)
+ return k_IsArc_Res_NEED_MORE;
+ UInt16 r = (UInt16)~GetUi16(p + 2);
+ if (GetUi16(p) != r)
+ return k_IsArc_Res_NO;
+ }
+ else if (type == 2)
+ {
+ // Dynamic Huffman
+ if (size < 1)
+ return k_IsArc_Res_NEED_MORE;
+ if ((*p & 0x1F) + 1 > 30) // numDistLevels
+ return k_IsArc_Res_NO;
+ }
+ return k_IsArc_Res_YES;
+}
+
+static const unsigned kNameMaxLen = 1 << 12;
+static const unsigned kCommentMaxLen = 1 << 16;
+
+API_FUNC_static_IsArc IsArc_Gz(const Byte *p, size_t size)
+{
+ if (size < 10)
+ return k_IsArc_Res_NEED_MORE;
+ if (p[0] != kSignature_0 ||
+ p[1] != kSignature_1 ||
+ p[2] != kSignature_2)
+ return k_IsArc_Res_NO;
+
+ Byte flags = p[3];
+ if ((flags & NFlags::kReserved) != 0)
+ return k_IsArc_Res_NO;
+
+ Byte extraFlags = p[8];
+ // maybe that flag can have another values for some gz archives?
+ if (extraFlags != 0 &&
+ extraFlags != NExtraFlags::kMaximum &&
+ extraFlags != NExtraFlags::kFastest)
+ return k_IsArc_Res_NO;
+
+ size -= 10;
+ p += 10;
+
+ if ((flags & NFlags::kExtra) != 0)
+ {
+ if (size < 2)
+ return k_IsArc_Res_NEED_MORE;
+ unsigned xlen = GetUi16(p);
+ size -= 2;
+ p += 2;
+ while (xlen != 0)
+ {
+ if (xlen < 4)
+ return k_IsArc_Res_NO;
+ if (size < 4)
+ return k_IsArc_Res_NEED_MORE;
+ unsigned len = GetUi16(p + 2);
+ size -= 4;
+ xlen -= 4;
+ p += 4;
+ if (len > xlen)
+ return k_IsArc_Res_NO;
+ if (len > size)
+ return k_IsArc_Res_NEED_MORE;
+ size -= len;
+ xlen -= len;
+ p += len;
+ }
+ }
+
+ if ((flags & NFlags::kName) != 0)
+ {
+ size_t limit = kNameMaxLen;
+ if (limit > size)
+ limit = size;
+ size_t i;
+ for (i = 0; i < limit && p[i] != 0; i++);
+ if (i == size)
+ return k_IsArc_Res_NEED_MORE;
+ if (i == limit)
+ return k_IsArc_Res_NO;
+ i++;
+ p += i;
+ size -= i;
+ }
+
+ if ((flags & NFlags::kComment) != 0)
+ {
+ size_t limit = kCommentMaxLen;
+ if (limit > size)
+ limit = size;
+ size_t i;
+ for (i = 0; i < limit && p[i] != 0; i++);
+ if (i == size)
+ return k_IsArc_Res_NEED_MORE;
+ if (i == limit)
+ return k_IsArc_Res_NO;
+ i++;
+ p += i;
+ size -= i;
+ }
+
+ if ((flags & NFlags::kCrc) != 0)
+ {
+ if (size < 2)
+ return k_IsArc_Res_NEED_MORE;
+ p += 2;
+ size -= 2;
+ }
+
+ return Is_Deflate(p, size);
+}
+}
+
+HRESULT CItem::ReadHeader(NDecoder::CCOMCoder *stream)
+{
+ Clear();
+
+ // Header-CRC field had another meaning in old version of gzip!
+ // UInt32 crc = CRC_INIT_VAL;
+ Byte buf[10];
+
+ RINOK(ReadBytes(stream, buf, 10))
+
+ if (buf[0] != kSignature_0 ||
+ buf[1] != kSignature_1 ||
+ buf[2] != kSignature_2)
+ return S_FALSE;
+
+ Flags = buf[3];
+ if (!IsSupported())
+ return S_FALSE;
+
+ Time = Get32(buf + 4);
+ ExtraFlags = buf[8];
+ HostOS = buf[9];
+
+ // crc = CrcUpdate(crc, buf, 10);
+
+ if (ExtraFieldIsPresent())
+ {
+ UInt32 xlen;
+ RINOK(ReadUInt16(stream, xlen /* , crc */))
+ RINOK(SkipBytes(stream, xlen))
+ // Extra.SetCapacity(xlen);
+ // RINOK(ReadStream_FALSE(stream, Extra, xlen));
+ // crc = CrcUpdate(crc, Extra, xlen);
+ }
+ if (NameIsPresent())
+ RINOK(ReadString(stream, Name, kNameMaxLen /* , crc */))
+ if (CommentIsPresent())
+ RINOK(ReadString(stream, Comment, kCommentMaxLen /* , crc */))
+
+ if (HeaderCrcIsPresent())
+ {
+ UInt32 headerCRC;
+ // UInt32 dummy = 0;
+ RINOK(ReadUInt16(stream, headerCRC /* , dummy */))
+ /*
+ if ((UInt16)CRC_GET_DIGEST(crc) != headerCRC)
+ return S_FALSE;
+ */
+ }
+ return stream->InputEofError() ? S_FALSE : S_OK;
+}
+
+HRESULT CItem::ReadFooter1(NDecoder::CCOMCoder *stream)
+{
+ Byte buf[8];
+ RINOK(ReadBytes(stream, buf, 8))
+ Crc = Get32(buf);
+ Size32 = Get32(buf + 4);
+ return stream->InputEofError() ? S_FALSE : S_OK;
+}
+
+HRESULT CItem::ReadFooter2(ISequentialInStream *stream)
+{
+ Byte buf[8];
+ RINOK(ReadStream_FALSE(stream, buf, 8))
+ Crc = Get32(buf);
+ Size32 = Get32(buf + 4);
+ return S_OK;
+}
+
+HRESULT CItem::WriteHeader(ISequentialOutStream *stream)
+{
+ Byte buf[10];
+ buf[0] = kSignature_0;
+ buf[1] = kSignature_1;
+ buf[2] = kSignature_2;
+ buf[3] = (Byte)(Flags & NFlags::kName);
+ // buf[3] |= NFlags::kCrc;
+ SetUi32(buf + 4, Time)
+ buf[8] = ExtraFlags;
+ buf[9] = HostOS;
+ RINOK(WriteStream(stream, buf, 10))
+ // crc = CrcUpdate(CRC_INIT_VAL, buf, 10);
+ if (NameIsPresent())
+ {
+ // crc = CrcUpdate(crc, (const char *)Name, Name.Len() + 1);
+ RINOK(WriteStream(stream, (const char *)Name, Name.Len() + 1))
+ }
+ // SetUi16(buf, (UInt16)CRC_GET_DIGEST(crc));
+ // RINOK(WriteStream(stream, buf, 2));
+ return S_OK;
+}
+
+HRESULT CItem::WriteFooter(ISequentialOutStream *stream)
+{
+ Byte buf[8];
+ SetUi32(buf, Crc)
+ SetUi32(buf + 4, Size32)
+ return WriteStream(stream, buf, 8);
+}
+
+Z7_CLASS_IMP_CHandler_IInArchive_3(
+ IArchiveOpenSeq,
+ IOutArchive,
+ ISetProperties
+)
+ CItem _item;
+
+ bool _isArc;
+ bool _needSeekToStart;
+ bool _dataAfterEnd;
+ bool _needMoreInput;
+
+ bool _packSize_Defined;
+ bool _unpackSize_Defined;
+ bool _numStreams_Defined;
+
+ UInt64 _packSize;
+ UInt64 _unpackSize; // real unpack size (NOT from footer)
+ UInt64 _numStreams;
+ UInt64 _headerSize; // only start header (without footer)
+
+ CMyComPtr<IInStream> _stream;
+ CMyComPtr<ICompressCoder> _decoder;
+ NDecoder::CCOMCoder *_decoderSpec;
+
+ CSingleMethodProps _props;
+ CHandlerTimeOptions _timeOptions;
+
+public:
+ CHandler():
+ _isArc(false),
+ _decoderSpec(NULL)
+ {}
+
+ void CreateDecoder()
+ {
+ if (_decoder)
+ return;
+ _decoderSpec = new NDecoder::CCOMCoder;
+ _decoder = _decoderSpec;
+ }
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidHostOS,
+ kpidCRC
+ // kpidComment
+};
+
+static const Byte kArcProps[] =
+{
+ kpidHeadersSize,
+ kpidNumStreams
+};
+
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySize: if (_packSize_Defined) prop = _packSize; break;
+ case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break;
+ case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break;
+ case kpidHeadersSize: if (_headerSize != 0) prop = _headerSize; break;
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
+ if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
+ prop = v;
+ break;
+ }
+ case kpidName:
+ if (_item.NameIsPresent())
+ {
+ UString s = MultiByteToUnicodeString(_item.Name, CP_ACP);
+ s += ".gz";
+ prop = s;
+ }
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPath:
+ if (_item.NameIsPresent())
+ prop = MultiByteToUnicodeString(_item.Name, CP_ACP);
+ break;
+ // case kpidComment: if (_item.CommentIsPresent()) prop = MultiByteToUnicodeString(_item.Comment, CP_ACP); break;
+ case kpidMTime:
+ // gzip specification: MTIME = 0 means no time stamp is available.
+ if (_item.Time != 0)
+ PropVariant_SetFrom_UnixTime(prop, _item.Time);
+ break;
+ case kpidTimeType:
+ if (_item.Time != 0)
+ prop = (UInt32)NFileTimeType::kUnix;
+ break;
+ case kpidSize:
+ {
+ if (_unpackSize_Defined)
+ prop = _unpackSize;
+ else if (_stream)
+ prop = (UInt64)_item.Size32;
+ break;
+ }
+ case kpidPackSize:
+ {
+ if (_packSize_Defined || _stream)
+ prop = _packSize;
+ break;
+ }
+ case kpidHostOS: TYPE_TO_PROP(kHostOSes, _item.HostOS, prop); break;
+ case kpidCRC: if (_stream) prop = _item.Crc; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_CLASS_IMP_COM_1(
+ CCompressProgressInfoImp,
+ ICompressProgressInfo
+)
+ CMyComPtr<IArchiveOpenCallback> Callback;
+public:
+ UInt64 Offset;
+ void Init(IArchiveOpenCallback *callback) { Callback = callback; }
+};
+
+Z7_COM7F_IMF(CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */))
+{
+ if (Callback)
+ {
+ UInt64 files = 0;
+ UInt64 value = Offset + *inSize;
+ return Callback->SetCompleted(&files, &value);
+ }
+ return S_OK;
+}
+
+/*
+*/
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *))
+{
+ COM_TRY_BEGIN
+ RINOK(OpenSeq(stream))
+ _isArc = false;
+ UInt64 endPos;
+ RINOK(stream->Seek(-8, STREAM_SEEK_END, &endPos))
+ _packSize = endPos + 8;
+ RINOK(_item.ReadFooter2(stream))
+ _stream = stream;
+ _isArc = true;
+ _needSeekToStart = true;
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream))
+{
+ COM_TRY_BEGIN
+ try
+ {
+ Close();
+ CreateDecoder();
+ _decoderSpec->SetInStream(stream);
+ _decoderSpec->InitInStream(true);
+ RINOK(_item.ReadHeader(_decoderSpec))
+ if (_decoderSpec->InputEofError())
+ return S_FALSE;
+ _headerSize = _decoderSpec->GetInputProcessedSize();
+ _isArc = true;
+ return S_OK;
+ }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _isArc = false;
+ _needSeekToStart = false;
+ _dataAfterEnd = false;
+ _needMoreInput = false;
+
+ _packSize_Defined = false;
+ _unpackSize_Defined = false;
+ _numStreams_Defined = false;
+
+ _packSize = 0;
+ _headerSize = 0;
+
+ _stream.Release();
+ if (_decoder)
+ _decoderSpec->ReleaseInStream();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ if (_packSize_Defined)
+ extractCallback->SetTotal(_packSize);
+ // UInt64 currentTotalPacked = 0;
+ // RINOK(extractCallback->SetCompleted(&currentTotalPacked));
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode))
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ CreateDecoder();
+
+ COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, true);
+
+ bool needReadFirstItem = _needSeekToStart;
+
+ if (_needSeekToStart)
+ {
+ if (!_stream)
+ return E_FAIL;
+ RINOK(InStream_SeekToBegin(_stream))
+ _decoderSpec->InitInStream(true);
+ // printf("\nSeek");
+ }
+ else
+ _needSeekToStart = true;
+
+ bool firstItem = true;
+
+ UInt64 packSize = _decoderSpec->GetInputProcessedSize();
+ // printf("\npackSize = %d", (unsigned)packSize);
+
+ UInt64 unpackedSize = 0;
+ UInt64 numStreams = 0;
+
+ bool crcError = false;
+
+ HRESULT result = S_OK;
+
+ try {
+
+ for (;;)
+ {
+ lps->InSize = packSize;
+ lps->OutSize = unpackedSize;
+
+ RINOK(lps->SetCur())
+
+ CItem item;
+
+ if (!firstItem || needReadFirstItem)
+ {
+ result = item.ReadHeader(_decoderSpec);
+
+ if (result != S_OK && result != S_FALSE)
+ return result;
+
+ if (_decoderSpec->InputEofError())
+ result = S_FALSE;
+
+ if (result != S_OK && firstItem)
+ {
+ _isArc = false;
+ break;
+ }
+
+ if (packSize == _decoderSpec->GetStreamSize())
+ {
+ result = S_OK;
+ break;
+ }
+
+ if (result != S_OK)
+ {
+ _dataAfterEnd = true;
+ break;
+ }
+ }
+
+ numStreams++;
+ firstItem = false;
+
+ UInt64 startOffset = outStreamSpec->GetSize();
+ outStreamSpec->InitCRC();
+
+ result = _decoderSpec->CodeResume(outStream, NULL, progress);
+
+ packSize = _decoderSpec->GetInputProcessedSize();
+ unpackedSize = outStreamSpec->GetSize();
+
+ if (result != S_OK && result != S_FALSE)
+ return result;
+
+ if (_decoderSpec->InputEofError())
+ {
+ packSize = _decoderSpec->GetStreamSize();
+ _needMoreInput = true;
+ result = S_FALSE;
+ }
+
+ if (result != S_OK)
+ break;
+
+ _decoderSpec->AlignToByte();
+
+ result = item.ReadFooter1(_decoderSpec);
+
+ packSize = _decoderSpec->GetInputProcessedSize();
+
+ if (result != S_OK && result != S_FALSE)
+ return result;
+
+ if (result != S_OK)
+ {
+ if (_decoderSpec->InputEofError())
+ {
+ _needMoreInput = true;
+ result = S_FALSE;
+ }
+ break;
+ }
+
+ if (item.Crc != outStreamSpec->GetCRC() ||
+ item.Size32 != (UInt32)(unpackedSize - startOffset))
+ {
+ crcError = true;
+ result = S_FALSE;
+ break;
+ }
+
+ // break; // we can use break, if we need only first stream
+ }
+
+ } catch(const CInBufferException &e) { return e.ErrorCode; }
+
+ if (!firstItem)
+ {
+ _packSize = packSize;
+ _unpackSize = unpackedSize;
+ _numStreams = numStreams;
+
+ _packSize_Defined = true;
+ _unpackSize_Defined = true;
+ _numStreams_Defined = true;
+ }
+
+ outStream.Release();
+
+ Int32 retResult = NExtract::NOperationResult::kDataError;
+
+ if (!_isArc)
+ retResult = NExtract::NOperationResult::kIsNotArc;
+ else if (_needMoreInput)
+ retResult = NExtract::NOperationResult::kUnexpectedEnd;
+ else if (crcError)
+ retResult = NExtract::NOperationResult::kCRCError;
+ else if (_dataAfterEnd)
+ retResult = NExtract::NOperationResult::kDataAfterEnd;
+ else if (result == S_FALSE)
+ retResult = NExtract::NOperationResult::kDataError;
+ else if (result == S_OK)
+ retResult = NExtract::NOperationResult::kOK;
+ else
+ return result;
+
+ return extractCallback->SetOperationResult(retResult);
+
+
+ COM_TRY_END
+}
+
+static const Byte kHostOS =
+ #ifdef _WIN32
+ NHostOS::kFAT;
+ #else
+ NHostOS::kUnix;
+ #endif
+
+
+/*
+static HRESULT ReportItemProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value)
+{
+ return reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, 0, propID, value);
+}
+
+static HRESULT ReportArcProp(IArchiveUpdateCallbackArcProp *reportArcProp, PROPID propID, const PROPVARIANT *value)
+{
+ return reportArcProp->ReportProp(NEventIndexType::kArcProp, 0, propID, value);
+}
+
+static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp,
+ const CItem &item,
+ bool needTime,
+ bool needCrc,
+ const UInt64 *unpackSize)
+{
+ NCOM::CPropVariant timeProp;
+ NCOM::CPropVariant sizeProp;
+ if (needTime)
+ {
+ FILETIME ft;
+ NTime::UnixTimeToFileTime(item.Time, ft);
+ timeProp.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Unix);
+ }
+ if (unpackSize)
+ {
+ sizeProp = *unpackSize;
+ RINOK(ReportItemProp(reportArcProp, kpidSize, &sizeProp));
+ }
+ if (needCrc)
+ {
+ NCOM::CPropVariant prop;
+ prop = item.Crc;
+ RINOK(ReportItemProp(reportArcProp, kpidCRC, &prop));
+ }
+ {
+ RINOK(ReportItemProp(reportArcProp, kpidMTime, &timeProp));
+ }
+
+ RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, 0, NArchive::NUpdate::NOperationResult::kOK));
+
+ if (unpackSize)
+ {
+ RINOK(ReportArcProp(reportArcProp, kpidSize, &sizeProp));
+ }
+ {
+ RINOK(ReportArcProp(reportArcProp, kpidComboMTime, &timeProp));
+ }
+ return S_OK;
+}
+*/
+
+static HRESULT UpdateArchive(
+ ISequentialOutStream *outStream,
+ UInt64 unpackSize,
+ CItem &item,
+ const CSingleMethodProps &props,
+ const CHandlerTimeOptions &timeOptions,
+ IArchiveUpdateCallback *updateCallback
+ // , IArchiveUpdateCallbackArcProp *reportArcProp
+ )
+{
+ UInt64 unpackSizeReal;
+ {
+ CMyComPtr<ISequentialInStream> fileInStream;
+
+ RINOK(updateCallback->GetStream(0, &fileInStream))
+
+ if (!fileInStream)
+ return S_FALSE;
+
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IStreamGetProps,
+ getProps, fileInStream)
+ if (getProps)
+ {
+ FILETIME mTime;
+ UInt64 size;
+ if (getProps->GetProps(&size, NULL, NULL, &mTime, NULL) == S_OK)
+ {
+ unpackSize = size;
+ if (timeOptions.Write_MTime.Val)
+ NTime::FileTime_To_UnixTime(mTime, item.Time);
+ }
+ }
+ }
+
+ UInt64 complexity = 0;
+ RINOK(updateCallback->SetTotal(unpackSize))
+ RINOK(updateCallback->SetCompleted(&complexity))
+
+ CSequentialInStreamWithCRC *inStreamSpec = new CSequentialInStreamWithCRC;
+ CMyComPtr<ISequentialInStream> crcStream(inStreamSpec);
+ inStreamSpec->SetStream(fileInStream);
+ inStreamSpec->Init();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ item.ExtraFlags = props.GetLevel() >= 7 ?
+ NExtraFlags::kMaximum :
+ NExtraFlags::kFastest;
+
+ item.HostOS = kHostOS;
+
+ RINOK(item.WriteHeader(outStream))
+
+ NEncoder::CCOMCoder *deflateEncoderSpec = new NEncoder::CCOMCoder;
+ CMyComPtr<ICompressCoder> deflateEncoder = deflateEncoderSpec;
+ RINOK(props.SetCoderProps(deflateEncoderSpec, NULL))
+ RINOK(deflateEncoder->Code(crcStream, outStream, NULL, NULL, progress))
+
+ item.Crc = inStreamSpec->GetCRC();
+ unpackSizeReal = inStreamSpec->GetSize();
+ item.Size32 = (UInt32)unpackSizeReal;
+ RINOK(item.WriteFooter(outStream))
+ }
+ /*
+ if (reportArcProp)
+ {
+ RINOK(ReportArcProps(reportArcProp,
+ item,
+ props._Write_MTime, // item.Time != 0,
+ true, // writeCrc
+ &unpackSizeReal));
+ }
+ */
+ return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK);
+}
+
+
+Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType))
+{
+ /*
+ if (_item.Time != 0)
+ {
+ we set NFileTimeType::kUnix in precision,
+ and we return NFileTimeType::kUnix in kpidTimeType
+ so GetFileTimeType() value is not used in any version of 7-zip.
+ }
+ else // (_item.Time == 0)
+ {
+ kpidMTime and kpidTimeType are not defined
+ before 22.00 : GetFileTimeType() value is used in GetUpdatePairInfoList();
+ 22.00 : GetFileTimeType() value is not used
+ }
+ */
+
+ UInt32 t;
+ t = NFileTimeType::kUnix;
+ if (_isArc ? (_item.Time == 0) : !_timeOptions.Write_MTime.Val)
+ {
+ t = GET_FileTimeType_NotDefined_for_GetFileTimeType;
+ // t = k_PropVar_TimePrec_1ns; // failed in 7-Zip 21
+ // t = (UInt32)(Int32)NFileTimeType::kNotDefined; // failed in 7-Zip 21
+ }
+ *timeType = t;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *updateCallback))
+{
+ COM_TRY_BEGIN
+
+ if (numItems != 1)
+ return E_INVALIDARG;
+
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IStreamSetRestriction,
+ setRestriction, outStream)
+ if (setRestriction)
+ RINOK(setRestriction->SetRestriction(0, 0))
+ }
+
+ Int32 newData, newProps;
+ UInt32 indexInArchive;
+ if (!updateCallback)
+ return E_FAIL;
+ RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive))
+
+ // Z7_DECL_CMyComPtr_QI_FROM(IArchiveUpdateCallbackArcProp, reportArcProp, updateCallback)
+
+ CItem newItem;
+
+ if (!IntToBool(newProps))
+ {
+ newItem.CopyMetaPropsFrom(_item);
+ }
+ else
+ {
+ newItem.HostOS = kHostOS;
+ if (_timeOptions.Write_MTime.Val)
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidMTime, &prop))
+ if (prop.vt == VT_FILETIME)
+ NTime::FileTime_To_UnixTime(prop.filetime, newItem.Time);
+ else if (prop.vt == VT_EMPTY)
+ newItem.Time = 0;
+ else
+ return E_INVALIDARG;
+ }
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidPath, &prop))
+ if (prop.vt == VT_BSTR)
+ {
+ UString name = prop.bstrVal;
+ int slashPos = name.ReverseFind_PathSepar();
+ if (slashPos >= 0)
+ name.DeleteFrontal((unsigned)(slashPos + 1));
+ newItem.Name = UnicodeStringToMultiByte(name, CP_ACP);
+ if (!newItem.Name.IsEmpty())
+ newItem.Flags |= NFlags::kName;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop))
+ if (prop.vt != VT_EMPTY)
+ if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE)
+ return E_INVALIDARG;
+ }
+ }
+
+ if (IntToBool(newData))
+ {
+ UInt64 size;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidSize, &prop))
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ }
+ return UpdateArchive(outStream, size, newItem, _props, _timeOptions, updateCallback);
+ }
+
+ if (indexInArchive != 0)
+ return E_INVALIDARG;
+
+ if (!_stream)
+ return E_NOTIMPL;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IArchiveUpdateCallbackFile,
+ opCallback, updateCallback)
+ if (opCallback)
+ {
+ RINOK(opCallback->ReportOperation(
+ NEventIndexType::kInArcIndex, 0,
+ NUpdateNotifyOp::kReplicate))
+ }
+
+ newItem.CopyDataPropsFrom(_item);
+
+ UInt64 offset = 0;
+ if (IntToBool(newProps))
+ {
+ newItem.WriteHeader(outStream);
+ offset += _headerSize;
+ }
+ RINOK(InStream_SeekSet(_stream, offset))
+
+ /*
+ if (reportArcProp)
+ ReportArcProps(reportArcProp, newItem,
+ _props._Write_MTime,
+ false, // writeCrc
+ NULL); // unpacksize
+ */
+
+ return NCompress::CopyStream(_stream, outStream, progress);
+
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
+{
+ _timeOptions.Init();
+ _props.Init();
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ UString name = names[i];
+ name.MakeLower_Ascii();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+ const PROPVARIANT &value = values[i];
+ {
+ bool processed = false;
+ RINOK(_timeOptions.Parse(name, value, processed))
+ if (processed)
+ {
+ if (_timeOptions.Write_CTime.Val ||
+ _timeOptions.Write_ATime.Val)
+ return E_INVALIDARG;
+ if ( _timeOptions.Prec != (UInt32)(Int32)-1
+ && _timeOptions.Prec != k_PropVar_TimePrec_0
+ && _timeOptions.Prec != k_PropVar_TimePrec_Unix
+ && _timeOptions.Prec != k_PropVar_TimePrec_HighPrec
+ && _timeOptions.Prec != k_PropVar_TimePrec_Base)
+ return E_INVALIDARG;
+ continue;
+ }
+ }
+ RINOK(_props.SetProperty(name, value))
+ }
+ return S_OK;
+}
+
+static const Byte k_Signature[] = { kSignature_0, kSignature_1, kSignature_2 };
+
+REGISTER_ARC_IO(
+ "gzip", "gz gzip tgz tpz apk", "* * .tar .tar .tar", 0xEF,
+ k_Signature, 0,
+ NArcInfoFlags::kKeepName
+ | NArcInfoFlags::kMTime
+ | NArcInfoFlags::kMTime_Default
+ , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix)
+ | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kUnix)
+ , IsArc_Gz)
+
+}}
diff --git a/CPP/7zip/Archive/HandlerCont.cpp b/CPP/7zip/Archive/HandlerCont.cpp
new file mode 100644
index 0000000..b4524a4
--- /dev/null
+++ b/CPP/7zip/Archive/HandlerCont.cpp
@@ -0,0 +1,346 @@
+// HandlerCont.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/ComTry.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "HandlerCont.h"
+
+namespace NArchive {
+
+namespace NExt {
+API_FUNC_IsArc IsArc_Ext(const Byte *p, size_t size);
+}
+
+Z7_COM7F_IMF(CHandlerCont::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ {
+ RINOK(GetNumberOfItems(&numItems))
+ }
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ UInt64 pos, size;
+ GetItem_ExtractInfo(allFilesMode ? i : indices[i], pos, size);
+ totalSize += size;
+ }
+ extractCallback->SetTotal(totalSize);
+
+ totalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur())
+ CMyComPtr<ISequentialOutStream> outStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+
+ RINOK(extractCallback->GetStream(index, &outStream, askMode))
+
+ UInt64 pos, size;
+ int opRes = GetItem_ExtractInfo(index, pos, size);
+ totalSize += size;
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode))
+
+ if (opRes == NExtract::NOperationResult::kOK)
+ {
+ RINOK(InStream_SeekSet(_stream, pos))
+ streamSpec->Init(size);
+
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress))
+
+ opRes = NExtract::NOperationResult::kDataError;
+
+ if (copyCoderSpec->TotalSize == size)
+ opRes = NExtract::NOperationResult::kOK;
+ else if (copyCoderSpec->TotalSize < size)
+ opRes = NExtract::NOperationResult::kUnexpectedEnd;
+ }
+
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes))
+ }
+
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandlerCont::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ *stream = NULL;
+ UInt64 pos, size;
+ if (GetItem_ExtractInfo(index, pos, size) != NExtract::NOperationResult::kOK)
+ return S_FALSE;
+ return CreateLimitedInStream(_stream, pos, size, stream);
+ COM_TRY_END
+}
+
+
+
+CHandlerImg::CHandlerImg()
+{
+ Clear_HandlerImg_Vars();
+}
+
+Z7_COM7F_IMF(CHandlerImg::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += _size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ {
+ if (newPosition)
+ *newPosition = _virtPos;
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ }
+ _virtPos = (UInt64)offset;
+ if (newPosition)
+ *newPosition = (UInt64)offset;
+ return S_OK;
+}
+
+static const Byte k_GDP_Signature[] = { 'E', 'F', 'I', ' ', 'P', 'A', 'R', 'T' };
+// static const Byte k_Ext_Signature[] = { 0x53, 0xEF };
+// static const unsigned k_Ext_Signature_offset = 0x438;
+
+static const char *GetImgExt(ISequentialInStream *stream)
+{
+ const size_t kHeaderSize = 1 << 11;
+ Byte buf[kHeaderSize];
+ if (ReadStream_FAIL(stream, buf, kHeaderSize) == S_OK)
+ {
+ if (buf[0x1FE] == 0x55 && buf[0x1FF] == 0xAA)
+ {
+ if (memcmp(buf + 512, k_GDP_Signature, sizeof(k_GDP_Signature)) == 0)
+ return "gpt";
+ return "mbr";
+ }
+ if (NExt::IsArc_Ext(buf, kHeaderSize) == k_IsArc_Res_YES)
+ return "ext";
+ }
+ return NULL;
+}
+
+void CHandlerImg::CloseAtError()
+{
+ Stream.Release();
+}
+
+void CHandlerImg::Clear_HandlerImg_Vars()
+{
+ _imgExt = NULL;
+ _size = 0;
+ ClearStreamVars();
+ Reset_VirtPos();
+ Reset_PosInArc();
+}
+
+Z7_COM7F_IMF(CHandlerImg::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * openCallback))
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ HRESULT res;
+ try
+ {
+ res = Open2(stream, openCallback);
+ if (res == S_OK)
+ {
+ CMyComPtr<ISequentialInStream> inStream;
+ const HRESULT res2 = GetStream(0, &inStream);
+ if (res2 == S_OK && inStream)
+ _imgExt = GetImgExt(inStream);
+ // _imgExt = GetImgExt(this); // for debug
+ /* we reset (_virtPos) to support cases, if some code will
+ call Read() from Handler object instead of GetStream() object. */
+ Reset_VirtPos();
+ // optional: we reset (_posInArc). if real seek position of stream will be changed in external code
+ Reset_PosInArc();
+ // optional: here we could also reset seek positions in parent streams..
+ return S_OK;
+ }
+ }
+ catch(...)
+ {
+ CloseAtError();
+ throw;
+ }
+ CloseAtError();
+ return res;
+ }
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandlerImg::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ CHandlerImgProgress
+ , ICompressProgressInfo
+)
+public:
+ CHandlerImg &Handler;
+ CMyComPtr<ICompressProgressInfo> _ratioProgress;
+
+ CHandlerImgProgress(CHandlerImg &handler) : Handler(handler) {}
+};
+
+
+Z7_COM7F_IMF(CHandlerImgProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
+{
+ UInt64 inSize2;
+ if (Handler.Get_PackSizeProcessed(inSize2))
+ inSize = &inSize2;
+ return _ratioProgress->SetRatioInfo(inSize, outSize);
+}
+
+
+Z7_COM7F_IMF(CHandlerImg::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ RINOK(extractCallback->SetTotal(_size))
+ CMyComPtr<ISequentialOutStream> outStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &outStream, askMode))
+ if (!testMode && !outStream)
+ return S_OK;
+ RINOK(extractCallback->PrepareOperation(askMode))
+
+ int opRes = NExtract::NOperationResult::kDataError;
+
+ ClearStreamVars();
+
+ CMyComPtr<ISequentialInStream> inStream;
+ HRESULT hres = GetStream(0, &inStream);
+ if (hres == S_FALSE)
+ hres = E_NOTIMPL;
+
+ if (hres == S_OK && inStream)
+ {
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ if (Init_PackSizeProcessed())
+ {
+ CHandlerImgProgress *imgProgressSpec = new CHandlerImgProgress(*this);
+ CMyComPtr<ICompressProgressInfo> imgProgress = imgProgressSpec;
+ imgProgressSpec->_ratioProgress = progress;
+ progress.Release();
+ progress = imgProgress;
+ }
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ hres = copyCoder->Code(inStream, outStream, NULL, &_size, progress);
+ if (hres == S_OK)
+ {
+ if (copyCoderSpec->TotalSize == _size)
+ opRes = NExtract::NOperationResult::kOK;
+
+ if (_stream_unavailData)
+ opRes = NExtract::NOperationResult::kUnavailable;
+ else if (_stream_unsupportedMethod)
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ else if (_stream_dataError)
+ opRes = NExtract::NOperationResult::kDataError;
+ else if (copyCoderSpec->TotalSize < _size)
+ opRes = NExtract::NOperationResult::kUnexpectedEnd;
+ }
+ }
+
+ inStream.Release();
+ outStream.Release();
+
+ if (hres != S_OK)
+ {
+ if (hres == S_FALSE)
+ opRes = NExtract::NOperationResult::kDataError;
+ else if (hres == E_NOTIMPL)
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ else
+ return hres;
+ }
+
+ return extractCallback->SetOperationResult(opRes);
+ COM_TRY_END
+}
+
+
+HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize)
+{
+ areThereNonZeros = false;
+ numZeros = 0;
+ const size_t kBufSize = 1 << 11;
+ Byte buf[kBufSize];
+ for (;;)
+ {
+ UInt32 size = 0;
+ RINOK(stream->Read(buf, kBufSize, &size))
+ if (size == 0)
+ return S_OK;
+ for (UInt32 i = 0; i < size; i++)
+ if (buf[i] != 0)
+ {
+ areThereNonZeros = true;
+ numZeros += i;
+ return S_OK;
+ }
+ numZeros += size;
+ if (numZeros > maxSize)
+ return S_OK;
+ }
+}
+
+}
diff --git a/CPP/7zip/Archive/HandlerCont.h b/CPP/7zip/Archive/HandlerCont.h
new file mode 100644
index 0000000..2dd0529
--- /dev/null
+++ b/CPP/7zip/Archive/HandlerCont.h
@@ -0,0 +1,134 @@
+// HandlerCont.h
+
+#ifndef ZIP7_INC_HANDLER_CONT_H
+#define ZIP7_INC_HANDLER_CONT_H
+
+#include "../../Common/MyCom.h"
+
+#include "IArchive.h"
+
+namespace NArchive {
+
+#define Z7_IFACEM_IInArchive_Cont(x) \
+ x(Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback)) \
+ x(Close()) \
+ x(GetNumberOfItems(UInt32 *numItems)) \
+ x(GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \
+ /* x(Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback)) */ \
+ x(GetArchiveProperty(PROPID propID, PROPVARIANT *value)) \
+ x(GetNumberOfProperties(UInt32 *numProps)) \
+ x(GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \
+ x(GetNumberOfArchiveProperties(UInt32 *numProps)) \
+ x(GetArchivePropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \
+
+
+// #define Z7_COM7F_PUREO(f) virtual Z7_COM7F_IMF(f) Z7_override =0;
+// #define Z7_COM7F_PUREO2(t, f) virtual Z7_COM7F_IMF2(t, f) Z7_override =0;
+
+class CHandlerCont:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_2(
+ IInArchive,
+ IInArchiveGetStream)
+ /*
+ Z7_IFACEM_IInArchive_Cont(Z7_COM7F_PUREO)
+ // Z7_IFACE_COM7_PURE(IInArchive_Cont)
+ */
+ Z7_COM7F_IMP(Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback))
+protected:
+ Z7_IFACE_COM7_IMP(IInArchiveGetStream)
+
+ CMyComPtr<IInStream> _stream;
+ virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const = 0;
+ // destructor must be virtual for this class
+ virtual ~CHandlerCont() {}
+};
+
+
+
+#define Z7_IFACEM_IInArchive_Img(x) \
+ /* x(Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback)) */ \
+ x(Close()) \
+ /* x(GetNumberOfItems(UInt32 *numItems)) */ \
+ x(GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \
+ /* x(Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback)) */ \
+ x(GetArchiveProperty(PROPID propID, PROPVARIANT *value)) \
+ x(GetNumberOfProperties(UInt32 *numProps)) \
+ x(GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \
+ x(GetNumberOfArchiveProperties(UInt32 *numProps)) \
+ x(GetArchivePropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \
+
+
+class CHandlerImg:
+ public IInArchive,
+ public IInArchiveGetStream,
+ public IInStream,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_3(
+ IInArchive,
+ IInArchiveGetStream,
+ IInStream)
+
+ Z7_COM7F_IMP(Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback))
+ Z7_COM7F_IMP(GetNumberOfItems(UInt32 *numItems))
+ Z7_COM7F_IMP(Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback))
+ Z7_IFACE_COM7_IMP(IInStream)
+ // Z7_IFACEM_IInArchive_Img(Z7_COM7F_PUREO)
+
+protected:
+ UInt64 _virtPos;
+ UInt64 _posInArc;
+ UInt64 _size;
+ CMyComPtr<IInStream> Stream;
+ const char *_imgExt;
+
+ bool _stream_unavailData;
+ bool _stream_unsupportedMethod;
+ bool _stream_dataError;
+ // bool _stream_UsePackSize;
+ // UInt64 _stream_PackSize;
+
+ void Reset_PosInArc() { _posInArc = (UInt64)0 - 1; }
+ void Reset_VirtPos() { _virtPos = (UInt64)0; }
+
+ void ClearStreamVars()
+ {
+ _stream_unavailData = false;
+ _stream_unsupportedMethod = false;
+ _stream_dataError = false;
+ // _stream_UsePackSize = false;
+ // _stream_PackSize = 0;
+ }
+
+ void Clear_HandlerImg_Vars(); // it doesn't Release (Stream) var.
+
+ virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) = 0;
+ virtual void CloseAtError();
+
+ // returns (true), if Get_PackSizeProcessed() is required in Extract()
+ virtual bool Init_PackSizeProcessed()
+ {
+ return false;
+ }
+public:
+ virtual bool Get_PackSizeProcessed(UInt64 &size)
+ {
+ size = 0;
+ return false;
+ }
+
+ CHandlerImg();
+ // destructor must be virtual for this class
+ virtual ~CHandlerImg() {}
+};
+
+
+HRESULT ReadZeroTail(ISequentialInStream *stream, bool &areThereNonZeros, UInt64 &numZeros, UInt64 maxSize);
+
+}
+
+#endif
diff --git a/CPP/7zip/Archive/HfsHandler.cpp b/CPP/7zip/Archive/HfsHandler.cpp
new file mode 100644
index 0000000..696ecd7
--- /dev/null
+++ b/CPP/7zip/Archive/HfsHandler.cpp
@@ -0,0 +1,2590 @@
+// HfsHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/MyString.h"
+
+#include "../../Windows/PropVariantUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "HfsHandler.h"
+
+/* if HFS_SHOW_ALT_STREAMS is defined, the handler will show attribute files
+ and resource forks. In most cases it looks useless. So we disable it. */
+
+#define HFS_SHOW_ALT_STREAMS
+
+#define Get16(p) GetBe16(p)
+#define Get32(p) GetBe32(p)
+#define Get64(p) GetBe64(p)
+
+namespace NArchive {
+namespace NHfs {
+
+static const char * const kResFileName = "rsrc"; // "com.apple.ResourceFork";
+
+struct CExtent
+{
+ UInt32 Pos;
+ UInt32 NumBlocks;
+};
+
+struct CIdExtents
+{
+ UInt32 ID;
+ UInt32 StartBlock;
+ CRecordVector<CExtent> Extents;
+};
+
+struct CFork
+{
+ UInt64 Size;
+ UInt32 NumBlocks;
+ // UInt32 ClumpSize;
+ CRecordVector<CExtent> Extents;
+
+ CFork(): Size(0), NumBlocks(0) {}
+
+ void Parse(const Byte *p);
+
+ bool IsEmpty() const { return Size == 0 && NumBlocks == 0 && Extents.Size() == 0; }
+
+ UInt32 Calc_NumBlocks_from_Extents() const;
+ bool Check_NumBlocks() const;
+
+ bool Check_Size_with_NumBlocks(unsigned blockSizeLog) const
+ {
+ return Size <= ((UInt64)NumBlocks << blockSizeLog);
+ }
+
+ bool IsOk(unsigned blockSizeLog) const
+ {
+ // we don't check cases with extra (empty) blocks in last extent
+ return Check_NumBlocks() && Check_Size_with_NumBlocks(blockSizeLog);
+ }
+
+ bool Upgrade(const CObjectVector<CIdExtents> &items, UInt32 id);
+ bool UpgradeAndTest(const CObjectVector<CIdExtents> &items, UInt32 id, unsigned blockSizeLog)
+ {
+ if (!Upgrade(items, id))
+ return false;
+ return IsOk(blockSizeLog);
+ }
+};
+
+static const unsigned kNumFixedExtents = 8;
+static const unsigned kForkRecSize = 16 + kNumFixedExtents * 8;
+
+
+void CFork::Parse(const Byte *p)
+{
+ Extents.Clear();
+ Size = Get64(p);
+ // ClumpSize = Get32(p + 8);
+ NumBlocks = Get32(p + 12);
+ p += 16;
+ for (unsigned i = 0; i < kNumFixedExtents; i++, p += 8)
+ {
+ CExtent e;
+ e.Pos = Get32(p);
+ e.NumBlocks = Get32(p + 4);
+ if (e.NumBlocks != 0)
+ Extents.Add(e);
+ }
+}
+
+UInt32 CFork::Calc_NumBlocks_from_Extents() const
+{
+ UInt32 num = 0;
+ FOR_VECTOR (i, Extents)
+ {
+ num += Extents[i].NumBlocks;
+ }
+ return num;
+}
+
+bool CFork::Check_NumBlocks() const
+{
+ UInt32 num = 0;
+ FOR_VECTOR (i, Extents)
+ {
+ UInt32 next = num + Extents[i].NumBlocks;
+ if (next < num)
+ return false;
+ num = next;
+ }
+ return num == NumBlocks;
+}
+
+struct CIdIndexPair
+{
+ UInt32 ID;
+ unsigned Index;
+
+ int Compare(const CIdIndexPair &a) const;
+};
+
+#define RINOZ(x) { const int _t_ = (x); if (_t_ != 0) return _t_; }
+
+int CIdIndexPair::Compare(const CIdIndexPair &a) const
+{
+ RINOZ(MyCompare(ID, a.ID))
+ return MyCompare(Index, a.Index);
+}
+
+static int FindItemIndex(const CRecordVector<CIdIndexPair> &items, UInt32 id)
+{
+ unsigned left = 0, right = items.Size();
+ while (left != right)
+ {
+ const unsigned mid = (left + right) / 2;
+ const UInt32 midVal = items[mid].ID;
+ if (id == midVal)
+ return (int)items[mid].Index;
+ if (id < midVal)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+}
+
+static int Find_in_IdExtents(const CObjectVector<CIdExtents> &items, UInt32 id)
+{
+ unsigned left = 0, right = items.Size();
+ while (left != right)
+ {
+ const unsigned mid = (left + right) / 2;
+ const UInt32 midVal = items[mid].ID;
+ if (id == midVal)
+ return (int)mid;
+ if (id < midVal)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+}
+
+bool CFork::Upgrade(const CObjectVector<CIdExtents> &items, UInt32 id)
+{
+ int index = Find_in_IdExtents(items, id);
+ if (index < 0)
+ return true;
+ const CIdExtents &item = items[index];
+ if (Calc_NumBlocks_from_Extents() != item.StartBlock)
+ return false;
+ Extents += item.Extents;
+ return true;
+}
+
+
+struct CVolHeader
+{
+ Byte Header[2];
+ UInt16 Version;
+ // UInt32 Attr;
+ // UInt32 LastMountedVersion;
+ // UInt32 JournalInfoBlock;
+
+ UInt32 CTime;
+ UInt32 MTime;
+ // UInt32 BackupTime;
+ // UInt32 CheckedTime;
+
+ UInt32 NumFiles;
+ UInt32 NumFolders;
+ unsigned BlockSizeLog;
+ UInt32 NumBlocks;
+ UInt32 NumFreeBlocks;
+
+ // UInt32 WriteCount;
+ // UInt32 FinderInfo[8];
+ // UInt64 VolID;
+
+ UInt64 GetPhySize() const { return (UInt64)NumBlocks << BlockSizeLog; }
+ UInt64 GetFreeSize() const { return (UInt64)NumFreeBlocks << BlockSizeLog; }
+ bool IsHfsX() const { return Version > 4; }
+};
+
+inline void HfsTimeToFileTime(UInt32 hfsTime, FILETIME &ft)
+{
+ UInt64 v = ((UInt64)3600 * 24 * (365 * 303 + 24 * 3) + hfsTime) * 10000000;
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+}
+
+enum ERecordType
+{
+ RECORD_TYPE_FOLDER = 1,
+ RECORD_TYPE_FILE,
+ RECORD_TYPE_FOLDER_THREAD,
+ RECORD_TYPE_FILE_THREAD
+};
+
+
+
+// static const UInt32 kMethod_1_NO_COMPRESSION = 1; // in xattr
+static const UInt32 kMethod_ZLIB_ATTR = 3;
+static const UInt32 kMethod_ZLIB_RSRC = 4;
+// static const UInt32 kMethod_DEDUP = 5; // de-dup within the generation store
+// macos 10.10
+static const UInt32 kMethod_LZVN_ATTR = 7;
+static const UInt32 kMethod_LZVN_RSRC = 8;
+static const UInt32 kMethod_COPY_ATTR = 9;
+static const UInt32 kMethod_COPY_RSRC = 10;
+// macos 10.11
+// static const UInt32 kMethod_LZFSE_ATTR = 11;
+static const UInt32 kMethod_LZFSE_RSRC = 12;
+
+// static const UInt32 kMethod_ZBM_RSRC = 14;
+
+static const char * const g_Methods[] =
+{
+ NULL
+ , NULL
+ , NULL
+ , "ZLIB-attr"
+ , "ZLIB-rsrc"
+ , NULL
+ , NULL
+ , "LZVN-attr"
+ , "LZVN-rsrc"
+ , "COPY-attr"
+ , "COPY-rsrc"
+ , "LZFSE-attr"
+ , "LZFSE-rsrc"
+ , NULL
+ , "ZBM-rsrc"
+};
+
+
+static const Byte k_COPY_Uncompressed_Marker = 0xcc;
+static const Byte k_LZVN_Uncompressed_Marker = 6;
+
+void CCompressHeader::Parse(const Byte *p, size_t dataSize)
+{
+ Clear();
+
+ if (dataSize < k_decmpfs_HeaderSize)
+ return;
+ if (GetUi32(p) != 0x636D7066) // magic == "fpmc"
+ return;
+ Method = GetUi32(p + 4);
+ UnpackSize = GetUi64(p + 8);
+ dataSize -= k_decmpfs_HeaderSize;
+ IsCorrect = true;
+
+ if ( Method == kMethod_ZLIB_RSRC
+ || Method == kMethod_COPY_RSRC
+ || Method == kMethod_LZVN_RSRC
+ || Method == kMethod_LZFSE_RSRC
+ // || Method == kMethod_ZBM_RSRC // for debug
+ )
+ {
+ IsResource = true;
+ if (dataSize == 0)
+ IsSupported = (
+ Method != kMethod_LZFSE_RSRC &&
+ Method != kMethod_COPY_RSRC);
+ return;
+ }
+
+ if ( Method == kMethod_ZLIB_ATTR
+ || Method == kMethod_COPY_ATTR
+ || Method == kMethod_LZVN_ATTR
+ // || Method == kMethod_LZFSE_ATTR
+ )
+ {
+ if (dataSize == 0)
+ return;
+ const Byte b = p[k_decmpfs_HeaderSize];
+ if ( (Method == kMethod_ZLIB_ATTR && (b & 0xf) == 0xf)
+ || (Method == kMethod_COPY_ATTR && b == k_COPY_Uncompressed_Marker)
+ || (Method == kMethod_LZVN_ATTR && b == k_LZVN_Uncompressed_Marker))
+ {
+ dataSize--;
+ // if (UnpackSize > dataSize)
+ if (UnpackSize != dataSize)
+ return;
+ DataPos = k_decmpfs_HeaderSize + 1;
+ IsSupported = true;
+ }
+ else
+ {
+ if (Method != kMethod_COPY_ATTR)
+ IsSupported = true;
+ DataPos = k_decmpfs_HeaderSize;
+ }
+ }
+}
+
+
+void CCompressHeader::MethodToProp(NWindows::NCOM::CPropVariant &prop) const
+{
+ if (!IsCorrect)
+ return;
+ const UInt32 method = Method;
+ const char *p = NULL;
+ if (method < Z7_ARRAY_SIZE(g_Methods))
+ p = g_Methods[method];
+ AString s;
+ if (p)
+ s = p;
+ else
+ s.Add_UInt32(method);
+ // if (!IsSupported) s += "-unsuported";
+ prop = s;
+}
+
+void MethodsMaskToProp(UInt32 methodsMask, NWindows::NCOM::CPropVariant &prop)
+{
+ FLAGS_TO_PROP(g_Methods, methodsMask, prop);
+}
+
+
+struct CItem
+{
+ UString Name;
+
+ UInt32 ParentID;
+
+ UInt16 Type;
+ UInt16 FileMode;
+ // UInt16 Flags;
+ // UInt32 Valence;
+ UInt32 ID;
+ UInt32 CTime;
+ UInt32 MTime;
+ UInt32 AttrMTime;
+ UInt32 ATime;
+ // UInt32 BackupDate;
+
+ /*
+ UInt32 OwnerID;
+ UInt32 GroupID;
+ Byte AdminFlags;
+ Byte OwnerFlags;
+ union
+ {
+ UInt32 iNodeNum;
+ UInt32 LinkCount;
+ UInt32 RawDevice;
+ } special;
+
+ UInt32 FileType;
+ UInt32 FileCreator;
+ UInt16 FinderFlags;
+ UInt16 Point[2];
+ */
+
+ CFork DataFork;
+ CFork ResourceFork;
+
+ // for compressed attribute (decmpfs)
+ int decmpfs_AttrIndex;
+ CCompressHeader CompressHeader;
+
+ CItem():
+ decmpfs_AttrIndex(-1)
+ {}
+ bool IsDir() const { return Type == RECORD_TYPE_FOLDER; }
+ // const CFork *GetFork(bool isResource) const { return (isResource ? &ResourceFork: &DataFork); }
+};
+
+
+struct CAttr
+{
+ UInt32 ID;
+ bool Fork_defined;
+
+ // UInt32 Size; // for (Fork_defined == false) case
+ // size_t DataPos; // for (Fork_defined == false) case
+ CByteBuffer Data;
+
+ CFork Fork;
+
+ UString Name;
+
+ UInt64 GetSize() const
+ {
+ if (Fork_defined)
+ return Fork.Size;
+ return Data.Size();
+ }
+
+ CAttr():
+ Fork_defined(false)
+ // Size(0),
+ // DataPos(0),
+ {}
+};
+
+
+static const int kAttrIndex_Item = -1;
+static const int kAttrIndex_Resource = -2;
+
+struct CRef
+{
+ unsigned ItemIndex;
+ int AttrIndex;
+ int Parent;
+
+ CRef(): AttrIndex(kAttrIndex_Item), Parent(-1) {}
+ bool IsResource() const { return AttrIndex == kAttrIndex_Resource; }
+ bool IsAltStream() const { return AttrIndex != kAttrIndex_Item; }
+ bool IsItem() const { return AttrIndex == kAttrIndex_Item; }
+};
+
+
+class CDatabase
+{
+ HRESULT ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream);
+ HRESULT LoadExtentFile(const CFork &fork, IInStream *inStream, CObjectVector<CIdExtents> *overflowExtentsArray);
+ HRESULT LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress);
+ HRESULT LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents> *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress);
+ bool Parse_decmpgfs(unsigned attrIndex, CItem &item, bool &skip);
+public:
+ CRecordVector<CRef> Refs;
+ CObjectVector<CItem> Items;
+ CObjectVector<CAttr> Attrs;
+
+ // CByteBuffer AttrBuf;
+
+ CVolHeader Header;
+ bool HeadersError;
+ bool UnsupportedFeature;
+ bool ThereAreAltStreams;
+ // bool CaseSensetive;
+ UString ResFileName;
+
+ UInt64 SpecOffset;
+ UInt64 PhySize;
+ UInt64 PhySize2;
+ UInt64 ArcFileSize;
+ UInt32 MethodsMask;
+
+ void Clear()
+ {
+ SpecOffset = 0;
+ PhySize = 0;
+ PhySize2 = 0;
+ ArcFileSize = 0;
+ MethodsMask = 0;
+ HeadersError = false;
+ UnsupportedFeature = false;
+ ThereAreAltStreams = false;
+ // CaseSensetive = false;
+
+ Refs.Clear();
+ Items.Clear();
+ Attrs.Clear();
+ // AttrBuf.Free();
+ }
+
+ UInt64 Get_UnpackSize_of_Ref(const CRef &ref) const
+ {
+ if (ref.AttrIndex >= 0)
+ return Attrs[ref.AttrIndex].GetSize();
+ const CItem &item = Items[ref.ItemIndex];
+ if (ref.IsResource())
+ return item.ResourceFork.Size;
+ if (item.IsDir())
+ return 0;
+ else if (item.CompressHeader.IsCorrect)
+ return item.CompressHeader.UnpackSize;
+ return item.DataFork.Size;
+ }
+
+ void GetItemPath(unsigned index, NWindows::NCOM::CPropVariant &path) const;
+ HRESULT Open2(IInStream *inStream, IArchiveOpenCallback *progress);
+};
+
+enum
+{
+ kHfsID_Root = 1,
+ kHfsID_RootFolder = 2,
+ kHfsID_ExtentsFile = 3,
+ kHfsID_CatalogFile = 4,
+ kHfsID_BadBlockFile = 5,
+ kHfsID_AllocationFile = 6,
+ kHfsID_StartupFile = 7,
+ kHfsID_AttributesFile = 8,
+ kHfsID_RepairCatalogFile = 14,
+ kHfsID_BogusExtentFile = 15,
+ kHfsID_FirstUserCatalogNode = 16
+};
+
+void CDatabase::GetItemPath(unsigned index, NWindows::NCOM::CPropVariant &path) const
+{
+ unsigned len = 0;
+ const unsigned kNumLevelsMax = (1 << 10);
+ unsigned cur = index;
+ unsigned i;
+
+ for (i = 0; i < kNumLevelsMax; i++)
+ {
+ const CRef &ref = Refs[cur];
+ const UString *s;
+
+ if (ref.IsResource())
+ s = &ResFileName;
+ else if (ref.AttrIndex >= 0)
+ s = &Attrs[ref.AttrIndex].Name;
+ else
+ s = &Items[ref.ItemIndex].Name;
+
+ len += s->Len();
+ len++;
+ cur = (unsigned)ref.Parent;
+ if (ref.Parent < 0)
+ break;
+ }
+
+ len--;
+ wchar_t *p = path.AllocBstr(len);
+ p[len] = 0;
+ cur = index;
+
+ for (;;)
+ {
+ const CRef &ref = Refs[cur];
+ const UString *s;
+ wchar_t delimChar = L':';
+
+ if (ref.IsResource())
+ s = &ResFileName;
+ else if (ref.AttrIndex >= 0)
+ s = &Attrs[ref.AttrIndex].Name;
+ else
+ {
+ delimChar = WCHAR_PATH_SEPARATOR;
+ s = &Items[ref.ItemIndex].Name;
+ }
+
+ unsigned curLen = s->Len();
+ len -= curLen;
+
+ const wchar_t *src = (const wchar_t *)*s;
+ wchar_t *dest = p + len;
+ for (unsigned j = 0; j < curLen; j++)
+ {
+ wchar_t c = src[j];
+ // 18.06
+ if (c == CHAR_PATH_SEPARATOR || c == '/')
+ c = '_';
+ dest[j] = c;
+ }
+
+ if (len == 0)
+ break;
+ p[--len] = delimChar;
+ cur = (unsigned)ref.Parent;
+ }
+}
+
+// Actually we read all blocks. It can be larger than fork.Size
+
+HRESULT CDatabase::ReadFile(const CFork &fork, CByteBuffer &buf, IInStream *inStream)
+{
+ if (fork.NumBlocks >= Header.NumBlocks)
+ return S_FALSE;
+ if ((ArcFileSize >> Header.BlockSizeLog) + 1 < fork.NumBlocks)
+ return S_FALSE;
+
+ const size_t totalSize = (size_t)fork.NumBlocks << Header.BlockSizeLog;
+ if ((totalSize >> Header.BlockSizeLog) != fork.NumBlocks)
+ return S_FALSE;
+ buf.Alloc(totalSize);
+ UInt32 curBlock = 0;
+ FOR_VECTOR (i, fork.Extents)
+ {
+ if (curBlock >= fork.NumBlocks)
+ return S_FALSE;
+ const CExtent &e = fork.Extents[i];
+ if (e.Pos > Header.NumBlocks ||
+ e.NumBlocks > fork.NumBlocks - curBlock ||
+ e.NumBlocks > Header.NumBlocks - e.Pos)
+ return S_FALSE;
+ RINOK(InStream_SeekSet(inStream, SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog)))
+ RINOK(ReadStream_FALSE(inStream,
+ (Byte *)buf + ((size_t)curBlock << Header.BlockSizeLog),
+ (size_t)e.NumBlocks << Header.BlockSizeLog))
+ curBlock += e.NumBlocks;
+ }
+ return S_OK;
+}
+
+static const unsigned kNodeDescriptor_Size = 14;
+
+struct CNodeDescriptor
+{
+ UInt32 fLink;
+ // UInt32 bLink;
+ Byte Kind;
+ // Byte Height;
+ unsigned NumRecords;
+
+ bool Parse(const Byte *p, unsigned nodeSizeLog);
+};
+
+
+bool CNodeDescriptor::Parse(const Byte *p, unsigned nodeSizeLog)
+{
+ fLink = Get32(p);
+ // bLink = Get32(p + 4);
+ Kind = p[8];
+ // Height = p[9];
+ NumRecords = Get16(p + 10);
+
+ const size_t nodeSize = (size_t)1 << nodeSizeLog;
+ if (kNodeDescriptor_Size + ((UInt32)NumRecords + 1) * 2 > nodeSize)
+ return false;
+ const size_t limit = nodeSize - ((UInt32)NumRecords + 1) * 2;
+
+ p += nodeSize - 2;
+
+ for (unsigned i = 0; i < NumRecords; i++)
+ {
+ const UInt32 offs = Get16(p);
+ p -= 2;
+ const UInt32 offsNext = Get16(p);
+ if (offs < kNodeDescriptor_Size
+ || offs >= offsNext
+ || offsNext > limit)
+ return false;
+ }
+ return true;
+}
+
+struct CHeaderRec
+{
+ // UInt16 TreeDepth;
+ // UInt32 RootNode;
+ // UInt32 LeafRecords;
+ UInt32 FirstLeafNode;
+ // UInt32 LastLeafNode;
+ unsigned NodeSizeLog;
+ // UInt16 MaxKeyLength;
+ UInt32 TotalNodes;
+ // UInt32 FreeNodes;
+ // UInt16 Reserved1;
+ // UInt32 ClumpSize;
+ // Byte BtreeType;
+ // Byte KeyCompareType;
+ // UInt32 Attributes;
+ // UInt32 Reserved3[16];
+
+ HRESULT Parse2(const CByteBuffer &buf);
+};
+
+HRESULT CHeaderRec::Parse2(const CByteBuffer &buf)
+{
+ if (buf.Size() < kNodeDescriptor_Size + 0x2A + 16 * 4)
+ return S_FALSE;
+ const Byte * p = (const Byte *)buf + kNodeDescriptor_Size;
+ // TreeDepth = Get16(p);
+ // RootNode = Get32(p + 2);
+ // LeafRecords = Get32(p + 6);
+ FirstLeafNode = Get32(p + 0xA);
+ // LastLeafNode = Get32(p + 0xE);
+ const UInt32 nodeSize = Get16(p + 0x12);
+
+ unsigned i;
+ for (i = 9; ((UInt32)1 << i) != nodeSize; i++)
+ if (i == 16)
+ return S_FALSE;
+ NodeSizeLog = i;
+
+ // MaxKeyLength = Get16(p + 0x14);
+ TotalNodes = Get32(p + 0x16);
+ // FreeNodes = Get32(p + 0x1A);
+ // Reserved1 = Get16(p + 0x1E);
+ // ClumpSize = Get32(p + 0x20);
+ // BtreeType = p[0x24];
+ // KeyCompareType = p[0x25];
+ // Attributes = Get32(p + 0x26);
+ /*
+ for (int i = 0; i < 16; i++)
+ Reserved3[i] = Get32(p + 0x2A + i * 4);
+ */
+
+ if ((buf.Size() >> NodeSizeLog) < TotalNodes)
+ return S_FALSE;
+
+ return S_OK;
+}
+
+
+static const Byte kNodeType_Leaf = 0xFF;
+// static const Byte kNodeType_Index = 0;
+// static const Byte kNodeType_Header = 1;
+// static const Byte kNodeType_Mode = 2;
+
+static const Byte kExtentForkType_Data = 0;
+static const Byte kExtentForkType_Resource = 0xFF;
+
+/* It loads data extents from Extents Overflow File
+ Most dmg installers are not fragmented. So there are no extents in Overflow File. */
+
+HRESULT CDatabase::LoadExtentFile(const CFork &fork, IInStream *inStream, CObjectVector<CIdExtents> *overflowExtentsArray)
+{
+ if (fork.NumBlocks == 0)
+ return S_OK;
+ CByteBuffer buf;
+ RINOK(ReadFile(fork, buf, inStream))
+ const Byte *p = (const Byte *)buf;
+
+ // CNodeDescriptor nodeDesc;
+ // nodeDesc.Parse(p);
+ CHeaderRec hr;
+ RINOK(hr.Parse2(buf))
+
+ UInt32 node = hr.FirstLeafNode;
+ if (node == 0)
+ return S_OK;
+ if (hr.TotalNodes == 0)
+ return S_FALSE;
+
+ CByteArr usedBuf(hr.TotalNodes);
+ memset(usedBuf, 0, hr.TotalNodes);
+
+ while (node != 0)
+ {
+ if (node >= hr.TotalNodes || usedBuf[node] != 0)
+ return S_FALSE;
+ usedBuf[node] = 1;
+
+ const size_t nodeOffset = (size_t)node << hr.NodeSizeLog;
+ CNodeDescriptor desc;
+ if (!desc.Parse(p + nodeOffset, hr.NodeSizeLog))
+ return S_FALSE;
+ if (desc.Kind != kNodeType_Leaf)
+ return S_FALSE;
+
+ UInt32 endBlock = 0;
+
+ for (unsigned i = 0; i < desc.NumRecords; i++)
+ {
+ const UInt32 nodeSize = ((UInt32)1 << hr.NodeSizeLog);
+ const Byte *r = p + nodeOffset + nodeSize - i * 2;
+ const UInt32 offs = Get16(r - 2);
+ UInt32 recSize = Get16(r - 4) - offs;
+ const unsigned kKeyLen = 10;
+
+ if (recSize != 2 + kKeyLen + kNumFixedExtents * 8)
+ return S_FALSE;
+
+ r = p + nodeOffset + offs;
+ if (Get16(r) != kKeyLen)
+ return S_FALSE;
+
+ const Byte forkType = r[2];
+ unsigned forkTypeIndex;
+ if (forkType == kExtentForkType_Data)
+ forkTypeIndex = 0;
+ else if (forkType == kExtentForkType_Resource)
+ forkTypeIndex = 1;
+ else
+ continue;
+ CObjectVector<CIdExtents> &overflowExtents = overflowExtentsArray[forkTypeIndex];
+
+ const UInt32 id = Get32(r + 4);
+ const UInt32 startBlock = Get32(r + 8);
+ r += 2 + kKeyLen;
+
+ bool needNew = true;
+
+ if (overflowExtents.Size() != 0)
+ {
+ CIdExtents &e = overflowExtents.Back();
+ if (e.ID == id)
+ {
+ if (endBlock != startBlock)
+ return S_FALSE;
+ needNew = false;
+ }
+ }
+
+ if (needNew)
+ {
+ CIdExtents &e = overflowExtents.AddNew();
+ e.ID = id;
+ e.StartBlock = startBlock;
+ endBlock = startBlock;
+ }
+
+ CIdExtents &e = overflowExtents.Back();
+
+ for (unsigned k = 0; k < kNumFixedExtents; k++, r += 8)
+ {
+ CExtent ee;
+ ee.Pos = Get32(r);
+ ee.NumBlocks = Get32(r + 4);
+ if (ee.NumBlocks != 0)
+ {
+ e.Extents.Add(ee);
+ endBlock += ee.NumBlocks;
+ }
+ }
+ }
+
+ node = desc.fLink;
+ }
+ return S_OK;
+}
+
+static void LoadName(const Byte *data, unsigned len, UString &dest)
+{
+ wchar_t *p = dest.GetBuf(len);
+ unsigned i;
+ for (i = 0; i < len; i++)
+ {
+ const wchar_t c = Get16(data + i * 2);
+ if (c == 0)
+ break;
+ p[i] = c;
+ }
+ p[i] = 0;
+ dest.ReleaseBuf_SetLen(i);
+}
+
+static bool IsNameEqualTo(const Byte *data, const char *name)
+{
+ for (unsigned i = 0;; i++)
+ {
+ const char c = name[i];
+ if (c == 0)
+ return true;
+ if (Get16(data + i * 2) != (Byte)c)
+ return false;
+ }
+}
+
+static const UInt32 kAttrRecordType_Inline = 0x10;
+static const UInt32 kAttrRecordType_Fork = 0x20;
+// static const UInt32 kAttrRecordType_Extents = 0x30;
+
+HRESULT CDatabase::LoadAttrs(const CFork &fork, IInStream *inStream, IArchiveOpenCallback *progress)
+{
+ if (fork.NumBlocks == 0)
+ return S_OK;
+
+ CByteBuffer AttrBuf;
+ RINOK(ReadFile(fork, AttrBuf, inStream))
+ const Byte *p = (const Byte *)AttrBuf;
+
+ // CNodeDescriptor nodeDesc;
+ // nodeDesc.Parse(p);
+ CHeaderRec hr;
+ RINOK(hr.Parse2(AttrBuf))
+
+ // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC);
+
+ UInt32 node = hr.FirstLeafNode;
+ if (node == 0)
+ return S_OK;
+ if (hr.TotalNodes == 0)
+ return S_FALSE;
+
+ CByteArr usedBuf(hr.TotalNodes);
+ memset(usedBuf, 0, hr.TotalNodes);
+
+ CFork resFork;
+
+ while (node != 0)
+ {
+ if (node >= hr.TotalNodes || usedBuf[node] != 0)
+ return S_FALSE;
+ usedBuf[node] = 1;
+
+ const size_t nodeOffset = (size_t)node << hr.NodeSizeLog;
+ CNodeDescriptor desc;
+ if (!desc.Parse(p + nodeOffset, hr.NodeSizeLog))
+ return S_FALSE;
+ if (desc.Kind != kNodeType_Leaf)
+ return S_FALSE;
+
+ for (unsigned i = 0; i < desc.NumRecords; i++)
+ {
+ const UInt32 nodeSize = ((UInt32)1 << hr.NodeSizeLog);
+ const Byte *r = p + nodeOffset + nodeSize - i * 2;
+ const UInt32 offs = Get16(r - 2);
+ UInt32 recSize = Get16(r - 4) - offs;
+ const unsigned kHeadSize = 14;
+ if (recSize < kHeadSize)
+ return S_FALSE;
+
+ r = p + nodeOffset + offs;
+ const UInt32 keyLen = Get16(r);
+
+ // UInt16 pad = Get16(r + 2);
+ const UInt32 fileID = Get32(r + 4);
+ const unsigned startBlock = Get32(r + 8);
+ if (startBlock != 0)
+ {
+ // that case is still unsupported
+ UnsupportedFeature = true;
+ continue;
+ }
+ const unsigned nameLen = Get16(r + 12);
+
+ if (keyLen + 2 > recSize ||
+ keyLen != kHeadSize - 2 + nameLen * 2)
+ return S_FALSE;
+ r += kHeadSize;
+ recSize -= kHeadSize;
+
+ const Byte *name = r;
+ r += nameLen * 2;
+ recSize -= nameLen * 2;
+
+ if (recSize < 4)
+ return S_FALSE;
+
+ const UInt32 recordType = Get32(r);
+
+ if (progress && (Attrs.Size() & 0xFFF) == 0)
+ {
+ const UInt64 numFiles = 0;
+ RINOK(progress->SetCompleted(&numFiles, NULL))
+ }
+
+ if (Attrs.Size() >= ((UInt32)1 << 31))
+ return S_FALSE;
+
+ CAttr &attr = Attrs.AddNew();
+ attr.ID = fileID;
+ LoadName(name, nameLen, attr.Name);
+
+ if (recordType == kAttrRecordType_Fork)
+ {
+ // 22.00 : some hfs files contain it;
+ /* spec: If the attribute has more than 8 extents, there will be additional
+ records (of type kAttrRecordType_Extents) for this attribute. */
+ if (recSize != 8 + kForkRecSize)
+ return S_FALSE;
+ if (Get32(r + 4) != 0) // reserved
+ return S_FALSE;
+ attr.Fork.Parse(r + 8);
+ attr.Fork_defined = true;
+ continue;
+ }
+ else if (recordType != kAttrRecordType_Inline)
+ {
+ UnsupportedFeature = true;
+ continue;
+ }
+
+ const unsigned kRecordHeaderSize = 16;
+ if (recSize < kRecordHeaderSize)
+ return S_FALSE;
+ if (Get32(r + 4) != 0 || Get32(r + 8) != 0) // reserved
+ return S_FALSE;
+ const UInt32 dataSize = Get32(r + 12);
+
+ r += kRecordHeaderSize;
+ recSize -= kRecordHeaderSize;
+
+ if (recSize < dataSize)
+ return S_FALSE;
+
+ attr.Data.CopyFrom(r, dataSize);
+ // attr.DataPos = nodeOffset + offs + 2 + keyLen + kRecordHeaderSize;
+ // attr.Size = dataSize;
+ }
+
+ node = desc.fLink;
+ }
+ return S_OK;
+}
+
+
+bool CDatabase::Parse_decmpgfs(unsigned attrIndex, CItem &item, bool &skip)
+{
+ const CAttr &attr = Attrs[attrIndex];
+ skip = false;
+ if (item.CompressHeader.IsCorrect || !item.DataFork.IsEmpty())
+ return false;
+
+ item.CompressHeader.Parse(attr.Data, attr.Data.Size());
+
+ if (item.CompressHeader.IsCorrect)
+ {
+ item.decmpfs_AttrIndex = (int)attrIndex;
+ skip = true;
+ if (item.CompressHeader.Method < sizeof(MethodsMask) * 8)
+ MethodsMask |= ((UInt32)1 << item.CompressHeader.Method);
+ }
+
+ return true;
+}
+
+
+HRESULT CDatabase::LoadCatalog(const CFork &fork, const CObjectVector<CIdExtents> *overflowExtentsArray, IInStream *inStream, IArchiveOpenCallback *progress)
+{
+ CByteBuffer buf;
+ RINOK(ReadFile(fork, buf, inStream))
+ const Byte *p = (const Byte *)buf;
+
+ // CNodeDescriptor nodeDesc;
+ // nodeDesc.Parse(p);
+ CHeaderRec hr;
+ RINOK(hr.Parse2(buf))
+
+ CRecordVector<CIdIndexPair> IdToIndexMap;
+
+ const unsigned reserveSize = (unsigned)(Header.NumFolders + 1 + Header.NumFiles);
+
+ const unsigned kBasicRecSize = 0x58;
+ const unsigned kMinRecSize = kBasicRecSize + 10;
+
+ if ((UInt64)reserveSize * kMinRecSize < buf.Size())
+ {
+ Items.ClearAndReserve(reserveSize);
+ Refs.ClearAndReserve(reserveSize);
+ IdToIndexMap.ClearAndReserve(reserveSize);
+ }
+
+ // CaseSensetive = (Header.IsHfsX() && hr.KeyCompareType == 0xBC);
+
+ CByteArr usedBuf(hr.TotalNodes);
+ if (hr.TotalNodes != 0)
+ memset(usedBuf, 0, hr.TotalNodes);
+
+ CFork resFork;
+
+ UInt32 node = hr.FirstLeafNode;
+ UInt32 numFiles = 0;
+ UInt32 numFolders = 0;
+
+ while (node != 0)
+ {
+ if (node >= hr.TotalNodes || usedBuf[node] != 0)
+ return S_FALSE;
+ usedBuf[node] = 1;
+
+ const size_t nodeOffset = (size_t)node << hr.NodeSizeLog;
+ CNodeDescriptor desc;
+ if (!desc.Parse(p + nodeOffset, hr.NodeSizeLog))
+ return S_FALSE;
+ if (desc.Kind != kNodeType_Leaf)
+ return S_FALSE;
+
+ for (unsigned i = 0; i < desc.NumRecords; i++)
+ {
+ const UInt32 nodeSize = (1 << hr.NodeSizeLog);
+ const Byte *r = p + nodeOffset + nodeSize - i * 2;
+ const UInt32 offs = Get16(r - 2);
+ UInt32 recSize = Get16(r - 4) - offs;
+ if (recSize < 6)
+ return S_FALSE;
+
+ r = p + nodeOffset + offs;
+ UInt32 keyLen = Get16(r);
+ UInt32 parentID = Get32(r + 2);
+ if (keyLen < 6 || (keyLen & 1) != 0 || keyLen + 2 > recSize)
+ return S_FALSE;
+ r += 6;
+ recSize -= 6;
+ keyLen -= 6;
+
+ unsigned nameLen = Get16(r);
+ if (nameLen * 2 != (unsigned)keyLen)
+ return S_FALSE;
+ r += 2;
+ recSize -= 2;
+
+ r += nameLen * 2;
+ recSize -= nameLen * 2;
+
+ if (recSize < 2)
+ return S_FALSE;
+ UInt16 type = Get16(r);
+
+ if (type != RECORD_TYPE_FOLDER &&
+ type != RECORD_TYPE_FILE)
+ continue;
+
+ if (recSize < kBasicRecSize)
+ return S_FALSE;
+
+ CItem &item = Items.AddNew();
+ item.ParentID = parentID;
+ item.Type = type;
+ // item.Flags = Get16(r + 2);
+ // item.Valence = Get32(r + 4);
+ item.ID = Get32(r + 8);
+ {
+ const Byte *name = r - (nameLen * 2);
+ LoadName(name, nameLen, item.Name);
+ if (item.Name.Len() <= 1)
+ {
+ if (item.Name.IsEmpty() && nameLen == 21)
+ {
+ if (GetUi32(name) == 0 &&
+ GetUi32(name + 4) == 0 &&
+ IsNameEqualTo(name + 8, "HFS+ Private Data"))
+ {
+ // it's folder for "Hard Links" files
+ item.Name = "[HFS+ Private Data]";
+ }
+ }
+
+ // Some dmg files have ' ' folder item.
+ if (item.Name.IsEmpty() || item.Name[0] == L' ')
+ item.Name = "[]";
+ }
+ }
+
+ item.CTime = Get32(r + 0xC);
+ item.MTime = Get32(r + 0x10);
+ item.AttrMTime = Get32(r + 0x14);
+ item.ATime = Get32(r + 0x18);
+ // item.BackupDate = Get32(r + 0x1C);
+
+ /*
+ item.OwnerID = Get32(r + 0x20);
+ item.GroupID = Get32(r + 0x24);
+ item.AdminFlags = r[0x28];
+ item.OwnerFlags = r[0x29];
+ */
+ item.FileMode = Get16(r + 0x2A);
+ /*
+ item.special.iNodeNum = Get16(r + 0x2C); // or .linkCount
+ item.FileType = Get32(r + 0x30);
+ item.FileCreator = Get32(r + 0x34);
+ item.FinderFlags = Get16(r + 0x38);
+ item.Point[0] = Get16(r + 0x3A); // v
+ item.Point[1] = Get16(r + 0x3C); // h
+ */
+
+ // const refIndex = Refs.Size();
+ CIdIndexPair pair;
+ pair.ID = item.ID;
+ pair.Index = Items.Size() - 1;
+ IdToIndexMap.Add(pair);
+
+ recSize -= kBasicRecSize;
+ r += kBasicRecSize;
+ if (item.IsDir())
+ {
+ numFolders++;
+ if (recSize != 0)
+ return S_FALSE;
+ }
+ else
+ {
+ numFiles++;
+ if (recSize != kForkRecSize * 2)
+ return S_FALSE;
+
+ item.DataFork.Parse(r);
+
+ if (!item.DataFork.UpgradeAndTest(overflowExtentsArray[0], item.ID, Header.BlockSizeLog))
+ HeadersError = true;
+
+ item.ResourceFork.Parse(r + kForkRecSize);
+ if (!item.ResourceFork.IsEmpty())
+ {
+ if (!item.ResourceFork.UpgradeAndTest(overflowExtentsArray[1], item.ID, Header.BlockSizeLog))
+ HeadersError = true;
+ // ThereAreAltStreams = true;
+ }
+ }
+ if (progress && (Items.Size() & 0xFFF) == 0)
+ {
+ const UInt64 numItems = Items.Size();
+ RINOK(progress->SetCompleted(&numItems, NULL))
+ }
+ }
+ node = desc.fLink;
+ }
+
+ if (Header.NumFiles != numFiles ||
+ Header.NumFolders + 1 != numFolders)
+ HeadersError = true;
+
+ IdToIndexMap.Sort2();
+ {
+ for (unsigned i = 1; i < IdToIndexMap.Size(); i++)
+ if (IdToIndexMap[i - 1].ID == IdToIndexMap[i].ID)
+ return S_FALSE;
+ }
+
+
+ CBoolArr skipAttr(Attrs.Size());
+ {
+ for (unsigned i = 0; i < Attrs.Size(); i++)
+ skipAttr[i] = false;
+ }
+
+ {
+ FOR_VECTOR (i, Attrs)
+ {
+ const CAttr &attr = Attrs[i];
+
+ const int itemIndex = FindItemIndex(IdToIndexMap, attr.ID);
+ if (itemIndex < 0)
+ {
+ HeadersError = true;
+ continue;
+ }
+
+ if (attr.Name.IsEqualTo("com.apple.decmpfs"))
+ {
+ if (!Parse_decmpgfs(i, Items[itemIndex], skipAttr[i]))
+ HeadersError = true;
+ }
+ }
+ }
+
+ IdToIndexMap.ClearAndReserve(Items.Size());
+
+ {
+ FOR_VECTOR (i, Items)
+ {
+ const CItem &item = Items[i];
+
+ CIdIndexPair pair;
+ pair.ID = item.ID;
+ pair.Index = Refs.Size();
+ IdToIndexMap.Add(pair);
+
+ CRef ref;
+ ref.ItemIndex = i;
+ Refs.Add(ref);
+
+ #ifdef HFS_SHOW_ALT_STREAMS
+
+ if (item.ResourceFork.IsEmpty())
+ continue;
+ if (item.CompressHeader.IsSupported && item.CompressHeader.IsMethod_Resource())
+ continue;
+
+ ThereAreAltStreams = true;
+ ref.AttrIndex = kAttrIndex_Resource;
+ ref.Parent = (int)(Refs.Size() - 1);
+ Refs.Add(ref);
+
+ #endif
+ }
+ }
+
+ IdToIndexMap.Sort2();
+
+ {
+ FOR_VECTOR (i, Refs)
+ {
+ CRef &ref = Refs[i];
+ if (ref.IsResource())
+ continue;
+ const CItem &item = Items[ref.ItemIndex];
+ ref.Parent = FindItemIndex(IdToIndexMap, item.ParentID);
+ if (ref.Parent >= 0)
+ {
+ if (!Items[Refs[ref.Parent].ItemIndex].IsDir())
+ {
+ ref.Parent = -1;
+ HeadersError = true;
+ }
+ }
+ }
+ }
+
+ #ifdef HFS_SHOW_ALT_STREAMS
+ {
+ FOR_VECTOR (i, Attrs)
+ {
+ if (skipAttr[i])
+ continue;
+ const CAttr &attr = Attrs[i];
+
+ const int refIndex = FindItemIndex(IdToIndexMap, attr.ID);
+ if (refIndex < 0)
+ {
+ HeadersError = true;
+ continue;
+ }
+
+ ThereAreAltStreams = true;
+
+ CRef ref;
+ ref.AttrIndex = (int)i;
+ ref.Parent = refIndex;
+ ref.ItemIndex = Refs[refIndex].ItemIndex;
+ Refs.Add(ref);
+ }
+ }
+ #endif
+
+ return S_OK;
+}
+
+static const unsigned kHeaderPadSize = (1 << 10);
+static const unsigned kMainHeaderSize = 512;
+static const unsigned kHfsHeaderSize = kHeaderPadSize + kMainHeaderSize;
+
+API_FUNC_static_IsArc IsArc_HFS(const Byte *p, size_t size)
+{
+ if (size < kHfsHeaderSize)
+ return k_IsArc_Res_NEED_MORE;
+ p += kHeaderPadSize;
+ if (p[0] == 'B' && p[1] == 'D')
+ {
+ if (p[0x7C] != 'H' || p[0x7C + 1] != '+')
+ return k_IsArc_Res_NO;
+ }
+ else
+ {
+ if (p[0] != 'H' || (p[1] != '+' && p[1] != 'X'))
+ return k_IsArc_Res_NO;
+ UInt32 version = Get16(p + 2);
+ if (version < 4 || version > 5)
+ return k_IsArc_Res_NO;
+ }
+ return k_IsArc_Res_YES;
+}
+}
+
+HRESULT CDatabase::Open2(IInStream *inStream, IArchiveOpenCallback *progress)
+{
+ Clear();
+ Byte buf[kHfsHeaderSize];
+ RINOK(ReadStream_FALSE(inStream, buf, kHfsHeaderSize))
+ {
+ for (unsigned i = 0; i < kHeaderPadSize; i++)
+ if (buf[i] != 0)
+ return S_FALSE;
+ }
+ const Byte *p = buf + kHeaderPadSize;
+ CVolHeader &h = Header;
+
+ h.Header[0] = p[0];
+ h.Header[1] = p[1];
+
+ if (p[0] == 'B' && p[1] == 'D')
+ {
+ /*
+ It's header for old HFS format.
+ We don't support old HFS format, but we support
+ special HFS volume that contains embedded HFS+ volume
+ */
+
+ if (p[0x7C] != 'H' || p[0x7C + 1] != '+')
+ return S_FALSE;
+
+ /*
+ h.CTime = Get32(p + 0x2);
+ h.MTime = Get32(p + 0x6);
+
+ h.NumFiles = Get32(p + 0x54);
+ h.NumFolders = Get32(p + 0x58);
+
+ if (h.NumFolders > ((UInt32)1 << 29) ||
+ h.NumFiles > ((UInt32)1 << 30))
+ return S_FALSE;
+ if (progress)
+ {
+ UInt64 numFiles = (UInt64)h.NumFiles + h.NumFolders + 1;
+ RINOK(progress->SetTotal(&numFiles, NULL))
+ }
+ h.NumFreeBlocks = Get16(p + 0x22);
+ */
+
+ UInt32 blockSize = Get32(p + 0x14);
+
+ {
+ unsigned i;
+ for (i = 9; ((UInt32)1 << i) != blockSize; i++)
+ if (i == 31)
+ return S_FALSE;
+ h.BlockSizeLog = i;
+ }
+
+ h.NumBlocks = Get16(p + 0x12);
+ /*
+ we suppose that it has the follwing layout
+ {
+ start block with header
+ [h.NumBlocks]
+ end block with header
+ }
+ */
+ PhySize2 = ((UInt64)h.NumBlocks + 2) << h.BlockSizeLog;
+
+ UInt32 startBlock = Get16(p + 0x7C + 2);
+ UInt32 blockCount = Get16(p + 0x7C + 4);
+ SpecOffset = (UInt64)(1 + startBlock) << h.BlockSizeLog;
+ UInt64 phy = SpecOffset + ((UInt64)blockCount << h.BlockSizeLog);
+ if (PhySize2 < phy)
+ PhySize2 = phy;
+ RINOK(InStream_SeekSet(inStream, SpecOffset))
+ RINOK(ReadStream_FALSE(inStream, buf, kHfsHeaderSize))
+ }
+
+ if (p[0] != 'H' || (p[1] != '+' && p[1] != 'X'))
+ return S_FALSE;
+ h.Version = Get16(p + 2);
+ if (h.Version < 4 || h.Version > 5)
+ return S_FALSE;
+
+ // h.Attr = Get32(p + 4);
+ // h.LastMountedVersion = Get32(p + 8);
+ // h.JournalInfoBlock = Get32(p + 0xC);
+
+ h.CTime = Get32(p + 0x10);
+ h.MTime = Get32(p + 0x14);
+ // h.BackupTime = Get32(p + 0x18);
+ // h.CheckedTime = Get32(p + 0x1C);
+
+ h.NumFiles = Get32(p + 0x20);
+ h.NumFolders = Get32(p + 0x24);
+
+ if (h.NumFolders > ((UInt32)1 << 29) ||
+ h.NumFiles > ((UInt32)1 << 30))
+ return S_FALSE;
+
+ RINOK(InStream_GetSize_SeekToEnd(inStream, ArcFileSize))
+
+ if (progress)
+ {
+ const UInt64 numFiles = (UInt64)h.NumFiles + h.NumFolders + 1;
+ RINOK(progress->SetTotal(&numFiles, NULL))
+ }
+
+ UInt32 blockSize = Get32(p + 0x28);
+
+ {
+ unsigned i;
+ for (i = 9; ((UInt32)1 << i) != blockSize; i++)
+ if (i == 31)
+ return S_FALSE;
+ h.BlockSizeLog = i;
+ }
+
+ h.NumBlocks = Get32(p + 0x2C);
+ h.NumFreeBlocks = Get32(p + 0x30);
+
+ /*
+ h.NextCalatlogNodeID = Get32(p + 0x40);
+ h.WriteCount = Get32(p + 0x44);
+ for (i = 0; i < 6; i++)
+ h.FinderInfo[i] = Get32(p + 0x50 + i * 4);
+ h.VolID = Get64(p + 0x68);
+ */
+
+ ResFileName = kResFileName;
+
+ CFork extentsFork, catalogFork, attrFork;
+ // allocationFork.Parse(p + 0x70 + 0x50 * 0);
+ extentsFork.Parse(p + 0x70 + 0x50 * 1);
+ catalogFork.Parse(p + 0x70 + 0x50 * 2);
+ attrFork.Parse (p + 0x70 + 0x50 * 3);
+ // startupFork.Parse(p + 0x70 + 0x50 * 4);
+
+ CObjectVector<CIdExtents> overflowExtents[2];
+ if (!extentsFork.IsOk(Header.BlockSizeLog))
+ HeadersError = true;
+ else
+ {
+ HRESULT res = LoadExtentFile(extentsFork, inStream, overflowExtents);
+ if (res == S_FALSE)
+ HeadersError = true;
+ else if (res != S_OK)
+ return res;
+ }
+
+ if (!catalogFork.UpgradeAndTest(overflowExtents[0], kHfsID_CatalogFile, Header.BlockSizeLog))
+ return S_FALSE;
+
+ if (!attrFork.UpgradeAndTest(overflowExtents[0], kHfsID_AttributesFile, Header.BlockSizeLog))
+ HeadersError = true;
+ else
+ {
+ if (attrFork.Size != 0)
+ RINOK(LoadAttrs(attrFork, inStream, progress))
+ }
+
+ RINOK(LoadCatalog(catalogFork, overflowExtents, inStream, progress))
+
+ PhySize = Header.GetPhySize();
+ return S_OK;
+}
+
+
+
+Z7_class_CHandler_final:
+ public IInArchive,
+ public IArchiveGetRawProps,
+ public IInArchiveGetStream,
+ public CMyUnknownImp,
+ public CDatabase
+{
+ Z7_IFACES_IMP_UNK_3(
+ IInArchive,
+ IArchiveGetRawProps,
+ IInArchiveGetStream)
+
+ CMyComPtr<IInStream> _stream;
+ HRESULT GetForkStream(const CFork &fork, ISequentialInStream **stream);
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidCTime,
+ kpidMTime,
+ kpidATime,
+ kpidChangeTime,
+ kpidPosixAttrib,
+ /*
+ kpidUserId,
+ kpidGroupId,
+ */
+#ifdef HFS_SHOW_ALT_STREAMS
+ kpidIsAltStream,
+#endif
+ kpidMethod
+};
+
+static const Byte kArcProps[] =
+{
+ kpidMethod,
+ kpidCharacts,
+ kpidClusterSize,
+ kpidFreeSpace,
+ kpidCTime,
+ kpidMTime
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static void HfsTimeToProp(UInt32 hfsTime, NWindows::NCOM::CPropVariant &prop)
+{
+ if (hfsTime == 0)
+ return;
+ FILETIME ft;
+ HfsTimeToFileTime(hfsTime, ft);
+ prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Base);
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidExtension: prop = Header.IsHfsX() ? "hfsx" : "hfs"; break;
+ case kpidMethod: prop = Header.IsHfsX() ? "HFSX" : "HFS+"; break;
+ case kpidCharacts: MethodsMaskToProp(MethodsMask, prop); break;
+ case kpidPhySize:
+ {
+ UInt64 v = SpecOffset + PhySize;
+ if (v < PhySize2)
+ v = PhySize2;
+ prop = v;
+ break;
+ }
+ case kpidClusterSize: prop = (UInt32)1 << Header.BlockSizeLog; break;
+ case kpidFreeSpace: prop = (UInt64)Header.GetFreeSize(); break;
+ case kpidMTime: HfsTimeToProp(Header.MTime, prop); break;
+ case kpidCTime:
+ {
+ if (Header.CTime != 0)
+ {
+ FILETIME localFt, ft;
+ HfsTimeToFileTime(Header.CTime, localFt);
+ if (LocalFileTimeToFileTime(&localFt, &ft))
+ prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Base);
+ }
+ break;
+ }
+ case kpidIsTree: prop = true; break;
+ case kpidErrorFlags:
+ {
+ UInt32 flags = 0;
+ if (HeadersError) flags |= kpv_ErrorFlags_HeadersError;
+ if (UnsupportedFeature) flags |= kpv_ErrorFlags_UnsupportedFeature;
+ if (flags != 0)
+ prop = flags;
+ break;
+ }
+ case kpidIsAltStream: prop = ThereAreAltStreams; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps))
+{
+ *numProps = 0;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID))
+{
+ *name = NULL;
+ *propID = 0;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType))
+{
+ const CRef &ref = Refs[index];
+ *parentType = ref.IsAltStream() ?
+ NParentType::kAltStream :
+ NParentType::kDir;
+ *parent = (UInt32)(Int32)ref.Parent;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
+{
+ *data = NULL;
+ *dataSize = 0;
+ *propType = 0;
+ #ifdef MY_CPU_LE
+ if (propID == kpidName)
+ {
+ const CRef &ref = Refs[index];
+ const UString *s;
+ if (ref.IsResource())
+ s = &ResFileName;
+ else if (ref.AttrIndex >= 0)
+ s = &Attrs[ref.AttrIndex].Name;
+ else
+ s = &Items[ref.ItemIndex].Name;
+ *data = (const wchar_t *)(*s);
+ *dataSize = (s->Len() + 1) * (UInt32)sizeof(wchar_t);
+ *propType = PROP_DATA_TYPE_wchar_t_PTR_Z_LE;
+ return S_OK;
+ }
+ #else
+ UNUSED_VAR(index);
+ UNUSED_VAR(propID);
+ #endif
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CRef &ref = Refs[index];
+ const CItem &item = Items[ref.ItemIndex];
+ switch (propID)
+ {
+ case kpidPath: GetItemPath(index, prop); break;
+ case kpidName:
+ {
+ const UString *s;
+ if (ref.IsResource())
+ s = &ResFileName;
+ else if (ref.AttrIndex >= 0)
+ s = &Attrs[ref.AttrIndex].Name;
+ else
+ s = &item.Name;
+ prop = *s;
+ break;
+ }
+ case kpidPackSize:
+ {
+ UInt64 size;
+ if (ref.AttrIndex >= 0)
+ size = Attrs[ref.AttrIndex].GetSize();
+ else if (ref.IsResource())
+ size = (UInt64)item.ResourceFork.NumBlocks << Header.BlockSizeLog;
+ else if (item.IsDir())
+ break;
+ else if (item.CompressHeader.IsCorrect)
+ {
+ if (item.CompressHeader.IsMethod_Resource())
+ size = (UInt64)item.ResourceFork.NumBlocks << Header.BlockSizeLog;
+ else if (item.decmpfs_AttrIndex >= 0)
+ {
+ // size = item.PackSize;
+ const CAttr &attr = Attrs[item.decmpfs_AttrIndex];
+ size = attr.Data.Size() - item.CompressHeader.DataPos;
+ }
+ else
+ size = 0;
+ }
+ else
+ size = (UInt64)item.DataFork.NumBlocks << Header.BlockSizeLog;
+ prop = size;
+ break;
+ }
+ case kpidSize:
+ {
+ UInt64 size;
+ if (ref.AttrIndex >= 0)
+ size = Attrs[ref.AttrIndex].GetSize();
+ else if (ref.IsResource())
+ size = item.ResourceFork.Size;
+ else if (item.IsDir())
+ break;
+ else if (item.CompressHeader.IsCorrect)
+ size = item.CompressHeader.UnpackSize;
+ else
+ size = item.DataFork.Size;
+ prop = size;
+ break;
+ }
+ case kpidIsDir: prop = (ref.IsItem() && item.IsDir()); break;
+ case kpidIsAltStream: prop = ref.IsAltStream(); break;
+ case kpidCTime: HfsTimeToProp(item.CTime, prop); break;
+ case kpidMTime: HfsTimeToProp(item.MTime, prop); break;
+ case kpidATime: HfsTimeToProp(item.ATime, prop); break;
+ case kpidChangeTime: HfsTimeToProp(item.AttrMTime, prop); break;
+ case kpidPosixAttrib: if (ref.IsItem()) prop = (UInt32)item.FileMode; break;
+ /*
+ case kpidUserId: prop = (UInt32)item.OwnerID; break;
+ case kpidGroupId: prop = (UInt32)item.GroupID; break;
+ */
+
+ case kpidMethod:
+ if (ref.IsItem())
+ item.CompressHeader.MethodToProp(prop);
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(Open2(inStream, callback))
+ _stream = inStream;
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _stream.Release();
+ Clear();
+ return S_OK;
+}
+
+static const UInt32 kCompressionBlockSize = 1 << 16;
+
+CDecoder::CDecoder()
+{
+ _zlibDecoderSpec = new NCompress::NZlib::CDecoder();
+ _zlibDecoder = _zlibDecoderSpec;
+
+ _lzfseDecoderSpec = new NCompress::NLzfse::CDecoder();
+ _lzfseDecoder = _lzfseDecoderSpec;
+ _lzfseDecoderSpec->LzvnMode = true;
+}
+
+HRESULT CDecoder::ExtractResourceFork_ZLIB(
+ ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ UInt64 forkSize, UInt64 unpackSize,
+ UInt64 progressStart, IArchiveExtractCallback *extractCallback)
+{
+ const unsigned kHeaderSize = 0x100 + 8;
+
+ const size_t kBufSize = kCompressionBlockSize;
+ _buf.Alloc(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header
+
+ RINOK(ReadStream_FALSE(inStream, _buf, kHeaderSize))
+ Byte *buf = _buf;
+ const UInt32 dataPos = Get32(buf);
+ const UInt32 mapPos = Get32(buf + 4);
+ const UInt32 dataSize = Get32(buf + 8);
+ const UInt32 mapSize = Get32(buf + 12);
+
+ const UInt32 kResMapSize = 50;
+
+ if (mapSize != kResMapSize
+ || dataPos > mapPos
+ || dataSize != mapPos - dataPos
+ || mapSize > forkSize
+ || mapPos != forkSize - mapSize)
+ return S_FALSE;
+
+ const UInt32 dataSize2 = Get32(buf + 0x100);
+ if (4 + dataSize2 != dataSize
+ || dataSize2 < 8
+ || dataSize2 > dataSize)
+ return S_FALSE;
+
+ const UInt32 numBlocks = GetUi32(buf + 0x100 + 4);
+ if (((dataSize2 - 4) >> 3) < numBlocks)
+ return S_FALSE;
+ {
+ const UInt64 up = unpackSize + kCompressionBlockSize - 1;
+ if (up < unpackSize || up / kCompressionBlockSize != numBlocks)
+ return S_FALSE;
+ }
+
+ const UInt32 tableSize = (numBlocks << 3);
+
+ _tableBuf.AllocAtLeast(tableSize);
+
+ RINOK(ReadStream_FALSE(inStream, _tableBuf, tableSize))
+ const Byte *tableBuf = _tableBuf;
+
+ UInt32 prev = 4 + tableSize;
+
+ UInt32 i;
+ for (i = 0; i < numBlocks; i++)
+ {
+ const UInt32 offs = GetUi32(tableBuf + i * 8);
+ const UInt32 size = GetUi32(tableBuf + i * 8 + 4);
+ if (size == 0
+ || prev != offs
+ || offs > dataSize2
+ || size > dataSize2 - offs)
+ return S_FALSE;
+ prev = offs + size;
+ }
+
+ if (prev != dataSize2)
+ return S_FALSE;
+
+ CBufInStream *bufInStreamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec;
+
+ // bool padError = false;
+ UInt64 outPos = 0;
+
+ for (i = 0; i < numBlocks; i++)
+ {
+ const UInt64 rem = unpackSize - outPos;
+ if (rem == 0)
+ return S_FALSE;
+ UInt32 blockSize = kCompressionBlockSize;
+ if (rem < kCompressionBlockSize)
+ blockSize = (UInt32)rem;
+
+ const UInt32 size = GetUi32(tableBuf + i * 8 + 4);
+
+ if (size > kCompressionBlockSize + 1)
+ return S_FALSE;
+
+ RINOK(ReadStream_FALSE(inStream, buf, size))
+
+ if ((buf[0] & 0xF) == 0xF)
+ {
+ // (buf[0] = 0xff) is marker of uncompressed block in APFS
+ // that code was not tested in HFS
+ if (size - 1 != blockSize)
+ return S_FALSE;
+
+ if (outStream)
+ {
+ RINOK(WriteStream(outStream, buf + 1, blockSize))
+ }
+ }
+ else
+ {
+ const UInt64 blockSize64 = blockSize;
+ bufInStreamSpec->Init(buf, size);
+ RINOK(_zlibDecoder->Code(bufInStream, outStream, NULL, &blockSize64, NULL))
+ if (_zlibDecoderSpec->GetOutputProcessedSize() != blockSize)
+ return S_FALSE;
+ const UInt64 inSize = _zlibDecoderSpec->GetInputProcessedSize();
+ if (inSize != size)
+ {
+ if (inSize > size)
+ return S_FALSE;
+ // apfs file can contain junk (non-zeros) after data block.
+ /*
+ if (!padError)
+ {
+ const Byte *p = buf + (UInt32)inSize;
+ const Byte *e = p + (size - (UInt32)inSize);
+ do
+ {
+ if (*p != 0)
+ {
+ padError = true;
+ break;
+ }
+ }
+ while (++p != e);
+ }
+ */
+ }
+ }
+
+ outPos += blockSize;
+ if ((i & 0xFF) == 0)
+ {
+ const UInt64 progressPos = progressStart + outPos;
+ RINOK(extractCallback->SetCompleted(&progressPos))
+ }
+ }
+
+ if (outPos != unpackSize)
+ return S_FALSE;
+
+ // if (padError) return S_FALSE;
+
+ /* We check Resource Map
+ Are there HFS files with another values in Resource Map ??? */
+
+ RINOK(ReadStream_FALSE(inStream, buf, mapSize))
+ const UInt32 types = Get16(buf + 24);
+ const UInt32 names = Get16(buf + 26);
+ const UInt32 numTypes = Get16(buf + 28);
+ if (numTypes != 0 || types != 28 || names != kResMapSize)
+ return S_FALSE;
+ const UInt32 resType = Get32(buf + 30);
+ const UInt32 numResources = Get16(buf + 34);
+ const UInt32 resListOffset = Get16(buf + 36);
+ if (resType != 0x636D7066) // cmpf
+ return S_FALSE;
+ if (numResources != 0 || resListOffset != 10)
+ return S_FALSE;
+
+ const UInt32 entryId = Get16(buf + 38);
+ const UInt32 nameOffset = Get16(buf + 40);
+ // Byte attrib = buf[42];
+ const UInt32 resourceOffset = Get32(buf + 42) & 0xFFFFFF;
+ if (entryId != 1 || nameOffset != 0xFFFF || resourceOffset != 0)
+ return S_FALSE;
+
+ return S_OK;
+}
+
+
+
+HRESULT CDecoder::ExtractResourceFork_LZFSE(
+ ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ UInt64 forkSize, UInt64 unpackSize,
+ UInt64 progressStart, IArchiveExtractCallback *extractCallback)
+{
+ const UInt32 kNumBlocksMax = (UInt32)1 << 29;
+ if (unpackSize >= (UInt64)kNumBlocksMax * kCompressionBlockSize)
+ return S_FALSE;
+ const UInt32 numBlocks = (UInt32)((unpackSize + kCompressionBlockSize - 1) / kCompressionBlockSize);
+ const UInt32 numBlocks2 = numBlocks + 1;
+ const UInt32 tableSize = (numBlocks2 << 2);
+ if (tableSize > forkSize)
+ return S_FALSE;
+ _tableBuf.AllocAtLeast(tableSize);
+ RINOK(ReadStream_FALSE(inStream, _tableBuf, tableSize))
+ const Byte *tableBuf = _tableBuf;
+
+ {
+ UInt32 prev = GetUi32(tableBuf);
+ if (prev != tableSize)
+ return S_FALSE;
+ for (UInt32 i = 1; i < numBlocks2; i++)
+ {
+ const UInt32 offs = GetUi32(tableBuf + i * 4);
+ if (offs <= prev)
+ return S_FALSE;
+ prev = offs;
+ }
+ if (prev != forkSize)
+ return S_FALSE;
+ }
+
+ const size_t kBufSize = kCompressionBlockSize;
+ _buf.Alloc(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header
+
+ CBufInStream *bufInStreamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec;
+
+ UInt64 outPos = 0;
+
+ for (UInt32 i = 0; i < numBlocks; i++)
+ {
+ const UInt64 rem = unpackSize - outPos;
+ if (rem == 0)
+ return S_FALSE;
+ UInt32 blockSize = kCompressionBlockSize;
+ if (rem < kCompressionBlockSize)
+ blockSize = (UInt32)rem;
+
+ const UInt32 size =
+ GetUi32(tableBuf + i * 4 + 4) -
+ GetUi32(tableBuf + i * 4);
+
+ if (size > kCompressionBlockSize + 1)
+ return S_FALSE;
+
+ RINOK(ReadStream_FALSE(inStream, _buf, size))
+ const Byte *buf = _buf;
+
+ if (buf[0] == k_LZVN_Uncompressed_Marker)
+ {
+ if (size - 1 != blockSize)
+ return S_FALSE;
+ if (outStream)
+ {
+ RINOK(WriteStream(outStream, buf + 1, blockSize))
+ }
+ }
+ else
+ {
+ const UInt64 blockSize64 = blockSize;
+ const UInt64 packSize64 = size;
+ bufInStreamSpec->Init(buf, size);
+ RINOK(_lzfseDecoder->Code(bufInStream, outStream, &packSize64, &blockSize64, NULL))
+ // in/out sizes were checked in Code()
+ }
+
+ outPos += blockSize;
+ if ((i & 0xFF) == 0)
+ {
+ const UInt64 progressPos = progressStart + outPos;
+ RINOK(extractCallback->SetCompleted(&progressPos))
+ }
+ }
+
+ return S_OK;
+}
+
+
+/*
+static UInt32 GetUi24(const Byte *p)
+{
+ return p[0] + ((UInt32)p[1] << 8) + ((UInt32)p[2] << 24);
+}
+
+HRESULT CDecoder::ExtractResourceFork_ZBM(
+ ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ UInt64 forkSize, UInt64 unpackSize,
+ UInt64 progressStart, IArchiveExtractCallback *extractCallback)
+{
+ const UInt32 kNumBlocksMax = (UInt32)1 << 29;
+ if (unpackSize >= (UInt64)kNumBlocksMax * kCompressionBlockSize)
+ return S_FALSE;
+ const UInt32 numBlocks = (UInt32)((unpackSize + kCompressionBlockSize - 1) / kCompressionBlockSize);
+ const UInt32 numBlocks2 = numBlocks + 1;
+ const UInt32 tableSize = (numBlocks2 << 2);
+ if (tableSize > forkSize)
+ return S_FALSE;
+ _tableBuf.AllocAtLeast(tableSize);
+ RINOK(ReadStream_FALSE(inStream, _tableBuf, tableSize));
+ const Byte *tableBuf = _tableBuf;
+
+ {
+ UInt32 prev = GetUi32(tableBuf);
+ if (prev != tableSize)
+ return S_FALSE;
+ for (UInt32 i = 1; i < numBlocks2; i++)
+ {
+ const UInt32 offs = GetUi32(tableBuf + i * 4);
+ if (offs <= prev)
+ return S_FALSE;
+ prev = offs;
+ }
+ if (prev != forkSize)
+ return S_FALSE;
+ }
+
+ const size_t kBufSize = kCompressionBlockSize;
+ _buf.Alloc(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header
+
+ CBufInStream *bufInStreamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec;
+
+ UInt64 outPos = 0;
+
+ for (UInt32 i = 0; i < numBlocks; i++)
+ {
+ const UInt64 rem = unpackSize - outPos;
+ if (rem == 0)
+ return S_FALSE;
+ UInt32 blockSize = kCompressionBlockSize;
+ if (rem < kCompressionBlockSize)
+ blockSize = (UInt32)rem;
+
+ const UInt32 size =
+ GetUi32(tableBuf + i * 4 + 4) -
+ GetUi32(tableBuf + i * 4);
+
+ // if (size > kCompressionBlockSize + 1)
+ if (size > blockSize + 1)
+ return S_FALSE; // we don't expect it, because encode will use uncompressed chunk
+
+ RINOK(ReadStream_FALSE(inStream, _buf, size));
+ const Byte *buf = _buf;
+
+ // (size != 0)
+ // if (size == 0) return S_FALSE;
+
+ if (buf[0] == 0xFF) // uncompressed marker
+ {
+ if (size != blockSize + 1)
+ return S_FALSE;
+ if (outStream)
+ {
+ RINOK(WriteStream(outStream, buf + 1, blockSize));
+ }
+ }
+ else
+ {
+ if (size < 4)
+ return S_FALSE;
+ if (buf[0] != 'Z' ||
+ buf[1] != 'B' ||
+ buf[2] != 'M' ||
+ buf[3] != 9)
+ return S_FALSE;
+ // for debug:
+ unsigned packPos = 4;
+ unsigned unpackPos = 0;
+ unsigned packRem = size - packPos;
+ for (;;)
+ {
+ if (packRem < 6)
+ return S_FALSE;
+ const UInt32 packSize = GetUi24(buf + packPos);
+ const UInt32 chunkUnpackSize = GetUi24(buf + packPos + 3);
+ if (packSize < 6)
+ return S_FALSE;
+ if (packSize > packRem)
+ return S_FALSE;
+ if (chunkUnpackSize > blockSize - unpackPos)
+ return S_FALSE;
+ packPos += packSize;
+ packRem -= packSize;
+ unpackPos += chunkUnpackSize;
+ if (packSize == 6)
+ {
+ if (chunkUnpackSize != 0)
+ return S_FALSE;
+ break;
+ }
+ if (packSize >= chunkUnpackSize + 6)
+ {
+ if (packSize > chunkUnpackSize + 6)
+ return S_FALSE;
+ // uncompressed chunk;
+ }
+ else
+ {
+ // compressed chunk
+ const Byte *t = buf + packPos - packSize + 6;
+ UInt32 r = packSize - 6;
+ if (r < 9)
+ return S_FALSE;
+ const UInt32 v0 = GetUi24(t);
+ const UInt32 v1 = GetUi24(t + 3);
+ const UInt32 v2 = GetUi24(t + 6);
+ if (v0 > v1 || v1 > v2 || v2 > packSize)
+ return S_FALSE;
+ // here we need the code that will decompress ZBM chunk
+ }
+ }
+
+ if (unpackPos != blockSize)
+ return S_FALSE;
+
+ UInt32 size1 = size;
+ if (size1 > kCompressionBlockSize)
+ {
+ size1 = kCompressionBlockSize;
+ // return S_FALSE;
+ }
+ if (outStream)
+ {
+ RINOK(WriteStream(outStream, buf, size1))
+
+ const UInt32 kTempSize = 1 << 16;
+ Byte temp[kTempSize];
+ memset(temp, 0, kTempSize);
+
+ for (UInt32 k = size1; k < kCompressionBlockSize; k++)
+ {
+ UInt32 cur = kCompressionBlockSize - k;
+ if (cur > kTempSize)
+ cur = kTempSize;
+ RINOK(WriteStream(outStream, temp, cur))
+ k += cur;
+ }
+ }
+
+ // const UInt64 blockSize64 = blockSize;
+ // const UInt64 packSize64 = size;
+ // bufInStreamSpec->Init(buf, size);
+ // RINOK(_zbmDecoderSpec->Code(bufInStream, outStream, &packSize64, &blockSize64, NULL));
+ // in/out sizes were checked in Code()
+ }
+
+ outPos += blockSize;
+ if ((i & 0xFF) == 0)
+ {
+ const UInt64 progressPos = progressStart + outPos;
+ RINOK(extractCallback->SetCompleted(&progressPos));
+ }
+ }
+
+ return S_OK;
+}
+*/
+
+HRESULT CDecoder::Extract(
+ ISequentialInStream *inStreamFork, ISequentialOutStream *realOutStream,
+ UInt64 forkSize,
+ const CCompressHeader &compressHeader,
+ const CByteBuffer *data,
+ UInt64 progressStart, IArchiveExtractCallback *extractCallback,
+ int &opRes)
+{
+ opRes = NExtract::NOperationResult::kDataError;
+
+ if (compressHeader.IsMethod_Uncompressed_Inline())
+ {
+ const size_t packSize = data->Size() - compressHeader.DataPos;
+ if (realOutStream)
+ {
+ RINOK(WriteStream(realOutStream, *data + compressHeader.DataPos, packSize))
+ }
+ opRes = NExtract::NOperationResult::kOK;
+ return S_OK;
+ }
+
+ if (compressHeader.Method == kMethod_ZLIB_ATTR ||
+ compressHeader.Method == kMethod_LZVN_ATTR)
+ {
+ CBufInStream *bufInStreamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec;
+ const size_t packSize = data->Size() - compressHeader.DataPos;
+ bufInStreamSpec->Init(*data + compressHeader.DataPos, packSize);
+
+ if (compressHeader.Method == kMethod_ZLIB_ATTR)
+ {
+ const HRESULT hres = _zlibDecoder->Code(bufInStream, realOutStream,
+ NULL, &compressHeader.UnpackSize, NULL);
+ if (hres == S_OK)
+ if (_zlibDecoderSpec->GetOutputProcessedSize() == compressHeader.UnpackSize
+ && _zlibDecoderSpec->GetInputProcessedSize() == packSize)
+ opRes = NExtract::NOperationResult::kOK;
+ return hres;
+ }
+ {
+ const UInt64 packSize64 = packSize;
+ const HRESULT hres = _lzfseDecoder->Code(bufInStream, realOutStream,
+ &packSize64, &compressHeader.UnpackSize, NULL);
+ if (hres == S_OK)
+ {
+ // in/out sizes were checked in Code()
+ opRes = NExtract::NOperationResult::kOK;
+ }
+ return hres;
+ }
+ }
+
+ HRESULT hres;
+ if (compressHeader.Method == NHfs::kMethod_ZLIB_RSRC)
+ {
+ hres = ExtractResourceFork_ZLIB(
+ inStreamFork, realOutStream,
+ forkSize, compressHeader.UnpackSize,
+ progressStart, extractCallback);
+ }
+ else if (compressHeader.Method == NHfs::kMethod_LZVN_RSRC)
+ {
+ hres = ExtractResourceFork_LZFSE(
+ inStreamFork, realOutStream,
+ forkSize, compressHeader.UnpackSize,
+ progressStart, extractCallback);
+ }
+ /*
+ else if (compressHeader.Method == NHfs::kMethod_ZBM_RSRC)
+ {
+ hres = ExtractResourceFork_ZBM(
+ inStreamFork, realOutStream,
+ forkSize, compressHeader.UnpackSize,
+ progressStart, extractCallback);
+ }
+ */
+ else
+ {
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ hres = S_FALSE;
+ }
+
+ if (hres == S_OK)
+ opRes = NExtract::NOperationResult::kOK;
+ return hres;
+}
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = Refs.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt32 i;
+ UInt64 totalSize = 0;
+ for (i = 0; i < numItems; i++)
+ {
+ const CRef &ref = Refs[allFilesMode ? i : indices[i]];
+ totalSize += Get_UnpackSize_of_Ref(ref);
+ }
+ RINOK(extractCallback->SetTotal(totalSize))
+
+ UInt64 currentTotalSize = 0, currentItemSize = 0;
+
+ const size_t kBufSize = kCompressionBlockSize;
+ CByteBuffer buf(kBufSize + 0x10); // we need 1 additional bytes for uncompressed chunk header
+
+ CDecoder decoder;
+
+ for (i = 0;; i++, currentTotalSize += currentItemSize)
+ {
+ RINOK(extractCallback->SetCompleted(&currentTotalSize))
+ if (i == numItems)
+ break;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CRef &ref = Refs[index];
+ const CItem &item = Items[ref.ItemIndex];
+ currentItemSize = Get_UnpackSize_of_Ref(ref);
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+ if (ref.IsItem() && item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+ if (!testMode && !realOutStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode))
+
+ UInt64 pos = 0;
+ int opRes = NExtract::NOperationResult::kDataError;
+ const CFork *fork = NULL;
+
+ if (ref.AttrIndex >= 0)
+ {
+ const CAttr &attr = Attrs[ref.AttrIndex];
+ if (attr.Fork_defined && attr.Data.Size() == 0)
+ fork = &attr.Fork;
+ else
+ {
+ opRes = NExtract::NOperationResult::kOK;
+ if (realOutStream)
+ {
+ RINOK(WriteStream(realOutStream,
+ // AttrBuf + attr.Pos, attr.Size
+ attr.Data, attr.Data.Size()
+ ))
+ }
+ }
+ }
+ else if (ref.IsResource())
+ fork = &item.ResourceFork;
+ else if (item.CompressHeader.IsSupported)
+ {
+ CMyComPtr<ISequentialInStream> inStreamFork;
+ UInt64 forkSize = 0;
+ const CByteBuffer *decmpfs_Data = NULL;
+
+ if (item.CompressHeader.IsMethod_Resource())
+ {
+ const CFork &resourceFork = item.ResourceFork;
+ forkSize = resourceFork.Size;
+ GetForkStream(resourceFork, &inStreamFork);
+ }
+ else
+ {
+ const CAttr &attr = Attrs[item.decmpfs_AttrIndex];
+ decmpfs_Data = &attr.Data;
+ }
+
+ if (inStreamFork || decmpfs_Data)
+ {
+ const HRESULT hres = decoder.Extract(
+ inStreamFork, realOutStream,
+ forkSize,
+ item.CompressHeader,
+ decmpfs_Data,
+ currentTotalSize, extractCallback,
+ opRes);
+ if (hres != S_FALSE && hres != S_OK)
+ return hres;
+ }
+ }
+ else if (item.CompressHeader.IsCorrect)
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ else
+ fork = &item.DataFork;
+
+ if (fork)
+ {
+ if (fork->IsOk(Header.BlockSizeLog))
+ {
+ opRes = NExtract::NOperationResult::kOK;
+ unsigned extentIndex;
+ for (extentIndex = 0; extentIndex < fork->Extents.Size(); extentIndex++)
+ {
+ if (opRes != NExtract::NOperationResult::kOK)
+ break;
+ if (fork->Size == pos)
+ break;
+ const CExtent &e = fork->Extents[extentIndex];
+ RINOK(InStream_SeekSet(_stream, SpecOffset + ((UInt64)e.Pos << Header.BlockSizeLog)))
+ UInt64 extentRem = (UInt64)e.NumBlocks << Header.BlockSizeLog;
+ while (extentRem != 0)
+ {
+ const UInt64 rem = fork->Size - pos;
+ if (rem == 0)
+ {
+ // Here we check that there are no extra (empty) blocks in last extent.
+ if (extentRem >= ((UInt64)1 << Header.BlockSizeLog))
+ opRes = NExtract::NOperationResult::kDataError;
+ break;
+ }
+ size_t cur = kBufSize;
+ if (cur > rem)
+ cur = (size_t)rem;
+ if (cur > extentRem)
+ cur = (size_t)extentRem;
+ RINOK(ReadStream(_stream, buf, &cur))
+ if (cur == 0)
+ {
+ opRes = NExtract::NOperationResult::kDataError;
+ break;
+ }
+ if (realOutStream)
+ {
+ RINOK(WriteStream(realOutStream, buf, cur))
+ }
+ pos += cur;
+ extentRem -= cur;
+ const UInt64 processed = currentTotalSize + pos;
+ RINOK(extractCallback->SetCompleted(&processed))
+ }
+ }
+ if (extentIndex != fork->Extents.Size() || fork->Size != pos)
+ opRes = NExtract::NOperationResult::kDataError;
+ }
+ }
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = Refs.Size();
+ return S_OK;
+}
+
+HRESULT CHandler::GetForkStream(const CFork &fork, ISequentialInStream **stream)
+{
+ *stream = NULL;
+
+ if (!fork.IsOk(Header.BlockSizeLog))
+ return S_FALSE;
+
+ CExtentsStream *extentStreamSpec = new CExtentsStream();
+ CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec;
+
+ UInt64 rem = fork.Size;
+ UInt64 virt = 0;
+
+ FOR_VECTOR (i, fork.Extents)
+ {
+ const CExtent &e = fork.Extents[i];
+ if (e.NumBlocks == 0)
+ continue;
+ UInt64 cur = ((UInt64)e.NumBlocks << Header.BlockSizeLog);
+ if (cur > rem)
+ {
+ cur = rem;
+ if (i != fork.Extents.Size() - 1)
+ return S_FALSE;
+ }
+ CSeekExtent se;
+ se.Phy = (UInt64)e.Pos << Header.BlockSizeLog;
+ se.Virt = virt;
+ virt += cur;
+ rem -= cur;
+ extentStreamSpec->Extents.Add(se);
+ }
+
+ if (rem != 0)
+ return S_FALSE;
+
+ CSeekExtent se;
+ se.Phy = 0;
+ se.Virt = virt;
+ extentStreamSpec->Extents.Add(se);
+ extentStreamSpec->Stream = _stream;
+ extentStreamSpec->Init();
+ *stream = extentStream.Detach();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ *stream = NULL;
+
+ const CRef &ref = Refs[index];
+ const CFork *fork = NULL;
+ if (ref.AttrIndex >= 0)
+ {
+ const CAttr &attr = Attrs[ref.AttrIndex];
+ if (!attr.Fork_defined || attr.Data.Size() != 0)
+ return S_FALSE;
+ fork = &attr.Fork;
+ }
+ else
+ {
+ const CItem &item = Items[ref.ItemIndex];
+ if (ref.IsResource())
+ fork = &item.ResourceFork;
+ else if (item.IsDir())
+ return S_FALSE;
+ else if (item.CompressHeader.IsCorrect)
+ return S_FALSE;
+ else
+ fork = &item.DataFork;
+ }
+ return GetForkStream(*fork, stream);
+}
+
+static const Byte k_Signature[] = {
+ 2, 'B', 'D',
+ 4, 'H', '+', 0, 4,
+ 4, 'H', 'X', 0, 5 };
+
+REGISTER_ARC_I(
+ "HFS", "hfs hfsx", NULL, 0xE3,
+ k_Signature,
+ kHeaderPadSize,
+ NArcInfoFlags::kMultiSignature,
+ IsArc_HFS)
+
+}}
diff --git a/CPP/7zip/Archive/HfsHandler.h b/CPP/7zip/Archive/HfsHandler.h
new file mode 100644
index 0000000..0006e12
--- /dev/null
+++ b/CPP/7zip/Archive/HfsHandler.h
@@ -0,0 +1,90 @@
+// HfsHandler.h
+
+#ifndef ZIP7_INC_HFS_HANDLER_H
+#define ZIP7_INC_HFS_HANDLER_H
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Compress/LzfseDecoder.h"
+#include "../Compress/ZlibDecoder.h"
+
+namespace NArchive {
+namespace NHfs {
+
+static const UInt32 k_decmpfs_HeaderSize = 16;
+
+struct CCompressHeader
+{
+ UInt64 UnpackSize;
+ UInt32 Method;
+ Byte DataPos;
+ bool IsCorrect;
+ bool IsSupported;
+ bool IsResource;
+
+ bool IsMethod_Compressed_Inline() const { return DataPos == k_decmpfs_HeaderSize; }
+ bool IsMethod_Uncompressed_Inline() const { return DataPos == k_decmpfs_HeaderSize + 1; }
+ bool IsMethod_Resource() const { return IsResource; }
+
+ void Parse(const Byte *p, size_t size);
+
+ void Clear()
+ {
+ UnpackSize = 0;
+ Method = 0;
+ DataPos = 0;
+ IsCorrect = false;
+ IsSupported = false;
+ IsResource = false;
+ }
+
+ CCompressHeader() { Clear(); }
+
+ void MethodToProp(NWindows::NCOM::CPropVariant &prop) const;
+};
+
+void MethodsMaskToProp(UInt32 methodsMask, NWindows::NCOM::CPropVariant &prop);
+
+
+class CDecoder
+{
+ NCompress::NZlib::CDecoder *_zlibDecoderSpec;
+ CMyComPtr<ICompressCoder> _zlibDecoder;
+
+ NCompress::NLzfse::CDecoder *_lzfseDecoderSpec;
+ CMyComPtr<ICompressCoder> _lzfseDecoder;
+
+ CByteBuffer _tableBuf;
+ CByteBuffer _buf;
+
+ HRESULT ExtractResourceFork_ZLIB(
+ ISequentialInStream *inStream, ISequentialOutStream *realOutStream,
+ UInt64 forkSize, UInt64 unpackSize,
+ UInt64 progressStart, IArchiveExtractCallback *extractCallback);
+
+ HRESULT ExtractResourceFork_LZFSE(
+ ISequentialInStream *inStream, ISequentialOutStream *realOutStream,
+ UInt64 forkSize, UInt64 unpackSize,
+ UInt64 progressStart, IArchiveExtractCallback *extractCallback);
+
+ HRESULT ExtractResourceFork_ZBM(
+ ISequentialInStream *inStream, ISequentialOutStream *realOutStream,
+ UInt64 forkSize, UInt64 unpackSize,
+ UInt64 progressStart, IArchiveExtractCallback *extractCallback);
+
+public:
+
+ HRESULT Extract(
+ ISequentialInStream *inStreamFork, ISequentialOutStream *realOutStream,
+ UInt64 forkSize,
+ const CCompressHeader &compressHeader,
+ const CByteBuffer *data,
+ UInt64 progressStart, IArchiveExtractCallback *extractCallback,
+ int &opRes);
+
+ CDecoder();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/IArchive.h b/CPP/7zip/Archive/IArchive.h
index 96451a6..3e68ac3 100644
--- a/CPP/7zip/Archive/IArchive.h
+++ b/CPP/7zip/Archive/IArchive.h
@@ -1,608 +1,704 @@
-// IArchive.h
-
-#ifndef __IARCHIVE_H
-#define __IARCHIVE_H
-
-#include "../IProgress.h"
-#include "../IStream.h"
-#include "../PropID.h"
-
-#define ARCHIVE_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 6, x)
-#define ARCHIVE_INTERFACE(i, x) ARCHIVE_INTERFACE_SUB(i, IUnknown, x)
-
-namespace NFileTimeType
-{
- enum EEnum
- {
- kWindows,
- kUnix,
- kDOS
- };
-}
-
-namespace NArcInfoFlags
-{
- const UInt32 kKeepName = 1 << 0; // keep name of file in archive name
- const UInt32 kAltStreams = 1 << 1; // the handler supports alt streams
- const UInt32 kNtSecure = 1 << 2; // the handler supports NT security
- const UInt32 kFindSignature = 1 << 3; // the handler can find start of archive
- const UInt32 kMultiSignature = 1 << 4; // there are several signatures
- const UInt32 kUseGlobalOffset = 1 << 5; // the seek position of stream must be set as global offset
- const UInt32 kStartOpen = 1 << 6; // call handler for each start position
- const UInt32 kPureStartOpen = 1 << 7; // call handler only for start of file
- const UInt32 kBackwardOpen = 1 << 8; // archive can be open backward
- const UInt32 kPreArc = 1 << 9; // such archive can be stored before real archive (like SFX stub)
- const UInt32 kSymLinks = 1 << 10; // the handler supports symbolic links
- const UInt32 kHardLinks = 1 << 11; // the handler supports hard links
-}
-
-namespace NArchive
-{
- namespace NHandlerPropID
- {
- enum
- {
- kName = 0, // VT_BSTR
- kClassID, // binary GUID in VT_BSTR
- kExtension, // VT_BSTR
- kAddExtension, // VT_BSTR
- kUpdate, // VT_BOOL
- kKeepName, // VT_BOOL
- kSignature, // binary in VT_BSTR
- kMultiSignature, // binary in VT_BSTR
- kSignatureOffset, // VT_UI4
- kAltStreams, // VT_BOOL
- kNtSecure, // VT_BOOL
- kFlags // VT_UI4
- // kVersion // VT_UI4 ((VER_MAJOR << 8) | VER_MINOR)
- };
- }
-
- namespace NExtract
- {
- namespace NAskMode
- {
- enum
- {
- kExtract = 0,
- kTest,
- kSkip
- };
- }
-
- namespace NOperationResult
- {
- enum
- {
- kOK = 0,
- kUnsupportedMethod,
- kDataError,
- kCRCError,
- kUnavailable,
- kUnexpectedEnd,
- kDataAfterEnd,
- kIsNotArc,
- kHeadersError,
- kWrongPassword
- };
- }
- }
-
- namespace NEventIndexType
- {
- enum
- {
- kNoIndex = 0,
- kInArcIndex,
- kBlockIndex,
- kOutArcIndex
- };
- }
-
- namespace NUpdate
- {
- namespace NOperationResult
- {
- enum
- {
- kOK = 0
- , // kError
- };
- }
- }
-}
-
-#define INTERFACE_IArchiveOpenCallback(x) \
- STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes) x; \
- STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes) x; \
-
-ARCHIVE_INTERFACE(IArchiveOpenCallback, 0x10)
-{
- INTERFACE_IArchiveOpenCallback(PURE);
-};
-
-/*
-IArchiveExtractCallback::
-
-7-Zip doesn't call IArchiveExtractCallback functions
- GetStream()
- PrepareOperation()
- SetOperationResult()
-from different threads simultaneously.
-But 7-Zip can call functions for IProgress or ICompressProgressInfo functions
-from another threads simultaneously with calls for IArchiveExtractCallback interface.
-
-IArchiveExtractCallback::GetStream()
- UInt32 index - index of item in Archive
- Int32 askExtractMode (Extract::NAskMode)
- if (askMode != NExtract::NAskMode::kExtract)
- {
- then the callee can not real stream: (*inStream == NULL)
- }
-
- Out:
- (*inStream == NULL) - for directories
- (*inStream == NULL) - if link (hard link or symbolic link) was created
- if (*inStream == NULL && askMode == NExtract::NAskMode::kExtract)
- {
- then the caller must skip extracting of that file.
- }
-
- returns:
- S_OK : OK
- S_FALSE : data error (for decoders)
-
-if (IProgress::SetTotal() was called)
-{
- IProgress::SetCompleted(completeValue) uses
- packSize - for some stream formats (xz, gz, bz2, lzma, z, ppmd).
- unpackSize - for another formats.
-}
-else
-{
- IProgress::SetCompleted(completeValue) uses packSize.
-}
-
-SetOperationResult()
- 7-Zip calls SetOperationResult at the end of extracting,
- so the callee can close the file, set attributes, timestamps and security information.
-
- Int32 opRes (NExtract::NOperationResult)
-*/
-
-#define INTERFACE_IArchiveExtractCallback(x) \
- INTERFACE_IProgress(x) \
- STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode) x; \
- STDMETHOD(PrepareOperation)(Int32 askExtractMode) x; \
- STDMETHOD(SetOperationResult)(Int32 opRes) x; \
-
-ARCHIVE_INTERFACE_SUB(IArchiveExtractCallback, IProgress, 0x20)
-{
- INTERFACE_IArchiveExtractCallback(PURE)
-};
-
-
-
-/*
-IArchiveExtractCallbackMessage can be requested from IArchiveExtractCallback object
- by Extract() or UpdateItems() functions to report about extracting errors
-ReportExtractResult()
- UInt32 indexType (NEventIndexType)
- UInt32 index
- Int32 opRes (NExtract::NOperationResult)
-*/
-
-#define INTERFACE_IArchiveExtractCallbackMessage(x) \
- STDMETHOD(ReportExtractResult)(UInt32 indexType, UInt32 index, Int32 opRes) x; \
-
-ARCHIVE_INTERFACE_SUB(IArchiveExtractCallbackMessage, IProgress, 0x21)
-{
- INTERFACE_IArchiveExtractCallbackMessage(PURE)
-};
-
-
-#define INTERFACE_IArchiveOpenVolumeCallback(x) \
- STDMETHOD(GetProperty)(PROPID propID, PROPVARIANT *value) x; \
- STDMETHOD(GetStream)(const wchar_t *name, IInStream **inStream) x; \
-
-ARCHIVE_INTERFACE(IArchiveOpenVolumeCallback, 0x30)
-{
- INTERFACE_IArchiveOpenVolumeCallback(PURE);
-};
-
-
-ARCHIVE_INTERFACE(IInArchiveGetStream, 0x40)
-{
- STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream) PURE;
-};
-
-
-ARCHIVE_INTERFACE(IArchiveOpenSetSubArchiveName, 0x50)
-{
- STDMETHOD(SetSubArchiveName)(const wchar_t *name) PURE;
-};
-
-
-/*
-IInArchive::Open
- stream
- if (kUseGlobalOffset), stream current position can be non 0.
- if (!kUseGlobalOffset), stream current position is 0.
- if (maxCheckStartPosition == NULL), the handler can try to search archive start in stream
- if (*maxCheckStartPosition == 0), the handler must check only current position as archive start
-
-IInArchive::Extract:
- indices must be sorted
- numItems = (UInt32)(Int32)-1 = 0xFFFFFFFF means "all files"
- testMode != 0 means "test files without writing to outStream"
-
-IInArchive::GetArchiveProperty:
- kpidOffset - start offset of archive.
- VT_EMPTY : means offset = 0.
- VT_UI4, VT_UI8, VT_I8 : result offset; negative values is allowed
- kpidPhySize - size of archive. VT_EMPTY means unknown size.
- kpidPhySize is allowed to be larger than file size. In that case it must show
- supposed size.
-
- kpidIsDeleted:
- kpidIsAltStream:
- kpidIsAux:
- kpidINode:
- must return VARIANT_TRUE (VT_BOOL), if archive can support that property in GetProperty.
-
-
-Notes:
- Don't call IInArchive functions for same IInArchive object from different threads simultaneously.
- Some IInArchive handlers will work incorrectly in that case.
-*/
-
-#ifdef _MSC_VER
- #define MY_NO_THROW_DECL_ONLY throw()
-#else
- #define MY_NO_THROW_DECL_ONLY
-#endif
-
-#define INTERFACE_IInArchive(x) \
- STDMETHOD(Open)(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback) MY_NO_THROW_DECL_ONLY x; \
- STDMETHOD(Close)() MY_NO_THROW_DECL_ONLY x; \
- STDMETHOD(GetNumberOfItems)(UInt32 *numItems) MY_NO_THROW_DECL_ONLY x; \
- STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \
- STDMETHOD(Extract)(const UInt32* indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback) MY_NO_THROW_DECL_ONLY x; \
- STDMETHOD(GetArchiveProperty)(PROPID propID, PROPVARIANT *value) MY_NO_THROW_DECL_ONLY x; \
- STDMETHOD(GetNumberOfProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \
- STDMETHOD(GetPropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \
- STDMETHOD(GetNumberOfArchiveProperties)(UInt32 *numProps) MY_NO_THROW_DECL_ONLY x; \
- STDMETHOD(GetArchivePropertyInfo)(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) MY_NO_THROW_DECL_ONLY x; \
-
-ARCHIVE_INTERFACE(IInArchive, 0x60)
-{
- INTERFACE_IInArchive(PURE)
-};
-
-namespace NParentType
-{
- enum
- {
- kDir = 0,
- kAltStream
- };
-};
-
-namespace NPropDataType
-{
- const UInt32 kMask_ZeroEnd = 1 << 4;
- // const UInt32 kMask_BigEndian = 1 << 5;
- const UInt32 kMask_Utf = 1 << 6;
- const UInt32 kMask_Utf8 = kMask_Utf | 0;
- const UInt32 kMask_Utf16 = kMask_Utf | 1;
- // const UInt32 kMask_Utf32 = kMask_Utf | 2;
-
- const UInt32 kNotDefined = 0;
- const UInt32 kRaw = 1;
-
- const UInt32 kUtf8z = kMask_Utf8 | kMask_ZeroEnd;
- const UInt32 kUtf16z = kMask_Utf16 | kMask_ZeroEnd;
-};
-
-// UTF string (pointer to wchar_t) with zero end and little-endian.
-#define PROP_DATA_TYPE_wchar_t_PTR_Z_LE ((NPropDataType::kMask_Utf | NPropDataType::kMask_ZeroEnd) + (sizeof(wchar_t) >> 1))
-
-/*
-GetRawProp:
- Result:
- S_OK - even if property is not set
-*/
-
-#define INTERFACE_IArchiveGetRawProps(x) \
- STDMETHOD(GetParent)(UInt32 index, UInt32 *parent, UInt32 *parentType) x; \
- STDMETHOD(GetRawProp)(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) x; \
- STDMETHOD(GetNumRawProps)(UInt32 *numProps) x; \
- STDMETHOD(GetRawPropInfo)(UInt32 index, BSTR *name, PROPID *propID) x;
-
-ARCHIVE_INTERFACE(IArchiveGetRawProps, 0x70)
-{
- INTERFACE_IArchiveGetRawProps(PURE)
-};
-
-#define INTERFACE_IArchiveGetRootProps(x) \
- STDMETHOD(GetRootProp)(PROPID propID, PROPVARIANT *value) x; \
- STDMETHOD(GetRootRawProp)(PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType) x; \
-
-ARCHIVE_INTERFACE(IArchiveGetRootProps, 0x71)
-{
- INTERFACE_IArchiveGetRootProps(PURE)
-};
-
-ARCHIVE_INTERFACE(IArchiveOpenSeq, 0x61)
-{
- STDMETHOD(OpenSeq)(ISequentialInStream *stream) PURE;
-};
-
-/*
- OpenForSize
- Result:
- S_FALSE - is not archive
- ? - DATA error
-*/
-
-/*
-const UInt32 kOpenFlags_RealPhySize = 1 << 0;
-const UInt32 kOpenFlags_NoSeek = 1 << 1;
-// const UInt32 kOpenFlags_BeforeExtract = 1 << 2;
-*/
-
-/*
-Flags:
- 0 - opens archive with IInStream, if IInStream interface is supported
- - if phySize is not available, it doesn't try to make full parse to get phySize
- kOpenFlags_NoSeek - ArcOpen2 function doesn't use IInStream interface, even if it's available
- kOpenFlags_RealPhySize - the handler will try to get PhySize, even if it requires full decompression for file
-
- if handler is not allowed to use IInStream and the flag kOpenFlags_RealPhySize is not specified,
- the handler can return S_OK, but it doesn't check even Signature.
- So next Extract can be called for that sequential stream.
-*/
-
-/*
-ARCHIVE_INTERFACE(IArchiveOpen2, 0x62)
-{
- STDMETHOD(ArcOpen2)(ISequentialInStream *stream, UInt32 flags, IArchiveOpenCallback *openCallback) PURE;
-};
-*/
-
-// ---------- UPDATE ----------
-
-/*
-GetUpdateItemInfo outs:
-*newData *newProps
- 0 0 - Copy data and properties from archive
- 0 1 - Copy data from archive, request new properties
- 1 0 - that combination is unused now
- 1 1 - Request new data and new properties. It can be used even for folders
-
- indexInArchive = -1 if there is no item in archive, or if it doesn't matter.
-
-
-GetStream out:
- Result:
- S_OK:
- (*inStream == NULL) - only for directories
- - the bug was fixed in 9.33: (*Stream == NULL) was in case of anti-file
- (*inStream != NULL) - for any file, even for empty file or anti-file
- S_FALSE - skip that file (don't add item to archive) - (client code can't open stream of that file by some reason)
- (*inStream == NULL)
-
-The order of calling for hard links:
- - GetStream()
- - GetProperty(kpidHardLink)
-
-SetOperationResult()
- Int32 opRes (NExtract::NOperationResult::kOK)
-*/
-
-#define INTERFACE_IArchiveUpdateCallback(x) \
- INTERFACE_IProgress(x); \
- STDMETHOD(GetUpdateItemInfo)(UInt32 index, Int32 *newData, Int32 *newProps, UInt32 *indexInArchive) x; \
- STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) x; \
- STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream) x; \
- STDMETHOD(SetOperationResult)(Int32 operationResult) x; \
-
-ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback, IProgress, 0x80)
-{
- INTERFACE_IArchiveUpdateCallback(PURE);
-};
-
-#define INTERFACE_IArchiveUpdateCallback2(x) \
- INTERFACE_IArchiveUpdateCallback(x) \
- STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size) x; \
- STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream) x; \
-
-ARCHIVE_INTERFACE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82)
-{
- INTERFACE_IArchiveUpdateCallback2(PURE);
-};
-
-namespace NUpdateNotifyOp
-{
- enum
- {
- kAdd = 0,
- kUpdate,
- kAnalyze,
- kReplicate,
- kRepack,
- kSkip,
- kDelete,
- kHeader
-
- // kNumDefined
- };
-};
-
-/*
-IArchiveUpdateCallbackFile::ReportOperation
- UInt32 indexType (NEventIndexType)
- UInt32 index
- UInt32 notifyOp (NUpdateNotifyOp)
-*/
-
-#define INTERFACE_IArchiveUpdateCallbackFile(x) \
- STDMETHOD(GetStream2)(UInt32 index, ISequentialInStream **inStream, UInt32 notifyOp) x; \
- STDMETHOD(ReportOperation)(UInt32 indexType, UInt32 index, UInt32 notifyOp) x; \
-
-ARCHIVE_INTERFACE(IArchiveUpdateCallbackFile, 0x83)
-{
- INTERFACE_IArchiveUpdateCallbackFile(PURE);
-};
-
-
-/*
-UpdateItems()
--------------
-
- outStream: output stream. (the handler) MUST support the case when
- Seek position in outStream is not ZERO.
- but the caller calls with empty outStream and seek position is ZERO??
-
- archives with stub:
-
- If archive is open and the handler and (Offset > 0), then the handler
- knows about stub size.
- UpdateItems():
- 1) the handler MUST copy that stub to outStream
- 2) the caller MUST NOT copy the stub to outStream, if
- "rsfx" property is set with SetProperties
-
- the handler must support the case where
- ISequentialOutStream *outStream
-*/
-
-
-#define INTERFACE_IOutArchive(x) \
- STDMETHOD(UpdateItems)(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback) x; \
- STDMETHOD(GetFileTimeType)(UInt32 *type) x;
-
-ARCHIVE_INTERFACE(IOutArchive, 0xA0)
-{
- INTERFACE_IOutArchive(PURE)
-};
-
-
-/*
-ISetProperties::SetProperties()
- PROPVARIANT values[i].vt:
- VT_EMPTY
- VT_BOOL
- VT_UI4 - if 32-bit number
- VT_UI8 - if 64-bit number
- VT_BSTR
-*/
-
-ARCHIVE_INTERFACE(ISetProperties, 0x03)
-{
- STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps) PURE;
-};
-
-ARCHIVE_INTERFACE(IArchiveKeepModeForNextOpen, 0x04)
-{
- STDMETHOD(KeepModeForNextOpen)() PURE;
-};
-
-/* Exe handler: the handler for executable format (PE, ELF, Mach-O).
- SFX archive: executable stub + some tail data.
- before 9.31: exe handler didn't parse SFX archives as executable format.
- for 9.31+: exe handler parses SFX archives as executable format, only if AllowTail(1) was called */
-
-ARCHIVE_INTERFACE(IArchiveAllowTail, 0x05)
-{
- STDMETHOD(AllowTail)(Int32 allowTail) PURE;
-};
-
-
-#define IMP_IInArchive_GetProp(k) \
- (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \
- { if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \
- *propID = k[index]; *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID]; *name = 0; return S_OK; } \
-
-
-struct CStatProp
-{
- const char *Name;
- UInt32 PropID;
- VARTYPE vt;
-};
-
-namespace NWindows {
-namespace NCOM {
-// PropVariant.cpp
-BSTR AllocBstrFromAscii(const char *s) throw();
-}}
-
-#define IMP_IInArchive_GetProp_WITH_NAME(k) \
- (UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType) \
- { if (index >= ARRAY_SIZE(k)) return E_INVALIDARG; \
- const CStatProp &prop = k[index]; \
- *propID = (PROPID)prop.PropID; *varType = prop.vt; \
- *name = NWindows::NCOM::AllocBstrFromAscii(prop.Name); return S_OK; } \
-
-#define IMP_IInArchive_Props \
- STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) \
- { *numProps = ARRAY_SIZE(kProps); return S_OK; } \
- STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp(kProps)
-
-#define IMP_IInArchive_Props_WITH_NAME \
- STDMETHODIMP CHandler::GetNumberOfProperties(UInt32 *numProps) \
- { *numProps = ARRAY_SIZE(kProps); return S_OK; } \
- STDMETHODIMP CHandler::GetPropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kProps)
-
-
-#define IMP_IInArchive_ArcProps \
- STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \
- { *numProps = ARRAY_SIZE(kArcProps); return S_OK; } \
- STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp(kArcProps)
-
-#define IMP_IInArchive_ArcProps_WITH_NAME \
- STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \
- { *numProps = ARRAY_SIZE(kArcProps); return S_OK; } \
- STDMETHODIMP CHandler::GetArchivePropertyInfo IMP_IInArchive_GetProp_WITH_NAME(kArcProps)
-
-#define IMP_IInArchive_ArcProps_NO_Table \
- STDMETHODIMP CHandler::GetNumberOfArchiveProperties(UInt32 *numProps) \
- { *numProps = 0; return S_OK; } \
- STDMETHODIMP CHandler::GetArchivePropertyInfo(UInt32, BSTR *, PROPID *, VARTYPE *) \
- { return E_NOTIMPL; } \
-
-#define IMP_IInArchive_ArcProps_NO \
- IMP_IInArchive_ArcProps_NO_Table \
- STDMETHODIMP CHandler::GetArchiveProperty(PROPID, PROPVARIANT *value) \
- { value->vt = VT_EMPTY; return S_OK; }
-
-
-
-#define k_IsArc_Res_NO 0
-#define k_IsArc_Res_YES 1
-#define k_IsArc_Res_NEED_MORE 2
-// #define k_IsArc_Res_YES_LOW_PROB 3
-
-#define API_FUNC_IsArc EXTERN_C UInt32 WINAPI
-#define API_FUNC_static_IsArc extern "C" { static UInt32 WINAPI
-
-extern "C"
-{
- typedef HRESULT (WINAPI *Func_CreateObject)(const GUID *clsID, const GUID *iid, void **outObject);
-
- typedef UInt32 (WINAPI *Func_IsArc)(const Byte *p, size_t size);
- typedef HRESULT (WINAPI *Func_GetIsArc)(UInt32 formatIndex, Func_IsArc *isArc);
-
- typedef HRESULT (WINAPI *Func_GetNumberOfFormats)(UInt32 *numFormats);
- typedef HRESULT (WINAPI *Func_GetHandlerProperty)(PROPID propID, PROPVARIANT *value);
- typedef HRESULT (WINAPI *Func_GetHandlerProperty2)(UInt32 index, PROPID propID, PROPVARIANT *value);
-
- typedef HRESULT (WINAPI *Func_SetCaseSensitive)(Int32 caseSensitive);
- typedef HRESULT (WINAPI *Func_SetLargePageMode)();
-
- typedef IOutArchive * (*Func_CreateOutArchive)();
- typedef IInArchive * (*Func_CreateInArchive)();
-}
-
-#endif
+// IArchive.h
+
+#ifndef ZIP7_INC_IARCHIVE_H
+#define ZIP7_INC_IARCHIVE_H
+
+#include "../IProgress.h"
+#include "../IStream.h"
+#include "../PropID.h"
+
+Z7_PURE_INTERFACES_BEGIN
+
+
+#define Z7_IFACE_CONSTR_ARCHIVE_SUB(i, base, n) \
+ Z7_DECL_IFACE_7ZIP_SUB(i, base, 6, n) \
+ { Z7_IFACE_COM7_PURE(i) };
+
+#define Z7_IFACE_CONSTR_ARCHIVE(i, n) \
+ Z7_IFACE_CONSTR_ARCHIVE_SUB(i, IUnknown, n)
+
+/*
+How the function in 7-Zip returns object for output parameter via pointer
+
+1) The caller sets the value of variable before function call:
+ PROPVARIANT : vt = VT_EMPTY
+ BSTR : NULL
+ IUnknown* and derived interfaces : NULL
+ another scalar types : any non-initialized value is allowed
+
+2) The callee in current 7-Zip code now can free input object for output parameter:
+ PROPVARIANT : the callee calls VariantClear(propvaiant_ptr) for input
+ value stored in variable
+ another types : the callee ignores stored value.
+
+3) The callee writes new value to variable for output parameter and
+ returns execution to caller.
+
+4) The caller must free or release object returned by the callee:
+ PROPVARIANT : VariantClear(&propvaiant)
+ BSTR : SysFreeString(bstr)
+ IUnknown* and derived interfaces : if (ptr) ptr->Relase()
+*/
+
+
+namespace NFileTimeType
+{
+ enum EEnum
+ {
+ kNotDefined = -1,
+ kWindows = 0,
+ kUnix,
+ kDOS,
+ k1ns
+ };
+}
+
+namespace NArcInfoFlags
+{
+ const UInt32 kKeepName = 1 << 0; // keep name of file in archive name
+ const UInt32 kAltStreams = 1 << 1; // the handler supports alt streams
+ const UInt32 kNtSecure = 1 << 2; // the handler supports NT security
+ const UInt32 kFindSignature = 1 << 3; // the handler can find start of archive
+ const UInt32 kMultiSignature = 1 << 4; // there are several signatures
+ const UInt32 kUseGlobalOffset = 1 << 5; // the seek position of stream must be set as global offset
+ const UInt32 kStartOpen = 1 << 6; // call handler for each start position
+ const UInt32 kPureStartOpen = 1 << 7; // call handler only for start of file
+ const UInt32 kBackwardOpen = 1 << 8; // archive can be open backward
+ const UInt32 kPreArc = 1 << 9; // such archive can be stored before real archive (like SFX stub)
+ const UInt32 kSymLinks = 1 << 10; // the handler supports symbolic links
+ const UInt32 kHardLinks = 1 << 11; // the handler supports hard links
+ const UInt32 kByExtOnlyOpen = 1 << 12; // call handler only if file extension matches
+ const UInt32 kHashHandler = 1 << 13; // the handler contains the hashes (checksums)
+ const UInt32 kCTime = 1 << 14;
+ const UInt32 kCTime_Default = 1 << 15;
+ const UInt32 kATime = 1 << 16;
+ const UInt32 kATime_Default = 1 << 17;
+ const UInt32 kMTime = 1 << 18;
+ const UInt32 kMTime_Default = 1 << 19;
+ // const UInt32 kTTime_Reserved = 1 << 20;
+ // const UInt32 kTTime_Reserved_Default = 1 << 21;
+}
+
+namespace NArcInfoTimeFlags
+{
+ const unsigned kTime_Prec_Mask_bit_index = 0;
+ const unsigned kTime_Prec_Mask_num_bits = 26;
+
+ const unsigned kTime_Prec_Default_bit_index = 27;
+ const unsigned kTime_Prec_Default_num_bits = 5;
+}
+
+#define TIME_PREC_TO_ARC_FLAGS_MASK(v) \
+ ((UInt32)1 << (NArcInfoTimeFlags::kTime_Prec_Mask_bit_index + (v)))
+
+#define TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT(v) \
+ ((UInt32)(v) << NArcInfoTimeFlags::kTime_Prec_Default_bit_index)
+
+namespace NArchive
+{
+ namespace NHandlerPropID
+ {
+ enum
+ {
+ kName = 0, // VT_BSTR
+ kClassID, // binary GUID in VT_BSTR
+ kExtension, // VT_BSTR
+ kAddExtension, // VT_BSTR
+ kUpdate, // VT_BOOL
+ kKeepName, // VT_BOOL
+ kSignature, // binary in VT_BSTR
+ kMultiSignature, // binary in VT_BSTR
+ kSignatureOffset, // VT_UI4
+ kAltStreams, // VT_BOOL
+ kNtSecure, // VT_BOOL
+ kFlags, // VT_UI4
+ kTimeFlags // VT_UI4
+ };
+ }
+
+ namespace NExtract
+ {
+ namespace NAskMode
+ {
+ enum
+ {
+ kExtract = 0,
+ kTest,
+ kSkip,
+ kReadExternal
+ };
+ }
+
+ namespace NOperationResult
+ {
+ enum
+ {
+ kOK = 0,
+ kUnsupportedMethod,
+ kDataError,
+ kCRCError,
+ kUnavailable,
+ kUnexpectedEnd,
+ kDataAfterEnd,
+ kIsNotArc,
+ kHeadersError,
+ kWrongPassword
+ // , kMemError
+ };
+ }
+ }
+
+ namespace NEventIndexType
+ {
+ enum
+ {
+ kNoIndex = 0,
+ kInArcIndex,
+ kBlockIndex,
+ kOutArcIndex
+ // kArcProp
+ };
+ }
+
+ namespace NUpdate
+ {
+ namespace NOperationResult
+ {
+ enum
+ {
+ kOK = 0
+ // kError = 1,
+ // kError_FileChanged
+ };
+ }
+ }
+}
+
+#define Z7_IFACEM_IArchiveOpenCallback(x) \
+ x(SetTotal(const UInt64 *files, const UInt64 *bytes)) \
+ x(SetCompleted(const UInt64 *files, const UInt64 *bytes)) \
+
+Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpenCallback, 0x10)
+
+/*
+IArchiveExtractCallback::
+
+7-Zip doesn't call IArchiveExtractCallback functions
+ GetStream()
+ PrepareOperation()
+ SetOperationResult()
+from different threads simultaneously.
+But 7-Zip can call functions for IProgress or ICompressProgressInfo functions
+from another threads simultaneously with calls for IArchiveExtractCallback interface.
+
+IArchiveExtractCallback::GetStream()
+ UInt32 index - index of item in Archive
+ Int32 askExtractMode (Extract::NAskMode)
+ if (askMode != NExtract::NAskMode::kExtract)
+ {
+ then the callee doesn't write data to stream: (*outStream == NULL)
+ }
+
+ Out:
+ (*outStream == NULL) - for directories
+ (*outStream == NULL) - if link (hard link or symbolic link) was created
+ if (*outStream == NULL && askMode == NExtract::NAskMode::kExtract)
+ {
+ then the caller must skip extracting of that file.
+ }
+
+ returns:
+ S_OK : OK
+ S_FALSE : data error (for decoders)
+
+if (IProgress::SetTotal() was called)
+{
+ IProgress::SetCompleted(completeValue) uses
+ packSize - for some stream formats (xz, gz, bz2, lzma, z, ppmd).
+ unpackSize - for another formats.
+}
+else
+{
+ IProgress::SetCompleted(completeValue) uses packSize.
+}
+
+SetOperationResult()
+ 7-Zip calls SetOperationResult at the end of extracting,
+ so the callee can close the file, set attributes, timestamps and security information.
+
+ Int32 opRes (NExtract::NOperationResult)
+*/
+
+// INTERFACE_IProgress(x)
+
+#define Z7_IFACEM_IArchiveExtractCallback(x) \
+ x(GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode)) \
+ x(PrepareOperation(Int32 askExtractMode)) \
+ x(SetOperationResult(Int32 opRes)) \
+
+Z7_IFACE_CONSTR_ARCHIVE_SUB(IArchiveExtractCallback, IProgress, 0x20)
+
+
+
+/*
+v23:
+IArchiveExtractCallbackMessage2 can be requested from IArchiveExtractCallback object
+ by Extract() or UpdateItems() functions to report about extracting errors
+ReportExtractResult()
+ UInt32 indexType (NEventIndexType)
+ UInt32 index
+ Int32 opRes (NExtract::NOperationResult)
+*/
+/*
+before v23:
+#define Z7_IFACEM_IArchiveExtractCallbackMessage(x) \
+ x(ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes))
+Z7_IFACE_CONSTR_ARCHIVE_SUB(IArchiveExtractCallbackMessage, IProgress, 0x21)
+*/
+#define Z7_IFACEM_IArchiveExtractCallbackMessage2(x) \
+ x(ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes))
+Z7_IFACE_CONSTR_ARCHIVE(IArchiveExtractCallbackMessage2, 0x22)
+
+#define Z7_IFACEM_IArchiveOpenVolumeCallback(x) \
+ x(GetProperty(PROPID propID, PROPVARIANT *value)) \
+ x(GetStream(const wchar_t *name, IInStream **inStream))
+Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpenVolumeCallback, 0x30)
+
+
+#define Z7_IFACEM_IInArchiveGetStream(x) \
+ x(GetStream(UInt32 index, ISequentialInStream **stream))
+Z7_IFACE_CONSTR_ARCHIVE(IInArchiveGetStream, 0x40)
+
+#define Z7_IFACEM_IArchiveOpenSetSubArchiveName(x) \
+ x(SetSubArchiveName(const wchar_t *name))
+Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpenSetSubArchiveName, 0x50)
+
+
+/*
+IInArchive::Open
+ stream
+ if (kUseGlobalOffset), stream current position can be non 0.
+ if (!kUseGlobalOffset), stream current position is 0.
+ if (maxCheckStartPosition == NULL), the handler can try to search archive start in stream
+ if (*maxCheckStartPosition == 0), the handler must check only current position as archive start
+
+IInArchive::Extract:
+ indices must be sorted
+ numItems = (UInt32)(Int32)-1 = 0xFFFFFFFF means "all files"
+ testMode != 0 means "test files without writing to outStream"
+
+IInArchive::GetArchiveProperty:
+ kpidOffset - start offset of archive.
+ VT_EMPTY : means offset = 0.
+ VT_UI4, VT_UI8, VT_I8 : result offset; negative values is allowed
+ kpidPhySize - size of archive. VT_EMPTY means unknown size.
+ kpidPhySize is allowed to be larger than file size. In that case it must show
+ supposed size.
+
+ kpidIsDeleted:
+ kpidIsAltStream:
+ kpidIsAux:
+ kpidINode:
+ must return VARIANT_TRUE (VT_BOOL), if archive can support that property in GetProperty.
+
+
+Notes:
+ Don't call IInArchive functions for same IInArchive object from different threads simultaneously.
+ Some IInArchive handlers will work incorrectly in that case.
+*/
+
+#if defined(_MSC_VER) && !defined(__clang__)
+ #define MY_NO_THROW_DECL_ONLY Z7_COM7F_E
+#else
+ #define MY_NO_THROW_DECL_ONLY
+#endif
+
+#define Z7_IFACEM_IInArchive(x) \
+ x(Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *openCallback)) \
+ x(Close()) \
+ x(GetNumberOfItems(UInt32 *numItems)) \
+ x(GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \
+ x(Extract(const UInt32 *indices, UInt32 numItems, Int32 testMode, IArchiveExtractCallback *extractCallback)) \
+ x(GetArchiveProperty(PROPID propID, PROPVARIANT *value)) \
+ x(GetNumberOfProperties(UInt32 *numProps)) \
+ x(GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \
+ x(GetNumberOfArchiveProperties(UInt32 *numProps)) \
+ x(GetArchivePropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \
+
+Z7_IFACE_CONSTR_ARCHIVE(IInArchive, 0x60)
+
+namespace NParentType
+{
+ enum
+ {
+ kDir = 0,
+ kAltStream
+ };
+}
+
+namespace NPropDataType
+{
+ const UInt32 kMask_ZeroEnd = 1 << 4;
+ // const UInt32 kMask_BigEndian = 1 << 5;
+ const UInt32 kMask_Utf = 1 << 6;
+ const UInt32 kMask_Utf8 = kMask_Utf | 0;
+ const UInt32 kMask_Utf16 = kMask_Utf | 1;
+ // const UInt32 kMask_Utf32 = kMask_Utf | 2;
+
+ const UInt32 kNotDefined = 0;
+ const UInt32 kRaw = 1;
+
+ const UInt32 kUtf8z = kMask_Utf8 | kMask_ZeroEnd;
+ const UInt32 kUtf16z = kMask_Utf16 | kMask_ZeroEnd;
+}
+
+// UTF string (pointer to wchar_t) with zero end and little-endian.
+#define PROP_DATA_TYPE_wchar_t_PTR_Z_LE ((NPropDataType::kMask_Utf | NPropDataType::kMask_ZeroEnd) + (sizeof(wchar_t) >> 1))
+
+
+/*
+GetRawProp:
+ Result:
+ S_OK - even if property is not set
+*/
+
+#define Z7_IFACEM_IArchiveGetRawProps(x) \
+ x(GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)) \
+ x(GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) \
+ x(GetNumRawProps(UInt32 *numProps)) \
+ x(GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID))
+
+Z7_IFACE_CONSTR_ARCHIVE(IArchiveGetRawProps, 0x70)
+
+#define Z7_IFACEM_IArchiveGetRootProps(x) \
+ x(GetRootProp(PROPID propID, PROPVARIANT *value)) \
+ x(GetRootRawProp(PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)) \
+
+Z7_IFACE_CONSTR_ARCHIVE(IArchiveGetRootProps, 0x71)
+
+#define Z7_IFACEM_IArchiveOpenSeq(x) \
+ x(OpenSeq(ISequentialInStream *stream)) \
+
+Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpenSeq, 0x61)
+
+/*
+ OpenForSize
+ Result:
+ S_FALSE - is not archive
+ ? - DATA error
+*/
+
+/*
+const UInt32 kOpenFlags_RealPhySize = 1 << 0;
+const UInt32 kOpenFlags_NoSeek = 1 << 1;
+// const UInt32 kOpenFlags_BeforeExtract = 1 << 2;
+*/
+
+/*
+Flags:
+ 0 - opens archive with IInStream, if IInStream interface is supported
+ - if phySize is not available, it doesn't try to make full parse to get phySize
+ kOpenFlags_NoSeek - ArcOpen2 function doesn't use IInStream interface, even if it's available
+ kOpenFlags_RealPhySize - the handler will try to get PhySize, even if it requires full decompression for file
+
+ if handler is not allowed to use IInStream and the flag kOpenFlags_RealPhySize is not specified,
+ the handler can return S_OK, but it doesn't check even Signature.
+ So next Extract can be called for that sequential stream.
+*/
+/*
+#define Z7_IFACEM_IArchiveOpen2(x) \
+ x(ArcOpen2(ISequentialInStream *stream, UInt32 flags, IArchiveOpenCallback *openCallback))
+Z7_IFACE_CONSTR_ARCHIVE(IArchiveOpen2, 0x62)
+*/
+
+// ---------- UPDATE ----------
+
+/*
+GetUpdateItemInfo outs:
+*newData *newProps
+ 0 0 - Copy data and properties from archive
+ 0 1 - Copy data from archive, request new properties
+ 1 0 - that combination is unused now
+ 1 1 - Request new data and new properties. It can be used even for folders
+
+ indexInArchive = -1 if there is no item in archive, or if it doesn't matter.
+
+
+GetStream out:
+ Result:
+ S_OK:
+ (*inStream == NULL) - only for directories
+ - the bug was fixed in 9.33: (*Stream == NULL) was in case of anti-file
+ (*inStream != NULL) - for any file, even for empty file or anti-file
+ S_FALSE - skip that file (don't add item to archive) - (client code can't open stream of that file by some reason)
+ (*inStream == NULL)
+
+The order of calling for hard links:
+ - GetStream()
+ - GetProperty(kpidHardLink)
+
+SetOperationResult()
+ Int32 opRes (NExtract::NOperationResult::kOK)
+*/
+
+// INTERFACE_IProgress(x)
+#define Z7_IFACEM_IArchiveUpdateCallback(x) \
+ x(GetUpdateItemInfo(UInt32 index, Int32 *newData, Int32 *newProps, UInt32 *indexInArchive)) \
+ x(GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \
+ x(GetStream(UInt32 index, ISequentialInStream **inStream)) \
+ x(SetOperationResult(Int32 operationResult)) \
+
+Z7_IFACE_CONSTR_ARCHIVE_SUB(IArchiveUpdateCallback, IProgress, 0x80)
+
+// INTERFACE_IArchiveUpdateCallback(x)
+#define Z7_IFACEM_IArchiveUpdateCallback2(x) \
+ x(GetVolumeSize(UInt32 index, UInt64 *size)) \
+ x(GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)) \
+
+Z7_IFACE_CONSTR_ARCHIVE_SUB(IArchiveUpdateCallback2, IArchiveUpdateCallback, 0x82)
+
+namespace NUpdateNotifyOp
+{
+ enum
+ {
+ kAdd = 0,
+ kUpdate,
+ kAnalyze,
+ kReplicate,
+ kRepack,
+ kSkip,
+ kDelete,
+ kHeader,
+ kHashRead,
+ kInFileChanged
+ // , kOpFinished
+ // , kNumDefined
+ };
+}
+
+/*
+IArchiveUpdateCallbackFile::ReportOperation
+ UInt32 indexType (NEventIndexType)
+ UInt32 index
+ UInt32 notifyOp (NUpdateNotifyOp)
+*/
+
+#define Z7_IFACEM_IArchiveUpdateCallbackFile(x) \
+ x(GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 notifyOp)) \
+ x(ReportOperation(UInt32 indexType, UInt32 index, UInt32 notifyOp)) \
+
+Z7_IFACE_CONSTR_ARCHIVE(IArchiveUpdateCallbackFile, 0x83)
+
+
+#define Z7_IFACEM_IArchiveGetDiskProperty(x) \
+ x(GetDiskProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \
+
+Z7_IFACE_CONSTR_ARCHIVE(IArchiveGetDiskProperty, 0x84)
+
+/*
+#define Z7_IFACEM_IArchiveUpdateCallbackArcProp(x) \
+ x(ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value)) \
+ x(ReportRawProp(UInt32 indexType, UInt32 index, PROPID propID, const void *data, UInt32 dataSize, UInt32 propType)) \
+ x(ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes)) \
+ x(DoNeedArcProp(PROPID propID, Int32 *answer)) \
+
+Z7_IFACE_CONSTR_ARCHIVE(IArchiveUpdateCallbackArcProp, 0x85)
+*/
+
+/*
+UpdateItems()
+-------------
+
+ outStream: output stream. (the handler) MUST support the case when
+ Seek position in outStream is not ZERO.
+ but the caller calls with empty outStream and seek position is ZERO??
+
+ archives with stub:
+
+ If archive is open and the handler and (Offset > 0), then the handler
+ knows about stub size.
+ UpdateItems():
+ 1) the handler MUST copy that stub to outStream
+ 2) the caller MUST NOT copy the stub to outStream, if
+ "rsfx" property is set with SetProperties
+
+ the handler must support the case where
+ ISequentialOutStream *outStream
+*/
+
+
+#define Z7_IFACEM_IOutArchive(x) \
+ x(UpdateItems(ISequentialOutStream *outStream, UInt32 numItems, IArchiveUpdateCallback *updateCallback)) \
+ x(GetFileTimeType(UInt32 *type))
+
+Z7_IFACE_CONSTR_ARCHIVE(IOutArchive, 0xA0)
+
+
+/*
+ISetProperties::SetProperties()
+ PROPVARIANT values[i].vt:
+ VT_EMPTY
+ VT_BOOL
+ VT_UI4 - if 32-bit number
+ VT_UI8 - if 64-bit number
+ VT_BSTR
+*/
+
+#define Z7_IFACEM_ISetProperties(x) \
+ x(SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
+
+Z7_IFACE_CONSTR_ARCHIVE(ISetProperties, 0x03)
+
+#define Z7_IFACEM_IArchiveKeepModeForNextOpen(x) \
+ x(KeepModeForNextOpen()) \
+
+Z7_IFACE_CONSTR_ARCHIVE(IArchiveKeepModeForNextOpen, 0x04)
+
+/* Exe handler: the handler for executable format (PE, ELF, Mach-O).
+ SFX archive: executable stub + some tail data.
+ before 9.31: exe handler didn't parse SFX archives as executable format.
+ for 9.31+: exe handler parses SFX archives as executable format, only if AllowTail(1) was called */
+
+#define Z7_IFACEM_IArchiveAllowTail(x) \
+ x(AllowTail(Int32 allowTail)) \
+
+Z7_IFACE_CONSTR_ARCHIVE(IArchiveAllowTail, 0x05)
+
+
+
+struct CStatProp
+{
+ const char *Name;
+ UInt32 PropID;
+ VARTYPE vt;
+};
+
+namespace NWindows {
+namespace NCOM {
+// PropVariant.cpp
+BSTR AllocBstrFromAscii(const char *s) throw();
+}}
+
+
+#define IMP_IInArchive_GetProp_Base(fn, f, k) \
+ Z7_COM7F_IMF(CHandler::fn(UInt32 *numProps)) \
+ { *numProps = Z7_ARRAY_SIZE(k); return S_OK; } \
+ Z7_COM7F_IMF(CHandler::f(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \
+ { if (index >= Z7_ARRAY_SIZE(k)) return E_INVALIDARG; \
+
+#define IMP_IInArchive_GetProp_NO_NAME(fn, f, k) \
+ IMP_IInArchive_GetProp_Base(fn, f, k) \
+ *propID = k[index]; \
+ *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID]; \
+ *name = NULL; return S_OK; } \
+
+#define IMP_IInArchive_GetProp_WITH_NAME(fn, f, k) \
+ IMP_IInArchive_GetProp_Base(fn, f, k) \
+ const CStatProp &prop = k[index]; \
+ *propID = (PROPID)prop.PropID; \
+ *varType = prop.vt; \
+ *name = NWindows::NCOM::AllocBstrFromAscii(prop.Name); return S_OK; } \
+
+
+#define IMP_IInArchive_Props \
+ IMP_IInArchive_GetProp_NO_NAME(GetNumberOfProperties, GetPropertyInfo, kProps)
+
+#define IMP_IInArchive_Props_WITH_NAME \
+ IMP_IInArchive_GetProp_WITH_NAME(GetNumberOfProperties, GetPropertyInfo, kProps)
+
+#define IMP_IInArchive_ArcProps \
+ IMP_IInArchive_GetProp_NO_NAME(GetNumberOfArchiveProperties, GetArchivePropertyInfo, kArcProps)
+
+#define IMP_IInArchive_ArcProps_WITH_NAME \
+ IMP_IInArchive_GetProp_WITH_NAME(GetNumberOfArchiveProperties, GetArchivePropertyInfo, kArcProps)
+
+#define IMP_IInArchive_ArcProps_NO_Table \
+ Z7_COM7F_IMF(CHandler::GetNumberOfArchiveProperties(UInt32 *numProps)) \
+ { *numProps = 0; return S_OK; } \
+ Z7_COM7F_IMF(CHandler::GetArchivePropertyInfo(UInt32, BSTR *, PROPID *, VARTYPE *)) \
+ { return E_NOTIMPL; } \
+
+#define IMP_IInArchive_ArcProps_NO \
+ IMP_IInArchive_ArcProps_NO_Table \
+ Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID, PROPVARIANT *value)) \
+ { value->vt = VT_EMPTY; return S_OK; }
+
+
+#define Z7_class_CHandler_final \
+ Z7_class_final(CHandler)
+
+
+#define Z7_CLASS_IMP_CHandler_IInArchive_0 \
+ Z7_CLASS_IMP_COM_1(CHandler, IInArchive)
+#define Z7_CLASS_IMP_CHandler_IInArchive_1(i1) \
+ Z7_CLASS_IMP_COM_2(CHandler, IInArchive, i1)
+#define Z7_CLASS_IMP_CHandler_IInArchive_2(i1, i2) \
+ Z7_CLASS_IMP_COM_3(CHandler, IInArchive, i1, i2)
+#define Z7_CLASS_IMP_CHandler_IInArchive_3(i1, i2, i3) \
+ Z7_CLASS_IMP_COM_4(CHandler, IInArchive, i1, i2, i3)
+#define Z7_CLASS_IMP_CHandler_IInArchive_4(i1, i2, i3, i4) \
+ Z7_CLASS_IMP_COM_5(CHandler, IInArchive, i1, i2, i3, i4)
+#define Z7_CLASS_IMP_CHandler_IInArchive_5(i1, i2, i3, i4, i5) \
+ Z7_CLASS_IMP_COM_6(CHandler, IInArchive, i1, i2, i3, i4, i5)
+
+
+
+#define k_IsArc_Res_NO 0
+#define k_IsArc_Res_YES 1
+#define k_IsArc_Res_NEED_MORE 2
+// #define k_IsArc_Res_YES_LOW_PROB 3
+
+#define API_FUNC_IsArc EXTERN_C UInt32 WINAPI
+#define API_FUNC_static_IsArc extern "C" { static UInt32 WINAPI
+
+extern "C"
+{
+ typedef HRESULT (WINAPI *Func_CreateObject)(const GUID *clsID, const GUID *iid, void **outObject);
+
+ typedef UInt32 (WINAPI *Func_IsArc)(const Byte *p, size_t size);
+ typedef HRESULT (WINAPI *Func_GetIsArc)(UInt32 formatIndex, Func_IsArc *isArc);
+
+ typedef HRESULT (WINAPI *Func_GetNumberOfFormats)(UInt32 *numFormats);
+ typedef HRESULT (WINAPI *Func_GetHandlerProperty)(PROPID propID, PROPVARIANT *value);
+ typedef HRESULT (WINAPI *Func_GetHandlerProperty2)(UInt32 index, PROPID propID, PROPVARIANT *value);
+
+ typedef HRESULT (WINAPI *Func_SetCaseSensitive)(Int32 caseSensitive);
+ typedef HRESULT (WINAPI *Func_SetLargePageMode)();
+ // typedef HRESULT (WINAPI *Func_SetClientVersion)(UInt32 version);
+
+ typedef IOutArchive * (*Func_CreateOutArchive)();
+ typedef IInArchive * (*Func_CreateInArchive)();
+}
+
+
+/*
+ if there is no time in archive, external MTime of archive
+ will be used instead of _item.Time from archive.
+ For 7-zip before 22.00 we need to return some supported value.
+ But (kpidTimeType > kDOS) is not allowed in 7-Zip before 22.00.
+ So we return highest precision value supported by old 7-Zip.
+ new 7-Zip 22.00 doesn't use that value in usual cases.
+*/
+
+
+#define DECLARE_AND_SET_CLIENT_VERSION_VAR
+#define GET_FileTimeType_NotDefined_for_GetFileTimeType \
+ NFileTimeType::kWindows
+
+/*
+extern UInt32 g_ClientVersion;
+
+#define GET_CLIENT_VERSION(major, minor) \
+ ((UInt32)(((UInt32)(major) << 16) | (UInt32)(minor)))
+
+#define DECLARE_AND_SET_CLIENT_VERSION_VAR \
+ UInt32 g_ClientVersion = GET_CLIENT_VERSION(MY_VER_MAJOR, MY_VER_MINOR);
+
+#define GET_FileTimeType_NotDefined_for_GetFileTimeType \
+ ((UInt32)(g_ClientVersion >= GET_CLIENT_VERSION(22, 0) ? \
+ (UInt32)(Int32)NFileTimeType::kNotDefined : \
+ NFileTimeType::kWindows))
+*/
+
+Z7_PURE_INTERFACES_END
+#endif
diff --git a/CPP/7zip/Archive/Icons/apfs.ico b/CPP/7zip/Archive/Icons/apfs.ico
new file mode 100644
index 0000000..124eb76
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/apfs.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/arj.ico b/CPP/7zip/Archive/Icons/arj.ico
new file mode 100644
index 0000000..c0f8b14
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/arj.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/bz2.ico b/CPP/7zip/Archive/Icons/bz2.ico
new file mode 100644
index 0000000..f22abeb
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/bz2.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/cab.ico b/CPP/7zip/Archive/Icons/cab.ico
new file mode 100644
index 0000000..c96c0f0
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/cab.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/cpio.ico b/CPP/7zip/Archive/Icons/cpio.ico
new file mode 100644
index 0000000..9abaabc
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/cpio.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/deb.ico b/CPP/7zip/Archive/Icons/deb.ico
new file mode 100644
index 0000000..97a0865
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/deb.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/dmg.ico b/CPP/7zip/Archive/Icons/dmg.ico
new file mode 100644
index 0000000..7d63b09
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/dmg.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/fat.ico b/CPP/7zip/Archive/Icons/fat.ico
new file mode 100644
index 0000000..7503d93
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/fat.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/gz.ico b/CPP/7zip/Archive/Icons/gz.ico
new file mode 100644
index 0000000..d402a69
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/gz.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/hfs.ico b/CPP/7zip/Archive/Icons/hfs.ico
new file mode 100644
index 0000000..bf2c198
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/hfs.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/iso.ico b/CPP/7zip/Archive/Icons/iso.ico
new file mode 100644
index 0000000..b3e3ac2
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/iso.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/lzh.ico b/CPP/7zip/Archive/Icons/lzh.ico
new file mode 100644
index 0000000..84dab49
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/lzh.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/lzma.ico b/CPP/7zip/Archive/Icons/lzma.ico
new file mode 100644
index 0000000..2de2c24
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/lzma.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/ntfs.ico b/CPP/7zip/Archive/Icons/ntfs.ico
new file mode 100644
index 0000000..6b2aeb0
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/ntfs.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/rar.ico b/CPP/7zip/Archive/Icons/rar.ico
new file mode 100644
index 0000000..2918d29
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/rar.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/rpm.ico b/CPP/7zip/Archive/Icons/rpm.ico
new file mode 100644
index 0000000..cdeb8d1
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/rpm.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/split.ico b/CPP/7zip/Archive/Icons/split.ico
new file mode 100644
index 0000000..65723ff
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/split.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/squashfs.ico b/CPP/7zip/Archive/Icons/squashfs.ico
new file mode 100644
index 0000000..b802d94
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/squashfs.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/tar.ico b/CPP/7zip/Archive/Icons/tar.ico
new file mode 100644
index 0000000..6835885
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/tar.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/vhd.ico b/CPP/7zip/Archive/Icons/vhd.ico
new file mode 100644
index 0000000..33bed3c
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/vhd.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/wim.ico b/CPP/7zip/Archive/Icons/wim.ico
new file mode 100644
index 0000000..887975e
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/wim.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/xar.ico b/CPP/7zip/Archive/Icons/xar.ico
new file mode 100644
index 0000000..281aa7d
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/xar.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/xz.ico b/CPP/7zip/Archive/Icons/xz.ico
new file mode 100644
index 0000000..bc07a7e
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/xz.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/z.ico b/CPP/7zip/Archive/Icons/z.ico
new file mode 100644
index 0000000..2db5358
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/z.ico
Binary files differ
diff --git a/CPP/7zip/Archive/Icons/zip.ico b/CPP/7zip/Archive/Icons/zip.ico
new file mode 100644
index 0000000..2af4606
--- /dev/null
+++ b/CPP/7zip/Archive/Icons/zip.ico
Binary files differ
diff --git a/CPP/7zip/Archive/IhexHandler.cpp b/CPP/7zip/Archive/IhexHandler.cpp
new file mode 100644
index 0000000..badb559
--- /dev/null
+++ b/CPP/7zip/Archive/IhexHandler.cpp
@@ -0,0 +1,493 @@
+// IhexHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/DynamicBuffer.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyVector.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+#include "../Common/InBuffer.h"
+
+namespace NArchive {
+namespace NIhex {
+
+/* We still don't support files with custom record types: 20, 22: used by Samsung */
+
+struct CBlock
+{
+ CByteDynamicBuffer Data;
+ UInt32 Offset;
+};
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_0
+
+ bool _isArc;
+ bool _needMoreInput;
+ bool _dataError;
+
+ UInt64 _phySize;
+
+ CObjectVector<CBlock> _blocks;
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidVa
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _blocks.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySize: if (_phySize != 0) prop = _phySize; break;
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
+ if (_dataError) v |= kpv_ErrorFlags_DataError;
+ prop = v;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CBlock &block = _blocks[index];
+ switch (propID)
+ {
+ case kpidSize: prop = (UInt64)block.Data.GetPos(); break;
+ case kpidVa: prop = block.Offset; break;
+ case kpidPath:
+ {
+ if (_blocks.Size() != 1)
+ {
+ char s[16];
+ ConvertUInt32ToString(index, s);
+ prop = s;
+ }
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+static inline int HexToByte(unsigned c)
+{
+ if (c >= '0' && c <= '9') return (int)(c - '0');
+ if (c >= 'A' && c <= 'F') return (int)(c - 'A' + 10);
+ if (c >= 'a' && c <= 'f') return (int)(c - 'a' + 10);
+ return -1;
+}
+
+static int Parse(const Byte *p)
+{
+ const int c1 = HexToByte(p[0]); if (c1 < 0) return -1;
+ const int c2 = HexToByte(p[1]); if (c2 < 0) return -1;
+ return (c1 << 4) | c2;
+}
+
+#define kType_Data 0
+#define kType_Eof 1
+#define kType_Seg 2
+// #define kType_CsIp 3
+#define kType_High 4
+// #define kType_Ip32 5
+
+#define kType_MAX 5
+
+#define IS_LINE_DELIMITER(c) ((c) == 0 || (c) == 10 || (c) == 13)
+
+API_FUNC_static_IsArc IsArc_Ihex(const Byte *p, size_t size)
+{
+ if (size < 1)
+ return k_IsArc_Res_NEED_MORE;
+ if (p[0] != ':')
+ return k_IsArc_Res_NO;
+ p++;
+ size--;
+
+ const unsigned kNumLinesToCheck = 3; // 1 line is OK also, but we don't want false detection
+
+ for (unsigned j = 0; j < kNumLinesToCheck; j++)
+ {
+ if (size < 4 * 2)
+ return k_IsArc_Res_NEED_MORE;
+
+ int num = Parse(p);
+ if (num < 0)
+ return k_IsArc_Res_NO;
+
+ int type = Parse(p + 6);
+ if (type < 0 || type > kType_MAX)
+ return k_IsArc_Res_NO;
+
+ unsigned numChars = ((unsigned)num + 5) * 2;
+ unsigned sum = 0;
+
+ for (unsigned i = 0; i < numChars; i += 2)
+ {
+ if (i + 2 > size)
+ return k_IsArc_Res_NEED_MORE;
+ int v = Parse(p + i);
+ if (v < 0)
+ return k_IsArc_Res_NO;
+ sum += (unsigned)v;
+ }
+
+ if ((sum & 0xFF) != 0)
+ return k_IsArc_Res_NO;
+
+ if (type == kType_Data)
+ {
+ // we don't want to open :0000000000 files
+ if (num == 0)
+ return k_IsArc_Res_NO;
+ }
+ else
+ {
+ if (type == kType_Eof)
+ {
+ if (num != 0)
+ return k_IsArc_Res_NO;
+ return k_IsArc_Res_YES;
+ }
+ if (p[2] != 0 ||
+ p[3] != 0 ||
+ p[4] != 0 ||
+ p[5] != 0)
+ return k_IsArc_Res_NO;
+ if (type == kType_Seg || type == kType_High)
+ {
+ if (num != 2)
+ return k_IsArc_Res_NO;
+ }
+ else
+ {
+ if (num != 4)
+ return k_IsArc_Res_NO;
+ }
+ }
+
+ p += numChars;
+ size -= numChars;
+
+ for (;;)
+ {
+ if (size == 0)
+ return k_IsArc_Res_NEED_MORE;
+ const Byte b = *p++;
+ size--;
+ if (IS_LINE_DELIMITER(b))
+ continue;
+ if (b == ':')
+ break;
+ return k_IsArc_Res_NO;
+ }
+ }
+
+ return k_IsArc_Res_YES;
+}
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *))
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ try
+ {
+ const unsigned kStartSize = (2 + (256 + 5) + 2) * 2;
+ Byte temp[kStartSize];
+ {
+ size_t size = kStartSize;
+ RINOK(ReadStream(stream, temp, &size))
+ UInt32 isArcRes = IsArc_Ihex(temp, size);
+ if (isArcRes == k_IsArc_Res_NO)
+ return S_FALSE;
+ if (isArcRes == k_IsArc_Res_NEED_MORE && size != kStartSize)
+ return S_FALSE;
+ }
+ _isArc = true;
+
+ RINOK(InStream_SeekToBegin(stream))
+ CInBuffer s;
+ if (!s.Create(1 << 15))
+ return E_OUTOFMEMORY;
+ s.SetStream(stream);
+ s.Init();
+
+ {
+ Byte b;
+ if (!s.ReadByte(b))
+ {
+ _needMoreInput = true;
+ return S_FALSE;
+ }
+ if (b != ':')
+ {
+ _dataError = true;
+ return S_FALSE;
+ }
+ }
+
+ UInt32 globalOffset = 0;
+
+ for (;;)
+ {
+ if (s.ReadBytes(temp, 2) != 2)
+ {
+ _needMoreInput = true;
+ return S_FALSE;
+ }
+ const int num = Parse(temp);
+ if (num < 0)
+ {
+ _dataError = true;
+ return S_FALSE;
+ }
+
+ {
+ size_t numPairs = ((unsigned)num + 4);
+ size_t numBytes = numPairs * 2;
+ if (s.ReadBytes(temp, numBytes) != numBytes)
+ {
+ _needMoreInput = true;
+ return S_FALSE;
+ }
+
+ unsigned sum = (unsigned)num;
+ for (size_t i = 0; i < numPairs; i++)
+ {
+ const int a = Parse(temp + i * 2);
+ if (a < 0)
+ {
+ _dataError = true;
+ return S_FALSE;
+ }
+ temp[i] = (Byte)a;
+ sum += (unsigned)a;
+ }
+ if ((sum & 0xFF) != 0)
+ {
+ _dataError = true;
+ return S_FALSE;
+ }
+ }
+
+ unsigned type = temp[2];
+ if (type > kType_MAX)
+ {
+ _dataError = true;
+ return S_FALSE;
+ }
+
+ UInt32 a = GetBe16(temp);
+
+ if (type == kType_Data)
+ {
+ if (num == 0)
+ {
+ // we don't want to open :0000000000 files
+ // maybe it can mean EOF in old-style files?
+ _dataError = true;
+ return S_FALSE;
+ }
+ // if (num != 0)
+ {
+ UInt32 offs = globalOffset + a;
+ CBlock *block = NULL;
+ if (!_blocks.IsEmpty())
+ {
+ block = &_blocks.Back();
+ if (block->Offset + block->Data.GetPos() != offs)
+ block = NULL;
+ }
+ if (!block)
+ {
+ block = &_blocks.AddNew();
+ block->Offset = offs;
+ }
+ block->Data.AddData(temp + 3, (unsigned)num);
+ }
+ }
+ else if (type == kType_Eof)
+ {
+ _phySize = s.GetProcessedSize();
+ {
+ Byte b;
+ if (s.ReadByte(b))
+ {
+ if (b == 10)
+ _phySize++;
+ else if (b == 13)
+ {
+ _phySize++;
+ if (s.ReadByte(b))
+ {
+ if (b == 10)
+ _phySize++;
+ }
+ }
+ }
+ }
+ return S_OK;
+ }
+ else
+ {
+ if (a != 0)
+ {
+ _dataError = true;
+ return S_FALSE;
+ }
+ if (type == kType_Seg || type == kType_High)
+ {
+ if (num != 2)
+ {
+ _dataError = true;
+ return S_FALSE;
+ }
+ UInt32 d = GetBe16(temp + 3);
+ globalOffset = d << (type == kType_Seg ? 4 : 16);
+ }
+ else
+ {
+ if (num != 4)
+ {
+ _dataError = true;
+ return S_FALSE;
+ }
+ }
+ }
+
+ for (;;)
+ {
+ Byte b;
+ if (!s.ReadByte(b))
+ {
+ _needMoreInput = true;
+ return S_FALSE;
+ }
+ if (IS_LINE_DELIMITER(b))
+ continue;
+ if (b == ':')
+ break;
+ _dataError = true;
+ return S_FALSE;
+ }
+ }
+ }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ }
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _phySize = 0;
+
+ _isArc = false;
+ _needMoreInput = false;
+ _dataError = false;
+
+ _blocks.Clear();
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _blocks.Size();
+ if (numItems == 0)
+ return S_OK;
+
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _blocks[allFilesMode ? i : indices[i]].Data.GetPos();
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+ UInt64 currentItemSize;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ currentItemSize = 0;
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur())
+
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CByteDynamicBuffer &data = _blocks[index].Data;
+ currentItemSize = data.GetPos();
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+ if (!testMode && !realOutStream)
+ continue;
+
+ extractCallback->PrepareOperation(askMode);
+
+ if (realOutStream)
+ {
+ RINOK(WriteStream(realOutStream, (const Byte *)data, data.GetPos()))
+ }
+
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ }
+
+ lps->InSize = lps->OutSize = currentTotalSize;
+ return lps->SetCur();
+
+ COM_TRY_END
+}
+
+// k_Signature: { ':', '1' }
+
+REGISTER_ARC_I_NO_SIG(
+ "IHex", "ihex", NULL, 0xCD,
+ 0,
+ NArcInfoFlags::kStartOpen,
+ IsArc_Ihex)
+
+}}
diff --git a/CPP/7zip/Archive/Iso/IsoHandler.cpp b/CPP/7zip/Archive/Iso/IsoHandler.cpp
new file mode 100644
index 0000000..0c63c71
--- /dev/null
+++ b/CPP/7zip/Archive/Iso/IsoHandler.cpp
@@ -0,0 +1,486 @@
+// IsoHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/MyLinux.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../Common/ItemNameUtils.h"
+
+#include "IsoHandler.h"
+
+using namespace NWindows;
+using namespace NTime;
+
+namespace NArchive {
+namespace NIso {
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ // kpidCTime,
+ // kpidATime,
+ kpidPosixAttrib,
+ // kpidUserId,
+ // kpidGroupId,
+ // kpidLinks,
+ kpidSymLink
+};
+
+static const Byte kArcProps[] =
+{
+ kpidComment,
+ kpidCTime,
+ kpidMTime,
+ // kpidHeadersSize
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */))
+{
+ COM_TRY_BEGIN
+ Close();
+ {
+ RINOK(_archive.Open(stream))
+ _stream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _archive.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _archive.Refs.Size() + _archive.BootEntries.Size();
+ return S_OK;
+}
+
+static void AddString(AString &s, const char *name, const Byte *p, unsigned size)
+{
+ unsigned i;
+ for (i = 0; i < size && p[i]; i++);
+ for (; i > 0 && p[i - 1] == ' '; i--);
+ if (i != 0)
+ {
+ AString d;
+ d.SetFrom((const char *)p, i);
+ s += '\n';
+ s += name;
+ s += ": ";
+ s += d;
+ }
+}
+
+#define ADD_STRING(n, v) AddString(s, n, vol. v, sizeof(vol. v))
+
+static void AddErrorMessage(AString &s, const char *message)
+{
+ if (!s.IsEmpty())
+ s += ". ";
+ s += message;
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ if (_stream)
+ {
+ const CVolumeDescriptor &vol = _archive.VolDescs[_archive.MainVolDescIndex];
+ switch (propID)
+ {
+ case kpidComment:
+ {
+ AString s;
+ ADD_STRING("System", SystemId);
+ ADD_STRING("Volume", VolumeId);
+ ADD_STRING("VolumeSet", VolumeSetId);
+ ADD_STRING("Publisher", PublisherId);
+ ADD_STRING("Preparer", DataPreparerId);
+ ADD_STRING("Application", ApplicationId);
+ ADD_STRING("Copyright", CopyrightFileId);
+ ADD_STRING("Abstract", AbstractFileId);
+ ADD_STRING("Bib", BibFileId);
+ prop = s;
+ break;
+ }
+ case kpidCTime: { vol.CTime.GetFileTime(prop); break; }
+ case kpidMTime: { vol.MTime.GetFileTime(prop); break; }
+ }
+ }
+
+ switch (propID)
+ {
+ case kpidPhySize: prop = _archive.PhySize; break;
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_archive.IsArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (_archive.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
+ if (_archive.HeadersError) v |= kpv_ErrorFlags_HeadersError;
+ prop = v;
+ break;
+ }
+
+ case kpidError:
+ {
+ AString s;
+ if (_archive.IncorrectBigEndian)
+ AddErrorMessage(s, "Incorrect big-endian headers");
+ if (_archive.SelfLinkedDirs)
+ AddErrorMessage(s, "Self-linked directory");
+ if (_archive.TooDeepDirs)
+ AddErrorMessage(s, "Too deep directory levels");
+ if (!s.IsEmpty())
+ prop = s;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ if (index >= (UInt32)_archive.Refs.Size())
+ {
+ index -= _archive.Refs.Size();
+ const CBootInitialEntry &be = _archive.BootEntries[index];
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ AString s ("[BOOT]" STRING_PATH_SEPARATOR);
+ if (_archive.BootEntries.Size() != 1)
+ {
+ s.Add_UInt32(index + 1);
+ s.Add_Minus();
+ }
+ s += be.GetName();
+ prop = s;
+ break;
+ }
+ case kpidIsDir: prop = false; break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)_archive.GetBootItemSize(index);
+ break;
+ }
+ }
+ else
+ {
+ const CRef &ref = _archive.Refs[index];
+ const CDir &item = ref.Dir->_subItems[ref.Index];
+ switch (propID)
+ {
+ case kpidPath:
+ // if (item.FileId.GetCapacity() >= 0)
+ {
+ UString s;
+ if (_archive.IsJoliet())
+ item.GetPathU(s);
+ else
+ s = MultiByteToUnicodeString(item.GetPath(_archive.IsSusp, _archive.SuspSkipSize), CP_OEMCP);
+
+ if (s.Len() >= 2 && s[s.Len() - 2] == ';' && s.Back() == '1')
+ s.DeleteFrom(s.Len() - 2);
+
+ if (!s.IsEmpty() && s.Back() == L'.')
+ s.DeleteBack();
+
+ NItemName::ReplaceToOsSlashes_Remove_TailSlash(s);
+ prop = s;
+ }
+ break;
+
+ case kpidSymLink:
+ if (_archive.IsSusp)
+ {
+ UInt32 mode;
+ if (item.GetPx(_archive.SuspSkipSize, k_Px_Mode, mode))
+ {
+ if (MY_LIN_S_ISLNK(mode))
+ {
+ AString s8;
+ if (item.GetSymLink(_archive.SuspSkipSize, s8))
+ {
+ UString s = MultiByteToUnicodeString(s8, CP_OEMCP);
+ prop = s;
+ }
+ }
+ }
+ }
+ break;
+
+
+ case kpidPosixAttrib:
+ /*
+ case kpidLinks:
+ case kpidUserId:
+ case kpidGroupId:
+ */
+ {
+ if (_archive.IsSusp)
+ {
+ UInt32 t = 0;
+ switch (propID)
+ {
+ case kpidPosixAttrib: t = k_Px_Mode; break;
+ /*
+ case kpidLinks: t = k_Px_Links; break;
+ case kpidUserId: t = k_Px_User; break;
+ case kpidGroupId: t = k_Px_Group; break;
+ */
+ }
+ UInt32 v;
+ if (item.GetPx(_archive.SuspSkipSize, t, v))
+ prop = v;
+ }
+ break;
+ }
+
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize:
+ case kpidPackSize:
+ if (!item.IsDir())
+ prop = (UInt64)ref.TotalSize;
+ break;
+
+ case kpidMTime:
+ // case kpidCTime:
+ // case kpidATime:
+ {
+ // if
+ item.DateTime.GetFileTime(prop);
+ /*
+ else
+ {
+ UInt32 t = 0;
+ switch (propID)
+ {
+ case kpidMTime: t = k_Tf_MTime; break;
+ case kpidCTime: t = k_Tf_CTime; break;
+ case kpidATime: t = k_Tf_ATime; break;
+ }
+ CRecordingDateTime dt;
+ if (item.GetTf(_archive.SuspSkipSize, t, dt))
+ {
+ FILETIME utc;
+ if (dt.GetFileTime(utc))
+ prop = utc;
+ }
+ }
+ */
+ break;
+ }
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _archive.Refs.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 index = (allFilesMode ? i : indices[i]);
+ if (index < (UInt32)_archive.Refs.Size())
+ {
+ const CRef &ref = _archive.Refs[index];
+ const CDir &item = ref.Dir->_subItems[ref.Index];
+ if (!item.IsDir())
+ totalSize += ref.TotalSize;
+ }
+ else
+ totalSize += _archive.GetBootItemSize(index - _archive.Refs.Size());
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+ UInt64 currentItemSize;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur())
+ currentItemSize = 0;
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+ UInt64 blockIndex;
+ if (index < (UInt32)_archive.Refs.Size())
+ {
+ const CRef &ref = _archive.Refs[index];
+ const CDir &item = ref.Dir->_subItems[ref.Index];
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+ currentItemSize = ref.TotalSize;
+ blockIndex = item.ExtentLocation;
+ }
+ else
+ {
+ unsigned bootIndex = index - _archive.Refs.Size();
+ const CBootInitialEntry &be = _archive.BootEntries[bootIndex];
+ currentItemSize = _archive.GetBootItemSize(bootIndex);
+ blockIndex = be.LoadRBA;
+ }
+
+
+ if (!testMode && !realOutStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode))
+
+ bool isOK = true;
+ if (index < (UInt32)_archive.Refs.Size())
+ {
+ const CRef &ref = _archive.Refs[index];
+ UInt64 offset = 0;
+ for (UInt32 e = 0; e < ref.NumExtents; e++)
+ {
+ const CDir &item2 = ref.Dir->_subItems[ref.Index + e];
+ if (item2.Size == 0)
+ continue;
+ lps->InSize = lps->OutSize = currentTotalSize + offset;
+ RINOK(InStream_SeekSet(_stream, (UInt64)item2.ExtentLocation * kBlockSize))
+ streamSpec->Init(item2.Size);
+ RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress))
+ if (copyCoderSpec->TotalSize != item2.Size)
+ {
+ isOK = false;
+ break;
+ }
+ offset += item2.Size;
+ }
+ }
+ else
+ {
+ RINOK(InStream_SeekSet(_stream, (UInt64)blockIndex * kBlockSize))
+ streamSpec->Init(currentItemSize);
+ RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress))
+ if (copyCoderSpec->TotalSize != currentItemSize)
+ isOK = false;
+ }
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(isOK ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ *stream = NULL;
+ UInt64 blockIndex;
+ UInt64 currentItemSize;
+
+ if (index < _archive.Refs.Size())
+ {
+ const CRef &ref = _archive.Refs[index];
+ const CDir &item = ref.Dir->_subItems[ref.Index];
+ if (item.IsDir())
+ return S_FALSE;
+
+ if (ref.NumExtents > 1)
+ {
+ CExtentsStream *extentStreamSpec = new CExtentsStream();
+ CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec;
+
+ extentStreamSpec->Stream = _stream;
+
+ UInt64 virtOffset = 0;
+ for (UInt32 i = 0; i < ref.NumExtents; i++)
+ {
+ const CDir &item2 = ref.Dir->_subItems[ref.Index + i];
+ if (item2.Size == 0)
+ continue;
+ CSeekExtent se;
+ se.Phy = (UInt64)item2.ExtentLocation * kBlockSize;
+ se.Virt = virtOffset;
+ extentStreamSpec->Extents.Add(se);
+ virtOffset += item2.Size;
+ }
+ if (virtOffset != ref.TotalSize)
+ return S_FALSE;
+ CSeekExtent se;
+ se.Phy = 0;
+ se.Virt = virtOffset;
+ extentStreamSpec->Extents.Add(se);
+ extentStreamSpec->Init();
+ *stream = extentStream.Detach();
+ return S_OK;
+ }
+
+ currentItemSize = item.Size;
+ blockIndex = item.ExtentLocation;
+ }
+ else
+ {
+ unsigned bootIndex = index - _archive.Refs.Size();
+ const CBootInitialEntry &be = _archive.BootEntries[bootIndex];
+ currentItemSize = _archive.GetBootItemSize(bootIndex);
+ blockIndex = be.LoadRBA;
+ }
+
+ return CreateLimitedInStream(_stream, (UInt64)blockIndex * kBlockSize, currentItemSize, stream);
+ COM_TRY_END
+}
+
+}}
diff --git a/CPP/7zip/Archive/Iso/IsoHandler.h b/CPP/7zip/Archive/Iso/IsoHandler.h
new file mode 100644
index 0000000..507814a
--- /dev/null
+++ b/CPP/7zip/Archive/Iso/IsoHandler.h
@@ -0,0 +1,24 @@
+// IsoHandler.h
+
+#ifndef ZIP7_INC_ISO_HANDLER_H
+#define ZIP7_INC_ISO_HANDLER_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../IArchive.h"
+
+#include "IsoIn.h"
+
+namespace NArchive {
+namespace NIso {
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IInArchiveGetStream
+)
+ CMyComPtr<IInStream> _stream;
+ CInArchive _archive;
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Iso/IsoHeader.cpp b/CPP/7zip/Archive/Iso/IsoHeader.cpp
new file mode 100644
index 0000000..3b59060
--- /dev/null
+++ b/CPP/7zip/Archive/Iso/IsoHeader.cpp
@@ -0,0 +1,12 @@
+// Archive/Iso/Header.h
+
+#include "StdAfx.h"
+
+#include "IsoHeader.h"
+
+namespace NArchive {
+namespace NIso {
+
+const char * const kElToritoSpec = "EL TORITO SPECIFICATION\0\0\0\0\0\0\0\0\0";
+
+}}
diff --git a/CPP/7zip/Archive/Iso/IsoHeader.h b/CPP/7zip/Archive/Iso/IsoHeader.h
new file mode 100644
index 0000000..0b14c9f
--- /dev/null
+++ b/CPP/7zip/Archive/Iso/IsoHeader.h
@@ -0,0 +1,64 @@
+// Archive/IsoHeader.h
+
+#ifndef ZIP7_INC_ARCHIVE_ISO_HEADER_H
+#define ZIP7_INC_ARCHIVE_ISO_HEADER_H
+
+#include "../../../Common/MyTypes.h"
+
+namespace NArchive {
+namespace NIso {
+
+namespace NVolDescType
+{
+ const Byte kBootRecord = 0;
+ const Byte kPrimaryVol = 1;
+ const Byte kSupplementaryVol = 2;
+ const Byte kVolParttition = 3;
+ const Byte kTerminator = 255;
+}
+
+const Byte kVersion = 1;
+
+namespace NFileFlags
+{
+ const Byte kDirectory = 1 << 1;
+ const Byte kNonFinalExtent = 1 << 7;
+}
+
+extern const char * const kElToritoSpec;
+
+const UInt32 kStartPos = 0x8000;
+
+namespace NBootEntryId
+{
+ const Byte kValidationEntry = 1;
+ const Byte kInitialEntryNotBootable = 0;
+ const Byte kInitialEntryBootable = 0x88;
+
+ const Byte kMoreHeaders = 0x90;
+ const Byte kFinalHeader = 0x91;
+
+ const Byte kExtensionIndicator = 0x44;
+}
+
+namespace NBootPlatformId
+{
+ const Byte kX86 = 0;
+ const Byte kPowerPC = 1;
+ const Byte kMac = 2;
+}
+
+const Byte kBootMediaTypeMask = 0xF;
+
+namespace NBootMediaType
+{
+ const Byte kNoEmulation = 0;
+ const Byte k1d2Floppy = 1;
+ const Byte k1d44Floppy = 2;
+ const Byte k2d88Floppy = 3;
+ const Byte kHardDisk = 4;
+}
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Iso/IsoIn.cpp b/CPP/7zip/Archive/Iso/IsoIn.cpp
new file mode 100644
index 0000000..1d3a42f
--- /dev/null
+++ b/CPP/7zip/Archive/Iso/IsoIn.cpp
@@ -0,0 +1,693 @@
+// Archive/IsoIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/MyException.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "../HandlerCont.h"
+
+#include "IsoIn.h"
+
+namespace NArchive {
+namespace NIso {
+
+struct CUnexpectedEndException {};
+struct CHeaderErrorException {};
+struct CEndianErrorException {};
+
+static const char * const kMediaTypes[] =
+{
+ "NoEmul"
+ , "1.2M"
+ , "1.44M"
+ , "2.88M"
+ , "HardDisk"
+};
+
+bool CBootInitialEntry::Parse(const Byte *p)
+{
+ Bootable = (p[0] == NBootEntryId::kInitialEntryBootable);
+ BootMediaType = p[1];
+ LoadSegment = GetUi16(p + 2);
+ SystemType = p[4];
+ SectorCount = GetUi16(p + 6);
+ LoadRBA = GetUi32(p + 8);
+ memcpy(VendorSpec, p + 12, 20);
+ if (p[5] != 0)
+ return false;
+ if (p[0] != NBootEntryId::kInitialEntryBootable
+ && p[0] != NBootEntryId::kInitialEntryNotBootable)
+ return false;
+ return true;
+}
+
+AString CBootInitialEntry::GetName() const
+{
+ AString s (Bootable ? "Boot" : "NotBoot");
+ s.Add_Minus();
+
+ if (BootMediaType < Z7_ARRAY_SIZE(kMediaTypes))
+ s += kMediaTypes[BootMediaType];
+ else
+ s.Add_UInt32(BootMediaType);
+
+ if (VendorSpec[0] == 1)
+ {
+ // "Language and Version Information (IBM)"
+
+ unsigned i;
+ for (i = 1; i < sizeof(VendorSpec); i++)
+ if (VendorSpec[i] > 0x7F)
+ break;
+ if (i == sizeof(VendorSpec))
+ {
+ s.Add_Minus();
+ for (i = 1; i < sizeof(VendorSpec); i++)
+ {
+ char c = (char)VendorSpec[i];
+ if (c == 0)
+ break;
+ if (c == '\\' || c == '/')
+ c = '_';
+ s += c;
+ }
+ }
+ }
+
+ s += ".img";
+ return s;
+}
+
+Byte CInArchive::ReadByte()
+{
+ if (m_BufferPos >= kBlockSize)
+ m_BufferPos = 0;
+ if (m_BufferPos == 0)
+ {
+ size_t processed = kBlockSize;
+ HRESULT res = ReadStream(_stream, m_Buffer, &processed);
+ if (res != S_OK)
+ throw CSystemException(res);
+ if (processed != kBlockSize)
+ throw CUnexpectedEndException();
+ UInt64 end = _position + processed;
+ if (PhySize < end)
+ PhySize = end;
+ }
+ Byte b = m_Buffer[m_BufferPos++];
+ _position++;
+ return b;
+}
+
+void CInArchive::ReadBytes(Byte *data, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ data[i] = ReadByte();
+}
+
+void CInArchive::Skip(size_t size)
+{
+ while (size-- != 0)
+ ReadByte();
+}
+
+void CInArchive::SkipZeros(size_t size)
+{
+ while (size-- != 0)
+ {
+ Byte b = ReadByte();
+ if (b != 0)
+ throw CHeaderErrorException();
+ }
+}
+
+UInt16 CInArchive::ReadUInt16()
+{
+ Byte b[4];
+ ReadBytes(b, 4);
+ UInt32 val = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ if (b[i] != b[3 - i])
+ IncorrectBigEndian = true;
+ val |= ((UInt32)(b[i]) << (8 * i));
+ }
+ return (UInt16)val;
+}
+
+UInt32 CInArchive::ReadUInt32Le()
+{
+ UInt32 val = 0;
+ for (int i = 0; i < 4; i++)
+ val |= ((UInt32)(ReadByte()) << (8 * i));
+ return val;
+}
+
+UInt32 CInArchive::ReadUInt32Be()
+{
+ UInt32 val = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ val <<= 8;
+ val |= ReadByte();
+ }
+ return val;
+}
+
+UInt32 CInArchive::ReadUInt32()
+{
+ Byte b[8];
+ ReadBytes(b, 8);
+ UInt32 val = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ if (b[i] != b[7 - i])
+ throw CEndianErrorException();
+ val |= ((UInt32)(b[i]) << (8 * i));
+ }
+ return val;
+}
+
+UInt32 CInArchive::ReadDigits(int numDigits)
+{
+ UInt32 res = 0;
+ for (int i = 0; i < numDigits; i++)
+ {
+ Byte b = ReadByte();
+ if (b < '0' || b > '9')
+ {
+ if (b == 0 || b == ' ') // it's bug in some CD's
+ b = '0';
+ else
+ throw CHeaderErrorException();
+ }
+ UInt32 d = (UInt32)(b - '0');
+ res *= 10;
+ res += d;
+ }
+ return res;
+}
+
+void CInArchive::ReadDateTime(CDateTime &d)
+{
+ d.Year = (UInt16)ReadDigits(4);
+ d.Month = (Byte)ReadDigits(2);
+ d.Day = (Byte)ReadDigits(2);
+ d.Hour = (Byte)ReadDigits(2);
+ d.Minute = (Byte)ReadDigits(2);
+ d.Second = (Byte)ReadDigits(2);
+ d.Hundredths = (Byte)ReadDigits(2);
+ d.GmtOffset = (signed char)ReadByte();
+}
+
+void CInArchive::ReadBootRecordDescriptor(CBootRecordDescriptor &d)
+{
+ ReadBytes(d.BootSystemId, sizeof(d.BootSystemId));
+ ReadBytes(d.BootId, sizeof(d.BootId));
+ ReadBytes(d.BootSystemUse, sizeof(d.BootSystemUse));
+}
+
+void CInArchive::ReadRecordingDateTime(CRecordingDateTime &t)
+{
+ t.Year = ReadByte();
+ t.Month = ReadByte();
+ t.Day = ReadByte();
+ t.Hour = ReadByte();
+ t.Minute = ReadByte();
+ t.Second = ReadByte();
+ t.GmtOffset = (signed char)ReadByte();
+}
+
+void CInArchive::ReadDirRecord2(CDirRecord &r, Byte len)
+{
+ r.ExtendedAttributeRecordLen = ReadByte();
+ if (r.ExtendedAttributeRecordLen != 0)
+ throw CHeaderErrorException();
+ r.ExtentLocation = ReadUInt32();
+ r.Size = ReadUInt32();
+ ReadRecordingDateTime(r.DateTime);
+ r.FileFlags = ReadByte();
+ r.FileUnitSize = ReadByte();
+ r.InterleaveGapSize = ReadByte();
+ r.VolSequenceNumber = ReadUInt16();
+ Byte idLen = ReadByte();
+ r.FileId.Alloc(idLen);
+ ReadBytes((Byte *)r.FileId, idLen);
+ unsigned padSize = 1 - (idLen & 1);
+
+ // SkipZeros(padSize);
+ Skip(padSize); // it's bug in some cd's. Must be zeros
+
+ unsigned curPos = 33 + idLen + padSize;
+ if (curPos > len)
+ throw CHeaderErrorException();
+ unsigned rem = len - curPos;
+ r.SystemUse.Alloc(rem);
+ ReadBytes((Byte *)r.SystemUse, rem);
+}
+
+void CInArchive::ReadDirRecord(CDirRecord &r)
+{
+ Byte len = ReadByte();
+ // Some CDs can have incorrect value len = 48 ('0') in VolumeDescriptor.
+ // But maybe we must use real "len" for other records.
+ len = 34;
+ ReadDirRecord2(r, len);
+}
+
+void CInArchive::ReadVolumeDescriptor(CVolumeDescriptor &d)
+{
+ d.VolFlags = ReadByte();
+ ReadBytes(d.SystemId, sizeof(d.SystemId));
+ ReadBytes(d.VolumeId, sizeof(d.VolumeId));
+ SkipZeros(8);
+ d.VolumeSpaceSize = ReadUInt32();
+ ReadBytes(d.EscapeSequence, sizeof(d.EscapeSequence));
+ d.VolumeSetSize = ReadUInt16();
+ d.VolumeSequenceNumber = ReadUInt16();
+ d.LogicalBlockSize = ReadUInt16();
+ d.PathTableSize = ReadUInt32();
+ d.LPathTableLocation = ReadUInt32Le();
+ d.LOptionalPathTableLocation = ReadUInt32Le();
+ d.MPathTableLocation = ReadUInt32Be();
+ d.MOptionalPathTableLocation = ReadUInt32Be();
+ ReadDirRecord(d.RootDirRecord);
+ ReadBytes(d.VolumeSetId, sizeof(d.VolumeSetId));
+ ReadBytes(d.PublisherId, sizeof(d.PublisherId));
+ ReadBytes(d.DataPreparerId, sizeof(d.DataPreparerId));
+ ReadBytes(d.ApplicationId, sizeof(d.ApplicationId));
+ ReadBytes(d.CopyrightFileId, sizeof(d.CopyrightFileId));
+ ReadBytes(d.AbstractFileId, sizeof(d.AbstractFileId));
+ ReadBytes(d.BibFileId, sizeof(d.BibFileId));
+ ReadDateTime(d.CTime);
+ ReadDateTime(d.MTime);
+ ReadDateTime(d.ExpirationTime);
+ ReadDateTime(d.EffectiveTime);
+ d.FileStructureVersion = ReadByte(); // = 1
+ SkipZeros(1);
+ ReadBytes(d.ApplicationUse, sizeof(d.ApplicationUse));
+
+ // Most ISO contains zeros in the following field (reserved for future standardization).
+ // But some ISO programs write some data to that area.
+ // So we disable check for zeros.
+ Skip(653); // SkipZeros(653);
+}
+
+static const Byte kSig_CD001[5] = { 'C', 'D', '0', '0', '1' };
+
+/*
+static const Byte kSig_NSR02[5] = { 'N', 'S', 'R', '0', '2' };
+static const Byte kSig_NSR03[5] = { 'N', 'S', 'R', '0', '3' };
+static const Byte kSig_BEA01[5] = { 'B', 'E', 'A', '0', '1' };
+static const Byte kSig_TEA01[5] = { 'T', 'E', 'A', '0', '1' };
+*/
+
+static inline bool CheckSignature(const Byte *sig, const Byte *data)
+{
+ for (int i = 0; i < 5; i++)
+ if (sig[i] != data[i])
+ return false;
+ return true;
+}
+
+void CInArchive::SeekToBlock(UInt32 blockIndex)
+{
+ const HRESULT res = _stream->Seek(
+ (Int64)((UInt64)blockIndex * VolDescs[MainVolDescIndex].LogicalBlockSize),
+ STREAM_SEEK_SET, &_position);
+ if (res != S_OK)
+ throw CSystemException(res);
+ m_BufferPos = 0;
+}
+
+static const int kNumLevelsMax = 256;
+
+void CInArchive::ReadDir(CDir &d, int level)
+{
+ if (!d.IsDir())
+ return;
+ if (level > kNumLevelsMax)
+ {
+ TooDeepDirs = true;
+ return;
+ }
+
+ {
+ FOR_VECTOR (i, UniqStartLocations)
+ if (UniqStartLocations[i] == d.ExtentLocation)
+ {
+ SelfLinkedDirs = true;
+ return;
+ }
+ UniqStartLocations.Add(d.ExtentLocation);
+ }
+
+ SeekToBlock(d.ExtentLocation);
+ UInt64 startPos = _position;
+
+ bool firstItem = true;
+ for (;;)
+ {
+ UInt64 offset = _position - startPos;
+ if (offset >= d.Size)
+ break;
+ Byte len = ReadByte();
+ if (len == 0)
+ continue;
+ CDir subItem;
+ ReadDirRecord2(subItem, len);
+ if (firstItem && level == 0)
+ IsSusp = subItem.CheckSusp(SuspSkipSize);
+
+ if (!subItem.IsSystemItem())
+ d._subItems.Add(subItem);
+
+ firstItem = false;
+ }
+ FOR_VECTOR (i, d._subItems)
+ ReadDir(d._subItems[i], level + 1);
+
+ UniqStartLocations.DeleteBack();
+}
+
+void CInArchive::CreateRefs(CDir &d)
+{
+ if (!d.IsDir())
+ return;
+ for (unsigned i = 0; i < d._subItems.Size();)
+ {
+ CRef ref;
+ CDir &subItem = d._subItems[i];
+ subItem.Parent = &d;
+ ref.Dir = &d;
+ ref.Index = i++;
+ ref.NumExtents = 1;
+ ref.TotalSize = subItem.Size;
+ if (subItem.IsNonFinalExtent())
+ {
+ for (;;)
+ {
+ if (i == d._subItems.Size())
+ {
+ HeadersError = true;
+ break;
+ }
+ const CDir &next = d._subItems[i];
+ if (!subItem.AreMultiPartEqualWith(next))
+ break;
+ i++;
+ ref.NumExtents++;
+ ref.TotalSize += next.Size;
+ if (!next.IsNonFinalExtent())
+ break;
+ }
+ }
+ Refs.Add(ref);
+ CreateRefs(subItem);
+ }
+}
+
+void CInArchive::ReadBootInfo()
+{
+ if (!_bootIsDefined)
+ return;
+ HeadersError = true;
+
+ if (memcmp(_bootDesc.BootSystemId, kElToritoSpec, sizeof(_bootDesc.BootSystemId)) != 0)
+ return;
+
+ UInt32 blockIndex = GetUi32(_bootDesc.BootSystemUse);
+ SeekToBlock(blockIndex);
+
+ Byte buf[32];
+ ReadBytes(buf, 32);
+
+ if (buf[0] != NBootEntryId::kValidationEntry
+ || buf[2] != 0
+ || buf[3] != 0
+ || buf[30] != 0x55
+ || buf[31] != 0xAA)
+ return;
+
+ {
+ UInt32 sum = 0;
+ for (unsigned i = 0; i < 32; i += 2)
+ sum += GetUi16(buf + i);
+ if ((sum & 0xFFFF) != 0)
+ return;
+ /*
+ CBootValidationEntry e;
+ e.PlatformId = buf[1];
+ memcpy(e.Id, buf + 4, sizeof(e.Id));
+ // UInt16 checkSum = GetUi16(p + 28);
+ */
+ }
+
+ ReadBytes(buf, 32);
+ {
+ CBootInitialEntry e;
+ if (!e.Parse(buf))
+ return;
+ BootEntries.Add(e);
+ }
+
+ bool error = false;
+
+ for (;;)
+ {
+ ReadBytes(buf, 32);
+ Byte headerIndicator = buf[0];
+ if (headerIndicator != NBootEntryId::kMoreHeaders
+ && headerIndicator != NBootEntryId::kFinalHeader)
+ break;
+
+ // Section Header
+ // Byte platform = p[1];
+ unsigned numEntries = GetUi16(buf + 2);
+ // id[28]
+
+ for (unsigned i = 0; i < numEntries; i++)
+ {
+ ReadBytes(buf, 32);
+ CBootInitialEntry e;
+ if (!e.Parse(buf))
+ {
+ error = true;
+ break;
+ }
+ if (e.BootMediaType & (1 << 5))
+ {
+ // Section entry extension
+ for (unsigned j = 0;; j++)
+ {
+ ReadBytes(buf, 32);
+ if (j > 32 || buf[0] != NBootEntryId::kExtensionIndicator)
+ {
+ error = true;
+ break;
+ }
+ if ((buf[1] & (1 << 5)) == 0)
+ break;
+ // info += (buf + 2, 30)
+ }
+ }
+ BootEntries.Add(e);
+ }
+
+ if (headerIndicator != NBootEntryId::kMoreHeaders)
+ break;
+ }
+
+ HeadersError = error;
+}
+
+HRESULT CInArchive::Open2()
+{
+ _position = 0;
+ RINOK(InStream_GetSize_SeekToEnd(_stream, _fileSize))
+ if (_fileSize < kStartPos)
+ return S_FALSE;
+ RINOK(_stream->Seek(kStartPos, STREAM_SEEK_SET, &_position))
+
+ PhySize = _position;
+ m_BufferPos = 0;
+ // BlockSize = kBlockSize;
+
+ for (;;)
+ {
+ Byte sig[7];
+ ReadBytes(sig, 7);
+ Byte ver = sig[6];
+
+ if (!CheckSignature(kSig_CD001, sig + 1))
+ {
+ return S_FALSE;
+ /*
+ if (sig[0] != 0 || ver != 1)
+ break;
+ if (CheckSignature(kSig_BEA01, sig + 1))
+ {
+ }
+ else if (CheckSignature(kSig_TEA01, sig + 1))
+ {
+ break;
+ }
+ else if (CheckSignature(kSig_NSR02, sig + 1))
+ {
+ }
+ else
+ break;
+ SkipZeros(0x800 - 7);
+ continue;
+ */
+ }
+
+ // version = 2 for ISO 9660:1999?
+ if (ver > 2)
+ return S_FALSE;
+
+ if (sig[0] == NVolDescType::kTerminator)
+ {
+ break;
+ // Skip(0x800 - 7);
+ // continue;
+ }
+
+ switch (sig[0])
+ {
+ case NVolDescType::kBootRecord:
+ {
+ _bootIsDefined = true;
+ ReadBootRecordDescriptor(_bootDesc);
+ break;
+ }
+ case NVolDescType::kPrimaryVol:
+ case NVolDescType::kSupplementaryVol:
+ {
+ // some ISOs have two PrimaryVols.
+ CVolumeDescriptor vd;
+ ReadVolumeDescriptor(vd);
+ if (sig[0] == NVolDescType::kPrimaryVol)
+ {
+ // some burners write "Joliet" Escape Sequence to primary volume
+ memset(vd.EscapeSequence, 0, sizeof(vd.EscapeSequence));
+ }
+ VolDescs.Add(vd);
+ break;
+ }
+ default:
+ break;
+ }
+ }
+
+ if (VolDescs.IsEmpty())
+ return S_FALSE;
+ for (MainVolDescIndex = (int)VolDescs.Size() - 1; MainVolDescIndex > 0; MainVolDescIndex--)
+ if (VolDescs[MainVolDescIndex].IsJoliet())
+ break;
+ /* FIXME: some volume can contain Rock Ridge, that is better than
+ Joliet volume. So we need some way to detect such case */
+ // MainVolDescIndex = 0; // to read primary volume
+ const CVolumeDescriptor &vd = VolDescs[MainVolDescIndex];
+ if (vd.LogicalBlockSize != kBlockSize)
+ return S_FALSE;
+
+ IsArc = true;
+
+ (CDirRecord &)_rootDir = vd.RootDirRecord;
+ ReadDir(_rootDir, 0);
+ CreateRefs(_rootDir);
+ ReadBootInfo();
+
+ {
+ FOR_VECTOR (i, Refs)
+ {
+ const CRef &ref = Refs[i];
+ for (UInt32 j = 0; j < ref.NumExtents; j++)
+ {
+ const CDir &item = ref.Dir->_subItems[ref.Index + j];
+ if (!item.IsDir() && item.Size != 0)
+ UpdatePhySize(item.ExtentLocation, item.Size);
+ }
+ }
+ }
+ {
+ FOR_VECTOR (i, BootEntries)
+ {
+ const CBootInitialEntry &be = BootEntries[i];
+ UpdatePhySize(be.LoadRBA, GetBootItemSize(i));
+ }
+ }
+
+ if (PhySize < _fileSize)
+ {
+ UInt64 rem = _fileSize - PhySize;
+ const UInt64 kRemMax = 1 << 21;
+ if (rem <= kRemMax)
+ {
+ RINOK(InStream_SeekSet(_stream, PhySize))
+ bool areThereNonZeros = false;
+ UInt64 numZeros = 0;
+ RINOK(ReadZeroTail(_stream, areThereNonZeros, numZeros, kRemMax))
+ if (!areThereNonZeros)
+ PhySize += numZeros;
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT CInArchive::Open(IInStream *inStream)
+{
+ Clear();
+ _stream = inStream;
+ try { return Open2(); }
+ catch(const CSystemException &e) { return e.ErrorCode; }
+ catch(CUnexpectedEndException &) { UnexpectedEnd = true; return S_FALSE; }
+ catch(CHeaderErrorException &) { HeadersError = true; return S_FALSE; }
+ catch(CEndianErrorException &) { IncorrectBigEndian = true; return S_FALSE; }
+}
+
+void CInArchive::Clear()
+{
+ IsArc = false;
+ UnexpectedEnd = false;
+ HeadersError = false;
+ IncorrectBigEndian = false;
+ TooDeepDirs = false;
+ SelfLinkedDirs = false;
+
+ UniqStartLocations.Clear();
+
+ Refs.Clear();
+ _rootDir.Clear();
+ VolDescs.Clear();
+ _bootIsDefined = false;
+ BootEntries.Clear();
+ SuspSkipSize = 0;
+ IsSusp = false;
+}
+
+
+UInt64 CInArchive::GetBootItemSize(unsigned index) const
+{
+ const CBootInitialEntry &be = BootEntries[index];
+ UInt64 size = be.GetSize();
+ if (be.BootMediaType == NBootMediaType::k1d2Floppy) size = 1200 << 10;
+ else if (be.BootMediaType == NBootMediaType::k1d44Floppy) size = 1440 << 10;
+ else if (be.BootMediaType == NBootMediaType::k2d88Floppy) size = 2880 << 10;
+ const UInt64 startPos = (UInt64)be.LoadRBA * kBlockSize;
+ if (startPos < _fileSize)
+ {
+ const UInt64 rem = _fileSize - startPos;
+ if (rem < size)
+ size = rem;
+ }
+ return size;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Iso/IsoIn.h b/CPP/7zip/Archive/Iso/IsoIn.h
new file mode 100644
index 0000000..f3e4751
--- /dev/null
+++ b/CPP/7zip/Archive/Iso/IsoIn.h
@@ -0,0 +1,318 @@
+// Archive/IsoIn.h
+
+#ifndef ZIP7_INC_ARCHIVE_ISO_IN_H
+#define ZIP7_INC_ARCHIVE_ISO_IN_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../IStream.h"
+
+#include "IsoHeader.h"
+#include "IsoItem.h"
+
+namespace NArchive {
+namespace NIso {
+
+struct CDir: public CDirRecord
+{
+ CDir *Parent;
+ CObjectVector<CDir> _subItems;
+
+ void Clear()
+ {
+ Parent = NULL;
+ _subItems.Clear();
+ }
+
+ AString GetPath(bool checkSusp, unsigned skipSize) const
+ {
+ AString s;
+
+ unsigned len = 0;
+ const CDir *cur = this;
+
+ for (;;)
+ {
+ unsigned curLen;
+ cur->GetNameCur(checkSusp, skipSize, curLen);
+ len += curLen;
+ cur = cur->Parent;
+ if (!cur || !cur->Parent)
+ break;
+ len++;
+ }
+
+ char *p = s.GetBuf_SetEnd(len) + len;
+
+ cur = this;
+
+ for (;;)
+ {
+ unsigned curLen;
+ const Byte *name = cur->GetNameCur(checkSusp, skipSize, curLen);
+ p -= curLen;
+ if (curLen != 0)
+ memcpy(p, name, curLen);
+ cur = cur->Parent;
+ if (!cur || !cur->Parent)
+ break;
+ p--;
+ *p = CHAR_PATH_SEPARATOR;
+ }
+
+ return s;
+ }
+
+ void GetPathU(UString &s) const
+ {
+ s.Empty();
+
+ unsigned len = 0;
+ const CDir *cur = this;
+
+ for (;;)
+ {
+ unsigned curLen = (unsigned)(cur->FileId.Size() / 2);
+ const Byte *fid = cur->FileId;
+
+ unsigned i;
+ for (i = 0; i < curLen; i++)
+ if (fid[i * 2] == 0 && fid[i * 2 + 1] == 0)
+ break;
+ len += i;
+ cur = cur->Parent;
+ if (!cur || !cur->Parent)
+ break;
+ len++;
+ }
+
+ wchar_t *p = s.GetBuf_SetEnd(len) + len;
+
+ cur = this;
+
+ for (;;)
+ {
+ unsigned curLen = (unsigned)(cur->FileId.Size() / 2);
+ const Byte *fid = cur->FileId;
+
+ unsigned i;
+ for (i = 0; i < curLen; i++)
+ if (fid[i * 2] == 0 && fid[i * 2 + 1] == 0)
+ break;
+ curLen = i;
+
+ p -= curLen;
+ for (i = 0; i < curLen; i++)
+ p[i] = (wchar_t)(((wchar_t)fid[i * 2] << 8) | fid[i * 2 + 1]);
+ cur = cur->Parent;
+ if (!cur || !cur->Parent)
+ break;
+ p--;
+ *p = WCHAR_PATH_SEPARATOR;
+ }
+ }
+};
+
+struct CDateTime
+{
+ UInt16 Year;
+ Byte Month;
+ Byte Day;
+ Byte Hour;
+ Byte Minute;
+ Byte Second;
+ Byte Hundredths;
+ signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded.
+
+ bool NotSpecified() const { return Year == 0 && Month == 0 && Day == 0 &&
+ Hour == 0 && Minute == 0 && Second == 0 && GmtOffset == 0; }
+
+ bool GetFileTime(NWindows::NCOM::CPropVariant &prop) const
+ {
+ UInt64 v;
+ const bool res = NWindows::NTime::GetSecondsSince1601(Year, Month, Day, Hour, Minute, Second, v);
+ if (res)
+ {
+ v = (UInt64)((Int64)v - (Int64)((Int32)GmtOffset * 15 * 60));
+ v *= 10000000;
+ if (Hundredths < 100)
+ v += (UInt32)Hundredths * 100000;
+ prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base + 2);
+ }
+ return res;
+ }
+};
+
+struct CBootRecordDescriptor
+{
+ Byte BootSystemId[32]; // a-characters
+ Byte BootId[32]; // a-characters
+ Byte BootSystemUse[1977];
+};
+
+struct CBootValidationEntry
+{
+ Byte PlatformId;
+ Byte Id[24]; // to identify the manufacturer/developer of the CD-ROM.
+};
+
+struct CBootInitialEntry
+{
+ bool Bootable;
+ Byte BootMediaType;
+ UInt16 LoadSegment;
+ /* This is the load segment for the initial boot image. If this
+ value is 0 the system will use the traditional segment of 7C0. If this value
+ is non-zero the system will use the specified segment. This applies to x86
+ architectures only. For "flat" model architectures (such as Motorola) this
+ is the address divided by 10. */
+ Byte SystemType; // This must be a copy of byte 5 (System Type) from the
+ // Partition Table found in the boot image.
+ UInt16 SectorCount; // This is the number of virtual/emulated sectors the system
+ // will store at Load Segment during the initial boot procedure.
+ UInt32 LoadRBA; // This is the start address of the virtual disk. CDs use
+ // Relative/Logical block addressing.
+
+ Byte VendorSpec[20];
+
+ UInt32 GetSize() const
+ {
+ // if (BootMediaType == NBootMediaType::k1d44Floppy) (1440 << 10);
+ return (UInt32)SectorCount * 512;
+ }
+
+ bool Parse(const Byte *p);
+ AString GetName() const;
+};
+
+struct CVolumeDescriptor
+{
+ Byte VolFlags;
+ Byte SystemId[32]; // a-characters. An identification of a system
+ // which can recognize and act upon the content of the Logical
+ // Sectors with logical Sector Numbers 0 to 15 of the volume.
+ Byte VolumeId[32]; // d-characters. An identification of the volume.
+ UInt32 VolumeSpaceSize; // the number of Logical Blocks in which the Volume Space of the volume is recorded
+ Byte EscapeSequence[32];
+ UInt16 VolumeSetSize;
+ UInt16 VolumeSequenceNumber; // the ordinal number of the volume in the Volume Set of which the volume is a member.
+ UInt16 LogicalBlockSize;
+ UInt32 PathTableSize;
+ UInt32 LPathTableLocation;
+ UInt32 LOptionalPathTableLocation;
+ UInt32 MPathTableLocation;
+ UInt32 MOptionalPathTableLocation;
+ CDirRecord RootDirRecord;
+ Byte VolumeSetId[128];
+ Byte PublisherId[128];
+ Byte DataPreparerId[128];
+ Byte ApplicationId[128];
+ Byte CopyrightFileId[37];
+ Byte AbstractFileId[37];
+ Byte BibFileId[37];
+ CDateTime CTime;
+ CDateTime MTime;
+ CDateTime ExpirationTime;
+ CDateTime EffectiveTime;
+ Byte FileStructureVersion; // = 1;
+ Byte ApplicationUse[512];
+
+ bool IsJoliet() const
+ {
+ if ((VolFlags & 1) != 0)
+ return false;
+ Byte b = EscapeSequence[2];
+ return (EscapeSequence[0] == 0x25 && EscapeSequence[1] == 0x2F &&
+ (b == 0x40 || b == 0x43 || b == 0x45));
+ }
+};
+
+struct CRef
+{
+ const CDir *Dir;
+ UInt32 Index;
+ UInt32 NumExtents;
+ UInt64 TotalSize;
+};
+
+const UInt32 kBlockSize = 1 << 11;
+
+class CInArchive
+{
+ IInStream *_stream;
+ UInt64 _position;
+
+ UInt32 m_BufferPos;
+
+ void Skip(size_t size);
+ void SkipZeros(size_t size);
+ Byte ReadByte();
+ void ReadBytes(Byte *data, UInt32 size);
+ UInt16 ReadUInt16();
+ UInt32 ReadUInt32Le();
+ UInt32 ReadUInt32Be();
+ UInt32 ReadUInt32();
+ UInt64 ReadUInt64();
+ UInt32 ReadDigits(int numDigits);
+ void ReadDateTime(CDateTime &d);
+ void ReadRecordingDateTime(CRecordingDateTime &t);
+ void ReadDirRecord2(CDirRecord &r, Byte len);
+ void ReadDirRecord(CDirRecord &r);
+
+ void ReadBootRecordDescriptor(CBootRecordDescriptor &d);
+ void ReadVolumeDescriptor(CVolumeDescriptor &d);
+
+ void SeekToBlock(UInt32 blockIndex);
+ void ReadDir(CDir &d, int level);
+ void CreateRefs(CDir &d);
+
+ void ReadBootInfo();
+ HRESULT Open2();
+public:
+ HRESULT Open(IInStream *inStream);
+ void Clear();
+
+ UInt64 _fileSize;
+ UInt64 PhySize;
+
+ CRecordVector<CRef> Refs;
+ CObjectVector<CVolumeDescriptor> VolDescs;
+ int MainVolDescIndex;
+ // UInt32 BlockSize;
+ CObjectVector<CBootInitialEntry> BootEntries;
+
+private:
+ bool _bootIsDefined;
+public:
+ bool IsArc;
+ bool UnexpectedEnd;
+ bool HeadersError;
+ bool IncorrectBigEndian;
+ bool TooDeepDirs;
+ bool SelfLinkedDirs;
+ bool IsSusp;
+ unsigned SuspSkipSize;
+
+ CRecordVector<UInt32> UniqStartLocations;
+
+ void UpdatePhySize(const UInt32 blockIndex, const UInt64 size)
+ {
+ const UInt64 alignedSize = (size + kBlockSize - 1) & ~((UInt64)kBlockSize - 1);
+ const UInt64 end = (UInt64)blockIndex * kBlockSize + alignedSize;
+ if (PhySize < end)
+ PhySize = end;
+ }
+
+ bool IsJoliet() const { return VolDescs[MainVolDescIndex].IsJoliet(); }
+
+ UInt64 GetBootItemSize(unsigned index) const;
+
+private:
+ CDir _rootDir;
+ Byte m_Buffer[kBlockSize];
+ CBootRecordDescriptor _bootDesc;
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Iso/IsoItem.h b/CPP/7zip/Archive/Iso/IsoItem.h
new file mode 100644
index 0000000..9556805
--- /dev/null
+++ b/CPP/7zip/Archive/Iso/IsoItem.h
@@ -0,0 +1,320 @@
+// Archive/IsoItem.h
+
+#ifndef ZIP7_INC_ARCHIVE_ISO_ITEM_H
+#define ZIP7_INC_ARCHIVE_ISO_ITEM_H
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/MyString.h"
+#include "../../../Common/MyBuffer.h"
+
+#include "../../../Windows/TimeUtils.h"
+
+#include "IsoHeader.h"
+
+namespace NArchive {
+namespace NIso {
+
+struct CRecordingDateTime
+{
+ Byte Year;
+ Byte Month;
+ Byte Day;
+ Byte Hour;
+ Byte Minute;
+ Byte Second;
+ signed char GmtOffset; // min intervals from -48 (West) to +52 (East) recorded.
+
+ bool GetFileTime(NWindows::NCOM::CPropVariant &prop) const
+ {
+ UInt64 v;
+ const bool res = NWindows::NTime::GetSecondsSince1601(Year + 1900, Month, Day, Hour, Minute, Second, v);
+ if (res)
+ {
+ v = (UInt64)((Int64)v - (Int64)((Int32)GmtOffset * 15 * 60));
+ v *= 10000000;
+ prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base);
+ }
+ return res;
+ }
+};
+
+enum EPx
+{
+ k_Px_Mode,
+ k_Px_Links,
+ k_Px_User,
+ k_Px_Group,
+ k_Px_SerialNumber
+
+ // k_Px_Num
+};
+
+/*
+enum ETf
+{
+ k_Tf_CTime,
+ k_Tf_MTime,
+ k_Tf_ATime,
+ k_Tf_Attrib,
+ k_Tf_Backup,
+ k_Tf_Expiration,
+ k_Tf_Effective
+
+ // k_Tf_Num
+};
+*/
+
+struct CDirRecord
+{
+ UInt32 ExtentLocation;
+ UInt32 Size;
+ CRecordingDateTime DateTime;
+ Byte FileFlags;
+ Byte FileUnitSize;
+ Byte InterleaveGapSize;
+ Byte ExtendedAttributeRecordLen;
+ UInt16 VolSequenceNumber;
+ CByteBuffer FileId;
+ CByteBuffer SystemUse;
+
+ bool AreMultiPartEqualWith(const CDirRecord &a) const
+ {
+ return FileId == a.FileId
+ && (FileFlags & (~NFileFlags::kNonFinalExtent)) ==
+ (a.FileFlags & (~NFileFlags::kNonFinalExtent));
+ }
+
+ bool IsDir() const { return (FileFlags & NFileFlags::kDirectory) != 0; }
+ bool IsNonFinalExtent() const { return (FileFlags & NFileFlags::kNonFinalExtent) != 0; }
+
+ bool IsSystemItem() const
+ {
+ if (FileId.Size() != 1)
+ return false;
+ Byte b = *(const Byte *)FileId;
+ return (b == 0 || b == 1);
+ }
+
+
+ const Byte* FindSuspRecord(unsigned skipSize, Byte id0, Byte id1, unsigned &lenRes) const
+ {
+ lenRes = 0;
+ if (SystemUse.Size() < skipSize)
+ return NULL;
+ const Byte *p = (const Byte *)SystemUse + skipSize;
+ unsigned rem = (unsigned)(SystemUse.Size() - skipSize);
+ while (rem >= 5)
+ {
+ unsigned len = p[2];
+ if (len < 3 || len > rem)
+ return NULL;
+ if (p[0] == id0 && p[1] == id1 && p[3] == 1)
+ {
+ if (len < 4)
+ return NULL; // Check it
+ lenRes = len - 4;
+ return p + 4;
+ }
+ p += len;
+ rem -= len;
+ }
+ return NULL;
+ }
+
+
+ const Byte* GetNameCur(bool checkSusp, unsigned skipSize, unsigned &nameLenRes) const
+ {
+ const Byte *res = NULL;
+ unsigned len = 0;
+ if (checkSusp)
+ res = FindSuspRecord(skipSize, 'N', 'M', len);
+ if (!res || len < 1)
+ {
+ res = (const Byte *)FileId;
+ len = (unsigned)FileId.Size();
+ }
+ else
+ {
+ res++;
+ len--;
+ }
+ unsigned i;
+ for (i = 0; i < len; i++)
+ if (res[i] == 0)
+ break;
+ nameLenRes = i;
+ return res;
+ }
+
+
+ bool GetSymLink(unsigned skipSize, AString &link) const
+ {
+ link.Empty();
+ const Byte *p = NULL;
+ unsigned len = 0;
+ p = FindSuspRecord(skipSize, 'S', 'L', len);
+ if (!p || len < 1)
+ return false;
+
+ if (*p != 0)
+ return false;
+
+ p++;
+ len--;
+
+ while (len != 0)
+ {
+ if (len < 2)
+ return false;
+ unsigned flags = p[0];
+ unsigned cl = p[1];
+ p += 2;
+ len -= 2;
+
+ if (cl > len)
+ return false;
+
+ bool needSlash = false;
+
+ if (flags & (1 << 1)) link += "./";
+ else if (flags & (1 << 2)) link += "../";
+ else if (flags & (1 << 3)) link += '/';
+ else
+ needSlash = true;
+
+ for (unsigned i = 0; i < cl; i++)
+ {
+ const Byte c = p[i];
+ if (c == 0)
+ {
+ break;
+ // return false;
+ }
+ link += (char)c;
+ }
+
+ p += cl;
+ len -= cl;
+
+ if (len == 0)
+ break;
+
+ if (needSlash)
+ link += '/';
+ }
+
+ return true;
+ }
+
+ static bool GetLe32Be32(const Byte *p, UInt32 &dest)
+ {
+ UInt32 v1 = GetUi32(p);
+ UInt32 v2 = GetBe32(p + 4);
+ if (v1 == v2)
+ {
+ dest = v1;
+ return true;
+ }
+ return false;
+ }
+
+
+ bool GetPx(unsigned skipSize, unsigned pxType, UInt32 &val) const
+ {
+ val = 0;
+ const Byte *p = NULL;
+ unsigned len = 0;
+ p = FindSuspRecord(skipSize, 'P', 'X', len);
+ if (!p)
+ return false;
+ // px.Clear();
+ if (len < (pxType + 1) * 8)
+ return false;
+
+ return GetLe32Be32(p + pxType * 8, val);
+ }
+
+ /*
+ bool GetTf(int skipSize, unsigned pxType, CRecordingDateTime &t) const
+ {
+ const Byte *p = NULL;
+ unsigned len = 0;
+ p = FindSuspRecord(skipSize, 'T', 'F', len);
+ if (!p)
+ return false;
+ if (len < 1)
+ return false;
+ Byte flags = *p++;
+ len--;
+
+ unsigned step = 7;
+ if (flags & 0x80)
+ {
+ step = 17;
+ return false;
+ }
+
+ if ((flags & (1 << pxType)) == 0)
+ return false;
+
+ for (unsigned i = 0; i < pxType; i++)
+ {
+ if (len < step)
+ return false;
+ if (flags & (1 << i))
+ {
+ p += step;
+ len -= step;
+ }
+ }
+
+ if (len < step)
+ return false;
+
+ t.Year = p[0];
+ t.Month = p[1];
+ t.Day = p[2];
+ t.Hour = p[3];
+ t.Minute = p[4];
+ t.Second = p[5];
+ t.GmtOffset = (signed char)p[6];
+
+ return true;
+ }
+ */
+
+ bool CheckSusp(const Byte *p, unsigned &startPos) const
+ {
+ if (p[0] == 'S' &&
+ p[1] == 'P' &&
+ p[2] == 0x7 &&
+ p[3] == 0x1 &&
+ p[4] == 0xBE &&
+ p[5] == 0xEF)
+ {
+ startPos = p[6];
+ return true;
+ }
+ return false;
+ }
+
+ bool CheckSusp(unsigned &startPos) const
+ {
+ const Byte *p = (const Byte *)SystemUse;
+ const size_t len = SystemUse.Size();
+ const unsigned kMinLen = 7;
+ if (len < kMinLen)
+ return false;
+ if (CheckSusp(p, startPos))
+ return true;
+ const unsigned kOffset2 = 14;
+ if (len < kOffset2 + kMinLen)
+ return false;
+ return CheckSusp(p + kOffset2, startPos);
+ }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Iso/IsoRegister.cpp b/CPP/7zip/Archive/Iso/IsoRegister.cpp
new file mode 100644
index 0000000..41b56ba
--- /dev/null
+++ b/CPP/7zip/Archive/Iso/IsoRegister.cpp
@@ -0,0 +1,21 @@
+// IsoRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "IsoHandler.h"
+
+namespace NArchive {
+namespace NIso {
+
+static const Byte k_Signature[] = { 'C', 'D', '0', '0', '1' };
+
+REGISTER_ARC_I(
+ "Iso", "iso img", NULL, 0xE7,
+ k_Signature,
+ NArchive::NIso::kStartPos + 1,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/Iso/StdAfx.h b/CPP/7zip/Archive/Iso/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Archive/Iso/StdAfx.h
@@ -0,0 +1,11 @@
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Archive/LpHandler.cpp b/CPP/7zip/Archive/LpHandler.cpp
new file mode 100644
index 0000000..c1a76b4
--- /dev/null
+++ b/CPP/7zip/Archive/LpHandler.cpp
@@ -0,0 +1,1166 @@
+// LpHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+#include "../../../C/Sha256.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer.h"
+
+#include "../../Windows/PropVariantUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+#define G16(_offs_, dest) dest = Get16(p + (_offs_));
+#define G32(_offs_, dest) dest = Get32(p + (_offs_));
+#define G64(_offs_, dest) dest = Get64(p + (_offs_));
+
+using namespace NWindows;
+
+namespace NArchive {
+
+namespace NExt {
+API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize);
+}
+
+namespace NLp {
+
+/*
+Android 10+ use Android's Dynamic Partitions to allow the
+different read-only system partitions (e.g. system, vendor, product)
+to share the same pool of storage space (as LVM in Linux).
+Name for partition: "super" (for GPT) or "super.img" (for file).
+Dynamic Partition Tools: lpmake
+All partitions that are A/B-ed should be named as follows (slots are always named a, b, etc.):
+boot_a, boot_b, system_a, system_b, vendor_a, vendor_b.
+*/
+
+#define LP_METADATA_MAJOR_VERSION 10
+// #define LP_METADATA_MINOR_VERSION_MIN 0
+// #define LP_METADATA_MINOR_VERSION_MAX 2
+
+// #define LP_SECTOR_SIZE 512
+static const unsigned kSectorSizeLog = 9;
+
+/* Amount of space reserved at the start of every super partition to avoid
+ * creating an accidental boot sector. */
+#define LP_PARTITION_RESERVED_BYTES 4096
+#define LP_METADATA_GEOMETRY_SIZE 4096
+#define LP_METADATA_HEADER_MAGIC 0x414C5030
+
+static const unsigned k_SignatureSize = 8;
+static const Byte k_Signature[k_SignatureSize] =
+ { 0x67, 0x44, 0x6c, 0x61, 0x34, 0, 0, 0 };
+
+// The length (36) is the same as the maximum length of a GPT partition name.
+static const unsigned kNameLen = 36;
+
+static void AddName36ToString(AString &s, const char *name, bool strictConvert)
+{
+ for (unsigned i = 0; i < kNameLen; i++)
+ {
+ char c = name[i];
+ if (c == 0)
+ return;
+ if (strictConvert && c < 32)
+ c = '_';
+ s += c;
+ }
+}
+
+
+static const unsigned k_Geometry_Size = 0x34;
+
+// LpMetadataGeometry
+struct CGeometry
+{
+ // UInt32 magic;
+ // UInt32 struct_size;
+ // Byte checksum[32]; /* SHA256 checksum of this struct, with this field set to 0. */
+
+ /* Maximum amount of space a single copy of the metadata can use,
+ a multiple of LP_SECTOR_SIZE. */
+ UInt32 metadata_max_size;
+
+ /* Number of copies of the metadata to keep.
+ For Non-A/B: 1, For A/B: 2, for A/B/C: 3.
+ A backup copy of each slot is kept */
+ UInt32 metadata_slot_count;
+
+ /* minimal alignment for partition and extent sizes, a multiple of LP_SECTOR_SIZE. */
+ UInt32 logical_block_size;
+
+ bool Parse(const Byte *p)
+ {
+ G32 (40, metadata_max_size)
+ G32 (44, metadata_slot_count)
+ G32 (48, logical_block_size)
+ if (metadata_slot_count == 0 || metadata_slot_count >= ((UInt32)1 << 20))
+ return false;
+ if (metadata_max_size == 0)
+ return false;
+ if ((metadata_max_size & (((UInt32)1 << kSectorSizeLog) - 1)) != 0)
+ return false;
+ return true;
+ }
+
+ UInt64 GetTotalMetadataSize() const
+ {
+ // there are 2 copies of GEOMETRY and METADATA slots
+ return LP_PARTITION_RESERVED_BYTES +
+ LP_METADATA_GEOMETRY_SIZE * 2 +
+ ((UInt64)metadata_max_size * metadata_slot_count) * 2;
+ }
+};
+
+
+
+// LpMetadataTableDescriptor
+struct CDescriptor
+{
+ UInt32 offset; /* Location of the table, relative to end of the metadata header. */
+ UInt32 num_entries; /* Number of entries in the table. */
+ UInt32 entry_size; /* Size of each entry in the table, in bytes. */
+
+ void Parse(const Byte *p)
+ {
+ G32 (0, offset)
+ G32 (4, num_entries)
+ G32 (8, entry_size)
+ }
+
+ bool CheckLimits(UInt32 limit) const
+ {
+ if (entry_size == 0)
+ return false;
+ const UInt32 size = num_entries * entry_size;
+ if (size / entry_size != num_entries)
+ return false;
+ if (offset > limit || limit - offset < size)
+ return false;
+ return true;
+ }
+};
+
+
+// #define LP_PARTITION_ATTR_NONE 0x0
+// #define LP_PARTITION_ATTR_READONLY (1 << 0)
+
+/* This flag is only intended to be used with super_empty.img and super.img on
+ * retrofit devices. On these devices there are A and B super partitions, and
+ * we don't know ahead of time which slot the image will be applied to.
+ *
+ * If set, the partition name needs a slot suffix applied. The slot suffix is
+ * determined by the metadata slot number (0 = _a, 1 = _b).
+ */
+// #define LP_PARTITION_ATTR_SLOT_SUFFIXED (1 << 1)
+
+/* This flag is applied automatically when using MetadataBuilder::NewForUpdate.
+ * It signals that the partition was created (or modified) for a snapshot-based
+ * update. If this flag is not present, the partition was likely flashed via
+ * fastboot.
+ */
+// #define LP_PARTITION_ATTR_UPDATED (1 << 2)
+
+/* This flag marks a partition as disabled. It should not be used or mapped. */
+// #define LP_PARTITION_ATTR_DISABLED (1 << 3)
+
+static const char * const g_PartitionAttr[] =
+{
+ "READONLY"
+ , "SLOT_SUFFIXED"
+ , "UPDATED"
+ , "DISABLED"
+};
+
+static unsigned const k_MetaPartition_Size = 52;
+
+// LpMetadataPartition
+struct CPartition
+{
+ /* ASCII characters: alphanumeric or _. at least one ASCII character,
+ (name) must be unique across all partition names. */
+ char name[kNameLen];
+
+ UInt32 attributes; /* (LP_PARTITION_ATTR_*). */
+
+ /* Index of the first extent owned by this partition. The extent will
+ * start at logical sector 0. Gaps between extents are not allowed. */
+ UInt32 first_extent_index;
+
+ /* Number of extents in the partition. Every partition must have at least one extent. */
+ UInt32 num_extents;
+
+ /* Group this partition belongs to. */
+ UInt32 group_index;
+
+ void Parse(const Byte *p)
+ {
+ memcpy(name, p, kNameLen);
+ G32 (36, attributes)
+ G32 (40, first_extent_index)
+ G32 (44, num_extents)
+ G32 (48, group_index)
+ }
+
+ // calced properties:
+ UInt32 MethodsMask;
+ UInt64 NumSectors;
+ UInt64 NumSectors_Pack;
+ const char *Ext;
+
+ UInt64 GetSize() const { return NumSectors << kSectorSizeLog; }
+ UInt64 GetPackSize() const { return NumSectors_Pack << kSectorSizeLog; }
+
+ CPartition():
+ MethodsMask(0),
+ NumSectors(0),
+ NumSectors_Pack(0),
+ Ext(NULL)
+ {}
+};
+
+
+
+
+#define LP_TARGET_TYPE_LINEAR 0
+/* This extent is a dm-zero target. The index is ignored and must be 0. */
+#define LP_TARGET_TYPE_ZERO 1
+
+static const char * const g_Methods[] =
+{
+ "RAW" // "LINEAR"
+ , "ZERO"
+};
+
+static unsigned const k_MetaExtent_Size = 24;
+
+// LpMetadataExtent
+struct CExtent
+{
+ UInt64 num_sectors; /* Length in 512-byte sectors. */
+ UInt32 target_type; /* Target type for device-mapper (LP_TARGET_TYPE_*). */
+
+ /* for LINEAR: The sector on the physical partition that this extent maps onto.
+ for ZERO: must be 0. */
+ UInt64 target_data;
+
+ /* for LINEAR: index into the block devices table.
+ for ZERO: must be 0. */
+ UInt32 target_source;
+
+ bool IsRAW() const { return target_type == LP_TARGET_TYPE_LINEAR; }
+
+ void Parse(const Byte *p)
+ {
+ G64 (0, num_sectors)
+ G32 (8, target_type)
+ G64 (12, target_data)
+ G32 (20, target_source)
+ }
+};
+
+
+/* This flag is only intended to be used with super_empty.img and super.img on
+ * retrofit devices. If set, the group needs a slot suffix to be interpreted
+ * correctly. The suffix is automatically applied by ReadMetadata().
+ */
+// #define LP_GROUP_SLOT_SUFFIXED (1 << 0)
+static unsigned const k_Group_Size = 48;
+
+// LpMetadataPartitionGroup
+struct CGroup
+{
+ char name[kNameLen];
+ UInt32 flags; /* (LP_GROUP_*). */
+ UInt64 maximum_size; /* Maximum size in bytes. If 0, the group has no maximum size. */
+
+ void Parse(const Byte *p)
+ {
+ memcpy(name, p, kNameLen);
+ G32 (36, flags)
+ G64 (40, maximum_size)
+ }
+};
+
+
+
+
+/* This flag is only intended to be used with super_empty.img and super.img on
+ * retrofit devices. On these devices there are A and B super partitions, and
+ * we don't know ahead of time which slot the image will be applied to.
+ *
+ * If set, the block device needs a slot suffix applied before being used with
+ * IPartitionOpener. The slot suffix is determined by the metadata slot number
+ * (0 = _a, 1 = _b).
+ */
+// #define LP_BLOCK_DEVICE_SLOT_SUFFIXED (1 << 0)
+
+static unsigned const k_Device_Size = 64;
+
+/* This struct defines an entry in the block_devices table. There must be at
+ * least one device, and the first device must represent the partition holding
+ * the super metadata.
+ */
+// LpMetadataBlockDevice
+struct CDevice
+{
+ /* 0: First usable sector for allocating logical partitions. this will be
+ * the first sector after the initial geometry blocks, followed by the
+ * space consumed by metadata_max_size*metadata_slot_count*2.
+ */
+ UInt64 first_logical_sector;
+
+ /* 8: Alignment for defining partitions or partition extents. For example,
+ * an alignment of 1MiB will require that all partitions have a size evenly
+ * divisible by 1MiB, and that the smallest unit the partition can grow by
+ * is 1MiB.
+ *
+ * Alignment is normally determined at runtime when growing or adding
+ * partitions. If for some reason the alignment cannot be determined, then
+ * this predefined alignment in the geometry is used instead. By default
+ * it is set to 1MiB.
+ */
+ UInt32 alignment;
+
+ /* 12: Alignment offset for "stacked" devices. For example, if the "super"
+ * partition itself is not aligned within the parent block device's
+ * partition table, then we adjust for this in deciding where to place
+ * |first_logical_sector|.
+ *
+ * Similar to |alignment|, this will be derived from the operating system.
+ * If it cannot be determined, it is assumed to be 0.
+ */
+ UInt32 alignment_offset;
+
+ /* 16: Block device size, as specified when the metadata was created. This
+ * can be used to verify the geometry against a target device.
+ */
+ UInt64 size;
+
+ /* 24: Partition name in the GPT*/
+ char partition_name[kNameLen];
+
+ /* 60: Flags (see LP_BLOCK_DEVICE_* flags below). */
+ UInt32 flags;
+
+ void Parse(const Byte *p)
+ {
+ memcpy(partition_name, p + 24, kNameLen);
+ G64 (0, first_logical_sector)
+ G32 (8, alignment)
+ G32 (12, alignment_offset)
+ G64 (16, size)
+ G32 (60, flags)
+ }
+};
+
+
+/* This device uses Virtual A/B. Note that on retrofit devices, the expanded
+ * header may not be present.
+ */
+// #define LP_HEADER_FLAG_VIRTUAL_AB_DEVICE 0x1
+
+static const char * const g_Header_Flags[] =
+{
+ "VIRTUAL_AB"
+};
+
+
+static const unsigned k_LpMetadataHeader10_size = 128;
+static const unsigned k_LpMetadataHeader12_size = 256;
+
+struct LpMetadataHeader
+{
+ /* 0: Four bytes equal to LP_METADATA_HEADER_MAGIC. */
+ UInt32 magic;
+
+ /* 4: Version number required to read this metadata. If the version is not
+ * equal to the library version, the metadata should be considered
+ * incompatible.
+ */
+ UInt16 major_version;
+
+ /* 6: Minor version. A library supporting newer features should be able to
+ * read metadata with an older minor version. However, an older library
+ * should not support reading metadata if its minor version is higher.
+ */
+ UInt16 minor_version;
+
+ /* 8: The size of this header struct. */
+ UInt32 header_size;
+
+ /* 12: SHA256 checksum of the header, up to |header_size| bytes, computed as
+ * if this field were set to 0.
+ */
+ // Byte header_checksum[32];
+
+ /* 44: The total size of all tables. This size is contiguous; tables may not
+ * have gaps in between, and they immediately follow the header.
+ */
+ UInt32 tables_size;
+
+ /* 48: SHA256 checksum of all table contents. */
+ Byte tables_checksum[32];
+
+ /* 80: Partition table descriptor. */
+ CDescriptor partitions;
+ /* 92: Extent table descriptor. */
+ CDescriptor extents;
+ /* 104: Updateable group descriptor. */
+ CDescriptor groups;
+ /* 116: Block device table. */
+ CDescriptor block_devices;
+
+ /* Everything past here is header version 1.2+, and is only included if
+ * needed. When liblp supporting >= 1.2 reads a < 1.2 header, it must
+ * zero these additional fields.
+ */
+
+ /* 128: See LP_HEADER_FLAG_ constants for possible values. Header flags are
+ * independent of the version number and intended to be informational only.
+ * New flags can be added without bumping the version.
+ */
+ // UInt32 flags;
+
+ /* 132: Reserved (zero), pad to 256 bytes. */
+ // Byte reserved[124];
+
+ void Parse128(const Byte *p)
+ {
+ G32 (0, magic)
+ G16 (4, major_version)
+ G16 (6, minor_version)
+ G32 (8, header_size)
+ // Byte header_checksum[32];
+ G32 (44, tables_size)
+ memcpy (tables_checksum, p + 48, 32);
+ partitions.Parse(p + 80);
+ extents.Parse(p + 92);
+ groups.Parse(p + 104);
+ block_devices.Parse(p + 116);
+ /* Everything past here is header version 1.2+, and is only included if
+ * needed. When liblp supporting >= 1.2 reads a < 1.2 header, it must
+ * zero these additional fields.
+ */
+ }
+};
+
+
+static bool CheckSha256(const Byte *data, size_t size, const Byte *checksum)
+{
+ CSha256 sha;
+ Sha256_Init(&sha);
+ Sha256_Update(&sha, data, size);
+ Byte calced[32];
+ Sha256_Final(&sha, calced);
+ return memcmp(checksum, calced, 32) == 0;
+}
+
+static bool CheckSha256_csOffset(Byte *data, size_t size, unsigned hashOffset)
+{
+ Byte checksum[32];
+ Byte *shaData = &data[hashOffset];
+ memcpy(checksum, shaData, 32);
+ memset(shaData, 0, 32);
+ return CheckSha256(data, size, checksum);
+}
+
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IInArchiveGetStream
+)
+ CRecordVector<CPartition> _items;
+ CRecordVector<CExtent> Extents;
+
+ CMyComPtr<IInStream> _stream;
+ UInt64 _totalSize;
+ // UInt64 _usedSize;
+ // UInt64 _headersSize;
+
+ CGeometry geom;
+ UInt16 Major_version;
+ UInt16 Minor_version;
+ UInt32 Flags;
+
+ Int32 _mainFileIndex;
+ UInt32 MethodsMask;
+ bool _headerWarning;
+ AString GroupsString;
+ AString DevicesString;
+ AString DeviceArcName;
+
+ HRESULT Open2(IInStream *stream);
+};
+
+
+static void AddComment_UInt64(AString &s, const char *name, UInt64 val)
+{
+ s.Add_Space();
+ s += name;
+ s += '=';
+ s.Add_UInt64(val);
+}
+
+
+static bool IsBufZero(const Byte *data, size_t size)
+{
+ for (size_t i = 0; i < size; i += 4)
+ if (*(const UInt32 *)(const void *)(data + i) != 0)
+ return false;
+ return true;
+}
+
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+ RINOK(InStream_SeekSet(stream, LP_PARTITION_RESERVED_BYTES))
+ {
+ Byte buf[k_Geometry_Size];
+ RINOK(ReadStream_FALSE(stream, buf, k_Geometry_Size))
+ if (memcmp(buf, k_Signature, k_SignatureSize) != 0)
+ return S_FALSE;
+ if (!geom.Parse(buf))
+ return S_FALSE;
+ if (!CheckSha256_csOffset(buf, k_Geometry_Size, 8))
+ return S_FALSE;
+ }
+
+ CByteBuffer buffer;
+ RINOK(InStream_SeekToBegin(stream))
+ buffer.Alloc(LP_METADATA_GEOMETRY_SIZE * 2);
+ {
+ // buffer.Size() >= LP_PARTITION_RESERVED_BYTES
+ RINOK(ReadStream_FALSE(stream, buffer, LP_PARTITION_RESERVED_BYTES))
+ if (!IsBufZero(buffer, LP_PARTITION_RESERVED_BYTES))
+ {
+ _headerWarning = true;
+ // return S_FALSE;
+ }
+ }
+
+ RINOK(ReadStream_FALSE(stream, buffer, LP_METADATA_GEOMETRY_SIZE * 2))
+ // we check that 2 copies of GEOMETRY are identical:
+ if (memcmp(buffer, buffer + LP_METADATA_GEOMETRY_SIZE, LP_METADATA_GEOMETRY_SIZE) != 0
+ || !IsBufZero(buffer + k_Geometry_Size, LP_METADATA_GEOMETRY_SIZE - k_Geometry_Size))
+ {
+ _headerWarning = true;
+ // return S_FALSE;
+ }
+
+ RINOK(ReadStream_FALSE(stream, buffer, k_LpMetadataHeader10_size))
+ LpMetadataHeader header;
+ header.Parse128(buffer);
+ if (header.magic != LP_METADATA_HEADER_MAGIC ||
+ header.major_version != LP_METADATA_MAJOR_VERSION ||
+ header.header_size < k_LpMetadataHeader10_size)
+ return S_FALSE;
+ Flags = 0;
+ if (header.header_size > k_LpMetadataHeader10_size)
+ {
+ if (header.header_size != k_LpMetadataHeader12_size)
+ return S_FALSE;
+ RINOK(ReadStream_FALSE(stream, buffer + k_LpMetadataHeader10_size,
+ header.header_size - k_LpMetadataHeader10_size))
+ Flags = Get32(buffer + k_LpMetadataHeader10_size);
+ }
+ Major_version = header.major_version;
+ Minor_version = header.minor_version;
+
+ if (!CheckSha256_csOffset(buffer, header.header_size, 12))
+ return S_FALSE;
+
+ if (geom.metadata_max_size < header.tables_size ||
+ geom.metadata_max_size - header.tables_size < header.header_size)
+ return S_FALSE;
+
+ buffer.AllocAtLeast(header.tables_size);
+ RINOK(ReadStream_FALSE(stream, buffer, header.tables_size))
+
+ const UInt64 totalMetaSize = geom.GetTotalMetadataSize();
+ // _headersSize = _totalSize;
+ _totalSize = totalMetaSize;
+
+ if (!CheckSha256(buffer, header.tables_size, header.tables_checksum))
+ return S_FALSE;
+
+ {
+ const CDescriptor &d = header.partitions;
+ if (!d.CheckLimits(header.tables_size))
+ return S_FALSE;
+ if (d.entry_size != k_MetaPartition_Size)
+ return S_FALSE;
+ for (UInt32 i = 0; i < d.num_entries; i++)
+ {
+ CPartition part;
+ part.Parse(buffer + d.offset + i * d.entry_size);
+ const UInt32 extLimit = part.first_extent_index + part.num_extents;
+ if (extLimit < part.first_extent_index ||
+ extLimit > header.extents.num_entries ||
+ part.group_index >= header.groups.num_entries)
+ return S_FALSE;
+ _items.Add(part);
+ }
+ }
+ {
+ const CDescriptor &d = header.extents;
+ if (!d.CheckLimits(header.tables_size))
+ return S_FALSE;
+ if (d.entry_size != k_MetaExtent_Size)
+ return S_FALSE;
+ for (UInt32 i = 0; i < d.num_entries; i++)
+ {
+ CExtent e;
+ e.Parse(buffer + d.offset + i * d.entry_size);
+ // if (e.target_type > LP_TARGET_TYPE_ZERO) return S_FALSE;
+ if (e.IsRAW())
+ {
+ if (e.target_source >= header.block_devices.num_entries)
+ return S_FALSE;
+ const UInt64 endSector = e.target_data + e.num_sectors;
+ const UInt64 endOffset = endSector << kSectorSizeLog;
+ if (_totalSize < endOffset)
+ _totalSize = endOffset;
+ }
+ MethodsMask |= (UInt32)1 << e.target_type;
+ Extents.Add(e);
+ }
+ }
+
+ // _usedSize = _totalSize;
+ {
+ const CDescriptor &d = header.groups;
+ if (!d.CheckLimits(header.tables_size))
+ return S_FALSE;
+ if (d.entry_size != k_Group_Size)
+ return S_FALSE;
+ AString s;
+ for (UInt32 i = 0; i < d.num_entries; i++)
+ {
+ CGroup g;
+ g.Parse(buffer + d.offset + i * d.entry_size);
+ if (_totalSize < g.maximum_size)
+ _totalSize = g.maximum_size;
+ s += " ";
+ AddName36ToString(s, g.name, true);
+ AddComment_UInt64(s, "maximum_size", g.maximum_size);
+ AddComment_UInt64(s, "flags", g.flags);
+ s.Add_LF();
+ }
+ GroupsString = s;
+ }
+
+ {
+ const CDescriptor &d = header.block_devices;
+ if (!d.CheckLimits(header.tables_size))
+ return S_FALSE;
+ if (d.entry_size != k_Device_Size)
+ return S_FALSE;
+ AString s;
+ // CRecordVector<CDevice> devices;
+ for (UInt32 i = 0; i < d.num_entries; i++)
+ {
+ CDevice v;
+ v.Parse(buffer + d.offset + i * d.entry_size);
+ // if (i == 0)
+ {
+ // it's super_device is first device;
+ if (totalMetaSize > (v.first_logical_sector << kSectorSizeLog))
+ return S_FALSE;
+ }
+ if (_totalSize < v.size)
+ _totalSize = v.size;
+ s += " ";
+ if (i == 0)
+ AddName36ToString(DeviceArcName, v.partition_name, true);
+ // devices.Add(v);
+ AddName36ToString(s, v.partition_name, true);
+ AddComment_UInt64(s, "size", v.size);
+ AddComment_UInt64(s, "first_logical_sector", v.first_logical_sector);
+ AddComment_UInt64(s, "alignment", v.alignment);
+ AddComment_UInt64(s, "alignment_offset", v.alignment_offset);
+ AddComment_UInt64(s, "flags", v.flags);
+ s.Add_LF();
+ }
+ DevicesString = s;
+ }
+
+ {
+ FOR_VECTOR (i, _items)
+ {
+ CPartition &part = _items[i];
+ if (part.first_extent_index > Extents.Size() ||
+ part.num_extents > Extents.Size() - part.first_extent_index)
+ return S_FALSE;
+
+ UInt64 numSectors = 0;
+ UInt64 numSectors_Pack = 0;
+ UInt32 methods = 0;
+ for (UInt32 k = 0; k < part.num_extents; k++)
+ {
+ const CExtent &e = Extents[part.first_extent_index + k];
+ numSectors += e.num_sectors;
+ if (e.IsRAW())
+ numSectors_Pack += e.num_sectors;
+ methods |= (UInt32)1 << e.target_type;
+ }
+ part.NumSectors = numSectors;
+ part.NumSectors_Pack = numSectors_Pack;
+ part.MethodsMask = methods;
+ }
+ }
+
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */))
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(Open2(stream))
+ _stream = stream;
+
+ int mainFileIndex = -1;
+ unsigned numNonEmptyParts = 0;
+
+ FOR_VECTOR (fileIndex, _items)
+ {
+ CPartition &item = _items[fileIndex];
+ if (item.NumSectors != 0)
+ {
+ mainFileIndex = (int)fileIndex;
+ numNonEmptyParts++;
+ CMyComPtr<ISequentialInStream> parseStream;
+ if (GetStream(fileIndex, &parseStream) == S_OK && parseStream)
+ {
+ const size_t kParseSize = 1 << 11;
+ Byte buf[kParseSize];
+ if (ReadStream_FAIL(parseStream, buf, kParseSize) == S_OK)
+ {
+ UInt64 extSize;
+ if (NExt::IsArc_Ext_PhySize(buf, kParseSize, &extSize) == k_IsArc_Res_YES)
+ if (extSize == item.GetSize())
+ item.Ext = "ext";
+ }
+ }
+ }
+ }
+ if (numNonEmptyParts == 1)
+ _mainFileIndex = mainFileIndex;
+
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _totalSize = 0;
+ // _usedSize = 0;
+ // _headersSize = 0;
+ _items.Clear();
+ Extents.Clear();
+ _stream.Release();
+ _mainFileIndex = -1;
+ _headerWarning = false;
+ MethodsMask = 0;
+ GroupsString.Empty();
+ DevicesString.Empty();
+ DeviceArcName.Empty();
+ return S_OK;
+}
+
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
+ kpidCharacts,
+ kpidMethod,
+ kpidNumBlocks,
+ kpidOffset
+};
+
+static const Byte kArcProps[] =
+{
+ kpidUnpackVer,
+ kpidMethod,
+ kpidClusterSize,
+ // kpidHeadersSize,
+ // kpidFreeSpace,
+ kpidName,
+ kpidComment
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidMainSubfile:
+ {
+ if (_mainFileIndex >= 0)
+ prop = (UInt32)_mainFileIndex;
+ break;
+ }
+ case kpidPhySize: prop = _totalSize; break;
+
+ // case kpidFreeSpace: if (_usedSize != 0) prop = _totalSize - _usedSize; break;
+ // case kpidHeadersSize: prop = _headersSize; break;
+
+ case kpidMethod:
+ {
+ const UInt32 m = MethodsMask;
+ if (m != 0)
+ {
+ FLAGS_TO_PROP(g_Methods, m, prop);
+ }
+ break;
+ }
+
+ case kpidUnpackVer:
+ {
+ AString s;
+ s.Add_UInt32(Major_version);
+ s.Add_Dot();
+ s.Add_UInt32(Minor_version);
+ prop = s;
+ break;
+ }
+
+ case kpidClusterSize:
+ prop = geom.logical_block_size;
+ break;
+
+ case kpidComment:
+ {
+ AString s;
+
+ s += "metadata_slot_count: ";
+ s.Add_UInt32(geom.metadata_slot_count);
+ s.Add_LF();
+
+ s += "metadata_max_size: ";
+ s.Add_UInt32(geom.metadata_max_size);
+ s.Add_LF();
+
+ if (Flags != 0)
+ {
+ s += "flags: ";
+ s += FlagsToString(g_Header_Flags, Z7_ARRAY_SIZE(g_Header_Flags), Flags);
+ s.Add_LF();
+ }
+
+ if (!GroupsString.IsEmpty())
+ {
+ s += "Groups:";
+ s.Add_LF();
+ s += GroupsString;
+ }
+
+ if (!DevicesString.IsEmpty())
+ {
+ s += "BlockDevices:";
+ s.Add_LF();
+ s += DevicesString;
+ }
+
+ if (!s.IsEmpty())
+ prop = s;
+ break;
+ }
+
+ case kpidName:
+ if (!DeviceArcName.IsEmpty())
+ prop = DeviceArcName + ".lpimg";
+ break;
+
+ case kpidWarningFlags:
+ if (_headerWarning)
+ {
+ UInt32 v = kpv_ErrorFlags_HeadersError;
+ prop = v;
+ }
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ const CPartition &item = _items[index];
+
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ AString s;
+ AddName36ToString(s, item.name, false);
+ if (s.IsEmpty())
+ s.Add_UInt32(index);
+ if (item.num_extents != 0)
+ {
+ s.Add_Dot();
+ s += (item.Ext ? item.Ext : "img");
+ }
+ prop = s;
+ break;
+ }
+
+ case kpidSize: prop = item.GetSize(); break;
+ case kpidPackSize: prop = item.GetPackSize(); break;
+ case kpidNumBlocks: prop = item.num_extents; break;
+ case kpidMethod:
+ {
+ const UInt32 m = item.MethodsMask;
+ if (m != 0)
+ {
+ FLAGS_TO_PROP(g_Methods, m, prop);
+ }
+ break;
+ }
+ case kpidOffset:
+ if (item.num_extents != 0)
+ if (item.first_extent_index < Extents.Size())
+ prop = Extents[item.first_extent_index].target_data << kSectorSizeLog;
+ break;
+
+ case kpidCharacts:
+ {
+ AString s;
+ s += "group:";
+ s.Add_UInt32(item.group_index);
+ s.Add_Space();
+ s += FlagsToString(g_PartitionAttr, Z7_ARRAY_SIZE(g_PartitionAttr), item.attributes);
+ prop = s;
+ break;
+ }
+ }
+
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ *stream = NULL;
+
+ const CPartition &item = _items[index];
+
+ if (item.first_extent_index > Extents.Size()
+ || item.num_extents > Extents.Size() - item.first_extent_index)
+ return S_FALSE;
+
+ if (item.num_extents == 0)
+ return CreateLimitedInStream(_stream, 0, 0, stream);
+
+ if (item.num_extents == 1)
+ {
+ const CExtent &e = Extents[item.first_extent_index];
+ if (e.IsRAW())
+ {
+ const UInt64 pos = e.target_data << kSectorSizeLog;
+ if ((pos >> kSectorSizeLog) != e.target_data)
+ return S_FALSE;
+ const UInt64 size = item.GetSize();
+ if (pos + size < pos)
+ return S_FALSE;
+ return CreateLimitedInStream(_stream, pos, size, stream);
+ }
+ }
+
+ CExtentsStream *extentStreamSpec = new CExtentsStream();
+ CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec;
+
+ // const unsigned kNumDebugExtents = 10;
+ extentStreamSpec->Extents.Reserve(item.num_extents + 1
+ // + kNumDebugExtents
+ );
+
+ UInt64 virt = 0;
+ for (UInt32 k = 0; k < item.num_extents; k++)
+ {
+ const CExtent &e = Extents[item.first_extent_index + k];
+
+ CSeekExtent se;
+ {
+ const UInt64 numSectors = e.num_sectors;
+ if (numSectors == 0)
+ {
+ continue;
+ // return S_FALSE;
+ }
+ const UInt64 numBytes = numSectors << kSectorSizeLog;
+ if ((numBytes >> kSectorSizeLog) != numSectors)
+ return S_FALSE;
+ if (numBytes >= ((UInt64)1 << 63) - virt)
+ return S_FALSE;
+
+ se.Virt = virt;
+ virt += numBytes;
+ }
+
+ const UInt64 phySector = e.target_data;
+ if (e.target_type == LP_TARGET_TYPE_ZERO)
+ {
+ if (phySector != 0)
+ return S_FALSE;
+ se.SetAs_ZeroFill();
+ }
+ else if (e.target_type == LP_TARGET_TYPE_LINEAR)
+ {
+ se.Phy = phySector << kSectorSizeLog;
+ if ((se.Phy >> kSectorSizeLog) != phySector)
+ return S_FALSE;
+ if (se.Phy >= ((UInt64)1 << 63))
+ return S_FALSE;
+ }
+ else
+ return S_FALSE;
+
+ extentStreamSpec->Extents.AddInReserved(se);
+
+ /*
+ {
+ // for debug
+ const UInt64 kAdd = (e.num_sectors << kSectorSizeLog) / kNumDebugExtents;
+ for (unsigned i = 0; i < kNumDebugExtents; i++)
+ {
+ se.Phy += kAdd;
+ // se.Phy += (UInt64)1 << 63; // for debug
+ // se.Phy += 1; // for debug
+ se.Virt += kAdd;
+ extentStreamSpec->Extents.AddInReserved(se);
+ }
+ }
+ */
+ }
+
+ CSeekExtent se;
+ se.Phy = 0;
+ se.Virt = virt;
+ extentStreamSpec->Extents.Add(se);
+ extentStreamSpec->Stream = _stream;
+ extentStreamSpec->Init();
+ *stream = extentStream.Detach();
+
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const UInt32 index = allFilesMode ? i : indices[i];
+ totalSize += _items[index].GetSize();
+ }
+ 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);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur())
+ CMyComPtr<ISequentialOutStream> outStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+
+ RINOK(extractCallback->GetStream(index, &outStream, askMode))
+
+ const UInt64 size = _items[index].GetSize();
+ totalSize += size;
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode))
+
+ CMyComPtr<ISequentialInStream> inStream;
+ const HRESULT hres = GetStream(index, &inStream);
+ int opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ if (hres != S_FALSE)
+ {
+ if (hres != S_OK)
+ return hres;
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress))
+ opRes = NExtract::NOperationResult::kDataError;
+ if (copyCoderSpec->TotalSize == size)
+ opRes = NExtract::NOperationResult::kOK;
+ else if (copyCoderSpec->TotalSize < size)
+ opRes = NExtract::NOperationResult::kUnexpectedEnd;
+ }
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes))
+ }
+
+ return S_OK;
+ COM_TRY_END
+}
+
+
+REGISTER_ARC_I(
+ "LP", "lpimg img", NULL, 0xc1,
+ k_Signature,
+ LP_PARTITION_RESERVED_BYTES,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/LzhHandler.cpp b/CPP/7zip/Archive/LzhHandler.cpp
new file mode 100644
index 0000000..9239afd
--- /dev/null
+++ b/CPP/7zip/Archive/LzhHandler.cpp
@@ -0,0 +1,733 @@
+// LzhHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/StringConvert.h"
+
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/PropVariantUtils.h"
+#include "../../Windows/TimeUtils.h"
+
+#include "../ICoder.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+#include "../Compress/LzhDecoder.h"
+
+#include "IArchive.h"
+
+#include "Common/ItemNameUtils.h"
+
+using namespace NWindows;
+using namespace NTime;
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
+
+// CRC-16 (-IBM, -ANSI). The poly is 0x8005 (x^16 + x^15 + x^2 + 1)
+
+static const UInt16 kCrc16Poly = 0xA001;
+
+static UInt16 g_LzhCrc16Table[256];
+
+#define CRC16_UPDATE_BYTE(crc, b) (g_LzhCrc16Table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+UInt32 LzhCrc16Update(UInt32 crc, const void *data, size_t size);
+UInt32 LzhCrc16Update(UInt32 crc, const void *data, size_t size)
+{
+ const Byte *p = (const Byte *)data;
+ const Byte *pEnd = p + size;
+ for (; p != pEnd; p++)
+ crc = CRC16_UPDATE_BYTE(crc, *p);
+ return crc;
+}
+
+static struct CLzhCrc16TableInit
+{
+ CLzhCrc16TableInit()
+ {
+ for (UInt32 i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ for (unsigned j = 0; j < 8; j++)
+ r = (r >> 1) ^ (kCrc16Poly & ((UInt32)0 - (r & 1)));
+ g_LzhCrc16Table[i] = (UInt16)r;
+ }
+ }
+} g_LzhCrc16TableInit;
+
+
+namespace NArchive {
+namespace NLzh{
+
+const unsigned kMethodIdSize = 5;
+
+const Byte kExtIdFileName = 0x01;
+const Byte kExtIdDirName = 0x02;
+const Byte kExtIdUnixTime = 0x54;
+
+struct CExtension
+{
+ Byte Type;
+ CByteBuffer Data;
+
+ AString GetString() const
+ {
+ AString s;
+ s.SetFrom_CalcLen((const char *)(const Byte *)Data, (unsigned)Data.Size());
+ return s;
+ }
+};
+
+const UInt32 kBasicPartSize = 22;
+
+API_FUNC_static_IsArc IsArc_Lzh(const Byte *p, size_t size)
+{
+ if (size < 2 + kBasicPartSize)
+ return k_IsArc_Res_NEED_MORE;
+ if (p[2] != '-' || p[3] != 'l' || p[4] != 'h' || p[6] != '-')
+ return k_IsArc_Res_NO;
+ Byte n = p[5];
+ if (n != 'd')
+ if (n < '0' || n > '7')
+ return k_IsArc_Res_NO;
+ return k_IsArc_Res_YES;
+}
+}
+
+struct CItem
+{
+ AString Name;
+ Byte Method[kMethodIdSize];
+ Byte Attributes;
+ Byte Level;
+ Byte OsId;
+ UInt32 PackSize;
+ UInt32 Size;
+ UInt32 ModifiedTime;
+ UInt16 CRC;
+ CObjectVector<CExtension> Extensions;
+
+ bool IsValidMethod() const { return (Method[0] == '-' && Method[1] == 'l' && Method[4] == '-'); }
+ bool IsLhMethod() const {return (IsValidMethod() && Method[2] == 'h'); }
+ bool IsDir() const {return (IsLhMethod() && Method[3] == 'd'); }
+
+ bool IsCopyMethod() const
+ {
+ return (IsLhMethod() && Method[3] == '0') ||
+ (IsValidMethod() && Method[2] == 'z' && Method[3] == '4');
+ }
+
+ bool IsLh1GroupMethod() const
+ {
+ if (!IsLhMethod())
+ return false;
+ switch (Method[3])
+ {
+ case '1':
+ return true;
+ }
+ return false;
+ }
+
+ bool IsLh4GroupMethod() const
+ {
+ if (!IsLhMethod())
+ return false;
+ switch (Method[3])
+ {
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ return true;
+ }
+ return false;
+ }
+
+ unsigned GetNumDictBits() const
+ {
+ if (!IsLhMethod())
+ return 0;
+ switch (Method[3])
+ {
+ case '1': return 12;
+ case '2': return 13;
+ case '3': return 13;
+ case '4': return 12;
+ case '5': return 13;
+ case '6': return 15;
+ case '7': return 16;
+ }
+ return 0;
+ }
+
+ int FindExt(Byte type) const
+ {
+ FOR_VECTOR (i, Extensions)
+ if (Extensions[i].Type == type)
+ return (int)i;
+ return -1;
+ }
+
+ bool GetUnixTime(UInt32 &value) const
+ {
+ value = 0;
+ int index = FindExt(kExtIdUnixTime);
+ if (index < 0
+ || Extensions[index].Data.Size() < 4)
+ {
+ if (Level == 2)
+ {
+ value = ModifiedTime;
+ return true;
+ }
+ return false;
+ }
+ const Byte *data = (const Byte *)(Extensions[index].Data);
+ value = GetUi32(data);
+ return true;
+ }
+
+ AString GetDirName() const
+ {
+ int index = FindExt(kExtIdDirName);
+ if (index < 0)
+ return AString();
+ return Extensions[index].GetString();
+ }
+
+ AString GetFileName() const
+ {
+ int index = FindExt(kExtIdFileName);
+ if (index < 0)
+ return Name;
+ return Extensions[index].GetString();
+ }
+
+ AString GetName() const
+ {
+ AString s (GetDirName());
+ const char kDirSeparator = '\\';
+ // check kDirSeparator in Linux
+ s.Replace((char)(unsigned char)0xFF, kDirSeparator);
+ if (!s.IsEmpty() && s.Back() != kDirSeparator)
+ s += kDirSeparator;
+ s += GetFileName();
+ return s;
+ }
+};
+
+static const Byte *ReadUInt16(const Byte *p, UInt16 &v)
+{
+ v = Get16(p);
+ return p + 2;
+}
+
+static const Byte *ReadString(const Byte *p, size_t size, AString &s)
+{
+ s.Empty();
+ for (size_t i = 0; i < size; i++)
+ {
+ const Byte c = p[i];
+ if (c == 0)
+ break;
+ s += (char)c;
+ }
+ return p + size;
+}
+
+static Byte CalcSum(const Byte *data, size_t size)
+{
+ Byte sum = 0;
+ for (size_t i = 0; i < size; i++)
+ sum = (Byte)(sum + data[i]);
+ return sum;
+}
+
+static HRESULT GetNextItem(ISequentialInStream *stream, bool &filled, CItem &item)
+{
+ filled = false;
+
+ size_t processedSize = 2;
+ Byte startHeader[2];
+ RINOK(ReadStream(stream, startHeader, &processedSize))
+ if (processedSize == 0)
+ return S_OK;
+ if (processedSize == 1)
+ return (startHeader[0] == 0) ? S_OK: S_FALSE;
+ if (startHeader[0] == 0 && startHeader[1] == 0)
+ return S_OK;
+
+ Byte header[256];
+ processedSize = kBasicPartSize;
+ RINOK(ReadStream(stream, header, &processedSize))
+ if (processedSize != kBasicPartSize)
+ return (startHeader[0] == 0) ? S_OK: S_FALSE;
+
+ const Byte *p = header;
+ memcpy(item.Method, p, kMethodIdSize);
+ if (!item.IsValidMethod())
+ return S_OK;
+ p += kMethodIdSize;
+ item.PackSize = Get32(p);
+ item.Size = Get32(p + 4);
+ item.ModifiedTime = Get32(p + 8);
+ item.Attributes = p[12];
+ item.Level = p[13];
+ p += 14;
+ if (item.Level > 2)
+ return S_FALSE;
+ UInt32 headerSize;
+ if (item.Level < 2)
+ {
+ headerSize = startHeader[0];
+ if (headerSize < kBasicPartSize)
+ return S_FALSE;
+ RINOK(ReadStream_FALSE(stream, header + kBasicPartSize, headerSize - kBasicPartSize))
+ if (startHeader[1] != CalcSum(header, headerSize))
+ return S_FALSE;
+ const size_t nameLength = *p++;
+ if ((size_t)(p - header) + nameLength + 2 > headerSize)
+ return S_FALSE;
+ p = ReadString(p, nameLength, item.Name);
+ }
+ else
+ headerSize = startHeader[0] | ((UInt32)startHeader[1] << 8);
+ p = ReadUInt16(p, item.CRC);
+ if (item.Level != 0)
+ {
+ if (item.Level == 2)
+ {
+ RINOK(ReadStream_FALSE(stream, header + kBasicPartSize, 2))
+ }
+ if ((size_t)(p - header) + 3 > headerSize)
+ return S_FALSE;
+ item.OsId = *p++;
+ UInt16 nextSize;
+ p = ReadUInt16(p, nextSize);
+ while (nextSize != 0)
+ {
+ if (nextSize < 3)
+ return S_FALSE;
+ if (item.Level == 1)
+ {
+ if (item.PackSize < nextSize)
+ return S_FALSE;
+ item.PackSize -= nextSize;
+ }
+ if (item.Extensions.Size() >= (1 << 8))
+ return S_FALSE;
+ CExtension ext;
+ RINOK(ReadStream_FALSE(stream, &ext.Type, 1))
+ nextSize = (UInt16)(nextSize - 3);
+ ext.Data.Alloc(nextSize);
+ RINOK(ReadStream_FALSE(stream, (Byte *)ext.Data, nextSize))
+ item.Extensions.Add(ext);
+ Byte hdr2[2];
+ RINOK(ReadStream_FALSE(stream, hdr2, 2))
+ ReadUInt16(hdr2, nextSize);
+ }
+ }
+ filled = true;
+ return S_OK;
+}
+
+
+static const CUInt32PCharPair g_OsPairs[] =
+{
+ { 0, "MS-DOS" },
+ { 'M', "MS-DOS" },
+ { '2', "OS/2" },
+ { '9', "OS9" },
+ { 'K', "OS/68K" },
+ { '3', "OS/386" },
+ { 'H', "HUMAN" },
+ { 'U', "UNIX" },
+ { 'C', "CP/M" },
+ { 'F', "FLEX" },
+ { 'm', "Mac" },
+ { 'R', "Runser" },
+ { 'T', "TownsOS" },
+ { 'X', "XOSK" },
+ { 'w', "Windows 95" },
+ { 'W', "Windows NT" },
+ { 'J', "Java VM" }
+};
+
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ // kpidAttrib,
+ kpidCRC,
+ kpidMethod,
+ kpidHostOS
+};
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ COutStreamWithCRC
+ , ISequentialOutStream
+)
+ UInt32 _crc;
+ CMyComPtr<ISequentialOutStream> _stream;
+public:
+ void Init(ISequentialOutStream *stream)
+ {
+ _stream = stream;
+ _crc = 0;
+ }
+ void ReleaseStream() { _stream.Release(); }
+ UInt32 GetCRC() const { return _crc; }
+};
+
+Z7_COM7F_IMF(COutStreamWithCRC::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ HRESULT res = S_OK;
+ if (_stream)
+ res = _stream->Write(data, size, &size);
+ _crc = LzhCrc16Update(_crc, data, size);
+ if (processedSize)
+ *processedSize = size;
+ return res;
+}
+
+
+struct CItemEx: public CItem
+{
+ UInt64 DataPosition;
+};
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_0
+
+ CObjectVector<CItemEx> _items;
+ CMyComPtr<IInStream> _stream;
+ UInt64 _phySize;
+ UInt32 _errorFlags;
+ bool _isArc;
+public:
+ CHandler();
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+CHandler::CHandler() {}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySize: prop = _phySize; break;
+
+ case kpidErrorFlags:
+ UInt32 v = _errorFlags;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
+ prop = v;
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ const CItemEx &item = _items[index];
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ UString s = NItemName::WinPathToOsPath(MultiByteToUnicodeString(item.GetName(), CP_OEMCP));
+ if (!s.IsEmpty())
+ {
+ if (s.Back() == WCHAR_PATH_SEPARATOR)
+ s.DeleteBack();
+ prop = s;
+ }
+ break;
+ }
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: prop = item.Size; break;
+ case kpidPackSize: prop = item.PackSize; break;
+ case kpidCRC: prop = (UInt32)item.CRC; break;
+ case kpidHostOS: PAIR_TO_PROP(g_OsPairs, item.OsId, prop); break;
+ case kpidMTime:
+ {
+ UInt32 unixTime;
+ if (item.GetUnixTime(unixTime))
+ PropVariant_SetFrom_UnixTime(prop, unixTime);
+ else
+ PropVariant_SetFrom_DosTime(prop, item.ModifiedTime);
+ break;
+ }
+ // case kpidAttrib: prop = (UInt32)item.Attributes; break;
+ case kpidMethod:
+ {
+ char method2[kMethodIdSize + 1];
+ method2[kMethodIdSize] = 0;
+ memcpy(method2, item.Method, kMethodIdSize);
+ prop = method2;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ Close();
+ try
+ {
+ _items.Clear();
+
+ UInt64 endPos;
+ bool needSetTotal = true;
+
+ RINOK(InStream_AtBegin_GetSize(stream, endPos))
+
+ for (;;)
+ {
+ CItemEx item;
+ bool filled;
+ const HRESULT res = GetNextItem(stream, filled, item);
+ RINOK(InStream_GetPos(stream, item.DataPosition))
+ if (res == S_FALSE)
+ {
+ _errorFlags = kpv_ErrorFlags_HeadersError;
+ break;
+ }
+
+ if (res != S_OK)
+ return S_FALSE;
+ _phySize = item.DataPosition;
+ if (!filled)
+ break;
+ _items.Add(item);
+
+ _isArc = true;
+
+ UInt64 newPostion;
+ RINOK(stream->Seek(item.PackSize, STREAM_SEEK_CUR, &newPostion))
+ if (newPostion > endPos)
+ {
+ _phySize = endPos;
+ _errorFlags = kpv_ErrorFlags_UnexpectedEnd;
+ break;
+ }
+ _phySize = newPostion;
+ if (callback)
+ {
+ if (needSetTotal)
+ {
+ RINOK(callback->SetTotal(NULL, &endPos))
+ needSetTotal = false;
+ }
+ if (_items.Size() % 100 == 0)
+ {
+ UInt64 numFiles = _items.Size();
+ UInt64 numBytes = item.DataPosition;
+ RINOK(callback->SetCompleted(&numFiles, &numBytes))
+ }
+ }
+ }
+ if (_items.IsEmpty())
+ return S_FALSE;
+
+ _stream = stream;
+ }
+ catch(...)
+ {
+ return S_FALSE;
+ }
+ COM_TRY_END
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _isArc = false;
+ _phySize = 0;
+ _errorFlags = 0;
+ _items.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalUnPacked = 0 /* , totalPacked = 0 */;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItemEx &item = _items[allFilesMode ? i : indices[i]];
+ totalUnPacked += item.Size;
+ // totalPacked += item.PackSize;
+ }
+ RINOK(extractCallback->SetTotal(totalUnPacked))
+
+ UInt64 currentItemUnPacked, currentItemPacked;
+
+ NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = NULL;
+ CMyComPtr<ICompressCoder> lzhDecoder;
+ // CMyComPtr<ICompressCoder> lzh1Decoder;
+ // CMyComPtr<ICompressCoder> arj2Decoder;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0;; i++,
+ lps->OutSize += currentItemUnPacked,
+ lps->InSize += currentItemPacked)
+ {
+ currentItemUnPacked = 0;
+ currentItemPacked = 0;
+
+ RINOK(lps->SetCur())
+
+ if (i >= numItems)
+ break;
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CItemEx &item = _items[index];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+ if (item.IsDir())
+ {
+ // if (!testMode)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ }
+ continue;
+ }
+
+ if (!testMode && !realOutStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode))
+ currentItemUnPacked = item.Size;
+ currentItemPacked = item.PackSize;
+
+ {
+ COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->Init(realOutStream);
+ realOutStream.Release();
+
+ RINOK(InStream_SeekSet(_stream, item.DataPosition))
+
+ streamSpec->Init(item.PackSize);
+
+ HRESULT res = S_OK;
+ Int32 opRes = NExtract::NOperationResult::kOK;
+
+ if (item.IsCopyMethod())
+ {
+ res = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ if (res == S_OK && copyCoderSpec->TotalSize != item.PackSize)
+ res = S_FALSE;
+ }
+ else if (item.IsLh4GroupMethod())
+ {
+ if (!lzhDecoder)
+ {
+ lzhDecoderSpec = new NCompress::NLzh::NDecoder::CCoder;
+ lzhDecoder = lzhDecoderSpec;
+ }
+ lzhDecoderSpec->FinishMode = true;
+ lzhDecoderSpec->SetDictSize(1 << item.GetNumDictBits());
+ res = lzhDecoder->Code(inStream, outStream, NULL, &currentItemUnPacked, progress);
+ if (res == S_OK && lzhDecoderSpec->GetInputProcessedSize() != item.PackSize)
+ res = S_FALSE;
+ }
+ /*
+ else if (item.IsLh1GroupMethod())
+ {
+ if (!lzh1Decoder)
+ {
+ lzh1DecoderSpec = new NCompress::NLzh1::NDecoder::CCoder;
+ lzh1Decoder = lzh1DecoderSpec;
+ }
+ lzh1DecoderSpec->SetDictionary(item.GetNumDictBits());
+ res = lzh1Decoder->Code(inStream, outStream, NULL, &currentItemUnPacked, progress);
+ }
+ */
+ else
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+
+ if (opRes == NExtract::NOperationResult::kOK)
+ {
+ if (res == S_FALSE)
+ opRes = NExtract::NOperationResult::kDataError;
+ else
+ {
+ RINOK(res)
+ if (outStreamSpec->GetCRC() != item.CRC)
+ opRes = NExtract::NOperationResult::kCRCError;
+ }
+ }
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes))
+ }
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+static const Byte k_Signature[] = { '-', 'l', 'h' };
+
+REGISTER_ARC_I(
+ "Lzh", "lzh lha", NULL, 6,
+ k_Signature,
+ 2,
+ 0,
+ IsArc_Lzh)
+
+}}
diff --git a/CPP/7zip/Archive/LzmaHandler.cpp b/CPP/7zip/Archive/LzmaHandler.cpp
index f13fca7..11cb76e 100644
--- a/CPP/7zip/Archive/LzmaHandler.cpp
+++ b/CPP/7zip/Archive/LzmaHandler.cpp
@@ -1,629 +1,611 @@
-// LzmaHandler.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/CpuArch.h"
-
-#include "../../Common/ComTry.h"
-#include "../../Common/IntToString.h"
-
-#include "../../Windows/PropVariant.h"
-
-#include "../Common/FilterCoder.h"
-#include "../Common/ProgressUtils.h"
-#include "../Common/RegisterArc.h"
-#include "../Common/StreamUtils.h"
-
-#include "../Compress/BcjCoder.h"
-#include "../Compress/LzmaDecoder.h"
-
-#include "Common/DummyOutStream.h"
-
-using namespace NWindows;
-
-namespace NArchive {
-namespace NLzma {
-
-static bool CheckDicSize(const Byte *p)
-{
- UInt32 dicSize = GetUi32(p);
- if (dicSize == 1)
- return true;
- for (unsigned i = 0; i <= 30; i++)
- if (dicSize == ((UInt32)2 << i) || dicSize == ((UInt32)3 << i))
- return true;
- return (dicSize == 0xFFFFFFFF);
-}
-
-static const Byte kProps[] =
-{
- kpidSize,
- kpidPackSize,
- kpidMethod
-};
-
-static const Byte kArcProps[] =
-{
- kpidNumStreams,
- kpidMethod
-};
-
-struct CHeader
-{
- UInt64 Size;
- Byte FilterID;
- Byte LzmaProps[5];
-
- Byte GetProp() const { return LzmaProps[0]; }
- UInt32 GetDicSize() const { return GetUi32(LzmaProps + 1); }
- bool HasSize() const { return (Size != (UInt64)(Int64)-1); }
- bool Parse(const Byte *buf, bool isThereFilter);
-};
-
-bool CHeader::Parse(const Byte *buf, bool isThereFilter)
-{
- FilterID = 0;
- if (isThereFilter)
- FilterID = buf[0];
- const Byte *sig = buf + (isThereFilter ? 1 : 0);
- for (int i = 0; i < 5; i++)
- LzmaProps[i] = sig[i];
- Size = GetUi64(sig + 5);
- return
- LzmaProps[0] < 5 * 5 * 9 &&
- FilterID < 2 &&
- (!HasSize() || Size < ((UInt64)1 << 56))
- && CheckDicSize(LzmaProps + 1);
-}
-
-class CDecoder
-{
- CMyComPtr<ISequentialOutStream> _bcjStream;
- CFilterCoder *_filterCoder;
- CMyComPtr<ICompressCoder> _lzmaDecoder;
-public:
- NCompress::NLzma::CDecoder *_lzmaDecoderSpec;
-
- ~CDecoder();
- HRESULT Create(bool filtered, ISequentialInStream *inStream);
-
- HRESULT Code(const CHeader &header, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
-
- UInt64 GetInputProcessedSize() const { return _lzmaDecoderSpec->GetInputProcessedSize(); }
-
- void ReleaseInStream() { if (_lzmaDecoder) _lzmaDecoderSpec->ReleaseInStream(); }
-
- HRESULT ReadInput(Byte *data, UInt32 size, UInt32 *processedSize)
- { return _lzmaDecoderSpec->ReadFromInputStream(data, size, processedSize); }
-};
-
-HRESULT CDecoder::Create(bool filteredMode, ISequentialInStream *inStream)
-{
- if (!_lzmaDecoder)
- {
- _lzmaDecoderSpec = new NCompress::NLzma::CDecoder;
- _lzmaDecoderSpec->FinishStream = true;
- _lzmaDecoder = _lzmaDecoderSpec;
- }
-
- if (filteredMode)
- {
- if (!_bcjStream)
- {
- _filterCoder = new CFilterCoder(false);
- CMyComPtr<ICompressCoder> coder = _filterCoder;
- _filterCoder->Filter = new NCompress::NBcj::CCoder(false);
- _bcjStream = _filterCoder;
- }
- }
-
- return _lzmaDecoderSpec->SetInStream(inStream);
-}
-
-CDecoder::~CDecoder()
-{
- ReleaseInStream();
-}
-
-HRESULT CDecoder::Code(const CHeader &header, ISequentialOutStream *outStream,
- ICompressProgressInfo *progress)
-{
- if (header.FilterID > 1)
- return E_NOTIMPL;
-
- RINOK(_lzmaDecoderSpec->SetDecoderProperties2(header.LzmaProps, 5));
-
- bool filteredMode = (header.FilterID == 1);
-
- if (filteredMode)
- {
- RINOK(_filterCoder->SetOutStream(outStream));
- outStream = _bcjStream;
- RINOK(_filterCoder->SetOutStreamSize(NULL));
- }
-
- const UInt64 *Size = header.HasSize() ? &header.Size : NULL;
- HRESULT res = _lzmaDecoderSpec->CodeResume(outStream, Size, progress);
-
- if (filteredMode)
- {
- {
- HRESULT res2 = _filterCoder->OutStreamFinish();
- if (res == S_OK)
- res = res2;
- }
- HRESULT res2 = _filterCoder->ReleaseOutStream();
- if (res == S_OK)
- res = res2;
- }
-
- RINOK(res);
-
- if (header.HasSize())
- if (_lzmaDecoderSpec->GetOutputProcessedSize() != header.Size)
- return S_FALSE;
-
- return S_OK;
-}
-
-
-class CHandler:
- public IInArchive,
- public IArchiveOpenSeq,
- public CMyUnknownImp
-{
- CHeader _header;
- bool _lzma86;
- CMyComPtr<IInStream> _stream;
- CMyComPtr<ISequentialInStream> _seqStream;
-
- bool _isArc;
- bool _needSeekToStart;
- bool _dataAfterEnd;
- bool _needMoreInput;
-
- bool _packSize_Defined;
- bool _unpackSize_Defined;
- bool _numStreams_Defined;
-
- bool _unsupported;
- bool _dataError;
-
- UInt64 _packSize;
- UInt64 _unpackSize;
- UInt64 _numStreams;
-
- void GetMethod(NCOM::CPropVariant &prop);
-
-public:
- MY_UNKNOWN_IMP2(IInArchive, IArchiveOpenSeq)
-
- INTERFACE_IInArchive(;)
- STDMETHOD(OpenSeq)(ISequentialInStream *stream);
-
- CHandler(bool lzma86) { _lzma86 = lzma86; }
-
- unsigned GetHeaderSize() const { return 5 + 8 + (_lzma86 ? 1 : 0); }
-
-};
-
-IMP_IInArchive_Props
-IMP_IInArchive_ArcProps
-
-STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
-{
- NCOM::CPropVariant prop;
- switch (propID)
- {
- case kpidPhySize: if (_packSize_Defined) prop = _packSize; break;
- case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break;
- case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break;
- case kpidMethod: GetMethod(prop); break;
- case kpidErrorFlags:
- {
- UInt32 v = 0;
- if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;;
- if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
- if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
- if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod;
- if (_dataError) v |= kpv_ErrorFlags_DataError;
- prop = v;
- break;
- }
- }
- prop.Detach(value);
- return S_OK;
-}
-
-STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
-{
- *numItems = 1;
- return S_OK;
-}
-
-
-static void DictSizeToString(UInt32 val, char *s)
-{
- for (unsigned i = 0; i <= 31; i++)
- if (((UInt32)1 << i) == val)
- {
- ::ConvertUInt32ToString(i, s);
- return;
- }
- char c = 'b';
- if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; }
- else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; }
- ::ConvertUInt32ToString(val, s);
- s += MyStringLen(s);
- *s++ = c;
- *s = 0;
-}
-
-static char *AddProp32(char *s, const char *name, UInt32 v)
-{
- *s++ = ':';
- s = MyStpCpy(s, name);
- ::ConvertUInt32ToString(v, s);
- return s + MyStringLen(s);
-}
-
-void CHandler::GetMethod(NCOM::CPropVariant &prop)
-{
- if (!_stream)
- return;
-
- char sz[64];
- char *s = sz;
- if (_header.FilterID != 0)
- s = MyStpCpy(s, "BCJ ");
- s = MyStpCpy(s, "LZMA:");
- DictSizeToString(_header.GetDicSize(), s);
- s += strlen(s);
-
- UInt32 d = _header.GetProp();
- // if (d != 0x5D)
- {
- UInt32 lc = d % 9;
- d /= 9;
- UInt32 pb = d / 5;
- UInt32 lp = d % 5;
- if (lc != 3) s = AddProp32(s, "lc", lc);
- if (lp != 0) s = AddProp32(s, "lp", lp);
- if (pb != 2) s = AddProp32(s, "pb", pb);
- }
- prop = sz;
-}
-
-
-STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
-{
- NCOM::CPropVariant prop;
- switch (propID)
- {
- case kpidSize: if (_stream && _header.HasSize()) prop = _header.Size; break;
- case kpidPackSize: if (_packSize_Defined) prop = _packSize; break;
- case kpidMethod: GetMethod(prop); break;
- }
- prop.Detach(value);
- return S_OK;
-}
-
-API_FUNC_static_IsArc IsArc_Lzma(const Byte *p, size_t size)
-{
- const UInt32 kHeaderSize = 1 + 4 + 8;
- if (size < kHeaderSize)
- return k_IsArc_Res_NEED_MORE;
- if (p[0] >= 5 * 5 * 9)
- return k_IsArc_Res_NO;
- UInt64 unpackSize = GetUi64(p + 1 + 4);
- if (unpackSize != (UInt64)(Int64)-1)
- {
- if (size >= ((UInt64)1 << 56))
- return k_IsArc_Res_NO;
- }
- if (unpackSize != 0)
- {
- if (size < kHeaderSize + 2)
- return k_IsArc_Res_NEED_MORE;
- if (p[kHeaderSize] != 0)
- return k_IsArc_Res_NO;
- if (unpackSize != (UInt64)(Int64)-1)
- {
- if ((p[kHeaderSize + 1] & 0x80) != 0)
- return k_IsArc_Res_NO;
- }
- }
- if (!CheckDicSize(p + 1))
- // return k_IsArc_Res_YES_LOW_PROB;
- return k_IsArc_Res_NO;
- return k_IsArc_Res_YES;
-}
-}
-
-API_FUNC_static_IsArc IsArc_Lzma86(const Byte *p, size_t size)
-{
- if (size < 1)
- return k_IsArc_Res_NEED_MORE;
- Byte filterID = p[0];
- if (filterID != 0 && filterID != 1)
- return k_IsArc_Res_NO;
- return IsArc_Lzma(p + 1, size - 1);
-}
-}
-
-
-
-STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *)
-{
- Close();
-
- const unsigned headerSize = GetHeaderSize();
- const UInt32 kBufSize = 1 << 7;
- Byte buf[kBufSize];
- size_t processedSize = kBufSize;
- RINOK(ReadStream(inStream, buf, &processedSize));
- if (processedSize < headerSize + 2)
- return S_FALSE;
- if (!_header.Parse(buf, _lzma86))
- return S_FALSE;
- const Byte *start = buf + headerSize;
- if (start[0] != 0 /* || (start[1] & 0x80) != 0 */ ) // empty stream with EOS is not 0x80
- return S_FALSE;
-
- RINOK(inStream->Seek(0, STREAM_SEEK_END, &_packSize));
-
- SizeT srcLen = processedSize - headerSize;
-
- if (srcLen > 10
- && _header.Size == 0
- // && _header.FilterID == 0
- && _header.LzmaProps[0] == 0
- )
- return S_FALSE;
-
- CDecoder state;
- const UInt32 outLimit = 1 << 11;
- Byte outBuf[outLimit];
-
- SizeT outSize = outLimit;
- if (outSize > _header.Size)
- outSize = (SizeT)_header.Size;
- SizeT destLen = outSize;
- ELzmaStatus status;
-
- SRes res = LzmaDecode(outBuf, &destLen, start, &srcLen,
- _header.LzmaProps, 5, LZMA_FINISH_ANY,
- &status, &g_Alloc);
-
- if (res != SZ_OK)
- if (res != SZ_ERROR_INPUT_EOF)
- return S_FALSE;
-
- _isArc = true;
- _stream = inStream;
- _seqStream = inStream;
- _needSeekToStart = true;
- return S_OK;
-}
-
-STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
-{
- Close();
- _isArc = true;
- _seqStream = stream;
- return S_OK;
-}
-
-STDMETHODIMP CHandler::Close()
-{
- _isArc = false;
- _packSize_Defined = false;
- _unpackSize_Defined = false;
- _numStreams_Defined = false;
-
- _dataAfterEnd = false;
- _needMoreInput = false;
- _unsupported = false;
- _dataError = false;
-
- _packSize = 0;
-
- _needSeekToStart = false;
-
- _stream.Release();
- _seqStream.Release();
- return S_OK;
-}
-
-class CCompressProgressInfoImp:
- public ICompressProgressInfo,
- public CMyUnknownImp
-{
- CMyComPtr<IArchiveOpenCallback> Callback;
-public:
- UInt64 Offset;
-
- MY_UNKNOWN_IMP1(ICompressProgressInfo)
- STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
- void Init(IArchiveOpenCallback *callback) { Callback = callback; }
-};
-
-STDMETHODIMP CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)
-{
- if (Callback)
- {
- const UInt64 files = 0;
- const UInt64 val = Offset + *inSize;
- return Callback->SetCompleted(&files, &val);
- }
- 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)(Int32)-1 && (numItems != 1 || indices[0] != 0))
- return E_INVALIDARG;
-
- if (_packSize_Defined)
- extractCallback->SetTotal(_packSize);
-
-
- CMyComPtr<ISequentialOutStream> realOutStream;
- Int32 askMode = testMode ?
- NExtract::NAskMode::kTest :
- NExtract::NAskMode::kExtract;
- RINOK(extractCallback->GetStream(0, &realOutStream, askMode));
- if (!testMode && !realOutStream)
- return S_OK;
-
- extractCallback->PrepareOperation(askMode);
-
- CDummyOutStream *outStreamSpec = new CDummyOutStream;
- CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
- outStreamSpec->SetStream(realOutStream);
- outStreamSpec->Init();
- realOutStream.Release();
-
- CLocalProgress *lps = new CLocalProgress;
- CMyComPtr<ICompressProgressInfo> progress = lps;
- lps->Init(extractCallback, true);
-
- if (_needSeekToStart)
- {
- if (!_stream)
- return E_FAIL;
- RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
- }
- else
- _needSeekToStart = true;
-
- CDecoder decoder;
- HRESULT result = decoder.Create(_lzma86, _seqStream);
- RINOK(result);
-
- bool firstItem = true;
-
- UInt64 packSize = 0;
- UInt64 unpackSize = 0;
- UInt64 numStreams = 0;
-
- bool dataAfterEnd = false;
-
- for (;;)
- {
- lps->InSize = packSize;
- lps->OutSize = unpackSize;
- RINOK(lps->SetCur());
-
- const UInt32 kBufSize = 1 + 5 + 8;
- Byte buf[kBufSize];
- const UInt32 headerSize = GetHeaderSize();
- UInt32 processed;
- RINOK(decoder.ReadInput(buf, headerSize, &processed));
- if (processed != headerSize)
- {
- if (processed != 0)
- dataAfterEnd = true;
- break;
- }
-
- CHeader st;
- if (!st.Parse(buf, _lzma86))
- {
- dataAfterEnd = true;
- break;
- }
- numStreams++;
- firstItem = false;
-
- result = decoder.Code(st, outStream, progress);
-
- packSize = decoder.GetInputProcessedSize();
- unpackSize = outStreamSpec->GetSize();
-
- if (result == E_NOTIMPL)
- {
- _unsupported = true;
- result = S_FALSE;
- break;
- }
- if (result == S_FALSE)
- break;
- RINOK(result);
- }
-
- if (firstItem)
- {
- _isArc = false;
- result = S_FALSE;
- }
- else if (result == S_OK || result == S_FALSE)
- {
- if (dataAfterEnd)
- _dataAfterEnd = true;
- else if (decoder._lzmaDecoderSpec->NeedsMoreInput())
- _needMoreInput = true;
-
- _packSize = packSize;
- _unpackSize = unpackSize;
- _numStreams = numStreams;
-
- _packSize_Defined = true;
- _unpackSize_Defined = true;
- _numStreams_Defined = true;
- }
-
- Int32 opResult = NExtract::NOperationResult::kOK;
-
- if (!_isArc)
- opResult = NExtract::NOperationResult::kIsNotArc;
- else if (_needMoreInput)
- opResult = NExtract::NOperationResult::kUnexpectedEnd;
- else if (_unsupported)
- opResult = NExtract::NOperationResult::kUnsupportedMethod;
- else if (_dataAfterEnd)
- opResult = NExtract::NOperationResult::kDataAfterEnd;
- else if (result == S_FALSE)
- opResult = NExtract::NOperationResult::kDataError;
- else if (result == S_OK)
- opResult = NExtract::NOperationResult::kOK;
- else
- return result;
-
- outStream.Release();
- return extractCallback->SetOperationResult(opResult);
-
- COM_TRY_END
-}
-
-namespace NLzmaAr {
-
-// 2, { 0x5D, 0x00 },
-
-REGISTER_ARC_I_CLS_NO_SIG(
- CHandler(false),
- "lzma", "lzma", 0, 0xA,
- 0,
- NArcInfoFlags::kStartOpen |
- NArcInfoFlags::kKeepName,
- IsArc_Lzma)
-
-}
-
-namespace NLzma86Ar {
-
-REGISTER_ARC_I_CLS_NO_SIG(
- CHandler(true),
- "lzma86", "lzma86", 0, 0xB,
- 0,
- NArcInfoFlags::kKeepName,
- IsArc_Lzma86)
-
-}
-
-}}
+// LzmaHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/FilterCoder.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/BcjCoder.h"
+#include "../Compress/LzmaDecoder.h"
+
+#include "Common/DummyOutStream.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NLzma {
+
+static bool CheckDicSize(const Byte *p)
+{
+ UInt32 dicSize = GetUi32(p);
+ if (dicSize == 1)
+ return true;
+ for (unsigned i = 0; i <= 30; i++)
+ if (dicSize == ((UInt32)2 << i) || dicSize == ((UInt32)3 << i))
+ return true;
+ return (dicSize == 0xFFFFFFFF);
+}
+
+static const Byte kProps[] =
+{
+ kpidSize,
+ kpidPackSize,
+ kpidMethod
+};
+
+static const Byte kArcProps[] =
+{
+ kpidNumStreams,
+ kpidMethod
+};
+
+struct CHeader
+{
+ UInt64 Size;
+ Byte FilterID;
+ Byte LzmaProps[5];
+
+ Byte GetProp() const { return LzmaProps[0]; }
+ UInt32 GetDicSize() const { return GetUi32(LzmaProps + 1); }
+ bool HasSize() const { return (Size != (UInt64)(Int64)-1); }
+ bool Parse(const Byte *buf, bool isThereFilter);
+};
+
+bool CHeader::Parse(const Byte *buf, bool isThereFilter)
+{
+ FilterID = 0;
+ if (isThereFilter)
+ FilterID = buf[0];
+ const Byte *sig = buf + (isThereFilter ? 1 : 0);
+ for (int i = 0; i < 5; i++)
+ LzmaProps[i] = sig[i];
+ Size = GetUi64(sig + 5);
+ return
+ LzmaProps[0] < 5 * 5 * 9 &&
+ FilterID < 2 &&
+ (!HasSize() || Size < ((UInt64)1 << 56))
+ && CheckDicSize(LzmaProps + 1);
+}
+
+class CDecoder Z7_final
+{
+ CMyComPtr<ISequentialOutStream> _bcjStream;
+ CFilterCoder *_filterCoder;
+ CMyComPtr<ICompressCoder> _lzmaDecoder;
+public:
+ NCompress::NLzma::CDecoder *_lzmaDecoderSpec;
+
+ ~CDecoder();
+ HRESULT Create(bool filtered, ISequentialInStream *inStream);
+
+ HRESULT Code(const CHeader &header, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
+
+ UInt64 GetInputProcessedSize() const { return _lzmaDecoderSpec->GetInputProcessedSize(); }
+
+ void ReleaseInStream() { if (_lzmaDecoder) _lzmaDecoderSpec->ReleaseInStream(); }
+
+ HRESULT ReadInput(Byte *data, UInt32 size, UInt32 *processedSize)
+ { return _lzmaDecoderSpec->ReadFromInputStream(data, size, processedSize); }
+};
+
+HRESULT CDecoder::Create(bool filteredMode, ISequentialInStream *inStream)
+{
+ if (!_lzmaDecoder)
+ {
+ _lzmaDecoderSpec = new NCompress::NLzma::CDecoder;
+ _lzmaDecoderSpec->FinishStream = true;
+ _lzmaDecoder = _lzmaDecoderSpec;
+ }
+
+ if (filteredMode)
+ {
+ if (!_bcjStream)
+ {
+ _filterCoder = new CFilterCoder(false);
+ CMyComPtr<ICompressCoder> coder = _filterCoder;
+ _filterCoder->Filter = new NCompress::NBcj::CCoder2(z7_BranchConvSt_X86_Dec);
+ _bcjStream = _filterCoder;
+ }
+ }
+
+ return _lzmaDecoderSpec->SetInStream(inStream);
+}
+
+CDecoder::~CDecoder()
+{
+ ReleaseInStream();
+}
+
+HRESULT CDecoder::Code(const CHeader &header, ISequentialOutStream *outStream,
+ ICompressProgressInfo *progress)
+{
+ if (header.FilterID > 1)
+ return E_NOTIMPL;
+
+ RINOK(_lzmaDecoderSpec->SetDecoderProperties2(header.LzmaProps, 5))
+
+ bool filteredMode = (header.FilterID == 1);
+
+ if (filteredMode)
+ {
+ RINOK(_filterCoder->SetOutStream(outStream))
+ outStream = _bcjStream;
+ RINOK(_filterCoder->SetOutStreamSize(NULL))
+ }
+
+ const UInt64 *Size = header.HasSize() ? &header.Size : NULL;
+ HRESULT res = _lzmaDecoderSpec->CodeResume(outStream, Size, progress);
+
+ if (filteredMode)
+ {
+ {
+ HRESULT res2 = _filterCoder->OutStreamFinish();
+ if (res == S_OK)
+ res = res2;
+ }
+ HRESULT res2 = _filterCoder->ReleaseOutStream();
+ if (res == S_OK)
+ res = res2;
+ }
+
+ RINOK(res)
+
+ if (header.HasSize())
+ if (_lzmaDecoderSpec->GetOutputProcessedSize() != header.Size)
+ return S_FALSE;
+
+ return S_OK;
+}
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IArchiveOpenSeq
+)
+ CHeader _header;
+ bool _lzma86;
+ CMyComPtr<IInStream> _stream;
+ CMyComPtr<ISequentialInStream> _seqStream;
+
+ bool _isArc;
+ bool _needSeekToStart;
+ bool _dataAfterEnd;
+ bool _needMoreInput;
+ bool _unsupported;
+ bool _dataError;
+
+ bool _packSize_Defined;
+ bool _unpackSize_Defined;
+ bool _numStreams_Defined;
+
+ UInt64 _packSize;
+ UInt64 _unpackSize;
+ UInt64 _numStreams;
+
+ void GetMethod(NCOM::CPropVariant &prop);
+
+ unsigned GetHeaderSize() const { return 5 + 8 + (_lzma86 ? 1 : 0); }
+public:
+ CHandler(bool lzma86) { _lzma86 = lzma86; }
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySize: if (_packSize_Defined) prop = _packSize; break;
+ case kpidNumStreams: if (_numStreams_Defined) prop = _numStreams; break;
+ case kpidUnpackSize: if (_unpackSize_Defined) prop = _unpackSize; break;
+ case kpidMethod: GetMethod(prop); break;
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
+ if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
+ if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod;
+ if (_dataError) v |= kpv_ErrorFlags_DataError;
+ prop = v;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+
+static char * DictSizeToString(UInt32 val, char *s)
+{
+ for (unsigned i = 0; i < 32; i++)
+ if (((UInt32)1 << i) == val)
+ return ::ConvertUInt32ToString(i, s);
+ char c = 'b';
+ if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; }
+ else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; }
+ s = ::ConvertUInt32ToString(val, s);
+ *s++ = c;
+ *s = 0;
+ return s;
+}
+
+static char *AddProp32(char *s, const char *name, UInt32 v)
+{
+ *s++ = ':';
+ s = MyStpCpy(s, name);
+ return ::ConvertUInt32ToString(v, s);
+}
+
+void CHandler::GetMethod(NCOM::CPropVariant &prop)
+{
+ if (!_stream)
+ return;
+
+ char sz[64];
+ char *s = sz;
+ if (_header.FilterID != 0)
+ s = MyStpCpy(s, "BCJ ");
+ s = MyStpCpy(s, "LZMA:");
+ s = DictSizeToString(_header.GetDicSize(), s);
+
+ UInt32 d = _header.GetProp();
+ // if (d != 0x5D)
+ {
+ UInt32 lc = d % 9;
+ d /= 9;
+ UInt32 pb = d / 5;
+ UInt32 lp = d % 5;
+ if (lc != 3) s = AddProp32(s, "lc", lc);
+ if (lp != 0) s = AddProp32(s, "lp", lp);
+ if (pb != 2) s = AddProp32(s, "pb", pb);
+ }
+ prop = sz;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidSize: if (_stream && _header.HasSize()) prop = _header.Size; break;
+ case kpidPackSize: if (_packSize_Defined) prop = _packSize; break;
+ case kpidMethod: GetMethod(prop); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+API_FUNC_static_IsArc IsArc_Lzma(const Byte *p, size_t size)
+{
+ const UInt32 kHeaderSize = 1 + 4 + 8;
+ if (size < kHeaderSize)
+ return k_IsArc_Res_NEED_MORE;
+ if (p[0] >= 5 * 5 * 9)
+ return k_IsArc_Res_NO;
+ const UInt64 unpackSize = GetUi64(p + 1 + 4);
+ if (unpackSize != (UInt64)(Int64)-1)
+ {
+ if (unpackSize >= ((UInt64)1 << 56))
+ return k_IsArc_Res_NO;
+ }
+ if (unpackSize != 0)
+ {
+ if (size < kHeaderSize + 2)
+ return k_IsArc_Res_NEED_MORE;
+ if (p[kHeaderSize] != 0)
+ return k_IsArc_Res_NO;
+ if (unpackSize != (UInt64)(Int64)-1)
+ {
+ if ((p[kHeaderSize + 1] & 0x80) != 0)
+ return k_IsArc_Res_NO;
+ }
+ }
+ if (!CheckDicSize(p + 1))
+ // return k_IsArc_Res_YES_LOW_PROB;
+ return k_IsArc_Res_NO;
+ return k_IsArc_Res_YES;
+}
+}
+
+API_FUNC_static_IsArc IsArc_Lzma86(const Byte *p, size_t size)
+{
+ if (size < 1)
+ return k_IsArc_Res_NEED_MORE;
+ Byte filterID = p[0];
+ if (filterID != 0 && filterID != 1)
+ return k_IsArc_Res_NO;
+ return IsArc_Lzma(p + 1, size - 1);
+}
+}
+
+
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *))
+{
+ Close();
+
+ const unsigned headerSize = GetHeaderSize();
+ const UInt32 kBufSize = 1 << 7;
+ Byte buf[kBufSize];
+ size_t processedSize = kBufSize;
+ RINOK(ReadStream(inStream, buf, &processedSize))
+ if (processedSize < headerSize + 2)
+ return S_FALSE;
+ if (!_header.Parse(buf, _lzma86))
+ return S_FALSE;
+ const Byte *start = buf + headerSize;
+ if (start[0] != 0 /* || (start[1] & 0x80) != 0 */ ) // empty stream with EOS is not 0x80
+ return S_FALSE;
+
+ RINOK(InStream_GetSize_SeekToEnd(inStream, _packSize))
+
+ SizeT srcLen = (SizeT)processedSize - headerSize;
+
+ if (srcLen > 10
+ && _header.Size == 0
+ // && _header.FilterID == 0
+ && _header.LzmaProps[0] == 0
+ )
+ return S_FALSE;
+
+ CDecoder state;
+ const UInt32 outLimit = 1 << 11;
+ Byte outBuf[outLimit];
+
+ SizeT outSize = outLimit;
+ if (outSize > _header.Size)
+ outSize = (SizeT)_header.Size;
+ SizeT destLen = outSize;
+ ELzmaStatus status;
+
+ SRes res = LzmaDecode(outBuf, &destLen, start, &srcLen,
+ _header.LzmaProps, 5, LZMA_FINISH_ANY,
+ &status, &g_Alloc);
+
+ if (res != SZ_OK)
+ if (res != SZ_ERROR_INPUT_EOF)
+ return S_FALSE;
+
+ _isArc = true;
+ _stream = inStream;
+ _seqStream = inStream;
+ _needSeekToStart = true;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream))
+{
+ Close();
+ _isArc = true;
+ _seqStream = stream;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _isArc = false;
+ _needSeekToStart = false;
+ _dataAfterEnd = false;
+ _needMoreInput = false;
+ _unsupported = false;
+ _dataError = false;
+
+ _packSize_Defined = false;
+ _unpackSize_Defined = false;
+ _numStreams_Defined = false;
+
+ _packSize = 0;
+
+ _stream.Release();
+ _seqStream.Release();
+ return S_OK;
+}
+
+Z7_CLASS_IMP_COM_1(
+ CCompressProgressInfoImp,
+ ICompressProgressInfo
+)
+ CMyComPtr<IArchiveOpenCallback> Callback;
+public:
+ UInt64 Offset;
+
+ void Init(IArchiveOpenCallback *callback) { Callback = callback; }
+};
+
+Z7_COM7F_IMF(CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */))
+{
+ if (Callback)
+ {
+ const UInt64 files = 0;
+ const UInt64 val = Offset + *inSize;
+ return Callback->SetCompleted(&files, &val);
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ if (_packSize_Defined)
+ extractCallback->SetTotal(_packSize);
+
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode))
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, true);
+
+ if (_needSeekToStart)
+ {
+ if (!_stream)
+ return E_FAIL;
+ RINOK(InStream_SeekToBegin(_stream))
+ }
+ else
+ _needSeekToStart = true;
+
+ CDecoder decoder;
+ HRESULT result = decoder.Create(_lzma86, _seqStream);
+ RINOK(result)
+
+ bool firstItem = true;
+
+ UInt64 packSize = 0;
+ UInt64 unpackSize = 0;
+ UInt64 numStreams = 0;
+
+ bool dataAfterEnd = false;
+
+ for (;;)
+ {
+ lps->InSize = packSize;
+ lps->OutSize = unpackSize;
+ RINOK(lps->SetCur())
+
+ const UInt32 kBufSize = 1 + 5 + 8;
+ Byte buf[kBufSize];
+ const UInt32 headerSize = GetHeaderSize();
+ UInt32 processed;
+ RINOK(decoder.ReadInput(buf, headerSize, &processed))
+ if (processed != headerSize)
+ {
+ if (processed != 0)
+ dataAfterEnd = true;
+ break;
+ }
+
+ CHeader st;
+ if (!st.Parse(buf, _lzma86))
+ {
+ dataAfterEnd = true;
+ break;
+ }
+ numStreams++;
+ firstItem = false;
+
+ result = decoder.Code(st, outStream, progress);
+
+ packSize = decoder.GetInputProcessedSize();
+ unpackSize = outStreamSpec->GetSize();
+
+ if (result == E_NOTIMPL)
+ {
+ _unsupported = true;
+ result = S_FALSE;
+ break;
+ }
+ if (result == S_FALSE)
+ break;
+ RINOK(result)
+ }
+
+ if (firstItem)
+ {
+ _isArc = false;
+ result = S_FALSE;
+ }
+ else if (result == S_OK || result == S_FALSE)
+ {
+ if (dataAfterEnd)
+ _dataAfterEnd = true;
+ else if (decoder._lzmaDecoderSpec->NeedsMoreInput())
+ _needMoreInput = true;
+
+ _packSize = packSize;
+ _unpackSize = unpackSize;
+ _numStreams = numStreams;
+
+ _packSize_Defined = true;
+ _unpackSize_Defined = true;
+ _numStreams_Defined = true;
+ }
+
+ Int32 opResult = NExtract::NOperationResult::kOK;
+
+ if (!_isArc)
+ opResult = NExtract::NOperationResult::kIsNotArc;
+ else if (_needMoreInput)
+ opResult = NExtract::NOperationResult::kUnexpectedEnd;
+ else if (_unsupported)
+ opResult = NExtract::NOperationResult::kUnsupportedMethod;
+ else if (_dataAfterEnd)
+ opResult = NExtract::NOperationResult::kDataAfterEnd;
+ else if (result == S_FALSE)
+ opResult = NExtract::NOperationResult::kDataError;
+ else if (result == S_OK)
+ opResult = NExtract::NOperationResult::kOK;
+ else
+ return result;
+
+ outStream.Release();
+ return extractCallback->SetOperationResult(opResult);
+
+ COM_TRY_END
+}
+
+namespace NLzmaAr {
+
+// 2, { 0x5D, 0x00 },
+
+REGISTER_ARC_I_CLS_NO_SIG(
+ CHandler(false),
+ "lzma", "lzma", NULL, 0xA,
+ 0,
+ NArcInfoFlags::kStartOpen |
+ NArcInfoFlags::kKeepName,
+ IsArc_Lzma)
+
+}
+
+namespace NLzma86Ar {
+
+REGISTER_ARC_I_CLS_NO_SIG(
+ CHandler(true),
+ "lzma86", "lzma86", NULL, 0xB,
+ 0,
+ NArcInfoFlags::kKeepName,
+ IsArc_Lzma86)
+
+}
+
+}}
diff --git a/CPP/7zip/Archive/MachoHandler.cpp b/CPP/7zip/Archive/MachoHandler.cpp
new file mode 100644
index 0000000..4920a04
--- /dev/null
+++ b/CPP/7zip/Archive/MachoHandler.cpp
@@ -0,0 +1,744 @@
+// MachoHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/StringConvert.h"
+#include "../../Common/IntToString.h"
+
+#include "../../Windows/PropVariantUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+static UInt32 Get32(const Byte *p, bool be) { if (be) return GetBe32(p); return GetUi32(p); }
+static UInt64 Get64(const Byte *p, bool be) { if (be) return GetBe64(p); return GetUi64(p); }
+
+using namespace NWindows;
+using namespace NCOM;
+
+namespace NArchive {
+namespace NMacho {
+
+#define CPU_ARCH_ABI64 (1 << 24)
+#define CPU_TYPE_386 7
+#define CPU_TYPE_ARM 12
+#define CPU_TYPE_SPARC 14
+#define CPU_TYPE_PPC 18
+
+#define CPU_SUBTYPE_I386_ALL 3
+
+// #define CPU_TYPE_PPC64 (CPU_ARCH_ABI64 | CPU_TYPE_PPC)
+#define CPU_TYPE_AMD64 (CPU_ARCH_ABI64 | CPU_TYPE_386)
+#define CPU_TYPE_ARM64 (CPU_ARCH_ABI64 | CPU_TYPE_ARM)
+
+#define CPU_SUBTYPE_LIB64 ((UInt32)1 << 31)
+
+#define CPU_SUBTYPE_POWERPC_970 100
+
+static const char * const k_PowerPc_SubTypes[] =
+{
+ NULL
+ , "601"
+ , "602"
+ , "603"
+ , "603e"
+ , "603ev"
+ , "604"
+ , "604e"
+ , "620"
+ , "750"
+ , "7400"
+ , "7450"
+};
+
+static const CUInt32PCharPair g_CpuPairs[] =
+{
+ { CPU_TYPE_AMD64, "x64" },
+ { CPU_TYPE_ARM64, "ARM64" },
+ { CPU_TYPE_386, "x86" },
+ { CPU_TYPE_ARM, "ARM" },
+ { CPU_TYPE_SPARC, "SPARC" },
+ { CPU_TYPE_PPC, "PowerPC" }
+};
+
+
+#define CMD_SEGMENT_32 1
+#define CMD_SEGMENT_64 0x19
+
+#define SECT_TYPE_MASK 0x000000FF
+#define SECT_ATTR_MASK 0xFFFFFF00
+
+#define SECT_ATTR_ZEROFILL 1
+
+static const char * const g_SectTypes[] =
+{
+ "REGULAR"
+ , "ZEROFILL"
+ , "CSTRINGS"
+ , "4BYTE_LITERALS"
+ , "8BYTE_LITERALS"
+ , "LITERAL_POINTERS"
+ , "NON_LAZY_SYMBOL_POINTERS"
+ , "LAZY_SYMBOL_POINTERS"
+ , "SYMBOL_STUBS"
+ , "MOD_INIT_FUNC_POINTERS"
+ , "MOD_TERM_FUNC_POINTERS"
+ , "COALESCED"
+ , "GB_ZEROFILL"
+ , "INTERPOSING"
+ , "16BYTE_LITERALS"
+ , "DTRACE_DOF"
+ , "LAZY_DYLIB_SYMBOL_POINTERS"
+ , "THREAD_LOCAL_REGULAR"
+ , "THREAD_LOCAL_ZEROFILL"
+ , "THREAD_LOCAL_VARIABLES"
+ , "THREAD_LOCAL_VARIABLE_POINTERS"
+ , "THREAD_LOCAL_INIT_FUNCTION_POINTERS"
+};
+
+enum EFileType
+{
+ kType_OBJECT = 1,
+ kType_EXECUTE,
+ kType_FVMLIB,
+ kType_CORE,
+ kType_PRELOAD,
+ kType_DYLIB,
+ kType_DYLINKER,
+ kType_BUNDLE,
+ kType_DYLIB_STUB,
+ kType_DSYM
+};
+
+static const char * const g_FileTypes[] =
+{
+ "0"
+ , "OBJECT"
+ , "EXECUTE"
+ , "FVMLIB"
+ , "CORE"
+ , "PRELOAD"
+ , "DYLIB"
+ , "DYLINKER"
+ , "BUNDLE"
+ , "DYLIB_STUB"
+ , "DSYM"
+};
+
+
+static const char * const g_ArcFlags[] =
+{
+ "NOUNDEFS"
+ , "INCRLINK"
+ , "DYLDLINK"
+ , "BINDATLOAD"
+ , "PREBOUND"
+ , "SPLIT_SEGS"
+ , "LAZY_INIT"
+ , "TWOLEVEL"
+ , "FORCE_FLAT"
+ , "NOMULTIDEFS"
+ , "NOFIXPREBINDING"
+ , "PREBINDABLE"
+ , "ALLMODSBOUND"
+ , "SUBSECTIONS_VIA_SYMBOLS"
+ , "CANONICAL"
+ , "WEAK_DEFINES"
+ , "BINDS_TO_WEAK"
+ , "ALLOW_STACK_EXECUTION"
+ , "ROOT_SAFE"
+ , "SETUID_SAFE"
+ , "NO_REEXPORTED_DYLIBS"
+ , "PIE"
+ , "DEAD_STRIPPABLE_DYLIB"
+ , "HAS_TLV_DESCRIPTORS"
+ , "NO_HEAP_EXECUTION"
+};
+
+
+static const CUInt32PCharPair g_SectFlags[] =
+{
+ { 31, "PURE_INSTRUCTIONS" },
+ { 30, "NO_TOC" },
+ { 29, "STRIP_STATIC_SYMS" },
+ { 28, "NO_DEAD_STRIP" },
+ { 27, "LIVE_SUPPORT" },
+ { 26, "SELF_MODIFYING_CODE" },
+ { 25, "DEBUG" },
+ { 10, "SOME_INSTRUCTIONS" },
+ { 9, "EXT_RELOC" },
+ { 8, "LOC_RELOC" }
+};
+
+
+// VM_PROT_*
+static const char * const g_SegmentProt[] =
+{
+ "READ"
+ , "WRITE"
+ , "EXECUTE"
+ /*
+ , "NO_CHANGE"
+ , "COPY"
+ , "TRUSTED"
+ , "IS_MASK"
+ */
+};
+
+// SG_*
+
+static const char * const g_SegmentFlags[] =
+{
+ "SG_HIGHVM"
+ , "SG_FVMLIB"
+ , "SG_NORELOC"
+ , "SG_PROTECTED_VERSION_1"
+ , "SG_READ_ONLY"
+};
+
+static const unsigned kNameSize = 16;
+
+struct CSegment
+{
+ char Name[kNameSize];
+ UInt32 MaxProt;
+ UInt32 InitProt;
+ UInt32 Flags;
+};
+
+struct CSection
+{
+ char Name[kNameSize];
+ // char SegName[kNameSize];
+ UInt64 Va;
+ UInt64 Pa;
+ UInt64 VSize;
+ UInt64 PSize;
+
+ UInt32 Align;
+ UInt32 Flags;
+ unsigned SegmentIndex;
+ bool IsDummy;
+
+ CSection(): IsDummy(false) {}
+ // UInt64 GetPackSize() const { return Flags == SECT_ATTR_ZEROFILL ? 0 : Size; }
+ UInt64 GetPackSize() const { return PSize; }
+};
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IArchiveAllowTail
+)
+ CMyComPtr<IInStream> _inStream;
+ CObjectVector<CSegment> _segments;
+ CObjectVector<CSection> _sections;
+ bool _allowTail;
+ bool _mode64;
+ bool _be;
+ UInt32 _cpuType;
+ UInt32 _cpuSubType;
+ UInt32 _type;
+ UInt32 _flags;
+ UInt32 _headersSize;
+ UInt64 _totalSize;
+
+ HRESULT Open2(ISequentialInStream *stream);
+public:
+ CHandler(): _allowTail(false) {}
+};
+
+static const Byte kArcProps[] =
+{
+ kpidCpu,
+ kpidBit64,
+ kpidBigEndian,
+ kpidCharacts,
+ kpidHeadersSize
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
+ kpidCharacts,
+ kpidOffset,
+ kpidVa,
+ kpidClusterSize // Align
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ CPropVariant prop;
+ switch (propID)
+ {
+ case kpidShortComment:
+ case kpidCpu:
+ {
+ AString s;
+ const UInt32 cpu = _cpuType & ~(UInt32)CPU_ARCH_ABI64;
+ UInt32 flag64 = _cpuType & (UInt32)CPU_ARCH_ABI64;
+ {
+ s.Add_UInt32(cpu);
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_CpuPairs); i++)
+ {
+ const CUInt32PCharPair &pair = g_CpuPairs[i];
+ if (pair.Value == cpu || pair.Value == _cpuType)
+ {
+ if (pair.Value == _cpuType)
+ flag64 = 0;
+ s = pair.Name;
+ break;
+ }
+ }
+
+ if (flag64 != 0)
+ s.Add_OptSpaced("64-bit");
+ else if ((_cpuSubType & CPU_SUBTYPE_LIB64) && _cpuType != CPU_TYPE_AMD64)
+ s.Add_OptSpaced("64-bit-lib");
+ }
+ const UInt32 t = _cpuSubType & ~(UInt32)CPU_SUBTYPE_LIB64;
+ if (t != 0 && (t != CPU_SUBTYPE_I386_ALL || cpu != CPU_TYPE_386))
+ {
+ const char *n = NULL;
+ if (cpu == CPU_TYPE_PPC)
+ {
+ if (t == CPU_SUBTYPE_POWERPC_970)
+ n = "970";
+ else if (t < Z7_ARRAY_SIZE(k_PowerPc_SubTypes))
+ n = k_PowerPc_SubTypes[t];
+ }
+ s.Add_Space();
+ if (n)
+ s += n;
+ else
+ s.Add_UInt32(t);
+ }
+ prop = s;
+ break;
+ }
+ case kpidCharacts:
+ {
+ // TYPE_TO_PROP(g_FileTypes, _type, prop); break;
+ AString res (TypeToString(g_FileTypes, Z7_ARRAY_SIZE(g_FileTypes), _type));
+ const AString s (FlagsToString(g_ArcFlags, Z7_ARRAY_SIZE(g_ArcFlags), _flags));
+ if (!s.IsEmpty())
+ {
+ res.Add_Space();
+ res += s;
+ }
+ prop = res;
+ break;
+ }
+ case kpidPhySize: prop = _totalSize; break;
+ case kpidHeadersSize: prop = _headersSize; break;
+ case kpidBit64: if (_mode64) prop = _mode64; break;
+ case kpidBigEndian: if (_be) prop = _be; break;
+ case kpidExtension:
+ {
+ const char *ext = NULL;
+ if (_type == kType_OBJECT)
+ ext = "o";
+ else if (_type == kType_BUNDLE)
+ ext = "bundle";
+ else if (_type == kType_DYLIB)
+ ext = "dylib"; // main shared library usually does not have extension
+ if (ext)
+ prop = ext;
+ break;
+ }
+ // case kpidIsSelfExe: prop = (_type == kType_EXECUTE); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+static void AddName(AString &s, const char *name)
+{
+ char temp[kNameSize + 1];
+ memcpy(temp, name, kNameSize);
+ temp[kNameSize] = 0;
+ s += temp;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ CPropVariant prop;
+ const CSection &item = _sections[index];
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ AString s;
+ AddName(s, _segments[item.SegmentIndex].Name);
+ if (!item.IsDummy)
+ {
+ // CSection::SegName and CSegment::Name are same in real cases.
+ // AddName(s, item.SegName);
+ AddName(s, item.Name);
+ }
+ prop = MultiByteToUnicodeString(s);
+ break;
+ }
+ case kpidSize: /* prop = (UInt64)item.VSize; break; */
+ case kpidPackSize: prop = (UInt64)item.GetPackSize(); break;
+ case kpidCharacts:
+ {
+ AString res;
+ {
+ if (!item.IsDummy)
+ {
+ {
+ const AString s (TypeToString(g_SectTypes, Z7_ARRAY_SIZE(g_SectTypes), item.Flags & SECT_TYPE_MASK));
+ if (!s.IsEmpty())
+ {
+ res.Add_OptSpaced("sect_type:");
+ res.Add_OptSpaced(s);
+ }
+ }
+ {
+ const AString s (FlagsToString(g_SectFlags, Z7_ARRAY_SIZE(g_SectFlags), item.Flags & SECT_ATTR_MASK));
+ if (!s.IsEmpty())
+ {
+ res.Add_OptSpaced("sect_flags:");
+ res.Add_OptSpaced(s);
+ }
+ }
+ }
+ const CSegment &seg = _segments[item.SegmentIndex];
+ {
+ const AString s (FlagsToString(g_SegmentFlags, Z7_ARRAY_SIZE(g_SegmentFlags), seg.Flags));
+ if (!s.IsEmpty())
+ {
+ res.Add_OptSpaced("seg_flags:");
+ res.Add_OptSpaced(s);
+ }
+ }
+ {
+ const AString s (FlagsToString(g_SegmentProt, Z7_ARRAY_SIZE(g_SegmentProt), seg.MaxProt));
+ if (!s.IsEmpty())
+ {
+ res.Add_OptSpaced("max_prot:");
+ res.Add_OptSpaced(s);
+ }
+ }
+ {
+ const AString s (FlagsToString(g_SegmentProt, Z7_ARRAY_SIZE(g_SegmentProt), seg.InitProt));
+ if (!s.IsEmpty())
+ {
+ res.Add_OptSpaced("init_prot:");
+ res.Add_OptSpaced(s);
+ }
+ }
+ }
+ if (!res.IsEmpty())
+ prop = res;
+ break;
+ }
+ case kpidOffset: prop = item.Pa; break;
+ case kpidVa: prop = item.Va; break;
+ case kpidClusterSize: prop = (UInt32)1 << item.Align; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+HRESULT CHandler::Open2(ISequentialInStream *stream)
+{
+ const UInt32 kStartHeaderSize = 7 * 4;
+
+ Byte header[kStartHeaderSize];
+ RINOK(ReadStream_FALSE(stream, header, kStartHeaderSize))
+ bool be, mode64;
+ switch (GetUi32(header))
+ {
+ case 0xCEFAEDFE: be = true; mode64 = false; break;
+ case 0xCFFAEDFE: be = true; mode64 = true; break;
+ case 0xFEEDFACE: be = false; mode64 = false; break;
+ case 0xFEEDFACF: be = false; mode64 = true; break;
+ default: return S_FALSE;
+ }
+
+ _mode64 = mode64;
+ _be = be;
+
+ const UInt32 numCommands = Get32(header + 0x10, be);
+ const UInt32 commandsSize = Get32(header + 0x14, be);
+
+ if (numCommands == 0)
+ return S_FALSE;
+
+ if (commandsSize > (1 << 24) ||
+ numCommands > (1 << 21) ||
+ numCommands * 8 > commandsSize)
+ return S_FALSE;
+
+ _cpuType = Get32(header + 4, be);
+ _cpuSubType = Get32(header + 8, be);
+ _type = Get32(header + 0xC, be);
+ _flags = Get32(header + 0x18, be);
+
+ /*
+ // Probably the sections are in first commands. So we can reduce the number of commands.
+ bool reduceCommands = false;
+ const UInt32 kNumReduceCommands = 16;
+ if (numCommands > kNumReduceCommands)
+ {
+ reduceCommands = true;
+ numCommands = kNumReduceCommands;
+ }
+ */
+
+ UInt32 startHeaderSize = kStartHeaderSize;
+ if (mode64)
+ startHeaderSize += 4;
+ _headersSize = startHeaderSize + commandsSize;
+ _totalSize = _headersSize;
+ CByteArr buffer(_headersSize);
+ RINOK(ReadStream_FALSE(stream, buffer + kStartHeaderSize, _headersSize - kStartHeaderSize))
+ const Byte *buf = buffer + startHeaderSize;
+ size_t size = _headersSize - startHeaderSize;
+ for (UInt32 cmdIndex = 0; cmdIndex < numCommands; cmdIndex++)
+ {
+ if (size < 8)
+ return S_FALSE;
+ UInt32 cmd = Get32(buf, be);
+ UInt32 cmdSize = Get32(buf + 4, be);
+ if (cmdSize < 8)
+ return S_FALSE;
+ if (size < cmdSize)
+ return S_FALSE;
+ if (cmd == CMD_SEGMENT_32 || cmd == CMD_SEGMENT_64)
+ {
+ UInt32 offs = (cmd == CMD_SEGMENT_64) ? 0x48 : 0x38;
+ if (cmdSize < offs)
+ break;
+
+ UInt64 vmAddr, vmSize, phAddr, phSize;
+
+ {
+ if (cmd == CMD_SEGMENT_64)
+ {
+ vmAddr = Get64(buf + 0x18, be);
+ vmSize = Get64(buf + 0x20, be);
+ phAddr = Get64(buf + 0x28, be);
+ phSize = Get64(buf + 0x30, be);
+ }
+ else
+ {
+ vmAddr = Get32(buf + 0x18, be);
+ vmSize = Get32(buf + 0x1C, be);
+ phAddr = Get32(buf + 0x20, be);
+ phSize = Get32(buf + 0x24, be);
+ }
+ {
+ UInt64 totalSize = phAddr + phSize;
+ if (totalSize < phAddr)
+ return S_FALSE;
+ if (_totalSize < totalSize)
+ _totalSize = totalSize;
+ }
+ }
+
+ CSegment seg;
+ seg.MaxProt = Get32(buf + offs - 16, be);
+ seg.InitProt = Get32(buf + offs - 12, be);
+ seg.Flags = Get32(buf + offs - 4, be);
+ memcpy(seg.Name, buf + 8, kNameSize);
+ _segments.Add(seg);
+
+ UInt32 numSections = Get32(buf + offs - 8, be);
+ if (numSections > (1 << 8))
+ return S_FALSE;
+
+ if (numSections == 0)
+ {
+ CSection &sect = _sections.AddNew();
+ sect.IsDummy = true;
+ sect.SegmentIndex = _segments.Size() - 1;
+ sect.Va = vmAddr;
+ sect.PSize = phSize;
+ sect.VSize = vmSize;
+ sect.Pa = phAddr;
+ sect.Align = 0;
+ sect.Flags = 0;
+ }
+ else do
+ {
+ const UInt32 headSize = (cmd == CMD_SEGMENT_64) ? 0x50 : 0x44;
+ const Byte *p = buf + offs;
+ if (cmdSize - offs < headSize)
+ break;
+ CSection &sect = _sections.AddNew();
+ unsigned f32Offset;
+ if (cmd == CMD_SEGMENT_64)
+ {
+ sect.Va = Get64(p + 0x20, be);
+ sect.VSize = Get64(p + 0x28, be);
+ f32Offset = 0x30;
+ }
+ else
+ {
+ sect.Va = Get32(p + 0x20, be);
+ sect.VSize = Get32(p + 0x24, be);
+ f32Offset = 0x28;
+ }
+ sect.Pa = Get32(p + f32Offset, be);
+ sect.Align = Get32(p + f32Offset + 4, be);
+ // sect.reloff = Get32(p + f32Offset + 8, be);
+ // sect.nreloc = Get32(p + f32Offset + 12, be);
+ sect.Flags = Get32(p + f32Offset + 16, be);
+ if ((sect.Flags & SECT_TYPE_MASK) == SECT_ATTR_ZEROFILL)
+ sect.PSize = 0;
+ else
+ sect.PSize = sect.VSize;
+ memcpy(sect.Name, p, kNameSize);
+ // memcpy(sect.SegName, p + kNameSize, kNameSize);
+ sect.SegmentIndex = _segments.Size() - 1;
+ offs += headSize;
+ }
+ while (--numSections);
+
+ if (offs != cmdSize)
+ return S_FALSE;
+ }
+ buf += cmdSize;
+ size -= cmdSize;
+ }
+ // return (reduceCommands || (size == 0)) ? S_OK : S_FALSE;
+ if (size != 0)
+ return S_FALSE;
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */))
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(Open2(inStream))
+ if (!_allowTail)
+ {
+ UInt64 fileSize;
+ RINOK(InStream_GetSize_SeekToEnd(inStream, fileSize))
+ if (fileSize > _totalSize)
+ return S_FALSE;
+ }
+ _inStream = inStream;
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _totalSize = 0;
+ _inStream.Release();
+ _sections.Clear();
+ _segments.Clear();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _sections.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _sections.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _sections[allFilesMode ? i : indices[i]].GetPackSize();
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+ UInt64 currentItemSize;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_inStream);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur())
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CSection &item = _sections[index];
+ currentItemSize = item.GetPackSize();
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ RINOK(extractCallback->GetStream(index, &outStream, askMode))
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(InStream_SeekSet(_inStream, item.Pa))
+ streamSpec->Init(currentItemSize);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress))
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(copyCoderSpec->TotalSize == currentItemSize ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::AllowTail(Int32 allowTail))
+{
+ _allowTail = IntToBool(allowTail);
+ return S_OK;
+}
+
+static const Byte k_Signature[] = {
+ 4, 0xCE, 0xFA, 0xED, 0xFE,
+ 4, 0xCF, 0xFA, 0xED, 0xFE,
+ 4, 0xFE, 0xED, 0xFA, 0xCE,
+ 4, 0xFE, 0xED, 0xFA, 0xCF };
+
+REGISTER_ARC_I(
+ "MachO", "macho", NULL, 0xDF,
+ k_Signature,
+ 0,
+ NArcInfoFlags::kMultiSignature |
+ NArcInfoFlags::kPreArc,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/MbrHandler.cpp b/CPP/7zip/Archive/MbrHandler.cpp
new file mode 100644
index 0000000..0d3611b
--- /dev/null
+++ b/CPP/7zip/Archive/MbrHandler.cpp
@@ -0,0 +1,567 @@
+// MbrHandler.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#endif
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "HandlerCont.h"
+
+#ifdef SHOW_DEBUG_INFO
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NMbr {
+
+struct CChs
+{
+ Byte Head;
+ Byte SectCyl;
+ Byte Cyl8;
+
+ UInt32 GetSector() const { return SectCyl & 0x3F; }
+ UInt32 GetCyl() const { return ((UInt32)SectCyl >> 6 << 8) | Cyl8; }
+ void ToString(NCOM::CPropVariant &prop) const;
+
+ void Parse(const Byte *p)
+ {
+ Head = p[0];
+ SectCyl = p[1];
+ Cyl8 = p[2];
+ }
+ bool Check() const { return GetSector() > 0; }
+};
+
+
+// Chs in some MBRs contains only low bits of "Cyl number". So we disable check.
+/*
+#define RINOZ(x) { int _t_ = (x); if (_t_ != 0) return _t_; }
+static int CompareChs(const CChs &c1, const CChs &c2)
+{
+ RINOZ(MyCompare(c1.GetCyl(), c2.GetCyl()));
+ RINOZ(MyCompare(c1.Head, c2.Head));
+ return MyCompare(c1.GetSector(), c2.GetSector());
+}
+*/
+
+void CChs::ToString(NCOM::CPropVariant &prop) const
+{
+ AString s;
+ s.Add_UInt32(GetCyl());
+ s.Add_Minus();
+ s.Add_UInt32(Head);
+ s.Add_Minus();
+ s.Add_UInt32(GetSector());
+ prop = s;
+}
+
+struct CPartition
+{
+ Byte Status;
+ CChs BeginChs;
+ Byte Type;
+ CChs EndChs;
+ UInt32 Lba;
+ UInt32 NumBlocks;
+
+ CPartition() { memset (this, 0, sizeof(*this)); }
+
+ bool IsEmpty() const { return Type == 0; }
+ bool IsExtended() const { return Type == 5 || Type == 0xF; }
+ UInt32 GetLimit() const { return Lba + NumBlocks; }
+ // bool IsActive() const { return Status == 0x80; }
+ UInt64 GetPos() const { return (UInt64)Lba * 512; }
+ UInt64 GetSize() const { return (UInt64)NumBlocks * 512; }
+
+ bool CheckLbaLimits() const { return (UInt32)0xFFFFFFFF - Lba >= NumBlocks; }
+ bool Parse(const Byte *p)
+ {
+ Status = p[0];
+ BeginChs.Parse(p + 1);
+ Type = p[4];
+ EndChs.Parse(p + 5);
+ Lba = GetUi32(p + 8);
+ NumBlocks = GetUi32(p + 12);
+ if (Type == 0)
+ return true;
+ if (Status != 0 && Status != 0x80)
+ return false;
+ return BeginChs.Check()
+ && EndChs.Check()
+ // && CompareChs(BeginChs, EndChs) <= 0
+ && NumBlocks > 0
+ && CheckLbaLimits();
+ }
+
+ #ifdef SHOW_DEBUG_INFO
+ void Print() const
+ {
+ NCOM::CPropVariant prop, prop2;
+ BeginChs.ToString(prop);
+ EndChs.ToString(prop2);
+ printf(" %2x %2x %8X %8X %12S %12S", (int)Status, (int)Type, Lba, NumBlocks, prop.bstrVal, prop2.bstrVal);
+ }
+ #endif
+};
+
+struct CPartType
+{
+ UInt32 Id;
+ const char *Ext;
+ const char *Name;
+};
+
+#define kFat "fat"
+
+/*
+if we use "format" command in Windows 10 for existing partition:
+ - if we format to ExFAT, it sets type=7
+ - if we format to UDF, it doesn't change type from previous value.
+*/
+
+static const unsigned kType_Windows_NTFS = 7;
+
+static const CPartType kPartTypes[] =
+{
+ { 0x01, kFat, "FAT12" },
+ { 0x04, kFat, "FAT16 DOS 3.0+" },
+ { 0x05, NULL, "Extended" },
+ { 0x06, kFat, "FAT16 DOS 3.31+" },
+ { 0x07, "ntfs", "NTFS" },
+ { 0x0B, kFat, "FAT32" },
+ { 0x0C, kFat, "FAT32-LBA" },
+ { 0x0E, kFat, "FAT16-LBA" },
+ { 0x0F, NULL, "Extended-LBA" },
+ { 0x11, kFat, "FAT12-Hidden" },
+ { 0x14, kFat, "FAT16-Hidden < 32 MB" },
+ { 0x16, kFat, "FAT16-Hidden >= 32 MB" },
+ { 0x1B, kFat, "FAT32-Hidden" },
+ { 0x1C, kFat, "FAT32-LBA-Hidden" },
+ { 0x1E, kFat, "FAT16-LBA-WIN95-Hidden" },
+ { 0x27, "ntfs", "NTFS-WinRE" },
+ { 0x82, NULL, "Solaris x86 / Linux swap" },
+ { 0x83, NULL, "Linux" },
+ { 0x8E, "lvm", "Linux LVM" },
+ { 0xA5, NULL, "BSD slice" },
+ { 0xBE, NULL, "Solaris 8 boot" },
+ { 0xBF, NULL, "New Solaris x86" },
+ { 0xC2, NULL, "Linux-Hidden" },
+ { 0xC3, NULL, "Linux swap-Hidden" },
+ { 0xEE, NULL, "GPT" },
+ { 0xEE, NULL, "EFI" }
+};
+
+static int FindPartType(UInt32 type)
+{
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(kPartTypes); i++)
+ if (kPartTypes[i].Id == type)
+ return (int)i;
+ return -1;
+}
+
+struct CItem
+{
+ bool IsReal;
+ bool IsPrim;
+ bool WasParsed;
+ const char *FileSystem;
+ UInt64 Size;
+ CPartition Part;
+
+ CItem():
+ WasParsed(false),
+ FileSystem(NULL)
+ {}
+};
+
+
+Z7_class_CHandler_final: public CHandlerCont
+{
+ Z7_IFACE_COM7_IMP(IInArchive_Cont)
+
+ CObjectVector<CItem> _items;
+ UInt64 _totalSize;
+ CByteBuffer _buffer;
+
+ virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override Z7_final
+ {
+ const CItem &item = _items[index];
+ pos = item.Part.GetPos();
+ size = item.Size;
+ return NExtract::NOperationResult::kOK;
+ }
+
+ HRESULT ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, unsigned level);
+};
+
+HRESULT CHandler::ReadTables(IInStream *stream, UInt32 baseLba, UInt32 lba, unsigned level)
+{
+ if (level >= 128 || _items.Size() >= 128)
+ return S_FALSE;
+
+ const unsigned kNumHeaderParts = 4;
+ CPartition parts[kNumHeaderParts];
+
+ {
+ const UInt32 kSectorSize = 512;
+ _buffer.Alloc(kSectorSize);
+ Byte *buf = _buffer;
+ UInt64 newPos = (UInt64)lba << 9;
+ if (newPos + 512 > _totalSize)
+ return S_FALSE;
+ RINOK(InStream_SeekSet(stream, newPos))
+ RINOK(ReadStream_FALSE(stream, buf, kSectorSize))
+
+ if (buf[0x1FE] != 0x55 || buf[0x1FF] != 0xAA)
+ return S_FALSE;
+
+ for (unsigned i = 0; i < kNumHeaderParts; i++)
+ if (!parts[i].Parse(buf + 0x1BE + 16 * i))
+ return S_FALSE;
+ }
+
+ PRF(printf("\n# %8X", lba));
+
+ UInt32 limLba = lba + 1;
+ if (limLba == 0)
+ return S_FALSE;
+
+ for (unsigned i = 0; i < kNumHeaderParts; i++)
+ {
+ CPartition &part = parts[i];
+
+ if (part.IsEmpty())
+ continue;
+ PRF(printf("\n %2d ", (unsigned)level));
+ #ifdef SHOW_DEBUG_INFO
+ part.Print();
+ #endif
+
+ unsigned numItems = _items.Size();
+ UInt32 newLba = lba + part.Lba;
+
+ if (part.IsExtended())
+ {
+ // if (part.Type == 5) // Check it!
+ newLba = baseLba + part.Lba;
+ if (newLba < limLba)
+ return S_FALSE;
+ HRESULT res = ReadTables(stream, level < 1 ? newLba : baseLba, newLba, level + 1);
+ if (res != S_FALSE && res != S_OK)
+ return res;
+ }
+ if (newLba < limLba)
+ return S_FALSE;
+ part.Lba = newLba;
+ if (!part.CheckLbaLimits())
+ return S_FALSE;
+
+ CItem n;
+ n.Part = part;
+ bool addItem = false;
+ if (numItems == _items.Size())
+ {
+ n.IsPrim = (level == 0);
+ n.IsReal = true;
+ addItem = true;
+ }
+ else
+ {
+ const CItem &back = _items.Back();
+ UInt32 backLimit = back.Part.GetLimit();
+ UInt32 partLimit = part.GetLimit();
+ if (backLimit < partLimit)
+ {
+ n.IsReal = false;
+ n.Part.Lba = backLimit;
+ n.Part.NumBlocks = partLimit - backLimit;
+ addItem = true;
+ }
+ }
+ if (addItem)
+ {
+ if (n.Part.GetLimit() < limLba)
+ return S_FALSE;
+ limLba = n.Part.GetLimit();
+ n.Size = n.Part.GetSize();
+ _items.Add(n);
+ }
+ }
+ return S_OK;
+}
+
+
+static bool Is_Ntfs(const Byte *p)
+{
+ if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA)
+ return false;
+ // int codeOffset = 0;
+ switch (p[0])
+ {
+ case 0xE9: /* codeOffset = 3 + (Int16)Get16(p + 1); */ break;
+ case 0xEB: if (p[2] != 0x90) return false; /* codeOffset = 2 + (int)(signed char)p[1]; */ break;
+ default: return false;
+ }
+ return memcmp(p + 3, "NTFS ", 8) == 0;
+}
+
+static bool Is_ExFat(const Byte *p)
+{
+ if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA)
+ return false;
+ if (p[0] != 0xEB || p[1] != 0x76 || p[2] != 0x90)
+ return false;
+ return memcmp(p + 3, "EXFAT ", 8) == 0;
+}
+
+static bool AllAreZeros(const Byte *p, size_t size)
+{
+ for (size_t i = 0; i < size; i++)
+ if (p[i] != 0)
+ return false;
+ return true;
+}
+
+static const UInt32 k_Udf_StartPos = 0x8000;
+static const Byte k_Udf_Signature[] = { 0, 'B', 'E', 'A', '0', '1', 1, 0 };
+
+static bool Is_Udf(const Byte *p)
+{
+ return memcmp(p + k_Udf_StartPos, k_Udf_Signature, sizeof(k_Udf_Signature)) == 0;
+}
+
+
+static const char *GetFileSystem(
+ ISequentialInStream *stream, UInt64 partitionSize)
+{
+ const size_t kHeaderSize = 1 << 9;
+ if (partitionSize >= kHeaderSize)
+ {
+ Byte buf[kHeaderSize];
+ if (ReadStream_FAIL(stream, buf, kHeaderSize) == S_OK)
+ {
+ // NTFS is expected default filesystem for (Type == 7)
+ if (Is_Ntfs(buf))
+ return "NTFS";
+ if (Is_ExFat(buf))
+ return "exFAT";
+ const size_t kHeaderSize2 = k_Udf_StartPos + (1 << 9);
+ if (partitionSize >= kHeaderSize2)
+ {
+ if (AllAreZeros(buf, kHeaderSize))
+ {
+ CByteBuffer buffer(kHeaderSize2);
+ // memcpy(buffer, buf, kHeaderSize);
+ if (ReadStream_FAIL(stream, buffer + kHeaderSize, kHeaderSize2 - kHeaderSize) == S_OK)
+ if (Is_Udf(buffer))
+ return "UDF";
+ }
+ }
+ }
+ }
+ return NULL;
+}
+
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */))
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(InStream_GetSize_SeekToEnd(stream, _totalSize))
+ RINOK(ReadTables(stream, 0, 0, 0))
+ if (_items.IsEmpty())
+ return S_FALSE;
+ UInt32 lbaLimit = _items.Back().Part.GetLimit();
+ UInt64 lim = (UInt64)lbaLimit << 9;
+ if (lim < _totalSize)
+ {
+ CItem n;
+ n.Part.Lba = lbaLimit;
+ n.Size = _totalSize - lim;
+ n.IsReal = false;
+ _items.Add(n);
+ }
+
+ FOR_VECTOR (i, _items)
+ {
+ CItem &item = _items[i];
+ if (item.Part.Type != kType_Windows_NTFS)
+ continue;
+ if (InStream_SeekSet(stream, item.Part.GetPos()) != S_OK)
+ continue;
+ item.FileSystem = GetFileSystem(stream, item.Size);
+ item.WasParsed = true;
+ }
+
+ _stream = stream;
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _totalSize = 0;
+ _items.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+
+enum
+{
+ kpidPrimary = kpidUserDefined,
+ kpidBegChs,
+ kpidEndChs
+};
+
+static const CStatProp kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidFileSystem, VT_BSTR},
+ { NULL, kpidOffset, VT_UI8},
+ { "Primary", kpidPrimary, VT_BOOL},
+ { "Begin CHS", kpidBegChs, VT_BSTR},
+ { "End CHS", kpidEndChs, VT_BSTR}
+};
+
+IMP_IInArchive_Props_WITH_NAME
+IMP_IInArchive_ArcProps_NO_Table
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidMainSubfile:
+ {
+ int mainIndex = -1;
+ FOR_VECTOR (i, _items)
+ if (_items[i].IsReal)
+ {
+ if (mainIndex >= 0)
+ {
+ mainIndex = -1;
+ break;
+ }
+ mainIndex = (int)i;
+ }
+ if (mainIndex >= 0)
+ prop = (UInt32)(Int32)mainIndex;
+ break;
+ }
+ case kpidPhySize: prop = _totalSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ const CItem &item = _items[index];
+ const CPartition &part = item.Part;
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ AString s;
+ s.Add_UInt32(index);
+ if (item.IsReal)
+ {
+ s.Add_Dot();
+ const char *ext = NULL;
+ if (item.FileSystem)
+ {
+ ext = "";
+ AString fs (item.FileSystem);
+ fs.MakeLower_Ascii();
+ s += fs;
+ }
+ else if (!item.WasParsed)
+ {
+ const int typeIndex = FindPartType(part.Type);
+ if (typeIndex >= 0)
+ ext = kPartTypes[(unsigned)typeIndex].Ext;
+ }
+ if (!ext)
+ ext = "img";
+ s += ext;
+ }
+ prop = s;
+ break;
+ }
+ case kpidFileSystem:
+ if (item.IsReal)
+ {
+ char s[32];
+ ConvertUInt32ToString(part.Type, s);
+ const char *res = s;
+ if (item.FileSystem)
+ {
+ // strcat(s, "-");
+ // strcpy(s, item.FileSystem);
+ res = item.FileSystem;
+ }
+ else if (!item.WasParsed)
+ {
+ const int typeIndex = FindPartType(part.Type);
+ if (typeIndex >= 0 && kPartTypes[(unsigned)typeIndex].Name)
+ res = kPartTypes[(unsigned)typeIndex].Name;
+ }
+ prop = res;
+ }
+ break;
+ case kpidSize:
+ case kpidPackSize: prop = item.Size; break;
+ case kpidOffset: prop = part.GetPos(); break;
+ case kpidPrimary: if (item.IsReal) prop = item.IsPrim; break;
+ case kpidBegChs: if (item.IsReal) part.BeginChs.ToString(prop); break;
+ case kpidEndChs: if (item.IsReal) part.EndChs.ToString(prop); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+ // 3, { 1, 1, 0 },
+ // 2, { 0x55, 0x1FF },
+
+REGISTER_ARC_I_NO_SIG(
+ "MBR", "mbr", NULL, 0xDB,
+ 0,
+ NArcInfoFlags::kPureStartOpen,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/MslzHandler.cpp b/CPP/7zip/Archive/MslzHandler.cpp
new file mode 100644
index 0000000..04549f8
--- /dev/null
+++ b/CPP/7zip/Archive/MslzHandler.cpp
@@ -0,0 +1,390 @@
+// MslzHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/MyString.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "Common/DummyOutStream.h"
+
+namespace NArchive {
+namespace NMslz {
+
+static const UInt32 kUnpackSizeMax = 0xFFFFFFE0;
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IArchiveOpenSeq
+)
+ CMyComPtr<IInStream> _inStream;
+ CMyComPtr<ISequentialInStream> _seqStream;
+
+ bool _isArc;
+ bool _needSeekToStart;
+ bool _dataAfterEnd;
+ bool _needMoreInput;
+
+ bool _packSize_Defined;
+ bool _unpackSize_Defined;
+
+ UInt32 _unpackSize;
+ UInt64 _packSize;
+ UInt64 _originalFileSize;
+ UString _name;
+
+ void ParseName(Byte replaceByte, IArchiveOpenCallback *callback);
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidExtension: prop = "mslz"; break;
+ case kpidIsNotArcType: prop = true; break;
+ case kpidPhySize: if (_packSize_Defined) prop = _packSize; break;
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (_needMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
+ if (_dataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
+ prop = v;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPath: if (!_name.IsEmpty()) prop = _name; break;
+ case kpidSize: if (_unpackSize_Defined || _inStream) prop = _unpackSize; break;
+ case kpidPackSize: if (_packSize_Defined || _inStream) prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+static const unsigned kSignatureSize = 9;
+static const unsigned kHeaderSize = kSignatureSize + 1 + 4;
+#define MSLZ_SIGNATURE { 0x53, 0x5A, 0x44, 0x44, 0x88, 0xF0, 0x27, 0x33, 0x41 }
+// old signature: 53 5A 20 88 F0 27 33
+static const Byte kSignature[kSignatureSize] = MSLZ_SIGNATURE;
+
+// we support only 3 chars strings here
+static const char * const g_Exts[] =
+{
+ "bin"
+ , "dll"
+ , "exe"
+ , "kmd"
+ , "pdf"
+ , "sys"
+};
+
+void CHandler::ParseName(Byte replaceByte, IArchiveOpenCallback *callback)
+{
+ if (!callback)
+ return;
+ Z7_DECL_CMyComPtr_QI_FROM(IArchiveOpenVolumeCallback, volumeCallback, callback)
+ if (!volumeCallback)
+ return;
+
+ NWindows::NCOM::CPropVariant prop;
+ if (volumeCallback->GetProperty(kpidName, &prop) != S_OK || prop.vt != VT_BSTR)
+ return;
+
+ UString s = prop.bstrVal;
+ if (s.IsEmpty() ||
+ s.Back() != L'_')
+ return;
+
+ s.DeleteBack();
+ _name = s;
+
+ if (replaceByte == 0)
+ {
+ if (s.Len() < 3 || s[s.Len() - 3] != '.')
+ return;
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Exts); i++)
+ {
+ const char *ext = g_Exts[i];
+ if (s[s.Len() - 2] == (Byte)ext[0] &&
+ s[s.Len() - 1] == (Byte)ext[1])
+ {
+ replaceByte = (Byte)ext[2];
+ break;
+ }
+ }
+ }
+
+ if (replaceByte >= 0x20 && replaceByte < 0x80)
+ _name += (char)replaceByte;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ _needSeekToStart = true;
+ Byte buffer[kHeaderSize];
+ RINOK(ReadStream_FALSE(stream, buffer, kHeaderSize))
+ if (memcmp(buffer, kSignature, kSignatureSize) != 0)
+ return S_FALSE;
+ _unpackSize = GetUi32(buffer + 10);
+ if (_unpackSize > kUnpackSizeMax)
+ return S_FALSE;
+ RINOK(InStream_GetSize_SeekToEnd(stream, _originalFileSize))
+ _packSize = _originalFileSize;
+
+ ParseName(buffer[kSignatureSize], callback);
+
+ _isArc = true;
+ _unpackSize_Defined = true;
+ _inStream = stream;
+ _seqStream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _originalFileSize = 0;
+ _packSize = 0;
+ _unpackSize = 0;
+
+ _isArc = false;
+ _needSeekToStart = false;
+ _dataAfterEnd = false;
+ _needMoreInput = false;
+
+ _packSize_Defined = false;
+ _unpackSize_Defined = false;
+
+ _seqStream.Release();
+ _inStream.Release();
+ _name.Empty();
+ return S_OK;
+}
+
+// MslzDec is modified LZSS algorithm of Haruhiko Okumura:
+// maxLen = 18; Okumura
+// maxLen = 16; MS
+
+#define PROGRESS_AND_WRITE \
+ if ((dest & kMask) == 0) { if (outStream) RINOK(WriteStream(outStream, buf, kBufSize)); \
+ if ((dest & ((1 << 20) - 1)) == 0) \
+ if (progress) \
+ { UInt64 inSize = inStream.GetProcessedSize(); UInt64 outSize = dest; \
+ RINOK(progress->SetRatioInfo(&inSize, &outSize)); }}
+
+static HRESULT MslzDec(CInBuffer &inStream, ISequentialOutStream *outStream, UInt32 unpackSize, bool &needMoreData, ICompressProgressInfo *progress)
+{
+ const unsigned kBufSize = (1 << 12);
+ const unsigned kMask = kBufSize - 1;
+ Byte buf[kBufSize];
+ UInt32 dest = 0;
+ memset(buf, ' ', kBufSize);
+
+ while (dest < unpackSize)
+ {
+ Byte b;
+ if (!inStream.ReadByte(b))
+ {
+ needMoreData = true;
+ return S_FALSE;
+ }
+
+ for (unsigned mask = (unsigned)b | 0x100; mask > 1 && dest < unpackSize; mask >>= 1)
+ {
+ if (!inStream.ReadByte(b))
+ {
+ needMoreData = true;
+ return S_FALSE;
+ }
+
+ if (mask & 1)
+ {
+ buf[dest++ & kMask] = b;
+ PROGRESS_AND_WRITE
+ }
+ else
+ {
+ Byte b1;
+ if (!inStream.ReadByte(b1))
+ {
+ needMoreData = true;
+ return S_FALSE;
+ }
+ const unsigned kMaxLen = 16; // 18 in Okumura's code.
+ unsigned src = (((((unsigned)b1 & 0xF0) << 4) | b) + kMaxLen) & kMask;
+ unsigned len = (b1 & 0xF) + 3;
+ if (len > kMaxLen || dest + len > unpackSize)
+ return S_FALSE;
+
+ do
+ {
+ buf[dest++ & kMask] = buf[src++ & kMask];
+ PROGRESS_AND_WRITE
+ }
+ while (--len != 0);
+ }
+ }
+ }
+
+ if (outStream)
+ RINOK(WriteStream(outStream, buf, dest & kMask))
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream))
+{
+ COM_TRY_BEGIN
+ Close();
+ _isArc = true;
+ _seqStream = stream;
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ // extractCallback->SetTotal(_unpackSize);
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode))
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ if (_needSeekToStart)
+ {
+ if (!_inStream)
+ return E_FAIL;
+ RINOK(InStream_SeekToBegin(_inStream))
+ }
+ else
+ _needSeekToStart = true;
+
+ Int32 opRes = NExtract::NOperationResult::kDataError;
+
+ bool isArc = false;
+ bool needMoreInput = false;
+ try
+ {
+ CInBuffer s;
+ if (!s.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ s.SetStream(_seqStream);
+ s.Init();
+
+ Byte buffer[kHeaderSize];
+ if (s.ReadBytes(buffer, kHeaderSize) == kHeaderSize)
+ {
+ UInt32 unpackSize;
+ if (memcmp(buffer, kSignature, kSignatureSize) == 0)
+ {
+ unpackSize = GetUi32(buffer + 10);
+ if (unpackSize <= kUnpackSizeMax)
+ {
+ HRESULT result = MslzDec(s, outStream, unpackSize, needMoreInput, progress);
+ if (result == S_OK)
+ opRes = NExtract::NOperationResult::kOK;
+ else if (result != S_FALSE)
+ return result;
+ _unpackSize = unpackSize;
+ _unpackSize_Defined = true;
+
+ _packSize = s.GetProcessedSize();
+ _packSize_Defined = true;
+
+ if (_inStream && _packSize < _originalFileSize)
+ _dataAfterEnd = true;
+
+ isArc = true;
+ }
+ }
+ }
+ }
+ catch (CInBufferException &e) { return e.ErrorCode; }
+
+ _isArc = isArc;
+ if (isArc)
+ _needMoreInput = needMoreInput;
+ if (!_isArc)
+ opRes = NExtract::NOperationResult::kIsNotArc;
+ else if (_needMoreInput)
+ opRes = NExtract::NOperationResult::kUnexpectedEnd;
+ else if (_dataAfterEnd)
+ opRes = NExtract::NOperationResult::kDataAfterEnd;
+
+ outStream.Release();
+ return extractCallback->SetOperationResult(opRes);
+ COM_TRY_END
+}
+
+REGISTER_ARC_I(
+ "MsLZ", "mslz", NULL, 0xD5,
+ kSignature,
+ 0,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/MubHandler.cpp b/CPP/7zip/Archive/MubHandler.cpp
new file mode 100644
index 0000000..7363b1b
--- /dev/null
+++ b/CPP/7zip/Archive/MubHandler.cpp
@@ -0,0 +1,262 @@
+// MubHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+#include "../../../C/SwapBytes.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyString.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "HandlerCont.h"
+
+using namespace NWindows;
+using namespace NCOM;
+
+namespace NArchive {
+namespace NMub {
+
+#define MACH_CPU_ARCH_ABI64 ((UInt32)1 << 24)
+#define MACH_CPU_TYPE_386 7
+#define MACH_CPU_TYPE_ARM 12
+#define MACH_CPU_TYPE_SPARC 14
+#define MACH_CPU_TYPE_PPC 18
+
+#define MACH_CPU_TYPE_PPC64 (MACH_CPU_ARCH_ABI64 | MACH_CPU_TYPE_PPC)
+#define MACH_CPU_TYPE_AMD64 (MACH_CPU_ARCH_ABI64 | MACH_CPU_TYPE_386)
+#define MACH_CPU_TYPE_ARM64 (MACH_CPU_ARCH_ABI64 | MACH_CPU_TYPE_ARM)
+
+#define MACH_CPU_SUBTYPE_LIB64 ((UInt32)1 << 31)
+
+#define MACH_CPU_SUBTYPE_I386_ALL 3
+
+struct CItem
+{
+ UInt32 Type;
+ UInt32 SubType;
+ UInt32 Offset;
+ UInt32 Size;
+ UInt32 Align;
+};
+
+static const UInt32 kNumFilesMax = 6;
+
+Z7_class_CHandler_final: public CHandlerCont
+{
+ Z7_IFACE_COM7_IMP(IInArchive_Cont)
+
+ // UInt64 _startPos;
+ UInt64 _phySize;
+ UInt32 _numItems;
+ bool _bigEndian;
+ CItem _items[kNumFilesMax];
+
+ HRESULT Open2(IInStream *stream);
+
+ virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override
+ {
+ const CItem &item = _items[index];
+ pos = item.Offset;
+ size = item.Size;
+ return NExtract::NOperationResult::kOK;
+ }
+};
+
+static const Byte kArcProps[] =
+{
+ kpidBigEndian
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidOffset,
+ kpidClusterSize // Align
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ PropVariant_Clear(value);
+ switch (propID)
+ {
+ case kpidBigEndian: PropVarEm_Set_Bool(value, _bigEndian); break;
+ case kpidPhySize: PropVarEm_Set_UInt64(value, _phySize); break;
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ PropVariant_Clear(value);
+ const CItem &item = _items[index];
+ switch (propID)
+ {
+ case kpidExtension:
+ {
+ char temp[32];
+ const char *ext = NULL;
+ switch (item.Type)
+ {
+ case MACH_CPU_TYPE_386: ext = "x86"; break;
+ case MACH_CPU_TYPE_ARM: ext = "arm"; break;
+ case MACH_CPU_TYPE_SPARC: ext = "sparc"; break;
+ case MACH_CPU_TYPE_PPC: ext = "ppc"; break;
+ case MACH_CPU_TYPE_AMD64: ext = "x64"; break;
+ case MACH_CPU_TYPE_ARM64: ext = "arm64"; break;
+ case MACH_CPU_TYPE_PPC64: ext = "ppc64"; break;
+ default:
+ temp[0] = 'c';
+ temp[1] = 'p';
+ temp[2] = 'u';
+ char *p = ConvertUInt32ToString(item.Type & ~MACH_CPU_ARCH_ABI64, temp + 3);
+ if (item.Type & MACH_CPU_ARCH_ABI64)
+ MyStringCopy(p, "_64");
+ break;
+ }
+ if (ext)
+ MyStringCopy(temp, ext);
+ if (item.SubType != 0)
+ if ((item.Type != MACH_CPU_TYPE_386 &&
+ item.Type != MACH_CPU_TYPE_AMD64)
+ || (item.SubType & ~(UInt32)MACH_CPU_SUBTYPE_LIB64) != MACH_CPU_SUBTYPE_I386_ALL
+ )
+ {
+ unsigned pos = MyStringLen(temp);
+ temp[pos++] = '-';
+ ConvertUInt32ToString(item.SubType, temp + pos);
+ }
+ return PropVarEm_Set_Str(value, temp);
+ }
+ case kpidSize:
+ case kpidPackSize:
+ PropVarEm_Set_UInt64(value, item.Size);
+ break;
+ case kpidOffset:
+ PropVarEm_Set_UInt64(value, item.Offset);
+ break;
+ case kpidClusterSize:
+ PropVarEm_Set_UInt32(value, (UInt32)1 << item.Align);
+ break;
+ }
+ return S_OK;
+}
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+ // RINOK(InStream_GetPos(stream, _startPos));
+
+ const UInt32 kHeaderSize = 2;
+ const UInt32 kRecordSize = 5;
+ const UInt32 kBufSize = kHeaderSize + kNumFilesMax * kRecordSize;
+ UInt32 buf[kBufSize];
+ size_t processed = kBufSize * 4;
+ RINOK(ReadStream(stream, buf, &processed))
+ processed >>= 2;
+ if (processed < kHeaderSize)
+ return S_FALSE;
+
+ bool be;
+ switch (buf[0])
+ {
+ case Z7_CONV_BE_TO_NATIVE_CONST32(0xCAFEBABE): be = true; break;
+ case Z7_CONV_BE_TO_NATIVE_CONST32(0xB9FAF10E): be = false; break;
+ default: return S_FALSE;
+ }
+ _bigEndian = be;
+ if (
+ #if defined(MY_CPU_BE)
+ !
+ #endif
+ be)
+ z7_SwapBytes4(&buf[1], processed - 1);
+ const UInt32 num = buf[1];
+ if (num > kNumFilesMax || processed < kHeaderSize + num * kRecordSize)
+ return S_FALSE;
+ if (num == 0)
+ return S_FALSE;
+ UInt64 endPosMax = kHeaderSize;
+
+ for (UInt32 i = 0; i < num; i++)
+ {
+ const UInt32 *p = buf + kHeaderSize + i * kRecordSize;
+ CItem &sb = _items[i];
+ sb.Type = p[0];
+ sb.SubType = p[1];
+ sb.Offset = p[2];
+ sb.Size = p[3];
+ const UInt32 align = p[4];
+ sb.Align = align;
+ if (align > 31)
+ return S_FALSE;
+ if (sb.Offset < kHeaderSize + num * kRecordSize)
+ return S_FALSE;
+ if ((sb.Type & ~MACH_CPU_ARCH_ABI64) >= 0x100 ||
+ (sb.SubType & ~MACH_CPU_SUBTYPE_LIB64) >= 0x100)
+ return S_FALSE;
+
+ const UInt64 endPos = (UInt64)sb.Offset + sb.Size;
+ if (endPosMax < endPos)
+ endPosMax = endPos;
+ }
+ _numItems = num;
+ _phySize = endPosMax;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */))
+{
+ COM_TRY_BEGIN
+ Close();
+ try
+ {
+ if (Open2(inStream) != S_OK)
+ return S_FALSE;
+ _stream = inStream;
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _stream.Release();
+ _numItems = 0;
+ _phySize = 0;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _numItems;
+ return S_OK;
+}
+
+namespace NBe {
+
+static const Byte k_Signature[] = {
+ 7, 0xCA, 0xFE, 0xBA, 0xBE, 0, 0, 0,
+ 4, 0xB9, 0xFA, 0xF1, 0x0E };
+
+REGISTER_ARC_I(
+ "Mub", "mub", NULL, 0xE2,
+ k_Signature,
+ 0,
+ NArcInfoFlags::kMultiSignature,
+ NULL)
+
+}
+
+}}
diff --git a/CPP/7zip/Archive/Nsis/NsisDecode.cpp b/CPP/7zip/Archive/Nsis/NsisDecode.cpp
new file mode 100644
index 0000000..044de37
--- /dev/null
+++ b/CPP/7zip/Archive/Nsis/NsisDecode.cpp
@@ -0,0 +1,295 @@
+// NsisDecode.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "NsisDecode.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/MethodId.h"
+
+#include "../../Compress/BcjCoder.h"
+
+#define Get32(p) GetUi32(p)
+
+namespace NArchive {
+namespace NNsis {
+
+UInt64 CDecoder::GetInputProcessedSize() const
+{
+ if (_lzmaDecoder)
+ return _lzmaDecoder->GetInputProcessedSize();
+ if (_deflateDecoder)
+ return _deflateDecoder->GetInputProcessedSize();
+ if (_bzDecoder)
+ return _bzDecoder->GetInputProcessedSize();
+ return 0;
+}
+
+
+HRESULT CDecoder::Init(ISequentialInStream *inStream, bool &useFilter)
+{
+ useFilter = false;
+
+ if (_decoderInStream)
+ if (Method != _curMethod)
+ Release();
+ _curMethod = Method;
+
+ if (!_codecInStream)
+ {
+ switch ((int)Method)
+ {
+ // case NMethodType::kCopy: return E_NOTIMPL;
+ case NMethodType::kDeflate:
+ _deflateDecoder = new NCompress::NDeflate::NDecoder::CCOMCoder();
+ _codecInStream = _deflateDecoder;
+ break;
+ case NMethodType::kBZip2:
+ _bzDecoder = new NCompress::NBZip2::CNsisDecoder();
+ _codecInStream = _bzDecoder;
+ break;
+ case NMethodType::kLZMA:
+ _lzmaDecoder = new NCompress::NLzma::CDecoder();
+ _codecInStream = _lzmaDecoder;
+ break;
+ default: return E_NOTIMPL;
+ }
+ }
+
+ if (Method == NMethodType::kDeflate)
+ _deflateDecoder->SetNsisMode(IsNsisDeflate);
+
+ if (FilterFlag)
+ {
+ Byte flag;
+ RINOK(ReadStream_FALSE(inStream, &flag, 1))
+ if (flag > 1)
+ return E_NOTIMPL;
+ useFilter = (flag != 0);
+ }
+
+ if (!useFilter)
+ _decoderInStream = _codecInStream;
+ else
+ {
+ if (!_filterInStream)
+ {
+ _filter = new CFilterCoder(false);
+ _filterInStream = _filter;
+ _filter->Filter = new NCompress::NBcj::CCoder2(z7_BranchConvSt_X86_Dec);
+ }
+ RINOK(_filter->SetInStream(_codecInStream))
+ _decoderInStream = _filterInStream;
+ }
+
+ if (Method == NMethodType::kLZMA)
+ {
+ const unsigned kPropsSize = LZMA_PROPS_SIZE;
+ Byte props[kPropsSize];
+ RINOK(ReadStream_FALSE(inStream, props, kPropsSize))
+ RINOK(_lzmaDecoder->SetDecoderProperties2((const Byte *)props, kPropsSize))
+ }
+
+ {
+ CMyComPtr<ICompressSetInStream> setInStream;
+ _codecInStream.QueryInterface(IID_ICompressSetInStream, &setInStream);
+ if (!setInStream)
+ return E_NOTIMPL;
+ RINOK(setInStream->SetInStream(inStream))
+ }
+
+ {
+ CMyComPtr<ICompressSetOutStreamSize> setOutStreamSize;
+ _codecInStream.QueryInterface(IID_ICompressSetOutStreamSize, &setOutStreamSize);
+ if (!setOutStreamSize)
+ return E_NOTIMPL;
+ RINOK(setOutStreamSize->SetOutStreamSize(NULL))
+ }
+
+ if (useFilter)
+ {
+ RINOK(_filter->SetOutStreamSize(NULL))
+ }
+
+ return S_OK;
+}
+
+
+static const UInt32 kMask_IsCompressed = (UInt32)1 << 31;
+
+
+HRESULT CDecoder::SetToPos(UInt64 pos, ICompressProgressInfo *progress)
+{
+ if (StreamPos > pos)
+ return E_FAIL;
+ const UInt64 inSizeStart = GetInputProcessedSize();
+ UInt64 offset = 0;
+ while (StreamPos < pos)
+ {
+ size_t size = (size_t)MyMin(pos - StreamPos, (UInt64)Buffer.Size());
+ RINOK(Read(Buffer, &size))
+ if (size == 0)
+ return S_FALSE;
+ StreamPos += size;
+ offset += size;
+
+ const UInt64 inSize = GetInputProcessedSize() - inSizeStart;
+ RINOK(progress->SetRatioInfo(&inSize, &offset))
+ }
+ return S_OK;
+}
+
+
+HRESULT CDecoder::Decode(CByteBuffer *outBuf, bool unpackSizeDefined, UInt32 unpackSize,
+ ISequentialOutStream *realOutStream, ICompressProgressInfo *progress,
+ UInt32 &packSizeRes, UInt32 &unpackSizeRes)
+{
+ CLimitedSequentialInStream *limitedStreamSpec = NULL;
+ CMyComPtr<ISequentialInStream> limitedStream;
+ packSizeRes = 0;
+ unpackSizeRes = 0;
+
+ if (Solid)
+ {
+ Byte temp[4];
+ size_t processedSize = 4;
+ RINOK(Read(temp, &processedSize))
+ StreamPos += processedSize;
+ if (processedSize != 4)
+ return S_FALSE;
+ UInt32 size = Get32(temp);
+ if (unpackSizeDefined && size != unpackSize)
+ return S_FALSE;
+ unpackSize = size;
+ unpackSizeDefined = true;
+ }
+ else
+ {
+ Byte temp[4];
+ {
+ size_t processedSize = 4;
+ RINOK(ReadStream(InputStream, temp, &processedSize))
+ StreamPos += processedSize;
+ if (processedSize != 4)
+ return S_FALSE;
+ }
+ UInt32 size = Get32(temp);
+
+ if ((size & kMask_IsCompressed) == 0)
+ {
+ if (unpackSizeDefined && size != unpackSize)
+ return S_FALSE;
+ packSizeRes = size;
+ if (outBuf)
+ outBuf->Alloc(size);
+
+ UInt64 offset = 0;
+
+ while (size > 0)
+ {
+ UInt32 curSize = (UInt32)MyMin((size_t)size, Buffer.Size());
+ UInt32 processedSize;
+ RINOK(InputStream->Read(Buffer, curSize, &processedSize))
+ if (processedSize == 0)
+ return S_FALSE;
+ if (outBuf)
+ memcpy((Byte *)*outBuf + (size_t)offset, Buffer, processedSize);
+ offset += processedSize;
+ size -= processedSize;
+ StreamPos += processedSize;
+ unpackSizeRes += processedSize;
+ if (realOutStream)
+ RINOK(WriteStream(realOutStream, Buffer, processedSize))
+ RINOK(progress->SetRatioInfo(&offset, &offset))
+ }
+
+ return S_OK;
+ }
+
+ size &= ~kMask_IsCompressed;
+ packSizeRes = size;
+ limitedStreamSpec = new CLimitedSequentialInStream;
+ limitedStream = limitedStreamSpec;
+ limitedStreamSpec->SetStream(InputStream);
+ limitedStreamSpec->Init(size);
+ {
+ bool useFilter;
+ RINOK(Init(limitedStream, useFilter))
+ }
+ }
+
+ if (outBuf)
+ {
+ if (unpackSizeDefined)
+ outBuf->Alloc(unpackSize);
+ }
+
+ const UInt64 inSizeStart = GetInputProcessedSize();
+
+ // we don't allow files larger than 4 GB;
+ if (!unpackSizeDefined)
+ unpackSize = 0xFFFFFFFF;
+ UInt32 offset = 0;
+
+ HRESULT res = S_OK;
+
+ for (;;)
+ {
+ size_t rem = unpackSize - offset;
+ if (rem == 0)
+ break;
+ size_t size = Buffer.Size();
+ if (size > rem)
+ size = rem;
+ RINOK(Read(Buffer, &size))
+ if (size == 0)
+ {
+ if (unpackSizeDefined)
+ res = S_FALSE;
+ break;
+ }
+
+ if (outBuf)
+ {
+ size_t nextSize = offset + size;
+ if (outBuf->Size() < nextSize)
+ {
+ {
+ const size_t nextSize2 = outBuf->Size() * 2;
+ if (nextSize < nextSize2)
+ nextSize = nextSize2;
+ }
+ outBuf->ChangeSize_KeepData(nextSize, offset);
+ }
+ memcpy((Byte *)*outBuf + (size_t)offset, Buffer, size);
+ }
+
+ StreamPos += size;
+ offset += (UInt32)size;
+
+ const UInt64 inSize = GetInputProcessedSize() - inSizeStart;
+
+ if (Solid)
+ packSizeRes = (UInt32)inSize;
+ unpackSizeRes += (UInt32)size;
+
+ UInt64 outSize = offset;
+ RINOK(progress->SetRatioInfo(&inSize, &outSize))
+ if (realOutStream)
+ {
+ res = WriteStream(realOutStream, Buffer, size);
+ if (res != S_OK)
+ break;
+ }
+ }
+
+ if (outBuf && offset != outBuf->Size())
+ outBuf->ChangeSize_KeepData(offset, offset);
+
+ return res;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Nsis/NsisDecode.h b/CPP/7zip/Archive/Nsis/NsisDecode.h
new file mode 100644
index 0000000..1d08d01
--- /dev/null
+++ b/CPP/7zip/Archive/Nsis/NsisDecode.h
@@ -0,0 +1,97 @@
+// NsisDecode.h
+
+#ifndef ZIP7_INC_NSIS_DECODE_H
+#define ZIP7_INC_NSIS_DECODE_H
+
+#include "../../../Common/MyBuffer.h"
+
+#include "../../Common/FilterCoder.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/BZip2Decoder.h"
+#include "../../Compress/DeflateDecoder.h"
+#include "../../Compress/LzmaDecoder.h"
+
+namespace NArchive {
+namespace NNsis {
+
+namespace NMethodType
+{
+ enum EEnum
+ {
+ kCopy,
+ kDeflate,
+ kBZip2,
+ kLZMA
+ };
+}
+
+/* 7-Zip installers 4.38 - 9.08 used modified version of NSIS that
+ supported BCJ filter for better compression ratio.
+ We support such modified NSIS archives. */
+
+class CDecoder
+{
+ NMethodType::EEnum _curMethod; // method of created decoder
+
+ CFilterCoder *_filter;
+ CMyComPtr<ISequentialInStream> _filterInStream;
+ CMyComPtr<ISequentialInStream> _codecInStream;
+ CMyComPtr<ISequentialInStream> _decoderInStream;
+
+ NCompress::NBZip2::CNsisDecoder *_bzDecoder;
+ NCompress::NDeflate::NDecoder::CCOMCoder *_deflateDecoder;
+ NCompress::NLzma::CDecoder *_lzmaDecoder;
+
+public:
+ CMyComPtr<IInStream> InputStream; // for non-solid
+ UInt64 StreamPos; // the pos in unpacked for solid, the pos in Packed for non-solid
+
+ NMethodType::EEnum Method;
+ bool FilterFlag;
+ bool Solid;
+ bool IsNsisDeflate;
+
+ CByteBuffer Buffer; // temp buf
+
+ CDecoder():
+ FilterFlag(false),
+ Solid(true),
+ IsNsisDeflate(true)
+ {
+ _bzDecoder = NULL;
+ _deflateDecoder = NULL;
+ _lzmaDecoder = NULL;
+ }
+
+ void Release()
+ {
+ _filterInStream.Release();
+ _codecInStream.Release();
+ _decoderInStream.Release();
+ InputStream.Release();
+
+ _bzDecoder = NULL;
+ _deflateDecoder = NULL;
+ _lzmaDecoder = NULL;
+ }
+
+ UInt64 GetInputProcessedSize() const;
+
+ HRESULT Init(ISequentialInStream *inStream, bool &useFilter);
+
+ HRESULT Read(void *data, size_t *processedSize)
+ {
+ return ReadStream(_decoderInStream, data, processedSize);
+ }
+
+
+ HRESULT SetToPos(UInt64 pos, ICompressProgressInfo *progress); // for solid
+ HRESULT Decode(CByteBuffer *outBuf, bool unpackSizeDefined, UInt32 unpackSize,
+ ISequentialOutStream *realOutStream, ICompressProgressInfo *progress,
+ UInt32 &packSizeRes, UInt32 &unpackSizeRes);
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Nsis/NsisHandler.cpp b/CPP/7zip/Archive/Nsis/NsisHandler.cpp
new file mode 100644
index 0000000..7a512b7
--- /dev/null
+++ b/CPP/7zip/Archive/Nsis/NsisHandler.cpp
@@ -0,0 +1,694 @@
+// NSisHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../Common/ItemNameUtils.h"
+
+#include "NsisHandler.h"
+
+#define Get32(p) GetUi32(p)
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NNsis {
+
+#define kBcjMethod "BCJ"
+#define kUnknownMethod "Unknown"
+
+static const char * const kMethods[] =
+{
+ "Copy"
+ , "Deflate"
+ , "BZip2"
+ , "LZMA"
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidAttrib,
+ kpidMethod,
+ kpidSolid,
+ kpidOffset
+};
+
+static const Byte kArcProps[] =
+{
+ kpidMethod,
+ kpidSolid,
+ kpidBit64,
+ kpidHeadersSize,
+ kpidEmbeddedStubSize,
+ kpidSubType
+ // kpidCodePage
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+
+static void AddDictProp(AString &s, UInt32 val)
+{
+ for (unsigned i = 0; i < 32; i++)
+ if (((UInt32)1 << i) == val)
+ {
+ s.Add_UInt32(i);
+ return;
+ }
+ char c = 'b';
+ if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; }
+ else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; }
+ s.Add_UInt32(val);
+ s += c;
+}
+
+static AString GetMethod(bool useFilter, NMethodType::EEnum method, UInt32 dict)
+{
+ AString s;
+ if (useFilter)
+ {
+ s += kBcjMethod;
+ s.Add_Space();
+ }
+ s += ((unsigned)method < Z7_ARRAY_SIZE(kMethods)) ? kMethods[(unsigned)method] : kUnknownMethod;
+ if (method == NMethodType::kLZMA)
+ {
+ s += ':';
+ AddDictProp(s, dict);
+ }
+ return s;
+}
+
+/*
+AString CHandler::GetMethod(NMethodType::EEnum method, bool useItemFilter, UInt32 dictionary) const
+{
+ AString s;
+ if (_archive.IsSolid && _archive.UseFilter || !_archive.IsSolid && useItemFilter)
+ {
+ s += kBcjMethod;
+ s.Add_Space();
+ }
+ s += (method < Z7_ARRAY_SIZE(kMethods)) ? kMethods[method] : kUnknownMethod;
+ if (method == NMethodType::kLZMA)
+ {
+ s += ':';
+ s += GetStringForSizeValue(_archive.IsSolid ? _archive.DictionarySize: dictionary);
+ }
+ return s;
+}
+*/
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ // case kpidCodePage: if (_archive.IsUnicode) prop = "UTF-16"; break;
+ case kpidSubType:
+ {
+ AString s (_archive.GetFormatDescription());
+ if (!_archive.IsInstaller)
+ {
+ s.Add_Space_if_NotEmpty();
+ s += "(Uninstall)";
+ }
+ if (!s.IsEmpty())
+ prop = s;
+ break;
+ }
+
+ case kpidBit64: if (_archive.Is64Bit) prop = true; break;
+ case kpidMethod: prop = _methodString; break;
+ case kpidSolid: prop = _archive.IsSolid; break;
+ case kpidOffset: prop = _archive.StartOffset; break;
+ case kpidPhySize: prop = (UInt64)((UInt64)_archive.ExeStub.Size() + _archive.FirstHeader.ArcSize); break;
+ case kpidEmbeddedStubSize: prop = (UInt64)_archive.ExeStub.Size(); break;
+ case kpidHeadersSize: prop = _archive.FirstHeader.HeaderSize; break;
+
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_archive.IsArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (_archive.IsTruncated()) v |= kpv_ErrorFlags_UnexpectedEnd;
+ prop = v;
+ break;
+ }
+
+ case kpidName:
+ {
+ AString s;
+
+ #ifdef NSIS_SCRIPT
+ if (!_archive.Name.IsEmpty())
+ s = _archive.Name;
+ if (!_archive.IsInstaller)
+ {
+ if (!s.IsEmpty())
+ s.Add_Dot();
+ s += "Uninstall";
+ }
+ #endif
+
+ if (s.IsEmpty())
+ s = _archive.IsInstaller ? "Install" : "Uninstall";
+ s += (_archive.ExeStub.Size() == 0) ? ".nsis" : ".exe";
+
+ prop = _archive.ConvertToUnicode(s);
+ break;
+ }
+
+ #ifdef NSIS_SCRIPT
+ case kpidShortComment:
+ {
+ if (!_archive.BrandingText.IsEmpty())
+ prop = _archive.ConvertToUnicode(_archive.BrandingText);
+ break;
+ }
+ #endif
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback * /* openArchiveCallback */))
+{
+ COM_TRY_BEGIN
+ Close();
+ {
+ if (_archive.Open(stream, maxCheckStartPosition) != S_OK)
+ return S_FALSE;
+ {
+ UInt32 dict = _archive.DictionarySize;
+ if (!_archive.IsSolid)
+ {
+ FOR_VECTOR (i, _archive.Items)
+ {
+ const CItem &item = _archive.Items[i];
+ if (item.DictionarySize > dict)
+ dict = item.DictionarySize;
+ }
+ }
+ _methodString = GetMethod(_archive.UseFilter, _archive.Method, dict);
+ }
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _archive.Clear();
+ _archive.Release();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _archive.Items.Size()
+ #ifdef NSIS_SCRIPT
+ + 1 + _archive.LicenseFiles.Size()
+ #endif
+ ;
+ return S_OK;
+}
+
+bool CHandler::GetUncompressedSize(unsigned index, UInt32 &size) const
+{
+ size = 0;
+ const CItem &item = _archive.Items[index];
+ if (item.Size_Defined)
+ size = item.Size;
+ else if (_archive.IsSolid && item.EstimatedSize_Defined)
+ size = item.EstimatedSize;
+ else if (!item.IsEmptyFile)
+ return false;
+ return true;
+}
+
+bool CHandler::GetCompressedSize(unsigned index, UInt32 &size) const
+{
+ size = 0;
+ const CItem &item = _archive.Items[index];
+ if (item.CompressedSize_Defined)
+ size = item.CompressedSize;
+ else
+ {
+ if (_archive.IsSolid)
+ {
+ if (index == 0)
+ size = _archive.FirstHeader.GetDataSize();
+ else
+ return false;
+ }
+ else
+ {
+ if (!item.IsCompressed)
+ size = item.Size;
+ else
+ return false;
+ }
+ }
+ return true;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ #ifdef NSIS_SCRIPT
+ if (index >= (UInt32)_archive.Items.Size())
+ {
+ if (index == (UInt32)_archive.Items.Size())
+ {
+ switch (propID)
+ {
+ case kpidPath: prop = "[NSIS].nsi"; break;
+ case kpidSize:
+ case kpidPackSize: prop = (UInt64)_archive.Script.Len(); break;
+ case kpidSolid: prop = false; break;
+ }
+ }
+ else
+ {
+ const CLicenseFile &lic = _archive.LicenseFiles[index - (_archive.Items.Size() + 1)];
+ switch (propID)
+ {
+ case kpidPath: prop = lic.Name; break;
+ case kpidSize:
+ case kpidPackSize: prop = (UInt64)lic.Size; break;
+ case kpidSolid: prop = false; break;
+ }
+ }
+ }
+ else
+ #endif
+ {
+ const CItem &item = _archive.Items[index];
+ switch (propID)
+ {
+ case kpidOffset: prop = item.Pos; break;
+ case kpidPath:
+ {
+ UString s = NItemName::WinPathToOsPath(_archive.GetReducedName(index));
+ if (!s.IsEmpty())
+ prop = (const wchar_t *)s;
+ break;
+ }
+ case kpidSize:
+ {
+ UInt32 size;
+ if (GetUncompressedSize(index, size))
+ prop = (UInt64)size;
+ break;
+ }
+ case kpidPackSize:
+ {
+ UInt32 size;
+ if (GetCompressedSize(index, size))
+ prop = (UInt64)size;
+ break;
+ }
+ case kpidMTime:
+ {
+ if (item.MTime.dwHighDateTime > 0x01000000 &&
+ item.MTime.dwHighDateTime < 0xFF000000)
+ prop = item.MTime;
+ break;
+ }
+ case kpidAttrib:
+ {
+ if (item.Attrib_Defined)
+ prop = item.Attrib;
+ break;
+ }
+
+ case kpidMethod:
+ if (_archive.IsSolid)
+ prop = _methodString;
+ else
+ prop = GetMethod(_archive.UseFilter, item.IsCompressed ? _archive.Method :
+ NMethodType::kCopy, item.DictionarySize);
+ break;
+
+ case kpidSolid: prop = _archive.IsSolid; break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+static bool UninstallerPatch(const Byte *p, size_t size, Byte *dest, size_t destSize)
+{
+ for (;;)
+ {
+ if (size < 4)
+ return false;
+ const UInt32 len = Get32(p);
+ if (len == 0)
+ return size == 4;
+ if (size < 8)
+ return false;
+ const UInt32 offs = Get32(p + 4);
+ p += 8;
+ size -= 8;
+ if (size < len || offs > destSize || len > destSize - offs)
+ return false;
+ memcpy(dest + offs, p, len);
+ p += len;
+ size -= len;
+ }
+}
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ GetNumberOfItems(&numItems);
+ if (numItems == 0)
+ return S_OK;
+
+ UInt64 totalSize = 0;
+ UInt64 solidPosMax = 0;
+
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const UInt32 index = (allFilesMode ? i : indices[i]);
+
+ #ifdef NSIS_SCRIPT
+ if (index >= _archive.Items.Size())
+ {
+ if (index == _archive.Items.Size())
+ totalSize += _archive.Script.Len();
+ else
+ totalSize += _archive.LicenseFiles[index - (_archive.Items.Size() + 1)].Size;
+ }
+ else
+ #endif
+ {
+ UInt32 size;
+ if (_archive.IsSolid)
+ {
+ GetUncompressedSize(index, size);
+ UInt64 pos = (UInt64)_archive.GetPosOfSolidItem(index) + size;
+ if (solidPosMax < pos)
+ solidPosMax = pos;
+ }
+ else
+ {
+ GetCompressedSize(index, size);
+ totalSize += size;
+ }
+ }
+ }
+
+ extractCallback->SetTotal(totalSize + solidPosMax);
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, !_archive.IsSolid);
+
+ if (_archive.IsSolid)
+ {
+ RINOK(_archive.SeekTo_DataStreamOffset())
+ RINOK(_archive.InitDecoder())
+ _archive.Decoder.StreamPos = 0;
+ }
+
+ /* We use tempBuf for solid archives, if there is duplicate item.
+ We don't know uncompressed size for non-solid archives, so we can't
+ allocate exact buffer.
+ We use tempBuf also for first part (EXE stub) of unistall.exe
+ and tempBuf2 is used for second part (NSIS script). */
+
+ CByteBuffer tempBuf;
+ CByteBuffer tempBuf2;
+
+ /* tempPos is pos in uncompressed stream of previous item for solid archive, that
+ was written to tempBuf */
+ UInt64 tempPos = (UInt64)(Int64)-1;
+
+ /* prevPos is pos in uncompressed stream of previous item for solid archive.
+ It's used for test mode (where we don't need to test same file second time */
+ UInt64 prevPos = (UInt64)(Int64)-1;
+
+ // if there is error in solid archive, we show error for all subsequent files
+ bool solidDataError = false;
+
+ UInt64 curTotalPacked = 0, curTotalUnpacked = 0;
+ UInt32 curPacked = 0;
+ UInt64 curUnpacked = 0;
+
+ for (i = 0; i < numItems; i++,
+ curTotalPacked += curPacked,
+ curTotalUnpacked += curUnpacked)
+ {
+ lps->InSize = curTotalPacked;
+ lps->OutSize = curTotalUnpacked;
+ if (_archive.IsSolid)
+ lps->OutSize += _archive.Decoder.StreamPos;
+
+ curPacked = 0;
+ curUnpacked = 0;
+ RINOK(lps->SetCur())
+
+ // RINOK(extractCallback->SetCompleted(&currentTotalSize))
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+ bool dataError = false;
+
+ #ifdef NSIS_SCRIPT
+ if (index >= (UInt32)_archive.Items.Size())
+ {
+ const void *data;
+ size_t size;
+ if (index == (UInt32)_archive.Items.Size())
+ {
+ data = (const Byte *)_archive.Script;
+ size = _archive.Script.Len();
+ }
+ else
+ {
+ CLicenseFile &lic = _archive.LicenseFiles[index - (_archive.Items.Size() + 1)];
+ if (lic.Text.Size() != 0)
+ data = lic.Text;
+ else
+ data = _archive._data + lic.Offset;
+ size = lic.Size;
+ }
+ curUnpacked = size;
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode))
+ if (realOutStream)
+ RINOK(WriteStream(realOutStream, data, size))
+ }
+ else
+ #endif
+ {
+ const CItem &item = _archive.Items[index];
+
+ if (!_archive.IsSolid)
+ GetCompressedSize(index, curPacked);
+
+ if (!testMode && !realOutStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode))
+
+ dataError = solidDataError;
+
+ bool needDecompress = false;
+
+ if (!item.IsEmptyFile)
+ {
+ needDecompress = !solidDataError;
+ if (needDecompress)
+ {
+ if (testMode && _archive.IsSolid && _archive.GetPosOfSolidItem(index) == prevPos)
+ needDecompress = false;
+ }
+ }
+
+ if (needDecompress)
+ {
+ bool writeToTemp = false;
+ bool readFromTemp = false;
+
+ if (!_archive.IsSolid)
+ {
+ RINOK(_archive.SeekToNonSolidItem(index))
+ }
+ else
+ {
+ UInt64 pos = _archive.GetPosOfSolidItem(index);
+ if (pos < _archive.Decoder.StreamPos)
+ {
+ if (pos != tempPos)
+ solidDataError = dataError = true;
+ readFromTemp = true;
+ }
+ else
+ {
+ HRESULT res = _archive.Decoder.SetToPos(pos, progress);
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ return res;
+ solidDataError = dataError = true;
+ }
+ else if (!testMode && i + 1 < numItems)
+ {
+ const UInt32 next = allFilesMode ? i + 1 : indices[i + 1];
+ if (next < _archive.Items.Size())
+ {
+ // next cannot be IsEmptyFile
+ const UInt64 nextPos = _archive.GetPosOfSolidItem(next);
+ if (nextPos == pos)
+ {
+ writeToTemp = true;
+ tempPos = pos;
+ }
+ }
+ }
+ }
+ prevPos = pos;
+ }
+
+ /* nsis 3.08 can use (PatchSize == 0) for uninstaller without patched section */
+
+ const bool is_PatchedUninstaller = item.Is_PatchedUninstaller();
+
+ if (!dataError)
+ {
+ // UInt32 unpackSize = 0;
+ // bool unpackSize_Defined = false;
+ bool writeToTemp1 = writeToTemp;
+ if (is_PatchedUninstaller)
+ {
+ // unpackSize = item.PatchSize;
+ // unpackSize_Defined = true;
+ if (!readFromTemp)
+ writeToTemp = true;
+ writeToTemp1 = writeToTemp;
+ if (_archive.ExeStub.Size() == 0)
+ {
+ if (writeToTemp1 && !readFromTemp)
+ tempBuf.Free();
+ writeToTemp1 = false;
+ }
+ }
+
+ if (readFromTemp)
+ {
+ if (realOutStream && !is_PatchedUninstaller)
+ RINOK(WriteStream(realOutStream, tempBuf, tempBuf.Size()))
+ }
+ else
+ {
+ UInt32 curUnpacked32 = 0;
+ const HRESULT res = _archive.Decoder.Decode(
+ writeToTemp1 ? &tempBuf : NULL,
+ is_PatchedUninstaller, item.PatchSize,
+ is_PatchedUninstaller ? NULL : (ISequentialOutStream *)realOutStream,
+ progress,
+ curPacked, curUnpacked32);
+ curUnpacked = curUnpacked32;
+ if (_archive.IsSolid)
+ curUnpacked = 0;
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ return res;
+ dataError = true;
+ if (_archive.IsSolid)
+ solidDataError = true;
+ }
+ }
+ }
+
+ if (!dataError && is_PatchedUninstaller)
+ {
+ if (_archive.ExeStub.Size() != 0)
+ {
+ CByteBuffer destBuf = _archive.ExeStub;
+ dataError = !UninstallerPatch(tempBuf, tempBuf.Size(), destBuf, destBuf.Size());
+ if (realOutStream)
+ RINOK(WriteStream(realOutStream, destBuf, destBuf.Size()))
+ }
+
+ if (readFromTemp)
+ {
+ if (realOutStream)
+ RINOK(WriteStream(realOutStream, tempBuf2, tempBuf2.Size()))
+ }
+ else
+ {
+ UInt32 curPacked2 = 0;
+ UInt32 curUnpacked2 = 0;
+
+ if (!_archive.IsSolid)
+ {
+ RINOK(_archive.SeekTo(_archive.GetPosOfNonSolidItem(index) + 4 + curPacked ))
+ }
+
+ const HRESULT res = _archive.Decoder.Decode(
+ writeToTemp ? &tempBuf2 : NULL,
+ false, 0,
+ realOutStream,
+ progress,
+ curPacked2, curUnpacked2);
+ curPacked += curPacked2;
+ if (!_archive.IsSolid)
+ curUnpacked += curUnpacked2;
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ return res;
+ dataError = true;
+ if (_archive.IsSolid)
+ solidDataError = true;
+ }
+ }
+ }
+ }
+ }
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(dataError ?
+ NExtract::NOperationResult::kDataError :
+ NExtract::NOperationResult::kOK))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+}}
diff --git a/CPP/7zip/Archive/Nsis/NsisHandler.h b/CPP/7zip/Archive/Nsis/NsisHandler.h
new file mode 100644
index 0000000..bb90bfe
--- /dev/null
+++ b/CPP/7zip/Archive/Nsis/NsisHandler.h
@@ -0,0 +1,30 @@
+// NSisHandler.h
+
+#ifndef ZIP7_INC_NSIS_HANDLER_H
+#define ZIP7_INC_NSIS_HANDLER_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../Common/CreateCoder.h"
+
+#include "../IArchive.h"
+
+#include "NsisIn.h"
+
+namespace NArchive {
+namespace NNsis {
+
+Z7_CLASS_IMP_CHandler_IInArchive_0
+
+ CInArchive _archive;
+ AString _methodString;
+
+ bool GetUncompressedSize(unsigned index, UInt32 &size) const;
+ bool GetCompressedSize(unsigned index, UInt32 &size) const;
+
+ // AString GetMethod(NMethodType::EEnum method, bool useItemFilter, UInt32 dictionary) const;
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Nsis/NsisIn.cpp b/CPP/7zip/Archive/Nsis/NsisIn.cpp
new file mode 100644
index 0000000..05ebfd0
--- /dev/null
+++ b/CPP/7zip/Archive/Nsis/NsisIn.cpp
@@ -0,0 +1,6138 @@
+// NsisIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../Common/LimitedStreams.h"
+
+#include "NsisIn.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
+// #define NUM_SPEED_TESTS 1000
+
+namespace NArchive {
+namespace NNsis {
+
+static const size_t kInputBufSize = 1 << 20;
+
+const Byte kSignature[kSignatureSize] = NSIS_SIGNATURE;
+static const UInt32 kMask_IsCompressed = (UInt32)1 << 31;
+
+static const unsigned kNumCommandParams = 6;
+static const unsigned kCmdSize = 4 + kNumCommandParams * 4;
+
+#ifdef NSIS_SCRIPT
+#define CR_LF "\x0D\x0A"
+#endif
+
+static const char * const kErrorStr = "$_ERROR_STR_";
+
+#define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; }
+
+
+/* There are several versions of NSIS:
+ 1) Original NSIS:
+ NSIS-2 ANSI
+ NSIS-3 ANSI
+ NSIS-3 Unicode
+ 2) NSIS from Jim Park that extends old NSIS-2 to Unicode support:
+ NSIS-Park-(1,2,3) ANSI
+ NSIS-Park-(1,2,3) Unicode
+
+ The command IDs layout is slightly different for different versions.
+ Also there are additional "log" versions of NSIS that support EW_LOG.
+ We use the layout of "NSIS-3 Unicode" without "log" as main layout.
+ And we transfer the command IDs to main layout, if another layout is detected. */
+
+
+enum
+{
+ EW_INVALID_OPCODE,
+ EW_RET, // Return
+ EW_NOP, // Nop, Goto
+ EW_ABORT, // Abort
+ EW_QUIT, // Quit
+ EW_CALL, // Call, InitPluginsDir
+ EW_UPDATETEXT, // DetailPrint
+ EW_SLEEP, // Sleep
+ EW_BRINGTOFRONT, // BringToFront
+ EW_CHDETAILSVIEW, // SetDetailsView
+ EW_SETFILEATTRIBUTES, // SetFileAttributes
+ EW_CREATEDIR, // CreateDirectory, SetOutPath
+ EW_IFFILEEXISTS, // IfFileExists
+ EW_SETFLAG, // SetRebootFlag, ...
+ EW_IFFLAG, // IfAbort, IfSilent, IfErrors, IfRebootFlag
+ EW_GETFLAG, // GetInstDirError, GetErrorLevel
+ EW_RENAME, // Rename
+ EW_GETFULLPATHNAME, // GetFullPathName
+ EW_SEARCHPATH, // SearchPath
+ EW_GETTEMPFILENAME, // GetTempFileName
+ EW_EXTRACTFILE, // File
+ EW_DELETEFILE, // Delete
+ EW_MESSAGEBOX, // MessageBox
+ EW_RMDIR, // RMDir
+ EW_STRLEN, // StrLen
+ EW_ASSIGNVAR, // StrCpy
+ EW_STRCMP, // StrCmp
+ EW_READENVSTR, // ReadEnvStr, ExpandEnvStrings
+ EW_INTCMP, // IntCmp, IntCmpU
+ EW_INTOP, // IntOp
+ EW_INTFMT, // IntFmt/Int64Fmt
+ EW_PUSHPOP, // Push/Pop/Exchange
+ EW_FINDWINDOW, // FindWindow
+ EW_SENDMESSAGE, // SendMessage
+ EW_ISWINDOW, // IsWindow
+ EW_GETDLGITEM, // GetDlgItem
+ EW_SETCTLCOLORS, // SetCtlColors
+ EW_SETBRANDINGIMAGE, // SetBrandingImage / LoadAndSetImage
+ EW_CREATEFONT, // CreateFont
+ EW_SHOWWINDOW, // ShowWindow, EnableWindow, HideWindow
+ EW_SHELLEXEC, // ExecShell
+ EW_EXECUTE, // Exec, ExecWait
+ EW_GETFILETIME, // GetFileTime
+ EW_GETDLLVERSION, // GetDLLVersion
+
+ // EW_GETFONTVERSION, // Park : 2.46.2
+ // EW_GETFONTNAME, // Park : 2.46.3
+
+ EW_REGISTERDLL, // RegDLL, UnRegDLL, CallInstDLL
+ EW_CREATESHORTCUT, // CreateShortCut
+ EW_COPYFILES, // CopyFiles
+ EW_REBOOT, // Reboot
+ EW_WRITEINI, // WriteINIStr, DeleteINISec, DeleteINIStr, FlushINI
+ EW_READINISTR, // ReadINIStr
+ EW_DELREG, // DeleteRegValue, DeleteRegKey
+ EW_WRITEREG, // WriteRegStr, WriteRegExpandStr, WriteRegBin, WriteRegDWORD
+ EW_READREGSTR, // ReadRegStr, ReadRegDWORD
+ EW_REGENUM, // EnumRegKey, EnumRegValue
+ EW_FCLOSE, // FileClose
+ EW_FOPEN, // FileOpen
+ EW_FPUTS, // FileWrite, FileWriteByte
+ EW_FGETS, // FileRead, FileReadByte
+
+ // Park
+ // EW_FPUTWS, // FileWriteUTF16LE, FileWriteWord
+ // EW_FGETWS, // FileReadUTF16LE, FileReadWord
+
+ EW_FSEEK, // FileSeek
+ EW_FINDCLOSE, // FindClose
+ EW_FINDNEXT, // FindNext
+ EW_FINDFIRST, // FindFirst
+ EW_WRITEUNINSTALLER, // WriteUninstaller
+
+ // Park : since 2.46.3 the log is enabled in main Park version
+ // EW_LOG, // LogSet, LogText
+
+ EW_SECTIONSET, // Get*, Set*
+ EW_INSTTYPESET, // InstTypeSetText, InstTypeGetText, SetCurInstType, GetCurInstType
+
+ /*
+ // before v3.06 nsis it was so:
+ // instructions not actually implemented in exehead, but used in compiler.
+ EW_GETLABELADDR, // both of these get converted to EW_ASSIGNVAR
+ EW_GETFUNCTIONADDR,
+ */
+
+ // v3.06 and later it was changed to:
+ EW_GETOSINFO,
+ EW_RESERVEDOPCODE,
+
+ EW_LOCKWINDOW, // LockWindow
+
+ // 2 unicode commands available only in Unicode archive
+ EW_FPUTWS, // FileWriteUTF16LE, FileWriteWord
+ EW_FGETWS, // FileReadUTF16LE, FileReadWord
+
+ /*
+ // since v3.06 the fllowing IDs codes was moved here:
+ // Opcodes listed here are not actually used in exehead. No exehead opcodes should be present after these!
+ EW_GETLABELADDR, // --> EW_ASSIGNVAR
+ EW_GETFUNCTIONADDR, // --> EW_ASSIGNVAR
+ */
+
+ // The following IDs are not IDs in real order.
+ // We just need some IDs to translate eny extended layout to main layout.
+
+ EW_LOG, // LogSet, LogText
+
+ // Park
+ EW_FINDPROC, // FindProc
+
+ EW_GETFONTVERSION, // GetFontVersion
+ EW_GETFONTNAME, // GetFontName
+
+ kNumCmds
+};
+
+
+
+struct CCommandInfo
+{
+ Byte NumParams;
+};
+
+static const CCommandInfo k_Commands[kNumCmds] =
+{
+ { 0 }, // "Invalid" },
+ { 0 }, // Return
+ { 1 }, // Nop, Goto
+ { 1 }, // "Abort" },
+ { 0 }, // "Quit" },
+ { 2 }, // Call
+ { 6 }, // "DetailPrint" }, // 1 param in new versions, 6 in old NSIS versions
+ { 1 }, // "Sleep" },
+ { 0 }, // "BringToFront" },
+ { 2 }, // "SetDetailsView" },
+ { 2 }, // "SetFileAttributes" },
+ { 3 }, // CreateDirectory, SetOutPath
+ { 3 }, // "IfFileExists" },
+ { 3 }, // SetRebootFlag, ...
+ { 4 }, // "If" }, // IfAbort, IfSilent, IfErrors, IfRebootFlag
+ { 2 }, // "Get" }, // GetInstDirError, GetErrorLevel
+ { 4 }, // "Rename" },
+ { 3 }, // "GetFullPathName" },
+ { 2 }, // "SearchPath" },
+ { 2 }, // "GetTempFileName" },
+ { 6 }, // "File"
+ { 2 }, // "Delete" },
+ { 6 }, // "MessageBox" },
+ { 2 }, // "RMDir" },
+ { 2 }, // "StrLen" },
+ { 4 }, // StrCpy, GetCurrentAddress
+ { 5 }, // "StrCmp" },
+ { 3 }, // ReadEnvStr, ExpandEnvStrings
+ { 6 }, // "IntCmp" },
+ { 4 }, // "IntOp" },
+ { 4 }, // "IntFmt" }, EW_INTFMT
+ { 6 }, // Push, Pop, Exch // it must be 3 params. But some multi-command write garbage.
+ { 5 }, // "FindWindow" },
+ { 6 }, // "SendMessage" },
+ { 3 }, // "IsWindow" },
+ { 3 }, // "GetDlgItem" },
+ { 2 }, // "SetCtlColors" },
+ { 4 }, // "SetBrandingImage" } // LoadAndSetImage
+ { 5 }, // "CreateFont" },
+ { 4 }, // ShowWindow, EnableWindow, HideWindow
+ { 6 }, // "ExecShell" },
+ { 3 }, // "Exec" }, // Exec, ExecWait
+ { 3 }, // "GetFileTime" },
+ { 4 }, // "GetDLLVersion" },
+ { 6 }, // RegDLL, UnRegDLL, CallInstDLL // it must be 5 params. But some multi-command write garbage.
+ { 6 }, // "CreateShortCut" },
+ { 4 }, // "CopyFiles" },
+ { 1 }, // "Reboot" },
+ { 5 }, // WriteINIStr, DeleteINISec, DeleteINIStr, FlushINI
+ { 4 }, // "ReadINIStr" },
+ { 5 }, // "DeleteReg" }, // DeleteRegKey, DeleteRegValue
+ { 6 }, // "WriteReg" }, // WriteRegStr, WriteRegExpandStr, WriteRegBin, WriteRegDWORD
+ { 5 }, // "ReadReg" }, // ReadRegStr, ReadRegDWORD
+ { 5 }, // "EnumReg" }, // EnumRegKey, EnumRegValue
+ { 1 }, // "FileClose" },
+ { 4 }, // "FileOpen" },
+ { 3 }, // "FileWrite" }, // FileWrite, FileWriteByte
+ { 4 }, // "FileRead" }, // FileRead, FileReadByte
+ { 4 }, // "FileSeek" },
+ { 1 }, // "FindClose" },
+ { 2 }, // "FindNext" },
+ { 3 }, // "FindFirst" },
+ { 4 }, // "WriteUninstaller" },
+ { 5 }, // "Section" }, // ***
+ { 4 }, // InstTypeSetText, InstTypeGetText, SetCurInstType, GetCurInstType
+
+ // { 6 }, // "GetLabelAddr" }, // before 3.06
+ { 6 }, // "GetOsInfo" }, GetKnownFolderPath, ReadMemory, // v3.06+
+
+ { 2 }, // "GetFunctionAddress" }, // before 3.06
+
+ { 1 }, // "LockWindow" },
+ { 4 }, // "FileWrite" }, // FileWriteUTF16LE, FileWriteWord
+ { 4 }, // "FileRead" }, // FileReadUTF16LE, FileReadWord
+
+ { 2 }, // "Log" }, // LogSet, LogText
+ // Park
+ { 2 }, // "FindProc" },
+ { 2 }, // "GetFontVersion" },
+ { 2 }, // "GetFontName" }
+};
+
+#ifdef NSIS_SCRIPT
+
+static const char * const k_CommandNames[kNumCmds] =
+{
+ "Invalid"
+ , NULL // Return
+ , NULL // Nop, Goto
+ , "Abort"
+ , "Quit"
+ , NULL // Call
+ , "DetailPrint" // 1 param in new versions, 6 in old NSIS versions
+ , "Sleep"
+ , "BringToFront"
+ , "SetDetailsView"
+ , "SetFileAttributes"
+ , NULL // CreateDirectory, SetOutPath
+ , "IfFileExists"
+ , NULL // SetRebootFlag, ...
+ , "If" // IfAbort, IfSilent, IfErrors, IfRebootFlag
+ , "Get" // GetInstDirError, GetErrorLevel
+ , "Rename"
+ , "GetFullPathName"
+ , "SearchPath"
+ , "GetTempFileName"
+ , NULL // File
+ , "Delete"
+ , "MessageBox"
+ , "RMDir"
+ , "StrLen"
+ , NULL // StrCpy, GetCurrentAddress
+ , "StrCmp"
+ , NULL // ReadEnvStr, ExpandEnvStrings
+ , NULL // IntCmp / Int64Cmp / EW_INTCMP
+ , "IntOp"
+ , NULL // IntFmt / Int64Fmt / EW_INTFMT
+ , NULL // Push, Pop, Exch // it must be 3 params. But some multi-command write garbage.
+ , "FindWindow"
+ , "SendMessage"
+ , "IsWindow"
+ , "GetDlgItem"
+ , "SetCtlColors"
+ , "SetBrandingImage"
+ , "CreateFont"
+ , NULL // ShowWindow, EnableWindow, HideWindow
+ , "ExecShell"
+ , "Exec" // Exec, ExecWait
+ , "GetFileTime"
+ , "GetDLLVersion"
+ , NULL // RegDLL, UnRegDLL, CallInstDLL // it must be 5 params. But some multi-command write garbage.
+ , "CreateShortCut"
+ , "CopyFiles"
+ , "Reboot"
+ , NULL // WriteINIStr, DeleteINISec, DeleteINIStr, FlushINI
+ , "ReadINIStr"
+ , "DeleteReg" // DeleteRegKey, DeleteRegValue
+ , "WriteReg" // WriteRegStr, WriteRegExpandStr, WriteRegBin, WriteRegDWORD
+ , "ReadReg" // ReadRegStr, ReadRegDWORD
+ , "EnumReg" // EnumRegKey, EnumRegValue
+ , "FileClose"
+ , "FileOpen"
+ , "FileWrite" // FileWrite, FileWriteByte
+ , "FileRead" // FileRead, FileReadByte
+ , "FileSeek"
+ , "FindClose"
+ , "FindNext"
+ , "FindFirst"
+ , "WriteUninstaller"
+ , "Section" // ***
+ , NULL // InstTypeSetText, InstTypeGetText, SetCurInstType, GetCurInstType
+
+ , NULL // "GetOsInfo" // , "GetLabelAddr" //
+ , "GetFunctionAddress"
+
+ , "LockWindow"
+ , "FileWrite" // FileWriteUTF16LE, FileWriteWord
+ , "FileRead" // FileReadUTF16LE, FileReadWord
+
+ , "Log" // LogSet, LogText
+
+ // Park
+ , "FindProc"
+ , "GetFontVersion"
+ , "GetFontName"
+};
+
+#endif
+
+/* NSIS can use one name for two CSIDL_*** and CSIDL_COMMON_*** items (CurrentUser / AllUsers)
+ Some NSIS shell names are not identical to WIN32 CSIDL_* names.
+ NSIS doesn't use some CSIDL_* values. But we add name for all CSIDL_ (marked with '+'). */
+
+static const char * const kShellStrings[] =
+{
+ "DESKTOP" // +
+ , "INTERNET" // +
+ , "SMPROGRAMS" // CSIDL_PROGRAMS
+ , "CONTROLS" // +
+ , "PRINTERS" // +
+ , "DOCUMENTS" // CSIDL_PERSONAL
+ , "FAVORITES" // CSIDL_FAVORITES
+ , "SMSTARTUP" // CSIDL_STARTUP
+ , "RECENT" // CSIDL_RECENT
+ , "SENDTO" // CSIDL_SENDTO
+ , "BITBUCKET" // +
+ , "STARTMENU"
+ , NULL // CSIDL_MYDOCUMENTS = CSIDL_PERSONAL
+ , "MUSIC" // CSIDL_MYMUSIC
+ , "VIDEOS" // CSIDL_MYVIDEO
+ , NULL
+ , "DESKTOP" // CSIDL_DESKTOPDIRECTORY
+ , "DRIVES" // +
+ , "NETWORK" // +
+ , "NETHOOD"
+ , "FONTS"
+ , "TEMPLATES"
+ , "STARTMENU" // CSIDL_COMMON_STARTMENU
+ , "SMPROGRAMS" // CSIDL_COMMON_PROGRAMS
+ , "SMSTARTUP" // CSIDL_COMMON_STARTUP
+ , "DESKTOP" // CSIDL_COMMON_DESKTOPDIRECTORY
+ , "APPDATA" // CSIDL_APPDATA !!! "QUICKLAUNCH"
+ , "PRINTHOOD"
+ , "LOCALAPPDATA"
+ , "ALTSTARTUP"
+ , "ALTSTARTUP" // CSIDL_COMMON_ALTSTARTUP
+ , "FAVORITES" // CSIDL_COMMON_FAVORITES
+ , "INTERNET_CACHE"
+ , "COOKIES"
+ , "HISTORY"
+ , "APPDATA" // CSIDL_COMMON_APPDATA
+ , "WINDIR"
+ , "SYSDIR"
+ , "PROGRAM_FILES" // +
+ , "PICTURES" // CSIDL_MYPICTURES
+ , "PROFILE"
+ , "SYSTEMX86" // +
+ , "PROGRAM_FILESX86" // +
+ , "PROGRAM_FILES_COMMON" // +
+ , "PROGRAM_FILES_COMMONX8" // + CSIDL_PROGRAM_FILES_COMMONX86
+ , "TEMPLATES" // CSIDL_COMMON_TEMPLATES
+ , "DOCUMENTS" // CSIDL_COMMON_DOCUMENTS
+ , "ADMINTOOLS" // CSIDL_COMMON_ADMINTOOLS
+ , "ADMINTOOLS" // CSIDL_ADMINTOOLS
+ , "CONNECTIONS" // +
+ , NULL
+ , NULL
+ , NULL
+ , "MUSIC" // CSIDL_COMMON_MUSIC
+ , "PICTURES" // CSIDL_COMMON_PICTURES
+ , "VIDEOS" // CSIDL_COMMON_VIDEO
+ , "RESOURCES"
+ , "RESOURCES_LOCALIZED"
+ , "COMMON_OEM_LINKS" // +
+ , "CDBURN_AREA"
+ , NULL // unused
+ , "COMPUTERSNEARME" // +
+};
+
+
+static inline void UIntToString(AString &s, UInt32 v)
+{
+ s.Add_UInt32(v);
+}
+
+#ifdef NSIS_SCRIPT
+
+void CInArchive::Add_UInt(UInt32 v)
+{
+ char sz[16];
+ ConvertUInt32ToString(v, sz);
+ Script += sz;
+}
+
+static void Add_SignedInt(CDynLimBuf &s, Int32 v)
+{
+ char sz[32];
+ ConvertInt64ToString(v, sz);
+ s += sz;
+}
+
+static void Add_Hex(CDynLimBuf &s, UInt32 v)
+{
+ char sz[16];
+ sz[0] = '0';
+ sz[1] = 'x';
+ ConvertUInt32ToHex(v, sz + 2);
+ s += sz;
+}
+
+static UInt32 GetUi16Str_Len(const Byte *p)
+{
+ const Byte *pp = p;
+ for (; *pp != 0 || *(pp + 1) != 0; pp += 2);
+ return (UInt32)((pp - p) >> 1);
+}
+
+void CInArchive::AddLicense(UInt32 param, Int32 langID)
+{
+ Space();
+ if (param >= NumStringChars ||
+ param + 1 >= NumStringChars)
+ {
+ Script += kErrorStr;
+ return;
+ }
+ strUsed[param] = 1;
+
+ const UInt32 start = _stringsPos + (IsUnicode ? param * 2 : param);
+ const UInt32 offset = start + (IsUnicode ? 2 : 1);
+ {
+ FOR_VECTOR (i, LicenseFiles)
+ {
+ const CLicenseFile &lic = LicenseFiles[i];
+ if (offset == lic.Offset)
+ {
+ Script += lic.Name;
+ return;
+ }
+ }
+ }
+ AString fileName ("[LICENSE]");
+ if (langID >= 0)
+ {
+ fileName += "\\license-";
+ // LangId_To_String(fileName, langID);
+ UIntToString(fileName, (UInt32)langID);
+ }
+ else if (++_numRootLicenses > 1)
+ {
+ fileName.Add_Minus();
+ UIntToString(fileName, _numRootLicenses);
+ }
+ const Byte *sz = (_data + start);
+ const unsigned marker = IsUnicode ? Get16(sz) : *sz;
+ const bool isRTF = (marker == 2);
+ fileName += isRTF ? ".rtf" : ".txt"; // if (*sz == 1) it's text;
+ Script += fileName;
+
+ CLicenseFile &lic = LicenseFiles.AddNew();
+ lic.Name = fileName;
+ lic.Offset = offset;
+ if (!IsUnicode)
+ lic.Size = (UInt32)strlen((const char *)sz + 1);
+ else
+ {
+ sz += 2;
+ const UInt32 len = GetUi16Str_Len(sz);
+ lic.Size = len * 2;
+ if (isRTF)
+ {
+ lic.Text.Alloc((size_t)len);
+ for (UInt32 i = 0; i < len; i++, sz += 2)
+ {
+ unsigned c = Get16(sz);
+ if (c >= 256)
+ c = '?';
+ lic.Text[i] = (Byte)(c);
+ }
+ lic.Size = len;
+ lic.Offset = 0;
+ }
+ }
+}
+
+#endif
+
+
+#ifdef NSIS_SCRIPT
+#define Z7_NSIS_WIN_GENERIC_READ ((UInt32)1 << 31)
+#endif
+#define Z7_NSIS_WIN_GENERIC_WRITE ((UInt32)1 << 30)
+#ifdef NSIS_SCRIPT
+#define Z7_NSIS_WIN_GENERIC_EXECUTE ((UInt32)1 << 29)
+#define Z7_NSIS_WIN_GENERIC_ALL ((UInt32)1 << 28)
+#endif
+
+#ifdef NSIS_SCRIPT
+#define Z7_NSIS_WIN_CREATE_NEW 1
+#endif
+#define Z7_NSIS_WIN_CREATE_ALWAYS 2
+#ifdef NSIS_SCRIPT
+#define Z7_NSIS_WIN_OPEN_EXISTING 3
+#define Z7_NSIS_WIN_OPEN_ALWAYS 4
+#define Z7_NSIS_WIN_TRUNCATE_EXISTING 5
+#endif
+
+
+// #define kVar_CMDLINE 20
+#define kVar_INSTDIR 21
+#define kVar_OUTDIR 22
+#define kVar_EXEDIR 23
+// #define kVar_LANGUAGE 24
+#define kVar_TEMP 25
+#define kVar_PLUGINSDIR 26
+#define kVar_EXEPATH 27 // NSIS 2.26+
+// #define kVar_EXEFILE 28 // NSIS 2.26+
+
+#define kVar_HWNDPARENT_225 27
+#ifdef NSIS_SCRIPT
+#define kVar_HWNDPARENT 29
+#endif
+
+// #define kVar__CLICK 30
+#define kVar_Spec_OUTDIR_225 29 // NSIS 2.04 - 2.25
+#define kVar_Spec_OUTDIR 31 // NSIS 2.26+
+
+
+static const char * const kVarStrings[] =
+{
+ "CMDLINE"
+ , "INSTDIR"
+ , "OUTDIR"
+ , "EXEDIR"
+ , "LANGUAGE"
+ , "TEMP"
+ , "PLUGINSDIR"
+ , "EXEPATH" // NSIS 2.26+
+ , "EXEFILE" // NSIS 2.26+
+ , "HWNDPARENT"
+ , "_CLICK" // is set from page->clicknext
+ , "_OUTDIR" // NSIS 2.04+
+};
+
+static const unsigned kNumInternalVars = 20 + Z7_ARRAY_SIZE(kVarStrings);
+
+#define GET_NUM_INTERNAL_VARS (IsNsis200 ? kNumInternalVars - 3 : IsNsis225 ? kNumInternalVars - 2 : kNumInternalVars)
+
+void CInArchive::GetVar2(AString &res, UInt32 index)
+{
+ if (index < 20)
+ {
+ if (index >= 10)
+ {
+ res += 'R';
+ index -= 10;
+ }
+ UIntToString(res, index);
+ }
+ else
+ {
+ unsigned numInternalVars = GET_NUM_INTERNAL_VARS;
+ if (index < numInternalVars)
+ {
+ if (IsNsis225 && index >= kVar_EXEPATH)
+ index += 2;
+ res += kVarStrings[index - 20];
+ }
+ else
+ {
+ res += '_';
+ UIntToString(res, index - numInternalVars);
+ res += '_';
+ }
+ }
+}
+
+void CInArchive::GetVar(AString &res, UInt32 index)
+{
+ res += '$';
+ GetVar2(res, index);
+}
+
+#ifdef NSIS_SCRIPT
+
+void CInArchive::Add_Var(UInt32 index)
+{
+ _tempString_for_GetVar.Empty();
+ GetVar(_tempString_for_GetVar, index);
+ Script += _tempString_for_GetVar;
+}
+
+void CInArchive::AddParam_Var(UInt32 index)
+{
+ Space();
+ Add_Var(index);
+}
+
+void CInArchive::AddParam_UInt(UInt32 value)
+{
+ Space();
+ Add_UInt(value);
+}
+
+#endif
+
+
+#define NS_CODE_SKIP 252
+#define NS_CODE_VAR 253
+#define NS_CODE_SHELL 254
+// #define NS_CODE_LANG 255
+
+// #define NS_3_CODE_LANG 1
+#define NS_3_CODE_SHELL 2
+#define NS_3_CODE_VAR 3
+#define NS_3_CODE_SKIP 4
+
+#define PARK_CODE_SKIP 0xE000
+#define PARK_CODE_VAR 0xE001
+#define PARK_CODE_SHELL 0xE002
+#define PARK_CODE_LANG 0xE003
+
+#define IS_NS_SPEC_CHAR(c) ((c) >= NS_CODE_SKIP)
+#define IS_PARK_SPEC_CHAR(c) ((c) >= PARK_CODE_SKIP && (c) <= PARK_CODE_LANG)
+
+#define DECODE_NUMBER_FROM_2_CHARS(c0, c1) (((unsigned)(c0) & 0x7F) | (((unsigned)((c1) & 0x7F)) << 7))
+#define CONVERT_NUMBER_NS_3_UNICODE(n) n = ((n & 0x7F) | (((n >> 8) & 0x7F) << 7))
+#define CONVERT_NUMBER_PARK(n) n &= 0x7FFF
+
+
+static bool AreStringsEqual_16and8(const Byte *p16, const char *p8)
+{
+ for (;;)
+ {
+ unsigned c16 = Get16(p16); p16 += 2;
+ unsigned c = (Byte)(*p8++);
+ if (c16 != c)
+ return false;
+ if (c == 0)
+ return true;
+ }
+}
+
+void CInArchive::GetShellString(AString &s, unsigned index1, unsigned index2)
+{
+ // zeros are not allowed here.
+ // if (index1 == 0 || index2 == 0) throw 333;
+
+ if ((index1 & 0x80) != 0)
+ {
+ unsigned offset = (index1 & 0x3F);
+
+ /* NSIS reads registry string:
+ keyName = HKLM Software\\Microsoft\\Windows\\CurrentVersion
+ mask = KEY_WOW64_64KEY, If 64-bit flag in index1 is set
+ valueName = string(offset)
+ If registry reading is failed, NSIS uses second parameter (index2)
+ to read string. The recursion is possible in that case in NSIS.
+ We don't parse index2 string. We only set strUsed status for that
+ string (but without recursion). */
+
+ if (offset >= NumStringChars)
+ {
+ s += kErrorStr;
+ return;
+ }
+
+ #ifdef NSIS_SCRIPT
+ strUsed[offset] = 1;
+ if (index2 < NumStringChars)
+ strUsed[index2] = 1;
+ #endif
+
+ const Byte *p = (const Byte *)(_data + _stringsPos);
+ int id = -1;
+ if (IsUnicode)
+ {
+ p += offset * 2;
+ if (AreStringsEqual_16and8(p, "ProgramFilesDir"))
+ id = 0;
+ else if (AreStringsEqual_16and8(p, "CommonFilesDir"))
+ id = 1;
+ }
+ else
+ {
+ p += offset;
+ if (strcmp((const char *)p, "ProgramFilesDir") == 0)
+ id = 0;
+ else if (strcmp((const char *)p, "CommonFilesDir") == 0)
+ id = 1;
+ }
+
+ s += ((id >= 0) ? (id == 0 ? "$PROGRAMFILES" : "$COMMONFILES") :
+ "$_ERROR_UNSUPPORTED_VALUE_REGISTRY_");
+ // s += ((index1 & 0x40) != 0) ? "64" : "32";
+ if ((index1 & 0x40) != 0)
+ s += "64";
+
+ if (id < 0)
+ {
+ s += '(';
+ if (IsUnicode)
+ {
+ for (unsigned i = 0; i < 256; i++)
+ {
+ wchar_t c = Get16(p + i * 2);
+ if (c == 0)
+ break;
+ if (c < 0x80)
+ s += (char)c;
+ }
+ }
+ else
+ s += (const char *)p;
+ s += ')';
+ }
+ return;
+ }
+
+ s += '$';
+ if (index1 < Z7_ARRAY_SIZE(kShellStrings))
+ {
+ const char *sz = kShellStrings[index1];
+ if (sz)
+ {
+ s += sz;
+ return;
+ }
+ }
+ if (index2 < Z7_ARRAY_SIZE(kShellStrings))
+ {
+ const char *sz = kShellStrings[index2];
+ if (sz)
+ {
+ s += sz;
+ return;
+ }
+ }
+ s += "_ERROR_UNSUPPORTED_SHELL_";
+ s += '[';
+ UIntToString(s, index1);
+ s += ',';
+ UIntToString(s, index2);
+ s += ']';
+}
+
+#ifdef NSIS_SCRIPT
+
+void CInArchive::Add_LangStr_Simple(UInt32 id)
+{
+ Script += "LSTR_";
+ Add_UInt(id);
+}
+
+#endif
+
+void CInArchive::Add_LangStr(AString &res, UInt32 id)
+{
+ #ifdef NSIS_SCRIPT
+ langStrIDs.Add(id);
+ #endif
+ res += "$(LSTR_";
+ UIntToString(res, id);
+ res += ')';
+}
+
+void CInArchive::GetNsisString_Raw(const Byte *s)
+{
+ Raw_AString.Empty();
+
+ if (NsisType != k_NsisType_Nsis3)
+ {
+ for (;;)
+ {
+ Byte c = *s++;
+ if (c == 0)
+ return;
+ if (IS_NS_SPEC_CHAR(c))
+ {
+ Byte c0 = *s++;
+ if (c0 == 0)
+ return;
+ if (c != NS_CODE_SKIP)
+ {
+ Byte c1 = *s++;
+ if (c1 == 0)
+ return;
+
+ if (c == NS_CODE_SHELL)
+ GetShellString(Raw_AString, c0, c1);
+ else
+ {
+ unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1);
+ if (c == NS_CODE_VAR)
+ GetVar(Raw_AString, n);
+ else // if (c == NS_CODE_LANG)
+ Add_LangStr(Raw_AString, n);
+ }
+ continue;
+ }
+ c = c0;
+ }
+ Raw_AString += (char)c;
+ }
+ }
+
+ // NSIS-3 ANSI
+ for (;;)
+ {
+ Byte c = *s++;
+ if (c <= NS_3_CODE_SKIP)
+ {
+ if (c == 0)
+ return;
+ Byte c0 = *s++;
+ if (c0 == 0)
+ return;
+ if (c != NS_3_CODE_SKIP)
+ {
+ Byte c1 = *s++;
+ if (c1 == 0)
+ return;
+
+ if (c == NS_3_CODE_SHELL)
+ GetShellString(Raw_AString, c0, c1);
+ else
+ {
+ unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1);
+ if (c == NS_3_CODE_VAR)
+ GetVar(Raw_AString, n);
+ else // if (c == NS_3_CODE_LANG)
+ Add_LangStr(Raw_AString, n);
+ }
+ continue;
+ }
+ c = c0;
+ }
+ Raw_AString += (char)c;
+ }
+}
+
+#ifdef NSIS_SCRIPT
+
+void CInArchive::GetNsisString(AString &res, const Byte *s)
+{
+ for (;;)
+ {
+ Byte c = *s++;
+ if (c == 0)
+ return;
+ if (NsisType != k_NsisType_Nsis3)
+ {
+ if (IS_NS_SPEC_CHAR(c))
+ {
+ Byte c0 = *s++;
+ if (c0 == 0)
+ return;
+ if (c != NS_CODE_SKIP)
+ {
+ Byte c1 = *s++;
+ if (c1 == 0)
+ return;
+ if (c == NS_CODE_SHELL)
+ GetShellString(res, c0, c1);
+ else
+ {
+ unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1);
+ if (c == NS_CODE_VAR)
+ GetVar(res, n);
+ else // if (c == NS_CODE_LANG)
+ Add_LangStr(res, n);
+ }
+ continue;
+ }
+ c = c0;
+ }
+ }
+ else
+ {
+ // NSIS-3 ANSI
+ if (c <= NS_3_CODE_SKIP)
+ {
+ Byte c0 = *s++;
+ if (c0 == 0)
+ return;
+ if (c0 == 0)
+ break;
+ if (c != NS_3_CODE_SKIP)
+ {
+ Byte c1 = *s++;
+ if (c1 == 0)
+ return;
+ if (c == NS_3_CODE_SHELL)
+ GetShellString(res, c0, c1);
+ else
+ {
+ unsigned n = DECODE_NUMBER_FROM_2_CHARS(c0, c1);
+ if (c == NS_3_CODE_VAR)
+ GetVar(res, n);
+ else // if (c == NS_3_CODE_LANG)
+ Add_LangStr(res, n);
+ }
+ continue;
+ }
+ c = c0;
+ }
+ }
+
+ {
+ const char *e;
+ if (c == 9) e = "$\\t";
+ else if (c == 10) e = "$\\n";
+ else if (c == 13) e = "$\\r";
+ else if (c == '"') e = "$\\\"";
+ else if (c == '$') e = "$$";
+ else
+ {
+ res += (char)c;
+ continue;
+ }
+ res += e;
+ continue;
+ }
+ }
+}
+
+#endif
+
+void CInArchive::GetNsisString_Unicode_Raw(const Byte *p)
+{
+ Raw_UString.Empty();
+
+ if (IsPark())
+ {
+ for (;;)
+ {
+ unsigned c = Get16(p);
+ p += 2;
+ if (c == 0)
+ break;
+ if (c < 0x80)
+ {
+ Raw_UString += (char)c;
+ continue;
+ }
+
+ if (IS_PARK_SPEC_CHAR(c))
+ {
+ unsigned n = Get16(p);
+ p += 2;
+ if (n == 0)
+ break;
+ if (c != PARK_CODE_SKIP)
+ {
+ Raw_AString.Empty();
+ if (c == PARK_CODE_SHELL)
+ GetShellString(Raw_AString, n & 0xFF, n >> 8);
+ else
+ {
+ CONVERT_NUMBER_PARK(n);
+ if (c == PARK_CODE_VAR)
+ GetVar(Raw_AString, n);
+ else // if (c == PARK_CODE_LANG)
+ Add_LangStr(Raw_AString, n);
+ }
+ Raw_UString += Raw_AString.Ptr(); // check it !
+ continue;
+ }
+ c = n;
+ }
+
+ Raw_UString += (wchar_t)c;
+ }
+
+ return;
+ }
+
+ // NSIS-3 Unicode
+ for (;;)
+ {
+ unsigned c = Get16(p);
+ p += 2;
+ if (c > NS_3_CODE_SKIP)
+ {
+ Raw_UString += (wchar_t)c;
+ continue;
+ }
+ if (c == 0)
+ break;
+
+ unsigned n = Get16(p);
+ p += 2;
+ if (n == 0)
+ break;
+ if (c == NS_3_CODE_SKIP)
+ {
+ Raw_UString += (wchar_t)n;
+ continue;
+ }
+
+ Raw_AString.Empty();
+ if (c == NS_3_CODE_SHELL)
+ GetShellString(Raw_AString, n & 0xFF, n >> 8);
+ else
+ {
+ CONVERT_NUMBER_NS_3_UNICODE(n);
+ if (c == NS_3_CODE_VAR)
+ GetVar(Raw_AString, n);
+ else // if (c == NS_3_CODE_LANG)
+ Add_LangStr(Raw_AString, n);
+ }
+ Raw_UString += Raw_AString.Ptr();
+ }
+}
+
+#ifdef NSIS_SCRIPT
+
+static const Byte kUtf8Limits[5] = { 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
+
+void CInArchive::GetNsisString_Unicode(AString &res, const Byte *p)
+{
+ for (;;)
+ {
+ unsigned c = Get16(p);
+ p += 2;
+ if (c == 0)
+ break;
+ if (IsPark())
+ {
+ if (IS_PARK_SPEC_CHAR(c))
+ {
+ unsigned n = Get16(p);
+ p += 2;
+ if (n == 0)
+ break;
+ if (c != PARK_CODE_SKIP)
+ {
+ if (c == PARK_CODE_SHELL)
+ GetShellString(res, n & 0xFF, n >> 8);
+ else
+ {
+ CONVERT_NUMBER_PARK(n);
+ if (c == PARK_CODE_VAR)
+ GetVar(res, n);
+ else // if (c == PARK_CODE_LANG)
+ Add_LangStr(res, n);
+ }
+ continue;
+ }
+ c = n;
+ }
+ }
+ else
+ {
+ // NSIS-3 Unicode
+ if (c <= NS_3_CODE_SKIP)
+ {
+ unsigned n = Get16(p);
+ p += 2;
+ if (n == 0)
+ break;
+ if (c != NS_3_CODE_SKIP)
+ {
+ if (c == NS_3_CODE_SHELL)
+ GetShellString(res, n & 0xFF, n >> 8);
+ else
+ {
+ CONVERT_NUMBER_NS_3_UNICODE(n);
+ if (c == NS_3_CODE_VAR)
+ GetVar(res, n);
+ else // if (c == NS_3_CODE_LANG)
+ Add_LangStr(res, n);
+ }
+ continue;
+ }
+ c = n;
+ }
+ }
+
+ if (c < 0x80)
+ {
+ const char *e;
+ if (c == 9) e = "$\\t";
+ else if (c == 10) e = "$\\n";
+ else if (c == 13) e = "$\\r";
+ else if (c == '"') e = "$\\\"";
+ else if (c == '$') e = "$$";
+ else
+ {
+ res += (char)c;
+ continue;
+ }
+ res += e;
+ continue;
+ }
+
+ UInt32 value = c;
+ /*
+ if (value >= 0xD800 && value < 0xE000)
+ {
+ UInt32 c2;
+ if (value >= 0xDC00 || srcPos == srcLen)
+ break;
+ c2 = src[srcPos++];
+ if (c2 < 0xDC00 || c2 >= 0xE000)
+ break;
+ value = (((value - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
+ }
+ */
+ unsigned numAdds;
+ for (numAdds = 1; numAdds < 5; numAdds++)
+ if (value < (((UInt32)1) << (numAdds * 5 + 6)))
+ break;
+ res += (char)(kUtf8Limits[numAdds - 1] + (value >> (6 * numAdds)));
+ do
+ {
+ numAdds--;
+ res += (char)(0x80 + ((value >> (6 * numAdds)) & 0x3F));
+ // destPos++;
+ }
+ while (numAdds != 0);
+
+ // AddToUtf8(res, c);
+ }
+}
+
+#endif
+
+void CInArchive::ReadString2_Raw(UInt32 pos)
+{
+ Raw_AString.Empty();
+ Raw_UString.Empty();
+ if ((Int32)pos < 0)
+ Add_LangStr(Raw_AString, (UInt32)-((Int32)pos + 1));
+ else if (pos >= NumStringChars)
+ {
+ Raw_AString += kErrorStr;
+ // UIntToString(Raw_AString, pos);
+ }
+ else
+ {
+ if (IsUnicode)
+ GetNsisString_Unicode_Raw(_data + _stringsPos + pos * 2);
+ else
+ GetNsisString_Raw(_data + _stringsPos + pos);
+ return;
+ }
+ Raw_UString = Raw_AString.Ptr();
+}
+
+bool CInArchive::IsGoodString(UInt32 param) const
+{
+ if (param >= NumStringChars)
+ return false;
+ if (param == 0)
+ return true;
+ const Byte *p = _data + _stringsPos;
+ unsigned c;
+ if (IsUnicode)
+ c = Get16(p + param * 2 - 2);
+ else
+ c = p[param - 1];
+ // some files have '\\' character before string?
+ return (c == 0 || c == '\\');
+}
+
+bool CInArchive::AreTwoParamStringsEqual(UInt32 param1, UInt32 param2) const
+{
+ if (param1 == param2)
+ return true;
+
+ /* NSIS-3.0a1 probably contains bug, so it can use 2 different strings
+ with same content. So we check real string also.
+ Also it's possible to check identical postfix parts of strings. */
+
+ if (param1 >= NumStringChars ||
+ param2 >= NumStringChars)
+ return false;
+
+ const Byte *p = _data + _stringsPos;
+
+ if (IsUnicode)
+ {
+ const Byte *p1 = p + param1 * 2;
+ const Byte *p2 = p + param2 * 2;
+ for (;;)
+ {
+ UInt16 c = Get16(p1);
+ if (c != Get16(p2))
+ return false;
+ if (c == 0)
+ return true;
+ p1 += 2;
+ p2 += 2;
+ }
+ }
+ else
+ {
+ const Byte *p1 = p + param1;
+ const Byte *p2 = p + param2;
+ for (;;)
+ {
+ Byte c = *p1++;
+ if (c != *p2++)
+ return false;
+ if (c == 0)
+ return true;
+ }
+ }
+}
+
+#ifdef NSIS_SCRIPT
+
+UInt32 CInArchive::GetNumUsedVars() const
+{
+ UInt32 numUsedVars = 0;
+ const Byte *data = (const Byte *)_data + _stringsPos;
+ unsigned npi = 0;
+ for (UInt32 i = 0; i < NumStringChars;)
+ {
+ bool process = true;
+ if (npi < noParseStringIndexes.Size() && noParseStringIndexes[npi] == i)
+ {
+ process = false;
+ npi++;
+ }
+
+ if (IsUnicode)
+ {
+ if (IsPark())
+ {
+ for (;;)
+ {
+ unsigned c = Get16(data + i * 2);
+ i++;
+ if (c == 0)
+ break;
+ if (IS_PARK_SPEC_CHAR(c))
+ {
+ UInt32 n = Get16(data + i * 2);
+ i++;
+ if (n == 0)
+ break;
+ if (process && c == PARK_CODE_VAR)
+ {
+ CONVERT_NUMBER_PARK(n);
+ n++;
+ if (numUsedVars < n)
+ numUsedVars = n;
+ }
+ }
+ }
+ }
+ else // NSIS-3 Unicode
+ {
+ for (;;)
+ {
+ unsigned c = Get16(data + i * 2);
+ i++;
+ if (c == 0)
+ break;
+ if (c > NS_3_CODE_SKIP)
+ continue;
+ UInt32 n = Get16(data + i * 2);
+ i++;
+ if (n == 0)
+ break;
+ if (process && c == NS_3_CODE_VAR)
+ {
+ CONVERT_NUMBER_NS_3_UNICODE(n);
+ n++;
+ if (numUsedVars < n)
+ numUsedVars = n;
+ }
+ }
+ }
+ }
+ else // not Unicode (ANSI)
+ {
+ if (NsisType != k_NsisType_Nsis3)
+ {
+ for (;;)
+ {
+ Byte c = data[i++];
+ if (c == 0)
+ break;
+ if (IS_NS_SPEC_CHAR(c))
+ {
+ Byte c0 = data[i++];
+ if (c0 == 0)
+ break;
+ if (c == NS_CODE_SKIP)
+ continue;
+ Byte c1 = data[i++];
+ if (c1 == 0)
+ break;
+ if (process && c == NS_CODE_VAR)
+ {
+ UInt32 n = DECODE_NUMBER_FROM_2_CHARS(c0, c1);
+ n++;
+ if (numUsedVars < n)
+ numUsedVars = n;
+ }
+ }
+ }
+ }
+ else
+ {
+ // NSIS-3 ANSI
+ for (;;)
+ {
+ Byte c = data[i++];
+ if (c == 0)
+ break;
+ if (c > NS_3_CODE_SKIP)
+ continue;
+
+ Byte c0 = data[i++];
+ if (c0 == 0)
+ break;
+ if (c == NS_3_CODE_SKIP)
+ continue;
+ Byte c1 = data[i++];
+ if (c1 == 0)
+ break;
+ if (process && c == NS_3_CODE_VAR)
+ {
+ UInt32 n = DECODE_NUMBER_FROM_2_CHARS(c0, c1);
+ n++;
+ if (numUsedVars < n)
+ numUsedVars = n;
+ }
+ }
+ }
+ }
+ }
+ return numUsedVars;
+}
+
+void CInArchive::ReadString2(AString &s, UInt32 pos)
+{
+ if ((Int32)pos < 0)
+ {
+ Add_LangStr(s, (UInt32)-((Int32)pos + 1));
+ return;
+ }
+
+ if (pos >= NumStringChars)
+ {
+ s += kErrorStr;
+ // UIntToString(s, pos);
+ return;
+ }
+
+ #ifdef NSIS_SCRIPT
+ strUsed[pos] = 1;
+ #endif
+
+ if (IsUnicode)
+ GetNsisString_Unicode(s, _data + _stringsPos + pos * 2);
+ else
+ GetNsisString(s, _data + _stringsPos + pos);
+}
+
+#endif
+
+#ifdef NSIS_SCRIPT
+
+// #define DEL_DIR 1
+#define DEL_RECURSE 2
+#define DEL_REBOOT 4
+// #define DEL_SIMPLE 8
+
+void CInArchive::AddRegRoot(UInt32 val)
+{
+ Space();
+ const char *s;
+ switch (val)
+ {
+ case 0: s = "SHCTX"; break;
+ case 0x80000000: s = "HKCR"; break;
+ case 0x80000001: s = "HKCU"; break;
+ case 0x80000002: s = "HKLM"; break;
+ case 0x80000003: s = "HKU"; break;
+ case 0x80000004: s = "HKPD"; break;
+ case 0x80000005: s = "HKCC"; break;
+ case 0x80000006: s = "HKDD"; break;
+ case 0x80000050: s = "HKPT"; break;
+ case 0x80000060: s = "HKPN"; break;
+ default:
+ // Script += " RRRRR ";
+ // throw 1;
+ Add_Hex(Script, val); return;
+ }
+ Script += s;
+}
+
+static const char * const g_WinAttrib[] =
+{
+ "READONLY"
+ , "HIDDEN"
+ , "SYSTEM"
+ , NULL
+ , "DIRECTORY"
+ , "ARCHIVE"
+ , "DEVICE"
+ , "NORMAL"
+ , "TEMPORARY"
+ , "SPARSE_FILE"
+ , "REPARSE_POINT"
+ , "COMPRESSED"
+ , "OFFLINE"
+ , "NOT_CONTENT_INDEXED"
+ , "ENCRYPTED"
+ , NULL
+ , "VIRTUAL"
+};
+
+#define FLAGS_DELIMITER '|'
+
+static void FlagsToString2(CDynLimBuf &s, const char * const *table, unsigned num, UInt32 flags)
+{
+ bool filled = false;
+ for (unsigned i = 0; i < num; i++)
+ {
+ UInt32 f = (UInt32)1 << i;
+ if ((flags & f) != 0)
+ {
+ const char *name = table[i];
+ if (name)
+ {
+ if (filled)
+ s += FLAGS_DELIMITER;
+ filled = true;
+ s += name;
+ flags &= ~f;
+ }
+ }
+ }
+ if (flags != 0)
+ {
+ if (filled)
+ s += FLAGS_DELIMITER;
+ Add_Hex(s, flags);
+ }
+}
+
+static bool DoesNeedQuotes(const char *s)
+{
+ {
+ char c = s[0];
+ if (c == 0 || c == '#' || c == ';' || (c == '/' && s[1] == '*'))
+ return true;
+ }
+ for (;;)
+ {
+ char c = *s++;
+ if (c == 0)
+ return false;
+ if (c == ' ')
+ return true;
+ }
+}
+
+void CInArchive::Add_QuStr(const AString &s)
+{
+ bool needQuotes = DoesNeedQuotes(s);
+ if (needQuotes)
+ Script += '\"';
+ Script += s;
+ if (needQuotes)
+ Script += '\"';
+}
+
+void CInArchive::SpaceQuStr(const AString &s)
+{
+ Space();
+ Add_QuStr(s);
+}
+
+void CInArchive::AddParam(UInt32 pos)
+{
+ _tempString.Empty();
+ ReadString2(_tempString, pos);
+ SpaceQuStr(_tempString);
+}
+
+void CInArchive::AddParams(const UInt32 *params, unsigned num)
+{
+ for (unsigned i = 0; i < num; i++)
+ AddParam(params[i]);
+}
+
+void CInArchive::AddOptionalParam(UInt32 pos)
+{
+ if (pos != 0)
+ AddParam(pos);
+}
+
+static unsigned GetNumParams(const UInt32 *params, unsigned num)
+{
+ for (; num > 0 && params[num - 1] == 0; num--);
+ return num;
+}
+
+void CInArchive::AddOptionalParams(const UInt32 *params, unsigned num)
+{
+ AddParams(params, GetNumParams(params, num));
+}
+
+
+static const UInt32 CMD_REF_Goto = (1 << 0);
+static const UInt32 CMD_REF_Call = (1 << 1);
+static const UInt32 CMD_REF_Pre = (1 << 2);
+static const UInt32 CMD_REF_Show = (1 << 3);
+static const UInt32 CMD_REF_Leave = (1 << 4);
+static const UInt32 CMD_REF_OnFunc = (1 << 5);
+static const UInt32 CMD_REF_Section = (1 << 6);
+static const UInt32 CMD_REF_InitPluginDir = (1 << 7);
+// static const UInt32 CMD_REF_Creator = (1 << 5); // CMD_REF_Pre is used instead
+static const unsigned CMD_REF_OnFunc_NumShifts = 28; // it uses for onFunc too
+static const unsigned CMD_REF_Page_NumShifts = 16; // it uses for onFunc too
+static const UInt32 CMD_REF_Page_Mask = 0x0FFF0000;
+static const UInt32 CMD_REF_OnFunc_Mask = 0xF0000000;
+
+inline bool IsPageFunc(UInt32 flag)
+{
+ return (flag & (CMD_REF_Pre | CMD_REF_Show | CMD_REF_Leave)) != 0;
+}
+
+inline bool IsFunc(UInt32 flag)
+{
+ // return (flag & (CMD_REF_Pre | CMD_REF_Show | CMD_REF_Leave | CMD_REF_OnFunc)) != 0;
+ return (flag & (CMD_REF_Call | CMD_REF_Pre | CMD_REF_Show | CMD_REF_Leave | CMD_REF_OnFunc)) != 0;
+}
+
+inline bool IsProbablyEndOfFunc(UInt32 flag)
+{
+ return (flag != 0 && flag != CMD_REF_Goto);
+}
+
+static const char * const kOnFunc[] =
+{
+ "Init"
+ , "InstSuccess"
+ , "InstFailed"
+ , "UserAbort"
+ , "GUIInit"
+ , "GUIEnd"
+ , "MouseOverSection"
+ , "VerifyInstDir"
+ , "SelChange"
+ , "RebootFailed"
+};
+
+void CInArchive::Add_FuncName(const UInt32 *labels, UInt32 index)
+{
+ UInt32 mask = labels[index];
+ if (mask & CMD_REF_OnFunc)
+ {
+ Script += ".on";
+ Script += kOnFunc[labels[index] >> CMD_REF_OnFunc_NumShifts];
+ }
+ else if (mask & CMD_REF_InitPluginDir)
+ {
+ /*
+ if (!IsInstaller)
+ Script += "un."
+ */
+ Script += "Initialize_____Plugins";
+ }
+ else
+ {
+ Script += "func_";
+ Add_UInt(index);
+ }
+}
+
+void CInArchive::AddParam_Func(const UInt32 *labels, UInt32 index)
+{
+ Space();
+ if ((Int32)index >= 0)
+ Add_FuncName(labels, index);
+ else
+ AddQuotes();
+}
+
+
+void CInArchive::Add_LabelName(UInt32 index)
+{
+ Script += "label_";
+ Add_UInt(index);
+}
+
+// param != 0
+void CInArchive::Add_GotoVar(UInt32 param)
+{
+ Space();
+ if ((Int32)param < 0)
+ Add_Var((UInt32)-((Int32)param + 1));
+ else
+ Add_LabelName(param - 1);
+}
+
+void CInArchive::Add_GotoVar1(UInt32 param)
+{
+ if (param == 0)
+ Script += " 0";
+ else
+ Add_GotoVar(param);
+}
+
+void CInArchive::Add_GotoVars2(const UInt32 *params)
+{
+ Add_GotoVar1(params[0]);
+ if (params[1] != 0)
+ Add_GotoVar(params[1]);
+}
+
+static bool NoLabels(const UInt32 *labels, UInt32 num)
+{
+ for (UInt32 i = 0; i < num; i++)
+ if (labels[i] != 0)
+ return false;
+ return true;
+}
+
+static const char * const k_REBOOTOK = " /REBOOTOK";
+
+#define Z7_NSIS_WIN_MB_ABORTRETRYIGNORE 2
+#define Z7_NSIS_WIN_MB_RETRYCANCEL 5
+
+static const char * const k_MB_Buttons[] =
+{
+ "OK"
+ , "OKCANCEL"
+ , "ABORTRETRYIGNORE"
+ , "YESNOCANCEL"
+ , "YESNO"
+ , "RETRYCANCEL"
+ , "CANCELTRYCONTINUE"
+};
+
+#define Z7_NSIS_WIN_MB_ICONSTOP (1 << 4)
+
+static const char * const k_MB_Icons[] =
+{
+ NULL
+ , "ICONSTOP"
+ , "ICONQUESTION"
+ , "ICONEXCLAMATION"
+ , "ICONINFORMATION"
+};
+
+static const char * const k_MB_Flags[] =
+{
+ "HELP"
+ , "NOFOCUS"
+ , "SETFOREGROUND"
+ , "DEFAULT_DESKTOP_ONLY"
+ , "TOPMOST"
+ , "RIGHT"
+ , "RTLREADING"
+ // , "SERVICE_NOTIFICATION" // unsupported. That bit is used for NSIS purposes
+};
+
+#define Z7_NSIS_WIN_IDCANCEL 2
+#define Z7_NSIS_WIN_IDIGNORE 5
+
+static const char * const k_Button_IDs[] =
+{
+ "0"
+ , "IDOK"
+ , "IDCANCEL"
+ , "IDABORT"
+ , "IDRETRY"
+ , "IDIGNORE"
+ , "IDYES"
+ , "IDNO"
+ , "IDCLOSE"
+ , "IDHELP"
+ , "IDTRYAGAIN"
+ , "IDCONTINUE"
+};
+
+void CInArchive::Add_ButtonID(UInt32 buttonID)
+{
+ Space();
+ if (buttonID < Z7_ARRAY_SIZE(k_Button_IDs))
+ Script += k_Button_IDs[buttonID];
+ else
+ {
+ Script += "Button_";
+ Add_UInt(buttonID);
+ }
+}
+
+bool CInArchive::IsDirectString_Equal(UInt32 offset, const char *s) const
+{
+ if (offset >= NumStringChars)
+ return false;
+ if (IsUnicode)
+ return AreStringsEqual_16and8(_data + _stringsPos + offset * 2, s);
+ else
+ return strcmp((const char *)(const Byte *)_data + _stringsPos + offset, s) == 0;
+}
+
+static bool StringToUInt32(const char *s, UInt32 &res)
+{
+ const char *end;
+ if (s[0] == '0' && (s[1] == 'x' || s[1] == 'X'))
+ res = ConvertHexStringToUInt32(s + 2, &end);
+ else
+ res = ConvertStringToUInt32(s, &end);
+ return (*end == 0);
+}
+
+static const unsigned k_CtlColors32_Size = 24;
+static const unsigned k_CtlColors64_Size = 28;
+
+#define GET_CtlColors_SIZE(is64) ((is64) ? k_CtlColors64_Size : k_CtlColors32_Size)
+
+struct CNsis_CtlColors
+{
+ UInt32 text; // COLORREF
+ UInt32 bkc; // COLORREF
+ UInt32 lbStyle;
+ UInt32 bkb; // HBRUSH
+ Int32 bkmode;
+ Int32 flags;
+ UInt32 bkb_hi32;
+
+ void Parse(const Byte *p, bool is64);
+};
+
+void CNsis_CtlColors::Parse(const Byte *p, bool is64)
+{
+ text = Get32(p);
+ bkc = Get32(p + 4);
+ if (is64)
+ {
+ bkb = Get32(p + 8);
+ bkb_hi32 = Get32(p + 12);
+ lbStyle = Get32(p + 16);
+ p += 4;
+ }
+ else
+ {
+ lbStyle = Get32(p + 8);
+ bkb = Get32(p + 12);
+ }
+ bkmode = (Int32)Get32(p + 16);
+ flags = (Int32)Get32(p + 20);
+}
+
+// Win32 constants
+#define Z7_NSIS_WIN_TRANSPARENT 1
+// #define Z7_NSIS_WIN_OPAQUE 2
+
+// text/bg colors
+#define kColorsFlags_TEXT 1
+#define kColorsFlags_TEXT_SYS 2
+#define kColorsFlags_BK 4
+#define kColorsFlags_BK_SYS 8
+#define kColorsFlags_BKB 16
+
+void CInArchive::Add_Color2(UInt32 v)
+{
+ v = ((v & 0xFF) << 16) | (v & 0xFF00) | ((v >> 16) & 0xFF);
+ char sz[32];
+ for (int i = 5; i >= 0; i--)
+ {
+ unsigned t = v & 0xF;
+ v >>= 4;
+ sz[i] = (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))));
+ }
+ sz[6] = 0;
+ Script += sz;
+}
+
+void CInArchive::Add_ColorParam(UInt32 v)
+{
+ Space();
+ Add_Color2(v);
+}
+
+void CInArchive::Add_Color(UInt32 v)
+{
+ Script += "0x";
+ Add_Color2(v);
+}
+
+#define Z7_NSIS_WIN_SW_HIDE 0
+#define Z7_NSIS_WIN_SW_SHOWNORMAL 1
+
+#define Z7_NSIS_WIN_SW_SHOWMINIMIZED 2
+#define Z7_NSIS_WIN_SW_SHOWMINNOACTIVE 7
+#define Z7_NSIS_WIN_SW_SHOWNA 8
+
+static const char * const kShowWindow_Commands[] =
+{
+ "HIDE"
+ , "SHOWNORMAL" // "NORMAL"
+ , "SHOWMINIMIZED"
+ , "SHOWMAXIMIZED" // "MAXIMIZE"
+ , "SHOWNOACTIVATE"
+ , "SHOW"
+ , "MINIMIZE"
+ , "SHOWMINNOACTIVE"
+ , "SHOWNA"
+ , "RESTORE"
+ , "SHOWDEFAULT"
+ , "FORCEMINIMIZE" // "MAX"
+};
+
+static void Add_ShowWindow_Cmd_2(AString &s, UInt32 cmd)
+{
+ if (cmd < Z7_ARRAY_SIZE(kShowWindow_Commands))
+ {
+ s += "SW_";
+ s += kShowWindow_Commands[cmd];
+ }
+ else
+ UIntToString(s, cmd);
+}
+
+void CInArchive::Add_ShowWindow_Cmd(UInt32 cmd)
+{
+ if (cmd < Z7_ARRAY_SIZE(kShowWindow_Commands))
+ {
+ Script += "SW_";
+ Script += kShowWindow_Commands[cmd];
+ }
+ else
+ Add_UInt(cmd);
+}
+
+void CInArchive::Add_TypeFromList(const char * const *table, unsigned tableSize, UInt32 type)
+{
+ if (type < tableSize)
+ Script += table[type];
+ else
+ {
+ Script += '_';
+ Add_UInt(type);
+ }
+}
+
+#define ADD_TYPE_FROM_LIST(table, type) Add_TypeFromList(table, Z7_ARRAY_SIZE(table), type)
+
+enum
+{
+ k_ExecFlags_AutoClose,
+ k_ExecFlags_ShellVarContext,
+ k_ExecFlags_Errors,
+ k_ExecFlags_Abort,
+ k_ExecFlags_RebootFlag,
+ k_ExecFlags_reboot_called,
+ k_ExecFlags_cur_insttype,
+ k_ExecFlags_plugin_api_version,
+ k_ExecFlags_Silent,
+ k_ExecFlags_InstDirError,
+ k_ExecFlags_rtl,
+ k_ExecFlags_ErrorLevel,
+ k_ExecFlags_RegView,
+ k_ExecFlags_DetailsPrint = 13
+};
+
+// Names for NSIS exec_flags_t structure vars
+static const char * const kExecFlags_VarsNames[] =
+{
+ "AutoClose" // autoclose;
+ , "ShellVarContext" // all_user_var;
+ , "Errors" // exec_error;
+ , "Abort" // abort;
+ , "RebootFlag" // exec_reboot; // NSIS_SUPPORT_REBOOT
+ , "reboot_called" // reboot_called; // NSIS_SUPPORT_REBOOT
+ , "cur_insttype" // XXX_cur_insttype; // depreacted
+ , "plugin_api_version" // plugin_api_version; // see NSISPIAPIVER_CURR
+ // used to be XXX_insttype_changed
+ , "Silent" // silent; // NSIS_CONFIG_SILENT_SUPPORT
+ , "InstDirError" // instdir_error;
+ , "rtl" // rtl;
+ , "ErrorLevel" // errlvl;
+ , "RegView" // alter_reg_view;
+ , "DetailsPrint" // status_update;
+};
+
+void CInArchive::Add_ExecFlags(UInt32 flagsType)
+{
+ ADD_TYPE_FROM_LIST(kExecFlags_VarsNames, flagsType);
+}
+
+
+// ---------- Page ----------
+
+// page flags
+#define PF_CANCEL_ENABLE 4
+#define PF_LICENSE_FORCE_SELECTION 32
+#define PF_LICENSE_NO_FORCE_SELECTION 64
+#define PF_PAGE_EX 512
+#define PF_DIR_NO_BTN_DISABLE 1024
+/*
+#define PF_LICENSE_SELECTED 1
+#define PF_NEXT_ENABLE 2
+#define PF_BACK_SHOW 8
+#define PF_LICENSE_STREAM 16
+#define PF_NO_NEXT_FOCUS 128
+#define PF_BACK_ENABLE 256
+*/
+
+// page window proc
+enum
+{
+ PWP_LICENSE,
+ PWP_SELCOM,
+ PWP_DIR,
+ PWP_INSTFILES,
+ PWP_UNINST,
+ PWP_COMPLETED,
+ PWP_CUSTOM
+};
+
+static const char * const kPageTypes[] =
+{
+ "license"
+ , "components"
+ , "directory"
+ , "instfiles"
+ , "uninstConfirm"
+ , "COMPLETED"
+ , "custom"
+};
+
+#define SET_FUNC_REF(x, flag) if ((Int32)(x) >= 0 && (x) < bh.Num) \
+ { labels[x] = (labels[x] & ~CMD_REF_Page_Mask) | ((flag) | (pageIndex << CMD_REF_Page_NumShifts)); }
+
+// #define IDD_LICENSE 102
+#define IDD_LICENSE_FSRB 108
+#define IDD_LICENSE_FSCB 109
+
+void CInArchive::AddPageOption1(UInt32 param, const char *name)
+{
+ if (param == 0)
+ return;
+ TabString(name);
+ AddParam(param);
+ NewLine();
+}
+
+void CInArchive::AddPageOption(const UInt32 *params, unsigned num, const char *name)
+{
+ num = GetNumParams(params, num);
+ if (num == 0)
+ return;
+ TabString(name);
+ AddParams(params, num);
+ NewLine();
+}
+
+void CInArchive::Separator()
+{
+ AddLF();
+ AddCommentAndString("--------------------");
+ AddLF();
+}
+
+void CInArchive::Space()
+{
+ Script += ' ';
+}
+
+void CInArchive::Tab()
+{
+ Script += " ";
+}
+
+void CInArchive::Tab(bool commented)
+{
+ Script += commented ? " ; " : " ";
+}
+
+void CInArchive::BigSpaceComment()
+{
+ Script += " ; ";
+}
+
+void CInArchive::SmallSpaceComment()
+{
+ Script += " ; ";
+}
+
+void CInArchive::AddCommentAndString(const char *s)
+{
+ Script += "; ";
+ Script += s;
+}
+
+void CInArchive::AddError(const char *s)
+{
+ BigSpaceComment();
+ Script += "!!! ERROR: ";
+ Script += s;
+}
+
+void CInArchive::AddErrorLF(const char *s)
+{
+ AddError(s);
+ AddLF();
+}
+
+void CInArchive::CommentOpen()
+{
+ AddStringLF("/*");
+}
+
+void CInArchive::CommentClose()
+{
+ AddStringLF("*/");
+}
+
+void CInArchive::AddLF()
+{
+ Script += CR_LF;
+}
+
+void CInArchive::AddQuotes()
+{
+ Script += "\"\"";
+}
+
+void CInArchive::TabString(const char *s)
+{
+ Tab();
+ Script += s;
+}
+
+void CInArchive::AddStringLF(const char *s)
+{
+ Script += s;
+ AddLF();
+}
+
+// ---------- Section ----------
+
+static const char * const kSection_VarsNames[] =
+{
+ "Text"
+ , "InstTypes"
+ , "Flags"
+ , "Code"
+ , "CodeSize"
+ , "Size" // size in KB
+};
+
+void CInArchive::Add_SectOp(UInt32 opType)
+{
+ ADD_TYPE_FROM_LIST(kSection_VarsNames, opType);
+}
+
+void CSection::Parse(const Byte *p)
+{
+ Name = Get32(p);
+ InstallTypes = Get32(p + 4);
+ Flags = Get32(p + 8);
+ StartCmdIndex = Get32(p + 12);
+ NumCommands = Get32(p + 16);
+ SizeKB = Get32(p + 20);
+}
+
+// used for section->flags
+#define SF_SELECTED (1 << 0)
+#define SF_SECGRP (1 << 1)
+#define SF_SECGRPEND (1 << 2)
+#define SF_BOLD (1 << 3)
+#define SF_RO (1 << 4)
+#define SF_EXPAND (1 << 5)
+/*
+#define SF_PSELECTED (1 << 6)
+#define SF_TOGGLED (1 << 7)
+#define SF_NAMECHG (1 << 8)
+*/
+
+bool CInArchive::PrintSectionBegin(const CSection &sect, unsigned index)
+{
+ AString name;
+ if (sect.Flags & SF_BOLD)
+ name += '!';
+ AString s2;
+ ReadString2(s2, sect.Name);
+ if (!IsInstaller)
+ {
+ if (!StringsAreEqualNoCase_Ascii(s2, "uninstall"))
+ name += "un.";
+ }
+ name += s2;
+
+ if (sect.Flags & SF_SECGRPEND)
+ {
+ AddStringLF("SectionGroupEnd");
+ return true;
+ }
+
+ if (sect.Flags & SF_SECGRP)
+ {
+ Script += "SectionGroup";
+ if (sect.Flags & SF_EXPAND)
+ Script += " /e";
+ SpaceQuStr(name);
+ Script += " ; Section";
+ AddParam_UInt(index);
+ NewLine();
+ return true;
+ }
+
+ Script += "Section";
+ if ((sect.Flags & SF_SELECTED) == 0)
+ Script += " /o";
+ if (!name.IsEmpty())
+ SpaceQuStr(name);
+
+ /*
+ if (!name.IsEmpty())
+ Script += ' ';
+ else
+ */
+ SmallSpaceComment();
+ Script += "Section_";
+ Add_UInt(index);
+
+ /*
+ Script += " ; flags = ";
+ Add_Hex(Script, sect.Flags);
+ */
+
+ NewLine();
+
+ if (sect.SizeKB != 0)
+ {
+ // probably we must show AddSize, only if there is additional size.
+ Tab();
+ AddCommentAndString("AddSize");
+ AddParam_UInt(sect.SizeKB);
+ AddLF();
+ }
+
+ bool needSectionIn =
+ (sect.Name != 0 && sect.InstallTypes != 0) ||
+ (sect.Name == 0 && sect.InstallTypes != 0xFFFFFFFF);
+ if (needSectionIn || (sect.Flags & SF_RO) != 0)
+ {
+ TabString("SectionIn");
+ UInt32 instTypes = sect.InstallTypes;
+ for (unsigned i = 0; i < 32; i++, instTypes >>= 1)
+ if ((instTypes & 1) != 0)
+ {
+ AddParam_UInt(i + 1);
+ }
+ if ((sect.Flags & SF_RO) != 0)
+ Script += " RO";
+ AddLF();
+ }
+ return false;
+}
+
+void CInArchive::PrintSectionEnd()
+{
+ AddStringLF("SectionEnd");
+ AddLF();
+}
+
+// static const unsigned kOnFuncShift = 4;
+
+void CInArchive::ClearLangComment()
+{
+ langStrIDs.Clear();
+}
+
+void CInArchive::PrintNumComment(const char *name, UInt32 value)
+{
+ // size_t len = Script.Len();
+ AddCommentAndString(name);
+ Script += ": ";
+ Add_UInt(value);
+ AddLF();
+ /*
+ len = Script.Len() - len;
+ char sz[16];
+ ConvertUInt32ToString(value, sz);
+ len += MyStringLen(sz);
+ for (; len < 20; len++)
+ Space();
+ AddStringLF(sz);
+ */
+}
+
+
+void CInArchive::NewLine()
+{
+ if (!langStrIDs.IsEmpty())
+ {
+ BigSpaceComment();
+ for (unsigned i = 0; i < langStrIDs.Size() && i < 20; i++)
+ {
+ /*
+ if (i != 0)
+ Script += ' ';
+ */
+ UInt32 langStr = langStrIDs[i];
+ if (langStr >= _numLangStrings)
+ {
+ AddError("langStr");
+ break;
+ }
+ UInt32 param = Get32(_mainLang + langStr * 4);
+ if (param != 0)
+ AddParam(param);
+ }
+ ClearLangComment();
+ }
+ AddLF();
+}
+
+static const UInt32 kPageSize = 16 * 4;
+
+static const char * const k_SetOverwrite_Modes[] =
+{
+ "on"
+ , "off"
+ , "try"
+ , "ifnewer"
+ , "ifdiff"
+ // "lastused"
+};
+
+
+void CInArchive::MessageBox_MB_Part(UInt32 param)
+{
+ {
+ UInt32 v = param & 0xF;
+ Script += " MB_";
+ if (v < Z7_ARRAY_SIZE(k_MB_Buttons))
+ Script += k_MB_Buttons[v];
+ else
+ {
+ Script += "Buttons_";
+ Add_UInt(v);
+ }
+ }
+ {
+ UInt32 icon = (param >> 4) & 0x7;
+ if (icon != 0)
+ {
+ Script += "|MB_";
+ if (icon < Z7_ARRAY_SIZE(k_MB_Icons) && k_MB_Icons[icon])
+ Script += k_MB_Icons[icon];
+ else
+ {
+ Script += "Icon_";
+ Add_UInt(icon);
+ }
+ }
+ }
+ if ((param & 0x80) != 0)
+ Script += "|MB_USERICON";
+ {
+ UInt32 defButton = (param >> 8) & 0xF;
+ if (defButton != 0)
+ {
+ Script += "|MB_DEFBUTTON";
+ Add_UInt(defButton + 1);
+ }
+ }
+ {
+ UInt32 modal = (param >> 12) & 0x3;
+ if (modal == 1) Script += "|MB_SYSTEMMODAL";
+ else if (modal == 2) Script += "|MB_TASKMODAL";
+ else if (modal == 3) Script += "|0x3000";
+ UInt32 flags = (param >> 14);
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_MB_Flags); i++)
+ if ((flags & (1 << i)) != 0)
+ {
+ Script += "|MB_";
+ Script += k_MB_Flags[i];
+ }
+ }
+}
+
+#define GET_CMD_PARAM(ppp, index) Get32((ppp) + 4 + (index) * 4)
+
+static const Byte k_InitPluginDir_Commands[] =
+ { 13, 26, 31, 13, 19, 21, 11, 14, 25, 31, 1, 22, 4, 1 };
+
+bool CInArchive::CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands)
+{
+ for (UInt32 kkk = 0; kkk < numCommands; kkk++, rawCmds += kCmdSize)
+ if (GetCmd(Get32(rawCmds)) != sequence[kkk])
+ return false;
+ return true;
+}
+
+
+static const UInt32 kSectionSize_base = 6 * 4;
+// static const UInt32 kSectionSize_8bit = kSectionSize_base + 1024;
+// static const UInt32 kSectionSize_16bit = kSectionSize_base + 1024 * 2;
+// static const UInt32 kSectionSize_16bit_Big = kSectionSize_base + 8196 * 2;
+// 8196 is default string length in NSIS-Unicode since 2.37.3
+
+#endif
+
+
+static void AddString(AString &dest, const char *src)
+{
+ dest.Add_Space_if_NotEmpty();
+ dest += src;
+}
+
+AString CInArchive::GetFormatDescription() const
+{
+ AString s ("NSIS-");
+ char c;
+ if (IsPark())
+ {
+ s += "Park-";
+ c = '1';
+ if (NsisType == k_NsisType_Park2) c = '2';
+ else if (NsisType == k_NsisType_Park3) c = '3';
+ }
+ else
+ {
+ c = '2';
+ if (NsisType == k_NsisType_Nsis3)
+ c = '3';
+ }
+ s += c;
+ if (IsNsis200)
+ s += ".00";
+ else if (IsNsis225)
+ s += ".25";
+
+ if (IsUnicode)
+ AddString(s, "Unicode");
+
+ if (Is64Bit)
+ AddString(s, "64-bit");
+
+ if (LogCmdIsEnabled)
+ AddString(s, "log");
+
+ if (BadCmd >= 0)
+ {
+ AddString(s, "BadCmd=");
+ UIntToString(s, (UInt32)BadCmd);
+ }
+ return s;
+}
+
+#ifdef NSIS_SCRIPT
+
+static const unsigned kNumAdditionalParkCmds = 3;
+
+unsigned CInArchive::GetNumSupportedCommands() const
+{
+ unsigned numCmds = IsPark() ? (unsigned)kNumCmds : (unsigned)(kNumCmds) - kNumAdditionalParkCmds;
+ if (!LogCmdIsEnabled)
+ numCmds--;
+ if (!IsUnicode)
+ numCmds -= 2;
+ return numCmds;
+}
+
+#endif
+
+UInt32 CInArchive::GetCmd(UInt32 a)
+{
+ if (!IsPark())
+ {
+ if (!LogCmdIsEnabled)
+ return a;
+ if (a < EW_SECTIONSET)
+ return a;
+ if (a == EW_SECTIONSET)
+ return EW_LOG;
+ return a - 1;
+ }
+
+ if (a < EW_REGISTERDLL)
+ return a;
+ if (NsisType >= k_NsisType_Park2)
+ {
+ if (a == EW_REGISTERDLL) return EW_GETFONTVERSION;
+ a--;
+ }
+ if (NsisType >= k_NsisType_Park3)
+ {
+ if (a == EW_REGISTERDLL) return EW_GETFONTNAME;
+ a--;
+ }
+ if (a >= EW_FSEEK)
+ {
+ if (IsUnicode)
+ {
+ if (a == EW_FSEEK) return EW_FPUTWS;
+ if (a == EW_FSEEK + 1) return EW_FPUTWS + 1;
+ a -= 2;
+ }
+
+ if (a >= EW_SECTIONSET && LogCmdIsEnabled)
+ {
+ if (a == EW_SECTIONSET)
+ return EW_LOG;
+ return a - 1;
+ }
+ if (a == EW_FPUTWS)
+ return EW_FINDPROC;
+ // if (a > EW_FPUTWS) return 0;
+ }
+ return a;
+}
+
+void CInArchive::FindBadCmd(const CBlockHeader &bh, const Byte *p)
+{
+ BadCmd = -1;
+
+ for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize)
+ {
+ const UInt32 id = GetCmd(Get32(p));
+ if (id >= kNumCmds)
+ continue;
+ if (BadCmd >= 0 && id >= (unsigned)BadCmd)
+ continue;
+ unsigned i;
+ if (IsNsis3_OrHigher())
+ {
+ if (id == EW_RESERVEDOPCODE)
+ {
+ BadCmd = (int)id;
+ continue;
+ }
+ }
+ else
+ {
+ // if (id == EW_GETLABELADDR || id == EW_GETFUNCTIONADDR)
+ if (id == EW_RESERVEDOPCODE || id == EW_GETOSINFO)
+ {
+ BadCmd = (int)id;
+ continue;
+ }
+ }
+ for (i = 6; i != 0; i--)
+ {
+ const UInt32 param = Get32(p + i * 4);
+ if (param != 0)
+ break;
+ }
+ if (id == EW_FINDPROC && i == 0)
+ {
+ BadCmd = (int)id;
+ continue;
+ }
+ if (k_Commands[id].NumParams < i)
+ BadCmd = (int)id;
+ }
+}
+
+/* We calculate the number of parameters in commands to detect
+ layout of commands. It's not very good way.
+ If you know simpler and more robust way to detect Version and layout,
+ please write to 7-Zip forum */
+
+void CInArchive::DetectNsisType(const CBlockHeader &bh, const Byte *p)
+{
+ bool strongPark = false;
+ bool strongNsis = false;
+
+ if (NumStringChars > 2)
+ {
+ const Byte *strData = _data + _stringsPos;
+ if (IsUnicode)
+ {
+ UInt32 num = NumStringChars - 2;
+ for (UInt32 i = 0; i < num; i++)
+ {
+ if (Get16(strData + i * 2) == 0)
+ {
+ unsigned c2 = Get16(strData + 2 + i * 2);
+ // it can be TXT/RTF with marker char (1 or 2). so we must check next char
+ // if (c2 <= NS_3_CODE_SKIP && c2 != NS_3_CODE_SHELL)
+ if (c2 == NS_3_CODE_VAR)
+ {
+ // 18.06: fixed: is it correct ?
+ // if ((Get16(strData + 3 + i * 2) & 0x8000) != 0)
+ if ((Get16(strData + 4 + i * 2) & 0x8080) == 0x8080)
+ {
+ NsisType = k_NsisType_Nsis3;
+ strongNsis = true;
+ break;
+ }
+ }
+ }
+ }
+ if (!strongNsis)
+ {
+ NsisType = k_NsisType_Park1;
+ strongPark = true;
+ }
+ }
+ else
+ {
+ UInt32 num = NumStringChars - 2;
+ for (UInt32 i = 0; i < num; i++)
+ {
+ if (strData[i] == 0)
+ {
+ Byte c2 = strData[i + 1];
+ // it can be TXT/RTF with marker char (1 or 2). so we must check next char
+ // for marker=1 (txt)
+ if (c2 == NS_3_CODE_VAR)
+ // if (c2 <= NS_3_CODE_SKIP && c2 != NS_3_CODE_SHELL && c2 != 1)
+ {
+ if ((strData[i + 2] & 0x80) != 0)
+ {
+ // const char *p2 = (const char *)(strData + i + 1);
+ // p2 = p2;
+ NsisType = k_NsisType_Nsis3;
+ strongNsis = true;
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (NsisType == k_NsisType_Nsis2 && !IsUnicode)
+ {
+ const Byte *p2 = p;
+
+ for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p2 += kCmdSize)
+ {
+ UInt32 cmd = GetCmd(Get32(p2));
+ if (cmd != EW_GETDLGITEM &&
+ cmd != EW_ASSIGNVAR)
+ continue;
+
+ UInt32 params[kNumCommandParams];
+ for (unsigned i = 0; i < kNumCommandParams; i++)
+ params[i] = Get32(p2 + 4 + 4 * i);
+
+ if (cmd == EW_GETDLGITEM)
+ {
+ // we can use also EW_SETCTLCOLORS
+ if (IsVarStr(params[1], kVar_HWNDPARENT_225))
+ {
+ IsNsis225 = true;
+ if (params[0] == kVar_Spec_OUTDIR_225)
+ {
+ IsNsis200 = true;
+ break;
+ }
+ }
+ }
+ else // if (cmd == EW_ASSIGNVAR)
+ {
+ if (params[0] == kVar_Spec_OUTDIR_225 &&
+ params[2] == 0 &&
+ params[3] == 0 &&
+ IsVarStr(params[1], kVar_OUTDIR))
+ IsNsis225 = true;
+ }
+ }
+ }
+
+ bool parkVer_WasDetected = false;
+
+ if (!strongNsis && !IsNsis225 && !IsNsis200)
+ {
+ // it must be before FindBadCmd(bh, p);
+ unsigned mask = 0;
+
+ unsigned numInsertMax = IsUnicode ? 4 : 2;
+
+ const Byte *p2 = p;
+
+ for (UInt32 kkk = 0; kkk < bh.Num; kkk++, p2 += kCmdSize)
+ {
+ UInt32 cmd = Get32(p2); // we use original (not converted) command
+
+ if (cmd < EW_WRITEUNINSTALLER ||
+ cmd > EW_WRITEUNINSTALLER + numInsertMax)
+ continue;
+
+ UInt32 params[kNumCommandParams];
+ for (unsigned i = 0; i < kNumCommandParams; i++)
+ params[i] = Get32(p2 + 4 + 4 * i);
+
+ if (params[4] != 0 ||
+ params[5] != 0 ||
+ params[0] <= 1 ||
+ params[3] <= 1)
+ continue;
+
+ UInt32 altParam = params[3];
+ if (!IsGoodString(params[0]) ||
+ !IsGoodString(altParam))
+ continue;
+
+ UInt32 additional = 0;
+ if (GetVarIndexFinished(altParam, '\\', additional) != kVar_INSTDIR)
+ continue;
+ if (AreTwoParamStringsEqual(altParam + additional, params[0]))
+ {
+ unsigned numInserts = cmd - EW_WRITEUNINSTALLER;
+ mask |= (1 << numInserts);
+ }
+ }
+
+ if (mask == 1)
+ {
+ parkVer_WasDetected = true; // it can be original NSIS or Park-1
+ }
+ else if (mask != 0)
+ {
+ ENsisType newType = NsisType;
+ if (IsUnicode)
+ switch (mask)
+ {
+ case (1 << 3): newType = k_NsisType_Park2; break;
+ case (1 << 4): newType = k_NsisType_Park3; break;
+ }
+ else
+ switch (mask)
+ {
+ case (1 << 1): newType = k_NsisType_Park2; break;
+ case (1 << 2): newType = k_NsisType_Park3; break;
+ }
+ if (newType != NsisType)
+ {
+ parkVer_WasDetected = true;
+ NsisType = newType;
+ }
+ }
+ }
+
+ FindBadCmd(bh, p);
+
+ /*
+ if (strongNsis)
+ return;
+ */
+
+ if (BadCmd < EW_REGISTERDLL)
+ return;
+
+ /*
+ // in ANSI archive we don't check Park and log version
+ if (!IsUnicode)
+ return;
+ */
+
+ // We can support Park-ANSI archives, if we remove if (strongPark) check
+ if (strongPark && !parkVer_WasDetected)
+ {
+ if (BadCmd < EW_SECTIONSET)
+ {
+ NsisType = k_NsisType_Park3;
+ LogCmdIsEnabled = true; // version 3 is provided with log enabled
+ FindBadCmd(bh, p);
+ if (BadCmd > 0 && BadCmd < EW_SECTIONSET)
+ {
+ NsisType = k_NsisType_Park2;
+ LogCmdIsEnabled = false;
+ FindBadCmd(bh, p);
+ if (BadCmd > 0 && BadCmd < EW_SECTIONSET)
+ {
+ NsisType = k_NsisType_Park1;
+ FindBadCmd(bh, p);
+ }
+ }
+ }
+ }
+
+ if (BadCmd >= EW_SECTIONSET)
+ {
+ LogCmdIsEnabled = !LogCmdIsEnabled;
+ FindBadCmd(bh, p);
+ if (BadCmd >= EW_SECTIONSET && LogCmdIsEnabled)
+ {
+ LogCmdIsEnabled = false;
+ FindBadCmd(bh, p);
+ }
+ }
+}
+
+Int32 CInArchive::GetVarIndex(UInt32 strPos) const
+{
+ if (strPos >= NumStringChars)
+ return -1;
+
+ if (IsUnicode)
+ {
+ if (NumStringChars - strPos < 3 * 2)
+ return -1;
+ const Byte *p = _data + _stringsPos + strPos * 2;
+ unsigned code = Get16(p);
+ if (IsPark())
+ {
+ if (code != PARK_CODE_VAR)
+ return -1;
+ UInt32 n = Get16(p + 2);
+ if (n == 0)
+ return -1;
+ CONVERT_NUMBER_PARK(n);
+ return (Int32)n;
+ }
+
+ // NSIS-3
+ {
+ if (code != NS_3_CODE_VAR)
+ return -1;
+ UInt32 n = Get16(p + 2);
+ if (n == 0)
+ return -1;
+ CONVERT_NUMBER_NS_3_UNICODE(n);
+ return (Int32)n;
+ }
+ }
+
+ if (NumStringChars - strPos < 4)
+ return -1;
+
+ const Byte *p = _data + _stringsPos + strPos;
+ unsigned c = *p;
+ if (NsisType == k_NsisType_Nsis3)
+ {
+ if (c != NS_3_CODE_VAR)
+ return -1;
+ }
+ else if (c != NS_CODE_VAR)
+ return -1;
+
+ const unsigned c0 = p[1];
+ if (c0 == 0)
+ return -1;
+ const unsigned c1 = p[2];
+ if (c1 == 0)
+ return -1;
+ return (Int32)DECODE_NUMBER_FROM_2_CHARS(c0, c1);
+}
+
+Int32 CInArchive::GetVarIndex(UInt32 strPos, UInt32 &resOffset) const
+{
+ resOffset = 0;
+ Int32 varIndex = GetVarIndex(strPos);
+ if (varIndex < 0)
+ return varIndex;
+ if (IsUnicode)
+ {
+ if (NumStringChars - strPos < 2 * 2)
+ return -1;
+ resOffset = 2;
+ }
+ else
+ {
+ if (NumStringChars - strPos < 3)
+ return -1;
+ resOffset = 3;
+ }
+ return varIndex;
+}
+
+Int32 CInArchive::GetVarIndexFinished(UInt32 strPos, Byte endChar, UInt32 &resOffset) const
+{
+ resOffset = 0;
+ Int32 varIndex = GetVarIndex(strPos);
+ if (varIndex < 0)
+ return varIndex;
+ if (IsUnicode)
+ {
+ if (NumStringChars - strPos < 3 * 2)
+ return -1;
+ const Byte *p = _data + _stringsPos + strPos * 2;
+ if (Get16(p + 4) != endChar)
+ return -1;
+ resOffset = 3;
+ }
+ else
+ {
+ if (NumStringChars - strPos < 4)
+ return -1;
+ const Byte *p = _data + _stringsPos + strPos;
+ if (p[3] != endChar)
+ return -1;
+ resOffset = 4;
+ }
+ return varIndex;
+}
+
+bool CInArchive::IsVarStr(UInt32 strPos, UInt32 varIndex) const
+{
+ if (varIndex > (UInt32)0x7FFF)
+ return false;
+ UInt32 resOffset;
+ return GetVarIndexFinished(strPos, 0, resOffset) == (Int32)varIndex;
+}
+
+bool CInArchive::IsAbsolutePathVar(UInt32 strPos) const
+{
+ Int32 varIndex = GetVarIndex(strPos);
+ if (varIndex < 0)
+ return false;
+ switch (varIndex)
+ {
+ case kVar_INSTDIR:
+ case kVar_EXEDIR:
+ case kVar_TEMP:
+ case kVar_PLUGINSDIR:
+ return true;
+ }
+ return false;
+}
+
+#define IS_LETTER_CHAR(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
+
+// We use same check as in NSIS decoder
+static bool IsDrivePath(const wchar_t *s) { return IS_LETTER_CHAR(s[0]) && s[1] == ':' /* && s[2] == '\\' */ ; }
+static bool IsDrivePath(const char *s) { return IS_LETTER_CHAR(s[0]) && s[1] == ':' /* && s[2] == '\\' */ ; }
+
+static bool IsAbsolutePath(const wchar_t *s)
+{
+ return (s[0] == WCHAR_PATH_SEPARATOR && s[1] == WCHAR_PATH_SEPARATOR) || IsDrivePath(s);
+}
+
+static bool IsAbsolutePath(const char *s)
+{
+ return (s[0] == CHAR_PATH_SEPARATOR && s[1] == CHAR_PATH_SEPARATOR) || IsDrivePath(s);
+}
+
+void CInArchive::SetItemName(CItem &item, UInt32 strPos)
+{
+ ReadString2_Raw(strPos);
+ const bool isAbs = IsAbsolutePathVar(strPos);
+ if (IsUnicode)
+ {
+ item.NameU = Raw_UString;
+ if (!isAbs && !IsAbsolutePath(Raw_UString))
+ item.Prefix = (int)UPrefixes.Size() - 1;
+ }
+ else
+ {
+ item.NameA = Raw_AString;
+ if (!isAbs && !IsAbsolutePath(Raw_AString))
+ item.Prefix = (int)APrefixes.Size() - 1;
+ }
+}
+
+HRESULT CInArchive::ReadEntries(const CBlockHeader &bh)
+{
+ #ifdef NSIS_SCRIPT
+ CDynLimBuf &s = Script;
+
+ CObjArray<UInt32> labels;
+ labels.Alloc(bh.Num);
+ memset(labels, 0, bh.Num * sizeof(UInt32));
+
+ {
+ const Byte *p = _data;
+ UInt32 i;
+ for (i = 0; i < numOnFunc; i++)
+ {
+ UInt32 func = Get32(p + onFuncOffset + 4 * i);
+ if (func < bh.Num)
+ labels[func] = (labels[func] & ~CMD_REF_OnFunc_Mask) | (CMD_REF_OnFunc | (i << CMD_REF_OnFunc_NumShifts));
+ }
+ }
+
+ /*
+ {
+ for (int i = 0; i < OnFuncs.Size(); i++)
+ {
+ UInt32 address = OnFuncs[i] >> kOnFuncShift;
+ if (address < bh.Num)
+ }
+ }
+ */
+
+ if (bhPages.Num != 0)
+ {
+ Separator();
+ PrintNumComment("PAGES", bhPages.Num);
+
+ if (bhPages.Num > (1 << 12)
+ || bhPages.Offset > _size
+ || bhPages.Num * kPageSize > _size - bhPages.Offset)
+ {
+ AddErrorLF("Pages error");
+ }
+ else
+ {
+
+ AddLF();
+ const Byte *p = _data + bhPages.Offset;
+
+ for (UInt32 pageIndex = 0; pageIndex < bhPages.Num; pageIndex++, p += kPageSize)
+ {
+ UInt32 dlgID = Get32(p);
+ UInt32 wndProcID = Get32(p + 4);
+ UInt32 preFunc = Get32(p + 8);
+ UInt32 showFunc = Get32(p + 12);
+ UInt32 leaveFunc = Get32(p + 16);
+ UInt32 flags = Get32(p + 20);
+ UInt32 caption = Get32(p + 24);
+ // UInt32 back = Get32(p + 28);
+ UInt32 next = Get32(p + 32);
+ // UInt32 clickNext = Get32(p + 36);
+ // UInt32 cancel = Get32(p + 40);
+ UInt32 params[5];
+ for (int i = 0; i < 5; i++)
+ params[i] = Get32(p + 44 + 4 * i);
+
+ SET_FUNC_REF(preFunc, CMD_REF_Pre)
+ SET_FUNC_REF(showFunc, CMD_REF_Show)
+ SET_FUNC_REF(leaveFunc, CMD_REF_Leave)
+
+ if (wndProcID == PWP_COMPLETED)
+ CommentOpen();
+
+ AddCommentAndString("Page ");
+ Add_UInt(pageIndex);
+ AddLF();
+
+ if (flags & PF_PAGE_EX)
+ {
+ s += "PageEx ";
+ if (!IsInstaller)
+ s += "un.";
+ }
+ else
+ s += IsInstaller ? "Page " : "UninstPage ";
+
+ if (wndProcID < Z7_ARRAY_SIZE(kPageTypes))
+ s += kPageTypes[wndProcID];
+ else
+ Add_UInt(wndProcID);
+
+
+ bool needCallbacks = (
+ (Int32)preFunc >= 0 ||
+ (Int32)showFunc >= 0 ||
+ (Int32)leaveFunc >= 0);
+
+ if (flags & PF_PAGE_EX)
+ {
+ AddLF();
+ if (needCallbacks)
+ TabString("PageCallbacks");
+ }
+
+ if (needCallbacks)
+ {
+ AddParam_Func(labels, preFunc); // it's creator_function for PWP_CUSTOM
+ if (wndProcID != PWP_CUSTOM)
+ {
+ AddParam_Func(labels, showFunc);
+ }
+ AddParam_Func(labels, leaveFunc);
+ }
+
+ if ((flags & PF_PAGE_EX) == 0)
+ {
+ // AddOptionalParam(caption);
+ if (flags & PF_CANCEL_ENABLE)
+ s += " /ENABLECANCEL";
+ AddLF();
+ }
+ else
+ {
+ AddLF();
+ AddPageOption1(caption, "Caption");
+ }
+
+ if (wndProcID == PWP_LICENSE)
+ {
+ if ((flags & PF_LICENSE_NO_FORCE_SELECTION) != 0 ||
+ (flags & PF_LICENSE_FORCE_SELECTION) != 0)
+ {
+ TabString("LicenseForceSelection ");
+ if (flags & PF_LICENSE_NO_FORCE_SELECTION)
+ s += "off";
+ else
+ {
+ if (dlgID == IDD_LICENSE_FSCB)
+ s += "checkbox";
+ else if (dlgID == IDD_LICENSE_FSRB)
+ s += "radiobuttons";
+ else
+ Add_UInt(dlgID);
+ AddOptionalParams(params + 2, 2);
+ }
+ NewLine();
+ }
+
+ if (params[0] != 0 || next != 0)
+ {
+ TabString("LicenseText");
+ AddParam(params[0]);
+ AddOptionalParam(next);
+ NewLine();
+ }
+ if (params[1] != 0)
+ {
+ TabString("LicenseData");
+ if ((Int32)params[1] < 0)
+ AddParam(params[1]);
+ else
+ AddLicense(params[1], -1);
+ ClearLangComment();
+ NewLine();
+ }
+ }
+ else if (wndProcID == PWP_SELCOM)
+ AddPageOption(params, 3, "ComponentsText");
+ else if (wndProcID == PWP_DIR)
+ {
+ AddPageOption(params, 4, "DirText");
+ if (params[4] != 0)
+ {
+ TabString("DirVar");
+ AddParam_Var(params[4] - 1);
+ AddLF();
+ }
+ if (flags & PF_DIR_NO_BTN_DISABLE)
+ {
+ TabString("DirVerify leave");
+ AddLF();
+ }
+
+ }
+ else if (wndProcID == PWP_INSTFILES)
+ {
+ AddPageOption1(params[2], "CompletedText");
+ AddPageOption1(params[1], "DetailsButtonText");
+ }
+ else if (wndProcID == PWP_UNINST)
+ {
+ if (params[4] != 0)
+ {
+ TabString("DirVar");
+ AddParam_Var(params[4] - 1);
+ AddLF();
+ }
+ AddPageOption(params, 2, "UninstallText");
+ }
+
+ if (flags & PF_PAGE_EX)
+ {
+ s += "PageExEnd";
+ NewLine();
+ }
+ if (wndProcID == PWP_COMPLETED)
+ CommentClose();
+ NewLine();
+ }
+ }
+ }
+
+ CObjArray<CSection> Sections;
+
+ {
+ Separator();
+ PrintNumComment("SECTIONS", bhSections.Num);
+ PrintNumComment("COMMANDS", bh.Num);
+ AddLF();
+
+ if (bhSections.Num > (1 << 15)
+ // || bhSections.Offset > _size
+ // || (bhSections.Num * SectionSize > _size - bhSections.Offset)
+ )
+ {
+ AddErrorLF("Sections error");
+ }
+ else if (bhSections.Num != 0)
+ {
+ Sections.Alloc((unsigned)bhSections.Num);
+ const Byte *p = _data + bhSections.Offset;
+ for (UInt32 i = 0; i < bhSections.Num; i++, p += SectionSize)
+ {
+ CSection &section = Sections[i];
+ section.Parse(p);
+ if (section.StartCmdIndex < bh.Num)
+ labels[section.StartCmdIndex] |= CMD_REF_Section;
+ }
+ }
+ }
+
+ #endif
+
+ const Byte *p;
+ UInt32 kkk;
+
+ #ifdef NSIS_SCRIPT
+
+ p = _data + bh.Offset;
+
+ for (kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize)
+ {
+ UInt32 commandId = GetCmd(Get32(p));
+ UInt32 mask;
+ switch (commandId)
+ {
+ case EW_NOP: mask = 1 << 0; break;
+ case EW_IFFILEEXISTS: mask = 3 << 1; break;
+ case EW_IFFLAG: mask = 3 << 0; break;
+ case EW_MESSAGEBOX: mask = 5 << 3; break;
+ case EW_STRCMP: mask = 3 << 2; break;
+ case EW_INTCMP: mask = 7 << 2; break;
+ case EW_ISWINDOW: mask = 3 << 1; break;
+ case EW_CALL:
+ {
+ if (Get32(p + 4 + 4) == 1) // it's Call :Label
+ {
+ mask = 1 << 0;
+ break;
+ }
+ UInt32 param0 = Get32(p + 4);
+ if ((Int32)param0 > 0)
+ labels[param0 - 1] |= CMD_REF_Call;
+ continue;
+ }
+ default: continue;
+ }
+ for (unsigned i = 0; mask != 0; i++, mask >>= 1)
+ if (mask & 1)
+ {
+ UInt32 param = Get32(p + 4 + 4 * i);
+ if ((Int32)param > 0 && (Int32)param <= (Int32)bh.Num)
+ labels[param - 1] |= CMD_REF_Goto;
+ }
+ }
+
+ int InitPluginsDir_Start = -1;
+ int InitPluginsDir_End = -1;
+ p = _data + bh.Offset;
+ for (kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize)
+ {
+ UInt32 flg = labels[kkk];
+ /*
+ if (IsFunc(flg))
+ {
+ AddLF();
+ for (int i = 0; i < 14; i++)
+ {
+ UInt32 commandId = GetCmd(Get32(p + kCmdSize * i));
+ s += ", ";
+ UIntToString(s, commandId);
+ }
+ AddLF();
+ }
+ */
+ if (IsFunc(flg)
+ && bh.Num - kkk >= Z7_ARRAY_SIZE(k_InitPluginDir_Commands)
+ && CompareCommands(p, k_InitPluginDir_Commands, Z7_ARRAY_SIZE(k_InitPluginDir_Commands)))
+ {
+ InitPluginsDir_Start = (int)kkk;
+ InitPluginsDir_End = (int)(kkk + Z7_ARRAY_SIZE(k_InitPluginDir_Commands));
+ labels[kkk] |= CMD_REF_InitPluginDir;
+ break;
+ }
+ }
+
+ #endif
+
+ // AString prefixA_Temp;
+ // UString prefixU_Temp;
+
+
+ // const UInt32 kFindS = 158;
+
+ #ifdef NSIS_SCRIPT
+
+ UInt32 curSectionIndex = 0;
+ // UInt32 lastSectionEndCmd = 0xFFFFFFFF;
+ bool sectionIsOpen = false;
+ // int curOnFunc = 0;
+ bool onFuncIsOpen = false;
+
+ /*
+ for (unsigned yyy = 0; yyy + 3 < _data.Size(); yyy++)
+ {
+ UInt32 val = Get32(_data + yyy);
+ if (val == kFindS)
+ val = val;
+ }
+ */
+
+ UInt32 overwrite_State = 0; // "SetOverwrite on"
+ Int32 allowSkipFiles_State = -1; // -1: on, -2: off, >=0 : RAW value
+ UInt32 endCommentIndex = 0;
+
+ unsigned numSupportedCommands = GetNumSupportedCommands();
+
+ #endif
+
+ p = _data + bh.Offset;
+
+ UString spec_outdir_U;
+ AString spec_outdir_A;
+
+ UPrefixes.Add(UString("$INSTDIR"));
+ APrefixes.Add(AString("$INSTDIR"));
+
+ p = _data + bh.Offset;
+
+ unsigned spec_outdir_VarIndex = IsNsis225 ?
+ kVar_Spec_OUTDIR_225 :
+ kVar_Spec_OUTDIR;
+
+ for (kkk = 0; kkk < bh.Num; kkk++, p += kCmdSize)
+ {
+ UInt32 commandId;
+ UInt32 params[kNumCommandParams];
+ commandId = GetCmd(Get32(p));
+ {
+ for (unsigned i = 0; i < kNumCommandParams; i++)
+ {
+ params[i] = Get32(p + 4 + 4 * i);
+ /*
+ if (params[i] == kFindS)
+ i = i;
+ */
+ }
+ }
+
+ #ifdef NSIS_SCRIPT
+
+ bool IsSectionGroup = false;
+ while (curSectionIndex < bhSections.Num)
+ {
+ const CSection &sect = Sections[curSectionIndex];
+ if (sectionIsOpen)
+ {
+ if (sect.StartCmdIndex + sect.NumCommands + 1 != kkk)
+ break;
+ PrintSectionEnd();
+ sectionIsOpen = false;
+ // lastSectionEndCmd = kkk;
+ curSectionIndex++;
+ continue;
+ }
+ if (sect.StartCmdIndex != kkk)
+ break;
+ if (PrintSectionBegin(sect, curSectionIndex))
+ {
+ IsSectionGroup = true;
+ curSectionIndex++;
+ // do we need to flush prefixes in new section?
+ // FlushOutPathPrefixes();
+ }
+ else
+ sectionIsOpen = true;
+ }
+
+ /*
+ if (curOnFunc < OnFuncs.Size())
+ {
+ if ((OnFuncs[curOnFunc] >> kOnFuncShift) == kkk)
+ {
+ s += "Function .on";
+ s += kOnFunc[OnFuncs[curOnFunc++] & ((1 << kOnFuncShift) - 1)];
+ AddLF();
+ onFuncIsOpen = true;
+ }
+ }
+ */
+
+ if (labels[kkk] != 0 && labels[kkk] != CMD_REF_Section)
+ {
+ UInt32 flg = labels[kkk];
+ if (IsFunc(flg))
+ {
+ if ((int)kkk == InitPluginsDir_Start)
+ CommentOpen();
+
+ onFuncIsOpen = true;
+ s += "Function ";
+ Add_FuncName(labels, kkk);
+ if (IsPageFunc(flg))
+ {
+ BigSpaceComment();
+ s += "Page ";
+ Add_UInt((flg & CMD_REF_Page_Mask) >> CMD_REF_Page_NumShifts);
+ // if (flg & CMD_REF_Creator) s += ", Creator";
+ if (flg & CMD_REF_Leave) s += ", Leave";
+ if (flg & CMD_REF_Pre) s += ", Pre";
+ if (flg & CMD_REF_Show) s += ", Show";
+ }
+ AddLF();
+ }
+ if (flg & CMD_REF_Goto)
+ {
+ Add_LabelName(kkk);
+ s += ':';
+ AddLF();
+ }
+ }
+
+ if (commandId != EW_RET)
+ {
+ Tab(kkk < endCommentIndex);
+ }
+
+ /*
+ UInt32 originalCmd = Get32(p);
+ if (originalCmd >= EW_REGISTERDLL)
+ {
+ UIntToString(s, originalCmd);
+ s += ' ';
+ if (originalCmd != commandId)
+ {
+ UIntToString(s, commandId);
+ s += ' ';
+ }
+ }
+ */
+
+ unsigned numSkipParams = 0;
+
+ if (commandId < Z7_ARRAY_SIZE(k_Commands) && commandId < numSupportedCommands)
+ {
+ numSkipParams = k_Commands[commandId].NumParams;
+ const char *sz = k_CommandNames[commandId];
+ if (sz)
+ s += sz;
+ }
+ else
+ {
+ s += "Command";
+ Add_UInt(commandId);
+ /* We don't show wrong commands that use overlapped ids.
+ So we change commandId to big value */
+ if (commandId < (1 << 12))
+ commandId += (1 << 12);
+ }
+
+ #endif
+
+ switch (commandId)
+ {
+ case EW_CREATEDIR:
+ {
+ bool isSetOutPath = (params[1] != 0);
+
+ if (isSetOutPath)
+ {
+ UInt32 par0 = params[0];
+
+ UInt32 resOffset;
+ Int32 idx = GetVarIndex(par0, resOffset);
+ if (idx == (Int32)spec_outdir_VarIndex ||
+ idx == kVar_OUTDIR)
+ par0 += resOffset;
+
+ ReadString2_Raw(par0);
+
+ if (IsUnicode)
+ {
+ if (idx == (Int32)spec_outdir_VarIndex)
+ Raw_UString.Insert(0, spec_outdir_U);
+ else if (idx == kVar_OUTDIR)
+ Raw_UString.Insert(0, UPrefixes.Back());
+ UPrefixes.Add(Raw_UString);
+ }
+ else
+ {
+ if (idx == (Int32)spec_outdir_VarIndex)
+ Raw_AString.Insert(0, spec_outdir_A);
+ else if (idx == kVar_OUTDIR)
+ Raw_AString.Insert(0, APrefixes.Back());
+ APrefixes.Add(Raw_AString);
+ }
+ }
+
+ #ifdef NSIS_SCRIPT
+ s += isSetOutPath ? "SetOutPath" : "CreateDirectory";
+ AddParam(params[0]);
+ if (params[2] != 0) // 2.51+ & 3.0b3+
+ {
+ SmallSpaceComment();
+ s += "CreateRestrictedDirectory";
+ }
+ #endif
+
+ break;
+ }
+
+
+ case EW_ASSIGNVAR:
+ {
+ if (params[0] == spec_outdir_VarIndex)
+ {
+ spec_outdir_U.Empty();
+ spec_outdir_A.Empty();
+ if (IsVarStr(params[1], kVar_OUTDIR) &&
+ params[2] == 0 &&
+ params[3] == 0)
+ {
+ spec_outdir_U = UPrefixes.Back(); // outdir_U;
+ spec_outdir_A = APrefixes.Back(); // outdir_A;
+ }
+ }
+
+ #ifdef NSIS_SCRIPT
+
+ if (params[2] == 0 &&
+ params[3] == 0 &&
+ params[4] == 0 &&
+ params[5] == 0 &&
+ params[1] != 0 &&
+ params[1] < NumStringChars)
+ {
+ char sz[16];
+ ConvertUInt32ToString(kkk + 1, sz);
+ if (IsDirectString_Equal(params[1], sz))
+ {
+ // we suppose that it's GetCurrentAddress command
+ // but there is probability that it's StrCpy command
+ s += "GetCurrentAddress";
+ AddParam_Var(params[0]);
+ SmallSpaceComment();
+ }
+ }
+ s += "StrCpy";
+ AddParam_Var(params[0]);
+ AddParam(params[1]);
+
+ AddOptionalParams(params + 2, 2);
+
+ #endif
+
+ break;
+ }
+
+ case EW_EXTRACTFILE:
+ {
+ CItem &item = Items.AddNew();
+
+ UInt32 par1 = params[1];
+
+ SetItemName(item, par1);
+
+ item.Pos = params[2];
+ item.MTime.dwLowDateTime = params[3];
+ item.MTime.dwHighDateTime = params[4];
+
+ #ifdef NSIS_SCRIPT
+
+ {
+ UInt32 overwrite = params[0] & 0x7;
+ if (overwrite != overwrite_State)
+ {
+ s += "SetOverwrite ";
+ ADD_TYPE_FROM_LIST(k_SetOverwrite_Modes, overwrite);
+ overwrite_State = overwrite;
+ AddLF();
+ Tab(kkk < endCommentIndex);
+ }
+ }
+
+ {
+ UInt32 nsisMB = params[0] >> 3;
+ if ((Int32)nsisMB != allowSkipFiles_State)
+ {
+ UInt32 mb = nsisMB & ((1 << 20) - 1); // old/new NSIS
+ UInt32 b1 = nsisMB >> 21; // NSIS 2.06+
+ UInt32 b2 = nsisMB >> 20; // NSIS old
+ Int32 asf = (Int32)nsisMB;
+ if (mb == (Z7_NSIS_WIN_MB_ABORTRETRYIGNORE | Z7_NSIS_WIN_MB_ICONSTOP) && (b1 == Z7_NSIS_WIN_IDIGNORE || b2 == Z7_NSIS_WIN_IDIGNORE))
+ asf = -1;
+ else if (mb == (Z7_NSIS_WIN_MB_RETRYCANCEL | Z7_NSIS_WIN_MB_ICONSTOP) && (b1 == Z7_NSIS_WIN_IDCANCEL || b2 == Z7_NSIS_WIN_IDCANCEL))
+ asf = -2;
+ else
+ {
+ AddCommentAndString("AllowSkipFiles [Overwrite]: ");
+ MessageBox_MB_Part(mb);
+ if (b1 != 0)
+ {
+ s += " /SD";
+ Add_ButtonID(b1);
+ }
+ }
+ if (asf != allowSkipFiles_State)
+ {
+ if (asf < 0)
+ {
+ s += "AllowSkipFiles ";
+ s += (asf == -1) ? "on" : "off";
+ }
+ AddLF();
+ Tab(kkk < endCommentIndex);
+ }
+ allowSkipFiles_State = (Int32)nsisMB;
+ }
+ }
+
+ s += "File";
+ AddParam(params[1]);
+
+ /* params[5] contains link to LangString (negative value)
+ with NLF_FILE_ERROR or NLF_FILE_ERROR_NOIGNORE message for MessageBox.
+ We don't need to print it. */
+
+ #endif
+
+ if (IsVarStr(par1, 10)) // is $R0
+ {
+ // we parse InstallLib macro in 7-Zip installers
+ unsigned kBackOffset = 28;
+ if (kkk > 1)
+ {
+ // detect old version of InstallLib macro
+ if (Get32(p - 1 * kCmdSize) == EW_NOP) // goto command
+ kBackOffset -= 2;
+ }
+
+ if (kkk > kBackOffset)
+ {
+ const Byte *p2 = p - kBackOffset * kCmdSize;
+ UInt32 cmd = Get32(p2);
+ if (cmd == EW_ASSIGNVAR)
+ {
+ UInt32 pars[6];
+ for (int i = 0; i < 6; i++)
+ pars[i] = Get32(p2 + i * 4 + 4);
+ if (pars[0] == 10 + 4 && pars[2] == 0 && pars[3] == 0) // 10 + 4 means $R4
+ {
+ item.Prefix = -1;
+ item.NameA.Empty();
+ item.NameU.Empty();
+ SetItemName(item, pars[1]);
+ // maybe here we can restore original item name, if new name is empty
+ }
+ }
+ }
+ }
+ /* UInt32 allowIgnore = params[5]; */
+ break;
+ }
+
+ case EW_SETFILEATTRIBUTES:
+ {
+ if (kkk > 0 && Get32(p - kCmdSize) == EW_EXTRACTFILE)
+ {
+ if (params[0] == Get32(p - kCmdSize + 4 + 4 * 1)) // compare with PrevCmd.Params[1]
+ {
+ CItem &item = Items.Back();
+ item.Attrib_Defined = true;
+ item.Attrib = params[1];
+ }
+ }
+ #ifdef NSIS_SCRIPT
+ AddParam(params[0]);
+ Space();
+ FlagsToString2(s, g_WinAttrib, Z7_ARRAY_SIZE(g_WinAttrib), params[1]);
+ #endif
+ break;
+ }
+
+ case EW_WRITEUNINSTALLER:
+ {
+ /* NSIS 2.29+ writes alternative path to params[3]
+ "$INSTDIR\\" + Str(params[0])
+ NSIS installer uses alternative path, if main path
+ from params[0] is not absolute path */
+
+ const bool pathOk = (params[0] > 0) && IsGoodString(params[0]);
+
+ if (!pathOk)
+ {
+ #ifdef NSIS_SCRIPT
+ AddError("bad path");
+ #endif
+ break;
+ }
+
+ #ifdef NSIS_SCRIPT
+
+ bool altPathOk = true;
+
+ const UInt32 altParam = params[3];
+ if (altParam != 0)
+ {
+ altPathOk = false;
+ UInt32 additional = 0;
+ if (GetVarIndexFinished(altParam, '\\', additional) == kVar_INSTDIR)
+ altPathOk = AreTwoParamStringsEqual(altParam + additional, params[0]);
+ }
+
+ AddParam(params[0]);
+
+ /*
+ for (int i = 1; i < 3; i++)
+ AddParam_UInt(params[i]);
+ */
+
+ if (params[3] != 0)
+ {
+ SmallSpaceComment();
+ AddParam(params[3]);
+ }
+
+ if (!altPathOk)
+ {
+ #ifdef NSIS_SCRIPT
+ AddError("alt path error");
+ #endif
+ }
+
+ #endif
+
+ if (BadCmd >= 0 && BadCmd <= EW_WRITEUNINSTALLER)
+ {
+ /* We don't support cases with incorrect installer commands.
+ Such bad installer item can break unpacking for other items. */
+ #ifdef NSIS_SCRIPT
+ AddError("SKIP possible BadCmd");
+ #endif
+ break;
+ }
+
+ CItem &item = Items.AddNew();
+
+ SetItemName(item, params[0]);
+
+ item.Pos = params[1];
+ item.PatchSize = params[2];
+ item.IsUninstaller = true;
+ const UInt32 param3 = params[3];
+ if (param3 != 0 && item.Prefix != -1)
+ {
+ /* (item.Prefix != -1) case means that param[0] path was not absolute.
+ So we use params[3] in that case, as original nsis */
+ SetItemName(item, param3);
+ }
+ /* UNINSTALLER file doesn't use directory prefixes.
+ So we remove prefix: */
+ item.Prefix = -1;
+
+ /*
+ // we can add second time to test the code
+ CItem item2 = item;
+ item2.NameU += L'2';
+ item2.NameA += '2';
+ Items.Add(item2);
+ */
+
+ break;
+ }
+
+ #ifdef NSIS_SCRIPT
+
+ case EW_RET:
+ {
+ // bool needComment = false;
+ if (onFuncIsOpen)
+ {
+ if (kkk == bh.Num - 1 || IsProbablyEndOfFunc(labels[kkk + 1]))
+ {
+ AddStringLF("FunctionEnd");
+
+ if ((int)kkk + 1 == InitPluginsDir_End)
+ CommentClose();
+ AddLF();
+ onFuncIsOpen = false;
+ // needComment = true;
+ break;
+ }
+ }
+ // if (!needComment)
+ if (IsSectionGroup)
+ break;
+ if (sectionIsOpen)
+ {
+ const CSection &sect = Sections[curSectionIndex];
+ if (sect.StartCmdIndex + sect.NumCommands == kkk)
+ {
+ PrintSectionEnd();
+ sectionIsOpen = false;
+ curSectionIndex++;
+ break;
+ }
+
+ // needComment = true;
+ // break;
+ }
+
+ /*
+ if (needComment)
+ s += " ;";
+ */
+ TabString("Return");
+ AddLF();
+ break;
+ }
+
+ case EW_NOP:
+ {
+ if (params[0] == 0)
+ s += "Nop";
+ else
+ {
+ s += "Goto";
+ Add_GotoVar(params[0]);
+ }
+ break;
+ }
+
+ case EW_ABORT:
+ {
+ AddOptionalParam(params[0]);
+ break;
+ }
+
+ case EW_CALL:
+ {
+ if (kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_EXTRACTFILE)
+ {
+ UInt32 par1 = GET_CMD_PARAM(p + kCmdSize, 1);
+
+ UInt32 pluginPar = 0;
+
+ if (GetVarIndexFinished(par1, '\\', pluginPar) == kVar_PLUGINSDIR)
+ {
+ pluginPar += par1;
+ UInt32 commandId2 = GetCmd(Get32(p + kCmdSize * 2));
+ if (commandId2 == EW_SETFLAG || commandId2 == EW_UPDATETEXT)
+ {
+ UInt32 i;
+ for (i = kkk + 3; i < bh.Num; i++)
+ {
+ const Byte *pCmd = p + kCmdSize * (i - kkk);
+ UInt32 commandId3 = GetCmd(Get32(pCmd));
+ if (commandId3 != EW_PUSHPOP
+ || GET_CMD_PARAM(pCmd, 1) != 0
+ || GET_CMD_PARAM(pCmd, 2) != 0)
+ break;
+ }
+ if (i < bh.Num)
+ {
+ const Byte *pCmd = p + kCmdSize * (i - kkk);
+
+ // UInt32 callDll_Param = GET_CMD_PARAM(pCmd, 0);
+ // UInt32 file_Param = GET_CMD_PARAM(p + kCmdSize, 1);
+
+ if (GetCmd(Get32(pCmd)) == EW_REGISTERDLL &&
+ AreTwoParamStringsEqual(
+ GET_CMD_PARAM(pCmd, 0),
+ GET_CMD_PARAM(p + kCmdSize, 1)))
+ {
+ // params[4] = 1 means GetModuleHandle attempt before default LoadLibraryEx;
+ /// new versions of NSIS use params[4] = 1 for Plugin command
+ if (GET_CMD_PARAM(pCmd, 2) == 0
+ // && GET_CMD_PARAM(pCmd, 4) != 0
+ )
+ {
+ {
+ AString s2;
+ ReadString2(s2, pluginPar);
+ if (s2.Len() >= 4 &&
+ StringsAreEqualNoCase_Ascii(s2.RightPtr(4), ".dll"))
+ s2.DeleteFrom(s2.Len() - 4);
+ s2 += "::";
+ AString func;
+ ReadString2(func, GET_CMD_PARAM(pCmd, 1));
+ s2 += func;
+ Add_QuStr(s2);
+
+ if (GET_CMD_PARAM(pCmd, 3) == 1)
+ s += " /NOUNLOAD";
+
+ for (UInt32 j = i - 1; j >= kkk + 3; j--)
+ {
+ const Byte *pCmd2 = p + kCmdSize * (j - kkk);
+ AddParam(GET_CMD_PARAM(pCmd2, 0));
+ }
+ NewLine();
+ Tab(true);
+ endCommentIndex = i + 1;
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+ {
+ const Byte *nextCmd = p + kCmdSize;
+ UInt32 commandId2 = GetCmd(Get32(nextCmd));
+ if (commandId2 == EW_SETFLAG
+ && GET_CMD_PARAM(nextCmd, 0) == k_ExecFlags_DetailsPrint
+ && GET_CMD_PARAM(nextCmd, 2) != 0) // is "lastused"
+ // || commandId2 == EW_UPDATETEXT)
+ {
+ if ((Int32)params[0] > 0 && labels[params[0] - 1] & CMD_REF_InitPluginDir)
+ {
+ s += "InitPluginsDir";
+ AddLF();
+ Tab(true);
+ endCommentIndex = kkk + 2;
+ }
+ }
+ }
+
+ s += "Call ";
+ if ((Int32)params[0] < 0)
+ Add_Var((UInt32)-((Int32)params[0] + 1));
+ else if (params[0] == 0)
+ s += '0';
+ else
+ {
+ const UInt32 val = params[0] - 1;
+ if (params[1] == 1) // it's Call :Label
+ {
+ s += ':';
+ Add_LabelName(val);
+ }
+ else // if (params[1] == 0) // it's Call Func
+ Add_FuncName(labels, val);
+ }
+ break;
+ }
+
+ case EW_UPDATETEXT:
+ case EW_SLEEP:
+ {
+ AddParam(params[0]);
+ break;
+ }
+
+ case EW_CHDETAILSVIEW:
+ {
+ if (params[0] == Z7_NSIS_WIN_SW_SHOWNA && params[1] == Z7_NSIS_WIN_SW_HIDE) s += " show";
+ else if (params[1] == Z7_NSIS_WIN_SW_SHOWNA && params[0] == Z7_NSIS_WIN_SW_HIDE) s += " hide";
+ else
+ for (int i = 0; i < 2; i++)
+ {
+ Space();
+ Add_ShowWindow_Cmd(params[i]);
+ }
+ break;
+ }
+
+ case EW_IFFILEEXISTS:
+ {
+ AddParam(params[0]);
+ Add_GotoVars2(&params[1]);
+ break;
+ }
+
+ case EW_SETFLAG:
+ {
+ AString temp;
+ ReadString2(temp, params[1]);
+ if (params[0] == k_ExecFlags_Errors && params[2] == 0)
+ {
+ s += (temp.Len() == 1 && temp[0] == '0') ? "ClearErrors" : "SetErrors";
+ break;
+ }
+ s += "Set";
+ Add_ExecFlags(params[0]);
+
+ if (params[2] != 0)
+ {
+ s += " lastused";
+ break;
+ }
+ UInt32 v;
+ if (StringToUInt32(temp, v))
+ {
+ const char *s2 = NULL;
+ switch (params[0])
+ {
+ case k_ExecFlags_AutoClose:
+ case k_ExecFlags_RebootFlag:
+ if (v < 2) { s2 = (v == 0) ? "false" : "true"; } break;
+ case k_ExecFlags_ShellVarContext:
+ if (v < 2) { s2 = (v == 0) ? "current" : "all"; } break;
+ case k_ExecFlags_Silent:
+ if (v < 2) { s2 = (v == 0) ? "normal" : "silent"; } break;
+ case k_ExecFlags_RegView:
+ if (v == 0) s2 = "32";
+ else if (v == 256) s2 = "64";
+ break;
+ case k_ExecFlags_DetailsPrint:
+ if (v == 0) s2 = "both";
+ else if (v == 2) s2 = "textonly";
+ else if (v == 4) s2 = "listonly";
+ else if (v == 6) s2 = "none";
+ break;
+ }
+ if (s2)
+ {
+ s += ' ';
+ s += s2;
+ break;
+ }
+ }
+ SpaceQuStr(temp);
+ break;
+ }
+
+ case EW_IFFLAG:
+ {
+ Add_ExecFlags(params[2]);
+ Add_GotoVars2(&params[0]);
+ /*
+ const unsigned kIfErrors = 2;
+ if (params[2] != kIfErrors && params[3] != 0xFFFFFFFF ||
+ params[2] == kIfErrors && params[3] != 0)
+ {
+ s += " # FLAG &= ";
+ AddParam_UInt(params[3]);
+ }
+ */
+ break;
+ }
+
+ case EW_GETFLAG:
+ {
+ Add_ExecFlags(params[1]);
+ AddParam_Var(params[0]);
+ break;
+ }
+
+ case EW_RENAME:
+ {
+ if (params[2] != 0)
+ s += k_REBOOTOK;
+ AddParams(params, 2);
+ if (params[3] != 0)
+ {
+ SmallSpaceComment();
+ AddParam(params[3]); // rename comment for log file
+ }
+ break;
+ }
+
+ case EW_GETFULLPATHNAME:
+ {
+ if (params[2] == 0)
+ s += " /SHORT";
+ AddParam_Var(params[1]);
+ AddParam(params[0]);
+ break;
+ }
+
+ case EW_SEARCHPATH:
+ case EW_STRLEN:
+ {
+ AddParam_Var(params[0]);
+ AddParam(params[1]);
+ break;
+ }
+
+ case EW_GETTEMPFILENAME:
+ {
+ AddParam_Var(params[0]);
+ AString temp;
+ ReadString2(temp, params[1]);
+ if (temp != "$TEMP")
+ SpaceQuStr(temp);
+ break;
+ }
+
+ case EW_DELETEFILE:
+ {
+ UInt32 flag = params[1];
+ if ((flag & DEL_REBOOT) != 0)
+ s += k_REBOOTOK;
+ AddParam(params[0]);
+ break;
+ }
+
+ case EW_MESSAGEBOX:
+ {
+ MessageBox_MB_Part(params[0]);
+ AddParam(params[1]);
+ {
+ UInt32 buttonID = (params[0] >> 21); // NSIS 2.06+
+ if (buttonID != 0)
+ {
+ s += " /SD";
+ Add_ButtonID(buttonID);
+ }
+ }
+ for (int i = 2; i < 6; i += 2)
+ if (params[i] != 0)
+ {
+ Add_ButtonID(params[i]);
+ Add_GotoVar1(params[i + 1]);
+ }
+ break;
+ }
+
+ case EW_RMDIR:
+ {
+ UInt32 flag = params[1];
+ if ((flag & DEL_RECURSE) != 0)
+ s += " /r";
+ if ((flag & DEL_REBOOT) != 0)
+ s += k_REBOOTOK;
+ AddParam(params[0]);
+ break;
+ }
+
+ case EW_STRCMP:
+ {
+ if (params[4] != 0)
+ s += 'S';
+ AddParams(params, 2);
+ Add_GotoVars2(&params[2]);
+ break;
+ }
+
+ case EW_READENVSTR:
+ {
+ s += (params[2] != 0) ?
+ "ReadEnvStr" :
+ "ExpandEnvStrings";
+ AddParam_Var(params[0]);
+ AString temp;
+ ReadString2(temp, params[1]);
+ if (params[2] != 0 &&temp.Len() >= 2 && temp[0] == '%' && temp.Back() == '%')
+ {
+ temp.DeleteBack();
+ temp.Delete(0);
+ }
+ SpaceQuStr(temp);
+ break;
+ }
+
+ case EW_INTCMP:
+ {
+ s += "Int";
+ const UInt32 param5 = params[5];
+ if (param5 & 0x8000)
+ s += "64"; // v3.03+
+ s += "Cmp";
+ if (IsNsis3_OrHigher() ? (param5 & 1) : (param5 != 0))
+ s += 'U';
+ AddParams(params, 2);
+ Add_GotoVar1(params[2]);
+ if (params[3] != 0 || params[4] != 0)
+ Add_GotoVars2(params + 3);
+ break;
+ }
+
+ case EW_INTOP:
+ {
+ AddParam_Var(params[0]);
+ const char * const kOps = "+-*/|&^!|&%<>>"; // NSIS 2.01+
+ // "+-*/|&^!|&%"; // NSIS 2.0b4+
+ // "+-*/|&^~!|&%"; // NSIS old
+ const UInt32 opIndex = params[3];
+ const char c = (opIndex < 14) ? kOps[opIndex] : '?';
+ const char c2 = (opIndex < 8 || opIndex == 10) ? (char)0 : c;
+ const int numOps = (opIndex == 7) ? 1 : 2;
+ AddParam(params[1]);
+ if (numOps == 2 && c == '^' && IsDirectString_Equal(params[2], "0xFFFFFFFF"))
+ s += " ~ ;";
+ Space();
+ s += c;
+ if (numOps != 1)
+ {
+ if (opIndex == 13) // v3.03+ : operation ">>>"
+ s += c;
+ if (c2 != 0)
+ s += c2;
+ AddParam(params[2]);
+ }
+ break;
+ }
+
+ case EW_INTFMT:
+ {
+ if (params[3])
+ s += "Int64Fmt"; // v3.03+
+ else
+ s += "IntFmt";
+ AddParam_Var(params[0]);
+ AddParams(params + 1, 2);
+ break;
+ }
+
+ case EW_PUSHPOP:
+ {
+ if (params[2] != 0)
+ {
+ s += "Exch";
+ if (params[2] != 1)
+ AddParam_UInt(params[2]);
+ }
+ else if (params[1] != 0)
+ {
+ s += "Pop";
+ AddParam_Var(params[0]);
+ }
+ else
+ {
+ if (NoLabels(labels + kkk + 1, 2)
+ && Get32(p + kCmdSize) == EW_PUSHPOP // Exch"
+ && GET_CMD_PARAM(p + kCmdSize, 2) == 1
+ && Get32(p + kCmdSize * 2) == EW_PUSHPOP // Pop $VAR
+ && GET_CMD_PARAM(p + kCmdSize * 2, 1) != 0)
+ {
+ if (IsVarStr(params[0], GET_CMD_PARAM(p + kCmdSize * 2, 0)))
+ {
+ s += "Exch";
+ AddParam(params[0]);
+ NewLine();
+ Tab(true);
+ endCommentIndex = kkk + 3;
+ }
+ }
+ s += "Push";
+ AddParam(params[0]);
+ }
+ break;
+ }
+
+ case EW_FINDWINDOW:
+ {
+ AddParam_Var(params[0]);
+ AddParam(params[1]);
+ AddOptionalParams(params + 2, 3);
+ break;
+ }
+
+ case EW_SENDMESSAGE:
+ {
+ // SendMessage: 6 [output, hwnd, msg, wparam, lparam, [wparamstring?1:0 | lparamstring?2:0 | timeout<<2]
+ AddParam(params[1]);
+
+ const char *w = NULL;
+ AString t;
+ ReadString2(t, params[2]);
+ UInt32 wm;
+ if (StringToUInt32(t, wm))
+ {
+ switch (wm)
+ {
+ case 0x0C: w = "SETTEXT"; break;
+ case 0x10: w = "CLOSE"; break;
+ case 0x30: w = "SETFONT"; break;
+ }
+ }
+ if (w)
+ {
+ s += " ${WM_";
+ s += w;
+ s += '}';
+ }
+ else
+ SpaceQuStr(t);
+
+ UInt32 spec = params[5];
+ for (unsigned i = 0; i < 2; i++)
+ {
+ AString s2;
+ if (spec & ((UInt32)1 << i))
+ s2 += "STR:";
+ ReadString2(s2, params[3 + i]);
+ SpaceQuStr(s2);
+ }
+
+ if ((Int32)params[0] >= 0)
+ AddParam_Var(params[0]);
+
+ spec >>= 2;
+ if (spec != 0)
+ {
+ s += " /TIMEOUT=";
+ Add_UInt(spec);
+ }
+ break;
+ }
+
+ case EW_ISWINDOW:
+ {
+ AddParam(params[0]);
+ Add_GotoVars2(&params[1]);
+ break;
+ }
+
+ case EW_GETDLGITEM:
+ {
+ AddParam_Var(params[0]);
+ AddParams(params + 1, 2);
+ break;
+ }
+
+ case EW_SETCTLCOLORS:
+ {
+ AddParam(params[0]);
+
+ UInt32 offset = params[1];
+
+ if (_size < bhCtlColors.Offset
+ || _size - bhCtlColors.Offset < offset
+ || _size - bhCtlColors.Offset - offset < GET_CtlColors_SIZE(Is64Bit))
+ {
+ AddError("bad offset");
+ break;
+ }
+
+ const Byte *p2 = _data + bhCtlColors.Offset + offset;
+ CNsis_CtlColors colors;
+ colors.Parse(p2, Is64Bit);
+
+ if ((colors.flags & kColorsFlags_BK_SYS) != 0 ||
+ (colors.flags & kColorsFlags_TEXT_SYS) != 0)
+ s += " /BRANDING";
+
+ AString bk;
+ bool bkc = false;
+ if (colors.bkmode == Z7_NSIS_WIN_TRANSPARENT)
+ bk += " transparent";
+ else if (colors.flags & kColorsFlags_BKB)
+ {
+ if ((colors.flags & kColorsFlags_BK_SYS) == 0 &&
+ (colors.flags & kColorsFlags_BK) != 0)
+ bkc = true;
+ }
+ if ((colors.flags & kColorsFlags_TEXT) != 0 || !bk.IsEmpty() || bkc)
+ {
+ Space();
+ if ((colors.flags & kColorsFlags_TEXT_SYS) != 0 || (colors.flags & kColorsFlags_TEXT) == 0)
+ AddQuotes();
+ else
+ Add_Color(colors.text);
+ }
+ s += bk;
+ if (bkc)
+ {
+ Space();
+ Add_Color(colors.bkc);
+ }
+
+ break;
+ }
+
+ // case EW_LOADANDSETIMAGE:
+ case EW_SETBRANDINGIMAGE:
+ {
+ s += " /IMGID=";
+ Add_UInt(params[1]);
+ if (params[2] == 1)
+ s += " /RESIZETOFIT";
+ AddParam(params[0]);
+ break;
+ }
+
+ case EW_CREATEFONT:
+ {
+ AddParam_Var(params[0]);
+ AddParam(params[1]);
+ AddOptionalParams(params + 2, 2);
+ if (params[4] & 1) s += " /ITALIC";
+ if (params[4] & 2) s += " /UNDERLINE";
+ if (params[4] & 4) s += " /STRIKE";
+ break;
+ }
+
+ case EW_SHOWWINDOW:
+ {
+ AString hw, sw;
+ ReadString2(hw, params[0]);
+ ReadString2(sw, params[1]);
+ if (params[3] != 0)
+ s += "EnableWindow";
+ else
+ {
+ UInt32 val;
+ bool valDefined = false;
+ if (StringToUInt32(sw, val))
+ {
+ if (val < Z7_ARRAY_SIZE(kShowWindow_Commands))
+ {
+ sw.Empty();
+ sw += "${";
+ Add_ShowWindow_Cmd_2(sw, val);
+ sw += '}';
+ valDefined = true;
+ }
+ }
+ bool isHwndParent = IsVarStr(params[0], IsNsis225 ? kVar_HWNDPARENT_225 : kVar_HWNDPARENT);
+ if (params[2] != 0)
+ {
+ if (valDefined && val == 0 && isHwndParent)
+ {
+ s += "HideWindow";
+ break;
+ }
+ }
+ if (valDefined && val == 5 && isHwndParent &&
+ kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_BRINGTOFRONT)
+ {
+ s += " ; ";
+ }
+ s += "ShowWindow";
+ }
+ SpaceQuStr(hw);
+ SpaceQuStr(sw);
+ break;
+ }
+
+ case EW_SHELLEXEC:
+ {
+ AddParams(params, 2);
+ if (params[2] != 0 || params[3] != Z7_NSIS_WIN_SW_SHOWNORMAL)
+ {
+ AddParam(params[2]);
+ if (params[3] != Z7_NSIS_WIN_SW_SHOWNORMAL)
+ {
+ Space();
+ Add_ShowWindow_Cmd(params[3]);
+ }
+ }
+ if (params[5] != 0)
+ {
+ s += " ;";
+ AddParam(params[5]); // it's tatus text update
+ }
+ break;
+ }
+
+ case EW_EXECUTE:
+ {
+ if (params[2] != 0)
+ s += "Wait";
+ AddParam(params[0]);
+ if (params[2] != 0)
+ if ((Int32)params[1] >= 0)
+ AddParam_Var(params[1]);
+ break;
+ }
+
+ case EW_GETFILETIME:
+ case EW_GETDLLVERSION:
+ {
+ if (commandId == EW_GETDLLVERSION)
+ if (params[3] == 2)
+ s += " /ProductVersion"; // v3.08+
+ AddParam(params[2]);
+ AddParam_Var(params[0]);
+ AddParam_Var(params[1]);
+ break;
+ }
+
+ case EW_REGISTERDLL:
+ {
+ AString func;
+ ReadString2(func, params[1]);
+ bool printFunc = true;
+ // params[4] = 1; for plugin command
+ if (params[2] == 0)
+ {
+ s += "CallInstDLL";
+ AddParam(params[0]);
+ if (params[3] == 1)
+ s += " /NOUNLOAD";
+ }
+ else
+ {
+ if (func == "DllUnregisterServer")
+ {
+ s += "UnRegDLL";
+ printFunc = false;
+ }
+ else
+ {
+ s += "RegDLL";
+ if (func == "DllRegisterServer")
+ printFunc = false;
+ }
+ AddParam(params[0]);
+ }
+ if (printFunc)
+ SpaceQuStr(func);
+ break;
+ }
+
+ case EW_CREATESHORTCUT:
+ {
+ unsigned numParams;
+ #define IsNsis3d0b3_OrHigher() 0 // change it
+ const unsigned v3_0b3 = IsNsis3d0b3_OrHigher();
+ for (numParams = 6; numParams > 2; numParams--)
+ if (params[numParams - 1] != 0)
+ break;
+
+ const UInt32 spec = params[4];
+ const unsigned sw_shift = v3_0b3 ? 12 : 8;
+ const UInt32 sw_mask = v3_0b3 ? 0x7000 : 0x7F;
+ if (spec & 0x8000) // NSIS 3.0b0
+ s += " /NoWorkingDir";
+
+ AddParams(params, numParams > 4 ? 4 : numParams);
+ if (numParams <= 4)
+ break;
+
+ UInt32 icon = (spec & (v3_0b3 ? 0xFFF : 0xFF));
+ Space();
+ if (icon != 0)
+ Add_UInt(icon);
+ else
+ AddQuotes();
+
+ if ((spec >> sw_shift) == 0 && numParams < 6)
+ break;
+ UInt32 sw = (spec >> sw_shift) & sw_mask;
+ Space();
+ // NSIS encoder replaces these names:
+ if (sw == Z7_NSIS_WIN_SW_SHOWMINNOACTIVE)
+ sw = Z7_NSIS_WIN_SW_SHOWMINIMIZED;
+ if (sw == 0)
+ AddQuotes();
+ else
+ Add_ShowWindow_Cmd(sw);
+
+ UInt32 modKey = spec >> 24;
+ UInt32 key = (spec >> 16) & 0xFF;
+
+ if (modKey == 0 && key == 0)
+ {
+ if (numParams < 6)
+ break;
+ Space();
+ AddQuotes();
+ }
+ else
+ {
+ Space();
+ if (modKey & 1) s += "SHIFT|"; // HOTKEYF_SHIFT
+ if (modKey & 2) s += "CONTROL|";
+ if (modKey & 4) s += "ALT|";
+ if (modKey & 8) s += "EXT|";
+
+ const unsigned kMy_VK_F1 = 0x70;
+ if (key >= kMy_VK_F1 && key <= kMy_VK_F1 + 23)
+ {
+ s += 'F';
+ Add_UInt(key - kMy_VK_F1 + 1);
+ }
+ else if ((key >= 'A' && key <= 'Z') || (key >= '0' && key <= '9'))
+ s += (char)key;
+ else
+ {
+ s += "Char_";
+ Add_UInt(key);
+ }
+ }
+ AddOptionalParam(params[5]); // description
+ break;
+ }
+
+ case EW_COPYFILES:
+ {
+ if (params[2] & 0x04) s += " /SILENT"; // FOF_SILENT
+ if (params[2] & 0x80) s += " /FILESONLY"; // FOF_FILESONLY
+ AddParams(params, 2);
+ if (params[3] != 0)
+ {
+ s += " ;";
+ AddParam(params[3]); // status text update
+ }
+ break;
+ }
+
+ case EW_REBOOT:
+ {
+ if (params[0] != 0xbadf00d)
+ s += " ; Corrupted ???";
+ else if (kkk + 1 < bh.Num && GetCmd(Get32(p + kCmdSize)) == EW_QUIT)
+ endCommentIndex = kkk + 2;
+ break;
+ }
+
+ case EW_WRITEINI:
+ {
+ unsigned numAlwaysParams = 0;
+ if (params[0] == 0) // Section
+ s += "FlushINI";
+ else if (params[4] != 0)
+ {
+ s += "WriteINIStr";
+ numAlwaysParams = 3;
+ }
+ else
+ {
+ s += "DeleteINI";
+ s += (params[1] == 0) ? "Sec" : "Str";
+ numAlwaysParams = 1;
+ }
+ AddParam(params[3]); // filename
+ // Section, EntryName, Value
+ AddParams(params, numAlwaysParams);
+ AddOptionalParams(params + numAlwaysParams, 3 - numAlwaysParams);
+ break;
+ }
+
+ case EW_READINISTR:
+ {
+ AddParam_Var(params[0]);
+ AddParam(params[3]); // FileName
+ AddParams(params +1, 2); // Section, EntryName
+ break;
+ }
+
+ case EW_DELREG:
+ {
+ // NSIS 2.00 used another scheme!
+
+ if (params[4] == 0)
+ s += "Value";
+ else
+ {
+ s += "Key";
+ if (params[4] & 2)
+ s += " /ifempty";
+ // TODO: /ifnosubkeys, /ifnovalues
+ }
+ AddRegRoot(params[1]);
+ AddParam(params[2]);
+ AddOptionalParam(params[3]);
+ break;
+ }
+
+ case EW_WRITEREG:
+ {
+ const char *s2 = NULL;
+ switch (params[4])
+ {
+ case 1: s2 = "Str"; break;
+ case 2: s2 = "ExpandStr"; break; // maybe unused
+ case 3: s2 = "Bin"; break;
+ case 4: s2 = "DWORD"; break;
+ default:
+ s += '?';
+ Add_UInt(params[4]);
+ }
+ if (params[4] == 1 && params[5] == 2)
+ s2 = "ExpandStr";
+ if (params[4] == 3 && params[5] == 7)
+ s2 = "MultiStr"; // v3.02+
+ if (s2)
+ s += s2;
+ AddRegRoot(params[0]);
+ AddParams(params + 1, 2); // keyName, valueName
+ if (params[4] != 3)
+ AddParam(params[3]); // value
+ else
+ {
+ // Binary data.
+ Space();
+ UInt32 offset = params[3];
+ bool isSupported = false;
+ if (AfterHeaderSize >= 4
+ && bhData.Offset <= AfterHeaderSize - 4
+ && offset <= AfterHeaderSize - 4 - bhData.Offset)
+ {
+ // we support it for solid archives.
+ const Byte *p2 = _afterHeader + bhData.Offset + offset;
+ UInt32 size = Get32(p2);
+ if (size <= AfterHeaderSize - 4 - bhData.Offset - offset)
+ {
+ for (UInt32 i = 0; i < size; i++)
+ {
+ Byte b = (p2 + 4)[i];
+ unsigned t;
+ t = (b >> 4); s += (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))));
+ t = (b & 15); s += (char)(((t < 10) ? ('0' + t) : ('A' + (t - 10))));
+ }
+ isSupported = true;
+ }
+ }
+ if (!isSupported)
+ {
+ // we must read from file here;
+ s += "data[";
+ Add_UInt(offset);
+ s += " ... ]";
+ s += " ; !!! Unsupported";
+ }
+ }
+ break;
+ }
+
+ case EW_READREGSTR:
+ {
+ s += (params[4] == 1) ? "DWORD" : "Str";
+ AddParam_Var(params[0]);
+ AddRegRoot(params[1]);
+ AddParams(params + 2, 2);
+ break;
+ }
+
+ case EW_REGENUM:
+ {
+ s += (params[4] != 0) ? "Key" : "Value";
+ AddParam_Var(params[0]);
+ AddRegRoot(params[1]);
+ AddParams(params + 2, 2);
+ break;
+ }
+
+ case EW_FCLOSE:
+ case EW_FINDCLOSE:
+ {
+ AddParam_Var(params[0]);
+ break;
+ }
+
+ #endif
+
+ case EW_FOPEN:
+ {
+ /*
+ the pattern for empty files is following:
+ FileOpen $0 "file_name" w
+ FileClose $0
+ */
+
+ const UInt32 acc = params[1]; // dwDesiredAccess
+ const UInt32 creat = params[2]; // dwCreationDisposition
+ if (creat == Z7_NSIS_WIN_CREATE_ALWAYS && acc == Z7_NSIS_WIN_GENERIC_WRITE)
+ {
+ if (kkk + 1 < bh.Num)
+ if (Get32(p + kCmdSize) == EW_FCLOSE)
+ if (Get32(p + kCmdSize + 4) == params[0])
+ {
+ CItem &item = Items.AddNew();
+ item.IsEmptyFile = true;
+ SetItemName(item, params[3]);
+ }
+ }
+
+ #ifdef NSIS_SCRIPT
+
+ AddParam_Var(params[0]);
+ AddParam(params[3]);
+ if (acc == 0 && creat == 0)
+ break;
+ char cc = 0;
+ if (creat == Z7_NSIS_WIN_OPEN_EXISTING && acc == Z7_NSIS_WIN_GENERIC_READ)
+ cc = 'r';
+ else if (creat == Z7_NSIS_WIN_CREATE_ALWAYS && acc == Z7_NSIS_WIN_GENERIC_WRITE)
+ cc = 'w';
+ else if (creat == Z7_NSIS_WIN_OPEN_ALWAYS && (acc == (Z7_NSIS_WIN_GENERIC_WRITE | Z7_NSIS_WIN_GENERIC_READ)))
+ cc = 'a';
+ // cc = 0;
+ if (cc != 0)
+ {
+ Space();
+ s += cc;
+ break;
+ }
+
+ if (acc & Z7_NSIS_WIN_GENERIC_READ) s += " GENERIC_READ";
+ if (acc & Z7_NSIS_WIN_GENERIC_WRITE) s += " GENERIC_WRITE";
+ if (acc & Z7_NSIS_WIN_GENERIC_EXECUTE) s += " GENERIC_EXECUTE";
+ if (acc & Z7_NSIS_WIN_GENERIC_ALL) s += " GENERIC_ALL";
+
+ const char *s2 = NULL;
+ switch (creat)
+ {
+ case Z7_NSIS_WIN_CREATE_NEW: s2 = "CREATE_NEW"; break;
+ case Z7_NSIS_WIN_CREATE_ALWAYS: s2 = "CREATE_ALWAYS"; break;
+ case Z7_NSIS_WIN_OPEN_EXISTING: s2 = "OPEN_EXISTING"; break;
+ case Z7_NSIS_WIN_OPEN_ALWAYS: s2 = "OPEN_ALWAYS"; break;
+ case Z7_NSIS_WIN_TRUNCATE_EXISTING: s2 = "TRUNCATE_EXISTING"; break;
+ }
+ Space();
+ if (s2)
+ s += s2;
+ else
+ Add_UInt(creat);
+ #endif
+
+ break;
+ }
+
+ #ifdef NSIS_SCRIPT
+
+ case EW_FPUTS:
+ case EW_FPUTWS:
+ {
+ if (commandId == EW_FPUTWS)
+ s += (params[2] == 0) ? "UTF16LE" : "Word";
+ else if (params[2] != 0)
+ s += "Byte";
+ if (params[2] == 0 && params[3])
+ s += " /BOM"; // v3.0b3+
+ AddParam_Var(params[0]);
+ AddParam(params[1]);
+ break;
+ }
+
+ case EW_FGETS:
+ case EW_FGETWS:
+ {
+ if (commandId == EW_FPUTWS)
+ s += (params[3] == 0) ? "UTF16LE" : "Word";
+ if (params[3] != 0)
+ s += "Byte";
+ AddParam_Var(params[0]);
+ AddParam_Var(params[1]);
+ AString maxLenStr;
+ ReadString2(maxLenStr, params[2]);
+ UInt32 maxLen;
+ if (StringToUInt32(maxLenStr, maxLen))
+ {
+ if (maxLen == 1 && params[3] != 0)
+ break;
+ if (maxLen == 1023 && params[3] == 0) // NSIS_MAX_STRLEN - 1; can be other value!!
+ break;
+ }
+ SpaceQuStr(maxLenStr);
+ break;
+ }
+
+ case EW_FSEEK:
+ {
+ AddParam_Var(params[0]);
+ AddParam(params[2]);
+ if (params[3] == 1) s += " CUR"; // FILE_CURRENT
+ if (params[3] == 2) s += " END"; // FILE_END
+ if ((Int32)params[1] >= 0)
+ {
+ if (params[3] == 0) s += " SET"; // FILE_BEGIN
+ AddParam_Var(params[1]);
+ }
+ break;
+ }
+
+ case EW_FINDNEXT:
+ {
+ AddParam_Var(params[1]);
+ AddParam_Var(params[0]);
+ break;
+ }
+
+ case EW_FINDFIRST:
+ {
+ AddParam_Var(params[1]);
+ AddParam_Var(params[0]);
+ AddParam(params[2]);
+ break;
+ }
+
+ case EW_LOG:
+ {
+ if (params[0] != 0)
+ {
+ s += "Set ";
+ s += (params[1] == 0) ? "off" : "on";
+ }
+ else
+ {
+ s += "Text";
+ AddParam(params[1]);
+ }
+ break;
+ }
+
+ case EW_SECTIONSET:
+ {
+ if ((Int32)params[2] >= 0)
+ {
+ s += "Get";
+ Add_SectOp(params[2]);
+ AddParam(params[0]);
+ AddParam_Var(params[1]);
+ }
+ else
+ {
+ s += "Set";
+ const UInt32 t = (UInt32)(-(Int32)params[2] - 1);
+ Add_SectOp(t);
+ AddParam(params[0]);
+ AddParam(params[t == 0 ? 4 : 1]);
+
+ // params[3] != 0 means call SectionFlagsChanged in installer
+ // used by SECTIONSETFLAGS command
+ }
+ break;
+ }
+
+ case EW_INSTTYPESET:
+ {
+ unsigned numQwParams = 0;
+ const char *s2;
+ if (params[3] == 0)
+ {
+ if (params[2] == 0)
+ {
+ s2 = "InstTypeGetText";
+ numQwParams = 1;
+ }
+ else
+ {
+ s2 = "InstTypeSetText";
+ numQwParams = 2;
+ }
+ }
+ else
+ {
+ if (params[2] == 0)
+ s2 = "GetCurInstType";
+ else
+ {
+ s2 = "SetCurInstType";
+ numQwParams = 1;
+ }
+ }
+ s += s2;
+ AddParams(params, numQwParams);
+ if (params[2] == 0)
+ AddParam_Var(params[1]);
+ break;
+ }
+
+ case EW_GETOSINFO:
+ {
+ if (IsNsis3_OrHigher())
+ {
+ // v3.06+
+ if (params[3] == 0) // GETOSINFO_KNOWNFOLDER
+ {
+ s += "GetKnownFolderPath";
+ AddParam_Var(params[1]);
+ AddParam(params[2]);
+ break;
+ }
+ else if (params[3] == 1) // GETOSINFO_READMEMORY
+ {
+ s += "ReadMemory";
+ AddParam_Var(params[1]);
+ AddParam(params[2]);
+ AddParam(params[4]);
+ // if (params[2] == "0") AddCommentAndString("GetWinVer");
+ }
+ else
+ s += "GetOsInfo";
+ break;
+ }
+ s += "GetLabelAddr"; // before v3.06+
+ break;
+ }
+
+ case EW_LOCKWINDOW:
+ {
+ s += (params[0] == 0) ? " on" : " off";
+ break;
+ }
+
+ case EW_FINDPROC:
+ {
+ AddParam_Var(params[0]);
+ AddParam(params[1]);
+ break;
+ }
+
+ default:
+ {
+ numSkipParams = 0;
+ }
+ #endif
+ }
+
+ #ifdef NSIS_SCRIPT
+
+ unsigned numParams = kNumCommandParams;
+
+ for (; numParams > 0; numParams--)
+ if (params[numParams - 1] != 0)
+ break;
+
+ if (numParams > numSkipParams)
+ {
+ s += " ; !!!! Unknown Params: ";
+ unsigned i;
+ for (i = 0; i < numParams; i++)
+ AddParam(params[i]);
+
+ s += " ;";
+
+ for (i = 0; i < numParams; i++)
+ {
+ Space();
+ UInt32 v = params[i];
+ if (v > 0xFFF00000)
+ Add_SignedInt(s, (Int32)v);
+ else
+ Add_UInt(v);
+ }
+ }
+
+ NewLine();
+
+ #endif
+ }
+
+ #ifdef NSIS_SCRIPT
+
+ if (sectionIsOpen)
+ {
+ if (curSectionIndex < bhSections.Num)
+ {
+ const CSection &sect = Sections[curSectionIndex];
+ if (sect.StartCmdIndex + sect.NumCommands + 1 == kkk)
+ {
+ PrintSectionEnd();
+ sectionIsOpen = false;
+ // lastSectionEndCmd = kkk;
+ curSectionIndex++;
+ }
+ }
+ }
+
+ while (curSectionIndex < bhSections.Num)
+ {
+ const CSection &sect = Sections[curSectionIndex];
+ if (sectionIsOpen)
+ {
+ if (sect.StartCmdIndex + sect.NumCommands != kkk)
+ AddErrorLF("SECTION ERROR");
+ PrintSectionEnd();
+ sectionIsOpen = false;
+ curSectionIndex++;
+ }
+ else
+ {
+ if (PrintSectionBegin(sect, curSectionIndex))
+ curSectionIndex++;
+ else
+ sectionIsOpen = true;
+ }
+ }
+
+ #endif
+
+ return S_OK;
+}
+
+static int CompareItems(void *const *p1, void *const *p2, void *param)
+{
+ const CItem &i1 = **(const CItem *const *)p1;
+ const CItem &i2 = **(const CItem *const *)p2;
+ RINOZ(MyCompare(i1.Pos, i2.Pos))
+
+ /* In another code we check CItem::Pos after each solid item.
+ So here we place empty files before all non empty files */
+ if (i1.IsEmptyFile)
+ {
+ if (!i2.IsEmptyFile)
+ return -1;
+ }
+ else if (i2.IsEmptyFile)
+ return 1;
+
+ const CInArchive *inArchive = (const CInArchive *)param;
+ if (inArchive->IsUnicode)
+ {
+ if (i1.Prefix != i2.Prefix)
+ {
+ if (i1.Prefix < 0) return -1;
+ if (i2.Prefix < 0) return 1;
+ RINOZ(
+ inArchive->UPrefixes[i1.Prefix].Compare(
+ inArchive->UPrefixes[i2.Prefix]))
+ }
+ RINOZ(i1.NameU.Compare(i2.NameU))
+ }
+ else
+ {
+ if (i1.Prefix != i2.Prefix)
+ {
+ if (i1.Prefix < 0) return -1;
+ if (i2.Prefix < 0) return 1;
+ RINOZ(strcmp(
+ inArchive->APrefixes[i1.Prefix],
+ inArchive->APrefixes[i2.Prefix]))
+ }
+ RINOZ(strcmp(i1.NameA, i2.NameA))
+ }
+ return 0;
+}
+
+HRESULT CInArchive::SortItems()
+{
+ {
+ Items.Sort(CompareItems, (void *)this);
+ unsigned i;
+
+ for (i = 0; i + 1 < Items.Size(); i++)
+ {
+ const CItem &i1 = Items[i];
+ if (i1.IsEmptyFile)
+ continue;
+ const CItem &i2 = Items[i + 1];
+ if (i1.Pos != i2.Pos)
+ continue;
+
+ if (IsUnicode)
+ {
+ if (i1.NameU != i2.NameU) continue;
+ if (i1.Prefix != i2.Prefix)
+ {
+ if (i1.Prefix < 0 || i2.Prefix < 0) continue;
+ if (UPrefixes[i1.Prefix] != UPrefixes[i2.Prefix]) continue;
+ }
+ }
+ else
+ {
+ if (i1.NameA != i2.NameA) continue;
+ if (i1.Prefix != i2.Prefix)
+ {
+ if (i1.Prefix < 0 || i2.Prefix < 0) continue;
+ if (APrefixes[i1.Prefix] != APrefixes[i2.Prefix]) continue;
+ }
+ }
+ Items.Delete(i + 1);
+ i--;
+ }
+
+ for (i = 0; i < Items.Size(); i++)
+ {
+ CItem &item = Items[i];
+ if (item.IsEmptyFile)
+ continue;
+ const UInt32 curPos = item.Pos + 4;
+ for (unsigned nextIndex = i + 1; nextIndex < Items.Size(); nextIndex++)
+ {
+ const CItem &nextItem = Items[nextIndex];
+ // if (nextItem.IsEmptyFile) continue;
+ const UInt32 nextPos = nextItem.Pos;
+ if (curPos <= nextPos)
+ {
+ item.EstimatedSize_Defined = true;
+ item.EstimatedSize = nextPos - curPos;
+ break;
+ }
+ }
+ }
+
+ if (!IsSolid)
+ {
+ for (i = 0; i < Items.Size(); i++)
+ {
+ CItem &item = Items[i];
+ if (item.IsEmptyFile)
+ continue;
+ RINOK(SeekToNonSolidItem(i))
+ const UInt32 kSigSize = 4 + 1 + 1 + 4; // size,[flag],prop,dict
+ BYTE sig[kSigSize];
+ size_t processedSize = kSigSize;
+ RINOK(ReadStream(_stream, sig, &processedSize))
+ if (processedSize < 4)
+ return S_FALSE;
+ UInt32 size = Get32(sig);
+ if ((size & kMask_IsCompressed) != 0)
+ {
+ item.IsCompressed = true;
+ size &= ~kMask_IsCompressed;
+ if (Method == NMethodType::kLZMA)
+ {
+ if (processedSize < 9)
+ return S_FALSE;
+ /*
+ if (FilterFlag)
+ item.UseFilter = (sig[4] != 0);
+ */
+ item.DictionarySize = Get32(sig + 4 + 1 + (FilterFlag ? 1 : 0));
+ }
+ }
+ else
+ {
+ item.IsCompressed = false;
+ item.Size = size;
+ item.Size_Defined = true;
+ }
+ item.CompressedSize = size;
+ item.CompressedSize_Defined = true;
+ }
+ }
+ }
+ return S_OK;
+}
+
+#ifdef NSIS_SCRIPT
+// Flags for common_header.flags
+// #define CH_FLAGS_DETAILS_SHOWDETAILS 1
+// #define CH_FLAGS_DETAILS_NEVERSHOW 2
+#define CH_FLAGS_PROGRESS_COLORED 4
+#define CH_FLAGS_SILENT 8
+#define CH_FLAGS_SILENT_LOG 16
+#define CH_FLAGS_AUTO_CLOSE 32
+// #define CH_FLAGS_DIR_NO_SHOW 64 // unused now
+#define CH_FLAGS_NO_ROOT_DIR 128
+#define CH_FLAGS_COMP_ONLY_ON_CUSTOM 256
+#define CH_FLAGS_NO_CUSTOM 512
+
+static const char * const k_PostStrings[] =
+{
+ "install_directory_auto_append"
+ , "uninstchild" // NSIS 2.25+, used by uninstaller:
+ , "uninstcmd" // NSIS 2.25+, used by uninstaller:
+ , "wininit" // NSIS 2.25+, used by move file on reboot
+};
+#endif
+
+
+void CBlockHeader::Parse(const Byte *p, unsigned bhoSize)
+{
+ if (bhoSize == 12)
+ {
+ // UInt64 a = GetUi64(p);
+ if (GetUi32(p + 4) != 0)
+ throw 1;
+ }
+ Offset = GetUi32(p);
+ Num = GetUi32(p + bhoSize - 4);
+}
+
+#define PARSE_BH(k, bh) bh.Parse (p1 + 4 + bhoSize * k, bhoSize)
+
+
+HRESULT CInArchive::Parse()
+{
+ // UInt32 offset = ReadUInt32();
+ // ???? offset == FirstHeader.HeaderSize
+ const Byte * const p1 = _data;
+
+ if (_size < 4 + 12 * 8)
+ Is64Bit = false;
+ else
+ {
+ Is64Bit = true;
+ // here we test high 32-bit of possible UInt64 CBlockHeader::Offset field
+ for (int k = 0; k < 8; k++)
+ if (GetUi32(p1 + 4 + 12 * k + 4) != 0)
+ Is64Bit = false;
+ }
+
+ const unsigned bhoSize = Is64Bit ? 12 : 8;
+ if (_size < 4 + bhoSize * 8)
+ return S_FALSE;
+
+ CBlockHeader bhEntries, bhStrings, bhLangTables;
+
+ PARSE_BH (2, bhEntries);
+ PARSE_BH (3, bhStrings);
+ PARSE_BH (4, bhLangTables);
+
+ #ifdef NSIS_SCRIPT
+
+ CBlockHeader bhFont;
+ PARSE_BH (0, bhPages);
+ PARSE_BH (1, bhSections);
+ PARSE_BH (5, bhCtlColors);
+ PARSE_BH (6, bhFont);
+ PARSE_BH (7, bhData);
+
+ #endif
+
+ _stringsPos = bhStrings.Offset;
+ if (_stringsPos > _size
+ || bhLangTables.Offset > _size
+ || bhEntries.Offset > _size)
+ return S_FALSE;
+ {
+ if (bhLangTables.Offset < bhStrings.Offset)
+ return S_FALSE;
+ const UInt32 stringTableSize = bhLangTables.Offset - bhStrings.Offset;
+ if (stringTableSize < 2)
+ return S_FALSE;
+ const Byte *strData = _data + _stringsPos;
+ if (strData[stringTableSize - 1] != 0)
+ return S_FALSE;
+ IsUnicode = (Get16(strData) == 0);
+ NumStringChars = stringTableSize;
+ if (IsUnicode)
+ {
+ if ((stringTableSize & 1) != 0)
+ return S_FALSE;
+ NumStringChars >>= 1;
+ if (strData[stringTableSize - 2] != 0)
+ return S_FALSE;
+ }
+ }
+
+ if (bhEntries.Num > (1 << 25))
+ return S_FALSE;
+ if (bhEntries.Num * kCmdSize > _size - bhEntries.Offset)
+ return S_FALSE;
+
+ DetectNsisType(bhEntries, _data + bhEntries.Offset);
+
+ Decoder.IsNsisDeflate = (NsisType != k_NsisType_Nsis3);
+
+ // some NSIS files (that are not detected as k_NsisType_Nsis3)
+ // use original (non-NSIS) Deflate
+ // How to detect these cases?
+
+ // Decoder.IsNsisDeflate = false;
+
+
+ #ifdef NSIS_SCRIPT
+
+ {
+ AddCommentAndString("NSIS script");
+ if (IsUnicode)
+ Script += " (UTF-8)";
+ Space();
+ Script += GetFormatDescription();
+ AddLF();
+ }
+ {
+ AddCommentAndString(IsInstaller ? "Install" : "Uninstall");
+ AddLF();
+ }
+
+ AddLF();
+ if (Is64Bit)
+ AddStringLF("Target AMD64-Unicode"); // TODO: Read PE machine type and use the correct CPU type
+ else if (IsUnicode)
+ AddStringLF("Unicode true");
+ else if (IsNsis3_OrHigher())
+ AddStringLF("Unicode false"); // Unicode is the default in 3.07+
+
+ if (Method != NMethodType::kCopy)
+ {
+ const char *m = NULL;
+ switch ((int)Method)
+ {
+ case NMethodType::kDeflate: m = "zlib"; break;
+ case NMethodType::kBZip2: m = "bzip2"; break;
+ case NMethodType::kLZMA: m = "lzma"; break;
+ default: break;
+ }
+ Script += "SetCompressor";
+ if (IsSolid)
+ Script += " /SOLID";
+ if (m)
+ {
+ Space();
+ Script += m;
+ }
+ AddLF();
+ }
+ if (Method == NMethodType::kLZMA)
+ {
+ // if (DictionarySize != (8 << 20))
+ {
+ Script += "SetCompressorDictSize";
+ AddParam_UInt(DictionarySize >> 20);
+ AddLF();
+ }
+ }
+
+ Separator();
+ PrintNumComment("HEADER SIZE", FirstHeader.HeaderSize);
+ // if (bhPages.Offset != 300 && bhPages.Offset != 288)
+ if (bhPages.Offset != 0)
+ {
+ PrintNumComment("START HEADER SIZE", bhPages.Offset);
+ }
+
+ if (bhSections.Num > 0)
+ {
+ if (bhEntries.Offset < bhSections.Offset)
+ return S_FALSE;
+ SectionSize = (bhEntries.Offset - bhSections.Offset) / bhSections.Num;
+ if (bhSections.Offset + bhSections.Num * SectionSize != bhEntries.Offset)
+ return S_FALSE;
+ if (SectionSize < kSectionSize_base)
+ return S_FALSE;
+ UInt32 maxStringLen = SectionSize - kSectionSize_base;
+ if (IsUnicode)
+ {
+ if ((maxStringLen & 1) != 0)
+ return S_FALSE;
+ maxStringLen >>= 1;
+ }
+ // if (maxStringLen != 1024)
+ {
+ if (maxStringLen == 0)
+ PrintNumComment("SECTION SIZE", SectionSize);
+ else
+ PrintNumComment("MAX STRING LENGTH", maxStringLen);
+ }
+ }
+
+ PrintNumComment("STRING CHARS", NumStringChars);
+ // PrintNumComment("LANG TABLE SIZE", bhCtlColors.Offset - bhLangTables.Offset);
+
+ if (bhCtlColors.Offset > _size)
+ AddErrorLF("Bad COLORS TABLE");
+ // PrintNumComment("COLORS TABLE SIZE", bhFont.Offset - bhCtlColors.Offset);
+ if (bhCtlColors.Num != 0)
+ PrintNumComment("COLORS Num", bhCtlColors.Num);
+
+ // bhData uses offset in _afterHeader (not in _data)
+ // PrintNumComment("FONT TABLE SIZE", bhData.Offset - bhFont.Offset);
+ if (bhFont.Num != 0)
+ PrintNumComment("FONTS Num", bhFont.Num);
+
+ // PrintNumComment("DATA SIZE", FirstHeader.HeaderSize - bhData.Offset);
+ if (bhData.Num != 0)
+ PrintNumComment("DATA NUM", bhData.Num);
+
+ AddLF();
+
+ AddStringLF("OutFile [NSIS].exe");
+ AddStringLF("!include WinMessages.nsh");
+
+ AddLF();
+
+ strUsed.Alloc(NumStringChars);
+ memset(strUsed, 0, NumStringChars);
+
+ {
+ UInt32 ehFlags = Get32(p1);
+ UInt32 showDetails = ehFlags & 3;// CH_FLAGS_DETAILS_SHOWDETAILS & CH_FLAGS_DETAILS_NEVERSHOW;
+ if (showDetails >= 1 && showDetails <= 2)
+ {
+ Script += IsInstaller ? "ShowInstDetails" : "ShowUninstDetails";
+ Script += (showDetails == 1) ? " show" : " nevershow";
+ AddLF();
+ }
+ if (ehFlags & CH_FLAGS_PROGRESS_COLORED) AddStringLF("InstProgressFlags colored" );
+ if ((ehFlags & (CH_FLAGS_SILENT | CH_FLAGS_SILENT_LOG)) != 0)
+ {
+ Script += IsInstaller ? "SilentInstall " : "SilentUnInstall ";
+ Script += (ehFlags & CH_FLAGS_SILENT_LOG) ? "silentlog" : "silent";
+ AddLF();
+ }
+ if (ehFlags & CH_FLAGS_AUTO_CLOSE) AddStringLF("AutoCloseWindow true");
+ if ((ehFlags & CH_FLAGS_NO_ROOT_DIR) == 0) AddStringLF("AllowRootDirInstall true");
+ if (ehFlags & CH_FLAGS_NO_CUSTOM) AddStringLF("InstType /NOCUSTOM");
+ if (ehFlags & CH_FLAGS_COMP_ONLY_ON_CUSTOM) AddStringLF("InstType /COMPONENTSONLYONCUSTOM");
+ }
+
+ // Separator();
+ // AddLF();
+
+ Int32 licenseLangIndex = -1;
+ {
+ const Byte *pp = _data + bhPages.Offset;
+
+ for (UInt32 pageIndex = 0; pageIndex < bhPages.Num; pageIndex++, pp += kPageSize)
+ {
+ UInt32 wndProcID = Get32(pp + 4);
+ UInt32 param1 = Get32(pp + 44 + 4 * 1);
+ if (wndProcID != PWP_LICENSE || param1 == 0)
+ continue;
+ if ((Int32)param1 < 0)
+ licenseLangIndex = - ((Int32)param1 + 1);
+ else
+ noParseStringIndexes.AddToUniqueSorted(param1);
+ }
+ }
+
+ unsigned paramsOffset;
+ {
+ unsigned numBhs = 8;
+ // probably its for old NSIS?
+ if (bhoSize == 8 && bhPages.Offset == 276)
+ numBhs = 7;
+ paramsOffset = 4 + bhoSize * numBhs;
+ }
+
+ const Byte *p2 = p1 + paramsOffset;
+
+ {
+ UInt32 rootKey = Get32(p2); // (rootKey = -1) in uninstaller by default (the bug in NSIS)
+ UInt32 subKey = Get32(p2 + 4);
+ UInt32 value = Get32(p2 + 8);
+ if ((rootKey != 0 && rootKey != (UInt32)(Int32)-1) || subKey != 0 || value != 0)
+ {
+ Script += "InstallDirRegKey";
+ AddRegRoot(rootKey);
+ AddParam(subKey);
+ AddParam(value);
+ AddLF();
+ }
+ }
+
+
+ {
+ UInt32 bg_color1 = Get32(p2 + 12);
+ UInt32 bg_color2 = Get32(p2 + 16);
+ UInt32 bg_textcolor = Get32(p2 + 20);
+ if (bg_color1 != (UInt32)(Int32)-1 || bg_color2 != (UInt32)(Int32)-1 || bg_textcolor != (UInt32)(Int32)-1)
+ {
+ Script += "BGGradient";
+ if (bg_color1 != 0 || bg_color2 != 0xFF0000 || bg_textcolor != (UInt32)(Int32)-1)
+ {
+ Add_ColorParam(bg_color1);
+ Add_ColorParam(bg_color2);
+ if (bg_textcolor != (UInt32)(Int32)-1)
+ Add_ColorParam(bg_textcolor);
+ }
+ AddLF();
+ }
+ }
+
+ {
+ UInt32 lb_bg = Get32(p2 + 24);
+ UInt32 lb_fg = Get32(p2 + 28);
+ if ((lb_bg != (UInt32)(Int32)-1 || lb_fg != (UInt32)(Int32)-1) &&
+ (lb_bg != 0 || lb_fg != 0xFF00))
+ {
+ Script += "InstallColors";
+ Add_ColorParam(lb_fg);
+ Add_ColorParam(lb_bg);
+ AddLF();
+ }
+ }
+
+ UInt32 license_bg = Get32(p2 + 36);
+ if (license_bg != (UInt32)(Int32)-1 &&
+ license_bg != (UInt32)(Int32)-15) // COLOR_BTNFACE
+ {
+ Script += "LicenseBkColor";
+ if ((Int32)license_bg == -5) // COLOR_WINDOW
+ Script += " /windows";
+ /*
+ else if ((Int32)license_bg == -15)
+ Script += " /grey";
+ */
+ else
+ Add_ColorParam(license_bg);
+ AddLF();
+ }
+
+ if (bhLangTables.Num > 0)
+ {
+ const UInt32 langtable_size = Get32(p2 + 32);
+
+ if (langtable_size == (UInt32)(Int32)-1)
+ return E_NOTIMPL; // maybe it's old NSIS archive()
+
+ if (langtable_size < 10)
+ return S_FALSE;
+ if (bhLangTables.Num > (_size - bhLangTables.Offset) / langtable_size)
+ return S_FALSE;
+
+ const UInt32 numStrings = (langtable_size - 10) / 4;
+ _numLangStrings = numStrings;
+ AddLF();
+ Separator();
+ PrintNumComment("LANG TABLES", bhLangTables.Num);
+ PrintNumComment("LANG STRINGS", numStrings);
+ AddLF();
+
+ if (licenseLangIndex >= 0 && (unsigned)licenseLangIndex < numStrings)
+ {
+ for (UInt32 i = 0; i < bhLangTables.Num; i++)
+ {
+ const Byte * const p = _data + bhLangTables.Offset + langtable_size * i;
+ const UInt16 langID = Get16(p);
+ UInt32 val = Get32(p + 10 + (UInt32)licenseLangIndex * 4);
+ if (val != 0)
+ {
+ Script += "LicenseLangString ";
+ Add_LangStr_Simple((UInt32)licenseLangIndex);
+ AddParam_UInt(langID);
+ AddLicense(val, langID);
+ noParseStringIndexes.AddToUniqueSorted(val);
+ NewLine();
+ }
+ }
+ AddLF();
+ }
+
+ UInt32 names[3] = { 0 };
+
+ UInt32 i;
+ for (i = 0; i < bhLangTables.Num; i++)
+ {
+ const Byte * const p = _data + bhLangTables.Offset + langtable_size * i;
+ const UInt16 langID = Get16(p);
+ if (i == 0 || langID == 1033)
+ _mainLang = p + 10;
+ for (unsigned k = 0; k < Z7_ARRAY_SIZE(names) && k < numStrings; k++)
+ {
+ UInt32 v = Get32(p + 10 + k * 4);
+ if (v != 0 && (langID == 1033 || names[k] == 0))
+ names[k] = v;
+ }
+ }
+
+ const UInt32 name = names[2];
+ if (name != 0)
+ {
+ Script += "Name";
+ AddParam(name);
+ NewLine();
+
+ ReadString2(Name, name);
+ }
+
+ /*
+ const UInt32 caption = names[1];
+ if (caption != 0)
+ {
+ Script += "Caption";
+ AddParam(caption);
+ NewLine();
+ }
+ */
+
+ const UInt32 brandingText = names[0];
+ if (brandingText != 0)
+ {
+ Script += "BrandingText";
+ AddParam(brandingText);
+ NewLine();
+
+ ReadString2(BrandingText, brandingText);
+ }
+
+ for (i = 0; i < bhLangTables.Num; i++)
+ {
+ const Byte * const p = _data + bhLangTables.Offset + langtable_size * i;
+ const UInt16 langID = Get16(p);
+
+ AddLF();
+ AddCommentAndString("LANG:");
+ AddParam_UInt(langID);
+ /*
+ Script += " (";
+ LangId_To_String(Script, langID);
+ Script += ')';
+ */
+ AddLF();
+ // UInt32 dlg_offset = Get32(p + 2);
+ // UInt32 g_exec_flags_rtl = Get32(p + 6);
+
+
+ for (UInt32 j = 0; j < numStrings; j++)
+ {
+ UInt32 val = Get32(p + 10 + j * 4);
+ if (val != 0)
+ {
+ if ((Int32)j != licenseLangIndex)
+ {
+ Script += "LangString ";
+ Add_LangStr_Simple(j);
+ AddParam_UInt(langID);
+ AddParam(val);
+ AddLF();
+ }
+ }
+ }
+ AddLF();
+ }
+ ClearLangComment();
+ }
+
+ {
+ unsigned numInternalVars = GET_NUM_INTERNAL_VARS;
+ UInt32 numUsedVars = GetNumUsedVars();
+ if (numUsedVars > numInternalVars)
+ {
+ Separator();
+ PrintNumComment("VARIABLES", numUsedVars - numInternalVars);
+ AddLF();
+ AString temp;
+ for (UInt32 i = numInternalVars; i < numUsedVars; i++)
+ {
+ Script += "Var ";
+ temp.Empty();
+ GetVar2(temp, i);
+ AddStringLF(temp);
+ }
+ AddLF();
+ }
+ }
+
+ onFuncOffset = paramsOffset + 40;
+ numOnFunc = Z7_ARRAY_SIZE(kOnFunc);
+ if (bhPages.Offset == 276)
+ numOnFunc--;
+ p2 += 40 + numOnFunc * 4;
+
+ #define NSIS_MAX_INST_TYPES 32
+
+ AddLF();
+
+ UInt32 i;
+ for (i = 0; i < NSIS_MAX_INST_TYPES + 1; i++, p2 += 4)
+ {
+ UInt32 instType = Get32(p2);
+ if (instType != 0)
+ {
+ Script += "InstType";
+ AString s2;
+ if (!IsInstaller)
+ s2 += "un.";
+ ReadString2(s2, instType);
+ SpaceQuStr(s2);
+ NewLine();
+ }
+ }
+
+ {
+ UInt32 installDir = Get32(p2);
+ p2 += 4;
+ if (installDir != 0)
+ {
+ Script += "InstallDir";
+ AddParam(installDir);
+ NewLine();
+ }
+ }
+
+ if (bhPages.Offset >= 288)
+ for (i = 0; i < 4; i++)
+ {
+ if (i != 0 && bhPages.Offset < 300)
+ break;
+ UInt32 param = Get32(p2 + 4 * i);
+ if (param == 0 || param == (UInt32)(Int32)-1)
+ continue;
+
+ /*
+ uninstaller:
+ UInt32 uninstChild = Get32(p2 + 8); // "$TEMP\\$1u_.exe"
+ UInt32 uninstCmd = Get32(p2 + 12); // "\"$TEMP\\$1u_.exe\" $0 _?=$INSTDIR\\"
+ int str_wininit = Get32(p2 + 16); // "$WINDIR\\wininit.ini"
+ */
+
+ AddCommentAndString(k_PostStrings[i]);
+ Script += " =";
+ AddParam(param);
+ NewLine();
+ }
+
+ AddLF();
+
+ #endif
+
+ RINOK(ReadEntries(bhEntries))
+
+ #ifdef NSIS_SCRIPT
+
+ Separator();
+ AddCommentAndString("UNREFERENCED STRINGS:");
+ AddLF();
+ AddLF();
+ CommentOpen();
+
+ for (i = 0; i < NumStringChars;)
+ {
+ if (!strUsed[i] && i != 0)
+ // Script += "!!! ";
+ {
+ Add_UInt(i);
+ AddParam(i);
+ NewLine();
+ }
+ if (IsUnicode)
+ i += GetUi16Str_Len((const Byte *)_data + _stringsPos + i * 2);
+ else
+ i += (UInt32)strlen((const char *)(const Byte *)_data + _stringsPos + i);
+ i++;
+ }
+ CommentClose();
+ #endif
+
+ return SortItems();
+}
+
+static bool IsLZMA(const Byte *p, UInt32 &dictionary)
+{
+ dictionary = Get32(p + 1);
+ return (p[0] == 0x5D &&
+ p[1] == 0x00 && p[2] == 0x00 &&
+ p[5] == 0x00 && (p[6] & 0x80) == 0x00);
+}
+
+static bool IsLZMA(const Byte *p, UInt32 &dictionary, bool &thereIsFlag)
+{
+ if (IsLZMA(p, dictionary))
+ {
+ thereIsFlag = false;
+ return true;
+ }
+ if (p[0] <= 1 && IsLZMA(p + 1, dictionary))
+ {
+ thereIsFlag = true;
+ return true;
+ }
+ return false;
+}
+
+static bool IsBZip2(const Byte *p)
+{
+ return (p[0] == 0x31 && p[1] < 14);
+}
+
+HRESULT CInArchive::Open2(const Byte *sig, size_t size)
+{
+ const UInt32 kSigSize = 4 + 1 + 5 + 2; // size, flag, 5 - lzma props, 2 - lzma first bytes
+ if (size < kSigSize)
+ return S_FALSE;
+
+ _headerIsCompressed = true;
+ IsSolid = true;
+ FilterFlag = false;
+ UseFilter = false;
+ DictionarySize = 1;
+
+ #ifdef NSIS_SCRIPT
+ AfterHeaderSize = 0;
+ #endif
+
+ UInt32 compressedHeaderSize = Get32(sig);
+
+
+ /*
+ XX XX XX XX XX XX XX XX == FirstHeader.HeaderSize, nonsolid, uncompressed
+ 5D 00 00 dd dd 00 solid LZMA
+ 00 5D 00 00 dd dd 00 solid LZMA, empty filter (there are no such archives)
+ 01 5D 00 00 dd dd 00 solid LZMA, BCJ filter (only 7-Zip installer used that format)
+
+ SS SS SS 80 00 5D 00 00 dd dd 00 non-solid LZMA, empty filter
+ SS SS SS 80 01 5D 00 00 dd dd 00 non-solid LZMA, BCJ filte
+ SS SS SS 80 01 tt non-solid BZip (tt < 14
+ SS SS SS 80 non-solid deflate
+
+ 01 tt solid BZip (tt < 14
+ other solid Deflate
+ */
+
+ if (compressedHeaderSize == FirstHeader.HeaderSize)
+ {
+ _headerIsCompressed = false;
+ IsSolid = false;
+ Method = NMethodType::kCopy;
+ }
+ else if (IsLZMA(sig, DictionarySize, FilterFlag))
+ Method = NMethodType::kLZMA;
+ else if (sig[3] == 0x80)
+ {
+ IsSolid = false;
+ if (IsLZMA(sig + 4, DictionarySize, FilterFlag) && sig[3] == 0x80)
+ Method = NMethodType::kLZMA;
+ else if (IsBZip2(sig + 4))
+ Method = NMethodType::kBZip2;
+ else
+ Method = NMethodType::kDeflate;
+ }
+ else if (IsBZip2(sig))
+ Method = NMethodType::kBZip2;
+ else
+ Method = NMethodType::kDeflate;
+
+ if (IsSolid)
+ {
+ RINOK(SeekTo_DataStreamOffset())
+ }
+ else
+ {
+ _headerIsCompressed = ((compressedHeaderSize & kMask_IsCompressed) != 0);
+ compressedHeaderSize &= ~kMask_IsCompressed;
+ _nonSolidStartOffset = compressedHeaderSize;
+ RINOK(SeekTo(DataStreamOffset + 4))
+ }
+
+ if (FirstHeader.HeaderSize == 0)
+ return S_FALSE;
+
+ _data.Alloc(FirstHeader.HeaderSize);
+ _size = (size_t)FirstHeader.HeaderSize;
+
+ Decoder.Method = Method;
+ Decoder.FilterFlag = FilterFlag;
+ Decoder.Solid = IsSolid;
+
+ Decoder.IsNsisDeflate = true; // we need some smart check that NSIS is not NSIS3 here.
+
+ Decoder.InputStream = _stream;
+ Decoder.Buffer.Alloc(kInputBufSize);
+ Decoder.StreamPos = 0;
+
+ if (_headerIsCompressed)
+ {
+ RINOK(Decoder.Init(_stream, UseFilter))
+ if (IsSolid)
+ {
+ size_t processedSize = 4;
+ Byte buf[4];
+ RINOK(Decoder.Read(buf, &processedSize))
+ if (processedSize != 4)
+ return S_FALSE;
+ if (Get32((const Byte *)buf) != FirstHeader.HeaderSize)
+ return S_FALSE;
+ }
+ {
+ size_t processedSize = FirstHeader.HeaderSize;
+ RINOK(Decoder.Read(_data, &processedSize))
+ if (processedSize != FirstHeader.HeaderSize)
+ return S_FALSE;
+ }
+
+ #ifdef NSIS_SCRIPT
+ if (IsSolid)
+ {
+ /* we need additional bytes for data for WriteRegBin */
+ AfterHeaderSize = (1 << 12);
+ _afterHeader.Alloc(AfterHeaderSize);
+ size_t processedSize = AfterHeaderSize;
+ RINOK(Decoder.Read(_afterHeader, &processedSize))
+ AfterHeaderSize = (UInt32)processedSize;
+ }
+ #endif
+ }
+ else
+ {
+ size_t processedSize = FirstHeader.HeaderSize;
+ RINOK(ReadStream(_stream, (Byte *)_data, &processedSize))
+ if (processedSize < FirstHeader.HeaderSize)
+ return S_FALSE;
+ }
+
+ #ifdef NUM_SPEED_TESTS
+ for (unsigned i = 0; i < NUM_SPEED_TESTS; i++)
+ {
+ RINOK(Parse());
+ Clear2();
+ }
+ #endif
+
+ return Parse();
+}
+
+/*
+NsisExe =
+{
+ ExeStub
+ Archive // must start from 512 * N
+ #ifndef NSIS_CONFIG_CRC_ANAL
+ {
+ Some additional data
+ }
+}
+
+Archive
+{
+ FirstHeader
+ Data
+ #ifdef NSIS_CONFIG_CRC_SUPPORT && FirstHeader.ThereIsCrc()
+ {
+ CRC
+ }
+}
+
+FirstHeader
+{
+ UInt32 Flags;
+ Byte Signature[16];
+ // points to the header+sections+entries+stringtable in the datablock
+ UInt32 HeaderSize;
+ UInt32 ArcSize;
+}
+*/
+
+
+// ---------- PE (EXE) parsing ----------
+
+static const unsigned k_PE_StartSize = 0x40;
+static const unsigned k_PE_HeaderSize = 4 + 20;
+static const unsigned k_PE_OptHeader32_Size_MIN = 96;
+
+static inline bool CheckPeOffset(UInt32 pe)
+{
+ return (pe >= 0x40 && pe <= 0x1000 && (pe & 7) == 0);
+}
+
+
+static bool IsArc_Pe(const Byte *p, size_t size)
+{
+ if (size < 2)
+ return false;
+ if (p[0] != 'M' || p[1] != 'Z')
+ return false;
+ if (size < k_PE_StartSize)
+ return false; // k_IsArc_Res_NEED_MORE;
+ UInt32 pe = Get32(p + 0x3C);
+ if (!CheckPeOffset(pe))
+ return false;
+ if (pe + k_PE_HeaderSize > size)
+ return false; // k_IsArc_Res_NEED_MORE;
+
+ p += pe;
+ if (Get32(p) != 0x00004550)
+ return false;
+ return Get16(p + 4 + 16) >= k_PE_OptHeader32_Size_MIN;
+}
+
+HRESULT CInArchive::Open(IInStream *inStream, const UInt64 *maxCheckStartPosition)
+{
+ Clear();
+
+ RINOK(InStream_GetPos(inStream, StartOffset))
+
+ const UInt32 kStartHeaderSize = 4 * 7;
+ const unsigned kStep = 512; // nsis start is aligned for 512
+ Byte buf[kStep];
+ UInt64 pos = StartOffset;
+ size_t bufSize = 0;
+ UInt64 pePos = (UInt64)(Int64)-1;
+
+ for (;;)
+ {
+ bufSize = kStep;
+ RINOK(ReadStream(inStream, buf, &bufSize))
+ if (bufSize < kStartHeaderSize)
+ return S_FALSE;
+ if (memcmp(buf + 4, kSignature, kSignatureSize) == 0)
+ break;
+ if (IsArc_Pe(buf, bufSize))
+ pePos = pos;
+ pos += kStep;
+ UInt64 proc = pos - StartOffset;
+ if (maxCheckStartPosition && proc > *maxCheckStartPosition)
+ {
+ if (pePos == 0)
+ {
+ if (proc > (1 << 20))
+ return S_FALSE;
+ }
+ else
+ return S_FALSE;
+ }
+ }
+
+ if (pePos == (UInt64)(Int64)-1)
+ {
+ UInt64 posCur = StartOffset;
+ for (;;)
+ {
+ if (posCur < kStep)
+ break;
+ posCur -= kStep;
+ if (pos - posCur > (1 << 20))
+ break;
+ bufSize = kStep;
+ RINOK(InStream_SeekSet(inStream, posCur))
+ RINOK(ReadStream(inStream, buf, &bufSize))
+ if (bufSize < kStep)
+ break;
+ if (IsArc_Pe(buf, bufSize))
+ {
+ pePos = posCur;
+ break;
+ }
+ }
+
+ // restore buf to nsis header
+ bufSize = kStep;
+ RINOK(InStream_SeekSet(inStream, pos))
+ RINOK(ReadStream(inStream, buf, &bufSize))
+ if (bufSize < kStartHeaderSize)
+ return S_FALSE;
+ }
+
+ StartOffset = pos;
+ UInt32 peSize = 0;
+
+ if (pePos != (UInt64)(Int64)-1)
+ {
+ UInt64 peSize64 = (pos - pePos);
+ if (peSize64 < (1 << 20))
+ {
+ peSize = (UInt32)peSize64;
+ StartOffset = pePos;
+ }
+ }
+
+ DataStreamOffset = pos + kStartHeaderSize;
+ FirstHeader.Flags = Get32(buf);
+ if ((FirstHeader.Flags & (~kFlagsMask)) != 0)
+ {
+ // return E_NOTIMPL;
+ return S_FALSE;
+ }
+ IsInstaller = (FirstHeader.Flags & NFlags::kUninstall) == 0;
+
+ FirstHeader.HeaderSize = Get32(buf + kSignatureSize + 4);
+ FirstHeader.ArcSize = Get32(buf + kSignatureSize + 8);
+ if (FirstHeader.ArcSize <= kStartHeaderSize)
+ return S_FALSE;
+
+ /*
+ if ((FirstHeader.Flags & NFlags::k_BI_ExternalFileSupport) != 0)
+ {
+ UInt32 datablock_low = Get32(buf + kSignatureSize + 12);
+ UInt32 datablock_high = Get32(buf + kSignatureSize + 16);
+ }
+ */
+
+ RINOK(InStream_GetSize_SeekToEnd(inStream, _fileSize))
+
+ IsArc = true;
+
+ if (peSize != 0)
+ {
+ ExeStub.Alloc(peSize);
+ RINOK(InStream_SeekSet(inStream, pePos))
+ RINOK(ReadStream_FALSE(inStream, ExeStub, peSize))
+ }
+
+ HRESULT res = S_FALSE;
+ try
+ {
+ CLimitedInStream *_limitedStreamSpec = new CLimitedInStream;
+ _stream = _limitedStreamSpec;
+ _limitedStreamSpec->SetStream(inStream);
+ _limitedStreamSpec->InitAndSeek(pos, FirstHeader.ArcSize);
+ DataStreamOffset -= pos;
+ res = Open2(buf + kStartHeaderSize, bufSize - kStartHeaderSize);
+ }
+ catch(...)
+ {
+ _stream.Release();
+ throw;
+ // res = S_FALSE;
+ }
+ if (res != S_OK)
+ {
+ _stream.Release();
+ // Clear();
+ }
+ return res;
+}
+
+UString CInArchive::ConvertToUnicode(const AString &s) const
+{
+ if (IsUnicode)
+ {
+ UString res;
+ // if (
+ ConvertUTF8ToUnicode(s, res);
+ return res;
+ }
+ return MultiByteToUnicodeString(s);
+}
+
+void CInArchive::Clear2()
+{
+ IsUnicode = false;
+ NsisType = k_NsisType_Nsis2;
+ IsNsis225 = false;
+ IsNsis200 = false;
+ LogCmdIsEnabled = false;
+ BadCmd = -1;
+ Is64Bit = false;
+
+ #ifdef NSIS_SCRIPT
+ Name.Empty();
+ BrandingText.Empty();
+ Script.Empty();
+ LicenseFiles.Clear();
+ _numRootLicenses = 0;
+ _numLangStrings = 0;
+ langStrIDs.Clear();
+ LangComment.Empty();
+ noParseStringIndexes.Clear();
+ #endif
+
+ APrefixes.Clear();
+ UPrefixes.Clear();
+ Items.Clear();
+ IsUnicode = false;
+ ExeStub.Free();
+}
+
+void CInArchive::Clear()
+{
+ Clear2();
+ IsArc = false;
+ _stream.Release();
+}
+
+}}
diff --git a/CPP/7zip/Archive/Nsis/NsisIn.h b/CPP/7zip/Archive/Nsis/NsisIn.h
new file mode 100644
index 0000000..bb8de62
--- /dev/null
+++ b/CPP/7zip/Archive/Nsis/NsisIn.h
@@ -0,0 +1,458 @@
+// NsisIn.h
+
+#ifndef ZIP7_INC_ARCHIVE_NSIS_IN_H
+#define ZIP7_INC_ARCHIVE_NSIS_IN_H
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/DynLimBuf.h"
+#include "../../../Common/MyBuffer.h"
+#include "../../../Common/MyCom.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/UTFConvert.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "NsisDecode.h"
+
+/* If NSIS_SCRIPT is defined, it will decompile NSIS script to [NSIS].nsi file.
+ The code is much larger in that case. */
+
+// #define NSIS_SCRIPT
+
+namespace NArchive {
+namespace NNsis {
+
+const size_t kScriptSizeLimit = 1 << 27;
+
+const unsigned kSignatureSize = 16;
+extern const Byte kSignature[kSignatureSize];
+#define NSIS_SIGNATURE { 0xEF, 0xBE, 0xAD, 0xDE, 'N', 'u', 'l', 'l', 's', 'o', 'f', 't', 'I', 'n', 's', 't' }
+
+const UInt32 kFlagsMask = 0xF;
+namespace NFlags
+{
+ const UInt32 kUninstall = 1;
+ const UInt32 kSilent = 2;
+ const UInt32 kNoCrc = 4;
+ const UInt32 kForceCrc = 8;
+ // NSISBI fork flags:
+ const UInt32 k_BI_LongOffset = 16;
+ const UInt32 k_BI_ExternalFileSupport = 32;
+ const UInt32 k_BI_ExternalFile = 64;
+ const UInt32 k_BI_IsStubInstaller = 128;
+}
+
+struct CFirstHeader
+{
+ UInt32 Flags;
+ UInt32 HeaderSize;
+ UInt32 ArcSize;
+
+ bool ThereIsCrc() const
+ {
+ return
+ (Flags & NFlags::kForceCrc) != 0 ||
+ (Flags & NFlags::kNoCrc) == 0;
+ }
+
+ UInt32 GetDataSize() const { return ArcSize - (ThereIsCrc() ? 4 : 0); }
+};
+
+
+struct CBlockHeader
+{
+ UInt32 Offset;
+ UInt32 Num;
+
+ void Parse(const Byte *p, unsigned bhoSize);
+};
+
+struct CItem
+{
+ bool IsEmptyFile;
+ bool IsCompressed;
+ bool Size_Defined;
+ bool CompressedSize_Defined;
+ bool EstimatedSize_Defined;
+ bool Attrib_Defined;
+ bool IsUninstaller;
+ // bool UseFilter;
+
+ UInt32 Attrib;
+ UInt32 Pos; // = 0, if (IsEmptyFile == true)
+ UInt32 Size;
+ UInt32 CompressedSize;
+ UInt32 EstimatedSize;
+ UInt32 DictionarySize;
+ UInt32 PatchSize; // for Uninstaller.exe
+ int Prefix; // - 1 means no prefix
+
+ FILETIME MTime;
+ AString NameA;
+ UString NameU;
+
+ bool Is_PatchedUninstaller() const { return PatchSize != 0; }
+
+ CItem():
+ IsEmptyFile(false),
+ IsCompressed(true),
+ Size_Defined(false),
+ CompressedSize_Defined(false),
+ EstimatedSize_Defined(false),
+ Attrib_Defined(false),
+ IsUninstaller(false),
+ // UseFilter(false),
+ Attrib(0),
+ Pos(0),
+ Size(0),
+ CompressedSize(0),
+ EstimatedSize(0),
+ DictionarySize(1),
+ PatchSize(0),
+ Prefix(-1)
+ {
+ MTime.dwLowDateTime = 0;
+ MTime.dwHighDateTime = 0;
+ }
+
+ /*
+ bool IsINSTDIR() const
+ {
+ return (PrefixA.Len() >= 3 || PrefixU.Len() >= 3);
+ }
+ */
+};
+
+enum ENsisType
+{
+ k_NsisType_Nsis2,
+ k_NsisType_Nsis3,
+ k_NsisType_Park1, // Park 2.46.1-
+ k_NsisType_Park2, // Park 2.46.2 : GetFontVersion
+ k_NsisType_Park3 // Park 2.46.3+ : GetFontName
+};
+
+#ifdef NSIS_SCRIPT
+
+struct CSection
+{
+ UInt32 InstallTypes; // bits set for each of the different install_types, if any.
+ UInt32 Flags; // SF_* - defined above
+ UInt32 StartCmdIndex; // code;
+ UInt32 NumCommands; // code_size;
+ UInt32 SizeKB;
+ UInt32 Name;
+
+ void Parse(const Byte *data);
+};
+
+struct CLicenseFile
+{
+ UInt32 Offset;
+ UInt32 Size;
+ AString Name;
+ CByteBuffer Text;
+};
+
+#endif
+
+class CInArchive
+{
+public:
+ #ifdef NSIS_SCRIPT
+ CDynLimBuf Script;
+ #endif
+ CByteBuffer _data;
+ CObjectVector<CItem> Items;
+ bool IsUnicode;
+ bool Is64Bit;
+private:
+ UInt32 _stringsPos; // relative to _data
+ UInt32 NumStringChars;
+ size_t _size; // it's Header Size
+
+ AString Raw_AString;
+ UString Raw_UString;
+
+ ENsisType NsisType;
+ bool IsNsis200; // NSIS 2.03 and before
+ bool IsNsis225; // NSIS 2.25 and before
+ bool LogCmdIsEnabled;
+ int BadCmd; // -1: no bad command; in another cases lowest bad command id
+
+ bool IsPark() const { return NsisType >= k_NsisType_Park1; }
+ bool IsNsis3_OrHigher() const { return NsisType == k_NsisType_Nsis3; }
+
+ UInt64 _fileSize;
+
+ bool _headerIsCompressed;
+ UInt32 _nonSolidStartOffset;
+
+ #ifdef NSIS_SCRIPT
+
+ CByteBuffer strUsed;
+
+ CBlockHeader bhPages;
+ CBlockHeader bhSections;
+ CBlockHeader bhCtlColors;
+ CBlockHeader bhData;
+ UInt32 AfterHeaderSize;
+ CByteBuffer _afterHeader;
+
+ UInt32 SectionSize;
+ const Byte *_mainLang;
+ UInt32 _numLangStrings;
+ AString LangComment;
+ CRecordVector<UInt32> langStrIDs;
+ UInt32 numOnFunc;
+ UInt32 onFuncOffset;
+ // CRecordVector<UInt32> OnFuncs;
+ unsigned _numRootLicenses;
+ CRecordVector<UInt32> noParseStringIndexes;
+ AString _tempString_for_GetVar;
+ AString _tempString_for_AddFuncName;
+ AString _tempString;
+
+ #endif
+
+
+public:
+ CMyComPtr<IInStream> _stream; // it's limited stream that contains only NSIS archive
+ UInt64 StartOffset; // offset in original stream.
+ UInt64 DataStreamOffset; // = sizeof(FirstHeader) = offset of Header in _stream
+
+ bool IsArc;
+
+ CDecoder Decoder;
+ CByteBuffer ExeStub;
+ CFirstHeader FirstHeader;
+ NMethodType::EEnum Method;
+ UInt32 DictionarySize;
+ bool IsSolid;
+ bool UseFilter;
+ bool FilterFlag;
+
+ bool IsInstaller;
+ AString Name;
+ AString BrandingText;
+ UStringVector UPrefixes;
+ AStringVector APrefixes;
+
+ #ifdef NSIS_SCRIPT
+ CObjectVector<CLicenseFile> LicenseFiles;
+ #endif
+
+private:
+ void GetShellString(AString &s, unsigned index1, unsigned index2);
+ void GetNsisString_Raw(const Byte *s);
+ void GetNsisString_Unicode_Raw(const Byte *s);
+ void ReadString2_Raw(UInt32 pos);
+ bool IsGoodString(UInt32 param) const;
+ bool AreTwoParamStringsEqual(UInt32 param1, UInt32 param2) const;
+
+ void Add_LangStr(AString &res, UInt32 id);
+
+ #ifdef NSIS_SCRIPT
+
+ void Add_UInt(UInt32 v);
+ void AddLicense(UInt32 param, Int32 langID);
+
+ void Add_LangStr_Simple(UInt32 id);
+ void Add_FuncName(const UInt32 *labels, UInt32 index);
+ void AddParam_Func(const UInt32 *labels, UInt32 index);
+ void Add_LabelName(UInt32 index);
+
+ void Add_Color2(UInt32 v);
+ void Add_ColorParam(UInt32 v);
+ void Add_Color(UInt32 index);
+
+ void Add_ButtonID(UInt32 buttonID);
+
+ void Add_ShowWindow_Cmd(UInt32 cmd);
+ void Add_TypeFromList(const char * const *table, unsigned tableSize, UInt32 type);
+ void Add_ExecFlags(UInt32 flagsType);
+ void Add_SectOp(UInt32 opType);
+
+ void Add_Var(UInt32 index);
+ void AddParam_Var(UInt32 value);
+ void AddParam_UInt(UInt32 value);
+
+ void Add_GotoVar(UInt32 param);
+ void Add_GotoVar1(UInt32 param);
+ void Add_GotoVars2(const UInt32 *params);
+
+
+
+ bool PrintSectionBegin(const CSection &sect, unsigned index);
+ void PrintSectionEnd();
+
+ void GetNsisString(AString &res, const Byte *s);
+ void GetNsisString_Unicode(AString &res, const Byte *s);
+ UInt32 GetNumUsedVars() const;
+ void ReadString2(AString &s, UInt32 pos);
+
+ void MessageBox_MB_Part(UInt32 param);
+ void AddParam(UInt32 pos);
+ void AddOptionalParam(UInt32 pos);
+ void AddParams(const UInt32 *params, unsigned num);
+ void AddPageOption1(UInt32 param, const char *name);
+ void AddPageOption(const UInt32 *params, unsigned num, const char *name);
+ void AddOptionalParams(const UInt32 *params, unsigned num);
+ void AddRegRoot(UInt32 value);
+
+
+ void ClearLangComment();
+ void Separator();
+ void Space();
+ void Tab();
+ void Tab(bool commented);
+ void BigSpaceComment();
+ void SmallSpaceComment();
+ void AddCommentAndString(const char *s);
+ void AddError(const char *s);
+ void AddErrorLF(const char *s);
+ void CommentOpen();
+ void CommentClose();
+ void AddLF();
+ void AddQuotes();
+ void TabString(const char *s);
+ void AddStringLF(const char *s);
+ void NewLine();
+ void PrintNumComment(const char *name, UInt32 value);
+ void Add_QuStr(const AString &s);
+ void SpaceQuStr(const AString &s);
+ bool CompareCommands(const Byte *rawCmds, const Byte *sequence, size_t numCommands);
+
+ #endif
+
+ #ifdef NSIS_SCRIPT
+ unsigned GetNumSupportedCommands() const;
+ #endif
+
+ UInt32 GetCmd(UInt32 a);
+ void FindBadCmd(const CBlockHeader &bh, const Byte *);
+ void DetectNsisType(const CBlockHeader &bh, const Byte *);
+
+ HRESULT ReadEntries(const CBlockHeader &bh);
+ HRESULT SortItems();
+ HRESULT Parse();
+ HRESULT Open2(const Byte *data, size_t size);
+ void Clear2();
+
+ void GetVar2(AString &res, UInt32 index);
+ void GetVar(AString &res, UInt32 index);
+ Int32 GetVarIndex(UInt32 strPos) const;
+ Int32 GetVarIndex(UInt32 strPos, UInt32 &resOffset) const;
+ Int32 GetVarIndexFinished(UInt32 strPos, Byte endChar, UInt32 &resOffset) const;
+ bool IsVarStr(UInt32 strPos, UInt32 varIndex) const;
+ bool IsAbsolutePathVar(UInt32 strPos) const;
+ void SetItemName(CItem &item, UInt32 strPos);
+
+public:
+ HRESULT Open(IInStream *inStream, const UInt64 *maxCheckStartPosition);
+ AString GetFormatDescription() const;
+ HRESULT InitDecoder()
+ {
+ bool useFilter;
+ return Decoder.Init(_stream, useFilter);
+ }
+
+ HRESULT SeekTo(UInt64 pos)
+ {
+ return InStream_SeekSet(_stream, pos);
+ }
+
+ HRESULT SeekTo_DataStreamOffset()
+ {
+ return SeekTo(DataStreamOffset);
+ }
+
+ HRESULT SeekToNonSolidItem(unsigned index)
+ {
+ return SeekTo(GetPosOfNonSolidItem(index));
+ }
+
+ void Clear();
+
+ bool IsDirectString_Equal(UInt32 offset, const char *s) const;
+ /*
+ UInt64 GetDataPos(unsigned index)
+ {
+ const CItem &item = Items[index];
+ return GetOffset() + FirstHeader.HeaderSize + item.Pos;
+ }
+ */
+
+ UInt64 GetPosOfSolidItem(unsigned index) const
+ {
+ const CItem &item = Items[index];
+ return 4 + (UInt64)FirstHeader.HeaderSize + item.Pos;
+ }
+
+ UInt64 GetPosOfNonSolidItem(unsigned index) const
+ {
+ const CItem &item = Items[index];
+ return DataStreamOffset + _nonSolidStartOffset + 4 + item.Pos;
+ }
+
+ void Release()
+ {
+ Decoder.Release();
+ }
+
+ bool IsTruncated() const { return (_fileSize - StartOffset < FirstHeader.ArcSize); }
+
+ UString GetReducedName(unsigned index) const
+ {
+ const CItem &item = Items[index];
+
+ UString s;
+ if (item.Prefix >= 0)
+ {
+ if (IsUnicode)
+ s = UPrefixes[item.Prefix];
+ else
+ s = MultiByteToUnicodeString(APrefixes[item.Prefix]);
+ if (s.Len() > 0)
+ if (s.Back() != L'\\')
+ s += '\\';
+ }
+
+ if (IsUnicode)
+ {
+ s += item.NameU;
+ if (item.NameU.IsEmpty())
+ s += "file";
+ }
+ else
+ {
+ s += MultiByteToUnicodeString(item.NameA);
+ if (item.NameA.IsEmpty())
+ s += "file";
+ }
+
+ const char * const kRemoveStr = "$INSTDIR\\";
+ if (s.IsPrefixedBy_Ascii_NoCase(kRemoveStr))
+ {
+ s.Delete(0, MyStringLen(kRemoveStr));
+ if (s[0] == L'\\')
+ s.DeleteFrontal(1);
+ }
+ if (item.Is_PatchedUninstaller() && ExeStub.Size() == 0)
+ s += ".nsis";
+ return s;
+ }
+
+ UString ConvertToUnicode(const AString &s) const;
+
+ CInArchive()
+ #ifdef NSIS_SCRIPT
+ : Script(kScriptSizeLimit)
+ #endif
+ {}
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Nsis/NsisRegister.cpp b/CPP/7zip/Archive/Nsis/NsisRegister.cpp
new file mode 100644
index 0000000..a500381
--- /dev/null
+++ b/CPP/7zip/Archive/Nsis/NsisRegister.cpp
@@ -0,0 +1,20 @@
+// NsisRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "NsisHandler.h"
+
+namespace NArchive {
+namespace NNsis {
+
+REGISTER_ARC_I(
+ "Nsis", "nsis", NULL, 0x9,
+ kSignature,
+ 4,
+ NArcInfoFlags::kFindSignature |
+ NArcInfoFlags::kUseGlobalOffset,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/Nsis/StdAfx.h b/CPP/7zip/Archive/Nsis/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Archive/Nsis/StdAfx.h
@@ -0,0 +1,11 @@
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Archive/NtfsHandler.cpp b/CPP/7zip/Archive/NtfsHandler.cpp
new file mode 100644
index 0000000..c13e0ca
--- /dev/null
+++ b/CPP/7zip/Archive/NtfsHandler.cpp
@@ -0,0 +1,2861 @@
+// NtfsHandler.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+// #define SHOW_DEBUG_INFO2
+
+#if defined(SHOW_DEBUG_INFO) || defined(SHOW_DEBUG_INFO2)
+#include <stdio.h>
+#endif
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/MyCom.h"
+
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/TimeUtils.h"
+
+#include "../Common/MethodProps.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "Common/DummyOutStream.h"
+
+#ifdef SHOW_DEBUG_INFO
+#define PRF(x) x
+#define PRF_UTF16(x) PRF(printf("%S", x))
+#else
+#define PRF(x)
+#define PRF_UTF16(x)
+#endif
+
+#ifdef SHOW_DEBUG_INFO2
+#define PRF2(x) x
+#else
+#define PRF2(x)
+#endif
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+#define G16(p, dest) dest = Get16(p)
+#define G32(p, dest) dest = Get32(p)
+#define G64(p, dest) dest = Get64(p)
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace Ntfs {
+
+static const wchar_t * const kVirtualFolder_System = L"[SYSTEM]";
+static const wchar_t * const kVirtualFolder_Lost_Normal = L"[LOST]";
+static const wchar_t * const kVirtualFolder_Lost_Deleted = L"[UNKNOWN]";
+
+static const unsigned kNumSysRecs = 16;
+
+static const unsigned kRecIndex_Volume = 3;
+static const unsigned kRecIndex_RootDir = 5;
+static const unsigned kRecIndex_BadClus = 8;
+static const unsigned kRecIndex_Security = 9;
+
+struct CHeader
+{
+ unsigned SectorSizeLog;
+ unsigned ClusterSizeLog;
+ // Byte MediaType;
+ UInt32 NumHiddenSectors;
+ UInt64 NumSectors;
+ UInt64 NumClusters;
+ UInt64 MftCluster;
+ UInt64 SerialNumber;
+ UInt16 SectorsPerTrack;
+ UInt16 NumHeads;
+
+ UInt64 GetPhySize_Clusters() const { return NumClusters << ClusterSizeLog; }
+ UInt64 GetPhySize_Max() const { return (NumSectors + 1) << SectorSizeLog; }
+ UInt32 ClusterSize() const { return (UInt32)1 << ClusterSizeLog; }
+ bool Parse(const Byte *p);
+};
+
+static int GetLog(UInt32 num)
+{
+ for (int i = 0; i < 31; i++)
+ if (((UInt32)1 << i) == num)
+ return i;
+ return -1;
+}
+
+bool CHeader::Parse(const Byte *p)
+{
+ if (p[0x1FE] != 0x55 || p[0x1FF] != 0xAA)
+ return false;
+
+ // int codeOffset = 0;
+ switch (p[0])
+ {
+ case 0xE9: /* codeOffset = 3 + (Int16)Get16(p + 1); */ break;
+ case 0xEB: if (p[2] != 0x90) return false; /* codeOffset = 2 + (int)(signed char)p[1]; */ break;
+ default: return false;
+ }
+ unsigned sectorsPerClusterLog;
+
+ if (memcmp(p + 3, "NTFS ", 8) != 0)
+ return false;
+ {
+ int t = GetLog(Get16(p + 11));
+ if (t < 9 || t > 12)
+ return false;
+ SectorSizeLog = (unsigned)t;
+ t = GetLog(p[13]);
+ if (t < 0)
+ return false;
+ sectorsPerClusterLog = (unsigned)t;
+ ClusterSizeLog = SectorSizeLog + sectorsPerClusterLog;
+ if (ClusterSizeLog > 30)
+ return false;
+ }
+
+ for (int i = 14; i < 21; i++)
+ if (p[i] != 0)
+ return false;
+
+ if (p[21] != 0xF8) // MediaType = Fixed_Disk
+ return false;
+ if (Get16(p + 22) != 0) // NumFatSectors
+ return false;
+ G16(p + 24, SectorsPerTrack); // 63 usually
+ G16(p + 26, NumHeads); // 255
+ G32(p + 28, NumHiddenSectors); // 63 (XP) / 2048 (Vista and win7) / (0 on media that are not partitioned ?)
+ if (Get32(p + 32) != 0) // NumSectors32
+ return false;
+
+ // DriveNumber = p[0x24];
+ if (p[0x25] != 0) // CurrentHead
+ return false;
+ /*
+ NTFS-HDD: p[0x26] = 0x80
+ NTFS-FLASH: p[0x26] = 0
+ */
+ if (p[0x26] != 0x80 && p[0x26] != 0) // ExtendedBootSig
+ return false;
+ if (p[0x27] != 0) // reserved
+ return false;
+
+ NumSectors = Get64(p + 0x28);
+ if (NumSectors >= ((UInt64)1 << (62 - SectorSizeLog)))
+ return false;
+
+ NumClusters = NumSectors >> sectorsPerClusterLog;
+
+ G64(p + 0x30, MftCluster);
+ // G64(p + 0x38, Mft2Cluster);
+ G64(p + 0x48, SerialNumber);
+ UInt32 numClustersInMftRec;
+ UInt32 numClustersInIndexBlock;
+ G32(p + 0x40, numClustersInMftRec); // -10 means 2 ^10 = 1024 bytes.
+ G32(p + 0x44, numClustersInIndexBlock);
+ return (numClustersInMftRec < 256 && numClustersInIndexBlock < 256);
+}
+
+struct CMftRef
+{
+ UInt64 Val;
+
+ UInt64 GetIndex() const { return Val & (((UInt64)1 << 48) - 1); }
+ UInt16 GetNumber() const { return (UInt16)(Val >> 48); }
+ bool IsBaseItself() const { return Val == 0; }
+
+ CMftRef(): Val(0) {}
+};
+
+#define ATNAME(n) ATTR_TYPE_ ## n
+#define DEF_ATTR_TYPE(v, n) ATNAME(n) = v
+
+enum
+{
+ DEF_ATTR_TYPE(0x00, UNUSED),
+ DEF_ATTR_TYPE(0x10, STANDARD_INFO),
+ DEF_ATTR_TYPE(0x20, ATTRIBUTE_LIST),
+ DEF_ATTR_TYPE(0x30, FILE_NAME),
+ DEF_ATTR_TYPE(0x40, OBJECT_ID),
+ DEF_ATTR_TYPE(0x50, SECURITY_DESCRIPTOR),
+ DEF_ATTR_TYPE(0x60, VOLUME_NAME),
+ DEF_ATTR_TYPE(0x70, VOLUME_INFO),
+ DEF_ATTR_TYPE(0x80, DATA),
+ DEF_ATTR_TYPE(0x90, INDEX_ROOT),
+ DEF_ATTR_TYPE(0xA0, INDEX_ALLOCATION),
+ DEF_ATTR_TYPE(0xB0, BITMAP),
+ DEF_ATTR_TYPE(0xC0, REPARSE_POINT),
+ DEF_ATTR_TYPE(0xD0, EA_INFO),
+ DEF_ATTR_TYPE(0xE0, EA),
+ DEF_ATTR_TYPE(0xF0, PROPERTY_SET),
+ DEF_ATTR_TYPE(0x100, LOGGED_UTILITY_STREAM),
+ DEF_ATTR_TYPE(0x1000, FIRST_USER_DEFINED_ATTRIBUTE)
+};
+
+
+/* WinXP-64:
+ Probably only one short name (dos name) per record is allowed.
+ There are no short names for hard links.
+ The pair (Win32,Dos) can be in any order.
+ Posix name can be after or before Win32 name
+*/
+
+// static const Byte kFileNameType_Posix = 0; // for hard links
+static const Byte kFileNameType_Win32 = 1; // after Dos name
+static const Byte kFileNameType_Dos = 2; // short name
+static const Byte kFileNameType_Win32Dos = 3; // short and full name are same
+
+struct CFileNameAttr
+{
+ CMftRef ParentDirRef;
+
+ // Probably these timestamps don't contain some useful timestamps. So we don't use them
+ // UInt64 CTime;
+ // UInt64 MTime;
+ // UInt64 ThisRecMTime; // xp-64: the time of previous name change (not last name change. why?)
+ // UInt64 ATime;
+ // UInt64 AllocatedSize;
+ // UInt64 DataSize;
+ // UInt16 PackedEaSize;
+ UString2 Name;
+ UInt32 Attrib;
+ Byte NameType;
+
+ bool IsDos() const { return NameType == kFileNameType_Dos; }
+ bool IsWin32() const { return (NameType == kFileNameType_Win32); }
+
+ bool Parse(const Byte *p, unsigned size);
+
+ CFileNameAttr():
+ Attrib(0),
+ NameType(0)
+ {}
+};
+
+static void GetString(const Byte *p, unsigned len, UString2 &res)
+{
+ if (len == 0 && res.IsEmpty())
+ return;
+ wchar_t *s = res.GetBuf(len);
+ unsigned i;
+ for (i = 0; i < len; i++)
+ {
+ wchar_t c = Get16(p + i * 2);
+ if (c == 0)
+ break;
+ s[i] = c;
+ }
+ s[i] = 0;
+ res.ReleaseBuf_SetLen(i);
+}
+
+bool CFileNameAttr::Parse(const Byte *p, unsigned size)
+{
+ if (size < 0x42)
+ return false;
+ G64(p + 0x00, ParentDirRef.Val);
+ // G64(p + 0x08, CTime);
+ // G64(p + 0x10, MTime);
+ // G64(p + 0x18, ThisRecMTime);
+ // G64(p + 0x20, ATime);
+ // G64(p + 0x28, AllocatedSize);
+ // G64(p + 0x30, DataSize);
+ G32(p + 0x38, Attrib);
+ // G16(p + 0x3C, PackedEaSize);
+ NameType = p[0x41];
+ unsigned len = p[0x40];
+ if (0x42 + len > size)
+ return false;
+ if (len != 0)
+ GetString(p + 0x42, len, Name);
+ return true;
+}
+
+struct CSiAttr
+{
+ UInt64 CTime;
+ UInt64 MTime;
+ UInt64 ThisRecMTime;
+ UInt64 ATime;
+ UInt32 Attrib;
+
+ /*
+ UInt32 MaxVersions;
+ UInt32 Version;
+ UInt32 ClassId;
+ UInt32 OwnerId;
+ */
+ UInt32 SecurityId; // SecurityId = 0 is possible ?
+ // UInt64 QuotaCharged;
+
+ bool Parse(const Byte *p, unsigned size);
+
+ CSiAttr():
+ CTime(0),
+ MTime(0),
+ ThisRecMTime(0),
+ ATime(0),
+ Attrib(0),
+ SecurityId(0)
+ {}
+};
+
+
+bool CSiAttr::Parse(const Byte *p, unsigned size)
+{
+ if (size < 0x24)
+ return false;
+ G64(p + 0x00, CTime);
+ G64(p + 0x08, MTime);
+ G64(p + 0x10, ThisRecMTime);
+ G64(p + 0x18, ATime);
+ G32(p + 0x20, Attrib);
+ SecurityId = 0;
+ if (size >= 0x38)
+ G32(p + 0x34, SecurityId);
+ return true;
+}
+
+static const UInt64 kEmptyExtent = (UInt64)(Int64)-1;
+
+struct CExtent
+{
+ UInt64 Virt;
+ UInt64 Phy;
+
+ bool IsEmpty() const { return Phy == kEmptyExtent; }
+};
+
+struct CVolInfo
+{
+ Byte MajorVer;
+ Byte MinorVer;
+ // UInt16 Flags;
+
+ bool Parse(const Byte *p, unsigned size);
+};
+
+bool CVolInfo::Parse(const Byte *p, unsigned size)
+{
+ if (size < 12)
+ return false;
+ MajorVer = p[8];
+ MinorVer = p[9];
+ // Flags = Get16(p + 10);
+ return true;
+}
+
+struct CAttr
+{
+ UInt32 Type;
+
+ Byte NonResident;
+
+ // Non-Resident
+ Byte CompressionUnit;
+
+ // UInt32 Len;
+ UString2 Name;
+ // UInt16 Flags;
+ // UInt16 Instance;
+ CByteBuffer Data;
+
+ // Non-Resident
+ UInt64 LowVcn;
+ UInt64 HighVcn;
+ UInt64 AllocatedSize;
+ UInt64 Size;
+ UInt64 PackSize;
+ UInt64 InitializedSize;
+
+ // Resident
+ // UInt16 ResidentFlags;
+
+ bool IsCompressionUnitSupported() const { return CompressionUnit == 0 || CompressionUnit == 4; }
+
+ UInt32 Parse(const Byte *p, unsigned size);
+ bool ParseFileName(CFileNameAttr &a) const { return a.Parse(Data, (unsigned)Data.Size()); }
+ bool ParseSi(CSiAttr &a) const { return a.Parse(Data, (unsigned)Data.Size()); }
+ bool ParseVolInfo(CVolInfo &a) const { return a.Parse(Data, (unsigned)Data.Size()); }
+ bool ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, unsigned compressionUnit) const;
+ UInt64 GetSize() const { return NonResident ? Size : Data.Size(); }
+ UInt64 GetPackSize() const
+ {
+ if (!NonResident)
+ return Data.Size();
+ if (CompressionUnit != 0)
+ return PackSize;
+ return AllocatedSize;
+ }
+};
+
+#define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; }
+
+static int CompareAttr(void *const *elem1, void *const *elem2, void *)
+{
+ const CAttr &a1 = *(*((const CAttr *const *)elem1));
+ const CAttr &a2 = *(*((const CAttr *const *)elem2));
+ RINOZ(MyCompare(a1.Type, a2.Type))
+ if (a1.Name.IsEmpty())
+ {
+ if (!a2.Name.IsEmpty())
+ return -1;
+ }
+ else if (a2.Name.IsEmpty())
+ return 1;
+ else
+ {
+ RINOZ(a1.Name.Compare(a2.Name.GetRawPtr()))
+ }
+ return MyCompare(a1.LowVcn, a2.LowVcn);
+}
+
+UInt32 CAttr::Parse(const Byte *p, unsigned size)
+{
+ if (size < 4)
+ return 0;
+ G32(p, Type);
+ if (Type == 0xFFFFFFFF)
+ return 8; // required size is 4, but attributes are 8 bytes aligned. So we return 8
+ if (size < 0x18)
+ return 0;
+
+ PRF(printf(" T=%2X", Type));
+
+ UInt32 len = Get32(p + 4);
+ PRF(printf(" L=%3d", len));
+ if (len > size)
+ return 0;
+ if ((len & 7) != 0)
+ return 0;
+ NonResident = p[8];
+ {
+ unsigned nameLen = p[9];
+ UInt32 nameOffset = Get16(p + 0x0A);
+ if (nameLen != 0)
+ {
+ if (nameOffset + nameLen * 2 > len)
+ return 0;
+ GetString(p + nameOffset, nameLen, Name);
+ PRF(printf(" N="));
+ PRF_UTF16(Name);
+ }
+ }
+
+ // G16(p + 0x0C, Flags);
+ // G16(p + 0x0E, Instance);
+ // PRF(printf(" F=%4X", Flags));
+ // PRF(printf(" Inst=%d", Instance));
+
+ UInt32 dataSize;
+ UInt32 offs;
+
+ if (NonResident)
+ {
+ if (len < 0x40)
+ return 0;
+ PRF(printf(" NR"));
+ G64(p + 0x10, LowVcn);
+ G64(p + 0x18, HighVcn);
+ G64(p + 0x28, AllocatedSize);
+ G64(p + 0x30, Size);
+ G64(p + 0x38, InitializedSize);
+ G16(p + 0x20, offs);
+ CompressionUnit = p[0x22];
+
+ PackSize = Size;
+ if (CompressionUnit != 0)
+ {
+ if (len < 0x48)
+ return 0;
+ G64(p + 0x40, PackSize);
+ PRF(printf(" PS=%I64x", PackSize));
+ }
+
+ // PRF(printf("\n"));
+ PRF(printf(" ASize=%4I64d", AllocatedSize));
+ PRF(printf(" Size=%I64d", Size));
+ PRF(printf(" IS=%I64d", InitializedSize));
+ PRF(printf(" Low=%I64d", LowVcn));
+ PRF(printf(" High=%I64d", HighVcn));
+ PRF(printf(" CU=%d", (unsigned)CompressionUnit));
+ dataSize = len - offs;
+ }
+ else
+ {
+ if (len < 0x18)
+ return 0;
+ G32(p + 0x10, dataSize);
+ G16(p + 0x14, offs);
+ // G16(p + 0x16, ResidentFlags);
+ PRF(printf(" RES"));
+ PRF(printf(" dataSize=%3d", dataSize));
+ // PRF(printf(" ResFlags=%4X", ResidentFlags));
+ }
+
+ if (offs > len || dataSize > len || len - dataSize < offs)
+ return 0;
+
+ Data.CopyFrom(p + offs, dataSize);
+
+ #ifdef SHOW_DEBUG_INFO
+ PRF(printf(" : "));
+ for (unsigned i = 0; i < Data.Size(); i++)
+ {
+ PRF(printf(" %02X", (unsigned)Data[i]));
+ }
+ #endif
+
+ return len;
+}
+
+
+bool CAttr::ParseExtents(CRecordVector<CExtent> &extents, UInt64 numClustersMax, unsigned compressionUnit) const
+{
+ const Byte *p = Data;
+ unsigned size = (unsigned)Data.Size();
+ UInt64 vcn = LowVcn;
+ UInt64 lcn = 0;
+ const UInt64 highVcn1 = HighVcn + 1;
+
+ if (LowVcn != extents.Back().Virt || highVcn1 > (UInt64)1 << 63)
+ return false;
+
+ extents.DeleteBack();
+
+ PRF2(printf("\n# ParseExtents # LowVcn = %4I64X # HighVcn = %4I64X", LowVcn, HighVcn));
+
+ while (size > 0)
+ {
+ Byte b = *p++;
+ size--;
+ if (b == 0)
+ break;
+ UInt32 num = b & 0xF;
+ if (num == 0 || num > 8 || num > size)
+ return false;
+
+ UInt64 vSize = 0;
+ {
+ unsigned i = num;
+ do vSize = (vSize << 8) | p[--i]; while (i);
+ }
+ if (vSize == 0)
+ return false;
+ p += num;
+ size -= num;
+ if ((highVcn1 - vcn) < vSize)
+ return false;
+
+ CExtent e;
+ e.Virt = vcn;
+ vcn += vSize;
+
+ num = (b >> 4) & 0xF;
+ if (num > 8 || num > size)
+ return false;
+
+ if (num == 0)
+ {
+ // Sparse
+
+ /* if Unit is compressed, it can have many Elements for each compressed Unit:
+ and last Element for unit MUST be without LCN.
+ Element 0: numCompressedClusters2, LCN_0
+ Element 1: numCompressedClusters2, LCN_1
+ ...
+ Last Element : (16 - total_clusters_in_previous_elements), no LCN
+ */
+
+ // sparse is not allowed for (compressionUnit == 0) ? Why ?
+ if (compressionUnit == 0)
+ return false;
+
+ e.Phy = kEmptyExtent;
+ }
+ else
+ {
+ Int64 v = (signed char)p[num - 1];
+ {
+ for (unsigned i = num - 1; i != 0;)
+ v = (v << 8) | p[--i];
+ }
+ p += num;
+ size -= num;
+ lcn = (UInt64)((Int64)lcn + v);
+ if (lcn > numClustersMax)
+ return false;
+ e.Phy = lcn;
+ }
+
+ extents.Add(e);
+ }
+
+ CExtent e;
+ e.Phy = kEmptyExtent;
+ e.Virt = vcn;
+ extents.Add(e);
+ return (highVcn1 == vcn);
+}
+
+
+static const UInt64 kEmptyTag = (UInt64)(Int64)-1;
+
+static const unsigned kNumCacheChunksLog = 1;
+static const size_t kNumCacheChunks = (size_t)1 << kNumCacheChunksLog;
+
+Z7_CLASS_IMP_COM_1(
+ CInStream
+ , IInStream
+)
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+
+ UInt64 _virtPos;
+ UInt64 _physPos;
+ UInt64 _curRem;
+ bool _sparseMode;
+public:
+ bool InUse;
+private:
+ unsigned _chunkSizeLog;
+ CByteBuffer _inBuf;
+ CByteBuffer _outBuf;
+public:
+ UInt64 Size;
+ UInt64 InitializedSize;
+ unsigned BlockSizeLog;
+ unsigned CompressionUnit;
+ CRecordVector<CExtent> Extents;
+ CMyComPtr<IInStream> Stream;
+private:
+ UInt64 _tags[kNumCacheChunks];
+
+ HRESULT SeekToPhys() { return InStream_SeekSet(Stream, _physPos); }
+ UInt32 GetCuSize() const { return (UInt32)1 << (BlockSizeLog + CompressionUnit); }
+public:
+ HRESULT InitAndSeek(unsigned compressionUnit)
+ {
+ CompressionUnit = compressionUnit;
+ _chunkSizeLog = BlockSizeLog + CompressionUnit;
+ if (compressionUnit != 0)
+ {
+ UInt32 cuSize = GetCuSize();
+ _inBuf.Alloc(cuSize);
+ _outBuf.Alloc(kNumCacheChunks << _chunkSizeLog);
+ }
+ for (size_t i = 0; i < kNumCacheChunks; i++)
+ _tags[i] = kEmptyTag;
+
+ _sparseMode = false;
+ _curRem = 0;
+ _virtPos = 0;
+ _physPos = 0;
+ const CExtent &e = Extents[0];
+ if (!e.IsEmpty())
+ _physPos = e.Phy << BlockSizeLog;
+ return SeekToPhys();
+ }
+};
+
+static size_t Lznt1Dec(Byte *dest, size_t outBufLim, size_t destLen, const Byte *src, size_t srcLen)
+{
+ size_t destSize = 0;
+ while (destSize < destLen)
+ {
+ if (srcLen < 2 || (destSize & 0xFFF) != 0)
+ break;
+ UInt32 comprSize;
+ {
+ const UInt32 v = Get16(src);
+ if (v == 0)
+ break;
+ src += 2;
+ srcLen -= 2;
+ comprSize = (v & 0xFFF) + 1;
+ if (comprSize > srcLen)
+ break;
+ srcLen -= comprSize;
+ if ((v & 0x8000) == 0)
+ {
+ if (comprSize != (1 << 12))
+ break;
+ memcpy(dest + destSize, src, comprSize);
+ src += comprSize;
+ destSize += comprSize;
+ continue;
+ }
+ }
+ {
+ if (destSize + (1 << 12) > outBufLim || (src[0] & 1) != 0)
+ return 0;
+ unsigned numDistBits = 4;
+ UInt32 sbOffset = 0;
+ UInt32 pos = 0;
+
+ do
+ {
+ comprSize--;
+ for (UInt32 mask = src[pos++] | 0x100; mask > 1 && comprSize > 0; mask >>= 1)
+ {
+ if ((mask & 1) == 0)
+ {
+ if (sbOffset >= (1 << 12))
+ return 0;
+ dest[destSize++] = src[pos++];
+ sbOffset++;
+ comprSize--;
+ }
+ else
+ {
+ if (comprSize < 2)
+ return 0;
+ const UInt32 v = Get16(src + pos);
+ pos += 2;
+ comprSize -= 2;
+
+ while (((sbOffset - 1) >> numDistBits) != 0)
+ numDistBits++;
+
+ UInt32 len = (v & (0xFFFF >> numDistBits)) + 3;
+ if (sbOffset + len > (1 << 12))
+ return 0;
+ UInt32 dist = (v >> (16 - numDistBits));
+ if (dist >= sbOffset)
+ return 0;
+ const size_t offs = 1 + dist;
+ Byte *p = dest + destSize - offs;
+ destSize += len;
+ sbOffset += len;
+ const Byte *lim = p + len;
+ p[offs] = *p; ++p;
+ p[offs] = *p; ++p;
+ do
+ p[offs] = *p;
+ while (++p != lim);
+ }
+ }
+ }
+ while (comprSize > 0);
+ src += pos;
+ }
+ }
+ return destSize;
+}
+
+Z7_COM7F_IMF(CInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (_virtPos >= Size)
+ return (Size == _virtPos) ? S_OK: E_FAIL;
+ if (size == 0)
+ return S_OK;
+ {
+ const UInt64 rem = Size - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ if (_virtPos >= InitializedSize)
+ {
+ memset((Byte *)data, 0, size);
+ _virtPos += size;
+ *processedSize = size;
+ return S_OK;
+ }
+
+ {
+ const UInt64 rem = InitializedSize - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ while (_curRem == 0)
+ {
+ const UInt64 cacheTag = _virtPos >> _chunkSizeLog;
+ const size_t cacheIndex = (size_t)cacheTag & (kNumCacheChunks - 1);
+
+ if (_tags[cacheIndex] == cacheTag)
+ {
+ const size_t chunkSize = (size_t)1 << _chunkSizeLog;
+ const size_t offset = (size_t)_virtPos & (chunkSize - 1);
+ size_t cur = chunkSize - offset;
+ if (cur > size)
+ cur = size;
+ memcpy(data, _outBuf + (cacheIndex << _chunkSizeLog) + offset, cur);
+ *processedSize = (UInt32)cur;
+ _virtPos += cur;
+ return S_OK;
+ }
+
+ PRF2(printf("\nVirtPos = %6d", _virtPos));
+
+ const UInt32 comprUnitSize = (UInt32)1 << CompressionUnit;
+ const UInt64 virtBlock = _virtPos >> BlockSizeLog;
+ const UInt64 virtBlock2 = virtBlock & ~((UInt64)comprUnitSize - 1);
+
+ unsigned left = 0, right = Extents.Size();
+ for (;;)
+ {
+ unsigned mid = (left + right) / 2;
+ if (mid == left)
+ break;
+ if (virtBlock2 < Extents[mid].Virt)
+ right = mid;
+ else
+ left = mid;
+ }
+
+ bool isCompressed = false;
+ const UInt64 virtBlock2End = virtBlock2 + comprUnitSize;
+ if (CompressionUnit != 0)
+ for (unsigned i = left; i < Extents.Size(); i++)
+ {
+ const CExtent &e = Extents[i];
+ if (e.Virt >= virtBlock2End)
+ break;
+ if (e.IsEmpty())
+ {
+ isCompressed = true;
+ break;
+ }
+ }
+
+ unsigned i;
+ for (i = left; Extents[i + 1].Virt <= virtBlock; i++);
+
+ _sparseMode = false;
+ if (!isCompressed)
+ {
+ const CExtent &e = Extents[i];
+ UInt64 newPos = (e.Phy << BlockSizeLog) + _virtPos - (e.Virt << BlockSizeLog);
+ if (newPos != _physPos)
+ {
+ _physPos = newPos;
+ RINOK(SeekToPhys())
+ }
+ UInt64 next = Extents[i + 1].Virt;
+ if (next > virtBlock2End)
+ next &= ~((UInt64)comprUnitSize - 1);
+ next <<= BlockSizeLog;
+ if (next > Size)
+ next = Size;
+ _curRem = next - _virtPos;
+ break;
+ }
+
+ bool thereArePhy = false;
+
+ for (unsigned i2 = left; i2 < Extents.Size(); i2++)
+ {
+ const CExtent &e = Extents[i2];
+ if (e.Virt >= virtBlock2End)
+ break;
+ if (!e.IsEmpty())
+ {
+ thereArePhy = true;
+ break;
+ }
+ }
+
+ if (!thereArePhy)
+ {
+ _curRem = (Extents[i + 1].Virt << BlockSizeLog) - _virtPos;
+ _sparseMode = true;
+ break;
+ }
+
+ size_t offs = 0;
+ UInt64 curVirt = virtBlock2;
+
+ for (i = left; i < Extents.Size(); i++)
+ {
+ const CExtent &e = Extents[i];
+ if (e.IsEmpty())
+ break;
+ if (e.Virt >= virtBlock2End)
+ return S_FALSE;
+ const UInt64 newPos = (e.Phy + (curVirt - e.Virt)) << BlockSizeLog;
+ if (newPos != _physPos)
+ {
+ _physPos = newPos;
+ RINOK(SeekToPhys())
+ }
+ UInt64 numChunks = Extents[i + 1].Virt - curVirt;
+ if (curVirt + numChunks > virtBlock2End)
+ numChunks = virtBlock2End - curVirt;
+ const size_t compressed = (size_t)numChunks << BlockSizeLog;
+ RINOK(ReadStream_FALSE(Stream, _inBuf + offs, compressed))
+ curVirt += numChunks;
+ _physPos += compressed;
+ offs += compressed;
+ }
+
+ const size_t destLenMax = GetCuSize();
+ size_t destLen = destLenMax;
+ const UInt64 rem = Size - (virtBlock2 << BlockSizeLog);
+ if (destLen > rem)
+ destLen = (size_t)rem;
+
+ Byte *dest = _outBuf + (cacheIndex << _chunkSizeLog);
+ const size_t destSizeRes = Lznt1Dec(dest, destLenMax, destLen, _inBuf, offs);
+ _tags[cacheIndex] = cacheTag;
+
+ // some files in Vista have destSize > destLen
+ if (destSizeRes < destLen)
+ {
+ memset(dest, 0, destLenMax);
+ if (InUse)
+ return S_FALSE;
+ }
+ }
+
+ if (size > _curRem)
+ size = (UInt32)_curRem;
+ HRESULT res = S_OK;
+ if (_sparseMode)
+ memset(data, 0, size);
+ else
+ {
+ res = Stream->Read(data, size, &size);
+ _physPos += size;
+ }
+ if (processedSize)
+ *processedSize = size;
+ _virtPos += size;
+ _curRem -= size;
+ return res;
+}
+
+Z7_COM7F_IMF(CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += Size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ if (_virtPos != (UInt64)offset)
+ {
+ _curRem = 0;
+ _virtPos = (UInt64)offset;
+ }
+ if (newPosition)
+ *newPosition = (UInt64)offset;
+ return S_OK;
+}
+
+static HRESULT DataParseExtents(unsigned clusterSizeLog, const CObjectVector<CAttr> &attrs,
+ unsigned attrIndex, unsigned attrIndexLim, UInt64 numPhysClusters, CRecordVector<CExtent> &Extents)
+{
+ {
+ CExtent e;
+ e.Virt = 0;
+ e.Phy = kEmptyExtent;
+ Extents.Add(e);
+ }
+
+ const CAttr &attr0 = attrs[attrIndex];
+
+ /*
+ if (attrs[attrIndexLim - 1].HighVcn + 1 != (attr0.AllocatedSize >> clusterSizeLog))
+ {
+ }
+ */
+
+ if (attr0.AllocatedSize < attr0.Size ||
+ (attrs[attrIndexLim - 1].HighVcn + 1) != (attr0.AllocatedSize >> clusterSizeLog) ||
+ (attr0.AllocatedSize & ((1 << clusterSizeLog) - 1)) != 0)
+ return S_FALSE;
+
+ for (unsigned i = attrIndex; i < attrIndexLim; i++)
+ if (!attrs[i].ParseExtents(Extents, numPhysClusters, attr0.CompressionUnit))
+ return S_FALSE;
+
+ UInt64 packSizeCalc = 0;
+ FOR_VECTOR (k, Extents)
+ {
+ CExtent &e = Extents[k];
+ if (!e.IsEmpty())
+ packSizeCalc += (Extents[k + 1].Virt - e.Virt) << clusterSizeLog;
+ PRF2(printf("\nSize = %4I64X", Extents[k + 1].Virt - e.Virt));
+ PRF2(printf(" Pos = %4I64X", e.Phy));
+ }
+
+ if (attr0.CompressionUnit != 0)
+ {
+ if (packSizeCalc != attr0.PackSize)
+ return S_FALSE;
+ }
+ else
+ {
+ if (packSizeCalc != attr0.AllocatedSize)
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+struct CDataRef
+{
+ unsigned Start;
+ unsigned Num;
+};
+
+static const UInt32 kMagic_FILE = 0x454C4946;
+static const UInt32 kMagic_BAAD = 0x44414142;
+
+// 22.02: we support some rare case magic values:
+static const UInt32 kMagic_INDX = 0x58444e49;
+static const UInt32 kMagic_HOLE = 0x454c4f48;
+static const UInt32 kMagic_RSTR = 0x52545352;
+static const UInt32 kMagic_RCRD = 0x44524352;
+static const UInt32 kMagic_CHKD = 0x444b4843;
+static const UInt32 kMagic_FFFFFFFF = 0xFFFFFFFF;
+
+
+struct CMftRec
+{
+ UInt32 Magic;
+ // UInt64 Lsn;
+ UInt16 SeqNumber; // Number of times this mft record has been reused
+ UInt16 Flags;
+ // UInt16 LinkCount;
+ // UInt16 NextAttrInstance;
+ CMftRef BaseMftRef;
+ // UInt32 ThisRecNumber;
+
+ UInt32 MyNumNameLinks;
+ int MyItemIndex; // index in Items[] of main item for that record, or -1 if there is no item for that record
+
+ CObjectVector<CAttr> DataAttrs;
+ CObjectVector<CFileNameAttr> FileNames;
+ CRecordVector<CDataRef> DataRefs;
+ // CAttr SecurityAttr;
+
+ CSiAttr SiAttr;
+
+ CByteBuffer ReparseData;
+
+ int FindWin32Name_for_DosName(unsigned dosNameIndex) const
+ {
+ const CFileNameAttr &cur = FileNames[dosNameIndex];
+ if (cur.IsDos())
+ for (unsigned i = 0; i < FileNames.Size(); i++)
+ {
+ const CFileNameAttr &next = FileNames[i];
+ if (next.IsWin32() && cur.ParentDirRef.Val == next.ParentDirRef.Val)
+ return (int)i;
+ }
+ return -1;
+ }
+
+ int FindDosName(unsigned nameIndex) const
+ {
+ const CFileNameAttr &cur = FileNames[nameIndex];
+ if (cur.IsWin32())
+ for (unsigned i = 0; i < FileNames.Size(); i++)
+ {
+ const CFileNameAttr &next = FileNames[i];
+ if (next.IsDos() && cur.ParentDirRef.Val == next.ParentDirRef.Val)
+ return (int)i;
+ }
+ return -1;
+ }
+
+ /*
+ bool IsAltStream(int dataIndex) const
+ {
+ return dataIndex >= 0 && (
+ (IsDir() ||
+ !DataAttrs[DataRefs[dataIndex].Start].Name.IsEmpty()));
+ }
+ */
+
+ void MoveAttrsFrom(CMftRec &src)
+ {
+ DataAttrs += src.DataAttrs;
+ FileNames += src.FileNames;
+ src.DataAttrs.ClearAndFree();
+ src.FileNames.ClearAndFree();
+ }
+
+ UInt64 GetPackSize() const
+ {
+ UInt64 res = 0;
+ FOR_VECTOR (i, DataRefs)
+ res += DataAttrs[DataRefs[i].Start].GetPackSize();
+ return res;
+ }
+
+ bool Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 recNumber, CObjectVector<CAttr> *attrs);
+
+ bool Is_Magic_Empty() const
+ {
+ // what exact Magic values are possible for empty and unused records?
+ const UInt32 k_Magic_Unused_MAX = 5; // 22.02
+ return (Magic <= k_Magic_Unused_MAX);
+ }
+ bool Is_Magic_FILE() const { return (Magic == kMagic_FILE); }
+ // bool Is_Magic_BAAD() const { return (Magic == kMagic_BAAD); }
+ bool Is_Magic_CanIgnore() const
+ {
+ return Is_Magic_Empty()
+ || Magic == kMagic_BAAD
+ || Magic == kMagic_INDX
+ || Magic == kMagic_HOLE
+ || Magic == kMagic_RSTR
+ || Magic == kMagic_RCRD
+ || Magic == kMagic_CHKD
+ || Magic == kMagic_FFFFFFFF;
+ }
+
+ bool InUse() const { return (Flags & 1) != 0; }
+ bool IsDir() const { return (Flags & 2) != 0; }
+
+ void ParseDataNames();
+ HRESULT GetStream(IInStream *mainStream, int dataIndex,
+ unsigned clusterSizeLog, UInt64 numPhysClusters, IInStream **stream) const;
+ unsigned GetNumExtents(int dataIndex, unsigned clusterSizeLog, UInt64 numPhysClusters) const;
+
+ UInt64 GetSize(unsigned dataIndex) const { return DataAttrs[DataRefs[dataIndex].Start].GetSize(); }
+
+ CMftRec():
+ SeqNumber(0),
+ Flags(0),
+ MyNumNameLinks(0),
+ MyItemIndex(-1) {}
+};
+
+void CMftRec::ParseDataNames()
+{
+ DataRefs.Clear();
+ DataAttrs.Sort(CompareAttr, NULL);
+
+ for (unsigned i = 0; i < DataAttrs.Size();)
+ {
+ CDataRef ref;
+ ref.Start = i;
+ for (i++; i < DataAttrs.Size(); i++)
+ if (DataAttrs[ref.Start].Name != DataAttrs[i].Name)
+ break;
+ ref.Num = i - ref.Start;
+ DataRefs.Add(ref);
+ }
+}
+
+HRESULT CMftRec::GetStream(IInStream *mainStream, int dataIndex,
+ unsigned clusterSizeLog, UInt64 numPhysClusters, IInStream **destStream) const
+{
+ *destStream = NULL;
+ CBufferInStream *streamSpec = new CBufferInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+
+ if (dataIndex >= 0)
+ if ((unsigned)dataIndex < DataRefs.Size())
+ {
+ const CDataRef &ref = DataRefs[dataIndex];
+ unsigned numNonResident = 0;
+ unsigned i;
+ for (i = ref.Start; i < ref.Start + ref.Num; i++)
+ if (DataAttrs[i].NonResident)
+ numNonResident++;
+
+ const CAttr &attr0 = DataAttrs[ref.Start];
+
+ if (numNonResident != 0 || ref.Num != 1)
+ {
+ if (numNonResident != ref.Num || !attr0.IsCompressionUnitSupported())
+ return S_FALSE;
+ CInStream *ss = new CInStream;
+ CMyComPtr<IInStream> streamTemp2 = ss;
+ RINOK(DataParseExtents(clusterSizeLog, DataAttrs, ref.Start, ref.Start + ref.Num, numPhysClusters, ss->Extents))
+ ss->Size = attr0.Size;
+ ss->InitializedSize = attr0.InitializedSize;
+ ss->Stream = mainStream;
+ ss->BlockSizeLog = clusterSizeLog;
+ ss->InUse = InUse();
+ RINOK(ss->InitAndSeek(attr0.CompressionUnit))
+ *destStream = streamTemp2.Detach();
+ return S_OK;
+ }
+
+ streamSpec->Buf = attr0.Data;
+ }
+
+ streamSpec->Init();
+ *destStream = streamTemp.Detach();
+ return S_OK;
+}
+
+unsigned CMftRec::GetNumExtents(int dataIndex, unsigned clusterSizeLog, UInt64 numPhysClusters) const
+{
+ if (dataIndex < 0)
+ return 0;
+ {
+ const CDataRef &ref = DataRefs[dataIndex];
+ unsigned numNonResident = 0;
+ unsigned i;
+ for (i = ref.Start; i < ref.Start + ref.Num; i++)
+ if (DataAttrs[i].NonResident)
+ numNonResident++;
+
+ const CAttr &attr0 = DataAttrs[ref.Start];
+
+ if (numNonResident != 0 || ref.Num != 1)
+ {
+ if (numNonResident != ref.Num || !attr0.IsCompressionUnitSupported())
+ return 0; // error;
+ CRecordVector<CExtent> extents;
+ if (DataParseExtents(clusterSizeLog, DataAttrs, ref.Start, ref.Start + ref.Num, numPhysClusters, extents) != S_OK)
+ return 0; // error;
+ return extents.Size() - 1;
+ }
+ // if (attr0.Data.Size() != 0)
+ // return 1;
+ return 0;
+ }
+}
+
+bool CMftRec::Parse(Byte *p, unsigned sectorSizeLog, UInt32 numSectors, UInt32 recNumber,
+ CObjectVector<CAttr> *attrs)
+{
+ G32(p, Magic);
+ if (!Is_Magic_FILE())
+ return Is_Magic_CanIgnore();
+
+ {
+ UInt32 usaOffset;
+ UInt32 numUsaItems;
+ G16(p + 0x04, usaOffset);
+ G16(p + 0x06, numUsaItems);
+
+ /* NTFS stores (usn) to 2 last bytes in each sector (before writing record to disk).
+ Original values of these two bytes are stored in table.
+ So we restore original data from table */
+
+ if ((usaOffset & 1) != 0
+ || usaOffset + numUsaItems * 2 > ((UInt32)1 << sectorSizeLog) - 2
+ || numUsaItems == 0
+ || numUsaItems - 1 != numSectors)
+ return false;
+
+ if (usaOffset >= 0x30) // NTFS 3.1+
+ {
+ UInt32 iii = Get32(p + 0x2C);
+ if (iii != recNumber)
+ {
+ // ntfs-3g probably writes 0 (that probably is incorrect value) to this field for unused records.
+ // so we support that "bad" case.
+ if (iii != 0)
+ return false;
+ }
+ }
+
+ UInt16 usn = Get16(p + usaOffset);
+ // PRF(printf("\nusn = %d", usn));
+ for (UInt32 i = 1; i < numUsaItems; i++)
+ {
+ void *pp = p + (i << sectorSizeLog) - 2;
+ if (Get16(pp) != usn)
+ return false;
+ SetUi16(pp, Get16(p + usaOffset + i * 2))
+ }
+ }
+
+ // G64(p + 0x08, Lsn);
+ G16(p + 0x10, SeqNumber);
+ // G16(p + 0x12, LinkCount);
+ // PRF(printf(" L=%d", LinkCount));
+ UInt32 attrOffs = Get16(p + 0x14);
+ G16(p + 0x16, Flags);
+ PRF(printf(" F=%4X", Flags));
+
+ UInt32 bytesInUse = Get32(p + 0x18);
+ UInt32 bytesAlloc = Get32(p + 0x1C);
+ G64(p + 0x20, BaseMftRef.Val);
+ if (BaseMftRef.Val != 0)
+ {
+ PRF(printf(" BaseRef=%d", (int)BaseMftRef.Val));
+ // return false; // Check it;
+ }
+ // G16(p + 0x28, NextAttrInstance);
+
+ UInt32 limit = numSectors << sectorSizeLog;
+ if (attrOffs >= limit
+ || (attrOffs & 7) != 0
+ || (bytesInUse & 7) != 0
+ || bytesInUse > limit
+ || bytesAlloc != limit)
+ return false;
+
+ limit = bytesInUse;
+
+ for (UInt32 t = attrOffs;;)
+ {
+ if (t >= limit)
+ return false;
+
+ CAttr attr;
+ // PRF(printf("\n %2d:", Attrs.Size()));
+ PRF(printf("\n"));
+ UInt32 len = attr.Parse(p + t, limit - t);
+ if (len == 0 || limit - t < len)
+ return false;
+ t += len;
+ if (attr.Type == 0xFFFFFFFF)
+ {
+ if (t != limit)
+ return false;
+ break;
+ }
+ switch (attr.Type)
+ {
+ case ATTR_TYPE_FILE_NAME:
+ {
+ CFileNameAttr fna;
+ if (!attr.ParseFileName(fna))
+ return false;
+ FileNames.Add(fna);
+ PRF(printf(" flags = %4x\n ", (int)fna.NameType));
+ PRF_UTF16(fna.Name);
+ break;
+ }
+ case ATTR_TYPE_STANDARD_INFO:
+ if (!attr.ParseSi(SiAttr))
+ return false;
+ break;
+ case ATTR_TYPE_DATA:
+ DataAttrs.Add(attr);
+ break;
+ case ATTR_TYPE_REPARSE_POINT:
+ ReparseData = attr.Data;
+ break;
+ /*
+ case ATTR_TYPE_SECURITY_DESCRIPTOR:
+ SecurityAttr = attr;
+ break;
+ */
+ default:
+ if (attrs)
+ attrs->Add(attr);
+ break;
+ }
+ }
+
+ return true;
+}
+
+/*
+ NTFS probably creates empty DATA_ATTRIBUTE for empty file,
+ But it doesn't do it for
+ $Secure (:$SDS),
+ $Extend\$Quota
+ $Extend\$ObjId
+ $Extend\$Reparse
+*/
+
+static const int k_Item_DataIndex_IsEmptyFile = -1; // file without unnamed data stream
+static const int k_Item_DataIndex_IsDir = -2;
+
+// static const int k_ParentFolderIndex_Root = -1;
+static const int k_ParentFolderIndex_Lost = -2;
+static const int k_ParentFolderIndex_Deleted = -3;
+
+struct CItem
+{
+ unsigned RecIndex; // index in Recs array
+ unsigned NameIndex; // index in CMftRec::FileNames
+
+ int DataIndex; /* index in CMftRec::DataRefs
+ -1: file without unnamed data stream
+ -2: for directories */
+
+ int ParentFolder; /* index in Items array
+ -1: for root items
+ -2: [LOST] folder
+ -3: [UNKNOWN] folder (deleted lost) */
+ int ParentHost; /* index in Items array, if it's AltStream
+ -1: if it's not AltStream */
+
+ CItem(): DataIndex(k_Item_DataIndex_IsDir), ParentFolder(-1), ParentHost(-1) {}
+
+ bool IsAltStream() const { return ParentHost != -1; }
+ bool IsDir() const { return DataIndex == k_Item_DataIndex_IsDir; }
+ // check it !!!
+ // probably NTFS for empty file still creates empty DATA_ATTRIBUTE
+ // But it doesn't do it for $Secure:$SDS
+};
+
+struct CDatabase
+{
+ CRecordVector<CItem> Items;
+ CObjectVector<CMftRec> Recs;
+ CMyComPtr<IInStream> InStream;
+ CHeader Header;
+ unsigned RecSizeLog;
+ UInt64 PhySize;
+
+ IArchiveOpenCallback *OpenCallback;
+
+ CByteBuffer ByteBuf;
+
+ CObjectVector<CAttr> VolAttrs;
+
+ CByteBuffer SecurData;
+ CRecordVector<size_t> SecurOffsets;
+
+ bool _showSystemFiles;
+ bool _showDeletedFiles;
+ CObjectVector<UString2> VirtFolderNames;
+ UString EmptyString;
+
+ int _systemFolderIndex;
+ int _lostFolderIndex_Normal;
+ int _lostFolderIndex_Deleted;
+
+ // bool _headerWarning;
+
+ bool ThereAreAltStreams;
+
+ void InitProps()
+ {
+ _showSystemFiles = true;
+ // we show SystemFiles by default since it's difficult to track $Extend\* system files
+ // it must be fixed later
+ _showDeletedFiles = false;
+ }
+
+ CDatabase() { InitProps(); }
+ ~CDatabase() { ClearAndClose(); }
+
+ void Clear();
+ void ClearAndClose();
+
+ void GetItemPath(unsigned index, NCOM::CPropVariant &path) const;
+ HRESULT Open();
+
+ HRESULT SeekToCluster(UInt64 cluster);
+
+ int FindDirItemForMtfRec(UInt64 recIndex) const
+ {
+ if (recIndex >= Recs.Size())
+ return -1;
+ const CMftRec &rec = Recs[(unsigned)recIndex];
+ if (!rec.IsDir())
+ return -1;
+ return rec.MyItemIndex;
+ /*
+ unsigned left = 0, right = Items.Size();
+ while (left != right)
+ {
+ unsigned mid = (left + right) / 2;
+ const CItem &item = Items[mid];
+ UInt64 midValue = item.RecIndex;
+ if (recIndex == midValue)
+ {
+ // if item is not dir (file or alt stream we don't return it)
+ // if (item.DataIndex < 0)
+ if (item.IsDir())
+ return mid;
+ right = mid;
+ }
+ else if (recIndex < midValue)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+ */
+ }
+
+ bool FindSecurityDescritor(UInt32 id, UInt64 &offset, UInt32 &size) const;
+
+ HRESULT ParseSecuritySDS_2();
+ void ParseSecuritySDS()
+ {
+ HRESULT res = ParseSecuritySDS_2();
+ if (res != S_OK)
+ {
+ SecurOffsets.Clear();
+ SecurData.Free();
+ }
+ }
+
+};
+
+HRESULT CDatabase::SeekToCluster(UInt64 cluster)
+{
+ return InStream_SeekSet(InStream, cluster << Header.ClusterSizeLog);
+}
+
+void CDatabase::Clear()
+{
+ Items.Clear();
+ Recs.Clear();
+ SecurOffsets.Clear();
+ SecurData.Free();
+ VirtFolderNames.Clear();
+ _systemFolderIndex = -1;
+ _lostFolderIndex_Normal = -1;
+ _lostFolderIndex_Deleted = -1;
+ ThereAreAltStreams = false;
+ // _headerWarning = false;
+ PhySize = 0;
+}
+
+void CDatabase::ClearAndClose()
+{
+ Clear();
+ InStream.Release();
+}
+
+
+static void CopyName(wchar_t *dest, const wchar_t *src)
+{
+ for (;;)
+ {
+ wchar_t c = *src++;
+ // 18.06
+ if (c == '\\' || c == '/')
+ c = '_';
+ *dest++ = c;
+ if (c == 0)
+ return;
+ }
+}
+
+void CDatabase::GetItemPath(unsigned index, NCOM::CPropVariant &path) const
+{
+ const CItem *item = &Items[index];
+ unsigned size = 0;
+ const CMftRec &rec = Recs[item->RecIndex];
+ size += rec.FileNames[item->NameIndex].Name.Len();
+
+ bool isAltStream = item->IsAltStream();
+
+ if (isAltStream)
+ {
+ const CAttr &data = rec.DataAttrs[rec.DataRefs[item->DataIndex].Start];
+ if (item->RecIndex == kRecIndex_RootDir)
+ {
+ wchar_t *s = path.AllocBstr(data.Name.Len() + 1);
+ s[0] = L':';
+ if (!data.Name.IsEmpty())
+ CopyName(s + 1, data.Name.GetRawPtr());
+ return;
+ }
+
+ size += data.Name.Len();
+ size++;
+ }
+
+ for (unsigned i = 0;; i++)
+ {
+ if (i > 256)
+ {
+ path = "[TOO-LONG]";
+ return;
+ }
+ const wchar_t *servName;
+ if (item->RecIndex < kNumSysRecs
+ /* && item->RecIndex != kRecIndex_RootDir */)
+ servName = kVirtualFolder_System;
+ else
+ {
+ int index2 = item->ParentFolder;
+ if (index2 >= 0)
+ {
+ item = &Items[index2];
+ size += Recs[item->RecIndex].FileNames[item->NameIndex].Name.Len() + 1;
+ continue;
+ }
+ if (index2 == -1)
+ break;
+ servName = (index2 == k_ParentFolderIndex_Lost) ?
+ kVirtualFolder_Lost_Normal :
+ kVirtualFolder_Lost_Deleted;
+ }
+ size += MyStringLen(servName) + 1;
+ break;
+ }
+
+ wchar_t *s = path.AllocBstr(size);
+
+ item = &Items[index];
+
+ bool needColon = false;
+ if (isAltStream)
+ {
+ const UString2 &name = rec.DataAttrs[rec.DataRefs[item->DataIndex].Start].Name;
+ if (!name.IsEmpty())
+ {
+ size -= name.Len();
+ CopyName(s + size, name.GetRawPtr());
+ }
+ s[--size] = ':';
+ needColon = true;
+ }
+
+ {
+ const UString2 &name = rec.FileNames[item->NameIndex].Name;
+ unsigned len = name.Len();
+ if (len != 0)
+ CopyName(s + size - len, name.GetRawPtr());
+ if (needColon)
+ s[size] = ':';
+ size -= len;
+ }
+
+ for (;;)
+ {
+ const wchar_t *servName;
+ if (item->RecIndex < kNumSysRecs
+ /* && && item->RecIndex != kRecIndex_RootDir */)
+ servName = kVirtualFolder_System;
+ else
+ {
+ int index2 = item->ParentFolder;
+ if (index2 >= 0)
+ {
+ item = &Items[index2];
+ const UString2 &name = Recs[item->RecIndex].FileNames[item->NameIndex].Name;
+ unsigned len = name.Len();
+ size--;
+ if (len != 0)
+ {
+ size -= len;
+ CopyName(s + size, name.GetRawPtr());
+ }
+ s[size + len] = WCHAR_PATH_SEPARATOR;
+ continue;
+ }
+ if (index2 == -1)
+ break;
+ servName = (index2 == k_ParentFolderIndex_Lost) ?
+ kVirtualFolder_Lost_Normal :
+ kVirtualFolder_Lost_Deleted;
+ }
+ MyStringCopy(s, servName);
+ s[MyStringLen(servName)] = WCHAR_PATH_SEPARATOR;
+ break;
+ }
+}
+
+bool CDatabase::FindSecurityDescritor(UInt32 item, UInt64 &offset, UInt32 &size) const
+{
+ offset = 0;
+ size = 0;
+ unsigned left = 0, right = SecurOffsets.Size();
+ while (left != right)
+ {
+ unsigned mid = (left + right) / 2;
+ size_t offs = SecurOffsets[mid];
+ UInt32 midValue = Get32(((const Byte *)SecurData) + offs + 4);
+ if (item == midValue)
+ {
+ offset = Get64((const Byte *)SecurData + offs + 8) + 20;
+ size = Get32((const Byte *)SecurData + offs + 16) - 20;
+ return true;
+ }
+ if (item < midValue)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return false;
+}
+
+/*
+static int CompareIDs(const size_t *p1, const size_t *p2, void *data)
+{
+ UInt32 id1 = Get32(((const Byte *)data) + *p1 + 4);
+ UInt32 id2 = Get32(((const Byte *)data) + *p2 + 4);
+ return MyCompare(id1, id2);
+}
+*/
+
+// security data contains duplication copy after each 256 KB.
+static const unsigned kSecureDuplicateStepBits = 18;
+
+HRESULT CDatabase::ParseSecuritySDS_2()
+{
+ const Byte *p = SecurData;
+ size_t size = SecurData.Size();
+ const size_t kDuplicateStep = (size_t)1 << kSecureDuplicateStepBits;
+ const size_t kDuplicateMask = kDuplicateStep - 1;
+ size_t lim = MyMin(size, kDuplicateStep);
+ UInt32 idPrev = 0;
+ for (size_t pos = 0; pos < size && size - pos >= 20;)
+ {
+ UInt32 id = Get32(p + pos + 4);
+ UInt64 offs = Get64(p + pos + 8);
+ UInt32 entrySize = Get32(p + pos + 16);
+ if (offs == pos && entrySize >= 20 && lim - pos >= entrySize)
+ {
+ if (id <= idPrev)
+ return S_FALSE;
+ idPrev = id;
+ SecurOffsets.Add(pos);
+ pos += entrySize;
+ pos = (pos + 0xF) & ~(size_t)0xF;
+ if ((pos & kDuplicateMask) != 0)
+ continue;
+ }
+ else
+ pos = (pos + kDuplicateStep) & ~kDuplicateMask;
+ pos += kDuplicateStep;
+ lim = pos + kDuplicateStep;
+ if (lim >= size)
+ lim = size;
+ }
+ // we checked that IDs are sorted, so we don't need Sort
+ // SecurOffsets.Sort(CompareIDs, (void *)p);
+ return S_OK;
+}
+
+HRESULT CDatabase::Open()
+{
+ Clear();
+
+ /* NTFS layout:
+ 1) main part (as specified by NumClusters). Only that part is available, if we open "\\.\c:"
+ 2) additional empty sectors (as specified by NumSectors)
+ 3) the copy of first sector (boot sector)
+
+ We support both cases:
+ - the file with only main part
+ - full file (as raw data on partition), including the copy
+ of first sector (boot sector) at the end of data
+
+ We don't support the case, when only the copy of boot sector
+ at the end was detected as NTFS signature.
+ */
+
+ {
+ const UInt32 kHeaderSize = 512;
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(InStream, buf, kHeaderSize))
+ if (!Header.Parse(buf))
+ return S_FALSE;
+
+ UInt64 fileSize;
+ RINOK(InStream_GetSize_SeekToEnd(InStream, fileSize))
+ PhySize = Header.GetPhySize_Clusters();
+ if (fileSize < PhySize)
+ return S_FALSE;
+
+ UInt64 phySizeMax = Header.GetPhySize_Max();
+ if (fileSize >= phySizeMax)
+ {
+ RINOK(InStream_SeekSet(InStream, Header.NumSectors << Header.SectorSizeLog))
+ Byte buf2[kHeaderSize];
+ if (ReadStream_FALSE(InStream, buf2, kHeaderSize) == S_OK)
+ {
+ if (memcmp(buf, buf2, kHeaderSize) == 0)
+ PhySize = phySizeMax;
+ // else _headerWarning = true;
+ }
+ }
+ }
+
+ SeekToCluster(Header.MftCluster);
+
+ CMftRec mftRec;
+ UInt32 numSectorsInRec;
+
+ CMyComPtr<IInStream> mftStream;
+ {
+ UInt32 blockSize = 1 << 12;
+ ByteBuf.Alloc(blockSize);
+ RINOK(ReadStream_FALSE(InStream, ByteBuf, blockSize))
+
+ {
+ const UInt32 allocSize = Get32(ByteBuf + 0x1C);
+ const int t = GetLog(allocSize);
+ if (t < (int)Header.SectorSizeLog)
+ return S_FALSE;
+ RecSizeLog = (unsigned)t;
+ if (RecSizeLog > 15)
+ return S_FALSE;
+ }
+
+ numSectorsInRec = 1 << (RecSizeLog - Header.SectorSizeLog);
+ if (!mftRec.Parse(ByteBuf, Header.SectorSizeLog, numSectorsInRec, 0, NULL))
+ return S_FALSE;
+ if (!mftRec.Is_Magic_FILE())
+ return S_FALSE;
+ mftRec.ParseDataNames();
+ if (mftRec.DataRefs.IsEmpty())
+ return S_FALSE;
+ RINOK(mftRec.GetStream(InStream, 0, Header.ClusterSizeLog, Header.NumClusters, &mftStream))
+ if (!mftStream)
+ return S_FALSE;
+ }
+
+ // CObjectVector<CAttr> SecurityAttrs;
+
+ UInt64 mftSize = mftRec.DataAttrs[0].Size;
+ if ((mftSize >> 4) > Header.GetPhySize_Clusters())
+ return S_FALSE;
+
+ const size_t kBufSize = (1 << 15);
+ const size_t recSize = ((size_t)1 << RecSizeLog);
+ if (kBufSize < recSize)
+ return S_FALSE;
+
+ {
+ const UInt64 numFiles = mftSize >> RecSizeLog;
+ if (numFiles > (1 << 30))
+ return S_FALSE;
+ if (OpenCallback)
+ {
+ RINOK(OpenCallback->SetTotal(&numFiles, &mftSize))
+ }
+
+ ByteBuf.Alloc(kBufSize);
+ Recs.ClearAndReserve((unsigned)numFiles);
+ }
+
+ for (UInt64 pos64 = 0;;)
+ {
+ if (OpenCallback)
+ {
+ const UInt64 numFiles = Recs.Size();
+ if ((numFiles & 0x3FFF) == 0)
+ {
+ RINOK(OpenCallback->SetCompleted(&numFiles, &pos64))
+ }
+ }
+ size_t readSize = kBufSize;
+ {
+ const UInt64 rem = mftSize - pos64;
+ if (readSize > rem)
+ readSize = (size_t)rem;
+ }
+ if (readSize < recSize)
+ break;
+ RINOK(ReadStream_FALSE(mftStream, ByteBuf, readSize))
+ pos64 += readSize;
+
+ for (size_t i = 0; readSize >= recSize; i += recSize, readSize -= recSize)
+ {
+ PRF(printf("\n---------------------"));
+ PRF(printf("\n%5d:", Recs.Size()));
+
+ Byte *p = ByteBuf + i;
+ CMftRec rec;
+
+ CObjectVector<CAttr> *attrs = NULL;
+ unsigned recIndex = Recs.Size();
+ switch (recIndex)
+ {
+ case kRecIndex_Volume: attrs = &VolAttrs; break;
+ // case kRecIndex_Security: attrs = &SecurityAttrs; break;
+ }
+
+ if (!rec.Parse(p, Header.SectorSizeLog, numSectorsInRec, (UInt32)Recs.Size(), attrs))
+ return S_FALSE;
+ Recs.Add(rec);
+ }
+ }
+
+ /*
+ // that code looks too complex. And we can get security info without index parsing
+ for (i = 0; i < SecurityAttrs.Size(); i++)
+ {
+ const CAttr &attr = SecurityAttrs[i];
+ if (attr.Name == L"$SII")
+ {
+ if (attr.Type == ATTR_TYPE_INDEX_ROOT)
+ {
+ const Byte *data = attr.Data;
+ size_t size = attr.Data.Size();
+
+ // Index Root
+ UInt32 attrType = Get32(data);
+ UInt32 collationRule = Get32(data + 4);
+ UInt32 indexAllocationEtrySizeSize = Get32(data + 8);
+ UInt32 clustersPerIndexRecord = Get32(data + 0xC);
+ data += 0x10;
+
+ // Index Header
+ UInt32 firstEntryOffset = Get32(data);
+ UInt32 totalSize = Get32(data + 4);
+ UInt32 allocSize = Get32(data + 8);
+ UInt32 flags = Get32(data + 0xC);
+
+ int num = 0;
+ for (int j = 0 ; j < num; j++)
+ {
+ if (Get32(data) != 0x1414 || // offset and size
+ Get32(data + 4) != 0 ||
+ Get32(data + 8) != 0x428) // KeySize / EntrySize
+ break;
+ UInt32 flags = Get32(data + 12);
+ UInt32 id = Get32(data + 0x10);
+ if (id = Get32(data + 0x18))
+ break;
+ UInt32 descriptorOffset = Get64(data + 0x1C);
+ UInt32 descriptorSize = Get64(data + 0x24);
+ data += 0x28;
+ }
+ // break;
+ }
+ }
+ }
+ */
+
+ unsigned i;
+
+ for (i = 0; i < Recs.Size(); i++)
+ {
+ CMftRec &rec = Recs[i];
+ if (!rec.Is_Magic_FILE())
+ continue;
+
+ if (!rec.BaseMftRef.IsBaseItself())
+ {
+ const UInt64 refIndex = rec.BaseMftRef.GetIndex();
+ if (refIndex >= Recs.Size())
+ return S_FALSE;
+ CMftRec &refRec = Recs[(unsigned)refIndex];
+ if (!refRec.Is_Magic_FILE())
+ continue;
+
+ bool moveAttrs = (refRec.SeqNumber == rec.BaseMftRef.GetNumber() && refRec.BaseMftRef.IsBaseItself());
+ if (rec.InUse() && refRec.InUse())
+ {
+ if (!moveAttrs)
+ return S_FALSE;
+ }
+ else if (rec.InUse() || refRec.InUse())
+ moveAttrs = false;
+ if (moveAttrs)
+ refRec.MoveAttrsFrom(rec);
+ }
+ }
+
+ for (i = 0; i < Recs.Size(); i++)
+ {
+ CMftRec &rec = Recs[i];
+ if (!rec.Is_Magic_FILE())
+ continue;
+ rec.ParseDataNames();
+ }
+
+ for (i = 0; i < Recs.Size(); i++)
+ {
+ CMftRec &rec = Recs[i];
+ if (!rec.Is_Magic_FILE() || !rec.BaseMftRef.IsBaseItself())
+ continue;
+ if (i < kNumSysRecs && !_showSystemFiles)
+ continue;
+ if (!rec.InUse() && !_showDeletedFiles)
+ continue;
+
+ rec.MyNumNameLinks = rec.FileNames.Size();
+
+ // printf("\n%4d: ", i);
+
+ /* Actually DataAttrs / DataRefs are sorted by name.
+ It can not be more than one unnamed stream in DataRefs
+ And indexOfUnnamedStream <= 0.
+ */
+
+ int indexOfUnnamedStream = -1;
+ if (!rec.IsDir())
+ {
+ FOR_VECTOR (di, rec.DataRefs)
+ if (rec.DataAttrs[rec.DataRefs[di].Start].Name.IsEmpty())
+ {
+ indexOfUnnamedStream = (int)di;
+ break;
+ }
+ }
+
+ if (rec.FileNames.IsEmpty())
+ {
+ bool needShow = true;
+ if (i < kNumSysRecs)
+ {
+ needShow = false;
+ FOR_VECTOR (di, rec.DataRefs)
+ if (rec.GetSize(di) != 0)
+ {
+ needShow = true;
+ break;
+ }
+ }
+ if (needShow)
+ {
+ CFileNameAttr &fna = rec.FileNames.AddNew();
+ // we set incorrect ParentDirRef, that will place item to [LOST] folder
+ fna.ParentDirRef.Val = (UInt64)(Int64)-1;
+ char s[16 + 16];
+ ConvertUInt32ToString(i, MyStpCpy(s, "[NONAME]-"));
+ fna.Name.SetFromAscii(s);
+ fna.NameType = kFileNameType_Win32Dos;
+ fna.Attrib = 0;
+ }
+ }
+
+ // bool isMainName = true;
+
+ FOR_VECTOR (t, rec.FileNames)
+ {
+ #ifdef SHOW_DEBUG_INFO
+ const CFileNameAttr &fna = rec.FileNames[t];
+ #endif
+ PRF(printf("\n %4d ", (int)fna.NameType));
+ PRF_UTF16(fna.Name);
+ // PRF(printf(" | "));
+
+ if (rec.FindWin32Name_for_DosName(t) >= 0)
+ {
+ rec.MyNumNameLinks--;
+ continue;
+ }
+
+ CItem item;
+ item.NameIndex = t;
+ item.RecIndex = i;
+ item.DataIndex = rec.IsDir() ?
+ k_Item_DataIndex_IsDir :
+ (indexOfUnnamedStream < 0 ?
+ k_Item_DataIndex_IsEmptyFile :
+ indexOfUnnamedStream);
+
+ if (rec.MyItemIndex < 0)
+ rec.MyItemIndex = (int)Items.Size();
+ item.ParentHost = (int)Items.Add(item);
+
+ /* we can use that code to reduce the number of alt streams:
+ it will not show how alt streams for hard links. */
+ // if (!isMainName) continue; isMainName = false;
+
+ // unsigned numAltStreams = 0;
+
+ FOR_VECTOR (di, rec.DataRefs)
+ {
+ if (!rec.IsDir() && (int)di == indexOfUnnamedStream)
+ continue;
+
+ const UString2 &subName = rec.DataAttrs[rec.DataRefs[di].Start].Name;
+
+ PRF(printf("\n alt stream: "));
+ PRF_UTF16(subName);
+
+ {
+ // $BadClus:$Bad is sparse file for all clusters. So we skip it.
+ if (i == kRecIndex_BadClus && subName == L"$Bad")
+ continue;
+ }
+
+ // numAltStreams++;
+ ThereAreAltStreams = true;
+ item.DataIndex = (int)di;
+ Items.Add(item);
+ }
+ }
+ }
+
+ if (Recs.Size() > kRecIndex_Security)
+ {
+ const CMftRec &rec = Recs[kRecIndex_Security];
+ FOR_VECTOR (di, rec.DataRefs)
+ {
+ const CAttr &attr = rec.DataAttrs[rec.DataRefs[di].Start];
+ if (attr.Name == L"$SDS")
+ {
+ CMyComPtr<IInStream> sdsStream;
+ RINOK(rec.GetStream(InStream, (int)di, Header.ClusterSizeLog, Header.NumClusters, &sdsStream))
+ if (sdsStream)
+ {
+ const UInt64 size64 = attr.GetSize();
+ if (size64 < (UInt32)1 << 29)
+ {
+ size_t size = (size_t)size64;
+ if ((((size + 1) >> kSecureDuplicateStepBits) & 1) != 0)
+ {
+ size -= (1 << kSecureDuplicateStepBits);
+ SecurData.Alloc(size);
+ if (ReadStream_FALSE(sdsStream, SecurData, size) == S_OK)
+ {
+ ParseSecuritySDS();
+ break;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ bool thereAreUnknownFolders_Normal = false;
+ bool thereAreUnknownFolders_Deleted = false;
+
+ for (i = 0; i < Items.Size(); i++)
+ {
+ CItem &item = Items[i];
+ const CMftRec &rec = Recs[item.RecIndex];
+ const CFileNameAttr &fn = rec.FileNames[item.NameIndex];
+ const CMftRef &parentDirRef = fn.ParentDirRef;
+ const UInt64 refIndex = parentDirRef.GetIndex();
+ if (refIndex == kRecIndex_RootDir)
+ item.ParentFolder = -1;
+ else
+ {
+ int index = FindDirItemForMtfRec(refIndex);
+ if (index < 0 ||
+ Recs[Items[index].RecIndex].SeqNumber != parentDirRef.GetNumber())
+ {
+ if (Recs[item.RecIndex].InUse())
+ {
+ thereAreUnknownFolders_Normal = true;
+ index = k_ParentFolderIndex_Lost;
+ }
+ else
+ {
+ thereAreUnknownFolders_Deleted = true;
+ index = k_ParentFolderIndex_Deleted;
+ }
+ }
+ item.ParentFolder = index;
+ }
+ }
+
+ unsigned virtIndex = Items.Size();
+ if (_showSystemFiles)
+ {
+ _systemFolderIndex = (int)(virtIndex++);
+ VirtFolderNames.Add(kVirtualFolder_System);
+ }
+ if (thereAreUnknownFolders_Normal)
+ {
+ _lostFolderIndex_Normal = (int)(virtIndex++);
+ VirtFolderNames.Add(kVirtualFolder_Lost_Normal);
+ }
+ if (thereAreUnknownFolders_Deleted)
+ {
+ _lostFolderIndex_Deleted = (int)(virtIndex++);
+ VirtFolderNames.Add(kVirtualFolder_Lost_Deleted);
+ }
+
+ return S_OK;
+}
+
+Z7_class_CHandler_final:
+ public IInArchive,
+ public IArchiveGetRawProps,
+ public IInArchiveGetStream,
+ public ISetProperties,
+ public CMyUnknownImp,
+ public CDatabase
+{
+ Z7_IFACES_IMP_UNK_4(
+ IInArchive,
+ IArchiveGetRawProps,
+ IInArchiveGetStream,
+ ISetProperties)
+};
+
+Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps))
+{
+ *numProps = 2;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID))
+{
+ *name = NULL;
+ *propID = index == 0 ? kpidNtReparse : kpidNtSecure;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType))
+{
+ *parentType = NParentType::kDir;
+ int par = -1;
+
+ if (index < Items.Size())
+ {
+ const CItem &item = Items[index];
+
+ if (item.ParentHost >= 0)
+ {
+ *parentType = NParentType::kAltStream;
+ par = (item.RecIndex == kRecIndex_RootDir ? -1 : item.ParentHost);
+ }
+ else if (item.RecIndex < kNumSysRecs)
+ {
+ if (_showSystemFiles)
+ par = _systemFolderIndex;
+ }
+ else if (item.ParentFolder >= 0)
+ par = item.ParentFolder;
+ else if (item.ParentFolder == k_ParentFolderIndex_Lost)
+ par = _lostFolderIndex_Normal;
+ else if (item.ParentFolder == k_ParentFolderIndex_Deleted)
+ par = _lostFolderIndex_Deleted;
+ }
+ *parent = (UInt32)(Int32)par;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
+{
+ *data = NULL;
+ *dataSize = 0;
+ *propType = 0;
+
+ if (propID == kpidName)
+ {
+ #ifdef MY_CPU_LE
+ const UString2 *s;
+ if (index >= Items.Size())
+ s = &VirtFolderNames[index - Items.Size()];
+ else
+ {
+ const CItem &item = Items[index];
+ const CMftRec &rec = Recs[item.RecIndex];
+ if (item.IsAltStream())
+ s = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start].Name;
+ else
+ s = &rec.FileNames[item.NameIndex].Name;
+ }
+ if (s->IsEmpty())
+ *data = (const wchar_t *)EmptyString;
+ else
+ *data = s->GetRawPtr();
+ *dataSize = (s->Len() + 1) * (UInt32)sizeof(wchar_t);
+ *propType = PROP_DATA_TYPE_wchar_t_PTR_Z_LE;
+ #endif
+ return S_OK;
+ }
+
+ if (propID == kpidNtReparse)
+ {
+ if (index >= Items.Size())
+ return S_OK;
+ const CItem &item = Items[index];
+ const CMftRec &rec = Recs[item.RecIndex];
+ const CByteBuffer &reparse = rec.ReparseData;
+
+ if (reparse.Size() != 0)
+ {
+ *dataSize = (UInt32)reparse.Size();
+ *propType = NPropDataType::kRaw;
+ *data = (const Byte *)reparse;
+ }
+ }
+
+ if (propID == kpidNtSecure)
+ {
+ if (index >= Items.Size())
+ return S_OK;
+ const CItem &item = Items[index];
+ const CMftRec &rec = Recs[item.RecIndex];
+ if (rec.SiAttr.SecurityId > 0)
+ {
+ UInt64 offset;
+ UInt32 size;
+ if (FindSecurityDescritor(rec.SiAttr.SecurityId, offset, size))
+ {
+ *dataSize = size;
+ *propType = NPropDataType::kRaw;
+ *data = (const Byte *)SecurData + offset;
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ *stream = NULL;
+ if (index >= Items.Size())
+ return S_OK;
+ IInStream *stream2;
+ const CItem &item = Items[index];
+ const CMftRec &rec = Recs[item.RecIndex];
+ HRESULT res = rec.GetStream(InStream, item.DataIndex, Header.ClusterSizeLog, Header.NumClusters, &stream2);
+ *stream = (ISequentialInStream *)stream2;
+ return res;
+ COM_TRY_END
+}
+
+/*
+enum
+{
+ kpidLink2 = kpidUserDefined,
+ kpidLinkType,
+ kpidRecMTime,
+ kpidRecMTime2,
+ kpidMTime2,
+ kpidCTime2,
+ kpidATime2
+};
+
+static const CStatProp kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+
+ // { NULL, kpidLink, VT_BSTR},
+
+ // { "Link 2", kpidLink2, VT_BSTR},
+ // { "Link Type", kpidLinkType, VT_UI2},
+ { NULL, kpidINode, VT_UI8},
+
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME},
+
+ // { "Record Modified", kpidRecMTime, VT_FILETIME},
+
+ // { "Modified 2", kpidMTime2, VT_FILETIME},
+ // { "Created 2", kpidCTime2, VT_FILETIME},
+ // { "Accessed 2", kpidATime2, VT_FILETIME},
+ // { "Record Modified 2", kpidRecMTime2, VT_FILETIME},
+
+ { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidNumBlocks, VT_UI4},
+ { NULL, kpidIsDeleted, VT_BOOL},
+};
+*/
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidCTime,
+ kpidATime,
+ kpidChangeTime,
+ kpidAttrib,
+ kpidLinks,
+ kpidINode,
+ kpidNumBlocks,
+ kpidNumAltStreams,
+ kpidIsAltStream,
+ kpidShortName,
+ kpidIsDeleted
+};
+
+enum
+{
+ kpidRecordSize = kpidUserDefined
+};
+
+static const CStatProp kArcProps[] =
+{
+ { NULL, kpidVolumeName, VT_BSTR},
+ { NULL, kpidFileSystem, VT_BSTR},
+ { NULL, kpidClusterSize, VT_UI4},
+ { NULL, kpidSectorSize, VT_UI4},
+ { "Record Size", kpidRecordSize, VT_UI4},
+ { NULL, kpidHeadersSize, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidId, VT_UI8},
+};
+
+/*
+static const Byte kArcProps[] =
+{
+ kpidVolumeName,
+ kpidFileSystem,
+ kpidClusterSize,
+ kpidHeadersSize,
+ kpidCTime,
+
+ kpidSectorSize,
+ kpidId
+ // kpidSectorsPerTrack,
+ // kpidNumHeads,
+ // kpidHiddenSectors
+};
+*/
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_WITH_NAME
+
+static void NtfsTimeToProp(UInt64 t, NCOM::CPropVariant &prop)
+{
+ FILETIME ft;
+ ft.dwLowDateTime = (DWORD)t;
+ ft.dwHighDateTime = (DWORD)(t >> 32);
+ prop = ft;
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ const CMftRec *volRec = (Recs.Size() > kRecIndex_Volume ? &Recs[kRecIndex_Volume] : NULL);
+
+ switch (propID)
+ {
+ case kpidClusterSize: prop = Header.ClusterSize(); break;
+ case kpidPhySize: prop = PhySize; break;
+ /*
+ case kpidHeadersSize:
+ {
+ UInt64 val = 0;
+ for (unsigned i = 0; i < kNumSysRecs; i++)
+ {
+ printf("\n%2d: %8I64d ", i, Recs[i].GetPackSize());
+ if (i == 8)
+ i = i
+ val += Recs[i].GetPackSize();
+ }
+ prop = val;
+ break;
+ }
+ */
+ case kpidCTime: if (volRec) NtfsTimeToProp(volRec->SiAttr.CTime, prop); break;
+ case kpidMTime: if (volRec) NtfsTimeToProp(volRec->SiAttr.MTime, prop); break;
+ case kpidShortComment:
+ case kpidVolumeName:
+ {
+ FOR_VECTOR (i, VolAttrs)
+ {
+ const CAttr &attr = VolAttrs[i];
+ if (attr.Type == ATTR_TYPE_VOLUME_NAME)
+ {
+ UString2 name;
+ GetString(attr.Data, (unsigned)attr.Data.Size() / 2, name);
+ if (!name.IsEmpty())
+ prop = name.GetRawPtr();
+ break;
+ }
+ }
+ break;
+ }
+ case kpidFileSystem:
+ {
+ AString s ("NTFS");
+ FOR_VECTOR (i, VolAttrs)
+ {
+ const CAttr &attr = VolAttrs[i];
+ if (attr.Type == ATTR_TYPE_VOLUME_INFO)
+ {
+ CVolInfo vi;
+ if (attr.ParseVolInfo(vi))
+ {
+ s.Add_Space();
+ s.Add_UInt32(vi.MajorVer);
+ s.Add_Dot();
+ s.Add_UInt32(vi.MinorVer);
+ }
+ break;
+ }
+ }
+ prop = s;
+ break;
+ }
+ case kpidSectorSize: prop = (UInt32)1 << Header.SectorSizeLog; break;
+ case kpidRecordSize: prop = (UInt32)1 << RecSizeLog; break;
+ case kpidId: prop = Header.SerialNumber; break;
+
+ case kpidIsTree: prop = true; break;
+ case kpidIsDeleted: prop = _showDeletedFiles; break;
+ case kpidIsAltStream: prop = ThereAreAltStreams; break;
+ case kpidIsAux: prop = true; break;
+ case kpidINode: prop = true; break;
+
+ case kpidWarning:
+ if (_lostFolderIndex_Normal >= 0)
+ prop = "There are lost files";
+ break;
+
+ /*
+ case kpidWarningFlags:
+ {
+ UInt32 flags = 0;
+ if (_headerWarning)
+ flags |= k_ErrorFlags_HeadersError;
+ if (flags != 0)
+ prop = flags;
+ break;
+ }
+ */
+
+ // case kpidMediaType: prop = Header.MediaType; break;
+ // case kpidSectorsPerTrack: prop = Header.SectorsPerTrack; break;
+ // case kpidNumHeads: prop = Header.NumHeads; break;
+ // case kpidHiddenSectors: prop = Header.NumHiddenSectors; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ if (index >= Items.Size())
+ {
+ switch (propID)
+ {
+ case kpidName:
+ case kpidPath:
+ prop = VirtFolderNames[index - Items.Size()].GetRawPtr();
+ break;
+ case kpidIsDir: prop = true; break;
+ case kpidIsAux: prop = true; break;
+ case kpidIsDeleted:
+ if ((int)index == _lostFolderIndex_Deleted)
+ prop = true;
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ }
+
+ const CItem &item = Items[index];
+ const CMftRec &rec = Recs[item.RecIndex];
+
+ const CAttr *data= NULL;
+ if (item.DataIndex >= 0)
+ data = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start];
+
+ // const CFileNameAttr *fn = &rec.FileNames[item.NameIndex];
+ /*
+ if (rec.FileNames.Size() > 0)
+ fn = &rec.FileNames[0];
+ */
+
+ switch (propID)
+ {
+ case kpidPath:
+ GetItemPath(index, prop);
+ break;
+
+ /*
+ case kpidLink:
+ if (!rec.ReparseAttr.SubsName.IsEmpty())
+ {
+ prop = rec.ReparseAttr.SubsName;
+ }
+ break;
+ case kpidLink2:
+ if (!rec.ReparseAttr.PrintName.IsEmpty())
+ {
+ prop = rec.ReparseAttr.PrintName;
+ }
+ break;
+
+ case kpidLinkType:
+ if (rec.ReparseAttr.Tag != 0)
+ {
+ prop = (rec.ReparseAttr.Tag & 0xFFFF);
+ }
+ break;
+ */
+
+ case kpidINode:
+ {
+ // const CMftRec &rec = Recs[item.RecIndex];
+ // prop = ((UInt64)rec.SeqNumber << 48) | item.RecIndex;
+ prop = (UInt32)item.RecIndex;
+ break;
+ }
+ case kpidStreamId:
+ {
+ if (item.DataIndex >= 0)
+ prop = ((UInt64)item.RecIndex << 32) | (unsigned)item.DataIndex;
+ break;
+ }
+
+ case kpidName:
+ {
+ const UString2 *s;
+ if (item.IsAltStream())
+ s = &rec.DataAttrs[rec.DataRefs[item.DataIndex].Start].Name;
+ else
+ s = &rec.FileNames[item.NameIndex].Name;
+ if (s->IsEmpty())
+ prop = (const wchar_t *)EmptyString;
+ else
+ prop = s->GetRawPtr();
+ break;
+ }
+
+ case kpidShortName:
+ {
+ if (!item.IsAltStream())
+ {
+ int dosNameIndex = rec.FindDosName(item.NameIndex);
+ if (dosNameIndex >= 0)
+ {
+ const UString2 &s = rec.FileNames[dosNameIndex].Name;
+ if (s.IsEmpty())
+ prop = (const wchar_t *)EmptyString;
+ else
+ prop = s.GetRawPtr();
+ }
+ }
+ break;
+ }
+
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidIsAltStream: prop = item.IsAltStream(); break;
+ case kpidIsDeleted: prop = !rec.InUse(); break;
+ case kpidIsAux: prop = false; break;
+
+ case kpidMTime: NtfsTimeToProp(rec.SiAttr.MTime, prop); break;
+ case kpidCTime: NtfsTimeToProp(rec.SiAttr.CTime, prop); break;
+ case kpidATime: NtfsTimeToProp(rec.SiAttr.ATime, prop); break;
+ case kpidChangeTime: NtfsTimeToProp(rec.SiAttr.ThisRecMTime, prop); break;
+
+ /*
+ case kpidMTime2: if (fn) NtfsTimeToProp(fn->MTime, prop); break;
+ case kpidCTime2: if (fn) NtfsTimeToProp(fn->CTime, prop); break;
+ case kpidATime2: if (fn) NtfsTimeToProp(fn->ATime, prop); break;
+ case kpidRecMTime2: if (fn) NtfsTimeToProp(fn->ThisRecMTime, prop); break;
+ */
+
+ case kpidAttrib:
+ {
+ UInt32 attrib;
+ /* WinXP-64: The CFileNameAttr::Attrib is not updated after some changes. Why?
+ CSiAttr:attrib is updated better. So we use CSiAttr:Sttrib */
+ /*
+ if (fn)
+ attrib = fn->Attrib;
+ else
+ */
+ attrib = rec.SiAttr.Attrib;
+ if (item.IsDir())
+ attrib |= FILE_ATTRIBUTE_DIRECTORY;
+
+ /* some system entries can contain extra flags (Index View).
+ // 0x10000000 (Directory)
+ // 0x20000000 FILE_ATTR_VIEW_INDEX_PRESENT MFT_RECORD_IS_VIEW_INDEX (Index View)
+ But we don't need them */
+ attrib &= 0xFFFF;
+
+ prop = attrib;
+ break;
+ }
+ case kpidLinks: if (rec.MyNumNameLinks != 1) prop = rec.MyNumNameLinks; break;
+
+ case kpidNumAltStreams:
+ {
+ if (!item.IsAltStream())
+ {
+ unsigned num = rec.DataRefs.Size();
+ if (num > 0)
+ {
+ if (!rec.IsDir() && rec.DataAttrs[rec.DataRefs[0].Start].Name.IsEmpty())
+ num--;
+ if (num > 0)
+ prop = (UInt32)num;
+ }
+ }
+ break;
+ }
+
+ case kpidSize: if (data) prop = data->GetSize(); else if (!item.IsDir()) prop = (UInt64)0; break;
+ case kpidPackSize: if (data) prop = data->GetPackSize(); else if (!item.IsDir()) prop = (UInt64)0; break;
+ case kpidNumBlocks: if (data) prop = (UInt32)rec.GetNumExtents(item.DataIndex, Header.ClusterSizeLog, Header.NumClusters); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ {
+ OpenCallback = callback;
+ InStream = stream;
+ HRESULT res;
+ try
+ {
+ res = CDatabase::Open();
+ if (res == S_OK)
+ return S_OK;
+ }
+ catch(...)
+ {
+ Close();
+ throw;
+ }
+ Close();
+ return res;
+ }
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ ClearAndClose();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = Items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt32 i;
+ UInt64 totalSize = 0;
+ for (i = 0; i < numItems; i++)
+ {
+ const UInt32 index = allFilesMode ? i : indices[i];
+ if (index >= (UInt32)Items.Size())
+ continue;
+ const CItem &item = Items[allFilesMode ? i : indices[i]];
+ const CMftRec &rec = Recs[item.RecIndex];
+ if (item.DataIndex >= 0)
+ totalSize += rec.GetSize((unsigned)item.DataIndex);
+ }
+ RINOK(extractCallback->SetTotal(totalSize))
+
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+
+ UInt32 clusterSize = Header.ClusterSize();
+ CByteBuffer buf(clusterSize);
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur())
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+ if (index >= (UInt32)Items.Size() || Items[index].IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+
+ const CItem &item = Items[index];
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode))
+
+ outStreamSpec->SetStream(realOutStream);
+ realOutStream.Release();
+ outStreamSpec->Init();
+
+ const CMftRec &rec = Recs[item.RecIndex];
+
+ int res = NExtract::NOperationResult::kDataError;
+ {
+ CMyComPtr<IInStream> inStream;
+ HRESULT hres = rec.GetStream(InStream, item.DataIndex, Header.ClusterSizeLog, Header.NumClusters, &inStream);
+ if (hres == S_FALSE)
+ res = NExtract::NOperationResult::kUnsupportedMethod;
+ else
+ {
+ RINOK(hres)
+ if (inStream)
+ {
+ hres = copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+ if (hres != S_OK && hres != S_FALSE)
+ {
+ RINOK(hres)
+ }
+ if (/* copyCoderSpec->TotalSize == item.GetSize() && */ hres == S_OK)
+ res = NExtract::NOperationResult::kOK;
+ }
+ }
+ }
+ if (item.DataIndex >= 0)
+ {
+ const CAttr &data = rec.DataAttrs[rec.DataRefs[item.DataIndex].Start];
+ totalPackSize += data.GetPackSize();
+ totalSize += data.GetSize();
+ }
+ outStreamSpec->ReleaseStream();
+ RINOK(extractCallback->SetOperationResult(res))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = Items.Size() + VirtFolderNames.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
+{
+ InitProps();
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const wchar_t *name = names[i];
+ const PROPVARIANT &prop = values[i];
+
+ if (StringsAreEqualNoCase_Ascii(name, "ld"))
+ {
+ RINOK(PROPVARIANT_to_bool(prop, _showDeletedFiles))
+ }
+ else if (StringsAreEqualNoCase_Ascii(name, "ls"))
+ {
+ RINOK(PROPVARIANT_to_bool(prop, _showSystemFiles))
+ }
+ else
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+static const Byte k_Signature[] = { 'N', 'T', 'F', 'S', ' ', ' ', ' ', ' ', 0 };
+
+REGISTER_ARC_I(
+ "NTFS", "ntfs img", NULL, 0xD9,
+ k_Signature,
+ 3,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/PeHandler.cpp b/CPP/7zip/Archive/PeHandler.cpp
new file mode 100644
index 0000000..9851ed3
--- /dev/null
+++ b/CPP/7zip/Archive/PeHandler.cpp
@@ -0,0 +1,3272 @@
+// PeHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/DynamicBuffer.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/StringConvert.h"
+
+#include "../../Windows/PropVariantUtils.h"
+#include "../../Windows/TimeUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+#define G16(offs, v) v = Get16(p + (offs))
+#define G32(offs, v) v = Get32(p + (offs))
+#define G32_signed(offs, v) v = (Int32)Get32(p + (offs))
+#define G64(offs, v) v = Get64(p + (offs))
+
+#define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; }
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NPe {
+
+static const UInt32 k_Signature32 = 0x00004550;
+
+static HRESULT CalcCheckSum(ISequentialInStream *stream, UInt32 size, UInt32 excludePos, UInt32 &res)
+{
+ const UInt32 kBufSizeMax = (UInt32)1 << 15;
+ UInt32 bufSize = kBufSizeMax;
+ CByteBuffer buffer(bufSize);
+ Byte *buf = buffer;
+ UInt32 sum = 0;
+ UInt32 pos = 0;
+ for (;;)
+ {
+ UInt32 rem = size - pos;
+ if (rem > bufSize)
+ rem = bufSize;
+ if (rem == 0)
+ break;
+ size_t processed = rem;
+ RINOK(ReadStream(stream, buf, &processed))
+
+ for (unsigned j = 0; j < 4; j++)
+ {
+ UInt32 e = excludePos + j;
+ if (pos <= e)
+ {
+ e -= pos;
+ if (e < processed)
+ buf[e] = 0;
+ }
+ }
+
+ const unsigned kStep = (1 << 4);
+ {
+ for (size_t i = processed; (i & (kStep - 1)) != 0; i++)
+ buf[i] = 0;
+ }
+ {
+ const Byte *buf2 = buf;
+ const Byte *bufLimit = buf + processed;
+ UInt64 sum2 = 0;
+ for (; buf2 < bufLimit; buf2 += kStep)
+ {
+ UInt64 sum3 = (UInt64)Get32(buf2)
+ + Get32(buf2 + 4)
+ + Get32(buf2 + 8)
+ + Get32(buf2 + 12);
+ sum2 += sum3;
+ }
+ sum2 = (UInt32)(sum2) + (UInt64)(sum2 >> 32);
+ UInt32 sum3 = ((UInt32)sum2 + (UInt32)(sum2 >> 32));
+ sum += (sum3 & 0xFFFF) + (sum3 >> 16);
+ sum = (sum & 0xFFFF) + (sum >> 16);
+ sum = (sum & 0xFFFF) + (sum >> 16);
+ }
+
+ pos += (UInt32)processed;
+ if (rem != processed)
+ break;
+ }
+ res = sum + pos;
+ return S_OK;
+}
+
+
+struct CVersion
+{
+ UInt16 Major;
+ UInt16 Minor;
+
+ void Parse(const Byte *p)
+ {
+ G16(0, Major);
+ G16(2, Minor);
+ }
+ void ToProp(NCOM::CPropVariant &prop);
+};
+
+void CVersion::ToProp(NCOM::CPropVariant &prop)
+{
+ char sz[32];
+ ConvertUInt32ToString(Major, sz);
+ unsigned len = MyStringLen(sz);
+ sz[len] = '.';
+ ConvertUInt32ToString(Minor, sz + len + 1);
+ prop = sz;
+}
+
+static const unsigned kCoffHeaderSize = 20;
+static const unsigned kPeHeaderSize = 4 + kCoffHeaderSize;
+static const unsigned k_OptHeader32_Size_MIN = 96;
+static const unsigned k_OptHeader64_Size_MIN = 112;
+
+static const UInt32 PE_IMAGE_FILE_DLL = (1 << 13);
+
+struct CHeader
+{
+ UInt16 Machine;
+ UInt16 NumSections;
+ UInt32 Time;
+ UInt32 PointerToSymbolTable;
+ UInt32 NumSymbols;
+ UInt16 OptHeaderSize;
+ UInt16 Flags;
+
+ void ParseBase(const Byte *p);
+ bool ParseCoff(const Byte *p);
+ bool ParsePe(const Byte *p);
+ bool IsDll() const { return (Flags & PE_IMAGE_FILE_DLL) != 0; }
+};
+
+void CHeader::ParseBase(const Byte *p)
+{
+ G16( 0, Machine);
+ G16( 2, NumSections);
+ G32( 4, Time);
+ G32( 8, PointerToSymbolTable);
+ G32(12, NumSymbols);
+ G16(16, OptHeaderSize);
+ G16(18, Flags);
+}
+
+bool CHeader::ParsePe(const Byte *p)
+{
+ if (Get32(p) != k_Signature32)
+ return false;
+ ParseBase(p + 4);
+ return OptHeaderSize >= k_OptHeader32_Size_MIN;
+}
+
+struct CDirLink
+{
+ UInt32 Va;
+ UInt32 Size;
+
+ CDirLink(): Va(0), Size(0) {}
+ void Parse(const Byte *p)
+ {
+ G32(0, Va);
+ G32(4, Size);
+ }
+};
+
+enum
+{
+ kDirLink_Certificate = 4,
+ kDirLink_Debug = 6
+};
+
+static const UInt32 kNumDirItemsMax = 16;
+
+struct CDebugEntry
+{
+ UInt32 Flags;
+ UInt32 Time;
+ CVersion Ver;
+ UInt32 Type;
+ UInt32 Size;
+ UInt32 Va;
+ UInt32 Pa;
+
+ void Parse(const Byte *p)
+ {
+ G32(0, Flags);
+ G32(4, Time);
+ Ver.Parse(p + 8);
+ G32(12, Type);
+ G32(16, Size);
+ G32(20, Va);
+ G32(24, Pa);
+ }
+};
+
+static const UInt32 k_CheckSum_Field_Offset = 64;
+
+static const UInt32 PE_OptHeader_Magic_32 = 0x10B;
+static const UInt32 PE_OptHeader_Magic_64 = 0x20B;
+
+static const UInt32 k_SubSystems_EFI_First = 10;
+static const UInt32 k_SubSystems_EFI_Last = 13;
+
+struct COptHeader
+{
+ UInt16 Magic;
+ Byte LinkerVerMajor;
+ Byte LinkerVerMinor;
+
+ UInt32 CodeSize;
+ UInt32 InitDataSize;
+ UInt32 UninitDataSize;
+
+ // UInt32 AddressOfEntryPoint;
+ // UInt32 BaseOfCode;
+ // UInt32 BaseOfData32;
+ UInt64 ImageBase;
+
+ UInt32 SectAlign;
+ UInt32 FileAlign;
+
+ CVersion OsVer;
+ CVersion ImageVer;
+ CVersion SubsysVer;
+
+ UInt32 ImageSize;
+ UInt32 HeadersSize;
+ UInt32 CheckSum;
+ UInt16 SubSystem;
+ UInt16 DllCharacts;
+
+ UInt64 StackReserve;
+ UInt64 StackCommit;
+ UInt64 HeapReserve;
+ UInt64 HeapCommit;
+
+ UInt32 NumDirItems;
+ CDirLink DirItems[kNumDirItemsMax];
+
+ bool Is64Bit() const { return Magic == PE_OptHeader_Magic_64; }
+ bool Parse(const Byte *p, UInt32 size);
+
+ int GetNumFileAlignBits() const
+ {
+ for (unsigned i = 0; i < 32; i++)
+ if (((UInt32)1 << i) == FileAlign)
+ return (int)i;
+ return -1;
+ }
+
+ bool IsSybSystem_EFI() const
+ {
+ return
+ SubSystem >= k_SubSystems_EFI_First &&
+ SubSystem <= k_SubSystems_EFI_Last;
+ }
+};
+
+bool COptHeader::Parse(const Byte *p, UInt32 size)
+{
+ if (size < k_OptHeader32_Size_MIN)
+ return false;
+ Magic = Get16(p);
+ switch (Magic)
+ {
+ case PE_OptHeader_Magic_32:
+ case PE_OptHeader_Magic_64:
+ break;
+ default:
+ return false;
+ }
+ LinkerVerMajor = p[2];
+ LinkerVerMinor = p[3];
+
+ G32( 4, CodeSize);
+ G32( 8, InitDataSize);
+ G32(12, UninitDataSize);
+ // G32(16, AddressOfEntryPoint);
+ // G32(20, BaseOfCode);
+
+ G32(32, SectAlign);
+ G32(36, FileAlign);
+
+ OsVer.Parse(p + 40);
+ ImageVer.Parse(p + 44);
+ SubsysVer.Parse(p + 48);
+
+ // reserved = Get32(p + 52);
+
+ G32(56, ImageSize);
+ G32(60, HeadersSize);
+ G32(64, CheckSum);
+ G16(68, SubSystem);
+ G16(70, DllCharacts);
+
+ UInt32 pos;
+ if (Is64Bit())
+ {
+ if (size < k_OptHeader64_Size_MIN)
+ return false;
+ // BaseOfData32 = 0;
+ G64(24, ImageBase);
+ G64(72, StackReserve);
+ G64(80, StackCommit);
+ G64(88, HeapReserve);
+ G64(96, HeapCommit);
+ pos = 108;
+ }
+ else
+ {
+ // G32(24, BaseOfData32);
+ G32(28, ImageBase);
+ G32(72, StackReserve);
+ G32(76, StackCommit);
+ G32(80, HeapReserve);
+ G32(84, HeapCommit);
+ pos = 92;
+ }
+
+ G32(pos, NumDirItems);
+ if (NumDirItems > (1 << 16))
+ return false;
+ pos += 4;
+ if (pos + 8 * NumDirItems > size)
+ return false;
+ memset((void *)DirItems, 0, sizeof(DirItems));
+ for (UInt32 i = 0; i < NumDirItems && i < kNumDirItemsMax; i++)
+ DirItems[i].Parse(p + pos + i * 8);
+ return true;
+}
+
+static const UInt32 kSectionSize = 40;
+
+struct CSection
+{
+ AString Name;
+
+ UInt32 VSize;
+ UInt32 Va;
+ UInt32 PSize;
+ UInt32 Pa;
+ UInt32 Flags;
+ UInt32 Time;
+ // UInt16 NumRelocs;
+ bool IsRealSect;
+ bool IsDebug;
+ bool IsAdditionalSection;
+
+ CSection(): IsRealSect(false), IsDebug(false), IsAdditionalSection(false) {}
+
+ UInt32 GetSizeExtract() const { return PSize; }
+ UInt32 GetSizeMin() const { return MyMin(PSize, VSize); }
+
+ void UpdateTotalSize(UInt32 &totalSize) const
+ {
+ UInt32 t = Pa + PSize;
+ if (totalSize < t)
+ totalSize = t;
+ }
+
+ void Parse(const Byte *p);
+
+ int Compare(const CSection &s) const
+ {
+ RINOZ(MyCompare(Pa, s.Pa))
+ UInt32 size1 = GetSizeExtract();
+ UInt32 size2 = s.GetSizeExtract();
+ return MyCompare(size1, size2);
+ }
+};
+
+static const unsigned kNameSize = 8;
+
+static void GetName(const Byte *name, AString &res)
+{
+ res.SetFrom_CalcLen((const char *)name, kNameSize);
+}
+
+void CSection::Parse(const Byte *p)
+{
+ GetName(p, Name);
+ G32( 8, VSize);
+ G32(12, Va);
+ G32(16, PSize);
+ G32(20, Pa);
+ // G16(32, NumRelocs);
+ G32(36, Flags);
+}
+
+
+
+// IMAGE_FILE_*
+
+static const CUInt32PCharPair g_HeaderCharacts[] =
+{
+ { 1, "Executable" },
+ { 13, "DLL" },
+ { 8, "32-bit" },
+ { 5, "LargeAddress" },
+ { 0, "NoRelocs" },
+ { 2, "NoLineNums" },
+ { 3, "NoLocalSyms" },
+ { 4, "AggressiveWsTrim" },
+ { 9, "NoDebugInfo" },
+ { 10, "RemovableRun" },
+ { 11, "NetRun" },
+ { 12, "System" },
+ { 14, "UniCPU" },
+ { 7, "Little-Endian" },
+ { 15, "Big-Endian" }
+};
+
+// IMAGE_DLLCHARACTERISTICS_*
+
+static const char * const g_DllCharacts[] =
+{
+ NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , "HighEntropyVA"
+ , "Relocated"
+ , "Integrity"
+ , "NX-Compatible"
+ , "NoIsolation"
+ , "NoSEH"
+ , "NoBind"
+ , "AppContainer"
+ , "WDM"
+ , "GuardCF"
+ , "TerminalServerAware"
+};
+
+
+// IMAGE_SCN_* constants:
+
+static const char * const g_SectFlags[] =
+{
+ NULL
+ , NULL
+ , NULL
+ , "NoPad"
+ , NULL
+ , "Code"
+ , "InitializedData"
+ , "UninitializedData"
+ , "Other"
+ , "Comments"
+ , NULL // OVER
+ , "Remove"
+ , "COMDAT"
+ , NULL
+ , "NO_DEFER_SPEC_EXC"
+ , "GP" // MEM_FARDATA
+ , NULL // SYSHEAP
+ , "PURGEABLE" // 16BIT
+ , "LOCKED"
+ , "PRELOAD"
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , "ExtendedRelocations"
+ , "Discardable"
+ , "NotCached"
+ , "NotPaged"
+ , "Shared"
+ , "Execute"
+ , "Read"
+ , "Write"
+};
+
+static const CUInt32PCharPair g_MachinePairs[] =
+{
+ { 0x014C, "x86" },
+ { 0x014D, "I860" },
+ { 0x0162, "MIPS-R3000" },
+ { 0x0166, "MIPS-R4000" },
+ { 0x0168, "MIPS-R10000" },
+ { 0x0169, "MIPS-V2" },
+ { 0x0184, "Alpha" },
+ { 0x01A2, "SH3" },
+ { 0x01A3, "SH3-DSP" },
+ { 0x01A4, "SH3E" },
+ { 0x01A6, "SH4" },
+ { 0x01A8, "SH5" },
+ { 0x01C0, "ARM" },
+ { 0x01C2, "ARM-Thumb" },
+ { 0x01C4, "ARM-NT" },
+ { 0x01D3, "AM33" },
+ { 0x01F0, "PPC" },
+ { 0x01F1, "PPC-FP" },
+ { 0x0200, "IA-64" },
+ { 0x0266, "MIPS-16" },
+ { 0x0284, "Alpha-64" },
+ { 0x0366, "MIPS-FPU" },
+ { 0x0466, "MIPS-FPU16" },
+ { 0x0520, "TriCore" },
+ { 0x0CEF, "CEF" },
+ { 0x0EBC, "EFI" },
+ { 0x8664, "x64" },
+ { 0x9041, "M32R" },
+ { 0xAA64, "ARM64" },
+ { 0xC0EE, "CEE" }
+};
+
+static const char * const g_SubSystems[] =
+{
+ "Unknown"
+ , "Native"
+ , "Windows GUI"
+ , "Windows CUI"
+ , NULL // "Old Windows CE"
+ , "OS2"
+ , NULL
+ , "Posix"
+ , "Win9x"
+ , "Windows CE"
+ , "EFI"
+ , "EFI Boot"
+ , "EFI Runtime"
+ , "EFI ROM"
+ , "XBOX"
+ , NULL
+ , "Windows Boot"
+ , "XBOX Catalog" // 17
+};
+
+static const char * const g_ResTypes[] =
+{
+ NULL
+ , "CURSOR"
+ , "BITMAP"
+ , "ICON"
+ , "MENU"
+ , "DIALOG"
+ , "STRING"
+ , "FONTDIR"
+ , "FONT"
+ , "ACCELERATOR"
+ , "RCDATA"
+ , "MESSAGETABLE"
+ , "GROUP_CURSOR"
+ , NULL
+ , "GROUP_ICON"
+ , NULL
+ , "VERSION"
+ , "DLGINCLUDE"
+ , NULL
+ , "PLUGPLAY"
+ , "VXD"
+ , "ANICURSOR"
+ , "ANIICON"
+ , "HTML"
+ , "MANIFEST"
+};
+
+static const UInt32 kFlag = (UInt32)1 << 31;
+static const UInt32 kMask = ~kFlag;
+
+struct CTableItem
+{
+ UInt32 Offset;
+ UInt32 ID;
+};
+
+
+static const UInt32 kBmpHeaderSize = 14;
+static const UInt32 kIconHeaderSize = 22;
+
+struct CResItem
+{
+ UInt32 Type;
+ UInt32 ID;
+ UInt32 Lang;
+
+ UInt32 Size;
+ UInt32 Offset;
+
+ UInt32 HeaderSize;
+ Byte Header[kIconHeaderSize]; // it must be enough for max size header.
+ bool Enabled;
+
+ bool IsNameEqual(const CResItem &item) const { return Lang == item.Lang; }
+ UInt32 GetSize() const { return Size + HeaderSize; }
+ bool IsBmp() const { return Type == 2; }
+ bool IsIcon() const { return Type == 3; }
+ bool IsString() const { return Type == 6; }
+ bool IsRcData() const { return Type == 10; }
+ bool IsVersion() const { return Type == 16; }
+ bool IsRcDataOrUnknown() const { return IsRcData() || Type > 64; }
+};
+
+struct CTextFile
+{
+ CByteDynamicBuffer Buf;
+
+ size_t FinalSize() const { return Buf.GetPos(); }
+
+ void AddChar(char c);
+ void AddWChar(UInt16 c);
+ void AddWChar_Smart(UInt16 c);
+ void NewLine();
+ void AddString(const char *s);
+ void AddSpaces(int num);
+ void AddBytes(const Byte *p, size_t size)
+ {
+ Buf.AddData(p, size);
+ }
+
+ void OpenBlock(int num)
+ {
+ AddSpaces(num);
+ AddChar('{');
+ NewLine();
+ }
+ void CloseBlock(int num)
+ {
+ AddSpaces(num);
+ AddChar('}');
+ NewLine();
+ }
+};
+
+void CTextFile::AddChar(char c)
+{
+ Byte *p = Buf.GetCurPtrAndGrow(2);
+ p[0] = (Byte)c;
+ p[1] = 0;
+}
+
+void CTextFile::AddWChar(UInt16 c)
+{
+ Byte *p = Buf.GetCurPtrAndGrow(2);
+ SetUi16(p, c)
+}
+
+void CTextFile::AddWChar_Smart(UInt16 c)
+{
+ if (c == '\n')
+ {
+ AddChar('\\');
+ c = 'n';
+ }
+ AddWChar(c);
+}
+
+void CTextFile::NewLine()
+{
+ AddChar(0x0D);
+ AddChar(0x0A);
+}
+
+void CTextFile::AddString(const char *s)
+{
+ for (;; s++)
+ {
+ char c = *s;
+ if (c == 0)
+ return;
+ AddChar(c);
+ }
+}
+
+void CTextFile::AddSpaces(int num)
+{
+ for (int i = 0; i < num; i++)
+ AddChar(' ');
+}
+
+struct CStringItem: public CTextFile
+{
+ UInt32 Lang;
+};
+
+struct CByteBuffer_WithLang: public CByteBuffer
+{
+ UInt32 Lang;
+};
+
+
+struct CMixItem
+{
+ int SectionIndex;
+ int ResourceIndex;
+ int StringIndex;
+ int VersionIndex;
+
+ CMixItem(): SectionIndex(-1), ResourceIndex(-1), StringIndex(-1), VersionIndex(-1) {}
+ bool IsSectionItem() const { return ResourceIndex < 0 && StringIndex < 0 && VersionIndex < 0; }
+};
+
+struct CUsedBitmap
+{
+ CByteBuffer Buf;
+public:
+ void Alloc(size_t size)
+ {
+ size = (size + 7) / 8;
+ Buf.Alloc(size);
+ memset(Buf, 0, size);
+ }
+
+ void Free()
+ {
+ Buf.Free();
+ }
+
+ bool SetRange(size_t from, unsigned size)
+ {
+ for (unsigned i = 0; i < size; i++)
+ {
+ size_t pos = (from + i) >> 3;
+ Byte mask = (Byte)(1 << ((from + i) & 7));
+ Byte b = Buf[pos];
+ if ((b & mask) != 0)
+ return false;
+ Buf[pos] = (Byte)(b | mask);
+ }
+ return true;
+ }
+};
+
+struct CStringKeyValue
+{
+ UString Key;
+ UString Value;
+};
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_2(
+ IInArchiveGetStream,
+ IArchiveAllowTail
+)
+ CMyComPtr<IInStream> _stream;
+ CObjectVector<CSection> _sections;
+ CHeader _header;
+ UInt32 _totalSize;
+ Int32 _mainSubfile;
+
+ CRecordVector<CMixItem> _mixItems;
+ CRecordVector<CResItem> _items;
+ CObjectVector<CStringItem> _strings;
+ CObjectVector<CByteBuffer_WithLang> _versionFiles;
+ UString _versionFullString;
+ UString _versionShortString;
+ UString _originalFilename;
+ CObjectVector<CStringKeyValue> _versionKeys;
+
+ CByteBuffer _buf;
+ bool _oneLang;
+ UString _resourcesPrefix;
+ CUsedBitmap _usedRes;
+ // bool _parseResources;
+ bool _checksumError;
+ bool _sectionsError;
+
+ bool IsOpt() const { return _header.OptHeaderSize != 0; }
+
+ COptHeader _optHeader;
+
+ bool _coffMode;
+ bool _allowTail;
+
+ HRESULT LoadDebugSections(IInStream *stream, bool &thereIsSection);
+ HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
+
+ void AddResNameToString(UString &s, UInt32 id) const;
+ void AddLangPrefix(UString &s, UInt32 lang) const;
+ HRESULT ReadString(UInt32 offset, UString &dest) const;
+ HRESULT ReadTable(UInt32 offset, CRecordVector<CTableItem> &items);
+ bool ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 size);
+ HRESULT OpenResources(unsigned sectIndex, IInStream *stream, IArchiveOpenCallback *callback);
+ void CloseResources();
+
+
+ bool CheckItem(const CSection &sect, const CResItem &item, size_t offset) const
+ {
+ return item.Offset >= sect.Va && offset <= _buf.Size() && _buf.Size() - offset >= item.Size;
+ }
+
+public:
+ CHandler(bool coffMode = false):
+ _coffMode(coffMode),
+ _allowTail(coffMode)
+ {}
+};
+
+
+enum
+{
+ kpidSectAlign = kpidUserDefined,
+ kpidFileAlign,
+ kpidLinkerVer,
+ kpidOsVer,
+ kpidImageVer,
+ kpidSubsysVer,
+ kpidCodeSize,
+ kpidImageSize,
+ kpidInitDataSize,
+ kpidUnInitDataSize,
+ kpidHeadersSizeUnInitDataSize,
+ kpidSubSystem,
+ kpidDllCharacts,
+ kpidStackReserve,
+ kpidStackCommit,
+ kpidHeapReserve,
+ kpidHeapCommit,
+ kpidImageBase
+ // kpidAddressOfEntryPoint,
+ // kpidBaseOfCode,
+ // kpidBaseOfData32,
+};
+
+static const CStatProp kArcProps[] =
+{
+ // { NULL, kpidWarning, VT_BSTR},
+ { NULL, kpidCpu, VT_BSTR},
+ { NULL, kpidBit64, VT_BOOL},
+ { NULL, kpidCharacts, VT_BSTR},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidHeadersSize, VT_UI4},
+ { NULL, kpidChecksum, VT_UI4},
+ { NULL, kpidName, VT_BSTR},
+
+ { "Image Size", kpidImageSize, VT_UI4},
+ { "Section Alignment", kpidSectAlign, VT_UI4},
+ { "File Alignment", kpidFileAlign, VT_UI4},
+ { "Code Size", kpidCodeSize, VT_UI4},
+ { "Initialized Data Size", kpidInitDataSize, VT_UI4},
+ { "Uninitialized Data Size", kpidUnInitDataSize, VT_UI4},
+ { "Linker Version", kpidLinkerVer, VT_BSTR},
+ { "OS Version", kpidOsVer, VT_BSTR},
+ { "Image Version", kpidImageVer, VT_BSTR},
+ { "Subsystem Version", kpidSubsysVer, VT_BSTR},
+ { "Subsystem", kpidSubSystem, VT_BSTR},
+ { "DLL Characteristics", kpidDllCharacts, VT_BSTR},
+ { "Stack Reserve", kpidStackReserve, VT_UI8},
+ { "Stack Commit", kpidStackCommit, VT_UI8},
+ { "Heap Reserve", kpidHeapReserve, VT_UI8},
+ { "Heap Commit", kpidHeapCommit, VT_UI8},
+ { "Image Base", kpidImageBase, VT_UI8},
+ { NULL, kpidComment, VT_BSTR},
+
+ // { "Address Of Entry Point", kpidAddressOfEntryPoint, VT_UI8},
+ // { "Base Of Code", kpidBaseOfCode, VT_UI8},
+ // { "Base Of Data", kpidBaseOfData32, VT_UI8},
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
+ kpidVirtualSize,
+ kpidCharacts,
+ kpidOffset,
+ kpidVa,
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_WITH_NAME
+
+static void TimeToProp(UInt32 unixTime, NCOM::CPropVariant &prop)
+{
+ if (unixTime != 0)
+ PropVariant_SetFrom_UnixTime(prop, unixTime);
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySize: prop = _totalSize; break;
+ case kpidComment: if (!_versionFullString.IsEmpty()) prop = _versionFullString; break;
+ case kpidShortComment:
+ if (!_versionShortString.IsEmpty())
+ prop = _versionShortString;
+ else
+ {
+ PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop);
+ }
+ break;
+
+ case kpidName: if (!_originalFilename.IsEmpty()) prop = _originalFilename; break;
+
+ // case kpidIsSelfExe: prop = !_header.IsDll(); break;
+ // case kpidError:
+ case kpidWarning: if (_checksumError) prop = "Checksum error"; break;
+
+ case kpidWarningFlags:
+ {
+ UInt32 v = 0;
+ if (_sectionsError) v |= kpv_ErrorFlags_HeadersError;
+ if (v != 0)
+ prop = v;
+ break;
+ }
+
+ case kpidCpu: PAIR_TO_PROP(g_MachinePairs, _header.Machine, prop); break;
+ case kpidMTime:
+ case kpidCTime: TimeToProp(_header.Time, prop); break;
+ case kpidCharacts: FLAGS_TO_PROP(g_HeaderCharacts, _header.Flags, prop); break;
+ case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
+
+ default:
+ if (IsOpt())
+ switch (propID)
+ {
+
+ case kpidSectAlign: prop = _optHeader.SectAlign; break;
+ case kpidFileAlign: prop = _optHeader.FileAlign; break;
+ case kpidLinkerVer:
+ {
+ CVersion v = { _optHeader.LinkerVerMajor, _optHeader.LinkerVerMinor };
+ v.ToProp(prop);
+ break;
+ }
+
+ case kpidOsVer: _optHeader.OsVer.ToProp(prop); break;
+ case kpidImageVer: _optHeader.ImageVer.ToProp(prop); break;
+ case kpidSubsysVer: _optHeader.SubsysVer.ToProp(prop); break;
+ case kpidCodeSize: prop = _optHeader.CodeSize; break;
+ case kpidInitDataSize: prop = _optHeader.InitDataSize; break;
+ case kpidUnInitDataSize: prop = _optHeader.UninitDataSize; break;
+ case kpidImageSize: prop = _optHeader.ImageSize; break;
+ case kpidHeadersSize: prop = _optHeader.HeadersSize; break;
+ case kpidChecksum: prop = _optHeader.CheckSum; break;
+
+ case kpidExtension:
+ if (_header.IsDll())
+ prop = "dll";
+ else if (_optHeader.IsSybSystem_EFI())
+ prop = "efi";
+ break;
+
+ case kpidBit64: if (_optHeader.Is64Bit()) prop = true; break;
+ case kpidSubSystem: TYPE_TO_PROP(g_SubSystems, _optHeader.SubSystem, prop); break;
+
+ case kpidDllCharacts: FLAGS_TO_PROP(g_DllCharacts, _optHeader.DllCharacts, prop); break;
+ case kpidStackReserve: prop = _optHeader.StackReserve; break;
+ case kpidStackCommit: prop = _optHeader.StackCommit; break;
+ case kpidHeapReserve: prop = _optHeader.HeapReserve; break;
+ case kpidHeapCommit: prop = _optHeader.HeapCommit; break;
+
+ case kpidImageBase: prop = _optHeader.ImageBase; break;
+ // case kpidAddressOfEntryPoint: prop = _optHeader.AddressOfEntryPoint; break;
+ // case kpidBaseOfCode: prop = _optHeader.BaseOfCode; break;
+ // case kpidBaseOfData32: if (!_optHeader.Is64Bit()) prop = _optHeader.BaseOfData32; break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CHandler::ReadString(UInt32 offset, UString &dest) const
+{
+ if ((offset & 1) != 0 || offset >= _buf.Size())
+ return S_FALSE;
+ size_t rem = _buf.Size() - offset;
+ if (rem < 2)
+ return S_FALSE;
+ unsigned len = Get16(_buf + offset);
+ if ((rem - 2) / 2 < len)
+ return S_FALSE;
+ dest.Empty();
+ wchar_t *destBuf = dest.GetBuf(len);
+ offset += 2;
+ const Byte *src = _buf + offset;
+ unsigned i;
+ for (i = 0; i < len; i++)
+ {
+ wchar_t c = (wchar_t)Get16(src + i * 2);
+ if (c == 0)
+ break;
+ destBuf[i] = c;
+ }
+ destBuf[i] = 0;
+ dest.ReleaseBuf_SetLen(i);
+ return S_OK;
+}
+
+void CHandler::AddResNameToString(UString &s, UInt32 id) const
+{
+ if ((id & kFlag) != 0)
+ {
+ UString name;
+ if (ReadString(id & kMask, name) == S_OK)
+ {
+ const wchar_t *str = L"[]";
+ if (name.Len() > 1 && name[0] == '"' && name.Back() == '"')
+ {
+ if (name.Len() != 2)
+ {
+ name.DeleteBack();
+ str = name.Ptr(1);
+ }
+ }
+ else if (!name.IsEmpty())
+ str = name;
+ s += str;
+ return;
+ }
+ }
+ s.Add_UInt32(id);
+}
+
+void CHandler::AddLangPrefix(UString &s, UInt32 lang) const
+{
+ if (!_oneLang)
+ {
+ AddResNameToString(s, lang);
+ s.Add_PathSepar();
+ }
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ const CMixItem &mixItem = _mixItems[index];
+ if (mixItem.StringIndex >= 0)
+ {
+ const CStringItem &item = _strings[mixItem.StringIndex];
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ UString s = _resourcesPrefix;
+ AddLangPrefix(s, item.Lang);
+ s += "string.txt";
+ prop = s;
+ break;
+ }
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)item.FinalSize(); break;
+ }
+ }
+ else if (mixItem.VersionIndex >= 0)
+ {
+ const CByteBuffer_WithLang &item = _versionFiles[mixItem.VersionIndex];
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ UString s = _resourcesPrefix;
+ AddLangPrefix(s, item.Lang);
+ s += "version.txt";
+ prop = s;
+ break;
+ }
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)item.Size(); break;
+ }
+ }
+ else if (mixItem.ResourceIndex >= 0)
+ {
+ const CResItem &item = _items[mixItem.ResourceIndex];
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ UString s = _resourcesPrefix;
+ AddLangPrefix(s, item.Lang);
+ {
+ const char *p = NULL;
+ if (item.Type < Z7_ARRAY_SIZE(g_ResTypes))
+ p = g_ResTypes[item.Type];
+ if (p)
+ s += p;
+ else
+ AddResNameToString(s, item.Type);
+ }
+ s.Add_PathSepar();
+ AddResNameToString(s, item.ID);
+ if (item.HeaderSize != 0)
+ {
+ if (item.IsBmp())
+ s += ".bmp";
+ else if (item.IsIcon())
+ s += ".ico";
+ }
+ prop = s;
+ break;
+ }
+ case kpidSize: prop = (UInt64)item.GetSize(); break;
+ case kpidPackSize: prop = (UInt64)item.Size; break;
+ }
+ }
+ else
+ {
+ const CSection &item = _sections[mixItem.SectionIndex];
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ AString s = item.Name;
+ s.Replace('/', '_');
+ s.Replace('\\', '_');
+ prop = MultiByteToUnicodeString(s);
+ break;
+ }
+ case kpidSize: prop = (UInt64)item.PSize; break;
+ case kpidPackSize: prop = (UInt64)item.PSize; break;
+ case kpidVirtualSize: prop = (UInt64)item.VSize; break;
+ case kpidOffset: prop = item.Pa; break;
+ case kpidVa: if (item.IsRealSect) prop = item.Va; break;
+ case kpidMTime:
+ case kpidCTime:
+ TimeToProp(item.IsDebug ? item.Time : _header.Time, prop); break;
+ case kpidCharacts:
+ if (item.IsRealSect)
+ {
+ UInt32 flags = item.Flags;
+ const UInt32 MY_IMAGE_SCN_ALIGN_MASK = 0x00F00000;
+ AString s = FlagsToString(g_SectFlags, Z7_ARRAY_SIZE(g_SectFlags), item.Flags & ~MY_IMAGE_SCN_ALIGN_MASK);
+ const UInt32 align = ((flags >> 20) & 0xF);
+ if (align != 0)
+ {
+ char sz[32];
+ ConvertUInt32ToString(1 << (align - 1), sz);
+ s.Add_Space();
+ s += "align_";
+ s += sz;
+ }
+ prop = s;
+ }
+ break;
+ case kpidZerosTailIsAllowed: if (!item.IsRealSect) prop = true; break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CHandler::LoadDebugSections(IInStream *stream, bool &thereIsSection)
+{
+ thereIsSection = false;
+ const CDirLink &debugLink = _optHeader.DirItems[kDirLink_Debug];
+ if (debugLink.Size == 0)
+ return S_OK;
+ const unsigned kEntrySize = 28;
+ UInt32 numItems = debugLink.Size / kEntrySize;
+ if (numItems > 16)
+ return S_FALSE;
+
+ // MAC's EFI file: numItems can be incorrect. Only first CDebugEntry entry is correct.
+ // debugLink.Size = kEntrySize + some_data, pointed by entry[0].
+ if (numItems * kEntrySize != debugLink.Size)
+ {
+ // return S_FALSE;
+ if (numItems > 1)
+ numItems = 1;
+ }
+
+ UInt64 pa = 0;
+ unsigned i;
+ for (i = 0; i < _sections.Size(); i++)
+ {
+ const CSection &sect = _sections[i];
+ if (sect.Va <= debugLink.Va && debugLink.Va + debugLink.Size <= sect.Va + sect.PSize)
+ {
+ pa = sect.Pa + (debugLink.Va - sect.Va);
+ break;
+ }
+ }
+ if (i == _sections.Size())
+ {
+ // Exe for ARM requires S_OK
+ // return S_FALSE;
+ return S_OK;
+ }
+
+ CByteBuffer buffer(debugLink.Size);
+ Byte *buf = buffer;
+
+ RINOK(InStream_SeekSet(stream, pa))
+ RINOK(ReadStream_FALSE(stream, buf, debugLink.Size))
+
+ for (i = 0; i < numItems; i++)
+ {
+ CDebugEntry de;
+ de.Parse(buf);
+
+ if (de.Size == 0)
+ continue;
+
+ UInt32 totalSize = de.Pa + de.Size;
+ if (totalSize > _totalSize)
+ {
+ _totalSize = totalSize;
+ thereIsSection = true;
+
+ CSection &sect = _sections.AddNew();
+ sect.Name = ".debug";
+ sect.Name.Add_UInt32(i);
+ sect.IsDebug = true;
+ sect.Time = de.Time;
+ sect.Va = de.Va;
+ sect.Pa = de.Pa;
+ sect.PSize = sect.VSize = de.Size;
+ }
+ buf += kEntrySize;
+ }
+
+ return S_OK;
+}
+
+HRESULT CHandler::ReadTable(UInt32 offset, CRecordVector<CTableItem> &items)
+{
+ if ((offset & 3) != 0 || offset >= _buf.Size())
+ return S_FALSE;
+ size_t rem = _buf.Size() - offset;
+ if (rem < 16)
+ return S_FALSE;
+ unsigned numNameItems = Get16(_buf + offset + 12);
+ unsigned numIdItems = Get16(_buf + offset + 14);
+ unsigned numItems = numNameItems + numIdItems;
+ if ((rem - 16) / 8 < numItems)
+ return S_FALSE;
+ if (!_usedRes.SetRange(offset, 16 + numItems * 8))
+ return S_FALSE;
+ offset += 16;
+ items.ClearAndReserve(numItems);
+ for (unsigned i = 0; i < numItems; i++, offset += 8)
+ {
+ const Byte *buf = _buf + offset;
+ CTableItem item;
+ item.ID = Get32(buf + 0);
+ if ((bool)((item.ID & kFlag) != 0) != (bool)(i < numNameItems))
+ return S_FALSE;
+ item.Offset = Get32(buf + 4);
+ items.AddInReserved(item);
+ }
+ return S_OK;
+}
+
+static const UInt32 kFileSizeMax = (UInt32)1 << 31;
+static const unsigned kNumResItemsMax = (unsigned)1 << 23;
+static const unsigned kNumStringLangsMax = 256;
+
+// BITMAPINFOHEADER
+struct CBitmapInfoHeader
+{
+ // UInt32 HeaderSize;
+ UInt32 XSize;
+ Int32 YSize;
+ UInt16 Planes;
+ UInt16 BitCount;
+ UInt32 Compression;
+ UInt32 SizeImage;
+
+ bool Parse(const Byte *p, size_t size);
+};
+
+static const UInt32 kBitmapInfoHeader_Size = 0x28;
+
+bool CBitmapInfoHeader::Parse(const Byte *p, size_t size)
+{
+ if (size < kBitmapInfoHeader_Size || Get32(p) != kBitmapInfoHeader_Size)
+ return false;
+ G32( 4, XSize);
+ G32_signed( 8, YSize);
+ G16(12, Planes);
+ G16(14, BitCount);
+ G32(16, Compression);
+ G32(20, SizeImage);
+ return true;
+}
+
+static UInt32 GetImageSize(UInt32 xSize, UInt32 ySize, UInt32 bitCount)
+{
+ return ((xSize * bitCount + 7) / 8 + 3) / 4 * 4 * ySize;
+}
+
+static UInt32 SetBitmapHeader(Byte *dest, const Byte *src, UInt32 size)
+{
+ CBitmapInfoHeader h;
+ if (!h.Parse(src, size))
+ return 0;
+ if (h.YSize < 0)
+ h.YSize = -h.YSize;
+ if (h.XSize > (1 << 26)
+ || h.YSize > (1 << 26)
+ || h.YSize < 0
+ || h.Planes != 1 || h.BitCount > 32)
+ return 0;
+ if (h.SizeImage == 0)
+ {
+ if (h.Compression != 0) // BI_RGB
+ return 0;
+ h.SizeImage = GetImageSize(h.XSize, (UInt32)h.YSize, h.BitCount);
+ }
+ UInt32 totalSize = kBmpHeaderSize + size;
+ UInt32 offBits = totalSize - h.SizeImage;
+ // BITMAPFILEHEADER
+ SetUi16(dest, 0x4D42)
+ SetUi32(dest + 2, totalSize)
+ SetUi32(dest + 6, 0)
+ SetUi32(dest + 10, offBits)
+ return kBmpHeaderSize;
+}
+
+static UInt32 SetIconHeader(Byte *dest, const Byte *src, UInt32 size)
+{
+ CBitmapInfoHeader h;
+ if (!h.Parse(src, size))
+ return 0;
+ if (h.YSize < 0)
+ h.YSize = -h.YSize;
+ if (h.XSize > (1 << 26)
+ || h.YSize > (1 << 26)
+ || h.YSize < 0
+ || h.Planes != 1
+ || h.Compression != 0) // BI_RGB
+ return 0;
+
+ const UInt32 numBitCount = h.BitCount;
+ if (numBitCount != 1 &&
+ numBitCount != 4 &&
+ numBitCount != 8 &&
+ numBitCount != 24 &&
+ numBitCount != 32)
+ return 0;
+
+ if ((h.YSize & 1) != 0)
+ return 0;
+ h.YSize /= 2;
+ if (h.XSize > 0x100 || h.YSize > 0x100)
+ return 0;
+
+ UInt32 imageSize;
+ // imageSize is not correct if AND mask array contains zeros
+ // in this case it is equal image1Size
+
+ // UInt32 imageSize = h.SizeImage;
+ // if (imageSize == 0)
+ // {
+ const UInt32 image1Size = GetImageSize(h.XSize, (UInt32)h.YSize, h.BitCount);
+ const UInt32 image2Size = GetImageSize(h.XSize, (UInt32)h.YSize, 1);
+ imageSize = image1Size + image2Size;
+ // }
+ UInt32 numColors = 0;
+ if (numBitCount < 16)
+ numColors = 1 << numBitCount;
+
+ SetUi16(dest, 0) // Reserved
+ SetUi16(dest + 2, 1) // RES_ICON
+ SetUi16(dest + 4, 1) // ResCount
+
+ dest[6] = (Byte)h.XSize; // Width
+ dest[7] = (Byte)h.YSize; // Height
+ dest[8] = (Byte)numColors; // ColorCount
+ dest[9] = 0; // Reserved
+
+ SetUi32(dest + 10, 0) // Reserved1 / Reserved2
+
+ UInt32 numQuadsBytes = numColors * 4;
+ UInt32 BytesInRes = kBitmapInfoHeader_Size + numQuadsBytes + imageSize;
+ SetUi32(dest + 14, BytesInRes)
+ SetUi32(dest + 18, kIconHeaderSize)
+
+ /*
+ Description = DWORDToString(xSize) +
+ kDelimiterChar + DWORDToString(ySize) +
+ kDelimiterChar + DWORDToString(numBitCount);
+ */
+ return kIconHeaderSize;
+}
+
+bool CHandler::ParseStringRes(UInt32 id, UInt32 lang, const Byte *src, UInt32 size)
+{
+ if ((size & 1) != 0)
+ return false;
+
+ unsigned i;
+ for (i = 0; i < _strings.Size(); i++)
+ if (_strings[i].Lang == lang)
+ break;
+ if (i == _strings.Size())
+ {
+ if (_strings.Size() >= kNumStringLangsMax)
+ return false;
+ CStringItem &item = _strings.AddNew();
+ item.Lang = lang;
+ }
+
+ CStringItem &item = _strings[i];
+ id = (id - 1) << 4;
+ UInt32 pos = 0;
+ for (i = 0; i < 16; i++)
+ {
+ if (size - pos < 2)
+ return false;
+ UInt32 len = Get16(src + pos);
+ pos += 2;
+ if (len != 0)
+ {
+ if (size - pos < len * 2)
+ return false;
+ char temp[32];
+ ConvertUInt32ToString(id + i, temp);
+ size_t tempLen = strlen(temp);
+ size_t j;
+ for (j = 0; j < tempLen; j++)
+ item.AddChar(temp[j]);
+ item.AddChar('\t');
+ for (j = 0; j < len; j++, pos += 2)
+ item.AddWChar_Smart(Get16(src + pos));
+ item.NewLine();
+ }
+ }
+ if (size == pos)
+ return true;
+
+ // Some rare case files have additional ZERO.
+ if (size == pos + 2 && Get16(src + pos) == 0)
+ return true;
+
+ return false;
+}
+
+
+// ---------- VERSION ----------
+
+static const UInt32 kMy_VS_FFI_SIGNATURE = 0xFEEF04BD;
+
+struct CMy_VS_FIXEDFILEINFO
+{
+ // UInt32 Signature;
+ // UInt32 StrucVersion;
+ UInt32 VersionMS;
+ UInt32 VersionLS;
+ UInt32 ProductVersionMS;
+ UInt32 ProductVersionLS;
+ UInt32 FlagsMask;
+ UInt32 Flags;
+ UInt32 OS;
+ UInt32 Type;
+ UInt32 Subtype;
+ UInt32 DateMS;
+ UInt32 DateLS;
+
+ bool Parse(const Byte *p);
+ void PrintToTextFile(CTextFile &f, CObjectVector<CStringKeyValue> &keys);
+};
+
+bool CMy_VS_FIXEDFILEINFO::Parse(const Byte *p)
+{
+ if (Get32(p) != kMy_VS_FFI_SIGNATURE) // signature;
+ return false;
+ // G32(0x04, StrucVersion);
+ G32(0x08, VersionMS);
+ G32(0x0C, VersionLS);
+ G32(0x10, ProductVersionMS);
+ G32(0x14, ProductVersionLS);
+ G32(0x18, FlagsMask);
+ G32(0x1C, Flags);
+ G32(0x20, OS);
+ G32(0x24, Type);
+ G32(0x28, Subtype);
+ G32(0x2C, DateMS);
+ G32(0x40, DateLS);
+ return true;
+}
+
+static void PrintUInt32(CTextFile &f, UInt32 v)
+{
+ char s[16];
+ ConvertUInt32ToString(v, s);
+ f.AddString(s);
+}
+
+static inline void PrintUInt32(UString &dest, UInt32 v)
+{
+ dest.Add_UInt32(v);
+}
+
+static void PrintHex(CTextFile &f, UInt32 val)
+{
+ char temp[16];
+ temp[0] = '0';
+ temp[1] = 'x';
+ ConvertUInt32ToHex(val, temp + 2);
+ f.AddString(temp);
+}
+
+static void PrintVersion(CTextFile &f, UInt32 ms, UInt32 ls)
+{
+ PrintUInt32(f, HIWORD(ms)); f.AddChar(',');
+ PrintUInt32(f, LOWORD(ms)); f.AddChar(',');
+ PrintUInt32(f, HIWORD(ls)); f.AddChar(',');
+ PrintUInt32(f, LOWORD(ls));
+}
+
+static void PrintVersion(UString &s, UInt32 ms, UInt32 ls)
+{
+ PrintUInt32(s, HIWORD(ms)); s.Add_Dot();
+ PrintUInt32(s, LOWORD(ms)); s.Add_Dot();
+ PrintUInt32(s, HIWORD(ls)); s.Add_Dot();
+ PrintUInt32(s, LOWORD(ls));
+}
+
+static const char * const k_VS_FileFlags[] =
+{
+ "DEBUG"
+ , "PRERELEASE"
+ , "PATCHED"
+ , "PRIVATEBUILD"
+ , "INFOINFERRED"
+ , "SPECIALBUILD"
+};
+
+static const CUInt32PCharPair k_VS_FileOS[] =
+{
+ { 0x10001, "VOS_DOS_WINDOWS16" },
+ { 0x10004, "VOS_DOS_WINDOWS32" },
+ { 0x20002, "VOS_OS216_PM16" },
+ { 0x30003, "VOS_OS232_PM32" },
+ { 0x40004, "VOS_NT_WINDOWS32" }
+};
+
+static const char * const k_VS_FileOS_High[] =
+{
+ "VOS_UNKNOWN"
+ , "VOS_DOS"
+ , "VOS_OS216"
+ , "VOS_OS232"
+ , "VOS_NT"
+ , "VOS_WINCE"
+};
+
+static const UInt32 kMY_VFT_DRV = 3;
+static const UInt32 kMY_VFT_FONT = 4;
+
+static const char * const k_VS_FileOS_Low[] =
+{
+ "VOS__BASE"
+ , "VOS__WINDOWS16"
+ , "VOS__PM16"
+ , "VOS__PM32"
+ , "VOS__WINDOWS32"
+};
+
+static const char * const k_VS_FileType[] =
+{
+ "VFT_UNKNOWN"
+ , "VFT_APP"
+ , "VFT_DLL"
+ , "VFT_DRV"
+ , "VFT_FONT"
+ , "VFT_VXD"
+ , "0x6"
+ , "VFT_STATIC_LIB"
+};
+
+// Subtype for VFT_DRV Type
+static const char * const k_VS_FileSubType_DRV[] =
+{
+ "0"
+ , "PRINTER"
+ , "KEYBOARD"
+ , "LANGUAGE"
+ , "DISPLAY"
+ , "MOUSE"
+ , "NETWORK"
+ , "SYSTEM"
+ , "INSTALLABLE"
+ , "SOUND"
+ , "COMM"
+ , "INPUTMETHOD"
+ , "VERSIONED_PRINTER"
+};
+
+// Subtype for VFT_FONT Type
+static const char * const k_VS_FileSubType_FONT[] =
+{
+ "0"
+ , "VFT2_FONT_RASTER"
+ , "VFT2_FONT_VECTOR"
+ , "VFT2_FONT_TRUETYPE"
+};
+
+static int FindKey(CObjectVector<CStringKeyValue> &v, const char *key)
+{
+ FOR_VECTOR (i, v)
+ if (v[i].Key.IsEqualTo(key))
+ return (int)i;
+ return -1;
+}
+
+static void AddToUniqueUStringVector(CObjectVector<CStringKeyValue> &v, const UString &key, const UString &value)
+{
+ bool needInsert = false;
+ unsigned i;
+ for (i = 0; i < v.Size(); i++)
+ {
+ if (v[i].Key == key)
+ {
+ if (v[i].Value == value)
+ return;
+ needInsert = true;
+ }
+ else if (needInsert)
+ break;
+ }
+ CStringKeyValue &pair = v.InsertNew(i);
+ pair.Key = key;
+ pair.Value = value;
+}
+
+void CMy_VS_FIXEDFILEINFO::PrintToTextFile(CTextFile &f, CObjectVector<CStringKeyValue> &keys)
+{
+ f.AddString("FILEVERSION ");
+ PrintVersion(f, VersionMS, VersionLS);
+ f.NewLine();
+
+ f.AddString("PRODUCTVERSION ");
+ PrintVersion(f, ProductVersionMS, ProductVersionLS);
+ f.NewLine();
+
+ {
+ UString s;
+ PrintVersion(s, VersionMS, VersionLS);
+ AddToUniqueUStringVector(keys, L"FileVersion", s);
+ }
+ {
+ UString s;
+ PrintVersion(s, ProductVersionMS, ProductVersionLS);
+ AddToUniqueUStringVector(keys, L"ProductVersion", s);
+ }
+
+ f.AddString("FILEFLAGSMASK ");
+ PrintHex(f, FlagsMask);
+ f.NewLine();
+
+ f.AddString("FILEFLAGS ");
+ {
+ bool wasPrinted = false;
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_VS_FileFlags); i++)
+ {
+ if ((Flags & ((UInt32)1 << i)) != 0)
+ {
+ if (wasPrinted)
+ f.AddString(" | ");
+ f.AddString("VS_FF_");
+ f.AddString(k_VS_FileFlags[i]);
+ wasPrinted = true;
+ }
+ }
+ UInt32 v = Flags & ~(((UInt32)1 << Z7_ARRAY_SIZE(k_VS_FileFlags)) - 1);
+ if (v != 0 || !wasPrinted)
+ {
+ if (wasPrinted)
+ f.AddString(" | ");
+ PrintHex(f, v);
+ }
+ }
+ f.NewLine();
+
+ // OS = 0x111230;
+ f.AddString("FILEOS ");
+ unsigned i;
+ for (i = 0; i < Z7_ARRAY_SIZE(k_VS_FileOS); i++)
+ {
+ const CUInt32PCharPair &pair = k_VS_FileOS[i];
+ if (OS == pair.Value)
+ {
+ // continue;
+ // f.AddString("VOS_");
+ f.AddString(pair.Name);
+ break;
+ }
+ }
+ if (i == Z7_ARRAY_SIZE(k_VS_FileOS))
+ {
+ UInt32 high = OS >> 16;
+ if (high < Z7_ARRAY_SIZE(k_VS_FileOS_High))
+ f.AddString(k_VS_FileOS_High[high]);
+ else
+ PrintHex(f, high << 16);
+ UInt32 low = OS & 0xFFFF;
+ if (low != 0)
+ {
+ f.AddString(" | ");
+ if (low < Z7_ARRAY_SIZE(k_VS_FileOS_Low))
+ f.AddString(k_VS_FileOS_Low[low]);
+ else
+ PrintHex(f, low);
+ }
+ }
+ f.NewLine();
+
+ f.AddString("FILETYPE ");
+ if (Type < Z7_ARRAY_SIZE(k_VS_FileType))
+ f.AddString(k_VS_FileType[Type]);
+ else
+ PrintHex(f, Type);
+ f.NewLine();
+
+ f.AddString("FILESUBTYPE ");
+ bool needPrintSubType = true;
+ if (Type == kMY_VFT_DRV)
+ {
+ if (Subtype != 0 && Subtype < Z7_ARRAY_SIZE(k_VS_FileSubType_DRV))
+ {
+ f.AddString("VFT2_DRV_");
+ f.AddString(k_VS_FileSubType_DRV[Subtype]);
+ needPrintSubType = false;
+ }
+ }
+ else if (Type == kMY_VFT_FONT)
+ {
+ if (Subtype != 0 && Subtype < Z7_ARRAY_SIZE(k_VS_FileSubType_FONT))
+ {
+ f.AddString(k_VS_FileSubType_FONT[Subtype]);
+ needPrintSubType = false;
+ }
+ }
+ if (needPrintSubType)
+ PrintHex(f, Subtype);
+ f.NewLine();
+}
+
+static void CopyToUString(const Byte *p, UString &s)
+{
+ for (;;)
+ {
+ wchar_t c = (wchar_t)Get16(p);
+ p += 2;
+ if (c == 0)
+ return;
+ s += c;
+ }
+}
+
+static bool CompareWStrStrings(const Byte *p, const char *s)
+{
+ unsigned pos = 0;
+ for (;;)
+ {
+ const Byte c = (Byte)*s++;
+ if (Get16(p + pos) != c)
+ return false;
+ pos += 2;
+ if (c == 0)
+ return true;
+ }
+}
+
+struct CVersionBlock
+{
+ UInt32 TotalLen;
+ UInt32 ValueLen;
+ bool IsTextValue;
+ unsigned StrSize;
+
+ bool Parse(const Byte *p, UInt32 size);
+};
+
+static int Get_Utf16Str_Len_InBytes(const Byte *p, size_t size)
+{
+ unsigned pos = 0;
+ for (;;)
+ {
+ if (pos + 1 >= size)
+ return -1;
+ if (Get16(p + pos) == 0)
+ return (int)pos;
+ pos += 2;
+ }
+}
+
+static const unsigned k_ResoureBlockHeader_Size = 6;
+
+bool CVersionBlock::Parse(const Byte *p, UInt32 size)
+{
+ if (size < k_ResoureBlockHeader_Size)
+ return false;
+ TotalLen = Get16(p);
+ ValueLen = Get16(p + 2);
+ if (TotalLen < k_ResoureBlockHeader_Size || TotalLen > size)
+ return false;
+ switch (Get16(p + 4))
+ {
+ case 0: IsTextValue = false; break;
+ case 1: IsTextValue = true; break;
+ default: return false;
+ }
+ StrSize = 0;
+ const int t = Get_Utf16Str_Len_InBytes(p + k_ResoureBlockHeader_Size, TotalLen - k_ResoureBlockHeader_Size);
+ if (t < 0)
+ return false;
+ StrSize = (unsigned)t;
+ return true;
+}
+
+static void AddParamString(CTextFile &f, const Byte *p, size_t sLen)
+{
+ f.AddChar(' ');
+ f.AddChar('\"');
+ f.AddBytes(p, sLen);
+ f.AddChar('\"');
+}
+
+static bool ParseVersion(const Byte *p, UInt32 size, CTextFile &f, CObjectVector<CStringKeyValue> &keys)
+{
+ UInt32 pos;
+ {
+ const unsigned k_sizeof_VS_FIXEDFILEINFO = 13 * 4;
+
+ CVersionBlock vb;
+ if (!vb.Parse(p, size))
+ return false;
+ if (vb.ValueLen != k_sizeof_VS_FIXEDFILEINFO) // maybe 0 is allowed here?
+ return false;
+ if (vb.IsTextValue)
+ return false;
+ pos = k_ResoureBlockHeader_Size;
+ if (!CompareWStrStrings(p + pos, "VS_VERSION_INFO"))
+ return false;
+ pos += vb.StrSize + 2;
+ pos += (4 - pos) & 3;
+ if (pos + vb.ValueLen > vb.TotalLen)
+ return false;
+ /* sometimes resource contains zeros in remainder.
+ So we don't check that size != vb.TotalLen
+ // if (size != vb.TotalLen) return false;
+ */
+ if (size > vb.TotalLen)
+ size = vb.TotalLen;
+ CMy_VS_FIXEDFILEINFO FixedFileInfo;
+ if (!FixedFileInfo.Parse(p + pos))
+ return false;
+ FixedFileInfo.PrintToTextFile(f, keys);
+ pos += vb.ValueLen;
+ }
+
+ f.OpenBlock(0);
+
+ for (;;)
+ {
+ pos += (4 - pos) & 3;
+ if (pos >= size)
+ break;
+
+ CVersionBlock vb;
+ if (!vb.Parse(p + pos, size - pos))
+ return false;
+ if (vb.ValueLen != 0)
+ return false;
+ UInt32 endPos = pos + vb.TotalLen;
+ pos += k_ResoureBlockHeader_Size;
+
+ f.AddSpaces(2);
+ f.AddString("BLOCK");
+ AddParamString(f, p + pos, vb.StrSize);
+
+ f.NewLine();
+ f.OpenBlock(2);
+
+ if (CompareWStrStrings(p + pos, "VarFileInfo"))
+ {
+ pos += vb.StrSize + 2;
+ for (;;)
+ {
+ pos += (4 - pos) & 3;
+ if (pos >= endPos)
+ break;
+ CVersionBlock vb2;
+ if (!vb2.Parse(p + pos, endPos - pos))
+ return false;
+ UInt32 endPos2 = pos + vb2.TotalLen;
+ if (vb2.IsTextValue)
+ return false;
+ pos += k_ResoureBlockHeader_Size;
+ f.AddSpaces(4);
+ f.AddString("VALUE");
+ AddParamString(f, p + pos, vb2.StrSize);
+ if (!CompareWStrStrings(p + pos, "Translation"))
+ return false;
+ pos += vb2.StrSize + 2;
+ pos += (4 - pos) & 3;
+ if (pos + vb2.ValueLen != endPos2)
+ return false;
+ if ((vb2.ValueLen & 3) != 0)
+ return false;
+ UInt32 num = (vb2.ValueLen >> 2);
+ for (; num != 0; num--, pos += 4)
+ {
+ UInt32 dw = Get32(p + pos);
+ UInt32 lang = LOWORD(dw);
+ UInt32 codePage = HIWORD(dw);
+
+ f.AddString(", ");
+ PrintHex(f, lang);
+ f.AddString(", ");
+ PrintUInt32(f, codePage);
+ }
+ f.NewLine();
+ }
+ }
+ else
+ {
+ if (!CompareWStrStrings(p + pos, "StringFileInfo"))
+ return false;
+ pos += vb.StrSize + 2;
+
+ for (;;)
+ {
+ pos += (4 - pos) & 3;
+ if (pos >= endPos)
+ break;
+ CVersionBlock vb2;
+ if (!vb2.Parse(p + pos, endPos - pos))
+ return false;
+ UInt32 endPos2 = pos + vb2.TotalLen;
+ if (vb2.ValueLen != 0)
+ return false;
+ pos += k_ResoureBlockHeader_Size;
+
+ f.AddSpaces(4);
+ f.AddString("BLOCK");
+ AddParamString(f, p + pos, vb2.StrSize);
+ pos += vb2.StrSize + 2;
+
+ f.NewLine();
+ f.OpenBlock(4);
+
+ for (;;)
+ {
+ pos += (4 - pos) & 3;
+ if (pos >= endPos2)
+ break;
+
+ CVersionBlock vb3;
+ if (!vb3.Parse(p + pos, endPos2 - pos))
+ return false;
+ // ValueLen sometimes is a number of characters (not bytes)?
+ // So we don't use it.
+ UInt32 endPos3 = pos + vb3.TotalLen;
+ pos += k_ResoureBlockHeader_Size;
+
+ // we don't write string if it's not text
+ if (vb3.IsTextValue)
+ {
+ f.AddSpaces(6);
+ f.AddString("VALUE");
+ AddParamString(f, p + pos, vb3.StrSize);
+ UString key;
+ UString value;
+ CopyToUString(p + pos, key);
+ pos += vb3.StrSize + 2;
+
+ pos += (4 - pos) & 3;
+ if (vb3.ValueLen > 0 && pos + 2 <= endPos3)
+ {
+ f.AddChar(',');
+ f.AddSpaces((34 - (int)vb3.StrSize) / 2);
+ const int sLen = Get_Utf16Str_Len_InBytes(p + pos, endPos3 - pos);
+ if (sLen < 0)
+ return false;
+ AddParamString(f, p + pos, (unsigned)sLen);
+ CopyToUString(p + pos, value);
+ pos += (unsigned)sLen + 2;
+ }
+ AddToUniqueUStringVector(keys, key, value);
+ }
+ pos = endPos3;
+ f.NewLine();
+ }
+ f.CloseBlock(4);
+ }
+ }
+ f.CloseBlock(2);
+ }
+
+ f.CloseBlock(0);
+ return true;
+}
+
+
+HRESULT CHandler::OpenResources(unsigned sectionIndex, IInStream *stream, IArchiveOpenCallback *callback)
+{
+ const CSection &sect = _sections[sectionIndex];
+ size_t fileSize = sect.PSize;
+ {
+ size_t fileSizeMin = sect.PSize;
+
+ if (sect.VSize < sect.PSize)
+ {
+ fileSize = fileSizeMin = sect.VSize;
+ const int numBits = _optHeader.GetNumFileAlignBits();
+ if (numBits > 0)
+ {
+ const UInt32 mask = ((UInt32)1 << numBits) - 1;
+ const size_t end = (size_t)((sect.VSize + mask) & (UInt32)~mask);
+ if (end > sect.VSize)
+ {
+ if (end <= sect.PSize)
+ fileSize = end;
+ else
+ fileSize = sect.PSize;
+ }
+ }
+ }
+
+ if (fileSize > kFileSizeMax)
+ return S_FALSE;
+
+ {
+ const UInt64 fileSize64 = fileSize;
+ if (callback)
+ RINOK(callback->SetTotal(NULL, &fileSize64))
+ }
+
+ RINOK(InStream_SeekSet(stream, sect.Pa))
+
+ _buf.Alloc(fileSize);
+
+ size_t pos;
+
+ for (pos = 0; pos < fileSize;)
+ {
+ {
+ const UInt64 offset64 = pos;
+ if (callback)
+ RINOK(callback->SetCompleted(NULL, &offset64))
+ }
+ size_t rem = MyMin(fileSize - pos, (size_t)(1 << 22));
+ RINOK(ReadStream(stream, _buf + pos, &rem))
+ if (rem == 0)
+ {
+ if (pos < fileSizeMin)
+ return S_FALSE;
+ break;
+ }
+ pos += rem;
+ }
+
+ if (pos < fileSize)
+ memset(_buf + pos, 0, fileSize - pos);
+ }
+
+ _usedRes.Alloc(fileSize);
+ CRecordVector<CTableItem> specItems;
+ RINOK(ReadTable(0, specItems))
+
+ _oneLang = true;
+ bool stringsOk = true;
+ size_t maxOffset = 0;
+
+ FOR_VECTOR (i, specItems)
+ {
+ const CTableItem &item1 = specItems[i];
+ if ((item1.Offset & kFlag) == 0)
+ return S_FALSE;
+
+ CRecordVector<CTableItem> specItems2;
+ RINOK(ReadTable(item1.Offset & kMask, specItems2))
+
+ FOR_VECTOR (j, specItems2)
+ {
+ const CTableItem &item2 = specItems2[j];
+ if ((item2.Offset & kFlag) == 0)
+ return S_FALSE;
+
+ CRecordVector<CTableItem> specItems3;
+ RINOK(ReadTable(item2.Offset & kMask, specItems3))
+
+ CResItem item;
+ item.Type = item1.ID;
+ item.ID = item2.ID;
+
+ FOR_VECTOR (k, specItems3)
+ {
+ if (_items.Size() >= kNumResItemsMax)
+ return S_FALSE;
+ const CTableItem &item3 = specItems3[k];
+ if ((item3.Offset & kFlag) != 0)
+ return S_FALSE;
+ if (item3.Offset >= _buf.Size() || _buf.Size() - item3.Offset < 16)
+ return S_FALSE;
+ const Byte *buf = _buf + item3.Offset;
+ item.Lang = item3.ID;
+ item.Offset = Get32(buf + 0);
+ item.Size = Get32(buf + 4);
+ // UInt32 codePage = Get32(buf + 8);
+ if (Get32(buf + 12) != 0)
+ return S_FALSE;
+ if (!_items.IsEmpty() && _oneLang && !item.IsNameEqual(_items.Back()))
+ _oneLang = false;
+
+ item.HeaderSize = 0;
+
+ size_t offset = item.Offset - sect.Va;
+ if (offset > maxOffset)
+ maxOffset = offset;
+ if (offset + item.Size > maxOffset)
+ maxOffset = offset + item.Size;
+
+ if (CheckItem(sect, item, offset))
+ {
+ const Byte *data = _buf + offset;
+ if (item.IsBmp())
+ item.HeaderSize = SetBitmapHeader(item.Header, data, item.Size);
+ else if (item.IsIcon())
+ item.HeaderSize = SetIconHeader(item.Header, data, item.Size);
+ else if (item.IsString())
+ {
+ if (stringsOk)
+ stringsOk = ParseStringRes(item.ID, item.Lang, data, item.Size);
+ }
+ }
+
+ if (item.IsVersion())
+ {
+ if (offset > _buf.Size() || _buf.Size() - offset < item.Size)
+ continue;
+ CTextFile f;
+ if (ParseVersion((const Byte *)_buf + offset, item.Size, f, _versionKeys))
+ {
+ CMixItem mixItem;
+ mixItem.VersionIndex = (int)_versionFiles.Size();
+ mixItem.SectionIndex = (int)sectionIndex; // check it !!!!
+ CByteBuffer_WithLang &vf = _versionFiles.AddNew();
+ vf.Lang = item.Lang;
+ vf.CopyFrom(f.Buf, f.Buf.GetPos());
+ _mixItems.Add(mixItem);
+ continue;
+ }
+ // PrintError("ver.Parse error");
+ }
+
+ item.Enabled = true;
+ _items.Add(item);
+ }
+ }
+ }
+
+ if (stringsOk && !_strings.IsEmpty())
+ {
+ unsigned i;
+ for (i = 0; i < _items.Size(); i++)
+ {
+ CResItem &item = _items[i];
+ if (item.IsString())
+ item.Enabled = false;
+ }
+ for (i = 0; i < _strings.Size(); i++)
+ {
+ if (_strings[i].FinalSize() == 0)
+ continue;
+ CMixItem mixItem;
+ mixItem.StringIndex = (int)i;
+ mixItem.SectionIndex = (int)sectionIndex;
+ _mixItems.Add(mixItem);
+ }
+ }
+
+ _usedRes.Free();
+
+ {
+ // PSize can be much larger than VSize in some exe installers.
+ // it contains archive data after PE resources.
+ // So we need to use PSize here!
+ if (maxOffset < sect.PSize)
+ {
+ size_t end = fileSize;
+
+ // we skip Zeros to start of aligned block
+ size_t i;
+ for (i = maxOffset; i < end; i++)
+ if (_buf[i] != 0)
+ break;
+ if (i == end)
+ maxOffset = end;
+
+ CSection sect2;
+ sect2.Flags = 0;
+ sect2.Pa = sect.Pa + (UInt32)maxOffset;
+ sect2.Va = sect.Va + (UInt32)maxOffset;
+
+ // 9.29: we use sect.PSize instead of sect.VSize to support some CAB-SFX
+ // the code for .rsrc_2 is commented.
+ sect2.PSize = sect.PSize - (UInt32)maxOffset;
+
+ if (sect2.PSize != 0)
+ {
+ sect2.VSize = sect2.PSize;
+ sect2.Name = ".rsrc_1";
+ sect2.Time = 0;
+ sect2.IsAdditionalSection = true;
+ _sections.Add(sect2);
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+bool CHeader::ParseCoff(const Byte *p)
+{
+ ParseBase(p);
+ if (PointerToSymbolTable < kCoffHeaderSize)
+ return false;
+ if (NumSymbols >= (1 << 24))
+ return false;
+ if (OptHeaderSize != 0 && OptHeaderSize < k_OptHeader32_Size_MIN)
+ return false;
+
+ // 18.04: we reduce false detections
+ if (NumSections == 0 && OptHeaderSize == 0)
+ return false;
+
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_MachinePairs); i++)
+ if (Machine == g_MachinePairs[i].Value)
+ return true;
+ if (Machine == 0)
+ return true;
+
+ return false;
+}
+
+
+static inline bool CheckPeOffset(UInt32 pe)
+{
+ // ((pe & 7) == 0) is for most PE files. But there is unusual EFI-PE file that uses unaligned pe value.
+ return pe >= 0x40 && pe <= 0x1000 /* && (pe & 7) == 0 */ ;
+}
+
+static const unsigned kStartSize = 0x40;
+
+API_FUNC_static_IsArc IsArc_Pe(const Byte *p, size_t size)
+{
+ if (size < 2)
+ return k_IsArc_Res_NEED_MORE;
+ if (p[0] != 'M' || p[1] != 'Z')
+ return k_IsArc_Res_NO;
+ if (size < kStartSize)
+ return k_IsArc_Res_NEED_MORE;
+ UInt32 pe = Get32(p + 0x3C);
+ if (!CheckPeOffset(pe))
+ return k_IsArc_Res_NO;
+ if (pe + kPeHeaderSize > size)
+ return k_IsArc_Res_NEED_MORE;
+ CHeader header;
+ if (!header.ParsePe(p + pe))
+ return k_IsArc_Res_NO;
+ return k_IsArc_Res_YES;
+}
+}
+
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
+{
+ UInt32 coffOffset = 0;
+ if (_coffMode)
+ {
+ Byte h[kCoffHeaderSize];
+ RINOK(ReadStream_FALSE(stream, h, kCoffHeaderSize))
+ if (!_header.ParseCoff(h))
+ return S_FALSE;
+ }
+ else
+ {
+ UInt32 _peOffset;
+ {
+ Byte h[kStartSize];
+ RINOK(ReadStream_FALSE(stream, h, kStartSize))
+ if (h[0] != 'M' || h[1] != 'Z')
+ return S_FALSE;
+ /* most of PE files contain 0x0090 at offset 2.
+ But some rare PE files contain another values. So we don't use that check.
+ if (Get16(h + 2) != 0x90) return false; */
+ _peOffset = Get32(h + 0x3C);
+ if (!CheckPeOffset(_peOffset))
+ return S_FALSE;
+ coffOffset = _peOffset + 4;
+ }
+ {
+ Byte h[kPeHeaderSize];
+ RINOK(InStream_SeekSet(stream, _peOffset))
+ RINOK(ReadStream_FALSE(stream, h, kPeHeaderSize))
+ if (!_header.ParsePe(h))
+ return S_FALSE;
+ }
+ }
+
+ const UInt32 optStart = coffOffset + kCoffHeaderSize;
+ const UInt32 bufSize = _header.OptHeaderSize + (UInt32)_header.NumSections * kSectionSize;
+ _totalSize = optStart + bufSize;
+ CByteBuffer buffer(bufSize);
+
+ RINOK(ReadStream_FALSE(stream, buffer, bufSize))
+
+ // memset((void *)&_optHeader, 0, sizeof(_optHeader));
+ if (_header.OptHeaderSize != 0)
+ if (!_optHeader.Parse(buffer, _header.OptHeaderSize))
+ return S_FALSE;
+
+ UInt32 pos = _header.OptHeaderSize;
+ unsigned i;
+ for (i = 0; i < _header.NumSections; i++, pos += kSectionSize)
+ {
+ CSection &sect = _sections.AddNew();
+ sect.Parse(buffer + pos);
+ sect.IsRealSect = true;
+
+ /* PE pre-file in .hxs file has errors:
+ PSize of resource is larger than real size.
+ So it overlaps next ".its" section.
+ 7-zip before 22.02: we corrected it.
+
+ 22.02: another bad case is possible in incorrect pe (exe) file:
+ PSize in .rsrc section is correct,
+ but next .reloc section has incorrect (Pa) that overlaps with .rsrc.
+ */
+
+ if (i != 0)
+ {
+ const CSection &prev = _sections[i - 1];
+ if (prev.Pa < sect.Pa
+ && prev.Pa + prev.PSize > sect.Pa
+ && sect.PSize != 0
+ && prev.PSize != 0)
+ {
+ _sectionsError = true;
+ // PRF(printf("\n !!!! Section correction: %s\n ", prev.Name));
+
+ /* we corrected that case in 7-zip before 22.02: */
+ // prev.PSize = sect.Pa - prev.Pa;
+
+ /* 22.02: here we can try to change bad section position to expected postion.
+ but original Windows code probably will not do same things. */
+ // if (prev.PSize <= sect.Va - prev.Va) sect.Pa = prev.Pa + prev.PSize;
+ }
+ }
+ /* last ".its" section in hxs file has incorrect sect.PSize.
+ 7-zip before 22.02: we reduced section to real sect.VSize */
+ /*
+ if (sect.VSize == 24 && sect.PSize == 512 && i == (unsigned)_header.NumSections - 1)
+ sect.PSize = sect.VSize;
+ */
+ }
+
+ for (i = 0; i < _sections.Size(); i++)
+ _sections[i].UpdateTotalSize(_totalSize);
+
+ bool thereISDebug = false;
+ if (IsOpt())
+ {
+ RINOK(LoadDebugSections(stream, thereISDebug))
+
+ const CDirLink &certLink = _optHeader.DirItems[kDirLink_Certificate];
+ if (certLink.Size != 0)
+ {
+ CSection &sect = _sections.AddNew();
+ sect.Name = "CERTIFICATE";
+ sect.Va = 0;
+ sect.Pa = certLink.Va;
+ sect.PSize = sect.VSize = certLink.Size;
+ sect.UpdateTotalSize(_totalSize);
+ }
+
+ if (thereISDebug)
+ {
+ /* sometime there is some data after debug section.
+ We don't see any reference in exe file to that data.
+ But we suppose that it's part of EXE file */
+
+ const UInt32 kAlign = 1 << 12;
+ UInt32 alignPos = _totalSize & (kAlign - 1);
+ if (alignPos != 0)
+ {
+ UInt32 size = kAlign - alignPos;
+ RINOK(InStream_SeekSet(stream, _totalSize))
+ buffer.Alloc(kAlign);
+ Byte *buf = buffer;
+ size_t processed = size;
+ RINOK(ReadStream(stream, buf, &processed))
+
+ /*
+ if (processed != 0)
+ {
+ printf("\ndata after debug %d, %d \n", (int)size, (int)processed);
+ fflush(stdout);
+ }
+ */
+
+ size_t k;
+ for (k = 0; k < processed; k++)
+ if (buf[k] != 0)
+ break;
+ if (processed < size && processed < 100)
+ _totalSize += (UInt32)processed;
+ else if (((_totalSize + k) & 0x1FF) == 0 || processed < size)
+ _totalSize += (UInt32)k;
+ }
+ }
+ }
+
+ if (_header.NumSymbols > 0 && _header.PointerToSymbolTable >= optStart)
+ {
+ if (_header.NumSymbols >= (1 << 24))
+ return S_FALSE;
+ UInt32 size = _header.NumSymbols * 18;
+ RINOK(InStream_SeekSet(stream, (UInt64)_header.PointerToSymbolTable + size))
+ Byte buf[4];
+ RINOK(ReadStream_FALSE(stream, buf, 4))
+ UInt32 size2 = Get32(buf);
+ if (size2 >= (1 << 28))
+ return S_FALSE;
+ size += size2;
+
+ CSection &sect = _sections.AddNew();
+ sect.Name = "COFF_SYMBOLS";
+ sect.Va = 0;
+ sect.Pa = _header.PointerToSymbolTable;
+ sect.PSize = sect.VSize = size;
+ sect.UpdateTotalSize(_totalSize);
+ }
+
+ {
+ CObjectVector<CSection> sections = _sections;
+ sections.Sort();
+ UInt32 limit = (1 << 12);
+ unsigned num = 0;
+ FOR_VECTOR (k, sections)
+ {
+ const CSection &s = sections[k];
+ if (s.Pa > limit)
+ {
+ CSection &s2 = _sections.AddNew();
+ s2.Pa = s2.Va = limit;
+ s2.PSize = s2.VSize = s.Pa - limit;
+ s2.IsAdditionalSection = true;
+ s2.Name = '[';
+ s2.Name.Add_UInt32(num++);
+ s2.Name += ']';
+ limit = s.Pa;
+ }
+ UInt32 next = s.Pa + s.PSize;
+ if (next < s.Pa)
+ break;
+ if (next >= limit)
+ limit = next;
+ }
+ }
+
+
+ if (IsOpt())
+ if (_optHeader.CheckSum != 0)
+ {
+ RINOK(InStream_SeekToBegin(stream))
+ UInt32 checkSum = 0;
+ RINOK(CalcCheckSum(stream, _totalSize, optStart + k_CheckSum_Field_Offset, checkSum))
+ _checksumError = (checkSum != _optHeader.CheckSum);
+ }
+
+
+ if (!_allowTail)
+ {
+ UInt64 fileSize;
+ RINOK(InStream_GetSize_SeekToEnd(stream, fileSize))
+ if (fileSize > _totalSize)
+ return S_FALSE;
+ }
+
+ bool _parseResources = true;
+ // _parseResources = false; // for debug
+
+ UInt64 mainSize = 0, mainSize2 = 0;
+
+ for (i = 0; i < _sections.Size(); i++)
+ {
+ const CSection &sect = _sections[i];
+ if (IsOpt())
+ if (_parseResources && sect.Name == ".rsrc")
+ {
+ // 20.01: we try to parse only first copy of .rsrc section.
+ _parseResources = false;
+ const unsigned numMixItems = _mixItems.Size();
+ HRESULT res = OpenResources(i, stream, callback);
+ if (res == S_OK)
+ {
+ _resourcesPrefix = sect.Name.Ptr();
+ _resourcesPrefix.Add_PathSepar();
+ FOR_VECTOR (j, _items)
+ {
+ const CResItem &item = _items[j];
+ if (item.Enabled)
+ {
+ CMixItem mixItem;
+ mixItem.SectionIndex = (int)i;
+ mixItem.ResourceIndex = (int)j;
+ if (item.IsRcDataOrUnknown())
+ {
+ if (item.Size >= mainSize)
+ {
+ mainSize2 = mainSize;
+ mainSize = item.Size;
+ _mainSubfile = (Int32)(int)_mixItems.Size();
+ }
+ else if (item.Size >= mainSize2)
+ mainSize2 = item.Size;
+ }
+ _mixItems.Add(mixItem);
+ }
+ }
+ // 9.29: .rsrc_2 code was commented.
+ // .rsrc_1 now must include that .rsrc_2 block.
+ /*
+ if (sect.PSize > sect.VSize)
+ {
+ int numBits = _optHeader.GetNumFileAlignBits();
+ if (numBits >= 0)
+ {
+ UInt32 mask = (1 << numBits) - 1;
+ UInt32 end = ((sect.VSize + mask) & ~mask);
+
+ if (sect.PSize > end)
+ {
+ CSection &sect2 = _sections.AddNew();
+ sect2.Flags = 0;
+ sect2.Pa = sect.Pa + end;
+ sect2.Va = sect.Va + end;
+ sect2.PSize = sect.PSize - end;
+ sect2.VSize = sect2.PSize;
+ sect2.Name = ".rsrc_2";
+ sect2.Time = 0;
+ sect2.IsAdditionalSection = true;
+ }
+ }
+ }
+ */
+ continue;
+ }
+ if (res != S_FALSE)
+ return res;
+ _mixItems.DeleteFrom(numMixItems);
+ CloseResources();
+ }
+
+ if (sect.IsAdditionalSection)
+ {
+ if (sect.PSize >= mainSize)
+ {
+ mainSize2 = mainSize;
+ mainSize = sect.PSize;
+ _mainSubfile = (Int32)(int)_mixItems.Size();
+ }
+ else if (sect.PSize >= mainSize2)
+ mainSize2 = sect.PSize;
+ }
+
+ CMixItem mixItem;
+ mixItem.SectionIndex = (int)i;
+ _mixItems.Add(mixItem);
+ }
+
+ if (mainSize2 >= (1 << 20) && mainSize < mainSize2 * 2)
+ _mainSubfile = -1;
+
+ for (i = 0; i < _mixItems.Size(); i++)
+ {
+ const CMixItem &mixItem = _mixItems[i];
+ if (mixItem.StringIndex < 0 && mixItem.ResourceIndex < 0 && _sections[mixItem.SectionIndex].Name == "_winzip_")
+ {
+ _mainSubfile = (Int32)(int)i;
+ break;
+ }
+ }
+
+ for (i = 0; i < _versionKeys.Size(); i++)
+ {
+ if (i != 0)
+ _versionFullString.Add_LF();
+ const CStringKeyValue &k = _versionKeys[i];
+ _versionFullString += k.Key;
+ _versionFullString += ": ";
+ _versionFullString += k.Value;
+ }
+
+ {
+ int keyIndex = FindKey(_versionKeys, "OriginalFilename");
+ if (keyIndex >= 0)
+ _originalFilename = _versionKeys[keyIndex].Value;
+ }
+ {
+ int keyIndex = FindKey(_versionKeys, "FileDescription");
+ if (keyIndex >= 0)
+ _versionShortString = _versionKeys[keyIndex].Value;
+ }
+ {
+ int keyIndex = FindKey(_versionKeys, "FileVersion");
+ if (keyIndex >= 0)
+ {
+ _versionShortString.Add_Space();
+ _versionShortString += _versionKeys[keyIndex].Value;
+ }
+ }
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ Close();
+ RINOK(Open2(inStream, callback))
+ _stream = inStream;
+ return S_OK;
+ COM_TRY_END
+}
+
+void CHandler::CloseResources()
+{
+ _usedRes.Free();
+ _items.Clear();
+ _strings.Clear();
+ _versionFiles.Clear();
+ _buf.Free();
+ _versionFullString.Empty();
+ _versionShortString.Empty();
+ _originalFilename.Empty();
+ _versionKeys.Clear();
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _totalSize = 0;
+ _checksumError = false;
+ _sectionsError = false;
+ _mainSubfile = -1;
+
+ _stream.Release();
+ _sections.Clear();
+ _mixItems.Clear();
+ CloseResources();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _mixItems.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _mixItems.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const CMixItem &mixItem = _mixItems[allFilesMode ? i : indices[i]];
+ UInt64 size;
+ if (mixItem.StringIndex >= 0)
+ size = _strings[mixItem.StringIndex].FinalSize();
+ else if (mixItem.VersionIndex >= 0)
+ size = _versionFiles[mixItem.VersionIndex].Size();
+ else if (mixItem.ResourceIndex >= 0)
+ size = _items[mixItem.ResourceIndex].GetSize();
+ else
+ size = _sections[mixItem.SectionIndex].GetSizeExtract();
+ totalSize += size;
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+ UInt64 currentItemSize;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++, currentTotalSize += currentItemSize)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur())
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ RINOK(extractCallback->GetStream(index, &outStream, askMode))
+ const CMixItem &mixItem = _mixItems[index];
+
+ const CSection &sect = _sections[mixItem.SectionIndex];
+ bool isOk = true;
+ if (mixItem.StringIndex >= 0)
+ {
+ const CStringItem &item = _strings[mixItem.StringIndex];
+ currentItemSize = item.FinalSize();
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode))
+ if (outStream)
+ RINOK(WriteStream(outStream, item.Buf, item.FinalSize()))
+ }
+ else if (mixItem.VersionIndex >= 0)
+ {
+ const CByteBuffer &item = _versionFiles[mixItem.VersionIndex];
+ currentItemSize = item.Size();
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode))
+ if (outStream)
+ RINOK(WriteStream(outStream, item, item.Size()))
+ }
+ else if (mixItem.ResourceIndex >= 0)
+ {
+ const CResItem &item = _items[mixItem.ResourceIndex];
+ currentItemSize = item.GetSize();
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode))
+ size_t offset = item.Offset - sect.Va;
+ if (!CheckItem(sect, item, offset))
+ isOk = false;
+ else if (outStream)
+ {
+ if (item.HeaderSize != 0)
+ RINOK(WriteStream(outStream, item.Header, item.HeaderSize))
+ RINOK(WriteStream(outStream, _buf + offset, item.Size))
+ }
+ }
+ else
+ {
+ currentItemSize = sect.GetSizeExtract();
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(InStream_SeekSet(_stream, sect.Pa))
+ streamSpec->Init(currentItemSize);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress))
+ isOk = (copyCoderSpec->TotalSize == currentItemSize);
+ }
+
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(isOk ?
+ NExtract::NOperationResult::kOK :
+ NExtract::NOperationResult::kDataError))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ *stream = NULL;
+
+ const CMixItem &mixItem = _mixItems[index];
+ const CSection &sect = _sections[mixItem.SectionIndex];
+ if (mixItem.IsSectionItem())
+ return CreateLimitedInStream(_stream, sect.Pa, sect.PSize, stream);
+
+ CBufInStream *inStreamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec;
+ CReferenceBuf *referenceBuf = new CReferenceBuf;
+ CMyComPtr<IUnknown> ref = referenceBuf;
+ if (mixItem.StringIndex >= 0)
+ {
+ const CStringItem &item = _strings[mixItem.StringIndex];
+ referenceBuf->Buf.CopyFrom(item.Buf, item.FinalSize());
+ }
+ else if (mixItem.VersionIndex >= 0)
+ {
+ const CByteBuffer &item = _versionFiles[mixItem.VersionIndex];
+ referenceBuf->Buf.CopyFrom(item, item.Size());
+ }
+ else
+ {
+ const CResItem &item = _items[mixItem.ResourceIndex];
+ size_t offset = item.Offset - sect.Va;
+ if (!CheckItem(sect, item, offset))
+ return S_FALSE;
+ if (item.HeaderSize == 0)
+ {
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<IInStream> streamTemp2 = streamSpec;
+ streamSpec->Init(_buf + offset, item.Size, (IInArchive *)this);
+ *stream = streamTemp2.Detach();
+ return S_OK;
+ }
+ referenceBuf->Buf.Alloc(item.HeaderSize + item.Size);
+ memcpy(referenceBuf->Buf, item.Header, item.HeaderSize);
+ if (item.Size != 0)
+ memcpy(referenceBuf->Buf + item.HeaderSize, _buf + offset, item.Size);
+ }
+ inStreamSpec->Init(referenceBuf);
+
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::AllowTail(Int32 allowTail))
+{
+ _allowTail = IntToBool(allowTail);
+ return S_OK;
+}
+
+static const Byte k_Signature[] = { 'M', 'Z' };
+
+REGISTER_ARC_I(
+ "PE", "exe dll sys", NULL, 0xDD,
+ k_Signature,
+ 0,
+ NArcInfoFlags::kPreArc,
+ IsArc_Pe)
+
+}
+
+namespace NCoff {
+
+API_FUNC_static_IsArc IsArc_Coff(const Byte *p, size_t size)
+{
+ if (size < NPe::kCoffHeaderSize)
+ return k_IsArc_Res_NEED_MORE;
+ NPe::CHeader header;
+ if (!header.ParseCoff(p))
+ return k_IsArc_Res_NO;
+ return k_IsArc_Res_YES;
+}
+}
+
+/*
+static const Byte k_Signature[] =
+{
+ 2, 0x4C, 0x01, // x86
+ 2, 0x64, 0x86, // x64
+ 2, 0x64, 0xAA // ARM64
+};
+REGISTER_ARC_I_CLS(
+*/
+
+REGISTER_ARC_I_CLS_NO_SIG(
+ NPe::CHandler(true),
+ "COFF", "obj", NULL, 0xC6,
+ // k_Signature,
+ 0,
+ // NArcInfoFlags::kMultiSignature |
+ NArcInfoFlags::kStartOpen,
+ IsArc_Coff)
+}
+
+
+namespace NTe {
+
+// Terse Executable (TE) image
+
+struct CDataDir
+{
+ UInt32 Va;
+ UInt32 Size;
+
+ void Parse(const Byte *p)
+ {
+ G32(0, Va);
+ G32(4, Size);
+ }
+};
+
+static const UInt32 kHeaderSize = 40;
+
+static bool FindValue(const CUInt32PCharPair *pairs, unsigned num, UInt32 value)
+{
+ for (unsigned i = 0; i < num; i++)
+ if (pairs[i].Value == value)
+ return true;
+ return false;
+}
+
+#define MY_FIND_VALUE(pairs, val) FindValue(pairs, Z7_ARRAY_SIZE(pairs), val)
+#define MY_FIND_VALUE_2(strings, val) (val < Z7_ARRAY_SIZE(strings) && strings[val])
+
+static const UInt32 kNumSection_MAX = 32;
+
+struct CHeader
+{
+ UInt16 Machine;
+ Byte NumSections;
+ Byte SubSystem;
+ UInt16 StrippedSize;
+ /*
+ UInt32 AddressOfEntryPoint;
+ UInt32 BaseOfCode;
+ UInt64 ImageBase;
+ */
+ CDataDir DataDir[2]; // base relocation and debug directory
+
+ bool ConvertPa(UInt32 &pa) const
+ {
+ if (pa < StrippedSize)
+ return false;
+ pa = pa - StrippedSize + kHeaderSize;
+ return true;
+ }
+ bool Parse(const Byte *p);
+};
+
+bool CHeader::Parse(const Byte *p)
+{
+ NumSections = p[4];
+ if (NumSections > kNumSection_MAX)
+ return false;
+ SubSystem = p[5];
+ G16(2, Machine);
+ G16(6, StrippedSize);
+ /*
+ G32(8, AddressOfEntryPoint);
+ G32(12, BaseOfCode);
+ G64(16, ImageBase);
+ */
+ for (int i = 0; i < 2; i++)
+ {
+ CDataDir &dd = DataDir[i];
+ dd.Parse(p + 24 + i * 8);
+ if (dd.Size >= ((UInt32)1 << 28))
+ return false;
+ }
+ return
+ MY_FIND_VALUE(NPe::g_MachinePairs, Machine) &&
+ MY_FIND_VALUE_2(NPe::g_SubSystems, SubSystem);
+}
+
+API_FUNC_static_IsArc IsArc_Te(const Byte *p, size_t size)
+{
+ if (size < 2)
+ return k_IsArc_Res_NEED_MORE;
+ if (p[0] != 'V' || p[1] != 'Z')
+ return k_IsArc_Res_NO;
+ if (size < kHeaderSize)
+ return k_IsArc_Res_NEED_MORE;
+
+ CHeader h;
+ if (!h.Parse(p))
+ return k_IsArc_Res_NO;
+ return k_IsArc_Res_YES;
+}
+}
+
+
+struct CSection
+{
+ Byte Name[NPe::kNameSize];
+
+ UInt32 VSize;
+ UInt32 Va;
+ UInt32 PSize;
+ UInt32 Pa;
+ UInt32 Flags;
+ // UInt16 NumRelocs;
+
+ void Parse(const Byte *p)
+ {
+ memcpy(Name, p, NPe::kNameSize);
+ G32(8, VSize);
+ G32(12, Va);
+ G32(16, PSize);
+ G32(20, Pa);
+ // G32(p + 32, NumRelocs);
+ G32(36, Flags);
+ }
+
+ bool Check() const
+ {
+ return
+ Pa <= ((UInt32)1 << 30) &&
+ PSize <= ((UInt32)1 << 30);
+ }
+
+ void UpdateTotalSize(UInt32 &totalSize)
+ {
+ UInt32 t = Pa + PSize;
+ if (t > totalSize)
+ totalSize = t;
+ }
+};
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_2(
+ IInArchiveGetStream,
+ IArchiveAllowTail
+)
+ CRecordVector<CSection> _items;
+ CMyComPtr<IInStream> _stream;
+ UInt32 _totalSize;
+ bool _allowTail;
+ CHeader _h;
+
+ HRESULT Open2(IInStream *stream);
+public:
+ CHandler(): _allowTail(false) {}
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidVirtualSize,
+ kpidCharacts,
+ kpidOffset,
+ kpidVa
+};
+
+enum
+{
+ kpidSubSystem = kpidUserDefined
+ // , kpidImageBase
+};
+
+static const CStatProp kArcProps[] =
+{
+ // { NULL, kpidHeadersSize, VT_UI4 },
+ { NULL, kpidCpu, VT_BSTR},
+ { "Subsystem", kpidSubSystem, VT_BSTR },
+ // { "Image Base", kpidImageBase, VT_UI8 }
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_WITH_NAME
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySize: prop = _totalSize; break;
+ case kpidCpu: PAIR_TO_PROP(NPe::g_MachinePairs, _h.Machine, prop); break;
+ case kpidSubSystem: TYPE_TO_PROP(NPe::g_SubSystems, _h.SubSystem, prop); break;
+ /*
+ case kpidImageBase: prop = _h.ImageBase; break;
+ case kpidAddressOfEntryPoint: prop = _h.AddressOfEntryPoint; break;
+ case kpidBaseOfCode: prop = _h.BaseOfCode; break;
+ */
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ {
+ const CSection &item = _items[index];
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ AString name;
+ NPe::GetName(item.Name, name);
+ prop = MultiByteToUnicodeString(name);
+ break;
+ }
+ case kpidSize:
+ case kpidPackSize: prop = (UInt64)item.PSize; break;
+ case kpidVirtualSize: prop = (UInt64)item.VSize; break;
+ case kpidOffset: prop = item.Pa; break;
+ case kpidVa: prop = item.Va; break;
+ case kpidCharacts: FLAGS_TO_PROP(NPe::g_SectFlags, item.Flags, prop); break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+ Byte h[kHeaderSize];
+ RINOK(ReadStream_FALSE(stream, h, kHeaderSize))
+ if (h[0] != 'V' || h[1] != 'Z')
+ return S_FALSE;
+ if (!_h.Parse(h))
+ return S_FALSE;
+
+ UInt32 headerSize = NPe::kSectionSize * (UInt32)_h.NumSections;
+ CByteArr buf(headerSize);
+ RINOK(ReadStream_FALSE(stream, buf, headerSize))
+ headerSize += kHeaderSize;
+
+ _totalSize = headerSize;
+ _items.ClearAndReserve(_h.NumSections);
+ for (UInt32 i = 0; i < _h.NumSections; i++)
+ {
+ CSection sect;
+ sect.Parse(buf + i * NPe::kSectionSize);
+ if (!_h.ConvertPa(sect.Pa))
+ return S_FALSE;
+ if (sect.Pa < headerSize)
+ return S_FALSE;
+ if (!sect.Check())
+ return S_FALSE;
+ _items.AddInReserved(sect);
+ sect.UpdateTotalSize(_totalSize);
+ }
+
+ if (!_allowTail)
+ {
+ UInt64 fileSize;
+ RINOK(InStream_GetSize_SeekToEnd(stream, fileSize))
+ if (fileSize > _totalSize)
+ return S_FALSE;
+ }
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */))
+{
+ COM_TRY_BEGIN
+ Close();
+ try
+ {
+ if (Open2(inStream) != S_OK)
+ return S_FALSE;
+ _stream = inStream;
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _totalSize = 0;
+ _stream.Release();
+ _items.Clear();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _items[allFilesMode ? i : indices[i]].PSize;
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur())
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CSection &item = _items[index];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+ currentTotalSize += item.PSize;
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode))
+ int res = NExtract::NOperationResult::kDataError;
+
+ RINOK(InStream_SeekSet(_stream, item.Pa))
+ streamSpec->Init(item.PSize);
+ RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress))
+ if (copyCoderSpec->TotalSize == item.PSize)
+ res = NExtract::NOperationResult::kOK;
+
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(res))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ const CSection &item = _items[index];
+ return CreateLimitedInStream(_stream, item.Pa, item.PSize, stream);
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::AllowTail(Int32 allowTail))
+{
+ _allowTail = IntToBool(allowTail);
+ return S_OK;
+}
+
+static const Byte k_Signature[] = { 'V', 'Z' };
+
+REGISTER_ARC_I(
+ "TE", "te", NULL, 0xCF,
+ k_Signature,
+ 0,
+ NArcInfoFlags::kPreArc,
+ IsArc_Te)
+
+}
+}
diff --git a/CPP/7zip/Archive/PpmdHandler.cpp b/CPP/7zip/Archive/PpmdHandler.cpp
new file mode 100644
index 0000000..e5c2f9b
--- /dev/null
+++ b/CPP/7zip/Archive/PpmdHandler.cpp
@@ -0,0 +1,398 @@
+/* PpmdHandler.cpp -- PPMd format handler
+2020 : Igor Pavlov : Public domain
+This code is based on:
+ PPMd var.H (2001) / var.I (2002): Dmitry Shkarin : Public domain
+ Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+#include "../../../C/Alloc.h"
+#include "../../../C/Ppmd7.h"
+#include "../../../C/Ppmd8.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/StringConvert.h"
+
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/TimeUtils.h"
+
+#include "../Common/CWrappers.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NPpmd {
+
+static const UInt32 kBufSize = (1 << 20);
+
+struct CBuf
+{
+ Byte *Buf;
+
+ CBuf(): Buf(NULL) {}
+ ~CBuf() { ::MidFree(Buf); }
+ bool Alloc()
+ {
+ if (!Buf)
+ Buf = (Byte *)::MidAlloc(kBufSize);
+ return (Buf != NULL);
+ }
+};
+
+static const UInt32 kHeaderSize = 16;
+static const UInt32 kSignature = 0x84ACAF8F;
+static const unsigned kNewHeaderVer = 8;
+
+struct CItem
+{
+ UInt32 Attrib;
+ UInt32 Time;
+ AString Name;
+
+ unsigned Order;
+ unsigned MemInMB;
+ unsigned Ver;
+ unsigned Restor;
+
+ HRESULT ReadHeader(ISequentialInStream *s, UInt32 &headerSize);
+ bool IsSupported() const
+ {
+ return (Ver == 7 && Order >= PPMD7_MIN_ORDER)
+ || (Ver == 8 && Order >= PPMD8_MIN_ORDER && Restor < PPMD8_RESTORE_METHOD_UNSUPPPORTED);
+ }
+};
+
+HRESULT CItem::ReadHeader(ISequentialInStream *s, UInt32 &headerSize)
+{
+ Byte h[kHeaderSize];
+ RINOK(ReadStream_FALSE(s, h, kHeaderSize))
+ if (GetUi32(h) != kSignature)
+ return S_FALSE;
+ Attrib = GetUi32(h + 4);
+ Time = GetUi32(h + 12);
+ unsigned info = GetUi16(h + 8);
+ Order = (info & 0xF) + 1;
+ MemInMB = ((info >> 4) & 0xFF) + 1;
+ Ver = info >> 12;
+
+ if (Ver < 6 || Ver > 11) return S_FALSE;
+
+ UInt32 nameLen = GetUi16(h + 10);
+ Restor = nameLen >> 14;
+ if (Restor > 2)
+ return S_FALSE;
+ if (Ver >= kNewHeaderVer)
+ nameLen &= 0x3FFF;
+ if (nameLen > (1 << 9))
+ return S_FALSE;
+ char *name = Name.GetBuf(nameLen);
+ HRESULT res = ReadStream_FALSE(s, name, nameLen);
+ Name.ReleaseBuf_CalcLen(nameLen);
+ headerSize = kHeaderSize + nameLen;
+ return res;
+}
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IArchiveOpenSeq
+)
+ CItem _item;
+ UInt32 _headerSize;
+ bool _packSize_Defined;
+ UInt64 _packSize;
+ CMyComPtr<ISequentialInStream> _stream;
+
+ void GetVersion(NCOM::CPropVariant &prop);
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidMTime,
+ kpidAttrib,
+ kpidMethod
+};
+
+static const Byte kArcProps[] =
+{
+ kpidMethod
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+void CHandler::GetVersion(NCOM::CPropVariant &prop)
+{
+ AString s ("PPMd");
+ s += (char)('A' + _item.Ver);
+ s += ":o";
+ s.Add_UInt32(_item.Order);
+ s += ":mem";
+ s.Add_UInt32(_item.MemInMB);
+ s += 'm';
+ if (_item.Ver >= kNewHeaderVer && _item.Restor != 0)
+ {
+ s += ":r";
+ s.Add_UInt32(_item.Restor);
+ }
+ prop = s;
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySize: if (_packSize_Defined) prop = _packSize; break;
+ case kpidMethod: GetVersion(prop); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPath: prop = MultiByteToUnicodeString(_item.Name, CP_ACP); break;
+ case kpidMTime:
+ {
+ // time can be in Unix format ???
+ FILETIME utc;
+ if (NTime::DosTime_To_FileTime(_item.Time, utc))
+ prop = utc;
+ break;
+ }
+ case kpidAttrib: prop = _item.Attrib; break;
+ case kpidPackSize: if (_packSize_Defined) prop = _packSize; break;
+ case kpidMethod: GetVersion(prop); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *))
+{
+ return OpenSeq(stream);
+}
+
+Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream))
+{
+ COM_TRY_BEGIN
+ HRESULT res;
+ try
+ {
+ Close();
+ res = _item.ReadHeader(stream, _headerSize);
+ }
+ catch(...) { res = S_FALSE; }
+ if (res == S_OK)
+ _stream = stream;
+ else
+ Close();
+ return res;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _packSize = 0;
+ _packSize_Defined = false;
+ _stream.Release();
+ return S_OK;
+}
+
+
+
+struct CPpmdCpp
+{
+ unsigned Ver;
+ CPpmd7 _ppmd7;
+ CPpmd8 _ppmd8;
+
+ CPpmdCpp(unsigned version)
+ {
+ Ver = version;
+ Ppmd7_Construct(&_ppmd7);
+ Ppmd8_Construct(&_ppmd8);
+ }
+
+ ~CPpmdCpp()
+ {
+ Ppmd7_Free(&_ppmd7, &g_BigAlloc);
+ Ppmd8_Free(&_ppmd8, &g_BigAlloc);
+ }
+
+ bool Alloc(UInt32 memInMB)
+ {
+ memInMB <<= 20;
+ if (Ver == 7)
+ return Ppmd7_Alloc(&_ppmd7, memInMB, &g_BigAlloc) != 0;
+ return Ppmd8_Alloc(&_ppmd8, memInMB, &g_BigAlloc) != 0;
+ }
+
+ void Init(unsigned order, unsigned restor)
+ {
+ if (Ver == 7)
+ Ppmd7_Init(&_ppmd7, order);
+ else
+ Ppmd8_Init(&_ppmd8, order, restor);
+ }
+
+ bool InitRc(CByteInBufWrap *inStream)
+ {
+ if (Ver == 7)
+ {
+ _ppmd7.rc.dec.Stream = &inStream->vt;
+ return (Ppmd7a_RangeDec_Init(&_ppmd7.rc.dec) != 0);
+ }
+ else
+ {
+ _ppmd8.Stream.In = &inStream->vt;
+ return Ppmd8_Init_RangeDec(&_ppmd8) != 0;
+ }
+ }
+
+ bool IsFinishedOK()
+ {
+ if (Ver == 7)
+ return Ppmd7z_RangeDec_IsFinishedOK(&_ppmd7.rc.dec);
+ return Ppmd8_RangeDec_IsFinishedOK(&_ppmd8);
+ }
+};
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ // extractCallback->SetTotal(_packSize);
+ UInt64 currentTotalPacked = 0;
+ RINOK(extractCallback->SetCompleted(&currentTotalPacked))
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode))
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ CByteInBufWrap inBuf;
+ if (!inBuf.Alloc(1 << 20))
+ return E_OUTOFMEMORY;
+ inBuf.Stream = _stream;
+
+ CBuf outBuf;
+ if (!outBuf.Alloc())
+ return E_OUTOFMEMORY;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, true);
+
+ CPpmdCpp ppmd(_item.Ver);
+ if (!ppmd.Alloc(_item.MemInMB))
+ return E_OUTOFMEMORY;
+
+ Int32 opRes = NExtract::NOperationResult::kUnsupportedMethod;
+
+ if (_item.IsSupported())
+ {
+ opRes = NExtract::NOperationResult::kDataError;
+
+ ppmd.Init(_item.Order, _item.Restor);
+ inBuf.Init();
+ UInt64 outSize = 0;
+
+ if (ppmd.InitRc(&inBuf) && !inBuf.Extra && inBuf.Res == S_OK)
+ for (;;)
+ {
+ lps->InSize = _packSize = inBuf.GetProcessed();
+ lps->OutSize = outSize;
+ RINOK(lps->SetCur())
+
+ size_t i;
+ int sym = 0;
+
+ Byte *buf = outBuf.Buf;
+ if (ppmd.Ver == 7)
+ {
+ for (i = 0; i < kBufSize; i++)
+ {
+ sym = Ppmd7a_DecodeSymbol(&ppmd._ppmd7);
+ if (inBuf.Extra || sym < 0)
+ break;
+ buf[i] = (Byte)sym;
+ }
+ }
+ else
+ {
+ for (i = 0; i < kBufSize; i++)
+ {
+ sym = Ppmd8_DecodeSymbol(&ppmd._ppmd8);
+ if (inBuf.Extra || sym < 0)
+ break;
+ buf[i] = (Byte)sym;
+ }
+ }
+
+ outSize += i;
+ _packSize = _headerSize + inBuf.GetProcessed();
+ _packSize_Defined = true;
+ if (realOutStream)
+ {
+ RINOK(WriteStream(realOutStream, outBuf.Buf, i))
+ }
+
+ if (inBuf.Extra)
+ {
+ opRes = NExtract::NOperationResult::kUnexpectedEnd;
+ break;
+ }
+
+ if (sym < 0)
+ {
+ if (sym == -1 && ppmd.IsFinishedOK())
+ opRes = NExtract::NOperationResult::kOK;
+ break;
+ }
+ }
+
+ RINOK(inBuf.Res)
+ }
+
+ realOutStream.Release();
+ return extractCallback->SetOperationResult(opRes);
+}
+
+
+static const Byte k_Signature[] = { 0x8F, 0xAF, 0xAC, 0x84 };
+
+REGISTER_ARC_I(
+ "Ppmd", "pmd", NULL, 0xD,
+ k_Signature,
+ 0,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/QcowHandler.cpp b/CPP/7zip/Archive/QcowHandler.cpp
new file mode 100644
index 0000000..5a80daa
--- /dev/null
+++ b/CPP/7zip/Archive/QcowHandler.cpp
@@ -0,0 +1,668 @@
+// QcowHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer2.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/DeflateDecoder.h"
+
+#include "HandlerCont.h"
+
+#define Get32(p) GetBe32(p)
+#define Get64(p) GetBe64(p)
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NQcow {
+
+static const Byte k_Signature[] = { 'Q', 'F', 'I', 0xFB, 0, 0, 0 };
+
+/*
+VA to PA maps:
+ high bits (L1) : : in L1 Table : the reference to L1 Table
+ mid bits (L2) : _numMidBits : in L2 Table : the reference to cluster
+ low bits : _clusterBits
+*/
+
+Z7_class_CHandler_final: public CHandlerImg
+{
+ Z7_IFACE_COM7_IMP(IInArchive_Img)
+ Z7_IFACE_COM7_IMP(IInArchiveGetStream)
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+
+ unsigned _clusterBits;
+ unsigned _numMidBits;
+ UInt64 _compressedFlag;
+
+ CObjArray2<UInt32> _dir;
+ CAlignedBuffer _table;
+ UInt64 _cacheCluster;
+ CByteBuffer _cache;
+ CByteBuffer _cacheCompressed;
+
+ UInt64 _comprPos;
+ size_t _comprSize;
+
+ UInt64 _phySize;
+
+ CBufInStream *_bufInStreamSpec;
+ CMyComPtr<ISequentialInStream> _bufInStream;
+
+ CBufPtrSeqOutStream *_bufOutStreamSpec;
+ CMyComPtr<ISequentialOutStream> _bufOutStream;
+
+ NCompress::NDeflate::NDecoder::CCOMCoder *_deflateDecoderSpec;
+ CMyComPtr<ICompressCoder> _deflateDecoder;
+
+ bool _needDeflate;
+ bool _isArc;
+ bool _unsupported;
+
+ UInt32 _version;
+ UInt32 _cryptMethod;
+
+ HRESULT Seek2(UInt64 offset)
+ {
+ _posInArc = offset;
+ return InStream_SeekSet(Stream, offset);
+ }
+
+ HRESULT InitAndSeek()
+ {
+ _virtPos = 0;
+ return Seek2(0);
+ }
+
+ HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) Z7_override;
+};
+
+
+static const UInt32 kEmptyDirItem = (UInt32)0 - 1;
+
+Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+
+ // printf("\nRead _virtPos = %6d size = %6d\n", (UInt32)_virtPos, size);
+
+ if (_virtPos >= _size)
+ return S_OK;
+ {
+ UInt64 rem = _size - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ if (size == 0)
+ return S_OK;
+ }
+
+ for (;;)
+ {
+ const UInt64 cluster = _virtPos >> _clusterBits;
+ const size_t clusterSize = (size_t)1 << _clusterBits;
+ const size_t lowBits = (size_t)_virtPos & (clusterSize - 1);
+ {
+ size_t rem = clusterSize - lowBits;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ if (cluster == _cacheCluster)
+ {
+ memcpy(data, _cache + lowBits, size);
+ break;
+ }
+
+ const UInt64 high = cluster >> _numMidBits;
+
+ if (high < _dir.Size())
+ {
+ const UInt32 tabl = _dir[(unsigned)high];
+
+ if (tabl != kEmptyDirItem)
+ {
+ const Byte *buffer = _table + ((size_t)tabl << (_numMidBits + 3));
+ const size_t midBits = (size_t)cluster & (((size_t)1 << _numMidBits) - 1);
+ const Byte *p = (const Byte *)buffer + (midBits << 3);
+ UInt64 v = Get64(p);
+
+ if (v != 0)
+ {
+ if ((v & _compressedFlag) != 0)
+ {
+ if (_version <= 1)
+ return E_FAIL;
+
+ /*
+ the example of table record for 12-bit clusters (4KB uncompressed).
+ 2 bits : isCompressed status
+ 4 bits : num_sectors_minus1; packSize = (num_sectors_minus1 + 1) * 512;
+ it uses one additional bit over unpacked cluster_bits
+ 49 bits : offset of 512-sector
+ 9 bits : offset in 512-sector
+ */
+
+ const unsigned numOffsetBits = (62 - (_clusterBits - 9 + 1));
+ const UInt64 offset = v & (((UInt64)1 << 62) - 1);
+ const size_t dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9;
+ UInt64 sectorOffset = offset & (((UInt64)1 << numOffsetBits) - (1 << 9));
+ const UInt64 offset2inCache = sectorOffset - _comprPos;
+
+ // _comprPos is aligned for 512-bytes
+ // we try to use previous _cacheCompressed that contains compressed data
+ // that was read for previous unpacking
+
+ if (sectorOffset >= _comprPos && offset2inCache < _comprSize)
+ {
+ if (offset2inCache != 0)
+ {
+ _comprSize -= (size_t)offset2inCache;
+ memmove(_cacheCompressed, _cacheCompressed + (size_t)offset2inCache, _comprSize);
+ _comprPos = sectorOffset;
+ }
+ sectorOffset += _comprSize;
+ }
+ else
+ {
+ _comprPos = sectorOffset;
+ _comprSize = 0;
+ }
+
+ if (dataSize > _comprSize)
+ {
+ if (sectorOffset != _posInArc)
+ {
+ // printf("\nDeflate-Seek %12I64x %12I64x\n", sectorOffset, sectorOffset - _posInArc);
+ RINOK(Seek2(sectorOffset))
+ }
+ if (_cacheCompressed.Size() < dataSize)
+ return E_FAIL;
+ const size_t dataSize3 = dataSize - _comprSize;
+ size_t dataSize2 = dataSize3;
+ // printf("\n\n=======\nReadStream = %6d _comprPos = %6d \n", (UInt32)dataSize2, (UInt32)_comprPos);
+ RINOK(ReadStream(Stream, _cacheCompressed + _comprSize, &dataSize2))
+ _posInArc += dataSize2;
+ if (dataSize2 != dataSize3)
+ return E_FAIL;
+ _comprSize += dataSize2;
+ }
+
+ const size_t kSectorMask = (1 << 9) - 1;
+ const size_t offsetInSector = ((size_t)offset & kSectorMask);
+ _bufInStreamSpec->Init(_cacheCompressed + offsetInSector, dataSize - offsetInSector);
+
+ _cacheCluster = (UInt64)(Int64)-1;
+ if (_cache.Size() < clusterSize)
+ return E_FAIL;
+ _bufOutStreamSpec->Init(_cache, clusterSize);
+
+ // Do we need to use smaller block than clusterSize for last cluster?
+ const UInt64 blockSize64 = clusterSize;
+ HRESULT res = _deflateDecoder->Code(_bufInStream, _bufOutStream, NULL, &blockSize64, NULL);
+
+ /*
+ if (_bufOutStreamSpec->GetPos() != clusterSize)
+ memset(_cache + _bufOutStreamSpec->GetPos(), 0, clusterSize - _bufOutStreamSpec->GetPos());
+ */
+
+ if (res == S_OK)
+ if (!_deflateDecoderSpec->IsFinished()
+ || _bufOutStreamSpec->GetPos() != clusterSize)
+ res = S_FALSE;
+
+ RINOK(res)
+ _cacheCluster = cluster;
+
+ continue;
+ /*
+ memcpy(data, _cache + lowBits, size);
+ break;
+ */
+ }
+
+ // version 3 support zero clusters
+ if (((UInt32)v & 511) != 1)
+ {
+ v &= (_compressedFlag - 1);
+ v += lowBits;
+ if (v != _posInArc)
+ {
+ // printf("\n%12I64x\n", v - _posInArc);
+ RINOK(Seek2(v))
+ }
+ HRESULT res = Stream->Read(data, size, &size);
+ _posInArc += size;
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return res;
+ }
+ }
+ }
+ }
+
+ memset(data, 0, size);
+ break;
+ }
+
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+}
+
+
+static const Byte kProps[] =
+{
+ kpidSize,
+ kpidPackSize
+};
+
+static const Byte kArcProps[] =
+{
+ kpidClusterSize,
+ kpidUnpackVer,
+ kpidMethod
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ switch (propID)
+ {
+ case kpidMainSubfile: prop = (UInt32)0; break;
+ case kpidClusterSize: prop = (UInt32)1 << _clusterBits; break;
+ case kpidPhySize: if (_phySize != 0) prop = _phySize; break;
+ case kpidUnpackVer: prop = _version; break;
+
+ case kpidMethod:
+ {
+ AString s;
+
+ if (_needDeflate)
+ s = "Deflate";
+
+ if (_cryptMethod != 0)
+ {
+ s.Add_Space_if_NotEmpty();
+ if (_cryptMethod == 1)
+ s += "AES";
+ else
+ s.Add_UInt32(_cryptMethod);
+ }
+
+ if (!s.IsEmpty())
+ prop = s;
+
+ break;
+ }
+
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod;
+ // if (_headerError) v |= kpv_ErrorFlags_HeadersError;
+ if (!Stream && v == 0 && _isArc)
+ v = kpv_ErrorFlags_HeadersError;
+ if (v != 0)
+ prop = v;
+ break;
+ }
+ }
+
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ switch (propID)
+ {
+ case kpidSize: prop = _size; break;
+ case kpidPackSize: prop = _phySize; break;
+ case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break;
+ }
+
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
+{
+ const unsigned kHeaderSize = 18 * 4;
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(stream, buf, kHeaderSize))
+
+ if (memcmp(buf, k_Signature, 4) != 0)
+ return S_FALSE;
+
+ _version = Get32(buf + 4);
+ if (_version < 1 || _version > 3)
+ return S_FALSE;
+
+ const UInt64 backOffset = Get64(buf + 8);
+ // UInt32 backSize = Get32(buf + 0x10);
+
+ UInt64 l1Offset;
+ UInt32 l1Size;
+
+ if (_version == 1)
+ {
+ // _mTime = Get32(buf + 0x14); // is unused im most images
+ _size = Get64(buf + 0x18);
+ _clusterBits = buf[0x20];
+ _numMidBits = buf[0x21];
+ if (_clusterBits < 9 || _clusterBits > 30)
+ return S_FALSE;
+ if (_numMidBits < 1 || _numMidBits > 28)
+ return S_FALSE;
+ _cryptMethod = Get32(buf + 0x24);
+ l1Offset = Get64(buf + 0x28);
+ if (l1Offset < 0x30)
+ return S_FALSE;
+ const unsigned numBits2 = (_clusterBits + _numMidBits);
+ const UInt64 l1Size64 = (_size + (((UInt64)1 << numBits2) - 1)) >> numBits2;
+ if (l1Size64 > ((UInt32)1 << 31))
+ return S_FALSE;
+ l1Size = (UInt32)l1Size64;
+ }
+ else
+ {
+ _clusterBits = Get32(buf + 0x14);
+ if (_clusterBits < 9 || _clusterBits > 30)
+ return S_FALSE;
+ _numMidBits = _clusterBits - 3;
+ _size = Get64(buf + 0x18);
+ _cryptMethod = Get32(buf + 0x20);
+ l1Size = Get32(buf + 0x24);
+ l1Offset = Get64(buf + 0x28); // must be aligned for cluster
+
+ const UInt64 refOffset = Get64(buf + 0x30); // must be aligned for cluster
+ const UInt32 refClusters = Get32(buf + 0x38);
+
+ // UInt32 numSnapshots = Get32(buf + 0x3C);
+ // UInt64 snapshotsOffset = Get64(buf + 0x40); // must be aligned for cluster
+ /*
+ if (numSnapshots != 0)
+ return S_FALSE;
+ */
+
+ if (refClusters != 0)
+ {
+ const size_t numBytes = refClusters << _clusterBits;
+ /*
+ CByteBuffer refs;
+ refs.Alloc(numBytes);
+ RINOK(InStream_SeekSet(stream, refOffset))
+ RINOK(ReadStream_FALSE(stream, refs, numBytes));
+ */
+ const UInt64 end = refOffset + numBytes;
+ if (_phySize < end)
+ _phySize = end;
+ /*
+ for (size_t i = 0; i < numBytes; i += 2)
+ {
+ UInt32 v = GetBe16((const Byte *)refs + (size_t)i);
+ if (v == 0)
+ continue;
+ }
+ */
+ }
+ }
+
+ _isArc = true;
+
+ if (backOffset != 0)
+ {
+ _unsupported = true;
+ return S_FALSE;
+ }
+
+ const size_t clusterSize = (size_t)1 << _clusterBits;
+
+ CByteBuffer table;
+ {
+ const size_t t1SizeBytes = (size_t)l1Size << 3;
+ if ((t1SizeBytes >> 3) != l1Size)
+ return S_FALSE;
+ table.Alloc(t1SizeBytes);
+ RINOK(InStream_SeekSet(stream, l1Offset))
+ RINOK(ReadStream_FALSE(stream, table, t1SizeBytes))
+
+ {
+ UInt64 end = l1Offset + t1SizeBytes;
+ // we need to uses align end for empty qcow files
+ end = (end + clusterSize - 1) >> _clusterBits << _clusterBits;
+ if (_phySize < end)
+ _phySize = end;
+ }
+ }
+
+ _compressedFlag = (_version <= 1) ? ((UInt64)1 << 63) : ((UInt64)1 << 62);
+ const UInt64 offsetMask = _compressedFlag - 1;
+
+ UInt32 numTables = 0;
+ UInt32 i;
+
+ for (i = 0; i < l1Size; i++)
+ {
+ const UInt64 v = Get64((const Byte *)table + (size_t)i * 8) & offsetMask;
+ if (v != 0)
+ numTables++;
+ }
+
+ if (numTables != 0)
+ {
+ const size_t size = (size_t)numTables << (_numMidBits + 3);
+ if (size >> (_numMidBits + 3) != numTables)
+ return E_OUTOFMEMORY;
+ _table.Alloc(size);
+ if (!_table.IsAllocated())
+ return E_OUTOFMEMORY;
+ }
+
+ _dir.SetSize(l1Size);
+
+ UInt32 curTable = 0;
+
+ if (openCallback)
+ {
+ const UInt64 totalBytes = (UInt64)numTables << (_numMidBits + 3);
+ RINOK(openCallback->SetTotal(NULL, &totalBytes))
+ }
+
+ for (i = 0; i < l1Size; i++)
+ {
+ Byte *buf2;
+ const size_t midSize = (size_t)1 << (_numMidBits + 3);
+
+ {
+ const UInt64 v = Get64((const Byte *)table + (size_t)i * 8) & offsetMask;
+ if (v == 0)
+ {
+ _dir[i] = kEmptyDirItem;
+ continue;
+ }
+
+ _dir[i] = curTable;
+ const size_t tableOffset = ((size_t)curTable << (_numMidBits + 3));
+ buf2 = (Byte *)_table + tableOffset;
+ curTable++;
+
+ if (openCallback && (tableOffset & 0xFFFFF) == 0)
+ {
+ const UInt64 numBytes = tableOffset;
+ RINOK(openCallback->SetCompleted(NULL, &numBytes))
+ }
+
+ RINOK(InStream_SeekSet(stream, v))
+ RINOK(ReadStream_FALSE(stream, buf2, midSize))
+
+ const UInt64 end = v + midSize;
+ if (_phySize < end)
+ _phySize = end;
+ }
+
+ for (size_t k = 0; k < midSize; k += 8)
+ {
+ const UInt64 v = Get64((const Byte *)buf2 + (size_t)k);
+ if (v == 0)
+ continue;
+ UInt64 offset = v & offsetMask;
+ size_t dataSize = clusterSize;
+
+ if ((v & _compressedFlag) != 0)
+ {
+ if (_version <= 1)
+ {
+ unsigned numOffsetBits = (63 - _clusterBits);
+ dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9;
+ offset &= ((UInt64)1 << numOffsetBits) - 1;
+ dataSize = 0;
+ // offset >>= 9;
+ // offset <<= 9;
+ }
+ else
+ {
+ unsigned numOffsetBits = (62 - (_clusterBits - 8));
+ dataSize = ((size_t)(offset >> numOffsetBits) + 1) << 9;
+ offset &= ((UInt64)1 << numOffsetBits) - 1;
+ offset >>= 9;
+ offset <<= 9;
+ }
+ _needDeflate = true;
+ }
+ else
+ {
+ UInt32 low = (UInt32)v & 511;
+ if (low != 0)
+ {
+ // version 3 support zero clusters
+ if (_version < 3 || low != 1)
+ {
+ _unsupported = true;
+ return S_FALSE;
+ }
+ }
+ }
+
+ const UInt64 end = offset + dataSize;
+ if (_phySize < end)
+ _phySize = end;
+ }
+ }
+
+ if (curTable != numTables)
+ return E_FAIL;
+
+ if (_cryptMethod != 0)
+ _unsupported = true;
+
+ if (_needDeflate && _version <= 1) // that case was not implemented
+ _unsupported = true;
+
+ Stream = stream;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _table.Free();
+ _dir.Free();
+ _phySize = 0;
+
+ _cacheCluster = (UInt64)(Int64)-1;
+ _comprPos = 0;
+ _comprSize = 0;
+ _needDeflate = false;
+
+ _isArc = false;
+ _unsupported = false;
+
+ // CHandlerImg:
+ Clear_HandlerImg_Vars();
+ Stream.Release();
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ *stream = NULL;
+
+ if (_unsupported)
+ return S_FALSE;
+
+ if (_needDeflate)
+ {
+ if (_version <= 1)
+ return S_FALSE;
+
+ if (!_bufInStream)
+ {
+ _bufInStreamSpec = new CBufInStream;
+ _bufInStream = _bufInStreamSpec;
+ }
+
+ if (!_bufOutStream)
+ {
+ _bufOutStreamSpec = new CBufPtrSeqOutStream();
+ _bufOutStream = _bufOutStreamSpec;
+ }
+
+ if (!_deflateDecoder)
+ {
+ _deflateDecoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder();
+ _deflateDecoder = _deflateDecoderSpec;
+ _deflateDecoderSpec->Set_NeedFinishInput(true);
+ }
+
+ const size_t clusterSize = (size_t)1 << _clusterBits;
+ _cache.AllocAtLeast(clusterSize);
+ _cacheCompressed.AllocAtLeast(clusterSize * 2);
+ }
+
+ CMyComPtr<ISequentialInStream> streamTemp = this;
+ RINOK(InitAndSeek())
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+
+REGISTER_ARC_I(
+ "QCOW", "qcow qcow2 qcow2c", NULL, 0xCA,
+ k_Signature,
+ 0,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.cpp b/CPP/7zip/Archive/Rar/Rar5Handler.cpp
new file mode 100644
index 0000000..87d11e7
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/Rar5Handler.cpp
@@ -0,0 +1,3001 @@
+// Rar5Handler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/7zCrc.h"
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/MyBuffer2.h"
+#include "../../../Common/UTFConvert.h"
+
+#include "../../../Windows/PropVariantUtils.h"
+#include "../../../Windows/TimeUtils.h"
+
+#include "../../IPassword.h"
+
+#include "../../Common/FilterCoder.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/RegisterArc.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Common/RegisterCodec.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../../Crypto/Rar5Aes.h"
+
+#include "../Common/FindSignature.h"
+#include "../Common/ItemNameUtils.h"
+
+#include "../HandlerCont.h"
+
+#include "RarVol.h"
+#include "Rar5Handler.h"
+
+using namespace NWindows;
+
+#define Get32(p) GetUi32(p)
+
+namespace NArchive {
+namespace NRar5 {
+
+static const unsigned kMarkerSize = 8;
+
+static const Byte kMarker[kMarkerSize] =
+ { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x01, 0 };
+
+static const size_t kCommentSize_Max = (size_t)1 << 16;
+
+
+static const char * const kHostOS[] =
+{
+ "Windows"
+ , "Unix"
+};
+
+
+static const char * const k_ArcFlags[] =
+{
+ "Volume"
+ , "VolumeField"
+ , "Solid"
+ , "Recovery"
+ , "Lock" // 4
+};
+
+
+static const char * const k_FileFlags[] =
+{
+ "Dir"
+ , "UnixTime"
+ , "CRC"
+ , "UnknownSize"
+};
+
+
+static const char * const g_ExtraTypes[] =
+{
+ "0"
+ , "Crypto"
+ , "Hash"
+ , "Time"
+ , "Version"
+ , "Link"
+ , "UnixOwner"
+ , "Subdata"
+};
+
+
+static const char * const g_LinkTypes[] =
+{
+ "0"
+ , "UnixSymLink"
+ , "WinSymLink"
+ , "WinJunction"
+ , "HardLink"
+ , "FileCopy"
+};
+
+
+static const char g_ExtraTimeFlags[] = { 'u', 'M', 'C', 'A', 'n' };
+
+
+static unsigned ReadVarInt(const Byte *p, size_t maxSize, UInt64 *val)
+{
+ *val = 0;
+
+ for (unsigned i = 0; i < maxSize && i < 10;)
+ {
+ Byte b = p[i];
+ *val |= (UInt64)(b & 0x7F) << (7 * i);
+ i++;
+ if ((b & 0x80) == 0)
+ return i;
+ }
+ return 0;
+}
+
+
+bool CLinkInfo::Parse(const Byte *p, unsigned size)
+{
+ const Byte *pStart = p;
+ unsigned num;
+ UInt64 len;
+ num = ReadVarInt(p, size, &Type); if (num == 0) { return false; } p += num; size -= num;
+ num = ReadVarInt(p, size, &Flags); if (num == 0) { return false; } p += num; size -= num;
+ num = ReadVarInt(p, size, &len); if (num == 0) { return false; } p += num; size -= num;
+ if (size != len)
+ return false;
+ NameLen = (unsigned)len;
+ NameOffset = (unsigned)(p - pStart);
+ return true;
+}
+
+
+static void AddHex64(AString &s, UInt64 v)
+{
+ char sz[32];
+ sz[0] = '0';
+ sz[1] = 'x';
+ ConvertUInt64ToHex(v, sz + 2);
+ s += sz;
+}
+
+
+static void PrintType(AString &s, const char * const table[], unsigned num, UInt64 val)
+{
+ char sz[32];
+ const char *p = NULL;
+ if (val < num)
+ p = table[(unsigned)val];
+ if (!p)
+ {
+ ConvertUInt64ToString(val, sz);
+ p = sz;
+ }
+ s += p;
+}
+
+
+int CItem::FindExtra(unsigned extraID, unsigned &recordDataSize) const
+{
+ recordDataSize = 0;
+ size_t offset = 0;
+
+ for (;;)
+ {
+ size_t rem = Extra.Size() - offset;
+ if (rem == 0)
+ return -1;
+
+ {
+ UInt64 size;
+ unsigned num = ReadVarInt(Extra + offset, rem, &size);
+ if (num == 0)
+ return -1;
+ offset += num;
+ rem -= num;
+ if (size > rem)
+ return -1;
+ rem = (size_t)size;
+ }
+ {
+ UInt64 id;
+ unsigned num = ReadVarInt(Extra + offset, rem, &id);
+ if (num == 0)
+ return -1;
+ offset += num;
+ rem -= num;
+
+ // There was BUG in RAR 5.21- : it stored (size-1) instead of (size)
+ // for Subdata record in Service header.
+ // That record always was last in bad archives, so we can fix that case.
+ if (id == NExtraID::kSubdata
+ && RecordType == NHeaderType::kService
+ && rem + 1 == Extra.Size() - offset)
+ rem++;
+
+ if (id == extraID)
+ {
+ recordDataSize = (unsigned)rem;
+ return (int)offset;
+ }
+
+ offset += rem;
+ }
+ }
+}
+
+
+void CItem::PrintInfo(AString &s) const
+{
+ size_t offset = 0;
+
+ for (;;)
+ {
+ size_t rem = Extra.Size() - offset;
+ if (rem == 0)
+ return;
+
+ {
+ UInt64 size;
+ unsigned num = ReadVarInt(Extra + offset, rem, &size);
+ if (num == 0)
+ return;
+ offset += num;
+ rem -= num;
+ if (size > rem)
+ break;
+ rem = (size_t)size;
+ }
+ {
+ UInt64 id;
+ {
+ unsigned num = ReadVarInt(Extra + offset, rem, &id);
+ if (num == 0)
+ break;
+ offset += num;
+ rem -= num;
+ }
+
+ // There was BUG in RAR 5.21- : it stored (size-1) instead of (size)
+ // for Subdata record in Service header.
+ // That record always was last in bad archives, so we can fix that case.
+ if (id == NExtraID::kSubdata
+ && RecordType == NHeaderType::kService
+ && rem + 1 == Extra.Size() - offset)
+ rem++;
+
+ s.Add_Space_if_NotEmpty();
+ PrintType(s, g_ExtraTypes, Z7_ARRAY_SIZE(g_ExtraTypes), id);
+
+ if (id == NExtraID::kTime)
+ {
+ const Byte *p = Extra + offset;
+ UInt64 flags;
+ unsigned num = ReadVarInt(p, rem, &flags);
+ if (num != 0)
+ {
+ s += ':';
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ExtraTimeFlags); i++)
+ if ((flags & ((UInt64)1 << i)) != 0)
+ s += g_ExtraTimeFlags[i];
+ flags &= ~(((UInt64)1 << Z7_ARRAY_SIZE(g_ExtraTimeFlags)) - 1);
+ if (flags != 0)
+ {
+ s += '_';
+ AddHex64(s, flags);
+ }
+ }
+ }
+ else if (id == NExtraID::kLink)
+ {
+ CLinkInfo linkInfo;
+ if (linkInfo.Parse(Extra + offset, (unsigned)rem))
+ {
+ s += ':';
+ PrintType(s, g_LinkTypes, Z7_ARRAY_SIZE(g_LinkTypes), linkInfo.Type);
+ UInt64 flags = linkInfo.Flags;
+ if (flags != 0)
+ {
+ s += ':';
+ if (flags & NLinkFlags::kTargetIsDir)
+ {
+ s += 'D';
+ flags &= ~((UInt64)NLinkFlags::kTargetIsDir);
+ }
+ if (flags != 0)
+ {
+ s += '_';
+ AddHex64(s, flags);
+ }
+ }
+ }
+ }
+
+ offset += rem;
+ }
+ }
+
+ s.Add_OptSpaced("ERROR");
+}
+
+
+bool CCryptoInfo::Parse(const Byte *p, size_t size)
+{
+ Algo = 0;
+ Flags = 0;
+ Cnt = 0;
+
+ unsigned num = ReadVarInt(p, size, &Algo);
+ if (num == 0) { return false; } p += num; size -= num;
+
+ num = ReadVarInt(p, size, &Flags);
+ if (num == 0) { return false; } p += num; size -= num;
+
+ if (size > 0)
+ Cnt = p[0];
+
+ if (size != 1 + 16 + 16 + (unsigned)(IsThereCheck() ? 12 : 0))
+ return false;
+
+ return true;
+}
+
+
+bool CItem::FindExtra_Version(UInt64 &version) const
+{
+ unsigned size;
+ int offset = FindExtra(NExtraID::kVersion, size);
+ if (offset < 0)
+ return false;
+ const Byte *p = Extra + (unsigned)offset;
+
+ UInt64 flags;
+ unsigned num = ReadVarInt(p, size, &flags);
+ if (num == 0) { return false; } p += num; size -= num;
+
+ num = ReadVarInt(p, size, &version);
+ if (num == 0) { return false; } p += num; size -= num;
+
+ return size == 0;
+}
+
+bool CItem::FindExtra_Link(CLinkInfo &link) const
+{
+ unsigned size;
+ const int offset = FindExtra(NExtraID::kLink, size);
+ if (offset < 0)
+ return false;
+ if (!link.Parse(Extra + (unsigned)offset, size))
+ return false;
+ link.NameOffset += (unsigned)offset;
+ return true;
+}
+
+bool CItem::Is_CopyLink() const
+{
+ CLinkInfo link;
+ return FindExtra_Link(link) && link.Type == NLinkType::kFileCopy;
+}
+
+bool CItem::Is_HardLink() const
+{
+ CLinkInfo link;
+ return FindExtra_Link(link) && link.Type == NLinkType::kHardLink;
+}
+
+bool CItem::Is_CopyLink_or_HardLink() const
+{
+ CLinkInfo link;
+ return FindExtra_Link(link) && (link.Type == NLinkType::kFileCopy || link.Type == NLinkType::kHardLink);
+}
+
+void CItem::Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) const
+{
+ CLinkInfo link;
+ if (!FindExtra_Link(link))
+ return;
+
+ if (link.Type != linkType)
+ {
+ if (linkType != NLinkType::kUnixSymLink)
+ return;
+ switch ((unsigned)link.Type)
+ {
+ case NLinkType::kUnixSymLink:
+ case NLinkType::kWinSymLink:
+ case NLinkType::kWinJunction:
+ break;
+ default: return;
+ }
+ }
+
+ AString s;
+ s.SetFrom_CalcLen((const char *)(Extra + link.NameOffset), link.NameLen);
+
+ UString unicode;
+ ConvertUTF8ToUnicode(s, unicode);
+ prop = NItemName::GetOsPath(unicode);
+}
+
+bool CItem::GetAltStreamName(AString &name) const
+{
+ name.Empty();
+ unsigned size;
+ int offset = FindExtra(NExtraID::kSubdata, size);
+ if (offset < 0)
+ return false;
+ name.SetFrom_CalcLen((const char *)(Extra + (unsigned)offset), size);
+ return true;
+}
+
+
+class CHash
+{
+ bool _calcCRC;
+ UInt32 _crc;
+ int _blakeOffset;
+ CBlake2sp _blake;
+public:
+
+ void Init_NoCalc()
+ {
+ _calcCRC = false;
+ _crc = CRC_INIT_VAL;
+ _blakeOffset = -1;
+ }
+
+ void Init(const CItem &item);
+ void Update(const void *data, size_t size);
+ UInt32 GetCRC() const { return CRC_GET_DIGEST(_crc); }
+
+ bool Check(const CItem &item, NCrypto::NRar5::CDecoder *cryptoDecoderSpec);
+};
+
+void CHash::Init(const CItem &item)
+{
+ _crc = CRC_INIT_VAL;
+ _calcCRC = item.Has_CRC();
+
+ _blakeOffset = item.FindExtra_Blake();
+ if (_blakeOffset >= 0)
+ Blake2sp_Init(&_blake);
+}
+
+void CHash::Update(const void *data, size_t size)
+{
+ if (_calcCRC)
+ _crc = CrcUpdate(_crc, data, size);
+ if (_blakeOffset >= 0)
+ Blake2sp_Update(&_blake, (const Byte *)data, size);
+}
+
+bool CHash::Check(const CItem &item, NCrypto::NRar5::CDecoder *cryptoDecoderSpec)
+{
+ if (_calcCRC)
+ {
+ UInt32 crc = GetCRC();
+ if (cryptoDecoderSpec)
+ crc = cryptoDecoderSpec->Hmac_Convert_Crc32(crc);
+ if (crc != item.CRC)
+ return false;
+ }
+
+ if (_blakeOffset >= 0)
+ {
+ Byte digest[BLAKE2S_DIGEST_SIZE];
+ Blake2sp_Final(&_blake, digest);
+ if (cryptoDecoderSpec)
+ cryptoDecoderSpec->Hmac_Convert_32Bytes(digest);
+ if (memcmp(digest, &item.Extra[(unsigned)_blakeOffset], BLAKE2S_DIGEST_SIZE) != 0)
+ return false;
+ }
+
+ return true;
+}
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ COutStreamWithHash
+ , ISequentialOutStream
+)
+ ISequentialOutStream *_stream;
+ UInt64 _pos;
+ UInt64 _size;
+ bool _size_Defined;
+ Byte *_destBuf;
+public:
+ CHash _hash;
+
+ COutStreamWithHash(): _destBuf(NULL) {}
+
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void Init(const CItem &item, Byte *destBuf)
+ {
+ _size_Defined = false;
+ _size = 0;
+ _destBuf = NULL;
+ if (!item.Is_UnknownSize())
+ {
+ _size_Defined = true;
+ _size = item.Size;
+ _destBuf = destBuf;
+ }
+ _pos = 0;
+ _hash.Init(item);
+ }
+ UInt64 GetPos() const { return _pos; }
+};
+
+
+Z7_COM7F_IMF(COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ HRESULT result = S_OK;
+ if (_size_Defined)
+ {
+ UInt64 rem = _size - _pos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+ if (_stream)
+ result = _stream->Write(data, size, &size);
+ if (_destBuf)
+ memcpy(_destBuf + (size_t)_pos, data, size);
+ _hash.Update(data, size);
+ _pos += size;
+ if (processedSize)
+ *processedSize = size;
+ return result;
+}
+
+
+
+
+
+class CInArchive
+{
+ CAlignedBuffer _buf;
+ size_t _bufSize;
+ size_t _bufPos;
+ ISequentialInStream *_stream;
+
+ NCrypto::NRar5::CDecoder *m_CryptoDecoderSpec;
+ CMyComPtr<ICompressFilter> m_CryptoDecoder;
+
+ Z7_CLASS_NO_COPY(CInArchive)
+
+ HRESULT ReadStream_Check(void *data, size_t size);
+
+public:
+ bool m_CryptoMode;
+
+ bool WrongPassword;
+ bool IsArc;
+ bool UnexpectedEnd;
+
+ UInt64 StreamStartPosition;
+ UInt64 Position;
+
+ bool ReadVar(UInt64 &val);
+
+ struct CHeader
+ {
+ UInt64 Type;
+ UInt64 Flags;
+ size_t ExtraSize;
+ UInt64 DataSize;
+ };
+
+ CInArchive() {}
+
+ HRESULT ReadBlockHeader(CHeader &h);
+ bool ReadFileHeader(const CHeader &header, CItem &item);
+ void AddToSeekValue(UInt64 addValue)
+ {
+ Position += addValue;
+ }
+
+ HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit, ICryptoGetTextPassword *getTextPassword,
+ CInArcInfo &info);
+};
+
+
+static HRESULT MySetPassword(ICryptoGetTextPassword *getTextPassword, NCrypto::NRar5::CDecoder *cryptoDecoderSpec)
+{
+ CMyComBSTR_Wipe password;
+ RINOK(getTextPassword->CryptoGetTextPassword(&password))
+ AString_Wipe utf8;
+ const unsigned kPasswordLen_MAX = 127;
+ UString_Wipe unicode;
+ unicode.SetFromBstr(password);
+ if (unicode.Len() > kPasswordLen_MAX)
+ unicode.DeleteFrom(kPasswordLen_MAX);
+ ConvertUnicodeToUTF8(unicode, utf8);
+ cryptoDecoderSpec->SetPassword((const Byte *)(const char *)utf8, utf8.Len());
+ return S_OK;
+}
+
+
+bool CInArchive::ReadVar(UInt64 &val)
+{
+ unsigned offset = ReadVarInt(_buf + _bufPos, _bufSize - _bufPos, &val);
+ _bufPos += offset;
+ return (offset != 0);
+}
+
+
+HRESULT CInArchive::ReadStream_Check(void *data, size_t size)
+{
+ size_t size2 = size;
+ RINOK(ReadStream(_stream, data, &size2))
+ if (size2 == size)
+ return S_OK;
+ UnexpectedEnd = true;
+ return S_FALSE;
+}
+
+
+HRESULT CInArchive::ReadBlockHeader(CHeader &h)
+{
+ h.Type = 0;
+ h.Flags = 0;
+ h.ExtraSize = 0;
+ h.DataSize = 0;
+
+ const unsigned kStartSize = 4 + 3;
+ const unsigned kBufSize = AES_BLOCK_SIZE + AES_BLOCK_SIZE; // must be >= kStartSize;
+ Byte buf[kBufSize];
+ unsigned filled;
+
+ if (m_CryptoMode)
+ {
+ RINOK(ReadStream_Check(buf, kBufSize))
+ memcpy(m_CryptoDecoderSpec->_iv, buf, AES_BLOCK_SIZE);
+ RINOK(m_CryptoDecoderSpec->Init())
+
+ _buf.AllocAtLeast(1 << 12);
+ if (!(Byte *)_buf)
+ return E_OUTOFMEMORY;
+
+ memcpy(_buf, buf + AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+ if (m_CryptoDecoder->Filter(_buf, AES_BLOCK_SIZE) != AES_BLOCK_SIZE)
+ return E_FAIL;
+ memcpy(buf, _buf, AES_BLOCK_SIZE);
+ filled = AES_BLOCK_SIZE;
+ }
+ else
+ {
+ RINOK(ReadStream_Check(buf, kStartSize))
+ filled = kStartSize;
+ }
+
+ UInt64 val;
+ unsigned offset = ReadVarInt(buf + 4, 3, &val);
+ if (offset == 0)
+ return S_FALSE;
+ {
+ size_t size = (size_t)val;
+ _bufPos = (4 + offset);
+ _bufSize = _bufPos + size;
+ if (size < 2)
+ return S_FALSE;
+ }
+
+ size_t allocSize = _bufSize;
+ if (m_CryptoMode)
+ allocSize = (allocSize + AES_BLOCK_SIZE - 1) & ~(size_t)(AES_BLOCK_SIZE - 1);
+ _buf.AllocAtLeast(allocSize);
+ if (!(Byte *)_buf)
+ return E_OUTOFMEMORY;
+
+ memcpy(_buf, buf, filled);
+
+ size_t rem = allocSize - filled;
+ AddToSeekValue(allocSize + (m_CryptoMode ? AES_BLOCK_SIZE : 0));
+ RINOK(ReadStream_Check(_buf + filled, rem))
+ if (m_CryptoMode)
+ {
+ if (m_CryptoDecoder->Filter(_buf + filled, (UInt32)rem) != rem)
+ return E_FAIL;
+ }
+
+ if (CrcCalc(_buf + 4, _bufSize - 4) != Get32(buf))
+ return S_FALSE;
+
+ if (!ReadVar(h.Type)) return S_FALSE;
+ if (!ReadVar(h.Flags)) return S_FALSE;
+
+ if (h.Flags & NHeaderFlags::kExtra)
+ {
+ UInt64 extraSize;
+ if (!ReadVar(extraSize))
+ return S_FALSE;
+ if (extraSize > _bufSize)
+ return S_FALSE;
+ h.ExtraSize = (size_t)extraSize;
+ }
+
+ if (h.Flags & NHeaderFlags::kData)
+ {
+ if (!ReadVar(h.DataSize))
+ return S_FALSE;
+ }
+
+ return S_OK;
+}
+
+
+/*
+int CInArcInfo::FindExtra(unsigned extraID, unsigned &recordDataSize) const
+{
+ recordDataSize = 0;
+ size_t offset = 0;
+
+ for (;;)
+ {
+ size_t rem = Extra.Size() - offset;
+ if (rem == 0)
+ return -1;
+
+ {
+ UInt64 size;
+ unsigned num = ReadVarInt(Extra + offset, rem, &size);
+ if (num == 0)
+ return -1;
+ offset += num;
+ rem -= num;
+ if (size > rem)
+ return -1;
+ rem = (size_t)size;
+ }
+ {
+ UInt64 id;
+ unsigned num = ReadVarInt(Extra + offset, rem, &id);
+ if (num == 0)
+ return -1;
+ offset += num;
+ rem -= num;
+
+ if (id == extraID)
+ {
+ recordDataSize = (unsigned)rem;
+ return (int)offset;
+ }
+
+ offset += rem;
+ }
+ }
+}
+
+
+bool CInArcInfo::FindExtra_Locator(CLocator &locator) const
+{
+ locator.Flags = 0;
+ locator.QuickOpen = 0;
+ locator.Recovery = 0;
+
+ unsigned size;
+ int offset = FindExtra(kArcExtraRecordType_Locator, size);
+ if (offset < 0)
+ return false;
+ const Byte *p = Extra + (unsigned)offset;
+
+ unsigned num;
+
+ num = ReadVarInt(p, size, &locator.Flags);
+ if (num == 0) return false; p += num; size -= num;
+
+ if (locator.Is_QuickOpen())
+ {
+ num = ReadVarInt(p, size, &locator.QuickOpen);
+ if (num == 0) return false; p += num; size -= num;
+ }
+
+ if (locator.Is_Recovery())
+ {
+ num = ReadVarInt(p, size, &locator.Recovery);
+ if (num == 0) return false; p += num; size -= num;
+ }
+
+ return true;
+}
+*/
+
+
+HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit, ICryptoGetTextPassword *getTextPassword,
+ CInArcInfo &info)
+{
+ m_CryptoMode = false;
+
+ WrongPassword = false;
+ IsArc = false;
+ UnexpectedEnd = false;
+
+ Position = StreamStartPosition;
+
+ UInt64 arcStartPos = StreamStartPosition;
+ {
+ Byte marker[kMarkerSize];
+ RINOK(ReadStream_FALSE(stream, marker, kMarkerSize))
+ if (memcmp(marker, kMarker, kMarkerSize) == 0)
+ Position += kMarkerSize;
+ else
+ {
+ if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0)
+ return S_FALSE;
+ RINOK(InStream_SeekSet(stream, StreamStartPosition))
+ RINOK(FindSignatureInStream(stream, kMarker, kMarkerSize,
+ searchHeaderSizeLimit, arcStartPos))
+ arcStartPos += StreamStartPosition;
+ Position = arcStartPos + kMarkerSize;
+ RINOK(InStream_SeekSet(stream, Position))
+ }
+ }
+
+ info.StartPos = arcStartPos;
+ _stream = stream;
+
+ CHeader h;
+ RINOK(ReadBlockHeader(h))
+ info.IsEncrypted = false;
+
+ if (h.Type == NHeaderType::kArcEncrypt)
+ {
+ info.IsEncrypted = true;
+ IsArc = true;
+ if (!getTextPassword)
+ return E_NOTIMPL;
+
+ m_CryptoMode = true;
+
+ if (!m_CryptoDecoder)
+ {
+ m_CryptoDecoderSpec = new NCrypto::NRar5::CDecoder;
+ m_CryptoDecoder = m_CryptoDecoderSpec;
+ }
+
+ RINOK(m_CryptoDecoderSpec->SetDecoderProps(
+ _buf + _bufPos, (unsigned)(_bufSize - _bufPos), false, false))
+
+ RINOK(MySetPassword(getTextPassword, m_CryptoDecoderSpec))
+
+ if (!m_CryptoDecoderSpec->CalcKey_and_CheckPassword())
+ {
+ WrongPassword = True;
+ return S_FALSE;
+ }
+
+ RINOK(ReadBlockHeader(h))
+ }
+
+ if (h.Type != NHeaderType::kArc)
+ return S_FALSE;
+
+ IsArc = true;
+ info.VolNumber = 0;
+
+ if (!ReadVar(info.Flags))
+ return S_FALSE;
+
+ if (info.Flags & NArcFlags::kVolNumber)
+ if (!ReadVar(info.VolNumber))
+ return S_FALSE;
+
+ if (h.ExtraSize != 0)
+ {
+ if (_bufSize - _bufPos < h.ExtraSize)
+ return S_FALSE;
+ /*
+ info.Extra.Alloc(h.ExtraSize);
+ memcpy(info.Extra, _buf + _bufPos, h.ExtraSize);
+ */
+ _bufPos += h.ExtraSize;
+
+ /*
+ CInArcInfo::CLocator locator;
+ if (info.FindExtra_Locator(locator))
+ locator.Flags = locator.Flags;
+ */
+ }
+
+ if (_bufPos != _bufSize)
+ return S_FALSE;
+
+ return S_OK;
+}
+
+
+bool CInArchive::ReadFileHeader(const CHeader &header, CItem &item)
+{
+ item.UnixMTime = 0;
+ item.CRC = 0;
+ item.Flags = 0;
+
+ item.CommonFlags = (UInt32)header.Flags;
+ item.PackSize = header.DataSize;
+
+ UInt64 flags64;
+ if (!ReadVar(flags64)) return false;
+ item.Flags = (UInt32)flags64;
+
+ if (!ReadVar(item.Size)) return false;
+
+ {
+ UInt64 attrib;
+ if (!ReadVar(attrib)) return false;
+ item.Attrib = (UInt32)attrib;
+ }
+
+ if (item.Has_UnixMTime())
+ {
+ if (_bufSize - _bufPos < 4)
+ return false;
+ item.UnixMTime = Get32(_buf + _bufPos);
+ _bufPos += 4;
+ }
+
+ if (item.Has_CRC())
+ {
+ if (_bufSize - _bufPos < 4)
+ return false;
+ item.CRC = Get32(_buf + _bufPos);
+ _bufPos += 4;
+ }
+
+ {
+ UInt64 method;
+ if (!ReadVar(method)) return false;
+ item.Method = (UInt32)method;
+ }
+
+ if (!ReadVar(item.HostOS)) return false;
+
+ {
+ UInt64 len;
+ if (!ReadVar(len)) return false;
+ if (len > _bufSize - _bufPos)
+ return false;
+ item.Name.SetFrom_CalcLen((const char *)(_buf + _bufPos), (unsigned)len);
+ _bufPos += (unsigned)len;
+ }
+
+ item.Extra.Free();
+ size_t extraSize = header.ExtraSize;
+ if (extraSize != 0)
+ {
+ if (_bufSize - _bufPos < extraSize)
+ return false;
+ item.Extra.Alloc(extraSize);
+ memcpy(item.Extra, _buf + _bufPos, extraSize);
+ _bufPos += extraSize;
+ }
+
+
+ return (_bufPos == _bufSize);
+}
+
+
+
+struct CLinkFile
+{
+ unsigned Index;
+ unsigned NumLinks; // the number of links to Data
+ CByteBuffer Data;
+ HRESULT Res;
+ bool crcOK;
+
+ CLinkFile(): Index(0), NumLinks(0), Res(S_OK), crcOK(true) {}
+};
+
+
+struct CUnpacker
+{
+ NCompress::CCopyCoder *copyCoderSpec;
+ CMyComPtr<ICompressCoder> copyCoder;
+
+ CMyComPtr<ICompressCoder> LzCoders[2];
+ bool SolidAllowed;
+
+ CFilterCoder *filterStreamSpec;
+ CMyComPtr<ISequentialInStream> filterStream;
+
+ NCrypto::NRar5::CDecoder *cryptoDecoderSpec;
+ CMyComPtr<ICompressFilter> cryptoDecoder;
+
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+
+ COutStreamWithHash *outStreamSpec;
+ CMyComPtr<ISequentialOutStream> outStream;
+
+ CByteBuffer _tempBuf;
+
+ CLinkFile *linkFile;
+
+ CUnpacker(): linkFile(NULL) { SolidAllowed = false; }
+
+ HRESULT Create(DECL_EXTERNAL_CODECS_LOC_VARS const CItem &item, bool isSolid, bool &wrongPassword);
+
+ HRESULT Code(const CItem &item, const CItem &lastItem, UInt64 packSize,
+ ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress,
+ bool &isCrcOK);
+
+ HRESULT DecodeToBuf(DECL_EXTERNAL_CODECS_LOC_VARS const CItem &item, UInt64 packSize, ISequentialInStream *inStream, CByteBuffer &buffer);
+};
+
+
+static const unsigned kLzMethodMax = 5;
+
+HRESULT CUnpacker::Create(DECL_EXTERNAL_CODECS_LOC_VARS const CItem &item, bool isSolid, bool &wrongPassword)
+{
+ wrongPassword = false;
+
+ if (item.GetAlgoVersion() != 0)
+ return E_NOTIMPL;
+
+ if (!outStream)
+ {
+ outStreamSpec = new COutStreamWithHash;
+ outStream = outStreamSpec;
+ }
+
+ unsigned method = item.GetMethod();
+
+ if (method == 0)
+ {
+ if (!copyCoder)
+ {
+ copyCoderSpec = new NCompress::CCopyCoder;
+ copyCoder = copyCoderSpec;
+ }
+ }
+ else
+ {
+ if (method > kLzMethodMax)
+ return E_NOTIMPL;
+
+ /*
+ if (item.IsSplitBefore())
+ return S_FALSE;
+ */
+
+ int lzIndex = item.IsService() ? 1 : 0;
+ CMyComPtr<ICompressCoder> &lzCoder = LzCoders[lzIndex];
+
+ if (!lzCoder)
+ {
+ const UInt32 methodID = 0x40305;
+ RINOK(CreateCoder_Id(EXTERNAL_CODECS_LOC_VARS methodID, false, lzCoder))
+ if (!lzCoder)
+ return E_NOTIMPL;
+ }
+
+ CMyComPtr<ICompressSetDecoderProperties2> csdp;
+ RINOK(lzCoder.QueryInterface(IID_ICompressSetDecoderProperties2, &csdp))
+
+ Byte props[2] = { (Byte)(item.GetDictSize()), (Byte)(isSolid ? 1 : 0) };
+ RINOK(csdp->SetDecoderProperties2(props, 2))
+ }
+
+ unsigned cryptoSize = 0;
+ int cryptoOffset = item.FindExtra(NExtraID::kCrypto, cryptoSize);
+
+ if (cryptoOffset >= 0)
+ {
+ if (!filterStream)
+ {
+ filterStreamSpec = new CFilterCoder(false);
+ filterStream = filterStreamSpec;
+ }
+
+ if (!cryptoDecoder)
+ {
+ cryptoDecoderSpec = new NCrypto::NRar5::CDecoder;
+ cryptoDecoder = cryptoDecoderSpec;
+ }
+
+ RINOK(cryptoDecoderSpec->SetDecoderProps(item.Extra + (unsigned)cryptoOffset, cryptoSize, true, item.IsService()))
+
+ if (!getTextPassword)
+ {
+ wrongPassword = True;
+ return E_NOTIMPL;
+ }
+
+ RINOK(MySetPassword(getTextPassword, cryptoDecoderSpec))
+
+ if (!cryptoDecoderSpec->CalcKey_and_CheckPassword())
+ wrongPassword = True;
+ }
+
+ return S_OK;
+}
+
+
+HRESULT CUnpacker::Code(const CItem &item, const CItem &lastItem, UInt64 packSize,
+ ISequentialInStream *volsInStream, ISequentialOutStream *realOutStream, ICompressProgressInfo *progress,
+ bool &isCrcOK)
+{
+ isCrcOK = true;
+
+ unsigned method = item.GetMethod();
+ if (method > kLzMethodMax)
+ return E_NOTIMPL;
+
+ bool needBuf = (linkFile && linkFile->NumLinks != 0);
+
+ if (needBuf && !lastItem.Is_UnknownSize())
+ {
+ size_t dataSize = (size_t)lastItem.Size;
+ if (dataSize != lastItem.Size)
+ return E_NOTIMPL;
+ linkFile->Data.Alloc(dataSize);
+ }
+
+ bool isCryptoMode = false;
+ ISequentialInStream *inStream;
+
+ if (item.IsEncrypted())
+ {
+ filterStreamSpec->Filter = cryptoDecoder;
+ filterStreamSpec->SetInStream(volsInStream);
+ filterStreamSpec->SetOutStreamSize(NULL);
+ inStream = filterStream;
+ isCryptoMode = true;
+ }
+ else
+ inStream = volsInStream;
+
+ ICompressCoder *commonCoder = (method == 0) ? copyCoder : LzCoders[item.IsService() ? 1 : 0];
+
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init(lastItem, (needBuf ? (Byte *)linkFile->Data : NULL));
+
+ HRESULT res = S_OK;
+ if (packSize != 0 || lastItem.Is_UnknownSize() || lastItem.Size != 0)
+ {
+ res = commonCoder->Code(inStream, outStream, &packSize,
+ lastItem.Is_UnknownSize() ? NULL : &lastItem.Size, progress);
+ if (!item.IsService())
+ SolidAllowed = true;
+ }
+ else
+ {
+ // res = res;
+ }
+
+ if (isCryptoMode)
+ filterStreamSpec->ReleaseInStream();
+
+ UInt64 processedSize = outStreamSpec->GetPos();
+ if (res == S_OK && !lastItem.Is_UnknownSize() && processedSize != lastItem.Size)
+ res = S_FALSE;
+
+ // if (res == S_OK)
+ {
+ unsigned cryptoSize = 0;
+ int cryptoOffset = lastItem.FindExtra(NExtraID::kCrypto, cryptoSize);
+ NCrypto::NRar5::CDecoder *crypto = NULL;
+
+ if (cryptoOffset >= 0)
+ {
+ CCryptoInfo cryptoInfo;
+ if (cryptoInfo.Parse(lastItem.Extra + (unsigned)cryptoOffset, cryptoSize))
+ if (cryptoInfo.UseMAC())
+ crypto = cryptoDecoderSpec;
+ }
+
+ isCrcOK = outStreamSpec->_hash.Check(lastItem, crypto);
+ }
+
+ if (linkFile)
+ {
+ linkFile->Res = res;
+ linkFile->crcOK = isCrcOK;
+ if (needBuf
+ && !lastItem.Is_UnknownSize()
+ && processedSize != lastItem.Size)
+ linkFile->Data.ChangeSize_KeepData((size_t)processedSize, (size_t)processedSize);
+ }
+
+ return res;
+}
+
+
+HRESULT CUnpacker::DecodeToBuf(DECL_EXTERNAL_CODECS_LOC_VARS const CItem &item, UInt64 packSize, ISequentialInStream *inStream, CByteBuffer &buffer)
+{
+ CBufPtrSeqOutStream *outSpec = new CBufPtrSeqOutStream;
+ CMyComPtr<ISequentialOutStream> out = outSpec;
+ _tempBuf.AllocAtLeast((size_t)item.Size);
+ outSpec->Init(_tempBuf, (size_t)item.Size);
+
+ bool wrongPassword;
+
+ if (item.IsSolid())
+ return E_NOTIMPL;
+
+ HRESULT res = Create(EXTERNAL_CODECS_LOC_VARS item, item.IsSolid(), wrongPassword);
+
+ if (res == S_OK)
+ {
+ if (wrongPassword)
+ return S_FALSE;
+
+ CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> limitedStream(limitedStreamSpec);
+ limitedStreamSpec->SetStream(inStream);
+ limitedStreamSpec->Init(packSize);
+
+ bool crcOK = true;
+ res = Code(item, item, packSize, limitedStream, out, NULL, crcOK);
+ if (res == S_OK)
+ {
+ if (!crcOK || outSpec->GetPos() != item.Size)
+ res = S_FALSE;
+ else
+ buffer.CopyFrom(_tempBuf, (size_t)item.Size);
+ }
+ }
+
+ return res;
+}
+
+
+struct CTempBuf
+{
+ CByteBuffer _buf;
+ size_t _offset;
+ bool _isOK;
+
+ void Clear()
+ {
+ _offset = 0;
+ _isOK = true;
+ }
+
+ CTempBuf() { Clear(); }
+
+ HRESULT Decode(DECL_EXTERNAL_CODECS_LOC_VARS
+ const CItem &item,
+ ISequentialInStream *inStream, CUnpacker &unpacker, CByteBuffer &destBuf);
+};
+
+
+HRESULT CTempBuf::Decode(DECL_EXTERNAL_CODECS_LOC_VARS
+ const CItem &item,
+ ISequentialInStream *inStream,
+ CUnpacker &unpacker,
+ CByteBuffer &destBuf)
+{
+ const size_t kPackSize_Max = (1 << 24);
+ if (item.Size > (1 << 24)
+ || item.Size == 0
+ || item.PackSize >= kPackSize_Max)
+ {
+ Clear();
+ return S_OK;
+ }
+
+ if (item.IsSplit() /* && _isOK */)
+ {
+ size_t packSize = (size_t)item.PackSize;
+ if (packSize > kPackSize_Max - _offset)
+ return S_OK;
+ size_t newSize = _offset + packSize;
+ if (newSize > _buf.Size())
+ _buf.ChangeSize_KeepData(newSize, _offset);
+
+ Byte *data = (Byte *)_buf + _offset;
+ RINOK(ReadStream_FALSE(inStream, data, packSize))
+
+ _offset += packSize;
+
+ if (item.IsSplitAfter())
+ {
+ CHash hash;
+ hash.Init(item);
+ hash.Update(data, packSize);
+ _isOK = hash.Check(item, NULL); // RAR5 doesn't use HMAC for packed part
+ }
+ }
+
+ if (_isOK)
+ {
+ if (!item.IsSplitAfter())
+ {
+ if (_offset == 0)
+ {
+ RINOK(unpacker.DecodeToBuf(EXTERNAL_CODECS_LOC_VARS
+ item, item.PackSize, inStream, destBuf))
+ }
+ else
+ {
+ CBufInStream *bufInStreamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> bufInStream = bufInStreamSpec;
+ bufInStreamSpec->Init(_buf, _offset);
+ RINOK(unpacker.DecodeToBuf(EXTERNAL_CODECS_LOC_VARS
+ item, _offset, bufInStream, destBuf))
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidCTime,
+ kpidATime,
+ kpidAttrib,
+
+ kpidIsAltStream,
+ kpidEncrypted,
+ kpidSolid,
+ kpidSplitBefore,
+ kpidSplitAfter,
+ kpidCRC,
+ kpidHostOS,
+ kpidMethod,
+ kpidCharacts,
+ kpidSymLink,
+ kpidHardLink,
+ kpidCopyLink,
+
+ kpidVolumeIndex
+};
+
+
+static const Byte kArcProps[] =
+{
+ kpidTotalPhySize,
+ kpidCharacts,
+ kpidSolid,
+ kpidNumBlocks,
+ kpidEncrypted,
+ kpidIsVolume,
+ kpidVolumeIndex,
+ kpidNumVolumes,
+ kpidComment
+};
+
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+
+UInt64 CHandler::GetPackSize(unsigned refIndex) const
+{
+ UInt64 size = 0;
+ unsigned index = _refs[refIndex].Item;
+ for (;;)
+ {
+ const CItem &item = _items[index];
+ size += item.PackSize;
+ if (item.NextItem < 0)
+ return size;
+ index = (unsigned)item.NextItem;
+ }
+}
+
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+
+ NCOM::CPropVariant prop;
+
+ const CInArcInfo *arcInfo = NULL;
+ if (!_arcs.IsEmpty())
+ arcInfo = &_arcs[0].Info;
+
+ switch (propID)
+ {
+ case kpidVolumeIndex: if (arcInfo && arcInfo->IsVolume()) prop = arcInfo->GetVolIndex(); break;
+ case kpidSolid: if (arcInfo) prop = arcInfo->IsSolid(); break;
+ case kpidCharacts:
+ {
+ if (!_arcs.IsEmpty())
+ {
+ FLAGS_TO_PROP(k_ArcFlags, (UInt32)arcInfo->Flags, prop);
+ }
+ break;
+ }
+ case kpidEncrypted: if (arcInfo) prop = arcInfo->IsEncrypted; break; // it's for encrypted names.
+ case kpidIsVolume: if (arcInfo) prop = arcInfo->IsVolume(); break;
+ case kpidNumVolumes: prop = (UInt32)_arcs.Size(); break;
+ case kpidOffset: if (arcInfo && arcInfo->StartPos != 0) prop = arcInfo->StartPos; break;
+
+ case kpidTotalPhySize:
+ {
+ if (_arcs.Size() > 1)
+ {
+ UInt64 sum = 0;
+ FOR_VECTOR (v, _arcs)
+ sum += _arcs[v].Info.GetPhySize();
+ prop = sum;
+ }
+ break;
+ }
+
+ case kpidPhySize:
+ {
+ if (arcInfo)
+ prop = arcInfo->GetPhySize();
+ break;
+ }
+
+ case kpidComment:
+ {
+ // if (!_arcs.IsEmpty())
+ {
+ // const CArc &arc = _arcs[0];
+ const CByteBuffer &cmt = _comment;
+ if (cmt.Size() != 0 && cmt.Size() < (1 << 16))
+ {
+ AString s;
+ s.SetFrom_CalcLen((const char *)(const Byte *)cmt, (unsigned)cmt.Size());
+ UString unicode;
+ ConvertUTF8ToUnicode(s, unicode);
+ prop = unicode;
+ }
+ }
+ break;
+ }
+
+ case kpidNumBlocks:
+ {
+ UInt32 numBlocks = 0;
+ FOR_VECTOR (i, _refs)
+ if (!_items[_refs[i].Item].IsSolid())
+ numBlocks++;
+ prop = (UInt32)numBlocks;
+ break;
+ }
+
+ case kpidError:
+ {
+ if (/* &_missingVol || */ !_missingVolName.IsEmpty())
+ {
+ UString s ("Missing volume : ");
+ s += _missingVolName;
+ prop = s;
+ }
+ break;
+ }
+
+ case kpidErrorFlags:
+ {
+ UInt32 v = _errorFlags;
+ if (!_isArc)
+ v |= kpv_ErrorFlags_IsNotArc;
+ prop = v;
+ break;
+ }
+
+ /*
+ case kpidWarningFlags:
+ {
+ if (_warningFlags != 0)
+ prop = _warningFlags;
+ break;
+ }
+ */
+
+ case kpidExtension:
+ if (_arcs.Size() == 1)
+ {
+ if (arcInfo->IsVolume())
+ {
+ AString s ("part");
+ UInt32 v = (UInt32)arcInfo->GetVolIndex() + 1;
+ if (v < 10)
+ s += '0';
+ s.Add_UInt32(v);
+ s += ".rar";
+ prop = s;
+ }
+ }
+ break;
+
+ case kpidIsAltStream: prop = true; break;
+ }
+
+ prop.Detach(value);
+ return S_OK;
+
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _refs.Size();
+ return S_OK;
+}
+
+
+static const Byte kRawProps[] =
+{
+ kpidChecksum,
+ kpidNtSecure
+};
+
+
+Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps))
+{
+ *numProps = Z7_ARRAY_SIZE(kRawProps);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID))
+{
+ *propID = kRawProps[index];
+ *name = NULL;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType))
+{
+ *parentType = NParentType::kDir;
+ *parent = (UInt32)(Int32)-1;
+
+ if (index >= _refs.Size())
+ return S_OK;
+
+ const CRefItem &ref = _refs[index];
+ const CItem &item = _items[ref.Item];
+
+ if (item.Is_STM() && ref.Parent >= 0)
+ {
+ *parent = (UInt32)ref.Parent;
+ *parentType = NParentType::kAltStream;
+ }
+
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
+{
+ *data = NULL;
+ *dataSize = 0;
+ *propType = 0;
+
+ if (index >= _refs.Size())
+ return E_INVALIDARG;
+
+ const CItem &item = _items[_refs[index].Item];
+
+ if (propID == kpidNtSecure)
+ {
+ if (item.ACL >= 0)
+ {
+ const CByteBuffer &buf = _acls[item.ACL];
+ *dataSize = (UInt32)buf.Size();
+ *propType = NPropDataType::kRaw;
+ *data = (const Byte *)buf;
+ }
+ return S_OK;
+ }
+
+ if (propID == kpidChecksum)
+ {
+ int hashRecOffset = item.FindExtra_Blake();
+ if (hashRecOffset >= 0)
+ {
+ *dataSize = BLAKE2S_DIGEST_SIZE;
+ *propType = NPropDataType::kRaw;
+ *data = &item.Extra[hashRecOffset];
+ }
+ return S_OK;
+ }
+
+ return S_OK;
+}
+
+
+static void TimeRecordToProp(const CItem &item, unsigned stampIndex, NCOM::CPropVariant &prop)
+{
+ unsigned size;
+ const int offset = item.FindExtra(NExtraID::kTime, size);
+ if (offset < 0)
+ return;
+
+ const Byte *p = item.Extra + (unsigned)offset;
+ UInt64 flags;
+ {
+ const unsigned num = ReadVarInt(p, size, &flags);
+ if (num == 0)
+ return;
+ p += num;
+ size -= num;
+ }
+
+ if ((flags & (NTimeRecord::NFlags::kMTime << stampIndex)) == 0)
+ return;
+
+ unsigned numStamps = 0;
+ unsigned curStamp = 0;
+
+ for (unsigned i = 0; i < 3; i++)
+ if ((flags & (NTimeRecord::NFlags::kMTime << i)) != 0)
+ {
+ if (i == stampIndex)
+ curStamp = numStamps;
+ numStamps++;
+ }
+
+ FILETIME ft;
+
+ unsigned timePrec = 0;
+ unsigned ns100 = 0;
+
+ if ((flags & NTimeRecord::NFlags::kUnixTime) != 0)
+ {
+ curStamp *= 4;
+ if (curStamp + 4 > size)
+ return;
+ p += curStamp;
+ UInt64 val = NTime::UnixTime_To_FileTime64(Get32(p));
+ numStamps *= 4;
+ timePrec = k_PropVar_TimePrec_Unix;
+ if ((flags & NTimeRecord::NFlags::kUnixNs) != 0 && numStamps * 2 <= size)
+ {
+ const UInt32 ns = Get32(p + numStamps) & 0x3FFFFFFF;
+ if (ns < 1000000000)
+ {
+ val += ns / 100;
+ ns100 = (unsigned)(ns % 100);
+ timePrec = k_PropVar_TimePrec_1ns;
+ }
+ }
+ ft.dwLowDateTime = (DWORD)val;
+ ft.dwHighDateTime = (DWORD)(val >> 32);
+ }
+ else
+ {
+ curStamp *= 8;
+ if (curStamp + 8 > size)
+ return;
+ p += curStamp;
+ ft.dwLowDateTime = Get32(p);
+ ft.dwHighDateTime = Get32(p + 4);
+ }
+
+ prop.SetAsTimeFrom_FT_Prec_Ns100(ft, timePrec, ns100);
+}
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+
+ NCOM::CPropVariant prop;
+ const CRefItem &ref = _refs[index];
+ const CItem &item = _items[ref.Item];
+ const CItem &lastItem = _items[ref.Last];
+
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ UString unicodeName;
+
+ if (item.Is_STM())
+ {
+ AString s;
+ if (ref.Parent >= 0)
+ {
+ const CItem &mainItem = _items[_refs[ref.Parent].Item];
+ s = mainItem.Name;
+ }
+
+ AString name;
+ item.GetAltStreamName(name);
+ if (name[0] != ':')
+ s += ':';
+ s += name;
+ ConvertUTF8ToUnicode(s, unicodeName);
+ }
+ else
+ {
+ ConvertUTF8ToUnicode(item.Name, unicodeName);
+
+ if (item.Version_Defined)
+ {
+ char temp[32];
+ // temp[0] = ';';
+ // ConvertUInt64ToString(item.Version, temp + 1);
+ // unicodeName += temp;
+ ConvertUInt64ToString(item.Version, temp);
+ UString s2 ("[VER]" STRING_PATH_SEPARATOR);
+ s2 += temp;
+ s2.Add_PathSepar();
+ unicodeName.Insert(0, s2);
+ }
+ }
+
+ NItemName::ReplaceToOsSlashes_Remove_TailSlash(unicodeName);
+ prop = unicodeName;
+
+ break;
+ }
+
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: if (!lastItem.Is_UnknownSize()) prop = lastItem.Size; break;
+ case kpidPackSize: prop = GetPackSize(index); break;
+
+ case kpidMTime:
+ {
+ TimeRecordToProp(item, NTimeRecord::k_Index_MTime, prop);
+ if (prop.vt == VT_EMPTY && item.Has_UnixMTime())
+ PropVariant_SetFrom_UnixTime(prop, item.UnixMTime);
+ if (prop.vt == VT_EMPTY && ref.Parent >= 0)
+ {
+ const CItem &baseItem = _items[_refs[ref.Parent].Item];
+ TimeRecordToProp(baseItem, NTimeRecord::k_Index_MTime, prop);
+ if (prop.vt == VT_EMPTY && baseItem.Has_UnixMTime())
+ PropVariant_SetFrom_UnixTime(prop, baseItem.UnixMTime);
+ }
+ break;
+ }
+ case kpidCTime: TimeRecordToProp(item, NTimeRecord::k_Index_CTime, prop); break;
+ case kpidATime: TimeRecordToProp(item, NTimeRecord::k_Index_ATime, prop); break;
+
+ case kpidName:
+ {
+ if (item.Is_STM())
+ {
+ AString name;
+ item.GetAltStreamName(name);
+ if (name[0] == ':')
+ {
+ name.DeleteFrontal(1);
+ UString unicodeName;
+ ConvertUTF8ToUnicode(name, unicodeName);
+ prop = unicodeName;
+ }
+ }
+ break;
+ }
+
+ case kpidIsAltStream: prop = item.Is_STM(); break;
+
+ case kpidSymLink: item.Link_to_Prop(NLinkType::kUnixSymLink, prop); break;
+ case kpidHardLink: item.Link_to_Prop(NLinkType::kHardLink, prop); break;
+ case kpidCopyLink: item.Link_to_Prop(NLinkType::kFileCopy, prop); break;
+
+ case kpidAttrib: prop = item.GetWinAttrib(); break;
+ case kpidEncrypted: prop = item.IsEncrypted(); break;
+ case kpidSolid: prop = item.IsSolid(); break;
+
+ case kpidSplitBefore: prop = item.IsSplitBefore(); break;
+ case kpidSplitAfter: prop = lastItem.IsSplitAfter(); break;
+
+ case kpidVolumeIndex:
+ {
+ if (item.VolIndex < _arcs.Size())
+ {
+ const CInArcInfo &arcInfo = _arcs[item.VolIndex].Info;
+ if (arcInfo.IsVolume())
+ prop = (UInt64)arcInfo.GetVolIndex();
+ }
+ break;
+ }
+
+ case kpidCRC:
+ {
+ const CItem *item2 = (lastItem.IsSplitAfter() ? &item : &lastItem);
+ if (item2->Has_CRC())
+ prop = item2->CRC;
+ break;
+ }
+
+ case kpidMethod:
+ {
+ char temp[128];
+ unsigned algo = item.GetAlgoVersion();
+ char *s = temp;
+ if (algo != 0)
+ {
+ ConvertUInt32ToString(algo, s);
+ s += MyStringLen(s);
+ *s++ = ':';
+ }
+ unsigned m = item.GetMethod();
+ {
+ s[0] = 'm';
+ s[1] = (char)(m + '0');
+ s[2] = 0;
+ if (!item.IsDir())
+ {
+ s[2] = ':';
+ ConvertUInt32ToString(item.GetDictSize() + 17, s + 3);
+ }
+ }
+
+ unsigned cryptoSize = 0;
+ int cryptoOffset = item.FindExtra(NExtraID::kCrypto, cryptoSize);
+ if (cryptoOffset >= 0)
+ {
+ s = temp + strlen(temp);
+ *s++ = ' ';
+
+ CCryptoInfo cryptoInfo;
+
+ bool isOK = cryptoInfo.Parse(item.Extra + (unsigned)cryptoOffset, cryptoSize);
+
+ if (cryptoInfo.Algo == 0)
+ s = MyStpCpy(s, "AES");
+ else
+ {
+ s = MyStpCpy(s, "Crypto_");
+ ConvertUInt64ToString(cryptoInfo.Algo, s);
+ s += strlen(s);
+ }
+
+ if (isOK)
+ {
+ *s++ = ':';
+ ConvertUInt32ToString(cryptoInfo.Cnt, s);
+ s += strlen(s);
+ *s++ = ':';
+ ConvertUInt64ToString(cryptoInfo.Flags, s);
+ }
+ }
+
+ prop = temp;
+ break;
+ }
+
+ case kpidCharacts:
+ {
+ AString s;
+
+ if (item.ACL >= 0)
+ {
+ s.Add_OptSpaced("ACL");
+ }
+
+ UInt32 flags = item.Flags;
+ // flags &= ~(6); // we don't need compression related bits here.
+
+ if (flags != 0)
+ {
+ AString s2 = FlagsToString(k_FileFlags, Z7_ARRAY_SIZE(k_FileFlags), flags);
+ if (!s2.IsEmpty())
+ {
+ s.Add_OptSpaced(s2);
+ }
+ }
+
+ item.PrintInfo(s);
+
+ if (!s.IsEmpty())
+ prop = s;
+ break;
+ }
+
+
+ case kpidHostOS:
+ if (item.HostOS < Z7_ARRAY_SIZE(kHostOS))
+ prop = kHostOS[(size_t)item.HostOS];
+ else
+ prop = (UInt64)item.HostOS;
+ break;
+ }
+
+ prop.Detach(value);
+ return S_OK;
+
+ COM_TRY_END
+}
+
+
+
+// ---------- Copy Links ----------
+
+static int CompareItemsPaths(const CHandler &handler, unsigned p1, unsigned p2, const AString *name1)
+{
+ const CItem &item1 = handler._items[handler._refs[p1].Item];
+ const CItem &item2 = handler._items[handler._refs[p2].Item];
+
+ if (item1.Version_Defined)
+ {
+ if (!item2.Version_Defined)
+ return -1;
+ int res = MyCompare(item1.Version, item2.Version);
+ if (res != 0)
+ return res;
+ }
+ else if (item2.Version_Defined)
+ return 1;
+
+ if (!name1)
+ name1 = &item1.Name;
+ return strcmp(*name1, item2.Name);
+}
+
+static int CompareItemsPaths2(const CHandler &handler, unsigned p1, unsigned p2, const AString *name1)
+{
+ int res = CompareItemsPaths(handler, p1, p2, name1);
+ if (res != 0)
+ return res;
+ return MyCompare(p1, p2);
+}
+
+static int CompareItemsPaths_Sort(const unsigned *p1, const unsigned *p2, void *param)
+{
+ return CompareItemsPaths2(*(const CHandler *)param, *p1, *p2, NULL);
+}
+
+static int FindLink(const CHandler &handler, const CUIntVector &sorted,
+ const AString &s, unsigned index)
+{
+ unsigned left = 0, right = sorted.Size();
+ for (;;)
+ {
+ if (left == right)
+ {
+ if (left > 0)
+ {
+ const unsigned refIndex = sorted[left - 1];
+ if (CompareItemsPaths(handler, index, refIndex, &s) == 0)
+ return (int)refIndex;
+ }
+ if (right < sorted.Size())
+ {
+ const unsigned refIndex = sorted[right];
+ if (CompareItemsPaths(handler, index, refIndex, &s) == 0)
+ return (int)refIndex;
+ }
+ return -1;
+ }
+
+ const unsigned mid = (left + right) / 2;
+ const unsigned refIndex = sorted[mid];
+ const int compare = CompareItemsPaths2(handler, index, refIndex, &s);
+ if (compare == 0)
+ return (int)refIndex;
+ if (compare < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+}
+
+void CHandler::FillLinks()
+{
+ unsigned i;
+
+ for (i = 0; i < _refs.Size(); i++)
+ {
+ const CItem &item = _items[_refs[i].Item];
+ if (!item.IsDir() && !item.IsService() && item.NeedUse_as_CopyLink())
+ break;
+ }
+
+ if (i == _refs.Size())
+ return;
+
+ CUIntVector sorted;
+ for (i = 0; i < _refs.Size(); i++)
+ {
+ const CItem &item = _items[_refs[i].Item];
+ if (!item.IsDir() && !item.IsService())
+ sorted.Add(i);
+ }
+
+ if (sorted.IsEmpty())
+ return;
+
+ sorted.Sort(CompareItemsPaths_Sort, (void *)this);
+
+ AString link;
+
+ for (i = 0; i < _refs.Size(); i++)
+ {
+ CRefItem &ref = _refs[i];
+ const CItem &item = _items[ref.Item];
+ if (item.IsDir() || item.IsService() || item.PackSize != 0)
+ continue;
+ CLinkInfo linkInfo;
+ if (!item.FindExtra_Link(linkInfo) || linkInfo.Type != NLinkType::kFileCopy)
+ continue;
+ link.SetFrom_CalcLen((const char *)(item.Extra + linkInfo.NameOffset), linkInfo.NameLen);
+ int linkIndex = FindLink(*this, sorted, link, i);
+ if (linkIndex < 0)
+ continue;
+ if ((unsigned)linkIndex >= i)
+ continue; // we don't support forward links that can lead to loops
+ const CRefItem &linkRef = _refs[linkIndex];
+ const CItem &linkItem = _items[linkRef.Item];
+ if (linkItem.Size == item.Size)
+ {
+ if (linkRef.Link >= 0)
+ ref.Link = linkRef.Link;
+ else if (!linkItem.NeedUse_as_CopyLink())
+ ref.Link = linkIndex;
+ }
+ }
+}
+
+
+
+HRESULT CHandler::Open2(IInStream *stream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *openCallback)
+{
+ CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+
+ NRar::CVolumeName seqName;
+
+ UInt64 totalBytes = 0;
+ UInt64 curBytes = 0;
+
+ if (openCallback)
+ {
+ openCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
+ openCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
+ }
+
+ CTempBuf tempBuf;
+
+ CUnpacker unpacker;
+ unpacker.getTextPassword = getTextPassword;
+
+ int prevSplitFile = -1;
+ int prevMainFile = -1;
+
+ bool nextVol_is_Required = false;
+
+ CInArchive arch;
+
+ for (;;)
+ {
+ CMyComPtr<IInStream> inStream;
+
+ if (_arcs.IsEmpty())
+ inStream = stream;
+ else
+ {
+ if (!openVolumeCallback)
+ break;
+
+ if (_arcs.Size() == 1)
+ {
+ UString baseName;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(openVolumeCallback->GetProperty(kpidName, &prop))
+ if (prop.vt != VT_BSTR)
+ break;
+ baseName = prop.bstrVal;
+ }
+ if (!seqName.InitName(baseName))
+ break;
+ }
+
+ const UString volName = seqName.GetNextName();
+
+ HRESULT result = openVolumeCallback->GetStream(volName, &inStream);
+
+ if (result != S_OK && result != S_FALSE)
+ return result;
+
+ if (!inStream || result != S_OK)
+ {
+ if (nextVol_is_Required)
+ _missingVolName = volName;
+ break;
+ }
+ }
+
+ UInt64 endPos = 0;
+ RINOK(InStream_GetPos_GetSize(inStream, arch.StreamStartPosition, endPos))
+
+ if (openCallback)
+ {
+ totalBytes += endPos;
+ RINOK(openCallback->SetTotal(NULL, &totalBytes))
+ }
+
+ CInArcInfo arcInfoOpen;
+ {
+ HRESULT res = arch.Open(inStream, maxCheckStartPosition, getTextPassword, arcInfoOpen);
+ if (arch.IsArc && arch.UnexpectedEnd)
+ _errorFlags |= kpv_ErrorFlags_UnexpectedEnd;
+ if (_arcs.IsEmpty())
+ {
+ _isArc = arch.IsArc;
+ }
+
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ return res;
+ if (_arcs.IsEmpty())
+ return res;
+ break;
+ }
+ }
+
+ CArc &arc = _arcs.AddNew();
+ CInArcInfo &arcInfo = arc.Info;
+ arcInfo = arcInfoOpen;
+ arc.Stream = inStream;
+
+ CItem item;
+
+ for (;;)
+ {
+ item.Clear();
+
+ arcInfo.EndPos = arch.Position;
+
+ if (arch.Position > endPos)
+ {
+ _errorFlags |= kpv_ErrorFlags_UnexpectedEnd;
+ break;
+ }
+
+ RINOK(InStream_SeekSet(inStream, arch.Position))
+
+ {
+ CInArchive::CHeader h;
+ HRESULT res = arch.ReadBlockHeader(h);
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ return res;
+ if (arch.UnexpectedEnd)
+ {
+ _errorFlags |= kpv_ErrorFlags_UnexpectedEnd;
+ if (arcInfo.EndPos < arch.Position)
+ arcInfo.EndPos = arch.Position;
+ if (arcInfo.EndPos < endPos)
+ arcInfo.EndPos = endPos;
+ }
+ else
+ _errorFlags |= kpv_ErrorFlags_HeadersError;
+ break;
+ }
+
+ if (h.Type == NHeaderType::kEndOfArc)
+ {
+ arcInfo.EndPos = arch.Position;
+ arcInfo.EndOfArchive_was_Read = true;
+ if (!arch.ReadVar(arcInfo.EndFlags))
+ _errorFlags |= kpv_ErrorFlags_HeadersError;
+ if (arcInfo.IsVolume())
+ {
+ // for multivolume archives RAR can add ZERO bytes at the end for alignment.
+ // We must skip these bytes to prevent phySize warning.
+ RINOK(InStream_SeekSet(inStream, arcInfo.EndPos))
+ bool areThereNonZeros;
+ UInt64 numZeros;
+ const UInt64 maxSize = 1 << 12;
+ RINOK(ReadZeroTail(inStream, areThereNonZeros, numZeros, maxSize))
+ if (!areThereNonZeros && numZeros != 0 && numZeros <= maxSize)
+ arcInfo.EndPos += numZeros;
+ }
+ break;
+ }
+
+ if (h.Type != NHeaderType::kFile &&
+ h.Type != NHeaderType::kService)
+ {
+ _errorFlags |= kpv_ErrorFlags_UnsupportedFeature;
+ break;
+ }
+
+ item.RecordType = (Byte)h.Type;
+
+ if (!arch.ReadFileHeader(h, item))
+ {
+ _errorFlags |= kpv_ErrorFlags_HeadersError;
+ break;
+ }
+
+ // item.MainPartSize = (UInt32)(Position - item.Position);
+ item.DataPos = arch.Position;
+ }
+
+ bool isOk_packSize = true;
+ {
+ arcInfo.EndPos = arch.Position;
+ if (arch.Position + item.PackSize < arch.Position)
+ {
+ isOk_packSize = false;
+ _errorFlags |= kpv_ErrorFlags_HeadersError;
+ if (arcInfo.EndPos < endPos)
+ arcInfo.EndPos = endPos;
+ }
+ else
+ {
+ arch.AddToSeekValue(item.PackSize); // Position points to next header;
+ arcInfo.EndPos = arch.Position;
+ }
+ }
+
+ bool needAdd = true;
+
+ {
+ if (_comment.Size() == 0
+ && item.Is_CMT()
+ && item.PackSize < kCommentSize_Max
+ && item.PackSize == item.Size
+ && item.PackSize != 0
+ && item.GetMethod() == 0
+ && !item.IsSplit())
+ {
+ RINOK(unpacker.DecodeToBuf(EXTERNAL_CODECS_VARS item, item.PackSize, inStream, _comment))
+ needAdd = false;
+ }
+ }
+
+ if (needAdd)
+ {
+ CRefItem ref;
+ ref.Item = _items.Size();
+ ref.Last = ref.Item;
+ ref.Parent = -1;
+ ref.Link = -1;
+
+ if (item.IsService())
+ {
+ if (item.Is_STM())
+ {
+ if (prevMainFile >= 0)
+ ref.Parent = prevMainFile;
+ }
+ else
+ {
+ needAdd = false;
+ if (item.Is_ACL() && (!item.IsEncrypted() || arch.m_CryptoMode))
+ {
+ if (prevMainFile >= 0 && item.Size < (1 << 24) && item.Size != 0)
+ {
+ CItem &mainItem = _items[_refs[prevMainFile].Item];
+
+ if (mainItem.ACL < 0)
+ {
+ CByteBuffer acl;
+ HRESULT res = tempBuf.Decode(EXTERNAL_CODECS_VARS item, inStream, unpacker, acl);
+ if (!item.IsSplitAfter())
+ tempBuf.Clear();
+ if (res != S_OK)
+ {
+ tempBuf.Clear();
+ if (res != S_FALSE && res != E_NOTIMPL)
+ return res;
+ }
+ // RINOK();
+
+ if (res == S_OK && acl.Size() != 0)
+ {
+ if (_acls.IsEmpty() || acl != _acls.Back())
+ _acls.Add(acl);
+ mainItem.ACL = (int)_acls.Size() - 1;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (needAdd)
+ {
+ if (item.IsSplitBefore())
+ {
+ if (prevSplitFile >= 0)
+ {
+ CRefItem &ref2 = _refs[prevSplitFile];
+ CItem &prevItem = _items[ref2.Last];
+ if (item.IsNextForItem(prevItem))
+ {
+ ref2.Last = _items.Size();
+ prevItem.NextItem = (int)ref2.Last;
+ needAdd = false;
+ }
+ }
+ }
+ }
+
+ if (needAdd)
+ {
+ if (item.IsSplitAfter())
+ prevSplitFile = (int)_refs.Size();
+ if (!item.IsService())
+ prevMainFile = (int)_refs.Size();
+ _refs.Add(ref);
+ }
+ }
+
+ {
+ UInt64 version;
+ if (item.FindExtra_Version(version))
+ {
+ item.Version_Defined = true;
+ item.Version = version;
+ }
+ }
+
+ item.VolIndex = _arcs.Size() - 1;
+ _items.Add(item);
+
+ if (openCallback && (_items.Size() & 0xFF) == 0)
+ {
+ UInt64 numFiles = _items.Size();
+ UInt64 numBytes = curBytes + item.DataPos;
+ RINOK(openCallback->SetCompleted(&numFiles, &numBytes))
+ }
+
+ if (!isOk_packSize)
+ break;
+ }
+
+ curBytes += endPos;
+
+ nextVol_is_Required = false;
+
+ if (!arcInfo.IsVolume())
+ break;
+
+ if (arcInfo.EndOfArchive_was_Read)
+ {
+ if (!arcInfo.AreMoreVolumes())
+ break;
+ nextVol_is_Required = true;
+ }
+ }
+
+ FillLinks();
+
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *openCallback))
+{
+ COM_TRY_BEGIN
+ Close();
+ return Open2(stream, maxCheckStartPosition, openCallback);
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ COM_TRY_BEGIN
+ _missingVolName.Empty();
+ _errorFlags = 0;
+ // _warningFlags = 0;
+ _isArc = false;
+ _refs.Clear();
+ _items.Clear();
+ _arcs.Clear();
+ _acls.Clear();
+ _comment.Free();
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ CVolsInStream
+ , ISequentialInStream
+)
+ UInt64 _rem;
+ ISequentialInStream *_stream;
+ const CObjectVector<CArc> *_arcs;
+ const CObjectVector<CItem> *_items;
+ int _itemIndex;
+public:
+ bool CrcIsOK;
+private:
+ CHash _hash;
+public:
+ void Init(const CObjectVector<CArc> *arcs,
+ const CObjectVector<CItem> *items,
+ unsigned itemIndex)
+ {
+ _arcs = arcs;
+ _items = items;
+ _itemIndex = (int)itemIndex;
+ _stream = NULL;
+ CrcIsOK = true;
+ }
+};
+
+Z7_COM7F_IMF(CVolsInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ UInt32 realProcessedSize = 0;
+
+ while (size != 0)
+ {
+ if (!_stream)
+ {
+ if (_itemIndex < 0)
+ break;
+ const CItem &item = (*_items)[_itemIndex];
+ IInStream *s = (*_arcs)[item.VolIndex].Stream;
+ RINOK(InStream_SeekSet(s, item.GetDataPosition()))
+ _stream = s;
+ if (CrcIsOK && item.IsSplitAfter())
+ _hash.Init(item);
+ else
+ _hash.Init_NoCalc();
+ _rem = item.PackSize;
+ }
+ {
+ UInt32 cur = size;
+ if (cur > _rem)
+ cur = (UInt32)_rem;
+ UInt32 num = cur;
+ HRESULT res = _stream->Read(data, cur, &cur);
+ _hash.Update(data, cur);
+ realProcessedSize += cur;
+ if (processedSize)
+ *processedSize = realProcessedSize;
+ data = (Byte *)data + cur;
+ size -= cur;
+ _rem -= cur;
+ if (_rem == 0)
+ {
+ const CItem &item = (*_items)[_itemIndex];
+ _itemIndex = item.NextItem;
+ if (!_hash.Check(item, NULL)) // RAR doesn't use MAC here
+ CrcIsOK = false;
+ _stream = NULL;
+ }
+ if (res != S_OK)
+ return res;
+ if (realProcessedSize != 0)
+ return S_OK;
+ if (cur == 0 && num != 0)
+ return S_OK;
+ }
+ }
+
+ return S_OK;
+}
+
+
+static int FindLinkBuf(CObjectVector<CLinkFile> &linkFiles, unsigned index)
+{
+ unsigned left = 0, right = linkFiles.Size();
+ for (;;)
+ {
+ if (left == right)
+ return -1;
+ const unsigned mid = (left + right) / 2;
+ const unsigned linkIndex = linkFiles[mid].Index;
+ if (index == linkIndex)
+ return (int)mid;
+ if (index < linkIndex)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+}
+
+
+static inline int DecoderRes_to_OpRes(HRESULT res, bool crcOK)
+{
+ if (res == E_NOTIMPL)
+ return NExtract::NOperationResult::kUnsupportedMethod;
+ // if (res == S_FALSE)
+ if (res != S_OK)
+ return NExtract::NOperationResult::kDataError;
+ return crcOK ?
+ NExtract::NOperationResult::kOK :
+ NExtract::NOperationResult::kCRCError;
+}
+
+
+static HRESULT CopyData_with_Progress(const Byte *data, size_t size,
+ ISequentialOutStream *outStream, ICompressProgressInfo *progress)
+{
+ size_t pos = 0;
+
+ while (pos < size)
+ {
+ const UInt32 kStepSize = ((UInt32)1 << 24);
+ UInt32 cur32;
+ {
+ size_t cur = size - pos;
+ if (cur > kStepSize)
+ cur = kStepSize;
+ cur32 = (UInt32)cur;
+ }
+ RINOK(outStream->Write(data + pos, cur32, &cur32))
+ if (cur32 == 0)
+ return E_FAIL;
+ pos += cur32;
+ if (progress)
+ {
+ UInt64 pos64 = pos;
+ RINOK(progress->SetRatioInfo(&pos64, &pos64))
+ }
+ }
+
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _refs.Size();
+ if (numItems == 0)
+ return S_OK;
+
+ CByteArr extractStatuses(_refs.Size());
+ memset(extractStatuses, 0, _refs.Size());
+
+ // we don't want to use temp buffer for big link files.
+ const size_t k_CopyLinkFile_MaxSize = (size_t)1 << (28 + sizeof(size_t) / 2);
+
+ const Byte kStatus_Extract = 1 << 0;
+ const Byte kStatus_Skip = 1 << 1;
+ const Byte kStatus_Link = 1 << 2;
+
+ /*
+ In original RAR:
+ 1) service streams are not allowed to be solid,
+ and solid flag must be ignored for service streams.
+ 2) If RAR creates new solid block and first file in solid block is Link file,
+ then it can clear solid flag for Link file and
+ clear solid flag for first non-Link file after Link file.
+ */
+
+ CObjectVector<CLinkFile> linkFiles;
+
+ {
+ UInt64 total = 0;
+ bool isThereUndefinedSize = false;
+ bool thereAreLinks = false;
+
+ {
+ unsigned solidLimit = 0;
+ for (UInt32 t = 0; t < numItems; t++)
+ {
+ unsigned index = allFilesMode ? t : indices[t];
+ const CRefItem &ref = _refs[index];
+ const CItem &item = _items[ref.Item];
+ const CItem &lastItem = _items[ref.Last];
+
+ extractStatuses[index] |= kStatus_Extract;
+
+ if (!lastItem.Is_UnknownSize())
+ total += lastItem.Size;
+ else
+ isThereUndefinedSize = true;
+
+ if (ref.Link >= 0)
+ {
+ // 18.06 fixed: we use links for Test mode too
+ // if (!testMode)
+ {
+ if ((unsigned)ref.Link < index)
+ {
+ const CRefItem &linkRef = _refs[(unsigned)ref.Link];
+ const CItem &linkItem = _items[linkRef.Item];
+ if (linkItem.IsSolid())
+ if (testMode || linkItem.Size <= k_CopyLinkFile_MaxSize)
+ {
+ if (extractStatuses[(unsigned)ref.Link] == 0)
+ {
+ const CItem &lastLinkItem = _items[linkRef.Last];
+ if (!lastLinkItem.Is_UnknownSize())
+ total += lastLinkItem.Size;
+ else
+ isThereUndefinedSize = true;
+ }
+ extractStatuses[(unsigned)ref.Link] |= kStatus_Link;
+ thereAreLinks = true;
+ }
+ }
+ }
+ continue;
+ }
+
+ if (item.IsService())
+ continue;
+
+ if (item.IsSolid())
+ {
+ unsigned j = index;
+
+ while (j > solidLimit)
+ {
+ j--;
+ const CRefItem &ref2 = _refs[j];
+ const CItem &item2 = _items[ref2.Item];
+ if (!item2.IsService())
+ {
+ if (extractStatuses[j] == 0)
+ {
+ const CItem &lastItem2 = _items[ref2.Last];
+ if (!lastItem2.Is_UnknownSize())
+ total += lastItem2.Size;
+ else
+ isThereUndefinedSize = true;
+ }
+ extractStatuses[j] |= kStatus_Skip;
+ if (!item2.IsSolid())
+ break;
+ }
+ }
+ }
+
+ solidLimit = index + 1;
+ }
+ }
+
+ if (thereAreLinks)
+ {
+ unsigned solidLimit = 0;
+
+ FOR_VECTOR (i, _refs)
+ {
+ if ((extractStatuses[i] & kStatus_Link) == 0)
+ continue;
+
+ // We use CLinkFile for testMode too.
+ // So we can show errors for copy files.
+ // if (!testMode)
+ {
+ CLinkFile &linkFile = linkFiles.AddNew();
+ linkFile.Index = i;
+ }
+
+ const CItem &item = _items[_refs[i].Item];
+ /*
+ if (item.IsService())
+ continue;
+ */
+
+ if (item.IsSolid())
+ {
+ unsigned j = i;
+
+ while (j > solidLimit)
+ {
+ j--;
+ const CRefItem &ref2 = _refs[j];
+ const CItem &item2 = _items[ref2.Item];
+ if (!item2.IsService())
+ {
+ if (extractStatuses[j] != 0)
+ break;
+ extractStatuses[j] = kStatus_Skip;
+ {
+ const CItem &lastItem2 = _items[ref2.Last];
+ if (!lastItem2.Is_UnknownSize())
+ total += lastItem2.Size;
+ else
+ isThereUndefinedSize = true;
+ }
+ if (!item2.IsSolid())
+ break;
+ }
+ }
+ }
+
+ solidLimit = i + 1;
+ }
+
+ if (!testMode)
+ for (UInt32 t = 0; t < numItems; t++)
+ {
+ unsigned index = allFilesMode ? t : indices[t];
+ const CRefItem &ref = _refs[index];
+
+ int linkIndex = ref.Link;
+ if (linkIndex < 0 || (unsigned)linkIndex >= index)
+ continue;
+ const CItem &linkItem = _items[_refs[(unsigned)linkIndex].Item];
+ if (!linkItem.IsSolid() || linkItem.Size > k_CopyLinkFile_MaxSize)
+ continue;
+ const int bufIndex = FindLinkBuf(linkFiles, (unsigned)linkIndex);
+ if (bufIndex < 0)
+ return E_FAIL;
+ linkFiles[bufIndex].NumLinks++;
+ }
+ }
+
+ if (total != 0 || !isThereUndefinedSize)
+ {
+ RINOK(extractCallback->SetTotal(total))
+ }
+ }
+
+
+ UInt64 totalUnpacked = 0;
+ UInt64 totalPacked = 0;
+ UInt64 curUnpackSize = 0;
+ UInt64 curPackSize = 0;
+
+ CUnpacker unpacker;
+
+ CVolsInStream *volsInStreamSpec = new CVolsInStream;
+ CMyComPtr<ISequentialInStream> volsInStream = volsInStreamSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ // bool needClearSolid = true;
+
+ FOR_VECTOR (i, _refs)
+ {
+ if (extractStatuses[i] == 0)
+ continue;
+
+ totalUnpacked += curUnpackSize;
+ totalPacked += curPackSize;
+ lps->InSize = totalPacked;
+ lps->OutSize = totalUnpacked;
+ RINOK(lps->SetCur())
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+
+ // isExtract means that we don't skip that item. So we need read data.
+
+ bool isExtract = ((extractStatuses[i] & kStatus_Extract) != 0);
+ Int32 askMode =
+ isExtract ? (testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract) :
+ NExtract::NAskMode::kSkip;
+
+ unpacker.linkFile = NULL;
+
+ // if (!testMode)
+ if ((extractStatuses[i] & kStatus_Link) != 0)
+ {
+ int bufIndex = FindLinkBuf(linkFiles, i);
+ if (bufIndex < 0)
+ return E_FAIL;
+ unpacker.linkFile = &linkFiles[bufIndex];
+ }
+
+ UInt32 index = i;
+
+ const CRefItem *ref = &_refs[index];
+ const CItem *item = &_items[ref->Item];
+ const CItem &lastItem = _items[ref->Last];
+
+ curUnpackSize = 0;
+ if (!lastItem.Is_UnknownSize())
+ curUnpackSize = lastItem.Size;
+
+ curPackSize = GetPackSize(index);
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+ bool isSolid = false;
+ if (!item->IsService())
+ {
+ if (item->IsSolid())
+ isSolid = unpacker.SolidAllowed;
+ unpacker.SolidAllowed = isSolid;
+ }
+
+ if (item->IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+
+ int index2 = ref->Link;
+
+ int bufIndex = -1;
+
+ if (index2 >= 0)
+ {
+ const CRefItem &ref2 = _refs[index2];
+ const CItem &item2 = _items[ref2.Item];
+ const CItem &lastItem2 = _items[ref2.Last];
+ if (!item2.IsSolid())
+ {
+ item = &item2;
+ ref = &ref2;
+ if (!lastItem2.Is_UnknownSize())
+ curUnpackSize = lastItem2.Size;
+ else
+ curUnpackSize = 0;
+ curPackSize = GetPackSize((unsigned)index2);
+ }
+ else
+ {
+ if ((unsigned)index2 < index)
+ bufIndex = FindLinkBuf(linkFiles, (unsigned)index2);
+ }
+ }
+
+ bool needCallback = true;
+
+ if (!realOutStream)
+ {
+ if (testMode)
+ {
+ if (item->NeedUse_as_CopyLink_or_HardLink())
+ {
+ Int32 opRes = NExtract::NOperationResult::kOK;
+ if (bufIndex >= 0)
+ {
+ const CLinkFile &linkFile = linkFiles[bufIndex];
+ opRes = DecoderRes_to_OpRes(linkFile.Res, linkFile.crcOK);
+ }
+
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(opRes))
+ continue;
+ }
+ }
+ else
+ {
+ if (item->IsService())
+ continue;
+
+ needCallback = false;
+
+ if (!item->NeedUse_as_HardLink())
+ if (index2 < 0)
+
+ for (unsigned n = i + 1; n < _refs.Size(); n++)
+ {
+ const CItem &nextItem = _items[_refs[n].Item];
+ if (nextItem.IsService())
+ continue;
+ if (!nextItem.IsSolid())
+ break;
+ if (extractStatuses[i] != 0)
+ {
+ needCallback = true;
+ break;
+ }
+ }
+
+ askMode = NExtract::NAskMode::kSkip;
+ }
+ }
+
+ if (needCallback)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ }
+
+ if (bufIndex >= 0)
+ {
+ CLinkFile &linkFile = linkFiles[bufIndex];
+
+ if (isExtract)
+ {
+ if (linkFile.NumLinks == 0)
+ return E_FAIL;
+
+ if (needCallback)
+ if (realOutStream)
+ {
+ RINOK(CopyData_with_Progress(linkFile.Data, linkFile.Data.Size(), realOutStream, progress))
+ }
+
+ if (--linkFile.NumLinks == 0)
+ linkFile.Data.Free();
+ }
+
+ if (needCallback)
+ {
+ RINOK(extractCallback->SetOperationResult(DecoderRes_to_OpRes(linkFile.Res, linkFile.crcOK)))
+ }
+ continue;
+ }
+
+ if (!needCallback)
+ continue;
+
+ if (item->NeedUse_as_CopyLink())
+ {
+ int opRes = realOutStream ?
+ NExtract::NOperationResult::kUnsupportedMethod:
+ NExtract::NOperationResult::kOK;
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes))
+ continue;
+ }
+
+ volsInStreamSpec->Init(&_arcs, &_items, ref->Item);
+
+ UInt64 packSize = curPackSize;
+
+ if (item->IsEncrypted())
+ if (!unpacker.getTextPassword)
+ extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&unpacker.getTextPassword);
+
+ bool wrongPassword;
+ HRESULT result = unpacker.Create(EXTERNAL_CODECS_VARS *item, isSolid, wrongPassword);
+
+ if (wrongPassword)
+ {
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kWrongPassword))
+ continue;
+ }
+
+ bool crcOK = true;
+ if (result == S_OK)
+ result = unpacker.Code(*item, _items[ref->Last], packSize, volsInStream, realOutStream, progress, crcOK);
+ realOutStream.Release();
+ if (!volsInStreamSpec->CrcIsOK)
+ crcOK = false;
+
+ int opRes = crcOK ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kCRCError;
+
+ if (result != S_OK)
+ {
+ if (result == S_FALSE)
+ opRes = NExtract::NOperationResult::kDataError;
+ else if (result == E_NOTIMPL)
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ else
+ return result;
+ }
+
+ RINOK(extractCallback->SetOperationResult(opRes))
+ }
+
+ {
+ FOR_VECTOR (i, linkFiles)
+ if (linkFiles[i].NumLinks != 0)
+ return E_FAIL;
+ }
+
+ return S_OK;
+
+ COM_TRY_END
+}
+
+
+IMPL_ISetCompressCodecsInfo
+
+REGISTER_ARC_I(
+ "Rar5", "rar r00", NULL, 0xCC,
+ kMarker,
+ 0,
+ NArcInfoFlags::kFindSignature,
+ NULL)
+
+}}
+
+
+Z7_CLASS_IMP_COM_1(
+ CBlake2spHasher
+ , IHasher
+)
+ CBlake2sp _blake;
+public:
+ Byte _mtDummy[1 << 7]; // it's public to eliminate clang warning: unused private field
+ CBlake2spHasher() { Init(); }
+};
+
+Z7_COM7F_IMF2(void, CBlake2spHasher::Init())
+{
+ Blake2sp_Init(&_blake);
+}
+
+Z7_COM7F_IMF2(void, CBlake2spHasher::Update(const void *data, UInt32 size))
+{
+ Blake2sp_Update(&_blake, (const Byte *)data, size);
+}
+
+Z7_COM7F_IMF2(void, CBlake2spHasher::Final(Byte *digest))
+{
+ Blake2sp_Final(&_blake, digest);
+}
+
+REGISTER_HASHER(CBlake2spHasher, 0x202, "BLAKE2sp", BLAKE2S_DIGEST_SIZE)
diff --git a/CPP/7zip/Archive/Rar/Rar5Handler.h b/CPP/7zip/Archive/Rar/Rar5Handler.h
new file mode 100644
index 0000000..72e1efc
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/Rar5Handler.h
@@ -0,0 +1,419 @@
+// Rar5Handler.h
+
+#ifndef ZIP7_INC_RAR5_HANDLER_H
+#define ZIP7_INC_RAR5_HANDLER_H
+
+#include "../../../../C/Blake2.h"
+
+#include "../../../Common/MyBuffer.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#include "../../Common/CreateCoder.h"
+
+#include "../IArchive.h"
+
+namespace NArchive {
+namespace NRar5 {
+
+namespace NHeaderFlags
+{
+ const unsigned kExtra = 1 << 0;
+ const unsigned kData = 1 << 1;
+ // const unsigned kUnknown = 1 << 2;
+ const unsigned kPrevVol = 1 << 3;
+ const unsigned kNextVol = 1 << 4;
+ // const unsigned kIsChild = 1 << 5;
+ // const unsigned kPreserveChild = 1 << 6;
+}
+
+namespace NHeaderType
+{
+ enum
+ {
+ kArc = 1,
+ kFile,
+ kService,
+ kArcEncrypt,
+ kEndOfArc
+ };
+}
+
+namespace NArcFlags
+{
+ const unsigned kVol = 1 << 0;
+ const unsigned kVolNumber = 1 << 1;
+ const unsigned kSolid = 1 << 2;
+ // const unsigned kRecovery = 1 << 3;
+ // const unsigned kLocked = 1 << 4;
+}
+
+const unsigned kArcExtraRecordType_Locator = 1;
+
+namespace NLocatorFlags
+{
+ const unsigned kQuickOpen = 1 << 0;
+ const unsigned kRecovery = 1 << 1;
+}
+
+namespace NFileFlags
+{
+ const unsigned kIsDir = 1 << 0;
+ const unsigned kUnixTime = 1 << 1;
+ const unsigned kCrc32 = 1 << 2;
+ const unsigned kUnknownSize = 1 << 3;
+}
+
+namespace NMethodFlags
+{
+ // const unsigned kVersionMask = 0x3F;
+ const unsigned kSolid = 1 << 6;
+}
+
+namespace NArcEndFlags
+{
+ const unsigned kMoreVols = 1 << 0;
+}
+
+enum EHostOS
+{
+ kHost_Windows = 0,
+ kHost_Unix
+};
+
+
+
+// ---------- Extra ----------
+
+namespace NExtraID
+{
+ enum
+ {
+ kCrypto = 1,
+ kHash,
+ kTime,
+ kVersion,
+ kLink,
+ kUnixOwner,
+ kSubdata
+ };
+}
+
+const unsigned kCryptoAlgo_AES = 0;
+
+namespace NCryptoFlags
+{
+ const unsigned kPswCheck = 1 << 0;
+ const unsigned kUseMAC = 1 << 1;
+}
+
+struct CCryptoInfo
+{
+ UInt64 Algo;
+ UInt64 Flags;
+ Byte Cnt;
+
+ bool UseMAC() const { return (Flags & NCryptoFlags::kUseMAC) != 0; }
+ bool IsThereCheck() const { return (Flags & NCryptoFlags::kPswCheck) != 0; }
+ bool Parse(const Byte *p, size_t size);
+};
+
+const unsigned kHashID_Blake2sp = 0;
+
+namespace NTimeRecord
+{
+ enum
+ {
+ k_Index_MTime = 0,
+ k_Index_CTime,
+ k_Index_ATime
+ };
+
+ namespace NFlags
+ {
+ const unsigned kUnixTime = 1 << 0;
+ const unsigned kMTime = 1 << 1;
+ const unsigned kCTime = 1 << 2;
+ const unsigned kATime = 1 << 3;
+ const unsigned kUnixNs = 1 << 4;
+ }
+}
+
+namespace NLinkType
+{
+ enum
+ {
+ kUnixSymLink = 1,
+ kWinSymLink,
+ kWinJunction,
+ kHardLink,
+ kFileCopy
+ };
+}
+
+namespace NLinkFlags
+{
+ const unsigned kTargetIsDir = 1 << 0;
+}
+
+
+struct CLinkInfo
+{
+ UInt64 Type;
+ UInt64 Flags;
+ unsigned NameOffset;
+ unsigned NameLen;
+
+ bool Parse(const Byte *p, unsigned size);
+};
+
+
+struct CItem
+{
+ UInt32 CommonFlags;
+ UInt32 Flags;
+
+ Byte RecordType;
+ bool Version_Defined;
+
+ int ACL;
+
+ AString Name;
+
+ unsigned VolIndex;
+ int NextItem;
+
+ UInt32 UnixMTime;
+ UInt32 CRC;
+ UInt32 Attrib;
+ UInt32 Method;
+
+ CByteBuffer Extra;
+
+ UInt64 Size;
+ UInt64 PackSize;
+ UInt64 HostOS;
+
+ UInt64 DataPos;
+ UInt64 Version;
+
+ CItem() { Clear(); }
+
+ void Clear()
+ {
+ CommonFlags = 0;
+ Flags = 0;
+
+ VolIndex = 0;
+ NextItem = -1;
+
+ Version_Defined = false;
+ Version = 0;
+
+ Name.Empty();
+ Extra.Free();
+ ACL = -1;
+ }
+
+ bool IsSplitBefore() const { return (CommonFlags & NHeaderFlags::kPrevVol) != 0; }
+ bool IsSplitAfter() const { return (CommonFlags & NHeaderFlags::kNextVol) != 0; }
+ bool IsSplit() const { return (CommonFlags & (NHeaderFlags::kPrevVol | NHeaderFlags::kNextVol)) != 0; }
+
+ bool IsDir() const { return (Flags & NFileFlags::kIsDir) != 0; }
+ bool Has_UnixMTime() const { return (Flags & NFileFlags::kUnixTime) != 0; }
+ bool Has_CRC() const { return (Flags & NFileFlags::kCrc32) != 0; }
+ bool Is_UnknownSize() const { return (Flags & NFileFlags::kUnknownSize) != 0; }
+
+ bool IsNextForItem(const CItem &prev) const
+ {
+ return !IsDir() && !prev.IsDir() && IsSplitBefore() && prev.IsSplitAfter() && (Name == prev.Name);
+ // && false;
+ }
+
+ bool IsSolid() const { return ((UInt32)Method & NMethodFlags::kSolid) != 0; }
+ unsigned GetAlgoVersion() const { return (unsigned)Method & 0x3F; }
+ unsigned GetMethod() const { return ((unsigned)Method >> 7) & 0x7; }
+ UInt32 GetDictSize() const { return (((UInt32)Method >> 10) & 0xF); }
+
+ bool IsService() const { return RecordType == NHeaderType::kService; }
+
+ bool Is_STM() const { return IsService() && Name == "STM"; }
+ bool Is_CMT() const { return IsService() && Name == "CMT"; }
+ bool Is_ACL() const { return IsService() && Name == "ACL"; }
+ // bool Is_QO() const { return IsService() && Name == "QO"; }
+
+ int FindExtra(unsigned extraID, unsigned &recordDataSize) const;
+ void PrintInfo(AString &s) const;
+
+
+ bool IsEncrypted() const
+ {
+ unsigned size;
+ return FindExtra(NExtraID::kCrypto, size) >= 0;
+ }
+
+ int FindExtra_Blake() const
+ {
+ unsigned size = 0;
+ int offset = FindExtra(NExtraID::kHash, size);
+ if (offset >= 0
+ && size == BLAKE2S_DIGEST_SIZE + 1
+ && Extra[(unsigned)offset] == kHashID_Blake2sp)
+ return offset + 1;
+ return -1;
+ }
+
+ bool FindExtra_Version(UInt64 &version) const;
+
+ bool FindExtra_Link(CLinkInfo &link) const;
+ void Link_to_Prop(unsigned linkType, NWindows::NCOM::CPropVariant &prop) const;
+ bool Is_CopyLink() const;
+ bool Is_HardLink() const;
+ bool Is_CopyLink_or_HardLink() const;
+
+ bool NeedUse_as_CopyLink() const { return PackSize == 0 && Is_CopyLink(); }
+ bool NeedUse_as_HardLink() const { return PackSize == 0 && Is_HardLink(); }
+ bool NeedUse_as_CopyLink_or_HardLink() const { return PackSize == 0 && Is_CopyLink_or_HardLink(); }
+
+ bool GetAltStreamName(AString &name) const;
+
+ UInt32 GetWinAttrib() const
+ {
+ UInt32 a;
+ switch (HostOS)
+ {
+ case kHost_Windows: a = Attrib; break;
+ case kHost_Unix: a = (Attrib << 16); break;
+ default: a = 0;
+ }
+ // if (IsDir()) a |= FILE_ATTRIBUTE_DIRECTORY;
+ return a;
+ }
+
+ UInt64 GetDataPosition() const { return DataPos; }
+};
+
+
+struct CInArcInfo
+{
+ UInt64 Flags;
+ UInt64 VolNumber;
+ UInt64 StartPos;
+ UInt64 EndPos;
+
+ UInt64 EndFlags;
+ bool EndOfArchive_was_Read;
+
+ bool IsEncrypted;
+
+ // CByteBuffer Extra;
+
+ /*
+ struct CLocator
+ {
+ UInt64 Flags;
+ UInt64 QuickOpen;
+ UInt64 Recovery;
+
+ bool Is_QuickOpen() const { return (Flags & NLocatorFlags::kQuickOpen) != 0; }
+ bool Is_Recovery() const { return (Flags & NLocatorFlags::kRecovery) != 0; }
+ };
+
+ int FindExtra(unsigned extraID, unsigned &recordDataSize) const;
+ bool FindExtra_Locator(CLocator &locator) const;
+ */
+
+ CInArcInfo():
+ Flags(0),
+ VolNumber(0),
+ StartPos(0),
+ EndPos(0),
+ EndFlags(0),
+ EndOfArchive_was_Read(false),
+ IsEncrypted(false)
+ {}
+
+ /*
+ void Clear()
+ {
+ Flags = 0;
+ VolNumber = 0;
+ StartPos = 0;
+ EndPos = 0;
+ EndFlags = 0;
+ EndOfArchive_was_Read = false;
+ Extra.Free();
+ }
+ */
+
+ UInt64 GetPhySize() const { return EndPos - StartPos; }
+
+ bool AreMoreVolumes() const { return (EndFlags & NArcEndFlags::kMoreVols) != 0; }
+
+ bool IsVolume() const { return (Flags & NArcFlags::kVol) != 0; }
+ bool IsSolid() const { return (Flags & NArcFlags::kSolid) != 0; }
+ bool Is_VolNumber_Defined() const { return (Flags & NArcFlags::kVolNumber) != 0; }
+
+ UInt64 GetVolIndex() const { return Is_VolNumber_Defined() ? VolNumber : 0; }
+};
+
+
+struct CRefItem
+{
+ unsigned Item;
+ unsigned Last;
+ int Parent;
+ int Link;
+};
+
+
+struct CArc
+{
+ CMyComPtr<IInStream> Stream;
+ CInArcInfo Info;
+};
+
+
+class CHandler Z7_final:
+ public IInArchive,
+ public IArchiveGetRawProps,
+ Z7_PUBLIC_ISetCompressCodecsInfo_IFEC
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(IInArchive)
+ Z7_COM_QI_ENTRY(IArchiveGetRawProps)
+ Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(IInArchive)
+ Z7_IFACE_COM7_IMP(IArchiveGetRawProps)
+ DECL_ISetCompressCodecsInfo
+
+public:
+ CRecordVector<CRefItem> _refs;
+ CObjectVector<CItem> _items;
+private:
+ CObjectVector<CArc> _arcs;
+ CObjectVector<CByteBuffer> _acls;
+
+ UInt32 _errorFlags;
+ // UInt32 _warningFlags;
+ bool _isArc;
+ CByteBuffer _comment;
+ UString _missingVolName;
+
+ DECL_EXTERNAL_CODECS_VARS
+
+ UInt64 GetPackSize(unsigned refIndex) const;
+
+ void FillLinks();
+
+ HRESULT Open2(IInStream *stream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *openCallback);
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Rar/RarHandler.cpp b/CPP/7zip/Archive/Rar/RarHandler.cpp
new file mode 100644
index 0000000..9157acc
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/RarHandler.cpp
@@ -0,0 +1,1782 @@
+// RarHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/MyBuffer2.h"
+#include "../../../Common/UTFConvert.h"
+
+#include "../../../Windows/PropVariantUtils.h"
+#include "../../../Windows/TimeUtils.h"
+
+#include "../../IPassword.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/FilterCoder.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/MethodId.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/RegisterArc.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../../Crypto/Rar20Crypto.h"
+#include "../../Crypto/RarAes.h"
+
+#include "../Common/FindSignature.h"
+#include "../Common/ItemNameUtils.h"
+#include "../Common/OutStreamWithCRC.h"
+
+#include "../HandlerCont.h"
+
+#include "RarVol.h"
+#include "RarHandler.h"
+
+using namespace NWindows;
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
+namespace NArchive {
+namespace NRar {
+
+static const Byte kMarker[NHeader::kMarkerSize] =
+ { 0x52, 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 };
+
+const unsigned kPasswordLen_MAX = 127;
+
+bool CItem::IgnoreItem() const
+{
+ switch (HostOS)
+ {
+ case NHeader::NFile::kHostMSDOS:
+ case NHeader::NFile::kHostOS2:
+ case NHeader::NFile::kHostWin32:
+ return ((Attrib & NHeader::NFile::kLabelFileAttribute) != 0);
+ }
+ return false;
+}
+
+bool CItem::IsDir() const
+{
+ if (GetDictSize() == NHeader::NFile::kDictDirectoryValue)
+ return true;
+ switch (HostOS)
+ {
+ case NHeader::NFile::kHostMSDOS:
+ case NHeader::NFile::kHostOS2:
+ case NHeader::NFile::kHostWin32:
+ if ((Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ return true;
+ }
+ return false;
+}
+
+UInt32 CItem::GetWinAttrib() const
+{
+ UInt32 a;
+ switch (HostOS)
+ {
+ case NHeader::NFile::kHostMSDOS:
+ case NHeader::NFile::kHostOS2:
+ case NHeader::NFile::kHostWin32:
+ a = Attrib;
+ break;
+ default:
+ a = 0; // must be converted from unix value;
+ }
+ if (IsDir())
+ a |= NHeader::NFile::kWinFileDirectoryAttributeMask;
+ return a;
+}
+
+static const char * const kHostOS[] =
+{
+ "MS DOS"
+ , "OS/2"
+ , "Win32"
+ , "Unix"
+ , "Mac OS"
+ , "BeOS"
+};
+
+static const char * const k_Flags[] =
+{
+ "Volume"
+ , "Comment"
+ , "Lock"
+ , "Solid"
+ , "NewVolName" // pack_comment in old versuons
+ , "Authenticity"
+ , "Recovery"
+ , "BlockEncryption"
+ , "FirstVolume"
+ , "EncryptVer" // 9
+};
+
+enum EErrorType
+{
+ k_ErrorType_OK,
+ k_ErrorType_Corrupted,
+ k_ErrorType_UnexpectedEnd,
+ k_ErrorType_DecryptionError
+};
+
+class CInArchive
+{
+ IInStream *m_Stream;
+ UInt64 m_StreamStartPosition;
+ UString _unicodeNameBuffer;
+ CByteBuffer _comment;
+ CByteBuffer m_FileHeaderData;
+ NHeader::NBlock::CBlock m_BlockHeader;
+ NCrypto::NRar3::CDecoder *m_RarAESSpec;
+ CMyComPtr<ICompressFilter> m_RarAES;
+ CAlignedBuffer m_DecryptedDataAligned;
+ UInt32 m_DecryptedDataSize;
+ bool m_CryptoMode;
+ UInt32 m_CryptoPos;
+
+
+ HRESULT ReadBytesSpec(void *data, size_t *size);
+ bool ReadBytesAndTestSize(void *data, UInt32 size);
+ void ReadName(const Byte *p, unsigned nameSize, CItem &item);
+ bool ReadHeaderReal(const Byte *p, unsigned size, CItem &item);
+
+ HRESULT Open2(IInStream *stream, const UInt64 *searchHeaderSizeLimit);
+
+ void AddToSeekValue(UInt64 addValue)
+ {
+ m_Position += addValue;
+ }
+
+ void FinishCryptoBlock()
+ {
+ if (m_CryptoMode)
+ while ((m_CryptoPos & 0xF) != 0)
+ {
+ m_CryptoPos++;
+ m_Position++;
+ }
+ }
+
+public:
+ UInt64 m_Position;
+ CInArcInfo ArcInfo;
+ bool HeaderErrorWarning;
+
+ HRESULT Open(IInStream *inStream, const UInt64 *searchHeaderSizeLimit);
+ HRESULT GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPassword,
+ bool &filled, EErrorType &error);
+};
+
+static bool CheckHeaderCrc(const Byte *header, size_t headerSize)
+{
+ return Get16(header) == (UInt16)(CrcCalc(header + 2, headerSize - 2) & 0xFFFF);
+}
+
+HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchHeaderSizeLimit)
+{
+ HeaderErrorWarning = false;
+ m_CryptoMode = false;
+ RINOK(InStream_GetPos_GetSize(stream, m_StreamStartPosition, ArcInfo.FileSize))
+ m_Position = m_StreamStartPosition;
+
+ UInt64 arcStartPos = m_StreamStartPosition;
+ {
+ Byte marker[NHeader::kMarkerSize];
+ RINOK(ReadStream_FALSE(stream, marker, NHeader::kMarkerSize))
+ if (memcmp(marker, kMarker, NHeader::kMarkerSize) == 0)
+ m_Position += NHeader::kMarkerSize;
+ else
+ {
+ if (searchHeaderSizeLimit && *searchHeaderSizeLimit == 0)
+ return S_FALSE;
+ RINOK(InStream_SeekSet(stream, m_StreamStartPosition))
+ RINOK(FindSignatureInStream(stream, kMarker, NHeader::kMarkerSize,
+ searchHeaderSizeLimit, arcStartPos))
+ m_Position = arcStartPos + NHeader::kMarkerSize;
+ RINOK(InStream_SeekSet(stream, m_Position))
+ }
+ }
+ Byte buf[NHeader::NArchive::kArchiveHeaderSize + 1];
+
+ RINOK(ReadStream_FALSE(stream, buf, NHeader::NArchive::kArchiveHeaderSize))
+ AddToSeekValue(NHeader::NArchive::kArchiveHeaderSize);
+
+
+ const UInt32 blockSize = Get16(buf + 5);
+
+ ArcInfo.EncryptVersion = 0;
+ ArcInfo.Flags = Get16(buf + 3);
+
+ UInt32 headerSize = NHeader::NArchive::kArchiveHeaderSize;
+
+ /*
+ if (ArcInfo.IsThereEncryptVer())
+ {
+ if (blockSize <= headerSize)
+ return S_FALSE;
+ RINOK(ReadStream_FALSE(stream, buf + NHeader::NArchive::kArchiveHeaderSize, 1));
+ AddToSeekValue(1);
+ ArcInfo.EncryptVersion = buf[NHeader::NArchive::kArchiveHeaderSize];
+ headerSize += 1;
+ }
+ */
+
+ if (blockSize < headerSize
+ || buf[2] != NHeader::NBlockType::kArchiveHeader
+ || !CheckHeaderCrc(buf, headerSize))
+ return S_FALSE;
+
+ size_t commentSize = blockSize - headerSize;
+ _comment.Alloc(commentSize);
+ RINOK(ReadStream_FALSE(stream, _comment, commentSize))
+ AddToSeekValue(commentSize);
+ m_Stream = stream;
+ ArcInfo.StartPos = arcStartPos;
+ return S_OK;
+}
+
+HRESULT CInArchive::ReadBytesSpec(void *data, size_t *resSize)
+{
+ if (m_CryptoMode)
+ {
+ size_t size = *resSize;
+ *resSize = 0;
+ const Byte *bufData = m_DecryptedDataAligned;
+ UInt32 bufSize = m_DecryptedDataSize;
+ size_t i;
+ for (i = 0; i < size && m_CryptoPos < bufSize; i++)
+ ((Byte *)data)[i] = bufData[m_CryptoPos++];
+ *resSize = i;
+ return S_OK;
+ }
+ return ReadStream(m_Stream, data, resSize);
+}
+
+bool CInArchive::ReadBytesAndTestSize(void *data, UInt32 size)
+{
+ size_t processed = size;
+ if (ReadBytesSpec(data, &processed) != S_OK)
+ return false;
+ return processed == size;
+}
+
+
+static unsigned DecodeUnicodeFileName(const Byte *name, const Byte *encName,
+ unsigned encSize, wchar_t *unicodeName, unsigned maxDecSize)
+{
+ unsigned encPos = 0;
+ unsigned decPos = 0;
+ unsigned flagBits = 0;
+ Byte flags = 0;
+
+ if (encPos >= encSize)
+ return 0; // error
+ const unsigned highBits = ((unsigned)encName[encPos++]) << 8;
+
+ while (encPos < encSize && decPos < maxDecSize)
+ {
+ if (flagBits == 0)
+ {
+ flags = encName[encPos++];
+ flagBits = 8;
+ }
+
+ if (encPos >= encSize)
+ break; // error
+ unsigned len = encName[encPos++];
+
+ flagBits -= 2;
+ const unsigned mode = (flags >> flagBits) & 3;
+
+ if (mode != 3)
+ {
+ if (mode == 1)
+ len += highBits;
+ else if (mode == 2)
+ {
+ if (encPos >= encSize)
+ break; // error
+ len += ((unsigned)encName[encPos++] << 8);
+ }
+ unicodeName[decPos++] = (wchar_t)len;
+ }
+ else
+ {
+ if (len & 0x80)
+ {
+ if (encPos >= encSize)
+ break; // error
+ Byte correction = encName[encPos++];
+ for (len = (len & 0x7f) + 2; len > 0 && decPos < maxDecSize; len--, decPos++)
+ unicodeName[decPos] = (wchar_t)(((name[decPos] + correction) & 0xff) + highBits);
+ }
+ else
+ for (len += 2; len > 0 && decPos < maxDecSize; len--, decPos++)
+ unicodeName[decPos] = name[decPos];
+ }
+ }
+
+ return decPos < maxDecSize ? decPos : maxDecSize - 1;
+}
+
+
+void CInArchive::ReadName(const Byte *p, unsigned nameSize, CItem &item)
+{
+ item.UnicodeName.Empty();
+ if (nameSize > 0)
+ {
+ unsigned i;
+ for (i = 0; i < nameSize && p[i] != 0; i++);
+ item.Name.SetFrom((const char *)p, i);
+
+ if (item.HasUnicodeName())
+ {
+ if (i < nameSize)
+ {
+ i++;
+ unsigned uNameSizeMax = MyMin(nameSize, (unsigned)0x400);
+ unsigned len = DecodeUnicodeFileName(p, p + i, nameSize - i, _unicodeNameBuffer.GetBuf(uNameSizeMax), uNameSizeMax);
+ _unicodeNameBuffer.ReleaseBuf_SetEnd(len);
+ item.UnicodeName = _unicodeNameBuffer;
+ }
+ else if (!ConvertUTF8ToUnicode(item.Name, item.UnicodeName))
+ item.UnicodeName.Empty();
+ }
+ }
+ else
+ item.Name.Empty();
+}
+
+static int ReadTime(const Byte *p, unsigned size, Byte mask, CRarTime &rarTime)
+{
+ rarTime.LowSecond = (Byte)(((mask & 4) != 0) ? 1 : 0);
+ const unsigned numDigits = (mask & 3);
+ rarTime.SubTime[0] =
+ rarTime.SubTime[1] =
+ rarTime.SubTime[2] = 0;
+ if (numDigits > size)
+ return -1;
+ for (unsigned i = 0; i < numDigits; i++)
+ rarTime.SubTime[3 - numDigits + i] = p[i];
+ return (int)numDigits;
+}
+
+#define READ_TIME(_mask_, _ttt_) \
+ { int size2 = ReadTime(p, size, _mask_, _ttt_); if (size2 < 0) return false; p += (unsigned)size2, size -= (unsigned)size2; }
+
+#define READ_TIME_2(_mask_, _def_, _ttt_) \
+ _def_ = ((_mask_ & 8) != 0); if (_def_) \
+ { if (size < 4) return false; \
+ _ttt_ .DosTime = Get32(p); p += 4; size -= 4; \
+ READ_TIME(_mask_, _ttt_); } \
+
+
+bool CInArchive::ReadHeaderReal(const Byte *p, unsigned size, CItem &item)
+{
+ const Byte *pStart = p;
+
+ item.Clear();
+ item.Flags = m_BlockHeader.Flags;
+
+ const unsigned kFileHeaderSize = 25;
+
+ if (size < kFileHeaderSize)
+ return false;
+
+ item.PackSize = Get32(p);
+ item.Size = Get32(p + 4);
+ item.HostOS = p[8];
+ item.FileCRC = Get32(p + 9);
+ item.MTime.DosTime = Get32(p + 13);
+ item.UnPackVersion = p[17];
+ item.Method = p[18];
+ unsigned nameSize = Get16(p + 19);
+ item.Attrib = Get32(p + 21);
+
+ item.MTime.LowSecond = 0;
+ item.MTime.SubTime[0] =
+ item.MTime.SubTime[1] =
+ item.MTime.SubTime[2] = 0;
+
+ p += kFileHeaderSize;
+ size -= kFileHeaderSize;
+ if ((item.Flags & NHeader::NFile::kSize64Bits) != 0)
+ {
+ if (size < 8)
+ return false;
+ item.PackSize |= ((UInt64)Get32(p) << 32);
+ if (item.PackSize >= ((UInt64)1 << 63))
+ return false;
+ item.Size |= ((UInt64)Get32(p + 4) << 32);
+ p += 8;
+ size -= 8;
+ }
+ if (nameSize > size)
+ return false;
+ ReadName(p, nameSize, item);
+ p += nameSize;
+ size -= nameSize;
+
+ /*
+ // It was commented, since it's difficult to support alt Streams for solid archives.
+ if (m_BlockHeader.Type == NHeader::NBlockType::kSubBlock)
+ {
+ if (item.HasSalt())
+ {
+ if (size < sizeof(item.Salt))
+ return false;
+ size -= sizeof(item.Salt);
+ p += sizeof(item.Salt);
+ }
+ if (item.Name == "ACL" && size == 0)
+ {
+ item.IsAltStream = true;
+ item.Name.Empty();
+ item.UnicodeName.SetFromAscii(".ACL");
+ }
+ else if (item.Name == "STM" && size != 0 && (size & 1) == 0)
+ {
+ item.IsAltStream = true;
+ item.Name.Empty();
+ for (UInt32 i = 0; i < size; i += 2)
+ {
+ wchar_t c = Get16(p + i);
+ if (c == 0)
+ return false;
+ item.UnicodeName += c;
+ }
+ }
+ }
+ */
+
+ if (item.HasSalt())
+ {
+ if (size < sizeof(item.Salt))
+ return false;
+ for (unsigned i = 0; i < sizeof(item.Salt); i++)
+ item.Salt[i] = p[i];
+ p += sizeof(item.Salt);
+ size -= (unsigned)sizeof(item.Salt);
+ }
+
+ // some rar archives have HasExtTime flag without field.
+ if (size >= 2 && item.HasExtTime())
+ {
+ Byte aMask = (Byte)(p[0] >> 4);
+ Byte b = p[1];
+ p += 2;
+ size -= 2;
+ Byte mMask = (Byte)(b >> 4);
+ Byte cMask = (Byte)(b & 0xF);
+ if ((mMask & 8) != 0)
+ {
+ READ_TIME(mMask, item.MTime)
+ }
+ READ_TIME_2(cMask, item.CTimeDefined, item.CTime)
+ READ_TIME_2(aMask, item.ATimeDefined, item.ATime)
+ }
+
+ unsigned fileHeaderWithNameSize = 7 + (unsigned)(p - pStart);
+
+ item.Position = m_Position;
+ item.MainPartSize = fileHeaderWithNameSize;
+ item.CommentSize = (UInt16)(m_BlockHeader.HeadSize - fileHeaderWithNameSize);
+
+ if (m_CryptoMode)
+ item.AlignSize = (UInt16)((16 - ((m_BlockHeader.HeadSize) & 0xF)) & 0xF);
+ else
+ item.AlignSize = 0;
+ AddToSeekValue(m_BlockHeader.HeadSize);
+
+ // return (m_BlockHeader.Type != NHeader::NBlockType::kSubBlock || item.IsAltStream);
+ return true;
+}
+
+HRESULT CInArchive::GetNextItem(CItem &item, ICryptoGetTextPassword *getTextPassword, bool &filled, EErrorType &error)
+{
+ filled = false;
+ error = k_ErrorType_OK;
+ for (;;)
+ {
+ RINOK(InStream_SeekSet(m_Stream, m_Position))
+ ArcInfo.EndPos = m_Position;
+ if (!m_CryptoMode && (ArcInfo.Flags &
+ NHeader::NArchive::kBlockHeadersAreEncrypted) != 0)
+ {
+ m_CryptoMode = false;
+ if (!getTextPassword)
+ {
+ error = k_ErrorType_DecryptionError;
+ return S_OK; // return S_FALSE;
+ }
+ if (!m_RarAES)
+ {
+ m_RarAESSpec = new NCrypto::NRar3::CDecoder;
+ m_RarAES = m_RarAESSpec;
+ }
+ // m_RarAESSpec->SetRar350Mode(ArcInfo.IsEncryptOld());
+
+ {
+ // Salt
+ const UInt32 kSaltSize = 8;
+ Byte salt[kSaltSize];
+ if (!ReadBytesAndTestSize(salt, kSaltSize))
+ return S_FALSE;
+ m_Position += kSaltSize;
+ RINOK(m_RarAESSpec->SetDecoderProperties2(salt, kSaltSize))
+ }
+
+ {
+ // Password
+ CMyComBSTR_Wipe password;
+ RINOK(getTextPassword->CryptoGetTextPassword(&password))
+ unsigned len = 0;
+ if (password)
+ len = MyStringLen(password);
+ if (len > kPasswordLen_MAX)
+ len = kPasswordLen_MAX;
+
+ CByteBuffer_Wipe buffer(len * 2);
+ for (unsigned i = 0; i < len; i++)
+ {
+ wchar_t c = password[i];
+ ((Byte *)buffer)[i * 2] = (Byte)c;
+ ((Byte *)buffer)[i * 2 + 1] = (Byte)(c >> 8);
+ }
+
+ m_RarAESSpec->SetPassword((const Byte *)buffer, len * 2);
+ }
+
+ const UInt32 kDecryptedBufferSize = (1 << 12);
+ if (m_DecryptedDataAligned.Size() == 0)
+ {
+ // const UInt32 kAlign = 16;
+ m_DecryptedDataAligned.AllocAtLeast(kDecryptedBufferSize);
+ if (!m_DecryptedDataAligned.IsAllocated())
+ return E_OUTOFMEMORY;
+ }
+ RINOK(m_RarAES->Init())
+ size_t decryptedDataSizeT = kDecryptedBufferSize;
+ RINOK(ReadStream(m_Stream, m_DecryptedDataAligned, &decryptedDataSizeT))
+ m_DecryptedDataSize = (UInt32)decryptedDataSizeT;
+ m_DecryptedDataSize = m_RarAES->Filter(m_DecryptedDataAligned, m_DecryptedDataSize);
+
+ m_CryptoMode = true;
+ m_CryptoPos = 0;
+ }
+
+ m_FileHeaderData.AllocAtLeast(7);
+ size_t processed = 7;
+ RINOK(ReadBytesSpec((Byte *)m_FileHeaderData, &processed))
+ if (processed != 7)
+ {
+ if (processed != 0)
+ error = k_ErrorType_UnexpectedEnd;
+ ArcInfo.EndPos = m_Position + processed; // test it
+ return S_OK;
+ }
+
+ const Byte *p = m_FileHeaderData;
+ m_BlockHeader.CRC = Get16(p + 0);
+ m_BlockHeader.Type = p[2];
+ m_BlockHeader.Flags = Get16(p + 3);
+ m_BlockHeader.HeadSize = Get16(p + 5);
+
+ if (m_BlockHeader.HeadSize < 7)
+ {
+ error = k_ErrorType_Corrupted;
+ return S_OK;
+ // ThrowExceptionWithCode(CInArchiveException::kIncorrectArchive);
+ }
+
+ if (m_BlockHeader.Type < NHeader::NBlockType::kFileHeader ||
+ m_BlockHeader.Type > NHeader::NBlockType::kEndOfArchive)
+ {
+ error = m_CryptoMode ?
+ k_ErrorType_DecryptionError :
+ k_ErrorType_Corrupted;
+ return S_OK;
+ }
+
+ if (m_BlockHeader.Type == NHeader::NBlockType::kEndOfArchive)
+ {
+ bool footerError = false;
+
+ unsigned expectHeadLen = 7;
+ if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_DataCRC)
+ expectHeadLen += 4;
+ if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_VolNumber)
+ expectHeadLen += 2;
+ if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_RevSpace)
+ expectHeadLen += 7;
+
+ // rar 5.0 beta 1 writes incorrect RevSpace and headSize
+
+ if (m_BlockHeader.HeadSize < expectHeadLen)
+ HeaderErrorWarning = true;
+
+ if (m_BlockHeader.HeadSize > 7)
+ {
+ /* We suppose that EndOfArchive header is always small.
+ It's only 20 bytes for multivolume
+ Fix the limit, if larger footers are possible */
+ if (m_BlockHeader.HeadSize > (1 << 8))
+ footerError = true;
+ else
+ {
+ if (m_FileHeaderData.Size() < m_BlockHeader.HeadSize)
+ m_FileHeaderData.ChangeSize_KeepData(m_BlockHeader.HeadSize, 7);
+ UInt32 afterSize = m_BlockHeader.HeadSize - 7;
+ if (ReadBytesAndTestSize(m_FileHeaderData + 7, afterSize))
+ processed += afterSize;
+ else
+ {
+ if (!m_CryptoMode)
+ {
+ error = k_ErrorType_UnexpectedEnd;
+ return S_OK;
+ }
+ footerError = true;
+ }
+ }
+ }
+
+ if (footerError || !CheckHeaderCrc(m_FileHeaderData, m_BlockHeader.HeadSize))
+ {
+ error = m_CryptoMode ?
+ k_ErrorType_DecryptionError :
+ k_ErrorType_Corrupted;
+ }
+ else
+ {
+ ArcInfo.EndFlags = m_BlockHeader.Flags;
+ UInt32 offset = 7;
+
+ if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_DataCRC)
+ {
+ if (processed < offset + 4)
+ error = k_ErrorType_Corrupted;
+ else
+ ArcInfo.DataCRC = Get32(m_FileHeaderData + offset);
+ offset += 4;
+ }
+
+ if (m_BlockHeader.Flags & NHeader::NArchive::kEndOfArc_Flags_VolNumber)
+ {
+ if (processed < offset + 2)
+ error = k_ErrorType_Corrupted;
+ else
+ ArcInfo.VolNumber = (UInt32)Get16(m_FileHeaderData + offset);
+ }
+
+ ArcInfo.EndOfArchive_was_Read = true;
+ }
+
+ m_Position += processed;
+ FinishCryptoBlock();
+ ArcInfo.EndPos = m_Position;
+ return S_OK;
+ }
+
+ if (m_BlockHeader.Type == NHeader::NBlockType::kFileHeader
+ /* || m_BlockHeader.Type == NHeader::NBlockType::kSubBlock */)
+ {
+ if (m_FileHeaderData.Size() < m_BlockHeader.HeadSize)
+ m_FileHeaderData.ChangeSize_KeepData(m_BlockHeader.HeadSize, 7);
+ // m_CurData = (Byte *)m_FileHeaderData;
+ // m_PosLimit = m_BlockHeader.HeadSize;
+ if (!ReadBytesAndTestSize(m_FileHeaderData + 7, m_BlockHeader.HeadSize - 7))
+ {
+ error = k_ErrorType_UnexpectedEnd;
+ return S_OK;
+ }
+
+ bool okItem = ReadHeaderReal(m_FileHeaderData + 7, m_BlockHeader.HeadSize - 7, item);
+ if (okItem)
+ {
+ if (!CheckHeaderCrc(m_FileHeaderData, (unsigned)m_BlockHeader.HeadSize - item.CommentSize))
+ {
+ error = k_ErrorType_Corrupted; // ThrowExceptionWithCode(CInArchiveException::kFileHeaderCRCError);
+ return S_OK;
+ }
+ filled = true;
+ }
+
+ FinishCryptoBlock();
+ m_CryptoMode = false;
+ // Move Position to compressed Data;
+ RINOK(InStream_SeekSet(m_Stream, m_Position))
+ AddToSeekValue(item.PackSize); // m_Position points to next header;
+ // if (okItem)
+ return S_OK;
+ /*
+ else
+ continue;
+ */
+ }
+
+ if (m_CryptoMode && m_BlockHeader.HeadSize > (1 << 10))
+ {
+ error = k_ErrorType_DecryptionError;
+ return S_OK;
+ }
+
+ if ((m_BlockHeader.Flags & NHeader::NBlock::kLongBlock) != 0)
+ {
+ if (m_FileHeaderData.Size() < 7 + 4)
+ m_FileHeaderData.ChangeSize_KeepData(7 + 4, 7);
+ if (!ReadBytesAndTestSize(m_FileHeaderData + 7, 4))
+ {
+ error = k_ErrorType_UnexpectedEnd;
+ return S_OK;
+ }
+ UInt32 dataSize = Get32(m_FileHeaderData + 7);
+ AddToSeekValue(dataSize);
+ if (m_CryptoMode && dataSize > (1 << 27))
+ {
+ error = k_ErrorType_DecryptionError;
+ return S_OK;
+ }
+ m_CryptoPos = m_BlockHeader.HeadSize;
+ }
+ else
+ m_CryptoPos = 0;
+
+ {
+ UInt64 newPos = m_Position + m_BlockHeader.HeadSize;
+ if (newPos > ArcInfo.FileSize)
+ {
+ error = k_ErrorType_UnexpectedEnd;
+ return S_OK;
+ }
+ }
+ AddToSeekValue(m_BlockHeader.HeadSize);
+ FinishCryptoBlock();
+ m_CryptoMode = false;
+ }
+}
+
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidCTime,
+ kpidATime,
+ kpidAttrib,
+
+ kpidEncrypted,
+ kpidSolid,
+ kpidCommented,
+ kpidSplitBefore,
+ kpidSplitAfter,
+ kpidCRC,
+ kpidHostOS,
+ kpidMethod,
+ kpidUnpackVer,
+
+ kpidVolumeIndex
+};
+
+static const Byte kArcProps[] =
+{
+ kpidTotalPhySize,
+ kpidCharacts,
+ kpidSolid,
+ kpidNumBlocks,
+ // kpidEncrypted,
+ kpidIsVolume,
+ kpidVolumeIndex,
+ kpidNumVolumes
+ // kpidCommented
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+UInt64 CHandler::GetPackSize(unsigned refIndex) const
+{
+ const CRefItem &refItem = _refItems[refIndex];
+ UInt64 totalPackSize = 0;
+ for (unsigned i = 0; i < refItem.NumItems; i++)
+ totalPackSize += _items[refItem.ItemIndex + i].PackSize;
+ return totalPackSize;
+}
+
+bool CHandler::IsSolid(unsigned refIndex) const
+{
+ const CItem &item = _items[_refItems[refIndex].ItemIndex];
+ if (item.UnPackVersion < 20)
+ {
+ if (_arcInfo.IsSolid())
+ return (refIndex > 0);
+ return false;
+ }
+ return item.IsSolid();
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidVolumeIndex: if (_arcInfo.Is_VolNumber_Defined()) prop = (UInt32)_arcInfo.VolNumber; break;
+ case kpidSolid: prop = _arcInfo.IsSolid(); break;
+ case kpidCharacts:
+ {
+ AString s (FlagsToString(k_Flags, Z7_ARRAY_SIZE(k_Flags), _arcInfo.Flags));
+ // FLAGS_TO_PROP(k_Flags, _arcInfo.Flags, prop);
+ if (_arcInfo.Is_DataCRC_Defined())
+ {
+ s.Add_Space_if_NotEmpty();
+ s += "VolCRC";
+ }
+ prop = s;
+ break;
+ }
+ // case kpidEncrypted: prop = _arcInfo.IsEncrypted(); break; // it's for encrypted names.
+ case kpidIsVolume: prop = _arcInfo.IsVolume(); break;
+ case kpidNumVolumes: prop = (UInt32)_arcs.Size(); break;
+ case kpidOffset: if (_arcs.Size() == 1 && _arcInfo.StartPos != 0) prop = _arcInfo.StartPos; break;
+
+ case kpidTotalPhySize:
+ {
+ if (_arcs.Size() > 1)
+ {
+ UInt64 sum = 0;
+ FOR_VECTOR (v, _arcs)
+ sum += _arcs[v].PhySize;
+ prop = sum;
+ }
+ break;
+ }
+
+ case kpidPhySize:
+ {
+ if (_arcs.Size() != 0)
+ prop = _arcInfo.GetPhySize();
+ break;
+ }
+
+ // case kpidCommented: prop = _arcInfo.IsCommented(); break;
+
+ case kpidNumBlocks:
+ {
+ UInt32 numBlocks = 0;
+ FOR_VECTOR (i, _refItems)
+ if (!IsSolid(i))
+ numBlocks++;
+ prop = (UInt32)numBlocks;
+ break;
+ }
+
+
+ case kpidError:
+ {
+ // if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
+
+ if (/* &_missingVol || */ !_missingVolName.IsEmpty())
+ {
+ UString s ("Missing volume : ");
+ s += _missingVolName;
+ prop = s;
+ }
+ break;
+ }
+
+ case kpidErrorFlags:
+ {
+ UInt32 v = _errorFlags;
+ if (!_isArc)
+ v |= kpv_ErrorFlags_IsNotArc;
+ prop = v;
+ break;
+ }
+
+ case kpidWarningFlags:
+ {
+ if (_warningFlags != 0)
+ prop = _warningFlags;
+ break;
+ }
+
+ case kpidExtension:
+ if (_arcs.Size() == 1)
+ {
+ if (_arcInfo.Is_VolNumber_Defined())
+ {
+ AString s ("part");
+ UInt32 v = (UInt32)_arcInfo.VolNumber + 1;
+ if (v < 10)
+ s += '0';
+ s.Add_UInt32(v);
+ s += ".rar";
+ prop = s;
+ }
+ }
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _refItems.Size();
+ return S_OK;
+}
+
+static bool RarTimeToFileTime(const CRarTime &rarTime, FILETIME &ft)
+{
+ if (!NTime::DosTime_To_FileTime(rarTime.DosTime, ft))
+ return false;
+ UInt64 v = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
+ v += (UInt32)rarTime.LowSecond * 10000000;
+ v +=
+ ((UInt32)rarTime.SubTime[2] << 16) +
+ ((UInt32)rarTime.SubTime[1] << 8) +
+ ((UInt32)rarTime.SubTime[0]);
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+ return true;
+}
+
+static void RarTimeToProp(const CRarTime &rarTime, NCOM::CPropVariant &prop)
+{
+ FILETIME localFileTime, utc;
+ if (RarTimeToFileTime(rarTime, localFileTime)
+ && LocalFileTimeToFileTime(&localFileTime, &utc))
+ prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_100ns);
+ /*
+ else
+ utc.dwHighDateTime = utc.dwLowDateTime = 0;
+ // prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_100ns);
+ */
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ const CRefItem &refItem = _refItems[index];
+ const CItem &item = _items[refItem.ItemIndex];
+ const CItem &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
+
+ /*
+ const CItem *mainItem = &item;
+ if (item.BaseFileIndex >= 0)
+ mainItem = &_items[_refItems[item.BaseFileIndex].ItemIndex];
+ */
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ /*
+ UString u;
+ if (item.BaseFileIndex >= 0)
+ u = mainItem->GetName();
+ u += item.GetName();
+ */
+ prop = (const wchar_t *)NItemName::WinPathToOsPath(item.GetName());
+ break;
+ }
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: if (lastItem.Is_Size_Defined()) prop = lastItem.Size; break;
+ case kpidPackSize: prop = GetPackSize(index); break;
+ case kpidMTime: RarTimeToProp(item.MTime, prop); break;
+ case kpidCTime: if (item.CTimeDefined) RarTimeToProp(item.CTime, prop); break;
+ case kpidATime: if (item.ATimeDefined) RarTimeToProp(item.ATime, prop); break;
+ case kpidAttrib: prop = item.GetWinAttrib(); break;
+ case kpidEncrypted: prop = item.IsEncrypted(); break;
+ case kpidSolid: prop = IsSolid(index); break;
+ case kpidCommented: prop = item.IsCommented(); break;
+ case kpidSplitBefore: prop = item.IsSplitBefore(); break;
+ case kpidSplitAfter: prop = _items[refItem.ItemIndex + refItem.NumItems - 1].IsSplitAfter(); break;
+
+ case kpidVolumeIndex:
+ if (_arcInfo.Is_VolNumber_Defined())
+ prop = (UInt32)(_arcInfo.VolNumber + refItem.VolumeIndex);
+ break;
+
+ case kpidCRC:
+ {
+ prop = ((lastItem.IsSplitAfter()) ? item.FileCRC : lastItem.FileCRC);
+ break;
+ }
+ case kpidUnpackVer: prop = item.UnPackVersion; break;
+ case kpidMethod:
+ {
+ char s[16];
+ Byte m = item.Method;
+ if (m < (Byte)'0' || m > (Byte)'5')
+ ConvertUInt32ToString(m, s);
+ else
+ {
+ s[0] = 'm';
+ s[1] = (char)m;
+ s[2] = 0;
+ if (!item.IsDir())
+ {
+ s[2] = ':';
+ ConvertUInt32ToString(16 + item.GetDictSize(), &s[3]);
+ }
+ }
+ prop = s;
+ break;
+ }
+ case kpidHostOS:
+ TYPE_TO_PROP(kHostOS, item.HostOS, prop);
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+HRESULT CHandler::Open2(IInStream *stream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *openCallback)
+{
+ {
+ CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+
+ CVolumeName seqName;
+
+ UInt64 totalBytes = 0;
+ UInt64 curBytes = 0;
+
+ if (openCallback)
+ {
+ openCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
+ openCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
+ }
+
+ bool nextVol_is_Required = false;
+
+ CInArchive archive;
+
+ for (;;)
+ {
+ CMyComPtr<IInStream> inStream;
+ if (!_arcs.IsEmpty())
+ {
+ if (!openVolumeCallback)
+ break;
+
+ if (_arcs.Size() == 1)
+ {
+ if (!_arcInfo.IsVolume())
+ break;
+ UString baseName;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(openVolumeCallback->GetProperty(kpidName, &prop))
+ if (prop.vt != VT_BSTR)
+ break;
+ baseName = prop.bstrVal;
+ }
+ if (!seqName.InitName(baseName, _arcInfo.HaveNewVolumeName()))
+ break;
+ /*
+ if (_arcInfo.HaveNewVolumeName() && !_arcInfo.IsFirstVolume())
+ {
+ seqName.MakeBeforeFirstName();
+ }
+ */
+ }
+
+ const UString volName = seqName.GetNextName();
+
+ HRESULT result = openVolumeCallback->GetStream(volName, &inStream);
+
+ if (result != S_OK && result != S_FALSE)
+ return result;
+
+ if (!inStream || result != S_OK)
+ {
+ if (nextVol_is_Required)
+ _missingVolName = volName;
+ break;
+ }
+ }
+ else
+ inStream = stream;
+
+ UInt64 endPos;
+ RINOK(InStream_AtBegin_GetSize(inStream, endPos))
+ if (openCallback)
+ {
+ totalBytes += endPos;
+ RINOK(openCallback->SetTotal(NULL, &totalBytes))
+ }
+
+ RINOK(archive.Open(inStream, maxCheckStartPosition))
+ _isArc = true;
+ CItem item;
+
+ for (;;)
+ {
+ if (archive.m_Position > endPos)
+ {
+ _errorFlags |= kpv_ErrorFlags_UnexpectedEnd;
+ break;
+ }
+
+ EErrorType error;
+ // bool decryptionError;
+ // AString errorMessageLoc;
+ bool filled;
+ HRESULT result = archive.GetNextItem(item, getTextPassword, filled, error);
+
+ if (error != k_ErrorType_OK)
+ {
+ if (error == k_ErrorType_UnexpectedEnd)
+ _errorFlags |= kpv_ErrorFlags_UnexpectedEnd;
+ else if (error == k_ErrorType_Corrupted)
+ _errorFlags |= kpv_ErrorFlags_HeadersError;
+ else if (error == k_ErrorType_DecryptionError)
+ _errorFlags |= kpv_ErrorFlags_EncryptedHeadersError;
+
+ // AddErrorMessage(errorMessageLoc);
+ }
+ RINOK(result)
+
+ if (!filled)
+ {
+ if (error == k_ErrorType_DecryptionError && _items.IsEmpty())
+ return S_FALSE;
+
+ if (archive.ArcInfo.ExtraZeroTail_is_Possible())
+ {
+ /* if there is recovery record for multivolume archive,
+ RAR adds 18 bytes (ZERO bytes) at the end for alignment.
+ We must skip these bytes to prevent phySize warning. */
+ RINOK(InStream_SeekSet(inStream, archive.ArcInfo.EndPos))
+ bool areThereNonZeros;
+ UInt64 numZeros;
+ const UInt64 maxSize = 1 << 12;
+ RINOK(ReadZeroTail(inStream, areThereNonZeros, numZeros, maxSize))
+ if (!areThereNonZeros && numZeros != 0 && numZeros <= maxSize)
+ archive.ArcInfo.EndPos += numZeros;
+ }
+ break;
+ }
+
+ if (item.IgnoreItem())
+ continue;
+
+ bool needAdd = true;
+
+ if (item.IsSplitBefore())
+ {
+ if (!_refItems.IsEmpty())
+ {
+ CRefItem &refItem = _refItems.Back();
+ refItem.NumItems++;
+ needAdd = false;
+ }
+ }
+
+ if (needAdd)
+ {
+ CRefItem refItem;
+ refItem.ItemIndex = _items.Size();
+ refItem.NumItems = 1;
+ refItem.VolumeIndex = _arcs.Size();
+ _refItems.Add(refItem);
+ }
+
+ _items.Add(item);
+
+ if (openCallback && _items.Size() % 100 == 0)
+ {
+ UInt64 numFiles = _items.Size();
+ UInt64 numBytes = curBytes + item.Position;
+ RINOK(openCallback->SetCompleted(&numFiles, &numBytes))
+ }
+ }
+
+ if (archive.HeaderErrorWarning)
+ _warningFlags |= kpv_ErrorFlags_HeadersError;
+
+ /*
+ if (archive.m_Position < endPos)
+ _warningFlags |= kpv_ErrorFlags_DataAfterEnd;
+ */
+ if (_arcs.IsEmpty())
+ _arcInfo = archive.ArcInfo;
+ // _arcInfo.EndPos = archive.EndPos;
+
+ curBytes += endPos;
+ {
+ CArc &arc = _arcs.AddNew();
+ arc.PhySize = archive.ArcInfo.GetPhySize();
+ arc.Stream = inStream;
+ }
+
+ nextVol_is_Required = false;
+
+ if (!archive.ArcInfo.IsVolume())
+ break;
+
+ if (archive.ArcInfo.EndOfArchive_was_Read)
+ {
+ if (!archive.ArcInfo.AreMoreVolumes())
+ break;
+ nextVol_is_Required = true;
+ }
+ }
+ }
+
+ /*
+ int baseFileIndex = -1;
+ for (unsigned i = 0; i < _refItems.Size(); i++)
+ {
+ CItem &item = _items[_refItems[i].ItemIndex];
+ if (item.IsAltStream)
+ item.BaseFileIndex = baseFileIndex;
+ else
+ baseFileIndex = i;
+ }
+ */
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *openCallback))
+{
+ COM_TRY_BEGIN
+ Close();
+ // try
+ {
+ HRESULT res = Open2(stream, maxCheckStartPosition, openCallback);
+ /*
+ if (res != S_OK)
+ Close();
+ */
+
+ return res;
+ }
+ // catch(const CInArchiveException &) { Close(); return S_FALSE; }
+ // catch(...) { Close(); throw; }
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ COM_TRY_BEGIN
+ // _errorMessage.Empty();
+ _missingVolName.Empty();
+ _errorFlags = 0;
+ _warningFlags = 0;
+ _isArc = false;
+ _refItems.Clear();
+ _items.Clear();
+ _arcs.Clear();
+ return S_OK;
+ COM_TRY_END
+}
+
+struct CMethodItem
+{
+ Byte RarUnPackVersion;
+ CMyComPtr<ICompressCoder> Coder;
+};
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ CVolsInStream
+ , ISequentialInStream
+)
+ UInt64 _rem;
+ ISequentialInStream *_stream;
+ const CObjectVector<CArc> *_arcs;
+ const CObjectVector<CItem> *_items;
+ CRefItem _refItem;
+ unsigned _curIndex;
+ UInt32 _crc;
+ bool _calcCrc;
+
+public:
+ void Init(const CObjectVector<CArc> *arcs,
+ const CObjectVector<CItem> *items,
+ const CRefItem &refItem)
+ {
+ _arcs = arcs;
+ _items = items;
+ _refItem = refItem;
+ _curIndex = 0;
+ _stream = NULL;
+ CrcIsOK = true;
+ }
+
+ bool CrcIsOK;
+};
+
+
+Z7_COM7F_IMF(CVolsInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ UInt32 realProcessedSize = 0;
+
+ while (size != 0)
+ {
+ if (!_stream)
+ {
+ if (_curIndex >= _refItem.NumItems)
+ break;
+ const CItem &item = (*_items)[_refItem.ItemIndex + _curIndex];
+ unsigned volIndex = _refItem.VolumeIndex + _curIndex;
+ if (volIndex >= _arcs->Size())
+ {
+ return S_OK;
+ // return S_FALSE;
+ }
+ IInStream *s = (*_arcs)[volIndex].Stream;
+ RINOK(InStream_SeekSet(s, item.GetDataPosition()))
+ _stream = s;
+ _calcCrc = (CrcIsOK && item.IsSplitAfter());
+ _crc = CRC_INIT_VAL;
+ _rem = item.PackSize;
+ }
+ {
+ UInt32 cur = size;
+ if (cur > _rem)
+ cur = (UInt32)_rem;
+ UInt32 num = cur;
+ HRESULT res = _stream->Read(data, cur, &cur);
+ if (_calcCrc)
+ _crc = CrcUpdate(_crc, data, cur);
+ realProcessedSize += cur;
+ if (processedSize)
+ *processedSize = realProcessedSize;
+ data = (Byte *)data + cur;
+ size -= cur;
+ _rem -= cur;
+ if (_rem == 0)
+ {
+ const CItem &item = (*_items)[_refItem.ItemIndex + _curIndex];
+ _curIndex++;
+ if (_calcCrc && CRC_GET_DIGEST(_crc) != item.FileCRC)
+ CrcIsOK = false;
+ _stream = NULL;
+ }
+ if (res != S_OK)
+ return res;
+ if (realProcessedSize != 0)
+ return S_OK;
+ if (cur == 0 && num != 0)
+ return S_OK;
+ }
+ }
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ UInt64 // censoredTotalUnPacked = 0,
+ // censoredTotalPacked = 0,
+ importantTotalUnPacked = 0;
+ // importantTotalPacked = 0;
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _refItems.Size();
+ if (numItems == 0)
+ return S_OK;
+ unsigned lastIndex = 0;
+ CRecordVector<unsigned> importantIndexes;
+ CRecordVector<bool> extractStatuses;
+
+ bool isThereUndefinedSize = false;
+
+ for (UInt32 t = 0; t < numItems; t++)
+ {
+ unsigned index = allFilesMode ? t : indices[t];
+
+ {
+ const CRefItem &refItem = _refItems[index];
+ const CItem &item = _items[refItem.ItemIndex + refItem.NumItems - 1];
+
+ if (item.Is_Size_Defined())
+ {
+ // censoredTotalUnPacked += item.Size;
+ }
+ else
+ isThereUndefinedSize = true;
+
+ // censoredTotalPacked += item.PackSize;
+ }
+
+ unsigned j;
+ for (j = lastIndex; j <= index; j++)
+ // if (!_items[_refItems[j].ItemIndex].IsSolid())
+ if (!IsSolid(j))
+ lastIndex = j;
+
+ for (j = lastIndex; j <= index; j++)
+ {
+ const CRefItem &refItem = _refItems[j];
+ const CItem &item = _items[refItem.ItemIndex + refItem.NumItems - 1];
+
+ if (item.Is_Size_Defined())
+ importantTotalUnPacked += item.Size;
+ else
+ isThereUndefinedSize = true;
+ // importantTotalPacked += item.PackSize;
+ importantIndexes.Add(j);
+ extractStatuses.Add(j == index);
+ }
+
+ lastIndex = index + 1;
+ }
+
+ if (importantTotalUnPacked != 0 || !isThereUndefinedSize)
+ {
+ RINOK(extractCallback->SetTotal(importantTotalUnPacked))
+ }
+
+ UInt64 currentImportantTotalUnPacked = 0;
+ UInt64 currentImportantTotalPacked = 0;
+ UInt64 currentUnPackSize, currentPackSize;
+
+ CObjectVector<CMethodItem> methodItems;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CFilterCoder *filterStreamSpec = new CFilterCoder(false);
+ CMyComPtr<ISequentialInStream> filterStream = filterStreamSpec;
+
+ NCrypto::NRar2::CDecoder *rar20CryptoDecoderSpec = NULL;
+ CMyComPtr<ICompressFilter> rar20CryptoDecoder;
+ NCrypto::NRar3::CDecoder *rar3CryptoDecoderSpec = NULL;
+ CMyComPtr<ICompressFilter> rar3CryptoDecoder;
+
+ CVolsInStream *volsInStreamSpec = NULL;
+ CMyComPtr<ISequentialInStream> volsInStream;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ bool solidStart = true;
+
+ for (unsigned i = 0;;
+ i++,
+ currentImportantTotalUnPacked += currentUnPackSize,
+ currentImportantTotalPacked += currentPackSize)
+ {
+ lps->InSize = currentImportantTotalPacked;
+ lps->OutSize = currentImportantTotalUnPacked;
+ RINOK(lps->SetCur())
+
+ if (i >= importantIndexes.Size())
+ break;
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+
+ Int32 askMode;
+ if (extractStatuses[i])
+ askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ else
+ askMode = NExtract::NAskMode::kSkip;
+
+ UInt32 index = importantIndexes[i];
+
+ const CRefItem &refItem = _refItems[index];
+ const CItem &item = _items[refItem.ItemIndex];
+ const CItem &lastItem = _items[refItem.ItemIndex + refItem.NumItems - 1];
+
+ UInt64 outSize = (UInt64)(Int64)-1;
+ currentUnPackSize = 0;
+ if (lastItem.Is_Size_Defined())
+ {
+ outSize = lastItem.Size;
+ currentUnPackSize = outSize;
+ }
+
+ currentPackSize = GetPackSize(index);
+
+ if (item.IgnoreItem())
+ continue;
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+ if (!IsSolid(index))
+ solidStart = true;
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+
+ bool mustBeProcessedAnywhere = false;
+ if (i < importantIndexes.Size() - 1)
+ {
+ // const CRefItem &nextRefItem = _refItems[importantIndexes[i + 1]];
+ // const CItem &nextItemInfo = _items[nextRefItem.ItemIndex];
+ // mustBeProcessedAnywhere = nextItemInfo.IsSolid();
+ mustBeProcessedAnywhere = IsSolid(importantIndexes[i + 1]);
+ }
+
+ if (!mustBeProcessedAnywhere && !testMode && !realOutStream)
+ continue;
+
+ if (!realOutStream && !testMode)
+ askMode = NExtract::NAskMode::kSkip;
+
+ RINOK(extractCallback->PrepareOperation(askMode))
+
+ COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+
+ if (!volsInStream)
+ {
+ volsInStreamSpec = new CVolsInStream;
+ volsInStream = volsInStreamSpec;
+ }
+
+ volsInStreamSpec->Init(&_arcs, &_items, refItem);
+
+ UInt64 packSize = currentPackSize;
+
+ // packedPos += item.PackSize;
+ // unpackedPos += 0;
+
+ CMyComPtr<ISequentialInStream> inStream;
+
+ if (item.IsEncrypted())
+ {
+ // CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+
+ if (item.UnPackVersion >= 29)
+ {
+ if (!rar3CryptoDecoder)
+ {
+ rar3CryptoDecoderSpec = new NCrypto::NRar3::CDecoder;
+ rar3CryptoDecoder = rar3CryptoDecoderSpec;
+ }
+ // rar3CryptoDecoderSpec->SetRar350Mode(item.UnPackVersion < 36);
+ /*
+ CMyComPtr<ICompressSetDecoderProperties2> cryptoProperties;
+ RINOK(rar3CryptoDecoder.QueryInterface(IID_ICompressSetDecoderProperties2,
+ &cryptoProperties));
+ */
+ RINOK(rar3CryptoDecoderSpec->SetDecoderProperties2(item.Salt, item.HasSalt() ? sizeof(item.Salt) : 0))
+ filterStreamSpec->Filter = rar3CryptoDecoder;
+ }
+ else if (item.UnPackVersion >= 20)
+ {
+ if (!rar20CryptoDecoder)
+ {
+ rar20CryptoDecoderSpec = new NCrypto::NRar2::CDecoder;
+ rar20CryptoDecoder = rar20CryptoDecoderSpec;
+ }
+ filterStreamSpec->Filter = rar20CryptoDecoder;
+ }
+ else
+ {
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod))
+ continue;
+ }
+
+ // RINOK(filterStreamSpec->Filter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword));
+
+ if (!getTextPassword)
+ extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
+
+ if (!getTextPassword)
+ {
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod))
+ continue;
+ }
+
+ // if (getTextPassword)
+ {
+ CMyComBSTR_Wipe password;
+ RINOK(getTextPassword->CryptoGetTextPassword(&password))
+
+ if (item.UnPackVersion >= 29)
+ {
+ unsigned len = 0;
+ if (password)
+ len = MyStringLen(password);
+ if (len > kPasswordLen_MAX)
+ len = kPasswordLen_MAX;
+ CByteBuffer_Wipe buffer(len * 2);
+ for (unsigned k = 0; k < len; k++)
+ {
+ wchar_t c = password[k];
+ ((Byte *)buffer)[k * 2] = (Byte)c;
+ ((Byte *)buffer)[k * 2 + 1] = (Byte)(c >> 8);
+ }
+ rar3CryptoDecoderSpec->SetPassword((const Byte *)buffer, len * 2);
+ }
+ else
+ {
+ AString_Wipe oemPassword;
+ if (password)
+ {
+ UString_Wipe unicode;
+ unicode.SetFromBstr(password);
+ if (unicode.Len() > kPasswordLen_MAX)
+ unicode.DeleteFrom(kPasswordLen_MAX);
+ UnicodeStringToMultiByte2(oemPassword, unicode, CP_OEMCP);
+ }
+ rar20CryptoDecoderSpec->SetPassword((const Byte *)(const char *)oemPassword, oemPassword.Len());
+ }
+ }
+ /*
+ else
+ {
+ RINOK(cryptoSetPassword->CryptoSetPassword(NULL, 0));
+ }
+ */
+
+ filterStreamSpec->SetInStream(volsInStream);
+ filterStreamSpec->SetOutStreamSize(NULL);
+ inStream = filterStream;
+ }
+ else
+ {
+ inStream = volsInStream;
+ }
+
+ CMyComPtr<ICompressCoder> commonCoder;
+
+ switch (item.Method)
+ {
+ case '0':
+ {
+ commonCoder = copyCoder;
+ break;
+ }
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ {
+ unsigned m;
+ for (m = 0; m < methodItems.Size(); m++)
+ if (methodItems[m].RarUnPackVersion == item.UnPackVersion)
+ break;
+ if (m == methodItems.Size())
+ {
+ CMethodItem mi;
+ mi.RarUnPackVersion = item.UnPackVersion;
+
+ mi.Coder.Release();
+ if (item.UnPackVersion <= 40)
+ {
+ UInt32 methodID = 0x40300;
+ if (item.UnPackVersion < 20)
+ methodID += 1;
+ else if (item.UnPackVersion < 29)
+ methodID += 2;
+ else
+ methodID += 3;
+ RINOK(CreateCoder_Id(EXTERNAL_CODECS_VARS methodID, false, mi.Coder))
+ }
+
+ if (!mi.Coder)
+ {
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod))
+ continue;
+ }
+
+ m = methodItems.Add(mi);
+ }
+ CMyComPtr<ICompressCoder> decoder = methodItems[m].Coder;
+
+ CMyComPtr<ICompressSetDecoderProperties2> compressSetDecoderProperties;
+ RINOK(decoder.QueryInterface(IID_ICompressSetDecoderProperties2,
+ &compressSetDecoderProperties))
+
+ Byte isSolid = (Byte)((IsSolid(index) || item.IsSplitBefore()) ? 1: 0);
+ if (solidStart)
+ {
+ isSolid = 0;
+ solidStart = false;
+ }
+
+
+ RINOK(compressSetDecoderProperties->SetDecoderProperties2(&isSolid, 1))
+
+ commonCoder = decoder;
+ break;
+ }
+ default:
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnsupportedMethod))
+ continue;
+ }
+
+ HRESULT result = commonCoder->Code(inStream, outStream, &packSize, &outSize, progress);
+
+ if (item.IsEncrypted())
+ filterStreamSpec->ReleaseInStream();
+
+ if (outSize == (UInt64)(Int64)-1)
+ currentUnPackSize = outStreamSpec->GetSize();
+
+ int opRes = (volsInStreamSpec->CrcIsOK && outStreamSpec->GetCRC() == lastItem.FileCRC) ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kCRCError;
+ outStream.Release();
+
+ if (result != S_OK)
+ {
+ if (result == S_FALSE)
+ opRes = NExtract::NOperationResult::kDataError;
+ else if (result == E_NOTIMPL)
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ else
+ return result;
+ }
+ RINOK(extractCallback->SetOperationResult(opRes))
+ }
+
+ return S_OK;
+ COM_TRY_END
+}
+
+IMPL_ISetCompressCodecsInfo
+
+REGISTER_ARC_I(
+ "Rar", "rar r00", NULL, 3,
+ kMarker,
+ 0,
+ NArcInfoFlags::kFindSignature,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/Rar/RarHandler.h b/CPP/7zip/Archive/Rar/RarHandler.h
new file mode 100644
index 0000000..c4d8450
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/RarHandler.h
@@ -0,0 +1,114 @@
+// RarHandler.h
+
+#ifndef ZIP7_INC_RAR_HANDLER_H
+#define ZIP7_INC_RAR_HANDLER_H
+
+#include "../IArchive.h"
+
+#include "../../Common/CreateCoder.h"
+
+#include "RarItem.h"
+
+namespace NArchive {
+namespace NRar {
+
+struct CInArcInfo
+{
+ UInt32 Flags;
+ Byte EncryptVersion;
+
+ UInt64 StartPos;
+ UInt64 EndPos;
+ UInt64 FileSize;
+
+ UInt32 EndFlags;
+ UInt32 VolNumber;
+ UInt32 DataCRC;
+ bool EndOfArchive_was_Read;
+
+ CInArcInfo(): EndFlags(0), VolNumber(0), EndOfArchive_was_Read(false) {}
+
+ UInt64 GetPhySize() const { return EndPos - StartPos; }
+
+ bool ExtraZeroTail_is_Possible() const { return IsVolume() && IsRecovery() && EndOfArchive_was_Read; }
+
+ bool IsVolume() const { return (Flags & NHeader::NArchive::kVolume) != 0; }
+ bool IsCommented() const { return (Flags & NHeader::NArchive::kComment) != 0; }
+ // kLock
+ bool IsSolid() const { return (Flags & NHeader::NArchive::kSolid) != 0; }
+ bool HaveNewVolumeName() const { return (Flags & NHeader::NArchive::kNewVolName) != 0; }
+ // kAuthenticity
+ bool IsRecovery() const { return (Flags & NHeader::NArchive::kRecovery) != 0; }
+ bool IsEncrypted() const { return (Flags & NHeader::NArchive::kBlockEncryption) != 0; }
+ bool IsFirstVolume() const { return (Flags & NHeader::NArchive::kFirstVolume) != 0; }
+
+ // bool IsThereEncryptVer() const { return (Flags & NHeader::NArchive::kEncryptVer) != 0; }
+ // bool IsEncryptOld() const { return (!IsThereEncryptVer() || EncryptVersion < 36); }
+
+ bool AreMoreVolumes() const { return (EndFlags & NHeader::NArchive::kEndOfArc_Flags_NextVol) != 0; }
+ bool Is_VolNumber_Defined() const { return (EndFlags & NHeader::NArchive::kEndOfArc_Flags_VolNumber) != 0; }
+ bool Is_DataCRC_Defined() const { return (EndFlags & NHeader::NArchive::kEndOfArc_Flags_DataCRC) != 0; }
+};
+
+struct CArc
+{
+ CMyComPtr<IInStream> Stream;
+ UInt64 PhySize;
+ // CByteBuffer Comment;
+
+ CArc(): PhySize(0) {}
+ ISequentialInStream *CreateLimitedStream(UInt64 offset, UInt64 size) const;
+};
+
+struct CRefItem
+{
+ unsigned VolumeIndex;
+ unsigned ItemIndex;
+ unsigned NumItems;
+};
+
+class CHandler Z7_final:
+ public IInArchive,
+ Z7_PUBLIC_ISetCompressCodecsInfo_IFEC
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(IInArchive)
+ Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(IInArchive)
+ DECL_ISetCompressCodecsInfo
+
+ CRecordVector<CRefItem> _refItems;
+ CObjectVector<CItem> _items;
+ CObjectVector<CArc> _arcs;
+ NArchive::NRar::CInArcInfo _arcInfo;
+ // AString _errorMessage;
+ UInt32 _errorFlags;
+ UInt32 _warningFlags;
+ bool _isArc;
+ UString _missingVolName;
+
+ DECL_EXTERNAL_CODECS_VARS
+
+ UInt64 GetPackSize(unsigned refIndex) const;
+ bool IsSolid(unsigned refIndex) const;
+
+ /*
+ void AddErrorMessage(const AString &s)
+ {
+ if (!_errorMessage.IsEmpty())
+ _errorMessage += '\n';
+ _errorMessage += s;
+ }
+ */
+
+ HRESULT Open2(IInStream *stream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *openCallback);
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Rar/RarHeader.h b/CPP/7zip/Archive/Rar/RarHeader.h
new file mode 100644
index 0000000..031fea6
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/RarHeader.h
@@ -0,0 +1,209 @@
+// Archive/RarHeader.h
+
+#ifndef ZIP7_INC_ARCHIVE_RAR_HEADER_H
+#define ZIP7_INC_ARCHIVE_RAR_HEADER_H
+
+#include "../../../Common/MyTypes.h"
+
+namespace NArchive {
+namespace NRar {
+namespace NHeader {
+
+const unsigned kMarkerSize = 7;
+
+const unsigned kArchiveSolid = 0x1;
+
+namespace NBlockType
+{
+ enum EBlockType
+ {
+ kMarker = 0x72,
+ kArchiveHeader,
+ kFileHeader,
+ kCommentHeader,
+ kOldAuthenticity,
+ kOldSubBlock,
+ kRecoveryRecord,
+ kAuthenticity,
+ kSubBlock,
+ kEndOfArchive
+ };
+}
+
+namespace NArchive
+{
+ const UInt16 kVolume = 1;
+ const UInt16 kComment = 2;
+ const UInt16 kLock = 4;
+ const UInt16 kSolid = 8;
+ const UInt16 kNewVolName = 0x10; // ('volname.partN.rar')
+ const UInt16 kAuthenticity = 0x20;
+ const UInt16 kRecovery = 0x40;
+ const UInt16 kBlockEncryption = 0x80;
+ const UInt16 kFirstVolume = 0x100; // (set only by RAR 3.0 and later)
+
+ // const UInt16 kEncryptVer = 0x200; // RAR 3.6 : that feature was discarded by origial RAR
+
+ const UInt16 kEndOfArc_Flags_NextVol = 1;
+ const UInt16 kEndOfArc_Flags_DataCRC = 2;
+ const UInt16 kEndOfArc_Flags_RevSpace = 4;
+ const UInt16 kEndOfArc_Flags_VolNumber = 8;
+
+ const unsigned kHeaderSizeMin = 7;
+
+ const unsigned kArchiveHeaderSize = 13;
+
+ const unsigned kBlockHeadersAreEncrypted = 0x80;
+}
+
+namespace NFile
+{
+ const unsigned kSplitBefore = 1 << 0;
+ const unsigned kSplitAfter = 1 << 1;
+ const unsigned kEncrypted = 1 << 2;
+ const unsigned kComment = 1 << 3;
+ const unsigned kSolid = 1 << 4;
+
+ const unsigned kDictBitStart = 5;
+ const unsigned kNumDictBits = 3;
+ const unsigned kDictMask = (1 << kNumDictBits) - 1;
+ const unsigned kDictDirectoryValue = 0x7;
+
+ const unsigned kSize64Bits = 1 << 8;
+ const unsigned kUnicodeName = 1 << 9;
+ const unsigned kSalt = 1 << 10;
+ const unsigned kOldVersion = 1 << 11;
+ const unsigned kExtTime = 1 << 12;
+ // const unsigned kExtFlags = 1 << 13;
+ // const unsigned kSkipIfUnknown = 1 << 14;
+
+ const unsigned kLongBlock = 1 << 15;
+
+ /*
+ struct CBlock
+ {
+ // UInt16 HeadCRC;
+ // Byte Type;
+ // UInt16 Flags;
+ // UInt16 HeadSize;
+ UInt32 PackSize;
+ UInt32 UnPackSize;
+ Byte HostOS;
+ UInt32 FileCRC;
+ UInt32 Time;
+ Byte UnPackVersion;
+ Byte Method;
+ UInt16 NameSize;
+ UInt32 Attributes;
+ };
+ */
+
+ /*
+ struct CBlock32
+ {
+ UInt16 HeadCRC;
+ Byte Type;
+ UInt16 Flags;
+ UInt16 HeadSize;
+ UInt32 PackSize;
+ UInt32 UnPackSize;
+ Byte HostOS;
+ UInt32 FileCRC;
+ UInt32 Time;
+ Byte UnPackVersion;
+ Byte Method;
+ UInt16 NameSize;
+ UInt32 Attributes;
+ UInt16 GetRealCRC(const void *aName, UInt32 aNameSize,
+ bool anExtraDataDefined = false, Byte *anExtraData = 0) const;
+ };
+ struct CBlock64
+ {
+ UInt16 HeadCRC;
+ Byte Type;
+ UInt16 Flags;
+ UInt16 HeadSize;
+ UInt32 PackSizeLow;
+ UInt32 UnPackSizeLow;
+ Byte HostOS;
+ UInt32 FileCRC;
+ UInt32 Time;
+ Byte UnPackVersion;
+ Byte Method;
+ UInt16 NameSize;
+ UInt32 Attributes;
+ UInt32 PackSizeHigh;
+ UInt32 UnPackSizeHigh;
+ UInt16 GetRealCRC(const void *aName, UInt32 aNameSize) const;
+ };
+ */
+
+ const unsigned kLabelFileAttribute = 0x08;
+ const unsigned kWinFileDirectoryAttributeMask = 0x10;
+
+ enum CHostOS
+ {
+ kHostMSDOS = 0,
+ kHostOS2 = 1,
+ kHostWin32 = 2,
+ kHostUnix = 3,
+ kHostMacOS = 4,
+ kHostBeOS = 5
+ };
+}
+
+namespace NBlock
+{
+ const UInt16 kLongBlock = 1 << 15;
+ struct CBlock
+ {
+ UInt16 CRC;
+ Byte Type;
+ UInt16 Flags;
+ UInt16 HeadSize;
+ // UInt32 DataSize;
+ };
+}
+
+/*
+struct CSubBlock
+{
+ UInt16 HeadCRC;
+ Byte HeadType;
+ UInt16 Flags;
+ UInt16 HeadSize;
+ UInt32 DataSize;
+ UInt16 SubType;
+ Byte Level; // Reserved : Must be 0
+};
+
+struct CCommentBlock
+{
+ UInt16 HeadCRC;
+ Byte HeadType;
+ UInt16 Flags;
+ UInt16 HeadSize;
+ UInt16 UnpSize;
+ Byte UnpVer;
+ Byte Method;
+ UInt16 CommCRC;
+};
+
+
+struct CProtectHeader
+{
+ UInt16 HeadCRC;
+ Byte HeadType;
+ UInt16 Flags;
+ UInt16 HeadSize;
+ UInt32 DataSize;
+ Byte Version;
+ UInt16 RecSectors;
+ UInt32 TotalBlocks;
+ Byte Mark[8];
+};
+*/
+
+}}}
+
+#endif
diff --git a/CPP/7zip/Archive/Rar/RarItem.h b/CPP/7zip/Archive/Rar/RarItem.h
new file mode 100644
index 0000000..e1028ba
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/RarItem.h
@@ -0,0 +1,97 @@
+// RarItem.h
+
+#ifndef ZIP7_INC_ARCHIVE_RAR_ITEM_H
+#define ZIP7_INC_ARCHIVE_RAR_ITEM_H
+
+#include "../../../Common/StringConvert.h"
+
+#include "RarHeader.h"
+
+namespace NArchive {
+namespace NRar {
+
+struct CRarTime
+{
+ UInt32 DosTime;
+ Byte LowSecond;
+ Byte SubTime[3];
+};
+
+struct CItem
+{
+ UInt64 Size;
+ UInt64 PackSize;
+
+ CRarTime CTime;
+ CRarTime ATime;
+ CRarTime MTime;
+
+ UInt32 FileCRC;
+ UInt32 Attrib;
+
+ UInt16 Flags;
+ Byte HostOS;
+ Byte UnPackVersion;
+ Byte Method;
+
+ bool CTimeDefined;
+ bool ATimeDefined;
+
+ AString Name;
+ UString UnicodeName;
+
+ Byte Salt[8];
+
+ bool Is_Size_Defined() const { return Size != (UInt64)(Int64)-1; }
+
+ bool IsEncrypted() const { return (Flags & NHeader::NFile::kEncrypted) != 0; }
+ bool IsSolid() const { return (Flags & NHeader::NFile::kSolid) != 0; }
+ bool IsCommented() const { return (Flags & NHeader::NFile::kComment) != 0; }
+ bool IsSplitBefore() const { return (Flags & NHeader::NFile::kSplitBefore) != 0; }
+ bool IsSplitAfter() const { return (Flags & NHeader::NFile::kSplitAfter) != 0; }
+ bool HasSalt() const { return (Flags & NHeader::NFile::kSalt) != 0; }
+ bool HasExtTime() const { return (Flags & NHeader::NFile::kExtTime) != 0; }
+ bool HasUnicodeName()const { return (Flags & NHeader::NFile::kUnicodeName) != 0; }
+ bool IsOldVersion() const { return (Flags & NHeader::NFile::kOldVersion) != 0; }
+
+ UInt32 GetDictSize() const { return (Flags >> NHeader::NFile::kDictBitStart) & NHeader::NFile::kDictMask; }
+ bool IsDir() const;
+ bool IgnoreItem() const;
+ UInt32 GetWinAttrib() const;
+
+ UInt64 Position;
+ unsigned MainPartSize;
+ UInt16 CommentSize;
+ UInt16 AlignSize;
+
+ // int BaseFileIndex;
+ // bool IsAltStream;
+
+ UString GetName() const
+ {
+ if (( /* IsAltStream || */ HasUnicodeName()) && !UnicodeName.IsEmpty())
+ return UnicodeName;
+ return MultiByteToUnicodeString(Name, CP_OEMCP);
+ }
+
+ void Clear()
+ {
+ CTimeDefined = false;
+ ATimeDefined = false;
+ Name.Empty();
+ UnicodeName.Empty();
+ // IsAltStream = false;
+ // BaseFileIndex = -1;
+ }
+
+ CItem() { Clear(); }
+
+ UInt64 GetFullSize() const { return MainPartSize + CommentSize + AlignSize + PackSize; }
+ // DWORD GetHeaderWithCommentSize() const { return MainPartSize + CommentSize; }
+ UInt64 GetCommentPosition() const { return Position + MainPartSize; }
+ UInt64 GetDataPosition() const { return GetCommentPosition() + CommentSize + AlignSize; }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Rar/RarVol.h b/CPP/7zip/Archive/Rar/RarVol.h
new file mode 100644
index 0000000..9ee8e86
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/RarVol.h
@@ -0,0 +1,136 @@
+// RarVol.h
+
+#ifndef ZIP7_INC_ARCHIVE_RAR_VOL_H
+#define ZIP7_INC_ARCHIVE_RAR_VOL_H
+
+#include "../../../Common/StringConvert.h"
+
+#include "RarHeader.h"
+
+namespace NArchive {
+namespace NRar {
+
+inline bool IsDigit(wchar_t c)
+{
+ return c >= L'0' && c <= L'9';
+}
+
+class CVolumeName
+{
+ bool _needChangeForNext;
+ UString _before;
+ UString _changed;
+ UString _after;
+public:
+ CVolumeName(): _needChangeForNext(true) {}
+
+ bool InitName(const UString &name, bool newStyle = true)
+ {
+ _needChangeForNext = true;
+ _after.Empty();
+ UString base (name);
+ const int dotPos = name.ReverseFind_Dot();
+
+ if (dotPos >= 0)
+ {
+ const UString ext (name.Ptr(dotPos + 1));
+ if (ext.IsEqualTo_Ascii_NoCase("rar"))
+ {
+ _after = name.Ptr(dotPos);
+ base.DeleteFrom(dotPos);
+ }
+ else if (ext.IsEqualTo_Ascii_NoCase("exe"))
+ {
+ _after = ".rar";
+ base.DeleteFrom(dotPos);
+ }
+ else if (!newStyle)
+ {
+ if (ext.IsEqualTo_Ascii_NoCase("000") ||
+ ext.IsEqualTo_Ascii_NoCase("001") ||
+ ext.IsEqualTo_Ascii_NoCase("r00") ||
+ ext.IsEqualTo_Ascii_NoCase("r01"))
+ {
+ _changed = ext;
+ _before.SetFrom(name.Ptr(), (unsigned)dotPos + 1);
+ return true;
+ }
+ }
+ }
+
+ if (newStyle)
+ {
+ unsigned k = base.Len();
+
+ for (; k != 0; k--)
+ if (IsDigit(base[k - 1]))
+ break;
+
+ unsigned i = k;
+
+ for (; i != 0; i--)
+ if (!IsDigit(base[i - 1]))
+ break;
+
+ if (i != k)
+ {
+ _before.SetFrom(base.Ptr(), i);
+ _changed.SetFrom(base.Ptr(i), k - i);
+ _after.Insert(0, base.Ptr(k));
+ return true;
+ }
+ }
+
+ _after.Empty();
+ _before = base;
+ _before.Add_Dot();
+ _changed = "r00";
+ _needChangeForNext = false;
+ return true;
+ }
+
+ /*
+ void MakeBeforeFirstName()
+ {
+ unsigned len = _changed.Len();
+ _changed.Empty();
+ for (unsigned i = 0; i < len; i++)
+ _changed += L'0';
+ }
+ */
+
+ UString GetNextName()
+ {
+ if (_needChangeForNext)
+ {
+ unsigned i = _changed.Len();
+ if (i == 0)
+ return UString();
+ for (;;)
+ {
+ wchar_t c = _changed[--i];
+ if (c == L'9')
+ {
+ c = L'0';
+ _changed.ReplaceOneCharAtPos(i, c);
+ if (i == 0)
+ {
+ _changed.InsertAtFront(L'1');
+ break;
+ }
+ continue;
+ }
+ c++;
+ _changed.ReplaceOneCharAtPos(i, c);
+ break;
+ }
+ }
+
+ _needChangeForNext = true;
+ return _before + _changed + _after;
+ }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Rar/StdAfx.cpp b/CPP/7zip/Archive/Rar/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Archive/Rar/StdAfx.h b/CPP/7zip/Archive/Rar/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Archive/Rar/StdAfx.h
@@ -0,0 +1,11 @@
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Archive/RpmHandler.cpp b/CPP/7zip/Archive/RpmHandler.cpp
new file mode 100644
index 0000000..e05ac26
--- /dev/null
+++ b/CPP/7zip/Archive/RpmHandler.cpp
@@ -0,0 +1,769 @@
+// RpmHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/MyBuffer.h"
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/StringConvert.h"
+#include "../../Common/UTFConvert.h"
+
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/PropVariantUtils.h"
+#include "../../Windows/TimeUtils.h"
+
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "HandlerCont.h"
+
+// #define Z7_RPM_SHOW_METADATA
+
+using namespace NWindows;
+
+#define Get16(p) GetBe16(p)
+#define Get32(p) GetBe32(p)
+
+namespace NArchive {
+namespace NRpm {
+
+static const unsigned kNameSize = 66;
+static const unsigned kLeadSize = kNameSize + 30;
+static const unsigned k_HeaderSig_Size = 16;
+static const unsigned k_Entry_Size = 16;
+
+#define RPMSIG_NONE 0 // Old signature
+#define RPMSIG_PGP262_1024 1 // Old signature
+#define RPMSIG_HEADERSIG 5 // New signature
+
+enum
+{
+ kRpmType_Bin = 0,
+ kRpmType_Src = 1
+};
+
+// There are two sets of TAGs: signature tags and header tags
+
+// ----- Signature TAGs -----
+
+#define RPMSIGTAG_SIZE 1000 // Header + Payload size (32bit)
+
+// ----- Header TAGs -----
+
+#define RPMTAG_NAME 1000
+#define RPMTAG_VERSION 1001
+#define RPMTAG_RELEASE 1002
+#define RPMTAG_BUILDTIME 1006
+#define RPMTAG_OS 1021 // string (old version used int?)
+#define RPMTAG_ARCH 1022 // string (old version used int?)
+#define RPMTAG_PAYLOADFORMAT 1124
+#define RPMTAG_PAYLOADCOMPRESSOR 1125
+// #define RPMTAG_PAYLOADFLAGS 1126
+
+enum
+{
+ k_EntryType_NULL,
+ k_EntryType_CHAR,
+ k_EntryType_INT8,
+ k_EntryType_INT16,
+ k_EntryType_INT32,
+ k_EntryType_INT64,
+ k_EntryType_STRING,
+ k_EntryType_BIN,
+ k_EntryType_STRING_ARRAY,
+ k_EntryType_I18NSTRING
+};
+
+static const char * const k_CPUs[] =
+{
+ "noarch"
+ , "i386"
+ , "alpha"
+ , "sparc"
+ , "mips"
+ , "ppc"
+ , "m68k"
+ , "sgi"
+ , "rs6000"
+ , "ia64"
+ , "sparc64" // 10 ???
+ , "mipsel"
+ , "arm"
+ , "m68kmint"
+ , "s390"
+ , "s390x"
+ , "ppc64"
+ , "sh"
+ , "xtensa"
+ , "aarch64" // 19
+};
+
+static const char * const k_OS[] =
+{
+ "0"
+ , "Linux"
+ , "Irix"
+ , "solaris"
+ , "SunOS"
+ , "AmigaOS" // AIX
+ , "HP-UX"
+ , "osf"
+ , "FreeBSD"
+ , "SCO_SV"
+ , "Irix64"
+ , "NextStep"
+ , "bsdi"
+ , "machten"
+ , "cygwin32-NT"
+ , "cygwin32-95"
+ , "MP_RAS"
+ , "MiNT"
+ , "OS/390"
+ , "VM/ESA"
+ , "Linux/390" // "Linux/ESA"
+ , "Darwin" // "MacOSX" 21
+};
+
+struct CLead
+{
+ unsigned char Major;
+ unsigned char Minor;
+ UInt16 Type;
+ UInt16 Cpu;
+ UInt16 Os;
+ UInt16 SignatureType;
+ char Name[kNameSize];
+ // char Reserved[16];
+
+ void Parse(const Byte *p)
+ {
+ Major = p[4];
+ Minor = p[5];
+ Type = Get16(p + 6);
+ Cpu= Get16(p + 8);
+ memcpy(Name, p + 10, kNameSize);
+ p += 10 + kNameSize;
+ Os = Get16(p);
+ SignatureType = Get16(p + 2);
+ }
+
+ bool IsSupported() const { return Major >= 3 && Type <= 1; }
+};
+
+struct CEntry
+{
+ UInt32 Tag;
+ UInt32 Type;
+ UInt32 Offset;
+ UInt32 Count;
+
+ void Parse(const Byte *p)
+ {
+ Tag = Get32(p + 0);
+ Type = Get32(p + 4);
+ Offset = Get32(p + 8);
+ Count = Get32(p + 12);
+ }
+};
+
+
+#ifdef Z7_RPM_SHOW_METADATA
+struct CMetaFile
+{
+ UInt32 Tag;
+ UInt32 Offset;
+ UInt32 Size;
+};
+#endif
+
+Z7_class_CHandler_final: public CHandlerCont
+{
+ Z7_IFACE_COM7_IMP(IInArchive_Cont)
+
+ UInt64 _headersSize; // is equal to start offset of payload data
+ UInt64 _payloadSize;
+ UInt64 _size;
+ // _size = _payloadSize, if (_payloadSize_Defined)
+ // _size = (fileSize - _headersSize), if (!_payloadSize_Defined)
+ UInt64 _phySize; // _headersSize + _payloadSize, if (_phySize_Defined)
+ UInt32 _headerPlusPayload_Size;
+ UInt32 _buildTime;
+
+ bool _payloadSize_Defined;
+ bool _phySize_Defined;
+ bool _headerPlusPayload_Size_Defined;
+ bool _time_Defined;
+
+ Byte _payloadSig[6]; // start data of payload
+
+ AString _name; // p7zip
+ AString _version; // 9.20.1
+ AString _release; // 8.1.1
+ AString _arch; // x86_64
+ AString _os; // linux
+
+ AString _format; // cpio
+ AString _compressor; // xz, gzip, bzip2
+
+ CLead _lead;
+
+ #ifdef Z7_RPM_SHOW_METADATA
+ AString _metadata;
+ CRecordVector<CMetaFile> _metaFiles;
+ #endif
+
+ void SetTime(NCOM::CPropVariant &prop) const
+ {
+ if (_time_Defined && _buildTime != 0)
+ PropVariant_SetFrom_UnixTime(prop, _buildTime);
+ }
+
+ void SetStringProp(const AString &s, NCOM::CPropVariant &prop) const
+ {
+ UString us;
+ if (!ConvertUTF8ToUnicode(s, us))
+ us = GetUnicodeString(s);
+ if (!us.IsEmpty())
+ prop = us;
+ }
+
+ void AddCPU(AString &s) const;
+ AString GetBaseName() const;
+ void AddSubFileExtension(AString &res) const;
+
+ HRESULT ReadHeader(ISequentialInStream *stream, bool isMainHeader);
+ HRESULT Open2(ISequentialInStream *stream);
+
+ virtual int GetItem_ExtractInfo(UInt32 /* index */, UInt64 &pos, UInt64 &size) const Z7_override
+ {
+ pos = _headersSize;
+ size = _size;
+ return NExtract::NOperationResult::kOK;
+ }
+};
+
+static const Byte kArcProps[] =
+{
+ kpidHeadersSize,
+ kpidCpu,
+ kpidHostOS,
+ kpidCTime
+ #ifdef Z7_RPM_SHOW_METADATA
+ , kpidComment
+ #endif
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidCTime
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+void CHandler::AddCPU(AString &s) const
+{
+ if (!_arch.IsEmpty())
+ s += _arch;
+ else
+ {
+ if (_lead.Type == kRpmType_Bin)
+ {
+ if (_lead.Cpu < Z7_ARRAY_SIZE(k_CPUs))
+ s += k_CPUs[_lead.Cpu];
+ else
+ s.Add_UInt32(_lead.Cpu);
+ }
+ }
+}
+
+AString CHandler::GetBaseName() const
+{
+ AString s;
+ if (!_name.IsEmpty())
+ {
+ s = _name;
+ if (!_version.IsEmpty())
+ {
+ s.Add_Minus();
+ s += _version;
+ }
+ if (!_release.IsEmpty())
+ {
+ s.Add_Minus();
+ s += _release;
+ }
+ }
+ else
+ s.SetFrom_CalcLen(_lead.Name, kNameSize);
+
+ s.Add_Dot();
+ if (_lead.Type == kRpmType_Src)
+ s += "src";
+ else
+ AddCPU(s);
+ return s;
+}
+
+void CHandler::AddSubFileExtension(AString &res) const
+{
+ if (!_format.IsEmpty())
+ res += _format;
+ else
+ res += "cpio";
+ res.Add_Dot();
+
+ const char *s;
+
+ if (!_compressor.IsEmpty())
+ {
+ s = _compressor;
+ if (_compressor == "bzip2")
+ s = "bz2";
+ else if (_compressor == "gzip")
+ s = "gz";
+ }
+ else
+ {
+ const Byte *p = _payloadSig;
+ if (p[0] == 0x1F && p[1] == 0x8B)
+ s = "gz";
+ else if (p[0] == 0xFD && p[1] == '7' && p[2] == 'z' && p[3] == 'X' && p[4] == 'Z' && p[5] == 0)
+ s = "xz";
+ else if (p[0] == 'B' && p[1] == 'Z' && p[2] == 'h' && p[3] >= '1' && p[3] <= '9')
+ s = "bz2";
+ else
+ s = "lzma";
+ }
+
+ res += s;
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidMainSubfile: prop = (UInt32)0; break;
+
+ case kpidHeadersSize: prop = _headersSize; break;
+ case kpidPhySize: if (_phySize_Defined) prop = _phySize; break;
+
+ case kpidMTime:
+ case kpidCTime:
+ SetTime(prop);
+ break;
+
+ case kpidCpu:
+ {
+ AString s;
+ AddCPU(s);
+ /*
+ if (_lead.Type == kRpmType_Src)
+ s = "src";
+ */
+ SetStringProp(s, prop);
+ break;
+ }
+
+ case kpidHostOS:
+ {
+ if (!_os.IsEmpty())
+ SetStringProp(_os, prop);
+ else
+ {
+ TYPE_TO_PROP(k_OS, _lead.Os, prop);
+ }
+ break;
+ }
+
+ #ifdef Z7_RPM_SHOW_METADATA
+ // case kpidComment: SetStringProp(_metadata, prop); break;
+ #endif
+
+ case kpidName:
+ {
+ SetStringProp(GetBaseName() + ".rpm", prop);
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ NWindows::NCOM::CPropVariant prop;
+ if (index == 0)
+ switch (propID)
+ {
+ case kpidSize:
+ case kpidPackSize:
+ prop = _size;
+ break;
+
+ case kpidMTime:
+ case kpidCTime:
+ SetTime(prop);
+ break;
+
+ case kpidPath:
+ {
+ AString s (GetBaseName());
+ s.Add_Dot();
+ AddSubFileExtension(s);
+ SetStringProp(s, prop);
+ break;
+ }
+
+ /*
+ case kpidExtension:
+ {
+ prop = GetSubFileExtension();
+ break;
+ }
+ */
+ }
+ #ifdef Z7_RPM_SHOW_METADATA
+ else
+ {
+ index--;
+ if (index > _metaFiles.Size())
+ return E_INVALIDARG;
+ const CMetaFile &meta = _metaFiles[index];
+ switch (propID)
+ {
+ case kpidSize:
+ case kpidPackSize:
+ prop = meta.Size;
+ break;
+
+ case kpidMTime:
+ case kpidCTime:
+ SetTime(prop);
+ break;
+
+ case kpidPath:
+ {
+ AString s ("[META]");
+ s.Add_PathSepar();
+ s.Add_UInt32(meta.Tag);
+ prop = s;
+ break;
+ }
+ }
+ }
+ #endif
+
+ prop.Detach(value);
+ return S_OK;
+}
+
+#ifdef Z7_RPM_SHOW_METADATA
+static inline char GetHex(unsigned value)
+{
+ return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+}
+#endif
+
+HRESULT CHandler::ReadHeader(ISequentialInStream *stream, bool isMainHeader)
+{
+ UInt32 numEntries;
+ UInt32 dataLen;
+ {
+ char buf[k_HeaderSig_Size];
+ RINOK(ReadStream_FALSE(stream, buf, k_HeaderSig_Size))
+ if (Get32(buf) != 0x8EADE801) // buf[3] = 0x01 - is version
+ return S_FALSE;
+ // reserved = Get32(buf + 4);
+ numEntries = Get32(buf + 8);
+ dataLen = Get32(buf + 12);
+ if (numEntries >= 1 << 24)
+ return S_FALSE;
+ }
+ size_t indexSize = (size_t)numEntries * k_Entry_Size;
+ size_t headerSize = indexSize + dataLen;
+ if (headerSize < dataLen)
+ return S_FALSE;
+ CByteBuffer buffer(headerSize);
+ RINOK(ReadStream_FALSE(stream, buffer, headerSize))
+
+ for (UInt32 i = 0; i < numEntries; i++)
+ {
+ CEntry entry;
+
+ entry.Parse(buffer + (size_t)i * k_Entry_Size);
+ if (entry.Offset > dataLen)
+ return S_FALSE;
+
+ const Byte *p = buffer + indexSize + entry.Offset;
+ size_t rem = dataLen - entry.Offset;
+
+ if (!isMainHeader)
+ {
+ if (entry.Tag == RPMSIGTAG_SIZE &&
+ entry.Type == k_EntryType_INT32)
+ {
+ if (rem < 4 || entry.Count != 1)
+ return S_FALSE;
+ _headerPlusPayload_Size = Get32(p);
+ _headerPlusPayload_Size_Defined = true;
+ }
+ }
+ else
+ {
+ #ifdef Z7_RPM_SHOW_METADATA
+ {
+ _metadata.Add_UInt32(entry.Tag);
+ _metadata += ": ";
+ }
+ #endif
+
+ if (entry.Type == k_EntryType_STRING)
+ {
+ if (entry.Count != 1)
+ return S_FALSE;
+ size_t j;
+ for (j = 0; j < rem && p[j] != 0; j++);
+ if (j == rem)
+ return S_FALSE;
+ AString s((const char *)p);
+ switch (entry.Tag)
+ {
+ case RPMTAG_NAME: _name = s; break;
+ case RPMTAG_VERSION: _version = s; break;
+ case RPMTAG_RELEASE: _release = s; break;
+ case RPMTAG_ARCH: _arch = s; break;
+ case RPMTAG_OS: _os = s; break;
+ case RPMTAG_PAYLOADFORMAT: _format = s; break;
+ case RPMTAG_PAYLOADCOMPRESSOR: _compressor = s; break;
+ }
+
+ #ifdef Z7_RPM_SHOW_METADATA
+ _metadata += s;
+ #endif
+ }
+ else if (entry.Type == k_EntryType_INT32)
+ {
+ if (rem / 4 < entry.Count)
+ return S_FALSE;
+ if (entry.Tag == RPMTAG_BUILDTIME)
+ {
+ if (entry.Count != 1)
+ return S_FALSE;
+ _buildTime = Get32(p);
+ _time_Defined = true;
+ }
+
+ #ifdef Z7_RPM_SHOW_METADATA
+ for (UInt32 t = 0; t < entry.Count; t++)
+ {
+ if (t != 0)
+ _metadata.Add_Space();
+ _metadata.Add_UInt32(Get32(p + t * 4));
+ }
+ #endif
+ }
+
+ #ifdef Z7_RPM_SHOW_METADATA
+
+ else if (
+ entry.Type == k_EntryType_STRING_ARRAY ||
+ entry.Type == k_EntryType_I18NSTRING)
+ {
+ const Byte *p2 = p;
+ size_t rem2 = rem;
+ for (UInt32 t = 0; t < entry.Count; t++)
+ {
+ if (rem2 == 0)
+ return S_FALSE;
+ if (t != 0)
+ _metadata += '\n';
+ size_t j;
+ for (j = 0; j < rem2 && p2[j] != 0; j++);
+ if (j == rem2)
+ return S_FALSE;
+ _metadata += (const char *)p2;
+ j++;
+ p2 += j;
+ rem2 -= j;
+ }
+ }
+ else if (entry.Type == k_EntryType_INT16)
+ {
+ if (rem / 2 < entry.Count)
+ return S_FALSE;
+ for (UInt32 t = 0; t < entry.Count; t++)
+ {
+ if (t != 0)
+ _metadata.Add_Space();
+ _metadata.Add_UInt32(Get16(p + t * 2));
+ }
+ }
+ else if (entry.Type == k_EntryType_BIN)
+ {
+ if (rem < entry.Count)
+ return S_FALSE;
+ for (UInt32 t = 0; t < entry.Count; t++)
+ {
+ const unsigned b = p[t];
+ _metadata += GetHex((b >> 4) & 0xF);
+ _metadata += GetHex(b & 0xF);
+ }
+ }
+ else
+ {
+ // p = p;
+ }
+
+ _metadata += '\n';
+ #endif
+ }
+
+ #ifdef Z7_RPM_SHOW_METADATA
+ CMetaFile meta;
+ meta.Offset = entry.Offset;
+ meta.Tag = entry.Tag;
+ meta.Size = entry.Count;
+ _metaFiles.Add(meta);
+ #endif
+ }
+
+ headerSize += k_HeaderSig_Size;
+ _headersSize += headerSize;
+ if (isMainHeader && _headerPlusPayload_Size_Defined)
+ {
+ if (_headerPlusPayload_Size < headerSize)
+ return S_FALSE;
+ _payloadSize = _headerPlusPayload_Size - headerSize;
+ _size = _payloadSize;
+ _phySize = _headersSize + _payloadSize;
+ _payloadSize_Defined = true;
+ _phySize_Defined = true;
+ }
+ return S_OK;
+}
+
+HRESULT CHandler::Open2(ISequentialInStream *stream)
+{
+ {
+ Byte buf[kLeadSize];
+ RINOK(ReadStream_FALSE(stream, buf, kLeadSize))
+ if (Get32(buf) != 0xEDABEEDB)
+ return S_FALSE;
+ _lead.Parse(buf);
+ if (!_lead.IsSupported())
+ return S_FALSE;
+ }
+
+ _headersSize = kLeadSize;
+
+ if (_lead.SignatureType == RPMSIG_NONE)
+ {
+
+ }
+ else if (_lead.SignatureType == RPMSIG_PGP262_1024)
+ {
+ Byte temp[256];
+ RINOK(ReadStream_FALSE(stream, temp, sizeof(temp)))
+ }
+ else if (_lead.SignatureType == RPMSIG_HEADERSIG)
+ {
+ RINOK(ReadHeader(stream, false))
+ unsigned pos = (unsigned)_headersSize & 7;
+ if (pos != 0)
+ {
+ Byte temp[8];
+ unsigned num = 8 - pos;
+ RINOK(ReadStream_FALSE(stream, temp, num))
+ _headersSize += num;
+ }
+ }
+ else
+ return S_FALSE;
+
+ return ReadHeader(stream, true);
+}
+
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *))
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ RINOK(Open2(inStream))
+
+ // start of payload is allowed to be unaligned
+ RINOK(ReadStream_FALSE(inStream, _payloadSig, sizeof(_payloadSig)))
+
+ if (!_payloadSize_Defined)
+ {
+ UInt64 endPos;
+ RINOK(InStream_GetSize_SeekToEnd(inStream, endPos))
+ _size = endPos - _headersSize;
+ }
+ _stream = inStream;
+ return S_OK;
+ }
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _headersSize = 0;
+ _payloadSize = 0;
+ _size = 0;
+ _phySize = 0;
+ _headerPlusPayload_Size = 0;
+
+ _payloadSize_Defined = false;
+ _phySize_Defined = false;
+ _headerPlusPayload_Size_Defined = false;
+ _time_Defined = false;
+
+ _name.Empty();
+ _version.Empty();
+ _release.Empty();
+ _arch.Empty();
+ _os.Empty();
+
+ _format.Empty();
+ _compressor.Empty();
+
+ #ifdef Z7_RPM_SHOW_METADATA
+ _metadata.Empty();
+ _metaFiles.Size();
+ #endif
+
+ _stream.Release();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = 1
+ #ifdef Z7_RPM_SHOW_METADATA
+ + _metaFiles.Size()
+ #endif
+ ;
+
+ return S_OK;
+}
+
+static const Byte k_Signature[] = { 0xED, 0xAB, 0xEE, 0xDB};
+
+REGISTER_ARC_I(
+ "Rpm", "rpm", NULL, 0xEB,
+ k_Signature,
+ 0,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/SparseHandler.cpp b/CPP/7zip/Archive/SparseHandler.cpp
new file mode 100644
index 0000000..ab76f32
--- /dev/null
+++ b/CPP/7zip/Archive/SparseHandler.cpp
@@ -0,0 +1,547 @@
+// SparseHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+
+#include "../../Windows/PropVariantUtils.h"
+
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "HandlerCont.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
+#define G16(_offs_, dest) dest = Get16(p + (_offs_));
+#define G32(_offs_, dest) dest = Get32(p + (_offs_));
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NSparse {
+
+// libsparse and simg2img
+
+struct CHeader
+{
+ // UInt32 magic; /* 0xed26ff3a */
+ // UInt16 major_version; /* (0x1) - reject images with higher major versions */
+ // UInt16 minor_version; /* (0x0) - allow images with higer minor versions */
+ UInt16 file_hdr_sz; /* 28 bytes for first revision of the file format */
+ UInt16 chunk_hdr_sz; /* 12 bytes for first revision of the file format */
+ UInt32 BlockSize; /* block size in bytes, must be a multiple of 4 (4096) */
+ UInt32 NumBlocks; /* total blocks in the non-sparse output image */
+ UInt32 NumChunks; /* total chunks in the sparse input image */
+ // UInt32 image_checksum; /* CRC32 checksum of the original data, counting "don't care" as 0. */
+
+ void Parse(const Byte *p)
+ {
+ // G16 (4, major_version);
+ // G16 (6, minor_version);
+ G16 (8, file_hdr_sz)
+ G16 (10, chunk_hdr_sz)
+ G32 (12, BlockSize)
+ G32 (16, NumBlocks)
+ G32 (20, NumChunks)
+ // G32 (24, image_checksum);
+ }
+};
+
+// #define SPARSE_HEADER_MAGIC 0xed26ff3a
+
+#define CHUNK_TYPE_RAW 0xCAC1
+#define CHUNK_TYPE_FILL 0xCAC2
+#define CHUNK_TYPE_DONT_CARE 0xCAC3
+#define CHUNK_TYPE_CRC32 0xCAC4
+
+#define MY_CHUNK_TYPE_FILL 0
+#define MY_CHUNK_TYPE_DONT_CARE 1
+#define MY_CHUNK_TYPE_RAW_START 2
+
+static const char * const g_Methods[] =
+{
+ "RAW"
+ , "FILL"
+ , "SPARSE" // "DONT_CARE"
+ , "CRC32"
+};
+
+static const unsigned kFillSize = 4;
+
+struct CChunk
+{
+ UInt32 VirtBlock;
+ Byte Fill [kFillSize];
+ UInt64 PhyOffset;
+};
+
+static const Byte k_Signature[] = { 0x3a, 0xff, 0x26, 0xed, 1, 0 };
+
+
+Z7_class_CHandler_final: public CHandlerImg
+{
+ Z7_IFACE_COM7_IMP(IInArchive_Img)
+
+ Z7_IFACE_COM7_IMP(IInArchiveGetStream)
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+
+ CRecordVector<CChunk> Chunks;
+ UInt64 _virtSize_fromChunks;
+ unsigned _blockSizeLog;
+ UInt32 _chunkIndexPrev;
+
+ UInt64 _packSizeProcessed;
+ UInt64 _phySize;
+ UInt32 _methodFlags;
+ bool _isArc;
+ bool _headersError;
+ bool _unexpectedEnd;
+ // bool _unsupported;
+ UInt32 NumChunks; // from header
+
+ HRESULT Seek2(UInt64 offset)
+ {
+ _posInArc = offset;
+ return InStream_SeekSet(Stream, offset);
+ }
+
+ void InitSeekPositions()
+ {
+ /* (_virtPos) and (_posInArc) is used only in Read() (that calls ReadPhy()).
+ So we must reset these variables before first call of Read() */
+ Reset_VirtPos();
+ Reset_PosInArc();
+ _chunkIndexPrev = 0;
+ _packSizeProcessed = 0;
+ }
+
+ // virtual functions
+ bool Init_PackSizeProcessed() Z7_override
+ {
+ _packSizeProcessed = 0;
+ return true;
+ }
+ bool Get_PackSizeProcessed(UInt64 &size) Z7_override
+ {
+ size = _packSizeProcessed;
+ return true;
+ }
+
+ HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) Z7_override;
+ HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed);
+};
+
+
+
+static const Byte kProps[] =
+{
+ kpidSize,
+ kpidPackSize
+};
+
+static const Byte kArcProps[] =
+{
+ kpidClusterSize,
+ kpidNumBlocks,
+ kpidMethod
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ switch (propID)
+ {
+ case kpidMainSubfile: prop = (UInt32)0; break;
+ case kpidClusterSize: prop = (UInt32)((UInt32)1 << _blockSizeLog); break;
+ case kpidNumBlocks: prop = (UInt32)NumChunks; break;
+ case kpidPhySize: if (_phySize != 0) prop = _phySize; break;
+
+ case kpidMethod:
+ {
+ FLAGS_TO_PROP(g_Methods, _methodFlags, prop);
+ break;
+ }
+
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (_headersError) v |= kpv_ErrorFlags_HeadersError;
+ if (_unexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
+ // if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod;
+ if (!Stream && v == 0 && _isArc)
+ v = kpv_ErrorFlags_HeadersError;
+ if (v != 0)
+ prop = v;
+ break;
+ }
+ }
+
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ switch (propID)
+ {
+ case kpidSize: prop = _size; break;
+ case kpidPackSize: prop = _phySize; break;
+ case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break;
+ }
+
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+static unsigned GetLogSize(UInt32 size)
+{
+ unsigned k;
+ for (k = 0; k < 32; k++)
+ if (((UInt32)1 << k) == size)
+ return k;
+ return k;
+}
+
+
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
+{
+ const unsigned kHeaderSize = 28;
+ const unsigned kChunkHeaderSize = 12;
+ CHeader h;
+ {
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(stream, buf, kHeaderSize))
+ if (memcmp(buf, k_Signature, 6) != 0)
+ return S_FALSE;
+ h.Parse(buf);
+ }
+
+ if (h.file_hdr_sz != kHeaderSize ||
+ h.chunk_hdr_sz != kChunkHeaderSize)
+ return S_FALSE;
+
+ NumChunks = h.NumChunks;
+
+ const unsigned logSize = GetLogSize(h.BlockSize);
+ if (logSize < 2 || logSize >= 32)
+ return S_FALSE;
+ _blockSizeLog = logSize;
+
+ _size = (UInt64)h.NumBlocks << logSize;
+
+ if (h.NumChunks >= (UInt32)(Int32)-2) // it's our limit
+ return S_FALSE;
+
+ _isArc = true;
+ Chunks.Reserve(h.NumChunks + 1);
+ UInt64 offset = kHeaderSize;
+ UInt32 virtBlock = 0;
+ UInt32 i;
+
+ for (i = 0; i < h.NumChunks; i++)
+ {
+ {
+ const UInt32 mask = ((UInt32)1 << 16) - 1;
+ if ((i & mask) == mask && openCallback)
+ {
+ RINOK(openCallback->SetCompleted(NULL, &offset))
+ }
+ }
+ Byte buf[kChunkHeaderSize];
+ {
+ size_t processed = kChunkHeaderSize;
+ RINOK(ReadStream(stream, buf, &processed))
+ if (kChunkHeaderSize != processed)
+ {
+ offset += kChunkHeaderSize;
+ break;
+ }
+ }
+ const UInt32 type = Get32(&buf[0]);
+ const UInt32 numBlocks = Get32(&buf[4]);
+ UInt32 size = Get32(&buf[8]);
+
+ if (type < CHUNK_TYPE_RAW ||
+ type > CHUNK_TYPE_CRC32)
+ return S_FALSE;
+ if (size < kChunkHeaderSize)
+ return S_FALSE;
+ CChunk c;
+ c.PhyOffset = offset + kChunkHeaderSize;
+ c.VirtBlock = virtBlock;
+ offset += size;
+ size -= kChunkHeaderSize;
+ _methodFlags |= ((UInt32)1 << (type - CHUNK_TYPE_RAW));
+
+ if (numBlocks > h.NumBlocks - virtBlock)
+ return S_FALSE;
+
+ if (type == CHUNK_TYPE_CRC32)
+ {
+ // crc chunk must be last chunk (i == h.NumChunks -1);
+ if (size != kFillSize || numBlocks != 0)
+ return S_FALSE;
+ {
+ size_t processed = kFillSize;
+ RINOK(ReadStream(stream, c.Fill, &processed))
+ if (kFillSize != processed)
+ break;
+ }
+ continue;
+ }
+ // else
+ {
+ if (numBlocks == 0)
+ return S_FALSE;
+
+ if (type == CHUNK_TYPE_DONT_CARE)
+ {
+ if (size != 0)
+ return S_FALSE;
+ c.PhyOffset = MY_CHUNK_TYPE_DONT_CARE;
+ }
+ else if (type == CHUNK_TYPE_FILL)
+ {
+ if (size != kFillSize)
+ return S_FALSE;
+ c.PhyOffset = MY_CHUNK_TYPE_FILL;
+ size_t processed = kFillSize;
+ RINOK(ReadStream(stream, c.Fill, &processed))
+ if (kFillSize != processed)
+ break;
+ }
+ else if (type == CHUNK_TYPE_RAW)
+ {
+ /* Here we require (size == virtSize).
+ Probably original decoder also requires it.
+ But maybe size of last chunk can be non-aligned with blockSize ? */
+ const UInt32 virtSize = (numBlocks << _blockSizeLog);
+ if (size != virtSize || numBlocks != (virtSize >> _blockSizeLog))
+ return S_FALSE;
+ }
+ else
+ return S_FALSE;
+
+ virtBlock += numBlocks;
+ Chunks.AddInReserved(c);
+ if (type == CHUNK_TYPE_RAW)
+ RINOK(InStream_SeekSet(stream, offset))
+ }
+ }
+
+ if (i != h.NumChunks)
+ _unexpectedEnd = true;
+ else if (virtBlock != h.NumBlocks)
+ _headersError = true;
+
+ _phySize = offset;
+
+ {
+ CChunk c;
+ c.VirtBlock = virtBlock;
+ c.PhyOffset = offset;
+ Chunks.AddInReserved(c);
+ }
+ _virtSize_fromChunks = (UInt64)virtBlock << _blockSizeLog;
+
+ Stream = stream;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ Chunks.Clear();
+ _isArc = false;
+ _virtSize_fromChunks = 0;
+ // _unsupported = false;
+ _headersError = false;
+ _unexpectedEnd = false;
+ _phySize = 0;
+ _methodFlags = 0;
+
+ _chunkIndexPrev = 0;
+ _packSizeProcessed = 0;
+
+ // CHandlerImg:
+ Clear_HandlerImg_Vars();
+ Stream.Release();
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ *stream = NULL;
+ if (Chunks.Size() < 1)
+ return S_FALSE;
+ if (Chunks.Size() < 2 && _virtSize_fromChunks != 0)
+ return S_FALSE;
+ // if (_unsupported) return S_FALSE;
+ InitSeekPositions();
+ CMyComPtr<ISequentialInStream> streamTemp = this;
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+
+
+HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed)
+{
+ processed = 0;
+ if (offset > _phySize || offset + size > _phySize)
+ {
+ // we don't expect these cases, if (_phySize) was set correctly.
+ return S_FALSE;
+ }
+ if (offset != _posInArc)
+ {
+ const HRESULT res = Seek2(offset);
+ if (res != S_OK)
+ {
+ Reset_PosInArc(); // we don't trust seek_pos in case of error
+ return res;
+ }
+ }
+ {
+ size_t size2 = size;
+ const HRESULT res = ReadStream(Stream, data, &size2);
+ processed = (UInt32)size2;
+ _packSizeProcessed += size2;
+ _posInArc += size2;
+ if (res != S_OK)
+ Reset_PosInArc(); // we don't trust seek_pos in case of reading error
+ return res;
+ }
+}
+
+
+Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ // const unsigned kLimit = (1 << 16) + 1; if (size > kLimit) size = kLimit; // for debug
+ if (_virtPos >= _virtSize_fromChunks)
+ return S_OK;
+ {
+ const UInt64 rem = _virtSize_fromChunks - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ if (size == 0)
+ return S_OK;
+ }
+
+ UInt32 chunkIndex = _chunkIndexPrev;
+ if (chunkIndex + 1 >= Chunks.Size())
+ return S_FALSE;
+ {
+ const UInt32 blockIndex = (UInt32)(_virtPos >> _blockSizeLog);
+ if (blockIndex < Chunks[chunkIndex ].VirtBlock ||
+ blockIndex >= Chunks[chunkIndex + 1].VirtBlock)
+ {
+ unsigned left = 0, right = Chunks.Size() - 1;
+ for (;;)
+ {
+ const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ if (mid == left)
+ break;
+ if (blockIndex < Chunks[mid].VirtBlock)
+ right = mid;
+ else
+ left = mid;
+ }
+ chunkIndex = left;
+ _chunkIndexPrev = chunkIndex;
+ }
+ }
+
+ const CChunk &c = Chunks[chunkIndex];
+ const UInt64 offset = _virtPos - ((UInt64)c.VirtBlock << _blockSizeLog);
+ {
+ const UInt32 numBlocks = Chunks[chunkIndex + 1].VirtBlock - c.VirtBlock;
+ const UInt64 rem = ((UInt64)numBlocks << _blockSizeLog) - offset;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ const UInt64 phyOffset = c.PhyOffset;
+
+ if (phyOffset >= MY_CHUNK_TYPE_RAW_START)
+ {
+ UInt32 processed = 0;
+ const HRESULT res = ReadPhy(phyOffset + offset, data, size, processed);
+ if (processedSize)
+ *processedSize = processed;
+ _virtPos += processed;
+ return res;
+ }
+
+ Byte b = 0;
+
+ if (phyOffset == MY_CHUNK_TYPE_FILL)
+ {
+ const Byte b0 = c.Fill [0];
+ const Byte b1 = c.Fill [1];
+ const Byte b2 = c.Fill [2];
+ const Byte b3 = c.Fill [3];
+ if (b0 != b1 ||
+ b0 != b2 ||
+ b0 != b3)
+ {
+ if (processedSize)
+ *processedSize = size;
+ _virtPos += size;
+ Byte *dest = (Byte *)data;
+ while (size >= 4)
+ {
+ dest[0] = b0;
+ dest[1] = b1;
+ dest[2] = b2;
+ dest[3] = b3;
+ dest += 4;
+ size -= 4;
+ }
+ if (size > 0) dest[0] = b0;
+ if (size > 1) dest[1] = b1;
+ if (size > 2) dest[2] = b2;
+ return S_OK;
+ }
+ b = b0;
+ }
+ else if (phyOffset != MY_CHUNK_TYPE_DONT_CARE)
+ return S_FALSE;
+
+ memset(data, b, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+}
+
+REGISTER_ARC_I(
+ "Sparse", "simg img", NULL, 0xc2,
+ k_Signature,
+ 0,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/SplitHandler.cpp b/CPP/7zip/Archive/SplitHandler.cpp
index ffb0e33..ae7ca03 100644
--- a/CPP/7zip/Archive/SplitHandler.cpp
+++ b/CPP/7zip/Archive/SplitHandler.cpp
@@ -1,359 +1,351 @@
-// SplitHandler.cpp
-
-#include "StdAfx.h"
-
-#include "../../Common/ComTry.h"
-#include "../../Common/MyString.h"
-
-#include "../../Windows/PropVariant.h"
-
-#include "../Common/ProgressUtils.h"
-#include "../Common/RegisterArc.h"
-
-#include "../Compress/CopyCoder.h"
-
-#include "Common/MultiStream.h"
-
-using namespace NWindows;
-
-namespace NArchive {
-namespace NSplit {
-
-static const Byte kProps[] =
-{
- kpidPath,
- kpidSize
-};
-
-static const Byte kArcProps[] =
-{
- kpidNumVolumes,
- kpidTotalPhySize
-};
-
-class CHandler:
- public IInArchive,
- public IInArchiveGetStream,
- public CMyUnknownImp
-{
- CObjectVector<CMyComPtr<IInStream> > _streams;
- CRecordVector<UInt64> _sizes;
- UString _subName;
- UInt64 _totalSize;
-
- HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
-public:
- MY_UNKNOWN_IMP2(IInArchive, IInArchiveGetStream)
- INTERFACE_IInArchive(;)
- STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
-};
-
-IMP_IInArchive_Props
-IMP_IInArchive_ArcProps
-
-STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
-{
- NCOM::CPropVariant prop;
- switch (propID)
- {
- case kpidMainSubfile: prop = (UInt32)0; break;
- case kpidPhySize: if (!_sizes.IsEmpty()) prop = _sizes[0]; break;
- case kpidTotalPhySize: prop = _totalSize; break;
- case kpidNumVolumes: prop = (UInt32)_streams.Size(); break;
- }
- prop.Detach(value);
- return S_OK;
-}
-
-struct CSeqName
-{
- UString _unchangedPart;
- UString _changedPart;
- bool _splitStyle;
-
- bool GetNextName(UString &s)
- {
- {
- unsigned i = _changedPart.Len();
- for (;;)
- {
- wchar_t c = _changedPart[--i];
-
- if (_splitStyle)
- {
- if (c == 'z')
- {
- _changedPart.ReplaceOneCharAtPos(i, L'a');
- if (i == 0)
- return false;
- continue;
- }
- else if (c == 'Z')
- {
- _changedPart.ReplaceOneCharAtPos(i, L'A');
- if (i == 0)
- return false;
- continue;
- }
- }
- else
- {
- if (c == '9')
- {
- _changedPart.ReplaceOneCharAtPos(i, L'0');
- if (i == 0)
- {
- _changedPart.InsertAtFront(L'1');
- break;
- }
- continue;
- }
- }
-
- c++;
- _changedPart.ReplaceOneCharAtPos(i, c);
- break;
- }
- }
-
- s = _unchangedPart + _changedPart;
- return true;
- }
-};
-
-HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
-{
- Close();
- if (!callback)
- return S_FALSE;
-
- CMyComPtr<IArchiveOpenVolumeCallback> volumeCallback;
- callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback);
- if (!volumeCallback)
- return S_FALSE;
-
- UString name;
- {
- NCOM::CPropVariant prop;
- RINOK(volumeCallback->GetProperty(kpidName, &prop));
- if (prop.vt != VT_BSTR)
- return S_FALSE;
- name = prop.bstrVal;
- }
-
- int dotPos = name.ReverseFind_Dot();
- const UString prefix = name.Left(dotPos + 1);
- const UString ext = name.Ptr(dotPos + 1);
- UString ext2 = ext;
- ext2.MakeLower_Ascii();
-
- CSeqName seqName;
-
- unsigned numLetters = 2;
- bool splitStyle = false;
-
- if (ext2.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "aa"))
- {
- splitStyle = true;
- while (numLetters < ext2.Len())
- {
- if (ext2[ext2.Len() - numLetters - 1] != 'a')
- break;
- numLetters++;
- }
- }
- else if (ext.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "01"))
- {
- while (numLetters < ext2.Len())
- {
- if (ext2[ext2.Len() - numLetters - 1] != '0')
- break;
- numLetters++;
- }
- if (numLetters != ext.Len())
- return S_FALSE;
- }
- else
- return S_FALSE;
-
- seqName._unchangedPart = prefix + ext.Left(ext2.Len() - numLetters);
- seqName._changedPart = ext.RightPtr(numLetters);
- seqName._splitStyle = splitStyle;
-
- if (prefix.Len() < 1)
- _subName = "file";
- else
- _subName.SetFrom(prefix, prefix.Len() - 1);
-
- UInt64 size;
- {
- /*
- NCOM::CPropVariant prop;
- RINOK(volumeCallback->GetProperty(kpidSize, &prop));
- if (prop.vt != VT_UI8)
- return E_INVALIDARG;
- size = prop.uhVal.QuadPart;
- */
- RINOK(stream->Seek(0, STREAM_SEEK_END, &size));
- RINOK(stream->Seek(0, STREAM_SEEK_SET, NULL));
- }
-
- _totalSize += size;
- _sizes.Add(size);
- _streams.Add(stream);
-
- {
- const UInt64 numFiles = _streams.Size();
- RINOK(callback->SetCompleted(&numFiles, NULL));
- }
-
- for (;;)
- {
- UString fullName;
- if (!seqName.GetNextName(fullName))
- break;
- CMyComPtr<IInStream> nextStream;
- HRESULT result = volumeCallback->GetStream(fullName, &nextStream);
- if (result == S_FALSE)
- break;
- if (result != S_OK)
- return result;
- if (!nextStream)
- break;
- {
- /*
- NCOM::CPropVariant prop;
- RINOK(volumeCallback->GetProperty(kpidSize, &prop));
- if (prop.vt != VT_UI8)
- return E_INVALIDARG;
- size = prop.uhVal.QuadPart;
- */
- RINOK(nextStream->Seek(0, STREAM_SEEK_END, &size));
- RINOK(nextStream->Seek(0, STREAM_SEEK_SET, NULL));
- }
- _totalSize += size;
- _sizes.Add(size);
- _streams.Add(nextStream);
- {
- const UInt64 numFiles = _streams.Size();
- RINOK(callback->SetCompleted(&numFiles, NULL));
- }
- }
-
- if (_streams.Size() == 1)
- {
- if (splitStyle)
- return S_FALSE;
- }
- return S_OK;
-}
-
-STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback)
-{
- COM_TRY_BEGIN
- HRESULT res = Open2(stream, callback);
- if (res != S_OK)
- Close();
- return res;
- COM_TRY_END
-}
-
-STDMETHODIMP CHandler::Close()
-{
- _totalSize = 0;
- _subName.Empty();
- _streams.Clear();
- _sizes.Clear();
- return S_OK;
-}
-
-STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
-{
- *numItems = _streams.IsEmpty() ? 0 : 1;
- return S_OK;
-}
-
-STDMETHODIMP CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value)
-{
- NCOM::CPropVariant prop;
- switch (propID)
- {
- case kpidPath: prop = _subName; break;
- case kpidSize:
- case kpidPackSize:
- prop = _totalSize;
- break;
- }
- prop.Detach(value);
- return S_OK;
-}
-
-STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
- Int32 testMode, IArchiveExtractCallback *extractCallback)
-{
- COM_TRY_BEGIN
- if (numItems == 0)
- return S_OK;
- if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
- return E_INVALIDARG;
-
- UInt64 currentTotalSize = 0;
- RINOK(extractCallback->SetTotal(_totalSize));
- CMyComPtr<ISequentialOutStream> outStream;
- Int32 askMode = testMode ?
- NExtract::NAskMode::kTest :
- NExtract::NAskMode::kExtract;
- RINOK(extractCallback->GetStream(0, &outStream, askMode));
- if (!testMode && !outStream)
- return S_OK;
- RINOK(extractCallback->PrepareOperation(askMode));
-
- NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
- CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
-
- CLocalProgress *lps = new CLocalProgress;
- CMyComPtr<ICompressProgressInfo> progress = lps;
- lps->Init(extractCallback, false);
-
- FOR_VECTOR (i, _streams)
- {
- lps->InSize = lps->OutSize = currentTotalSize;
- RINOK(lps->SetCur());
- IInStream *inStream = _streams[i];
- RINOK(inStream->Seek(0, STREAM_SEEK_SET, NULL));
- RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
- currentTotalSize += copyCoderSpec->TotalSize;
- }
- outStream.Release();
- return extractCallback->SetOperationResult(NExtract::NOperationResult::kOK);
- COM_TRY_END
-}
-
-STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
-{
- COM_TRY_BEGIN
- if (index != 0)
- return E_INVALIDARG;
- *stream = 0;
- CMultiStream *streamSpec = new CMultiStream;
- CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
- FOR_VECTOR (i, _streams)
- {
- CMultiStream::CSubStreamInfo subStreamInfo;
- subStreamInfo.Stream = _streams[i];
- subStreamInfo.Size = _sizes[i];
- streamSpec->Streams.Add(subStreamInfo);
- }
- streamSpec->Init();
- *stream = streamTemp.Detach();
- return S_OK;
- COM_TRY_END
-}
-
-REGISTER_ARC_I_NO_SIG(
- "Split", "001", 0, 0xEA,
- 0,
- 0,
- NULL)
-
-}}
+// SplitHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/MyString.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+
+#include "Common/MultiStream.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NSplit {
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize
+};
+
+static const Byte kArcProps[] =
+{
+ kpidNumVolumes,
+ kpidTotalPhySize
+};
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IInArchiveGetStream
+)
+ CObjectVector<CMyComPtr<IInStream> > _streams;
+ CRecordVector<UInt64> _sizes;
+ UString _subName;
+ UInt64 _totalSize;
+
+ HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidMainSubfile: prop = (UInt32)0; break;
+ case kpidPhySize: if (!_sizes.IsEmpty()) prop = _sizes[0]; break;
+ case kpidTotalPhySize: prop = _totalSize; break;
+ case kpidNumVolumes: prop = (UInt32)_streams.Size(); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+struct CSeqName
+{
+ UString _unchangedPart;
+ UString _changedPart;
+ bool _splitStyle;
+
+ bool GetNextName(UString &s)
+ {
+ {
+ unsigned i = _changedPart.Len();
+ for (;;)
+ {
+ wchar_t c = _changedPart[--i];
+
+ if (_splitStyle)
+ {
+ if (c == 'z')
+ {
+ _changedPart.ReplaceOneCharAtPos(i, L'a');
+ if (i == 0)
+ return false;
+ continue;
+ }
+ else if (c == 'Z')
+ {
+ _changedPart.ReplaceOneCharAtPos(i, L'A');
+ if (i == 0)
+ return false;
+ continue;
+ }
+ }
+ else
+ {
+ if (c == '9')
+ {
+ _changedPart.ReplaceOneCharAtPos(i, L'0');
+ if (i == 0)
+ {
+ _changedPart.InsertAtFront(L'1');
+ break;
+ }
+ continue;
+ }
+ }
+
+ c++;
+ _changedPart.ReplaceOneCharAtPos(i, c);
+ break;
+ }
+ }
+
+ s = _unchangedPart + _changedPart;
+ return true;
+ }
+};
+
+
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
+{
+ Close();
+ if (!callback)
+ return S_FALSE;
+
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IArchiveOpenVolumeCallback,
+ volumeCallback, callback)
+ if (!volumeCallback)
+ return S_FALSE;
+
+ UString name;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(volumeCallback->GetProperty(kpidName, &prop))
+ if (prop.vt != VT_BSTR)
+ return S_FALSE;
+ name = prop.bstrVal;
+ }
+
+ const int dotPos = name.ReverseFind_Dot();
+ const UString prefix = name.Left((unsigned)(dotPos + 1));
+ const UString ext = name.Ptr((unsigned)(dotPos + 1));
+ UString ext2 = ext;
+ ext2.MakeLower_Ascii();
+
+ CSeqName seqName;
+
+ unsigned numLetters = 2;
+ bool splitStyle = false;
+
+ if (ext2.Len() >= 2 && StringsAreEqual_Ascii(ext2.RightPtr(2), "aa"))
+ {
+ splitStyle = true;
+ while (numLetters < ext2.Len())
+ {
+ if (ext2[ext2.Len() - numLetters - 1] != 'a')
+ break;
+ numLetters++;
+ }
+ }
+ else if (ext2.Len() >= 2 && (
+ StringsAreEqual_Ascii(ext2.RightPtr(2), "01")
+ || StringsAreEqual_Ascii(ext2.RightPtr(2), "00")
+ ))
+ {
+ while (numLetters < ext2.Len())
+ {
+ if (ext2[ext2.Len() - numLetters - 1] != '0')
+ break;
+ numLetters++;
+ }
+ if (numLetters != ext2.Len())
+ return S_FALSE;
+ }
+ else
+ return S_FALSE;
+
+ seqName._unchangedPart = prefix + ext.Left(ext2.Len() - numLetters);
+ seqName._changedPart = ext.RightPtr(numLetters);
+ seqName._splitStyle = splitStyle;
+
+ if (prefix.Len() < 1)
+ _subName = "file";
+ else
+ _subName.SetFrom(prefix, prefix.Len() - 1);
+
+ UInt64 size;
+ {
+ /*
+ NCOM::CPropVariant prop;
+ RINOK(volumeCallback->GetProperty(kpidSize, &prop))
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ */
+ }
+ RINOK(InStream_AtBegin_GetSize(stream, size))
+
+ _totalSize += size;
+ _sizes.Add(size);
+ _streams.Add(stream);
+
+ {
+ const UInt64 numFiles = _streams.Size();
+ RINOK(callback->SetCompleted(&numFiles, NULL))
+ }
+
+ for (;;)
+ {
+ UString fullName;
+ if (!seqName.GetNextName(fullName))
+ break;
+ CMyComPtr<IInStream> nextStream;
+ const HRESULT result = volumeCallback->GetStream(fullName, &nextStream);
+ if (result == S_FALSE)
+ break;
+ if (result != S_OK)
+ return result;
+ if (!nextStream)
+ break;
+ RINOK(InStream_AtBegin_GetSize(nextStream, size))
+ _totalSize += size;
+ _sizes.Add(size);
+ _streams.Add(nextStream);
+ {
+ const UInt64 numFiles = _streams.Size();
+ RINOK(callback->SetCompleted(&numFiles, NULL))
+ }
+ }
+
+ if (_streams.Size() == 1)
+ {
+ if (splitStyle)
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ const HRESULT res = Open2(stream, callback);
+ if (res != S_OK)
+ Close();
+ return res;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _totalSize = 0;
+ _subName.Empty();
+ _streams.Clear();
+ _sizes.Clear();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _streams.IsEmpty() ? 0 : 1;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPath: prop = _subName; break;
+ case kpidSize:
+ case kpidPackSize:
+ prop = _totalSize;
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ UInt64 currentTotalSize = 0;
+ RINOK(extractCallback->SetTotal(_totalSize))
+ CMyComPtr<ISequentialOutStream> outStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &outStream, askMode))
+ if (!testMode && !outStream)
+ return S_OK;
+ RINOK(extractCallback->PrepareOperation(askMode))
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (unsigned i = 0;; i++)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur())
+ if (i == _streams.Size())
+ break;
+ IInStream *inStream = _streams[i];
+ RINOK(InStream_SeekToBegin(inStream))
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress))
+ currentTotalSize += copyCoderSpec->TotalSize;
+ }
+ outStream.Release();
+ return extractCallback->SetOperationResult(NExtract::NOperationResult::kOK);
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ if (index != 0)
+ return E_INVALIDARG;
+ *stream = NULL;
+ CMultiStream *streamSpec = new CMultiStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ FOR_VECTOR (i, _streams)
+ {
+ CMultiStream::CSubStreamInfo subStreamInfo;
+ subStreamInfo.Stream = _streams[i];
+ subStreamInfo.Size = _sizes[i];
+ streamSpec->Streams.Add(subStreamInfo);
+ }
+ streamSpec->Init();
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+REGISTER_ARC_I_NO_SIG(
+ "Split", "001", NULL, 0xEA,
+ 0,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/SquashfsHandler.cpp b/CPP/7zip/Archive/SquashfsHandler.cpp
new file mode 100644
index 0000000..9c9ec03
--- /dev/null
+++ b/CPP/7zip/Archive/SquashfsHandler.cpp
@@ -0,0 +1,2326 @@
+// SquashfsHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+#include "../../../C/CpuArch.h"
+#include "../../../C/LzmaDec.h"
+#include "../../../C/Xz.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/MyLinux.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/StringConvert.h"
+#include "../../Common/UTFConvert.h"
+
+#include "../../Windows/PropVariantUtils.h"
+#include "../../Windows/TimeUtils.h"
+
+#include "../Common/CWrappers.h"
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+#include "../Compress/ZlibDecoder.h"
+// #include "../Compress/LzmaDecoder.h"
+
+namespace NArchive {
+namespace NSquashfs {
+
+static const UInt32 kNumFilesMax = (1 << 28);
+static const unsigned kNumDirLevelsMax = (1 << 10);
+
+// Layout: Header, Data, inodes, Directories, Fragments, UIDs, GIDs
+
+/*
+#define Get16(p) (be ? GetBe16(p) : GetUi16(p))
+#define Get32(p) (be ? GetBe32(p) : GetUi32(p))
+#define Get64(p) (be ? GetBe64(p) : GetUi64(p))
+*/
+
+static UInt16 Get16b(const Byte *p, bool be) { return be ? GetBe16(p) : GetUi16(p); }
+static UInt32 Get32b(const Byte *p, bool be) { return be ? GetBe32(p) : GetUi32(p); }
+static UInt64 Get64b(const Byte *p, bool be) { return be ? GetBe64(p) : GetUi64(p); }
+
+#define Get16(p) Get16b(p, be)
+#define Get32(p) Get32b(p, be)
+#define Get64(p) Get64b(p, be)
+
+#define LE_16(offs, dest) dest = GetUi16(p + (offs))
+#define LE_32(offs, dest) dest = GetUi32(p + (offs))
+#define LE_64(offs, dest) dest = GetUi64(p + (offs))
+
+#define GET_16(offs, dest) dest = Get16(p + (offs))
+#define GET_32(offs, dest) dest = Get32(p + (offs))
+#define GET_64(offs, dest) dest = Get64(p + (offs))
+
+static const UInt32 kSignature32_LE = 0x73717368;
+static const UInt32 kSignature32_BE = 0x68737173;
+static const UInt32 kSignature32_LZ = 0x71736873;
+static const UInt32 kSignature32_B2 = 0x73687371;
+
+#define kMethod_ZLIB 1
+#define kMethod_LZMA 2
+#define kMethod_LZO 3
+#define kMethod_XZ 4
+
+static const char * const k_Methods[] =
+{
+ "0"
+ , "ZLIB"
+ , "LZMA"
+ , "LZO"
+ , "XZ"
+};
+
+static const unsigned kMetadataBlockSizeLog = 13;
+static const UInt32 kMetadataBlockSize = (1 << kMetadataBlockSizeLog);
+
+enum
+{
+ kType_IPC,
+ kType_DIR,
+ kType_FILE,
+ kType_LNK,
+ kType_BLK,
+ kType_CHR,
+ kType_FIFO,
+ kType_SOCK
+};
+
+static const UInt32 k_TypeToMode[] =
+{
+ 0,
+ MY_LIN_S_IFDIR, MY_LIN_S_IFREG, MY_LIN_S_IFLNK, MY_LIN_S_IFBLK, MY_LIN_S_IFCHR, MY_LIN_S_IFIFO, MY_LIN_S_IFSOCK,
+ MY_LIN_S_IFDIR, MY_LIN_S_IFREG, MY_LIN_S_IFLNK, MY_LIN_S_IFBLK, MY_LIN_S_IFCHR, MY_LIN_S_IFIFO, MY_LIN_S_IFSOCK
+};
+
+
+enum
+{
+ kFlag_UNC_INODES,
+ kFlag_UNC_DATA,
+ kFlag_CHECK,
+ kFlag_UNC_FRAGS,
+ kFlag_NO_FRAGS,
+ kFlag_ALWAYS_FRAG,
+ kFlag_DUPLICATE,
+ kFlag_EXPORT
+};
+
+static const char * const k_Flags[] =
+{
+ "UNCOMPRESSED_INODES"
+ , "UNCOMPRESSED_DATA"
+ , "CHECK"
+ , "UNCOMPRESSED_FRAGMENTS"
+ , "NO_FRAGMENTS"
+ , "ALWAYS_FRAGMENTS"
+ , "DUPLICATES_REMOVED"
+ , "EXPORTABLE"
+ , "UNCOMPRESSED_XATTRS"
+ , "NO_XATTRS"
+ , "COMPRESSOR_OPTIONS"
+ , "UNCOMPRESSED_IDS"
+};
+
+static const UInt32 kNotCompressedBit16 = (1 << 15);
+static const UInt32 kNotCompressedBit32 = (1 << 24);
+
+#define GET_COMPRESSED_BLOCK_SIZE(size) ((size) & ~kNotCompressedBit32)
+#define IS_COMPRESSED_BLOCK(size) (((size) & kNotCompressedBit32) == 0)
+
+// static const UInt32 kHeaderSize1 = 0x33;
+// static const UInt32 kHeaderSize2 = 0x3F;
+static const UInt32 kHeaderSize3 = 0x77;
+// static const UInt32 kHeaderSize4 = 0x60;
+
+struct CHeader
+{
+ bool be;
+ bool SeveralMethods;
+ Byte NumUids;
+ Byte NumGids;
+
+ UInt32 NumInodes;
+ UInt32 CTime;
+ UInt32 BlockSize;
+ UInt32 NumFrags;
+ UInt16 Method;
+ UInt16 BlockSizeLog;
+ UInt16 Flags;
+ UInt16 NumIDs;
+ UInt16 Major;
+ UInt16 Minor;
+ UInt64 RootInode;
+ UInt64 Size;
+ UInt64 UidTable;
+ UInt64 GidTable;
+ UInt64 XattrIdTable;
+ UInt64 InodeTable;
+ UInt64 DirTable;
+ UInt64 FragTable;
+ UInt64 LookupTable;
+
+ void Parse3(const Byte *p)
+ {
+ Method = kMethod_ZLIB;
+ GET_32 (0x08, Size);
+ GET_32 (0x0C, UidTable);
+ GET_32 (0x10, GidTable);
+ GET_32 (0x14, InodeTable);
+ GET_32 (0x18, DirTable);
+ GET_16 (0x20, BlockSize);
+ GET_16 (0x22, BlockSizeLog);
+ Flags = p[0x24];
+ NumUids = p[0x25];
+ NumGids = p[0x26];
+ GET_32 (0x27, CTime);
+ GET_64 (0x2B, RootInode);
+ NumFrags = 0;
+ FragTable = UidTable;
+
+ if (Major >= 2)
+ {
+ GET_32 (0x33, BlockSize);
+ GET_32 (0x37, NumFrags);
+ GET_32 (0x3B, FragTable);
+ if (Major == 3)
+ {
+ GET_64 (0x3F, Size);
+ GET_64 (0x47, UidTable);
+ GET_64 (0x4F, GidTable);
+ GET_64 (0x57, InodeTable);
+ GET_64 (0x5F, DirTable);
+ GET_64 (0x67, FragTable);
+ GET_64 (0x6F, LookupTable);
+ }
+ }
+ }
+
+ void Parse4(const Byte *p)
+ {
+ LE_32 (0x08, CTime);
+ LE_32 (0x0C, BlockSize);
+ LE_32 (0x10, NumFrags);
+ LE_16 (0x14, Method);
+ LE_16 (0x16, BlockSizeLog);
+ LE_16 (0x18, Flags);
+ LE_16 (0x1A, NumIDs);
+ LE_64 (0x20, RootInode);
+ LE_64 (0x28, Size);
+ LE_64 (0x30, UidTable);
+ LE_64 (0x38, XattrIdTable);
+ LE_64 (0x40, InodeTable);
+ LE_64 (0x48, DirTable);
+ LE_64 (0x50, FragTable);
+ LE_64 (0x58, LookupTable);
+ GidTable = 0;
+ }
+
+ bool Parse(const Byte *p)
+ {
+ be = false;
+ SeveralMethods = false;
+ switch (GetUi32(p))
+ {
+ case kSignature32_LE: break;
+ case kSignature32_BE: be = true; break;
+ case kSignature32_LZ: SeveralMethods = true; break;
+ case kSignature32_B2: SeveralMethods = true; be = true; break;
+ default: return false;
+ }
+ GET_32 (4, NumInodes);
+ GET_16 (0x1C, Major);
+ GET_16 (0x1E, Minor);
+ if (Major <= 3)
+ Parse3(p);
+ else
+ {
+ if (be)
+ return false;
+ Parse4(p);
+ }
+ return
+ InodeTable < DirTable &&
+ DirTable <= FragTable &&
+ FragTable <= Size &&
+ UidTable <= Size &&
+ BlockSizeLog >= 12 &&
+ BlockSizeLog < 31 &&
+ BlockSize == ((UInt32)1 << BlockSizeLog);
+ }
+
+ bool IsSupported() const { return Major > 0 && Major <= 4 && BlockSizeLog <= 23; }
+ bool IsOldVersion() const { return Major < 4; }
+ bool NeedCheckData() const { return (Flags & (1 << kFlag_CHECK)) != 0; }
+ unsigned GetFileNameOffset() const { return Major <= 2 ? 3 : (Major == 3 ? 5 : 8); }
+ unsigned GetSymLinkOffset() const { return Major <= 1 ? 5: (Major <= 2 ? 6: (Major == 3 ? 18 : 24)); }
+ unsigned GetSpecGuidIndex() const { return Major <= 1 ? 0xF: 0xFF; }
+};
+
+static const UInt32 kFrag_Empty = (UInt32)(Int32)-1;
+// static const UInt32 kXattr_Empty = (UInt32)(Int32)-1;
+
+struct CNode
+{
+ UInt16 Type;
+ UInt16 Mode;
+ UInt16 Uid;
+ UInt16 Gid;
+ UInt32 Frag;
+ UInt32 Offset;
+ // UInt32 MTime;
+ // UInt32 Number;
+ // UInt32 NumLinks;
+ // UInt32 RDev;
+ // UInt32 Xattr;
+ // UInt32 Parent;
+
+ UInt64 FileSize;
+ UInt64 StartBlock;
+ // UInt64 Sparse;
+
+ UInt32 Parse1(const Byte *p, UInt32 size, const CHeader &_h);
+ UInt32 Parse2(const Byte *p, UInt32 size, const CHeader &_h);
+ UInt32 Parse3(const Byte *p, UInt32 size, const CHeader &_h);
+ UInt32 Parse4(const Byte *p, UInt32 size, const CHeader &_h);
+
+ bool IsDir() const { return (Type == kType_DIR || Type == kType_DIR + 7); }
+ bool IsLink() const { return (Type == kType_LNK || Type == kType_LNK + 7); }
+ UInt64 GetSize() const { return IsDir() ? 0 : FileSize; }
+
+ bool ThereAreFrags() const { return Frag != kFrag_Empty; }
+ UInt64 GetNumBlocks(const CHeader &_h) const
+ {
+ return (FileSize >> _h.BlockSizeLog) +
+ (!ThereAreFrags() && (FileSize & (_h.BlockSize - 1)) != 0);
+ }
+};
+
+UInt32 CNode::Parse1(const Byte *p, UInt32 size, const CHeader &_h)
+{
+ const bool be = _h.be;
+ if (size < 4)
+ return 0;
+ {
+ const UInt32 t = Get16(p);
+ if (be)
+ {
+ Type = (UInt16)(t >> 12);
+ Mode = (UInt16)(t & 0xFFF);
+ Uid = (UInt16)(p[2] >> 4);
+ Gid = (UInt16)(p[2] & 0xF);
+ }
+ else
+ {
+ Type = (UInt16)(t & 0xF);
+ Mode = (UInt16)(t >> 4);
+ Uid = (UInt16)(p[2] & 0xF);
+ Gid = (UInt16)(p[2] >> 4);
+ }
+ }
+
+ // Xattr = kXattr_Empty;
+ // MTime = 0;
+ FileSize = 0;
+ StartBlock = 0;
+ Frag = kFrag_Empty;
+
+ if (Type == 0)
+ {
+ Byte t = p[3];
+ if (be)
+ {
+ Type = (UInt16)(t >> 4);
+ Offset = (UInt16)(t & 0xF);
+ }
+ else
+ {
+ Type = (UInt16)(t & 0xF);
+ Offset = (UInt16)(t >> 4);
+ }
+ return (Type == kType_FIFO || Type == kType_SOCK) ? 4 : 0;
+ }
+
+ Type--;
+ Uid = (UInt16)(Uid + (Type / 5) * 16);
+ Type = (UInt16)((Type % 5) + 1);
+
+ if (Type == kType_FILE)
+ {
+ if (size < 15)
+ return 0;
+ // GET_32 (3, MTime);
+ GET_32 (7, StartBlock);
+ UInt32 t;
+ GET_32 (11, t);
+ FileSize = t;
+ UInt32 numBlocks = t >> _h.BlockSizeLog;
+ if ((t & (_h.BlockSize - 1)) != 0)
+ numBlocks++;
+ UInt32 pos = numBlocks * 2 + 15;
+ return (pos <= size) ? pos : 0;
+ }
+
+ if (Type == kType_DIR)
+ {
+ if (size < 14)
+ return 0;
+ UInt32 t = Get32(p + 3);
+ if (be)
+ {
+ FileSize = t >> 13;
+ Offset = t & 0x1FFF;
+ }
+ else
+ {
+ FileSize = t & 0x7FFFF;
+ Offset = t >> 19;
+ }
+ // GET_32 (7, MTime);
+ GET_32 (10, StartBlock);
+ if (be)
+ StartBlock &= 0xFFFFFF;
+ else
+ StartBlock >>= 8;
+ return 14;
+ }
+
+ if (size < 5)
+ return 0;
+
+ if (Type == kType_LNK)
+ {
+ UInt32 len;
+ GET_16 (3, len);
+ FileSize = len;
+ len += 5;
+ return (len <= size) ? len : 0;
+ }
+
+ // GET_32 (3, RDev);
+ return 5;
+}
+
+UInt32 CNode::Parse2(const Byte *p, UInt32 size, const CHeader &_h)
+{
+ const bool be = _h.be;
+ if (size < 4)
+ return 0;
+ {
+ const UInt32 t = Get16(p);
+ if (be)
+ {
+ Type = (UInt16)(t >> 12);
+ Mode = (UInt16)(t & 0xFFF);
+ }
+ else
+ {
+ Type = (UInt16)(t & 0xF);
+ Mode = (UInt16)(t >> 4);
+ }
+ }
+
+ Uid = p[2];
+ Gid = p[3];
+
+ // Xattr = kXattr_Empty;
+
+ if (Type == kType_FILE)
+ {
+ if (size < 24)
+ return 0;
+ // GET_32 (4, MTime);
+ GET_32 (8, StartBlock);
+ GET_32 (12, Frag);
+ GET_32 (16, Offset);
+ UInt32 t;
+ GET_32 (20, t);
+ FileSize = t;
+ UInt32 numBlocks = t >> _h.BlockSizeLog;
+ if (!ThereAreFrags() && (t & (_h.BlockSize - 1)) != 0)
+ numBlocks++;
+ UInt32 pos = numBlocks * 4 + 24;
+ return (pos <= size) ? (UInt32)pos : 0;
+ }
+
+ FileSize = 0;
+ // MTime = 0;
+ StartBlock = 0;
+ Frag = kFrag_Empty;
+
+ if (Type == kType_DIR)
+ {
+ if (size < 15)
+ return 0;
+ UInt32 t = Get32(p + 4);
+ if (be)
+ {
+ FileSize = t >> 13;
+ Offset = t & 0x1FFF;
+ }
+ else
+ {
+ FileSize = t & 0x7FFFF;
+ Offset = t >> 19;
+ }
+ // GET_32 (8, MTime);
+ GET_32 (11, StartBlock);
+ if (be)
+ StartBlock &= 0xFFFFFF;
+ else
+ StartBlock >>= 8;
+ return 15;
+ }
+
+ if (Type == kType_DIR + 7)
+ {
+ if (size < 18)
+ return 0;
+ UInt32 t = Get32(p + 4);
+ UInt32 t2 = Get16(p + 7);
+ if (be)
+ {
+ FileSize = t >> 5;
+ Offset = t2 & 0x1FFF;
+ }
+ else
+ {
+ FileSize = t & 0x7FFFFFF;
+ Offset = t2 >> 3;
+ }
+ // GET_32 (9, MTime);
+ GET_32 (12, StartBlock);
+ if (be)
+ StartBlock &= 0xFFFFFF;
+ else
+ StartBlock >>= 8;
+ UInt32 iCount;
+ GET_16 (16, iCount);
+ UInt32 pos = 18;
+ for (UInt32 i = 0; i < iCount; i++)
+ {
+ // 27 bits: index
+ // 29 bits: startBlock
+ if (pos + 8 > size)
+ return 0;
+ pos += 8 + (UInt32)p[pos + 7] + 1; // nameSize
+ if (pos > size)
+ return 0;
+ }
+ return pos;
+ }
+
+ if (Type == kType_FIFO || Type == kType_SOCK)
+ return 4;
+
+ if (size < 6)
+ return 0;
+
+ if (Type == kType_LNK)
+ {
+ UInt32 len;
+ GET_16 (4, len);
+ FileSize = len;
+ len += 6;
+ return (len <= size) ? len : 0;
+ }
+
+ if (Type == kType_BLK || Type == kType_CHR)
+ {
+ // GET_16 (4, RDev);
+ return 6;
+ }
+
+ return 0;
+}
+
+UInt32 CNode::Parse3(const Byte *p, UInt32 size, const CHeader &_h)
+{
+ const bool be = _h.be;
+ if (size < 12)
+ return 0;
+
+ {
+ const UInt32 t = Get16(p);
+ if (be)
+ {
+ Type = (UInt16)(t >> 12);
+ Mode = (UInt16)(t & 0xFFF);
+ }
+ else
+ {
+ Type = (UInt16)(t & 0xF);
+ Mode = (UInt16)(t >> 4);
+ }
+ }
+
+ Uid = p[2];
+ Gid = p[3];
+ // GET_32 (4, MTime);
+ // GET_32 (8, Number);
+ // Xattr = kXattr_Empty;
+ FileSize = 0;
+ StartBlock = 0;
+
+ if (Type == kType_FILE || Type == kType_FILE + 7)
+ {
+ UInt32 offset;
+ if (Type == kType_FILE)
+ {
+ if (size < 32)
+ return 0;
+ GET_64 (12, StartBlock);
+ GET_32 (20, Frag);
+ GET_32 (24, Offset);
+ GET_32 (28, FileSize);
+ offset = 32;
+ }
+ else
+ {
+ if (size < 40)
+ return 0;
+ // GET_32 (12, NumLinks);
+ GET_64 (16, StartBlock);
+ GET_32 (24, Frag);
+ GET_32 (28, Offset);
+ GET_64 (32, FileSize);
+ offset = 40;
+ }
+ UInt64 pos = GetNumBlocks(_h) * 4 + offset;
+ return (pos <= size) ? (UInt32)pos : 0;
+ }
+
+ if (size < 16)
+ return 0;
+ // GET_32 (12, NumLinks);
+
+ if (Type == kType_DIR)
+ {
+ if (size < 28)
+ return 0;
+ UInt32 t = Get32(p + 16);
+ if (be)
+ {
+ FileSize = t >> 13;
+ Offset = t & 0x1FFF;
+ }
+ else
+ {
+ FileSize = t & 0x7FFFF;
+ Offset = t >> 19;
+ }
+ GET_32 (20, StartBlock);
+ // GET_32 (24, Parent);
+ return 28;
+ }
+
+ if (Type == kType_DIR + 7)
+ {
+ if (size < 31)
+ return 0;
+ UInt32 t = Get32(p + 16);
+ UInt32 t2 = Get16(p + 19);
+ if (be)
+ {
+ FileSize = t >> 5;
+ Offset = t2 & 0x1FFF;
+ }
+ else
+ {
+ FileSize = t & 0x7FFFFFF;
+ Offset = t2 >> 3;
+ }
+ GET_32 (21, StartBlock);
+ UInt32 iCount;
+ GET_16 (25, iCount);
+ // GET_32 (27, Parent);
+ UInt32 pos = 31;
+ for (UInt32 i = 0; i < iCount; i++)
+ {
+ // UInt32 index
+ // UInt32 startBlock
+ if (pos + 9 > size)
+ return 0;
+ pos += 9 + (unsigned)p[pos + 8] + 1; // nameSize
+ if (pos > size)
+ return 0;
+ }
+ return pos;
+ }
+
+ if (Type == kType_FIFO || Type == kType_SOCK)
+ return 16;
+
+ if (size < 18)
+ return 0;
+ if (Type == kType_LNK)
+ {
+ UInt32 len;
+ GET_16 (16, len);
+ FileSize = len;
+ len += 18;
+ return (len <= size) ? len : 0;
+ }
+
+ if (Type == kType_BLK || Type == kType_CHR)
+ {
+ // GET_16 (16, RDev);
+ return 18;
+ }
+
+ return 0;
+}
+
+UInt32 CNode::Parse4(const Byte *p, UInt32 size, const CHeader &_h)
+{
+ if (size < 20)
+ return 0;
+ LE_16 (0, Type);
+ LE_16 (2, Mode);
+ LE_16 (4, Uid);
+ LE_16 (6, Gid);
+ // LE_32 (8, MTime);
+ // LE_32 (12, Number);
+
+ // Xattr = kXattr_Empty;
+ FileSize = 0;
+ StartBlock = 0;
+
+ if (Type == kType_FILE || Type == kType_FILE + 7)
+ {
+ UInt32 offset;
+ if (Type == kType_FILE)
+ {
+ if (size < 32)
+ return 0;
+ LE_32 (16, StartBlock);
+ LE_32 (20, Frag);
+ LE_32 (24, Offset);
+ LE_32 (28, FileSize);
+ offset = 32;
+ }
+ else
+ {
+ if (size < 56)
+ return 0;
+ LE_64 (16, StartBlock);
+ LE_64 (24, FileSize);
+ // LE_64 (32, Sparse);
+ // LE_32 (40, NumLinks);
+ LE_32 (44, Frag);
+ LE_32 (48, Offset);
+ // LE_32 (52, Xattr);
+ offset = 56;
+ }
+ UInt64 pos = GetNumBlocks(_h) * 4 + offset;
+ return (pos <= size) ? (UInt32)pos : 0;
+ }
+
+ if (Type == kType_DIR)
+ {
+ if (size < 32)
+ return 0;
+ LE_32 (16, StartBlock);
+ // LE_32 (20, NumLinks);
+ LE_16 (24, FileSize);
+ LE_16 (26, Offset);
+ // LE_32 (28, Parent);
+ return 32;
+ }
+
+ // LE_32 (16, NumLinks);
+
+ if (Type == kType_DIR + 7)
+ {
+ if (size < 40)
+ return 0;
+ LE_32 (20, FileSize);
+ LE_32 (24, StartBlock);
+ // LE_32 (28, Parent);
+ UInt32 iCount;
+ LE_16 (32, iCount);
+ LE_16 (34, Offset);
+ // LE_32 (36, Xattr);
+
+ UInt32 pos = 40;
+ for (UInt32 i = 0; i < iCount; i++)
+ {
+ // UInt32 index
+ // UInt32 startBlock
+ if (pos + 12 > size)
+ return 0;
+ UInt32 nameLen = GetUi32(p + pos + 8);
+ pos += 12 + nameLen + 1;
+ if (pos > size || nameLen > (1 << 10))
+ return 0;
+ }
+ return pos;
+ }
+
+ unsigned offset = 20;
+ switch (Type)
+ {
+ case kType_FIFO: case kType_FIFO + 7:
+ case kType_SOCK: case kType_SOCK + 7:
+ break;
+ case kType_LNK: case kType_LNK + 7:
+ {
+ if (size < 24)
+ return 0;
+ UInt32 len;
+ LE_32 (20, len);
+ FileSize = len;
+ offset = len + 24;
+ if (size < offset || len > (1 << 30))
+ return 0;
+ break;
+ }
+ case kType_BLK: case kType_BLK + 7:
+ case kType_CHR: case kType_CHR + 7:
+ if (size < 24)
+ return 0;
+ // LE_32 (20, RDev);
+ offset = 24;
+ break;
+ default:
+ return 0;
+ }
+
+ if (Type >= 8)
+ {
+ if (size < offset + 4)
+ return 0;
+ // LE_32 (offset, Xattr);
+ offset += 4;
+ }
+ return offset;
+}
+
+struct CItem
+{
+ int Node;
+ int Parent;
+ UInt32 Ptr;
+
+ CItem(): Node(-1), Parent(-1), Ptr(0) {}
+};
+
+struct CData
+{
+ CByteBuffer Data;
+ CRecordVector<UInt32> PackPos;
+ CRecordVector<UInt32> UnpackPos; // additional item at the end contains TotalUnpackSize
+
+ UInt32 GetNumBlocks() const { return PackPos.Size(); }
+ void Clear()
+ {
+ Data.Free();
+ PackPos.Clear();
+ UnpackPos.Clear();
+ }
+};
+
+struct CFrag
+{
+ UInt64 StartBlock;
+ UInt32 Size;
+};
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IInArchiveGetStream
+)
+ CRecordVector<CItem> _items;
+ CRecordVector<CNode> _nodes;
+ CRecordVector<UInt32> _nodesPos;
+ CRecordVector<UInt32> _blockToNode;
+ CData _inodesData;
+ CData _dirs;
+ CRecordVector<CFrag> _frags;
+ CByteBuffer _uids;
+ CByteBuffer _gids;
+ CHeader _h;
+ bool _noPropsLZMA;
+ bool _needCheckLzma;
+
+ UInt32 _openCodePage;
+
+ CMyComPtr<IInStream> _stream;
+ UInt64 _sizeCalculated;
+
+ IArchiveOpenCallback *_openCallback;
+
+ int _nodeIndex;
+ CRecordVector<bool> _blockCompressed;
+ CRecordVector<UInt64> _blockOffsets;
+
+ CByteBuffer _cachedBlock;
+ UInt64 _cachedBlockStartPos;
+ UInt32 _cachedPackBlockSize;
+ UInt32 _cachedUnpackBlockSize;
+
+ CLimitedSequentialInStream *_limitedInStreamSpec;
+ CMyComPtr<ISequentialInStream> _limitedInStream;
+
+ CBufPtrSeqOutStream *_outStreamSpec;
+ CMyComPtr<ISequentialOutStream> _outStream;
+
+ // NCompress::NLzma::CDecoder *_lzmaDecoderSpec;
+ // CMyComPtr<ICompressCoder> _lzmaDecoder;
+
+ NCompress::NZlib::CDecoder *_zlibDecoderSpec;
+ CMyComPtr<ICompressCoder> _zlibDecoder;
+
+ CXzUnpacker _xz;
+
+ CByteBuffer _inputBuffer;
+
+ CDynBufSeqOutStream *_dynOutStreamSpec;
+ CMyComPtr<ISequentialOutStream> _dynOutStream;
+
+ void ClearCache()
+ {
+ _cachedBlockStartPos = 0;
+ _cachedPackBlockSize = 0;
+ _cachedUnpackBlockSize = 0;
+ }
+
+ HRESULT Seek2(UInt64 offset)
+ {
+ return InStream_SeekSet(_stream, offset);
+ }
+
+ HRESULT Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize,
+ UInt32 inSize, UInt32 outSizeMax);
+ HRESULT ReadMetadataBlock(UInt32 &packSize);
+ HRESULT ReadMetadataBlock2();
+ HRESULT ReadData(CData &data, UInt64 start, UInt64 end);
+
+ HRESULT OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex);
+ HRESULT ScanInodes(UInt64 ptr);
+ HRESULT ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids);
+ HRESULT Open2(IInStream *inStream);
+ AString GetPath(unsigned index) const;
+ bool GetPackSize(unsigned index, UInt64 &res, bool fillOffsets);
+
+public:
+ CHandler();
+ ~CHandler()
+ {
+ XzUnpacker_Free(&_xz);
+ }
+
+ HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize);
+};
+
+
+CHandler::CHandler()
+{
+ XzUnpacker_Construct(&_xz, &g_Alloc);
+
+ _limitedInStreamSpec = new CLimitedSequentialInStream;
+ _limitedInStream = _limitedInStreamSpec;
+
+ _outStreamSpec = new CBufPtrSeqOutStream();
+ _outStream = _outStreamSpec;
+
+ _dynOutStreamSpec = new CDynBufSeqOutStream;
+ _dynOutStream = _dynOutStreamSpec;
+}
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidPosixAttrib,
+ kpidUserId,
+ kpidGroupId
+ // kpidLinks,
+ // kpidOffset
+};
+
+static const Byte kArcProps[] =
+{
+ kpidHeadersSize,
+ kpidFileSystem,
+ kpidMethod,
+ kpidClusterSize,
+ kpidBigEndian,
+ kpidCTime,
+ kpidCharacts,
+ kpidCodePage
+ // kpidNumBlocks
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static HRESULT LzoDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen)
+{
+ SizeT destRem = *destLen;
+ SizeT srcRem = *srcLen;
+ *destLen = 0;
+ *srcLen = 0;
+ const Byte *destStart = dest;
+ const Byte *srcStart = src;
+ unsigned mode = 0;
+
+ {
+ if (srcRem == 0)
+ return S_FALSE;
+ UInt32 b = *src;
+ if (b > 17)
+ {
+ src++;
+ srcRem--;
+ b -= 17;
+ mode = (b < 4 ? 1 : 4);
+ if (b > srcRem || b > destRem)
+ return S_FALSE;
+ srcRem -= b;
+ destRem -= b;
+ do
+ *dest++ = *src++;
+ while (--b);
+ }
+ }
+
+ for (;;)
+ {
+ if (srcRem < 3)
+ return S_FALSE;
+ UInt32 b = *src++;
+ srcRem--;
+ UInt32 len, back;
+
+ if (b >= 64)
+ {
+ srcRem--;
+ back = ((b >> 2) & 7) + ((UInt32)*src++ << 3);
+ len = (b >> 5) + 1;
+ }
+ else if (b < 16)
+ {
+ if (mode == 0)
+ {
+ if (b == 0)
+ {
+ for (b = 15;; b += 255)
+ {
+ if (srcRem == 0)
+ return S_FALSE;
+ UInt32 b2 = *src++;
+ srcRem--;
+ if (b2 != 0)
+ {
+ b += b2;
+ break;
+ }
+ }
+ }
+
+ b += 3;
+ if (b > srcRem || b > destRem)
+ return S_FALSE;
+ srcRem -= b;
+ destRem -= b;
+ mode = 4;
+ do
+ *dest++ = *src++;
+ while (--b);
+ continue;
+ }
+
+ srcRem--;
+ back = (b >> 2) + ((UInt32)*src++ << 2);
+ len = 2;
+ if (mode == 4)
+ {
+ back += (1 << 11);
+ len = 3;
+ }
+ }
+ else
+ {
+ UInt32 bOld = b;
+ b = (b < 32 ? 7 : 31);
+ len = bOld & b;
+
+ if (len == 0)
+ {
+ for (len = b;; len += 255)
+ {
+ if (srcRem == 0)
+ return S_FALSE;
+ UInt32 b2 = *src++;
+ srcRem--;
+ if (b2 != 0)
+ {
+ len += b2;
+ break;
+ }
+ }
+ }
+
+ len += 2;
+ if (srcRem < 2)
+ return S_FALSE;
+ b = *src;
+ back = (b >> 2) + ((UInt32)src[1] << 6);
+ src += 2;
+ srcRem -= 2;
+ if (bOld < 32)
+ {
+ back += ((bOld & 8) << 11);
+ if (back == 0)
+ {
+ *destLen = (size_t)(dest - destStart);
+ *srcLen = (size_t)(src - srcStart);
+ return S_OK;
+ }
+ back += (1 << 14) - 1;
+ }
+ }
+
+ back++;
+ if (len > destRem || (size_t)(dest - destStart) < back)
+ return S_FALSE;
+ destRem -= len;
+ Byte *destTemp = dest - back;
+ dest += len;
+
+ do
+ {
+ *(destTemp + back) = *destTemp;
+ destTemp++;
+ }
+ while (--len);
+
+ b &= 3;
+ mode = b;
+ if (b == 0)
+ continue;
+ if (b > srcRem || b > destRem)
+ return S_FALSE;
+ srcRem -= b;
+ destRem -= b;
+ *dest++ = *src++;
+ if (b > 1)
+ {
+ *dest++ = *src++;
+ if (b > 2)
+ *dest++ = *src++;
+ }
+ }
+}
+
+HRESULT CHandler::Decompress(ISequentialOutStream *outStream, Byte *outBuf, bool *outBufWasWritten, UInt32 *outBufWasWrittenSize, UInt32 inSize, UInt32 outSizeMax)
+{
+ if (outBuf)
+ {
+ *outBufWasWritten = false;
+ *outBufWasWrittenSize = 0;
+ }
+ UInt32 method = _h.Method;
+ if (_h.SeveralMethods)
+ {
+ Byte b;
+ RINOK(ReadStream_FALSE(_stream, &b, 1))
+ RINOK(_stream->Seek(-1, STREAM_SEEK_CUR, NULL))
+ method = (b == 0x5D ? kMethod_LZMA : kMethod_ZLIB);
+ }
+
+ if (method == kMethod_ZLIB && _needCheckLzma)
+ {
+ Byte b;
+ RINOK(ReadStream_FALSE(_stream, &b, 1))
+ RINOK(_stream->Seek(-1, STREAM_SEEK_CUR, NULL))
+ if (b == 0)
+ {
+ _noPropsLZMA = true;
+ method = _h.Method = kMethod_LZMA;
+ }
+ _needCheckLzma = false;
+ }
+
+ if (method == kMethod_ZLIB)
+ {
+ if (!_zlibDecoder)
+ {
+ _zlibDecoderSpec = new NCompress::NZlib::CDecoder();
+ _zlibDecoder = _zlibDecoderSpec;
+ }
+ RINOK(_zlibDecoder->Code(_limitedInStream, outStream, NULL, NULL, NULL))
+ if (inSize != _zlibDecoderSpec->GetInputProcessedSize())
+ return S_FALSE;
+ }
+ /*
+ else if (method == kMethod_LZMA)
+ {
+ if (!_lzmaDecoder)
+ {
+ _lzmaDecoderSpec = new NCompress::NLzma::CDecoder();
+ // _lzmaDecoderSpec->FinishStream = true;
+ _lzmaDecoder = _lzmaDecoderSpec;
+ }
+ const UInt32 kPropsSize = LZMA_PROPS_SIZE + 8;
+ Byte props[kPropsSize];
+ UInt32 propsSize;
+ UInt64 outSize;
+ if (_noPropsLZMA)
+ {
+ props[0] = 0x5D;
+ SetUi32(&props[1], _h.BlockSize);
+ propsSize = 0;
+ outSize = outSizeMax;
+ }
+ else
+ {
+ RINOK(ReadStream_FALSE(_limitedInStream, props, kPropsSize));
+ propsSize = kPropsSize;
+ outSize = GetUi64(&props[LZMA_PROPS_SIZE]);
+ if (outSize > outSizeMax)
+ return S_FALSE;
+ }
+ RINOK(_lzmaDecoderSpec->SetDecoderProperties2(props, LZMA_PROPS_SIZE));
+ RINOK(_lzmaDecoder->Code(_limitedInStream, outStream, NULL, &outSize, NULL));
+ if (inSize != propsSize + _lzmaDecoderSpec->GetInputProcessedSize())
+ return S_FALSE;
+ }
+ */
+ else
+ {
+ if (_inputBuffer.Size() < inSize)
+ _inputBuffer.Alloc(inSize);
+ RINOK(ReadStream_FALSE(_stream, _inputBuffer, inSize))
+
+ Byte *dest = outBuf;
+ if (!outBuf)
+ {
+ dest = _dynOutStreamSpec->GetBufPtrForWriting(outSizeMax);
+ if (!dest)
+ return E_OUTOFMEMORY;
+ }
+
+ SizeT destLen = outSizeMax, srcLen = inSize;
+
+ if (method == kMethod_LZO)
+ {
+ RINOK(LzoDecode(dest, &destLen, _inputBuffer, &srcLen))
+ }
+ else if (method == kMethod_LZMA)
+ {
+ Byte props[5];
+ const Byte *src = _inputBuffer;
+
+ if (_noPropsLZMA)
+ {
+ props[0] = 0x5D;
+ SetUi32(&props[1], _h.BlockSize)
+ }
+ else
+ {
+ const UInt32 kPropsSize = LZMA_PROPS_SIZE + 8;
+ if (inSize < kPropsSize)
+ return S_FALSE;
+ memcpy(props, src, LZMA_PROPS_SIZE);
+ UInt64 outSize = GetUi64(src + LZMA_PROPS_SIZE);
+ if (outSize > outSizeMax)
+ return S_FALSE;
+ destLen = (SizeT)outSize;
+ src += kPropsSize;
+ inSize -= kPropsSize;
+ srcLen = inSize;
+ }
+
+ ELzmaStatus status;
+ SRes res = LzmaDecode(dest, &destLen,
+ src, &srcLen,
+ props, LZMA_PROPS_SIZE,
+ LZMA_FINISH_END,
+ &status, &g_Alloc);
+ if (res != 0)
+ return SResToHRESULT(res);
+ if (status != LZMA_STATUS_FINISHED_WITH_MARK
+ && status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
+ return S_FALSE;
+ }
+ else
+ {
+ ECoderStatus status;
+ SRes res = XzUnpacker_CodeFull(&_xz,
+ dest, &destLen,
+ _inputBuffer, &srcLen,
+ CODER_FINISH_END, &status);
+ if (res != 0)
+ return SResToHRESULT(res);
+ if (status != CODER_STATUS_NEEDS_MORE_INPUT || !XzUnpacker_IsStreamWasFinished(&_xz))
+ return S_FALSE;
+ }
+
+ if (inSize != srcLen)
+ return S_FALSE;
+ if (outBuf)
+ {
+ *outBufWasWritten = true;
+ *outBufWasWrittenSize = (UInt32)destLen;
+ }
+ else
+ _dynOutStreamSpec->UpdateSize(destLen);
+ }
+ return S_OK;
+}
+
+HRESULT CHandler::ReadMetadataBlock(UInt32 &packSize)
+{
+ Byte temp[3];
+ const unsigned offset = _h.NeedCheckData() ? 3 : 2;
+ if (offset > packSize)
+ return S_FALSE;
+ RINOK(ReadStream_FALSE(_stream, temp, offset))
+ // if (NeedCheckData && Major < 4) checkByte must be = 0xFF
+ const bool be = _h.be;
+ UInt32 size = Get16(temp);
+ const bool isCompressed = ((size & kNotCompressedBit16) == 0);
+ if (size != kNotCompressedBit16)
+ size &= ~kNotCompressedBit16;
+
+ if (size > kMetadataBlockSize || offset + size > packSize)
+ return S_FALSE;
+ packSize = offset + size;
+ if (isCompressed)
+ {
+ _limitedInStreamSpec->Init(size);
+ RINOK(Decompress(_dynOutStream, NULL, NULL, NULL, size, kMetadataBlockSize))
+ }
+ else
+ {
+ // size != 0 here
+ Byte *buf = _dynOutStreamSpec->GetBufPtrForWriting(size);
+ if (!buf)
+ return E_OUTOFMEMORY;
+ RINOK(ReadStream_FALSE(_stream, buf, size))
+ _dynOutStreamSpec->UpdateSize(size);
+ }
+ return S_OK;
+}
+
+
+HRESULT CHandler::ReadMetadataBlock2()
+{
+ _dynOutStreamSpec->Init();
+ UInt32 packSize = kMetadataBlockSize + 3; // check it
+ return ReadMetadataBlock(packSize);
+}
+
+HRESULT CHandler::ReadData(CData &data, UInt64 start, UInt64 end)
+{
+ if (end < start || end - start >= ((UInt64)1 << 32))
+ return S_FALSE;
+ const UInt32 size = (UInt32)(end - start);
+ RINOK(Seek2(start))
+ _dynOutStreamSpec->Init();
+ UInt32 packPos = 0;
+ while (packPos != size)
+ {
+ data.PackPos.Add(packPos);
+ data.UnpackPos.Add((UInt32)_dynOutStreamSpec->GetSize());
+ if (packPos > size)
+ return S_FALSE;
+ UInt32 packSize = size - packPos;
+ RINOK(ReadMetadataBlock(packSize))
+ {
+ const size_t tSize = _dynOutStreamSpec->GetSize();
+ if (tSize != (UInt32)tSize)
+ return S_FALSE;
+ }
+ packPos += packSize;
+ }
+ data.UnpackPos.Add((UInt32)_dynOutStreamSpec->GetSize());
+ _dynOutStreamSpec->CopyToBuffer(data.Data);
+ return S_OK;
+}
+
+struct CTempItem
+{
+ UInt32 StartBlock;
+ // UInt32 iNodeNumber1;
+ UInt32 Offset;
+ // UInt16 iNodeNumber2;
+ UInt16 Type;
+};
+
+HRESULT CHandler::OpenDir(int parent, UInt32 startBlock, UInt32 offset, unsigned level, int &nodeIndex)
+{
+ if (level > kNumDirLevelsMax)
+ return S_FALSE;
+
+ int blockIndex = _inodesData.PackPos.FindInSorted(startBlock);
+ if (blockIndex < 0)
+ return S_FALSE;
+ UInt32 unpackPos = _inodesData.UnpackPos[blockIndex] + offset;
+ if (unpackPos < offset)
+ return S_FALSE;
+
+ nodeIndex = _nodesPos.FindInSorted(unpackPos, _blockToNode[blockIndex], _blockToNode[blockIndex + 1]);
+ // nodeIndex = _nodesPos.FindInSorted(unpackPos);
+ if (nodeIndex < 0)
+ return S_FALSE;
+
+ const CNode &n = _nodes[nodeIndex];
+ if (!n.IsDir())
+ return S_OK;
+ blockIndex = _dirs.PackPos.FindInSorted((UInt32)n.StartBlock);
+ if (blockIndex < 0)
+ return S_FALSE;
+ unpackPos = _dirs.UnpackPos[blockIndex] + n.Offset;
+ if (unpackPos < n.Offset || unpackPos > _dirs.Data.Size())
+ return S_FALSE;
+
+ UInt32 rem = (UInt32)_dirs.Data.Size() - unpackPos;
+ const Byte *p = _dirs.Data + unpackPos;
+ UInt32 fileSize = (UInt32)n.FileSize;
+
+ // for some squashfs files: fileSize = rem + 3 !!!
+ if (_h.Major >= 3)
+ {
+ if (fileSize < 3)
+ return S_FALSE;
+ fileSize -= 3;
+ }
+ if (fileSize > rem)
+ return S_FALSE;
+ rem = fileSize;
+
+ AString tempString;
+
+ CRecordVector<CTempItem> tempItems;
+ while (rem != 0)
+ {
+ const bool be = _h.be;
+ UInt32 count;
+ CTempItem tempItem;
+ if (_h.Major <= 2)
+ {
+ if (rem < 4)
+ return S_FALSE;
+ count = p[0];
+ tempItem.StartBlock = Get32(p);
+ if (be)
+ tempItem.StartBlock &= 0xFFFFFF;
+ else
+ tempItem.StartBlock >>= 8;
+ p += 4;
+ rem -= 4;
+ }
+ else
+ {
+ if (_h.Major == 3)
+ {
+ if (rem < 9)
+ return S_FALSE;
+ count = p[0];
+ p += 1;
+ rem -= 1;
+ }
+ else
+ {
+ if (rem < 12)
+ return S_FALSE;
+ count = GetUi32(p);
+ p += 4;
+ rem -= 4;
+ }
+ GET_32 (0, tempItem.StartBlock);
+ // GET_32 (4, tempItem.iNodeNumber1);
+ p += 8;
+ rem -= 8;
+ }
+ count++;
+
+ for (UInt32 i = 0; i < count; i++)
+ {
+ if (rem == 0)
+ return S_FALSE;
+
+ UInt32 nameOffset = _h.GetFileNameOffset();
+ if (rem < nameOffset)
+ return S_FALSE;
+
+ if ((UInt32)_items.Size() >= kNumFilesMax)
+ return S_FALSE;
+ if (_openCallback)
+ {
+ UInt64 numFiles = _items.Size();
+ if ((numFiles & 0xFFFF) == 0)
+ {
+ RINOK(_openCallback->SetCompleted(&numFiles, NULL))
+ }
+ }
+
+ CItem item;
+ item.Ptr = (UInt32)(p - (const Byte *)_dirs.Data);
+
+ UInt32 size;
+ if (_h.IsOldVersion())
+ {
+ UInt32 t = Get16(p);
+ if (be)
+ {
+ tempItem.Offset = t >> 3;
+ tempItem.Type = (UInt16)(t & 0x7);
+ }
+ else
+ {
+ tempItem.Offset = t & 0x1FFF;
+ tempItem.Type = (UInt16)(t >> 13);
+ }
+ size = (UInt32)p[2];
+ /*
+ if (_h.Major > 2)
+ tempItem.iNodeNumber2 = Get16(p + 3);
+ */
+ }
+ else
+ {
+ GET_16 (0, tempItem.Offset);
+ // GET_16 (2, tempItem.iNodeNumber2);
+ GET_16 (4, tempItem.Type);
+ GET_16 (6, size);
+ }
+ p += nameOffset;
+ rem -= nameOffset;
+ size++;
+ if (rem < size)
+ return S_FALSE;
+
+ if (_openCodePage == CP_UTF8)
+ {
+ tempString.SetFrom_CalcLen((const char *)p, size);
+ if (!CheckUTF8_AString(tempString))
+ _openCodePage = CP_OEMCP;
+ }
+
+ p += size;
+ rem -= size;
+ item.Parent = parent;
+ _items.Add(item);
+ tempItems.Add(tempItem);
+ }
+ }
+
+ const unsigned startItemIndex = _items.Size() - tempItems.Size();
+ FOR_VECTOR (i, tempItems)
+ {
+ const CTempItem &tempItem = tempItems[i];
+ const unsigned index = startItemIndex + i;
+ CItem &item = _items[index];
+ RINOK(OpenDir((int)index, tempItem.StartBlock, tempItem.Offset, level + 1, item.Node))
+ }
+
+ return S_OK;
+}
+
+HRESULT CHandler::ReadUids(UInt64 start, UInt32 num, CByteBuffer &ids)
+{
+ const size_t size = (size_t)num * 4;
+ ids.Alloc(size);
+ if (num == 0)
+ return S_OK;
+ RINOK(Seek2(start))
+ return ReadStream_FALSE(_stream, ids, size);
+}
+
+HRESULT CHandler::Open2(IInStream *inStream)
+{
+ {
+ Byte buf[kHeaderSize3];
+ RINOK(ReadStream_FALSE(inStream, buf, kHeaderSize3))
+ if (!_h.Parse(buf))
+ return S_FALSE;
+ if (!_h.IsSupported())
+ return E_NOTIMPL;
+
+ _noPropsLZMA = false;
+ _needCheckLzma = false;
+ switch (_h.Method)
+ {
+ case kMethod_ZLIB: _needCheckLzma = true; break;
+ case kMethod_LZMA:
+ case kMethod_LZO:
+ case kMethod_XZ:
+ break;
+ default:
+ return E_NOTIMPL;
+ }
+ }
+
+ _stream = inStream;
+
+ if (_h.NumFrags != 0)
+ {
+ if (_h.NumFrags > kNumFilesMax)
+ return S_FALSE;
+ _frags.ClearAndReserve(_h.NumFrags);
+ const unsigned bigFrag = (_h.Major > 2);
+
+ const unsigned fragPtrsInBlockLog = kMetadataBlockSizeLog - (3 + bigFrag);
+ const UInt32 numBlocks = (_h.NumFrags + (1 << fragPtrsInBlockLog) - 1) >> fragPtrsInBlockLog;
+ const size_t numBlocksBytes = (size_t)numBlocks << (2 + bigFrag);
+ CByteBuffer data(numBlocksBytes);
+ RINOK(Seek2(_h.FragTable))
+ RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes))
+ const bool be = _h.be;
+
+ for (UInt32 i = 0; i < numBlocks; i++)
+ {
+ const UInt64 offset = bigFrag ? Get64(data + i * 8) : Get32(data + i * 4);
+ RINOK(Seek2(offset))
+ RINOK(ReadMetadataBlock2())
+ const UInt32 unpackSize = (UInt32)_dynOutStreamSpec->GetSize();
+ if (unpackSize != kMetadataBlockSize)
+ if (i != numBlocks - 1 || unpackSize != ((_h.NumFrags << (3 + bigFrag)) & (kMetadataBlockSize - 1)))
+ return S_FALSE;
+ const Byte *buf = _dynOutStreamSpec->GetBuffer();
+ for (UInt32 j = 0; j < kMetadataBlockSize && j < unpackSize;)
+ {
+ CFrag frag;
+ if (bigFrag)
+ {
+ frag.StartBlock = Get64(buf + j);
+ frag.Size = Get32(buf + j + 8);
+ // some archives contain nonzero in unused (buf + j + 12)
+ j += 16;
+ }
+ else
+ {
+ frag.StartBlock = Get32(buf + j);
+ frag.Size = Get32(buf + j + 4);
+ j += 8;
+ }
+ _frags.Add(frag);
+ }
+ }
+ if ((UInt32)_frags.Size() != _h.NumFrags)
+ return S_FALSE;
+ }
+
+ RINOK(ReadData(_inodesData, _h.InodeTable, _h.DirTable))
+ RINOK(ReadData(_dirs, _h.DirTable, _h.FragTable))
+
+ UInt64 absOffset = _h.RootInode >> 16;
+ if (absOffset >= ((UInt64)1 << 32))
+ return S_FALSE;
+ {
+ UInt32 pos = 0;
+ UInt32 totalSize = (UInt32)_inodesData.Data.Size();
+ const unsigned kMinNodeParseSize = 4;
+ if (_h.NumInodes > totalSize / kMinNodeParseSize)
+ return S_FALSE;
+ _nodesPos.ClearAndReserve(_h.NumInodes);
+ _nodes.ClearAndReserve(_h.NumInodes);
+ // we use _blockToNode for binary search seed optimizations
+ _blockToNode.ClearAndReserve(_inodesData.GetNumBlocks() + 1);
+ unsigned curBlock = 0;
+ for (UInt32 i = 0; i < _h.NumInodes; i++)
+ {
+ CNode n;
+ const Byte *p = _inodesData.Data + pos;
+ UInt32 size = totalSize - pos;
+
+ switch (_h.Major)
+ {
+ case 1: size = n.Parse1(p, size, _h); break;
+ case 2: size = n.Parse2(p, size, _h); break;
+ case 3: size = n.Parse3(p, size, _h); break;
+ default: size = n.Parse4(p, size, _h); break;
+ }
+ if (size == 0)
+ return S_FALSE;
+ while (pos >= _inodesData.UnpackPos[curBlock])
+ {
+ _blockToNode.Add(_nodesPos.Size());
+ curBlock++;
+ }
+ _nodesPos.AddInReserved(pos);
+ _nodes.AddInReserved(n);
+ pos += size;
+ }
+ _blockToNode.Add(_nodesPos.Size());
+ if (pos != totalSize)
+ return S_FALSE;
+ }
+ int rootNodeIndex;
+ RINOK(OpenDir(-1, (UInt32)absOffset, (UInt32)_h.RootInode & 0xFFFF, 0, rootNodeIndex))
+
+ if (_h.Major < 4)
+ {
+ RINOK(ReadUids(_h.UidTable, _h.NumUids, _uids))
+ RINOK(ReadUids(_h.GidTable, _h.NumGids, _gids))
+ }
+ else
+ {
+ const UInt32 size = (UInt32)_h.NumIDs * 4;
+ _uids.Alloc(size);
+
+ const UInt32 numBlocks = (size + kMetadataBlockSize - 1) / kMetadataBlockSize;
+ const UInt32 numBlocksBytes = numBlocks << 3;
+ CByteBuffer data(numBlocksBytes);
+ RINOK(Seek2(_h.UidTable))
+ RINOK(ReadStream_FALSE(inStream, data, numBlocksBytes))
+
+ for (UInt32 i = 0; i < numBlocks; i++)
+ {
+ const UInt64 offset = GetUi64(data + i * 8);
+ RINOK(Seek2(offset))
+ // RINOK(ReadMetadataBlock(NULL, _uids + kMetadataBlockSize * i, packSize, unpackSize));
+ RINOK(ReadMetadataBlock2())
+ const size_t unpackSize = _dynOutStreamSpec->GetSize();
+ const UInt32 remSize = (i == numBlocks - 1) ?
+ (size & (kMetadataBlockSize - 1)) : kMetadataBlockSize;
+ if (unpackSize != remSize)
+ return S_FALSE;
+ memcpy(_uids + kMetadataBlockSize * i, _dynOutStreamSpec->GetBuffer(), remSize);
+ }
+ }
+
+ {
+ const UInt32 alignSize = 1 << 12;
+ Byte buf[alignSize];
+ RINOK(Seek2(_h.Size))
+ UInt32 rem = (UInt32)(0 - _h.Size) & (alignSize - 1);
+ _sizeCalculated = _h.Size;
+ if (rem != 0)
+ {
+ if (ReadStream_FALSE(_stream, buf, rem) == S_OK)
+ {
+ size_t i;
+ for (i = 0; i < rem && buf[i] == 0; i++);
+ if (i == rem)
+ _sizeCalculated = _h.Size + rem;
+ }
+ }
+ }
+ return S_OK;
+}
+
+AString CHandler::GetPath(unsigned index) const
+{
+ unsigned len = 0;
+ const unsigned indexMem = index;
+ const bool be = _h.be;
+ for (;;)
+ {
+ const CItem &item = _items[index];
+ const Byte *p = _dirs.Data + item.Ptr;
+ const unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1;
+ p += _h.GetFileNameOffset();
+ unsigned i;
+ for (i = 0; i < size && p[i]; i++);
+ len += i + 1;
+ index = (unsigned)item.Parent;
+ if (item.Parent < 0)
+ break;
+ }
+ len--;
+
+ AString path;
+ char *dest = path.GetBuf_SetEnd(len) + len;
+ index = indexMem;
+ for (;;)
+ {
+ const CItem &item = _items[index];
+ const Byte *p = _dirs.Data + item.Ptr;
+ const unsigned size = (_h.IsOldVersion() ? (unsigned)p[2] : (unsigned)Get16(p + 6)) + 1;
+ p += _h.GetFileNameOffset();
+ unsigned i;
+ for (i = 0; i < size && p[i]; i++);
+ dest -= i;
+ memcpy(dest, p, i);
+ index = (unsigned)item.Parent;
+ if (item.Parent < 0)
+ break;
+ *(--dest) = CHAR_PATH_SEPARATOR;
+ }
+ return path;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ _limitedInStreamSpec->SetStream(stream);
+ HRESULT res;
+ try
+ {
+ _openCallback = callback;
+ res = Open2(stream);
+ }
+ catch(...)
+ {
+ Close();
+ throw;
+ }
+ if (res != S_OK)
+ {
+ Close();
+ return res;
+ }
+ _stream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _openCodePage = CP_UTF8;
+ _sizeCalculated = 0;
+
+ _limitedInStreamSpec->ReleaseStream();
+ _stream.Release();
+
+ _items.Clear();
+ _nodes.Clear();
+ _nodesPos.Clear();
+ _blockToNode.Clear();
+ _frags.Clear();
+ _inodesData.Clear();
+ _dirs.Clear();
+
+ _uids.Free();
+ _gids.Free();
+
+ _cachedBlock.Free();
+ ClearCache();
+
+ return S_OK;
+}
+
+bool CHandler::GetPackSize(unsigned index, UInt64 &totalPack, bool fillOffsets)
+{
+ totalPack = 0;
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[item.Node];
+ const UInt32 ptr = _nodesPos[item.Node];
+ const Byte *p = _inodesData.Data + ptr;
+ const bool be = _h.be;
+
+ const UInt32 type = node.Type;
+ UInt32 offset;
+ if (node.IsLink() || node.FileSize == 0)
+ {
+ totalPack = node.FileSize;
+ return true;
+ }
+
+ const UInt32 numBlocks = (UInt32)node.GetNumBlocks(_h);
+
+ if (fillOffsets)
+ {
+ _blockOffsets.Clear();
+ _blockCompressed.Clear();
+ _blockOffsets.Add(totalPack);
+ }
+
+ if (_h.Major <= 1)
+ {
+ offset = 15;
+ p += offset;
+
+ for (UInt32 i = 0; i < numBlocks; i++)
+ {
+ UInt32 t = Get16(p + i * 2);
+ if (fillOffsets)
+ _blockCompressed.Add((t & kNotCompressedBit16) == 0);
+ if (t != kNotCompressedBit16)
+ t &= ~kNotCompressedBit16;
+ totalPack += t;
+ if (fillOffsets)
+ _blockOffsets.Add(totalPack);
+ }
+ }
+ else
+ {
+ if (_h.Major <= 2)
+ offset = 24;
+ else if (type == kType_FILE)
+ offset = 32;
+ else if (type == kType_FILE + 7)
+ offset = (_h.Major <= 3 ? 40 : 56);
+ else
+ return false;
+
+ p += offset;
+
+ for (UInt64 i = 0; i < numBlocks; i++)
+ {
+ UInt32 t = Get32(p + i * 4);
+ if (fillOffsets)
+ _blockCompressed.Add(IS_COMPRESSED_BLOCK(t));
+ UInt32 size = GET_COMPRESSED_BLOCK_SIZE(t);
+ if (size > _h.BlockSize)
+ return false;
+ totalPack += size;
+ if (fillOffsets)
+ _blockOffsets.Add(totalPack);
+ }
+
+ if (node.ThereAreFrags())
+ {
+ if (node.Frag >= (UInt32)_frags.Size())
+ return false;
+ const CFrag &frag = _frags[node.Frag];
+ if (node.Offset == 0)
+ {
+ UInt32 size = GET_COMPRESSED_BLOCK_SIZE(frag.Size);
+ if (size > _h.BlockSize)
+ return false;
+ totalPack += size;
+ }
+ }
+ }
+ return true;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidMethod:
+ {
+ char sz[16];
+ const char *s;
+ if (_noPropsLZMA)
+ s = "LZMA Spec";
+ else if (_h.SeveralMethods)
+ s = "LZMA ZLIB";
+ else
+ {
+ s = NULL;
+ if (_h.Method < Z7_ARRAY_SIZE(k_Methods))
+ s = k_Methods[_h.Method];
+ if (!s)
+ {
+ ConvertUInt32ToString(_h.Method, sz);
+ s = sz;
+ }
+ }
+ prop = s;
+ break;
+ }
+ case kpidFileSystem:
+ {
+ AString res ("SquashFS");
+ if (_h.SeveralMethods)
+ res += "-LZMA";
+ res.Add_Space();
+ res.Add_UInt32(_h.Major);
+ res.Add_Dot();
+ res.Add_UInt32(_h.Minor);
+ prop = res;
+ break;
+ }
+ case kpidClusterSize: prop = _h.BlockSize; break;
+ case kpidBigEndian: prop = _h.be; break;
+ case kpidCTime:
+ if (_h.CTime != 0)
+ PropVariant_SetFrom_UnixTime(prop, _h.CTime);
+ break;
+ case kpidCharacts: FLAGS_TO_PROP(k_Flags, _h.Flags, prop); break;
+ // case kpidNumBlocks: prop = _h.NumFrags; break;
+ case kpidPhySize: prop = _sizeCalculated; break;
+ case kpidHeadersSize:
+ if (_sizeCalculated >= _h.InodeTable)
+ prop = _sizeCalculated - _h.InodeTable;
+ break;
+
+ case kpidCodePage:
+ {
+ char sz[16];
+ const char *name = NULL;
+ switch (_openCodePage)
+ {
+ case CP_OEMCP: name = "OEM"; break;
+ case CP_UTF8: name = "UTF-8"; break;
+ }
+ if (!name)
+ {
+ ConvertUInt32ToString(_openCodePage, sz);
+ name = sz;
+ }
+ prop = name;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[item.Node];
+ const bool isDir = node.IsDir();
+ const bool be = _h.be;
+
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ AString path (GetPath(index));
+ UString s;
+ if (_openCodePage == CP_UTF8)
+ ConvertUTF8ToUnicode(path, s);
+ else
+ MultiByteToUnicodeString2(s, path, _openCodePage);
+ prop = s;
+ break;
+ }
+ case kpidIsDir: prop = isDir; break;
+ // case kpidOffset: if (!node.IsLink()) prop = (UInt64)node.StartBlock; break;
+ case kpidSize: if (!isDir) prop = node.GetSize(); break;
+ case kpidPackSize:
+ if (!isDir)
+ {
+ UInt64 size;
+ if (GetPackSize(index, size, false))
+ prop = size;
+ }
+ break;
+ case kpidMTime:
+ {
+ UInt32 offset = 0;
+ switch (_h.Major)
+ {
+ case 1:
+ if (node.Type == kType_FILE)
+ offset = 3;
+ else if (node.Type == kType_DIR)
+ offset = 7;
+ break;
+ case 2:
+ if (node.Type == kType_FILE)
+ offset = 4;
+ else if (node.Type == kType_DIR)
+ offset = 8;
+ else if (node.Type == kType_DIR + 7)
+ offset = 9;
+ break;
+ case 3: offset = 4; break;
+ case 4: offset = 8; break;
+ }
+ if (offset != 0)
+ {
+ const Byte *p = _inodesData.Data + _nodesPos[item.Node] + offset;
+ PropVariant_SetFrom_UnixTime(prop, Get32(p));
+ }
+ break;
+ }
+ case kpidPosixAttrib:
+ {
+ if (node.Type != 0 && node.Type < Z7_ARRAY_SIZE(k_TypeToMode))
+ prop = (UInt32)(node.Mode & 0xFFF) | k_TypeToMode[node.Type];
+ break;
+ }
+ case kpidUserId:
+ case kpidGroupId:
+ {
+ UInt32 id = node.Uid;
+ const CByteBuffer *ids = &_uids;
+ if (propID == kpidGroupId)
+ {
+ id = node.Gid;
+ if (_h.Major < 4)
+ {
+ if (id == _h.GetSpecGuidIndex())
+ id = node.Uid;
+ else
+ ids = &_gids;
+ }
+ }
+ const UInt32 offset = (UInt32)id * 4;
+ if (offset < ids->Size())
+ prop = (UInt32)Get32(*ids + offset);
+ break;
+ }
+ /*
+ case kpidLinks:
+ if (_h.Major >= 3 && node.Type != kType_FILE)
+ prop = node.NumLinks;
+ break;
+ */
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CSquashfsInStream: public CCachedInStream
+{
+ HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) Z7_override;
+public:
+ CHandler *Handler;
+};
+
+HRESULT CSquashfsInStream::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
+{
+ return Handler->ReadBlock(blockIndex, dest, blockSize);
+}
+
+HRESULT CHandler::ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize)
+{
+ const CNode &node = _nodes[_nodeIndex];
+ UInt64 blockOffset;
+ UInt32 packBlockSize;
+ UInt32 offsetInBlock = 0;
+ bool compressed;
+ if (blockIndex < _blockCompressed.Size())
+ {
+ compressed = _blockCompressed[(unsigned)blockIndex];
+ blockOffset = _blockOffsets[(unsigned)blockIndex];
+ packBlockSize = (UInt32)(_blockOffsets[(unsigned)blockIndex + 1] - blockOffset);
+ blockOffset += node.StartBlock;
+ }
+ else
+ {
+ if (!node.ThereAreFrags())
+ return S_FALSE;
+ const CFrag &frag = _frags[node.Frag];
+ offsetInBlock = node.Offset;
+ blockOffset = frag.StartBlock;
+ packBlockSize = GET_COMPRESSED_BLOCK_SIZE(frag.Size);
+ compressed = IS_COMPRESSED_BLOCK(frag.Size);
+ }
+
+ if (packBlockSize == 0)
+ {
+ // sparse file ???
+ memset(dest, 0, blockSize);
+ return S_OK;
+ }
+
+ if (blockOffset != _cachedBlockStartPos ||
+ packBlockSize != _cachedPackBlockSize)
+ {
+ ClearCache();
+ RINOK(Seek2(blockOffset))
+ _limitedInStreamSpec->Init(packBlockSize);
+
+ if (compressed)
+ {
+ _outStreamSpec->Init((Byte *)_cachedBlock, _h.BlockSize);
+ bool outBufWasWritten;
+ UInt32 outBufWasWrittenSize;
+ HRESULT res = Decompress(_outStream, _cachedBlock, &outBufWasWritten, &outBufWasWrittenSize, packBlockSize, _h.BlockSize);
+ RINOK(res)
+ if (outBufWasWritten)
+ _cachedUnpackBlockSize = outBufWasWrittenSize;
+ else
+ _cachedUnpackBlockSize = (UInt32)_outStreamSpec->GetPos();
+ }
+ else
+ {
+ if (packBlockSize > _h.BlockSize)
+ return S_FALSE;
+ RINOK(ReadStream_FALSE(_limitedInStream, _cachedBlock, packBlockSize))
+ _cachedUnpackBlockSize = packBlockSize;
+ }
+ _cachedBlockStartPos = blockOffset;
+ _cachedPackBlockSize = packBlockSize;
+ }
+ if (offsetInBlock + blockSize > _cachedUnpackBlockSize)
+ return S_FALSE;
+ if (blockSize != 0)
+ memcpy(dest, _cachedBlock + offsetInBlock, blockSize);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItem &item = _items[allFilesMode ? i : indices[i]];
+ const CNode &node = _nodes[item.Node];
+ totalSize += node.GetSize();
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur())
+ CMyComPtr<ISequentialOutStream> outStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[item.Node];
+ RINOK(extractCallback->GetStream(index, &outStream, askMode))
+ // const Byte *p = _data + item.Offset;
+
+ if (node.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+ UInt64 unpackSize = node.GetSize();
+ totalSize += unpackSize;
+ UInt64 packSize;
+ if (GetPackSize(index, packSize, false))
+ totalPackSize += packSize;
+
+ if (!testMode && !outStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode))
+
+ int res = NExtract::NOperationResult::kDataError;
+ {
+ CMyComPtr<ISequentialInStream> inSeqStream;
+ HRESULT hres = GetStream(index, &inSeqStream);
+ if (hres == S_FALSE || !inSeqStream)
+ {
+ if (hres == E_OUTOFMEMORY)
+ return hres;
+ res = NExtract::NOperationResult::kUnsupportedMethod;
+ }
+ else
+ {
+ RINOK(hres)
+ {
+ hres = copyCoder->Code(inSeqStream, outStream, NULL, NULL, progress);
+ if (hres == S_OK)
+ {
+ if (copyCoderSpec->TotalSize == unpackSize)
+ res = NExtract::NOperationResult::kOK;
+ }
+ else if (hres == E_NOTIMPL)
+ {
+ res = NExtract::NOperationResult::kUnsupportedMethod;
+ }
+ else if (hres != S_FALSE)
+ {
+ RINOK(hres)
+ }
+ }
+ }
+ }
+
+ RINOK(extractCallback->SetOperationResult(res))
+ }
+
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+
+ const CItem &item = _items[index];
+ const CNode &node = _nodes[item.Node];
+
+ if (node.IsDir())
+ return E_FAIL;
+
+ const Byte *p = _inodesData.Data + _nodesPos[item.Node];
+
+ if (node.FileSize == 0 || node.IsLink())
+ {
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ if (node.IsLink())
+ streamSpec->Init(p + _h.GetSymLinkOffset(), (size_t)node.FileSize);
+ else
+ streamSpec->Init(NULL, 0);
+ *stream = streamTemp.Detach();
+ return S_OK;
+ }
+
+ UInt64 packSize;
+ if (!GetPackSize(index, packSize, true))
+ return S_FALSE;
+
+ _nodeIndex = item.Node;
+
+ size_t cacheSize = _h.BlockSize;
+ if (_cachedBlock.Size() != cacheSize)
+ {
+ ClearCache();
+ _cachedBlock.Alloc(cacheSize);
+ }
+
+ CSquashfsInStream *streamSpec = new CSquashfsInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ streamSpec->Handler = this;
+ unsigned cacheSizeLog = 22;
+ if (cacheSizeLog <= _h.BlockSizeLog)
+ cacheSizeLog = _h.BlockSizeLog + 1;
+ if (!streamSpec->Alloc(_h.BlockSizeLog, cacheSizeLog - _h.BlockSizeLog))
+ return E_OUTOFMEMORY;
+ streamSpec->Init(node.FileSize);
+ *stream = streamTemp.Detach();
+
+ return S_OK;
+
+ COM_TRY_END
+}
+
+static const Byte k_Signature[] = {
+ 4, 'h', 's', 'q', 's',
+ 4, 's', 'q', 's', 'h',
+ 4, 's', 'h', 's', 'q',
+ 4, 'q', 's', 'h', 's' };
+
+REGISTER_ARC_I(
+ "SquashFS", "squashfs", NULL, 0xD2,
+ k_Signature,
+ 0,
+ NArcInfoFlags::kMultiSignature,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/StdAfx.h b/CPP/7zip/Archive/StdAfx.h
index 42a088f..8086655 100644
--- a/CPP/7zip/Archive/StdAfx.h
+++ b/CPP/7zip/Archive/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "../../Common/Common.h"
-
-#endif
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Archive/SwfHandler.cpp b/CPP/7zip/Archive/SwfHandler.cpp
new file mode 100644
index 0000000..ab704b6
--- /dev/null
+++ b/CPP/7zip/Archive/SwfHandler.cpp
@@ -0,0 +1,994 @@
+// SwfHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/MyString.h"
+
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/PropVariantUtils.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+#include "../Compress/LzmaDecoder.h"
+#include "../Compress/ZlibDecoder.h"
+
+#include "Common/DummyOutStream.h"
+
+// #define Z7_SWF_UPDATE
+
+#ifdef Z7_SWF_UPDATE
+
+#include "../Compress/LzmaEncoder.h"
+#include "../Compress/ZlibEncoder.h"
+
+#include "Common/HandlerOut.h"
+
+#endif
+
+using namespace NWindows;
+
+namespace NArchive {
+
+static const UInt32 kFileSizeMax = (UInt32)1 << 29;
+
+namespace NSwfc {
+
+static const unsigned kHeaderBaseSize = 8;
+static const unsigned kHeaderLzmaSize = 17;
+
+static const Byte SWF_UNCOMPRESSED = 'F';
+static const Byte SWF_COMPRESSED_ZLIB = 'C';
+static const Byte SWF_COMPRESSED_LZMA = 'Z';
+
+static const Byte SWF_MIN_COMPRESSED_ZLIB_VER = 6;
+static const Byte SWF_MIN_COMPRESSED_LZMA_VER = 13;
+
+static const Byte kVerLim = 64;
+
+API_FUNC_static_IsArc IsArc_Swf(const Byte *p, size_t size)
+{
+ if (size < kHeaderBaseSize)
+ return k_IsArc_Res_NEED_MORE;
+ if (p[0] != SWF_UNCOMPRESSED ||
+ p[1] != 'W' ||
+ p[2] != 'S' ||
+ p[3] >= kVerLim)
+ return k_IsArc_Res_NO;
+ UInt32 uncompressedSize = GetUi32(p + 4);
+ if (uncompressedSize > kFileSizeMax)
+ return k_IsArc_Res_NO;
+ return k_IsArc_Res_YES;
+}
+}
+
+API_FUNC_static_IsArc IsArc_Swfc(const Byte *p, size_t size)
+{
+ if (size < kHeaderBaseSize + 2 + 1) // 2 + 1 (for zlib check)
+ return k_IsArc_Res_NEED_MORE;
+ if ((p[0] != SWF_COMPRESSED_ZLIB &&
+ p[0] != SWF_COMPRESSED_LZMA) ||
+ p[1] != 'W' ||
+ p[2] != 'S' ||
+ p[3] >= kVerLim)
+ return k_IsArc_Res_NO;
+ UInt32 uncompressedSize = GetUi32(p + 4);
+ if (uncompressedSize > kFileSizeMax)
+ return k_IsArc_Res_NO;
+
+ if (p[0] == SWF_COMPRESSED_ZLIB)
+ {
+ if (!NCompress::NZlib::IsZlib_3bytes(p + 8))
+ return k_IsArc_Res_NO;
+ }
+ else
+ {
+ if (size < kHeaderLzmaSize + 2)
+ return k_IsArc_Res_NEED_MORE;
+ if (p[kHeaderLzmaSize] != 0 ||
+ (p[kHeaderLzmaSize + 1] & 0x80) != 0)
+ return k_IsArc_Res_NO;
+ UInt32 lzmaPackSize = GetUi32(p + 8);
+ UInt32 lzmaProp = p[12];
+ UInt32 lzmaDicSize = GetUi32(p + 13);
+ if (lzmaProp > 5 * 5 * 9 ||
+ lzmaDicSize > ((UInt32)1 << 28) ||
+ lzmaPackSize < 5 ||
+ lzmaPackSize > ((UInt32)1 << 28))
+ return k_IsArc_Res_NO;
+ }
+
+ return k_IsArc_Res_YES;
+}
+}
+
+struct CItem
+{
+ Byte Buf[kHeaderLzmaSize];
+ unsigned HeaderSize;
+
+ UInt32 GetSize() const { return GetUi32(Buf + 4); }
+ UInt32 GetLzmaPackSize() const { return GetUi32(Buf + 8); }
+ UInt32 GetLzmaDicSize() const { return GetUi32(Buf + 13); }
+
+ bool IsSwf() const { return (Buf[1] == 'W' && Buf[2] == 'S' && Buf[3] < kVerLim); }
+ bool IsUncompressed() const { return Buf[0] == SWF_UNCOMPRESSED; }
+ bool IsZlib() const { return Buf[0] == SWF_COMPRESSED_ZLIB; }
+ bool IsLzma() const { return Buf[0] == SWF_COMPRESSED_LZMA; }
+
+ void MakeUncompressed()
+ {
+ Buf[0] = SWF_UNCOMPRESSED;
+ HeaderSize = kHeaderBaseSize;
+ }
+ void MakeZlib()
+ {
+ Buf[0] = SWF_COMPRESSED_ZLIB;
+ if (Buf[3] < SWF_MIN_COMPRESSED_ZLIB_VER)
+ Buf[3] = SWF_MIN_COMPRESSED_ZLIB_VER;
+ }
+ void MakeLzma(UInt32 packSize)
+ {
+ Buf[0] = SWF_COMPRESSED_LZMA;
+ if (Buf[3] < SWF_MIN_COMPRESSED_LZMA_VER)
+ Buf[3] = SWF_MIN_COMPRESSED_LZMA_VER;
+ SetUi32(Buf + 8, packSize)
+ HeaderSize = kHeaderLzmaSize;
+ }
+
+ HRESULT ReadHeader(ISequentialInStream *stream)
+ {
+ HeaderSize = kHeaderBaseSize;
+ return ReadStream_FALSE(stream, Buf, kHeaderBaseSize);
+ }
+ HRESULT WriteHeader(ISequentialOutStream *stream)
+ {
+ return WriteStream(stream, Buf, HeaderSize);
+ }
+};
+
+
+Z7_class_CHandler_final:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ #ifdef Z7_SWF_UPDATE
+ public IOutArchive,
+ public ISetProperties,
+ #endif
+ public CMyUnknownImp
+{
+ #ifdef Z7_SWF_UPDATE
+ Z7_IFACES_IMP_UNK_4(IInArchive, IArchiveOpenSeq, IOutArchive, ISetProperties)
+ #else
+ Z7_IFACES_IMP_UNK_2(IInArchive, IArchiveOpenSeq)
+ #endif
+
+ CItem _item;
+ UInt64 _packSize;
+ bool _packSizeDefined;
+ CMyComPtr<ISequentialInStream> _seqStream;
+ CMyComPtr<IInStream> _stream;
+
+ #ifdef Z7_SWF_UPDATE
+ CSingleMethodProps _props;
+ bool _lzmaMode;
+ #endif
+
+public:
+ #ifdef Z7_SWF_UPDATE
+ CHandler(): _lzmaMode(false) {}
+ #endif
+};
+
+static const Byte kProps[] =
+{
+ kpidSize,
+ kpidPackSize,
+ kpidMethod
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySize: if (_packSizeDefined) prop = _item.HeaderSize + _packSize; break;
+ case kpidIsNotArcType: prop = true; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+static void DicSizeToString(char *s, UInt32 val)
+{
+ char c = 0;
+ unsigned i;
+ for (i = 0; i < 32; i++)
+ if (((UInt32)1 << i) == val)
+ {
+ val = i;
+ break;
+ }
+ if (i == 32)
+ {
+ c = 'b';
+ if ((val & ((1 << 20) - 1)) == 0) { val >>= 20; c = 'm'; }
+ else if ((val & ((1 << 10) - 1)) == 0) { val >>= 10; c = 'k'; }
+ }
+ ::ConvertUInt32ToString(val, s);
+ unsigned pos = MyStringLen(s);
+ s[pos++] = c;
+ s[pos] = 0;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
+{
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidSize: prop = (UInt64)_item.GetSize(); break;
+ case kpidPackSize: if (_packSizeDefined) prop = _item.HeaderSize + _packSize; break;
+ case kpidMethod:
+ {
+ char s[32];
+ if (_item.IsZlib())
+ MyStringCopy(s, "zlib");
+ else
+ {
+ MyStringCopy(s, "LZMA:");
+ DicSizeToString(s + 5, _item.GetLzmaDicSize());
+ }
+ prop = s;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *))
+{
+ RINOK(OpenSeq(stream))
+ _stream = stream;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream))
+{
+ Close();
+ RINOK(_item.ReadHeader(stream))
+ if (!_item.IsSwf())
+ return S_FALSE;
+ if (_item.IsLzma())
+ {
+ RINOK(ReadStream_FALSE(stream, _item.Buf + kHeaderBaseSize, kHeaderLzmaSize - kHeaderBaseSize))
+ _item.HeaderSize = kHeaderLzmaSize;
+ _packSize = _item.GetLzmaPackSize();
+ _packSizeDefined = true;
+ }
+ else if (!_item.IsZlib())
+ return S_FALSE;
+ if (_item.GetSize() < _item.HeaderSize)
+ return S_FALSE;
+ _seqStream = stream;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _packSize = 0;
+ _packSizeDefined = false;
+ _seqStream.Release();
+ _stream.Release();
+ return S_OK;
+}
+
+Z7_CLASS_IMP_COM_1(
+ CCompressProgressInfoImp,
+ ICompressProgressInfo
+)
+ CMyComPtr<IArchiveOpenCallback> Callback;
+public:
+ UInt64 Offset;
+ void Init(IArchiveOpenCallback *callback) { Callback = callback; }
+};
+
+Z7_COM7F_IMF(CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */))
+{
+ if (Callback)
+ {
+ const UInt64 files = 0;
+ const UInt64 value = Offset + *inSize;
+ return Callback->SetCompleted(&files, &value);
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ RINOK(extractCallback->SetTotal(_item.GetSize()))
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode))
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ lps->InSize = _item.HeaderSize;
+ lps->OutSize = outStreamSpec->GetSize();
+ RINOK(lps->SetCur())
+
+ CItem item = _item;
+ item.MakeUncompressed();
+ if (_stream)
+ RINOK(InStream_SeekSet(_stream, _item.HeaderSize))
+ NCompress::NZlib::CDecoder *_decoderZlibSpec = NULL;
+ NCompress::NLzma::CDecoder *_decoderLzmaSpec = NULL;
+ CMyComPtr<ICompressCoder> _decoder;
+
+ CMyComPtr<ISequentialInStream> inStream2;
+
+ UInt64 unpackSize = _item.GetSize() - (UInt32)8;
+ if (_item.IsZlib())
+ {
+ _decoderZlibSpec = new NCompress::NZlib::CDecoder;
+ _decoder = _decoderZlibSpec;
+ inStream2 = _seqStream;
+ }
+ else
+ {
+ /* Some .swf files with lzma contain additional 8 bytes at the end
+ in uncompressed stream.
+ What does that data mean ???
+ We don't decompress these additional 8 bytes */
+
+ // unpackSize = _item.GetSize();
+ // SetUi32(item.Buf + 4, (UInt32)(unpackSize + 8));
+ CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream;
+ inStream2 = limitedStreamSpec;
+ limitedStreamSpec->SetStream(_seqStream);
+ limitedStreamSpec->Init(_item.GetLzmaPackSize());
+
+ _decoderLzmaSpec = new NCompress::NLzma::CDecoder;
+ _decoder = _decoderLzmaSpec;
+ // _decoderLzmaSpec->FinishStream = true;
+
+ Byte props[5];
+ memcpy(props, _item.Buf + 12, 5);
+ UInt32 dicSize = _item.GetLzmaDicSize();
+ if (dicSize > (UInt32)unpackSize)
+ {
+ dicSize = (UInt32)unpackSize;
+ SetUi32(props + 1, dicSize)
+ }
+ RINOK(_decoderLzmaSpec->SetDecoderProperties2(props, 5))
+ }
+ RINOK(item.WriteHeader(outStream))
+ HRESULT result = _decoder->Code(inStream2, outStream, NULL, &unpackSize, progress);
+ Int32 opRes = NExtract::NOperationResult::kDataError;
+ if (result == S_OK)
+ {
+ if (item.GetSize() == outStreamSpec->GetSize())
+ {
+ if (_item.IsZlib())
+ {
+ _packSizeDefined = true;
+ _packSize = _decoderZlibSpec->GetInputProcessedSize();
+ opRes = NExtract::NOperationResult::kOK;
+ }
+ else
+ {
+ // if (_decoderLzmaSpec->GetInputProcessedSize() == _packSize)
+ opRes = NExtract::NOperationResult::kOK;
+ }
+ }
+ }
+ else if (result != S_FALSE)
+ return result;
+
+ outStream.Release();
+ return extractCallback->SetOperationResult(opRes);
+ COM_TRY_END
+}
+
+
+#ifdef Z7_SWF_UPDATE
+
+static HRESULT UpdateArchive(ISequentialOutStream *outStream, UInt64 size,
+ bool lzmaMode, const CSingleMethodProps &props,
+ IArchiveUpdateCallback *updateCallback)
+{
+ UInt64 complexity = 0;
+ RINOK(updateCallback->SetTotal(size))
+ RINOK(updateCallback->SetCompleted(&complexity))
+
+ CMyComPtr<ISequentialInStream> fileInStream;
+ RINOK(updateCallback->GetStream(0, &fileInStream))
+
+ /*
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+ */
+
+ CItem item;
+ const HRESULT res = item.ReadHeader(fileInStream);
+ if (res == S_FALSE)
+ return E_INVALIDARG;
+ RINOK(res)
+ if (!item.IsSwf() || !item.IsUncompressed() || size != item.GetSize())
+ return E_INVALIDARG;
+
+ NCompress::NZlib::CEncoder *encoderZlibSpec = NULL;
+ NCompress::NLzma::CEncoder *encoderLzmaSpec = NULL;
+ CMyComPtr<ICompressCoder> encoder;
+ CMyComPtr<IOutStream> outSeekStream;
+ if (lzmaMode)
+ {
+ outStream->QueryInterface(IID_IOutStream, (void **)&outSeekStream);
+ if (!outSeekStream)
+ return E_NOTIMPL;
+ encoderLzmaSpec = new NCompress::NLzma::CEncoder;
+ encoder = encoderLzmaSpec;
+ RINOK(props.SetCoderProps(encoderLzmaSpec, &size))
+ item.MakeLzma((UInt32)0xFFFFFFFF);
+ CBufPtrSeqOutStream *propStreamSpec = new CBufPtrSeqOutStream;
+ CMyComPtr<ISequentialOutStream> propStream = propStreamSpec;
+ propStreamSpec->Init(item.Buf + 12, 5);
+ RINOK(encoderLzmaSpec->WriteCoderProperties(propStream))
+ }
+ else
+ {
+ encoderZlibSpec = new NCompress::NZlib::CEncoder;
+ encoder = encoderZlibSpec;
+ encoderZlibSpec->Create();
+ RINOK(props.SetCoderProps(encoderZlibSpec->DeflateEncoderSpec, NULL))
+ item.MakeZlib();
+ }
+ RINOK(item.WriteHeader(outStream))
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, progress))
+ UInt64 inputProcessed;
+ if (lzmaMode)
+ {
+ UInt64 curPos = 0;
+ RINOK(outSeekStream->Seek(0, STREAM_SEEK_CUR, &curPos))
+ const UInt64 packSize = curPos - kHeaderLzmaSize;
+ if (packSize > (UInt32)0xFFFFFFFF)
+ return E_INVALIDARG;
+ item.MakeLzma((UInt32)packSize);
+ RINOK(outSeekStream->Seek(0, STREAM_SEEK_SET, NULL))
+ RINOK(item.WriteHeader(outStream))
+ inputProcessed = encoderLzmaSpec->GetInputProcessedSize();
+ }
+ else
+ {
+ inputProcessed = encoderZlibSpec->GetInputProcessedSize();
+ }
+ if (inputProcessed + kHeaderBaseSize != size)
+ return E_INVALIDARG;
+ return updateCallback->SetOperationResult(NUpdate::NOperationResult::kOK);
+}
+
+Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType))
+{
+ *timeType = NFileTimeType::kUnix;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *updateCallback))
+{
+ if (numItems != 1)
+ return E_INVALIDARG;
+
+ Int32 newData, newProps;
+ UInt32 indexInArchive;
+ if (!updateCallback)
+ return E_FAIL;
+ RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive))
+
+ if (IntToBool(newProps))
+ {
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop))
+ if (prop.vt == VT_BOOL)
+ {
+ if (prop.boolVal != VARIANT_FALSE)
+ return E_INVALIDARG;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ }
+
+ if (IntToBool(newData))
+ {
+ UInt64 size;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidSize, &prop))
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ }
+ return UpdateArchive(outStream, size, _lzmaMode, _props, updateCallback);
+ }
+
+ if (indexInArchive != 0)
+ return E_INVALIDARG;
+
+ if (!_seqStream)
+ return E_NOTIMPL;
+
+ if (_stream)
+ {
+ RINOK(InStream_SeekToBegin(_stream))
+ }
+ else
+ _item.WriteHeader(outStream);
+ return NCompress::CopyStream(_seqStream, outStream, NULL);
+}
+
+Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
+{
+ _lzmaMode = false;
+ RINOK(_props.SetProperties(names, values, numProps))
+ const AString &m = _props.MethodName;
+ if (m.IsEqualTo_Ascii_NoCase("lzma"))
+ {
+ return E_NOTIMPL;
+ // _lzmaMode = true;
+ }
+ else if (m.IsEqualTo_Ascii_NoCase("Deflate") || m.IsEmpty())
+ _lzmaMode = false;
+ else
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+#endif
+
+
+static const Byte k_Signature[] = {
+ 3, 'C', 'W', 'S',
+ 3, 'Z', 'W', 'S' };
+
+REGISTER_ARC_I(
+ "SWFc", "swf", "~.swf", 0xD8,
+ k_Signature,
+ 0,
+ NArcInfoFlags::kMultiSignature,
+ IsArc_Swfc)
+
+}
+
+namespace NSwf {
+
+static const unsigned kNumTagsMax = 1 << 23;
+
+struct CTag
+{
+ UInt32 Type;
+ CByteBuffer Buf;
+};
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IArchiveOpenSeq
+)
+ CObjectVector<CTag> _tags;
+ NSwfc::CItem _item;
+ UInt64 _phySize;
+
+ HRESULT OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *callback);
+ HRESULT OpenSeq2(ISequentialInStream *stream, IArchiveOpenCallback *callback);
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidComment,
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySize: prop = _phySize; break;
+ case kpidIsNotArcType: prop = true; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _tags.Size();
+ return S_OK;
+}
+
+static const char * const g_TagDesc[92] =
+{
+ "End"
+ , "ShowFrame"
+ , "DefineShape"
+ , NULL
+ , "PlaceObject"
+ , "RemoveObject"
+ , "DefineBits"
+ , "DefineButton"
+ , "JPEGTables"
+ , "SetBackgroundColor"
+ , "DefineFont"
+ , "DefineText"
+ , "DoAction"
+ , "DefineFontInfo"
+ , "DefineSound"
+ , "StartSound"
+ , NULL
+ , "DefineButtonSound"
+ , "SoundStreamHead"
+ , "SoundStreamBlock"
+ , "DefineBitsLossless"
+ , "DefineBitsJPEG2"
+ , "DefineShape2"
+ , "DefineButtonCxform"
+ , "Protect"
+ , NULL
+ , "PlaceObject2"
+ , NULL
+ , "RemoveObject2"
+ , NULL
+ , NULL
+ , NULL
+ , "DefineShape3"
+ , "DefineText2"
+ , "DefineButton2"
+ , "DefineBitsJPEG3"
+ , "DefineBitsLossless2"
+ , "DefineEditText"
+ , NULL
+ , "DefineSprite"
+ , NULL
+ , "41"
+ , NULL
+ , "FrameLabel"
+ , NULL
+ , "SoundStreamHead2"
+ , "DefineMorphShape"
+ , NULL
+ , "DefineFont2"
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , "ExportAssets"
+ , "ImportAssets"
+ , "EnableDebugger"
+ , "DoInitAction"
+ , "DefineVideoStream"
+ , "VideoFrame"
+ , "DefineFontInfo2"
+ , NULL
+ , "EnableDebugger2"
+ , "ScriptLimits"
+ , "SetTabIndex"
+ , NULL
+ , NULL
+ , "FileAttributes"
+ , "PlaceObject3"
+ , "ImportAssets2"
+ , NULL
+ , "DefineFontAlignZones"
+ , "CSMTextSettings"
+ , "DefineFont3"
+ , "SymbolClass"
+ , "Metadata"
+ , "DefineScalingGrid"
+ , NULL
+ , NULL
+ , NULL
+ , "DoABC"
+ , "DefineShape4"
+ , "DefineMorphShape2"
+ , NULL
+ , "DefineSceneAndFrameLabelData"
+ , "DefineBinaryData"
+ , "DefineFontName"
+ , "StartSound2"
+ , "DefineBitsJPEG4"
+ , "DefineFont4"
+};
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ NWindows::NCOM::CPropVariant prop;
+ const CTag &tag = _tags[index];
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ char s[32];
+ ConvertUInt32ToString(index, s);
+ size_t i = strlen(s);
+ s[i++] = '.';
+ ConvertUInt32ToString(tag.Type, s + i);
+ prop = s;
+ break;
+ }
+ case kpidSize:
+ case kpidPackSize:
+ prop = (UInt64)tag.Buf.Size(); break;
+ case kpidComment:
+ TYPE_TO_PROP(g_TagDesc, tag.Type, prop);
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback))
+{
+ return OpenSeq2(stream, callback);
+}
+
+static UInt16 Read16(CInBuffer &stream)
+{
+ UInt32 res = 0;
+ for (unsigned i = 0; i < 2; i++)
+ {
+ Byte b;
+ if (!stream.ReadByte(b))
+ throw 1;
+ res |= (UInt32)b << (i * 8);
+ }
+ return (UInt16)res;
+}
+
+static UInt32 Read32(CInBuffer &stream)
+{
+ UInt32 res = 0;
+ for (unsigned i = 0; i < 4; i++)
+ {
+ Byte b;
+ if (!stream.ReadByte(b))
+ throw 1;
+ res |= (UInt32)b << (i * 8);
+ }
+ return res;
+}
+
+struct CBitReader
+{
+ CInBuffer *stream;
+ unsigned NumBits;
+ Byte Val;
+
+ CBitReader(): NumBits(0), Val(0) {}
+
+ UInt32 ReadBits(unsigned numBits);
+};
+
+UInt32 CBitReader::ReadBits(unsigned numBits)
+{
+ UInt32 res = 0;
+ while (numBits > 0)
+ {
+ if (NumBits == 0)
+ {
+ Val = stream->ReadByte();
+ NumBits = 8;
+ }
+ if (numBits <= NumBits)
+ {
+ res <<= numBits;
+ NumBits -= numBits;
+ res |= (Val >> NumBits);
+ Val = (Byte)(Val & (((unsigned)1 << NumBits) - 1));
+ break;
+ }
+ else
+ {
+ res <<= NumBits;
+ res |= Val;
+ numBits -= NumBits;
+ NumBits = 0;
+ }
+ }
+ return res;
+}
+
+HRESULT CHandler::OpenSeq3(ISequentialInStream *stream, IArchiveOpenCallback *callback)
+{
+ RINOK(_item.ReadHeader(stream))
+ if (!_item.IsSwf() || !_item.IsUncompressed())
+ return S_FALSE;
+ const UInt32 uncompressedSize = _item.GetSize();
+ if (uncompressedSize > kFileSizeMax)
+ return S_FALSE;
+
+
+ CInBuffer s;
+ if (!s.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ s.SetStream(stream);
+ s.Init();
+ {
+ CBitReader br;
+ br.stream = &s;
+ const unsigned numBits = br.ReadBits(5);
+ /* UInt32 xMin = */ br.ReadBits(numBits);
+ /* UInt32 xMax = */ br.ReadBits(numBits);
+ /* UInt32 yMin = */ br.ReadBits(numBits);
+ /* UInt32 yMax = */ br.ReadBits(numBits);
+ }
+ /* UInt32 frameDelay = */ Read16(s);
+ /* UInt32 numFrames = */ Read16(s);
+
+ _tags.Clear();
+ UInt64 offsetPrev = 0;
+ for (;;)
+ {
+ const UInt32 pair = Read16(s);
+ const UInt32 type = pair >> 6;
+ UInt32 length = pair & 0x3F;
+ if (length == 0x3F)
+ length = Read32(s);
+ if (type == 0)
+ break;
+ const UInt64 offset = s.GetProcessedSize() + NSwfc::kHeaderBaseSize + length;
+ if (offset > uncompressedSize || _tags.Size() >= kNumTagsMax)
+ return S_FALSE;
+ CTag &tag = _tags.AddNew();
+ tag.Type = type;
+ tag.Buf.Alloc(length);
+ if (s.ReadBytes(tag.Buf, length) != length)
+ return S_FALSE;
+ if (callback && offset >= offsetPrev + (1 << 20))
+ {
+ const UInt64 numItems = _tags.Size();
+ RINOK(callback->SetCompleted(&numItems, &offset))
+ offsetPrev = offset;
+ }
+ }
+ _phySize = s.GetProcessedSize() + NSwfc::kHeaderBaseSize;
+ if (_phySize != uncompressedSize)
+ {
+ // do we need to support files extracted from SFW-LZMA with additional 8 bytes?
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+HRESULT CHandler::OpenSeq2(ISequentialInStream *stream, IArchiveOpenCallback *callback)
+{
+ HRESULT res;
+ try { res = OpenSeq3(stream, callback); }
+ catch(...) { res = S_FALSE; }
+ return res;
+}
+
+Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream))
+{
+ return OpenSeq2(stream, NULL);
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _phySize = 0;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _tags.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _tags[allFilesMode ? i : indices[i]].Buf.Size();
+ RINOK(extractCallback->SetTotal(totalSize))
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ totalSize = 0;
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = totalSize;
+ RINOK(lps->SetCur())
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CByteBuffer &buf = _tags[index].Buf;
+ totalSize += buf.Size();
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ RINOK(extractCallback->GetStream(index, &outStream, askMode))
+ if (!testMode && !outStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode))
+ if (outStream)
+ RINOK(WriteStream(outStream, buf, buf.Size()))
+ outStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+static const Byte k_Signature[] = { 'F', 'W', 'S' };
+
+REGISTER_ARC_I(
+ "SWF", "swf", NULL, 0xD7,
+ k_Signature,
+ 0,
+ NArcInfoFlags::kKeepName,
+ NSwfc::IsArc_Swf)
+
+}}
diff --git a/CPP/7zip/Archive/Tar/StdAfx.h b/CPP/7zip/Archive/Tar/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/StdAfx.h
@@ -0,0 +1,11 @@
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Archive/Tar/TarHandler.cpp b/CPP/7zip/Archive/Tar/TarHandler.cpp
new file mode 100644
index 0000000..d7fe175
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarHandler.cpp
@@ -0,0 +1,1045 @@
+// TarHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/UTFConvert.h"
+
+#include "../../../Windows/TimeUtils.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/MethodProps.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../Common/ItemNameUtils.h"
+
+#include "TarHandler.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NTar {
+
+// 21.02: we use UTF8 code page by default, even if some files show error
+// before 21.02 : CP_OEMCP;
+// static const UINT k_DefaultCodePage = CP_UTF8;
+
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidCTime,
+ kpidATime,
+ kpidPosixAttrib,
+ kpidUser,
+ kpidGroup,
+ kpidUserId,
+ kpidGroupId,
+ kpidSymLink,
+ kpidHardLink,
+ kpidCharacts,
+ kpidComment
+ , kpidDeviceMajor
+ , kpidDeviceMinor
+ // , kpidDevice
+ // , kpidHeadersSize // for debug
+ // , kpidOffset // for debug
+};
+
+static const Byte kArcProps[] =
+{
+ kpidHeadersSize,
+ kpidCodePage,
+ kpidCharacts,
+ kpidComment
+};
+
+static const char *k_Characts_Prefix = "PREFIX";
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySize: if (_arc._phySize_Defined) prop = _arc._phySize; break;
+ case kpidHeadersSize: if (_arc._phySize_Defined) prop = _arc._headersSize; break;
+ case kpidErrorFlags:
+ {
+ UInt32 flags = 0;
+ if (!_isArc)
+ flags |= kpv_ErrorFlags_IsNotArc;
+ else switch (_arc._error)
+ {
+ case k_ErrorType_UnexpectedEnd: flags = kpv_ErrorFlags_UnexpectedEnd; break;
+ case k_ErrorType_Corrupted: flags = kpv_ErrorFlags_HeadersError; break;
+ case k_ErrorType_OK: break;
+ // case k_ErrorType_Warning: break;
+ // default: break;
+ }
+ if (flags != 0)
+ prop = flags;
+ break;
+ }
+
+ case kpidWarningFlags:
+ {
+ if (_arc._is_Warning)
+ prop = kpv_ErrorFlags_HeadersError;
+ break;
+ }
+
+ case kpidCodePage:
+ {
+ char sz[16];
+ const char *name = NULL;
+ switch (_openCodePage)
+ {
+ case CP_OEMCP: name = "OEM"; break;
+ case CP_UTF8: name = "UTF-8"; break;
+ }
+ if (!name)
+ {
+ ConvertUInt32ToString(_openCodePage, sz);
+ name = sz;
+ }
+ prop = name;
+ break;
+ }
+
+ case kpidCharacts:
+ {
+ AString s;
+ if (_arc._are_Gnu) s.Add_OptSpaced("GNU");
+ if (_arc._are_Posix) s.Add_OptSpaced("POSIX");
+ if (_arc._are_Pax_Items) s.Add_OptSpaced("PAX_ITEM");
+ if (_arc._pathPrefix_WasUsed) s.Add_OptSpaced(k_Characts_Prefix);
+ if (_arc._are_LongName) s.Add_OptSpaced("LongName");
+ if (_arc._are_LongLink) s.Add_OptSpaced("LongLink");
+ if (_arc._are_Pax) s.Add_OptSpaced("PAX");
+ if (_arc._are_pax_path) s.Add_OptSpaced("path");
+ if (_arc._are_pax_link) s.Add_OptSpaced("linkpath");
+ if (_arc._are_mtime) s.Add_OptSpaced("mtime");
+ if (_arc._are_atime) s.Add_OptSpaced("atime");
+ if (_arc._are_ctime) s.Add_OptSpaced("ctime");
+ if (_arc._is_PaxGlobal_Error) s.Add_OptSpaced("PAX_GLOBAL_ERROR");
+ s.Add_OptSpaced(_encodingCharacts.GetCharactsString());
+ prop = s;
+ break;
+ }
+
+ case kpidComment:
+ {
+ if (_arc.PaxGlobal_Defined)
+ {
+ AString s;
+ _arc.PaxGlobal.Print_To_String(s);
+ if (!s.IsEmpty())
+ prop = s;
+ }
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+
+void CEncodingCharacts::Check(const AString &s)
+{
+ IsAscii = s.IsAscii();
+ if (!IsAscii)
+ {
+ /*
+ {
+ Oem_Checked = true;
+ UString u;
+ MultiByteToUnicodeString2(u, s, CP_OEMCP);
+ Oem_Ok = (u.Find((wchar_t)0xfffd) <= 0);
+ }
+ Utf_Checked = true;
+ */
+ UtfCheck.Check_AString(s);
+ }
+}
+
+
+AString CEncodingCharacts::GetCharactsString() const
+{
+ AString s;
+ if (IsAscii)
+ {
+ s += "ASCII";
+ }
+ /*
+ if (Oem_Checked)
+ {
+ s.Add_Space_if_NotEmpty();
+ s += (Oem_Ok ? "oem-ok" : "oem-error");
+ }
+ if (Utf_Checked)
+ */
+ else
+ {
+ s.Add_Space_if_NotEmpty();
+ s += (UtfCheck.IsOK() ? "UTF8" : "UTF8-ERROR"); // "UTF8-error"
+ {
+ AString s2;
+ UtfCheck.PrintStatus(s2);
+ s.Add_Space_if_NotEmpty();
+ s += s2;
+ }
+ }
+ return s;
+}
+
+
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *callback)
+{
+ UInt64 endPos;
+ {
+ RINOK(InStream_AtBegin_GetSize(stream, endPos))
+ }
+
+ _arc._phySize_Defined = true;
+
+ // bool utf8_OK = true;
+
+ _arc.SeqStream = stream;
+ _arc.InStream = stream;
+ _arc.OpenCallback = callback;
+
+ CItemEx item;
+ for (;;)
+ {
+ _arc.NumFiles = _items.Size();
+ RINOK(_arc.ReadItem(item))
+ if (!_arc.filled)
+ break;
+
+ _isArc = true;
+
+ /*
+ if (!_forceCodePage)
+ {
+ if (utf8_OK) utf8_OK = CheckUTF8(item.Name, item.NameCouldBeReduced);
+ if (utf8_OK) utf8_OK = CheckUTF8(item.LinkName, item.LinkNameCouldBeReduced);
+ if (utf8_OK) utf8_OK = CheckUTF8(item.User);
+ if (utf8_OK) utf8_OK = CheckUTF8(item.Group);
+ }
+ */
+
+ item.EncodingCharacts.Check(item.Name);
+ _encodingCharacts.Update(item.EncodingCharacts);
+
+ _items.Add(item);
+
+ RINOK(stream->Seek((Int64)item.Get_PackSize_Aligned(), STREAM_SEEK_CUR, &_arc._phySize))
+ if (_arc._phySize > endPos)
+ {
+ _arc._error = k_ErrorType_UnexpectedEnd;
+ break;
+ }
+ /*
+ if (_phySize == endPos)
+ {
+ _errorMessage = "There are no trailing zero-filled records";
+ break;
+ }
+ */
+ /*
+ if (callback)
+ {
+ if (_items.Size() == 1)
+ {
+ RINOK(callback->SetTotal(NULL, &endPos));
+ }
+ if ((_items.Size() & 0x3FF) == 0)
+ {
+ const UInt64 numFiles = _items.Size();
+ RINOK(callback->SetCompleted(&numFiles, &_phySize));
+ }
+ }
+ */
+ }
+
+ /*
+ if (!_forceCodePage)
+ {
+ if (!utf8_OK)
+ _curCodePage = k_DefaultCodePage;
+ }
+ */
+ _openCodePage = _curCodePage;
+
+ if (_items.Size() == 0)
+ {
+ if (_arc._error != k_ErrorType_OK)
+ {
+ _isArc = false;
+ return S_FALSE;
+ }
+ if (!callback)
+ return S_FALSE;
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IArchiveOpenVolumeCallback,
+ openVolumeCallback, callback)
+ if (!openVolumeCallback)
+ return S_FALSE;
+ NCOM::CPropVariant prop;
+ if (openVolumeCallback->GetProperty(kpidName, &prop) != S_OK)
+ return S_FALSE;
+ if (prop.vt != VT_BSTR)
+ return S_FALSE;
+ unsigned len = MyStringLen(prop.bstrVal);
+ if (len < 4 || MyStringCompareNoCase(prop.bstrVal + len - 4, L".tar") != 0)
+ return S_FALSE;
+ }
+
+ _isArc = true;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openArchiveCallback))
+{
+ COM_TRY_BEGIN
+ // for (int i = 0; i < 10; i++) // for debug
+ {
+ Close();
+ RINOK(Open2(stream, openArchiveCallback))
+ _stream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream))
+{
+ Close();
+ _seqStream = stream;
+ _isArc = true;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _isArc = false;
+
+ _arc.Clear();
+
+ _curIndex = 0;
+ _latestIsRead = false;
+ _encodingCharacts.Clear();
+ _items.Clear();
+ _seqStream.Release();
+ _stream.Release();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = (_stream ? _items.Size() : (UInt32)(Int32)-1);
+ return S_OK;
+}
+
+CHandler::CHandler()
+{
+ copyCoderSpec = new NCompress::CCopyCoder();
+ copyCoder = copyCoderSpec;
+ _openCodePage = CP_UTF8;
+ Init();
+}
+
+HRESULT CHandler::SkipTo(UInt32 index)
+{
+ while (_curIndex < index || !_latestIsRead)
+ {
+ if (_latestIsRead)
+ {
+ const UInt64 packSize = _latestItem.Get_PackSize_Aligned();
+ RINOK(copyCoder->Code(_seqStream, NULL, &packSize, &packSize, NULL))
+ _arc._phySize += copyCoderSpec->TotalSize;
+ if (copyCoderSpec->TotalSize != packSize)
+ {
+ _arc._error = k_ErrorType_UnexpectedEnd;
+ return S_FALSE;
+ }
+ _latestIsRead = false;
+ _curIndex++;
+ }
+ else
+ {
+ _arc.SeqStream = _seqStream;
+ _arc.InStream = NULL;
+ RINOK(_arc.ReadItem(_latestItem))
+ if (!_arc.filled)
+ {
+ _arc._phySize_Defined = true;
+ return E_INVALIDARG;
+ }
+ _latestIsRead = true;
+ }
+ }
+ return S_OK;
+}
+
+void CHandler::TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs) const
+{
+ UString dest;
+ if (_curCodePage == CP_UTF8)
+ ConvertUTF8ToUnicode(s, dest);
+ else
+ MultiByteToUnicodeString2(dest, s, _curCodePage);
+ if (toOs)
+ NItemName::ReplaceToOsSlashes_Remove_TailSlash(dest,
+ true); // useBackslashReplacement
+ prop = dest;
+}
+
+
+// CPaxTime is defined (NumDigits >= 0)
+static void PaxTimeToProp(const CPaxTime &pt, NWindows::NCOM::CPropVariant &prop)
+{
+ UInt64 v;
+ if (!NTime::UnixTime64_To_FileTime64(pt.Sec, v))
+ return;
+ if (pt.Ns != 0)
+ v += pt.Ns / 100;
+ FILETIME ft;
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+ prop.SetAsTimeFrom_FT_Prec_Ns100(ft,
+ k_PropVar_TimePrec_Base + (unsigned)pt.NumDigits, pt.Ns % 100);
+}
+
+
+#define ValToHex(t) ((char)(((t) < 10) ? ('0' + (t)) : ('a' + ((t) - 10))))
+
+static void AddByteToHex2(unsigned val, AString &s)
+{
+ unsigned t;
+ t = val >> 4;
+ s += ValToHex(t);
+ t = val & 0xF;
+ s += ValToHex(t);
+}
+
+static void AddSpecCharToString(const char c, AString &s)
+{
+ if ((Byte)c <= 0x20 || (Byte)c > 127)
+ {
+ s += '[';
+ AddByteToHex2((Byte)(c), s);
+ s += ']';
+ }
+ else
+ s += c;
+}
+
+static void AddSpecUInt64(AString &s, const char *name, UInt64 v)
+{
+ if (v != 0)
+ {
+ s.Add_OptSpaced(name);
+ if (v > 1)
+ {
+ s += ':';
+ s.Add_UInt64(v);
+ }
+ }
+}
+
+static void AddSpecBools(AString &s, const char *name, bool b1, bool b2)
+{
+ if (b1)
+ {
+ s.Add_OptSpaced(name);
+ if (b2)
+ s += '*';
+ }
+}
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ const CItemEx *item;
+ if (_stream)
+ item = &_items[index];
+ else
+ {
+ if (index < _curIndex)
+ return E_INVALIDARG;
+ else
+ {
+ RINOK(SkipTo(index))
+ item = &_latestItem;
+ }
+ }
+
+ switch (propID)
+ {
+ case kpidPath: TarStringToUnicode(item->Name, prop, true); break;
+ case kpidIsDir: prop = item->IsDir(); break;
+ case kpidSize: prop = item->Get_UnpackSize(); break;
+ case kpidPackSize: prop = item->Get_PackSize_Aligned(); break;
+ case kpidMTime:
+ {
+ /*
+ // for debug:
+ PropVariant_SetFrom_UnixTime(prop, 1 << 30);
+ prop.wReserved1 = k_PropVar_TimePrec_Base + 1;
+ prop.wReserved2 = 12;
+ break;
+ */
+
+ if (item->PaxTimes.MTime.IsDefined())
+ PaxTimeToProp(item->PaxTimes.MTime, prop);
+ else
+ // if (item->MTime != 0)
+ {
+ // we allow (item->MTime == 0)
+ FILETIME ft;
+ if (NTime::UnixTime64_To_FileTime(item->MTime, ft))
+ {
+ unsigned prec = k_PropVar_TimePrec_Unix;
+ if (item->MTime_IsBin)
+ {
+ /* we report here that it's Int64-UnixTime
+ instead of basic UInt32-UnixTime range */
+ prec = k_PropVar_TimePrec_Base;
+ }
+ prop.SetAsTimeFrom_FT_Prec(ft, prec);
+ }
+ }
+ break;
+ }
+ case kpidATime:
+ if (item->PaxTimes.ATime.IsDefined())
+ PaxTimeToProp(item->PaxTimes.ATime, prop);
+ break;
+ case kpidCTime:
+ if (item->PaxTimes.CTime.IsDefined())
+ PaxTimeToProp(item->PaxTimes.CTime, prop);
+ break;
+ case kpidPosixAttrib: prop = item->Get_Combined_Mode(); break;
+
+ case kpidUser:
+ if (!item->User.IsEmpty())
+ TarStringToUnicode(item->User, prop);
+ break;
+ case kpidGroup:
+ if (!item->Group.IsEmpty())
+ TarStringToUnicode(item->Group, prop);
+ break;
+
+ case kpidUserId:
+ // if (item->UID != 0)
+ prop = (UInt32)item->UID;
+ break;
+ case kpidGroupId:
+ // if (item->GID != 0)
+ prop = (UInt32)item->GID;
+ break;
+
+ case kpidDeviceMajor:
+ if (item->DeviceMajor_Defined)
+ // if (item->DeviceMajor != 0)
+ prop = (UInt32)item->DeviceMajor;
+ break;
+
+ case kpidDeviceMinor:
+ if (item->DeviceMinor_Defined)
+ // if (item->DeviceMinor != 0)
+ prop = (UInt32)item->DeviceMinor;
+ break;
+ /*
+ case kpidDevice:
+ if (item->DeviceMajor_Defined)
+ if (item->DeviceMinor_Defined)
+ prop = (UInt64)MY_dev_makedev(item->DeviceMajor, item->DeviceMinor);
+ break;
+ */
+
+ case kpidSymLink:
+ if (item->Is_SymLink())
+ if (!item->LinkName.IsEmpty())
+ TarStringToUnicode(item->LinkName, prop);
+ break;
+ case kpidHardLink:
+ if (item->Is_HardLink())
+ if (!item->LinkName.IsEmpty())
+ TarStringToUnicode(item->LinkName, prop);
+ break;
+
+ case kpidCharacts:
+ {
+ AString s;
+ {
+ s.Add_Space_if_NotEmpty();
+ AddSpecCharToString(item->LinkFlag, s);
+ }
+ if (item->IsMagic_GNU())
+ s.Add_OptSpaced("GNU");
+ else if (item->IsMagic_Posix_ustar_00())
+ s.Add_OptSpaced("POSIX");
+ else
+ {
+ s.Add_Space_if_NotEmpty();
+ for (unsigned i = 0; i < sizeof(item->Magic); i++)
+ AddSpecCharToString(item->Magic[i], s);
+ }
+
+ if (item->IsSignedChecksum)
+ s.Add_OptSpaced("SignedChecksum");
+
+ if (item->Prefix_WasUsed)
+ s.Add_OptSpaced(k_Characts_Prefix);
+
+ s.Add_OptSpaced(item->EncodingCharacts.GetCharactsString());
+
+ // AddSpecUInt64(s, "LongName", item->Num_LongName_Records);
+ // AddSpecUInt64(s, "LongLink", item->Num_LongLink_Records);
+ AddSpecBools(s, "LongName", item->LongName_WasUsed, item->LongName_WasUsed_2);
+ AddSpecBools(s, "LongLink", item->LongLink_WasUsed, item->LongLink_WasUsed_2);
+
+ if (item->MTime_IsBin)
+ s.Add_OptSpaced("bin_mtime");
+ if (item->PackSize_IsBin)
+ s.Add_OptSpaced("bin_psize");
+ if (item->Size_IsBin)
+ s.Add_OptSpaced("bin_size");
+
+ AddSpecUInt64(s, "PAX", item->Num_Pax_Records);
+
+ if (item->PaxTimes.MTime.IsDefined()) s.Add_OptSpaced("mtime");
+ if (item->PaxTimes.ATime.IsDefined()) s.Add_OptSpaced("atime");
+ if (item->PaxTimes.CTime.IsDefined()) s.Add_OptSpaced("ctime");
+
+ if (item->pax_path_WasUsed)
+ s.Add_OptSpaced("pax_path");
+ if (item->pax_link_WasUsed)
+ s.Add_OptSpaced("pax_linkpath");
+ if (item->pax_size_WasUsed)
+ s.Add_OptSpaced("pax_size");
+
+ if (item->IsThereWarning())
+ s.Add_OptSpaced("WARNING");
+ if (item->HeaderError)
+ s.Add_OptSpaced("ERROR");
+ if (item->Pax_Error)
+ s.Add_OptSpaced("PAX_error");
+ if (!item->PaxExtra.RawLines.IsEmpty())
+ s.Add_OptSpaced("PAX_unsupported_line");
+ if (item->Pax_Overflow)
+ s.Add_OptSpaced("PAX_overflow");
+ if (!s.IsEmpty())
+ prop = s;
+ break;
+ }
+ case kpidComment:
+ {
+ AString s;
+ item->PaxExtra.Print_To_String(s);
+ if (!s.IsEmpty())
+ prop = s;
+ break;
+ }
+ // case kpidHeadersSize: prop = item->HeaderSize; break; // for debug
+ // case kpidOffset: prop = item->HeaderPos; break; // for debug
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ ISequentialInStream *stream = _seqStream;
+ const bool seqMode = (_stream == NULL);
+ if (!seqMode)
+ stream = _stream;
+
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (_stream && numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _items[allFilesMode ? i : indices[i]].Get_UnpackSize();
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 totalPackSize;
+ totalSize = totalPackSize = 0;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(stream);
+
+ CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+ for (i = 0; i < numItems || seqMode; i++)
+ {
+ lps->InSize = totalPackSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur())
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CItemEx *item;
+ if (seqMode)
+ {
+ HRESULT res = SkipTo(index);
+ if (res == E_INVALIDARG)
+ break;
+ RINOK(res)
+ item = &_latestItem;
+ }
+ else
+ item = &_items[index];
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+ const UInt64 unpackSize = item->Get_UnpackSize();
+ totalSize += unpackSize;
+ totalPackSize += item->Get_PackSize_Aligned();
+ if (item->IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+ bool skipMode = false;
+ if (!testMode && !realOutStream)
+ {
+ if (!seqMode)
+ {
+ /*
+ // probably we must show extracting info it callback handler instead
+ if (item->IsHardLink() ||
+ item->IsSymLink())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ }
+ */
+ continue;
+ }
+ skipMode = true;
+ askMode = NExtract::NAskMode::kSkip;
+ }
+ RINOK(extractCallback->PrepareOperation(askMode))
+
+ outStreamSpec->SetStream(realOutStream);
+ realOutStream.Release();
+ outStreamSpec->Init(skipMode ? 0 : unpackSize, true);
+
+ Int32 opRes = NExtract::NOperationResult::kOK;
+ CMyComPtr<ISequentialInStream> inStream2;
+ if (!item->Is_Sparse())
+ inStream2 = inStream;
+ else
+ {
+ GetStream(index, &inStream2);
+ if (!inStream2)
+ return E_FAIL;
+ }
+
+ {
+ if (item->Is_SymLink())
+ {
+ RINOK(WriteStream(outStreamSpec, (const char *)item->LinkName, item->LinkName.Len()))
+ }
+ else
+ {
+ if (!seqMode)
+ {
+ RINOK(InStream_SeekSet(_stream, item->Get_DataPos()))
+ }
+ streamSpec->Init(item->Get_PackSize_Aligned());
+ RINOK(copyCoder->Code(inStream2, outStream, NULL, NULL, progress))
+ }
+ if (outStreamSpec->GetRem() != 0)
+ opRes = NExtract::NOperationResult::kDataError;
+ }
+ if (seqMode)
+ {
+ _latestIsRead = false;
+ _curIndex++;
+ }
+ outStreamSpec->ReleaseStream();
+ RINOK(extractCallback->SetOperationResult(opRes))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_CLASS_IMP_IInStream(
+ CSparseStream
+)
+ UInt64 _phyPos;
+ UInt64 _virtPos;
+ bool _needStartSeek;
+
+public:
+ CHandler *Handler;
+ CMyComPtr<IUnknown> HandlerRef;
+ unsigned ItemIndex;
+ CRecordVector<UInt64> PhyOffsets;
+
+ void Init()
+ {
+ _virtPos = 0;
+ _phyPos = 0;
+ _needStartSeek = true;
+ }
+};
+
+
+Z7_COM7F_IMF(CSparseStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ const CItemEx &item = Handler->_items[ItemIndex];
+ if (_virtPos >= item.Size)
+ return S_OK;
+ {
+ UInt64 rem = item.Size - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ HRESULT res = S_OK;
+
+ if (item.SparseBlocks.IsEmpty())
+ memset(data, 0, size);
+ else
+ {
+ unsigned left = 0, right = item.SparseBlocks.Size();
+ for (;;)
+ {
+ const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ if (mid == left)
+ break;
+ if (_virtPos < item.SparseBlocks[mid].Offset)
+ right = mid;
+ else
+ left = mid;
+ }
+
+ const CSparseBlock &sb = item.SparseBlocks[left];
+ UInt64 relat = _virtPos - sb.Offset;
+
+ if (_virtPos >= sb.Offset && relat < sb.Size)
+ {
+ UInt64 rem = sb.Size - relat;
+ if (size > rem)
+ size = (UInt32)rem;
+ UInt64 phyPos = PhyOffsets[left] + relat;
+ if (_needStartSeek || _phyPos != phyPos)
+ {
+ RINOK(InStream_SeekSet(Handler->_stream, (item.Get_DataPos() + phyPos)))
+ _needStartSeek = false;
+ _phyPos = phyPos;
+ }
+ res = Handler->_stream->Read(data, size, &size);
+ _phyPos += size;
+ }
+ else
+ {
+ UInt64 next = item.Size;
+ if (_virtPos < sb.Offset)
+ next = sb.Offset;
+ else if (left + 1 < item.SparseBlocks.Size())
+ next = item.SparseBlocks[left + 1].Offset;
+ UInt64 rem = next - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ memset(data, 0, size);
+ }
+ }
+
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return res;
+}
+
+Z7_COM7F_IMF(CSparseStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += Handler->_items[ItemIndex].Size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _virtPos = (UInt64)offset;
+ if (newPosition)
+ *newPosition = _virtPos;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+
+ const CItemEx &item = _items[index];
+
+ if (item.Is_Sparse())
+ {
+ CSparseStream *streamSpec = new CSparseStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ streamSpec->Init();
+ streamSpec->Handler = this;
+ streamSpec->HandlerRef = (IInArchive *)this;
+ streamSpec->ItemIndex = index;
+ streamSpec->PhyOffsets.Reserve(item.SparseBlocks.Size());
+ UInt64 offs = 0;
+ FOR_VECTOR(i, item.SparseBlocks)
+ {
+ const CSparseBlock &sb = item.SparseBlocks[i];
+ streamSpec->PhyOffsets.AddInReserved(offs);
+ offs += sb.Size;
+ }
+ *stream = streamTemp.Detach();
+ return S_OK;
+ }
+
+ if (item.Is_SymLink())
+ {
+ Create_BufInStream_WithReference((const Byte *)(const char *)item.LinkName, item.LinkName.Len(), (IInArchive *)this, stream);
+ return S_OK;
+ }
+
+ return CreateLimitedInStream(_stream, item.Get_DataPos(), item.PackSize, stream);
+
+ COM_TRY_END
+}
+
+
+void CHandler::Init()
+{
+ _forceCodePage = false;
+ _curCodePage = _specifiedCodePage = CP_UTF8; // CP_OEMCP;
+ _posixMode = false;
+ _posixMode_WasForced = false;
+ // TimeOptions.Clear();
+ _handlerTimeOptions.Init();
+ // _handlerTimeOptions.Write_MTime.Val = true; // it's default already
+}
+
+
+Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
+{
+ Init();
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ UString name = names[i];
+ name.MakeLower_Ascii();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+
+ const PROPVARIANT &prop = values[i];
+
+ if (name[0] == L'x')
+ {
+ // some clients write 'x' property. So we support it
+ UInt32 level = 0;
+ RINOK(ParsePropToUInt32(name.Ptr(1), prop, level))
+ }
+ else if (name.IsEqualTo("cp"))
+ {
+ UInt32 cp = CP_OEMCP;
+ RINOK(ParsePropToUInt32(L"", prop, cp))
+ _forceCodePage = true;
+ _curCodePage = _specifiedCodePage = cp;
+ }
+ else if (name.IsPrefixedBy_Ascii_NoCase("mt"))
+ {
+ }
+ else if (name.IsPrefixedBy_Ascii_NoCase("memuse"))
+ {
+ }
+ else if (name.IsEqualTo("m"))
+ {
+ if (prop.vt != VT_BSTR)
+ return E_INVALIDARG;
+ const UString s = prop.bstrVal;
+ if (s.IsEqualTo_Ascii_NoCase("pax") ||
+ s.IsEqualTo_Ascii_NoCase("posix"))
+ _posixMode = true;
+ else if (s.IsEqualTo_Ascii_NoCase("gnu"))
+ _posixMode = false;
+ else
+ return E_INVALIDARG;
+ _posixMode_WasForced = true;
+ }
+ else
+ {
+ /*
+ if (name.IsPrefixedBy_Ascii_NoCase("td"))
+ {
+ name.Delete(0, 3);
+ if (prop.vt == VT_EMPTY)
+ {
+ if (name.IsEqualTo_Ascii_NoCase("n"))
+ {
+ // TimeOptions.UseNativeDigits = true;
+ }
+ else if (name.IsEqualTo_Ascii_NoCase("r"))
+ {
+ // TimeOptions.RemoveZeroDigits = true;
+ }
+ else
+ return E_INVALIDARG;
+ }
+ else
+ {
+ UInt32 numTimeDigits = 0;
+ RINOK(ParsePropToUInt32(name, prop, numTimeDigits));
+ TimeOptions.NumDigits_WasForced = true;
+ TimeOptions.NumDigits = numTimeDigits;
+ }
+ }
+ */
+ bool processed = false;
+ RINOK(_handlerTimeOptions.Parse(name, prop, processed))
+ if (processed)
+ continue;
+ return E_INVALIDARG;
+ }
+ }
+ return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Tar/TarHandler.h b/CPP/7zip/Archive/Tar/TarHandler.h
new file mode 100644
index 0000000..451c2fd
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarHandler.h
@@ -0,0 +1,58 @@
+// TarHandler.h
+
+#ifndef ZIP7_INC_TAR_HANDLER_H
+#define ZIP7_INC_TAR_HANDLER_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../Common/HandlerOut.h"
+
+#include "TarIn.h"
+
+namespace NArchive {
+namespace NTar {
+
+Z7_CLASS_IMP_CHandler_IInArchive_4(
+ IArchiveOpenSeq
+ , IInArchiveGetStream
+ , ISetProperties
+ , IOutArchive
+)
+public:
+ CObjectVector<CItemEx> _items;
+ CMyComPtr<IInStream> _stream;
+ CMyComPtr<ISequentialInStream> _seqStream;
+private:
+ bool _isArc;
+ bool _posixMode_WasForced;
+ bool _posixMode;
+ bool _forceCodePage;
+ UInt32 _specifiedCodePage;
+ UInt32 _curCodePage;
+ UInt32 _openCodePage;
+ // CTimeOptions TimeOptions;
+ CHandlerTimeOptions _handlerTimeOptions;
+ CEncodingCharacts _encodingCharacts;
+
+ UInt32 _curIndex;
+ bool _latestIsRead;
+ CItemEx _latestItem;
+
+ CArchive _arc;
+
+ NCompress::CCopyCoder *copyCoderSpec;
+ CMyComPtr<ICompressCoder> copyCoder;
+
+ HRESULT Open2(IInStream *stream, IArchiveOpenCallback *callback);
+ HRESULT SkipTo(UInt32 index);
+ void TarStringToUnicode(const AString &s, NWindows::NCOM::CPropVariant &prop, bool toOs = false) const;
+public:
+ void Init();
+ CHandler();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Tar/TarHandlerOut.cpp b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
new file mode 100644
index 0000000..c93a86e
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarHandlerOut.cpp
@@ -0,0 +1,332 @@
+// TarHandlerOut.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/MyLinux.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/TimeUtils.h"
+
+#include "../Common/ItemNameUtils.h"
+
+#include "TarHandler.h"
+#include "TarUpdate.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NTar {
+
+Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *type))
+{
+ UInt32 t = NFileTimeType::kUnix;
+ const UInt32 prec = _handlerTimeOptions.Prec;
+ if (prec != (UInt32)(Int32)-1)
+ {
+ t = NFileTimeType::kWindows;
+ if (prec == k_PropVar_TimePrec_0 ||
+ prec == k_PropVar_TimePrec_100ns)
+ t = NFileTimeType::kWindows;
+ else if (prec == k_PropVar_TimePrec_HighPrec)
+ t = k_PropVar_TimePrec_1ns;
+ else if (prec >= k_PropVar_TimePrec_Base)
+ t = prec;
+ }
+ // 7-Zip before 22.00 fails, if unknown typeType.
+ *type = t;
+ return S_OK;
+}
+
+
+void Get_AString_From_UString(const UString &s, AString &res,
+ UINT codePage, unsigned utfFlags)
+{
+ if (codePage == CP_UTF8)
+ ConvertUnicodeToUTF8_Flags(s, res, utfFlags);
+ else
+ UnicodeStringToMultiByte2(res, s, codePage);
+}
+
+
+HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res,
+ UINT codePage, unsigned utfFlags, bool convertSlash)
+{
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(index, propId, &prop))
+
+ if (prop.vt == VT_BSTR)
+ {
+ UString s = prop.bstrVal;
+ if (convertSlash)
+ NItemName::ReplaceSlashes_OsToUnix(s);
+ Get_AString_From_UString(s, res, codePage, utfFlags);
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+
+ return S_OK;
+}
+
+
+// sort old files with original order.
+
+static int CompareUpdateItems(void *const *p1, void *const *p2, void *)
+{
+ const CUpdateItem &u1 = *(*((const CUpdateItem *const *)p1));
+ const CUpdateItem &u2 = *(*((const CUpdateItem *const *)p2));
+ if (!u1.NewProps)
+ {
+ if (u2.NewProps)
+ return -1;
+ return MyCompare(u1.IndexInArc, u2.IndexInArc);
+ }
+ if (!u2.NewProps)
+ return 1;
+ return MyCompare(u1.IndexInClient, u2.IndexInClient);
+}
+
+
+static HRESULT GetTime(UInt32 i, UInt32 pid, IArchiveUpdateCallback *callback,
+ CPaxTime &pt)
+{
+ pt.Clear();
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, pid, &prop))
+ return Prop_To_PaxTime(prop, pt);
+}
+
+
+/*
+static HRESULT GetDevice(IArchiveUpdateCallback *callback, UInt32 i,
+ UInt32 &majo, UInt32 &mino, bool &majo_defined, bool &mino_defined)
+{
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidDevice, &prop));
+ if (prop.vt == VT_EMPTY)
+ return S_OK;
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ {
+ const UInt64 v = prop.uhVal.QuadPart;
+ majo = MY_dev_major(v);
+ mino = MY_dev_minor(v);
+ majo_defined = true;
+ mino_defined = true;
+ }
+ return S_OK;
+}
+*/
+
+static HRESULT GetDevice(IArchiveUpdateCallback *callback, UInt32 i,
+ UInt32 pid, UInt32 &id, bool &defined)
+{
+ defined = false;
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, pid, &prop))
+ if (prop.vt == VT_EMPTY)
+ return S_OK;
+ if (prop.vt == VT_UI4)
+ {
+ id = prop.ulVal;
+ defined = true;
+ return S_OK;
+ }
+ return E_INVALIDARG;
+}
+
+
+static HRESULT GetUser(IArchiveUpdateCallback *callback, UInt32 i,
+ UInt32 pidName, UInt32 pidId, AString &name, UInt32 &id,
+ UINT codePage, unsigned utfFlags)
+{
+ // printf("\ncallback->GetProperty(i, pidId, &prop))\n");
+
+ bool isSet = false;
+ {
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, pidId, &prop))
+ if (prop.vt == VT_UI4)
+ {
+ isSet = true;
+ id = prop.ulVal;
+ // printf("\ncallback->GetProperty(i, pidId, &prop)); = %d \n", (unsigned)id);
+ name.Empty();
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ {
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, pidName, &prop))
+ if (prop.vt == VT_BSTR)
+ {
+ const UString s = prop.bstrVal;
+ Get_AString_From_UString(s, name, codePage, utfFlags);
+ if (!isSet)
+ id = 0;
+ }
+ else if (prop.vt == VT_UI4)
+ {
+ id = prop.ulVal;
+ name.Empty();
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+
+
+Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *callback))
+{
+ COM_TRY_BEGIN
+
+ if ((_stream && (_arc._error != k_ErrorType_OK || _arc._is_Warning
+ /* || _isSparse */
+ )) || _seqStream)
+ return E_NOTIMPL;
+ CObjectVector<CUpdateItem> updateItems;
+ const UINT codePage = (_forceCodePage ? _specifiedCodePage : _openCodePage);
+ const unsigned utfFlags = g_Unicode_To_UTF8_Flags;
+ /*
+ // for debug only:
+ unsigned utfFlags = 0;
+ utfFlags |= Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE;
+ utfFlags |= Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR;
+ */
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ CUpdateItem ui;
+ Int32 newData;
+ Int32 newProps;
+ UInt32 indexInArc;
+
+ if (!callback)
+ return E_FAIL;
+
+ RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArc))
+
+ ui.NewProps = IntToBool(newProps);
+ ui.NewData = IntToBool(newData);
+ ui.IndexInArc = (int)indexInArc;
+ ui.IndexInClient = i;
+
+ if (IntToBool(newProps))
+ {
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidIsDir, &prop))
+ if (prop.vt == VT_EMPTY)
+ ui.IsDir = false;
+ else if (prop.vt != VT_BOOL)
+ return E_INVALIDARG;
+ else
+ ui.IsDir = (prop.boolVal != VARIANT_FALSE);
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidPosixAttrib, &prop))
+ if (prop.vt == VT_EMPTY)
+ ui.Mode =
+ MY_LIN_S_IRWXO
+ | MY_LIN_S_IRWXG
+ | MY_LIN_S_IRWXU
+ | (ui.IsDir ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG);
+ else if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ else
+ ui.Mode = prop.ulVal;
+ // 21.07 : we clear high file type bits as GNU TAR.
+ // we will clear it later
+ // ui.Mode &= ~(UInt32)MY_LIN_S_IFMT;
+ }
+
+ if (_handlerTimeOptions.Write_MTime.Val)
+ RINOK(GetTime(i, kpidMTime, callback, ui.PaxTimes.MTime))
+ if (_handlerTimeOptions.Write_ATime.Val)
+ RINOK(GetTime(i, kpidATime, callback, ui.PaxTimes.ATime))
+ if (_handlerTimeOptions.Write_CTime.Val)
+ RINOK(GetTime(i, kpidCTime, callback, ui.PaxTimes.CTime))
+
+ RINOK(GetPropString(callback, i, kpidPath, ui.Name, codePage, utfFlags, true))
+ if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/')
+ ui.Name += '/';
+ // ui.Name += '/'; // for debug
+
+ if (_posixMode)
+ {
+ RINOK(GetDevice(callback, i, kpidDeviceMajor, ui.DeviceMajor, ui.DeviceMajor_Defined))
+ RINOK(GetDevice(callback, i, kpidDeviceMinor, ui.DeviceMinor, ui.DeviceMinor_Defined))
+ }
+
+ RINOK(GetUser(callback, i, kpidUser, kpidUserId, ui.User, ui.UID, codePage, utfFlags))
+ RINOK(GetUser(callback, i, kpidGroup, kpidGroupId, ui.Group, ui.GID, codePage, utfFlags))
+ }
+
+ if (IntToBool(newData))
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidSize, &prop))
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ ui.Size = prop.uhVal.QuadPart;
+ /*
+ // now we support GNU extension for big files
+ if (ui.Size >= ((UInt64)1 << 33))
+ return E_INVALIDARG;
+ */
+ }
+
+ updateItems.Add(ui);
+ }
+
+ if (_arc._are_Pax_Items)
+ {
+ // we restore original order of files, if there are pax items
+ updateItems.Sort(CompareUpdateItems, NULL);
+ }
+
+ CUpdateOptions options;
+
+ options.CodePage = codePage;
+ options.UtfFlags = utfFlags;
+ options.PosixMode = _posixMode;
+
+ options.Write_MTime = _handlerTimeOptions.Write_MTime;
+ options.Write_ATime = _handlerTimeOptions.Write_ATime;
+ options.Write_CTime = _handlerTimeOptions.Write_CTime;
+
+ // options.TimeOptions = TimeOptions;
+
+ const UInt32 prec = _handlerTimeOptions.Prec;
+ if (prec != (UInt32)(Int32)-1)
+ {
+ unsigned numDigits = 0;
+ if (prec == 0)
+ numDigits = 7;
+ else if (prec == k_PropVar_TimePrec_HighPrec
+ || prec >= k_PropVar_TimePrec_1ns)
+ numDigits = 9;
+ else if (prec >= k_PropVar_TimePrec_Base)
+ numDigits = prec - k_PropVar_TimePrec_Base;
+ options.TimeOptions.NumDigitsMax = numDigits;
+ // options.TimeOptions.RemoveZeroMode =
+ // k_PaxTimeMode_DontRemoveZero; // pure for debug
+ // k_PaxTimeMode_RemoveZero_if_PureSecondOnly; // optimized code
+ // k_PaxTimeMode_RemoveZero_Always; // original pax code
+ }
+
+ return UpdateArchive(_stream, outStream, _items, updateItems,
+ options, callback);
+
+ COM_TRY_END
+}
+
+}}
diff --git a/CPP/7zip/Archive/Tar/TarHeader.cpp b/CPP/7zip/Archive/Tar/TarHeader.cpp
new file mode 100644
index 0000000..deae357
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarHeader.cpp
@@ -0,0 +1,99 @@
+// Archive/TarHeader.cpp
+
+#include "StdAfx.h"
+
+#include "TarHeader.h"
+
+namespace NArchive {
+namespace NTar {
+namespace NFileHeader {
+
+ const char * const kLongLink = "././@LongLink";
+ const char * const kLongLink2 = "@LongLink";
+
+ // The magic field is filled with this if uname and gname are valid.
+ namespace NMagic
+ {
+ // const char * const kUsTar = "ustar"; // 5 chars
+ // const char * const kGNUTar = "GNUtar "; // 7 chars and a null
+ // const char * const kEmpty = "\0\0\0\0\0\0\0\0";
+ // 7-Zip used kUsTar_00 before 21.07:
+ const char k_Posix_ustar_00[8] = { 'u', 's', 't', 'a', 'r', 0, '0', '0' } ;
+ // GNU TAR uses such header:
+ const char k_GNU_ustar[8] = { 'u', 's', 't', 'a', 'r', ' ', ' ', 0 } ;
+ }
+
+/*
+pre-POSIX.1-1988 (i.e. v7) tar header:
+-----
+Link indicator:
+'0' or 0 : Normal file
+'1' : Hard link
+'2' : Symbolic link
+Some pre-POSIX.1-1988 tar implementations indicated a directory by having
+a trailing slash (/) in the name.
+
+Numeric values : octal with leading zeroes.
+For historical reasons, a final NUL or space character should also be used.
+Thus only 11 octal digits can be stored from 12 bytes field.
+
+2001 star : introduced a base-256 coding that is indicated by
+setting the high-order bit of the leftmost byte of a numeric field.
+GNU-tar and BSD-tar followed this idea.
+
+versions of tar from before the first POSIX standard from 1988
+pad the values with spaces instead of zeroes.
+
+UStar
+-----
+UStar (Unix Standard TAR) : POSIX IEEE P1003.1 : 1988.
+ 257 signature: "ustar", 0, "00"
+ 265 32 Owner user name
+ 297 32 Owner group name
+ 329 8 Device major number
+ 337 8 Device minor number
+ 345 155 Filename prefix
+
+POSIX.1-2001/pax
+----
+format is known as extended tar format or pax format
+vendor-tagged vendor-specific enhancements.
+tags Defined by the POSIX standard:
+ atime, mtime, path, linkpath, uname, gname, size, uid, gid, ...
+
+
+PAX EXTENSION
+-----------
+Hard links
+A further difference from the ustar header block is that data blocks
+for files of typeflag 1 (hard link) may be included,
+which means that the size field may be greater than zero.
+Archives created by pax -o linkdata shall include these data
+blocks with the hard links.
+*
+
+compatiblity
+------------
+ 7-Zip 16.03 supports "PaxHeader/"
+ 7-Zip 20.01 supports "PaxHeaders.X/" with optional "./"
+ 7-Zip 21.02 supports "@PaxHeader" with optional "./" "./"
+
+ GNU tar --format=posix uses "PaxHeaders/" in folder of file
+
+
+GNU TAR format
+==============
+v7 - Unix V7
+oldgnu - GNU tar <=1.12 : writes zero in last character in name
+gnu - GNU tar 1.13 : doesn't write zero in last character in name
+ as 7-zip 21.07
+ustar - POSIX.1-1988
+posix (pax) - POSIX.1-2001
+
+ gnu tar:
+ if (S_ISCHR (st->stat.st_mode) || S_ISBLK (st->stat.st_mode)) {
+ major_t devmajor = major (st->stat.st_rdev);
+ minor_t devminor = minor (st->stat.st_rdev); }
+*/
+
+}}}
diff --git a/CPP/7zip/Archive/Tar/TarHeader.h b/CPP/7zip/Archive/Tar/TarHeader.h
new file mode 100644
index 0000000..aeccd28
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarHeader.h
@@ -0,0 +1,90 @@
+// Archive/TarHeader.h
+
+#ifndef ZIP7_INC_ARCHIVE_TAR_HEADER_H
+#define ZIP7_INC_ARCHIVE_TAR_HEADER_H
+
+#include "../../../Common/MyTypes.h"
+
+namespace NArchive {
+namespace NTar {
+
+namespace NFileHeader
+{
+ const unsigned kRecordSize = 512;
+ const unsigned kNameSize = 100;
+ const unsigned kUserNameSize = 32;
+ const unsigned kGroupNameSize = 32;
+ const unsigned kPrefixSize = 155;
+
+ const unsigned kUstarMagic_Offset = 257;
+
+ /*
+ struct CHeader
+ {
+ char Name[kNameSize];
+ char Mode[8];
+ char UID[8];
+ char GID[8];
+ char Size[12];
+ char ModificationTime[12];
+ char CheckSum[8];
+ char LinkFlag;
+ char LinkName[kNameSize];
+ char Magic[8];
+ char UserName[kUserNameSize];
+ char GroupName[kGroupNameSize];
+ char DeviceMajor[8];
+ char DeviceMinor[8];
+ char Prefix[155];
+ };
+ union CRecord
+ {
+ CHeader Header;
+ Byte Padding[kRecordSize];
+ };
+ */
+
+ namespace NLinkFlag
+ {
+ const char kOldNormal = 0; // Normal disk file, Unix compatible
+ const char kNormal = '0'; // Normal disk file
+ const char kHardLink = '1'; // Link to previously dumped file
+ const char kSymLink = '2'; // Symbolic link
+ const char kCharacter = '3'; // Character special file
+ const char kBlock = '4'; // Block special file
+ const char kDirectory = '5'; // Directory
+ const char kFIFO = '6'; // FIFO special file
+ const char kContiguous = '7'; // Contiguous file
+ const char kGnu_LongLink = 'K';
+ const char kGnu_LongName = 'L';
+ const char kSparse = 'S';
+ const char kLabel = 'V';
+ const char kPax = 'x'; // Extended header with meta data for the next file in the archive (POSIX.1-2001)
+ const char kPax_2 = 'X';
+ const char kGlobal = 'g'; // Global extended header with meta data (POSIX.1-2001)
+ const char kDumpDir = 'D'; /* GNUTYPE_DUMPDIR.
+ data: list of files created by the --incremental (-G) option
+ Each file name is preceded by either
+ - 'Y' (file should be in this archive)
+ - 'N' (file is a directory, or is not stored in the archive.)
+ Each file name is terminated by a null + an additional null after
+ the last file name. */
+ // 'A'-'Z' Vendor specific extensions (POSIX.1-1988)
+ }
+
+ extern const char * const kLongLink; // = "././@LongLink";
+ extern const char * const kLongLink2; // = "@LongLink";
+
+ namespace NMagic
+ {
+ // extern const char * const kUsTar; // = "ustar"; // 5 chars
+ // extern const char * const kGNUTar; // = "GNUtar "; // 7 chars and a null
+ // extern const char * const kEmpty; // = "\0\0\0\0\0\0\0\0"
+ extern const char k_Posix_ustar_00[8];
+ extern const char k_GNU_ustar[8];
+ }
+}
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Tar/TarIn.cpp b/CPP/7zip/Archive/Tar/TarIn.cpp
new file mode 100644
index 0000000..90b6f84
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarIn.cpp
@@ -0,0 +1,1132 @@
+// TarIn.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/StringToInt.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "../IArchive.h"
+
+#include "TarIn.h"
+
+#define NUM_UNROLL_BYTES (8 * 4)
+
+Z7_NO_INLINE static bool IsBufNonZero(const void *data, size_t size);
+Z7_NO_INLINE static bool IsBufNonZero(const void *data, size_t size)
+{
+ const Byte *p = (const Byte *)data;
+
+ for (; size != 0 && ((unsigned)(ptrdiff_t)p & (NUM_UNROLL_BYTES - 1)) != 0; size--)
+ if (*p++ != 0)
+ return true;
+
+ if (size >= NUM_UNROLL_BYTES)
+ {
+ const Byte *lim = p + size;
+ size &= (NUM_UNROLL_BYTES - 1);
+ lim -= size;
+ do
+ {
+ if (*(const UInt64 *)(const void *)(p ) != 0) return true;
+ if (*(const UInt64 *)(const void *)(p + 8 * 1) != 0) return true;
+ if (*(const UInt64 *)(const void *)(p + 8 * 2) != 0) return true;
+ if (*(const UInt64 *)(const void *)(p + 8 * 3) != 0) return true;
+ // if (*(const UInt32 *)(const void *)(p ) != 0) return true;
+ // if (*(const UInt32 *)(const void *)(p + 4 * 1) != 0) return true;
+ // if (*(const UInt32 *)(const void *)(p + 4 * 2) != 0) return true;
+ // if (*(const UInt32 *)(const void *)(p + 4 * 3) != 0) return true;
+ p += NUM_UNROLL_BYTES;
+ }
+ while (p != lim);
+ }
+
+ for (; size != 0; size--)
+ if (*p++ != 0)
+ return true;
+
+ return false;
+}
+
+
+namespace NArchive {
+namespace NTar {
+
+static void MyStrNCpy(char *dest, const char *src, unsigned size)
+{
+ for (unsigned i = 0; i < size; i++)
+ {
+ char c = src[i];
+ dest[i] = c;
+ if (c == 0)
+ break;
+ }
+}
+
+static bool OctalToNumber(const char *srcString, unsigned size, UInt64 &res, bool allowEmpty = false)
+{
+ res = 0;
+ char sz[32];
+ MyStrNCpy(sz, srcString, size);
+ sz[size] = 0;
+ const char *end;
+ unsigned i;
+ for (i = 0; sz[i] == ' '; i++);
+ if (sz[i] == 0)
+ return allowEmpty;
+ res = ConvertOctStringToUInt64(sz + i, &end);
+ return (*end == ' ' || *end == 0);
+}
+
+static bool OctalToNumber32(const char *srcString, UInt32 &res, bool allowEmpty = false)
+{
+ const unsigned kSize = 8;
+ UInt64 res64;
+ if (!OctalToNumber(srcString, kSize, res64, allowEmpty))
+ return false;
+ res = (UInt32)res64;
+ return (res64 <= 0xFFFFFFFF);
+}
+
+#define RIF(x) { if (!(x)) return S_OK; }
+
+static void ReadString(const char *s, unsigned size, AString &result)
+{
+ result.SetFrom_CalcLen(s, size);
+}
+
+static bool ParseInt64(const char *p, Int64 &val, bool &isBin)
+{
+ const UInt32 h = GetBe32(p);
+ val = (Int64)GetBe64(p + 4);
+ isBin = true;
+ if (h == (UInt32)1 << 31)
+ return ((val >> 63) & 1) == 0;
+ if (h == (UInt32)(Int32)-1)
+ return ((val >> 63) & 1) != 0;
+ isBin = false;
+ UInt64 u;
+ const bool res = OctalToNumber(p, 12, u);
+ val = (Int64)u;
+ return res;
+}
+
+static bool ParseInt64_MTime(const char *p, Int64 &val, bool &isBin)
+{
+ // rare case tar : ZEROs in Docker-Windows TARs
+ // rare case tar : spaces
+ isBin = false;
+ if (GetUi32(p) != 0)
+ for (unsigned i = 0; i < 12; i++)
+ if (p[i] != ' ')
+ return ParseInt64(p, val, isBin);
+ val = 0;
+ return true;
+}
+
+static bool ParseSize(const char *p, UInt64 &val, bool &isBin)
+{
+ if (GetBe32(p) == (UInt32)1 << 31)
+ {
+ // GNU extension
+ isBin = true;
+ val = GetBe64(p + 4);
+ return ((val >> 63) & 1) == 0;
+ }
+ isBin = false;
+ return OctalToNumber(p, 12, val,
+ true // 20.03: allow empty size for 'V' Label entry
+ );
+}
+
+static bool ParseSize(const char *p, UInt64 &val)
+{
+ bool isBin;
+ return ParseSize(p, val, isBin);
+}
+
+#define CHECK(x) { if (!(x)) return k_IsArc_Res_NO; }
+
+API_FUNC_IsArc IsArc_Tar(const Byte *p2, size_t size)
+{
+ if (size < NFileHeader::kRecordSize)
+ return k_IsArc_Res_NEED_MORE;
+
+ const char *p = (const char *)p2;
+ p += NFileHeader::kNameSize;
+
+ UInt32 mode;
+ // we allow empty Mode value for LongName prefix items
+ CHECK(OctalToNumber32(p, mode, true)) p += 8;
+
+ // if (!OctalToNumber32(p, item.UID)) item.UID = 0;
+ p += 8;
+ // if (!OctalToNumber32(p, item.GID)) item.GID = 0;
+ p += 8;
+
+ UInt64 packSize;
+ Int64 time;
+ UInt32 checkSum;
+ bool isBin;
+ CHECK(ParseSize(p, packSize, isBin)) p += 12;
+ CHECK(ParseInt64_MTime(p, time, isBin)) p += 12;
+ CHECK(OctalToNumber32(p, checkSum))
+ return k_IsArc_Res_YES;
+}
+
+
+HRESULT CArchive::GetNextItemReal(CItemEx &item)
+{
+ char buf[NFileHeader::kRecordSize];
+
+ error = k_ErrorType_OK;
+ filled = false;
+
+ bool thereAreEmptyRecords = false;
+ for (;;)
+ {
+ size_t processedSize = NFileHeader::kRecordSize;
+ RINOK(ReadStream(SeqStream, buf, &processedSize))
+ if (processedSize == 0)
+ {
+ if (!thereAreEmptyRecords)
+ error = k_ErrorType_UnexpectedEnd; // "There are no trailing zero-filled records";
+ return S_OK;
+ }
+ if (processedSize != NFileHeader::kRecordSize)
+ {
+ if (!thereAreEmptyRecords)
+ error = k_ErrorType_UnexpectedEnd; // error = "There is no correct record at the end of archive";
+ else
+ {
+ /*
+ if (IsEmptyData(buf, processedSize))
+ error = k_ErrorType_UnexpectedEnd;
+ else
+ {
+ // extraReadSize = processedSize;
+ // error = k_ErrorType_Corrupted; // some data after the end tail zeros
+ }
+ */
+ }
+
+ return S_OK;
+ }
+ if (IsBufNonZero(buf, NFileHeader::kRecordSize))
+ break;
+ item.HeaderSize += NFileHeader::kRecordSize;
+ thereAreEmptyRecords = true;
+ if (OpenCallback)
+ {
+ RINOK(Progress(item, 0))
+ }
+ }
+ if (thereAreEmptyRecords)
+ {
+ // error = "There are data after end of archive";
+ return S_OK;
+ }
+
+ char *p = buf;
+
+ error = k_ErrorType_Corrupted;
+
+ // ReadString(p, NFileHeader::kNameSize, item.Name);
+ p += NFileHeader::kNameSize;
+
+ /*
+ item.Name_CouldBeReduced =
+ (item.Name.Len() == NFileHeader::kNameSize ||
+ item.Name.Len() == NFileHeader::kNameSize - 1);
+ */
+
+ // we allow empty Mode value for LongName prefix items
+ RIF(OctalToNumber32(p, item.Mode, true)) p += 8;
+
+ if (!OctalToNumber32(p, item.UID)) { item.UID = 0; } p += 8;
+ if (!OctalToNumber32(p, item.GID)) { item.GID = 0; } p += 8;
+
+ RIF(ParseSize(p, item.PackSize, item.PackSize_IsBin))
+ item.Size = item.PackSize;
+ item.Size_IsBin = item.PackSize_IsBin;
+ p += 12;
+ RIF(ParseInt64_MTime(p, item.MTime, item.MTime_IsBin)) p += 12;
+
+ UInt32 checkSum;
+ RIF(OctalToNumber32(p, checkSum))
+ memset(p, ' ', 8); p += 8;
+
+ item.LinkFlag = *p++;
+
+ ReadString(p, NFileHeader::kNameSize, item.LinkName); p += NFileHeader::kNameSize;
+
+ /*
+ item.LinkName_CouldBeReduced =
+ (item.LinkName.Len() == NFileHeader::kNameSize ||
+ item.LinkName.Len() == NFileHeader::kNameSize - 1);
+ */
+
+ memcpy(item.Magic, p, 8); p += 8;
+
+ ReadString(p, NFileHeader::kUserNameSize, item.User); p += NFileHeader::kUserNameSize;
+ ReadString(p, NFileHeader::kGroupNameSize, item.Group); p += NFileHeader::kGroupNameSize;
+
+ item.DeviceMajor_Defined = (p[0] != 0); if (item.DeviceMajor_Defined) { RIF(OctalToNumber32(p, item.DeviceMajor)) } p += 8;
+ item.DeviceMinor_Defined = (p[0] != 0); if (item.DeviceMinor_Defined) { RIF(OctalToNumber32(p, item.DeviceMinor)) } p += 8;
+
+ if (p[0] != 0
+ && item.IsMagic_ustar_5chars()
+ && (item.LinkFlag != 'L' ))
+ {
+ item.Prefix_WasUsed = true;
+ ReadString(p, NFileHeader::kPrefixSize, item.Name);
+ item.Name += '/';
+ unsigned i;
+ for (i = 0; i < NFileHeader::kNameSize; i++)
+ if (buf[i] == 0)
+ break;
+ item.Name.AddFrom(buf, i);
+ }
+ else
+ ReadString(buf, NFileHeader::kNameSize, item.Name);
+
+ p += NFileHeader::kPrefixSize;
+
+ if (item.LinkFlag == NFileHeader::NLinkFlag::kHardLink)
+ {
+ item.PackSize = 0;
+ item.Size = 0;
+ }
+
+ if (item.LinkFlag == NFileHeader::NLinkFlag::kDirectory)
+ {
+ // GNU tar ignores Size field, if LinkFlag is kDirectory
+ // 21.02 : we set PackSize = 0 to be more compatible with GNU tar
+ item.PackSize = 0;
+ // item.Size = 0;
+ }
+
+ /*
+ TAR standard requires sum of unsigned byte values.
+ But some old TAR programs use sum of signed byte values.
+ So we check both values.
+ */
+ // for (int y = 0; y < 100; y++) // for debug
+ {
+ UInt32 sum0 = 0;
+ {
+ for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
+ sum0 += (Byte)buf[i];
+ }
+ if (sum0 != checkSum)
+ {
+ Int32 sum = 0;
+ for (unsigned i = 0; i < NFileHeader::kRecordSize; i++)
+ sum += (signed char)buf[i];
+ if ((UInt32)sum != checkSum)
+ return S_OK;
+ item.IsSignedChecksum = true;
+ }
+ }
+
+ item.HeaderSize += NFileHeader::kRecordSize;
+
+ if (item.LinkFlag == NFileHeader::NLinkFlag::kSparse)
+ {
+ Byte isExtended = (Byte)buf[482];
+ if (isExtended != 0 && isExtended != 1)
+ return S_OK;
+ RIF(ParseSize(buf + 483, item.Size, item.Size_IsBin))
+ UInt64 min = 0;
+ for (unsigned i = 0; i < 4; i++)
+ {
+ p = buf + 386 + 24 * i;
+ if (GetBe32(p) == 0)
+ {
+ if (isExtended != 0)
+ return S_OK;
+ break;
+ }
+ CSparseBlock sb;
+ RIF(ParseSize(p, sb.Offset))
+ RIF(ParseSize(p + 12, sb.Size))
+ item.SparseBlocks.Add(sb);
+ if (sb.Offset < min || sb.Offset > item.Size)
+ return S_OK;
+ if ((sb.Offset & 0x1FF) != 0 || (sb.Size & 0x1FF) != 0)
+ return S_OK;
+ min = sb.Offset + sb.Size;
+ if (min < sb.Offset)
+ return S_OK;
+ }
+ if (min > item.Size)
+ return S_OK;
+
+ while (isExtended != 0)
+ {
+ size_t processedSize = NFileHeader::kRecordSize;
+ RINOK(ReadStream(SeqStream, buf, &processedSize))
+ if (processedSize != NFileHeader::kRecordSize)
+ {
+ error = k_ErrorType_UnexpectedEnd;
+ return S_OK;
+ }
+
+ item.HeaderSize += NFileHeader::kRecordSize;
+
+ if (OpenCallback)
+ {
+ RINOK(Progress(item, 0))
+ }
+
+ isExtended = (Byte)buf[21 * 24];
+ if (isExtended != 0 && isExtended != 1)
+ return S_OK;
+ for (unsigned i = 0; i < 21; i++)
+ {
+ p = buf + 24 * i;
+ if (GetBe32(p) == 0)
+ {
+ if (isExtended != 0)
+ return S_OK;
+ break;
+ }
+ CSparseBlock sb;
+ RIF(ParseSize(p, sb.Offset))
+ RIF(ParseSize(p + 12, sb.Size))
+ item.SparseBlocks.Add(sb);
+ if (sb.Offset < min || sb.Offset > item.Size)
+ return S_OK;
+ if ((sb.Offset & 0x1FF) != 0 || (sb.Size & 0x1FF) != 0)
+ return S_OK;
+ min = sb.Offset + sb.Size;
+ if (min < sb.Offset)
+ return S_OK;
+ }
+ }
+ if (min > item.Size)
+ return S_OK;
+ }
+
+ if (item.PackSize >= (UInt64)1 << 63)
+ return S_OK;
+
+ filled = true;
+ error = k_ErrorType_OK;
+ return S_OK;
+}
+
+
+HRESULT CArchive::Progress(const CItemEx &item, UInt64 posOffset)
+{
+ const UInt64 pos = item.Get_DataPos() + posOffset;
+ if (NumFiles - NumFiles_Prev < (1 << 16)
+ // && NumRecords - NumRecords_Prev < (1 << 16)
+ && pos - Pos_Prev < ((UInt32)1 << 28))
+ return S_OK;
+ {
+ Pos_Prev = pos;
+ NumFiles_Prev = NumFiles;
+ // NumRecords_Prev = NumRecords;
+ // Sleep(100); // for debug
+ return OpenCallback->SetCompleted(&NumFiles, &pos);
+ }
+}
+
+
+HRESULT CArchive::ReadDataToBuffer(const CItemEx &item,
+ CTempBuffer &tb, size_t stringLimit)
+{
+ tb.Init();
+ UInt64 packSize = item.Get_PackSize_Aligned();
+ if (packSize == 0)
+ return S_OK;
+
+ UInt64 pos;
+
+ {
+ size_t size = stringLimit;
+ if (size > packSize)
+ size = (size_t)packSize;
+ tb.Buffer.AllocAtLeast(size);
+ size_t processedSize = size;
+ const HRESULT res = ReadStream(SeqStream, tb.Buffer, &processedSize);
+ pos = processedSize;
+ if (processedSize != size)
+ {
+ error = k_ErrorType_UnexpectedEnd;
+ return res;
+ }
+ RINOK(res)
+
+ packSize -= size;
+
+ size_t i;
+ const Byte *p = tb.Buffer;
+ for (i = 0; i < size; i++)
+ if (p[i] == 0)
+ break;
+ if (i >= item.PackSize)
+ tb.StringSize_IsConfirmed = true;
+ if (i > item.PackSize)
+ {
+ tb.StringSize = (size_t)item.PackSize;
+ tb.IsNonZeroTail = true;
+ }
+ else
+ {
+ tb.StringSize = i;
+ if (i != size)
+ {
+ tb.StringSize_IsConfirmed = true;
+ if (IsBufNonZero(p + i, size - i))
+ tb.IsNonZeroTail = true;
+ }
+ }
+
+ if (packSize == 0)
+ return S_OK;
+ }
+
+ if (InStream)
+ {
+ RINOK(InStream->Seek((Int64)packSize, STREAM_SEEK_CUR, NULL))
+ return S_OK;
+ }
+ const unsigned kBufSize = 1 << 15;
+ Buffer.AllocAtLeast(kBufSize);
+
+ do
+ {
+ if (OpenCallback)
+ {
+ RINOK(Progress(item, pos))
+ }
+
+ unsigned size = kBufSize;
+ if (size > packSize)
+ size = (unsigned)packSize;
+ size_t processedSize = size;
+ const HRESULT res = ReadStream(SeqStream, Buffer, &processedSize);
+ if (processedSize != size)
+ {
+ error = k_ErrorType_UnexpectedEnd;
+ return res;
+ }
+ if (!tb.IsNonZeroTail)
+ {
+ if (IsBufNonZero(Buffer, size))
+ tb.IsNonZeroTail = true;
+ }
+ packSize -= size;
+ pos += size;
+ }
+ while (packSize != 0);
+ return S_OK;
+}
+
+
+
+struct CPaxInfo: public CPaxTimes
+{
+ bool DoubleTagError;
+ bool TagParsingError;
+ bool UnknownLines_Overflow;
+ bool Size_Defined;
+ bool UID_Defined;
+ bool GID_Defined;
+ bool Path_Defined;
+ bool Link_Defined;
+ bool User_Defined;
+ bool Group_Defined;
+
+ UInt64 Size;
+ UInt32 UID;
+ UInt32 GID;
+
+ AString Path;
+ AString Link;
+ AString User;
+ AString Group;
+ AString UnknownLines;
+
+ bool ParseID(const AString &val, bool &defined, UInt32 &res)
+ {
+ if (defined)
+ DoubleTagError = true;
+ if (val.IsEmpty())
+ return false;
+ const char *end2;
+ res = ConvertStringToUInt32(val.Ptr(), &end2);
+ if (*end2 != 0)
+ return false;
+ defined = true;
+ return true;
+ }
+
+ bool ParsePax(const CTempBuffer &tb, bool isFile);
+};
+
+
+static bool ParsePaxTime(const AString &src, CPaxTime &pt, bool &doubleTagError)
+{
+ if (pt.IsDefined())
+ doubleTagError = true;
+ pt.Clear();
+ const char *s = src.Ptr();
+ bool isNegative = false;
+ if (*s == '-')
+ {
+ isNegative = true;
+ s++;
+ }
+ const char *end;
+ {
+ UInt64 sec = ConvertStringToUInt64(s, &end);
+ if (s == end)
+ return false;
+ if (sec >= ((UInt64)1 << 63))
+ return false;
+ if (isNegative)
+ sec = (UInt64)-(Int64)sec;
+ pt.Sec = (Int64)sec;
+ }
+ if (*end == 0)
+ {
+ pt.Ns = 0;
+ pt.NumDigits = 0;
+ return true;
+ }
+ if (*end != '.')
+ return false;
+ s = end + 1;
+
+ UInt32 ns = 0;
+ unsigned i;
+ const unsigned kNsDigits = 9;
+ for (i = 0;; i++)
+ {
+ const char c = s[i];
+ if (c == 0)
+ break;
+ if (c < '0' || c > '9')
+ return false;
+ // we ignore digits after 9 digits as GNU TAR
+ if (i < kNsDigits)
+ {
+ ns *= 10;
+ ns += (unsigned)(c - '0');
+ }
+ }
+ pt.NumDigits = (int)(i < kNsDigits ? i : kNsDigits);
+ while (i < kNsDigits)
+ {
+ ns *= 10;
+ i++;
+ }
+ if (isNegative && ns != 0)
+ {
+ pt.Sec--;
+ ns = (UInt32)1000 * 1000 * 1000 - ns;
+ }
+ pt.Ns = ns;
+ return true;
+}
+
+
+bool CPaxInfo::ParsePax(const CTempBuffer &tb, bool isFile)
+{
+ DoubleTagError = false;
+ TagParsingError = false;
+ UnknownLines_Overflow = false;
+ Size_Defined = false;
+ UID_Defined = false;
+ GID_Defined = false;
+ Path_Defined = false;
+ Link_Defined = false;
+ User_Defined = false;
+ Group_Defined = false;
+
+ // CPaxTimes::Clear();
+
+ const char *s = (const char *)(const void *)(const Byte *)tb.Buffer;
+ size_t rem = tb.StringSize;
+
+ Clear();
+
+ AString name, val;
+
+ while (rem != 0)
+ {
+ unsigned i;
+ for (i = 0;; i++)
+ {
+ if (i > 24 || i >= rem) // we use limitation for size of (size) field
+ return false;
+ if (s[i] == ' ')
+ break;
+ }
+ if (i == 0)
+ return false;
+ const char *end;
+ const UInt32 size = ConvertStringToUInt32(s, &end);
+ const unsigned offset = (unsigned)(end - s) + 1;
+ if (size > rem
+ || size <= offset + 1
+ || offset != i + 1
+ || s[size - 1] != '\n')
+ return false;
+
+ for (i = offset; i < size; i++)
+ if (s[i] == 0)
+ return false;
+
+ for (i = offset; i < size - 1; i++)
+ if (s[i] == '=')
+ break;
+ if (i == size - 1)
+ return false;
+
+ name.SetFrom(s + offset, i - offset);
+ val.SetFrom(s + i + 1, (unsigned)(size - 1 - (i + 1)));
+
+ bool parsed = false;
+ if (isFile)
+ {
+ bool isDetectedName = true;
+ // only lower case (name) is supported
+ if (name.IsEqualTo("path"))
+ {
+ if (Path_Defined)
+ DoubleTagError = true;
+ Path = val;
+ Path_Defined = true;
+ parsed = true;
+ }
+ else if (name.IsEqualTo("linkpath"))
+ {
+ if (Link_Defined)
+ DoubleTagError = true;
+ Link = val;
+ Link_Defined = true;
+ parsed = true;
+ }
+ else if (name.IsEqualTo("uname"))
+ {
+ if (User_Defined)
+ DoubleTagError = true;
+ User = val;
+ User_Defined = true;
+ parsed = true;
+ }
+ else if (name.IsEqualTo("gname"))
+ {
+ if (Group_Defined)
+ DoubleTagError = true;
+ Group = val;
+ Group_Defined = true;
+ parsed = true;
+ }
+ else if (name.IsEqualTo("uid"))
+ {
+ parsed = ParseID(val, UID_Defined, UID);
+ }
+ else if (name.IsEqualTo("gid"))
+ {
+ parsed = ParseID(val, GID_Defined, GID);
+ }
+ else if (name.IsEqualTo("size"))
+ {
+ if (Size_Defined)
+ DoubleTagError = true;
+ Size_Defined = false;
+ if (!val.IsEmpty())
+ {
+ const char *end2;
+ Size = ConvertStringToUInt64(val.Ptr(), &end2);
+ if (*end2 == 0)
+ {
+ Size_Defined = true;
+ parsed = true;
+ }
+ }
+ }
+ else if (name.IsEqualTo("mtime"))
+ { parsed = ParsePaxTime(val, MTime, DoubleTagError); }
+ else if (name.IsEqualTo("atime"))
+ { parsed = ParsePaxTime(val, ATime, DoubleTagError); }
+ else if (name.IsEqualTo("ctime"))
+ { parsed = ParsePaxTime(val, CTime, DoubleTagError); }
+ else
+ isDetectedName = false;
+ if (isDetectedName && !parsed)
+ TagParsingError = true;
+ }
+ if (!parsed)
+ {
+ if (!UnknownLines_Overflow)
+ {
+ const unsigned addSize = size - offset;
+ if (UnknownLines.Len() + addSize < (1 << 16))
+ UnknownLines.AddFrom(s + offset, addSize);
+ else
+ UnknownLines_Overflow = true;
+ }
+ }
+
+ s += size;
+ rem -= size;
+ }
+ return true;
+}
+
+
+HRESULT CArchive::ReadItem2(CItemEx &item)
+{
+ // CItem
+
+ item.SparseBlocks.Clear();
+ item.PaxTimes.Clear();
+
+ // CItemEx
+
+ item.HeaderSize = 0;
+ item.Num_Pax_Records = 0;
+
+ item.LongName_WasUsed = false;
+ item.LongName_WasUsed_2 = false;
+
+ item.LongLink_WasUsed = false;
+ item.LongLink_WasUsed_2 = false;
+
+ item.HeaderError = false;
+ item.IsSignedChecksum = false;
+ item.Prefix_WasUsed = false;
+
+ item.Pax_Error = false;
+ item.Pax_Overflow = false;
+ item.pax_path_WasUsed = false;
+ item.pax_link_WasUsed = false;
+ item.pax_size_WasUsed = false;
+
+ item.PaxExtra.Clear();
+
+ item.EncodingCharacts.Clear();
+
+ // CArchive temp variable
+
+ NameBuf.Init();
+ LinkBuf.Init();
+ PaxBuf.Init();
+ PaxBuf_global.Init();
+
+ UInt64 numExtraRecords = 0;
+
+ for (;;)
+ {
+ if (OpenCallback)
+ {
+ RINOK(Progress(item, 0))
+ }
+
+ RINOK(GetNextItemReal(item))
+
+ // NumRecords++;
+
+ if (!filled)
+ {
+ if (error == k_ErrorType_OK)
+ if (numExtraRecords != 0
+ || item.LongName_WasUsed
+ || item.LongLink_WasUsed
+ || item.Num_Pax_Records != 0)
+ error = k_ErrorType_Corrupted;
+ return S_OK;
+ }
+ if (error != k_ErrorType_OK)
+ return S_OK;
+
+ numExtraRecords++;
+
+ const char lf = item.LinkFlag;
+ if (lf == NFileHeader::NLinkFlag::kGnu_LongName ||
+ lf == NFileHeader::NLinkFlag::kGnu_LongLink)
+ {
+ // GNU tar ignores item.Name after LinkFlag test
+ // 22.00 : now we also ignore item.Name here
+ /*
+ if (item.Name != NFileHeader::kLongLink &&
+ item.Name != NFileHeader::kLongLink2)
+ {
+ break;
+ // return S_OK;
+ }
+ */
+
+ CTempBuffer *tb =
+ lf == NFileHeader::NLinkFlag::kGnu_LongName ?
+ &NameBuf :
+ &LinkBuf;
+
+ /*
+ if (item.PackSize > (1 << 29))
+ {
+ // break;
+ return S_OK;
+ }
+ */
+
+ const unsigned kLongNameSizeMax = (unsigned)1 << 14;
+ RINOK(ReadDataToBuffer(item, *tb, kLongNameSizeMax))
+ if (error != k_ErrorType_OK)
+ return S_OK;
+
+ if (lf == NFileHeader::NLinkFlag::kGnu_LongName)
+ {
+ item.LongName_WasUsed_2 =
+ item.LongName_WasUsed;
+ item.LongName_WasUsed = true;
+ }
+ else
+ {
+ item.LongLink_WasUsed_2 =
+ item.LongLink_WasUsed;
+ item.LongLink_WasUsed = true;
+ }
+
+ if (!tb->StringSize_IsConfirmed)
+ tb->StringSize = 0;
+ item.HeaderSize += item.Get_PackSize_Aligned();
+ if (tb->StringSize == 0 ||
+ tb->StringSize + 1 != item.PackSize)
+ item.HeaderError = true;
+ if (tb->IsNonZeroTail)
+ item.HeaderError = true;
+ continue;
+ }
+
+ if (lf == NFileHeader::NLinkFlag::kGlobal ||
+ lf == NFileHeader::NLinkFlag::kPax ||
+ lf == NFileHeader::NLinkFlag::kPax_2)
+ {
+ // GNU tar ignores item.Name after LinkFlag test
+ // 22.00 : now we also ignore item.Name here
+ /*
+ if (item.PackSize > (UInt32)1 << 26)
+ {
+ break; // we don't want big PaxBuf files
+ // return S_OK;
+ }
+ */
+ const unsigned kParsingPaxSizeMax = (unsigned)1 << 26;
+
+ const bool isStartHeader = (item.HeaderSize == NFileHeader::kRecordSize);
+
+ CTempBuffer *tb = (lf == NFileHeader::NLinkFlag::kGlobal ? &PaxBuf_global : &PaxBuf);
+
+ RINOK(ReadDataToBuffer(item, *tb, kParsingPaxSizeMax))
+ if (error != k_ErrorType_OK)
+ return S_OK;
+
+ item.HeaderSize += item.Get_PackSize_Aligned();
+
+ if (tb->StringSize != item.PackSize
+ || tb->StringSize == 0
+ || tb->IsNonZeroTail)
+ item.Pax_Error = true;
+
+ item.Num_Pax_Records++;
+ if (lf != NFileHeader::NLinkFlag::kGlobal)
+ {
+ item.PaxExtra.RecordPath = item.Name;
+ continue;
+ }
+ // break; // for debug
+ {
+ if (PaxGlobal_Defined)
+ _is_PaxGlobal_Error = true;
+ CPaxInfo paxInfo;
+ if (paxInfo.ParsePax(PaxBuf_global, false))
+ {
+ PaxGlobal.RawLines = paxInfo.UnknownLines;
+ PaxGlobal.RecordPath = item.Name;
+ PaxGlobal_Defined = true;
+ }
+ else
+ _is_PaxGlobal_Error = true;
+
+ if (isStartHeader
+ && item.Num_Pax_Records == 1
+ && numExtraRecords == 1)
+ {
+ // we skip global pax header info after parsing
+ item.HeaderPos += item.HeaderSize;
+ item.HeaderSize = 0;
+ item.Num_Pax_Records = 0;
+ numExtraRecords = 0;
+ }
+ else
+ _is_PaxGlobal_Error = true;
+ }
+ continue;
+ }
+
+ /*
+ if (lf == NFileHeader::NLinkFlag::kDumpDir ||
+ lf == NFileHeader::NLinkFlag::kSparse)
+ {
+ // GNU Extensions to the Archive Format
+ break;
+ }
+ if (lf > '7' || (lf < '0' && lf != 0))
+ {
+ break;
+ // return S_OK;
+ }
+ */
+ break;
+ }
+
+ // we still use name from main header, if long_name is bad
+ if (item.LongName_WasUsed && NameBuf.StringSize != 0)
+ {
+ NameBuf.CopyToString(item.Name);
+ // item.Name_CouldBeReduced = false;
+ }
+
+ if (item.LongLink_WasUsed)
+ {
+ // we use empty link, if long_link is bad
+ LinkBuf.CopyToString(item.LinkName);
+ // item.LinkName_CouldBeReduced = false;
+ }
+
+ error = k_ErrorType_OK;
+
+ if (PaxBuf.StringSize != 0)
+ {
+ CPaxInfo paxInfo;
+ if (!paxInfo.ParsePax(PaxBuf, true))
+ item.Pax_Error = true;
+ else
+ {
+ if (paxInfo.Path_Defined) // if (!paxInfo.Path.IsEmpty())
+ {
+ item.Name = paxInfo.Path;
+ item.pax_path_WasUsed = true;
+ }
+ if (paxInfo.Link_Defined) // (!paxInfo.Link.IsEmpty())
+ {
+ item.LinkName = paxInfo.Link;
+ item.pax_link_WasUsed = true;
+ }
+ if (paxInfo.User_Defined)
+ {
+ item.User = paxInfo.User;
+ // item.pax_uname_WasUsed = true;
+ }
+ if (paxInfo.Group_Defined)
+ {
+ item.Group = paxInfo.Group;
+ // item.pax_gname_WasUsed = true;
+ }
+ if (paxInfo.UID_Defined)
+ {
+ item.UID = (UInt32)paxInfo.UID;
+ }
+ if (paxInfo.GID_Defined)
+ {
+ item.GID = (UInt32)paxInfo.GID;
+ }
+
+ if (paxInfo.Size_Defined)
+ {
+ const UInt64 piSize = paxInfo.Size;
+ // GNU TAR ignores (item.Size) in that case
+ if (item.Size != 0 && item.Size != piSize)
+ item.Pax_Error = true;
+ item.Size = piSize;
+ item.PackSize = piSize;
+ item.pax_size_WasUsed = true;
+ }
+
+ item.PaxTimes = paxInfo;
+ item.PaxExtra.RawLines = paxInfo.UnknownLines;
+ if (paxInfo.UnknownLines_Overflow)
+ item.Pax_Overflow = true;
+ if (paxInfo.TagParsingError)
+ item.Pax_Error = true;
+ if (paxInfo.DoubleTagError)
+ item.Pax_Error = true;
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+HRESULT CArchive::ReadItem(CItemEx &item)
+{
+ item.HeaderPos = _phySize;
+
+ const HRESULT res = ReadItem2(item);
+
+ /*
+ if (error == k_ErrorType_Warning)
+ _is_Warning = true;
+ else
+ */
+
+ if (error != k_ErrorType_OK)
+ _error = error;
+
+ RINOK(res)
+
+ if (filled)
+ {
+ if (item.IsMagic_GNU())
+ _are_Gnu = true;
+ else if (item.IsMagic_Posix_ustar_00())
+ _are_Posix = true;
+
+ if (item.Num_Pax_Records != 0)
+ _are_Pax = true;
+
+ if (item.PaxTimes.MTime.IsDefined()) _are_mtime = true;
+ if (item.PaxTimes.ATime.IsDefined()) _are_atime = true;
+ if (item.PaxTimes.CTime.IsDefined()) _are_ctime = true;
+
+ if (item.pax_path_WasUsed)
+ _are_pax_path = true;
+ if (item.pax_link_WasUsed)
+ _are_pax_link = true;
+ if (item.LongName_WasUsed)
+ _are_LongName = true;
+ if (item.LongLink_WasUsed)
+ _are_LongLink = true;
+ if (item.Prefix_WasUsed)
+ _pathPrefix_WasUsed = true;
+ /*
+ if (item.IsSparse())
+ _isSparse = true;
+ */
+ if (item.Is_PaxExtendedHeader())
+ _are_Pax_Items = true;
+ if (item.IsThereWarning()
+ || item.HeaderError
+ || item.Pax_Error)
+ _is_Warning = true;
+ }
+
+ const UInt64 headerEnd = item.HeaderPos + item.HeaderSize;
+ // _headersSize += headerEnd - _phySize;
+ // we don't count skipped records
+ _headersSize += item.HeaderSize;
+ _phySize = headerEnd;
+ return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Tar/TarIn.h b/CPP/7zip/Archive/Tar/TarIn.h
new file mode 100644
index 0000000..8c69057
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarIn.h
@@ -0,0 +1,149 @@
+// TarIn.h
+
+#ifndef ZIP7_INC_ARCHIVE_TAR_IN_H
+#define ZIP7_INC_ARCHIVE_TAR_IN_H
+
+#include "../IArchive.h"
+
+#include "TarItem.h"
+
+namespace NArchive {
+namespace NTar {
+
+enum EErrorType
+{
+ k_ErrorType_OK,
+ k_ErrorType_Corrupted,
+ k_ErrorType_UnexpectedEnd
+ // , k_ErrorType_Warning
+};
+
+
+struct CTempBuffer
+{
+ CByteBuffer Buffer;
+ size_t StringSize; // num characters before zero Byte (StringSize <= item.PackSize)
+ bool IsNonZeroTail;
+ bool StringSize_IsConfirmed;
+
+ void CopyToString(AString &s)
+ {
+ s.Empty();
+ if (StringSize != 0)
+ s.SetFrom((const char *)(const void *)(const Byte *)Buffer, (unsigned)StringSize);
+ }
+
+ void Init()
+ {
+ StringSize = 0;
+ IsNonZeroTail = false;
+ StringSize_IsConfirmed = false;
+ }
+};
+
+
+class CArchive
+{
+public:
+ bool _phySize_Defined;
+ bool _is_Warning;
+ bool PaxGlobal_Defined;
+ bool _is_PaxGlobal_Error;
+ bool _are_Pax_Items;
+ bool _are_Gnu;
+ bool _are_Posix;
+ bool _are_Pax;
+ bool _are_mtime;
+ bool _are_atime;
+ bool _are_ctime;
+ bool _are_pax_path;
+ bool _are_pax_link;
+ bool _are_LongName;
+ bool _are_LongLink;
+ bool _pathPrefix_WasUsed;
+ // bool _isSparse;
+
+ // temp internal vars for ReadItem():
+ bool filled;
+private:
+ EErrorType error;
+
+public:
+ UInt64 _phySize;
+ UInt64 _headersSize;
+ EErrorType _error;
+
+ ISequentialInStream *SeqStream;
+ IInStream *InStream;
+ IArchiveOpenCallback *OpenCallback;
+ UInt64 NumFiles;
+ UInt64 NumFiles_Prev;
+ UInt64 Pos_Prev;
+ // UInt64 NumRecords;
+ // UInt64 NumRecords_Prev;
+
+ CPaxExtra PaxGlobal;
+
+ void Clear()
+ {
+ SeqStream = NULL;
+ InStream = NULL;
+ OpenCallback = NULL;
+ NumFiles = 0;
+ NumFiles_Prev = 0;
+ Pos_Prev = 0;
+ // NumRecords = 0;
+ // NumRecords_Prev = 0;
+
+ PaxGlobal.Clear();
+ PaxGlobal_Defined = false;
+ _is_PaxGlobal_Error = false;
+ _are_Pax_Items = false; // if there are final paxItems
+ _are_Gnu = false;
+ _are_Posix = false;
+ _are_Pax = false;
+ _are_mtime = false;
+ _are_atime = false;
+ _are_ctime = false;
+ _are_pax_path = false;
+ _are_pax_link = false;
+ _are_LongName = false;
+ _are_LongLink = false;
+ _pathPrefix_WasUsed = false;
+ // _isSparse = false;
+
+ _is_Warning = false;
+ _error = k_ErrorType_OK;
+
+ _phySize_Defined = false;
+ _phySize = 0;
+ _headersSize = 0;
+ }
+
+private:
+ CTempBuffer NameBuf;
+ CTempBuffer LinkBuf;
+ CTempBuffer PaxBuf;
+ CTempBuffer PaxBuf_global;
+
+ CByteBuffer Buffer;
+
+ HRESULT ReadDataToBuffer(const CItemEx &item, CTempBuffer &tb, size_t stringLimit);
+ HRESULT Progress(const CItemEx &item, UInt64 posOffset);
+ HRESULT GetNextItemReal(CItemEx &item);
+ HRESULT ReadItem2(CItemEx &itemInfo);
+public:
+ CArchive()
+ {
+ // we will call Clear() in CHandler::Close().
+ // Clear(); // it's not required here
+ }
+ HRESULT ReadItem(CItemEx &itemInfo);
+};
+
+
+API_FUNC_IsArc IsArc_Tar(const Byte *p, size_t size);
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Tar/TarItem.h b/CPP/7zip/Archive/Tar/TarItem.h
new file mode 100644
index 0000000..2e12c9d
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarItem.h
@@ -0,0 +1,360 @@
+// TarItem.h
+
+#ifndef ZIP7_INC_ARCHIVE_TAR_ITEM_H
+#define ZIP7_INC_ARCHIVE_TAR_ITEM_H
+
+#include "../../../Common/MyLinux.h"
+#include "../../../Common/UTFConvert.h"
+
+#include "TarHeader.h"
+
+namespace NArchive {
+namespace NTar {
+
+struct CSparseBlock
+{
+ UInt64 Offset;
+ UInt64 Size;
+};
+
+
+enum EPaxTimeRemoveZeroMode
+{
+ k_PaxTimeMode_DontRemoveZero,
+ k_PaxTimeMode_RemoveZero_if_PureSecondOnly,
+ k_PaxTimeMode_RemoveZero_Always
+};
+
+struct CTimeOptions
+{
+ EPaxTimeRemoveZeroMode RemoveZeroMode;
+ unsigned NumDigitsMax;
+
+ void Init()
+ {
+ RemoveZeroMode = k_PaxTimeMode_RemoveZero_if_PureSecondOnly;
+ NumDigitsMax = 0;
+ }
+ CTimeOptions() { Init(); }
+};
+
+
+struct CPaxTime
+{
+ Int32 NumDigits; // -1 means undefined
+ UInt32 Ns; // it's smaller than 1G. Even if (Sec < 0), larger (Ns) value means newer files.
+ Int64 Sec; // can be negative
+
+ Int64 GetSec() const { return NumDigits != -1 ? Sec : 0; }
+
+ bool IsDefined() const { return NumDigits != -1; }
+ // bool IsDefined_And_nonZero() const { return NumDigits != -1 && (Sec != 0 || Ns != 0); }
+
+ void Clear()
+ {
+ NumDigits = -1;
+ Ns = 0;
+ Sec = 0;
+ }
+ CPaxTime() { Clear(); }
+
+ /*
+ void ReducePrecison(int numDigits)
+ {
+ // we don't use this->NumDigits here
+ if (numDigits > 0)
+ {
+ if (numDigits >= 9)
+ return;
+ UInt32 r = 1;
+ for (unsigned i = numDigits; i < 9; i++)
+ r *= 10;
+ Ns /= r;
+ Ns *= r;
+ return;
+ }
+ Ns = 0;
+ if (numDigits == 0)
+ return;
+ UInt32 r;
+ if (numDigits == -1) r = 60;
+ else if (numDigits == -2) r = 60 * 60;
+ else if (numDigits == -3) r = 60 * 60 * 24;
+ else return;
+ Sec /= r;
+ Sec *= r;
+ }
+ */
+};
+
+
+struct CPaxTimes
+{
+ CPaxTime MTime;
+ CPaxTime ATime;
+ CPaxTime CTime;
+
+ void Clear()
+ {
+ MTime.Clear();
+ ATime.Clear();
+ CTime.Clear();
+ }
+
+ /*
+ void ReducePrecison(int numDigits)
+ {
+ MTime.ReducePrecison(numDigits);
+ CTime.ReducePrecison(numDigits);
+ ATime.ReducePrecison(numDigits);
+ }
+ */
+};
+
+
+struct CItem
+{
+ UInt64 PackSize;
+ UInt64 Size;
+ Int64 MTime;
+
+ char LinkFlag;
+ bool DeviceMajor_Defined;
+ bool DeviceMinor_Defined;
+
+ UInt32 Mode;
+ UInt32 UID;
+ UInt32 GID;
+ UInt32 DeviceMajor;
+ UInt32 DeviceMinor;
+
+ AString Name;
+ AString LinkName;
+ AString User;
+ AString Group;
+
+ char Magic[8];
+
+ CPaxTimes PaxTimes;
+
+ CRecordVector<CSparseBlock> SparseBlocks;
+
+ void SetMagic_Posix(bool posixMode)
+ {
+ memcpy(Magic, posixMode ?
+ NFileHeader::NMagic::k_Posix_ustar_00 :
+ NFileHeader::NMagic::k_GNU_ustar,
+ 8);
+ }
+
+ bool Is_SymLink() const { return LinkFlag == NFileHeader::NLinkFlag::kSymLink && (Size == 0); }
+ bool Is_HardLink() const { return LinkFlag == NFileHeader::NLinkFlag::kHardLink; }
+ bool Is_Sparse() const { return LinkFlag == NFileHeader::NLinkFlag::kSparse; }
+
+ UInt64 Get_UnpackSize() const { return Is_SymLink() ? LinkName.Len() : Size; }
+
+ bool Is_PaxExtendedHeader() const
+ {
+ switch (LinkFlag)
+ {
+ case NFileHeader::NLinkFlag::kPax:
+ case NFileHeader::NLinkFlag::kPax_2:
+ case NFileHeader::NLinkFlag::kGlobal:
+ return true;
+ }
+ return false;
+ }
+
+ UInt32 Get_Combined_Mode() const
+ {
+ return (Mode & ~(UInt32)MY_LIN_S_IFMT) | Get_FileTypeMode_from_LinkFlag();
+ }
+
+ void Set_LinkFlag_for_File(UInt32 mode)
+ {
+ char lf = NFileHeader::NLinkFlag::kNormal;
+ if (MY_LIN_S_ISCHR(mode)) lf = NFileHeader::NLinkFlag::kCharacter;
+ else if (MY_LIN_S_ISBLK(mode)) lf = NFileHeader::NLinkFlag::kBlock;
+ else if (MY_LIN_S_ISFIFO(mode)) lf = NFileHeader::NLinkFlag::kFIFO;
+ // else if (MY_LIN_S_ISDIR(mode)) lf = NFileHeader::NLinkFlag::kDirectory;
+ // else if (MY_LIN_S_ISLNK(mode)) lf = NFileHeader::NLinkFlag::kSymLink;
+ LinkFlag = lf;
+ }
+
+ UInt32 Get_FileTypeMode_from_LinkFlag() const
+ {
+ switch (LinkFlag)
+ {
+ /*
+ case NFileHeader::NLinkFlag::kDirectory:
+ case NFileHeader::NLinkFlag::kDumpDir:
+ return MY_LIN_S_IFDIR;
+ */
+ case NFileHeader::NLinkFlag::kSymLink: return MY_LIN_S_IFLNK;
+ case NFileHeader::NLinkFlag::kBlock: return MY_LIN_S_IFBLK;
+ case NFileHeader::NLinkFlag::kCharacter: return MY_LIN_S_IFCHR;
+ case NFileHeader::NLinkFlag::kFIFO: return MY_LIN_S_IFIFO;
+ // case return MY_LIN_S_IFSOCK;
+ }
+
+ if (IsDir())
+ return MY_LIN_S_IFDIR;
+ return MY_LIN_S_IFREG;
+ }
+
+ bool IsDir() const
+ {
+ switch (LinkFlag)
+ {
+ case NFileHeader::NLinkFlag::kDirectory:
+ case NFileHeader::NLinkFlag::kDumpDir:
+ return true;
+ case NFileHeader::NLinkFlag::kOldNormal:
+ case NFileHeader::NLinkFlag::kNormal:
+ case NFileHeader::NLinkFlag::kSymLink:
+ if (Name.IsEmpty())
+ return false;
+ // GNU TAR uses last character as directory marker
+ // we also do it
+ return Name.Back() == '/';
+ // return NItemName::HasTailSlash(Name, CP_OEMCP);
+ }
+ return false;
+ }
+
+ bool IsMagic_ustar_5chars() const
+ {
+ for (unsigned i = 0; i < 5; i++)
+ if (Magic[i] != NFileHeader::NMagic::k_GNU_ustar[i])
+ return false;
+ return true;
+ }
+
+ bool IsMagic_Posix_ustar_00() const
+ {
+ for (unsigned i = 0; i < 8; i++)
+ if (Magic[i] != NFileHeader::NMagic::k_Posix_ustar_00[i])
+ return false;
+ return true;
+ }
+
+ bool IsMagic_GNU() const
+ {
+ for (unsigned i = 0; i < 8; i++)
+ if (Magic[i] != NFileHeader::NMagic::k_GNU_ustar[i])
+ return false;
+ return true;
+ }
+
+ UInt64 Get_PackSize_Aligned() const { return (PackSize + 0x1FF) & (~((UInt64)0x1FF)); }
+
+ bool IsThereWarning() const
+ {
+ // that Header Warning is possible if (Size != 0) for dir item
+ return (PackSize < Size) && (LinkFlag == NFileHeader::NLinkFlag::kDirectory);
+ }
+};
+
+
+
+struct CEncodingCharacts
+{
+ bool IsAscii;
+ // bool Oem_Checked;
+ // bool Oem_Ok;
+ // bool Utf_Checked;
+ CUtf8Check UtfCheck;
+
+ void Clear()
+ {
+ IsAscii = true;
+ // Oem_Checked = false;
+ // Oem_Ok = false;
+ // Utf_Checked = false;
+ UtfCheck.Clear();
+ }
+
+ void Update(const CEncodingCharacts &ec)
+ {
+ if (!ec.IsAscii)
+ IsAscii = false;
+
+ // if (ec.Utf_Checked)
+ {
+ UtfCheck.Update(ec.UtfCheck);
+ // Utf_Checked = true;
+ }
+ }
+
+ CEncodingCharacts() { Clear(); }
+ void Check(const AString &s);
+ AString GetCharactsString() const;
+};
+
+
+struct CPaxExtra
+{
+ AString RecordPath;
+ AString RawLines;
+
+ void Clear()
+ {
+ RecordPath.Empty();
+ RawLines.Empty();
+ }
+
+ void Print_To_String(AString &s) const
+ {
+ if (!RecordPath.IsEmpty())
+ {
+ s += RecordPath;
+ s.Add_LF();
+ }
+ if (!RawLines.IsEmpty())
+ s += RawLines;
+ }
+};
+
+
+struct CItemEx: public CItem
+{
+ bool HeaderError;
+
+ bool IsSignedChecksum;
+ bool Prefix_WasUsed;
+
+ bool Pax_Error;
+ bool Pax_Overflow;
+ bool pax_path_WasUsed;
+ bool pax_link_WasUsed;
+ bool pax_size_WasUsed;
+
+ bool MTime_IsBin;
+ bool PackSize_IsBin;
+ bool Size_IsBin;
+
+ bool LongName_WasUsed;
+ bool LongName_WasUsed_2;
+
+ bool LongLink_WasUsed;
+ bool LongLink_WasUsed_2;
+
+ // bool Name_CouldBeReduced;
+ // bool LinkName_CouldBeReduced;
+
+ UInt64 HeaderPos;
+ UInt64 HeaderSize;
+
+ UInt64 Num_Pax_Records;
+ CPaxExtra PaxExtra;
+
+ CEncodingCharacts EncodingCharacts;
+
+ UInt64 Get_DataPos() const { return HeaderPos + HeaderSize; }
+ // UInt64 GetFullSize() const { return HeaderSize + PackSize; }
+ UInt64 Get_FullSize_Aligned() const { return HeaderSize + Get_PackSize_Aligned(); }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Tar/TarOut.cpp b/CPP/7zip/Archive/Tar/TarOut.cpp
new file mode 100644
index 0000000..26d0855
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarOut.cpp
@@ -0,0 +1,644 @@
+// TarOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/7zCrc.h"
+
+#include "../../../Common/IntToString.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "TarOut.h"
+
+namespace NArchive {
+namespace NTar {
+
+using namespace NFileHeader;
+
+// it's path prefix assigned by 7-Zip to show that file path was cut
+#define K_PREFIX_PATH_CUT "@PathCut"
+
+static const UInt32 k_7_oct_digits_Val_Max = ((UInt32)1 << (7 * 3)) - 1;
+
+static void WriteOctal_8(char *s, UInt32 val)
+{
+ const unsigned kNumDigits = 8 - 1;
+ if (val >= ((UInt32)1 << (kNumDigits * 3)))
+ {
+ val = 0;
+ // return false;
+ }
+ for (unsigned i = 0; i < kNumDigits; i++)
+ {
+ s[kNumDigits - 1 - i] = (char)('0' + (val & 7));
+ val >>= 3;
+ }
+ // return true;
+}
+
+static void WriteBin_64bit(char *s, UInt64 val)
+{
+ for (unsigned i = 0; i < 8; i++, val <<= 8)
+ s[i] = (char)(val >> 56);
+}
+
+static void WriteOctal_12(char *s, UInt64 val)
+{
+ const unsigned kNumDigits = 12 - 1;
+ if (val >= ((UInt64)1 << (kNumDigits * 3)))
+ {
+ // GNU extension;
+ s[0] = (char)(Byte)0x80;
+ s[1] = s[2] = s[3] = 0;
+ WriteBin_64bit(s + 4, val);
+ return;
+ }
+ for (unsigned i = 0; i < kNumDigits; i++)
+ {
+ s[kNumDigits - 1 - i] = (char)('0' + (val & 7));
+ val >>= 3;
+ }
+}
+
+static void WriteOctal_12_Signed(char *s, const Int64 val)
+{
+ if (val >= 0)
+ {
+ WriteOctal_12(s, (UInt64)val);
+ return;
+ }
+ s[0] = s[1] = s[2] = s[3] = (char)(Byte)0xFF;
+ WriteBin_64bit(s + 4, (UInt64)val);
+}
+
+static void CopyString(char *dest, const AString &src, const unsigned maxSize)
+{
+ unsigned len = src.Len();
+ if (len == 0)
+ return;
+ // 21.07: new gnu : we don't require additional 0 character at the end
+ // if (len >= maxSize)
+ if (len > maxSize)
+ {
+ len = maxSize;
+ /*
+ // oldgnu needs 0 character at the end
+ len = maxSize - 1;
+ dest[len] = 0;
+ */
+ }
+ memcpy(dest, src.Ptr(), len);
+}
+
+// #define RETURN_IF_NOT_TRUE(x) { if (!(x)) return E_INVALIDARG; }
+#define RETURN_IF_NOT_TRUE(x) { x; }
+
+#define COPY_STRING_CHECK(dest, src, size) \
+ CopyString(dest, src, size); dest += (size);
+
+#define WRITE_OCTAL_8_CHECK(dest, src) \
+ RETURN_IF_NOT_TRUE(WriteOctal_8(dest, src))
+
+
+HRESULT COutArchive::WriteHeaderReal(const CItem &item, bool isPax
+ // , bool zero_PackSize
+ // , bool zero_MTime
+ )
+{
+ /*
+ if (isPax) { we don't use Glob_Name and Prefix }
+ if (!isPax)
+ {
+ we use Glob_Name if it's not empty
+ we use Prefix if it's not empty
+ }
+ */
+ char record[kRecordSize];
+ memset(record, 0, kRecordSize);
+ char *cur = record;
+
+ COPY_STRING_CHECK (cur,
+ (!isPax && !Glob_Name.IsEmpty()) ? Glob_Name : item.Name,
+ kNameSize)
+
+ WRITE_OCTAL_8_CHECK (cur, item.Mode) cur += 8; // & k_7_oct_digits_Val_Max
+ WRITE_OCTAL_8_CHECK (cur, item.UID) cur += 8;
+ WRITE_OCTAL_8_CHECK (cur, item.GID) cur += 8;
+
+ WriteOctal_12 (cur, /* zero_PackSize ? 0 : */ item.PackSize); cur += 12;
+ WriteOctal_12_Signed (cur, /* zero_MTime ? 0 : */ item.MTime); cur += 12;
+
+ // we will use binary init for checksum instead of memset
+ // checksum field:
+ // memset(cur, ' ', 8);
+ cur += 8;
+
+ *cur++ = item.LinkFlag;
+
+ COPY_STRING_CHECK (cur, item.LinkName, kNameSize)
+
+ memcpy(cur, item.Magic, 8);
+ cur += 8;
+
+ COPY_STRING_CHECK (cur, item.User, kUserNameSize)
+ COPY_STRING_CHECK (cur, item.Group, kGroupNameSize)
+
+ const bool needDevice = (IsPosixMode && !isPax);
+
+ if (item.DeviceMajor_Defined)
+ WRITE_OCTAL_8_CHECK (cur, item.DeviceMajor)
+ else if (needDevice)
+ WRITE_OCTAL_8_CHECK (cur, 0)
+ cur += 8;
+
+ if (item.DeviceMinor_Defined)
+ WRITE_OCTAL_8_CHECK (cur, item.DeviceMinor)
+ else if (needDevice)
+ WRITE_OCTAL_8_CHECK (cur, 0)
+ cur += 8;
+
+ if (!isPax && !Prefix.IsEmpty())
+ {
+ COPY_STRING_CHECK (cur, Prefix, kPrefixSize)
+ }
+
+ if (item.Is_Sparse())
+ {
+ record[482] = (char)(item.SparseBlocks.Size() > 4 ? 1 : 0);
+ WriteOctal_12(record + 483, item.Size);
+ for (unsigned i = 0; i < item.SparseBlocks.Size() && i < 4; i++)
+ {
+ const CSparseBlock &sb = item.SparseBlocks[i];
+ char *p = record + 386 + 24 * i;
+ WriteOctal_12(p, sb.Offset);
+ WriteOctal_12(p + 12, sb.Size);
+ }
+ }
+
+ {
+ UInt32 sum = (unsigned)(' ') * 8; // we use binary init
+ {
+ for (unsigned i = 0; i < kRecordSize; i++)
+ sum += (Byte)record[i];
+ }
+ /* checksum field is formatted differently from the
+ other fields: it has [6] digits, a null, then a space. */
+ // WRITE_OCTAL_8_CHECK(record + 148, sum);
+ const unsigned kNumDigits = 6;
+ for (unsigned i = 0; i < kNumDigits; i++)
+ {
+ record[148 + kNumDigits - 1 - i] = (char)('0' + (sum & 7));
+ sum >>= 3;
+ }
+ // record[148 + 6] = 0; // we need it, if we use memset(' ') init
+ record[148 + 7] = ' '; // we need it, if we use binary init
+ }
+
+ RINOK(Write_Data(record, kRecordSize))
+
+ if (item.Is_Sparse())
+ {
+ for (unsigned i = 4; i < item.SparseBlocks.Size();)
+ {
+ memset(record, 0, kRecordSize);
+ for (unsigned t = 0; t < 21 && i < item.SparseBlocks.Size(); t++, i++)
+ {
+ const CSparseBlock &sb = item.SparseBlocks[i];
+ char *p = record + 24 * t;
+ WriteOctal_12(p, sb.Offset);
+ WriteOctal_12(p + 12, sb.Size);
+ }
+ record[21 * 24] = (char)(i < item.SparseBlocks.Size() ? 1 : 0);
+ RINOK(Write_Data(record, kRecordSize))
+ }
+ }
+
+ return S_OK;
+}
+
+
+static void AddPaxLine(AString &s, const char *name, const AString &val)
+{
+ // s.Add_LF(); // for debug
+ const unsigned len = 3 + (unsigned)strlen(name) + val.Len();
+ AString n;
+ for (unsigned numDigits = 1;; numDigits++)
+ {
+ n.Empty();
+ n.Add_UInt32(numDigits + len);
+ if (numDigits == n.Len())
+ break;
+ }
+ s += n;
+ s.Add_Space();
+ s += name;
+ s += '=';
+ s += val;
+ s.Add_LF();
+}
+
+// pt is defined : (pt.NumDigits >= 0)
+static void AddPaxTime(AString &s, const char *name, const CPaxTime &pt,
+ const CTimeOptions &options)
+{
+ unsigned numDigits = (unsigned)pt.NumDigits;
+ if (numDigits > options.NumDigitsMax)
+ numDigits = options.NumDigitsMax;
+
+ bool needNs = false;
+ UInt32 ns = 0;
+ if (numDigits != 0)
+ {
+ ns = pt.Ns;
+ // if (ns != 0) before reduction, we show all digits after digits reduction
+ needNs = (ns != 0 || options.RemoveZeroMode == k_PaxTimeMode_DontRemoveZero);
+ UInt32 d = 1;
+ for (unsigned k = numDigits; k < 9; k++)
+ d *= 10;
+ ns /= d;
+ ns *= d;
+ }
+
+ AString v;
+ {
+ Int64 sec = pt.Sec;
+ if (pt.Sec < 0)
+ {
+ sec = -sec;
+ v.Add_Minus();
+ if (ns != 0)
+ {
+ ns = 1000*1000*1000 - ns;
+ sec--;
+ }
+ }
+ v.Add_UInt64((UInt64)sec);
+ }
+
+ if (needNs)
+ {
+ AString d;
+ d.Add_UInt32(ns);
+ while (d.Len() < 9)
+ d.InsertAtFront('0');
+ // here we have precision
+ while (d.Len() > (unsigned)numDigits)
+ d.DeleteBack();
+ // GNU TAR reduces '0' digits.
+ if (options.RemoveZeroMode == k_PaxTimeMode_RemoveZero_Always)
+ while (!d.IsEmpty() && d.Back() == '0')
+ d.DeleteBack();
+
+ if (!d.IsEmpty())
+ {
+ v.Add_Dot();
+ v += d;
+ // v += "1234567009999"; // for debug
+ // for (int y = 0; y < 1000; y++) v += '8'; // for debug
+ }
+ }
+
+ AddPaxLine(s, name, v);
+}
+
+
+static void AddPax_UInt32_ifBig(AString &s, const char *name, const UInt32 &v)
+{
+ if (v > k_7_oct_digits_Val_Max)
+ {
+ AString s2;
+ s2.Add_UInt32(v);
+ AddPaxLine(s, name, s2);
+ }
+}
+
+
+/* OLD_GNU_TAR: writes name with zero at the end
+ NEW_GNU_TAR: can write name filled with all kNameSize characters */
+
+static const unsigned kNameSize_Max =
+ kNameSize; // NEW_GNU_TAR / 7-Zip 21.07
+ // kNameSize - 1; // OLD_GNU_TAR / old 7-Zip
+
+#define DOES_NAME_FIT_IN_FIELD(name) ((name).Len() <= kNameSize_Max)
+
+
+HRESULT COutArchive::WriteHeader(const CItem &item)
+{
+ Glob_Name.Empty();
+ Prefix.Empty();
+
+ unsigned namePos = 0;
+ bool needPathCut = false;
+ bool allowPrefix = false;
+
+ if (!DOES_NAME_FIT_IN_FIELD(item.Name))
+ {
+ const char *s = item.Name;
+ const char *p = s + item.Name.Len() - 1;
+ for (; *p == '/' && p != s; p--)
+ {}
+ for (; p != s && p[-1] != '/'; p--)
+ {}
+ namePos = (unsigned)(p - s);
+ needPathCut = true;
+ }
+
+ if (IsPosixMode)
+ {
+ AString s;
+
+ if (needPathCut)
+ {
+ const unsigned nameLen = item.Name.Len() - namePos;
+ if ( item.LinkFlag >= NLinkFlag::kNormal
+ && item.LinkFlag <= NLinkFlag::kDirectory
+ && namePos > 1
+ && nameLen != 0
+ // && IsPrefixAllowed
+ && item.IsMagic_Posix_ustar_00())
+ {
+ /* GNU TAR decoder supports prefix field, only if (magic)
+ signature matches 6-bytes "ustar\0".
+ so here we use prefix field only in posix mode with posix signature */
+
+ allowPrefix = true;
+ // allowPrefix = false; // for debug
+ if (namePos <= kPrefixSize + 1 && nameLen <= kNameSize_Max)
+ {
+ needPathCut = false;
+ /* we will set Prefix and Glob_Name later, for such conditions:
+ if (!DOES_NAME_FIT_IN_FIELD(item.Name) && !needPathCut) */
+ }
+ }
+
+ if (needPathCut)
+ AddPaxLine(s, "path", item.Name);
+ }
+
+ // AddPaxLine(s, "testname", AString("testval")); // for debug
+
+ if (item.LinkName.Len() > kNameSize_Max)
+ AddPaxLine(s, "linkpath", item.LinkName);
+
+ const UInt64 kPaxSize_Limit = ((UInt64)1 << 33);
+ // const UInt64 kPaxSize_Limit = ((UInt64)1 << 1); // for debug
+ // bool zero_PackSize = false;
+ if (item.PackSize >= kPaxSize_Limit)
+ {
+ /* GNU TAR in pax mode sets PackSize = 0 in main record, if pack_size >= 8 GiB
+ But old 7-Zip doesn't detect "size" property from pax header.
+ So we write real size (>= 8 GiB) to main record in binary format,
+ and old 7-Zip can decode size correctly */
+ // zero_PackSize = true;
+ AString v;
+ v.Add_UInt64(item.PackSize);
+ AddPaxLine(s, "size", v);
+ }
+
+ /* GNU TAR encoder can set "devmajor" / "devminor" attributes,
+ but GNU TAR decoder doesn't parse "devmajor" / "devminor" */
+ if (item.DeviceMajor_Defined)
+ AddPax_UInt32_ifBig(s, "devmajor", item.DeviceMajor);
+ if (item.DeviceMinor_Defined)
+ AddPax_UInt32_ifBig(s, "devminor", item.DeviceMinor);
+
+ AddPax_UInt32_ifBig(s, "uid", item.UID);
+ AddPax_UInt32_ifBig(s, "gid", item.GID);
+
+ const UInt64 kPax_MTime_Limit = ((UInt64)1 << 33);
+ const bool zero_MTime = (
+ item.MTime < 0 ||
+ item.MTime >= (Int64)kPax_MTime_Limit);
+
+ const CPaxTime &mtime = item.PaxTimes.MTime;
+ if (mtime.IsDefined())
+ {
+ bool needPax = false;
+ if (zero_MTime)
+ needPax = true;
+ else if (TimeOptions.NumDigitsMax > 0)
+ if (mtime.Ns != 0 ||
+ (mtime.NumDigits != 0 &&
+ TimeOptions.RemoveZeroMode == k_PaxTimeMode_DontRemoveZero))
+ needPax = true;
+ if (needPax)
+ AddPaxTime(s, "mtime", mtime, TimeOptions);
+ }
+
+ if (item.PaxTimes.ATime.IsDefined())
+ AddPaxTime(s, "atime", item.PaxTimes.ATime, TimeOptions);
+ if (item.PaxTimes.CTime.IsDefined())
+ AddPaxTime(s, "ctime", item.PaxTimes.CTime, TimeOptions);
+
+ if (item.User.Len() > kUserNameSize)
+ AddPaxLine(s, "uname", item.User);
+ if (item.Group.Len() > kGroupNameSize)
+ AddPaxLine(s, "gname", item.Group);
+
+ /*
+ // for debug
+ AString a ("11"); for (int y = 0; y < (1 << 24); y++) AddPaxLine(s, "temp", a);
+ */
+
+ const unsigned paxSize = s.Len();
+ if (paxSize != 0)
+ {
+ CItem mi = item;
+ mi.LinkName.Empty();
+ // SparseBlocks will be ignored by Is_Sparse()
+ // mi.SparseBlocks.Clear();
+ // we use "PaxHeader/*" for compatibility with previous 7-Zip decoder
+
+ // GNU TAR writes empty for these fields;
+ mi.User.Empty();
+ mi.Group.Empty();
+ mi.UID = 0;
+ mi.GID = 0;
+
+ mi.DeviceMajor_Defined = false;
+ mi.DeviceMinor_Defined = false;
+
+ mi.Name = "PaxHeader/@PaxHeader";
+ mi.Mode = 0644; // octal
+ if (zero_MTime)
+ mi.MTime = 0;
+ mi.LinkFlag = NLinkFlag::kPax;
+ // mi.LinkFlag = 'Z'; // for debug
+ mi.PackSize = paxSize;
+ // for (unsigned y = 0; y < 1; y++) { // for debug
+ RINOK(WriteHeaderReal(mi, true)) // isPax
+ RINOK(Write_Data_And_Residual(s, paxSize))
+ // } // for debug
+ /*
+ we can send (zero_MTime) for compatibility with gnu tar output.
+ we can send (zero_MTime = false) for better compatibility with old 7-Zip
+ */
+ // return WriteHeaderReal(item);
+ /*
+ false, // isPax
+ false, // zero_PackSize
+ false); // zero_MTime
+ */
+ }
+ }
+ else // !PosixMode
+ if (!DOES_NAME_FIT_IN_FIELD(item.Name) ||
+ !DOES_NAME_FIT_IN_FIELD(item.LinkName))
+ {
+ // here we can get all fields from main (item) or create new empty item
+ /*
+ CItem mi;
+ mi.SetDefaultWriteFields();
+ */
+ CItem mi = item;
+ mi.LinkName.Empty();
+ // SparseBlocks will be ignored by Is_Sparse()
+ // mi.SparseBlocks.Clear();
+ mi.Name = kLongLink;
+ // mi.Name = "././@BAD_LONG_LINK_TEST"; // for debug
+ // 21.07 : we set Mode and MTime props as in GNU TAR:
+ mi.Mode = 0644; // octal
+ mi.MTime = 0;
+
+ mi.User.Empty();
+ mi.Group.Empty();
+ /*
+ gnu tar sets "root" for such items:
+ uid_to_uname (0, &uname);
+ gid_to_gname (0, &gname);
+ */
+ /*
+ mi.User = "root";
+ mi.Group = "root";
+ */
+ mi.UID = 0;
+ mi.GID = 0;
+ mi.DeviceMajor_Defined = false;
+ mi.DeviceMinor_Defined = false;
+
+
+ for (unsigned i = 0; i < 2; i++)
+ {
+ const AString *name;
+ // We suppose that GNU TAR also writes item for long link before item for LongName?
+ if (i == 0)
+ {
+ mi.LinkFlag = NLinkFlag::kGnu_LongLink;
+ name = &item.LinkName;
+ }
+ else
+ {
+ mi.LinkFlag = NLinkFlag::kGnu_LongName;
+ name = &item.Name;
+ }
+ if (DOES_NAME_FIT_IN_FIELD(*name))
+ continue;
+ // GNU TAR writes null character after NAME to file. We do same here:
+ const unsigned nameStreamSize = name->Len() + 1;
+ mi.PackSize = nameStreamSize;
+ // for (unsigned y = 0; y < 3; y++) { // for debug
+ RINOK(WriteHeaderReal(mi))
+ RINOK(Write_Data_And_Residual(name->Ptr(), nameStreamSize))
+ // }
+
+ // for debug
+ /*
+ const unsigned kSize = (1 << 29) + 16;
+ CByteBuffer buf;
+ buf.Alloc(kSize);
+ memset(buf, 0, kSize);
+ memcpy(buf, name->Ptr(), name->Len());
+ const unsigned nameStreamSize = kSize;
+ mi.PackSize = nameStreamSize;
+ // for (unsigned y = 0; y < 3; y++) { // for debug
+ RINOK(WriteHeaderReal(mi));
+ RINOK(WriteBytes(buf, nameStreamSize));
+ RINOK(FillDataResidual(nameStreamSize));
+ */
+ }
+ }
+
+ // bool fals = false; if (fals) // for debug: for bit-to-bit output compatibility with GNU TAR
+
+ if (!DOES_NAME_FIT_IN_FIELD(item.Name))
+ {
+ const unsigned nameLen = item.Name.Len() - namePos;
+ if (!needPathCut)
+ Prefix.SetFrom(item.Name, namePos - 1);
+ else
+ {
+ Glob_Name = K_PREFIX_PATH_CUT "/_pc_";
+
+ if (namePos == 0)
+ Glob_Name += "root";
+ else
+ {
+ Glob_Name += "crc32/";
+ char temp[12];
+ ConvertUInt32ToHex8Digits(CrcCalc(item.Name, namePos - 1), temp);
+ Glob_Name += temp;
+ }
+
+ if (!allowPrefix || Glob_Name.Len() + 1 + nameLen <= kNameSize_Max)
+ Glob_Name.Add_Slash();
+ else
+ {
+ Prefix = Glob_Name;
+ Glob_Name.Empty();
+ }
+ }
+ Glob_Name.AddFrom(item.Name.Ptr(namePos), nameLen);
+ }
+
+ return WriteHeaderReal(item);
+}
+
+
+HRESULT COutArchive::Write_Data(const void *data, unsigned size)
+{
+ Pos += size;
+ return WriteStream(Stream, data, size);
+}
+
+HRESULT COutArchive::Write_AfterDataResidual(UInt64 dataSize)
+{
+ const unsigned v = ((unsigned)dataSize & (kRecordSize - 1));
+ if (v == 0)
+ return S_OK;
+ const unsigned rem = kRecordSize - v;
+ Byte buf[kRecordSize];
+ memset(buf, 0, rem);
+ return Write_Data(buf, rem);
+}
+
+
+HRESULT COutArchive::Write_Data_And_Residual(const void *data, unsigned size)
+{
+ RINOK(Write_Data(data, size))
+ return Write_AfterDataResidual(size);
+}
+
+
+HRESULT COutArchive::WriteFinishHeader()
+{
+ Byte record[kRecordSize];
+ memset(record, 0, kRecordSize);
+
+ const unsigned kNumFinishRecords = 2;
+
+ /* GNU TAR by default uses --blocking-factor=20 (512 * 20 = 10 KiB)
+ we also can use cluster alignment:
+ const unsigned numBlocks = (unsigned)(Pos / kRecordSize) + kNumFinishRecords;
+ const unsigned kNumClusterBlocks = (1 << 3); // 8 blocks = 4 KiB
+ const unsigned numFinishRecords = kNumFinishRecords + ((kNumClusterBlocks - numBlocks) & (kNumClusterBlocks - 1));
+ */
+
+ for (unsigned i = 0; i < kNumFinishRecords; i++)
+ {
+ RINOK(Write_Data(record, kRecordSize))
+ }
+ return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Tar/TarOut.h b/CPP/7zip/Archive/Tar/TarOut.h
new file mode 100644
index 0000000..7b99c26
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarOut.h
@@ -0,0 +1,53 @@
+// Archive/TarOut.h
+
+#ifndef ZIP7_INC_ARCHIVE_TAR_OUT_H
+#define ZIP7_INC_ARCHIVE_TAR_OUT_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../IStream.h"
+
+#include "TarItem.h"
+
+namespace NArchive {
+namespace NTar {
+
+class COutArchive
+{
+ CMyComPtr<ISequentialOutStream> Stream;
+
+ AString Glob_Name;
+ AString Prefix;
+
+ HRESULT WriteHeaderReal(const CItem &item, bool isPax = false
+ // , bool zero_PackSize = false
+ // , bool zero_MTime = false
+ );
+
+ HRESULT Write_Data(const void *data, unsigned size);
+ HRESULT Write_Data_And_Residual(const void *data, unsigned size);
+
+public:
+ UInt64 Pos;
+ bool IsPosixMode;
+ // bool IsPrefixAllowed; // it's used only if (IsPosixMode == true)
+ CTimeOptions TimeOptions;
+
+ void Create(ISequentialOutStream *outStream)
+ {
+ Stream = outStream;
+ }
+ HRESULT WriteHeader(const CItem &item);
+ HRESULT Write_AfterDataResidual(UInt64 dataSize);
+ HRESULT WriteFinishHeader();
+
+ COutArchive():
+ Pos(0),
+ IsPosixMode(false)
+ // , IsPrefixAllowed(true)
+ {}
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Tar/TarRegister.cpp b/CPP/7zip/Archive/Tar/TarRegister.cpp
new file mode 100644
index 0000000..709c191
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarRegister.cpp
@@ -0,0 +1,31 @@
+// TarRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "TarHandler.h"
+
+namespace NArchive {
+namespace NTar {
+
+static const Byte k_Signature[] = { 'u', 's', 't', 'a', 'r' };
+
+REGISTER_ARC_IO(
+ "tar", "tar ova", NULL, 0xEE,
+ k_Signature,
+ NFileHeader::kUstarMagic_Offset,
+ NArcInfoFlags::kStartOpen
+ | NArcInfoFlags::kSymLinks
+ | NArcInfoFlags::kHardLinks
+ | NArcInfoFlags::kMTime
+ | NArcInfoFlags::kMTime_Default
+ // | NArcInfoTimeFlags::kCTime
+ // | NArcInfoTimeFlags::kATime
+ , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows)
+ | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix)
+ | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::k1ns)
+ | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kUnix)
+ , IsArc_Tar)
+
+}}
diff --git a/CPP/7zip/Archive/Tar/TarUpdate.cpp b/CPP/7zip/Archive/Tar/TarUpdate.cpp
new file mode 100644
index 0000000..0b348e9
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarUpdate.cpp
@@ -0,0 +1,555 @@
+// TarUpdate.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../Windows/TimeUtils.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "TarOut.h"
+#include "TarUpdate.h"
+
+namespace NArchive {
+namespace NTar {
+
+static void FILETIME_To_PaxTime(const FILETIME &ft, CPaxTime &pt)
+{
+ UInt32 ns;
+ pt.Sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(ft, ns);
+ pt.Ns = ns * 100;
+ pt.NumDigits = 7;
+}
+
+
+HRESULT Prop_To_PaxTime(const NWindows::NCOM::CPropVariant &prop, CPaxTime &pt)
+{
+ pt.Clear();
+ if (prop.vt == VT_EMPTY)
+ {
+ // pt.Sec = 0;
+ return S_OK;
+ }
+ if (prop.vt != VT_FILETIME)
+ return E_INVALIDARG;
+ {
+ UInt32 ns;
+ pt.Sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(prop.filetime, ns);
+ ns *= 100;
+ pt.NumDigits = 7;
+ const unsigned prec = prop.wReserved1;
+ if (prec >= k_PropVar_TimePrec_Base)
+ {
+ pt.NumDigits = (int)(prec - k_PropVar_TimePrec_Base);
+ if (prop.wReserved2 < 100)
+ ns += prop.wReserved2;
+ }
+ pt.Ns = ns;
+ return S_OK;
+ }
+}
+
+
+static HRESULT GetTime(IStreamGetProp *getProp, UInt32 pid, CPaxTime &pt)
+{
+ pt.Clear();
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(getProp->GetProperty(pid, &prop))
+ return Prop_To_PaxTime(prop, pt);
+}
+
+
+static HRESULT GetUser(IStreamGetProp *getProp,
+ UInt32 pidName, UInt32 pidId, AString &name, UInt32 &id,
+ UINT codePage, unsigned utfFlags)
+{
+ // printf("\nGetUser\n");
+ // we keep old values, if both GetProperty() return VT_EMPTY
+ // we clear old values, if any of GetProperty() returns non-VT_EMPTY;
+ bool isSet = false;
+ {
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(getProp->GetProperty(pidId, &prop))
+ if (prop.vt == VT_UI4)
+ {
+ isSet = true;
+ id = prop.ulVal;
+ name.Empty();
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ {
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(getProp->GetProperty(pidName, &prop))
+ if (prop.vt == VT_BSTR)
+ {
+ const UString s = prop.bstrVal;
+ Get_AString_From_UString(s, name, codePage, utfFlags);
+ // printf("\ngetProp->GetProperty(pidName, &prop) : %s" , name.Ptr());
+ if (!isSet)
+ id = 0;
+ }
+ else if (prop.vt == VT_UI4)
+ {
+ id = prop.ulVal;
+ name.Empty();
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+
+/*
+static HRESULT GetDevice(IStreamGetProp *getProp,
+ UInt32 &majo, UInt32 &mino, bool &majo_defined, bool &mino_defined)
+{
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(getProp->GetProperty(kpidDevice, &prop));
+ if (prop.vt == VT_EMPTY)
+ return S_OK;
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ {
+ printf("\nTarUpdate.cpp :: GetDevice()\n");
+ const UInt64 v = prop.uhVal.QuadPart;
+ majo = MY_dev_major(v);
+ mino = MY_dev_minor(v);
+ majo_defined = true;
+ mino_defined = true;
+ }
+ return S_OK;
+}
+*/
+
+static HRESULT GetDevice(IStreamGetProp *getProp,
+ UInt32 pid, UInt32 &id, bool &defined)
+{
+ defined = false;
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(getProp->GetProperty(pid, &prop))
+ if (prop.vt == VT_EMPTY)
+ return S_OK;
+ if (prop.vt == VT_UI4)
+ {
+ id = prop.ulVal;
+ defined = true;
+ return S_OK;
+ }
+ return E_INVALIDARG;
+}
+
+
+HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
+ const CObjectVector<NArchive::NTar::CItemEx> &inputItems,
+ const CObjectVector<CUpdateItem> &updateItems,
+ const CUpdateOptions &options,
+ IArchiveUpdateCallback *updateCallback)
+{
+ COutArchive outArchive;
+ outArchive.Create(outStream);
+ outArchive.Pos = 0;
+ outArchive.IsPosixMode = options.PosixMode;
+ outArchive.TimeOptions = options.TimeOptions;
+
+ Z7_DECL_CMyComPtr_QI_FROM(IOutStream, outSeekStream, outStream)
+ Z7_DECL_CMyComPtr_QI_FROM(IStreamSetRestriction, setRestriction, outStream)
+ Z7_DECL_CMyComPtr_QI_FROM(IArchiveUpdateCallbackFile, opCallback, outStream)
+
+ if (outSeekStream)
+ {
+ /*
+ // for debug
+ Byte buf[1 << 14];
+ memset (buf, 0, sizeof(buf));
+ RINOK(outStream->Write(buf, sizeof(buf), NULL));
+ */
+ // we need real outArchive.Pos, if outSeekStream->SetSize() will be used.
+ RINOK(outSeekStream->Seek(0, STREAM_SEEK_CUR, &outArchive.Pos))
+ }
+ if (setRestriction)
+ RINOK(setRestriction->SetRestriction(0, 0))
+
+ UInt64 complexity = 0;
+
+ unsigned i;
+ for (i = 0; i < updateItems.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[i];
+ if (ui.NewData)
+ complexity += ui.Size;
+ else
+ complexity += inputItems[(unsigned)ui.IndexInArc].Get_FullSize_Aligned();
+ }
+
+ RINOK(updateCallback->SetTotal(complexity))
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStreamLimited(streamSpec);
+ streamSpec->SetStream(inStream);
+
+ complexity = 0;
+
+ // const int kNumReduceDigits = -1; // for debug
+
+ for (i = 0;; i++)
+ {
+ lps->InSize = lps->OutSize = complexity;
+ RINOK(lps->SetCur())
+
+ if (i == updateItems.Size())
+ {
+ if (outSeekStream && setRestriction)
+ RINOK(setRestriction->SetRestriction(0, 0))
+ return outArchive.WriteFinishHeader();
+ }
+
+ const CUpdateItem &ui = updateItems[i];
+ CItem item;
+
+ if (ui.NewProps)
+ {
+ item.SetMagic_Posix(options.PosixMode);
+ item.Name = ui.Name;
+ item.User = ui.User;
+ item.Group = ui.Group;
+ item.UID = ui.UID;
+ item.GID = ui.GID;
+ item.DeviceMajor = ui.DeviceMajor;
+ item.DeviceMinor = ui.DeviceMinor;
+ item.DeviceMajor_Defined = ui.DeviceMajor_Defined;
+ item.DeviceMinor_Defined = ui.DeviceMinor_Defined;
+
+ if (ui.IsDir)
+ {
+ item.LinkFlag = NFileHeader::NLinkFlag::kDirectory;
+ item.PackSize = 0;
+ }
+ else
+ {
+ item.PackSize = ui.Size;
+ item.Set_LinkFlag_for_File(ui.Mode);
+ }
+
+ // 22.00
+ item.Mode = ui.Mode & ~(UInt32)MY_LIN_S_IFMT;
+ item.PaxTimes = ui.PaxTimes;
+ // item.PaxTimes.ReducePrecison(kNumReduceDigits); // for debug
+ item.MTime = ui.PaxTimes.MTime.GetSec();
+ }
+ else
+ item = inputItems[(unsigned)ui.IndexInArc];
+
+ AString symLink;
+ if (ui.NewData || ui.NewProps)
+ {
+ RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidSymLink, symLink,
+ options.CodePage, options.UtfFlags, true))
+ if (!symLink.IsEmpty())
+ {
+ item.LinkFlag = NFileHeader::NLinkFlag::kSymLink;
+ item.LinkName = symLink;
+ }
+ }
+
+ if (ui.NewData)
+ {
+ item.SparseBlocks.Clear();
+ item.PackSize = ui.Size;
+ item.Size = ui.Size;
+ if (ui.Size == (UInt64)(Int64)-1)
+ return E_INVALIDARG;
+
+ CMyComPtr<ISequentialInStream> fileInStream;
+
+ bool needWrite = true;
+
+ if (!symLink.IsEmpty())
+ {
+ item.PackSize = 0;
+ item.Size = 0;
+ }
+ else
+ {
+ const HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
+
+ if (res == S_FALSE)
+ needWrite = false;
+ else
+ {
+ RINOK(res)
+
+ if (!fileInStream)
+ {
+ item.PackSize = 0;
+ item.Size = 0;
+ }
+ else
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(IStreamGetProp, getProp, fileInStream)
+ if (getProp)
+ {
+ if (options.Write_MTime.Val) RINOK(GetTime(getProp, kpidMTime, item.PaxTimes.MTime))
+ if (options.Write_ATime.Val) RINOK(GetTime(getProp, kpidATime, item.PaxTimes.ATime))
+ if (options.Write_CTime.Val) RINOK(GetTime(getProp, kpidCTime, item.PaxTimes.CTime))
+
+ if (options.PosixMode)
+ {
+ /*
+ RINOK(GetDevice(getProp, item.DeviceMajor, item.DeviceMinor,
+ item.DeviceMajor_Defined, item.DeviceMinor_Defined));
+ */
+ bool defined = false;
+ UInt32 val = 0;
+ RINOK(GetDevice(getProp, kpidDeviceMajor, val, defined))
+ if (defined)
+ {
+ item.DeviceMajor = val;
+ item.DeviceMajor_Defined = true;
+ item.DeviceMinor = 0;
+ item.DeviceMinor_Defined = false;
+ RINOK(GetDevice(getProp, kpidDeviceMinor, item.DeviceMinor, item.DeviceMinor_Defined))
+ }
+ }
+
+ RINOK(GetUser(getProp, kpidUser, kpidUserId, item.User, item.UID, options.CodePage, options.UtfFlags))
+ RINOK(GetUser(getProp, kpidGroup, kpidGroupId, item.Group, item.GID, options.CodePage, options.UtfFlags))
+
+ {
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(getProp->GetProperty(kpidPosixAttrib, &prop))
+ if (prop.vt == VT_EMPTY)
+ item.Mode =
+ MY_LIN_S_IRWXO
+ | MY_LIN_S_IRWXG
+ | MY_LIN_S_IRWXU
+ | (ui.IsDir ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG);
+ else if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ else
+ item.Mode = prop.ulVal;
+ // 21.07 : we clear high file type bits as GNU TAR.
+ item.Set_LinkFlag_for_File(item.Mode);
+ item.Mode &= ~(UInt32)MY_LIN_S_IFMT;
+ }
+
+ {
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(getProp->GetProperty(kpidSize, &prop))
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ const UInt64 size = prop.uhVal.QuadPart;
+ item.PackSize = size;
+ item.Size = size;
+ }
+ /*
+ printf("\nNum digits = %d %d\n",
+ (int)item.PaxTimes.MTime.NumDigits,
+ (int)item.PaxTimes.MTime.Ns);
+ */
+ }
+ else
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(IStreamGetProps, getProps, fileInStream)
+ if (getProps)
+ {
+ FILETIME mTime, aTime, cTime;
+ UInt64 size2;
+ if (getProps->GetProps(&size2,
+ options.Write_CTime.Val ? &cTime : NULL,
+ options.Write_ATime.Val ? &aTime : NULL,
+ options.Write_MTime.Val ? &mTime : NULL,
+ NULL) == S_OK)
+ {
+ item.PackSize = size2;
+ item.Size = size2;
+ if (options.Write_MTime.Val) FILETIME_To_PaxTime(mTime, item.PaxTimes.MTime);
+ if (options.Write_ATime.Val) FILETIME_To_PaxTime(aTime, item.PaxTimes.ATime);
+ if (options.Write_CTime.Val) FILETIME_To_PaxTime(cTime, item.PaxTimes.CTime);
+ }
+ }
+ }
+ }
+
+ {
+ // we must request kpidHardLink after updateCallback->GetStream()
+ AString hardLink;
+ RINOK(GetPropString(updateCallback, ui.IndexInClient, kpidHardLink, hardLink,
+ options.CodePage, options.UtfFlags, true))
+ if (!hardLink.IsEmpty())
+ {
+ item.LinkFlag = NFileHeader::NLinkFlag::kHardLink;
+ item.LinkName = hardLink;
+ item.PackSize = 0;
+ item.Size = 0;
+ fileInStream.Release();
+ }
+ }
+ }
+ }
+
+ // item.PaxTimes.ReducePrecison(kNumReduceDigits); // for debug
+
+ if (ui.NewProps)
+ item.MTime = item.PaxTimes.MTime.GetSec();
+
+ if (needWrite)
+ {
+ const UInt64 headerPos = outArchive.Pos;
+ // item.PackSize = ((UInt64)1 << 33); // for debug
+
+ if (outSeekStream && setRestriction)
+ RINOK(setRestriction->SetRestriction(outArchive.Pos, (UInt64)(Int64)-1))
+
+ RINOK(outArchive.WriteHeader(item))
+ if (fileInStream)
+ {
+ for (unsigned numPasses = 0;; numPasses++)
+ {
+ /* we support 2 attempts to write header:
+ pass-0: main pass:
+ pass-1: additional pass, if size_of_file and size_of_header are changed */
+ if (numPasses >= 2)
+ {
+ // opRes = NArchive::NUpdate::NOperationResult::kError_FileChanged;
+ // break;
+ return E_FAIL;
+ }
+
+ const UInt64 dataPos = outArchive.Pos;
+ RINOK(copyCoder->Code(fileInStream, outStream, NULL, NULL, progress))
+ outArchive.Pos += copyCoderSpec->TotalSize;
+ RINOK(outArchive.Write_AfterDataResidual(copyCoderSpec->TotalSize))
+
+ // if (numPasses >= 10) // for debug
+ if (copyCoderSpec->TotalSize == item.PackSize)
+ break;
+
+ if (opCallback)
+ {
+ RINOK(opCallback->ReportOperation(
+ NEventIndexType::kOutArcIndex, (UInt32)ui.IndexInClient,
+ NUpdateNotifyOp::kInFileChanged))
+ }
+
+ if (!outSeekStream)
+ return E_FAIL;
+ const UInt64 nextPos = outArchive.Pos;
+ RINOK(outSeekStream->Seek(-(Int64)(nextPos - headerPos), STREAM_SEEK_CUR, NULL))
+ outArchive.Pos = headerPos;
+ item.PackSize = copyCoderSpec->TotalSize;
+
+ RINOK(outArchive.WriteHeader(item))
+
+ // if (numPasses >= 10) // for debug
+ if (outArchive.Pos == dataPos)
+ {
+ const UInt64 alignedSize = nextPos - dataPos;
+ if (alignedSize != 0)
+ {
+ RINOK(outSeekStream->Seek((Int64)alignedSize, STREAM_SEEK_CUR, NULL))
+ outArchive.Pos += alignedSize;
+ }
+ break;
+ }
+
+ // size of header was changed.
+ // we remove data after header and try new attempt, if required
+ Z7_DECL_CMyComPtr_QI_FROM(IInStream, fileSeekStream, fileInStream)
+ if (!fileSeekStream)
+ return E_FAIL;
+ RINOK(InStream_SeekToBegin(fileSeekStream))
+ RINOK(outSeekStream->SetSize(outArchive.Pos))
+ if (item.PackSize == 0)
+ break;
+ }
+ }
+ }
+
+ complexity += item.PackSize;
+ fileInStream.Release();
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK))
+ }
+ else
+ {
+ // (ui.NewData == false)
+
+ if (opCallback)
+ {
+ RINOK(opCallback->ReportOperation(
+ NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc,
+ NUpdateNotifyOp::kReplicate))
+ }
+
+ const CItemEx &existItem = inputItems[(unsigned)ui.IndexInArc];
+ UInt64 size, pos;
+
+ if (ui.NewProps)
+ {
+ // memcpy(item.Magic, NFileHeader::NMagic::kEmpty, 8);
+
+ if (!symLink.IsEmpty())
+ {
+ item.PackSize = 0;
+ item.Size = 0;
+ }
+ else
+ {
+ if (ui.IsDir == existItem.IsDir())
+ item.LinkFlag = existItem.LinkFlag;
+
+ item.SparseBlocks = existItem.SparseBlocks;
+ item.Size = existItem.Size;
+ item.PackSize = existItem.PackSize;
+ }
+
+ item.DeviceMajor_Defined = existItem.DeviceMajor_Defined;
+ item.DeviceMinor_Defined = existItem.DeviceMinor_Defined;
+ item.DeviceMajor = existItem.DeviceMajor;
+ item.DeviceMinor = existItem.DeviceMinor;
+ item.UID = existItem.UID;
+ item.GID = existItem.GID;
+
+ RINOK(outArchive.WriteHeader(item))
+ size = existItem.Get_PackSize_Aligned();
+ pos = existItem.Get_DataPos();
+ }
+ else
+ {
+ size = existItem.Get_FullSize_Aligned();
+ pos = existItem.HeaderPos;
+ }
+
+ if (size != 0)
+ {
+ RINOK(InStream_SeekSet(inStream, pos))
+ streamSpec->Init(size);
+ if (outSeekStream && setRestriction)
+ RINOK(setRestriction->SetRestriction(0, 0))
+ // 22.00 : we copy Residual data from old archive to new archive instead of zeroing
+ RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress))
+ if (copyCoderSpec->TotalSize != size)
+ return E_FAIL;
+ outArchive.Pos += size;
+ // RINOK(outArchive.Write_AfterDataResidual(existItem.PackSize));
+ complexity += size;
+ }
+ }
+ }
+}
+
+}}
diff --git a/CPP/7zip/Archive/Tar/TarUpdate.h b/CPP/7zip/Archive/Tar/TarUpdate.h
new file mode 100644
index 0000000..f6c2e77
--- /dev/null
+++ b/CPP/7zip/Archive/Tar/TarUpdate.h
@@ -0,0 +1,74 @@
+// TarUpdate.h
+
+#ifndef ZIP7_INC_TAR_UPDATE_H
+#define ZIP7_INC_TAR_UPDATE_H
+
+#include "../IArchive.h"
+
+#include "TarItem.h"
+
+namespace NArchive {
+namespace NTar {
+
+struct CUpdateItem
+{
+ int IndexInArc;
+ unsigned IndexInClient;
+ UInt64 Size;
+ // Int64 MTime;
+ UInt32 Mode;
+ bool NewData;
+ bool NewProps;
+ bool IsDir;
+ bool DeviceMajor_Defined;
+ bool DeviceMinor_Defined;
+ UInt32 UID;
+ UInt32 GID;
+ UInt32 DeviceMajor;
+ UInt32 DeviceMinor;
+ AString Name;
+ AString User;
+ AString Group;
+
+ CPaxTimes PaxTimes;
+
+ CUpdateItem():
+ Size(0),
+ IsDir(false),
+ DeviceMajor_Defined(false),
+ DeviceMinor_Defined(false),
+ UID(0),
+ GID(0)
+ {}
+};
+
+
+struct CUpdateOptions
+{
+ UINT CodePage;
+ unsigned UtfFlags;
+ bool PosixMode;
+ CBoolPair Write_MTime;
+ CBoolPair Write_ATime;
+ CBoolPair Write_CTime;
+ CTimeOptions TimeOptions;
+};
+
+
+HRESULT UpdateArchive(IInStream *inStream, ISequentialOutStream *outStream,
+ const CObjectVector<CItemEx> &inputItems,
+ const CObjectVector<CUpdateItem> &updateItems,
+ const CUpdateOptions &options,
+ IArchiveUpdateCallback *updateCallback);
+
+HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId, AString &res,
+ UINT codePage, unsigned utfFlags, bool convertSlash);
+
+HRESULT Prop_To_PaxTime(const NWindows::NCOM::CPropVariant &prop, CPaxTime &pt);
+
+void Get_AString_From_UString(const UString &s, AString &res,
+ UINT codePage, unsigned utfFlags);
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Udf/StdAfx.h b/CPP/7zip/Archive/Udf/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Archive/Udf/StdAfx.h
@@ -0,0 +1,11 @@
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Archive/Udf/UdfHandler.cpp b/CPP/7zip/Archive/Udf/UdfHandler.cpp
new file mode 100644
index 0000000..ae6113f
--- /dev/null
+++ b/CPP/7zip/Archive/Udf/UdfHandler.cpp
@@ -0,0 +1,428 @@
+// UdfHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/ComTry.h"
+
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/TimeUtils.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/RegisterArc.h"
+#include "../../Common/StreamObjects.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "UdfHandler.h"
+
+namespace NArchive {
+namespace NUdf {
+
+static void UdfTimeToFileTime(const CTime &t, NWindows::NCOM::CPropVariant &prop)
+{
+ UInt64 numSecs;
+ const Byte *d = t.Data;
+ if (!NWindows::NTime::GetSecondsSince1601(t.GetYear(), d[4], d[5], d[6], d[7], d[8], numSecs))
+ return;
+ if (t.IsLocal())
+ numSecs = (UInt64)((Int64)numSecs - (Int64)((Int32)t.GetMinutesOffset() * 60));
+ const UInt32 m0 = d[9];
+ const UInt32 m1 = d[10];
+ const UInt32 m2 = d[11];
+ unsigned numDigits = 0;
+ UInt64 v = numSecs * 10000000;
+ if (m0 < 100 && m1 < 100 && m2 < 100)
+ {
+ v += m0 * 100000 + m1 * 1000 + m2 * 10;
+ numDigits = 6;
+ }
+ prop.SetAsTimeFrom_Ft64_Prec(v, k_PropVar_TimePrec_Base + numDigits);
+}
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidATime,
+ kpidCTime,
+ kpidChangeTime,
+ // kpidUserId,
+ // kpidGroupId,
+ // kpidPosixAttrib,
+ kpidLinks
+};
+
+static const Byte kArcProps[] =
+{
+ kpidUnpackVer,
+ kpidClusterSize,
+ kpidSectorSize,
+ kpidCTime,
+ kpidMTime,
+ kpidComment
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySize: prop = _archive.PhySize; break;
+
+ case kpidUnpackVer:
+ {
+ if (_archive.LogVols.Size() == 1)
+ {
+ UString s;
+ const CLogVol &vol = _archive.LogVols[0];
+ vol.DomainId.AddUdfVersionTo(s);
+ if (!s.IsEmpty())
+ prop = s;
+ }
+ break;
+ }
+ case kpidComment:
+ {
+ UString comment = _archive.GetComment();
+ if (!comment.IsEmpty())
+ prop = comment;
+ break;
+ }
+
+ case kpidClusterSize:
+ if (_archive.LogVols.Size() > 0)
+ {
+ UInt32 blockSize = _archive.LogVols[0].BlockSize;
+ unsigned i;
+ for (i = 1; i < _archive.LogVols.Size(); i++)
+ if (_archive.LogVols[i].BlockSize != blockSize)
+ break;
+ if (i == _archive.LogVols.Size())
+ prop = blockSize;
+ }
+ break;
+
+ case kpidSectorSize: prop = ((UInt32)1 << _archive.SecLogSize); break;
+
+ case kpidCTime:
+ if (_archive.LogVols.Size() == 1)
+ {
+ const CLogVol &vol = _archive.LogVols[0];
+ if (vol.FileSets.Size() >= 1)
+ UdfTimeToFileTime(vol.FileSets[0].RecordingTime, prop);
+ }
+ break;
+ case kpidMTime:
+ if (_archive.PrimeVols.Size() == 1)
+ {
+ const CPrimeVol &pv = _archive.PrimeVols[0];
+ UdfTimeToFileTime(pv.RecordingTime, prop);
+ }
+ break;
+
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_archive.IsArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (_archive.Unsupported) v |= kpv_ErrorFlags_UnsupportedFeature;
+ if (_archive.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
+ if (_archive.NoEndAnchor) v |= kpv_ErrorFlags_HeadersError;
+ prop = v;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+class CProgressImp Z7_final: public CProgressVirt
+{
+ CMyComPtr<IArchiveOpenCallback> _callback;
+ UInt64 _numFiles;
+ UInt64 _numBytes;
+public:
+ HRESULT SetTotal(UInt64 numBytes) Z7_override;
+ HRESULT SetCompleted(UInt64 numFiles, UInt64 numBytes) Z7_override;
+ HRESULT SetCompleted() Z7_override;
+ CProgressImp(IArchiveOpenCallback *callback): _callback(callback), _numFiles(0), _numBytes(0) {}
+};
+
+HRESULT CProgressImp::SetTotal(UInt64 numBytes)
+{
+ if (_callback)
+ return _callback->SetTotal(NULL, &numBytes);
+ return S_OK;
+}
+
+HRESULT CProgressImp::SetCompleted(UInt64 numFiles, UInt64 numBytes)
+{
+ _numFiles = numFiles;
+ _numBytes = numBytes;
+ return SetCompleted();
+}
+
+HRESULT CProgressImp::SetCompleted()
+{
+ if (_callback)
+ return _callback->SetCompleted(&_numFiles, &_numBytes);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ CProgressImp progressImp(callback);
+ RINOK(_archive.Open(stream, &progressImp))
+ bool showVolName = (_archive.LogVols.Size() > 1);
+ FOR_VECTOR (volIndex, _archive.LogVols)
+ {
+ const CLogVol &vol = _archive.LogVols[volIndex];
+ bool showFileSetName = (vol.FileSets.Size() > 1);
+ // showFileSetName = true; // for debug
+ FOR_VECTOR (fsIndex, vol.FileSets)
+ {
+ const CFileSet &fs = vol.FileSets[fsIndex];
+ for (unsigned i = ((showVolName || showFileSetName) ? 0 : 1); i < fs.Refs.Size(); i++)
+ {
+ CRef2 ref2;
+ ref2.Vol = volIndex;
+ ref2.Fs = fsIndex;
+ ref2.Ref = i;
+ _refs2.Add(ref2);
+ }
+ }
+ }
+ _inStream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _inStream.Release();
+ _archive.Clear();
+ _refs2.Clear();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _refs2.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ {
+ const CRef2 &ref2 = _refs2[index];
+ const CLogVol &vol = _archive.LogVols[ref2.Vol];
+ const CRef &ref = vol.FileSets[ref2.Fs].Refs[ref2.Ref];
+ const CFile &file = _archive.Files[ref.FileIndex];
+ const CItem &item = _archive.Items[file.ItemIndex];
+ switch (propID)
+ {
+ case kpidPath: prop = _archive.GetItemPath(ref2.Vol, ref2.Fs, ref2.Ref,
+ _archive.LogVols.Size() > 1, vol.FileSets.Size() > 1); break;
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize: if (!item.IsDir()) prop = (UInt64)item.Size; break;
+ case kpidPackSize: if (!item.IsDir()) prop = (UInt64)item.NumLogBlockRecorded * vol.BlockSize; break;
+ case kpidMTime: UdfTimeToFileTime(item.MTime, prop); break;
+ case kpidATime: UdfTimeToFileTime(item.ATime, prop); break;
+ case kpidCTime:
+ if (item.IsExtended)
+ UdfTimeToFileTime(item.CreateTime, prop);
+ break;
+ case kpidChangeTime: UdfTimeToFileTime(item.AttribTime, prop); break;
+ // case kpidUserId: prop = item.Uid; break;
+ // case kpidGroupId: prop = item.Gid; break;
+ // case kpidPosixAttrib: prop = (UInt32)item.Permissions; break;
+ case kpidLinks: prop = (UInt32)item.FileLinkCount; break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ *stream = NULL;
+
+ const CRef2 &ref2 = _refs2[index];
+ const CLogVol &vol = _archive.LogVols[ref2.Vol];
+ const CRef &ref = vol.FileSets[ref2.Fs].Refs[ref2.Ref];
+ const CFile &file = _archive.Files[ref.FileIndex];
+ const CItem &item = _archive.Items[file.ItemIndex];
+ UInt64 size = item.Size;
+
+ if (!item.IsRecAndAlloc() || !item.CheckChunkSizes() || ! _archive.CheckItemExtents(ref2.Vol, item))
+ return E_NOTIMPL;
+
+ if (item.IsInline)
+ {
+ Create_BufInStream_WithNewBuffer(item.InlineData, stream);
+ return S_OK;
+ }
+
+ CExtentsStream *extentStreamSpec = new CExtentsStream();
+ CMyComPtr<ISequentialInStream> extentStream = extentStreamSpec;
+
+ extentStreamSpec->Stream = _inStream;
+
+ UInt64 virtOffset = 0;
+ FOR_VECTOR (extentIndex, item.Extents)
+ {
+ const CMyExtent &extent = item.Extents[extentIndex];
+ UInt32 len = extent.GetLen();
+ if (len == 0)
+ continue;
+ if (size < len)
+ return S_FALSE;
+
+ const unsigned partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex;
+ UInt32 logBlockNumber = extent.Pos;
+ const CPartition &partition = _archive.Partitions[partitionIndex];
+ UInt64 offset = ((UInt64)partition.Pos << _archive.SecLogSize) +
+ (UInt64)logBlockNumber * vol.BlockSize;
+
+ CSeekExtent se;
+ se.Phy = offset;
+ se.Virt = virtOffset;
+ virtOffset += len;
+ extentStreamSpec->Extents.Add(se);
+
+ size -= len;
+ }
+ if (size != 0)
+ return S_FALSE;
+ CSeekExtent se;
+ se.Phy = 0;
+ se.Virt = virtOffset;
+ extentStreamSpec->Extents.Add(se);
+ extentStreamSpec->Init();
+ *stream = extentStream.Detach();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _refs2.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 index = (allFilesMode ? i : indices[i]);
+ const CRef2 &ref2 = _refs2[index];
+ const CRef &ref = _archive.LogVols[ref2.Vol].FileSets[ref2.Fs].Refs[ref2.Ref];
+ const CFile &file = _archive.Files[ref.FileIndex];
+ const CItem &item = _archive.Items[file.ItemIndex];
+ if (!item.IsDir())
+ totalSize += item.Size;
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur())
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+ const CRef2 &ref2 = _refs2[index];
+ const CRef &ref = _archive.LogVols[ref2.Vol].FileSets[ref2.Fs].Refs[ref2.Ref];
+ const CFile &file = _archive.Files[ref.FileIndex];
+ const CItem &item = _archive.Items[file.ItemIndex];
+
+ if (item.IsDir())
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+ currentTotalSize += item.Size;
+
+ if (!testMode && !realOutStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode))
+ outStreamSpec->SetStream(realOutStream);
+ realOutStream.Release();
+ outStreamSpec->Init(item.Size);
+ Int32 opRes;
+ CMyComPtr<ISequentialInStream> udfInStream;
+ HRESULT res = GetStream(index, &udfInStream);
+ if (res == E_NOTIMPL)
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ else if (res != S_OK)
+ opRes = NExtract::NOperationResult::kDataError;
+ else
+ {
+ RINOK(copyCoder->Code(udfInStream, outStream, NULL, NULL, progress))
+ opRes = outStreamSpec->IsFinishedOK() ?
+ NExtract::NOperationResult::kOK:
+ NExtract::NOperationResult::kDataError;
+ }
+ outStreamSpec->ReleaseStream();
+ RINOK(extractCallback->SetOperationResult(opRes))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+static const UInt32 kIsoStartPos = 0x8000;
+
+// 5, { 0, 'N', 'S', 'R', '0' },
+
+static const Byte k_Signature[] =
+{
+ 8, 0, 'B', 'E', 'A', '0', '1', 1, 0,
+ 6, 1, 'C', 'D', '0', '0', '1'
+};
+
+REGISTER_ARC_I(
+ "Udf", "udf iso img", NULL, 0xE0,
+ k_Signature,
+ kIsoStartPos,
+ NArcInfoFlags::kMultiSignature |
+ NArcInfoFlags::kStartOpen,
+ IsArc_Udf)
+
+}}
diff --git a/CPP/7zip/Archive/Udf/UdfHandler.h b/CPP/7zip/Archive/Udf/UdfHandler.h
new file mode 100644
index 0000000..5426d06
--- /dev/null
+++ b/CPP/7zip/Archive/Udf/UdfHandler.h
@@ -0,0 +1,32 @@
+// UdfHandler.h
+
+#ifndef ZIP7_INC_UDF_HANDLER_H
+#define ZIP7_INC_UDF_HANDLER_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../IArchive.h"
+
+#include "UdfIn.h"
+
+namespace NArchive {
+namespace NUdf {
+
+struct CRef2
+{
+ unsigned Vol;
+ unsigned Fs;
+ unsigned Ref;
+};
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IInArchiveGetStream
+)
+ CRecordVector<CRef2> _refs2;
+ CMyComPtr<IInStream> _inStream;
+ CInArchive _archive;
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Udf/UdfIn.cpp b/CPP/7zip/Archive/Udf/UdfIn.cpp
new file mode 100644
index 0000000..13d84e0
--- /dev/null
+++ b/CPP/7zip/Archive/Udf/UdfIn.cpp
@@ -0,0 +1,1741 @@
+// Archive/UdfIn.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#endif
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Windows/PropVariantUtils.h"
+
+#include "../../Common/RegisterArc.h"
+#include "../../Common/StreamUtils.h"
+
+#include "UdfIn.h"
+
+#ifdef SHOW_DEBUG_INFO
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+#define G16(_offs_, dest) dest = Get16(p + (_offs_))
+#define G32(_offs_, dest) dest = Get32(p + (_offs_))
+#define G64(_offs_, dest) dest = Get64(p + (_offs_))
+
+namespace NArchive {
+namespace NUdf {
+
+static const unsigned kNumPartitionsMax = 64;
+static const unsigned kNumLogVolumesMax = 64;
+static const unsigned kNumRecursionLevelsMax = 1 << 10;
+static const unsigned kNumItemsMax = 1 << 27;
+static const unsigned kNumFilesMax = 1 << 28;
+static const unsigned kNumRefsMax = 1 << 28;
+static const UInt32 kNumExtentsMax = (UInt32)1 << 30;
+static const UInt64 kFileNameLengthTotalMax = (UInt64)1 << 33;
+static const UInt64 kInlineExtentsSizeMax = (UInt64)1 << 33;
+
+#define CRC16_INIT_VAL 0
+#define CRC16_UPDATE_BYTE(crc, b) ((UInt16)(g_Crc16Table[(((crc) >> 8) ^ (b)) & 0xFF] ^ ((crc) << 8)))
+
+#define kCrc16Poly 0x1021
+static UInt16 g_Crc16Table[256];
+
+static void Z7_FASTCALL Crc16GenerateTable(void)
+{
+ UInt32 i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = (i << 8);
+ for (unsigned j = 0; j < 8; j++)
+ r = ((r << 1) ^ (kCrc16Poly & ((UInt32)0 - (r >> 15)))) & 0xFFFF;
+ g_Crc16Table[i] = (UInt16)r;
+ }
+}
+
+static UInt32 Z7_FASTCALL Crc16Calc(const void *data, size_t size)
+{
+ UInt32 v = CRC16_INIT_VAL;
+ const Byte *p = (const Byte *)data;
+ const Byte *pEnd = p + size;
+ for (; p != pEnd; p++)
+ v = CRC16_UPDATE_BYTE(v, *p);
+ return v;
+}
+
+static struct CCrc16TableInit { CCrc16TableInit() { Crc16GenerateTable(); } } g_Crc16TableInit;
+
+
+// ---------- ECMA Part 1 ----------
+
+void CDString::Parse(const Byte *p, unsigned size)
+{
+ Data.CopyFrom(p, size);
+}
+
+static UString ParseDString(const Byte *data, unsigned size)
+{
+ UString res;
+ if (size != 0)
+ {
+ wchar_t *p;
+ const Byte type = *data++;
+ size--;
+ if (type == 8)
+ {
+ p = res.GetBuf(size);
+ for (unsigned i = 0; i < size; i++)
+ {
+ const wchar_t c = data[i];
+ if (c == 0)
+ break;
+ *p++ = c;
+ }
+ }
+ else if (type == 16)
+ {
+ size &= ~(unsigned)1;
+ p = res.GetBuf(size / 2);
+ for (unsigned i = 0; i < size; i += 2)
+ {
+ const wchar_t c = GetBe16(data + i);
+ if (c == 0)
+ break;
+ *p++ = c;
+ }
+ }
+ else
+ return UString("[unknown]");
+ *p = 0;
+ res.ReleaseBuf_SetLen((unsigned)(p - (const wchar_t *)res));
+ }
+ return res;
+}
+
+UString CDString32::GetString() const
+{
+ const unsigned size = Data[sizeof(Data) - 1];
+ return ParseDString(Data, MyMin(size, (unsigned)(sizeof(Data) - 1)));
+}
+
+UString CDString128::GetString() const
+{
+ const unsigned size = Data[sizeof(Data) - 1];
+ return ParseDString(Data, MyMin(size, (unsigned)(sizeof(Data) - 1)));
+}
+
+UString CDString::GetString() const { return ParseDString(Data, (unsigned)Data.Size()); }
+
+void CTime::Parse(const Byte *p) { memcpy(Data, p, sizeof(Data)); }
+
+
+static void AddCommentChars(UString &dest, const char *s, size_t size)
+{
+ for (size_t i = 0; i < size; i++)
+ {
+ char c = s[i];
+ if (c == 0)
+ break;
+ if (c < 0x20)
+ c = '_';
+ dest += (wchar_t)c;
+ }
+}
+
+
+void CRegId::Parse(const Byte *p)
+{
+ Flags = p[0];
+ memcpy(Id, p + 1, sizeof(Id));
+ memcpy(Suffix, p + 24, sizeof(Suffix));
+}
+
+void CRegId::AddCommentTo(UString &s) const
+{
+ AddCommentChars(s, Id, sizeof(Id));
+}
+
+void CRegId::AddUdfVersionTo(UString &s) const
+{
+ // use it only for "Domain Identifier Suffix" and "UDF Identifier Suffix"
+ // UDF 2.1.5.3
+ // Revision in hex (3 digits)
+ const Byte minor = Suffix[0];
+ const Byte major = Suffix[1];
+ if (major != 0 || minor != 0)
+ {
+ char temp[16];
+ ConvertUInt32ToHex(major, temp);
+ s += temp;
+ s.Add_Dot();
+ ConvertUInt32ToHex8Digits(minor, temp);
+ s += &temp[8 - 2];
+ }
+}
+
+
+// ---------- ECMA Part 3: Volume Structure ----------
+
+void CExtent::Parse(const Byte *p)
+{
+ /* Len shall be less than < 2^30.
+ Unless otherwise specified, the length shall be an integral multiple of the logical sector size.
+ If (Len == 0), no extent is specified and (Pos) shall contain 0 */
+ G32 (0, Len);
+ G32 (4, Pos);
+}
+
+
+// ECMA 3/7.2
+
+struct CTag
+{
+ UInt16 Id;
+ // UInt16 Version;
+ // Byte Checksum;
+ // UInt16 SerialNumber;
+ // UInt16 Crc;
+ UInt16 CrcLen;
+ // UInt32 TagLocation; // the number of the logical sector
+
+ HRESULT Parse(const Byte *p, size_t size);
+};
+
+HRESULT CTag::Parse(const Byte *p, size_t size)
+{
+ if (size < 16)
+ return S_FALSE;
+ {
+ unsigned sum = 0;
+ for (unsigned i = 0; i < 16; i++)
+ sum = sum + p[i];
+ if ((Byte)(sum - p[4]) != p[4] || p[5] != 0)
+ return S_FALSE;
+ }
+ Id = Get16(p);
+ const UInt16 Version = Get16(p + 2);
+ if (Version != 2 && Version != 3)
+ return S_FALSE;
+ // SerialNumber = Get16(p + 6);
+ const UInt32 crc = Get16(p + 8);
+ CrcLen = Get16(p + 10);
+ // TagLocation = Get32(p + 12);
+
+ if (size >= 16 + (size_t)CrcLen)
+ if (crc == Crc16Calc(p + 16, (size_t)CrcLen))
+ return S_OK;
+ return S_FALSE;
+}
+
+// ECMA 3/7.2.1
+
+enum EDescriptorType
+{
+ DESC_TYPE_SpoaringTable = 0, // UDF
+ DESC_TYPE_PrimVol = 1,
+ DESC_TYPE_AnchorVolPtr = 2,
+ DESC_TYPE_VolPtr = 3,
+ DESC_TYPE_ImplUseVol = 4,
+ DESC_TYPE_Partition = 5,
+ DESC_TYPE_LogicalVol = 6,
+ DESC_TYPE_UnallocSpace = 7,
+ DESC_TYPE_Terminating = 8,
+ DESC_TYPE_LogicalVolIntegrity = 9,
+ DESC_TYPE_FileSet = 256,
+ DESC_TYPE_FileId = 257,
+ DESC_TYPE_AllocationExtent = 258,
+ DESC_TYPE_Indirect = 259,
+ DESC_TYPE_Terminal = 260,
+ DESC_TYPE_File = 261,
+ DESC_TYPE_ExtendedAttrHeader = 262,
+ DESC_TYPE_UnallocatedSpaceEntry = 263,
+ DESC_TYPE_SpaceBitmap = 264,
+ DESC_TYPE_PartitionIntegrity = 265,
+ DESC_TYPE_ExtendedFile = 266
+};
+
+
+void CLogBlockAddr::Parse(const Byte *p)
+{
+ G32 (0, Pos);
+ G16 (4, PartitionRef);
+}
+
+void CShortAllocDesc::Parse(const Byte *p)
+{
+ G32 (0, Len);
+ G32 (4, Pos);
+}
+
+/*
+void CADImpUse::Parse(const Byte *p)
+{
+ G16 (0, Flags);
+ G32 (2, UdfUniqueId);
+}
+*/
+
+void CLongAllocDesc::Parse(const Byte *p)
+{
+ G32 (0, Len);
+ Location.Parse(p + 4);
+ // memcpy(ImplUse, p + 10, sizeof(ImplUse));
+ // adImpUse.Parse(ImplUse);
+}
+
+
+void CPrimeVol::Parse(const Byte *p)
+{
+ // G32 (16, VolumeDescriptorSequenceNumber);
+ G32 (20, PrimaryVolumeDescriptorNumber);
+ VolumeId.Parse(p + 24);
+ G16 (56, VolumeSequenceNumber);
+ G16 (58, MaximumVolumeSequenceNumber);
+ // G16 (60, InterchangeLevel);
+ // G16 (62, MaximumInterchangeLevel);
+ // G32 (64, CharacterSetList)
+ // G32 (68, MaximumCharacterSetList)
+ VolumeSetId.Parse(p + 72);
+ // 200 64 Descriptor Character Set charspec (1/7.2.1)
+ // 264 64 Explanatory Character Set charspec (1/7.2.1)
+ // VolumeAbstract.Parse(p + 328);
+ // VolumeCopyrightNotice.Parse(p + 336);
+ ApplicationId.Parse(p + 344);
+ RecordingTime.Parse(p + 376);
+ ImplId.Parse(p + 388);
+ // 420 64 Implementation Use bytes
+ // G32 (484, PredecessorVolumeDescriptorSequenceLocation);
+ // G16 (488, Flags);
+}
+
+
+
+bool CInArchive::CheckExtent(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len) const
+{
+ const CLogVol &vol = LogVols[volIndex];
+ if (partitionRef >= vol.PartitionMaps.Size())
+ return false;
+ const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex];
+ return ((UInt64)blockPos * vol.BlockSize + len) <= ((UInt64)partition.Len << SecLogSize);
+}
+
+bool CInArchive::CheckItemExtents(unsigned volIndex, const CItem &item) const
+{
+ FOR_VECTOR (i, item.Extents)
+ {
+ const CMyExtent &e = item.Extents[i];
+ if (!CheckExtent(volIndex, e.PartitionRef, e.Pos, e.GetLen()))
+ return false;
+ }
+ return true;
+}
+
+HRESULT CInArchive::Read(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len, Byte *buf)
+{
+ if (!CheckExtent(volIndex, partitionRef, blockPos, len))
+ return S_FALSE;
+ const CLogVol &vol = LogVols[volIndex];
+ const CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex];
+ UInt64 offset = ((UInt64)partition.Pos << SecLogSize) + (UInt64)blockPos * vol.BlockSize;
+ RINOK(InStream_SeekSet(_stream, offset))
+ offset += len;
+ UpdatePhySize(offset);
+ const HRESULT res = ReadStream_FALSE(_stream, buf, len);
+ if (res == S_FALSE && offset > FileSize)
+ UnexpectedEnd = true;
+ return res;
+}
+
+HRESULT CInArchive::ReadLad(unsigned volIndex, const CLongAllocDesc &lad, Byte *buf)
+{
+ return Read(volIndex, lad.Location.PartitionRef, lad.Location.Pos, lad.GetLen(), (Byte *)buf);
+}
+
+HRESULT CInArchive::ReadFromFile(unsigned volIndex, const CItem &item, CByteBuffer &buf)
+{
+ if (item.Size >= (UInt32)1 << 30)
+ return S_FALSE;
+ if (item.IsInline)
+ {
+ buf = item.InlineData;
+ return S_OK;
+ }
+ buf.Alloc((size_t)item.Size);
+ size_t pos = 0;
+ FOR_VECTOR (i, item.Extents)
+ {
+ const CMyExtent &e = item.Extents[i];
+ const UInt32 len = e.GetLen();
+ RINOK(Read(volIndex, e.PartitionRef, e.Pos, len, (Byte *)buf + pos))
+ pos += len;
+ }
+ return S_OK;
+}
+
+
+void CIcbTag::Parse(const Byte *p)
+{
+ // G32 (0, PriorDirectNum);
+ // G16 (4, StrategyType);
+ // G16 (6, StrategyParam);
+ // G16 (8, MaxNumOfEntries);
+ FileType = p[11];
+ // ParentIcb.Parse(p + 12);
+ G16 (18, Flags);
+}
+
+
+// ECMA 4/14.9 File Entry
+// UDF FileEntry 2.3.6
+
+// ECMA 4/14.17 Extended File Entry
+
+void CItem::Parse(const Byte *p)
+{
+ // (-1) can be stored in Uid/Gid.
+ // G32 (36, Uid);
+ // G32 (40, Gid);
+ // G32 (44, Permissions);
+ G16 (48, FileLinkCount);
+ // RecordFormat = p[50];
+ // RecordDisplayAttr = p[51];
+ // G32 (52, RecordLen);
+ G64 (56, Size);
+ if (IsExtended)
+ {
+ // The sum of all Information Length fields for all streams of a file (including the default stream). If this file has no
+ // streams, the Object Size shall be equal to the Information Length.
+ // G64 (64, ObjectSize);
+ p += 8;
+ }
+ G64 (64, NumLogBlockRecorded);
+ ATime.Parse(p + 72);
+ MTime.Parse(p + 84);
+ if (IsExtended)
+ {
+ CreateTime.Parse(p + 96);
+ p += 12;
+ }
+ AttribTime.Parse(p + 96);
+ // G32 (108, CheckPoint);
+ /*
+ if (IsExtended)
+ {
+ // Get32(p + 112); // reserved
+ p += 4;
+ }
+ // ExtendedAttrIcb.Parse(p + 112);
+ if (IsExtended)
+ {
+ StreamDirectoryIcb.Parse(p + 128);
+ p += 16;
+ }
+ */
+
+ // ImplId.Parse(p + 128);
+ // G64 (160, UniqueId);
+}
+
+
+// ECMA 4/14.4
+// UDF 2.3.4
+
+/*
+File Characteristics:
+Deleted bit:
+ ECMA: If set to ONE, shall mean this File Identifier Descriptor
+ identifies a file that has been deleted;
+ UDF: If the space for the file or directory is deallocated,
+ the implementation shall set the ICB field to zero.
+ ECMA 167 4/8.6 requires that the File Identifiers of all FIDs in a directory shall be unique.
+ The implementations shall follow these rules when a Deleted bit is set:
+ rewrire the compression ID of the File Identifier: 8 -> 254, 16 -> 255.
+*/
+
+struct CFileId
+{
+ // UInt16 FileVersion;
+ Byte FileCharacteristics;
+ // CByteBuffer ImplUse;
+ CDString Id;
+ CLongAllocDesc Icb;
+
+ bool IsItLink_Dir () const { return (FileCharacteristics & FILEID_CHARACS_Dir) != 0; }
+ bool IsItLink_Deleted() const { return (FileCharacteristics & FILEID_CHARACS_Deleted) != 0; }
+ bool IsItLink_Parent () const { return (FileCharacteristics & FILEID_CHARACS_Parent) != 0; }
+
+ size_t Parse(const Byte *p, size_t size);
+};
+
+size_t CFileId::Parse(const Byte *p, size_t size)
+{
+ size_t processed = 0;
+ if (size < 38)
+ return 0;
+ CTag tag;
+ if (tag.Parse(p, size) != S_OK)
+ return 0;
+ if (tag.Id != DESC_TYPE_FileId)
+ return 0;
+ // FileVersion = Get16(p + 16);
+ // UDF: There shall be only one version of a file as specified below with the value being set to 1.
+
+ FileCharacteristics = p[18];
+ const unsigned idLen = p[19];
+ Icb.Parse(p + 20);
+ const unsigned impLen = Get16(p + 36);
+ if (size < 38 + idLen + impLen)
+ return 0;
+ processed = 38;
+ // ImplUse.CopyFrom(p + processed, impLen);
+ processed += impLen;
+ Id.Parse(p + processed, idLen);
+ processed += idLen;
+ for (;(processed & 3) != 0; processed++)
+ if (p[processed] != 0)
+ return 0;
+ if ((size_t)tag.CrcLen + 16 != processed) return 0;
+ return (processed <= size) ? processed : 0;
+}
+
+
+
+HRESULT CInArchive::ReadFileItem(unsigned volIndex, unsigned fsIndex, const CLongAllocDesc &lad, bool isDir, int numRecurseAllowed)
+{
+ if (Files.Size() % 100 == 0)
+ RINOK(_progress->SetCompleted(Files.Size(), _processedProgressBytes))
+ if (numRecurseAllowed-- == 0)
+ return S_FALSE;
+ CFile &file = Files.Back();
+ const CLogVol &vol = LogVols[volIndex];
+ const unsigned partitionRef = lad.Location.PartitionRef;
+ if (partitionRef >= vol.PartitionMaps.Size())
+ return S_FALSE;
+ CPartition &partition = Partitions[vol.PartitionMaps[partitionRef].PartitionIndex];
+
+ const UInt32 key = lad.Location.Pos;
+ UInt32 value;
+ const UInt32 kRecursedErrorValue = (UInt32)(Int32)-1;
+ if (partition.Map.Find(key, value))
+ {
+ if (value == kRecursedErrorValue)
+ return S_FALSE;
+ file.ItemIndex = (int)(Int32)value;
+ }
+ else
+ {
+ value = Items.Size();
+ file.ItemIndex = (int)(Int32)value;
+ if (partition.Map.Set(key, kRecursedErrorValue))
+ return S_FALSE;
+ RINOK(ReadItem(volIndex, (int)fsIndex, lad, isDir, numRecurseAllowed))
+ if (!partition.Map.Set(key, value))
+ return S_FALSE;
+ }
+ return S_OK;
+}
+
+
+// (fsIndex = -1) means that it's metadata file
+
+HRESULT CInArchive::ReadItem(unsigned volIndex, int fsIndex, const CLongAllocDesc &lad, bool isDir, int numRecurseAllowed)
+{
+ if (Items.Size() >= kNumItemsMax)
+ return S_FALSE;
+ CItem &item = Items.AddNew();
+
+ const CLogVol &vol = LogVols[volIndex];
+
+ const size_t size = lad.GetLen();
+ if (size != vol.BlockSize)
+ return S_FALSE;
+
+ CByteBuffer buf(size);
+ RINOK(ReadLad(volIndex, lad, buf))
+
+ CTag tag;
+ const Byte *p = buf;
+ RINOK(tag.Parse(p, size))
+
+ item.IsExtended = (tag.Id == DESC_TYPE_ExtendedFile);
+ const size_t kExtendOffset = item.IsExtended ? 40 : 0;
+
+ if (size < kExtendOffset + 176)
+ return S_FALSE;
+ if (tag.Id != DESC_TYPE_File &&
+ tag.Id != DESC_TYPE_ExtendedFile)
+ return S_FALSE;
+
+ item.IcbTag.Parse(p + 16);
+
+ if (fsIndex < 0)
+ {
+ if (item.IcbTag.FileType != ICB_FILE_TYPE_METADATA &&
+ item.IcbTag.FileType != ICB_FILE_TYPE_METADATA_MIRROR)
+ return S_FALSE;
+ }
+ else if (
+ item.IcbTag.FileType != ICB_FILE_TYPE_DIR &&
+ item.IcbTag.FileType != ICB_FILE_TYPE_FILE)
+ return S_FALSE;
+
+ item.Parse(p);
+
+ _processedProgressBytes += (UInt64)item.NumLogBlockRecorded * vol.BlockSize + size;
+
+ const UInt32 extendedAttrLen = Get32(p + 168 + kExtendOffset);
+ const UInt32 allocDescriptorsLen = Get32(p + 172 + kExtendOffset);
+
+ if ((extendedAttrLen & 3) != 0)
+ return S_FALSE;
+ size_t pos = 176 + kExtendOffset;
+ if (extendedAttrLen > size - pos)
+ return S_FALSE;
+ /*
+ if (extendedAttrLen != 16)
+ {
+ if (extendedAttrLen < 24)
+ return S_FALSE;
+ CTag attrTag;
+ RINOK(attrTag.Parse(p + pos, size));
+ if (attrTag.Id != DESC_TYPE_ExtendedAttrHeader)
+ return S_FALSE;
+ // UInt32 implAttrLocation = Get32(p + pos + 16);
+ // UInt32 applicationlAttrLocation = Get32(p + pos + 20);
+ }
+ */
+ pos += extendedAttrLen;
+
+ const int descType = item.IcbTag.GetDescriptorType();
+ if (allocDescriptorsLen > size - pos)
+ return S_FALSE;
+ if (descType == ICB_DESC_TYPE_INLINE)
+ {
+ item.IsInline = true;
+ item.InlineData.CopyFrom(p + pos, allocDescriptorsLen);
+ }
+ else
+ {
+ item.IsInline = false;
+ if (descType != ICB_DESC_TYPE_SHORT && descType != ICB_DESC_TYPE_LONG)
+ return S_FALSE;
+ for (UInt32 i = 0; i < allocDescriptorsLen;)
+ {
+ CMyExtent e;
+ if (descType == ICB_DESC_TYPE_SHORT)
+ {
+ if (i + 8 > allocDescriptorsLen)
+ return S_FALSE;
+ CShortAllocDesc sad;
+ sad.Parse(p + pos + i);
+ e.Pos = sad.Pos;
+ e.Len = sad.Len;
+ e.PartitionRef = lad.Location.PartitionRef;
+ i += 8;
+ }
+ else
+ {
+ if (i + 16 > allocDescriptorsLen)
+ return S_FALSE;
+ CLongAllocDesc ladNew;
+ ladNew.Parse(p + pos + i);
+ e.Pos = ladNew.Location.Pos;
+ e.PartitionRef = ladNew.Location.PartitionRef;
+ e.Len = ladNew.Len;
+ i += 16;
+ }
+ item.Extents.Add(e);
+ }
+ }
+
+ if (isDir != item.IcbTag.IsDir())
+ return S_FALSE;
+
+ if (item.IcbTag.IsDir())
+ {
+ if (fsIndex < 0)
+ return S_FALSE;
+
+ if (!item.CheckChunkSizes() || !CheckItemExtents(volIndex, item))
+ return S_FALSE;
+ CByteBuffer buf2;
+ RINOK(ReadFromFile(volIndex, item, buf2))
+ item.Size = 0;
+ item.Extents.ClearAndFree();
+ item.InlineData.Free();
+
+ const Byte *p2 = buf2;
+ size_t size2 = buf2.Size();
+ while (size2 != 0)
+ {
+ CFileId fileId;
+ {
+ const size_t cur = fileId.Parse(p2, size2);
+ if (cur == 0)
+ return S_FALSE;
+ p2 += cur;
+ size2 -= cur;
+ }
+ if (fileId.IsItLink_Parent())
+ continue;
+ if (fileId.IsItLink_Deleted())
+ continue;
+ {
+ CFile file;
+ // file.FileVersion = fileId.FileVersion;
+ // file.FileCharacteristics = fileId.FileCharacteristics;
+ // file.ImplUse = fileId.ImplUse;
+ file.Id = fileId.Id;
+
+ _fileNameLengthTotal += file.Id.Data.Size();
+ if (_fileNameLengthTotal > kFileNameLengthTotalMax)
+ return S_FALSE;
+
+ item.SubFiles.Add(Files.Size());
+ if (Files.Size() >= kNumFilesMax)
+ return S_FALSE;
+ Files.Add(file);
+ RINOK(ReadFileItem(volIndex, (unsigned)fsIndex, fileId.Icb,
+ fileId.IsItLink_Dir(), numRecurseAllowed))
+ }
+ }
+ }
+ else
+ {
+ if ((UInt32)item.Extents.Size() > kNumExtentsMax - _numExtents)
+ return S_FALSE;
+ _numExtents += item.Extents.Size();
+
+ if (item.InlineData.Size() > kInlineExtentsSizeMax - _inlineExtentsSize)
+ return S_FALSE;
+ _inlineExtentsSize += item.InlineData.Size();
+ }
+
+ return S_OK;
+}
+
+
+HRESULT CInArchive::FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed)
+{
+ if ((_numRefs & 0xFFF) == 0)
+ {
+ RINOK(_progress->SetCompleted())
+ }
+ if (numRecurseAllowed-- == 0)
+ return S_FALSE;
+ if (_numRefs >= kNumRefsMax)
+ return S_FALSE;
+ _numRefs++;
+ CRef ref;
+ ref.FileIndex = fileIndex;
+ ref.Parent = parent;
+ parent = (int)fs.Refs.Size();
+ fs.Refs.Add(ref);
+ const CItem &item = Items[Files[fileIndex].ItemIndex];
+ FOR_VECTOR (i, item.SubFiles)
+ {
+ RINOK(FillRefs(fs, item.SubFiles[i], parent, numRecurseAllowed))
+ }
+ return S_OK;
+}
+
+
+API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size)
+{
+ UInt32 res = k_IsArc_Res_NO;
+ unsigned SecLogSize;
+ for (SecLogSize = 11;; SecLogSize -= 2)
+ {
+ if (SecLogSize < 9)
+ return res;
+ const UInt32 offset = (UInt32)256 << SecLogSize;
+ const UInt32 bufSize = (UInt32)1 << SecLogSize;
+ if (offset + bufSize > size)
+ res = k_IsArc_Res_NEED_MORE;
+ else
+ {
+ CTag tag;
+ if (tag.Parse(p + offset, bufSize) == S_OK)
+ if (tag.Id == DESC_TYPE_AnchorVolPtr)
+ {
+ if (Get32(p + offset + 12) == 256 && // TagLocation
+ tag.CrcLen >= 16)
+ return k_IsArc_Res_YES;
+ }
+ }
+ }
+}
+
+
+HRESULT CInArchive::Open2()
+{
+ Clear();
+ UInt64 fileSize;
+ RINOK(InStream_GetSize_SeekToEnd(_stream, fileSize))
+ FileSize = fileSize;
+
+ // Some UDFs contain additional pad zeros (2 KB).
+ // Seek to STREAM_SEEK_END for direct DVD reading can return 8 KB more, so we check last 16 KB.
+ // And when we read last block, result read size can be smaller than required size.
+
+ /*
+ const size_t kBufSize = 1 << 14;
+ Byte buf[kBufSize];
+ size_t readSize = (fileSize < kBufSize) ? (size_t)fileSize : kBufSize;
+ RINOK(InStream_SeekSet(_stream, fileSize - readSize))
+ RINOK(ReadStream(_stream, buf, &readSize));
+ size_t i = readSize;
+ for (;;)
+ {
+ const size_t kSecSizeMin = 1 << 8;
+ if (i < kSecSizeMin)
+ return S_FALSE;
+ i -= kSecSizeMin;
+ SecLogSize = (readSize - i < ((size_t)1 << 11)) ? 8 : 11;
+ CTag tag;
+ if (tag.Parse(buf + i, (1 << SecLogSize)) == S_OK)
+ if (tag.Id == DESC_TYPE_AnchorVolPtr)
+ break;
+ }
+ PhySize = fileSize;
+ CExtent extentVDS;
+ extentVDS.Parse(buf + i + 16);
+ */
+
+ /*
+ An Anchor Volume Descriptor Pointer structure shall be recorded in at
+ least 2 of the following 3 locations on the media:
+ Logical Sector 256.
+ Logical Sector (N - 256).
+ N
+ */
+
+ const size_t kBufSize = 1 << 11;
+ Byte buf[kBufSize];
+
+ for (SecLogSize = 11;; SecLogSize -= 2)
+ {
+ // Windows 10 uses unusual (SecLogSize = 9)
+ if (SecLogSize < 9)
+ return S_FALSE;
+ const UInt32 offset = (UInt32)256 << SecLogSize;
+ if (offset >= fileSize)
+ continue;
+ RINOK(InStream_SeekSet(_stream, offset))
+ const size_t bufSize = (size_t)1 << SecLogSize;
+ size_t readSize = bufSize;
+ RINOK(ReadStream(_stream, buf, &readSize))
+ if (readSize == bufSize)
+ {
+ CTag tag;
+ if (tag.Parse(buf, readSize) == S_OK)
+ if (tag.Id == DESC_TYPE_AnchorVolPtr)
+ {
+ if (Get32(buf + 12) == 256 &&
+ tag.CrcLen >= 16) // TagLocation
+ break;
+ }
+ }
+ }
+
+ PhySize = (UInt32)(256 + 1) << SecLogSize;
+ IsArc = true;
+
+ // UDF 2.2.3 AnchorVolumeDescriptorPointer
+
+ CExtent extentVDS;
+ extentVDS.Parse(buf + 16);
+ {
+ CExtent extentVDS2;
+ extentVDS2.Parse(buf + 24);
+ UpdatePhySize(extentVDS);
+ UpdatePhySize(extentVDS2);
+ }
+
+ for (UInt32 location = 0; ; location++)
+ {
+ if (location >= (extentVDS.Len >> SecLogSize))
+ return S_FALSE;
+
+ const size_t bufSize = (size_t)1 << SecLogSize;
+ {
+ const UInt64 offs = ((UInt64)extentVDS.Pos + location) << SecLogSize;
+ RINOK(InStream_SeekSet(_stream, offs))
+ const HRESULT res = ReadStream_FALSE(_stream, buf, bufSize);
+ if (res == S_FALSE && offs + bufSize > FileSize)
+ UnexpectedEnd = true;
+ RINOK(res)
+ }
+
+ CTag tag;
+ RINOK(tag.Parse(buf, bufSize))
+
+ if (tag.Id == DESC_TYPE_Terminating)
+ break;
+
+ if (tag.Id == DESC_TYPE_PrimVol)
+ {
+ CPrimeVol &pm = PrimeVols.AddNew();
+ pm.Parse(buf);
+ continue;
+ }
+
+ if (tag.Id == DESC_TYPE_Partition)
+ {
+ // Partition Descriptor
+ // ECMA 3/10.5
+ // UDF 2.2.14
+ if (Partitions.Size() >= kNumPartitionsMax)
+ return S_FALSE;
+ CPartition partition;
+ // const UInt32 volDescSeqNumer = Get32(buf + 16);
+ partition.Flags = Get16(buf + 20);
+ partition.Number = Get16(buf + 22);
+ partition.ContentsId.Parse(buf + 24);
+
+ // memcpy(partition.ContentsUse, buf + 56, sizeof(partition.ContentsUse));
+ // ContentsUse contains Partition Header Description.
+ // ECMA 4/14.3
+ // UDF PartitionHeaderDescriptor 2.3.3
+
+ partition.AccessType = Get32(buf + 184);
+ partition.Pos = Get32(buf + 188);
+ partition.Len = Get32(buf + 192);
+ partition.ImplId.Parse(buf + 196);
+ // memcpy(partition.ImplUse, buf + 228, sizeof(partition.ImplUse));
+
+ PRF(printf("\nPartition number = %2d pos = %d len = %d", partition.Number, partition.Pos, partition.Len));
+ Partitions.Add(partition);
+ continue;
+ }
+
+ if (tag.Id == DESC_TYPE_LogicalVol)
+ {
+ /* Logical Volume Descriptor
+ ECMA 3/10.6
+ UDF 2.60 2.2.4 */
+
+ if (LogVols.Size() >= kNumLogVolumesMax)
+ return S_FALSE;
+ CLogVol &vol = LogVols.AddNew();
+
+ vol.Id.Parse(buf + 84);
+ vol.BlockSize = Get32(buf + 212);
+ if (vol.BlockSize != ((UInt32)1 << SecLogSize))
+ {
+ // UDF 2.2.4.2 LogicalBlockSize
+ // UDF probably doesn't allow different sizes
+ return S_FALSE;
+ }
+ /*
+ if (vol.BlockSize < 512 || vol.BlockSize > ((UInt32)1 << 30))
+ return S_FALSE;
+ */
+
+ vol.DomainId.Parse(buf + 216);
+
+ // ECMA 4/3.1
+ // UDF 2.2.4.4 LogicalVolumeContentsUse
+ /* the extent in which the first File Set Descriptor Sequence
+ of the logical volume is recorded */
+ vol.FileSetLocation.Parse(buf + 248);
+ // memcpy(vol.ContentsUse, buf + 248, sizeof(vol.ContentsUse));
+
+ vol.ImplId.Parse(buf + 272);
+ // memcpy(vol.ImplUse, buf + 304, sizeof(vol.ImplUse));
+ // vol.IntegritySequenceExtent.Parse(buf + 432);
+
+ const UInt32 mapTableLen = Get32(buf + 264);
+ const UInt32 numPartitionMaps = Get32(buf + 268);
+ if (numPartitionMaps > kNumPartitionsMax)
+ return S_FALSE;
+
+ PRF(printf("\nLogicalVol numPartitionMaps = %2d", numPartitionMaps));
+
+ size_t pos = 440;
+ if (mapTableLen > bufSize - pos)
+ return S_FALSE;
+ const size_t posLimit = pos + mapTableLen;
+
+ for (UInt32 i = 0; i < numPartitionMaps; i++)
+ {
+ // ECMA 3/10.7 Partition maps
+ if (pos + 2 > posLimit)
+ return S_FALSE;
+ CPartitionMap pm;
+ pm.Type = buf[pos + 0];
+ // pm.Length = buf[pos + 1];
+ const Byte len = buf[pos + 1];
+ if (pos + len > posLimit)
+ return S_FALSE;
+
+ // memcpy(pm.Data, buf + pos + 2, pm.Length - 2);
+ if (pm.Type == 1)
+ {
+ // ECMA 3/10.7.2
+ if (len != 6)
+ return S_FALSE;
+ pm.VolumeSequenceNumber = Get16(buf + pos + 2);
+ pm.PartitionNumber = Get16(buf + pos + 4);
+ PRF(printf("\nPartitionMap type 1 PartitionNumber = %2d", pm.PartitionNumber));
+ }
+ else if (pm.Type == 2)
+ {
+ if (len != 64)
+ return S_FALSE;
+ /* ECMA 10.7.3 / Type 2 Partition Map
+ 62 bytes: Partition Identifier. */
+
+ /* UDF
+ 2.2.8 "*UDF Virtual Partition"
+ 2.2.9 "*UDF Sparable Partition"
+ 2.2.10 "*UDF Metadata Partition"
+ */
+
+ if (Get16(buf + pos + 2) != 0) // reserved
+ return S_FALSE;
+
+ pm.PartitionTypeId.Parse(buf + pos + 4);
+ pm.VolumeSequenceNumber = Get16(buf + pos + 36);
+ pm.PartitionNumber = Get16(buf + pos + 38);
+
+ if (memcmp(pm.PartitionTypeId.Id, "*UDF Metadata Partition", 23) != 0)
+ return S_FALSE;
+
+ // UDF 2.2.10 Metadata Partition Map
+ pm.MetadataFileLocation = Get32(buf + pos + 40);
+ // pm.MetadataMirrorFileLocation = Get32(buf + pos + 44);
+ // pm.MetadataBitmapFileLocation = Get32(buf + pos + 48);
+ // pm.AllocationUnitSize = Get32(buf + pos + 52);
+ // pm.AlignmentUnitSize = Get16(buf + pos + 56);
+ // pm.Flags = buf[pos + 58];
+
+ PRF(printf("\nPartitionMap type 2 PartitionNumber = %2d", pm.PartitionNumber));
+ // Unsupported = true;
+ // return S_FALSE;
+ }
+ else
+ return S_FALSE;
+ pos += len;
+ vol.PartitionMaps.Add(pm);
+ }
+ continue;
+ }
+
+ /*
+ if (tag.Id == DESC_TYPE_UnallocSpace)
+ {
+ // UInt32 volDescSeqNumer = Get32(buf + 16);
+ const UInt32 numAlocDescs = Get32(buf + 20);
+ // we need examples for (numAlocDescs != 0) case
+ if (numAlocDescs > (bufSize - 24) / 8)
+ return S_FALSE;
+ for (UInt32 i = 0; i < numAlocDescs; i++)
+ {
+ CExtent e;
+ e.Parse(buf + 24 + i * 8);
+ }
+ continue;
+ }
+ else
+ continue;
+ */
+ }
+
+ UInt64 totalSize = 0;
+
+ unsigned volIndex;
+ for (volIndex = 0; volIndex < LogVols.Size(); volIndex++)
+ {
+ CLogVol &vol = LogVols[volIndex];
+ FOR_VECTOR (pmIndex, vol.PartitionMaps)
+ {
+ CPartitionMap &pm = vol.PartitionMaps[pmIndex];
+ for (unsigned i = 0;; i++)
+ {
+ if (i == Partitions.Size())
+ return S_FALSE;
+ CPartition &part = Partitions[i];
+ if (part.Number == pm.PartitionNumber)
+ {
+ pm.PartitionIndex = i;
+ if (pm.Type == 2)
+ break;
+
+ /*
+ if (part.VolIndex >= 0)
+ {
+ // it's for 2.60. Fix it
+ if (part.VolIndex != (int)volIndex)
+ return S_FALSE;
+ // return S_FALSE;
+ }
+ part.VolIndex = volIndex;
+ */
+
+ totalSize += (UInt64)part.Len << SecLogSize;
+ break;
+ }
+ }
+ }
+ }
+
+ for (volIndex = 0; volIndex < LogVols.Size(); volIndex++)
+ {
+ CLogVol &vol = LogVols[volIndex];
+ FOR_VECTOR (pmIndex, vol.PartitionMaps)
+ {
+ CPartitionMap &pm = vol.PartitionMaps[pmIndex];
+ if (pm.Type != 2)
+ continue;
+
+ {
+ CLongAllocDesc lad;
+ lad.Len = vol.BlockSize;
+ lad.Location.Pos = pm.MetadataFileLocation;
+ // lad.Location.Pos = pm.MetadataMirrorFileLocation;
+
+ lad.Location.PartitionRef = (UInt16)pmIndex;
+
+ /* we need correct PartitionMaps[lad.Location.PartitionRef].PartitionIndex.
+ so we can use pmIndex or find (Type==1) PartitionMap */
+ FOR_VECTOR (pmIndex2, vol.PartitionMaps)
+ {
+ const CPartitionMap &pm2 = vol.PartitionMaps[pmIndex2];
+ if (pm2.PartitionNumber == pm.PartitionNumber && pm2.Type == 1)
+ {
+ lad.Location.PartitionRef = (UInt16)pmIndex2;
+ break;
+ }
+ }
+
+ RINOK(ReadItem(volIndex,
+ -1, // (fsIndex = -1) means that it's metadata
+ lad,
+ false, // isDir
+ 1)) // numRecurseAllowed
+ }
+ {
+ const CItem &item = Items.Back();
+ if (!CheckItemExtents(volIndex, item))
+ return S_FALSE;
+ if (item.Extents.Size() != 1)
+ {
+ if (item.Extents.Size() < 1)
+ return S_FALSE;
+ /* Windows 10 writes empty record item.Extents[1].
+ we ignore such extent here */
+ for (unsigned k = 1; k < item.Extents.Size(); k++)
+ {
+ const CMyExtent &e = item.Extents[k];
+ if (e.GetLen() != 0)
+ return S_FALSE;
+ }
+ }
+
+ const CMyExtent &e = item.Extents[0];
+ const CPartition &part = Partitions[pm.PartitionIndex];
+ CPartition mp = part;
+ mp.IsMetadata = true;
+ // mp.Number = part.Number;
+ mp.Pos = part.Pos + e.Pos;
+ mp.Len = e.Len >> SecLogSize;
+ pm.PartitionIndex = Partitions.Add(mp);
+ }
+ // Items.DeleteBack(); // we can delete that metadata item
+
+ /*
+ // short version of code to read metadata file.
+ RINOK(CInArchive::Read(volIndex, pmIndex, pm.MetadataFileLocation, 224, buf));
+ CTag tag;
+ RINOK(tag.Parse(buf, 224));
+ if (tag.Id != DESC_TYPE_ExtendedFile)
+ return S_FALSE;
+ CShortAllocDesc sad;
+ sad.Parse(buf + 216);
+ const CPartition &part = Partitions[pm.PartitionIndex];
+ CPartition mp = part;
+ mp.IsMetadata = true;
+ // mp.Number = part.Number;
+ mp.Pos = part.Pos + sad.Pos;
+ mp.Len = sad.Len >> SecLogSize;
+ pm.PartitionIndex = Partitions.Add(mp);
+ */
+ }
+ }
+
+ RINOK(_progress->SetTotal(totalSize))
+
+ PRF(printf("\n Read files"));
+
+ for (volIndex = 0; volIndex < LogVols.Size(); volIndex++)
+ {
+ CLogVol &vol = LogVols[volIndex];
+
+ PRF(printf("\nLogVol %2d", volIndex));
+
+ CLongAllocDesc nextExtent = vol.FileSetLocation;
+ // while (nextExtent.ExtentLen != 0)
+ // for (int i = 0; i < 1; i++)
+ {
+ if (nextExtent.GetLen() < 512)
+ return S_FALSE;
+ CByteBuffer buf2(nextExtent.GetLen());
+ RINOK(ReadLad(volIndex, nextExtent, buf2))
+ const Byte *p = buf2;
+ const size_t size = nextExtent.GetLen();
+
+ CTag tag;
+ RINOK(tag.Parse(p, size))
+
+ /*
+ // commented in 22.01
+ if (tag.Id == DESC_TYPE_ExtendedFile)
+ {
+ // ECMA 4 / 14.17
+ // 2.60 ??
+ return S_FALSE;
+ }
+ */
+
+ if (tag.Id != DESC_TYPE_FileSet)
+ return S_FALSE;
+
+ PRF(printf("\n FileSet", volIndex));
+ CFileSet fs;
+ fs.RecordingTime.Parse(p + 16);
+ // fs.InterchangeLevel = Get16(p + 18);
+ // fs.MaxInterchangeLevel = Get16(p + 20);
+ fs.FileSetNumber = Get32(p + 40);
+ fs.FileSetDescNumber = Get32(p + 44);
+
+ fs.LogicalVolumeId.Parse(p + 112);
+ fs.Id.Parse(p + 304);
+ fs.CopyrightId.Parse(p + 336);
+ fs.AbstractId.Parse(p + 368);
+
+ fs.RootDirICB.Parse(p + 400);
+ fs.DomainId.Parse(p + 416);
+
+ // fs.SystemStreamDirICB.Parse(p + 464);
+
+ vol.FileSets.Add(fs);
+
+ // nextExtent.Parse(p + 448);
+ }
+
+ FOR_VECTOR (fsIndex, vol.FileSets)
+ {
+ CFileSet &fs = vol.FileSets[fsIndex];
+ const unsigned fileIndex = Files.Size();
+ Files.AddNew();
+ RINOK(ReadFileItem(volIndex, fsIndex, fs.RootDirICB,
+ true, // isDir
+ kNumRecursionLevelsMax))
+ RINOK(FillRefs(fs, fileIndex, -1, kNumRecursionLevelsMax))
+ }
+ }
+
+
+ for (volIndex = 0; volIndex < LogVols.Size(); volIndex++)
+ {
+ const CLogVol &vol = LogVols[volIndex];
+ // bool showFileSetName = (vol.FileSets.Size() > 1);
+ FOR_VECTOR (fsIndex, vol.FileSets)
+ {
+ const CFileSet &fs = vol.FileSets[fsIndex];
+ for (unsigned i =
+ // ((showVolName || showFileSetName) ? 0 : 1)
+ 0; i < fs.Refs.Size(); i++)
+ {
+ const CRef &ref = vol.FileSets[fsIndex].Refs[i];
+ const CFile &file = Files[ref.FileIndex];
+ const CItem &item = Items[file.ItemIndex];
+ UInt64 size = item.Size;
+
+ if (!item.IsRecAndAlloc() || !item.CheckChunkSizes() || !CheckItemExtents(volIndex, item))
+ continue;
+
+ FOR_VECTOR (extentIndex, item.Extents)
+ {
+ const CMyExtent &extent = item.Extents[extentIndex];
+ const UInt32 len = extent.GetLen();
+ if (len == 0)
+ continue;
+ if (size < len)
+ break;
+
+ const unsigned partitionIndex = vol.PartitionMaps[extent.PartitionRef].PartitionIndex;
+ const UInt32 logBlockNumber = extent.Pos;
+ const CPartition &partition = Partitions[partitionIndex];
+ const UInt64 offset = ((UInt64)partition.Pos << SecLogSize) +
+ (UInt64)logBlockNumber * vol.BlockSize;
+ UpdatePhySize(offset + len);
+ }
+ }
+ }
+ }
+
+ {
+ const UInt32 secMask = ((UInt32)1 << SecLogSize) - 1;
+ PhySize = (PhySize + secMask) & ~(UInt64)secMask;
+ }
+
+ NoEndAnchor = true;
+
+ if (PhySize < fileSize)
+ {
+ UInt64 rem = fileSize - PhySize;
+ const size_t secSize = (size_t)1 << SecLogSize;
+
+ RINOK(InStream_SeekSet(_stream, PhySize))
+
+ // some UDF images contain ZEROs before "Anchor Volume Descriptor Pointer" at the end
+
+ for (unsigned sec = 0; sec < 1024; sec++)
+ {
+ if (rem == 0)
+ break;
+
+ size_t readSize = secSize;
+ if (readSize > rem)
+ readSize = (size_t)rem;
+
+ RINOK(ReadStream(_stream, buf, &readSize))
+
+ if (readSize == 0)
+ break;
+
+ // some udf contain many EndAnchors
+ if (readSize == secSize /* && NoEndAnchor */)
+ {
+ CTag tag;
+ if (tag.Parse(buf, readSize) == S_OK
+ && tag.Id == DESC_TYPE_AnchorVolPtr
+ && Get32(buf + 12) == (UInt32)((fileSize - rem) >> SecLogSize))
+ {
+ NoEndAnchor = false;
+ rem -= readSize;
+ PhySize = fileSize - rem;
+ continue;
+ }
+ }
+
+ size_t i;
+ for (i = 0; i < readSize && buf[i] == 0; i++);
+ if (i != readSize)
+ break;
+ rem -= readSize;
+ }
+
+ if (rem == 0)
+ PhySize = fileSize;
+ }
+
+ return S_OK;
+}
+
+
+HRESULT CInArchive::Open(IInStream *inStream, CProgressVirt *progress)
+{
+ _progress = progress;
+ _stream = inStream;
+ HRESULT res = Open2();
+ if (res == S_FALSE && IsArc && !UnexpectedEnd)
+ Unsupported = true;
+ return res;
+
+ /*
+ HRESULT res;
+ try
+ {
+ res = Open2();
+ }
+ catch(...)
+ {
+ // Clear();
+ // res = S_FALSE;
+ _stream.Release();
+ throw;
+ }
+ _stream.Release();
+ return res;
+ */
+}
+
+void CInArchive::Clear()
+{
+ IsArc = false;
+ Unsupported = false;
+ UnexpectedEnd = false;
+ NoEndAnchor = false;
+
+ PhySize = 0;
+ FileSize = 0;
+
+ Partitions.Clear();
+ LogVols.Clear();
+ PrimeVols.Clear();
+ Items.Clear();
+ Files.Clear();
+ _fileNameLengthTotal = 0;
+ _numRefs = 0;
+ _numExtents = 0;
+ _inlineExtentsSize = 0;
+ _processedProgressBytes = 0;
+}
+
+
+static const char * const g_PartitionTypes[] =
+{
+ "Pseudo-Overwritable" // UDF
+ , "Read-Only"
+ , "Write-Once"
+ , "Rewritable"
+ , "Overwritable"
+};
+
+
+static void AddComment_Align(UString &s)
+{
+ s += " ";
+}
+
+static void AddComment_PropName(UString &s, const char *name)
+{
+ AddComment_Align(s);
+ s += name;
+ s += ": ";
+}
+
+static void AddComment_UInt32(UString &s, const char *name, UInt32 val)
+{
+ AddComment_PropName(s, name);
+ s.Add_UInt32(val);
+ s.Add_LF();
+}
+
+static void AddComment_UInt32_2(UString &s, const char *name, UInt32 val)
+{
+ AddComment_Align(s);
+ AddComment_UInt32(s, name, val);
+}
+
+
+static void AddComment_UInt64(UString &s, const char *name, UInt64 val)
+{
+ AddComment_PropName(s, name);
+ s.Add_UInt64(val);
+ s.Add_LF();
+}
+
+static void AddComment_RegId(UString &s, const char *name, const CRegId &ri)
+{
+ AddComment_PropName(s, name);
+ ri.AddCommentTo(s);
+ s.Add_LF();
+}
+
+static void AddComment_RegId_Domain(UString &s, const char *name, const CRegId &ri)
+{
+ AddComment_PropName(s, name);
+ ri.AddCommentTo(s);
+ {
+ UString s2;
+ ri.AddUdfVersionTo(s2);
+ if (!s2.IsEmpty())
+ {
+ s += "::";
+ s += s2;
+ }
+ }
+ s.Add_LF();
+}
+
+
+// UDF 6.3.1 OS Class
+
+static const char * const g_OsClasses[] =
+{
+ NULL
+ , "DOS"
+ , "OS/2"
+ , "Macintosh OS"
+ , "UNIX"
+ , "Windows 9x"
+ , "Windows NT"
+ , "OS/400"
+ , "BeOS"
+ , "Windows CE"
+};
+
+// UDF 6.3.2 OS Identifier
+
+static const char * const g_OsIds_Unix[] =
+{
+ NULL // "Generic"
+ , "AIX"
+ , "SUN OS / Solaris"
+ , "HP/UX"
+ , "Silicon Graphics Irix"
+ , "Linux"
+ , "MKLinux"
+ , "FreeBSD"
+ , "NetBSD"
+};
+
+static void AddOs_Class_Id(UString &s, const Byte *p)
+{
+ // UDF 2.1.5.3 Implementation Identifier Suffix
+ // Appendix 6.3 Operating System Identifiers.
+ const Byte osClass = p[0];
+ if (osClass != 0)
+ {
+ s += "::";
+ s += TypeToString(g_OsClasses, Z7_ARRAY_SIZE(g_OsClasses), osClass);
+ }
+ const Byte osId = p[1];
+ if (osId != 0)
+ {
+ s += "::";
+ if (osClass == 4) // unix
+ {
+ s += TypeToString(g_OsIds_Unix, Z7_ARRAY_SIZE(g_OsIds_Unix), osId);
+ }
+ else
+ s.Add_UInt32(osId);
+ }
+}
+
+
+static void AddComment_RegId_Impl(UString &s, const char *name, const CRegId &ri)
+{
+ AddComment_PropName(s, name);
+ ri.AddCommentTo(s);
+ {
+ AddOs_Class_Id(s, ri.Suffix);
+ }
+ s.Add_LF();
+}
+
+
+static void AddComment_RegId_UdfId(UString &s, const char *name, const CRegId &ri)
+{
+ AddComment_PropName(s, name);
+ ri.AddCommentTo(s);
+ {
+ // UDF 2.1.5.3
+ // UDF Identifier Suffix format
+ UString s2;
+ ri.AddUdfVersionTo(s2);
+ if (!s2.IsEmpty())
+ {
+ s += "::";
+ s += s2;
+ }
+ AddOs_Class_Id(s, &ri.Suffix[2]);
+ }
+ s.Add_LF();
+}
+
+static void AddComment_DString32(UString &s, const char *name, const CDString32 &d)
+{
+ AddComment_Align(s);
+ AddComment_PropName(s, name);
+ s += d.GetString();
+ s.Add_LF();
+}
+
+UString CInArchive::GetComment() const
+{
+ UString s;
+ {
+ s += "Primary Volumes:";
+ s.Add_LF();
+ FOR_VECTOR (i, PrimeVols)
+ {
+ if (i != 0)
+ s.Add_LF();
+ const CPrimeVol &pv = PrimeVols[i];
+ // AddComment_UInt32(s, "VolumeDescriptorSequenceNumber", pv.VolumeDescriptorSequenceNumber);
+ // if (PrimeVols.Size() != 1 || pv.PrimaryVolumeDescriptorNumber != 0)
+ AddComment_UInt32(s, "PrimaryVolumeDescriptorNumber", pv.PrimaryVolumeDescriptorNumber);
+ // if (pv.MaximumVolumeSequenceNumber != 1 || pv.VolumeSequenceNumber != 1)
+ AddComment_UInt32(s, "VolumeSequenceNumber", pv.VolumeSequenceNumber);
+ if (pv.MaximumVolumeSequenceNumber != 1)
+ AddComment_UInt32(s, "MaximumVolumeSequenceNumber", pv.MaximumVolumeSequenceNumber);
+ AddComment_PropName(s, "VolumeId");
+ s += pv.VolumeId.GetString();
+ s.Add_LF();
+ AddComment_PropName(s, "VolumeSetId");
+ s += pv.VolumeSetId.GetString();
+ s.Add_LF();
+ // AddComment_UInt32(s, "InterchangeLevel", pv.InterchangeLevel);
+ // AddComment_UInt32(s, "MaximumInterchangeLevel", pv.MaximumInterchangeLevel);
+ AddComment_RegId(s, "ApplicationId", pv.ApplicationId);
+ AddComment_RegId_Impl(s, "ImplementationId", pv.ImplId);
+ }
+ }
+ {
+ s += "Partitions:";
+ s.Add_LF();
+ FOR_VECTOR (i, Partitions)
+ {
+ if (i != 0)
+ s.Add_LF();
+ const CPartition &part = Partitions[i];
+ AddComment_UInt32(s, "PartitionIndex", i);
+ AddComment_UInt32(s, "PartitionNumber", part.Number);
+ if (part.IsMetadata)
+ AddComment_UInt32(s, "IsMetadata", 1);
+ else
+ {
+ AddComment_RegId(s, "ContentsId", part.ContentsId);
+ AddComment_RegId_Impl(s, "ImplementationId", part.ImplId);
+ AddComment_PropName(s, "AccessType");
+ s += TypeToString(g_PartitionTypes, Z7_ARRAY_SIZE(g_PartitionTypes), part.AccessType);
+ s.Add_LF();
+ }
+ AddComment_UInt64(s, "Size", (UInt64)part.Len << SecLogSize);
+ AddComment_UInt64(s, "Pos", (UInt64)part.Pos << SecLogSize);
+ }
+ }
+ s += "Logical Volumes:";
+ s.Add_LF();
+ {
+ FOR_VECTOR (i, LogVols)
+ {
+ if (i != 0)
+ s.Add_LF();
+ const CLogVol &vol = LogVols[i];
+ if (LogVols.Size() != 1)
+ AddComment_UInt32(s, "Number", i);
+ AddComment_PropName(s, "Id");
+ s += vol.Id.GetString();
+ s.Add_LF();
+ AddComment_UInt32(s, "BlockSize", vol.BlockSize);
+ AddComment_RegId_Domain(s, "DomainId", vol.DomainId);
+ AddComment_RegId_Impl(s, "ImplementationId", vol.ImplId);
+ // AddComment_UInt64(s, "IntegritySequenceExtent_Len", vol.IntegritySequenceExtent.Len);
+ // AddComment_UInt64(s, "IntegritySequenceExtent_Pos", (UInt64)vol.IntegritySequenceExtent.Pos << SecLogSize);
+
+ s += " Partition Maps:";
+ s.Add_LF();
+ {
+ FOR_VECTOR (j, vol.PartitionMaps)
+ {
+ if (j != 0)
+ s.Add_LF();
+ const CPartitionMap &pm = vol.PartitionMaps[j];
+ AddComment_UInt32_2(s, "PartitionMap", j);
+ AddComment_UInt32_2(s, "Type", pm.Type);
+ AddComment_UInt32_2(s, "VolumeSequenceNumber", pm.VolumeSequenceNumber);
+ AddComment_UInt32_2(s, "PartitionNumber", pm.PartitionNumber);
+ if (pm.Type == 2)
+ {
+ AddComment_UInt32_2(s, "MetadataFileLocation", pm.MetadataFileLocation);
+ // AddComment_UInt32_2(s, "MetadataMirrorFileLocation", pm.MetadataMirrorFileLocation);
+ // AddComment_UInt32_2(s, "MetadataBitmapFileLocation", pm.MetadataBitmapFileLocation);
+ // AddComment_UInt32_2(s, "AllocationUnitSize", pm.AllocationUnitSize);
+ // AddComment_UInt32_2(s, "AlignmentUnitSize", pm.AlignmentUnitSize);
+ // AddComment_UInt32_2(s, "Flags", pm.Flags);
+ AddComment_Align(s); AddComment_RegId_UdfId(s, "PartitionTypeId", pm.PartitionTypeId);
+ }
+ }
+ }
+ s += " File Sets:";
+ s.Add_LF();
+ {
+ FOR_VECTOR (j, vol.FileSets)
+ {
+ if (j != 0)
+ s.Add_LF();
+ const CFileSet &fs = vol.FileSets[j];
+ AddComment_Align(s); AddComment_UInt32(s, "FileSetNumber", fs.FileSetNumber);
+ AddComment_Align(s); AddComment_UInt32(s, "FileSetDescNumber", fs.FileSetDescNumber);
+
+ AddComment_Align(s);
+ AddComment_PropName(s, "LogicalVolumeId");
+ s += fs.LogicalVolumeId.GetString();
+ s.Add_LF();
+
+ AddComment_DString32(s, "Id", fs.Id);
+ AddComment_DString32(s, "CopyrightId", fs.CopyrightId);
+ AddComment_DString32(s, "AbstractId", fs.AbstractId);
+
+ AddComment_Align(s);
+ AddComment_RegId_Domain(s, "DomainId", fs.DomainId);
+ }
+ }
+ }
+ }
+ return s;
+}
+
+static UString GetSpecName(const UString &name)
+{
+ UString name2 = name;
+ name2.Trim();
+ if (name2.IsEmpty())
+ return UString("[]");
+ return name;
+}
+
+static void UpdateWithName(UString &res, const UString &addString)
+{
+ if (res.IsEmpty())
+ res = addString;
+ else
+ res.Insert(0, addString + WCHAR_PATH_SEPARATOR);
+}
+
+UString CInArchive::GetItemPath(unsigned volIndex, unsigned fsIndex, unsigned refIndex,
+ bool showVolName, bool showFsName) const
+{
+ // showVolName = true;
+ const CLogVol &vol = LogVols[volIndex];
+ const CFileSet &fs = vol.FileSets[fsIndex];
+
+ UString name;
+
+ for (;;)
+ {
+ const CRef &ref = fs.Refs[refIndex];
+ // we break on root file (that probably has empty name)
+ if (ref.Parent < 0)
+ break;
+ refIndex = (unsigned)ref.Parent;
+ UpdateWithName(name, GetSpecName(Files[ref.FileIndex].GetName()));
+ }
+
+ if (showFsName)
+ {
+ UString newName ("File Set ");
+ newName.Add_UInt32(fsIndex);
+ UpdateWithName(name, newName);
+ }
+
+ if (showVolName)
+ {
+ UString newName;
+ newName.Add_UInt32(volIndex);
+ UString newName2 = vol.GetName();
+ if (newName2.IsEmpty())
+ newName2 = "Volume";
+ newName += '-';
+ newName += newName2;
+ UpdateWithName(name, newName);
+ }
+ return name;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Udf/UdfIn.h b/CPP/7zip/Archive/Udf/UdfIn.h
new file mode 100644
index 0000000..9ccbf74
--- /dev/null
+++ b/CPP/7zip/Archive/Udf/UdfIn.h
@@ -0,0 +1,507 @@
+// Archive/UdfIn.h -- UDF / ECMA-167
+
+#ifndef ZIP7_INC_ARCHIVE_UDF_IN_H
+#define ZIP7_INC_ARCHIVE_UDF_IN_H
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/MyBuffer.h"
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyMap.h"
+#include "../../../Common/MyString.h"
+
+#include "../../IStream.h"
+
+namespace NArchive {
+namespace NUdf {
+
+// ---------- ECMA Part 1 ----------
+
+// ECMA 1/7.2.12
+// UDF 2.1.3
+
+struct CDString32
+{
+ Byte Data[32];
+
+ void Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); }
+ UString GetString() const;
+};
+
+struct CDString128
+{
+ Byte Data[128];
+
+ void Parse(const Byte *buf) { memcpy(Data, buf, sizeof(Data)); }
+ UString GetString() const;
+};
+
+struct CDString
+{
+ CByteBuffer Data;
+
+ void Parse(const Byte *p, unsigned size);
+ UString GetString() const;
+};
+
+
+// ECMA 1/7.3
+// UDF 2.1.4 timestamp
+
+struct CTime
+{
+ Byte Data[12];
+
+ unsigned GetType() const { return Data[1] >> 4; }
+ bool IsLocal() const { return GetType() == 1; }
+ int GetMinutesOffset() const
+ {
+ int t = (Data[0] | ((unsigned)Data[1] << 8)) & 0xFFF;
+ if ((t >> 11) != 0)
+ t -= (1 << 12);
+ return (t > (60 * 24) || t < -(60 * 24)) ? 0 : t;
+ }
+ unsigned GetYear() const { return (Data[2] | ((unsigned)Data[3] << 8)); }
+ void Parse(const Byte *buf);
+};
+
+
+// ECMA 1/7.4 regid
+// UDF 2.1.5 EntityID
+
+struct CRegId
+{
+ Byte Flags;
+ char Id[23];
+ Byte Suffix[8];
+
+ void Parse(const Byte *buf);
+ void AddCommentTo(UString &s) const;
+ void AddUdfVersionTo(UString &s) const;
+};
+
+
+
+// ---------- ECMA Part 3: Volume Structure ----------
+
+// ECMA 3/7.1
+
+struct CExtent
+{
+ UInt32 Len;
+ UInt32 Pos; // logical sector number
+
+ void Parse(const Byte *p);
+};
+
+
+// ECMA 3/10.1
+// UDF 2.2.2 PrimaryVolumeDescriptor
+
+struct CPrimeVol
+{
+ // UInt32 VolumeDescriptorSequenceNumber;
+ UInt32 PrimaryVolumeDescriptorNumber;
+ CDString32 VolumeId;
+ UInt16 VolumeSequenceNumber;
+ UInt16 MaximumVolumeSequenceNumber;
+ // UInt16 InterchangeLevel;
+ // UInt16 MaximumInterchangeLevel;
+ // UInt32 CharacterSetList;
+ // UInt32 MaximumCharacterSetList;
+ CDString128 VolumeSetId;
+ // charspec DescriptorCharacterSet; // (1/7.2.1)
+ // charspec ExplanatoryCharacterSet; // (1/7.2.1)
+ // CExtent VolumeAbstract;
+ // CExtent VolumeCopyrightNotice;
+ CRegId ApplicationId;
+ CTime RecordingTime;
+ CRegId ImplId;
+ // bytes ImplementationUse
+ // UInt32 PredecessorVolumeDescriptorSequenceLocation;
+ // UInt16 Flags;
+
+ void Parse(const Byte *p);
+};
+
+
+// ECMA 3/10.5
+// UDF 2.2.14 PartitionDescriptor
+
+struct CPartition
+{
+ UInt32 Pos;
+ UInt32 Len;
+
+ UInt16 Flags;
+ UInt16 Number;
+ CRegId ContentsId;
+ // Byte ContentsUse[128];
+ UInt32 AccessType;
+
+ CRegId ImplId;
+ // Byte ImplUse[128];
+
+ // int VolIndex;
+ CMap32 Map;
+
+ bool IsMetadata;
+
+ CPartition():
+ // VolIndex(-1),
+ IsMetadata(false) {}
+
+ // bool IsNsr() const { return (strncmp(ContentsId.Id, "+NSR0", 5) == 0); }
+ // bool IsAllocated() const { return ((Flags & 1) != 0); }
+};
+
+
+// ECMA 4/7.1 lb_addr
+
+struct CLogBlockAddr
+{
+ UInt32 Pos;
+ UInt16 PartitionRef;
+
+ void Parse(const Byte *p);
+};
+
+
+enum EShortAllocDescType
+{
+ SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated = 0,
+ SHORT_ALLOC_DESC_TYPE_NotRecordedButAllocated = 1,
+ SHORT_ALLOC_DESC_TYPE_NotRecordedAndNotAllocated = 2,
+ SHORT_ALLOC_DESC_TYPE_NextExtent = 3
+};
+
+
+// ECMA 4/14.14.1 short_ad
+
+struct CShortAllocDesc
+{
+ UInt32 Len;
+ UInt32 Pos;
+
+ // UInt32 GetLen() const { return Len & 0x3FFFFFFF; }
+ // UInt32 GetType() const { return Len >> 30; }
+ // bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; }
+ void Parse(const Byte *p);
+};
+
+/*
+struct CADImpUse
+{
+ UInt16 Flags;
+ UInt32 UdfUniqueId;
+ void Parse(const Byte *p);
+};
+*/
+
+// ECMA 4/14.14.2 long_ad
+// UDF 2.3.10.1
+
+struct CLongAllocDesc
+{
+ UInt32 Len;
+ CLogBlockAddr Location;
+
+ // Byte ImplUse[6];
+ // CADImpUse adImpUse; // UDF
+
+ UInt32 GetLen() const { return Len & 0x3FFFFFFF; }
+ UInt32 GetType() const { return Len >> 30; }
+ bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; }
+ void Parse(const Byte *p);
+};
+
+
+// ECMA 3/10.7 Partition maps
+// UDF 2.2.8-2.2.10 Partition Maps
+
+struct CPartitionMap
+{
+ unsigned PartitionIndex;
+
+ Byte Type;
+ // Byte Len;
+
+ // ECMA 10.7.2
+ UInt16 VolumeSequenceNumber;
+ UInt16 PartitionNumber;
+
+ CRegId PartitionTypeId;
+
+ // UDF 2.2.10 Metadata Partition Map
+ UInt32 MetadataFileLocation;
+ // UInt32 MetadataMirrorFileLocation;
+ // UInt32 MetadataBitmapFileLocation;
+ // UInt32 AllocationUnitSize; // (Blocks)
+ // UInt16 AlignmentUnitSize; // (Blocks)
+ // Byte Flags;
+
+ // Byte Data[256];
+ // CPartitionMap(): PartitionIndex(-1) {}
+};
+
+
+// ECMA 4/14.6.6
+
+enum EIcbFileType
+{
+ ICB_FILE_TYPE_DIR = 4,
+ ICB_FILE_TYPE_FILE = 5,
+
+ ICB_FILE_TYPE_METADATA = 250, // 2.2.13.1 Metadata File
+ ICB_FILE_TYPE_METADATA_MIRROR = 251
+};
+
+enum EIcbDescriptorType
+{
+ ICB_DESC_TYPE_SHORT = 0,
+ ICB_DESC_TYPE_LONG = 1,
+ ICB_DESC_TYPE_EXTENDED = 2,
+ ICB_DESC_TYPE_INLINE = 3
+};
+
+// ECMA 4/14.6
+// UDF 3.3.2
+
+struct CIcbTag
+{
+ // UInt32 PriorDirectNum;
+ // UInt16 StrategyType;
+ // UInt16 StrategyParam;
+ // UInt16 MaxNumOfEntries;
+ Byte FileType;
+ // CLogBlockAddr ParentIcb;
+ UInt16 Flags;
+
+ bool IsDir() const { return FileType == ICB_FILE_TYPE_DIR; }
+ int GetDescriptorType() const { return Flags & 3; }
+ void Parse(const Byte *p);
+};
+
+
+// ECMA 4/14.4.3
+// UDF 2.3.4.2 FileCharacteristics
+
+// const Byte FILEID_CHARACS_Existance = (1 << 0);
+const Byte FILEID_CHARACS_Dir = (1 << 1);
+const Byte FILEID_CHARACS_Deleted = (1 << 2);
+const Byte FILEID_CHARACS_Parent = (1 << 3);
+// const Byte FILEID_CHARACS_Metadata = (1 << 4);
+
+struct CFile
+{
+ int ItemIndex;
+ // UInt16 FileVersion;
+ // Byte FileCharacteristics;
+ // CByteBuffer ImplUse;
+ CDString Id;
+
+ CFile(): /* FileVersion(0), FileCharacteristics(0), */ ItemIndex(-1) {}
+ UString GetName() const { return Id.GetString(); }
+};
+
+
+struct CMyExtent
+{
+ UInt32 Pos;
+ UInt32 Len;
+ unsigned PartitionRef; // index in CLogVol::PartitionMaps
+
+ UInt32 GetLen() const { return Len & 0x3FFFFFFF; }
+ UInt32 GetType() const { return Len >> 30; }
+ bool IsRecAndAlloc() const { return GetType() == SHORT_ALLOC_DESC_TYPE_RecordedAndAllocated; }
+};
+
+
+struct CItem
+{
+ CIcbTag IcbTag;
+
+ // UInt32 Uid;
+ // UInt32 Gid;
+ // UInt32 Permissions;
+ UInt16 FileLinkCount;
+ // Byte RecordFormat;
+ // Byte RecordDisplayAttr;
+ // UInt32 RecordLen;
+ UInt64 Size;
+ UInt64 NumLogBlockRecorded;
+ // UInt64 ObjectSize;
+
+ CTime ATime;
+ CTime MTime;
+ CTime AttribTime; // Attribute time : most recent date and time of the day of file creation or modification of the attributes of.
+ CTime CreateTime;
+ // UInt32 CheckPoint;
+ // CLongAllocDesc ExtendedAttrIcb;
+ // CRegId ImplId;
+ // UInt64 UniqueId;
+
+ bool IsExtended;
+ bool IsInline;
+ CByteBuffer InlineData;
+ CRecordVector<CMyExtent> Extents;
+ CUIntVector SubFiles;
+
+ void Parse(const Byte *p);
+
+ bool IsRecAndAlloc() const
+ {
+ FOR_VECTOR (i, Extents)
+ if (!Extents[i].IsRecAndAlloc())
+ return false;
+ return true;
+ }
+
+ UInt64 GetChunksSumSize() const
+ {
+ if (IsInline)
+ return InlineData.Size();
+ UInt64 size = 0;
+ FOR_VECTOR (i, Extents)
+ size += Extents[i].GetLen();
+ return size;
+ }
+
+ bool CheckChunkSizes() const { return GetChunksSumSize() == Size; }
+
+ bool IsDir() const { return IcbTag.IsDir(); }
+};
+
+
+struct CRef
+{
+ unsigned FileIndex;
+ int Parent;
+};
+
+
+// ECMA 4 / 14.1
+struct CFileSet
+{
+ CRecordVector<CRef> Refs;
+
+ CTime RecordingTime;
+ // UInt16 InterchangeLevel;
+ // UInt16 MaxInterchangeLevel;
+ UInt32 FileSetNumber;
+ UInt32 FileSetDescNumber;
+ CDString128 LogicalVolumeId;
+ CDString32 Id;
+ CDString32 CopyrightId;
+ CDString32 AbstractId;
+
+ CLongAllocDesc RootDirICB;
+ CRegId DomainId;
+ // CLongAllocDesc SystemStreamDirICB;
+};
+
+
+/* 8.3 Volume descriptors
+8.4
+A Volume Descriptor Sequence:
+ shall contain one or more Primary Volume Descriptors.
+*/
+
+// ECMA 3/10.6
+// UDF 2.2.4 LogicalVolumeDescriptor
+
+struct CLogVol
+{
+ CObjectVector<CPartitionMap> PartitionMaps;
+ CObjectVector<CFileSet> FileSets;
+
+ UInt32 BlockSize;
+ CDString128 Id;
+ CRegId DomainId;
+
+ // Byte ContentsUse[16];
+ CLongAllocDesc FileSetLocation; // UDF
+
+ CRegId ImplId;
+ // Byte ImplUse[128];
+ // CExtent IntegritySequenceExtent;
+
+ UString GetName() const { return Id.GetString(); }
+};
+
+
+Z7_PURE_INTERFACES_BEGIN
+struct Z7_DECLSPEC_NOVTABLE CProgressVirt
+{
+ virtual HRESULT SetTotal(UInt64 numBytes) =0; \
+ virtual HRESULT SetCompleted(UInt64 numFiles, UInt64 numBytes) =0; \
+ virtual HRESULT SetCompleted() =0; \
+};
+Z7_PURE_INTERFACES_END
+
+class CInArchive
+{
+public:
+ CObjectVector<CLogVol> LogVols;
+ CObjectVector<CItem> Items;
+ CObjectVector<CFile> Files;
+ CObjectVector<CPartition> Partitions;
+
+ unsigned SecLogSize;
+ UInt64 PhySize;
+ UInt64 FileSize;
+
+ bool IsArc;
+ bool Unsupported;
+ bool UnexpectedEnd;
+ bool NoEndAnchor;
+
+ CObjectVector<CPrimeVol> PrimeVols;
+
+ HRESULT Open(IInStream *inStream, CProgressVirt *progress);
+ void Clear();
+
+ UString GetComment() const;
+ UString GetItemPath(unsigned volIndex, unsigned fsIndex, unsigned refIndex,
+ bool showVolName, bool showFsName) const;
+
+ bool CheckItemExtents(unsigned volIndex, const CItem &item) const;
+
+private:
+ IInStream *_stream;
+ CProgressVirt *_progress;
+
+ HRESULT Read(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len, Byte *buf);
+ HRESULT ReadLad(unsigned volIndex, const CLongAllocDesc &lad, Byte *buf);
+ HRESULT ReadFromFile(unsigned volIndex, const CItem &item, CByteBuffer &buf);
+
+ HRESULT ReadFileItem(unsigned volIndex, unsigned fsIndex, const CLongAllocDesc &lad, bool isDir, int numRecurseAllowed);
+ HRESULT ReadItem(unsigned volIndex, int fsIndex, const CLongAllocDesc &lad, bool isDir, int numRecurseAllowed);
+
+ HRESULT Open2();
+ HRESULT FillRefs(CFileSet &fs, unsigned fileIndex, int parent, int numRecurseAllowed);
+
+ UInt64 _processedProgressBytes;
+
+ UInt64 _fileNameLengthTotal;
+ unsigned _numRefs;
+ UInt32 _numExtents;
+ UInt64 _inlineExtentsSize;
+ bool CheckExtent(unsigned volIndex, unsigned partitionRef, UInt32 blockPos, UInt32 len) const;
+
+ void UpdatePhySize(UInt64 val)
+ {
+ if (PhySize < val)
+ PhySize = val;
+ }
+
+ void UpdatePhySize(const CExtent &e)
+ {
+ UpdatePhySize(((UInt64)e.Pos << SecLogSize) + e.Len);
+ }
+};
+
+API_FUNC_IsArc IsArc_Udf(const Byte *p, size_t size);
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/UefiHandler.cpp b/CPP/7zip/Archive/UefiHandler.cpp
new file mode 100644
index 0000000..cd6fcbd
--- /dev/null
+++ b/CPP/7zip/Archive/UefiHandler.cpp
@@ -0,0 +1,1893 @@
+// UefiHandler.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#endif
+
+#include "../../../C/7zCrc.h"
+#include "../../../C/Alloc.h"
+#include "../../../C/CpuArch.h"
+#include "../../../C/LzmaDec.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/StringConvert.h"
+
+#include "../../Windows/PropVariantUtils.h"
+
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+#include "../Compress/LzhDecoder.h"
+
+#ifdef SHOW_DEBUG_INFO
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+#define Get24(p) (Get32(p) & 0xFFFFFF)
+
+namespace NArchive {
+namespace NUefi {
+
+static const size_t kBufTotalSizeMax = (1 << 29);
+static const unsigned kNumFilesMax = (1 << 18);
+static const unsigned kLevelMax = 64;
+
+static const Byte k_IntelMeSignature[] =
+{
+ 0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
+ 0x5A, 0xA5, 0xF0, 0x0F
+};
+
+static bool IsIntelMe(const Byte *p)
+{
+ return memcmp(p, k_IntelMeSignature, sizeof(k_IntelMeSignature)) == 0;
+}
+
+static const unsigned kFvHeaderSize = 0x38;
+
+static const unsigned kGuidSize = 16;
+
+#define CAPSULE_SIGNATURE 0xBD,0x86,0x66,0x3B,0x76,0x0D,0x30,0x40,0xB7,0x0E,0xB5,0x51,0x9E,0x2F,0xC5,0xA0
+#define CAPSULE2_SIGNATURE 0x8B,0xA6,0x3C,0x4A,0x23,0x77,0xFB,0x48,0x80,0x3D,0x57,0x8C,0xC1,0xFE,0xC4,0x4D
+#define CAPSULE_UEFI_SIGNATURE 0xB9,0x82,0x91,0x53,0xB5,0xAB,0x91,0x43,0xB6,0x9A,0xE3,0xA9,0x43,0xF7,0x2F,0xCC
+/*
+ 6dcbd5ed-e82d-4c44-bda1-7194199ad92a : Firmware Management `
+*/
+
+static const Byte k_Guids_Capsules[][kGuidSize] =
+{
+ { CAPSULE_SIGNATURE },
+ { CAPSULE2_SIGNATURE },
+ { CAPSULE_UEFI_SIGNATURE }
+};
+
+
+static const unsigned kFfsGuidOffset = 16;
+
+#define FFS1_SIGNATURE 0xD9,0x54,0x93,0x7A,0x68,0x04,0x4A,0x44,0x81,0xCE,0x0B,0xF6,0x17,0xD8,0x90,0xDF
+#define FFS2_SIGNATURE 0x78,0xE5,0x8C,0x8C,0x3D,0x8A,0x1C,0x4F,0x99,0x35,0x89,0x61,0x85,0xC3,0x2D,0xD3
+#define MACFS_SIGNATURE 0xAD,0xEE,0xAD,0x04,0xFF,0x61,0x31,0x4D,0xB6,0xBA,0x64,0xF8,0xBF,0x90,0x1F,0x5A
+// APPLE_BOOT
+/*
+ "FFS3": "5473c07a-3dcb-4dca-bd6f-1e9689e7349a",
+ "NVRAM_EVSA": "fff12b8d-7696-4c8b-a985-2747075b4f50",
+ "NVRAM_NVAR": "cef5b9a3-476d-497f-9fdc-e98143e0422c",
+ "NVRAM_EVSA2": "00504624-8a59-4eeb-bd0f-6b36e96128e0",
+static const Byte k_NVRAM_NVAR_Guid[kGuidSize] =
+ { 0xA3,0xB9,0xF5,0xCE,0x6D,0x47,0x7F,0x49,0x9F,0xDC,0xE9,0x81,0x43,0xE0,0x42,0x2C };
+*/
+
+static const Byte k_Guids_FS[][kGuidSize] =
+{
+ { FFS1_SIGNATURE },
+ { FFS2_SIGNATURE },
+ { MACFS_SIGNATURE }
+};
+
+
+static const UInt32 kFvSignature = 0x4856465F; // "_FVH"
+
+static const Byte kGuids[][kGuidSize] =
+{
+ { 0xB0,0xCD,0x1B,0xFC,0x31,0x7D,0xAA,0x49,0x93,0x6A,0xA4,0x60,0x0D,0x9D,0xD0,0x83 },
+ { 0x2E,0x06,0xA0,0x1B,0x79,0xC7,0x82,0x45,0x85,0x66,0x33,0x6A,0xE8,0xF7,0x8F,0x09 },
+ { 0x25,0x4E,0x37,0x7E,0x01,0x8E,0xEE,0x4F,0x87,0xf2,0x39,0x0C,0x23,0xC6,0x06,0xCD },
+ { 0x97,0xE5,0x1B,0x16,0xC5,0xE9,0xDB,0x49,0xAE,0x50,0xC4,0x62,0xAB,0x54,0xEE,0xDA },
+ { 0xDB,0x7F,0xAD,0x77,0x2A,0xDF,0x02,0x43,0x88,0x98,0xC7,0x2E,0x4C,0xDB,0xD0,0xF4 },
+ { 0xAB,0x71,0xCF,0xF5,0x4B,0xB0,0x7E,0x4B,0x98,0x8A,0xD8,0xA0,0xD4,0x98,0xE6,0x92 },
+ { 0x91,0x45,0x53,0x7A,0xCE,0x37,0x81,0x48,0xB3,0xC9,0x71,0x38,0x14,0xF4,0x5D,0x6B },
+ { 0x84,0xE6,0x7A,0x36,0x5D,0x33,0x71,0x46,0xA1,0x6D,0x89,0x9D,0xBF,0xEA,0x6B,0x88 },
+ { 0x98,0x07,0x40,0x24,0x07,0x38,0x42,0x4A,0xB4,0x13,0xA1,0xEC,0xEE,0x20,0x5D,0xD8 },
+ { 0xEE,0xA2,0x3F,0x28,0x2C,0x53,0x4D,0x48,0x93,0x83,0x9F,0x93,0xB3,0x6F,0x0B,0x7E },
+ { 0x9B,0xD5,0xB8,0x98,0xBA,0xE8,0xEE,0x48,0x98,0xDD,0xC2,0x95,0x39,0x2F,0x1E,0xDB },
+ { 0x09,0x6D,0xE3,0xC3,0x94,0x82,0x97,0x4B,0xA8,0x57,0xD5,0x28,0x8F,0xE3,0x3E,0x28 },
+ { 0x18,0x88,0x53,0x4A,0xE0,0x5A,0xB2,0x4E,0xB2,0xEB,0x48,0x8B,0x23,0x65,0x70,0x22 }
+};
+
+static const Byte k_Guid_LZMA_COMPRESSED[kGuidSize] =
+ { 0x98,0x58,0x4E,0xEE,0x14,0x39,0x59,0x42,0x9D,0x6E,0xDC,0x7B,0xD7,0x94,0x03,0xCF };
+
+static const char * const kGuidNames[] =
+{
+ "CRC"
+ , "VolumeTopFile"
+ , "ACPI"
+ , "ACPI2"
+ , "Main"
+ , "Intel32"
+ , "Intel64"
+ , "Intel32c"
+ , "Intel64c"
+ , "MacVolume"
+ , "MacUpdate.txt"
+ , "MacName"
+ , "Insyde"
+};
+
+enum
+{
+ kGuidIndex_CRC = 0
+};
+
+struct CSigExtPair
+{
+ const char *ext;
+ unsigned sigSize;
+ Byte sig[16];
+};
+
+static const CSigExtPair g_Sigs[] =
+{
+ { "bmp", 2, { 'B','M' } },
+ { "riff", 4, { 'R','I','F','F' } },
+ { "pe", 2, { 'M','Z'} },
+ { "gif", 6, { 'G','I','F','8','9', 'a' } },
+ { "png", 8, { 0x89,0x50,0x4E,0x47,0x0D,0x0A,0x1A,0x0A } },
+ { "jpg", 10, { 0xFF,0xD8,0xFF,0xE0,0x00,0x10,0x4A,0x46,0x49,0x46 } },
+ { "rom", 2, { 0x55,0xAA } }
+};
+
+enum
+{
+ kSig_BMP,
+ kSig_RIFF,
+ kSig_PE
+};
+
+static const char *FindExt(const Byte *p, size_t size)
+{
+ unsigned i;
+ for (i = 0; i < Z7_ARRAY_SIZE(g_Sigs); i++)
+ {
+ const CSigExtPair &pair = g_Sigs[i];
+ if (size >= pair.sigSize)
+ if (memcmp(p, pair.sig, pair.sigSize) == 0)
+ break;
+ }
+ if (i == Z7_ARRAY_SIZE(g_Sigs))
+ return NULL;
+ switch (i)
+ {
+ case kSig_BMP:
+ if (GetUi32(p + 2) > size || GetUi32(p + 0xA) > size)
+ return NULL;
+ break;
+ case kSig_RIFF:
+ if (GetUi32(p + 8) == 0x45564157 || GetUi32(p + 0xC) == 0x20746D66 )
+ return "wav";
+ break;
+ case kSig_PE:
+ {
+ if (size < 512)
+ return NULL;
+ UInt32 peOffset = GetUi32(p + 0x3C);
+ if (peOffset >= 0x1000 || peOffset + 512 > size || (peOffset & 7) != 0)
+ return NULL;
+ if (GetUi32(p + peOffset) != 0x00004550)
+ return NULL;
+ break;
+ }
+ }
+ return g_Sigs[i].ext;
+}
+
+static bool AreGuidsEq(const Byte *p1, const Byte *p2)
+{
+ return memcmp(p1, p2, kGuidSize) == 0;
+}
+
+static int FindGuid(const Byte *p)
+{
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(kGuids); i++)
+ if (AreGuidsEq(p, kGuids[i]))
+ return (int)i;
+ return -1;
+}
+
+static bool IsFfs(const Byte *p)
+{
+ if (Get32(p + 0x28) != kFvSignature)
+ return false;
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_Guids_FS); i++)
+ if (AreGuidsEq(p + kFfsGuidOffset, k_Guids_FS[i]))
+ return true;
+ return false;
+}
+
+#define FVB_ERASE_POLARITY (1 << 11)
+
+/*
+static const CUInt32PCharPair g_FV_Attribs[] =
+{
+ { 0, "ReadDisabledCap" },
+ { 1, "ReadEnabledCap" },
+ { 2, "ReadEnabled" },
+ { 3, "WriteDisabledCap" },
+ { 4, "WriteEnabledCap" },
+ { 5, "WriteEnabled" },
+ { 6, "LockCap" },
+ { 7, "Locked" },
+
+ { 9, "StickyWrite" },
+ { 10, "MemoryMapped" },
+ { 11, "ErasePolarity" },
+
+ { 12, "ReadLockCap" },
+ { 13, "WriteLockCap" },
+ { 14, "WriteLockCap" }
+};
+*/
+
+enum
+{
+ FV_FILETYPE_ALL,
+ FV_FILETYPE_RAW,
+ FV_FILETYPE_FREEFORM,
+ FV_FILETYPE_SECURITY_CORE,
+ FV_FILETYPE_PEI_CORE,
+ FV_FILETYPE_DXE_CORE,
+ FV_FILETYPE_PEIM,
+ FV_FILETYPE_DRIVER,
+ FV_FILETYPE_COMBINED_PEIM_DRIVER,
+ FV_FILETYPE_APPLICATION,
+ // The value 0x0A is reserved and should not be used
+ FV_FILETYPE_FIRMWARE_VOLUME_IMAGE = 0x0B,
+ // types 0xF0 - 0xFF are FFS file types
+ FV_FILETYPE_FFS_PAD = 0xF0
+};
+
+static const char * const g_FileTypes[] =
+{
+ "ALL"
+ , "RAW"
+ , "FREEFORM"
+ , "SECURITY_CORE"
+ , "PEI_CORE"
+ , "DXE_CORE"
+ , "PEIM"
+ , "DRIVER"
+ , "COMBINED_PEIM_DRIVER"
+ , "APPLICATION"
+ , "0xA"
+ , "VOLUME"
+};
+
+// typedef Byte FFS_FILE_ATTRIBUTES;
+// FFS File Attributes
+#define FFS_ATTRIB_TAIL_PRESENT 0x01
+// #define FFS_ATTRIB_RECOVERY 0x02
+// #define FFS_ATTRIB_HEADER_EXTENSION 0x04
+// #define FFS_ATTRIB_DATA_ALIGNMENT 0x38
+#define FFS_ATTRIB_CHECKSUM 0x40
+
+static const CUInt32PCharPair g_FFS_FILE_ATTRIBUTES[] =
+{
+ { 0, "" /* "TAIL" */ },
+ { 1, "RECOVERY" },
+ // { 2, "HEADER_EXTENSION" }, // reserved for future
+ { 6, "" /* "CHECKSUM" */ }
+};
+
+// static const Byte g_Allignment[8] = { 3, 4, 7, 9, 10, 12, 15, 16 };
+
+// typedef Byte FFS_FILE_STATE;
+
+// Look also FVB_ERASE_POLARITY.
+// Lower-order State bits are superceded by higher-order State bits.
+
+// #define FILE_HEADER_CONSTRUCTION 0x01
+// #define FILE_HEADER_VALID 0x02
+#define FILE_DATA_VALID 0x04
+// #define FILE_MARKED_FOR_UPDATE 0x08
+// #define FILE_DELETED 0x10
+// #define FILE_HEADER_INVALID 0x20
+
+// SECTION_TYPE
+
+// #define SECTION_ALL 0x00
+
+#define SECTION_COMPRESSION 0x01
+#define SECTION_GUID_DEFINED 0x02
+
+// Leaf section Type values
+// #define SECTION_PE32 0x10
+// #define SECTION_PIC 0x11
+// #define SECTION_TE 0x12
+#define SECTION_DXE_DEPEX 0x13
+#define SECTION_VERSION 0x14
+#define SECTION_USER_INTERFACE 0x15
+// #define SECTION_COMPATIBILITY16 0x16
+#define SECTION_FIRMWARE_VOLUME_IMAGE 0x17
+#define SECTION_FREEFORM_SUBTYPE_GUID 0x18
+#define SECTION_RAW 0x19
+#define SECTION_PEI_DEPEX 0x1B
+
+
+// #define GUIDED_SECTION_PROCESSING_REQUIRED 0x01
+// #define GUIDED_SECTION_AUTH_STATUS_VALID 0x02
+
+static const CUInt32PCharPair g_GUIDED_SECTION_ATTRIBUTES[] =
+{
+ { 0, "PROCESSING_REQUIRED" },
+ { 1, "AUTH" }
+};
+
+static const CUInt32PCharPair g_SECTION_TYPE[] =
+{
+ { 0x01, "COMPRESSION" },
+ { 0x02, "GUID" },
+ { 0x10, "efi" },
+ { 0x11, "PIC" },
+ { 0x12, "te" },
+ { 0x13, "DXE_DEPEX" },
+ { 0x14, "VERSION" },
+ { 0x15, "USER_INTERFACE" },
+ { 0x16, "COMPATIBILITY16" },
+ { 0x17, "VOLUME" },
+ { 0x18, "FREEFORM_SUBTYPE_GUID" },
+ { 0x19, "raw" },
+ { 0x1B, "PEI_DEPEX" }
+};
+
+#define COMPRESSION_TYPE_NONE 0
+#define COMPRESSION_TYPE_LZH 1
+#define COMPRESSION_TYPE_LZMA 2
+
+static const char * const g_Methods[] =
+{
+ "COPY"
+ , "LZH"
+ , "LZMA"
+};
+
+
+static void AddGuid(AString &dest, const Byte *p, bool full)
+{
+ char s[64];
+ ::RawLeGuidToString(p, s);
+ // MyStringUpper_Ascii(s);
+ if (!full)
+ s[8] = 0;
+ dest += s;
+}
+
+static const char * const kExpressionCommands[] =
+{
+ "BEFORE", "AFTER", "PUSH", "AND", "OR", "NOT", "TRUE", "FALSE", "END", "SOR"
+};
+
+static bool ParseDepedencyExpression(const Byte *p, UInt32 size, AString &res)
+{
+ res.Empty();
+ for (UInt32 i = 0; i < size;)
+ {
+ unsigned command = p[i++];
+ if (command > Z7_ARRAY_SIZE(kExpressionCommands))
+ return false;
+ res += kExpressionCommands[command];
+ if (command < 3)
+ {
+ if (i + kGuidSize > size)
+ return false;
+ res.Add_Space();
+ AddGuid(res, p + i, false);
+ i += kGuidSize;
+ }
+ res += "; ";
+ }
+ return true;
+}
+
+static bool ParseUtf16zString(const Byte *p, UInt32 size, UString &res)
+{
+ if ((size & 1) != 0)
+ return false;
+ res.Empty();
+ UInt32 i;
+ for (i = 0; i < size; i += 2)
+ {
+ wchar_t c = Get16(p + i);
+ if (c == 0)
+ break;
+ res += c;
+ }
+ return (i == size - 2);
+}
+
+static bool ParseUtf16zString2(const Byte *p, UInt32 size, AString &res)
+{
+ UString s;
+ if (!ParseUtf16zString(p, size, s))
+ return false;
+ res = UnicodeStringToMultiByte(s);
+ return true;
+}
+
+#define FLAGS_TO_STRING(pairs, value) FlagsToString(pairs, Z7_ARRAY_SIZE(pairs), value)
+#define TYPE_TO_STRING(table, value) TypeToString(table, Z7_ARRAY_SIZE(table), value)
+#define TYPE_PAIR_TO_STRING(table, value) TypePairToString(table, Z7_ARRAY_SIZE(table), value)
+
+static const UInt32 kFileHeaderSize = 24;
+
+static void AddSpaceAndString(AString &res, const AString &newString)
+{
+ if (!newString.IsEmpty())
+ {
+ res.Add_Space_if_NotEmpty();
+ res += newString;
+ }
+}
+
+class CFfsFileHeader
+{
+PRF(public:)
+ Byte CheckHeader;
+ Byte CheckFile;
+ Byte Attrib;
+ Byte State;
+
+ UInt16 GetTailReference() const { return (UInt16)(CheckHeader | ((UInt16)CheckFile << 8)); }
+ UInt32 GetTailSize() const { return IsThereTail() ? 2 : 0; }
+ bool IsThereFileChecksum() const { return (Attrib & FFS_ATTRIB_CHECKSUM) != 0; }
+ bool IsThereTail() const { return (Attrib & FFS_ATTRIB_TAIL_PRESENT) != 0; }
+public:
+ Byte GuidName[kGuidSize];
+ Byte Type;
+ UInt32 Size;
+
+ bool Parse(const Byte *p)
+ {
+ unsigned i;
+ for (i = 0; i < kFileHeaderSize; i++)
+ if (p[i] != 0xFF)
+ break;
+ if (i == kFileHeaderSize)
+ return false;
+ memcpy(GuidName, p, kGuidSize);
+ CheckHeader = p[0x10];
+ CheckFile = p[0x11];
+ Type = p[0x12];
+ Attrib = p[0x13];
+ Size = Get24(p + 0x14);
+ State = p[0x17];
+ return true;
+ }
+
+ UInt32 GetDataSize() const { return Size - kFileHeaderSize - GetTailSize(); }
+ UInt32 GetDataSize2(UInt32 rem) const { return rem - kFileHeaderSize - GetTailSize(); }
+
+ bool Check(const Byte *p, UInt32 size)
+ {
+ if (Size > size)
+ return false;
+ UInt32 tailSize = GetTailSize();
+ if (Size < kFileHeaderSize + tailSize)
+ return false;
+
+ {
+ unsigned checkSum = 0;
+ for (UInt32 i = 0; i < kFileHeaderSize; i++)
+ checkSum += p[i];
+ checkSum -= p[0x17];
+ checkSum -= p[0x11];
+ if ((Byte)checkSum != 0)
+ return false;
+ }
+
+ if (IsThereFileChecksum())
+ {
+ unsigned checkSum = 0;
+ UInt32 checkSize = Size - tailSize;
+ for (UInt32 i = 0; i < checkSize; i++)
+ checkSum += p[i];
+ checkSum -= p[0x17];
+ if ((Byte)checkSum != 0)
+ return false;
+ }
+
+ if (IsThereTail())
+ if (GetTailReference() != (UInt16)~Get16(p + Size - 2))
+ return false;
+
+ int polarity = 0;
+ int i;
+ for (i = 5; i >= 0; i--)
+ if (((State >> i) & 1) == polarity)
+ {
+ // AddSpaceAndString(s, g_FFS_FILE_STATE_Flags[i]);
+ if ((1 << i) != FILE_DATA_VALID)
+ return false;
+ break;
+ }
+ if (i < 0)
+ return false;
+
+ return true;
+ }
+
+ AString GetCharacts() const
+ {
+ AString s;
+ if (Type == FV_FILETYPE_FFS_PAD)
+ s += "PAD";
+ else
+ s += TYPE_TO_STRING(g_FileTypes, Type);
+ AddSpaceAndString(s, FLAGS_TO_STRING(g_FFS_FILE_ATTRIBUTES, Attrib & 0xC7));
+ /*
+ int align = (Attrib >> 3) & 7;
+ if (align != 0)
+ {
+ s += " Align:";
+ s.Add_UInt32((UInt32)1 << g_Allignment[align]);
+ }
+ */
+ return s;
+ }
+};
+
+#define G32(_offs_, dest) dest = Get32(p + (_offs_))
+#define G16(_offs_, dest) dest = Get16(p + (_offs_))
+
+struct CCapsuleHeader
+{
+ UInt32 HeaderSize;
+ UInt32 Flags;
+ UInt32 CapsuleImageSize;
+ UInt32 SequenceNumber;
+ // Guid InstanceId;
+ UInt32 OffsetToSplitInformation;
+ UInt32 OffsetToCapsuleBody;
+ UInt32 OffsetToOemDefinedHeader;
+ UInt32 OffsetToAuthorInformation;
+ UInt32 OffsetToRevisionInformation;
+ UInt32 OffsetToShortDescription;
+ UInt32 OffsetToLongDescription;
+ UInt32 OffsetToApplicableDevices;
+
+ void Clear() { memset(this, 0, sizeof(*this)); }
+
+ bool Parse(const Byte *p)
+ {
+ Clear();
+ G32(0x10, HeaderSize);
+ G32(0x14, Flags);
+ G32(0x18, CapsuleImageSize);
+ if (HeaderSize < 0x1C)
+ return false;
+ if (AreGuidsEq(p, k_Guids_Capsules[0]))
+ {
+ const unsigned kHeaderSize = 80;
+ if (HeaderSize != kHeaderSize)
+ return false;
+ G32(0x1C, SequenceNumber);
+ G32(0x30, OffsetToSplitInformation);
+ G32(0x34, OffsetToCapsuleBody);
+ G32(0x38, OffsetToOemDefinedHeader);
+ G32(0x3C, OffsetToAuthorInformation);
+ G32(0x40, OffsetToRevisionInformation);
+ G32(0x44, OffsetToShortDescription);
+ G32(0x48, OffsetToLongDescription);
+ G32(0x4C, OffsetToApplicableDevices);
+ return true;
+ }
+ else if (AreGuidsEq(p, k_Guids_Capsules[1]))
+ {
+ // capsule v2
+ G16(0x1C, OffsetToCapsuleBody);
+ G16(0x1E, OffsetToOemDefinedHeader);
+ return true;
+ }
+ else if (AreGuidsEq(p, k_Guids_Capsules[2]))
+ {
+ OffsetToCapsuleBody = HeaderSize;
+ return true;
+ }
+ else
+ {
+ // here we must check for another capsule types
+ return false;
+ }
+ }
+};
+
+
+struct CItem
+{
+ AString Name;
+ AString Characts;
+ int Parent;
+ int Method;
+ int NameIndex;
+ unsigned NumChilds;
+ bool IsDir;
+ bool Skip;
+ bool ThereAreSubDirs;
+ bool ThereIsUniqueName;
+ bool KeepName;
+
+ unsigned BufIndex;
+ UInt32 Offset;
+ UInt32 Size;
+
+ CItem(): Parent(-1), Method(-1), NameIndex(-1), NumChilds(0),
+ IsDir(false), Skip(false), ThereAreSubDirs(false), ThereIsUniqueName(false), KeepName(true) {}
+ void SetGuid(const Byte *guidName, bool full = false);
+ AString GetName(int numChildsInParent) const;
+};
+
+void CItem::SetGuid(const Byte *guidName, bool full)
+{
+ ThereIsUniqueName = true;
+ int index = FindGuid(guidName);
+ if (index >= 0)
+ Name = kGuidNames[(unsigned)index];
+ else
+ {
+ Name.Empty();
+ AddGuid(Name, guidName, full);
+ }
+}
+
+AString CItem::GetName(int numChildsInParent) const
+{
+ if (numChildsInParent <= 1 || NameIndex < 0)
+ return Name;
+ char sz[32];
+ char sz2[32];
+ ConvertUInt32ToString((unsigned)NameIndex, sz);
+ ConvertUInt32ToString((unsigned)numChildsInParent - 1, sz2);
+ const int numZeros = (int)strlen(sz2) - (int)strlen(sz);
+ AString res;
+ for (int i = 0; i < numZeros; i++)
+ res += '0';
+ res += sz;
+ res.Add_Dot();
+ res += Name;
+ return res;
+}
+
+struct CItem2
+{
+ AString Name;
+ AString Characts;
+ unsigned MainIndex;
+ int Parent;
+
+ CItem2(): Parent(-1) {}
+};
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IInArchiveGetStream
+)
+ CObjectVector<CItem> _items;
+ CObjectVector<CItem2> _items2;
+ CObjectVector<CByteBuffer> _bufs;
+ UString _comment;
+ UInt32 _methodsMask;
+ bool _capsuleMode;
+ bool _headersError;
+
+ size_t _totalBufsSize;
+ CCapsuleHeader _h;
+ UInt64 _phySize;
+
+ void AddCommentString(const char *name, UInt32 pos);
+ unsigned AddItem(const CItem &item);
+ unsigned AddFileItemWithIndex(CItem &item);
+ unsigned AddDirItem(CItem &item);
+ unsigned AddBuf(size_t size);
+
+ HRESULT DecodeLzma(const Byte *data, size_t inputSize);
+
+ HRESULT ParseSections(unsigned bufIndex, UInt32 pos,
+ UInt32 size,
+ int parent, int method, unsigned level,
+ bool &error);
+
+ HRESULT ParseIntelMe(unsigned bufIndex, UInt32 posBase,
+ UInt32 exactSize, UInt32 limitSize,
+ int parent, int method, unsigned level);
+
+ HRESULT ParseVolume(unsigned bufIndex, UInt32 posBase,
+ UInt32 exactSize, UInt32 limitSize,
+ int parent, int method, unsigned level);
+
+ HRESULT OpenCapsule(IInStream *stream);
+ HRESULT OpenFv(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback);
+ HRESULT Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback);
+public:
+ CHandler(bool capsuleMode): _capsuleMode(capsuleMode) {}
+};
+
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ // kpidOffset,
+ kpidMethod,
+ kpidCharacts
+};
+
+static const Byte kArcProps[] =
+{
+ kpidComment,
+ kpidMethod,
+ kpidCharacts
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItem2 &item2 = _items2[index];
+ const CItem &item = _items[item2.MainIndex];
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ AString path (item2.Name);
+ int cur = item2.Parent;
+ while (cur >= 0)
+ {
+ const CItem2 &item3 = _items2[cur];
+ path.InsertAtFront(CHAR_PATH_SEPARATOR);
+ path.Insert(0, item3.Name);
+ cur = item3.Parent;
+ }
+ prop = path;
+ break;
+ }
+ case kpidIsDir: prop = item.IsDir; break;
+ case kpidMethod: if (item.Method >= 0) prop = g_Methods[(unsigned)item.Method]; break;
+ case kpidCharacts: if (!item2.Characts.IsEmpty()) prop = item2.Characts; break;
+ case kpidSize: if (!item.IsDir) prop = (UInt64)item.Size; break;
+ // case kpidOffset: if (!item.IsDir) prop = item.Offset; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+void CHandler::AddCommentString(const char *name, UInt32 pos)
+{
+ UString s;
+ if (pos < _h.HeaderSize)
+ return;
+ if (pos >= _h.OffsetToCapsuleBody)
+ return;
+ UInt32 limit = (_h.OffsetToCapsuleBody - pos) & ~(UInt32)1;
+ const Byte *buf = _bufs[0] + pos;
+ for (UInt32 i = 0;;)
+ {
+ if (s.Len() > (1 << 16) || i >= limit)
+ return;
+ wchar_t c = Get16(buf + i);
+ i += 2;
+ if (c == 0)
+ {
+ if (i >= limit)
+ return;
+ c = Get16(buf + i);
+ i += 2;
+ if (c == 0)
+ break;
+ s.Add_LF();
+ }
+ s += c;
+ }
+ if (s.IsEmpty())
+ return;
+ _comment.Add_LF();
+ _comment += name;
+ _comment += ": ";
+ _comment += s;
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidMethod:
+ {
+ AString s;
+ for (unsigned i = 0; i < 32; i++)
+ if ((_methodsMask & ((UInt32)1 << i)) != 0)
+ AddSpaceAndString(s, (AString)g_Methods[i]);
+ if (!s.IsEmpty())
+ prop = s;
+ break;
+ }
+ case kpidComment: if (!_comment.IsEmpty()) prop = _comment; break;
+ case kpidPhySize: prop = (UInt64)_phySize; break;
+
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_headersError) v |= kpv_ErrorFlags_HeadersError;
+ if (v != 0)
+ prop = v;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+#ifdef SHOW_DEBUG_INFO
+static void PrintLevel(unsigned level)
+{
+ PRF(printf("\n"));
+ for (unsigned i = 0; i < level; i++)
+ PRF(printf(" "));
+}
+static void MyPrint(UInt32 posBase, UInt32 size, unsigned level, const char *name)
+{
+ PrintLevel(level);
+ PRF(printf("%s, pos = %6x, size = %6x", name, posBase, size));
+}
+#else
+#define PrintLevel(level)
+#define MyPrint(posBase, size, level, name)
+#endif
+
+
+
+unsigned CHandler::AddItem(const CItem &item)
+{
+ if (_items.Size() >= kNumFilesMax)
+ throw 2;
+ return _items.Add(item);
+}
+
+unsigned CHandler::AddFileItemWithIndex(CItem &item)
+{
+ unsigned nameIndex = _items.Size();
+ if (item.Parent >= 0)
+ nameIndex = _items[item.Parent].NumChilds++;
+ item.NameIndex = (int)nameIndex;
+ return AddItem(item);
+}
+
+unsigned CHandler::AddDirItem(CItem &item)
+{
+ if (item.Parent >= 0)
+ _items[item.Parent].ThereAreSubDirs = true;
+ item.IsDir = true;
+ item.Size = 0;
+ return AddItem(item);
+}
+
+unsigned CHandler::AddBuf(size_t size)
+{
+ if (size > kBufTotalSizeMax - _totalBufsSize)
+ throw 1;
+ _totalBufsSize += size;
+ unsigned index = _bufs.Size();
+ _bufs.AddNew().Alloc(size);
+ return index;
+}
+
+
+HRESULT CHandler::DecodeLzma(const Byte *data, size_t inputSize)
+{
+ if (inputSize < 5 + 8)
+ return S_FALSE;
+ const UInt64 unpackSize = Get64(data + 5);
+ if (unpackSize > ((UInt32)1 << 30))
+ return S_FALSE;
+ SizeT destLen = (SizeT)unpackSize;
+ const unsigned newBufIndex = AddBuf((size_t)unpackSize);
+ CByteBuffer &buf = _bufs[newBufIndex];
+ ELzmaStatus status;
+ SizeT srcLen = inputSize - (5 + 8);
+ const SizeT srcLen2 = srcLen;
+ SRes res = LzmaDecode(buf, &destLen, data + 13, &srcLen,
+ data, 5, LZMA_FINISH_END, &status, &g_Alloc);
+ if (res != 0)
+ return S_FALSE;
+ if (srcLen != srcLen2 || destLen != unpackSize || (
+ status != LZMA_STATUS_FINISHED_WITH_MARK &&
+ status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK))
+ return S_FALSE;
+ return S_OK;
+}
+
+
+HRESULT CHandler::ParseSections(unsigned bufIndex, UInt32 posBase, UInt32 size, int parent, int method, unsigned level, bool &error)
+{
+ error = false;
+
+ if (level > kLevelMax)
+ return S_FALSE;
+ MyPrint(posBase, size, level, "Sections");
+ level++;
+ const Byte *bufData = _bufs[bufIndex];
+ UInt32 pos = 0;
+ for (;;)
+ {
+ if (size == pos)
+ return S_OK;
+ PrintLevel(level);
+ PRF(printf("%s, abs = %6x, relat = %6x", "Sect", posBase + pos, pos));
+ pos = (pos + 3) & ~(UInt32)3;
+ if (pos > size)
+ return S_FALSE;
+ UInt32 rem = size - pos;
+ if (rem == 0)
+ return S_OK;
+ if (rem < 4)
+ return S_FALSE;
+
+ const Byte *p = bufData + posBase + pos;
+
+ const UInt32 sectSize = Get24(p);
+ const Byte type = p[3];
+
+ // PrintLevel(level);
+ PRF(printf(" type = %2x, sectSize = %6x", type, sectSize));
+
+ if (sectSize > rem || sectSize < 4)
+ {
+ _headersError = true;
+ error = true;
+ return S_OK;
+ // return S_FALSE;
+ }
+
+ CItem item;
+ item.Method = method;
+ item.BufIndex = bufIndex;
+ item.Parent = parent;
+ item.Offset = posBase + pos + 4;
+ UInt32 sectDataSize = sectSize - 4;
+ item.Size = sectDataSize;
+ item.Name = TYPE_PAIR_TO_STRING(g_SECTION_TYPE, type);
+
+ if (type == SECTION_COMPRESSION)
+ {
+ if (sectSize < 4 + 5)
+ return S_FALSE;
+ UInt32 uncompressedSize = Get32(p + 4);
+ Byte compressionType = p[8];
+
+ UInt32 newSectSize = sectSize - 9;
+ UInt32 newOffset = posBase + pos + 9;
+ const Byte *pStart = p + 9;
+
+ item.KeepName = false;
+ if (compressionType > 2)
+ {
+ // AddFileItemWithIndex(item);
+ return S_FALSE;
+ }
+ else
+ {
+ item.Name = g_Methods[compressionType];
+ // int parent = AddDirItem(item);
+ if (compressionType == COMPRESSION_TYPE_NONE)
+ {
+ bool error2;
+ RINOK(ParseSections(bufIndex, newOffset, newSectSize, parent, method, level, error2))
+ }
+ else if (compressionType == COMPRESSION_TYPE_LZH)
+ {
+ unsigned newBufIndex = AddBuf(uncompressedSize);
+ CByteBuffer &buf = _bufs[newBufIndex];
+
+ NCompress::NLzh::NDecoder::CCoder *lzhDecoderSpec = NULL;
+ CMyComPtr<ICompressCoder> lzhDecoder;
+
+ lzhDecoderSpec = new NCompress::NLzh::NDecoder::CCoder;
+ lzhDecoder = lzhDecoderSpec;
+
+ {
+ const Byte *src = pStart;
+ if (newSectSize < 8)
+ return S_FALSE;
+ UInt32 packSize = Get32(src);
+ UInt32 unpackSize = Get32(src + 4);
+
+ PRF(printf(" LZH packSize = %6x, unpackSize = %6x", packSize, unpackSize));
+
+ if (uncompressedSize != unpackSize || newSectSize - 8 != packSize)
+ return S_FALSE;
+ if (packSize < 1)
+ return S_FALSE;
+ packSize--;
+ src += 8;
+ if (src[packSize] != 0)
+ return S_FALSE;
+
+ CBufInStream *inStreamSpec = new CBufInStream;
+ CMyComPtr<IInStream> inStream = inStreamSpec;
+
+ CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;
+ CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+
+ UInt64 uncompressedSize64 = uncompressedSize;
+ lzhDecoderSpec->FinishMode = true;
+ /*
+ EFI 1.1 probably used LZH with small dictionary and (pbit = 4). It was named "Efi compression".
+ New version of compression code (named Tiano) uses LZH with (1 << 19) dictionary.
+ But maybe LZH decoder in UEFI decoder supports larger than (1 << 19) dictionary.
+ We check both LZH versions: Tiano and then Efi.
+ */
+ HRESULT res = S_FALSE;
+
+ for (unsigned m = 0 ; m < 2; m++)
+ {
+ inStreamSpec->Init(src, packSize);
+ outStreamSpec->Init(buf, uncompressedSize);
+ lzhDecoderSpec->SetDictSize((m == 0) ? ((UInt32)1 << 19) : ((UInt32)1 << 14));
+ res = lzhDecoder->Code(inStream, outStream, NULL, &uncompressedSize64, NULL);
+ if (res == S_OK)
+ break;
+ }
+ RINOK(res)
+ }
+
+ bool error2;
+ RINOK(ParseSections(newBufIndex, 0, uncompressedSize, parent, compressionType, level, error2))
+ }
+ else
+ {
+ if (newSectSize < 4 + 5 + 8)
+ return S_FALSE;
+ unsigned addSize = 4;
+ if (pStart[0] == 0x5d && pStart[1] == 0 && pStart[2] == 0 && pStart[3] == 0x80 && pStart[4] == 0)
+ {
+ addSize = 0;
+ // some archives have such header
+ }
+ else
+ {
+ // normal BIOS contains uncompressed size here
+ // UInt32 uncompressedSize2 = Get24(pStart);
+ // Byte firstSectType = p[9 + 3];
+ // firstSectType can be 0 in some archives
+ }
+ pStart += addSize;
+
+ RINOK(DecodeLzma(pStart, newSectSize - addSize))
+ const size_t lzmaUncompressedSize = _bufs.Back().Size();
+ // if (lzmaUncompressedSize != uncompressedSize)
+ if (lzmaUncompressedSize < uncompressedSize)
+ return S_FALSE;
+ bool error2;
+ RINOK(ParseSections(_bufs.Size() - 1, 0, (UInt32)lzmaUncompressedSize, parent, compressionType, level, error2))
+ }
+ _methodsMask |= (1 << compressionType);
+ }
+ }
+ else if (type == SECTION_GUID_DEFINED)
+ {
+ const unsigned kHeaderSize = 4 + kGuidSize + 4;
+ if (sectSize < kHeaderSize)
+ return S_FALSE;
+ item.SetGuid(p + 4);
+ const UInt32 dataOffset = Get16(p + 4 + kGuidSize);
+ const UInt32 attrib = Get16(p + 4 + kGuidSize + 2);
+ if (dataOffset > sectSize || dataOffset < kHeaderSize)
+ return S_FALSE;
+ UInt32 newSectSize = sectSize - dataOffset;
+ item.Size = newSectSize;
+ UInt32 newOffset = posBase + pos + dataOffset;
+ item.Offset = newOffset;
+ const UInt32 propsSize = dataOffset - kHeaderSize;
+ AddSpaceAndString(item.Characts, FLAGS_TO_STRING(g_GUIDED_SECTION_ATTRIBUTES, attrib));
+
+ bool needDir = true;
+ unsigned newBufIndex = bufIndex;
+ int newMethod = method;
+
+ if (AreGuidsEq(p + 0x4, k_Guid_LZMA_COMPRESSED))
+ {
+ // item.Name = "guid.lzma";
+ // AddItem(item);
+ const Byte *pStart = bufData + newOffset;
+ // do we need correct pStart here for lzma steram offset?
+ RINOK(DecodeLzma(pStart, newSectSize))
+ _methodsMask |= (1 << COMPRESSION_TYPE_LZMA);
+ newBufIndex = _bufs.Size() - 1;
+ newOffset = 0;
+ newSectSize = (UInt32)_bufs.Back().Size();
+ newMethod = COMPRESSION_TYPE_LZMA;
+ }
+ else if (AreGuidsEq(p + 0x4, kGuids[kGuidIndex_CRC]) && propsSize == 4)
+ {
+ needDir = false;
+ item.KeepName = false;
+ if (CrcCalc(bufData + newOffset, newSectSize) != Get32(p + kHeaderSize))
+ return S_FALSE;
+ }
+ else
+ {
+ if (propsSize != 0)
+ {
+ CItem item2 = item;
+ item2.Name += ".prop";
+ item2.Size = propsSize;
+ item2.Offset = posBase + pos + kHeaderSize;
+ AddItem(item2);
+ }
+ }
+
+ int newParent = parent;
+ if (needDir)
+ newParent = (int)AddDirItem(item);
+ bool error2;
+ RINOK(ParseSections(newBufIndex, newOffset, newSectSize, newParent, newMethod, level, error2))
+ }
+ else if (type == SECTION_FIRMWARE_VOLUME_IMAGE)
+ {
+ item.KeepName = false;
+ const int newParent = (int)AddDirItem(item);
+ RINOK(ParseVolume(bufIndex, posBase + pos + 4,
+ sectSize - 4,
+ sectSize - 4,
+ newParent, method, level))
+ }
+ else
+ {
+ bool needAdd = true;
+ switch (type)
+ {
+ case SECTION_RAW:
+ {
+ const UInt32 kInsydeOffset = 12;
+ if (sectDataSize >= kFvHeaderSize + kInsydeOffset)
+ {
+ if (IsFfs(p + 4 + kInsydeOffset) &&
+ sectDataSize - kInsydeOffset == Get64(p + 4 + kInsydeOffset + 0x20))
+ {
+ needAdd = false;
+ item.Name = "vol";
+ const unsigned newParent = AddDirItem(item);
+ RINOK(ParseVolume(bufIndex, posBase + pos + 4 + kInsydeOffset,
+ sectDataSize - kInsydeOffset,
+ sectDataSize - kInsydeOffset,
+ (int)newParent, method, level))
+ }
+
+ if (needAdd)
+ {
+ const char *ext = FindExt(p + 4, sectDataSize);
+ if (ext)
+ item.Name = ext;
+ }
+ }
+ break;
+ }
+ case SECTION_DXE_DEPEX:
+ case SECTION_PEI_DEPEX:
+ {
+ AString s;
+ if (ParseDepedencyExpression(p + 4, sectDataSize, s))
+ {
+ if (s.Len() < (1 << 9))
+ {
+ s.InsertAtFront('[');
+ s += ']';
+ AddSpaceAndString(_items[item.Parent].Characts, s);
+ needAdd = false;
+ }
+ else
+ {
+ item.BufIndex = AddBuf(s.Len());
+ CByteBuffer &buf0 = _bufs[item.BufIndex];
+ if (s.Len() != 0)
+ memcpy(buf0, s, s.Len());
+ item.Offset = 0;
+ item.Size = s.Len();
+ }
+ }
+ break;
+ }
+ case SECTION_VERSION:
+ {
+ if (sectDataSize > 2)
+ {
+ AString s;
+ if (ParseUtf16zString2(p + 6, sectDataSize - 2, s))
+ {
+ AString s2 ("ver:");
+ s2.Add_UInt32(Get16(p + 4));
+ s2.Add_Space();
+ s2 += s;
+ AddSpaceAndString(_items[item.Parent].Characts, s2);
+ needAdd = false;
+ }
+ }
+ break;
+ }
+ case SECTION_USER_INTERFACE:
+ {
+ AString s;
+ if (ParseUtf16zString2(p + 4, sectDataSize, s))
+ {
+ _items[parent].Name = s;
+ needAdd = false;
+ }
+ break;
+ }
+ case SECTION_FREEFORM_SUBTYPE_GUID:
+ {
+ if (sectDataSize >= kGuidSize)
+ {
+ item.SetGuid(p + 4);
+ item.Size = sectDataSize - kGuidSize;
+ item.Offset = posBase + pos + 4 + kGuidSize;
+ }
+ break;
+ }
+ }
+
+ if (needAdd)
+ AddFileItemWithIndex(item);
+ }
+
+ pos += sectSize;
+ }
+}
+
+static UInt32 Count_FF_Bytes(const Byte *p, UInt32 size)
+{
+ UInt32 i;
+ for (i = 0; i < size && p[i] == 0xFF; i++);
+ return i;
+}
+
+static bool Is_FF_Stream(const Byte *p, UInt32 size)
+{
+ return (Count_FF_Bytes(p, size) == size);
+}
+
+struct CVolFfsHeader
+{
+ UInt32 HeaderLen;
+ UInt64 VolSize;
+
+ bool Parse(const Byte *p);
+};
+
+bool CVolFfsHeader::Parse(const Byte *p)
+{
+ if (Get32(p + 0x28) != kFvSignature)
+ return false;
+
+ UInt32 attribs = Get32(p + 0x2C);
+ if ((attribs & FVB_ERASE_POLARITY) == 0)
+ return false;
+ VolSize = Get64(p + 0x20);
+ HeaderLen = Get16(p + 0x30);
+ if (HeaderLen < kFvHeaderSize || (HeaderLen & 0x7) != 0 || VolSize < HeaderLen)
+ return false;
+ return true;
+}
+
+
+HRESULT CHandler::ParseVolume(
+ unsigned bufIndex, UInt32 posBase,
+ UInt32 exactSize, UInt32 limitSize,
+ int parent, int method, unsigned level)
+{
+ if (level > kLevelMax)
+ return S_FALSE;
+ MyPrint(posBase, exactSize, level, "Volume");
+ level++;
+ if (exactSize < kFvHeaderSize)
+ return S_FALSE;
+ const Byte *p = _bufs[bufIndex] + posBase;
+ // first 16 bytes must be zeros, but they are not zeros sometimes.
+ if (!IsFfs(p))
+ {
+ CItem item;
+ item.Method = method;
+ item.BufIndex = bufIndex;
+ item.Parent = parent;
+ item.Offset = posBase;
+ item.Size = exactSize;
+ if (!Is_FF_Stream(p + kFfsGuidOffset, 16))
+ item.SetGuid(p + kFfsGuidOffset);
+ // if (item.Name.IsEmpty())
+ item.Name += "[VOL]";
+ AddItem(item);
+ return S_OK;
+ }
+
+ CVolFfsHeader ffsHeader;
+ if (!ffsHeader.Parse(p))
+ return S_FALSE;
+ // if (parent >= 0) AddSpaceAndString(_items[parent].Characts, FLAGS_TO_STRING(g_FV_Attribs, attribs));
+
+ // VolSize > exactSize (fh.Size) for some UEFI archives (is it correct UEFI?)
+ // so we check VolSize for limitSize instead.
+
+ if (ffsHeader.HeaderLen > limitSize || ffsHeader.VolSize > limitSize)
+ return S_FALSE;
+
+ {
+ UInt32 checkCalc = 0;
+ for (UInt32 i = 0; i < ffsHeader.HeaderLen; i += 2)
+ checkCalc += Get16(p + i);
+ if ((checkCalc & 0xFFFF) != 0)
+ return S_FALSE;
+ }
+
+ // 3 reserved bytes are not zeros sometimes.
+ // UInt16 ExtHeaderOffset; // in new SPECIFICATION?
+ // Byte revision = p[0x37];
+
+ UInt32 pos = kFvHeaderSize;
+ for (;;)
+ {
+ if (pos >= ffsHeader.HeaderLen)
+ return S_FALSE;
+ UInt32 numBlocks = Get32(p + pos);
+ UInt32 length = Get32(p + pos + 4);
+ pos += 8;
+ if (numBlocks == 0 && length == 0)
+ break;
+ }
+ if (pos != ffsHeader.HeaderLen)
+ return S_FALSE;
+
+ CRecordVector<UInt32> guidsVector;
+
+ for (;;)
+ {
+ UInt32 rem = (UInt32)ffsHeader.VolSize - pos;
+ if (rem < kFileHeaderSize)
+ break;
+ pos = (pos + 7) & ~7u;
+ rem = (UInt32)ffsHeader.VolSize - pos;
+ if (rem < kFileHeaderSize)
+ break;
+
+ CItem item;
+ item.Method = method;
+ item.BufIndex = bufIndex;
+ item.Parent = parent;
+
+ const Byte *pFile = p + pos;
+ CFfsFileHeader fh;
+ if (!fh.Parse(pFile))
+ {
+ UInt32 num_FF_bytes = Count_FF_Bytes(pFile, rem);
+ if (num_FF_bytes != rem)
+ {
+ item.Name = "[junk]";
+ item.Offset = posBase + pos + num_FF_bytes;
+ item.Size = rem - num_FF_bytes;
+ AddItem(item);
+ }
+ PrintLevel(level); PRF(printf("== FF FF reminder"));
+
+ break;
+ }
+
+ PrintLevel(level); PRF(printf("%s, type = %3d, pos = %7x, size = %7x", "FILE", fh.Type, posBase + pos, fh.Size));
+
+ if (!fh.Check(pFile, rem))
+ return S_FALSE;
+
+ UInt32 offset = posBase + pos + kFileHeaderSize;
+ UInt32 sectSize = fh.GetDataSize();
+ item.Offset = offset;
+ item.Size = sectSize;
+
+ pos += fh.Size;
+
+ if (fh.Type == FV_FILETYPE_FFS_PAD)
+ if (Is_FF_Stream(pFile + kFileHeaderSize, sectSize))
+ continue;
+
+ UInt32 guid32 = Get32(fh.GuidName);
+ bool full = true;
+ if (guidsVector.FindInSorted(guid32) < 0)
+ {
+ guidsVector.AddToUniqueSorted(guid32);
+ full = false;
+ }
+ item.SetGuid(fh.GuidName, full);
+
+ item.Characts = fh.GetCharacts();
+ // PrintLevel(level);
+ PRF(printf(" : %s", item.Characts));
+
+ {
+ PRF(printf(" attrib = %2d State = %3d ", (unsigned)fh.Attrib, (unsigned)fh.State));
+ PRF(char s[64]);
+ PRF(RawLeGuidToString(fh.GuidName, s));
+ PRF(printf(" : %s ", s));
+ }
+
+ if (fh.Type == FV_FILETYPE_FFS_PAD ||
+ fh.Type == FV_FILETYPE_RAW)
+ {
+ bool isVolume = false;
+ if (fh.Type == FV_FILETYPE_RAW)
+ {
+ if (sectSize >= kFvHeaderSize)
+ if (IsFfs(pFile + kFileHeaderSize))
+ isVolume = true;
+ }
+ if (isVolume)
+ {
+ const unsigned newParent = AddDirItem(item);
+ const UInt32 limSize = fh.GetDataSize2(rem);
+ // volume.VolSize > fh.Size for some UEFI archives (is it correct UEFI?)
+ // so we will check VolSize for limitSize instead.
+ RINOK(ParseVolume(bufIndex, offset, sectSize, limSize, (int)newParent, method, level))
+ }
+ else
+ AddItem(item);
+ }
+ else
+ {
+ /*
+ if (fh.Type == FV_FILETYPE_FREEFORM)
+ {
+ // in intel bio example: one FV_FILETYPE_FREEFORM file is wav file (not sections)
+ // AddItem(item);
+ }
+ else
+ */
+ {
+ const unsigned newParent = AddDirItem(item);
+ bool error2;
+ RINOK(ParseSections(bufIndex, offset, sectSize, (int)newParent, method, level + 1, error2))
+ if (error2)
+ {
+ // in intel bio example: one FV_FILETYPE_FREEFORM file is wav file (not sections)
+ item.IsDir = false;
+ item.Size = sectSize;
+ item.Name.Insert(0, "[ERROR]");
+ AddItem(item);
+ }
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+static const char * const kRegionName[] =
+{
+ "Descriptor"
+ , "BIOS"
+ , "ME"
+ , "GbE"
+ , "PDR"
+ , "Region5"
+ , "Region6"
+ , "Region7"
+};
+
+
+HRESULT CHandler::ParseIntelMe(
+ unsigned bufIndex, UInt32 posBase,
+ UInt32 exactSize, UInt32 limitSize,
+ int parent, int method, unsigned /* level */)
+{
+ UNUSED_VAR(limitSize)
+ // level++;
+
+ const Byte *p = _bufs[bufIndex] + posBase;
+ if (exactSize < 16 + 16)
+ return S_FALSE;
+ if (!IsIntelMe(p))
+ return S_FALSE;
+
+ UInt32 v0 = GetUi32(p + 20);
+ // UInt32 numRegions = (v0 >> 24) & 0x7;
+ UInt32 regAddr = (v0 >> 12) & 0xFF0;
+ // UInt32 numComps = (v0 >> 8) & 0x3;
+ // UInt32 fcba = (v0 << 4) & 0xFF0;
+
+ // (numRegions == 0) in header in some new images.
+ // So we don't use the value from header
+ UInt32 numRegions = 7;
+
+ for (unsigned i = 0; i <= numRegions; i++)
+ {
+ UInt32 offset = regAddr + i * 4;
+ if (offset + 4 > exactSize)
+ break;
+ UInt32 val = GetUi32(p + offset);
+
+ // only 12 bits probably are OK.
+ // How does it work for files larger than 16 MB?
+ const UInt32 kMask = 0xFFF;
+ // const UInt32 kMask = 0xFFFF; // 16-bit is more logical
+ const UInt32 lim = (val >> 16) & kMask;
+ const UInt32 base = (val & kMask);
+
+ /*
+ strange combinations:
+ PDR: base = 0x1FFF lim = 0;
+ empty: base = 0xFFFF lim = 0xFFFF;
+
+ PDR: base = 0x7FFF lim = 0;
+ empty: base = 0x7FFF lim = 0;
+ */
+ if (base == kMask && lim == 0)
+ continue; // unused
+
+ if (lim < base)
+ continue; // unused
+
+ CItem item;
+ item.Name = kRegionName[i];
+ item.Method = method;
+ item.BufIndex = bufIndex;
+ item.Parent = parent;
+ item.Offset = posBase + (base << 12);
+ if (item.Offset > exactSize)
+ continue;
+ item.Size = (lim + 1 - base) << 12;
+ // item.SetGuid(p + kFfsGuidOffset);
+ // item.Name += " [VOLUME]";
+ AddItem(item);
+ }
+ return S_OK;
+}
+
+
+HRESULT CHandler::OpenCapsule(IInStream *stream)
+{
+ const unsigned kHeaderSize = 80;
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(stream, buf, kHeaderSize))
+ if (!_h.Parse(buf))
+ return S_FALSE;
+ if (_h.CapsuleImageSize < kHeaderSize
+ || _h.CapsuleImageSize < _h.HeaderSize
+ || _h.OffsetToCapsuleBody < _h.HeaderSize
+ || _h.OffsetToCapsuleBody > _h.CapsuleImageSize
+ )
+ return S_FALSE;
+ _phySize = _h.CapsuleImageSize;
+
+ if (_h.SequenceNumber != 0 ||
+ _h.OffsetToSplitInformation != 0 )
+ return E_NOTIMPL;
+
+ unsigned bufIndex = AddBuf(_h.CapsuleImageSize);
+ CByteBuffer &buf0 = _bufs[bufIndex];
+ memcpy(buf0, buf, kHeaderSize);
+ ReadStream_FALSE(stream, buf0 + kHeaderSize, _h.CapsuleImageSize - kHeaderSize);
+
+ AddCommentString("Author", _h.OffsetToAuthorInformation);
+ AddCommentString("Revision", _h.OffsetToRevisionInformation);
+ AddCommentString("Short Description", _h.OffsetToShortDescription);
+ AddCommentString("Long Description", _h.OffsetToLongDescription);
+
+
+ const UInt32 size = _h.CapsuleImageSize - _h.OffsetToCapsuleBody;
+
+ if (size >= 32 && IsIntelMe(buf0 + _h.OffsetToCapsuleBody))
+ return ParseIntelMe(bufIndex, _h.OffsetToCapsuleBody, size, size, -1, -1, 0);
+
+ return ParseVolume(bufIndex, _h.OffsetToCapsuleBody, size, size, -1, -1, 0);
+}
+
+
+HRESULT CHandler::OpenFv(IInStream *stream, const UInt64 * /* maxCheckStartPosition */, IArchiveOpenCallback * /* callback */)
+{
+ Byte buf[kFvHeaderSize];
+ RINOK(ReadStream_FALSE(stream, buf, kFvHeaderSize))
+ if (!IsFfs(buf))
+ return S_FALSE;
+ CVolFfsHeader ffsHeader;
+ if (!ffsHeader.Parse(buf))
+ return S_FALSE;
+ if (ffsHeader.VolSize > ((UInt32)1 << 30))
+ return S_FALSE;
+ _phySize = ffsHeader.VolSize;
+ RINOK(InStream_SeekToBegin(stream))
+ UInt32 fvSize32 = (UInt32)ffsHeader.VolSize;
+ unsigned bufIndex = AddBuf(fvSize32);
+ RINOK(ReadStream_FALSE(stream, _bufs[bufIndex], fvSize32))
+ return ParseVolume(bufIndex, 0, fvSize32, fvSize32, -1, -1, 0);
+}
+
+
+HRESULT CHandler::Open2(IInStream *stream, const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback)
+{
+ if (_capsuleMode)
+ {
+ RINOK(OpenCapsule(stream))
+ }
+ else
+ {
+ RINOK(OpenFv(stream, maxCheckStartPosition, callback))
+ }
+
+ const unsigned num = _items.Size();
+ CIntArr numChilds(num);
+
+ unsigned i;
+
+ for (i = 0; i < num; i++)
+ numChilds[i] = 0;
+
+ for (i = 0; i < num; i++)
+ {
+ const int parent = _items[i].Parent;
+ if (parent >= 0)
+ numChilds[(unsigned)parent]++;
+ }
+
+ for (i = 0; i < num; i++)
+ {
+ const CItem &item = _items[i];
+ const int parent = item.Parent;
+ if (parent >= 0)
+ {
+ CItem &parentItem = _items[(unsigned)parent];
+ if (numChilds[(unsigned)parent] == 1)
+ if (!item.ThereIsUniqueName || !parentItem.ThereIsUniqueName || !parentItem.ThereAreSubDirs)
+ parentItem.Skip = true;
+ }
+ }
+
+ CUIntVector mainToReduced;
+
+ for (i = 0; i < _items.Size(); i++)
+ {
+ mainToReduced.Add(_items2.Size());
+ const CItem &item = _items[i];
+ if (item.Skip)
+ continue;
+ AString name;
+ int numItems = -1;
+ int parent = item.Parent;
+ if (parent >= 0)
+ numItems = numChilds[(unsigned)parent];
+ AString name2 (item.GetName(numItems));
+ AString characts2 (item.Characts);
+ if (item.KeepName)
+ name = name2;
+
+ while (parent >= 0)
+ {
+ const CItem &item3 = _items[(unsigned)parent];
+ if (!item3.Skip)
+ break;
+ if (item3.KeepName)
+ {
+ AString name3 (item3.GetName(-1));
+ if (name.IsEmpty())
+ name = name3;
+ else
+ name = name3 + '.' + name;
+ }
+ AddSpaceAndString(characts2, item3.Characts);
+ parent = item3.Parent;
+ }
+
+ if (name.IsEmpty())
+ name = name2;
+
+ CItem2 item2;
+ item2.MainIndex = i;
+ item2.Name = name;
+ item2.Characts = characts2;
+ if (parent >= 0)
+ item2.Parent = (int)mainToReduced[(unsigned)parent];
+ _items2.Add(item2);
+ /*
+ CItem2 item2;
+ item2.MainIndex = i;
+ item2.Name = item.Name;
+ item2.Parent = item.Parent;
+ _items2.Add(item2);
+ */
+ }
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
+ const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ Close();
+ {
+ HRESULT res = Open2(inStream, maxCheckStartPosition, callback);
+ if (res == E_NOTIMPL)
+ res = S_FALSE;
+ return res;
+ }
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _phySize = 0;
+ _totalBufsSize = 0;
+ _methodsMask = 0;
+ _items.Clear();
+ _items2.Clear();
+ _bufs.Clear();
+ _comment.Empty();
+ _headersError = false;
+ _h.Clear();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _items2.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _items2.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _items[_items2[allFilesMode ? i : indices[i]].MainIndex].Size;
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentTotalSize = 0;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = lps->OutSize = currentTotalSize;
+ RINOK(lps->SetCur())
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CItem &item = _items[_items2[index].MainIndex];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+ currentTotalSize += item.Size;
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode))
+ if (testMode || item.IsDir)
+ {
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+ int res = NExtract::NOperationResult::kDataError;
+ CMyComPtr<ISequentialInStream> inStream;
+ GetStream(index, &inStream);
+ if (inStream)
+ {
+ RINOK(copyCoder->Code(inStream, realOutStream, NULL, NULL, progress))
+ if (copyCoderSpec->TotalSize == item.Size)
+ res = NExtract::NOperationResult::kOK;
+ }
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(res))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ const CItem &item = _items[_items2[index].MainIndex];
+ if (item.IsDir)
+ return S_FALSE;
+ CBufInStream *streamSpec = new CBufInStream;
+ CMyComPtr<IInStream> streamTemp = streamSpec;
+ const CByteBuffer &buf = _bufs[item.BufIndex];
+ if (item.Offset > buf.Size())
+ return S_FALSE;
+ size_t size = buf.Size() - item.Offset;
+ if (size > item.Size)
+ size = item.Size;
+ streamSpec->Init(buf + item.Offset, size, (IInArchive *)this);
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+
+namespace UEFIc {
+
+static const Byte k_Capsule_Signatures[] =
+{
+ 16, CAPSULE_SIGNATURE,
+ 16, CAPSULE2_SIGNATURE,
+ 16, CAPSULE_UEFI_SIGNATURE
+};
+
+REGISTER_ARC_I_CLS(
+ CHandler(true),
+ "UEFIc", "scap", NULL, 0xD0,
+ k_Capsule_Signatures,
+ 0,
+ NArcInfoFlags::kMultiSignature |
+ NArcInfoFlags::kFindSignature,
+ NULL)
+
+}
+
+namespace UEFIf {
+
+static const Byte k_FFS_Signatures[] =
+{
+ 16, FFS1_SIGNATURE,
+ 16, FFS2_SIGNATURE
+};
+
+
+REGISTER_ARC_I_CLS(
+ CHandler(false),
+ "UEFIf", "uefif", NULL, 0xD1,
+ k_FFS_Signatures,
+ kFfsGuidOffset,
+ NArcInfoFlags::kMultiSignature |
+ NArcInfoFlags::kFindSignature,
+ NULL)
+
+}
+
+}}
diff --git a/CPP/7zip/Archive/VdiHandler.cpp b/CPP/7zip/Archive/VdiHandler.cpp
new file mode 100644
index 0000000..a5a9332
--- /dev/null
+++ b/CPP/7zip/Archive/VdiHandler.cpp
@@ -0,0 +1,438 @@
+// VdiHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer.h"
+
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/PropVariantUtils.h"
+
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "HandlerCont.h"
+
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NVdi {
+
+static const Byte k_Signature[] = { 0x7F, 0x10, 0xDA, 0xBE };
+
+static const unsigned k_ClusterBits = 20;
+static const UInt32 k_ClusterSize = (UInt32)1 << k_ClusterBits;
+
+
+/*
+VDI_IMAGE_BLOCK_FREE = (~0) // returns any random data
+VDI_IMAGE_BLOCK_ZERO = (~1) // returns zeros
+*/
+
+// static const UInt32 k_ClusterType_Free = 0xffffffff;
+static const UInt32 k_ClusterType_Zero = 0xfffffffe;
+
+#define IS_CLUSTER_ALLOCATED(v) ((UInt32)(v) < k_ClusterType_Zero)
+
+
+// static const UInt32 kDiskType_Dynamic = 1;
+// static const UInt32 kDiskType_Static = 2;
+
+static const char * const kDiskTypes[] =
+{
+ "0"
+ , "Dynamic"
+ , "Static"
+ , "Undo"
+ , "Diff"
+};
+
+
+enum EGuidType
+{
+ k_GuidType_Creat,
+ k_GuidType_Modif,
+ k_GuidType_Link,
+ k_GuidType_PModif
+};
+
+static const unsigned kNumGuids = 4;
+static const char * const kGuidNames[kNumGuids] =
+{
+ "Creat "
+ , "Modif "
+ , "Link "
+ , "PModif"
+};
+
+static bool IsEmptyGuid(const Byte *data)
+{
+ for (unsigned i = 0; i < 16; i++)
+ if (data[i] != 0)
+ return false;
+ return true;
+}
+
+
+
+Z7_class_CHandler_final: public CHandlerImg
+{
+ UInt32 _dataOffset;
+ CByteBuffer _table;
+ UInt64 _phySize;
+ UInt32 _imageType;
+ bool _isArc;
+ bool _unsupported;
+
+ Byte Guids[kNumGuids][16];
+
+ HRESULT Seek2(UInt64 offset)
+ {
+ _posInArc = offset;
+ return InStream_SeekSet(Stream, offset);
+ }
+
+ HRESULT InitAndSeek()
+ {
+ _virtPos = 0;
+ return Seek2(0);
+ }
+
+ HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) Z7_override;
+
+public:
+ Z7_IFACE_COM7_IMP(IInArchive_Img)
+
+ Z7_IFACE_COM7_IMP(IInArchiveGetStream)
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+};
+
+
+Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (_virtPos >= _size)
+ return S_OK;
+ {
+ UInt64 rem = _size - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ if (size == 0)
+ return S_OK;
+ }
+
+ {
+ UInt64 cluster = _virtPos >> k_ClusterBits;
+ UInt32 lowBits = (UInt32)_virtPos & (k_ClusterSize - 1);
+ {
+ UInt32 rem = k_ClusterSize - lowBits;
+ if (size > rem)
+ size = rem;
+ }
+
+ cluster <<= 2;
+ if (cluster < _table.Size())
+ {
+ const Byte *p = (const Byte *)_table + (size_t)cluster;
+ const UInt32 v = Get32(p);
+ if (IS_CLUSTER_ALLOCATED(v))
+ {
+ UInt64 offset = _dataOffset + ((UInt64)v << k_ClusterBits);
+ offset += lowBits;
+ if (offset != _posInArc)
+ {
+ RINOK(Seek2(offset))
+ }
+ HRESULT res = Stream->Read(data, size, &size);
+ _posInArc += size;
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return res;
+ }
+ }
+
+ memset(data, 0, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ }
+}
+
+
+static const Byte kProps[] =
+{
+ kpidSize,
+ kpidPackSize
+};
+
+static const Byte kArcProps[] =
+{
+ kpidHeadersSize,
+ kpidMethod,
+ kpidComment,
+ kpidName
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ switch (propID)
+ {
+ case kpidMainSubfile: prop = (UInt32)0; break;
+ case kpidPhySize: if (_phySize != 0) prop = _phySize; break;
+ case kpidHeadersSize: prop = _dataOffset; break;
+
+ case kpidMethod:
+ {
+ TYPE_TO_PROP(kDiskTypes, _imageType, prop);
+ break;
+ }
+
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod;
+ // if (_headerError) v |= kpv_ErrorFlags_HeadersError;
+ if (!Stream && v == 0 && _isArc)
+ v = kpv_ErrorFlags_HeadersError;
+ if (v != 0)
+ prop = v;
+ break;
+ }
+
+ case kpidComment:
+ {
+ AString s;
+ for (unsigned i = 0; i < kNumGuids; i++)
+ {
+ const Byte *guid = Guids[i];
+ if (!IsEmptyGuid(guid))
+ {
+ s.Add_LF();
+ s += kGuidNames[i];
+ s += " : ";
+ char temp[64];
+ RawLeGuidToString_Braced(guid, temp);
+ MyStringLower_Ascii(temp);
+ s += temp;
+ }
+ }
+ if (!s.IsEmpty())
+ prop = s;
+ break;
+ }
+
+ case kpidName:
+ {
+ const Byte *guid = Guids[k_GuidType_Creat];
+ if (!IsEmptyGuid(guid))
+ {
+ char temp[64];
+ RawLeGuidToString_Braced(guid, temp);
+ MyStringLower_Ascii(temp);
+ MyStringCat(temp, ".vdi");
+ prop = temp;
+ }
+ break;
+ }
+ }
+
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ switch (propID)
+ {
+ case kpidSize: prop = _size; break;
+ case kpidPackSize: prop = _phySize - _dataOffset; break;
+ case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break;
+ }
+
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback * /* openCallback */)
+{
+ const unsigned kHeaderSize = 512;
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(stream, buf, kHeaderSize))
+
+ if (memcmp(buf + 0x40, k_Signature, sizeof(k_Signature)) != 0)
+ return S_FALSE;
+
+ const UInt32 version = Get32(buf + 0x44);
+ if (version >= 0x20000)
+ return S_FALSE;
+ if (version < 0x10000)
+ {
+ _unsupported = true;
+ return S_FALSE;
+ }
+
+ const unsigned kHeaderOffset = 0x48;
+ const unsigned kGuidsOffsets = 0x188;
+ const UInt32 headerSize = Get32(buf + kHeaderOffset);
+ if (headerSize < kGuidsOffsets - kHeaderOffset || headerSize > 0x200 - kHeaderOffset)
+ return S_FALSE;
+
+ _imageType = Get32(buf + 0x4C);
+ // Int32 flags = Get32(buf + 0x50);
+ // Byte Comment[0x100]
+
+ const UInt32 tableOffset = Get32(buf + 0x154);
+ if (tableOffset < 0x200)
+ return S_FALSE;
+
+ _dataOffset = Get32(buf + 0x158);
+
+ // UInt32 geometry[3];
+
+ const UInt32 sectorSize = Get32(buf + 0x168);
+ if (sectorSize != 0x200)
+ return S_FALSE;
+
+ _size = Get64(buf + 0x170);
+ const UInt32 blockSize = Get32(buf + 0x178);
+ const UInt32 totalBlocks = Get32(buf + 0x180);
+ const UInt32 numAllocatedBlocks = Get32(buf + 0x184);
+
+ _isArc = true;
+
+ if (_dataOffset < tableOffset)
+ return S_FALSE;
+
+ if (_imageType > 4)
+ _unsupported = true;
+
+ if (blockSize != k_ClusterSize)
+ {
+ _unsupported = true;
+ return S_FALSE;
+ }
+
+ if (headerSize >= kGuidsOffsets + kNumGuids * 16 - kHeaderOffset)
+ {
+ for (unsigned i = 0; i < kNumGuids; i++)
+ memcpy(Guids[i], buf + kGuidsOffsets + 16 * i, 16);
+
+ if (!IsEmptyGuid(Guids[k_GuidType_Link]) ||
+ !IsEmptyGuid(Guids[k_GuidType_PModif]))
+ _unsupported = true;
+ }
+
+ {
+ UInt64 size2 = (UInt64)totalBlocks << k_ClusterBits;
+ if (size2 < _size)
+ {
+ _unsupported = true;
+ return S_FALSE;
+ }
+ /*
+ if (size2 > _size)
+ _size = size2;
+ */
+ }
+
+ {
+ UInt32 tableReserved = _dataOffset - tableOffset;
+ if ((tableReserved >> 2) < totalBlocks)
+ return S_FALSE;
+ }
+
+ _phySize = _dataOffset + ((UInt64)numAllocatedBlocks << k_ClusterBits);
+
+ const size_t numBytes = (size_t)totalBlocks * 4;
+ if ((numBytes >> 2) != totalBlocks)
+ {
+ _unsupported = true;
+ return E_OUTOFMEMORY;
+ }
+
+ _table.Alloc(numBytes);
+ RINOK(InStream_SeekSet(stream, tableOffset))
+ RINOK(ReadStream_FALSE(stream, _table, numBytes))
+
+ const Byte *data = _table;
+ for (UInt32 i = 0; i < totalBlocks; i++)
+ {
+ const UInt32 v = Get32(data + (size_t)i * 4);
+ if (!IS_CLUSTER_ALLOCATED(v))
+ continue;
+ if (v >= numAllocatedBlocks)
+ {
+ _unsupported = true;
+ return S_FALSE;
+ }
+ }
+
+ Stream = stream;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _table.Free();
+ _phySize = 0;
+ _isArc = false;
+ _unsupported = false;
+
+ for (unsigned i = 0; i < kNumGuids; i++)
+ memset(Guids[i], 0, 16);
+
+ // CHandlerImg:
+ Clear_HandlerImg_Vars();
+ Stream.Release();
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ *stream = NULL;
+ if (_unsupported)
+ return S_FALSE;
+ CMyComPtr<ISequentialInStream> streamTemp = this;
+ RINOK(InitAndSeek())
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+
+REGISTER_ARC_I(
+ "VDI", "vdi", NULL, 0xC9,
+ k_Signature,
+ 0x40,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/VhdHandler.cpp b/CPP/7zip/Archive/VhdHandler.cpp
new file mode 100644
index 0000000..e5bf997
--- /dev/null
+++ b/CPP/7zip/Archive/VhdHandler.cpp
@@ -0,0 +1,977 @@
+// VhdHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "HandlerCont.h"
+
+#define Get16(p) GetBe16(p)
+#define Get32(p) GetBe32(p)
+#define Get64(p) GetBe64(p)
+
+#define G32(_offs_, dest) dest = Get32(p + (_offs_))
+#define G64(_offs_, dest) dest = Get64(p + (_offs_))
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NVhd {
+
+static const unsigned kSignatureSize = 10;
+static const Byte kSignature[kSignatureSize] =
+ { 'c', 'o', 'n', 'e', 'c', 't', 'i', 'x', 0, 0 };
+
+static const UInt32 kUnusedBlock = 0xFFFFFFFF;
+
+static const UInt32 kDiskType_Fixed = 2;
+static const UInt32 kDiskType_Dynamic = 3;
+static const UInt32 kDiskType_Diff = 4;
+
+static const char * const kDiskTypes[] =
+{
+ "0"
+ , "1"
+ , "Fixed"
+ , "Dynamic"
+ , "Differencing"
+};
+
+struct CFooter
+{
+ // UInt32 Features;
+ // UInt32 FormatVersion;
+ UInt64 DataOffset;
+ UInt32 CTime;
+ UInt32 CreatorApp;
+ UInt32 CreatorVersion;
+ UInt32 CreatorHostOS;
+ // UInt64 OriginalSize;
+ UInt64 CurrentSize;
+ UInt32 DiskGeometry;
+ UInt32 Type;
+ Byte Id[16];
+ Byte SavedState;
+
+ bool IsFixed() const { return Type == kDiskType_Fixed; }
+ bool ThereIsDynamic() const { return Type == kDiskType_Dynamic || Type == kDiskType_Diff; }
+ // bool IsSupported() const { return Type == kDiskType_Fixed || Type == kDiskType_Dynamic || Type == kDiskType_Diff; }
+ UInt32 NumCyls() const { return DiskGeometry >> 16; }
+ UInt32 NumHeads() const { return (DiskGeometry >> 8) & 0xFF; }
+ UInt32 NumSectorsPerTrack() const { return DiskGeometry & 0xFF; }
+ void AddTypeString(AString &s) const;
+ bool Parse(const Byte *p);
+};
+
+void CFooter::AddTypeString(AString &s) const
+{
+ if (Type < Z7_ARRAY_SIZE(kDiskTypes))
+ s += kDiskTypes[Type];
+ else
+ s.Add_UInt32(Type);
+}
+
+static bool CheckBlock(const Byte *p, unsigned size, unsigned checkSumOffset, unsigned zeroOffset)
+{
+ UInt32 sum = 0;
+ unsigned i;
+ for (i = 0; i < checkSumOffset; i++)
+ sum += p[i];
+ for (i = checkSumOffset + 4; i < size; i++)
+ sum += p[i];
+ if (~sum != Get32(p + checkSumOffset))
+ return false;
+ for (i = zeroOffset; i < size; i++)
+ if (p[i] != 0)
+ return false;
+ return true;
+}
+
+static const unsigned kSectorSize_Log = 9;
+static const unsigned kSectorSize = 1 << kSectorSize_Log;
+static const unsigned kHeaderSize = 512;
+
+bool CFooter::Parse(const Byte *p)
+{
+ if (memcmp(p, kSignature, kSignatureSize) != 0)
+ return false;
+ // G32(0x08, Features);
+ // G32(0x0C, FormatVersion);
+ G64(0x10, DataOffset);
+ G32(0x18, CTime);
+ G32(0x1C, CreatorApp);
+ G32(0x20, CreatorVersion);
+ G32(0x24, CreatorHostOS);
+ // G64(0x28, OriginalSize);
+ G64(0x30, CurrentSize);
+ G32(0x38, DiskGeometry);
+ G32(0x3C, Type);
+ if (Type < kDiskType_Fixed ||
+ Type > kDiskType_Diff)
+ return false;
+ memcpy(Id, p + 0x44, 16);
+ SavedState = p[0x54];
+ // if (DataOffset > ((UInt64)1 << 62)) return false;
+ // if (CurrentSize > ((UInt64)1 << 62)) return false;
+ return CheckBlock(p, kHeaderSize, 0x40, 0x55);
+}
+
+struct CParentLocatorEntry
+{
+ UInt32 Code;
+ UInt32 DataSpace;
+ UInt32 DataLen;
+ UInt64 DataOffset;
+
+ bool Parse(const Byte *p)
+ {
+ G32(0x00, Code);
+ G32(0x04, DataSpace);
+ G32(0x08, DataLen);
+ G64(0x10, DataOffset);
+ return Get32(p + 0x0C) == 0; // Reserved
+ }
+};
+
+struct CDynHeader
+{
+ // UInt64 DataOffset;
+ UInt64 TableOffset;
+ // UInt32 HeaderVersion;
+ UInt32 NumBlocks;
+ unsigned BlockSizeLog;
+ UInt32 ParentTime;
+ Byte ParentId[16];
+ bool RelativeNameWasUsed;
+ UString ParentName;
+ UString RelativeParentNameFromLocator;
+ CParentLocatorEntry ParentLocators[8];
+
+ bool Parse(const Byte *p);
+ UInt32 NumBitMapSectors() const
+ {
+ UInt32 numSectorsInBlock = (1 << (BlockSizeLog - kSectorSize_Log));
+ return (numSectorsInBlock + kSectorSize * 8 - 1) / (kSectorSize * 8);
+ }
+ void Clear()
+ {
+ RelativeNameWasUsed = false;
+ ParentName.Empty();
+ RelativeParentNameFromLocator.Empty();
+ }
+};
+
+bool CDynHeader::Parse(const Byte *p)
+{
+ if (memcmp(p, "cxsparse", 8) != 0)
+ return false;
+ // G64(0x08, DataOffset);
+ G64(0x10, TableOffset);
+ // G32(0x18, HeaderVersion);
+ G32(0x1C, NumBlocks);
+ {
+ UInt32 blockSize = Get32(p + 0x20);
+ unsigned i;
+ for (i = kSectorSize_Log;; i++)
+ {
+ if (i > 31)
+ return false;
+ if (((UInt32)1 << i) == blockSize)
+ break;
+ }
+ BlockSizeLog = i;
+ }
+ G32(0x38, ParentTime);
+ if (Get32(p + 0x3C) != 0) // reserved
+ return false;
+ memcpy(ParentId, p + 0x28, 16);
+ {
+ const unsigned kNameLen = 256;
+ wchar_t *s = ParentName.GetBuf(kNameLen);
+ unsigned i;
+ for (i = 0; i < kNameLen; i++)
+ {
+ wchar_t c = Get16(p + 0x40 + i * 2);
+ if (c == 0)
+ break;
+ s[i] = c;
+ }
+ s[i] = 0;
+ ParentName.ReleaseBuf_SetLen(i);
+ }
+ for (unsigned i = 0; i < 8; i++)
+ if (!ParentLocators[i].Parse(p + 0x240 + i * 24))
+ return false;
+ return CheckBlock(p, 1024, 0x24, 0x240 + 8 * 24);
+}
+
+Z7_class_CHandler_final: public CHandlerImg
+{
+ UInt64 _posInArcLimit;
+ UInt64 _startOffset;
+ UInt64 _phySize;
+
+ CFooter Footer;
+ CDynHeader Dyn;
+ CRecordVector<UInt32> Bat;
+ CByteBuffer BitMap;
+ UInt32 BitMapTag;
+ UInt32 NumUsedBlocks;
+ CMyComPtr<IInStream> ParentStream;
+ CHandler *Parent;
+ UInt64 NumLevels;
+ UString _errorMessage;
+ // bool _unexpectedEnd;
+
+ void AddErrorMessage(const char *message, const wchar_t *name = NULL)
+ {
+ if (!_errorMessage.IsEmpty())
+ _errorMessage.Add_LF();
+ _errorMessage += message;
+ if (name)
+ _errorMessage += name;
+ }
+
+ void UpdatePhySize(UInt64 value)
+ {
+ if (_phySize < value)
+ _phySize = value;
+ }
+
+ HRESULT Seek2(UInt64 offset);
+ HRESULT InitAndSeek();
+ HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size);
+
+ bool NeedParent() const { return Footer.Type == kDiskType_Diff; }
+ UInt64 GetPackSize() const
+ { return Footer.ThereIsDynamic() ? ((UInt64)NumUsedBlocks << Dyn.BlockSizeLog) : Footer.CurrentSize; }
+
+ UString GetParentSequence() const
+ {
+ const CHandler *p = this;
+ UString res;
+ while (p && p->NeedParent())
+ {
+ if (!res.IsEmpty())
+ res += " -> ";
+ UString mainName;
+ UString anotherName;
+ if (Dyn.RelativeNameWasUsed)
+ {
+ mainName = p->Dyn.RelativeParentNameFromLocator;
+ anotherName = p->Dyn.ParentName;
+ }
+ else
+ {
+ mainName = p->Dyn.ParentName;
+ anotherName = p->Dyn.RelativeParentNameFromLocator;
+ }
+ res += mainName;
+ if (mainName != anotherName && !anotherName.IsEmpty())
+ {
+ res.Add_Space();
+ res += '(';
+ res += anotherName;
+ res += ')';
+ }
+ p = p->Parent;
+ }
+ return res;
+ }
+
+ bool AreParentsOK() const
+ {
+ const CHandler *p = this;
+ while (p->NeedParent())
+ {
+ p = p->Parent;
+ if (!p)
+ return false;
+ }
+ return true;
+ }
+
+ HRESULT Open3();
+ HRESULT Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, unsigned level);
+ HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback) Z7_override
+ {
+ return Open2(stream, NULL, openArchiveCallback, 0);
+ }
+ void CloseAtError() Z7_override;
+
+public:
+ Z7_IFACE_COM7_IMP(IInArchive_Img)
+
+ Z7_IFACE_COM7_IMP(IInArchiveGetStream)
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+};
+
+HRESULT CHandler::Seek2(UInt64 offset) { return InStream_SeekSet(Stream, _startOffset + offset); }
+
+HRESULT CHandler::InitAndSeek()
+{
+ if (ParentStream)
+ {
+ RINOK(Parent->InitAndSeek())
+ }
+ _virtPos = _posInArc = 0;
+ BitMapTag = kUnusedBlock;
+ BitMap.Alloc(Dyn.NumBitMapSectors() << kSectorSize_Log);
+ return Seek2(0);
+}
+
+HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size)
+{
+ if (offset + size > _posInArcLimit)
+ return S_FALSE;
+ if (offset != _posInArc)
+ {
+ _posInArc = offset;
+ RINOK(Seek2(offset))
+ }
+ HRESULT res = ReadStream_FALSE(Stream, data, size);
+ if (res == S_OK)
+ _posInArc += size;
+ else
+ Reset_PosInArc();
+ return res;
+}
+
+HRESULT CHandler::Open3()
+{
+ // Fixed archive uses only footer
+
+ UInt64 startPos;
+ RINOK(InStream_GetPos(Stream, startPos))
+ _startOffset = startPos;
+ Byte header[kHeaderSize];
+ RINOK(ReadStream_FALSE(Stream, header, kHeaderSize))
+ bool headerIsOK = Footer.Parse(header);
+ _size = Footer.CurrentSize;
+
+ if (headerIsOK && !Footer.ThereIsDynamic())
+ {
+ // fixed archive
+ if (startPos < Footer.CurrentSize)
+ return S_FALSE;
+ _posInArcLimit = Footer.CurrentSize;
+ _phySize = Footer.CurrentSize + kHeaderSize;
+ _startOffset = startPos - Footer.CurrentSize;
+ _posInArc = _phySize;
+ return S_OK;
+ }
+
+ UInt64 fileSize;
+ RINOK(InStream_GetSize_SeekToEnd(Stream, fileSize))
+ if (fileSize < kHeaderSize)
+ return S_FALSE;
+
+ const UInt32 kDynSize = 1024;
+ Byte buf[kDynSize];
+
+ RINOK(InStream_SeekSet(Stream, fileSize - kHeaderSize))
+ RINOK(ReadStream_FALSE(Stream, buf, kHeaderSize))
+
+ if (!headerIsOK)
+ {
+ if (!Footer.Parse(buf))
+ return S_FALSE;
+ _size = Footer.CurrentSize;
+ if (Footer.ThereIsDynamic())
+ return S_FALSE; // we can't open Dynamic Archive backward.
+ // fixed archive
+ _posInArcLimit = Footer.CurrentSize;
+ _phySize = Footer.CurrentSize + kHeaderSize;
+ _startOffset = fileSize - kHeaderSize - Footer.CurrentSize;
+ _posInArc = _phySize;
+ return S_OK;
+ }
+
+ _phySize = kHeaderSize;
+ _posInArc = fileSize - startPos;
+ _posInArcLimit = _posInArc - kHeaderSize;
+
+ bool headerAndFooterAreEqual = false;
+ if (memcmp(header, buf, kHeaderSize) == 0)
+ {
+ headerAndFooterAreEqual = true;
+ _phySize = fileSize - _startOffset;
+ }
+
+ RINOK(ReadPhy(Footer.DataOffset, buf, kDynSize))
+ if (!Dyn.Parse(buf))
+ return S_FALSE;
+
+ UpdatePhySize(Footer.DataOffset + kDynSize);
+
+ for (int i = 0; i < 8; i++)
+ {
+ const CParentLocatorEntry &locator = Dyn.ParentLocators[i];
+ const UInt32 kNameBufSizeMax = 1024;
+ if (locator.DataLen < kNameBufSizeMax &&
+ locator.DataOffset < _posInArcLimit &&
+ locator.DataOffset + locator.DataLen <= _posInArcLimit)
+ {
+ if (locator.Code == 0x57327275 && (locator.DataLen & 1) == 0)
+ {
+ // "W2ru" locator
+ // Path is encoded as little-endian UTF-16
+ Byte nameBuf[kNameBufSizeMax];
+ UString tempString;
+ unsigned len = (locator.DataLen >> 1);
+ {
+ wchar_t *s = tempString.GetBuf(len);
+ RINOK(ReadPhy(locator.DataOffset, nameBuf, locator.DataLen))
+ unsigned j;
+ for (j = 0; j < len; j++)
+ {
+ wchar_t c = GetUi16(nameBuf + j * 2);
+ if (c == 0)
+ break;
+ s[j] = c;
+ }
+ s[j] = 0;
+ tempString.ReleaseBuf_SetLen(j);
+ }
+ if (tempString[0] == L'.' && tempString[1] == L'\\')
+ tempString.DeleteFrontal(2);
+ Dyn.RelativeParentNameFromLocator = tempString;
+ }
+ }
+ if (locator.DataLen != 0)
+ UpdatePhySize(locator.DataOffset + locator.DataLen);
+ }
+
+ if (Dyn.NumBlocks >= (UInt32)1 << 31)
+ return S_FALSE;
+ if (Footer.CurrentSize == 0)
+ {
+ if (Dyn.NumBlocks != 0)
+ return S_FALSE;
+ }
+ else if (((Footer.CurrentSize - 1) >> Dyn.BlockSizeLog) + 1 != Dyn.NumBlocks)
+ return S_FALSE;
+
+ Bat.ClearAndReserve(Dyn.NumBlocks);
+
+ UInt32 bitmapSize = Dyn.NumBitMapSectors() << kSectorSize_Log;
+
+ while ((UInt32)Bat.Size() < Dyn.NumBlocks)
+ {
+ RINOK(ReadPhy(Dyn.TableOffset + (UInt64)Bat.Size() * 4, buf, kSectorSize))
+ UpdatePhySize(Dyn.TableOffset + kSectorSize);
+ for (UInt32 j = 0; j < kSectorSize; j += 4)
+ {
+ UInt32 v = Get32(buf + j);
+ if (v != kUnusedBlock)
+ {
+ UInt32 blockSize = (UInt32)1 << Dyn.BlockSizeLog;
+ UpdatePhySize(((UInt64)v << kSectorSize_Log) + bitmapSize + blockSize);
+ NumUsedBlocks++;
+ }
+ Bat.AddInReserved(v);
+ if ((UInt32)Bat.Size() >= Dyn.NumBlocks)
+ break;
+ }
+ }
+
+ if (headerAndFooterAreEqual)
+ return S_OK;
+
+ if (_startOffset + _phySize + kHeaderSize > fileSize)
+ {
+ // _unexpectedEnd = true;
+ _posInArcLimit = _phySize;
+ _phySize += kHeaderSize;
+ return S_OK;
+ }
+
+ RINOK(ReadPhy(_phySize, buf, kHeaderSize))
+ if (memcmp(header, buf, kHeaderSize) == 0)
+ {
+ _posInArcLimit = _phySize;
+ _phySize += kHeaderSize;
+ return S_OK;
+ }
+
+ if (_phySize == 0x800)
+ {
+ /* WHY does empty archive contain additional empty sector?
+ We skip that sector and check footer again. */
+ unsigned i;
+ for (i = 0; i < kSectorSize && buf[i] == 0; i++);
+ if (i == kSectorSize)
+ {
+ RINOK(ReadPhy(_phySize + kSectorSize, buf, kHeaderSize))
+ if (memcmp(header, buf, kHeaderSize) == 0)
+ {
+ _phySize += kSectorSize;
+ _posInArcLimit = _phySize;
+ _phySize += kHeaderSize;
+ return S_OK;
+ }
+ }
+ }
+ _posInArcLimit = _phySize;
+ _phySize += kHeaderSize;
+ AddErrorMessage("Can't find footer");
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (_virtPos >= Footer.CurrentSize)
+ return S_OK;
+ {
+ const UInt64 rem = Footer.CurrentSize - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+ if (size == 0)
+ return S_OK;
+
+ if (Footer.IsFixed())
+ {
+ if (_virtPos > _posInArcLimit)
+ return S_FALSE;
+ {
+ const UInt64 rem = _posInArcLimit - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+ HRESULT res = S_OK;
+ if (_virtPos != _posInArc)
+ {
+ _posInArc = _virtPos;
+ res = Seek2(_virtPos);
+ }
+ if (res == S_OK)
+ {
+ UInt32 processedSize2 = 0;
+ res = Stream->Read(data, size, &processedSize2);
+ if (processedSize)
+ *processedSize = processedSize2;
+ _posInArc += processedSize2;
+ }
+ if (res != S_OK)
+ Reset_PosInArc();
+ return res;
+ }
+
+ const UInt32 blockIndex = (UInt32)(_virtPos >> Dyn.BlockSizeLog);
+ if (blockIndex >= Bat.Size())
+ return E_FAIL; // it's some unexpected case
+ const UInt32 blockSectIndex = Bat[blockIndex];
+ const UInt32 blockSize = (UInt32)1 << Dyn.BlockSizeLog;
+ UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
+ size = MyMin(blockSize - offsetInBlock, size);
+
+ HRESULT res = S_OK;
+ if (blockSectIndex == kUnusedBlock)
+ {
+ if (ParentStream)
+ {
+ RINOK(InStream_SeekSet(ParentStream, _virtPos))
+ res = ParentStream->Read(data, size, &size);
+ }
+ else
+ memset(data, 0, size);
+ }
+ else
+ {
+ const UInt64 newPos = (UInt64)blockSectIndex << kSectorSize_Log;
+ if (BitMapTag != blockIndex)
+ {
+ RINOK(ReadPhy(newPos, BitMap, (UInt32)BitMap.Size()))
+ BitMapTag = blockIndex;
+ }
+ RINOK(ReadPhy(newPos + BitMap.Size() + offsetInBlock, data, size))
+ for (UInt32 cur = 0; cur < size;)
+ {
+ const UInt32 rem = MyMin(0x200 - (offsetInBlock & 0x1FF), size - cur);
+ const UInt32 bmi = offsetInBlock >> kSectorSize_Log;
+ if (((BitMap[bmi >> 3] >> (7 - (bmi & 7))) & 1) == 0)
+ {
+ if (ParentStream)
+ {
+ RINOK(InStream_SeekSet(ParentStream, _virtPos + cur))
+ RINOK(ReadStream_FALSE(ParentStream, (Byte *)data + cur, rem))
+ }
+ else
+ {
+ const Byte *p = (const Byte *)data + cur;
+ for (UInt32 i = 0; i < rem; i++)
+ if (p[i] != 0)
+ return S_FALSE;
+ }
+ }
+ offsetInBlock += rem;
+ cur += rem;
+ }
+ }
+ if (processedSize)
+ *processedSize = size;
+ _virtPos += size;
+ return res;
+}
+
+
+enum
+{
+ kpidParent = kpidUserDefined,
+ kpidSavedState
+};
+
+static const CStatProp kArcProps[] =
+{
+ { NULL, kpidOffset, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidClusterSize, VT_UI8},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidNumVolumes, VT_UI4},
+ { NULL, kpidTotalPhySize, VT_UI8},
+ { "Parent", kpidParent, VT_BSTR},
+ { NULL, kpidCreatorApp, VT_BSTR},
+ { NULL, kpidHostOS, VT_BSTR},
+ { "Saved State", kpidSavedState, VT_BOOL},
+ { NULL, kpidId, VT_BSTR}
+ };
+
+static const Byte kProps[] =
+{
+ kpidSize,
+ kpidPackSize,
+ kpidCTime
+
+ /*
+ { kpidNumCyls, VT_UI4},
+ { kpidNumHeads, VT_UI4},
+ { kpidSectorsPerTrack, VT_UI4}
+ */
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_WITH_NAME
+
+// VHD start time: 2000-01-01
+static const UInt64 kVhdTimeStartValue = (UInt64)3600 * 24 * (399 * 365 + 24 * 4);
+
+static void VhdTimeToFileTime(UInt32 vhdTime, NCOM::CPropVariant &prop)
+{
+ FILETIME ft, utc;
+ UInt64 v = (kVhdTimeStartValue + vhdTime) * 10000000;
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+ // specification says that it's UTC time, but Virtual PC 6 writes local time. Why?
+ LocalFileTimeToFileTime(&ft, &utc);
+ prop = utc;
+}
+
+static void StringToAString(char *dest, UInt32 val)
+{
+ for (int i = 24; i >= 0; i -= 8)
+ {
+ const Byte b = (Byte)((val >> i) & 0xFF);
+ if (b < 0x20 || b > 0x7F)
+ break;
+ *dest++ = (char)b;
+ }
+ *dest = 0;
+}
+
+static void ConvertByteToHex(unsigned value, char *s)
+{
+ for (int i = 0; i < 2; i++)
+ {
+ unsigned t = value & 0xF;
+ value >>= 4;
+ s[1 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
+ }
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidMainSubfile: prop = (UInt32)0; break;
+ case kpidCTime: VhdTimeToFileTime(Footer.CTime, prop); break;
+ case kpidClusterSize: if (Footer.ThereIsDynamic()) prop = (UInt32)1 << Dyn.BlockSizeLog; break;
+ case kpidShortComment:
+ case kpidMethod:
+ {
+ AString s;
+ Footer.AddTypeString(s);
+ if (NeedParent())
+ {
+ s += " -> ";
+ const CHandler *p = this;
+ while (p && p->NeedParent())
+ p = p->Parent;
+ if (!p)
+ s += '?';
+ else
+ p->Footer.AddTypeString(s);
+ }
+ prop = s;
+ break;
+ }
+ case kpidCreatorApp:
+ {
+ char s[16];
+ StringToAString(s, Footer.CreatorApp);
+ AString res (s);
+ res.Trim();
+ res.Add_Space();
+ res.Add_UInt32(Footer.CreatorVersion >> 16);
+ res.Add_Dot();
+ res.Add_UInt32(Footer.CreatorVersion & 0xFFFF);
+ prop = res;
+ break;
+ }
+ case kpidHostOS:
+ {
+ if (Footer.CreatorHostOS == 0x5769326B)
+ prop = "Windows";
+ else
+ {
+ char s[16];
+ StringToAString(s, Footer.CreatorHostOS);
+ prop = s;
+ }
+ break;
+ }
+ case kpidId:
+ {
+ char s[32 + 4];
+ for (int i = 0; i < 16; i++)
+ ConvertByteToHex(Footer.Id[i], s + i * 2);
+ s[32] = 0;
+ prop = s;
+ break;
+ }
+ case kpidSavedState: prop = Footer.SavedState ? true : false; break;
+ case kpidParent: if (NeedParent()) prop = GetParentSequence(); break;
+ case kpidOffset: prop = _startOffset; break;
+ case kpidPhySize: prop = _phySize; break;
+ case kpidTotalPhySize:
+ {
+ const CHandler *p = this;
+ UInt64 sum = 0;
+ do
+ {
+ sum += p->_phySize;
+ p = p->Parent;
+ }
+ while (p);
+ prop = sum;
+ break;
+ }
+ case kpidNumVolumes: if (NumLevels != 1) prop = (UInt32)NumLevels; break;
+
+ /*
+ case kpidErrorFlags:
+ {
+ UInt32 flags = 0;
+ if (_unexpectedEnd)
+ flags |= kpv_ErrorFlags_UnexpectedEndOfArc;
+ if (flags != 0)
+ prop = flags;
+ break;
+ }
+ */
+ case kpidError: if (!_errorMessage.IsEmpty()) prop = _errorMessage; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+HRESULT CHandler::Open2(IInStream *stream, CHandler *child, IArchiveOpenCallback *openArchiveCallback, unsigned level)
+{
+ Close();
+ Stream = stream;
+ if (level > (1 << 12)) // Maybe we need to increase that limit
+ return S_FALSE;
+
+ RINOK(Open3())
+
+ NumLevels = 1;
+ if (child && memcmp(child->Dyn.ParentId, Footer.Id, 16) != 0)
+ return S_FALSE;
+ if (Footer.Type != kDiskType_Diff)
+ return S_OK;
+
+ bool useRelative;
+ UString name;
+
+ if (!Dyn.RelativeParentNameFromLocator.IsEmpty())
+ {
+ useRelative = true;
+ name = Dyn.RelativeParentNameFromLocator;
+ }
+ else
+ {
+ useRelative = false;
+ name = Dyn.ParentName;
+ }
+
+ Dyn.RelativeNameWasUsed = useRelative;
+
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IArchiveOpenVolumeCallback,
+ openVolumeCallback, openArchiveCallback)
+
+ if (openVolumeCallback)
+ {
+ CMyComPtr<IInStream> nextStream;
+ HRESULT res = openVolumeCallback->GetStream(name, &nextStream);
+
+ if (res == S_FALSE)
+ {
+ if (useRelative && Dyn.ParentName != Dyn.RelativeParentNameFromLocator)
+ {
+ res = openVolumeCallback->GetStream(Dyn.ParentName, &nextStream);
+ if (res == S_OK)
+ Dyn.RelativeNameWasUsed = false;
+ }
+ }
+
+ if (res != S_OK && res != S_FALSE)
+ return res;
+
+ if (res == S_FALSE || !nextStream)
+ {
+ AddErrorMessage("Missing volume : ", name);
+ return S_OK;
+ }
+
+ Parent = new CHandler;
+ ParentStream = Parent;
+
+ res = Parent->Open2(nextStream, this, openArchiveCallback, level + 1);
+
+ if (res != S_OK)
+ {
+ Parent = NULL;
+ ParentStream.Release();
+ if (res == E_ABORT)
+ return res;
+ if (res != S_FALSE)
+ {
+ // we must show that error code
+ }
+ }
+ if (res == S_OK)
+ {
+ NumLevels = Parent->NumLevels + 1;
+ }
+ }
+ {
+ const CHandler *p = this;
+ while (p->NeedParent())
+ {
+ p = p->Parent;
+ if (!p)
+ {
+ AddErrorMessage("Can't open parent VHD file : ", Dyn.ParentName);
+ break;
+ }
+ }
+ }
+ return S_OK;
+}
+
+
+void CHandler::CloseAtError()
+{
+ // CHandlerImg:
+ Stream.Release();
+ Clear_HandlerImg_Vars();
+
+ _phySize = 0;
+ NumLevels = 0;
+ Bat.Clear();
+ NumUsedBlocks = 0;
+ Parent = NULL;
+ ParentStream.Release();
+ Dyn.Clear();
+ _errorMessage.Empty();
+ // _unexpectedEnd = false;
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ CloseAtError();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ switch (propID)
+ {
+ case kpidSize: prop = Footer.CurrentSize; break;
+ case kpidPackSize: prop = GetPackSize(); break;
+ case kpidCTime: VhdTimeToFileTime(Footer.CTime, prop); break;
+ case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break;
+
+ /*
+ case kpidNumCyls: prop = Footer.NumCyls(); break;
+ case kpidNumHeads: prop = Footer.NumHeads(); break;
+ case kpidSectorsPerTrack: prop = Footer.NumSectorsPerTrack(); break;
+ */
+ }
+
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ *stream = NULL;
+ if (Footer.IsFixed())
+ {
+ CLimitedInStream *streamSpec = new CLimitedInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->SetStream(Stream);
+ // fixme : check (startOffset = 0)
+ streamSpec->InitAndSeek(_startOffset, Footer.CurrentSize);
+ RINOK(streamSpec->SeekToStart())
+ *stream = streamTemp.Detach();
+ return S_OK;
+ }
+ if (!Footer.ThereIsDynamic() || !AreParentsOK())
+ return S_FALSE;
+ CMyComPtr<ISequentialInStream> streamTemp = this;
+ RINOK(InitAndSeek())
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+REGISTER_ARC_I(
+ "VHD", "vhd", NULL, 0xDC,
+ kSignature,
+ 0,
+ NArcInfoFlags::kUseGlobalOffset,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/VhdxHandler.cpp b/CPP/7zip/Archive/VhdxHandler.cpp
new file mode 100644
index 0000000..e3ddedd
--- /dev/null
+++ b/CPP/7zip/Archive/VhdxHandler.cpp
@@ -0,0 +1,2097 @@
+// VhdxHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/MyBuffer.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "HandlerCont.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+#define G32(_offs_, dest) dest = Get32(p + (_offs_))
+#define G64(_offs_, dest) dest = Get64(p + (_offs_))
+
+using namespace NWindows;
+
+
+EXTERN_C_BEGIN
+
+// CRC-32C (Castagnoli) : reversed for poly 0x1EDC6F41
+#define k_Crc32c_Poly 0x82f63b78
+
+static UInt32 g_Crc32c_Table[256];
+
+static void Z7_FASTCALL Crc32c_GenerateTable()
+{
+ UInt32 i;
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ unsigned j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (k_Crc32c_Poly & ((UInt32)0 - (r & 1)));
+ g_Crc32c_Table[i] = r;
+ }
+}
+
+
+#define CRC32C_INIT_VAL 0xFFFFFFFF
+
+#define CRC_UPDATE_BYTE_2(crc, b) (table[((crc) ^ (b)) & 0xFF] ^ ((crc) >> 8))
+
+// UInt32 Z7_FASTCALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table);
+static UInt32 Z7_FASTCALL CrcUpdateT1_vhdx(UInt32 v, const void *data, size_t size, const UInt32 *table)
+{
+ const Byte *p = (const Byte *)data;
+ const Byte *pEnd = p + size;
+ for (; p != pEnd; p++)
+ v = CRC_UPDATE_BYTE_2(v, *p);
+ return v;
+}
+
+static UInt32 Z7_FASTCALL Crc32c_Calc(const void *data, size_t size)
+{
+ return CrcUpdateT1_vhdx(CRC32C_INIT_VAL, data, size, g_Crc32c_Table) ^ CRC32C_INIT_VAL;
+}
+
+EXTERN_C_END
+
+
+namespace NArchive {
+namespace NVhdx {
+
+static struct C_CRC32c_TableInit { C_CRC32c_TableInit() { Crc32c_GenerateTable(); } } g_CRC32c_TableInit;
+
+static const unsigned kSignatureSize = 8;
+static const Byte kSignature[kSignatureSize] =
+ { 'v', 'h', 'd', 'x', 'f', 'i', 'l', 'e' };
+
+static const unsigned kBitmapSize_Log = 20;
+static const size_t kBitmapSize = (size_t)1 << kBitmapSize_Log;
+
+
+static bool IsZeroArr(const Byte *p, size_t size)
+{
+ for (size_t i = 0; i < size; i++)
+ if (p[i] != 0)
+ return false;
+ return true;
+}
+
+
+#define ValToHex(t) ((char)(((t) < 10) ? ('0' + (t)) : ('a' + ((t) - 10))))
+
+static void AddByteToHex2(unsigned val, UString &s)
+{
+ unsigned t;
+ t = val >> 4;
+ s += ValToHex(t);
+ t = val & 0xF;
+ s += ValToHex(t);
+}
+
+
+static int HexToVal(const wchar_t c)
+{
+ if (c >= '0' && c <= '9') return c - '0';
+ if (c >= 'a' && c <= 'z') return c - 'a' + 10;
+ if (c >= 'A' && c <= 'Z') return c - 'A' + 10;
+ return -1;
+}
+
+static int DecodeFrom2HexChars(const wchar_t *s)
+{
+ const int v0 = HexToVal(s[0]); if (v0 < 0) return -1;
+ const int v1 = HexToVal(s[1]); if (v1 < 0) return -1;
+ return (int)(((unsigned)v0 << 4) | (unsigned)v1);
+}
+
+
+struct CGuid
+{
+ Byte Data[16];
+
+ bool IsZero() const { return IsZeroArr(Data, 16); }
+ bool IsEqualTo(const Byte *a) const { return memcmp(Data, a, 16) == 0; }
+ bool IsEqualTo(const CGuid &g) const { return IsEqualTo(g.Data); }
+ void AddHexToString(UString &s) const;
+
+ void SetFrom(const Byte *p) { memcpy(Data, p, 16); }
+
+ bool ParseFromFormatedHexString(const UString &s)
+ {
+ const unsigned kLen = 16 * 2 + 4 + 2;
+ if (s.Len() != kLen || s[0] != '{' || s[kLen - 1] != '}')
+ return false;
+ unsigned pos = 0;
+ for (unsigned i = 1; i < kLen - 1;)
+ {
+ if (i == 9 || i == 14 || i == 19 || i == 24)
+ {
+ if (s[i] != '-')
+ return false;
+ i++;
+ continue;
+ }
+ const int v = DecodeFrom2HexChars(s.Ptr(i));
+ if (v < 0)
+ return false;
+ unsigned pos2 = pos;
+ if (pos < 8)
+ pos2 ^= (pos < 4 ? 3 : 1);
+ Data[pos2] = (Byte)v;
+ pos++;
+ i += 2;
+ }
+ return true; // pos == 16;
+ }
+};
+
+void CGuid::AddHexToString(UString &s) const
+{
+ for (unsigned i = 0; i < 16; i++)
+ AddByteToHex2(Data[i], s);
+}
+
+
+#define IS_NON_ALIGNED(v) (((v) & 0xFFFFF) != 0)
+
+static const unsigned kHeader_GUID_Index_FileWriteGuid = 0;
+static const unsigned kHeader_GUID_Index_DataWriteGuid = 1;
+static const unsigned kHeader_GUID_Index_LogGuid = 2;
+
+struct CHeader
+{
+ UInt64 SequenceNumber;
+ // UInt16 LogVersion;
+ // UInt16 Version;
+ UInt32 LogLength;
+ UInt64 LogOffset;
+ CGuid Guids[3];
+
+ bool IsEqualTo(const CHeader &h) const
+ {
+ if (SequenceNumber != h.SequenceNumber)
+ return false;
+ if (LogLength != h.LogLength)
+ return false;
+ if (LogOffset != h.LogOffset)
+ return false;
+ for (unsigned i = 0; i < 3; i++)
+ if (!Guids[i].IsEqualTo(h.Guids[i]))
+ return false;
+ return true;
+ }
+
+ bool Parse(Byte *p);
+};
+
+static const unsigned kHeader2Size = 1 << 12;
+
+bool CHeader::Parse(Byte *p)
+{
+ if (Get32(p) != 0x64616568) // "head"
+ return false;
+ const UInt32 crc = Get32(p + 4);
+ SetUi32(p + 4, 0)
+ if (Crc32c_Calc(p, kHeader2Size) != crc)
+ return false;
+ G64(8, SequenceNumber);
+ for (unsigned i = 0; i < 3; i++)
+ Guids[i].SetFrom(p + 0x10 + 0x10 * i);
+ // LogVersion = Get16(p + 0x40);
+ /* LogVersion MUST be set to zero, for known log format
+ but we don't parse log so we ignore it */
+ G32(0x44, LogLength);
+ G64(0x48, LogOffset);
+ if (Get16(p + 0x42) != 1) // Header format Version
+ return false;
+ if (IS_NON_ALIGNED(LogLength))
+ return false;
+ if (IS_NON_ALIGNED(LogOffset))
+ return false;
+ return true;
+ // return IsZeroArr(p + 0x50, kHeader2Size - 0x50);
+}
+
+
+
+static const Byte kBat[16] =
+ { 0x66,0x77,0xC2,0x2D,0x23,0xF6,0x00,0x42,0x9D,0x64,0x11,0x5E,0x9B,0xFD,0x4A,0x08 };
+static const Byte kMetadataRegion[16] =
+ { 0x06,0xA2,0x7C,0x8B,0x90,0x47,0x9A,0x4B,0xB8,0xFE,0x57,0x5F,0x05,0x0F,0x88,0x6E };
+
+struct CRegionEntry
+{
+ // CGuid Guid;
+ UInt64 Offset;
+ UInt32 Len;
+ UInt32 Required;
+
+ UInt64 GetEndPos() const { return Offset + Len; }
+ bool Parse(const Byte *p);
+};
+
+bool CRegionEntry::Parse(const Byte *p)
+{
+ // Guid.SetFrom(p);
+ G64(0x10, Offset);
+ G32(0x18, Len);
+ G32(0x1c, Required);
+ if (IS_NON_ALIGNED(Offset))
+ return false;
+ if (IS_NON_ALIGNED(Len))
+ return false;
+ if (Offset + Len < Offset)
+ return false;
+ return true;
+}
+
+
+struct CRegion
+{
+ bool Bat_Defined;
+ bool Meta_Defined;
+ UInt64 EndPos;
+ UInt64 DataSize;
+
+ CRegionEntry BatEntry;
+ CRegionEntry MetaEntry;
+
+ bool Parse(Byte *p);
+};
+
+
+static const unsigned kRegionSize = 1 << 16;
+static const unsigned kNumRegionEntriesMax = (1 << 11) - 1;
+
+bool CRegion::Parse(Byte *p)
+{
+ Bat_Defined = false;
+ Meta_Defined = false;
+ EndPos = 0;
+ DataSize = 0;
+
+ if (Get32(p) != 0x69676572) // "regi"
+ return false;
+ const UInt32 crc = Get32(p + 4);
+ SetUi32(p + 4, 0)
+ const UInt32 crc_calced = Crc32c_Calc(p, kRegionSize);
+ if (crc_calced != crc)
+ return false;
+
+ const UInt32 EntryCount = Get32(p + 8);
+ if (Get32(p + 12) != 0) // reserved field must be set to 0.
+ return false;
+ if (EntryCount > kNumRegionEntriesMax)
+ return false;
+ for (UInt32 i = 0; i < EntryCount; i++)
+ {
+ CRegionEntry e;
+ const Byte *p2 = p + 0x10 + 0x20 * (size_t)i;
+ if (!e.Parse(p2))
+ return false;
+ DataSize += e.Len;
+ const UInt64 endPos = e.GetEndPos();
+ if (EndPos < endPos)
+ EndPos = endPos;
+ CGuid Guid;
+ Guid.SetFrom(p2);
+ if (Guid.IsEqualTo(kBat))
+ {
+ if (Bat_Defined)
+ return false;
+ BatEntry = e;
+ Bat_Defined = true;
+ }
+ else if (Guid.IsEqualTo(kMetadataRegion))
+ {
+ if (Meta_Defined)
+ return false;
+ MetaEntry = e;
+ Meta_Defined = true;
+ }
+ else
+ {
+ if (e.Required != 0)
+ return false;
+ // it's allowed to ignore unknown non-required region entries
+ }
+ }
+ /*
+ const size_t k = 0x10 + 0x20 * EntryCount;
+ return IsZeroArr(p + k, kRegionSize - k);
+ */
+ return true;
+}
+
+
+
+
+struct CMetaEntry
+{
+ CGuid Guid;
+ UInt32 Offset;
+ UInt32 Len;
+ UInt32 Flags0;
+ // UInt32 Flags1;
+
+ bool IsUser() const { return (Flags0 & 1) != 0; }
+ bool IsVirtualDisk() const { return (Flags0 & 2) != 0; }
+ bool IsRequired() const { return (Flags0 & 4) != 0; }
+
+ bool CheckLimit(size_t regionSize) const
+ {
+ return Offset <= regionSize && Len <= regionSize - Offset;
+ }
+
+ bool Parse(const Byte *p);
+};
+
+
+bool CMetaEntry::Parse(const Byte *p)
+{
+ Guid.SetFrom(p);
+
+ G32(0x10, Offset);
+ G32(0x14, Len);
+ G32(0x18, Flags0);
+ UInt32 Flags1;
+ G32(0x1C, Flags1);
+
+ if (Offset != 0 && Offset < (1 << 16))
+ return false;
+ if (Len > (1 << 20))
+ return false;
+ if (Len == 0 && Offset != 0)
+ return false;
+ if ((Flags0 >> 3) != 0) // Reserved
+ return false;
+ if ((Flags1 & 3) != 0) // Reserved2
+ return false;
+ return true;
+}
+
+
+struct CParentPair
+{
+ UString Key;
+ UString Value;
+};
+
+
+struct CMetaHeader
+{
+ // UInt16 EntryCount;
+ bool Guid_Defined;
+ bool VirtualDiskSize_Defined;
+ bool Locator_Defined;
+
+ unsigned BlockSize_Log;
+ unsigned LogicalSectorSize_Log;
+ unsigned PhysicalSectorSize_Log;
+
+ UInt32 Flags;
+ UInt64 VirtualDiskSize;
+ CGuid Guid;
+ // CGuid LocatorType;
+
+ CObjectVector<CParentPair> ParentPairs;
+
+ int FindParentKey(const char *name) const
+ {
+ FOR_VECTOR (i, ParentPairs)
+ {
+ const CParentPair &pair = ParentPairs[i];
+ if (pair.Key.IsEqualTo(name))
+ return (int)i;
+ }
+ return -1;
+ }
+
+ bool Is_LeaveBlockAllocated() const { return (Flags & 1) != 0; }
+ bool Is_HasParent() const { return (Flags & 2) != 0; }
+
+ void Clear()
+ {
+ Guid_Defined = false;
+ VirtualDiskSize_Defined = false;
+ Locator_Defined = false;
+ BlockSize_Log = 0;
+ LogicalSectorSize_Log = 0;
+ PhysicalSectorSize_Log = 0;
+ Flags = 0;
+ VirtualDiskSize = 0;
+ ParentPairs.Clear();
+ }
+
+ bool Parse(const Byte *p, size_t size);
+};
+
+
+static unsigned GetLogSize(UInt32 size)
+{
+ unsigned k;
+ for (k = 0; k < 32; k++)
+ if (((UInt32)1 << k) == size)
+ return k;
+ return k;
+}
+
+
+static const unsigned kMetadataSize = 8;
+static const Byte kMetadata[kMetadataSize] =
+ { 'm','e','t','a','d','a','t','a' };
+
+static const unsigned k_Num_MetaEntries_Max = (1 << 11) - 1;
+
+static const Byte kFileParameters[16] =
+ { 0x37,0x67,0xa1,0xca,0x36,0xfa,0x43,0x4d,0xb3,0xb6,0x33,0xf0,0xaa,0x44,0xe7,0x6b };
+static const Byte kVirtualDiskSize[16] =
+ { 0x24,0x42,0xa5,0x2f,0x1b,0xcd,0x76,0x48,0xb2,0x11,0x5d,0xbe,0xd8,0x3b,0xf4,0xb8 };
+static const Byte kVirtualDiskID[16] =
+ { 0xab,0x12,0xca,0xbe,0xe6,0xb2,0x23,0x45,0x93,0xef,0xc3,0x09,0xe0,0x00,0xc7,0x46 };
+static const Byte kLogicalSectorSize[16] =
+ { 0x1d,0xbf,0x41,0x81,0x6f,0xa9,0x09,0x47,0xba,0x47,0xf2,0x33,0xa8,0xfa,0xab,0x5f };
+static const Byte kPhysicalSectorSize[16] =
+ { 0xc7,0x48,0xa3,0xcd,0x5d,0x44,0x71,0x44,0x9c,0xc9,0xe9,0x88,0x52,0x51,0xc5,0x56 };
+static const Byte kParentLocator[16] =
+ { 0x2d,0x5f,0xd3,0xa8,0x0b,0xb3,0x4d,0x45,0xab,0xf7,0xd3,0xd8,0x48,0x34,0xab,0x0c };
+
+static bool GetString16(UString &s, const Byte *p, size_t size)
+{
+ s.Empty();
+ if (size & 1)
+ return false;
+ for (size_t i = 0; i < size; i += 2)
+ {
+ const wchar_t c = Get16(p + i);
+ if (c == 0)
+ return false;
+ s += c;
+ }
+ return true;
+}
+
+
+bool CMetaHeader::Parse(const Byte *p, size_t size)
+{
+ if (memcmp(p, kMetadata, kMetadataSize) != 0)
+ return false;
+ if (Get16(p + 8) != 0) // Reserved
+ return false;
+ const UInt32 EntryCount = Get16(p + 10);
+ if (EntryCount > k_Num_MetaEntries_Max)
+ return false;
+ if (!IsZeroArr(p + 12, 20)) // Reserved
+ return false;
+
+ for (unsigned i = 0; i < EntryCount; i++)
+ {
+ CMetaEntry e;
+ if (!e.Parse(p + 32 + 32 * (size_t)i))
+ return false;
+ if (!e.CheckLimit(size))
+ return false;
+ const Byte *p2 = p + e.Offset;
+
+ if (e.Guid.IsEqualTo(kFileParameters))
+ {
+ if (BlockSize_Log != 0)
+ return false;
+ if (e.Len != 8)
+ return false;
+ const UInt32 v = Get32(p2);
+ Flags = Get32(p2 + 4);
+ BlockSize_Log = GetLogSize(v);
+ if (BlockSize_Log < 20 || BlockSize_Log > 28) // specification from 1 MB to 256 MB
+ return false;
+ if ((Flags >> 2) != 0) // reserved
+ return false;
+ }
+ else if (e.Guid.IsEqualTo(kVirtualDiskSize))
+ {
+ if (VirtualDiskSize_Defined)
+ return false;
+ if (e.Len != 8)
+ return false;
+ VirtualDiskSize = Get64(p2);
+ VirtualDiskSize_Defined = true;
+ }
+ else if (e.Guid.IsEqualTo(kVirtualDiskID))
+ {
+ if (e.Len != 16)
+ return false;
+ Guid.SetFrom(p2);
+ Guid_Defined = true;
+ }
+ else if (e.Guid.IsEqualTo(kLogicalSectorSize))
+ {
+ if (LogicalSectorSize_Log != 0)
+ return false;
+ if (e.Len != 4)
+ return false;
+ const UInt32 v = Get32(p2);
+ LogicalSectorSize_Log = GetLogSize(v);
+ if (LogicalSectorSize_Log != 9 && LogicalSectorSize_Log != 12)
+ return false;
+ }
+ else if (e.Guid.IsEqualTo(kPhysicalSectorSize))
+ {
+ if (PhysicalSectorSize_Log != 0)
+ return false;
+ if (e.Len != 4)
+ return false;
+ const UInt32 v = Get32(p2);
+ PhysicalSectorSize_Log = GetLogSize(v);
+ if (PhysicalSectorSize_Log != 9 && PhysicalSectorSize_Log != 12)
+ return false;
+ }
+ else if (e.Guid.IsEqualTo(kParentLocator))
+ {
+ if (Locator_Defined)
+ return false;
+ if (e.Len < 20)
+ return false;
+ // LocatorType.SetFrom(p2);
+ /* Specifies the type of the parent virtual disk.
+ is different for each type: VHDX, VHD or iSCSI.
+ only "B04AEFB7-D19E-4A81-B789-25B8E9445913" (for VHDX) is supported now
+ */
+ Locator_Defined = true;
+ if (Get16(p2 + 16) != 0) // reserved
+ return false;
+ const UInt32 KeyValueCount = Get16(p2 + 18);
+ if (20 + (UInt32)KeyValueCount * 12 > e.Len)
+ return false;
+ for (unsigned k = 0; k < KeyValueCount; k++)
+ {
+ const Byte *p3 = p2 + 20 + (size_t)k * 12;
+ const UInt32 KeyOffset = Get32(p3);
+ const UInt32 ValueOffset = Get32(p3 + 4);
+ const UInt32 KeyLength = Get16(p3 + 8);
+ const UInt32 ValueLength = Get16(p3 + 10);
+ if (KeyOffset > e.Len || KeyLength > e.Len - KeyOffset)
+ return false;
+ if (ValueOffset > e.Len || ValueLength > e.Len - ValueOffset)
+ return false;
+ CParentPair pair;
+ if (!GetString16(pair.Key, p2 + KeyOffset, KeyLength))
+ return false;
+ if (!GetString16(pair.Value, p2 + ValueOffset, ValueLength))
+ return false;
+ ParentPairs.Add(pair);
+ }
+ }
+ else
+ {
+ if (e.IsRequired())
+ return false;
+ // return false; // unknown metadata;
+ }
+ }
+
+ // some properties are required for correct processing
+
+ if (BlockSize_Log == 0)
+ return false;
+ if (LogicalSectorSize_Log == 0)
+ return false;
+ if (!VirtualDiskSize_Defined)
+ return false;
+ if (((UInt32)VirtualDiskSize & ((UInt32)1 << LogicalSectorSize_Log)) != 0)
+ return false;
+
+ // vhdx specification sets limit for 64 TB.
+ // do we need to check over same limit ?
+ const UInt64 kVirtualDiskSize_Max = (UInt64)1 << 46;
+ if (VirtualDiskSize > kVirtualDiskSize_Max)
+ return false;
+
+ return true;
+}
+
+
+
+struct CBat
+{
+ CByteBuffer Data;
+
+ void Clear() { Data.Free(); }
+ UInt64 GetItem(size_t n) const
+ {
+ return Get64(Data + n * 8);
+ }
+};
+
+
+
+Z7_class_CHandler_final: public CHandlerImg
+{
+ UInt64 _phySize;
+
+ CBat Bat;
+ CObjectVector<CByteBuffer> BitMaps;
+
+ unsigned ChunkRatio_Log;
+ size_t ChunkRatio;
+ size_t TotalBatEntries;
+
+ CMetaHeader Meta;
+ CHeader Header;
+
+ UInt32 NumUsedBlocks;
+ UInt32 NumUsedBitMaps;
+ UInt64 HeadersSize;
+
+ UInt32 NumLevels;
+ UInt64 PackSize_Total;
+
+ /*
+ UInt64 NumUsed_1MB_Blocks; // data and bitmaps
+ bool NumUsed_1MB_Blocks_Defined;
+ */
+
+ CMyComPtr<IInStream> ParentStream;
+ CHandler *Parent;
+ UString _errorMessage;
+ UString _creator;
+
+ bool _nonEmptyLog;
+ bool _isDataContiguous;
+ // bool _batOverlap;
+
+ CGuid _parentGuid;
+ bool _parentGuid_IsDefined;
+ UStringVector ParentNames;
+ UString ParentName_Used;
+
+ const CHandler *_child;
+ unsigned _level;
+ bool _isCyclic;
+ bool _isCyclic_or_CyclicParent;
+
+ void AddErrorMessage(const char *message);
+ void AddErrorMessage(const char *message, const wchar_t *name);
+
+ void UpdatePhySize(UInt64 value)
+ {
+ if (_phySize < value)
+ _phySize = value;
+ }
+
+ HRESULT Seek2(UInt64 offset);
+ HRESULT Read_FALSE(Byte *data, size_t size)
+ {
+ return ReadStream_FALSE(Stream, data, size);
+ }
+ HRESULT ReadToBuf_FALSE(CByteBuffer &buf, size_t size)
+ {
+ buf.Alloc(size);
+ return ReadStream_FALSE(Stream, buf, size);
+ }
+
+ void InitSeekPositions();
+ HRESULT ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed);
+
+ bool IsDiff() const
+ {
+ // here we suppose that only HasParent() flag is mandatory for Diff archive type
+ return Meta.Is_HasParent();
+ // return _parentGuid_IsDefined;
+ }
+
+ void AddTypeString(AString &s) const
+ {
+ if (IsDiff())
+ s += "Differencing";
+ else
+ {
+ if (Meta.Is_LeaveBlockAllocated())
+ s += _isDataContiguous ? "fixed" : "fixed-non-cont";
+ else
+ s += "dynamic";
+ }
+ }
+
+ void AddComment(UString &s) const;
+
+ UInt64 GetPackSize() const
+ {
+ return (UInt64)NumUsedBlocks << Meta.BlockSize_Log;
+ }
+
+ UString GetParentSequence() const
+ {
+ const CHandler *p = this;
+ UString res;
+ while (p && p->IsDiff())
+ {
+ if (!res.IsEmpty())
+ res += " -> ";
+ res += ParentName_Used;
+ p = p->Parent;
+ }
+ return res;
+ }
+
+ bool AreParentsOK() const
+ {
+ if (_isCyclic_or_CyclicParent)
+ return false;
+ const CHandler *p = this;
+ while (p->IsDiff())
+ {
+ p = p->Parent;
+ if (!p)
+ return false;
+ }
+ return true;
+ }
+
+ // bool ParseLog(CByteBuffer &log);
+ bool ParseBat();
+ bool CheckBat();
+
+ HRESULT Open3();
+ HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback) Z7_override;
+ HRESULT OpenParent(IArchiveOpenCallback *openArchiveCallback, bool &_parentFileWasOpen);
+ virtual void CloseAtError() Z7_override;
+
+public:
+ Z7_IFACE_COM7_IMP(IInArchive_Img)
+
+ Z7_IFACE_COM7_IMP(IInArchiveGetStream)
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+
+ CHandler():
+ _child(NULL),
+ _level(0),
+ _isCyclic(false),
+ _isCyclic_or_CyclicParent(false)
+ {}
+};
+
+
+HRESULT CHandler::Seek2(UInt64 offset)
+{
+ return InStream_SeekSet(Stream, offset);
+}
+
+
+void CHandler::InitSeekPositions()
+{
+ /* (_virtPos) and (_posInArc) is used only in Read() (that calls ReadPhy()).
+ So we must reset these variables before first call of Read() */
+ Reset_VirtPos();
+ Reset_PosInArc();
+ if (ParentStream)
+ Parent->InitSeekPositions();
+}
+
+
+HRESULT CHandler::ReadPhy(UInt64 offset, void *data, UInt32 size, UInt32 &processed)
+{
+ processed = 0;
+ if (offset > _phySize
+ || offset + size > _phySize)
+ {
+ // we don't expect these cases, if (_phySize) was set correctly.
+ return S_FALSE;
+ }
+ if (offset != _posInArc)
+ {
+ const HRESULT res = Seek2(offset);
+ if (res != S_OK)
+ {
+ Reset_PosInArc(); // we don't trust seek_pos in case of error
+ return res;
+ }
+ _posInArc = offset;
+ }
+ {
+ size_t size2 = size;
+ const HRESULT res = ReadStream(Stream, data, &size2);
+ processed = (UInt32)size2;
+ _posInArc += size2;
+ if (res != S_OK)
+ Reset_PosInArc(); // we don't trust seek_pos in case of reading error
+ return res;
+ }
+}
+
+
+#define PAYLOAD_BLOCK_NOT_PRESENT 0
+#define PAYLOAD_BLOCK_UNDEFINED 1
+#define PAYLOAD_BLOCK_ZERO 2
+#define PAYLOAD_BLOCK_UNMAPPED 3
+#define PAYLOAD_BLOCK_FULLY_PRESENT 6
+#define PAYLOAD_BLOCK_PARTIALLY_PRESENT 7
+
+#define SB_BLOCK_NOT_PRESENT 0
+#define SB_BLOCK_PRESENT 6
+
+#define BAT_GET_OFFSET(v) ((v) & ~(UInt64)0xFFFFF)
+#define BAT_GET_STATE(v) ((UInt32)(v) & 7)
+
+/* The log contains only updates to metadata, bat and region tables
+ The log doesn't contain updates to start header, and 2 headers (first 192 KB of file).
+ The log is array of 4 KB blocks and each block has 4-byte signature.
+ So it's possible to scan whole log to find the latest entry sequence (and header for replay).
+*/
+
+/*
+struct CLogEntry
+{
+ UInt32 EntryLength;
+ UInt32 Tail;
+ UInt64 SequenceNumber;
+ CGuid LogGuid;
+ UInt32 DescriptorCount;
+ UInt64 FlushedFileOffset;
+ UInt64 LastFileOffset;
+
+ bool Parse(const Byte *p);
+};
+
+bool CLogEntry::Parse(const Byte *p)
+{
+ G32 (8, EntryLength);
+ G32 (12,Tail);
+ G64 (16, SequenceNumber);
+ G32 (24, DescriptorCount); // it's 32-bit, but specification says 64-bit
+ if (Get32(p + 28) != 0) // reserved
+ return false;
+ LogGuid.SetFrom(p + 32);
+ G64 (48, FlushedFileOffset);
+ G64 (56, LastFileOffset);
+
+ if (SequenceNumber == 0)
+ return false;
+ if ((Tail & 0xfff) != 0)
+ return false;
+ if (IS_NON_ALIGNED(FlushedFileOffset))
+ return false;
+ if (IS_NON_ALIGNED(LastFileOffset))
+ return false;
+ return true;
+}
+
+
+bool CHandler::ParseLog(CByteBuffer &log)
+{
+ CLogEntry lastEntry;
+ lastEntry.SequenceNumber = 0;
+ bool lastEntry_found = false;
+ size_t lastEntry_Offset = 0;
+ for (size_t i = 0; i < log.Size(); i += 1 << 12)
+ {
+ Byte *p = (Byte *)(log + i);
+
+ if (Get32(p) != 0x65676F6C) // "loge"
+ continue;
+ const UInt32 crc = Get32(p + 4);
+
+ CLogEntry e;
+ if (!e.Parse(p))
+ {
+ return false;
+ continue;
+ }
+ const UInt32 entryLength = Get32(p + 8);
+ if (e.EntryLength > log.Size() || (e.EntryLength & 0xFFF) != 0 || e.EntryLength == 0)
+ {
+ return false;
+ continue;
+ }
+ SetUi32(p + 4, 0);
+ const UInt32 crc_calced = Crc32c_Calc(p, entryLength);
+ SetUi32(p + 4, crc); // we must restore crc if we want same data in log
+ if (crc_calced != crc)
+ continue;
+ if (!lastEntry_found || lastEntry.SequenceNumber < e.SequenceNumber)
+ {
+ lastEntry = e;
+ lastEntry_found = true;
+ lastEntry_Offset = i;
+ }
+ }
+
+ return true;
+}
+*/
+
+
+bool CHandler::ParseBat()
+{
+ ChunkRatio_Log = kBitmapSize_Log + 3 + Meta.LogicalSectorSize_Log - Meta.BlockSize_Log;
+ ChunkRatio = (size_t)1 << (ChunkRatio_Log);
+
+ UInt64 totalBatEntries64;
+ const bool isDiff = IsDiff();
+ const UInt32 blockSize = (UInt32)1 << Meta.BlockSize_Log;
+ {
+ const UInt64 up = Meta.VirtualDiskSize + blockSize - 1;
+ if (up < Meta.VirtualDiskSize)
+ return false;
+ const UInt64 numDataBlocks = up >> Meta.BlockSize_Log;
+
+ if (isDiff)
+ {
+ // differencing table must be finished with bitmap entry
+ const UInt64 numBitmaps = (numDataBlocks + ChunkRatio - 1) >> ChunkRatio_Log;
+ totalBatEntries64 = numBitmaps * (ChunkRatio + 1);
+ }
+ else
+ {
+ // we don't need last Bitmap entry
+ totalBatEntries64 = numDataBlocks + ((numDataBlocks - 1) >> ChunkRatio_Log);
+ }
+ }
+
+ if (totalBatEntries64 > Bat.Data.Size() / 8)
+ return false;
+
+ const size_t totalBatEntries = (size_t)totalBatEntries64;
+ TotalBatEntries = totalBatEntries;
+
+ bool isCont = (!isDiff && Meta.Is_LeaveBlockAllocated());
+ UInt64 prevBlockOffset = 0;
+ UInt64 maxBlockOffset = 0;
+
+ size_t remEntries = ChunkRatio + 1;
+
+ size_t i;
+ for (i = 0; i < totalBatEntries; i++)
+ {
+ const UInt64 v = Bat.GetItem(i);
+ if ((v & 0xFFFF8) != 0)
+ return false;
+ const UInt64 offset = BAT_GET_OFFSET(v);
+ const unsigned state = BAT_GET_STATE(v);
+
+ /*
+ UInt64 index64 = v >> 20;
+ printf("\n%7d", i);
+ printf("%10d, ", (unsigned)index64);
+ printf("%4x, ", (unsigned)state);
+ */
+
+ remEntries--;
+ if (remEntries == 0)
+ {
+ // printf(" ========");
+ // printf("\n");
+ remEntries = ChunkRatio + 1;
+ if (state == SB_BLOCK_PRESENT)
+ {
+ isCont = false;
+ if (!isDiff)
+ return false;
+ if (offset == 0)
+ return false;
+ const UInt64 lim = offset + kBitmapSize;
+ if (lim < offset)
+ return false;
+ if (_phySize < lim)
+ _phySize = lim;
+ NumUsedBitMaps++;
+ }
+ else if (state != SB_BLOCK_NOT_PRESENT)
+ return false;
+ }
+ else
+ {
+ if (state == PAYLOAD_BLOCK_FULLY_PRESENT
+ || state == PAYLOAD_BLOCK_PARTIALLY_PRESENT)
+ {
+ if (offset == 0)
+ return false;
+ if (maxBlockOffset < offset)
+ maxBlockOffset = offset;
+
+ if (state == PAYLOAD_BLOCK_PARTIALLY_PRESENT)
+ {
+ isCont = false;
+ if (!isDiff)
+ return false;
+ }
+ else if (isCont)
+ {
+ if (prevBlockOffset != 0 && prevBlockOffset + blockSize != offset)
+ isCont = false;
+ else
+ prevBlockOffset = offset;
+ }
+
+ NumUsedBlocks++;
+ }
+ else if (state == PAYLOAD_BLOCK_UNMAPPED)
+ {
+ isCont = false;
+ // non-empty (offset) is allowed
+ }
+ else if (state == PAYLOAD_BLOCK_NOT_PRESENT
+ || state == PAYLOAD_BLOCK_UNDEFINED
+ || state == PAYLOAD_BLOCK_ZERO)
+ {
+ isCont = false;
+ /* (offset) is reserved and (offset == 0) is expected here,
+ but we ignore (offset) here */
+ // if (offset != 0) return false;
+ }
+ else
+ return false;
+ }
+ }
+
+ _isDataContiguous = isCont;
+
+ if (maxBlockOffset != 0)
+ {
+ const UInt64 lim = maxBlockOffset + blockSize;
+ if (lim < maxBlockOffset)
+ return false;
+ if (_phySize < lim)
+ _phySize = lim;
+ const UInt64 kPhyLimit = (UInt64)1 << 62;
+ if (maxBlockOffset >= kPhyLimit)
+ return false;
+ }
+ return true;
+}
+
+
+bool CHandler::CheckBat()
+{
+ const UInt64 upSize = _phySize + kBitmapSize * 8 - 1;
+ if (upSize < _phySize)
+ return false;
+ const UInt64 useMapSize64 = upSize >> (kBitmapSize_Log + 3);
+ const size_t useMapSize = (size_t)useMapSize64;
+
+ const UInt32 blockSizeMB = (UInt32)1 << (Meta.BlockSize_Log - kBitmapSize_Log);
+
+ // we don't check useMap, if it's too big.
+ if (useMapSize != useMapSize64)
+ return true;
+ if (useMapSize == 0 || useMapSize > ((size_t)1 << 28))
+ return true;
+
+ CByteArr useMap;
+ useMap.Alloc(useMapSize);
+ memset(useMap, 0, useMapSize);
+ // useMap[0] = (Byte)(1 << 0); // first 1 MB is used by headers
+ // we can also update useMap for log, and region data.
+
+ const size_t totalBatEntries = TotalBatEntries;
+ size_t remEntries = ChunkRatio + 1;
+
+ size_t i;
+ for (i = 0; i < totalBatEntries; i++)
+ {
+ const UInt64 v = Bat.GetItem(i);
+ const UInt64 offset = BAT_GET_OFFSET(v);
+ const unsigned state = BAT_GET_STATE(v);
+ const UInt64 index = offset >> kBitmapSize_Log;
+ UInt32 numBlocks = 1;
+ remEntries--;
+ if (remEntries == 0)
+ {
+ remEntries = ChunkRatio + 1;
+ if (state != SB_BLOCK_PRESENT)
+ continue;
+ }
+ else
+ {
+ if (state != PAYLOAD_BLOCK_FULLY_PRESENT &&
+ state != PAYLOAD_BLOCK_PARTIALLY_PRESENT)
+ continue;
+ numBlocks = blockSizeMB;
+ }
+
+ for (unsigned k = 0; k < numBlocks; k++)
+ {
+ const UInt64 index2 = index + k;
+ const unsigned flag = (unsigned)1 << ((unsigned)index2 & 7);
+ const size_t byteIndex = (size_t)(index2 >> 3);
+ if (byteIndex >= useMapSize)
+ return false;
+ const unsigned m = useMap[byteIndex];
+ if (m & flag)
+ return false;
+ useMap[byteIndex] = (Byte)(m | flag);
+ }
+ }
+
+ /*
+ UInt64 num = 0;
+ for (i = 0; i < useMapSize; i++)
+ {
+ Byte b = useMap[i];
+ unsigned t = 0;
+ t += (b & 1); b >>= 1;
+ t += (b & 1); b >>= 1;
+ t += (b & 1); b >>= 1;
+ t += (b & 1); b >>= 1;
+ t += (b & 1); b >>= 1;
+ t += (b & 1); b >>= 1;
+ t += (b & 1); b >>= 1;
+ t += (b & 1);
+ num += t;
+ }
+ NumUsed_1MB_Blocks = num;
+ NumUsed_1MB_Blocks_Defined = true;
+ */
+
+ return true;
+}
+
+
+
+HRESULT CHandler::Open3()
+{
+ {
+ const unsigned kHeaderSize = 512; // + 8
+ Byte header[kHeaderSize];
+
+ RINOK(Read_FALSE(header, kHeaderSize))
+
+ if (memcmp(header, kSignature, kSignatureSize) != 0)
+ return S_FALSE;
+
+ const Byte *p = &header[0];
+ for (unsigned i = kSignatureSize; i < kHeaderSize; i += 2)
+ {
+ const wchar_t c = Get16(p + i);
+ if (c < 0x20 || c > 0x7F)
+ break;
+ _creator += c;
+ }
+ }
+
+ HeadersSize = (UInt32)1 << 20;
+ CHeader headers[2];
+ {
+ Byte header[kHeader2Size];
+ for (unsigned i = 0; i < 2; i++)
+ {
+ RINOK(Seek2((1 << 16) * (1 + i)))
+ RINOK(Read_FALSE(header, kHeader2Size))
+ bool headerIsOK = headers[i].Parse(header);
+ if (!headerIsOK)
+ return S_FALSE;
+ }
+ }
+ unsigned mainIndex;
+ if (headers[0].SequenceNumber > headers[1].SequenceNumber) mainIndex = 0;
+ else if (headers[0].SequenceNumber < headers[1].SequenceNumber) mainIndex = 1;
+ else
+ {
+ /* Disk2vhd v2.02 can create image with 2 full copies of headers.
+ It's violation of VHDX specification:
+ "A header is current if it is the only valid header
+ or if it is valid and its SequenceNumber field is
+ greater than the other header's SequenceNumber".
+ but we support such Disk2vhd archives. */
+ if (!headers[0].IsEqualTo(headers[1]))
+ return S_FALSE;
+ mainIndex = 0;
+ }
+
+ const CHeader &h = headers[mainIndex];
+ Header = h;
+ if (h.LogLength != 0)
+ {
+ HeadersSize += h.LogLength;
+ UpdatePhySize(h.LogOffset + h.LogLength);
+ if (!h.Guids[kHeader_GUID_Index_LogGuid].IsZero())
+ {
+ _nonEmptyLog = true;
+ AddErrorMessage("non-empty LOG was not replayed");
+ /*
+ if (h.LogVersion != 0)
+ AddErrorMessage("unknown LogVresion");
+ else
+ {
+ CByteBuffer log;
+ RINOK(Seek2(h.LogOffset));
+ RINOK(ReadToBuf_FALSE(log, h.LogLength));
+ if (!ParseLog(log))
+ {
+ return S_FALSE;
+ }
+ }
+ */
+ }
+ }
+ CRegion regions[2];
+ int correctRegionIndex = -1;
+
+ {
+ CByteBuffer temp;
+ temp.Alloc(kRegionSize * 2);
+ RINOK(Seek2((1 << 16) * 3))
+ RINOK(Read_FALSE(temp, kRegionSize * 2))
+ unsigned numTables = 1;
+ if (memcmp(temp, temp + kRegionSize, kRegionSize) != 0)
+ {
+ AddErrorMessage("Region tables mismatch");
+ numTables = 2;
+ }
+
+ for (unsigned i = 0; i < numTables; i++)
+ {
+ // RINOK(Seek2((1 << 16) * (3 + i)));
+ // RINOK(Read_FALSE(temp, kRegionSize));
+ if (regions[i].Parse(temp))
+ {
+ if (correctRegionIndex < 0)
+ correctRegionIndex = (int)i;
+ }
+ else
+ {
+ AddErrorMessage("Incorrect region table");
+ }
+ }
+ if (correctRegionIndex < 0)
+ return S_FALSE;
+ /*
+ if (!regions[0].IsEqualTo(regions[1]))
+ return S_FALSE;
+ */
+ }
+
+ // UpdatePhySize((1 << 16) * 5);
+ UpdatePhySize(1 << 20);
+
+ {
+ const CRegion &region = regions[correctRegionIndex];
+ HeadersSize += region.DataSize;
+ UpdatePhySize(region.EndPos);
+ {
+ if (!region.Meta_Defined)
+ return S_FALSE;
+ const CRegionEntry &e = region.MetaEntry;
+ if (e.Len == 0)
+ return S_FALSE;
+ {
+ // static const kMetaTableSize = 1 << 16;
+ CByteBuffer temp;
+ {
+ RINOK(Seek2(e.Offset))
+ RINOK(ReadToBuf_FALSE(temp, e.Len))
+ }
+ if (!Meta.Parse(temp, temp.Size()))
+ return S_FALSE;
+ }
+ // UpdatePhySize(e.GetEndPos());
+ }
+ {
+ if (!region.Bat_Defined)
+ return S_FALSE;
+ const CRegionEntry &e = region.BatEntry;
+ if (e.Len == 0)
+ return S_FALSE;
+ // UpdatePhySize(e.GetEndPos());
+ {
+ RINOK(Seek2(e.Offset))
+ RINOK(ReadToBuf_FALSE(Bat.Data, e.Len))
+ }
+ if (!ParseBat())
+ return S_FALSE;
+ if (!CheckBat())
+ {
+ AddErrorMessage("BAT overlap");
+ // _batOverlap = true;
+ // return S_FALSE;
+ }
+ }
+ }
+
+ {
+ // do we need to check "parent_linkage2" also?
+ FOR_VECTOR (i, Meta.ParentPairs)
+ {
+ const CParentPair &pair = Meta.ParentPairs[i];
+ if (pair.Key.IsEqualTo("parent_linkage"))
+ {
+ _parentGuid_IsDefined = _parentGuid.ParseFromFormatedHexString(pair.Value);
+ break;
+ }
+ }
+ }
+
+ {
+ // absolute paths for parent stream can be rejected later in client callback
+ // the order of check by specification:
+ const char * const g_ParentKeys[] =
+ {
+ "relative_path" // "..\..\path2\sub3\parent.vhdx"
+ , "volume_path" // "\\?\Volume{26A21BDA-A627-11D7-9931-806E6F6E6963}\path2\sub3\parent.vhdx")
+ , "absolute_win32_path" // "d:\path2\sub3\parent.vhdx"
+ };
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ParentKeys); i++)
+ {
+ const int index = Meta.FindParentKey(g_ParentKeys[i]);
+ if (index < 0)
+ continue;
+ ParentNames.Add(Meta.ParentPairs[index].Value);
+ }
+ }
+
+ if (Meta.Is_HasParent())
+ {
+ if (!Meta.Locator_Defined)
+ AddErrorMessage("Parent locator is not defined");
+ else
+ {
+ if (!_parentGuid_IsDefined)
+ AddErrorMessage("Parent GUID is not defined");
+ if (ParentNames.IsEmpty())
+ AddErrorMessage("Parent VHDX file name is not defined");
+ }
+ }
+ else
+ {
+ if (Meta.Locator_Defined)
+ AddErrorMessage("Unexpected parent locator");
+ }
+
+ // here we suppose that and locator can be used only with HasParent flag
+
+ // return S_FALSE;
+
+ _size = Meta.VirtualDiskSize; // CHandlerImg
+
+ // _posInArc = 0;
+ // Reset_PosInArc();
+ // RINOK(InStream_SeekToBegin(Stream))
+
+ return S_OK;
+}
+
+
+/*
+static UInt32 g_NumCalls = 0;
+static UInt32 g_NumCalls2 = 0;
+static struct CCounter { ~CCounter()
+{
+ printf("\nNumCalls = %10u\n", g_NumCalls);
+ printf("NumCalls2 = %10u\n", g_NumCalls2);
+} } g_Counter;
+*/
+
+Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ // g_NumCalls++;
+ if (processedSize)
+ *processedSize = 0;
+ if (_virtPos >= Meta.VirtualDiskSize)
+ return S_OK;
+ {
+ const UInt64 rem = Meta.VirtualDiskSize - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+ if (size == 0)
+ return S_OK;
+ const size_t blockIndex = (size_t)(_virtPos >> Meta.BlockSize_Log);
+ const size_t chunkIndex = blockIndex >> ChunkRatio_Log;
+ const size_t chunkRatio = (size_t)1 << ChunkRatio_Log;
+ const size_t blockIndex2 = chunkIndex * (chunkRatio + 1) + (blockIndex & (chunkRatio - 1));
+ const UInt64 blockSectVal = Bat.GetItem(blockIndex2);
+ const UInt64 blockOffset = BAT_GET_OFFSET(blockSectVal);
+ const UInt32 blockState = BAT_GET_STATE(blockSectVal);
+
+ const UInt32 blockSize = (UInt32)1 << Meta.BlockSize_Log;
+ const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
+ size = MyMin(blockSize - offsetInBlock, size);
+
+ bool needParent = false;
+ bool needRead = false;
+
+ if (blockState == PAYLOAD_BLOCK_FULLY_PRESENT)
+ needRead = true;
+ else if (blockState == PAYLOAD_BLOCK_NOT_PRESENT)
+ {
+ /* for a differencing VHDX: parent virtual disk SHOULD be
+ inspected to determine the associated contents (SPECIFICATION).
+ we suppose that we should not check BitMap.
+ for fixed or dynamic VHDX files: the block contents are undefined and
+ can contain arbitrary data (SPECIFICATION). NTFS::pagefile.sys can use such state. */
+ if (IsDiff())
+ needParent = true;
+ }
+ else if (blockState == PAYLOAD_BLOCK_PARTIALLY_PRESENT)
+ {
+ // only allowed for differencing VHDX files.
+ // associated sector bitmap block MUST be valid
+ if (chunkIndex >= BitMaps.Size())
+ return S_FALSE;
+ // else
+ {
+ const CByteBuffer &bitmap = BitMaps[(unsigned)chunkIndex];
+ const Byte *p = (const Byte *)bitmap;
+ if (!p)
+ return S_FALSE;
+ // else
+ {
+ // g_NumCalls2++;
+ const UInt64 sectorIndex = _virtPos >> Meta.LogicalSectorSize_Log;
+
+ #define BIT_MAP_UNIT_LOG 3 // it's for small block (4 KB)
+ // #define BIT_MAP_UNIT_LOG 5 // speed optimization for large blocks (16 KB)
+
+ const size_t offs = (size_t)(sectorIndex >> 3) &
+ (
+ (kBitmapSize - 1)
+ & ~(((UInt32)1 << (BIT_MAP_UNIT_LOG - 3)) - 1)
+ );
+
+ unsigned sector2 = (unsigned)sectorIndex & ((1 << BIT_MAP_UNIT_LOG) - 1);
+ #if BIT_MAP_UNIT_LOG == 5
+ UInt32 v = GetUi32(p + offs) >> sector2;
+ #else
+ unsigned v = (unsigned)p[offs] >> sector2;
+ #endif
+ // UInt32 v = GetUi32(p + offs) >> sector2;
+ const UInt32 sectorSize = (UInt32)1 << Meta.LogicalSectorSize_Log;
+ const UInt32 offsetInSector = (UInt32)_virtPos & (sectorSize - 1);
+ const unsigned bit = (unsigned)(v & 1);
+ if (bit)
+ needRead = true;
+ else
+ needParent = true; // zero - from the parent VHDX file
+ UInt32 rem = sectorSize - offsetInSector;
+ for (sector2++; sector2 < (1 << BIT_MAP_UNIT_LOG); sector2++)
+ {
+ v >>= 1;
+ if (bit != (v & 1))
+ break;
+ rem += sectorSize;
+ }
+ if (size > rem)
+ size = rem;
+ }
+ }
+ }
+
+ bool needZero = true;
+
+ HRESULT res = S_OK;
+
+ if (needParent)
+ {
+ if (!ParentStream)
+ return S_FALSE;
+ // if (ParentStream)
+ {
+ RINOK(InStream_SeekSet(ParentStream, _virtPos))
+ size_t processed = size;
+ res = ReadStream(ParentStream, (Byte *)data, &processed);
+ size = (UInt32)processed;
+ needZero = false;
+ }
+ }
+ else if (needRead)
+ {
+ UInt32 processed = 0;
+ res = ReadPhy(blockOffset + offsetInBlock, data, size, processed);
+ size = processed;
+ needZero = false;
+ }
+
+ if (needZero)
+ memset(data, 0, size);
+
+ if (processedSize)
+ *processedSize = size;
+
+ _virtPos += size;
+ return res;
+}
+
+
+enum
+{
+ kpidParent = kpidUserDefined
+};
+
+static const CStatProp kArcProps[] =
+{
+ { NULL, kpidClusterSize, VT_UI4},
+ { NULL, kpidSectorSize, VT_UI4},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidNumVolumes, VT_UI4},
+ { NULL, kpidTotalPhySize, VT_UI8},
+ { "Parent", kpidParent, VT_BSTR},
+ { NULL, kpidCreatorApp, VT_BSTR},
+ { NULL, kpidComment, VT_BSTR},
+ { NULL, kpidId, VT_BSTR}
+ };
+
+static const Byte kProps[] =
+{
+ kpidSize,
+ kpidPackSize
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_WITH_NAME
+
+
+void CHandler::AddErrorMessage(const char *message)
+{
+ if (!_errorMessage.IsEmpty())
+ _errorMessage.Add_LF();
+ _errorMessage += message;
+}
+
+void CHandler::AddErrorMessage(const char *message, const wchar_t *name)
+{
+ AddErrorMessage(message);
+ _errorMessage += name;
+}
+
+
+static void AddComment_Name(UString &s, const char *name)
+{
+ s += name;
+ s += ": ";
+}
+
+static void AddComment_Bool(UString &s, const char *name, bool val)
+{
+ AddComment_Name(s, name);
+ s += val ? "+" : "-";
+ s.Add_LF();
+}
+
+static void AddComment_UInt64(UString &s, const char *name, UInt64 v, bool showMB = false)
+{
+ AddComment_Name(s, name);
+ s.Add_UInt64(v);
+ if (showMB)
+ {
+ s += " (";
+ s.Add_UInt64(v >> 20);
+ s += " MiB)";
+ }
+ s.Add_LF();
+}
+
+static void AddComment_BlockSize(UString &s, const char *name, unsigned logSize)
+{
+ if (logSize != 0)
+ AddComment_UInt64(s, name, ((UInt64)1 << logSize));
+}
+
+
+void CHandler::AddComment(UString &s) const
+{
+ AddComment_UInt64(s, "VirtualDiskSize", Meta.VirtualDiskSize);
+ AddComment_UInt64(s, "PhysicalSize", _phySize);
+
+ if (!_errorMessage.IsEmpty())
+ {
+ AddComment_Name(s, "Error");
+ s += _errorMessage;
+ s.Add_LF();
+ }
+
+ if (Meta.Guid_Defined)
+ {
+ AddComment_Name(s, "Id");
+ Meta.Guid.AddHexToString(s);
+ s.Add_LF();
+ }
+
+ AddComment_UInt64(s, "SequenceNumber", Header.SequenceNumber);
+ AddComment_UInt64(s, "LogLength", Header.LogLength, true);
+
+ for (unsigned i = 0; i < 3; i++)
+ {
+ const CGuid &g = Header.Guids[i];
+ if (g.IsZero())
+ continue;
+ if (i == 0)
+ s += "FileWrite";
+ else if (i == 1)
+ s += "DataWrite";
+ else
+ s += "Log";
+ AddComment_Name(s, "Guid");
+ g.AddHexToString(s);
+ s.Add_LF();
+ }
+
+ AddComment_Bool(s, "HasParent", Meta.Is_HasParent());
+ AddComment_Bool(s, "Fixed", Meta.Is_LeaveBlockAllocated());
+ if (Meta.Is_LeaveBlockAllocated())
+ AddComment_Bool(s, "DataContiguous", _isDataContiguous);
+
+ AddComment_BlockSize(s, "BlockSize", Meta.BlockSize_Log);
+ AddComment_BlockSize(s, "LogicalSectorSize", Meta.LogicalSectorSize_Log);
+ AddComment_BlockSize(s, "PhysicalSectorSize", Meta.PhysicalSectorSize_Log);
+
+ {
+ const UInt64 packSize = GetPackSize();
+ AddComment_UInt64(s, "PackSize", packSize, true);
+ const UInt64 headersSize = HeadersSize + ((UInt64)NumUsedBitMaps << kBitmapSize_Log);
+ AddComment_UInt64(s, "HeadersSize", headersSize, true);
+ AddComment_UInt64(s, "FreeSpace", _phySize - packSize - headersSize, true);
+ /*
+ if (NumUsed_1MB_Blocks_Defined)
+ AddComment_UInt64(s, "used2", (NumUsed_1MB_Blocks << 20));
+ */
+ }
+
+ if (Meta.ParentPairs.Size() != 0)
+ {
+ s += "Parent:";
+ s.Add_LF();
+ FOR_VECTOR(i, Meta.ParentPairs)
+ {
+ const CParentPair &pair = Meta.ParentPairs[i];
+ s += " ";
+ s += pair.Key;
+ s += ": ";
+ s += pair.Value;
+ s.Add_LF();
+ }
+ s.Add_LF();
+ }
+}
+
+
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidMainSubfile: prop = (UInt32)0; break;
+ case kpidClusterSize: prop = (UInt32)1 << Meta.BlockSize_Log; break;
+ case kpidSectorSize: prop = (UInt32)1 << Meta.LogicalSectorSize_Log; break;
+ case kpidShortComment:
+ case kpidMethod:
+ {
+ AString s;
+ AddTypeString(s);
+ if (IsDiff())
+ {
+ s += " -> ";
+ const CHandler *p = this;
+ while (p && p->IsDiff())
+ p = p->Parent;
+ if (!p)
+ s += '?';
+ else
+ p->AddTypeString(s);
+ }
+ prop = s;
+ break;
+ }
+ case kpidComment:
+ {
+ UString s;
+ {
+ if (NumLevels > 1)
+ {
+ AddComment_UInt64(s, "NumVolumeLevels", NumLevels);
+ AddComment_UInt64(s, "PackSizeTotal", PackSize_Total, true);
+ s += "----";
+ s.Add_LF();
+ }
+
+ const CHandler *p = this;
+ for (;;)
+ {
+ if (p->_level != 0 || p->Parent)
+ AddComment_UInt64(s, "VolumeLevel", p->_level + 1);
+ p->AddComment(s);
+ if (!p->Parent)
+ break;
+ s += "----";
+ s.Add_LF();
+ {
+ s.Add_LF();
+ if (!p->ParentName_Used.IsEmpty())
+ {
+ AddComment_Name(s, "Name");
+ s += p->ParentName_Used;
+ s.Add_LF();
+ }
+ }
+ p = p->Parent;
+ }
+ }
+ prop = s;
+ break;
+ }
+ case kpidCreatorApp:
+ {
+ if (!_creator.IsEmpty())
+ prop = _creator;
+ break;
+ }
+ case kpidId:
+ {
+ if (Meta.Guid_Defined)
+ {
+ UString s;
+ Meta.Guid.AddHexToString(s);
+ prop = s;
+ }
+ break;
+ }
+ case kpidName:
+ {
+ if (Meta.Guid_Defined)
+ {
+ UString s;
+ Meta.Guid.AddHexToString(s);
+ s += ".vhdx";
+ prop = s;
+ }
+ break;
+ }
+ case kpidParent: if (IsDiff()) prop = GetParentSequence(); break;
+ case kpidPhySize: prop = _phySize; break;
+ case kpidTotalPhySize:
+ {
+ const CHandler *p = this;
+ UInt64 sum = 0;
+ do
+ {
+ sum += p->_phySize;
+ p = p->Parent;
+ }
+ while (p);
+ prop = sum;
+ break;
+ }
+ case kpidNumVolumes: if (NumLevels != 1) prop = (UInt32)NumLevels; break;
+ case kpidError:
+ {
+ UString s;
+ const CHandler *p = this;
+ do
+ {
+ if (!p->_errorMessage.IsEmpty())
+ {
+ if (!s.IsEmpty())
+ s.Add_LF();
+ s += p->_errorMessage;
+ }
+ p = p->Parent;
+ }
+ while (p);
+ if (!s.IsEmpty())
+ prop = s;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openArchiveCallback)
+{
+ Stream = stream;
+ if (_level >= (1 << 20))
+ return S_FALSE;
+
+ RINOK(Open3())
+
+ NumLevels = 1;
+ PackSize_Total = GetPackSize();
+
+ if (_child)
+ {
+ if (!_child->_parentGuid.IsEqualTo(Header.Guids[kHeader_GUID_Index_DataWriteGuid]))
+ return S_FALSE;
+ const CHandler *child = _child;
+ do
+ {
+ /* We suppose that only FileWriteGuid is unique.
+ Another IDs must be identical in in difference and parent archives. */
+ if (Header.Guids[kHeader_GUID_Index_FileWriteGuid].IsEqualTo(
+ child->Header.Guids[kHeader_GUID_Index_FileWriteGuid])
+ && _phySize == child->_phySize)
+ {
+ _isCyclic = true;
+ _isCyclic_or_CyclicParent = true;
+ AddErrorMessage("Cyclic parent archive was blocked");
+ return S_OK;
+ }
+ child = child->_child;
+ }
+ while (child);
+ }
+
+ if (!Meta.Is_HasParent())
+ return S_OK;
+
+ if (!Meta.Locator_Defined
+ || !_parentGuid_IsDefined
+ || ParentNames.IsEmpty())
+ {
+ return S_OK;
+ }
+
+ ParentName_Used = ParentNames.Front();
+
+ HRESULT res;
+ const unsigned kNumLevelsMax = (1 << 8); // Maybe we need to increase that limit
+ if (_level >= kNumLevelsMax - 1)
+ {
+ AddErrorMessage("Too many parent levels");
+ return S_OK;
+ }
+
+ bool _parentFileWasOpen = false;
+
+ if (!openArchiveCallback)
+ res = S_FALSE;
+ else
+ res = OpenParent(openArchiveCallback, _parentFileWasOpen);
+
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ return res;
+
+ if (_parentFileWasOpen)
+ AddErrorMessage("Can't parse parent VHDX file : ", ParentName_Used);
+ else
+ AddErrorMessage("Missing parent VHDX file : ", ParentName_Used);
+ }
+
+
+ return S_OK;
+}
+
+
+HRESULT CHandler::OpenParent(IArchiveOpenCallback *openArchiveCallback, bool &_parentFileWasOpen)
+{
+ _parentFileWasOpen = false;
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IArchiveOpenVolumeCallback,
+ openVolumeCallback, openArchiveCallback)
+ if (!openVolumeCallback)
+ return S_FALSE;
+ {
+ CMyComPtr<IInStream> nextStream;
+ HRESULT res = S_FALSE;
+ UString name;
+
+ FOR_VECTOR (i, ParentNames)
+ {
+ name = ParentNames[i];
+
+ // we remove prefix ".\\', but client already can support any variant
+ if (name[0] == L'.' && name[1] == L'\\')
+ name.DeleteFrontal(2);
+
+ res = openVolumeCallback->GetStream(name, &nextStream);
+
+ if (res == S_OK && nextStream)
+ break;
+
+ if (res != S_OK && res != S_FALSE)
+ return res;
+ }
+
+ if (res == S_FALSE || !nextStream)
+ return S_FALSE;
+
+ ParentName_Used = name;
+ _parentFileWasOpen = true;
+
+ Parent = new CHandler;
+ ParentStream = Parent;
+
+ try
+ {
+ Parent->_level = _level + 1;
+ Parent->_child = this;
+ /* we could call CHandlerImg::Open() here.
+ but we don't need (_imgExt) in (Parent). So we call Open2() here */
+ Parent->Close();
+ res = Parent->Open2(nextStream, openArchiveCallback);
+ }
+ catch(...)
+ {
+ Parent = NULL;
+ ParentStream.Release();
+ res = S_FALSE;
+ throw;
+ }
+
+ if (res != S_OK)
+ {
+ Parent = NULL;
+ ParentStream.Release();
+ if (res == E_ABORT)
+ return res;
+ if (res != S_FALSE)
+ {
+ // we must show that error code
+ }
+ }
+
+ if (res == S_OK)
+ {
+ if (Parent->_isCyclic_or_CyclicParent)
+ _isCyclic_or_CyclicParent = true;
+
+ NumLevels = Parent->NumLevels + 1;
+ PackSize_Total += Parent->GetPackSize();
+
+ // we read BitMaps only if Parent was open
+
+ UInt64 numBytes = (UInt64)NumUsedBitMaps << kBitmapSize_Log;
+ if (openArchiveCallback && numBytes != 0)
+ {
+ RINOK(openArchiveCallback->SetTotal(NULL, &numBytes))
+ }
+ numBytes = 0;
+ for (size_t i = ChunkRatio; i < TotalBatEntries; i += ChunkRatio + 1)
+ {
+ const UInt64 v = Bat.GetItem(i);
+ const UInt64 offset = BAT_GET_OFFSET(v);
+ const unsigned state = BAT_GET_STATE(v);
+
+ CByteBuffer &buf = BitMaps.AddNew();
+ if (state == SB_BLOCK_PRESENT)
+ {
+ if (openArchiveCallback)
+ {
+ RINOK(openArchiveCallback->SetCompleted(NULL, &numBytes))
+ }
+ numBytes += kBitmapSize;
+ buf.Alloc(kBitmapSize);
+ RINOK(Seek2(offset))
+ RINOK(Read_FALSE(buf, kBitmapSize))
+ /*
+ for (unsigned i = 0; i < (1 << 20); i+=4)
+ {
+ UInt32 v = GetUi32(buf + i);
+ if (v != 0 && v != (UInt32)(Int32)-1)
+ printf("\n%7d %8x", i, v);
+ }
+ */
+ }
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+void CHandler::CloseAtError()
+{
+ // CHandlerImg
+ Clear_HandlerImg_Vars();
+ Stream.Release();
+
+ _phySize = 0;
+ Bat.Clear();
+ BitMaps.Clear();
+ NumUsedBlocks = 0;
+ NumUsedBitMaps = 0;
+ HeadersSize = 0;
+ /*
+ NumUsed_1MB_Blocks = 0;
+ NumUsed_1MB_Blocks_Defined = false;
+ */
+
+ Parent = NULL;
+ ParentStream.Release();
+ _errorMessage.Empty();
+ _creator.Empty();
+ _nonEmptyLog = false;
+ _parentGuid_IsDefined = false;
+ _isDataContiguous = false;
+ // _batOverlap = false;
+
+ ParentNames.Clear();
+ ParentName_Used.Empty();
+
+ Meta.Clear();
+
+ ChunkRatio_Log = 0;
+ ChunkRatio = 0;
+ TotalBatEntries = 0;
+ NumLevels = 0;
+ PackSize_Total = 0;
+
+ _isCyclic = false;
+ _isCyclic_or_CyclicParent = false;
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ CloseAtError();
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ switch (propID)
+ {
+ case kpidSize: prop = Meta.VirtualDiskSize; break;
+ case kpidPackSize: prop = PackSize_Total; break;
+ case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break;
+ }
+
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ *stream = NULL;
+ // if some prarent is not OK, we don't create stream
+ if (!AreParentsOK())
+ return S_FALSE;
+ InitSeekPositions();
+ CMyComPtr<ISequentialInStream> streamTemp = this;
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+REGISTER_ARC_I(
+ "VHDX", "vhdx avhdx", NULL, 0xc4,
+ kSignature,
+ 0,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/VmdkHandler.cpp b/CPP/7zip/Archive/VmdkHandler.cpp
new file mode 100644
index 0000000..0a6b967
--- /dev/null
+++ b/CPP/7zip/Archive/VmdkHandler.cpp
@@ -0,0 +1,1527 @@
+// VmdkHandler.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/StringConvert.h"
+#include "../../Common/StringToInt.h"
+#include "../../Common/UTFConvert.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/ZlibDecoder.h"
+
+#include "HandlerCont.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NVmdk {
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+#define LE_16(offs, dest) dest = Get16(p + (offs))
+#define LE_32(offs, dest) dest = Get32(p + (offs))
+#define LE_64(offs, dest) dest = Get64(p + (offs))
+
+
+static const Byte k_Signature[] = { 'K', 'D', 'M', 'V' };
+
+static const UInt32 k_Flags_NL = (UInt32)1 << 0;
+// static const UInt32 k_Flags_RGD = (UInt32)1 << 1;
+static const UInt32 k_Flags_ZeroGrain = (UInt32)1 << 2;
+static const UInt32 k_Flags_Compressed = (UInt32)1 << 16;
+static const UInt32 k_Flags_Marker = (UInt32)1 << 17;
+
+static const unsigned k_NumMidBits = 9; // num bits for index in Grain Table
+
+struct CHeader
+{
+ UInt32 flags;
+ UInt32 version;
+
+ UInt64 capacity;
+ UInt64 grainSize;
+ UInt64 descriptorOffset;
+ UInt64 descriptorSize;
+
+ UInt32 numGTEsPerGT;
+ UInt16 algo;
+ // Byte uncleanShutdown;
+ // UInt64 rgdOffset;
+ UInt64 gdOffset;
+ UInt64 overHead;
+
+ bool Is_NL() const { return (flags & k_Flags_NL) != 0; }
+ bool Is_ZeroGrain() const { return (flags & k_Flags_ZeroGrain) != 0; }
+ bool Is_Compressed() const { return (flags & k_Flags_Compressed) != 0; }
+ bool Is_Marker() const { return (flags & k_Flags_Marker) != 0; }
+
+ bool Parse(const Byte *p);
+
+ bool IsSameImageFor(const CHeader &h) const
+ {
+ return flags == h.flags
+ && version == h.version
+ && capacity == h.capacity
+ && grainSize == h.grainSize
+ && algo == h.algo;
+ }
+};
+
+bool CHeader::Parse(const Byte *p)
+{
+ if (memcmp(p, k_Signature, sizeof(k_Signature)) != 0)
+ return false;
+
+ LE_32 (0x04, version);
+ LE_32 (0x08, flags);
+ LE_64 (0x0C, capacity);
+ LE_64 (0x14, grainSize);
+ LE_64 (0x1C, descriptorOffset);
+ LE_64 (0x24, descriptorSize);
+ LE_32 (0x2C, numGTEsPerGT);
+ // LE_64 (0x30, rgdOffset);
+ LE_64 (0x38, gdOffset);
+ LE_64 (0x40, overHead);
+ // uncleanShutdown = buf[0x48];
+ LE_16(0x4D, algo);
+
+ if (Is_NL() && Get32(p + 0x49) != 0x0A0D200A) // do we need Is_NL() check here?
+ return false;
+
+ return (numGTEsPerGT == (1 << k_NumMidBits)) && (version <= 3);
+}
+
+
+enum
+{
+ k_Marker_END_OF_STREAM = 0,
+ k_Marker_GRAIN_TABLE = 1,
+ k_Marker_GRAIN_DIR = 2,
+ k_Marker_FOOTER = 3
+};
+
+struct CMarker
+{
+ UInt64 NumSectors;
+ UInt32 SpecSize; // = 0 for metadata sectors
+ UInt32 Type;
+
+ void Parse(const Byte *p)
+ {
+ LE_64 (0, NumSectors);
+ LE_32 (8, SpecSize);
+ LE_32 (12, Type);
+ }
+};
+
+
+static bool Str_to_ValName(const AString &s, AString &name, AString &val)
+{
+ name.Empty();
+ val.Empty();
+ int qu = s.Find('"');
+ int eq = s.Find('=');
+ if (eq < 0 || (qu >= 0 && eq > qu))
+ return false;
+ name.SetFrom(s.Ptr(), eq);
+ name.Trim();
+ val = s.Ptr(eq + 1);
+ val.Trim();
+ return true;
+}
+
+static inline bool IsSpaceChar(char c)
+{
+ return (c == ' ' || c == '\t');
+}
+
+static const char *SkipSpaces(const char *s)
+{
+ for (;; s++)
+ {
+ char c = *s;
+ if (c == 0 || !IsSpaceChar(c))
+ return s;
+ }
+}
+
+#define SKIP_SPACES(s) s = SkipSpaces(s);
+
+static const char *GetNextWord(const char *s, AString &dest)
+{
+ dest.Empty();
+ SKIP_SPACES(s)
+ const char *start = s;
+ for (;; s++)
+ {
+ char c = *s;
+ if (c == 0 || IsSpaceChar(c))
+ {
+ dest.SetFrom(start, (unsigned)(s - start));
+ return s;
+ }
+ }
+}
+
+static const char *GetNextNumber(const char *s, UInt64 &val)
+{
+ SKIP_SPACES(s)
+ if (*s == 0)
+ return s;
+ const char *end;
+ val = ConvertStringToUInt64(s, &end);
+ char c = *end;
+ if (c != 0 && !IsSpaceChar(c))
+ return NULL;
+ return end;
+}
+
+
+struct CExtentInfo
+{
+ AString Access; // RW, RDONLY, or NOACCESS
+ UInt64 NumSectors; // 512 bytes sectors
+ AString Type; // FLAT, SPARSE, ZERO, VMFS, VMFSSPARSE, VMFSRDM, VMFSRAW
+ AString FileName;
+ UInt64 StartSector; // used for FLAT
+
+ // for VMWare Player 9:
+ // PartitionUUID
+ // DeviceIdentifier
+
+ bool IsType_ZERO() const { return Type == "ZERO"; }
+ // bool IsType_FLAT() const { return Type == "FLAT"; }
+ bool IsType_Flat() const { return Type == "FLAT" || Type == "VMFS" || Type == "VMFSRAW"; }
+
+ bool Parse(const char *s);
+};
+
+bool CExtentInfo::Parse(const char *s)
+{
+ NumSectors = 0;
+ StartSector = 0;
+ Access.Empty();
+ Type.Empty();
+ FileName.Empty();
+
+ s = GetNextWord(s, Access);
+ s = GetNextNumber(s, NumSectors);
+ if (!s)
+ return false;
+ s = GetNextWord(s, Type);
+
+ if (Type.IsEmpty())
+ return false;
+
+ SKIP_SPACES(s)
+
+ if (IsType_ZERO())
+ return (*s == 0);
+
+ if (*s != '\"')
+ return false;
+ s++;
+ {
+ const char *s2 = strchr(s, '\"');
+ if (!s2)
+ return false;
+ FileName.SetFrom(s, (unsigned)(s2 - s));
+ s = s2 + 1;
+ }
+ SKIP_SPACES(s)
+ if (*s == 0)
+ return true;
+
+ s = GetNextNumber(s, StartSector);
+ if (!s)
+ return false;
+ return true;
+ // SKIP_SPACES(s);
+ // return (*s == 0);
+}
+
+
+struct CDescriptor
+{
+ AString CID;
+ AString parentCID;
+ AString createType;
+ // AString encoding; // UTF-8, windows-1252 - default is UTF-8
+
+ CObjectVector<CExtentInfo> Extents;
+
+ static void GetUnicodeName(const AString &s, UString &res)
+ {
+ if (!ConvertUTF8ToUnicode(s, res))
+ MultiByteToUnicodeString2(res, s);
+ }
+
+ void Clear()
+ {
+ CID.Empty();
+ parentCID.Empty();
+ createType.Empty();
+ Extents.Clear();
+ }
+
+ bool IsThere_Parent() const
+ {
+ return !parentCID.IsEmpty() && !parentCID.IsEqualTo_Ascii_NoCase("ffffffff");
+ }
+
+ bool Parse(const Byte *p, size_t size);
+};
+
+
+bool CDescriptor::Parse(const Byte *p, size_t size)
+{
+ Clear();
+
+ AString s;
+ AString name;
+ AString val;
+
+ for (;;)
+ {
+ Byte c = 0;
+ if (size != 0)
+ {
+ size--;
+ c = *p++;
+ }
+ if (c == 0 || c == 0xA || c == 0xD)
+ {
+ if (!s.IsEmpty() && s[0] != '#')
+ {
+ if (Str_to_ValName(s, name, val))
+ {
+ if (name.IsEqualTo_Ascii_NoCase("CID"))
+ CID = val;
+ else if (name.IsEqualTo_Ascii_NoCase("parentCID"))
+ parentCID = val;
+ else if (name.IsEqualTo_Ascii_NoCase("createType"))
+ createType = val;
+ }
+ else
+ {
+ CExtentInfo ei;
+ if (!ei.Parse(s))
+ return false;
+ Extents.Add(ei);
+ }
+ }
+
+ s.Empty();
+ if (c == 0)
+ return true;
+ }
+ else
+ s += (char)c;
+ }
+}
+
+
+struct CExtent
+{
+ bool IsOK;
+ bool IsArc;
+ bool NeedDeflate;
+ bool Unsupported;
+ bool IsZero;
+ bool IsFlat;
+ bool DescriptorOK;
+ bool HeadersError;
+
+ unsigned ClusterBits;
+ UInt32 ZeroSector;
+
+ CObjectVector<CByteBuffer> Tables;
+
+ CMyComPtr<IInStream> Stream;
+ UInt64 PosInArc;
+
+ UInt64 PhySize;
+ UInt64 VirtSize; // from vmdk header of volume
+
+ UInt64 StartOffset; // virtual offset of this extent
+ UInt64 NumBytes; // from main descriptor, if multi-vol
+ UInt64 FlatOffset; // in Stream
+
+ CByteBuffer DescriptorBuf;
+ CDescriptor Descriptor;
+
+ CHeader h;
+
+ UInt64 GetEndOffset() const { return StartOffset + NumBytes; }
+
+ bool IsVmdk() const { return !IsZero && !IsFlat; }
+ // if (IsOK && IsVmdk()), then VMDK header of this extent was read
+
+ CExtent():
+ IsOK(false),
+ IsArc(false),
+ NeedDeflate(false),
+ Unsupported(false),
+ IsZero(false),
+ IsFlat(false),
+ DescriptorOK(false),
+ HeadersError(false),
+
+ ClusterBits(0),
+ ZeroSector(0),
+
+ PosInArc(0),
+
+ PhySize(0),
+ VirtSize(0),
+
+ StartOffset(0),
+ NumBytes(0),
+ FlatOffset(0)
+ {}
+
+
+ HRESULT ReadForHeader(IInStream *stream, UInt64 sector, void *data, size_t numSectors);
+ HRESULT Open3(IInStream *stream, IArchiveOpenCallback *openCallback,
+ unsigned numVols, unsigned volIndex, UInt64 &complexity);
+
+ HRESULT Seek(UInt64 offset)
+ {
+ PosInArc = offset;
+ return InStream_SeekSet(Stream, offset);
+ }
+
+ HRESULT InitAndSeek()
+ {
+ if (Stream)
+ return Seek(0);
+ return S_OK;
+ }
+
+ HRESULT Read(void *data, size_t *size)
+ {
+ HRESULT res = ReadStream(Stream, data, size);
+ PosInArc += *size;
+ return res;
+ }
+};
+
+
+Z7_class_CHandler_final: public CHandlerImg
+{
+ bool _isArc;
+ bool _unsupported;
+ bool _unsupportedSome;
+ bool _headerError;
+ bool _missingVol;
+ bool _isMultiVol;
+ bool _needDeflate;
+
+ UInt64 _cacheCluster;
+ unsigned _cacheExtent;
+ CByteBuffer _cache;
+ CByteBuffer _cacheCompressed;
+
+ unsigned _clusterBitsMax;
+ UInt64 _phySize;
+
+ CObjectVector<CExtent> _extents;
+
+ CBufInStream *_bufInStreamSpec;
+ CMyComPtr<ISequentialInStream> _bufInStream;
+
+ CBufPtrSeqOutStream *_bufOutStreamSpec;
+ CMyComPtr<ISequentialOutStream> _bufOutStream;
+
+ NCompress::NZlib::CDecoder *_zlibDecoderSpec;
+ CMyComPtr<ICompressCoder> _zlibDecoder;
+
+ CByteBuffer _descriptorBuf;
+ CDescriptor _descriptor;
+
+ UString _missingVolName;
+
+ void InitAndSeekMain()
+ {
+ _virtPos = 0;
+ }
+
+ virtual HRESULT Open2(IInStream *stream, IArchiveOpenCallback *openCallback) Z7_override;
+ virtual void CloseAtError() Z7_override;
+public:
+ Z7_IFACE_COM7_IMP(IInArchive_Img)
+
+ Z7_IFACE_COM7_IMP(IInArchiveGetStream)
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+};
+
+
+Z7_COM7F_IMF(CHandler::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (_virtPos >= _size)
+ return S_OK;
+ {
+ UInt64 rem = _size - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ if (size == 0)
+ return S_OK;
+ }
+
+ unsigned extentIndex;
+ {
+ unsigned left = 0, right = _extents.Size();
+ for (;;)
+ {
+ unsigned mid = (left + right) / 2;
+ if (mid == left)
+ break;
+ if (_virtPos < _extents[mid].StartOffset)
+ right = mid;
+ else
+ left = mid;
+ }
+ extentIndex = left;
+ }
+
+ CExtent &extent = _extents[extentIndex];
+
+ {
+ const UInt64 vir = _virtPos - extent.StartOffset;
+ if (vir >= extent.NumBytes)
+ {
+ return E_FAIL;
+ /*
+ if (vir > extent.NumBytes)
+ _stream_dataError = true;
+ memset(data, 0, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ */
+ }
+
+ {
+ const UInt64 rem = extent.NumBytes - vir;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ if (vir >= extent.VirtSize)
+ {
+ // if vmdk's VirtSize is smaller than VirtSize from main multi-volume descriptor
+ _stream_dataError = true;
+ return S_FALSE;
+ /*
+ memset(data, 0, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ */
+ }
+
+ {
+ const UInt64 rem = extent.VirtSize - vir;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ if (extent.IsZero || !extent.IsOK || !extent.Stream || extent.Unsupported)
+ {
+ if (extent.Unsupported)
+ {
+ _stream_unsupportedMethod = true;
+ return S_FALSE;
+ }
+ if (!extent.IsOK || !extent.Stream)
+ {
+ _stream_unavailData = true;
+ return S_FALSE;
+ }
+ memset(data, 0, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ }
+
+ if (extent.IsFlat)
+ {
+ UInt64 offset = extent.FlatOffset + vir;
+ if (offset != extent.PosInArc)
+ {
+ RINOK(extent.Seek(offset))
+ }
+ UInt32 size2 = 0;
+ HRESULT res = extent.Stream->Read(data, size, &size2);
+ if (res == S_OK && size2 == 0)
+ {
+ _stream_unavailData = true;
+ /*
+ memset(data, 0, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ */
+ }
+ // _stream_PackSize += size2;
+ extent.PosInArc += size2;
+ _virtPos += size2;
+ if (processedSize)
+ *processedSize = size2;
+ return res;
+ }
+ }
+
+
+ for (;;)
+ {
+ const UInt64 vir = _virtPos - extent.StartOffset;
+ const unsigned clusterBits = extent.ClusterBits;
+ const UInt64 cluster = vir >> clusterBits;
+ const size_t clusterSize = (size_t)1 << clusterBits;
+ const size_t lowBits = (size_t)vir & (clusterSize - 1);
+ {
+ size_t rem = clusterSize - lowBits;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ if (extentIndex == _cacheExtent && cluster == _cacheCluster)
+ {
+ memcpy(data, _cache + lowBits, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ }
+
+ const UInt64 high = cluster >> k_NumMidBits;
+
+ if (high < extent.Tables.Size())
+ {
+ const CByteBuffer &table = extent.Tables[(unsigned)high];
+
+ if (table.Size() != 0)
+ {
+ const size_t midBits = (size_t)cluster & ((1 << k_NumMidBits) - 1);
+ const Byte *p = (const Byte *)table + (midBits << 2);
+ const UInt32 v = Get32(p);
+
+ if (v != 0 && v != extent.ZeroSector)
+ {
+ UInt64 offset = (UInt64)v << 9;
+ if (extent.NeedDeflate)
+ {
+ if (offset != extent.PosInArc)
+ {
+ // printf("\n%12x %12x\n", (unsigned)offset, (unsigned)(offset - extent.PosInArc));
+ RINOK(extent.Seek(offset))
+ }
+
+ const size_t kStartSize = 1 << 9;
+ {
+ size_t curSize = kStartSize;
+ RINOK(extent.Read(_cacheCompressed, &curSize))
+ // _stream_PackSize += curSize;
+ if (curSize != kStartSize)
+ return S_FALSE;
+ }
+
+ if (Get64(_cacheCompressed) != (cluster << (clusterBits - 9)))
+ return S_FALSE;
+
+ UInt32 dataSize = Get32(_cacheCompressed + 8);
+ if (dataSize > ((UInt32)1 << 31))
+ return S_FALSE;
+
+ size_t dataSize2 = (size_t)dataSize + 12;
+
+ if (dataSize2 > kStartSize)
+ {
+ dataSize2 = (dataSize2 + 511) & ~(size_t)511;
+ if (dataSize2 > _cacheCompressed.Size())
+ return S_FALSE;
+ size_t curSize = dataSize2 - kStartSize;
+ const size_t curSize2 = curSize;
+ RINOK(extent.Read(_cacheCompressed + kStartSize, &curSize))
+ // _stream_PackSize += curSize;
+ if (curSize != curSize2)
+ return S_FALSE;
+ }
+
+ _bufInStreamSpec->Init(_cacheCompressed + 12, dataSize);
+
+ _cacheCluster = (UInt64)(Int64)-1;
+ _cacheExtent = (unsigned)(int)-1;
+
+ if (_cache.Size() < clusterSize)
+ return E_FAIL;
+ _bufOutStreamSpec->Init(_cache, clusterSize);
+
+ // Do we need to use smaller block than clusterSize for last cluster?
+ const UInt64 blockSize64 = clusterSize;
+ HRESULT res = _zlibDecoder->Code(_bufInStream, _bufOutStream, NULL, &blockSize64, NULL);
+
+ /*
+ if (_bufOutStreamSpec->GetPos() != clusterSize)
+ {
+ _stream_dataError = true;
+ memset(_cache + _bufOutStreamSpec->GetPos(), 0, clusterSize - _bufOutStreamSpec->GetPos());
+ }
+ */
+
+ if (_bufOutStreamSpec->GetPos() != clusterSize
+ || _zlibDecoderSpec->GetInputProcessedSize() != dataSize)
+ {
+ _stream_dataError = true;
+ if (res == S_OK)
+ res = S_FALSE;
+ }
+
+ RINOK(res)
+
+ _cacheCluster = cluster;
+ _cacheExtent = extentIndex;
+
+ continue;
+ /*
+ memcpy(data, _cache + lowBits, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ */
+ }
+ {
+ offset += lowBits;
+ if (offset != extent.PosInArc)
+ {
+ // printf("\n%12x %12x\n", (unsigned)offset, (unsigned)(offset - extent.PosInArc));
+ RINOK(extent.Seek(offset))
+ }
+ UInt32 size2 = 0;
+ HRESULT res = extent.Stream->Read(data, size, &size2);
+ if (res == S_OK && size2 == 0)
+ {
+ _stream_unavailData = true;
+ /*
+ memset(data, 0, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ */
+ }
+ extent.PosInArc += size2;
+ // _stream_PackSize += size2;
+ _virtPos += size2;
+ if (processedSize)
+ *processedSize = size2;
+ return res;
+ }
+ }
+ }
+ }
+
+ memset(data, 0, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ }
+}
+
+
+static const Byte kProps[] =
+{
+ kpidSize,
+ kpidPackSize
+};
+
+static const Byte kArcProps[] =
+{
+ kpidNumVolumes,
+ kpidTotalPhySize,
+ kpidMethod,
+ kpidClusterSize,
+ kpidHeadersSize,
+ kpidId,
+ kpidName,
+ kpidComment
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ const CExtent *e = NULL;
+ const CDescriptor *desc = NULL;
+
+ if (_isMultiVol)
+ desc = &_descriptor;
+ else if (_extents.Size() == 1)
+ {
+ e = &_extents[0];
+ desc = &e->Descriptor;
+ }
+
+ switch (propID)
+ {
+ case kpidMainSubfile: prop = (UInt32)0; break;
+ case kpidPhySize: if (_phySize != 0) prop = _phySize; break;
+ case kpidTotalPhySize:
+ {
+ UInt64 sum = _phySize;
+ if (_isMultiVol)
+ {
+ FOR_VECTOR (i, _extents)
+ sum += _extents[i].PhySize;
+ }
+ prop = sum;
+ break;
+ }
+ case kpidClusterSize: prop = (UInt32)((UInt32)1 << _clusterBitsMax); break;
+ case kpidHeadersSize: if (e) prop = (e->h.overHead << 9); break;
+ case kpidMethod:
+ {
+ AString s;
+
+ if (desc && !desc->createType.IsEmpty())
+ s = desc->createType;
+
+ bool zlib = false;
+ bool marker = false;
+ int algo = -1;
+
+ FOR_VECTOR (i, _extents)
+ {
+ const CExtent &extent = _extents[i];
+ if (!extent.IsOK || !extent.IsVmdk())
+ continue;
+
+ const CHeader &h = extent.h;
+
+ if (h.algo != 0)
+ {
+ if (h.algo == 1)
+ zlib = true;
+ else if (algo != (int)h.algo)
+ {
+ s.Add_Space_if_NotEmpty();
+ s.Add_UInt32(h.algo);
+ algo = h.algo;
+ }
+ }
+
+ if (h.Is_Marker())
+ marker = true;
+ }
+
+ if (zlib)
+ s.Add_OptSpaced("zlib");
+
+ if (marker)
+ s.Add_OptSpaced("Marker");
+
+ if (!s.IsEmpty())
+ prop = s;
+ break;
+ }
+
+ case kpidComment:
+ {
+ if (e && e->DescriptorBuf.Size() != 0)
+ {
+ AString s;
+ s.SetFrom_CalcLen((const char *)(const Byte *)e->DescriptorBuf, (unsigned)e->DescriptorBuf.Size());
+ if (!s.IsEmpty() && s.Len() <= (1 << 16))
+ prop = s;
+ }
+ break;
+ }
+
+ case kpidId:
+ {
+ if (desc && !desc->CID.IsEmpty())
+ {
+ prop = desc->CID;
+ }
+ break;
+ }
+
+ case kpidName:
+ {
+ if (!_isMultiVol && desc && desc->Extents.Size() == 1)
+ {
+ const CExtentInfo &ei = desc->Extents[0];
+ if (!ei.FileName.IsEmpty())
+ {
+ UString u;
+ CDescriptor::GetUnicodeName(ei.FileName, u);
+ if (!u.IsEmpty())
+ prop = u;
+ }
+ }
+ break;
+ }
+
+ case kpidNumVolumes: if (_isMultiVol) prop = (UInt32)_extents.Size(); break;
+
+ case kpidError:
+ {
+ if (_missingVol || !_missingVolName.IsEmpty())
+ {
+ UString s ("Missing volume : ");
+ if (!_missingVolName.IsEmpty())
+ s += _missingVolName;
+ prop = s;
+ }
+ break;
+ }
+
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (_unsupported) v |= kpv_ErrorFlags_UnsupportedMethod;
+ if (_unsupportedSome) v |= kpv_ErrorFlags_UnsupportedMethod;
+ if (_headerError) v |= kpv_ErrorFlags_HeadersError;
+ // if (_missingVol) v |= kpv_ErrorFlags_UnexpectedEnd;
+ if (v != 0)
+ prop = v;
+ break;
+ }
+ }
+
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ switch (propID)
+ {
+ case kpidSize: prop = _size; break;
+ case kpidPackSize:
+ {
+ UInt64 packSize = 0;
+ FOR_VECTOR (i, _extents)
+ {
+ const CExtent &e = _extents[i];
+ if (!e.IsOK)
+ continue;
+ if (e.IsVmdk() && !_isMultiVol)
+ {
+ UInt64 ov = (e.h.overHead << 9);
+ if (e.PhySize >= ov)
+ packSize += e.PhySize - ov;
+ }
+ else
+ packSize += e.PhySize;
+ }
+ prop = packSize;
+ break;
+ }
+ case kpidExtension: prop = (_imgExt ? _imgExt : "img"); break;
+ }
+
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+static int inline GetLog(UInt64 num)
+{
+ for (int i = 0; i < 64; i++)
+ if (((UInt64)1 << i) == num)
+ return i;
+ return -1;
+}
+
+
+HRESULT CExtent::ReadForHeader(IInStream *stream, UInt64 sector, void *data, size_t numSectors)
+{
+ sector <<= 9;
+ RINOK(InStream_SeekSet(stream, sector))
+ size_t size = numSectors << 9;
+ RINOK(ReadStream_FALSE(stream, data, size))
+ UInt64 end = sector + size;
+ if (PhySize < end)
+ PhySize = end;
+ return S_OK;
+}
+
+
+void CHandler::CloseAtError()
+{
+ _extents.Clear();
+ CHandlerImg::CloseAtError();
+}
+
+
+static const char * const kSignature_Descriptor = "# Disk DescriptorFile";
+
+
+HRESULT CHandler::Open2(IInStream *stream, IArchiveOpenCallback *openCallback)
+{
+ const unsigned kSectoreSize = 512;
+ Byte buf[kSectoreSize];
+ size_t headerSize = kSectoreSize;
+ RINOK(ReadStream(stream, buf, &headerSize))
+
+ if (headerSize < sizeof(k_Signature))
+ return S_FALSE;
+
+ CMyComPtr<IArchiveOpenVolumeCallback> volumeCallback;
+
+ if (memcmp(buf, k_Signature, sizeof(k_Signature)) != 0)
+ {
+ const size_t k_SigDesc_Size = strlen(kSignature_Descriptor);
+ if (headerSize < k_SigDesc_Size)
+ return S_FALSE;
+ if (memcmp(buf, kSignature_Descriptor, k_SigDesc_Size) != 0)
+ return S_FALSE;
+
+ UInt64 endPos;
+ RINOK(InStream_GetSize_SeekToEnd(stream, endPos))
+ if (endPos > (1 << 20))
+ return S_FALSE;
+ const size_t numBytes = (size_t)endPos;
+ _descriptorBuf.Alloc(numBytes);
+ RINOK(InStream_SeekToBegin(stream))
+ RINOK(ReadStream_FALSE(stream, _descriptorBuf, numBytes))
+
+ if (!_descriptor.Parse(_descriptorBuf, _descriptorBuf.Size()))
+ return S_FALSE;
+ _isMultiVol = true;
+ _isArc = true;
+ _phySize = numBytes;
+ if (_descriptor.IsThere_Parent())
+ _unsupported = true;
+
+ if (openCallback)
+ {
+ openCallback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volumeCallback);
+ }
+ if (!volumeCallback)
+ {
+ _unsupported = true;
+ return E_NOTIMPL;
+ }
+
+ /*
+ UInt64 totalVirtSize = 0;
+ FOR_VECTOR (i, _descriptor.Extents)
+ {
+ const CExtentInfo &ei = _descriptor.Extents[i];
+ if (ei.NumSectors >= ((UInt64)1 << (63 - 9)))
+ return S_FALSE;
+ totalVirtSize += ei.NumSectors;
+ if (totalVirtSize >= ((UInt64)1 << (63 - 9)))
+ return S_FALSE;
+ }
+ totalVirtSize <<= 9;
+ */
+
+ if (_descriptor.Extents.Size() > 1)
+ {
+ const UInt64 numFiles = _descriptor.Extents.Size();
+ RINOK(openCallback->SetTotal(&numFiles, NULL))
+ }
+ }
+
+ UInt64 complexity = 0;
+
+ for (;;)
+ {
+ CExtent *e = NULL;
+ CMyComPtr<IInStream> nextStream;
+
+ if (_isMultiVol)
+ {
+ const unsigned extentIndex = _extents.Size();
+ if (extentIndex >= _descriptor.Extents.Size())
+ break;
+ const CExtentInfo &ei = _descriptor.Extents[extentIndex];
+ e = &_extents.AddNew();
+ e->StartOffset = 0;
+ if (ei.NumSectors >= ((UInt64)1 << (62 - 9)) ||
+ ei.StartSector >= ((UInt64)1 << (62 - 9)))
+ return S_FALSE;
+ e->NumBytes = ei.NumSectors << 9;
+ e->IsZero = ei.IsType_ZERO();
+ if (extentIndex != 0)
+ e->StartOffset = _extents[extentIndex - 1].GetEndOffset();
+ if (e->GetEndOffset() < e->StartOffset)
+ return S_FALSE;
+
+ e->VirtSize = e->NumBytes;
+ if (e->IsZero)
+ {
+ e->IsOK = true;
+ continue;
+ }
+
+ e->IsFlat = ei.IsType_Flat();
+ e->FlatOffset = ei.StartSector << 9;
+
+ UString u;
+ CDescriptor::GetUnicodeName(ei.FileName, u);
+ if (u.IsEmpty())
+ {
+ _missingVol = true;
+ continue;
+ }
+
+ HRESULT result = volumeCallback->GetStream(u, &nextStream);
+
+ if (result != S_OK && result != S_FALSE)
+ return result;
+
+ if (!nextStream || result != S_OK)
+ {
+ if (_missingVolName.IsEmpty())
+ _missingVolName = u;
+ _missingVol = true;
+ continue;
+ }
+
+ if (e->IsFlat)
+ {
+ e->IsOK = true;
+ e->Stream = nextStream;
+ e->PhySize = e->NumBytes;
+ continue;
+ }
+
+ stream = nextStream;
+
+ headerSize = kSectoreSize;
+ RINOK(ReadStream(stream, buf, &headerSize))
+
+ if (headerSize != kSectoreSize)
+ continue;
+ if (memcmp(buf, k_Signature, sizeof(k_Signature)) != 0)
+ continue;
+ }
+ else
+ {
+ if (headerSize != kSectoreSize)
+ return S_FALSE;
+ e = &_extents.AddNew();
+ e->StartOffset = 0;
+ }
+
+ HRESULT res = S_FALSE;
+ if (e->h.Parse(buf))
+ res = e->Open3(stream, openCallback, _isMultiVol ? _descriptor.Extents.Size() : 1, _extents.Size() - 1, complexity);
+
+ if (!_isMultiVol)
+ {
+ _isArc = e->IsArc;
+ _phySize = e->PhySize;
+ _unsupported = e->Unsupported;
+ }
+
+ if (e->Unsupported)
+ _unsupportedSome = true;
+ if (e->HeadersError)
+ _headerError = true;
+
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ return res;
+ if (!_isMultiVol)
+ return res;
+ continue;
+ }
+
+ e->Stream = stream;
+ e->IsOK = true;
+
+ if (!_isMultiVol)
+ {
+ e->NumBytes = e->VirtSize;
+ break;
+ }
+
+ if (e->NumBytes != e->VirtSize)
+ _headerError = true;
+ }
+
+ if (!_extents.IsEmpty())
+ _size = _extents.Back().GetEndOffset();
+
+ _needDeflate = false;
+ _clusterBitsMax = 0;
+
+ // unsigned numOKs = 0;
+ unsigned numUnsupported = 0;
+
+ FOR_VECTOR (i, _extents)
+ {
+ const CExtent &e = _extents[i];
+ if (e.Unsupported)
+ numUnsupported++;
+ if (!e.IsOK)
+ continue;
+ // numOKs++;
+ if (e.IsVmdk())
+ {
+ if (e.NeedDeflate)
+ _needDeflate = true;
+ if (_clusterBitsMax < e.ClusterBits)
+ _clusterBitsMax = e.ClusterBits;
+ }
+ }
+
+ if (numUnsupported != 0 && numUnsupported == _extents.Size())
+ _unsupported = true;
+
+ return S_OK;
+}
+
+
+HRESULT CExtent::Open3(IInStream *stream, IArchiveOpenCallback *openCallback,
+ unsigned numVols, unsigned volIndex, UInt64 &complexity)
+{
+ if (h.descriptorSize != 0)
+ {
+ if (h.descriptorOffset == 0 ||
+ h.descriptorSize > (1 << 10))
+ return S_FALSE;
+ DescriptorBuf.Alloc((size_t)h.descriptorSize << 9);
+ RINOK(ReadForHeader(stream, h.descriptorOffset, DescriptorBuf, (size_t)h.descriptorSize))
+ if (h.descriptorOffset == 1 && h.Is_Marker() && Get64(DescriptorBuf) == 0)
+ {
+ // We check data as end marker.
+ // and if probably it's footer's copy of header, we don't want to open it.
+ return S_FALSE;
+ }
+
+ DescriptorOK = Descriptor.Parse(DescriptorBuf, DescriptorBuf.Size());
+ if (!DescriptorOK)
+ HeadersError = true;
+ if (Descriptor.IsThere_Parent())
+ Unsupported = true;
+ }
+
+ if (h.gdOffset == (UInt64)(Int64)-1)
+ {
+ // Grain Dir is at end of file
+ UInt64 endPos;
+ RINOK(InStream_GetSize_SeekToEnd(stream, endPos))
+ if ((endPos & 511) != 0)
+ return S_FALSE;
+
+ const size_t kEndSize = 512 * 3;
+ Byte buf2[kEndSize];
+ if (endPos < kEndSize)
+ return S_FALSE;
+ RINOK(InStream_SeekSet(stream, endPos - kEndSize))
+ RINOK(ReadStream_FALSE(stream, buf2, kEndSize))
+
+ CHeader h2;
+ if (!h2.Parse(buf2 + 512))
+ return S_FALSE;
+ if (!h.IsSameImageFor(h2))
+ return S_FALSE;
+
+ h = h2;
+
+ CMarker m;
+ m.Parse(buf2);
+ if (m.NumSectors != 1 || m.SpecSize != 0 || m.Type != k_Marker_FOOTER)
+ return S_FALSE;
+ m.Parse(buf2 + 512 * 2);
+ if (m.NumSectors != 0 || m.SpecSize != 0 || m.Type != k_Marker_END_OF_STREAM)
+ return S_FALSE;
+ PhySize = endPos;
+ }
+
+ const int grainSize_Log = GetLog(h.grainSize);
+ if (grainSize_Log < 3 || grainSize_Log > 30 - 9) // grain size must be >= 4 KB
+ return S_FALSE;
+ if (h.capacity >= ((UInt64)1 << (63 - 9)))
+ return S_FALSE;
+ if (h.overHead >= ((UInt64)1 << (63 - 9)))
+ return S_FALSE;
+
+ IsArc = true;
+ ClusterBits = (9 + (unsigned)grainSize_Log);
+ VirtSize = h.capacity << 9;
+ NeedDeflate = (h.algo >= 1);
+
+ if (h.Is_Compressed() ? (h.algo > 1 || !h.Is_Marker()) : (h.algo != 0))
+ {
+ Unsupported = true;
+ PhySize = 0;
+ return S_FALSE;
+ }
+
+ {
+ const UInt64 overHeadBytes = h.overHead << 9;
+ if (PhySize < overHeadBytes)
+ PhySize = overHeadBytes;
+ }
+
+ ZeroSector = 0;
+ if (h.Is_ZeroGrain())
+ ZeroSector = 1;
+
+ const UInt64 numSectorsPerGde = (UInt64)1 << ((unsigned)grainSize_Log + k_NumMidBits);
+ const UInt64 numGdeEntries = (h.capacity + numSectorsPerGde - 1) >> ((unsigned)grainSize_Log + k_NumMidBits);
+ CByteBuffer table;
+
+ if (numGdeEntries != 0)
+ {
+ if (h.gdOffset == 0)
+ return S_FALSE;
+
+ size_t numSectors = (size_t)((numGdeEntries + ((1 << (9 - 2)) - 1)) >> (9 - 2));
+ size_t t1SizeBytes = numSectors << 9;
+ if ((t1SizeBytes >> 2) < numGdeEntries)
+ return S_FALSE;
+ table.Alloc(t1SizeBytes);
+
+ if (h.Is_Marker())
+ {
+ Byte buf2[1 << 9];
+ if (ReadForHeader(stream, h.gdOffset - 1, buf2, 1) != S_OK)
+ return S_FALSE;
+ {
+ CMarker m;
+ m.Parse(buf2);
+ if (m.Type != k_Marker_GRAIN_DIR
+ || m.NumSectors != numSectors
+ || m.SpecSize != 0)
+ return S_FALSE;
+ }
+ }
+
+ RINOK(ReadForHeader(stream, h.gdOffset, table, numSectors))
+ }
+
+ const size_t clusterSize = (size_t)1 << ClusterBits;
+
+ const UInt64 complexityStart = complexity;
+
+ if (openCallback)
+ {
+ complexity += (UInt64)numGdeEntries << (k_NumMidBits + 2);
+ {
+ const UInt64 numVols2 = numVols;
+ RINOK(openCallback->SetTotal((numVols == 1) ? NULL : &numVols2, &complexity))
+ }
+ if (numVols != 1)
+ {
+ const UInt64 volIndex2 = volIndex;
+ RINOK(openCallback->SetCompleted(numVols == 1 ? NULL : &volIndex2, &complexityStart))
+ }
+ }
+
+ UInt64 lastSector = 0;
+ UInt64 lastVirtCluster = 0;
+ size_t numProcessed_Prev = 0;
+
+ for (size_t i = 0; i < numGdeEntries; i++)
+ {
+ const size_t k_NumSectors = (size_t)1 << (k_NumMidBits - 9 + 2);
+ const size_t k_NumMidItems = (size_t)1 << k_NumMidBits;
+
+ CByteBuffer &buf = Tables.AddNew();
+
+ {
+ const UInt32 v = Get32((const Byte *)table + (size_t)i * 4);
+ if (v == 0 || v == ZeroSector)
+ continue;
+ if (openCallback && (i - numProcessed_Prev) >= 1024)
+ {
+ const UInt64 comp = complexityStart + ((UInt64)i << (k_NumMidBits + 2));
+ const UInt64 volIndex2 = volIndex;
+ RINOK(openCallback->SetCompleted(numVols == 1 ? NULL : &volIndex2, &comp))
+ numProcessed_Prev = i;
+ }
+
+ if (h.Is_Marker())
+ {
+ Byte buf2[1 << 9];
+ if (ReadForHeader(stream, v - 1, buf2, 1) != S_OK)
+ return S_FALSE;
+ {
+ CMarker m;
+ m.Parse(buf2);
+ if (m.Type != k_Marker_GRAIN_TABLE
+ || m.NumSectors != k_NumSectors
+ || m.SpecSize != 0)
+ return S_FALSE;
+ }
+ }
+
+ buf.Alloc(k_NumMidItems * 4);
+ RINOK(ReadForHeader(stream, v, buf, k_NumSectors))
+ }
+
+ for (size_t k = 0; k < k_NumMidItems; k++)
+ {
+ const UInt32 v = Get32((const Byte *)buf + (size_t)k * 4);
+ if (v == 0 || v == ZeroSector)
+ continue;
+ if (v < h.overHead)
+ return S_FALSE;
+ if (lastSector < v)
+ {
+ lastSector = v;
+ if (NeedDeflate)
+ lastVirtCluster = ((UInt64)i << k_NumMidBits) + k;
+ }
+ }
+ }
+
+ if (!NeedDeflate)
+ {
+ UInt64 end = ((UInt64)lastSector << 9) + clusterSize;
+ if (PhySize < end)
+ PhySize = end;
+ }
+ else if (lastSector != 0)
+ {
+ Byte buf[1 << 9];
+ if (ReadForHeader(stream, lastSector, buf, 1) == S_OK)
+ {
+ UInt64 lba = Get64(buf);
+ if (lba == (lastVirtCluster << (ClusterBits - 9)))
+ {
+ UInt32 dataSize = Get32(buf + 8);
+ size_t dataSize2 = (size_t)dataSize + 12;
+ dataSize2 = (dataSize2 + 511) & ~(size_t)511;
+ UInt64 end = ((UInt64)lastSector << 9) + dataSize2;
+ if (PhySize < end)
+ PhySize = end;
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _phySize = 0;
+
+ _cacheCluster = (UInt64)(Int64)-1;
+ _cacheExtent = (unsigned)(int)-1;
+
+ _clusterBitsMax = 0;
+
+ _isArc = false;
+ _unsupported = false;
+ _unsupportedSome = false;
+ _headerError = false;
+ _missingVol = false;
+ _isMultiVol = false;
+ _needDeflate = false;
+
+ _missingVolName.Empty();
+
+ _descriptorBuf.Free();
+ _descriptor.Clear();
+
+ // CHandlerImg:
+ Clear_HandlerImg_Vars();
+ Stream.Release();
+
+ _extents.Clear();
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 /* index */, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ *stream = NULL;
+
+ if (_unsupported)
+ return S_FALSE;
+
+ ClearStreamVars();
+ // _stream_UsePackSize = true;
+
+ if (_needDeflate)
+ {
+ if (!_bufInStream)
+ {
+ _bufInStreamSpec = new CBufInStream;
+ _bufInStream = _bufInStreamSpec;
+ }
+
+ if (!_bufOutStream)
+ {
+ _bufOutStreamSpec = new CBufPtrSeqOutStream();
+ _bufOutStream = _bufOutStreamSpec;
+ }
+
+ if (!_zlibDecoder)
+ {
+ _zlibDecoderSpec = new NCompress::NZlib::CDecoder;
+ _zlibDecoder = _zlibDecoderSpec;
+ }
+
+ const size_t clusterSize = (size_t)1 << _clusterBitsMax;
+ _cache.AllocAtLeast(clusterSize);
+ _cacheCompressed.AllocAtLeast(clusterSize * 2);
+ }
+
+ FOR_VECTOR (i, _extents)
+ {
+ RINOK(_extents[i].InitAndSeek())
+ }
+
+ CMyComPtr<ISequentialInStream> streamTemp = this;
+ InitAndSeekMain();
+ *stream = streamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+
+REGISTER_ARC_I(
+ "VMDK", "vmdk", NULL, 0xC8,
+ k_Signature,
+ 0,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/Wim/StdAfx.h b/CPP/7zip/Archive/Wim/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/StdAfx.h
@@ -0,0 +1,11 @@
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Archive/Wim/WimHandler.cpp b/CPP/7zip/Archive/Wim/WimHandler.cpp
new file mode 100644
index 0000000..7f96dcc
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/WimHandler.cpp
@@ -0,0 +1,1236 @@
+// WimHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+
+#include "../../Common/MethodProps.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamUtils.h"
+
+#include "WimHandler.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NWim {
+
+#define FILES_DIR_NAME "[DELETED]"
+
+// #define WIM_DETAILS
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidCTime,
+ kpidATime,
+ kpidAttrib,
+ kpidMethod,
+ kpidSolid,
+ kpidShortName,
+ kpidINode,
+ kpidLinks,
+ kpidIsAltStream,
+ kpidNumAltStreams,
+
+ #ifdef WIM_DETAILS
+ , kpidVolume
+ , kpidOffset
+ #endif
+};
+
+enum
+{
+ kpidNumImages = kpidUserDefined,
+ kpidBootImage
+};
+
+static const CStatProp kArcProps[] =
+{
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidPackSize, VT_UI8},
+ { NULL, kpidMethod, VT_BSTR},
+ { NULL, kpidClusterSize, VT_UI4},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidComment, VT_BSTR},
+ { NULL, kpidUnpackVer, VT_BSTR},
+ { NULL, kpidIsVolume, VT_BOOL},
+ { NULL, kpidVolume, VT_UI4},
+ { NULL, kpidNumVolumes, VT_UI4},
+ { "Images", kpidNumImages, VT_UI4},
+ { "Boot Image", kpidBootImage, VT_UI4}
+};
+
+
+static const char * const k_Methods[] =
+{
+ "Copy"
+ , "XPress"
+ , "LZX"
+ , "LZMS"
+};
+
+
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_WITH_NAME
+
+static void AddErrorMessage(AString &s, const char *message)
+{
+ if (!s.IsEmpty())
+ s += ". ";
+ s += message;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ const CImageInfo *image = NULL;
+ if (_xmls.Size() == 1)
+ {
+ const CWimXml &xml = _xmls[0];
+ if (xml.Images.Size() == 1)
+ image = &xml.Images[0];
+ }
+
+ switch (propID)
+ {
+ case kpidPhySize: prop = _phySize; break;
+ case kpidSize: prop = _db.GetUnpackSize(); break;
+ case kpidPackSize: prop = _db.GetPackSize(); break;
+
+ case kpidCTime:
+ if (_xmls.Size() == 1)
+ {
+ const CWimXml &xml = _xmls[0];
+ int index = -1;
+ FOR_VECTOR (i, xml.Images)
+ {
+ const CImageInfo &image2 = xml.Images[i];
+ if (image2.CTimeDefined)
+ if (index < 0 || ::CompareFileTime(&image2.CTime, &xml.Images[index].CTime) < 0)
+ index = (int)i;
+ }
+ if (index >= 0)
+ prop = xml.Images[index].CTime;
+ }
+ break;
+
+ case kpidMTime:
+ if (_xmls.Size() == 1)
+ {
+ const CWimXml &xml = _xmls[0];
+ int index = -1;
+ FOR_VECTOR (i, xml.Images)
+ {
+ const CImageInfo &image2 = xml.Images[i];
+ if (image2.MTimeDefined)
+ if (index < 0 || ::CompareFileTime(&image2.MTime, &xml.Images[index].MTime) > 0)
+ index = (int)i;
+ }
+ if (index >= 0)
+ prop = xml.Images[index].MTime;
+ }
+ break;
+
+ case kpidComment:
+ if (image)
+ {
+ if (_xmlInComments)
+ {
+ UString s;
+ _xmls[0].ToUnicode(s);
+ prop = s;
+ }
+ else if (image->NameDefined)
+ prop = image->Name;
+ }
+ break;
+
+ case kpidUnpackVer:
+ {
+ UInt32 ver1 = _version >> 16;
+ UInt32 ver2 = (_version >> 8) & 0xFF;
+ UInt32 ver3 = (_version) & 0xFF;
+
+ AString res;
+ res.Add_UInt32(ver1);
+ res.Add_Dot();
+ res.Add_UInt32(ver2);
+ if (ver3 != 0)
+ {
+ res.Add_Dot();
+ res.Add_UInt32(ver3);
+ }
+ prop = res;
+ break;
+ }
+
+ case kpidIsVolume:
+ if (_xmls.Size() > 0)
+ {
+ UInt16 volIndex = _xmls[0].VolIndex;
+ if (volIndex < _volumes.Size())
+ prop = (_volumes[volIndex].Header.NumParts > 1);
+ }
+ break;
+ case kpidVolume:
+ if (_xmls.Size() > 0)
+ {
+ UInt16 volIndex = _xmls[0].VolIndex;
+ if (volIndex < _volumes.Size())
+ prop = (UInt32)_volumes[volIndex].Header.PartNumber;
+ }
+ break;
+ case kpidNumVolumes: if (_volumes.Size() > 0) prop = (UInt32)(_volumes.Size() - 1); break;
+
+ case kpidClusterSize:
+ if (_xmls.Size() > 0)
+ {
+ UInt16 volIndex = _xmls[0].VolIndex;
+ if (volIndex < _volumes.Size())
+ {
+ const CHeader &h = _volumes[volIndex].Header;
+ prop = (UInt32)1 << h.ChunkSizeBits;
+ }
+ }
+ break;
+
+ case kpidName:
+ if (_firstVolumeIndex >= 0)
+ {
+ const CHeader &h = _volumes[_firstVolumeIndex].Header;
+ if (GetUi32(h.Guid) != 0)
+ {
+ char temp[64];
+ RawLeGuidToString(h.Guid, temp);
+ temp[8] = 0; // for reduced GUID
+ AString s (temp);
+ const char *ext = ".wim";
+ if (h.NumParts != 1)
+ {
+ s += '_';
+ if (h.PartNumber != 1)
+ s.Add_UInt32(h.PartNumber);
+ ext = ".swm";
+ }
+ s += ext;
+ prop = s;
+ }
+ }
+ break;
+
+ case kpidExtension:
+ if (_firstVolumeIndex >= 0)
+ {
+ const CHeader &h = _volumes[_firstVolumeIndex].Header;
+ if (h.NumParts > 1)
+ {
+ AString s;
+ if (h.PartNumber != 1)
+ {
+ s.Add_UInt32(h.PartNumber);
+ s.Add_Dot();
+ }
+ s += "swm";
+ prop = s;
+ }
+ }
+ break;
+
+ case kpidNumImages: prop = (UInt32)_db.Images.Size(); break;
+ case kpidBootImage: if (_bootIndex != 0) prop = (UInt32)_bootIndex; break;
+
+ case kpidMethod:
+ {
+ UInt32 methodUnknown = 0;
+ UInt32 methodMask = 0;
+ unsigned chunkSizeBits = 0;
+
+ {
+ FOR_VECTOR (i, _xmls)
+ {
+ const CHeader &header = _volumes[_xmls[i].VolIndex].Header;
+ unsigned method = header.GetMethod();
+ if (method < Z7_ARRAY_SIZE(k_Methods))
+ methodMask |= ((UInt32)1 << method);
+ else
+ methodUnknown = method;
+ if (chunkSizeBits < header.ChunkSizeBits)
+ chunkSizeBits = header.ChunkSizeBits;
+ }
+ }
+
+ AString res;
+
+ unsigned numMethods = 0;
+
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_Methods); i++)
+ {
+ if (methodMask & ((UInt32)1 << i))
+ {
+ res.Add_Space_if_NotEmpty();
+ res += k_Methods[i];
+ numMethods++;
+ }
+ }
+
+ if (methodUnknown != 0)
+ {
+ res.Add_Space_if_NotEmpty();
+ res.Add_UInt32(methodUnknown);
+ numMethods++;
+ }
+
+ if (numMethods == 1 && chunkSizeBits != 0)
+ {
+ res += ':';
+ res.Add_UInt32((UInt32)chunkSizeBits);
+ }
+
+ prop = res;
+ break;
+ }
+
+ case kpidIsTree: prop = true; break;
+ case kpidIsAltStream: prop = _db.ThereAreAltStreams; break;
+ case kpidIsAux: prop = true; break;
+ // WIM uses special prefix to represent deleted items
+ // case kpidIsDeleted: prop = _db.ThereAreDeletedStreams; break;
+ case kpidINode: prop = true; break;
+
+ case kpidErrorFlags:
+ {
+ UInt32 flags = 0;
+ if (!_isArc) flags |= kpv_ErrorFlags_IsNotArc;
+ if (_db.HeadersError) flags |= kpv_ErrorFlags_HeadersError;
+ if (_unsupported) flags |= kpv_ErrorFlags_UnsupportedMethod;
+ prop = flags;
+ break;
+ }
+
+ case kpidWarning:
+ {
+ AString s;
+ if (_xmlError)
+ AddErrorMessage(s, "XML error");
+ if (_db.RefCountError)
+ AddErrorMessage(s, "Some files have incorrect reference count");
+ if (!s.IsEmpty())
+ prop = s;
+ break;
+ }
+
+ case kpidReadOnly:
+ {
+ bool readOnly = !IsUpdateSupported();
+ if (readOnly)
+ prop = readOnly;
+ break;
+ }
+ }
+
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+static void GetFileTime(const Byte *p, NCOM::CPropVariant &prop)
+{
+ prop.vt = VT_FILETIME;
+ prop.filetime.dwLowDateTime = Get32(p);
+ prop.filetime.dwHighDateTime = Get32(p + 4);
+ prop.Set_FtPrec(k_PropVar_TimePrec_100ns);
+}
+
+
+static void MethodToProp(int method, int chunksSizeBits, NCOM::CPropVariant &prop)
+{
+ if (method >= 0)
+ {
+ char temp[32];
+
+ if ((unsigned)method < Z7_ARRAY_SIZE(k_Methods))
+ MyStringCopy(temp, k_Methods[(unsigned)method]);
+ else
+ ConvertUInt32ToString((UInt32)(unsigned)method, temp);
+
+ if (chunksSizeBits >= 0)
+ {
+ size_t pos = strlen(temp);
+ temp[pos++] = ':';
+ ConvertUInt32ToString((unsigned)chunksSizeBits, temp + pos);
+ }
+
+ prop = temp;
+ }
+}
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ if (index < _db.SortedItems.Size())
+ {
+ unsigned realIndex = _db.SortedItems[index];
+ const CItem &item = _db.Items[realIndex];
+ const CStreamInfo *si = NULL;
+ const CVolume *vol = NULL;
+ if (item.StreamIndex >= 0)
+ {
+ si = &_db.DataStreams[item.StreamIndex];
+ vol = &_volumes[si->PartNumber];
+ }
+
+ const CItem *mainItem = &item;
+ if (item.IsAltStream)
+ mainItem = &_db.Items[item.Parent];
+ const Byte *metadata = NULL;
+ if (mainItem->ImageIndex >= 0)
+ metadata = _db.Images[mainItem->ImageIndex].Meta + mainItem->Offset;
+
+ switch (propID)
+ {
+ case kpidPath:
+ if (item.ImageIndex >= 0)
+ _db.GetItemPath(realIndex, _showImageNumber, prop);
+ else
+ {
+ /*
+ while (s.Len() < _nameLenForStreams)
+ s = '0' + s;
+ */
+ /*
+ if (si->Resource.IsFree())
+ s = (AString)("[Free]" STRING_PATH_SEPARATOR) + sz;
+ else
+ */
+ AString s (FILES_DIR_NAME STRING_PATH_SEPARATOR);
+ s.Add_UInt32((UInt32)(Int32)item.StreamIndex);
+ prop = s;
+ }
+ break;
+
+ case kpidName:
+ if (item.ImageIndex >= 0)
+ _db.GetItemName(realIndex, prop);
+ else
+ {
+ char sz[16];
+ ConvertUInt32ToString((UInt32)(Int32)item.StreamIndex, sz);
+ /*
+ AString s = sz;
+ while (s.Len() < _nameLenForStreams)
+ s = '0' + s;
+ */
+ prop = sz;
+ }
+ break;
+
+ case kpidShortName:
+ if (item.ImageIndex >= 0 && !item.IsAltStream)
+ _db.GetShortName(realIndex, prop);
+ break;
+
+ case kpidPackSize:
+ {
+ if (si)
+ {
+ if (!si->Resource.IsSolidSmall())
+ prop = si->Resource.PackSize;
+ else
+ {
+ if (si->Resource.SolidIndex >= 0)
+ {
+ const CSolid &ss = _db.Solids[(unsigned)si->Resource.SolidIndex];
+ if (ss.FirstSmallStream == item.StreamIndex)
+ prop = _db.DataStreams[ss.StreamIndex].Resource.PackSize;
+ }
+ }
+ }
+ else if (!item.IsDir)
+ prop = (UInt64)0;
+
+ break;
+ }
+
+ case kpidSize:
+ {
+ if (si)
+ {
+ if (si->Resource.IsSolid())
+ {
+ if (si->Resource.IsSolidBig())
+ {
+ if (si->Resource.SolidIndex >= 0)
+ {
+ const CSolid &ss = _db.Solids[(unsigned)si->Resource.SolidIndex];
+ prop = ss.UnpackSize;
+ }
+ }
+ else
+ prop = si->Resource.PackSize;
+ }
+ else
+ prop = si->Resource.UnpackSize;
+ }
+ else if (!item.IsDir)
+ prop = (UInt64)0;
+
+ break;
+ }
+
+ case kpidIsDir: prop = item.IsDir; break;
+ case kpidIsAltStream: prop = item.IsAltStream; break;
+ case kpidNumAltStreams:
+ {
+ if (!item.IsAltStream && mainItem->HasMetadata())
+ {
+ UInt32 dirRecordSize = _db.IsOldVersion ? kDirRecordSizeOld : kDirRecordSize;
+ UInt32 numAltStreams = Get16(metadata + dirRecordSize - 6);
+ if (numAltStreams != 0)
+ {
+ if (!item.IsDir)
+ numAltStreams--;
+ prop = numAltStreams;
+ }
+ }
+ break;
+ }
+
+ case kpidAttrib:
+ if (!item.IsAltStream && mainItem->ImageIndex >= 0)
+ {
+ /*
+ if (fileNameLen == 0 && isDir && !item.HasStream())
+ item.Attrib = 0x10; // some swm archives have system/hidden attributes for root
+ */
+ prop = (UInt32)Get32(metadata + 8);
+ }
+ break;
+ case kpidCTime: if (mainItem->HasMetadata()) GetFileTime(metadata + (_db.IsOldVersion ? 0x18: 0x28), prop); break;
+ case kpidATime: if (mainItem->HasMetadata()) GetFileTime(metadata + (_db.IsOldVersion ? 0x20: 0x30), prop); break;
+ case kpidMTime: if (mainItem->HasMetadata()) GetFileTime(metadata + (_db.IsOldVersion ? 0x28: 0x38), prop); break;
+
+ case kpidINode:
+ if (mainItem->HasMetadata() && !_isOldVersion)
+ {
+ UInt32 attrib = (UInt32)Get32(metadata + 8);
+ if ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
+ {
+ // we don't know about that field in OLD WIM format
+ unsigned offset = 0x58; // (_db.IsOldVersion ? 0x30: 0x58);
+ UInt64 val = Get64(metadata + offset);
+ if (val != 0)
+ prop = val;
+ }
+ }
+ break;
+
+ case kpidStreamId:
+ if (item.StreamIndex >= 0)
+ prop = (UInt32)item.StreamIndex;
+ break;
+
+ case kpidMethod:
+ if (si)
+ {
+ const CResource &r = si->Resource;
+ if (r.IsSolid())
+ {
+ if (r.SolidIndex >= 0)
+ {
+ CSolid &ss = _db.Solids[r.SolidIndex];
+ MethodToProp(ss.Method, (int)ss.ChunkSizeBits, prop);
+ }
+ }
+ else
+ {
+ int method = 0;
+ int chunkSizeBits = -1;
+ if (r.IsCompressed())
+ {
+ method = (int)vol->Header.GetMethod();
+ chunkSizeBits = (int)vol->Header.ChunkSizeBits;
+ }
+ MethodToProp(method, chunkSizeBits, prop);
+ }
+ }
+ break;
+
+ case kpidSolid: if (si) prop = si->Resource.IsSolid(); break;
+ case kpidLinks: if (si) prop = (UInt32)si->RefCount; break;
+ #ifdef WIM_DETAILS
+ case kpidVolume: if (si) prop = (UInt32)si->PartNumber; break;
+ case kpidOffset: if (si) prop = (UInt64)si->Resource.Offset; break;
+ #endif
+ }
+ }
+ else
+ {
+ index -= _db.SortedItems.Size();
+ if (index < _numXmlItems)
+ {
+ switch (propID)
+ {
+ case kpidPath:
+ case kpidName: prop = _xmls[index].FileName; break;
+ case kpidIsDir: prop = false; break;
+ case kpidPackSize:
+ case kpidSize: prop = (UInt64)_xmls[index].Data.Size(); break;
+ case kpidMethod: /* prop = k_Method_Copy; */ break;
+ }
+ }
+ else
+ {
+ index -= _numXmlItems;
+ switch (propID)
+ {
+ case kpidPath:
+ case kpidName:
+ if (index < (UInt32)_db.VirtualRoots.Size())
+ prop = _db.Images[_db.VirtualRoots[index]].RootName;
+ else
+ prop = FILES_DIR_NAME;
+ break;
+ case kpidIsDir: prop = true; break;
+ case kpidIsAux: prop = true; break;
+ }
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetRootProp(PROPID propID, PROPVARIANT *value))
+{
+ // COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ if (_db.Images.Size() != 0 && _db.NumExcludededItems != 0)
+ {
+ const CImage &image = _db.Images[_db.IndexOfUserImage];
+ const CItem &item = _db.Items[image.StartItem];
+ if (!item.IsDir || item.ImageIndex != _db.IndexOfUserImage)
+ return E_FAIL;
+ const Byte *metadata = image.Meta + item.Offset;
+
+ switch (propID)
+ {
+ case kpidIsDir: prop = true; break;
+ case kpidAttrib: prop = (UInt32)Get32(metadata + 8); break;
+ case kpidCTime: GetFileTime(metadata + (_db.IsOldVersion ? 0x18: 0x28), prop); break;
+ case kpidATime: GetFileTime(metadata + (_db.IsOldVersion ? 0x20: 0x30), prop); break;
+ case kpidMTime: GetFileTime(metadata + (_db.IsOldVersion ? 0x28: 0x38), prop); break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ // COM_TRY_END
+}
+
+HRESULT CHandler::GetSecurity(UInt32 realIndex, const void **data, UInt32 *dataSize, UInt32 *propType)
+{
+ const CItem &item = _db.Items[realIndex];
+ if (item.IsAltStream || item.ImageIndex < 0)
+ return S_OK;
+ const CImage &image = _db.Images[item.ImageIndex];
+ const Byte *metadata = image.Meta + item.Offset;
+ UInt32 securityId = Get32(metadata + 0xC);
+ if (securityId == (UInt32)(Int32)-1)
+ return S_OK;
+ if (securityId >= (UInt32)image.SecurOffsets.Size())
+ return E_FAIL;
+ UInt32 offs = image.SecurOffsets[securityId];
+ UInt32 len = image.SecurOffsets[securityId + 1] - offs;
+ const CByteBuffer &buf = image.Meta;
+ if (offs <= buf.Size() && buf.Size() - offs >= len)
+ {
+ *data = buf + offs;
+ *dataSize = len;
+ *propType = NPropDataType::kRaw;
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetRootRawProp(PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
+{
+ *data = NULL;
+ *dataSize = 0;
+ *propType = 0;
+ if (propID == kpidNtSecure && _db.Images.Size() != 0 && _db.NumExcludededItems != 0)
+ {
+ const CImage &image = _db.Images[_db.IndexOfUserImage];
+ const CItem &item = _db.Items[image.StartItem];
+ if (!item.IsDir || item.ImageIndex != _db.IndexOfUserImage)
+ return E_FAIL;
+ return GetSecurity(image.StartItem, data, dataSize, propType);
+ }
+ return S_OK;
+}
+
+static const Byte kRawProps[] =
+{
+ kpidSha1,
+ kpidNtReparse,
+ kpidNtSecure
+};
+
+
+Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps))
+{
+ *numProps = Z7_ARRAY_SIZE(kRawProps);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID))
+{
+ *propID = kRawProps[index];
+ *name = NULL;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType))
+{
+ *parentType = NParentType::kDir;
+ *parent = (UInt32)(Int32)-1;
+ if (index >= _db.SortedItems.Size())
+ return S_OK;
+
+ const CItem &item = _db.Items[_db.SortedItems[index]];
+
+ if (item.ImageIndex >= 0)
+ {
+ *parentType = item.IsAltStream ? NParentType::kAltStream : NParentType::kDir;
+ if (item.Parent >= 0)
+ {
+ if (_db.ExludedItem != item.Parent)
+ *parent = (unsigned)_db.Items[item.Parent].IndexInSorted;
+ }
+ else
+ {
+ CImage &image = _db.Images[item.ImageIndex];
+ if (image.VirtualRootIndex >= 0)
+ *parent = _db.SortedItems.Size() + _numXmlItems + (unsigned)image.VirtualRootIndex;
+ }
+ }
+ else
+ *parent = _db.SortedItems.Size() + _numXmlItems + _db.VirtualRoots.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
+{
+ *data = NULL;
+ *dataSize = 0;
+ *propType = 0;
+
+ if (propID == kpidName)
+ {
+ if (index < _db.SortedItems.Size())
+ {
+ const CItem &item = _db.Items[_db.SortedItems[index]];
+ if (item.ImageIndex < 0)
+ return S_OK;
+ const CImage &image = _db.Images[item.ImageIndex];
+ *propType = NPropDataType::kUtf16z;
+ if (image.NumEmptyRootItems != 0 && item.Parent < 0)
+ {
+ const CByteBuffer &buf = _db.Images[item.ImageIndex].RootNameBuf;
+ *data = (void *)(const Byte *)buf;
+ *dataSize = (UInt32)buf.Size();
+ return S_OK;
+ }
+ const Byte *meta = image.Meta + item.Offset +
+ (item.IsAltStream ?
+ (_isOldVersion ? 0x10 : 0x24) :
+ (_isOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2));
+ *data = (const void *)(meta + 2);
+ *dataSize = (UInt32)Get16(meta) + 2;
+ return S_OK;
+ }
+ {
+ index -= _db.SortedItems.Size();
+ if (index < _numXmlItems)
+ return S_OK;
+ index -= _numXmlItems;
+ if (index >= (UInt32)_db.VirtualRoots.Size())
+ return S_OK;
+ const CByteBuffer &buf = _db.Images[_db.VirtualRoots[index]].RootNameBuf;
+ *data = (void *)(const Byte *)buf;
+ *dataSize = (UInt32)buf.Size();
+ *propType = NPropDataType::kUtf16z;
+ return S_OK;
+ }
+ }
+
+ if (index >= _db.SortedItems.Size())
+ return S_OK;
+
+ unsigned index2 = _db.SortedItems[index];
+
+ if (propID == kpidNtSecure)
+ {
+ return GetSecurity(index2, data, dataSize, propType);
+ }
+
+ const CItem &item = _db.Items[index2];
+ if (propID == kpidSha1)
+ {
+ if (item.StreamIndex >= 0)
+ *data = _db.DataStreams[item.StreamIndex].Hash;
+ else
+ {
+ if (_isOldVersion)
+ return S_OK;
+ const Byte *sha1 = _db.Images[item.ImageIndex].Meta + item.Offset + (item.IsAltStream ? 0x10 : 0x40);
+ if (IsEmptySha(sha1))
+ return S_OK;
+ *data = sha1;
+ }
+ *dataSize = kHashSize;
+ *propType = NPropDataType::kRaw;
+ return S_OK;
+ }
+
+ if (propID == kpidNtReparse && !_isOldVersion)
+ {
+ // we don't know about Reparse field in OLD WIM format
+
+ if (item.StreamIndex < 0)
+ return S_OK;
+ if (index2 >= _db.ItemToReparse.Size())
+ return S_OK;
+ int reparseIndex = _db.ItemToReparse[index2];
+ if (reparseIndex < 0)
+ return S_OK;
+ const CByteBuffer &buf = _db.ReparseItems[reparseIndex];
+ if (buf.Size() == 0)
+ return S_OK;
+ *data = buf;
+ *dataSize = (UInt32)buf.Size();
+ *propType = NPropDataType::kRaw;
+ return S_OK;
+ }
+
+ return S_OK;
+}
+
+class CVolumeName
+{
+ UString _before;
+ UString _after;
+public:
+ void InitName(const UString &name)
+ {
+ int dotPos = name.ReverseFind_Dot();
+ if (dotPos < 0)
+ dotPos = (int)name.Len();
+ _before.SetFrom(name.Ptr(), (unsigned)dotPos);
+ _after = name.Ptr(dotPos);
+ }
+
+ UString GetNextName(UInt32 index) const
+ {
+ UString s = _before;
+ s.Add_UInt32(index);
+ s += _after;
+ return s;
+ }
+};
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+
+ Close();
+ {
+ CMyComPtr<IArchiveOpenVolumeCallback> openVolumeCallback;
+
+ CVolumeName seqName;
+ if (callback)
+ callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&openVolumeCallback);
+
+ UInt32 numVolumes = 1;
+
+ for (UInt32 i = 1; i <= numVolumes; i++)
+ {
+ CMyComPtr<IInStream> curStream;
+
+ if (i == 1)
+ curStream = inStream;
+ else
+ {
+ if (!openVolumeCallback)
+ continue;
+ const UString fullName = seqName.GetNextName(i);
+ const HRESULT result = openVolumeCallback->GetStream(fullName, &curStream);
+ if (result == S_FALSE)
+ continue;
+ if (result != S_OK)
+ return result;
+ if (!curStream)
+ break;
+ }
+
+ CHeader header;
+ HRESULT res = NWim::ReadHeader(curStream, header, _phySize);
+
+ if (res != S_OK)
+ {
+ if (i != 1 && res == S_FALSE)
+ continue;
+ return res;
+ }
+
+ _isArc = true;
+ _bootIndex = header.BootIndex;
+ _version = header.Version;
+ _isOldVersion = header.IsOldVersion();
+ if (_firstVolumeIndex >= 0)
+ if (!header.AreFromOnArchive(_volumes[_firstVolumeIndex].Header))
+ break;
+ if (_volumes.Size() > header.PartNumber && _volumes[header.PartNumber].Stream)
+ break;
+ CWimXml xml;
+ xml.VolIndex = header.PartNumber;
+ res = _db.OpenXml(curStream, header, xml.Data);
+
+ if (res == S_OK)
+ {
+ if (!xml.Parse())
+ _xmlError = true;
+
+ if (xml.IsEncrypted)
+ {
+ _unsupported = true;
+ return S_FALSE;
+ }
+
+ UInt64 totalFiles = xml.GetTotalFilesAndDirs() + xml.Images.Size();
+ totalFiles += 16 + xml.Images.Size() * 4; // we reserve some additional items
+ if (totalFiles >= ((UInt32)1 << 30))
+ totalFiles = 0;
+ res = _db.Open(curStream, header, (unsigned)totalFiles, callback);
+ }
+
+ if (res != S_OK)
+ {
+ if (i != 1 && res == S_FALSE)
+ continue;
+ return res;
+ }
+
+ while (_volumes.Size() <= header.PartNumber)
+ _volumes.AddNew();
+ CVolume &volume = _volumes[header.PartNumber];
+ volume.Header = header;
+ volume.Stream = curStream;
+
+ _firstVolumeIndex = header.PartNumber;
+
+ if (_xmls.IsEmpty() || xml.Data != _xmls[0].Data)
+ {
+ xml.FileName = '[';
+ xml.FileName.Add_UInt32(xml.VolIndex);
+ xml.FileName += "].xml";
+ _xmls.Add(xml);
+ }
+
+ if (i == 1)
+ {
+ if (header.PartNumber != 1)
+ break;
+ if (!openVolumeCallback)
+ break;
+ numVolumes = header.NumParts;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(openVolumeCallback->GetProperty(kpidName, &prop))
+ if (prop.vt != VT_BSTR)
+ break;
+ seqName.InitName(prop.bstrVal);
+ }
+ }
+ }
+
+ RINOK(_db.FillAndCheck(_volumes))
+ int defaultImageIndex = (int)_defaultImageNumber - 1;
+
+ bool showImageNumber = (_db.Images.Size() != 1 && defaultImageIndex < 0);
+ if (!showImageNumber && _set_use_ShowImageNumber)
+ showImageNumber = _set_showImageNumber;
+
+ if (!showImageNumber && _keepMode_ShowImageNumber)
+ showImageNumber = true;
+
+ _showImageNumber = showImageNumber;
+
+ RINOK(_db.GenerateSortedItems(defaultImageIndex, showImageNumber))
+ RINOK(_db.ExtractReparseStreams(_volumes, callback))
+
+ /*
+ wchar_t sz[16];
+ ConvertUInt32ToString(_db.DataStreams.Size(), sz);
+ _nameLenForStreams = MyStringLen(sz);
+ */
+
+ _xmlInComments = !_showImageNumber;
+ _numXmlItems = (_xmlInComments ? 0 : _xmls.Size());
+ _numIgnoreItems = _db.ThereAreDeletedStreams ? 1 : 0;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _firstVolumeIndex = -1;
+ _phySize = 0;
+ _db.Clear();
+ _volumes.Clear();
+ _xmls.Clear();
+ // _nameLenForStreams = 0;
+ _xmlInComments = false;
+ _numXmlItems = 0;
+ _numIgnoreItems = 0;
+ _xmlError = false;
+ _isArc = false;
+ _unsupported = false;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+
+ if (allFilesMode)
+ numItems = _db.SortedItems.Size() + _numXmlItems + _db.VirtualRoots.Size() + _numIgnoreItems;
+ if (numItems == 0)
+ return S_OK;
+
+ UInt32 i;
+ UInt64 totalSize = 0;
+
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 index = allFilesMode ? i : indices[i];
+ if (index < _db.SortedItems.Size())
+ {
+ int streamIndex = _db.Items[_db.SortedItems[index]].StreamIndex;
+ if (streamIndex >= 0)
+ {
+ const CStreamInfo &si = _db.DataStreams[streamIndex];
+ totalSize += _db.Get_UnpackSize_of_Resource(si.Resource);
+ }
+ }
+ else
+ {
+ index -= _db.SortedItems.Size();
+ if (index < _numXmlItems)
+ totalSize += _xmls[index].Data.Size();
+ }
+ }
+
+ RINOK(extractCallback->SetTotal(totalSize))
+
+ UInt64 currentTotalUnPacked = 0;
+ UInt64 currentItemUnPacked;
+
+ int prevSuccessStreamIndex = -1;
+
+ CUnpacker unpacker;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0;; i++,
+ currentTotalUnPacked += currentItemUnPacked)
+ {
+ currentItemUnPacked = 0;
+
+ lps->InSize = unpacker.TotalPacked;
+ lps->OutSize = currentTotalUnPacked;
+
+ RINOK(lps->SetCur())
+
+ if (i >= numItems)
+ break;
+
+ UInt32 index = allFilesMode ? i : indices[i];
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+ if (index >= _db.SortedItems.Size())
+ {
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode))
+ index -= _db.SortedItems.Size();
+ if (index < _numXmlItems)
+ {
+ const CByteBuffer &data = _xmls[index].Data;
+ currentItemUnPacked = data.Size();
+ if (realOutStream)
+ {
+ RINOK(WriteStream(realOutStream, (const Byte *)data, data.Size()))
+ realOutStream.Release();
+ }
+ }
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+
+ const CItem &item = _db.Items[_db.SortedItems[index]];
+ int streamIndex = item.StreamIndex;
+ if (streamIndex < 0)
+ {
+ if (!item.IsDir)
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode))
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(!item.IsDir && _db.ItemHasStream(item) ?
+ NExtract::NOperationResult::kDataError :
+ NExtract::NOperationResult::kOK))
+ continue;
+ }
+
+ const CStreamInfo &si = _db.DataStreams[streamIndex];
+ currentItemUnPacked = _db.Get_UnpackSize_of_Resource(si.Resource);
+ // currentItemPacked = _db.Get_PackSize_of_Resource(streamIndex);
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode))
+ Int32 opRes = NExtract::NOperationResult::kOK;
+
+ if (streamIndex != prevSuccessStreamIndex || realOutStream)
+ {
+ Byte digest[kHashSize];
+ const CVolume &vol = _volumes[si.PartNumber];
+ bool needDigest = !si.IsEmptyHash();
+
+ HRESULT res = unpacker.Unpack(vol.Stream, si.Resource, vol.Header, &_db,
+ realOutStream, progress, needDigest ? digest : NULL);
+
+ if (res == S_OK)
+ {
+ if (!needDigest || memcmp(digest, si.Hash, kHashSize) == 0)
+ prevSuccessStreamIndex = streamIndex;
+ else
+ opRes = NExtract::NOperationResult::kCRCError;
+ }
+ else if (res == S_FALSE)
+ opRes = NExtract::NOperationResult::kDataError;
+ else if (res == E_NOTIMPL)
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ else
+ return res;
+ }
+
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(opRes))
+ }
+
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _db.SortedItems.Size() +
+ _numXmlItems +
+ _db.VirtualRoots.Size() +
+ _numIgnoreItems;
+ return S_OK;
+}
+
+CHandler::CHandler()
+{
+ _keepMode_ShowImageNumber = false;
+ InitDefaults();
+ _xmlError = false;
+}
+
+Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
+{
+ InitDefaults();
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ UString name = names[i];
+ name.MakeLower_Ascii();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+
+ const PROPVARIANT &prop = values[i];
+
+ if (name[0] == L'x')
+ {
+ // some clients write 'x' property. So we support it
+ UInt32 level = 0;
+ RINOK(ParsePropToUInt32(name.Ptr(1), prop, level))
+ }
+ else if (name.IsEqualTo("is"))
+ {
+ RINOK(PROPVARIANT_to_bool(prop, _set_showImageNumber))
+ _set_use_ShowImageNumber = true;
+ }
+ else if (name.IsEqualTo("im"))
+ {
+ UInt32 image = 9;
+ RINOK(ParsePropToUInt32(L"", prop, image))
+ _defaultImageNumber = (int)image;
+ }
+ else if (name.IsPrefixedBy_Ascii_NoCase("mt"))
+ {
+ }
+ else if (name.IsPrefixedBy_Ascii_NoCase("memuse"))
+ {
+ }
+ else
+ {
+ bool processed = false;
+ RINOK(_timeOptions.Parse(name, prop, processed))
+ if (!processed)
+ return E_INVALIDARG;
+ }
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::KeepModeForNextOpen())
+{
+ _keepMode_ShowImageNumber = _showImageNumber;
+ return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Wim/WimHandler.h b/CPP/7zip/Archive/Wim/WimHandler.h
new file mode 100644
index 0000000..60bb156
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/WimHandler.h
@@ -0,0 +1,93 @@
+// WimHandler.h
+
+#ifndef ZIP7_INC_ARCHIVE_WIM_HANDLER_H
+#define ZIP7_INC_ARCHIVE_WIM_HANDLER_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../Common/HandlerOut.h"
+
+#include "WimIn.h"
+
+namespace NArchive {
+namespace NWim {
+
+static const Int32 kNumImagesMaxUpdate = (1 << 10);
+
+Z7_CLASS_IMP_CHandler_IInArchive_5(
+ IArchiveGetRawProps
+ , IArchiveGetRootProps
+ , IArchiveKeepModeForNextOpen
+ , ISetProperties
+ , IOutArchive
+)
+ CDatabase _db;
+ UInt32 _version;
+ bool _isOldVersion;
+ UInt32 _bootIndex;
+
+ CObjectVector<CVolume> _volumes;
+ CObjectVector<CWimXml> _xmls;
+ // unsigned _nameLenForStreams;
+ bool _xmlInComments;
+
+ unsigned _numXmlItems;
+ unsigned _numIgnoreItems;
+
+ bool _xmlError;
+ bool _isArc;
+ bool _unsupported;
+
+ bool _set_use_ShowImageNumber;
+ bool _set_showImageNumber;
+ int _defaultImageNumber;
+
+ bool _showImageNumber;
+
+ bool _keepMode_ShowImageNumber;
+
+ UInt64 _phySize;
+ int _firstVolumeIndex;
+
+ CHandlerTimeOptions _timeOptions;
+
+ void InitDefaults()
+ {
+ _set_use_ShowImageNumber = false;
+ _set_showImageNumber = false;
+ _defaultImageNumber = -1;
+ _timeOptions.Init();
+ }
+
+ bool IsUpdateSupported() const
+ {
+ if (ThereIsError()) return false;
+ if (_db.Images.Size() > kNumImagesMaxUpdate) return false;
+
+ // Solid format is complicated. So we disable updating now.
+ if (!_db.Solids.IsEmpty()) return false;
+
+ if (_volumes.Size() == 0)
+ return true;
+
+ if (_volumes.Size() != 2) return false;
+ if (_volumes[0].Stream) return false;
+ if (_version != k_Version_NonSolid
+ // && _version != k_Version_Solid
+ ) return false;
+
+ return true;
+ }
+
+ bool ThereIsError() const { return _xmlError || _db.ThereIsError(); }
+ HRESULT GetSecurity(UInt32 realIndex, const void **data, UInt32 *dataSize, UInt32 *propType);
+
+ HRESULT GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value);
+ HRESULT GetTime(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, FILETIME &ft);
+public:
+ CHandler();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Wim/WimHandlerOut.cpp b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp
new file mode 100644
index 0000000..5d9dea2
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/WimHandlerOut.cpp
@@ -0,0 +1,2008 @@
+// WimHandlerOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/MyBuffer2.h"
+#include "../../../Common/StringToInt.h"
+#include "../../../Common/UTFConvert.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/TimeUtils.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamUtils.h"
+#include "../../Common/UniqBlocks.h"
+
+#include "../../Crypto/RandGen.h"
+#include "../../Crypto/Sha1Cls.h"
+
+#include "WimHandler.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NWim {
+
+static const unsigned k_NumSubVectors_Bits = 12; // must be <= 16
+
+struct CSortedIndex
+{
+ CObjectVector<CUIntVector> Vectors;
+
+ CSortedIndex()
+ {
+ const unsigned k_NumSubVectors = 1 << k_NumSubVectors_Bits;
+ Vectors.ClearAndReserve(k_NumSubVectors);
+ for (unsigned i = 0; i < k_NumSubVectors; i++)
+ Vectors.AddNew();
+ }
+};
+
+static int AddUniqHash(const CStreamInfo *streams, CSortedIndex &sorted2, const Byte *h, int streamIndexForInsert)
+{
+ const unsigned hash = (((unsigned)h[0] << 8) | (unsigned)h[1]) >> (16 - k_NumSubVectors_Bits);
+ CUIntVector &sorted = sorted2.Vectors[hash];
+ unsigned left = 0, right = sorted.Size();
+ while (left != right)
+ {
+ const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const unsigned index = sorted[mid];
+ const Byte *hash2 = streams[index].Hash;
+
+ unsigned i;
+ for (i = 0; i < kHashSize; i++)
+ if (h[i] != hash2[i])
+ break;
+
+ if (i == kHashSize)
+ return (int)index;
+
+ if (h[i] < hash2[i])
+ right = mid;
+ else
+ left = mid + 1;
+ }
+
+ if (streamIndexForInsert != -1)
+ sorted.Insert(left, (unsigned)streamIndexForInsert);
+
+ return -1;
+}
+
+
+struct CAltStream
+{
+ int UpdateIndex;
+ int HashIndex;
+ UInt64 Size;
+ UString Name;
+ bool Skip;
+
+ CAltStream(): UpdateIndex(-1), HashIndex(-1), Skip(false) {}
+};
+
+
+struct CMetaItem
+{
+ int UpdateIndex;
+ int HashIndex;
+
+ UInt64 Size;
+ FILETIME CTime;
+ FILETIME ATime;
+ FILETIME MTime;
+ UInt64 FileID;
+ UInt64 VolID;
+
+ UString Name;
+ UString ShortName;
+
+ UInt32 Attrib;
+ int SecurityId; // -1: means no secutity ID
+ bool IsDir;
+ bool Skip;
+ unsigned NumSkipAltStreams;
+ CObjectVector<CAltStream> AltStreams;
+
+ CByteBuffer Reparse;
+
+ unsigned GetNumAltStreams() const { return AltStreams.Size() - NumSkipAltStreams; }
+ CMetaItem():
+ UpdateIndex(-1)
+ , HashIndex(-1)
+ , Size(0)
+ , FileID(0)
+ , VolID(0)
+ , Attrib(0)
+ , SecurityId(-1)
+ , IsDir(false)
+ , Skip(false)
+ , NumSkipAltStreams(0)
+ {
+ FILETIME_Clear(CTime);
+ FILETIME_Clear(ATime);
+ FILETIME_Clear(MTime);
+ }
+};
+
+
+static int Compare_HardLink_MetaItems(const CMetaItem &a1, const CMetaItem &a2)
+{
+ if (a1.VolID < a2.VolID) return -1;
+ if (a1.VolID > a2.VolID) return 1;
+ if (a1.FileID < a2.FileID) return -1;
+ if (a1.FileID > a2.FileID) return 1;
+ if (a1.Size < a2.Size) return -1;
+ if (a1.Size > a2.Size) return 1;
+ return ::CompareFileTime(&a1.MTime, &a2.MTime);
+}
+
+
+static int AddToHardLinkList(const CObjectVector<CMetaItem> &metaItems, unsigned indexOfItem, CUIntVector &indexes)
+{
+ const CMetaItem &mi = metaItems[indexOfItem];
+ unsigned left = 0, right = indexes.Size();
+ while (left != right)
+ {
+ const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const unsigned index = indexes[mid];
+ const int comp = Compare_HardLink_MetaItems(mi, metaItems[index]);
+ if (comp == 0)
+ return (int)index;
+ if (comp < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ indexes.Insert(left, indexOfItem);
+ return -1;
+}
+
+
+struct CUpdateItem
+{
+ unsigned CallbackIndex; // index in callback
+
+ int MetaIndex; // index in in MetaItems[]
+
+ int AltStreamIndex; // index in CMetaItem::AltStreams vector
+ // -1: if not alt stream?
+
+ int InArcIndex; // >= 0, if we use OLD Data
+ // -1, if we use NEW Data
+
+ CUpdateItem(): MetaIndex(-1), AltStreamIndex(-1), InArcIndex(-1) {}
+};
+
+
+struct CDir
+{
+ int MetaIndex;
+ CObjectVector<CDir> Dirs;
+ CUIntVector Files; // indexes in MetaItems[]
+
+ CDir(): MetaIndex(-1) {}
+ unsigned GetNumDirs() const;
+ unsigned GetNumFiles() const;
+ UInt64 GetTotalSize(const CObjectVector<CMetaItem> &metaItems) const;
+ bool FindDir(const CObjectVector<CMetaItem> &items, const UString &name, unsigned &index);
+};
+
+/* imagex counts Junctions as files (not as dirs).
+ We suppose that it's not correct */
+
+unsigned CDir::GetNumDirs() const
+{
+ unsigned num = Dirs.Size();
+ FOR_VECTOR (i, Dirs)
+ num += Dirs[i].GetNumDirs();
+ return num;
+}
+
+unsigned CDir::GetNumFiles() const
+{
+ unsigned num = Files.Size();
+ FOR_VECTOR (i, Dirs)
+ num += Dirs[i].GetNumFiles();
+ return num;
+}
+
+UInt64 CDir::GetTotalSize(const CObjectVector<CMetaItem> &metaItems) const
+{
+ UInt64 sum = 0;
+ unsigned i;
+ for (i = 0; i < Files.Size(); i++)
+ sum += metaItems[Files[i]].Size;
+ for (i = 0; i < Dirs.Size(); i++)
+ sum += Dirs[i].GetTotalSize(metaItems);
+ return sum;
+}
+
+bool CDir::FindDir(const CObjectVector<CMetaItem> &items, const UString &name, unsigned &index)
+{
+ unsigned left = 0, right = Dirs.Size();
+ while (left != right)
+ {
+ const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const int comp = CompareFileNames(name, items[Dirs[mid].MetaIndex].Name);
+ if (comp == 0)
+ {
+ index = mid;
+ return true;
+ }
+ if (comp < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ index = left;
+ return false;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *type))
+{
+ *type = NFileTimeType::kWindows;
+ return S_OK;
+}
+
+
+HRESULT CHandler::GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value)
+{
+ if (arcIndex != -1)
+ return GetProperty((UInt32)arcIndex, propID, value);
+ return callback->GetProperty(callbackIndex, propID, value);
+}
+
+
+HRESULT CHandler::GetTime(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, FILETIME &ft)
+{
+ ft.dwLowDateTime = ft.dwHighDateTime = 0;
+ NCOM::CPropVariant prop;
+ RINOK(GetOutProperty(callback, callbackIndex, arcIndex, propID, &prop))
+ if (prop.vt == VT_FILETIME)
+ ft = prop.filetime;
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+
+static HRESULT GetRootTime(
+ IArchiveGetRootProps *callback,
+ IArchiveGetRootProps *arcRoot,
+ PROPID propID, FILETIME &ft)
+{
+ NCOM::CPropVariant prop;
+ if (callback)
+ {
+ RINOK(callback->GetRootProp(propID, &prop))
+ if (prop.vt == VT_FILETIME)
+ {
+ ft = prop.filetime;
+ return S_OK;
+ }
+ if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ if (arcRoot)
+ {
+ RINOK(arcRoot->GetRootProp(propID, &prop))
+ if (prop.vt == VT_FILETIME)
+ {
+ ft = prop.filetime;
+ return S_OK;
+ }
+ if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+#define Set16(p, d) SetUi16(p, d)
+#define Set32(p, d) SetUi32(p, d)
+#define Set64(p, d) SetUi64(p, d)
+
+void CResource::WriteTo(Byte *p) const
+{
+ Set64(p, PackSize)
+ p[7] = Flags;
+ Set64(p + 8, Offset)
+ Set64(p + 16, UnpackSize)
+}
+
+
+void CHeader::WriteTo(Byte *p) const
+{
+ memcpy(p, kSignature, kSignatureSize);
+ Set32(p + 8, kHeaderSizeMax)
+ Set32(p + 0xC, Version)
+ Set32(p + 0x10, Flags)
+ Set32(p + 0x14, ChunkSize)
+ memcpy(p + 0x18, Guid, 16);
+ Set16(p + 0x28, PartNumber)
+ Set16(p + 0x2A, NumParts)
+ Set32(p + 0x2C, NumImages)
+ OffsetResource.WriteTo(p + 0x30);
+ XmlResource.WriteTo(p + 0x48);
+ MetadataResource.WriteTo(p + 0x60);
+ IntegrityResource.WriteTo(p + 0x7C);
+ Set32(p + 0x78, BootIndex)
+ memset(p + 0x94, 0, 60);
+}
+
+
+void CStreamInfo::WriteTo(Byte *p) const
+{
+ Resource.WriteTo(p);
+ Set16(p + 0x18, PartNumber)
+ Set32(p + 0x1A, RefCount)
+ memcpy(p + 0x1E, Hash, kHashSize);
+}
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ CInStreamWithSha1
+ , ISequentialInStream
+)
+ CMyComPtr<ISequentialInStream> _stream;
+ UInt64 _size;
+ // NCrypto::NSha1::CContext _sha;
+ CAlignedBuffer1 _sha;
+ CSha1 *Sha() { return (CSha1 *)(void *)(Byte *)_sha; }
+public:
+ CInStreamWithSha1(): _sha(sizeof(CSha1)) {}
+ void SetStream(ISequentialInStream *stream) { _stream = stream; }
+ void Init()
+ {
+ _size = 0;
+ Sha1_Init(Sha());
+ }
+ void ReleaseStream() { _stream.Release(); }
+ UInt64 GetSize() const { return _size; }
+ void Final(Byte *digest) { Sha1_Final(Sha(), digest); }
+};
+
+Z7_COM7F_IMF(CInStreamWithSha1::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ UInt32 realProcessedSize;
+ const HRESULT result = _stream->Read(data, size, &realProcessedSize);
+ _size += realProcessedSize;
+ Sha1_Update(Sha(), (const Byte *)data, realProcessedSize);
+ if (processedSize)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+
+static void SetFileTimeToMem(Byte *p, const FILETIME &ft)
+{
+ Set32(p, ft.dwLowDateTime)
+ Set32(p + 4, ft.dwHighDateTime)
+}
+
+static size_t WriteItem_Dummy(const CMetaItem &item)
+{
+ if (item.Skip)
+ return 0;
+ unsigned fileNameLen = item.Name.Len() * 2;
+ // we write fileNameLen + 2 + 2 to be same as original WIM.
+ unsigned fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2);
+
+ const unsigned shortNameLen = item.ShortName.Len() * 2;
+ const unsigned shortNameLen2 = (shortNameLen == 0 ? 2 : shortNameLen + 4);
+
+ size_t totalLen = ((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~(unsigned)7);
+ if (item.GetNumAltStreams() != 0)
+ {
+ if (!item.IsDir)
+ {
+ const UInt32 curLen = (((0x26 + 0) + 6) & ~(unsigned)7);
+ totalLen += curLen;
+ }
+ FOR_VECTOR (i, item.AltStreams)
+ {
+ const CAltStream &ss = item.AltStreams[i];
+ if (ss.Skip)
+ continue;
+ fileNameLen = ss.Name.Len() * 2;
+ fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2 + 2);
+ const UInt32 curLen = (((0x26 + fileNameLen2) + 6) & ~(unsigned)7);
+ totalLen += curLen;
+ }
+ }
+ return totalLen;
+}
+
+
+static size_t WriteItem(const CStreamInfo *streams, const CMetaItem &item, Byte *p)
+{
+ if (item.Skip)
+ return 0;
+ unsigned fileNameLen = item.Name.Len() * 2;
+ unsigned fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2);
+ unsigned shortNameLen = item.ShortName.Len() * 2;
+ unsigned shortNameLen2 = (shortNameLen == 0 ? 2 : shortNameLen + 4);
+
+ size_t totalLen = ((kDirRecordSize + fileNameLen2 + shortNameLen2 + 6) & ~(unsigned)7);
+
+ memset(p, 0, totalLen);
+ Set64(p, totalLen)
+ Set64(p + 8, item.Attrib)
+ Set32(p + 0xC, (UInt32)(Int32)item.SecurityId)
+ SetFileTimeToMem(p + 0x28, item.CTime);
+ SetFileTimeToMem(p + 0x30, item.ATime);
+ SetFileTimeToMem(p + 0x38, item.MTime);
+
+ /* WIM format probably doesn't support hard links to symbolic links.
+ In these cases it just stores symbolic links (REPARSE TAGS).
+ Check it in new versions of WIM software form MS !!!
+ We also follow that scheme */
+
+ if (item.Reparse.Size() != 0)
+ {
+ UInt32 tag = GetUi32(item.Reparse);
+ Set32(p + 0x58, tag)
+ // Set32(p + 0x5C, 0); // probably it's always ZERO
+ }
+ else if (item.FileID != 0)
+ {
+ Set64(p + 0x58, item.FileID)
+ }
+
+ Set16(p + 0x62, (UInt16)shortNameLen)
+ Set16(p + 0x64, (UInt16)fileNameLen)
+ unsigned i;
+ for (i = 0; i * 2 < fileNameLen; i++)
+ Set16(p + kDirRecordSize + i * 2, (UInt16)item.Name[i])
+ for (i = 0; i * 2 < shortNameLen; i++)
+ Set16(p + kDirRecordSize + fileNameLen2 + i * 2, (UInt16)item.ShortName[i])
+
+ if (item.GetNumAltStreams() == 0)
+ {
+ if (item.HashIndex >= 0)
+ memcpy(p + 0x40, streams[item.HashIndex].Hash, kHashSize);
+ }
+ else
+ {
+ Set16(p + 0x60, (UInt16)(item.GetNumAltStreams() + (item.IsDir ? 0 : 1)))
+ p += totalLen;
+
+ if (!item.IsDir)
+ {
+ const UInt32 curLen = (((0x26 + 0) + 6) & ~(unsigned)7);
+ memset(p, 0, curLen);
+ Set64(p, curLen)
+ if (item.HashIndex >= 0)
+ memcpy(p + 0x10, streams[item.HashIndex].Hash, kHashSize);
+ totalLen += curLen;
+ p += curLen;
+ }
+
+ FOR_VECTOR (si, item.AltStreams)
+ {
+ const CAltStream &ss = item.AltStreams[si];
+ if (ss.Skip)
+ continue;
+
+ fileNameLen = ss.Name.Len() * 2;
+ fileNameLen2 = (fileNameLen == 0 ? 0 : fileNameLen + 2 + 2);
+ UInt32 curLen = (((0x26 + fileNameLen2) + 6) & ~(unsigned)7);
+ memset(p, 0, curLen);
+
+ Set64(p, curLen)
+ if (ss.HashIndex >= 0)
+ memcpy(p + 0x10, streams[ss.HashIndex].Hash, kHashSize);
+ Set16(p + 0x24, (UInt16)fileNameLen)
+ for (i = 0; i * 2 < fileNameLen; i++)
+ Set16(p + 0x26 + i * 2, (UInt16)ss.Name[i])
+ totalLen += curLen;
+ p += curLen;
+ }
+ }
+
+ return totalLen;
+}
+
+
+struct CDb
+{
+ CMetaItem DefaultDirItem;
+ const CStreamInfo *Hashes;
+ CObjectVector<CMetaItem> MetaItems;
+ CRecordVector<CUpdateItem> UpdateItems;
+ CUIntVector UpdateIndexes; /* indexes in UpdateItems in order of writing data streams
+ to disk (the order of tree items). */
+
+ size_t WriteTree_Dummy(const CDir &tree) const;
+ void WriteTree(const CDir &tree, Byte *dest, size_t &pos) const;
+ void WriteOrderList(const CDir &tree);
+};
+
+
+size_t CDb::WriteTree_Dummy(const CDir &tree) const
+{
+ unsigned i;
+ size_t pos = 0;
+ for (i = 0; i < tree.Files.Size(); i++)
+ pos += WriteItem_Dummy(MetaItems[tree.Files[i]]);
+ for (i = 0; i < tree.Dirs.Size(); i++)
+ {
+ const CDir &subDir = tree.Dirs[i];
+ pos += WriteItem_Dummy(MetaItems[subDir.MetaIndex]);
+ pos += WriteTree_Dummy(subDir);
+ }
+ return pos + 8;
+}
+
+
+void CDb::WriteTree(const CDir &tree, Byte *dest, size_t &pos) const
+{
+ unsigned i;
+ for (i = 0; i < tree.Files.Size(); i++)
+ pos += WriteItem(Hashes, MetaItems[tree.Files[i]], dest + pos);
+
+ size_t posStart = pos;
+ for (i = 0; i < tree.Dirs.Size(); i++)
+ pos += WriteItem_Dummy(MetaItems[tree.Dirs[i].MetaIndex]);
+
+ Set64(dest + pos, 0)
+
+ pos += 8;
+
+ for (i = 0; i < tree.Dirs.Size(); i++)
+ {
+ const CDir &subDir = tree.Dirs[i];
+ const CMetaItem &metaItem = MetaItems[subDir.MetaIndex];
+ bool needCreateTree = (metaItem.Reparse.Size() == 0)
+ || !subDir.Files.IsEmpty()
+ || !subDir.Dirs.IsEmpty();
+ size_t len = WriteItem(Hashes, metaItem, dest + posStart);
+ posStart += len;
+ if (needCreateTree)
+ {
+ Set64(dest + posStart - len + 0x10, pos) // subdirOffset
+ WriteTree(subDir, dest, pos);
+ }
+ }
+}
+
+
+void CDb::WriteOrderList(const CDir &tree)
+{
+ if (tree.MetaIndex >= 0)
+ {
+ const CMetaItem &mi = MetaItems[tree.MetaIndex];
+ if (mi.UpdateIndex >= 0)
+ UpdateIndexes.Add((unsigned)mi.UpdateIndex);
+ FOR_VECTOR (si, mi.AltStreams)
+ UpdateIndexes.Add((unsigned)mi.AltStreams[si].UpdateIndex);
+ }
+
+ unsigned i;
+ for (i = 0; i < tree.Files.Size(); i++)
+ {
+ const CMetaItem &mi = MetaItems[tree.Files[i]];
+ UpdateIndexes.Add((unsigned)mi.UpdateIndex);
+ FOR_VECTOR (si, mi.AltStreams)
+ UpdateIndexes.Add((unsigned)mi.AltStreams[si].UpdateIndex);
+ }
+
+ for (i = 0; i < tree.Dirs.Size(); i++)
+ WriteOrderList(tree.Dirs[i]);
+}
+
+
+static void AddTag_ToString(AString &s, const char *name, const char *value)
+{
+ s += '<';
+ s += name;
+ s += '>';
+ s += value;
+ s += '<';
+ s += '/';
+ s += name;
+ s += '>';
+}
+
+
+static void AddTagUInt64_ToString(AString &s, const char *name, UInt64 value)
+{
+ char temp[32];
+ ConvertUInt64ToString(value, temp);
+ AddTag_ToString(s, name, temp);
+}
+
+
+static CXmlItem &AddUniqueTag(CXmlItem &parentItem, const char *name)
+{
+ int index = parentItem.FindSubTag(name);
+ if (index < 0)
+ {
+ CXmlItem &subItem = parentItem.SubItems.AddNew();
+ subItem.IsTag = true;
+ subItem.Name = name;
+ return subItem;
+ }
+ CXmlItem &subItem = parentItem.SubItems[index];
+ subItem.SubItems.Clear();
+ return subItem;
+}
+
+
+static void AddTag_UInt64_2(CXmlItem &item, UInt64 value)
+{
+ CXmlItem &subItem = item.SubItems.AddNew();
+ subItem.IsTag = false;
+ char temp[32];
+ ConvertUInt64ToString(value, temp);
+ subItem.Name = temp;
+}
+
+
+static void AddTag_UInt64(CXmlItem &parentItem, const char *name, UInt64 value)
+{
+ AddTag_UInt64_2(AddUniqueTag(parentItem, name), value);
+}
+
+
+static void AddTag_Hex(CXmlItem &item, const char *name, UInt32 value)
+{
+ item.IsTag = true;
+ item.Name = name;
+ char temp[16];
+ temp[0] = '0';
+ temp[1] = 'x';
+ ConvertUInt32ToHex8Digits(value, temp + 2);
+ CXmlItem &subItem = item.SubItems.AddNew();
+ subItem.IsTag = false;
+ subItem.Name = temp;
+}
+
+
+static void AddTag_Time_2(CXmlItem &item, const FILETIME &ft)
+{
+ AddTag_Hex(item.SubItems.AddNew(), "HIGHPART", ft.dwHighDateTime);
+ AddTag_Hex(item.SubItems.AddNew(), "LOWPART", ft.dwLowDateTime);
+}
+
+
+static void AddTag_Time(CXmlItem &parentItem, const char *name, const FILETIME &ft)
+{
+ AddTag_Time_2(AddUniqueTag(parentItem, name), ft);
+}
+
+
+static void AddTag_String_IfEmpty(CXmlItem &parentItem, const char *name, const char *value)
+{
+ int index = parentItem.FindSubTag(name);
+ if (index >= 0)
+ return;
+ CXmlItem &tag = parentItem.SubItems.AddNew();
+ tag.IsTag = true;
+ tag.Name = name;
+ CXmlItem &subItem = tag.SubItems.AddNew();
+ subItem.IsTag = false;
+ subItem.Name = value;
+}
+
+
+void CHeader::SetDefaultFields(bool useLZX)
+{
+ Version = k_Version_NonSolid;
+ Flags = NHeaderFlags::kReparsePointFixup;
+ ChunkSize = 0;
+ if (useLZX)
+ {
+ Flags |= NHeaderFlags::kCompression | NHeaderFlags::kLZX;
+ ChunkSize = kChunkSize;
+ ChunkSizeBits = kChunkSizeBits;
+ }
+ MY_RAND_GEN(Guid, 16);
+ PartNumber = 1;
+ NumParts = 1;
+ NumImages = 1;
+ BootIndex = 0;
+ OffsetResource.Clear();
+ XmlResource.Clear();
+ MetadataResource.Clear();
+ IntegrityResource.Clear();
+}
+
+
+static void AddTrees(CObjectVector<CDir> &trees, CObjectVector<CMetaItem> &metaItems, const CMetaItem &ri, int curTreeIndex)
+{
+ while (curTreeIndex >= (int)trees.Size())
+ trees.AddNew().Dirs.AddNew().MetaIndex = (int)metaItems.Add(ri);
+}
+
+
+#define IS_LETTER_CHAR(c) (((c) >= 'a' && (c) <= 'z') || ((c) >= 'A' && (c) <= 'Z'))
+
+
+
+Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outSeqStream, UInt32 numItems, IArchiveUpdateCallback *callback))
+{
+ COM_TRY_BEGIN
+
+ if (!IsUpdateSupported())
+ return E_NOTIMPL;
+
+ bool isUpdate = (_volumes.Size() != 0);
+ int defaultImageIndex = _defaultImageNumber - 1;
+ bool showImageNumber;
+
+ if (isUpdate)
+ {
+ showImageNumber = _showImageNumber;
+ if (!showImageNumber)
+ defaultImageIndex = _db.IndexOfUserImage;
+ }
+ else
+ {
+ showImageNumber = (_set_use_ShowImageNumber && _set_showImageNumber);
+ if (!showImageNumber)
+ defaultImageIndex = 0;
+ }
+
+ if (defaultImageIndex >= kNumImagesMaxUpdate)
+ return E_NOTIMPL;
+
+ CMyComPtr<IOutStream> outStream;
+ RINOK(outSeqStream->QueryInterface(IID_IOutStream, (void **)&outStream))
+ if (!outStream)
+ return E_NOTIMPL;
+ if (!callback)
+ return E_FAIL;
+
+ CDb db;
+ CObjectVector<CDir> trees;
+
+ CMetaItem ri; // default DIR item
+ FILETIME ftCur;
+ NTime::GetCurUtcFileTime(ftCur);
+ // ri.MTime = ri.ATime = ri.CTime = ftCur;
+ ri.Attrib = FILE_ATTRIBUTE_DIRECTORY;
+ ri.IsDir = true;
+
+
+ // ---------- Detect changed images ----------
+
+ unsigned i;
+ CBoolVector isChangedImage;
+ {
+ CUIntVector numUnchangedItemsInImage;
+ for (i = 0; i < _db.Images.Size(); i++)
+ {
+ numUnchangedItemsInImage.Add(0);
+ isChangedImage.Add(false);
+ }
+
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 indexInArchive;
+ Int32 newData, newProps;
+ RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive))
+ if (newProps == 0)
+ {
+ if (indexInArchive >= _db.SortedItems.Size())
+ continue;
+ const CItem &item = _db.Items[_db.SortedItems[indexInArchive]];
+ if (newData == 0)
+ {
+ if (item.ImageIndex >= 0)
+ numUnchangedItemsInImage[item.ImageIndex]++;
+ }
+ else
+ {
+ // oldProps & newData. Current version of 7-Zip doesn't use it
+ if (item.ImageIndex >= 0)
+ isChangedImage[item.ImageIndex] = true;
+ }
+ }
+ else if (!showImageNumber)
+ {
+ if (defaultImageIndex >= 0 && defaultImageIndex < (int)isChangedImage.Size())
+ isChangedImage[defaultImageIndex] = true;
+ }
+ else
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidPath, &prop))
+
+ if (prop.vt != VT_BSTR)
+ return E_INVALIDARG;
+ const wchar_t *path = prop.bstrVal;
+ if (!path)
+ return E_INVALIDARG;
+
+ const wchar_t *end;
+ UInt64 val = ConvertStringToUInt64(path, &end);
+ if (end == path)
+ return E_INVALIDARG;
+ if (val == 0 || val > kNumImagesMaxUpdate)
+ return E_INVALIDARG;
+ wchar_t c = *end;
+ if (c != 0 && c != ':' && c != L'/' && c != WCHAR_PATH_SEPARATOR)
+ return E_INVALIDARG;
+ unsigned imageIndex = (unsigned)val - 1;
+ if (imageIndex < _db.Images.Size())
+ isChangedImage[imageIndex] = true;
+ if (_defaultImageNumber > 0 && val != (unsigned)_defaultImageNumber)
+ return E_INVALIDARG;
+ }
+ }
+
+ for (i = 0; i < _db.Images.Size(); i++)
+ if (!isChangedImage[i])
+ isChangedImage[i] = _db.GetNumUserItemsInImage(i) != numUnchangedItemsInImage[i];
+ }
+
+ if (defaultImageIndex >= 0)
+ {
+ for (i = 0; i < _db.Images.Size(); i++)
+ if ((int)i != defaultImageIndex)
+ isChangedImage[i] = false;
+ }
+
+ CMyComPtr<IArchiveGetRawProps> getRawProps;
+ callback->QueryInterface(IID_IArchiveGetRawProps, (void **)&getRawProps);
+
+ CMyComPtr<IArchiveGetRootProps> getRootProps;
+ callback->QueryInterface(IID_IArchiveGetRootProps, (void **)&getRootProps);
+
+ CObjectVector<CUniqBlocks> secureBlocks;
+
+ if (!showImageNumber && (getRootProps || isUpdate) &&
+ (
+ defaultImageIndex >= (int)isChangedImage.Size()
+ || defaultImageIndex < 0 // test it
+ || isChangedImage[defaultImageIndex]
+ ))
+ {
+ // Fill Root Item: Metadata and security
+ CMetaItem rootItem = ri;
+ {
+ const void *data = NULL;
+ UInt32 dataSize = 0;
+ UInt32 propType = 0;
+ if (getRootProps)
+ {
+ RINOK(getRootProps->GetRootRawProp(kpidNtSecure, &data, &dataSize, &propType))
+ }
+ if (dataSize == 0 && isUpdate)
+ {
+ RINOK(GetRootRawProp(kpidNtSecure, &data, &dataSize, &propType))
+ }
+ if (dataSize != 0)
+ {
+ if (propType != NPropDataType::kRaw)
+ return E_FAIL;
+ while (defaultImageIndex >= (int)secureBlocks.Size())
+ secureBlocks.AddNew();
+ CUniqBlocks &secUniqBlocks = secureBlocks[defaultImageIndex];
+ rootItem.SecurityId = (int)secUniqBlocks.AddUniq((const Byte *)data, dataSize);
+ }
+ }
+
+ IArchiveGetRootProps *thisGetRoot = isUpdate ? this : NULL;
+
+ if (_timeOptions.Write_CTime.Val) RINOK(GetRootTime(getRootProps, thisGetRoot, kpidCTime, rootItem.CTime))
+ if (_timeOptions.Write_ATime.Val) RINOK(GetRootTime(getRootProps, thisGetRoot, kpidATime, rootItem.ATime))
+ if (_timeOptions.Write_MTime.Val) RINOK(GetRootTime(getRootProps, thisGetRoot, kpidMTime, rootItem.MTime))
+
+ {
+ NCOM::CPropVariant prop;
+ if (getRootProps)
+ {
+ RINOK(getRootProps->GetRootProp(kpidAttrib, &prop))
+ if (prop.vt == VT_UI4)
+ rootItem.Attrib = prop.ulVal;
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ if (prop.vt == VT_EMPTY && thisGetRoot)
+ {
+ RINOK(GetRootProp(kpidAttrib, &prop))
+ if (prop.vt == VT_UI4)
+ rootItem.Attrib = prop.ulVal;
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ rootItem.Attrib |= FILE_ATTRIBUTE_DIRECTORY;
+ }
+
+ AddTrees(trees, db.MetaItems, ri, defaultImageIndex);
+ db.MetaItems[trees[defaultImageIndex].Dirs[0].MetaIndex] = rootItem;
+ }
+
+ // ---------- Request Metadata for changed items ----------
+
+ UString fileName;
+
+ for (i = 0; i < numItems; i++)
+ {
+ CUpdateItem ui;
+ UInt32 indexInArchive;
+ Int32 newData, newProps;
+ RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArchive))
+
+ if (newData == 0 || newProps == 0)
+ {
+ if (indexInArchive >= _db.SortedItems.Size())
+ continue;
+
+ const CItem &item = _db.Items[_db.SortedItems[indexInArchive]];
+
+ if (item.ImageIndex >= 0)
+ {
+ if (!isChangedImage[item.ImageIndex])
+ {
+ if (newData == 0 && newProps == 0)
+ continue;
+ return E_FAIL;
+ }
+ }
+ else
+ {
+ // if deleted item was not renamed, we just skip it
+ if (newProps == 0)
+ continue;
+ if (item.StreamIndex >= 0)
+ {
+ // we don't support property change for SolidBig streams
+ if (_db.DataStreams[item.StreamIndex].Resource.IsSolidBig())
+ return E_NOTIMPL;
+ }
+ }
+
+ if (newData == 0)
+ ui.InArcIndex = (Int32)indexInArchive;
+ }
+
+ // we set arcIndex only if we must use old props
+ const Int32 arcIndex = (newProps ? -1 : (Int32)indexInArchive);
+
+ bool isDir = false;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(GetOutProperty(callback, i, arcIndex, kpidIsDir, &prop))
+ if (prop.vt == VT_BOOL)
+ isDir = (prop.boolVal != VARIANT_FALSE);
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+
+ bool isAltStream = false;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(GetOutProperty(callback, i, arcIndex, kpidIsAltStream, &prop))
+ if (prop.vt == VT_BOOL)
+ isAltStream = (prop.boolVal != VARIANT_FALSE);
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+
+ if (isDir && isAltStream)
+ return E_INVALIDARG;
+
+ UInt64 size = 0;
+ UInt64 iNode = 0;
+
+ if (!isDir)
+ {
+ if (!newData)
+ {
+ NCOM::CPropVariant prop;
+ GetProperty(indexInArchive, kpidINode, &prop);
+ if (prop.vt == VT_UI8)
+ iNode = prop.uhVal.QuadPart;
+ }
+
+ NCOM::CPropVariant prop;
+
+ if (newData)
+ {
+ RINOK(callback->GetProperty(i, kpidSize, &prop))
+ }
+ else
+ {
+ RINOK(GetProperty(indexInArchive, kpidSize, &prop))
+ }
+
+ if (prop.vt == VT_UI8)
+ size = prop.uhVal.QuadPart;
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+
+ {
+ NCOM::CPropVariant propPath;
+ const wchar_t *path = NULL;
+ RINOK(GetOutProperty(callback, i, arcIndex, kpidPath, &propPath))
+ if (propPath.vt == VT_BSTR)
+ path = propPath.bstrVal;
+ else if (propPath.vt != VT_EMPTY)
+ return E_INVALIDARG;
+
+ if (!path)
+ return E_INVALIDARG;
+
+ CDir *curItem = NULL;
+ bool isRootImageDir = false;
+ fileName.Empty();
+
+ int imageIndex;
+
+ if (!showImageNumber)
+ {
+ imageIndex = defaultImageIndex;
+ AddTrees(trees, db.MetaItems, ri, imageIndex);
+ curItem = &trees[imageIndex].Dirs[0];
+ }
+ else
+ {
+ const wchar_t *end;
+ UInt64 val = ConvertStringToUInt64(path, &end);
+ if (end == path)
+ return E_INVALIDARG;
+ if (val == 0 || val > kNumImagesMaxUpdate)
+ return E_INVALIDARG;
+
+ imageIndex = (int)val - 1;
+ if (imageIndex < (int)isChangedImage.Size())
+ if (!isChangedImage[imageIndex])
+ return E_FAIL;
+
+ AddTrees(trees, db.MetaItems, ri, imageIndex);
+ curItem = &trees[imageIndex].Dirs[0];
+ wchar_t c = *end;
+
+ if (c == 0)
+ {
+ if (!isDir || isAltStream)
+ return E_INVALIDARG;
+ ui.MetaIndex = curItem->MetaIndex;
+ isRootImageDir = true;
+ }
+ else if (c == ':')
+ {
+ if (isDir || !isAltStream)
+ return E_INVALIDARG;
+ ui.MetaIndex = curItem->MetaIndex;
+ CAltStream ss;
+ ss.Size = size;
+ ss.Name = end + 1;
+ ss.UpdateIndex = (int)db.UpdateItems.Size();
+ ui.AltStreamIndex = (int)db.MetaItems[ui.MetaIndex].AltStreams.Add(ss);
+ }
+ else if (c == WCHAR_PATH_SEPARATOR || c == L'/')
+ {
+ path = end + 1;
+ if (*path == 0)
+ return E_INVALIDARG;
+ }
+ else
+ return E_INVALIDARG;
+ }
+
+ if (ui.MetaIndex < 0)
+ {
+ for (;;)
+ {
+ wchar_t c = *path++;
+ if (c == 0)
+ break;
+ if (c == WCHAR_PATH_SEPARATOR || c == L'/')
+ {
+ unsigned indexOfDir;
+ if (!curItem->FindDir(db.MetaItems, fileName, indexOfDir))
+ {
+ CDir &dir = curItem->Dirs.InsertNew(indexOfDir);
+ dir.MetaIndex = (int)db.MetaItems.Add(ri);
+ db.MetaItems.Back().Name = fileName;
+ }
+ curItem = &curItem->Dirs[indexOfDir];
+ fileName.Empty();
+ }
+ else
+ {
+ /*
+ #if WCHAR_MAX > 0xffff
+ if (c >= 0x10000)
+ {
+ c -= 0x10000;
+
+ if (c < (1 << 20))
+ {
+ wchar_t c0 = 0xd800 + ((c >> 10) & 0x3FF);
+ fileName += c0;
+ c = 0xdc00 + (c & 0x3FF);
+ }
+ else
+ c = '_'; // we change character unsupported by UTF16
+ }
+ #endif
+ */
+
+ fileName += c;
+ }
+ }
+
+ if (isAltStream)
+ {
+ int colonPos = fileName.Find(L':');
+ if (colonPos < 0)
+ return E_INVALIDARG;
+
+ // we want to support cases of c::substream, where c: is drive name
+ if (colonPos == 1 && fileName[2] == L':' && IS_LETTER_CHAR(fileName[0]))
+ colonPos = 2;
+ const UString mainName = fileName.Left((unsigned)colonPos);
+ unsigned indexOfDir;
+
+ if (mainName.IsEmpty())
+ ui.MetaIndex = curItem->MetaIndex;
+ else if (curItem->FindDir(db.MetaItems, mainName, indexOfDir))
+ ui.MetaIndex = curItem->Dirs[indexOfDir].MetaIndex;
+ else
+ {
+ for (int j = (int)curItem->Files.Size() - 1; j >= 0; j--)
+ {
+ const unsigned metaIndex = curItem->Files[j];
+ const CMetaItem &mi = db.MetaItems[metaIndex];
+ if (CompareFileNames(mainName, mi.Name) == 0)
+ {
+ ui.MetaIndex = (int)metaIndex;
+ break;
+ }
+ }
+ }
+
+ if (ui.MetaIndex >= 0)
+ {
+ CAltStream ss;
+ ss.Size = size;
+ ss.Name = fileName.Ptr(colonPos + 1);
+ ss.UpdateIndex = (int)db.UpdateItems.Size();
+ ui.AltStreamIndex = (int)db.MetaItems[ui.MetaIndex].AltStreams.Add(ss);
+ }
+ }
+ }
+
+
+ if (ui.MetaIndex < 0 || isRootImageDir)
+ {
+ if (!isRootImageDir)
+ {
+ ui.MetaIndex = (int)db.MetaItems.Size();
+ db.MetaItems.AddNew();
+ }
+
+ CMetaItem &mi = db.MetaItems[ui.MetaIndex];
+ mi.Size = size;
+ mi.IsDir = isDir;
+ mi.Name = fileName;
+ mi.UpdateIndex = (int)db.UpdateItems.Size();
+ {
+ NCOM::CPropVariant prop;
+ RINOK(GetOutProperty(callback, i, arcIndex, kpidAttrib, &prop))
+ if (prop.vt == VT_EMPTY)
+ mi.Attrib = 0;
+ else if (prop.vt == VT_UI4)
+ mi.Attrib = prop.ulVal;
+ else
+ return E_INVALIDARG;
+ if (isDir)
+ mi.Attrib |= FILE_ATTRIBUTE_DIRECTORY;
+ }
+
+ if (arcIndex != -1 || _timeOptions.Write_CTime.Val)
+ RINOK(GetTime(callback, i, arcIndex, kpidCTime, mi.CTime))
+ if (arcIndex != -1 || _timeOptions.Write_ATime.Val)
+ RINOK(GetTime(callback, i, arcIndex, kpidATime, mi.ATime))
+ if (arcIndex != -1 || _timeOptions.Write_MTime.Val)
+ RINOK(GetTime(callback, i, arcIndex, kpidMTime, mi.MTime))
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(GetOutProperty(callback, i, arcIndex, kpidShortName, &prop))
+ if (prop.vt == VT_BSTR)
+ mi.ShortName.SetFromBstr(prop.bstrVal);
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+
+ while (imageIndex >= (int)secureBlocks.Size())
+ secureBlocks.AddNew();
+
+ if (!isAltStream && (getRawProps || arcIndex >= 0))
+ {
+ CUniqBlocks &secUniqBlocks = secureBlocks[imageIndex];
+ const void *data;
+ UInt32 dataSize;
+ UInt32 propType;
+
+ data = NULL;
+ dataSize = 0;
+ propType = 0;
+
+ if (arcIndex >= 0)
+ {
+ GetRawProp((UInt32)arcIndex, kpidNtSecure, &data, &dataSize, &propType);
+ }
+ else
+ {
+ getRawProps->GetRawProp(i, kpidNtSecure, &data, &dataSize, &propType);
+ }
+
+ if (dataSize != 0)
+ {
+ if (propType != NPropDataType::kRaw)
+ return E_FAIL;
+ mi.SecurityId = (int)secUniqBlocks.AddUniq((const Byte *)data, dataSize);
+ }
+
+ data = NULL;
+ dataSize = 0;
+ propType = 0;
+
+ if (arcIndex >= 0)
+ {
+ GetRawProp((UInt32)arcIndex, kpidNtReparse, &data, &dataSize, &propType);
+ }
+ else
+ {
+ getRawProps->GetRawProp(i, kpidNtReparse, &data, &dataSize, &propType);
+ }
+
+ if (dataSize != 0)
+ {
+ if (propType != NPropDataType::kRaw)
+ return E_FAIL;
+ mi.Reparse.CopyFrom((const Byte *)data, dataSize);
+ }
+ }
+
+ if (!isRootImageDir)
+ {
+ if (isDir)
+ {
+ unsigned indexOfDir;
+ if (curItem->FindDir(db.MetaItems, fileName, indexOfDir))
+ curItem->Dirs[indexOfDir].MetaIndex = ui.MetaIndex;
+ else
+ curItem->Dirs.InsertNew(indexOfDir).MetaIndex = ui.MetaIndex;
+ }
+ else
+ curItem->Files.Add((unsigned)ui.MetaIndex);
+ }
+ }
+
+ }
+
+ if (iNode != 0 && ui.MetaIndex >= 0 && ui.AltStreamIndex < 0)
+ db.MetaItems[ui.MetaIndex].FileID = iNode;
+
+ ui.CallbackIndex = i;
+ db.UpdateItems.Add(ui);
+ }
+
+ unsigned numNewImages = trees.Size();
+ for (i = numNewImages; i < isChangedImage.Size(); i++)
+ if (!isChangedImage[i])
+ numNewImages = i + 1;
+
+ AddTrees(trees, db.MetaItems, ri, (int)numNewImages - 1);
+
+ for (i = 0; i < trees.Size(); i++)
+ if (i >= isChangedImage.Size() || isChangedImage[i])
+ db.WriteOrderList(trees[i]);
+
+
+ UInt64 complexity = 0;
+
+ unsigned numDataStreams = _db.DataStreams.Size();
+ CUIntArr streamsRefs(numDataStreams);
+ for (i = 0; i < numDataStreams; i++)
+ streamsRefs[i] = 0;
+
+ // ---------- Calculate Streams Refs Counts in unchanged images
+
+ for (i = 0; i < _db.Images.Size(); i++)
+ {
+ if (isChangedImage[i])
+ continue;
+ complexity += _db.MetaStreams[i].Resource.PackSize;
+ const CImage &image = _db.Images[i];
+ unsigned endItem = image.StartItem + image.NumItems;
+ for (unsigned k = image.StartItem; k < endItem; k++)
+ {
+ const CItem &item = _db.Items[k];
+ if (item.StreamIndex >= 0)
+ streamsRefs[(unsigned)item.StreamIndex]++;
+ }
+ }
+
+
+ // ---------- Update Streams Refs Counts in changed images
+
+ for (i = 0; i < db.UpdateIndexes.Size(); i++)
+ {
+ const CUpdateItem &ui = db.UpdateItems[db.UpdateIndexes[i]];
+
+ if (ui.InArcIndex >= 0)
+ {
+ if ((unsigned)ui.InArcIndex >= _db.SortedItems.Size())
+ continue;
+ const CItem &item = _db.Items[_db.SortedItems[ui.InArcIndex]];
+ if (item.StreamIndex >= 0)
+ streamsRefs[(unsigned)item.StreamIndex]++;
+ }
+ else
+ {
+ const CMetaItem &mi = db.MetaItems[ui.MetaIndex];
+ UInt64 size;
+ if (ui.AltStreamIndex < 0)
+ size = mi.Size;
+ else
+ size = mi.AltStreams[ui.AltStreamIndex].Size;
+ complexity += size;
+ }
+ }
+
+ // Clear ref counts for SolidBig streams
+
+ for (i = 0; i < _db.DataStreams.Size(); i++)
+ if (_db.DataStreams[i].Resource.IsSolidBig())
+ streamsRefs[i] = 0;
+
+ // Set ref counts for SolidBig streams
+
+ for (i = 0; i < _db.DataStreams.Size(); i++)
+ if (streamsRefs[i] != 0)
+ {
+ const CResource &rs = _db.DataStreams[i].Resource;
+ if (rs.IsSolidSmall())
+ streamsRefs[_db.Solids[rs.SolidIndex].StreamIndex] = 1;
+ }
+
+ for (i = 0; i < _db.DataStreams.Size(); i++)
+ if (streamsRefs[i] != 0)
+ {
+ const CResource &rs = _db.DataStreams[i].Resource;
+ if (!rs.IsSolidSmall())
+ complexity += rs.PackSize;
+ }
+
+ RINOK(callback->SetTotal(complexity))
+ UInt64 totalComplexity = complexity;
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(callback, true);
+
+ complexity = 0;
+
+ // bool useResourceCompression = false;
+ // use useResourceCompression only if CHeader::Flags compression is also set
+
+ CHeader header;
+ header.SetDefaultFields(false);
+
+ if (isUpdate)
+ {
+ const CHeader &srcHeader = _volumes[1].Header;
+ header.Flags = srcHeader.Flags;
+ header.Version = srcHeader.Version;
+ header.ChunkSize = srcHeader.ChunkSize;
+ header.ChunkSizeBits = srcHeader.ChunkSizeBits;
+ }
+
+ CMyComPtr<IStreamSetRestriction> setRestriction;
+ outSeqStream->QueryInterface(IID_IStreamSetRestriction, (void **)&setRestriction);
+ if (setRestriction)
+ RINOK(setRestriction->SetRestriction(0, kHeaderSizeMax))
+
+ {
+ Byte buf[kHeaderSizeMax];
+ header.WriteTo(buf);
+ RINOK(WriteStream(outStream, buf, kHeaderSizeMax))
+ }
+
+ UInt64 curPos = kHeaderSizeMax;
+
+ CInStreamWithSha1 *inShaStreamSpec = new CInStreamWithSha1;
+ CMyComPtr<ISequentialInStream> inShaStream = inShaStreamSpec;
+
+ CLimitedSequentialInStream *inStreamLimitedSpec = NULL;
+ CMyComPtr<ISequentialInStream> inStreamLimited;
+ if (_volumes.Size() == 2)
+ {
+ inStreamLimitedSpec = new CLimitedSequentialInStream;
+ inStreamLimited = inStreamLimitedSpec;
+ inStreamLimitedSpec->SetStream(_volumes[1].Stream);
+ }
+
+
+ CRecordVector<CStreamInfo> streams;
+ CSortedIndex sortedHashes; // indexes to streams, sorted by SHA1
+
+ // ---------- Copy unchanged data streams ----------
+
+ UInt64 solidRunOffset = 0;
+ UInt64 curSolidSize = 0;
+
+ for (i = 0; i < _db.DataStreams.Size(); i++)
+ {
+ const CStreamInfo &siOld = _db.DataStreams[i];
+ const CResource &rs = siOld.Resource;
+
+ const unsigned numRefs = streamsRefs[i];
+
+ if (numRefs == 0)
+ {
+ if (!rs.IsSolidSmall())
+ continue;
+ if (streamsRefs[_db.Solids[rs.SolidIndex].StreamIndex] == 0)
+ continue;
+ }
+
+ lps->InSize = lps->OutSize = complexity;
+ RINOK(lps->SetCur())
+
+ const unsigned streamIndex = streams.Size();
+ CStreamInfo s;
+ s.Resource = rs;
+ s.PartNumber = 1;
+ s.RefCount = numRefs;
+
+ memcpy(s.Hash, siOld.Hash, kHashSize);
+
+ if (rs.IsSolid())
+ {
+ CSolid &ss = _db.Solids[rs.SolidIndex];
+ if (rs.IsSolidSmall())
+ {
+ UInt64 oldOffset = ss.SolidOffset;
+ if (rs.Offset < oldOffset)
+ return E_FAIL;
+ UInt64 relatOffset = rs.Offset - oldOffset;
+ s.Resource.Offset = solidRunOffset + relatOffset;
+ }
+ else
+ {
+ // IsSolidBig
+ solidRunOffset += curSolidSize;
+ curSolidSize = ss.UnpackSize;
+ }
+ }
+ else
+ {
+ solidRunOffset = 0;
+ curSolidSize = 0;
+ }
+
+ if (!rs.IsSolid() || rs.IsSolidSmall())
+ {
+ const int find = AddUniqHash(&streams.Front(), sortedHashes, siOld.Hash, (int)streamIndex);
+ if (find != -1)
+ return E_FAIL; // two streams with same SHA-1
+ }
+
+ if (!rs.IsSolid() || rs.IsSolidBig())
+ {
+ RINOK(InStream_SeekSet(_volumes[siOld.PartNumber].Stream, rs.Offset))
+ inStreamLimitedSpec->Init(rs.PackSize);
+ RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress))
+ if (copyCoderSpec->TotalSize != rs.PackSize)
+ return E_FAIL;
+ s.Resource.Offset = curPos;
+ curPos += rs.PackSize;
+ lps->ProgressOffset += rs.PackSize;
+ }
+
+ streams.Add(s);
+ }
+
+
+ // ---------- Write new items ----------
+
+ CUIntVector hlIndexes; // sorted indexes for hard link items
+
+ for (i = 0; i < db.UpdateIndexes.Size(); i++)
+ {
+ lps->InSize = lps->OutSize = complexity;
+ RINOK(lps->SetCur())
+ const CUpdateItem &ui = db.UpdateItems[db.UpdateIndexes[i]];
+ CMetaItem &mi = db.MetaItems[ui.MetaIndex];
+ UInt64 size = 0;
+
+ if (ui.AltStreamIndex >= 0)
+ {
+ if (mi.Skip)
+ continue;
+ size = mi.AltStreams[ui.AltStreamIndex].Size;
+ }
+ else
+ {
+ size = mi.Size;
+ if (mi.IsDir)
+ {
+ // we support LINK files here
+ if (mi.Reparse.Size() == 0)
+ continue;
+ }
+ }
+
+ if (ui.InArcIndex >= 0)
+ {
+ // data streams with OLD Data were written already
+ // we just need to find HashIndex in hashes.
+
+ if ((unsigned)ui.InArcIndex >= _db.SortedItems.Size())
+ return E_FAIL;
+
+ const CItem &item = _db.Items[_db.SortedItems[ui.InArcIndex]];
+
+ if (item.StreamIndex < 0)
+ {
+ if (size == 0)
+ continue;
+ // if (_db.ItemHasStream(item))
+ return E_FAIL;
+ }
+
+ // We support empty file (size = 0, but with stream and SHA-1) from old archive
+
+ const CStreamInfo &siOld = _db.DataStreams[item.StreamIndex];
+
+ const int index = AddUniqHash(&streams.Front(), sortedHashes, siOld.Hash, -1);
+ // we must have written that stream already
+ if (index == -1)
+ return E_FAIL;
+
+ if (ui.AltStreamIndex < 0)
+ mi.HashIndex = index;
+ else
+ mi.AltStreams[ui.AltStreamIndex].HashIndex = index;
+
+ continue;
+ }
+
+ CMyComPtr<ISequentialInStream> fileInStream;
+ HRESULT res = callback->GetStream(ui.CallbackIndex, &fileInStream);
+
+ if (res == S_FALSE)
+ {
+ if (ui.AltStreamIndex >= 0)
+ {
+ mi.NumSkipAltStreams++;
+ mi.AltStreams[ui.AltStreamIndex].Skip = true;
+ }
+ else
+ mi.Skip = true;
+ }
+ else
+ {
+ RINOK(res)
+
+ int miIndex = -1;
+
+ if (!fileInStream)
+ {
+ if (!mi.IsDir)
+ return E_INVALIDARG;
+ }
+ else if (ui.AltStreamIndex < 0)
+ {
+ CMyComPtr<IStreamGetProps2> getProps2;
+ fileInStream->QueryInterface(IID_IStreamGetProps2, (void **)&getProps2);
+ if (getProps2)
+ {
+ CStreamFileProps props;
+ if (getProps2->GetProps2(&props) == S_OK)
+ {
+ mi.Attrib = props.Attrib;
+ if (_timeOptions.Write_CTime.Val) mi.CTime = props.CTime;
+ if (_timeOptions.Write_ATime.Val) mi.ATime = props.ATime;
+ if (_timeOptions.Write_MTime.Val) mi.MTime = props.MTime;
+ mi.FileID = props.FileID_Low;
+ if (props.NumLinks <= 1)
+ mi.FileID = 0;
+ mi.VolID = props.VolID;
+ if (mi.FileID != 0)
+ miIndex = AddToHardLinkList(db.MetaItems, (unsigned)ui.MetaIndex, hlIndexes);
+
+ if (props.Size != size && props.Size != (UInt64)(Int64)-1)
+ {
+ const Int64 delta = (Int64)props.Size - (Int64)size;
+ const Int64 newComplexity = (Int64)totalComplexity + delta;
+ if (newComplexity > 0)
+ {
+ totalComplexity = (UInt64)newComplexity;
+ callback->SetTotal(totalComplexity);
+ }
+ mi.Size = props.Size;
+ size = props.Size;
+ }
+ }
+ }
+ }
+
+ if (miIndex >= 0)
+ {
+ mi.HashIndex = db.MetaItems[miIndex].HashIndex;
+ if (mi.HashIndex >= 0)
+ streams[mi.HashIndex].RefCount++;
+ // fix for future: maybe we need to check also that real size is equal to size from IStreamGetProps2
+ }
+ else if (ui.AltStreamIndex < 0 && mi.Reparse.Size() != 0)
+ {
+ if (mi.Reparse.Size() < 8)
+ return E_FAIL;
+ NCrypto::NSha1::CContext sha1;
+ sha1.Init();
+ const size_t packSize = mi.Reparse.Size() - 8;
+ sha1.Update((const Byte *)mi.Reparse + 8, packSize);
+ Byte hash[kHashSize];
+ sha1.Final(hash);
+
+ int index = AddUniqHash(&streams.Front(), sortedHashes, hash, (int)streams.Size());
+
+ if (index != -1)
+ streams[index].RefCount++;
+ else
+ {
+ index = (int)streams.Size();
+ RINOK(WriteStream(outStream, (const Byte *)mi.Reparse + 8, packSize))
+ CStreamInfo s;
+ s.Resource.PackSize = packSize;
+ s.Resource.Offset = curPos;
+ s.Resource.UnpackSize = packSize;
+ s.Resource.Flags = 0; // check it
+ /*
+ if (useResourceCompression)
+ s.Resource.Flags = NResourceFlags::Compressed;
+ */
+ s.PartNumber = 1;
+ s.RefCount = 1;
+ memcpy(s.Hash, hash, kHashSize);
+ curPos += packSize;
+
+ streams.Add(s);
+ }
+
+ mi.HashIndex = index;
+ }
+ else
+ {
+ inShaStreamSpec->SetStream(fileInStream);
+
+ CMyComPtr<IInStream> inSeekStream;
+ fileInStream.QueryInterface(IID_IInStream, (void **)&inSeekStream);
+
+ fileInStream.Release();
+ inShaStreamSpec->Init();
+ UInt64 offsetBlockSize = 0;
+ /*
+ if (useResourceCompression)
+ {
+ for (UInt64 t = kChunkSize; t < size; t += kChunkSize)
+ {
+ Byte buf[8];
+ SetUi32(buf, (UInt32)t);
+ RINOK(WriteStream(outStream, buf, 4));
+ offsetBlockSize += 4;
+ }
+ }
+ */
+
+ // 22.02: we use additional read-only pass to calculate SHA-1
+ bool needWritePass = true;
+ int index = -1;
+
+ if (inSeekStream /* && !sortedHashes.IsEmpty() */)
+ {
+ RINOK(copyCoder->Code(inShaStream, NULL, NULL, NULL, progress))
+ size = copyCoderSpec->TotalSize;
+ if (size == 0)
+ needWritePass = false;
+ else
+ {
+ Byte hash[kHashSize];
+ inShaStreamSpec->Final(hash);
+
+ index = AddUniqHash(&streams.Front(), sortedHashes, hash, -1);
+ if (index != -1)
+ {
+ streams[index].RefCount++;
+ needWritePass = false;
+ }
+ else
+ {
+ RINOK(InStream_SeekToBegin(inSeekStream))
+ inShaStreamSpec->Init();
+ }
+ }
+ }
+
+ if (needWritePass)
+ {
+ RINOK(copyCoder->Code(inShaStream, outStream, NULL, NULL, progress))
+ size = copyCoderSpec->TotalSize;
+ }
+
+ if (size != 0)
+ {
+ if (needWritePass)
+ {
+ Byte hash[kHashSize];
+ const UInt64 packSize = offsetBlockSize + size;
+ inShaStreamSpec->Final(hash);
+
+ index = AddUniqHash(&streams.Front(), sortedHashes, hash, (int)streams.Size());
+
+ if (index != -1)
+ {
+ streams[index].RefCount++;
+ outStream->Seek(-(Int64)packSize, STREAM_SEEK_CUR, &curPos);
+ outStream->SetSize(curPos);
+ }
+ else
+ {
+ index = (int)streams.Size();
+ CStreamInfo s;
+ s.Resource.PackSize = packSize;
+ s.Resource.Offset = curPos;
+ s.Resource.UnpackSize = size;
+ s.Resource.Flags = 0;
+ /*
+ if (useResourceCompression)
+ s.Resource.Flags = NResourceFlags::Compressed;
+ */
+ s.PartNumber = 1;
+ s.RefCount = 1;
+ memcpy(s.Hash, hash, kHashSize);
+ curPos += packSize;
+
+ streams.Add(s);
+ }
+ } // needWritePass
+ if (ui.AltStreamIndex < 0)
+ mi.HashIndex = index;
+ else
+ mi.AltStreams[ui.AltStreamIndex].HashIndex = index;
+ } // (size != 0)
+ }
+ }
+ fileInStream.Release();
+ complexity += size;
+ RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK))
+ }
+
+ while (secureBlocks.Size() < numNewImages)
+ secureBlocks.AddNew();
+
+
+
+ // ---------- Write Images ----------
+
+ for (i = 0; i < numNewImages; i++)
+ {
+ lps->InSize = lps->OutSize = complexity;
+ RINOK(lps->SetCur())
+ if (i < isChangedImage.Size() && !isChangedImage[i])
+ {
+ CStreamInfo s = _db.MetaStreams[i];
+
+ RINOK(InStream_SeekSet(_volumes[1].Stream, s.Resource.Offset))
+ inStreamLimitedSpec->Init(s.Resource.PackSize);
+ RINOK(copyCoder->Code(inStreamLimited, outStream, NULL, NULL, progress))
+ if (copyCoderSpec->TotalSize != s.Resource.PackSize)
+ return E_FAIL;
+
+ s.Resource.Offset = curPos;
+ s.PartNumber = 1;
+ s.RefCount = 1;
+ streams.Add(s);
+
+ if (_bootIndex != 0 && _bootIndex == (UInt32)i + 1)
+ {
+ header.MetadataResource = s.Resource;
+ header.BootIndex = _bootIndex;
+ }
+
+ lps->ProgressOffset += s.Resource.PackSize;
+ curPos += s.Resource.PackSize;
+ // printf("\nWrite old image %x\n", i + 1);
+ continue;
+ }
+
+ const CDir &tree = trees[i];
+ const UInt32 kSecuritySize = 8;
+
+ size_t pos = kSecuritySize;
+
+ const CUniqBlocks &secUniqBlocks = secureBlocks[i];
+ const CObjectVector<CByteBuffer> &secBufs = secUniqBlocks.Bufs;
+ pos += (size_t)secUniqBlocks.GetTotalSizeInBytes();
+ pos += secBufs.Size() * 8;
+ pos = (pos + 7) & ~(size_t)7;
+
+ db.DefaultDirItem = ri;
+ pos += db.WriteTree_Dummy(tree);
+
+ CByteArr meta(pos);
+
+ Set32((Byte *)meta + 4, secBufs.Size()) // num security entries
+ pos = kSecuritySize;
+
+ if (secBufs.Size() == 0)
+ {
+ // we can write 0 here only if there is no security data, imageX does it,
+ // but some programs expect size = 8
+ Set32((Byte *)meta, 8) // size of security data
+ // Set32((Byte *)meta, 0);
+ }
+ else
+ {
+ unsigned k;
+ for (k = 0; k < secBufs.Size(); k++, pos += 8)
+ {
+ Set64(meta + pos, secBufs[k].Size())
+ }
+ for (k = 0; k < secBufs.Size(); k++)
+ {
+ const CByteBuffer &buf = secBufs[k];
+ size_t size = buf.Size();
+ if (size != 0)
+ {
+ memcpy(meta + pos, buf, size);
+ pos += size;
+ }
+ }
+ while ((pos & 7) != 0)
+ meta[pos++] = 0;
+ Set32((Byte *)meta, (UInt32)pos) // size of security data
+ }
+
+ db.Hashes = &streams.Front();
+ db.WriteTree(tree, (Byte *)meta, pos);
+
+ {
+ NCrypto::NSha1::CContext sha;
+ sha.Init();
+ sha.Update((const Byte *)meta, pos);
+
+ Byte digest[kHashSize];
+ sha.Final(digest);
+
+ CStreamInfo s;
+ s.Resource.PackSize = pos;
+ s.Resource.Offset = curPos;
+ s.Resource.UnpackSize = pos;
+ s.Resource.Flags = NResourceFlags::kMetadata;
+ s.PartNumber = 1;
+ s.RefCount = 1;
+ memcpy(s.Hash, digest, kHashSize);
+ streams.Add(s);
+
+ if (_bootIndex != 0 && _bootIndex == (UInt32)i + 1)
+ {
+ header.MetadataResource = s.Resource;
+ header.BootIndex = _bootIndex;
+ }
+
+ RINOK(WriteStream(outStream, (const Byte *)meta, pos))
+ meta.Free();
+ curPos += pos;
+ }
+ }
+
+ lps->InSize = lps->OutSize = complexity;
+ RINOK(lps->SetCur())
+
+ header.OffsetResource.UnpackSize = header.OffsetResource.PackSize = (UInt64)streams.Size() * kStreamInfoSize;
+ header.OffsetResource.Offset = curPos;
+ header.OffsetResource.Flags = NResourceFlags::kMetadata;
+
+
+
+ // ---------- Write Streams Info Tables ----------
+
+ for (i = 0; i < streams.Size(); i++)
+ {
+ Byte buf[kStreamInfoSize];
+ streams[i].WriteTo(buf);
+ RINOK(WriteStream(outStream, buf, kStreamInfoSize))
+ curPos += kStreamInfoSize;
+ }
+
+ AString xml ("<WIM>");
+ AddTagUInt64_ToString(xml, "TOTALBYTES", curPos);
+ for (i = 0; i < trees.Size(); i++)
+ {
+ const CDir &tree = trees[i];
+
+ CXmlItem item;
+ if (_xmls.Size() == 1)
+ {
+ const CWimXml &_oldXml = _xmls[0];
+ if (i < _oldXml.Images.Size())
+ {
+ // int ttt = _oldXml.Images[i].ItemIndexInXml;
+ item = _oldXml.Xml.Root.SubItems[_oldXml.Images[i].ItemIndexInXml];
+ }
+ }
+ if (i >= isChangedImage.Size() || isChangedImage[i])
+ {
+ char temp[16];
+ if (item.Name.IsEmpty())
+ {
+ ConvertUInt32ToString(i + 1, temp);
+ item.Name = "IMAGE";
+ item.IsTag = true;
+ CXmlProp &prop = item.Props.AddNew();
+ prop.Name = "INDEX";
+ prop.Value = temp;
+ }
+
+ AddTag_String_IfEmpty(item, "NAME", temp);
+ AddTag_UInt64(item, "DIRCOUNT", tree.GetNumDirs() - 1);
+ AddTag_UInt64(item, "FILECOUNT", tree.GetNumFiles());
+ AddTag_UInt64(item, "TOTALBYTES", tree.GetTotalSize(db.MetaItems));
+
+ AddTag_Time(item, "CREATIONTIME", ftCur);
+ AddTag_Time(item, "LASTMODIFICATIONTIME", ftCur);
+ }
+
+ item.AppendTo(xml);
+ }
+ xml += "</WIM>";
+
+ size_t xmlSize;
+ {
+ UString utf16;
+ if (!ConvertUTF8ToUnicode(xml, utf16))
+ return S_FALSE;
+ xmlSize = ((size_t)utf16.Len() + 1) * 2;
+
+ CByteArr xmlBuf(xmlSize);
+ Set16((Byte *)xmlBuf, 0xFEFF)
+ for (i = 0; i < (unsigned)utf16.Len(); i++)
+ {
+ Set16((Byte *)xmlBuf + 2 + (size_t)i * 2, (UInt16)utf16[i])
+ }
+ RINOK(WriteStream(outStream, (const Byte *)xmlBuf, xmlSize))
+ }
+
+ header.XmlResource.UnpackSize =
+ header.XmlResource.PackSize = xmlSize;
+ header.XmlResource.Offset = curPos;
+ header.XmlResource.Flags = NResourceFlags::kMetadata;
+
+ outStream->Seek(0, STREAM_SEEK_SET, NULL);
+ header.NumImages = trees.Size();
+ {
+ Byte buf[kHeaderSizeMax];
+ header.WriteTo(buf);
+ RINOK(WriteStream(outStream, buf, kHeaderSizeMax))
+ }
+
+ if (setRestriction)
+ RINOK(setRestriction->SetRestriction(0, 0))
+
+ return S_OK;
+
+ COM_TRY_END
+}
+
+}}
diff --git a/CPP/7zip/Archive/Wim/WimIn.cpp b/CPP/7zip/Archive/Wim/WimIn.cpp
new file mode 100644
index 0000000..ff118d8
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/WimIn.cpp
@@ -0,0 +1,1878 @@
+// Archive/WimIn.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringToInt.h"
+#include "../../../Common/UTFConvert.h"
+
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/XpressDecoder.h"
+
+#include "../Common/OutStreamWithSha1.h"
+
+#include "WimIn.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+namespace NArchive {
+namespace NWim {
+
+static int inline GetLog(UInt32 num)
+{
+ for (int i = 0; i < 32; i++)
+ if (((UInt32)1 << i) == num)
+ return i;
+ return -1;
+}
+
+
+CUnpacker::~CUnpacker()
+{
+ if (lzmsDecoder)
+ delete lzmsDecoder;
+}
+
+
+HRESULT CUnpacker::UnpackChunk(
+ ISequentialInStream *inStream,
+ unsigned method, unsigned chunkSizeBits,
+ size_t inSize, size_t outSize,
+ ISequentialOutStream *outStream)
+{
+ if (inSize == outSize)
+ {
+ }
+ else if (method == NMethod::kXPRESS)
+ {
+ }
+ else if (method == NMethod::kLZX)
+ {
+ if (!lzxDecoder)
+ {
+ lzxDecoderSpec = new NCompress::NLzx::CDecoder(true);
+ lzxDecoder = lzxDecoderSpec;
+ }
+ }
+ else if (method == NMethod::kLZMS)
+ {
+ if (!lzmsDecoder)
+ lzmsDecoder = new NCompress::NLzms::CDecoder();
+ }
+ else
+ return E_NOTIMPL;
+
+ const size_t chunkSize = (size_t)1 << chunkSizeBits;
+
+ unpackBuf.EnsureCapacity(chunkSize);
+ if (!unpackBuf.Data)
+ return E_OUTOFMEMORY;
+
+ HRESULT res = S_FALSE;
+ size_t unpackedSize = 0;
+
+ if (inSize == outSize)
+ {
+ unpackedSize = outSize;
+ res = ReadStream(inStream, unpackBuf.Data, &unpackedSize);
+ TotalPacked += unpackedSize;
+ }
+ else if (inSize < chunkSize)
+ {
+ packBuf.EnsureCapacity(chunkSize);
+ if (!packBuf.Data)
+ return E_OUTOFMEMORY;
+
+ RINOK(ReadStream_FALSE(inStream, packBuf.Data, inSize))
+
+ TotalPacked += inSize;
+
+ if (method == NMethod::kXPRESS)
+ {
+ res = NCompress::NXpress::Decode(packBuf.Data, inSize, unpackBuf.Data, outSize);
+ if (res == S_OK)
+ unpackedSize = outSize;
+ }
+ else if (method == NMethod::kLZX)
+ {
+ res = lzxDecoderSpec->SetExternalWindow(unpackBuf.Data, chunkSizeBits);
+ if (res != S_OK)
+ return E_NOTIMPL;
+ lzxDecoderSpec->KeepHistoryForNext = false;
+ lzxDecoderSpec->SetKeepHistory(false);
+ res = lzxDecoderSpec->Code(packBuf.Data, inSize, (UInt32)outSize);
+ unpackedSize = lzxDecoderSpec->GetUnpackSize();
+ if (res == S_OK && !lzxDecoderSpec->WasBlockFinished())
+ res = S_FALSE;
+ }
+ else
+ {
+ res = lzmsDecoder->Code(packBuf.Data, inSize, unpackBuf.Data, outSize);
+ unpackedSize = lzmsDecoder->GetUnpackSize();
+ }
+ }
+
+ if (unpackedSize != outSize)
+ {
+ if (res == S_OK)
+ res = S_FALSE;
+
+ if (unpackedSize > outSize)
+ res = S_FALSE;
+ else
+ memset(unpackBuf.Data + unpackedSize, 0, outSize - unpackedSize);
+ }
+
+ if (outStream)
+ {
+ RINOK(WriteStream(outStream, unpackBuf.Data, outSize))
+ }
+
+ return res;
+}
+
+
+HRESULT CUnpacker::Unpack2(
+ IInStream *inStream,
+ const CResource &resource,
+ const CHeader &header,
+ const CDatabase *db,
+ ISequentialOutStream *outStream,
+ ICompressProgressInfo *progress)
+{
+ if (!resource.IsCompressed() && !resource.IsSolid())
+ {
+ if (!copyCoder)
+ {
+ copyCoderSpec = new NCompress::CCopyCoder;
+ copyCoder = copyCoderSpec;
+ }
+
+ CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream();
+ CMyComPtr<ISequentialInStream> limitedStream = limitedStreamSpec;
+ limitedStreamSpec->SetStream(inStream);
+
+ RINOK(InStream_SeekSet(inStream, resource.Offset))
+ if (resource.PackSize != resource.UnpackSize)
+ return S_FALSE;
+
+ limitedStreamSpec->Init(resource.PackSize);
+ TotalPacked += resource.PackSize;
+
+ HRESULT res = copyCoder->Code(limitedStream, outStream, NULL, NULL, progress);
+
+ if (res == S_OK && copyCoderSpec->TotalSize != resource.UnpackSize)
+ res = S_FALSE;
+ return res;
+ }
+
+ if (resource.IsSolid())
+ {
+ if (!db || resource.SolidIndex < 0)
+ return E_NOTIMPL;
+ if (resource.IsCompressed())
+ return E_NOTIMPL;
+
+ const CSolid &ss = db->Solids[resource.SolidIndex];
+
+ const unsigned chunkSizeBits = ss.ChunkSizeBits;
+ const size_t chunkSize = (size_t)1 << chunkSizeBits;
+
+ size_t chunkIndex = 0;
+ UInt64 rem = ss.UnpackSize;
+ size_t offsetInChunk = 0;
+
+ if (resource.IsSolidSmall())
+ {
+ UInt64 offs = resource.Offset;
+ if (offs < ss.SolidOffset)
+ return E_NOTIMPL;
+ offs -= ss.SolidOffset;
+ if (offs > ss.UnpackSize)
+ return E_NOTIMPL;
+ rem = resource.PackSize;
+ if (rem > ss.UnpackSize - offs)
+ return E_NOTIMPL;
+ chunkIndex = (size_t)(offs >> chunkSizeBits);
+ offsetInChunk = (size_t)offs & (chunkSize - 1);
+ }
+
+ UInt64 packProcessed = 0;
+ UInt64 outProcessed = 0;
+
+ if (_solidIndex == resource.SolidIndex && _unpackedChunkIndex == chunkIndex)
+ {
+ size_t cur = chunkSize - offsetInChunk;
+ if (cur > rem)
+ cur = (size_t)rem;
+ RINOK(WriteStream(outStream, unpackBuf.Data + offsetInChunk, cur))
+ outProcessed += cur;
+ rem -= cur;
+ offsetInChunk = 0;
+ chunkIndex++;
+ }
+
+ for (;;)
+ {
+ if (rem == 0)
+ return S_OK;
+
+ const UInt64 offset = ss.Chunks[chunkIndex];
+ const UInt64 packSize = ss.GetChunkPackSize(chunkIndex);
+ const CResource &rs = db->DataStreams[ss.StreamIndex].Resource;
+ RINOK(InStream_SeekSet(inStream, rs.Offset + ss.HeadersSize + offset))
+
+ size_t cur = chunkSize;
+ const UInt64 unpackRem = ss.UnpackSize - ((UInt64)chunkIndex << chunkSizeBits);
+ if (cur > unpackRem)
+ cur = (size_t)unpackRem;
+
+ _solidIndex = -1;
+ _unpackedChunkIndex = 0;
+
+ const HRESULT res = UnpackChunk(inStream, (unsigned)ss.Method, chunkSizeBits, (size_t)packSize, cur, NULL);
+
+ if (res != S_OK)
+ {
+ // We ignore data errors in solid stream. SHA will show what files are bad.
+ if (res != S_FALSE)
+ return res;
+ }
+
+ _solidIndex = resource.SolidIndex;
+ _unpackedChunkIndex = chunkIndex;
+
+ if (cur < offsetInChunk)
+ return E_FAIL;
+
+ cur -= offsetInChunk;
+
+ if (cur > rem)
+ cur = (size_t)rem;
+
+ RINOK(WriteStream(outStream, unpackBuf.Data + offsetInChunk, cur))
+
+ if (progress)
+ {
+ RINOK(progress->SetRatioInfo(&packProcessed, &outProcessed))
+ packProcessed += packSize;
+ outProcessed += cur;
+ }
+
+ rem -= cur;
+ offsetInChunk = 0;
+ chunkIndex++;
+ }
+ }
+
+
+ // ---------- NON Solid ----------
+
+ const UInt64 unpackSize = resource.UnpackSize;
+ if (unpackSize == 0)
+ {
+ if (resource.PackSize == 0)
+ return S_OK;
+ return S_FALSE;
+ }
+
+ if (unpackSize > ((UInt64)1 << 63))
+ return E_NOTIMPL;
+
+ const unsigned chunkSizeBits = header.ChunkSizeBits;
+ const unsigned entrySizeShifts = (resource.UnpackSize < ((UInt64)1 << 32) ? 2 : 3);
+
+ UInt64 baseOffset = resource.Offset;
+ UInt64 packDataSize;
+ size_t numChunks;
+ {
+ const UInt64 numChunks64 = (unpackSize + (((UInt32)1 << chunkSizeBits) - 1)) >> chunkSizeBits;
+ const UInt64 sizesBufSize64 = (numChunks64 - 1) << entrySizeShifts;
+ if (sizesBufSize64 > resource.PackSize)
+ return S_FALSE;
+ packDataSize = resource.PackSize - sizesBufSize64;
+ const size_t sizesBufSize = (size_t)sizesBufSize64;
+ if (sizesBufSize != sizesBufSize64)
+ return E_OUTOFMEMORY;
+ sizesBuf.AllocAtLeast(sizesBufSize);
+ RINOK(InStream_SeekSet(inStream, baseOffset))
+ RINOK(ReadStream_FALSE(inStream, sizesBuf, sizesBufSize))
+ baseOffset += sizesBufSize64;
+ numChunks = (size_t)numChunks64;
+ }
+
+ _solidIndex = -1;
+ _unpackedChunkIndex = 0;
+
+ UInt64 outProcessed = 0;
+ UInt64 offset = 0;
+
+ for (size_t i = 0; i < numChunks; i++)
+ {
+ UInt64 nextOffset = packDataSize;
+
+ if (i + 1 < numChunks)
+ {
+ const Byte *p = (const Byte *)sizesBuf + (i << entrySizeShifts);
+ nextOffset = (entrySizeShifts == 2) ? Get32(p): Get64(p);
+ }
+
+ if (nextOffset < offset)
+ return S_FALSE;
+
+ UInt64 inSize64 = nextOffset - offset;
+ size_t inSize = (size_t)inSize64;
+ if (inSize != inSize64)
+ return S_FALSE;
+
+ RINOK(InStream_SeekSet(inStream, baseOffset + offset))
+
+ if (progress)
+ {
+ RINOK(progress->SetRatioInfo(&offset, &outProcessed))
+ }
+
+ size_t outSize = (size_t)1 << chunkSizeBits;
+ const UInt64 rem = unpackSize - outProcessed;
+ if (outSize > rem)
+ outSize = (size_t)rem;
+
+ RINOK(UnpackChunk(inStream, header.GetMethod(), chunkSizeBits, inSize, outSize, outStream))
+
+ outProcessed += outSize;
+ offset = nextOffset;
+ }
+
+ return S_OK;
+}
+
+
+HRESULT CUnpacker::Unpack(IInStream *inStream, const CResource &resource, const CHeader &header, const CDatabase *db,
+ ISequentialOutStream *outStream, ICompressProgressInfo *progress, Byte *digest)
+{
+ COutStreamWithSha1 *shaStreamSpec = NULL;
+ CMyComPtr<ISequentialOutStream> shaStream;
+
+ // outStream can be NULL, so we use COutStreamWithSha1 even if sha1 is not required
+ // if (digest)
+ {
+ shaStreamSpec = new COutStreamWithSha1();
+ shaStream = shaStreamSpec;
+ shaStreamSpec->SetStream(outStream);
+ shaStreamSpec->Init(digest != NULL);
+ outStream = shaStream;
+ }
+
+ HRESULT res = Unpack2(inStream, resource, header, db, outStream, progress);
+
+ if (digest)
+ shaStreamSpec->Final(digest);
+
+ return res;
+}
+
+
+HRESULT CUnpacker::UnpackData(IInStream *inStream,
+ const CResource &resource, const CHeader &header,
+ const CDatabase *db,
+ CByteBuffer &buf, Byte *digest)
+{
+ // if (resource.IsSolid()) return E_NOTIMPL;
+
+ UInt64 unpackSize64 = resource.UnpackSize;
+ if (db)
+ unpackSize64 = db->Get_UnpackSize_of_Resource(resource);
+
+ size_t size = (size_t)unpackSize64;
+ if (size != unpackSize64)
+ return E_OUTOFMEMORY;
+
+ buf.Alloc(size);
+
+ CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream();
+ CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+ outStreamSpec->Init((Byte *)buf, size);
+
+ return Unpack(inStream, resource, header, db, outStream, NULL, digest);
+}
+
+
+void CResource::Parse(const Byte *p)
+{
+ Flags = p[7];
+ PackSize = Get64(p) & (((UInt64)1 << 56) - 1);
+ Offset = Get64(p + 8);
+ UnpackSize = Get64(p + 16);
+ KeepSolid = false;
+ SolidIndex = -1;
+}
+
+#define GET_RESOURCE(_p_, res) res.ParseAndUpdatePhySize(_p_, phySize)
+
+static inline void ParseStream(bool oldVersion, const Byte *p, CStreamInfo &s)
+{
+ s.Resource.Parse(p);
+ if (oldVersion)
+ {
+ s.PartNumber = 1;
+ s.Id = Get32(p + 24);
+ p += 28;
+ }
+ else
+ {
+ s.PartNumber = Get16(p + 24);
+ p += 26;
+ }
+ s.RefCount = Get32(p);
+ memcpy(s.Hash, p + 4, kHashSize);
+}
+
+
+#define kLongPath "[LongPath]"
+
+void CDatabase::GetShortName(unsigned index, NWindows::NCOM::CPropVariant &name) const
+{
+ const CItem &item = Items[index];
+ const CImage &image = Images[item.ImageIndex];
+ if (item.Parent < 0 && image.NumEmptyRootItems != 0)
+ {
+ name.Clear();
+ return;
+ }
+ const Byte *meta = image.Meta + item.Offset +
+ (IsOldVersion ? kDirRecordSizeOld : kDirRecordSize);
+ UInt32 fileNameLen = Get16(meta - 2);
+ UInt32 shortLen = Get16(meta - 4) / 2;
+ wchar_t *s = name.AllocBstr(shortLen);
+ if (fileNameLen != 0)
+ meta += fileNameLen + 2;
+ for (UInt32 i = 0; i < shortLen; i++)
+ s[i] = Get16(meta + i * 2);
+ s[shortLen] = 0;
+ // empty shortName has no ZERO at the end ?
+}
+
+
+void CDatabase::GetItemName(unsigned index, NWindows::NCOM::CPropVariant &name) const
+{
+ const CItem &item = Items[index];
+ const CImage &image = Images[item.ImageIndex];
+ if (item.Parent < 0 && image.NumEmptyRootItems != 0)
+ {
+ name = image.RootName;
+ return;
+ }
+ const Byte *meta = image.Meta + item.Offset +
+ (item.IsAltStream ?
+ (IsOldVersion ? 0x10 : 0x24) :
+ (IsOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2));
+ UInt32 len = Get16(meta) / 2;
+ wchar_t *s = name.AllocBstr(len);
+ meta += 2;
+ len++;
+ for (UInt32 i = 0; i < len; i++)
+ s[i] = Get16(meta + i * 2);
+}
+
+
+void CDatabase::GetItemPath(unsigned index1, bool showImageNumber, NWindows::NCOM::CPropVariant &path) const
+{
+ unsigned size = 0;
+ int index = (int)index1;
+ const int imageIndex = Items[index].ImageIndex;
+ const CImage &image = Images[imageIndex];
+
+ unsigned newLevel = 0;
+ bool needColon = false;
+
+ for (;;)
+ {
+ const CItem &item = Items[index];
+ index = item.Parent;
+ if (index >= 0 || image.NumEmptyRootItems == 0)
+ {
+ const Byte *meta = image.Meta + item.Offset;
+ meta += item.IsAltStream ?
+ (IsOldVersion ? 0x10 : 0x24) :
+ (IsOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2);
+ needColon = item.IsAltStream;
+ size += Get16(meta) / 2;
+ size += newLevel;
+ newLevel = 1;
+ if (size >= ((UInt32)1 << 15))
+ {
+ path = kLongPath;
+ return;
+ }
+ }
+ if (index < 0)
+ break;
+ }
+
+ if (showImageNumber)
+ {
+ size += image.RootName.Len();
+ size += newLevel;
+ }
+ else if (needColon)
+ size++;
+
+ wchar_t *s = path.AllocBstr(size);
+ s[size] = 0;
+
+ if (showImageNumber)
+ {
+ MyStringCopy(s, (const wchar_t *)image.RootName);
+ if (newLevel)
+ s[image.RootName.Len()] = (wchar_t)(needColon ? L':' : WCHAR_PATH_SEPARATOR);
+ }
+ else if (needColon)
+ s[0] = L':';
+
+ index = (int)index1;
+ wchar_t separator = 0;
+
+ for (;;)
+ {
+ const CItem &item = Items[index];
+ index = item.Parent;
+ if (index >= 0 || image.NumEmptyRootItems == 0)
+ {
+ if (separator != 0)
+ s[--size] = separator;
+ const Byte *meta = image.Meta + item.Offset;
+ meta += (item.IsAltStream) ?
+ (IsOldVersion ? 0x10: 0x24) :
+ (IsOldVersion ? kDirRecordSizeOld - 2 : kDirRecordSize - 2);
+ unsigned len = Get16(meta) / 2;
+ size -= len;
+ wchar_t *dest = s + size;
+ meta += 2;
+ for (unsigned i = 0; i < len; i++)
+ {
+ wchar_t c = Get16(meta + i * 2);
+ if (c == L'/')
+ c = L'_';
+ #if WCHAR_PATH_SEPARATOR != L'/'
+ else if (c == L'\\')
+ c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // 22.00 : WSL scheme
+ #endif
+ dest[i] = c;
+ }
+ }
+ if (index < 0)
+ return;
+ separator = item.IsAltStream ? L':' : WCHAR_PATH_SEPARATOR;
+ }
+}
+
+
+// if (ver <= 1.10), root folder contains real items.
+// if (ver >= 1.12), root folder contains only one folder with empty name.
+
+HRESULT CDatabase::ParseDirItem(size_t pos, int parent)
+{
+ const unsigned align = GetDirAlignMask();
+ if ((pos & align) != 0)
+ return S_FALSE;
+
+ for (unsigned numItems = 0;; numItems++)
+ {
+ if (OpenCallback && (Items.Size() & 0xFFFF) == 0)
+ {
+ UInt64 numFiles = Items.Size();
+ RINOK(OpenCallback->SetCompleted(&numFiles, NULL))
+ }
+
+ const size_t rem = DirSize - pos;
+ if (pos < DirStartOffset || pos > DirSize || rem < 8)
+ return S_FALSE;
+
+ const Byte *p = DirData + pos;
+
+ UInt64 len = Get64(p);
+ if (len == 0)
+ {
+ DirProcessed += 8;
+ return S_OK;
+ }
+
+ if ((len & align) != 0 || rem < len)
+ return S_FALSE;
+
+ DirProcessed += (size_t)len;
+ if (DirProcessed > DirSize)
+ return S_FALSE;
+
+ const unsigned dirRecordSize = IsOldVersion ? kDirRecordSizeOld : kDirRecordSize;
+ if (len < dirRecordSize)
+ return S_FALSE;
+
+ CItem item;
+ UInt32 attrib = Get32(p + 8);
+ item.IsDir = ((attrib & 0x10) != 0);
+ UInt64 subdirOffset = Get64(p + 0x10);
+
+ const UInt32 numAltStreams = Get16(p + dirRecordSize - 6);
+ const UInt32 shortNameLen = Get16(p + dirRecordSize - 4);
+ const UInt32 fileNameLen = Get16(p + dirRecordSize - 2);
+ if ((shortNameLen & 1) != 0 || (fileNameLen & 1) != 0)
+ return S_FALSE;
+ const UInt32 shortNameLen2 = (shortNameLen == 0 ? shortNameLen : shortNameLen + 2);
+ const UInt32 fileNameLen2 = (fileNameLen == 0 ? fileNameLen : fileNameLen + 2);
+ if (((dirRecordSize + fileNameLen2 + shortNameLen2 + align) & ~align) > len)
+ return S_FALSE;
+
+ p += dirRecordSize;
+
+ {
+ if (*(const UInt16 *)(const void *)(p + fileNameLen) != 0)
+ return S_FALSE;
+ for (UInt32 j = 0; j < fileNameLen; j += 2)
+ if (*(const UInt16 *)(const void *)(p + j) == 0)
+ return S_FALSE;
+ }
+
+ // PRF(printf("\n%S", p));
+
+ if (shortNameLen != 0)
+ {
+ // empty shortName has no ZERO at the end ?
+ const Byte *p2 = p + fileNameLen2;
+ if (*(const UInt16 *)(const void *)(p2 + shortNameLen) != 0)
+ return S_FALSE;
+ for (UInt32 j = 0; j < shortNameLen; j += 2)
+ if (*(const UInt16 *)(const void *)(p2 + j) == 0)
+ return S_FALSE;
+ }
+
+ item.Offset = pos;
+ item.Parent = parent;
+ item.ImageIndex = (int)Images.Size() - 1;
+
+ const unsigned prevIndex = Items.Add(item);
+
+ pos += (size_t)len;
+
+ for (UInt32 i = 0; i < numAltStreams; i++)
+ {
+ const size_t rem2 = DirSize - pos;
+ if (pos < DirStartOffset || pos > DirSize || rem2 < 8)
+ return S_FALSE;
+ const Byte *p2 = DirData + pos;
+ const UInt64 len2 = Get64(p2);
+ if ((len2 & align) != 0 || rem2 < len2
+ || len2 < (unsigned)(IsOldVersion ? 0x18 : 0x28))
+ return S_FALSE;
+
+ DirProcessed += (size_t)len2;
+ if (DirProcessed > DirSize)
+ return S_FALSE;
+
+ unsigned extraOffset = 0;
+
+ if (IsOldVersion)
+ extraOffset = 0x10;
+ else
+ {
+ if (Get64(p2 + 8) != 0)
+ return S_FALSE;
+ extraOffset = 0x24;
+ }
+
+ const UInt32 fileNameLen111 = Get16(p2 + extraOffset);
+ if ((fileNameLen111 & 1) != 0)
+ return S_FALSE;
+ /* Probably different versions of ImageX can use different number of
+ additional ZEROs. So we don't use exact check. */
+ const UInt32 fileNameLen222 = (fileNameLen111 == 0 ? fileNameLen111 : fileNameLen111 + 2);
+ if (((extraOffset + 2 + fileNameLen222 + align) & ~align) > len2)
+ return S_FALSE;
+
+ {
+ const Byte *p3 = p2 + extraOffset + 2;
+ if (*(const UInt16 *)(const void *)(p3 + fileNameLen111) != 0)
+ return S_FALSE;
+ for (UInt32 j = 0; j < fileNameLen111; j += 2)
+ if (*(const UInt16 *)(const void *)(p3 + j) == 0)
+ return S_FALSE;
+
+ // PRF(printf("\n %S", p3));
+ }
+
+
+ /* wim uses alt sreams list, if there is at least one alt stream.
+ And alt stream without name is main stream. */
+
+ // Why wimlib writes two alt streams for REPARSE_POINT, with empty second alt stream?
+
+ Byte *prevMeta = DirData + item.Offset;
+
+ if (fileNameLen111 == 0 &&
+ ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) || !item.IsDir)
+ && (IsOldVersion || IsEmptySha(prevMeta + 0x40)))
+ {
+ if (IsOldVersion)
+ memcpy(prevMeta + 0x10, p2 + 8, 4); // It's 32-bit Id
+ else if (!IsEmptySha(p2 + 0x10))
+ {
+ // if (IsEmptySha(prevMeta + 0x40))
+ memcpy(prevMeta + 0x40, p2 + 0x10, kHashSize);
+ // else HeadersError = true;
+ }
+ }
+ else
+ {
+ ThereAreAltStreams = true;
+ CItem item2;
+ item2.Offset = pos;
+ item2.IsAltStream = true;
+ item2.Parent = (int)prevIndex;
+ item2.ImageIndex = (int)Images.Size() - 1;
+ Items.Add(item2);
+ }
+
+ pos += (size_t)len2;
+ }
+
+ if (parent < 0 && numItems == 0 && shortNameLen == 0 && fileNameLen == 0 && item.IsDir)
+ {
+ const Byte *p2 = DirData + pos;
+ if (DirSize - pos >= 8 && Get64(p2) == 0)
+ {
+ CImage &image = Images.Back();
+ image.NumEmptyRootItems = 1;
+
+ if (subdirOffset != 0
+ && DirSize - pos >= 16
+ && Get64(p2 + 8) != 0
+ && pos + 8 < subdirOffset)
+ {
+ // Longhorn.4093 contains hidden files after empty root folder and before items of next folder. Why?
+ // That code shows them. If we want to ignore them, we need to update DirProcessed.
+ // DirProcessed += (size_t)(subdirOffset - (pos + 8));
+ // printf("\ndirOffset = %5d hiddenOffset = %5d\n", (int)subdirOffset, (int)pos + 8);
+ subdirOffset = pos + 8;
+ // return S_FALSE;
+ }
+ }
+ }
+
+ if (item.IsDir && subdirOffset != 0)
+ {
+ RINOK(ParseDirItem((size_t)subdirOffset, (int)prevIndex))
+ }
+ }
+}
+
+
+HRESULT CDatabase::ParseImageDirs(CByteBuffer &buf, int parent)
+{
+ DirData = buf;
+ DirSize = buf.Size();
+ if (DirSize < 8)
+ return S_FALSE;
+ const Byte *p = DirData;
+ size_t pos = 0;
+ CImage &image = Images.Back();
+
+ if (IsOldVersion)
+ {
+ UInt32 numEntries = Get32(p + 4);
+
+ if (numEntries > (1 << 28) ||
+ numEntries > (DirSize >> 3))
+ return S_FALSE;
+
+ UInt32 sum = 8;
+ if (numEntries != 0)
+ sum = numEntries * 8;
+
+ image.SecurOffsets.ClearAndReserve(numEntries + 1);
+ image.SecurOffsets.AddInReserved(sum);
+
+ for (UInt32 i = 0; i < numEntries; i++)
+ {
+ const Byte *pp = p + (size_t)i * 8;
+ UInt32 len = Get32(pp);
+ if (i != 0 && Get32(pp + 4) != 0)
+ return S_FALSE;
+ if (len > DirSize - sum)
+ return S_FALSE;
+ sum += len;
+ if (sum < len)
+ return S_FALSE;
+ image.SecurOffsets.AddInReserved(sum);
+ }
+
+ pos = sum;
+
+ const size_t align = GetDirAlignMask();
+ pos = (pos + align) & ~(size_t)align;
+ }
+ else
+ {
+ UInt32 totalLen = Get32(p);
+ if (totalLen == 0)
+ pos = 8;
+ else
+ {
+ if (totalLen < 8)
+ return S_FALSE;
+ UInt32 numEntries = Get32(p + 4);
+ pos = 8;
+ if (totalLen > DirSize || numEntries > ((totalLen - 8) >> 3))
+ return S_FALSE;
+ UInt32 sum = (UInt32)pos + numEntries * 8;
+ image.SecurOffsets.ClearAndReserve(numEntries + 1);
+ image.SecurOffsets.AddInReserved(sum);
+
+ for (UInt32 i = 0; i < numEntries; i++, pos += 8)
+ {
+ UInt64 len = Get64(p + pos);
+ if (len > totalLen - sum)
+ return S_FALSE;
+ sum += (UInt32)len;
+ image.SecurOffsets.AddInReserved(sum);
+ }
+
+ pos = sum;
+ pos = (pos + 7) & ~(size_t)7;
+ if (pos != (((size_t)totalLen + 7) & ~(size_t)7))
+ return S_FALSE;
+ }
+ }
+
+ if (pos > DirSize)
+ return S_FALSE;
+
+ DirStartOffset = DirProcessed = pos;
+ image.StartItem = Items.Size();
+
+ RINOK(ParseDirItem(pos, parent))
+
+ image.NumItems = Items.Size() - image.StartItem;
+ if (DirProcessed == DirSize)
+ return S_OK;
+
+ /* Original program writes additional 8 bytes (END_OF_ROOT_FOLDER),
+ but the reference to that folder is empty */
+
+ // we can't use DirProcessed - DirStartOffset == 112 check if there is alt stream in root
+ if (DirProcessed == DirSize - 8 && Get64(p + DirSize - 8) != 0)
+ return S_OK;
+
+ // 18.06: we support cases, when some old dism can capture images
+ // where DirProcessed much smaller than DirSize
+ HeadersError = true;
+ return S_OK;
+ // return S_FALSE;
+}
+
+
+HRESULT CHeader::Parse(const Byte *p, UInt64 &phySize)
+{
+ UInt32 headerSize = Get32(p + 8);
+ phySize = headerSize;
+ Version = Get32(p + 0x0C);
+ Flags = Get32(p + 0x10);
+ if (!IsSupported())
+ return S_FALSE;
+
+ {
+ ChunkSize = Get32(p + 0x14);
+ ChunkSizeBits = kChunkSizeBits;
+ if (ChunkSize != 0)
+ {
+ const int log = GetLog(ChunkSize);
+ if (log < 12)
+ return S_FALSE;
+ ChunkSizeBits = (unsigned)log;
+ }
+ }
+
+ _isOldVersion = false;
+ _isNewVersion = false;
+
+ if (IsSolidVersion())
+ _isNewVersion = true;
+ else
+ {
+ if (Version < 0x010900)
+ return S_FALSE;
+ _isOldVersion = (Version <= 0x010A00);
+ // We don't know details about 1.11 version. So we use headerSize to guess exact features.
+ if (Version == 0x010B00 && headerSize == 0x60)
+ _isOldVersion = true;
+ _isNewVersion = (Version >= 0x010D00);
+ }
+
+ unsigned offset;
+
+ if (IsOldVersion())
+ {
+ if (headerSize != 0x60)
+ return S_FALSE;
+ memset(Guid, 0, 16);
+ offset = 0x18;
+ PartNumber = 1;
+ NumParts = 1;
+ }
+ else
+ {
+ if (headerSize < 0x74)
+ return S_FALSE;
+ memcpy(Guid, p + 0x18, 16);
+ PartNumber = Get16(p + 0x28);
+ NumParts = Get16(p + 0x2A);
+ if (PartNumber == 0 || PartNumber > NumParts)
+ return S_FALSE;
+ offset = 0x2C;
+ if (IsNewVersion())
+ {
+ // if (headerSize < 0xD0)
+ if (headerSize != 0xD0)
+ return S_FALSE;
+ NumImages = Get32(p + offset);
+ offset += 4;
+ }
+ }
+
+ GET_RESOURCE(p + offset , OffsetResource);
+ GET_RESOURCE(p + offset + 0x18, XmlResource);
+ GET_RESOURCE(p + offset + 0x30, MetadataResource);
+ BootIndex = 0;
+
+ if (IsNewVersion())
+ {
+ BootIndex = Get32(p + offset + 0x48);
+ GET_RESOURCE(p + offset + 0x4C, IntegrityResource);
+ }
+
+ return S_OK;
+}
+
+
+const Byte kSignature[kSignatureSize] = { 'M', 'S', 'W', 'I', 'M', 0, 0, 0 };
+
+HRESULT ReadHeader(IInStream *inStream, CHeader &h, UInt64 &phySize)
+{
+ Byte p[kHeaderSizeMax];
+ RINOK(ReadStream_FALSE(inStream, p, kHeaderSizeMax))
+ if (memcmp(p, kSignature, kSignatureSize) != 0)
+ return S_FALSE;
+ return h.Parse(p, phySize);
+}
+
+
+static HRESULT ReadStreams(IInStream *inStream, const CHeader &h, CDatabase &db)
+{
+ CByteBuffer offsetBuf;
+
+ CUnpacker unpacker;
+ RINOK(unpacker.UnpackData(inStream, h.OffsetResource, h, NULL, offsetBuf, NULL))
+
+ const size_t streamInfoSize = h.IsOldVersion() ? kStreamInfoSize + 2 : kStreamInfoSize;
+ {
+ const unsigned numItems = (unsigned)(offsetBuf.Size() / streamInfoSize);
+ if ((size_t)numItems * streamInfoSize != offsetBuf.Size())
+ return S_FALSE;
+ const unsigned numItems2 = db.DataStreams.Size() + numItems;
+ if (numItems2 < numItems)
+ return S_FALSE;
+ db.DataStreams.Reserve(numItems2);
+ }
+
+ bool keepSolid = false;
+
+ for (size_t i = 0; i < offsetBuf.Size(); i += streamInfoSize)
+ {
+ CStreamInfo s;
+ ParseStream(h.IsOldVersion(), (const Byte *)offsetBuf + i, s);
+
+ PRF(printf("\n"));
+ PRF(printf(s.Resource.IsMetadata() ? "### META" : " DATA"));
+ PRF(printf(" %2X", s.Resource.Flags));
+ PRF(printf(" %9I64X", s.Resource.Offset));
+ PRF(printf(" %9I64X", s.Resource.PackSize));
+ PRF(printf(" %9I64X", s.Resource.UnpackSize));
+ PRF(printf(" %d", s.RefCount));
+
+ if (s.PartNumber != h.PartNumber)
+ continue;
+
+ if (s.Resource.IsSolid())
+ {
+ s.Resource.KeepSolid = keepSolid;
+ keepSolid = true;
+ }
+ else
+ {
+ s.Resource.KeepSolid = false;
+ keepSolid = false;
+ }
+
+ if (!s.Resource.IsMetadata())
+ db.DataStreams.AddInReserved(s);
+ else
+ {
+ if (s.Resource.IsSolid())
+ return E_NOTIMPL;
+ if (s.RefCount == 0)
+ {
+ // some wims have such (deleted?) metadata stream.
+ // examples: boot.wim in VistaBeta2, WinPE.wim from WAIK.
+ // db.DataStreams.Add(s);
+ // we can show these delete images, if we comment "continue" command;
+ continue;
+ }
+
+ if (s.RefCount > 1)
+ {
+ return S_FALSE;
+ // s.RefCount--;
+ // db.DataStreams.Add(s);
+ }
+
+ db.MetaStreams.Add(s);
+ }
+ }
+
+ PRF(printf("\n"));
+
+ return S_OK;
+}
+
+
+HRESULT CDatabase::OpenXml(IInStream *inStream, const CHeader &h, CByteBuffer &xml)
+{
+ CUnpacker unpacker;
+ return unpacker.UnpackData(inStream, h.XmlResource, h, this, xml, NULL);
+}
+
+static void SetRootNames(CImage &image, unsigned value)
+{
+ wchar_t temp[16];
+ ConvertUInt32ToString(value, temp);
+ image.RootName = temp;
+ image.RootNameBuf.Alloc(image.RootName.Len() * 2 + 2);
+ Byte *p = image.RootNameBuf;
+ unsigned len = image.RootName.Len() + 1;
+ for (unsigned k = 0; k < len; k++)
+ {
+ p[k * 2] = (Byte)temp[k];
+ p[k * 2 + 1] = 0;
+ }
+}
+
+
+HRESULT CDatabase::Open(IInStream *inStream, const CHeader &h, unsigned numItemsReserve, IArchiveOpenCallback *openCallback)
+{
+ OpenCallback = openCallback;
+ IsOldVersion = h.IsOldVersion();
+ IsOldVersion9 = (h.Version == 0x10900);
+
+ RINOK(ReadStreams(inStream, h, *this))
+
+ bool needBootMetadata = !h.MetadataResource.IsEmpty();
+ unsigned numNonDeletedImages = 0;
+
+ CUnpacker unpacker;
+
+ FOR_VECTOR (i, MetaStreams)
+ {
+ const CStreamInfo &si = MetaStreams[i];
+
+ if (h.PartNumber != 1 || si.PartNumber != h.PartNumber)
+ continue;
+
+ const unsigned userImage = Images.Size() + GetStartImageIndex();
+ CImage &image = Images.AddNew();
+ SetRootNames(image, userImage);
+
+ CByteBuffer &metadata = image.Meta;
+ Byte hash[kHashSize];
+
+ RINOK(unpacker.UnpackData(inStream, si.Resource, h, this, metadata, hash))
+
+ if (memcmp(hash, si.Hash, kHashSize) != 0 &&
+ !(h.IsOldVersion() && IsEmptySha(si.Hash)))
+ return S_FALSE;
+
+ image.NumEmptyRootItems = 0;
+
+ if (Items.IsEmpty())
+ Items.ClearAndReserve(numItemsReserve);
+
+ RINOK(ParseImageDirs(metadata, -1))
+
+ if (needBootMetadata)
+ {
+ bool sameRes = (h.MetadataResource.Offset == si.Resource.Offset);
+ if (sameRes)
+ needBootMetadata = false;
+ if (h.IsNewVersion())
+ {
+ if (si.RefCount == 1)
+ {
+ numNonDeletedImages++;
+ bool isBootIndex = (h.BootIndex == numNonDeletedImages);
+ if (sameRes && !isBootIndex)
+ return S_FALSE;
+ if (isBootIndex && !sameRes)
+ return S_FALSE;
+ }
+ }
+ }
+ }
+
+ if (needBootMetadata)
+ return S_FALSE;
+ return S_OK;
+}
+
+
+bool CDatabase::ItemHasStream(const CItem &item) const
+{
+ if (item.ImageIndex < 0)
+ return true;
+ const Byte *meta = Images[item.ImageIndex].Meta + item.Offset;
+ if (IsOldVersion)
+ {
+ // old wim use same field for file_id and dir_offset;
+ if (item.IsDir)
+ return false;
+ meta += (item.IsAltStream ? 0x8 : 0x10);
+ UInt32 id = GetUi32(meta);
+ return id != 0;
+ }
+ meta += (item.IsAltStream ? 0x10 : 0x40);
+ return !IsEmptySha(meta);
+}
+
+
+#define RINOZ(x) { int _tt_ = (x); if (_tt_ != 0) return _tt_; }
+
+static int CompareStreamsByPos(const CStreamInfo *p1, const CStreamInfo *p2, void * /* param */)
+{
+ RINOZ(MyCompare(p1->PartNumber, p2->PartNumber))
+ RINOZ(MyCompare(p1->Resource.Offset, p2->Resource.Offset))
+ return MyCompare(p1->Resource.PackSize, p2->Resource.PackSize);
+}
+
+static int CompareIDs(const unsigned *p1, const unsigned *p2, void *param)
+{
+ const CStreamInfo *streams = (const CStreamInfo *)param;
+ return MyCompare(streams[*p1].Id, streams[*p2].Id);
+}
+
+static int CompareHashRefs(const unsigned *p1, const unsigned *p2, void *param)
+{
+ const CStreamInfo *streams = (const CStreamInfo *)param;
+ return memcmp(streams[*p1].Hash, streams[*p2].Hash, kHashSize);
+}
+
+static int FindId(const CStreamInfo *streams, const CUIntVector &sorted, UInt32 id)
+{
+ unsigned left = 0, right = sorted.Size();
+ while (left != right)
+ {
+ const unsigned mid = (left + right) / 2;
+ const unsigned streamIndex = sorted[mid];
+ const UInt32 id2 = streams[streamIndex].Id;
+ if (id == id2)
+ return (int)streamIndex;
+ if (id < id2)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+}
+
+static int FindHash(const CStreamInfo *streams, const CUIntVector &sorted, const Byte *hash)
+{
+ unsigned left = 0, right = sorted.Size();
+ while (left != right)
+ {
+ const unsigned mid = (left + right) / 2;
+ const unsigned streamIndex = sorted[mid];
+ const Byte *hash2 = streams[streamIndex].Hash;
+ unsigned i;
+ for (i = 0; i < kHashSize; i++)
+ if (hash[i] != hash2[i])
+ break;
+ if (i == kHashSize)
+ return (int)streamIndex;
+ if (hash[i] < hash2[i])
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+}
+
+static int CompareItems(const unsigned *a1, const unsigned *a2, void *param)
+{
+ const CRecordVector<CItem> &items = ((CDatabase *)param)->Items;
+ const CItem &i1 = items[*a1];
+ const CItem &i2 = items[*a2];
+
+ if (i1.IsDir != i2.IsDir)
+ return i1.IsDir ? -1 : 1;
+ if (i1.IsAltStream != i2.IsAltStream)
+ return i1.IsAltStream ? 1 : -1;
+ RINOZ(MyCompare(i1.StreamIndex, i2.StreamIndex))
+ RINOZ(MyCompare(i1.ImageIndex, i2.ImageIndex))
+ return MyCompare(i1.Offset, i2.Offset);
+}
+
+
+HRESULT CDatabase::FillAndCheck(const CObjectVector<CVolume> &volumes)
+{
+ CUIntVector sortedByHash;
+ sortedByHash.Reserve(DataStreams.Size());
+ {
+ CByteBuffer sizesBuf;
+
+ for (unsigned iii = 0; iii < DataStreams.Size();)
+ {
+ {
+ const CResource &r = DataStreams[iii].Resource;
+ if (!r.IsSolid())
+ {
+ sortedByHash.AddInReserved(iii++);
+ continue;
+ }
+ }
+
+ UInt64 solidRunOffset = 0;
+ unsigned k;
+ unsigned numSolidsStart = Solids.Size();
+
+ for (k = iii; k < DataStreams.Size(); k++)
+ {
+ CStreamInfo &si = DataStreams[k];
+ CResource &r = si.Resource;
+
+ if (!r.IsSolid())
+ break;
+ if (!r.KeepSolid && k != iii)
+ break;
+
+ if (r.Flags != NResourceFlags::kSolid)
+ return S_FALSE;
+
+ if (!r.IsSolidBig())
+ continue;
+
+ if (!si.IsEmptyHash())
+ return S_FALSE;
+ if (si.RefCount != 1)
+ return S_FALSE;
+
+ r.SolidIndex = (int)Solids.Size();
+
+ CSolid &ss = Solids.AddNew();
+ ss.StreamIndex = k;
+ ss.SolidOffset = solidRunOffset;
+ {
+ const size_t kSolidHeaderSize = 8 + 4 + 4;
+ Byte header[kSolidHeaderSize];
+
+ if (si.PartNumber >= volumes.Size())
+ return S_FALSE;
+
+ const CVolume &vol = volumes[si.PartNumber];
+ IInStream *inStream = vol.Stream;
+ RINOK(InStream_SeekSet(inStream, r.Offset))
+ RINOK(ReadStream_FALSE(inStream, (Byte *)header, kSolidHeaderSize))
+
+ ss.UnpackSize = GetUi64(header);
+
+ if (ss.UnpackSize > ((UInt64)1 << 63))
+ return S_FALSE;
+
+ solidRunOffset += ss.UnpackSize;
+ if (solidRunOffset < ss.UnpackSize)
+ return S_FALSE;
+
+ const UInt32 solidChunkSize = GetUi32(header + 8);
+ const int log = GetLog(solidChunkSize);
+ if (log < 8 || log > 31)
+ return S_FALSE;
+ ss.ChunkSizeBits = (unsigned)log;
+ ss.Method = (Int32)GetUi32(header + 12);
+
+ UInt64 numChunks64 = (ss.UnpackSize + (((UInt32)1 << ss.ChunkSizeBits) - 1)) >> ss.ChunkSizeBits;
+ UInt64 sizesBufSize64 = 4 * numChunks64;
+ ss.HeadersSize = kSolidHeaderSize + sizesBufSize64;
+ size_t sizesBufSize = (size_t)sizesBufSize64;
+ if (sizesBufSize != sizesBufSize64)
+ return E_OUTOFMEMORY;
+ sizesBuf.AllocAtLeast(sizesBufSize);
+
+ RINOK(ReadStream_FALSE(inStream, sizesBuf, sizesBufSize))
+
+ size_t numChunks = (size_t)numChunks64;
+ ss.Chunks.Alloc(numChunks + 1);
+
+ UInt64 offset = 0;
+
+ size_t c;
+ for (c = 0; c < numChunks; c++)
+ {
+ ss.Chunks[c] = offset;
+ UInt32 packSize = GetUi32((const Byte *)sizesBuf + c * 4);
+ offset += packSize;
+ if (offset < packSize)
+ return S_FALSE;
+ }
+ ss.Chunks[c] = offset;
+
+ if (ss.Chunks[0] != 0)
+ return S_FALSE;
+ if (ss.HeadersSize + offset != r.PackSize)
+ return S_FALSE;
+ }
+ }
+
+ unsigned solidLim = k;
+
+ for (k = iii; k < solidLim; k++)
+ {
+ CStreamInfo &si = DataStreams[k];
+ CResource &r = si.Resource;
+
+ if (!r.IsSolidSmall())
+ continue;
+
+ if (si.IsEmptyHash())
+ return S_FALSE;
+
+ unsigned solidIndex;
+ {
+ UInt64 offset = r.Offset;
+ for (solidIndex = numSolidsStart;; solidIndex++)
+ {
+ if (solidIndex == Solids.Size())
+ return S_FALSE;
+ UInt64 unpackSize = Solids[solidIndex].UnpackSize;
+ if (offset < unpackSize)
+ break;
+ offset -= unpackSize;
+ }
+ }
+ CSolid &ss = Solids[solidIndex];
+ if (r.Offset < ss.SolidOffset)
+ return S_FALSE;
+ const UInt64 relat = r.Offset - ss.SolidOffset;
+ if (relat > ss.UnpackSize)
+ return S_FALSE;
+ if (r.PackSize > ss.UnpackSize - relat)
+ return S_FALSE;
+ r.SolidIndex = (int)solidIndex;
+ if (ss.FirstSmallStream < 0)
+ ss.FirstSmallStream = (int)k;
+
+ sortedByHash.AddInReserved(k);
+ // ss.NumRefs++;
+ }
+
+ iii = solidLim;
+ }
+ }
+
+ if (Solids.IsEmpty())
+ {
+ /* We want to check that streams layout is OK.
+ So we need resources sorted by offset.
+ Another code can work with non-sorted streams.
+ NOTE: all WIM programs probably create wim archives with
+ sorted data streams. So it doesn't call Sort() here. */
+
+ {
+ unsigned i;
+ for (i = 1; i < DataStreams.Size(); i++)
+ {
+ const CStreamInfo &s0 = DataStreams[i - 1];
+ const CStreamInfo &s1 = DataStreams[i];
+ if (s0.PartNumber < s1.PartNumber) continue;
+ if (s0.PartNumber > s1.PartNumber) break;
+ if (s0.Resource.Offset < s1.Resource.Offset) continue;
+ if (s0.Resource.Offset > s1.Resource.Offset) break;
+ if (s0.Resource.PackSize > s1.Resource.PackSize) break;
+ }
+
+ if (i < DataStreams.Size())
+ {
+ // return E_FAIL;
+ DataStreams.Sort(CompareStreamsByPos, NULL);
+ }
+ }
+
+ for (unsigned i = 1; i < DataStreams.Size(); i++)
+ {
+ const CStreamInfo &s0 = DataStreams[i - 1];
+ const CStreamInfo &s1 = DataStreams[i];
+ if (s0.PartNumber == s1.PartNumber)
+ if (s0.Resource.GetEndLimit() > s1.Resource.Offset)
+ return S_FALSE;
+ }
+ }
+
+ {
+ {
+ const CStreamInfo *streams = &DataStreams.Front();
+
+ if (IsOldVersion)
+ {
+ sortedByHash.Sort(CompareIDs, (void *)streams);
+
+ for (unsigned i = 1; i < sortedByHash.Size(); i++)
+ if (streams[sortedByHash[i - 1]].Id >=
+ streams[sortedByHash[i]].Id)
+ return S_FALSE;
+ }
+ else
+ {
+ sortedByHash.Sort(CompareHashRefs, (void *)streams);
+
+ if (!sortedByHash.IsEmpty())
+ {
+ if (IsEmptySha(streams[sortedByHash[0]].Hash))
+ HeadersError = true;
+
+ for (unsigned i = 1; i < sortedByHash.Size(); i++)
+ if (memcmp(
+ streams[sortedByHash[i - 1]].Hash,
+ streams[sortedByHash[i]].Hash,
+ kHashSize) >= 0)
+ return S_FALSE;
+ }
+ }
+ }
+
+ FOR_VECTOR (i, Items)
+ {
+ CItem &item = Items[i];
+ item.StreamIndex = -1;
+ const Byte *hash = Images[item.ImageIndex].Meta + item.Offset;
+ if (IsOldVersion)
+ {
+ if (!item.IsDir)
+ {
+ hash += (item.IsAltStream ? 0x8 : 0x10);
+ UInt32 id = GetUi32(hash);
+ if (id != 0)
+ item.StreamIndex = FindId(&DataStreams.Front(), sortedByHash, id);
+ }
+ }
+ /*
+ else if (item.IsDir)
+ {
+ // reparse points can have dirs some dir
+ }
+ */
+ else
+ {
+ hash += (item.IsAltStream ? 0x10 : 0x40);
+ if (!IsEmptySha(hash))
+ {
+ item.StreamIndex = FindHash(&DataStreams.Front(), sortedByHash, hash);
+ }
+ }
+ }
+ }
+ {
+ CUIntVector refCounts;
+ refCounts.ClearAndSetSize(DataStreams.Size());
+ unsigned i;
+
+ for (i = 0; i < DataStreams.Size(); i++)
+ {
+ UInt32 startVal = 0;
+ // const CStreamInfo &s = DataStreams[i];
+ /*
+ if (s.Resource.IsMetadata() && s.PartNumber == 1)
+ startVal = 1;
+ */
+ refCounts[i] = startVal;
+ }
+
+ for (i = 0; i < Items.Size(); i++)
+ {
+ int streamIndex = Items[i].StreamIndex;
+ if (streamIndex >= 0)
+ refCounts[streamIndex]++;
+ }
+
+ for (i = 0; i < DataStreams.Size(); i++)
+ {
+ const CStreamInfo &s = DataStreams[i];
+ if (s.RefCount != refCounts[i]
+ && !s.Resource.IsSolidBig())
+ {
+ /*
+ printf("\ni=%5d si.Ref=%2d realRefs=%2d size=%8d offset=%8x id=%4d ",
+ i, s.RefCount, refCounts[i], (unsigned)s.Resource.UnpackSize, (unsigned)s.Resource.Offset, s.Id);
+ */
+ RefCountError = true;
+ }
+
+ if (refCounts[i] == 0)
+ {
+ const CResource &r = DataStreams[i].Resource;
+ if (!r.IsSolidBig() || Solids[r.SolidIndex].FirstSmallStream < 0)
+ {
+ CItem item;
+ item.Offset = 0;
+ item.StreamIndex = (int)i;
+ item.ImageIndex = -1;
+ Items.Add(item);
+ ThereAreDeletedStreams = true;
+ }
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+HRESULT CDatabase::GenerateSortedItems(int imageIndex, bool showImageNumber)
+{
+ SortedItems.Clear();
+ VirtualRoots.Clear();
+ IndexOfUserImage = imageIndex;
+ NumExcludededItems = 0;
+ ExludedItem = -1;
+
+ if (Images.Size() != 1 && imageIndex < 0)
+ showImageNumber = true;
+
+ unsigned startItem = 0;
+ unsigned endItem = 0;
+
+ if (imageIndex < 0)
+ {
+ endItem = Items.Size();
+ if (Images.Size() == 1)
+ {
+ IndexOfUserImage = 0;
+ const CImage &image = Images[0];
+ if (!showImageNumber)
+ NumExcludededItems = image.NumEmptyRootItems;
+ }
+ }
+ else if ((unsigned)imageIndex < Images.Size())
+ {
+ const CImage &image = Images[imageIndex];
+ startItem = image.StartItem;
+ endItem = startItem + image.NumItems;
+ if (!showImageNumber)
+ NumExcludededItems = image.NumEmptyRootItems;
+ }
+
+ if (NumExcludededItems != 0)
+ {
+ ExludedItem = (int)startItem;
+ startItem += NumExcludededItems;
+ }
+
+ unsigned num = endItem - startItem;
+ SortedItems.ClearAndSetSize(num);
+ unsigned i;
+ for (i = 0; i < num; i++)
+ SortedItems[i] = startItem + i;
+
+ SortedItems.Sort(CompareItems, this);
+ for (i = 0; i < SortedItems.Size(); i++)
+ Items[SortedItems[i]].IndexInSorted = (int)i;
+
+ if (showImageNumber)
+ for (i = 0; i < Images.Size(); i++)
+ {
+ CImage &image = Images[i];
+ if (image.NumEmptyRootItems != 0)
+ continue;
+ image.VirtualRootIndex = (int)VirtualRoots.Size();
+ VirtualRoots.Add(i);
+ }
+
+ return S_OK;
+}
+
+
+static void IntVector_SetMinusOne_IfNeed(CIntVector &v, unsigned size)
+{
+ if (v.Size() == size)
+ return;
+ v.ClearAndSetSize(size);
+ int *vals = &v[0];
+ for (unsigned i = 0; i < size; i++)
+ vals[i] = -1;
+}
+
+
+HRESULT CDatabase::ExtractReparseStreams(const CObjectVector<CVolume> &volumes, IArchiveOpenCallback *openCallback)
+{
+ ItemToReparse.Clear();
+ ReparseItems.Clear();
+
+ // we don't know about Reparse field for OLD WIM format
+ if (IsOldVersion)
+ return S_OK;
+
+ CIntVector streamToReparse;
+ CUnpacker unpacker;
+ UInt64 totalPackedPrev = 0;
+
+ FOR_VECTOR(indexInSorted, SortedItems)
+ {
+ // we use sorted items for faster access
+ unsigned itemIndex = SortedItems[indexInSorted];
+ const CItem &item = Items[itemIndex];
+
+ if (!item.HasMetadata() || item.IsAltStream)
+ continue;
+
+ if (item.ImageIndex < 0)
+ continue;
+
+ const Byte *metadata = Images[item.ImageIndex].Meta + item.Offset;
+
+ const UInt32 attrib = Get32(metadata + 8);
+ if ((attrib & FILE_ATTRIBUTE_REPARSE_POINT) == 0)
+ continue;
+
+ if (item.StreamIndex < 0)
+ continue; // it's ERROR
+
+ const CStreamInfo &si = DataStreams[item.StreamIndex];
+ if (si.Resource.UnpackSize >= (1 << 16))
+ continue; // reparse data can not be larger than 64 KB
+
+ IntVector_SetMinusOne_IfNeed(streamToReparse, DataStreams.Size());
+ IntVector_SetMinusOne_IfNeed(ItemToReparse, Items.Size());
+
+ const unsigned offset = 0x58; // we don't know about Reparse field for OLD WIM format
+ UInt32 tag = Get32(metadata + offset);
+ int reparseIndex = streamToReparse[item.StreamIndex];
+ CByteBuffer buf;
+
+ if (openCallback)
+ {
+ if ((unpacker.TotalPacked - totalPackedPrev) >= ((UInt32)1 << 16))
+ {
+ UInt64 numFiles = Items.Size();
+ RINOK(openCallback->SetCompleted(&numFiles, &unpacker.TotalPacked))
+ totalPackedPrev = unpacker.TotalPacked;
+ }
+ }
+
+ if (reparseIndex >= 0)
+ {
+ const CByteBuffer &reparse = ReparseItems[reparseIndex];
+ if (tag == Get32(reparse))
+ {
+ ItemToReparse[itemIndex] = reparseIndex;
+ continue;
+ }
+ buf = reparse;
+ // we support that strange and unusual situation with different tags and same reparse data.
+ }
+ else
+ {
+ /*
+ if (si.PartNumber >= volumes.Size())
+ continue;
+ */
+ const CVolume &vol = volumes[si.PartNumber];
+ /*
+ if (!vol.Stream)
+ continue;
+ */
+
+ Byte digest[kHashSize];
+ HRESULT res = unpacker.UnpackData(vol.Stream, si.Resource, vol.Header, this, buf, digest);
+
+ if (res == S_FALSE)
+ continue;
+
+ RINOK(res)
+
+ if (memcmp(digest, si.Hash, kHashSize) != 0
+ // && !(h.IsOldVersion() && IsEmptySha(si.Hash))
+ )
+ {
+ // setErrorStatus;
+ continue;
+ }
+ }
+
+ CByteBuffer &reparse = ReparseItems.AddNew();
+ reparse.Alloc(8 + buf.Size());
+ Byte *dest = (Byte *)reparse;
+ SetUi32(dest, tag)
+ SetUi32(dest + 4, (UInt32)buf.Size())
+ if (buf.Size() != 0)
+ memcpy(dest + 8, buf, buf.Size());
+ ItemToReparse[itemIndex] = (int)ReparseItems.Size() - 1;
+ }
+
+ return S_OK;
+}
+
+
+
+static bool ParseNumber64(const AString &s, UInt64 &res)
+{
+ const char *end;
+ if (s.IsPrefixedBy("0x"))
+ {
+ if (s.Len() == 2)
+ return false;
+ res = ConvertHexStringToUInt64(s.Ptr(2), &end);
+ }
+ else
+ {
+ if (s.IsEmpty())
+ return false;
+ res = ConvertStringToUInt64(s, &end);
+ }
+ return *end == 0;
+}
+
+
+static bool ParseNumber32(const AString &s, UInt32 &res)
+{
+ UInt64 res64;
+ if (!ParseNumber64(s, res64) || res64 >= ((UInt64)1 << 32))
+ return false;
+ res = (UInt32)res64;
+ return true;
+}
+
+
+static bool ParseTime(const CXmlItem &item, FILETIME &ft, const char *tag)
+{
+ int index = item.FindSubTag(tag);
+ if (index >= 0)
+ {
+ const CXmlItem &timeItem = item.SubItems[index];
+ UInt32 low = 0, high = 0;
+ if (ParseNumber32(timeItem.GetSubStringForTag("LOWPART"), low) &&
+ ParseNumber32(timeItem.GetSubStringForTag("HIGHPART"), high))
+ {
+ ft.dwLowDateTime = low;
+ ft.dwHighDateTime = high;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void CImageInfo::Parse(const CXmlItem &item)
+{
+ CTimeDefined = ParseTime(item, CTime, "CREATIONTIME");
+ MTimeDefined = ParseTime(item, MTime, "LASTMODIFICATIONTIME");
+ NameDefined = true;
+ ConvertUTF8ToUnicode(item.GetSubStringForTag("NAME"), Name);
+
+ ParseNumber64(item.GetSubStringForTag("DIRCOUNT"), DirCount);
+ ParseNumber64(item.GetSubStringForTag("FILECOUNT"), FileCount);
+ IndexDefined = ParseNumber32(item.GetPropVal("INDEX"), Index);
+}
+
+void CWimXml::ToUnicode(UString &s)
+{
+ size_t size = Data.Size();
+ if (size < 2 || (size & 1) != 0 || size > (1 << 24))
+ return;
+ const Byte *p = Data;
+ if (Get16(p) != 0xFEFF)
+ return;
+ wchar_t *chars = s.GetBuf((unsigned)(size / 2));
+ for (size_t i = 2; i < size; i += 2)
+ {
+ wchar_t c = Get16(p + i);
+ if (c == 0)
+ break;
+ *chars++ = c;
+ }
+ *chars = 0;
+ s.ReleaseBuf_SetLen((unsigned)(chars - (const wchar_t *)s));
+}
+
+
+bool CWimXml::Parse()
+{
+ IsEncrypted = false;
+ AString utf;
+ {
+ UString s;
+ ToUnicode(s);
+ // if (!ConvertUnicodeToUTF8(s, utf)) return false;
+ ConvertUnicodeToUTF8(s, utf);
+ }
+
+ if (!Xml.Parse(utf))
+ return false;
+ if (Xml.Root.Name != "WIM")
+ return false;
+
+ FOR_VECTOR (i, Xml.Root.SubItems)
+ {
+ const CXmlItem &item = Xml.Root.SubItems[i];
+
+ if (item.IsTagged("IMAGE"))
+ {
+ CImageInfo imageInfo;
+ imageInfo.Parse(item);
+ if (!imageInfo.IndexDefined)
+ return false;
+
+ if (imageInfo.Index != (UInt32)Images.Size() + 1)
+ {
+ // old wim (1.09) uses zero based image index
+ if (imageInfo.Index != (UInt32)Images.Size())
+ return false;
+ }
+
+ imageInfo.ItemIndexInXml = (int)i;
+ Images.Add(imageInfo);
+ }
+
+ if (item.IsTagged("ESD"))
+ {
+ FOR_VECTOR (k, item.SubItems)
+ {
+ const CXmlItem &item2 = item.SubItems[k];
+ if (item2.IsTagged("ENCRYPTED"))
+ IsEncrypted = true;
+ }
+ }
+ }
+
+ return true;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Wim/WimIn.h b/CPP/7zip/Archive/Wim/WimIn.h
new file mode 100644
index 0000000..3de8456
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/WimIn.h
@@ -0,0 +1,659 @@
+// Archive/WimIn.h
+
+#ifndef ZIP7_INC_ARCHIVE_WIM_IN_H
+#define ZIP7_INC_ARCHIVE_WIM_IN_H
+
+#include "../../../../C/Alloc.h"
+
+#include "../../../Common/MyBuffer.h"
+#include "../../../Common/MyXml.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#include "../../Compress/CopyCoder.h"
+#include "../../Compress/LzmsDecoder.h"
+#include "../../Compress/LzxDecoder.h"
+
+#include "../IArchive.h"
+
+namespace NArchive {
+namespace NWim {
+
+/*
+WIM versions:
+hexVer : headerSize : ver
+ : 1.07.01 - 1.08.01 : Longhorn.4001-4015 - another header, no signature, CAB compression
+10900 : 60 : 1.09 : Longhorn.4029-4039 (2003)
+10A00 : 60 : 1.10 : Longhorn.4083 (2004) image starting from 1
+10B00 : ?? : 1.11 : ??
+10C00 : 74 : 1.12 : Longhorn.4093 - VistaBeta1.5112 (2005) - (Multi-Part, SHA1)
+10D00 : D0 : 1.13 : VistaBeta2 - Win10, (NumImages, BootIndex, IntegrityResource)
+00E00 : D0 : 0.14 : LZMS, solid, esd, dism
+*/
+
+const unsigned kDirRecordSizeOld = 62;
+const unsigned kDirRecordSize = 102;
+
+/*
+ There is error in WIM specification about dwReparseTag, dwReparseReserved and liHardLink fields.
+
+ Correct DIRENTRY structure:
+ {
+ hex offset
+ 0 UInt64 Len;
+ 8 UInt32 Attrib;
+ C UInt32 SecurityId;
+
+ 10 UInt64 SubdirOffset; // = 0 for files
+
+ 18 UInt64 unused1; // = 0?
+ 20 UInt64 unused2; // = 0?
+
+ 28 UInt64 CTime;
+ 30 UInt64 ATime;
+ 38 UInt64 MTime;
+
+ 40 Byte Sha1[20];
+
+ 54 UInt32 Unknown1; // is it 0 always?
+
+
+ union
+ {
+ 58 UInt64 NtNodeId;
+ {
+ 58 UInt32 ReparseTag;
+ 5C UInt32 ReparseFlags; // is it 0 always? Check with new imagex.
+ }
+ }
+
+ 60 UInt16 Streams;
+
+ 62 UInt16 ShortNameLen;
+ 64 UInt16 FileNameLen;
+
+ 66 UInt16 Name[];
+ UInt16 ShortName[];
+ }
+
+ // DIRENTRY for WIM_VERSION <= 1.10
+ DIRENTRY_OLD structure:
+ {
+ hex offset
+ 0 UInt64 Len;
+ 8 UInt32 Attrib;
+ C UInt32 SecurityId;
+
+ union
+ {
+ 10 UInt64 SubdirOffset; //
+
+ 10 UInt32 OldWimFileId; // used for files in old WIMs
+ 14 UInt32 OldWimFileId_Reserved; // = 0
+ }
+
+ 18 UInt64 CTime;
+ 20 UInt64 ATime;
+ 28 UInt64 MTime;
+
+ 30 UInt64 Unknown; // NtNodeId ?
+
+ 38 UInt16 Streams;
+ 3A UInt16 ShortNameLen;
+ 3C UInt16 FileNameLen;
+ 3E UInt16 FileName[];
+ UInt16 ShortName[];
+ }
+
+ ALT_STREAM structure:
+ {
+ hex offset
+ 0 UInt64 Len;
+ 8 UInt64 Unused;
+ 10 Byte Sha1[20];
+ 24 UInt16 FileNameLen;
+ 26 UInt16 FileName[];
+ }
+
+ ALT_STREAM_OLD structure:
+ {
+ hex offset
+ 0 UInt64 Len;
+ 8 UInt64 StreamId; // 32-bit value
+ 10 UInt16 FileNameLen;
+ 12 UInt16 FileName[];
+ }
+
+ If item is file (not Directory) and there are alternative streams,
+ there is additional ALT_STREAM item of main "unnamed" stream in Streams array.
+
+*/
+
+
+namespace NResourceFlags
+{
+ // const Byte kFree = 1 << 0;
+ const Byte kMetadata = 1 << 1;
+ const Byte kCompressed = 1 << 2;
+ // const Byte kSpanned = 1 << 3;
+ const Byte kSolid = 1 << 4;
+}
+
+const UInt64 k_SolidBig_Resource_Marker = (UInt64)1 << 32;
+
+struct CResource
+{
+ UInt64 PackSize;
+ UInt64 Offset;
+ UInt64 UnpackSize;
+ Byte Flags;
+ bool KeepSolid;
+ int SolidIndex;
+
+ void Clear()
+ {
+ PackSize = 0;
+ Offset = 0;
+ UnpackSize = 0;
+ Flags = 0;
+ KeepSolid = false;
+ SolidIndex = -1;
+ }
+
+ UInt64 GetEndLimit() const { return Offset + PackSize; }
+ void Parse(const Byte *p);
+ void ParseAndUpdatePhySize(const Byte *p, UInt64 &phySize)
+ {
+ Parse(p);
+ UInt64 v = GetEndLimit();
+ if (phySize < v)
+ phySize = v;
+ }
+
+ void WriteTo(Byte *p) const;
+
+ bool IsMetadata() const { return (Flags & NResourceFlags::kMetadata) != 0; }
+ bool IsCompressed() const { return (Flags & NResourceFlags::kCompressed) != 0; }
+ bool IsSolid() const { return (Flags & NResourceFlags::kSolid) != 0; }
+ bool IsSolidBig() const { return IsSolid() && UnpackSize == k_SolidBig_Resource_Marker; }
+ bool IsSolidSmall() const { return IsSolid() && UnpackSize == 0; }
+
+ bool IsEmpty() const { return (UnpackSize == 0); }
+};
+
+
+struct CSolid
+{
+ unsigned StreamIndex;
+ // unsigned NumRefs;
+ int FirstSmallStream;
+
+ UInt64 SolidOffset;
+
+ UInt64 UnpackSize;
+ int Method;
+ unsigned ChunkSizeBits;
+
+ UInt64 HeadersSize;
+ // size_t NumChunks;
+ CObjArray<UInt64> Chunks; // [NumChunks + 1] (start offset)
+
+ UInt64 GetChunkPackSize(size_t chunkIndex) const { return Chunks[chunkIndex + 1] - Chunks[chunkIndex]; }
+
+ CSolid():
+ FirstSmallStream(-1),
+ // NumRefs(0),
+ Method(-1)
+ {}
+};
+
+
+namespace NHeaderFlags
+{
+ const UInt32 kCompression = 1 << 1;
+ const UInt32 kReadOnly = 1 << 2;
+ const UInt32 kSpanned = 1 << 3;
+ const UInt32 kResourceOnly = 1 << 4;
+ const UInt32 kMetadataOnly = 1 << 5;
+ const UInt32 kWriteInProgress = 1 << 6;
+ const UInt32 kReparsePointFixup = 1 << 7;
+
+ const UInt32 kXPRESS = (UInt32)1 << 17;
+ const UInt32 kLZX = (UInt32)1 << 18;
+ const UInt32 kLZMS = (UInt32)1 << 19;
+ const UInt32 kXPRESS2 = (UInt32)1 << 21; // XPRESS with nonstandard chunk size ?
+
+ const UInt32 kMethodMask = 0xFFFE0000;
+}
+
+
+namespace NMethod
+{
+ const UInt32 kXPRESS = 1;
+ const UInt32 kLZX = 2;
+ const UInt32 kLZMS = 3;
+}
+
+
+const UInt32 k_Version_NonSolid = 0x10D00;
+const UInt32 k_Version_Solid = 0xE00;
+
+const unsigned kHeaderSizeMax = 0xD0;
+const unsigned kSignatureSize = 8;
+extern const Byte kSignature[kSignatureSize];
+
+const unsigned kChunkSizeBits = 15;
+const UInt32 kChunkSize = (UInt32)1 << kChunkSizeBits;
+
+
+struct CHeader
+{
+ UInt32 Version;
+ UInt32 Flags;
+ UInt32 ChunkSize;
+ unsigned ChunkSizeBits;
+ Byte Guid[16];
+ UInt16 PartNumber;
+ UInt16 NumParts;
+ UInt32 NumImages;
+ UInt32 BootIndex;
+
+ bool _isOldVersion; // 1.10-
+ bool _isNewVersion; // 1.13+ or 0.14
+
+ CResource OffsetResource;
+ CResource XmlResource;
+ CResource MetadataResource;
+ CResource IntegrityResource;
+
+ void SetDefaultFields(bool useLZX);
+
+ void WriteTo(Byte *p) const;
+ HRESULT Parse(const Byte *p, UInt64 &phySize);
+
+ bool IsCompressed() const { return (Flags & NHeaderFlags::kCompression) != 0; }
+
+ bool IsSupported() const
+ {
+ return (!IsCompressed()
+ || (Flags & NHeaderFlags::kLZX) != 0
+ || (Flags & NHeaderFlags::kXPRESS) != 0
+ || (Flags & NHeaderFlags::kLZMS) != 0
+ || (Flags & NHeaderFlags::kXPRESS2) != 0);
+ }
+
+ unsigned GetMethod() const
+ {
+ if (!IsCompressed())
+ return 0;
+ UInt32 mask = (Flags & NHeaderFlags::kMethodMask);
+ if (mask == 0) return 0;
+ if (mask == NHeaderFlags::kXPRESS) return NMethod::kXPRESS;
+ if (mask == NHeaderFlags::kLZX) return NMethod::kLZX;
+ if (mask == NHeaderFlags::kLZMS) return NMethod::kLZMS;
+ if (mask == NHeaderFlags::kXPRESS2) return NMethod::kXPRESS;
+ return mask;
+ }
+
+ bool IsOldVersion() const { return _isOldVersion; }
+ bool IsNewVersion() const { return _isNewVersion; }
+ bool IsSolidVersion() const { return (Version == k_Version_Solid); }
+
+ bool AreFromOnArchive(const CHeader &h)
+ {
+ return (memcmp(Guid, h.Guid, sizeof(Guid)) == 0) && (h.NumParts == NumParts);
+ }
+};
+
+
+const unsigned kHashSize = 20;
+
+inline bool IsEmptySha(const Byte *data)
+{
+ for (unsigned i = 0; i < kHashSize; i++)
+ if (data[i] != 0)
+ return false;
+ return true;
+}
+
+const unsigned kStreamInfoSize = 24 + 2 + 4 + kHashSize;
+
+struct CStreamInfo
+{
+ CResource Resource;
+ UInt16 PartNumber; // for NEW WIM format, we set it to 1 for OLD WIM format
+ UInt32 RefCount;
+ UInt32 Id; // for OLD WIM format
+ Byte Hash[kHashSize];
+
+ bool IsEmptyHash() const { return IsEmptySha(Hash); }
+
+ void WriteTo(Byte *p) const;
+};
+
+
+struct CItem
+{
+ size_t Offset;
+ int IndexInSorted;
+ int StreamIndex;
+ int Parent;
+ int ImageIndex; // -1 means that file is unreferenced in Images (deleted item?)
+ bool IsDir;
+ bool IsAltStream;
+
+ bool HasMetadata() const { return ImageIndex >= 0; }
+
+ CItem():
+ IndexInSorted(-1),
+ StreamIndex(-1),
+ Parent(-1),
+ IsDir(false),
+ IsAltStream(false)
+ {}
+};
+
+struct CImage
+{
+ CByteBuffer Meta;
+ CRecordVector<UInt32> SecurOffsets;
+ unsigned StartItem;
+ unsigned NumItems;
+ unsigned NumEmptyRootItems;
+ int VirtualRootIndex; // index in CDatabase::VirtualRoots[]
+ UString RootName;
+ CByteBuffer RootNameBuf;
+
+ CImage(): VirtualRootIndex(-1) {}
+};
+
+
+struct CImageInfo
+{
+ bool CTimeDefined;
+ bool MTimeDefined;
+ bool NameDefined;
+ bool IndexDefined;
+
+ FILETIME CTime;
+ FILETIME MTime;
+ UString Name;
+
+ UInt64 DirCount;
+ UInt64 FileCount;
+ UInt32 Index;
+
+ int ItemIndexInXml;
+
+ UInt64 GetTotalFilesAndDirs() const { return DirCount + FileCount; }
+
+ CImageInfo(): CTimeDefined(false), MTimeDefined(false), NameDefined(false),
+ IndexDefined(false), ItemIndexInXml(-1) {}
+ void Parse(const CXmlItem &item);
+};
+
+
+struct CWimXml
+{
+ CByteBuffer Data;
+ CXml Xml;
+
+ UInt16 VolIndex;
+ CObjectVector<CImageInfo> Images;
+
+ UString FileName;
+ bool IsEncrypted;
+
+ UInt64 GetTotalFilesAndDirs() const
+ {
+ UInt64 sum = 0;
+ FOR_VECTOR (i, Images)
+ sum += Images[i].GetTotalFilesAndDirs();
+ return sum;
+ }
+
+ void ToUnicode(UString &s);
+ bool Parse();
+
+ CWimXml(): IsEncrypted(false) {}
+};
+
+
+struct CVolume
+{
+ CHeader Header;
+ CMyComPtr<IInStream> Stream;
+};
+
+
+class CDatabase
+{
+ Byte *DirData;
+ size_t DirSize;
+ size_t DirProcessed;
+ size_t DirStartOffset;
+ IArchiveOpenCallback *OpenCallback;
+
+ HRESULT ParseDirItem(size_t pos, int parent);
+ HRESULT ParseImageDirs(CByteBuffer &buf, int parent);
+
+public:
+ CRecordVector<CStreamInfo> DataStreams;
+ CRecordVector<CStreamInfo> MetaStreams;
+
+ CObjectVector<CSolid> Solids;
+
+ CRecordVector<CItem> Items;
+ CObjectVector<CByteBuffer> ReparseItems;
+ CIntVector ItemToReparse; // from index_in_Items to index_in_ReparseItems
+ // -1 means no reparse;
+
+ CObjectVector<CImage> Images;
+
+ bool IsOldVersion9;
+ bool IsOldVersion;
+ bool ThereAreDeletedStreams;
+ bool ThereAreAltStreams;
+ bool RefCountError;
+ bool HeadersError;
+
+ unsigned GetStartImageIndex() const { return IsOldVersion9 ? 0 : 1; }
+ unsigned GetDirAlignMask() const { return IsOldVersion9 ? 3 : 7; }
+
+ // User Items can contain all images or just one image from all.
+ CUIntVector SortedItems;
+ int IndexOfUserImage; // -1 : if more than one images was filled to Sorted Items
+
+ unsigned NumExcludededItems;
+ int ExludedItem; // -1 : if there are no exclude items
+ CUIntVector VirtualRoots; // we use them for old 1.10 WIM archives
+
+ bool ThereIsError() const { return RefCountError || HeadersError; }
+
+ unsigned GetNumUserItemsInImage(unsigned imageIndex) const
+ {
+ if (IndexOfUserImage >= 0 && imageIndex != (unsigned)IndexOfUserImage)
+ return 0;
+ if (imageIndex >= Images.Size())
+ return 0;
+ return Images[imageIndex].NumItems - NumExcludededItems;
+ }
+
+ bool ItemHasStream(const CItem &item) const;
+
+ UInt64 Get_UnpackSize_of_Resource(const CResource &r) const
+ {
+ if (!r.IsSolid())
+ return r.UnpackSize;
+ if (r.IsSolidSmall())
+ return r.PackSize;
+ if (r.IsSolidBig() && r.SolidIndex >= 0)
+ return Solids[(unsigned)r.SolidIndex].UnpackSize;
+ return 0;
+ }
+
+ UInt64 Get_PackSize_of_Resource(unsigned streamIndex) const
+ {
+ const CResource &r = DataStreams[streamIndex].Resource;
+ if (!r.IsSolidSmall())
+ return r.PackSize;
+ if (r.SolidIndex >= 0)
+ {
+ const CSolid &ss = Solids[(unsigned)r.SolidIndex];
+ if (ss.FirstSmallStream == (int)streamIndex)
+ return DataStreams[ss.StreamIndex].Resource.PackSize;
+ }
+ return 0;
+ }
+
+ UInt64 GetUnpackSize() const
+ {
+ UInt64 res = 0;
+ FOR_VECTOR (i, DataStreams)
+ res += DataStreams[i].Resource.UnpackSize;
+ return res;
+ }
+
+ UInt64 GetPackSize() const
+ {
+ UInt64 res = 0;
+ FOR_VECTOR (i, DataStreams)
+ res += DataStreams[i].Resource.PackSize;
+ return res;
+ }
+
+ void Clear()
+ {
+ DataStreams.Clear();
+ MetaStreams.Clear();
+ Solids.Clear();
+
+ Items.Clear();
+ ReparseItems.Clear();
+ ItemToReparse.Clear();
+
+ SortedItems.Clear();
+
+ Images.Clear();
+ VirtualRoots.Clear();
+
+ IsOldVersion = false;
+ ThereAreDeletedStreams = false;
+ ThereAreAltStreams = false;
+ RefCountError = false;
+ HeadersError = false;
+ }
+
+ CDatabase():
+ RefCountError(false),
+ HeadersError(false)
+ {}
+
+ void GetShortName(unsigned index, NWindows::NCOM::CPropVariant &res) const;
+ void GetItemName(unsigned index1, NWindows::NCOM::CPropVariant &res) const;
+ void GetItemPath(unsigned index, bool showImageNumber, NWindows::NCOM::CPropVariant &res) const;
+
+ HRESULT OpenXml(IInStream *inStream, const CHeader &h, CByteBuffer &xml);
+ HRESULT Open(IInStream *inStream, const CHeader &h, unsigned numItemsReserve, IArchiveOpenCallback *openCallback);
+ HRESULT FillAndCheck(const CObjectVector<CVolume> &volumes);
+
+ /*
+ imageIndex showImageNumber NumImages
+ * true * Show Image_Number
+ -1 * >1 Show Image_Number
+ -1 false 1 Don't show Image_Number
+ N false * Don't show Image_Number
+ */
+ HRESULT GenerateSortedItems(int imageIndex, bool showImageNumber);
+
+ HRESULT ExtractReparseStreams(const CObjectVector<CVolume> &volumes, IArchiveOpenCallback *openCallback);
+};
+
+HRESULT ReadHeader(IInStream *inStream, CHeader &header, UInt64 &phySize);
+
+
+struct CMidBuf
+{
+ Byte *Data;
+ size_t _size;
+
+ CMidBuf(): Data(NULL), _size(0) {}
+
+ void EnsureCapacity(size_t size)
+ {
+ if (size > _size)
+ {
+ ::MidFree(Data);
+ _size = 0;
+ Data = (Byte *)::MidAlloc(size);
+ if (Data)
+ _size = size;
+ }
+ }
+
+ ~CMidBuf() { ::MidFree(Data); }
+};
+
+
+class CUnpacker
+{
+ NCompress::CCopyCoder *copyCoderSpec;
+ CMyComPtr<ICompressCoder> copyCoder;
+
+ NCompress::NLzx::CDecoder *lzxDecoderSpec;
+ CMyComPtr<IUnknown> lzxDecoder;
+
+ NCompress::NLzms::CDecoder *lzmsDecoder;
+
+ CByteBuffer sizesBuf;
+
+ CMidBuf packBuf;
+ CMidBuf unpackBuf;
+
+ // solid resource
+ int _solidIndex;
+ size_t _unpackedChunkIndex;
+
+ HRESULT UnpackChunk(
+ ISequentialInStream *inStream,
+ unsigned method, unsigned chunkSizeBits,
+ size_t inSize, size_t outSize,
+ ISequentialOutStream *outStream);
+
+ HRESULT Unpack2(
+ IInStream *inStream,
+ const CResource &res,
+ const CHeader &header,
+ const CDatabase *db,
+ ISequentialOutStream *outStream,
+ ICompressProgressInfo *progress);
+
+public:
+ UInt64 TotalPacked;
+
+ CUnpacker():
+ lzmsDecoder(NULL),
+ _solidIndex(-1),
+ _unpackedChunkIndex(0),
+ TotalPacked(0)
+ {}
+ ~CUnpacker();
+
+ HRESULT Unpack(
+ IInStream *inStream,
+ const CResource &res,
+ const CHeader &header,
+ const CDatabase *db,
+ ISequentialOutStream *outStream,
+ ICompressProgressInfo *progress,
+ Byte *digest);
+
+ HRESULT UnpackData(IInStream *inStream,
+ const CResource &resource, const CHeader &header,
+ const CDatabase *db,
+ CByteBuffer &buf, Byte *digest);
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Wim/WimRegister.cpp b/CPP/7zip/Archive/Wim/WimRegister.cpp
new file mode 100644
index 0000000..e143f91
--- /dev/null
+++ b/CPP/7zip/Archive/Wim/WimRegister.cpp
@@ -0,0 +1,29 @@
+// WimRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "WimHandler.h"
+
+namespace NArchive {
+namespace NWim {
+
+REGISTER_ARC_IO(
+ "wim", "wim swm esd ppkg", NULL, 0xE6
+ , kSignature, 0
+ , NArcInfoFlags::kAltStreams
+ | NArcInfoFlags::kNtSecure
+ | NArcInfoFlags::kSymLinks
+ | NArcInfoFlags::kHardLinks
+ | NArcInfoFlags::kCTime
+ // | NArcInfoFlags::kCTime_Default
+ | NArcInfoFlags::kATime
+ // | NArcInfoFlags::kATime_Default
+ | NArcInfoFlags::kMTime
+ | NArcInfoFlags::kMTime_Default
+ , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows)
+ | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kWindows)
+ , NULL)
+
+}}
diff --git a/CPP/7zip/Archive/XarHandler.cpp b/CPP/7zip/Archive/XarHandler.cpp
new file mode 100644
index 0000000..c03128f
--- /dev/null
+++ b/CPP/7zip/Archive/XarHandler.cpp
@@ -0,0 +1,730 @@
+// XarHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/MyLinux.h"
+#include "../../Common/MyXml.h"
+#include "../../Common/StringToInt.h"
+#include "../../Common/UTFConvert.h"
+
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/TimeUtils.h"
+
+#include "../Common/LimitedStreams.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamObjects.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/BZip2Decoder.h"
+#include "../Compress/CopyCoder.h"
+#include "../Compress/ZlibDecoder.h"
+
+#include "Common/OutStreamWithSha1.h"
+
+using namespace NWindows;
+
+#define XAR_SHOW_RAW
+
+#define Get16(p) GetBe16(p)
+#define Get32(p) GetBe32(p)
+#define Get64(p) GetBe64(p)
+
+namespace NArchive {
+namespace NXar {
+
+static const size_t kXmlSizeMax = ((size_t )1 << 30) - (1 << 14);
+static const size_t kXmlPackSizeMax = kXmlSizeMax;
+
+/*
+#define XAR_CKSUM_NONE 0
+#define XAR_CKSUM_SHA1 1
+#define XAR_CKSUM_MD5 2
+
+static const char * const k_ChecksumAlgos[] =
+{
+ "None"
+ , "SHA-1"
+ , "MD5"
+};
+*/
+
+#define METHOD_NAME_ZLIB "zlib"
+
+
+struct CFile
+{
+ AString Name;
+ AString Method;
+ UInt64 Size;
+ UInt64 PackSize;
+ UInt64 Offset;
+
+ UInt64 CTime;
+ UInt64 MTime;
+ UInt64 ATime;
+ UInt32 Mode;
+
+ AString User;
+ AString Group;
+
+ bool IsDir;
+ bool HasData;
+ bool ModeDefined;
+ bool Sha1IsDefined;
+ // bool packSha1IsDefined;
+
+ Byte Sha1[SHA1_DIGEST_SIZE];
+ // Byte packSha1[SHA1_DIGEST_SIZE];
+
+ int Parent;
+
+ CFile():
+ Size(0), PackSize(0), Offset(0),
+ CTime(0), MTime(0), ATime(0), Mode(0),
+ IsDir(false), HasData(false), ModeDefined(false), Sha1IsDefined(false),
+ /* packSha1IsDefined(false), */
+ Parent(-1)
+ {}
+
+ bool IsCopyMethod() const
+ {
+ return Method.IsEmpty() || Method == "octet-stream";
+ }
+
+ void UpdateTotalPackSize(UInt64 &totalSize) const
+ {
+ UInt64 t = Offset + PackSize;
+ if (totalSize < t)
+ totalSize = t;
+ }
+};
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IInArchiveGetStream
+)
+ UInt64 _dataStartPos;
+ CMyComPtr<IInStream> _inStream;
+ CByteArr _xml;
+ size_t _xmlLen;
+ CObjectVector<CFile> _files;
+ // UInt32 _checkSumAlgo;
+ UInt64 _phySize;
+ Int32 _mainSubfile;
+ bool _is_pkg;
+
+ HRESULT Open2(IInStream *stream);
+ HRESULT Extract(IInStream *stream);
+};
+
+static const Byte kArcProps[] =
+{
+ kpidSubType,
+ kpidHeadersSize
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidCTime,
+ kpidATime,
+ kpidPosixAttrib,
+ kpidUser,
+ kpidGroup,
+ kpidMethod
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+#define PARSE_NUM(_num_, _dest_) \
+ { const char *end; _dest_ = ConvertStringToUInt32(p, &end); \
+ if ((unsigned)(end - p) != _num_) return 0; \
+ p += _num_ + 1; }
+
+static bool ParseUInt64(const CXmlItem &item, const char *name, UInt64 &res)
+{
+ const AString s (item.GetSubStringForTag(name));
+ if (s.IsEmpty())
+ return false;
+ const char *end;
+ res = ConvertStringToUInt64(s, &end);
+ return *end == 0;
+}
+
+static UInt64 ParseTime(const CXmlItem &item, const char *name)
+{
+ const AString s (item.GetSubStringForTag(name));
+ if (s.Len() < 20)
+ return 0;
+ const char *p = s;
+ if (p[ 4] != '-' || p[ 7] != '-' || p[10] != 'T' ||
+ p[13] != ':' || p[16] != ':' || p[19] != 'Z')
+ return 0;
+ UInt32 year, month, day, hour, min, sec;
+ PARSE_NUM(4, year)
+ PARSE_NUM(2, month)
+ PARSE_NUM(2, day)
+ PARSE_NUM(2, hour)
+ PARSE_NUM(2, min)
+ PARSE_NUM(2, sec)
+
+ UInt64 numSecs;
+ if (!NTime::GetSecondsSince1601(year, month, day, hour, min, sec, numSecs))
+ return 0;
+ return numSecs * 10000000;
+}
+
+static int HexToByte(char c)
+{
+ if (c >= '0' && c <= '9') return c - '0';
+ if (c >= 'A' && c <= 'F') return c - 'A' + 10;
+ if (c >= 'a' && c <= 'f') return c - 'a' + 10;
+ return -1;
+}
+
+static bool ParseSha1(const CXmlItem &item, const char *name, Byte *digest)
+{
+ const int index = item.FindSubTag(name);
+ if (index < 0)
+ return false;
+ const CXmlItem &checkItem = item.SubItems[index];
+ const AString style (checkItem.GetPropVal("style"));
+ if (style == "SHA1")
+ {
+ const AString s (checkItem.GetSubString());
+ if (s.Len() != SHA1_DIGEST_SIZE * 2)
+ return false;
+ for (unsigned i = 0; i < s.Len(); i += 2)
+ {
+ const int b0 = HexToByte(s[i]);
+ const int b1 = HexToByte(s[i + 1]);
+ if (b0 < 0 || b1 < 0)
+ return false;
+ digest[i / 2] = (Byte)((b0 << 4) | b1);
+ }
+ return true;
+ }
+ return false;
+}
+
+static bool AddItem(const CXmlItem &item, CObjectVector<CFile> &files, int parent)
+{
+ if (!item.IsTag)
+ return true;
+ if (item.Name == "file")
+ {
+ CFile file;
+ file.Parent = parent;
+ parent = (int)files.Size();
+ file.Name = item.GetSubStringForTag("name");
+ const AString type (item.GetSubStringForTag("type"));
+ if (type == "directory")
+ file.IsDir = true;
+ else if (type == "file")
+ file.IsDir = false;
+ else
+ return false;
+
+ int dataIndex = item.FindSubTag("data");
+ if (dataIndex >= 0 && !file.IsDir)
+ {
+ file.HasData = true;
+ const CXmlItem &dataItem = item.SubItems[dataIndex];
+ if (!ParseUInt64(dataItem, "size", file.Size))
+ return false;
+ if (!ParseUInt64(dataItem, "length", file.PackSize))
+ return false;
+ if (!ParseUInt64(dataItem, "offset", file.Offset))
+ return false;
+ file.Sha1IsDefined = ParseSha1(dataItem, "extracted-checksum", file.Sha1);
+ // file.packSha1IsDefined = ParseSha1(dataItem, "archived-checksum", file.packSha1);
+ int encodingIndex = dataItem.FindSubTag("encoding");
+ if (encodingIndex >= 0)
+ {
+ const CXmlItem &encodingItem = dataItem.SubItems[encodingIndex];
+ if (encodingItem.IsTag)
+ {
+ AString s (encodingItem.GetPropVal("style"));
+ if (!s.IsEmpty())
+ {
+ const AString appl ("application/");
+ if (s.IsPrefixedBy(appl))
+ {
+ s.DeleteFrontal(appl.Len());
+ const AString xx ("x-");
+ if (s.IsPrefixedBy(xx))
+ {
+ s.DeleteFrontal(xx.Len());
+ if (s == "gzip")
+ s = METHOD_NAME_ZLIB;
+ }
+ }
+ file.Method = s;
+ }
+ }
+ }
+ }
+
+ file.CTime = ParseTime(item, "ctime");
+ file.MTime = ParseTime(item, "mtime");
+ file.ATime = ParseTime(item, "atime");
+
+ {
+ const AString s (item.GetSubStringForTag("mode"));
+ if (s[0] == '0')
+ {
+ const char *end;
+ file.Mode = ConvertOctStringToUInt32(s, &end);
+ file.ModeDefined = (*end == 0);
+ }
+ }
+
+ file.User = item.GetSubStringForTag("user");
+ file.Group = item.GetSubStringForTag("group");
+
+ files.Add(file);
+ }
+ FOR_VECTOR (i, item.SubItems)
+ if (!AddItem(item.SubItems[i], files, parent))
+ return false;
+ return true;
+}
+
+HRESULT CHandler::Open2(IInStream *stream)
+{
+ const UInt32 kHeaderSize = 0x1C;
+ Byte buf[kHeaderSize];
+ RINOK(ReadStream_FALSE(stream, buf, kHeaderSize))
+ UInt32 size = Get16(buf + 4);
+ // UInt32 ver = Get16(buf + 6); // == 1
+ if (Get32(buf) != 0x78617221 || size != kHeaderSize)
+ return S_FALSE;
+
+ UInt64 packSize = Get64(buf + 8);
+ UInt64 unpackSize = Get64(buf + 0x10);
+
+ // _checkSumAlgo = Get32(buf + 0x18);
+
+ if (packSize >= kXmlPackSizeMax ||
+ unpackSize >= kXmlSizeMax)
+ return S_FALSE;
+
+ _dataStartPos = kHeaderSize + packSize;
+ _phySize = _dataStartPos;
+
+ _xml.Alloc((size_t)unpackSize + 1);
+ _xmlLen = (size_t)unpackSize;
+
+ NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
+ CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;
+
+ CLimitedSequentialInStream *inStreamLimSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStreamLim(inStreamLimSpec);
+ inStreamLimSpec->SetStream(stream);
+ inStreamLimSpec->Init(packSize);
+
+ CBufPtrSeqOutStream *outStreamLimSpec = new CBufPtrSeqOutStream;
+ CMyComPtr<ISequentialOutStream> outStreamLim(outStreamLimSpec);
+ outStreamLimSpec->Init(_xml, (size_t)unpackSize);
+
+ RINOK(zlibCoder->Code(inStreamLim, outStreamLim, NULL, NULL, NULL))
+
+ if (outStreamLimSpec->GetPos() != (size_t)unpackSize)
+ return S_FALSE;
+
+ _xml[(size_t)unpackSize] = 0;
+ if (strlen((const char *)(const Byte *)_xml) != unpackSize) return S_FALSE;
+
+ CXml xml;
+ if (!xml.Parse((const char *)(const Byte *)_xml))
+ return S_FALSE;
+
+ if (!xml.Root.IsTagged("xar") || xml.Root.SubItems.Size() != 1)
+ return S_FALSE;
+ const CXmlItem &toc = xml.Root.SubItems[0];
+ if (!toc.IsTagged("toc"))
+ return S_FALSE;
+ if (!AddItem(toc, _files, -1))
+ return S_FALSE;
+
+ UInt64 totalPackSize = 0;
+ unsigned numMainFiles = 0;
+
+ FOR_VECTOR (i, _files)
+ {
+ const CFile &file = _files[i];
+ file.UpdateTotalPackSize(totalPackSize);
+ if (file.Name == "Payload" || file.Name == "Content")
+ {
+ _mainSubfile = (Int32)(int)i;
+ numMainFiles++;
+ }
+ else if (file.Name == "PackageInfo")
+ _is_pkg = true;
+ }
+
+ if (numMainFiles > 1)
+ _mainSubfile = -1;
+
+ _phySize = _dataStartPos + totalPackSize;
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openArchiveCallback */))
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ if (Open2(stream) != S_OK)
+ return S_FALSE;
+ _inStream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _phySize = 0;
+ _inStream.Release();
+ _files.Clear();
+ _xmlLen = 0;
+ _xml.Free();
+ _mainSubfile = -1;
+ _is_pkg = false;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _files.Size()
+ #ifdef XAR_SHOW_RAW
+ + 1
+ #endif
+ ;
+ return S_OK;
+}
+
+static void TimeToProp(UInt64 t, NCOM::CPropVariant &prop)
+{
+ if (t != 0)
+ {
+ FILETIME ft;
+ ft.dwLowDateTime = (UInt32)(t);
+ ft.dwHighDateTime = (UInt32)(t >> 32);
+ prop = ft;
+ }
+}
+
+static void Utf8StringToProp(const AString &s, NCOM::CPropVariant &prop)
+{
+ if (!s.IsEmpty())
+ {
+ UString us;
+ ConvertUTF8ToUnicode(s, us);
+ prop = us;
+ }
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidHeadersSize: prop = _dataStartPos; break;
+ case kpidPhySize: prop = _phySize; break;
+ case kpidMainSubfile: if (_mainSubfile >= 0) prop = (UInt32)_mainSubfile; break;
+ case kpidSubType: if (_is_pkg) prop = "pkg"; break;
+ case kpidExtension: prop = _is_pkg ? "pkg" : "xar"; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ #ifdef XAR_SHOW_RAW
+ if (index == _files.Size())
+ {
+ switch (propID)
+ {
+ case kpidPath: prop = "[TOC].xml"; break;
+ case kpidSize:
+ case kpidPackSize: prop = (UInt64)_xmlLen; break;
+ }
+ }
+ else
+ #endif
+ {
+ const CFile &item = _files[index];
+ switch (propID)
+ {
+ case kpidMethod: Utf8StringToProp(item.Method, prop); break;
+
+ case kpidPath:
+ {
+ AString path;
+ unsigned cur = index;
+ for (;;)
+ {
+ const CFile &item2 = _files[cur];
+ if (!path.IsEmpty())
+ path.InsertAtFront(CHAR_PATH_SEPARATOR);
+ if (item2.Name.IsEmpty())
+ path.Insert(0, "unknown");
+ else
+ path.Insert(0, item2.Name);
+ cur = (unsigned)item2.Parent;
+ if (item2.Parent < 0)
+ break;
+ }
+
+ Utf8StringToProp(path, prop);
+ break;
+ }
+
+ case kpidIsDir: prop = item.IsDir; break;
+ case kpidSize: if (!item.IsDir) prop = item.Size; break;
+ case kpidPackSize: if (!item.IsDir) prop = item.PackSize; break;
+
+ case kpidMTime: TimeToProp(item.MTime, prop); break;
+ case kpidCTime: TimeToProp(item.CTime, prop); break;
+ case kpidATime: TimeToProp(item.ATime, prop); break;
+ case kpidPosixAttrib:
+ if (item.ModeDefined)
+ {
+ UInt32 mode = item.Mode;
+ if ((mode & MY_LIN_S_IFMT) == 0)
+ mode |= (item.IsDir ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG);
+ prop = mode;
+ }
+ break;
+ case kpidUser: Utf8StringToProp(item.User, prop); break;
+ case kpidGroup: Utf8StringToProp(item.Group, prop); break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _files.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 index = (allFilesMode ? i : indices[i]);
+ #ifdef XAR_SHOW_RAW
+ if (index == _files.Size())
+ totalSize += _xmlLen;
+ else
+ #endif
+ totalSize += _files[index].Size;
+ }
+ extractCallback->SetTotal(totalSize);
+
+ UInt64 currentPackTotal = 0;
+ UInt64 currentUnpTotal = 0;
+ UInt64 currentPackSize = 0;
+ UInt64 currentUnpSize = 0;
+
+ const UInt32 kZeroBufSize = (1 << 14);
+ CByteBuffer zeroBuf(kZeroBufSize);
+ memset(zeroBuf, 0, kZeroBufSize);
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ NCompress::NZlib::CDecoder *zlibCoderSpec = new NCompress::NZlib::CDecoder();
+ CMyComPtr<ICompressCoder> zlibCoder = zlibCoderSpec;
+
+ NCompress::NBZip2::CDecoder *bzip2CoderSpec = new NCompress::NBZip2::CDecoder();
+ CMyComPtr<ICompressCoder> bzip2Coder = bzip2CoderSpec;
+
+ NCompress::NDeflate::NDecoder::CCOMCoder *deflateCoderSpec = new NCompress::NDeflate::NDecoder::CCOMCoder();
+ CMyComPtr<ICompressCoder> deflateCoder = deflateCoderSpec;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *inStreamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(inStreamSpec);
+ inStreamSpec->SetStream(_inStream);
+
+
+ CLimitedSequentialOutStream *outStreamLimSpec = new CLimitedSequentialOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamLimSpec);
+
+ COutStreamWithSha1 *outStreamSha1Spec = new COutStreamWithSha1;
+ {
+ CMyComPtr<ISequentialOutStream> outStreamSha1(outStreamSha1Spec);
+ outStreamLimSpec->SetStream(outStreamSha1);
+ }
+
+ for (i = 0; i < numItems; i++, currentPackTotal += currentPackSize, currentUnpTotal += currentUnpSize)
+ {
+ lps->InSize = currentPackTotal;
+ lps->OutSize = currentUnpTotal;
+ currentPackSize = 0;
+ currentUnpSize = 0;
+ RINOK(lps->SetCur())
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+ if (index < _files.Size())
+ {
+ const CFile &item = _files[index];
+ if (item.IsDir)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ continue;
+ }
+ }
+
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode))
+
+ outStreamSha1Spec->SetStream(realOutStream);
+ realOutStream.Release();
+
+ Int32 opRes = NExtract::NOperationResult::kOK;
+ #ifdef XAR_SHOW_RAW
+ if (index == _files.Size())
+ {
+ outStreamSha1Spec->Init(false);
+ outStreamLimSpec->Init(_xmlLen);
+ RINOK(WriteStream(outStream, _xml, _xmlLen))
+ currentPackSize = currentUnpSize = _xmlLen;
+ }
+ else
+ #endif
+ {
+ const CFile &item = _files[index];
+ if (item.HasData)
+ {
+ currentPackSize = item.PackSize;
+ currentUnpSize = item.Size;
+
+ RINOK(InStream_SeekSet(_inStream, _dataStartPos + item.Offset))
+ inStreamSpec->Init(item.PackSize);
+ outStreamSha1Spec->Init(item.Sha1IsDefined);
+ outStreamLimSpec->Init(item.Size);
+ HRESULT res = S_OK;
+
+ ICompressCoder *coder = NULL;
+ if (item.IsCopyMethod())
+ if (item.PackSize == item.Size)
+ coder = copyCoder;
+ else
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ else if (item.Method == METHOD_NAME_ZLIB)
+ coder = zlibCoder;
+ else if (item.Method == "bzip2")
+ coder = bzip2Coder;
+ else
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+
+ if (coder)
+ res = coder->Code(inStream, outStream, NULL, NULL, progress);
+
+ if (res != S_OK)
+ {
+ if (!outStreamLimSpec->IsFinishedOK())
+ opRes = NExtract::NOperationResult::kDataError;
+ else if (res != S_FALSE)
+ return res;
+ if (opRes == NExtract::NOperationResult::kOK)
+ opRes = NExtract::NOperationResult::kDataError;
+ }
+
+ if (opRes == NExtract::NOperationResult::kOK)
+ {
+ if (outStreamLimSpec->IsFinishedOK() &&
+ outStreamSha1Spec->GetSize() == item.Size)
+ {
+ if (!outStreamLimSpec->IsFinishedOK())
+ {
+ opRes = NExtract::NOperationResult::kDataError;
+ }
+ else if (item.Sha1IsDefined)
+ {
+ Byte digest[SHA1_DIGEST_SIZE];
+ outStreamSha1Spec->Final(digest);
+ if (memcmp(digest, item.Sha1, SHA1_DIGEST_SIZE) != 0)
+ opRes = NExtract::NOperationResult::kCRCError;
+ }
+ }
+ else
+ opRes = NExtract::NOperationResult::kDataError;
+ }
+ }
+ }
+ outStreamSha1Spec->ReleaseStream();
+ RINOK(extractCallback->SetOperationResult(opRes))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ *stream = NULL;
+ COM_TRY_BEGIN
+ #ifdef XAR_SHOW_RAW
+ if (index == _files.Size())
+ {
+ Create_BufInStream_WithNewBuffer(_xml, _xmlLen, stream);
+ return S_OK;
+ }
+ else
+ #endif
+ {
+ const CFile &item = _files[index];
+ if (item.HasData && item.IsCopyMethod() && item.PackSize == item.Size)
+ return CreateLimitedInStream(_inStream, _dataStartPos + item.Offset, item.Size, stream);
+ }
+ return S_FALSE;
+ COM_TRY_END
+}
+
+static const Byte k_Signature[] = { 'x', 'a', 'r', '!', 0, 0x1C };
+
+REGISTER_ARC_I(
+ "Xar", "xar pkg xip", NULL, 0xE1,
+ k_Signature,
+ 0,
+ 0,
+ NULL)
+
+}}
diff --git a/CPP/7zip/Archive/XzHandler.cpp b/CPP/7zip/Archive/XzHandler.cpp
index 743271a..976817c 100644
--- a/CPP/7zip/Archive/XzHandler.cpp
+++ b/CPP/7zip/Archive/XzHandler.cpp
@@ -1,1308 +1,1443 @@
-// XzHandler.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/Alloc.h"
-
-#include "../../Common/ComTry.h"
-#include "../../Common/Defs.h"
-#include "../../Common/IntToString.h"
-#include "../../Common/MyBuffer.h"
-#include "../../Common/StringToInt.h"
-
-#include "../../Windows/PropVariant.h"
-#include "../../Windows/System.h"
-
-#include "../Common/CWrappers.h"
-#include "../Common/ProgressUtils.h"
-#include "../Common/RegisterArc.h"
-#include "../Common/StreamUtils.h"
-
-#include "../Compress/CopyCoder.h"
-#include "../Compress/XzDecoder.h"
-#include "../Compress/XzEncoder.h"
-
-#include "IArchive.h"
-
-#include "Common/HandlerOut.h"
-
-using namespace NWindows;
-
-namespace NArchive {
-namespace NXz {
-
-#define k_LZMA2_Name "LZMA2"
-
-
-struct CBlockInfo
-{
- unsigned StreamFlags;
- UInt64 PackPos;
- UInt64 PackSize; // pure value from Index record, it doesn't include pad zeros
- UInt64 UnpackPos;
-};
-
-
-class CHandler:
- public IInArchive,
- public IArchiveOpenSeq,
- public IInArchiveGetStream,
- public ISetProperties,
-
- #ifndef EXTRACT_ONLY
- public IOutArchive,
- #endif
-
- public CMyUnknownImp,
-
- #ifndef EXTRACT_ONLY
- public CMultiMethodProps
- #else
- public CCommonMethodProps
- #endif
-{
- CXzStatInfo _stat;
- SRes MainDecodeSRes;
-
- bool _isArc;
- bool _needSeekToStart;
- bool _phySize_Defined;
- bool _firstBlockWasRead;
-
- AString _methodsString;
-
- #ifndef EXTRACT_ONLY
-
- UInt32 _filterId;
-
- UInt64 _numSolidBytes;
-
- void InitXz()
- {
- _filterId = 0;
- _numSolidBytes = XZ_PROPS__BLOCK_SIZE__AUTO;
- }
-
- #endif
-
- void Init()
- {
- #ifndef EXTRACT_ONLY
- InitXz();
- CMultiMethodProps::Init();
- #else
- CCommonMethodProps::InitCommon();
- #endif
- }
-
- HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value);
-
- HRESULT Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback);
-
- HRESULT Decode(NCompress::NXz::CDecoder &decoder,
- ISequentialInStream *seqInStream,
- ISequentialOutStream *outStream,
- ICompressProgressInfo *progress)
- {
- #ifndef _7ZIP_ST
- decoder._numThreads = _numThreads;
- #endif
- decoder._memUsage = _memUsage;
-
- MainDecodeSRes = SZ_OK;
-
- RINOK(decoder.Decode(seqInStream, outStream,
- NULL, // *outSizeLimit
- true, // finishStream
- progress));
-
- _stat = decoder.Stat;
- MainDecodeSRes = decoder.MainDecodeSRes;
-
- _phySize_Defined = true;
- return S_OK;
- }
-
-public:
- MY_QUERYINTERFACE_BEGIN2(IInArchive)
- MY_QUERYINTERFACE_ENTRY(IArchiveOpenSeq)
- MY_QUERYINTERFACE_ENTRY(IInArchiveGetStream)
- MY_QUERYINTERFACE_ENTRY(ISetProperties)
- #ifndef EXTRACT_ONLY
- MY_QUERYINTERFACE_ENTRY(IOutArchive)
- #endif
- MY_QUERYINTERFACE_END
- MY_ADDREF_RELEASE
-
- INTERFACE_IInArchive(;)
- STDMETHOD(OpenSeq)(ISequentialInStream *stream);
- STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
- STDMETHOD(SetProperties)(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps);
-
- #ifndef EXTRACT_ONLY
- INTERFACE_IOutArchive(;)
- #endif
-
- size_t _blocksArraySize;
- CBlockInfo *_blocks;
- UInt64 _maxBlocksSize;
- CMyComPtr<IInStream> _stream;
- CMyComPtr<ISequentialInStream> _seqStream;
-
- CXzBlock _firstBlock;
-
- CHandler();
- ~CHandler();
-
- HRESULT SeekToPackPos(UInt64 pos)
- {
- return _stream->Seek(pos, STREAM_SEEK_SET, NULL);
- }
-};
-
-
-CHandler::CHandler():
- _blocks(NULL),
- _blocksArraySize(0)
-{
- #ifndef EXTRACT_ONLY
- InitXz();
- #endif
-}
-
-CHandler::~CHandler()
-{
- MyFree(_blocks);
-}
-
-
-static const Byte kProps[] =
-{
- kpidSize,
- kpidPackSize,
- kpidMethod
-};
-
-static const Byte kArcProps[] =
-{
- kpidMethod,
- kpidNumStreams,
- kpidNumBlocks,
- kpidClusterSize,
- kpidCharacts
-};
-
-IMP_IInArchive_Props
-IMP_IInArchive_ArcProps
-
-static inline char GetHex(unsigned value)
-{
- return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
-}
-
-static inline void AddHexToString(AString &s, Byte value)
-{
- s += GetHex(value >> 4);
- s += GetHex(value & 0xF);
-}
-
-static void Lzma2PropToString(AString &s, unsigned prop)
-{
- char c = 0;
- UInt32 size;
- if ((prop & 1) == 0)
- size = prop / 2 + 12;
- else
- {
- c = 'k';
- size = (UInt32)(2 | (prop & 1)) << (prop / 2 + 1);
- if (prop > 17)
- {
- size >>= 10;
- c = 'm';
- }
- }
- s.Add_UInt32(size);
- if (c != 0)
- s += c;
-}
-
-struct CMethodNamePair
-{
- UInt32 Id;
- const char *Name;
-};
-
-static const CMethodNamePair g_NamePairs[] =
-{
- { XZ_ID_Subblock, "SB" },
- { XZ_ID_Delta, "Delta" },
- { XZ_ID_X86, "BCJ" },
- { XZ_ID_PPC, "PPC" },
- { XZ_ID_IA64, "IA64" },
- { XZ_ID_ARM, "ARM" },
- { XZ_ID_ARMT, "ARMT" },
- { XZ_ID_SPARC, "SPARC" },
- { XZ_ID_LZMA2, "LZMA2" }
-};
-
-static void AddMethodString(AString &s, const CXzFilter &f)
-{
- const char *p = NULL;
- for (unsigned i = 0; i < ARRAY_SIZE(g_NamePairs); i++)
- if (g_NamePairs[i].Id == f.id)
- {
- p = g_NamePairs[i].Name;
- break;
- }
- char temp[32];
- if (!p)
- {
- ::ConvertUInt64ToString(f.id, temp);
- p = temp;
- }
-
- s += p;
-
- if (f.propsSize > 0)
- {
- s += ':';
- if (f.id == XZ_ID_LZMA2 && f.propsSize == 1)
- Lzma2PropToString(s, f.props[0]);
- else if (f.id == XZ_ID_Delta && f.propsSize == 1)
- s.Add_UInt32((UInt32)f.props[0] + 1);
- else
- {
- s += '[';
- for (UInt32 bi = 0; bi < f.propsSize; bi++)
- AddHexToString(s, f.props[bi]);
- s += ']';
- }
- }
-}
-
-static const char * const kChecks[] =
-{
- "NoCheck"
- , "CRC32"
- , NULL
- , NULL
- , "CRC64"
- , NULL
- , NULL
- , NULL
- , NULL
- , NULL
- , "SHA256"
- , NULL
- , NULL
- , NULL
- , NULL
- , NULL
-};
-
-static void AddCheckString(AString &s, const CXzs &xzs)
-{
- size_t i;
- UInt32 mask = 0;
- for (i = 0; i < xzs.num; i++)
- mask |= ((UInt32)1 << XzFlags_GetCheckType(xzs.streams[i].flags));
- for (i = 0; i <= XZ_CHECK_MASK; i++)
- if (((mask >> i) & 1) != 0)
- {
- s.Add_Space_if_NotEmpty();
- if (kChecks[i])
- s += kChecks[i];
- else
- {
- s += "Check-";
- s.Add_UInt32((UInt32)i);
- }
- }
-}
-
-STDMETHODIMP CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value)
-{
- COM_TRY_BEGIN
- NCOM::CPropVariant prop;
- switch (propID)
- {
- case kpidPhySize: if (_phySize_Defined) prop = _stat.InSize; break;
- case kpidNumStreams: if (_stat.NumStreams_Defined) prop = _stat.NumStreams; break;
- case kpidNumBlocks: if (_stat.NumBlocks_Defined) prop = _stat.NumBlocks; break;
- case kpidUnpackSize: if (_stat.UnpackSize_Defined) prop = _stat.OutSize; break;
- case kpidClusterSize: if (_stat.NumBlocks_Defined && _stat.NumBlocks > 1) prop = _maxBlocksSize; break;
- case kpidCharacts:
- if (_firstBlockWasRead)
- {
- AString s;
- if (XzBlock_HasPackSize(&_firstBlock))
- s.Add_OptSpaced("BlockPackSize");
- if (XzBlock_HasUnpackSize(&_firstBlock))
- s.Add_OptSpaced("BlockUnpackSize");
- if (!s.IsEmpty())
- prop = s;
- }
- break;
-
-
- case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;
- case kpidErrorFlags:
- {
- UInt32 v = 0;
- SRes sres = MainDecodeSRes; // _stat.DecodeRes2; //
- if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
- if (/*_stat.UnexpectedEnd */ sres == SZ_ERROR_INPUT_EOF) v |= kpv_ErrorFlags_UnexpectedEnd;
- if (_stat.DataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
- if (/* _stat.HeadersError */ sres == SZ_ERROR_ARCHIVE) v |= kpv_ErrorFlags_HeadersError;
- if (/* _stat.Unsupported */ sres == SZ_ERROR_UNSUPPORTED) v |= kpv_ErrorFlags_UnsupportedMethod;
- if (/* _stat.DataError */ sres == SZ_ERROR_DATA) v |= kpv_ErrorFlags_DataError;
- if (/* _stat.CrcError */ sres == SZ_ERROR_CRC) v |= kpv_ErrorFlags_CrcError;
- if (v != 0)
- prop = v;
- break;
- }
-
- case kpidMainSubfile:
- {
- // debug only, comment it:
- // if (_blocks) prop = (UInt32)0;
- break;
- }
- }
- prop.Detach(value);
- return S_OK;
- COM_TRY_END
-}
-
-STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
-{
- *numItems = 1;
- return S_OK;
-}
-
-STDMETHODIMP CHandler::GetProperty(UInt32, PROPID propID, PROPVARIANT *value)
-{
- COM_TRY_BEGIN
- NCOM::CPropVariant prop;
- switch (propID)
- {
- case kpidSize: if (_stat.UnpackSize_Defined) prop = _stat.OutSize; break;
- case kpidPackSize: if (_phySize_Defined) prop = _stat.InSize; break;
- case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;
- }
- prop.Detach(value);
- return S_OK;
- COM_TRY_END
-}
-
-
-struct COpenCallbackWrap
-{
- ICompressProgress vt;
- IArchiveOpenCallback *OpenCallback;
- HRESULT Res;
- COpenCallbackWrap(IArchiveOpenCallback *progress);
-};
-
-static SRes OpenCallbackProgress(const ICompressProgress *pp, UInt64 inSize, UInt64 /* outSize */)
-{
- COpenCallbackWrap *p = CONTAINER_FROM_VTBL(pp, COpenCallbackWrap, vt);
- if (p->OpenCallback)
- p->Res = p->OpenCallback->SetCompleted(NULL, &inSize);
- return HRESULT_To_SRes(p->Res, SZ_ERROR_PROGRESS);
-}
-
-COpenCallbackWrap::COpenCallbackWrap(IArchiveOpenCallback *callback)
-{
- vt.Progress = OpenCallbackProgress;
- OpenCallback = callback;
- Res = SZ_OK;
-}
-
-
-struct CXzsCPP
-{
- CXzs p;
- CXzsCPP() { Xzs_Construct(&p); }
- ~CXzsCPP() { Xzs_Free(&p, &g_Alloc); }
-};
-
-#define kInputBufSize ((size_t)1 << 10)
-
-struct CLookToRead2_CPP: public CLookToRead2
-{
- CLookToRead2_CPP()
- {
- buf = NULL;
- LookToRead2_CreateVTable(this,
- True // Lookahead ?
- );
- }
- void Alloc(size_t allocSize)
- {
- buf = (Byte *)MyAlloc(allocSize);
- if (buf)
- this->bufSize = allocSize;
- }
- ~CLookToRead2_CPP()
- {
- MyFree(buf);
- }
-};
-
-
-static HRESULT SRes_to_Open_HRESULT(SRes res)
-{
- switch (res)
- {
- case SZ_OK: return S_OK;
- case SZ_ERROR_MEM: return E_OUTOFMEMORY;
- case SZ_ERROR_PROGRESS: return E_ABORT;
- /*
- case SZ_ERROR_UNSUPPORTED:
- case SZ_ERROR_CRC:
- case SZ_ERROR_DATA:
- case SZ_ERROR_ARCHIVE:
- case SZ_ERROR_NO_ARCHIVE:
- return S_FALSE;
- */
- }
- return S_FALSE;
-}
-
-
-
-HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback)
-{
- _needSeekToStart = true;
-
- {
- CXzStreamFlags st;
- CSeqInStreamWrap inStreamWrap;
-
- inStreamWrap.Init(inStream);
- SRes res = Xz_ReadHeader(&st, &inStreamWrap.vt);
- if (res != SZ_OK)
- return SRes_to_Open_HRESULT(res);
-
- {
- CXzBlock block;
- BoolInt isIndex;
- UInt32 headerSizeRes;
- SRes res2 = XzBlock_ReadHeader(&block, &inStreamWrap.vt, &isIndex, &headerSizeRes);
- if (res2 == SZ_OK && !isIndex)
- {
- _firstBlockWasRead = true;
- _firstBlock = block;
-
- unsigned numFilters = XzBlock_GetNumFilters(&block);
- for (unsigned i = 0; i < numFilters; i++)
- {
- _methodsString.Add_Space_if_NotEmpty();
- AddMethodString(_methodsString, block.filters[i]);
- }
- }
- }
- }
-
- RINOK(inStream->Seek(0, STREAM_SEEK_END, &_stat.InSize));
- if (callback)
- {
- RINOK(callback->SetTotal(NULL, &_stat.InSize));
- }
-
- CSeekInStreamWrap inStreamImp;
-
- inStreamImp.Init(inStream);
-
- CLookToRead2_CPP lookStream;
-
- lookStream.Alloc(kInputBufSize);
-
- if (!lookStream.buf)
- return E_OUTOFMEMORY;
-
- lookStream.realStream = &inStreamImp.vt;
- LookToRead2_Init(&lookStream);
-
- COpenCallbackWrap openWrap(callback);
-
- CXzsCPP xzs;
- Int64 startPosition;
- SRes res = Xzs_ReadBackward(&xzs.p, &lookStream.vt, &startPosition, &openWrap.vt, &g_Alloc);
- if (res == SZ_ERROR_PROGRESS)
- return (openWrap.Res == S_OK) ? E_FAIL : openWrap.Res;
- /*
- if (res == SZ_ERROR_NO_ARCHIVE && xzs.p.num > 0)
- res = SZ_OK;
- */
- if (res == SZ_OK && startPosition == 0)
- {
- _phySize_Defined = true;
-
- _stat.OutSize = Xzs_GetUnpackSize(&xzs.p);
- _stat.UnpackSize_Defined = true;
-
- _stat.NumStreams = xzs.p.num;
- _stat.NumStreams_Defined = true;
-
- _stat.NumBlocks = Xzs_GetNumBlocks(&xzs.p);
- _stat.NumBlocks_Defined = true;
-
- AddCheckString(_methodsString, xzs.p);
-
- const size_t numBlocks = (size_t)_stat.NumBlocks + 1;
- const size_t bytesAlloc = numBlocks * sizeof(CBlockInfo);
-
- if (bytesAlloc / sizeof(CBlockInfo) == _stat.NumBlocks + 1)
- {
- _blocks = (CBlockInfo *)MyAlloc(bytesAlloc);
- if (_blocks)
- {
- unsigned blockIndex = 0;
- UInt64 unpackPos = 0;
-
- for (size_t si = xzs.p.num; si != 0;)
- {
- si--;
- const CXzStream &str = xzs.p.streams[si];
- UInt64 packPos = str.startOffset + XZ_STREAM_HEADER_SIZE;
-
- for (size_t bi = 0; bi < str.numBlocks; bi++)
- {
- const CXzBlockSizes &bs = str.blocks[bi];
- const UInt64 packSizeAligned = bs.totalSize + ((0 - (unsigned)bs.totalSize) & 3);
-
- if (bs.unpackSize != 0)
- {
- if (blockIndex >= _stat.NumBlocks)
- return E_FAIL;
-
- CBlockInfo &block = _blocks[blockIndex++];
- block.StreamFlags = str.flags;
- block.PackSize = bs.totalSize; // packSizeAligned;
- block.PackPos = packPos;
- block.UnpackPos = unpackPos;
- }
- packPos += packSizeAligned;
- unpackPos += bs.unpackSize;
- if (_maxBlocksSize < bs.unpackSize)
- _maxBlocksSize = bs.unpackSize;
- }
- }
-
- /*
- if (blockIndex != _stat.NumBlocks)
- {
- // there are Empty blocks;
- }
- */
- if (_stat.OutSize != unpackPos)
- return E_FAIL;
- CBlockInfo &block = _blocks[blockIndex++];
- block.StreamFlags = 0;
- block.PackSize = 0;
- block.PackPos = 0;
- block.UnpackPos = unpackPos;
- _blocksArraySize = blockIndex;
- }
- }
- }
- else
- {
- res = SZ_OK;
- }
-
- RINOK(SRes_to_Open_HRESULT(res));
- _stream = inStream;
- _seqStream = inStream;
- _isArc = true;
- return S_OK;
-}
-
-
-
-STDMETHODIMP CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback)
-{
- COM_TRY_BEGIN
- {
- Close();
- return Open2(inStream, callback);
- }
- COM_TRY_END
-}
-
-STDMETHODIMP CHandler::OpenSeq(ISequentialInStream *stream)
-{
- Close();
- _seqStream = stream;
- _isArc = true;
- _needSeekToStart = false;
- return S_OK;
-}
-
-STDMETHODIMP CHandler::Close()
-{
- XzStatInfo_Clear(&_stat);
-
- _isArc = false;
- _needSeekToStart = false;
- _phySize_Defined = false;
- _firstBlockWasRead = false;
-
- _methodsString.Empty();
- _stream.Release();
- _seqStream.Release();
-
- MyFree(_blocks);
- _blocks = NULL;
- _blocksArraySize = 0;
- _maxBlocksSize = 0;
-
- MainDecodeSRes = SZ_OK;
-
- return S_OK;
-}
-
-
-struct CXzUnpackerCPP2
-{
- Byte *InBuf;
- // Byte *OutBuf;
- CXzUnpacker p;
-
- CXzUnpackerCPP2();
- ~CXzUnpackerCPP2();
-};
-
-CXzUnpackerCPP2::CXzUnpackerCPP2(): InBuf(NULL)
- // , OutBuf(NULL)
-{
- XzUnpacker_Construct(&p, &g_Alloc);
-}
-
-CXzUnpackerCPP2::~CXzUnpackerCPP2()
-{
- XzUnpacker_Free(&p);
- MidFree(InBuf);
- // MidFree(OutBuf);
-}
-
-
-class CInStream:
- public IInStream,
- public CMyUnknownImp
-{
-public:
- UInt64 _virtPos;
- UInt64 Size;
- UInt64 _cacheStartPos;
- size_t _cacheSize;
- CByteBuffer _cache;
- // UInt64 _startPos;
- CXzUnpackerCPP2 xz;
-
- void InitAndSeek()
- {
- _virtPos = 0;
- _cacheStartPos = 0;
- _cacheSize = 0;
- // _startPos = startPos;
- }
-
- CHandler *_handlerSpec;
- CMyComPtr<IUnknown> _handler;
-
- MY_UNKNOWN_IMP1(IInStream)
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
-
- ~CInStream();
-};
-
-
-CInStream::~CInStream()
-{
- // _cache.Free();
-}
-
-
-size_t FindBlock(const CBlockInfo *blocks, size_t numBlocks, UInt64 pos)
-{
- size_t left = 0, right = numBlocks;
- for (;;)
- {
- size_t mid = (left + right) / 2;
- if (mid == left)
- return left;
- if (pos < blocks[mid].UnpackPos)
- right = mid;
- else
- left = mid;
- }
-}
-
-
-
-static HRESULT DecodeBlock(CXzUnpackerCPP2 &xzu,
- ISequentialInStream *seqInStream,
- unsigned streamFlags,
- UInt64 packSize, // pure size from Index record, it doesn't include pad zeros
- size_t unpackSize, Byte *dest
- // , ICompressProgressInfo *progress
- )
-{
- const size_t kInBufSize = (size_t)1 << 16;
-
- XzUnpacker_Init(&xzu.p);
-
- if (!xzu.InBuf)
- {
- xzu.InBuf = (Byte *)MidAlloc(kInBufSize);
- if (!xzu.InBuf)
- return E_OUTOFMEMORY;
- }
-
- xzu.p.streamFlags = (UInt16)streamFlags;
- XzUnpacker_PrepareToRandomBlockDecoding(&xzu.p);
-
- XzUnpacker_SetOutBuf(&xzu.p, dest, unpackSize);
-
- const UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3);
- UInt64 packRem = packSizeAligned;
-
- UInt32 inSize = 0;
- SizeT inPos = 0;
- SizeT outPos = 0;
-
- HRESULT readRes = S_OK;
-
- for (;;)
- {
- if (inPos == inSize && readRes == S_OK)
- {
- inPos = 0;
- inSize = 0;
- UInt32 rem = kInBufSize;
- if (rem > packRem)
- rem = (UInt32)packRem;
- if (rem != 0)
- readRes = seqInStream->Read(xzu.InBuf, rem, &inSize);
- }
-
- SizeT inLen = inSize - inPos;
- SizeT outLen = unpackSize - outPos;
-
- ECoderStatus status;
-
- SRes res = XzUnpacker_Code(&xzu.p,
- // dest + outPos,
- NULL,
- &outLen,
- xzu.InBuf + inPos, &inLen,
- (inLen == 0), // srcFinished
- CODER_FINISH_END, &status);
-
- // return E_OUTOFMEMORY;
- // res = SZ_ERROR_CRC;
-
- if (res != SZ_OK)
- {
- if (res == SZ_ERROR_CRC)
- return S_FALSE;
- return SResToHRESULT(res);
- }
-
- inPos += inLen;
- outPos += outLen;
-
- packRem -= inLen;
-
- BoolInt blockFinished = XzUnpacker_IsBlockFinished(&xzu.p);
-
- if ((inLen == 0 && outLen == 0) || blockFinished)
- {
- if (packRem != 0 || !blockFinished || unpackSize != outPos)
- return S_FALSE;
- if (XzUnpacker_GetPackSizeForIndex(&xzu.p) != packSize)
- return S_FALSE;
- return S_OK;
- }
- }
-}
-
-
-STDMETHODIMP CInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- COM_TRY_BEGIN
-
- if (processedSize)
- *processedSize = 0;
- if (size == 0)
- return S_OK;
-
- {
- if (_virtPos >= Size)
- return S_OK; // (Size == _virtPos) ? S_OK: E_FAIL;
- {
- UInt64 rem = Size - _virtPos;
- if (size > rem)
- size = (UInt32)rem;
- }
- }
-
- if (size == 0)
- return S_OK;
-
- if (_virtPos < _cacheStartPos || _virtPos >= _cacheStartPos + _cacheSize)
- {
- size_t bi = FindBlock(_handlerSpec->_blocks, _handlerSpec->_blocksArraySize, _virtPos);
- const CBlockInfo &block = _handlerSpec->_blocks[bi];
- const UInt64 unpackSize = _handlerSpec->_blocks[bi + 1].UnpackPos - block.UnpackPos;
- if (_cache.Size() < unpackSize)
- return E_FAIL;
-
- _cacheSize = 0;
-
- RINOK(_handlerSpec->SeekToPackPos(block.PackPos));
- RINOK(DecodeBlock(xz, _handlerSpec->_seqStream, block.StreamFlags, block.PackSize,
- (size_t)unpackSize, _cache));
- _cacheStartPos = block.UnpackPos;
- _cacheSize = (size_t)unpackSize;
- }
-
- {
- size_t offset = (size_t)(_virtPos - _cacheStartPos);
- size_t rem = _cacheSize - offset;
- if (size > rem)
- size = (UInt32)rem;
- memcpy(data, _cache + offset, size);
- _virtPos += size;
- if (processedSize)
- *processedSize = size;
- return S_OK;
- }
-
- COM_TRY_END
-}
-
-
-STDMETHODIMP CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- switch (seekOrigin)
- {
- case STREAM_SEEK_SET: break;
- case STREAM_SEEK_CUR: offset += _virtPos; break;
- case STREAM_SEEK_END: offset += Size; break;
- default: return STG_E_INVALIDFUNCTION;
- }
- if (offset < 0)
- return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
- _virtPos = offset;
- if (newPosition)
- *newPosition = offset;
- return S_OK;
-}
-
-
-
-static const UInt64 kMaxBlockSize_for_GetStream = (UInt64)1 << 40;
-
-STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
-{
- COM_TRY_BEGIN
-
- *stream = NULL;
-
- if (index != 0)
- return E_INVALIDARG;
-
- if (!_stat.UnpackSize_Defined
- || _maxBlocksSize == 0 // 18.02
- || _maxBlocksSize > kMaxBlockSize_for_GetStream
- || _maxBlocksSize != (size_t)_maxBlocksSize)
- return S_FALSE;
-
- UInt64 memSize;
- if (!NSystem::GetRamSize(memSize))
- memSize = (UInt64)(sizeof(size_t)) << 28;
- {
- if (_maxBlocksSize > memSize / 4)
- return S_FALSE;
- }
-
- CInStream *spec = new CInStream;
- CMyComPtr<ISequentialInStream> specStream = spec;
- spec->_cache.Alloc((size_t)_maxBlocksSize);
- spec->_handlerSpec = this;
- spec->_handler = (IInArchive *)this;
- spec->Size = _stat.OutSize;
- spec->InitAndSeek();
-
- *stream = specStream.Detach();
- return S_OK;
-
- COM_TRY_END
-}
-
-
-static Int32 Get_Extract_OperationResult(const NCompress::NXz::CDecoder &decoder)
-{
- Int32 opRes;
- SRes sres = decoder.MainDecodeSRes; // decoder.Stat.DecodeRes2;
- if (sres == SZ_ERROR_NO_ARCHIVE) // (!IsArc)
- opRes = NExtract::NOperationResult::kIsNotArc;
- else if (sres == SZ_ERROR_INPUT_EOF) // (UnexpectedEnd)
- opRes = NExtract::NOperationResult::kUnexpectedEnd;
- else if (decoder.Stat.DataAfterEnd)
- opRes = NExtract::NOperationResult::kDataAfterEnd;
- else if (sres == SZ_ERROR_CRC) // (CrcError)
- opRes = NExtract::NOperationResult::kCRCError;
- else if (sres == SZ_ERROR_UNSUPPORTED) // (Unsupported)
- opRes = NExtract::NOperationResult::kUnsupportedMethod;
- else if (sres == SZ_ERROR_ARCHIVE) // (HeadersError)
- opRes = NExtract::NOperationResult::kDataError;
- else if (sres == SZ_ERROR_DATA) // (DataError)
- opRes = NExtract::NOperationResult::kDataError;
- else if (sres != SZ_OK)
- opRes = NExtract::NOperationResult::kDataError;
- else
- opRes = NExtract::NOperationResult::kOK;
- return opRes;
-}
-
-
-
-
-STDMETHODIMP CHandler::Extract(const UInt32 *indices, UInt32 numItems,
- Int32 testMode, IArchiveExtractCallback *extractCallback)
-{
- COM_TRY_BEGIN
- if (numItems == 0)
- return S_OK;
- if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
- return E_INVALIDARG;
-
- if (_phySize_Defined)
- extractCallback->SetTotal(_stat.InSize);
-
- 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);
-
- CLocalProgress *lps = new CLocalProgress;
- CMyComPtr<ICompressProgressInfo> lpsRef = lps;
- lps->Init(extractCallback, true);
-
- if (_needSeekToStart)
- {
- if (!_stream)
- return E_FAIL;
- RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
- }
- else
- _needSeekToStart = true;
-
-
- NCompress::NXz::CDecoder decoder;
-
- HRESULT hres = Decode(decoder, _seqStream, realOutStream, lpsRef);
-
- if (!decoder.MainDecodeSRes_wasUsed)
- return hres == S_OK ? E_FAIL : hres;
-
- Int32 opRes = Get_Extract_OperationResult(decoder);
- if (opRes == NExtract::NOperationResult::kOK
- && hres != S_OK)
- opRes = NExtract::NOperationResult::kDataError;
-
- realOutStream.Release();
- return extractCallback->SetOperationResult(opRes);
- COM_TRY_END
-}
-
-
-
-#ifndef EXTRACT_ONLY
-
-STDMETHODIMP CHandler::GetFileTimeType(UInt32 *timeType)
-{
- *timeType = NFileTimeType::kUnix;
- return S_OK;
-}
-
-
-STDMETHODIMP CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
- IArchiveUpdateCallback *updateCallback)
-{
- COM_TRY_BEGIN
-
- if (numItems == 0)
- {
- CSeqOutStreamWrap seqOutStream;
- seqOutStream.Init(outStream);
- SRes res = Xz_EncodeEmpty(&seqOutStream.vt);
- return SResToHRESULT(res);
- }
-
- if (numItems != 1)
- return E_INVALIDARG;
-
- Int32 newData, newProps;
- UInt32 indexInArchive;
- if (!updateCallback)
- return E_FAIL;
- RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive));
-
- if (IntToBool(newProps))
- {
- {
- NCOM::CPropVariant prop;
- RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop));
- if (prop.vt != VT_EMPTY)
- if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE)
- return E_INVALIDARG;
- }
- }
-
- if (IntToBool(newData))
- {
- UInt64 size;
- {
- NCOM::CPropVariant prop;
- RINOK(updateCallback->GetProperty(0, kpidSize, &prop));
- if (prop.vt != VT_UI8)
- return E_INVALIDARG;
- size = prop.uhVal.QuadPart;
- RINOK(updateCallback->SetTotal(size));
- }
-
- NCompress::NXz::CEncoder *encoderSpec = new NCompress::NXz::CEncoder;
- CMyComPtr<ICompressCoder> encoder = encoderSpec;
-
- CXzProps &xzProps = encoderSpec->xzProps;
- CLzma2EncProps &lzma2Props = xzProps.lzma2Props;
-
- lzma2Props.lzmaProps.level = GetLevel();
-
- xzProps.reduceSize = size;
- /*
- {
- NCOM::CPropVariant prop = (UInt64)size;
- RINOK(encoderSpec->SetCoderProp(NCoderPropID::kReduceSize, prop));
- }
- */
-
- #ifndef _7ZIP_ST
- xzProps.numTotalThreads = _numThreads;
- #endif
-
- xzProps.blockSize = _numSolidBytes;
- if (_numSolidBytes == XZ_PROPS__BLOCK_SIZE__SOLID)
- {
- xzProps.lzma2Props.blockSize = LZMA2_ENC_PROPS__BLOCK_SIZE__SOLID;
- }
-
- RINOK(encoderSpec->SetCheckSize(_crcSize));
-
- {
- CXzFilterProps &filter = xzProps.filterProps;
-
- if (_filterId == XZ_ID_Delta)
- {
- bool deltaDefined = false;
- FOR_VECTOR (j, _filterMethod.Props)
- {
- const CProp &prop = _filterMethod.Props[j];
- if (prop.Id == NCoderPropID::kDefaultProp && prop.Value.vt == VT_UI4)
- {
- UInt32 delta = (UInt32)prop.Value.ulVal;
- if (delta < 1 || delta > 256)
- return E_INVALIDARG;
- filter.delta = delta;
- deltaDefined = true;
- }
- else
- return E_INVALIDARG;
- }
- if (!deltaDefined)
- return E_INVALIDARG;
- }
- filter.id = _filterId;
- }
-
- FOR_VECTOR (i, _methods)
- {
- COneMethodInfo &m = _methods[i];
-
- FOR_VECTOR (j, m.Props)
- {
- const CProp &prop = m.Props[j];
- RINOK(encoderSpec->SetCoderProp(prop.Id, prop.Value));
- }
- }
-
- CMyComPtr<ISequentialInStream> fileInStream;
- RINOK(updateCallback->GetStream(0, &fileInStream));
-
- CLocalProgress *lps = new CLocalProgress;
- CMyComPtr<ICompressProgressInfo> progress = lps;
- lps->Init(updateCallback, true);
-
- return encoderSpec->Code(fileInStream, outStream, NULL, NULL, progress);
- }
-
- if (indexInArchive != 0)
- return E_INVALIDARG;
-
- CMyComPtr<IArchiveUpdateCallbackFile> opCallback;
- updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
- if (opCallback)
- {
- RINOK(opCallback->ReportOperation(NEventIndexType::kInArcIndex, 0, NUpdateNotifyOp::kReplicate))
- }
-
- if (_stream)
- {
- if (_phySize_Defined)
- RINOK(updateCallback->SetTotal(_stat.InSize));
- RINOK(_stream->Seek(0, STREAM_SEEK_SET, NULL));
- }
-
- CLocalProgress *lps = new CLocalProgress;
- CMyComPtr<ICompressProgressInfo> progress = lps;
- lps->Init(updateCallback, true);
-
- return NCompress::CopyStream(_stream, outStream, progress);
-
- COM_TRY_END
-}
-
-#endif
-
-
-HRESULT CHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
-{
- UString name = nameSpec;
- name.MakeLower_Ascii();
- if (name.IsEmpty())
- return E_INVALIDARG;
-
- #ifndef EXTRACT_ONLY
-
- if (name[0] == L's')
- {
- const wchar_t *s = name.Ptr(1);
- if (*s == 0)
- {
- bool useStr = false;
- bool isSolid;
- switch (value.vt)
- {
- case VT_EMPTY: isSolid = true; break;
- case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break;
- case VT_BSTR:
- if (!StringToBool(value.bstrVal, isSolid))
- useStr = true;
- break;
- default: return E_INVALIDARG;
- }
- if (!useStr)
- {
- _numSolidBytes = (isSolid ? XZ_PROPS__BLOCK_SIZE__SOLID : XZ_PROPS__BLOCK_SIZE__AUTO);
- return S_OK;
- }
- }
- return ParseSizeString(s, value,
- 0, // percentsBase
- _numSolidBytes) ? S_OK: E_INVALIDARG;
- }
-
- return CMultiMethodProps::SetProperty(name, value);
-
- #else
-
- {
- HRESULT hres;
- if (SetCommonProperty(name, value, hres))
- return hres;
- }
-
- return E_INVALIDARG;
-
- #endif
-}
-
-
-
-STDMETHODIMP CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps)
-{
- COM_TRY_BEGIN
-
- Init();
-
- for (UInt32 i = 0; i < numProps; i++)
- {
- RINOK(SetProperty(names[i], values[i]));
- }
-
- #ifndef EXTRACT_ONLY
-
- if (!_filterMethod.MethodName.IsEmpty())
- {
- unsigned k;
- for (k = 0; k < ARRAY_SIZE(g_NamePairs); k++)
- {
- const CMethodNamePair &pair = g_NamePairs[k];
- if (StringsAreEqualNoCase_Ascii(_filterMethod.MethodName, pair.Name))
- {
- _filterId = pair.Id;
- break;
- }
- }
- if (k == ARRAY_SIZE(g_NamePairs))
- return E_INVALIDARG;
- }
-
- _methods.DeleteFrontal(GetNumEmptyMethods());
- if (_methods.Size() > 1)
- return E_INVALIDARG;
- if (_methods.Size() == 1)
- {
- AString &methodName = _methods[0].MethodName;
- if (methodName.IsEmpty())
- methodName = k_LZMA2_Name;
- else if (
- !methodName.IsEqualTo_Ascii_NoCase(k_LZMA2_Name)
- && !methodName.IsEqualTo_Ascii_NoCase("xz"))
- return E_INVALIDARG;
- }
-
- #endif
-
- return S_OK;
-
- COM_TRY_END
-}
-
-
-REGISTER_ARC_IO(
- "xz", "xz txz", "* .tar", 0xC,
- XZ_SIG,
- 0,
- NArcInfoFlags::kKeepName,
- NULL)
-
-}}
+// XzHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/Defs.h"
+#include "../../Common/IntToString.h"
+#include "../../Common/MyBuffer.h"
+#include "../../Common/StringToInt.h"
+
+#include "../../Windows/PropVariant.h"
+#include "../../Windows/System.h"
+
+#include "../Common/CWrappers.h"
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/CopyCoder.h"
+#include "../Compress/XzDecoder.h"
+#include "../Compress/XzEncoder.h"
+
+#include "IArchive.h"
+
+#include "Common/HandlerOut.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NXz {
+
+#define k_LZMA2_Name "LZMA2"
+
+
+struct CBlockInfo
+{
+ unsigned StreamFlags;
+ UInt64 PackPos;
+ UInt64 PackSize; // pure value from Index record, it doesn't include pad zeros
+ UInt64 UnpackPos;
+};
+
+
+Z7_class_CHandler_final:
+ public IInArchive,
+ public IArchiveOpenSeq,
+ public IInArchiveGetStream,
+ public ISetProperties,
+ #ifndef Z7_EXTRACT_ONLY
+ public IOutArchive,
+ #endif
+ public CMyUnknownImp,
+ #ifndef Z7_EXTRACT_ONLY
+ public CMultiMethodProps
+ #else
+ public CCommonMethodProps
+ #endif
+{
+ Z7_COM_QI_BEGIN2(IInArchive)
+ Z7_COM_QI_ENTRY(IArchiveOpenSeq)
+ Z7_COM_QI_ENTRY(IInArchiveGetStream)
+ Z7_COM_QI_ENTRY(ISetProperties)
+ #ifndef Z7_EXTRACT_ONLY
+ Z7_COM_QI_ENTRY(IOutArchive)
+ #endif
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(IInArchive)
+ Z7_IFACE_COM7_IMP(IArchiveOpenSeq)
+ Z7_IFACE_COM7_IMP(IInArchiveGetStream)
+ Z7_IFACE_COM7_IMP(ISetProperties)
+ #ifndef Z7_EXTRACT_ONLY
+ Z7_IFACE_COM7_IMP(IOutArchive)
+ #endif
+
+ CXzStatInfo _stat; // it's stat from backward parsing
+ CXzStatInfo _stat2; // it's data from forward parsing, if the decoder was called
+ SRes _stat2_decode_SRes;
+ bool _stat_defined;
+ bool _stat2_defined;
+
+ const CXzStatInfo *GetStat() const
+ {
+ if (_stat_defined) return &_stat;
+ if (_stat2_defined) return &_stat2;
+ return NULL;
+ }
+
+ bool _isArc;
+ bool _needSeekToStart;
+ bool _firstBlockWasRead;
+
+ AString _methodsString;
+
+
+ #ifndef Z7_EXTRACT_ONLY
+
+ UInt32 _filterId;
+ UInt64 _numSolidBytes;
+
+ void InitXz()
+ {
+ _filterId = 0;
+ _numSolidBytes = XZ_PROPS_BLOCK_SIZE_AUTO;
+ }
+
+ #endif
+
+
+ void Init()
+ {
+ #ifndef Z7_EXTRACT_ONLY
+ InitXz();
+ CMultiMethodProps::Init();
+ #else
+ CCommonMethodProps::InitCommon();
+ #endif
+ }
+
+ HRESULT SetProperty(const wchar_t *name, const PROPVARIANT &value);
+
+ HRESULT Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback);
+
+ HRESULT Decode(NCompress::NXz::CDecoder &decoder,
+ ISequentialInStream *seqInStream,
+ ISequentialOutStream *outStream,
+ ICompressProgressInfo *progress)
+ {
+ #ifndef Z7_ST
+ decoder._numThreads = _numThreads;
+ #endif
+ decoder._memUsage = _memUsage_Decompress;
+
+ HRESULT hres = decoder.Decode(seqInStream, outStream,
+ NULL, // *outSizeLimit
+ true, // finishStream
+ progress);
+
+ if (decoder.MainDecodeSRes_wasUsed
+ && decoder.MainDecodeSRes != SZ_ERROR_MEM
+ && decoder.MainDecodeSRes != SZ_ERROR_UNSUPPORTED)
+ {
+ // if (!_stat2_defined)
+ {
+ _stat2_decode_SRes = decoder.MainDecodeSRes;
+ _stat2 = decoder.Stat;
+ _stat2_defined = true;
+ }
+ }
+
+ return hres;
+ }
+
+public:
+ CBlockInfo *_blocks;
+ size_t _blocksArraySize;
+ UInt64 _maxBlocksSize;
+ CMyComPtr<IInStream> _stream;
+ CMyComPtr<ISequentialInStream> _seqStream;
+
+ CXzBlock _firstBlock;
+
+ CHandler();
+ ~CHandler();
+
+ HRESULT SeekToPackPos(UInt64 pos)
+ {
+ return InStream_SeekSet(_stream, pos);
+ }
+};
+
+
+CHandler::CHandler():
+ _blocks(NULL),
+ _blocksArraySize(0)
+{
+ #ifndef Z7_EXTRACT_ONLY
+ InitXz();
+ #endif
+}
+
+CHandler::~CHandler()
+{
+ MyFree(_blocks);
+}
+
+
+static const Byte kProps[] =
+{
+ kpidSize,
+ kpidPackSize,
+ kpidMethod
+};
+
+static const Byte kArcProps[] =
+{
+ kpidMethod,
+ kpidNumStreams,
+ kpidNumBlocks,
+ kpidClusterSize,
+ kpidCharacts
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+static inline char GetHex(unsigned value)
+{
+ return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
+}
+
+static inline void AddHexToString(AString &s, Byte value)
+{
+ s += GetHex(value >> 4);
+ s += GetHex(value & 0xF);
+}
+
+static void Lzma2PropToString(AString &s, unsigned prop)
+{
+ char c = 0;
+ UInt32 size;
+ if ((prop & 1) == 0)
+ size = prop / 2 + 12;
+ else
+ {
+ c = 'k';
+ size = (UInt32)(2 | (prop & 1)) << (prop / 2 + 1);
+ if (prop > 17)
+ {
+ size >>= 10;
+ c = 'm';
+ }
+ }
+ s.Add_UInt32(size);
+ if (c != 0)
+ s += c;
+}
+
+struct CMethodNamePair
+{
+ UInt32 Id;
+ const char *Name;
+};
+
+static const CMethodNamePair g_NamePairs[] =
+{
+ { XZ_ID_Subblock, "SB" },
+ { XZ_ID_Delta, "Delta" },
+ { XZ_ID_X86, "BCJ" },
+ { XZ_ID_PPC, "PPC" },
+ { XZ_ID_IA64, "IA64" },
+ { XZ_ID_ARM, "ARM" },
+ { XZ_ID_ARMT, "ARMT" },
+ { XZ_ID_SPARC, "SPARC" },
+ { XZ_ID_ARM64, "ARM64" },
+ { XZ_ID_LZMA2, "LZMA2" }
+};
+
+static void AddMethodString(AString &s, const CXzFilter &f)
+{
+ const char *p = NULL;
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_NamePairs); i++)
+ if (g_NamePairs[i].Id == f.id)
+ {
+ p = g_NamePairs[i].Name;
+ break;
+ }
+ char temp[32];
+ if (!p)
+ {
+ ::ConvertUInt64ToString(f.id, temp);
+ p = temp;
+ }
+
+ s += p;
+
+ if (f.propsSize > 0)
+ {
+ s += ':';
+ if (f.id == XZ_ID_LZMA2 && f.propsSize == 1)
+ Lzma2PropToString(s, f.props[0]);
+ else if (f.id == XZ_ID_Delta && f.propsSize == 1)
+ s.Add_UInt32((UInt32)f.props[0] + 1);
+ else if (f.id == XZ_ID_ARM64 && f.propsSize == 1)
+ s.Add_UInt32((UInt32)f.props[0] + 16 + 2);
+ else
+ {
+ s += '[';
+ for (UInt32 bi = 0; bi < f.propsSize; bi++)
+ AddHexToString(s, f.props[bi]);
+ s += ']';
+ }
+ }
+}
+
+static const char * const kChecks[] =
+{
+ "NoCheck"
+ , "CRC32"
+ , NULL
+ , NULL
+ , "CRC64"
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , "SHA256"
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+};
+
+static void AddCheckString(AString &s, const CXzs &xzs)
+{
+ size_t i;
+ UInt32 mask = 0;
+ for (i = 0; i < xzs.num; i++)
+ mask |= ((UInt32)1 << XzFlags_GetCheckType(xzs.streams[i].flags));
+ for (i = 0; i <= XZ_CHECK_MASK; i++)
+ if (((mask >> i) & 1) != 0)
+ {
+ s.Add_Space_if_NotEmpty();
+ if (kChecks[i])
+ s += kChecks[i];
+ else
+ {
+ s += "Check-";
+ s.Add_UInt32((UInt32)i);
+ }
+ }
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ const CXzStatInfo *stat = GetStat();
+
+ switch (propID)
+ {
+ case kpidPhySize: if (stat) prop = stat->InSize; break;
+ case kpidNumStreams: if (stat && stat->NumStreams_Defined) prop = stat->NumStreams; break;
+ case kpidNumBlocks: if (stat && stat->NumBlocks_Defined) prop = stat->NumBlocks; break;
+ case kpidUnpackSize: if (stat && stat->UnpackSize_Defined) prop = stat->OutSize; break;
+ case kpidClusterSize: if (_stat_defined && _stat.NumBlocks_Defined && stat->NumBlocks > 1) prop = _maxBlocksSize; break;
+ case kpidCharacts:
+ if (_firstBlockWasRead)
+ {
+ AString s;
+ if (XzBlock_HasPackSize(&_firstBlock))
+ s.Add_OptSpaced("BlockPackSize");
+ if (XzBlock_HasUnpackSize(&_firstBlock))
+ s.Add_OptSpaced("BlockUnpackSize");
+ if (!s.IsEmpty())
+ prop = s;
+ }
+ break;
+
+
+ case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ SRes sres = _stat2_decode_SRes;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (sres == SZ_ERROR_INPUT_EOF) v |= kpv_ErrorFlags_UnexpectedEnd;
+ if (_stat2_defined && _stat2.DataAfterEnd) v |= kpv_ErrorFlags_DataAfterEnd;
+ if (sres == SZ_ERROR_ARCHIVE) v |= kpv_ErrorFlags_HeadersError;
+ if (sres == SZ_ERROR_UNSUPPORTED) v |= kpv_ErrorFlags_UnsupportedMethod;
+ if (sres == SZ_ERROR_DATA) v |= kpv_ErrorFlags_DataError;
+ if (sres == SZ_ERROR_CRC) v |= kpv_ErrorFlags_CrcError;
+ if (v != 0)
+ prop = v;
+ break;
+ }
+
+ case kpidMainSubfile:
+ {
+ // debug only, comment it:
+ // if (_blocks) prop = (UInt32)0;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ const CXzStatInfo *stat = GetStat();
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidSize: if (stat && stat->UnpackSize_Defined) prop = stat->OutSize; break;
+ case kpidPackSize: if (stat) prop = stat->InSize; break;
+ case kpidMethod: if (!_methodsString.IsEmpty()) prop = _methodsString; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+struct COpenCallbackWrap
+{
+ ICompressProgress vt;
+ IArchiveOpenCallback *OpenCallback;
+ HRESULT Res;
+
+ // new clang shows "non-POD" warning for offsetof(), if we use constructor instead of Init()
+ void Init(IArchiveOpenCallback *progress);
+};
+
+static SRes OpenCallbackProgress(ICompressProgressPtr pp, UInt64 inSize, UInt64 /* outSize */)
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(COpenCallbackWrap)
+ if (p->OpenCallback)
+ p->Res = p->OpenCallback->SetCompleted(NULL, &inSize);
+ return HRESULT_To_SRes(p->Res, SZ_ERROR_PROGRESS);
+}
+
+void COpenCallbackWrap::Init(IArchiveOpenCallback *callback)
+{
+ vt.Progress = OpenCallbackProgress;
+ OpenCallback = callback;
+ Res = SZ_OK;
+}
+
+
+struct CXzsCPP
+{
+ CXzs p;
+ CXzsCPP() { Xzs_Construct(&p); }
+ ~CXzsCPP() { Xzs_Free(&p, &g_Alloc); }
+};
+
+#define kInputBufSize ((size_t)1 << 10)
+
+struct CLookToRead2_CPP: public CLookToRead2
+{
+ CLookToRead2_CPP()
+ {
+ buf = NULL;
+ LookToRead2_CreateVTable(this,
+ True // Lookahead ?
+ );
+ }
+ void Alloc(size_t allocSize)
+ {
+ buf = (Byte *)MyAlloc(allocSize);
+ if (buf)
+ this->bufSize = allocSize;
+ }
+ ~CLookToRead2_CPP()
+ {
+ MyFree(buf);
+ }
+};
+
+
+static HRESULT SRes_to_Open_HRESULT(SRes res)
+{
+ switch (res)
+ {
+ case SZ_OK: return S_OK;
+ case SZ_ERROR_MEM: return E_OUTOFMEMORY;
+ case SZ_ERROR_PROGRESS: return E_ABORT;
+ /*
+ case SZ_ERROR_UNSUPPORTED:
+ case SZ_ERROR_CRC:
+ case SZ_ERROR_DATA:
+ case SZ_ERROR_ARCHIVE:
+ case SZ_ERROR_NO_ARCHIVE:
+ return S_FALSE;
+ */
+ }
+ return S_FALSE;
+}
+
+
+
+HRESULT CHandler::Open2(IInStream *inStream, /* UInt32 flags, */ IArchiveOpenCallback *callback)
+{
+ _needSeekToStart = true;
+
+ {
+ CXzStreamFlags st;
+ CSeqInStreamWrap inStreamWrap;
+
+ inStreamWrap.Init(inStream);
+
+ SRes res = Xz_ReadHeader(&st, &inStreamWrap.vt);
+
+ if (inStreamWrap.Res != S_OK)
+ return inStreamWrap.Res;
+ if (res != SZ_OK)
+ return SRes_to_Open_HRESULT(res);
+
+ {
+ CXzBlock block;
+ BoolInt isIndex;
+ UInt32 headerSizeRes;
+
+ SRes res2 = XzBlock_ReadHeader(&block, &inStreamWrap.vt, &isIndex, &headerSizeRes);
+
+ if (inStreamWrap.Res != S_OK)
+ return inStreamWrap.Res;
+
+ if (res2 != SZ_OK)
+ {
+ if (res2 == SZ_ERROR_INPUT_EOF)
+ {
+ _stat2_decode_SRes = res2;
+ _stream = inStream;
+ _seqStream = inStream;
+ _isArc = true;
+ return S_OK;
+ }
+
+ if (res2 == SZ_ERROR_ARCHIVE)
+ return S_FALSE;
+ }
+ else if (!isIndex)
+ {
+ _firstBlockWasRead = true;
+ _firstBlock = block;
+
+ unsigned numFilters = XzBlock_GetNumFilters(&block);
+ for (unsigned i = 0; i < numFilters; i++)
+ {
+ _methodsString.Add_Space_if_NotEmpty();
+ AddMethodString(_methodsString, block.filters[i]);
+ }
+ }
+ }
+ }
+
+ RINOK(InStream_GetSize_SeekToEnd(inStream, _stat.InSize))
+ if (callback)
+ {
+ RINOK(callback->SetTotal(NULL, &_stat.InSize))
+ }
+
+ CSeekInStreamWrap inStreamImp;
+
+ inStreamImp.Init(inStream);
+
+ CLookToRead2_CPP lookStream;
+
+ lookStream.Alloc(kInputBufSize);
+
+ if (!lookStream.buf)
+ return E_OUTOFMEMORY;
+
+ lookStream.realStream = &inStreamImp.vt;
+ LookToRead2_INIT(&lookStream)
+
+ COpenCallbackWrap openWrap;
+ openWrap.Init(callback);
+
+ CXzsCPP xzs;
+ Int64 startPosition;
+ SRes res = Xzs_ReadBackward(&xzs.p, &lookStream.vt, &startPosition, &openWrap.vt, &g_Alloc);
+ if (res == SZ_ERROR_PROGRESS)
+ return (openWrap.Res == S_OK) ? E_FAIL : openWrap.Res;
+ /*
+ if (res == SZ_ERROR_NO_ARCHIVE && xzs.p.num > 0)
+ res = SZ_OK;
+ */
+ if (res == SZ_OK && startPosition == 0)
+ {
+ _stat_defined = true;
+
+ _stat.OutSize = Xzs_GetUnpackSize(&xzs.p);
+ _stat.UnpackSize_Defined = true;
+
+ _stat.NumStreams = xzs.p.num;
+ _stat.NumStreams_Defined = true;
+
+ _stat.NumBlocks = Xzs_GetNumBlocks(&xzs.p);
+ _stat.NumBlocks_Defined = true;
+
+ AddCheckString(_methodsString, xzs.p);
+
+ const size_t numBlocks = (size_t)_stat.NumBlocks + 1;
+ const size_t bytesAlloc = numBlocks * sizeof(CBlockInfo);
+
+ if (bytesAlloc / sizeof(CBlockInfo) == _stat.NumBlocks + 1)
+ {
+ _blocks = (CBlockInfo *)MyAlloc(bytesAlloc);
+ if (_blocks)
+ {
+ unsigned blockIndex = 0;
+ UInt64 unpackPos = 0;
+
+ for (size_t si = xzs.p.num; si != 0;)
+ {
+ si--;
+ const CXzStream &str = xzs.p.streams[si];
+ UInt64 packPos = str.startOffset + XZ_STREAM_HEADER_SIZE;
+
+ for (size_t bi = 0; bi < str.numBlocks; bi++)
+ {
+ const CXzBlockSizes &bs = str.blocks[bi];
+ const UInt64 packSizeAligned = bs.totalSize + ((0 - (unsigned)bs.totalSize) & 3);
+
+ if (bs.unpackSize != 0)
+ {
+ if (blockIndex >= _stat.NumBlocks)
+ return E_FAIL;
+
+ CBlockInfo &block = _blocks[blockIndex++];
+ block.StreamFlags = str.flags;
+ block.PackSize = bs.totalSize; // packSizeAligned;
+ block.PackPos = packPos;
+ block.UnpackPos = unpackPos;
+ }
+ packPos += packSizeAligned;
+ unpackPos += bs.unpackSize;
+ if (_maxBlocksSize < bs.unpackSize)
+ _maxBlocksSize = bs.unpackSize;
+ }
+ }
+
+ /*
+ if (blockIndex != _stat.NumBlocks)
+ {
+ // there are Empty blocks;
+ }
+ */
+ if (_stat.OutSize != unpackPos)
+ return E_FAIL;
+ CBlockInfo &block = _blocks[blockIndex++];
+ block.StreamFlags = 0;
+ block.PackSize = 0;
+ block.PackPos = 0;
+ block.UnpackPos = unpackPos;
+ _blocksArraySize = blockIndex;
+ }
+ }
+ }
+ else
+ {
+ res = SZ_OK;
+ }
+
+ RINOK(SRes_to_Open_HRESULT(res))
+
+ _stream = inStream;
+ _seqStream = inStream;
+ _isArc = true;
+ return S_OK;
+}
+
+
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *inStream, const UInt64 *, IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ return Open2(inStream, callback);
+ }
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::OpenSeq(ISequentialInStream *stream))
+{
+ Close();
+ _seqStream = stream;
+ _isArc = true;
+ _needSeekToStart = false;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ XzStatInfo_Clear(&_stat);
+ XzStatInfo_Clear(&_stat2);
+ _stat_defined = false;
+ _stat2_defined = false;
+ _stat2_decode_SRes = SZ_OK;
+
+ _isArc = false;
+ _needSeekToStart = false;
+ _firstBlockWasRead = false;
+
+ _methodsString.Empty();
+ _stream.Release();
+ _seqStream.Release();
+
+ MyFree(_blocks);
+ _blocks = NULL;
+ _blocksArraySize = 0;
+ _maxBlocksSize = 0;
+
+ return S_OK;
+}
+
+
+struct CXzUnpackerCPP2
+{
+ Byte *InBuf;
+ // Byte *OutBuf;
+ CXzUnpacker p;
+
+ CXzUnpackerCPP2();
+ ~CXzUnpackerCPP2();
+};
+
+CXzUnpackerCPP2::CXzUnpackerCPP2(): InBuf(NULL)
+ // , OutBuf(NULL)
+{
+ XzUnpacker_Construct(&p, &g_Alloc);
+}
+
+CXzUnpackerCPP2::~CXzUnpackerCPP2()
+{
+ XzUnpacker_Free(&p);
+ MidFree(InBuf);
+ // MidFree(OutBuf);
+}
+
+
+Z7_CLASS_IMP_COM_1(
+ CInStream
+ , IInStream
+)
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+
+ UInt64 _virtPos;
+public:
+ UInt64 Size;
+ UInt64 _cacheStartPos;
+ size_t _cacheSize;
+ CByteBuffer _cache;
+ // UInt64 _startPos;
+ CXzUnpackerCPP2 xz;
+
+ void InitAndSeek()
+ {
+ _virtPos = 0;
+ _cacheStartPos = 0;
+ _cacheSize = 0;
+ // _startPos = startPos;
+ }
+
+ CHandler *_handlerSpec;
+ CMyComPtr<IUnknown> _handler;
+
+ // ~CInStream();
+};
+
+/*
+CInStream::~CInStream()
+{
+ // _cache.Free();
+}
+*/
+
+static size_t FindBlock(const CBlockInfo *blocks, size_t numBlocks, UInt64 pos)
+{
+ size_t left = 0, right = numBlocks;
+ for (;;)
+ {
+ size_t mid = (left + right) / 2;
+ if (mid == left)
+ return left;
+ if (pos < blocks[mid].UnpackPos)
+ right = mid;
+ else
+ left = mid;
+ }
+}
+
+
+
+static HRESULT DecodeBlock(CXzUnpackerCPP2 &xzu,
+ ISequentialInStream *seqInStream,
+ unsigned streamFlags,
+ UInt64 packSize, // pure size from Index record, it doesn't include pad zeros
+ size_t unpackSize, Byte *dest
+ // , ICompressProgressInfo *progress
+ )
+{
+ const size_t kInBufSize = (size_t)1 << 16;
+
+ XzUnpacker_Init(&xzu.p);
+
+ if (!xzu.InBuf)
+ {
+ xzu.InBuf = (Byte *)MidAlloc(kInBufSize);
+ if (!xzu.InBuf)
+ return E_OUTOFMEMORY;
+ }
+
+ xzu.p.streamFlags = (UInt16)streamFlags;
+ XzUnpacker_PrepareToRandomBlockDecoding(&xzu.p);
+
+ XzUnpacker_SetOutBuf(&xzu.p, dest, unpackSize);
+
+ const UInt64 packSizeAligned = packSize + ((0 - (unsigned)packSize) & 3);
+ UInt64 packRem = packSizeAligned;
+
+ UInt32 inSize = 0;
+ SizeT inPos = 0;
+ SizeT outPos = 0;
+
+ HRESULT readRes = S_OK;
+
+ for (;;)
+ {
+ if (inPos == inSize && readRes == S_OK)
+ {
+ inPos = 0;
+ inSize = 0;
+ UInt32 rem = kInBufSize;
+ if (rem > packRem)
+ rem = (UInt32)packRem;
+ if (rem != 0)
+ readRes = seqInStream->Read(xzu.InBuf, rem, &inSize);
+ }
+
+ SizeT inLen = inSize - inPos;
+ SizeT outLen = unpackSize - outPos;
+
+ ECoderStatus status;
+
+ const SRes res = XzUnpacker_Code(&xzu.p,
+ // dest + outPos,
+ NULL,
+ &outLen,
+ xzu.InBuf + inPos, &inLen,
+ (inLen == 0), // srcFinished
+ CODER_FINISH_END, &status);
+
+ // return E_OUTOFMEMORY;
+ // res = SZ_ERROR_CRC;
+
+ if (res != SZ_OK)
+ {
+ if (res == SZ_ERROR_CRC)
+ return S_FALSE;
+ return SResToHRESULT(res);
+ }
+
+ inPos += inLen;
+ outPos += outLen;
+
+ packRem -= inLen;
+
+ const BoolInt blockFinished = XzUnpacker_IsBlockFinished(&xzu.p);
+
+ if ((inLen == 0 && outLen == 0) || blockFinished)
+ {
+ if (packRem != 0 || !blockFinished || unpackSize != outPos)
+ return S_FALSE;
+ if (XzUnpacker_GetPackSizeForIndex(&xzu.p) != packSize)
+ return S_FALSE;
+ return S_OK;
+ }
+ }
+}
+
+
+Z7_COM7F_IMF(CInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ COM_TRY_BEGIN
+
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+
+ {
+ if (_virtPos >= Size)
+ return S_OK; // (Size == _virtPos) ? S_OK: E_FAIL;
+ {
+ UInt64 rem = Size - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+ }
+
+ if (size == 0)
+ return S_OK;
+
+ if (_virtPos < _cacheStartPos || _virtPos >= _cacheStartPos + _cacheSize)
+ {
+ const size_t bi = FindBlock(_handlerSpec->_blocks, _handlerSpec->_blocksArraySize, _virtPos);
+ const CBlockInfo &block = _handlerSpec->_blocks[bi];
+ const UInt64 unpackSize = _handlerSpec->_blocks[bi + 1].UnpackPos - block.UnpackPos;
+ if (_cache.Size() < unpackSize)
+ return E_FAIL;
+
+ _cacheSize = 0;
+
+ RINOK(_handlerSpec->SeekToPackPos(block.PackPos))
+ RINOK(DecodeBlock(xz, _handlerSpec->_seqStream, block.StreamFlags, block.PackSize,
+ (size_t)unpackSize, _cache))
+ _cacheStartPos = block.UnpackPos;
+ _cacheSize = (size_t)unpackSize;
+ }
+
+ {
+ const size_t offset = (size_t)(_virtPos - _cacheStartPos);
+ const size_t rem = _cacheSize - offset;
+ if (size > rem)
+ size = (UInt32)rem;
+ memcpy(data, _cache + offset, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ }
+
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += Size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _virtPos = (UInt64)offset;
+ if (newPosition)
+ *newPosition = (UInt64)offset;
+ return S_OK;
+}
+
+
+
+static const UInt64 kMaxBlockSize_for_GetStream = (UInt64)1 << 40;
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+
+ *stream = NULL;
+
+ if (index != 0)
+ return E_INVALIDARG;
+
+ if (!_stat.UnpackSize_Defined
+ || _maxBlocksSize == 0 // 18.02
+ || _maxBlocksSize > kMaxBlockSize_for_GetStream
+ || _maxBlocksSize != (size_t)_maxBlocksSize)
+ return S_FALSE;
+
+ UInt64 memSize;
+ if (!NSystem::GetRamSize(memSize))
+ memSize = (UInt64)(sizeof(size_t)) << 28;
+ {
+ if (_maxBlocksSize > memSize / 4)
+ return S_FALSE;
+ }
+
+ CInStream *spec = new CInStream;
+ CMyComPtr<ISequentialInStream> specStream = spec;
+ spec->_cache.Alloc((size_t)_maxBlocksSize);
+ spec->_handlerSpec = this;
+ spec->_handler = (IInArchive *)this;
+ spec->Size = _stat.OutSize;
+ spec->InitAndSeek();
+
+ *stream = specStream.Detach();
+ return S_OK;
+
+ COM_TRY_END
+}
+
+
+static Int32 Get_Extract_OperationResult(const NCompress::NXz::CDecoder &decoder)
+{
+ Int32 opRes;
+ SRes sres = decoder.MainDecodeSRes;
+ if (sres == SZ_ERROR_NO_ARCHIVE) // (!IsArc)
+ opRes = NExtract::NOperationResult::kIsNotArc;
+ else if (sres == SZ_ERROR_INPUT_EOF) // (UnexpectedEnd)
+ opRes = NExtract::NOperationResult::kUnexpectedEnd;
+ else if (decoder.Stat.DataAfterEnd)
+ opRes = NExtract::NOperationResult::kDataAfterEnd;
+ else if (sres == SZ_ERROR_CRC) // (CrcError)
+ opRes = NExtract::NOperationResult::kCRCError;
+ else if (sres == SZ_ERROR_UNSUPPORTED) // (Unsupported)
+ opRes = NExtract::NOperationResult::kUnsupportedMethod;
+ else if (sres == SZ_ERROR_ARCHIVE) // (HeadersError)
+ opRes = NExtract::NOperationResult::kDataError;
+ else if (sres == SZ_ERROR_DATA) // (DataError)
+ opRes = NExtract::NOperationResult::kDataError;
+ else if (sres != SZ_OK)
+ opRes = NExtract::NOperationResult::kDataError;
+ else
+ opRes = NExtract::NOperationResult::kOK;
+ return opRes;
+}
+
+
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ const CXzStatInfo *stat = GetStat();
+
+ if (stat)
+ extractCallback->SetTotal(stat->InSize);
+
+ UInt64 currentTotalPacked = 0;
+ RINOK(extractCallback->SetCompleted(&currentTotalPacked))
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode))
+
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> lpsRef = lps;
+ lps->Init(extractCallback, true);
+
+ if (_needSeekToStart)
+ {
+ if (!_stream)
+ return E_FAIL;
+ RINOK(InStream_SeekToBegin(_stream))
+ }
+ else
+ _needSeekToStart = true;
+
+
+ NCompress::NXz::CDecoder decoder;
+
+ HRESULT hres = Decode(decoder, _seqStream, realOutStream, lpsRef);
+
+ if (!decoder.MainDecodeSRes_wasUsed)
+ return hres == S_OK ? E_FAIL : hres;
+
+ Int32 opRes = Get_Extract_OperationResult(decoder);
+ if (opRes == NExtract::NOperationResult::kOK
+ && hres != S_OK)
+ opRes = NExtract::NOperationResult::kDataError;
+
+ realOutStream.Release();
+ return extractCallback->SetOperationResult(opRes);
+ COM_TRY_END
+}
+
+
+
+#ifndef Z7_EXTRACT_ONLY
+
+Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType))
+{
+ *timeType = GET_FileTimeType_NotDefined_for_GetFileTimeType;
+ // *timeType = NFileTimeType::kUnix;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *updateCallback))
+{
+ COM_TRY_BEGIN
+
+ if (numItems == 0)
+ {
+ CSeqOutStreamWrap seqOutStream;
+ seqOutStream.Init(outStream);
+ SRes res = Xz_EncodeEmpty(&seqOutStream.vt);
+ return SResToHRESULT(res);
+ }
+
+ if (numItems != 1)
+ return E_INVALIDARG;
+
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IStreamSetRestriction,
+ setRestriction, outStream)
+ if (setRestriction)
+ RINOK(setRestriction->SetRestriction(0, 0))
+ }
+
+ Int32 newData, newProps;
+ UInt32 indexInArchive;
+ if (!updateCallback)
+ return E_FAIL;
+ RINOK(updateCallback->GetUpdateItemInfo(0, &newData, &newProps, &indexInArchive))
+
+ if (IntToBool(newProps))
+ {
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidIsDir, &prop))
+ if (prop.vt != VT_EMPTY)
+ if (prop.vt != VT_BOOL || prop.boolVal != VARIANT_FALSE)
+ return E_INVALIDARG;
+ }
+ }
+
+ if (IntToBool(newData))
+ {
+ UInt64 dataSize;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(updateCallback->GetProperty(0, kpidSize, &prop))
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ dataSize = prop.uhVal.QuadPart;
+ }
+
+ NCompress::NXz::CEncoder *encoderSpec = new NCompress::NXz::CEncoder;
+ CMyComPtr<ICompressCoder> encoder = encoderSpec;
+
+ CXzProps &xzProps = encoderSpec->xzProps;
+ CLzma2EncProps &lzma2Props = xzProps.lzma2Props;
+
+ lzma2Props.lzmaProps.level = GetLevel();
+
+ xzProps.reduceSize = dataSize;
+ /*
+ {
+ NCOM::CPropVariant prop = (UInt64)dataSize;
+ RINOK(encoderSpec->SetCoderProp(NCoderPropID::kReduceSize, prop))
+ }
+ */
+
+ #ifndef Z7_ST
+
+ UInt32 numThreads = _numThreads;
+
+ const UInt32 kNumThreads_Max = 1024;
+ if (numThreads > kNumThreads_Max)
+ numThreads = kNumThreads_Max;
+
+ if (!_numThreads_WasForced
+ && _numThreads >= 1
+ && _memUsage_WasSet)
+ {
+ COneMethodInfo oneMethodInfo;
+ if (!_methods.IsEmpty())
+ oneMethodInfo = _methods[0];
+
+ SetGlobalLevelTo(oneMethodInfo);
+
+ const bool numThreads_WasSpecifiedInMethod = (oneMethodInfo.Get_NumThreads() >= 0);
+ if (!numThreads_WasSpecifiedInMethod)
+ {
+ // here we set the (NCoderPropID::kNumThreads) property in each method, only if there is no such property already
+ CMultiMethodProps::SetMethodThreadsTo_IfNotFinded(oneMethodInfo, numThreads);
+ }
+
+ UInt64 cs = _numSolidBytes;
+ if (cs != XZ_PROPS_BLOCK_SIZE_AUTO)
+ oneMethodInfo.AddProp_BlockSize2(cs);
+ cs = oneMethodInfo.Get_Xz_BlockSize();
+
+ if (cs != XZ_PROPS_BLOCK_SIZE_AUTO &&
+ cs != XZ_PROPS_BLOCK_SIZE_SOLID)
+ {
+ const UInt32 lzmaThreads = oneMethodInfo.Get_Lzma_NumThreads();
+ const UInt32 numBlockThreads_Original = numThreads / lzmaThreads;
+
+ if (numBlockThreads_Original > 1)
+ {
+ UInt32 numBlockThreads = numBlockThreads_Original;
+ {
+ const UInt64 lzmaMemUsage = oneMethodInfo.Get_Lzma_MemUsage(false);
+ for (; numBlockThreads > 1; numBlockThreads--)
+ {
+ UInt64 size = numBlockThreads * (lzmaMemUsage + cs);
+ UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1;
+ if (cs < ((UInt32)1 << 26)) numPackChunks++;
+ if (cs < ((UInt32)1 << 24)) numPackChunks++;
+ if (cs < ((UInt32)1 << 22)) numPackChunks++;
+ size += numPackChunks * cs;
+ // printf("\nnumBlockThreads = %d, size = %d\n", (unsigned)(numBlockThreads), (unsigned)(size >> 20));
+ if (size <= _memUsage_Compress)
+ break;
+ }
+ }
+ if (numBlockThreads == 0)
+ numBlockThreads = 1;
+ if (numBlockThreads != numBlockThreads_Original)
+ numThreads = numBlockThreads * lzmaThreads;
+ }
+ }
+ }
+ xzProps.numTotalThreads = (int)numThreads;
+
+ #endif // Z7_ST
+
+
+ xzProps.blockSize = _numSolidBytes;
+ if (_numSolidBytes == XZ_PROPS_BLOCK_SIZE_SOLID)
+ {
+ xzProps.lzma2Props.blockSize = LZMA2_ENC_PROPS_BLOCK_SIZE_SOLID;
+ }
+
+ RINOK(encoderSpec->SetCheckSize(_crcSize))
+
+ {
+ CXzFilterProps &filter = xzProps.filterProps;
+
+ if (_filterId == XZ_ID_Delta)
+ {
+ bool deltaDefined = false;
+ FOR_VECTOR (j, _filterMethod.Props)
+ {
+ const CProp &prop = _filterMethod.Props[j];
+ if (prop.Id == NCoderPropID::kDefaultProp && prop.Value.vt == VT_UI4)
+ {
+ UInt32 delta = (UInt32)prop.Value.ulVal;
+ if (delta < 1 || delta > 256)
+ return E_INVALIDARG;
+ filter.delta = delta;
+ deltaDefined = true;
+ }
+ else
+ return E_INVALIDARG;
+ }
+ if (!deltaDefined)
+ return E_INVALIDARG;
+ }
+ filter.id = _filterId;
+ }
+
+ FOR_VECTOR (i, _methods)
+ {
+ COneMethodInfo &m = _methods[i];
+
+ FOR_VECTOR (j, m.Props)
+ {
+ const CProp &prop = m.Props[j];
+ RINOK(encoderSpec->SetCoderProp(prop.Id, prop.Value))
+ }
+ }
+
+ {
+ CMyComPtr<ISequentialInStream> fileInStream;
+ RINOK(updateCallback->GetStream(0, &fileInStream))
+ if (!fileInStream)
+ return S_FALSE;
+ {
+ CMyComPtr<IStreamGetSize> streamGetSize;
+ fileInStream.QueryInterface(IID_IStreamGetSize, &streamGetSize);
+ if (streamGetSize)
+ {
+ UInt64 size;
+ if (streamGetSize->GetSize(&size) == S_OK)
+ dataSize = size;
+ }
+ }
+ RINOK(updateCallback->SetTotal(dataSize))
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+ RINOK(encoder->Code(fileInStream, outStream, NULL, NULL, progress))
+ }
+
+ return updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK);
+ }
+
+ if (indexInArchive != 0)
+ return E_INVALIDARG;
+
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IArchiveUpdateCallbackFile,
+ opCallback, updateCallback)
+ if (opCallback)
+ {
+ RINOK(opCallback->ReportOperation(NEventIndexType::kInArcIndex, 0, NUpdateNotifyOp::kReplicate))
+ }
+
+ if (_stream)
+ {
+ const CXzStatInfo *stat = GetStat();
+ if (stat)
+ {
+ RINOK(updateCallback->SetTotal(stat->InSize))
+ }
+ RINOK(InStream_SeekToBegin(_stream))
+ }
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ return NCompress::CopyStream(_stream, outStream, progress);
+
+ COM_TRY_END
+}
+
+#endif
+
+
+HRESULT CHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
+{
+ UString name = nameSpec;
+ name.MakeLower_Ascii();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+
+ #ifndef Z7_EXTRACT_ONLY
+
+ if (name[0] == L's')
+ {
+ const wchar_t *s = name.Ptr(1);
+ if (*s == 0)
+ {
+ bool useStr = false;
+ bool isSolid;
+ switch (value.vt)
+ {
+ case VT_EMPTY: isSolid = true; break;
+ case VT_BOOL: isSolid = (value.boolVal != VARIANT_FALSE); break;
+ case VT_BSTR:
+ if (!StringToBool(value.bstrVal, isSolid))
+ useStr = true;
+ break;
+ default: return E_INVALIDARG;
+ }
+ if (!useStr)
+ {
+ _numSolidBytes = (isSolid ? XZ_PROPS_BLOCK_SIZE_SOLID : XZ_PROPS_BLOCK_SIZE_AUTO);
+ return S_OK;
+ }
+ }
+ return ParseSizeString(s, value,
+ 0, // percentsBase
+ _numSolidBytes) ? S_OK: E_INVALIDARG;
+ }
+
+ return CMultiMethodProps::SetProperty(name, value);
+
+ #else
+
+ {
+ HRESULT hres;
+ if (SetCommonProperty(name, value, hres))
+ return hres;
+ }
+
+ return E_INVALIDARG;
+
+ #endif
+}
+
+
+
+Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
+{
+ COM_TRY_BEGIN
+
+ Init();
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ RINOK(SetProperty(names[i], values[i]))
+ }
+
+ #ifndef Z7_EXTRACT_ONLY
+
+ if (!_filterMethod.MethodName.IsEmpty())
+ {
+ unsigned k;
+ for (k = 0; k < Z7_ARRAY_SIZE(g_NamePairs); k++)
+ {
+ const CMethodNamePair &pair = g_NamePairs[k];
+ if (StringsAreEqualNoCase_Ascii(_filterMethod.MethodName, pair.Name))
+ {
+ _filterId = pair.Id;
+ break;
+ }
+ }
+ if (k == Z7_ARRAY_SIZE(g_NamePairs))
+ return E_INVALIDARG;
+ }
+
+ _methods.DeleteFrontal(GetNumEmptyMethods());
+ if (_methods.Size() > 1)
+ return E_INVALIDARG;
+ if (_methods.Size() == 1)
+ {
+ AString &methodName = _methods[0].MethodName;
+ if (methodName.IsEmpty())
+ methodName = k_LZMA2_Name;
+ else if (
+ !methodName.IsEqualTo_Ascii_NoCase(k_LZMA2_Name)
+ && !methodName.IsEqualTo_Ascii_NoCase("xz"))
+ return E_INVALIDARG;
+ }
+
+ #endif
+
+ return S_OK;
+
+ COM_TRY_END
+}
+
+
+REGISTER_ARC_IO(
+ "xz", "xz txz", "* .tar", 0xC,
+ XZ_SIG, 0
+ , NArcInfoFlags::kKeepName
+ , 0
+ , NULL)
+
+}}
diff --git a/CPP/7zip/Archive/XzHandler.h b/CPP/7zip/Archive/XzHandler.h
index 18633fb..4d09954 100644
--- a/CPP/7zip/Archive/XzHandler.h
+++ b/CPP/7zip/Archive/XzHandler.h
@@ -1,11 +1,11 @@
-// XzHandler.h
-
-#ifndef __XZ_HANDLER_H
-#define __XZ_HANDLER_H
-
-namespace NArchive {
-namespace NXz {
-
-}}
-
-#endif
+// XzHandler.h
+
+#ifndef ZIP7_INC_XZ_HANDLER_H
+#define ZIP7_INC_XZ_HANDLER_H
+
+namespace NArchive {
+namespace NXz {
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/ZHandler.cpp b/CPP/7zip/Archive/ZHandler.cpp
new file mode 100644
index 0000000..18e712a
--- /dev/null
+++ b/CPP/7zip/Archive/ZHandler.cpp
@@ -0,0 +1,230 @@
+// ZHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/ComTry.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../Common/ProgressUtils.h"
+#include "../Common/RegisterArc.h"
+#include "../Common/StreamUtils.h"
+
+#include "../Compress/ZDecoder.h"
+
+#include "Common/DummyOutStream.h"
+
+namespace NArchive {
+namespace NZ {
+
+Z7_CLASS_IMP_CHandler_IInArchive_0
+
+ CMyComPtr<IInStream> _stream;
+ UInt64 _packSize;
+ // UInt64 _unpackSize;
+ // bool _unpackSize_Defined;
+};
+
+static const Byte kProps[] =
+{
+ kpidPackSize
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO_Table
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = 1;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySizeCantBeDetected: prop = true; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
+{
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ // case kpidSize: if (_unpackSize_Defined) prop = _unpackSize; break;
+ case kpidPackSize: prop = _packSize; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+/*
+Z7_CLASS_IMP_COM_1(
+ CCompressProgressInfoImp
+ , ICompressProgressInfo
+)
+ CMyComPtr<IArchiveOpenCallback> Callback;
+public:
+ void Init(IArchiveOpenCallback *callback) { Callback = callback; }
+};
+
+Z7_COM7F_IMF(CCompressProgressInfoImp::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
+{
+ outSize = outSize;
+ if (Callback)
+ {
+ const UInt64 files = 1;
+ return Callback->SetCompleted(&files, inSize);
+ }
+ return S_OK;
+}
+*/
+
+API_FUNC_static_IsArc IsArc_Z(const Byte *p, size_t size)
+{
+ if (size < 3)
+ return k_IsArc_Res_NEED_MORE;
+ if (size > NCompress::NZ::kRecommendedCheckSize)
+ size = NCompress::NZ::kRecommendedCheckSize;
+ if (!NCompress::NZ::CheckStream(p, size))
+ return k_IsArc_Res_NO;
+ return k_IsArc_Res_YES;
+}
+}
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
+ const UInt64 * /* maxCheckStartPosition */,
+ IArchiveOpenCallback * /* openCallback */))
+{
+ COM_TRY_BEGIN
+ {
+ // RINOK(InStream_GetPos(stream, _streamStartPosition));
+ Byte buffer[NCompress::NZ::kRecommendedCheckSize];
+ // Byte buffer[1500];
+ size_t size = NCompress::NZ::kRecommendedCheckSize;
+ // size = 700;
+ RINOK(ReadStream(stream, buffer, &size))
+ if (!NCompress::NZ::CheckStream(buffer, size))
+ return S_FALSE;
+
+ UInt64 endPos;
+ RINOK(InStream_GetSize_SeekToEnd(stream, endPos))
+ _packSize = endPos;
+
+ /*
+ bool fullCheck = false;
+ if (fullCheck)
+ {
+ CCompressProgressInfoImp *compressProgressSpec = new CCompressProgressInfoImp;
+ CMyComPtr<ICompressProgressInfo> compressProgress = compressProgressSpec;
+ compressProgressSpec->Init(openCallback);
+
+ NCompress::NZ::CDecoder *decoderSpec = new NCompress::NZ::CDecoder;
+ CMyComPtr<ICompressCoder> decoder = decoderSpec;
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(NULL);
+ outStreamSpec->Init();
+ decoderSpec->SetProp(_prop);
+ if (openCallback)
+ {
+ UInt64 files = 1;
+ RINOK(openCallback->SetTotal(&files, &endPos));
+ }
+ RINOK(InStream_SeekSet(stream, _streamStartPosition + kSignatureSize))
+ HRESULT res = decoder->Code(stream, outStream, NULL, NULL, openCallback ? compressProgress : NULL);
+ if (res != S_OK)
+ return S_FALSE;
+ _packSize = decoderSpec->PackSize;
+ }
+ */
+ _stream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _packSize = 0;
+ // _unpackSize_Defined = false;
+ _stream.Release();
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ if (numItems == 0)
+ return S_OK;
+ if (numItems != (UInt32)(Int32)-1 && (numItems != 1 || indices[0] != 0))
+ return E_INVALIDARG;
+
+ extractCallback->SetTotal(_packSize);
+
+ UInt64 currentTotalPacked = 0;
+
+ RINOK(extractCallback->SetCompleted(&currentTotalPacked))
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+
+ RINOK(extractCallback->GetStream(0, &realOutStream, askMode))
+
+ if (!testMode && !realOutStream)
+ return S_OK;
+
+ extractCallback->PrepareOperation(askMode);
+
+ CDummyOutStream *outStreamSpec = new CDummyOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init();
+ realOutStream.Release();
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, true);
+
+ RINOK(InStream_SeekToBegin(_stream))
+
+ NCompress::NZ::CDecoder *decoderSpec = new NCompress::NZ::CDecoder;
+ CMyComPtr<ICompressCoder> decoder = decoderSpec;
+
+ int opRes;
+ {
+ HRESULT result = decoder->Code(_stream, outStream, NULL, NULL, progress);
+ if (result == S_FALSE)
+ opRes = NExtract::NOperationResult::kDataError;
+ else
+ {
+ RINOK(result)
+ opRes = NExtract::NOperationResult::kOK;
+ }
+ }
+ // _unpackSize = outStreamSpec->GetSize();
+ // _unpackSize_Defined = true;
+ outStream.Release();
+ return extractCallback->SetOperationResult(opRes);
+ COM_TRY_END
+}
+
+static const Byte k_Signature[] = { 0x1F, 0x9D };
+
+REGISTER_ARC_I(
+ "Z", "z taz", "* .tar", 5,
+ k_Signature,
+ 0,
+ 0,
+ IsArc_Z)
+
+}}
diff --git a/CPP/7zip/Archive/Zip/StdAfx.h b/CPP/7zip/Archive/Zip/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/StdAfx.h
@@ -0,0 +1,11 @@
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.cpp b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
new file mode 100644
index 0000000..8af84b4
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipAddCommon.cpp
@@ -0,0 +1,499 @@
+// ZipAddCommon.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/7zCrc.h"
+#include "../../../../C/Alloc.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#include "../../ICoder.h"
+#include "../../IPassword.h"
+#include "../../MyVersion.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/LzmaEncoder.h"
+#include "../../Compress/PpmdZip.h"
+#include "../../Compress/XzEncoder.h"
+
+#include "../Common/InStreamWithCRC.h"
+
+#include "ZipAddCommon.h"
+#include "ZipHeader.h"
+
+namespace NArchive {
+namespace NZip {
+
+using namespace NFileHeader;
+
+
+static const unsigned kLzmaPropsSize = 5;
+static const unsigned kLzmaHeaderSize = 4 + kLzmaPropsSize;
+
+Z7_CLASS_IMP_NOQIB_3(
+ CLzmaEncoder
+ , ICompressCoder
+ , ICompressSetCoderProperties
+ , ICompressSetCoderPropertiesOpt
+)
+public:
+ NCompress::NLzma::CEncoder *EncoderSpec;
+ CMyComPtr<ICompressCoder> Encoder;
+ Byte Header[kLzmaHeaderSize];
+};
+
+Z7_COM7F_IMF(CLzmaEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps))
+{
+ if (!Encoder)
+ {
+ EncoderSpec = new NCompress::NLzma::CEncoder;
+ Encoder = EncoderSpec;
+ }
+ CBufPtrSeqOutStream *outStreamSpec = new CBufPtrSeqOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+ outStreamSpec->Init(Header + 4, kLzmaPropsSize);
+ RINOK(EncoderSpec->SetCoderProperties(propIDs, props, numProps))
+ RINOK(EncoderSpec->WriteCoderProperties(outStream))
+ if (outStreamSpec->GetPos() != kLzmaPropsSize)
+ return E_FAIL;
+ Header[0] = MY_VER_MAJOR;
+ Header[1] = MY_VER_MINOR;
+ Header[2] = kLzmaPropsSize;
+ Header[3] = 0;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CLzmaEncoder::SetCoderPropertiesOpt(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps))
+{
+ return EncoderSpec->SetCoderPropertiesOpt(propIDs, props, numProps);
+}
+
+Z7_COM7F_IMF(CLzmaEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ RINOK(WriteStream(outStream, Header, kLzmaHeaderSize))
+ return Encoder->Code(inStream, outStream, inSize, outSize, progress);
+}
+
+
+CAddCommon::CAddCommon():
+ _copyCoderSpec(NULL),
+ _isLzmaEos(false),
+ _cryptoStreamSpec(NULL),
+ _buf(NULL)
+ {}
+
+void CAddCommon::SetOptions(const CCompressionMethodMode &options)
+{
+ _options = options;
+}
+
+CAddCommon::~CAddCommon()
+{
+ MidFree(_buf);
+}
+
+static const UInt32 kBufSize = ((UInt32)1 << 16);
+
+HRESULT CAddCommon::CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC)
+{
+ if (!_buf)
+ {
+ _buf = (Byte *)MidAlloc(kBufSize);
+ if (!_buf)
+ return E_OUTOFMEMORY;
+ }
+
+ UInt32 crc = CRC_INIT_VAL;
+ for (;;)
+ {
+ UInt32 processed;
+ RINOK(inStream->Read(_buf, kBufSize, &processed))
+ if (processed == 0)
+ {
+ resultCRC = CRC_GET_DIGEST(crc);
+ return S_OK;
+ }
+ crc = CrcUpdate(crc, _buf, (size_t)processed);
+ }
+}
+
+
+HRESULT CAddCommon::Set_Pre_CompressionResult(bool inSeqMode, bool outSeqMode, UInt64 unpackSize,
+ CCompressingResult &opRes) const
+{
+ // We use Zip64, if unPackSize size is larger than 0xF8000000 to support
+ // cases when compressed size can be about 3% larger than uncompressed size
+
+ const UInt32 kUnpackZip64Limit = 0xF8000000;
+
+ opRes.UnpackSize = unpackSize;
+ opRes.PackSize = (UInt64)1 << 60; // we use big value to force Zip64 mode.
+
+ if (unpackSize < kUnpackZip64Limit)
+ opRes.PackSize = (UInt32)0xFFFFFFFF - 1; // it will not use Zip64 for that size
+
+ if (opRes.PackSize < unpackSize)
+ opRes.PackSize = unpackSize;
+
+ const Byte method = _options.MethodSequence[0];
+
+ if (method == NCompressionMethod::kStore && !_options.Password_Defined)
+ opRes.PackSize = unpackSize;
+
+ opRes.CRC = 0;
+
+ opRes.LzmaEos = false;
+
+ opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default;
+ opRes.DescriptorMode = outSeqMode;
+
+ if (_options.Password_Defined)
+ {
+ opRes.ExtractVersion = NCompressionMethod::kExtractVersion_ZipCrypto;
+ if (_options.IsAesMode)
+ opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Aes;
+ else
+ {
+ if (inSeqMode)
+ opRes.DescriptorMode = true;
+ }
+ }
+
+ opRes.Method = method;
+ Byte ver = 0;
+
+ switch (method)
+ {
+ case NCompressionMethod::kStore: break;
+ case NCompressionMethod::kDeflate: ver = NCompressionMethod::kExtractVersion_Deflate; break;
+ case NCompressionMethod::kDeflate64: ver = NCompressionMethod::kExtractVersion_Deflate64; break;
+ case NCompressionMethod::kXz : ver = NCompressionMethod::kExtractVersion_Xz; break;
+ case NCompressionMethod::kPPMd : ver = NCompressionMethod::kExtractVersion_PPMd; break;
+ case NCompressionMethod::kBZip2: ver = NCompressionMethod::kExtractVersion_BZip2; break;
+ case NCompressionMethod::kLZMA :
+ {
+ ver = NCompressionMethod::kExtractVersion_LZMA;
+ const COneMethodInfo *oneMethodMain = &_options._methods[0];
+ opRes.LzmaEos = oneMethodMain->Get_Lzma_Eos();
+ break;
+ }
+ }
+ if (opRes.ExtractVersion < ver)
+ opRes.ExtractVersion = ver;
+
+ return S_OK;
+}
+
+
+HRESULT CAddCommon::Compress(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ ISequentialInStream *inStream, IOutStream *outStream,
+ bool inSeqMode, bool outSeqMode,
+ UInt32 fileTime,
+ UInt64 expectedDataSize, bool expectedDataSize_IsConfirmed,
+ ICompressProgressInfo *progress, CCompressingResult &opRes)
+{
+ // opRes.LzmaEos = false;
+
+ if (!inStream)
+ {
+ // We can create empty stream here. But it was already implemented in caller code in 9.33+
+ return E_INVALIDARG;
+ }
+
+ CSequentialInStreamWithCRC *inSecCrcStreamSpec = new CSequentialInStreamWithCRC;
+ CMyComPtr<ISequentialInStream> inCrcStream = inSecCrcStreamSpec;
+
+ CMyComPtr<IInStream> inStream2;
+ if (!inSeqMode)
+ {
+ inStream->QueryInterface(IID_IInStream, (void **)&inStream2);
+ if (!inStream2)
+ {
+ // inSeqMode = true;
+ // inSeqMode must be correct before
+ return E_FAIL;
+ }
+ }
+
+ inSecCrcStreamSpec->SetStream(inStream);
+ inSecCrcStreamSpec->SetFullSize(expectedDataSize_IsConfirmed ? expectedDataSize : (UInt64)(Int64)-1);
+ // inSecCrcStreamSpec->Init();
+
+ unsigned numTestMethods = _options.MethodSequence.Size();
+ // numTestMethods != 0
+
+ bool descriptorMode = outSeqMode;
+
+ // ZipCrypto without descriptor requires additional reading pass for
+ // inStream to calculate CRC for password check field.
+ // The descriptor allows to use ZipCrypto check field without CRC (InfoZip's modification).
+
+ if (!outSeqMode)
+ if (inSeqMode && _options.Password_Defined && !_options.IsAesMode)
+ descriptorMode = true;
+ opRes.DescriptorMode = descriptorMode;
+
+ if (numTestMethods > 1)
+ if (inSeqMode || outSeqMode || !inStream2)
+ numTestMethods = 1;
+
+ UInt32 crc = 0;
+ bool crc_IsCalculated = false;
+
+ CFilterCoder::C_OutStream_Releaser outStreamReleaser;
+ // opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default;
+
+ for (unsigned i = 0; i < numTestMethods; i++)
+ {
+ inSecCrcStreamSpec->Init();
+
+ if (i != 0)
+ {
+ // if (inStream2)
+ {
+ RINOK(InStream_SeekToBegin(inStream2))
+ }
+ RINOK(outStream->Seek(0, STREAM_SEEK_SET, NULL))
+ RINOK(outStream->SetSize(0))
+ }
+
+ opRes.LzmaEos = false;
+ opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Default;
+
+ const Byte method = _options.MethodSequence[i];
+ if (method == NCompressionMethod::kStore && descriptorMode)
+ {
+ // we still can create descriptor_mode archives with "Store" method, but they are not good for 100%
+ return E_NOTIMPL;
+ }
+
+ bool needCode = true;
+
+ if (_options.Password_Defined)
+ {
+ opRes.ExtractVersion = NCompressionMethod::kExtractVersion_ZipCrypto;
+
+ if (!_cryptoStream)
+ {
+ _cryptoStreamSpec = new CFilterCoder(true);
+ _cryptoStream = _cryptoStreamSpec;
+ }
+
+ if (_options.IsAesMode)
+ {
+ opRes.ExtractVersion = NCompressionMethod::kExtractVersion_Aes;
+ if (!_cryptoStreamSpec->Filter)
+ {
+ _cryptoStreamSpec->Filter = _filterAesSpec = new NCrypto::NWzAes::CEncoder;
+ _filterAesSpec->SetKeyMode(_options.AesKeyMode);
+ RINOK(_filterAesSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Len()))
+ }
+ RINOK(_filterAesSpec->WriteHeader(outStream))
+ }
+ else
+ {
+ if (!_cryptoStreamSpec->Filter)
+ {
+ _cryptoStreamSpec->Filter = _filterSpec = new NCrypto::NZip::CEncoder;
+ _filterSpec->CryptoSetPassword((const Byte *)(const char *)_options.Password, _options.Password.Len());
+ }
+
+ UInt32 check;
+
+ if (descriptorMode)
+ {
+ // it's Info-ZIP modification for stream_mode descriptor_mode (bit 3 of the general purpose bit flag is set)
+ check = (fileTime & 0xFFFF);
+ }
+ else
+ {
+ if (!crc_IsCalculated)
+ {
+ RINOK(CalcStreamCRC(inStream, crc))
+ crc_IsCalculated = true;
+ RINOK(InStream_SeekToBegin(inStream2))
+ inSecCrcStreamSpec->Init();
+ }
+ check = (crc >> 16);
+ }
+
+ RINOK(_filterSpec->WriteHeader_Check16(outStream, (UInt16)check))
+ }
+
+ if (method == NCompressionMethod::kStore)
+ {
+ needCode = false;
+ RINOK(_cryptoStreamSpec->Code(inCrcStream, outStream, NULL, NULL, progress))
+ }
+ else
+ {
+ RINOK(_cryptoStreamSpec->SetOutStream(outStream))
+ RINOK(_cryptoStreamSpec->InitEncoder())
+ outStreamReleaser.FilterCoder = _cryptoStreamSpec;
+ }
+ }
+
+ if (needCode)
+ {
+ switch (method)
+ {
+ case NCompressionMethod::kStore:
+ {
+ if (!_copyCoderSpec)
+ {
+ _copyCoderSpec = new NCompress::CCopyCoder;
+ _copyCoder = _copyCoderSpec;
+ }
+ CMyComPtr<ISequentialOutStream> outStreamNew;
+ if (_options.Password_Defined)
+ outStreamNew = _cryptoStream;
+ else
+ outStreamNew = outStream;
+ RINOK(_copyCoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress))
+ break;
+ }
+
+ default:
+ {
+ if (!_compressEncoder)
+ {
+ CLzmaEncoder *_lzmaEncoder = NULL;
+ if (method == NCompressionMethod::kLZMA)
+ {
+ _compressExtractVersion = NCompressionMethod::kExtractVersion_LZMA;
+ _lzmaEncoder = new CLzmaEncoder();
+ _compressEncoder = _lzmaEncoder;
+ }
+ else if (method == NCompressionMethod::kXz)
+ {
+ _compressExtractVersion = NCompressionMethod::kExtractVersion_Xz;
+ NCompress::NXz::CEncoder *encoder = new NCompress::NXz::CEncoder();
+ _compressEncoder = encoder;
+ }
+ else if (method == NCompressionMethod::kPPMd)
+ {
+ _compressExtractVersion = NCompressionMethod::kExtractVersion_PPMd;
+ NCompress::NPpmdZip::CEncoder *encoder = new NCompress::NPpmdZip::CEncoder();
+ _compressEncoder = encoder;
+ }
+ else
+ {
+ CMethodId methodId;
+ switch (method)
+ {
+ case NCompressionMethod::kBZip2:
+ methodId = kMethodId_BZip2;
+ _compressExtractVersion = NCompressionMethod::kExtractVersion_BZip2;
+ break;
+ default:
+ _compressExtractVersion = ((method == NCompressionMethod::kDeflate64) ?
+ NCompressionMethod::kExtractVersion_Deflate64 :
+ NCompressionMethod::kExtractVersion_Deflate);
+ methodId = kMethodId_ZipBase + method;
+ break;
+ }
+ RINOK(CreateCoder_Id(
+ EXTERNAL_CODECS_LOC_VARS
+ methodId, true, _compressEncoder))
+ if (!_compressEncoder)
+ return E_NOTIMPL;
+
+ if (method == NCompressionMethod::kDeflate ||
+ method == NCompressionMethod::kDeflate64)
+ {
+ }
+ else if (method == NCompressionMethod::kBZip2)
+ {
+ }
+ }
+ {
+ CMyComPtr<ICompressSetCoderProperties> setCoderProps;
+ _compressEncoder.QueryInterface(IID_ICompressSetCoderProperties, &setCoderProps);
+ if (setCoderProps)
+ {
+ if (!_options._methods.IsEmpty())
+ {
+ COneMethodInfo *oneMethodMain = &_options._methods[0];
+
+ RINOK(oneMethodMain->SetCoderProps(setCoderProps,
+ _options.DataSizeReduce_Defined ? &_options.DataSizeReduce : NULL))
+ }
+ }
+ }
+ if (method == NCompressionMethod::kLZMA)
+ _isLzmaEos = _lzmaEncoder->EncoderSpec->IsWriteEndMark();
+ }
+
+ if (method == NCompressionMethod::kLZMA)
+ opRes.LzmaEos = _isLzmaEos;
+
+ CMyComPtr<ISequentialOutStream> outStreamNew;
+ if (_options.Password_Defined)
+ outStreamNew = _cryptoStream;
+ else
+ outStreamNew = outStream;
+ if (_compressExtractVersion > opRes.ExtractVersion)
+ opRes.ExtractVersion = _compressExtractVersion;
+
+ {
+ CMyComPtr<ICompressSetCoderPropertiesOpt> optProps;
+ _compressEncoder->QueryInterface(IID_ICompressSetCoderPropertiesOpt, (void **)&optProps);
+ if (optProps)
+ {
+ const PROPID propID = NCoderPropID::kExpectedDataSize;
+ NWindows::NCOM::CPropVariant prop = (UInt64)expectedDataSize;
+ RINOK(optProps->SetCoderPropertiesOpt(&propID, &prop, 1))
+ }
+ }
+
+ try {
+ RINOK(_compressEncoder->Code(inCrcStream, outStreamNew, NULL, NULL, progress))
+ } catch (...) { return E_FAIL; }
+ break;
+ }
+ } // switch end
+
+ if (_options.Password_Defined)
+ {
+ RINOK(_cryptoStreamSpec->OutStreamFinish())
+ }
+ }
+
+ if (_options.Password_Defined)
+ {
+ if (_options.IsAesMode)
+ {
+ RINOK(_filterAesSpec->WriteFooter(outStream))
+ }
+ }
+
+ RINOK(outStream->Seek(0, STREAM_SEEK_CUR, &opRes.PackSize))
+
+ {
+ opRes.CRC = inSecCrcStreamSpec->GetCRC();
+ opRes.UnpackSize = inSecCrcStreamSpec->GetSize();
+ opRes.Method = method;
+ }
+
+ if (!inSecCrcStreamSpec->WasFinished())
+ return E_FAIL;
+
+ if (_options.Password_Defined)
+ {
+ if (opRes.PackSize < opRes.UnpackSize +
+ (_options.IsAesMode ? _filterAesSpec->GetAddPackSize() : NCrypto::NZip::kHeaderSize))
+ break;
+ }
+ else if (opRes.PackSize < opRes.UnpackSize)
+ break;
+ }
+
+ return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Zip/ZipAddCommon.h b/CPP/7zip/Archive/Zip/ZipAddCommon.h
new file mode 100644
index 0000000..051915c
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipAddCommon.h
@@ -0,0 +1,78 @@
+// ZipAddCommon.h
+
+#ifndef ZIP7_INC_ZIP_ADD_COMMON_H
+#define ZIP7_INC_ZIP_ADD_COMMON_H
+
+#include "../../ICoder.h"
+#include "../../IProgress.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/FilterCoder.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../../Crypto/ZipCrypto.h"
+#include "../../Crypto/WzAes.h"
+
+#include "ZipCompressionMode.h"
+
+namespace NArchive {
+namespace NZip {
+
+struct CCompressingResult
+{
+ UInt64 UnpackSize;
+ UInt64 PackSize;
+ UInt32 CRC;
+ UInt16 Method;
+ Byte ExtractVersion;
+ bool DescriptorMode;
+ bool LzmaEos;
+
+ CCompressingResult()
+ {
+ // for GCC:
+ UnpackSize = 0;
+ }
+};
+
+class CAddCommon MY_UNCOPYABLE
+{
+ CCompressionMethodMode _options;
+ NCompress::CCopyCoder *_copyCoderSpec;
+ CMyComPtr<ICompressCoder> _copyCoder;
+
+ CMyComPtr<ICompressCoder> _compressEncoder;
+ Byte _compressExtractVersion;
+ bool _isLzmaEos;
+
+ CFilterCoder *_cryptoStreamSpec;
+ CMyComPtr<ISequentialOutStream> _cryptoStream;
+
+ NCrypto::NZip::CEncoder *_filterSpec;
+ NCrypto::NWzAes::CEncoder *_filterAesSpec;
+
+ Byte *_buf;
+
+ HRESULT CalcStreamCRC(ISequentialInStream *inStream, UInt32 &resultCRC);
+public:
+ // CAddCommon(const CCompressionMethodMode &options);
+ CAddCommon();
+ void SetOptions(const CCompressionMethodMode &options);
+ ~CAddCommon();
+
+ HRESULT Set_Pre_CompressionResult(bool inSeqMode, bool outSeqMode, UInt64 unpackSize,
+ CCompressingResult &opRes) const;
+
+ HRESULT Compress(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ ISequentialInStream *inStream, IOutStream *outStream,
+ bool inSeqMode, bool outSeqMode,
+ UInt32 fileTime,
+ UInt64 expectedDataSize, bool expectedDataSize_IsConfirmed,
+ ICompressProgressInfo *progress, CCompressingResult &opRes);
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Zip/ZipCompressionMode.h b/CPP/7zip/Archive/Zip/ZipCompressionMode.h
new file mode 100644
index 0000000..8974261
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipCompressionMode.h
@@ -0,0 +1,62 @@
+// CompressionMode.h
+
+#ifndef ZIP7_INC_ZIP_COMPRESSION_MODE_H
+#define ZIP7_INC_ZIP_COMPRESSION_MODE_H
+
+#include "../../../Common/MyString.h"
+
+#ifndef Z7_ST
+#include "../../../Windows/System.h"
+#endif
+
+#include "../Common/HandlerOut.h"
+
+namespace NArchive {
+namespace NZip {
+
+const CMethodId kMethodId_ZipBase = 0x040100;
+const CMethodId kMethodId_BZip2 = 0x040202;
+
+struct CBaseProps: public CMultiMethodProps
+{
+ bool IsAesMode;
+ Byte AesKeyMode;
+
+ void Init()
+ {
+ CMultiMethodProps::Init();
+
+ IsAesMode = false;
+ AesKeyMode = 3;
+ }
+};
+
+struct CCompressionMethodMode: public CBaseProps
+{
+ CRecordVector<Byte> MethodSequence;
+ AString Password; // _Wipe
+ bool Password_Defined;
+ bool Force_SeqOutMode;
+ bool DataSizeReduce_Defined;
+ UInt64 DataSizeReduce;
+
+ bool IsRealAesMode() const { return Password_Defined && IsAesMode; }
+
+ CCompressionMethodMode()
+ {
+ Password_Defined = false;
+ Force_SeqOutMode = false;
+ DataSizeReduce_Defined = false;
+ DataSizeReduce = 0;
+ }
+
+#ifdef Z7_CPP_IS_SUPPORTED_default
+ CCompressionMethodMode(const CCompressionMethodMode &) = default;
+ CCompressionMethodMode& operator =(const CCompressionMethodMode &) = default;
+#endif
+ ~CCompressionMethodMode() { Password.Wipe_and_Empty(); }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Zip/ZipHandler.cpp b/CPP/7zip/Archive/Zip/ZipHandler.cpp
new file mode 100644
index 0000000..5f022cc
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipHandler.cpp
@@ -0,0 +1,1716 @@
+// ZipHandler.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/PropVariantUtils.h"
+#include "../../../Windows/TimeUtils.h"
+
+#include "../../IPassword.h"
+
+#include "../../Common/FilterCoder.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#ifdef Z7_EXTERNAL_CODECS
+#ifndef SUPPORT_LZFSE
+#define SUPPORT_LZFSE
+#endif
+#endif
+
+#ifdef SUPPORT_LZFSE
+#include "../../Compress/LzfseDecoder.h"
+#endif
+
+#include "../../Compress/LzmaDecoder.h"
+#include "../../Compress/ImplodeDecoder.h"
+#include "../../Compress/PpmdZip.h"
+#include "../../Compress/ShrinkDecoder.h"
+#include "../../Compress/XzDecoder.h"
+
+#include "../../Crypto/WzAes.h"
+#include "../../Crypto/ZipCrypto.h"
+#include "../../Crypto/ZipStrong.h"
+
+#include "../Common/ItemNameUtils.h"
+#include "../Common/OutStreamWithCRC.h"
+
+
+#include "ZipHandler.h"
+
+using namespace NWindows;
+
+namespace NArchive {
+namespace NZip {
+
+static const char * const kHostOS[] =
+{
+ "FAT"
+ , "AMIGA"
+ , "VMS"
+ , "Unix"
+ , "VM/CMS"
+ , "Atari"
+ , "HPFS"
+ , "Macintosh"
+ , "Z-System"
+ , "CP/M"
+ , "TOPS-20"
+ , "NTFS"
+ , "SMS/QDOS"
+ , "Acorn"
+ , "VFAT"
+ , "MVS"
+ , "BeOS"
+ , "Tandem"
+ , "OS/400"
+ , "OS/X"
+};
+
+
+const char * const kMethodNames1[kNumMethodNames1] =
+{
+ "Store"
+ , "Shrink"
+ , "Reduce1"
+ , "Reduce2"
+ , "Reduce3"
+ , "Reduce4"
+ , "Implode"
+ , NULL // "Tokenize"
+ , "Deflate"
+ , "Deflate64"
+ , "PKImploding"
+ , NULL
+ , "BZip2"
+ , NULL
+ , "LZMA"
+ /*
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , NULL
+ , "zstd-pk" // deprecated
+ */
+};
+
+
+const char * const kMethodNames2[kNumMethodNames2] =
+{
+ "zstd"
+ , "MP3"
+ , "xz"
+ , "Jpeg"
+ , "WavPack"
+ , "PPMd"
+ , "LZFSE" // , "WzAES"
+};
+
+#define kMethod_AES "AES"
+#define kMethod_ZipCrypto "ZipCrypto"
+#define kMethod_StrongCrypto "StrongCrypto"
+
+static const char * const kDeflateLevels[4] =
+{
+ "Normal"
+ , "Maximum"
+ , "Fast"
+ , "Fastest"
+};
+
+
+static const CUInt32PCharPair g_HeaderCharacts[] =
+{
+ { 0, "Encrypt" },
+ { 3, "Descriptor" },
+ // { 4, "Enhanced" },
+ // { 5, "Patched" },
+ { 6, kMethod_StrongCrypto },
+ { 11, "UTF8" },
+ { 14, "Alt" }
+};
+
+struct CIdToNamePair
+{
+ unsigned Id;
+ const char *Name;
+};
+
+
+static const CIdToNamePair k_StrongCryptoPairs[] =
+{
+ { NStrongCrypto_AlgId::kDES, "DES" },
+ { NStrongCrypto_AlgId::kRC2old, "RC2a" },
+ { NStrongCrypto_AlgId::k3DES168, "3DES-168" },
+ { NStrongCrypto_AlgId::k3DES112, "3DES-112" },
+ { NStrongCrypto_AlgId::kAES128, "pkAES-128" },
+ { NStrongCrypto_AlgId::kAES192, "pkAES-192" },
+ { NStrongCrypto_AlgId::kAES256, "pkAES-256" },
+ { NStrongCrypto_AlgId::kRC2, "RC2" },
+ { NStrongCrypto_AlgId::kBlowfish, "Blowfish" },
+ { NStrongCrypto_AlgId::kTwofish, "Twofish" },
+ { NStrongCrypto_AlgId::kRC4, "RC4" }
+};
+
+static const char *FindNameForId(const CIdToNamePair *pairs, unsigned num, unsigned id)
+{
+ for (unsigned i = 0; i < num; i++)
+ {
+ const CIdToNamePair &pair = pairs[i];
+ if (id == pair.Id)
+ return pair.Name;
+ }
+ return NULL;
+}
+
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidMTime,
+ kpidCTime,
+ kpidATime,
+ kpidAttrib,
+ // kpidPosixAttrib,
+ kpidEncrypted,
+ kpidComment,
+ kpidCRC,
+ kpidMethod,
+ kpidCharacts,
+ kpidHostOS,
+ kpidUnpackVer,
+ kpidVolumeIndex,
+ kpidOffset
+ // kpidIsAltStream
+ // , kpidChangeTime // for debug
+ // , 255 // for debug
+};
+
+static const Byte kArcProps[] =
+{
+ kpidEmbeddedStubSize,
+ kpidBit64,
+ kpidComment,
+ kpidCharacts,
+ kpidTotalPhySize,
+ kpidIsVolume,
+ kpidVolumeIndex,
+ kpidNumVolumes
+};
+
+CHandler::CHandler()
+{
+ InitMethodProps();
+}
+
+static AString BytesToString(const CByteBuffer &data)
+{
+ AString s;
+ s.SetFrom_CalcLen((const char *)(const Byte *)data, (unsigned)data.Size());
+ return s;
+}
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidBit64: if (m_Archive.IsZip64) prop = m_Archive.IsZip64; break;
+ case kpidComment: if (m_Archive.ArcInfo.Comment.Size() != 0) prop = MultiByteToUnicodeString(BytesToString(m_Archive.ArcInfo.Comment), CP_ACP); break;
+
+ case kpidPhySize: prop = m_Archive.GetPhySize(); break;
+ case kpidOffset: prop = m_Archive.GetOffset(); break;
+
+ case kpidEmbeddedStubSize:
+ {
+ UInt64 stubSize = m_Archive.GetEmbeddedStubSize();
+ if (stubSize != 0)
+ prop = stubSize;
+ break;
+ }
+
+ case kpidTotalPhySize: if (m_Archive.IsMultiVol) prop = m_Archive.Vols.TotalBytesSize; break;
+ case kpidVolumeIndex: if (m_Archive.IsMultiVol) prop = (UInt32)m_Archive.Vols.StartVolIndex; break;
+ case kpidIsVolume: if (m_Archive.IsMultiVol) prop = true; break;
+ case kpidNumVolumes: if (m_Archive.IsMultiVol) prop = (UInt32)m_Archive.Vols.Streams.Size(); break;
+
+ case kpidCharacts:
+ {
+ AString s;
+
+ if (m_Archive.LocalsWereRead)
+ {
+ s.Add_OptSpaced("Local");
+
+ if (m_Archive.LocalsCenterMerged)
+ s.Add_OptSpaced("Central");
+ }
+
+ if (m_Archive.IsZip64)
+ s.Add_OptSpaced("Zip64");
+
+ if (m_Archive.IsCdUnsorted)
+ s.Add_OptSpaced("Unsorted_CD");
+
+ if (m_Archive.IsApk)
+ s.Add_OptSpaced("apk");
+
+ if (m_Archive.ExtraMinorError)
+ s.Add_OptSpaced("Minor_Extra_ERROR");
+
+ if (!s.IsEmpty())
+ prop = s;
+ break;
+ }
+
+ case kpidWarningFlags:
+ {
+ UInt32 v = 0;
+ // if (m_Archive.ExtraMinorError) v |= kpv_ErrorFlags_HeadersError;
+ if (m_Archive.HeadersWarning) v |= kpv_ErrorFlags_HeadersError;
+ if (v != 0)
+ prop = v;
+ break;
+ }
+
+ case kpidWarning:
+ {
+ AString s;
+ if (m_Archive.Overflow32bit)
+ s.Add_OptSpaced("32-bit overflow in headers");
+ if (m_Archive.Cd_NumEntries_Overflow_16bit)
+ s.Add_OptSpaced("16-bit overflow for number of files in headers");
+ if (!s.IsEmpty())
+ prop = s;
+ break;
+ }
+
+ case kpidError:
+ {
+ if (!m_Archive.Vols.MissingName.IsEmpty())
+ {
+ UString s("Missing volume : ");
+ s += m_Archive.Vols.MissingName;
+ prop = s;
+ }
+ break;
+ }
+
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!m_Archive.IsArc) v |= kpv_ErrorFlags_IsNotArc;
+ if (m_Archive.HeadersError) v |= kpv_ErrorFlags_HeadersError;
+ if (m_Archive.UnexpectedEnd) v |= kpv_ErrorFlags_UnexpectedEnd;
+ if (m_Archive.ArcInfo.Base < 0)
+ {
+ /* We try to support case when we have sfx-zip with embedded stub,
+ but the stream has access only to zip part.
+ In that case we ignore UnavailableStart error.
+ maybe we must show warning in that case. */
+ UInt64 stubSize = m_Archive.GetEmbeddedStubSize();
+ if (stubSize < (UInt64)-m_Archive.ArcInfo.Base)
+ v |= kpv_ErrorFlags_UnavailableStart;
+ }
+ if (m_Archive.NoCentralDir) v |= kpv_ErrorFlags_UnconfirmedStart;
+ prop = v;
+ break;
+ }
+
+ case kpidReadOnly:
+ {
+ if (m_Archive.IsOpen())
+ if (!m_Archive.CanUpdate())
+ prop = true;
+ break;
+ }
+
+ // case kpidIsAltStream: prop = true; break;
+ }
+ return prop.Detach(value);
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = m_Items.Size();
+ return S_OK;
+}
+
+
+static bool NtfsUnixTimeToProp(bool fromCentral,
+ const CExtraBlock &extra,
+ unsigned ntfsIndex, unsigned unixIndex, NWindows::NCOM::CPropVariant &prop)
+{
+ {
+ FILETIME ft;
+ if (extra.GetNtfsTime(ntfsIndex, ft))
+ {
+ PropVariant_SetFrom_NtfsTime(prop, ft);
+ return true;
+ }
+ }
+ {
+ UInt32 unixTime = 0;
+ if (!extra.GetUnixTime(fromCentral, unixIndex, unixTime))
+ return false;
+ /*
+ // we allow unixTime == 0
+ if (unixTime == 0)
+ return false;
+ */
+ PropVariant_SetFrom_UnixTime(prop, unixTime);
+ return true;
+ }
+}
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ const CItemEx &item = m_Items[index];
+ const CExtraBlock &extra = item.GetMainExtra();
+
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ UString res;
+ item.GetUnicodeString(res, item.Name, false, _forceCodePage, _specifiedCodePage);
+ NItemName::ReplaceToOsSlashes_Remove_TailSlash(res,
+ item.Is_MadeBy_Unix() // useBackslashReplacement
+ );
+ /*
+ if (item.ParentOfAltStream >= 0)
+ {
+ const CItemEx &prevItem = m_Items[item.ParentOfAltStream];
+ UString prevName;
+ prevItem.GetUnicodeString(prevName, prevItem.Name, false, _forceCodePage, _specifiedCodePage);
+ NItemName::ReplaceToOsSlashes_Remove_TailSlash(prevName);
+ if (res.IsPrefixedBy(prevName))
+ if (IsString1PrefixedByString2(res.Ptr(prevName.Len()), k_SpecName_NTFS_STREAM))
+ {
+ res.Delete(prevName.Len(), (unsigned)strlen(k_SpecName_NTFS_STREAM));
+ res.Insert(prevName.Len(), L":");
+ }
+ }
+ */
+ prop = res;
+ break;
+ }
+
+ case kpidIsDir: prop = item.IsDir(); break;
+ case kpidSize:
+ {
+ if (!item.IsBadDescriptor())
+ prop = item.Size;
+ break;
+ }
+
+ case kpidPackSize: prop = item.PackSize; break;
+
+ case kpidCTime:
+ NtfsUnixTimeToProp(item.FromCentral, extra,
+ NFileHeader::NNtfsExtra::kCTime,
+ NFileHeader::NUnixTime::kCTime, prop);
+ break;
+
+ case kpidATime:
+ NtfsUnixTimeToProp(item.FromCentral, extra,
+ NFileHeader::NNtfsExtra::kATime,
+ NFileHeader::NUnixTime::kATime, prop);
+ break;
+
+ case kpidMTime:
+ {
+ if (!NtfsUnixTimeToProp(item.FromCentral, extra,
+ NFileHeader::NNtfsExtra::kMTime,
+ NFileHeader::NUnixTime::kMTime, prop))
+ {
+ if (item.Time != 0)
+ PropVariant_SetFrom_DosTime(prop, item.Time);
+ }
+ break;
+ }
+
+ case kpidTimeType:
+ {
+ FILETIME ft;
+ UInt32 unixTime;
+ UInt32 type;
+ if (extra.GetNtfsTime(NFileHeader::NNtfsExtra::kMTime, ft))
+ type = NFileTimeType::kWindows;
+ else if (extra.GetUnixTime(item.FromCentral, NFileHeader::NUnixTime::kMTime, unixTime))
+ type = NFileTimeType::kUnix;
+ else
+ type = NFileTimeType::kDOS;
+ prop = type;
+ break;
+ }
+
+ /*
+ // for debug to get Dos time values:
+ case kpidChangeTime: if (item.Time != 0) PropVariant_SetFrom_DosTime(prop, item.Time); break;
+ // for debug
+ // time difference (dos - utc)
+ case 255:
+ {
+ if (NtfsUnixTimeToProp(item.FromCentral, extra,
+ NFileHeader::NNtfsExtra::kMTime,
+ NFileHeader::NUnixTime::kMTime, prop))
+ {
+ FILETIME localFileTime;
+ if (item.Time != 0 && NTime::DosTime_To_FileTime(item.Time, localFileTime))
+ {
+ UInt64 t1 = FILETIME_To_UInt64(prop.filetime);
+ UInt64 t2 = FILETIME_To_UInt64(localFileTime);
+ prop.Set_Int64(t2 - t1);
+ }
+ }
+ break;
+ }
+ */
+
+ case kpidAttrib: prop = item.GetWinAttrib(); break;
+
+ case kpidPosixAttrib:
+ {
+ UInt32 attrib;
+ if (item.GetPosixAttrib(attrib))
+ prop = attrib;
+ break;
+ }
+
+ case kpidEncrypted: prop = item.IsEncrypted(); break;
+
+ case kpidComment:
+ {
+ if (item.Comment.Size() != 0)
+ {
+ UString res;
+ item.GetUnicodeString(res, BytesToString(item.Comment), true, _forceCodePage, _specifiedCodePage);
+ prop = res;
+ }
+ break;
+ }
+
+ case kpidCRC: if (item.IsThereCrc()) prop = item.Crc; break;
+
+ case kpidMethod:
+ {
+ AString m;
+ bool isWzAes = false;
+ unsigned id = item.Method;
+
+ if (id == NFileHeader::NCompressionMethod::kWzAES)
+ {
+ CWzAesExtra aesField;
+ if (extra.GetWzAes(aesField))
+ {
+ m += kMethod_AES;
+ m.Add_Minus();
+ m.Add_UInt32(((unsigned)aesField.Strength + 1) * 64);
+ id = aesField.Method;
+ isWzAes = true;
+ }
+ }
+
+ if (item.IsEncrypted())
+ if (!isWzAes)
+ {
+ if (item.IsStrongEncrypted())
+ {
+ CStrongCryptoExtra f;
+ f.AlgId = 0;
+ if (extra.GetStrongCrypto(f))
+ {
+ const char *s = FindNameForId(k_StrongCryptoPairs, Z7_ARRAY_SIZE(k_StrongCryptoPairs), f.AlgId);
+ if (s)
+ m += s;
+ else
+ {
+ m += kMethod_StrongCrypto;
+ m += ':';
+ m.Add_UInt32(f.AlgId);
+ }
+ if (f.CertificateIsUsed())
+ m += "-Cert";
+ }
+ else
+ m += kMethod_StrongCrypto;
+ }
+ else
+ m += kMethod_ZipCrypto;
+ }
+
+ m.Add_Space_if_NotEmpty();
+
+ {
+ const char *s = NULL;
+ if (id < kNumMethodNames1)
+ s = kMethodNames1[id];
+ else
+ {
+ int id2 = (int)id - (int)kMethodNames2Start;
+ if (id2 >= 0 && (unsigned)id2 < kNumMethodNames2)
+ s = kMethodNames2[id2];
+ }
+ if (s)
+ m += s;
+ else
+ m.Add_UInt32(id);
+ }
+ {
+ unsigned level = item.GetDeflateLevel();
+ if (level != 0)
+ {
+ if (id == NFileHeader::NCompressionMethod::kLZMA)
+ {
+ if (level & 1)
+ m += ":eos";
+ level &= ~(unsigned)1;
+ }
+ else if (id == NFileHeader::NCompressionMethod::kDeflate)
+ {
+ m += ':';
+ m += kDeflateLevels[level];
+ level = 0;
+ }
+
+ if (level != 0)
+ {
+ m += ":v";
+ m.Add_UInt32(level);
+ }
+ }
+ }
+
+ prop = m;
+ break;
+ }
+
+ case kpidCharacts:
+ {
+ AString s;
+
+ if (item.FromLocal)
+ {
+ s.Add_OptSpaced("Local");
+
+ item.LocalExtra.PrintInfo(s);
+
+ if (item.FromCentral)
+ {
+ s.Add_OptSpaced(":");
+ s.Add_OptSpaced("Central");
+ }
+ }
+
+ if (item.FromCentral)
+ {
+ item.CentralExtra.PrintInfo(s);
+ }
+
+ UInt32 flags = item.Flags;
+ flags &= ~(unsigned)6; // we don't need compression related bits here.
+
+ if (flags != 0)
+ {
+ const AString s2 = FlagsToString(g_HeaderCharacts, Z7_ARRAY_SIZE(g_HeaderCharacts), flags);
+ if (!s2.IsEmpty())
+ {
+ if (!s.IsEmpty())
+ s.Add_OptSpaced(":");
+ s.Add_OptSpaced(s2);
+ }
+ }
+
+ if (item.IsBadDescriptor())
+ s.Add_OptSpaced("Descriptor_ERROR");
+
+ if (!s.IsEmpty())
+ prop = s;
+ break;
+ }
+
+ case kpidHostOS:
+ {
+ if (item.FromCentral)
+ {
+ // 18.06: now we use HostOS only from Central::MadeByVersion
+ const Byte hostOS = item.MadeByVersion.HostOS;
+ TYPE_TO_PROP(kHostOS, hostOS, prop);
+ }
+ break;
+ }
+
+ case kpidUnpackVer:
+ prop = (UInt32)item.ExtractVersion.Version;
+ break;
+
+ case kpidVolumeIndex:
+ prop = item.Disk;
+ break;
+
+ case kpidOffset:
+ prop = item.LocalHeaderPos;
+ break;
+
+ /*
+ case kpidIsAltStream:
+ prop = (bool)(item.ParentOfAltStream >= 0); // item.IsAltStream();
+ break;
+
+ case kpidName:
+ if (item.ParentOfAltStream >= 0)
+ {
+ // extract name of stream here
+ }
+ break;
+ */
+ }
+
+ return prop.Detach(value);
+ COM_TRY_END
+}
+
+
+
+/*
+Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps)
+{
+ *numProps = 0;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID)
+{
+ UNUSED_VAR(index);
+ *propID = 0;
+ *name = 0;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetParent(UInt32 index, UInt32 *parent, UInt32 *parentType)
+{
+ *parentType = NParentType::kDir;
+ *parent = (UInt32)(Int32)-1;
+ if (index >= m_Items.Size())
+ return S_OK;
+ const CItemEx &item = m_Items[index];
+
+ if (item.ParentOfAltStream >= 0)
+ {
+ *parentType = NParentType::kAltStream;
+ *parent = item.ParentOfAltStream;
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)
+{
+ UNUSED_VAR(index);
+ UNUSED_VAR(propID);
+ *data = NULL;
+ *dataSize = 0;
+ *propType = 0;
+ return S_OK;
+}
+
+
+void CHandler::MarkAltStreams(CObjectVector<CItemEx> &items)
+{
+ int prevIndex = -1;
+ UString prevName;
+ UString name;
+
+ for (unsigned i = 0; i < items.Size(); i++)
+ {
+ CItemEx &item = m_Items[i];
+ if (item.IsAltStream())
+ {
+ if (prevIndex == -1)
+ continue;
+ if (prevName.IsEmpty())
+ {
+ const CItemEx &prevItem = m_Items[prevIndex];
+ prevItem.GetUnicodeString(prevName, prevItem.Name, false, _forceCodePage, _specifiedCodePage);
+ NItemName::ReplaceToOsSlashes_Remove_TailSlash(prevName);
+ }
+ name.Empty();
+ item.GetUnicodeString(name, item.Name, false, _forceCodePage, _specifiedCodePage);
+ NItemName::ReplaceToOsSlashes_Remove_TailSlash(name);
+
+ if (name.IsPrefixedBy(prevName))
+ if (IsString1PrefixedByString2(name.Ptr(prevName.Len()), k_SpecName_NTFS_STREAM))
+ item.ParentOfAltStream = prevIndex;
+ }
+ else
+ {
+ prevIndex = i;
+ prevName.Empty();
+ }
+ }
+}
+*/
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *inStream,
+ const UInt64 *maxCheckStartPosition, IArchiveOpenCallback *callback))
+{
+ COM_TRY_BEGIN
+ try
+ {
+ Close();
+ m_Archive.Force_ReadLocals_Mode = _force_OpenSeq;
+ // m_Archive.Disable_VolsRead = _force_OpenSeq;
+ // m_Archive.Disable_FindMarker = _force_OpenSeq;
+ HRESULT res = m_Archive.Open(inStream, maxCheckStartPosition, callback, m_Items);
+ if (res != S_OK)
+ {
+ m_Items.Clear();
+ m_Archive.ClearRefs(); // we don't want to clear error flags
+ }
+ // MarkAltStreams(m_Items);
+ return res;
+ }
+ catch(...) { Close(); throw; }
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ m_Items.Clear();
+ m_Archive.Close();
+ return S_OK;
+}
+
+
+Z7_CLASS_IMP_NOQIB_3(
+ CLzmaDecoder
+ , ICompressCoder
+ , ICompressSetFinishMode
+ , ICompressGetInStreamProcessedSize
+)
+public:
+ NCompress::NLzma::CDecoder *DecoderSpec;
+ CMyComPtr<ICompressCoder> Decoder;
+
+ CLzmaDecoder();
+};
+
+CLzmaDecoder::CLzmaDecoder()
+{
+ DecoderSpec = new NCompress::NLzma::CDecoder;
+ Decoder = DecoderSpec;
+}
+
+static const unsigned kZipLzmaPropsSize = 4 + LZMA_PROPS_SIZE;
+
+Z7_COM7F_IMF(CLzmaDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ Byte buf[kZipLzmaPropsSize];
+ RINOK(ReadStream_FALSE(inStream, buf, kZipLzmaPropsSize))
+ if (buf[2] != LZMA_PROPS_SIZE || buf[3] != 0)
+ return E_NOTIMPL;
+ RINOK(DecoderSpec->SetDecoderProperties2(buf + 4, LZMA_PROPS_SIZE))
+ UInt64 inSize2 = 0;
+ if (inSize)
+ {
+ inSize2 = *inSize;
+ if (inSize2 < kZipLzmaPropsSize)
+ return S_FALSE;
+ inSize2 -= kZipLzmaPropsSize;
+ }
+ return Decoder->Code(inStream, outStream, inSize ? &inSize2 : NULL, outSize, progress);
+}
+
+Z7_COM7F_IMF(CLzmaDecoder::SetFinishMode(UInt32 finishMode))
+{
+ DecoderSpec->FinishStream = (finishMode != 0);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CLzmaDecoder::GetInStreamProcessedSize(UInt64 *value))
+{
+ *value = DecoderSpec->GetInputProcessedSize() + kZipLzmaPropsSize;
+ return S_OK;
+}
+
+
+
+
+
+
+
+struct CMethodItem
+{
+ unsigned ZipMethod;
+ CMyComPtr<ICompressCoder> Coder;
+};
+
+
+
+class CZipDecoder
+{
+ NCrypto::NZip::CDecoder *_zipCryptoDecoderSpec;
+ NCrypto::NZipStrong::CDecoder *_pkAesDecoderSpec;
+ NCrypto::NWzAes::CDecoder *_wzAesDecoderSpec;
+
+ CMyComPtr<ICompressFilter> _zipCryptoDecoder;
+ CMyComPtr<ICompressFilter> _pkAesDecoder;
+ CMyComPtr<ICompressFilter> _wzAesDecoder;
+
+ CFilterCoder *filterStreamSpec;
+ CMyComPtr<ISequentialInStream> filterStream;
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ CObjectVector<CMethodItem> methodItems;
+
+ CLzmaDecoder *lzmaDecoderSpec;
+public:
+ CZipDecoder():
+ _zipCryptoDecoderSpec(NULL),
+ _pkAesDecoderSpec(NULL),
+ _wzAesDecoderSpec(NULL),
+ filterStreamSpec(NULL),
+ lzmaDecoderSpec(NULL)
+ {}
+
+ HRESULT Decode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CInArchive &archive, const CItemEx &item,
+ ISequentialOutStream *realOutStream,
+ IArchiveExtractCallback *extractCallback,
+ ICompressProgressInfo *compressProgress,
+ #ifndef Z7_ST
+ UInt32 numThreads, UInt64 memUsage,
+ #endif
+ Int32 &res);
+};
+
+
+static HRESULT SkipStreamData(ISequentialInStream *stream,
+ ICompressProgressInfo *progress, UInt64 packSize, UInt64 unpackSize,
+ bool &thereAreData)
+{
+ thereAreData = false;
+ const size_t kBufSize = 1 << 12;
+ Byte buf[kBufSize];
+ UInt64 prev = packSize;
+ for (;;)
+ {
+ size_t size = kBufSize;
+ RINOK(ReadStream(stream, buf, &size))
+ if (size == 0)
+ return S_OK;
+ thereAreData = true;
+ packSize += size;
+ if ((packSize - prev) >= (1 << 22))
+ {
+ prev = packSize;
+ RINOK(progress->SetRatioInfo(&packSize, &unpackSize))
+ }
+ }
+}
+
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ COutStreamWithPadPKCS7
+ , ISequentialOutStream
+)
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+ UInt64 _padPos;
+ UInt32 _padSize;
+ bool _padFailure;
+public:
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+
+ // padSize == 0 means (no_pad Mode)
+ void Init(UInt64 padPos, UInt32 padSize)
+ {
+ _padPos = padPos;
+ _padSize = padSize;
+ _size = 0;
+ _padFailure = false;
+ }
+ UInt64 GetSize() const { return _size; }
+ bool WasPadFailure() const { return _padFailure; }
+};
+
+
+Z7_COM7F_IMF(COutStreamWithPadPKCS7::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ UInt32 written = 0;
+ HRESULT result = S_OK;
+ if (_size < _padPos)
+ {
+ const UInt64 rem = _padPos - _size;
+ UInt32 num = size;
+ if (num > rem)
+ num = (UInt32)rem;
+ result = _stream->Write(data, num, &written);
+ _size += written;
+ if (processedSize)
+ *processedSize = written;
+ if (_size != _padPos || result != S_OK)
+ return result;
+ size -= written;
+ data = ((const Byte *)data) + written;
+ }
+ _size += size;
+ written += size;
+ if (processedSize)
+ *processedSize = written;
+ if (_padSize != 0)
+ for (; size != 0; size--)
+ {
+ if (*(const Byte *)data != _padSize)
+ _padFailure = true;
+ data = ((const Byte *)data) + 1;
+ }
+ return result;
+}
+
+
+
+HRESULT CZipDecoder::Decode(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CInArchive &archive, const CItemEx &item,
+ ISequentialOutStream *realOutStream,
+ IArchiveExtractCallback *extractCallback,
+ ICompressProgressInfo *compressProgress,
+ #ifndef Z7_ST
+ UInt32 numThreads, UInt64 memUsage,
+ #endif
+ Int32 &res)
+{
+ res = NExtract::NOperationResult::kHeadersError;
+
+ CFilterCoder::C_InStream_Releaser inStreamReleaser;
+ CFilterCoder::C_Filter_Releaser filterReleaser;
+
+ bool needCRC = true;
+ bool wzAesMode = false;
+ bool pkAesMode = false;
+
+ bool badDescriptor = item.IsBadDescriptor();
+ if (badDescriptor)
+ needCRC = false;
+
+
+ unsigned id = item.Method;
+
+ CWzAesExtra aesField;
+ // LZFSE and WinZip's AES use same id - kWzAES.
+
+ if (id == NFileHeader::NCompressionMethod::kWzAES)
+ {
+ if (item.GetMainExtra().GetWzAes(aesField))
+ {
+ if (!item.IsEncrypted())
+ {
+ res = NExtract::NOperationResult::kUnsupportedMethod;
+ return S_OK;
+ }
+ wzAesMode = true;
+ needCRC = aesField.NeedCrc();
+ }
+ }
+
+ if (!wzAesMode)
+ if (item.IsEncrypted())
+ {
+ if (item.IsStrongEncrypted())
+ {
+ CStrongCryptoExtra f;
+ if (!item.CentralExtra.GetStrongCrypto(f))
+ {
+ res = NExtract::NOperationResult::kUnsupportedMethod;
+ return S_OK;
+ }
+ pkAesMode = true;
+ }
+ }
+
+ COutStreamWithCRC *outStreamSpec = new COutStreamWithCRC;
+ CMyComPtr<ISequentialOutStream> outStream = outStreamSpec;
+ outStreamSpec->SetStream(realOutStream);
+ outStreamSpec->Init(needCRC);
+
+ CMyComPtr<ISequentialInStream> packStream;
+
+ CLimitedSequentialInStream *limitedStreamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(limitedStreamSpec);
+
+ {
+ UInt64 packSize = item.PackSize;
+ if (wzAesMode)
+ {
+ if (packSize < NCrypto::NWzAes::kMacSize)
+ return S_OK;
+ packSize -= NCrypto::NWzAes::kMacSize;
+ }
+ RINOK(archive.GetItemStream(item, true, packStream))
+ if (!packStream)
+ {
+ res = NExtract::NOperationResult::kUnavailable;
+ return S_OK;
+ }
+ limitedStreamSpec->SetStream(packStream);
+ limitedStreamSpec->Init(packSize);
+ }
+
+
+ res = NExtract::NOperationResult::kDataError;
+
+ CMyComPtr<ICompressFilter> cryptoFilter;
+
+ if (item.IsEncrypted())
+ {
+ if (wzAesMode)
+ {
+ id = aesField.Method;
+ if (!_wzAesDecoder)
+ {
+ _wzAesDecoderSpec = new NCrypto::NWzAes::CDecoder;
+ _wzAesDecoder = _wzAesDecoderSpec;
+ }
+ cryptoFilter = _wzAesDecoder;
+ if (!_wzAesDecoderSpec->SetKeyMode(aesField.Strength))
+ {
+ res = NExtract::NOperationResult::kUnsupportedMethod;
+ return S_OK;
+ }
+ }
+ else if (pkAesMode)
+ {
+ if (!_pkAesDecoder)
+ {
+ _pkAesDecoderSpec = new NCrypto::NZipStrong::CDecoder;
+ _pkAesDecoder = _pkAesDecoderSpec;
+ }
+ cryptoFilter = _pkAesDecoder;
+ }
+ else
+ {
+ if (!_zipCryptoDecoder)
+ {
+ _zipCryptoDecoderSpec = new NCrypto::NZip::CDecoder;
+ _zipCryptoDecoder = _zipCryptoDecoderSpec;
+ }
+ cryptoFilter = _zipCryptoDecoder;
+ }
+
+ CMyComPtr<ICryptoSetPassword> cryptoSetPassword;
+ RINOK(cryptoFilter.QueryInterface(IID_ICryptoSetPassword, &cryptoSetPassword))
+ if (!cryptoSetPassword)
+ return E_FAIL;
+
+ if (!getTextPassword)
+ extractCallback->QueryInterface(IID_ICryptoGetTextPassword, (void **)&getTextPassword);
+
+ if (getTextPassword)
+ {
+ CMyComBSTR_Wipe password;
+ RINOK(getTextPassword->CryptoGetTextPassword(&password))
+ AString_Wipe charPassword;
+ if (password)
+ {
+ /*
+ // 22.00: do we need UTF-8 passwords here ?
+ if (item.IsUtf8()) // 22.00
+ {
+ // throw 1;
+ ConvertUnicodeToUTF8((LPCOLESTR)password, charPassword);
+ }
+ else
+ */
+ {
+ UnicodeStringToMultiByte2(charPassword, (LPCOLESTR)password, CP_ACP);
+ }
+ /*
+ if (wzAesMode || pkAesMode)
+ {
+ }
+ else
+ {
+ // PASSWORD encoding for ZipCrypto:
+ // pkzip25 / WinZip / Windows probably use ANSI
+ // 7-Zip < 4.43 creates ZIP archives with OEM encoding in password
+ // 7-Zip >= 4.43 creates ZIP archives only with ASCII characters in password
+ // 7-Zip < 17.00 uses CP_OEMCP for password decoding
+ // 7-Zip >= 17.00 uses CP_ACP for password decoding
+ }
+ */
+ }
+ HRESULT result = cryptoSetPassword->CryptoSetPassword(
+ (const Byte *)(const char *)charPassword, charPassword.Len());
+ if (result != S_OK)
+ {
+ res = NExtract::NOperationResult::kWrongPassword;
+ return S_OK;
+ }
+ }
+ else
+ {
+ res = NExtract::NOperationResult::kWrongPassword;
+ return S_OK;
+ // RINOK(cryptoSetPassword->CryptoSetPassword(NULL, 0));
+ }
+ }
+
+ unsigned m;
+ for (m = 0; m < methodItems.Size(); m++)
+ if (methodItems[m].ZipMethod == id)
+ break;
+
+ if (m == methodItems.Size())
+ {
+ CMethodItem mi;
+ mi.ZipMethod = id;
+ if (id == NFileHeader::NCompressionMethod::kStore)
+ mi.Coder = new NCompress::CCopyCoder;
+ else if (id == NFileHeader::NCompressionMethod::kShrink)
+ mi.Coder = new NCompress::NShrink::CDecoder;
+ else if (id == NFileHeader::NCompressionMethod::kImplode)
+ mi.Coder = new NCompress::NImplode::NDecoder::CCoder;
+ else if (id == NFileHeader::NCompressionMethod::kLZMA)
+ {
+ lzmaDecoderSpec = new CLzmaDecoder;
+ mi.Coder = lzmaDecoderSpec;
+ }
+ else if (id == NFileHeader::NCompressionMethod::kXz)
+ mi.Coder = new NCompress::NXz::CComDecoder;
+ else if (id == NFileHeader::NCompressionMethod::kPPMd)
+ mi.Coder = new NCompress::NPpmdZip::CDecoder(true);
+ #ifdef SUPPORT_LZFSE
+ else if (id == NFileHeader::NCompressionMethod::kWzAES)
+ mi.Coder = new NCompress::NLzfse::CDecoder;
+ #endif
+ else
+ {
+ CMethodId szMethodID;
+ if (id == NFileHeader::NCompressionMethod::kBZip2)
+ szMethodID = kMethodId_BZip2;
+ else
+ {
+ if (id > 0xFF)
+ {
+ res = NExtract::NOperationResult::kUnsupportedMethod;
+ return S_OK;
+ }
+ szMethodID = kMethodId_ZipBase + (Byte)id;
+ }
+
+ RINOK(CreateCoder_Id(EXTERNAL_CODECS_LOC_VARS szMethodID, false, mi.Coder))
+
+ if (!mi.Coder)
+ {
+ res = NExtract::NOperationResult::kUnsupportedMethod;
+ return S_OK;
+ }
+ }
+ m = methodItems.Add(mi);
+ }
+
+ const CMethodItem &mi = methodItems[m];
+ ICompressCoder *coder = mi.Coder;
+
+
+ #ifndef Z7_ST
+ {
+ CMyComPtr<ICompressSetCoderMt> setCoderMt;
+ coder->QueryInterface(IID_ICompressSetCoderMt, (void **)&setCoderMt);
+ if (setCoderMt)
+ {
+ RINOK(setCoderMt->SetNumberOfThreads(numThreads))
+ }
+ }
+ // if (memUsage != 0)
+ {
+ CMyComPtr<ICompressSetMemLimit> setMemLimit;
+ coder->QueryInterface(IID_ICompressSetMemLimit, (void **)&setMemLimit);
+ if (setMemLimit)
+ {
+ RINOK(setMemLimit->SetMemLimit(memUsage))
+ }
+ }
+ #endif
+
+ {
+ CMyComPtr<ICompressSetDecoderProperties2> setDecoderProperties;
+ coder->QueryInterface(IID_ICompressSetDecoderProperties2, (void **)&setDecoderProperties);
+ if (setDecoderProperties)
+ {
+ Byte properties = (Byte)item.Flags;
+ RINOK(setDecoderProperties->SetDecoderProperties2(&properties, 1))
+ }
+ }
+
+
+ bool isFullStreamExpected = (!item.HasDescriptor() || item.PackSize != 0);
+ bool needReminderCheck = false;
+
+ bool dataAfterEnd = false;
+ bool truncatedError = false;
+ bool lzmaEosError = false;
+ bool headersError = false;
+ bool padError = false;
+ bool readFromFilter = false;
+
+ const bool useUnpackLimit = (id == NFileHeader::NCompressionMethod::kStore
+ || !item.HasDescriptor()
+ || item.Size >= ((UInt64)1 << 32)
+ || item.LocalExtra.IsZip64
+ || item.CentralExtra.IsZip64
+ );
+
+ {
+ HRESULT result = S_OK;
+ if (item.IsEncrypted())
+ {
+ if (!filterStream)
+ {
+ filterStreamSpec = new CFilterCoder(false);
+ filterStream = filterStreamSpec;
+ }
+
+ filterReleaser.FilterCoder = filterStreamSpec;
+ filterStreamSpec->Filter = cryptoFilter;
+
+ if (wzAesMode)
+ {
+ result = _wzAesDecoderSpec->ReadHeader(inStream);
+ if (result == S_OK)
+ {
+ if (!_wzAesDecoderSpec->Init_and_CheckPassword())
+ {
+ res = NExtract::NOperationResult::kWrongPassword;
+ return S_OK;
+ }
+ }
+ }
+ else if (pkAesMode)
+ {
+ isFullStreamExpected = false;
+ result =_pkAesDecoderSpec->ReadHeader(inStream, item.Crc, item.Size);
+ if (result == S_OK)
+ {
+ bool passwOK;
+ result = _pkAesDecoderSpec->Init_and_CheckPassword(passwOK);
+ if (result == S_OK && !passwOK)
+ {
+ res = NExtract::NOperationResult::kWrongPassword;
+ return S_OK;
+ }
+ }
+ }
+ else
+ {
+ result = _zipCryptoDecoderSpec->ReadHeader(inStream);
+ if (result == S_OK)
+ {
+ _zipCryptoDecoderSpec->Init_BeforeDecode();
+
+ /* Info-ZIP modification to ZipCrypto format:
+ if bit 3 of the general purpose bit flag is set,
+ it uses high byte of 16-bit File Time.
+ Info-ZIP code probably writes 2 bytes of File Time.
+ We check only 1 byte. */
+
+ // UInt32 v1 = GetUi16(_zipCryptoDecoderSpec->_header + NCrypto::NZip::kHeaderSize - 2);
+ // UInt32 v2 = (item.HasDescriptor() ? (item.Time & 0xFFFF) : (item.Crc >> 16));
+
+ Byte v1 = _zipCryptoDecoderSpec->_header[NCrypto::NZip::kHeaderSize - 1];
+ Byte v2 = (Byte)(item.HasDescriptor() ? (item.Time >> 8) : (item.Crc >> 24));
+
+ if (v1 != v2)
+ {
+ res = NExtract::NOperationResult::kWrongPassword;
+ return S_OK;
+ }
+ }
+ }
+ }
+
+ if (result == S_OK)
+ {
+ CMyComPtr<ICompressSetFinishMode> setFinishMode;
+ coder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode);
+ if (setFinishMode)
+ {
+ RINOK(setFinishMode->SetFinishMode(BoolToUInt(true)))
+ }
+
+ const UInt64 coderPackSize = limitedStreamSpec->GetRem();
+
+ if (id == NFileHeader::NCompressionMethod::kStore && item.IsEncrypted())
+ {
+ // for debug : we can disable this code (kStore + 50), if we want to test CopyCoder+Filter
+ // here we use filter without CopyCoder
+ readFromFilter = false;
+
+ COutStreamWithPadPKCS7 *padStreamSpec = NULL;
+ CMyComPtr<ISequentialOutStream> padStream;
+ UInt32 padSize = 0;
+
+ if (pkAesMode)
+ {
+ padStreamSpec = new COutStreamWithPadPKCS7;
+ padStream = padStreamSpec;
+ padSize = _pkAesDecoderSpec->GetPadSize((UInt32)item.Size);
+ padStreamSpec->SetStream(outStream);
+ padStreamSpec->Init(item.Size, padSize);
+ }
+
+ // Here we decode minimal required size, including padding
+ const UInt64 expectedSize = item.Size + padSize;
+ UInt64 size = coderPackSize;
+ if (item.Size > coderPackSize)
+ headersError = true;
+ else if (expectedSize != coderPackSize)
+ {
+ headersError = true;
+ if (coderPackSize > expectedSize)
+ size = expectedSize;
+ }
+
+ result = filterStreamSpec->Code(inStream, padStream ?
+ (ISequentialOutStream *)padStream :
+ (ISequentialOutStream *)outStream,
+ NULL, &size, compressProgress);
+
+ if (outStreamSpec->GetSize() != item.Size)
+ truncatedError = true;
+
+ if (pkAesMode)
+ {
+ if (padStreamSpec->GetSize() != size)
+ truncatedError = true;
+ if (padStreamSpec->WasPadFailure())
+ padError = true;
+ }
+ }
+ else
+ {
+ if (item.IsEncrypted())
+ {
+ readFromFilter = true;
+ inStreamReleaser.FilterCoder = filterStreamSpec;
+ RINOK(filterStreamSpec->SetInStream(inStream))
+
+ /* IFilter::Init() does nothing in all zip crypto filters.
+ So we can call any Initialize function in CFilterCoder. */
+
+ RINOK(filterStreamSpec->Init_NoSubFilterInit())
+ // RINOK(filterStreamSpec->SetOutStreamSize(NULL));
+ }
+
+ try {
+ result = coder->Code(readFromFilter ?
+ (ISequentialInStream *)filterStream :
+ (ISequentialInStream *)inStream,
+ outStream,
+ isFullStreamExpected ? &coderPackSize : NULL,
+ // NULL,
+ useUnpackLimit ? &item.Size : NULL,
+ compressProgress);
+ } catch (...) { return E_FAIL; }
+
+ if (result == S_OK)
+ {
+ CMyComPtr<ICompressGetInStreamProcessedSize> getInStreamProcessedSize;
+ coder->QueryInterface(IID_ICompressGetInStreamProcessedSize, (void **)&getInStreamProcessedSize);
+ if (getInStreamProcessedSize && setFinishMode)
+ {
+ UInt64 processed;
+ RINOK(getInStreamProcessedSize->GetInStreamProcessedSize(&processed))
+ if (processed != (UInt64)(Int64)-1)
+ {
+ if (pkAesMode)
+ {
+ const UInt32 padSize = _pkAesDecoderSpec->GetPadSize((UInt32)processed);
+ if (processed + padSize > coderPackSize)
+ truncatedError = true;
+ else if (processed + padSize < coderPackSize)
+ dataAfterEnd = true;
+ else
+ {
+ {
+ // here we check PKCS7 padding data from reminder (it can be inside stream buffer in coder).
+ CMyComPtr<ICompressReadUnusedFromInBuf> readInStream;
+ coder->QueryInterface(IID_ICompressReadUnusedFromInBuf, (void **)&readInStream);
+ // CCopyCoder() for kStore doesn't read data outside of (item.Size)
+ if (readInStream || id == NFileHeader::NCompressionMethod::kStore)
+ {
+ // change pad size, if we support another block size in ZipStrong.
+ // here we request more data to detect error with data after end.
+ const UInt32 kBufSize = NCrypto::NZipStrong::kAesPadAllign + 16;
+ Byte buf[kBufSize];
+ UInt32 processedSize = 0;
+ if (readInStream)
+ {
+ RINOK(readInStream->ReadUnusedFromInBuf(buf, kBufSize, &processedSize))
+ }
+ if (processedSize > padSize)
+ dataAfterEnd = true;
+ else
+ {
+ size_t processedSize2 = kBufSize - processedSize;
+ result = ReadStream(filterStream, buf + processedSize, &processedSize2);
+ if (result == S_OK)
+ {
+ processedSize2 += processedSize;
+ if (processedSize2 > padSize)
+ dataAfterEnd = true;
+ else if (processedSize2 < padSize)
+ truncatedError = true;
+ else
+ for (unsigned i = 0; i < padSize; i++)
+ if (buf[i] != padSize)
+ padError = true;
+ }
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ if (processed < coderPackSize)
+ {
+ if (isFullStreamExpected)
+ dataAfterEnd = true;
+ }
+ else if (processed > coderPackSize)
+ {
+ // that case is additional check, that can show the bugs in code (coder)
+ truncatedError = true;
+ }
+ needReminderCheck = isFullStreamExpected;
+ }
+ }
+ }
+ }
+ }
+
+ if (result == S_OK && id == NFileHeader::NCompressionMethod::kLZMA)
+ if (!lzmaDecoderSpec->DecoderSpec->CheckFinishStatus(item.IsLzmaEOS()))
+ lzmaEosError = true;
+ }
+
+ if (result == S_FALSE)
+ return S_OK;
+
+ if (result == E_NOTIMPL)
+ {
+ res = NExtract::NOperationResult::kUnsupportedMethod;
+ return S_OK;
+ }
+
+ RINOK(result)
+ }
+
+ bool crcOK = true;
+ bool authOk = true;
+ if (needCRC)
+ crcOK = (outStreamSpec->GetCRC() == item.Crc);
+
+ if (useUnpackLimit)
+ if (outStreamSpec->GetSize() != item.Size)
+ truncatedError = true;
+
+ if (wzAesMode)
+ {
+ const UInt64 unpackSize = outStreamSpec->GetSize();
+ const UInt64 packSize = limitedStreamSpec->GetSize();
+ bool thereAreData = false;
+ // read to the end from filter or from packed stream
+ if (SkipStreamData(readFromFilter ?
+ (ISequentialInStream *)filterStream :
+ (ISequentialInStream *)inStream,
+ compressProgress, packSize, unpackSize, thereAreData) != S_OK)
+ authOk = false;
+ if (needReminderCheck && thereAreData)
+ dataAfterEnd = true;
+
+ if (limitedStreamSpec->GetRem() != 0)
+ truncatedError = true;
+ else
+ {
+ limitedStreamSpec->Init(NCrypto::NWzAes::kMacSize);
+ if (_wzAesDecoderSpec->CheckMac(inStream, authOk) != S_OK)
+ authOk = false;
+ }
+ }
+
+ res = NExtract::NOperationResult::kCRCError;
+
+ if (crcOK && authOk)
+ {
+ res = NExtract::NOperationResult::kOK;
+
+ if (dataAfterEnd)
+ res = NExtract::NOperationResult::kDataAfterEnd;
+ else if (padError)
+ res = NExtract::NOperationResult::kCRCError;
+ else if (truncatedError)
+ res = NExtract::NOperationResult::kUnexpectedEnd;
+ else if (headersError)
+ res = NExtract::NOperationResult::kHeadersError;
+ else if (lzmaEosError)
+ res = NExtract::NOperationResult::kHeadersError;
+ else if (badDescriptor)
+ res = NExtract::NOperationResult::kUnexpectedEnd;
+
+ // CheckDescriptor() supports only data descriptor with signature and
+ // it doesn't support "old" pkzip's data descriptor without signature.
+ // So we disable that check.
+ /*
+ if (item.HasDescriptor() && archive.CheckDescriptor(item) != S_OK)
+ res = NExtract::NOperationResult::kHeadersError;
+ */
+ }
+
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = m_Items.Size();
+ if (numItems == 0)
+ return S_OK;
+ UInt64 total = 0; // , totalPacked = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const CItemEx &item = m_Items[allFilesMode ? i : indices[i]];
+ total += item.Size;
+ // totalPacked += item.PackSize;
+ }
+ RINOK(extractCallback->SetTotal(total))
+
+ CZipDecoder myDecoder;
+ UInt64 cur_Unpacked, cur_Packed;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ for (i = 0;; i++,
+ lps->OutSize += cur_Unpacked,
+ lps->InSize += cur_Packed)
+ {
+ RINOK(lps->SetCur())
+ if (i >= numItems)
+ return S_OK;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ CItemEx item = m_Items[index];
+ cur_Unpacked = item.Size;
+ cur_Packed = item.PackSize;
+
+ const bool isLocalOffsetOK = m_Archive.IsLocalOffsetOK(item);
+ const bool skip = !isLocalOffsetOK && !item.IsDir();
+ const Int32 askMode = skip ?
+ NExtract::NAskMode::kSkip : testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+ if (!isLocalOffsetOK)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kUnavailable))
+ continue;
+ }
+
+ bool headersError = false;
+
+ if (!item.FromLocal)
+ {
+ bool isAvail = true;
+ const HRESULT hres = m_Archive.Read_LocalItem_After_CdItem(item, isAvail, headersError);
+ if (hres == S_FALSE)
+ {
+ if (item.IsDir() || realOutStream || testMode)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(
+ isAvail ?
+ NExtract::NOperationResult::kHeadersError :
+ NExtract::NOperationResult::kUnavailable))
+ }
+ continue;
+ }
+ RINOK(hres)
+ }
+
+ if (item.IsDir())
+ {
+ // if (!testMode)
+ {
+ RINOK(extractCallback->PrepareOperation(askMode))
+ realOutStream.Release();
+ RINOK(extractCallback->SetOperationResult(NExtract::NOperationResult::kOK))
+ }
+ continue;
+ }
+
+ if (!testMode && !realOutStream)
+ continue;
+
+ RINOK(extractCallback->PrepareOperation(askMode))
+
+ Int32 res;
+ const HRESULT hres = myDecoder.Decode(
+ EXTERNAL_CODECS_VARS
+ m_Archive, item, realOutStream, extractCallback,
+ progress,
+ #ifndef Z7_ST
+ _props._numThreads, _props._memUsage_Decompress,
+ #endif
+ res);
+
+ RINOK(hres)
+ realOutStream.Release();
+
+ if (res == NExtract::NOperationResult::kOK && headersError)
+ res = NExtract::NOperationResult::kHeadersError;
+
+ RINOK(extractCallback->SetOperationResult(res))
+ }
+
+ COM_TRY_END
+}
+
+IMPL_ISetCompressCodecsInfo
+
+}}
diff --git a/CPP/7zip/Archive/Zip/ZipHandler.h b/CPP/7zip/Archive/Zip/ZipHandler.h
new file mode 100644
index 0000000..1f38bff
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipHandler.h
@@ -0,0 +1,94 @@
+// Zip/Handler.h
+
+#ifndef ZIP7_INC_ZIP_HANDLER_H
+#define ZIP7_INC_ZIP_HANDLER_H
+
+#include "../../../Common/DynamicBuffer.h"
+#include "../../ICoder.h"
+#include "../IArchive.h"
+
+#include "../../Common/CreateCoder.h"
+
+#include "ZipCompressionMode.h"
+#include "ZipIn.h"
+
+namespace NArchive {
+namespace NZip {
+
+const unsigned kNumMethodNames1 = NFileHeader::NCompressionMethod::kZstdPk + 1;
+const unsigned kMethodNames2Start = NFileHeader::NCompressionMethod::kZstdWz;
+const unsigned kNumMethodNames2 = NFileHeader::NCompressionMethod::kWzAES + 1 - kMethodNames2Start;
+
+extern const char * const kMethodNames1[kNumMethodNames1];
+extern const char * const kMethodNames2[kNumMethodNames2];
+
+
+class CHandler Z7_final:
+ public IInArchive,
+ // public IArchiveGetRawProps,
+ public IOutArchive,
+ public ISetProperties,
+ Z7_PUBLIC_ISetCompressCodecsInfo_IFEC
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(IInArchive)
+ // Z7_COM_QI_ENTRY(IArchiveGetRawProps)
+ Z7_COM_QI_ENTRY(IOutArchive)
+ Z7_COM_QI_ENTRY(ISetProperties)
+ Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(IInArchive)
+ // Z7_IFACE_COM7_IMP(IArchiveGetRawProps)
+ Z7_IFACE_COM7_IMP(IOutArchive)
+ Z7_IFACE_COM7_IMP(ISetProperties)
+ DECL_ISetCompressCodecsInfo
+
+private:
+ CObjectVector<CItemEx> m_Items;
+ CInArchive m_Archive;
+
+ CBaseProps _props;
+ CHandlerTimeOptions TimeOptions;
+
+ int m_MainMethod;
+ bool m_ForceAesMode;
+
+ bool _removeSfxBlock;
+ bool m_ForceLocal;
+ bool m_ForceUtf8;
+ bool _force_SeqOutMode; // for creation
+ bool _force_OpenSeq;
+ bool _forceCodePage;
+ UInt32 _specifiedCodePage;
+
+ DECL_EXTERNAL_CODECS_VARS
+
+ void InitMethodProps()
+ {
+ _props.Init();
+ TimeOptions.Init();
+ TimeOptions.Prec = k_PropVar_TimePrec_0;
+ m_MainMethod = -1;
+ m_ForceAesMode = false;
+ _removeSfxBlock = false;
+ m_ForceLocal = false;
+ m_ForceUtf8 = false;
+ _force_SeqOutMode = false;
+ _force_OpenSeq = false;
+ _forceCodePage = false;
+ _specifiedCodePage = CP_OEMCP;
+ }
+
+ // void MarkAltStreams(CObjectVector<CItemEx> &items);
+
+ HRESULT GetOutProperty(IArchiveUpdateCallback *callback, UInt32 callbackIndex, Int32 arcIndex, PROPID propID, PROPVARIANT *value);
+
+public:
+ CHandler();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
new file mode 100644
index 0000000..19699b5
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipHandlerOut.cpp
@@ -0,0 +1,618 @@
+// ZipHandlerOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/TimeUtils.h"
+
+#include "../../IPassword.h"
+
+#include "../../Common/OutBuffer.h"
+
+#include "../../Crypto/WzAes.h"
+
+#include "../Common/ItemNameUtils.h"
+#include "../Common/ParseProperties.h"
+
+#include "ZipHandler.h"
+#include "ZipUpdate.h"
+
+using namespace NWindows;
+using namespace NCOM;
+using namespace NTime;
+
+namespace NArchive {
+namespace NZip {
+
+Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *timeType))
+{
+ *timeType = TimeOptions.Prec;
+ return S_OK;
+}
+
+static bool IsSimpleAsciiString(const wchar_t *s)
+{
+ for (;;)
+ {
+ wchar_t c = *s++;
+ if (c == 0)
+ return true;
+ if (c < 0x20 || c > 0x7F)
+ return false;
+ }
+}
+
+
+static int FindZipMethod(const char *s, const char * const *names, unsigned num)
+{
+ for (unsigned i = 0; i < num; i++)
+ {
+ const char *name = names[i];
+ if (name && StringsAreEqualNoCase_Ascii(s, name))
+ return (int)i;
+ }
+ return -1;
+}
+
+static int FindZipMethod(const char *s)
+{
+ int k = FindZipMethod(s, kMethodNames1, kNumMethodNames1);
+ if (k >= 0)
+ return k;
+ k = FindZipMethod(s, kMethodNames2, kNumMethodNames2);
+ if (k >= 0)
+ return (int)kMethodNames2Start + k;
+ return -1;
+}
+
+
+#define COM_TRY_BEGIN2 try {
+#define COM_TRY_END2 } \
+catch(const CSystemException &e) { return e.ErrorCode; } \
+catch(...) { return E_OUTOFMEMORY; }
+
+static HRESULT GetTime(IArchiveUpdateCallback *callback, unsigned index, PROPID propID, FILETIME &filetime)
+{
+ filetime.dwHighDateTime = filetime.dwLowDateTime = 0;
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(index, propID, &prop))
+ if (prop.vt == VT_FILETIME)
+ filetime = prop.filetime;
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *callback))
+{
+ COM_TRY_BEGIN2
+
+ if (m_Archive.IsOpen())
+ {
+ if (!m_Archive.CanUpdate())
+ return E_NOTIMPL;
+ }
+
+ CObjectVector<CUpdateItem> updateItems;
+ updateItems.ClearAndReserve(numItems);
+
+ bool thereAreAesUpdates = false;
+ UInt64 largestSize = 0;
+ bool largestSizeDefined = false;
+
+ #ifdef _WIN32
+ const UINT oemCP = GetOEMCP();
+ #endif
+
+ UString name;
+ CUpdateItem ui;
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ Int32 newData;
+ Int32 newProps;
+ UInt32 indexInArc;
+
+ if (!callback)
+ return E_FAIL;
+
+ RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArc))
+
+ name.Empty();
+ ui.Clear();
+
+ ui.NewProps = IntToBool(newProps);
+ ui.NewData = IntToBool(newData);
+ ui.IndexInArc = (int)indexInArc;
+ ui.IndexInClient = i;
+
+ bool existInArchive = (indexInArc != (UInt32)(Int32)-1);
+ if (existInArchive)
+ {
+ const CItemEx &inputItem = m_Items[indexInArc];
+ if (inputItem.IsAesEncrypted())
+ thereAreAesUpdates = true;
+ if (!IntToBool(newProps))
+ ui.IsDir = inputItem.IsDir();
+ // ui.IsAltStream = inputItem.IsAltStream();
+ }
+
+ if (IntToBool(newProps))
+ {
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidAttrib, &prop))
+ if (prop.vt == VT_EMPTY)
+ ui.Attrib = 0;
+ else if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ else
+ ui.Attrib = prop.ulVal;
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidPath, &prop))
+ if (prop.vt == VT_EMPTY)
+ {
+ // name.Empty();
+ }
+ else if (prop.vt != VT_BSTR)
+ return E_INVALIDARG;
+ else
+ name = prop.bstrVal;
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidIsDir, &prop))
+ if (prop.vt == VT_EMPTY)
+ ui.IsDir = false;
+ else if (prop.vt != VT_BOOL)
+ return E_INVALIDARG;
+ else
+ ui.IsDir = (prop.boolVal != VARIANT_FALSE);
+ }
+
+ /*
+ {
+ bool isAltStream = false;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidIsAltStream, &prop));
+ if (prop.vt == VT_BOOL)
+ isAltStream = (prop.boolVal != VARIANT_FALSE);
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+
+ if (isAltStream)
+ {
+ if (ui.IsDir)
+ return E_INVALIDARG;
+ int delim = name.ReverseFind(L':');
+ if (delim >= 0)
+ {
+ name.Delete(delim, 1);
+ name.Insert(delim, UString(k_SpecName_NTFS_STREAM));
+ ui.IsAltStream = true;
+ }
+ }
+ }
+ */
+
+ // 22.00 : kpidTimeType is useless here : the code was disabled
+ /*
+ {
+ CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidTimeType, &prop));
+ if (prop.vt == VT_UI4)
+ ui.NtfsTime_IsDefined = (prop.ulVal == NFileTimeType::kWindows);
+ else
+ ui.NtfsTime_IsDefined = _Write_NtfsTime;
+ }
+ */
+
+ if (TimeOptions.Write_MTime.Val) RINOK (GetTime (callback, i, kpidMTime, ui.Ntfs_MTime))
+ if (TimeOptions.Write_ATime.Val) RINOK (GetTime (callback, i, kpidATime, ui.Ntfs_ATime))
+ if (TimeOptions.Write_CTime.Val) RINOK (GetTime (callback, i, kpidCTime, ui.Ntfs_CTime))
+
+ if (TimeOptions.Prec != k_PropVar_TimePrec_DOS)
+ {
+ if (TimeOptions.Prec == k_PropVar_TimePrec_Unix ||
+ TimeOptions.Prec == k_PropVar_TimePrec_Base)
+ ui.Write_UnixTime = ! FILETIME_IsZero (ui.Ntfs_MTime);
+ else
+ {
+ /*
+ // if we want to store zero timestamps as zero timestamp, use the following:
+ ui.Write_NtfsTime =
+ _Write_MTime ||
+ _Write_ATime ||
+ _Write_CTime;
+ */
+
+ // We treat zero timestamp as no timestamp
+ ui.Write_NtfsTime =
+ ! FILETIME_IsZero (ui.Ntfs_MTime) ||
+ ! FILETIME_IsZero (ui.Ntfs_ATime) ||
+ ! FILETIME_IsZero (ui.Ntfs_CTime);
+ }
+ }
+
+ /*
+ how 0 in dos time works:
+ win10 explorer extract : some random date 1601-04-25.
+ winrar 6.10 : write time.
+ 7zip : MTime of archive is used
+ how 0 in tar works:
+ winrar 6.10 : 1970
+ 0 in dos field can show that there is no timestamp.
+ we write correct 1970-01-01 in dos field, to support correct extraction in Win10.
+ */
+
+ UtcFileTime_To_LocalDosTime(ui.Ntfs_MTime, ui.Time);
+
+ NItemName::ReplaceSlashes_OsToUnix(name);
+
+ bool needSlash = ui.IsDir;
+ const wchar_t kSlash = L'/';
+ if (!name.IsEmpty())
+ {
+ if (name.Back() == kSlash)
+ {
+ if (!ui.IsDir)
+ return E_INVALIDARG;
+ needSlash = false;
+ }
+ }
+ if (needSlash)
+ name += kSlash;
+
+ const UINT codePage = _forceCodePage ? _specifiedCodePage : CP_OEMCP;
+ bool tryUtf8 = true;
+
+ /*
+ Windows 10 allows users to set UTF-8 in Region Settings via option:
+ "Beta: Use Unicode UTF-8 for worldwide language support"
+ In that case Windows uses CP_UTF8 when we use CP_OEMCP.
+ 21.02 fixed:
+ we set UTF-8 mark for non-latin files for such UTF-8 mode in Windows.
+ we write additional Info-Zip Utf-8 FileName Extra for non-latin names/
+ */
+
+ if ((codePage != CP_UTF8) &&
+ #ifdef _WIN32
+ (m_ForceLocal || !m_ForceUtf8) && (oemCP != CP_UTF8)
+ #else
+ (m_ForceLocal && !m_ForceUtf8)
+ #endif
+ )
+ {
+ bool defaultCharWasUsed;
+ ui.Name = UnicodeStringToMultiByte(name, codePage, '_', defaultCharWasUsed);
+ tryUtf8 = (!m_ForceLocal && (defaultCharWasUsed ||
+ MultiByteToUnicodeString(ui.Name, codePage) != name));
+ }
+
+ const bool isNonLatin = !name.IsAscii();
+
+ if (tryUtf8)
+ {
+ ui.IsUtf8 = isNonLatin;
+ ConvertUnicodeToUTF8(name, ui.Name);
+
+ #ifndef _WIN32
+ if (ui.IsUtf8 && !CheckUTF8_AString(ui.Name))
+ {
+ // if it's non-Windows and there are non-UTF8 characters we clear UTF8-flag
+ ui.IsUtf8 = false;
+ }
+ #endif
+ }
+ else if (isNonLatin)
+ Convert_Unicode_To_UTF8_Buf(name, ui.Name_Utf);
+
+ if (ui.Name.Len() >= (1 << 16)
+ || ui.Name_Utf.Size() >= (1 << 16) - 128)
+ return E_INVALIDARG;
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidComment, &prop))
+ if (prop.vt == VT_EMPTY)
+ {
+ // ui.Comment.Free();
+ }
+ else if (prop.vt != VT_BSTR)
+ return E_INVALIDARG;
+ else
+ {
+ UString s = prop.bstrVal;
+ AString a;
+ if (ui.IsUtf8)
+ ConvertUnicodeToUTF8(s, a);
+ else
+ {
+ bool defaultCharWasUsed;
+ a = UnicodeStringToMultiByte(s, codePage, '_', defaultCharWasUsed);
+ }
+ if (a.Len() >= (1 << 16))
+ return E_INVALIDARG;
+ ui.Comment.CopyFrom((const Byte *)(const char *)a, a.Len());
+ }
+ }
+
+
+ /*
+ if (existInArchive)
+ {
+ const CItemEx &itemInfo = m_Items[indexInArc];
+ // ui.Commented = itemInfo.IsCommented();
+ ui.Commented = false;
+ if (ui.Commented)
+ {
+ ui.CommentRange.Position = itemInfo.GetCommentPosition();
+ ui.CommentRange.Size = itemInfo.CommentSize;
+ }
+ }
+ else
+ ui.Commented = false;
+ */
+ }
+
+
+ if (IntToBool(newData))
+ {
+ UInt64 size = 0;
+ if (!ui.IsDir)
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidSize, &prop))
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ size = prop.uhVal.QuadPart;
+ if (largestSize < size)
+ largestSize = size;
+ largestSizeDefined = true;
+ }
+ ui.Size = size;
+ }
+
+ updateItems.Add(ui);
+ }
+
+
+ CMyComPtr<ICryptoGetTextPassword2> getTextPassword;
+ {
+ CMyComPtr<IArchiveUpdateCallback> udateCallBack2(callback);
+ udateCallBack2.QueryInterface(IID_ICryptoGetTextPassword2, &getTextPassword);
+ }
+ CCompressionMethodMode options;
+ (CBaseProps &)options = _props;
+ options.DataSizeReduce = largestSize;
+ options.DataSizeReduce_Defined = largestSizeDefined;
+
+ options.Password_Defined = false;
+ options.Password.Wipe_and_Empty();
+ if (getTextPassword)
+ {
+ CMyComBSTR_Wipe password;
+ Int32 passwordIsDefined;
+ RINOK(getTextPassword->CryptoGetTextPassword2(&passwordIsDefined, &password))
+ options.Password_Defined = IntToBool(passwordIsDefined);
+ if (options.Password_Defined)
+ {
+ if (!m_ForceAesMode)
+ options.IsAesMode = thereAreAesUpdates;
+
+ if (!IsSimpleAsciiString(password))
+ return E_INVALIDARG;
+ if (password)
+ UnicodeStringToMultiByte2(options.Password, (LPCOLESTR)password, CP_OEMCP);
+ if (options.IsAesMode)
+ {
+ if (options.Password.Len() > NCrypto::NWzAes::kPasswordSizeMax)
+ return E_INVALIDARG;
+ }
+ }
+ }
+
+
+ int mainMethod = m_MainMethod;
+
+ if (mainMethod < 0)
+ {
+ if (!_props._methods.IsEmpty())
+ {
+ const AString &methodName = _props._methods.Front().MethodName;
+ if (!methodName.IsEmpty())
+ {
+ mainMethod = FindZipMethod(methodName);
+ if (mainMethod < 0)
+ {
+ CMethodId methodId;
+ UInt32 numStreams;
+ bool isFilter;
+ if (FindMethod_Index(EXTERNAL_CODECS_VARS methodName, true,
+ methodId, numStreams, isFilter) < 0)
+ return E_NOTIMPL;
+ if (numStreams != 1)
+ return E_NOTIMPL;
+ if (methodId == kMethodId_BZip2)
+ mainMethod = NFileHeader::NCompressionMethod::kBZip2;
+ else
+ {
+ if (methodId < kMethodId_ZipBase)
+ return E_NOTIMPL;
+ methodId -= kMethodId_ZipBase;
+ if (methodId > 0xFF)
+ return E_NOTIMPL;
+ mainMethod = (int)methodId;
+ }
+ }
+ }
+ }
+ }
+
+ if (mainMethod < 0)
+ mainMethod = (Byte)(((_props.GetLevel() == 0) ?
+ NFileHeader::NCompressionMethod::kStore :
+ NFileHeader::NCompressionMethod::kDeflate));
+ else
+ mainMethod = (Byte)mainMethod;
+
+ options.MethodSequence.Add((Byte)mainMethod);
+
+ if (mainMethod != NFileHeader::NCompressionMethod::kStore)
+ options.MethodSequence.Add(NFileHeader::NCompressionMethod::kStore);
+
+ options.Force_SeqOutMode = _force_SeqOutMode;
+
+ CUpdateOptions uo;
+ uo.Write_MTime = TimeOptions.Write_MTime.Val;
+ uo.Write_ATime = TimeOptions.Write_ATime.Val;
+ uo.Write_CTime = TimeOptions.Write_CTime.Val;
+ /*
+ uo.Write_NtfsTime = _Write_NtfsTime &&
+ (_Write_MTime || _Write_ATime || _Write_CTime);
+ uo.Write_UnixTime = _Write_UnixTime;
+ */
+
+ return Update(
+ EXTERNAL_CODECS_VARS
+ m_Items, updateItems, outStream,
+ m_Archive.IsOpen() ? &m_Archive : NULL, _removeSfxBlock,
+ uo, options, callback);
+
+ COM_TRY_END2
+}
+
+
+
+Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
+{
+ InitMethodProps();
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ UString name = names[i];
+ name.MakeLower_Ascii();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+
+ const PROPVARIANT &prop = values[i];
+
+ if (name.IsEqualTo_Ascii_NoCase("em"))
+ {
+ if (prop.vt != VT_BSTR)
+ return E_INVALIDARG;
+ {
+ const wchar_t *m = prop.bstrVal;
+ if (IsString1PrefixedByString2_NoCase_Ascii(m, "aes"))
+ {
+ m += 3;
+ if (StringsAreEqual_Ascii(m, "128"))
+ _props.AesKeyMode = 1;
+ else if (StringsAreEqual_Ascii(m, "192"))
+ _props.AesKeyMode = 2;
+ else if (StringsAreEqual_Ascii(m, "256") || m[0] == 0)
+ _props.AesKeyMode = 3;
+ else
+ return E_INVALIDARG;
+ _props.IsAesMode = true;
+ m_ForceAesMode = true;
+ }
+ else if (StringsAreEqualNoCase_Ascii(m, "ZipCrypto"))
+ {
+ _props.IsAesMode = false;
+ m_ForceAesMode = true;
+ }
+ else
+ return E_INVALIDARG;
+ }
+ }
+
+
+
+ else if (name.IsEqualTo("cl"))
+ {
+ RINOK(PROPVARIANT_to_bool(prop, m_ForceLocal))
+ if (m_ForceLocal)
+ m_ForceUtf8 = false;
+ }
+ else if (name.IsEqualTo("cu"))
+ {
+ RINOK(PROPVARIANT_to_bool(prop, m_ForceUtf8))
+ if (m_ForceUtf8)
+ m_ForceLocal = false;
+ }
+ else if (name.IsEqualTo("cp"))
+ {
+ UInt32 cp = CP_OEMCP;
+ RINOK(ParsePropToUInt32(L"", prop, cp))
+ _forceCodePage = true;
+ _specifiedCodePage = cp;
+ }
+ else if (name.IsEqualTo("rsfx"))
+ {
+ RINOK(PROPVARIANT_to_bool(prop, _removeSfxBlock))
+ }
+ else if (name.IsEqualTo("rws"))
+ {
+ RINOK(PROPVARIANT_to_bool(prop, _force_SeqOutMode))
+ }
+ else if (name.IsEqualTo("ros"))
+ {
+ RINOK(PROPVARIANT_to_bool(prop, _force_OpenSeq))
+ }
+ else
+ {
+ if (name.IsEqualTo_Ascii_NoCase("m") && prop.vt == VT_UI4)
+ {
+ UInt32 id = prop.ulVal;
+ if (id > 0xFF)
+ return E_INVALIDARG;
+ m_MainMethod = (int)id;
+ }
+ else
+ {
+ bool processed = false;
+ RINOK(TimeOptions.Parse(name, prop, processed))
+ if (!processed)
+ {
+ RINOK(_props.SetProperty(name, prop))
+ }
+ }
+ // RINOK(_props.MethodInfo.ParseParamsFromPROPVARIANT(name, prop));
+ }
+ }
+
+ _props._methods.DeleteFrontal(_props.GetNumEmptyMethods());
+ if (_props._methods.Size() > 1)
+ return E_INVALIDARG;
+ if (_props._methods.Size() == 1)
+ {
+ const AString &methodName = _props._methods[0].MethodName;
+
+ if (!methodName.IsEmpty())
+ {
+ const char *end;
+ UInt32 id = ConvertStringToUInt32(methodName, &end);
+ if (*end == 0 && id <= 0xFF)
+ m_MainMethod = (int)id;
+ else if (methodName.IsEqualTo_Ascii_NoCase("Copy")) // it's alias for "Store"
+ m_MainMethod = 0;
+ }
+ }
+
+ return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Zip/ZipHeader.h b/CPP/7zip/Archive/Zip/ZipHeader.h
new file mode 100644
index 0000000..038d49d
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipHeader.h
@@ -0,0 +1,201 @@
+// ZipHeader.h
+
+#ifndef ZIP7_INC_ARCHIVE_ZIP_HEADER_H
+#define ZIP7_INC_ARCHIVE_ZIP_HEADER_H
+
+#include "../../../Common/MyTypes.h"
+
+namespace NArchive {
+namespace NZip {
+
+const unsigned kMarkerSize = 4;
+
+namespace NSignature
+{
+ const UInt32 kLocalFileHeader = 0x04034B50;
+ const UInt32 kDataDescriptor = 0x08074B50;
+ const UInt32 kCentralFileHeader = 0x02014B50;
+ const UInt32 kEcd = 0x06054B50;
+ const UInt32 kEcd64 = 0x06064B50;
+ const UInt32 kEcd64Locator = 0x07064B50;
+ const UInt32 kSpan = 0x08074B50;
+ const UInt32 kNoSpan = 0x30304B50; // PK00, replaces kSpan, if there is only 1 segment
+}
+
+const unsigned kLocalHeaderSize = 4 + 26; // including signature
+const unsigned kDataDescriptorSize32 = 4 + 4 + 4 * 2; // including signature
+const unsigned kDataDescriptorSize64 = 4 + 4 + 8 * 2; // including signature
+const unsigned kCentralHeaderSize = 4 + 42; // including signature
+
+const unsigned kEcdSize = 22; // including signature
+const unsigned kEcd64_MainSize = 44;
+const unsigned kEcd64_FullSize = 12 + kEcd64_MainSize;
+const unsigned kEcd64Locator_Size = 20;
+
+namespace NFileHeader
+{
+ namespace NCompressionMethod
+ {
+ enum EType
+ {
+ kStore = 0,
+ kShrink = 1,
+ kReduce1 = 2,
+ kReduce2 = 3,
+ kReduce3 = 4,
+ kReduce4 = 5,
+ kImplode = 6,
+ kTokenize = 7,
+ kDeflate = 8,
+ kDeflate64 = 9,
+ kPKImploding = 10,
+
+ kBZip2 = 12,
+
+ kLZMA = 14,
+
+ kTerse = 18,
+ kLz77 = 19,
+ kZstdPk = 20,
+
+ kZstdWz = 93,
+ kMP3 = 94,
+ kXz = 95,
+ kJpeg = 96,
+ kWavPack = 97,
+ kPPMd = 98,
+ kWzAES = 99
+ };
+
+ const Byte kMadeByProgramVersion = 63;
+
+ const Byte kExtractVersion_Default = 10;
+ const Byte kExtractVersion_Dir = 20;
+ const Byte kExtractVersion_ZipCrypto = 20;
+ const Byte kExtractVersion_Deflate = 20;
+ const Byte kExtractVersion_Deflate64 = 21;
+ const Byte kExtractVersion_Zip64 = 45;
+ const Byte kExtractVersion_BZip2 = 46;
+ const Byte kExtractVersion_Aes = 51;
+ const Byte kExtractVersion_LZMA = 63;
+ const Byte kExtractVersion_PPMd = 63;
+ const Byte kExtractVersion_Xz = 20; // test it
+ }
+
+ namespace NExtraID
+ {
+ enum
+ {
+ kZip64 = 0x01,
+ kNTFS = 0x0A,
+ kUnix0 = 0x0D, // Info-ZIP : (UNIX) PK
+ kStrongEncrypt = 0x17,
+ kIzNtSecurityDescriptor = 0x4453,
+ kUnixTime = 0x5455, // "UT" (time) Info-ZIP
+ kUnix1 = 0x5855, // Info-ZIP
+ kIzUnicodeComment = 0x6375,
+ kIzUnicodeName = 0x7075,
+ kUnix2 = 0x7855, // Info-ZIP
+ kUnixN = 0x7875, // Info-ZIP
+ kWzAES = 0x9901,
+ kApkAlign = 0xD935
+ };
+ }
+
+ namespace NNtfsExtra
+ {
+ const UInt16 kTagTime = 1;
+ enum
+ {
+ kMTime = 0,
+ kATime,
+ kCTime
+ };
+ }
+
+ namespace NUnixTime
+ {
+ enum
+ {
+ kMTime = 0,
+ kATime,
+ kCTime
+ };
+ }
+
+ namespace NUnixExtra
+ {
+ enum
+ {
+ kATime = 0,
+ kMTime
+ };
+ }
+
+ namespace NFlags
+ {
+ const unsigned kEncrypted = 1 << 0;
+ const unsigned kLzmaEOS = 1 << 1;
+ const unsigned kDescriptorUsedMask = 1 << 3;
+ const unsigned kStrongEncrypted = 1 << 6;
+ const unsigned kUtf8 = 1 << 11;
+ const unsigned kAltStream = 1 << 14;
+
+ const unsigned kImplodeDictionarySizeMask = 1 << 1;
+ const unsigned kImplodeLiteralsOnMask = 1 << 2;
+
+ /*
+ const unsigned kDeflateTypeBitStart = 1;
+ const unsigned kNumDeflateTypeBits = 2;
+ const unsigned kNumDeflateTypes = (1 << kNumDeflateTypeBits);
+ const unsigned kDeflateTypeMask = (1 << kNumDeflateTypeBits) - 1;
+ */
+ }
+
+ namespace NHostOS
+ {
+ enum EEnum
+ {
+ kFAT = 0,
+ kAMIGA = 1,
+ kVMS = 2, // VAX/VMS
+ kUnix = 3,
+ kVM_CMS = 4,
+ kAtari = 5, // what if it's a minix filesystem? [cjh]
+ kHPFS = 6, // filesystem used by OS/2 (and NT 3.x)
+ kMac = 7,
+ kZ_System = 8,
+ kCPM = 9,
+ kTOPS20 = 10, // pkzip 2.50 NTFS
+ kNTFS = 11, // filesystem used by Windows NT
+ kQDOS = 12, // SMS/QDOS
+ kAcorn = 13, // Archimedes Acorn RISC OS
+ kVFAT = 14, // filesystem used by Windows 95, NT
+ kMVS = 15,
+ kBeOS = 16, // hybrid POSIX/database filesystem
+ kTandem = 17,
+ kOS400 = 18,
+ kOSX = 19
+ };
+ }
+
+
+ namespace NAmigaAttrib
+ {
+ const UInt32 kIFMT = 06000; // Amiga file type mask
+ const UInt32 kIFDIR = 04000; // Amiga directory
+ const UInt32 kIFREG = 02000; // Amiga regular file
+ const UInt32 kIHIDDEN = 00200; // to be supported in AmigaDOS 3.x
+ const UInt32 kISCRIPT = 00100; // executable script (text command file)
+ const UInt32 kIPURE = 00040; // allow loading into resident memory
+ const UInt32 kIARCHIVE = 00020; // not modified since bit was last set
+ const UInt32 kIREAD = 00010; // can be opened for reading
+ const UInt32 kIWRITE = 00004; // can be opened for writing
+ const UInt32 kIEXECUTE = 00002; // executable image, a loadable runfile
+ const UInt32 kIDELETE = 00001; // can be deleted
+ }
+}
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Zip/ZipIn.cpp b/CPP/7zip/Archive/Zip/ZipIn.cpp
new file mode 100644
index 0000000..4236df7
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipIn.cpp
@@ -0,0 +1,3485 @@
+// Archive/ZipIn.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../Common/DynamicBuffer.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/MyException.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#include "../IArchive.h"
+
+#include "ZipIn.h"
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+#define Get64(p) GetUi64(p)
+
+#define G16(offs, v) v = Get16(p + (offs))
+#define G32(offs, v) v = Get32(p + (offs))
+#define G64(offs, v) v = Get64(p + (offs))
+
+namespace NArchive {
+namespace NZip {
+
+/* we try to use same size of Buffer (1 << 17) for all tasks.
+ it allow to avoid reallocations and cache clearing. */
+
+static const size_t kSeqBufferSize = (size_t)1 << 17;
+
+/*
+Open()
+{
+ _inBufMode = false;
+ ReadVols()
+ FindCd();
+ TryEcd64()
+ SeekToVol()
+ FindMarker()
+ _inBufMode = true;
+ ReadHeaders()
+ _inBufMode = false;
+ ReadCd()
+ FindCd()
+ TryEcd64()
+ TryReadCd()
+ {
+ SeekToVol();
+ _inBufMode = true;
+ }
+ _inBufMode = true;
+ ReadLocals()
+ ReadCdItem()
+ ....
+}
+FindCd() writes to Buffer without touching (_inBufMode)
+*/
+
+/*
+ if (not defined ZIP_SELF_CHECK) : it reads CD and if error in first pass CD reading, it reads LOCALS-CD-MODE
+ if ( defined ZIP_SELF_CHECK) : it always reads CD and LOCALS-CD-MODE
+ use ZIP_SELF_CHECK to check LOCALS-CD-MODE for any zip archive
+*/
+
+// #define ZIP_SELF_CHECK
+
+
+struct CEcd
+{
+ UInt16 ThisDisk;
+ UInt16 CdDisk;
+ UInt16 NumEntries_in_ThisDisk;
+ UInt16 NumEntries;
+ UInt32 Size;
+ UInt32 Offset;
+ UInt16 CommentSize;
+
+ bool IsEmptyArc() const
+ {
+ return ThisDisk == 0
+ && CdDisk == 0
+ && NumEntries_in_ThisDisk == 0
+ && NumEntries == 0
+ && Size == 0
+ && Offset == 0 // test it
+ ;
+ }
+
+ void Parse(const Byte *p); // (p) doesn't include signature
+};
+
+void CEcd::Parse(const Byte *p)
+{
+ // (p) doesn't include signature
+ G16(0, ThisDisk);
+ G16(2, CdDisk);
+ G16(4, NumEntries_in_ThisDisk);
+ G16(6, NumEntries);
+ G32(8, Size);
+ G32(12, Offset);
+ G16(16, CommentSize);
+}
+
+
+void CCdInfo::ParseEcd32(const Byte *p)
+{
+ IsFromEcd64 = false;
+ // (p) includes signature
+ p += 4;
+ G16(0, ThisDisk);
+ G16(2, CdDisk);
+ G16(4, NumEntries_in_ThisDisk);
+ G16(6, NumEntries);
+ G32(8, Size);
+ G32(12, Offset);
+ G16(16, CommentSize);
+}
+
+void CCdInfo::ParseEcd64e(const Byte *p)
+{
+ IsFromEcd64 = true;
+ // (p) exclude signature
+ G16(0, VersionMade);
+ G16(2, VersionNeedExtract);
+ G32(4, ThisDisk);
+ G32(8, CdDisk);
+
+ G64(12, NumEntries_in_ThisDisk);
+ G64(20, NumEntries);
+ G64(28, Size);
+ G64(36, Offset);
+}
+
+
+struct CLocator
+{
+ UInt32 Ecd64Disk;
+ UInt32 NumDisks;
+ UInt64 Ecd64Offset;
+
+ CLocator(): Ecd64Disk(0), NumDisks(0), Ecd64Offset(0) {}
+
+ void Parse(const Byte *p)
+ {
+ G32(0, Ecd64Disk);
+ G64(4, Ecd64Offset);
+ G32(12, NumDisks);
+ }
+
+ bool IsEmptyArc() const
+ {
+ return Ecd64Disk == 0 && NumDisks == 0 && Ecd64Offset == 0;
+ }
+};
+
+
+
+
+void CInArchive::ClearRefs()
+{
+ StreamRef.Release();
+ Stream = NULL;
+ StartStream = NULL;
+ Callback = NULL;
+
+ Vols.Clear();
+}
+
+void CInArchive::Close()
+{
+ _cnt = 0;
+ DisableBufMode();
+
+ IsArcOpen = false;
+
+ IsArc = false;
+ IsZip64 = false;
+
+ IsApk = false;
+ IsCdUnsorted = false;
+
+ HeadersError = false;
+ HeadersWarning = false;
+ ExtraMinorError = false;
+
+ UnexpectedEnd = false;
+ LocalsWereRead = false;
+ LocalsCenterMerged = false;
+ NoCentralDir = false;
+ Overflow32bit = false;
+ Cd_NumEntries_Overflow_16bit = false;
+
+ MarkerIsFound = false;
+ MarkerIsSafe = false;
+
+ IsMultiVol = false;
+ UseDisk_in_SingleVol = false;
+ EcdVolIndex = 0;
+
+ ArcInfo.Clear();
+
+ ClearRefs();
+}
+
+
+
+HRESULT CInArchive::Seek_SavePos(UInt64 offset)
+{
+ // InitBuf();
+ // if (!Stream) return S_FALSE;
+ return Stream->Seek((Int64)offset, STREAM_SEEK_SET, &_streamPos);
+}
+
+
+/* SeekToVol() will keep the cached mode, if new volIndex is
+ same Vols.StreamIndex volume, and offset doesn't go out of cached region */
+
+HRESULT CInArchive::SeekToVol(int volIndex, UInt64 offset)
+{
+ if (volIndex != Vols.StreamIndex)
+ {
+ if (IsMultiVol && volIndex >= 0)
+ {
+ if ((unsigned)volIndex >= Vols.Streams.Size())
+ return S_FALSE;
+ if (!Vols.Streams[(unsigned)volIndex].Stream)
+ return S_FALSE;
+ Stream = Vols.Streams[(unsigned)volIndex].Stream;
+ }
+ else if (volIndex == -2)
+ {
+ if (!Vols.ZipStream)
+ return S_FALSE;
+ Stream = Vols.ZipStream;
+ }
+ else
+ Stream = StartStream;
+ Vols.StreamIndex = volIndex;
+ }
+ else
+ {
+ if (offset <= _streamPos)
+ {
+ const UInt64 back = _streamPos - offset;
+ if (back <= _bufCached)
+ {
+ _bufPos = _bufCached - (size_t)back;
+ return S_OK;
+ }
+ }
+ }
+ InitBuf();
+ return Seek_SavePos(offset);
+}
+
+
+HRESULT CInArchive::AllocateBuffer(size_t size)
+{
+ if (size <= Buffer.Size())
+ return S_OK;
+ /* in cached mode virtual_pos is not equal to phy_pos (_streamPos)
+ so we change _streamPos and do Seek() to virtual_pos before cache clearing */
+ if (_bufPos != _bufCached)
+ {
+ RINOK(Seek_SavePos(GetVirtStreamPos()))
+ }
+ InitBuf();
+ Buffer.AllocAtLeast(size);
+ if (!Buffer.IsAllocated())
+ return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+// ---------- ReadFromCache ----------
+// reads from cache and from Stream
+// move to next volume can be allowed if (CanStartNewVol) and only before first byte reading
+
+HRESULT CInArchive::ReadFromCache(Byte *data, unsigned size, unsigned &processed)
+{
+ HRESULT result = S_OK;
+ processed = 0;
+
+ for (;;)
+ {
+ if (size == 0)
+ return S_OK;
+
+ const size_t avail = GetAvail();
+
+ if (avail != 0)
+ {
+ unsigned cur = size;
+ if (cur > avail)
+ cur = (unsigned)avail;
+ memcpy(data, (const Byte *)Buffer + _bufPos, cur);
+
+ data += cur;
+ size -= cur;
+ processed += cur;
+
+ _bufPos += cur;
+ _cnt += cur;
+
+ CanStartNewVol = false;
+
+ continue;
+ }
+
+ InitBuf();
+
+ if (_inBufMode)
+ {
+ UInt32 cur = 0;
+ result = Stream->Read(Buffer, (UInt32)Buffer.Size(), &cur);
+ _bufPos = 0;
+ _bufCached = cur;
+ _streamPos += cur;
+ if (cur != 0)
+ CanStartNewVol = false;
+ if (result != S_OK)
+ break;
+ if (cur != 0)
+ continue;
+ }
+ else
+ {
+ size_t cur = size;
+ result = ReadStream(Stream, data, &cur);
+ data += cur;
+ size -= (unsigned)cur;
+ processed += (unsigned)cur;
+ _streamPos += cur;
+ _cnt += cur;
+ if (cur != 0)
+ {
+ CanStartNewVol = false;
+ break;
+ }
+ if (result != S_OK)
+ break;
+ }
+
+ if ( !IsMultiVol
+ || !CanStartNewVol
+ || Vols.StreamIndex < 0
+ || (unsigned)Vols.StreamIndex + 1 >= Vols.Streams.Size())
+ break;
+
+ const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex + 1];
+ if (!s.Stream)
+ break;
+ result = s.SeekToStart();
+ if (result != S_OK)
+ break;
+ Vols.StreamIndex++;
+ _streamPos = 0;
+ // Vols.NeedSeek = false;
+
+ Stream = s.Stream;
+ }
+
+ return result;
+}
+
+
+HRESULT CInArchive::ReadFromCache_FALSE(Byte *data, unsigned size)
+{
+ unsigned processed;
+ HRESULT res = ReadFromCache(data, size, processed);
+ if (res == S_OK && size != processed)
+ return S_FALSE;
+ return res;
+}
+
+
+static bool CheckDosTime(UInt32 dosTime)
+{
+ if (dosTime == 0)
+ return true;
+ unsigned month = (dosTime >> 21) & 0xF;
+ unsigned day = (dosTime >> 16) & 0x1F;
+ unsigned hour = (dosTime >> 11) & 0x1F;
+ unsigned min = (dosTime >> 5) & 0x3F;
+ unsigned sec = (dosTime & 0x1F) * 2;
+ if (month < 1 || month > 12 || day < 1 || day > 31 || hour > 23 || min > 59 || sec > 59)
+ return false;
+ return true;
+}
+
+API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size)
+{
+ if (size < 8)
+ return k_IsArc_Res_NEED_MORE;
+ if (p[0] != 'P')
+ return k_IsArc_Res_NO;
+
+ UInt32 sig = Get32(p);
+
+ if (sig == NSignature::kNoSpan || sig == NSignature::kSpan)
+ {
+ p += 4;
+ size -= 4;
+ }
+
+ sig = Get32(p);
+
+ if (sig == NSignature::kEcd64)
+ {
+ if (size < kEcd64_FullSize)
+ return k_IsArc_Res_NEED_MORE;
+
+ const UInt64 recordSize = Get64(p + 4);
+ if ( recordSize < kEcd64_MainSize
+ || recordSize > kEcd64_MainSize + (1 << 20))
+ return k_IsArc_Res_NO;
+ CCdInfo cdInfo;
+ cdInfo.ParseEcd64e(p + 12);
+ if (!cdInfo.IsEmptyArc())
+ return k_IsArc_Res_NO;
+ return k_IsArc_Res_YES; // k_IsArc_Res_YES_2;
+ }
+
+ if (sig == NSignature::kEcd)
+ {
+ if (size < kEcdSize)
+ return k_IsArc_Res_NEED_MORE;
+ CEcd ecd;
+ ecd.Parse(p + 4);
+ // if (ecd.cdSize != 0)
+ if (!ecd.IsEmptyArc())
+ return k_IsArc_Res_NO;
+ return k_IsArc_Res_YES; // k_IsArc_Res_YES_2;
+ }
+
+ if (sig != NSignature::kLocalFileHeader)
+ return k_IsArc_Res_NO;
+
+ if (size < kLocalHeaderSize)
+ return k_IsArc_Res_NEED_MORE;
+
+ p += 4;
+
+ {
+ const unsigned kPureHeaderSize = kLocalHeaderSize - 4;
+ unsigned i;
+ for (i = 0; i < kPureHeaderSize && p[i] == 0; i++);
+ if (i == kPureHeaderSize)
+ return k_IsArc_Res_NEED_MORE;
+ }
+
+ /*
+ if (p[0] >= 128) // ExtractVersion.Version;
+ return k_IsArc_Res_NO;
+ */
+
+ // ExtractVersion.Version = p[0];
+ // ExtractVersion.HostOS = p[1];
+ // Flags = Get16(p + 2);
+ // Method = Get16(p + 4);
+ /*
+ // 9.33: some zip archives contain incorrect value in timestamp. So we don't check it now
+ UInt32 dosTime = Get32(p + 6);
+ if (!CheckDosTime(dosTime))
+ return k_IsArc_Res_NO;
+ */
+ // Crc = Get32(p + 10);
+ // PackSize = Get32(p + 14);
+ // Size = Get32(p + 18);
+ const unsigned nameSize = Get16(p + 22);
+ unsigned extraSize = Get16(p + 24);
+ const UInt32 extraOffset = kLocalHeaderSize + (UInt32)nameSize;
+
+ /*
+ // 21.02: fixed. we don't use the following check
+ if (extraOffset + extraSize > (1 << 16))
+ return k_IsArc_Res_NO;
+ */
+
+ p -= 4;
+
+ {
+ size_t rem = size - kLocalHeaderSize;
+ if (rem > nameSize)
+ rem = nameSize;
+ const Byte *p2 = p + kLocalHeaderSize;
+ for (size_t i = 0; i < rem; i++)
+ if (p2[i] == 0)
+ {
+ // we support some "bad" zip archives that contain zeros after name
+ for (size_t k = i + 1; k < rem; k++)
+ if (p2[k] != 0)
+ return k_IsArc_Res_NO;
+ break;
+ /*
+ if (i != nameSize - 1)
+ return k_IsArc_Res_NO;
+ */
+ }
+ }
+
+ if (size < extraOffset)
+ return k_IsArc_Res_NEED_MORE;
+
+ if (extraSize > 0)
+ {
+ p += extraOffset;
+ size -= extraOffset;
+ while (extraSize != 0)
+ {
+ if (extraSize < 4)
+ {
+ // 7-Zip before 9.31 created incorrect WzAES Extra in folder's local headers.
+ // so we return k_IsArc_Res_YES to support such archives.
+ // return k_IsArc_Res_NO; // do we need to support such extra ?
+ return k_IsArc_Res_YES;
+ }
+ if (size < 4)
+ return k_IsArc_Res_NEED_MORE;
+ unsigned dataSize = Get16(p + 2);
+ size -= 4;
+ extraSize -= 4;
+ p += 4;
+ if (dataSize > extraSize)
+ {
+ // It can be error on header.
+ // We want to support such rare case bad archives.
+ // We use additional checks to reduce false-positive probability.
+ if (nameSize == 0
+ || nameSize > (1 << 9)
+ || extraSize > (1 << 9))
+ return k_IsArc_Res_NO;
+ return k_IsArc_Res_YES;
+ }
+ if (dataSize > size)
+ return k_IsArc_Res_NEED_MORE;
+ size -= dataSize;
+ extraSize -= dataSize;
+ p += dataSize;
+ }
+ }
+
+ return k_IsArc_Res_YES;
+}
+
+static UInt32 IsArc_Zip_2(const Byte *p, size_t size, bool isFinal)
+{
+ UInt32 res = IsArc_Zip(p, size);
+ if (res == k_IsArc_Res_NEED_MORE && isFinal)
+ return k_IsArc_Res_NO;
+ return res;
+}
+
+
+
+/* FindPK_4() is allowed to access data up to and including &limit[3].
+ limit[4] access is not allowed.
+ return:
+ (return_ptr < limit) : "PK" was found at (return_ptr)
+ (return_ptr >= limit) : limit was reached or crossed. So no "PK" found before limit
+*/
+Z7_NO_INLINE
+static const Byte *FindPK_4(const Byte *p, const Byte *limit)
+{
+ for (;;)
+ {
+ for (;;)
+ {
+ if (p >= limit)
+ return limit;
+ Byte b = p[1];
+ if (b == 0x4B) { if (p[0] == 0x50) { return p; } p += 1; break; }
+ if (b == 0x50) { if (p[2] == 0x4B) { return p + 1; } p += 2; break; }
+ b = p[3];
+ p += 4;
+ if (b == 0x4B) { if (p[-2]== 0x50) { return p - 2; } p -= 1; break; }
+ if (b == 0x50) { if (p[0] == 0x4B) { return p - 1; } break; }
+ }
+ }
+ /*
+ for (;;)
+ {
+ for (;;)
+ {
+ if (p >= limit)
+ return limit;
+ if (*p++ == 0x50) break;
+ if (*p++ == 0x50) break;
+ if (*p++ == 0x50) break;
+ if (*p++ == 0x50) break;
+ }
+ if (*p == 0x4B)
+ return p - 1;
+ }
+ */
+}
+
+
+/*
+---------- FindMarker ----------
+returns:
+ S_OK:
+ ArcInfo.MarkerVolIndex : volume of marker
+ ArcInfo.MarkerPos : Pos of first signature
+ ArcInfo.MarkerPos2 : Pos of main signature (local item signature in most cases)
+ _streamPos : stream pos
+ _cnt : The number of virtal Bytes after start of search to offset after signature
+ _signature : main signature
+
+ S_FALSE: can't find marker, or there is some non-zip data after marker
+
+ Error code: stream reading error.
+*/
+
+HRESULT CInArchive::FindMarker(const UInt64 *searchLimit)
+{
+ ArcInfo.MarkerPos = GetVirtStreamPos();
+ ArcInfo.MarkerPos2 = ArcInfo.MarkerPos;
+ ArcInfo.MarkerVolIndex = Vols.StreamIndex;
+
+ _cnt = 0;
+
+ CanStartNewVol = false;
+
+ if (searchLimit && *searchLimit == 0)
+ {
+ Byte startBuf[kMarkerSize];
+ RINOK(ReadFromCache_FALSE(startBuf, kMarkerSize))
+
+ UInt32 marker = Get32(startBuf);
+ _signature = marker;
+
+ if ( marker == NSignature::kNoSpan
+ || marker == NSignature::kSpan)
+ {
+ RINOK(ReadFromCache_FALSE(startBuf, kMarkerSize))
+ _signature = Get32(startBuf);
+ }
+
+ if ( _signature != NSignature::kEcd
+ && _signature != NSignature::kEcd64
+ && _signature != NSignature::kLocalFileHeader)
+ return S_FALSE;
+
+ ArcInfo.MarkerPos2 = GetVirtStreamPos() - 4;
+ ArcInfo.IsSpanMode = (marker == NSignature::kSpan);
+
+ // we use weak test in case of (*searchLimit == 0)
+ // since error will be detected later in Open function
+ return S_OK;
+ }
+
+ // zip specification: (_zip_header_size < (1 << 16))
+ // so we need such size to check header
+ const size_t kCheckSize = (size_t)1 << 16;
+ const size_t kBufSize = (size_t)1 << 17; // (kBufSize must be > kCheckSize)
+
+ RINOK(AllocateBuffer(kBufSize))
+
+ _inBufMode = true;
+
+ UInt64 progressPrev = 0;
+
+ for (;;)
+ {
+ RINOK(LookAhead(kBufSize))
+
+ const size_t avail = GetAvail();
+
+ size_t limitPos;
+ // (avail > kBufSize) is possible, if (Buffer.Size() > kBufSize)
+ const bool isFinished = (avail < kBufSize);
+ if (isFinished)
+ {
+ const unsigned kMinAllowed = 4;
+ if (avail <= kMinAllowed)
+ {
+ if ( !IsMultiVol
+ || Vols.StreamIndex < 0
+ || (unsigned)Vols.StreamIndex + 1 >= Vols.Streams.Size())
+ break;
+
+ SkipLookahed(avail);
+
+ const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex + 1];
+ if (!s.Stream)
+ break;
+
+ RINOK(s.SeekToStart())
+
+ InitBuf();
+ Vols.StreamIndex++;
+ _streamPos = 0;
+ Stream = s.Stream;
+ continue;
+ }
+ limitPos = avail - kMinAllowed;
+ }
+ else
+ limitPos = (avail - kCheckSize);
+
+ // we don't check at (limitPos) for good fast aligned operations
+
+ if (searchLimit)
+ {
+ if (_cnt > *searchLimit)
+ break;
+ UInt64 rem = *searchLimit - _cnt;
+ if (limitPos > rem)
+ limitPos = (size_t)rem + 1;
+ }
+
+ if (limitPos == 0)
+ break;
+
+ const Byte * const pStart = Buffer + _bufPos;
+ const Byte * p = pStart;
+ const Byte * const limit = pStart + limitPos;
+
+ for (;; p++)
+ {
+ p = FindPK_4(p, limit);
+ if (p >= limit)
+ break;
+ size_t rem = (size_t)(pStart + avail - p);
+ /* 22.02 : we limit check size with kCheckSize to be consistent for
+ any different combination of _bufPos in Buffer and size of Buffer. */
+ if (rem > kCheckSize)
+ rem = kCheckSize;
+ const UInt32 res = IsArc_Zip_2(p, rem, isFinished);
+ if (res != k_IsArc_Res_NO)
+ {
+ if (rem < kMarkerSize)
+ return S_FALSE;
+ _signature = Get32(p);
+ SkipLookahed((size_t)(p - pStart));
+ ArcInfo.MarkerVolIndex = Vols.StreamIndex;
+ ArcInfo.MarkerPos = GetVirtStreamPos();
+ ArcInfo.MarkerPos2 = ArcInfo.MarkerPos;
+ SkipLookahed(4);
+ if ( _signature == NSignature::kNoSpan
+ || _signature == NSignature::kSpan)
+ {
+ if (rem < kMarkerSize * 2)
+ return S_FALSE;
+ ArcInfo.IsSpanMode = (_signature == NSignature::kSpan);
+ _signature = Get32(p + 4);
+ ArcInfo.MarkerPos2 += 4;
+ SkipLookahed(4);
+ }
+ return S_OK;
+ }
+ }
+
+ if (!IsMultiVol && isFinished)
+ break;
+
+ SkipLookahed((size_t)(p - pStart));
+
+ if (Callback && (_cnt - progressPrev) >= ((UInt32)1 << 23))
+ {
+ progressPrev = _cnt;
+ // const UInt64 numFiles64 = 0;
+ RINOK(Callback->SetCompleted(NULL, &_cnt))
+ }
+ }
+
+ return S_FALSE;
+}
+
+
+/*
+---------- IncreaseRealPosition ----------
+moves virtual offset in virtual stream.
+changing to new volumes is allowed
+*/
+
+HRESULT CInArchive::IncreaseRealPosition(UInt64 offset, bool &isFinished)
+{
+ isFinished = false;
+
+ for (;;)
+ {
+ const size_t avail = GetAvail();
+
+ if (offset <= avail)
+ {
+ _bufPos += (size_t)offset;
+ _cnt += offset;
+ return S_OK;
+ }
+
+ _cnt += avail;
+ offset -= avail;
+
+ _bufCached = 0;
+ _bufPos = 0;
+
+ if (!_inBufMode)
+ break;
+
+ CanStartNewVol = true;
+ LookAhead(1);
+
+ if (GetAvail() == 0)
+ return S_OK;
+ }
+
+ // cache is empty
+
+ if (!IsMultiVol)
+ {
+ _cnt += offset;
+ return Stream->Seek((Int64)offset, STREAM_SEEK_CUR, &_streamPos);
+ }
+
+ for (;;)
+ {
+ if (offset == 0)
+ return S_OK;
+
+ if (Vols.StreamIndex < 0)
+ return S_FALSE;
+ if ((unsigned)Vols.StreamIndex >= Vols.Streams.Size())
+ {
+ isFinished = true;
+ return S_OK;
+ }
+ {
+ const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex];
+ if (!s.Stream)
+ {
+ isFinished = true;
+ return S_OK;
+ }
+ if (_streamPos > s.Size)
+ return S_FALSE;
+ const UInt64 rem = s.Size - _streamPos;
+ if ((UInt64)offset <= rem)
+ {
+ _cnt += offset;
+ return Stream->Seek((Int64)offset, STREAM_SEEK_CUR, &_streamPos);
+ }
+ RINOK(Seek_SavePos(s.Size))
+ offset -= rem;
+ _cnt += rem;
+ }
+
+ Stream = NULL;
+ _streamPos = 0;
+ Vols.StreamIndex++;
+ if ((unsigned)Vols.StreamIndex >= Vols.Streams.Size())
+ {
+ isFinished = true;
+ return S_OK;
+ }
+ const CVols::CSubStreamInfo &s2 = Vols.Streams[(unsigned)Vols.StreamIndex];
+ if (!s2.Stream)
+ {
+ isFinished = true;
+ return S_OK;
+ }
+ Stream = s2.Stream;
+ RINOK(Seek_SavePos(0))
+ }
+}
+
+
+
+/*
+---------- LookAhead ----------
+Reads data to buffer, if required.
+
+It can read from volumes as long as Buffer.Size().
+But it moves to new volume, only if it's required to provide minRequired bytes in buffer.
+
+in:
+ (minRequired <= Buffer.Size())
+
+return:
+ S_OK : if (GetAvail() < minRequired) after function return, it's end of stream(s) data, or no new volume stream.
+ Error codes: IInStream::Read() error or IInStream::Seek() error for multivol
+*/
+
+HRESULT CInArchive::LookAhead(size_t minRequired)
+{
+ for (;;)
+ {
+ const size_t avail = GetAvail();
+
+ if (minRequired <= avail)
+ return S_OK;
+
+ if (_bufPos != 0)
+ {
+ if (avail != 0)
+ memmove(Buffer, Buffer + _bufPos, avail);
+ _bufPos = 0;
+ _bufCached = avail;
+ }
+
+ const size_t pos = _bufCached;
+ UInt32 processed = 0;
+ HRESULT res = Stream->Read(Buffer + pos, (UInt32)(Buffer.Size() - pos), &processed);
+ _streamPos += processed;
+ _bufCached += processed;
+
+ if (res != S_OK)
+ return res;
+
+ if (processed != 0)
+ continue;
+
+ if ( !IsMultiVol
+ || !CanStartNewVol
+ || Vols.StreamIndex < 0
+ || (unsigned)Vols.StreamIndex + 1 >= Vols.Streams.Size())
+ return S_OK;
+
+ const CVols::CSubStreamInfo &s = Vols.Streams[(unsigned)Vols.StreamIndex + 1];
+ if (!s.Stream)
+ return S_OK;
+
+ RINOK(s.SeekToStart())
+
+ Vols.StreamIndex++;
+ _streamPos = 0;
+ Stream = s.Stream;
+ // Vols.NeedSeek = false;
+ }
+}
+
+
+class CUnexpectEnd {};
+
+
+/*
+---------- SafeRead ----------
+
+reads data of exact size from stream(s)
+
+in:
+ _inBufMode
+ if (CanStartNewVol) it can go to next volume before first byte reading, if there is end of volume data.
+
+in, out:
+ _streamPos : position in Stream
+ Stream
+ Vols : if (IsMultiVol)
+ _cnt
+
+out:
+ (CanStartNewVol == false), if some data was read
+
+return:
+ S_OK : success reading of requested data
+
+exceptions:
+ CSystemException() - stream reading error
+ CUnexpectEnd() : could not read data of requested size
+*/
+
+void CInArchive::SafeRead(Byte *data, unsigned size)
+{
+ unsigned processed;
+ HRESULT result = ReadFromCache(data, size, processed);
+ if (result != S_OK)
+ throw CSystemException(result);
+ if (size != processed)
+ throw CUnexpectEnd();
+}
+
+void CInArchive::ReadBuffer(CByteBuffer &buffer, unsigned size)
+{
+ buffer.Alloc(size);
+ if (size != 0)
+ SafeRead(buffer, size);
+}
+
+// Byte CInArchive::ReadByte () { Byte b; SafeRead(&b, 1); return b; }
+// UInt16 CInArchive::ReadUInt16() { Byte buf[2]; SafeRead(buf, 2); return Get16(buf); }
+UInt32 CInArchive::ReadUInt32() { Byte buf[4]; SafeRead(buf, 4); return Get32(buf); }
+UInt64 CInArchive::ReadUInt64() { Byte buf[8]; SafeRead(buf, 8); return Get64(buf); }
+
+void CInArchive::ReadSignature()
+{
+ CanStartNewVol = true;
+ _signature = ReadUInt32();
+ // CanStartNewVol = false; // it's already changed in SafeRead
+}
+
+
+// we Skip() inside headers only, so no need for stream change in multivol.
+
+void CInArchive::Skip(size_t num)
+{
+ while (num != 0)
+ {
+ const unsigned kBufSize = (size_t)1 << 10;
+ Byte buf[kBufSize];
+ unsigned step = kBufSize;
+ if (step > num)
+ step = (unsigned)num;
+ SafeRead(buf, step);
+ num -= step;
+ }
+}
+
+/*
+HRESULT CInArchive::Callback_Completed(unsigned numFiles)
+{
+ const UInt64 numFiles64 = numFiles;
+ return Callback->SetCompleted(&numFiles64, &_cnt);
+}
+*/
+
+HRESULT CInArchive::Skip64(UInt64 num, unsigned numFiles)
+{
+ if (num == 0)
+ return S_OK;
+
+ for (;;)
+ {
+ size_t step = (size_t)1 << 24;
+ if (step > num)
+ step = (size_t)num;
+ Skip(step);
+ num -= step;
+ if (num == 0)
+ return S_OK;
+ if (Callback)
+ {
+ const UInt64 numFiles64 = numFiles;
+ RINOK(Callback->SetCompleted(&numFiles64, &_cnt))
+ }
+ }
+}
+
+
+bool CInArchive::ReadFileName(unsigned size, AString &s)
+{
+ if (size == 0)
+ {
+ s.Empty();
+ return true;
+ }
+ char *p = s.GetBuf(size);
+ SafeRead((Byte *)p, size);
+ unsigned i = size;
+ do
+ {
+ if (p[i - 1] != 0)
+ break;
+ }
+ while (--i);
+ s.ReleaseBuf_CalcLen(size);
+ return s.Len() == i;
+}
+
+
+#define ZIP64_IS_32_MAX(n) ((n) == 0xFFFFFFFF)
+#define ZIP64_IS_16_MAX(n) ((n) == 0xFFFF)
+
+
+bool CInArchive::ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlock &extra,
+ UInt64 &unpackSize, UInt64 &packSize,
+ CItem *cdItem)
+{
+ extra.Clear();
+
+ while (extraSize >= 4)
+ {
+ CExtraSubBlock subBlock;
+ const UInt32 pair = ReadUInt32();
+ subBlock.ID = (pair & 0xFFFF);
+ unsigned size = (unsigned)(pair >> 16);
+ // const unsigned origSize = size;
+
+ extraSize -= 4;
+
+ if (size > extraSize)
+ {
+ // it's error in extra
+ HeadersWarning = true;
+ extra.Error = true;
+ Skip(extraSize);
+ return false;
+ }
+
+ extraSize -= size;
+
+ if (subBlock.ID == NFileHeader::NExtraID::kZip64)
+ {
+ extra.IsZip64 = true;
+ bool isOK = true;
+
+ if (!cdItem
+ && size == 16
+ && !ZIP64_IS_32_MAX(unpackSize)
+ && !ZIP64_IS_32_MAX(packSize))
+ {
+ /* Win10 Explorer's "Send to Zip" for big (3500 MiB) files
+ creates Zip64 Extra in local file header.
+ But if both uncompressed and compressed sizes are smaller than 4 GiB,
+ Win10 doesn't store 0xFFFFFFFF in 32-bit fields as expected by zip specification.
+ 21.04: we ignore these minor errors in Win10 zip archives. */
+ if (ReadUInt64() != unpackSize)
+ isOK = false;
+ if (ReadUInt64() != packSize)
+ isOK = false;
+ size = 0;
+ }
+ else
+ {
+ if (ZIP64_IS_32_MAX(unpackSize))
+ { if (size < 8) isOK = false; else { size -= 8; unpackSize = ReadUInt64(); }}
+
+ if (isOK && ZIP64_IS_32_MAX(packSize))
+ { if (size < 8) isOK = false; else { size -= 8; packSize = ReadUInt64(); }}
+
+ if (cdItem)
+ {
+ if (isOK)
+ {
+ if (ZIP64_IS_32_MAX(cdItem->LocalHeaderPos))
+ { if (size < 8) isOK = false; else { size -= 8; cdItem->LocalHeaderPos = ReadUInt64(); }}
+ /*
+ else if (size == 8)
+ {
+ size -= 8;
+ const UInt64 v = ReadUInt64();
+ // soong_zip, an AOSP tool (written in the Go) writes incorrect value.
+ // we can ignore that minor error here
+ if (v != cdItem->LocalHeaderPos)
+ isOK = false; // ignore error
+ // isOK = false; // force error
+ }
+ */
+ }
+
+ if (isOK && ZIP64_IS_16_MAX(cdItem->Disk))
+ { if (size < 4) isOK = false; else { size -= 4; cdItem->Disk = ReadUInt32(); }}
+ }
+ }
+
+ // we can ignore errors, when some zip archiver still write all fields to zip64 extra in local header
+ // if (&& (cdItem || !isOK || origSize != 8 * 3 + 4 || size != 8 * 1 + 4))
+ if (!isOK || size != 0)
+ {
+ HeadersWarning = true;
+ extra.Error = true;
+ extra.IsZip64_Error = true;
+ }
+ Skip(size);
+ }
+ else
+ {
+ ReadBuffer(subBlock.Data, size);
+ extra.SubBlocks.Add(subBlock);
+ if (subBlock.ID == NFileHeader::NExtraID::kIzUnicodeName)
+ {
+ if (!subBlock.CheckIzUnicode(item.Name))
+ extra.Error = true;
+ }
+ }
+ }
+
+ if (extraSize != 0)
+ {
+ ExtraMinorError = true;
+ extra.MinorError = true;
+ // 7-Zip before 9.31 created incorrect WzAES Extra in folder's local headers.
+ // so we don't return false, but just set warning flag
+ // return false;
+ Skip(extraSize);
+ }
+
+ return true;
+}
+
+
+bool CInArchive::ReadLocalItem(CItemEx &item)
+{
+ item.Disk = 0;
+ if (IsMultiVol && Vols.StreamIndex >= 0)
+ item.Disk = (UInt32)Vols.StreamIndex;
+ const unsigned kPureHeaderSize = kLocalHeaderSize - 4;
+ Byte p[kPureHeaderSize];
+ SafeRead(p, kPureHeaderSize);
+ {
+ unsigned i;
+ for (i = 0; i < kPureHeaderSize && p[i] == 0; i++);
+ if (i == kPureHeaderSize)
+ return false;
+ }
+
+ item.ExtractVersion.Version = p[0];
+ item.ExtractVersion.HostOS = p[1];
+ G16(2, item.Flags);
+ G16(4, item.Method);
+ G32(6, item.Time);
+ G32(10, item.Crc);
+ G32(14, item.PackSize);
+ G32(18, item.Size);
+ const unsigned nameSize = Get16(p + 22);
+ const unsigned extraSize = Get16(p + 24);
+ bool isOkName = ReadFileName(nameSize, item.Name);
+ item.LocalFullHeaderSize = kLocalHeaderSize + (UInt32)nameSize + extraSize;
+ item.DescriptorWasRead = false;
+
+ /*
+ if (item.IsDir())
+ item.Size = 0; // check It
+ */
+
+ if (extraSize > 0)
+ {
+ if (!ReadExtra(item, extraSize, item.LocalExtra, item.Size, item.PackSize, NULL))
+ {
+ /* Most of archives are OK for Extra. But there are some rare cases
+ that have error. And if error in first item, it can't open archive.
+ So we ignore that error */
+ // return false;
+ }
+ }
+
+ if (!CheckDosTime(item.Time))
+ {
+ HeadersWarning = true;
+ // return false;
+ }
+
+ if (item.Name.Len() != nameSize)
+ {
+ // we support some "bad" zip archives that contain zeros after name
+ if (!isOkName)
+ return false;
+ HeadersWarning = true;
+ }
+
+ // return item.LocalFullHeaderSize <= ((UInt32)1 << 16);
+ return true;
+}
+
+
+static bool FlagsAreSame(const CItem &i1, const CItem &i2_cd)
+{
+ if (i1.Method != i2_cd.Method)
+ return false;
+
+ UInt32 mask = i1.Flags ^ i2_cd.Flags;
+ if (mask == 0)
+ return true;
+ switch (i1.Method)
+ {
+ case NFileHeader::NCompressionMethod::kDeflate:
+ mask &= 0x7FF9;
+ break;
+ default:
+ if (i1.Method <= NFileHeader::NCompressionMethod::kImplode)
+ mask &= 0x7FFF;
+ }
+
+ // we can ignore utf8 flag, if name is ascii, or if only cdItem has utf8 flag
+ if (mask & NFileHeader::NFlags::kUtf8)
+ if ((i1.Name.IsAscii() && i2_cd.Name.IsAscii())
+ || (i2_cd.Flags & NFileHeader::NFlags::kUtf8))
+ mask &= ~NFileHeader::NFlags::kUtf8;
+
+ // some bad archive in rare case can use descriptor without descriptor flag in Central Dir
+ // if (i1.HasDescriptor())
+ mask &= ~NFileHeader::NFlags::kDescriptorUsedMask;
+
+ return (mask == 0);
+}
+
+
+// #ifdef _WIN32
+static bool AreEqualPaths_IgnoreSlashes(const char *s1, const char *s2)
+{
+ for (;;)
+ {
+ char c1 = *s1++;
+ char c2 = *s2++;
+ if (c1 == c2)
+ {
+ if (c1 == 0)
+ return true;
+ }
+ else
+ {
+ if (c1 == '\\') c1 = '/';
+ if (c2 == '\\') c2 = '/';
+ if (c1 != c2)
+ return false;
+ }
+ }
+}
+// #endif
+
+
+static bool AreItemsEqual(const CItemEx &localItem, const CItemEx &cdItem)
+{
+ if (!FlagsAreSame(localItem, cdItem))
+ return false;
+ if (!localItem.HasDescriptor())
+ {
+ if (cdItem.PackSize != localItem.PackSize
+ || cdItem.Size != localItem.Size
+ || (cdItem.Crc != localItem.Crc && cdItem.Crc != 0)) // some program writes 0 to crc field in central directory
+ return false;
+ }
+ /* pkzip 2.50 creates incorrect archives. It uses
+ - WIN encoding for name in local header
+ - OEM encoding for name in central header
+ We don't support these strange items. */
+
+ /* if (cdItem.Name.Len() != localItem.Name.Len())
+ return false;
+ */
+ if (cdItem.Name != localItem.Name)
+ {
+ // #ifdef _WIN32
+ // some xap files use backslash in central dir items.
+ // we can ignore such errors in windows, where all slashes are converted to backslashes
+ unsigned hostOs = cdItem.GetHostOS();
+
+ if (hostOs == NFileHeader::NHostOS::kFAT ||
+ hostOs == NFileHeader::NHostOS::kNTFS)
+ {
+ if (!AreEqualPaths_IgnoreSlashes(cdItem.Name, localItem.Name))
+ {
+ // pkzip 2.50 uses DOS encoding in central dir and WIN encoding in local header.
+ // so we ignore that error
+ if (hostOs != NFileHeader::NHostOS::kFAT
+ || cdItem.MadeByVersion.Version < 25
+ || cdItem.MadeByVersion.Version > 40)
+ return false;
+ }
+ }
+ /*
+ else
+ #endif
+ return false;
+ */
+ }
+ return true;
+}
+
+
+HRESULT CInArchive::Read_LocalItem_After_CdItem(CItemEx &item, bool &isAvail, bool &headersError)
+{
+ isAvail = true;
+ headersError = false;
+ if (item.FromLocal)
+ return S_OK;
+ try
+ {
+ UInt64 offset = item.LocalHeaderPos;
+
+ if (IsMultiVol)
+ {
+ if (item.Disk >= Vols.Streams.Size())
+ {
+ isAvail = false;
+ return S_FALSE;
+ }
+ Stream = Vols.Streams[item.Disk].Stream;
+ Vols.StreamIndex = (int)item.Disk;
+ if (!Stream)
+ {
+ isAvail = false;
+ return S_FALSE;
+ }
+ }
+ else
+ {
+ if (UseDisk_in_SingleVol && item.Disk != EcdVolIndex)
+ {
+ isAvail = false;
+ return S_FALSE;
+ }
+ Stream = StreamRef;
+
+ offset = (UInt64)((Int64)offset + ArcInfo.Base);
+ if (ArcInfo.Base < 0 && (Int64)offset < 0)
+ {
+ isAvail = false;
+ return S_FALSE;
+ }
+ }
+
+ _inBufMode = false;
+ RINOK(Seek_SavePos(offset))
+ InitBuf();
+ /*
+ // we can use buf mode with small buffer to reduce
+ // the number of Read() calls in ReadLocalItem()
+ _inBufMode = true;
+ Buffer.Alloc(1 << 10);
+ if (!Buffer.IsAllocated())
+ return E_OUTOFMEMORY;
+ */
+
+ CItemEx localItem;
+ if (ReadUInt32() != NSignature::kLocalFileHeader)
+ return S_FALSE;
+ ReadLocalItem(localItem);
+ if (!AreItemsEqual(localItem, item))
+ return S_FALSE;
+ item.LocalFullHeaderSize = localItem.LocalFullHeaderSize;
+ item.LocalExtra = localItem.LocalExtra;
+ if (item.Crc != localItem.Crc && !localItem.HasDescriptor())
+ {
+ item.Crc = localItem.Crc;
+ headersError = true;
+ }
+ if ((item.Flags ^ localItem.Flags) & NFileHeader::NFlags::kDescriptorUsedMask)
+ {
+ item.Flags = (UInt16)(item.Flags ^ NFileHeader::NFlags::kDescriptorUsedMask);
+ headersError = true;
+ }
+ item.FromLocal = true;
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+}
+
+
+/*
+---------- FindDescriptor ----------
+
+in:
+ _streamPos : position in Stream
+ Stream :
+ Vols : if (IsMultiVol)
+
+action:
+ searches descriptor in input stream(s).
+ sets
+ item.DescriptorWasRead = true;
+ item.Size
+ item.PackSize
+ item.Crc
+ if descriptor was found
+
+out:
+ S_OK:
+ if ( item.DescriptorWasRead) : if descriptor was found
+ if (!item.DescriptorWasRead) : if descriptor was not found : unexpected end of stream(s)
+
+ S_FALSE: if no items or there is just one item with strange properies that doesn't look like real archive.
+
+ another error code: Callback error.
+
+exceptions :
+ CSystemException() : stream reading error
+*/
+
+HRESULT CInArchive::FindDescriptor(CItemEx &item, unsigned numFiles)
+{
+ // const size_t kBufSize = (size_t)1 << 5; // don't increase it too much. It reads data look ahead.
+
+ // Buffer.Alloc(kBufSize);
+ // Byte *buf = Buffer;
+
+ UInt64 packedSize = 0;
+
+ UInt64 progressPrev = _cnt;
+
+ for (;;)
+ {
+ /* appnote specification claims that we must use 64-bit descriptor, if there is zip64 extra.
+ But some old third-party xps archives used 64-bit descriptor without zip64 extra. */
+ // unsigned descriptorSize = kDataDescriptorSize64 + kNextSignatureSize;
+
+ // const unsigned kNextSignatureSize = 0; // we can disable check for next signatuire
+ const unsigned kNextSignatureSize = 4; // we check also for signature for next File headear
+
+ const unsigned descriptorSize4 = item.GetDescriptorSize() + kNextSignatureSize;
+
+ if (descriptorSize4 > Buffer.Size()) return E_FAIL;
+
+ // size_t processedSize;
+ CanStartNewVol = true;
+ RINOK(LookAhead(descriptorSize4))
+ const size_t avail = GetAvail();
+
+ if (avail < descriptorSize4)
+ {
+ // we write to packSize all these available bytes.
+ // later it's simpler to work with such value than with 0
+ // if (item.PackSize == 0)
+ item.PackSize = packedSize + avail;
+ if (item.Method == 0)
+ item.Size = item.PackSize;
+ SkipLookahed(avail);
+ return S_OK;
+ }
+
+ const Byte * const pStart = Buffer + _bufPos;
+ const Byte * p = pStart;
+ const Byte * const limit = pStart + (avail - descriptorSize4);
+
+ for (; p <= limit; p++)
+ {
+ // descriptor signature field is Info-ZIP's extension to pkware Zip specification.
+ // New ZIP specification also allows descriptorSignature.
+
+ p = FindPK_4(p, limit + 1);
+ if (p > limit)
+ break;
+
+ /*
+ if (*p != 0x50)
+ continue;
+ */
+
+ if (Get32(p) != NSignature::kDataDescriptor)
+ continue;
+
+ // we check next signatuire after descriptor
+ // maybe we need check only 2 bytes "PK" instead of 4 bytes, if some another type of header is possible after descriptor
+ const UInt32 sig = Get32(p + descriptorSize4 - kNextSignatureSize);
+ if ( sig != NSignature::kLocalFileHeader
+ && sig != NSignature::kCentralFileHeader)
+ continue;
+
+ const UInt64 packSizeCur = packedSize + (size_t)(p - pStart);
+ if (descriptorSize4 == kDataDescriptorSize64 + kNextSignatureSize) // if (item.LocalExtra.IsZip64)
+ {
+ const UInt64 descriptorPackSize = Get64(p + 8);
+ if (descriptorPackSize != packSizeCur)
+ continue;
+ item.Size = Get64(p + 16);
+ }
+ else
+ {
+ const UInt32 descriptorPackSize = Get32(p + 8);
+ if (descriptorPackSize != (UInt32)packSizeCur)
+ continue;
+ item.Size = Get32(p + 12);
+ // that item.Size can be truncated to 32-bit value here
+ }
+ // We write calculated 64-bit packSize, even if descriptor64 was not used
+ item.PackSize = packSizeCur;
+
+ item.DescriptorWasRead = true;
+ item.Crc = Get32(p + 4);
+
+ const size_t skip = (size_t)(p - pStart) + descriptorSize4 - kNextSignatureSize;
+
+ SkipLookahed(skip);
+
+ return S_OK;
+ }
+
+ const size_t skip = (size_t)(p - pStart);
+ SkipLookahed(skip);
+
+ packedSize += skip;
+
+ if (Callback)
+ if (_cnt - progressPrev >= ((UInt32)1 << 22))
+ {
+ progressPrev = _cnt;
+ const UInt64 numFiles64 = numFiles;
+ RINOK(Callback->SetCompleted(&numFiles64, &_cnt))
+ }
+ }
+}
+
+
+HRESULT CInArchive::CheckDescriptor(const CItemEx &item)
+{
+ if (!item.HasDescriptor())
+ return S_OK;
+
+ // pkzip's version without descriptor signature is not supported
+
+ bool isFinished = false;
+ RINOK(IncreaseRealPosition(item.PackSize, isFinished))
+ if (isFinished)
+ return S_FALSE;
+
+ /*
+ if (!IsMultiVol)
+ {
+ RINOK(Seek_SavePos(ArcInfo.Base + item.GetDataPosition() + item.PackSize));
+ }
+ */
+
+ Byte buf[kDataDescriptorSize64];
+ try
+ {
+ CanStartNewVol = true;
+ SafeRead(buf, item.GetDescriptorSize());
+ }
+ catch (const CSystemException &e) { return e.ErrorCode; }
+ // catch (const CUnexpectEnd &)
+ catch(...)
+ {
+ return S_FALSE;
+ }
+ // RINOK(ReadStream_FALSE(Stream, buf, item.GetDescriptorSize()));
+
+ if (Get32(buf) != NSignature::kDataDescriptor)
+ return S_FALSE;
+ UInt32 crc = Get32(buf + 4);
+ UInt64 packSize, unpackSize;
+
+ if (item.LocalExtra.IsZip64)
+ {
+ packSize = Get64(buf + 8);
+ unpackSize = Get64(buf + 16);
+ }
+ else
+ {
+ packSize = Get32(buf + 8);
+ unpackSize = Get32(buf + 12);
+ }
+
+ if (crc != item.Crc || item.PackSize != packSize || item.Size != unpackSize)
+ return S_FALSE;
+ return S_OK;
+}
+
+
+HRESULT CInArchive::Read_LocalItem_After_CdItem_Full(CItemEx &item)
+{
+ if (item.FromLocal)
+ return S_OK;
+ try
+ {
+ bool isAvail = true;
+ bool headersError = false;
+ RINOK(Read_LocalItem_After_CdItem(item, isAvail, headersError))
+ if (headersError)
+ return S_FALSE;
+ if (item.HasDescriptor())
+ return CheckDescriptor(item);
+ }
+ catch(...) { return S_FALSE; }
+ return S_OK;
+}
+
+
+HRESULT CInArchive::ReadCdItem(CItemEx &item)
+{
+ item.FromCentral = true;
+ Byte p[kCentralHeaderSize - 4];
+ SafeRead(p, kCentralHeaderSize - 4);
+
+ item.MadeByVersion.Version = p[0];
+ item.MadeByVersion.HostOS = p[1];
+ item.ExtractVersion.Version = p[2];
+ item.ExtractVersion.HostOS = p[3];
+ G16(4, item.Flags);
+ G16(6, item.Method);
+ G32(8, item.Time);
+ G32(12, item.Crc);
+ G32(16, item.PackSize);
+ G32(20, item.Size);
+ const unsigned nameSize = Get16(p + 24);
+ const unsigned extraSize = Get16(p + 26);
+ const unsigned commentSize = Get16(p + 28);
+ G16(30, item.Disk);
+ G16(32, item.InternalAttrib);
+ G32(34, item.ExternalAttrib);
+ G32(38, item.LocalHeaderPos);
+ ReadFileName(nameSize, item.Name);
+
+ if (extraSize > 0)
+ ReadExtra(item, extraSize, item.CentralExtra, item.Size, item.PackSize, &item);
+
+ // May be these strings must be deleted
+ /*
+ if (item.IsDir())
+ item.Size = 0;
+ */
+
+ ReadBuffer(item.Comment, commentSize);
+ return S_OK;
+}
+
+
+/*
+TryEcd64()
+ (_inBufMode == false) is expected here
+ so TryEcd64() can't change the Buffer.
+ if (Ecd64 is not covered by cached region),
+ TryEcd64() can change cached region ranges (_bufCached, _bufPos) and _streamPos.
+*/
+
+HRESULT CInArchive::TryEcd64(UInt64 offset, CCdInfo &cdInfo)
+{
+ if (offset >= ((UInt64)1 << 63))
+ return S_FALSE;
+ Byte buf[kEcd64_FullSize];
+
+ RINOK(SeekToVol(Vols.StreamIndex, offset))
+ RINOK(ReadFromCache_FALSE(buf, kEcd64_FullSize))
+
+ if (Get32(buf) != NSignature::kEcd64)
+ return S_FALSE;
+ UInt64 mainSize = Get64(buf + 4);
+ if (mainSize < kEcd64_MainSize || mainSize > ((UInt64)1 << 40))
+ return S_FALSE;
+ cdInfo.ParseEcd64e(buf + 12);
+ return S_OK;
+}
+
+
+/* FindCd() doesn't use previous cached region,
+ but it uses Buffer. So it sets new cached region */
+
+HRESULT CInArchive::FindCd(bool checkOffsetMode)
+{
+ CCdInfo &cdInfo = Vols.ecd;
+
+ UInt64 endPos;
+
+ // There are no useful data in cache in most cases here.
+ // So here we don't use cache data from previous operations .
+
+ InitBuf();
+ RINOK(InStream_GetSize_SeekToEnd(Stream, endPos))
+ _streamPos = endPos;
+
+ // const UInt32 kBufSizeMax2 = ((UInt32)1 << 16) + kEcdSize + kEcd64Locator_Size + kEcd64_FullSize;
+ const size_t kBufSizeMax = ((size_t)1 << 17); // must be larger than kBufSizeMax2
+
+ const size_t bufSize = (endPos < kBufSizeMax) ? (size_t)endPos : kBufSizeMax;
+ if (bufSize < kEcdSize)
+ return S_FALSE;
+ // CByteArr byteBuffer(bufSize);
+
+ RINOK(AllocateBuffer(kBufSizeMax))
+
+ RINOK(Seek_SavePos(endPos - bufSize))
+
+ size_t processed = bufSize;
+ HRESULT res = ReadStream(Stream, Buffer, &processed);
+ _streamPos += processed;
+ _bufCached = processed;
+ _bufPos = 0;
+ _cnt += processed;
+ if (res != S_OK)
+ return res;
+ if (processed != bufSize)
+ return S_FALSE;
+
+
+ for (size_t i = bufSize - kEcdSize + 1;;)
+ {
+ if (i == 0)
+ return S_FALSE;
+
+ const Byte *buf = Buffer;
+
+ for (;;)
+ {
+ i--;
+ if (buf[i] == 0x50)
+ break;
+ if (i == 0)
+ return S_FALSE;
+ }
+
+ if (Get32(buf + i) != NSignature::kEcd)
+ continue;
+
+ cdInfo.ParseEcd32(buf + i);
+
+ if (i >= kEcd64Locator_Size)
+ {
+ const size_t locatorIndex = i - kEcd64Locator_Size;
+ if (Get32(buf + locatorIndex) == NSignature::kEcd64Locator)
+ {
+ CLocator locator;
+ locator.Parse(buf + locatorIndex + 4);
+ UInt32 numDisks = locator.NumDisks;
+ // we ignore the error, where some zip creators use (NumDisks == 0)
+ if (numDisks == 0)
+ numDisks = 1;
+ if ((cdInfo.ThisDisk == numDisks - 1 || ZIP64_IS_16_MAX(cdInfo.ThisDisk))
+ && locator.Ecd64Disk < numDisks)
+ {
+ if (locator.Ecd64Disk != cdInfo.ThisDisk && !ZIP64_IS_16_MAX(cdInfo.ThisDisk))
+ return E_NOTIMPL;
+
+ // Most of the zip64 use fixed size Zip64 ECD
+ // we try relative backward reading.
+
+ UInt64 absEcd64 = endPos - bufSize + i - (kEcd64Locator_Size + kEcd64_FullSize);
+
+ if (locatorIndex >= kEcd64_FullSize)
+ if (checkOffsetMode || absEcd64 == locator.Ecd64Offset)
+ {
+ const Byte *ecd64 = buf + locatorIndex - kEcd64_FullSize;
+ if (Get32(ecd64) == NSignature::kEcd64)
+ {
+ UInt64 mainEcd64Size = Get64(ecd64 + 4);
+ if (mainEcd64Size == kEcd64_MainSize)
+ {
+ cdInfo.ParseEcd64e(ecd64 + 12);
+ ArcInfo.Base = (Int64)(absEcd64 - locator.Ecd64Offset);
+ // ArcInfo.BaseVolIndex = cdInfo.ThisDisk;
+ return S_OK;
+ }
+ }
+ }
+
+ // some zip64 use variable size Zip64 ECD.
+ // we try to use absolute offset from locator.
+
+ if (absEcd64 != locator.Ecd64Offset)
+ {
+ if (TryEcd64(locator.Ecd64Offset, cdInfo) == S_OK)
+ {
+ ArcInfo.Base = 0;
+ // ArcInfo.BaseVolIndex = cdInfo.ThisDisk;
+ return S_OK;
+ }
+ }
+
+ // for variable Zip64 ECD with for archives with offset != 0.
+
+ if (checkOffsetMode
+ && ArcInfo.MarkerPos != 0
+ && ArcInfo.MarkerPos + locator.Ecd64Offset != absEcd64)
+ {
+ if (TryEcd64(ArcInfo.MarkerPos + locator.Ecd64Offset, cdInfo) == S_OK)
+ {
+ ArcInfo.Base = (Int64)ArcInfo.MarkerPos;
+ // ArcInfo.BaseVolIndex = cdInfo.ThisDisk;
+ return S_OK;
+ }
+ }
+ }
+ }
+ }
+
+ // bool isVolMode = (Vols.EndVolIndex != -1);
+ // UInt32 searchDisk = (isVolMode ? Vols.EndVolIndex : 0);
+
+ if (/* searchDisk == thisDisk && */ cdInfo.CdDisk <= cdInfo.ThisDisk)
+ {
+ // if (isVolMode)
+ {
+ if (cdInfo.CdDisk != cdInfo.ThisDisk)
+ return S_OK;
+ }
+
+ UInt64 absEcdPos = endPos - bufSize + i;
+ UInt64 cdEnd = cdInfo.Size + cdInfo.Offset;
+ ArcInfo.Base = 0;
+ // ArcInfo.BaseVolIndex = cdInfo.ThisDisk;
+ if (absEcdPos != cdEnd)
+ {
+ /*
+ if (cdInfo.Offset <= 16 && cdInfo.Size != 0)
+ {
+ // here we support some rare ZIP files with Central directory at the start
+ ArcInfo.Base = 0;
+ }
+ else
+ */
+ ArcInfo.Base = (Int64)(absEcdPos - cdEnd);
+ }
+ return S_OK;
+ }
+ }
+}
+
+
+HRESULT CInArchive::TryReadCd(CObjectVector<CItemEx> &items, const CCdInfo &cdInfo, UInt64 cdOffset, UInt64 cdSize)
+{
+ items.Clear();
+ IsCdUnsorted = false;
+
+ // _startLocalFromCd_Disk = (UInt32)(Int32)-1;
+ // _startLocalFromCd_Offset = (UInt64)(Int64)-1;
+
+ RINOK(SeekToVol(IsMultiVol ? (int)cdInfo.CdDisk : -1, cdOffset))
+
+ _inBufMode = true;
+ _cnt = 0;
+
+ if (Callback)
+ {
+ RINOK(Callback->SetTotal(&cdInfo.NumEntries, IsMultiVol ? &Vols.TotalBytesSize : NULL))
+ }
+ UInt64 numFileExpected = cdInfo.NumEntries;
+ const UInt64 *totalFilesPtr = &numFileExpected;
+ bool isCorrect_NumEntries = (cdInfo.IsFromEcd64 || numFileExpected >= ((UInt32)1 << 16));
+
+ while (_cnt < cdSize)
+ {
+ CanStartNewVol = true;
+ if (ReadUInt32() != NSignature::kCentralFileHeader)
+ return S_FALSE;
+ CanStartNewVol = false;
+ {
+ CItemEx cdItem;
+ RINOK(ReadCdItem(cdItem))
+
+ /*
+ if (cdItem.Disk < _startLocalFromCd_Disk ||
+ cdItem.Disk == _startLocalFromCd_Disk &&
+ cdItem.LocalHeaderPos < _startLocalFromCd_Offset)
+ {
+ _startLocalFromCd_Disk = cdItem.Disk;
+ _startLocalFromCd_Offset = cdItem.LocalHeaderPos;
+ }
+ */
+
+ if (items.Size() > 0 && !IsCdUnsorted)
+ {
+ const CItemEx &prev = items.Back();
+ if (cdItem.Disk < prev.Disk
+ || (cdItem.Disk == prev.Disk &&
+ cdItem.LocalHeaderPos < prev.LocalHeaderPos))
+ IsCdUnsorted = true;
+ }
+
+ items.Add(cdItem);
+ }
+ if (Callback && (items.Size() & 0xFFF) == 0)
+ {
+ const UInt64 numFiles = items.Size();
+
+ if (numFiles > numFileExpected && totalFilesPtr)
+ {
+ if (isCorrect_NumEntries)
+ totalFilesPtr = NULL;
+ else
+ while (numFiles > numFileExpected)
+ numFileExpected += (UInt32)1 << 16;
+ RINOK(Callback->SetTotal(totalFilesPtr, NULL))
+ }
+
+ RINOK(Callback->SetCompleted(&numFiles, &_cnt))
+ }
+ }
+
+ CanStartNewVol = true;
+
+ return (_cnt == cdSize) ? S_OK : S_FALSE;
+}
+
+
+/*
+static int CompareCdItems(void *const *elem1, void *const *elem2, void *)
+{
+ const CItemEx *i1 = *(const CItemEx **)elem1;
+ const CItemEx *i2 = *(const CItemEx **)elem2;
+
+ if (i1->Disk < i2->Disk) return -1;
+ if (i1->Disk > i2->Disk) return 1;
+ if (i1->LocalHeaderPos < i2->LocalHeaderPos) return -1;
+ if (i1->LocalHeaderPos > i2->LocalHeaderPos) return 1;
+ if (i1 < i2) return -1;
+ if (i1 > i2) return 1;
+ return 0;
+}
+*/
+
+HRESULT CInArchive::ReadCd(CObjectVector<CItemEx> &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize)
+{
+ bool checkOffsetMode = true;
+
+ if (IsMultiVol)
+ {
+ if (Vols.EndVolIndex == -1)
+ return S_FALSE;
+ Stream = Vols.Streams[(unsigned)Vols.EndVolIndex].Stream;
+ if (!Vols.StartIsZip)
+ checkOffsetMode = false;
+ }
+ else
+ Stream = StartStream;
+
+ if (!Vols.ecd_wasRead)
+ {
+ RINOK(FindCd(checkOffsetMode))
+ }
+
+ CCdInfo &cdInfo = Vols.ecd;
+
+ HRESULT res = S_FALSE;
+
+ cdSize = cdInfo.Size;
+ cdOffset = cdInfo.Offset;
+ cdDisk = cdInfo.CdDisk;
+
+ if (!IsMultiVol)
+ {
+ if (cdInfo.ThisDisk != cdInfo.CdDisk)
+ return S_FALSE;
+ }
+
+ const UInt64 base = (IsMultiVol ? 0 : (UInt64)ArcInfo.Base);
+ res = TryReadCd(items, cdInfo, base + cdOffset, cdSize);
+
+ if (res == S_FALSE && !IsMultiVol && base != ArcInfo.MarkerPos)
+ {
+ // do we need that additional attempt to read cd?
+ res = TryReadCd(items, cdInfo, ArcInfo.MarkerPos + cdOffset, cdSize);
+ if (res == S_OK)
+ ArcInfo.Base = (Int64)ArcInfo.MarkerPos;
+ }
+
+ // Some rare case files are unsorted
+ // items.Sort(CompareCdItems, NULL);
+ return res;
+}
+
+
+static int FindItem(const CObjectVector<CItemEx> &items, const CItemEx &item)
+{
+ unsigned left = 0, right = items.Size();
+ for (;;)
+ {
+ if (left >= right)
+ return -1;
+ const unsigned index = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const CItemEx &item2 = items[index];
+ if (item.Disk < item2.Disk)
+ right = index;
+ else if (item.Disk > item2.Disk)
+ left = index + 1;
+ else if (item.LocalHeaderPos == item2.LocalHeaderPos)
+ return (int)index;
+ else if (item.LocalHeaderPos < item2.LocalHeaderPos)
+ right = index;
+ else
+ left = index + 1;
+ }
+}
+
+static bool IsStrangeItem(const CItem &item)
+{
+ return item.Name.Len() > (1 << 14) || item.Method > (1 << 8);
+}
+
+
+
+/*
+ ---------- ReadLocals ----------
+
+in:
+ (_signature == NSignature::kLocalFileHeader)
+ VirtStreamPos : after _signature : position in Stream
+ Stream :
+ Vols : if (IsMultiVol)
+ (_inBufMode == false)
+
+action:
+ it parses local items.
+
+ if ( IsMultiVol) it writes absolute offsets to CItemEx::LocalHeaderPos
+ if (!IsMultiVol) it writes relative (from ArcInfo.Base) offsets to CItemEx::LocalHeaderPos
+ later we can correct CItemEx::LocalHeaderPos values, if
+ some new value for ArcInfo.Base will be detected
+out:
+ S_OK:
+ (_signature != NSignature::kLocalFileHeade)
+ _streamPos : after _signature
+
+ S_FALSE: if no items or there is just one item with strange properies that doesn't look like real archive.
+
+ another error code: stream reading error or Callback error.
+
+ CUnexpectEnd() exception : it's not fatal exception here.
+ It means that reading was interrupted by unexpected end of input stream,
+ but some CItemEx items were parsed OK.
+ We can stop further archive parsing.
+ But we can use all filled CItemEx items.
+*/
+
+HRESULT CInArchive::ReadLocals(CObjectVector<CItemEx> &items)
+{
+ items.Clear();
+
+ UInt64 progressPrev = _cnt;
+
+ if (Callback)
+ {
+ RINOK(Callback->SetTotal(NULL, IsMultiVol ? &Vols.TotalBytesSize : NULL))
+ }
+
+ while (_signature == NSignature::kLocalFileHeader)
+ {
+ CItemEx item;
+
+ item.LocalHeaderPos = GetVirtStreamPos() - 4;
+ if (!IsMultiVol)
+ item.LocalHeaderPos = (UInt64)((Int64)item.LocalHeaderPos - ArcInfo.Base);
+
+ try
+ {
+ ReadLocalItem(item);
+ item.FromLocal = true;
+ bool isFinished = false;
+
+ if (item.HasDescriptor())
+ {
+ RINOK(FindDescriptor(item, items.Size()))
+ isFinished = !item.DescriptorWasRead;
+ }
+ else
+ {
+ if (item.PackSize >= ((UInt64)1 << 62))
+ throw CUnexpectEnd();
+ RINOK(IncreaseRealPosition(item.PackSize, isFinished))
+ }
+
+ items.Add(item);
+
+ if (isFinished)
+ throw CUnexpectEnd();
+
+ ReadSignature();
+ }
+ catch (CUnexpectEnd &)
+ {
+ if (items.IsEmpty() || (items.Size() == 1 && IsStrangeItem(items[0])))
+ return S_FALSE;
+ throw;
+ }
+
+
+ if (Callback)
+ if ((items.Size() & 0xFF) == 0
+ || _cnt - progressPrev >= ((UInt32)1 << 22))
+ {
+ progressPrev = _cnt;
+ const UInt64 numFiles = items.Size();
+ RINOK(Callback->SetCompleted(&numFiles, &_cnt))
+ }
+ }
+
+ if (items.Size() == 1 && _signature != NSignature::kCentralFileHeader)
+ if (IsStrangeItem(items[0]))
+ return S_FALSE;
+
+ return S_OK;
+}
+
+
+
+HRESULT CVols::ParseArcName(IArchiveOpenVolumeCallback *volCallback)
+{
+ UString name;
+ {
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(volCallback->GetProperty(kpidName, &prop))
+ if (prop.vt != VT_BSTR)
+ return S_OK;
+ name = prop.bstrVal;
+ }
+
+ const int dotPos = name.ReverseFind_Dot();
+ if (dotPos < 0)
+ return S_OK;
+ const UString ext = name.Ptr((unsigned)(dotPos + 1));
+ name.DeleteFrom((unsigned)(dotPos + 1));
+
+ StartVolIndex = (Int32)(-1);
+
+ if (ext.IsEmpty())
+ return S_OK;
+ {
+ wchar_t c = ext[0];
+ IsUpperCase = (c >= 'A' && c <= 'Z');
+ if (ext.IsEqualTo_Ascii_NoCase("zip"))
+ {
+ BaseName = name;
+ StartIsZ = true;
+ StartIsZip = true;
+ return S_OK;
+ }
+ else if (ext.IsEqualTo_Ascii_NoCase("exe"))
+ {
+ /* possible cases:
+ - exe with zip inside
+ - sfx: a.exe, a.z02, a.z03,... , a.zip
+ a.exe is start volume.
+ - zip renamed to exe
+ */
+
+ StartIsExe = true;
+ BaseName = name;
+ StartVolIndex = 0;
+ /* sfx-zip can use both arc.exe and arc.zip
+ We can open arc.zip, if it was requesed to open arc.exe.
+ But it's possible that arc.exe and arc.zip are not parts of same archive.
+ So we can disable such operation */
+
+ // 18.04: we still want to open zip renamed to exe.
+ /*
+ {
+ UString volName = name;
+ volName += IsUpperCase ? "Z01" : "z01";
+ {
+ CMyComPtr<IInStream> stream;
+ HRESULT res2 = volCallback->GetStream(volName, &stream);
+ if (res2 == S_OK)
+ DisableVolsSearch = true;
+ }
+ }
+ */
+ DisableVolsSearch = true;
+ return S_OK;
+ }
+ else if (ext[0] == 'z' || ext[0] == 'Z')
+ {
+ if (ext.Len() < 3)
+ return S_OK;
+ const wchar_t *end = NULL;
+ UInt32 volNum = ConvertStringToUInt32(ext.Ptr(1), &end);
+ if (*end != 0 || volNum < 1 || volNum > ((UInt32)1 << 30))
+ return S_OK;
+ StartVolIndex = (Int32)(volNum - 1);
+ BaseName = name;
+ StartIsZ = true;
+ }
+ else
+ return S_OK;
+ }
+
+ UString volName = BaseName;
+ volName += (IsUpperCase ? "ZIP" : "zip");
+
+ HRESULT res = volCallback->GetStream(volName, &ZipStream);
+
+ if (res == S_FALSE || !ZipStream)
+ {
+ if (MissingName.IsEmpty())
+ {
+ MissingZip = true;
+ MissingName = volName;
+ }
+ return S_OK;
+ }
+
+ return res;
+}
+
+
+HRESULT CInArchive::ReadVols2(IArchiveOpenVolumeCallback *volCallback,
+ unsigned start, int lastDisk, int zipDisk, unsigned numMissingVolsMax, unsigned &numMissingVols)
+{
+ if (Vols.DisableVolsSearch)
+ return S_OK;
+
+ numMissingVols = 0;
+
+ for (unsigned i = start;; i++)
+ {
+ if (lastDisk >= 0 && i >= (unsigned)lastDisk)
+ break;
+
+ if (i < Vols.Streams.Size())
+ if (Vols.Streams[i].Stream)
+ continue;
+
+ CMyComPtr<IInStream> stream;
+
+ if ((int)i == zipDisk)
+ {
+ stream = Vols.ZipStream;
+ }
+ else if ((int)i == Vols.StartVolIndex)
+ {
+ stream = StartStream;
+ }
+ else
+ {
+ UString volName = Vols.BaseName;
+ {
+ volName += (char)(Vols.IsUpperCase ? 'Z' : 'z');
+ unsigned v = i + 1;
+ if (v < 10)
+ volName += '0';
+ volName.Add_UInt32(v);
+ }
+
+ HRESULT res = volCallback->GetStream(volName, &stream);
+ if (res != S_OK && res != S_FALSE)
+ return res;
+ if (res == S_FALSE || !stream)
+ {
+ if (i == 0)
+ {
+ UString volName_exe = Vols.BaseName;
+ volName_exe += (Vols.IsUpperCase ? "EXE" : "exe");
+
+ HRESULT res2 = volCallback->GetStream(volName_exe, &stream);
+ if (res2 != S_OK && res2 != S_FALSE)
+ return res2;
+ res = res2;
+ }
+ }
+ if (res == S_FALSE || !stream)
+ {
+ if (i == 1 && Vols.StartIsExe)
+ return S_OK;
+ if (Vols.MissingName.IsEmpty())
+ Vols.MissingName = volName;
+ numMissingVols++;
+ if (numMissingVols > numMissingVolsMax)
+ return S_OK;
+ if (lastDisk == -1 && numMissingVols != 0)
+ return S_OK;
+ continue;
+ }
+ }
+
+ UInt64 pos, size;
+ RINOK(InStream_GetPos_GetSize(stream, pos, size))
+
+ while (i >= Vols.Streams.Size())
+ Vols.Streams.AddNew();
+
+ CVols::CSubStreamInfo &ss = Vols.Streams[i];
+ Vols.NumVols++;
+ Vols.TotalBytesSize += size;
+
+ ss.Stream = stream;
+ ss.Size = size;
+
+ if ((int)i == zipDisk)
+ {
+ Vols.EndVolIndex = (int)(Vols.Streams.Size() - 1);
+ break;
+ }
+ }
+
+ return S_OK;
+}
+
+
+HRESULT CInArchive::ReadVols()
+{
+ CMyComPtr<IArchiveOpenVolumeCallback> volCallback;
+
+ Callback->QueryInterface(IID_IArchiveOpenVolumeCallback, (void **)&volCallback);
+ if (!volCallback)
+ return S_OK;
+
+ RINOK(Vols.ParseArcName(volCallback))
+
+ // const int startZIndex = Vols.StartVolIndex;
+
+ if (!Vols.StartIsZ)
+ {
+ if (!Vols.StartIsExe)
+ return S_OK;
+ }
+
+ int zipDisk = -1;
+ int cdDisk = -1;
+
+ if (Vols.StartIsZip)
+ Vols.ZipStream = StartStream;
+
+ if (Vols.ZipStream)
+ {
+ Stream = Vols.ZipStream;
+
+ if (Vols.StartIsZip)
+ Vols.StreamIndex = -1;
+ else
+ {
+ Vols.StreamIndex = -2;
+ InitBuf();
+ }
+
+ HRESULT res = FindCd(true);
+
+ CCdInfo &ecd = Vols.ecd;
+ if (res == S_OK)
+ {
+ zipDisk = (int)ecd.ThisDisk;
+ Vols.ecd_wasRead = true;
+
+ // if is not multivol or bad multivol, we return to main single stream code
+ if (ecd.ThisDisk == 0
+ || ecd.ThisDisk >= ((UInt32)1 << 30)
+ || ecd.ThisDisk < ecd.CdDisk)
+ return S_OK;
+
+ cdDisk = (int)ecd.CdDisk;
+ if (Vols.StartVolIndex < 0)
+ Vols.StartVolIndex = (Int32)ecd.ThisDisk;
+ else if ((UInt32)Vols.StartVolIndex >= ecd.ThisDisk)
+ return S_OK;
+
+ // Vols.StartVolIndex = ecd.ThisDisk;
+ // Vols.EndVolIndex = ecd.ThisDisk;
+ unsigned numMissingVols;
+ if (cdDisk != zipDisk)
+ {
+ // get volumes required for cd.
+ RINOK(ReadVols2(volCallback, (unsigned)cdDisk, zipDisk, zipDisk, 0, numMissingVols))
+ if (numMissingVols != 0)
+ {
+ // cdOK = false;
+ }
+ }
+ }
+ else if (res != S_FALSE)
+ return res;
+ }
+
+ if (Vols.StartVolIndex < 0)
+ {
+ // is not mutivol;
+ return S_OK;
+ }
+
+ /*
+ if (!Vols.Streams.IsEmpty())
+ IsMultiVol = true;
+ */
+
+ unsigned numMissingVols;
+
+ if (cdDisk != 0)
+ {
+ // get volumes that were no requested still
+ const unsigned kNumMissingVolsMax = 1 << 12;
+ RINOK(ReadVols2(volCallback, 0, cdDisk < 0 ? -1 : cdDisk, zipDisk, kNumMissingVolsMax, numMissingVols))
+ }
+
+ // if (Vols.StartVolIndex >= 0)
+ {
+ if (Vols.Streams.IsEmpty())
+ if (Vols.StartVolIndex > (1 << 20))
+ return S_OK;
+ if ((unsigned)Vols.StartVolIndex >= Vols.Streams.Size()
+ || !Vols.Streams[(unsigned)Vols.StartVolIndex].Stream)
+ {
+ // we get volumes starting from StartVolIndex, if they we not requested before know the volume index (if FindCd() was ok)
+ RINOK(ReadVols2(volCallback, (unsigned)Vols.StartVolIndex, zipDisk, zipDisk, 0, numMissingVols))
+ }
+ }
+
+ if (Vols.ZipStream)
+ {
+ // if there is no another volumes and volumeIndex is too big, we don't use multivol mode
+ if (Vols.Streams.IsEmpty())
+ if (zipDisk > (1 << 10))
+ return S_OK;
+ if (zipDisk >= 0)
+ {
+ // we create item in Streams for ZipStream, if we know the volume index (if FindCd() was ok)
+ RINOK(ReadVols2(volCallback, (unsigned)zipDisk, zipDisk + 1, zipDisk, 0, numMissingVols))
+ }
+ }
+
+ if (!Vols.Streams.IsEmpty())
+ {
+ IsMultiVol = true;
+ /*
+ if (cdDisk)
+ IsMultiVol = true;
+ */
+ const int startZIndex = Vols.StartVolIndex;
+ if (startZIndex >= 0)
+ {
+ // if all volumes before start volume are OK, we can start parsing from 0
+ // if there are missing volumes before startZIndex, we start parsing in current startZIndex
+ if ((unsigned)startZIndex < Vols.Streams.Size())
+ {
+ for (unsigned i = 0; i <= (unsigned)startZIndex; i++)
+ if (!Vols.Streams[i].Stream)
+ {
+ Vols.StartParsingVol = startZIndex;
+ break;
+ }
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+HRESULT CVols::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+
+ for (;;)
+ {
+ if (StreamIndex < 0)
+ return S_OK;
+ if ((unsigned)StreamIndex >= Streams.Size())
+ return S_OK;
+ const CVols::CSubStreamInfo &s = Streams[(unsigned)StreamIndex];
+ if (!s.Stream)
+ return S_FALSE;
+ if (NeedSeek)
+ {
+ RINOK(s.SeekToStart())
+ NeedSeek = false;
+ }
+ UInt32 realProcessedSize = 0;
+ HRESULT res = s.Stream->Read(data, size, &realProcessedSize);
+ if (processedSize)
+ *processedSize = realProcessedSize;
+ if (res != S_OK)
+ return res;
+ if (realProcessedSize != 0)
+ return res;
+ StreamIndex++;
+ NeedSeek = true;
+ }
+}
+
+Z7_COM7F_IMF(CVolStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ return Vols->Read(data, size, processedSize);
+}
+
+
+
+
+#define COPY_ECD_ITEM_16(n) if (!isZip64 || !ZIP64_IS_16_MAX(ecd. n)) cdInfo. n = ecd. n;
+#define COPY_ECD_ITEM_32(n) if (!isZip64 || !ZIP64_IS_32_MAX(ecd. n)) cdInfo. n = ecd. n;
+
+
+HRESULT CInArchive::ReadHeaders(CObjectVector<CItemEx> &items)
+{
+ // buffer that can be used for cd reading
+ RINOK(AllocateBuffer(kSeqBufferSize))
+
+ // here we can read small records. So we switch off _inBufMode.
+ _inBufMode = false;
+
+ HRESULT res = S_OK;
+
+ bool localsWereRead = false;
+
+ /* we try to open archive with the following modes:
+ 1) CD-MODE : fast mode : we read backward ECD and CD, compare CD items with first Local item.
+ 2) LOCALS-CD-MODE : slow mode, if CD-MODE fails : we sequentially read all Locals and then CD.
+ Then we read sequentially ECD64, Locator, ECD again at the end.
+
+ - in LOCALS-CD-MODE we use use the following
+ variables (with real cd properties) to set Base archive offset
+ and check real cd properties with values from ECD/ECD64.
+ */
+
+ UInt64 cdSize = 0;
+ UInt64 cdRelatOffset = 0;
+ UInt32 cdDisk = 0;
+
+ UInt64 cdAbsOffset = 0; // absolute cd offset, for LOCALS-CD-MODE only.
+
+if (Force_ReadLocals_Mode)
+{
+ IsArc = true;
+ res = S_FALSE; // we will use LOCALS-CD-MODE mode
+}
+else
+{
+ if (!MarkerIsFound || !MarkerIsSafe)
+ {
+ IsArc = true;
+ res = ReadCd(items, cdDisk, cdRelatOffset, cdSize);
+ if (res == S_OK)
+ ReadSignature();
+ else if (res != S_FALSE)
+ return res;
+ }
+ else // (MarkerIsFound && MarkerIsSafe)
+ {
+
+ // _signature must be kLocalFileHeader or kEcd or kEcd64
+
+ SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2 + 4);
+
+ CanStartNewVol = false;
+
+ if (_signature == NSignature::kEcd64)
+ {
+ // UInt64 ecd64Offset = GetVirtStreamPos() - 4;
+ IsZip64 = true;
+
+ {
+ const UInt64 recordSize = ReadUInt64();
+ if (recordSize < kEcd64_MainSize)
+ return S_FALSE;
+ if (recordSize >= ((UInt64)1 << 62))
+ return S_FALSE;
+
+ {
+ const unsigned kBufSize = kEcd64_MainSize;
+ Byte buf[kBufSize];
+ SafeRead(buf, kBufSize);
+ CCdInfo cdInfo;
+ cdInfo.ParseEcd64e(buf);
+ if (!cdInfo.IsEmptyArc())
+ return S_FALSE;
+ }
+
+ RINOK(Skip64(recordSize - kEcd64_MainSize, 0))
+ }
+
+ ReadSignature();
+ if (_signature != NSignature::kEcd64Locator)
+ return S_FALSE;
+
+ {
+ const unsigned kBufSize = 16;
+ Byte buf[kBufSize];
+ SafeRead(buf, kBufSize);
+ CLocator locator;
+ locator.Parse(buf);
+ if (!locator.IsEmptyArc())
+ return S_FALSE;
+ }
+
+ ReadSignature();
+ if (_signature != NSignature::kEcd)
+ return S_FALSE;
+ }
+
+ if (_signature == NSignature::kEcd)
+ {
+ // It must be empty archive or backware archive
+ // we don't support backware archive still
+
+ const unsigned kBufSize = kEcdSize - 4;
+ Byte buf[kBufSize];
+ SafeRead(buf, kBufSize);
+ CEcd ecd;
+ ecd.Parse(buf);
+ // if (ecd.cdSize != 0)
+ // Do we need also to support the case where empty zip archive with PK00 uses cdOffset = 4 ??
+ if (!ecd.IsEmptyArc())
+ return S_FALSE;
+
+ ArcInfo.Base = (Int64)ArcInfo.MarkerPos;
+ IsArc = true; // check it: we need more tests?
+
+ RINOK(SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2))
+ ReadSignature();
+ }
+ else
+ {
+ CItemEx firstItem;
+ try
+ {
+ try
+ {
+ if (!ReadLocalItem(firstItem))
+ return S_FALSE;
+ }
+ catch(CUnexpectEnd &)
+ {
+ return S_FALSE;
+ }
+
+ IsArc = true;
+ res = ReadCd(items, cdDisk, cdRelatOffset, cdSize);
+ if (res == S_OK)
+ ReadSignature();
+ }
+ catch(CUnexpectEnd &) { res = S_FALSE; }
+
+ if (res != S_FALSE && res != S_OK)
+ return res;
+
+ if (res == S_OK && items.Size() == 0)
+ res = S_FALSE;
+
+ if (res == S_OK)
+ {
+ // we can't read local items here to keep _inBufMode state
+ if ((Int64)ArcInfo.MarkerPos2 < ArcInfo.Base)
+ res = S_FALSE;
+ else
+ {
+ firstItem.LocalHeaderPos = (UInt64)((Int64)ArcInfo.MarkerPos2 - ArcInfo.Base);
+ int index = -1;
+
+ UInt32 min_Disk = (UInt32)(Int32)-1;
+ UInt64 min_LocalHeaderPos = (UInt64)(Int64)-1;
+
+ if (!IsCdUnsorted)
+ index = FindItem(items, firstItem);
+ else
+ {
+ FOR_VECTOR (i, items)
+ {
+ const CItemEx &cdItem = items[i];
+ if (cdItem.Disk == firstItem.Disk
+ && (cdItem.LocalHeaderPos == firstItem.LocalHeaderPos))
+ index = (int)i;
+
+ if (i == 0
+ || cdItem.Disk < min_Disk
+ || (cdItem.Disk == min_Disk && cdItem.LocalHeaderPos < min_LocalHeaderPos))
+ {
+ min_Disk = cdItem.Disk;
+ min_LocalHeaderPos = cdItem.LocalHeaderPos;
+ }
+ }
+ }
+
+ if (index == -1)
+ res = S_FALSE;
+ else if (!AreItemsEqual(firstItem, items[(unsigned)index]))
+ res = S_FALSE;
+ else
+ {
+ ArcInfo.CdWasRead = true;
+ if (IsCdUnsorted)
+ ArcInfo.FirstItemRelatOffset = min_LocalHeaderPos;
+ else
+ ArcInfo.FirstItemRelatOffset = items[0].LocalHeaderPos;
+
+ // ArcInfo.FirstItemRelatOffset = _startLocalFromCd_Offset;
+ }
+ }
+ }
+ }
+ } // (MarkerIsFound && MarkerIsSafe)
+
+} // (!onlyLocalsMode)
+
+
+ CObjectVector<CItemEx> cdItems;
+
+ bool needSetBase = false; // we set needSetBase only for LOCALS_CD_MODE
+ unsigned numCdItems = items.Size();
+
+ #ifdef ZIP_SELF_CHECK
+ res = S_FALSE; // if uncommented, it uses additional LOCALS-CD-MODE mode to check the code
+ #endif
+
+ if (res != S_OK)
+ {
+ // ---------- LOCALS-CD-MODE ----------
+ // CD doesn't match firstItem,
+ // so we clear items and read Locals and CD.
+
+ items.Clear();
+ localsWereRead = true;
+
+ HeadersError = false;
+ HeadersWarning = false;
+ ExtraMinorError = false;
+
+ /* we can use any mode: with buffer and without buffer
+ without buffer : skips packed data : fast for big files : slow for small files
+ with buffer : reads packed data : slow for big files : fast for small files
+ Buffer mode is more effective. */
+ // _inBufMode = false;
+ _inBufMode = true;
+ // we could change the buffer size here, if we want smaller Buffer.
+ // RINOK(ReAllocateBuffer(kSeqBufferSize));
+ // InitBuf()
+
+ ArcInfo.Base = 0;
+
+ if (!Disable_FindMarker)
+ {
+ if (!MarkerIsFound)
+ {
+ if (!IsMultiVol)
+ return S_FALSE;
+ if (Vols.StartParsingVol != 0)
+ return S_FALSE;
+ // if (StartParsingVol == 0) and we didn't find marker, we use default zero marker.
+ // so we suppose that there is no sfx stub
+ RINOK(SeekToVol(0, ArcInfo.MarkerPos2))
+ }
+ else
+ {
+ if (ArcInfo.MarkerPos != 0)
+ {
+ /*
+ If multi-vol or there is (No)Span-marker at start of stream, we set (Base) as 0.
+ In another caes:
+ (No)Span-marker is supposed as false positive. So we set (Base) as main marker (MarkerPos2).
+ The (Base) can be corrected later after ECD reading.
+ But sfx volume with stub and (No)Span-marker in (!IsMultiVol) mode will have incorrect (Base) here.
+ */
+ ArcInfo.Base = (Int64)ArcInfo.MarkerPos2;
+ }
+ RINOK(SeekToVol(ArcInfo.MarkerVolIndex, ArcInfo.MarkerPos2))
+ }
+ }
+ _cnt = 0;
+
+ ReadSignature();
+
+ LocalsWereRead = true;
+
+ RINOK(ReadLocals(items))
+
+ if (_signature != NSignature::kCentralFileHeader)
+ {
+ // GetVirtStreamPos() - 4
+ if (items.IsEmpty())
+ return S_FALSE;
+
+ bool isError = true;
+
+ const UInt32 apkSize = _signature;
+ const unsigned kApkFooterSize = 16 + 8;
+ if (apkSize >= kApkFooterSize && apkSize <= (1 << 20))
+ {
+ if (ReadUInt32() == 0)
+ {
+ CByteBuffer apk;
+ apk.Alloc(apkSize);
+ SafeRead(apk, apkSize);
+ ReadSignature();
+ const Byte *footer = apk + apkSize - kApkFooterSize;
+ if (_signature == NSignature::kCentralFileHeader)
+ if (GetUi64(footer) == apkSize)
+ if (memcmp(footer + 8, "APK Sig Block 42", 16) == 0)
+ {
+ isError = false;
+ IsApk = true;
+ }
+ }
+ }
+
+ if (isError)
+ {
+ NoCentralDir = true;
+ HeadersError = true;
+ return S_OK;
+ }
+ }
+
+ _inBufMode = true;
+
+ cdAbsOffset = GetVirtStreamPos() - 4;
+ cdDisk = (UInt32)Vols.StreamIndex;
+
+ #ifdef ZIP_SELF_CHECK
+ if (!IsMultiVol && _cnt != GetVirtStreamPos() - ArcInfo.MarkerPos2)
+ return E_FAIL;
+ #endif
+
+ const UInt64 processedCnt_start = _cnt;
+
+ for (;;)
+ {
+ CItemEx cdItem;
+
+ RINOK(ReadCdItem(cdItem))
+
+ cdItems.Add(cdItem);
+ if (Callback && (cdItems.Size() & 0xFFF) == 0)
+ {
+ const UInt64 numFiles = items.Size();
+ const UInt64 numBytes = _cnt;
+ RINOK(Callback->SetCompleted(&numFiles, &numBytes))
+ }
+ ReadSignature();
+ if (_signature != NSignature::kCentralFileHeader)
+ break;
+ }
+
+ cdSize = _cnt - processedCnt_start;
+
+ #ifdef ZIP_SELF_CHECK
+ if (!IsMultiVol)
+ {
+ if (_cnt != GetVirtStreamPos() - ArcInfo.MarkerPos2)
+ return E_FAIL;
+ if (cdSize != (GetVirtStreamPos() - 4) - cdAbsOffset)
+ return E_FAIL;
+ }
+ #endif
+
+ needSetBase = true;
+ numCdItems = cdItems.Size();
+ cdRelatOffset = (UInt64)((Int64)cdAbsOffset - ArcInfo.Base);
+
+ if (!cdItems.IsEmpty())
+ {
+ ArcInfo.CdWasRead = true;
+ ArcInfo.FirstItemRelatOffset = cdItems[0].LocalHeaderPos;
+ }
+ }
+
+
+
+ CCdInfo cdInfo;
+ CLocator locator;
+ bool isZip64 = false;
+ const UInt64 ecd64AbsOffset = GetVirtStreamPos() - 4;
+ int ecd64Disk = -1;
+
+ if (_signature == NSignature::kEcd64)
+ {
+ ecd64Disk = Vols.StreamIndex;
+
+ IsZip64 = isZip64 = true;
+
+ {
+ const UInt64 recordSize = ReadUInt64();
+ if (recordSize < kEcd64_MainSize
+ || recordSize >= ((UInt64)1 << 62))
+ {
+ HeadersError = true;
+ return S_OK;
+ }
+
+ {
+ const unsigned kBufSize = kEcd64_MainSize;
+ Byte buf[kBufSize];
+ SafeRead(buf, kBufSize);
+ cdInfo.ParseEcd64e(buf);
+ }
+
+ RINOK(Skip64(recordSize - kEcd64_MainSize, items.Size()))
+ }
+
+
+ ReadSignature();
+
+ if (_signature != NSignature::kEcd64Locator)
+ {
+ HeadersError = true;
+ return S_OK;
+ }
+
+ {
+ const unsigned kBufSize = 16;
+ Byte buf[kBufSize];
+ SafeRead(buf, kBufSize);
+ locator.Parse(buf);
+ // we ignore the error, where some zip creators use (NumDisks == 0)
+ // if (locator.NumDisks == 0) HeadersWarning = true;
+ }
+
+ ReadSignature();
+ }
+
+
+ if (_signature != NSignature::kEcd)
+ {
+ HeadersError = true;
+ return S_OK;
+ }
+
+
+ CanStartNewVol = false;
+
+ // ---------- ECD ----------
+
+ CEcd ecd;
+ {
+ const unsigned kBufSize = kEcdSize - 4;
+ Byte buf[kBufSize];
+ SafeRead(buf, kBufSize);
+ ecd.Parse(buf);
+ }
+
+ COPY_ECD_ITEM_16(ThisDisk)
+ COPY_ECD_ITEM_16(CdDisk)
+ COPY_ECD_ITEM_16(NumEntries_in_ThisDisk)
+ COPY_ECD_ITEM_16(NumEntries)
+ COPY_ECD_ITEM_32(Size)
+ COPY_ECD_ITEM_32(Offset)
+
+ bool cdOK = true;
+
+ if ((UInt32)cdInfo.Size != (UInt32)cdSize)
+ {
+ // return S_FALSE;
+ cdOK = false;
+ }
+
+ if (isZip64)
+ {
+ if (cdInfo.NumEntries != numCdItems
+ || cdInfo.Size != cdSize)
+ {
+ cdOK = false;
+ }
+ }
+
+
+ if (IsMultiVol)
+ {
+ if (cdDisk != cdInfo.CdDisk)
+ HeadersError = true;
+ }
+ else if (needSetBase && cdOK)
+ {
+ const UInt64 oldBase = (UInt64)ArcInfo.Base;
+ // localsWereRead == true
+ // ArcInfo.Base == ArcInfo.MarkerPos2
+ // cdRelatOffset == (cdAbsOffset - ArcInfo.Base)
+
+ if (isZip64)
+ {
+ if (ecd64Disk == Vols.StartVolIndex)
+ {
+ const Int64 newBase = (Int64)ecd64AbsOffset - (Int64)locator.Ecd64Offset;
+ if (newBase <= (Int64)ecd64AbsOffset)
+ {
+ if (!localsWereRead || newBase <= (Int64)ArcInfo.MarkerPos2)
+ {
+ ArcInfo.Base = newBase;
+ cdRelatOffset = (UInt64)((Int64)cdAbsOffset - newBase);
+ }
+ else
+ cdOK = false;
+ }
+ }
+ }
+ else if (numCdItems != 0) // we can't use ecd.Offset in empty archive?
+ {
+ if ((int)cdDisk == Vols.StartVolIndex)
+ {
+ const Int64 newBase = (Int64)cdAbsOffset - (Int64)cdInfo.Offset;
+ if (newBase <= (Int64)cdAbsOffset)
+ {
+ if (!localsWereRead || newBase <= (Int64)ArcInfo.MarkerPos2)
+ {
+ // cd can be more accurate, when it points before Locals
+ // so we change Base and cdRelatOffset
+ ArcInfo.Base = newBase;
+ cdRelatOffset = cdInfo.Offset;
+ }
+ else
+ {
+ // const UInt64 delta = ((UInt64)cdRelatOffset - cdInfo.Offset);
+ const UInt64 delta = ((UInt64)(newBase - ArcInfo.Base));
+ if ((UInt32)delta == 0)
+ {
+ // we set Overflow32bit mode, only if there is (x<<32) offset
+ // between real_CD_offset_from_MarkerPos and CD_Offset_in_ECD.
+ // Base and cdRelatOffset unchanged
+ Overflow32bit = true;
+ }
+ else
+ cdOK = false;
+ }
+ }
+ else
+ cdOK = false;
+ }
+ }
+ // cdRelatOffset = cdAbsOffset - ArcInfo.Base;
+
+ if (localsWereRead)
+ {
+ const UInt64 delta = (UInt64)((Int64)oldBase - ArcInfo.Base);
+ if (delta != 0)
+ {
+ FOR_VECTOR (i, items)
+ items[i].LocalHeaderPos += delta;
+ }
+ }
+ }
+
+ if (!cdOK)
+ HeadersError = true;
+
+ EcdVolIndex = cdInfo.ThisDisk;
+
+ if (!IsMultiVol)
+ {
+ if (EcdVolIndex == 0 && Vols.MissingZip && Vols.StartIsExe)
+ {
+ Vols.MissingName.Empty();
+ Vols.MissingZip = false;
+ }
+
+ if (localsWereRead)
+ {
+ if (EcdVolIndex != 0)
+ {
+ FOR_VECTOR (i, items)
+ items[i].Disk = EcdVolIndex;
+ }
+ }
+
+ UseDisk_in_SingleVol = true;
+ }
+
+ if (isZip64)
+ {
+ if ((cdInfo.ThisDisk == 0 && ecd64AbsOffset != (UInt64)(ArcInfo.Base + (Int64)locator.Ecd64Offset))
+ // || cdInfo.NumEntries_in_ThisDisk != numCdItems
+ || cdInfo.NumEntries != numCdItems
+ || cdInfo.Size != cdSize
+ || (cdInfo.Offset != cdRelatOffset && !items.IsEmpty()))
+ {
+ HeadersError = true;
+ return S_OK;
+ }
+ }
+
+ if (cdOK && !cdItems.IsEmpty())
+ {
+ // ---------- merge Central Directory Items ----------
+
+ CRecordVector<unsigned> items2;
+
+ int nextLocalIndex = 0;
+
+ LocalsCenterMerged = true;
+
+ FOR_VECTOR (i, cdItems)
+ {
+ if (Callback)
+ if ((i & 0x3FFF) == 0)
+ {
+ const UInt64 numFiles64 = items.Size() + items2.Size();
+ RINOK(Callback->SetCompleted(&numFiles64, &_cnt))
+ }
+
+ const CItemEx &cdItem = cdItems[i];
+
+ int index = -1;
+
+ if (nextLocalIndex != -1)
+ {
+ if ((unsigned)nextLocalIndex < items.Size())
+ {
+ CItemEx &item = items[(unsigned)nextLocalIndex];
+ if (item.Disk == cdItem.Disk &&
+ (item.LocalHeaderPos == cdItem.LocalHeaderPos
+ || (Overflow32bit && (UInt32)item.LocalHeaderPos == cdItem.LocalHeaderPos)))
+ index = nextLocalIndex++;
+ else
+ nextLocalIndex = -1;
+ }
+ }
+
+ if (index == -1)
+ index = FindItem(items, cdItem);
+
+ // index = -1;
+
+ if (index == -1)
+ {
+ items2.Add(i);
+ HeadersError = true;
+ continue;
+ }
+
+ CItemEx &item = items[(unsigned)index];
+ if (item.Name != cdItem.Name
+ // || item.Name.Len() != cdItem.Name.Len()
+ || item.PackSize != cdItem.PackSize
+ || item.Size != cdItem.Size
+ // item.ExtractVersion != cdItem.ExtractVersion
+ || !FlagsAreSame(item, cdItem)
+ || item.Crc != cdItem.Crc)
+ {
+ HeadersError = true;
+ continue;
+ }
+
+ // item.Name = cdItem.Name;
+ item.MadeByVersion = cdItem.MadeByVersion;
+ item.CentralExtra = cdItem.CentralExtra;
+ item.InternalAttrib = cdItem.InternalAttrib;
+ item.ExternalAttrib = cdItem.ExternalAttrib;
+ item.Comment = cdItem.Comment;
+ item.FromCentral = cdItem.FromCentral;
+ // 22.02: we force utf8 flag, if central header has utf8 flag
+ if (cdItem.Flags & NFileHeader::NFlags::kUtf8)
+ item.Flags |= NFileHeader::NFlags::kUtf8;
+ }
+
+ FOR_VECTOR (k, items2)
+ items.Add(cdItems[items2[k]]);
+ }
+
+ if (ecd.NumEntries < ecd.NumEntries_in_ThisDisk)
+ HeadersError = true;
+
+ if (ecd.ThisDisk == 0)
+ {
+ // if (isZip64)
+ {
+ if (ecd.NumEntries != ecd.NumEntries_in_ThisDisk)
+ HeadersError = true;
+ }
+ }
+
+ if (isZip64)
+ {
+ if (cdInfo.NumEntries != items.Size()
+ || (ecd.NumEntries != items.Size() && ecd.NumEntries != 0xFFFF))
+ HeadersError = true;
+ }
+ else
+ {
+ // old 7-zip could store 32-bit number of CD items to 16-bit field.
+ // if (ecd.NumEntries != items.Size())
+ if (ecd.NumEntries > items.Size())
+ HeadersError = true;
+
+ if (cdInfo.NumEntries != numCdItems)
+ {
+ if ((UInt16)cdInfo.NumEntries != (UInt16)numCdItems)
+ HeadersError = true;
+ else
+ Cd_NumEntries_Overflow_16bit = true;
+ }
+ }
+
+ ReadBuffer(ArcInfo.Comment, ecd.CommentSize);
+
+ _inBufMode = false;
+
+ // DisableBufMode();
+ // Buffer.Free();
+ /* we can't clear buf varibles. we need them to calculate PhySize of archive */
+
+ if ((UInt16)cdInfo.NumEntries != (UInt16)numCdItems
+ || (UInt32)cdInfo.Size != (UInt32)cdSize
+ || ((UInt32)cdInfo.Offset != (UInt32)cdRelatOffset && !items.IsEmpty()))
+ {
+ // return S_FALSE;
+ HeadersError = true;
+ }
+
+ #ifdef ZIP_SELF_CHECK
+ if (localsWereRead)
+ {
+ const UInt64 endPos = ArcInfo.MarkerPos2 + _cnt;
+ if (endPos != (IsMultiVol ? Vols.TotalBytesSize : ArcInfo.FileEndPos))
+ {
+ // there are some data after the end of archive or error in code;
+ return E_FAIL;
+ }
+ }
+ #endif
+
+ // printf("\nOpen OK");
+ return S_OK;
+}
+
+
+
+HRESULT CInArchive::Open(IInStream *stream, const UInt64 *searchLimit,
+ IArchiveOpenCallback *callback, CObjectVector<CItemEx> &items)
+{
+ items.Clear();
+
+ Close();
+
+ UInt64 startPos;
+ RINOK(InStream_GetPos(stream, startPos))
+ RINOK(InStream_GetSize_SeekToEnd(stream, ArcInfo.FileEndPos))
+ _streamPos = ArcInfo.FileEndPos;
+
+ StartStream = stream;
+ Stream = stream;
+ Callback = callback;
+
+ DisableBufMode();
+
+ bool volWasRequested = false;
+
+ if (!Disable_VolsRead)
+ if (callback
+ && (startPos == 0 || !searchLimit || *searchLimit != 0))
+ {
+ // we try to read volumes only if it's first call (offset == 0) or scan is allowed.
+ volWasRequested = true;
+ RINOK(ReadVols())
+ }
+
+ if (Disable_FindMarker)
+ {
+ RINOK(SeekToVol(-1, startPos))
+ StreamRef = stream;
+ Stream = stream;
+ MarkerIsFound = true;
+ MarkerIsSafe = true;
+ ArcInfo.MarkerPos = startPos;
+ ArcInfo.MarkerPos2 = startPos;
+ }
+ else
+ if (IsMultiVol && Vols.StartParsingVol == 0 && (unsigned)Vols.StartParsingVol < Vols.Streams.Size())
+ {
+ // only StartParsingVol = 0 is safe search.
+ RINOK(SeekToVol(0, 0))
+ // if (Stream)
+ {
+ // UInt64 limit = 1 << 22; // for sfx
+ UInt64 limit = 0; // without sfx
+
+ HRESULT res = FindMarker(&limit);
+
+ if (res == S_OK)
+ {
+ MarkerIsFound = true;
+ MarkerIsSafe = true;
+ }
+ else if (res != S_FALSE)
+ return res;
+ }
+ }
+ else
+ {
+ // printf("\nOpen offset = %u\n", (unsigned)startPos);
+ if (IsMultiVol
+ && (unsigned)Vols.StartParsingVol < Vols.Streams.Size()
+ && Vols.Streams[(unsigned)Vols.StartParsingVol].Stream)
+ {
+ RINOK(SeekToVol(Vols.StartParsingVol, Vols.StreamIndex == Vols.StartVolIndex ? startPos : 0))
+ }
+ else
+ {
+ RINOK(SeekToVol(-1, startPos))
+ }
+
+ // UInt64 limit = 1 << 22;
+ // HRESULT res = FindMarker(&limit);
+
+ HRESULT res = FindMarker(searchLimit);
+
+ // const UInt64 curPos = GetVirtStreamPos();
+ const UInt64 curPos = ArcInfo.MarkerPos2 + 4;
+
+ if (res == S_OK)
+ MarkerIsFound = true;
+ else if (!IsMultiVol)
+ {
+ /*
+ // if (startPos != 0), probably CD could be already tested with another call with (startPos == 0).
+ // so we don't want to try to open CD again in that case.
+ if (startPos != 0)
+ return res;
+ // we can try to open CD, if there is no Marker and (startPos == 0).
+ // is it OK to open such files as ZIP, or big number of false positive, when CD can be find in end of file ?
+ */
+ return res;
+ }
+
+ if (ArcInfo.IsSpanMode && !volWasRequested)
+ {
+ RINOK(ReadVols())
+ if (IsMultiVol && MarkerIsFound && ArcInfo.MarkerVolIndex < 0)
+ ArcInfo.MarkerVolIndex = Vols.StartVolIndex;
+ }
+
+ MarkerIsSafe = !IsMultiVol
+ || (ArcInfo.MarkerVolIndex == 0 && ArcInfo.MarkerPos == 0)
+ ;
+
+
+ if (IsMultiVol)
+ {
+ if ((unsigned)Vols.StartVolIndex < Vols.Streams.Size())
+ {
+ Stream = Vols.Streams[(unsigned)Vols.StartVolIndex].Stream;
+ if (Stream)
+ {
+ RINOK(Seek_SavePos(curPos))
+ }
+ else
+ IsMultiVol = false;
+ }
+ else
+ IsMultiVol = false;
+ }
+
+ if (!IsMultiVol)
+ {
+ if (Vols.StreamIndex != -1)
+ {
+ Stream = StartStream;
+ Vols.StreamIndex = -1;
+ InitBuf();
+ RINOK(Seek_SavePos(curPos))
+ }
+
+ ArcInfo.MarkerVolIndex = -1;
+ StreamRef = stream;
+ Stream = stream;
+ }
+ }
+
+
+ if (!IsMultiVol)
+ Vols.ClearRefs();
+
+ {
+ HRESULT res;
+ try
+ {
+ res = ReadHeaders(items);
+ }
+ catch (const CSystemException &e) { res = e.ErrorCode; }
+ catch (const CUnexpectEnd &)
+ {
+ if (items.IsEmpty())
+ return S_FALSE;
+ UnexpectedEnd = true;
+ res = S_OK;
+ }
+ catch (...)
+ {
+ DisableBufMode();
+ throw;
+ }
+
+ if (IsMultiVol)
+ {
+ ArcInfo.FinishPos = ArcInfo.FileEndPos;
+ if ((unsigned)Vols.StreamIndex < Vols.Streams.Size())
+ if (GetVirtStreamPos() < Vols.Streams[(unsigned)Vols.StreamIndex].Size)
+ ArcInfo.ThereIsTail = true;
+ }
+ else
+ {
+ ArcInfo.FinishPos = GetVirtStreamPos();
+ ArcInfo.ThereIsTail = (ArcInfo.FileEndPos > ArcInfo.FinishPos);
+ }
+
+ DisableBufMode();
+
+ IsArcOpen = true;
+ if (!IsMultiVol)
+ Vols.Streams.Clear();
+ return res;
+ }
+}
+
+
+HRESULT CInArchive::GetItemStream(const CItemEx &item, bool seekPackData, CMyComPtr<ISequentialInStream> &stream)
+{
+ stream.Release();
+
+ UInt64 pos = item.LocalHeaderPos;
+ if (seekPackData)
+ pos += item.LocalFullHeaderSize;
+
+ if (!IsMultiVol)
+ {
+ if (UseDisk_in_SingleVol && item.Disk != EcdVolIndex)
+ return S_OK;
+ pos = (UInt64)((Int64)pos + ArcInfo.Base);
+ RINOK(InStream_SeekSet(StreamRef, pos))
+ stream = StreamRef;
+ return S_OK;
+ }
+
+ if (item.Disk >= Vols.Streams.Size())
+ return S_OK;
+
+ IInStream *str2 = Vols.Streams[item.Disk].Stream;
+ if (!str2)
+ return S_OK;
+ RINOK(InStream_SeekSet(str2, pos))
+
+ Vols.NeedSeek = false;
+ Vols.StreamIndex = (int)item.Disk;
+
+ CVolStream *volsStreamSpec = new CVolStream;
+ volsStreamSpec->Vols = &Vols;
+ stream = volsStreamSpec;
+
+ return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Zip/ZipIn.h b/CPP/7zip/Archive/Zip/ZipIn.h
new file mode 100644
index 0000000..bea26dc
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipIn.h
@@ -0,0 +1,449 @@
+// Archive/ZipIn.h
+
+#ifndef ZIP7_INC_ZIP_IN_H
+#define ZIP7_INC_ZIP_IN_H
+
+#include "../../../Common/MyBuffer2.h"
+#include "../../../Common/MyCom.h"
+
+#include "../../Common/StreamUtils.h"
+#include "../../IStream.h"
+
+#include "ZipHeader.h"
+#include "ZipItem.h"
+
+API_FUNC_IsArc IsArc_Zip(const Byte *p, size_t size);
+
+namespace NArchive {
+namespace NZip {
+
+class CItemEx: public CItem
+{
+public:
+ UInt32 LocalFullHeaderSize; // including Name and Extra
+ // int ParentOfAltStream; // -1, if not AltStream
+
+ bool DescriptorWasRead;
+
+ CItemEx():
+ // ParentOfAltStream(-1),
+ DescriptorWasRead(false) {}
+
+ UInt64 GetLocalFullSize() const
+ { return LocalFullHeaderSize + GetPackSizeWithDescriptor(); }
+ UInt64 GetDataPosition() const
+ { return LocalHeaderPos + LocalFullHeaderSize; }
+
+ bool IsBadDescriptor() const
+ {
+ return !FromCentral && FromLocal && HasDescriptor() && !DescriptorWasRead;
+ }
+};
+
+
+struct CInArchiveInfo
+{
+ Int64 Base; /* Base offset of start of archive in stream.
+ Offsets in headers must be calculated from that Base.
+ Base is equal to MarkerPos for normal ZIPs.
+ Base can point to PE stub for some ZIP SFXs.
+ if CentralDir was read,
+ Base can be negative, if start of data is not available,
+ if CentralDirs was not read,
+ Base = ArcInfo.MarkerPos; */
+
+ /* The following *Pos variables contain absolute offsets in Stream */
+
+ UInt64 MarkerPos; /* Pos of first signature, it can point to kSpan/kNoSpan signature
+ = MarkerPos2 in most archives
+ = MarkerPos2 - 4 if there is kSpan/kNoSpan signature */
+ UInt64 MarkerPos2; // Pos of first local item signature in stream
+ UInt64 FinishPos; // Finish pos of archive data in starting volume
+ UInt64 FileEndPos; // Finish pos of stream
+
+ UInt64 FirstItemRelatOffset; /* Relative offset of first local (read from cd) (relative to Base).
+ = 0 in most archives
+ = size of stub for some SFXs */
+
+
+ int MarkerVolIndex;
+
+ bool CdWasRead;
+ bool IsSpanMode;
+ bool ThereIsTail;
+
+ // UInt32 BaseVolIndex;
+
+ CByteBuffer Comment;
+
+
+ CInArchiveInfo():
+ Base(0),
+ MarkerPos(0),
+ MarkerPos2(0),
+ FinishPos(0),
+ FileEndPos(0),
+ FirstItemRelatOffset(0),
+ MarkerVolIndex(-1),
+ CdWasRead(false),
+ IsSpanMode(false),
+ ThereIsTail(false)
+ // BaseVolIndex(0)
+ {}
+
+ void Clear()
+ {
+ // BaseVolIndex = 0;
+ Base = 0;
+ MarkerPos = 0;
+ MarkerPos2 = 0;
+ FinishPos = 0;
+ FileEndPos = 0;
+ MarkerVolIndex = -1;
+ ThereIsTail = false;
+
+ FirstItemRelatOffset = 0;
+
+ CdWasRead = false;
+ IsSpanMode = false;
+
+ Comment.Free();
+ }
+};
+
+
+struct CCdInfo
+{
+ bool IsFromEcd64;
+
+ UInt16 CommentSize;
+
+ // 64
+ UInt16 VersionMade;
+ UInt16 VersionNeedExtract;
+
+ // old zip
+ UInt32 ThisDisk;
+ UInt32 CdDisk;
+ UInt64 NumEntries_in_ThisDisk;
+ UInt64 NumEntries;
+ UInt64 Size;
+ UInt64 Offset;
+
+ CCdInfo() { memset(this, 0, sizeof(*this)); IsFromEcd64 = false; }
+
+ void ParseEcd32(const Byte *p); // (p) includes signature
+ void ParseEcd64e(const Byte *p); // (p) exclude signature
+
+ bool IsEmptyArc() const
+ {
+ return ThisDisk == 0
+ && CdDisk == 0
+ && NumEntries_in_ThisDisk == 0
+ && NumEntries == 0
+ && Size == 0
+ && Offset == 0 // test it
+ ;
+ }
+};
+
+
+struct CVols
+{
+ struct CSubStreamInfo
+ {
+ CMyComPtr<IInStream> Stream;
+ UInt64 Size;
+
+ HRESULT SeekToStart() const { return InStream_SeekToBegin(Stream); }
+
+ CSubStreamInfo(): Size(0) {}
+ };
+
+ CObjectVector<CSubStreamInfo> Streams;
+
+ int StreamIndex; // -1 for StartStream
+ // -2 for ZipStream at multivol detection code
+ // >=0 volume index in multivol
+
+ bool NeedSeek;
+
+ bool DisableVolsSearch;
+ bool StartIsExe; // is .exe
+ bool StartIsZ; // is .zip or .zNN
+ bool StartIsZip; // is .zip
+ bool IsUpperCase;
+ bool MissingZip;
+
+ bool ecd_wasRead;
+
+ Int32 StartVolIndex; // -1, if unknown vol index
+ // = (NN - 1), if StartStream is .zNN
+ // = 0, if start vol is exe
+
+ Int32 StartParsingVol; // if we need local parsing, we must use that stream
+ unsigned NumVols;
+
+ int EndVolIndex; // index of last volume (ecd volume),
+ // -1, if is not multivol
+
+ UString BaseName; // name of archive including '.'
+ UString MissingName;
+
+ CMyComPtr<IInStream> ZipStream;
+
+ CCdInfo ecd;
+
+ UInt64 TotalBytesSize; // for MultiVol only
+
+ void ClearRefs()
+ {
+ Streams.Clear();
+ ZipStream.Release();
+ TotalBytesSize = 0;
+ }
+
+ void Clear()
+ {
+ StreamIndex = -1;
+ NeedSeek = false;
+
+ DisableVolsSearch = false;
+ StartIsExe = false;
+ StartIsZ = false;
+ StartIsZip = false;
+ IsUpperCase = false;
+
+ StartVolIndex = -1;
+ StartParsingVol = 0;
+ NumVols = 0;
+ EndVolIndex = -1;
+
+ BaseName.Empty();
+ MissingName.Empty();
+
+ MissingZip = false;
+ ecd_wasRead = false;
+
+ ClearRefs();
+ }
+
+ HRESULT ParseArcName(IArchiveOpenVolumeCallback *volCallback);
+
+ HRESULT Read(void *data, UInt32 size, UInt32 *processedSize);
+};
+
+
+Z7_CLASS_IMP_COM_1(
+ CVolStream
+ , ISequentialInStream
+)
+public:
+ CVols *Vols;
+};
+
+
+class CInArchive
+{
+ CMidBuffer Buffer;
+ size_t _bufPos;
+ size_t _bufCached;
+
+ UInt64 _streamPos;
+ UInt64 _cnt;
+
+ // UInt32 _startLocalFromCd_Disk;
+ // UInt64 _startLocalFromCd_Offset;
+
+ size_t GetAvail() const { return _bufCached - _bufPos; }
+
+ void InitBuf() { _bufPos = 0; _bufCached = 0; }
+ void DisableBufMode() { InitBuf(); _inBufMode = false; }
+
+ void SkipLookahed(size_t skip)
+ {
+ _bufPos += skip;
+ _cnt += skip;
+ }
+
+ HRESULT AllocateBuffer(size_t size);
+
+ UInt64 GetVirtStreamPos() { return _streamPos - _bufCached + _bufPos; }
+
+ bool _inBufMode;
+
+ bool IsArcOpen;
+ bool CanStartNewVol;
+
+ UInt32 _signature;
+
+ CMyComPtr<IInStream> StreamRef;
+ IInStream *Stream;
+ IInStream *StartStream;
+ IArchiveOpenCallback *Callback;
+
+ HRESULT Seek_SavePos(UInt64 offset);
+ HRESULT SeekToVol(int volIndex, UInt64 offset);
+
+ HRESULT ReadFromCache(Byte *data, unsigned size, unsigned &processed);
+ HRESULT ReadFromCache_FALSE(Byte *data, unsigned size);
+
+ HRESULT ReadVols2(IArchiveOpenVolumeCallback *volCallback,
+ unsigned start, int lastDisk, int zipDisk, unsigned numMissingVolsMax, unsigned &numMissingVols);
+ HRESULT ReadVols();
+
+ HRESULT FindMarker(const UInt64 *searchLimit);
+ HRESULT IncreaseRealPosition(UInt64 addValue, bool &isFinished);
+
+ HRESULT LookAhead(size_t minRequiredInBuffer);
+ void SafeRead(Byte *data, unsigned size);
+ void ReadBuffer(CByteBuffer &buffer, unsigned size);
+ // Byte ReadByte();
+ // UInt16 ReadUInt16();
+ UInt32 ReadUInt32();
+ UInt64 ReadUInt64();
+
+ void ReadSignature();
+
+ void Skip(size_t num);
+ HRESULT Skip64(UInt64 num, unsigned numFiles);
+
+ bool ReadFileName(unsigned nameSize, AString &dest);
+
+ bool ReadExtra(const CLocalItem &item, unsigned extraSize, CExtraBlock &extra,
+ UInt64 &unpackSize, UInt64 &packSize, CItem *cdItem);
+ bool ReadLocalItem(CItemEx &item);
+ HRESULT FindDescriptor(CItemEx &item, unsigned numFiles);
+ HRESULT ReadCdItem(CItemEx &item);
+ HRESULT TryEcd64(UInt64 offset, CCdInfo &cdInfo);
+ HRESULT FindCd(bool checkOffsetMode);
+ HRESULT TryReadCd(CObjectVector<CItemEx> &items, const CCdInfo &cdInfo, UInt64 cdOffset, UInt64 cdSize);
+ HRESULT ReadCd(CObjectVector<CItemEx> &items, UInt32 &cdDisk, UInt64 &cdOffset, UInt64 &cdSize);
+ HRESULT ReadLocals(CObjectVector<CItemEx> &localItems);
+
+ HRESULT ReadHeaders(CObjectVector<CItemEx> &items);
+
+ HRESULT GetVolStream(unsigned vol, UInt64 pos, CMyComPtr<ISequentialInStream> &stream);
+
+public:
+ CInArchiveInfo ArcInfo;
+
+ bool IsArc;
+ bool IsZip64;
+
+ bool IsApk;
+ bool IsCdUnsorted;
+
+ bool HeadersError;
+ bool HeadersWarning;
+ bool ExtraMinorError;
+ bool UnexpectedEnd;
+ bool LocalsWereRead;
+ bool LocalsCenterMerged;
+ bool NoCentralDir;
+ bool Overflow32bit; // = true, if zip without Zip64 extension support and it has some fields values truncated to 32-bits.
+ bool Cd_NumEntries_Overflow_16bit; // = true, if no Zip64 and 16-bit ecd:NumEntries was overflowed.
+
+ bool MarkerIsFound;
+ bool MarkerIsSafe;
+
+ bool IsMultiVol;
+ bool UseDisk_in_SingleVol;
+ UInt32 EcdVolIndex;
+
+ CVols Vols;
+
+ bool Force_ReadLocals_Mode;
+ bool Disable_VolsRead;
+ bool Disable_FindMarker;
+
+ CInArchive():
+ IsArcOpen(false),
+ Stream(NULL),
+ StartStream(NULL),
+ Callback(NULL),
+ Force_ReadLocals_Mode(false),
+ Disable_VolsRead(false),
+ Disable_FindMarker(false)
+ {}
+
+ UInt64 GetPhySize() const
+ {
+ if (IsMultiVol)
+ return ArcInfo.FinishPos;
+ else
+ return (UInt64)((Int64)ArcInfo.FinishPos - ArcInfo.Base);
+ }
+
+ UInt64 GetOffset() const
+ {
+ if (IsMultiVol)
+ return 0;
+ else
+ return (UInt64)ArcInfo.Base;
+ }
+
+
+ void ClearRefs();
+ void Close();
+ HRESULT Open(IInStream *stream, const UInt64 *searchLimit, IArchiveOpenCallback *callback, CObjectVector<CItemEx> &items);
+
+ bool IsOpen() const { return IsArcOpen; }
+
+ bool AreThereErrors() const
+ {
+ return HeadersError
+ || UnexpectedEnd
+ || !Vols.MissingName.IsEmpty();
+ }
+
+ bool IsLocalOffsetOK(const CItemEx &item) const
+ {
+ if (item.FromLocal)
+ return true;
+ return (Int64)GetOffset() + (Int64)item.LocalHeaderPos >= 0;
+ }
+
+ UInt64 GetEmbeddedStubSize() const
+ {
+ // it's possible that first item in CD doesn refers to first local item
+ // so FirstItemRelatOffset is not first local item
+
+ if (ArcInfo.CdWasRead)
+ return ArcInfo.FirstItemRelatOffset;
+ if (IsMultiVol)
+ return 0;
+ return (UInt64)((Int64)ArcInfo.MarkerPos2 - ArcInfo.Base);
+ }
+
+
+ HRESULT CheckDescriptor(const CItemEx &item);
+ HRESULT Read_LocalItem_After_CdItem(CItemEx &item, bool &isAvail, bool &headersError);
+ HRESULT Read_LocalItem_After_CdItem_Full(CItemEx &item);
+
+ HRESULT GetItemStream(const CItemEx &item, bool seekPackData, CMyComPtr<ISequentialInStream> &stream);
+
+ IInStream *GetBaseStream() { return StreamRef; }
+
+ bool CanUpdate() const
+ {
+ if (AreThereErrors()
+ || IsMultiVol
+ || ArcInfo.Base < 0
+ || (Int64)ArcInfo.MarkerPos2 < ArcInfo.Base
+ || ArcInfo.ThereIsTail
+ || GetEmbeddedStubSize() != 0
+ || IsApk
+ || IsCdUnsorted)
+ return false;
+
+ // 7-zip probably can update archives with embedded stubs.
+ // we just disable that feature for more safety.
+
+ return true;
+ }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Zip/ZipItem.cpp b/CPP/7zip/Archive/Zip/ZipItem.cpp
new file mode 100644
index 0000000..a77643b
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipItem.cpp
@@ -0,0 +1,462 @@
+// Archive/ZipItem.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+#include "../../../../C/7zCrc.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/MyLinux.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/PropVariantUtils.h"
+
+#include "../Common/ItemNameUtils.h"
+
+#include "ZipItem.h"
+
+namespace NArchive {
+namespace NZip {
+
+using namespace NFileHeader;
+
+
+/*
+const char *k_SpecName_NTFS_STREAM = "@@NTFS@STREAM@";
+const char *k_SpecName_MAC_RESOURCE_FORK = "@@MAC@RESOURCE-FORK@";
+*/
+
+static const CUInt32PCharPair g_ExtraTypes[] =
+{
+ { NExtraID::kZip64, "Zip64" },
+ { NExtraID::kNTFS, "NTFS" },
+ { NExtraID::kUnix0, "UNIX" },
+ { NExtraID::kStrongEncrypt, "StrongCrypto" },
+ { NExtraID::kUnixTime, "UT" },
+ { NExtraID::kUnix1, "UX" },
+ { NExtraID::kUnix2, "Ux" },
+ { NExtraID::kUnixN, "ux" },
+ { NExtraID::kIzUnicodeComment, "uc" },
+ { NExtraID::kIzUnicodeName, "up" },
+ { NExtraID::kIzNtSecurityDescriptor, "SD" },
+ { NExtraID::kWzAES, "WzAES" },
+ { NExtraID::kApkAlign, "ApkAlign" }
+};
+
+void CExtraSubBlock::PrintInfo(AString &s) const
+{
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ExtraTypes); i++)
+ {
+ const CUInt32PCharPair &pair = g_ExtraTypes[i];
+ if (pair.Value == ID)
+ {
+ s += pair.Name;
+ if (ID == NExtraID::kUnixTime)
+ {
+ if (Data.Size() >= 1)
+ {
+ s += ':';
+ const Byte flags = Data[0];
+ if (flags & 1) s += 'M';
+ if (flags & 2) s += 'A';
+ if (flags & 4) s += 'C';
+ const UInt32 size = (UInt32)(Data.Size()) - 1;
+ if (size % 4 == 0)
+ {
+ s += ':';
+ s.Add_UInt32(size / 4);
+ }
+ }
+ }
+ /*
+ if (ID == NExtraID::kApkAlign && Data.Size() >= 2)
+ {
+ char sz[32];
+ sz[0] = ':';
+ ConvertUInt32ToHex(GetUi16(Data), sz + 1);
+ s += sz;
+ for (unsigned j = 2; j < Data.Size(); j++)
+ {
+ char sz[32];
+ sz[0] = '-';
+ ConvertUInt32ToHex(Data[j], sz + 1);
+ s += sz;
+ }
+ }
+ */
+ return;
+ }
+ }
+ {
+ char sz[32];
+ sz[0] = '0';
+ sz[1] = 'x';
+ ConvertUInt32ToHex(ID, sz + 2);
+ s += sz;
+ }
+}
+
+
+void CExtraBlock::PrintInfo(AString &s) const
+{
+ if (Error)
+ s.Add_OptSpaced("Extra_ERROR");
+
+ if (MinorError)
+ s.Add_OptSpaced("Minor_Extra_ERROR");
+
+ if (IsZip64 || IsZip64_Error)
+ {
+ s.Add_OptSpaced("Zip64");
+ if (IsZip64_Error)
+ s += "_ERROR";
+ }
+
+ FOR_VECTOR (i, SubBlocks)
+ {
+ s.Add_Space_if_NotEmpty();
+ SubBlocks[i].PrintInfo(s);
+ }
+}
+
+
+bool CExtraSubBlock::ExtractNtfsTime(unsigned index, FILETIME &ft) const
+{
+ ft.dwHighDateTime = ft.dwLowDateTime = 0;
+ UInt32 size = (UInt32)Data.Size();
+ if (ID != NExtraID::kNTFS || size < 32)
+ return false;
+ const Byte *p = (const Byte *)Data;
+ p += 4; // for reserved
+ size -= 4;
+ while (size > 4)
+ {
+ UInt16 tag = GetUi16(p);
+ unsigned attrSize = GetUi16(p + 2);
+ p += 4;
+ size -= 4;
+ if (attrSize > size)
+ attrSize = size;
+
+ if (tag == NNtfsExtra::kTagTime && attrSize >= 24)
+ {
+ p += 8 * index;
+ ft.dwLowDateTime = GetUi32(p);
+ ft.dwHighDateTime = GetUi32(p + 4);
+ return true;
+ }
+ p += attrSize;
+ size -= attrSize;
+ }
+ return false;
+}
+
+bool CExtraSubBlock::Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const
+{
+ /* Info-Zip :
+ The central-header extra field contains the modification
+ time only, or no timestamp at all.
+ Size of Data is used to flag its presence or absence
+ If "Flags" indicates that Modtime is present in the local header
+ field, it MUST be present in the central header field, too
+ */
+
+ res = 0;
+ UInt32 size = (UInt32)Data.Size();
+ if (ID != NExtraID::kUnixTime || size < 5)
+ return false;
+ const Byte *p = (const Byte *)Data;
+ const Byte flags = *p++;
+ size--;
+ if (isCentral)
+ {
+ if (index != NUnixTime::kMTime ||
+ (flags & (1 << NUnixTime::kMTime)) == 0 ||
+ size < 4)
+ return false;
+ res = GetUi32(p);
+ return true;
+ }
+ for (unsigned i = 0; i < 3; i++)
+ if ((flags & (1 << i)) != 0)
+ {
+ if (size < 4)
+ return false;
+ if (index == i)
+ {
+ res = GetUi32(p);
+ return true;
+ }
+ p += 4;
+ size -= 4;
+ }
+ return false;
+}
+
+
+// Info-ZIP's abandoned "Unix1 timestamps & owner ID info"
+
+bool CExtraSubBlock::Extract_Unix01_Time(unsigned index, UInt32 &res) const
+{
+ res = 0;
+ const unsigned offset = index * 4;
+ if (Data.Size() < offset + 4)
+ return false;
+ if (ID != NExtraID::kUnix0 &&
+ ID != NExtraID::kUnix1)
+ return false;
+ const Byte *p = (const Byte *)Data + offset;
+ res = GetUi32(p);
+ return true;
+}
+
+/*
+// PKWARE's Unix "extra" is similar to Info-ZIP's abandoned "Unix1 timestamps"
+bool CExtraSubBlock::Extract_Unix_Time(unsigned index, UInt32 &res) const
+{
+ res = 0;
+ const unsigned offset = index * 4;
+ if (ID != NExtraID::kUnix0 || Data.Size() < offset)
+ return false;
+ const Byte *p = (const Byte *)Data + offset;
+ res = GetUi32(p);
+ return true;
+}
+*/
+
+bool CExtraBlock::GetNtfsTime(unsigned index, FILETIME &ft) const
+{
+ FOR_VECTOR (i, SubBlocks)
+ {
+ const CExtraSubBlock &sb = SubBlocks[i];
+ if (sb.ID == NFileHeader::NExtraID::kNTFS)
+ return sb.ExtractNtfsTime(index, ft);
+ }
+ return false;
+}
+
+bool CExtraBlock::GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const
+{
+ {
+ FOR_VECTOR (i, SubBlocks)
+ {
+ const CExtraSubBlock &sb = SubBlocks[i];
+ if (sb.ID == NFileHeader::NExtraID::kUnixTime)
+ return sb.Extract_UnixTime(isCentral, index, res);
+ }
+ }
+
+ switch (index)
+ {
+ case NUnixTime::kMTime: index = NUnixExtra::kMTime; break;
+ case NUnixTime::kATime: index = NUnixExtra::kATime; break;
+ default: return false;
+ }
+
+ {
+ FOR_VECTOR (i, SubBlocks)
+ {
+ const CExtraSubBlock &sb = SubBlocks[i];
+ if (sb.ID == NFileHeader::NExtraID::kUnix0 ||
+ sb.ID == NFileHeader::NExtraID::kUnix1)
+ return sb.Extract_Unix01_Time(index, res);
+ }
+ }
+ return false;
+}
+
+
+bool CLocalItem::IsDir() const
+{
+ return NItemName::HasTailSlash(Name, GetCodePage());
+}
+
+bool CItem::IsDir() const
+{
+ // FIXME: we can check InfoZip UTF-8 name at first.
+ if (NItemName::HasTailSlash(Name, GetCodePage()))
+ return true;
+
+ Byte hostOS = GetHostOS();
+
+ if (Size == 0 && PackSize == 0 && !Name.IsEmpty() && Name.Back() == '\\')
+ {
+ // do we need to use CharPrevExA?
+ // .NET Framework 4.5 : System.IO.Compression::CreateFromDirectory() probably writes backslashes to headers?
+ // so we support that case
+ switch (hostOS)
+ {
+ case NHostOS::kFAT:
+ case NHostOS::kNTFS:
+ case NHostOS::kHPFS:
+ case NHostOS::kVFAT:
+ return true;
+ }
+ }
+
+ if (!FromCentral)
+ return false;
+
+ UInt16 highAttrib = (UInt16)((ExternalAttrib >> 16 ) & 0xFFFF);
+
+ switch (hostOS)
+ {
+ case NHostOS::kAMIGA:
+ switch (highAttrib & NAmigaAttrib::kIFMT)
+ {
+ case NAmigaAttrib::kIFDIR: return true;
+ case NAmigaAttrib::kIFREG: return false;
+ default: return false; // change it throw kUnknownAttributes;
+ }
+ case NHostOS::kFAT:
+ case NHostOS::kNTFS:
+ case NHostOS::kHPFS:
+ case NHostOS::kVFAT:
+ return ((ExternalAttrib & FILE_ATTRIBUTE_DIRECTORY) != 0);
+ case NHostOS::kAtari:
+ case NHostOS::kMac:
+ case NHostOS::kVMS:
+ case NHostOS::kVM_CMS:
+ case NHostOS::kAcorn:
+ case NHostOS::kMVS:
+ return false; // change it throw kUnknownAttributes;
+ case NHostOS::kUnix:
+ return MY_LIN_S_ISDIR(highAttrib);
+ default:
+ return false;
+ }
+}
+
+UInt32 CItem::GetWinAttrib() const
+{
+ UInt32 winAttrib = 0;
+ switch (GetHostOS())
+ {
+ case NHostOS::kFAT:
+ case NHostOS::kNTFS:
+ if (FromCentral)
+ winAttrib = ExternalAttrib;
+ break;
+ case NHostOS::kUnix:
+ // do we need to clear 16 low bits in this case?
+ if (FromCentral)
+ {
+ /*
+ Some programs write posix attributes in high 16 bits of ExternalAttrib
+ Also some programs can write additional marker flag:
+ 0x8000 - p7zip
+ 0x4000 - Zip in MacOS
+ no marker - Info-Zip
+
+ Client code has two options to detect posix field:
+ 1) check 0x8000 marker. In that case we must add 0x8000 marker here.
+ 2) check that high 4 bits (file type bits in posix field) of attributes are not zero.
+ */
+
+ winAttrib = ExternalAttrib & 0xFFFF0000;
+
+ // #ifndef _WIN32
+ winAttrib |= 0x8000; // add posix mode marker
+ // #endif
+ }
+ break;
+ }
+ if (IsDir()) // test it;
+ winAttrib |= FILE_ATTRIBUTE_DIRECTORY;
+ return winAttrib;
+}
+
+bool CItem::GetPosixAttrib(UInt32 &attrib) const
+{
+ // some archivers can store PosixAttrib in high 16 bits even with HostOS=FAT.
+ if (FromCentral && GetHostOS() == NHostOS::kUnix)
+ {
+ attrib = ExternalAttrib >> 16;
+ return (attrib != 0);
+ }
+ attrib = 0;
+ if (IsDir())
+ attrib = MY_LIN_S_IFDIR;
+ return false;
+}
+
+
+bool CExtraSubBlock::CheckIzUnicode(const AString &s) const
+{
+ size_t size = Data.Size();
+ if (size < 1 + 4)
+ return false;
+ const Byte *p = (const Byte *)Data;
+ if (p[0] > 1)
+ return false;
+ if (CrcCalc(s, s.Len()) != GetUi32(p + 1))
+ return false;
+ size -= 5;
+ p += 5;
+ for (size_t i = 0; i < size; i++)
+ if (p[i] == 0)
+ return false;
+ return Check_UTF8_Buf((const char *)(const void *)p, size, false);
+}
+
+
+void CItem::GetUnicodeString(UString &res, const AString &s, bool isComment, bool useSpecifiedCodePage, UINT codePage) const
+{
+ bool isUtf8 = IsUtf8();
+ // bool ignore_Utf8_Errors = true;
+
+ if (!isUtf8)
+ {
+ {
+ const unsigned id = isComment ?
+ NFileHeader::NExtraID::kIzUnicodeComment:
+ NFileHeader::NExtraID::kIzUnicodeName;
+ const CObjectVector<CExtraSubBlock> &subBlocks = GetMainExtra().SubBlocks;
+
+ FOR_VECTOR (i, subBlocks)
+ {
+ const CExtraSubBlock &sb = subBlocks[i];
+ if (sb.ID == id)
+ {
+ if (sb.CheckIzUnicode(s))
+ {
+ // const unsigned kIzUnicodeHeaderSize = 5;
+ if (Convert_UTF8_Buf_To_Unicode(
+ (const char *)(const void *)(const Byte *)sb.Data + 5,
+ sb.Data.Size() - 5, res))
+ return;
+ }
+ break;
+ }
+ }
+ }
+
+ if (useSpecifiedCodePage)
+ isUtf8 = (codePage == CP_UTF8);
+ #ifdef _WIN32
+ else if (GetHostOS() == NFileHeader::NHostOS::kUnix)
+ {
+ /* Some ZIP archives in Unix use UTF-8 encoding without Utf8 flag in header.
+ We try to get name as UTF-8.
+ Do we need to do it in POSIX version also? */
+ isUtf8 = true;
+
+ /* 21.02: we want to ignore UTF-8 errors to support file paths that are mixed
+ of UTF-8 and non-UTF-8 characters. */
+ // ignore_Utf8_Errors = false;
+ // ignore_Utf8_Errors = true;
+ }
+ #endif
+ }
+
+
+ if (isUtf8)
+ {
+ ConvertUTF8ToUnicode(s, res);
+ return;
+ }
+
+ MultiByteToUnicodeString2(res, s, useSpecifiedCodePage ? codePage : GetCodePage());
+}
+
+}}
diff --git a/CPP/7zip/Archive/Zip/ZipItem.h b/CPP/7zip/Archive/Zip/ZipItem.h
new file mode 100644
index 0000000..4a25de3
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipItem.h
@@ -0,0 +1,356 @@
+// Archive/ZipItem.h
+
+#ifndef ZIP7_INC_ARCHIVE_ZIP_ITEM_H
+#define ZIP7_INC_ARCHIVE_ZIP_ITEM_H
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/MyBuffer.h"
+#include "../../../Common/MyString.h"
+#include "../../../Common/UTFConvert.h"
+
+#include "ZipHeader.h"
+
+namespace NArchive {
+namespace NZip {
+
+/*
+extern const char *k_SpecName_NTFS_STREAM;
+extern const char *k_SpecName_MAC_RESOURCE_FORK;
+*/
+
+struct CVersion
+{
+ Byte Version;
+ Byte HostOS;
+};
+
+struct CExtraSubBlock
+{
+ UInt32 ID;
+ CByteBuffer Data;
+
+ bool ExtractNtfsTime(unsigned index, FILETIME &ft) const;
+ bool Extract_UnixTime(bool isCentral, unsigned index, UInt32 &res) const;
+ bool Extract_Unix01_Time(unsigned index, UInt32 &res) const;
+ // bool Extract_Unix_Time(unsigned index, UInt32 &res) const;
+
+ bool CheckIzUnicode(const AString &s) const;
+
+ void PrintInfo(AString &s) const;
+};
+
+const unsigned k_WzAesExtra_Size = 7;
+
+struct CWzAesExtra
+{
+ UInt16 VendorVersion; // 1: AE-1, 2: AE-2,
+ // UInt16 VendorId; // 'A' 'E'
+ Byte Strength; // 1: 128-bit, 2: 192-bit, 3: 256-bit
+ UInt16 Method;
+
+ CWzAesExtra(): VendorVersion(2), Strength(3), Method(0) {}
+
+ bool NeedCrc() const { return (VendorVersion == 1); }
+
+ bool ParseFromSubBlock(const CExtraSubBlock &sb)
+ {
+ if (sb.ID != NFileHeader::NExtraID::kWzAES)
+ return false;
+ if (sb.Data.Size() < k_WzAesExtra_Size)
+ return false;
+ const Byte *p = (const Byte *)sb.Data;
+ VendorVersion = GetUi16(p);
+ if (p[2] != 'A' || p[3] != 'E')
+ return false;
+ Strength = p[4];
+ // 9.31: The BUG was fixed:
+ Method = GetUi16(p + 5);
+ return true;
+ }
+
+ void SetSubBlock(CExtraSubBlock &sb) const
+ {
+ sb.Data.Alloc(k_WzAesExtra_Size);
+ sb.ID = NFileHeader::NExtraID::kWzAES;
+ Byte *p = (Byte *)sb.Data;
+ p[0] = (Byte)VendorVersion;
+ p[1] = (Byte)(VendorVersion >> 8);
+ p[2] = 'A';
+ p[3] = 'E';
+ p[4] = Strength;
+ p[5] = (Byte)Method;
+ p[6] = (Byte)(Method >> 8);
+ }
+};
+
+namespace NStrongCrypto_AlgId
+{
+ const UInt16 kDES = 0x6601;
+ const UInt16 kRC2old = 0x6602;
+ const UInt16 k3DES168 = 0x6603;
+ const UInt16 k3DES112 = 0x6609;
+ const UInt16 kAES128 = 0x660E;
+ const UInt16 kAES192 = 0x660F;
+ const UInt16 kAES256 = 0x6610;
+ const UInt16 kRC2 = 0x6702;
+ const UInt16 kBlowfish = 0x6720;
+ const UInt16 kTwofish = 0x6721;
+ const UInt16 kRC4 = 0x6801;
+}
+
+struct CStrongCryptoExtra
+{
+ UInt16 Format;
+ UInt16 AlgId;
+ UInt16 BitLen;
+ UInt16 Flags;
+
+ bool ParseFromSubBlock(const CExtraSubBlock &sb)
+ {
+ if (sb.ID != NFileHeader::NExtraID::kStrongEncrypt)
+ return false;
+ const Byte *p = (const Byte *)sb.Data;
+ if (sb.Data.Size() < 8)
+ return false;
+ Format = GetUi16(p + 0);
+ AlgId = GetUi16(p + 2);
+ BitLen = GetUi16(p + 4);
+ Flags = GetUi16(p + 6);
+ return (Format == 2);
+ }
+
+ bool CertificateIsUsed() const { return (Flags > 0x0001); }
+};
+
+
+struct CExtraBlock
+{
+ CObjectVector<CExtraSubBlock> SubBlocks;
+ bool Error;
+ bool MinorError;
+ bool IsZip64;
+ bool IsZip64_Error;
+
+ CExtraBlock(): Error(false), MinorError(false), IsZip64(false), IsZip64_Error(false) {}
+
+ void Clear()
+ {
+ SubBlocks.Clear();
+ IsZip64 = false;
+ }
+
+ size_t GetSize() const
+ {
+ size_t res = 0;
+ FOR_VECTOR (i, SubBlocks)
+ res += SubBlocks[i].Data.Size() + 2 + 2;
+ return res;
+ }
+
+ bool GetWzAes(CWzAesExtra &e) const
+ {
+ FOR_VECTOR (i, SubBlocks)
+ if (e.ParseFromSubBlock(SubBlocks[i]))
+ return true;
+ return false;
+ }
+
+ bool HasWzAes() const
+ {
+ CWzAesExtra e;
+ return GetWzAes(e);
+ }
+
+ bool GetStrongCrypto(CStrongCryptoExtra &e) const
+ {
+ FOR_VECTOR (i, SubBlocks)
+ if (e.ParseFromSubBlock(SubBlocks[i]))
+ return true;
+ return false;
+ }
+
+ /*
+ bool HasStrongCrypto() const
+ {
+ CStrongCryptoExtra e;
+ return GetStrongCrypto(e);
+ }
+ */
+
+ bool GetNtfsTime(unsigned index, FILETIME &ft) const;
+ bool GetUnixTime(bool isCentral, unsigned index, UInt32 &res) const;
+
+ void PrintInfo(AString &s) const;
+
+ void RemoveUnknownSubBlocks()
+ {
+ for (unsigned i = SubBlocks.Size(); i != 0;)
+ {
+ i--;
+ switch (SubBlocks[i].ID)
+ {
+ case NFileHeader::NExtraID::kStrongEncrypt:
+ case NFileHeader::NExtraID::kWzAES:
+ break;
+ default:
+ SubBlocks.Delete(i);
+ }
+ }
+ }
+};
+
+
+class CLocalItem
+{
+public:
+ UInt16 Flags;
+ UInt16 Method;
+
+ /*
+ Zip specification doesn't mention that ExtractVersion field uses HostOS subfield.
+ 18.06: 7-Zip now doesn't use ExtractVersion::HostOS to detect codePage
+ */
+
+ CVersion ExtractVersion;
+
+ UInt64 Size;
+ UInt64 PackSize;
+ UInt32 Time;
+ UInt32 Crc;
+
+ UInt32 Disk;
+
+ AString Name;
+
+ CExtraBlock LocalExtra;
+
+ unsigned GetDescriptorSize() const { return LocalExtra.IsZip64 ? kDataDescriptorSize64 : kDataDescriptorSize32; }
+
+ UInt64 GetPackSizeWithDescriptor() const
+ { return PackSize + (HasDescriptor() ? GetDescriptorSize() : 0); }
+
+ bool IsUtf8() const { return (Flags & NFileHeader::NFlags::kUtf8) != 0; }
+ bool IsEncrypted() const { return (Flags & NFileHeader::NFlags::kEncrypted) != 0; }
+ bool IsStrongEncrypted() const { return IsEncrypted() && (Flags & NFileHeader::NFlags::kStrongEncrypted) != 0; }
+ bool IsAesEncrypted() const { return IsEncrypted() && (IsStrongEncrypted() || Method == NFileHeader::NCompressionMethod::kWzAES); }
+ bool IsLzmaEOS() const { return (Flags & NFileHeader::NFlags::kLzmaEOS) != 0; }
+ bool HasDescriptor() const { return (Flags & NFileHeader::NFlags::kDescriptorUsedMask) != 0; }
+ // bool IsAltStream() const { return (Flags & NFileHeader::NFlags::kAltStream) != 0; }
+
+ unsigned GetDeflateLevel() const { return (Flags >> 1) & 3; }
+
+ bool IsDir() const;
+
+ /*
+ void GetUnicodeString(const AString &s, UString &res) const
+ {
+ bool isUtf8 = IsUtf8();
+ if (isUtf8)
+ if (ConvertUTF8ToUnicode(s, res))
+ return;
+ MultiByteToUnicodeString2(res, s, GetCodePage());
+ }
+ */
+
+private:
+
+ void SetFlag(unsigned bitMask, bool enable)
+ {
+ if (enable)
+ Flags = (UInt16)(Flags | bitMask);
+ else
+ Flags = (UInt16)(Flags & ~bitMask);
+ }
+
+public:
+
+ void ClearFlags() { Flags = 0; }
+ void SetEncrypted(bool encrypted) { SetFlag(NFileHeader::NFlags::kEncrypted, encrypted); }
+ void SetUtf8(bool isUtf8) { SetFlag(NFileHeader::NFlags::kUtf8, isUtf8); }
+ // void SetFlag_AltStream(bool isAltStream) { SetFlag(NFileHeader::NFlags::kAltStream, isAltStream); }
+ void SetDescriptorMode(bool useDescriptor) { SetFlag(NFileHeader::NFlags::kDescriptorUsedMask, useDescriptor); }
+
+ UINT GetCodePage() const
+ {
+ if (IsUtf8())
+ return CP_UTF8;
+ return CP_OEMCP;
+ }
+};
+
+
+class CItem: public CLocalItem
+{
+public:
+ CVersion MadeByVersion;
+ UInt16 InternalAttrib;
+ UInt32 ExternalAttrib;
+
+ UInt64 LocalHeaderPos;
+
+ CExtraBlock CentralExtra;
+ CByteBuffer Comment;
+
+ bool FromLocal;
+ bool FromCentral;
+
+ // CItem can be used as CLocalItem. So we must clear unused fields
+ CItem():
+ InternalAttrib(0),
+ ExternalAttrib(0),
+ FromLocal(false),
+ FromCentral(false)
+ {
+ MadeByVersion.Version = 0;
+ MadeByVersion.HostOS = 0;
+ }
+
+ const CExtraBlock &GetMainExtra() const { return *(FromCentral ? &CentralExtra : &LocalExtra); }
+
+ bool IsDir() const;
+ UInt32 GetWinAttrib() const;
+ bool GetPosixAttrib(UInt32 &attrib) const;
+
+ // 18.06: 0 instead of ExtractVersion.HostOS for local item
+ Byte GetHostOS() const { return FromCentral ? MadeByVersion.HostOS : (Byte)0; }
+
+ void GetUnicodeString(UString &res, const AString &s, bool isComment, bool useSpecifiedCodePage, UINT codePage) const;
+
+ bool IsThereCrc() const
+ {
+ if (Method == NFileHeader::NCompressionMethod::kWzAES)
+ {
+ CWzAesExtra aesField;
+ if (GetMainExtra().GetWzAes(aesField))
+ return aesField.NeedCrc();
+ }
+ return (Crc != 0 || !IsDir());
+ }
+
+ bool Is_MadeBy_Unix() const
+ {
+ if (!FromCentral)
+ return false;
+ return (MadeByVersion.HostOS == NFileHeader::NHostOS::kUnix);
+ }
+
+ UINT GetCodePage() const
+ {
+ // 18.06: now we use HostOS only from Central::MadeByVersion
+ if (IsUtf8())
+ return CP_UTF8;
+ if (!FromCentral)
+ return CP_OEMCP;
+ Byte hostOS = MadeByVersion.HostOS;
+ return (UINT)((
+ hostOS == NFileHeader::NHostOS::kFAT
+ || hostOS == NFileHeader::NHostOS::kNTFS
+ || hostOS == NFileHeader::NHostOS::kUnix // do we need it?
+ ) ? CP_OEMCP : CP_ACP);
+ }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Zip/ZipOut.cpp b/CPP/7zip/Archive/Zip/ZipOut.cpp
new file mode 100644
index 0000000..63f1a71
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipOut.cpp
@@ -0,0 +1,420 @@
+// ZipOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/7zCrc.h"
+
+#include "../../../Windows/TimeUtils.h"
+#include "../../Common/OffsetStream.h"
+
+#include "ZipOut.h"
+
+namespace NArchive {
+namespace NZip {
+
+HRESULT COutArchive::ClearRestriction()
+{
+ if (SetRestriction)
+ return SetRestriction->SetRestriction(0, 0);
+ return S_OK;
+}
+
+HRESULT COutArchive::SetRestrictionFromCurrent()
+{
+ if (SetRestriction)
+ return SetRestriction->SetRestriction(m_Base + m_CurPos, (UInt64)(Int64)-1);
+ return S_OK;
+}
+
+HRESULT COutArchive::Create(IOutStream *outStream)
+{
+ m_CurPos = 0;
+ if (!m_OutBuffer.Create(1 << 16))
+ return E_OUTOFMEMORY;
+ m_Stream = outStream;
+ m_OutBuffer.SetStream(outStream);
+ m_OutBuffer.Init();
+
+ return m_Stream->Seek(0, STREAM_SEEK_CUR, &m_Base);
+}
+
+void COutArchive::SeekToCurPos()
+{
+ HRESULT res = m_Stream->Seek((Int64)(m_Base + m_CurPos), STREAM_SEEK_SET, NULL);
+ if (res != S_OK)
+ throw CSystemException(res);
+}
+
+#define DOES_NEED_ZIP64(v) (v >= (UInt32)0xFFFFFFFF)
+// #define DOES_NEED_ZIP64(v) (v >= 0)
+
+
+void COutArchive::WriteBytes(const void *data, size_t size)
+{
+ m_OutBuffer.WriteBytes(data, size);
+ m_CurPos += size;
+}
+
+void COutArchive::Write8(Byte b)
+{
+ m_OutBuffer.WriteByte(b);
+ m_CurPos++;
+}
+
+void COutArchive::Write16(UInt16 val)
+{
+ Write8((Byte)val);
+ Write8((Byte)(val >> 8));
+}
+
+void COutArchive::Write32(UInt32 val)
+{
+ for (int i = 0; i < 4; i++)
+ {
+ Write8((Byte)val);
+ val >>= 8;
+ }
+}
+
+void COutArchive::Write64(UInt64 val)
+{
+ for (int i = 0; i < 8; i++)
+ {
+ Write8((Byte)val);
+ val >>= 8;
+ }
+}
+
+void COutArchive::WriteExtra(const CExtraBlock &extra)
+{
+ FOR_VECTOR (i, extra.SubBlocks)
+ {
+ const CExtraSubBlock &subBlock = extra.SubBlocks[i];
+ Write16((UInt16)subBlock.ID);
+ Write16((UInt16)subBlock.Data.Size());
+ WriteBytes(subBlock.Data, (UInt16)subBlock.Data.Size());
+ }
+}
+
+void COutArchive::WriteCommonItemInfo(const CLocalItem &item, bool isZip64)
+{
+ {
+ Byte ver = item.ExtractVersion.Version;
+ if (isZip64 && ver < NFileHeader::NCompressionMethod::kExtractVersion_Zip64)
+ ver = NFileHeader::NCompressionMethod::kExtractVersion_Zip64;
+ Write8(ver);
+ }
+ Write8(item.ExtractVersion.HostOS);
+ Write16(item.Flags);
+ Write16(item.Method);
+ Write32(item.Time);
+}
+
+
+#define WRITE_32_VAL_SPEC(_v_, _isZip64_) Write32((_isZip64_) ? 0xFFFFFFFF : (UInt32)(_v_));
+
+
+void COutArchive::WriteUtfName(const CItemOut &item)
+{
+ if (item.Name_Utf.Size() == 0)
+ return;
+ Write16(NFileHeader::NExtraID::kIzUnicodeName);
+ Write16((UInt16)(5 + item.Name_Utf.Size()));
+ Write8(1); // (1 = version) of that extra field
+ Write32(CrcCalc(item.Name.Ptr(), item.Name.Len()));
+ WriteBytes(item.Name_Utf, (UInt16)item.Name_Utf.Size());
+}
+
+
+static const unsigned k_Ntfs_ExtraSize = 4 + 2 + 2 + (3 * 8);
+static const unsigned k_UnixTime_ExtraSize = 1 + (1 * 4);
+
+void COutArchive::WriteTimeExtra(const CItemOut &item, bool writeNtfs)
+{
+ if (writeNtfs)
+ {
+ // windows explorer ignores that extra
+ Write16(NFileHeader::NExtraID::kNTFS);
+ Write16(k_Ntfs_ExtraSize);
+ Write32(0); // reserved
+ Write16(NFileHeader::NNtfsExtra::kTagTime);
+ Write16(8 * 3);
+ WriteNtfsTime(item.Ntfs_MTime);
+ WriteNtfsTime(item.Ntfs_ATime);
+ WriteNtfsTime(item.Ntfs_CTime);
+ }
+
+ if (item.Write_UnixTime)
+ {
+ // windows explorer ignores that extra
+ // by specification : should we write to local header also?
+ Write16(NFileHeader::NExtraID::kUnixTime);
+ Write16(k_UnixTime_ExtraSize);
+ const Byte flags = (Byte)((unsigned)1 << NFileHeader::NUnixTime::kMTime);
+ Write8(flags);
+ UInt32 unixTime;
+ NWindows::NTime::FileTime_To_UnixTime(item.Ntfs_MTime, unixTime);
+ Write32(unixTime);
+ }
+}
+
+
+void COutArchive::WriteLocalHeader(CItemOut &item, bool needCheck)
+{
+ m_LocalHeaderPos = m_CurPos;
+ item.LocalHeaderPos = m_CurPos;
+
+ bool isZip64 =
+ DOES_NEED_ZIP64(item.PackSize) ||
+ DOES_NEED_ZIP64(item.Size);
+
+ if (needCheck && m_IsZip64)
+ isZip64 = true;
+
+ // Why don't we write NTFS timestamps to local header?
+ // Probably we want to reduce size of archive?
+ const bool writeNtfs = false; // do not write NTFS timestamp to local header
+ // const bool writeNtfs = item.Write_NtfsTime; // write NTFS time to local header
+ const UInt32 localExtraSize = (UInt32)(
+ (isZip64 ? (4 + 8 + 8): 0)
+ + (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0)
+ + (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0)
+ + item.Get_UtfName_ExtraSize()
+ + item.LocalExtra.GetSize());
+ if ((UInt16)localExtraSize != localExtraSize)
+ throw CSystemException(E_FAIL);
+ if (needCheck && m_ExtraSize != localExtraSize)
+ throw CSystemException(E_FAIL);
+
+ m_IsZip64 = isZip64;
+ m_ExtraSize = localExtraSize;
+
+ item.LocalExtra.IsZip64 = isZip64;
+
+ Write32(NSignature::kLocalFileHeader);
+
+ WriteCommonItemInfo(item, isZip64);
+
+ Write32(item.HasDescriptor() ? 0 : item.Crc);
+
+ UInt64 packSize = item.PackSize;
+ UInt64 size = item.Size;
+
+ if (item.HasDescriptor())
+ {
+ packSize = 0;
+ size = 0;
+ }
+
+ WRITE_32_VAL_SPEC(packSize, isZip64)
+ WRITE_32_VAL_SPEC(size, isZip64)
+
+ Write16((UInt16)item.Name.Len());
+
+ Write16((UInt16)localExtraSize);
+
+ WriteBytes((const char *)item.Name, (UInt16)item.Name.Len());
+
+ if (isZip64)
+ {
+ Write16(NFileHeader::NExtraID::kZip64);
+ Write16(8 + 8);
+ Write64(size);
+ Write64(packSize);
+ }
+
+ WriteTimeExtra(item, writeNtfs);
+
+ WriteUtfName(item);
+
+ WriteExtra(item.LocalExtra);
+
+ const UInt32 localFileHeaderSize = (UInt32)(m_CurPos - m_LocalHeaderPos);
+ if (needCheck && m_LocalFileHeaderSize != localFileHeaderSize)
+ throw CSystemException(E_FAIL);
+ m_LocalFileHeaderSize = localFileHeaderSize;
+
+ m_OutBuffer.FlushWithCheck();
+}
+
+
+void COutArchive::WriteLocalHeader_Replace(CItemOut &item)
+{
+ m_CurPos = m_LocalHeaderPos + m_LocalFileHeaderSize + item.PackSize;
+
+ if (item.HasDescriptor())
+ {
+ WriteDescriptor(item);
+ m_OutBuffer.FlushWithCheck();
+ return;
+ // we don't replace local header, if we write Descriptor.
+ // so local header with Descriptor flag must be written to local header before.
+ }
+
+ const UInt64 nextPos = m_CurPos;
+ m_CurPos = m_LocalHeaderPos;
+ SeekToCurPos();
+ WriteLocalHeader(item, true);
+ m_CurPos = nextPos;
+ SeekToCurPos();
+}
+
+
+void COutArchive::WriteDescriptor(const CItemOut &item)
+{
+ Byte buf[kDataDescriptorSize64];
+ SetUi32(buf, NSignature::kDataDescriptor)
+ SetUi32(buf + 4, item.Crc)
+ unsigned descriptorSize;
+ if (m_IsZip64)
+ {
+ SetUi64(buf + 8, item.PackSize)
+ SetUi64(buf + 16, item.Size)
+ descriptorSize = kDataDescriptorSize64;
+ }
+ else
+ {
+ SetUi32(buf + 8, (UInt32)item.PackSize)
+ SetUi32(buf + 12, (UInt32)item.Size)
+ descriptorSize = kDataDescriptorSize32;
+ }
+ WriteBytes(buf, descriptorSize);
+}
+
+
+
+void COutArchive::WriteCentralHeader(const CItemOut &item)
+{
+ const bool isUnPack64 = DOES_NEED_ZIP64(item.Size);
+ const bool isPack64 = DOES_NEED_ZIP64(item.PackSize);
+ const bool isPosition64 = DOES_NEED_ZIP64(item.LocalHeaderPos);
+ const bool isZip64 = isPack64 || isUnPack64 || isPosition64;
+
+ Write32(NSignature::kCentralFileHeader);
+ Write8(item.MadeByVersion.Version);
+ Write8(item.MadeByVersion.HostOS);
+
+ WriteCommonItemInfo(item, isZip64);
+ Write32(item.Crc);
+
+ WRITE_32_VAL_SPEC(item.PackSize, isPack64)
+ WRITE_32_VAL_SPEC(item.Size, isUnPack64)
+
+ Write16((UInt16)item.Name.Len());
+
+ const UInt16 zip64ExtraSize = (UInt16)((isUnPack64 ? 8: 0) + (isPack64 ? 8: 0) + (isPosition64 ? 8: 0));
+ const bool writeNtfs = item.Write_NtfsTime;
+ const size_t centralExtraSize =
+ (isZip64 ? 4 + zip64ExtraSize : 0)
+ + (writeNtfs ? 4 + k_Ntfs_ExtraSize : 0)
+ + (item.Write_UnixTime ? 4 + k_UnixTime_ExtraSize : 0)
+ + item.Get_UtfName_ExtraSize()
+ + item.CentralExtra.GetSize();
+
+ const UInt16 centralExtraSize16 = (UInt16)centralExtraSize;
+ if (centralExtraSize16 != centralExtraSize)
+ throw CSystemException(E_FAIL);
+
+ Write16(centralExtraSize16);
+
+ const UInt16 commentSize = (UInt16)item.Comment.Size();
+
+ Write16(commentSize);
+ Write16(0); // DiskNumberStart
+ Write16(item.InternalAttrib);
+ Write32(item.ExternalAttrib);
+ WRITE_32_VAL_SPEC(item.LocalHeaderPos, isPosition64)
+ WriteBytes((const char *)item.Name, item.Name.Len());
+
+ if (isZip64)
+ {
+ Write16(NFileHeader::NExtraID::kZip64);
+ Write16(zip64ExtraSize);
+ if (isUnPack64)
+ Write64(item.Size);
+ if (isPack64)
+ Write64(item.PackSize);
+ if (isPosition64)
+ Write64(item.LocalHeaderPos);
+ }
+
+ WriteTimeExtra(item, writeNtfs);
+ WriteUtfName(item);
+
+ WriteExtra(item.CentralExtra);
+ if (commentSize != 0)
+ WriteBytes(item.Comment, commentSize);
+}
+
+HRESULT COutArchive::WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment)
+{
+ RINOK(ClearRestriction())
+
+ const UInt64 cdOffset = GetCurPos();
+ FOR_VECTOR (i, items)
+ WriteCentralHeader(items[i]);
+ const UInt64 cd64EndOffset = GetCurPos();
+ const UInt64 cdSize = cd64EndOffset - cdOffset;
+ const bool cdOffset64 = DOES_NEED_ZIP64(cdOffset);
+ const bool cdSize64 = DOES_NEED_ZIP64(cdSize);
+ const bool items64 = items.Size() >= 0xFFFF;
+ const bool isZip64 = (cdOffset64 || cdSize64 || items64);
+
+ // isZip64 = true; // to test Zip64
+
+ if (isZip64)
+ {
+ Write32(NSignature::kEcd64);
+ Write64(kEcd64_MainSize);
+
+ // to test extra block:
+ // const UInt32 extraSize = 1 << 26;
+ // Write64(kEcd64_MainSize + extraSize);
+
+ Write16(45); // made by version
+ Write16(45); // extract version
+ Write32(0); // ThisDiskNumber
+ Write32(0); // StartCentralDirectoryDiskNumber
+ Write64((UInt64)items.Size());
+ Write64((UInt64)items.Size());
+ Write64((UInt64)cdSize);
+ Write64((UInt64)cdOffset);
+
+ // for (UInt32 iii = 0; iii < extraSize; iii++) Write8(1);
+
+ Write32(NSignature::kEcd64Locator);
+ Write32(0); // number of the disk with the start of the zip64 end of central directory
+ Write64(cd64EndOffset);
+ Write32(1); // total number of disks
+ }
+
+ Write32(NSignature::kEcd);
+ Write16(0); // ThisDiskNumber
+ Write16(0); // StartCentralDirectoryDiskNumber
+ Write16((UInt16)(items64 ? 0xFFFF: items.Size()));
+ Write16((UInt16)(items64 ? 0xFFFF: items.Size()));
+
+ WRITE_32_VAL_SPEC(cdSize, cdSize64)
+ WRITE_32_VAL_SPEC(cdOffset, cdOffset64)
+
+ const UInt16 commentSize = (UInt16)(comment ? comment->Size() : 0);
+ Write16((UInt16)commentSize);
+ if (commentSize != 0)
+ WriteBytes((const Byte *)*comment, commentSize);
+ m_OutBuffer.FlushWithCheck();
+ return S_OK;
+}
+
+void COutArchive::CreateStreamForCompressing(CMyComPtr<IOutStream> &outStream)
+{
+ COffsetOutStream *streamSpec = new COffsetOutStream;
+ outStream = streamSpec;
+ streamSpec->Init(m_Stream, m_Base + m_CurPos);
+}
+
+void COutArchive::CreateStreamForCopying(CMyComPtr<ISequentialOutStream> &outStream)
+{
+ outStream = m_Stream;
+}
+
+}}
diff --git a/CPP/7zip/Archive/Zip/ZipOut.h b/CPP/7zip/Archive/Zip/ZipOut.h
new file mode 100644
index 0000000..e9b2abb
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipOut.h
@@ -0,0 +1,103 @@
+// ZipOut.h
+
+#ifndef ZIP7_INC_ZIP_OUT_H
+#define ZIP7_INC_ZIP_OUT_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../Common/OutBuffer.h"
+
+#include "ZipItem.h"
+
+namespace NArchive {
+namespace NZip {
+
+class CItemOut: public CItem
+{
+public:
+ FILETIME Ntfs_MTime;
+ FILETIME Ntfs_ATime;
+ FILETIME Ntfs_CTime;
+ bool Write_NtfsTime;
+ bool Write_UnixTime;
+
+ // It's possible that NtfsTime is not defined, but there is NtfsTime in Extra.
+
+ CByteBuffer Name_Utf; // for Info-Zip (kIzUnicodeName) Extra
+
+ size_t Get_UtfName_ExtraSize() const
+ {
+ const size_t size = Name_Utf.Size();
+ if (size == 0)
+ return 0;
+ return 4 + 5 + size;
+ }
+
+ CItemOut():
+ Write_NtfsTime(false),
+ Write_UnixTime(false)
+ {}
+};
+
+
+// COutArchive can throw CSystemException and COutBufferException
+
+class COutArchive
+{
+ COutBuffer m_OutBuffer;
+ CMyComPtr<IOutStream> m_Stream;
+
+ UInt64 m_Base; // Base of archive (offset in output Stream)
+ UInt64 m_CurPos; // Curent position in archive (relative from m_Base)
+ UInt64 m_LocalHeaderPos; // LocalHeaderPos (relative from m_Base) for last WriteLocalHeader() call
+
+ UInt32 m_LocalFileHeaderSize;
+ UInt32 m_ExtraSize;
+ bool m_IsZip64;
+
+ void WriteBytes(const void *data, size_t size);
+ void Write8(Byte b);
+ void Write16(UInt16 val);
+ void Write32(UInt32 val);
+ void Write64(UInt64 val);
+ void WriteNtfsTime(const FILETIME &ft)
+ {
+ Write32(ft.dwLowDateTime);
+ Write32(ft.dwHighDateTime);
+ }
+
+ void WriteTimeExtra(const CItemOut &item, bool writeNtfs);
+ void WriteUtfName(const CItemOut &item);
+ void WriteExtra(const CExtraBlock &extra);
+ void WriteCommonItemInfo(const CLocalItem &item, bool isZip64);
+ void WriteCentralHeader(const CItemOut &item);
+
+ void SeekToCurPos();
+public:
+ CMyComPtr<IStreamSetRestriction> SetRestriction;
+
+ HRESULT ClearRestriction();
+ HRESULT SetRestrictionFromCurrent();
+ HRESULT Create(IOutStream *outStream);
+
+ UInt64 GetCurPos() const { return m_CurPos; }
+
+ void MoveCurPos(UInt64 distanceToMove)
+ {
+ m_CurPos += distanceToMove;
+ }
+
+ void WriteLocalHeader(CItemOut &item, bool needCheck = false);
+ void WriteLocalHeader_Replace(CItemOut &item);
+
+ void WriteDescriptor(const CItemOut &item);
+
+ HRESULT WriteCentralDir(const CObjectVector<CItemOut> &items, const CByteBuffer *comment);
+
+ void CreateStreamForCompressing(CMyComPtr<IOutStream> &outStream);
+ void CreateStreamForCopying(CMyComPtr<ISequentialOutStream> &outStream);
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/Zip/ZipRegister.cpp b/CPP/7zip/Archive/Zip/ZipRegister.cpp
new file mode 100644
index 0000000..c17a1a3
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipRegister.cpp
@@ -0,0 +1,38 @@
+// ZipRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/RegisterArc.h"
+
+#include "ZipHandler.h"
+
+namespace NArchive {
+namespace NZip {
+
+static const Byte k_Signature[] = {
+ 4, 0x50, 0x4B, 0x03, 0x04, // Local
+ 4, 0x50, 0x4B, 0x05, 0x06, // Ecd
+ 4, 0x50, 0x4B, 0x06, 0x06, // Ecd64
+ 6, 0x50, 0x4B, 0x07, 0x08, 0x50, 0x4B, // Span / Descriptor
+ 6, 0x50, 0x4B, 0x30, 0x30, 0x50, 0x4B }; // NoSpan
+
+REGISTER_ARC_IO(
+ "zip", "zip z01 zipx jar xpi odt ods docx xlsx epub ipa apk appx", NULL, 1,
+ k_Signature,
+ 0,
+ NArcInfoFlags::kFindSignature
+ | NArcInfoFlags::kMultiSignature
+ | NArcInfoFlags::kUseGlobalOffset
+ | NArcInfoFlags::kCTime
+ // | NArcInfoFlags::kCTime_Default
+ | NArcInfoFlags::kATime
+ // | NArcInfoFlags::kATime_Default
+ | NArcInfoFlags::kMTime
+ | NArcInfoFlags::kMTime_Default
+ , TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kWindows)
+ | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kUnix)
+ | TIME_PREC_TO_ARC_FLAGS_MASK (NFileTimeType::kDOS)
+ | TIME_PREC_TO_ARC_FLAGS_TIME_DEFAULT (NFileTimeType::kWindows)
+ , IsArc_Zip)
+
+}}
diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.cpp b/CPP/7zip/Archive/Zip/ZipUpdate.cpp
new file mode 100644
index 0000000..e6d881c
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipUpdate.cpp
@@ -0,0 +1,2027 @@
+// ZipUpdate.cpp
+
+#include "StdAfx.h"
+
+// #define DEBUG_CACHE
+
+#ifdef DEBUG_CACHE
+#include <stdio.h>
+ #define PRF(x) x
+#else
+ #define PRF(x)
+#endif
+
+#include "../../../../C/Alloc.h"
+
+#include "../../../Common/AutoPtr.h"
+#include "../../../Common/Defs.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/TimeUtils.h"
+#include "../../../Windows/Thread.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/OutMemStream.h"
+#include "../../Common/ProgressUtils.h"
+#ifndef Z7_ST
+#include "../../Common/ProgressMt.h"
+#endif
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+// #include "../../Compress/ZstdEncoderProps.h"
+
+#include "ZipAddCommon.h"
+#include "ZipOut.h"
+#include "ZipUpdate.h"
+
+using namespace NWindows;
+using namespace NSynchronization;
+
+namespace NArchive {
+namespace NZip {
+
+static const Byte kHostOS =
+ #ifdef _WIN32
+ NFileHeader::NHostOS::kFAT;
+ #else
+ NFileHeader::NHostOS::kUnix;
+ #endif
+
+static const Byte kMadeByHostOS = kHostOS;
+
+// 18.06: now we always write zero to high byte of ExtractVersion field.
+// Previous versions of p7zip wrote (NFileHeader::NHostOS::kUnix) there, that is not correct
+static const Byte kExtractHostOS = 0;
+
+static const Byte kMethodForDirectory = NFileHeader::NCompressionMethod::kStore;
+
+
+static void AddAesExtra(CItem &item, Byte aesKeyMode, UInt16 method)
+{
+ CWzAesExtra wzAesField;
+ wzAesField.Strength = aesKeyMode;
+ wzAesField.Method = method;
+ item.Method = NFileHeader::NCompressionMethod::kWzAES;
+ item.Crc = 0;
+ CExtraSubBlock sb;
+ wzAesField.SetSubBlock(sb);
+ item.LocalExtra.SubBlocks.Add(sb);
+ item.CentralExtra.SubBlocks.Add(sb);
+}
+
+
+static void Copy_From_UpdateItem_To_ItemOut(const CUpdateItem &ui, CItemOut &item)
+{
+ item.Name = ui.Name;
+ item.Name_Utf = ui.Name_Utf;
+ item.Comment = ui.Comment;
+ item.SetUtf8(ui.IsUtf8);
+ // item.SetFlag_AltStream(ui.IsAltStream);
+ // item.ExternalAttrib = ui.Attrib;
+ item.Time = ui.Time;
+ item.Ntfs_MTime = ui.Ntfs_MTime;
+ item.Ntfs_ATime = ui.Ntfs_ATime;
+ item.Ntfs_CTime = ui.Ntfs_CTime;
+
+ item.Write_UnixTime = ui.Write_UnixTime;
+ item.Write_NtfsTime = ui.Write_NtfsTime;
+}
+
+static void SetFileHeader(
+ const CCompressionMethodMode &options,
+ const CUpdateItem &ui,
+ bool useDescriptor,
+ CItemOut &item)
+{
+ item.Size = ui.Size;
+ const bool isDir = ui.IsDir;
+
+ item.ClearFlags();
+
+ if (ui.NewProps)
+ {
+ Copy_From_UpdateItem_To_ItemOut(ui, item);
+ // item.SetFlag_AltStream(ui.IsAltStream);
+ item.ExternalAttrib = ui.Attrib;
+ }
+ /*
+ else
+ isDir = item.IsDir();
+ */
+
+ item.MadeByVersion.HostOS = kMadeByHostOS;
+ item.MadeByVersion.Version = NFileHeader::NCompressionMethod::kMadeByProgramVersion;
+
+ item.ExtractVersion.HostOS = kExtractHostOS;
+
+ item.InternalAttrib = 0; // test it
+ item.SetEncrypted(!isDir && options.Password_Defined);
+ item.SetDescriptorMode(useDescriptor);
+
+ if (isDir)
+ {
+ item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir;
+ item.Method = kMethodForDirectory;
+ item.PackSize = 0;
+ item.Size = 0;
+ item.Crc = 0;
+ }
+
+ item.LocalExtra.Clear();
+ item.CentralExtra.Clear();
+
+ if (isDir)
+ {
+ item.ExtractVersion.Version = NFileHeader::NCompressionMethod::kExtractVersion_Dir;
+ item.Method = kMethodForDirectory;
+ item.PackSize = 0;
+ item.Size = 0;
+ item.Crc = 0;
+ }
+ else if (options.IsRealAesMode())
+ AddAesExtra(item, options.AesKeyMode, (Byte)(options.MethodSequence.IsEmpty() ? 8 : options.MethodSequence[0]));
+}
+
+
+// we call SetItemInfoFromCompressingResult() after SetFileHeader()
+
+static void SetItemInfoFromCompressingResult(const CCompressingResult &compressingResult,
+ bool isAesMode, Byte aesKeyMode, CItem &item)
+{
+ item.ExtractVersion.Version = compressingResult.ExtractVersion;
+ item.Method = compressingResult.Method;
+ if (compressingResult.Method == NFileHeader::NCompressionMethod::kLZMA && compressingResult.LzmaEos)
+ item.Flags |= NFileHeader::NFlags::kLzmaEOS;
+ item.Crc = compressingResult.CRC;
+ item.Size = compressingResult.UnpackSize;
+ item.PackSize = compressingResult.PackSize;
+
+ item.LocalExtra.Clear();
+ item.CentralExtra.Clear();
+
+ if (isAesMode)
+ AddAesExtra(item, aesKeyMode, compressingResult.Method);
+}
+
+
+#ifndef Z7_ST
+
+struct CMtSem
+{
+ NWindows::NSynchronization::CSemaphore Semaphore;
+ NWindows::NSynchronization::CCriticalSection CS;
+ CIntVector Indexes;
+ int Head;
+
+ void ReleaseItem(unsigned index)
+ {
+ {
+ CCriticalSectionLock lock(CS);
+ Indexes[index] = Head;
+ Head = (int)index;
+ }
+ Semaphore.Release();
+ }
+
+ int GetFreeItem()
+ {
+ int i;
+ {
+ CCriticalSectionLock lock(CS);
+ i = Head;
+ Head = Indexes[(unsigned)i];
+ }
+ return i;
+ }
+};
+
+static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo);
+
+struct CThreadInfo
+{
+ DECL_EXTERNAL_CODECS_LOC_VARS_DECL
+
+ NWindows::CThread Thread;
+ NWindows::NSynchronization::CAutoResetEvent CompressEvent;
+ CMtSem *MtSem;
+ unsigned ThreadIndex;
+
+ bool ExitThread;
+
+ CMtCompressProgress *ProgressSpec;
+ CMyComPtr<ICompressProgressInfo> Progress;
+
+ COutMemStream *OutStreamSpec;
+ CMyComPtr<IOutStream> OutStream;
+ CMyComPtr<ISequentialInStream> InStream;
+
+ CAddCommon Coder;
+ HRESULT Result;
+ CCompressingResult CompressingResult;
+
+ bool IsFree;
+ bool InSeqMode;
+ bool OutSeqMode;
+ bool ExpectedDataSize_IsConfirmed;
+
+ UInt32 UpdateIndex;
+ UInt32 FileTime;
+ UInt64 ExpectedDataSize;
+
+ CThreadInfo():
+ MtSem(NULL),
+ ExitThread(false),
+ ProgressSpec(NULL),
+ OutStreamSpec(NULL),
+ IsFree(true),
+ InSeqMode(false),
+ OutSeqMode(false),
+ ExpectedDataSize_IsConfirmed(false),
+ FileTime(0),
+ ExpectedDataSize((UInt64)(Int64)-1)
+ {}
+
+ void SetOptions(const CCompressionMethodMode &options)
+ {
+ Coder.SetOptions(options);
+ }
+
+ HRESULT CreateEvents()
+ {
+ WRes wres = CompressEvent.CreateIfNotCreated_Reset();
+ return HRESULT_FROM_WIN32(wres);
+ }
+
+ HRESULT CreateThread()
+ {
+ WRes wres = Thread.Create(CoderThread, this);
+ return HRESULT_FROM_WIN32(wres);
+ }
+
+ void WaitAndCode();
+
+ void StopWait_Close()
+ {
+ ExitThread = true;
+ if (OutStreamSpec)
+ OutStreamSpec->StopWriting(E_ABORT);
+ if (CompressEvent.IsCreated())
+ CompressEvent.Set();
+ Thread.Wait_Close();
+ }
+};
+
+void CThreadInfo::WaitAndCode()
+{
+ for (;;)
+ {
+ CompressEvent.Lock();
+ if (ExitThread)
+ return;
+
+ Result = Coder.Compress(
+ EXTERNAL_CODECS_LOC_VARS
+ InStream, OutStream,
+ InSeqMode, OutSeqMode, FileTime, ExpectedDataSize,
+ ExpectedDataSize_IsConfirmed,
+ Progress, CompressingResult);
+
+ if (Result == S_OK && Progress)
+ Result = Progress->SetRatioInfo(&CompressingResult.UnpackSize, &CompressingResult.PackSize);
+
+ MtSem->ReleaseItem(ThreadIndex);
+ }
+}
+
+static THREAD_FUNC_DECL CoderThread(void *threadCoderInfo)
+{
+ ((CThreadInfo *)threadCoderInfo)->WaitAndCode();
+ return 0;
+}
+
+class CThreads
+{
+public:
+ CObjectVector<CThreadInfo> Threads;
+ ~CThreads()
+ {
+ FOR_VECTOR (i, Threads)
+ Threads[i].StopWait_Close();
+ }
+};
+
+struct CMemBlocks2: public CMemLockBlocks
+{
+ bool Skip;
+ bool InSeqMode;
+ bool PreDescriptorMode;
+ bool Finished;
+ CCompressingResult CompressingResult;
+
+ CMemBlocks2(): Skip(false), InSeqMode(false), PreDescriptorMode(false), Finished(false),
+ CompressingResult() {}
+};
+
+class CMemRefs
+{
+public:
+ CMemBlockManagerMt *Manager;
+ CObjectVector<CMemBlocks2> Refs;
+ CMemRefs(CMemBlockManagerMt *manager): Manager(manager) {}
+ ~CMemRefs()
+ {
+ FOR_VECTOR (i, Refs)
+ Refs[i].FreeOpt(Manager);
+ }
+};
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ CMtProgressMixer2
+ , ICompressProgressInfo
+)
+ UInt64 ProgressOffset;
+ UInt64 InSizes[2];
+ UInt64 OutSizes[2];
+ CMyComPtr<IProgress> Progress;
+ CMyComPtr<ICompressProgressInfo> RatioProgress;
+ bool _inSizeIsMain;
+public:
+ NWindows::NSynchronization::CCriticalSection CriticalSection;
+ void Create(IProgress *progress, bool inSizeIsMain);
+ void SetProgressOffset(UInt64 progressOffset);
+ void SetProgressOffset_NoLock(UInt64 progressOffset);
+ HRESULT SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize);
+};
+
+void CMtProgressMixer2::Create(IProgress *progress, bool inSizeIsMain)
+{
+ Progress = progress;
+ Progress.QueryInterface(IID_ICompressProgressInfo, &RatioProgress);
+ _inSizeIsMain = inSizeIsMain;
+ ProgressOffset = InSizes[0] = InSizes[1] = OutSizes[0] = OutSizes[1] = 0;
+}
+
+void CMtProgressMixer2::SetProgressOffset_NoLock(UInt64 progressOffset)
+{
+ InSizes[1] = OutSizes[1] = 0;
+ ProgressOffset = progressOffset;
+}
+
+void CMtProgressMixer2::SetProgressOffset(UInt64 progressOffset)
+{
+ CriticalSection.Enter();
+ SetProgressOffset_NoLock(progressOffset);
+ CriticalSection.Leave();
+}
+
+HRESULT CMtProgressMixer2::SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize)
+{
+ NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
+ if (index == 0 && RatioProgress)
+ {
+ RINOK(RatioProgress->SetRatioInfo(inSize, outSize))
+ }
+ if (inSize)
+ InSizes[index] = *inSize;
+ if (outSize)
+ OutSizes[index] = *outSize;
+ UInt64 v = ProgressOffset + (_inSizeIsMain ?
+ (InSizes[0] + InSizes[1]) :
+ (OutSizes[0] + OutSizes[1]));
+ return Progress->SetCompleted(&v);
+}
+
+Z7_COM7F_IMF(CMtProgressMixer2::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
+{
+ return SetRatioInfo(0, inSize, outSize);
+}
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ CMtProgressMixer
+ , ICompressProgressInfo
+)
+public:
+ CMtProgressMixer2 *Mixer2;
+ CMyComPtr<ICompressProgressInfo> RatioProgress;
+ void Create(IProgress *progress, bool inSizeIsMain);
+};
+
+void CMtProgressMixer::Create(IProgress *progress, bool inSizeIsMain)
+{
+ Mixer2 = new CMtProgressMixer2;
+ RatioProgress = Mixer2;
+ Mixer2->Create(progress, inSizeIsMain);
+}
+
+Z7_COM7F_IMF(CMtProgressMixer::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
+{
+ return Mixer2->SetRatioInfo(1, inSize, outSize);
+}
+
+
+#endif
+
+static HRESULT UpdateItemOldData(
+ COutArchive &archive,
+ CInArchive *inArchive,
+ const CItemEx &itemEx,
+ const CUpdateItem &ui,
+ CItemOut &item,
+ /* bool izZip64, */
+ ICompressProgressInfo *progress,
+ IArchiveUpdateCallbackFile *opCallback,
+ UInt64 &complexity)
+{
+ if (opCallback)
+ {
+ RINOK(opCallback->ReportOperation(
+ NEventIndexType::kInArcIndex, (UInt32)ui.IndexInArc,
+ NUpdateNotifyOp::kReplicate))
+ }
+
+ UInt64 rangeSize;
+
+ RINOK(archive.ClearRestriction())
+
+ if (ui.NewProps)
+ {
+ if (item.HasDescriptor())
+ return E_NOTIMPL;
+
+ // we keep ExternalAttrib and some another properties from old archive
+ // item.ExternalAttrib = ui.Attrib;
+ // if we don't change Comment, we keep Comment from OldProperties
+ Copy_From_UpdateItem_To_ItemOut(ui, item);
+ // item.SetFlag_AltStream(ui.IsAltStream);
+
+ item.CentralExtra.RemoveUnknownSubBlocks();
+ item.LocalExtra.RemoveUnknownSubBlocks();
+
+ archive.WriteLocalHeader(item);
+ rangeSize = item.GetPackSizeWithDescriptor();
+ }
+ else
+ {
+ item.LocalHeaderPos = archive.GetCurPos();
+ rangeSize = itemEx.GetLocalFullSize();
+ }
+
+ CMyComPtr<ISequentialInStream> packStream;
+
+ RINOK(inArchive->GetItemStream(itemEx, ui.NewProps, packStream))
+ if (!packStream)
+ return E_NOTIMPL;
+
+ complexity += rangeSize;
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ archive.CreateStreamForCopying(outStream);
+ HRESULT res = NCompress::CopyStream_ExactSize(packStream, outStream, rangeSize, progress);
+ archive.MoveCurPos(rangeSize);
+ return res;
+}
+
+
+static HRESULT WriteDirHeader(COutArchive &archive, const CCompressionMethodMode *options,
+ const CUpdateItem &ui, CItemOut &item)
+{
+ SetFileHeader(*options, ui, false, item);
+ RINOK(archive.ClearRestriction())
+ archive.WriteLocalHeader(item);
+ return S_OK;
+}
+
+
+static void UpdatePropsFromStream(
+ const CUpdateOptions &options,
+ CUpdateItem &item, ISequentialInStream *fileInStream,
+ IArchiveUpdateCallback *updateCallback, UInt64 &totalComplexity)
+{
+ CMyComPtr<IStreamGetProps> getProps;
+ fileInStream->QueryInterface(IID_IStreamGetProps, (void **)&getProps);
+ UInt64 size = (UInt64)(Int64)-1;
+ bool size_WasSet = false;
+
+ if (getProps)
+ {
+ FILETIME cTime, aTime, mTime;
+ UInt32 attrib;
+ if (getProps->GetProps(&size, &cTime, &aTime, &mTime, &attrib) == S_OK)
+ {
+ if (options.Write_MTime)
+ if (!FILETIME_IsZero(mTime))
+ {
+ item.Ntfs_MTime = mTime;
+ NTime::UtcFileTime_To_LocalDosTime(mTime, item.Time);
+ }
+
+ if (options.Write_CTime) if (!FILETIME_IsZero(cTime)) item.Ntfs_CTime = cTime;
+ if (options.Write_ATime) if (!FILETIME_IsZero(aTime)) item.Ntfs_ATime = aTime;
+
+ item.Attrib = attrib;
+ size_WasSet = true;
+ }
+ }
+
+ if (!size_WasSet)
+ {
+ CMyComPtr<IStreamGetSize> streamGetSize;
+ fileInStream->QueryInterface(IID_IStreamGetSize, (void **)&streamGetSize);
+ if (streamGetSize)
+ {
+ if (streamGetSize->GetSize(&size) == S_OK)
+ size_WasSet = true;
+ }
+ }
+
+ if (size_WasSet && size != (UInt64)(Int64)-1)
+ {
+ item.Size_WasSetFromStream = true;
+ if (size != item.Size)
+ {
+ const Int64 newComplexity = (Int64)totalComplexity + ((Int64)size - (Int64)item.Size);
+ if (newComplexity > 0)
+ {
+ totalComplexity = (UInt64)newComplexity;
+ updateCallback->SetTotal(totalComplexity);
+ }
+ item.Size = size;
+ }
+ }
+}
+
+
+/*
+static HRESULT ReportProps(
+ IArchiveUpdateCallbackArcProp *reportArcProp,
+ UInt32 index,
+ const CItemOut &item,
+ bool isAesMode)
+{
+ PROPVARIANT prop;
+ prop.vt = VT_EMPTY;
+ prop.wReserved1 = 0;
+
+ NCOM::PropVarEm_Set_UInt64(&prop, item.Size);
+ RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidSize, &prop));
+
+ NCOM::PropVarEm_Set_UInt64(&prop, item.PackSize);
+ RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidPackSize, &prop));
+
+ if (!isAesMode)
+ {
+ NCOM::PropVarEm_Set_UInt32(&prop, item.Crc);
+ RINOK(reportArcProp->ReportProp(NEventIndexType::kOutArcIndex, index, kpidCRC, &prop));
+ }
+
+ RINOK(reportArcProp->ReportFinished(NEventIndexType::kOutArcIndex, index, NUpdate::NOperationResult::kOK));
+
+ // if (opCallback) RINOK(opCallback->ReportOperation(NEventIndexType::kOutArcIndex, index, NUpdateNotifyOp::kOpFinished))
+
+ return S_OK;
+}
+*/
+
+/*
+struct CTotalStats
+{
+ UInt64 Size;
+ UInt64 PackSize;
+
+ void UpdateWithItem(const CItemOut &item)
+ {
+ Size += item.Size;
+ PackSize += item.PackSize;
+ }
+};
+
+static HRESULT ReportArcProps(IArchiveUpdateCallbackArcProp *reportArcProp,
+ CTotalStats &st)
+{
+ PROPVARIANT prop;
+ prop.vt = VT_EMPTY;
+ prop.wReserved1 = 0;
+ {
+ NWindows::NCOM::PropVarEm_Set_UInt64(&prop, st.Size);
+ RINOK(reportArcProp->ReportProp(
+ NEventIndexType::kArcProp, 0, kpidSize, &prop));
+ }
+ {
+ NWindows::NCOM::PropVarEm_Set_UInt64(&prop, st.PackSize);
+ RINOK(reportArcProp->ReportProp(
+ NEventIndexType::kArcProp, 0, kpidPackSize, &prop));
+ }
+ return S_OK;
+}
+*/
+
+
+static HRESULT Update2St(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ COutArchive &archive,
+ CInArchive *inArchive,
+ const CObjectVector<CItemEx> &inputItems,
+ CObjectVector<CUpdateItem> &updateItems,
+ const CUpdateOptions &updateOptions,
+ const CCompressionMethodMode *options, bool outSeqMode,
+ const CByteBuffer *comment,
+ IArchiveUpdateCallback *updateCallback,
+ UInt64 &totalComplexity,
+ IArchiveUpdateCallbackFile *opCallback
+ // , IArchiveUpdateCallbackArcProp *reportArcProp
+ )
+{
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(updateCallback, true);
+
+ CAddCommon compressor;
+ compressor.SetOptions(*options);
+
+ CObjectVector<CItemOut> items;
+ UInt64 unpackSizeTotal = 0, packSizeTotal = 0;
+
+ FOR_VECTOR (itemIndex, updateItems)
+ {
+ lps->InSize = unpackSizeTotal;
+ lps->OutSize = packSizeTotal;
+ RINOK(lps->SetCur())
+ CUpdateItem &ui = updateItems[itemIndex];
+ CItemEx itemEx;
+ CItemOut item;
+
+ if (!ui.NewProps || !ui.NewData)
+ {
+ // Note: for (ui.NewProps && !ui.NewData) it copies Props from old archive,
+ // But we will rewrite all important properties later. But we can keep some properties like Comment
+ itemEx = inputItems[(unsigned)ui.IndexInArc];
+ if (inArchive->Read_LocalItem_After_CdItem_Full(itemEx) != S_OK)
+ return E_NOTIMPL;
+ (CItem &)item = itemEx;
+ }
+
+ if (ui.NewData)
+ {
+ // bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir());
+ bool isDir = ui.IsDir;
+ if (isDir)
+ {
+ RINOK(WriteDirHeader(archive, options, ui, item))
+ }
+ else
+ {
+ CMyComPtr<ISequentialInStream> fileInStream;
+ {
+ HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
+ if (res == S_FALSE)
+ {
+ lps->ProgressOffset += ui.Size;
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK))
+ continue;
+ }
+ RINOK(res)
+ if (!fileInStream)
+ return E_INVALIDARG;
+
+ bool inSeqMode = false;
+ if (!inSeqMode)
+ {
+ CMyComPtr<IInStream> inStream2;
+ fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2);
+ inSeqMode = (inStream2 == NULL);
+ }
+ // seqMode = true; // to test seqMode
+
+ UpdatePropsFromStream(updateOptions, ui, fileInStream, updateCallback, totalComplexity);
+
+ CCompressingResult compressingResult;
+
+ RINOK(compressor.Set_Pre_CompressionResult(
+ inSeqMode, outSeqMode,
+ ui.Size,
+ compressingResult))
+
+ SetFileHeader(*options, ui, compressingResult.DescriptorMode, item);
+
+ // file Size can be 64-bit !!!
+
+ SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item);
+
+ RINOK(archive.SetRestrictionFromCurrent())
+ archive.WriteLocalHeader(item);
+
+ CMyComPtr<IOutStream> outStream;
+ archive.CreateStreamForCompressing(outStream);
+
+ RINOK(compressor.Compress(
+ EXTERNAL_CODECS_LOC_VARS
+ fileInStream, outStream,
+ inSeqMode, outSeqMode,
+ ui.Time,
+ ui.Size, ui.Size_WasSetFromStream,
+ progress, compressingResult))
+
+ if (item.HasDescriptor() != compressingResult.DescriptorMode)
+ return E_FAIL;
+
+ SetItemInfoFromCompressingResult(compressingResult, options->IsRealAesMode(), options->AesKeyMode, item);
+
+ archive.WriteLocalHeader_Replace(item);
+ }
+ // if (reportArcProp) RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options->IsRealAesMode()))
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK))
+ unpackSizeTotal += item.Size;
+ packSizeTotal += item.PackSize;
+ }
+ }
+ else
+ {
+ UInt64 complexity = 0;
+ lps->SendRatio = false;
+
+ RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, opCallback, complexity))
+
+ lps->SendRatio = true;
+ lps->ProgressOffset += complexity;
+ }
+
+ items.Add(item);
+ lps->ProgressOffset += kLocalHeaderSize;
+ }
+
+ lps->InSize = unpackSizeTotal;
+ lps->OutSize = packSizeTotal;
+ RINOK(lps->SetCur())
+
+ RINOK(archive.WriteCentralDir(items, comment))
+
+ /*
+ CTotalStats stat;
+ stat.Size = unpackSizeTotal;
+ stat.PackSize = packSizeTotal;
+ if (reportArcProp)
+ RINOK(ReportArcProps(reportArcProp, stat))
+ */
+
+ lps->ProgressOffset += kCentralHeaderSize * updateItems.Size() + 1;
+ return lps->SetCur();
+}
+
+#ifndef Z7_ST
+
+
+static const size_t kBlockSize = 1 << 16;
+// kMemPerThread must be >= kBlockSize
+//
+static const size_t kMemPerThread = (size_t)sizeof(size_t) << 23;
+// static const size_t kMemPerThread = (size_t)sizeof(size_t) << 16; // for debug
+// static const size_t kMemPerThread = (size_t)1 << 16; // for debug
+
+/*
+in:
+ nt_Zip >= 1: the starting maximum number of ZIP threads for search
+out:
+ nt_Zip: calculated number of ZIP threads
+ returns: calculated number of ZSTD threads
+*/
+/*
+static UInt32 CalcThreads_for_ZipZstd(CZstdEncProps *zstdProps,
+ UInt64 memLimit, UInt32 totalThreads,
+ UInt32 &nt_Zip)
+{
+ for (; nt_Zip > 1; nt_Zip--)
+ {
+ UInt64 mem1 = memLimit / nt_Zip;
+ if (mem1 <= kMemPerThread)
+ continue;
+ mem1 -= kMemPerThread;
+ UInt32 n_ZSTD = ZstdEncProps_GetNumThreads_for_MemUsageLimit(
+ zstdProps, mem1, totalThreads / nt_Zip);
+ // we don't allow (nbWorkers == 1) here
+ if (n_ZSTD <= 1)
+ n_ZSTD = 0;
+ zstdProps->nbWorkers = n_ZSTD;
+ mem1 = ZstdEncProps_GetMemUsage(zstdProps);
+ if ((mem1 + kMemPerThread) * nt_Zip <= memLimit)
+ return n_ZSTD;
+ }
+ return ZstdEncProps_GetNumThreads_for_MemUsageLimit(
+ zstdProps, memLimit, totalThreads);
+}
+
+
+static UInt32 SetZstdThreads(
+ const CCompressionMethodMode &options,
+ COneMethodInfo *oneMethodMain,
+ UInt32 numThreads,
+ UInt32 numZipThreads_limit,
+ UInt64 numFilesToCompress,
+ UInt64 numBytesToCompress)
+{
+ NCompress::NZstd::CEncoderProps encoderProps;
+ RINOK(encoderProps.SetFromMethodProps(*oneMethodMain));
+ CZstdEncProps &zstdProps = encoderProps.EncProps;
+ ZstdEncProps_NormalizeFull(&zstdProps);
+ if (oneMethodMain->FindProp(NCoderPropID::kNumThreads) >= 0)
+ {
+ // threads for ZSTD are fixed
+ if (zstdProps.nbWorkers > 1)
+ numThreads /= zstdProps.nbWorkers;
+ if (numThreads > numZipThreads_limit)
+ numThreads = numZipThreads_limit;
+ if (options._memUsage_WasSet
+ && !options._numThreads_WasForced)
+ {
+ const UInt64 mem1 = ZstdEncProps_GetMemUsage(&zstdProps);
+ const UInt64 numZipThreads = options._memUsage_Compress / (mem1 + kMemPerThread);
+ if (numThreads > numZipThreads)
+ numThreads = (UInt32)numZipThreads;
+ }
+ return numThreads;
+ }
+ {
+ // threads for ZSTD are not fixed
+
+ // calculate estimated required number of ZST threads per file size statistics
+ UInt32 t = MY_ZSTDMT_NBWORKERS_MAX;
+ {
+ UInt64 averageNumberOfBlocks = 0;
+ const UInt64 averageSize = numBytesToCompress / numFilesToCompress;
+ const UInt64 jobSize = zstdProps.jobSize;
+ if (jobSize != 0)
+ averageNumberOfBlocks = averageSize / jobSize + 0;
+ if (t > averageNumberOfBlocks)
+ t = (UInt32)averageNumberOfBlocks;
+ }
+ if (t > numThreads)
+ t = numThreads;
+
+ // calculate the nuber of zip threads
+ UInt32 numZipThreads = numThreads;
+ if (t > 1)
+ numZipThreads = numThreads / t;
+ if (numZipThreads > numZipThreads_limit)
+ numZipThreads = numZipThreads_limit;
+ if (numZipThreads < 1)
+ numZipThreads = 1;
+ {
+ // recalculate the number of ZSTD threads via the number of ZIP threads
+ const UInt32 t2 = numThreads / numZipThreads;
+ if (t < t2)
+ t = t2;
+ }
+
+ if (options._memUsage_WasSet
+ && !options._numThreads_WasForced)
+ {
+ t = CalcThreads_for_ZipZstd(&zstdProps,
+ options._memUsage_Compress, numThreads, numZipThreads);
+ numThreads = numZipThreads;
+ }
+ // we don't use (nbWorkers = 1) here
+ if (t <= 1)
+ t = 0;
+ oneMethodMain->AddProp_NumThreads(t);
+ return numThreads;
+ }
+}
+*/
+
+#endif
+
+
+
+
+static HRESULT Update2(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ COutArchive &archive,
+ CInArchive *inArchive,
+ const CObjectVector<CItemEx> &inputItems,
+ CObjectVector<CUpdateItem> &updateItems,
+ const CUpdateOptions &updateOptions,
+ const CCompressionMethodMode &options, bool outSeqMode,
+ const CByteBuffer *comment,
+ IArchiveUpdateCallback *updateCallback)
+{
+ CMyComPtr<IArchiveUpdateCallbackFile> opCallback;
+ updateCallback->QueryInterface(IID_IArchiveUpdateCallbackFile, (void **)&opCallback);
+
+ /*
+ CMyComPtr<IArchiveUpdateCallbackArcProp> reportArcProp;
+ updateCallback->QueryInterface(IID_IArchiveUpdateCallbackArcProp, (void **)&reportArcProp);
+ */
+
+ bool unknownComplexity = false;
+ UInt64 complexity = 0;
+ #ifndef Z7_ST
+ UInt64 numFilesToCompress = 0;
+ UInt64 numBytesToCompress = 0;
+ #endif
+
+ unsigned i;
+
+ for (i = 0; i < updateItems.Size(); i++)
+ {
+ const CUpdateItem &ui = updateItems[i];
+ if (ui.NewData)
+ {
+ if (ui.Size == (UInt64)(Int64)-1)
+ unknownComplexity = true;
+ else
+ complexity += ui.Size;
+ #ifndef Z7_ST
+ numBytesToCompress += ui.Size;
+ numFilesToCompress++;
+ #endif
+ /*
+ if (ui.Commented)
+ complexity += ui.CommentRange.Size;
+ */
+ }
+ else
+ {
+ CItemEx inputItem = inputItems[(unsigned)ui.IndexInArc];
+ if (inArchive->Read_LocalItem_After_CdItem_Full(inputItem) != S_OK)
+ return E_NOTIMPL;
+ complexity += inputItem.GetLocalFullSize();
+ // complexity += inputItem.GetCentralExtraPlusCommentSize();
+ }
+ complexity += kLocalHeaderSize;
+ complexity += kCentralHeaderSize;
+ }
+
+ if (comment)
+ complexity += comment->Size();
+ complexity++; // end of central
+
+ if (!unknownComplexity)
+ updateCallback->SetTotal(complexity);
+
+ UInt64 totalComplexity = complexity;
+
+ CCompressionMethodMode options2 = options;
+
+ if (options2._methods.IsEmpty())
+ {
+ // we need method item, if default method was used
+ options2._methods.AddNew();
+ }
+
+ CAddCommon compressor;
+ compressor.SetOptions(options2);
+
+ complexity = 0;
+
+ const Byte method = options.MethodSequence.Front();
+
+ COneMethodInfo *oneMethodMain = NULL;
+ if (!options2._methods.IsEmpty())
+ oneMethodMain = &options2._methods[0];
+
+ {
+ FOR_VECTOR (mi, options2._methods)
+ {
+ options2.SetGlobalLevelTo(options2._methods[mi]);
+ }
+ }
+
+ if (oneMethodMain)
+ {
+ // appnote recommends to use EOS marker for LZMA.
+ if (method == NFileHeader::NCompressionMethod::kLZMA)
+ oneMethodMain->AddProp_EndMarker_if_NotFound(true);
+ }
+
+
+ #ifndef Z7_ST
+
+ UInt32 numThreads = options._numThreads;
+
+ UInt32 numZipThreads_limit = numThreads;
+ if (numZipThreads_limit > numFilesToCompress)
+ numZipThreads_limit = (UInt32)numFilesToCompress;
+
+ if (numZipThreads_limit > 1)
+ {
+ const unsigned numFiles_OPEN_MAX = NSystem::Get_File_OPEN_MAX_Reduced_for_3_tasks();
+ // printf("\nzip:numFiles_OPEN_MAX =%d\n", (unsigned)numFiles_OPEN_MAX);
+ if (numZipThreads_limit > numFiles_OPEN_MAX)
+ numZipThreads_limit = (UInt32)numFiles_OPEN_MAX;
+ }
+
+ {
+ const UInt32 kNumMaxThreads =
+ #ifdef _WIN32
+ 64; // _WIN32 supports only 64 threads in one group. So no need for more threads here
+ #else
+ 128;
+ #endif
+ if (numThreads > kNumMaxThreads)
+ numThreads = kNumMaxThreads;
+ }
+ /*
+ if (numThreads > MAXIMUM_WAIT_OBJECTS) // is 64 in Windows
+ numThreads = MAXIMUM_WAIT_OBJECTS;
+ */
+
+
+ /*
+ // zstd supports (numThreads == 0);
+ if (numThreads < 1)
+ numThreads = 1;
+ */
+
+ bool mtMode = (numThreads > 1);
+
+ if (numFilesToCompress <= 1)
+ mtMode = false;
+
+ // mtMode = true; // debug: to test mtMode
+
+ if (!mtMode)
+ {
+ // if (oneMethodMain) {
+ /*
+ if (method == NFileHeader::NCompressionMethod::kZstdWz)
+ {
+ if (oneMethodMain->FindProp(NCoderPropID::kNumThreads) < 0)
+ {
+ // numZstdThreads was not forced in oneMethodMain
+ if (numThreads >= 1
+ && options._memUsage_WasSet
+ && !options._numThreads_WasForced)
+ {
+ NCompress::NZstd::CEncoderProps encoderProps;
+ RINOK(encoderProps.SetFromMethodProps(*oneMethodMain))
+ CZstdEncProps &zstdProps = encoderProps.EncProps;
+ ZstdEncProps_NormalizeFull(&zstdProps);
+ numThreads = ZstdEncProps_GetNumThreads_for_MemUsageLimit(
+ &zstdProps, options._memUsage_Compress, numThreads);
+ // we allow (nbWorkers = 1) here.
+ }
+ oneMethodMain->AddProp_NumThreads(numThreads);
+ }
+ } // kZstdWz
+ */
+ // } // oneMethodMain
+
+ FOR_VECTOR (mi, options2._methods)
+ {
+ COneMethodInfo &onem = options2._methods[mi];
+
+ if (onem.FindProp(NCoderPropID::kNumThreads) < 0)
+ {
+ // fixme: we should check the number of threads for xz method also
+ // fixed for 9.31. bzip2 default is just one thread.
+ onem.AddProp_NumThreads(numThreads);
+ }
+ }
+ }
+ else // mtMode
+ {
+ if (method == NFileHeader::NCompressionMethod::kStore && !options.Password_Defined)
+ numThreads = 1;
+
+ if (oneMethodMain)
+ {
+
+ if (method == NFileHeader::NCompressionMethod::kBZip2)
+ {
+ bool fixedNumber;
+ UInt32 numBZip2Threads = oneMethodMain->Get_BZip2_NumThreads(fixedNumber);
+ if (!fixedNumber)
+ {
+ const UInt64 averageSize = numBytesToCompress / numFilesToCompress;
+ const UInt32 blockSize = oneMethodMain->Get_BZip2_BlockSize();
+ const UInt64 averageNumberOfBlocks = averageSize / blockSize + 1;
+ numBZip2Threads = 64;
+ if (numBZip2Threads > averageNumberOfBlocks)
+ numBZip2Threads = (UInt32)averageNumberOfBlocks;
+ if (numBZip2Threads > numThreads)
+ numBZip2Threads = numThreads;
+ oneMethodMain->AddProp_NumThreads(numBZip2Threads);
+ }
+ numThreads /= numBZip2Threads;
+ }
+ else if (method == NFileHeader::NCompressionMethod::kXz)
+ {
+ UInt32 numLzmaThreads = 1;
+ int numXzThreads = oneMethodMain->Get_Xz_NumThreads(numLzmaThreads);
+ if (numXzThreads < 0)
+ {
+ // numXzThreads is unknown
+ const UInt64 averageSize = numBytesToCompress / numFilesToCompress;
+ const UInt64 blockSize = oneMethodMain->Get_Xz_BlockSize();
+ UInt64 averageNumberOfBlocks = 1;
+ if (blockSize != (UInt64)(Int64)-1)
+ averageNumberOfBlocks = averageSize / blockSize + 1;
+ UInt32 t = 256;
+ if (t > averageNumberOfBlocks)
+ t = (UInt32)averageNumberOfBlocks;
+ t *= numLzmaThreads;
+ if (t > numThreads)
+ t = numThreads;
+ oneMethodMain->AddProp_NumThreads(t);
+ numXzThreads = (int)t;
+ }
+ numThreads /= (unsigned)numXzThreads;
+ }
+ /*
+ else if (method == NFileHeader::NCompressionMethod::kZstdWz)
+ {
+ numThreads = SetZstdThreads(options,
+ oneMethodMain, numThreads,
+ numZipThreads_limit,
+ numFilesToCompress, numBytesToCompress);
+ }
+ */
+ else if (
+ method == NFileHeader::NCompressionMethod::kDeflate
+ || method == NFileHeader::NCompressionMethod::kDeflate64
+ || method == NFileHeader::NCompressionMethod::kPPMd)
+ {
+ if (numThreads > 1
+ && options._memUsage_WasSet
+ && !options._numThreads_WasForced)
+ {
+ UInt64 methodMemUsage;
+ if (method == NFileHeader::NCompressionMethod::kPPMd)
+ methodMemUsage = oneMethodMain->Get_Ppmd_MemSize();
+ else
+ methodMemUsage = (4 << 20); // for deflate
+ const UInt64 threadMemUsage = kMemPerThread + methodMemUsage;
+ const UInt64 numThreads64 = options._memUsage_Compress / threadMemUsage;
+ if (numThreads64 < numThreads)
+ numThreads = (UInt32)numThreads64;
+ }
+ }
+ else if (method == NFileHeader::NCompressionMethod::kLZMA)
+ {
+ // we suppose that default LZMA is 2 thread. So we don't change it
+ const UInt32 numLZMAThreads = oneMethodMain->Get_Lzma_NumThreads();
+ numThreads /= numLZMAThreads;
+
+ if (numThreads > 1
+ && options._memUsage_WasSet
+ && !options._numThreads_WasForced)
+ {
+ const UInt64 methodMemUsage = oneMethodMain->Get_Lzma_MemUsage(true);
+ const UInt64 threadMemUsage = kMemPerThread + methodMemUsage;
+ const UInt64 numThreads64 = options._memUsage_Compress / threadMemUsage;
+ if (numThreads64 < numThreads)
+ numThreads = (UInt32)numThreads64;
+ }
+ }
+ } // (oneMethodMain)
+
+ if (numThreads > numZipThreads_limit)
+ numThreads = numZipThreads_limit;
+ if (numThreads <= 1)
+ {
+ mtMode = false;
+ numThreads = 1;
+ }
+ }
+
+ // mtMode = true; // to test mtMode for seqMode
+
+ if (!mtMode)
+ #endif
+ return Update2St(
+ EXTERNAL_CODECS_LOC_VARS
+ archive, inArchive,
+ inputItems, updateItems,
+ updateOptions,
+ &options2, outSeqMode,
+ comment, updateCallback, totalComplexity,
+ opCallback
+ // , reportArcProp
+ );
+
+
+ #ifndef Z7_ST
+
+ /*
+ CTotalStats stat;
+ stat.Size = 0;
+ stat.PackSize = 0;
+ */
+ if (numThreads < 1)
+ numThreads = 1;
+
+ CObjectVector<CItemOut> items;
+
+ CMtProgressMixer *mtProgressMixerSpec = new CMtProgressMixer;
+ CMyComPtr<ICompressProgressInfo> progress = mtProgressMixerSpec;
+ mtProgressMixerSpec->Create(updateCallback, true);
+
+ CMtCompressProgressMixer mtCompressProgressMixer;
+ mtCompressProgressMixer.Init(numThreads, mtProgressMixerSpec->RatioProgress);
+
+ CMemBlockManagerMt memManager(kBlockSize);
+ CMemRefs refs(&memManager);
+
+ CMtSem mtSem;
+ CThreads threads;
+ mtSem.Head = -1;
+ mtSem.Indexes.ClearAndSetSize(numThreads);
+ {
+ WRes wres = mtSem.Semaphore.Create(0, numThreads);
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ }
+
+ CUIntVector threadIndices; // list threads in order of updateItems
+
+ {
+ RINOK(memManager.AllocateSpaceAlways((size_t)numThreads * (kMemPerThread / kBlockSize)))
+ for (i = 0; i < updateItems.Size(); i++)
+ refs.Refs.Add(CMemBlocks2());
+
+ for (i = 0; i < numThreads; i++)
+ {
+ threads.Threads.AddNew();
+ // mtSem.Indexes[i] = -1; // actually we don't use these values
+ }
+
+ for (i = 0; i < numThreads; i++)
+ {
+ CThreadInfo &threadInfo = threads.Threads[i];
+ threadInfo.ThreadIndex = i;
+ threadInfo.SetOptions(options2);
+ #ifdef Z7_EXTERNAL_CODECS
+ threadInfo._externalCodecs = _externalCodecs;
+ #endif
+ RINOK(threadInfo.CreateEvents())
+ threadInfo.OutStreamSpec = new COutMemStream(&memManager);
+ RINOK(threadInfo.OutStreamSpec->CreateEvents(SYNC_WFMO(&memManager.Synchro)))
+ threadInfo.OutStream = threadInfo.OutStreamSpec;
+ threadInfo.ProgressSpec = new CMtCompressProgress();
+ threadInfo.Progress = threadInfo.ProgressSpec;
+ threadInfo.ProgressSpec->Init(&mtCompressProgressMixer, i);
+ threadInfo.MtSem = &mtSem;
+ RINOK(threadInfo.CreateThread())
+ }
+ }
+
+ unsigned mtItemIndex = 0;
+ unsigned itemIndex = 0;
+ int lastRealStreamItemIndex = -1;
+
+
+ while (itemIndex < updateItems.Size())
+ {
+ if (threadIndices.Size() < numThreads && mtItemIndex < updateItems.Size())
+ {
+ // we start ahead the threads for compressing
+ // also we set refs.Refs[itemIndex].SeqMode that is used later
+ // don't move that code block
+
+ CUpdateItem &ui = updateItems[mtItemIndex++];
+ if (!ui.NewData)
+ continue;
+ CItemEx itemEx;
+ CItemOut item;
+
+ if (ui.NewProps)
+ {
+ if (ui.IsDir)
+ continue;
+ }
+ else
+ {
+ itemEx = inputItems[(unsigned)ui.IndexInArc];
+ if (inArchive->Read_LocalItem_After_CdItem_Full(itemEx) != S_OK)
+ return E_NOTIMPL;
+ (CItem &)item = itemEx;
+ if (item.IsDir() != ui.IsDir)
+ return E_NOTIMPL;
+ if (ui.IsDir)
+ continue;
+ }
+
+ CMyComPtr<ISequentialInStream> fileInStream;
+
+ CMemBlocks2 &memRef2 = refs.Refs[mtItemIndex - 1];
+
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(mtProgressMixerSpec->Mixer2->CriticalSection);
+ HRESULT res = updateCallback->GetStream(ui.IndexInClient, &fileInStream);
+ if (res == S_FALSE)
+ {
+ complexity += ui.Size;
+ complexity += kLocalHeaderSize;
+ mtProgressMixerSpec->Mixer2->SetProgressOffset_NoLock(complexity);
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK))
+ memRef2.Skip = true;
+ continue;
+ }
+ RINOK(res)
+ if (!fileInStream)
+ return E_INVALIDARG;
+ UpdatePropsFromStream(updateOptions, ui, fileInStream, updateCallback, totalComplexity);
+ RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK))
+ }
+
+ UInt32 k;
+ for (k = 0; k < numThreads; k++)
+ if (threads.Threads[k].IsFree)
+ break;
+
+ if (k == numThreads)
+ return E_FAIL;
+ {
+ {
+ CThreadInfo &threadInfo = threads.Threads[k];
+ threadInfo.IsFree = false;
+ threadInfo.InStream = fileInStream;
+
+ bool inSeqMode = false;
+
+ if (!inSeqMode)
+ {
+ CMyComPtr<IInStream> inStream2;
+ fileInStream->QueryInterface(IID_IInStream, (void **)&inStream2);
+ inSeqMode = (inStream2 == NULL);
+ }
+ memRef2.InSeqMode = inSeqMode;
+
+ // !!!!! we must release ref before sending event
+ // BUG was here in v4.43 and v4.44. It could change ref counter in two threads in same time
+ fileInStream.Release();
+
+ threadInfo.OutStreamSpec->Init();
+ threadInfo.ProgressSpec->Reinit();
+
+ threadInfo.UpdateIndex = mtItemIndex - 1;
+ threadInfo.InSeqMode = inSeqMode;
+ threadInfo.OutSeqMode = outSeqMode;
+ threadInfo.FileTime = ui.Time; // FileTime is used for ZipCrypto only in seqMode
+ threadInfo.ExpectedDataSize = ui.Size;
+ threadInfo.ExpectedDataSize_IsConfirmed = ui.Size_WasSetFromStream;
+
+ threadInfo.CompressEvent.Set();
+
+ threadIndices.Add(k);
+ }
+ }
+
+ continue;
+ }
+
+ if (refs.Refs[itemIndex].Skip)
+ {
+ itemIndex++;
+ continue;
+ }
+
+ const CUpdateItem &ui = updateItems[itemIndex];
+
+ CItemEx itemEx;
+ CItemOut item;
+
+ if (!ui.NewProps || !ui.NewData)
+ {
+ itemEx = inputItems[(unsigned)ui.IndexInArc];
+ if (inArchive->Read_LocalItem_After_CdItem_Full(itemEx) != S_OK)
+ return E_NOTIMPL;
+ (CItem &)item = itemEx;
+ }
+
+ if (ui.NewData)
+ {
+ // bool isDir = ((ui.NewProps) ? ui.IsDir : item.IsDir());
+ bool isDir = ui.IsDir;
+
+ if (isDir)
+ {
+ RINOK(WriteDirHeader(archive, &options, ui, item))
+ }
+ else
+ {
+ CMemBlocks2 &memRef = refs.Refs[itemIndex];
+
+ if (memRef.Finished)
+ {
+ if (lastRealStreamItemIndex < (int)itemIndex)
+ lastRealStreamItemIndex = (int)itemIndex;
+
+ SetFileHeader(options, ui, memRef.CompressingResult.DescriptorMode, item);
+
+ // the BUG was fixed in 9.26:
+ // SetItemInfoFromCompressingResult must be after SetFileHeader
+ // to write correct Size.
+
+ SetItemInfoFromCompressingResult(memRef.CompressingResult,
+ options.IsRealAesMode(), options.AesKeyMode, item);
+ RINOK(archive.ClearRestriction())
+ archive.WriteLocalHeader(item);
+ // RINOK(updateCallback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK));
+ CMyComPtr<ISequentialOutStream> outStream;
+ archive.CreateStreamForCopying(outStream);
+ memRef.WriteToStream(memManager.GetBlockSize(), outStream);
+ // v23: we fixed the bug: we need to write descriptor also
+ if (item.HasDescriptor())
+ {
+ /* that function doesn't rewrite local header, if item.HasDescriptor().
+ it just writes descriptor */
+ archive.WriteLocalHeader_Replace(item);
+ }
+ else
+ archive.MoveCurPos(item.PackSize);
+ memRef.FreeOpt(&memManager);
+ /*
+ if (reportArcProp)
+ {
+ stat.UpdateWithItem(item);
+ RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options.IsRealAesMode()));
+ }
+ */
+ }
+ else
+ {
+ // current file was not finished
+
+ if (lastRealStreamItemIndex < (int)itemIndex)
+ {
+ // LocalHeader was not written for current itemIndex still
+
+ lastRealStreamItemIndex = (int)itemIndex;
+
+ // thread was started before for that item already, and memRef.SeqMode was set
+
+ CCompressingResult compressingResult;
+ RINOK(compressor.Set_Pre_CompressionResult(
+ memRef.InSeqMode, outSeqMode,
+ ui.Size,
+ compressingResult))
+
+ memRef.PreDescriptorMode = compressingResult.DescriptorMode;
+ SetFileHeader(options, ui, compressingResult.DescriptorMode, item);
+
+ SetItemInfoFromCompressingResult(compressingResult, options.IsRealAesMode(), options.AesKeyMode, item);
+
+ // file Size can be 64-bit !!!
+ RINOK(archive.SetRestrictionFromCurrent())
+ archive.WriteLocalHeader(item);
+ }
+
+ {
+ CThreadInfo &thread = threads.Threads[threadIndices.Front()];
+ if (!thread.OutStreamSpec->WasUnlockEventSent())
+ {
+ CMyComPtr<IOutStream> outStream;
+ archive.CreateStreamForCompressing(outStream);
+ thread.OutStreamSpec->SetOutStream(outStream);
+ thread.OutStreamSpec->SetRealStreamMode();
+ }
+ }
+
+ WRes wres = mtSem.Semaphore.Lock();
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+
+ int ti = mtSem.GetFreeItem();
+ if (ti < 0)
+ return E_FAIL;
+
+ CThreadInfo &threadInfo = threads.Threads[(unsigned)ti];
+ threadInfo.InStream.Release();
+ threadInfo.IsFree = true;
+ RINOK(threadInfo.Result)
+
+ unsigned t = 0;
+
+ for (;;)
+ {
+ if (t == threadIndices.Size())
+ return E_FAIL;
+ if (threadIndices[t] == (unsigned)ti)
+ break;
+ t++;
+ }
+ threadIndices.Delete(t);
+
+ if (t == 0)
+ {
+ // if thread for current file was finished.
+ if (threadInfo.UpdateIndex != itemIndex)
+ return E_FAIL;
+
+ if (memRef.PreDescriptorMode != threadInfo.CompressingResult.DescriptorMode)
+ return E_FAIL;
+
+ RINOK(threadInfo.OutStreamSpec->WriteToRealStream())
+ threadInfo.OutStreamSpec->ReleaseOutStream();
+ SetFileHeader(options, ui, threadInfo.CompressingResult.DescriptorMode, item);
+ SetItemInfoFromCompressingResult(threadInfo.CompressingResult,
+ options.IsRealAesMode(), options.AesKeyMode, item);
+
+ archive.WriteLocalHeader_Replace(item);
+
+ /*
+ if (reportArcProp)
+ {
+ stat.UpdateWithItem(item);
+ RINOK(ReportProps(reportArcProp, ui.IndexInClient, item, options.IsRealAesMode()));
+ }
+ */
+ }
+ else
+ {
+ // it's not current file. So we must store information in array
+ CMemBlocks2 &memRef2 = refs.Refs[threadInfo.UpdateIndex];
+ threadInfo.OutStreamSpec->DetachData(memRef2);
+ memRef2.CompressingResult = threadInfo.CompressingResult;
+ // memRef2.SeqMode = threadInfo.SeqMode; // it was set before
+ memRef2.Finished = true;
+ continue;
+ }
+ }
+ }
+ }
+ else
+ {
+ RINOK(UpdateItemOldData(archive, inArchive, itemEx, ui, item, progress, opCallback, complexity))
+ }
+
+ items.Add(item);
+ complexity += kLocalHeaderSize;
+ mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
+ itemIndex++;
+ }
+
+ RINOK(mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL))
+
+ RINOK(archive.WriteCentralDir(items, comment))
+
+ /*
+ if (reportArcProp)
+ {
+ RINOK(ReportArcProps(reportArcProp, stat));
+ }
+ */
+
+ complexity += kCentralHeaderSize * updateItems.Size() + 1;
+ mtProgressMixerSpec->Mixer2->SetProgressOffset(complexity);
+ return mtCompressProgressMixer.SetRatioInfo(0, NULL, NULL);
+
+ #endif
+}
+
+/*
+// we need CSeekOutStream, if we need Seek(0, STREAM_SEEK_CUR) for seqential stream
+Z7_CLASS_IMP_COM_1(
+ CSeekOutStream
+ , IOutStream
+)
+ Z7_IFACE_COM7_IMP(ISequentialOutStream)
+
+ CMyComPtr<ISequentialOutStream> _seqStream;
+ UInt64 _size;
+public:
+ void Init(ISequentialOutStream *seqStream)
+ {
+ _size = 0;
+ _seqStream = seqStream;
+ }
+};
+
+Z7_COM7F_IMF(CSeekOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ UInt32 realProcessedSize;
+ const HRESULT result = _seqStream->Write(data, size, &realProcessedSize);
+ _size += realProcessedSize;
+ if (processedSize)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+Z7_COM7F_IMF(CSeekOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ if (seekOrigin != STREAM_SEEK_CUR || offset != 0)
+ return E_NOTIMPL;
+ if (newPosition)
+ *newPosition = (UInt64)_size;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CSeekOutStream::SetSize(UInt64 newSize))
+{
+ UNUSED_VAR(newSize)
+ return E_NOTIMPL;
+}
+*/
+
+static const size_t kCacheBlockSize = (1 << 20);
+static const size_t kCacheSize = (kCacheBlockSize << 2);
+static const size_t kCacheMask = (kCacheSize - 1);
+
+Z7_CLASS_IMP_NOQIB_2(
+ CCacheOutStream
+ , IOutStream
+ , IStreamSetRestriction
+)
+ Z7_IFACE_COM7_IMP(ISequentialOutStream)
+
+ CMyComPtr<IOutStream> _stream;
+ CMyComPtr<ISequentialOutStream> _seqStream;
+ Byte *_cache;
+ UInt64 _virtPos;
+ UInt64 _virtSize;
+ UInt64 _phyPos;
+ UInt64 _phySize; // <= _virtSize
+ UInt64 _cachedPos; // (_cachedPos + _cachedSize) <= _virtSize
+ size_t _cachedSize;
+ HRESULT _hres;
+
+ UInt64 _restrict_begin;
+ UInt64 _restrict_end;
+ UInt64 _restrict_phy; // begin
+ CMyComPtr<IStreamSetRestriction> _setRestriction;
+
+ HRESULT MyWrite(size_t size);
+ HRESULT MyWriteBlock()
+ {
+ return MyWrite(kCacheBlockSize - ((size_t)_cachedPos & (kCacheBlockSize - 1)));
+ }
+ HRESULT WriteNonRestrictedBlocks();
+ HRESULT FlushCache();
+public:
+ CCacheOutStream(): _cache(NULL) {}
+ ~CCacheOutStream();
+ bool Allocate();
+ HRESULT Init(ISequentialOutStream *seqStream, IOutStream *stream, IStreamSetRestriction *setRestriction);
+ HRESULT FinalFlush();
+};
+
+
+bool CCacheOutStream::Allocate()
+{
+ if (!_cache)
+ _cache = (Byte *)::MidAlloc(kCacheSize);
+ return (_cache != NULL);
+}
+
+HRESULT CCacheOutStream::Init(ISequentialOutStream *seqStream, IOutStream *stream, IStreamSetRestriction *setRestriction)
+{
+ _cachedPos = 0;
+ _cachedSize = 0;
+ _hres = S_OK;
+ _restrict_begin = 0;
+ _restrict_end = 0;
+ _restrict_phy = 0;
+ _virtPos = 0;
+ _virtSize = 0;
+ _seqStream = seqStream;
+ _stream = stream;
+ _setRestriction = setRestriction;
+ if (_stream)
+ {
+ RINOK(_stream->Seek(0, STREAM_SEEK_CUR, &_virtPos))
+ RINOK(_stream->Seek(0, STREAM_SEEK_END, &_virtSize))
+ RINOK(_stream->Seek((Int64)_virtPos, STREAM_SEEK_SET, &_virtPos))
+ }
+ _phyPos = _virtPos;
+ _phySize = _virtSize;
+ return S_OK;
+}
+
+
+/* it writes up to (size) bytes from cache.
+ (size > _cachedSize) is allowed */
+
+HRESULT CCacheOutStream::MyWrite(size_t size)
+{
+ PRF(printf("\n-- CCacheOutStream::MyWrite %u\n", (unsigned)size));
+ if (_hres != S_OK)
+ return _hres;
+ while (size != 0 && _cachedSize != 0)
+ {
+ if (_phyPos != _cachedPos)
+ {
+ if (!_stream)
+ return E_FAIL;
+ _hres = _stream->Seek((Int64)_cachedPos, STREAM_SEEK_SET, &_phyPos);
+ RINOK(_hres)
+ if (_phyPos != _cachedPos)
+ {
+ _hres = E_FAIL;
+ return _hres;
+ }
+ }
+ const size_t pos = (size_t)_cachedPos & kCacheMask;
+ size_t curSize = kCacheSize - pos;
+ curSize = MyMin(curSize, _cachedSize);
+ curSize = MyMin(curSize, size);
+ _hres = WriteStream(_seqStream, _cache + pos, curSize);
+ RINOK(_hres)
+ _phyPos += curSize;
+ if (_phySize < _phyPos)
+ _phySize = _phyPos;
+ _cachedPos += curSize;
+ _cachedSize -= curSize;
+ size -= curSize;
+ }
+
+ if (_setRestriction)
+ if (_restrict_begin == _restrict_end || _cachedPos <= _restrict_begin)
+ if (_restrict_phy < _cachedPos)
+ {
+ _restrict_phy = _cachedPos;
+ return _setRestriction->SetRestriction(_cachedPos, (UInt64)(Int64)-1);
+ }
+ return S_OK;
+}
+
+
+HRESULT CCacheOutStream::WriteNonRestrictedBlocks()
+{
+ for (;;)
+ {
+ const size_t size = kCacheBlockSize - ((size_t)_cachedPos & (kCacheBlockSize - 1));
+ if (_cachedSize < size)
+ break;
+ if (_restrict_begin != _restrict_end && _cachedPos + size > _restrict_begin)
+ break;
+ RINOK(MyWrite(size))
+ }
+ return S_OK;
+}
+
+
+HRESULT CCacheOutStream::FlushCache()
+{
+ return MyWrite(_cachedSize);
+}
+
+HRESULT CCacheOutStream::FinalFlush()
+{
+ _restrict_begin = 0;
+ _restrict_end = 0;
+ RINOK(FlushCache())
+ if (_stream && _hres == S_OK)
+ {
+ if (_virtSize != _phySize)
+ {
+ // it's unexpected
+ RINOK(_stream->SetSize(_virtSize))
+ }
+ if (_virtPos != _phyPos)
+ {
+ RINOK(_stream->Seek((Int64)_virtPos, STREAM_SEEK_SET, NULL))
+ }
+ }
+ return S_OK;
+}
+
+
+CCacheOutStream::~CCacheOutStream()
+{
+ ::MidFree(_cache);
+}
+
+
+Z7_COM7F_IMF(CCacheOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ PRF(printf("\n-- CCacheOutStream::Write %u\n", (unsigned)size));
+
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ if (_hres != S_OK)
+ return _hres;
+
+ if (_cachedSize != 0)
+ if (_virtPos < _cachedPos ||
+ _virtPos > _cachedPos + _cachedSize)
+ {
+ RINOK(FlushCache())
+ }
+
+ // ---------- Writing data to cache ----------
+
+ if (_cachedSize == 0)
+ _cachedPos = _virtPos;
+
+ const size_t pos = (size_t)_virtPos & kCacheMask;
+ size = (UInt32)MyMin((size_t)size, kCacheSize - pos);
+ const UInt64 cachedEnd = _cachedPos + _cachedSize;
+
+ // (_virtPos >= _cachedPos) (_virtPos <= cachedEnd)
+
+ if (_virtPos != cachedEnd)
+ {
+ // _virtPos < cachedEnd
+ // we rewrite only existing data in cache. So _cachedSize will be not changed
+ size = (UInt32)MyMin((size_t)size, (size_t)(cachedEnd - _virtPos));
+ }
+ else
+ {
+ // _virtPos == cachedEnd
+ // so we need to add new data to the end of cache
+ if (_cachedSize == kCacheSize)
+ {
+ // cache is full. So we flush part of cache
+ RINOK(MyWriteBlock())
+ }
+ // _cachedSize != kCacheSize
+ // so we have some space for new data in cache
+ const size_t startPos = (size_t)_cachedPos & kCacheMask;
+ // we don't allow new data to overwrite old start data in cache.
+ if (startPos > pos)
+ size = (UInt32)MyMin((size_t)size, (size_t)(startPos - pos));
+ _cachedSize += size;
+ }
+
+ memcpy(_cache + pos, data, size);
+ if (processedSize)
+ *processedSize = size;
+ _virtPos += size;
+ if (_virtSize < _virtPos)
+ _virtSize = _virtPos;
+ return WriteNonRestrictedBlocks();
+}
+
+
+Z7_COM7F_IMF(CCacheOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ PRF(printf("\n-- CCacheOutStream::Seek seekOrigin=%d Seek =%u\n", seekOrigin, (unsigned)offset));
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += _virtSize; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _virtPos = (UInt64)offset;
+ if (newPosition)
+ *newPosition = (UInt64)offset;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CCacheOutStream::SetSize(UInt64 newSize))
+{
+ if (_hres != S_OK)
+ return _hres;
+ _virtSize = newSize;
+
+ if (newSize <= _cachedPos)
+ {
+ _cachedSize = 0;
+ _cachedPos = newSize;
+ }
+ else
+ {
+ // newSize > _cachedPos
+ const UInt64 offset = newSize - _cachedPos;
+ if (offset <= _cachedSize)
+ {
+ _cachedSize = (size_t)offset;
+ if (_phySize <= newSize)
+ return S_OK;
+ }
+ else
+ {
+ // newSize > _cachedPos + _cachedSize
+ // So we flush cache
+ RINOK(FlushCache())
+ }
+ }
+
+ if (newSize != _phySize)
+ {
+ if (!_stream)
+ return E_NOTIMPL;
+ _hres = _stream->SetSize(newSize);
+ RINOK(_hres)
+ _phySize = newSize;
+ }
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CCacheOutStream::SetRestriction(UInt64 begin, UInt64 end))
+{
+ PRF(printf("\n============ CCacheOutStream::SetRestriction %u, %u\n", (unsigned)begin, (unsigned)end));
+ _restrict_begin = begin;
+ _restrict_end = end;
+ return WriteNonRestrictedBlocks();
+}
+
+
+
+HRESULT Update(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const CObjectVector<CItemEx> &inputItems,
+ CObjectVector<CUpdateItem> &updateItems,
+ ISequentialOutStream *seqOutStream,
+ CInArchive *inArchive, bool removeSfx,
+ const CUpdateOptions &updateOptions,
+ const CCompressionMethodMode &compressionMethodMode,
+ IArchiveUpdateCallback *updateCallback)
+{
+ /*
+ // it was tested before
+ if (inArchive)
+ {
+ if (!inArchive->CanUpdate())
+ return E_NOTIMPL;
+ }
+ */
+
+ CMyComPtr<IStreamSetRestriction> setRestriction;
+ seqOutStream->QueryInterface(IID_IStreamSetRestriction, (void **)&setRestriction);
+ if (setRestriction)
+ {
+ RINOK(setRestriction->SetRestriction(0, 0))
+ }
+
+ CMyComPtr<IOutStream> outStream;
+ CCacheOutStream *cacheStream;
+ bool outSeqMode;
+
+ {
+ CMyComPtr<IOutStream> outStreamReal;
+
+ if (!compressionMethodMode.Force_SeqOutMode)
+ {
+ seqOutStream->QueryInterface(IID_IOutStream, (void **)&outStreamReal);
+ /*
+ if (!outStreamReal)
+ return E_NOTIMPL;
+ */
+ }
+
+ if (inArchive)
+ {
+ if (!inArchive->IsMultiVol && inArchive->ArcInfo.Base > 0 && !removeSfx)
+ {
+ IInStream *baseStream = inArchive->GetBaseStream();
+ RINOK(InStream_SeekToBegin(baseStream))
+ RINOK(NCompress::CopyStream_ExactSize(baseStream, seqOutStream, (UInt64)inArchive->ArcInfo.Base, NULL))
+ }
+ }
+
+ // bool use_cacheStream = true;
+ // if (use_cacheStream)
+ {
+ cacheStream = new CCacheOutStream();
+ outStream = cacheStream;
+ if (!cacheStream->Allocate())
+ return E_OUTOFMEMORY;
+ RINOK(cacheStream->Init(seqOutStream, outStreamReal, setRestriction))
+ setRestriction.Release();
+ setRestriction = cacheStream;
+ }
+ /*
+ else if (!outStreamReal)
+ {
+ CSeekOutStream *seekOutStream = new CSeekOutStream();
+ outStream = seekOutStream;
+ seekOutStream->Init(seqOutStream);
+ }
+ else
+ outStream = outStreamReal;
+ */
+ outSeqMode = (outStreamReal == NULL);
+ }
+
+ COutArchive outArchive;
+ outArchive.SetRestriction = setRestriction;
+
+ RINOK(outArchive.Create(outStream))
+
+ if (inArchive)
+ {
+ if (!inArchive->IsMultiVol && (Int64)inArchive->ArcInfo.MarkerPos2 > inArchive->ArcInfo.Base)
+ {
+ IInStream *baseStream = inArchive->GetBaseStream();
+ RINOK(InStream_SeekSet(baseStream, (UInt64)inArchive->ArcInfo.Base))
+ const UInt64 embStubSize = (UInt64)((Int64)inArchive->ArcInfo.MarkerPos2 - inArchive->ArcInfo.Base);
+ RINOK(NCompress::CopyStream_ExactSize(baseStream, outStream, embStubSize, NULL))
+ outArchive.MoveCurPos(embStubSize);
+ }
+ }
+
+ RINOK (Update2(
+ EXTERNAL_CODECS_LOC_VARS
+ outArchive, inArchive,
+ inputItems, updateItems,
+ updateOptions,
+ compressionMethodMode, outSeqMode,
+ inArchive ? &inArchive->ArcInfo.Comment : NULL,
+ updateCallback))
+
+ return cacheStream->FinalFlush();
+}
+
+}}
diff --git a/CPP/7zip/Archive/Zip/ZipUpdate.h b/CPP/7zip/Archive/Zip/ZipUpdate.h
new file mode 100644
index 0000000..13ecd9c
--- /dev/null
+++ b/CPP/7zip/Archive/Zip/ZipUpdate.h
@@ -0,0 +1,107 @@
+// ZipUpdate.h
+
+#ifndef ZIP7_INC_ZIP_UPDATE_H
+#define ZIP7_INC_ZIP_UPDATE_H
+
+#include "../../ICoder.h"
+#include "../IArchive.h"
+
+#include "../../Common/CreateCoder.h"
+
+#include "ZipCompressionMode.h"
+#include "ZipIn.h"
+
+namespace NArchive {
+namespace NZip {
+
+/*
+struct CUpdateRange
+{
+ UInt64 Position;
+ UInt64 Size;
+
+ // CUpdateRange() {}
+ CUpdateRange(UInt64 position, UInt64 size): Position(position), Size(size) {}
+};
+*/
+
+struct CUpdateItem
+{
+ bool NewData;
+ bool NewProps;
+ bool IsDir;
+ bool Write_NtfsTime;
+ bool Write_UnixTime;
+ // bool Write_UnixTime_ATime;
+ bool IsUtf8;
+ bool Size_WasSetFromStream;
+ // bool IsAltStream;
+ int IndexInArc;
+ unsigned IndexInClient;
+ UInt32 Attrib;
+ UInt32 Time;
+ UInt64 Size;
+ AString Name;
+ CByteBuffer Name_Utf; // for Info-Zip (kIzUnicodeName) Extra
+ CByteBuffer Comment;
+ // bool Commented;
+ // CUpdateRange CommentRange;
+ FILETIME Ntfs_MTime;
+ FILETIME Ntfs_ATime;
+ FILETIME Ntfs_CTime;
+
+ void Clear()
+ {
+ IsDir = false;
+
+ Write_NtfsTime = false;
+ Write_UnixTime = false;
+
+ IsUtf8 = false;
+ Size_WasSetFromStream = false;
+ // IsAltStream = false;
+ Time = 0;
+ Size = 0;
+ Name.Empty();
+ Name_Utf.Free();
+ Comment.Free();
+
+ FILETIME_Clear(Ntfs_MTime);
+ FILETIME_Clear(Ntfs_ATime);
+ FILETIME_Clear(Ntfs_CTime);
+ }
+
+ CUpdateItem():
+ IsDir(false),
+ Write_NtfsTime(false),
+ Write_UnixTime(false),
+ IsUtf8(false),
+ Size_WasSetFromStream(false),
+ // IsAltStream(false),
+ Time(0),
+ Size(0)
+ {}
+};
+
+
+struct CUpdateOptions
+{
+ bool Write_MTime;
+ bool Write_ATime;
+ bool Write_CTime;
+};
+
+
+HRESULT Update(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const CObjectVector<CItemEx> &inputItems,
+ CObjectVector<CUpdateItem> &updateItems,
+ ISequentialOutStream *seqOutStream,
+ CInArchive *inArchive, bool removeSfx,
+ const CUpdateOptions &updateOptions,
+ const CCompressionMethodMode &compressionMethodMode,
+ IArchiveUpdateCallback *updateCallback);
+
+}}
+
+#endif
diff --git a/CPP/7zip/Archive/makefile b/CPP/7zip/Archive/makefile
new file mode 100644
index 0000000..7512ad5
--- /dev/null
+++ b/CPP/7zip/Archive/makefile
@@ -0,0 +1,23 @@
+DIRS = \
+ 7z\~ \
+ Arj\~ \
+ BZip2\~ \
+ Cab\~ \
+ Chm\~ \
+ Cpio\~ \
+ Deb\~ \
+ GZip\~ \
+ Iso\~ \
+ Lzh\~ \
+ Nsis\~ \
+ Rar\~ \
+ RPM\~ \
+ Split\~ \
+ Tar\~ \
+ Z\~ \
+ Zip\~ \
+
+all: $(DIRS)
+
+$(DIRS):
+!include "../SubBuild.mak"
diff --git a/CPP/7zip/Asm.mak b/CPP/7zip/Asm.mak
index 3ad238a..c4073e8 100644
--- a/CPP/7zip/Asm.mak
+++ b/CPP/7zip/Asm.mak
@@ -1,9 +1,9 @@
-!IFDEF ASM_OBJS
-!IF "$(CPU)" == "ARM"
-$(ASM_OBJS): ../../../../Asm/Arm/$(*B).asm
- $(COMPL_ASM)
-!ELSEIF "$(CPU)" != "IA64" && "$(CPU)" != "MIPS" && "$(CPU)" != "ARM64"
-$(ASM_OBJS): ../../../../Asm/x86/$(*B).asm
- $(COMPL_ASM)
-!ENDIF
-!ENDIF
+!IFDEF ASM_OBJS
+!IF "$(CPU)" == "ARM"
+$(ASM_OBJS): ../../../../Asm/Arm/$(*B).asm
+ $(COMPL_ASM)
+!ELSEIF "$(CPU)" != "IA64" && "$(CPU)" != "MIPS" && "$(CPU)" != "ARM64"
+$(ASM_OBJS): ../../../../Asm/x86/$(*B).asm
+ $(COMPL_ASM)
+!ENDIF
+!ENDIF
diff --git a/CPP/7zip/Bundles/Alone/Alone.dsp b/CPP/7zip/Bundles/Alone/Alone.dsp
new file mode 100644
index 0000000..65c81c4
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone/Alone.dsp
@@ -0,0 +1,3234 @@
+# Microsoft Developer Studio Project File - Name="Alone" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=Alone - Win32 DebugU
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "Alone.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "Alone.mak" CFG="Alone - Win32 DebugU"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Alone - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "Alone - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "Alone - Win32 ReleaseU" (based on "Win32 (x86) Console Application")
+!MESSAGE "Alone - Win32 DebugU" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /Gr /MT /W4 /WX /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /FAcs /Yu"StdAfx.h" /FD /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7za.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /Gz /MDd /W4 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c
+# SUBTRACT CPP /WX
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7za.exe" /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ReleaseU"
+# PROP BASE Intermediate_Dir "ReleaseU"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "ReleaseU"
+# PROP Intermediate_Dir "ReleaseU"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /Yu"StdAfx.h" /FD /c
+# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "UNICODE" /D "_UNICODE" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7za.exe" /opt:NOWIN98
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7zan.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "DebugU"
+# PROP BASE Intermediate_Dir "DebugU"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "DebugU"
+# PROP Intermediate_Dir "DebugU"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c
+# ADD CPP /nologo /Gz /MDd /W4 /WX /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7za.exe" /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7zan.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "Alone - Win32 Release"
+# Name "Alone - Win32 Debug"
+# Name "Alone - Win32 ReleaseU"
+# Name "Alone - Win32 DebugU"
+# Begin Group "Console"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ArError.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\BenchCon.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\BenchCon.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\CompressionMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ConsoleClose.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ConsoleClose.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ExtractCallbackConsole.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ExtractCallbackConsole.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\HashCon.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\HashCon.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\List.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\List.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\Main.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\MainAr.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\OpenCallbackConsole.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\OpenCallbackConsole.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\PercentPrinter.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\PercentPrinter.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\UpdateCallbackConsole.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\UpdateCallbackConsole.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\UserInputUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\UserInputUtils.h
+# End Source File
+# End Group
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"StdAfx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\AutoPtr.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Buffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Common.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ComTry.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CrcReg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynamicBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynLimBuf.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynLimBuf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ListFileUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ListFileUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\LzFindPrepare.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyBuffer2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyCom.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyException.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyGuidDef.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyInitGuid.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyLinux.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyUnknown.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Sha1Prepare.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Sha1Reg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Sha256Prepare.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Sha256Reg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdInStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdInStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdOutStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\XzCrc64Init.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\XzCrc64Reg.cpp
+# End Source File
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Device.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileLink.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileMapping.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileSystem.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileSystem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Handle.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryLock.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryLock.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\NtCheck.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Registry.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Registry.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\SecurityUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\SystemInfo.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\SystemInfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Thread.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\TimeUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\TimeUtils.h
+# End Source File
+# End Group
+# Begin Group "7zip Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CWrappers.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CWrappers.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InOutTempBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InOutTempBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LockedStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LockedStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MemBlocks.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MemBlocks.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodId.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodId.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MultiOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MultiOutStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OffsetStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OffsetStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutMemStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutMemStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressMt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\PropId.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\RegisterArc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\RegisterCodec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamBinder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamBinder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\UniqBlocks.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\UniqBlocks.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\VirtThread.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\VirtThread.h
+# End Source File
+# End Group
+# Begin Group "Compress"
+
+# PROP Default_Filter ""
+# Begin Group "BZip2"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\BZip2Const.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BZip2Crc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BZip2Crc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BZip2Decoder.cpp
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BZip2Decoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BZip2Encoder.cpp
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BZip2Encoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BZip2Register.cpp
+# End Source File
+# End Group
+# Begin Group "Copy"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyRegister.cpp
+# End Source File
+# End Group
+# Begin Group "Deflate"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\Deflate64Register.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\DeflateConst.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\DeflateDecoder.cpp
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\DeflateDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\DeflateEncoder.cpp
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\DeflateEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\DeflateRegister.cpp
+# End Source File
+# End Group
+# Begin Group "Huffman"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\HuffmanDecoder.h
+# End Source File
+# End Group
+# Begin Group "Implode"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\ImplodeDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\ImplodeDecoder.h
+# End Source File
+# End Group
+# Begin Group "LZMA"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Decoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Decoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Encoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Encoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Register.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaDecoder.cpp
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaEncoder.cpp
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaRegister.cpp
+# End Source File
+# End Group
+# Begin Group "PPMd"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdDecoder.cpp
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdEncoder.cpp
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdZip.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdZip.h
+# End Source File
+# End Group
+# Begin Group "RangeCoder"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\RangeCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\RangeCoderBit.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\RangeCoderBitTree.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\RangeCoderOpt.h
+# End Source File
+# End Group
+# Begin Group "Shrink"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\ShrinkDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\ShrinkDecoder.h
+# End Source File
+# End Group
+# Begin Group "BWT"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\Mtf8.h
+# End Source File
+# End Group
+# Begin Group "LZX"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzx.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzxDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzxDecoder.h
+# End Source File
+# End Group
+# Begin Group "Quantum"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\QuantumDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\QuantumDecoder.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\Compress\Bcj2Coder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Bcj2Coder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Bcj2Register.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BcjCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BcjCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BcjRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BitlDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BitlDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BitlEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BitmDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BitmEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchMisc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchMisc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\ByteSwap.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\ByteSwap.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\DeltaFilter.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzOutWindow.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzOutWindow.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\XzDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\XzDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\XzEncoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\XzEncoder.h
+# End Source File
+# End Group
+# Begin Group "Archive"
+
+# PROP Default_Filter ""
+# Begin Group "7z"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zCompressionMode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zCompressionMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zDecode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zEncode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zEncode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zExtract.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zFolderInStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zFolderInStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandlerOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHeader.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zOut.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zProperties.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zSpecStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zSpecStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zUpdate.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zUpdate.h
+# End Source File
+# End Group
+# Begin Group "tar"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarHandlerOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarHeader.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarOut.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarUpdate.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarUpdate.h
+# End Source File
+# End Group
+# Begin Group "zip"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipAddCommon.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipAddCommon.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipCompressionMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipHandlerOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipItem.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipOut.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipUpdate.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipUpdate.h
+# End Source File
+# End Group
+# Begin Group "Archive Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderLoader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\DummyOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\DummyOutStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\FindSignature.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\FindSignature.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\HandlerOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\HandlerOut.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\InStreamWithCRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\InStreamWithCRC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\MultiStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\MultiStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ParseProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ParseProperties.h
+# End Source File
+# End Group
+# Begin Group "cab"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabBlockInStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabBlockInStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabHeader.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabRegister.cpp
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\Archive\Bz2Handler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\DeflateProps.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\DeflateProps.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\GzHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\IArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\LzmaHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\SplitHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\XzHandler.cpp
+# End Source File
+# End Group
+# Begin Group "UI Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveCommandLine.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveCommandLine.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveOpenCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Bench.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Bench.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\DefaultName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\DefaultName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\DirItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\EnumDirItems.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\EnumDirItems.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExitCode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Extract.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Extract.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExtractingFilePath.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExtractingFilePath.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExtractMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\HashCalc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\HashCalc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\IFileExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\LoadCodecs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\LoadCodecs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\OpenArchive.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\OpenArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Property.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\PropIDUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\PropIDUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\SetProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\SetProperties.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\SortUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\SortUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\TempFiles.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\TempFiles.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Update.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Update.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateAction.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateAction.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdatePair.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdatePair.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateProduce.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateProduce.h
+# End Source File
+# End Group
+# Begin Group "Crypto"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Crypto\7zAes.cpp
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\7zAes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\7zAesRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\HmacSha1.cpp
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\HmacSha1.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\MyAes.cpp
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\MyAes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\MyAesReg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\Pbkdf2HmacSha1.cpp
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\Pbkdf2HmacSha1.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\RandGen.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\RandGen.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\Sha1Cls.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\WzAes.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\WzAes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\ZipCrypto.cpp
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O1
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O1
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\ZipCrypto.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\ZipStrong.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\ZipStrong.h
+# End Source File
+# End Group
+# Begin Group "7-zip"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\ICoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IDecl.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IMyUnknown.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IPassword.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IProgress.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\MyVersion.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\PropID.h
+# End Source File
+# End Group
+# Begin Group "C"
+
+# PROP Default_Filter ""
+# Begin Group "Xz"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Xz.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Xz.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzCrc64.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzCrc64.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzCrc64Opt.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzDec.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzEnc.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzEnc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzIn.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrcOpt.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zStream.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zVersion.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Aes.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Aes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\AesOpt.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bcj2.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bcj2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bcj2Enc.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra86.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\BraIA64.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\BwtSort.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\BwtSort.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Delta.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Delta.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\DllSecur.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\DllSecur.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\HuffEnc.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\HuffEnc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\IStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFind.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFindMt.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFindMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFindOpt.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzHash.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Dec.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Dec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2DecMt.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2DecMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Enc.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Enc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaDec.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaDec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaEnc.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaEnc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtCoder.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtDec.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtDec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd7.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd7.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd7Dec.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd7Enc.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd8.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd8.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd8Dec.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd8Enc.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\RotateDefs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha1.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha1.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha1Opt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha256.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha256.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha256Opt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sort.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sort.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\SwapBytes.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\SwapBytes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/CPP/7zip/Bundles/Alone/Alone.dsw b/CPP/7zip/Bundles/Alone/Alone.dsw
new file mode 100644
index 0000000..65eca43
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone/Alone.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "Alone"=.\Alone.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/Bundles/Alone/StdAfx.cpp b/CPP/7zip/Bundles/Alone/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/Alone/StdAfx.h b/CPP/7zip/Bundles/Alone/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone/StdAfx.h
@@ -0,0 +1,11 @@
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Bundles/Alone/afxres.h b/CPP/7zip/Bundles/Alone/afxres.h
new file mode 100644
index 0000000..c2fadd4
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone/afxres.h
@@ -0,0 +1 @@
+#include <winresrc.h>
diff --git a/CPP/7zip/Bundles/Alone/makefile b/CPP/7zip/Bundles/Alone/makefile
new file mode 100644
index 0000000..bad953a
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone/makefile
@@ -0,0 +1,230 @@
+PROG = 7za.exe
+# USE_C_AES = 1
+# USE_C_SHA = 1
+# USE_C_LZFINDOPT = 1
+
+COMMON_OBJS = \
+ $O\CommandLineParser.obj \
+ $O\CRC.obj \
+ $O\CrcReg.obj \
+ $O\DynLimBuf.obj \
+ $O\IntToString.obj \
+ $O\ListFileUtils.obj \
+ $O\LzFindPrepare.obj \
+ $O\NewHandler.obj \
+ $O\StdInStream.obj \
+ $O\StdOutStream.obj \
+ $O\MyString.obj \
+ $O\StringConvert.obj \
+ $O\StringToInt.obj \
+ $O\UTFConvert.obj \
+ $O\MyVector.obj \
+ $O\Wildcard.obj \
+ $O\XzCrc64Init.obj \
+ $O\XzCrc64Reg.obj \
+ $O\Sha1Reg.obj \
+ $O\Sha256Reg.obj \
+
+WIN_OBJS = \
+ $O\DLL.obj \
+ $O\ErrorMsg.obj \
+ $O\FileDir.obj \
+ $O\FileFind.obj \
+ $O\FileIO.obj \
+ $O\FileLink.obj \
+ $O\FileName.obj \
+ $O\FileSystem.obj \
+ $O\MemoryLock.obj \
+ $O\PropVariant.obj \
+ $O\PropVariantConv.obj \
+ $O\PropVariantUtils.obj \
+ $O\Registry.obj \
+ $O\Synchronization.obj \
+ $O\System.obj \
+ $O\SystemInfo.obj \
+ $O\TimeUtils.obj \
+
+7ZIP_COMMON_OBJS = \
+ $O\CreateCoder.obj \
+ $O\CWrappers.obj \
+ $O\FilePathAutoRename.obj \
+ $O\FileStreams.obj \
+ $O\FilterCoder.obj \
+ $O\InBuffer.obj \
+ $O\InOutTempBuffer.obj \
+ $O\LimitedStreams.obj \
+ $O\MemBlocks.obj \
+ $O\MethodId.obj \
+ $O\MethodProps.obj \
+ $O\MultiOutStream.obj \
+ $O\OffsetStream.obj \
+ $O\OutBuffer.obj \
+ $O\OutMemStream.obj \
+ $O\ProgressMt.obj \
+ $O\ProgressUtils.obj \
+ $O\PropId.obj \
+ $O\StreamBinder.obj \
+ $O\StreamObjects.obj \
+ $O\StreamUtils.obj \
+ $O\UniqBlocks.obj \
+ $O\VirtThread.obj \
+
+AR_OBJS = \
+ $O\Bz2Handler.obj \
+ $O\DeflateProps.obj \
+ $O\GzHandler.obj \
+ $O\LzmaHandler.obj \
+ $O\SplitHandler.obj \
+ $O\XzHandler.obj \
+
+AR_COMMON_OBJS = \
+ $O\CoderMixer2.obj \
+ $O\DummyOutStream.obj \
+ $O\FindSignature.obj \
+ $O\HandlerOut.obj \
+ $O\InStreamWithCRC.obj \
+ $O\ItemNameUtils.obj \
+ $O\MultiStream.obj \
+ $O\OutStreamWithCRC.obj \
+ $O\ParseProperties.obj \
+
+
+7Z_OBJS = \
+ $O\7zCompressionMode.obj \
+ $O\7zDecode.obj \
+ $O\7zEncode.obj \
+ $O\7zExtract.obj \
+ $O\7zFolderInStream.obj \
+ $O\7zHandler.obj \
+ $O\7zHandlerOut.obj \
+ $O\7zHeader.obj \
+ $O\7zIn.obj \
+ $O\7zOut.obj \
+ $O\7zProperties.obj \
+ $O\7zSpecStream.obj \
+ $O\7zUpdate.obj \
+ $O\7zRegister.obj \
+
+CAB_OBJS = \
+ $O\CabBlockInStream.obj \
+ $O\CabHandler.obj \
+ $O\CabHeader.obj \
+ $O\CabIn.obj \
+ $O\CabRegister.obj \
+
+TAR_OBJS = \
+ $O\TarHandler.obj \
+ $O\TarHandlerOut.obj \
+ $O\TarHeader.obj \
+ $O\TarIn.obj \
+ $O\TarOut.obj \
+ $O\TarUpdate.obj \
+ $O\TarRegister.obj \
+
+ZIP_OBJS = \
+ $O\ZipAddCommon.obj \
+ $O\ZipHandler.obj \
+ $O\ZipHandlerOut.obj \
+ $O\ZipIn.obj \
+ $O\ZipItem.obj \
+ $O\ZipOut.obj \
+ $O\ZipUpdate.obj \
+ $O\ZipRegister.obj \
+
+
+COMPRESS_OBJS = \
+ $O\Bcj2Coder.obj \
+ $O\Bcj2Register.obj \
+ $O\BcjCoder.obj \
+ $O\BcjRegister.obj \
+ $O\BitlDecoder.obj \
+ $O\BranchMisc.obj \
+ $O\BranchRegister.obj \
+ $O\ByteSwap.obj \
+ $O\BZip2Crc.obj \
+ $O\BZip2Decoder.obj \
+ $O\BZip2Encoder.obj \
+ $O\BZip2Register.obj \
+ $O\CopyCoder.obj \
+ $O\CopyRegister.obj \
+ $O\Deflate64Register.obj \
+ $O\DeflateDecoder.obj \
+ $O\DeflateEncoder.obj \
+ $O\DeflateRegister.obj \
+ $O\DeltaFilter.obj \
+ $O\ImplodeDecoder.obj \
+ $O\Lzma2Decoder.obj \
+ $O\Lzma2Encoder.obj \
+ $O\Lzma2Register.obj \
+ $O\LzmaDecoder.obj \
+ $O\LzmaEncoder.obj \
+ $O\LzmaRegister.obj \
+ $O\LzOutWindow.obj \
+ $O\LzxDecoder.obj \
+ $O\PpmdDecoder.obj \
+ $O\PpmdEncoder.obj \
+ $O\PpmdRegister.obj \
+ $O\PpmdZip.obj \
+ $O\QuantumDecoder.obj \
+ $O\ShrinkDecoder.obj \
+ $O\XzDecoder.obj \
+ $O\XzEncoder.obj \
+
+CRYPTO_OBJS = \
+ $O\7zAes.obj \
+ $O\7zAesRegister.obj \
+ $O\HmacSha1.obj \
+ $O\MyAes.obj \
+ $O\MyAesReg.obj \
+ $O\Pbkdf2HmacSha1.obj \
+ $O\RandGen.obj \
+ $O\WzAes.obj \
+ $O\ZipCrypto.obj \
+ $O\ZipStrong.obj \
+
+C_OBJS = \
+ $O\7zStream.obj \
+ $O\Alloc.obj \
+ $O\Bcj2.obj \
+ $O\Bcj2Enc.obj \
+ $O\Bra.obj \
+ $O\Bra86.obj \
+ $O\BraIA64.obj \
+ $O\BwtSort.obj \
+ $O\CpuArch.obj \
+ $O\Delta.obj \
+ $O\HuffEnc.obj \
+ $O\LzFind.obj \
+ $O\LzFindMt.obj \
+ $O\Lzma2Dec.obj \
+ $O\Lzma2DecMt.obj \
+ $O\Lzma2Enc.obj \
+ $O\LzmaDec.obj \
+ $O\LzmaEnc.obj \
+ $O\MtCoder.obj \
+ $O\MtDec.obj \
+ $O\Ppmd7.obj \
+ $O\Ppmd7Dec.obj \
+ $O\Ppmd7Enc.obj \
+ $O\Ppmd8.obj \
+ $O\Ppmd8Dec.obj \
+ $O\Ppmd8Enc.obj \
+ $O\Sort.obj \
+ $O\SwapBytes.obj \
+ $O\Threads.obj \
+ $O\Xz.obj \
+ $O\XzDec.obj \
+ $O\XzEnc.obj \
+ $O\XzIn.obj \
+
+!include "../../UI/Console/Console.mak"
+
+!include "../../Aes.mak"
+!include "../../Crc.mak"
+!include "../../Crc64.mak"
+!include "../../LzFindOpt.mak"
+!include "../../LzmaDec.mak"
+!include "../../Sha1.mak"
+!include "../../Sha256.mak"
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/Bundles/Alone/makefile.gcc b/CPP/7zip/Bundles/Alone/makefile.gcc
new file mode 100644
index 0000000..cb7e828
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone/makefile.gcc
@@ -0,0 +1,348 @@
+PROG = 7za
+
+
+
+# IS_X64 = 1
+# USE_ASM = 1
+# ST_MODE = 1
+
+include ../../LzmaDec_gcc.mak
+
+
+LOCAL_FLAGS_ST =
+MT_OBJS =
+
+
+ifdef SystemDrive
+IS_MINGW = 1
+else
+ifdef SYSTEMDRIVE
+# ifdef OS
+IS_MINGW = 1
+endif
+endif
+
+ifdef ST_MODE
+
+LOCAL_FLAGS_ST = -DZ7_ST
+
+ifdef IS_MINGW
+MT_OBJS = \
+ $O/Threads.o \
+
+endif
+
+else
+
+MT_OBJS = \
+ $O/LzFindMt.o \
+ $O/StreamBinder.o \
+ $O/Synchronization.o \
+ $O/VirtThread.o \
+ $O/MemBlocks.o \
+ $O/OutMemStream.o \
+ $O/ProgressMt.o \
+ $O/Threads.o \
+
+endif
+
+
+
+LOCAL_FLAGS_SYS =
+
+ifdef IS_MINGW
+
+LOCAL_FLAGS_SYS = \
+ -DZ7_LARGE_PAGES \
+ -DZ7_LONG_PATH \
+ -DZ7_DEVICE_FILE \
+
+SYS_OBJS = \
+ $O/FileSystem.o \
+ $O/Registry.o \
+ $O/MemoryLock.o \
+ $O/DLL.o \
+ $O/DllSecur.o \
+ $O/resource.o \
+
+else
+
+SYS_OBJS = \
+ $O/MyWindows.o \
+
+endif
+
+LOCAL_FLAGS = \
+ $(LOCAL_FLAGS_ST) \
+ $(LOCAL_FLAGS_SYS) \
+
+
+
+CONSOLE_OBJS = \
+ $O/BenchCon.o \
+ $O/ConsoleClose.o \
+ $O/ExtractCallbackConsole.o \
+ $O/HashCon.o \
+ $O/List.o \
+ $O/Main.o \
+ $O/MainAr.o \
+ $O/OpenCallbackConsole.o \
+ $O/PercentPrinter.o \
+ $O/UpdateCallbackConsole.o \
+ $O/UserInputUtils.o \
+
+UI_COMMON_OBJS = \
+ $O/ArchiveCommandLine.o \
+ $O/ArchiveExtractCallback.o \
+ $O/ArchiveOpenCallback.o \
+ $O/Bench.o \
+ $O/DefaultName.o \
+ $O/EnumDirItems.o \
+ $O/Extract.o \
+ $O/ExtractingFilePath.o \
+ $O/HashCalc.o \
+ $O/LoadCodecs.o \
+ $O/OpenArchive.o \
+ $O/PropIDUtils.o \
+ $O/SetProperties.o \
+ $O/SortUtils.o \
+ $O/TempFiles.o \
+ $O/Update.o \
+ $O/UpdateAction.o \
+ $O/UpdateCallback.o \
+ $O/UpdatePair.o \
+ $O/UpdateProduce.o \
+
+COMMON_OBJS = \
+ $O/CommandLineParser.o \
+ $O/CRC.o \
+ $O/CrcReg.o \
+ $O/DynLimBuf.o \
+ $O/IntToString.o \
+ $O/ListFileUtils.o \
+ $O/LzFindPrepare.o \
+ $O/MyString.o \
+ $O/NewHandler.o \
+ $O/StdInStream.o \
+ $O/StdOutStream.o \
+ $O/Sha1Prepare.o \
+ $O/Sha1Reg.o \
+ $O/Sha256Prepare.o \
+ $O/Sha256Reg.o \
+ $O/StringConvert.o \
+ $O/StringToInt.o \
+ $O/UTFConvert.o \
+ $O/MyVector.o \
+ $O/Wildcard.o \
+ $O/XzCrc64Init.o \
+ $O/XzCrc64Reg.o \
+
+
+WIN_OBJS = \
+ $O/ErrorMsg.o \
+ $O/FileDir.o \
+ $O/FileFind.o \
+ $O/FileIO.o \
+ $O/FileLink.o \
+ $O/FileName.o \
+ $O/PropVariant.o \
+ $O/PropVariantConv.o \
+ $O/PropVariantUtils.o \
+ $O/System.o \
+ $O/SystemInfo.o \
+ $O/TimeUtils.o \
+
+
+7ZIP_COMMON_OBJS = \
+ $O/CreateCoder.o \
+ $O/CWrappers.o \
+ $O/FilePathAutoRename.o \
+ $O/FileStreams.o \
+ $O/InBuffer.o \
+ $O/InOutTempBuffer.o \
+ $O/FilterCoder.o \
+ $O/LimitedStreams.o \
+ $O/MethodId.o \
+ $O/MethodProps.o \
+ $O/MultiOutStream.o \
+ $O/OffsetStream.o \
+ $O/OutBuffer.o \
+ $O/ProgressUtils.o \
+ $O/PropId.o \
+ $O/StreamObjects.o \
+ $O/StreamUtils.o \
+ $O/UniqBlocks.o \
+
+AR_OBJS = \
+ $O/Bz2Handler.o \
+ $O/GzHandler.o \
+ $O/LzmaHandler.o \
+ $O/SplitHandler.o \
+ $O/XzHandler.o \
+
+AR_COMMON_OBJS = \
+ $O/CoderMixer2.o \
+ $O/DummyOutStream.o \
+ $O/HandlerOut.o \
+ $O/InStreamWithCRC.o \
+ $O/ItemNameUtils.o \
+ $O/MultiStream.o \
+ $O/OutStreamWithCRC.o \
+ $O/ParseProperties.o \
+
+7Z_OBJS = \
+ $O/7zCompressionMode.o \
+ $O/7zDecode.o \
+ $O/7zEncode.o \
+ $O/7zExtract.o \
+ $O/7zFolderInStream.o \
+ $O/7zHandler.o \
+ $O/7zHandlerOut.o \
+ $O/7zHeader.o \
+ $O/7zIn.o \
+ $O/7zOut.o \
+ $O/7zProperties.o \
+ $O/7zRegister.o \
+ $O/7zSpecStream.o \
+ $O/7zUpdate.o \
+
+CAB_OBJS = \
+ $O/CabBlockInStream.o \
+ $O/CabHandler.o \
+ $O/CabHeader.o \
+ $O/CabIn.o \
+ $O/CabRegister.o \
+
+TAR_OBJS = \
+ $O/TarHandler.o \
+ $O/TarHandlerOut.o \
+ $O/TarHeader.o \
+ $O/TarIn.o \
+ $O/TarOut.o \
+ $O/TarUpdate.o \
+ $O/TarRegister.o \
+
+ZIP_OBJS = \
+ $O/ZipAddCommon.o \
+ $O/ZipHandler.o \
+ $O/ZipHandlerOut.o \
+ $O/ZipIn.o \
+ $O/ZipItem.o \
+ $O/ZipOut.o \
+ $O/ZipUpdate.o \
+ $O/ZipRegister.o \
+
+COMPRESS_OBJS = \
+ $O/Bcj2Coder.o \
+ $O/Bcj2Register.o \
+ $O/BcjCoder.o \
+ $O/BcjRegister.o \
+ $O/BitlDecoder.o \
+ $O/BranchMisc.o \
+ $O/BranchRegister.o \
+ $O/ByteSwap.o \
+ $O/BZip2Crc.o \
+ $O/BZip2Decoder.o \
+ $O/BZip2Encoder.o \
+ $O/BZip2Register.o \
+ $O/CopyCoder.o \
+ $O/CopyRegister.o \
+ $O/Deflate64Register.o \
+ $O/DeflateDecoder.o \
+ $O/DeflateEncoder.o \
+ $O/DeflateRegister.o \
+ $O/DeltaFilter.o \
+ $O/ImplodeDecoder.o \
+ $O/Lzma2Decoder.o \
+ $O/Lzma2Encoder.o \
+ $O/Lzma2Register.o \
+ $O/LzmaDecoder.o \
+ $O/LzmaEncoder.o \
+ $O/LzmaRegister.o \
+ $O/LzOutWindow.o \
+ $O/LzxDecoder.o \
+ $O/PpmdDecoder.o \
+ $O/PpmdEncoder.o \
+ $O/PpmdRegister.o \
+ $O/PpmdZip.o \
+ $O/QuantumDecoder.o \
+ $O/ShrinkDecoder.o \
+ $O/XzDecoder.o \
+ $O/XzEncoder.o \
+
+CRYPTO_OBJS = \
+ $O/7zAes.o \
+ $O/7zAesRegister.o \
+ $O/HmacSha1.o \
+ $O/MyAes.o \
+ $O/MyAesReg.o \
+ $O/Pbkdf2HmacSha1.o \
+ $O/RandGen.o \
+ $O/WzAes.o \
+ $O/ZipCrypto.o \
+ $O/ZipStrong.o \
+
+C_OBJS = \
+ $O/7zStream.o \
+ $O/Alloc.o \
+ $O/Bcj2.o \
+ $O/Bcj2Enc.o \
+ $O/Bra.o \
+ $O/Bra86.o \
+ $O/BraIA64.o \
+ $O/BwtSort.o \
+ $O/CpuArch.o \
+ $O/Delta.o \
+ $O/HuffEnc.o \
+ $O/LzFind.o \
+ $O/LzFindOpt.o \
+ $O/Lzma2Dec.o \
+ $O/Lzma2DecMt.o \
+ $O/Lzma2Enc.o \
+ $O/LzmaDec.o \
+ $O/LzmaEnc.o \
+ $O/MtCoder.o \
+ $O/MtDec.o \
+ $O/Ppmd7.o \
+ $O/Ppmd7Dec.o \
+ $O/Ppmd7Enc.o \
+ $O/Ppmd8.o \
+ $O/Ppmd8Dec.o \
+ $O/Ppmd8Enc.o \
+ $O/Sort.o \
+ $O/SwapBytes.o \
+ $O/Xz.o \
+ $O/XzDec.o \
+ $O/XzEnc.o \
+ $O/XzIn.o \
+ $O/XzCrc64.o \
+ $O/XzCrc64Opt.o \
+ $O/7zCrc.o \
+ $O/7zCrcOpt.o \
+ $O/Aes.o \
+ $O/AesOpt.o \
+ $O/Sha256.o \
+ $O/Sha256Opt.o \
+ $O/Sha1.o \
+ $O/Sha1Opt.o \
+
+OBJS = \
+ $(LZMA_DEC_OPT_OBJS) \
+ $(C_OBJS) \
+ $(MT_OBJS) \
+ $(SYS_OBJS) \
+ $(COMMON_OBJS) \
+ $(WIN_OBJS) \
+ $(COMPRESS_OBJS) \
+ $(CRYPTO_OBJS) \
+ $(7ZIP_COMMON_OBJS) \
+ $(AR_OBJS) \
+ $(AR_COMMON_OBJS) \
+ $(7Z_OBJS) \
+ $(CAB_OBJS) \
+ $(TAR_OBJS) \
+ $(ZIP_OBJS) \
+ $(UI_COMMON_OBJS) \
+ $(CONSOLE_OBJS) \
+
+include ../../7zip_gcc.mak
diff --git a/CPP/7zip/Bundles/Alone/resource.rc b/CPP/7zip/Bundles/Alone/resource.rc
new file mode 100644
index 0000000..c85acaa
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone/resource.rc
@@ -0,0 +1,7 @@
+#include "../../MyVersionInfo.rc"
+
+MY_VERSION_INFO_APP("7-Zip Standalone Console", "7za")
+
+#ifndef UNDER_CE
+1 24 MOVEABLE PURE "../../UI/Console/Console.manifest"
+#endif
diff --git a/CPP/7zip/Bundles/Alone2/StdAfx.cpp b/CPP/7zip/Bundles/Alone2/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone2/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/Alone2/StdAfx.h b/CPP/7zip/Bundles/Alone2/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone2/StdAfx.h
@@ -0,0 +1,11 @@
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Bundles/Alone2/makefile b/CPP/7zip/Bundles/Alone2/makefile
new file mode 100644
index 0000000..4cb7718
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone2/makefile
@@ -0,0 +1,29 @@
+PROG = 7zz.exe
+# USE_C_AES = 1
+# USE_C_SHA = 1
+CFLAGS = $(CFLAGS) -DZ7_PROG_VARIANT_Z
+
+!include "../Format7zF/Arc.mak"
+!include "../../UI/Console/Console.mak"
+
+COMMON_OBJS = $(COMMON_OBJS) \
+ $O\CommandLineParser.obj \
+ $O\ListFileUtils.obj \
+ $O\StdInStream.obj \
+ $O\StdOutStream.obj \
+
+WIN_OBJS = $(WIN_OBJS) \
+ $O\DLL.obj \
+ $O\ErrorMsg.obj \
+ $O\FileLink.obj \
+ $O\FileSystem.obj \
+ $O\MemoryLock.obj \
+ $O\Registry.obj \
+ $O\SystemInfo.obj \
+
+7ZIP_COMMON_OBJS = $(7ZIP_COMMON_OBJS) \
+ $O\FilePathAutoRename.obj \
+ $O\FileStreams.obj \
+ $O\MultiOutStream.obj \
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/Bundles/Alone2/makefile.gcc b/CPP/7zip/Bundles/Alone2/makefile.gcc
new file mode 100644
index 0000000..f767b0d
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone2/makefile.gcc
@@ -0,0 +1,109 @@
+PROG = 7zz
+
+# IS_X64 = 1
+# USE_ASM = 1
+# ST_MODE = 1
+
+CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_Z
+
+include ../Format7zF/Arc_gcc.mak
+
+ifdef SystemDrive
+IS_MINGW = 1
+else
+ifdef SYSTEMDRIVE
+# ifdef OS
+IS_MINGW = 1
+endif
+endif
+
+ifdef IS_MINGW
+
+LOCAL_FLAGS_SYS = \
+ -DZ7_LARGE_PAGES \
+ -DZ7_LONG_PATH \
+ -DZ7_DEVICE_FILE \
+
+SYS_OBJS = \
+ $O/FileSystem.o \
+ $O/Registry.o \
+ $O/MemoryLock.o \
+ $O/DLL.o \
+ $O/DllSecur.o \
+ $O/resource.o \
+
+else
+
+SYS_OBJS = \
+ $O/MyWindows.o \
+
+endif
+
+
+LOCAL_FLAGS = \
+ $(LOCAL_FLAGS_SYS) \
+ $(LOCAL_FLAGS_ST) \
+
+
+UI_COMMON_OBJS = \
+ $O/ArchiveCommandLine.o \
+ $O/ArchiveExtractCallback.o \
+ $O/ArchiveOpenCallback.o \
+ $O/Bench.o \
+ $O/DefaultName.o \
+ $O/EnumDirItems.o \
+ $O/Extract.o \
+ $O/ExtractingFilePath.o \
+ $O/HashCalc.o \
+ $O/LoadCodecs.o \
+ $O/OpenArchive.o \
+ $O/PropIDUtils.o \
+ $O/SetProperties.o \
+ $O/SortUtils.o \
+ $O/TempFiles.o \
+ $O/Update.o \
+ $O/UpdateAction.o \
+ $O/UpdateCallback.o \
+ $O/UpdatePair.o \
+ $O/UpdateProduce.o \
+
+
+CONSOLE_OBJS = \
+ $O/BenchCon.o \
+ $O/ConsoleClose.o \
+ $O/ExtractCallbackConsole.o \
+ $O/HashCon.o \
+ $O/List.o \
+ $O/Main.o \
+ $O/MainAr.o \
+ $O/OpenCallbackConsole.o \
+ $O/PercentPrinter.o \
+ $O/UpdateCallbackConsole.o \
+ $O/UserInputUtils.o \
+
+COMMON_OBJS_2 = \
+ $O/CommandLineParser.o \
+ $O/ListFileUtils.o \
+ $O/StdInStream.o \
+ $O/StdOutStream.o \
+
+WIN_OBJS_2 = \
+ $O/ErrorMsg.o \
+ $O/FileLink.o \
+ $O/SystemInfo.o \
+
+7ZIP_COMMON_OBJS_2 = \
+ $O/FilePathAutoRename.o \
+ $O/FileStreams.o \
+ $O/MultiOutStream.o \
+
+OBJS = \
+ $(ARC_OBJS) \
+ $(SYS_OBJS) \
+ $(COMMON_OBJS_2) \
+ $(WIN_OBJS_2) \
+ $(7ZIP_COMMON_OBJS_2) \
+ $(UI_COMMON_OBJS) \
+ $(CONSOLE_OBJS) \
+
+include ../../7zip_gcc.mak
diff --git a/CPP/7zip/Bundles/Alone2/resource.rc b/CPP/7zip/Bundles/Alone2/resource.rc
new file mode 100644
index 0000000..af24c17
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone2/resource.rc
@@ -0,0 +1,7 @@
+#include "../../MyVersionInfo.rc"
+
+MY_VERSION_INFO_APP("7-Zip Standalone 2 Console", "7zz")
+
+#ifndef UNDER_CE
+1 24 MOVEABLE PURE "../../UI/Console/Console.manifest"
+#endif
diff --git a/CPP/7zip/Bundles/Alone7z/Alone.dsp b/CPP/7zip/Bundles/Alone7z/Alone.dsp
index e12207d..ef4ec60 100644
--- a/CPP/7zip/Bundles/Alone7z/Alone.dsp
+++ b/CPP/7zip/Bundles/Alone7z/Alone.dsp
@@ -1,1910 +1,2043 @@
-# Microsoft Developer Studio Project File - Name="Alone" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Console Application" 0x0103
-
-CFG=Alone - Win32 DebugU
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "Alone.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "Alone.mak" CFG="Alone - Win32 DebugU"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "Alone - Win32 Release" (based on "Win32 (x86) Console Application")
-!MESSAGE "Alone - Win32 Debug" (based on "Win32 (x86) Console Application")
-!MESSAGE "Alone - Win32 ReleaseU" (based on "Win32 (x86) Console Application")
-!MESSAGE "Alone - Win32 DebugU" (based on "Win32 (x86) Console Application")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /Gr /MT /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "_7ZIP_LARGE_PAGES" /D "SUPPORT_DEVICE_FILE" /FAc /Yu"StdAfx.h" /FD /c
-# ADD BASE RSC /l 0x419 /d "NDEBUG"
-# ADD RSC /l 0x419 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7zr.exe" /opt:NOWIN98
-# SUBTRACT LINK32 /pdb:none
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
-# ADD CPP /nologo /Gr /MDd /W3 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "_7ZIP_LARGE_PAGES" /D "SUPPORT_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c
-# ADD BASE RSC /l 0x419 /d "_DEBUG"
-# ADD RSC /l 0x419 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7zr.exe" /pdbtype:sept
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "ReleaseU"
-# PROP BASE Intermediate_Dir "ReleaseU"
-# PROP BASE Ignore_Export_Lib 0
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "ReleaseU"
-# PROP Intermediate_Dir "ReleaseU"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "EXCLUDE_COM" /D "NO_REGISTRY" /Yu"StdAfx.h" /FD /c
-# ADD CPP /nologo /Gr /MD /W4 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "UNICODE" /D "_UNICODE" /D "WIN32" /D "_CONSOLE" /D "_7ZIP_LARGE_PAGES" /D "SUPPORT_DEVICE_FILE" /Yu"StdAfx.h" /FD /c
-# ADD BASE RSC /l 0x419 /d "NDEBUG"
-# ADD RSC /l 0x419 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7za.exe" /opt:NOWIN98
-# SUBTRACT BASE LINK32 /pdb:none
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7zr.exe" /opt:NOWIN98
-# SUBTRACT LINK32 /pdb:none
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "DebugU"
-# PROP BASE Intermediate_Dir "DebugU"
-# PROP BASE Ignore_Export_Lib 0
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "DebugU"
-# PROP Intermediate_Dir "DebugU"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "EXCLUDE_COM" /D "NO_REGISTRY" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c
-# ADD CPP /nologo /Gr /MDd /W4 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_CONSOLE" /D "_7ZIP_LARGE_PAGES" /D "SUPPORT_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c
-# ADD BASE RSC /l 0x419 /d "_DEBUG"
-# ADD RSC /l 0x419 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7za.exe" /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7zr.exe" /pdbtype:sept
-
-!ENDIF
-
-# Begin Target
-
-# Name "Alone - Win32 Release"
-# Name "Alone - Win32 Debug"
-# Name "Alone - Win32 ReleaseU"
-# Name "Alone - Win32 DebugU"
-# Begin Group "Console"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\UI\Console\ArError.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\BenchCon.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\BenchCon.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\CompressionMode.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\ConsoleClose.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\ConsoleClose.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\ExtractCallbackConsole.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\ExtractCallbackConsole.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\HashCon.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\HashCon.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\List.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\List.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\Main.cpp
-# ADD CPP /D "PROG_VARIANT_R"
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\MainAr.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\OpenCallbackConsole.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\OpenCallbackConsole.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\PercentPrinter.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\PercentPrinter.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\UpdateCallbackConsole.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\UpdateCallbackConsole.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\UserInputUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\UserInputUtils.h
-# End Source File
-# End Group
-# Begin Group "Spec"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=.\resource.rc
-# End Source File
-# Begin Source File
-
-SOURCE=.\StdAfx.cpp
-# ADD CPP /Yc"StdAfx.h"
-# End Source File
-# Begin Source File
-
-SOURCE=.\StdAfx.h
-# End Source File
-# End Group
-# Begin Group "Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\Common\AutoPtr.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\Buffer.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\CommandLineParser.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\CommandLineParser.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\ComTry.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\CRC.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\CrcReg.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\Defs.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\DynamicBuffer.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\IntToString.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\IntToString.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\ListFileUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\ListFileUtils.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyCom.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyException.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyGuidDef.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyInitGuid.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyString.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyString.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyUnknown.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyVector.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyVector.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\NewHandler.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\NewHandler.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\Sha256Reg.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StdInStream.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StdInStream.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StdOutStream.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StdOutStream.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StringConvert.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StringConvert.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StringToInt.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StringToInt.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\Types.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\UTFConvert.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\UTFConvert.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\Wildcard.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\Wildcard.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\XzCrc64Init.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\XzCrc64Reg.cpp
-# End Source File
-# End Group
-# Begin Group "Windows"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Defs.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Device.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\DLL.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\DLL.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\ErrorMsg.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\ErrorMsg.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileDir.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileDir.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileFind.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileFind.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileIO.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileIO.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileLink.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileMapping.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileName.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileName.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileSystem.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileSystem.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Handle.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\MemoryLock.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\MemoryLock.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariant.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariant.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariantConv.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariantConv.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Synchronization.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Synchronization.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\System.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\System.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Thread.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\TimeUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\TimeUtils.h
-# End Source File
-# End Group
-# Begin Group "7zip Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Common\CreateCoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\CreateCoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\CWrappers.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\CWrappers.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FilePathAutoRename.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FilePathAutoRename.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FileStreams.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FileStreams.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FilterCoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FilterCoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\InBuffer.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\InBuffer.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\InOutTempBuffer.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\InOutTempBuffer.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\LimitedStreams.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\LimitedStreams.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\LockedStream.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\LockedStream.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\MethodId.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\MethodId.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\MethodProps.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\MethodProps.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\OffsetStream.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\OffsetStream.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\OutBuffer.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\OutBuffer.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\ProgressUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\ProgressUtils.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\PropId.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\RegisterArc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\RegisterCodec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamBinder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamBinder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamObjects.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamObjects.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamUtils.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\UniqBlocks.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\UniqBlocks.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\VirtThread.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\VirtThread.h
-# End Source File
-# End Group
-# Begin Group "Compress"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Compress\Bcj2Coder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\Bcj2Coder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\Bcj2Register.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BcjCoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BcjCoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BcjRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BranchMisc.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BranchMisc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BranchRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\ByteSwap.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\ByteSwap.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\CopyCoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\CopyCoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\CopyRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\DeltaFilter.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\Lzma2Decoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\Lzma2Decoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\Lzma2Encoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\Lzma2Encoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\Lzma2Register.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\LzmaDecoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\LzmaDecoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\LzmaEncoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\LzmaEncoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\LzmaRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\XzDecoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\XzDecoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\XzEncoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\XzEncoder.h
-# End Source File
-# End Group
-# Begin Group "Archive"
-
-# PROP Default_Filter ""
-# Begin Group "7z"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zCompressionMode.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zCompressionMode.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zDecode.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zDecode.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zEncode.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zEncode.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zExtract.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zFolderInStream.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zFolderInStream.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zHandler.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zHandler.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zHandlerOut.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zHeader.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zHeader.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zIn.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zIn.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zItem.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zOut.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zOut.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zProperties.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zProperties.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zSpecStream.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zSpecStream.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zUpdate.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zUpdate.h
-# End Source File
-# End Group
-# Begin Group "Archive Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\CoderMixer2.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\CoderMixer2.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\DummyOutStream.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\DummyOutStream.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\HandlerOut.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\HandlerOut.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\InStreamWithCRC.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\InStreamWithCRC.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\ItemNameUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\ItemNameUtils.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\MultiStream.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\MultiStream.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\OutStreamWithCRC.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\ParseProperties.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\ParseProperties.h
-# End Source File
-# End Group
-# Begin Source File
-
-SOURCE=..\..\Archive\IArchive.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\LzmaHandler.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\SplitHandler.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\XzHandler.cpp
-# End Source File
-# End Group
-# Begin Group "UI Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ArchiveCommandLine.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ArchiveCommandLine.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ArchiveExtractCallback.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ArchiveOpenCallback.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\Bench.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\Bench.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\DefaultName.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\DefaultName.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\EnumDirItems.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\EnumDirItems.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\Extract.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\Extract.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ExtractingFilePath.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ExtractingFilePath.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\HashCalc.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\HashCalc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\LoadCodecs.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\LoadCodecs.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\OpenArchive.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\OpenArchive.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\Property.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\PropIDUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\PropIDUtils.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\SetProperties.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\SetProperties.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\SortUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\SortUtils.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\TempFiles.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\TempFiles.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\Update.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\Update.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\UpdateAction.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\UpdateAction.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\UpdateCallback.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\UpdateCallback.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\UpdatePair.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\UpdatePair.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\UpdateProduce.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\UpdateProduce.h
-# End Source File
-# End Group
-# Begin Group "7-zip"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\ICoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\IMyUnknown.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\IPassword.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\IProgress.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\IStream.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\PropID.h
-# End Source File
-# End Group
-# Begin Group "C"
-
-# PROP Default_Filter ""
-# Begin Group "Xz"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Sha256.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Sha256.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Xz.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Xz.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\XzCrc64.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\XzCrc64.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\XzCrc64Opt.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\XzDec.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\XzEnc.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\XzEnc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\XzIn.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# End Group
-# Begin Source File
-
-SOURCE=..\..\..\..\C\7zCrc.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\7zCrc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\7zCrcOpt.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\7zStream.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Aes.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Aes.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\AesOpt.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Alloc.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Alloc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bcj2.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bcj2.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bcj2Enc.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bra.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bra.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bra86.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\BraIA64.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\CpuArch.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\CpuArch.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Delta.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Delta.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\DllSecur.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\DllSecur.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\IStream.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzFind.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzFind.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzFindMt.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzFindMt.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Compress\Lz\LzHash.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzHash.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma2Dec.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma2Dec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma2DecMt.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma2DecMt.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma2Enc.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma2Enc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzmaDec.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzmaDec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzmaEnc.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzmaEnc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\MtCoder.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\MtCoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\MtDec.c
-
-!IF "$(CFG)" == "Alone - Win32 Release"
-
-# ADD CPP /O2
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
-
-# SUBTRACT CPP /YX /Yc /Yu
-
-!ENDIF
-
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\MtDec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Threads.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Threads.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Types.h
-# End Source File
-# End Group
-# Begin Group "Crypto"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Crypto\7zAes.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Crypto\7zAes.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Crypto\7zAesRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Crypto\MyAes.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Crypto\MyAes.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Crypto\RandGen.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Crypto\RandGen.h
-# End Source File
-# End Group
-# End Target
-# End Project
+# Microsoft Developer Studio Project File - Name="Alone" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=Alone - Win32 DebugU
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "Alone.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "Alone.mak" CFG="Alone - Win32 DebugU"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Alone - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "Alone - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "Alone - Win32 ReleaseU" (based on "Win32 (x86) Console Application")
+!MESSAGE "Alone - Win32 DebugU" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /Gr /MT /W4 /WX /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /FAcs /Yu"StdAfx.h" /FD /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7zr.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /Gr /MDd /W4 /WX /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7zr.exe" /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ReleaseU"
+# PROP BASE Intermediate_Dir "ReleaseU"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "ReleaseU"
+# PROP Intermediate_Dir "ReleaseU"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /Yu"StdAfx.h" /FD /c
+# ADD CPP /nologo /Gr /MD /W4 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "UNICODE" /D "_UNICODE" /D "WIN32" /D "_CONSOLE" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7za.exe" /opt:NOWIN98
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"c:\UTIL\7zr.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "DebugU"
+# PROP BASE Intermediate_Dir "DebugU"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "DebugU"
+# PROP Intermediate_Dir "DebugU"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c
+# ADD CPP /nologo /Gr /MDd /W4 /Gm /GX /ZI /Od /I "..\..\..\\" /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_CONSOLE" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7za.exe" /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"c:\UTIL\7zr.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "Alone - Win32 Release"
+# Name "Alone - Win32 Debug"
+# Name "Alone - Win32 ReleaseU"
+# Name "Alone - Win32 DebugU"
+# Begin Group "Console"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\Console\BenchCon.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\BenchCon.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\CompressionMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ConsoleClose.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ConsoleClose.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ExtractCallbackConsole.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ExtractCallbackConsole.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\HashCon.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\HashCon.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\List.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\List.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\Main.cpp
+# ADD CPP /D "PROG_VARIANT_R"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\MainAr.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\OpenCallbackConsole.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\OpenCallbackConsole.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\PercentPrinter.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\PercentPrinter.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\UpdateCallbackConsole.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\UpdateCallbackConsole.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\UserInputUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\UserInputUtils.h
+# End Source File
+# End Group
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"StdAfx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\AutoPtr.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Buffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Common.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ComTry.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CrcReg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynamicBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynLimBuf.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynLimBuf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ListFileUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ListFileUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\LzFindPrepare.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyBuffer2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyCom.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyException.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyGuidDef.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyInitGuid.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyUnknown.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyWindows.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Sha256Prepare.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Sha256Reg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdInStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdInStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdOutStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Types.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\XzCrc64Init.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\XzCrc64Reg.cpp
+# End Source File
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Device.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileLink.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileMapping.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileSystem.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileSystem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Handle.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryLock.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryLock.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\NtCheck.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Registry.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Registry.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\SystemInfo.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\SystemInfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Thread.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\TimeUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\TimeUtils.h
+# End Source File
+# End Group
+# Begin Group "7zip Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CWrappers.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CWrappers.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InOutTempBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InOutTempBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LockedStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LockedStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodId.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodId.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MultiOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MultiOutStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OffsetStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OffsetStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\PropId.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\RegisterArc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\RegisterCodec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamBinder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamBinder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\UniqBlocks.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\UniqBlocks.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\VirtThread.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\VirtThread.h
+# End Source File
+# End Group
+# Begin Group "Compress"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\Bcj2Coder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Bcj2Coder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Bcj2Register.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BcjCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BcjCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BcjRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchMisc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchMisc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\ByteSwap.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\DeltaFilter.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Decoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Decoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Encoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Encoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Register.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaEncoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\XzDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\XzDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\XzEncoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\XzEncoder.h
+# End Source File
+# End Group
+# Begin Group "Archive"
+
+# PROP Default_Filter ""
+# Begin Group "7z"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zCompressionMode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zCompressionMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zDecode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zEncode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zEncode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zExtract.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zFolderInStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zFolderInStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandlerOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHeader.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zOut.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zProperties.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zSpecStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zSpecStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zUpdate.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zUpdate.h
+# End Source File
+# End Group
+# Begin Group "Archive Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\DummyOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\DummyOutStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\HandlerOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\HandlerOut.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\InStreamWithCRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\InStreamWithCRC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\MultiStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\MultiStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ParseProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ParseProperties.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\Archive\IArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\LzmaHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\SplitHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\XzHandler.cpp
+# End Source File
+# End Group
+# Begin Group "UI Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveCommandLine.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveCommandLine.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveOpenCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Bench.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Bench.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\DefaultName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\DefaultName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\EnumDirItems.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\EnumDirItems.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExitCode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Extract.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Extract.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExtractingFilePath.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExtractingFilePath.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\HashCalc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\HashCalc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\LoadCodecs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\LoadCodecs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\OpenArchive.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\OpenArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Property.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\PropIDUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\PropIDUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\SetProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\SetProperties.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\SortUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\SortUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\TempFiles.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\TempFiles.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Update.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Update.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateAction.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateAction.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdatePair.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdatePair.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateProduce.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateProduce.h
+# End Source File
+# End Group
+# Begin Group "7-zip"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\ICoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IDecl.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IPassword.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IProgress.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\PropID.h
+# End Source File
+# End Group
+# Begin Group "C"
+
+# PROP Default_Filter ""
+# Begin Group "Xz"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Xz.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Xz.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzCrc64.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzCrc64.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzCrc64Opt.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzDec.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzEnc.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzEnc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzIn.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrcOpt.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zStream.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Aes.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Aes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\AesOpt.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bcj2.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bcj2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bcj2Enc.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra86.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\BraIA64.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Delta.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Delta.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\DllSecur.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\DllSecur.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\IStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFind.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFindMt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFindMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFindOpt.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compress\Lz\LzHash.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzHash.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Dec.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Dec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2DecMt.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2DecMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Enc.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Enc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaDec.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaDec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaEnc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaEnc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtCoder.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtDec.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtDec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\RotateDefs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha256.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha256.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha256Opt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\SwapBytes.c
+
+!IF "$(CFG)" == "Alone - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Alone - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\SwapBytes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.h
+# End Source File
+# End Group
+# Begin Group "Crypto"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Crypto\7zAes.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\7zAes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\7zAesRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\MyAes.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\MyAes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\MyAesReg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\RandGen.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\RandGen.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/CPP/7zip/Bundles/Alone7z/Alone.dsw b/CPP/7zip/Bundles/Alone7z/Alone.dsw
index 036aab4..65eca43 100644
--- a/CPP/7zip/Bundles/Alone7z/Alone.dsw
+++ b/CPP/7zip/Bundles/Alone7z/Alone.dsw
@@ -1,29 +1,29 @@
-Microsoft Developer Studio Workspace File, Format Version 6.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "Alone"=.\Alone.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
-
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "Alone"=.\Alone.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/Bundles/Alone7z/StdAfx.cpp b/CPP/7zip/Bundles/Alone7z/StdAfx.cpp
index c6d3b1f..d0feea8 100644
--- a/CPP/7zip/Bundles/Alone7z/StdAfx.cpp
+++ b/CPP/7zip/Bundles/Alone7z/StdAfx.cpp
@@ -1,3 +1,3 @@
-// StdAfx.cpp
-
-#include "StdAfx.h"
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/Alone7z/StdAfx.h b/CPP/7zip/Bundles/Alone7z/StdAfx.h
index 59d9ac1..035267c 100644
--- a/CPP/7zip/Bundles/Alone7z/StdAfx.h
+++ b/CPP/7zip/Bundles/Alone7z/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "../../../Common/Common.h"
-
-#endif
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Bundles/Alone7z/makefile b/CPP/7zip/Bundles/Alone7z/makefile
index 4f23c10..1f857c5 100644
--- a/CPP/7zip/Bundles/Alone7z/makefile
+++ b/CPP/7zip/Bundles/Alone7z/makefile
@@ -1,154 +1,163 @@
-PROG = 7zr.exe
-CFLAGS = $(CFLAGS) \
- -DPROG_VARIANT_R \
-
-COMMON_OBJS = \
- $O\CommandLineParser.obj \
- $O\CRC.obj \
- $O\CrcReg.obj \
- $O\IntToString.obj \
- $O\ListFileUtils.obj \
- $O\NewHandler.obj \
- $O\StdInStream.obj \
- $O\StdOutStream.obj \
- $O\MyString.obj \
- $O\Sha256Reg.obj \
- $O\StringConvert.obj \
- $O\StringToInt.obj \
- $O\UTFConvert.obj \
- $O\MyVector.obj \
- $O\Wildcard.obj \
- $O\XzCrc64Init.obj \
- $O\XzCrc64Reg.obj \
-
-WIN_OBJS = \
- $O\DLL.obj \
- $O\ErrorMsg.obj \
- $O\FileDir.obj \
- $O\FileFind.obj \
- $O\FileIO.obj \
- $O\FileLink.obj \
- $O\FileName.obj \
- $O\FileSystem.obj \
- $O\MemoryLock.obj \
- $O\PropVariant.obj \
- $O\PropVariantConv.obj \
- $O\Synchronization.obj \
- $O\System.obj \
- $O\TimeUtils.obj \
-
-7ZIP_COMMON_OBJS = \
- $O\CreateCoder.obj \
- $O\CWrappers.obj \
- $O\FilePathAutoRename.obj \
- $O\FileStreams.obj \
- $O\InBuffer.obj \
- $O\InOutTempBuffer.obj \
- $O\FilterCoder.obj \
- $O\LimitedStreams.obj \
- $O\MethodId.obj \
- $O\MethodProps.obj \
- $O\OffsetStream.obj \
- $O\OutBuffer.obj \
- $O\ProgressUtils.obj \
- $O\PropId.obj \
- $O\StreamBinder.obj \
- $O\StreamObjects.obj \
- $O\StreamUtils.obj \
- $O\UniqBlocks.obj \
- $O\VirtThread.obj \
-
-AR_OBJS = \
- $O\LzmaHandler.obj \
- $O\SplitHandler.obj \
- $O\XzHandler.obj \
-
-AR_COMMON_OBJS = \
- $O\CoderMixer2.obj \
- $O\DummyOutStream.obj \
- $O\HandlerOut.obj \
- $O\InStreamWithCRC.obj \
- $O\ItemNameUtils.obj \
- $O\MultiStream.obj \
- $O\OutStreamWithCRC.obj \
- $O\ParseProperties.obj \
-
-
-7Z_OBJS = \
- $O\7zCompressionMode.obj \
- $O\7zDecode.obj \
- $O\7zEncode.obj \
- $O\7zExtract.obj \
- $O\7zFolderInStream.obj \
- $O\7zHandler.obj \
- $O\7zHandlerOut.obj \
- $O\7zHeader.obj \
- $O\7zIn.obj \
- $O\7zOut.obj \
- $O\7zProperties.obj \
- $O\7zRegister.obj \
- $O\7zSpecStream.obj \
- $O\7zUpdate.obj \
-
-COMPRESS_OBJS = \
- $O\Bcj2Coder.obj \
- $O\Bcj2Register.obj \
- $O\BcjCoder.obj \
- $O\BcjRegister.obj \
- $O\BranchMisc.obj \
- $O\BranchRegister.obj \
- $O\ByteSwap.obj \
- $O\CopyCoder.obj \
- $O\CopyRegister.obj \
- $O\DeltaFilter.obj \
- $O\Lzma2Decoder.obj \
- $O\Lzma2Encoder.obj \
- $O\Lzma2Register.obj \
- $O\LzmaDecoder.obj \
- $O\LzmaEncoder.obj \
- $O\LzmaRegister.obj \
- $O\XzDecoder.obj \
- $O\XzEncoder.obj \
-
-CRYPTO_OBJS = \
- $O\7zAes.obj \
- $O\7zAesRegister.obj \
- $O\MyAes.obj \
- $O\MyAesReg.obj \
- $O\RandGen.obj \
-
-C_OBJS = \
- $O\7zStream.obj \
- $O\Alloc.obj \
- $O\Bcj2.obj \
- $O\Bcj2Enc.obj \
- $O\Bra.obj \
- $O\Bra86.obj \
- $O\BraIA64.obj \
- $O\CpuArch.obj \
- $O\Delta.obj \
- $O\LzFind.obj \
- $O\LzFindMt.obj \
- $O\Lzma2Dec.obj \
- $O\Lzma2DecMt.obj \
- $O\Lzma2Enc.obj \
- $O\LzmaDec.obj \
- $O\LzmaEnc.obj \
- $O\MtCoder.obj \
- $O\MtDec.obj \
- $O\Sha256.obj \
- $O\Sort.obj \
- $O\Threads.obj \
- $O\Xz.obj \
- $O\XzDec.obj \
- $O\XzEnc.obj \
- $O\XzIn.obj \
-
-!include "../../UI/Console/Console.mak"
-
-!include "../../Aes.mak"
-!include "../../Crc.mak"
-!include "../../Crc64.mak"
-!include "../../LzmaDec.mak"
-
-!include "../../7zip.mak"
+PROG = 7zr.exe
+
+# USE_C_AES = 1
+# USE_C_SHA = 1
+
+CFLAGS = $(CFLAGS) -DZ7_PROG_VARIANT_R
+
+COMMON_OBJS = \
+ $O\CommandLineParser.obj \
+ $O\CRC.obj \
+ $O\CrcReg.obj \
+ $O\DynLimBuf.obj \
+ $O\IntToString.obj \
+ $O\ListFileUtils.obj \
+ $O\LzFindPrepare.obj \
+ $O\NewHandler.obj \
+ $O\StdInStream.obj \
+ $O\StdOutStream.obj \
+ $O\MyString.obj \
+ $O\Sha256Reg.obj \
+ $O\StringConvert.obj \
+ $O\StringToInt.obj \
+ $O\UTFConvert.obj \
+ $O\MyVector.obj \
+ $O\Wildcard.obj \
+ $O\XzCrc64Init.obj \
+ $O\XzCrc64Reg.obj \
+
+WIN_OBJS = \
+ $O\DLL.obj \
+ $O\ErrorMsg.obj \
+ $O\FileDir.obj \
+ $O\FileFind.obj \
+ $O\FileIO.obj \
+ $O\FileLink.obj \
+ $O\FileName.obj \
+ $O\FileSystem.obj \
+ $O\MemoryLock.obj \
+ $O\PropVariant.obj \
+ $O\PropVariantConv.obj \
+ $O\Registry.obj \
+ $O\System.obj \
+ $O\SystemInfo.obj \
+ $O\TimeUtils.obj \
+
+7ZIP_COMMON_OBJS = \
+ $O\CreateCoder.obj \
+ $O\CWrappers.obj \
+ $O\FilePathAutoRename.obj \
+ $O\FileStreams.obj \
+ $O\InBuffer.obj \
+ $O\InOutTempBuffer.obj \
+ $O\FilterCoder.obj \
+ $O\LimitedStreams.obj \
+ $O\MethodId.obj \
+ $O\MethodProps.obj \
+ $O\MultiOutStream.obj \
+ $O\OffsetStream.obj \
+ $O\OutBuffer.obj \
+ $O\ProgressUtils.obj \
+ $O\PropId.obj \
+ $O\StreamBinder.obj \
+ $O\StreamObjects.obj \
+ $O\StreamUtils.obj \
+ $O\UniqBlocks.obj \
+ $O\VirtThread.obj \
+
+AR_OBJS = \
+ $O\LzmaHandler.obj \
+ $O\SplitHandler.obj \
+ $O\XzHandler.obj \
+
+AR_COMMON_OBJS = \
+ $O\CoderMixer2.obj \
+ $O\DummyOutStream.obj \
+ $O\HandlerOut.obj \
+ $O\InStreamWithCRC.obj \
+ $O\ItemNameUtils.obj \
+ $O\MultiStream.obj \
+ $O\OutStreamWithCRC.obj \
+ $O\ParseProperties.obj \
+
+
+7Z_OBJS = \
+ $O\7zCompressionMode.obj \
+ $O\7zDecode.obj \
+ $O\7zEncode.obj \
+ $O\7zExtract.obj \
+ $O\7zFolderInStream.obj \
+ $O\7zHandler.obj \
+ $O\7zHandlerOut.obj \
+ $O\7zHeader.obj \
+ $O\7zIn.obj \
+ $O\7zOut.obj \
+ $O\7zProperties.obj \
+ $O\7zRegister.obj \
+ $O\7zSpecStream.obj \
+ $O\7zUpdate.obj \
+
+COMPRESS_OBJS = \
+ $O\Bcj2Coder.obj \
+ $O\Bcj2Register.obj \
+ $O\BcjCoder.obj \
+ $O\BcjRegister.obj \
+ $O\BranchMisc.obj \
+ $O\BranchRegister.obj \
+ $O\ByteSwap.obj \
+ $O\CopyCoder.obj \
+ $O\CopyRegister.obj \
+ $O\DeltaFilter.obj \
+ $O\Lzma2Decoder.obj \
+ $O\Lzma2Encoder.obj \
+ $O\Lzma2Register.obj \
+ $O\LzmaDecoder.obj \
+ $O\LzmaEncoder.obj \
+ $O\LzmaRegister.obj \
+ $O\XzDecoder.obj \
+ $O\XzEncoder.obj \
+
+CRYPTO_OBJS = \
+ $O\7zAes.obj \
+ $O\7zAesRegister.obj \
+ $O\MyAes.obj \
+ $O\MyAesReg.obj \
+ $O\RandGen.obj \
+
+C_OBJS = \
+ $O\7zStream.obj \
+ $O\Alloc.obj \
+ $O\Bcj2.obj \
+ $O\Bcj2Enc.obj \
+ $O\Bra.obj \
+ $O\Bra86.obj \
+ $O\BraIA64.obj \
+ $O\CpuArch.obj \
+ $O\Delta.obj \
+ $O\LzFind.obj \
+ $O\LzFindMt.obj \
+ $O\Lzma2Dec.obj \
+ $O\Lzma2DecMt.obj \
+ $O\Lzma2Enc.obj \
+ $O\LzmaDec.obj \
+ $O\LzmaEnc.obj \
+ $O\MtCoder.obj \
+ $O\MtDec.obj \
+ $O\Sort.obj \
+ $O\SwapBytes.obj \
+ $O\Threads.obj \
+ $O\Xz.obj \
+ $O\XzDec.obj \
+ $O\XzEnc.obj \
+ $O\XzIn.obj \
+
+!include "../../UI/Console/Console.mak"
+
+!include "../../Aes.mak"
+!include "../../Crc.mak"
+!include "../../Crc64.mak"
+!include "../../LzFindOpt.mak"
+!include "../../LzmaDec.mak"
+!include "../../Sha256.mak"
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/Bundles/Alone7z/makefile.gcc b/CPP/7zip/Bundles/Alone7z/makefile.gcc
new file mode 100644
index 0000000..6d92c19
--- /dev/null
+++ b/CPP/7zip/Bundles/Alone7z/makefile.gcc
@@ -0,0 +1,276 @@
+PROG = 7zr
+
+CONSOLE_VARIANT_FLAGS=-DZ7_PROG_VARIANT_R
+
+# IS_X64 = 1
+# USE_ASM = 1
+# ST_MODE = 1
+
+ifdef SystemDrive
+IS_MINGW = 1
+else
+ifdef SYSTEMDRIVE
+# ifdef OS
+IS_MINGW = 1
+endif
+endif
+
+include ../../LzmaDec_gcc.mak
+
+
+LOCAL_FLAGS_ST =
+MT_OBJS =
+
+
+ifdef ST_MODE
+
+LOCAL_FLAGS_ST = -DZ7_ST
+
+ifdef IS_MINGW
+MT_OBJS = \
+ $O/Threads.o \
+
+endif
+
+else
+
+MT_OBJS = \
+ $O/LzFindMt.o \
+ $O/LzFindOpt.o \
+ $O/StreamBinder.o \
+ $O/VirtThread.o \
+ $O/Threads.o \
+
+
+
+endif
+
+
+
+LOCAL_FLAGS_SYS =
+
+ifdef IS_MINGW
+
+LOCAL_FLAGS_SYS = \
+ -DZ7_LARGE_PAGES \
+ -DZ7_LONG_PATH \
+ -DZ7_DEVICE_FILE \
+
+SYS_OBJS = \
+ $O/FileSystem.o \
+ $O/Registry.o \
+ $O/MemoryLock.o \
+ $O/DLL.o \
+ $O/DllSecur.o \
+ $O/resource.o \
+
+else
+
+SYS_OBJS = \
+ $O/MyWindows.o \
+
+endif
+
+LOCAL_FLAGS = \
+ $(LOCAL_FLAGS_ST) \
+ $(LOCAL_FLAGS_SYS) \
+
+
+CONSOLE_OBJS = \
+ $O/BenchCon.o \
+ $O/ConsoleClose.o \
+ $O/DynLimBuf.o \
+ $O/ExtractCallbackConsole.o \
+ $O/HashCon.o \
+ $O/List.o \
+ $O/Main.o \
+ $O/MainAr.o \
+ $O/OpenCallbackConsole.o \
+ $O/PercentPrinter.o \
+ $O/UpdateCallbackConsole.o \
+ $O/UserInputUtils.o \
+
+UI_COMMON_OBJS = \
+ $O/ArchiveCommandLine.o \
+ $O/ArchiveExtractCallback.o \
+ $O/ArchiveOpenCallback.o \
+ $O/Bench.o \
+ $O/DefaultName.o \
+ $O/EnumDirItems.o \
+ $O/Extract.o \
+ $O/ExtractingFilePath.o \
+ $O/HashCalc.o \
+ $O/LoadCodecs.o \
+ $O/OpenArchive.o \
+ $O/PropIDUtils.o \
+ $O/SetProperties.o \
+ $O/SortUtils.o \
+ $O/TempFiles.o \
+ $O/Update.o \
+ $O/UpdateAction.o \
+ $O/UpdateCallback.o \
+ $O/UpdatePair.o \
+ $O/UpdateProduce.o \
+
+COMMON_OBJS = \
+ $O/CommandLineParser.o \
+ $O/CRC.o \
+ $O/CrcReg.o \
+ $O/IntToString.o \
+ $O/ListFileUtils.o \
+ $O/LzFindPrepare.o \
+ $O/MyString.o \
+ $O/MyVector.o \
+ $O/NewHandler.o \
+ $O/Sha256Prepare.o \
+ $O/Sha256Reg.o \
+ $O/StringConvert.o \
+ $O/StringToInt.o \
+ $O/StdInStream.o \
+ $O/StdOutStream.o \
+ $O/UTFConvert.o \
+ $O/Wildcard.o \
+ $O/XzCrc64Init.o \
+ $O/XzCrc64Reg.o \
+
+WIN_OBJS = \
+ $O/ErrorMsg.o \
+ $O/FileDir.o \
+ $O/FileFind.o \
+ $O/FileIO.o \
+ $O/FileLink.o \
+ $O/FileName.o \
+ $O/PropVariant.o \
+ $O/PropVariantConv.o \
+ $O/System.o \
+ $O/SystemInfo.o \
+ $O/TimeUtils.o \
+
+7ZIP_COMMON_OBJS = \
+ $O/CreateCoder.o \
+ $O/CWrappers.o \
+ $O/FilePathAutoRename.o \
+ $O/FileStreams.o \
+ $O/InBuffer.o \
+ $O/InOutTempBuffer.o \
+ $O/FilterCoder.o \
+ $O/LimitedStreams.o \
+ $O/MethodId.o \
+ $O/MethodProps.o \
+ $O/MultiOutStream.o \
+ $O/OffsetStream.o \
+ $O/OutBuffer.o \
+ $O/ProgressUtils.o \
+ $O/PropId.o \
+ $O/StreamObjects.o \
+ $O/StreamUtils.o \
+ $O/UniqBlocks.o \
+
+AR_OBJS = \
+ $O/LzmaHandler.o \
+ $O/SplitHandler.o \
+ $O/XzHandler.o \
+
+AR_COMMON_OBJS = \
+ $O/CoderMixer2.o \
+ $O/DummyOutStream.o \
+ $O/HandlerOut.o \
+ $O/InStreamWithCRC.o \
+ $O/ItemNameUtils.o \
+ $O/MultiStream.o \
+ $O/OutStreamWithCRC.o \
+ $O/ParseProperties.o \
+
+7Z_OBJS = \
+ $O/7zCompressionMode.o \
+ $O/7zDecode.o \
+ $O/7zEncode.o \
+ $O/7zExtract.o \
+ $O/7zFolderInStream.o \
+ $O/7zHandler.o \
+ $O/7zHandlerOut.o \
+ $O/7zHeader.o \
+ $O/7zIn.o \
+ $O/7zOut.o \
+ $O/7zProperties.o \
+ $O/7zRegister.o \
+ $O/7zSpecStream.o \
+ $O/7zUpdate.o \
+
+COMPRESS_OBJS = \
+ $O/Bcj2Coder.o \
+ $O/Bcj2Register.o \
+ $O/BcjCoder.o \
+ $O/BcjRegister.o \
+ $O/BranchMisc.o \
+ $O/BranchRegister.o \
+ $O/ByteSwap.o \
+ $O/CopyCoder.o \
+ $O/CopyRegister.o \
+ $O/DeltaFilter.o \
+ $O/Lzma2Decoder.o \
+ $O/Lzma2Encoder.o \
+ $O/Lzma2Register.o \
+ $O/LzmaDecoder.o \
+ $O/LzmaEncoder.o \
+ $O/LzmaRegister.o \
+ $O/XzDecoder.o \
+ $O/XzEncoder.o \
+
+CRYPTO_OBJS = \
+ $O/7zAes.o \
+ $O/7zAesRegister.o \
+ $O/MyAes.o \
+ $O/MyAesReg.o \
+ $O/RandGen.o \
+
+C_OBJS = \
+ $O/7zStream.o \
+ $O/Alloc.o \
+ $O/Bcj2.o \
+ $O/Bcj2Enc.o \
+ $O/Bra.o \
+ $O/Bra86.o \
+ $O/BraIA64.o \
+ $O/CpuArch.o \
+ $O/Delta.o \
+ $O/LzFind.o \
+ $O/Lzma2Dec.o \
+ $O/Lzma2DecMt.o \
+ $O/Lzma2Enc.o \
+ $O/LzmaDec.o \
+ $O/LzmaEnc.o \
+ $O/MtCoder.o \
+ $O/MtDec.o \
+ $O/Sha256.o \
+ $O/Sha256Opt.o \
+ $O/SwapBytes.o \
+ $O/Xz.o \
+ $O/XzDec.o \
+ $O/XzEnc.o \
+ $O/XzIn.o \
+ $O/XzCrc64.o \
+ $O/XzCrc64Opt.o \
+ $O/7zCrc.o \
+ $O/7zCrcOpt.o \
+ $O/Aes.o \
+ $O/AesOpt.o \
+
+
+OBJS = \
+ $(LZMA_DEC_OPT_OBJS) \
+ $(C_OBJS) \
+ $(MT_OBJS) \
+ $(SYS_OBJS) \
+ $(COMMON_OBJS) \
+ $(WIN_OBJS) \
+ $(COMPRESS_OBJS) \
+ $(CRYPTO_OBJS) \
+ $(7ZIP_COMMON_OBJS) \
+ $(AR_OBJS) \
+ $(AR_COMMON_OBJS) \
+ $(7Z_OBJS) \
+ $(UI_COMMON_OBJS) \
+ $(CONSOLE_OBJS) \
+
+include ../../7zip_gcc.mak
diff --git a/CPP/7zip/Bundles/Alone7z/resource.rc b/CPP/7zip/Bundles/Alone7z/resource.rc
index 36d70e7..5937850 100644
--- a/CPP/7zip/Bundles/Alone7z/resource.rc
+++ b/CPP/7zip/Bundles/Alone7z/resource.rc
@@ -1,7 +1,7 @@
-#include "../../../../C/7zVersion.rc"
-
-MY_VERSION_INFO_APP("7-Zip Reduced Standalone Console", "7zr")
-
-#ifndef UNDER_CE
-1 24 MOVEABLE PURE "../../UI/Console/Console.manifest"
-#endif
+#include "../../../../C/7zVersion.rc"
+
+MY_VERSION_INFO_APP("7-Zip Reduced Standalone Console", "7zr")
+
+#ifndef UNDER_CE
+1 24 MOVEABLE PURE "../../UI/Console/Console.manifest"
+#endif
diff --git a/CPP/7zip/Bundles/Fm/FM.dsp b/CPP/7zip/Bundles/Fm/FM.dsp
new file mode 100644
index 0000000..402dd2c
--- /dev/null
+++ b/CPP/7zip/Bundles/Fm/FM.dsp
@@ -0,0 +1,2251 @@
+# Microsoft Developer Studio Project File - Name="FM" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=FM - Win32 DebugU
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "FM.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "FM.mak" CFG="FM - Win32 DebugU"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "FM - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "FM - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE "FM - Win32 ReleaseU" (based on "Win32 (x86) Application")
+!MESSAGE "FM - Win32 DebugU" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "FM - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS_2" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zFM.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "FM - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /Gz /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS_2" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zFM.exe" /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "FM - Win32 ReleaseU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ReleaseU"
+# PROP BASE Intermediate_Dir "ReleaseU"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "ReleaseU"
+# PROP Intermediate_Dir "ReleaseU"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"StdAfx.h" /FD /c
+# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS_2" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zFM.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "FM - Win32 DebugU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "DebugU"
+# PROP BASE Intermediate_Dir "DebugU"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "DebugU"
+# PROP Intermediate_Dir "DebugU"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c
+# ADD CPP /nologo /Gz /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS_2" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zFM.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "FM - Win32 Release"
+# Name "FM - Win32 Debug"
+# Name "FM - Win32 ReleaseU"
+# Name "FM - Win32 DebugU"
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\7zipLogo.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\add.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ClassDefs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\Copy.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\Delete.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\Extract.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FM.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\Move.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\Parent.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\Properties.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\StdAfx.cpp
+# ADD CPP /Yc"StdAfx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\StdAfx.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\Test.bmp
+# End Source File
+# End Group
+# Begin Group "Archive"
+
+# PROP Default_Filter ""
+# Begin Group "Archive Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\DummyOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\DummyOutStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\FindSignature.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\FindSignature.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\HandlerOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\HandlerOut.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\InStreamWithCRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\InStreamWithCRC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\MultiStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\MultiStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ParseProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ParseProperties.h
+# End Source File
+# End Group
+# Begin Group "7z"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zCompressionMode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zCompressionMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zDecode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zEncode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zEncode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zExtract.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zFolderInStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zFolderInStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandlerOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHeader.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zOut.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zProperties.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zSpecStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zSpecStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zUpdate.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zUpdate.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\Archive\IArchive.h
+# End Source File
+# End Group
+# Begin Group "Folders"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\AltStreamsFolder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\AltStreamsFolder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FSDrives.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FSDrives.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FSFolder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FSFolder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FSFolderCopy.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\IFolder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\NetFolder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\NetFolder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\RootFolder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\RootFolder.h
+# End Source File
+# End Group
+# Begin Group "Registry"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\RegistryAssociations.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\RegistryAssociations.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\RegistryPlugins.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\RegistryPlugins.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\RegistryUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\RegistryUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ViewSettings.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ViewSettings.h
+# End Source File
+# End Group
+# Begin Group "Panel"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\App.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\App.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\AppState.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\EnumFormatEtc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\EnumFormatEtc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FileFolderPluginOpen.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FileFolderPluginOpen.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\Panel.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\Panel.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PanelCopy.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PanelCrc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PanelDrag.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PanelFolderChange.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PanelItemOpen.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PanelItems.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PanelKey.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PanelListNotify.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PanelMenu.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PanelOperations.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PanelSelect.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PanelSort.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PanelSplitFile.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\VerCtrl.cpp
+# End Source File
+# End Group
+# Begin Group "Dialog"
+
+# PROP Default_Filter ""
+# Begin Group "Options"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\EditPage.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\EditPage.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FoldersPage.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FoldersPage.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\LangPage.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\LangPage.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\MenuPage.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\MenuPage.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\OptionsDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\SettingsPage.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\SettingsPage.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\SystemPage.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\SystemPage.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\AboutDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\AboutDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\BrowseDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\BrowseDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ComboDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ComboDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\CopyDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\CopyDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\DialogSize.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\EditDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\EditDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\LinkDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\LinkDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ListViewDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ListViewDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\MessagesDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\MessagesDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\OverwriteDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\OverwriteDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PasswordDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PasswordDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ProgressDialog2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ProgressDialog2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\SplitDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\SplitDialog.h
+# End Source File
+# End Group
+# Begin Group "FM Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ExtractCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FormatUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FormatUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\HelpUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\HelpUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\LangUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\LangUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ProgramLocation.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ProgramLocation.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\UpdateCallback100.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\UpdateCallback100.h
+# End Source File
+# End Group
+# Begin Group "7-Zip Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CWrappers.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CWrappers.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InOutTempBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InOutTempBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MultiOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MultiOutStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\PropId.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamBinder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamBinder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\UniqBlocks.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\UniqBlocks.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\VirtThread.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\VirtThread.h
+# End Source File
+# End Group
+# Begin Group "C"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrcOpt.c
+
+!IF "$(CFG)" == "FM - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "FM - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "FM - Win32 ReleaseU"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "FM - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zStream.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.c
+
+!IF "$(CFG)" == "FM - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "FM - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "FM - Win32 ReleaseU"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "FM - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\DllSecur.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\DllSecur.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFind.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFindMt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFindMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFindOpt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Dec.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Dec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2DecMt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2DecMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Enc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Enc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaDec.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaDec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaEnc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaEnc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtCoder.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtDec.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtDec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha1.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha1.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha1Opt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha256.c
+
+!IF "$(CFG)" == "FM - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "FM - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "FM - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "FM - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha256.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha256Opt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sort.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sort.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzCrc64.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzCrc64Opt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Group "Control"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ComboBox.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ComboBox.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\CommandBar.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Dialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Dialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Edit.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ImageList.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ListView.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ListView.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ProgressBar.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\PropertyPage.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\PropertyPage.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ReBar.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Static.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\StatusBar.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ToolBar.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Trackbar.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Window2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Window2.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Clipboard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Clipboard.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\COM.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\CommonDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\CommonDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Device.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileLink.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileMapping.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileSystem.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileSystem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Handle.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryGlobal.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryGlobal.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryLock.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryLock.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Menu.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Menu.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Net.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Net.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ProcessUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ProcessUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Registry.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Registry.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ResourceString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ResourceString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\SecurityUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\SecurityUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Shell.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Shell.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\SystemInfo.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\SystemInfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Thread.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\TimeUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\TimeUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Window.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Window.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Common.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ComTry.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CrcReg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynamicBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynLimBuf.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynLimBuf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Exception.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Lang.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Lang.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ListFileUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ListFileUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\LzFindPrepare.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyCom.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Random.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Random.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Sha1Prepare.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Sha1Reg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Sha256Prepare.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Sha256Reg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Types.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\XzCrc64Init.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\XzCrc64Reg.cpp
+# End Source File
+# End Group
+# Begin Group "UI"
+
+# PROP Default_Filter ""
+# Begin Group "UI Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveOpenCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Bench.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Bench.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\CompressCall.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\CompressCall2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\DefaultName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\DefaultName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\DirItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\EnumDirItems.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\EnumDirItems.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExitCode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Extract.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Extract.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExtractingFilePath.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExtractingFilePath.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExtractMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\HashCalc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\HashCalc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\IFileExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\LoadCodecs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\LoadCodecs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\OpenArchive.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\OpenArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Property.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\PropIDUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\PropIDUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\SetProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\SetProperties.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\SortUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\SortUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\StdAfx.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\TempFiles.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\TempFiles.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Update.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Update.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateAction.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateAction.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdatePair.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdatePair.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateProduce.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\UpdateProduce.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\WorkDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\WorkDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ZipRegistry.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ZipRegistry.h
+# End Source File
+# End Group
+# Begin Group "Agent"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\Agent\Agent.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Agent\Agent.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Agent\AgentOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Agent\AgentProxy.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Agent\AgentProxy.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Agent\ArchiveFolder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Agent\ArchiveFolderOpen.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Agent\ArchiveFolderOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Agent\IFolderArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Agent\UpdateCallbackAgent.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Agent\UpdateCallbackAgent.h
+# End Source File
+# End Group
+# Begin Group "Explorer"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\Explorer\ContextMenu.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Explorer\ContextMenu.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Explorer\MyMessages.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Explorer\MyMessages.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Explorer\RegistryContextMenu.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Explorer\RegistryContextMenu.h
+# End Source File
+# End Group
+# Begin Group "GUI"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\BenchmarkDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\BenchmarkDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\BenchmarkDialogRes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\CompressDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\CompressDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\ExtractDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\ExtractDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\ExtractGUI.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\ExtractGUI.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\HashGUI.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\HashGUI.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\UpdateCallbackGUI.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\UpdateCallbackGUI.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\UpdateCallbackGUI2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\UpdateCallbackGUI2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\UpdateGUI.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\UpdateGUI.h
+# End Source File
+# End Group
+# End Group
+# Begin Group "Compress"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Decoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Decoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Encoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Encoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Register.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaEncoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaRegister.cpp
+# End Source File
+# End Group
+# Begin Group "Interface"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\ICoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IDecl.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IPassword.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IProgress.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\7zFM.exe.manifest
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\7zipLogo.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\Add2.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\Copy2.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\Delete2.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\Extract2.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FilePlugins.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FilePlugins.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FM.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\Info.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\Info2.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\Move2.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\MyCom2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\MyLoadMenu.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\MyLoadMenu.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\OpenCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\OpenCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PluginInterface.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PluginLoader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PropertyName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PropertyName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\resource.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\SplitUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\SplitUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\StringUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\StringUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\SysIconUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\SysIconUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\Test2.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\TextPairs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\TextPairs.h
+# End Source File
+# End Target
+# End Project
diff --git a/CPP/7zip/Bundles/Fm/FM.dsw b/CPP/7zip/Bundles/Fm/FM.dsw
new file mode 100644
index 0000000..1c955d9
--- /dev/null
+++ b/CPP/7zip/Bundles/Fm/FM.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "FM"=.\FM.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/Bundles/Fm/StdAfx.cpp b/CPP/7zip/Bundles/Fm/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/Bundles/Fm/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/Fm/StdAfx.h b/CPP/7zip/Bundles/Fm/StdAfx.h
new file mode 100644
index 0000000..4f27255
--- /dev/null
+++ b/CPP/7zip/Bundles/Fm/StdAfx.h
@@ -0,0 +1,6 @@
+// StdAfx.h
+
+#if _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../UI/FileManager/StdAfx.h"
diff --git a/CPP/7zip/Bundles/Fm/makefile b/CPP/7zip/Bundles/Fm/makefile
new file mode 100644
index 0000000..33b5320
--- /dev/null
+++ b/CPP/7zip/Bundles/Fm/makefile
@@ -0,0 +1,84 @@
+PROG = 7zFM.exe
+
+CFLAGS = $(CFLAGS) -DZ7_LARGE_PAGES
+
+!include "../Format7zF/Arc.mak"
+
+!include "../../UI/FileManager/FM.mak"
+
+COMMON_OBJS = $(COMMON_OBJS) \
+ $O\CommandLineParser.obj \
+ $O\Lang.obj \
+ $O\ListFileUtils.obj \
+ $O\Random.obj \
+
+WIN_OBJS = $(WIN_OBJS) \
+ $O\Clipboard.obj \
+ $O\CommonDialog.obj \
+ $O\DLL.obj \
+ $O\ErrorMsg.obj \
+ $O\FileLink.obj \
+ $O\MemoryGlobal.obj \
+ $O\MemoryLock.obj \
+ $O\Menu.obj \
+ $O\ProcessUtils.obj \
+ $O\Registry.obj \
+ $O\ResourceString.obj \
+ $O\SystemInfo.obj \
+ $O\Shell.obj \
+ $O\Window.obj \
+
+WIN_CTRL_OBJS = \
+ $O\ComboBox.obj \
+ $O\Dialog.obj \
+ $O\ListView.obj \
+ $O\PropertyPage.obj \
+ $O\Window2.obj \
+
+7ZIP_COMMON_OBJS = $(7ZIP_COMMON_OBJS) \
+ $O\FilePathAutoRename.obj \
+ $O\FileStreams.obj \
+ $O\MultiOutStream.obj \
+
+UI_COMMON_OBJS = \
+ $O\ArchiveExtractCallback.obj \
+ $O\ArchiveName.obj \
+ $O\ArchiveOpenCallback.obj \
+ $O\Bench.obj \
+ $O\CompressCall2.obj \
+ $O\DefaultName.obj \
+ $O\EnumDirItems.obj \
+ $O\Extract.obj \
+ $O\ExtractingFilePath.obj \
+ $O\HashCalc.obj \
+ $O\LoadCodecs.obj \
+ $O\OpenArchive.obj \
+ $O\PropIDUtils.obj \
+ $O\SetProperties.obj \
+ $O\SortUtils.obj \
+ $O\TempFiles.obj \
+ $O\Update.obj \
+ $O\UpdateAction.obj \
+ $O\UpdateCallback.obj \
+ $O\UpdatePair.obj \
+ $O\UpdateProduce.obj \
+ $O\WorkDir.obj \
+ $O\ZipRegistry.obj \
+
+EXPLORER_OBJS = \
+ $O\ContextMenu.obj \
+ $O\MyMessages.obj \
+ $O\RegistryContextMenu.obj \
+
+GUI_OBJS = \
+ $O\BenchmarkDialog.obj \
+ $O\CompressDialog.obj \
+ $O\ExtractDialog.obj \
+ $O\ExtractGUI.obj \
+ $O\HashGUI.obj \
+ $O\UpdateCallbackGUI.obj \
+ $O\UpdateCallbackGUI2.obj \
+ $O\UpdateGUI.obj \
+
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/Bundles/Fm/resource.rc b/CPP/7zip/Bundles/Fm/resource.rc
new file mode 100644
index 0000000..ebc2f74
--- /dev/null
+++ b/CPP/7zip/Bundles/Fm/resource.rc
@@ -0,0 +1,7 @@
+#include "../../UI/FileManager/resource.rc"
+#include "../../UI/GUI/resource2.rc"
+
+STRINGTABLE
+BEGIN
+ 100 "7z zip rar 001 cab iso xz txz lzma tar cpio bz2 bzip2 tbz2 tbz gz gzip tgz tpz z taz lzh lha rpm deb arj vhd vhdx wim swm esd fat ntfs dmg hfs xar squashfs apfs"
+END
diff --git a/CPP/7zip/Bundles/Format7z/StdAfx.cpp b/CPP/7zip/Bundles/Format7z/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7z/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/Format7z/StdAfx.h b/CPP/7zip/Bundles/Format7z/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7z/StdAfx.h
@@ -0,0 +1,11 @@
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Bundles/Format7z/makefile b/CPP/7zip/Bundles/Format7z/makefile
new file mode 100644
index 0000000..d20a3c1
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7z/makefile
@@ -0,0 +1,147 @@
+PROG = 7za.dll
+DEF_FILE = ../../Archive/Archive2.def
+CFLAGS = $(CFLAGS) \
+ -DZ7_DEFLATE_EXTRACT_ONLY \
+ -DZ7_BZIP2_EXTRACT_ONLY \
+
+COMMON_OBJS = \
+ $O\CRC.obj \
+ $O\CrcReg.obj \
+ $O\IntToString.obj \
+ $O\LzFindPrepare.obj \
+ $O\NewHandler.obj \
+ $O\MyString.obj \
+ $O\Sha256Reg.obj \
+ $O\StringConvert.obj \
+ $O\StringToInt.obj \
+ $O\MyVector.obj \
+ $O\Wildcard.obj \
+
+WIN_OBJS = \
+ $O\FileDir.obj \
+ $O\FileFind.obj \
+ $O\FileIO.obj \
+ $O\FileName.obj \
+ $O\PropVariant.obj \
+ $O\Synchronization.obj \
+ $O\System.obj \
+
+7ZIP_COMMON_OBJS = \
+ $O\CreateCoder.obj \
+ $O\CWrappers.obj \
+ $O\InBuffer.obj \
+ $O\InOutTempBuffer.obj \
+ $O\FilterCoder.obj \
+ $O\LimitedStreams.obj \
+ $O\MethodId.obj \
+ $O\MethodProps.obj \
+ $O\OutBuffer.obj \
+ $O\ProgressUtils.obj \
+ $O\PropId.obj \
+ $O\StreamBinder.obj \
+ $O\StreamObjects.obj \
+ $O\StreamUtils.obj \
+ $O\UniqBlocks.obj \
+ $O\VirtThread.obj \
+
+AR_OBJS = \
+ $O\ArchiveExports.obj \
+ $O\DllExports2.obj \
+
+AR_COMMON_OBJS = \
+ $O\CoderMixer2.obj \
+ $O\HandlerOut.obj \
+ $O\InStreamWithCRC.obj \
+ $O\ItemNameUtils.obj \
+ $O\OutStreamWithCRC.obj \
+ $O\ParseProperties.obj \
+
+
+7Z_OBJS = \
+ $O\7zCompressionMode.obj \
+ $O\7zDecode.obj \
+ $O\7zEncode.obj \
+ $O\7zExtract.obj \
+ $O\7zFolderInStream.obj \
+ $O\7zHandler.obj \
+ $O\7zHandlerOut.obj \
+ $O\7zHeader.obj \
+ $O\7zIn.obj \
+ $O\7zOut.obj \
+ $O\7zProperties.obj \
+ $O\7zSpecStream.obj \
+ $O\7zUpdate.obj \
+ $O\7zRegister.obj \
+
+
+COMPRESS_OBJS = \
+ $O\CodecExports.obj \
+ $O\Bcj2Coder.obj \
+ $O\Bcj2Register.obj \
+ $O\BcjCoder.obj \
+ $O\BcjRegister.obj \
+ $O\BitlDecoder.obj \
+ $O\BranchMisc.obj \
+ $O\BranchRegister.obj \
+ $O\ByteSwap.obj \
+ $O\BZip2Crc.obj \
+ $O\BZip2Decoder.obj \
+ $O\BZip2Register.obj \
+ $O\CopyCoder.obj \
+ $O\CopyRegister.obj \
+ $O\DeflateDecoder.obj \
+ $O\DeflateRegister.obj \
+ $O\DeltaFilter.obj \
+ $O\Lzma2Decoder.obj \
+ $O\Lzma2Encoder.obj \
+ $O\Lzma2Register.obj \
+ $O\LzmaDecoder.obj \
+ $O\LzmaEncoder.obj \
+ $O\LzmaRegister.obj \
+ $O\LzOutWindow.obj \
+ $O\PpmdDecoder.obj \
+ $O\PpmdEncoder.obj \
+ $O\PpmdRegister.obj \
+
+CRYPTO_OBJS = \
+ $O\7zAes.obj \
+ $O\7zAesRegister.obj \
+ $O\MyAes.obj \
+ $O\MyAesReg.obj \
+ $O\RandGen.obj \
+
+C_OBJS = \
+ $O\7zStream.obj \
+ $O\Alloc.obj \
+ $O\Bcj2.obj \
+ $O\Bcj2Enc.obj \
+ $O\Bra.obj \
+ $O\Bra86.obj \
+ $O\BraIA64.obj \
+ $O\BwtSort.obj \
+ $O\CpuArch.obj \
+ $O\Delta.obj \
+ $O\HuffEnc.obj \
+ $O\LzFind.obj \
+ $O\LzFindMt.obj \
+ $O\Lzma2Dec.obj \
+ $O\Lzma2DecMt.obj \
+ $O\Lzma2Enc.obj \
+ $O\LzmaDec.obj \
+ $O\LzmaEnc.obj \
+ $O\MtCoder.obj \
+ $O\MtDec.obj \
+ $O\Ppmd7.obj \
+ $O\Ppmd7Dec.obj \
+ $O\Ppmd7Enc.obj \
+ $O\Sort.obj \
+ $O\SwapBytes.obj \
+ $O\Threads.obj \
+
+!include "../../Aes.mak"
+!include "../../Crc.mak"
+!include "../../LzFindOpt.mak"
+!include "../../LzmaDec.mak"
+!include "../../Sha256.mak"
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/Bundles/Format7z/resource.rc b/CPP/7zip/Bundles/Format7z/resource.rc
new file mode 100644
index 0000000..2f2b42a
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7z/resource.rc
@@ -0,0 +1,5 @@
+#include "../../MyVersionInfo.rc"
+
+MY_VERSION_INFO_DLL("7z Standalone Plugin", "7za")
+
+101 ICON "../../Archive/Icons/7z.ico"
diff --git a/CPP/7zip/Bundles/Format7zExtract/StdAfx.cpp b/CPP/7zip/Bundles/Format7zExtract/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zExtract/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/Format7zExtract/StdAfx.h b/CPP/7zip/Bundles/Format7zExtract/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zExtract/StdAfx.h
@@ -0,0 +1,11 @@
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Bundles/Format7zExtract/makefile b/CPP/7zip/Bundles/Format7zExtract/makefile
new file mode 100644
index 0000000..4e2ed3e
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zExtract/makefile
@@ -0,0 +1,116 @@
+PROG = 7zxa.dll
+DEF_FILE = ../../Archive/Archive2.def
+CFLAGS = $(CFLAGS) \
+ -DZ7_EXTRACT_ONLY \
+
+COMMON_OBJS = \
+ $O\CRC.obj \
+ $O\CrcReg.obj \
+ $O\IntToString.obj \
+ $O\MyString.obj \
+ $O\MyVector.obj \
+ $O\NewHandler.obj \
+ $O\Sha256Reg.obj \
+ $O\StringConvert.obj \
+ $O\StringToInt.obj \
+ $O\Wildcard.obj \
+
+WIN_OBJS = \
+ $O\PropVariant.obj \
+ $O\Synchronization.obj \
+ $O\System.obj \
+
+7ZIP_COMMON_OBJS = \
+ $O\CreateCoder.obj \
+ $O\CWrappers.obj \
+ $O\InBuffer.obj \
+ $O\FilterCoder.obj \
+ $O\LimitedStreams.obj \
+ $O\MethodId.obj \
+ $O\MethodProps.obj \
+ $O\OutBuffer.obj \
+ $O\ProgressUtils.obj \
+ $O\PropId.obj \
+ $O\StreamBinder.obj \
+ $O\StreamObjects.obj \
+ $O\StreamUtils.obj \
+ $O\VirtThread.obj \
+
+AR_OBJS = \
+ $O\ArchiveExports.obj \
+ $O\DllExports2.obj \
+
+AR_COMMON_OBJS = \
+ $O\CoderMixer2.obj \
+ $O\HandlerOut.obj \
+ $O\ItemNameUtils.obj \
+ $O\OutStreamWithCRC.obj \
+ $O\ParseProperties.obj \
+
+7Z_OBJS = \
+ $O\7zCompressionMode.obj \
+ $O\7zDecode.obj \
+ $O\7zExtract.obj \
+ $O\7zHandler.obj \
+ $O\7zHeader.obj \
+ $O\7zIn.obj \
+ $O\7zProperties.obj \
+ $O\7zRegister.obj \
+
+
+COMPRESS_OBJS = \
+ $O\CodecExports.obj \
+ $O\Bcj2Coder.obj \
+ $O\Bcj2Register.obj \
+ $O\BcjCoder.obj \
+ $O\BcjRegister.obj \
+ $O\BitlDecoder.obj \
+ $O\BranchMisc.obj \
+ $O\BranchRegister.obj \
+ $O\ByteSwap.obj \
+ $O\BZip2Crc.obj \
+ $O\BZip2Decoder.obj \
+ $O\BZip2Register.obj \
+ $O\CopyCoder.obj \
+ $O\CopyRegister.obj \
+ $O\DeflateDecoder.obj \
+ $O\DeflateRegister.obj \
+ $O\DeltaFilter.obj \
+ $O\Lzma2Decoder.obj \
+ $O\Lzma2Register.obj \
+ $O\LzmaDecoder.obj \
+ $O\LzmaRegister.obj \
+ $O\LzOutWindow.obj \
+ $O\PpmdDecoder.obj \
+ $O\PpmdRegister.obj \
+
+CRYPTO_OBJS = \
+ $O\7zAes.obj \
+ $O\7zAesRegister.obj \
+ $O\MyAes.obj \
+ $O\MyAesReg.obj \
+
+C_OBJS = \
+ $O\7zStream.obj \
+ $O\Alloc.obj \
+ $O\Bcj2.obj \
+ $O\Bra.obj \
+ $O\Bra86.obj \
+ $O\BraIA64.obj \
+ $O\CpuArch.obj \
+ $O\Delta.obj \
+ $O\Lzma2Dec.obj \
+ $O\Lzma2DecMt.obj \
+ $O\LzmaDec.obj \
+ $O\MtDec.obj \
+ $O\Ppmd7.obj \
+ $O\Ppmd7Dec.obj \
+ $O\SwapBytes.obj \
+ $O\Threads.obj \
+
+!include "../../Aes.mak"
+!include "../../Crc.mak"
+!include "../../LzmaDec.mak"
+!include "../../Sha256.mak"
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/Bundles/Format7zExtract/resource.rc b/CPP/7zip/Bundles/Format7zExtract/resource.rc
new file mode 100644
index 0000000..6a65461
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zExtract/resource.rc
@@ -0,0 +1,5 @@
+#include "../../MyVersionInfo.rc"
+
+MY_VERSION_INFO_DLL("7z Standalone Extracting Plugin", "7zxa")
+
+101 ICON "../../Archive/Icons/7z.ico"
diff --git a/CPP/7zip/Bundles/Format7zExtractR/StdAfx.cpp b/CPP/7zip/Bundles/Format7zExtractR/StdAfx.cpp
index c6d3b1f..d0feea8 100644
--- a/CPP/7zip/Bundles/Format7zExtractR/StdAfx.cpp
+++ b/CPP/7zip/Bundles/Format7zExtractR/StdAfx.cpp
@@ -1,3 +1,3 @@
-// StdAfx.cpp
-
-#include "StdAfx.h"
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/Format7zExtractR/StdAfx.h b/CPP/7zip/Bundles/Format7zExtractR/StdAfx.h
index 59d9ac1..035267c 100644
--- a/CPP/7zip/Bundles/Format7zExtractR/StdAfx.h
+++ b/CPP/7zip/Bundles/Format7zExtractR/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "../../../Common/Common.h"
-
-#endif
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Bundles/Format7zExtractR/makefile b/CPP/7zip/Bundles/Format7zExtractR/makefile
index 3a7f981..50b84d8 100644
--- a/CPP/7zip/Bundles/Format7zExtractR/makefile
+++ b/CPP/7zip/Bundles/Format7zExtractR/makefile
@@ -1,96 +1,98 @@
-PROG = 7zxr.dll
-DEF_FILE = ../../Archive/Archive2.def
-CFLAGS = $(CFLAGS) \
- -DEXTRACT_ONLY \
- -D_NO_CRYPTO
-
-COMMON_OBJS = \
- $O\CRC.obj \
- $O\CrcReg.obj \
- $O\IntToString.obj \
- $O\NewHandler.obj \
- $O\MyString.obj \
- $O\StringConvert.obj \
- $O\StringToInt.obj \
- $O\MyVector.obj \
- $O\Wildcard.obj \
-
-WIN_OBJS = \
- $O\PropVariant.obj \
- $O\Synchronization.obj \
- $O\System.obj \
-
-7ZIP_COMMON_OBJS = \
- $O\CreateCoder.obj \
- $O\CWrappers.obj \
- $O\InBuffer.obj \
- $O\FilterCoder.obj \
- $O\LimitedStreams.obj \
- $O\MethodId.obj \
- $O\MethodProps.obj \
- $O\OutBuffer.obj \
- $O\ProgressUtils.obj \
- $O\PropId.obj \
- $O\StreamBinder.obj \
- $O\StreamObjects.obj \
- $O\StreamUtils.obj \
- $O\VirtThread.obj \
-
-AR_OBJS = \
- $O\ArchiveExports.obj \
- $O\DllExports2.obj \
-
-AR_COMMON_OBJS = \
- $O\CoderMixer2.obj \
- $O\HandlerOut.obj \
- $O\ItemNameUtils.obj \
- $O\OutStreamWithCRC.obj \
- $O\ParseProperties.obj \
-
-
-7Z_OBJS = \
- $O\7zCompressionMode.obj \
- $O\7zDecode.obj \
- $O\7zExtract.obj \
- $O\7zHandler.obj \
- $O\7zHeader.obj \
- $O\7zIn.obj \
- $O\7zProperties.obj \
- $O\7zRegister.obj \
-
-
-COMPRESS_OBJS = \
- $O\CodecExports.obj \
- $O\Bcj2Coder.obj \
- $O\Bcj2Register.obj \
- $O\BcjCoder.obj \
- $O\BcjRegister.obj \
- $O\BranchMisc.obj \
- $O\BranchRegister.obj \
- $O\ByteSwap.obj \
- $O\CopyCoder.obj \
- $O\CopyRegister.obj \
- $O\DeltaFilter.obj \
- $O\Lzma2Decoder.obj \
- $O\Lzma2Register.obj \
- $O\LzmaDecoder.obj \
- $O\LzmaRegister.obj \
-
-C_OBJS = \
- $O\Alloc.obj \
- $O\Bcj2.obj \
- $O\Bra.obj \
- $O\Bra86.obj \
- $O\BraIA64.obj \
- $O\CpuArch.obj \
- $O\Delta.obj \
- $O\Lzma2Dec.obj \
- $O\Lzma2DecMt.obj \
- $O\LzmaDec.obj \
- $O\MtDec.obj \
- $O\Threads.obj \
-
-!include "../../Crc.mak"
-!include "../../LzmaDec.mak"
-
-!include "../../7zip.mak"
+PROG = 7zxr.dll
+DEF_FILE = ../../Archive/Archive2.def
+CFLAGS = $(CFLAGS) \
+ -DZ7_EXTRACT_ONLY \
+ -DZ7_NO_CRYPTO
+
+COMMON_OBJS = \
+ $O\CRC.obj \
+ $O\CrcReg.obj \
+ $O\IntToString.obj \
+ $O\NewHandler.obj \
+ $O\MyString.obj \
+ $O\StringConvert.obj \
+ $O\StringToInt.obj \
+ $O\MyVector.obj \
+ $O\Wildcard.obj \
+
+WIN_OBJS = \
+ $O\PropVariant.obj \
+ $O\Synchronization.obj \
+ $O\System.obj \
+
+7ZIP_COMMON_OBJS = \
+ $O\CreateCoder.obj \
+ $O\CWrappers.obj \
+ $O\InBuffer.obj \
+ $O\FilterCoder.obj \
+ $O\LimitedStreams.obj \
+ $O\MethodId.obj \
+ $O\MethodProps.obj \
+ $O\OutBuffer.obj \
+ $O\ProgressUtils.obj \
+ $O\PropId.obj \
+ $O\StreamBinder.obj \
+ $O\StreamObjects.obj \
+ $O\StreamUtils.obj \
+ $O\VirtThread.obj \
+
+AR_OBJS = \
+ $O\ArchiveExports.obj \
+ $O\DllExports2.obj \
+
+AR_COMMON_OBJS = \
+ $O\CoderMixer2.obj \
+ $O\HandlerOut.obj \
+ $O\ItemNameUtils.obj \
+ $O\OutStreamWithCRC.obj \
+ $O\ParseProperties.obj \
+
+
+7Z_OBJS = \
+ $O\7zCompressionMode.obj \
+ $O\7zDecode.obj \
+ $O\7zExtract.obj \
+ $O\7zHandler.obj \
+ $O\7zHeader.obj \
+ $O\7zIn.obj \
+ $O\7zProperties.obj \
+ $O\7zRegister.obj \
+
+
+COMPRESS_OBJS = \
+ $O\CodecExports.obj \
+ $O\Bcj2Coder.obj \
+ $O\Bcj2Register.obj \
+ $O\BcjCoder.obj \
+ $O\BcjRegister.obj \
+ $O\BranchMisc.obj \
+ $O\BranchRegister.obj \
+ $O\ByteSwap.obj \
+ $O\CopyCoder.obj \
+ $O\CopyRegister.obj \
+ $O\DeltaFilter.obj \
+ $O\Lzma2Decoder.obj \
+ $O\Lzma2Register.obj \
+ $O\LzmaDecoder.obj \
+ $O\LzmaRegister.obj \
+
+C_OBJS = \
+ $O\7zStream.obj \
+ $O\Alloc.obj \
+ $O\Bcj2.obj \
+ $O\Bra.obj \
+ $O\Bra86.obj \
+ $O\BraIA64.obj \
+ $O\CpuArch.obj \
+ $O\Delta.obj \
+ $O\Lzma2Dec.obj \
+ $O\Lzma2DecMt.obj \
+ $O\LzmaDec.obj \
+ $O\MtDec.obj \
+ $O\SwapBytes.obj \
+ $O\Threads.obj \
+
+!include "../../Crc.mak"
+!include "../../LzmaDec.mak"
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/Bundles/Format7zExtractR/resource.rc b/CPP/7zip/Bundles/Format7zExtractR/resource.rc
index dac02a6..149f58c 100644
--- a/CPP/7zip/Bundles/Format7zExtractR/resource.rc
+++ b/CPP/7zip/Bundles/Format7zExtractR/resource.rc
@@ -1,5 +1,5 @@
-#include "../../../../C/7zVersion.rc"
-
-MY_VERSION_INFO_DLL("7z Extracting Reduced Standalone Plugin", "7zxr")
-
-101 ICON "../../Archive/Icons/7z.ico"
+#include "../../../../C/7zVersion.rc"
+
+MY_VERSION_INFO_DLL("7z Extracting Reduced Standalone Plugin", "7zxr")
+
+101 ICON "../../Archive/Icons/7z.ico"
diff --git a/CPP/7zip/Bundles/Format7zF/Arc.mak b/CPP/7zip/Bundles/Format7zF/Arc.mak
new file mode 100644
index 0000000..37b400e
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zF/Arc.mak
@@ -0,0 +1,297 @@
+COMMON_OBJS = \
+ $O\CRC.obj \
+ $O\CrcReg.obj \
+ $O\DynLimBuf.obj \
+ $O\IntToString.obj \
+ $O\LzFindPrepare.obj \
+ $O\MyMap.obj \
+ $O\MyString.obj \
+ $O\MyVector.obj \
+ $O\MyXml.obj \
+ $O\NewHandler.obj \
+ $O\Sha1Reg.obj \
+ $O\Sha256Reg.obj \
+ $O\StringConvert.obj \
+ $O\StringToInt.obj \
+ $O\UTFConvert.obj \
+ $O\Wildcard.obj \
+ $O\XzCrc64Init.obj \
+ $O\XzCrc64Reg.obj \
+
+WIN_OBJS = \
+ $O\FileDir.obj \
+ $O\FileFind.obj \
+ $O\FileIO.obj \
+ $O\FileName.obj \
+ $O\PropVariant.obj \
+ $O\PropVariantConv.obj \
+ $O\PropVariantUtils.obj \
+ $O\Synchronization.obj \
+ $O\System.obj \
+ $O\TimeUtils.obj \
+
+7ZIP_COMMON_OBJS = \
+ $O\CreateCoder.obj \
+ $O\CWrappers.obj \
+ $O\InBuffer.obj \
+ $O\InOutTempBuffer.obj \
+ $O\FilterCoder.obj \
+ $O\LimitedStreams.obj \
+ $O\LockedStream.obj \
+ $O\MemBlocks.obj \
+ $O\MethodId.obj \
+ $O\MethodProps.obj \
+ $O\OffsetStream.obj \
+ $O\OutBuffer.obj \
+ $O\OutMemStream.obj \
+ $O\ProgressMt.obj \
+ $O\ProgressUtils.obj \
+ $O\PropId.obj \
+ $O\StreamBinder.obj \
+ $O\StreamObjects.obj \
+ $O\StreamUtils.obj \
+ $O\UniqBlocks.obj \
+ $O\VirtThread.obj \
+
+AR_OBJS = \
+ $O\ApfsHandler.obj \
+ $O\ApmHandler.obj \
+ $O\ArHandler.obj \
+ $O\ArjHandler.obj \
+ $O\Base64Handler.obj \
+ $O\Bz2Handler.obj \
+ $O\ComHandler.obj \
+ $O\CpioHandler.obj \
+ $O\CramfsHandler.obj \
+ $O\DeflateProps.obj \
+ $O\DmgHandler.obj \
+ $O\ElfHandler.obj \
+ $O\ExtHandler.obj \
+ $O\FatHandler.obj \
+ $O\FlvHandler.obj \
+ $O\GzHandler.obj \
+ $O\GptHandler.obj \
+ $O\HandlerCont.obj \
+ $O\HfsHandler.obj \
+ $O\IhexHandler.obj \
+ $O\LpHandler.obj \
+ $O\LzhHandler.obj \
+ $O\LzmaHandler.obj \
+ $O\MachoHandler.obj \
+ $O\MbrHandler.obj \
+ $O\MslzHandler.obj \
+ $O\MubHandler.obj \
+ $O\NtfsHandler.obj \
+ $O\PeHandler.obj \
+ $O\PpmdHandler.obj \
+ $O\QcowHandler.obj \
+ $O\RpmHandler.obj \
+ $O\SparseHandler.obj \
+ $O\SplitHandler.obj \
+ $O\SquashfsHandler.obj \
+ $O\SwfHandler.obj \
+ $O\UefiHandler.obj \
+ $O\VdiHandler.obj \
+ $O\VhdHandler.obj \
+ $O\VhdxHandler.obj \
+ $O\VmdkHandler.obj \
+ $O\XarHandler.obj \
+ $O\XzHandler.obj \
+ $O\ZHandler.obj \
+
+AR_COMMON_OBJS = \
+ $O\CoderMixer2.obj \
+ $O\DummyOutStream.obj \
+ $O\FindSignature.obj \
+ $O\InStreamWithCRC.obj \
+ $O\ItemNameUtils.obj \
+ $O\MultiStream.obj \
+ $O\OutStreamWithCRC.obj \
+ $O\OutStreamWithSha1.obj \
+ $O\HandlerOut.obj \
+ $O\ParseProperties.obj \
+
+7Z_OBJS = \
+ $O\7zCompressionMode.obj \
+ $O\7zDecode.obj \
+ $O\7zEncode.obj \
+ $O\7zExtract.obj \
+ $O\7zFolderInStream.obj \
+ $O\7zHandler.obj \
+ $O\7zHandlerOut.obj \
+ $O\7zHeader.obj \
+ $O\7zIn.obj \
+ $O\7zOut.obj \
+ $O\7zProperties.obj \
+ $O\7zSpecStream.obj \
+ $O\7zUpdate.obj \
+ $O\7zRegister.obj \
+
+CAB_OBJS = \
+ $O\CabBlockInStream.obj \
+ $O\CabHandler.obj \
+ $O\CabHeader.obj \
+ $O\CabIn.obj \
+ $O\CabRegister.obj \
+
+CHM_OBJS = \
+ $O\ChmHandler.obj \
+ $O\ChmIn.obj \
+
+ISO_OBJS = \
+ $O\IsoHandler.obj \
+ $O\IsoHeader.obj \
+ $O\IsoIn.obj \
+ $O\IsoRegister.obj \
+
+NSIS_OBJS = \
+ $O\NsisDecode.obj \
+ $O\NsisHandler.obj \
+ $O\NsisIn.obj \
+ $O\NsisRegister.obj \
+
+RAR_OBJS = \
+ $O\RarHandler.obj \
+ $O\Rar5Handler.obj \
+
+TAR_OBJS = \
+ $O\TarHandler.obj \
+ $O\TarHandlerOut.obj \
+ $O\TarHeader.obj \
+ $O\TarIn.obj \
+ $O\TarOut.obj \
+ $O\TarUpdate.obj \
+ $O\TarRegister.obj \
+
+UDF_OBJS = \
+ $O\UdfHandler.obj \
+ $O\UdfIn.obj \
+
+WIM_OBJS = \
+ $O\WimHandler.obj \
+ $O\WimHandlerOut.obj \
+ $O\WimIn.obj \
+ $O\WimRegister.obj \
+
+ZIP_OBJS = \
+ $O\ZipAddCommon.obj \
+ $O\ZipHandler.obj \
+ $O\ZipHandlerOut.obj \
+ $O\ZipIn.obj \
+ $O\ZipItem.obj \
+ $O\ZipOut.obj \
+ $O\ZipUpdate.obj \
+ $O\ZipRegister.obj \
+
+COMPRESS_OBJS = \
+ $O\Bcj2Coder.obj \
+ $O\Bcj2Register.obj \
+ $O\BcjCoder.obj \
+ $O\BcjRegister.obj \
+ $O\BitlDecoder.obj \
+ $O\BranchMisc.obj \
+ $O\BranchRegister.obj \
+ $O\ByteSwap.obj \
+ $O\BZip2Crc.obj \
+ $O\BZip2Decoder.obj \
+ $O\BZip2Encoder.obj \
+ $O\BZip2Register.obj \
+ $O\CopyCoder.obj \
+ $O\CopyRegister.obj \
+ $O\Deflate64Register.obj \
+ $O\DeflateDecoder.obj \
+ $O\DeflateEncoder.obj \
+ $O\DeflateRegister.obj \
+ $O\DeltaFilter.obj \
+ $O\ImplodeDecoder.obj \
+ $O\LzfseDecoder.obj \
+ $O\LzhDecoder.obj \
+ $O\Lzma2Decoder.obj \
+ $O\Lzma2Encoder.obj \
+ $O\Lzma2Register.obj \
+ $O\LzmaDecoder.obj \
+ $O\LzmaEncoder.obj \
+ $O\LzmaRegister.obj \
+ $O\LzmsDecoder.obj \
+ $O\LzOutWindow.obj \
+ $O\LzxDecoder.obj \
+ $O\PpmdDecoder.obj \
+ $O\PpmdEncoder.obj \
+ $O\PpmdRegister.obj \
+ $O\PpmdZip.obj \
+ $O\QuantumDecoder.obj \
+ $O\Rar1Decoder.obj \
+ $O\Rar2Decoder.obj \
+ $O\Rar3Decoder.obj \
+ $O\Rar3Vm.obj \
+ $O\Rar5Decoder.obj \
+ $O\RarCodecsRegister.obj \
+ $O\ShrinkDecoder.obj \
+ $O\XpressDecoder.obj \
+ $O\XzDecoder.obj \
+ $O\XzEncoder.obj \
+ $O\ZlibDecoder.obj \
+ $O\ZlibEncoder.obj \
+ $O\ZDecoder.obj \
+
+CRYPTO_OBJS = \
+ $O\7zAes.obj \
+ $O\7zAesRegister.obj \
+ $O\HmacSha1.obj \
+ $O\HmacSha256.obj \
+ $O\MyAes.obj \
+ $O\MyAesReg.obj \
+ $O\Pbkdf2HmacSha1.obj \
+ $O\RandGen.obj \
+ $O\Rar20Crypto.obj \
+ $O\Rar5Aes.obj \
+ $O\RarAes.obj \
+ $O\WzAes.obj \
+ $O\ZipCrypto.obj \
+ $O\ZipStrong.obj \
+
+C_OBJS = \
+ $O\7zBuf2.obj \
+ $O\7zStream.obj \
+ $O\Alloc.obj \
+ $O\Bcj2.obj \
+ $O\Bcj2Enc.obj \
+ $O\Blake2s.obj \
+ $O\Bra.obj \
+ $O\Bra86.obj \
+ $O\BraIA64.obj \
+ $O\BwtSort.obj \
+ $O\CpuArch.obj \
+ $O\Delta.obj \
+ $O\HuffEnc.obj \
+ $O\LzFind.obj \
+ $O\LzFindMt.obj \
+ $O\Lzma2Dec.obj \
+ $O\Lzma2DecMt.obj \
+ $O\Lzma2Enc.obj \
+ $O\LzmaDec.obj \
+ $O\LzmaEnc.obj \
+ $O\MtCoder.obj \
+ $O\MtDec.obj \
+ $O\Ppmd7.obj \
+ $O\Ppmd7Dec.obj \
+ $O\Ppmd7aDec.obj \
+ $O\Ppmd7Enc.obj \
+ $O\Ppmd8.obj \
+ $O\Ppmd8Dec.obj \
+ $O\Ppmd8Enc.obj \
+ $O\Sort.obj \
+ $O\SwapBytes.obj \
+ $O\Threads.obj \
+ $O\Xz.obj \
+ $O\XzDec.obj \
+ $O\XzEnc.obj \
+ $O\XzIn.obj \
+
+!include "../../Aes.mak"
+!include "../../Crc.mak"
+!include "../../Crc64.mak"
+!include "../../LzFindOpt.mak"
+!include "../../LzmaDec.mak"
+!include "../../Sha1.mak"
+!include "../../Sha256.mak"
diff --git a/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak b/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak
new file mode 100644
index 0000000..404d917
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zF/Arc_gcc.mak
@@ -0,0 +1,379 @@
+include ../../LzmaDec_gcc.mak
+
+LOCAL_FLAGS_ST =
+MT_OBJS =
+
+ifdef SystemDrive
+IS_MINGW = 1
+else
+ifdef SYSTEMDRIVE
+# ifdef OS
+IS_MINGW = 1
+endif
+endif
+
+ifdef ST_MODE
+
+LOCAL_FLAGS_ST = -DZ7_ST
+
+ifdef IS_MINGW
+MT_OBJS = \
+ $O/Threads.o \
+
+endif
+
+else
+
+MT_OBJS = \
+ $O/LzFindMt.o \
+ $O/LzFindOpt.o \
+ $O/StreamBinder.o \
+ $O/Synchronization.o \
+ $O/VirtThread.o \
+ $O/MemBlocks.o \
+ $O/OutMemStream.o \
+ $O/ProgressMt.o \
+ $O/Threads.o \
+
+endif
+
+
+
+COMMON_OBJS = \
+ $O/CRC.o \
+ $O/CrcReg.o \
+ $O/DynLimBuf.o \
+ $O/IntToString.o \
+ $O/LzFindPrepare.o \
+ $O/MyMap.o \
+ $O/MyString.o \
+ $O/MyVector.o \
+ $O/MyXml.o \
+ $O/NewHandler.o \
+ $O/Sha1Prepare.o \
+ $O/Sha1Reg.o \
+ $O/Sha256Prepare.o \
+ $O/Sha256Reg.o \
+ $O/StringConvert.o \
+ $O/StringToInt.o \
+ $O/UTFConvert.o \
+ $O/Wildcard.o \
+ $O/XzCrc64Init.o \
+ $O/XzCrc64Reg.o \
+
+WIN_OBJS = \
+ $O/FileDir.o \
+ $O/FileFind.o \
+ $O/FileIO.o \
+ $O/FileName.o \
+ $O/PropVariant.o \
+ $O/PropVariantConv.o \
+ $O/PropVariantUtils.o \
+ $O/System.o \
+ $O/TimeUtils.o \
+
+7ZIP_COMMON_OBJS = \
+ $O/CreateCoder.o \
+ $O/CWrappers.o \
+ $O/InBuffer.o \
+ $O/InOutTempBuffer.o \
+ $O/FilterCoder.o \
+ $O/LimitedStreams.o \
+ $O/LockedStream.o \
+ $O/MethodId.o \
+ $O/MethodProps.o \
+ $O/OffsetStream.o \
+ $O/OutBuffer.o \
+ $O/ProgressUtils.o \
+ $O/PropId.o \
+ $O/StreamObjects.o \
+ $O/StreamUtils.o \
+ $O/UniqBlocks.o \
+
+AR_OBJS = \
+ $O/ApfsHandler.o \
+ $O/ApmHandler.o \
+ $O/ArHandler.o \
+ $O/ArjHandler.o \
+ $O/Base64Handler.o \
+ $O/Bz2Handler.o \
+ $O/ComHandler.o \
+ $O/CpioHandler.o \
+ $O/CramfsHandler.o \
+ $O/DeflateProps.o \
+ $O/DmgHandler.o \
+ $O/ElfHandler.o \
+ $O/ExtHandler.o \
+ $O/FatHandler.o \
+ $O/FlvHandler.o \
+ $O/GzHandler.o \
+ $O/GptHandler.o \
+ $O/HandlerCont.o \
+ $O/HfsHandler.o \
+ $O/IhexHandler.o \
+ $O/LpHandler.o \
+ $O/LzhHandler.o \
+ $O/LzmaHandler.o \
+ $O/MachoHandler.o \
+ $O/MbrHandler.o \
+ $O/MslzHandler.o \
+ $O/MubHandler.o \
+ $O/NtfsHandler.o \
+ $O/PeHandler.o \
+ $O/PpmdHandler.o \
+ $O/QcowHandler.o \
+ $O/RpmHandler.o \
+ $O/SparseHandler.o \
+ $O/SplitHandler.o \
+ $O/SquashfsHandler.o \
+ $O/SwfHandler.o \
+ $O/UefiHandler.o \
+ $O/VdiHandler.o \
+ $O/VhdHandler.o \
+ $O/VhdxHandler.o \
+ $O/VmdkHandler.o \
+ $O/XarHandler.o \
+ $O/XzHandler.o \
+ $O/ZHandler.o \
+
+AR_COMMON_OBJS = \
+ $O/CoderMixer2.o \
+ $O/DummyOutStream.o \
+ $O/FindSignature.o \
+ $O/InStreamWithCRC.o \
+ $O/ItemNameUtils.o \
+ $O/MultiStream.o \
+ $O/OutStreamWithCRC.o \
+ $O/OutStreamWithSha1.o \
+ $O/HandlerOut.o \
+ $O/ParseProperties.o \
+
+
+7Z_OBJS = \
+ $O/7zCompressionMode.o \
+ $O/7zDecode.o \
+ $O/7zEncode.o \
+ $O/7zExtract.o \
+ $O/7zFolderInStream.o \
+ $O/7zHandler.o \
+ $O/7zHandlerOut.o \
+ $O/7zHeader.o \
+ $O/7zIn.o \
+ $O/7zOut.o \
+ $O/7zProperties.o \
+ $O/7zSpecStream.o \
+ $O/7zUpdate.o \
+ $O/7zRegister.o \
+
+CAB_OBJS = \
+ $O/CabBlockInStream.o \
+ $O/CabHandler.o \
+ $O/CabHeader.o \
+ $O/CabIn.o \
+ $O/CabRegister.o \
+
+CHM_OBJS = \
+ $O/ChmHandler.o \
+ $O/ChmIn.o \
+
+ISO_OBJS = \
+ $O/IsoHandler.o \
+ $O/IsoHeader.o \
+ $O/IsoIn.o \
+ $O/IsoRegister.o \
+
+NSIS_OBJS = \
+ $O/NsisDecode.o \
+ $O/NsisHandler.o \
+ $O/NsisIn.o \
+ $O/NsisRegister.o \
+
+ifndef DISABLE_RAR
+RAR_OBJS = \
+ $O/RarHandler.o \
+ $O/Rar5Handler.o \
+
+endif
+
+
+TAR_OBJS = \
+ $O/TarHandler.o \
+ $O/TarHandlerOut.o \
+ $O/TarHeader.o \
+ $O/TarIn.o \
+ $O/TarOut.o \
+ $O/TarUpdate.o \
+ $O/TarRegister.o \
+
+UDF_OBJS = \
+ $O/UdfHandler.o \
+ $O/UdfIn.o \
+
+WIM_OBJS = \
+ $O/WimHandler.o \
+ $O/WimHandlerOut.o \
+ $O/WimIn.o \
+ $O/WimRegister.o \
+
+ZIP_OBJS = \
+ $O/ZipAddCommon.o \
+ $O/ZipHandler.o \
+ $O/ZipHandlerOut.o \
+ $O/ZipIn.o \
+ $O/ZipItem.o \
+ $O/ZipOut.o \
+ $O/ZipUpdate.o \
+ $O/ZipRegister.o \
+
+COMPRESS_OBJS = \
+ $O/Bcj2Coder.o \
+ $O/Bcj2Register.o \
+ $O/BcjCoder.o \
+ $O/BcjRegister.o \
+ $O/BitlDecoder.o \
+ $O/BranchMisc.o \
+ $O/BranchRegister.o \
+ $O/ByteSwap.o \
+ $O/BZip2Crc.o \
+ $O/BZip2Decoder.o \
+ $O/BZip2Encoder.o \
+ $O/BZip2Register.o \
+ $O/CopyCoder.o \
+ $O/CopyRegister.o \
+ $O/Deflate64Register.o \
+ $O/DeflateDecoder.o \
+ $O/DeflateEncoder.o \
+ $O/DeflateRegister.o \
+ $O/DeltaFilter.o \
+ $O/ImplodeDecoder.o \
+ $O/LzfseDecoder.o \
+ $O/LzhDecoder.o \
+ $O/Lzma2Decoder.o \
+ $O/Lzma2Encoder.o \
+ $O/Lzma2Register.o \
+ $O/LzmaDecoder.o \
+ $O/LzmaEncoder.o \
+ $O/LzmaRegister.o \
+ $O/LzmsDecoder.o \
+ $O/LzOutWindow.o \
+ $O/LzxDecoder.o \
+ $O/PpmdDecoder.o \
+ $O/PpmdEncoder.o \
+ $O/PpmdRegister.o \
+ $O/PpmdZip.o \
+ $O/QuantumDecoder.o \
+ $O/ShrinkDecoder.o \
+ $O/XpressDecoder.o \
+ $O/XzDecoder.o \
+ $O/XzEncoder.o \
+ $O/ZlibDecoder.o \
+ $O/ZlibEncoder.o \
+ $O/ZDecoder.o \
+
+ifdef DISABLE_RAR
+DISABLE_RAR_COMPRESS=1
+endif
+
+ifndef DISABLE_RAR_COMPRESS
+COMPRESS_OBJS += \
+ $O/Rar1Decoder.o \
+ $O/Rar2Decoder.o \
+ $O/Rar3Decoder.o \
+ $O/Rar3Vm.o \
+ $O/Rar5Decoder.o \
+ $O/RarCodecsRegister.o \
+
+endif
+
+CRYPTO_OBJS = \
+ $O/7zAes.o \
+ $O/7zAesRegister.o \
+ $O/HmacSha1.o \
+ $O/HmacSha256.o \
+ $O/MyAes.o \
+ $O/MyAesReg.o \
+ $O/Pbkdf2HmacSha1.o \
+ $O/RandGen.o \
+ $O/WzAes.o \
+ $O/ZipCrypto.o \
+ $O/ZipStrong.o \
+
+ifndef DISABLE_RAR
+CRYPTO_OBJS += \
+ $O/Rar20Crypto.o \
+ $O/Rar5Aes.o \
+ $O/RarAes.o \
+
+endif
+
+
+C_OBJS = \
+ $O/7zBuf2.o \
+ $O/7zStream.o \
+ $O/Alloc.o \
+ $O/Bcj2.o \
+ $O/Bcj2Enc.o \
+ $O/Blake2s.o \
+ $O/Bra.o \
+ $O/Bra86.o \
+ $O/BraIA64.o \
+ $O/BwtSort.o \
+ $O/CpuArch.o \
+ $O/Delta.o \
+ $O/HuffEnc.o \
+ $O/LzFind.o \
+ $O/Lzma2Dec.o \
+ $O/Lzma2DecMt.o \
+ $O/Lzma2Enc.o \
+ $O/LzmaDec.o \
+ $O/LzmaEnc.o \
+ $O/MtCoder.o \
+ $O/MtDec.o \
+ $O/Ppmd7.o \
+ $O/Ppmd7Dec.o \
+ $O/Ppmd7aDec.o \
+ $O/Ppmd7Enc.o \
+ $O/Ppmd8.o \
+ $O/Ppmd8Dec.o \
+ $O/Ppmd8Enc.o \
+ $O/Sort.o \
+ $O/Xz.o \
+ $O/XzDec.o \
+ $O/XzEnc.o \
+ $O/XzIn.o \
+ $O/XzCrc64.o \
+ $O/XzCrc64Opt.o \
+ $O/7zCrc.o \
+ $O/7zCrcOpt.o \
+ $O/Aes.o \
+ $O/AesOpt.o \
+ $O/Sha256.o \
+ $O/Sha256Opt.o \
+ $O/Sha1.o \
+ $O/Sha1Opt.o \
+ $O/SwapBytes.o \
+
+ARC_OBJS = \
+ $(LZMA_DEC_OPT_OBJS) \
+ $(C_OBJS) \
+ $(MT_OBJS) \
+ $(COMMON_OBJS) \
+ $(WIN_OBJS) \
+ $(7ZIP_COMMON_OBJS) \
+ $(AR_OBJS) \
+ $(AR_COMMON_OBJS) \
+ $(7Z_OBJS) \
+ $(CAB_OBJS) \
+ $(CHM_OBJS) \
+ $(COM_OBJS) \
+ $(ISO_OBJS) \
+ $(NSIS_OBJS) \
+ $(RAR_OBJS) \
+ $(TAR_OBJS) \
+ $(UDF_OBJS) \
+ $(WIM_OBJS) \
+ $(ZIP_OBJS) \
+ $(COMPRESS_OBJS) \
+ $(CRYPTO_OBJS) \
+
+# we need empty line after last line above
diff --git a/CPP/7zip/Bundles/Format7zF/Format7z.dsp b/CPP/7zip/Bundles/Format7zF/Format7z.dsp
new file mode 100644
index 0000000..a0c5d83
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zF/Format7z.dsp
@@ -0,0 +1,3266 @@
+# Microsoft Developer Studio Project File - Name="7z" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=7z - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "Format7z.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "Format7z.mak" CFG="7z - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "7z - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "7z - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /D "Z7_EXTERNAL_CODECS" /D "Z7_LARGE_PAGES" /D "Z7_ST_9" /FAcs /Yu"StdAfx.h" /FD /GF /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Util\7z.dll" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none /debug
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /Gr /MTd /W4 /WX /Gm /GX /ZI /Od /I "..\..\..\..\SDK" /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "MY7Z_EXPORTS" /D "Z7_EXTERNAL_CODECS" /D "Z7_LARGE_PAGES" /D "Z7_ST_9" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\7z.dll" /pdbtype:sept /ignore:4033
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "7z - Win32 Release"
+# Name "7z - Win32 Debug"
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Group "Icons"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\7z.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\arj.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\bz2.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\cab.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\cpio.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\deb.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\dmg.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\fat.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\gz.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\hfs.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\iso.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\lzh.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\lzma.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\ntfs.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\rar.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\rpm.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\split.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\squashfs.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\tar.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\vhd.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\wim.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\xar.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\xz.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\z.ico
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Icons\zip.ico
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\Archive\Archive2.def
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\ArchiveExports.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CodecExports.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\DllExports2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"StdAfx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\Common.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ComTry.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CrcReg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynamicBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynLimBuf.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynLimBuf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\LzFindPrepare.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyBuffer2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyCom.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyException.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyInitGuid.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyLinux.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyMap.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyMap.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyUnknown.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyWindows.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyXml.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyXml.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Sha1Prepare.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Sha1Reg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Sha256Prepare.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Sha256Reg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\XzCrc64Init.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\XzCrc64Reg.cpp
+# End Source File
+# End Group
+# Begin Group "Compress"
+
+# PROP Default_Filter ""
+# Begin Group "Bit Coder"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\BitlDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BitlDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BitlEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BitmDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BitmEncoder.h
+# End Source File
+# End Group
+# Begin Group "Rar Compress"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\Rar1Decoder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Rar1Decoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Rar2Decoder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Rar2Decoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Rar3Decoder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Rar3Decoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Rar3Vm.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Rar3Vm.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Rar5Decoder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Rar5Decoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\RarCodecsRegister.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# End Group
+# Begin Group "BZip2 Compress"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\BZip2Const.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BZip2Crc.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BZip2Crc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BZip2Decoder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BZip2Decoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BZip2Encoder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BZip2Encoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BZip2Register.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Mtf8.h
+# End Source File
+# End Group
+# Begin Group "Zip Compress"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\Deflate64Register.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\DeflateConst.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\DeflateDecoder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\DeflateDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\DeflateEncoder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\DeflateEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\DeflateRegister.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\ImplodeDecoder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\ImplodeDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdZip.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdZip.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\ShrinkDecoder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\ShrinkDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\ZlibDecoder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\ZlibDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\ZlibEncoder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\ZlibEncoder.h
+# End Source File
+# End Group
+# Begin Group "7z Compress"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\Bcj2Coder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Bcj2Coder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Bcj2Register.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BcjCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BcjCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BcjRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchMisc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchMisc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\ByteSwap.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\DeltaFilter.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Decoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Decoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Encoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Encoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Register.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaEncoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdDecoder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdEncoder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdRegister.cpp
+# End Source File
+# End Group
+# Begin Group "Cab Compress"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzx.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzxDecoder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzxDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\QuantumDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\QuantumDecoder.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\Compress\HuffmanDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzfseDecoder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzfseDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzhDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzhDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmsDecoder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmsDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzOutWindow.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzOutWindow.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\XpressDecoder.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\XpressDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\XzDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\XzDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\XzEncoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\XzEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\ZDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\ZDecoder.h
+# End Source File
+# End Group
+# Begin Group "Crypto"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Crypto\7zAes.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\7zAes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\7zAesRegister.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\HmacSha1.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\HmacSha1.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\HmacSha256.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\HmacSha256.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\MyAes.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\MyAes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\MyAesReg.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\Pbkdf2HmacSha1.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\Pbkdf2HmacSha1.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\RandGen.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\RandGen.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\Rar20Crypto.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\Rar20Crypto.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\Rar5Aes.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\Rar5Aes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\RarAes.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\RarAes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\Sha1Cls.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\WzAes.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\WzAes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\ZipCrypto.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\ZipCrypto.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\ZipStrong.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\ZipStrong.h
+# End Source File
+# End Group
+# Begin Group "7zip Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CWrappers.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CWrappers.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InOutTempBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InOutTempBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MemBlocks.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MemBlocks.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodId.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodId.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OffsetStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OffsetStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutMemStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutMemStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressMt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\PropId.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\RegisterArc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\RegisterCodec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamBinder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamBinder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\UniqBlocks.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\UniqBlocks.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\VirtThread.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\VirtThread.h
+# End Source File
+# End Group
+# Begin Group "C"
+
+# PROP Default_Filter ""
+# Begin Group "xz"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Xz.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /W4
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# ADD CPP /W4 /WX
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Xz.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzCrc64.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /W4 /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# ADD CPP /W4 /WX
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzCrc64.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzCrc64Opt.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzDec.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /W4
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# ADD CPP /W4 /WX
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzEnc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzEnc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\XzIn.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /W4
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# ADD CPP /W4 /WX
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zBuf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zBuf2.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zStream.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zVersion.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Aes.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Aes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bcj2.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bcj2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bcj2Enc.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Blake2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Blake2s.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra86.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\BraIA64.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\BwtSort.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\BwtSort.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Delta.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Delta.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\HuffEnc.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\HuffEnc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFind.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFindMt.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFindMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFindOpt.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzHash.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Dec.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Dec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2DecMt.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2DecMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Enc.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Enc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaDec.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaDec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaEnc.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaEnc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtCoder.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtDec.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtDec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd7.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd7.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd7aDec.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd7Dec.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd7Enc.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd8.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd8.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd8Dec.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd8Enc.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Precomp.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\RotateDefs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha1.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha1.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha256.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha256.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sort.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sort.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\SwapBytes.c
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\SwapBytes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.h
+# End Source File
+# End Group
+# Begin Group "Archive"
+
+# PROP Default_Filter ""
+# Begin Group "7z"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zCompressionMode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zCompressionMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zDecode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zEncode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zEncode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zExtract.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zFolderInStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zFolderInStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandlerOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHeader.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zOut.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zProperties.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zSpecStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zSpecStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zUpdate.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zUpdate.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zUpdateItem.h
+# End Source File
+# End Group
+# Begin Group "Rar"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Rar\Rar5Handler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Rar\Rar5Handler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Rar\RarHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Rar\RarHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Rar\RarHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Rar\RarItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Rar\RarVol.h
+# End Source File
+# End Group
+# Begin Group "Cab"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabBlockInStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabBlockInStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabHeader.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Cab\CabRegister.cpp
+# End Source File
+# End Group
+# Begin Group "Chm"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Chm\ChmHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Chm\ChmHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Chm\ChmIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Chm\ChmIn.h
+# End Source File
+# End Group
+# Begin Group "Archive common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\DummyOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\DummyOutStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\FindSignature.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\FindSignature.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\HandlerOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\HandlerOut.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\InStreamWithCRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\InStreamWithCRC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\MultiStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\MultiStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithSha1.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithSha1.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ParseProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ParseProperties.h
+# End Source File
+# End Group
+# Begin Group "Iso"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Iso\IsoHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Iso\IsoHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Iso\IsoHeader.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Iso\IsoHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Iso\IsoIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Iso\IsoIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Iso\IsoItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Iso\IsoRegister.cpp
+# End Source File
+# End Group
+# Begin Group "Nsis"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Nsis\NsisDecode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Nsis\NsisDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Nsis\NsisHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Nsis\NsisHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Nsis\NsisIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Nsis\NsisIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Nsis\NsisRegister.cpp
+# End Source File
+# End Group
+# Begin Group "Tar"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarHandlerOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarHeader.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarOut.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarUpdate.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Tar\TarUpdate.h
+# End Source File
+# End Group
+# Begin Group "Zip"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipAddCommon.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipAddCommon.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipCompressionMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipHandlerOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipItem.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipOut.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipUpdate.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Zip\ZipUpdate.h
+# End Source File
+# End Group
+# Begin Group "Wim"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Wim\WimHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Wim\WimHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Wim\WimHandlerOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Wim\WimIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Wim\WimIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Wim\WimRegister.cpp
+# End Source File
+# End Group
+# Begin Group "Udf"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Udf\UdfHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Udf\UdfHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Udf\UdfIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Udf\UdfIn.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\Archive\ApfsHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\ApmHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\ArHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\ArjHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Base64Handler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Bz2Handler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\ComHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\CpioHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\CramfsHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\DeflateProps.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\DeflateProps.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\DmgHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\ElfHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\ExtHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\FatHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\FlvHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\GptHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\GzHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\HandlerCont.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\HandlerCont.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\HfsHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\HfsHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\IArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\IhexHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\LpHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\LzhHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\LzmaHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\MachoHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\MbrHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\MslzHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\MubHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\NtfsHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\PeHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\PpmdHandler.cpp
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\QcowHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\RpmHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\SparseHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\SplitHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\SquashfsHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\SwfHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\UefiHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\VdiHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\VhdHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\VhdxHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\VmdkHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\XarHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\XzHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\XzHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\ZHandler.cpp
+# End Source File
+# End Group
+# Begin Group "7zip"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\ICoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IDecl.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IPassword.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IProgress.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\MyVersion.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\PropID.h
+# End Source File
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Handle.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\NtCheck.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Thread.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\TimeUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\TimeUtils.h
+# End Source File
+# End Group
+# Begin Group "Asm"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\Asm\x86\7zAsm.asm
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\Asm\x86\7zCrcOpt.asm
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\Release
+InputPath=..\..\..\..\Asm\x86\7zCrcOpt.asm
+InputName=7zCrcOpt
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml.exe -c -Fo$(OutDir)\$(InputName).obj $(InputPath)
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\Debug
+InputPath=..\..\..\..\Asm\x86\7zCrcOpt.asm
+InputName=7zCrcOpt
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml.exe -c -omf -Fo$(OutDir)\$(InputName).obj $(InputPath)
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\Asm\x86\AesOpt.asm
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build
+OutDir=.\Release
+InputPath=..\..\..\..\Asm\x86\AesOpt.asm
+InputName=AesOpt
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml.exe -c -Fo$(OutDir)\$(InputName).obj $(InputPath)
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# PROP Ignore_Default_Tool 1
+# Begin Custom Build
+OutDir=.\Debug
+InputPath=..\..\..\..\Asm\x86\AesOpt.asm
+InputName=AesOpt
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml.exe -c -omf -WX -W3 -Fo$(OutDir)\$(InputName).obj $(InputPath)
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\Asm\x86\Sha1Opt.asm
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\Release
+InputPath=..\..\..\..\Asm\x86\Sha1Opt.asm
+InputName=Sha1Opt
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml.exe -c -Fo$(OutDir)\$(InputName).obj $(InputPath)
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\Debug
+InputPath=..\..\..\..\Asm\x86\Sha1Opt.asm
+InputName=Sha1Opt
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml.exe -c -omf -Fo$(OutDir)\$(InputName).obj $(InputPath)
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\Asm\x86\Sha256Opt.asm
+
+!IF "$(CFG)" == "7z - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\Release
+InputPath=..\..\..\..\Asm\x86\Sha256Opt.asm
+InputName=Sha256Opt
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml.exe -c -Fo$(OutDir)\$(InputName).obj $(InputPath)
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "7z - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\Debug
+InputPath=..\..\..\..\Asm\x86\Sha256Opt.asm
+InputName=Sha256Opt
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml.exe -c -omf -Fo$(OutDir)\$(InputName).obj $(InputPath)
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/CPP/7zip/Bundles/Format7zF/Format7z.dsw b/CPP/7zip/Bundles/Format7zF/Format7z.dsw
new file mode 100644
index 0000000..324dab1
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zF/Format7z.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "7z"=.\Format7z.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/Bundles/Format7zF/StdAfx.cpp b/CPP/7zip/Bundles/Format7zF/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zF/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/Format7zF/StdAfx.h b/CPP/7zip/Bundles/Format7zF/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zF/StdAfx.h
@@ -0,0 +1,11 @@
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Bundles/Format7zF/makefile b/CPP/7zip/Bundles/Format7zF/makefile
new file mode 100644
index 0000000..3487596
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zF/makefile
@@ -0,0 +1,21 @@
+PROG = 7z.dll
+# USE_C_LZFINDOPT = 1
+DEF_FILE = ../../Archive/Archive2.def
+CFLAGS = $(CFLAGS) \
+ -DZ7_EXTERNAL_CODECS \
+
+!IFNDEF UNDER_CE
+CFLAGS = $(CFLAGS) -DZ7_LARGE_PAGES
+!ENDIF
+
+!include "Arc.mak"
+
+COMPRESS_OBJS = $(COMPRESS_OBJS) \
+ $O\CodecExports.obj \
+
+AR_OBJS = $(AR_OBJS) \
+ $O\ArchiveExports.obj \
+ $O\DllExports2.obj \
+
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/Bundles/Format7zF/makefile.gcc b/CPP/7zip/Bundles/Format7zF/makefile.gcc
new file mode 100644
index 0000000..fc65795
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zF/makefile.gcc
@@ -0,0 +1,55 @@
+PROG = 7z
+DEF_FILE = ../../Archive/Archive2.def
+
+# IS_X64 = 1
+# USE_ASM = 1
+# ST_MODE = 1
+
+include Arc_gcc.mak
+
+ifdef SystemDrive
+IS_MINGW = 1
+else
+ifdef SYSTEMDRIVE
+# ifdef OS
+IS_MINGW = 1
+endif
+endif
+
+
+ifdef IS_MINGW
+
+LOCAL_FLAGS_WIN = \
+ -DZ7_LARGE_PAGES \
+ $(LOCAL_FLAGS_ST) \
+
+SYS_OBJS = \
+ $O/resource.o \
+
+else
+
+SYS_OBJS = \
+ $O/MyWindows.o \
+
+endif
+
+LOCAL_FLAGS = \
+ -DZ7_EXTERNAL_CODECS \
+ $(LOCAL_FLAGS_WIN) \
+ $(LOCAL_FLAGS_ST) \
+
+
+COMPRESS_OBJS_2 = \
+ $O/CodecExports.o \
+
+AR_OBJS_2 = \
+ $O/ArchiveExports.o \
+ $O/DllExports2.o \
+
+OBJS = \
+ $(ARC_OBJS) \
+ $(AR_OBJS_2) \
+ $(COMPRESS_OBJS_2) \
+ $(SYS_OBJS) \
+
+include ../../7zip_gcc.mak
diff --git a/CPP/7zip/Bundles/Format7zF/resource.rc b/CPP/7zip/Bundles/Format7zF/resource.rc
new file mode 100644
index 0000000..9c797c1
--- /dev/null
+++ b/CPP/7zip/Bundles/Format7zF/resource.rc
@@ -0,0 +1,38 @@
+#include "../../MyVersionInfo.rc"
+
+MY_VERSION_INFO_DLL("7z Plugin" , "7z")
+
+
+0 ICON "../../Archive/Icons/7z.ico"
+1 ICON "../../Archive/Icons/zip.ico"
+2 ICON "../../Archive/Icons/bz2.ico"
+3 ICON "../../Archive/Icons/rar.ico"
+4 ICON "../../Archive/Icons/arj.ico"
+5 ICON "../../Archive/Icons/z.ico"
+6 ICON "../../Archive/Icons/lzh.ico"
+7 ICON "../../Archive/Icons/cab.ico"
+8 ICON "../../Archive/Icons/iso.ico"
+9 ICON "../../Archive/Icons/split.ico"
+10 ICON "../../Archive/Icons/rpm.ico"
+11 ICON "../../Archive/Icons/deb.ico"
+12 ICON "../../Archive/Icons/cpio.ico"
+13 ICON "../../Archive/Icons/tar.ico"
+14 ICON "../../Archive/Icons/gz.ico"
+15 ICON "../../Archive/Icons/wim.ico"
+16 ICON "../../Archive/Icons/lzma.ico"
+17 ICON "../../Archive/Icons/dmg.ico"
+18 ICON "../../Archive/Icons/hfs.ico"
+19 ICON "../../Archive/Icons/xar.ico"
+20 ICON "../../Archive/Icons/vhd.ico"
+21 ICON "../../Archive/Icons/fat.ico"
+22 ICON "../../Archive/Icons/ntfs.ico"
+23 ICON "../../Archive/Icons/xz.ico"
+24 ICON "../../Archive/Icons/squashfs.ico"
+25 ICON "../../Archive/Icons/apfs.ico"
+
+
+
+STRINGTABLE
+BEGIN
+ 100 "7z:0 zip:1 rar:3 001:9 cab:7 iso:8 xz:23 txz:23 lzma:16 tar:13 cpio:12 bz2:2 bzip2:2 tbz2:2 tbz:2 gz:14 gzip:14 tgz:14 tpz:14 z:5 taz:5 lzh:6 lha:6 rpm:10 deb:11 arj:4 vhd:20 vhdx:20 wim:15 swm:15 esd:15 fat:21 ntfs:22 dmg:17 hfs:18 xar:19 squashfs:24 apfs:25"
+END
diff --git a/CPP/7zip/Bundles/Format7zR/StdAfx.cpp b/CPP/7zip/Bundles/Format7zR/StdAfx.cpp
index c6d3b1f..d0feea8 100644
--- a/CPP/7zip/Bundles/Format7zR/StdAfx.cpp
+++ b/CPP/7zip/Bundles/Format7zR/StdAfx.cpp
@@ -1,3 +1,3 @@
-// StdAfx.cpp
-
-#include "StdAfx.h"
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/Format7zR/StdAfx.h b/CPP/7zip/Bundles/Format7zR/StdAfx.h
index 59d9ac1..035267c 100644
--- a/CPP/7zip/Bundles/Format7zR/StdAfx.h
+++ b/CPP/7zip/Bundles/Format7zR/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "../../../Common/Common.h"
-
-#endif
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Bundles/Format7zR/makefile b/CPP/7zip/Bundles/Format7zR/makefile
index 6a9dfb9..2449755 100644
--- a/CPP/7zip/Bundles/Format7zR/makefile
+++ b/CPP/7zip/Bundles/Format7zR/makefile
@@ -1,116 +1,120 @@
-PROG = 7zra.dll
-DEF_FILE = ../../Archive/Archive2.def
-CFLAGS = $(CFLAGS) \
- -D_NO_CRYPTO
-
-COMMON_OBJS = \
- $O\CRC.obj \
- $O\CrcReg.obj \
- $O\IntToString.obj \
- $O\NewHandler.obj \
- $O\MyString.obj \
- $O\StringConvert.obj \
- $O\StringToInt.obj \
- $O\MyVector.obj \
- $O\Wildcard.obj \
-
-WIN_OBJS = \
- $O\FileDir.obj \
- $O\FileFind.obj \
- $O\FileIO.obj \
- $O\FileName.obj \
- $O\PropVariant.obj \
- $O\Synchronization.obj \
- $O\System.obj \
-
-7ZIP_COMMON_OBJS = \
- $O\CreateCoder.obj \
- $O\CWrappers.obj \
- $O\InBuffer.obj \
- $O\InOutTempBuffer.obj \
- $O\FilterCoder.obj \
- $O\LimitedStreams.obj \
- $O\MethodId.obj \
- $O\MethodProps.obj \
- $O\OutBuffer.obj \
- $O\ProgressUtils.obj \
- $O\PropId.obj \
- $O\StreamBinder.obj \
- $O\StreamObjects.obj \
- $O\StreamUtils.obj \
- $O\UniqBlocks.obj \
- $O\VirtThread.obj \
-
-AR_OBJS = \
- $O\ArchiveExports.obj \
- $O\DllExports2.obj \
-
-AR_COMMON_OBJS = \
- $O\CoderMixer2.obj \
- $O\HandlerOut.obj \
- $O\InStreamWithCRC.obj \
- $O\ItemNameUtils.obj \
- $O\OutStreamWithCRC.obj \
- $O\ParseProperties.obj \
-
-
-7Z_OBJS = \
- $O\7zCompressionMode.obj \
- $O\7zDecode.obj \
- $O\7zEncode.obj \
- $O\7zExtract.obj \
- $O\7zFolderInStream.obj \
- $O\7zHandler.obj \
- $O\7zHandlerOut.obj \
- $O\7zHeader.obj \
- $O\7zIn.obj \
- $O\7zOut.obj \
- $O\7zProperties.obj \
- $O\7zSpecStream.obj \
- $O\7zUpdate.obj \
- $O\7zRegister.obj \
-
-
-COMPRESS_OBJS = \
- $O\CodecExports.obj \
- $O\Bcj2Coder.obj \
- $O\Bcj2Register.obj \
- $O\BcjCoder.obj \
- $O\BcjRegister.obj \
- $O\BranchMisc.obj \
- $O\BranchRegister.obj \
- $O\ByteSwap.obj \
- $O\CopyCoder.obj \
- $O\CopyRegister.obj \
- $O\DeltaFilter.obj \
- $O\Lzma2Decoder.obj \
- $O\Lzma2Encoder.obj \
- $O\Lzma2Register.obj \
- $O\LzmaDecoder.obj \
- $O\LzmaEncoder.obj \
- $O\LzmaRegister.obj \
-
-C_OBJS = \
- $O\Alloc.obj \
- $O\Bcj2.obj \
- $O\Bcj2Enc.obj \
- $O\Bra.obj \
- $O\Bra86.obj \
- $O\BraIA64.obj \
- $O\CpuArch.obj \
- $O\Delta.obj \
- $O\LzFind.obj \
- $O\LzFindMt.obj \
- $O\Lzma2Dec.obj \
- $O\Lzma2DecMt.obj \
- $O\Lzma2Enc.obj \
- $O\LzmaDec.obj \
- $O\LzmaEnc.obj \
- $O\MtCoder.obj \
- $O\MtDec.obj \
- $O\Threads.obj \
-
-!include "../../Crc.mak"
-!include "../../LzmaDec.mak"
-
-!include "../../7zip.mak"
+PROG = 7zra.dll
+DEF_FILE = ../../Archive/Archive2.def
+CFLAGS = $(CFLAGS) \
+ -DZ7_NO_CRYPTO
+
+COMMON_OBJS = \
+ $O\CRC.obj \
+ $O\CrcReg.obj \
+ $O\IntToString.obj \
+ $O\LzFindPrepare.obj \
+ $O\NewHandler.obj \
+ $O\MyString.obj \
+ $O\StringConvert.obj \
+ $O\StringToInt.obj \
+ $O\MyVector.obj \
+ $O\Wildcard.obj \
+
+WIN_OBJS = \
+ $O\FileDir.obj \
+ $O\FileFind.obj \
+ $O\FileIO.obj \
+ $O\FileName.obj \
+ $O\PropVariant.obj \
+ $O\Synchronization.obj \
+ $O\System.obj \
+
+7ZIP_COMMON_OBJS = \
+ $O\CreateCoder.obj \
+ $O\CWrappers.obj \
+ $O\InBuffer.obj \
+ $O\InOutTempBuffer.obj \
+ $O\FilterCoder.obj \
+ $O\LimitedStreams.obj \
+ $O\MethodId.obj \
+ $O\MethodProps.obj \
+ $O\OutBuffer.obj \
+ $O\ProgressUtils.obj \
+ $O\PropId.obj \
+ $O\StreamBinder.obj \
+ $O\StreamObjects.obj \
+ $O\StreamUtils.obj \
+ $O\UniqBlocks.obj \
+ $O\VirtThread.obj \
+
+AR_OBJS = \
+ $O\ArchiveExports.obj \
+ $O\DllExports2.obj \
+
+AR_COMMON_OBJS = \
+ $O\CoderMixer2.obj \
+ $O\HandlerOut.obj \
+ $O\InStreamWithCRC.obj \
+ $O\ItemNameUtils.obj \
+ $O\OutStreamWithCRC.obj \
+ $O\ParseProperties.obj \
+
+
+7Z_OBJS = \
+ $O\7zCompressionMode.obj \
+ $O\7zDecode.obj \
+ $O\7zEncode.obj \
+ $O\7zExtract.obj \
+ $O\7zFolderInStream.obj \
+ $O\7zHandler.obj \
+ $O\7zHandlerOut.obj \
+ $O\7zHeader.obj \
+ $O\7zIn.obj \
+ $O\7zOut.obj \
+ $O\7zProperties.obj \
+ $O\7zSpecStream.obj \
+ $O\7zUpdate.obj \
+ $O\7zRegister.obj \
+
+
+COMPRESS_OBJS = \
+ $O\CodecExports.obj \
+ $O\Bcj2Coder.obj \
+ $O\Bcj2Register.obj \
+ $O\BcjCoder.obj \
+ $O\BcjRegister.obj \
+ $O\BranchMisc.obj \
+ $O\BranchRegister.obj \
+ $O\ByteSwap.obj \
+ $O\CopyCoder.obj \
+ $O\CopyRegister.obj \
+ $O\DeltaFilter.obj \
+ $O\Lzma2Decoder.obj \
+ $O\Lzma2Encoder.obj \
+ $O\Lzma2Register.obj \
+ $O\LzmaDecoder.obj \
+ $O\LzmaEncoder.obj \
+ $O\LzmaRegister.obj \
+
+C_OBJS = \
+ $O\7zStream.obj \
+ $O\Alloc.obj \
+ $O\Bcj2.obj \
+ $O\Bcj2Enc.obj \
+ $O\Bra.obj \
+ $O\Bra86.obj \
+ $O\BraIA64.obj \
+ $O\CpuArch.obj \
+ $O\Delta.obj \
+ $O\LzFind.obj \
+ $O\LzFindMt.obj \
+ $O\Lzma2Dec.obj \
+ $O\Lzma2DecMt.obj \
+ $O\Lzma2Enc.obj \
+ $O\LzmaDec.obj \
+ $O\LzmaEnc.obj \
+ $O\MtCoder.obj \
+ $O\MtDec.obj \
+ $O\SwapBytes.obj \
+ $O\Threads.obj \
+
+!include "../../Crc.mak"
+!include "../../LzFindOpt.mak"
+!include "../../LzmaDec.mak"
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/Bundles/Format7zR/resource.rc b/CPP/7zip/Bundles/Format7zR/resource.rc
index 262125c..a8baa59 100644
--- a/CPP/7zip/Bundles/Format7zR/resource.rc
+++ b/CPP/7zip/Bundles/Format7zR/resource.rc
@@ -1,5 +1,5 @@
-#include "../../../../C/7zVersion.rc"
-
-MY_VERSION_INFO_DLL("7z Reduced Standalone Plugin", "7zr")
-
-101 ICON "../../Archive/Icons/7z.ico"
+#include "../../../../C/7zVersion.rc"
+
+MY_VERSION_INFO_DLL("7z Reduced Standalone Plugin", "7zr")
+
+101 ICON "../../Archive/Icons/7z.ico"
diff --git a/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp b/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp
index f273337..ac1334f 100644
--- a/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp
+++ b/CPP/7zip/Bundles/LzmaCon/LzmaAlone.cpp
@@ -1,799 +1,808 @@
-// LzmaAlone.cpp
-
-#include "StdAfx.h"
-
-#include <stdio.h>
-
-#include "../../../../C/CpuArch.h"
-
-#if (defined(_WIN32) || defined(OS2) || defined(MSDOS)) && !defined(UNDER_CE)
-#include <fcntl.h>
-#include <io.h>
-#define MY_SET_BINARY_MODE(file) _setmode(_fileno(file), O_BINARY)
-#else
-#define MY_SET_BINARY_MODE(file)
-#endif
-
-#include "../../../Common/MyWindows.h"
-#include "../../../Common/MyInitGuid.h"
-
-#include "../../../../C/7zVersion.h"
-#include "../../../../C/Alloc.h"
-#include "../../../../C/Lzma86.h"
-
-#include "../../../Windows/NtCheck.h"
-
-#ifndef _7ZIP_ST
-#include "../../../Windows/System.h"
-#endif
-
-#include "../../../Common/IntToString.h"
-#include "../../../Common/CommandLineParser.h"
-#include "../../../Common/StringConvert.h"
-#include "../../../Common/StringToInt.h"
-
-#include "../../Common/FileStreams.h"
-#include "../../Common/StreamUtils.h"
-
-#include "../../Compress/LzmaDecoder.h"
-#include "../../Compress/LzmaEncoder.h"
-
-#include "../../UI/Console/BenchCon.h"
-#include "../../UI/Console/ConsoleClose.h"
-
-bool g_LargePagesMode = false;
-
-using namespace NCommandLineParser;
-
-static const unsigned kDictSizeLog = 24;
-
-#define kCopyrightString "\nLZMA " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n\n"
-
-static const char * const kHelpString =
- "Usage: lzma <command> [inputFile] [outputFile] [<switches>...]\n"
- "\n"
- "<command>\n"
- " e : Encode file\n"
- " d : Decode file\n"
- " b : Benchmark\n"
- "<switches>\n"
- " -a{N} : set compression mode : [0, 1] : default = 1 (max)\n"
- " -d{N} : set dictionary size : [12, 30] : default = 24 (16 MiB)\n"
- " -fb{N} : set number of fast bytes : [5, 273] : default = 128\n"
- " -mc{N} : set number of cycles for match finder\n"
- " -lc{N} : set number of literal context bits : [0, 8] : default = 3\n"
- " -lp{N} : set number of literal pos bits : [0, 4] : default = 0\n"
- " -pb{N} : set number of pos bits : [0, 4] : default = 2\n"
- " -mf{M} : set match finder: [hc4, bt2, bt3, bt4] : default = bt4\n"
- " -mt{N} : set number of CPU threads\n"
- " -eos : write end of stream marker\n"
- " -si : read data from stdin\n"
- " -so : write data to stdout\n";
-
-
-static const char * const kCantAllocate = "Can not allocate memory";
-static const char * const kReadError = "Read error";
-static const char * const kWriteError = "Write error";
-
-
-namespace NKey {
-enum Enum
-{
- kHelp1 = 0,
- kHelp2,
- kMethod,
- kLevel,
- kAlgo,
- kDict,
- kFb,
- kMc,
- kLc,
- kLp,
- kPb,
- kMatchFinder,
- kMultiThread,
- kEOS,
- kStdIn,
- kStdOut,
- kFilter86
-};
-}
-
-static const CSwitchForm kSwitchForms[] =
-{
- { "?", NSwitchType::kSimple, false },
- { "H", NSwitchType::kSimple, false },
- { "MM", NSwitchType::kString, false, 1 },
- { "X", NSwitchType::kString, false, 1 },
- { "A", NSwitchType::kString, false, 1 },
- { "D", NSwitchType::kString, false, 1 },
- { "FB", NSwitchType::kString, false, 1 },
- { "MC", NSwitchType::kString, false, 1 },
- { "LC", NSwitchType::kString, false, 1 },
- { "LP", NSwitchType::kString, false, 1 },
- { "PB", NSwitchType::kString, false, 1 },
- { "MF", NSwitchType::kString, false, 1 },
- { "MT", NSwitchType::kString, false, 0 },
- { "EOS", NSwitchType::kSimple, false },
- { "SI", NSwitchType::kSimple, false },
- { "SO", NSwitchType::kSimple, false },
- { "F86", NSwitchType::kChar, false, 0, "+" }
-};
-
-
-static void Convert_UString_to_AString(const UString &s, AString &temp)
-{
- int codePage = CP_OEMCP;
- /*
- int g_CodePage = -1;
- int codePage = g_CodePage;
- if (codePage == -1)
- codePage = CP_OEMCP;
- if (codePage == CP_UTF8)
- ConvertUnicodeToUTF8(s, temp);
- else
- */
- UnicodeStringToMultiByte2(temp, s, (UINT)codePage);
-}
-
-static void PrintErr(const char *s)
-{
- fputs(s, stderr);
-}
-
-static void PrintErr_LF(const char *s)
-{
- PrintErr(s);
- fputc('\n', stderr);
-}
-
-
-static void PrintError(const char *s)
-{
- PrintErr("\nERROR: ");
- PrintErr_LF(s);
-}
-
-static void PrintError2(const char *s1, const UString &s2)
-{
- PrintError(s1);
- AString a;
- Convert_UString_to_AString(s2, a);
- PrintErr_LF(a);
-}
-
-static void PrintError_int(const char *s, int code)
-{
- PrintError(s);
- char temp[32];
- ConvertInt64ToString(code, temp);
- PrintErr("Error code = ");
- PrintErr_LF(temp);
-}
-
-
-
-static void Print(const char *s)
-{
- fputs(s, stdout);
-}
-
-static void Print_UInt64(UInt64 v)
-{
- char temp[32];
- ConvertUInt64ToString(v, temp);
- Print(temp);
-}
-
-static void Print_MB(UInt64 v)
-{
- Print_UInt64(v);
- Print(" MiB");
-}
-
-static void Print_Size(const char *s, UInt64 v)
-{
- Print(s);
- Print_UInt64(v);
- Print(" (");
- Print_MB(v >> 20);
- Print(")\n");
-}
-
-static void PrintTitle()
-{
- Print(kCopyrightString);
-}
-
-static void PrintHelp()
-{
- PrintTitle();
- Print(kHelpString);
-}
-
-class CProgressPrint:
- public ICompressProgressInfo,
- public CMyUnknownImp
-{
- UInt64 _size1;
- UInt64 _size2;
-public:
- CProgressPrint(): _size1(0), _size2(0) {}
-
- void ClosePrint();
-
- MY_UNKNOWN_IMP1(ICompressProgressInfo)
-
- STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
-};
-
-#define BACK_STR \
-"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
-static const char * const kBackSpaces =
-BACK_STR
-" "
-BACK_STR;
-
-
-void CProgressPrint::ClosePrint()
-{
- Print(kBackSpaces);
-}
-
-STDMETHODIMP CProgressPrint::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
-{
- if (NConsoleClose::TestBreakSignal())
- return E_ABORT;
- if (inSize)
- {
- UInt64 v1 = *inSize >> 20;
- UInt64 v2 = _size2;
- if (outSize)
- v2 = *outSize >> 20;
- if (v1 != _size1 || v2 != _size2)
- {
- _size1 = v1;
- _size2 = v2;
- ClosePrint();
- Print_MB(_size1);
- Print(" -> ");
- Print_MB(_size2);
- }
- }
- return S_OK;
-}
-
-
-static void IncorrectCommand()
-{
- throw "Incorrect command";
-}
-
-static UInt32 GetNumber(const wchar_t *s)
-{
- const wchar_t *end;
- UInt32 v = ConvertStringToUInt32(s, &end);
- if (*end != 0)
- IncorrectCommand();
- return v;
-}
-
-static void ParseUInt32(const CParser &parser, unsigned index, UInt32 &res)
-{
- if (parser[index].ThereIs)
- res = GetNumber(parser[index].PostStrings[0]);
-}
-
-
-static int Error_HRESULT(const char *s, HRESULT res)
-{
- if (res == E_ABORT)
- {
- Print("\n\nBreak signaled\n");
- return 255;
- }
-
- PrintError(s);
-
- if (res == E_OUTOFMEMORY)
- {
- PrintErr_LF(kCantAllocate);
- return 8;
- }
- if (res == E_INVALIDARG)
- {
- PrintErr_LF("Ununsupported parameter");
- }
- else
- {
- char temp[32];
- ConvertUInt32ToHex(res, temp);
- PrintErr("Error code = 0x");
- PrintErr_LF(temp);
- }
- return 1;
-}
-
-#define NT_CHECK_FAIL_ACTION PrintError("Unsupported Windows version"); return 1;
-
-static void AddProp(CObjectVector<CProperty> &props2, const char *name, const wchar_t *val)
-{
- CProperty &prop = props2.AddNew();
- prop.Name = name;
- prop.Value = val;
-}
-
-static int main2(int numArgs, const char *args[])
-{
- NT_CHECK
-
- if (numArgs == 1)
- {
- PrintHelp();
- return 0;
- }
-
- /*
- bool unsupportedTypes = (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 8);
- if (unsupportedTypes)
- throw "Unsupported base types. Edit Common/Types.h and recompile";
- */
-
- UStringVector commandStrings;
- for (int i = 1; i < numArgs; i++)
- commandStrings.Add(MultiByteToUnicodeString(args[i]));
-
- CParser parser;
- try
- {
- if (!parser.ParseStrings(kSwitchForms, ARRAY_SIZE(kSwitchForms), commandStrings))
- {
- PrintError2(parser.ErrorMessage, parser.ErrorLine);
- return 1;
- }
- }
- catch(...)
- {
- IncorrectCommand();
- }
-
- if (parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
- {
- PrintHelp();
- return 0;
- }
-
- bool stdInMode = parser[NKey::kStdIn].ThereIs;
- bool stdOutMode = parser[NKey::kStdOut].ThereIs;
-
- if (!stdOutMode)
- PrintTitle();
-
- const UStringVector &params = parser.NonSwitchStrings;
-
- unsigned paramIndex = 0;
- if (paramIndex >= params.Size())
- IncorrectCommand();
- const UString &command = params[paramIndex++];
-
- CObjectVector<CProperty> props2;
- bool dictDefined = false;
- UInt32 dict = (UInt32)(Int32)-1;
-
- if (parser[NKey::kDict].ThereIs)
- {
- UInt32 dictLog;
- const UString &s = parser[NKey::kDict].PostStrings[0];
- dictLog = GetNumber(s);
- dict = 1 << dictLog;
- dictDefined = true;
- AddProp(props2, "d", s);
- }
-
- if (parser[NKey::kLevel].ThereIs)
- {
- const UString &s = parser[NKey::kLevel].PostStrings[0];
- /* UInt32 level = */ GetNumber(s);
- AddProp(props2, "x", s);
- }
-
- UString mf ("BT4");
- if (parser[NKey::kMatchFinder].ThereIs)
- mf = parser[NKey::kMatchFinder].PostStrings[0];
-
- UInt32 numThreads = (UInt32)(Int32)-1;
-
- #ifndef _7ZIP_ST
-
- if (parser[NKey::kMultiThread].ThereIs)
- {
- const UString &s = parser[NKey::kMultiThread].PostStrings[0];
- if (s.IsEmpty())
- numThreads = NWindows::NSystem::GetNumberOfProcessors();
- else
- numThreads = GetNumber(s);
- AddProp(props2, "mt", s);
- }
-
- #endif
-
-
- if (parser[NKey::kMethod].ThereIs)
- {
- const UString &s = parser[NKey::kMethod].PostStrings[0];
- if (s.IsEmpty() || s[0] != '=')
- IncorrectCommand();
- AddProp(props2, "m", s.Ptr(1));
- }
-
- if (StringsAreEqualNoCase_Ascii(command, "b"))
- {
- UInt32 numIterations = 1;
- if (paramIndex < params.Size())
- numIterations = GetNumber(params[paramIndex++]);
- if (params.Size() != paramIndex)
- IncorrectCommand();
-
- HRESULT res = BenchCon(props2, numIterations, stdout);
-
- if (res == S_OK)
- return 0;
- return Error_HRESULT("Benchmark error", res);
- }
-
- {
- UInt32 needParams = 3;
- if (stdInMode) needParams--;
- if (stdOutMode) needParams--;
- if (needParams != params.Size())
- IncorrectCommand();
- }
-
- if (numThreads == (UInt32)(Int32)-1)
- numThreads = 1;
-
- bool encodeMode = false;
-
- if (StringsAreEqualNoCase_Ascii(command, "e"))
- encodeMode = true;
- else if (!StringsAreEqualNoCase_Ascii(command, "d"))
- IncorrectCommand();
-
- CMyComPtr<ISequentialInStream> inStream;
- CInFileStream *inStreamSpec = NULL;
-
- if (stdInMode)
- {
- inStream = new CStdInFileStream;
- MY_SET_BINARY_MODE(stdin);
- }
- else
- {
- const UString &inputName = params[paramIndex++];
- inStreamSpec = new CInFileStream;
- inStream = inStreamSpec;
- if (!inStreamSpec->Open(us2fs(inputName)))
- {
- PrintError2("can not open input file", inputName);
- return 1;
- }
- }
-
- CMyComPtr<ISequentialOutStream> outStream;
- COutFileStream *outStreamSpec = NULL;
-
- if (stdOutMode)
- {
- outStream = new CStdOutFileStream;
- MY_SET_BINARY_MODE(stdout);
- }
- else
- {
- const UString &outputName = params[paramIndex++];
- outStreamSpec = new COutFileStream;
- outStream = outStreamSpec;
- if (!outStreamSpec->Create(us2fs(outputName), true))
- {
- PrintError2("can not open output file", outputName);
- return 1;
- }
- }
-
- bool fileSizeDefined = false;
- UInt64 fileSize = 0;
-
- if (inStreamSpec)
- {
- if (!inStreamSpec->File.GetLength(fileSize))
- throw "Can not get file length";
- fileSizeDefined = true;
- if (!stdOutMode)
- Print_Size("Input size: ", fileSize);
- }
-
- if (encodeMode && !dictDefined)
- {
- dict = 1 << kDictSizeLog;
- if (fileSizeDefined)
- {
- unsigned i;
- for (i = 16; i < kDictSizeLog; i++)
- if ((UInt32)((UInt32)1 << i) >= fileSize)
- break;
- dict = (UInt32)1 << i;
- }
- }
-
- if (parser[NKey::kFilter86].ThereIs)
- {
- /* -f86 switch is for x86 filtered mode: BCJ + LZMA.
- It uses modified header format.
- It's not recommended to use -f86 mode now.
- You can use xz format instead, if you want to use filters */
-
- if (parser[NKey::kEOS].ThereIs || stdInMode)
- throw "Can not use stdin in this mode";
-
- size_t inSize = (size_t)fileSize;
-
- if (inSize != fileSize)
- throw "File is too big";
-
- Byte *inBuffer = NULL;
-
- if (inSize != 0)
- {
- inBuffer = (Byte *)MyAlloc((size_t)inSize);
- if (!inBuffer)
- throw kCantAllocate;
- }
-
- if (ReadStream_FAIL(inStream, inBuffer, inSize) != S_OK)
- throw "Can not read";
-
- Byte *outBuffer = NULL;
- size_t outSize;
-
- if (encodeMode)
- {
- // we allocate 105% of original size for output buffer
- UInt64 outSize64 = fileSize / 20 * 21 + (1 << 16);
-
- outSize = (size_t)outSize64;
-
- if (outSize != outSize64)
- throw "File is too big";
-
- if (outSize != 0)
- {
- outBuffer = (Byte *)MyAlloc((size_t)outSize);
- if (!outBuffer)
- throw kCantAllocate;
- }
-
- int res = Lzma86_Encode(outBuffer, &outSize, inBuffer, inSize,
- 5, dict, parser[NKey::kFilter86].PostCharIndex == 0 ? SZ_FILTER_YES : SZ_FILTER_AUTO);
-
- if (res != 0)
- {
- PrintError_int("Encode error", (int)res);
- return 1;
- }
- }
- else
- {
- UInt64 outSize64;
-
- if (Lzma86_GetUnpackSize(inBuffer, inSize, &outSize64) != 0)
- throw "data error";
-
- outSize = (size_t)outSize64;
- if (outSize != outSize64)
- throw "Unpack size is too big";
- if (outSize != 0)
- {
- outBuffer = (Byte *)MyAlloc(outSize);
- if (!outBuffer)
- throw kCantAllocate;
- }
-
- int res = Lzma86_Decode(outBuffer, &outSize, inBuffer, &inSize);
-
- if (inSize != (size_t)fileSize)
- throw "incorrect processed size";
- if (res != 0)
- {
- PrintError_int("Decode error", (int)res);
- return 1;
- }
- }
-
- if (WriteStream(outStream, outBuffer, outSize) != S_OK)
- throw kWriteError;
-
- MyFree(outBuffer);
- MyFree(inBuffer);
- }
- else
- {
-
- CProgressPrint *progressSpec = NULL;
- CMyComPtr<ICompressProgressInfo> progress;
-
- if (!stdOutMode)
- {
- progressSpec = new CProgressPrint;
- progress = progressSpec;
- }
-
- if (encodeMode)
- {
- NCompress::NLzma::CEncoder *encoderSpec = new NCompress::NLzma::CEncoder;
- CMyComPtr<ICompressCoder> encoder = encoderSpec;
-
- UInt32 pb = 2;
- UInt32 lc = 3; // = 0; for 32-bit data
- UInt32 lp = 0; // = 2; for 32-bit data
- UInt32 algo = 1;
- UInt32 fb = 128;
- UInt32 mc = 16 + fb / 2;
- bool mcDefined = false;
-
- bool eos = parser[NKey::kEOS].ThereIs || stdInMode;
-
- ParseUInt32(parser, NKey::kAlgo, algo);
- ParseUInt32(parser, NKey::kFb, fb);
- ParseUInt32(parser, NKey::kLc, lc);
- ParseUInt32(parser, NKey::kLp, lp);
- ParseUInt32(parser, NKey::kPb, pb);
-
- mcDefined = parser[NKey::kMc].ThereIs;
- if (mcDefined)
- mc = GetNumber(parser[NKey::kMc].PostStrings[0]);
-
- const PROPID propIDs[] =
- {
- NCoderPropID::kDictionarySize,
- NCoderPropID::kPosStateBits,
- NCoderPropID::kLitContextBits,
- NCoderPropID::kLitPosBits,
- NCoderPropID::kAlgorithm,
- NCoderPropID::kNumFastBytes,
- NCoderPropID::kMatchFinder,
- NCoderPropID::kEndMarker,
- NCoderPropID::kNumThreads,
- NCoderPropID::kMatchFinderCycles,
- };
-
- const unsigned kNumPropsMax = ARRAY_SIZE(propIDs);
-
- PROPVARIANT props[kNumPropsMax];
- for (int p = 0; p < 6; p++)
- props[p].vt = VT_UI4;
-
- props[0].ulVal = (UInt32)dict;
- props[1].ulVal = (UInt32)pb;
- props[2].ulVal = (UInt32)lc;
- props[3].ulVal = (UInt32)lp;
- props[4].ulVal = (UInt32)algo;
- props[5].ulVal = (UInt32)fb;
-
- props[6].vt = VT_BSTR;
- props[6].bstrVal = const_cast<BSTR>((const wchar_t *)mf);
-
- props[7].vt = VT_BOOL;
- props[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE;
-
- props[8].vt = VT_UI4;
- props[8].ulVal = (UInt32)numThreads;
-
- // it must be last in property list
- props[9].vt = VT_UI4;
- props[9].ulVal = (UInt32)mc;
-
- unsigned numProps = kNumPropsMax;
- if (!mcDefined)
- numProps--;
-
- HRESULT res = encoderSpec->SetCoderProperties(propIDs, props, numProps);
- if (res != S_OK)
- return Error_HRESULT("incorrect encoder properties", res);
-
- if (encoderSpec->WriteCoderProperties(outStream) != S_OK)
- throw kWriteError;
-
- bool fileSizeWasUsed = true;
- if (eos || stdInMode)
- {
- fileSize = (UInt64)(Int64)-1;
- fileSizeWasUsed = false;
- }
-
- {
- Byte temp[8];
- for (int i = 0; i < 8; i++)
- temp[i]= (Byte)(fileSize >> (8 * i));
- if (WriteStream(outStream, temp, 8) != S_OK)
- throw kWriteError;
- }
-
- res = encoder->Code(inStream, outStream, NULL, NULL, progress);
- if (progressSpec)
- progressSpec->ClosePrint();
-
- if (res != S_OK)
- return Error_HRESULT("Encoding error", res);
-
- UInt64 processedSize = encoderSpec->GetInputProcessedSize();
-
- if (fileSizeWasUsed && processedSize != fileSize)
- throw "Incorrect size of processed data";
- }
- else
- {
- NCompress::NLzma::CDecoder *decoderSpec = new NCompress::NLzma::CDecoder;
- CMyComPtr<ICompressCoder> decoder = decoderSpec;
-
- decoderSpec->FinishStream = true;
-
- const unsigned kPropertiesSize = 5;
- Byte header[kPropertiesSize + 8];
-
- if (ReadStream_FALSE(inStream, header, kPropertiesSize + 8) != S_OK)
- throw kReadError;
-
- if (decoderSpec->SetDecoderProperties2(header, kPropertiesSize) != S_OK)
- throw "SetDecoderProperties error";
-
- UInt64 unpackSize = 0;
- for (int i = 0; i < 8; i++)
- unpackSize |= ((UInt64)header[kPropertiesSize + i]) << (8 * i);
-
- bool unpackSizeDefined = (unpackSize != (UInt64)(Int64)-1);
-
- HRESULT res = decoder->Code(inStream, outStream, NULL, unpackSizeDefined ? &unpackSize : NULL, progress);
- if (progressSpec)
- progressSpec->ClosePrint();
-
- if (res != S_OK)
- {
- if (res == S_FALSE)
- {
- PrintError("Decoding error");
- return 1;
- }
- return Error_HRESULT("Decoding error", res);
- }
-
- if (unpackSizeDefined && unpackSize != decoderSpec->GetOutputProcessedSize())
- throw "incorrect uncompressed size in header";
- }
- }
-
- if (outStreamSpec)
- {
- if (!stdOutMode)
- Print_Size("Output size: ", outStreamSpec->ProcessedSize);
- if (outStreamSpec->Close() != S_OK)
- throw "File closing error";
- }
-
- return 0;
-}
-
-int MY_CDECL main(int numArgs, const char *args[])
-{
- NConsoleClose::CCtrlHandlerSetter ctrlHandlerSetter;
-
- try { return main2(numArgs, args); }
- catch (const char *s)
- {
- PrintError(s);
- return 1;
- }
- catch(...)
- {
- PrintError("Unknown Error");
- return 1;
- }
-}
+ // LzmaAlone.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#if (defined(_WIN32) || defined(OS2) || defined(MSDOS)) && !defined(UNDER_CE)
+#include <fcntl.h>
+#include <io.h>
+#define MY_SET_BINARY_MODE(file) _setmode(_fileno(file), O_BINARY)
+#else
+#define MY_SET_BINARY_MODE(file)
+#endif
+
+#include "../../../../C/CpuArch.h"
+#include "../../../../C/7zVersion.h"
+#include "../../../../C/Alloc.h"
+#include "../../../../C/Lzma86.h"
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/MyInitGuid.h"
+
+#include "../../../Windows/NtCheck.h"
+
+#ifndef Z7_ST
+#include "../../../Windows/System.h"
+#endif
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/CommandLineParser.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/LzmaDecoder.h"
+#include "../../Compress/LzmaEncoder.h"
+
+#include "../../UI/Console/BenchCon.h"
+#include "../../UI/Console/ConsoleClose.h"
+
+extern
+bool g_LargePagesMode;
+bool g_LargePagesMode = false;
+
+using namespace NCommandLineParser;
+
+static const unsigned kDictSizeLog = 24;
+
+#define kCopyrightString "\nLZMA " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n\n"
+
+static const char * const kHelpString =
+ "Usage: lzma <command> [inputFile] [outputFile] [<switches>...]\n"
+ "\n"
+ "<command>\n"
+ " e : Encode file\n"
+ " d : Decode file\n"
+ " b : Benchmark\n"
+ "<switches>\n"
+ " -a{N} : set compression mode : [0, 1] : default = 1 (max)\n"
+ " -d{N} : set dictionary size : [12, 30] : default = 24 (16 MiB)\n"
+ " -fb{N} : set number of fast bytes : [5, 273] : default = 128\n"
+ " -mc{N} : set number of cycles for match finder\n"
+ " -lc{N} : set number of literal context bits : [0, 8] : default = 3\n"
+ " -lp{N} : set number of literal pos bits : [0, 4] : default = 0\n"
+ " -pb{N} : set number of pos bits : [0, 4] : default = 2\n"
+ " -mf{M} : set match finder: [hc4, bt2, bt3, bt4] : default = bt4\n"
+ " -mt{N} : set number of CPU threads\n"
+ " -eos : write end of stream marker\n"
+ " -si : read data from stdin\n"
+ " -so : write data to stdout\n";
+
+
+static const char * const kCantAllocate = "Cannot allocate memory";
+static const char * const kReadError = "Read error";
+static const char * const kWriteError = "Write error";
+
+
+namespace NKey {
+enum Enum
+{
+ kHelp1 = 0,
+ kHelp2,
+ kMethod,
+ kLevel,
+ kAlgo,
+ kDict,
+ kFb,
+ kMc,
+ kLc,
+ kLp,
+ kPb,
+ kMatchFinder,
+ kMultiThread,
+ kEOS,
+ kStdIn,
+ kStdOut,
+ kFilter86
+};
+}
+
+#define SWFRM_3(t, mu, mi) t, mu, mi, NULL
+
+#define SWFRM_1(t) SWFRM_3(t, false, 0)
+#define SWFRM_SIMPLE SWFRM_1(NSwitchType::kSimple)
+#define SWFRM_STRING SWFRM_1(NSwitchType::kString)
+
+#define SWFRM_STRING_SINGL(mi) SWFRM_3(NSwitchType::kString, false, mi)
+
+static const CSwitchForm kSwitchForms[] =
+{
+ { "?", SWFRM_SIMPLE },
+ { "H", SWFRM_SIMPLE },
+ { "MM", SWFRM_STRING_SINGL(1) },
+ { "X", SWFRM_STRING_SINGL(1) },
+ { "A", SWFRM_STRING_SINGL(1) },
+ { "D", SWFRM_STRING_SINGL(1) },
+ { "FB", SWFRM_STRING_SINGL(1) },
+ { "MC", SWFRM_STRING_SINGL(1) },
+ { "LC", SWFRM_STRING_SINGL(1) },
+ { "LP", SWFRM_STRING_SINGL(1) },
+ { "PB", SWFRM_STRING_SINGL(1) },
+ { "MF", SWFRM_STRING_SINGL(1) },
+ { "MT", SWFRM_STRING },
+ { "EOS", SWFRM_SIMPLE },
+ { "SI", SWFRM_SIMPLE },
+ { "SO", SWFRM_SIMPLE },
+ { "F86", NSwitchType::kChar, false, 0, "+" }
+};
+
+
+static void Convert_UString_to_AString(const UString &s, AString &temp)
+{
+ int codePage = CP_OEMCP;
+ /*
+ int g_CodePage = -1;
+ int codePage = g_CodePage;
+ if (codePage == -1)
+ codePage = CP_OEMCP;
+ if (codePage == CP_UTF8)
+ ConvertUnicodeToUTF8(s, temp);
+ else
+ */
+ UnicodeStringToMultiByte2(temp, s, (UINT)codePage);
+}
+
+static void PrintErr(const char *s)
+{
+ fputs(s, stderr);
+}
+
+static void PrintErr_LF(const char *s)
+{
+ PrintErr(s);
+ fputc('\n', stderr);
+}
+
+
+static void PrintError(const char *s)
+{
+ PrintErr("\nERROR: ");
+ PrintErr_LF(s);
+}
+
+static void PrintError2(const char *s1, const UString &s2)
+{
+ PrintError(s1);
+ AString a;
+ Convert_UString_to_AString(s2, a);
+ PrintErr_LF(a);
+}
+
+static void PrintError_int(const char *s, int code)
+{
+ PrintError(s);
+ char temp[32];
+ ConvertInt64ToString(code, temp);
+ PrintErr("Error code = ");
+ PrintErr_LF(temp);
+}
+
+
+
+static void Print(const char *s)
+{
+ fputs(s, stdout);
+}
+
+static void Print_UInt64(UInt64 v)
+{
+ char temp[32];
+ ConvertUInt64ToString(v, temp);
+ Print(temp);
+}
+
+static void Print_MB(UInt64 v)
+{
+ Print_UInt64(v);
+ Print(" MiB");
+}
+
+static void Print_Size(const char *s, UInt64 v)
+{
+ Print(s);
+ Print_UInt64(v);
+ Print(" (");
+ Print_MB(v >> 20);
+ Print(")\n");
+}
+
+static void PrintTitle()
+{
+ Print(kCopyrightString);
+}
+
+static void PrintHelp()
+{
+ PrintTitle();
+ Print(kHelpString);
+}
+
+
+Z7_CLASS_IMP_COM_1(
+ CProgressPrint,
+ ICompressProgressInfo
+)
+ UInt64 _size1;
+ UInt64 _size2;
+public:
+ CProgressPrint(): _size1(0), _size2(0) {}
+
+ void ClosePrint();
+};
+
+#define BACK_STR \
+"\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b"
+static const char * const kBackSpaces =
+BACK_STR
+" "
+BACK_STR;
+
+
+void CProgressPrint::ClosePrint()
+{
+ Print(kBackSpaces);
+}
+
+Z7_COM7F_IMF(CProgressPrint::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
+{
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+ if (inSize)
+ {
+ UInt64 v1 = *inSize >> 20;
+ UInt64 v2 = _size2;
+ if (outSize)
+ v2 = *outSize >> 20;
+ if (v1 != _size1 || v2 != _size2)
+ {
+ _size1 = v1;
+ _size2 = v2;
+ ClosePrint();
+ Print_MB(_size1);
+ Print(" -> ");
+ Print_MB(_size2);
+ }
+ }
+ return S_OK;
+}
+
+
+Z7_ATTR_NORETURN
+static void IncorrectCommand()
+{
+ throw "Incorrect command";
+}
+
+static UInt32 GetNumber(const wchar_t *s)
+{
+ const wchar_t *end;
+ UInt32 v = ConvertStringToUInt32(s, &end);
+ if (*end != 0)
+ IncorrectCommand();
+ return v;
+}
+
+static void ParseUInt32(const CParser &parser, unsigned index, UInt32 &res)
+{
+ if (parser[index].ThereIs)
+ res = GetNumber(parser[index].PostStrings[0]);
+}
+
+
+static int Error_HRESULT(const char *s, HRESULT res)
+{
+ if (res == E_ABORT)
+ {
+ Print("\n\nBreak signaled\n");
+ return 255;
+ }
+
+ PrintError(s);
+
+ if (res == E_OUTOFMEMORY)
+ {
+ PrintErr_LF(kCantAllocate);
+ return 8;
+ }
+ if (res == E_INVALIDARG)
+ {
+ PrintErr_LF("Ununsupported parameter");
+ }
+ else
+ {
+ char temp[32];
+ ConvertUInt32ToHex((UInt32)res, temp);
+ PrintErr("Error code = 0x");
+ PrintErr_LF(temp);
+ }
+ return 1;
+}
+
+#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE)
+#define NT_CHECK_FAIL_ACTION PrintError("Unsupported Windows version"); return 1;
+#endif
+
+static void AddProp(CObjectVector<CProperty> &props2, const char *name, const wchar_t *val)
+{
+ CProperty &prop = props2.AddNew();
+ prop.Name = name;
+ prop.Value = val;
+}
+
+static int main2(int numArgs, const char *args[])
+{
+ NT_CHECK
+
+ if (numArgs == 1)
+ {
+ PrintHelp();
+ return 0;
+ }
+
+ /*
+ bool unsupportedTypes = (sizeof(Byte) != 1 || sizeof(UInt32) < 4 || sizeof(UInt64) < 8);
+ if (unsupportedTypes)
+ throw "Unsupported base types. Edit Common/Types.h and recompile";
+ */
+
+ UStringVector commandStrings;
+ for (int i = 1; i < numArgs; i++)
+ commandStrings.Add(MultiByteToUnicodeString(args[i]));
+
+ CParser parser;
+ try
+ {
+ if (!parser.ParseStrings(kSwitchForms, Z7_ARRAY_SIZE(kSwitchForms), commandStrings))
+ {
+ PrintError2(parser.ErrorMessage, parser.ErrorLine);
+ return 1;
+ }
+ }
+ catch(...)
+ {
+ IncorrectCommand();
+ }
+
+ if (parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
+ {
+ PrintHelp();
+ return 0;
+ }
+
+ bool stdInMode = parser[NKey::kStdIn].ThereIs;
+ bool stdOutMode = parser[NKey::kStdOut].ThereIs;
+
+ if (!stdOutMode)
+ PrintTitle();
+
+ const UStringVector &params = parser.NonSwitchStrings;
+
+ unsigned paramIndex = 0;
+ if (paramIndex >= params.Size())
+ IncorrectCommand();
+ const UString &command = params[paramIndex++];
+
+ CObjectVector<CProperty> props2;
+ bool dictDefined = false;
+ UInt32 dict = (UInt32)(Int32)-1;
+
+ if (parser[NKey::kDict].ThereIs)
+ {
+ UInt32 dictLog;
+ const UString &s = parser[NKey::kDict].PostStrings[0];
+ dictLog = GetNumber(s);
+ dict = 1 << dictLog;
+ dictDefined = true;
+ AddProp(props2, "d", s);
+ }
+
+ if (parser[NKey::kLevel].ThereIs)
+ {
+ const UString &s = parser[NKey::kLevel].PostStrings[0];
+ /* UInt32 level = */ GetNumber(s);
+ AddProp(props2, "x", s);
+ }
+
+ UString mf ("BT4");
+ if (parser[NKey::kMatchFinder].ThereIs)
+ mf = parser[NKey::kMatchFinder].PostStrings[0];
+
+ UInt32 numThreads = (UInt32)(Int32)-1;
+
+ #ifndef Z7_ST
+
+ if (parser[NKey::kMultiThread].ThereIs)
+ {
+ const UString &s = parser[NKey::kMultiThread].PostStrings[0];
+ if (s.IsEmpty())
+ numThreads = NWindows::NSystem::GetNumberOfProcessors();
+ else
+ numThreads = GetNumber(s);
+ AddProp(props2, "mt", s);
+ }
+
+ #endif
+
+
+ if (parser[NKey::kMethod].ThereIs)
+ {
+ const UString &s = parser[NKey::kMethod].PostStrings[0];
+ if (s.IsEmpty() || s[0] != '=')
+ IncorrectCommand();
+ AddProp(props2, "m", s.Ptr(1));
+ }
+
+ if (StringsAreEqualNoCase_Ascii(command, "b"))
+ {
+ UInt32 numIterations = 1;
+ if (paramIndex < params.Size())
+ numIterations = GetNumber(params[paramIndex++]);
+ if (params.Size() != paramIndex)
+ IncorrectCommand();
+
+ HRESULT res = BenchCon(props2, numIterations, stdout);
+
+ if (res == S_OK)
+ return 0;
+ return Error_HRESULT("Benchmark error", res);
+ }
+
+ {
+ UInt32 needParams = 3;
+ if (stdInMode) needParams--;
+ if (stdOutMode) needParams--;
+ if (needParams != params.Size())
+ IncorrectCommand();
+ }
+
+ if (numThreads == (UInt32)(Int32)-1)
+ numThreads = 1;
+
+ bool encodeMode = false;
+
+ if (StringsAreEqualNoCase_Ascii(command, "e"))
+ encodeMode = true;
+ else if (!StringsAreEqualNoCase_Ascii(command, "d"))
+ IncorrectCommand();
+
+ CMyComPtr<ISequentialInStream> inStream;
+ CInFileStream *inStreamSpec = NULL;
+
+ if (stdInMode)
+ {
+ inStream = new CStdInFileStream;
+ MY_SET_BINARY_MODE(stdin);
+ }
+ else
+ {
+ const UString &inputName = params[paramIndex++];
+ inStreamSpec = new CInFileStream;
+ inStream = inStreamSpec;
+ if (!inStreamSpec->Open(us2fs(inputName)))
+ {
+ PrintError2("Cannot open input file", inputName);
+ return 1;
+ }
+ }
+
+ CMyComPtr<ISequentialOutStream> outStream;
+ COutFileStream *outStreamSpec = NULL;
+
+ if (stdOutMode)
+ {
+ outStream = new CStdOutFileStream;
+ MY_SET_BINARY_MODE(stdout);
+ }
+ else
+ {
+ const UString &outputName = params[paramIndex++];
+ outStreamSpec = new COutFileStream;
+ outStream = outStreamSpec;
+ if (!outStreamSpec->Create(us2fs(outputName), true))
+ {
+ PrintError2("Cannot open output file", outputName);
+ return 1;
+ }
+ }
+
+ bool fileSizeDefined = false;
+ UInt64 fileSize = 0;
+
+ if (inStreamSpec)
+ {
+ if (!inStreamSpec->GetLength(fileSize))
+ throw "Cannot get file length";
+ fileSizeDefined = true;
+ if (!stdOutMode)
+ Print_Size("Input size: ", fileSize);
+ }
+
+ if (encodeMode && !dictDefined)
+ {
+ dict = 1 << kDictSizeLog;
+ if (fileSizeDefined)
+ {
+ unsigned i;
+ for (i = 16; i < kDictSizeLog; i++)
+ if ((UInt32)((UInt32)1 << i) >= fileSize)
+ break;
+ dict = (UInt32)1 << i;
+ }
+ }
+
+ if (parser[NKey::kFilter86].ThereIs)
+ {
+ /* -f86 switch is for x86 filtered mode: BCJ + LZMA.
+ It uses modified header format.
+ It's not recommended to use -f86 mode now.
+ You can use xz format instead, if you want to use filters */
+
+ if (parser[NKey::kEOS].ThereIs || stdInMode)
+ throw "Cannot use stdin in this mode";
+
+ size_t inSize = (size_t)fileSize;
+
+ if (inSize != fileSize)
+ throw "File is too big";
+
+ Byte *inBuffer = NULL;
+
+ if (inSize != 0)
+ {
+ inBuffer = (Byte *)MyAlloc((size_t)inSize);
+ if (!inBuffer)
+ throw kCantAllocate;
+ }
+
+ if (ReadStream_FAIL(inStream, inBuffer, inSize) != S_OK)
+ throw "Cannot read";
+
+ Byte *outBuffer = NULL;
+ size_t outSize;
+
+ if (encodeMode)
+ {
+ // we allocate 105% of original size for output buffer
+ UInt64 outSize64 = fileSize / 20 * 21 + (1 << 16);
+
+ outSize = (size_t)outSize64;
+
+ if (outSize != outSize64)
+ throw "File is too big";
+
+ if (outSize != 0)
+ {
+ outBuffer = (Byte *)MyAlloc((size_t)outSize);
+ if (!outBuffer)
+ throw kCantAllocate;
+ }
+
+ int res = Lzma86_Encode(outBuffer, &outSize, inBuffer, inSize,
+ 5, dict, parser[NKey::kFilter86].PostCharIndex == 0 ? SZ_FILTER_YES : SZ_FILTER_AUTO);
+
+ if (res != 0)
+ {
+ PrintError_int("Encode error", (int)res);
+ return 1;
+ }
+ }
+ else
+ {
+ UInt64 outSize64;
+
+ if (Lzma86_GetUnpackSize(inBuffer, inSize, &outSize64) != 0)
+ throw "data error";
+
+ outSize = (size_t)outSize64;
+ if (outSize != outSize64)
+ throw "Unpack size is too big";
+ if (outSize != 0)
+ {
+ outBuffer = (Byte *)MyAlloc(outSize);
+ if (!outBuffer)
+ throw kCantAllocate;
+ }
+
+ int res = Lzma86_Decode(outBuffer, &outSize, inBuffer, &inSize);
+
+ if (inSize != (size_t)fileSize)
+ throw "incorrect processed size";
+ if (res != 0)
+ {
+ PrintError_int("Decode error", (int)res);
+ return 1;
+ }
+ }
+
+ if (WriteStream(outStream, outBuffer, outSize) != S_OK)
+ throw kWriteError;
+
+ MyFree(outBuffer);
+ MyFree(inBuffer);
+ }
+ else
+ {
+
+ CProgressPrint *progressSpec = NULL;
+ CMyComPtr<ICompressProgressInfo> progress;
+
+ if (!stdOutMode)
+ {
+ progressSpec = new CProgressPrint;
+ progress = progressSpec;
+ }
+
+ if (encodeMode)
+ {
+ NCompress::NLzma::CEncoder *encoderSpec = new NCompress::NLzma::CEncoder;
+ CMyComPtr<ICompressCoder> encoder = encoderSpec;
+
+ UInt32 pb = 2;
+ UInt32 lc = 3; // = 0; for 32-bit data
+ UInt32 lp = 0; // = 2; for 32-bit data
+ UInt32 algo = 1;
+ UInt32 fb = 128;
+ UInt32 mc = 16 + fb / 2;
+ bool mcDefined = false;
+
+ bool eos = parser[NKey::kEOS].ThereIs || stdInMode;
+
+ ParseUInt32(parser, NKey::kAlgo, algo);
+ ParseUInt32(parser, NKey::kFb, fb);
+ ParseUInt32(parser, NKey::kLc, lc);
+ ParseUInt32(parser, NKey::kLp, lp);
+ ParseUInt32(parser, NKey::kPb, pb);
+
+ mcDefined = parser[NKey::kMc].ThereIs;
+ if (mcDefined)
+ mc = GetNumber(parser[NKey::kMc].PostStrings[0]);
+
+ const PROPID propIDs[] =
+ {
+ NCoderPropID::kDictionarySize,
+ NCoderPropID::kPosStateBits,
+ NCoderPropID::kLitContextBits,
+ NCoderPropID::kLitPosBits,
+ NCoderPropID::kAlgorithm,
+ NCoderPropID::kNumFastBytes,
+ NCoderPropID::kMatchFinder,
+ NCoderPropID::kEndMarker,
+ NCoderPropID::kNumThreads,
+ NCoderPropID::kMatchFinderCycles,
+ };
+
+ const unsigned kNumPropsMax = Z7_ARRAY_SIZE(propIDs);
+
+ PROPVARIANT props[kNumPropsMax];
+ for (int p = 0; p < 6; p++)
+ props[p].vt = VT_UI4;
+
+ props[0].ulVal = (UInt32)dict;
+ props[1].ulVal = (UInt32)pb;
+ props[2].ulVal = (UInt32)lc;
+ props[3].ulVal = (UInt32)lp;
+ props[4].ulVal = (UInt32)algo;
+ props[5].ulVal = (UInt32)fb;
+
+ props[6].vt = VT_BSTR;
+ props[6].bstrVal = const_cast<BSTR>((const wchar_t *)mf);
+
+ props[7].vt = VT_BOOL;
+ props[7].boolVal = eos ? VARIANT_TRUE : VARIANT_FALSE;
+
+ props[8].vt = VT_UI4;
+ props[8].ulVal = (UInt32)numThreads;
+
+ // it must be last in property list
+ props[9].vt = VT_UI4;
+ props[9].ulVal = (UInt32)mc;
+
+ unsigned numProps = kNumPropsMax;
+ if (!mcDefined)
+ numProps--;
+
+ HRESULT res = encoderSpec->SetCoderProperties(propIDs, props, numProps);
+ if (res != S_OK)
+ return Error_HRESULT("incorrect encoder properties", res);
+
+ if (encoderSpec->WriteCoderProperties(outStream) != S_OK)
+ throw kWriteError;
+
+ bool fileSizeWasUsed = true;
+ if (eos || stdInMode)
+ {
+ fileSize = (UInt64)(Int64)-1;
+ fileSizeWasUsed = false;
+ }
+
+ {
+ Byte temp[8];
+ for (int i = 0; i < 8; i++)
+ temp[i]= (Byte)(fileSize >> (8 * i));
+ if (WriteStream(outStream, temp, 8) != S_OK)
+ throw kWriteError;
+ }
+
+ res = encoder->Code(inStream, outStream, NULL, NULL, progress);
+ if (progressSpec)
+ progressSpec->ClosePrint();
+
+ if (res != S_OK)
+ return Error_HRESULT("Encoding error", res);
+
+ UInt64 processedSize = encoderSpec->GetInputProcessedSize();
+
+ if (fileSizeWasUsed && processedSize != fileSize)
+ throw "Incorrect size of processed data";
+ }
+ else
+ {
+ NCompress::NLzma::CDecoder *decoderSpec = new NCompress::NLzma::CDecoder;
+ CMyComPtr<ICompressCoder> decoder = decoderSpec;
+
+ decoderSpec->FinishStream = true;
+
+ const unsigned kPropertiesSize = 5;
+ Byte header[kPropertiesSize + 8];
+
+ if (ReadStream_FALSE(inStream, header, kPropertiesSize + 8) != S_OK)
+ throw kReadError;
+
+ if (decoderSpec->SetDecoderProperties2(header, kPropertiesSize) != S_OK)
+ throw "SetDecoderProperties error";
+
+ UInt64 unpackSize = 0;
+ for (unsigned i = 0; i < 8; i++)
+ unpackSize |= ((UInt64)header[kPropertiesSize + i]) << (8 * i);
+
+ bool unpackSizeDefined = (unpackSize != (UInt64)(Int64)-1);
+
+ HRESULT res = decoder->Code(inStream, outStream, NULL, unpackSizeDefined ? &unpackSize : NULL, progress);
+ if (progressSpec)
+ progressSpec->ClosePrint();
+
+ if (res != S_OK)
+ {
+ if (res == S_FALSE)
+ {
+ PrintError("Decoding error");
+ return 1;
+ }
+ return Error_HRESULT("Decoding error", res);
+ }
+
+ if (unpackSizeDefined && unpackSize != decoderSpec->GetOutputProcessedSize())
+ throw "incorrect uncompressed size in header";
+ }
+ }
+
+ if (outStreamSpec)
+ {
+ if (!stdOutMode)
+ Print_Size("Output size: ", outStreamSpec->ProcessedSize);
+ if (outStreamSpec->Close() != S_OK)
+ throw "File closing error";
+ }
+
+ return 0;
+}
+
+int Z7_CDECL main(int numArgs, const char *args[])
+{
+ NConsoleClose::CCtrlHandlerSetter ctrlHandlerSetter;
+
+ try { return main2(numArgs, args); }
+ catch (const char *s)
+ {
+ PrintError(s);
+ return 1;
+ }
+ catch(...)
+ {
+ PrintError("Unknown Error");
+ return 1;
+ }
+}
diff --git a/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp b/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp
index bdc0c3e..5a8911b 100644
--- a/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp
+++ b/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsp
@@ -1,477 +1,540 @@
-# Microsoft Developer Studio Project File - Name="LzmaCon" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Console Application" 0x0103
-
-CFG=LzmaCon - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "LzmaCon.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "LzmaCon.mak" CFG="LzmaCon - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "LzmaCon - Win32 Release" (based on "Win32 (x86) Console Application")
-!MESSAGE "LzmaCon - Win32 Debug" (based on "Win32 (x86) Console Application")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "LzmaCon - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"StdAfx.h" /FD /c
-# ADD BASE RSC /l 0x419 /d "NDEBUG"
-# ADD RSC /l 0x419 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"C:\Util\lzma.exe"
-
-!ELSEIF "$(CFG)" == "LzmaCon - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
-# ADD CPP /nologo /MDd /W4 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c
-# ADD BASE RSC /l 0x419 /d "_DEBUG"
-# ADD RSC /l 0x419 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"C:\Util\lzma.exe" /pdbtype:sept
-
-!ENDIF
-
-# Begin Target
-
-# Name "LzmaCon - Win32 Release"
-# Name "LzmaCon - Win32 Debug"
-# Begin Group "Spec"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=.\StdAfx.cpp
-# ADD CPP /Yc"StdAfx.h"
-# End Source File
-# Begin Source File
-
-SOURCE=.\StdAfx.h
-# End Source File
-# End Group
-# Begin Group "Compress"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Compress\LzmaDecoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\LzmaDecoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\LzmaEncoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\LzmaEncoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\LzmaRegister.cpp
-# End Source File
-# End Group
-# Begin Group "Windows"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileIO.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileIO.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariant.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariant.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Synchronization.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Synchronization.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\System.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\System.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Thread.h
-# End Source File
-# End Group
-# Begin Group "Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\Common\CommandLineParser.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\CommandLineParser.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\ComTry.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\CRC.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\CrcReg.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\Defs.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\IntToString.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\IntToString.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyCom.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyString.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyString.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyUnknown.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyVector.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyVector.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyWindows.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyWindows.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\NewHandler.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\NewHandler.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StringConvert.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StringConvert.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StringToInt.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StringToInt.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\Types.h
-# End Source File
-# End Group
-# Begin Group "7zip Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Common\CreateCoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\CreateCoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\CWrappers.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\CWrappers.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FileStreams.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FileStreams.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FilterCoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FilterCoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\MethodProps.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\MethodProps.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamUtils.h
-# End Source File
-# End Group
-# Begin Group "UI Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\UI\Common\Bench.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\Bench.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\LoadCodecs.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\LoadCodecs.h
-# End Source File
-# End Group
-# Begin Group "Console"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\UI\Console\BenchCon.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\BenchCon.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\ConsoleClose.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\ConsoleClose.h
-# End Source File
-# End Group
-# Begin Group "C"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\..\C\7zCrc.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\7zCrc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\7zCrcOpt.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\7zTypes.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Alloc.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Alloc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bra.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bra.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bra86.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\BraIA64.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\CpuArch.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\CpuArch.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzFind.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzFind.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzFindMt.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzFindMt.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzHash.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma86.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma86Dec.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma86Enc.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzmaDec.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzmaDec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzmaEnc.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzmaEnc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Threads.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Threads.h
-# End Source File
-# End Group
-# Begin Source File
-
-SOURCE=.\LzmaAlone.cpp
-# End Source File
-# End Target
-# End Project
+# Microsoft Developer Studio Project File - Name="LzmaCon" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=LzmaCon - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "LzmaCon.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "LzmaCon.mak" CFG="LzmaCon - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "LzmaCon - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "LzmaCon - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "LzmaCon - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"StdAfx.h" /FD /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"C:\Util\lzma.exe"
+
+!ELSEIF "$(CFG)" == "LzmaCon - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /MDd /W4 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"C:\Util\lzma.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "LzmaCon - Win32 Release"
+# Name "LzmaCon - Win32 Debug"
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"StdAfx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "Compress"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaEncoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaEncoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaRegister.cpp
+# End Source File
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\NtCheck.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Registry.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Registry.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\SystemInfo.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\SystemInfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Thread.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Common.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ComTry.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CrcReg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\LzFindPrepare.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyBuffer2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyCom.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyInitGuid.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyLinux.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyUnknown.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyWindows.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Types.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.h
+# End Source File
+# End Group
+# Begin Group "7zip Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CWrappers.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CWrappers.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.h
+# End Source File
+# End Group
+# Begin Group "UI Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Bench.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Bench.h
+# End Source File
+# End Group
+# Begin Group "Console"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\Console\BenchCon.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\BenchCon.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ConsoleClose.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ConsoleClose.h
+# End Source File
+# End Group
+# Begin Group "C"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrcOpt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra86.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFind.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFindMt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFindMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzFindOpt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzHash.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma86.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma86Dec.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma86Enc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaDec.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaDec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaEnc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaEnc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.h
+# End Source File
+# End Group
+# Begin Group "7zip"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\ICoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IDecl.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IProgress.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\LzmaAlone.cpp
+# End Source File
+# End Target
+# End Project
diff --git a/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsw b/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsw
index c6a6662..e62c9d2 100644
--- a/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsw
+++ b/CPP/7zip/Bundles/LzmaCon/LzmaCon.dsw
@@ -1,29 +1,29 @@
-Microsoft Developer Studio Workspace File, Format Version 6.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "LzmaCon"=.\LzmaCon.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
-
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "LzmaCon"=.\LzmaCon.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/Bundles/LzmaCon/StdAfx.cpp b/CPP/7zip/Bundles/LzmaCon/StdAfx.cpp
index c6d3b1f..d0feea8 100644
--- a/CPP/7zip/Bundles/LzmaCon/StdAfx.cpp
+++ b/CPP/7zip/Bundles/LzmaCon/StdAfx.cpp
@@ -1,3 +1,3 @@
-// StdAfx.cpp
-
-#include "StdAfx.h"
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/LzmaCon/StdAfx.h b/CPP/7zip/Bundles/LzmaCon/StdAfx.h
index 59d9ac1..035267c 100644
--- a/CPP/7zip/Bundles/LzmaCon/StdAfx.h
+++ b/CPP/7zip/Bundles/LzmaCon/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "../../../Common/Common.h"
-
-#endif
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Bundles/LzmaCon/makefile b/CPP/7zip/Bundles/LzmaCon/makefile
index 5a50808..f303c31 100644
--- a/CPP/7zip/Bundles/LzmaCon/makefile
+++ b/CPP/7zip/Bundles/LzmaCon/makefile
@@ -1,59 +1,67 @@
-PROG = lzma.exe
-MY_CONSOLE = 1
-
-CURRENT_OBJS = \
- $O\LzmaAlone.obj \
-
-COMPRESS_OBJS = \
- $O\LzmaDecoder.obj \
- $O\LzmaEncoder.obj \
- $O\LzmaRegister.obj \
-
-COMMON_OBJS = \
- $O\CommandLineParser.obj \
- $O\CRC.obj \
- $O\CrcReg.obj \
- $O\IntToString.obj \
- $O\MyString.obj \
- $O\NewHandler.obj \
- $O\StringConvert.obj \
- $O\StringToInt.obj \
- $O\MyVector.obj
-
-WIN_OBJS = \
- $O\FileIO.obj \
- $O\PropVariant.obj \
- $O\System.obj
-
-7ZIP_COMMON_OBJS = \
- $O\CWrappers.obj \
- $O\CreateCoder.obj \
- $O\FileStreams.obj \
- $O\FilterCoder.obj \
- $O\MethodProps.obj \
- $O\OutBuffer.obj \
- $O\StreamUtils.obj \
-
-UI_COMMON_OBJS = \
- $O\Bench.obj \
-
-CONSOLE_OBJS = \
- $O\ConsoleClose.obj \
- $O\BenchCon.obj \
-
-C_OBJS = \
- $O\Alloc.obj \
- $O\Bra86.obj \
- $O\CpuArch.obj \
- $O\LzFind.obj \
- $O\LzFindMt.obj \
- $O\Lzma86Dec.obj \
- $O\Lzma86Enc.obj \
- $O\LzmaDec.obj \
- $O\LzmaEnc.obj \
- $O\Threads.obj \
-
-!include "../../Crc.mak"
-!include "../../LzmaDec.mak"
-
-!include "../../7zip.mak"
+PROG = lzma.exe
+MY_CONSOLE = 1
+
+# CFLAGS = $(CFLAGS) -DZ7_ST
+
+
+CURRENT_OBJS = \
+ $O\LzmaAlone.obj \
+
+COMPRESS_OBJS = \
+ $O\LzmaDecoder.obj \
+ $O\LzmaEncoder.obj \
+ $O\LzmaRegister.obj \
+
+COMMON_OBJS = \
+ $O\CommandLineParser.obj \
+ $O\CRC.obj \
+ $O\CrcReg.obj \
+ $O\IntToString.obj \
+ $O\LzFindPrepare.obj \
+ $O\MyString.obj \
+ $O\MyVector.obj \
+ $O\NewHandler.obj \
+ $O\StringConvert.obj \
+ $O\StringToInt.obj \
+ $O\Wildcard.obj \
+
+WIN_OBJS = \
+ $O\FileIO.obj \
+ $O\PropVariant.obj \
+ $O\Registry.obj \
+ $O\System.obj \
+ $O\SystemInfo.obj \
+
+7ZIP_COMMON_OBJS = \
+ $O\CreateCoder.obj \
+ $O\CWrappers.obj \
+ $O\FileStreams.obj \
+ $O\FilterCoder.obj \
+ $O\MethodProps.obj \
+ $O\StreamObjects.obj \
+ $O\StreamUtils.obj \
+
+UI_COMMON_OBJS = \
+ $O\Bench.obj \
+
+CONSOLE_OBJS = \
+ $O\ConsoleClose.obj \
+ $O\BenchCon.obj \
+
+C_OBJS = \
+ $O\Alloc.obj \
+ $O\Bra86.obj \
+ $O\CpuArch.obj \
+ $O\LzFind.obj \
+ $O\LzFindMt.obj \
+ $O\Lzma86Dec.obj \
+ $O\Lzma86Enc.obj \
+ $O\LzmaDec.obj \
+ $O\LzmaEnc.obj \
+ $O\Threads.obj \
+
+!include "../../Crc.mak"
+!include "../../LzFindOpt.mak"
+!include "../../LzmaDec.mak"
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/Bundles/LzmaCon/makefile.gcc b/CPP/7zip/Bundles/LzmaCon/makefile.gcc
index 3fb5ec2..dd19a0e 100644
--- a/CPP/7zip/Bundles/LzmaCon/makefile.gcc
+++ b/CPP/7zip/Bundles/LzmaCon/makefile.gcc
@@ -1,195 +1,126 @@
-PROG = lzma
-CXX = g++ -O2
-# -Wall -Werror -Wno-delete-non-virtual-dtor
-CXX_C = gcc -O2 -Wall -Werror
-
-ifdef SystemDrive
-IS_MINGW = 1
-endif
-
-ifdef IS_MINGW
-
-RM = del
-CFLAGS = -c
-LIB2 = -loleaut32 -luuid
-LDFLAGS = -s
-
-FILE_IO =FileIO
-FILE_IO_2 =Windows/$(FILE_IO)
-
-MT_FILES = \
- LzFindMt.o \
- Threads.o \
-
-else
-
-RM = rm -f
-CFLAGS = -c -D_7ZIP_ST
-
-FILE_IO =C_FileIO
-FILE_IO_2 =Common/$(FILE_IO)
-
-
-endif
-
-
-OBJS = \
- $(MT_FILES) \
- $(FILE_IO).o \
- LzmaAlone.o \
- Bench.o \
- BenchCon.o \
- ConsoleClose.o \
- LzmaDecoder.o \
- LzmaEncoder.o \
- LzmaRegister.o \
- CreateCoder.o \
- CWrappers.o \
- FileStreams.o \
- FilterCoder.o \
- MethodProps.o \
- StreamUtils.o \
- CommandLineParser.o \
- CRC.o \
- CrcReg.o \
- IntToString.o \
- MyString.o \
- MyVector.o \
- MyWindows.o \
- StringConvert.o \
- StringToInt.o \
- PropVariant.o \
- System.o \
- 7zCrc.o \
- 7zCrcOpt.o \
- Alloc.o \
- Bra86.o \
- CpuArch.o \
- LzFind.o \
- LzmaDec.o \
- LzmaEnc.o \
- Lzma86Dec.o \
- Lzma86Enc.o \
-
-
-all: $(PROG)
-
-$(PROG): $(OBJS)
- $(CXX) -o $(PROG) $(LDFLAGS) $(OBJS) $(LIB2)
-
-LzmaAlone.o: LzmaAlone.cpp
- $(CXX) $(CFLAGS) LzmaAlone.cpp
-
-Bench.o: ../../UI/Common/Bench.cpp
- $(CXX) $(CFLAGS) ../../UI/Common/Bench.cpp
-
-BenchCon.o: ../../UI/Console/BenchCon.cpp
- $(CXX) $(CFLAGS) ../../UI/Console/BenchCon.cpp
-
-ConsoleClose.o: ../../UI/Console/ConsoleClose.cpp
- $(CXX) $(CFLAGS) ../../UI/Console/ConsoleClose.cpp
-
-LzmaDecoder.o: ../../Compress/LzmaDecoder.cpp
- $(CXX) $(CFLAGS) ../../Compress/LzmaDecoder.cpp
-
-LzmaEncoder.o: ../../Compress/LzmaEncoder.cpp
- $(CXX) $(CFLAGS) ../../Compress/LzmaEncoder.cpp
-
-LzmaRegister.o: ../../Compress/LzmaRegister.cpp
- $(CXX) $(CFLAGS) ../../Compress/LzmaRegister.cpp
-
-CreateCoder.o: ../../Common/CreateCoder.cpp
- $(CXX) $(CFLAGS) ../../Common/CreateCoder.cpp
-
-CWrappers.o: ../../Common/CWrappers.cpp
- $(CXX) $(CFLAGS) ../../Common/CWrappers.cpp
-
-FileStreams.o: ../../Common/FileStreams.cpp
- $(CXX) $(CFLAGS) ../../Common/FileStreams.cpp
-
-FilterCoder.o: ../../Common/FilterCoder.cpp
- $(CXX) $(CFLAGS) ../../Common/FilterCoder.cpp
-
-MethodProps.o: ../../Common/MethodProps.cpp
- $(CXX) $(CFLAGS) ../../Common/MethodProps.cpp
-
-StreamUtils.o: ../../Common/StreamUtils.cpp
- $(CXX) $(CFLAGS) ../../Common/StreamUtils.cpp
-
-$(FILE_IO).o: ../../../$(FILE_IO_2).cpp
- $(CXX) $(CFLAGS) ../../../$(FILE_IO_2).cpp
-
-
-CommandLineParser.o: ../../../Common/CommandLineParser.cpp
- $(CXX) $(CFLAGS) ../../../Common/CommandLineParser.cpp
-
-CRC.o: ../../../Common/CRC.cpp
- $(CXX) $(CFLAGS) ../../../Common/CRC.cpp
-
-CrcReg.o: ../../../Common/CrcReg.cpp
- $(CXX) $(CFLAGS) ../../../Common/CrcReg.cpp
-
-IntToString.o: ../../../Common/IntToString.cpp
- $(CXX) $(CFLAGS) ../../../Common/IntToString.cpp
-
-MyString.o: ../../../Common/MyString.cpp
- $(CXX) $(CFLAGS) ../../../Common/MyString.cpp
-
-MyVector.o: ../../../Common/MyVector.cpp
- $(CXX) $(CFLAGS) ../../../Common/MyVector.cpp
-
-MyWindows.o: ../../../Common/MyWindows.cpp
- $(CXX) $(CFLAGS) ../../../Common/MyWindows.cpp
-
-StringConvert.o: ../../../Common/StringConvert.cpp
- $(CXX) $(CFLAGS) ../../../Common/StringConvert.cpp
-
-StringToInt.o: ../../../Common/StringToInt.cpp
- $(CXX) $(CFLAGS) ../../../Common/StringToInt.cpp
-
-PropVariant.o: ../../../Windows/PropVariant.cpp
- $(CXX) $(CFLAGS) ../../../Windows/PropVariant.cpp
-
-System.o: ../../../Windows/System.cpp
- $(CXX) $(CFLAGS) ../../../Windows/System.cpp
-
-7zCrc.o: ../../../../C/7zCrc.c
- $(CXX_C) $(CFLAGS) ../../../../C/7zCrc.c
-
-7zCrcOpt.o: ../../../../C/7zCrcOpt.c
- $(CXX_C) $(CFLAGS) ../../../../C/7zCrcOpt.c
-
-Alloc.o: ../../../../C/Alloc.c
- $(CXX_C) $(CFLAGS) ../../../../C/Alloc.c
-
-Bra86.o: ../../../../C/Bra86.c
- $(CXX_C) $(CFLAGS) ../../../../C/Bra86.c
-
-CpuArch.o: ../../../../C/CpuArch.c
- $(CXX_C) $(CFLAGS) ../../../../C/CpuArch.c
-
-LzFind.o: ../../../../C/LzFind.c
- $(CXX_C) $(CFLAGS) ../../../../C/LzFind.c
-
-ifdef MT_FILES
-LzFindMt.o: ../../../../C/LzFindMt.c
- $(CXX_C) $(CFLAGS) ../../../../C/LzFindMt.c
-
-Threads.o: ../../../../C/Threads.c
- $(CXX_C) $(CFLAGS) ../../../../C/Threads.c
-endif
-
-LzmaDec.o: ../../../../C/LzmaDec.c
- $(CXX_C) $(CFLAGS) ../../../../C/LzmaDec.c
-
-LzmaEnc.o: ../../../../C/LzmaEnc.c
- $(CXX_C) $(CFLAGS) ../../../../C/LzmaEnc.c
-
-Lzma86Dec.o: ../../../../C/Lzma86Dec.c
- $(CXX_C) $(CFLAGS) ../../../../C/Lzma86Dec.c
-
-Lzma86Enc.o: ../../../../C/Lzma86Enc.c
- $(CXX_C) $(CFLAGS) ../../../../C/Lzma86Enc.c
-
-clean:
- -$(RM) $(PROG) $(OBJS)
+PROG = lzma
+
+# IS_X64 = 1
+# USE_ASM = 1
+# ST_MODE = 1
+
+include ../../LzmaDec_gcc.mak
+
+LOCAL_FLAGS_ST =
+MT_OBJS =
+
+
+ifdef SystemDrive
+IS_MINGW = 1
+else
+ifdef SYSTEMDRIVE
+# ifdef OS
+IS_MINGW = 1
+endif
+endif
+
+ifdef ST_MODE
+
+LOCAL_FLAGS_ST = -DZ7_ST
+
+else
+
+MT_OBJS = \
+ $O/LzFindMt.o \
+ $O/LzFindOpt.o \
+ $O/Synchronization.o \
+ $O/Threads.o \
+
+
+
+endif
+
+
+
+LOCAL_FLAGS_SYS =
+
+ifdef IS_MINGW
+
+SYS_OBJS = \
+ $O/Registry.o \
+ $O/resource.o \
+
+else
+
+SYS_OBJS = \
+ $O/FileDir.o \
+ $O/FileFind.o \
+ $O/FileName.o \
+ $O/MyWindows.o \
+ $O/TimeUtils.o \
+
+endif
+
+LOCAL_FLAGS = \
+ $(LOCAL_FLAGS_ST) \
+
+
+COMMON_OBJS = \
+ $O/CommandLineParser.o \
+ $O/CRC.o \
+ $O/CrcReg.o \
+ $O/IntToString.o \
+ $O/LzFindPrepare.o \
+ $O/MyString.o \
+ $O/MyVector.o \
+ $O/NewHandler.o \
+ $O/StringConvert.o \
+ $O/StringToInt.o \
+ $O/UTFConvert.o \
+ $O/Wildcard.o \
+
+WIN_OBJS = \
+ $O/FileIO.o \
+ $O/PropVariant.o \
+ $O/System.o \
+ $O/SystemInfo.o \
+
+COMPRESS_OBJS = \
+ $O/LzmaDecoder.o \
+ $O/LzmaEncoder.o \
+ $O/LzmaRegister.o \
+
+CONSOLE_OBJS = \
+ $O/BenchCon.o \
+ $O/ConsoleClose.o \
+
+7ZIP_COMMON_OBJS = \
+ $O/CreateCoder.o \
+ $O/CWrappers.o \
+ $O/FileStreams.o \
+ $O/FilterCoder.o \
+ $O/MethodProps.o \
+ $O/StreamObjects.o \
+ $O/StreamUtils.o \
+
+C_OBJS = \
+ $O/7zCrc.o \
+ $O/7zCrcOpt.o \
+ $O/Alloc.o \
+ $O/Bra86.o \
+ $O/CpuArch.o \
+ $O/LzFind.o \
+ $O/LzmaDec.o \
+ $O/LzmaEnc.o \
+ $O/Lzma86Dec.o \
+ $O/Lzma86Enc.o \
+
+OBJS = \
+ $(LZMA_DEC_OPT_OBJS) \
+ $(C_OBJS) \
+ $(MT_OBJS) \
+ $(SYS_OBJS) \
+ $(COMMON_OBJS) \
+ $(WIN_OBJS) \
+ $(COMPRESS_OBJS) \
+ $(7ZIP_COMMON_OBJS) \
+ $(CONSOLE_OBJS) \
+ $O/LzmaAlone.o \
+ $O/Bench.o \
+
+include ../../7zip_gcc.mak
diff --git a/CPP/7zip/Bundles/LzmaCon/resource.rc b/CPP/7zip/Bundles/LzmaCon/resource.rc
index 9b54fa8..43b5073 100644
--- a/CPP/7zip/Bundles/LzmaCon/resource.rc
+++ b/CPP/7zip/Bundles/LzmaCon/resource.rc
@@ -1,3 +1,3 @@
-#include "../../MyVersionInfo.rc"
-
-MY_VERSION_INFO_APP("LZMA", "lzma")
+#include "../../MyVersionInfo.rc"
+
+MY_VERSION_INFO_APP("LZMA", "lzma")
diff --git a/CPP/7zip/Bundles/LzmaSpec/LzmaSpec.cpp b/CPP/7zip/Bundles/LzmaSpec/LzmaSpec.cpp
deleted file mode 100644
index 67e8dfc..0000000
--- a/CPP/7zip/Bundles/LzmaSpec/LzmaSpec.cpp
+++ /dev/null
@@ -1,715 +0,0 @@
-/* LzmaSpec.cpp -- LZMA Reference Decoder
-2015-06-14 : Igor Pavlov : Public domain */
-
-// This code implements LZMA file decoding according to LZMA specification.
-// This code is not optimized for speed.
-
-#include <stdio.h>
-
-#ifdef _MSC_VER
- #pragma warning(disable : 4710) // function not inlined
- #pragma warning(disable : 4996) // This function or variable may be unsafe
-#endif
-
-typedef unsigned char Byte;
-typedef unsigned short UInt16;
-
-#ifdef _LZMA_UINT32_IS_ULONG
- typedef unsigned long UInt32;
-#else
- typedef unsigned int UInt32;
-#endif
-
-#if defined(_MSC_VER) || defined(__BORLANDC__)
- typedef unsigned __int64 UInt64;
-#else
- typedef unsigned long long int UInt64;
-#endif
-
-
-struct CInputStream
-{
- FILE *File;
- UInt64 Processed;
-
- void Init() { Processed = 0; }
-
- Byte ReadByte()
- {
- int c = getc(File);
- if (c < 0)
- throw "Unexpected end of file";
- Processed++;
- return (Byte)c;
- }
-};
-
-
-struct COutStream
-{
- FILE *File;
- UInt64 Processed;
-
- void Init() { Processed = 0; }
-
- void WriteByte(Byte b)
- {
- if (putc(b, File) == EOF)
- throw "File writing error";
- Processed++;
- }
-};
-
-
-class COutWindow
-{
- Byte *Buf;
- UInt32 Pos;
- UInt32 Size;
- bool IsFull;
-
-public:
- unsigned TotalPos;
- COutStream OutStream;
-
- COutWindow(): Buf(NULL) {}
- ~COutWindow() { delete []Buf; }
-
- void Create(UInt32 dictSize)
- {
- Buf = new Byte[dictSize];
- Pos = 0;
- Size = dictSize;
- IsFull = false;
- TotalPos = 0;
- }
-
- void PutByte(Byte b)
- {
- TotalPos++;
- Buf[Pos++] = b;
- if (Pos == Size)
- {
- Pos = 0;
- IsFull = true;
- }
- OutStream.WriteByte(b);
- }
-
- Byte GetByte(UInt32 dist) const
- {
- return Buf[dist <= Pos ? Pos - dist : Size - dist + Pos];
- }
-
- void CopyMatch(UInt32 dist, unsigned len)
- {
- for (; len > 0; len--)
- PutByte(GetByte(dist));
- }
-
- bool CheckDistance(UInt32 dist) const
- {
- return dist <= Pos || IsFull;
- }
-
- bool IsEmpty() const
- {
- return Pos == 0 && !IsFull;
- }
-};
-
-
-#define kNumBitModelTotalBits 11
-#define kNumMoveBits 5
-
-typedef UInt16 CProb;
-
-#define PROB_INIT_VAL ((1 << kNumBitModelTotalBits) / 2)
-
-#define INIT_PROBS(p) \
- { for (unsigned i = 0; i < sizeof(p) / sizeof(p[0]); i++) p[i] = PROB_INIT_VAL; }
-
-class CRangeDecoder
-{
- UInt32 Range;
- UInt32 Code;
-
- void Normalize();
-
-public:
-
- CInputStream *InStream;
- bool Corrupted;
-
- bool Init();
- bool IsFinishedOK() const { return Code == 0; }
-
- UInt32 DecodeDirectBits(unsigned numBits);
- unsigned DecodeBit(CProb *prob);
-};
-
-bool CRangeDecoder::Init()
-{
- Corrupted = false;
- Range = 0xFFFFFFFF;
- Code = 0;
-
- Byte b = InStream->ReadByte();
-
- for (int i = 0; i < 4; i++)
- Code = (Code << 8) | InStream->ReadByte();
-
- if (b != 0 || Code == Range)
- Corrupted = true;
- return b == 0;
-}
-
-#define kTopValue ((UInt32)1 << 24)
-
-void CRangeDecoder::Normalize()
-{
- if (Range < kTopValue)
- {
- Range <<= 8;
- Code = (Code << 8) | InStream->ReadByte();
- }
-}
-
-UInt32 CRangeDecoder::DecodeDirectBits(unsigned numBits)
-{
- UInt32 res = 0;
- do
- {
- Range >>= 1;
- Code -= Range;
- UInt32 t = 0 - ((UInt32)Code >> 31);
- Code += Range & t;
-
- if (Code == Range)
- Corrupted = true;
-
- Normalize();
- res <<= 1;
- res += t + 1;
- }
- while (--numBits);
- return res;
-}
-
-unsigned CRangeDecoder::DecodeBit(CProb *prob)
-{
- unsigned v = *prob;
- UInt32 bound = (Range >> kNumBitModelTotalBits) * v;
- unsigned symbol;
- if (Code < bound)
- {
- v += ((1 << kNumBitModelTotalBits) - v) >> kNumMoveBits;
- Range = bound;
- symbol = 0;
- }
- else
- {
- v -= v >> kNumMoveBits;
- Code -= bound;
- Range -= bound;
- symbol = 1;
- }
- *prob = (CProb)v;
- Normalize();
- return symbol;
-}
-
-
-unsigned BitTreeReverseDecode(CProb *probs, unsigned numBits, CRangeDecoder *rc)
-{
- unsigned m = 1;
- unsigned symbol = 0;
- for (unsigned i = 0; i < numBits; i++)
- {
- unsigned bit = rc->DecodeBit(&probs[m]);
- m <<= 1;
- m += bit;
- symbol |= (bit << i);
- }
- return symbol;
-}
-
-template <unsigned NumBits>
-class CBitTreeDecoder
-{
- CProb Probs[(unsigned)1 << NumBits];
-
-public:
-
- void Init()
- {
- INIT_PROBS(Probs);
- }
-
- unsigned Decode(CRangeDecoder *rc)
- {
- unsigned m = 1;
- for (unsigned i = 0; i < NumBits; i++)
- m = (m << 1) + rc->DecodeBit(&Probs[m]);
- return m - ((unsigned)1 << NumBits);
- }
-
- unsigned ReverseDecode(CRangeDecoder *rc)
- {
- return BitTreeReverseDecode(Probs, NumBits, rc);
- }
-};
-
-#define kNumPosBitsMax 4
-
-#define kNumStates 12
-#define kNumLenToPosStates 4
-#define kNumAlignBits 4
-#define kStartPosModelIndex 4
-#define kEndPosModelIndex 14
-#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
-#define kMatchMinLen 2
-
-class CLenDecoder
-{
- CProb Choice;
- CProb Choice2;
- CBitTreeDecoder<3> LowCoder[1 << kNumPosBitsMax];
- CBitTreeDecoder<3> MidCoder[1 << kNumPosBitsMax];
- CBitTreeDecoder<8> HighCoder;
-
-public:
-
- void Init()
- {
- Choice = PROB_INIT_VAL;
- Choice2 = PROB_INIT_VAL;
- HighCoder.Init();
- for (unsigned i = 0; i < (1 << kNumPosBitsMax); i++)
- {
- LowCoder[i].Init();
- MidCoder[i].Init();
- }
- }
-
- unsigned Decode(CRangeDecoder *rc, unsigned posState)
- {
- if (rc->DecodeBit(&Choice) == 0)
- return LowCoder[posState].Decode(rc);
- if (rc->DecodeBit(&Choice2) == 0)
- return 8 + MidCoder[posState].Decode(rc);
- return 16 + HighCoder.Decode(rc);
- }
-};
-
-unsigned UpdateState_Literal(unsigned state)
-{
- if (state < 4) return 0;
- else if (state < 10) return state - 3;
- else return state - 6;
-}
-unsigned UpdateState_Match (unsigned state) { return state < 7 ? 7 : 10; }
-unsigned UpdateState_Rep (unsigned state) { return state < 7 ? 8 : 11; }
-unsigned UpdateState_ShortRep(unsigned state) { return state < 7 ? 9 : 11; }
-
-#define LZMA_DIC_MIN (1 << 12)
-
-class CLzmaDecoder
-{
-public:
- CRangeDecoder RangeDec;
- COutWindow OutWindow;
-
- bool markerIsMandatory;
- unsigned lc, pb, lp;
- UInt32 dictSize;
- UInt32 dictSizeInProperties;
-
- void DecodeProperties(const Byte *properties)
- {
- unsigned d = properties[0];
- if (d >= (9 * 5 * 5))
- throw "Incorrect LZMA properties";
- lc = d % 9;
- d /= 9;
- pb = d / 5;
- lp = d % 5;
- dictSizeInProperties = 0;
- for (int i = 0; i < 4; i++)
- dictSizeInProperties |= (UInt32)properties[i + 1] << (8 * i);
- dictSize = dictSizeInProperties;
- if (dictSize < LZMA_DIC_MIN)
- dictSize = LZMA_DIC_MIN;
- }
-
- CLzmaDecoder(): LitProbs(NULL) {}
- ~CLzmaDecoder() { delete []LitProbs; }
-
- void Create()
- {
- OutWindow.Create(dictSize);
- CreateLiterals();
- }
-
- int Decode(bool unpackSizeDefined, UInt64 unpackSize);
-
-private:
-
- CProb *LitProbs;
-
- void CreateLiterals()
- {
- LitProbs = new CProb[(UInt32)0x300 << (lc + lp)];
- }
-
- void InitLiterals()
- {
- UInt32 num = (UInt32)0x300 << (lc + lp);
- for (UInt32 i = 0; i < num; i++)
- LitProbs[i] = PROB_INIT_VAL;
- }
-
- void DecodeLiteral(unsigned state, UInt32 rep0)
- {
- unsigned prevByte = 0;
- if (!OutWindow.IsEmpty())
- prevByte = OutWindow.GetByte(1);
-
- unsigned symbol = 1;
- unsigned litState = ((OutWindow.TotalPos & ((1 << lp) - 1)) << lc) + (prevByte >> (8 - lc));
- CProb *probs = &LitProbs[(UInt32)0x300 * litState];
-
- if (state >= 7)
- {
- unsigned matchByte = OutWindow.GetByte(rep0 + 1);
- do
- {
- unsigned matchBit = (matchByte >> 7) & 1;
- matchByte <<= 1;
- unsigned bit = RangeDec.DecodeBit(&probs[((1 + matchBit) << 8) + symbol]);
- symbol = (symbol << 1) | bit;
- if (matchBit != bit)
- break;
- }
- while (symbol < 0x100);
- }
- while (symbol < 0x100)
- symbol = (symbol << 1) | RangeDec.DecodeBit(&probs[symbol]);
- OutWindow.PutByte((Byte)(symbol - 0x100));
- }
-
- CBitTreeDecoder<6> PosSlotDecoder[kNumLenToPosStates];
- CBitTreeDecoder<kNumAlignBits> AlignDecoder;
- CProb PosDecoders[1 + kNumFullDistances - kEndPosModelIndex];
-
- void InitDist()
- {
- for (unsigned i = 0; i < kNumLenToPosStates; i++)
- PosSlotDecoder[i].Init();
- AlignDecoder.Init();
- INIT_PROBS(PosDecoders);
- }
-
- unsigned DecodeDistance(unsigned len)
- {
- unsigned lenState = len;
- if (lenState > kNumLenToPosStates - 1)
- lenState = kNumLenToPosStates - 1;
-
- unsigned posSlot = PosSlotDecoder[lenState].Decode(&RangeDec);
- if (posSlot < 4)
- return posSlot;
-
- unsigned numDirectBits = (unsigned)((posSlot >> 1) - 1);
- UInt32 dist = ((2 | (posSlot & 1)) << numDirectBits);
- if (posSlot < kEndPosModelIndex)
- dist += BitTreeReverseDecode(PosDecoders + dist - posSlot, numDirectBits, &RangeDec);
- else
- {
- dist += RangeDec.DecodeDirectBits(numDirectBits - kNumAlignBits) << kNumAlignBits;
- dist += AlignDecoder.ReverseDecode(&RangeDec);
- }
- return dist;
- }
-
- CProb IsMatch[kNumStates << kNumPosBitsMax];
- CProb IsRep[kNumStates];
- CProb IsRepG0[kNumStates];
- CProb IsRepG1[kNumStates];
- CProb IsRepG2[kNumStates];
- CProb IsRep0Long[kNumStates << kNumPosBitsMax];
-
- CLenDecoder LenDecoder;
- CLenDecoder RepLenDecoder;
-
- void Init()
- {
- InitLiterals();
- InitDist();
-
- INIT_PROBS(IsMatch);
- INIT_PROBS(IsRep);
- INIT_PROBS(IsRepG0);
- INIT_PROBS(IsRepG1);
- INIT_PROBS(IsRepG2);
- INIT_PROBS(IsRep0Long);
-
- LenDecoder.Init();
- RepLenDecoder.Init();
- }
-};
-
-
-#define LZMA_RES_ERROR 0
-#define LZMA_RES_FINISHED_WITH_MARKER 1
-#define LZMA_RES_FINISHED_WITHOUT_MARKER 2
-
-int CLzmaDecoder::Decode(bool unpackSizeDefined, UInt64 unpackSize)
-{
- if (!RangeDec.Init())
- return LZMA_RES_ERROR;
-
- Init();
-
- UInt32 rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;
- unsigned state = 0;
-
- for (;;)
- {
- if (unpackSizeDefined && unpackSize == 0 && !markerIsMandatory)
- if (RangeDec.IsFinishedOK())
- return LZMA_RES_FINISHED_WITHOUT_MARKER;
-
- unsigned posState = OutWindow.TotalPos & ((1 << pb) - 1);
-
- if (RangeDec.DecodeBit(&IsMatch[(state << kNumPosBitsMax) + posState]) == 0)
- {
- if (unpackSizeDefined && unpackSize == 0)
- return LZMA_RES_ERROR;
- DecodeLiteral(state, rep0);
- state = UpdateState_Literal(state);
- unpackSize--;
- continue;
- }
-
- unsigned len;
-
- if (RangeDec.DecodeBit(&IsRep[state]) != 0)
- {
- if (unpackSizeDefined && unpackSize == 0)
- return LZMA_RES_ERROR;
- if (OutWindow.IsEmpty())
- return LZMA_RES_ERROR;
- if (RangeDec.DecodeBit(&IsRepG0[state]) == 0)
- {
- if (RangeDec.DecodeBit(&IsRep0Long[(state << kNumPosBitsMax) + posState]) == 0)
- {
- state = UpdateState_ShortRep(state);
- OutWindow.PutByte(OutWindow.GetByte(rep0 + 1));
- unpackSize--;
- continue;
- }
- }
- else
- {
- UInt32 dist;
- if (RangeDec.DecodeBit(&IsRepG1[state]) == 0)
- dist = rep1;
- else
- {
- if (RangeDec.DecodeBit(&IsRepG2[state]) == 0)
- dist = rep2;
- else
- {
- dist = rep3;
- rep3 = rep2;
- }
- rep2 = rep1;
- }
- rep1 = rep0;
- rep0 = dist;
- }
- len = RepLenDecoder.Decode(&RangeDec, posState);
- state = UpdateState_Rep(state);
- }
- else
- {
- rep3 = rep2;
- rep2 = rep1;
- rep1 = rep0;
- len = LenDecoder.Decode(&RangeDec, posState);
- state = UpdateState_Match(state);
- rep0 = DecodeDistance(len);
- if (rep0 == 0xFFFFFFFF)
- return RangeDec.IsFinishedOK() ?
- LZMA_RES_FINISHED_WITH_MARKER :
- LZMA_RES_ERROR;
-
- if (unpackSizeDefined && unpackSize == 0)
- return LZMA_RES_ERROR;
- if (rep0 >= dictSize || !OutWindow.CheckDistance(rep0))
- return LZMA_RES_ERROR;
- }
- len += kMatchMinLen;
- bool isError = false;
- if (unpackSizeDefined && unpackSize < len)
- {
- len = (unsigned)unpackSize;
- isError = true;
- }
- OutWindow.CopyMatch(rep0 + 1, len);
- unpackSize -= len;
- if (isError)
- return LZMA_RES_ERROR;
- }
-}
-
-static void Print(const char *s)
-{
- fputs(s, stdout);
-}
-
-static void PrintError(const char *s)
-{
- fputs(s, stderr);
-}
-
-
-#define CONVERT_INT_TO_STR(charType, tempSize) \
-
-void ConvertUInt64ToString(UInt64 val, char *s)
-{
- char temp[32];
- unsigned i = 0;
- while (val >= 10)
- {
- temp[i++] = (char)('0' + (unsigned)(val % 10));
- val /= 10;
- }
- *s++ = (char)('0' + (unsigned)val);
- while (i != 0)
- {
- i--;
- *s++ = temp[i];
- }
- *s = 0;
-}
-
-void PrintUInt64(const char *title, UInt64 v)
-{
- Print(title);
- Print(" : ");
- char s[32];
- ConvertUInt64ToString(v, s);
- Print(s);
- Print(" bytes \n");
-}
-
-int main2(int numArgs, const char *args[])
-{
- Print("\nLZMA Reference Decoder 15.00 : Igor Pavlov : Public domain : 2015-04-16\n");
- if (numArgs == 1)
- Print("\nUse: lzmaSpec a.lzma outFile");
-
- if (numArgs != 3)
- throw "you must specify two parameters";
-
- CInputStream inStream;
- inStream.File = fopen(args[1], "rb");
- inStream.Init();
- if (inStream.File == 0)
- throw "Can't open input file";
-
- CLzmaDecoder lzmaDecoder;
- lzmaDecoder.OutWindow.OutStream.File = fopen(args[2], "wb+");
- lzmaDecoder.OutWindow.OutStream.Init();
- if (inStream.File == 0)
- throw "Can't open output file";
-
- Byte header[13];
- int i;
- for (i = 0; i < 13; i++)
- header[i] = inStream.ReadByte();
-
- lzmaDecoder.DecodeProperties(header);
-
- printf("\nlc=%d, lp=%d, pb=%d", lzmaDecoder.lc, lzmaDecoder.lp, lzmaDecoder.pb);
- printf("\nDictionary Size in properties = %u", lzmaDecoder.dictSizeInProperties);
- printf("\nDictionary Size for decoding = %u", lzmaDecoder.dictSize);
-
- UInt64 unpackSize = 0;
- bool unpackSizeDefined = false;
- for (i = 0; i < 8; i++)
- {
- Byte b = header[5 + i];
- if (b != 0xFF)
- unpackSizeDefined = true;
- unpackSize |= (UInt64)b << (8 * i);
- }
-
- lzmaDecoder.markerIsMandatory = !unpackSizeDefined;
-
- Print("\n");
- if (unpackSizeDefined)
- PrintUInt64("Uncompressed Size", unpackSize);
- else
- Print("End marker is expected\n");
- lzmaDecoder.RangeDec.InStream = &inStream;
-
- Print("\n");
-
- lzmaDecoder.Create();
-
- int res = lzmaDecoder.Decode(unpackSizeDefined, unpackSize);
-
- PrintUInt64("Read ", inStream.Processed);
- PrintUInt64("Written ", lzmaDecoder.OutWindow.OutStream.Processed);
-
- if (res == LZMA_RES_ERROR)
- throw "LZMA decoding error";
- else if (res == LZMA_RES_FINISHED_WITHOUT_MARKER)
- Print("Finished without end marker");
- else if (res == LZMA_RES_FINISHED_WITH_MARKER)
- {
- if (unpackSizeDefined)
- {
- if (lzmaDecoder.OutWindow.OutStream.Processed != unpackSize)
- throw "Finished with end marker before than specified size";
- Print("Warning: ");
- }
- Print("Finished with end marker");
- }
- else
- throw "Internal Error";
-
- Print("\n");
-
- if (lzmaDecoder.RangeDec.Corrupted)
- {
- Print("\nWarning: LZMA stream is corrupted\n");
- }
-
- return 0;
-}
-
-
-int
- #ifdef _MSC_VER
- __cdecl
- #endif
-main(int numArgs, const char *args[])
-{
- try { return main2(numArgs, args); }
- catch (const char *s)
- {
- PrintError("\nError:\n");
- PrintError(s);
- PrintError("\n");
- return 1;
- }
- catch(...)
- {
- PrintError("\nError\n");
- return 1;
- }
-}
diff --git a/CPP/7zip/Bundles/SFXCon/SFXCon.dsp b/CPP/7zip/Bundles/SFXCon/SFXCon.dsp
index 8775319..1bb063d 100644
--- a/CPP/7zip/Bundles/SFXCon/SFXCon.dsp
+++ b/CPP/7zip/Bundles/SFXCon/SFXCon.dsp
@@ -1,912 +1,1009 @@
-# Microsoft Developer Studio Project File - Name="SFXCon" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Console Application" 0x0103
-
-CFG=SFXCon - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "SFXCon.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "SFXCon.mak" CFG="SFXCon - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "SFXCon - Win32 Release" (based on "Win32 (x86) Console Application")
-!MESSAGE "SFXCon - Win32 Debug" (based on "Win32 (x86) Console Application")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "SFXCon - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "EXTRACT_ONLY" /D "_SFX" /D "NO_READ_FROM_CODER" /Yu"StdAfx.h" /FD /c
-# ADD BASE RSC /l 0x419 /d "NDEBUG"
-# ADD RSC /l 0x419 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"C:\Util\7zCon.exe" /opt:NOWIN98
-# SUBTRACT LINK32 /pdb:none
-
-!ELSEIF "$(CFG)" == "SFXCon - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
-# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /I "..\..\..\..\\" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "EXTRACT_ONLY" /D "_SFX" /D "NO_READ_FROM_CODER" /Yu"StdAfx.h" /FD /GZ /c
-# ADD BASE RSC /l 0x419 /d "_DEBUG"
-# ADD RSC /l 0x419 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"C:\Util\7zCon.exe" /pdbtype:sept
-
-!ENDIF
-
-# Begin Target
-
-# Name "SFXCon - Win32 Release"
-# Name "SFXCon - Win32 Debug"
-# Begin Group "Spec"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=.\resource.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\resource.rc
-# End Source File
-# Begin Source File
-
-SOURCE=.\StdAfx.cpp
-# ADD CPP /Yc"StdAfx.h"
-# End Source File
-# Begin Source File
-
-SOURCE=.\StdAfx.h
-# End Source File
-# End Group
-# Begin Group "Archive Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\CoderMixer2.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\CoderMixer2.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\HandlerOut.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\ItemNameUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\ItemNameUtils.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\MultiStream.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\MultiStream.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\OutStreamWithCRC.h
-# End Source File
-# End Group
-# Begin Group "Console"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\UI\Console\ConsoleClose.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\ConsoleClose.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\ExtractCallbackConsole.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\ExtractCallbackConsole.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\List.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\List.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\MainAr.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\OpenCallbackConsole.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\OpenCallbackConsole.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\PercentPrinter.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\PercentPrinter.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\UserInputUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Console\UserInputUtils.h
-# End Source File
-# End Group
-# Begin Group "7z"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zDecode.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zDecode.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zExtract.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zHandler.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zHandler.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zHeader.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zIn.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zIn.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zItem.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\SplitHandler.cpp
-# End Source File
-# End Group
-# Begin Group "Compress"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Compress\Bcj2Coder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\Bcj2Register.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BcjCoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BcjRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BranchMisc.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BranchMisc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BranchRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\CopyCoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\CopyRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\DeltaFilter.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\Lzma2Decoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\Lzma2Decoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\Lzma2Register.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\LzmaDecoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\LzmaRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\PpmdDecoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\PpmdRegister.cpp
-# End Source File
-# End Group
-# Begin Group "Crypto"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Crypto\7zAes.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Crypto\7zAes.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Crypto\7zAesRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Crypto\MyAes.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Crypto\MyAes.h
-# End Source File
-# End Group
-# Begin Group "Windows"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\Windows\DLL.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\DLL.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\ErrorMsg.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\ErrorMsg.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileDir.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileDir.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileFind.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileFind.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileIO.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileIO.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileName.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileName.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariant.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariant.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariantConv.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariantConv.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Synchronization.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Synchronization.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\System.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\System.h
-# End Source File
-# End Group
-# Begin Group "Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\Common\CommandLineParser.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\CommandLineParser.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\CRC.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\CRC.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\IntToString.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\IntToString.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyString.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyString.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyVector.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyVector.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\NewHandler.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\NewHandler.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StdInStream.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StdInStream.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StdOutStream.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StdOutStream.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StringConvert.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StringConvert.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\UTFConvert.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\UTFConvert.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\Wildcard.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\Wildcard.h
-# End Source File
-# End Group
-# Begin Group "7zip Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Common\CreateCoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\CreateCoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\CWrappers.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\CWrappers.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FilePathAutoRename.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FilePathAutoRename.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FileStreams.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FileStreams.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FilterCoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FilterCoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\InBuffer.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\InBuffer.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\LimitedStreams.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\LimitedStreams.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\LockedStream.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\LockedStream.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\OffsetStream.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\OffsetStream.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\OutBuffer.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\OutBuffer.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\ProgressUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\ProgressUtils.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\PropId.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\RegisterArc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\RegisterCodec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamBinder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamBinder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamObjects.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamObjects.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamUtils.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\VirtThread.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\VirtThread.h
-# End Source File
-# End Group
-# Begin Group "UI"
-
-# PROP Default_Filter ""
-# Begin Group "UI Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ArchiveExtractCallback.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ArchiveOpenCallback.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\DefaultName.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\DefaultName.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ExitCode.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\Extract.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\Extract.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ExtractingFilePath.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ExtractingFilePath.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ExtractMode.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\LoadCodecs.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\LoadCodecs.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\OpenArchive.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\OpenArchive.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\PropIDUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\PropIDUtils.h
-# End Source File
-# End Group
-# End Group
-# Begin Group "C"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\..\C\7zCrc.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\7zCrc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\7zCrcOpt.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Aes.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Aes.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\AesOpt.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Alloc.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Alloc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bcj2.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bcj2.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bra.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bra.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bra86.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\BraIA64.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\CpuArch.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Delta.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Delta.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\DllSecur.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\DllSecur.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma2Dec.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma2Dec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma2DecMt.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma2DecMt.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzmaDec.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzmaDec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\MtDec.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\MtDec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Ppmd7.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Ppmd7.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Ppmd7Dec.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Sha256.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Sha256.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Threads.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Threads.h
-# End Source File
-# End Group
-# Begin Source File
-
-SOURCE=.\7z.ico
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\IArchive.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\SfxCon.cpp
-# End Source File
-# End Target
-# End Project
+# Microsoft Developer Studio Project File - Name="SFXCon" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=SFXCon - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "SFXCon.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "SFXCon.mak" CFG="SFXCon - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "SFXCon - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "SFXCon - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "SFXCon - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_SFX" /D "Z7_NO_READ_FROM_CODER" /FAcs /Yu"StdAfx.h" /FD /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"C:\Util\7zCon.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "SFXCon - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /I "..\..\..\..\\" /D "_DEBUG" /D "WIN32" /D "_CONSOLE" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_SFX" /D "Z7_NO_READ_FROM_CODER" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"C:\Util\7zCon.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "SFXCon - Win32 Release"
+# Name "SFXCon - Win32 Debug"
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\resource.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"StdAfx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "Archive Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\HandlerOut.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\MultiStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\MultiStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.h
+# End Source File
+# End Group
+# Begin Group "Console"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ConsoleClose.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ConsoleClose.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ExtractCallbackConsole.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\ExtractCallbackConsole.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\List.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\List.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\MainAr.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\OpenCallbackConsole.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\OpenCallbackConsole.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\PercentPrinter.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\PercentPrinter.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\UserInputUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Console\UserInputUtils.h
+# End Source File
+# End Group
+# Begin Group "7z"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zDecode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zExtract.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\SplitHandler.cpp
+# End Source File
+# End Group
+# Begin Group "Compress"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\Bcj2Coder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Bcj2Coder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Bcj2Register.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BcjCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BcjCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BcjRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchMisc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchMisc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\DeltaFilter.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Decoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Decoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Register.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdRegister.cpp
+# End Source File
+# End Group
+# Begin Group "Crypto"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Crypto\7zAes.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\7zAes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\7zAesRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\MyAes.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\MyAes.h
+# End Source File
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Common.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyBuffer2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyCom.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Sha256Prepare.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdInStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdInStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdOutStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.h
+# End Source File
+# End Group
+# Begin Group "7zip Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CWrappers.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CWrappers.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LockedStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LockedStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OffsetStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OffsetStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\PropId.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\RegisterArc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\RegisterCodec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamBinder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamBinder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\VirtThread.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\VirtThread.h
+# End Source File
+# End Group
+# Begin Group "UI"
+
+# PROP Default_Filter ""
+# Begin Group "UI Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveOpenCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\DefaultName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\DefaultName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExitCode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Extract.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Extract.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExtractingFilePath.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExtractingFilePath.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExtractMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\LoadCodecs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\LoadCodecs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\OpenArchive.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\OpenArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\PropIDUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\PropIDUtils.h
+# End Source File
+# End Group
+# End Group
+# Begin Group "C"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrcOpt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zStream.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Aes.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Aes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\AesOpt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bcj2.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bcj2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra86.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\BraIA64.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Delta.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Delta.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\DllSecur.c
+
+!IF "$(CFG)" == "SFXCon - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "SFXCon - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\DllSecur.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Dec.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Dec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2DecMt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2DecMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaDec.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaDec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtDec.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtDec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd7.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd7.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd7Dec.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha256.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha256.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha256Opt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.h
+# End Source File
+# End Group
+# Begin Group "7zip"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\IArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ICoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IDecl.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IPassword.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IProgress.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\7z.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\SfxCon.cpp
+# End Source File
+# End Target
+# End Project
diff --git a/CPP/7zip/Bundles/SFXCon/SFXCon.dsw b/CPP/7zip/Bundles/SFXCon/SFXCon.dsw
index bfbc2b7..27bf7e6 100644
--- a/CPP/7zip/Bundles/SFXCon/SFXCon.dsw
+++ b/CPP/7zip/Bundles/SFXCon/SFXCon.dsw
@@ -1,29 +1,29 @@
-Microsoft Developer Studio Workspace File, Format Version 6.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "SFXCon"=.\SFXCon.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
-
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "SFXCon"=.\SFXCon.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/Bundles/SFXCon/SfxCon.cpp b/CPP/7zip/Bundles/SFXCon/SfxCon.cpp
index 9b34a08..cfce24d 100644
--- a/CPP/7zip/Bundles/SFXCon/SfxCon.cpp
+++ b/CPP/7zip/Bundles/SFXCon/SfxCon.cpp
@@ -1,482 +1,521 @@
-// Main.cpp
-
-#include "StdAfx.h"
-
-#include "../../../../C/CpuArch.h"
-
-#include "../../../Common/MyWindows.h"
-
-#include "../../../Common/MyInitGuid.h"
-
-#include "../../../Common/CommandLineParser.h"
-#include "../../../Common/MyException.h"
-
-#ifdef _WIN32
-#include "../../../Windows/DLL.h"
-#include "../../../Windows/FileDir.h"
-#endif
-#include "../../../Windows/FileName.h"
-
-#include "../../UI/Common/ExitCode.h"
-#include "../../UI/Common/Extract.h"
-
-#include "../../UI/Console/ExtractCallbackConsole.h"
-#include "../../UI/Console/List.h"
-#include "../../UI/Console/OpenCallbackConsole.h"
-
-#include "../../MyVersion.h"
-
-#include "../../../../C/DllSecur.h"
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NDir;
-using namespace NCommandLineParser;
-
-#ifdef _WIN32
-HINSTANCE g_hInstance = 0;
-#endif
-int g_CodePage = -1;
-extern CStdOutStream *g_StdStream;
-
-static const char * const kCopyrightString =
-"\n7-Zip SFX " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n";
-
-static const int kNumSwitches = 6;
-
-namespace NKey {
-enum Enum
-{
- kHelp1 = 0,
- kHelp2,
- kDisablePercents,
- kYes,
- kPassword,
- kOutputDir
-};
-
-}
-
-namespace NRecursedType {
-enum EEnum
-{
- kRecursed,
- kWildcardOnlyRecursed,
- kNonRecursed
-};
-}
-/*
-static const char kRecursedIDChar = 'R';
-
-namespace NRecursedPostCharIndex {
- enum EEnum
- {
- kWildcardRecursionOnly = 0,
- kNoRecursion = 1
- };
-}
-
-static const char kFileListID = '@';
-static const char kImmediateNameID = '!';
-
-static const char kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be
-static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be
-*/
-static const CSwitchForm kSwitchForms[kNumSwitches] =
-{
- { "?", NSwitchType::kSimple },
- { "H", NSwitchType::kSimple },
- { "BD", NSwitchType::kSimple },
- { "Y", NSwitchType::kSimple },
- { "P", NSwitchType::kString, false, 1 },
- { "O", NSwitchType::kString, false, 1 },
-};
-
-static const int kNumCommandForms = 3;
-
-static const NRecursedType::EEnum kCommandRecursedDefault[kNumCommandForms] =
-{
- NRecursedType::kRecursed
-};
-
-// static const bool kTestExtractRecursedDefault = true;
-// static const bool kAddRecursedDefault = false;
-
-static const char * const kUniversalWildcard = "*";
-static const int kCommandIndex = 0;
-
-static const char * const kHelpString =
- "\nUsage: 7zSFX [<command>] [<switches>...] [<file_name>...]\n"
- "\n"
- "<Commands>\n"
- // " l: List contents of archive\n"
- " t: Test integrity of archive\n"
- " x: eXtract files with full pathname (default)\n"
- "<Switches>\n"
- // " -bd Disable percentage indicator\n"
- " -o{Directory}: set Output directory\n"
- " -p{Password}: set Password\n"
- " -y: assume Yes on all queries\n";
-
-
-// ---------------------------
-// exception messages
-
-static const char * const kUserErrorMessage = "Incorrect command line"; // NExitCode::kUserError
-// static const char * const kIncorrectListFile = "Incorrect wildcard in listfile";
-static const char * const kIncorrectWildcardInCommandLine = "Incorrect wildcard in command line";
-
-// static const CSysString kFileIsNotArchiveMessageBefore = "File \"";
-// static const CSysString kFileIsNotArchiveMessageAfter = "\" is not archive";
-
-// static const char * const kProcessArchiveMessage = " archive: ";
-
-static const char * const kCantFindSFX = " cannot find sfx";
-
-namespace NCommandType
-{
- enum EEnum
- {
- kTest = 0,
- kFullExtract,
- kList
- };
-}
-
-static const char *g_Commands = "txl";
-
-struct CArchiveCommand
-{
- NCommandType::EEnum CommandType;
-
- NRecursedType::EEnum DefaultRecursedType() const;
-};
-
-bool ParseArchiveCommand(const UString &commandString, CArchiveCommand &command)
-{
- UString s = commandString;
- s.MakeLower_Ascii();
- if (s.Len() != 1)
- return false;
- if (s[0] >= 0x80)
- return false;
- int index = FindCharPosInString(g_Commands, (char)s[0]);
- if (index < 0)
- return false;
- command.CommandType = (NCommandType::EEnum)index;
- return true;
-}
-
-NRecursedType::EEnum CArchiveCommand::DefaultRecursedType() const
-{
- return kCommandRecursedDefault[CommandType];
-}
-
-void PrintHelp(void)
-{
- g_StdOut << kHelpString;
-}
-
-static void ShowMessageAndThrowException(const char *message, NExitCode::EEnum code)
-{
- g_StdOut << message << endl;
- throw code;
-}
-
-static void PrintHelpAndExit() // yyy
-{
- PrintHelp();
- ShowMessageAndThrowException(kUserErrorMessage, NExitCode::kUserError);
-}
-
-// ------------------------------------------------------------------
-// filenames functions
-
-static bool AddNameToCensor(NWildcard::CCensor &wildcardCensor,
- const UString &name, bool include, NRecursedType::EEnum type)
-{
- /*
- if (!IsWildcardFilePathLegal(name))
- return false;
- */
- bool isWildcard = DoesNameContainWildcard(name);
- bool recursed = false;
-
- switch (type)
- {
- case NRecursedType::kWildcardOnlyRecursed:
- recursed = isWildcard;
- break;
- case NRecursedType::kRecursed:
- recursed = true;
- break;
- case NRecursedType::kNonRecursed:
- recursed = false;
- break;
- }
- wildcardCensor.AddPreItem(include, name, recursed, true);
- return true;
-}
-
-void AddCommandLineWildcardToCensor(NWildcard::CCensor &wildcardCensor,
- const UString &name, bool include, NRecursedType::EEnum type)
-{
- if (!AddNameToCensor(wildcardCensor, name, include, type))
- ShowMessageAndThrowException(kIncorrectWildcardInCommandLine, NExitCode::kUserError);
-}
-
-
-#ifndef _WIN32
-static void GetArguments(int numArgs, const char *args[], UStringVector &parts)
-{
- parts.Clear();
- for (int i = 0; i < numArgs; i++)
- {
- UString s = MultiByteToUnicodeString(args[i]);
- parts.Add(s);
- }
-}
-#endif
-
-int Main2(
- #ifndef _WIN32
- int numArgs, const char *args[]
- #endif
-)
-{
- #ifdef _WIN32
- // do we need load Security DLLs for console program?
- LoadSecurityDlls();
- #endif
-
- #if defined(_WIN32) && !defined(UNDER_CE)
- SetFileApisToOEM();
- #endif
-
- g_StdOut << kCopyrightString;
-
- UStringVector commandStrings;
- #ifdef _WIN32
- NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);
- #else
- GetArguments(numArgs, args, commandStrings);
- #endif
-
- #ifdef _WIN32
-
- FString arcPath;
- {
- FString path;
- NDLL::MyGetModuleFileName(path);
- if (!MyGetFullPathName(path, arcPath))
- {
- g_StdOut << "GetFullPathName Error";
- return NExitCode::kFatalError;
- }
- }
-
- #else
-
- UString arcPath = commandStrings.Front();
-
- #endif
-
- #ifndef UNDER_CE
- if (commandStrings.Size() > 0)
- commandStrings.Delete(0);
- #endif
-
- NCommandLineParser::CParser parser;
-
- try
- {
- if (!parser.ParseStrings(kSwitchForms, kNumSwitches, commandStrings))
- {
- g_StdOut << "Command line error:" << endl
- << parser.ErrorMessage << endl
- << parser.ErrorLine << endl;
- return NExitCode::kUserError;
- }
- }
- catch(...)
- {
- PrintHelpAndExit();
- }
-
- if (parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
- {
- PrintHelp();
- return 0;
- }
-
- const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
-
- unsigned curCommandIndex = 0;
-
- CArchiveCommand command;
- if (nonSwitchStrings.IsEmpty())
- command.CommandType = NCommandType::kFullExtract;
- else
- {
- const UString &cmd = nonSwitchStrings[curCommandIndex];
- if (!ParseArchiveCommand(cmd, command))
- {
- g_StdOut << "ERROR: Unknown command:" << endl << cmd << endl;
- return NExitCode::kUserError;
- }
- curCommandIndex = 1;
- }
-
-
- NRecursedType::EEnum recursedType;
- recursedType = command.DefaultRecursedType();
-
- NWildcard::CCensor wildcardCensor;
-
- {
- if (nonSwitchStrings.Size() == curCommandIndex)
- AddCommandLineWildcardToCensor(wildcardCensor, (UString)kUniversalWildcard, true, recursedType);
- for (; curCommandIndex < nonSwitchStrings.Size(); curCommandIndex++)
- {
- const UString &s = nonSwitchStrings[curCommandIndex];
- if (s.IsEmpty())
- throw "Empty file path";
- AddCommandLineWildcardToCensor(wildcardCensor, s, true, recursedType);
- }
- }
-
- bool yesToAll = parser[NKey::kYes].ThereIs;
-
- // NExtractMode::EEnum extractMode;
- // bool isExtractGroupCommand = command.IsFromExtractGroup(extractMode);
-
- bool passwordEnabled = parser[NKey::kPassword].ThereIs;
-
- UString password;
- if (passwordEnabled)
- password = parser[NKey::kPassword].PostStrings[0];
-
- if (!NFind::DoesFileExist(arcPath))
- throw kCantFindSFX;
-
- FString outputDir;
- if (parser[NKey::kOutputDir].ThereIs)
- {
- outputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]);
- NName::NormalizeDirPathPrefix(outputDir);
- }
-
-
- wildcardCensor.AddPathsToCensor(NWildcard::k_RelatPath);
-
- {
- UStringVector v1, v2;
- v1.Add(fs2us(arcPath));
- v2.Add(fs2us(arcPath));
- const NWildcard::CCensorNode &wildcardCensorHead =
- wildcardCensor.Pairs.Front().Head;
-
- CCodecs *codecs = new CCodecs;
- CMyComPtr<
- #ifdef EXTERNAL_CODECS
- ICompressCodecsInfo
- #else
- IUnknown
- #endif
- > compressCodecsInfo = codecs;
- {
- HRESULT result = codecs->Load();
- if (result != S_OK)
- throw CSystemException(result);
- }
-
- if (command.CommandType != NCommandType::kList)
- {
- CExtractCallbackConsole *ecs = new CExtractCallbackConsole;
- CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
- ecs->Init(g_StdStream, &g_StdErr, g_StdStream);
-
- #ifndef _NO_CRYPTO
- ecs->PasswordIsDefined = passwordEnabled;
- ecs->Password = password;
- #endif
-
- /*
- COpenCallbackConsole openCallback;
- openCallback.Init(g_StdStream, g_StdStream);
-
- #ifndef _NO_CRYPTO
- openCallback.PasswordIsDefined = passwordEnabled;
- openCallback.Password = password;
- #endif
- */
-
- CExtractOptions eo;
- eo.StdOutMode = false;
- eo.YesToAll = yesToAll;
- eo.TestMode = command.CommandType == NCommandType::kTest;
- eo.PathMode = NExtract::NPathMode::kFullPaths;
- eo.OverwriteMode = yesToAll ?
- NExtract::NOverwriteMode::kOverwrite :
- NExtract::NOverwriteMode::kAsk;
- eo.OutputDir = outputDir;
-
- UString errorMessage;
- CDecompressStat stat;
- HRESULT result = Extract(
- codecs, CObjectVector<COpenType>(), CIntVector(),
- v1, v2,
- wildcardCensorHead,
- eo, ecs, ecs,
- // NULL, // hash
- errorMessage, stat);
- if (!errorMessage.IsEmpty())
- {
- (*g_StdStream) << endl << "Error: " << errorMessage;;
- if (result == S_OK)
- result = E_FAIL;
- }
-
- if (ecs->NumArcsWithError != 0 || ecs->NumFileErrors != 0)
- {
- if (ecs->NumArcsWithError != 0)
- (*g_StdStream) << endl << "Archive Errors" << endl;
- if (ecs->NumFileErrors != 0)
- (*g_StdStream) << endl << "Sub items Errors: " << ecs->NumFileErrors << endl;
- return NExitCode::kFatalError;
- }
- if (result != S_OK)
- throw CSystemException(result);
- }
- else
- {
- throw CSystemException(E_NOTIMPL);
-
- /*
- UInt64 numErrors = 0;
- UInt64 numWarnings = 0;
- HRESULT result = ListArchives(
- codecs, CObjectVector<COpenType>(), CIntVector(),
- false, // stdInMode
- v1, v2,
- true, // processAltStreams
- false, // showAltStreams
- wildcardCensorHead,
- true, // enableHeaders
- false, // techMode
- #ifndef _NO_CRYPTO
- passwordEnabled, password,
- #endif
- numErrors, numWarnings);
- if (numErrors > 0)
- {
- g_StdOut << endl << "Errors: " << numErrors;
- return NExitCode::kFatalError;
- }
- if (result != S_OK)
- throw CSystemException(result);
- */
- }
- }
- return 0;
-}
+// Main.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+#include "../../../../C/DllSecur.h"
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/MyInitGuid.h"
+
+#include "../../../Common/CommandLineParser.h"
+#include "../../../Common/MyException.h"
+
+#ifdef _WIN32
+#include "../../../Windows/DLL.h"
+#else
+#include "../../../Common/StringConvert.h"
+#endif
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileName.h"
+
+#include "../../UI/Common/ExitCode.h"
+#include "../../UI/Common/Extract.h"
+
+#include "../../UI/Console/ExtractCallbackConsole.h"
+#include "../../UI/Console/List.h"
+#include "../../UI/Console/OpenCallbackConsole.h"
+
+#include "../../MyVersion.h"
+
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+using namespace NCommandLineParser;
+
+#ifdef _WIN32
+extern
+HINSTANCE g_hInstance;
+HINSTANCE g_hInstance = NULL;
+#endif
+extern
+int g_CodePage;
+int g_CodePage = -1;
+extern CStdOutStream *g_StdStream;
+
+static const char * const kCopyrightString =
+"\n7-Zip SFX " MY_VERSION_CPU " : " MY_COPYRIGHT_DATE "\n";
+
+static const int kNumSwitches = 6;
+
+namespace NKey {
+enum Enum
+{
+ kHelp1 = 0,
+ kHelp2,
+ kDisablePercents,
+ kYes,
+ kPassword,
+ kOutputDir
+};
+
+}
+
+namespace NRecursedType {
+enum EEnum
+{
+ kRecursed,
+ kWildcardOnlyRecursed,
+ kNonRecursed
+};
+}
+/*
+static const char kRecursedIDChar = 'R';
+
+namespace NRecursedPostCharIndex {
+ enum EEnum
+ {
+ kWildcardRecursionOnly = 0,
+ kNoRecursion = 1
+ };
+}
+
+static const char kFileListID = '@';
+static const char kImmediateNameID = '!';
+
+static const char kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be
+static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be
+*/
+
+#define SWFRM_3(t, mu, mi) t, mu, mi, NULL
+#define SWFRM_1(t) SWFRM_3(t, false, 0)
+#define SWFRM_SIMPLE SWFRM_1(NSwitchType::kSimple)
+#define SWFRM_STRING_SINGL(mi) SWFRM_3(NSwitchType::kString, false, mi)
+
+static const CSwitchForm kSwitchForms[kNumSwitches] =
+{
+ { "?", SWFRM_SIMPLE },
+ { "H", SWFRM_SIMPLE },
+ { "BD", SWFRM_SIMPLE },
+ { "Y", SWFRM_SIMPLE },
+ { "P", SWFRM_STRING_SINGL(1) },
+ { "O", SWFRM_STRING_SINGL(1) },
+};
+
+static const int kNumCommandForms = 3;
+
+static const NRecursedType::EEnum kCommandRecursedDefault[kNumCommandForms] =
+{
+ NRecursedType::kRecursed
+};
+
+// static const bool kTestExtractRecursedDefault = true;
+// static const bool kAddRecursedDefault = false;
+
+static const char * const kUniversalWildcard = "*";
+
+static const char * const kHelpString =
+ "\nUsage: 7zSFX [<command>] [<switches>...] [<file_name>...]\n"
+ "\n"
+ "<Commands>\n"
+ // " l: List contents of archive\n"
+ " t: Test integrity of archive\n"
+ " x: eXtract files with full pathname (default)\n"
+ "<Switches>\n"
+ // " -bd Disable percentage indicator\n"
+ " -o{Directory}: set Output directory\n"
+ " -p{Password}: set Password\n"
+ " -y: assume Yes on all queries\n";
+
+
+// ---------------------------
+// exception messages
+
+static const char * const kUserErrorMessage = "Incorrect command line"; // NExitCode::kUserError
+// static const char * const kIncorrectListFile = "Incorrect wildcard in listfile";
+static const char * const kIncorrectWildcardInCommandLine = "Incorrect wildcard in command line";
+
+// static const CSysString kFileIsNotArchiveMessageBefore = "File \"";
+// static const CSysString kFileIsNotArchiveMessageAfter = "\" is not archive";
+
+// static const char * const kProcessArchiveMessage = " archive: ";
+
+static const char * const kCantFindSFX = " cannot find sfx";
+
+namespace NCommandType
+{
+ enum EEnum
+ {
+ kTest = 0,
+ kFullExtract,
+ kList
+ };
+}
+
+static const char *g_Commands = "txl";
+
+struct CArchiveCommand
+{
+ NCommandType::EEnum CommandType;
+
+ NRecursedType::EEnum DefaultRecursedType() const;
+};
+
+static bool ParseArchiveCommand(const UString &commandString, CArchiveCommand &command)
+{
+ UString s = commandString;
+ s.MakeLower_Ascii();
+ if (s.Len() != 1)
+ return false;
+ if (s[0] >= 0x80)
+ return false;
+ int index = FindCharPosInString(g_Commands, (char)s[0]);
+ if (index < 0)
+ return false;
+ command.CommandType = (NCommandType::EEnum)index;
+ return true;
+}
+
+NRecursedType::EEnum CArchiveCommand::DefaultRecursedType() const
+{
+ return kCommandRecursedDefault[CommandType];
+}
+
+static void PrintHelp(void)
+{
+ g_StdOut << kHelpString;
+}
+
+Z7_ATTR_NORETURN
+static void ShowMessageAndThrowException(const char *message, NExitCode::EEnum code)
+{
+ g_StdOut << message << endl;
+ throw code;
+}
+
+Z7_ATTR_NORETURN
+static void PrintHelpAndExit() // yyy
+{
+ PrintHelp();
+ ShowMessageAndThrowException(kUserErrorMessage, NExitCode::kUserError);
+}
+
+// ------------------------------------------------------------------
+// filenames functions
+
+static bool AddNameToCensor(NWildcard::CCensor &wildcardCensor,
+ const UString &name, bool include, NRecursedType::EEnum type)
+{
+ /*
+ if (!IsWildcardFilePathLegal(name))
+ return false;
+ */
+ const bool isWildcard = DoesNameContainWildcard(name);
+ bool recursed = false;
+
+ switch (type)
+ {
+ case NRecursedType::kWildcardOnlyRecursed:
+ recursed = isWildcard;
+ break;
+ case NRecursedType::kRecursed:
+ recursed = true;
+ break;
+ case NRecursedType::kNonRecursed:
+ recursed = false;
+ break;
+ }
+
+ NWildcard::CCensorPathProps props;
+ props.Recursive = recursed;
+ wildcardCensor.AddPreItem(include, name, props);
+ return true;
+}
+
+static void AddCommandLineWildcardToCensor(NWildcard::CCensor &wildcardCensor,
+ const UString &name, bool include, NRecursedType::EEnum type)
+{
+ if (!AddNameToCensor(wildcardCensor, name, include, type))
+ ShowMessageAndThrowException(kIncorrectWildcardInCommandLine, NExitCode::kUserError);
+}
+
+
+#ifndef _WIN32
+static void GetArguments(int numArgs, char *args[], UStringVector &parts)
+{
+ parts.Clear();
+ for (int i = 0; i < numArgs; i++)
+ {
+ UString s = MultiByteToUnicodeString(args[i]);
+ parts.Add(s);
+ }
+}
+#endif
+
+
+int Main2(
+ #ifndef _WIN32
+ int numArgs, char *args[]
+ #endif
+);
+int Main2(
+ #ifndef _WIN32
+ int numArgs, char *args[]
+ #endif
+)
+{
+ #ifdef _WIN32
+ // do we need load Security DLLs for console program?
+ LoadSecurityDlls();
+ #endif
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ SetFileApisToOEM();
+ #endif
+
+ #ifdef ENV_HAVE_LOCALE
+ MY_SetLocale();
+ #endif
+
+ g_StdOut << kCopyrightString;
+
+ UStringVector commandStrings;
+ #ifdef _WIN32
+ NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);
+ #else
+ GetArguments(numArgs, args, commandStrings);
+ #endif
+
+ #ifdef _WIN32
+
+ FString arcPath;
+ {
+ FString path;
+ NDLL::MyGetModuleFileName(path);
+ if (!MyGetFullPathName(path, arcPath))
+ {
+ g_StdOut << "GetFullPathName Error";
+ return NExitCode::kFatalError;
+ }
+ }
+
+ #else
+
+ if (commandStrings.IsEmpty())
+ return NExitCode::kFatalError;
+
+ const FString arcPath = us2fs(commandStrings.Front());
+
+ #endif
+
+ #ifndef UNDER_CE
+ if (commandStrings.Size() > 0)
+ commandStrings.Delete(0);
+ #endif
+
+ NCommandLineParser::CParser parser;
+
+ try
+ {
+ if (!parser.ParseStrings(kSwitchForms, kNumSwitches, commandStrings))
+ {
+ g_StdOut << "Command line error:" << endl
+ << parser.ErrorMessage << endl
+ << parser.ErrorLine << endl;
+ return NExitCode::kUserError;
+ }
+ }
+ catch(...)
+ {
+ PrintHelpAndExit();
+ }
+
+ if (parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs)
+ {
+ PrintHelp();
+ return 0;
+ }
+
+ const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
+
+ unsigned curCommandIndex = 0;
+
+ CArchiveCommand command;
+ if (nonSwitchStrings.IsEmpty())
+ command.CommandType = NCommandType::kFullExtract;
+ else
+ {
+ const UString &cmd = nonSwitchStrings[curCommandIndex];
+ if (!ParseArchiveCommand(cmd, command))
+ {
+ g_StdOut << "ERROR: Unknown command:" << endl << cmd << endl;
+ return NExitCode::kUserError;
+ }
+ curCommandIndex = 1;
+ }
+
+
+ NRecursedType::EEnum recursedType;
+ recursedType = command.DefaultRecursedType();
+
+ NWildcard::CCensor wildcardCensor;
+
+ {
+ if (nonSwitchStrings.Size() == curCommandIndex)
+ AddCommandLineWildcardToCensor(wildcardCensor, (UString)kUniversalWildcard, true, recursedType);
+ for (; curCommandIndex < nonSwitchStrings.Size(); curCommandIndex++)
+ {
+ const UString &s = nonSwitchStrings[curCommandIndex];
+ if (s.IsEmpty())
+ throw "Empty file path";
+ AddCommandLineWildcardToCensor(wildcardCensor, s, true, recursedType);
+ }
+ }
+
+ const bool yesToAll = parser[NKey::kYes].ThereIs;
+
+ // NExtractMode::EEnum extractMode;
+ // bool isExtractGroupCommand = command.IsFromExtractGroup(extractMode);
+
+ const bool passwordEnabled = parser[NKey::kPassword].ThereIs;
+
+ UString password;
+ if (passwordEnabled)
+ password = parser[NKey::kPassword].PostStrings[0];
+
+ if (!NFind::DoesFileExist_FollowLink(arcPath))
+ throw kCantFindSFX;
+
+ FString outputDir;
+ if (parser[NKey::kOutputDir].ThereIs)
+ {
+ outputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]);
+ NName::NormalizeDirPathPrefix(outputDir);
+ }
+
+
+ wildcardCensor.AddPathsToCensor(NWildcard::k_RelatPath);
+
+ {
+ UStringVector v1, v2;
+ v1.Add(fs2us(arcPath));
+ v2.Add(fs2us(arcPath));
+ const NWildcard::CCensorNode &wildcardCensorHead =
+ wildcardCensor.Pairs.Front().Head;
+
+ CCodecs *codecs = new CCodecs;
+ CMyComPtr<
+ #ifdef Z7_EXTERNAL_CODECS
+ ICompressCodecsInfo
+ #else
+ IUnknown
+ #endif
+ > compressCodecsInfo = codecs;
+ {
+ HRESULT result = codecs->Load();
+ if (result != S_OK)
+ throw CSystemException(result);
+ }
+
+ if (command.CommandType != NCommandType::kList)
+ {
+ CExtractCallbackConsole *ecs = new CExtractCallbackConsole;
+ CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
+ ecs->Init(g_StdStream, &g_StdErr, g_StdStream);
+
+ #ifndef Z7_NO_CRYPTO
+ ecs->PasswordIsDefined = passwordEnabled;
+ ecs->Password = password;
+ #endif
+
+ /*
+ COpenCallbackConsole openCallback;
+ openCallback.Init(g_StdStream, g_StdStream);
+
+ #ifndef Z7_NO_CRYPTO
+ openCallback.PasswordIsDefined = passwordEnabled;
+ openCallback.Password = password;
+ #endif
+ */
+
+ CExtractOptions eo;
+ eo.StdOutMode = false;
+ eo.YesToAll = yesToAll;
+ eo.TestMode = command.CommandType == NCommandType::kTest;
+ eo.PathMode = NExtract::NPathMode::kFullPaths;
+ eo.OverwriteMode = yesToAll ?
+ NExtract::NOverwriteMode::kOverwrite :
+ NExtract::NOverwriteMode::kAsk;
+ eo.OutputDir = outputDir;
+
+ UString errorMessage;
+ CDecompressStat stat;
+ HRESULT result = Extract(
+ codecs, CObjectVector<COpenType>(), CIntVector(),
+ v1, v2,
+ wildcardCensorHead,
+ eo,
+ ecs, ecs, ecs,
+ // NULL, // hash
+ errorMessage, stat);
+
+ ecs->ClosePercents();
+
+ if (!errorMessage.IsEmpty())
+ {
+ (*g_StdStream) << endl << "Error: " << errorMessage;
+ if (result == S_OK)
+ result = E_FAIL;
+ }
+
+ if ( 0 != ecs->NumCantOpenArcs
+ || 0 != ecs->NumArcsWithError
+ || 0 != ecs->NumFileErrors
+ || 0 != ecs->NumOpenArcErrors)
+ {
+ if (ecs->NumCantOpenArcs != 0)
+ (*g_StdStream) << endl << "Can't open as archive" << endl;
+ if (ecs->NumArcsWithError != 0)
+ (*g_StdStream) << endl << "Archive Errors" << endl;
+ if (ecs->NumFileErrors != 0)
+ (*g_StdStream) << endl << "Sub items Errors: " << ecs->NumFileErrors << endl;
+ if (ecs->NumOpenArcErrors != 0)
+ (*g_StdStream) << endl << "Open Errors: " << ecs->NumOpenArcErrors << endl;
+ return NExitCode::kFatalError;
+ }
+ if (result != S_OK)
+ throw CSystemException(result);
+ }
+ else
+ {
+ throw CSystemException(E_NOTIMPL);
+
+ /*
+ UInt64 numErrors = 0;
+ UInt64 numWarnings = 0;
+ HRESULT result = ListArchives(
+ codecs, CObjectVector<COpenType>(), CIntVector(),
+ false, // stdInMode
+ v1, v2,
+ true, // processAltStreams
+ false, // showAltStreams
+ wildcardCensorHead,
+ true, // enableHeaders
+ false, // techMode
+ #ifndef Z7_NO_CRYPTO
+ passwordEnabled, password,
+ #endif
+ numErrors, numWarnings);
+ if (numErrors > 0)
+ {
+ g_StdOut << endl << "Errors: " << numErrors;
+ return NExitCode::kFatalError;
+ }
+ if (result != S_OK)
+ throw CSystemException(result);
+ */
+ }
+ }
+ return 0;
+}
diff --git a/CPP/7zip/Bundles/SFXCon/StdAfx.cpp b/CPP/7zip/Bundles/SFXCon/StdAfx.cpp
index c6d3b1f..d0feea8 100644
--- a/CPP/7zip/Bundles/SFXCon/StdAfx.cpp
+++ b/CPP/7zip/Bundles/SFXCon/StdAfx.cpp
@@ -1,3 +1,3 @@
-// StdAfx.cpp
-
-#include "StdAfx.h"
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/SFXCon/StdAfx.h b/CPP/7zip/Bundles/SFXCon/StdAfx.h
index 59d9ac1..035267c 100644
--- a/CPP/7zip/Bundles/SFXCon/StdAfx.h
+++ b/CPP/7zip/Bundles/SFXCon/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "../../../Common/Common.h"
-
-#endif
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Bundles/SFXCon/makefile b/CPP/7zip/Bundles/SFXCon/makefile
index 811975c..51aaf51 100644
--- a/CPP/7zip/Bundles/SFXCon/makefile
+++ b/CPP/7zip/Bundles/SFXCon/makefile
@@ -1,134 +1,134 @@
-PROG = 7zCon.sfx
-MY_CONSOLE = 1
-MY_FIXED = 1
-
-CFLAGS = $(CFLAGS) \
- -DEXTRACT_ONLY \
- -DNO_READ_FROM_CODER \
- -D_SFX \
-
-CURRENT_OBJS = \
- $O\SfxCon.obj \
-
-CONSOLE_OBJS = \
- $O\ConsoleClose.obj \
- $O\ExtractCallbackConsole.obj \
- $O\List.obj \
- $O\MainAr.obj \
- $O\OpenCallbackConsole.obj \
- $O\PercentPrinter.obj \
- $O\UserInputUtils.obj \
-
-COMMON_OBJS = \
- $O\CommandLineParser.obj \
- $O\CRC.obj \
- $O\IntToString.obj \
- $O\MyString.obj \
- $O\MyVector.obj \
- $O\NewHandler.obj \
- $O\StdInStream.obj \
- $O\StdOutStream.obj \
- $O\StringConvert.obj \
- $O\Wildcard.obj \
- $O\UTFConvert.obj \
-
-WIN_OBJS = \
- $O\DLL.obj \
- $O\ErrorMsg.obj \
- $O\FileDir.obj \
- $O\FileFind.obj \
- $O\FileIO.obj \
- $O\FileName.obj \
- $O\PropVariant.obj \
- $O\PropVariantConv.obj \
- $O\Synchronization.obj \
- $O\System.obj \
-
-7ZIP_COMMON_OBJS = \
- $O\CreateCoder.obj \
- $O\CWrappers.obj \
- $O\FilePathAutoRename.obj \
- $O\FileStreams.obj \
- $O\InBuffer.obj \
- $O\FilterCoder.obj \
- $O\LimitedStreams.obj \
- $O\OutBuffer.obj \
- $O\ProgressUtils.obj \
- $O\PropId.obj \
- $O\StreamBinder.obj \
- $O\StreamObjects.obj \
- $O\StreamUtils.obj \
- $O\VirtThread.obj \
-
-UI_COMMON_OBJS = \
- $O\ArchiveExtractCallback.obj \
- $O\ArchiveOpenCallback.obj \
- $O\DefaultName.obj \
- $O\LoadCodecs.obj \
- $O\Extract.obj \
- $O\ExtractingFilePath.obj \
- $O\OpenArchive.obj \
- $O\PropIDUtils.obj \
-
-AR_OBJS = \
- $O\SplitHandler.obj \
-
-AR_COMMON_OBJS = \
- $O\CoderMixer2.obj \
- $O\ItemNameUtils.obj \
- $O\MultiStream.obj \
- $O\OutStreamWithCRC.obj \
-
-
-7Z_OBJS = \
- $O\7zDecode.obj \
- $O\7zExtract.obj \
- $O\7zHandler.obj \
- $O\7zIn.obj \
- $O\7zRegister.obj \
-
-COMPRESS_OBJS = \
- $O\Bcj2Coder.obj \
- $O\Bcj2Register.obj \
- $O\BcjCoder.obj \
- $O\BcjRegister.obj \
- $O\BranchMisc.obj \
- $O\BranchRegister.obj \
- $O\CopyCoder.obj \
- $O\CopyRegister.obj \
- $O\DeltaFilter.obj \
- $O\Lzma2Decoder.obj \
- $O\Lzma2Register.obj \
- $O\LzmaDecoder.obj \
- $O\LzmaRegister.obj \
- $O\PpmdDecoder.obj \
- $O\PpmdRegister.obj \
-
-CRYPTO_OBJS = \
- $O\7zAes.obj \
- $O\7zAesRegister.obj \
- $O\MyAes.obj \
-
-C_OBJS = \
- $O\Alloc.obj \
- $O\Bcj2.obj \
- $O\Bra.obj \
- $O\Bra86.obj \
- $O\BraIA64.obj \
- $O\CpuArch.obj \
- $O\Delta.obj \
- $O\DllSecur.obj \
- $O\Lzma2Dec.obj \
- $O\Lzma2DecMt.obj \
- $O\LzmaDec.obj \
- $O\MtDec.obj \
- $O\Ppmd7.obj \
- $O\Ppmd7Dec.obj \
- $O\Sha256.obj \
- $O\Threads.obj \
-
-!include "../../Aes.mak"
-!include "../../Crc.mak"
-!include "../../LzmaDec.mak"
-
-!include "../../7zip.mak"
+PROG = 7zCon.sfx
+MY_CONSOLE = 1
+MY_FIXED = 1
+
+CFLAGS = $(CFLAGS) \
+ -DZ7_EXTRACT_ONLY \
+ -DZ7_NO_READ_FROM_CODER \
+ -DZ7_SFX \
+
+CURRENT_OBJS = \
+ $O\SfxCon.obj \
+
+CONSOLE_OBJS = \
+ $O\ConsoleClose.obj \
+ $O\ExtractCallbackConsole.obj \
+ $O\List.obj \
+ $O\MainAr.obj \
+ $O\OpenCallbackConsole.obj \
+ $O\PercentPrinter.obj \
+ $O\UserInputUtils.obj \
+
+COMMON_OBJS = \
+ $O\CommandLineParser.obj \
+ $O\CRC.obj \
+ $O\IntToString.obj \
+ $O\MyString.obj \
+ $O\MyVector.obj \
+ $O\NewHandler.obj \
+ $O\StdInStream.obj \
+ $O\StdOutStream.obj \
+ $O\StringConvert.obj \
+ $O\UTFConvert.obj \
+ $O\Wildcard.obj \
+
+WIN_OBJS = \
+ $O\DLL.obj \
+ $O\ErrorMsg.obj \
+ $O\FileDir.obj \
+ $O\FileFind.obj \
+ $O\FileIO.obj \
+ $O\FileName.obj \
+ $O\PropVariant.obj \
+ $O\PropVariantConv.obj \
+ $O\Synchronization.obj \
+ $O\System.obj \
+
+7ZIP_COMMON_OBJS = \
+ $O\CreateCoder.obj \
+ $O\CWrappers.obj \
+ $O\FilePathAutoRename.obj \
+ $O\FileStreams.obj \
+ $O\InBuffer.obj \
+ $O\FilterCoder.obj \
+ $O\LimitedStreams.obj \
+ $O\OutBuffer.obj \
+ $O\ProgressUtils.obj \
+ $O\PropId.obj \
+ $O\StreamBinder.obj \
+ $O\StreamObjects.obj \
+ $O\StreamUtils.obj \
+ $O\VirtThread.obj \
+
+UI_COMMON_OBJS = \
+ $O\ArchiveExtractCallback.obj \
+ $O\ArchiveOpenCallback.obj \
+ $O\DefaultName.obj \
+ $O\Extract.obj \
+ $O\ExtractingFilePath.obj \
+ $O\LoadCodecs.obj \
+ $O\OpenArchive.obj \
+ $O\PropIDUtils.obj \
+
+AR_OBJS = \
+ $O\SplitHandler.obj \
+
+AR_COMMON_OBJS = \
+ $O\CoderMixer2.obj \
+ $O\ItemNameUtils.obj \
+ $O\MultiStream.obj \
+ $O\OutStreamWithCRC.obj \
+
+7Z_OBJS = \
+ $O\7zDecode.obj \
+ $O\7zExtract.obj \
+ $O\7zHandler.obj \
+ $O\7zIn.obj \
+ $O\7zRegister.obj \
+
+COMPRESS_OBJS = \
+ $O\Bcj2Coder.obj \
+ $O\Bcj2Register.obj \
+ $O\BcjCoder.obj \
+ $O\BcjRegister.obj \
+ $O\BranchMisc.obj \
+ $O\BranchRegister.obj \
+ $O\CopyCoder.obj \
+ $O\CopyRegister.obj \
+ $O\DeltaFilter.obj \
+ $O\Lzma2Decoder.obj \
+ $O\Lzma2Register.obj \
+ $O\LzmaDecoder.obj \
+ $O\LzmaRegister.obj \
+ $O\PpmdDecoder.obj \
+ $O\PpmdRegister.obj \
+
+CRYPTO_OBJS = \
+ $O\7zAes.obj \
+ $O\7zAesRegister.obj \
+ $O\MyAes.obj \
+
+C_OBJS = \
+ $O\7zStream.obj \
+ $O\Alloc.obj \
+ $O\Bcj2.obj \
+ $O\Bra.obj \
+ $O\Bra86.obj \
+ $O\BraIA64.obj \
+ $O\CpuArch.obj \
+ $O\Delta.obj \
+ $O\DllSecur.obj \
+ $O\Lzma2Dec.obj \
+ $O\Lzma2DecMt.obj \
+ $O\LzmaDec.obj \
+ $O\MtDec.obj \
+ $O\Ppmd7.obj \
+ $O\Ppmd7Dec.obj \
+ $O\Threads.obj \
+
+!include "../../Aes.mak"
+!include "../../Crc.mak"
+!include "../../LzmaDec.mak"
+!include "../../Sha256.mak"
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/Bundles/SFXCon/makefile.gcc b/CPP/7zip/Bundles/SFXCon/makefile.gcc
new file mode 100644
index 0000000..9278502
--- /dev/null
+++ b/CPP/7zip/Bundles/SFXCon/makefile.gcc
@@ -0,0 +1,213 @@
+PROG = 7zCon
+
+# IS_X64 = 1
+# USE_ASM = 1
+# ST_MODE = 1
+
+include ../../LzmaDec_gcc.mak
+
+
+LOCAL_FLAGS_ST =
+MT_OBJS =
+
+
+ifdef SystemDrive
+IS_MINGW = 1
+else
+ifdef SYSTEMDRIVE
+# ifdef OS
+IS_MINGW = 1
+endif
+endif
+
+ifdef ST_MODE
+
+LOCAL_FLAGS_ST = -DZ7_ST
+
+ifdef IS_MINGW
+MT_OBJS = \
+ $O/Threads.o \
+
+endif
+
+else
+
+MT_OBJS = \
+ $O/StreamBinder.o \
+ $O/Synchronization.o \
+ $O/VirtThread.o \
+ $O/Threads.o \
+
+endif
+
+
+
+LOCAL_FLAGS_SYS =
+
+ifdef IS_MINGW
+
+LOCAL_FLAGS_SYS = \
+
+SYS_OBJS = \
+ $O/DLL.o \
+ $O/DllSecur.o \
+ $O/resource.o \
+
+else
+
+SYS_OBJS = \
+ $O/MyWindows.o \
+
+endif
+
+LOCAL_FLAGS = \
+ $(LOCAL_FLAGS_ST) \
+ $(LOCAL_FLAGS_SYS) \
+ -DZ7_EXTRACT_ONLY \
+ -DZ7_NO_READ_FROM_CODER \
+ -DZ7_SFX \
+
+
+CURRENT_OBJS = \
+ $O/SfxCon.o \
+
+CONSOLE_OBJS = \
+ $O/ConsoleClose.o \
+ $O/ExtractCallbackConsole.o \
+ $O/List.o \
+ $O/MainAr.o \
+ $O/OpenCallbackConsole.o \
+ $O/PercentPrinter.o \
+ $O/UserInputUtils.o \
+
+COMMON_OBJS = \
+ $O/CommandLineParser.o \
+ $O/CRC.o \
+ $O/IntToString.o \
+ $O/MyString.o \
+ $O/MyVector.o \
+ $O/NewHandler.o \
+ $O/Sha256Prepare.o \
+ $O/StdInStream.o \
+ $O/StdOutStream.o \
+ $O/StringConvert.o \
+ $O/UTFConvert.o \
+ $O/Wildcard.o \
+
+WIN_OBJS = \
+ \
+ $O/ErrorMsg.o \
+ $O/FileDir.o \
+ $O/FileFind.o \
+ $O/FileIO.o \
+ $O/FileName.o \
+ $O/PropVariant.o \
+ $O/PropVariantConv.o \
+ \
+ $O/System.o \
+ $O/TimeUtils.o \
+
+7ZIP_COMMON_OBJS = \
+ $O/CreateCoder.o \
+ $O/CWrappers.o \
+ $O/FilePathAutoRename.o \
+ $O/FileStreams.o \
+ $O/InBuffer.o \
+ $O/FilterCoder.o \
+ $O/LimitedStreams.o \
+ $O/OutBuffer.o \
+ $O/ProgressUtils.o \
+ $O/PropId.o \
+ \
+ $O/StreamObjects.o \
+ $O/StreamUtils.o \
+ \
+
+UI_COMMON_OBJS = \
+ $O/ArchiveExtractCallback.o \
+ $O/ArchiveOpenCallback.o \
+ $O/DefaultName.o \
+ $O/Extract.o \
+ $O/ExtractingFilePath.o \
+ $O/LoadCodecs.o \
+ $O/OpenArchive.o \
+ $O/PropIDUtils.o \
+
+AR_OBJS = \
+ $O/SplitHandler.o \
+
+AR_COMMON_OBJS = \
+ $O/CoderMixer2.o \
+ $O/ItemNameUtils.o \
+ $O/MultiStream.o \
+ $O/OutStreamWithCRC.o \
+
+7Z_OBJS = \
+ $O/7zDecode.o \
+ $O/7zExtract.o \
+ $O/7zHandler.o \
+ $O/7zIn.o \
+ $O/7zRegister.o \
+
+COMPRESS_OBJS = \
+ $O/Bcj2Coder.o \
+ $O/Bcj2Register.o \
+ $O/BcjCoder.o \
+ $O/BcjRegister.o \
+ $O/BranchMisc.o \
+ $O/BranchRegister.o \
+ $O/CopyCoder.o \
+ $O/CopyRegister.o \
+ $O/DeltaFilter.o \
+ $O/Lzma2Decoder.o \
+ $O/Lzma2Register.o \
+ $O/LzmaDecoder.o \
+ $O/LzmaRegister.o \
+ $O/PpmdDecoder.o \
+ $O/PpmdRegister.o \
+
+CRYPTO_OBJS = \
+ $O/7zAes.o \
+ $O/7zAesRegister.o \
+ $O/MyAes.o \
+
+C_OBJS = \
+ $O/7zStream.o \
+ $O/Alloc.o \
+ $O/Bcj2.o \
+ $O/Bra.o \
+ $O/Bra86.o \
+ $O/BraIA64.o \
+ $O/CpuArch.o \
+ $O/Delta.o \
+ $O/Lzma2Dec.o \
+ $O/Lzma2DecMt.o \
+ $O/LzmaDec.o \
+ $O/MtDec.o \
+ $O/Ppmd7.o \
+ $O/Ppmd7Dec.o \
+ $O/Sha256.o \
+ $O/Sha256Opt.o \
+ $O/7zCrc.o \
+ $O/7zCrcOpt.o \
+ $O/Aes.o \
+ $O/AesOpt.o \
+
+OBJS = \
+ $(LZMA_DEC_OPT_OBJS) \
+ $(C_OBJS) \
+ $(MT_OBJS) \
+ $(SYS_OBJS) \
+ $(COMMON_OBJS) \
+ $(WIN_OBJS) \
+ $(COMPRESS_OBJS) \
+ $(CRYPTO_OBJS) \
+ $(7ZIP_COMMON_OBJS) \
+ $(AR_OBJS) \
+ $(AR_COMMON_OBJS) \
+ $(7Z_OBJS) \
+ $(UI_COMMON_OBJS) \
+ $(CONSOLE_OBJS) \
+ $(CURRENT_OBJS) \
+
+include ../../7zip_gcc.mak
diff --git a/CPP/7zip/Bundles/SFXCon/resource.rc b/CPP/7zip/Bundles/SFXCon/resource.rc
index 97882cd..6576212 100644
--- a/CPP/7zip/Bundles/SFXCon/resource.rc
+++ b/CPP/7zip/Bundles/SFXCon/resource.rc
@@ -1,5 +1,9 @@
-#include "../../MyVersionInfo.rc"
-
-MY_VERSION_INFO_APP("7z Console SFX", "7z.sfx")
-
-101 ICON "7z.ico" \ No newline at end of file
+#include "../../MyVersionInfo.rc"
+
+MY_VERSION_INFO_APP("7z Console SFX", "7z.sfx")
+
+101 ICON "7z.ico"
+
+#ifndef UNDER_CE
+1 24 MOVEABLE PURE "../../UI/Console/Console.manifest"
+#endif
diff --git a/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.cpp b/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.cpp
index d35a24f..9d632ee 100644
--- a/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.cpp
+++ b/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.cpp
@@ -1,246 +1,246 @@
-// ExtractCallbackSfx.h
-
-#include "StdAfx.h"
-
-#include "../../../Common/Wildcard.h"
-
-#include "../../../Windows/FileDir.h"
-#include "../../../Windows/FileFind.h"
-#include "../../../Windows/FileName.h"
-#include "../../../Windows/PropVariant.h"
-
-#include "ExtractCallbackSfx.h"
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NDir;
-
-static LPCSTR const kCantDeleteFile = "Can not delete output file";
-static LPCSTR const kCantOpenFile = "Can not open output file";
-static LPCSTR const kUnsupportedMethod = "Unsupported Method";
-
-void CExtractCallbackImp::Init(IInArchive *archiveHandler,
- const FString &directoryPath,
- const UString &itemDefaultName,
- const FILETIME &defaultMTime,
- UInt32 defaultAttributes)
-{
- _message.Empty();
- _isCorrupt = false;
- _itemDefaultName = itemDefaultName;
- _defaultMTime = defaultMTime;
- _defaultAttributes = defaultAttributes;
- _archiveHandler = archiveHandler;
- _directoryPath = directoryPath;
- NName::NormalizeDirPathPrefix(_directoryPath);
-}
-
-HRESULT CExtractCallbackImp::Open_CheckBreak()
-{
- #ifndef _NO_PROGRESS
- return ProgressDialog.Sync.ProcessStopAndPause();
- #else
- return S_OK;
- #endif
-}
-
-HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */)
-{
- return S_OK;
-}
-
-HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */)
-{
- #ifndef _NO_PROGRESS
- return ProgressDialog.Sync.ProcessStopAndPause();
- #else
- return S_OK;
- #endif
-}
-
-HRESULT CExtractCallbackImp::Open_Finished()
-{
- return S_OK;
-}
-
-STDMETHODIMP CExtractCallbackImp::SetTotal(UInt64 size)
-{
- #ifndef _NO_PROGRESS
- ProgressDialog.Sync.SetProgress(size, 0);
- #endif
- return S_OK;
-}
-
-STDMETHODIMP CExtractCallbackImp::SetCompleted(const UInt64 *completeValue)
-{
- #ifndef _NO_PROGRESS
- RINOK(ProgressDialog.Sync.ProcessStopAndPause());
- if (completeValue != NULL)
- ProgressDialog.Sync.SetPos(*completeValue);
- #endif
- return S_OK;
-}
-
-void CExtractCallbackImp::CreateComplexDirectory(const UStringVector &dirPathParts)
-{
- FString fullPath = _directoryPath;
- FOR_VECTOR (i, dirPathParts)
- {
- fullPath += us2fs(dirPathParts[i]);
- CreateDir(fullPath);
- fullPath.Add_PathSepar();
- }
-}
-
-STDMETHODIMP CExtractCallbackImp::GetStream(UInt32 index,
- ISequentialOutStream **outStream, Int32 askExtractMode)
-{
- #ifndef _NO_PROGRESS
- if (ProgressDialog.Sync.GetStopped())
- return E_ABORT;
- #endif
- _outFileStream.Release();
-
- UString fullPath;
- {
- NCOM::CPropVariant prop;
- RINOK(_archiveHandler->GetProperty(index, kpidPath, &prop));
- if (prop.vt == VT_EMPTY)
- fullPath = _itemDefaultName;
- else
- {
- if (prop.vt != VT_BSTR)
- return E_FAIL;
- fullPath.SetFromBstr(prop.bstrVal);
- }
- _filePath = fullPath;
- }
-
- if (askExtractMode == NArchive::NExtract::NAskMode::kExtract)
- {
- NCOM::CPropVariant prop;
- RINOK(_archiveHandler->GetProperty(index, kpidAttrib, &prop));
- if (prop.vt == VT_EMPTY)
- _processedFileInfo.Attributes = _defaultAttributes;
- else
- {
- if (prop.vt != VT_UI4)
- return E_FAIL;
- _processedFileInfo.Attributes = prop.ulVal;
- }
-
- RINOK(_archiveHandler->GetProperty(index, kpidIsDir, &prop));
- _processedFileInfo.IsDir = VARIANT_BOOLToBool(prop.boolVal);
-
- bool isAnti = false;
- {
- NCOM::CPropVariant propTemp;
- RINOK(_archiveHandler->GetProperty(index, kpidIsAnti, &propTemp));
- if (propTemp.vt == VT_BOOL)
- isAnti = VARIANT_BOOLToBool(propTemp.boolVal);
- }
-
- RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop));
- switch (prop.vt)
- {
- case VT_EMPTY: _processedFileInfo.MTime = _defaultMTime; break;
- case VT_FILETIME: _processedFileInfo.MTime = prop.filetime; break;
- default: return E_FAIL;
- }
-
- UStringVector pathParts;
- SplitPathToParts(fullPath, pathParts);
- if (pathParts.IsEmpty())
- return E_FAIL;
-
- UString processedPath = fullPath;
-
- if (!_processedFileInfo.IsDir)
- pathParts.DeleteBack();
- if (!pathParts.IsEmpty())
- {
- if (!isAnti)
- CreateComplexDirectory(pathParts);
- }
-
- FString fullProcessedPath = _directoryPath + us2fs(processedPath);
-
- if (_processedFileInfo.IsDir)
- {
- _diskFilePath = fullProcessedPath;
-
- if (isAnti)
- RemoveDir(_diskFilePath);
- else
- SetDirTime(_diskFilePath, NULL, NULL, &_processedFileInfo.MTime);
- return S_OK;
- }
-
- NFind::CFileInfo fileInfo;
- if (fileInfo.Find(fullProcessedPath))
- {
- if (!DeleteFileAlways(fullProcessedPath))
- {
- _message = kCantDeleteFile;
- return E_FAIL;
- }
- }
-
- if (!isAnti)
- {
- _outFileStreamSpec = new COutFileStream;
- CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
- if (!_outFileStreamSpec->Create(fullProcessedPath, true))
- {
- _message = kCantOpenFile;
- return E_FAIL;
- }
- _outFileStream = outStreamLoc;
- *outStream = outStreamLoc.Detach();
- }
- _diskFilePath = fullProcessedPath;
- }
- else
- {
- *outStream = NULL;
- }
- return S_OK;
-}
-
-STDMETHODIMP CExtractCallbackImp::PrepareOperation(Int32 askExtractMode)
-{
- _extractMode = (askExtractMode == NArchive::NExtract::NAskMode::kExtract);
- return S_OK;
-}
-
-STDMETHODIMP CExtractCallbackImp::SetOperationResult(Int32 resultEOperationResult)
-{
- switch (resultEOperationResult)
- {
- case NArchive::NExtract::NOperationResult::kOK:
- break;
-
- default:
- {
- _outFileStream.Release();
- switch (resultEOperationResult)
- {
- case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
- _message = kUnsupportedMethod;
- break;
- default:
- _isCorrupt = true;
- }
- return E_FAIL;
- }
- }
- if (_outFileStream != NULL)
- {
- _outFileStreamSpec->SetMTime(&_processedFileInfo.MTime);
- RINOK(_outFileStreamSpec->Close());
- }
- _outFileStream.Release();
- if (_extractMode)
- SetFileAttrib(_diskFilePath, _processedFileInfo.Attributes);
- return S_OK;
-}
+// ExtractCallbackSfx.h
+
+#include "StdAfx.h"
+
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/PropVariant.h"
+
+#include "ExtractCallbackSfx.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+static LPCSTR const kCantDeleteFile = "Cannot delete output file";
+static LPCSTR const kCantOpenFile = "Cannot open output file";
+static LPCSTR const kUnsupportedMethod = "Unsupported Method";
+
+void CExtractCallbackImp::Init(IInArchive *archiveHandler,
+ const FString &directoryPath,
+ const UString &itemDefaultName,
+ const FILETIME &defaultMTime,
+ UInt32 defaultAttributes)
+{
+ _message.Empty();
+ _isCorrupt = false;
+ _itemDefaultName = itemDefaultName;
+ _defaultMTime = defaultMTime;
+ _defaultAttributes = defaultAttributes;
+ _archiveHandler = archiveHandler;
+ _directoryPath = directoryPath;
+ NName::NormalizeDirPathPrefix(_directoryPath);
+}
+
+HRESULT CExtractCallbackImp::Open_CheckBreak()
+{
+ #ifndef _NO_PROGRESS
+ return ProgressDialog.Sync.ProcessStopAndPause();
+ #else
+ return S_OK;
+ #endif
+}
+
+HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */)
+{
+ return S_OK;
+}
+
+HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */)
+{
+ #ifndef _NO_PROGRESS
+ return ProgressDialog.Sync.ProcessStopAndPause();
+ #else
+ return S_OK;
+ #endif
+}
+
+HRESULT CExtractCallbackImp::Open_Finished()
+{
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CExtractCallbackImp::SetTotal(UInt64 size))
+{
+ #ifndef _NO_PROGRESS
+ ProgressDialog.Sync.SetProgress(size, 0);
+ #endif
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CExtractCallbackImp::SetCompleted(const UInt64 *completeValue))
+{
+ #ifndef _NO_PROGRESS
+ RINOK(ProgressDialog.Sync.ProcessStopAndPause())
+ if (completeValue != NULL)
+ ProgressDialog.Sync.SetPos(*completeValue);
+ #endif
+ return S_OK;
+}
+
+void CExtractCallbackImp::CreateComplexDirectory(const UStringVector &dirPathParts)
+{
+ FString fullPath = _directoryPath;
+ FOR_VECTOR (i, dirPathParts)
+ {
+ fullPath += us2fs(dirPathParts[i]);
+ CreateDir(fullPath);
+ fullPath.Add_PathSepar();
+ }
+}
+
+Z7_COM7F_IMF(CExtractCallbackImp::GetStream(UInt32 index,
+ ISequentialOutStream **outStream, Int32 askExtractMode))
+{
+ #ifndef _NO_PROGRESS
+ if (ProgressDialog.Sync.GetStopped())
+ return E_ABORT;
+ #endif
+ _outFileStream.Release();
+
+ UString fullPath;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(_archiveHandler->GetProperty(index, kpidPath, &prop))
+ if (prop.vt == VT_EMPTY)
+ fullPath = _itemDefaultName;
+ else
+ {
+ if (prop.vt != VT_BSTR)
+ return E_FAIL;
+ fullPath.SetFromBstr(prop.bstrVal);
+ }
+ _filePath = fullPath;
+ }
+
+ if (askExtractMode == NArchive::NExtract::NAskMode::kExtract)
+ {
+ NCOM::CPropVariant prop;
+ RINOK(_archiveHandler->GetProperty(index, kpidAttrib, &prop))
+ if (prop.vt == VT_EMPTY)
+ _processedFileInfo.Attributes = _defaultAttributes;
+ else
+ {
+ if (prop.vt != VT_UI4)
+ return E_FAIL;
+ _processedFileInfo.Attributes = prop.ulVal;
+ }
+
+ RINOK(_archiveHandler->GetProperty(index, kpidIsDir, &prop))
+ _processedFileInfo.IsDir = VARIANT_BOOLToBool(prop.boolVal);
+
+ bool isAnti = false;
+ {
+ NCOM::CPropVariant propTemp;
+ RINOK(_archiveHandler->GetProperty(index, kpidIsAnti, &propTemp))
+ if (propTemp.vt == VT_BOOL)
+ isAnti = VARIANT_BOOLToBool(propTemp.boolVal);
+ }
+
+ RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop))
+ switch (prop.vt)
+ {
+ case VT_EMPTY: _processedFileInfo.MTime = _defaultMTime; break;
+ case VT_FILETIME: _processedFileInfo.MTime = prop.filetime; break;
+ default: return E_FAIL;
+ }
+
+ UStringVector pathParts;
+ SplitPathToParts(fullPath, pathParts);
+ if (pathParts.IsEmpty())
+ return E_FAIL;
+
+ UString processedPath = fullPath;
+
+ if (!_processedFileInfo.IsDir)
+ pathParts.DeleteBack();
+ if (!pathParts.IsEmpty())
+ {
+ if (!isAnti)
+ CreateComplexDirectory(pathParts);
+ }
+
+ FString fullProcessedPath = _directoryPath + us2fs(processedPath);
+
+ if (_processedFileInfo.IsDir)
+ {
+ _diskFilePath = fullProcessedPath;
+
+ if (isAnti)
+ RemoveDir(_diskFilePath);
+ else
+ SetDirTime(_diskFilePath, NULL, NULL, &_processedFileInfo.MTime);
+ return S_OK;
+ }
+
+ NFind::CFileInfo fileInfo;
+ if (fileInfo.Find(fullProcessedPath))
+ {
+ if (!DeleteFileAlways(fullProcessedPath))
+ {
+ _message = kCantDeleteFile;
+ return E_FAIL;
+ }
+ }
+
+ if (!isAnti)
+ {
+ _outFileStreamSpec = new COutFileStream;
+ CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
+ if (!_outFileStreamSpec->Create(fullProcessedPath, true))
+ {
+ _message = kCantOpenFile;
+ return E_FAIL;
+ }
+ _outFileStream = outStreamLoc;
+ *outStream = outStreamLoc.Detach();
+ }
+ _diskFilePath = fullProcessedPath;
+ }
+ else
+ {
+ *outStream = NULL;
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CExtractCallbackImp::PrepareOperation(Int32 askExtractMode))
+{
+ _extractMode = (askExtractMode == NArchive::NExtract::NAskMode::kExtract);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CExtractCallbackImp::SetOperationResult(Int32 resultEOperationResult))
+{
+ switch (resultEOperationResult)
+ {
+ case NArchive::NExtract::NOperationResult::kOK:
+ break;
+
+ default:
+ {
+ _outFileStream.Release();
+ switch (resultEOperationResult)
+ {
+ case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
+ _message = kUnsupportedMethod;
+ break;
+ default:
+ _isCorrupt = true;
+ }
+ return E_FAIL;
+ }
+ }
+ if (_outFileStream != NULL)
+ {
+ _outFileStreamSpec->SetMTime(&_processedFileInfo.MTime);
+ RINOK(_outFileStreamSpec->Close())
+ }
+ _outFileStream.Release();
+ if (_extractMode)
+ SetFileAttrib(_diskFilePath, _processedFileInfo.Attributes);
+ return S_OK;
+}
diff --git a/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.h b/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.h
index b7f04e0..b9377ae 100644
--- a/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.h
+++ b/CPP/7zip/Bundles/SFXSetup/ExtractCallbackSfx.h
@@ -1,86 +1,83 @@
-// ExtractCallbackSfx.h
-
-#ifndef __EXTRACT_CALLBACK_SFX_H
-#define __EXTRACT_CALLBACK_SFX_H
-
-#include "resource.h"
-
-#include "../../../Windows/ResourceString.h"
-
-#include "../../Archive/IArchive.h"
-
-#include "../../Common/FileStreams.h"
-#include "../../ICoder.h"
-
-#include "../../UI/FileManager/LangUtils.h"
-
-#ifndef _NO_PROGRESS
-#include "../../UI/FileManager/ProgressDialog.h"
-#endif
-#include "../../UI/Common/ArchiveOpenCallback.h"
-
-class CExtractCallbackImp:
- public IArchiveExtractCallback,
- public IOpenCallbackUI,
- public CMyUnknownImp
-{
-public:
-
- MY_UNKNOWN_IMP
-
- INTERFACE_IArchiveExtractCallback(;)
- INTERFACE_IOpenCallbackUI(;)
-
-private:
- CMyComPtr<IInArchive> _archiveHandler;
- FString _directoryPath;
- UString _filePath;
- FString _diskFilePath;
-
- bool _extractMode;
- struct CProcessedFileInfo
- {
- FILETIME MTime;
- bool IsDir;
- UInt32 Attributes;
- } _processedFileInfo;
-
- COutFileStream *_outFileStreamSpec;
- CMyComPtr<ISequentialOutStream> _outFileStream;
-
- UString _itemDefaultName;
- FILETIME _defaultMTime;
- UInt32 _defaultAttributes;
-
- void CreateComplexDirectory(const UStringVector &dirPathParts);
-public:
- #ifndef _NO_PROGRESS
- CProgressDialog ProgressDialog;
- #endif
-
- bool _isCorrupt;
- UString _message;
-
- void Init(IInArchive *archiveHandler,
- const FString &directoryPath,
- const UString &itemDefaultName,
- const FILETIME &defaultMTime,
- UInt32 defaultAttributes);
-
- #ifndef _NO_PROGRESS
- HRESULT StartProgressDialog(const UString &title, NWindows::CThread &thread)
- {
- ProgressDialog.Create(title, thread, 0);
- {
- ProgressDialog.SetText(LangString(IDS_PROGRESS_EXTRACTING));
- }
-
- ProgressDialog.Show(SW_SHOWNORMAL);
- return S_OK;
- }
- virtual ~CExtractCallbackImp() { ProgressDialog.Destroy(); }
- #endif
-
-};
-
-#endif
+// ExtractCallbackSfx.h
+
+#ifndef ZIP7_INC_EXTRACT_CALLBACK_SFX_H
+#define ZIP7_INC_EXTRACT_CALLBACK_SFX_H
+
+#include "resource.h"
+
+#include "../../../Windows/ResourceString.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../ICoder.h"
+
+#include "../../UI/FileManager/LangUtils.h"
+
+#ifndef _NO_PROGRESS
+#include "../../UI/FileManager/ProgressDialog.h"
+#endif
+#include "../../UI/Common/ArchiveOpenCallback.h"
+
+class CExtractCallbackImp Z7_final:
+ public IArchiveExtractCallback,
+ public IOpenCallbackUI,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_0
+ Z7_IFACE_COM7_IMP(IProgress)
+ Z7_IFACE_COM7_IMP(IArchiveExtractCallback)
+ Z7_IFACE_IMP(IOpenCallbackUI)
+
+ CMyComPtr<IInArchive> _archiveHandler;
+ FString _directoryPath;
+ UString _filePath;
+ FString _diskFilePath;
+
+ bool _extractMode;
+ struct CProcessedFileInfo
+ {
+ FILETIME MTime;
+ bool IsDir;
+ UInt32 Attributes;
+ } _processedFileInfo;
+
+ COutFileStream *_outFileStreamSpec;
+ CMyComPtr<ISequentialOutStream> _outFileStream;
+
+ UString _itemDefaultName;
+ FILETIME _defaultMTime;
+ UInt32 _defaultAttributes;
+
+ void CreateComplexDirectory(const UStringVector &dirPathParts);
+public:
+ #ifndef _NO_PROGRESS
+ CProgressDialog ProgressDialog;
+ #endif
+
+ bool _isCorrupt;
+ UString _message;
+
+ void Init(IInArchive *archiveHandler,
+ const FString &directoryPath,
+ const UString &itemDefaultName,
+ const FILETIME &defaultMTime,
+ UInt32 defaultAttributes);
+
+ #ifndef _NO_PROGRESS
+ HRESULT StartProgressDialog(const UString &title, NWindows::CThread &thread)
+ {
+ ProgressDialog.Create(title, thread, NULL);
+ {
+ ProgressDialog.SetText(LangString(IDS_PROGRESS_EXTRACTING));
+ }
+
+ ProgressDialog.Show(SW_SHOWNORMAL);
+ return S_OK;
+ }
+ ~CExtractCallbackImp() { ProgressDialog.Destroy(); }
+ #endif
+
+};
+
+#endif
diff --git a/CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp b/CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp
index 194e376..73ccff1 100644
--- a/CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp
+++ b/CPP/7zip/Bundles/SFXSetup/ExtractEngine.cpp
@@ -1,137 +1,135 @@
-// ExtractEngine.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Windows/FileDir.h"
-#include "../../../Windows/FileName.h"
-#include "../../../Windows/Thread.h"
-
-#include "../../UI/Common/OpenArchive.h"
-
-#include "../../UI/FileManager/FormatUtils.h"
-#include "../../UI/FileManager/LangUtils.h"
-
-#include "ExtractCallbackSfx.h"
-#include "ExtractEngine.h"
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NDir;
-
-static LPCSTR const kCantFindArchive = "Can not find archive file";
-static LPCSTR const kCantOpenArchive = "Can not open the file as archive";
-
-struct CThreadExtracting
-{
- CCodecs *Codecs;
- FString FileName;
- FString DestFolder;
-
- CExtractCallbackImp *ExtractCallbackSpec;
- CMyComPtr<IArchiveExtractCallback> ExtractCallback;
-
- CArchiveLink ArchiveLink;
- HRESULT Result;
- UString ErrorMessage;
-
- void Process2()
- {
- NFind::CFileInfo fi;
- if (!fi.Find(FileName))
- {
- ErrorMessage = kCantFindArchive;
- Result = E_FAIL;
- return;
- }
-
- CObjectVector<COpenType> incl;
- CIntVector excl;
- COpenOptions options;
- options.codecs = Codecs;
- options.types = &incl;
- options.excludedFormats = &excl;
- options.filePath = fs2us(FileName);
-
- Result = ArchiveLink.Open2(options, ExtractCallbackSpec);
- if (Result != S_OK)
- {
- ErrorMessage = kCantOpenArchive;
- return;
- }
-
- FString dirPath = DestFolder;
- NName::NormalizeDirPathPrefix(dirPath);
-
- if (!CreateComplexDir(dirPath))
- {
- ErrorMessage = MyFormatNew(IDS_CANNOT_CREATE_FOLDER,
- #ifdef LANG
- 0x02000603,
- #endif
- fs2us(dirPath));
- Result = E_FAIL;
- return;
- }
-
- ExtractCallbackSpec->Init(ArchiveLink.GetArchive(), dirPath, (UString)"Default", fi.MTime, 0);
-
- Result = ArchiveLink.GetArchive()->Extract(0, (UInt32)(Int32)-1 , BoolToInt(false), ExtractCallback);
- }
-
- void Process()
- {
- try
- {
- #ifndef _NO_PROGRESS
- CProgressCloser closer(ExtractCallbackSpec->ProgressDialog);
- #endif
- Process2();
- }
- catch(...) { Result = E_FAIL; }
- }
-
- static THREAD_FUNC_DECL MyThreadFunction(void *param)
- {
- ((CThreadExtracting *)param)->Process();
- return 0;
- }
-};
-
-HRESULT ExtractArchive(CCodecs *codecs, const FString &fileName, const FString &destFolder,
- bool showProgress, bool &isCorrupt, UString &errorMessage)
-{
- isCorrupt = false;
- CThreadExtracting t;
-
- t.Codecs = codecs;
- t.FileName = fileName;
- t.DestFolder = destFolder;
-
- t.ExtractCallbackSpec = new CExtractCallbackImp;
- t.ExtractCallback = t.ExtractCallbackSpec;
-
- #ifndef _NO_PROGRESS
-
- if (showProgress)
- {
- t.ExtractCallbackSpec->ProgressDialog.IconID = IDI_ICON;
- NWindows::CThread thread;
- RINOK(thread.Create(CThreadExtracting::MyThreadFunction, &t));
-
- UString title;
- LangString(IDS_PROGRESS_EXTRACTING, title);
- t.ExtractCallbackSpec->StartProgressDialog(title, thread);
- }
- else
-
- #endif
- {
- t.Process2();
- }
-
- errorMessage = t.ErrorMessage;
- if (errorMessage.IsEmpty())
- errorMessage = t.ExtractCallbackSpec->_message;
- isCorrupt = t.ExtractCallbackSpec->_isCorrupt;
- return t.Result;
-}
+// ExtractEngine.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/Thread.h"
+
+#include "../../UI/Common/OpenArchive.h"
+
+#include "../../UI/FileManager/FormatUtils.h"
+#include "../../UI/FileManager/LangUtils.h"
+
+#include "ExtractCallbackSfx.h"
+#include "ExtractEngine.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+static LPCSTR const kCantFindArchive = "Cannot find archive file";
+static LPCSTR const kCantOpenArchive = "Cannot open the file as archive";
+
+struct CThreadExtracting
+{
+ CCodecs *Codecs;
+ FString FileName;
+ FString DestFolder;
+
+ CExtractCallbackImp *ExtractCallbackSpec;
+ CMyComPtr<IArchiveExtractCallback> ExtractCallback;
+
+ CArchiveLink ArchiveLink;
+ HRESULT Result;
+ UString ErrorMessage;
+
+ void Process2()
+ {
+ NFind::CFileInfo fi;
+ if (!fi.Find(FileName))
+ {
+ ErrorMessage = kCantFindArchive;
+ Result = E_FAIL;
+ return;
+ }
+
+ CObjectVector<COpenType> incl;
+ CIntVector excl;
+ COpenOptions options;
+ options.codecs = Codecs;
+ options.types = &incl;
+ options.excludedFormats = &excl;
+ options.filePath = fs2us(FileName);
+
+ Result = ArchiveLink.Open2(options, ExtractCallbackSpec);
+ if (Result != S_OK)
+ {
+ ErrorMessage = kCantOpenArchive;
+ return;
+ }
+
+ FString dirPath = DestFolder;
+ NName::NormalizeDirPathPrefix(dirPath);
+
+ if (!CreateComplexDir(dirPath))
+ {
+ ErrorMessage = MyFormatNew(IDS_CANNOT_CREATE_FOLDER, fs2us(dirPath));
+ Result = E_FAIL;
+ return;
+ }
+
+ ExtractCallbackSpec->Init(ArchiveLink.GetArchive(), dirPath, (UString)"Default", fi.MTime, 0);
+
+ Result = ArchiveLink.GetArchive()->Extract(NULL, (UInt32)(Int32)-1 , BoolToInt(false), ExtractCallback);
+ }
+
+ void Process()
+ {
+ try
+ {
+ #ifndef _NO_PROGRESS
+ CProgressCloser closer(ExtractCallbackSpec->ProgressDialog);
+ #endif
+ Process2();
+ }
+ catch(...) { Result = E_FAIL; }
+ }
+
+ static THREAD_FUNC_DECL MyThreadFunction(void *param)
+ {
+ ((CThreadExtracting *)param)->Process();
+ return 0;
+ }
+};
+
+HRESULT ExtractArchive(CCodecs *codecs, const FString &fileName, const FString &destFolder,
+ bool showProgress, bool &isCorrupt, UString &errorMessage)
+{
+ isCorrupt = false;
+ CThreadExtracting t;
+
+ t.Codecs = codecs;
+ t.FileName = fileName;
+ t.DestFolder = destFolder;
+
+ t.ExtractCallbackSpec = new CExtractCallbackImp;
+ t.ExtractCallback = t.ExtractCallbackSpec;
+
+ #ifndef _NO_PROGRESS
+
+ if (showProgress)
+ {
+ t.ExtractCallbackSpec->ProgressDialog.IconID = IDI_ICON;
+ NWindows::CThread thread;
+ const WRes wres = thread.Create(CThreadExtracting::MyThreadFunction, &t);
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+
+ UString title;
+ LangString(IDS_PROGRESS_EXTRACTING, title);
+ t.ExtractCallbackSpec->StartProgressDialog(title, thread);
+ }
+ else
+
+ #endif
+ {
+ t.Process2();
+ }
+
+ errorMessage = t.ErrorMessage;
+ if (errorMessage.IsEmpty())
+ errorMessage = t.ExtractCallbackSpec->_message;
+ isCorrupt = t.ExtractCallbackSpec->_isCorrupt;
+ return t.Result;
+}
diff --git a/CPP/7zip/Bundles/SFXSetup/ExtractEngine.h b/CPP/7zip/Bundles/SFXSetup/ExtractEngine.h
index 8aa9724..b7f7965 100644
--- a/CPP/7zip/Bundles/SFXSetup/ExtractEngine.h
+++ b/CPP/7zip/Bundles/SFXSetup/ExtractEngine.h
@@ -1,11 +1,11 @@
-// ExtractEngine.h
-
-#ifndef __EXTRACT_ENGINE_H
-#define __EXTRACT_ENGINE_H
-
-#include "../../UI/Common/LoadCodecs.h"
-
-HRESULT ExtractArchive(CCodecs *codecs, const FString &fileName, const FString &destFolder,
- bool showProgress, bool &isCorrupt, UString &errorMessage);
-
-#endif
+// ExtractEngine.h
+
+#ifndef ZIP7_INC_EXTRACT_ENGINE_H
+#define ZIP7_INC_EXTRACT_ENGINE_H
+
+#include "../../UI/Common/LoadCodecs.h"
+
+HRESULT ExtractArchive(CCodecs *codecs, const FString &fileName, const FString &destFolder,
+ bool showProgress, bool &isCorrupt, UString &errorMessage);
+
+#endif
diff --git a/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp b/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp
index b1d740e..cf96460 100644
--- a/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp
+++ b/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsp
@@ -1,803 +1,864 @@
-# Microsoft Developer Studio Project File - Name="SFXSetup" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Application" 0x0101
-
-CFG=SFXSetup - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "SFXSetup.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "SFXSetup.mak" CFG="SFXSetup - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "SFXSetup - Win32 Release" (based on "Win32 (x86) Application")
-!MESSAGE "SFXSetup - Win32 Debug" (based on "Win32 (x86) Application")
-!MESSAGE "SFXSetup - Win32 ReleaseD" (based on "Win32 (x86) Application")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "SFXSetup - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /Gz /MT /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "EXTRACT_ONLY" /D "NO_REGISTRY" /D "_SFX" /D "_NO_CRYPTO" /Yu"StdAfx.h" /FD /c
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x419 /d "NDEBUG"
-# ADD RSC /l 0x419 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
-# ADD LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zS.sfx" /opt:NOWIN98
-# SUBTRACT LINK32 /pdb:none
-
-!ELSEIF "$(CFG)" == "SFXSetup - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
-# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "EXTRACT_ONLY" /D "NO_REGISTRY" /D "_SFX" /D "_NO_CRYPTO" /Yu"StdAfx.h" /FD /GZ /c
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x419 /d "_DEBUG"
-# ADD RSC /l 0x419 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\UTIL\7zSfxS.exe" /pdbtype:sept
-
-!ELSEIF "$(CFG)" == "SFXSetup - Win32 ReleaseD"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "ReleaseD"
-# PROP BASE Intermediate_Dir "ReleaseD"
-# PROP BASE Ignore_Export_Lib 0
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "ReleaseD"
-# PROP Intermediate_Dir "ReleaseD"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /MD /W3 /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "EXTRACT_ONLY" /D "EXCLUDE_COM" /D "NO_REGISTRY" /D "_SFX" /Yu"StdAfx.h" /FD /c
-# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "EXTRACT_ONLY" /D "NO_REGISTRY" /D "_SFX" /D "_NO_CRYPTO" /Yu"StdAfx.h" /FD /c
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x419 /d "NDEBUG"
-# ADD RSC /l 0x419 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\UTIL\7zWinSR.exe"
-# SUBTRACT BASE LINK32 /debug /nodefaultlib
-# ADD LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zSD.sfx" /opt:NOWIN98
-# SUBTRACT LINK32 /pdb:none
-
-!ENDIF
-
-# Begin Target
-
-# Name "SFXSetup - Win32 Release"
-# Name "SFXSetup - Win32 Debug"
-# Name "SFXSetup - Win32 ReleaseD"
-# Begin Group "Spec"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=.\resource.rc
-# End Source File
-# Begin Source File
-
-SOURCE=.\StdAfx.cpp
-# ADD CPP /Yc"StdAfx.h"
-# End Source File
-# Begin Source File
-
-SOURCE=.\StdAfx.h
-# End Source File
-# End Group
-# Begin Group "Interface"
-
-# PROP Default_Filter ""
-# End Group
-# Begin Group "7z"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zDecode.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zDecode.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zExtract.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zHandler.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zHandler.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zHeader.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zIn.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zIn.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zItem.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zRegister.cpp
-# End Source File
-# End Group
-# Begin Group "Archive Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\CoderMixer2.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\CoderMixer2.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\ItemNameUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\ItemNameUtils.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\OutStreamWithCRC.h
-# End Source File
-# End Group
-# Begin Group "Compress"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Compress\Bcj2Coder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\Bcj2Register.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BcjCoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BcjRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BranchMisc.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BranchMisc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BranchRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\CopyCoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\CopyRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\DeltaFilter.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\Lzma2Decoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\Lzma2Decoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\Lzma2Register.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\LzmaDecoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\LzmaRegister.cpp
-# End Source File
-# End Group
-# Begin Group "Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\Common\CommandLineParser.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\CommandLineParser.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\CRC.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\CRC.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\IntToString.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\IntToString.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyString.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyString.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyVector.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyVector.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\NewHandler.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\NewHandler.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StringConvert.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StringConvert.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\TextConfig.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\TextConfig.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\UTFConvert.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\UTFConvert.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\Wildcard.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\Wildcard.h
-# End Source File
-# End Group
-# Begin Group "Windows"
-
-# PROP Default_Filter ""
-# Begin Group "Control"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Control\Dialog.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Control\Dialog.h
-# End Source File
-# End Group
-# Begin Source File
-
-SOURCE=..\..\..\Windows\DLL.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\DLL.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\ErrorMsg.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\ErrorMsg.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileDir.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileDir.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileFind.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileFind.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileIO.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileIO.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileName.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileName.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariant.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariant.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\ResourceString.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\ResourceString.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Synchronization.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Synchronization.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\System.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\System.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Window.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Window.h
-# End Source File
-# End Group
-# Begin Group "7z Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Common\CreateCoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\CreateCoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\CWrappers.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\CWrappers.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FileStreams.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FileStreams.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FilterCoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FilterCoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\InBuffer.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\InBuffer.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\LimitedStreams.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\LimitedStreams.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\OutBuffer.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\OutBuffer.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\ProgressUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\ProgressUtils.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\PropId.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamBinder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamBinder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamObjects.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamObjects.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamUtils.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\VirtThread.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\VirtThread.h
-# End Source File
-# End Group
-# Begin Group "UI"
-
-# PROP Default_Filter ""
-# Begin Group "Explorer"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\UI\Explorer\MyMessages.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Explorer\MyMessages.h
-# End Source File
-# End Group
-# Begin Group "UI Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ArchiveOpenCallback.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\DefaultName.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\DefaultName.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ExtractMode.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\LoadCodecs.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\LoadCodecs.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\OpenArchive.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\OpenArchive.h
-# End Source File
-# End Group
-# End Group
-# Begin Group "File Manager"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\FormatUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\FormatUtils.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\LangUtils.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\ProgressDialog.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\ProgressDialog.h
-# End Source File
-# End Group
-# Begin Group "C"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\..\C\7zCrc.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\7zCrc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\7zCrcOpt.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Alloc.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Alloc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bcj2.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bcj2.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bra.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bra.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bra86.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\BraIA64.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\CpuArch.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\CpuArch.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Delta.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Delta.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\DllSecur.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\DllSecur.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma2Dec.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma2Dec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma2DecMt.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma2DecMt.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzmaDec.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzmaDec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\MtDec.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\MtDec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Threads.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Threads.h
-# End Source File
-# End Group
-# Begin Source File
-
-SOURCE=.\ExtractCallbackSfx.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\ExtractCallbackSfx.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\ExtractEngine.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=.\ExtractEngine.h
-# End Source File
-# Begin Source File
-
-SOURCE=.\setup.ico
-# End Source File
-# Begin Source File
-
-SOURCE=.\SfxSetup.cpp
-# End Source File
-# End Target
-# End Project
+# Microsoft Developer Studio Project File - Name="SFXSetup" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=SFXSetup - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "SFXSetup.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "SFXSetup.mak" CFG="SFXSetup - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "SFXSetup - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "SFXSetup - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE "SFXSetup - Win32 ReleaseD" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "SFXSetup - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /Gz /MT /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_SFX" /D "Z7_NO_CRYPTO" /Yu"StdAfx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zS.sfx" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "SFXSetup - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_SFX" /D "Z7_NO_CRYPTO" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\UTIL\7zSfxS.exe" /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "SFXSetup - Win32 ReleaseD"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ReleaseD"
+# PROP BASE Intermediate_Dir "ReleaseD"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "ReleaseD"
+# PROP Intermediate_Dir "ReleaseD"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_SFX" /Yu"StdAfx.h" /FD /c
+# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_SFX" /D "Z7_NO_CRYPTO" /Yu"StdAfx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\UTIL\7zWinSR.exe"
+# SUBTRACT BASE LINK32 /debug /nodefaultlib
+# ADD LINK32 comctl32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zSD.sfx" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "SFXSetup - Win32 Release"
+# Name "SFXSetup - Win32 Debug"
+# Name "SFXSetup - Win32 ReleaseD"
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"StdAfx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "Interface"
+
+# PROP Default_Filter ""
+# End Group
+# Begin Group "7z"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zDecode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zExtract.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zRegister.cpp
+# End Source File
+# End Group
+# Begin Group "Archive Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.h
+# End Source File
+# End Group
+# Begin Group "Compress"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\Bcj2Coder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Bcj2Coder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Bcj2Register.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BcjCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BcjCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BcjRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchMisc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchMisc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\DeltaFilter.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Decoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Decoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Register.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaRegister.cpp
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Common.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyCom.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\TextConfig.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\TextConfig.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.h
+# End Source File
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Group "Control"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Dialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Dialog.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ResourceString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ResourceString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Window.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Window.h
+# End Source File
+# End Group
+# Begin Group "7zip Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CWrappers.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CWrappers.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\PropId.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamBinder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamBinder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\VirtThread.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\VirtThread.h
+# End Source File
+# End Group
+# Begin Group "UI"
+
+# PROP Default_Filter ""
+# Begin Group "Explorer"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\Explorer\MyMessages.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Explorer\MyMessages.h
+# End Source File
+# End Group
+# Begin Group "UI Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveOpenCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\DefaultName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\DefaultName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExtractMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\LoadCodecs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\LoadCodecs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\OpenArchive.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\OpenArchive.h
+# End Source File
+# End Group
+# End Group
+# Begin Group "File Manager"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FormatUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FormatUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\LangUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ProgressDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ProgressDialog.h
+# End Source File
+# End Group
+# Begin Group "C"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrcOpt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zStream.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bcj2.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bcj2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra86.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\BraIA64.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Delta.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Delta.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\DllSecur.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\DllSecur.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Dec.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Dec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2DecMt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2DecMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaDec.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaDec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtDec.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtDec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.h
+# End Source File
+# End Group
+# Begin Group "7zip"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\IArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ICoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IDecl.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IPassword.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IProgress.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\ExtractCallbackSfx.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ExtractCallbackSfx.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ExtractEngine.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ExtractEngine.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\setup.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\SfxSetup.cpp
+# End Source File
+# End Target
+# End Project
diff --git a/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsw b/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsw
index 2970370..f563b21 100644
--- a/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsw
+++ b/CPP/7zip/Bundles/SFXSetup/SFXSetup.dsw
@@ -1,29 +1,29 @@
-Microsoft Developer Studio Workspace File, Format Version 6.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "SFXSetup"=.\SFXSetup.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
-
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "SFXSetup"=.\SFXSetup.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp b/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
index 1705a8d..47d7966 100644
--- a/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
+++ b/CPP/7zip/Bundles/SFXSetup/SfxSetup.cpp
@@ -1,364 +1,368 @@
-// Main.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/MyWindows.h"
-
-#include "../../../Common/MyInitGuid.h"
-
-#include "../../../Common/CommandLineParser.h"
-#include "../../../Common/StringConvert.h"
-#include "../../../Common/TextConfig.h"
-
-#include "../../../Windows/DLL.h"
-#include "../../../Windows/ErrorMsg.h"
-#include "../../../Windows/FileDir.h"
-#include "../../../Windows/FileFind.h"
-#include "../../../Windows/FileIO.h"
-#include "../../../Windows/FileName.h"
-#include "../../../Windows/NtCheck.h"
-#include "../../../Windows/ResourceString.h"
-
-#include "../../UI/Explorer/MyMessages.h"
-
-#include "ExtractEngine.h"
-
-#include "../../../../C/DllSecur.h"
-
-#include "resource.h"
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NDir;
-
-HINSTANCE g_hInstance;
-
-static CFSTR const kTempDirPrefix = FTEXT("7zS");
-
-#define _SHELL_EXECUTE
-
-static bool ReadDataString(CFSTR fileName, LPCSTR startID,
- LPCSTR endID, AString &stringResult)
-{
- stringResult.Empty();
- NIO::CInFile inFile;
- if (!inFile.Open(fileName))
- return false;
- const int kBufferSize = (1 << 12);
-
- Byte buffer[kBufferSize];
- int signatureStartSize = MyStringLen(startID);
- int signatureEndSize = MyStringLen(endID);
-
- UInt32 numBytesPrev = 0;
- bool writeMode = false;
- UInt64 posTotal = 0;
- for (;;)
- {
- if (posTotal > (1 << 20))
- return (stringResult.IsEmpty());
- UInt32 numReadBytes = kBufferSize - numBytesPrev;
- UInt32 processedSize;
- if (!inFile.Read(buffer + numBytesPrev, numReadBytes, processedSize))
- return false;
- if (processedSize == 0)
- return true;
- UInt32 numBytesInBuffer = numBytesPrev + processedSize;
- UInt32 pos = 0;
- for (;;)
- {
- if (writeMode)
- {
- if (pos > numBytesInBuffer - signatureEndSize)
- break;
- if (memcmp(buffer + pos, endID, signatureEndSize) == 0)
- return true;
- char b = buffer[pos];
- if (b == 0)
- return false;
- stringResult += b;
- pos++;
- }
- else
- {
- if (pos > numBytesInBuffer - signatureStartSize)
- break;
- if (memcmp(buffer + pos, startID, signatureStartSize) == 0)
- {
- writeMode = true;
- pos += signatureStartSize;
- }
- else
- pos++;
- }
- }
- numBytesPrev = numBytesInBuffer - pos;
- posTotal += pos;
- memmove(buffer, buffer + pos, numBytesPrev);
- }
-}
-
-static char kStartID[] = { ',','!','@','I','n','s','t','a','l','l','@','!','U','T','F','-','8','!', 0 };
-static char kEndID[] = { ',','!','@','I','n','s','t','a','l','l','E','n','d','@','!', 0 };
-
-struct CInstallIDInit
-{
- CInstallIDInit()
- {
- kStartID[0] = ';';
- kEndID[0] = ';';
- };
-} g_CInstallIDInit;
-
-
-#define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return 1;
-
-static void ShowErrorMessageSpec(const UString &name)
-{
- UString message = NError::MyFormatMessage(::GetLastError());
- int pos = message.Find(L"%1");
- if (pos >= 0)
- {
- message.Delete(pos, 2);
- message.Insert(pos, name);
- }
- ShowErrorMessage(NULL, message);
-}
-
-int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */,
- #ifdef UNDER_CE
- LPWSTR
- #else
- LPSTR
- #endif
- /* lpCmdLine */,int /* nCmdShow */)
-{
- g_hInstance = (HINSTANCE)hInstance;
-
- NT_CHECK
-
- #ifdef _WIN32
- LoadSecurityDlls();
- #endif
-
- // InitCommonControls();
-
- UString archiveName, switches;
- #ifdef _SHELL_EXECUTE
- UString executeFile, executeParameters;
- #endif
- NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches);
-
- FString fullPath;
- NDLL::MyGetModuleFileName(fullPath);
-
- switches.Trim();
- bool assumeYes = false;
- if (switches.IsPrefixedBy_Ascii_NoCase("-y"))
- {
- assumeYes = true;
- switches = switches.Ptr(2);
- switches.Trim();
- }
-
- AString config;
- if (!ReadDataString(fullPath, kStartID, kEndID, config))
- {
- if (!assumeYes)
- ShowErrorMessage(L"Can't load config info");
- return 1;
- }
-
- UString dirPrefix ("." STRING_PATH_SEPARATOR);
- UString appLaunched;
- bool showProgress = true;
- if (!config.IsEmpty())
- {
- CObjectVector<CTextConfigPair> pairs;
- if (!GetTextConfig(config, pairs))
- {
- if (!assumeYes)
- ShowErrorMessage(L"Config failed");
- return 1;
- }
- UString friendlyName = GetTextConfigValue(pairs, "Title");
- UString installPrompt = GetTextConfigValue(pairs, "BeginPrompt");
- UString progress = GetTextConfigValue(pairs, "Progress");
- if (progress.IsEqualTo_Ascii_NoCase("no"))
- showProgress = false;
- int index = FindTextConfigItem(pairs, "Directory");
- if (index >= 0)
- dirPrefix = pairs[index].String;
- if (!installPrompt.IsEmpty() && !assumeYes)
- {
- if (MessageBoxW(0, installPrompt, friendlyName, MB_YESNO |
- MB_ICONQUESTION) != IDYES)
- return 0;
- }
- appLaunched = GetTextConfigValue(pairs, "RunProgram");
-
- #ifdef _SHELL_EXECUTE
- executeFile = GetTextConfigValue(pairs, "ExecuteFile");
- executeParameters = GetTextConfigValue(pairs, "ExecuteParameters");
- #endif
- }
-
- CTempDir tempDir;
- if (!tempDir.Create(kTempDirPrefix))
- {
- if (!assumeYes)
- ShowErrorMessage(L"Can not create temp folder archive");
- return 1;
- }
-
- CCodecs *codecs = new CCodecs;
- CMyComPtr<IUnknown> compressCodecsInfo = codecs;
- {
- HRESULT result = codecs->Load();
- if (result != S_OK)
- {
- ShowErrorMessage(L"Can not load codecs");
- return 1;
- }
- }
-
- const FString tempDirPath = tempDir.GetPath();
- // tempDirPath = L"M:\\1\\"; // to test low disk space
- {
- bool isCorrupt = false;
- UString errorMessage;
- HRESULT result = ExtractArchive(codecs, fullPath, tempDirPath, showProgress,
- isCorrupt, errorMessage);
-
- if (result != S_OK)
- {
- if (!assumeYes)
- {
- if (result == S_FALSE || isCorrupt)
- {
- NWindows::MyLoadString(IDS_EXTRACTION_ERROR_MESSAGE, errorMessage);
- result = E_FAIL;
- }
- if (result != E_ABORT)
- {
- if (errorMessage.IsEmpty())
- errorMessage = NError::MyFormatMessage(result);
- ::MessageBoxW(0, errorMessage, NWindows::MyLoadString(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR);
- }
- }
- return 1;
- }
- }
-
- #ifndef UNDER_CE
- CCurrentDirRestorer currentDirRestorer;
- if (!SetCurrentDir(tempDirPath))
- return 1;
- #endif
-
- HANDLE hProcess = 0;
-#ifdef _SHELL_EXECUTE
- if (!executeFile.IsEmpty())
- {
- CSysString filePath (GetSystemString(executeFile));
- SHELLEXECUTEINFO execInfo;
- execInfo.cbSize = sizeof(execInfo);
- execInfo.fMask = SEE_MASK_NOCLOSEPROCESS
- #ifndef UNDER_CE
- | SEE_MASK_FLAG_DDEWAIT
- #endif
- ;
- execInfo.hwnd = NULL;
- execInfo.lpVerb = NULL;
- execInfo.lpFile = filePath;
-
- if (!switches.IsEmpty())
- {
- executeParameters.Add_Space_if_NotEmpty();
- executeParameters += switches;
- }
-
- CSysString parametersSys (GetSystemString(executeParameters));
- if (parametersSys.IsEmpty())
- execInfo.lpParameters = NULL;
- else
- execInfo.lpParameters = parametersSys;
-
- execInfo.lpDirectory = NULL;
- execInfo.nShow = SW_SHOWNORMAL;
- execInfo.hProcess = 0;
- /* BOOL success = */ ::ShellExecuteEx(&execInfo);
- UINT32 result = (UINT32)(UINT_PTR)execInfo.hInstApp;
- if (result <= 32)
- {
- if (!assumeYes)
- ShowErrorMessage(L"Can not open file");
- return 1;
- }
- hProcess = execInfo.hProcess;
- }
- else
-#endif
- {
- if (appLaunched.IsEmpty())
- {
- appLaunched = L"setup.exe";
- if (!NFind::DoesFileExist(us2fs(appLaunched)))
- {
- if (!assumeYes)
- ShowErrorMessage(L"Can not find setup.exe");
- return 1;
- }
- }
-
- {
- FString s2 = tempDirPath;
- NName::NormalizeDirPathPrefix(s2);
- appLaunched.Replace(L"%%T" WSTRING_PATH_SEPARATOR, fs2us(s2));
- }
-
- UString appNameForError = appLaunched; // actually we need to rtemove parameters also
-
- appLaunched.Replace(L"%%T", fs2us(tempDirPath));
-
- if (!switches.IsEmpty())
- {
- appLaunched.Add_Space();
- appLaunched += switches;
- }
- STARTUPINFO startupInfo;
- startupInfo.cb = sizeof(startupInfo);
- startupInfo.lpReserved = 0;
- startupInfo.lpDesktop = 0;
- startupInfo.lpTitle = 0;
- startupInfo.dwFlags = 0;
- startupInfo.cbReserved2 = 0;
- startupInfo.lpReserved2 = 0;
-
- PROCESS_INFORMATION processInformation;
-
- CSysString appLaunchedSys (GetSystemString(dirPrefix + appLaunched));
-
- BOOL createResult = CreateProcess(NULL, (LPTSTR)(LPCTSTR)appLaunchedSys,
- NULL, NULL, FALSE, 0, NULL, NULL /*tempDir.GetPath() */,
- &startupInfo, &processInformation);
- if (createResult == 0)
- {
- if (!assumeYes)
- {
- // we print name of exe file, if error message is
- // ERROR_BAD_EXE_FORMAT: "%1 is not a valid Win32 application".
- ShowErrorMessageSpec(appNameForError);
- }
- return 1;
- }
- ::CloseHandle(processInformation.hThread);
- hProcess = processInformation.hProcess;
- }
- if (hProcess != 0)
- {
- WaitForSingleObject(hProcess, INFINITE);
- ::CloseHandle(hProcess);
- }
- return 0;
-}
+// Main.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/DllSecur.h"
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/MyInitGuid.h"
+
+#include "../../../Common/CommandLineParser.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/TextConfig.h"
+
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/FileIO.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/NtCheck.h"
+#include "../../../Windows/ResourceString.h"
+
+#include "../../UI/Explorer/MyMessages.h"
+
+#include "ExtractEngine.h"
+
+#include "resource.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+extern
+HINSTANCE g_hInstance;
+HINSTANCE g_hInstance;
+
+static CFSTR const kTempDirPrefix = FTEXT("7zS");
+
+#define MY_SHELL_EXECUTE
+
+static bool ReadDataString(CFSTR fileName, LPCSTR startID,
+ LPCSTR endID, AString &stringResult)
+{
+ stringResult.Empty();
+ NIO::CInFile inFile;
+ if (!inFile.Open(fileName))
+ return false;
+ const size_t kBufferSize = (1 << 12);
+
+ Byte buffer[kBufferSize];
+ const unsigned signatureStartSize = MyStringLen(startID);
+ const unsigned signatureEndSize = MyStringLen(endID);
+
+ size_t numBytesPrev = 0;
+ bool writeMode = false;
+ UInt64 posTotal = 0;
+ for (;;)
+ {
+ if (posTotal > (1 << 20))
+ return (stringResult.IsEmpty());
+ const size_t numReadBytes = kBufferSize - numBytesPrev;
+ size_t processedSize;
+ if (!inFile.ReadFull(buffer + numBytesPrev, numReadBytes, processedSize))
+ return false;
+ if (processedSize == 0)
+ return true;
+ const size_t numBytesInBuffer = numBytesPrev + processedSize;
+ UInt32 pos = 0;
+ for (;;)
+ {
+ if (writeMode)
+ {
+ if (pos + signatureEndSize > numBytesInBuffer)
+ break;
+ if (memcmp(buffer + pos, endID, signatureEndSize) == 0)
+ return true;
+ const Byte b = buffer[pos];
+ if (b == 0)
+ return false;
+ stringResult += (char)b;
+ pos++;
+ }
+ else
+ {
+ if (pos + signatureStartSize > numBytesInBuffer)
+ break;
+ if (memcmp(buffer + pos, startID, signatureStartSize) == 0)
+ {
+ writeMode = true;
+ pos += signatureStartSize;
+ }
+ else
+ pos++;
+ }
+ }
+ numBytesPrev = numBytesInBuffer - pos;
+ posTotal += pos;
+ memmove(buffer, buffer + pos, numBytesPrev);
+ }
+}
+
+static char kStartID[] = { ',','!','@','I','n','s','t','a','l','l','@','!','U','T','F','-','8','!', 0 };
+static char kEndID[] = { ',','!','@','I','n','s','t','a','l','l','E','n','d','@','!', 0 };
+
+static struct CInstallIDInit
+{
+ CInstallIDInit()
+ {
+ kStartID[0] = ';';
+ kEndID[0] = ';';
+ }
+} g_CInstallIDInit;
+
+
+#if defined(_WIN32) && defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE)
+#define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return 1;
+#endif
+
+static void ShowErrorMessageSpec(const UString &name)
+{
+ UString message = NError::MyFormatMessage(::GetLastError());
+ const int pos = message.Find(L"%1");
+ if (pos >= 0)
+ {
+ message.Delete((unsigned)pos, 2);
+ message.Insert((unsigned)pos, name);
+ }
+ ShowErrorMessage(NULL, message);
+}
+
+int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */,
+ #ifdef UNDER_CE
+ LPWSTR
+ #else
+ LPSTR
+ #endif
+ /* lpCmdLine */,int /* nCmdShow */)
+{
+ g_hInstance = (HINSTANCE)hInstance;
+
+ NT_CHECK
+
+ #ifdef _WIN32
+ LoadSecurityDlls();
+ #endif
+
+ // InitCommonControls();
+
+ UString archiveName, switches;
+ #ifdef MY_SHELL_EXECUTE
+ UString executeFile, executeParameters;
+ #endif
+ NCommandLineParser::SplitCommandLine(GetCommandLineW(), archiveName, switches);
+
+ FString fullPath;
+ NDLL::MyGetModuleFileName(fullPath);
+
+ switches.Trim();
+ bool assumeYes = false;
+ if (switches.IsPrefixedBy_Ascii_NoCase("-y"))
+ {
+ assumeYes = true;
+ switches = switches.Ptr(2);
+ switches.Trim();
+ }
+
+ AString config;
+ if (!ReadDataString(fullPath, kStartID, kEndID, config))
+ {
+ if (!assumeYes)
+ ShowErrorMessage(L"Can't load config info");
+ return 1;
+ }
+
+ UString dirPrefix ("." STRING_PATH_SEPARATOR);
+ UString appLaunched;
+ bool showProgress = true;
+ if (!config.IsEmpty())
+ {
+ CObjectVector<CTextConfigPair> pairs;
+ if (!GetTextConfig(config, pairs))
+ {
+ if (!assumeYes)
+ ShowErrorMessage(L"Config failed");
+ return 1;
+ }
+ const UString friendlyName = GetTextConfigValue(pairs, "Title");
+ const UString installPrompt = GetTextConfigValue(pairs, "BeginPrompt");
+ const UString progress = GetTextConfigValue(pairs, "Progress");
+ if (progress.IsEqualTo_Ascii_NoCase("no"))
+ showProgress = false;
+ const int index = FindTextConfigItem(pairs, "Directory");
+ if (index >= 0)
+ dirPrefix = pairs[index].String;
+ if (!installPrompt.IsEmpty() && !assumeYes)
+ {
+ if (MessageBoxW(NULL, installPrompt, friendlyName, MB_YESNO |
+ MB_ICONQUESTION) != IDYES)
+ return 0;
+ }
+ appLaunched = GetTextConfigValue(pairs, "RunProgram");
+
+ #ifdef MY_SHELL_EXECUTE
+ executeFile = GetTextConfigValue(pairs, "ExecuteFile");
+ executeParameters = GetTextConfigValue(pairs, "ExecuteParameters");
+ #endif
+ }
+
+ CTempDir tempDir;
+ if (!tempDir.Create(kTempDirPrefix))
+ {
+ if (!assumeYes)
+ ShowErrorMessage(L"Cannot create temp folder archive");
+ return 1;
+ }
+
+ CCodecs *codecs = new CCodecs;
+ CMyComPtr<IUnknown> compressCodecsInfo = codecs;
+ {
+ const HRESULT result = codecs->Load();
+ if (result != S_OK)
+ {
+ ShowErrorMessage(L"Cannot load codecs");
+ return 1;
+ }
+ }
+
+ const FString tempDirPath = tempDir.GetPath();
+ // tempDirPath = L"M:\\1\\"; // to test low disk space
+ {
+ bool isCorrupt = false;
+ UString errorMessage;
+ HRESULT result = ExtractArchive(codecs, fullPath, tempDirPath, showProgress,
+ isCorrupt, errorMessage);
+
+ if (result != S_OK)
+ {
+ if (!assumeYes)
+ {
+ if (result == S_FALSE || isCorrupt)
+ {
+ NWindows::MyLoadString(IDS_EXTRACTION_ERROR_MESSAGE, errorMessage);
+ result = E_FAIL;
+ }
+ if (result != E_ABORT)
+ {
+ if (errorMessage.IsEmpty())
+ errorMessage = NError::MyFormatMessage(result);
+ ::MessageBoxW(NULL, errorMessage, NWindows::MyLoadString(IDS_EXTRACTION_ERROR_TITLE), MB_ICONERROR);
+ }
+ }
+ return 1;
+ }
+ }
+
+ #ifndef UNDER_CE
+ CCurrentDirRestorer currentDirRestorer;
+ if (!SetCurrentDir(tempDirPath))
+ return 1;
+ #endif
+
+ HANDLE hProcess = NULL;
+#ifdef MY_SHELL_EXECUTE
+ if (!executeFile.IsEmpty())
+ {
+ CSysString filePath (GetSystemString(executeFile));
+ SHELLEXECUTEINFO execInfo;
+ execInfo.cbSize = sizeof(execInfo);
+ execInfo.fMask = SEE_MASK_NOCLOSEPROCESS
+ #ifndef UNDER_CE
+ | SEE_MASK_FLAG_DDEWAIT
+ #endif
+ ;
+ execInfo.hwnd = NULL;
+ execInfo.lpVerb = NULL;
+ execInfo.lpFile = filePath;
+
+ if (!switches.IsEmpty())
+ {
+ executeParameters.Add_Space_if_NotEmpty();
+ executeParameters += switches;
+ }
+
+ const CSysString parametersSys (GetSystemString(executeParameters));
+ if (parametersSys.IsEmpty())
+ execInfo.lpParameters = NULL;
+ else
+ execInfo.lpParameters = parametersSys;
+
+ execInfo.lpDirectory = NULL;
+ execInfo.nShow = SW_SHOWNORMAL;
+ execInfo.hProcess = NULL;
+ /* BOOL success = */ ::ShellExecuteEx(&execInfo);
+ UINT32 result = (UINT32)(UINT_PTR)execInfo.hInstApp;
+ if (result <= 32)
+ {
+ if (!assumeYes)
+ ShowErrorMessage(L"Cannot open file");
+ return 1;
+ }
+ hProcess = execInfo.hProcess;
+ }
+ else
+#endif
+ {
+ if (appLaunched.IsEmpty())
+ {
+ appLaunched = L"setup.exe";
+ if (!NFind::DoesFileExist_FollowLink(us2fs(appLaunched)))
+ {
+ if (!assumeYes)
+ ShowErrorMessage(L"Cannot find setup.exe");
+ return 1;
+ }
+ }
+
+ {
+ FString s2 = tempDirPath;
+ NName::NormalizeDirPathPrefix(s2);
+ appLaunched.Replace(L"%%T" WSTRING_PATH_SEPARATOR, fs2us(s2));
+ }
+
+ const UString appNameForError = appLaunched; // actually we need to rtemove parameters also
+
+ appLaunched.Replace(L"%%T", fs2us(tempDirPath));
+
+ if (!switches.IsEmpty())
+ {
+ appLaunched.Add_Space();
+ appLaunched += switches;
+ }
+ STARTUPINFO startupInfo;
+ startupInfo.cb = sizeof(startupInfo);
+ startupInfo.lpReserved = NULL;
+ startupInfo.lpDesktop = NULL;
+ startupInfo.lpTitle = NULL;
+ startupInfo.dwFlags = 0;
+ startupInfo.cbReserved2 = 0;
+ startupInfo.lpReserved2 = NULL;
+
+ PROCESS_INFORMATION processInformation;
+
+ const CSysString appLaunchedSys (GetSystemString(dirPrefix + appLaunched));
+
+ const BOOL createResult = CreateProcess(NULL,
+ appLaunchedSys.Ptr_non_const(),
+ NULL, NULL, FALSE, 0, NULL, NULL /*tempDir.GetPath() */,
+ &startupInfo, &processInformation);
+ if (createResult == 0)
+ {
+ if (!assumeYes)
+ {
+ // we print name of exe file, if error message is
+ // ERROR_BAD_EXE_FORMAT: "%1 is not a valid Win32 application".
+ ShowErrorMessageSpec(appNameForError);
+ }
+ return 1;
+ }
+ ::CloseHandle(processInformation.hThread);
+ hProcess = processInformation.hProcess;
+ }
+ if (hProcess)
+ {
+ WaitForSingleObject(hProcess, INFINITE);
+ ::CloseHandle(hProcess);
+ }
+ return 0;
+}
diff --git a/CPP/7zip/Bundles/SFXSetup/StdAfx.cpp b/CPP/7zip/Bundles/SFXSetup/StdAfx.cpp
index c6d3b1f..d0feea8 100644
--- a/CPP/7zip/Bundles/SFXSetup/StdAfx.cpp
+++ b/CPP/7zip/Bundles/SFXSetup/StdAfx.cpp
@@ -1,3 +1,3 @@
-// StdAfx.cpp
-
-#include "StdAfx.h"
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/SFXSetup/StdAfx.h b/CPP/7zip/Bundles/SFXSetup/StdAfx.h
index 72410ee..4f27255 100644
--- a/CPP/7zip/Bundles/SFXSetup/StdAfx.h
+++ b/CPP/7zip/Bundles/SFXSetup/StdAfx.h
@@ -1,13 +1,6 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "../../../Common/Common.h"
-
-#include <commctrl.h>
-
-// #define printf(x) NO_PRINTF_(x)
-// #define sprintf(x) NO_SPRINTF_(x)
-
-#endif
+// StdAfx.h
+
+#if _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../UI/FileManager/StdAfx.h"
diff --git a/CPP/7zip/Bundles/SFXSetup/makefile b/CPP/7zip/Bundles/SFXSetup/makefile
index b97daad..ea0ece2 100644
--- a/CPP/7zip/Bundles/SFXSetup/makefile
+++ b/CPP/7zip/Bundles/SFXSetup/makefile
@@ -1,117 +1,118 @@
-PROG = 7zS.sfx
-MY_FIXED = 1
-
-CFLAGS = $(CFLAGS) \
- -DNO_REGISTRY \
- -DEXTRACT_ONLY \
- -DNO_READ_FROM_CODER \
- -D_SFX \
- -D_NO_CRYPTO \
-
-CURRENT_OBJS = \
- $O\SfxSetup.obj \
- $O\ExtractCallbackSfx.obj \
- $O\ExtractEngine.obj \
-
-COMMON_OBJS = \
- $O\CommandLineParser.obj \
- $O\CRC.obj \
- $O\IntToString.obj \
- $O\NewHandler.obj \
- $O\MyString.obj \
- $O\StringConvert.obj \
- $O\TextConfig.obj \
- $O\UTFConvert.obj \
- $O\MyVector.obj \
- $O\Wildcard.obj \
-
-WIN_OBJS = \
- $O\DLL.obj \
- $O\ErrorMsg.obj \
- $O\FileDir.obj \
- $O\FileFind.obj \
- $O\FileIO.obj \
- $O\FileName.obj \
- $O\PropVariant.obj \
- $O\ResourceString.obj \
- $O\Synchronization.obj \
- $O\System.obj \
- $O\Window.obj \
-
-WIN_CTRL_OBJS = \
- $O\Dialog.obj \
-
-7ZIP_COMMON_OBJS = \
- $O\CreateCoder.obj \
- $O\CWrappers.obj \
- $O\FileStreams.obj \
- $O\InBuffer.obj \
- $O\FilterCoder.obj \
- $O\LimitedStreams.obj \
- $O\OutBuffer.obj \
- $O\ProgressUtils.obj \
- $O\PropId.obj \
- $O\StreamBinder.obj \
- $O\StreamObjects.obj \
- $O\StreamUtils.obj \
- $O\VirtThread.obj \
-
-UI_COMMON_OBJS = \
- $O\ArchiveOpenCallback.obj \
- $O\DefaultName.obj \
- $O\LoadCodecs.obj \
- $O\OpenArchive.obj \
-
-EXPLORER_OBJS = \
- $O\MyMessages.obj \
-
-FM_OBJS = \
- $O\FormatUtils.obj \
- $O\ProgressDialog.obj \
-
-AR_COMMON_OBJS = \
- $O\CoderMixer2.obj \
- $O\ItemNameUtils.obj \
- $O\OutStreamWithCRC.obj \
-
-7Z_OBJS = \
- $O\7zDecode.obj \
- $O\7zExtract.obj \
- $O\7zHandler.obj \
- $O\7zIn.obj \
- $O\7zRegister.obj \
-
-COMPRESS_OBJS = \
- $O\Bcj2Coder.obj \
- $O\Bcj2Register.obj \
- $O\BcjCoder.obj \
- $O\BcjRegister.obj \
- $O\BranchMisc.obj \
- $O\BranchRegister.obj \
- $O\CopyCoder.obj \
- $O\CopyRegister.obj \
- $O\DeltaFilter.obj \
- $O\Lzma2Decoder.obj \
- $O\Lzma2Register.obj \
- $O\LzmaDecoder.obj \
- $O\LzmaRegister.obj \
-
-C_OBJS = \
- $O\Alloc.obj \
- $O\Bcj2.obj \
- $O\Bra.obj \
- $O\Bra86.obj \
- $O\BraIA64.obj \
- $O\CpuArch.obj \
- $O\Delta.obj \
- $O\DllSecur.obj \
- $O\Lzma2Dec.obj \
- $O\Lzma2DecMt.obj \
- $O\LzmaDec.obj \
- $O\MtDec.obj \
- $O\Threads.obj \
-
-!include "../../Crc.mak"
-!include "../../LzmaDec.mak"
-
-!include "../../7zip.mak"
+PROG = 7zS.sfx
+MY_FIXED = 1
+
+CFLAGS = $(CFLAGS) \
+ -DZ7_NO_REGISTRY \
+ -DZ7_EXTRACT_ONLY \
+ -DZ7_NO_READ_FROM_CODER \
+ -DZ7_SFX \
+ -DZ7_NO_CRYPTO \
+
+CURRENT_OBJS = \
+ $O\SfxSetup.obj \
+ $O\ExtractCallbackSfx.obj \
+ $O\ExtractEngine.obj \
+
+COMMON_OBJS = \
+ $O\CommandLineParser.obj \
+ $O\CRC.obj \
+ $O\IntToString.obj \
+ $O\NewHandler.obj \
+ $O\MyString.obj \
+ $O\StringConvert.obj \
+ $O\TextConfig.obj \
+ $O\UTFConvert.obj \
+ $O\MyVector.obj \
+ $O\Wildcard.obj \
+
+WIN_OBJS = \
+ $O\DLL.obj \
+ $O\ErrorMsg.obj \
+ $O\FileDir.obj \
+ $O\FileFind.obj \
+ $O\FileIO.obj \
+ $O\FileName.obj \
+ $O\PropVariant.obj \
+ $O\ResourceString.obj \
+ $O\Synchronization.obj \
+ $O\System.obj \
+ $O\Window.obj \
+
+WIN_CTRL_OBJS = \
+ $O\Dialog.obj \
+
+7ZIP_COMMON_OBJS = \
+ $O\CreateCoder.obj \
+ $O\CWrappers.obj \
+ $O\FileStreams.obj \
+ $O\InBuffer.obj \
+ $O\FilterCoder.obj \
+ $O\LimitedStreams.obj \
+ $O\OutBuffer.obj \
+ $O\ProgressUtils.obj \
+ $O\PropId.obj \
+ $O\StreamBinder.obj \
+ $O\StreamObjects.obj \
+ $O\StreamUtils.obj \
+ $O\VirtThread.obj \
+
+UI_COMMON_OBJS = \
+ $O\ArchiveOpenCallback.obj \
+ $O\DefaultName.obj \
+ $O\LoadCodecs.obj \
+ $O\OpenArchive.obj \
+
+EXPLORER_OBJS = \
+ $O\MyMessages.obj \
+
+FM_OBJS = \
+ $O\FormatUtils.obj \
+ $O\ProgressDialog.obj \
+
+AR_COMMON_OBJS = \
+ $O\CoderMixer2.obj \
+ $O\ItemNameUtils.obj \
+ $O\OutStreamWithCRC.obj \
+
+7Z_OBJS = \
+ $O\7zDecode.obj \
+ $O\7zExtract.obj \
+ $O\7zHandler.obj \
+ $O\7zIn.obj \
+ $O\7zRegister.obj \
+
+COMPRESS_OBJS = \
+ $O\Bcj2Coder.obj \
+ $O\Bcj2Register.obj \
+ $O\BcjCoder.obj \
+ $O\BcjRegister.obj \
+ $O\BranchMisc.obj \
+ $O\BranchRegister.obj \
+ $O\CopyCoder.obj \
+ $O\CopyRegister.obj \
+ $O\DeltaFilter.obj \
+ $O\Lzma2Decoder.obj \
+ $O\Lzma2Register.obj \
+ $O\LzmaDecoder.obj \
+ $O\LzmaRegister.obj \
+
+C_OBJS = \
+ $O\7zStream.obj \
+ $O\Alloc.obj \
+ $O\Bcj2.obj \
+ $O\Bra.obj \
+ $O\Bra86.obj \
+ $O\BraIA64.obj \
+ $O\CpuArch.obj \
+ $O\Delta.obj \
+ $O\DllSecur.obj \
+ $O\Lzma2Dec.obj \
+ $O\Lzma2DecMt.obj \
+ $O\LzmaDec.obj \
+ $O\MtDec.obj \
+ $O\Threads.obj \
+
+!include "../../Crc.mak"
+!include "../../LzmaDec.mak"
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/Bundles/SFXSetup/resource.h b/CPP/7zip/Bundles/SFXSetup/resource.h
index 533197e..d5f440b 100644
--- a/CPP/7zip/Bundles/SFXSetup/resource.h
+++ b/CPP/7zip/Bundles/SFXSetup/resource.h
@@ -1,6 +1,6 @@
-#define IDI_ICON 1
-
-#define IDS_EXTRACTION_ERROR_TITLE 7
-#define IDS_EXTRACTION_ERROR_MESSAGE 8
-#define IDS_CANNOT_CREATE_FOLDER 3003
-#define IDS_PROGRESS_EXTRACTING 3300
+#define IDI_ICON 1
+
+#define IDS_EXTRACTION_ERROR_TITLE 7
+#define IDS_EXTRACTION_ERROR_MESSAGE 8
+#define IDS_CANNOT_CREATE_FOLDER 3003
+#define IDS_PROGRESS_EXTRACTING 3300
diff --git a/CPP/7zip/Bundles/SFXSetup/resource.rc b/CPP/7zip/Bundles/SFXSetup/resource.rc
index 9e88fd4..47e1b76 100644
--- a/CPP/7zip/Bundles/SFXSetup/resource.rc
+++ b/CPP/7zip/Bundles/SFXSetup/resource.rc
@@ -1,16 +1,16 @@
-#include "../../MyVersionInfo.rc"
-#include "resource.h"
-
-MY_VERSION_INFO_APP("7z Setup SFX", "7zS.sfx")
-
-IDI_ICON ICON "setup.ico"
-
-STRINGTABLE
-BEGIN
- IDS_EXTRACTION_ERROR_TITLE "Extraction Failed"
- IDS_EXTRACTION_ERROR_MESSAGE "File is corrupt"
- IDS_CANNOT_CREATE_FOLDER "Cannot create folder '{0}'"
- IDS_PROGRESS_EXTRACTING "Extracting"
-END
-
-#include "../../UI/FileManager/ProgressDialog.rc"
+#include "../../MyVersionInfo.rc"
+#include "resource.h"
+
+MY_VERSION_INFO_APP("7z Setup SFX", "7zS.sfx")
+
+IDI_ICON ICON "setup.ico"
+
+STRINGTABLE
+BEGIN
+ IDS_EXTRACTION_ERROR_TITLE "Extraction Failed"
+ IDS_EXTRACTION_ERROR_MESSAGE "File is corrupt"
+ IDS_CANNOT_CREATE_FOLDER "Cannot create folder '{0}'"
+ IDS_PROGRESS_EXTRACTING "Extracting"
+END
+
+#include "../../UI/FileManager/ProgressDialog.rc"
diff --git a/CPP/7zip/Bundles/SFXWin/SFXWin.dsp b/CPP/7zip/Bundles/SFXWin/SFXWin.dsp
index 83ec931..65cf0bf 100644
--- a/CPP/7zip/Bundles/SFXWin/SFXWin.dsp
+++ b/CPP/7zip/Bundles/SFXWin/SFXWin.dsp
@@ -1,988 +1,1066 @@
-# Microsoft Developer Studio Project File - Name="SFXWin" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Application" 0x0101
-
-CFG=SFXWin - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "SFXWin.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "SFXWin.mak" CFG="SFXWin - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "SFXWin - Win32 Release" (based on "Win32 (x86) Application")
-!MESSAGE "SFXWin - Win32 Debug" (based on "Win32 (x86) Application")
-!MESSAGE "SFXWin - Win32 ReleaseD" (based on "Win32 (x86) Application")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-MTL=midl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "SFXWin - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
-# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_SFXWIN32" /D "_WINDOWS" /D "_MBCS" /D "EXTRACT_ONLY" /D "NO_REGISTRY" /D "NO_READ_FROM_CODER" /D "_SFX" /Yu"StdAfx.h" /FD /c
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x419 /d "NDEBUG"
-# ADD RSC /l 0x419 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7z.sfx" /opt:NOWIN98
-# SUBTRACT LINK32 /pdb:none
-
-!ELSEIF "$(CFG)" == "SFXWin - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
-# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_SFXWIN32" /D "_WINDOWS" /D "_MBCS" /D "EXTRACT_ONLY" /D "NO_REGISTRY" /D "NO_READ_FROM_CODER" /D "_SFX" /Yu"StdAfx.h" /FD /GZ /c
-# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x419 /d "_DEBUG"
-# ADD RSC /l 0x419 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zsfx.exe" /pdbtype:sept
-
-!ELSEIF "$(CFG)" == "SFXWin - Win32 ReleaseD"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "SFXWin___Win32_ReleaseD"
-# PROP BASE Intermediate_Dir "SFXWin___Win32_ReleaseD"
-# PROP BASE Ignore_Export_Lib 0
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "SFXWin___Win32_ReleaseD"
-# PROP Intermediate_Dir "SFXWin___Win32_ReleaseD"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /Gz /MT /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "EXTRACT_ONLY" /D "EXCLUDE_COM" /D "NO_REGISTRY" /D "_SFX" /Yu"StdAfx.h" /FD /c
-# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_SFXWIN32" /D "_WINDOWS" /D "_MBCS" /D "EXTRACT_ONLY" /D "NO_REGISTRY" /D "NO_READ_FROM_CODER" /D "_SFX" /Yu"StdAfx.h" /FD /c
-# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
-# ADD BASE RSC /l 0x419 /d "NDEBUG"
-# ADD RSC /l 0x419 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7z.sfx" /opt:NOWIN98
-# SUBTRACT BASE LINK32 /pdb:none
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zD.sfx" /opt:NOWIN98
-# SUBTRACT LINK32 /pdb:none
-
-!ENDIF
-
-# Begin Target
-
-# Name "SFXWin - Win32 Release"
-# Name "SFXWin - Win32 Debug"
-# Name "SFXWin - Win32 ReleaseD"
-# Begin Group "Spec"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=.\StdAfx.cpp
-# ADD CPP /Yc"StdAfx.h"
-# End Source File
-# Begin Source File
-
-SOURCE=.\StdAfx.h
-# End Source File
-# End Group
-# Begin Group "7z"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zDecode.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zDecode.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zExtract.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zHandler.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zHandler.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zHeader.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zIn.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zIn.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\7z\7zRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\SplitHandler.cpp
-# End Source File
-# End Group
-# Begin Group "Archive Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\CoderMixer2.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\CoderMixer2.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\ItemNameUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\ItemNameUtils.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\MultiStream.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\MultiStream.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Archive\Common\OutStreamWithCRC.h
-# End Source File
-# End Group
-# Begin Group "Compress"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Compress\Bcj2Coder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\Bcj2Register.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BcjCoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BcjRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BranchMisc.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BranchMisc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\BranchRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\CopyCoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\CopyRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\DeltaFilter.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\Lzma2Decoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\Lzma2Register.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\LzmaDecoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\LzmaRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\PpmdDecoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Compress\PpmdRegister.cpp
-# End Source File
-# End Group
-# Begin Group "Crypto"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Crypto\7zAes.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Crypto\7zAes.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Crypto\7zAesRegister.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Crypto\MyAes.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Crypto\MyAes.h
-# End Source File
-# End Group
-# Begin Group "Dialogs"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\BrowseDialog.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\BrowseDialog.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\ComboDialog.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\ComboDialog.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\OverwriteDialog.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\OverwriteDialog.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\PasswordDialog.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\PasswordDialog.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\ProgressDialog2.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\ProgressDialog2.h
-# End Source File
-# End Group
-# Begin Group "7zip Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Common\CreateCoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\CreateCoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\CWrappers.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\CWrappers.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FilePathAutoRename.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FilePathAutoRename.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FileStreams.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FileStreams.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FilterCoder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FilterCoder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\InBuffer.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\InBuffer.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\LimitedStreams.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\LimitedStreams.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\LockedStream.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\LockedStream.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\OutBuffer.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\OutBuffer.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\ProgressUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\ProgressUtils.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\PropId.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamBinder.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamBinder.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamObjects.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamObjects.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\StreamUtils.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\VirtThread.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\VirtThread.h
-# End Source File
-# End Group
-# Begin Group "File Manager"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\ExtractCallback.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\ExtractCallback.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\FormatUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\FormatUtils.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\PropertyName.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\PropertyName.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\SysIconUtils.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\FileManager\SysIconUtils.h
-# End Source File
-# End Group
-# Begin Group "Windows"
-
-# PROP Default_Filter ""
-# Begin Group "Control"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Control\ComboBox.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Control\ComboBox.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Control\Dialog.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Control\Dialog.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Control\ListView.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Control\ListView.h
-# End Source File
-# End Group
-# Begin Source File
-
-SOURCE=..\..\..\Windows\CommonDialog.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\CommonDialog.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\DLL.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\DLL.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\ErrorMsg.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\ErrorMsg.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileDir.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileDir.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileFind.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileFind.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileIO.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileIO.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileName.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileName.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariant.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariant.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariantConv.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariantConv.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\ResourceString.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\ResourceString.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Shell.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Shell.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Synchronization.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Synchronization.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\System.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\System.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Window.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\Window.h
-# End Source File
-# End Group
-# Begin Group "Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\Common\CommandLineParser.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\CommandLineParser.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\CRC.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\CRC.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\IntToString.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\IntToString.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyString.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyString.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyVector.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyVector.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\NewHandler.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\NewHandler.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StringConvert.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StringConvert.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\Wildcard.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\Wildcard.h
-# End Source File
-# End Group
-# Begin Group "UI"
-
-# PROP Default_Filter ""
-# Begin Group "UI Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ArchiveExtractCallback.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ArchiveOpenCallback.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\DefaultName.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\DefaultName.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\Extract.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\Extract.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ExtractingFilePath.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\ExtractingFilePath.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\LoadCodecs.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\LoadCodecs.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\OpenArchive.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Common\OpenArchive.h
-# End Source File
-# End Group
-# Begin Group "GUI"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\UI\GUI\ExtractDialog.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\GUI\ExtractDialog.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\GUI\ExtractGUI.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\GUI\ExtractGUI.h
-# End Source File
-# End Group
-# Begin Group "Explorer"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\UI\Explorer\MyMessages.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\UI\Explorer\MyMessages.h
-# End Source File
-# End Group
-# End Group
-# Begin Group "C"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\..\C\7zCrc.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\7zCrc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\7zCrcOpt.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Aes.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Aes.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\AesOpt.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Alloc.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Alloc.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bcj2.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bcj2.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bra.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bra.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Bra86.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\BraIA64.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\CpuArch.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Delta.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Delta.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\DllSecur.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\DllSecur.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma2Dec.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma2Dec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma2DecMt.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Lzma2DecMt.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzmaDec.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\LzmaDec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\MtDec.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\MtDec.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Ppmd7.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Ppmd7.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Ppmd7Dec.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Sha256.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Threads.c
-# SUBTRACT CPP /YX /Yc /Yu
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Threads.h
-# End Source File
-# End Group
-# Begin Source File
-
-SOURCE=.\7z.ico
-# End Source File
-# Begin Source File
-
-SOURCE=.\7z1.ico
-# End Source File
-# Begin Source File
-
-SOURCE=.\resource.rc
-# End Source File
-# Begin Source File
-
-SOURCE=.\SfxWin.cpp
-# End Source File
-# End Target
-# End Project
+# Microsoft Developer Studio Project File - Name="SFXWin" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=SFXWin - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "SFXWin.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "SFXWin.mak" CFG="SFXWin - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "SFXWin - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "SFXWin - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE "SFXWin - Win32 ReleaseD" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "SFXWin - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_NO_READ_FROM_CODER" /D "Z7_SFX" /Yu"StdAfx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7z.sfx" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "SFXWin - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_NO_READ_FROM_CODER" /D "Z7_SFX" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zsfx.exe" /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "SFXWin - Win32 ReleaseD"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "SFXWin___Win32_ReleaseD"
+# PROP BASE Intermediate_Dir "SFXWin___Win32_ReleaseD"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "SFXWin___Win32_ReleaseD"
+# PROP Intermediate_Dir "SFXWin___Win32_ReleaseD"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /Gz /MT /W3 /GX /O1 /I "..\..\..\\" /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_SFX" /Yu"StdAfx.h" /FD /c
+# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "Z7_EXTRACT_ONLY" /D "Z7_NO_REGISTRY" /D "Z7_NO_READ_FROM_CODER" /D "Z7_SFX" /Yu"StdAfx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7z.sfx" /opt:NOWIN98
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zD.sfx" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ENDIF
+
+# Begin Target
+
+# Name "SFXWin - Win32 Release"
+# Name "SFXWin - Win32 Debug"
+# Name "SFXWin - Win32 ReleaseD"
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"StdAfx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "7z"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zDecode.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zDecode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zExtract.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zHeader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zIn.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zIn.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\7z\7zRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\SplitHandler.cpp
+# End Source File
+# End Group
+# Begin Group "Archive Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\CoderMixer2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\MultiStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\MultiStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.h
+# End Source File
+# End Group
+# Begin Group "Compress"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\Bcj2Coder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Bcj2Coder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Bcj2Register.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BcjCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BcjCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BcjRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchMisc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchMisc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\BranchRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\DeltaFilter.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Decoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\Lzma2Register.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\LzmaRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdDecoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdDecoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\PpmdRegister.cpp
+# End Source File
+# End Group
+# Begin Group "Crypto"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Crypto\7zAes.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\7zAes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\7zAesRegister.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\MyAes.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Crypto\MyAes.h
+# End Source File
+# End Group
+# Begin Group "Dialogs"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\BrowseDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\BrowseDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ComboDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ComboDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\OverwriteDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\OverwriteDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PasswordDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PasswordDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ProgressDialog2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ProgressDialog2.h
+# End Source File
+# End Group
+# Begin Group "7zip Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CWrappers.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CWrappers.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\InBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LockedStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LockedStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\OutBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\PropId.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamBinder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamBinder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\VirtThread.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\VirtThread.h
+# End Source File
+# End Group
+# Begin Group "File Manager"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ExtractCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\ExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FormatUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\FormatUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PropertyName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\PropertyName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\SysIconUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\FileManager\SysIconUtils.h
+# End Source File
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Group "Control"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ComboBox.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ComboBox.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Dialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Dialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ListView.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ListView.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Clipboard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Clipboard.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\CommonDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\CommonDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryGlobal.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryGlobal.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ResourceString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ResourceString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Shell.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Shell.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Window.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Window.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Common.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Sha256Prepare.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.h
+# End Source File
+# End Group
+# Begin Group "UI"
+
+# PROP Default_Filter ""
+# Begin Group "UI Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveExtractCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveOpenCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ArchiveOpenCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\DefaultName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\DefaultName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Extract.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\Extract.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExtractingFilePath.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\ExtractingFilePath.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\LoadCodecs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\LoadCodecs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\OpenArchive.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Common\OpenArchive.h
+# End Source File
+# End Group
+# Begin Group "GUI"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\ExtractDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\ExtractDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\ExtractGUI.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\GUI\ExtractGUI.h
+# End Source File
+# End Group
+# Begin Group "Explorer"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\UI\Explorer\MyMessages.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\UI\Explorer\MyMessages.h
+# End Source File
+# End Group
+# End Group
+# Begin Group "C"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrcOpt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zStream.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Aes.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Aes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\AesOpt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bcj2.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bcj2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Bra86.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\BraIA64.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Delta.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Delta.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\DllSecur.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\DllSecur.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Dec.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2Dec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2DecMt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Lzma2DecMt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaDec.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\LzmaDec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtDec.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\MtDec.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd7.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd7.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Ppmd7Dec.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha256.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sha256Opt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.h
+# End Source File
+# End Group
+# Begin Group "7zip"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\IArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ICoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IDecl.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IPassword.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IProgress.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\7z.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\SfxWin.cpp
+# End Source File
+# End Target
+# End Project
diff --git a/CPP/7zip/Bundles/SFXWin/SFXWin.dsw b/CPP/7zip/Bundles/SFXWin/SFXWin.dsw
index 6695803..a9926c7 100644
--- a/CPP/7zip/Bundles/SFXWin/SFXWin.dsw
+++ b/CPP/7zip/Bundles/SFXWin/SFXWin.dsw
@@ -1,29 +1,29 @@
-Microsoft Developer Studio Workspace File, Format Version 6.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "SFXWin"=.\SFXWin.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
-
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "SFXWin"=.\SFXWin.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/Bundles/SFXWin/SfxWin.cpp b/CPP/7zip/Bundles/SFXWin/SfxWin.cpp
index 5eade1a..3e1880e 100644
--- a/CPP/7zip/Bundles/SFXWin/SfxWin.cpp
+++ b/CPP/7zip/Bundles/SFXWin/SfxWin.cpp
@@ -1,241 +1,254 @@
-// Main.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/MyWindows.h"
-
-#include <Shlwapi.h>
-
-#include "../../../Common/MyInitGuid.h"
-
-#include "../../../Common/CommandLineParser.h"
-#include "../../../Common/StringConvert.h"
-
-#include "../../../Windows/DLL.h"
-#include "../../../Windows/ErrorMsg.h"
-#include "../../../Windows/FileDir.h"
-#include "../../../Windows/FileName.h"
-#include "../../../Windows/NtCheck.h"
-#include "../../../Windows/ResourceString.h"
-
-#include "../../ICoder.h"
-#include "../../IPassword.h"
-#include "../../Archive/IArchive.h"
-#include "../../UI/Common/Extract.h"
-#include "../../UI/Common/ExitCode.h"
-#include "../../UI/Explorer/MyMessages.h"
-#include "../../UI/FileManager/MyWindowsNew.h"
-#include "../../UI/GUI/ExtractGUI.h"
-#include "../../UI/GUI/ExtractRes.h"
-
-#include "../../../../C/DllSecur.h"
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NDir;
-
-HINSTANCE g_hInstance;
-
-#ifndef UNDER_CE
-
-DWORD g_ComCtl32Version;
-
-static DWORD GetDllVersion(LPCTSTR dllName)
-{
- DWORD dwVersion = 0;
- HINSTANCE hinstDll = LoadLibrary(dllName);
- if (hinstDll)
- {
- DLLGETVERSIONPROC pDllGetVersion = (DLLGETVERSIONPROC)GetProcAddress(hinstDll, "DllGetVersion");
- if (pDllGetVersion)
- {
- DLLVERSIONINFO dvi;
- ZeroMemory(&dvi, sizeof(dvi));
- dvi.cbSize = sizeof(dvi);
- HRESULT hr = (*pDllGetVersion)(&dvi);
- if (SUCCEEDED(hr))
- dwVersion = MAKELONG(dvi.dwMinorVersion, dvi.dwMajorVersion);
- }
- FreeLibrary(hinstDll);
- }
- return dwVersion;
-}
-
-#endif
-
-bool g_LVN_ITEMACTIVATE_Support = true;
-
-static const wchar_t * const kUnknownExceptionMessage = L"ERROR: Unknown Error!";
-
-void ErrorMessageForHRESULT(HRESULT res)
-{
- ShowErrorMessage(HResultToMessage(res));
-}
-
-int APIENTRY WinMain2()
-{
- // OleInitialize is required for ProgressBar in TaskBar.
- #ifndef UNDER_CE
- OleInitialize(NULL);
- #endif
-
- #ifndef UNDER_CE
- g_ComCtl32Version = ::GetDllVersion(TEXT("comctl32.dll"));
- g_LVN_ITEMACTIVATE_Support = (g_ComCtl32Version >= MAKELONG(71, 4));
- #endif
-
- UString password;
- bool assumeYes = false;
- bool outputFolderDefined = false;
- FString outputFolder;
- UStringVector commandStrings;
- NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);
-
- #ifndef UNDER_CE
- if (commandStrings.Size() > 0)
- commandStrings.Delete(0);
- #endif
-
- FOR_VECTOR (i, commandStrings)
- {
- const UString &s = commandStrings[i];
- if (s.Len() > 1 && s[0] == '-')
- {
- wchar_t c = MyCharLower_Ascii(s[1]);
- if (c == 'y')
- {
- assumeYes = true;
- if (s.Len() != 2)
- {
- ShowErrorMessage(L"Bad command");
- return 1;
- }
- }
- else if (c == 'o')
- {
- outputFolder = us2fs(s.Ptr(2));
- NName::NormalizeDirPathPrefix(outputFolder);
- outputFolderDefined = !outputFolder.IsEmpty();
- }
- else if (c == 'p')
- {
- password = s.Ptr(2);
- }
- }
- }
-
- FString path;
- NDLL::MyGetModuleFileName(path);
-
- FString fullPath;
- if (!MyGetFullPathName(path, fullPath))
- {
- ShowErrorMessage(L"Error 1329484");
- return 1;
- }
-
- CCodecs *codecs = new CCodecs;
- CMyComPtr<IUnknown> compressCodecsInfo = codecs;
- HRESULT result = codecs->Load();
- if (result != S_OK)
- {
- ErrorMessageForHRESULT(result);
- return 1;
- }
-
- // COpenCallbackGUI openCallback;
-
- // openCallback.PasswordIsDefined = !password.IsEmpty();
- // openCallback.Password = password;
-
- CExtractCallbackImp *ecs = new CExtractCallbackImp;
- CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
- ecs->Init();
-
- #ifndef _NO_CRYPTO
- ecs->PasswordIsDefined = !password.IsEmpty();
- ecs->Password = password;
- #endif
-
- CExtractOptions eo;
-
- FString dirPrefix;
- if (!GetOnlyDirPrefix(path, dirPrefix))
- {
- ShowErrorMessage(L"Error 1329485");
- return 1;
- }
-
- eo.OutputDir = outputFolderDefined ? outputFolder : dirPrefix;
- eo.YesToAll = assumeYes;
- eo.OverwriteMode = assumeYes ?
- NExtract::NOverwriteMode::kOverwrite :
- NExtract::NOverwriteMode::kAsk;
- eo.PathMode = NExtract::NPathMode::kFullPaths;
- eo.TestMode = false;
-
- UStringVector v1, v2;
- v1.Add(fs2us(fullPath));
- v2.Add(fs2us(fullPath));
- NWildcard::CCensorNode wildcardCensor;
- wildcardCensor.AddItem(true, L"*", true, true, true, true);
-
- bool messageWasDisplayed = false;
- result = ExtractGUI(codecs,
- CObjectVector<COpenType>(), CIntVector(),
- v1, v2,
- wildcardCensor, eo, (assumeYes ? false: true), messageWasDisplayed, ecs);
-
- if (result == S_OK)
- {
- if (!ecs->IsOK())
- return NExitCode::kFatalError;
- return 0;
- }
- if (result == E_ABORT)
- return NExitCode::kUserBreak;
- if (!messageWasDisplayed)
- {
- if (result == S_FALSE)
- ShowErrorMessage(L"Error in archive");
- else
- ErrorMessageForHRESULT(result);
- }
- if (result == E_OUTOFMEMORY)
- return NExitCode::kMemoryError;
- return NExitCode::kFatalError;
-}
-
-#define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return NExitCode::kFatalError;
-
-int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */,
- #ifdef UNDER_CE
- LPWSTR
- #else
- LPSTR
- #endif
- /* lpCmdLine */, int /* nCmdShow */)
-{
- g_hInstance = (HINSTANCE)hInstance;
-
- NT_CHECK
-
- try
- {
- #ifdef _WIN32
- LoadSecurityDlls();
- #endif
-
- return WinMain2();
- }
- catch(const CNewException &)
- {
- ErrorMessageForHRESULT(E_OUTOFMEMORY);
- return NExitCode::kMemoryError;
- }
- catch(...)
- {
- ShowErrorMessage(kUnknownExceptionMessage);
- return NExitCode::kFatalError;
- }
-}
+// Main.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <shlwapi.h>
+#else
+#include <Shlwapi.h>
+#endif
+
+#include "../../../../C/DllSecur.h"
+
+#include "../../../Common/MyInitGuid.h"
+
+#include "../../../Common/CommandLineParser.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/NtCheck.h"
+#include "../../../Windows/ResourceString.h"
+
+#include "../../ICoder.h"
+#include "../../IPassword.h"
+#include "../../Archive/IArchive.h"
+#include "../../UI/Common/Extract.h"
+#include "../../UI/Common/ExitCode.h"
+#include "../../UI/Explorer/MyMessages.h"
+#include "../../UI/FileManager/MyWindowsNew.h"
+#include "../../UI/GUI/ExtractGUI.h"
+#include "../../UI/GUI/ExtractRes.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+extern
+HINSTANCE g_hInstance;
+HINSTANCE g_hInstance;
+
+#ifndef UNDER_CE
+
+static
+DWORD g_ComCtl32Version;
+
+static DWORD GetDllVersion(LPCTSTR dllName)
+{
+ DWORD dwVersion = 0;
+ const HINSTANCE hinstDll = LoadLibrary(dllName);
+ if (hinstDll)
+ {
+ const
+ DLLGETVERSIONPROC func_DllGetVersion = Z7_GET_PROC_ADDRESS(
+ DLLGETVERSIONPROC, hinstDll, "DllGetVersion");
+ if (func_DllGetVersion)
+ {
+ DLLVERSIONINFO dvi;
+ ZeroMemory(&dvi, sizeof(dvi));
+ dvi.cbSize = sizeof(dvi);
+ const HRESULT hr = func_DllGetVersion(&dvi);
+ if (SUCCEEDED(hr))
+ dwVersion = (DWORD)MAKELONG(dvi.dwMinorVersion, dvi.dwMajorVersion);
+ }
+ FreeLibrary(hinstDll);
+ }
+ return dwVersion;
+}
+
+#endif
+
+extern
+bool g_LVN_ITEMACTIVATE_Support;
+bool g_LVN_ITEMACTIVATE_Support = true;
+
+static const wchar_t * const kUnknownExceptionMessage = L"ERROR: Unknown Error!";
+
+static void ErrorMessageForHRESULT(HRESULT res)
+{
+ ShowErrorMessage(HResultToMessage(res));
+}
+
+static int APIENTRY WinMain2()
+{
+ // OleInitialize is required for ProgressBar in TaskBar.
+ #ifndef UNDER_CE
+ OleInitialize(NULL);
+ #endif
+
+ #ifndef UNDER_CE
+ g_ComCtl32Version = ::GetDllVersion(TEXT("comctl32.dll"));
+ g_LVN_ITEMACTIVATE_Support = (g_ComCtl32Version >= MAKELONG(71, 4));
+ #endif
+
+ UString password;
+ bool assumeYes = false;
+ bool outputFolderDefined = false;
+ FString outputFolder;
+ UStringVector commandStrings;
+ NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);
+
+ #ifndef UNDER_CE
+ if (commandStrings.Size() > 0)
+ commandStrings.Delete(0);
+ #endif
+
+ FOR_VECTOR (i, commandStrings)
+ {
+ const UString &s = commandStrings[i];
+ if (s.Len() > 1 && s[0] == '-')
+ {
+ const wchar_t c = MyCharLower_Ascii(s[1]);
+ if (c == 'y')
+ {
+ assumeYes = true;
+ if (s.Len() != 2)
+ {
+ ShowErrorMessage(L"Bad command");
+ return 1;
+ }
+ }
+ else if (c == 'o')
+ {
+ outputFolder = us2fs(s.Ptr(2));
+ NName::NormalizeDirPathPrefix(outputFolder);
+ outputFolderDefined = !outputFolder.IsEmpty();
+ }
+ else if (c == 'p')
+ {
+ password = s.Ptr(2);
+ }
+ }
+ }
+
+ FString path;
+ NDLL::MyGetModuleFileName(path);
+
+ FString fullPath;
+ if (!MyGetFullPathName(path, fullPath))
+ {
+ ShowErrorMessage(L"Error 1329484");
+ return 1;
+ }
+
+ CCodecs *codecs = new CCodecs;
+ CMyComPtr<IUnknown> compressCodecsInfo = codecs;
+ HRESULT result = codecs->Load();
+ if (result != S_OK)
+ {
+ ErrorMessageForHRESULT(result);
+ return 1;
+ }
+
+ // COpenCallbackGUI openCallback;
+
+ // openCallback.PasswordIsDefined = !password.IsEmpty();
+ // openCallback.Password = password;
+
+ CExtractCallbackImp *ecs = new CExtractCallbackImp;
+ CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
+ ecs->Init();
+
+ #ifndef Z7_NO_CRYPTO
+ ecs->PasswordIsDefined = !password.IsEmpty();
+ ecs->Password = password;
+ #endif
+
+ CExtractOptions eo;
+
+ FString dirPrefix;
+ if (!GetOnlyDirPrefix(path, dirPrefix))
+ {
+ ShowErrorMessage(L"Error 1329485");
+ return 1;
+ }
+
+ eo.OutputDir = outputFolderDefined ? outputFolder : dirPrefix;
+ eo.YesToAll = assumeYes;
+ eo.OverwriteMode = assumeYes ?
+ NExtract::NOverwriteMode::kOverwrite :
+ NExtract::NOverwriteMode::kAsk;
+ eo.PathMode = NExtract::NPathMode::kFullPaths;
+ eo.TestMode = false;
+
+ UStringVector v1, v2;
+ v1.Add(fs2us(fullPath));
+ v2.Add(fs2us(fullPath));
+ NWildcard::CCensorNode wildcardCensor;
+ wildcardCensor.Add_Wildcard();
+
+ bool messageWasDisplayed = false;
+ result = ExtractGUI(codecs,
+ CObjectVector<COpenType>(), CIntVector(),
+ v1, v2,
+ wildcardCensor, eo, (assumeYes ? false: true), messageWasDisplayed, ecs);
+
+ if (result == S_OK)
+ {
+ if (!ecs->IsOK())
+ return NExitCode::kFatalError;
+ return 0;
+ }
+ if (result == E_ABORT)
+ return NExitCode::kUserBreak;
+ if (!messageWasDisplayed)
+ {
+ if (result == S_FALSE)
+ ShowErrorMessage(L"Error in archive");
+ else
+ ErrorMessageForHRESULT(result);
+ }
+ if (result == E_OUTOFMEMORY)
+ return NExitCode::kMemoryError;
+ return NExitCode::kFatalError;
+}
+
+#if defined(_WIN32) && defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE)
+#define NT_CHECK_FAIL_ACTION ShowErrorMessage(L"Unsupported Windows version"); return NExitCode::kFatalError;
+#endif
+
+int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */,
+ #ifdef UNDER_CE
+ LPWSTR
+ #else
+ LPSTR
+ #endif
+ /* lpCmdLine */, int /* nCmdShow */)
+{
+ g_hInstance = (HINSTANCE)hInstance;
+
+ NT_CHECK
+
+ try
+ {
+ #ifdef _WIN32
+ LoadSecurityDlls();
+ #endif
+
+ return WinMain2();
+ }
+ catch(const CNewException &)
+ {
+ ErrorMessageForHRESULT(E_OUTOFMEMORY);
+ return NExitCode::kMemoryError;
+ }
+ catch(...)
+ {
+ ShowErrorMessage(kUnknownExceptionMessage);
+ return NExitCode::kFatalError;
+ }
+}
diff --git a/CPP/7zip/Bundles/SFXWin/StdAfx.cpp b/CPP/7zip/Bundles/SFXWin/StdAfx.cpp
index c6d3b1f..d0feea8 100644
--- a/CPP/7zip/Bundles/SFXWin/StdAfx.cpp
+++ b/CPP/7zip/Bundles/SFXWin/StdAfx.cpp
@@ -1,3 +1,3 @@
-// StdAfx.cpp
-
-#include "StdAfx.h"
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Bundles/SFXWin/StdAfx.h b/CPP/7zip/Bundles/SFXWin/StdAfx.h
index f263ecb..4f27255 100644
--- a/CPP/7zip/Bundles/SFXWin/StdAfx.h
+++ b/CPP/7zip/Bundles/SFXWin/StdAfx.h
@@ -1,14 +1,6 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "../../../Common/Common.h"
-
-#include <commctrl.h>
-#include <ShlObj.h>
-
-// #define printf(x) NO_PRINTF_(x)
-// #define sprintf(x) NO_SPRINTF_(x)
-
-#endif
+// StdAfx.h
+
+#if _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../UI/FileManager/StdAfx.h"
diff --git a/CPP/7zip/Bundles/SFXWin/makefile b/CPP/7zip/Bundles/SFXWin/makefile
index 21a67dd..69a8553 100644
--- a/CPP/7zip/Bundles/SFXWin/makefile
+++ b/CPP/7zip/Bundles/SFXWin/makefile
@@ -1,153 +1,156 @@
-PROG = 7z.sfx
-MY_FIXED = 1
-
-CFLAGS = $(CFLAGS) \
- -DNO_REGISTRY \
- -DEXTRACT_ONLY \
- -DNO_READ_FROM_CODER \
- -D_SFX \
-
-!IFDEF UNDER_CE
-LIBS = $(LIBS) ceshell.lib Commctrl.lib
-!ELSE
-LIBS = $(LIBS) comctl32.lib comdlg32.lib
-!ENDIF
-
-CURRENT_OBJS = \
- $O\SfxWin.obj \
-
-GUI_OBJS = \
- $O\ExtractDialog.obj \
- $O\ExtractGUI.obj \
-
-COMMON_OBJS = \
- $O\CRC.obj \
- $O\CommandLineParser.obj \
- $O\IntToString.obj \
- $O\NewHandler.obj \
- $O\MyString.obj \
- $O\StringConvert.obj \
- $O\MyVector.obj \
- $O\Wildcard.obj \
-
-WIN_OBJS = \
- $O\CommonDialog.obj \
- $O\DLL.obj \
- $O\ErrorMsg.obj \
- $O\FileDir.obj \
- $O\FileFind.obj \
- $O\FileIO.obj \
- $O\FileName.obj \
- $O\PropVariant.obj \
- $O\PropVariantConv.obj \
- $O\ResourceString.obj \
- $O\Shell.obj \
- $O\Synchronization.obj \
- $O\System.obj \
- $O\Window.obj \
-
-WIN_CTRL_OBJS = \
- $O\ComboBox.obj \
- $O\Dialog.obj \
- $O\ListView.obj \
-
-7ZIP_COMMON_OBJS = \
- $O\CreateCoder.obj \
- $O\CWrappers.obj \
- $O\FilePathAutoRename.obj \
- $O\FileStreams.obj \
- $O\InBuffer.obj \
- $O\FilterCoder.obj \
- $O\LimitedStreams.obj \
- $O\OutBuffer.obj \
- $O\ProgressUtils.obj \
- $O\PropId.obj \
- $O\StreamBinder.obj \
- $O\StreamObjects.obj \
- $O\StreamUtils.obj \
- $O\VirtThread.obj \
-
-UI_COMMON_OBJS = \
- $O\ArchiveExtractCallback.obj \
- $O\ArchiveOpenCallback.obj \
- $O\DefaultName.obj \
- $O\Extract.obj \
- $O\ExtractingFilePath.obj \
- $O\LoadCodecs.obj \
- $O\OpenArchive.obj \
-
-EXPLORER_OBJS = \
- $O\MyMessages.obj \
-
-FM_OBJS = \
- $O\BrowseDialog.obj \
- $O\ComboDialog.obj \
- $O\ExtractCallback.obj \
- $O\FormatUtils.obj \
- $O\OverwriteDialog.obj \
- $O\PasswordDialog.obj \
- $O\ProgressDialog2.obj \
- $O\PropertyName.obj \
- $O\SysIconUtils.obj \
-
-AR_OBJS = \
- $O\SplitHandler.obj \
-
-AR_COMMON_OBJS = \
- $O\CoderMixer2.obj \
- $O\ItemNameUtils.obj \
- $O\MultiStream.obj \
- $O\OutStreamWithCRC.obj \
-
-7Z_OBJS = \
- $O\7zDecode.obj \
- $O\7zExtract.obj \
- $O\7zHandler.obj \
- $O\7zIn.obj \
- $O\7zRegister.obj \
-
-COMPRESS_OBJS = \
- $O\Bcj2Coder.obj \
- $O\Bcj2Register.obj \
- $O\BcjCoder.obj \
- $O\BcjRegister.obj \
- $O\BranchMisc.obj \
- $O\BranchRegister.obj \
- $O\CopyCoder.obj \
- $O\CopyRegister.obj \
- $O\DeltaFilter.obj \
- $O\Lzma2Decoder.obj \
- $O\Lzma2Register.obj \
- $O\LzmaDecoder.obj \
- $O\LzmaRegister.obj \
- $O\PpmdDecoder.obj \
- $O\PpmdRegister.obj \
-
-CRYPTO_OBJS = \
- $O\7zAes.obj \
- $O\7zAesRegister.obj \
- $O\MyAes.obj \
-
-C_OBJS = \
- $O\Alloc.obj \
- $O\Bcj2.obj \
- $O\Bra.obj \
- $O\Bra86.obj \
- $O\BraIA64.obj \
- $O\CpuArch.obj \
- $O\Delta.obj \
- $O\DllSecur.obj \
- $O\Lzma2Dec.obj \
- $O\Lzma2DecMt.obj \
- $O\LzmaDec.obj \
- $O\MtDec.obj \
- $O\Ppmd7.obj \
- $O\Ppmd7Dec.obj \
- $O\Sha256.obj \
- $O\Threads.obj \
-
-!include "../../Aes.mak"
-!include "../../Crc.mak"
-!include "../../LzmaDec.mak"
-
-!include "../../7zip.mak"
+PROG = 7z.sfx
+MY_FIXED = 1
+
+CFLAGS = $(CFLAGS) \
+ -DZ7_NO_REGISTRY \
+ -DZ7_EXTRACT_ONLY \
+ -DZ7_NO_READ_FROM_CODER \
+ -DZ7_SFX \
+
+!IFDEF UNDER_CE
+LIBS = $(LIBS) ceshell.lib Commctrl.lib
+!ELSE
+LIBS = $(LIBS) comctl32.lib comdlg32.lib
+!ENDIF
+
+CURRENT_OBJS = \
+ $O\SfxWin.obj \
+
+GUI_OBJS = \
+ $O\ExtractDialog.obj \
+ $O\ExtractGUI.obj \
+
+COMMON_OBJS = \
+ $O\CRC.obj \
+ $O\CommandLineParser.obj \
+ $O\IntToString.obj \
+ $O\NewHandler.obj \
+ $O\MyString.obj \
+ $O\StringConvert.obj \
+ $O\MyVector.obj \
+ $O\Wildcard.obj \
+
+WIN_OBJS = \
+ $O\Clipboard.obj \
+ $O\CommonDialog.obj \
+ $O\DLL.obj \
+ $O\ErrorMsg.obj \
+ $O\FileDir.obj \
+ $O\FileFind.obj \
+ $O\FileIO.obj \
+ $O\FileName.obj \
+ $O\MemoryGlobal.obj \
+ $O\PropVariant.obj \
+ $O\PropVariantConv.obj \
+ $O\ResourceString.obj \
+ $O\Shell.obj \
+ $O\Synchronization.obj \
+ $O\System.obj \
+ $O\Window.obj \
+
+WIN_CTRL_OBJS = \
+ $O\ComboBox.obj \
+ $O\Dialog.obj \
+ $O\ListView.obj \
+
+7ZIP_COMMON_OBJS = \
+ $O\CreateCoder.obj \
+ $O\CWrappers.obj \
+ $O\FilePathAutoRename.obj \
+ $O\FileStreams.obj \
+ $O\InBuffer.obj \
+ $O\FilterCoder.obj \
+ $O\LimitedStreams.obj \
+ $O\OutBuffer.obj \
+ $O\ProgressUtils.obj \
+ $O\PropId.obj \
+ $O\StreamBinder.obj \
+ $O\StreamObjects.obj \
+ $O\StreamUtils.obj \
+ $O\VirtThread.obj \
+
+UI_COMMON_OBJS = \
+ $O\ArchiveExtractCallback.obj \
+ $O\ArchiveOpenCallback.obj \
+ $O\DefaultName.obj \
+ $O\Extract.obj \
+ $O\ExtractingFilePath.obj \
+ $O\LoadCodecs.obj \
+ $O\OpenArchive.obj \
+
+EXPLORER_OBJS = \
+ $O\MyMessages.obj \
+
+FM_OBJS = \
+ $O\BrowseDialog.obj \
+ $O\ComboDialog.obj \
+ $O\ExtractCallback.obj \
+ $O\FormatUtils.obj \
+ $O\OverwriteDialog.obj \
+ $O\PasswordDialog.obj \
+ $O\ProgressDialog2.obj \
+ $O\PropertyName.obj \
+ $O\SysIconUtils.obj \
+
+AR_OBJS = \
+ $O\SplitHandler.obj \
+
+AR_COMMON_OBJS = \
+ $O\CoderMixer2.obj \
+ $O\ItemNameUtils.obj \
+ $O\MultiStream.obj \
+ $O\OutStreamWithCRC.obj \
+
+7Z_OBJS = \
+ $O\7zDecode.obj \
+ $O\7zExtract.obj \
+ $O\7zHandler.obj \
+ $O\7zIn.obj \
+ $O\7zRegister.obj \
+
+COMPRESS_OBJS = \
+ $O\Bcj2Coder.obj \
+ $O\Bcj2Register.obj \
+ $O\BcjCoder.obj \
+ $O\BcjRegister.obj \
+ $O\BranchMisc.obj \
+ $O\BranchRegister.obj \
+ $O\CopyCoder.obj \
+ $O\CopyRegister.obj \
+ $O\DeltaFilter.obj \
+ $O\Lzma2Decoder.obj \
+ $O\Lzma2Register.obj \
+ $O\LzmaDecoder.obj \
+ $O\LzmaRegister.obj \
+ $O\PpmdDecoder.obj \
+ $O\PpmdRegister.obj \
+
+CRYPTO_OBJS = \
+ $O\7zAes.obj \
+ $O\7zAesRegister.obj \
+ $O\MyAes.obj \
+
+C_OBJS = \
+ $O\7zStream.obj \
+ $O\Alloc.obj \
+ $O\Bcj2.obj \
+ $O\Bra.obj \
+ $O\Bra86.obj \
+ $O\BraIA64.obj \
+ $O\CpuArch.obj \
+ $O\Delta.obj \
+ $O\DllSecur.obj \
+ $O\Lzma2Dec.obj \
+ $O\Lzma2DecMt.obj \
+ $O\LzmaDec.obj \
+ $O\MtDec.obj \
+ $O\Ppmd7.obj \
+ $O\Ppmd7Dec.obj \
+ $O\Threads.obj \
+
+!include "../../Aes.mak"
+!include "../../Crc.mak"
+!include "../../LzmaDec.mak"
+!include "../../Sha256.mak"
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/Bundles/SFXWin/resource.h b/CPP/7zip/Bundles/SFXWin/resource.h
index d9fae1b..30fe203 100644
--- a/CPP/7zip/Bundles/SFXWin/resource.h
+++ b/CPP/7zip/Bundles/SFXWin/resource.h
@@ -1 +1 @@
-#define IDI_ICON 1
+#define IDI_ICON 1
diff --git a/CPP/7zip/Bundles/SFXWin/resource.rc b/CPP/7zip/Bundles/SFXWin/resource.rc
index 3b69b35..3b2217a 100644
--- a/CPP/7zip/Bundles/SFXWin/resource.rc
+++ b/CPP/7zip/Bundles/SFXWin/resource.rc
@@ -1,50 +1,55 @@
-#include "../../MyVersionInfo.rc"
-#include "../../GuiCommon.rc"
-#include "../../UI/GUI/ExtractDialogRes.h"
-#include "../../UI/FileManager/PropertyNameRes.h"
-
-#include "resource.h"
-
-MY_VERSION_INFO_APP("7z SFX", "7z.sfx")
-
-#define xc 240
-#define yc 64
-
-IDI_ICON ICON "7z.ico"
-
-IDD_EXTRACT DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
-CAPTION "7-Zip self-extracting archive"
-BEGIN
- LTEXT "E&xtract to:", IDT_EXTRACT_EXTRACT_TO, m, m, xc, 8
- EDITTEXT IDC_EXTRACT_PATH, m, 21, xc - bxsDots - 12, 14, ES_AUTOHSCROLL
- PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, 20, bxsDots, bys, WS_GROUP
- DEFPUSHBUTTON "Extract", IDOK, bx2, by, bxs, bys, WS_GROUP
- PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys
-END
-
-#ifdef UNDER_CE
-
-#undef xc
-#define xc 144
-
-IDD_EXTRACT_2 DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
-CAPTION "7-Zip self-extracting archive"
-BEGIN
- LTEXT "E&xtract to:", IDT_EXTRACT_EXTRACT_TO, m, m, xc - bxsDots - 12, 8
- EDITTEXT IDC_EXTRACT_PATH, m, m + bys + 4, xc, 14, ES_AUTOHSCROLL
- PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, m, bxsDots, bys, WS_GROUP
- DEFPUSHBUTTON "Extract", IDOK, bx2, by, bxs, bys, WS_GROUP
- PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys
-END
-
-#endif
-
-#include "../../UI/FileManager/OverwriteDialog.rc"
-#include "../../UI/FileManager/PasswordDialog.rc"
-#include "../../UI/FileManager/ProgressDialog2.rc"
-#include "../../UI/GUI/Extract.rc"
-
-STRINGTABLE DISCARDABLE
-BEGIN
- IDS_PROP_MTIME "Modified"
-END
+#include "../../MyVersionInfo.rc"
+#include "../../GuiCommon.rc"
+#include "../../UI/GUI/ExtractDialogRes.h"
+#include "../../UI/FileManager/PropertyNameRes.h"
+
+#include "resource.h"
+
+MY_VERSION_INFO_APP("7z SFX", "7z.sfx")
+
+#define xc 240
+#define yc 64
+
+IDI_ICON ICON "7z.ico"
+
+IDD_EXTRACT DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
+CAPTION "7-Zip self-extracting archive"
+BEGIN
+ LTEXT "E&xtract to:", IDT_EXTRACT_EXTRACT_TO, m, m, xc, 8
+ EDITTEXT IDC_EXTRACT_PATH, m, 21, xc - bxsDots - 12, 14, ES_AUTOHSCROLL
+ PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, 20, bxsDots, bys, WS_GROUP
+ DEFPUSHBUTTON "Extract", IDOK, bx2, by, bxs, bys, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys
+END
+
+#ifdef UNDER_CE
+
+#undef xc
+#define xc 144
+
+IDD_EXTRACT_2 DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
+CAPTION "7-Zip self-extracting archive"
+BEGIN
+ LTEXT "E&xtract to:", IDT_EXTRACT_EXTRACT_TO, m, m, xc - bxsDots - 12, 8
+ EDITTEXT IDC_EXTRACT_PATH, m, m + bys + 4, xc, 14, ES_AUTOHSCROLL
+ PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, m, bxsDots, bys, WS_GROUP
+ DEFPUSHBUTTON "Extract", IDOK, bx2, by, bxs, bys, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys
+END
+
+#endif
+
+#include "../../UI/FileManager/OverwriteDialog.rc"
+#include "../../UI/FileManager/PasswordDialog.rc"
+#include "../../UI/FileManager/ProgressDialog2.rc"
+#include "../../UI/GUI/Extract.rc"
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_PROP_MTIME "Modified"
+END
+
+
+#ifndef UNDER_CE
+1 24 MOVEABLE PURE "../../UI/GUI/7zG.exe.manifest"
+#endif
diff --git a/CPP/7zip/Bundles/makefile b/CPP/7zip/Bundles/makefile
new file mode 100644
index 0000000..0651da5
--- /dev/null
+++ b/CPP/7zip/Bundles/makefile
@@ -0,0 +1,19 @@
+DIRS = \
+ Alone\~ \
+ Alone2\~ \
+ Alone7z\~ \
+ Fm\~ \
+ Format7z\~ \
+ Format7zF\~ \
+ Format7zR\~ \
+ Format7zExtract\~ \
+ Format7zExtractR\~ \
+ LzmaCon\~ \
+ SFXCon\~ \
+ SFXSetup\~ \
+ SFXWin\~ \
+
+all: $(DIRS)
+
+$(DIRS):
+!include "../SubBuild.mak"
diff --git a/CPP/7zip/Common/CWrappers.cpp b/CPP/7zip/Common/CWrappers.cpp
index e726dad..346774e 100644
--- a/CPP/7zip/Common/CWrappers.cpp
+++ b/CPP/7zip/Common/CWrappers.cpp
@@ -1,250 +1,354 @@
-// CWrappers.h
-
-#include "StdAfx.h"
-
-#include "../../../C/Alloc.h"
-
-#include "CWrappers.h"
-
-#include "StreamUtils.h"
-
-SRes HRESULT_To_SRes(HRESULT res, SRes defaultRes) throw()
-{
- switch (res)
- {
- case S_OK: return SZ_OK;
- case E_OUTOFMEMORY: return SZ_ERROR_MEM;
- case E_INVALIDARG: return SZ_ERROR_PARAM;
- case E_ABORT: return SZ_ERROR_PROGRESS;
- case S_FALSE: return SZ_ERROR_DATA;
- case E_NOTIMPL: return SZ_ERROR_UNSUPPORTED;
- }
- return defaultRes;
-}
-
-
-HRESULT SResToHRESULT(SRes res) throw()
-{
- switch (res)
- {
- case SZ_OK: return S_OK;
-
- case SZ_ERROR_DATA:
- case SZ_ERROR_CRC:
- case SZ_ERROR_INPUT_EOF:
- return S_FALSE;
-
- case SZ_ERROR_MEM: return E_OUTOFMEMORY;
- case SZ_ERROR_PARAM: return E_INVALIDARG;
- case SZ_ERROR_PROGRESS: return E_ABORT;
- case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL;
- // case SZ_ERROR_OUTPUT_EOF:
- // case SZ_ERROR_READ:
- // case SZ_ERROR_WRITE:
- // case SZ_ERROR_THREAD:
- // case SZ_ERROR_ARCHIVE:
- // case SZ_ERROR_NO_ARCHIVE:
- // return E_FAIL;
- }
- if (res < 0)
- return res;
- return E_FAIL;
-}
-
-
-#define PROGRESS_UNKNOWN_VALUE ((UInt64)(Int64)-1)
-
-#define CONVERT_PR_VAL(x) (x == PROGRESS_UNKNOWN_VALUE ? NULL : &x)
-
-
-static SRes CompressProgress(const ICompressProgress *pp, UInt64 inSize, UInt64 outSize) throw()
-{
- CCompressProgressWrap *p = CONTAINER_FROM_VTBL(pp, CCompressProgressWrap, vt);
- p->Res = p->Progress->SetRatioInfo(CONVERT_PR_VAL(inSize), CONVERT_PR_VAL(outSize));
- return HRESULT_To_SRes(p->Res, SZ_ERROR_PROGRESS);
-}
-
-void CCompressProgressWrap::Init(ICompressProgressInfo *progress) throw()
-{
- vt.Progress = CompressProgress;
- Progress = progress;
- Res = SZ_OK;
-}
-
-static const UInt32 kStreamStepSize = (UInt32)1 << 31;
-
-static SRes MyRead(const ISeqInStream *pp, void *data, size_t *size) throw()
-{
- CSeqInStreamWrap *p = CONTAINER_FROM_VTBL(pp, CSeqInStreamWrap, vt);
- UInt32 curSize = ((*size < kStreamStepSize) ? (UInt32)*size : kStreamStepSize);
- p->Res = (p->Stream->Read(data, curSize, &curSize));
- *size = curSize;
- p->Processed += curSize;
- if (p->Res == S_OK)
- return SZ_OK;
- return HRESULT_To_SRes(p->Res, SZ_ERROR_READ);
-}
-
-static size_t MyWrite(const ISeqOutStream *pp, const void *data, size_t size) throw()
-{
- CSeqOutStreamWrap *p = CONTAINER_FROM_VTBL(pp, CSeqOutStreamWrap, vt);
- if (p->Stream)
- {
- p->Res = WriteStream(p->Stream, data, size);
- if (p->Res != 0)
- return 0;
- }
- else
- p->Res = S_OK;
- p->Processed += size;
- return size;
-}
-
-
-void CSeqInStreamWrap::Init(ISequentialInStream *stream) throw()
-{
- vt.Read = MyRead;
- Stream = stream;
- Processed = 0;
- Res = S_OK;
-}
-
-void CSeqOutStreamWrap::Init(ISequentialOutStream *stream) throw()
-{
- vt.Write = MyWrite;
- Stream = stream;
- Res = SZ_OK;
- Processed = 0;
-}
-
-
-static SRes InStreamWrap_Read(const ISeekInStream *pp, void *data, size_t *size) throw()
-{
- CSeekInStreamWrap *p = CONTAINER_FROM_VTBL(pp, CSeekInStreamWrap, vt);
- UInt32 curSize = ((*size < kStreamStepSize) ? (UInt32)*size : kStreamStepSize);
- p->Res = p->Stream->Read(data, curSize, &curSize);
- *size = curSize;
- return (p->Res == S_OK) ? SZ_OK : SZ_ERROR_READ;
-}
-
-static SRes InStreamWrap_Seek(const ISeekInStream *pp, Int64 *offset, ESzSeek origin) throw()
-{
- CSeekInStreamWrap *p = CONTAINER_FROM_VTBL(pp, CSeekInStreamWrap, vt);
- UInt32 moveMethod;
- switch (origin)
- {
- case SZ_SEEK_SET: moveMethod = STREAM_SEEK_SET; break;
- case SZ_SEEK_CUR: moveMethod = STREAM_SEEK_CUR; break;
- case SZ_SEEK_END: moveMethod = STREAM_SEEK_END; break;
- default: return SZ_ERROR_PARAM;
- }
- UInt64 newPosition;
- p->Res = p->Stream->Seek(*offset, moveMethod, &newPosition);
- *offset = (Int64)newPosition;
- return (p->Res == S_OK) ? SZ_OK : SZ_ERROR_READ;
-}
-
-void CSeekInStreamWrap::Init(IInStream *stream) throw()
-{
- Stream = stream;
- vt.Read = InStreamWrap_Read;
- vt.Seek = InStreamWrap_Seek;
- Res = S_OK;
-}
-
-
-/* ---------- CByteInBufWrap ---------- */
-
-void CByteInBufWrap::Free() throw()
-{
- ::MidFree(Buf);
- Buf = 0;
-}
-
-bool CByteInBufWrap::Alloc(UInt32 size) throw()
-{
- if (Buf == 0 || size != Size)
- {
- Free();
- Lim = Cur = Buf = (Byte *)::MidAlloc((size_t)size);
- Size = size;
- }
- return (Buf != 0);
-}
-
-Byte CByteInBufWrap::ReadByteFromNewBlock() throw()
-{
- if (Res == S_OK)
- {
- UInt32 avail;
- Processed += (Cur - Buf);
- Res = Stream->Read(Buf, Size, &avail);
- Cur = Buf;
- Lim = Buf + avail;
- if (avail != 0)
- return *Cur++;
- }
- Extra = true;
- return 0;
-}
-
-static Byte Wrap_ReadByte(const IByteIn *pp) throw()
-{
- CByteInBufWrap *p = CONTAINER_FROM_VTBL_CLS(pp, CByteInBufWrap, vt);
- if (p->Cur != p->Lim)
- return *p->Cur++;
- return p->ReadByteFromNewBlock();
-}
-
-CByteInBufWrap::CByteInBufWrap(): Buf(0)
-{
- vt.Read = Wrap_ReadByte;
-}
-
-
-/* ---------- CByteOutBufWrap ---------- */
-
-void CByteOutBufWrap::Free() throw()
-{
- ::MidFree(Buf);
- Buf = 0;
-}
-
-bool CByteOutBufWrap::Alloc(size_t size) throw()
-{
- if (Buf == 0 || size != Size)
- {
- Free();
- Buf = (Byte *)::MidAlloc(size);
- Size = size;
- }
- return (Buf != 0);
-}
-
-HRESULT CByteOutBufWrap::Flush() throw()
-{
- if (Res == S_OK)
- {
- size_t size = (Cur - Buf);
- Res = WriteStream(Stream, Buf, size);
- if (Res == S_OK)
- Processed += size;
- Cur = Buf;
- }
- return Res;
-}
-
-static void Wrap_WriteByte(const IByteOut *pp, Byte b) throw()
-{
- CByteOutBufWrap *p = CONTAINER_FROM_VTBL_CLS(pp, CByteOutBufWrap, vt);
- Byte *dest = p->Cur;
- *dest = b;
- p->Cur = ++dest;
- if (dest == p->Lim)
- p->Flush();
-}
-
-CByteOutBufWrap::CByteOutBufWrap() throw(): Buf(0)
-{
- vt.Write = Wrap_WriteByte;
-}
+// CWrappers.c
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "CWrappers.h"
+
+#include "StreamUtils.h"
+
+SRes HRESULT_To_SRes(HRESULT res, SRes defaultRes) throw()
+{
+ switch (res)
+ {
+ case S_OK: return SZ_OK;
+ case E_OUTOFMEMORY: return SZ_ERROR_MEM;
+ case E_INVALIDARG: return SZ_ERROR_PARAM;
+ case E_ABORT: return SZ_ERROR_PROGRESS;
+ case S_FALSE: return SZ_ERROR_DATA;
+ case E_NOTIMPL: return SZ_ERROR_UNSUPPORTED;
+ }
+ return defaultRes;
+}
+
+
+HRESULT SResToHRESULT(SRes res) throw()
+{
+ switch (res)
+ {
+ case SZ_OK: return S_OK;
+
+ case SZ_ERROR_DATA:
+ case SZ_ERROR_CRC:
+ case SZ_ERROR_INPUT_EOF:
+ return S_FALSE;
+
+ case SZ_ERROR_MEM: return E_OUTOFMEMORY;
+ case SZ_ERROR_PARAM: return E_INVALIDARG;
+ case SZ_ERROR_PROGRESS: return E_ABORT;
+ case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL;
+ // case SZ_ERROR_OUTPUT_EOF:
+ // case SZ_ERROR_READ:
+ // case SZ_ERROR_WRITE:
+ // case SZ_ERROR_THREAD:
+ // case SZ_ERROR_ARCHIVE:
+ // case SZ_ERROR_NO_ARCHIVE:
+ // return E_FAIL;
+ }
+ if (res < 0)
+ return res;
+ return E_FAIL;
+}
+
+
+#define PROGRESS_UNKNOWN_VALUE ((UInt64)(Int64)-1)
+
+#define CONVERT_PR_VAL(x) (x == PROGRESS_UNKNOWN_VALUE ? NULL : &x)
+
+
+static SRes CompressProgress(ICompressProgressPtr pp, UInt64 inSize, UInt64 outSize) throw()
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CCompressProgressWrap)
+ p->Res = p->Progress->SetRatioInfo(CONVERT_PR_VAL(inSize), CONVERT_PR_VAL(outSize));
+ return HRESULT_To_SRes(p->Res, SZ_ERROR_PROGRESS);
+}
+
+void CCompressProgressWrap::Init(ICompressProgressInfo *progress) throw()
+{
+ vt.Progress = CompressProgress;
+ Progress = progress;
+ Res = SZ_OK;
+}
+
+static const UInt32 kStreamStepSize = (UInt32)1 << 31;
+
+static SRes MyRead(ISeqInStreamPtr pp, void *data, size_t *size) throw()
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqInStreamWrap)
+ UInt32 curSize = ((*size < kStreamStepSize) ? (UInt32)*size : kStreamStepSize);
+ p->Res = (p->Stream->Read(data, curSize, &curSize));
+ *size = curSize;
+ p->Processed += curSize;
+ if (p->Res == S_OK)
+ return SZ_OK;
+ return HRESULT_To_SRes(p->Res, SZ_ERROR_READ);
+}
+
+static size_t MyWrite(ISeqOutStreamPtr pp, const void *data, size_t size) throw()
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeqOutStreamWrap)
+ if (p->Stream)
+ {
+ p->Res = WriteStream(p->Stream, data, size);
+ if (p->Res != 0)
+ return 0;
+ }
+ else
+ p->Res = S_OK;
+ p->Processed += size;
+ return size;
+}
+
+
+void CSeqInStreamWrap::Init(ISequentialInStream *stream) throw()
+{
+ vt.Read = MyRead;
+ Stream = stream;
+ Processed = 0;
+ Res = S_OK;
+}
+
+void CSeqOutStreamWrap::Init(ISequentialOutStream *stream) throw()
+{
+ vt.Write = MyWrite;
+ Stream = stream;
+ Res = SZ_OK;
+ Processed = 0;
+}
+
+
+static SRes InStreamWrap_Read(ISeekInStreamPtr pp, void *data, size_t *size) throw()
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeekInStreamWrap)
+ UInt32 curSize = ((*size < kStreamStepSize) ? (UInt32)*size : kStreamStepSize);
+ p->Res = p->Stream->Read(data, curSize, &curSize);
+ *size = curSize;
+ return (p->Res == S_OK) ? SZ_OK : SZ_ERROR_READ;
+}
+
+static SRes InStreamWrap_Seek(ISeekInStreamPtr pp, Int64 *offset, ESzSeek origin) throw()
+{
+ Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CSeekInStreamWrap)
+ UInt32 moveMethod;
+ /* we need (int)origin to eliminate the clang warning:
+ default label in switch which covers all enumeration values
+ [-Wcovered-switch-default */
+ switch ((int)origin)
+ {
+ case SZ_SEEK_SET: moveMethod = STREAM_SEEK_SET; break;
+ case SZ_SEEK_CUR: moveMethod = STREAM_SEEK_CUR; break;
+ case SZ_SEEK_END: moveMethod = STREAM_SEEK_END; break;
+ default: return SZ_ERROR_PARAM;
+ }
+ UInt64 newPosition;
+ p->Res = p->Stream->Seek(*offset, moveMethod, &newPosition);
+ *offset = (Int64)newPosition;
+ return (p->Res == S_OK) ? SZ_OK : SZ_ERROR_READ;
+}
+
+void CSeekInStreamWrap::Init(IInStream *stream) throw()
+{
+ Stream = stream;
+ vt.Read = InStreamWrap_Read;
+ vt.Seek = InStreamWrap_Seek;
+ Res = S_OK;
+}
+
+
+/* ---------- CByteInBufWrap ---------- */
+
+void CByteInBufWrap::Free() throw()
+{
+ ::MidFree(Buf);
+ Buf = NULL;
+}
+
+bool CByteInBufWrap::Alloc(UInt32 size) throw()
+{
+ if (!Buf || size != Size)
+ {
+ Free();
+ Lim = Cur = Buf = (Byte *)::MidAlloc((size_t)size);
+ Size = size;
+ }
+ return (Buf != NULL);
+}
+
+Byte CByteInBufWrap::ReadByteFromNewBlock() throw()
+{
+ if (!Extra && Res == S_OK)
+ {
+ UInt32 avail;
+ Res = Stream->Read(Buf, Size, &avail);
+ Processed += (size_t)(Cur - Buf);
+ Cur = Buf;
+ Lim = Buf + avail;
+ if (avail != 0)
+ return *Cur++;
+ }
+ Extra = true;
+ return 0;
+}
+
+// #pragma GCC diagnostic ignored "-Winvalid-offsetof"
+
+static Byte Wrap_ReadByte(IByteInPtr pp) throw()
+{
+ CByteInBufWrap *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CByteInBufWrap, vt);
+ // Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CByteInBufWrap)
+ if (p->Cur != p->Lim)
+ return *p->Cur++;
+ return p->ReadByteFromNewBlock();
+}
+
+CByteInBufWrap::CByteInBufWrap() throw(): Buf(NULL)
+{
+ vt.Read = Wrap_ReadByte;
+}
+
+
+
+/* ---------- CByteOutBufWrap ---------- */
+
+/*
+void CLookToSequentialWrap::Free() throw()
+{
+ ::MidFree(BufBase);
+ BufBase = NULL;
+}
+
+bool CLookToSequentialWrap::Alloc(UInt32 size) throw()
+{
+ if (!BufBase || size != Size)
+ {
+ Free();
+ BufBase = (Byte *)::MidAlloc((size_t)size);
+ Size = size;
+ }
+ return (BufBase != NULL);
+}
+*/
+
+/*
+EXTERN_C_BEGIN
+
+void CLookToSequentialWrap_Look(ILookInSeqStreamPtr pp)
+{
+ CLookToSequentialWrap *p = (CLookToSequentialWrap *)pp->Obj;
+
+ if (p->Extra || p->Res != S_OK)
+ return;
+ {
+ UInt32 avail;
+ p->Res = p->Stream->Read(p->BufBase, p->Size, &avail);
+ p->Processed += avail;
+ pp->Buf = p->BufBase;
+ pp->Limit = pp->Buf + avail;
+ if (avail == 0)
+ p->Extra = true;
+ }
+}
+
+EXTERN_C_END
+*/
+
+
+/* ---------- CByteOutBufWrap ---------- */
+
+void CByteOutBufWrap::Free() throw()
+{
+ ::MidFree(Buf);
+ Buf = NULL;
+}
+
+bool CByteOutBufWrap::Alloc(size_t size) throw()
+{
+ if (!Buf || size != Size)
+ {
+ Free();
+ Buf = (Byte *)::MidAlloc(size);
+ Size = size;
+ }
+ return (Buf != NULL);
+}
+
+HRESULT CByteOutBufWrap::Flush() throw()
+{
+ if (Res == S_OK)
+ {
+ const size_t size = (size_t)(Cur - Buf);
+ Res = WriteStream(Stream, Buf, size);
+ if (Res == S_OK)
+ Processed += size;
+ // else throw 11;
+ }
+ Cur = Buf; // reset pointer for later Wrap_WriteByte()
+ return Res;
+}
+
+static void Wrap_WriteByte(IByteOutPtr pp, Byte b) throw()
+{
+ CByteOutBufWrap *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CByteOutBufWrap, vt);
+ // Z7_CONTAINER_FROM_VTBL_TO_DECL_VAR_pp_vt_p(CByteOutBufWrap)
+ Byte *dest = p->Cur;
+ *dest = b;
+ p->Cur = ++dest;
+ if (dest == p->Lim)
+ p->Flush();
+}
+
+CByteOutBufWrap::CByteOutBufWrap() throw(): Buf(NULL), Size(0)
+{
+ vt.Write = Wrap_WriteByte;
+}
+
+
+/* ---------- CLookOutWrap ---------- */
+
+/*
+void CLookOutWrap::Free() throw()
+{
+ ::MidFree(Buf);
+ Buf = NULL;
+}
+
+bool CLookOutWrap::Alloc(size_t size) throw()
+{
+ if (!Buf || size != Size)
+ {
+ Free();
+ Buf = (Byte *)::MidAlloc(size);
+ Size = size;
+ }
+ return (Buf != NULL);
+}
+
+static size_t LookOutWrap_GetOutBuf(ILookOutStreamPtr pp, void **buf) throw()
+{
+ CLookOutWrap *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CLookOutWrap, vt);
+ *buf = p->Buf;
+ return p->Size;
+}
+
+static size_t LookOutWrap_Write(ILookOutStreamPtr pp, size_t size) throw()
+{
+ CLookOutWrap *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CLookOutWrap, vt);
+ if (p->Res == S_OK && size != 0)
+ {
+ p->Res = WriteStream(p->Stream, p->Buf, size);
+ if (p->Res == S_OK)
+ {
+ p->Processed += size;
+ return size;
+ }
+ }
+ return 0;
+}
+
+CLookOutWrap::CLookOutWrap() throw(): Buf(NULL), Size(0)
+{
+ vt.GetOutBuf = LookOutWrap_GetOutBuf;
+ vt.Write = LookOutWrap_Write;
+}
+*/
diff --git a/CPP/7zip/Common/CWrappers.h b/CPP/7zip/Common/CWrappers.h
index f93c98a..6c10a5c 100644
--- a/CPP/7zip/Common/CWrappers.h
+++ b/CPP/7zip/Common/CWrappers.h
@@ -1,120 +1,182 @@
-// CWrappers.h
-
-#ifndef __C_WRAPPERS_H
-#define __C_WRAPPERS_H
-
-#include "../ICoder.h"
-#include "../../Common/MyCom.h"
-
-SRes HRESULT_To_SRes(HRESULT res, SRes defaultRes) throw();
-HRESULT SResToHRESULT(SRes res) throw();
-
-struct CCompressProgressWrap
-{
- ICompressProgress vt;
- ICompressProgressInfo *Progress;
- HRESULT Res;
-
- void Init(ICompressProgressInfo *progress) throw();
-};
-
-
-struct CSeqInStreamWrap
-{
- ISeqInStream vt;
- ISequentialInStream *Stream;
- HRESULT Res;
- UInt64 Processed;
-
- void Init(ISequentialInStream *stream) throw();
-};
-
-
-struct CSeekInStreamWrap
-{
- ISeekInStream vt;
- IInStream *Stream;
- HRESULT Res;
-
- void Init(IInStream *stream) throw();
-};
-
-
-struct CSeqOutStreamWrap
-{
- ISeqOutStream vt;
- ISequentialOutStream *Stream;
- HRESULT Res;
- UInt64 Processed;
-
- void Init(ISequentialOutStream *stream) throw();
-};
-
-
-struct CByteInBufWrap
-{
- IByteIn vt;
- const Byte *Cur;
- const Byte *Lim;
- Byte *Buf;
- UInt32 Size;
- ISequentialInStream *Stream;
- UInt64 Processed;
- bool Extra;
- HRESULT Res;
-
- CByteInBufWrap();
- ~CByteInBufWrap() { Free(); }
- void Free() throw();
- bool Alloc(UInt32 size) throw();
- void Init()
- {
- Lim = Cur = Buf;
- Processed = 0;
- Extra = false;
- Res = S_OK;
- }
- UInt64 GetProcessed() const { return Processed + (Cur - Buf); }
- Byte ReadByteFromNewBlock() throw();
- Byte ReadByte()
- {
- if (Cur != Lim)
- return *Cur++;
- return ReadByteFromNewBlock();
- }
-};
-
-
-struct CByteOutBufWrap
-{
- IByteOut vt;
- Byte *Cur;
- const Byte *Lim;
- Byte *Buf;
- size_t Size;
- ISequentialOutStream *Stream;
- UInt64 Processed;
- HRESULT Res;
-
- CByteOutBufWrap() throw();
- ~CByteOutBufWrap() { Free(); }
- void Free() throw();
- bool Alloc(size_t size) throw();
- void Init()
- {
- Cur = Buf;
- Lim = Buf + Size;
- Processed = 0;
- Res = S_OK;
- }
- UInt64 GetProcessed() const { return Processed + (Cur - Buf); }
- HRESULT Flush() throw();
- void WriteByte(Byte b)
- {
- *Cur++ = b;
- if (Cur == Lim)
- Flush();
- }
-};
-
-#endif
+// CWrappers.h
+
+#ifndef ZIP7_INC_C_WRAPPERS_H
+#define ZIP7_INC_C_WRAPPERS_H
+
+#include "../ICoder.h"
+#include "../../Common/MyCom.h"
+
+SRes HRESULT_To_SRes(HRESULT res, SRes defaultRes) throw();
+HRESULT SResToHRESULT(SRes res) throw();
+
+struct CCompressProgressWrap
+{
+ ICompressProgress vt;
+ ICompressProgressInfo *Progress;
+ HRESULT Res;
+
+ void Init(ICompressProgressInfo *progress) throw();
+};
+
+
+struct CSeqInStreamWrap
+{
+ ISeqInStream vt;
+ ISequentialInStream *Stream;
+ HRESULT Res;
+ UInt64 Processed;
+
+ void Init(ISequentialInStream *stream) throw();
+};
+
+
+struct CSeekInStreamWrap
+{
+ ISeekInStream vt;
+ IInStream *Stream;
+ HRESULT Res;
+
+ void Init(IInStream *stream) throw();
+};
+
+
+struct CSeqOutStreamWrap
+{
+ ISeqOutStream vt;
+ ISequentialOutStream *Stream;
+ HRESULT Res;
+ UInt64 Processed;
+
+ void Init(ISequentialOutStream *stream) throw();
+};
+
+
+struct CByteInBufWrap
+{
+ IByteIn vt;
+ const Byte *Cur;
+ const Byte *Lim;
+ Byte *Buf;
+ UInt32 Size;
+ ISequentialInStream *Stream;
+ UInt64 Processed;
+ bool Extra;
+ HRESULT Res;
+
+ CByteInBufWrap() throw();
+ ~CByteInBufWrap() { Free(); }
+ void Free() throw();
+ bool Alloc(UInt32 size) throw();
+ void Init()
+ {
+ Lim = Cur = Buf;
+ Processed = 0;
+ Extra = false;
+ Res = S_OK;
+ }
+ UInt64 GetProcessed() const { return Processed + (size_t)(Cur - Buf); }
+ Byte ReadByteFromNewBlock() throw();
+ Byte ReadByte()
+ {
+ if (Cur != Lim)
+ return *Cur++;
+ return ReadByteFromNewBlock();
+ }
+};
+
+
+/*
+struct CLookToSequentialWrap
+{
+ Byte *BufBase;
+ UInt32 Size;
+ ISequentialInStream *Stream;
+ UInt64 Processed;
+ bool Extra;
+ HRESULT Res;
+
+ CLookToSequentialWrap(): BufBase(NULL) {}
+ ~CLookToSequentialWrap() { Free(); }
+ void Free() throw();
+ bool Alloc(UInt32 size) throw();
+ void Init()
+ {
+ // Lim = Cur = Buf;
+ Processed = 0;
+ Extra = false;
+ Res = S_OK;
+ }
+ // UInt64 GetProcessed() const { return Processed + (Cur - Buf); }
+
+ Byte ReadByteFromNewBlock() throw();
+ Byte ReadByte()
+ {
+ if (Cur != Lim)
+ return *Cur++;
+ return ReadByteFromNewBlock();
+ }
+};
+
+EXTERN_C_BEGIN
+// void CLookToSequentialWrap_Look(ILookInSeqStream *pp);
+EXTERN_C_END
+*/
+
+
+
+struct CByteOutBufWrap
+{
+ IByteOut vt;
+ Byte *Cur;
+ const Byte *Lim;
+ Byte *Buf;
+ size_t Size;
+ ISequentialOutStream *Stream;
+ UInt64 Processed;
+ HRESULT Res;
+
+ CByteOutBufWrap() throw();
+ ~CByteOutBufWrap() { Free(); }
+ void Free() throw();
+ bool Alloc(size_t size) throw();
+ void Init()
+ {
+ Cur = Buf;
+ Lim = Buf + Size;
+ Processed = 0;
+ Res = S_OK;
+ }
+ UInt64 GetProcessed() const { return Processed + (size_t)(Cur - Buf); }
+ HRESULT Flush() throw();
+ void WriteByte(Byte b)
+ {
+ *Cur++ = b;
+ if (Cur == Lim)
+ Flush();
+ }
+};
+
+
+/*
+struct CLookOutWrap
+{
+ ILookOutStream vt;
+ Byte *Buf;
+ size_t Size;
+ ISequentialOutStream *Stream;
+ UInt64 Processed;
+ HRESULT Res;
+
+ CLookOutWrap() throw();
+ ~CLookOutWrap() { Free(); }
+ void Free() throw();
+ bool Alloc(size_t size) throw();
+ void Init()
+ {
+ Processed = 0;
+ Res = S_OK;
+ }
+};
+*/
+
+#endif
diff --git a/CPP/7zip/Common/CreateCoder.cpp b/CPP/7zip/Common/CreateCoder.cpp
index 5040765..bf7b04e 100644
--- a/CPP/7zip/Common/CreateCoder.cpp
+++ b/CPP/7zip/Common/CreateCoder.cpp
@@ -1,536 +1,548 @@
-// CreateCoder.cpp
-
-#include "StdAfx.h"
-
-#include "../../Windows/Defs.h"
-#include "../../Windows/PropVariant.h"
-
-#include "CreateCoder.h"
-
-#include "FilterCoder.h"
-#include "RegisterCodec.h"
-
-static const unsigned kNumCodecsMax = 64;
-unsigned g_NumCodecs = 0;
-const CCodecInfo *g_Codecs[kNumCodecsMax];
-
-// We use g_ExternalCodecs in other stages.
-/*
-#ifdef EXTERNAL_CODECS
-extern CExternalCodecs g_ExternalCodecs;
-#define CHECK_GLOBAL_CODECS \
- if (!__externalCodecs || !__externalCodecs->IsSet()) __externalCodecs = &g_ExternalCodecs;
-#endif
-*/
-
-#define CHECK_GLOBAL_CODECS
-
-void RegisterCodec(const CCodecInfo *codecInfo) throw()
-{
- if (g_NumCodecs < kNumCodecsMax)
- g_Codecs[g_NumCodecs++] = codecInfo;
-}
-
-static const unsigned kNumHashersMax = 16;
-unsigned g_NumHashers = 0;
-const CHasherInfo *g_Hashers[kNumHashersMax];
-
-void RegisterHasher(const CHasherInfo *hashInfo) throw()
-{
- if (g_NumHashers < kNumHashersMax)
- g_Hashers[g_NumHashers++] = hashInfo;
-}
-
-
-#ifdef EXTERNAL_CODECS
-
-static HRESULT ReadNumberOfStreams(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, UInt32 &res)
-{
- NWindows::NCOM::CPropVariant prop;
- RINOK(codecsInfo->GetProperty(index, propID, &prop));
- if (prop.vt == VT_EMPTY)
- res = 1;
- else if (prop.vt == VT_UI4)
- res = prop.ulVal;
- else
- return E_INVALIDARG;
- return S_OK;
-}
-
-static HRESULT ReadIsAssignedProp(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, bool &res)
-{
- NWindows::NCOM::CPropVariant prop;
- RINOK(codecsInfo->GetProperty(index, propID, &prop));
- if (prop.vt == VT_EMPTY)
- res = true;
- else if (prop.vt == VT_BOOL)
- res = VARIANT_BOOLToBool(prop.boolVal);
- else
- return E_INVALIDARG;
- return S_OK;
-}
-
-HRESULT CExternalCodecs::Load()
-{
- Codecs.Clear();
- Hashers.Clear();
-
- if (GetCodecs)
- {
- CCodecInfoEx info;
-
- UString s;
- UInt32 num;
- RINOK(GetCodecs->GetNumMethods(&num));
-
- for (UInt32 i = 0; i < num; i++)
- {
- NWindows::NCOM::CPropVariant prop;
-
- RINOK(GetCodecs->GetProperty(i, NMethodPropID::kID, &prop));
- if (prop.vt != VT_UI8)
- continue; // old Interface
- info.Id = prop.uhVal.QuadPart;
-
- prop.Clear();
-
- info.Name.Empty();
- RINOK(GetCodecs->GetProperty(i, NMethodPropID::kName, &prop));
- if (prop.vt == VT_BSTR)
- info.Name.SetFromWStr_if_Ascii(prop.bstrVal);
- else if (prop.vt != VT_EMPTY)
- continue;
-
- RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kPackStreams, info.NumStreams));
- {
- UInt32 numUnpackStreams = 1;
- RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kUnpackStreams, numUnpackStreams));
- if (numUnpackStreams != 1)
- continue;
- }
- RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kEncoderIsAssigned, info.EncoderIsAssigned));
- RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kDecoderIsAssigned, info.DecoderIsAssigned));
-
- Codecs.Add(info);
- }
- }
-
- if (GetHashers)
- {
- UInt32 num = GetHashers->GetNumHashers();
- CHasherInfoEx info;
-
- for (UInt32 i = 0; i < num; i++)
- {
- NWindows::NCOM::CPropVariant prop;
-
- RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kID, &prop));
- if (prop.vt != VT_UI8)
- continue;
- info.Id = prop.uhVal.QuadPart;
-
- prop.Clear();
-
- info.Name.Empty();
- RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kName, &prop));
- if (prop.vt == VT_BSTR)
- info.Name.SetFromWStr_if_Ascii(prop.bstrVal);
- else if (prop.vt != VT_EMPTY)
- continue;
-
- Hashers.Add(info);
- }
- }
-
- return S_OK;
-}
-
-#endif
-
-
-int FindMethod_Index(
- DECL_EXTERNAL_CODECS_LOC_VARS
- const AString &name,
- bool encode,
- CMethodId &methodId,
- UInt32 &numStreams)
-{
- unsigned i;
- for (i = 0; i < g_NumCodecs; i++)
- {
- const CCodecInfo &codec = *g_Codecs[i];
- if ((encode ? codec.CreateEncoder : codec.CreateDecoder)
- && StringsAreEqualNoCase_Ascii(name, codec.Name))
- {
- methodId = codec.Id;
- numStreams = codec.NumStreams;
- return i;
- }
- }
-
- #ifdef EXTERNAL_CODECS
-
- CHECK_GLOBAL_CODECS
-
- if (__externalCodecs)
- for (i = 0; i < __externalCodecs->Codecs.Size(); i++)
- {
- const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
- if ((encode ? codec.EncoderIsAssigned : codec.DecoderIsAssigned)
- && StringsAreEqualNoCase_Ascii(name, codec.Name))
- {
- methodId = codec.Id;
- numStreams = codec.NumStreams;
- return g_NumCodecs + i;
- }
- }
-
- #endif
-
- return -1;
-}
-
-
-static int FindMethod_Index(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CMethodId methodId, bool encode)
-{
- unsigned i;
- for (i = 0; i < g_NumCodecs; i++)
- {
- const CCodecInfo &codec = *g_Codecs[i];
- if (codec.Id == methodId && (encode ? codec.CreateEncoder : codec.CreateDecoder))
- return i;
- }
-
- #ifdef EXTERNAL_CODECS
-
- CHECK_GLOBAL_CODECS
-
- if (__externalCodecs)
- for (i = 0; i < __externalCodecs->Codecs.Size(); i++)
- {
- const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
- if (codec.Id == methodId && (encode ? codec.EncoderIsAssigned : codec.DecoderIsAssigned))
- return g_NumCodecs + i;
- }
-
- #endif
-
- return -1;
-}
-
-
-bool FindMethod(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CMethodId methodId,
- AString &name)
-{
- name.Empty();
-
- unsigned i;
- for (i = 0; i < g_NumCodecs; i++)
- {
- const CCodecInfo &codec = *g_Codecs[i];
- if (methodId == codec.Id)
- {
- name = codec.Name;
- return true;
- }
- }
-
- #ifdef EXTERNAL_CODECS
-
- CHECK_GLOBAL_CODECS
-
- if (__externalCodecs)
- for (i = 0; i < __externalCodecs->Codecs.Size(); i++)
- {
- const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
- if (methodId == codec.Id)
- {
- name = codec.Name;
- return true;
- }
- }
-
- #endif
-
- return false;
-}
-
-bool FindHashMethod(
- DECL_EXTERNAL_CODECS_LOC_VARS
- const AString &name,
- CMethodId &methodId)
-{
- unsigned i;
- for (i = 0; i < g_NumHashers; i++)
- {
- const CHasherInfo &codec = *g_Hashers[i];
- if (StringsAreEqualNoCase_Ascii(name, codec.Name))
- {
- methodId = codec.Id;
- return true;
- }
- }
-
- #ifdef EXTERNAL_CODECS
-
- CHECK_GLOBAL_CODECS
-
- if (__externalCodecs)
- for (i = 0; i < __externalCodecs->Hashers.Size(); i++)
- {
- const CHasherInfoEx &codec = __externalCodecs->Hashers[i];
- if (StringsAreEqualNoCase_Ascii(name, codec.Name))
- {
- methodId = codec.Id;
- return true;
- }
- }
-
- #endif
-
- return false;
-}
-
-void GetHashMethods(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CRecordVector<CMethodId> &methods)
-{
- methods.ClearAndSetSize(g_NumHashers);
- unsigned i;
- for (i = 0; i < g_NumHashers; i++)
- methods[i] = (*g_Hashers[i]).Id;
-
- #ifdef EXTERNAL_CODECS
-
- CHECK_GLOBAL_CODECS
-
- if (__externalCodecs)
- for (i = 0; i < __externalCodecs->Hashers.Size(); i++)
- methods.Add(__externalCodecs->Hashers[i].Id);
-
- #endif
-}
-
-
-
-HRESULT CreateCoder_Index(
- DECL_EXTERNAL_CODECS_LOC_VARS
- unsigned i, bool encode,
- CMyComPtr<ICompressFilter> &filter,
- CCreatedCoder &cod)
-{
- cod.IsExternal = false;
- cod.IsFilter = false;
- cod.NumStreams = 1;
-
- if (i < g_NumCodecs)
- {
- const CCodecInfo &codec = *g_Codecs[i];
- // if (codec.Id == methodId)
- {
- if (encode)
- {
- if (codec.CreateEncoder)
- {
- void *p = codec.CreateEncoder();
- if (codec.IsFilter) filter = (ICompressFilter *)p;
- else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p;
- else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; }
- return S_OK;
- }
- }
- else
- if (codec.CreateDecoder)
- {
- void *p = codec.CreateDecoder();
- if (codec.IsFilter) filter = (ICompressFilter *)p;
- else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p;
- else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; }
- return S_OK;
- }
- }
- }
-
- #ifdef EXTERNAL_CODECS
-
- CHECK_GLOBAL_CODECS
-
- if (__externalCodecs)
- {
- i -= g_NumCodecs;
- cod.IsExternal = true;
- if (i < __externalCodecs->Codecs.Size())
- {
- const CCodecInfoEx &codec = __externalCodecs->Codecs[i];
- // if (codec.Id == methodId)
- {
- if (encode)
- {
- if (codec.EncoderIsAssigned)
- {
- if (codec.NumStreams == 1)
- {
- HRESULT res = __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder, (void **)&cod.Coder);
- if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE)
- return res;
- if (cod.Coder)
- return res;
- return __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter);
- }
- cod.NumStreams = codec.NumStreams;
- return __externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2);
- }
- }
- else
- if (codec.DecoderIsAssigned)
- {
- if (codec.NumStreams == 1)
- {
- HRESULT res = __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder, (void **)&cod.Coder);
- if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE)
- return res;
- if (cod.Coder)
- return res;
- return __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter);
- }
- cod.NumStreams = codec.NumStreams;
- return __externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2);
- }
- }
- }
- }
- #endif
-
- return S_OK;
-}
-
-
-HRESULT CreateCoder_Index(
- DECL_EXTERNAL_CODECS_LOC_VARS
- unsigned index, bool encode,
- CCreatedCoder &cod)
-{
- CMyComPtr<ICompressFilter> filter;
- HRESULT res = CreateCoder_Index(
- EXTERNAL_CODECS_LOC_VARS
- index, encode,
- filter, cod);
-
- if (filter)
- {
- cod.IsFilter = true;
- CFilterCoder *coderSpec = new CFilterCoder(encode);
- cod.Coder = coderSpec;
- coderSpec->Filter = filter;
- }
-
- return res;
-}
-
-
-HRESULT CreateCoder_Id(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CMethodId methodId, bool encode,
- CMyComPtr<ICompressFilter> &filter,
- CCreatedCoder &cod)
-{
- int index = FindMethod_Index(EXTERNAL_CODECS_LOC_VARS methodId, encode);
- if (index < 0)
- return S_OK;
- return CreateCoder_Index(EXTERNAL_CODECS_LOC_VARS index, encode, filter, cod);
-}
-
-
-HRESULT CreateCoder_Id(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CMethodId methodId, bool encode,
- CCreatedCoder &cod)
-{
- CMyComPtr<ICompressFilter> filter;
- HRESULT res = CreateCoder_Id(
- EXTERNAL_CODECS_LOC_VARS
- methodId, encode,
- filter, cod);
-
- if (filter)
- {
- cod.IsFilter = true;
- CFilterCoder *coderSpec = new CFilterCoder(encode);
- cod.Coder = coderSpec;
- coderSpec->Filter = filter;
- }
-
- return res;
-}
-
-
-HRESULT CreateCoder_Id(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CMethodId methodId, bool encode,
- CMyComPtr<ICompressCoder> &coder)
-{
- CCreatedCoder cod;
- HRESULT res = CreateCoder_Id(
- EXTERNAL_CODECS_LOC_VARS
- methodId, encode,
- cod);
- coder = cod.Coder;
- return res;
-}
-
-HRESULT CreateFilter(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CMethodId methodId, bool encode,
- CMyComPtr<ICompressFilter> &filter)
-{
- CCreatedCoder cod;
- return CreateCoder_Id(
- EXTERNAL_CODECS_LOC_VARS
- methodId, encode,
- filter, cod);
-}
-
-
-HRESULT CreateHasher(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CMethodId methodId,
- AString &name,
- CMyComPtr<IHasher> &hasher)
-{
- name.Empty();
-
- unsigned i;
- for (i = 0; i < g_NumHashers; i++)
- {
- const CHasherInfo &codec = *g_Hashers[i];
- if (codec.Id == methodId)
- {
- hasher = codec.CreateHasher();
- name = codec.Name;
- break;
- }
- }
-
- #ifdef EXTERNAL_CODECS
-
- CHECK_GLOBAL_CODECS
-
- if (!hasher && __externalCodecs)
- for (i = 0; i < __externalCodecs->Hashers.Size(); i++)
- {
- const CHasherInfoEx &codec = __externalCodecs->Hashers[i];
- if (codec.Id == methodId)
- {
- name = codec.Name;
- return __externalCodecs->GetHashers->CreateHasher((UInt32)i, &hasher);
- }
- }
-
- #endif
-
- return S_OK;
-}
+// CreateCoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../Windows/Defs.h"
+#include "../../Windows/PropVariant.h"
+
+#include "CreateCoder.h"
+
+#include "FilterCoder.h"
+#include "RegisterCodec.h"
+
+static const unsigned kNumCodecsMax = 64;
+extern
+unsigned g_NumCodecs;
+unsigned g_NumCodecs = 0;
+extern
+const CCodecInfo *g_Codecs[];
+const CCodecInfo *g_Codecs[kNumCodecsMax];
+
+// We use g_ExternalCodecs in other stages.
+#ifdef Z7_EXTERNAL_CODECS
+/*
+extern CExternalCodecs g_ExternalCodecs;
+#define CHECK_GLOBAL_CODECS \
+ if (!_externalCodecs || !_externalCodecs->IsSet()) _externalCodecs = &g_ExternalCodecs;
+*/
+#define CHECK_GLOBAL_CODECS
+#endif
+
+
+void RegisterCodec(const CCodecInfo *codecInfo) throw()
+{
+ if (g_NumCodecs < kNumCodecsMax)
+ g_Codecs[g_NumCodecs++] = codecInfo;
+}
+
+static const unsigned kNumHashersMax = 16;
+extern
+unsigned g_NumHashers;
+unsigned g_NumHashers = 0;
+extern
+const CHasherInfo *g_Hashers[];
+const CHasherInfo *g_Hashers[kNumHashersMax];
+
+void RegisterHasher(const CHasherInfo *hashInfo) throw()
+{
+ if (g_NumHashers < kNumHashersMax)
+ g_Hashers[g_NumHashers++] = hashInfo;
+}
+
+
+#ifdef Z7_EXTERNAL_CODECS
+
+static HRESULT ReadNumberOfStreams(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, UInt32 &res)
+{
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(codecsInfo->GetProperty(index, propID, &prop))
+ if (prop.vt == VT_EMPTY)
+ res = 1;
+ else if (prop.vt == VT_UI4)
+ res = prop.ulVal;
+ else
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+static HRESULT ReadIsAssignedProp(ICompressCodecsInfo *codecsInfo, UInt32 index, PROPID propID, bool &res)
+{
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(codecsInfo->GetProperty(index, propID, &prop))
+ if (prop.vt == VT_EMPTY)
+ res = true;
+ else if (prop.vt == VT_BOOL)
+ res = VARIANT_BOOLToBool(prop.boolVal);
+ else
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+HRESULT CExternalCodecs::Load()
+{
+ Codecs.Clear();
+ Hashers.Clear();
+
+ if (GetCodecs)
+ {
+ CCodecInfoEx info;
+
+ UString s;
+ UInt32 num;
+ RINOK(GetCodecs->GetNumMethods(&num))
+
+ for (UInt32 i = 0; i < num; i++)
+ {
+ NWindows::NCOM::CPropVariant prop;
+
+ RINOK(GetCodecs->GetProperty(i, NMethodPropID::kID, &prop))
+ if (prop.vt != VT_UI8)
+ continue; // old Interface
+ info.Id = prop.uhVal.QuadPart;
+
+ prop.Clear();
+
+ info.Name.Empty();
+ RINOK(GetCodecs->GetProperty(i, NMethodPropID::kName, &prop))
+ if (prop.vt == VT_BSTR)
+ info.Name.SetFromWStr_if_Ascii(prop.bstrVal);
+ else if (prop.vt != VT_EMPTY)
+ continue;
+
+ RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kPackStreams, info.NumStreams))
+ {
+ UInt32 numUnpackStreams = 1;
+ RINOK(ReadNumberOfStreams(GetCodecs, i, NMethodPropID::kUnpackStreams, numUnpackStreams))
+ if (numUnpackStreams != 1)
+ continue;
+ }
+ RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kEncoderIsAssigned, info.EncoderIsAssigned))
+ RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kDecoderIsAssigned, info.DecoderIsAssigned))
+ RINOK(ReadIsAssignedProp(GetCodecs, i, NMethodPropID::kIsFilter, info.IsFilter))
+
+ Codecs.Add(info);
+ }
+ }
+
+ if (GetHashers)
+ {
+ UInt32 num = GetHashers->GetNumHashers();
+ CHasherInfoEx info;
+
+ for (UInt32 i = 0; i < num; i++)
+ {
+ NWindows::NCOM::CPropVariant prop;
+
+ RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kID, &prop))
+ if (prop.vt != VT_UI8)
+ continue;
+ info.Id = prop.uhVal.QuadPart;
+
+ prop.Clear();
+
+ info.Name.Empty();
+ RINOK(GetHashers->GetHasherProp(i, NMethodPropID::kName, &prop))
+ if (prop.vt == VT_BSTR)
+ info.Name.SetFromWStr_if_Ascii(prop.bstrVal);
+ else if (prop.vt != VT_EMPTY)
+ continue;
+
+ Hashers.Add(info);
+ }
+ }
+
+ return S_OK;
+}
+
+#endif
+
+
+int FindMethod_Index(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const AString &name,
+ bool encode,
+ CMethodId &methodId,
+ UInt32 &numStreams,
+ bool &isFilter)
+{
+ unsigned i;
+ for (i = 0; i < g_NumCodecs; i++)
+ {
+ const CCodecInfo &codec = *g_Codecs[i];
+ if ((encode ? codec.CreateEncoder : codec.CreateDecoder)
+ && StringsAreEqualNoCase_Ascii(name, codec.Name))
+ {
+ methodId = codec.Id;
+ numStreams = codec.NumStreams;
+ isFilter = codec.IsFilter;
+ return (int)i;
+ }
+ }
+
+ #ifdef Z7_EXTERNAL_CODECS
+
+ CHECK_GLOBAL_CODECS
+
+ if (_externalCodecs)
+ for (i = 0; i < _externalCodecs->Codecs.Size(); i++)
+ {
+ const CCodecInfoEx &codec = _externalCodecs->Codecs[i];
+ if ((encode ? codec.EncoderIsAssigned : codec.DecoderIsAssigned)
+ && StringsAreEqualNoCase_Ascii(name, codec.Name))
+ {
+ methodId = codec.Id;
+ numStreams = codec.NumStreams;
+ isFilter = codec.IsFilter;
+ return (int)(g_NumCodecs + i);
+ }
+ }
+
+ #endif
+
+ return -1;
+}
+
+
+static int FindMethod_Index(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId, bool encode)
+{
+ unsigned i;
+ for (i = 0; i < g_NumCodecs; i++)
+ {
+ const CCodecInfo &codec = *g_Codecs[i];
+ if (codec.Id == methodId && (encode ? codec.CreateEncoder : codec.CreateDecoder))
+ return (int)i;
+ }
+
+ #ifdef Z7_EXTERNAL_CODECS
+
+ CHECK_GLOBAL_CODECS
+
+ if (_externalCodecs)
+ for (i = 0; i < _externalCodecs->Codecs.Size(); i++)
+ {
+ const CCodecInfoEx &codec = _externalCodecs->Codecs[i];
+ if (codec.Id == methodId && (encode ? codec.EncoderIsAssigned : codec.DecoderIsAssigned))
+ return (int)(g_NumCodecs + i);
+ }
+
+ #endif
+
+ return -1;
+}
+
+
+bool FindMethod(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ AString &name)
+{
+ name.Empty();
+
+ unsigned i;
+ for (i = 0; i < g_NumCodecs; i++)
+ {
+ const CCodecInfo &codec = *g_Codecs[i];
+ if (methodId == codec.Id)
+ {
+ name = codec.Name;
+ return true;
+ }
+ }
+
+ #ifdef Z7_EXTERNAL_CODECS
+
+ CHECK_GLOBAL_CODECS
+
+ if (_externalCodecs)
+ for (i = 0; i < _externalCodecs->Codecs.Size(); i++)
+ {
+ const CCodecInfoEx &codec = _externalCodecs->Codecs[i];
+ if (methodId == codec.Id)
+ {
+ name = codec.Name;
+ return true;
+ }
+ }
+
+ #endif
+
+ return false;
+}
+
+bool FindHashMethod(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const AString &name,
+ CMethodId &methodId)
+{
+ unsigned i;
+ for (i = 0; i < g_NumHashers; i++)
+ {
+ const CHasherInfo &codec = *g_Hashers[i];
+ if (StringsAreEqualNoCase_Ascii(name, codec.Name))
+ {
+ methodId = codec.Id;
+ return true;
+ }
+ }
+
+ #ifdef Z7_EXTERNAL_CODECS
+
+ CHECK_GLOBAL_CODECS
+
+ if (_externalCodecs)
+ for (i = 0; i < _externalCodecs->Hashers.Size(); i++)
+ {
+ const CHasherInfoEx &codec = _externalCodecs->Hashers[i];
+ if (StringsAreEqualNoCase_Ascii(name, codec.Name))
+ {
+ methodId = codec.Id;
+ return true;
+ }
+ }
+
+ #endif
+
+ return false;
+}
+
+void GetHashMethods(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CRecordVector<CMethodId> &methods)
+{
+ methods.ClearAndSetSize(g_NumHashers);
+ unsigned i;
+ for (i = 0; i < g_NumHashers; i++)
+ methods[i] = (*g_Hashers[i]).Id;
+
+ #ifdef Z7_EXTERNAL_CODECS
+
+ CHECK_GLOBAL_CODECS
+
+ if (_externalCodecs)
+ for (i = 0; i < _externalCodecs->Hashers.Size(); i++)
+ methods.Add(_externalCodecs->Hashers[i].Id);
+
+ #endif
+}
+
+
+
+HRESULT CreateCoder_Index(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ unsigned i, bool encode,
+ CMyComPtr<ICompressFilter> &filter,
+ CCreatedCoder &cod)
+{
+ cod.IsExternal = false;
+ cod.IsFilter = false;
+ cod.NumStreams = 1;
+
+ if (i < g_NumCodecs)
+ {
+ const CCodecInfo &codec = *g_Codecs[i];
+ // if (codec.Id == methodId)
+ {
+ if (encode)
+ {
+ if (codec.CreateEncoder)
+ {
+ void *p = codec.CreateEncoder();
+ if (codec.IsFilter) filter = (ICompressFilter *)p;
+ else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p;
+ else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; }
+ return S_OK;
+ }
+ }
+ else
+ if (codec.CreateDecoder)
+ {
+ void *p = codec.CreateDecoder();
+ if (codec.IsFilter) filter = (ICompressFilter *)p;
+ else if (codec.NumStreams == 1) cod.Coder = (ICompressCoder *)p;
+ else { cod.Coder2 = (ICompressCoder2 *)p; cod.NumStreams = codec.NumStreams; }
+ return S_OK;
+ }
+ }
+ }
+
+ #ifdef Z7_EXTERNAL_CODECS
+
+ CHECK_GLOBAL_CODECS
+
+ if (_externalCodecs)
+ {
+ i -= g_NumCodecs;
+ cod.IsExternal = true;
+ if (i < _externalCodecs->Codecs.Size())
+ {
+ const CCodecInfoEx &codec = _externalCodecs->Codecs[i];
+ // if (codec.Id == methodId)
+ {
+ if (encode)
+ {
+ if (codec.EncoderIsAssigned)
+ {
+ if (codec.NumStreams == 1)
+ {
+ const HRESULT res = _externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder, (void **)&cod.Coder);
+ if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE)
+ return res;
+ if (cod.Coder)
+ return res;
+ return _externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressFilter, (void **)&filter);
+ }
+ cod.NumStreams = codec.NumStreams;
+ return _externalCodecs->GetCodecs->CreateEncoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2);
+ }
+ }
+ else
+ if (codec.DecoderIsAssigned)
+ {
+ if (codec.NumStreams == 1)
+ {
+ const HRESULT res = _externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder, (void **)&cod.Coder);
+ if (res != S_OK && res != E_NOINTERFACE && res != CLASS_E_CLASSNOTAVAILABLE)
+ return res;
+ if (cod.Coder)
+ return res;
+ return _externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressFilter, (void **)&filter);
+ }
+ cod.NumStreams = codec.NumStreams;
+ return _externalCodecs->GetCodecs->CreateDecoder(i, &IID_ICompressCoder2, (void **)&cod.Coder2);
+ }
+ }
+ }
+ }
+ #endif
+
+ return S_OK;
+}
+
+
+HRESULT CreateCoder_Index(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ unsigned index, bool encode,
+ CCreatedCoder &cod)
+{
+ CMyComPtr<ICompressFilter> filter;
+ const HRESULT res = CreateCoder_Index(
+ EXTERNAL_CODECS_LOC_VARS
+ index, encode,
+ filter, cod);
+
+ if (filter)
+ {
+ cod.IsFilter = true;
+ CFilterCoder *coderSpec = new CFilterCoder(encode);
+ cod.Coder = coderSpec;
+ coderSpec->Filter = filter;
+ }
+
+ return res;
+}
+
+
+HRESULT CreateCoder_Id(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId, bool encode,
+ CMyComPtr<ICompressFilter> &filter,
+ CCreatedCoder &cod)
+{
+ const int index = FindMethod_Index(EXTERNAL_CODECS_LOC_VARS methodId, encode);
+ if (index < 0)
+ return S_OK;
+ return CreateCoder_Index(EXTERNAL_CODECS_LOC_VARS (unsigned)index, encode, filter, cod);
+}
+
+
+HRESULT CreateCoder_Id(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId, bool encode,
+ CCreatedCoder &cod)
+{
+ CMyComPtr<ICompressFilter> filter;
+ const HRESULT res = CreateCoder_Id(
+ EXTERNAL_CODECS_LOC_VARS
+ methodId, encode,
+ filter, cod);
+
+ if (filter)
+ {
+ cod.IsFilter = true;
+ CFilterCoder *coderSpec = new CFilterCoder(encode);
+ cod.Coder = coderSpec;
+ coderSpec->Filter = filter;
+ }
+
+ return res;
+}
+
+
+HRESULT CreateCoder_Id(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId, bool encode,
+ CMyComPtr<ICompressCoder> &coder)
+{
+ CCreatedCoder cod;
+ const HRESULT res = CreateCoder_Id(
+ EXTERNAL_CODECS_LOC_VARS
+ methodId, encode,
+ cod);
+ coder = cod.Coder;
+ return res;
+}
+
+HRESULT CreateFilter(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId, bool encode,
+ CMyComPtr<ICompressFilter> &filter)
+{
+ CCreatedCoder cod;
+ return CreateCoder_Id(
+ EXTERNAL_CODECS_LOC_VARS
+ methodId, encode,
+ filter, cod);
+}
+
+
+HRESULT CreateHasher(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ AString &name,
+ CMyComPtr<IHasher> &hasher)
+{
+ name.Empty();
+
+ unsigned i;
+ for (i = 0; i < g_NumHashers; i++)
+ {
+ const CHasherInfo &codec = *g_Hashers[i];
+ if (codec.Id == methodId)
+ {
+ hasher = codec.CreateHasher();
+ name = codec.Name;
+ break;
+ }
+ }
+
+ #ifdef Z7_EXTERNAL_CODECS
+
+ CHECK_GLOBAL_CODECS
+
+ if (!hasher && _externalCodecs)
+ for (i = 0; i < _externalCodecs->Hashers.Size(); i++)
+ {
+ const CHasherInfoEx &codec = _externalCodecs->Hashers[i];
+ if (codec.Id == methodId)
+ {
+ name = codec.Name;
+ return _externalCodecs->GetHashers->CreateHasher((UInt32)i, &hasher);
+ }
+ }
+
+ #endif
+
+ return S_OK;
+}
diff --git a/CPP/7zip/Common/CreateCoder.h b/CPP/7zip/Common/CreateCoder.h
index 2105818..709fe83 100644
--- a/CPP/7zip/Common/CreateCoder.h
+++ b/CPP/7zip/Common/CreateCoder.h
@@ -1,192 +1,200 @@
-// CreateCoder.h
-
-#ifndef __CREATE_CODER_H
-#define __CREATE_CODER_H
-
-#include "../../Common/MyCom.h"
-#include "../../Common/MyString.h"
-
-#include "../ICoder.h"
-
-#include "MethodId.h"
-
-/*
- if EXTERNAL_CODECS is not defined, the code supports only codecs that
- are statically linked at compile-time and link-time.
-
- if EXTERNAL_CODECS is defined, the code supports also codecs from another
- executable modules, that can be linked dynamically at run-time:
- - EXE module can use codecs from external DLL files.
- - DLL module can use codecs from external EXE and DLL files.
-
- CExternalCodecs contains information about codecs and interfaces to create them.
-
- The order of codecs:
- 1) Internal codecs
- 2) External codecs
-*/
-
-#ifdef EXTERNAL_CODECS
-
-struct CCodecInfoEx
-{
- CMethodId Id;
- AString Name;
- UInt32 NumStreams;
- bool EncoderIsAssigned;
- bool DecoderIsAssigned;
-
- CCodecInfoEx(): EncoderIsAssigned(false), DecoderIsAssigned(false) {}
-};
-
-struct CHasherInfoEx
-{
- CMethodId Id;
- AString Name;
-};
-
-#define PUBLIC_ISetCompressCodecsInfo public ISetCompressCodecsInfo,
-#define QUERY_ENTRY_ISetCompressCodecsInfo MY_QUERYINTERFACE_ENTRY(ISetCompressCodecsInfo)
-#define DECL_ISetCompressCodecsInfo STDMETHOD(SetCompressCodecsInfo)(ICompressCodecsInfo *compressCodecsInfo);
-#define IMPL_ISetCompressCodecsInfo2(x) \
-STDMETHODIMP x::SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo) { \
- COM_TRY_BEGIN __externalCodecs.GetCodecs = compressCodecsInfo; return __externalCodecs.Load(); COM_TRY_END }
-#define IMPL_ISetCompressCodecsInfo IMPL_ISetCompressCodecsInfo2(CHandler)
-
-struct CExternalCodecs
-{
- CMyComPtr<ICompressCodecsInfo> GetCodecs;
- CMyComPtr<IHashers> GetHashers;
-
- CObjectVector<CCodecInfoEx> Codecs;
- CObjectVector<CHasherInfoEx> Hashers;
-
- bool IsSet() const { return GetCodecs != NULL || GetHashers != NULL; }
-
- HRESULT Load();
-
- void ClearAndRelease()
- {
- Hashers.Clear();
- Codecs.Clear();
- GetHashers.Release();
- GetCodecs.Release();
- }
-
- ~CExternalCodecs()
- {
- GetHashers.Release();
- GetCodecs.Release();
- }
-};
-
-extern CExternalCodecs g_ExternalCodecs;
-
-#define EXTERNAL_CODECS_VARS2 (__externalCodecs.IsSet() ? &__externalCodecs : &g_ExternalCodecs)
-#define EXTERNAL_CODECS_VARS2_L (&__externalCodecs)
-#define EXTERNAL_CODECS_VARS2_G (&g_ExternalCodecs)
-
-#define DECL_EXTERNAL_CODECS_VARS CExternalCodecs __externalCodecs;
-
-#define EXTERNAL_CODECS_VARS EXTERNAL_CODECS_VARS2,
-#define EXTERNAL_CODECS_VARS_L EXTERNAL_CODECS_VARS2_L,
-#define EXTERNAL_CODECS_VARS_G EXTERNAL_CODECS_VARS2_G,
-
-#define DECL_EXTERNAL_CODECS_LOC_VARS2 const CExternalCodecs *__externalCodecs
-#define EXTERNAL_CODECS_LOC_VARS2 __externalCodecs
-
-#define DECL_EXTERNAL_CODECS_LOC_VARS DECL_EXTERNAL_CODECS_LOC_VARS2,
-#define EXTERNAL_CODECS_LOC_VARS EXTERNAL_CODECS_LOC_VARS2,
-
-#else
-
-#define PUBLIC_ISetCompressCodecsInfo
-#define QUERY_ENTRY_ISetCompressCodecsInfo
-#define DECL_ISetCompressCodecsInfo
-#define IMPL_ISetCompressCodecsInfo
-#define EXTERNAL_CODECS_VARS2
-#define DECL_EXTERNAL_CODECS_VARS
-#define EXTERNAL_CODECS_VARS
-#define EXTERNAL_CODECS_VARS_L
-#define EXTERNAL_CODECS_VARS_G
-#define DECL_EXTERNAL_CODECS_LOC_VARS2
-#define EXTERNAL_CODECS_LOC_VARS2
-#define DECL_EXTERNAL_CODECS_LOC_VARS
-#define EXTERNAL_CODECS_LOC_VARS
-
-#endif
-
-int FindMethod_Index(
- DECL_EXTERNAL_CODECS_LOC_VARS
- const AString &name,
- bool encode,
- CMethodId &methodId,
- UInt32 &numStreams);
-
-bool FindMethod(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CMethodId methodId,
- AString &name);
-
-bool FindHashMethod(
- DECL_EXTERNAL_CODECS_LOC_VARS
- const AString &name,
- CMethodId &methodId);
-
-void GetHashMethods(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CRecordVector<CMethodId> &methods);
-
-
-struct CCreatedCoder
-{
- CMyComPtr<ICompressCoder> Coder;
- CMyComPtr<ICompressCoder2> Coder2;
-
- bool IsExternal;
- bool IsFilter; // = true, if Coder was created from filter
- UInt32 NumStreams;
-
- // CCreatedCoder(): IsExternal(false), IsFilter(false), NumStreams(1) {}
-};
-
-
-HRESULT CreateCoder_Index(
- DECL_EXTERNAL_CODECS_LOC_VARS
- unsigned codecIndex, bool encode,
- CMyComPtr<ICompressFilter> &filter,
- CCreatedCoder &cod);
-
-HRESULT CreateCoder_Index(
- DECL_EXTERNAL_CODECS_LOC_VARS
- unsigned index, bool encode,
- CCreatedCoder &cod);
-
-HRESULT CreateCoder_Id(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CMethodId methodId, bool encode,
- CMyComPtr<ICompressFilter> &filter,
- CCreatedCoder &cod);
-
-HRESULT CreateCoder_Id(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CMethodId methodId, bool encode,
- CCreatedCoder &cod);
-
-HRESULT CreateCoder_Id(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CMethodId methodId, bool encode,
- CMyComPtr<ICompressCoder> &coder);
-
-HRESULT CreateFilter(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CMethodId methodId, bool encode,
- CMyComPtr<ICompressFilter> &filter);
-
-HRESULT CreateHasher(
- DECL_EXTERNAL_CODECS_LOC_VARS
- CMethodId methodId,
- AString &name,
- CMyComPtr<IHasher> &hasher);
-
-#endif
+// CreateCoder.h
+
+#ifndef ZIP7_INC_CREATE_CODER_H
+#define ZIP7_INC_CREATE_CODER_H
+
+#include "../../Common/MyCom.h"
+#include "../../Common/MyString.h"
+
+#include "../ICoder.h"
+
+#include "MethodId.h"
+
+/*
+ if Z7_EXTERNAL_CODECS is not defined, the code supports only codecs that
+ are statically linked at compile-time and link-time.
+
+ if Z7_EXTERNAL_CODECS is defined, the code supports also codecs from another
+ executable modules, that can be linked dynamically at run-time:
+ - EXE module can use codecs from external DLL files.
+ - DLL module can use codecs from external EXE and DLL files.
+
+ CExternalCodecs contains information about codecs and interfaces to create them.
+
+ The order of codecs:
+ 1) Internal codecs
+ 2) External codecs
+*/
+
+#ifdef Z7_EXTERNAL_CODECS
+
+struct CCodecInfoEx
+{
+ CMethodId Id;
+ AString Name;
+ UInt32 NumStreams;
+ bool EncoderIsAssigned;
+ bool DecoderIsAssigned;
+ bool IsFilter; // it's unused
+
+ CCodecInfoEx(): EncoderIsAssigned(false), DecoderIsAssigned(false), IsFilter(false) {}
+};
+
+struct CHasherInfoEx
+{
+ CMethodId Id;
+ AString Name;
+};
+
+#define Z7_PUBLIC_ISetCompressCodecsInfo_IFEC \
+ public ISetCompressCodecsInfo,
+#define Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC \
+ Z7_COM_QI_ENTRY(ISetCompressCodecsInfo)
+#define DECL_ISetCompressCodecsInfo \
+ Z7_COM7F_IMP(SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo))
+#define IMPL_ISetCompressCodecsInfo2(cls) \
+ Z7_COM7F_IMF(cls::SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo)) \
+ { COM_TRY_BEGIN _externalCodecs.GetCodecs = compressCodecsInfo; \
+ return _externalCodecs.Load(); COM_TRY_END }
+#define IMPL_ISetCompressCodecsInfo IMPL_ISetCompressCodecsInfo2(CHandler)
+
+struct CExternalCodecs
+{
+ CMyComPtr<ICompressCodecsInfo> GetCodecs;
+ CMyComPtr<IHashers> GetHashers;
+
+ CObjectVector<CCodecInfoEx> Codecs;
+ CObjectVector<CHasherInfoEx> Hashers;
+
+ bool IsSet() const { return GetCodecs != NULL || GetHashers != NULL; }
+
+ HRESULT Load();
+
+ void ClearAndRelease()
+ {
+ Hashers.Clear();
+ Codecs.Clear();
+ GetHashers.Release();
+ GetCodecs.Release();
+ }
+
+ ~CExternalCodecs()
+ {
+ GetHashers.Release();
+ GetCodecs.Release();
+ }
+};
+
+extern CExternalCodecs g_ExternalCodecs;
+
+#define EXTERNAL_CODECS_VARS2 (_externalCodecs.IsSet() ? &_externalCodecs : &g_ExternalCodecs)
+#define EXTERNAL_CODECS_VARS2_L (&_externalCodecs)
+#define EXTERNAL_CODECS_VARS2_G (&g_ExternalCodecs)
+
+#define DECL_EXTERNAL_CODECS_VARS CExternalCodecs _externalCodecs;
+
+#define EXTERNAL_CODECS_VARS EXTERNAL_CODECS_VARS2,
+#define EXTERNAL_CODECS_VARS_L EXTERNAL_CODECS_VARS2_L,
+#define EXTERNAL_CODECS_VARS_G EXTERNAL_CODECS_VARS2_G,
+
+#define DECL_EXTERNAL_CODECS_LOC_VARS2 const CExternalCodecs *_externalCodecs
+#define DECL_EXTERNAL_CODECS_LOC_VARS DECL_EXTERNAL_CODECS_LOC_VARS2,
+#define DECL_EXTERNAL_CODECS_LOC_VARS_DECL DECL_EXTERNAL_CODECS_LOC_VARS2;
+
+#define EXTERNAL_CODECS_LOC_VARS2 _externalCodecs
+#define EXTERNAL_CODECS_LOC_VARS EXTERNAL_CODECS_LOC_VARS2,
+
+#else
+
+#define Z7_PUBLIC_ISetCompressCodecsInfo_IFEC
+#define Z7_COM_QI_ENTRY_ISetCompressCodecsInfo_IFEC
+#define DECL_ISetCompressCodecsInfo
+#define IMPL_ISetCompressCodecsInfo
+#define EXTERNAL_CODECS_VARS2
+#define DECL_EXTERNAL_CODECS_VARS
+#define EXTERNAL_CODECS_VARS
+#define EXTERNAL_CODECS_VARS_L
+#define EXTERNAL_CODECS_VARS_G
+#define DECL_EXTERNAL_CODECS_LOC_VARS2
+#define DECL_EXTERNAL_CODECS_LOC_VARS
+#define DECL_EXTERNAL_CODECS_LOC_VARS_DECL
+#define EXTERNAL_CODECS_LOC_VARS2
+#define EXTERNAL_CODECS_LOC_VARS
+
+#endif
+
+int FindMethod_Index(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const AString &name,
+ bool encode,
+ CMethodId &methodId,
+ UInt32 &numStreams,
+ bool &isFilter);
+
+bool FindMethod(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ AString &name);
+
+bool FindHashMethod(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const AString &name,
+ CMethodId &methodId);
+
+void GetHashMethods(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CRecordVector<CMethodId> &methods);
+
+
+struct CCreatedCoder
+{
+ CMyComPtr<ICompressCoder> Coder;
+ CMyComPtr<ICompressCoder2> Coder2;
+
+ bool IsExternal;
+ bool IsFilter; // = true, if Coder was created from filter
+ UInt32 NumStreams;
+
+ // CCreatedCoder(): IsExternal(false), IsFilter(false), NumStreams(1) {}
+};
+
+
+HRESULT CreateCoder_Index(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ unsigned codecIndex, bool encode,
+ CMyComPtr<ICompressFilter> &filter,
+ CCreatedCoder &cod);
+
+HRESULT CreateCoder_Index(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ unsigned index, bool encode,
+ CCreatedCoder &cod);
+
+HRESULT CreateCoder_Id(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId, bool encode,
+ CMyComPtr<ICompressFilter> &filter,
+ CCreatedCoder &cod);
+
+HRESULT CreateCoder_Id(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId, bool encode,
+ CCreatedCoder &cod);
+
+HRESULT CreateCoder_Id(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId, bool encode,
+ CMyComPtr<ICompressCoder> &coder);
+
+HRESULT CreateFilter(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId, bool encode,
+ CMyComPtr<ICompressFilter> &filter);
+
+HRESULT CreateHasher(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ CMethodId methodId,
+ AString &name,
+ CMyComPtr<IHasher> &hasher);
+
+#endif
diff --git a/CPP/7zip/Common/FilePathAutoRename.cpp b/CPP/7zip/Common/FilePathAutoRename.cpp
index 84c9e2b..1ebfd72 100644
--- a/CPP/7zip/Common/FilePathAutoRename.cpp
+++ b/CPP/7zip/Common/FilePathAutoRename.cpp
@@ -1,46 +1,46 @@
-// FilePathAutoRename.cpp
-
-#include "StdAfx.h"
-
-#include "../../Windows/FileFind.h"
-
-#include "FilePathAutoRename.h"
-
-using namespace NWindows;
-
-static bool MakeAutoName(const FString &name,
- const FString &extension, UInt32 value, FString &path)
-{
- path = name;
- path.Add_UInt32(value);
- path += extension;
- return NFile::NFind::DoesFileOrDirExist(path);
-}
-
-bool AutoRenamePath(FString &path)
-{
- int dotPos = path.ReverseFind_Dot();
- int slashPos = path.ReverseFind_PathSepar();
-
- FString name = path;
- FString extension;
- if (dotPos > slashPos + 1)
- {
- name.DeleteFrom(dotPos);
- extension = path.Ptr(dotPos);
- }
- name += '_';
-
- FString temp;
-
- UInt32 left = 1, right = ((UInt32)1 << 30);
- while (left != right)
- {
- UInt32 mid = (left + right) / 2;
- if (MakeAutoName(name, extension, mid, temp))
- left = mid + 1;
- else
- right = mid;
- }
- return !MakeAutoName(name, extension, right, path);
-}
+// FilePathAutoRename.cpp
+
+#include "StdAfx.h"
+
+#include "../../Windows/FileFind.h"
+
+#include "FilePathAutoRename.h"
+
+using namespace NWindows;
+
+static bool MakeAutoName(const FString &name,
+ const FString &extension, UInt32 value, FString &path)
+{
+ path = name;
+ path.Add_UInt32(value);
+ path += extension;
+ return NFile::NFind::DoesFileOrDirExist(path);
+}
+
+bool AutoRenamePath(FString &path)
+{
+ int dotPos = path.ReverseFind_Dot();
+ int slashPos = path.ReverseFind_PathSepar();
+
+ FString name = path;
+ FString extension;
+ if (dotPos > slashPos + 1)
+ {
+ name.DeleteFrom((unsigned)dotPos);
+ extension = path.Ptr((unsigned)dotPos);
+ }
+ name += '_';
+
+ FString temp;
+
+ UInt32 left = 1, right = ((UInt32)1 << 30);
+ while (left != right)
+ {
+ UInt32 mid = (left + right) / 2;
+ if (MakeAutoName(name, extension, mid, temp))
+ left = mid + 1;
+ else
+ right = mid;
+ }
+ return !MakeAutoName(name, extension, right, path);
+}
diff --git a/CPP/7zip/Common/FilePathAutoRename.h b/CPP/7zip/Common/FilePathAutoRename.h
index cb2d71b..ac36882 100644
--- a/CPP/7zip/Common/FilePathAutoRename.h
+++ b/CPP/7zip/Common/FilePathAutoRename.h
@@ -1,10 +1,10 @@
-// FilePathAutoRename.h
-
-#ifndef __FILE_PATH_AUTO_RENAME_H
-#define __FILE_PATH_AUTO_RENAME_H
-
-#include "../../Common/MyString.h"
-
-bool AutoRenamePath(FString &fullProcessedPath);
-
-#endif
+// FilePathAutoRename.h
+
+#ifndef ZIP7_INC_FILE_PATH_AUTO_RENAME_H
+#define ZIP7_INC_FILE_PATH_AUTO_RENAME_H
+
+#include "../../Common/MyString.h"
+
+bool AutoRenamePath(FString &fullProcessedPath);
+
+#endif
diff --git a/CPP/7zip/Common/FileStreams.cpp b/CPP/7zip/Common/FileStreams.cpp
index 11c14d2..4298636 100644
--- a/CPP/7zip/Common/FileStreams.cpp
+++ b/CPP/7zip/Common/FileStreams.cpp
@@ -1,475 +1,800 @@
-// FileStreams.cpp
-
-#include "StdAfx.h"
-
-#ifndef _WIN32
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#endif
-
-#ifdef SUPPORT_DEVICE_FILE
-#include "../../../C/Alloc.h"
-#include "../../Common/Defs.h"
-#endif
-
-#include "FileStreams.h"
-
-static inline HRESULT ConvertBoolToHRESULT(bool result)
-{
- #ifdef _WIN32
- if (result)
- return S_OK;
- DWORD lastError = ::GetLastError();
- if (lastError == 0)
- return E_FAIL;
- return HRESULT_FROM_WIN32(lastError);
- #else
- return result ? S_OK: E_FAIL;
- #endif
-}
-
-
-static const UInt32 kClusterSize = 1 << 18;
-CInFileStream::CInFileStream():
- #ifdef SUPPORT_DEVICE_FILE
- VirtPos(0),
- PhyPos(0),
- Buf(0),
- BufSize(0),
- #endif
- SupportHardLinks(false),
- Callback(NULL),
- CallbackRef(0)
-{
-}
-
-CInFileStream::~CInFileStream()
-{
- #ifdef SUPPORT_DEVICE_FILE
- MidFree(Buf);
- #endif
-
- if (Callback)
- Callback->InFileStream_On_Destroy(CallbackRef);
-}
-
-STDMETHODIMP CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- #ifdef USE_WIN_FILE
-
- #ifdef SUPPORT_DEVICE_FILE
- if (processedSize)
- *processedSize = 0;
- if (size == 0)
- return S_OK;
- if (File.IsDeviceFile)
- {
- if (File.SizeDefined)
- {
- if (VirtPos >= File.Size)
- return VirtPos == File.Size ? S_OK : E_FAIL;
- UInt64 rem = File.Size - VirtPos;
- if (size > rem)
- size = (UInt32)rem;
- }
- for (;;)
- {
- const UInt32 mask = kClusterSize - 1;
- const UInt64 mask2 = ~(UInt64)mask;
- UInt64 alignedPos = VirtPos & mask2;
- if (BufSize > 0 && BufStartPos == alignedPos)
- {
- UInt32 pos = (UInt32)VirtPos & mask;
- if (pos >= BufSize)
- return S_OK;
- UInt32 rem = MyMin(BufSize - pos, size);
- memcpy(data, Buf + pos, rem);
- VirtPos += rem;
- if (processedSize)
- *processedSize += rem;
- return S_OK;
- }
-
- bool useBuf = false;
- if ((VirtPos & mask) != 0 || ((ptrdiff_t)data & mask) != 0 )
- useBuf = true;
- else
- {
- UInt64 end = VirtPos + size;
- if ((end & mask) != 0)
- {
- end &= mask2;
- if (end <= VirtPos)
- useBuf = true;
- else
- size = (UInt32)(end - VirtPos);
- }
- }
- if (!useBuf)
- break;
- if (alignedPos != PhyPos)
- {
- UInt64 realNewPosition;
- bool result = File.Seek(alignedPos, FILE_BEGIN, realNewPosition);
- if (!result)
- return ConvertBoolToHRESULT(result);
- PhyPos = realNewPosition;
- }
-
- BufStartPos = alignedPos;
- UInt32 readSize = kClusterSize;
- if (File.SizeDefined)
- readSize = (UInt32)MyMin(File.Size - PhyPos, (UInt64)kClusterSize);
-
- if (!Buf)
- {
- Buf = (Byte *)MidAlloc(kClusterSize);
- if (!Buf)
- return E_OUTOFMEMORY;
- }
- bool result = File.Read1(Buf, readSize, BufSize);
- if (!result)
- return ConvertBoolToHRESULT(result);
-
- if (BufSize == 0)
- return S_OK;
- PhyPos += BufSize;
- }
-
- if (VirtPos != PhyPos)
- {
- UInt64 realNewPosition;
- bool result = File.Seek(VirtPos, FILE_BEGIN, realNewPosition);
- if (!result)
- return ConvertBoolToHRESULT(result);
- PhyPos = VirtPos = realNewPosition;
- }
- }
- #endif
-
- UInt32 realProcessedSize;
- bool result = File.ReadPart(data, size, realProcessedSize);
- if (processedSize)
- *processedSize = realProcessedSize;
-
- #ifdef SUPPORT_DEVICE_FILE
- VirtPos += realProcessedSize;
- PhyPos += realProcessedSize;
- #endif
-
- if (result)
- return S_OK;
-
- {
- DWORD error = ::GetLastError();
-
- if (Callback)
- return Callback->InFileStream_On_Error(CallbackRef, error);
- if (error == 0)
- return E_FAIL;
-
- return HRESULT_FROM_WIN32(error);
- }
-
- #else
-
- if (processedSize)
- *processedSize = 0;
- ssize_t res = File.Read(data, (size_t)size);
- if (res == -1)
- {
- if (Callback)
- return Callback->InFileStream_On_Error(CallbackRef, E_FAIL);
- return E_FAIL;
- }
- if (processedSize)
- *processedSize = (UInt32)res;
- return S_OK;
-
- #endif
-}
-
-#ifdef UNDER_CE
-STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- size_t s2 = fread(data, 1, size, stdin);
- int error = ferror(stdin);
- if (processedSize)
- *processedSize = s2;
- if (s2 <= size && error == 0)
- return S_OK;
- return E_FAIL;
-}
-#else
-STDMETHODIMP CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- #ifdef _WIN32
-
- DWORD realProcessedSize;
- UInt32 sizeTemp = (1 << 20);
- if (sizeTemp > size)
- sizeTemp = size;
- BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), data, sizeTemp, &realProcessedSize, NULL);
- if (processedSize)
- *processedSize = realProcessedSize;
- if (res == FALSE && GetLastError() == ERROR_BROKEN_PIPE)
- return S_OK;
- return ConvertBoolToHRESULT(res != FALSE);
-
- #else
-
- if (processedSize)
- *processedSize = 0;
- ssize_t res;
- do
- {
- res = read(0, data, (size_t)size);
- }
- while (res < 0 && (errno == EINTR));
- if (res == -1)
- return E_FAIL;
- if (processedSize)
- *processedSize = (UInt32)res;
- return S_OK;
-
- #endif
-}
-
-#endif
-
-STDMETHODIMP CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- if (seekOrigin >= 3)
- return STG_E_INVALIDFUNCTION;
-
- #ifdef USE_WIN_FILE
-
- #ifdef SUPPORT_DEVICE_FILE
- if (File.IsDeviceFile && (File.SizeDefined || seekOrigin != STREAM_SEEK_END))
- {
- switch (seekOrigin)
- {
- case STREAM_SEEK_SET: break;
- case STREAM_SEEK_CUR: offset += VirtPos; break;
- case STREAM_SEEK_END: offset += File.Size; break;
- default: return STG_E_INVALIDFUNCTION;
- }
- if (offset < 0)
- return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
- VirtPos = offset;
- if (newPosition)
- *newPosition = offset;
- return S_OK;
- }
- #endif
-
- UInt64 realNewPosition;
- bool result = File.Seek(offset, seekOrigin, realNewPosition);
-
- #ifdef SUPPORT_DEVICE_FILE
- PhyPos = VirtPos = realNewPosition;
- #endif
-
- if (newPosition)
- *newPosition = realNewPosition;
- return ConvertBoolToHRESULT(result);
-
- #else
-
- off_t res = File.Seek((off_t)offset, seekOrigin);
- if (res == -1)
- return E_FAIL;
- if (newPosition)
- *newPosition = (UInt64)res;
- return S_OK;
-
- #endif
-}
-
-STDMETHODIMP CInFileStream::GetSize(UInt64 *size)
-{
- return ConvertBoolToHRESULT(File.GetLength(*size));
-}
-
-#ifdef USE_WIN_FILE
-
-STDMETHODIMP CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib)
-{
- BY_HANDLE_FILE_INFORMATION info;
- if (File.GetFileInformation(&info))
- {
- if (size) *size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
- if (cTime) *cTime = info.ftCreationTime;
- if (aTime) *aTime = info.ftLastAccessTime;
- if (mTime) *mTime = info.ftLastWriteTime;
- if (attrib) *attrib = info.dwFileAttributes;
- return S_OK;
- }
- return GetLastError();
-}
-
-STDMETHODIMP CInFileStream::GetProps2(CStreamFileProps *props)
-{
- BY_HANDLE_FILE_INFORMATION info;
- if (File.GetFileInformation(&info))
- {
- props->Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
- props->VolID = info.dwVolumeSerialNumber;
- props->FileID_Low = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow;
- props->FileID_High = 0;
- props->NumLinks = SupportHardLinks ? info.nNumberOfLinks : 1;
- props->Attrib = info.dwFileAttributes;
- props->CTime = info.ftCreationTime;
- props->ATime = info.ftLastAccessTime;
- props->MTime = info.ftLastWriteTime;
- return S_OK;
- }
- return GetLastError();
-}
-
-#endif
-
-//////////////////////////
-// COutFileStream
-
-HRESULT COutFileStream::Close()
-{
- return ConvertBoolToHRESULT(File.Close());
-}
-
-STDMETHODIMP COutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- #ifdef USE_WIN_FILE
-
- UInt32 realProcessedSize;
- bool result = File.Write(data, size, realProcessedSize);
- ProcessedSize += realProcessedSize;
- if (processedSize)
- *processedSize = realProcessedSize;
- return ConvertBoolToHRESULT(result);
-
- #else
-
- if (processedSize)
- *processedSize = 0;
- ssize_t res = File.Write(data, (size_t)size);
- if (res == -1)
- return E_FAIL;
- if (processedSize)
- *processedSize = (UInt32)res;
- ProcessedSize += res;
- return S_OK;
-
- #endif
-}
-
-STDMETHODIMP COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- if (seekOrigin >= 3)
- return STG_E_INVALIDFUNCTION;
-
- #ifdef USE_WIN_FILE
-
- UInt64 realNewPosition;
- bool result = File.Seek(offset, seekOrigin, realNewPosition);
- if (newPosition)
- *newPosition = realNewPosition;
- return ConvertBoolToHRESULT(result);
-
- #else
-
- off_t res = File.Seek((off_t)offset, seekOrigin);
- if (res == -1)
- return E_FAIL;
- if (newPosition)
- *newPosition = (UInt64)res;
- return S_OK;
-
- #endif
-}
-
-STDMETHODIMP COutFileStream::SetSize(UInt64 newSize)
-{
- #ifdef USE_WIN_FILE
-
- UInt64 currentPos;
- if (!File.Seek(0, FILE_CURRENT, currentPos))
- return E_FAIL;
- bool result = File.SetLength(newSize);
- UInt64 currentPos2;
- result = result && File.Seek(currentPos, currentPos2);
- return result ? S_OK : E_FAIL;
-
- #else
-
- return E_FAIL;
-
- #endif
-}
-
-HRESULT COutFileStream::GetSize(UInt64 *size)
-{
- return ConvertBoolToHRESULT(File.GetLength(*size));
-}
-
-#ifdef UNDER_CE
-
-STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- size_t s2 = fwrite(data, 1, size, stdout);
- if (processedSize)
- *processedSize = s2;
- return (s2 == size) ? S_OK : E_FAIL;
-}
-
-#else
-
-STDMETHODIMP CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
-
- #ifdef _WIN32
-
- UInt32 realProcessedSize;
- BOOL res = TRUE;
- if (size > 0)
- {
- // Seems that Windows doesn't like big amounts writing to stdout.
- // So we limit portions by 32KB.
- UInt32 sizeTemp = (1 << 15);
- if (sizeTemp > size)
- sizeTemp = size;
- res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),
- data, sizeTemp, (DWORD *)&realProcessedSize, NULL);
- _size += realProcessedSize;
- size -= realProcessedSize;
- data = (const void *)((const Byte *)data + realProcessedSize);
- if (processedSize)
- *processedSize += realProcessedSize;
- }
- return ConvertBoolToHRESULT(res != FALSE);
-
- #else
-
- ssize_t res;
-
- do
- {
- res = write(1, data, (size_t)size);
- }
- while (res < 0 && (errno == EINTR));
-
- if (res == -1)
- return E_FAIL;
-
- _size += (size_t)res;
- if (processedSize)
- *processedSize = (UInt32)res;
- return S_OK;
-
- #endif
-}
-
-#endif
+// FileStreams.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#ifndef _WIN32
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <grp.h>
+#include <pwd.h>
+
+// for major()/minor():
+#include <sys/types.h>
+#if defined(__FreeBSD__) || defined(BSD) || defined(__APPLE__)
+#else
+#ifndef major
+#include <sys/sysmacros.h>
+#endif
+#endif
+
+#endif // _WIN32
+
+#include "../../Windows/FileFind.h"
+
+#ifdef Z7_DEVICE_FILE
+#include "../../../C/Alloc.h"
+#include "../../Common/Defs.h"
+#endif
+
+#include "../PropID.h"
+
+#include "FileStreams.h"
+
+static inline HRESULT GetLastError_HRESULT()
+{
+ DWORD lastError = ::GetLastError();
+ if (lastError == 0)
+ return E_FAIL;
+ return HRESULT_FROM_WIN32(lastError);
+}
+
+static inline HRESULT ConvertBoolToHRESULT(bool result)
+{
+ if (result)
+ return S_OK;
+ return GetLastError_HRESULT();
+}
+
+
+#ifdef Z7_DEVICE_FILE
+static const UInt32 kClusterSize = 1 << 18;
+#endif
+
+CInFileStream::CInFileStream():
+ #ifdef Z7_DEVICE_FILE
+ VirtPos(0),
+ PhyPos(0),
+ Buf(NULL),
+ BufSize(0),
+ #endif
+ #ifndef _WIN32
+ _uid(0),
+ _gid(0),
+ StoreOwnerId(false),
+ StoreOwnerName(false),
+ #endif
+ _info_WasLoaded(false),
+ SupportHardLinks(false),
+ Callback(NULL),
+ CallbackRef(0)
+{
+}
+
+CInFileStream::~CInFileStream()
+{
+ #ifdef Z7_DEVICE_FILE
+ MidFree(Buf);
+ #endif
+
+ if (Callback)
+ Callback->InFileStream_On_Destroy(this, CallbackRef);
+}
+
+Z7_COM7F_IMF(CInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ #ifdef Z7_FILE_STREAMS_USE_WIN_FILE
+
+ #ifdef Z7_DEVICE_FILE
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ if (File.IsDeviceFile)
+ {
+ if (File.SizeDefined)
+ {
+ if (VirtPos >= File.Size)
+ return VirtPos == File.Size ? S_OK : E_FAIL;
+ const UInt64 rem = File.Size - VirtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+ for (;;)
+ {
+ const UInt32 mask = kClusterSize - 1;
+ const UInt64 mask2 = ~(UInt64)mask;
+ const UInt64 alignedPos = VirtPos & mask2;
+ if (BufSize > 0 && BufStartPos == alignedPos)
+ {
+ const UInt32 pos = (UInt32)VirtPos & mask;
+ if (pos >= BufSize)
+ return S_OK;
+ const UInt32 rem = MyMin(BufSize - pos, size);
+ memcpy(data, Buf + pos, rem);
+ VirtPos += rem;
+ if (processedSize)
+ *processedSize += rem;
+ return S_OK;
+ }
+
+ bool useBuf = false;
+ if ((VirtPos & mask) != 0 || ((size_t)(ptrdiff_t)data & mask) != 0 )
+ useBuf = true;
+ else
+ {
+ UInt64 end = VirtPos + size;
+ if ((end & mask) != 0)
+ {
+ end &= mask2;
+ if (end <= VirtPos)
+ useBuf = true;
+ else
+ size = (UInt32)(end - VirtPos);
+ }
+ }
+ if (!useBuf)
+ break;
+ if (alignedPos != PhyPos)
+ {
+ UInt64 realNewPosition;
+ const bool result = File.Seek((Int64)alignedPos, FILE_BEGIN, realNewPosition);
+ if (!result)
+ return ConvertBoolToHRESULT(result);
+ PhyPos = realNewPosition;
+ }
+
+ BufStartPos = alignedPos;
+ UInt32 readSize = kClusterSize;
+ if (File.SizeDefined)
+ readSize = (UInt32)MyMin(File.Size - PhyPos, (UInt64)kClusterSize);
+
+ if (!Buf)
+ {
+ Buf = (Byte *)MidAlloc(kClusterSize);
+ if (!Buf)
+ return E_OUTOFMEMORY;
+ }
+ const bool result = File.Read1(Buf, readSize, BufSize);
+ if (!result)
+ return ConvertBoolToHRESULT(result);
+
+ if (BufSize == 0)
+ return S_OK;
+ PhyPos += BufSize;
+ }
+
+ if (VirtPos != PhyPos)
+ {
+ UInt64 realNewPosition;
+ bool result = File.Seek((Int64)VirtPos, FILE_BEGIN, realNewPosition);
+ if (!result)
+ return ConvertBoolToHRESULT(result);
+ PhyPos = VirtPos = realNewPosition;
+ }
+ }
+ #endif
+
+ UInt32 realProcessedSize;
+ const bool result = File.ReadPart(data, size, realProcessedSize);
+ if (processedSize)
+ *processedSize = realProcessedSize;
+
+ #ifdef Z7_DEVICE_FILE
+ VirtPos += realProcessedSize;
+ PhyPos += realProcessedSize;
+ #endif
+
+ if (result)
+ return S_OK;
+
+ #else // Z7_FILE_STREAMS_USE_WIN_FILE
+
+ if (processedSize)
+ *processedSize = 0;
+ const ssize_t res = File.read_part(data, (size_t)size);
+ if (res != -1)
+ {
+ if (processedSize)
+ *processedSize = (UInt32)res;
+ return S_OK;
+ }
+ #endif // Z7_FILE_STREAMS_USE_WIN_FILE
+
+ {
+ const DWORD error = ::GetLastError();
+ if (Callback)
+ return Callback->InFileStream_On_Error(CallbackRef, error);
+ if (error == 0)
+ return E_FAIL;
+ return HRESULT_FROM_WIN32(error);
+ }
+}
+
+#ifdef UNDER_CE
+Z7_COM7F_IMF(CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ size_t s2 = fread(data, 1, size, stdin);
+ int error = ferror(stdin);
+ if (processedSize)
+ *processedSize = s2;
+ if (s2 <= size && error == 0)
+ return S_OK;
+ return E_FAIL;
+}
+#else
+Z7_COM7F_IMF(CStdInFileStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ #ifdef _WIN32
+
+ DWORD realProcessedSize;
+ UInt32 sizeTemp = (1 << 20);
+ if (sizeTemp > size)
+ sizeTemp = size;
+ BOOL res = ::ReadFile(GetStdHandle(STD_INPUT_HANDLE), data, sizeTemp, &realProcessedSize, NULL);
+ if (processedSize)
+ *processedSize = realProcessedSize;
+ if (res == FALSE && GetLastError() == ERROR_BROKEN_PIPE)
+ return S_OK;
+ return ConvertBoolToHRESULT(res != FALSE);
+
+ #else
+
+ if (processedSize)
+ *processedSize = 0;
+ ssize_t res;
+ do
+ {
+ res = read(0, data, (size_t)size);
+ }
+ while (res < 0 && (errno == EINTR));
+ if (res == -1)
+ return GetLastError_HRESULT();
+ if (processedSize)
+ *processedSize = (UInt32)res;
+ return S_OK;
+
+ #endif
+}
+
+#endif
+
+Z7_COM7F_IMF(CInFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ if (seekOrigin >= 3)
+ return STG_E_INVALIDFUNCTION;
+
+ #ifdef Z7_FILE_STREAMS_USE_WIN_FILE
+
+ #ifdef Z7_DEVICE_FILE
+ if (File.IsDeviceFile && (File.SizeDefined || seekOrigin != STREAM_SEEK_END))
+ {
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += VirtPos; break;
+ case STREAM_SEEK_END: offset += File.Size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ VirtPos = (UInt64)offset;
+ if (newPosition)
+ *newPosition = (UInt64)offset;
+ return S_OK;
+ }
+ #endif
+
+ UInt64 realNewPosition = 0;
+ const bool result = File.Seek(offset, seekOrigin, realNewPosition);
+ const HRESULT hres = ConvertBoolToHRESULT(result);
+
+ /* 21.07: new File.Seek() in 21.07 already returns correct (realNewPosition)
+ in case of error. So we don't need additional code below */
+ // if (!result) { realNewPosition = 0; File.GetPosition(realNewPosition); }
+
+ #ifdef Z7_DEVICE_FILE
+ PhyPos = VirtPos = realNewPosition;
+ #endif
+
+ if (newPosition)
+ *newPosition = realNewPosition;
+
+ return hres;
+
+ #else
+
+ const off_t res = File.seek((off_t)offset, (int)seekOrigin);
+ if (res == -1)
+ {
+ const HRESULT hres = GetLastError_HRESULT();
+ if (newPosition)
+ *newPosition = (UInt64)File.seekToCur();
+ return hres;
+ }
+ if (newPosition)
+ *newPosition = (UInt64)res;
+ return S_OK;
+
+ #endif
+}
+
+Z7_COM7F_IMF(CInFileStream::GetSize(UInt64 *size))
+{
+ return ConvertBoolToHRESULT(File.GetLength(*size));
+}
+
+#ifdef Z7_FILE_STREAMS_USE_WIN_FILE
+
+Z7_COM7F_IMF(CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib))
+{
+ if (!_info_WasLoaded)
+ {
+ RINOK(ReloadProps())
+ }
+ const BY_HANDLE_FILE_INFORMATION &info = _info;
+ /*
+ BY_HANDLE_FILE_INFORMATION info;
+ if (!File.GetFileInformation(&info))
+ return GetLastError_HRESULT();
+ */
+ {
+ if (size) *size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
+ if (cTime) *cTime = info.ftCreationTime;
+ if (aTime) *aTime = info.ftLastAccessTime;
+ if (mTime) *mTime = info.ftLastWriteTime;
+ if (attrib) *attrib = info.dwFileAttributes;
+ return S_OK;
+ }
+}
+
+Z7_COM7F_IMF(CInFileStream::GetProps2(CStreamFileProps *props))
+{
+ if (!_info_WasLoaded)
+ {
+ RINOK(ReloadProps())
+ }
+ const BY_HANDLE_FILE_INFORMATION &info = _info;
+ /*
+ BY_HANDLE_FILE_INFORMATION info;
+ if (!File.GetFileInformation(&info))
+ return GetLastError_HRESULT();
+ */
+ {
+ props->Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
+ props->VolID = info.dwVolumeSerialNumber;
+ props->FileID_Low = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow;
+ props->FileID_High = 0;
+ props->NumLinks = SupportHardLinks ? info.nNumberOfLinks : 1;
+ props->Attrib = info.dwFileAttributes;
+ props->CTime = info.ftCreationTime;
+ props->ATime = info.ftLastAccessTime;
+ props->MTime = info.ftLastWriteTime;
+ return S_OK;
+ }
+}
+
+Z7_COM7F_IMF(CInFileStream::GetProperty(PROPID propID, PROPVARIANT *value))
+{
+ if (!_info_WasLoaded)
+ {
+ RINOK(ReloadProps())
+ }
+
+ if (!_info_WasLoaded)
+ return S_OK;
+
+ NWindows::NCOM::CPropVariant prop;
+
+ #ifdef Z7_DEVICE_FILE
+ if (File.IsDeviceFile)
+ {
+ switch (propID)
+ {
+ case kpidSize:
+ if (File.SizeDefined)
+ prop = File.Size;
+ break;
+ // case kpidAttrib: prop = (UInt32)0; break;
+ case kpidPosixAttrib:
+ {
+ prop = (UInt32)NWindows::NFile::NFind::NAttributes::
+ Get_PosixMode_From_WinAttrib(0);
+ /* GNU TAR by default can't extract file with MY_LIN_S_IFBLK attribute
+ so we don't use MY_LIN_S_IFBLK here */
+ // prop = (UInt32)(MY_LIN_S_IFBLK | 0600); // for debug
+ break;
+ }
+ /*
+ case kpidDeviceMajor:
+ prop = (UInt32)8; // id for SCSI type device (sda)
+ break;
+ case kpidDeviceMinor:
+ prop = (UInt32)0;
+ break;
+ */
+ }
+ }
+ else
+ #endif
+ {
+ switch (propID)
+ {
+ case kpidSize:
+ {
+ const UInt64 size = (((UInt64)_info.nFileSizeHigh) << 32) + _info.nFileSizeLow;
+ prop = size;
+ break;
+ }
+ case kpidAttrib: prop = (UInt32)_info.dwFileAttributes; break;
+ case kpidCTime: PropVariant_SetFrom_FiTime(prop, _info.ftCreationTime); break;
+ case kpidATime: PropVariant_SetFrom_FiTime(prop, _info.ftLastAccessTime); break;
+ case kpidMTime: PropVariant_SetFrom_FiTime(prop, _info.ftLastWriteTime); break;
+ case kpidPosixAttrib:
+ prop = (UInt32)NWindows::NFile::NFind::NAttributes::
+ Get_PosixMode_From_WinAttrib(_info.dwFileAttributes);
+ // | (UInt32)(1 << 21); // for debug
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CInFileStream::ReloadProps())
+{
+ #ifdef Z7_DEVICE_FILE
+ if (File.IsDeviceFile)
+ {
+ memset(&_info, 0, sizeof(_info));
+ if (File.SizeDefined)
+ {
+ _info.nFileSizeHigh = (DWORD)(File.Size >> 32);
+ _info.nFileSizeLow = (DWORD)(File.Size);
+ }
+ _info.nNumberOfLinks = 1;
+ _info_WasLoaded = true;
+ return S_OK;
+ }
+ #endif
+ _info_WasLoaded = File.GetFileInformation(&_info);
+ if (!_info_WasLoaded)
+ return GetLastError_HRESULT();
+ return S_OK;
+}
+
+
+#elif !defined(_WIN32)
+
+Z7_COM7F_IMF(CInFileStream::GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib))
+{
+ if (!_info_WasLoaded)
+ {
+ RINOK(ReloadProps())
+ }
+ const struct stat &st = _info;
+ /*
+ struct stat st;
+ if (File.my_fstat(&st) != 0)
+ return GetLastError_HRESULT();
+ */
+
+ if (size) *size = (UInt64)st.st_size;
+ if (cTime) FiTime_To_FILETIME (ST_CTIME(st), *cTime);
+ if (aTime) FiTime_To_FILETIME (ST_ATIME(st), *aTime);
+ if (mTime) FiTime_To_FILETIME (ST_MTIME(st), *mTime);
+ if (attrib) *attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
+
+ return S_OK;
+}
+
+// #include <stdio.h>
+
+Z7_COM7F_IMF(CInFileStream::GetProps2(CStreamFileProps *props))
+{
+ if (!_info_WasLoaded)
+ {
+ RINOK(ReloadProps())
+ }
+ const struct stat &st = _info;
+ /*
+ struct stat st;
+ if (File.my_fstat(&st) != 0)
+ return GetLastError_HRESULT();
+ */
+
+ props->Size = (UInt64)st.st_size;
+ /*
+ dev_t stat::st_dev:
+ GCC:Linux long unsigned int : __dev_t
+ Mac: int
+ */
+ props->VolID = (UInt64)(Int64)st.st_dev;
+ props->FileID_Low = st.st_ino;
+ props->FileID_High = 0;
+ props->NumLinks = (UInt32)st.st_nlink; // we reduce to UInt32 from (nlink_t) that is (unsigned long)
+ props->Attrib = NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
+
+ FiTime_To_FILETIME (ST_CTIME(st), props->CTime);
+ FiTime_To_FILETIME (ST_ATIME(st), props->ATime);
+ FiTime_To_FILETIME (ST_MTIME(st), props->MTime);
+
+ /*
+ printf("\nGetProps2() NumLinks=%d = st_dev=%d st_ino = %d\n"
+ , (unsigned)(props->NumLinks)
+ , (unsigned)(st.st_dev)
+ , (unsigned)(st.st_ino)
+ );
+ */
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CInFileStream::GetProperty(PROPID propID, PROPVARIANT *value))
+{
+ if (!_info_WasLoaded)
+ {
+ RINOK(ReloadProps())
+ }
+
+ if (!_info_WasLoaded)
+ return S_OK;
+
+ const struct stat &st = _info;
+
+ NWindows::NCOM::CPropVariant prop;
+ {
+ switch (propID)
+ {
+ case kpidSize: prop = (UInt64)st.st_size; break;
+ case kpidAttrib:
+ prop = (UInt32)NWindows::NFile::NFind::Get_WinAttribPosix_From_PosixMode(st.st_mode);
+ break;
+ case kpidCTime: PropVariant_SetFrom_FiTime(prop, ST_CTIME(st)); break;
+ case kpidATime: PropVariant_SetFrom_FiTime(prop, ST_ATIME(st)); break;
+ case kpidMTime: PropVariant_SetFrom_FiTime(prop, ST_MTIME(st)); break;
+ case kpidPosixAttrib: prop = (UInt32)st.st_mode; break;
+
+ #if defined(__APPLE__)
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wsign-conversion"
+ #endif
+
+ case kpidDeviceMajor:
+ {
+ // printf("\nst.st_rdev = %d\n", st.st_rdev);
+ if (S_ISCHR(st.st_mode) ||
+ S_ISBLK(st.st_mode))
+ prop = (UInt32)(major(st.st_rdev)); // + 1000);
+ // prop = (UInt32)12345678; // for debug
+ break;
+ }
+
+ case kpidDeviceMinor:
+ if (S_ISCHR(st.st_mode) ||
+ S_ISBLK(st.st_mode))
+ prop = (UInt32)(minor(st.st_rdev)); // + 100);
+ // prop = (UInt32)(st.st_rdev); // for debug
+ // printf("\nst.st_rdev = %d\n", st.st_rdev);
+ // prop = (UInt32)123456789; // for debug
+ break;
+
+ #if defined(__APPLE__)
+ #pragma GCC diagnostic pop
+ #endif
+
+ /*
+ case kpidDevice:
+ if (S_ISCHR(st.st_mode) ||
+ S_ISBLK(st.st_mode))
+ prop = (UInt64)(st.st_rdev);
+ break;
+ */
+
+ case kpidUserId:
+ {
+ if (StoreOwnerId)
+ prop = (UInt32)st.st_uid;
+ break;
+ }
+ case kpidGroupId:
+ {
+ if (StoreOwnerId)
+ prop = (UInt32)st.st_gid;
+ break;
+ }
+ case kpidUser:
+ {
+ if (StoreOwnerName)
+ {
+ const uid_t uid = st.st_uid;
+ {
+ if (!OwnerName.IsEmpty() && _uid == uid)
+ prop = OwnerName;
+ else
+ {
+ const passwd *pw = getpwuid(uid);
+ if (pw)
+ {
+ // we can use utf-8 here.
+ // prop = pw->pw_name;
+ }
+ }
+ }
+ }
+ break;
+ }
+ case kpidGroup:
+ {
+ if (StoreOwnerName)
+ {
+ const uid_t gid = st.st_gid;
+ {
+ if (!OwnerGroup.IsEmpty() && _gid == gid)
+ prop = OwnerGroup;
+ else
+ {
+ const group *gr = getgrgid(gid);
+ if (gr)
+ {
+ // we can use utf-8 here.
+ // prop = gr->gr_name;
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CInFileStream::ReloadProps())
+{
+ _info_WasLoaded = (File.my_fstat(&_info) == 0);
+ if (!_info_WasLoaded)
+ return GetLastError_HRESULT();
+ return S_OK;
+}
+
+#endif
+
+
+
+
+//////////////////////////
+// COutFileStream
+
+HRESULT COutFileStream::Close()
+{
+ return ConvertBoolToHRESULT(File.Close());
+}
+
+Z7_COM7F_IMF(COutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ #ifdef Z7_FILE_STREAMS_USE_WIN_FILE
+
+ UInt32 realProcessedSize;
+ const bool result = File.Write(data, size, realProcessedSize);
+ ProcessedSize += realProcessedSize;
+ if (processedSize)
+ *processedSize = realProcessedSize;
+ return ConvertBoolToHRESULT(result);
+
+ #else
+
+ if (processedSize)
+ *processedSize = 0;
+ size_t realProcessedSize;
+ const ssize_t res = File.write_full(data, (size_t)size, realProcessedSize);
+ ProcessedSize += realProcessedSize;
+ if (processedSize)
+ *processedSize = (UInt32)realProcessedSize;
+ if (res == -1)
+ return GetLastError_HRESULT();
+ return S_OK;
+
+ #endif
+}
+
+Z7_COM7F_IMF(COutFileStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ if (seekOrigin >= 3)
+ return STG_E_INVALIDFUNCTION;
+
+ #ifdef Z7_FILE_STREAMS_USE_WIN_FILE
+
+ UInt64 realNewPosition = 0;
+ const bool result = File.Seek(offset, seekOrigin, realNewPosition);
+ if (newPosition)
+ *newPosition = realNewPosition;
+ return ConvertBoolToHRESULT(result);
+
+ #else
+
+ const off_t res = File.seek((off_t)offset, (int)seekOrigin);
+ if (res == -1)
+ return GetLastError_HRESULT();
+ if (newPosition)
+ *newPosition = (UInt64)res;
+ return S_OK;
+
+ #endif
+}
+
+Z7_COM7F_IMF(COutFileStream::SetSize(UInt64 newSize))
+{
+ return ConvertBoolToHRESULT(File.SetLength_KeepPosition(newSize));
+}
+
+HRESULT COutFileStream::GetSize(UInt64 *size)
+{
+ return ConvertBoolToHRESULT(File.GetLength(*size));
+}
+
+#ifdef UNDER_CE
+
+Z7_COM7F_IMF(CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ size_t s2 = fwrite(data, 1, size, stdout);
+ if (processedSize)
+ *processedSize = s2;
+ return (s2 == size) ? S_OK : E_FAIL;
+}
+
+#else
+
+Z7_COM7F_IMF(CStdOutFileStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+
+ #ifdef _WIN32
+
+ UInt32 realProcessedSize;
+ BOOL res = TRUE;
+ if (size > 0)
+ {
+ // Seems that Windows doesn't like big amounts writing to stdout.
+ // So we limit portions by 32KB.
+ UInt32 sizeTemp = (1 << 15);
+ if (sizeTemp > size)
+ sizeTemp = size;
+ res = ::WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),
+ data, sizeTemp, (DWORD *)&realProcessedSize, NULL);
+ _size += realProcessedSize;
+ size -= realProcessedSize;
+ data = (const void *)((const Byte *)data + realProcessedSize);
+ if (processedSize)
+ *processedSize += realProcessedSize;
+ }
+ return ConvertBoolToHRESULT(res != FALSE);
+
+ #else
+
+ ssize_t res;
+
+ do
+ {
+ res = write(1, data, (size_t)size);
+ }
+ while (res < 0 && (errno == EINTR));
+
+ if (res == -1)
+ return GetLastError_HRESULT();
+
+ _size += (size_t)res;
+ if (processedSize)
+ *processedSize = (UInt32)res;
+ return S_OK;
+
+ #endif
+}
+
+#endif
diff --git a/CPP/7zip/Common/FileStreams.h b/CPP/7zip/Common/FileStreams.h
index a0996f8..7e1b086 100644
--- a/CPP/7zip/Common/FileStreams.h
+++ b/CPP/7zip/Common/FileStreams.h
@@ -1,166 +1,186 @@
-// FileStreams.h
-
-#ifndef __FILE_STREAMS_H
-#define __FILE_STREAMS_H
-
-#ifdef _WIN32
-#define USE_WIN_FILE
-#endif
-
-#include "../../Common/MyString.h"
-
-#ifdef USE_WIN_FILE
-#include "../../Windows/FileIO.h"
-#else
-#include "../../Common/C_FileIO.h"
-#endif
-
-#include "../../Common/MyCom.h"
-
-#include "../IStream.h"
-
-#ifdef _WIN32
-typedef UINT_PTR My_UINT_PTR;
-#else
-typedef UINT My_UINT_PTR;
-#endif
-
-struct IInFileStream_Callback
-{
- virtual HRESULT InFileStream_On_Error(My_UINT_PTR val, DWORD error) = 0;
- virtual void InFileStream_On_Destroy(My_UINT_PTR val) = 0;
-};
-
-class CInFileStream:
- public IInStream,
- public IStreamGetSize,
- #ifdef USE_WIN_FILE
- public IStreamGetProps,
- public IStreamGetProps2,
- #endif
- public CMyUnknownImp
-{
-public:
- #ifdef USE_WIN_FILE
- NWindows::NFile::NIO::CInFile File;
-
- #ifdef SUPPORT_DEVICE_FILE
- UInt64 VirtPos;
- UInt64 PhyPos;
- UInt64 BufStartPos;
- Byte *Buf;
- UInt32 BufSize;
- #endif
-
- #else
- NC::NFile::NIO::CInFile File;
- #endif
-
- bool SupportHardLinks;
-
- IInFileStream_Callback *Callback;
- My_UINT_PTR CallbackRef;
-
- virtual ~CInFileStream();
-
- CInFileStream();
-
- bool Open(CFSTR fileName)
- {
- return File.Open(fileName);
- }
-
- bool OpenShared(CFSTR fileName, bool shareForWrite)
- {
- return File.OpenShared(fileName, shareForWrite);
- }
-
- MY_QUERYINTERFACE_BEGIN2(IInStream)
- MY_QUERYINTERFACE_ENTRY(IStreamGetSize)
- #ifdef USE_WIN_FILE
- MY_QUERYINTERFACE_ENTRY(IStreamGetProps)
- MY_QUERYINTERFACE_ENTRY(IStreamGetProps2)
- #endif
- MY_QUERYINTERFACE_END
- MY_ADDREF_RELEASE
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
-
- STDMETHOD(GetSize)(UInt64 *size);
- #ifdef USE_WIN_FILE
- STDMETHOD(GetProps)(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib);
- STDMETHOD(GetProps2)(CStreamFileProps *props);
- #endif
-};
-
-class CStdInFileStream:
- public ISequentialInStream,
- public CMyUnknownImp
-{
-public:
- MY_UNKNOWN_IMP
-
- virtual ~CStdInFileStream() {}
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
-};
-
-class COutFileStream:
- public IOutStream,
- public CMyUnknownImp
-{
-public:
- #ifdef USE_WIN_FILE
- NWindows::NFile::NIO::COutFile File;
- #else
- NC::NFile::NIO::COutFile File;
- #endif
- virtual ~COutFileStream() {}
- bool Create(CFSTR fileName, bool createAlways)
- {
- ProcessedSize = 0;
- return File.Create(fileName, createAlways);
- }
- bool Open(CFSTR fileName, DWORD creationDisposition)
- {
- ProcessedSize = 0;
- return File.Open(fileName, creationDisposition);
- }
-
- HRESULT Close();
-
- UInt64 ProcessedSize;
-
- #ifdef USE_WIN_FILE
- bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime)
- {
- return File.SetTime(cTime, aTime, mTime);
- }
- bool SetMTime(const FILETIME *mTime) { return File.SetMTime(mTime); }
- #endif
-
-
- MY_UNKNOWN_IMP1(IOutStream)
-
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
- STDMETHOD(SetSize)(UInt64 newSize);
-
- HRESULT GetSize(UInt64 *size);
-};
-
-class CStdOutFileStream:
- public ISequentialOutStream,
- public CMyUnknownImp
-{
- UInt64 _size;
-public:
- MY_UNKNOWN_IMP
-
- UInt64 GetSize() const { return _size; }
- CStdOutFileStream(): _size(0) {}
- virtual ~CStdOutFileStream() {}
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
-};
-
-#endif
+// FileStreams.h
+
+#ifndef ZIP7_INC_FILE_STREAMS_H
+#define ZIP7_INC_FILE_STREAMS_H
+
+#ifdef _WIN32
+#define Z7_FILE_STREAMS_USE_WIN_FILE
+#endif
+
+#include "../../Common/MyCom.h"
+#include "../../Common/MyString.h"
+
+#include "../../Windows/FileIO.h"
+
+#include "../IStream.h"
+
+#include "UniqBlocks.h"
+
+
+class CInFileStream;
+
+Z7_PURE_INTERFACES_BEGIN
+DECLARE_INTERFACE(IInFileStream_Callback)
+{
+ virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error) = 0;
+ virtual void InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val) = 0;
+};
+Z7_PURE_INTERFACES_END
+
+
+/*
+Z7_CLASS_IMP_COM_5(
+ CInFileStream
+ , IInStream
+ , IStreamGetSize
+ , IStreamGetProps
+ , IStreamGetProps2
+ , IStreamGetProp
+)
+*/
+Z7_class_final(CInFileStream) :
+ public IInStream,
+ public IStreamGetSize,
+ public IStreamGetProps,
+ public IStreamGetProps2,
+ public IStreamGetProp,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_5(
+ IInStream,
+ IStreamGetSize,
+ IStreamGetProps,
+ IStreamGetProps2,
+ IStreamGetProp)
+
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+ Z7_IFACE_COM7_IMP(IInStream)
+public:
+ Z7_IFACE_COM7_IMP(IStreamGetSize)
+private:
+ Z7_IFACE_COM7_IMP(IStreamGetProps)
+public:
+ Z7_IFACE_COM7_IMP(IStreamGetProps2)
+ Z7_IFACE_COM7_IMP(IStreamGetProp)
+
+private:
+ NWindows::NFile::NIO::CInFile File;
+public:
+
+ #ifdef Z7_FILE_STREAMS_USE_WIN_FILE
+
+ #ifdef Z7_DEVICE_FILE
+ UInt64 VirtPos;
+ UInt64 PhyPos;
+ UInt64 BufStartPos;
+ Byte *Buf;
+ UInt32 BufSize;
+ #endif
+
+ #endif
+
+ #ifdef _WIN32
+ BY_HANDLE_FILE_INFORMATION _info;
+ #else
+ struct stat _info;
+ UInt32 _uid;
+ UInt32 _gid;
+ UString OwnerName;
+ UString OwnerGroup;
+ bool StoreOwnerId;
+ bool StoreOwnerName;
+ #endif
+
+ bool _info_WasLoaded;
+ bool SupportHardLinks;
+ IInFileStream_Callback *Callback;
+ UINT_PTR CallbackRef;
+
+ CInFileStream();
+ ~CInFileStream();
+
+ void Set_PreserveATime(bool v)
+ {
+ File.PreserveATime = v;
+ }
+
+ bool GetLength(UInt64 &length) const throw()
+ {
+ return File.GetLength(length);
+ }
+
+ bool Open(CFSTR fileName)
+ {
+ _info_WasLoaded = false;
+ return File.Open(fileName);
+ }
+
+ bool OpenShared(CFSTR fileName, bool shareForWrite)
+ {
+ _info_WasLoaded = false;
+ return File.OpenShared(fileName, shareForWrite);
+ }
+};
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ CStdInFileStream
+ , ISequentialInStream
+)
+};
+
+
+Z7_CLASS_IMP_COM_1(
+ COutFileStream
+ , IOutStream
+)
+ Z7_IFACE_COM7_IMP(ISequentialOutStream)
+public:
+
+ NWindows::NFile::NIO::COutFile File;
+
+ bool Create(CFSTR fileName, bool createAlways)
+ {
+ ProcessedSize = 0;
+ return File.Create(fileName, createAlways);
+ }
+ bool Open(CFSTR fileName, DWORD creationDisposition)
+ {
+ ProcessedSize = 0;
+ return File.Open(fileName, creationDisposition);
+ }
+
+ HRESULT Close();
+
+ UInt64 ProcessedSize;
+
+ bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime)
+ {
+ return File.SetTime(cTime, aTime, mTime);
+ }
+ bool SetMTime(const CFiTime *mTime) { return File.SetMTime(mTime); }
+
+ bool SeekToBegin_bool()
+ {
+ #ifdef Z7_FILE_STREAMS_USE_WIN_FILE
+ return File.SeekToBegin();
+ #else
+ return File.seekToBegin() == 0;
+ #endif
+ }
+
+ HRESULT GetSize(UInt64 *size);
+};
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ CStdOutFileStream
+ , ISequentialOutStream
+)
+ UInt64 _size;
+public:
+ UInt64 GetSize() const { return _size; }
+ CStdOutFileStream(): _size(0) {}
+};
+
+#endif
diff --git a/CPP/7zip/Common/FilterCoder.cpp b/CPP/7zip/Common/FilterCoder.cpp
index d5c7ff0..8d7e0dc 100644
--- a/CPP/7zip/Common/FilterCoder.cpp
+++ b/CPP/7zip/Common/FilterCoder.cpp
@@ -1,435 +1,577 @@
-// FilterCoder.cpp
-
-#include "StdAfx.h"
-
-#include "../../Common/Defs.h"
-
-#include "FilterCoder.h"
-#include "StreamUtils.h"
-
-#ifdef _WIN32
- #define alignedMidBuffer_Alloc g_MidAlloc
-#else
- #define alignedMidBuffer_Alloc g_AlignedAlloc
-#endif
-
-CAlignedMidBuffer::~CAlignedMidBuffer()
-{
- ISzAlloc_Free(&alignedMidBuffer_Alloc, _buf);
-}
-
-void CAlignedMidBuffer::AllocAligned(size_t size)
-{
- ISzAlloc_Free(&alignedMidBuffer_Alloc, _buf);
- _buf = (Byte *)ISzAlloc_Alloc(&alignedMidBuffer_Alloc, size);
-}
-
-/*
- AES filters need 16-bytes alignment for HARDWARE-AES instructions.
- So we call IFilter::Filter(, size), where (size != 16 * N) only for last data block.
-
- AES-CBC filters need data size aligned for 16-bytes.
- So the encoder can add zeros to the end of original stream.
-
- Some filters (BCJ and others) don't process data at the end of stream in some cases.
- So the encoder and decoder write such last bytes without change.
-*/
-
-
-static const UInt32 kBufSize = 1 << 20;
-
-STDMETHODIMP CFilterCoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSize = size; return S_OK; }
-STDMETHODIMP CFilterCoder::SetOutBufSize(UInt32 , UInt32 size) { _outBufSize = size; return S_OK; }
-
-HRESULT CFilterCoder::Alloc()
-{
- UInt32 size = MyMin(_inBufSize, _outBufSize);
- /* minimal bufSize is 16 bytes for AES and IA64 filter.
- bufSize for AES must be aligned for 16 bytes.
- We use (1 << 12) min size to support future aligned filters. */
- const UInt32 kMinSize = 1 << 12;
- size &= ~(UInt32)(kMinSize - 1);
- if (size < kMinSize)
- size = kMinSize;
- if (!_buf || _bufSize != size)
- {
- AllocAligned(size);
- if (!_buf)
- return E_OUTOFMEMORY;
- _bufSize = size;
- }
- return S_OK;
-}
-
-HRESULT CFilterCoder::Init_and_Alloc()
-{
- RINOK(Filter->Init());
- return Alloc();
-}
-
-CFilterCoder::CFilterCoder(bool encodeMode):
- _bufSize(0),
- _inBufSize(kBufSize),
- _outBufSize(kBufSize),
- _encodeMode(encodeMode),
- _outSizeIsDefined(false),
- _outSize(0),
- _nowPos64(0)
- {}
-
-CFilterCoder::~CFilterCoder()
-{
-}
-
-STDMETHODIMP CFilterCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
-{
- RINOK(Init_and_Alloc());
-
- UInt64 nowPos64 = 0;
- bool inputFinished = false;
- UInt32 pos = 0;
-
- while (!outSize || nowPos64 < *outSize)
- {
- UInt32 endPos = pos;
-
- if (!inputFinished)
- {
- size_t processedSize = _bufSize - pos;
- RINOK(ReadStream(inStream, _buf + pos, &processedSize));
- endPos = pos + (UInt32)processedSize;
- inputFinished = (endPos != _bufSize);
- }
-
- pos = Filter->Filter(_buf, endPos);
-
- if (pos > endPos)
- {
- // AES
- if (!inputFinished || pos > _bufSize)
- return E_FAIL;
- if (!_encodeMode)
- return S_FALSE;
-
- do
- _buf[endPos] = 0;
- while (++endPos != pos);
-
- if (pos != Filter->Filter(_buf, pos))
- return E_FAIL;
- }
-
- if (endPos == 0)
- return S_OK;
-
- UInt32 size = (pos != 0 ? pos : endPos);
- if (outSize)
- {
- UInt64 remSize = *outSize - nowPos64;
- if (size > remSize)
- size = (UInt32)remSize;
- }
-
- RINOK(WriteStream(outStream, _buf, size));
- nowPos64 += size;
-
- if (pos == 0)
- return S_OK;
-
- if (progress)
- RINOK(progress->SetRatioInfo(&nowPos64, &nowPos64));
-
- UInt32 i = 0;
- while (pos < endPos)
- _buf[i++] = _buf[pos++];
- pos = i;
- }
-
- return S_OK;
-}
-
-
-
-// ---------- Write to Filter ----------
-
-STDMETHODIMP CFilterCoder::SetOutStream(ISequentialOutStream *outStream)
-{
- _outStream = outStream;
- return S_OK;
-}
-
-STDMETHODIMP CFilterCoder::ReleaseOutStream()
-{
- _outStream.Release();
- return S_OK;
-}
-
-HRESULT CFilterCoder::Flush2()
-{
- while (_convSize != 0)
- {
- UInt32 num = _convSize;
- if (_outSizeIsDefined)
- {
- UInt64 rem = _outSize - _nowPos64;
- if (num > rem)
- num = (UInt32)rem;
- if (num == 0)
- return k_My_HRESULT_WritingWasCut;
- }
-
- UInt32 processed = 0;
- HRESULT res = _outStream->Write(_buf + _convPos, num, &processed);
- if (processed == 0)
- return res != S_OK ? res : E_FAIL;
-
- _convPos += processed;
- _convSize -= processed;
- _nowPos64 += processed;
- RINOK(res);
- }
-
- if (_convPos != 0)
- {
- UInt32 num = _bufPos - _convPos;
- for (UInt32 i = 0; i < num; i++)
- _buf[i] = _buf[_convPos + i];
- _bufPos = num;
- _convPos = 0;
- }
-
- return S_OK;
-}
-
-STDMETHODIMP CFilterCoder::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
-
- while (size != 0)
- {
- RINOK(Flush2());
-
- // _convSize is 0
- // _convPos is 0
- // _bufPos is small
-
- if (_bufPos != _bufSize)
- {
- UInt32 num = MyMin(size, _bufSize - _bufPos);
- memcpy(_buf + _bufPos, data, num);
- size -= num;
- data = (const Byte *)data + num;
- if (processedSize)
- *processedSize += num;
- _bufPos += num;
- if (_bufPos != _bufSize)
- continue;
- }
-
- // _bufPos == _bufSize
- _convSize = Filter->Filter(_buf, _bufPos);
-
- if (_convSize == 0)
- break;
- if (_convSize > _bufPos)
- {
- // that case is not possible.
- _convSize = 0;
- return E_FAIL;
- }
- }
-
- return S_OK;
-}
-
-STDMETHODIMP CFilterCoder::OutStreamFinish()
-{
- for (;;)
- {
- RINOK(Flush2());
- if (_bufPos == 0)
- break;
- _convSize = Filter->Filter(_buf, _bufPos);
- if (_convSize == 0)
- _convSize = _bufPos;
- else if (_convSize > _bufPos)
- {
- // AES
- if (_convSize > _bufSize)
- {
- _convSize = 0;
- return E_FAIL;
- }
- if (!_encodeMode)
- {
- _convSize = 0;
- return S_FALSE;
- }
- for (; _bufPos < _convSize; _bufPos++)
- _buf[_bufPos] = 0;
- _convSize = Filter->Filter(_buf, _bufPos);
- if (_convSize != _bufPos)
- return E_FAIL;
- }
- }
-
- CMyComPtr<IOutStreamFinish> finish;
- _outStream.QueryInterface(IID_IOutStreamFinish, &finish);
- if (finish)
- return finish->OutStreamFinish();
- return S_OK;
-}
-
-// ---------- Init functions ----------
-
-STDMETHODIMP CFilterCoder::InitEncoder()
-{
- InitSpecVars();
- return Init_and_Alloc();
-}
-
-HRESULT CFilterCoder::Init_NoSubFilterInit()
-{
- InitSpecVars();
- return Alloc();
-}
-
-STDMETHODIMP CFilterCoder::SetOutStreamSize(const UInt64 *outSize)
-{
- InitSpecVars();
- if (outSize)
- {
- _outSize = *outSize;
- _outSizeIsDefined = true;
- }
- return Init_and_Alloc();
-}
-
-// ---------- Read from Filter ----------
-
-STDMETHODIMP CFilterCoder::SetInStream(ISequentialInStream *inStream)
-{
- _inStream = inStream;
- return S_OK;
-}
-
-STDMETHODIMP CFilterCoder::ReleaseInStream()
-{
- _inStream.Release();
- return S_OK;
-}
-
-
-STDMETHODIMP CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
-
- while (size != 0)
- {
- if (_convSize != 0)
- {
- if (size > _convSize)
- size = _convSize;
- if (_outSizeIsDefined)
- {
- UInt64 rem = _outSize - _nowPos64;
- if (size > rem)
- size = (UInt32)rem;
- }
- memcpy(data, _buf + _convPos, size);
- _convPos += size;
- _convSize -= size;
- _nowPos64 += size;
- if (processedSize)
- *processedSize = size;
- break;
- }
-
- if (_convPos != 0)
- {
- UInt32 num = _bufPos - _convPos;
- for (UInt32 i = 0; i < num; i++)
- _buf[i] = _buf[_convPos + i];
- _bufPos = num;
- _convPos = 0;
- }
-
- {
- size_t readSize = _bufSize - _bufPos;
- HRESULT res = ReadStream(_inStream, _buf + _bufPos, &readSize);
- _bufPos += (UInt32)readSize;
- RINOK(res);
- }
-
- _convSize = Filter->Filter(_buf, _bufPos);
-
- if (_convSize == 0)
- {
- if (_bufPos == 0)
- break;
- // BCJ
- _convSize = _bufPos;
- continue;
- }
-
- if (_convSize > _bufPos)
- {
- // AES
- if (_convSize > _bufSize)
- return E_FAIL;
- if (!_encodeMode)
- return S_FALSE;
-
- do
- _buf[_bufPos] = 0;
- while (++_bufPos != _convSize);
-
- _convSize = Filter->Filter(_buf, _convSize);
- if (_convSize != _bufPos)
- return E_FAIL;
- }
- }
-
- return S_OK;
-}
-
-
-#ifndef _NO_CRYPTO
-
-STDMETHODIMP CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size)
- { return _SetPassword->CryptoSetPassword(data, size); }
-
-STDMETHODIMP CFilterCoder::SetKey(const Byte *data, UInt32 size)
- { return _CryptoProperties->SetKey(data, size); }
-
-STDMETHODIMP CFilterCoder::SetInitVector(const Byte *data, UInt32 size)
- { return _CryptoProperties->SetInitVector(data, size); }
-
-#endif
-
-
-#ifndef EXTRACT_ONLY
-
-STDMETHODIMP CFilterCoder::SetCoderProperties(const PROPID *propIDs,
- const PROPVARIANT *properties, UInt32 numProperties)
- { return _SetCoderProperties->SetCoderProperties(propIDs, properties, numProperties); }
-
-STDMETHODIMP CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream)
- { return _WriteCoderProperties->WriteCoderProperties(outStream); }
-
-/*
-STDMETHODIMP CFilterCoder::ResetSalt()
- { return _CryptoResetSalt->ResetSalt(); }
-*/
-
-STDMETHODIMP CFilterCoder::ResetInitVector()
- { return _CryptoResetInitVector->ResetInitVector(); }
-
-#endif
-
-
-STDMETHODIMP CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size)
- { return _SetDecoderProperties2->SetDecoderProperties2(data, size); }
+// FilterCoder.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../Common/Defs.h"
+
+#include "FilterCoder.h"
+#include "StreamUtils.h"
+
+#ifdef _WIN32
+ #define alignedMidBuffer_Alloc g_MidAlloc
+#else
+ #define alignedMidBuffer_Alloc g_AlignedAlloc
+#endif
+
+CAlignedMidBuffer::~CAlignedMidBuffer()
+{
+ ISzAlloc_Free(&alignedMidBuffer_Alloc, _buf);
+}
+
+void CAlignedMidBuffer::AllocAligned(size_t size)
+{
+ ISzAlloc_Free(&alignedMidBuffer_Alloc, _buf);
+ _buf = (Byte *)ISzAlloc_Alloc(&alignedMidBuffer_Alloc, size);
+}
+
+/*
+ AES filters need 16-bytes alignment for HARDWARE-AES instructions.
+ So we call IFilter::Filter(, size), where (size != 16 * N) only for last data block.
+
+ AES-CBC filters need data size aligned for 16-bytes.
+ So the encoder can add zeros to the end of original stream.
+
+ Some filters (BCJ and others) don't process data at the end of stream in some cases.
+ So the encoder and decoder write such last bytes without change.
+
+ Most filters process all data, if we send aligned size to filter.
+ But BCJ filter can process up 4 bytes less than sent size.
+ And ARMT filter can process 2 bytes less than sent size.
+*/
+
+
+static const UInt32 kBufSize = 1 << 21;
+
+Z7_COM7F_IMF(CFilterCoder::SetInBufSize(UInt32 , UInt32 size)) { _inBufSize = size; return S_OK; }
+Z7_COM7F_IMF(CFilterCoder::SetOutBufSize(UInt32 , UInt32 size)) { _outBufSize = size; return S_OK; }
+
+HRESULT CFilterCoder::Alloc()
+{
+ UInt32 size = MyMin(_inBufSize, _outBufSize);
+ /* minimal bufSize is 16 bytes for AES and IA64 filter.
+ bufSize for AES must be aligned for 16 bytes.
+ We use (1 << 12) min size to support future aligned filters. */
+ const UInt32 kMinSize = 1 << 12;
+ size &= ~(UInt32)(kMinSize - 1);
+ if (size < kMinSize)
+ size = kMinSize;
+ // size = (1 << 12); // + 117; // for debug
+ if (!_buf || _bufSize != size)
+ {
+ AllocAligned(size);
+ if (!_buf)
+ return E_OUTOFMEMORY;
+ _bufSize = size;
+ }
+ return S_OK;
+}
+
+HRESULT CFilterCoder::Init_and_Alloc()
+{
+ RINOK(Filter->Init())
+ return Alloc();
+}
+
+CFilterCoder::CFilterCoder(bool encodeMode):
+ _bufSize(0),
+ _inBufSize(kBufSize),
+ _outBufSize(kBufSize),
+ _encodeMode(encodeMode),
+ _outSize_Defined(false),
+ _outSize(0),
+ _nowPos64(0)
+ {}
+
+
+Z7_COM7F_IMF(CFilterCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ RINOK(Init_and_Alloc())
+
+ /*
+ It's expected that BCJ/ARMT filter can process up to 4 bytes less
+ than sent data size. For such BCJ/ARMT cases with non-filtered data we:
+ - write some filtered data to output stream
+ - move non-written data (filtered and non-filtered data) to start of buffer
+ - read more new data from input stream to position after end of non-filtered data
+ - call Filter() for concatenated data in buffer.
+
+ For all cases, even for cases with partial filtering (BCJ/ARMT),
+ we try to keep real/virtual alignment for all operations
+ (memmove, Read(), Filter(), Write()).
+ We use (kAlignSize=64) alignmnent that is larger than (16-bytes)
+ required for AES filter alignment.
+
+ AES-CBC uses 16-bytes blocks, that is simple case for processing here,
+ if we call Filter() for aligned size for all calls except of last call (last block).
+ And now there are no filters that use blocks with non-power2 size,
+ but we try to support such non-power2 filters too here at Code().
+ */
+
+ UInt64 prev = 0;
+ UInt64 nowPos64 = 0;
+ bool inputFinished = false;
+ UInt32 readPos = 0;
+ UInt32 filterPos = 0;
+
+ while (!outSize || nowPos64 < *outSize)
+ {
+ HRESULT hres = S_OK;
+ if (!inputFinished)
+ {
+ size_t processedSize = _bufSize - readPos;
+ /* for AES filters we need at least max(16, kAlignSize) bytes in buffer.
+ But we try to read full buffer to reduce the number of Filter() and Write() calls.
+ */
+ hres = ReadStream(inStream, _buf + readPos, &processedSize);
+ readPos += (UInt32)processedSize;
+ inputFinished = (readPos != _bufSize);
+ if (hres != S_OK)
+ {
+ // do we need to stop encoding after reading error?
+ // if (_encodeMode) return hres;
+ inputFinished = true;
+ }
+ }
+
+ if (readPos == 0)
+ return hres;
+
+ /* we set (needMoreInput = true), if it's block-filter (like AES-CBC)
+ that needs more data for current block filtering:
+ We read full input buffer with Read(), and _bufSize is aligned,
+ So the possible cases when we set (needMoreInput = true) are:
+ 1) decode : filter needs more data after the end of input stream.
+ another cases are possible for non-power2-block-filter,
+ because buffer size is not aligned for filter_non_power2_block_size:
+ 2) decode/encode : filter needs more data from non-finished input stream
+ 3) encode : filter needs more space for zeros after the end of input stream
+ */
+ bool needMoreInput = false;
+
+ while (readPos != filterPos)
+ {
+ /* Filter() is allowed to process part of data.
+ Here we use the loop to filter as max as possible.
+ when we call Filter(data, size):
+ if (size < 16), AES-CTR filter uses internal 16-byte buffer.
+ new (since v23.00) AES-CTR filter allows (size < 16) for non-last block,
+ but it will work less efficiently than calls with aligned (size).
+ We still support old (before v23.00) AES-CTR filters here.
+ We have aligned (size) for AES-CTR, if it's not last block.
+ We have aligned (readPos) for any filter, if (!inputFinished).
+ We also meet the requirements for (data) pointer in Filter() call:
+ {
+ (virtual_stream_offset % aligment_size) == (data_ptr % aligment_size)
+ (aligment_size == 2^N)
+ (aligment_size >= 16)
+ }
+ */
+ const UInt32 cur = Filter->Filter(_buf + filterPos, readPos - filterPos);
+ if (cur == 0)
+ break;
+ const UInt32 f = filterPos + cur;
+ if (cur > readPos - filterPos)
+ {
+ // AES-CBC
+ if (hres != S_OK)
+ break;
+
+ if (!_encodeMode
+ || cur > _bufSize - filterPos
+ || !inputFinished)
+ {
+ /* (cur > _bufSize - filterPos) is unexpected for AES filter, if _bufSize is multiply of 16.
+ But we support this case, if some future filter will use block with non-power2-size.
+ */
+ needMoreInput = true;
+ break;
+ }
+
+ /* (_encodeMode && inputFinished).
+ We add zero bytes as pad in current block after the end of read data. */
+ Byte *buf = _buf;
+ do
+ buf[readPos] = 0;
+ while (++readPos != f);
+ // (readPos) now is (size_of_real_input_data + size_of_zero_pad)
+ if (cur != Filter->Filter(buf + filterPos, cur))
+ return E_FAIL;
+ }
+ filterPos = f;
+ }
+
+ UInt32 size = filterPos;
+ if (hres == S_OK)
+ {
+ /* If we need more Read() or Filter() calls, then we need to Write()
+ some data and move unwritten data to get additional space in buffer.
+ We try to keep alignment for data moves, Read(), Filter() and Write() calls.
+ */
+ const UInt32 kAlignSize = 1 << 6;
+ const UInt32 alignedFiltered = filterPos & ~(kAlignSize - 1);
+ if (inputFinished)
+ {
+ if (!needMoreInput)
+ size = readPos; // for risc/bcj filters in last block we write data after filterPos.
+ else if (_encodeMode)
+ size = alignedFiltered; // for non-power2-block-encode-filter
+ }
+ else
+ size = alignedFiltered;
+ }
+
+ {
+ UInt32 writeSize = size;
+ if (outSize)
+ {
+ const UInt64 rem = *outSize - nowPos64;
+ if (writeSize > rem)
+ writeSize = (UInt32)rem;
+ }
+ RINOK(WriteStream(outStream, _buf, writeSize))
+ nowPos64 += writeSize;
+ }
+
+ if (hres != S_OK)
+ return hres;
+
+ if (inputFinished)
+ {
+ if (readPos == size)
+ return hres;
+ if (!_encodeMode)
+ {
+ // block-decode-filter (AES-CBS) has non-full last block
+ // we don't want unaligned data move for more iterations with this error case.
+ return S_FALSE;
+ }
+ }
+
+ if (size == 0)
+ {
+ // it's unexpected that we have no any move in this iteration.
+ return E_FAIL;
+ }
+ // if (size != 0)
+ {
+ if (filterPos < size)
+ return E_FAIL; // filterPos = 0; else
+ filterPos -= size;
+ readPos -= size;
+ if (readPos != 0)
+ memmove(_buf, _buf + size, readPos);
+ }
+ // printf("\nnowPos64=%x, readPos=%x, filterPos=%x\n", (unsigned)nowPos64, (unsigned)readPos, (unsigned)filterPos);
+
+ if (progress && (nowPos64 - prev) >= (1 << 22))
+ {
+ prev = nowPos64;
+ RINOK(progress->SetRatioInfo(&nowPos64, &nowPos64))
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+// ---------- Write to Filter ----------
+
+Z7_COM7F_IMF(CFilterCoder::SetOutStream(ISequentialOutStream *outStream))
+{
+ _outStream = outStream;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFilterCoder::ReleaseOutStream())
+{
+ _outStream.Release();
+ return S_OK;
+}
+
+HRESULT CFilterCoder::Flush2()
+{
+ while (_convSize != 0)
+ {
+ UInt32 num = _convSize;
+ if (_outSize_Defined)
+ {
+ const UInt64 rem = _outSize - _nowPos64;
+ if (num > rem)
+ num = (UInt32)rem;
+ if (num == 0)
+ return k_My_HRESULT_WritingWasCut;
+ }
+
+ UInt32 processed = 0;
+ const HRESULT res = _outStream->Write(_buf + _convPos, num, &processed);
+ if (processed == 0)
+ return res != S_OK ? res : E_FAIL;
+
+ _convPos += processed;
+ _convSize -= processed;
+ _nowPos64 += processed;
+ RINOK(res)
+ }
+
+ const UInt32 convPos = _convPos;
+ if (convPos != 0)
+ {
+ const UInt32 num = _bufPos - convPos;
+ Byte *buf = _buf;
+ for (UInt32 i = 0; i < num; i++)
+ buf[i] = buf[convPos + i];
+ _bufPos = num;
+ _convPos = 0;
+ }
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFilterCoder::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+
+ while (size != 0)
+ {
+ RINOK(Flush2())
+
+ // _convSize is 0
+ // _convPos is 0
+ // _bufPos is small
+
+ if (_bufPos != _bufSize)
+ {
+ UInt32 num = MyMin(size, _bufSize - _bufPos);
+ memcpy(_buf + _bufPos, data, num);
+ size -= num;
+ data = (const Byte *)data + num;
+ if (processedSize)
+ *processedSize += num;
+ _bufPos += num;
+ if (_bufPos != _bufSize)
+ continue;
+ }
+
+ // _bufPos == _bufSize
+ _convSize = Filter->Filter(_buf, _bufPos);
+
+ if (_convSize == 0)
+ break;
+ if (_convSize > _bufPos)
+ {
+ // that case is not possible.
+ _convSize = 0;
+ return E_FAIL;
+ }
+ }
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFilterCoder::OutStreamFinish())
+{
+ for (;;)
+ {
+ RINOK(Flush2())
+ if (_bufPos == 0)
+ break;
+ const UInt32 convSize = Filter->Filter(_buf, _bufPos);
+ _convSize = convSize;
+ UInt32 bufPos = _bufPos;
+ if (convSize == 0)
+ _convSize = bufPos;
+ else if (convSize > bufPos)
+ {
+ // AES
+ if (convSize > _bufSize)
+ {
+ _convSize = 0;
+ return E_FAIL;
+ }
+ if (!_encodeMode)
+ {
+ _convSize = 0;
+ return S_FALSE;
+ }
+ Byte *buf = _buf;
+ for (; bufPos < convSize; bufPos++)
+ buf[bufPos] = 0;
+ _bufPos = bufPos;
+ _convSize = Filter->Filter(_buf, bufPos);
+ if (_convSize != _bufPos)
+ return E_FAIL;
+ }
+ }
+
+ CMyComPtr<IOutStreamFinish> finish;
+ _outStream.QueryInterface(IID_IOutStreamFinish, &finish);
+ if (finish)
+ return finish->OutStreamFinish();
+ return S_OK;
+}
+
+// ---------- Init functions ----------
+
+Z7_COM7F_IMF(CFilterCoder::InitEncoder())
+{
+ InitSpecVars();
+ return Init_and_Alloc();
+}
+
+HRESULT CFilterCoder::Init_NoSubFilterInit()
+{
+ InitSpecVars();
+ return Alloc();
+}
+
+Z7_COM7F_IMF(CFilterCoder::SetOutStreamSize(const UInt64 *outSize))
+{
+ InitSpecVars();
+ if (outSize)
+ {
+ _outSize = *outSize;
+ _outSize_Defined = true;
+ }
+ return Init_and_Alloc();
+}
+
+// ---------- Read from Filter ----------
+
+Z7_COM7F_IMF(CFilterCoder::SetInStream(ISequentialInStream *inStream))
+{
+ _inStream = inStream;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFilterCoder::ReleaseInStream())
+{
+ _inStream.Release();
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CFilterCoder::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+
+ while (size != 0)
+ {
+ if (_convSize != 0)
+ {
+ if (size > _convSize)
+ size = _convSize;
+ if (_outSize_Defined)
+ {
+ const UInt64 rem = _outSize - _nowPos64;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+ memcpy(data, _buf + _convPos, size);
+ _convPos += size;
+ _convSize -= size;
+ _nowPos64 += size;
+ if (processedSize)
+ *processedSize = size;
+ break;
+ }
+
+ const UInt32 convPos = _convPos;
+ if (convPos != 0)
+ {
+ const UInt32 num = _bufPos - convPos;
+ Byte *buf = _buf;
+ for (UInt32 i = 0; i < num; i++)
+ buf[i] = buf[convPos + i];
+ _bufPos = num;
+ _convPos = 0;
+ }
+
+ {
+ size_t readSize = _bufSize - _bufPos;
+ const HRESULT res = ReadStream(_inStream, _buf + _bufPos, &readSize);
+ _bufPos += (UInt32)readSize;
+ RINOK(res)
+ }
+
+ const UInt32 convSize = Filter->Filter(_buf, _bufPos);
+ _convSize = convSize;
+
+ UInt32 bufPos = _bufPos;
+
+ if (convSize == 0)
+ {
+ if (bufPos == 0)
+ break;
+ // BCJ
+ _convSize = bufPos;
+ continue;
+ }
+
+ if (convSize > bufPos)
+ {
+ // AES
+ if (convSize > _bufSize)
+ return E_FAIL;
+ if (!_encodeMode)
+ return S_FALSE;
+ Byte *buf = _buf;
+ do
+ buf[bufPos] = 0;
+ while (++bufPos != convSize);
+ _bufPos = bufPos;
+ _convSize = Filter->Filter(_buf, convSize);
+ if (_convSize != _bufPos)
+ return E_FAIL;
+ }
+ }
+
+ return S_OK;
+}
+
+
+#ifndef Z7_NO_CRYPTO
+
+Z7_COM7F_IMF(CFilterCoder::CryptoSetPassword(const Byte *data, UInt32 size))
+ { return _setPassword->CryptoSetPassword(data, size); }
+
+Z7_COM7F_IMF(CFilterCoder::SetKey(const Byte *data, UInt32 size))
+ { return _cryptoProperties->SetKey(data, size); }
+
+Z7_COM7F_IMF(CFilterCoder::SetInitVector(const Byte *data, UInt32 size))
+ { return _cryptoProperties->SetInitVector(data, size); }
+
+#endif
+
+
+#ifndef Z7_EXTRACT_ONLY
+
+Z7_COM7F_IMF(CFilterCoder::SetCoderProperties(const PROPID *propIDs,
+ const PROPVARIANT *properties, UInt32 numProperties))
+ { return _setCoderProperties->SetCoderProperties(propIDs, properties, numProperties); }
+
+Z7_COM7F_IMF(CFilterCoder::WriteCoderProperties(ISequentialOutStream *outStream))
+ { return _writeCoderProperties->WriteCoderProperties(outStream); }
+
+Z7_COM7F_IMF(CFilterCoder::SetCoderPropertiesOpt(const PROPID *propIDs,
+ const PROPVARIANT *properties, UInt32 numProperties))
+ { return _setCoderPropertiesOpt->SetCoderPropertiesOpt(propIDs, properties, numProperties); }
+
+/*
+Z7_COM7F_IMF(CFilterCoder::ResetSalt()
+ { return _cryptoResetSalt->ResetSalt(); }
+*/
+
+Z7_COM7F_IMF(CFilterCoder::ResetInitVector())
+ { return _cryptoResetInitVector->ResetInitVector(); }
+
+#endif
+
+
+Z7_COM7F_IMF(CFilterCoder::SetDecoderProperties2(const Byte *data, UInt32 size))
+ { return _setDecoderProperties2->SetDecoderProperties2(data, size); }
diff --git a/CPP/7zip/Common/FilterCoder.h b/CPP/7zip/Common/FilterCoder.h
index bde0e2b..3a588fd 100644
--- a/CPP/7zip/Common/FilterCoder.h
+++ b/CPP/7zip/Common/FilterCoder.h
@@ -1,205 +1,201 @@
-// FilterCoder.h
-
-#ifndef __FILTER_CODER_H
-#define __FILTER_CODER_H
-
-#include "../../../C/Alloc.h"
-
-#include "../../Common/MyCom.h"
-#include "../ICoder.h"
-
-#ifndef _NO_CRYPTO
-#include "../IPassword.h"
-#endif
-
-#define MY_QUERYINTERFACE_ENTRY_AG(i, sub0, sub) else if (iid == IID_ ## i) \
- { if (!sub) RINOK(sub0->QueryInterface(IID_ ## i, (void **)&sub)) \
- *outObject = (void *)(i *)this; }
-
-
-struct CAlignedMidBuffer
-{
- Byte *_buf;
-
- CAlignedMidBuffer(): _buf(NULL) {}
- ~CAlignedMidBuffer();
- void AllocAligned(size_t size);
-};
-
-class CFilterCoder:
- public ICompressCoder,
-
- public ICompressSetOutStreamSize,
- public ICompressInitEncoder,
-
- public ICompressSetInStream,
- public ISequentialInStream,
-
- public ICompressSetOutStream,
- public ISequentialOutStream,
- public IOutStreamFinish,
-
- public ICompressSetBufSize,
-
- #ifndef _NO_CRYPTO
- public ICryptoSetPassword,
- public ICryptoProperties,
- #endif
-
- #ifndef EXTRACT_ONLY
- public ICompressSetCoderProperties,
- public ICompressWriteCoderProperties,
- // public ICryptoResetSalt,
- public ICryptoResetInitVector,
- #endif
-
- public ICompressSetDecoderProperties2,
- public CMyUnknownImp,
- public CAlignedMidBuffer
-{
- UInt32 _bufSize;
- UInt32 _inBufSize;
- UInt32 _outBufSize;
-
- bool _encodeMode;
- bool _outSizeIsDefined;
- UInt64 _outSize;
- UInt64 _nowPos64;
-
- CMyComPtr<ISequentialInStream> _inStream;
- CMyComPtr<ISequentialOutStream> _outStream;
- UInt32 _bufPos;
- UInt32 _convPos; // current pos in buffer for converted data
- UInt32 _convSize; // size of converted data starting from _convPos
-
- void InitSpecVars()
- {
- _bufPos = 0;
- _convPos = 0;
- _convSize = 0;
-
- _outSizeIsDefined = false;
- _outSize = 0;
- _nowPos64 = 0;
- }
-
- HRESULT Alloc();
- HRESULT Init_and_Alloc();
- HRESULT Flush2();
-
- #ifndef _NO_CRYPTO
- CMyComPtr<ICryptoSetPassword> _SetPassword;
- CMyComPtr<ICryptoProperties> _CryptoProperties;
- #endif
-
- #ifndef EXTRACT_ONLY
- CMyComPtr<ICompressSetCoderProperties> _SetCoderProperties;
- CMyComPtr<ICompressWriteCoderProperties> _WriteCoderProperties;
- // CMyComPtr<ICryptoResetSalt> _CryptoResetSalt;
- CMyComPtr<ICryptoResetInitVector> _CryptoResetInitVector;
- #endif
-
- CMyComPtr<ICompressSetDecoderProperties2> _SetDecoderProperties2;
-
-public:
- CMyComPtr<ICompressFilter> Filter;
-
- CFilterCoder(bool encodeMode);
- ~CFilterCoder();
-
- class C_InStream_Releaser
- {
- public:
- CFilterCoder *FilterCoder;
- C_InStream_Releaser(): FilterCoder(NULL) {}
- ~C_InStream_Releaser() { if (FilterCoder) FilterCoder->ReleaseInStream(); }
- };
-
- class C_OutStream_Releaser
- {
- public:
- CFilterCoder *FilterCoder;
- C_OutStream_Releaser(): FilterCoder(NULL) {}
- ~C_OutStream_Releaser() { if (FilterCoder) FilterCoder->ReleaseOutStream(); }
- };
-
- class C_Filter_Releaser
- {
- public:
- CFilterCoder *FilterCoder;
- C_Filter_Releaser(): FilterCoder(NULL) {}
- ~C_Filter_Releaser() { if (FilterCoder) FilterCoder->Filter.Release(); }
- };
-
-
- MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
-
- MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)
- MY_QUERYINTERFACE_ENTRY(ICompressInitEncoder)
-
- MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
- MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
-
- MY_QUERYINTERFACE_ENTRY(ICompressSetOutStream)
- MY_QUERYINTERFACE_ENTRY(ISequentialOutStream)
- MY_QUERYINTERFACE_ENTRY(IOutStreamFinish)
-
- MY_QUERYINTERFACE_ENTRY(ICompressSetBufSize)
-
- #ifndef _NO_CRYPTO
- MY_QUERYINTERFACE_ENTRY_AG(ICryptoSetPassword, Filter, _SetPassword)
- MY_QUERYINTERFACE_ENTRY_AG(ICryptoProperties, Filter, _CryptoProperties)
- #endif
-
- #ifndef EXTRACT_ONLY
- MY_QUERYINTERFACE_ENTRY_AG(ICompressSetCoderProperties, Filter, _SetCoderProperties)
- MY_QUERYINTERFACE_ENTRY_AG(ICompressWriteCoderProperties, Filter, _WriteCoderProperties)
- // MY_QUERYINTERFACE_ENTRY_AG(ICryptoResetSalt, Filter, _CryptoResetSalt)
- MY_QUERYINTERFACE_ENTRY_AG(ICryptoResetInitVector, Filter, _CryptoResetInitVector)
- #endif
-
- MY_QUERYINTERFACE_ENTRY_AG(ICompressSetDecoderProperties2, Filter, _SetDecoderProperties2)
- MY_QUERYINTERFACE_END
- MY_ADDREF_RELEASE
-
-
- STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
-
- STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
- STDMETHOD(InitEncoder)();
-
- STDMETHOD(SetInStream)(ISequentialInStream *inStream);
- STDMETHOD(ReleaseInStream)();
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
-
- STDMETHOD(SetOutStream)(ISequentialOutStream *outStream);
- STDMETHOD(ReleaseOutStream)();
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(OutStreamFinish)();
-
- STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);
- STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);
-
- #ifndef _NO_CRYPTO
- STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
-
- STDMETHOD(SetKey)(const Byte *data, UInt32 size);
- STDMETHOD(SetInitVector)(const Byte *data, UInt32 size);
- #endif
-
- #ifndef EXTRACT_ONLY
- STDMETHOD(SetCoderProperties)(const PROPID *propIDs,
- const PROPVARIANT *properties, UInt32 numProperties);
- STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
- // STDMETHOD(ResetSalt)();
- STDMETHOD(ResetInitVector)();
- #endif
-
- STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
-
-
- HRESULT Init_NoSubFilterInit();
-};
-
-#endif
+// FilterCoder.h
+
+#ifndef ZIP7_INC_FILTER_CODER_H
+#define ZIP7_INC_FILTER_CODER_H
+
+#include "../../../C/Alloc.h"
+
+#include "../../Common/MyCom.h"
+#include "../ICoder.h"
+
+#ifndef Z7_NO_CRYPTO
+#include "../IPassword.h"
+#endif
+
+#define Z7_COM_QI_ENTRY_AG(i, sub0, sub) else if (iid == IID_ ## i) \
+ { if (!sub) RINOK(sub0->QueryInterface(IID_ ## i, (void **)&sub)) \
+ *outObject = (void *)(i *)this; }
+
+
+struct CAlignedMidBuffer
+{
+ Byte *_buf;
+
+ CAlignedMidBuffer(): _buf(NULL) {}
+ ~CAlignedMidBuffer();
+ void AllocAligned(size_t size);
+};
+
+
+class CFilterCoder Z7_final :
+ public ICompressCoder,
+
+ public ICompressSetOutStreamSize,
+ public ICompressInitEncoder,
+
+ public ICompressSetInStream,
+ public ISequentialInStream,
+
+ public ICompressSetOutStream,
+ public ISequentialOutStream,
+ public IOutStreamFinish,
+
+ public ICompressSetBufSize,
+
+ #ifndef Z7_NO_CRYPTO
+ public ICryptoSetPassword,
+ public ICryptoProperties,
+ #endif
+
+ #ifndef Z7_EXTRACT_ONLY
+ public ICompressSetCoderProperties,
+ public ICompressWriteCoderProperties,
+ public ICompressSetCoderPropertiesOpt,
+ // public ICryptoResetSalt,
+ public ICryptoResetInitVector,
+ #endif
+
+ public ICompressSetDecoderProperties2,
+ public CMyUnknownImp,
+ public CAlignedMidBuffer
+{
+ UInt32 _bufSize;
+ UInt32 _inBufSize;
+ UInt32 _outBufSize;
+
+ bool _encodeMode;
+ bool _outSize_Defined;
+ UInt64 _outSize;
+ UInt64 _nowPos64;
+
+ CMyComPtr<ISequentialInStream> _inStream;
+ CMyComPtr<ISequentialOutStream> _outStream;
+ UInt32 _bufPos;
+ UInt32 _convPos; // current pos in buffer for converted data
+ UInt32 _convSize; // size of converted data starting from _convPos
+
+ void InitSpecVars()
+ {
+ _bufPos = 0;
+ _convPos = 0;
+ _convSize = 0;
+
+ _outSize_Defined = false;
+ _outSize = 0;
+ _nowPos64 = 0;
+ }
+
+ HRESULT Alloc();
+ HRESULT Init_and_Alloc();
+ HRESULT Flush2();
+
+ #ifndef Z7_NO_CRYPTO
+ CMyComPtr<ICryptoSetPassword> _setPassword;
+ CMyComPtr<ICryptoProperties> _cryptoProperties;
+ #endif
+
+ #ifndef Z7_EXTRACT_ONLY
+ CMyComPtr<ICompressSetCoderProperties> _setCoderProperties;
+ CMyComPtr<ICompressWriteCoderProperties> _writeCoderProperties;
+ CMyComPtr<ICompressSetCoderPropertiesOpt> _setCoderPropertiesOpt;
+ // CMyComPtr<ICryptoResetSalt> _cryptoResetSalt;
+ CMyComPtr<ICryptoResetInitVector> _cryptoResetInitVector;
+ #endif
+
+ CMyComPtr<ICompressSetDecoderProperties2> _setDecoderProperties2;
+
+public:
+ CMyComPtr<ICompressFilter> Filter;
+
+ CFilterCoder(bool encodeMode);
+
+ struct C_InStream_Releaser
+ {
+ CFilterCoder *FilterCoder;
+ C_InStream_Releaser(): FilterCoder(NULL) {}
+ ~C_InStream_Releaser() { if (FilterCoder) FilterCoder->ReleaseInStream(); }
+ };
+
+ struct C_OutStream_Releaser
+ {
+ CFilterCoder *FilterCoder;
+ C_OutStream_Releaser(): FilterCoder(NULL) {}
+ ~C_OutStream_Releaser() { if (FilterCoder) FilterCoder->ReleaseOutStream(); }
+ };
+
+ struct C_Filter_Releaser
+ {
+ CFilterCoder *FilterCoder;
+ C_Filter_Releaser(): FilterCoder(NULL) {}
+ ~C_Filter_Releaser() { if (FilterCoder) FilterCoder->Filter.Release(); }
+ };
+
+private:
+ Z7_COM_QI_BEGIN2(ICompressCoder)
+
+ Z7_COM_QI_ENTRY(ICompressSetOutStreamSize)
+ Z7_COM_QI_ENTRY(ICompressInitEncoder)
+
+ Z7_COM_QI_ENTRY(ICompressSetInStream)
+ Z7_COM_QI_ENTRY(ISequentialInStream)
+
+ Z7_COM_QI_ENTRY(ICompressSetOutStream)
+ Z7_COM_QI_ENTRY(ISequentialOutStream)
+ Z7_COM_QI_ENTRY(IOutStreamFinish)
+
+ Z7_COM_QI_ENTRY(ICompressSetBufSize)
+
+ #ifndef Z7_NO_CRYPTO
+ Z7_COM_QI_ENTRY_AG(ICryptoSetPassword, Filter, _setPassword)
+ Z7_COM_QI_ENTRY_AG(ICryptoProperties, Filter, _cryptoProperties)
+ #endif
+
+ #ifndef Z7_EXTRACT_ONLY
+ Z7_COM_QI_ENTRY_AG(ICompressSetCoderProperties, Filter, _setCoderProperties)
+ Z7_COM_QI_ENTRY_AG(ICompressWriteCoderProperties, Filter, _writeCoderProperties)
+ Z7_COM_QI_ENTRY_AG(ICompressSetCoderPropertiesOpt, Filter, _setCoderPropertiesOpt)
+ // Z7_COM_QI_ENTRY_AG(ICryptoResetSalt, Filter, _cryptoResetSalt)
+ Z7_COM_QI_ENTRY_AG(ICryptoResetInitVector, Filter, _cryptoResetInitVector)
+ #endif
+
+ Z7_COM_QI_ENTRY_AG(ICompressSetDecoderProperties2, Filter, _setDecoderProperties2)
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+public:
+ Z7_IFACE_COM7_IMP(ICompressCoder)
+ Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize)
+ Z7_IFACE_COM7_IMP(ICompressInitEncoder)
+ Z7_IFACE_COM7_IMP(ICompressSetInStream)
+private:
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+public:
+ Z7_IFACE_COM7_IMP(ICompressSetOutStream)
+private:
+ Z7_IFACE_COM7_IMP(ISequentialOutStream)
+public:
+ Z7_IFACE_COM7_IMP(IOutStreamFinish)
+private:
+
+ Z7_IFACE_COM7_IMP(ICompressSetBufSize)
+
+ #ifndef Z7_NO_CRYPTO
+ Z7_IFACE_COM7_IMP(ICryptoSetPassword)
+ Z7_IFACE_COM7_IMP(ICryptoProperties)
+ #endif
+
+ #ifndef Z7_EXTRACT_ONLY
+ Z7_IFACE_COM7_IMP(ICompressSetCoderProperties)
+ Z7_IFACE_COM7_IMP(ICompressWriteCoderProperties)
+ Z7_IFACE_COM7_IMP(ICompressSetCoderPropertiesOpt)
+ // Z7_IFACE_COM7_IMP(ICryptoResetSalt)
+ Z7_IFACE_COM7_IMP(ICryptoResetInitVector)
+ #endif
+
+public:
+ Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2)
+
+ HRESULT Init_NoSubFilterInit();
+};
+
+#endif
diff --git a/CPP/7zip/Common/InBuffer.cpp b/CPP/7zip/Common/InBuffer.cpp
index 826e98b..b0f222c 100644
--- a/CPP/7zip/Common/InBuffer.cpp
+++ b/CPP/7zip/Common/InBuffer.cpp
@@ -1,163 +1,164 @@
-// InBuffer.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/Alloc.h"
-
-#include "InBuffer.h"
-
-CInBufferBase::CInBufferBase() throw():
- _buf(0),
- _bufLim(0),
- _bufBase(0),
- _stream(0),
- _processedSize(0),
- _bufSize(0),
- _wasFinished(false),
- NumExtraBytes(0)
-{}
-
-bool CInBuffer::Create(size_t bufSize) throw()
-{
- const unsigned kMinBlockSize = 1;
- if (bufSize < kMinBlockSize)
- bufSize = kMinBlockSize;
- if (_bufBase != 0 && _bufSize == bufSize)
- return true;
- Free();
- _bufSize = bufSize;
- _bufBase = (Byte *)::MidAlloc(bufSize);
- return (_bufBase != 0);
-}
-
-void CInBuffer::Free() throw()
-{
- ::MidFree(_bufBase);
- _bufBase = 0;
-}
-
-void CInBufferBase::Init() throw()
-{
- _processedSize = 0;
- _buf = _bufBase;
- _bufLim = _buf;
- _wasFinished = false;
- #ifdef _NO_EXCEPTIONS
- ErrorCode = S_OK;
- #endif
- NumExtraBytes = 0;
-}
-
-bool CInBufferBase::ReadBlock()
-{
- #ifdef _NO_EXCEPTIONS
- if (ErrorCode != S_OK)
- return false;
- #endif
- if (_wasFinished)
- return false;
- _processedSize += (_buf - _bufBase);
- _buf = _bufBase;
- _bufLim = _bufBase;
- UInt32 processed;
- // FIX_ME: we can improve it to support (_bufSize >= (1 << 32))
- HRESULT result = _stream->Read(_bufBase, (UInt32)_bufSize, &processed);
- #ifdef _NO_EXCEPTIONS
- ErrorCode = result;
- #else
- if (result != S_OK)
- throw CInBufferException(result);
- #endif
- _bufLim = _buf + processed;
- _wasFinished = (processed == 0);
- return !_wasFinished;
-}
-
-bool CInBufferBase::ReadByte_FromNewBlock(Byte &b)
-{
- if (!ReadBlock())
- {
- NumExtraBytes++;
- b = 0xFF;
- return false;
- }
- b = *_buf++;
- return true;
-}
-
-Byte CInBufferBase::ReadByte_FromNewBlock()
-{
- if (!ReadBlock())
- {
- NumExtraBytes++;
- return 0xFF;
- }
- return *_buf++;
-}
-
-size_t CInBufferBase::ReadBytes(Byte *buf, size_t size)
-{
- size_t num = 0;
- for (;;)
- {
- const size_t rem = _bufLim - _buf;
- if (size <= rem)
- {
- if (size != 0)
- {
- memcpy(buf, _buf, size);
- _buf += size;
- num += size;
- }
- return num;
- }
- if (rem != 0)
- {
- memcpy(buf, _buf, rem);
- _buf += rem;
- buf += rem;
- num += rem;
- size -= rem;
- }
- if (!ReadBlock())
- return num;
- }
-
- /*
- if ((size_t)(_bufLim - _buf) >= size)
- {
- const Byte *src = _buf;
- for (size_t i = 0; i < size; i++)
- buf[i] = src[i];
- _buf += size;
- return size;
- }
- for (size_t i = 0; i < size; i++)
- {
- if (_buf >= _bufLim)
- if (!ReadBlock())
- return i;
- buf[i] = *_buf++;
- }
- return size;
- */
-}
-
-size_t CInBufferBase::Skip(size_t size)
-{
- size_t processed = 0;
- for (;;)
- {
- size_t rem = (_bufLim - _buf);
- if (rem >= size)
- {
- _buf += size;
- return processed + size;
- }
- _buf += rem;
- processed += rem;
- size -= rem;
- if (!ReadBlock())
- return processed;
- }
-}
+// InBuffer.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "InBuffer.h"
+
+CInBufferBase::CInBufferBase() throw():
+ _buf(NULL),
+ _bufLim(NULL),
+ _bufBase(NULL),
+ _stream(NULL),
+ _processedSize(0),
+ _bufSize(0),
+ _wasFinished(false),
+ NumExtraBytes(0)
+{}
+
+bool CInBuffer::Create(size_t bufSize) throw()
+{
+ const unsigned kMinBlockSize = 1;
+ if (bufSize < kMinBlockSize)
+ bufSize = kMinBlockSize;
+ if (_bufBase != NULL && _bufSize == bufSize)
+ return true;
+ Free();
+ _bufSize = bufSize;
+ _bufBase = (Byte *)::MidAlloc(bufSize);
+ return (_bufBase != NULL);
+}
+
+void CInBuffer::Free() throw()
+{
+ ::MidFree(_bufBase);
+ _bufBase = NULL;
+}
+
+void CInBufferBase::Init() throw()
+{
+ _processedSize = 0;
+ _buf = _bufBase;
+ _bufLim = _buf;
+ _wasFinished = false;
+ #ifdef Z7_NO_EXCEPTIONS
+ ErrorCode = S_OK;
+ #endif
+ NumExtraBytes = 0;
+}
+
+bool CInBufferBase::ReadBlock()
+{
+ #ifdef Z7_NO_EXCEPTIONS
+ if (ErrorCode != S_OK)
+ return false;
+ #endif
+ if (_wasFinished)
+ return false;
+ _processedSize += (size_t)(_buf - _bufBase);
+ _buf = _bufBase;
+ _bufLim = _bufBase;
+ UInt32 processed;
+ // FIX_ME: we can improve it to support (_bufSize >= (1 << 32))
+ const HRESULT result = _stream->Read(_bufBase, (UInt32)_bufSize, &processed);
+ #ifdef Z7_NO_EXCEPTIONS
+ ErrorCode = result;
+ #else
+ if (result != S_OK)
+ throw CInBufferException(result);
+ #endif
+ _bufLim = _buf + processed;
+ _wasFinished = (processed == 0);
+ return !_wasFinished;
+}
+
+bool CInBufferBase::ReadByte_FromNewBlock(Byte &b)
+{
+ if (!ReadBlock())
+ {
+ // 22.00: we don't increment (NumExtraBytes) here
+ // NumExtraBytes++;
+ b = 0xFF;
+ return false;
+ }
+ b = *_buf++;
+ return true;
+}
+
+Byte CInBufferBase::ReadByte_FromNewBlock()
+{
+ if (!ReadBlock())
+ {
+ NumExtraBytes++;
+ return 0xFF;
+ }
+ return *_buf++;
+}
+
+size_t CInBufferBase::ReadBytes(Byte *buf, size_t size)
+{
+ size_t num = 0;
+ for (;;)
+ {
+ const size_t rem = (size_t)(_bufLim - _buf);
+ if (size <= rem)
+ {
+ if (size != 0)
+ {
+ memcpy(buf, _buf, size);
+ _buf += size;
+ num += size;
+ }
+ return num;
+ }
+ if (rem != 0)
+ {
+ memcpy(buf, _buf, rem);
+ _buf += rem;
+ buf += rem;
+ num += rem;
+ size -= rem;
+ }
+ if (!ReadBlock())
+ return num;
+ }
+
+ /*
+ if ((size_t)(_bufLim - _buf) >= size)
+ {
+ const Byte *src = _buf;
+ for (size_t i = 0; i < size; i++)
+ buf[i] = src[i];
+ _buf += size;
+ return size;
+ }
+ for (size_t i = 0; i < size; i++)
+ {
+ if (_buf >= _bufLim)
+ if (!ReadBlock())
+ return i;
+ buf[i] = *_buf++;
+ }
+ return size;
+ */
+}
+
+size_t CInBufferBase::Skip(size_t size)
+{
+ size_t processed = 0;
+ for (;;)
+ {
+ const size_t rem = (size_t)(_bufLim - _buf);
+ if (rem >= size)
+ {
+ _buf += size;
+ return processed + size;
+ }
+ _buf += rem;
+ processed += rem;
+ size -= rem;
+ if (!ReadBlock())
+ return processed;
+ }
+}
diff --git a/CPP/7zip/Common/InBuffer.h b/CPP/7zip/Common/InBuffer.h
index 76e359a..3aaf797 100644
--- a/CPP/7zip/Common/InBuffer.h
+++ b/CPP/7zip/Common/InBuffer.h
@@ -1,92 +1,109 @@
-// InBuffer.h
-
-#ifndef __IN_BUFFER_H
-#define __IN_BUFFER_H
-
-#include "../../Common/MyException.h"
-#include "../IStream.h"
-
-#ifndef _NO_EXCEPTIONS
-struct CInBufferException: public CSystemException
-{
- CInBufferException(HRESULT errorCode): CSystemException(errorCode) {}
-};
-#endif
-
-class CInBufferBase
-{
-protected:
- Byte *_buf;
- Byte *_bufLim;
- Byte *_bufBase;
-
- ISequentialInStream *_stream;
- UInt64 _processedSize;
- size_t _bufSize; // actually it's number of Bytes for next read. The buf can be larger
- // only up to 32-bits values now are supported!
- bool _wasFinished;
-
- bool ReadBlock();
- bool ReadByte_FromNewBlock(Byte &b);
- Byte ReadByte_FromNewBlock();
-
-public:
- #ifdef _NO_EXCEPTIONS
- HRESULT ErrorCode;
- #endif
- UInt32 NumExtraBytes;
-
- CInBufferBase() throw();
-
- UInt64 GetStreamSize() const { return _processedSize + (_buf - _bufBase); }
- UInt64 GetProcessedSize() const { return _processedSize + NumExtraBytes + (_buf - _bufBase); }
- bool WasFinished() const { return _wasFinished; }
-
- void SetStream(ISequentialInStream *stream) { _stream = stream; }
-
- void SetBuf(Byte *buf, size_t bufSize, size_t end, size_t pos)
- {
- _bufBase = buf;
- _bufSize = bufSize;
- _processedSize = 0;
- _buf = buf + pos;
- _bufLim = buf + end;
- _wasFinished = false;
- #ifdef _NO_EXCEPTIONS
- ErrorCode = S_OK;
- #endif
- NumExtraBytes = 0;
- }
-
- void Init() throw();
-
- MY_FORCE_INLINE
- bool ReadByte(Byte &b)
- {
- if (_buf >= _bufLim)
- return ReadByte_FromNewBlock(b);
- b = *_buf++;
- return true;
- }
-
- MY_FORCE_INLINE
- Byte ReadByte()
- {
- if (_buf >= _bufLim)
- return ReadByte_FromNewBlock();
- return *_buf++;
- }
-
- size_t ReadBytes(Byte *buf, size_t size);
- size_t Skip(size_t size);
-};
-
-class CInBuffer: public CInBufferBase
-{
-public:
- ~CInBuffer() { Free(); }
- bool Create(size_t bufSize) throw(); // only up to 32-bits values now are supported!
- void Free() throw();
-};
-
-#endif
+// InBuffer.h
+
+#ifndef ZIP7_INC_IN_BUFFER_H
+#define ZIP7_INC_IN_BUFFER_H
+
+#include "../../Common/MyException.h"
+#include "../IStream.h"
+
+#ifndef Z7_NO_EXCEPTIONS
+struct CInBufferException: public CSystemException
+{
+ CInBufferException(HRESULT errorCode): CSystemException(errorCode) {}
+};
+#endif
+
+class CInBufferBase
+{
+protected:
+ Byte *_buf;
+ Byte *_bufLim;
+ Byte *_bufBase;
+
+ ISequentialInStream *_stream;
+ UInt64 _processedSize;
+ size_t _bufSize; // actually it's number of Bytes for next read. The buf can be larger
+ // only up to 32-bits values now are supported!
+ bool _wasFinished;
+
+ bool ReadBlock();
+ bool ReadByte_FromNewBlock(Byte &b);
+ Byte ReadByte_FromNewBlock();
+
+public:
+ #ifdef Z7_NO_EXCEPTIONS
+ HRESULT ErrorCode;
+ #endif
+ UInt32 NumExtraBytes;
+
+ CInBufferBase() throw();
+
+ // the size of portion of data in real stream that was already read from this object
+ // it doesn't include unused data in buffer
+ // it doesn't include virtual Extra bytes after the end of real stream data
+ UInt64 GetStreamSize() const { return _processedSize + (size_t)(_buf - _bufBase); }
+
+ // the size of virtual data that was read from this object
+ // it doesn't include unused data in buffers
+ // it includes any virtual Extra bytes after the end of real data
+ UInt64 GetProcessedSize() const { return _processedSize + NumExtraBytes + (size_t)(_buf - _bufBase); }
+
+ bool WasFinished() const { return _wasFinished; }
+
+ void SetStream(ISequentialInStream *stream) { _stream = stream; }
+
+ void SetBuf(Byte *buf, size_t bufSize, size_t end, size_t pos)
+ {
+ _bufBase = buf;
+ _bufSize = bufSize;
+ _processedSize = 0;
+ _buf = buf + pos;
+ _bufLim = buf + end;
+ _wasFinished = false;
+ #ifdef Z7_NO_EXCEPTIONS
+ ErrorCode = S_OK;
+ #endif
+ NumExtraBytes = 0;
+ }
+
+ void Init() throw();
+
+ Z7_FORCE_INLINE
+ bool ReadByte(Byte &b)
+ {
+ if (_buf >= _bufLim)
+ return ReadByte_FromNewBlock(b);
+ b = *_buf++;
+ return true;
+ }
+
+ Z7_FORCE_INLINE
+ bool ReadByte_FromBuf(Byte &b)
+ {
+ if (_buf >= _bufLim)
+ return false;
+ b = *_buf++;
+ return true;
+ }
+
+ Z7_FORCE_INLINE
+ Byte ReadByte()
+ {
+ if (_buf >= _bufLim)
+ return ReadByte_FromNewBlock();
+ return *_buf++;
+ }
+
+ size_t ReadBytes(Byte *buf, size_t size);
+ size_t Skip(size_t size);
+};
+
+class CInBuffer: public CInBufferBase
+{
+public:
+ ~CInBuffer() { Free(); }
+ bool Create(size_t bufSize) throw(); // only up to 32-bits values now are supported!
+ void Free() throw();
+};
+
+#endif
diff --git a/CPP/7zip/Common/InOutTempBuffer.cpp b/CPP/7zip/Common/InOutTempBuffer.cpp
index d83d674..3f7272e 100644
--- a/CPP/7zip/Common/InOutTempBuffer.cpp
+++ b/CPP/7zip/Common/InOutTempBuffer.cpp
@@ -1,127 +1,237 @@
-// InOutTempBuffer.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/7zCrc.h"
-
-#include "../../Common/Defs.h"
-
-#include "InOutTempBuffer.h"
-#include "StreamUtils.h"
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NDir;
-
-static const size_t kTempBufSize = (1 << 20);
-
-#define kTempFilePrefixString FTEXT("7zt")
-
-CInOutTempBuffer::CInOutTempBuffer(): _buf(NULL) { }
-
-void CInOutTempBuffer::Create()
-{
- if (!_buf)
- _buf = new Byte[kTempBufSize];
-}
-
-CInOutTempBuffer::~CInOutTempBuffer()
-{
- delete []_buf;
-}
-
-void CInOutTempBuffer::InitWriting()
-{
- _bufPos = 0;
- _tempFileCreated = false;
- _size = 0;
- _crc = CRC_INIT_VAL;
-}
-
-bool CInOutTempBuffer::WriteToFile(const void *data, UInt32 size)
-{
- if (size == 0)
- return true;
- if (!_tempFileCreated)
- {
- if (!_tempFile.CreateRandomInTempFolder(kTempFilePrefixString, &_outFile))
- return false;
- _tempFileCreated = true;
- }
- UInt32 processed;
- if (!_outFile.Write(data, size, processed))
- return false;
- _crc = CrcUpdate(_crc, data, processed);
- _size += processed;
- return (processed == size);
-}
-
-bool CInOutTempBuffer::Write(const void *data, UInt32 size)
-{
- if (size == 0)
- return true;
- size_t cur = kTempBufSize - _bufPos;
- if (cur != 0)
- {
- if (cur > size)
- cur = size;
- memcpy(_buf + _bufPos, data, cur);
- _crc = CrcUpdate(_crc, data, cur);
- _bufPos += cur;
- _size += cur;
- size -= (UInt32)cur;
- data = ((const Byte *)data) + cur;
- }
- return WriteToFile(data, size);
-}
-
-HRESULT CInOutTempBuffer::WriteToStream(ISequentialOutStream *stream)
-{
- if (!_outFile.Close())
- return E_FAIL;
-
- UInt64 size = 0;
- UInt32 crc = CRC_INIT_VAL;
-
- if (_bufPos != 0)
- {
- RINOK(WriteStream(stream, _buf, _bufPos));
- crc = CrcUpdate(crc, _buf, _bufPos);
- size += _bufPos;
- }
-
- if (_tempFileCreated)
- {
- NIO::CInFile inFile;
- if (!inFile.Open(_tempFile.GetPath()))
- return E_FAIL;
- while (size < _size)
- {
- UInt32 processed;
- if (!inFile.ReadPart(_buf, kTempBufSize, processed))
- return E_FAIL;
- if (processed == 0)
- break;
- RINOK(WriteStream(stream, _buf, processed));
- crc = CrcUpdate(crc, _buf, processed);
- size += processed;
- }
- }
-
- return (_crc == crc && size == _size) ? S_OK : E_FAIL;
-}
-
-/*
-STDMETHODIMP CSequentialOutTempBufferImp::Write(const void *data, UInt32 size, UInt32 *processed)
-{
- if (!_buf->Write(data, size))
- {
- if (processed)
- *processed = 0;
- return E_FAIL;
- }
- if (processed)
- *processed = size;
- return S_OK;
-}
-*/
+// InOutTempBuffer.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "InOutTempBuffer.h"
+
+#include "StreamUtils.h"
+
+#ifdef USE_InOutTempBuffer_FILE
+
+#include "../../../C/7zCrc.h"
+
+#define kTempFilePrefixString FTEXT("7zt")
+/*
+ Total buffer size limit, if we use temp file scheme:
+ 32-bit: 16 MiB = 1 MiB * 16 buffers
+ 64-bit: 4 GiB = 1 MiB * 4096 buffers
+*/
+static const size_t kNumBufsMax = (size_t)1 << (sizeof(size_t) * 2 - 4);
+
+#endif
+
+static const size_t kBufSize = (size_t)1 << 20;
+
+
+CInOutTempBuffer::CInOutTempBuffer():
+ _size(0),
+ _bufs(NULL),
+ _numBufs(0),
+ _numFilled(0)
+{
+ #ifdef USE_InOutTempBuffer_FILE
+ _tempFile_Created = false;
+ _useMemOnly = false;
+ _crc = CRC_INIT_VAL;
+ #endif
+}
+
+CInOutTempBuffer::~CInOutTempBuffer()
+{
+ for (size_t i = 0; i < _numBufs; i++)
+ MyFree(_bufs[i]);
+ MyFree(_bufs);
+}
+
+
+void *CInOutTempBuffer::GetBuf(size_t index)
+{
+ if (index >= _numBufs)
+ {
+ const size_t num = (_numBufs == 0 ? 16 : _numBufs * 2);
+ void **p = (void **)MyRealloc(_bufs, num * sizeof(void *));
+ if (!p)
+ return NULL;
+ _bufs = p;
+ memset(p + _numBufs, 0, (num - _numBufs) * sizeof(void *));
+ _numBufs = num;
+ }
+
+ void *buf = _bufs[index];
+ if (!buf)
+ {
+ buf = MyAlloc(kBufSize);
+ if (buf)
+ _bufs[index] = buf;
+ }
+ return buf;
+}
+
+
+HRESULT CInOutTempBuffer::Write_HRESULT(const void *data, UInt32 size)
+{
+ if (size == 0)
+ return S_OK;
+
+ #ifdef USE_InOutTempBuffer_FILE
+ if (!_tempFile_Created)
+ #endif
+ for (;;) // loop for additional attemp to allocate memory after file creation error
+ {
+ #ifdef USE_InOutTempBuffer_FILE
+ bool allocError = false;
+ #endif
+
+ for (;;) // loop for writing to buffers
+ {
+ const size_t index = (size_t)(_size / kBufSize);
+
+ #ifdef USE_InOutTempBuffer_FILE
+ if (index >= kNumBufsMax && !_useMemOnly)
+ break;
+ #endif
+
+ void *buf = GetBuf(index);
+ if (!buf)
+ {
+ #ifdef USE_InOutTempBuffer_FILE
+ if (!_useMemOnly)
+ {
+ allocError = true;
+ break;
+ }
+ #endif
+ return E_OUTOFMEMORY;
+ }
+
+ const size_t offset = (size_t)(_size) & (kBufSize - 1);
+ size_t cur = kBufSize - offset;
+ if (cur > size)
+ cur = size;
+ memcpy((Byte *)buf + offset, data, cur);
+ _size += cur;
+ if (index >= _numFilled)
+ _numFilled = index + 1;
+ data = (const void *)((const Byte *)data + cur);
+ size -= (UInt32)cur;
+ if (size == 0)
+ return S_OK;
+ }
+
+ #ifdef USE_InOutTempBuffer_FILE
+ #ifndef _WIN32
+ _outFile.mode_for_Create = 0600; // only owner will have the rights to access this file
+ #endif
+ if (_tempFile.CreateRandomInTempFolder(kTempFilePrefixString, &_outFile))
+ {
+ _tempFile_Created = true;
+ break;
+ }
+ _useMemOnly = true;
+ if (allocError)
+ return GetLastError_noZero_HRESULT();
+ #endif
+ }
+
+ #ifdef USE_InOutTempBuffer_FILE
+ if (!_outFile.WriteFull(data, size))
+ return GetLastError_noZero_HRESULT();
+ _crc = CrcUpdate(_crc, data, size);
+ _size += size;
+ return S_OK;
+ #endif
+}
+
+
+HRESULT CInOutTempBuffer::WriteToStream(ISequentialOutStream *stream)
+{
+ UInt64 rem = _size;
+ // if (rem == 0) return S_OK;
+
+ const size_t numFilled = _numFilled;
+ _numFilled = 0;
+
+ for (size_t i = 0; i < numFilled; i++)
+ {
+ if (rem == 0)
+ return E_FAIL;
+ size_t cur = kBufSize;
+ if (cur > rem)
+ cur = (size_t)rem;
+ RINOK(WriteStream(stream, _bufs[i], cur))
+ rem -= cur;
+ #ifdef USE_InOutTempBuffer_FILE
+ // we will use _bufs[0] later for writing from temp file
+ if (i != 0 || !_tempFile_Created)
+ #endif
+ {
+ MyFree(_bufs[i]);
+ _bufs[i] = NULL;
+ }
+ }
+
+
+ #ifdef USE_InOutTempBuffer_FILE
+
+ if (rem == 0)
+ return _tempFile_Created ? E_FAIL : S_OK;
+
+ if (!_tempFile_Created)
+ return E_FAIL;
+
+ if (!_outFile.Close())
+ return GetLastError_noZero_HRESULT();
+
+ HRESULT hres;
+ void *buf = GetBuf(0); // index
+ if (!buf)
+ hres = E_OUTOFMEMORY;
+ else
+ {
+ NWindows::NFile::NIO::CInFile inFile;
+ if (!inFile.Open(_tempFile.GetPath()))
+ hres = GetLastError_noZero_HRESULT();
+ else
+ {
+ UInt32 crc = CRC_INIT_VAL;
+ for (;;)
+ {
+ size_t processed;
+ if (!inFile.ReadFull(buf, kBufSize, processed))
+ {
+ hres = GetLastError_noZero_HRESULT();
+ break;
+ }
+ if (processed == 0)
+ {
+ // we compare crc without CRC_GET_DIGEST
+ hres = (_crc == crc ? S_OK : E_FAIL);
+ break;
+ }
+ size_t n = processed;
+ if (n > rem)
+ n = (size_t)rem;
+ hres = WriteStream(stream, buf, n);
+ if (hres != S_OK)
+ break;
+ crc = CrcUpdate(crc, buf, n);
+ rem -= n;
+ if (n != processed)
+ {
+ hres = E_FAIL;
+ break;
+ }
+ }
+ }
+ }
+
+ // _tempFile.DisableDeleting(); // for debug
+ _tempFile.Remove();
+ RINOK(hres)
+
+ #endif
+
+ return rem == 0 ? S_OK : E_FAIL;
+}
diff --git a/CPP/7zip/Common/InOutTempBuffer.h b/CPP/7zip/Common/InOutTempBuffer.h
index 4140d28..345c386 100644
--- a/CPP/7zip/Common/InOutTempBuffer.h
+++ b/CPP/7zip/Common/InOutTempBuffer.h
@@ -1,48 +1,45 @@
-// InOutTempBuffer.h
-
-#ifndef __IN_OUT_TEMP_BUFFER_H
-#define __IN_OUT_TEMP_BUFFER_H
-
-#include "../../Common/MyCom.h"
-#include "../../Windows/FileDir.h"
-
-#include "../IStream.h"
-
-class CInOutTempBuffer
-{
- NWindows::NFile::NDir::CTempFile _tempFile;
- NWindows::NFile::NIO::COutFile _outFile;
- Byte *_buf;
- size_t _bufPos;
- UInt64 _size;
- UInt32 _crc;
- bool _tempFileCreated;
-
- bool WriteToFile(const void *data, UInt32 size);
-public:
- CInOutTempBuffer();
- ~CInOutTempBuffer();
- void Create();
-
- void InitWriting();
- bool Write(const void *data, UInt32 size);
-
- HRESULT WriteToStream(ISequentialOutStream *stream);
- UInt64 GetDataSize() const { return _size; }
-};
-
-/*
-class CSequentialOutTempBufferImp:
- public ISequentialOutStream,
- public CMyUnknownImp
-{
- CInOutTempBuffer *_buf;
-public:
- void Init(CInOutTempBuffer *buffer) { _buf = buffer; }
- MY_UNKNOWN_IMP
-
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
-};
-*/
-
-#endif
+// InOutTempBuffer.h
+
+#ifndef ZIP7_INC_IN_OUT_TEMP_BUFFER_H
+#define ZIP7_INC_IN_OUT_TEMP_BUFFER_H
+
+// #ifdef _WIN32
+#define USE_InOutTempBuffer_FILE
+// #endif
+
+#ifdef USE_InOutTempBuffer_FILE
+#include "../../Windows/FileDir.h"
+#endif
+
+#include "../IStream.h"
+
+class CInOutTempBuffer
+{
+ UInt64 _size;
+ void **_bufs;
+ size_t _numBufs;
+ size_t _numFilled;
+
+ #ifdef USE_InOutTempBuffer_FILE
+
+ bool _tempFile_Created;
+ bool _useMemOnly;
+ UInt32 _crc;
+ // COutFile object must be declared after CTempFile object for correct destructor order
+ NWindows::NFile::NDir::CTempFile _tempFile;
+ NWindows::NFile::NIO::COutFile _outFile;
+
+ #endif
+
+ void *GetBuf(size_t index);
+
+ Z7_CLASS_NO_COPY(CInOutTempBuffer)
+public:
+ CInOutTempBuffer();
+ ~CInOutTempBuffer();
+ HRESULT Write_HRESULT(const void *data, UInt32 size);
+ HRESULT WriteToStream(ISequentialOutStream *stream);
+ UInt64 GetDataSize() const { return _size; }
+};
+
+#endif
diff --git a/CPP/7zip/Common/LimitedStreams.cpp b/CPP/7zip/Common/LimitedStreams.cpp
index fc7e794..664cd0c 100644
--- a/CPP/7zip/Common/LimitedStreams.cpp
+++ b/CPP/7zip/Common/LimitedStreams.cpp
@@ -1,367 +1,393 @@
-// LimitedStreams.cpp
-
-#include "StdAfx.h"
-
-#include <string.h>
-
-#include "LimitedStreams.h"
-
-STDMETHODIMP CLimitedSequentialInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- UInt32 realProcessedSize = 0;
- {
- const UInt64 rem = _size - _pos;
- if (size > rem)
- size = (UInt32)rem;
- }
- HRESULT result = S_OK;
- if (size != 0)
- {
- result = _stream->Read(data, size, &realProcessedSize);
- _pos += realProcessedSize;
- if (realProcessedSize == 0)
- _wasFinished = true;
- }
- if (processedSize)
- *processedSize = realProcessedSize;
- return result;
-}
-
-STDMETHODIMP CLimitedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
- if (_virtPos >= _size)
- {
- // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case.
- return S_OK;
- // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF
- }
- {
- const UInt64 rem = _size - _virtPos;
- if (size > rem)
- size = (UInt32)rem;
- }
- UInt64 newPos = _startOffset + _virtPos;
- if (newPos != _physPos)
- {
- _physPos = newPos;
- RINOK(SeekToPhys());
- }
- HRESULT res = _stream->Read(data, size, &size);
- if (processedSize)
- *processedSize = size;
- _physPos += size;
- _virtPos += size;
- return res;
-}
-
-STDMETHODIMP CLimitedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- switch (seekOrigin)
- {
- case STREAM_SEEK_SET: break;
- case STREAM_SEEK_CUR: offset += _virtPos; break;
- case STREAM_SEEK_END: offset += _size; break;
- default: return STG_E_INVALIDFUNCTION;
- }
- if (offset < 0)
- return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
- _virtPos = offset;
- if (newPosition)
- *newPosition = _virtPos;
- return S_OK;
-}
-
-HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream)
-{
- *resStream = 0;
- CLimitedInStream *streamSpec = new CLimitedInStream;
- CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
- streamSpec->SetStream(inStream);
- RINOK(streamSpec->InitAndSeek(pos, size));
- streamSpec->SeekToStart();
- *resStream = streamTemp.Detach();
- return S_OK;
-}
-
-STDMETHODIMP CClusterInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
- if (_virtPos >= Size)
- return S_OK;
- {
- UInt64 rem = Size - _virtPos;
- if (size > rem)
- size = (UInt32)rem;
- }
- if (size == 0)
- return S_OK;
-
- if (_curRem == 0)
- {
- const UInt32 blockSize = (UInt32)1 << BlockSizeLog;
- const UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog);
- const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
- const UInt32 phyBlock = Vector[virtBlock];
-
- UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock;
- if (newPos != _physPos)
- {
- _physPos = newPos;
- RINOK(SeekToPhys());
- }
-
- _curRem = blockSize - offsetInBlock;
-
- for (int i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++)
- _curRem += (UInt32)1 << BlockSizeLog;
- }
-
- if (size > _curRem)
- size = _curRem;
- HRESULT res = Stream->Read(data, size, &size);
- if (processedSize)
- *processedSize = size;
- _physPos += size;
- _virtPos += size;
- _curRem -= size;
- return res;
-}
-
-STDMETHODIMP CClusterInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- switch (seekOrigin)
- {
- case STREAM_SEEK_SET: break;
- case STREAM_SEEK_CUR: offset += _virtPos; break;
- case STREAM_SEEK_END: offset += Size; break;
- default: return STG_E_INVALIDFUNCTION;
- }
- if (offset < 0)
- return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
- if (_virtPos != (UInt64)offset)
- _curRem = 0;
- _virtPos = offset;
- if (newPosition)
- *newPosition = offset;
- return S_OK;
-}
-
-
-STDMETHODIMP CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
- if (_virtPos >= Extents.Back().Virt)
- return S_OK;
- if (size == 0)
- return S_OK;
-
- unsigned left = 0, right = Extents.Size() - 1;
- for (;;)
- {
- unsigned mid = (left + right) / 2;
- if (mid == left)
- break;
- if (_virtPos < Extents[mid].Virt)
- right = mid;
- else
- left = mid;
- }
-
- const CSeekExtent &extent = Extents[left];
- UInt64 phyPos = extent.Phy + (_virtPos - extent.Virt);
- if (_needStartSeek || _phyPos != phyPos)
- {
- _needStartSeek = false;
- _phyPos = phyPos;
- RINOK(SeekToPhys());
- }
-
- UInt64 rem = Extents[left + 1].Virt - _virtPos;
- if (size > rem)
- size = (UInt32)rem;
-
- HRESULT res = Stream->Read(data, size, &size);
- _phyPos += size;
- _virtPos += size;
- if (processedSize)
- *processedSize = size;
- return res;
-}
-
-STDMETHODIMP CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- switch (seekOrigin)
- {
- case STREAM_SEEK_SET: break;
- case STREAM_SEEK_CUR: offset += _virtPos; break;
- case STREAM_SEEK_END: offset += Extents.Back().Virt; break;
- default: return STG_E_INVALIDFUNCTION;
- }
- if (offset < 0)
- return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
- _virtPos = offset;
- if (newPosition)
- *newPosition = _virtPos;
- return S_OK;
-}
-
-
-STDMETHODIMP CLimitedSequentialOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- HRESULT result = S_OK;
- if (processedSize)
- *processedSize = 0;
- if (size > _size)
- {
- if (_size == 0)
- {
- _overflow = true;
- if (!_overflowIsAllowed)
- return E_FAIL;
- if (processedSize)
- *processedSize = size;
- return S_OK;
- }
- size = (UInt32)_size;
- }
- if (_stream)
- result = _stream->Write(data, size, &size);
- _size -= size;
- if (processedSize)
- *processedSize = size;
- return result;
-}
-
-
-STDMETHODIMP CTailInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- UInt32 cur;
- HRESULT res = Stream->Read(data, size, &cur);
- if (processedSize)
- *processedSize = cur;
- _virtPos += cur;
- return res;
-}
-
-STDMETHODIMP CTailInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- switch (seekOrigin)
- {
- case STREAM_SEEK_SET: break;
- case STREAM_SEEK_CUR: offset += _virtPos; break;
- case STREAM_SEEK_END:
- {
- UInt64 pos = 0;
- RINOK(Stream->Seek(offset, STREAM_SEEK_END, &pos));
- if (pos < Offset)
- return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
- _virtPos = pos - Offset;
- if (newPosition)
- *newPosition = _virtPos;
- return S_OK;
- }
- default: return STG_E_INVALIDFUNCTION;
- }
- if (offset < 0)
- return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
- _virtPos = offset;
- if (newPosition)
- *newPosition = _virtPos;
- return Stream->Seek(Offset + _virtPos, STREAM_SEEK_SET, NULL);
-}
-
-STDMETHODIMP CLimitedCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
- if (_virtPos >= _size)
- {
- // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case.
- return S_OK;
- // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF
- }
- UInt64 rem = _size - _virtPos;
- if (rem < size)
- size = (UInt32)rem;
-
- UInt64 newPos = _startOffset + _virtPos;
- UInt64 offsetInCache = newPos - _cachePhyPos;
- HRESULT res = S_OK;
- if (newPos >= _cachePhyPos &&
- offsetInCache <= _cacheSize &&
- size <= _cacheSize - (size_t)offsetInCache)
- {
- if (size != 0)
- memcpy(data, _cache + (size_t)offsetInCache, size);
- }
- else
- {
- if (newPos != _physPos)
- {
- _physPos = newPos;
- RINOK(SeekToPhys());
- }
- res = _stream->Read(data, size, &size);
- _physPos += size;
- }
- if (processedSize)
- *processedSize = size;
- _virtPos += size;
- return res;
-}
-
-STDMETHODIMP CLimitedCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- switch (seekOrigin)
- {
- case STREAM_SEEK_SET: break;
- case STREAM_SEEK_CUR: offset += _virtPos; break;
- case STREAM_SEEK_END: offset += _size; break;
- default: return STG_E_INVALIDFUNCTION;
- }
- if (offset < 0)
- return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
- _virtPos = offset;
- if (newPosition)
- *newPosition = _virtPos;
- return S_OK;
-}
-
-STDMETHODIMP CTailOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- UInt32 cur;
- HRESULT res = Stream->Write(data, size, &cur);
- if (processedSize)
- *processedSize = cur;
- _virtPos += cur;
- if (_virtSize < _virtPos)
- _virtSize = _virtPos;
- return res;
-}
-
-STDMETHODIMP CTailOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- switch (seekOrigin)
- {
- case STREAM_SEEK_SET: break;
- case STREAM_SEEK_CUR: offset += _virtPos; break;
- case STREAM_SEEK_END: offset += _virtSize; break;
- default: return STG_E_INVALIDFUNCTION;
- }
- if (offset < 0)
- return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
- _virtPos = offset;
- if (newPosition)
- *newPosition = _virtPos;
- return Stream->Seek(Offset + _virtPos, STREAM_SEEK_SET, NULL);
-}
-
-STDMETHODIMP CTailOutStream::SetSize(UInt64 newSize)
-{
- _virtSize = newSize;
- return Stream->SetSize(Offset + newSize);
-}
+// LimitedStreams.cpp
+
+#include "StdAfx.h"
+
+#include <string.h>
+
+#include "LimitedStreams.h"
+
+Z7_COM7F_IMF(CLimitedSequentialInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ UInt32 realProcessedSize = 0;
+ {
+ const UInt64 rem = _size - _pos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+ HRESULT result = S_OK;
+ if (size != 0)
+ {
+ result = _stream->Read(data, size, &realProcessedSize);
+ _pos += realProcessedSize;
+ if (realProcessedSize == 0)
+ _wasFinished = true;
+ }
+ if (processedSize)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+Z7_COM7F_IMF(CLimitedInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (_virtPos >= _size)
+ {
+ // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case.
+ return S_OK;
+ // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF
+ }
+ {
+ const UInt64 rem = _size - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+ UInt64 newPos = _startOffset + _virtPos;
+ if (newPos != _physPos)
+ {
+ _physPos = newPos;
+ RINOK(SeekToPhys())
+ }
+ HRESULT res = _stream->Read(data, size, &size);
+ if (processedSize)
+ *processedSize = size;
+ _physPos += size;
+ _virtPos += size;
+ return res;
+}
+
+Z7_COM7F_IMF(CLimitedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += _size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _virtPos = (UInt64)offset;
+ if (newPosition)
+ *newPosition = _virtPos;
+ return S_OK;
+}
+
+HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream)
+{
+ *resStream = NULL;
+ CLimitedInStream *streamSpec = new CLimitedInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = streamSpec;
+ streamSpec->SetStream(inStream);
+ RINOK(streamSpec->InitAndSeek(pos, size))
+ streamSpec->SeekToStart();
+ *resStream = streamTemp.Detach();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CClusterInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (_virtPos >= Size)
+ return S_OK;
+ {
+ UInt64 rem = Size - _virtPos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+ if (size == 0)
+ return S_OK;
+
+ if (_curRem == 0)
+ {
+ const UInt32 blockSize = (UInt32)1 << BlockSizeLog;
+ const UInt32 virtBlock = (UInt32)(_virtPos >> BlockSizeLog);
+ const UInt32 offsetInBlock = (UInt32)_virtPos & (blockSize - 1);
+ const UInt32 phyBlock = Vector[virtBlock];
+
+ UInt64 newPos = StartOffset + ((UInt64)phyBlock << BlockSizeLog) + offsetInBlock;
+ if (newPos != _physPos)
+ {
+ _physPos = newPos;
+ RINOK(SeekToPhys())
+ }
+
+ _curRem = blockSize - offsetInBlock;
+
+ for (unsigned i = 1; i < 64 && (virtBlock + i) < (UInt32)Vector.Size() && phyBlock + i == Vector[virtBlock + i]; i++)
+ _curRem += (UInt32)1 << BlockSizeLog;
+ }
+
+ if (size > _curRem)
+ size = _curRem;
+ HRESULT res = Stream->Read(data, size, &size);
+ if (processedSize)
+ *processedSize = size;
+ _physPos += size;
+ _virtPos += size;
+ _curRem -= size;
+ return res;
+}
+
+Z7_COM7F_IMF(CClusterInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += Size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ if (_virtPos != (UInt64)offset)
+ _curRem = 0;
+ _virtPos = (UInt64)offset;
+ if (newPosition)
+ *newPosition = (UInt64)offset;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CExtentsStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ const UInt64 virt = _virtPos;
+ if (virt >= Extents.Back().Virt)
+ return S_OK;
+ if (size == 0)
+ return S_OK;
+
+ unsigned left = _prevExtentIndex;
+ if (virt < Extents[left].Virt ||
+ virt >= Extents[left + 1].Virt)
+ {
+ left = 0;
+ unsigned right = Extents.Size() - 1;
+ for (;;)
+ {
+ const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ if (mid == left)
+ break;
+ if (virt < Extents[mid].Virt)
+ right = mid;
+ else
+ left = mid;
+ }
+ _prevExtentIndex = left;
+ }
+
+ {
+ const UInt64 rem = Extents[left + 1].Virt - virt;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ const CSeekExtent &extent = Extents[left];
+
+ if (extent.Is_ZeroFill())
+ {
+ memset(data, 0, size);
+ _virtPos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ }
+
+ {
+ const UInt64 phy = extent.Phy + (virt - extent.Virt);
+ if (_phyPos != phy)
+ {
+ _phyPos = (UInt64)0 - 1; // we don't trust seek_pos in case of error
+ RINOK(InStream_SeekSet(Stream, phy))
+ _phyPos = phy;
+ }
+ }
+
+ const HRESULT res = Stream->Read(data, size, &size);
+ _virtPos += size;
+ if (res == S_OK)
+ _phyPos += size;
+ else
+ _phyPos = (UInt64)0 - 1; // we don't trust seek_pos in case of error
+ if (processedSize)
+ *processedSize = size;
+ return res;
+}
+
+
+Z7_COM7F_IMF(CExtentsStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += Extents.Back().Virt; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _virtPos = (UInt64)offset;
+ if (newPosition)
+ *newPosition = _virtPos;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CLimitedSequentialOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ HRESULT result = S_OK;
+ if (processedSize)
+ *processedSize = 0;
+ if (size > _size)
+ {
+ if (_size == 0)
+ {
+ _overflow = true;
+ if (!_overflowIsAllowed)
+ return E_FAIL;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ }
+ size = (UInt32)_size;
+ }
+ if (_stream)
+ result = _stream->Write(data, size, &size);
+ _size -= size;
+ if (processedSize)
+ *processedSize = size;
+ return result;
+}
+
+
+Z7_COM7F_IMF(CTailInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ UInt32 cur;
+ HRESULT res = Stream->Read(data, size, &cur);
+ if (processedSize)
+ *processedSize = cur;
+ _virtPos += cur;
+ return res;
+}
+
+Z7_COM7F_IMF(CTailInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END:
+ {
+ UInt64 pos = 0;
+ RINOK(Stream->Seek(offset, STREAM_SEEK_END, &pos))
+ if (pos < Offset)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _virtPos = pos - Offset;
+ if (newPosition)
+ *newPosition = _virtPos;
+ return S_OK;
+ }
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _virtPos = (UInt64)offset;
+ if (newPosition)
+ *newPosition = _virtPos;
+ return InStream_SeekSet(Stream, Offset + _virtPos);
+}
+
+Z7_COM7F_IMF(CLimitedCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (_virtPos >= _size)
+ {
+ // 9.31: Fixed. Windows doesn't return error in ReadFile and IStream->Read in that case.
+ return S_OK;
+ // return (_virtPos == _size) ? S_OK: E_FAIL; // ERROR_HANDLE_EOF
+ }
+ UInt64 rem = _size - _virtPos;
+ if (rem < size)
+ size = (UInt32)rem;
+
+ UInt64 newPos = _startOffset + _virtPos;
+ UInt64 offsetInCache = newPos - _cachePhyPos;
+ HRESULT res = S_OK;
+ if (newPos >= _cachePhyPos &&
+ offsetInCache <= _cacheSize &&
+ size <= _cacheSize - (size_t)offsetInCache)
+ {
+ if (size != 0)
+ memcpy(data, _cache + (size_t)offsetInCache, size);
+ }
+ else
+ {
+ if (newPos != _physPos)
+ {
+ _physPos = newPos;
+ RINOK(SeekToPhys())
+ }
+ res = _stream->Read(data, size, &size);
+ _physPos += size;
+ }
+ if (processedSize)
+ *processedSize = size;
+ _virtPos += size;
+ return res;
+}
+
+Z7_COM7F_IMF(CLimitedCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += _size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _virtPos = (UInt64)offset;
+ if (newPosition)
+ *newPosition = _virtPos;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CTailOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ UInt32 cur;
+ HRESULT res = Stream->Write(data, size, &cur);
+ if (processedSize)
+ *processedSize = cur;
+ _virtPos += cur;
+ if (_virtSize < _virtPos)
+ _virtSize = _virtPos;
+ return res;
+}
+
+Z7_COM7F_IMF(CTailOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _virtPos; break;
+ case STREAM_SEEK_END: offset += _virtSize; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _virtPos = (UInt64)offset;
+ if (newPosition)
+ *newPosition = _virtPos;
+ return Stream->Seek((Int64)(Offset + _virtPos), STREAM_SEEK_SET, NULL);
+}
+
+Z7_COM7F_IMF(CTailOutStream::SetSize(UInt64 newSize))
+{
+ _virtSize = newSize;
+ return Stream->SetSize(Offset + newSize);
+}
diff --git a/CPP/7zip/Common/LimitedStreams.h b/CPP/7zip/Common/LimitedStreams.h
index 2e55aa0..69fcdcd 100644
--- a/CPP/7zip/Common/LimitedStreams.h
+++ b/CPP/7zip/Common/LimitedStreams.h
@@ -1,252 +1,221 @@
-// LimitedStreams.h
-
-#ifndef __LIMITED_STREAMS_H
-#define __LIMITED_STREAMS_H
-
-#include "../../Common/MyBuffer.h"
-#include "../../Common/MyCom.h"
-#include "../../Common/MyVector.h"
-#include "../IStream.h"
-
-class CLimitedSequentialInStream:
- public ISequentialInStream,
- public CMyUnknownImp
-{
- CMyComPtr<ISequentialInStream> _stream;
- UInt64 _size;
- UInt64 _pos;
- bool _wasFinished;
-public:
- void SetStream(ISequentialInStream *stream) { _stream = stream; }
- void ReleaseStream() { _stream.Release(); }
- void Init(UInt64 streamSize)
- {
- _size = streamSize;
- _pos = 0;
- _wasFinished = false;
- }
-
- MY_UNKNOWN_IMP1(ISequentialInStream)
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- UInt64 GetSize() const { return _pos; }
- UInt64 GetRem() const { return _size - _pos; }
- bool WasFinished() const { return _wasFinished; }
-};
-
-class CLimitedInStream:
- public IInStream,
- public CMyUnknownImp
-{
- CMyComPtr<IInStream> _stream;
- UInt64 _virtPos;
- UInt64 _physPos;
- UInt64 _size;
- UInt64 _startOffset;
-
- HRESULT SeekToPhys() { return _stream->Seek(_physPos, STREAM_SEEK_SET, NULL); }
-public:
- void SetStream(IInStream *stream) { _stream = stream; }
- HRESULT InitAndSeek(UInt64 startOffset, UInt64 size)
- {
- _startOffset = startOffset;
- _physPos = startOffset;
- _virtPos = 0;
- _size = size;
- return SeekToPhys();
- }
-
- MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
-
- HRESULT SeekToStart() { return Seek(0, STREAM_SEEK_SET, NULL); }
-};
-
-HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream);
-
-class CClusterInStream:
- public IInStream,
- public CMyUnknownImp
-{
- UInt64 _virtPos;
- UInt64 _physPos;
- UInt32 _curRem;
-public:
- unsigned BlockSizeLog;
- UInt64 Size;
- CMyComPtr<IInStream> Stream;
- CRecordVector<UInt32> Vector;
- UInt64 StartOffset;
-
- HRESULT SeekToPhys() { return Stream->Seek(_physPos, STREAM_SEEK_SET, NULL); }
-
- HRESULT InitAndSeek()
- {
- _curRem = 0;
- _virtPos = 0;
- _physPos = StartOffset;
- if (Vector.Size() > 0)
- {
- _physPos = StartOffset + (Vector[0] << BlockSizeLog);
- return SeekToPhys();
- }
- return S_OK;
- }
-
- MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
-};
-
-struct CSeekExtent
-{
- UInt64 Phy;
- UInt64 Virt;
-};
-
-class CExtentsStream:
- public IInStream,
- public CMyUnknownImp
-{
- UInt64 _phyPos;
- UInt64 _virtPos;
- bool _needStartSeek;
-
- HRESULT SeekToPhys() { return Stream->Seek(_phyPos, STREAM_SEEK_SET, NULL); }
-
-public:
- CMyComPtr<IInStream> Stream;
- CRecordVector<CSeekExtent> Extents;
-
- MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
- void ReleaseStream() { Stream.Release(); }
-
- void Init()
- {
- _virtPos = 0;
- _phyPos = 0;
- _needStartSeek = true;
- }
-};
-
-class CLimitedSequentialOutStream:
- public ISequentialOutStream,
- public CMyUnknownImp
-{
- CMyComPtr<ISequentialOutStream> _stream;
- UInt64 _size;
- bool _overflow;
- bool _overflowIsAllowed;
-public:
- MY_UNKNOWN_IMP1(ISequentialOutStream)
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
- void SetStream(ISequentialOutStream *stream) { _stream = stream; }
- void ReleaseStream() { _stream.Release(); }
- void Init(UInt64 size, bool overflowIsAllowed = false)
- {
- _size = size;
- _overflow = false;
- _overflowIsAllowed = overflowIsAllowed;
- }
- bool IsFinishedOK() const { return (_size == 0 && !_overflow); }
- UInt64 GetRem() const { return _size; }
-};
-
-
-class CTailInStream:
- public IInStream,
- public CMyUnknownImp
-{
- UInt64 _virtPos;
-public:
- CMyComPtr<IInStream> Stream;
- UInt64 Offset;
-
- void Init()
- {
- _virtPos = 0;
- }
-
- MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
-
- HRESULT SeekToStart() { return Stream->Seek(Offset, STREAM_SEEK_SET, NULL); }
-};
-
-class CLimitedCachedInStream:
- public IInStream,
- public CMyUnknownImp
-{
- CMyComPtr<IInStream> _stream;
- UInt64 _virtPos;
- UInt64 _physPos;
- UInt64 _size;
- UInt64 _startOffset;
-
- const Byte *_cache;
- size_t _cacheSize;
- size_t _cachePhyPos;
-
-
- HRESULT SeekToPhys() { return _stream->Seek(_physPos, STREAM_SEEK_SET, NULL); }
-public:
- CByteBuffer Buffer;
-
- void SetStream(IInStream *stream) { _stream = stream; }
- void SetCache(size_t cacheSize, size_t cachePos)
- {
- _cache = Buffer;
- _cacheSize = cacheSize;
- _cachePhyPos = cachePos;
- }
-
- HRESULT InitAndSeek(UInt64 startOffset, UInt64 size)
- {
- _startOffset = startOffset;
- _physPos = startOffset;
- _virtPos = 0;
- _size = size;
- return SeekToPhys();
- }
-
- MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
-
- HRESULT SeekToStart() { return Seek(0, STREAM_SEEK_SET, NULL); }
-};
-
-class CTailOutStream:
- public IOutStream,
- public CMyUnknownImp
-{
- UInt64 _virtPos;
- UInt64 _virtSize;
-public:
- CMyComPtr<IOutStream> Stream;
- UInt64 Offset;
-
- virtual ~CTailOutStream() {}
-
- MY_UNKNOWN_IMP2(ISequentialOutStream, IOutStream)
-
- void Init()
- {
- _virtPos = 0;
- _virtSize = 0;
- }
-
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
- STDMETHOD(SetSize)(UInt64 newSize);
-};
-
-#endif
+// LimitedStreams.h
+
+#ifndef ZIP7_INC_LIMITED_STREAMS_H
+#define ZIP7_INC_LIMITED_STREAMS_H
+
+#include "../../Common/MyBuffer.h"
+#include "../../Common/MyCom.h"
+#include "../../Common/MyVector.h"
+#include "../IStream.h"
+
+#include "StreamUtils.h"
+
+Z7_CLASS_IMP_COM_1(
+ CLimitedSequentialInStream
+ , ISequentialInStream
+)
+ CMyComPtr<ISequentialInStream> _stream;
+ UInt64 _size;
+ UInt64 _pos;
+ bool _wasFinished;
+public:
+ void SetStream(ISequentialInStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init(UInt64 streamSize)
+ {
+ _size = streamSize;
+ _pos = 0;
+ _wasFinished = false;
+ }
+ UInt64 GetSize() const { return _pos; }
+ UInt64 GetRem() const { return _size - _pos; }
+ bool WasFinished() const { return _wasFinished; }
+};
+
+
+Z7_CLASS_IMP_IInStream(
+ CLimitedInStream
+)
+ CMyComPtr<IInStream> _stream;
+ UInt64 _virtPos;
+ UInt64 _physPos;
+ UInt64 _size;
+ UInt64 _startOffset;
+
+ HRESULT SeekToPhys() { return InStream_SeekSet(_stream, _physPos); }
+public:
+ void SetStream(IInStream *stream) { _stream = stream; }
+ HRESULT InitAndSeek(UInt64 startOffset, UInt64 size)
+ {
+ _startOffset = startOffset;
+ _physPos = startOffset;
+ _virtPos = 0;
+ _size = size;
+ return SeekToPhys();
+ }
+ HRESULT SeekToStart() { return Seek(0, STREAM_SEEK_SET, NULL); }
+};
+
+HRESULT CreateLimitedInStream(IInStream *inStream, UInt64 pos, UInt64 size, ISequentialInStream **resStream);
+
+
+Z7_CLASS_IMP_IInStream(
+ CClusterInStream
+)
+ UInt64 _virtPos;
+ UInt64 _physPos;
+ UInt32 _curRem;
+public:
+ unsigned BlockSizeLog;
+ UInt64 Size;
+ CMyComPtr<IInStream> Stream;
+ CRecordVector<UInt32> Vector;
+ UInt64 StartOffset;
+
+ HRESULT SeekToPhys() { return InStream_SeekSet(Stream, _physPos); }
+
+ HRESULT InitAndSeek()
+ {
+ _curRem = 0;
+ _virtPos = 0;
+ _physPos = StartOffset;
+ if (Vector.Size() > 0)
+ {
+ _physPos = StartOffset + (Vector[0] << BlockSizeLog);
+ return SeekToPhys();
+ }
+ return S_OK;
+ }
+};
+
+
+
+const UInt64 k_SeekExtent_Phy_Type_ZeroFill = (UInt64)(Int64)-1;
+
+struct CSeekExtent
+{
+ UInt64 Virt;
+ UInt64 Phy;
+
+ void SetAs_ZeroFill() { Phy = k_SeekExtent_Phy_Type_ZeroFill; }
+ bool Is_ZeroFill() const { return Phy == k_SeekExtent_Phy_Type_ZeroFill; }
+};
+
+
+Z7_CLASS_IMP_IInStream(
+ CExtentsStream
+)
+ UInt64 _virtPos;
+ UInt64 _phyPos;
+ unsigned _prevExtentIndex;
+public:
+ CMyComPtr<IInStream> Stream;
+ CRecordVector<CSeekExtent> Extents;
+
+ void ReleaseStream() { Stream.Release(); }
+ void Init()
+ {
+ _virtPos = 0;
+ _phyPos = (UInt64)0 - 1; // we need Seek() for Stream
+ _prevExtentIndex = 0;
+ }
+};
+
+
+
+Z7_CLASS_IMP_COM_1(
+ CLimitedSequentialOutStream
+ , ISequentialOutStream
+)
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+ bool _overflow;
+ bool _overflowIsAllowed;
+public:
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init(UInt64 size, bool overflowIsAllowed = false)
+ {
+ _size = size;
+ _overflow = false;
+ _overflowIsAllowed = overflowIsAllowed;
+ }
+ bool IsFinishedOK() const { return (_size == 0 && !_overflow); }
+ UInt64 GetRem() const { return _size; }
+};
+
+
+Z7_CLASS_IMP_IInStream(
+ CTailInStream
+)
+ UInt64 _virtPos;
+public:
+ CMyComPtr<IInStream> Stream;
+ UInt64 Offset;
+
+ void Init()
+ {
+ _virtPos = 0;
+ }
+ HRESULT SeekToStart() { return InStream_SeekSet(Stream, Offset); }
+};
+
+
+Z7_CLASS_IMP_IInStream(
+ CLimitedCachedInStream
+)
+ CMyComPtr<IInStream> _stream;
+ UInt64 _virtPos;
+ UInt64 _physPos;
+ UInt64 _size;
+ UInt64 _startOffset;
+
+ const Byte *_cache;
+ size_t _cacheSize;
+ size_t _cachePhyPos;
+
+ HRESULT SeekToPhys() { return InStream_SeekSet(_stream, _physPos); }
+public:
+ CByteBuffer Buffer;
+
+ void SetStream(IInStream *stream) { _stream = stream; }
+ void SetCache(size_t cacheSize, size_t cachePos)
+ {
+ _cache = Buffer;
+ _cacheSize = cacheSize;
+ _cachePhyPos = cachePos;
+ }
+
+ HRESULT InitAndSeek(UInt64 startOffset, UInt64 size)
+ {
+ _startOffset = startOffset;
+ _physPos = startOffset;
+ _virtPos = 0;
+ _size = size;
+ return SeekToPhys();
+ }
+
+ HRESULT SeekToStart() { return Seek(0, STREAM_SEEK_SET, NULL); }
+};
+
+
+class CTailOutStream Z7_final :
+ public IOutStream,
+ public CMyUnknownImp
+{
+ Z7_IFACES_IMP_UNK_2(ISequentialOutStream, IOutStream)
+
+ UInt64 _virtPos;
+ UInt64 _virtSize;
+public:
+ CMyComPtr<IOutStream> Stream;
+ UInt64 Offset;
+
+ void Init()
+ {
+ _virtPos = 0;
+ _virtSize = 0;
+ }
+};
+
+#endif
diff --git a/CPP/7zip/Common/LockedStream.cpp b/CPP/7zip/Common/LockedStream.cpp
index 1223efe..ca39fb4 100644
--- a/CPP/7zip/Common/LockedStream.cpp
+++ b/CPP/7zip/Common/LockedStream.cpp
@@ -1,3 +1,3 @@
-// LockedStream.cpp
-
-#include "StdAfx.h"
+// LockedStream.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Common/LockedStream.h b/CPP/7zip/Common/LockedStream.h
index 5bf5c85..99ee805 100644
--- a/CPP/7zip/Common/LockedStream.h
+++ b/CPP/7zip/Common/LockedStream.h
@@ -1,6 +1,6 @@
-// LockedStream.h
-
-#ifndef __LOCKED_STREAM_H
-#define __LOCKED_STREAM_H
-
-#endif
+// LockedStream.h
+
+#ifndef ZIP7_INC_LOCKED_STREAM_H
+#define ZIP7_INC_LOCKED_STREAM_H
+
+#endif
diff --git a/CPP/7zip/Common/MemBlocks.cpp b/CPP/7zip/Common/MemBlocks.cpp
new file mode 100644
index 0000000..aa68244
--- /dev/null
+++ b/CPP/7zip/Common/MemBlocks.cpp
@@ -0,0 +1,215 @@
+// MemBlocks.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "MemBlocks.h"
+#include "StreamUtils.h"
+
+bool CMemBlockManager::AllocateSpace_bool(size_t numBlocks)
+{
+ FreeSpace();
+ if (numBlocks == 0)
+ {
+ return true;
+ // return false;
+ }
+ if (_blockSize < sizeof(void *))
+ return false;
+ const size_t totalSize = numBlocks * _blockSize;
+ if (totalSize / _blockSize != numBlocks)
+ return false;
+ _data = ::MidAlloc(totalSize);
+ if (!_data)
+ return false;
+ Byte *p = (Byte *)_data;
+ for (size_t i = 0; i + 1 < numBlocks; i++, p += _blockSize)
+ *(Byte **)(void *)p = (p + _blockSize);
+ *(Byte **)(void *)p = NULL;
+ _headFree = _data;
+ return true;
+}
+
+void CMemBlockManager::FreeSpace()
+{
+ ::MidFree(_data);
+ _data = NULL;
+ _headFree= NULL;
+}
+
+void *CMemBlockManager::AllocateBlock()
+{
+ void *p = _headFree;
+ if (p)
+ _headFree = *(void **)p;
+ return p;
+}
+
+void CMemBlockManager::FreeBlock(void *p)
+{
+ if (!p)
+ return;
+ *(void **)p = _headFree;
+ _headFree = p;
+}
+
+
+// #include <stdio.h>
+
+HRes CMemBlockManagerMt::AllocateSpace(size_t numBlocks, size_t numNoLockBlocks)
+{
+ if (numNoLockBlocks > numBlocks)
+ return E_INVALIDARG;
+ const size_t numLockBlocks = numBlocks - numNoLockBlocks;
+ UInt32 maxCount = (UInt32)numLockBlocks;
+ if (maxCount != numLockBlocks)
+ return E_OUTOFMEMORY;
+ if (!CMemBlockManager::AllocateSpace_bool(numBlocks))
+ return E_OUTOFMEMORY;
+ // we need (maxCount = 1), if we want to create non-use empty Semaphore
+ if (maxCount == 0)
+ maxCount = 1;
+
+ // printf("\n Synchro.Create() \n");
+ WRes wres;
+ #ifndef _WIN32
+ Semaphore.Close();
+ wres = Synchro.Create();
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ wres = Semaphore.Create(&Synchro, (UInt32)numLockBlocks, maxCount);
+ #else
+ wres = Semaphore.OptCreateInit((UInt32)numLockBlocks, maxCount);
+ #endif
+
+ return HRESULT_FROM_WIN32(wres);
+}
+
+
+HRes CMemBlockManagerMt::AllocateSpaceAlways(size_t desiredNumberOfBlocks, size_t numNoLockBlocks)
+{
+ // desiredNumberOfBlocks = 0; // for debug
+ if (numNoLockBlocks > desiredNumberOfBlocks)
+ return E_INVALIDARG;
+ for (;;)
+ {
+ // if (desiredNumberOfBlocks == 0) return E_OUTOFMEMORY;
+ HRes hres = AllocateSpace(desiredNumberOfBlocks, numNoLockBlocks);
+ if (hres != E_OUTOFMEMORY)
+ return hres;
+ if (desiredNumberOfBlocks == numNoLockBlocks)
+ return E_OUTOFMEMORY;
+ desiredNumberOfBlocks = numNoLockBlocks + ((desiredNumberOfBlocks - numNoLockBlocks) >> 1);
+ }
+}
+
+void CMemBlockManagerMt::FreeSpace()
+{
+ Semaphore.Close();
+ CMemBlockManager::FreeSpace();
+}
+
+void *CMemBlockManagerMt::AllocateBlock()
+{
+ // Semaphore.Lock();
+ NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ return CMemBlockManager::AllocateBlock();
+}
+
+void CMemBlockManagerMt::FreeBlock(void *p, bool lockMode)
+{
+ if (!p)
+ return;
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ CMemBlockManager::FreeBlock(p);
+ }
+ if (lockMode)
+ Semaphore.Release();
+}
+
+
+
+void CMemBlocks::Free(CMemBlockManagerMt *manager)
+{
+ while (Blocks.Size() > 0)
+ {
+ manager->FreeBlock(Blocks.Back());
+ Blocks.DeleteBack();
+ }
+ TotalSize = 0;
+}
+
+void CMemBlocks::FreeOpt(CMemBlockManagerMt *manager)
+{
+ Free(manager);
+ Blocks.ClearAndFree();
+}
+
+HRESULT CMemBlocks::WriteToStream(size_t blockSize, ISequentialOutStream *outStream) const
+{
+ UInt64 totalSize = TotalSize;
+ for (unsigned blockIndex = 0; totalSize > 0; blockIndex++)
+ {
+ size_t curSize = blockSize;
+ if (curSize > totalSize)
+ curSize = (size_t)totalSize;
+ if (blockIndex >= Blocks.Size())
+ return E_FAIL;
+ RINOK(WriteStream(outStream, Blocks[blockIndex], curSize))
+ totalSize -= curSize;
+ }
+ return S_OK;
+}
+
+
+void CMemLockBlocks::FreeBlock(unsigned index, CMemBlockManagerMt *memManager)
+{
+ memManager->FreeBlock(Blocks[index], LockMode);
+ Blocks[index] = NULL;
+}
+
+void CMemLockBlocks::Free(CMemBlockManagerMt *memManager)
+{
+ while (Blocks.Size() > 0)
+ {
+ FreeBlock(Blocks.Size() - 1, memManager);
+ Blocks.DeleteBack();
+ }
+ TotalSize = 0;
+}
+
+/*
+HRes CMemLockBlocks::SwitchToNoLockMode(CMemBlockManagerMt *memManager)
+{
+ if (LockMode)
+ {
+ if (Blocks.Size() > 0)
+ {
+ RINOK(memManager->ReleaseLockedBlocks(Blocks.Size()));
+ }
+ LockMode = false;
+ }
+ return 0;
+}
+*/
+
+void CMemLockBlocks::Detach(CMemLockBlocks &blocks, CMemBlockManagerMt *memManager)
+{
+ blocks.Free(memManager);
+ blocks.LockMode = LockMode;
+ UInt64 totalSize = 0;
+ const size_t blockSize = memManager->GetBlockSize();
+ FOR_VECTOR (i, Blocks)
+ {
+ if (totalSize < TotalSize)
+ blocks.Blocks.Add(Blocks[i]);
+ else
+ FreeBlock(i, memManager);
+ Blocks[i] = NULL;
+ totalSize += blockSize;
+ }
+ blocks.TotalSize = TotalSize;
+ Free(memManager);
+}
diff --git a/CPP/7zip/Common/MemBlocks.h b/CPP/7zip/Common/MemBlocks.h
new file mode 100644
index 0000000..7c34f21
--- /dev/null
+++ b/CPP/7zip/Common/MemBlocks.h
@@ -0,0 +1,72 @@
+// MemBlocks.h
+
+#ifndef ZIP7_INC_MEM_BLOCKS_H
+#define ZIP7_INC_MEM_BLOCKS_H
+
+#include "../../Common/MyVector.h"
+
+#include "../../Windows/Synchronization.h"
+
+#include "../IStream.h"
+
+class CMemBlockManager
+{
+ void *_data;
+ size_t _blockSize;
+ void *_headFree;
+public:
+ CMemBlockManager(size_t blockSize = (1 << 20)): _data(NULL), _blockSize(blockSize), _headFree(NULL) {}
+ ~CMemBlockManager() { FreeSpace(); }
+
+ bool AllocateSpace_bool(size_t numBlocks);
+ void FreeSpace();
+ size_t GetBlockSize() const { return _blockSize; }
+ void *AllocateBlock();
+ void FreeBlock(void *p);
+};
+
+
+class CMemBlockManagerMt: public CMemBlockManager
+{
+ NWindows::NSynchronization::CCriticalSection _criticalSection;
+public:
+ SYNC_OBJ_DECL(Synchro)
+ NWindows::NSynchronization::CSemaphore_WFMO Semaphore;
+
+ CMemBlockManagerMt(size_t blockSize = (1 << 20)): CMemBlockManager(blockSize) {}
+ ~CMemBlockManagerMt() { FreeSpace(); }
+
+ HRes AllocateSpace(size_t numBlocks, size_t numNoLockBlocks);
+ HRes AllocateSpaceAlways(size_t desiredNumberOfBlocks, size_t numNoLockBlocks = 0);
+ void FreeSpace();
+ void *AllocateBlock();
+ void FreeBlock(void *p, bool lockMode = true);
+ // WRes ReleaseLockedBlocks_WRes(unsigned number) { return Semaphore.Release(number); }
+};
+
+
+class CMemBlocks
+{
+ void Free(CMemBlockManagerMt *manager);
+public:
+ CRecordVector<void *> Blocks;
+ UInt64 TotalSize;
+
+ CMemBlocks(): TotalSize(0) {}
+
+ void FreeOpt(CMemBlockManagerMt *manager);
+ HRESULT WriteToStream(size_t blockSize, ISequentialOutStream *outStream) const;
+};
+
+struct CMemLockBlocks: public CMemBlocks
+{
+ bool LockMode;
+
+ CMemLockBlocks(): LockMode(true) {}
+ void Free(CMemBlockManagerMt *memManager);
+ void FreeBlock(unsigned index, CMemBlockManagerMt *memManager);
+ // HRes SwitchToNoLockMode(CMemBlockManagerMt *memManager);
+ void Detach(CMemLockBlocks &blocks, CMemBlockManagerMt *memManager);
+};
+
+#endif
diff --git a/CPP/7zip/Common/MethodId.cpp b/CPP/7zip/Common/MethodId.cpp
index 9a07e4c..1566c97 100644
--- a/CPP/7zip/Common/MethodId.cpp
+++ b/CPP/7zip/Common/MethodId.cpp
@@ -1,3 +1,3 @@
-// MethodId.cpp
-
-#include "StdAfx.h"
+// MethodId.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Common/MethodId.h b/CPP/7zip/Common/MethodId.h
index 1ba9f49..19b1f10 100644
--- a/CPP/7zip/Common/MethodId.h
+++ b/CPP/7zip/Common/MethodId.h
@@ -1,10 +1,10 @@
-// MethodId.h
-
-#ifndef __7Z_METHOD_ID_H
-#define __7Z_METHOD_ID_H
-
-#include "../../Common/MyTypes.h"
-
-typedef UInt64 CMethodId;
-
-#endif
+// MethodId.h
+
+#ifndef ZIP7_INC_7Z_METHOD_ID_H
+#define ZIP7_INC_7Z_METHOD_ID_H
+
+#include "../../Common/MyTypes.h"
+
+typedef UInt64 CMethodId;
+
+#endif
diff --git a/CPP/7zip/Common/MethodProps.cpp b/CPP/7zip/Common/MethodProps.cpp
index 2134462..fe60f61 100644
--- a/CPP/7zip/Common/MethodProps.cpp
+++ b/CPP/7zip/Common/MethodProps.cpp
@@ -1,509 +1,737 @@
-// MethodProps.cpp
-
-#include "StdAfx.h"
-
-#include "../../Common/StringToInt.h"
-
-#include "MethodProps.h"
-
-using namespace NWindows;
-
-bool StringToBool(const wchar_t *s, bool &res)
-{
- if (s[0] == 0 || (s[0] == '+' && s[1] == 0) || StringsAreEqualNoCase_Ascii(s, "ON"))
- {
- res = true;
- return true;
- }
- if ((s[0] == '-' && s[1] == 0) || StringsAreEqualNoCase_Ascii(s, "OFF"))
- {
- res = false;
- return true;
- }
- return false;
-}
-
-HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest)
-{
- switch (prop.vt)
- {
- case VT_EMPTY: dest = true; return S_OK;
- case VT_BOOL: dest = (prop.boolVal != VARIANT_FALSE); return S_OK;
- case VT_BSTR: return StringToBool(prop.bstrVal, dest) ? S_OK : E_INVALIDARG;
- }
- return E_INVALIDARG;
-}
-
-unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number)
-{
- const wchar_t *start = srcString;
- const wchar_t *end;
- number = ConvertStringToUInt32(start, &end);
- return (unsigned)(end - start);
-}
-
-static unsigned ParseStringToUInt64(const UString &srcString, UInt64 &number)
-{
- const wchar_t *start = srcString;
- const wchar_t *end;
- number = ConvertStringToUInt64(start, &end);
- return (unsigned)(end - start);
-}
-
-HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue)
-{
- // =VT_UI4
- // =VT_EMPTY
- // {stringUInt32}=VT_EMPTY
-
- if (prop.vt == VT_UI4)
- {
- if (!name.IsEmpty())
- return E_INVALIDARG;
- resValue = prop.ulVal;
- return S_OK;
- }
- if (prop.vt != VT_EMPTY)
- return E_INVALIDARG;
- if (name.IsEmpty())
- return S_OK;
- UInt32 v;
- if (ParseStringToUInt32(name, v) != name.Len())
- return E_INVALIDARG;
- resValue = v;
- return S_OK;
-}
-
-HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads)
-{
- if (name.IsEmpty())
- {
- switch (prop.vt)
- {
- case VT_UI4:
- numThreads = prop.ulVal;
- break;
- default:
- {
- bool val;
- RINOK(PROPVARIANT_to_bool(prop, val));
- numThreads = (val ? defaultNumThreads : 1);
- break;
- }
- }
- return S_OK;
- }
- if (prop.vt != VT_EMPTY)
- return E_INVALIDARG;
- return ParsePropToUInt32(name, prop, numThreads);
-}
-
-
-static HRESULT StringToDictSize(const UString &s, NCOM::CPropVariant &destProp)
-{
- const wchar_t *end;
- UInt32 number = ConvertStringToUInt32(s, &end);
- unsigned numDigits = (unsigned)(end - s.Ptr());
- if (numDigits == 0 || s.Len() > numDigits + 1)
- return E_INVALIDARG;
-
- if (s.Len() == numDigits)
- {
- if (number >= 64)
- return E_INVALIDARG;
- if (number < 32)
- destProp = (UInt32)((UInt32)1 << (unsigned)number);
- else
- destProp = (UInt64)((UInt64)1 << (unsigned)number);
- return S_OK;
- }
-
- unsigned numBits;
-
- switch (MyCharLower_Ascii(s[numDigits]))
- {
- case 'b': destProp = number; return S_OK;
- case 'k': numBits = 10; break;
- case 'm': numBits = 20; break;
- case 'g': numBits = 30; break;
- default: return E_INVALIDARG;
- }
-
- if (number < ((UInt32)1 << (32 - numBits)))
- destProp = (UInt32)(number << numBits);
- else
- destProp = (UInt64)((UInt64)number << numBits);
-
- return S_OK;
-}
-
-
-static HRESULT PROPVARIANT_to_DictSize(const PROPVARIANT &prop, NCOM::CPropVariant &destProp)
-{
- if (prop.vt == VT_UI4)
- {
- UInt32 v = prop.ulVal;
- if (v >= 64)
- return E_INVALIDARG;
- if (v < 32)
- destProp = (UInt32)((UInt32)1 << (unsigned)v);
- else
- destProp = (UInt64)((UInt64)1 << (unsigned)v);
- return S_OK;
- }
- if (prop.vt == VT_BSTR)
- {
- UString s;
- s = prop.bstrVal;
- return StringToDictSize(s, destProp);
- }
- return E_INVALIDARG;
-}
-
-
-void CProps::AddProp32(PROPID propid, UInt32 val)
-{
- CProp &prop = Props.AddNew();
- prop.IsOptional = true;
- prop.Id = propid;
- prop.Value = (UInt32)val;
-}
-
-void CProps::AddPropBool(PROPID propid, bool val)
-{
- CProp &prop = Props.AddNew();
- prop.IsOptional = true;
- prop.Id = propid;
- prop.Value = val;
-}
-
-class CCoderProps
-{
- PROPID *_propIDs;
- NCOM::CPropVariant *_props;
- unsigned _numProps;
- unsigned _numPropsMax;
-public:
- CCoderProps(unsigned numPropsMax)
- {
- _numPropsMax = numPropsMax;
- _numProps = 0;
- _propIDs = new PROPID[numPropsMax];
- _props = new NCOM::CPropVariant[numPropsMax];
- }
- ~CCoderProps()
- {
- delete []_propIDs;
- delete []_props;
- }
- void AddProp(const CProp &prop);
- HRESULT SetProps(ICompressSetCoderProperties *setCoderProperties)
- {
- return setCoderProperties->SetCoderProperties(_propIDs, _props, _numProps);
- }
-};
-
-void CCoderProps::AddProp(const CProp &prop)
-{
- if (_numProps >= _numPropsMax)
- throw 1;
- _propIDs[_numProps] = prop.Id;
- _props[_numProps] = prop.Value;
- _numProps++;
-}
-
-HRESULT CProps::SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const
-{
- CCoderProps coderProps(Props.Size() + (dataSizeReduce ? 1 : 0));
- FOR_VECTOR (i, Props)
- coderProps.AddProp(Props[i]);
- if (dataSizeReduce)
- {
- CProp prop;
- prop.Id = NCoderPropID::kReduceSize;
- prop.Value = *dataSizeReduce;
- coderProps.AddProp(prop);
- }
- return coderProps.SetProps(scp);
-}
-
-
-int CMethodProps::FindProp(PROPID id) const
-{
- for (int i = Props.Size() - 1; i >= 0; i--)
- if (Props[i].Id == id)
- return i;
- return -1;
-}
-
-int CMethodProps::GetLevel() const
-{
- int i = FindProp(NCoderPropID::kLevel);
- if (i < 0)
- return 5;
- if (Props[i].Value.vt != VT_UI4)
- return 9;
- UInt32 level = Props[i].Value.ulVal;
- return level > 9 ? 9 : (int)level;
-}
-
-struct CNameToPropID
-{
- VARTYPE VarType;
- const char *Name;
-};
-
-
-// the following are related to NCoderPropID::EEnum values
-
-static const CNameToPropID g_NameToPropID[] =
-{
- { VT_UI4, "" },
- { VT_UI4, "d" },
- { VT_UI4, "mem" },
- { VT_UI4, "o" },
- { VT_UI4, "c" },
- { VT_UI4, "pb" },
- { VT_UI4, "lc" },
- { VT_UI4, "lp" },
- { VT_UI4, "fb" },
- { VT_BSTR, "mf" },
- { VT_UI4, "mc" },
- { VT_UI4, "pass" },
- { VT_UI4, "a" },
- { VT_UI4, "mt" },
- { VT_BOOL, "eos" },
- { VT_UI4, "x" },
- { VT_UI8, "reduce" },
- { VT_UI8, "expect" },
- { VT_UI4, "b" },
- { VT_UI4, "check" },
- { VT_BSTR, "filter" },
- { VT_UI8, "memuse" }
-};
-
-static int FindPropIdExact(const UString &name)
-{
- for (unsigned i = 0; i < ARRAY_SIZE(g_NameToPropID); i++)
- if (StringsAreEqualNoCase_Ascii(name, g_NameToPropID[i].Name))
- return i;
- return -1;
-}
-
-static bool ConvertProperty(const PROPVARIANT &srcProp, VARTYPE varType, NCOM::CPropVariant &destProp)
-{
- if (varType == srcProp.vt)
- {
- destProp = srcProp;
- return true;
- }
-
- if (varType == VT_UI8 && srcProp.vt == VT_UI4)
- {
- destProp = (UInt64)srcProp.ulVal;
- return true;
- }
-
- if (varType == VT_BOOL)
- {
- bool res;
- if (PROPVARIANT_to_bool(srcProp, res) != S_OK)
- return false;
- destProp = res;
- return true;
- }
- if (srcProp.vt == VT_EMPTY)
- {
- destProp = srcProp;
- return true;
- }
- return false;
-}
-
-static void SplitParams(const UString &srcString, UStringVector &subStrings)
-{
- subStrings.Clear();
- UString s;
- unsigned len = srcString.Len();
- if (len == 0)
- return;
- for (unsigned i = 0; i < len; i++)
- {
- wchar_t c = srcString[i];
- if (c == L':')
- {
- subStrings.Add(s);
- s.Empty();
- }
- else
- s += c;
- }
- subStrings.Add(s);
-}
-
-static void SplitParam(const UString &param, UString &name, UString &value)
-{
- int eqPos = param.Find(L'=');
- if (eqPos >= 0)
- {
- name.SetFrom(param, eqPos);
- value = param.Ptr(eqPos + 1);
- return;
- }
- unsigned i;
- for (i = 0; i < param.Len(); i++)
- {
- wchar_t c = param[i];
- if (c >= L'0' && c <= L'9')
- break;
- }
- name.SetFrom(param, i);
- value = param.Ptr(i);
-}
-
-static bool IsLogSizeProp(PROPID propid)
-{
- switch (propid)
- {
- case NCoderPropID::kDictionarySize:
- case NCoderPropID::kUsedMemorySize:
- case NCoderPropID::kBlockSize:
- case NCoderPropID::kBlockSize2:
- // case NCoderPropID::kReduceSize:
- return true;
- }
- return false;
-}
-
-HRESULT CMethodProps::SetParam(const UString &name, const UString &value)
-{
- int index = FindPropIdExact(name);
- if (index < 0)
- return E_INVALIDARG;
- const CNameToPropID &nameToPropID = g_NameToPropID[(unsigned)index];
- CProp prop;
- prop.Id = index;
-
- if (IsLogSizeProp(prop.Id))
- {
- RINOK(StringToDictSize(value, prop.Value));
- }
- else
- {
- NCOM::CPropVariant propValue;
- if (nameToPropID.VarType == VT_BSTR)
- propValue = value;
- else if (nameToPropID.VarType == VT_BOOL)
- {
- bool res;
- if (!StringToBool(value, res))
- return E_INVALIDARG;
- propValue = res;
- }
- else if (!value.IsEmpty())
- {
- if (nameToPropID.VarType == VT_UI4)
- {
- UInt32 number;
- if (ParseStringToUInt32(value, number) == value.Len())
- propValue = number;
- else
- propValue = value;
- }
- else if (nameToPropID.VarType == VT_UI8)
- {
- UInt64 number;
- if (ParseStringToUInt64(value, number) == value.Len())
- propValue = number;
- else
- propValue = value;
- }
- else
- propValue = value;
- }
- if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value))
- return E_INVALIDARG;
- }
- Props.Add(prop);
- return S_OK;
-}
-
-HRESULT CMethodProps::ParseParamsFromString(const UString &srcString)
-{
- UStringVector params;
- SplitParams(srcString, params);
- FOR_VECTOR (i, params)
- {
- const UString &param = params[i];
- UString name, value;
- SplitParam(param, name, value);
- RINOK(SetParam(name, value));
- }
- return S_OK;
-}
-
-HRESULT CMethodProps::ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value)
-{
- if (realName.Len() == 0)
- {
- // [empty]=method
- return E_INVALIDARG;
- }
- if (value.vt == VT_EMPTY)
- {
- // {realName}=[empty]
- UString name, valueStr;
- SplitParam(realName, name, valueStr);
- return SetParam(name, valueStr);
- }
-
- // {realName}=value
- int index = FindPropIdExact(realName);
- if (index < 0)
- return E_INVALIDARG;
- const CNameToPropID &nameToPropID = g_NameToPropID[(unsigned)index];
- CProp prop;
- prop.Id = index;
-
- if (IsLogSizeProp(prop.Id))
- {
- RINOK(PROPVARIANT_to_DictSize(value, prop.Value));
- }
- else
- {
- if (!ConvertProperty(value, nameToPropID.VarType, prop.Value))
- return E_INVALIDARG;
- }
- Props.Add(prop);
- return S_OK;
-}
-
-HRESULT COneMethodInfo::ParseMethodFromString(const UString &s)
-{
- MethodName.Empty();
- int splitPos = s.Find(L':');
- {
- UString temp = s;
- if (splitPos >= 0)
- temp.DeleteFrom(splitPos);
- if (!temp.IsAscii())
- return E_INVALIDARG;
- MethodName.SetFromWStr_if_Ascii(temp);
- }
- if (splitPos < 0)
- return S_OK;
- PropsString = s.Ptr(splitPos + 1);
- return ParseParamsFromString(PropsString);
-}
-
-HRESULT COneMethodInfo::ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value)
-{
- if (!realName.IsEmpty() && !StringsAreEqualNoCase_Ascii(realName, "m"))
- return ParseParamsFromPROPVARIANT(realName, value);
- // -m{N}=method
- if (value.vt != VT_BSTR)
- return E_INVALIDARG;
- UString s;
- s = value.bstrVal;
- return ParseMethodFromString(s);
-}
+// MethodProps.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/StringToInt.h"
+
+#include "MethodProps.h"
+
+using namespace NWindows;
+
+UInt64 Calc_From_Val_Percents(UInt64 val, UInt64 percents)
+{
+ // if (percents == 0) return 0;
+ const UInt64 q = percents / 100;
+ const UInt32 r = (UInt32)(percents % 100);
+ UInt64 res = 0;
+
+ if (q != 0)
+ {
+ if (val > (UInt64)(Int64)-1 / q)
+ return (UInt64)(Int64)-1;
+ res = val * q;
+ }
+
+ if (r != 0)
+ {
+ UInt64 v2;
+ if (val <= (UInt64)(Int64)-1 / r)
+ v2 = val * r / 100;
+ else
+ v2 = val / 100 * r;
+ res += v2;
+ if (res < v2)
+ return (UInt64)(Int64)-1;
+ }
+
+ return res;
+}
+
+
+bool StringToBool(const wchar_t *s, bool &res)
+{
+ if (s[0] == 0 || (s[0] == '+' && s[1] == 0) || StringsAreEqualNoCase_Ascii(s, "ON"))
+ {
+ res = true;
+ return true;
+ }
+ if ((s[0] == '-' && s[1] == 0) || StringsAreEqualNoCase_Ascii(s, "OFF"))
+ {
+ res = false;
+ return true;
+ }
+ return false;
+}
+
+HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest)
+{
+ switch (prop.vt)
+ {
+ case VT_EMPTY: dest = true; return S_OK;
+ case VT_BOOL: dest = (prop.boolVal != VARIANT_FALSE); return S_OK;
+ case VT_BSTR: return StringToBool(prop.bstrVal, dest) ? S_OK : E_INVALIDARG;
+ }
+ return E_INVALIDARG;
+}
+
+unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number)
+{
+ const wchar_t *start = srcString;
+ const wchar_t *end;
+ number = ConvertStringToUInt32(start, &end);
+ return (unsigned)(end - start);
+}
+
+static unsigned ParseStringToUInt64(const UString &srcString, UInt64 &number)
+{
+ const wchar_t *start = srcString;
+ const wchar_t *end;
+ number = ConvertStringToUInt64(start, &end);
+ return (unsigned)(end - start);
+}
+
+HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue)
+{
+ // =VT_UI4
+ // =VT_EMPTY : it doesn't change (resValue), and returns S_OK
+ // {stringUInt32}=VT_EMPTY
+
+ if (prop.vt == VT_UI4)
+ {
+ if (!name.IsEmpty())
+ return E_INVALIDARG;
+ resValue = prop.ulVal;
+ return S_OK;
+ }
+ if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ if (name.IsEmpty())
+ return S_OK;
+ UInt32 v;
+ if (ParseStringToUInt32(name, v) != name.Len())
+ return E_INVALIDARG;
+ resValue = v;
+ return S_OK;
+}
+
+
+
+HRESULT ParseMtProp2(const UString &name, const PROPVARIANT &prop, UInt32 &numThreads, bool &force)
+{
+ force = false;
+ UString s;
+ if (name.IsEmpty())
+ {
+ if (prop.vt == VT_UI4)
+ {
+ numThreads = prop.ulVal;
+ force = true;
+ return S_OK;
+ }
+ bool val;
+ HRESULT res = PROPVARIANT_to_bool(prop, val);
+ if (res == S_OK)
+ {
+ if (!val)
+ {
+ numThreads = 1;
+ force = true;
+ }
+ // force = true; for debug
+ // "(VT_BOOL = VARIANT_TRUE)" set "force = false" and doesn't change numThreads
+ return S_OK;
+ }
+ if (prop.vt != VT_BSTR)
+ return res;
+ s.SetFromBstr(prop.bstrVal);
+ if (s.IsEmpty())
+ return E_INVALIDARG;
+ }
+ else
+ {
+ if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ s = name;
+ }
+
+ s.MakeLower_Ascii();
+ const wchar_t *start = s;
+ UInt32 v = numThreads;
+
+ /* we force up, if threads number specified
+ only `d` will force it down */
+ bool force_loc = true;
+ for (;;)
+ {
+ const wchar_t c = *start;
+ if (!c)
+ break;
+ if (c == 'd')
+ {
+ force_loc = false; // force down
+ start++;
+ continue;
+ }
+ if (c == 'u')
+ {
+ force_loc = true; // force up
+ start++;
+ continue;
+ }
+ bool isPercent = false;
+ if (c == 'p')
+ {
+ isPercent = true;
+ start++;
+ }
+ const wchar_t *end;
+ v = ConvertStringToUInt32(start, &end);
+ if (end == start)
+ return E_INVALIDARG;
+ if (isPercent)
+ v = numThreads * v / 100;
+ start = end;
+ }
+
+ numThreads = v;
+ force = force_loc;
+ return S_OK;
+}
+
+
+
+static HRESULT SetLogSizeProp(UInt64 number, NCOM::CPropVariant &destProp)
+{
+ if (number >= 64)
+ return E_INVALIDARG;
+ UInt32 val32;
+ if (number < 32)
+ val32 = (UInt32)1 << (unsigned)number;
+ /*
+ else if (number == 32 && reduce_4GB_to_32bits)
+ val32 = (UInt32)(Int32)-1;
+ */
+ else
+ {
+ destProp = (UInt64)((UInt64)1 << (unsigned)number);
+ return S_OK;
+ }
+ destProp = (UInt32)val32;
+ return S_OK;
+}
+
+
+static HRESULT StringToDictSize(const UString &s, NCOM::CPropVariant &destProp)
+{
+ /* if (reduce_4GB_to_32bits) we can reduce (4 GiB) property to (4 GiB - 1).
+ to fit the value to UInt32 for clients that do not support 64-bit values */
+
+ const wchar_t *end;
+ const UInt64 number = ConvertStringToUInt64(s, &end);
+ const unsigned numDigits = (unsigned)(end - s.Ptr());
+ if (numDigits == 0 || s.Len() > numDigits + 1)
+ return E_INVALIDARG;
+
+ if (s.Len() == numDigits)
+ return SetLogSizeProp(number, destProp);
+
+ unsigned numBits;
+
+ switch (MyCharLower_Ascii(s[numDigits]))
+ {
+ case 'b': numBits = 0; break;
+ case 'k': numBits = 10; break;
+ case 'm': numBits = 20; break;
+ case 'g': numBits = 30; break;
+ default: return E_INVALIDARG;
+ }
+
+ const UInt64 range4g = ((UInt64)1 << (32 - numBits));
+ if (number < range4g)
+ destProp = (UInt32)((UInt32)number << numBits);
+ /*
+ else if (number == range4g && reduce_4GB_to_32bits)
+ destProp = (UInt32)(Int32)-1;
+ */
+ else if (numBits == 0)
+ destProp = (UInt64)number;
+ else if (number >= ((UInt64)1 << (64 - numBits)))
+ return E_INVALIDARG;
+ else
+ destProp = (UInt64)((UInt64)number << numBits);
+ return S_OK;
+}
+
+
+static HRESULT PROPVARIANT_to_DictSize(const PROPVARIANT &prop, NCOM::CPropVariant &destProp)
+{
+ if (prop.vt == VT_UI4)
+ return SetLogSizeProp(prop.ulVal, destProp);
+
+ if (prop.vt == VT_BSTR)
+ {
+ UString s;
+ s = prop.bstrVal;
+ return StringToDictSize(s, destProp);
+ }
+ return E_INVALIDARG;
+}
+
+
+void CProps::AddProp32(PROPID propid, UInt32 val)
+{
+ CProp &prop = Props.AddNew();
+ prop.IsOptional = true;
+ prop.Id = propid;
+ prop.Value = (UInt32)val;
+}
+
+void CProps::AddPropBool(PROPID propid, bool val)
+{
+ CProp &prop = Props.AddNew();
+ prop.IsOptional = true;
+ prop.Id = propid;
+ prop.Value = val;
+}
+
+class CCoderProps
+{
+ PROPID *_propIDs;
+ NCOM::CPropVariant *_props;
+ unsigned _numProps;
+ unsigned _numPropsMax;
+public:
+ CCoderProps(unsigned numPropsMax):
+ _propIDs(NULL),
+ _props(NULL),
+ _numProps(0),
+ _numPropsMax(numPropsMax)
+ {
+ _propIDs = new PROPID[numPropsMax];
+ _props = new NCOM::CPropVariant[numPropsMax];
+ }
+ ~CCoderProps()
+ {
+ delete []_propIDs;
+ delete []_props;
+ }
+ void AddProp(const CProp &prop);
+ HRESULT SetProps(ICompressSetCoderProperties *setCoderProperties)
+ {
+ return setCoderProperties->SetCoderProperties(_propIDs, _props, _numProps);
+ }
+};
+
+void CCoderProps::AddProp(const CProp &prop)
+{
+ if (_numProps >= _numPropsMax)
+ throw 1;
+ _propIDs[_numProps] = prop.Id;
+ _props[_numProps] = prop.Value;
+ _numProps++;
+}
+
+HRESULT CProps::SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const
+{
+ return SetCoderProps_DSReduce_Aff(scp, dataSizeReduce, NULL);
+}
+
+HRESULT CProps::SetCoderProps_DSReduce_Aff(
+ ICompressSetCoderProperties *scp,
+ const UInt64 *dataSizeReduce,
+ const UInt64 *affinity) const
+{
+ CCoderProps coderProps(Props.Size() + (dataSizeReduce ? 1 : 0) + (affinity ? 1 : 0) );
+ FOR_VECTOR (i, Props)
+ coderProps.AddProp(Props[i]);
+ if (dataSizeReduce)
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kReduceSize;
+ prop.Value = *dataSizeReduce;
+ coderProps.AddProp(prop);
+ }
+ if (affinity)
+ {
+ CProp prop;
+ prop.Id = NCoderPropID::kAffinity;
+ prop.Value = *affinity;
+ coderProps.AddProp(prop);
+ }
+ return coderProps.SetProps(scp);
+}
+
+
+int CMethodProps::FindProp(PROPID id) const
+{
+ for (unsigned i = Props.Size(); i != 0;)
+ if (Props[--i].Id == id)
+ return (int)i;
+ return -1;
+}
+
+unsigned CMethodProps::GetLevel() const
+{
+ int i = FindProp(NCoderPropID::kLevel);
+ if (i < 0)
+ return 5;
+ if (Props[(unsigned)i].Value.vt != VT_UI4)
+ return 9;
+ UInt32 level = Props[(unsigned)i].Value.ulVal;
+ return level > 9 ? 9 : (unsigned)level;
+}
+
+struct CNameToPropID
+{
+ VARTYPE VarType;
+ const char *Name;
+};
+
+
+// the following are related to NCoderPropID::EEnum values
+// NCoderPropID::k_NUM_DEFINED
+static const CNameToPropID g_NameToPropID[] =
+{
+ { VT_UI4, "" },
+ { VT_UI4, "d" },
+ { VT_UI4, "mem" },
+ { VT_UI4, "o" },
+ { VT_UI8, "c" },
+ { VT_UI4, "pb" },
+ { VT_UI4, "lc" },
+ { VT_UI4, "lp" },
+ { VT_UI4, "fb" },
+ { VT_BSTR, "mf" },
+ { VT_UI4, "mc" },
+ { VT_UI4, "pass" },
+ { VT_UI4, "a" },
+ { VT_UI4, "mt" },
+ { VT_BOOL, "eos" },
+ { VT_UI4, "x" },
+ { VT_UI8, "reduce" },
+ { VT_UI8, "expect" },
+ { VT_UI8, "cc" }, // "cc" in v23, "b" in v22.01
+ { VT_UI4, "check" },
+ { VT_BSTR, "filter" },
+ { VT_UI8, "memuse" },
+ { VT_UI8, "aff" },
+ { VT_UI4, "offset" },
+ { VT_UI4, "zhb" }
+ /*
+ ,
+ // { VT_UI4, "zhc" },
+ // { VT_UI4, "zhd" },
+ // { VT_UI4, "zcb" },
+ { VT_UI4, "dc" },
+ { VT_UI4, "zx" },
+ { VT_UI4, "zf" },
+ { VT_UI4, "zmml" },
+ { VT_UI4, "zov" },
+ { VT_BOOL, "zmfr" },
+ { VT_BOOL, "zle" }, // long enable
+ // { VT_UI4, "zldb" },
+ { VT_UI4, "zld" },
+ { VT_UI4, "zlhb" },
+ { VT_UI4, "zlmml" },
+ { VT_UI4, "zlbb" },
+ { VT_UI4, "zlhrb" },
+ { VT_BOOL, "zwus" },
+ { VT_BOOL, "zshp" },
+ { VT_BOOL, "zshs" },
+ { VT_BOOL, "zshe" },
+ { VT_BOOL, "zshg" },
+ { VT_UI4, "zpsm" }
+ */
+ // { VT_UI4, "mcb" }, // mc log version
+ // { VT_UI4, "ztlen" }, // fb ?
+};
+
+/*
+#if defined(static_assert) || (defined(__cplusplus) && __cplusplus >= 200410L) || (defined(_MSC_VER) && _MSC_VER >= 1600)
+
+#if (defined(__cplusplus) && __cplusplus < 201103L) \
+ && defined(__clang__) && __clang_major__ >= 4
+#pragma GCC diagnostic ignored "-Wc11-extensions"
+#endif
+ static_assert(Z7_ARRAY_SIZE(g_NameToPropID) == NCoderPropID::k_NUM_DEFINED,
+ "g_NameToPropID doesn't match NCoderPropID enum");
+#endif
+*/
+
+static int FindPropIdExact(const UString &name)
+{
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_NameToPropID); i++)
+ if (StringsAreEqualNoCase_Ascii(name, g_NameToPropID[i].Name))
+ return (int)i;
+ return -1;
+}
+
+static bool ConvertProperty(const PROPVARIANT &srcProp, VARTYPE varType, NCOM::CPropVariant &destProp)
+{
+ if (varType == srcProp.vt)
+ {
+ destProp = srcProp;
+ return true;
+ }
+
+ if (varType == VT_UI8 && srcProp.vt == VT_UI4)
+ {
+ destProp = (UInt64)srcProp.ulVal;
+ return true;
+ }
+
+ if (varType == VT_BOOL)
+ {
+ bool res;
+ if (PROPVARIANT_to_bool(srcProp, res) != S_OK)
+ return false;
+ destProp = res;
+ return true;
+ }
+ if (srcProp.vt == VT_EMPTY)
+ {
+ destProp = srcProp;
+ return true;
+ }
+ return false;
+}
+
+static void SplitParams(const UString &srcString, UStringVector &subStrings)
+{
+ subStrings.Clear();
+ UString s;
+ unsigned len = srcString.Len();
+ if (len == 0)
+ return;
+ for (unsigned i = 0; i < len; i++)
+ {
+ wchar_t c = srcString[i];
+ if (c == L':')
+ {
+ subStrings.Add(s);
+ s.Empty();
+ }
+ else
+ s += c;
+ }
+ subStrings.Add(s);
+}
+
+static void SplitParam(const UString &param, UString &name, UString &value)
+{
+ int eqPos = param.Find(L'=');
+ if (eqPos >= 0)
+ {
+ name.SetFrom(param, (unsigned)eqPos);
+ value = param.Ptr((unsigned)(eqPos + 1));
+ return;
+ }
+ unsigned i;
+ for (i = 0; i < param.Len(); i++)
+ {
+ wchar_t c = param[i];
+ if (c >= L'0' && c <= L'9')
+ break;
+ }
+ name.SetFrom(param, i);
+ value = param.Ptr(i);
+}
+
+static bool IsLogSizeProp(PROPID propid)
+{
+ switch (propid)
+ {
+ case NCoderPropID::kDictionarySize:
+ case NCoderPropID::kUsedMemorySize:
+ case NCoderPropID::kBlockSize:
+ case NCoderPropID::kBlockSize2:
+ /*
+ case NCoderPropID::kChainSize:
+ case NCoderPropID::kLdmWindowSize:
+ */
+ // case NCoderPropID::kReduceSize:
+ return true;
+ }
+ return false;
+}
+
+HRESULT CMethodProps::SetParam(const UString &name, const UString &value)
+{
+ int index = FindPropIdExact(name);
+ if (index < 0)
+ {
+ // 'b' was used as NCoderPropID::kBlockSize2 before v23
+ if (!name.IsEqualTo_Ascii_NoCase("b") || value.Find(L':') >= 0)
+ return E_INVALIDARG;
+ index = NCoderPropID::kBlockSize2;
+ }
+ const CNameToPropID &nameToPropID = g_NameToPropID[(unsigned)index];
+ CProp prop;
+ prop.Id = (unsigned)index;
+
+ if (IsLogSizeProp(prop.Id))
+ {
+ RINOK(StringToDictSize(value, prop.Value))
+ }
+ else
+ {
+ NCOM::CPropVariant propValue;
+ if (nameToPropID.VarType == VT_BSTR)
+ propValue = value;
+ else if (nameToPropID.VarType == VT_BOOL)
+ {
+ bool res;
+ if (!StringToBool(value, res))
+ return E_INVALIDARG;
+ propValue = res;
+ }
+ else if (!value.IsEmpty())
+ {
+ if (nameToPropID.VarType == VT_UI4)
+ {
+ UInt32 number;
+ if (ParseStringToUInt32(value, number) == value.Len())
+ propValue = number;
+ else
+ propValue = value;
+ }
+ else if (nameToPropID.VarType == VT_UI8)
+ {
+ UInt64 number;
+ if (ParseStringToUInt64(value, number) == value.Len())
+ propValue = number;
+ else
+ propValue = value;
+ }
+ else
+ propValue = value;
+ }
+ if (!ConvertProperty(propValue, nameToPropID.VarType, prop.Value))
+ return E_INVALIDARG;
+ }
+ Props.Add(prop);
+ return S_OK;
+}
+
+HRESULT CMethodProps::ParseParamsFromString(const UString &srcString)
+{
+ UStringVector params;
+ SplitParams(srcString, params);
+ FOR_VECTOR (i, params)
+ {
+ const UString &param = params[i];
+ UString name, value;
+ SplitParam(param, name, value);
+ RINOK(SetParam(name, value))
+ }
+ return S_OK;
+}
+
+HRESULT CMethodProps::ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value)
+{
+ if (realName.Len() == 0)
+ {
+ // [empty]=method
+ return E_INVALIDARG;
+ }
+ if (value.vt == VT_EMPTY)
+ {
+ // {realName}=[empty]
+ UString name, valueStr;
+ SplitParam(realName, name, valueStr);
+ return SetParam(name, valueStr);
+ }
+
+ // {realName}=value
+ const int index = FindPropIdExact(realName);
+ if (index < 0)
+ return E_INVALIDARG;
+ const CNameToPropID &nameToPropID = g_NameToPropID[(unsigned)index];
+ CProp prop;
+ prop.Id = (unsigned)index;
+
+ if (IsLogSizeProp(prop.Id))
+ {
+ RINOK(PROPVARIANT_to_DictSize(value, prop.Value))
+ }
+ else
+ {
+ if (!ConvertProperty(value, nameToPropID.VarType, prop.Value))
+ return E_INVALIDARG;
+ }
+ Props.Add(prop);
+ return S_OK;
+}
+
+
+static UInt64 GetMemoryUsage_LZMA(UInt32 dict, bool isBt, UInt32 numThreads)
+{
+ UInt32 hs = dict - 1;
+ hs |= (hs >> 1);
+ hs |= (hs >> 2);
+ hs |= (hs >> 4);
+ hs |= (hs >> 8);
+ hs >>= 1;
+ if (hs >= (1 << 24))
+ hs >>= 1;
+ hs |= (1 << 16) - 1;
+ // if (numHashBytes >= 5)
+ if (!isBt)
+ hs |= (256 << 10) - 1;
+ hs++;
+ UInt64 size1 = (UInt64)hs * 4;
+ size1 += (UInt64)dict * 4;
+ if (isBt)
+ size1 += (UInt64)dict * 4;
+ size1 += (2 << 20);
+
+ if (numThreads > 1 && isBt)
+ size1 += (2 << 20) + (4 << 20);
+ return size1;
+}
+
+static const UInt32 kLzmaMaxDictSize = (UInt32)15 << 28;
+
+UInt64 CMethodProps::Get_Lzma_MemUsage(bool addSlidingWindowSize) const
+{
+ const UInt64 dicSize = Get_Lzma_DicSize();
+ const bool isBt = Get_Lzma_MatchFinder_IsBt();
+ const UInt32 dict32 = (dicSize >= kLzmaMaxDictSize ? kLzmaMaxDictSize : (UInt32)dicSize);
+ const UInt32 numThreads = Get_Lzma_NumThreads();
+ UInt64 size = GetMemoryUsage_LZMA(dict32, isBt, numThreads);
+
+ if (addSlidingWindowSize)
+ {
+ const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)(1 << 16);
+ UInt64 blockSize = (UInt64)dict32 + (1 << 16)
+ + (numThreads > 1 ? (1 << 20) : 0);
+ blockSize += (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2));
+ if (blockSize >= kBlockSizeMax)
+ blockSize = kBlockSizeMax;
+ size += blockSize;
+ }
+ return size;
+}
+
+
+
+
+HRESULT COneMethodInfo::ParseMethodFromString(const UString &s)
+{
+ MethodName.Empty();
+ int splitPos = s.Find(L':');
+ {
+ UString temp = s;
+ if (splitPos >= 0)
+ temp.DeleteFrom((unsigned)splitPos);
+ if (!temp.IsAscii())
+ return E_INVALIDARG;
+ MethodName.SetFromWStr_if_Ascii(temp);
+ }
+ if (splitPos < 0)
+ return S_OK;
+ PropsString = s.Ptr((unsigned)(splitPos + 1));
+ return ParseParamsFromString(PropsString);
+}
+
+HRESULT COneMethodInfo::ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value)
+{
+ if (!realName.IsEmpty() && !StringsAreEqualNoCase_Ascii(realName, "m"))
+ return ParseParamsFromPROPVARIANT(realName, value);
+ // -m{N}=method
+ if (value.vt != VT_BSTR)
+ return E_INVALIDARG;
+ UString s;
+ s = value.bstrVal;
+ return ParseMethodFromString(s);
+}
diff --git a/CPP/7zip/Common/MethodProps.h b/CPP/7zip/Common/MethodProps.h
index c8a3d0d..3c332d6 100644
--- a/CPP/7zip/Common/MethodProps.h
+++ b/CPP/7zip/Common/MethodProps.h
@@ -1,264 +1,345 @@
-// MethodProps.h
-
-#ifndef __7Z_METHOD_PROPS_H
-#define __7Z_METHOD_PROPS_H
-
-#include "../../Common/MyString.h"
-#include "../../Common/Defs.h"
-
-#include "../../Windows/Defs.h"
-
-#include "../../Windows/PropVariant.h"
-
-#include "../ICoder.h"
-
-bool StringToBool(const wchar_t *s, bool &res);
-HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest);
-unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number);
-HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue);
-
-HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 defaultNumThreads, UInt32 &numThreads);
-
-struct CProp
-{
- PROPID Id;
- bool IsOptional;
- NWindows::NCOM::CPropVariant Value;
- CProp(): IsOptional(false) {}
-};
-
-struct CProps
-{
- CObjectVector<CProp> Props;
-
- void Clear() { Props.Clear(); }
-
- bool AreThereNonOptionalProps() const
- {
- FOR_VECTOR (i, Props)
- if (!Props[i].IsOptional)
- return true;
- return false;
- }
-
- void AddProp32(PROPID propid, UInt32 val);
-
- void AddPropBool(PROPID propid, bool val);
-
- void AddProp_Ascii(PROPID propid, const char *s)
- {
- CProp &prop = Props.AddNew();
- prop.IsOptional = true;
- prop.Id = propid;
- prop.Value = s;
- }
-
- HRESULT SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce) const;
-};
-
-class CMethodProps: public CProps
-{
- HRESULT SetParam(const UString &name, const UString &value);
-public:
- int GetLevel() const;
- int Get_NumThreads() const
- {
- int i = FindProp(NCoderPropID::kNumThreads);
- if (i >= 0)
- if (Props[i].Value.vt == VT_UI4)
- return (int)Props[i].Value.ulVal;
- return -1;
- }
-
- bool Get_DicSize(UInt32 &res) const
- {
- res = 0;
- int i = FindProp(NCoderPropID::kDictionarySize);
- if (i >= 0)
- if (Props[i].Value.vt == VT_UI4)
- {
- res = Props[i].Value.ulVal;
- return true;
- }
- return false;
- }
-
- int FindProp(PROPID id) const;
-
- UInt32 Get_Lzma_Algo() const
- {
- int i = FindProp(NCoderPropID::kAlgorithm);
- if (i >= 0)
- if (Props[i].Value.vt == VT_UI4)
- return Props[i].Value.ulVal;
- return GetLevel() >= 5 ? 1 : 0;
- }
-
- UInt32 Get_Lzma_DicSize() const
- {
- int i = FindProp(NCoderPropID::kDictionarySize);
- if (i >= 0)
- if (Props[i].Value.vt == VT_UI4)
- return Props[i].Value.ulVal;
- int level = GetLevel();
- return level <= 5 ? (1 << (level * 2 + 14)) : (level == 6 ? (1 << 25) : (1 << 26));
- }
-
- bool Get_Lzma_Eos() const
- {
- int i = FindProp(NCoderPropID::kEndMarker);
- if (i >= 0)
- {
- const NWindows::NCOM::CPropVariant &val = Props[i].Value;
- if (val.vt == VT_BOOL)
- return VARIANT_BOOLToBool(val.boolVal);
- }
- return false;
- }
-
- bool Are_Lzma_Model_Props_Defined() const
- {
- if (FindProp(NCoderPropID::kPosStateBits) >= 0) return true;
- if (FindProp(NCoderPropID::kLitContextBits) >= 0) return true;
- if (FindProp(NCoderPropID::kLitPosBits) >= 0) return true;
- return false;
- }
-
- UInt32 Get_Lzma_NumThreads() const
- {
- if (Get_Lzma_Algo() == 0)
- return 1;
- int numThreads = Get_NumThreads();
- if (numThreads >= 0)
- return numThreads < 2 ? 1 : 2;
- return 2;
- }
-
- int Get_Xz_NumThreads(UInt32 &lzmaThreads) const
- {
- lzmaThreads = 1;
- int numThreads = Get_NumThreads();
- if (numThreads >= 0 && numThreads <= 1)
- return 1;
- if (Get_Lzma_Algo() != 0)
- lzmaThreads = 2;
- return numThreads;
- }
-
- UInt64 GetProp_BlockSize(PROPID id) const
- {
- int i = FindProp(id);
- if (i >= 0)
- {
- const NWindows::NCOM::CPropVariant &val = Props[i].Value;
- if (val.vt == VT_UI4) { return val.ulVal; }
- if (val.vt == VT_UI8) { return val.uhVal.QuadPart; }
- }
- return 0;
- }
-
- UInt64 Get_Xz_BlockSize() const
- {
- {
- UInt64 blockSize1 = GetProp_BlockSize(NCoderPropID::kBlockSize);
- UInt64 blockSize2 = GetProp_BlockSize(NCoderPropID::kBlockSize2);
- UInt64 minSize = MyMin(blockSize1, blockSize2);
- if (minSize != 0)
- return minSize;
- UInt64 maxSize = MyMax(blockSize1, blockSize2);
- if (maxSize != 0)
- return maxSize;
- }
- const UInt32 kMinSize = (UInt32)1 << 20;
- const UInt32 kMaxSize = (UInt32)1 << 28;
- UInt32 dictSize = Get_Lzma_DicSize();
- UInt64 blockSize = (UInt64)dictSize << 2;
- if (blockSize < kMinSize) blockSize = kMinSize;
- if (blockSize > kMaxSize) blockSize = kMaxSize;
- if (blockSize < dictSize) blockSize = dictSize;
- blockSize += (kMinSize - 1);
- blockSize &= ~(UInt64)(kMinSize - 1);
- return blockSize;
- }
-
-
- UInt32 Get_BZip2_NumThreads(bool &fixedNumber) const
- {
- fixedNumber = false;
- int numThreads = Get_NumThreads();
- if (numThreads >= 0)
- {
- fixedNumber = true;
- if (numThreads < 1) return 1;
- const unsigned kNumBZip2ThreadsMax = 64;
- if (numThreads > kNumBZip2ThreadsMax) return kNumBZip2ThreadsMax;
- return numThreads;
- }
- return 1;
- }
-
- UInt32 Get_BZip2_BlockSize() const
- {
- int i = FindProp(NCoderPropID::kDictionarySize);
- if (i >= 0)
- if (Props[i].Value.vt == VT_UI4)
- {
- UInt32 blockSize = Props[i].Value.ulVal;
- const UInt32 kDicSizeMin = 100000;
- const UInt32 kDicSizeMax = 900000;
- if (blockSize < kDicSizeMin) blockSize = kDicSizeMin;
- if (blockSize > kDicSizeMax) blockSize = kDicSizeMax;
- return blockSize;
- }
- int level = GetLevel();
- return 100000 * (level >= 5 ? 9 : (level >= 1 ? level * 2 - 1: 1));
- }
-
- UInt32 Get_Ppmd_MemSize() const
- {
- int i = FindProp(NCoderPropID::kUsedMemorySize);
- if (i >= 0)
- if (Props[i].Value.vt == VT_UI4)
- return Props[i].Value.ulVal;
- int level = GetLevel();
- return level >= 9 ? (192 << 20) : ((UInt32)1 << (level + 19));
- }
-
- void AddProp_Level(UInt32 level)
- {
- AddProp32(NCoderPropID::kLevel, level);
- }
-
- void AddProp_NumThreads(UInt32 numThreads)
- {
- AddProp32(NCoderPropID::kNumThreads, numThreads);
- }
-
- void AddProp_EndMarker_if_NotFound(bool eos)
- {
- if (FindProp(NCoderPropID::kEndMarker) < 0)
- AddPropBool(NCoderPropID::kEndMarker, eos);
- }
-
- HRESULT ParseParamsFromString(const UString &srcString);
- HRESULT ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value);
-};
-
-class COneMethodInfo: public CMethodProps
-{
-public:
- AString MethodName;
- UString PropsString;
-
- void Clear()
- {
- CMethodProps::Clear();
- MethodName.Empty();
- PropsString.Empty();
- }
- bool IsEmpty() const { return MethodName.IsEmpty() && Props.IsEmpty(); }
- HRESULT ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value);
- HRESULT ParseMethodFromString(const UString &s);
-};
-
-#endif
+// MethodProps.h
+
+#ifndef ZIP7_INC_7Z_METHOD_PROPS_H
+#define ZIP7_INC_7Z_METHOD_PROPS_H
+
+#include "../../Common/MyString.h"
+#include "../../Common/Defs.h"
+
+#include "../../Windows/Defs.h"
+
+#include "../../Windows/PropVariant.h"
+
+#include "../ICoder.h"
+
+// UInt64 GetMemoryUsage_LZMA(UInt32 dict, bool isBt, UInt32 numThreads);
+
+inline UInt64 Calc_From_Val_Percents_Less100(UInt64 val, UInt64 percents)
+{
+ if (percents == 0)
+ return 0;
+ if (val <= (UInt64)(Int64)-1 / percents)
+ return val * percents / 100;
+ return val / 100 * percents;
+}
+
+UInt64 Calc_From_Val_Percents(UInt64 val, UInt64 percents);
+
+bool StringToBool(const wchar_t *s, bool &res);
+HRESULT PROPVARIANT_to_bool(const PROPVARIANT &prop, bool &dest);
+unsigned ParseStringToUInt32(const UString &srcString, UInt32 &number);
+
+/*
+if (name.IsEmpty() && prop.vt == VT_EMPTY), it doesn't change (resValue) and returns S_OK.
+ So you must set (resValue) for default value before calling */
+HRESULT ParsePropToUInt32(const UString &name, const PROPVARIANT &prop, UInt32 &resValue);
+
+/* input: (numThreads = the_number_of_processors) */
+HRESULT ParseMtProp2(const UString &name, const PROPVARIANT &prop, UInt32 &numThreads, bool &force);
+
+inline HRESULT ParseMtProp(const UString &name, const PROPVARIANT &prop, UInt32 numCPUs, UInt32 &numThreads)
+{
+ bool forced = false;
+ numThreads = numCPUs;
+ return ParseMtProp2(name, prop, numThreads, forced);
+}
+
+
+struct CProp
+{
+ PROPID Id;
+ bool IsOptional;
+ NWindows::NCOM::CPropVariant Value;
+ CProp(): IsOptional(false) {}
+};
+
+struct CProps
+{
+ CObjectVector<CProp> Props;
+
+ void Clear() { Props.Clear(); }
+
+ bool AreThereNonOptionalProps() const
+ {
+ FOR_VECTOR (i, Props)
+ if (!Props[i].IsOptional)
+ return true;
+ return false;
+ }
+
+ void AddProp32(PROPID propid, UInt32 val);
+
+ void AddPropBool(PROPID propid, bool val);
+
+ void AddProp_Ascii(PROPID propid, const char *s)
+ {
+ CProp &prop = Props.AddNew();
+ prop.IsOptional = true;
+ prop.Id = propid;
+ prop.Value = s;
+ }
+
+ HRESULT SetCoderProps(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce = NULL) const;
+ HRESULT SetCoderProps_DSReduce_Aff(ICompressSetCoderProperties *scp, const UInt64 *dataSizeReduce, const UInt64 *affinity) const;
+};
+
+class CMethodProps: public CProps
+{
+ HRESULT SetParam(const UString &name, const UString &value);
+public:
+ unsigned GetLevel() const;
+ int Get_NumThreads() const
+ {
+ const int i = FindProp(NCoderPropID::kNumThreads);
+ if (i >= 0)
+ {
+ const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value;
+ if (val.vt == VT_UI4)
+ return (int)val.ulVal;
+ }
+ return -1;
+ }
+
+ bool Get_DicSize(UInt64 &res) const
+ {
+ res = 0;
+ const int i = FindProp(NCoderPropID::kDictionarySize);
+ if (i >= 0)
+ {
+ const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value;
+ if (val.vt == VT_UI4)
+ {
+ res = val.ulVal;
+ return true;
+ }
+ if (val.vt == VT_UI8)
+ {
+ res = val.uhVal.QuadPart;
+ return true;
+ }
+ }
+ return false;
+ }
+
+ int FindProp(PROPID id) const;
+
+ UInt32 Get_Lzma_Algo() const
+ {
+ int i = FindProp(NCoderPropID::kAlgorithm);
+ if (i >= 0)
+ {
+ const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value;
+ if (val.vt == VT_UI4)
+ return val.ulVal;
+ }
+ return GetLevel() >= 5 ? 1 : 0;
+ }
+
+ UInt64 Get_Lzma_DicSize() const
+ {
+ UInt64 v;
+ if (Get_DicSize(v))
+ return v;
+ const unsigned level = GetLevel();
+ const UInt32 dictSize =
+ ( level <= 3 ? ((UInt32)1 << (level * 2 + 16)) :
+ ( level <= 6 ? ((UInt32)1 << (level + 19)) :
+ ( level <= 7 ? ((UInt32)1 << 25) : ((UInt32)1 << 26)
+ )));
+ return dictSize;
+ }
+
+ bool Get_Lzma_MatchFinder_IsBt() const
+ {
+ const int i = FindProp(NCoderPropID::kMatchFinder);
+ if (i >= 0)
+ {
+ const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value;
+ if (val.vt == VT_BSTR)
+ return ((val.bstrVal[0] | 0x20) != 'h'); // check for "hc"
+ }
+ return GetLevel() >= 5;
+ }
+
+ bool Get_Lzma_Eos() const
+ {
+ const int i = FindProp(NCoderPropID::kEndMarker);
+ if (i >= 0)
+ {
+ const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value;
+ if (val.vt == VT_BOOL)
+ return VARIANT_BOOLToBool(val.boolVal);
+ }
+ return false;
+ }
+
+ bool Are_Lzma_Model_Props_Defined() const
+ {
+ if (FindProp(NCoderPropID::kPosStateBits) >= 0) return true;
+ if (FindProp(NCoderPropID::kLitContextBits) >= 0) return true;
+ if (FindProp(NCoderPropID::kLitPosBits) >= 0) return true;
+ return false;
+ }
+
+ UInt32 Get_Lzma_NumThreads() const
+ {
+ if (Get_Lzma_Algo() == 0)
+ return 1;
+ int numThreads = Get_NumThreads();
+ if (numThreads >= 0)
+ return numThreads < 2 ? 1 : 2;
+ return 2;
+ }
+
+ UInt64 Get_Lzma_MemUsage(bool addSlidingWindowSize) const;
+
+ /* returns -1, if numThreads is unknown */
+ int Get_Xz_NumThreads(UInt32 &lzmaThreads) const
+ {
+ lzmaThreads = 1;
+ int numThreads = Get_NumThreads();
+ if (numThreads >= 0 && numThreads <= 1)
+ return 1;
+ if (Get_Lzma_Algo() != 0)
+ lzmaThreads = 2;
+ return numThreads;
+ }
+
+ UInt64 GetProp_BlockSize(PROPID id) const
+ {
+ const int i = FindProp(id);
+ if (i >= 0)
+ {
+ const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value;
+ if (val.vt == VT_UI4) { return val.ulVal; }
+ if (val.vt == VT_UI8) { return val.uhVal.QuadPart; }
+ }
+ return 0;
+ }
+
+ UInt64 Get_Xz_BlockSize() const
+ {
+ {
+ UInt64 blockSize1 = GetProp_BlockSize(NCoderPropID::kBlockSize);
+ UInt64 blockSize2 = GetProp_BlockSize(NCoderPropID::kBlockSize2);
+ UInt64 minSize = MyMin(blockSize1, blockSize2);
+ if (minSize != 0)
+ return minSize;
+ UInt64 maxSize = MyMax(blockSize1, blockSize2);
+ if (maxSize != 0)
+ return maxSize;
+ }
+ const UInt32 kMinSize = (UInt32)1 << 20;
+ const UInt32 kMaxSize = (UInt32)1 << 28;
+ const UInt64 dictSize = Get_Lzma_DicSize();
+ /* lzma2 code uses fake 4 GiB to calculate ChunkSize. So we do same */
+ UInt64 blockSize = (UInt64)dictSize << 2;
+ if (blockSize < kMinSize) blockSize = kMinSize;
+ if (blockSize > kMaxSize) blockSize = kMaxSize;
+ if (blockSize < dictSize) blockSize = dictSize;
+ blockSize += (kMinSize - 1);
+ blockSize &= ~(UInt64)(kMinSize - 1);
+ return blockSize;
+ }
+
+
+ UInt32 Get_BZip2_NumThreads(bool &fixedNumber) const
+ {
+ fixedNumber = false;
+ int numThreads = Get_NumThreads();
+ if (numThreads >= 0)
+ {
+ fixedNumber = true;
+ if (numThreads < 1) return 1;
+ const unsigned kNumBZip2ThreadsMax = 64;
+ if ((unsigned)numThreads > kNumBZip2ThreadsMax) return kNumBZip2ThreadsMax;
+ return (unsigned)numThreads;
+ }
+ return 1;
+ }
+
+ UInt32 Get_BZip2_BlockSize() const
+ {
+ const int i = FindProp(NCoderPropID::kDictionarySize);
+ if (i >= 0)
+ {
+ const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value;
+ if (val.vt == VT_UI4)
+ {
+ UInt32 blockSize = val.ulVal;
+ const UInt32 kDicSizeMin = 100000;
+ const UInt32 kDicSizeMax = 900000;
+ if (blockSize < kDicSizeMin) blockSize = kDicSizeMin;
+ if (blockSize > kDicSizeMax) blockSize = kDicSizeMax;
+ return blockSize;
+ }
+ }
+ const unsigned level = GetLevel();
+ return 100000 * (level >= 5 ? 9 : (level >= 1 ? level * 2 - 1: 1));
+ }
+
+ UInt64 Get_Ppmd_MemSize() const
+ {
+ const int i = FindProp(NCoderPropID::kUsedMemorySize);
+ if (i >= 0)
+ {
+ const NWindows::NCOM::CPropVariant &val = Props[(unsigned)i].Value;
+ if (val.vt == VT_UI4)
+ return val.ulVal;
+ if (val.vt == VT_UI8)
+ return val.uhVal.QuadPart;
+ }
+ const unsigned level = GetLevel();
+ const UInt32 mem = (UInt32)1 << (level + 19);
+ return mem;
+ }
+
+ void AddProp_Level(UInt32 level)
+ {
+ AddProp32(NCoderPropID::kLevel, level);
+ }
+
+ void AddProp_NumThreads(UInt32 numThreads)
+ {
+ AddProp32(NCoderPropID::kNumThreads, numThreads);
+ }
+
+ void AddProp_EndMarker_if_NotFound(bool eos)
+ {
+ if (FindProp(NCoderPropID::kEndMarker) < 0)
+ AddPropBool(NCoderPropID::kEndMarker, eos);
+ }
+
+ void AddProp_BlockSize2(UInt64 blockSize2)
+ {
+ if (FindProp(NCoderPropID::kBlockSize2) < 0)
+ {
+ CProp &prop = Props.AddNew();
+ prop.IsOptional = true;
+ prop.Id = NCoderPropID::kBlockSize2;
+ prop.Value = blockSize2;
+ }
+ }
+
+ HRESULT ParseParamsFromString(const UString &srcString);
+ HRESULT ParseParamsFromPROPVARIANT(const UString &realName, const PROPVARIANT &value);
+};
+
+class COneMethodInfo: public CMethodProps
+{
+public:
+ AString MethodName;
+ UString PropsString;
+
+ void Clear()
+ {
+ CMethodProps::Clear();
+ MethodName.Empty();
+ PropsString.Empty();
+ }
+ bool IsEmpty() const { return MethodName.IsEmpty() && Props.IsEmpty(); }
+ HRESULT ParseMethodFromPROPVARIANT(const UString &realName, const PROPVARIANT &value);
+ HRESULT ParseMethodFromString(const UString &s);
+};
+
+#endif
diff --git a/CPP/7zip/Common/MultiOutStream.cpp b/CPP/7zip/Common/MultiOutStream.cpp
new file mode 100644
index 0000000..8efb977
--- /dev/null
+++ b/CPP/7zip/Common/MultiOutStream.cpp
@@ -0,0 +1,849 @@
+// MultiOutStream.cpp
+
+#include "StdAfx.h"
+
+// #define DEBUG_VOLUMES
+
+#ifdef DEBUG_VOLUMES
+#include <stdio.h>
+ #define PRF(x) x;
+#else
+ #define PRF(x)
+#endif
+
+#include "../../Common/ComTry.h"
+
+#include "../../Windows/FileDir.h"
+#include "../../Windows/FileFind.h"
+#include "../../Windows/System.h"
+
+#include "MultiOutStream.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+static const unsigned k_NumVols_MAX = k_VectorSizeMax - 1;
+ // 2; // for debug
+
+/*
+#define UPDATE_HRES(hres, x) \
+ { const HRESULT res2 = (x); if (hres == SZ_OK) hres = res2; }
+*/
+
+HRESULT CMultiOutStream::Destruct()
+{
+ COM_TRY_BEGIN
+ HRESULT hres = S_OK;
+ HRESULT hres3 = S_OK;
+
+ while (!Streams.IsEmpty())
+ {
+ try
+ {
+ HRESULT hres2;
+ if (NeedDelete)
+ {
+ /* we could call OptReOpen_and_SetSize() to test that we try to delete correct file,
+ but we cannot guarantee that (RealSize) will be correct after Write() or another failures.
+ And we still want to delete files even for such cases.
+ So we don't check for OptReOpen_and_SetSize() here: */
+ // if (OptReOpen_and_SetSize(Streams.Size() - 1, 0) == S_OK)
+ hres2 = CloseStream_and_DeleteFile(Streams.Size() - 1);
+ }
+ else
+ {
+ hres2 = CloseStream(Streams.Size() - 1);
+ }
+ if (hres == S_OK)
+ hres = hres2;
+ }
+ catch(...)
+ {
+ hres3 = E_OUTOFMEMORY;
+ }
+
+ {
+ /* Stream was released in CloseStream_*() above already, and it was removed from linked list
+ it's some unexpected case, if Stream is still attached here.
+ So the following code is optional: */
+ CVolStream &s = Streams.Back();
+ if (s.Stream)
+ {
+ if (hres3 == S_OK)
+ hres3 = E_FAIL;
+ s.Stream.Detach();
+ /* it will be not failure, even if we call RemoveFromLinkedList()
+ twice for same CVolStream in this Destruct() function */
+ RemoveFromLinkedList(Streams.Size() - 1);
+ }
+ }
+ Streams.DeleteBack();
+ // Delete_LastStream_Records();
+ }
+
+ if (hres == S_OK)
+ hres = hres3;
+ if (hres == S_OK && NumListItems != 0)
+ hres = E_FAIL;
+ return hres;
+ COM_TRY_END
+}
+
+
+CMultiOutStream::~CMultiOutStream()
+{
+ // we try to avoid exception in destructors
+ Destruct();
+}
+
+
+void CMultiOutStream::Init(const CRecordVector<UInt64> &sizes)
+{
+ Streams.Clear();
+ InitLinkedList();
+ Sizes = sizes;
+ NeedDelete = true;
+ MTime_Defined = false;
+ FinalVol_WasReopen = false;
+ NumOpenFiles_AllowedMax = NSystem::Get_File_OPEN_MAX_Reduced_for_3_tasks();
+
+ _streamIndex = 0;
+ _offsetPos = 0;
+ _absPos = 0;
+ _length = 0;
+ _absLimit = (UInt64)(Int64)-1;
+
+ _restrict_Begin = 0;
+ _restrict_End = (UInt64)(Int64)-1;
+ _restrict_Global = 0;
+
+ UInt64 sum = 0;
+ unsigned i = 0;
+ for (i = 0; i < Sizes.Size(); i++)
+ {
+ if (i >= k_NumVols_MAX)
+ {
+ _absLimit = sum;
+ break;
+ }
+ const UInt64 size = Sizes[i];
+ const UInt64 next = sum + size;
+ if (next < sum)
+ break;
+ sum = next;
+ }
+
+ // if (Sizes.IsEmpty()) throw "no volume sizes";
+ const UInt64 size = Sizes.Back();
+ if (size == 0)
+ throw "zero size last volume";
+
+ if (i == Sizes.Size())
+ if ((_absLimit - sum) / size >= (k_NumVols_MAX - i))
+ _absLimit = sum + (k_NumVols_MAX - i) * size;
+}
+
+
+/* IsRestricted():
+ we must call only if volume is full (s.RealSize==VolSize) or finished.
+ the function doesn't use VolSize and it uses s.RealSize instead.
+ it returns true : if stream is restricted, and we can't close that stream
+ it returns false : if there is no restriction, and we can close that stream
+ Note: (RealSize == 0) (empty volume) on restriction bounds are supposed as non-restricted
+*/
+bool CMultiOutStream::IsRestricted(const CVolStream &s) const
+{
+ if (s.Start < _restrict_Global)
+ return true;
+ if (_restrict_Begin == _restrict_End)
+ return false;
+ if (_restrict_Begin <= s.Start)
+ return _restrict_End > s.Start;
+ return _restrict_Begin < s.Start + s.RealSize;
+}
+
+/*
+// this function check also _length and volSize
+bool CMultiOutStream::IsRestricted_for_Close(unsigned index) const
+{
+ const CVolStream &s = Streams[index];
+ if (_length <= s.Start) // we don't close streams after the end, because we still can write them later
+ return true;
+ // (_length > s.Start)
+ const UInt64 volSize = GetVolSize_for_Stream(index);
+ if (volSize == 0)
+ return IsRestricted_Empty(s);
+ if (_length - s.Start < volSize)
+ return true;
+ return IsRestricted(s);
+}
+*/
+
+FString CMultiOutStream::GetFilePath(unsigned index)
+{
+ FString name;
+ name.Add_UInt32(index + 1);
+ while (name.Len() < 3)
+ name.InsertAtFront(FTEXT('0'));
+ name.Insert(0, Prefix);
+ return name;
+}
+
+
+// we close stream, but we still keep item in Streams[] vector
+HRESULT CMultiOutStream::CloseStream(unsigned index)
+{
+ CVolStream &s = Streams[index];
+ if (s.Stream)
+ {
+ RINOK(s.StreamSpec->Close())
+ // the following two commands must be called together:
+ s.Stream.Release();
+ RemoveFromLinkedList(index);
+ }
+ return S_OK;
+}
+
+
+// we close stream and delete file, but we still keep item in Streams[] vector
+HRESULT CMultiOutStream::CloseStream_and_DeleteFile(unsigned index)
+{
+ PRF(printf("\n====== %u, CloseStream_AndDelete \n", index));
+ RINOK(CloseStream(index))
+ FString path = GetFilePath(index);
+ path += Streams[index].Postfix;
+ // we can checki that file exist
+ // if (NFind::DoesFileExist_Raw(path))
+ if (!DeleteFileAlways(path))
+ return GetLastError_noZero_HRESULT();
+ return S_OK;
+}
+
+
+HRESULT CMultiOutStream::CloseStream_and_FinalRename(unsigned index)
+{
+ PRF(printf("\n====== %u, CloseStream_and_FinalRename \n", index));
+ CVolStream &s = Streams[index];
+ // HRESULT res = S_OK;
+ bool mtime_WasSet = false;
+ if (MTime_Defined && s.Stream)
+ {
+ if (s.StreamSpec->SetMTime(&MTime))
+ mtime_WasSet = true;
+ // else res = GetLastError_noZero_HRESULT();
+ }
+
+ RINOK(CloseStream(index))
+ if (s.Postfix.IsEmpty()) // if Postfix is empty, the path is already final
+ return S_OK;
+ const FString path = GetFilePath(index);
+ FString tempPath = path;
+ tempPath += s.Postfix;
+
+ if (MTime_Defined && !mtime_WasSet)
+ {
+ if (!SetDirTime(tempPath, NULL, NULL, &MTime))
+ {
+ // res = GetLastError_noZero_HRESULT();
+ }
+ }
+ if (!MyMoveFile(tempPath, path))
+ return GetLastError_noZero_HRESULT();
+ /* we clear CVolStream::Postfix. So we will not use Temp path
+ anymore for this stream, and we will work only with final path */
+ s.Postfix.Empty();
+ // we can ignore set_mtime error or we can return it
+ return S_OK;
+ // return res;
+}
+
+
+HRESULT CMultiOutStream::PrepareToOpenNew()
+{
+ if (NumListItems < NumOpenFiles_AllowedMax)
+ return S_OK;
+ /* when we create zip archive: in most cases we need only starting
+ data of restricted region for rewriting zip's local header.
+ So here we close latest created volume (from Head), and we try to
+ keep oldest volumes that will be used for header rewriting later. */
+ const int index = Head;
+ if (index == -1)
+ return E_FAIL;
+ PRF(printf("\n== %u, PrepareToOpenNew::CloseStream, NumListItems =%u \n", index, NumListItems));
+ /* we don't expect non-restricted stream here in normal cases (if _restrict_Global was not changed).
+ if there was non-restricted stream, it should be closed before */
+ // if (!IsRestricted_for_Close(index)) return CloseStream_and_FinalRename(index);
+ return CloseStream((unsigned)index);
+}
+
+
+HRESULT CMultiOutStream::CreateNewStream(UInt64 newSize)
+{
+ PRF(printf("\n== %u, CreateNewStream, size =%u \n", Streams.Size(), (unsigned)newSize));
+
+ if (Streams.Size() >= k_NumVols_MAX)
+ return E_INVALIDARG; // E_OUTOFMEMORY
+
+ RINOK(PrepareToOpenNew())
+ CVolStream s;
+ s.StreamSpec = new COutFileStream;
+ s.Stream = s.StreamSpec;
+ const FString path = GetFilePath(Streams.Size());
+
+ if (NFind::DoesFileExist_Raw(path))
+ return HRESULT_FROM_WIN32(ERROR_ALREADY_EXISTS);
+ if (!CreateTempFile2(path, false, s.Postfix, &s.StreamSpec->File))
+ return GetLastError_noZero_HRESULT();
+
+ s.Start = GetGlobalOffset_for_NewStream();
+ s.Pos = 0;
+ s.RealSize = 0;
+
+ const unsigned index = Streams.Add(s);
+ InsertToLinkedList(index);
+
+ if (newSize != 0)
+ return s.SetSize2(newSize);
+ return S_OK;
+}
+
+
+HRESULT CMultiOutStream::CreateStreams_If_Required(unsigned streamIndex)
+{
+ // UInt64 lastStreamSize = 0;
+ for (;;)
+ {
+ const unsigned numStreamsBefore = Streams.Size();
+ if (streamIndex < numStreamsBefore)
+ return S_OK;
+ UInt64 newSize;
+ if (streamIndex == numStreamsBefore)
+ {
+ // it's final volume that will be used for real writing.
+ /* SetSize(_offsetPos) is not required,
+ because the file Size will be set later by calling Seek() with Write() */
+ newSize = 0; // lastStreamSize;
+ }
+ else
+ {
+ // it's intermediate volume. So we need full volume size
+ newSize = GetVolSize_for_Stream(numStreamsBefore);
+ }
+
+ RINOK(CreateNewStream(newSize))
+
+ // optional check
+ if (numStreamsBefore + 1 != Streams.Size()) return E_FAIL;
+
+ if (streamIndex != numStreamsBefore)
+ {
+ // it's intermediate volume. So we can close it, if it's non-restricted
+ bool isRestricted;
+ {
+ const CVolStream &s = Streams[numStreamsBefore];
+ if (newSize == 0)
+ isRestricted = IsRestricted_Empty(s);
+ else
+ isRestricted = IsRestricted(s);
+ }
+ if (!isRestricted)
+ {
+ RINOK(CloseStream_and_FinalRename(numStreamsBefore))
+ }
+ }
+ }
+}
+
+
+HRESULT CMultiOutStream::ReOpenStream(unsigned streamIndex)
+{
+ PRF(printf("\n====== %u, ReOpenStream \n", streamIndex));
+ RINOK(PrepareToOpenNew())
+ CVolStream &s = Streams[streamIndex];
+
+ FString path = GetFilePath(streamIndex);
+ path += s.Postfix;
+
+ s.StreamSpec = new COutFileStream;
+ s.Stream = s.StreamSpec;
+ s.Pos = 0;
+
+ HRESULT hres;
+ if (s.StreamSpec->Open(path, OPEN_EXISTING))
+ {
+ if (s.Postfix.IsEmpty())
+ {
+ /* it's unexpected case that we open finished volume.
+ It can mean that the code for restriction is incorrect */
+ FinalVol_WasReopen = true;
+ }
+ UInt64 realSize = 0;
+ hres = s.StreamSpec->GetSize(&realSize);
+ if (hres == S_OK)
+ {
+ if (realSize == s.RealSize)
+ {
+ InsertToLinkedList(streamIndex);
+ return S_OK;
+ }
+ // file size was changed between Close() and ReOpen()
+ // we must release Stream to be consistent with linked list
+ hres = E_FAIL;
+ }
+ }
+ else
+ hres = GetLastError_noZero_HRESULT();
+ s.Stream.Release();
+ s.StreamSpec = NULL;
+ return hres;
+}
+
+
+/* Sets size of stream, if new size is not equal to old size (RealSize).
+ If stream was closed and size change is required, it reopens the stream. */
+
+HRESULT CMultiOutStream::OptReOpen_and_SetSize(unsigned index, UInt64 size)
+{
+ CVolStream &s = Streams[index];
+ if (size == s.RealSize)
+ return S_OK;
+ if (!s.Stream)
+ {
+ RINOK(ReOpenStream(index))
+ }
+ PRF(printf("\n== %u, OptReOpen_and_SetSize, size =%u RealSize = %u\n", index, (unsigned)size, (unsigned)s.RealSize));
+ // comment it to debug tail after data
+ return s.SetSize2(size);
+}
+
+
+/*
+call Normalize_finalMode(false), if _length was changed.
+ for all streams starting after _length:
+ - it sets zero size
+ - it still keeps file open
+ Note: after _length reducing with CMultiOutStream::SetSize() we can
+ have very big number of empty streams at the end of Streams[] list.
+ And Normalize_finalMode() will runs all these empty streams of Streams[] vector.
+ So it can be ineffective, if we call Normalize_finalMode() many
+ times after big reducing of (_length).
+
+call Normalize_finalMode(true) to set final presentations of all streams
+ for all streams starting after _length:
+ - it sets zero size
+ - it removes file
+ - it removes CVolStream object from Streams[] vector
+
+Note: we don't remove zero sized first volume, if (_length == 0)
+*/
+
+HRESULT CMultiOutStream::Normalize_finalMode(bool finalMode)
+{
+ PRF(printf("\n== Normalize_finalMode: _length =%d \n", (unsigned)_length));
+
+ unsigned i = Streams.Size();
+
+ UInt64 offset = 0;
+
+ /* At first we normalize (reduce or increase) the sizes of all existing
+ streams in Streams[] that can be affected by changed _length.
+ And we remove tailing zero-size streams, if (finalMode == true) */
+ while (i != 0)
+ {
+ offset = Streams[--i].Start; // it's last item in Streams[]
+ // we don't want to remove first volume
+ if (offset < _length || i == 0)
+ {
+ const UInt64 volSize = GetVolSize_for_Stream(i);
+ UInt64 size = _length - offset; // (size != 0) here
+ if (size > volSize)
+ size = volSize;
+ RINOK(OptReOpen_and_SetSize(i, size))
+ if (_length - offset <= volSize)
+ return S_OK;
+ // _length - offset > volSize
+ offset += volSize;
+ // _length > offset
+ break;
+ // UPDATE_HRES(res, OptReOpen_and_SetSize(i, size));
+ }
+
+ /* we Set Size of stream to zero even for (finalMode==true), although
+ that stream will be deleted in next commands */
+ // UPDATE_HRES(res, OptReOpen_and_SetSize(i, 0));
+ RINOK(OptReOpen_and_SetSize(i, 0))
+ if (finalMode)
+ {
+ RINOK(CloseStream_and_DeleteFile(i))
+ /* CVolStream::Stream was released above already, and it was
+ removed from linked list. So we don't need to update linked list
+ structure, when we delete last item in Streams[] */
+ Streams.DeleteBack();
+ // Delete_LastStream_Records();
+ }
+ }
+
+ /* now we create new zero-filled streams to cover all data up to _length */
+
+ if (_length == 0)
+ return S_OK;
+
+ // (offset) is start offset of next stream after existing Streams[]
+
+ for (;;)
+ {
+ // _length > offset
+ const UInt64 volSize = GetVolSize_for_Stream(Streams.Size());
+ UInt64 size = _length - offset; // (size != 0) here
+ if (size > volSize)
+ size = volSize;
+ RINOK(CreateNewStream(size))
+ if (_length - offset <= volSize)
+ return S_OK;
+ // _length - offset > volSize)
+ offset += volSize;
+ // _length > offset
+ }
+}
+
+
+HRESULT CMultiOutStream::FinalFlush_and_CloseFiles(unsigned &numTotalVolumesRes)
+{
+ // at first we remove unused zero-sized streams after _length
+ HRESULT res = Normalize_finalMode(true);
+ numTotalVolumesRes = Streams.Size();
+ FOR_VECTOR (i, Streams)
+ {
+ const HRESULT res2 = CloseStream_and_FinalRename(i);
+ if (res == S_OK)
+ res = res2;
+ }
+ if (NumListItems != 0 && res == S_OK)
+ res = E_FAIL;
+ return res;
+}
+
+
+bool CMultiOutStream::SetMTime_Final(const CFiTime &mTime)
+{
+ // we will set mtime only if new value differs from previous
+ if (!FinalVol_WasReopen && MTime_Defined && Compare_FiTime(&MTime, &mTime) == 0)
+ return true;
+ bool res = true;
+ FOR_VECTOR (i, Streams)
+ {
+ CVolStream &s = Streams[i];
+ if (s.Stream)
+ {
+ if (!s.StreamSpec->SetMTime(&mTime))
+ res = false;
+ }
+ else
+ {
+ if (!SetDirTime(GetFilePath(i), NULL, NULL, &mTime))
+ res = false;
+ }
+ }
+ return res;
+}
+
+
+Z7_COM7F_IMF(CMultiOutStream::SetSize(UInt64 newSize))
+{
+ COM_TRY_BEGIN
+ if ((Int64)newSize < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ if (newSize > _absLimit)
+ {
+ /* big seek value was sent to SetSize() or to Seek()+Write().
+ It can mean one of two situations:
+ 1) some incorrect code called it with big seek value.
+ 2) volume size was small, and we have too big number of volumes
+ */
+ /* in Windows SetEndOfFile() can return:
+ ERROR_NEGATIVE_SEEK: for >= (1 << 63)
+ ERROR_INVALID_PARAMETER: for > (16 TiB - 64 KiB)
+ ERROR_DISK_FULL: for <= (16 TiB - 64 KiB)
+ */
+ // return E_FAIL;
+ // return E_OUTOFMEMORY;
+ return E_INVALIDARG;
+ }
+
+ if (newSize > _length)
+ {
+ // we don't expect such case. So we just define global restriction */
+ _restrict_Global = newSize;
+ }
+ else if (newSize < _restrict_Global)
+ _restrict_Global = newSize;
+
+ PRF(printf("\n== SetSize, size =%u \n", (unsigned)newSize));
+
+ _length = newSize;
+ return Normalize_finalMode(false);
+
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CMultiOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ COM_TRY_BEGIN
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+
+ if (_absPos > _length)
+ {
+ // it create data only up to _absPos.
+ // but we still can need additional new streams, if _absPos at range of volume
+ RINOK(SetSize(_absPos))
+ }
+
+ while (size != 0)
+ {
+ UInt64 volSize;
+ {
+ if (_streamIndex < Sizes.Size() - 1)
+ {
+ volSize = Sizes[_streamIndex];
+ if (_offsetPos >= volSize)
+ {
+ _offsetPos -= volSize;
+ _streamIndex++;
+ continue;
+ }
+ }
+ else
+ {
+ volSize = Sizes[Sizes.Size() - 1];
+ if (_offsetPos >= volSize)
+ {
+ const UInt64 v = _offsetPos / volSize;
+ if (v >= ((UInt32)(Int32)-1) - _streamIndex)
+ return E_INVALIDARG;
+ // throw 202208;
+ _streamIndex += (unsigned)v;
+ _offsetPos -= (unsigned)v * volSize;
+ }
+ if (_streamIndex >= k_NumVols_MAX)
+ return E_INVALIDARG;
+ }
+ }
+
+ // (_offsetPos < volSize) here
+
+ /* we can need to create one or more streams here,
+ vol_size for some streams is allowed to be 0.
+ Also we close some new created streams, if they are non-restricted */
+ // file Size will be set later by calling Seek() with Write()
+
+ /* the case (_absPos > _length) was processed above with SetSize(_absPos),
+ so here it's expected. that we can create optional zero-size streams and then _streamIndex */
+ RINOK(CreateStreams_If_Required(_streamIndex))
+
+ CVolStream &s = Streams[_streamIndex];
+
+ PRF(printf("\n%d, == Write : Pos = %u, RealSize = %u size =%u \n",
+ _streamIndex, (unsigned)s.Pos, (unsigned)s.RealSize, size));
+
+ if (!s.Stream)
+ {
+ RINOK(ReOpenStream(_streamIndex))
+ }
+ if (_offsetPos != s.Pos)
+ {
+ RINOK(s.Stream->Seek((Int64)_offsetPos, STREAM_SEEK_SET, NULL))
+ s.Pos = _offsetPos;
+ }
+
+ UInt32 curSize = size;
+ {
+ const UInt64 rem = volSize - _offsetPos;
+ if (curSize > rem)
+ curSize = (UInt32)rem;
+ }
+ // curSize != 0
+ UInt32 realProcessed = 0;
+
+ HRESULT hres = s.Stream->Write(data, curSize, &realProcessed);
+
+ data = (const void *)((const Byte *)data + realProcessed);
+ size -= realProcessed;
+ s.Pos += realProcessed;
+ _offsetPos += realProcessed;
+ _absPos += realProcessed;
+ if (_length < _absPos)
+ _length = _absPos;
+ if (s.RealSize < _offsetPos)
+ s.RealSize = _offsetPos;
+ if (processedSize)
+ *processedSize += realProcessed;
+
+ if (s.Pos == volSize)
+ {
+ bool isRestricted;
+ if (volSize == 0)
+ isRestricted = IsRestricted_Empty(s);
+ else
+ isRestricted = IsRestricted(s);
+ if (!isRestricted)
+ {
+ const HRESULT res2 = CloseStream_and_FinalRename(_streamIndex);
+ if (hres == S_OK)
+ hres = res2;
+ }
+ _streamIndex++;
+ _offsetPos = 0;
+ }
+
+ RINOK(hres)
+ if (realProcessed == 0 && curSize != 0)
+ return E_FAIL;
+ // break;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CMultiOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ PRF(printf("\n-- Seek seekOrigin=%u Seek =%u\n", seekOrigin, (unsigned)offset));
+
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _absPos; break;
+ case STREAM_SEEK_END: offset += _length; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ if ((UInt64)offset != _absPos)
+ {
+ _absPos = (UInt64)offset;
+ _offsetPos = (UInt64)offset;
+ _streamIndex = 0;
+ }
+ if (newPosition)
+ *newPosition = (UInt64)offset;
+ return S_OK;
+}
+
+
+// result value will be saturated to (UInt32)(Int32)-1
+
+unsigned CMultiOutStream::GetStreamIndex_for_Offset(UInt64 offset, UInt64 &relOffset) const
+{
+ const unsigned last = Sizes.Size() - 1;
+ for (unsigned i = 0; i < last; i++)
+ {
+ const UInt64 size = Sizes[i];
+ if (offset < size)
+ {
+ relOffset = offset;
+ return i;
+ }
+ offset -= size;
+ }
+ const UInt64 size = Sizes[last];
+ const UInt64 v = offset / size;
+ if (v >= ((UInt32)(Int32)-1) - last)
+ return (UInt32)(Int32)-1; // saturation
+ relOffset = offset - (unsigned)v * size;
+ return last + (unsigned)(v);
+}
+
+
+Z7_COM7F_IMF(CMultiOutStream::SetRestriction(UInt64 begin, UInt64 end))
+{
+ COM_TRY_BEGIN
+
+ // begin = end = 0; // for debug
+
+ PRF(printf("\n==================== CMultiOutStream::SetRestriction %u, %u\n", (unsigned)begin, (unsigned)end));
+ if (begin > end)
+ {
+ // these value are FAILED values.
+ return E_FAIL;
+ // return E_INVALIDARG;
+ /*
+ // or we can ignore error with 3 ways: no change, non-restricted, saturation:
+ end = begin; // non-restricted
+ end = (UInt64)(Int64)-1; // saturation:
+ return S_OK;
+ */
+ }
+ UInt64 b = _restrict_Begin;
+ UInt64 e = _restrict_End;
+ _restrict_Begin = begin;
+ _restrict_End = end;
+
+ if (b == e) // if there were no restriction before
+ return S_OK; // no work to derestrict now.
+
+ /* [b, e) is previous restricted region. So all volumes that
+ intersect that [b, e) region are candidats for derestriction */
+
+ if (begin != end) // if there is new non-empty restricted region
+ {
+ /* Now we will try to reduce or change (b) and (e) bounds
+ to reduce main loop that checks volumes for derestriction.
+ We still use one big derestriction region in main loop, although
+ in some cases we could have two smaller derestriction regions.
+ Also usually restriction region cannot move back from previous start position,
+ so (b <= begin) is expected here for normal cases */
+ if (b == begin) // if same low bounds
+ b = end; // we need to derestrict only after the end of new restricted region
+ if (e == end) // if same high bounds
+ e = begin; // we need to derestrict only before the begin of new restricted region
+ }
+
+ if (b > e) // || b == (UInt64)(Int64)-1
+ return S_OK;
+
+ /* Here we close finished volumes that are not restricted anymore.
+ We close (low number) volumes at first. */
+
+ UInt64 offset;
+ unsigned index = GetStreamIndex_for_Offset(b, offset);
+
+ for (; index < Streams.Size(); index++)
+ {
+ {
+ const CVolStream &s = Streams[index];
+ if (_length <= s.Start)
+ break; // we don't close streams after _length
+ // (_length > s.Start)
+ const UInt64 volSize = GetVolSize_for_Stream(index);
+ if (volSize == 0)
+ {
+ if (e < s.Start)
+ break;
+ // we don't close empty stream, if next byte [s.Start, s.Start] is restricted
+ if (IsRestricted_Empty(s))
+ continue;
+ }
+ else
+ {
+ if (e <= s.Start)
+ break;
+ // we don't close non full streams
+ if (_length - s.Start < volSize)
+ break;
+ // (volSize == s.RealSize) is expected here. So no need to check it
+ // if (volSize != s.RealSize) break;
+ if (IsRestricted(s))
+ continue;
+ }
+ }
+ RINOK(CloseStream_and_FinalRename(index))
+ }
+
+ return S_OK;
+ COM_TRY_END
+}
diff --git a/CPP/7zip/Common/MultiOutStream.h b/CPP/7zip/Common/MultiOutStream.h
new file mode 100644
index 0000000..2fb7811
--- /dev/null
+++ b/CPP/7zip/Common/MultiOutStream.h
@@ -0,0 +1,160 @@
+// MultiOutStream.h
+
+#ifndef ZIP7_INC_MULTI_OUT_STREAM_H
+#define ZIP7_INC_MULTI_OUT_STREAM_H
+
+#include "FileStreams.h"
+
+Z7_CLASS_IMP_COM_2(
+ CMultiOutStream
+ , IOutStream
+ , IStreamSetRestriction
+)
+ Z7_IFACE_COM7_IMP(ISequentialOutStream)
+
+ Z7_CLASS_NO_COPY(CMultiOutStream)
+
+ struct CVolStream
+ {
+ COutFileStream *StreamSpec;
+ CMyComPtr<IOutStream> Stream;
+ UInt64 Start; // start pos of current Stream in global stream
+ UInt64 Pos; // pos in current Stream
+ UInt64 RealSize;
+ int Next; // next older
+ int Prev; // prev newer
+ AString Postfix;
+
+ HRESULT SetSize2(UInt64 size)
+ {
+ const HRESULT res = Stream->SetSize(size);
+ if (res == SZ_OK)
+ RealSize = size;
+ return res;
+ }
+ };
+
+ unsigned _streamIndex; // (_streamIndex >= Stream.Size()) is allowed in some internal code
+ UInt64 _offsetPos; // offset relative to Streams[_streamIndex] volume. (_offsetPos >= volSize is allowed)
+ UInt64 _absPos;
+ UInt64 _length; // virtual Length
+ UInt64 _absLimit;
+
+ CObjectVector<CVolStream> Streams;
+ CRecordVector<UInt64> Sizes;
+
+ UInt64 _restrict_Begin;
+ UInt64 _restrict_End;
+ UInt64 _restrict_Global;
+
+ unsigned NumOpenFiles_AllowedMax;
+
+ // ----- Double Linked List -----
+
+ unsigned NumListItems;
+ int Head; // newest
+ int Tail; // oldest
+
+ void InitLinkedList()
+ {
+ Head = -1;
+ Tail = -1;
+ NumListItems = 0;
+ }
+
+ void InsertToLinkedList(unsigned index)
+ {
+ {
+ CVolStream &node = Streams[index];
+ node.Next = Head;
+ node.Prev = -1;
+ }
+ if (Head != -1)
+ Streams[(unsigned)Head].Prev = (int)index;
+ else
+ {
+ // if (Tail != -1) throw 1;
+ Tail = (int)index;
+ }
+ Head = (int)index;
+ NumListItems++;
+ }
+
+ void RemoveFromLinkedList(unsigned index)
+ {
+ CVolStream &s = Streams[index];
+ if (s.Next != -1) Streams[(unsigned)s.Next].Prev = s.Prev; else Tail = s.Prev;
+ if (s.Prev != -1) Streams[(unsigned)s.Prev].Next = s.Next; else Head = s.Next;
+ s.Next = -1; // optional
+ s.Prev = -1; // optional
+ NumListItems--;
+ }
+
+ /*
+ void Delete_LastStream_Records()
+ {
+ if (Streams.Back().Stream)
+ RemoveFromLinkedList(Streams.Size() - 1);
+ Streams.DeleteBack();
+ }
+ */
+
+ UInt64 GetVolSize_for_Stream(unsigned i) const
+ {
+ const unsigned last = Sizes.Size() - 1;
+ return Sizes[i < last ? i : last];
+ }
+ UInt64 GetGlobalOffset_for_NewStream() const
+ {
+ return Streams.Size() == 0 ? 0:
+ Streams.Back().Start +
+ GetVolSize_for_Stream(Streams.Size() - 1);
+ }
+ unsigned GetStreamIndex_for_Offset(UInt64 offset, UInt64 &relOffset) const;
+ bool IsRestricted(const CVolStream &s) const;
+ bool IsRestricted_Empty(const CVolStream &s) const
+ {
+ // (s) must be stream that has (VolSize == 0).
+ // we treat empty stream as restricted, if next byte is restricted.
+ if (s.Start < _restrict_Global)
+ return true;
+ return
+ (_restrict_Begin != _restrict_End)
+ && (_restrict_Begin <= s.Start)
+ && (_restrict_Begin == s.Start || _restrict_End > s.Start);
+ }
+ // bool IsRestricted_for_Close(unsigned index) const;
+ FString GetFilePath(unsigned index);
+
+ HRESULT CloseStream(unsigned index);
+ HRESULT CloseStream_and_DeleteFile(unsigned index);
+ HRESULT CloseStream_and_FinalRename(unsigned index);
+
+ HRESULT PrepareToOpenNew();
+ HRESULT CreateNewStream(UInt64 newSize);
+ HRESULT CreateStreams_If_Required(unsigned streamIndex);
+ HRESULT ReOpenStream(unsigned streamIndex);
+ HRESULT OptReOpen_and_SetSize(unsigned index, UInt64 size);
+
+ HRESULT Normalize_finalMode(bool finalMode);
+public:
+ FString Prefix;
+ CFiTime MTime;
+ bool MTime_Defined;
+ bool FinalVol_WasReopen;
+ bool NeedDelete;
+
+ CMultiOutStream() {}
+ ~CMultiOutStream();
+ void Init(const CRecordVector<UInt64> &sizes);
+ bool SetMTime_Final(const CFiTime &mTime);
+ UInt64 GetSize() const { return _length; }
+ /* it makes final flushing, closes open files and renames to final name if required
+ but it still keeps Streams array of all closed files.
+ So we still can delete all files later, if required */
+ HRESULT FinalFlush_and_CloseFiles(unsigned &numTotalVolumesRes);
+ // Destruct object without exceptions
+ HRESULT Destruct();
+};
+
+#endif
diff --git a/CPP/7zip/Common/OffsetStream.cpp b/CPP/7zip/Common/OffsetStream.cpp
index 3b01c7f..a6b005e 100644
--- a/CPP/7zip/Common/OffsetStream.cpp
+++ b/CPP/7zip/Common/OffsetStream.cpp
@@ -1,39 +1,37 @@
-// OffsetStream.cpp
-
-#include "StdAfx.h"
-
-#include "../../Common/Defs.h"
-
-#include "OffsetStream.h"
-
-HRESULT COffsetOutStream::Init(IOutStream *stream, UInt64 offset)
-{
- _offset = offset;
- _stream = stream;
- return _stream->Seek(offset, STREAM_SEEK_SET, NULL);
-}
-
-STDMETHODIMP COffsetOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- return _stream->Write(data, size, processedSize);
-}
-
-STDMETHODIMP COffsetOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- UInt64 absoluteNewPosition;
- if (seekOrigin == STREAM_SEEK_SET)
- {
- if (offset < 0)
- return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
- offset += _offset;
- }
- HRESULT result = _stream->Seek(offset, seekOrigin, &absoluteNewPosition);
- if (newPosition)
- *newPosition = absoluteNewPosition - _offset;
- return result;
-}
-
-STDMETHODIMP COffsetOutStream::SetSize(UInt64 newSize)
-{
- return _stream->SetSize(_offset + newSize);
-}
+// OffsetStream.cpp
+
+#include "StdAfx.h"
+
+#include "OffsetStream.h"
+
+HRESULT COffsetOutStream::Init(IOutStream *stream, UInt64 offset)
+{
+ _offset = offset;
+ _stream = stream;
+ return _stream->Seek((Int64)offset, STREAM_SEEK_SET, NULL);
+}
+
+Z7_COM7F_IMF(COffsetOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ return _stream->Write(data, size, processedSize);
+}
+
+Z7_COM7F_IMF(COffsetOutStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ if (seekOrigin == STREAM_SEEK_SET)
+ {
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ offset += _offset;
+ }
+ UInt64 absoluteNewPosition = 0; // =0 for gcc-10
+ const HRESULT result = _stream->Seek(offset, seekOrigin, &absoluteNewPosition);
+ if (newPosition)
+ *newPosition = absoluteNewPosition - _offset;
+ return result;
+}
+
+Z7_COM7F_IMF(COffsetOutStream::SetSize(UInt64 newSize))
+{
+ return _stream->SetSize(_offset + newSize);
+}
diff --git a/CPP/7zip/Common/OffsetStream.h b/CPP/7zip/Common/OffsetStream.h
index ad835f2..9bd554c 100644
--- a/CPP/7zip/Common/OffsetStream.h
+++ b/CPP/7zip/Common/OffsetStream.h
@@ -1,26 +1,22 @@
-// OffsetStream.h
-
-#ifndef __OFFSET_STREAM_H
-#define __OFFSET_STREAM_H
-
-#include "../../Common/MyCom.h"
-
-#include "../IStream.h"
-
-class COffsetOutStream:
- public IOutStream,
- public CMyUnknownImp
-{
- UInt64 _offset;
- CMyComPtr<IOutStream> _stream;
-public:
- HRESULT Init(IOutStream *stream, UInt64 offset);
-
- MY_UNKNOWN_IMP
-
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
- STDMETHOD(SetSize)(UInt64 newSize);
-};
-
-#endif
+// OffsetStream.h
+
+#ifndef ZIP7_INC_OFFSET_STREAM_H
+#define ZIP7_INC_OFFSET_STREAM_H
+
+#include "../../Common/MyCom.h"
+
+#include "../IStream.h"
+
+Z7_CLASS_IMP_NOQIB_1(
+ COffsetOutStream
+ , IOutStream
+)
+ Z7_IFACE_COM7_IMP(ISequentialOutStream)
+
+ CMyComPtr<IOutStream> _stream;
+ UInt64 _offset;
+public:
+ HRESULT Init(IOutStream *stream, UInt64 offset);
+};
+
+#endif
diff --git a/CPP/7zip/Common/OutBuffer.cpp b/CPP/7zip/Common/OutBuffer.cpp
index fb8dc8d..197b376 100644
--- a/CPP/7zip/Common/OutBuffer.cpp
+++ b/CPP/7zip/Common/OutBuffer.cpp
@@ -1,111 +1,111 @@
-// OutBuffer.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/Alloc.h"
-
-#include "OutBuffer.h"
-
-bool COutBuffer::Create(UInt32 bufSize) throw()
-{
- const UInt32 kMinBlockSize = 1;
- if (bufSize < kMinBlockSize)
- bufSize = kMinBlockSize;
- if (_buf != 0 && _bufSize == bufSize)
- return true;
- Free();
- _bufSize = bufSize;
- _buf = (Byte *)::MidAlloc(bufSize);
- return (_buf != 0);
-}
-
-void COutBuffer::Free() throw()
-{
- ::MidFree(_buf);
- _buf = 0;
-}
-
-void COutBuffer::Init() throw()
-{
- _streamPos = 0;
- _limitPos = _bufSize;
- _pos = 0;
- _processedSize = 0;
- _overDict = false;
- #ifdef _NO_EXCEPTIONS
- ErrorCode = S_OK;
- #endif
-}
-
-UInt64 COutBuffer::GetProcessedSize() const throw()
-{
- UInt64 res = _processedSize + _pos - _streamPos;
- if (_streamPos > _pos)
- res += _bufSize;
- return res;
-}
-
-
-HRESULT COutBuffer::FlushPart() throw()
-{
- // _streamPos < _bufSize
- UInt32 size = (_streamPos >= _pos) ? (_bufSize - _streamPos) : (_pos - _streamPos);
- HRESULT result = S_OK;
- #ifdef _NO_EXCEPTIONS
- result = ErrorCode;
- #endif
- if (_buf2 != 0)
- {
- memcpy(_buf2, _buf + _streamPos, size);
- _buf2 += size;
- }
-
- if (_stream != 0
- #ifdef _NO_EXCEPTIONS
- && (ErrorCode == S_OK)
- #endif
- )
- {
- UInt32 processedSize = 0;
- result = _stream->Write(_buf + _streamPos, size, &processedSize);
- size = processedSize;
- }
- _streamPos += size;
- if (_streamPos == _bufSize)
- _streamPos = 0;
- if (_pos == _bufSize)
- {
- _overDict = true;
- _pos = 0;
- }
- _limitPos = (_streamPos > _pos) ? _streamPos : _bufSize;
- _processedSize += size;
- return result;
-}
-
-HRESULT COutBuffer::Flush() throw()
-{
- #ifdef _NO_EXCEPTIONS
- if (ErrorCode != S_OK)
- return ErrorCode;
- #endif
-
- while (_streamPos != _pos)
- {
- HRESULT result = FlushPart();
- if (result != S_OK)
- return result;
- }
- return S_OK;
-}
-
-void COutBuffer::FlushWithCheck()
-{
- HRESULT result = Flush();
- #ifdef _NO_EXCEPTIONS
- ErrorCode = result;
- #else
- if (result != S_OK)
- throw COutBufferException(result);
- #endif
-}
+// OutBuffer.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "OutBuffer.h"
+
+bool COutBuffer::Create(UInt32 bufSize) throw()
+{
+ const UInt32 kMinBlockSize = 1;
+ if (bufSize < kMinBlockSize)
+ bufSize = kMinBlockSize;
+ if (_buf && _bufSize == bufSize)
+ return true;
+ Free();
+ _bufSize = bufSize;
+ _buf = (Byte *)::MidAlloc(bufSize);
+ return (_buf != NULL);
+}
+
+void COutBuffer::Free() throw()
+{
+ ::MidFree(_buf);
+ _buf = NULL;
+}
+
+void COutBuffer::Init() throw()
+{
+ _streamPos = 0;
+ _limitPos = _bufSize;
+ _pos = 0;
+ _processedSize = 0;
+ _overDict = false;
+ #ifdef Z7_NO_EXCEPTIONS
+ ErrorCode = S_OK;
+ #endif
+}
+
+UInt64 COutBuffer::GetProcessedSize() const throw()
+{
+ UInt64 res = _processedSize + _pos - _streamPos;
+ if (_streamPos > _pos)
+ res += _bufSize;
+ return res;
+}
+
+
+HRESULT COutBuffer::FlushPart() throw()
+{
+ // _streamPos < _bufSize
+ UInt32 size = (_streamPos >= _pos) ? (_bufSize - _streamPos) : (_pos - _streamPos);
+ HRESULT result = S_OK;
+ #ifdef Z7_NO_EXCEPTIONS
+ result = ErrorCode;
+ #endif
+ if (_buf2)
+ {
+ memcpy(_buf2, _buf + _streamPos, size);
+ _buf2 += size;
+ }
+
+ if (_stream
+ #ifdef Z7_NO_EXCEPTIONS
+ && (ErrorCode == S_OK)
+ #endif
+ )
+ {
+ UInt32 processedSize = 0;
+ result = _stream->Write(_buf + _streamPos, size, &processedSize);
+ size = processedSize;
+ }
+ _streamPos += size;
+ if (_streamPos == _bufSize)
+ _streamPos = 0;
+ if (_pos == _bufSize)
+ {
+ _overDict = true;
+ _pos = 0;
+ }
+ _limitPos = (_streamPos > _pos) ? _streamPos : _bufSize;
+ _processedSize += size;
+ return result;
+}
+
+HRESULT COutBuffer::Flush() throw()
+{
+ #ifdef Z7_NO_EXCEPTIONS
+ if (ErrorCode != S_OK)
+ return ErrorCode;
+ #endif
+
+ while (_streamPos != _pos)
+ {
+ const HRESULT result = FlushPart();
+ if (result != S_OK)
+ return result;
+ }
+ return S_OK;
+}
+
+void COutBuffer::FlushWithCheck()
+{
+ const HRESULT result = Flush();
+ #ifdef Z7_NO_EXCEPTIONS
+ ErrorCode = result;
+ #else
+ if (result != S_OK)
+ throw COutBufferException(result);
+ #endif
+}
diff --git a/CPP/7zip/Common/OutBuffer.h b/CPP/7zip/Common/OutBuffer.h
index 2ffb5cd..cef7d50 100644
--- a/CPP/7zip/Common/OutBuffer.h
+++ b/CPP/7zip/Common/OutBuffer.h
@@ -1,66 +1,66 @@
-// OutBuffer.h
-
-#ifndef __OUT_BUFFER_H
-#define __OUT_BUFFER_H
-
-#include "../IStream.h"
-#include "../../Common/MyCom.h"
-#include "../../Common/MyException.h"
-
-#ifndef _NO_EXCEPTIONS
-struct COutBufferException: public CSystemException
-{
- COutBufferException(HRESULT errorCode): CSystemException(errorCode) {}
-};
-#endif
-
-class COutBuffer
-{
-protected:
- Byte *_buf;
- UInt32 _pos;
- UInt32 _limitPos;
- UInt32 _streamPos;
- UInt32 _bufSize;
- ISequentialOutStream *_stream;
- UInt64 _processedSize;
- Byte *_buf2;
- bool _overDict;
-
- HRESULT FlushPart() throw();
-public:
- #ifdef _NO_EXCEPTIONS
- HRESULT ErrorCode;
- #endif
-
- COutBuffer(): _buf(0), _pos(0), _stream(0), _buf2(0) {}
- ~COutBuffer() { Free(); }
-
- bool Create(UInt32 bufSize) throw();
- void Free() throw();
-
- void SetMemStream(Byte *buf) { _buf2 = buf; }
- void SetStream(ISequentialOutStream *stream) { _stream = stream; }
- void Init() throw();
- HRESULT Flush() throw();
- void FlushWithCheck();
-
- void WriteByte(Byte b)
- {
- UInt32 pos = _pos;
- _buf[pos] = b;
- pos++;
- _pos = pos;
- if (pos == _limitPos)
- FlushWithCheck();
- }
- void WriteBytes(const void *data, size_t size)
- {
- for (size_t i = 0; i < size; i++)
- WriteByte(((const Byte *)data)[i]);
- }
-
- UInt64 GetProcessedSize() const throw();
-};
-
-#endif
+// OutBuffer.h
+
+#ifndef ZIP7_INC_OUT_BUFFER_H
+#define ZIP7_INC_OUT_BUFFER_H
+
+#include "../IStream.h"
+#include "../../Common/MyCom.h"
+#include "../../Common/MyException.h"
+
+#ifndef Z7_NO_EXCEPTIONS
+struct COutBufferException: public CSystemException
+{
+ COutBufferException(HRESULT errorCode): CSystemException(errorCode) {}
+};
+#endif
+
+class COutBuffer
+{
+protected:
+ Byte *_buf;
+ UInt32 _pos;
+ UInt32 _limitPos;
+ UInt32 _streamPos;
+ UInt32 _bufSize;
+ ISequentialOutStream *_stream;
+ UInt64 _processedSize;
+ Byte *_buf2;
+ bool _overDict;
+
+ HRESULT FlushPart() throw();
+public:
+ #ifdef Z7_NO_EXCEPTIONS
+ HRESULT ErrorCode;
+ #endif
+
+ COutBuffer(): _buf(NULL), _pos(0), _stream(NULL), _buf2(NULL) {}
+ ~COutBuffer() { Free(); }
+
+ bool Create(UInt32 bufSize) throw();
+ void Free() throw();
+
+ void SetMemStream(Byte *buf) { _buf2 = buf; }
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void Init() throw();
+ HRESULT Flush() throw();
+ void FlushWithCheck();
+
+ void WriteByte(Byte b)
+ {
+ UInt32 pos = _pos;
+ _buf[pos] = b;
+ pos++;
+ _pos = pos;
+ if (pos == _limitPos)
+ FlushWithCheck();
+ }
+ void WriteBytes(const void *data, size_t size)
+ {
+ for (size_t i = 0; i < size; i++)
+ WriteByte(((const Byte *)data)[i]);
+ }
+
+ UInt64 GetProcessedSize() const throw();
+};
+
+#endif
diff --git a/CPP/7zip/Common/OutMemStream.cpp b/CPP/7zip/Common/OutMemStream.cpp
new file mode 100644
index 0000000..29a2394
--- /dev/null
+++ b/CPP/7zip/Common/OutMemStream.cpp
@@ -0,0 +1,158 @@
+// OutMemStream.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "OutMemStream.h"
+
+void COutMemStream::Free()
+{
+ Blocks.Free(_memManager);
+ Blocks.LockMode = true;
+}
+
+void COutMemStream::Init()
+{
+ WriteToRealStreamEvent.Reset();
+ _unlockEventWasSent = false;
+ _realStreamMode = false;
+ Free();
+ _curBlockPos = 0;
+ _curBlockIndex = 0;
+}
+
+void COutMemStream::DetachData(CMemLockBlocks &blocks)
+{
+ Blocks.Detach(blocks, _memManager);
+ Free();
+}
+
+
+HRESULT COutMemStream::WriteToRealStream()
+{
+ RINOK(Blocks.WriteToStream(_memManager->GetBlockSize(), OutSeqStream))
+ Blocks.Free(_memManager);
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(COutMemStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (_realStreamMode)
+ return OutSeqStream->Write(data, size, processedSize);
+ if (processedSize)
+ *processedSize = 0;
+ while (size != 0)
+ {
+ if (_curBlockIndex < Blocks.Blocks.Size())
+ {
+ Byte *p = (Byte *)Blocks.Blocks[_curBlockIndex] + _curBlockPos;
+ size_t curSize = _memManager->GetBlockSize() - _curBlockPos;
+ if (size < curSize)
+ curSize = size;
+ memcpy(p, data, curSize);
+ if (processedSize)
+ *processedSize += (UInt32)curSize;
+ data = (const void *)((const Byte *)data + curSize);
+ size -= (UInt32)curSize;
+ _curBlockPos += curSize;
+
+ const UInt64 pos64 = GetPos();
+ if (pos64 > Blocks.TotalSize)
+ Blocks.TotalSize = pos64;
+ if (_curBlockPos == _memManager->GetBlockSize())
+ {
+ _curBlockIndex++;
+ _curBlockPos = 0;
+ }
+ continue;
+ }
+
+ const NWindows::NSynchronization::CHandle_WFMO events[3] =
+ { StopWritingEvent, WriteToRealStreamEvent, /* NoLockEvent, */ _memManager->Semaphore };
+ const DWORD waitResult = NWindows::NSynchronization::WaitForMultiObj_Any_Infinite(
+ ((Blocks.LockMode /* && _memManager->Semaphore.IsCreated() */) ? 3 : 2), events);
+
+ // printf("\n 1- outMemStream %d\n", waitResult - WAIT_OBJECT_0);
+
+ switch (waitResult)
+ {
+ case (WAIT_OBJECT_0 + 0):
+ return StopWriteResult;
+ case (WAIT_OBJECT_0 + 1):
+ {
+ _realStreamMode = true;
+ RINOK(WriteToRealStream())
+ UInt32 processedSize2;
+ const HRESULT res = OutSeqStream->Write(data, size, &processedSize2);
+ if (processedSize)
+ *processedSize += processedSize2;
+ return res;
+ }
+ case (WAIT_OBJECT_0 + 2):
+ {
+ // it has bug: no write.
+ /*
+ if (!Blocks.SwitchToNoLockMode(_memManager))
+ return E_FAIL;
+ */
+ break;
+ }
+ default:
+ {
+ if (waitResult == WAIT_FAILED)
+ {
+ const DWORD res = ::GetLastError();
+ if (res != 0)
+ return HRESULT_FROM_WIN32(res);
+ }
+ return E_FAIL;
+ }
+ }
+ void *p = _memManager->AllocateBlock();
+ if (!p)
+ return E_FAIL;
+ Blocks.Blocks.Add(p);
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(COutMemStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ if (_realStreamMode)
+ {
+ if (!OutStream)
+ return E_FAIL;
+ return OutStream->Seek(offset, seekOrigin, newPosition);
+ }
+ if (seekOrigin == STREAM_SEEK_CUR)
+ {
+ if (offset != 0)
+ return E_NOTIMPL;
+ }
+ else if (seekOrigin == STREAM_SEEK_SET)
+ {
+ if (offset != 0)
+ return E_NOTIMPL;
+ _curBlockIndex = 0;
+ _curBlockPos = 0;
+ }
+ else
+ return E_NOTIMPL;
+ if (newPosition)
+ *newPosition = GetPos();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(COutMemStream::SetSize(UInt64 newSize))
+{
+ if (_realStreamMode)
+ {
+ if (!OutStream)
+ return E_FAIL;
+ return OutStream->SetSize(newSize);
+ }
+ Blocks.TotalSize = newSize;
+ return S_OK;
+}
diff --git a/CPP/7zip/Common/OutMemStream.h b/CPP/7zip/Common/OutMemStream.h
new file mode 100644
index 0000000..7fc2dbd
--- /dev/null
+++ b/CPP/7zip/Common/OutMemStream.h
@@ -0,0 +1,104 @@
+// OutMemStream.h
+
+#ifndef ZIP7_INC_OUT_MEM_STREAM_H
+#define ZIP7_INC_OUT_MEM_STREAM_H
+
+#include "../../Common/MyCom.h"
+
+#include "MemBlocks.h"
+
+Z7_CLASS_IMP_NOQIB_1(
+ COutMemStream
+ , IOutStream
+)
+ Z7_IFACE_COM7_IMP(ISequentialOutStream)
+
+ CMemBlockManagerMt *_memManager;
+ size_t _curBlockPos;
+ unsigned _curBlockIndex;
+ bool _realStreamMode;
+
+ bool _unlockEventWasSent;
+ NWindows::NSynchronization::CAutoResetEvent_WFMO StopWritingEvent;
+ NWindows::NSynchronization::CAutoResetEvent_WFMO WriteToRealStreamEvent;
+ // NWindows::NSynchronization::CAutoResetEvent NoLockEvent;
+
+ HRESULT StopWriteResult;
+ CMemLockBlocks Blocks;
+
+ CMyComPtr<ISequentialOutStream> OutSeqStream;
+ CMyComPtr<IOutStream> OutStream;
+
+ UInt64 GetPos() const { return (UInt64)_curBlockIndex * _memManager->GetBlockSize() + _curBlockPos; }
+
+public:
+
+ HRes CreateEvents(SYNC_PARAM_DECL(synchro))
+ {
+ WRes wres = StopWritingEvent.CreateIfNotCreated_Reset(SYNC_WFMO(synchro));
+ if (wres == 0)
+ wres = WriteToRealStreamEvent.CreateIfNotCreated_Reset(SYNC_WFMO(synchro));
+ return HRESULT_FROM_WIN32(wres);
+ }
+
+ void SetOutStream(IOutStream *outStream)
+ {
+ OutStream = outStream;
+ OutSeqStream = outStream;
+ }
+
+ void SetSeqOutStream(ISequentialOutStream *outStream)
+ {
+ OutStream = NULL;
+ OutSeqStream = outStream;
+ }
+
+ void ReleaseOutStream()
+ {
+ OutStream.Release();
+ OutSeqStream.Release();
+ }
+
+ COutMemStream(CMemBlockManagerMt *memManager):
+ _memManager(memManager)
+ {
+ /*
+ #ifndef _WIN32
+ StopWritingEvent._sync =
+ WriteToRealStreamEvent._sync = &memManager->Synchro;
+ #endif
+ */
+ }
+
+ ~COutMemStream() { Free(); }
+ void Free();
+
+ void Init();
+ HRESULT WriteToRealStream();
+
+ void DetachData(CMemLockBlocks &blocks);
+
+ bool WasUnlockEventSent() const { return _unlockEventWasSent; }
+
+ void SetRealStreamMode()
+ {
+ _unlockEventWasSent = true;
+ WriteToRealStreamEvent.Set();
+ }
+
+ /*
+ void SetNoLockMode()
+ {
+ _unlockEventWasSent = true;
+ NoLockEvent.Set();
+ }
+ */
+
+ void StopWriting(HRESULT res)
+ {
+ StopWriteResult = res;
+ StopWritingEvent.Set();
+ }
+};
+
+#endif
diff --git a/CPP/7zip/Common/ProgressMt.cpp b/CPP/7zip/Common/ProgressMt.cpp
new file mode 100644
index 0000000..ee21ab3
--- /dev/null
+++ b/CPP/7zip/Common/ProgressMt.cpp
@@ -0,0 +1,53 @@
+// ProgressMt.h
+
+#include "StdAfx.h"
+
+#include "ProgressMt.h"
+
+void CMtCompressProgressMixer::Init(unsigned numItems, ICompressProgressInfo *progress)
+{
+ NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
+ InSizes.Clear();
+ OutSizes.Clear();
+ for (unsigned i = 0; i < numItems; i++)
+ {
+ InSizes.Add(0);
+ OutSizes.Add(0);
+ }
+ TotalInSize = 0;
+ TotalOutSize = 0;
+ _progress = progress;
+}
+
+void CMtCompressProgressMixer::Reinit(unsigned index)
+{
+ NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
+ InSizes[index] = 0;
+ OutSizes[index] = 0;
+}
+
+HRESULT CMtCompressProgressMixer::SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize)
+{
+ NWindows::NSynchronization::CCriticalSectionLock lock(CriticalSection);
+ if (inSize)
+ {
+ const UInt64 diff = *inSize - InSizes[index];
+ InSizes[index] = *inSize;
+ TotalInSize += diff;
+ }
+ if (outSize)
+ {
+ const UInt64 diff = *outSize - OutSizes[index];
+ OutSizes[index] = *outSize;
+ TotalOutSize += diff;
+ }
+ if (_progress)
+ return _progress->SetRatioInfo(&TotalInSize, &TotalOutSize);
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CMtCompressProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
+{
+ return _progress->SetRatioInfo(_index, inSize, outSize);
+}
diff --git a/CPP/7zip/Common/ProgressMt.h b/CPP/7zip/Common/ProgressMt.h
new file mode 100644
index 0000000..78c806c
--- /dev/null
+++ b/CPP/7zip/Common/ProgressMt.h
@@ -0,0 +1,43 @@
+// ProgressMt.h
+
+#ifndef ZIP7_INC_PROGRESSMT_H
+#define ZIP7_INC_PROGRESSMT_H
+
+#include "../../Common/MyCom.h"
+#include "../../Common/MyVector.h"
+#include "../../Windows/Synchronization.h"
+
+#include "../ICoder.h"
+#include "../IProgress.h"
+
+class CMtCompressProgressMixer
+{
+ CMyComPtr<ICompressProgressInfo> _progress;
+ CRecordVector<UInt64> InSizes;
+ CRecordVector<UInt64> OutSizes;
+ UInt64 TotalInSize;
+ UInt64 TotalOutSize;
+public:
+ NWindows::NSynchronization::CCriticalSection CriticalSection;
+ void Init(unsigned numItems, ICompressProgressInfo *progress);
+ void Reinit(unsigned index);
+ HRESULT SetRatioInfo(unsigned index, const UInt64 *inSize, const UInt64 *outSize);
+};
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ CMtCompressProgress
+ , ICompressProgressInfo
+)
+ unsigned _index;
+ CMtCompressProgressMixer *_progress;
+public:
+ void Init(CMtCompressProgressMixer *progress, unsigned index)
+ {
+ _progress = progress;
+ _index = index;
+ }
+ void Reinit() { _progress->Reinit(_index); }
+};
+
+#endif
diff --git a/CPP/7zip/Common/ProgressUtils.cpp b/CPP/7zip/Common/ProgressUtils.cpp
index 86f1e78..fb81f29 100644
--- a/CPP/7zip/Common/ProgressUtils.cpp
+++ b/CPP/7zip/Common/ProgressUtils.cpp
@@ -1,51 +1,51 @@
-// ProgressUtils.cpp
-
-#include "StdAfx.h"
-
-#include "ProgressUtils.h"
-
-CLocalProgress::CLocalProgress():
- ProgressOffset(0),
- InSize(0),
- OutSize(0),
- SendRatio(true),
- SendProgress(true)
- {}
-
-void CLocalProgress::Init(IProgress *progress, bool inSizeIsMain)
-{
- _ratioProgress.Release();
- _progress = progress;
- _progress.QueryInterface(IID_ICompressProgressInfo, &_ratioProgress);
- _inSizeIsMain = inSizeIsMain;
-}
-
-STDMETHODIMP CLocalProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
-{
- UInt64 inSize2 = InSize;
- UInt64 outSize2 = OutSize;
-
- if (inSize)
- inSize2 += (*inSize);
- if (outSize)
- outSize2 += (*outSize);
-
- if (SendRatio && _ratioProgress)
- {
- RINOK(_ratioProgress->SetRatioInfo(&inSize2, &outSize2));
- }
-
- if (SendProgress)
- {
- inSize2 += ProgressOffset;
- outSize2 += ProgressOffset;
- return _progress->SetCompleted(_inSizeIsMain ? &inSize2 : &outSize2);
- }
-
- return S_OK;
-}
-
-HRESULT CLocalProgress::SetCur()
-{
- return SetRatioInfo(NULL, NULL);
-}
+// ProgressUtils.cpp
+
+#include "StdAfx.h"
+
+#include "ProgressUtils.h"
+
+CLocalProgress::CLocalProgress():
+ SendRatio(true),
+ SendProgress(true),
+ ProgressOffset(0),
+ InSize(0),
+ OutSize(0)
+ {}
+
+void CLocalProgress::Init(IProgress *progress, bool inSizeIsMain)
+{
+ _ratioProgress.Release();
+ _progress = progress;
+ _progress.QueryInterface(IID_ICompressProgressInfo, &_ratioProgress);
+ _inSizeIsMain = inSizeIsMain;
+}
+
+Z7_COM7F_IMF(CLocalProgress::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
+{
+ UInt64 inSize2 = InSize;
+ UInt64 outSize2 = OutSize;
+
+ if (inSize)
+ inSize2 += (*inSize);
+ if (outSize)
+ outSize2 += (*outSize);
+
+ if (SendRatio && _ratioProgress)
+ {
+ RINOK(_ratioProgress->SetRatioInfo(&inSize2, &outSize2))
+ }
+
+ if (SendProgress)
+ {
+ inSize2 += ProgressOffset;
+ outSize2 += ProgressOffset;
+ return _progress->SetCompleted(_inSizeIsMain ? &inSize2 : &outSize2);
+ }
+
+ return S_OK;
+}
+
+HRESULT CLocalProgress::SetCur()
+{
+ return SetRatioInfo(NULL, NULL);
+}
diff --git a/CPP/7zip/Common/ProgressUtils.h b/CPP/7zip/Common/ProgressUtils.h
index 176e8bb..dad5fcc 100644
--- a/CPP/7zip/Common/ProgressUtils.h
+++ b/CPP/7zip/Common/ProgressUtils.h
@@ -1,35 +1,33 @@
-// ProgressUtils.h
-
-#ifndef __PROGRESS_UTILS_H
-#define __PROGRESS_UTILS_H
-
-#include "../../Common/MyCom.h"
-
-#include "../ICoder.h"
-#include "../IProgress.h"
-
-class CLocalProgress:
- public ICompressProgressInfo,
- public CMyUnknownImp
-{
- CMyComPtr<IProgress> _progress;
- CMyComPtr<ICompressProgressInfo> _ratioProgress;
- bool _inSizeIsMain;
-public:
- UInt64 ProgressOffset;
- UInt64 InSize;
- UInt64 OutSize;
- bool SendRatio;
- bool SendProgress;
-
- CLocalProgress();
-
- void Init(IProgress *progress, bool inSizeIsMain);
- HRESULT SetCur();
-
- MY_UNKNOWN_IMP1(ICompressProgressInfo)
-
- STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
-};
-
-#endif
+// ProgressUtils.h
+
+#ifndef ZIP7_INC_PROGRESS_UTILS_H
+#define ZIP7_INC_PROGRESS_UTILS_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+#include "../IProgress.h"
+
+Z7_CLASS_IMP_COM_1(
+ CLocalProgress
+ , ICompressProgressInfo
+)
+public:
+ bool SendRatio;
+ bool SendProgress;
+private:
+ bool _inSizeIsMain;
+ CMyComPtr<IProgress> _progress;
+ CMyComPtr<ICompressProgressInfo> _ratioProgress;
+public:
+ UInt64 ProgressOffset;
+ UInt64 InSize;
+ UInt64 OutSize;
+
+ CLocalProgress();
+
+ void Init(IProgress *progress, bool inSizeIsMain);
+ HRESULT SetCur();
+};
+
+#endif
diff --git a/CPP/7zip/Common/PropId.cpp b/CPP/7zip/Common/PropId.cpp
index 96f8f05..6117b0e 100644
--- a/CPP/7zip/Common/PropId.cpp
+++ b/CPP/7zip/Common/PropId.cpp
@@ -1,108 +1,117 @@
-// PropId.cpp
-
-#include "StdAfx.h"
-
-#include "../../Common/MyWindows.h"
-
-#include "../PropID.h"
-
-// VARTYPE
-const Byte k7z_PROPID_To_VARTYPE[kpid_NUM_DEFINED] =
-{
- VT_EMPTY,
- VT_UI4,
- VT_UI4,
- VT_BSTR,
- VT_BSTR,
- VT_BSTR,
- VT_BOOL,
- VT_UI8,
- VT_UI8,
- VT_UI4,
- VT_FILETIME,
- VT_FILETIME,
- VT_FILETIME,
- VT_BOOL,
- VT_BOOL,
- VT_BOOL,
- VT_BOOL,
- VT_BOOL,
- VT_UI4,
- VT_UI4,
- VT_BSTR,
- VT_BOOL,
- VT_BSTR,
- VT_BSTR,
- VT_BSTR,
- VT_BSTR,
- VT_BSTR,
- VT_UI8,
- VT_BSTR,
- VT_UI8,
- VT_BSTR,
- VT_UI8,
- VT_UI8,
- VT_BSTR, // or VT_UI8 kpidUnpackVer
- VT_UI4, // or VT_UI8 kpidVolume
- VT_BOOL,
- VT_UI8,
- VT_UI8,
- VT_UI8,
- VT_UI8,
- VT_UI4,
- VT_BOOL,
- VT_BOOL,
- VT_BSTR,
- VT_UI8,
- VT_UI8,
- VT_UI4, // kpidChecksum
- VT_BSTR,
- VT_UI8,
- VT_BSTR, // or VT_UI8 kpidId
- VT_BSTR,
- VT_BSTR,
- VT_UI4,
- VT_UI4,
- VT_BSTR,
- VT_BSTR,
- VT_UI8,
- VT_UI8,
- VT_UI4,
- VT_BSTR,
- VT_BSTR,
- VT_BSTR,
- VT_BSTR, // kpidNtSecure
- VT_BOOL,
- VT_BOOL,
- VT_BOOL,
- VT_BOOL,
- VT_BSTR, // SHA-1
- VT_BSTR, // SHA-256
- VT_BSTR,
- VT_UI8,
- VT_UI4,
- VT_UI4,
- VT_BSTR,
- VT_UI8,
- VT_UI8,
- VT_UI8,
- VT_UI8,
- VT_UI8,
- VT_UI8,
- VT_UI8,
- VT_BSTR,
- VT_BSTR,
- VT_BSTR,
- VT_BOOL,
- VT_BOOL,
- VT_BOOL,
- VT_UI8,
- VT_UI8,
- VT_BSTR, // kpidNtReparse
- VT_BSTR,
- VT_UI8,
- VT_UI8,
- VT_BOOL,
- VT_BSTR,
- VT_BSTR
-};
+// PropId.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyWindows.h"
+
+#include "../PropID.h"
+
+// VARTYPE
+const Byte k7z_PROPID_To_VARTYPE[kpid_NUM_DEFINED] =
+{
+ VT_EMPTY,
+ VT_UI4,
+ VT_UI4,
+ VT_BSTR,
+ VT_BSTR,
+ VT_BSTR,
+ VT_BOOL,
+ VT_UI8,
+ VT_UI8,
+ VT_UI4,
+ VT_FILETIME,
+ VT_FILETIME,
+ VT_FILETIME,
+ VT_BOOL,
+ VT_BOOL,
+ VT_BOOL,
+ VT_BOOL,
+ VT_BOOL,
+ VT_UI4,
+ VT_UI4,
+ VT_BSTR,
+ VT_BOOL,
+ VT_BSTR,
+ VT_BSTR,
+ VT_BSTR,
+ VT_BSTR,
+ VT_BSTR,
+ VT_UI8,
+ VT_BSTR,
+ VT_UI8,
+ VT_BSTR,
+ VT_UI8,
+ VT_UI8,
+ VT_BSTR, // or VT_UI8 kpidUnpackVer
+ VT_UI4, // or VT_UI8 kpidVolume
+ VT_BOOL,
+ VT_UI8,
+ VT_UI8,
+ VT_UI8,
+ VT_UI8,
+ VT_UI4,
+ VT_BOOL,
+ VT_BOOL,
+ VT_BSTR,
+ VT_UI8,
+ VT_UI8,
+ VT_UI4, // kpidChecksum
+ VT_BSTR,
+ VT_UI8,
+ VT_BSTR, // or VT_UI8 kpidId
+ VT_BSTR,
+ VT_BSTR,
+ VT_UI4,
+ VT_UI4,
+ VT_BSTR,
+ VT_BSTR,
+ VT_UI8,
+ VT_UI8,
+ VT_UI4,
+ VT_BSTR,
+ VT_BSTR,
+ VT_BSTR,
+ VT_BSTR, // kpidNtSecure
+ VT_BOOL,
+ VT_BOOL,
+ VT_BOOL,
+ VT_BOOL,
+ VT_BSTR, // SHA-1
+ VT_BSTR, // SHA-256
+ VT_BSTR,
+ VT_UI8,
+ VT_UI4,
+ VT_UI4,
+ VT_BSTR,
+ VT_UI8,
+ VT_UI8,
+ VT_UI8,
+ VT_UI8,
+ VT_UI8,
+ VT_UI8,
+ VT_UI8,
+ VT_BSTR,
+ VT_BSTR,
+ VT_BSTR,
+ VT_BOOL,
+ VT_BOOL,
+ VT_BOOL,
+ VT_UI8,
+ VT_UI8,
+ VT_BSTR, // kpidNtReparse
+ VT_BSTR,
+ VT_UI8,
+ VT_UI8,
+ VT_BOOL,
+ VT_BSTR,
+ VT_BSTR,
+ VT_BSTR,
+ VT_BOOL,
+ VT_FILETIME, // kpidChangeTime
+ VT_UI4,
+ VT_UI4,
+ VT_UI4,
+ VT_UI4,
+ VT_UI4,
+ VT_UI4 // kpidDevMinor
+};
diff --git a/CPP/7zip/Common/RegisterArc.h b/CPP/7zip/Common/RegisterArc.h
index 08aa2d4..55c1483 100644
--- a/CPP/7zip/Common/RegisterArc.h
+++ b/CPP/7zip/Common/RegisterArc.h
@@ -1,78 +1,80 @@
-// RegisterArc.h
-
-#ifndef __REGISTER_ARC_H
-#define __REGISTER_ARC_H
-
-#include "../Archive/IArchive.h"
-
-struct CArcInfo
-{
- UInt16 Flags;
- Byte Id;
- Byte SignatureSize;
- UInt16 SignatureOffset;
-
- const Byte *Signature;
- const char *Name;
- const char *Ext;
- const char *AddExt;
-
- Func_CreateInArchive CreateInArchive;
- Func_CreateOutArchive CreateOutArchive;
- Func_IsArc IsArc;
-
- bool IsMultiSignature() const { return (Flags & NArcInfoFlags::kMultiSignature) != 0; }
-};
-
-void RegisterArc(const CArcInfo *arcInfo) throw();
-
-
-#define IMP_CreateArcIn_2(c) \
- static IInArchive *CreateArc() { return new c; }
-
-#define IMP_CreateArcIn IMP_CreateArcIn_2(CHandler())
-
-#ifdef EXTRACT_ONLY
- #define IMP_CreateArcOut
- #define CreateArcOut NULL
-#else
- #define IMP_CreateArcOut static IOutArchive *CreateArcOut() { return new CHandler(); }
-#endif
-
-#define REGISTER_ARC_V(n, e, ae, id, sigSize, sig, offs, flags, crIn, crOut, isArc) \
- static const CArcInfo g_ArcInfo = { flags, id, sigSize, offs, sig, n, e, ae, crIn, crOut, isArc } ; \
-
-#define REGISTER_ARC_R(n, e, ae, id, sigSize, sig, offs, flags, crIn, crOut, isArc) \
- REGISTER_ARC_V(n, e, ae, id, sigSize, sig, offs, flags, crIn, crOut, isArc) \
- struct CRegisterArc { CRegisterArc() { RegisterArc(&g_ArcInfo); }}; \
- static CRegisterArc g_RegisterArc;
-
-
-#define REGISTER_ARC_I_CLS(cls, n, e, ae, id, sig, offs, flags, isArc) \
- IMP_CreateArcIn_2(cls) \
- REGISTER_ARC_R(n, e, ae, id, ARRAY_SIZE(sig), sig, offs, flags, CreateArc, NULL, isArc)
-
-#define REGISTER_ARC_I_CLS_NO_SIG(cls, n, e, ae, id, offs, flags, isArc) \
- IMP_CreateArcIn_2(cls) \
- REGISTER_ARC_R(n, e, ae, id, 0, NULL, offs, flags, CreateArc, NULL, isArc)
-
-#define REGISTER_ARC_I(n, e, ae, id, sig, offs, flags, isArc) \
- REGISTER_ARC_I_CLS(CHandler(), n, e, ae, id, sig, offs, flags, isArc)
-
-#define REGISTER_ARC_I_NO_SIG(n, e, ae, id, offs, flags, isArc) \
- REGISTER_ARC_I_CLS_NO_SIG(CHandler(), n, e, ae, id, offs, flags, isArc)
-
-
-#define REGISTER_ARC_IO(n, e, ae, id, sig, offs, flags, isArc) \
- IMP_CreateArcIn \
- IMP_CreateArcOut \
- REGISTER_ARC_R(n, e, ae, id, ARRAY_SIZE(sig), sig, offs, flags, CreateArc, CreateArcOut, isArc)
-
-#define REGISTER_ARC_IO_DECREMENT_SIG(n, e, ae, id, sig, offs, flags, isArc) \
- IMP_CreateArcIn \
- IMP_CreateArcOut \
- REGISTER_ARC_V(n, e, ae, id, ARRAY_SIZE(sig), sig, offs, flags, CreateArc, CreateArcOut, isArc) \
- struct CRegisterArcDecSig { CRegisterArcDecSig() { sig[0]--; RegisterArc(&g_ArcInfo); }}; \
- static CRegisterArcDecSig g_RegisterArc;
-
-#endif
+// RegisterArc.h
+
+#ifndef ZIP7_INC_REGISTER_ARC_H
+#define ZIP7_INC_REGISTER_ARC_H
+
+#include "../Archive/IArchive.h"
+
+struct CArcInfo
+{
+ UInt32 Flags;
+ Byte Id;
+ Byte SignatureSize;
+ UInt16 SignatureOffset;
+
+ const Byte *Signature;
+ const char *Name;
+ const char *Ext;
+ const char *AddExt;
+
+ UInt32 TimeFlags;
+
+ Func_CreateInArchive CreateInArchive;
+ Func_CreateOutArchive CreateOutArchive;
+ Func_IsArc IsArc;
+
+ bool IsMultiSignature() const { return (Flags & NArcInfoFlags::kMultiSignature) != 0; }
+};
+
+void RegisterArc(const CArcInfo *arcInfo) throw();
+
+
+#define IMP_CreateArcIn_2(c) \
+ static IInArchive *CreateArc() { return new c; }
+
+#define IMP_CreateArcIn IMP_CreateArcIn_2(CHandler())
+
+#ifdef Z7_EXTRACT_ONLY
+ #define IMP_CreateArcOut
+ #define CreateArcOut NULL
+#else
+ #define IMP_CreateArcOut static IOutArchive *CreateArcOut() { return new CHandler(); }
+#endif
+
+#define REGISTER_ARC_V(n, e, ae, id, sigSize, sig, offs, flags, tf, crIn, crOut, isArc) \
+ static const CArcInfo g_ArcInfo = { flags, id, sigSize, offs, sig, n, e, ae, tf, crIn, crOut, isArc } ; \
+
+#define REGISTER_ARC_R(n, e, ae, id, sigSize, sig, offs, flags, tf, crIn, crOut, isArc) \
+ REGISTER_ARC_V (n, e, ae, id, sigSize, sig, offs, flags, tf, crIn, crOut, isArc) \
+ struct CRegisterArc { CRegisterArc() { RegisterArc(&g_ArcInfo); }}; \
+ static CRegisterArc g_RegisterArc;
+
+
+#define REGISTER_ARC_I_CLS(cls, n, e, ae, id, sig, offs, flags, isArc) \
+ IMP_CreateArcIn_2(cls) \
+ REGISTER_ARC_R(n, e, ae, id, Z7_ARRAY_SIZE(sig), sig, offs, flags, 0, CreateArc, NULL, isArc)
+
+#define REGISTER_ARC_I_CLS_NO_SIG(cls, n, e, ae, id, offs, flags, isArc) \
+ IMP_CreateArcIn_2(cls) \
+ REGISTER_ARC_R(n, e, ae, id, 0, NULL, offs, flags, 0, CreateArc, NULL, isArc)
+
+#define REGISTER_ARC_I(n, e, ae, id, sig, offs, flags, isArc) \
+ REGISTER_ARC_I_CLS(CHandler(), n, e, ae, id, sig, offs, flags, isArc)
+
+#define REGISTER_ARC_I_NO_SIG(n, e, ae, id, offs, flags, isArc) \
+ REGISTER_ARC_I_CLS_NO_SIG(CHandler(), n, e, ae, id, offs, flags, isArc)
+
+
+#define REGISTER_ARC_IO(n, e, ae, id, sig, offs, flags, tf, isArc) \
+ IMP_CreateArcIn \
+ IMP_CreateArcOut \
+ REGISTER_ARC_R(n, e, ae, id, Z7_ARRAY_SIZE(sig), sig, offs, flags, tf, CreateArc, CreateArcOut, isArc)
+
+#define REGISTER_ARC_IO_DECREMENT_SIG(n, e, ae, id, sig, offs, flags, tf, isArc) \
+ IMP_CreateArcIn \
+ IMP_CreateArcOut \
+ REGISTER_ARC_V(n, e, ae, id, Z7_ARRAY_SIZE(sig), sig, offs, flags, tf, CreateArc, CreateArcOut, isArc) \
+ struct CRegisterArcDecSig { CRegisterArcDecSig() { sig[0]--; RegisterArc(&g_ArcInfo); }}; \
+ static CRegisterArcDecSig g_RegisterArc;
+
+#endif
diff --git a/CPP/7zip/Common/RegisterCodec.h b/CPP/7zip/Common/RegisterCodec.h
index b566065..cf94998 100644
--- a/CPP/7zip/Common/RegisterCodec.h
+++ b/CPP/7zip/Common/RegisterCodec.h
@@ -1,106 +1,106 @@
-// RegisterCodec.h
-
-#ifndef __REGISTER_CODEC_H
-#define __REGISTER_CODEC_H
-
-#include "../Common/MethodId.h"
-
-#include "../ICoder.h"
-
-typedef void * (*CreateCodecP)();
-
-struct CCodecInfo
-{
- CreateCodecP CreateDecoder;
- CreateCodecP CreateEncoder;
- CMethodId Id;
- const char *Name;
- UInt32 NumStreams;
- bool IsFilter;
-};
-
-void RegisterCodec(const CCodecInfo *codecInfo) throw();
-
-
-#define REGISTER_CODEC_CREATE_2(name, cls, i) static void *name() { return (void *)(i *)(new cls); }
-#define REGISTER_CODEC_CREATE(name, cls) REGISTER_CODEC_CREATE_2(name, cls, ICompressCoder)
-
-#define REGISTER_CODEC_NAME(x) CRegisterCodec ## x
-#define REGISTER_CODEC_VAR static const CCodecInfo g_CodecInfo =
-
-#define REGISTER_CODEC(x) struct REGISTER_CODEC_NAME(x) { \
- REGISTER_CODEC_NAME(x)() { RegisterCodec(&g_CodecInfo); }}; \
- static REGISTER_CODEC_NAME(x) g_RegisterCodec;
-
-
-#define REGISTER_CODECS_NAME(x) CRegisterCodecs ## x
-#define REGISTER_CODECS_VAR static const CCodecInfo g_CodecsInfo[] =
-
-#define REGISTER_CODECS(x) struct REGISTER_CODECS_NAME(x) { \
- REGISTER_CODECS_NAME(x)() { for (unsigned i = 0; i < ARRAY_SIZE(g_CodecsInfo); i++) \
- RegisterCodec(&g_CodecsInfo[i]); }}; \
- static REGISTER_CODECS_NAME(x) g_RegisterCodecs;
-
-
-#define REGISTER_CODEC_2(x, crDec, crEnc, id, name) \
- REGISTER_CODEC_VAR \
- { crDec, crEnc, id, name, 1, false }; \
- REGISTER_CODEC(x)
-
-
-#ifdef EXTRACT_ONLY
- #define REGISTER_CODEC_E(x, clsDec, clsEnc, id, name) \
- REGISTER_CODEC_CREATE(CreateDec, clsDec) \
- REGISTER_CODEC_2(x, CreateDec, NULL, id, name)
-#else
- #define REGISTER_CODEC_E(x, clsDec, clsEnc, id, name) \
- REGISTER_CODEC_CREATE(CreateDec, clsDec) \
- REGISTER_CODEC_CREATE(CreateEnc, clsEnc) \
- REGISTER_CODEC_2(x, CreateDec, CreateEnc, id, name)
-#endif
-
-
-
-#define REGISTER_FILTER_CREATE(name, cls) REGISTER_CODEC_CREATE_2(name, cls, ICompressFilter)
-
-#define REGISTER_FILTER_ITEM(crDec, crEnc, id, name) \
- { crDec, crEnc, id, name, 1, true }
-
-#define REGISTER_FILTER(x, crDec, crEnc, id, name) \
- REGISTER_CODEC_VAR \
- REGISTER_FILTER_ITEM(crDec, crEnc, id, name); \
- REGISTER_CODEC(x)
-
-#ifdef EXTRACT_ONLY
- #define REGISTER_FILTER_E(x, clsDec, clsEnc, id, name) \
- REGISTER_FILTER_CREATE(CreateDec, clsDec) \
- REGISTER_FILTER(x, CreateDec, NULL, id, name)
-#else
- #define REGISTER_FILTER_E(x, clsDec, clsEnc, id, name) \
- REGISTER_FILTER_CREATE(CreateDec, clsDec) \
- REGISTER_FILTER_CREATE(CreateEnc, clsEnc) \
- REGISTER_FILTER(x, CreateDec, CreateEnc, id, name)
-#endif
-
-
-
-struct CHasherInfo
-{
- IHasher * (*CreateHasher)();
- CMethodId Id;
- const char *Name;
- UInt32 DigestSize;
-};
-
-void RegisterHasher(const CHasherInfo *hasher) throw();
-
-#define REGISTER_HASHER_NAME(x) CRegHasher_ ## x
-
-#define REGISTER_HASHER(cls, id, name, size) \
- STDMETHODIMP_(UInt32) cls::GetDigestSize() throw() { return size; } \
- static IHasher *CreateHasherSpec() { return new cls(); } \
- static const CHasherInfo g_HasherInfo = { CreateHasherSpec, id, name, size }; \
- struct REGISTER_HASHER_NAME(cls) { REGISTER_HASHER_NAME(cls)() { RegisterHasher(&g_HasherInfo); }}; \
- static REGISTER_HASHER_NAME(cls) g_RegisterHasher;
-
-#endif
+// RegisterCodec.h
+
+#ifndef ZIP7_INC_REGISTER_CODEC_H
+#define ZIP7_INC_REGISTER_CODEC_H
+
+#include "../Common/MethodId.h"
+
+#include "../ICoder.h"
+
+typedef void * (*CreateCodecP)();
+
+struct CCodecInfo
+{
+ CreateCodecP CreateDecoder;
+ CreateCodecP CreateEncoder;
+ CMethodId Id;
+ const char *Name;
+ UInt32 NumStreams;
+ bool IsFilter;
+};
+
+void RegisterCodec(const CCodecInfo *codecInfo) throw();
+
+
+#define REGISTER_CODEC_CREATE_2(name, cls, i) static void *name() { return (void *)(i *)(new cls); }
+#define REGISTER_CODEC_CREATE(name, cls) REGISTER_CODEC_CREATE_2(name, cls, ICompressCoder)
+
+#define REGISTER_CODEC_NAME(x) CRegisterCodec ## x
+#define REGISTER_CODEC_VAR(x) static const CCodecInfo g_CodecInfo_ ## x =
+
+#define REGISTER_CODEC(x) struct REGISTER_CODEC_NAME(x) { \
+ REGISTER_CODEC_NAME(x)() { RegisterCodec(&g_CodecInfo_ ## x); }}; \
+ static REGISTER_CODEC_NAME(x) g_RegisterCodec_ ## x;
+
+
+#define REGISTER_CODECS_NAME(x) CRegisterCodecs ## x
+#define REGISTER_CODECS_VAR static const CCodecInfo g_CodecsInfo[] =
+
+#define REGISTER_CODECS(x) struct REGISTER_CODECS_NAME(x) { \
+ REGISTER_CODECS_NAME(x)() { for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_CodecsInfo); i++) \
+ RegisterCodec(&g_CodecsInfo[i]); }}; \
+ static REGISTER_CODECS_NAME(x) g_RegisterCodecs;
+
+
+#define REGISTER_CODEC_2(x, crDec, crEnc, id, name) \
+ REGISTER_CODEC_VAR(x) \
+ { crDec, crEnc, id, name, 1, false }; \
+ REGISTER_CODEC(x)
+
+
+#ifdef Z7_EXTRACT_ONLY
+ #define REGISTER_CODEC_E(x, clsDec, clsEnc, id, name) \
+ REGISTER_CODEC_CREATE(CreateDec, clsDec) \
+ REGISTER_CODEC_2(x, CreateDec, NULL, id, name)
+#else
+ #define REGISTER_CODEC_E(x, clsDec, clsEnc, id, name) \
+ REGISTER_CODEC_CREATE(CreateDec, clsDec) \
+ REGISTER_CODEC_CREATE(CreateEnc, clsEnc) \
+ REGISTER_CODEC_2(x, CreateDec, CreateEnc, id, name)
+#endif
+
+
+
+#define REGISTER_FILTER_CREATE(name, cls) REGISTER_CODEC_CREATE_2(name, cls, ICompressFilter)
+
+#define REGISTER_FILTER_ITEM(crDec, crEnc, id, name) \
+ { crDec, crEnc, id, name, 1, true }
+
+#define REGISTER_FILTER(x, crDec, crEnc, id, name) \
+ REGISTER_CODEC_VAR(x) \
+ REGISTER_FILTER_ITEM(crDec, crEnc, id, name); \
+ REGISTER_CODEC(x)
+
+#ifdef Z7_EXTRACT_ONLY
+ #define REGISTER_FILTER_E(x, clsDec, clsEnc, id, name) \
+ REGISTER_FILTER_CREATE(x ## _CreateDec, clsDec) \
+ REGISTER_FILTER(x, x ## _CreateDec, NULL, id, name)
+#else
+ #define REGISTER_FILTER_E(x, clsDec, clsEnc, id, name) \
+ REGISTER_FILTER_CREATE(x ## _CreateDec, clsDec) \
+ REGISTER_FILTER_CREATE(x ## _CreateEnc, clsEnc) \
+ REGISTER_FILTER(x, x ## _CreateDec, x ## _CreateEnc, id, name)
+#endif
+
+
+
+struct CHasherInfo
+{
+ IHasher * (*CreateHasher)();
+ CMethodId Id;
+ const char *Name;
+ UInt32 DigestSize;
+};
+
+void RegisterHasher(const CHasherInfo *hasher) throw();
+
+#define REGISTER_HASHER_NAME(x) CRegHasher_ ## x
+
+#define REGISTER_HASHER(cls, id, name, size) \
+ Z7_COM7F_IMF2(UInt32, cls::GetDigestSize()) { return size; } \
+ static IHasher *CreateHasherSpec() { return new cls(); } \
+ static const CHasherInfo g_HasherInfo = { CreateHasherSpec, id, name, size }; \
+ struct REGISTER_HASHER_NAME(cls) { REGISTER_HASHER_NAME(cls)() { RegisterHasher(&g_HasherInfo); }}; \
+ static REGISTER_HASHER_NAME(cls) g_RegisterHasher;
+
+#endif
diff --git a/CPP/7zip/Common/StdAfx.h b/CPP/7zip/Common/StdAfx.h
index 42a088f..8086655 100644
--- a/CPP/7zip/Common/StdAfx.h
+++ b/CPP/7zip/Common/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "../../Common/Common.h"
-
-#endif
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Common/StreamBinder.cpp b/CPP/7zip/Common/StreamBinder.cpp
index a6627db..38334af 100644
--- a/CPP/7zip/Common/StreamBinder.cpp
+++ b/CPP/7zip/Common/StreamBinder.cpp
@@ -1,156 +1,151 @@
-// StreamBinder.cpp
-
-#include "StdAfx.h"
-
-#include "../../Common/MyCom.h"
-
-#include "StreamBinder.h"
-
-class CBinderInStream:
- public ISequentialInStream,
- public CMyUnknownImp
-{
- CStreamBinder *_binder;
-public:
- MY_UNKNOWN_IMP1(ISequentialInStream)
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- ~CBinderInStream() { _binder->CloseRead(); }
- CBinderInStream(CStreamBinder *binder): _binder(binder) {}
-};
-
-STDMETHODIMP CBinderInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
- { return _binder->Read(data, size, processedSize); }
-
-class CBinderOutStream:
- public ISequentialOutStream,
- public CMyUnknownImp
-{
- CStreamBinder *_binder;
-public:
- MY_UNKNOWN_IMP1(ISequentialOutStream)
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
- ~CBinderOutStream() { _binder->CloseWrite(); }
- CBinderOutStream(CStreamBinder *binder): _binder(binder) {}
-};
-
-STDMETHODIMP CBinderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
- { return _binder->Write(data, size, processedSize); }
-
-
-
-WRes CStreamBinder::CreateEvents()
-{
- RINOK(_canWrite_Event.Create());
- RINOK(_canRead_Event.Create());
- return _readingWasClosed_Event.Create();
-}
-
-void CStreamBinder::ReInit()
-{
- _canWrite_Event.Reset();
- _canRead_Event.Reset();
- _readingWasClosed_Event.Reset();
-
- // _readingWasClosed = false;
- _readingWasClosed2 = false;
-
- _waitWrite = true;
- _bufSize = 0;
- _buf = NULL;
- ProcessedSize = 0;
- // WritingWasCut = false;
-}
-
-
-void CStreamBinder::CreateStreams(ISequentialInStream **inStream, ISequentialOutStream **outStream)
-{
- // _readingWasClosed = false;
- _readingWasClosed2 = false;
-
- _waitWrite = true;
- _bufSize = 0;
- _buf = NULL;
- ProcessedSize = 0;
- // WritingWasCut = false;
-
- CBinderInStream *inStreamSpec = new CBinderInStream(this);
- CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
- *inStream = inStreamLoc.Detach();
-
- CBinderOutStream *outStreamSpec = new CBinderOutStream(this);
- CMyComPtr<ISequentialOutStream> outStreamLoc(outStreamSpec);
- *outStream = outStreamLoc.Detach();
-}
-
-// (_canRead_Event && _bufSize == 0) means that stream is finished.
-
-HRESULT CStreamBinder::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
- if (size != 0)
- {
- if (_waitWrite)
- {
- RINOK(_canRead_Event.Lock());
- _waitWrite = false;
- }
- if (size > _bufSize)
- size = _bufSize;
- if (size != 0)
- {
- memcpy(data, _buf, size);
- _buf = ((const Byte *)_buf) + size;
- ProcessedSize += size;
- if (processedSize)
- *processedSize = size;
- _bufSize -= size;
- if (_bufSize == 0)
- {
- _waitWrite = true;
- _canRead_Event.Reset();
- _canWrite_Event.Set();
- }
- }
- }
- return S_OK;
-}
-
-HRESULT CStreamBinder::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
- if (size == 0)
- return S_OK;
-
- if (!_readingWasClosed2)
- {
- _buf = data;
- _bufSize = size;
- _canRead_Event.Set();
-
- /*
- _canWrite_Event.Lock();
- if (_readingWasClosed)
- _readingWasClosed2 = true;
- */
-
- HANDLE events[2] = { _canWrite_Event, _readingWasClosed_Event };
- DWORD waitResult = ::WaitForMultipleObjects(2, events, FALSE, INFINITE);
- if (waitResult >= WAIT_OBJECT_0 + 2)
- return E_FAIL;
-
- size -= _bufSize;
- if (size != 0)
- {
- if (processedSize)
- *processedSize = size;
- return S_OK;
- }
- // if (waitResult == WAIT_OBJECT_0 + 1)
- _readingWasClosed2 = true;
- }
-
- // WritingWasCut = true;
- return k_My_HRESULT_WritingWasCut;
-}
+// StreamBinder.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyCom.h"
+
+#include "StreamBinder.h"
+
+Z7_CLASS_IMP_COM_1(
+ CBinderInStream
+ , ISequentialInStream
+)
+ CStreamBinder *_binder;
+public:
+ ~CBinderInStream() { _binder->CloseRead_CallOnce(); }
+ CBinderInStream(CStreamBinder *binder): _binder(binder) {}
+};
+
+Z7_COM7F_IMF(CBinderInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+ { return _binder->Read(data, size, processedSize); }
+
+
+Z7_CLASS_IMP_COM_1(
+ CBinderOutStream
+ , ISequentialOutStream
+)
+ CStreamBinder *_binder;
+public:
+ ~CBinderOutStream() { _binder->CloseWrite(); }
+ CBinderOutStream(CStreamBinder *binder): _binder(binder) {}
+};
+
+Z7_COM7F_IMF(CBinderOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+ { return _binder->Write(data, size, processedSize); }
+
+
+static HRESULT Event_Create_or_Reset(NWindows::NSynchronization::CAutoResetEvent &event)
+{
+ const WRes wres = event.CreateIfNotCreated_Reset();
+ return HRESULT_FROM_WIN32(wres);
+}
+
+HRESULT CStreamBinder::Create_ReInit()
+{
+ RINOK(Event_Create_or_Reset(_canRead_Event))
+ // RINOK(Event_Create_or_Reset(_canWrite_Event))
+
+ // _canWrite_Semaphore.Close();
+ // we need at least 3 items of maxCount: 1 for normal unlock in Read(), 2 items for unlock in CloseRead_CallOnce()
+ _canWrite_Semaphore.OptCreateInit(0, 3);
+
+ // _readingWasClosed = false;
+ _readingWasClosed2 = false;
+
+ _waitWrite = true;
+ _bufSize = 0;
+ _buf = NULL;
+ ProcessedSize = 0;
+ // WritingWasCut = false;
+ return S_OK;
+}
+
+
+void CStreamBinder::CreateStreams2(CMyComPtr<ISequentialInStream> &inStream, CMyComPtr<ISequentialOutStream> &outStream)
+{
+ inStream = new CBinderInStream(this);
+ outStream = new CBinderOutStream(this);
+}
+
+// (_canRead_Event && _bufSize == 0) means that stream is finished.
+
+HRESULT CStreamBinder::Read(void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size != 0)
+ {
+ if (_waitWrite)
+ {
+ WRes wres = _canRead_Event.Lock();
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ _waitWrite = false;
+ }
+ if (size > _bufSize)
+ size = _bufSize;
+ if (size != 0)
+ {
+ memcpy(data, _buf, size);
+ _buf = ((const Byte *)_buf) + size;
+ ProcessedSize += size;
+ if (processedSize)
+ *processedSize = size;
+ _bufSize -= size;
+
+ /*
+ if (_bufSize == 0), then we have read whole buffer
+ we have two ways here:
+ - if we check (_bufSize == 0) here, we unlock Write only after full data Reading - it reduces the number of syncs
+ - if we don't check (_bufSize == 0) here, we unlock Write after partial data Reading
+ */
+ if (_bufSize == 0)
+ {
+ _waitWrite = true;
+ // _canWrite_Event.Set();
+ _canWrite_Semaphore.Release();
+ }
+ }
+ }
+ return S_OK;
+}
+
+
+HRESULT CStreamBinder::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+
+ if (!_readingWasClosed2)
+ {
+ _buf = data;
+ _bufSize = size;
+ _canRead_Event.Set();
+
+ /*
+ _canWrite_Event.Lock();
+ if (_readingWasClosed)
+ _readingWasClosed2 = true;
+ */
+
+ _canWrite_Semaphore.Lock();
+
+ // _bufSize : is remain size that was not read
+ size -= _bufSize;
+
+ // size : is size of data that was read
+ if (size != 0)
+ {
+ // if some data was read, then we report that size and return
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+ }
+ _readingWasClosed2 = true;
+ }
+
+ // WritingWasCut = true;
+ return k_My_HRESULT_WritingWasCut;
+}
diff --git a/CPP/7zip/Common/StreamBinder.h b/CPP/7zip/Common/StreamBinder.h
index f4d4f3b..c0a7079 100644
--- a/CPP/7zip/Common/StreamBinder.h
+++ b/CPP/7zip/Common/StreamBinder.h
@@ -1,60 +1,78 @@
-// StreamBinder.h
-
-#ifndef __STREAM_BINDER_H
-#define __STREAM_BINDER_H
-
-#include "../../Windows/Synchronization.h"
-
-#include "../IStream.h"
-
-/*
-We don't use probably UNSAFE version:
-reader thread:
- _canWrite_Event.Set();
- _readingWasClosed = true
- _canWrite_Event.Set();
-writer thread:
- _canWrite_Event.Wait()
- if (_readingWasClosed)
-Can second call of _canWrite_Event.Set() be executed without memory barrier, if event is already set?
-*/
-
-class CStreamBinder
-{
- NWindows::NSynchronization::CAutoResetEvent _canWrite_Event;
- NWindows::NSynchronization::CManualResetEvent _canRead_Event;
- NWindows::NSynchronization::CManualResetEvent _readingWasClosed_Event;
-
- // bool _readingWasClosed;
- bool _readingWasClosed2;
- // bool WritingWasCut;
- bool _waitWrite;
- UInt32 _bufSize;
- const void *_buf;
-public:
- UInt64 ProcessedSize;
-
- WRes CreateEvents();
- void CreateStreams(ISequentialInStream **inStream, ISequentialOutStream **outStream);
-
- void ReInit();
-
- HRESULT Read(void *data, UInt32 size, UInt32 *processedSize);
- HRESULT Write(const void *data, UInt32 size, UInt32 *processedSize);
-
- void CloseRead()
- {
- _readingWasClosed_Event.Set();
- // _readingWasClosed = true;
- // _canWrite_Event.Set();
- }
-
- void CloseWrite()
- {
- _buf = NULL;
- _bufSize = 0;
- _canRead_Event.Set();
- }
-};
-
-#endif
+// StreamBinder.h
+
+#ifndef ZIP7_INC_STREAM_BINDER_H
+#define ZIP7_INC_STREAM_BINDER_H
+
+#include "../../Windows/Synchronization.h"
+
+#include "../IStream.h"
+
+/*
+We can use one from two code versions here: with Event or with Semaphore to unlock Writer thread
+The difference for cases where Reading must be closed before Writing closing
+
+1) Event Version: _canWrite_Event
+ We call _canWrite_Event.Set() without waiting _canRead_Event in CloseRead() function.
+ The writer thread can get (_readingWasClosed) status in one from two iterations.
+ It's ambiguity of processing flow. But probably it's SAFE to use, if Event functions provide memory barriers.
+ reader thread:
+ _canWrite_Event.Set();
+ _readingWasClosed = true;
+ _canWrite_Event.Set();
+ writer thread:
+ _canWrite_Event.Wait()
+ if (_readingWasClosed)
+
+2) Semaphore Version: _canWrite_Semaphore
+ writer thread always will detect closing of reading in latest iteration after all data processing iterations
+*/
+
+class CStreamBinder
+{
+ NWindows::NSynchronization::CAutoResetEvent _canRead_Event;
+ // NWindows::NSynchronization::CAutoResetEvent _canWrite_Event;
+ NWindows::NSynchronization::CSemaphore _canWrite_Semaphore;
+
+ // bool _readingWasClosed; // set it in reader thread and check it in write thread
+ bool _readingWasClosed2; // use it in writer thread
+ // bool WritingWasCut;
+ bool _waitWrite; // use it in reader thread
+ UInt32 _bufSize;
+ const void *_buf;
+public:
+ UInt64 ProcessedSize; // the size that was read by reader thread
+
+ void CreateStreams2(CMyComPtr<ISequentialInStream> &inStream, CMyComPtr<ISequentialOutStream> &outStream);
+
+ HRESULT Create_ReInit();
+
+ HRESULT Read(void *data, UInt32 size, UInt32 *processedSize);
+ HRESULT Write(const void *data, UInt32 size, UInt32 *processedSize);
+
+ void CloseRead_CallOnce()
+ {
+ // call it only once: for example, in destructor
+
+ /*
+ _readingWasClosed = true;
+ _canWrite_Event.Set();
+ */
+
+ /*
+ We must relase Semaphore only once !!!
+ we must release at least 2 items of Semaphore:
+ one item to unlock partial Write(), if Read() have read some items
+ then additional item to stop writing (_bufSize will be 0)
+ */
+ _canWrite_Semaphore.Release(2);
+ }
+
+ void CloseWrite()
+ {
+ _buf = NULL;
+ _bufSize = 0;
+ _canRead_Event.Set();
+ }
+};
+
+#endif
diff --git a/CPP/7zip/Common/StreamObjects.cpp b/CPP/7zip/Common/StreamObjects.cpp
index 4cd9cc6..b54f423 100644
--- a/CPP/7zip/Common/StreamObjects.cpp
+++ b/CPP/7zip/Common/StreamObjects.cpp
@@ -1,285 +1,290 @@
-// StreamObjects.cpp
-
-#include "StdAfx.h"
-
-#include <stdlib.h>
-
-#include "../../../C/Alloc.h"
-
-#include "StreamObjects.h"
-
-STDMETHODIMP CBufferInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
- if (size == 0)
- return S_OK;
- if (_pos >= Buf.Size())
- return S_OK;
- size_t rem = Buf.Size() - (size_t)_pos;
- if (rem > size)
- rem = (size_t)size;
- memcpy(data, (const Byte *)Buf + (size_t)_pos, rem);
- _pos += rem;
- if (processedSize)
- *processedSize = (UInt32)rem;
- return S_OK;
-}
-
-STDMETHODIMP CBufferInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- switch (seekOrigin)
- {
- case STREAM_SEEK_SET: break;
- case STREAM_SEEK_CUR: offset += _pos; break;
- case STREAM_SEEK_END: offset += Buf.Size(); break;
- default: return STG_E_INVALIDFUNCTION;
- }
- if (offset < 0)
- return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
- _pos = offset;
- if (newPosition)
- *newPosition = offset;
- return S_OK;
-}
-
-STDMETHODIMP CBufInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
- if (size == 0)
- return S_OK;
- if (_pos >= _size)
- return S_OK;
- size_t rem = _size - (size_t)_pos;
- if (rem > size)
- rem = (size_t)size;
- memcpy(data, _data + (size_t)_pos, rem);
- _pos += rem;
- if (processedSize)
- *processedSize = (UInt32)rem;
- return S_OK;
-}
-
-STDMETHODIMP CBufInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- switch (seekOrigin)
- {
- case STREAM_SEEK_SET: break;
- case STREAM_SEEK_CUR: offset += _pos; break;
- case STREAM_SEEK_END: offset += _size; break;
- default: return STG_E_INVALIDFUNCTION;
- }
- if (offset < 0)
- return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
- _pos = offset;
- if (newPosition)
- *newPosition = offset;
- return S_OK;
-}
-
-void Create_BufInStream_WithReference(const void *data, size_t size, IUnknown *ref, ISequentialInStream **stream)
-{
- *stream = NULL;
- CBufInStream *inStreamSpec = new CBufInStream;
- CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec;
- inStreamSpec->Init((const Byte *)data, size, ref);
- *stream = streamTemp.Detach();
-}
-
-void Create_BufInStream_WithNewBuffer(const void *data, size_t size, ISequentialInStream **stream)
-{
- *stream = NULL;
- CBufferInStream *inStreamSpec = new CBufferInStream;
- CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec;
- inStreamSpec->Buf.CopyFrom((const Byte *)data, size);
- inStreamSpec->Init();
- *stream = streamTemp.Detach();
-}
-
-void CByteDynBuffer::Free() throw()
-{
- free(_buf);
- _buf = 0;
- _capacity = 0;
-}
-
-bool CByteDynBuffer::EnsureCapacity(size_t cap) throw()
-{
- if (cap <= _capacity)
- return true;
- size_t delta;
- if (_capacity > 64)
- delta = _capacity / 4;
- else if (_capacity > 8)
- delta = 16;
- else
- delta = 4;
- cap = MyMax(_capacity + delta, cap);
- Byte *buf = (Byte *)realloc(_buf, cap);
- if (!buf)
- return false;
- _buf = buf;
- _capacity = cap;
- return true;
-}
-
-Byte *CDynBufSeqOutStream::GetBufPtrForWriting(size_t addSize)
-{
- addSize += _size;
- if (addSize < _size)
- return NULL;
- if (!_buffer.EnsureCapacity(addSize))
- return NULL;
- return (Byte *)_buffer + _size;
-}
-
-void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const
-{
- dest.CopyFrom((const Byte *)_buffer, _size);
-}
-
-STDMETHODIMP CDynBufSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
- if (size == 0)
- return S_OK;
- Byte *buf = GetBufPtrForWriting(size);
- if (!buf)
- return E_OUTOFMEMORY;
- memcpy(buf, data, size);
- UpdateSize(size);
- if (processedSize)
- *processedSize = size;
- return S_OK;
-}
-
-STDMETHODIMP CBufPtrSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- size_t rem = _size - _pos;
- if (rem > size)
- rem = (size_t)size;
- if (rem != 0)
- {
- memcpy(_buffer + _pos, data, rem);
- _pos += rem;
- }
- if (processedSize)
- *processedSize = (UInt32)rem;
- return (rem != 0 || size == 0) ? S_OK : E_FAIL;
-}
-
-STDMETHODIMP CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- UInt32 realProcessedSize;
- HRESULT result = _stream->Write(data, size, &realProcessedSize);
- _size += realProcessedSize;
- if (processedSize)
- *processedSize = realProcessedSize;
- return result;
-}
-
-static const UInt64 kEmptyTag = (UInt64)(Int64)-1;
-
-void CCachedInStream::Free() throw()
-{
- MyFree(_tags);
- _tags = 0;
- MidFree(_data);
- _data = 0;
-}
-
-bool CCachedInStream::Alloc(unsigned blockSizeLog, unsigned numBlocksLog) throw()
-{
- unsigned sizeLog = blockSizeLog + numBlocksLog;
- if (sizeLog >= sizeof(size_t) * 8)
- return false;
- size_t dataSize = (size_t)1 << sizeLog;
- if (_data == 0 || dataSize != _dataSize)
- {
- MidFree(_data);
- _data = (Byte *)MidAlloc(dataSize);
- if (_data == 0)
- return false;
- _dataSize = dataSize;
- }
- if (_tags == 0 || numBlocksLog != _numBlocksLog)
- {
- MyFree(_tags);
- _tags = (UInt64 *)MyAlloc(sizeof(UInt64) << numBlocksLog);
- if (_tags == 0)
- return false;
- _numBlocksLog = numBlocksLog;
- }
- _blockSizeLog = blockSizeLog;
- return true;
-}
-
-void CCachedInStream::Init(UInt64 size) throw()
-{
- _size = size;
- _pos = 0;
- size_t numBlocks = (size_t)1 << _numBlocksLog;
- for (size_t i = 0; i < numBlocks; i++)
- _tags[i] = kEmptyTag;
-}
-
-STDMETHODIMP CCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
- if (size == 0)
- return S_OK;
- if (_pos >= _size)
- return S_OK;
-
- {
- UInt64 rem = _size - _pos;
- if (size > rem)
- size = (UInt32)rem;
- }
-
- while (size != 0)
- {
- UInt64 cacheTag = _pos >> _blockSizeLog;
- size_t cacheIndex = (size_t)cacheTag & (((size_t)1 << _numBlocksLog) - 1);
- Byte *p = _data + (cacheIndex << _blockSizeLog);
- if (_tags[cacheIndex] != cacheTag)
- {
- UInt64 remInBlock = _size - (cacheTag << _blockSizeLog);
- size_t blockSize = (size_t)1 << _blockSizeLog;
- if (blockSize > remInBlock)
- blockSize = (size_t)remInBlock;
- RINOK(ReadBlock(cacheTag, p, blockSize));
- _tags[cacheIndex] = cacheTag;
- }
- size_t offset = (size_t)_pos & (((size_t)1 << _blockSizeLog) - 1);
- UInt32 cur = (UInt32)MyMin(((size_t)1 << _blockSizeLog) - offset, (size_t)size);
- memcpy(data, p + offset, cur);
- if (processedSize)
- *processedSize += cur;
- data = (void *)((const Byte *)data + cur);
- _pos += cur;
- size -= cur;
- }
-
- return S_OK;
-}
-
-STDMETHODIMP CCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- switch (seekOrigin)
- {
- case STREAM_SEEK_SET: break;
- case STREAM_SEEK_CUR: offset += _pos; break;
- case STREAM_SEEK_END: offset += _size; break;
- default: return STG_E_INVALIDFUNCTION;
- }
- if (offset < 0)
- return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
- _pos = offset;
- if (newPosition)
- *newPosition = offset;
- return S_OK;
-}
+// StreamObjects.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "StreamObjects.h"
+
+Z7_COM7F_IMF(CBufferInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ if (_pos >= Buf.Size())
+ return S_OK;
+ size_t rem = Buf.Size() - (size_t)_pos;
+ if (rem > size)
+ rem = (size_t)size;
+ memcpy(data, (const Byte *)Buf + (size_t)_pos, rem);
+ _pos += rem;
+ if (processedSize)
+ *processedSize = (UInt32)rem;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CBufferInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _pos; break;
+ case STREAM_SEEK_END: offset += Buf.Size(); break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _pos = (UInt64)offset;
+ if (newPosition)
+ *newPosition = (UInt64)offset;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CBufInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ if (_pos >= _size)
+ return S_OK;
+ size_t rem = _size - (size_t)_pos;
+ if (rem > size)
+ rem = (size_t)size;
+ memcpy(data, _data + (size_t)_pos, rem);
+ _pos += rem;
+ if (processedSize)
+ *processedSize = (UInt32)rem;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CBufInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _pos; break;
+ case STREAM_SEEK_END: offset += _size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _pos = (UInt64)offset;
+ if (newPosition)
+ *newPosition = (UInt64)offset;
+ return S_OK;
+}
+
+void Create_BufInStream_WithReference(const void *data, size_t size, IUnknown *ref, ISequentialInStream **stream)
+{
+ *stream = NULL;
+ CBufInStream *inStreamSpec = new CBufInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec;
+ inStreamSpec->Init((const Byte *)data, size, ref);
+ *stream = streamTemp.Detach();
+}
+
+void Create_BufInStream_WithNewBuffer(const void *data, size_t size, ISequentialInStream **stream)
+{
+ *stream = NULL;
+ CBufferInStream *inStreamSpec = new CBufferInStream;
+ CMyComPtr<ISequentialInStream> streamTemp = inStreamSpec;
+ inStreamSpec->Buf.CopyFrom((const Byte *)data, size);
+ inStreamSpec->Init();
+ *stream = streamTemp.Detach();
+}
+
+void CByteDynBuffer::Free() throw()
+{
+ MyFree(_buf);
+ _buf = NULL;
+ _capacity = 0;
+}
+
+bool CByteDynBuffer::EnsureCapacity(size_t cap) throw()
+{
+ if (cap <= _capacity)
+ return true;
+ const size_t cap2 = _capacity + _capacity / 4;
+ if (cap < cap2)
+ cap = cap2;
+ Byte *buf = (Byte *)MyRealloc(_buf, cap);
+ if (!buf)
+ return false;
+ _buf = buf;
+ _capacity = cap;
+ return true;
+}
+
+Byte *CDynBufSeqOutStream::GetBufPtrForWriting(size_t addSize)
+{
+ addSize += _size;
+ if (addSize < _size)
+ return NULL;
+ if (!_buffer.EnsureCapacity(addSize))
+ return NULL;
+ return (Byte *)_buffer + _size;
+}
+
+void CDynBufSeqOutStream::CopyToBuffer(CByteBuffer &dest) const
+{
+ dest.CopyFrom((const Byte *)_buffer, _size);
+}
+
+Z7_COM7F_IMF(CDynBufSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ Byte *buf = GetBufPtrForWriting(size);
+ if (!buf)
+ return E_OUTOFMEMORY;
+ memcpy(buf, data, size);
+ UpdateSize(size);
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CBufPtrSeqOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ size_t rem = _size - _pos;
+ if (rem > size)
+ rem = (size_t)size;
+ if (rem != 0)
+ {
+ memcpy(_buffer + _pos, data, rem);
+ _pos += rem;
+ }
+ if (processedSize)
+ *processedSize = (UInt32)rem;
+ return (rem != 0 || size == 0) ? S_OK : E_FAIL;
+}
+
+Z7_COM7F_IMF(CSequentialOutStreamSizeCount::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ UInt32 realProcessedSize;
+ HRESULT result = _stream->Write(data, size, &realProcessedSize);
+ _size += realProcessedSize;
+ if (processedSize)
+ *processedSize = realProcessedSize;
+ return result;
+}
+
+static const UInt64 kEmptyTag = (UInt64)(Int64)-1;
+
+void CCachedInStream::Free() throw()
+{
+ MyFree(_tags);
+ _tags = NULL;
+ MidFree(_data);
+ _data = NULL;
+}
+
+bool CCachedInStream::Alloc(unsigned blockSizeLog, unsigned numBlocksLog) throw()
+{
+ unsigned sizeLog = blockSizeLog + numBlocksLog;
+ if (sizeLog >= sizeof(size_t) * 8)
+ return false;
+ size_t dataSize = (size_t)1 << sizeLog;
+ if (!_data || dataSize != _dataSize)
+ {
+ MidFree(_data);
+ _data = (Byte *)MidAlloc(dataSize);
+ if (!_data)
+ return false;
+ _dataSize = dataSize;
+ }
+ if (!_tags || numBlocksLog != _numBlocksLog)
+ {
+ MyFree(_tags);
+ _tags = (UInt64 *)MyAlloc(sizeof(UInt64) << numBlocksLog);
+ if (!_tags)
+ return false;
+ _numBlocksLog = numBlocksLog;
+ }
+ _blockSizeLog = blockSizeLog;
+ return true;
+}
+
+void CCachedInStream::Init(UInt64 size) throw()
+{
+ _size = size;
+ _pos = 0;
+ const size_t numBlocks = (size_t)1 << _numBlocksLog;
+ for (size_t i = 0; i < numBlocks; i++)
+ _tags[i] = kEmptyTag;
+}
+
+Z7_COM7F_IMF(CCachedInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ if (_pos >= _size)
+ return S_OK;
+
+ {
+ const UInt64 rem = _size - _pos;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ while (size != 0)
+ {
+ const UInt64 cacheTag = _pos >> _blockSizeLog;
+ const size_t cacheIndex = (size_t)cacheTag & (((size_t)1 << _numBlocksLog) - 1);
+ Byte *p = _data + (cacheIndex << _blockSizeLog);
+
+ if (_tags[cacheIndex] != cacheTag)
+ {
+ _tags[cacheIndex] = kEmptyTag;
+ const UInt64 remInBlock = _size - (cacheTag << _blockSizeLog);
+ size_t blockSize = (size_t)1 << _blockSizeLog;
+ if (blockSize > remInBlock)
+ blockSize = (size_t)remInBlock;
+
+ RINOK(ReadBlock(cacheTag, p, blockSize))
+
+ _tags[cacheIndex] = cacheTag;
+ }
+
+ const size_t kBlockSize = (size_t)1 << _blockSizeLog;
+ const size_t offset = (size_t)_pos & (kBlockSize - 1);
+ UInt32 cur = size;
+ const size_t rem = kBlockSize - offset;
+ if (cur > rem)
+ cur = (UInt32)rem;
+
+ memcpy(data, p + offset, cur);
+
+ if (processedSize)
+ *processedSize += cur;
+ data = (void *)((const Byte *)data + cur);
+ _pos += cur;
+ size -= cur;
+ }
+
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CCachedInStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ switch (seekOrigin)
+ {
+ case STREAM_SEEK_SET: break;
+ case STREAM_SEEK_CUR: offset += _pos; break;
+ case STREAM_SEEK_END: offset += _size; break;
+ default: return STG_E_INVALIDFUNCTION;
+ }
+ if (offset < 0)
+ return HRESULT_WIN32_ERROR_NEGATIVE_SEEK;
+ _pos = (UInt64)offset;
+ if (newPosition)
+ *newPosition = (UInt64)offset;
+ return S_OK;
+}
diff --git a/CPP/7zip/Common/StreamObjects.h b/CPP/7zip/Common/StreamObjects.h
index c3e0837..2c0ebea 100644
--- a/CPP/7zip/Common/StreamObjects.h
+++ b/CPP/7zip/Common/StreamObjects.h
@@ -1,157 +1,146 @@
-// StreamObjects.h
-
-#ifndef __STREAM_OBJECTS_H
-#define __STREAM_OBJECTS_H
-
-#include "../../Common/MyBuffer.h"
-#include "../../Common/MyCom.h"
-#include "../../Common/MyVector.h"
-
-#include "../IStream.h"
-
-class CBufferInStream:
- public IInStream,
- public CMyUnknownImp
-{
- UInt64 _pos;
-public:
- CByteBuffer Buf;
- void Init() { _pos = 0; }
-
- MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
-};
-
-struct CReferenceBuf:
- public IUnknown,
- public CMyUnknownImp
-{
- CByteBuffer Buf;
- MY_UNKNOWN_IMP
-};
-
-class CBufInStream:
- public IInStream,
- public CMyUnknownImp
-{
- const Byte *_data;
- UInt64 _pos;
- size_t _size;
- CMyComPtr<IUnknown> _ref;
-public:
- void Init(const Byte *data, size_t size, IUnknown *ref = 0)
- {
- _data = data;
- _size = size;
- _pos = 0;
- _ref = ref;
- }
- void Init(CReferenceBuf *ref) { Init(ref->Buf, ref->Buf.Size(), ref); }
-
- MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
-};
-
-void Create_BufInStream_WithReference(const void *data, size_t size, IUnknown *ref, ISequentialInStream **stream);
-void Create_BufInStream_WithNewBuffer(const void *data, size_t size, ISequentialInStream **stream);
-inline void Create_BufInStream_WithNewBuffer(const CByteBuffer &buf, ISequentialInStream **stream)
- { Create_BufInStream_WithNewBuffer(buf, buf.Size(), stream); }
-
-class CByteDynBuffer
-{
- size_t _capacity;
- Byte *_buf;
-public:
- CByteDynBuffer(): _capacity(0), _buf(0) {};
- // there is no copy constructor. So don't copy this object.
- ~CByteDynBuffer() { Free(); }
- void Free() throw();
- size_t GetCapacity() const { return _capacity; }
- operator Byte*() const { return _buf; }
- operator const Byte*() const { return _buf; }
- bool EnsureCapacity(size_t capacity) throw();
-};
-
-class CDynBufSeqOutStream:
- public ISequentialOutStream,
- public CMyUnknownImp
-{
- CByteDynBuffer _buffer;
- size_t _size;
-public:
- CDynBufSeqOutStream(): _size(0) {}
- void Init() { _size = 0; }
- size_t GetSize() const { return _size; }
- const Byte *GetBuffer() const { return _buffer; }
- void CopyToBuffer(CByteBuffer &dest) const;
- Byte *GetBufPtrForWriting(size_t addSize);
- void UpdateSize(size_t addSize) { _size += addSize; }
-
- MY_UNKNOWN_IMP1(ISequentialOutStream)
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
-};
-
-class CBufPtrSeqOutStream:
- public ISequentialOutStream,
- public CMyUnknownImp
-{
- Byte *_buffer;
- size_t _size;
- size_t _pos;
-public:
- void Init(Byte *buffer, size_t size)
- {
- _buffer = buffer;
- _pos = 0;
- _size = size;
- }
- size_t GetPos() const { return _pos; }
-
- MY_UNKNOWN_IMP1(ISequentialOutStream)
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
-};
-
-class CSequentialOutStreamSizeCount:
- public ISequentialOutStream,
- public CMyUnknownImp
-{
- CMyComPtr<ISequentialOutStream> _stream;
- UInt64 _size;
-public:
- void SetStream(ISequentialOutStream *stream) { _stream = stream; }
- void Init() { _size = 0; }
- UInt64 GetSize() const { return _size; }
-
- MY_UNKNOWN_IMP1(ISequentialOutStream)
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
-};
-
-class CCachedInStream:
- public IInStream,
- public CMyUnknownImp
-{
- UInt64 *_tags;
- Byte *_data;
- size_t _dataSize;
- unsigned _blockSizeLog;
- unsigned _numBlocksLog;
- UInt64 _size;
- UInt64 _pos;
-protected:
- virtual HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) = 0;
-public:
- CCachedInStream(): _tags(0), _data(0) {}
- virtual ~CCachedInStream() { Free(); } // the destructor must be virtual (release calls it) !!!
- void Free() throw();
- bool Alloc(unsigned blockSizeLog, unsigned numBlocksLog) throw();
- void Init(UInt64 size) throw();
-
- MY_UNKNOWN_IMP2(ISequentialInStream, IInStream)
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
-};
-
-#endif
+// StreamObjects.h
+
+#ifndef ZIP7_INC_STREAM_OBJECTS_H
+#define ZIP7_INC_STREAM_OBJECTS_H
+
+#include "../../Common/MyBuffer.h"
+#include "../../Common/MyCom.h"
+#include "../../Common/MyVector.h"
+
+#include "../IStream.h"
+
+Z7_CLASS_IMP_IInStream(
+ CBufferInStream
+)
+ UInt64 _pos;
+public:
+ CByteBuffer Buf;
+ void Init() { _pos = 0; }
+};
+
+
+Z7_CLASS_IMP_COM_0(
+ CReferenceBuf
+)
+public:
+ CByteBuffer Buf;
+};
+
+
+Z7_CLASS_IMP_IInStream(
+ CBufInStream
+)
+ const Byte *_data;
+ UInt64 _pos;
+ size_t _size;
+ CMyComPtr<IUnknown> _ref;
+public:
+ void Init(const Byte *data, size_t size, IUnknown *ref = NULL)
+ {
+ _data = data;
+ _size = size;
+ _pos = 0;
+ _ref = ref;
+ }
+ void Init(CReferenceBuf *ref) { Init(ref->Buf, ref->Buf.Size(), ref); }
+
+ // Seek() is allowed here. So reading order could be changed
+ bool WasFinished() const { return _pos == _size; }
+};
+
+
+void Create_BufInStream_WithReference(const void *data, size_t size, IUnknown *ref, ISequentialInStream **stream);
+void Create_BufInStream_WithNewBuffer(const void *data, size_t size, ISequentialInStream **stream);
+inline void Create_BufInStream_WithNewBuffer(const CByteBuffer &buf, ISequentialInStream **stream)
+ { Create_BufInStream_WithNewBuffer(buf, buf.Size(), stream); }
+
+
+class CByteDynBuffer Z7_final
+{
+ size_t _capacity;
+ Byte *_buf;
+ Z7_CLASS_NO_COPY(CByteDynBuffer)
+public:
+ CByteDynBuffer(): _capacity(0), _buf(NULL) {}
+ // there is no copy constructor. So don't copy this object.
+ ~CByteDynBuffer() { Free(); }
+ void Free() throw();
+ size_t GetCapacity() const { return _capacity; }
+ operator Byte*() const { return _buf; }
+ operator const Byte*() const { return _buf; }
+ bool EnsureCapacity(size_t capacity) throw();
+};
+
+
+Z7_CLASS_IMP_COM_1(
+ CDynBufSeqOutStream
+ , ISequentialOutStream
+)
+ CByteDynBuffer _buffer;
+ size_t _size;
+public:
+ CDynBufSeqOutStream(): _size(0) {}
+ void Init() { _size = 0; }
+ size_t GetSize() const { return _size; }
+ const Byte *GetBuffer() const { return _buffer; }
+ void CopyToBuffer(CByteBuffer &dest) const;
+ Byte *GetBufPtrForWriting(size_t addSize);
+ void UpdateSize(size_t addSize) { _size += addSize; }
+};
+
+
+Z7_CLASS_IMP_COM_1(
+ CBufPtrSeqOutStream
+ , ISequentialOutStream
+)
+ Byte *_buffer;
+ size_t _size;
+ size_t _pos;
+public:
+ void Init(Byte *buffer, size_t size)
+ {
+ _buffer = buffer;
+ _pos = 0;
+ _size = size;
+ }
+ size_t GetPos() const { return _pos; }
+};
+
+
+Z7_CLASS_IMP_COM_1(
+ CSequentialOutStreamSizeCount
+ , ISequentialOutStream
+)
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+public:
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void Init() { _size = 0; }
+ UInt64 GetSize() const { return _size; }
+};
+
+
+class CCachedInStream:
+ public IInStream,
+ public CMyUnknownImp
+{
+ Z7_IFACES_IMP_UNK_2(ISequentialInStream, IInStream)
+
+ UInt64 *_tags;
+ Byte *_data;
+ size_t _dataSize;
+ unsigned _blockSizeLog;
+ unsigned _numBlocksLog;
+ UInt64 _size;
+ UInt64 _pos;
+protected:
+ virtual HRESULT ReadBlock(UInt64 blockIndex, Byte *dest, size_t blockSize) = 0;
+public:
+ CCachedInStream(): _tags(NULL), _data(NULL) {}
+ virtual ~CCachedInStream() { Free(); } // the destructor must be virtual (Release() calls it) !!!
+ void Free() throw();
+ bool Alloc(unsigned blockSizeLog, unsigned numBlocksLog) throw();
+ void Init(UInt64 size) throw();
+};
+
+#endif
diff --git a/CPP/7zip/Common/StreamUtils.cpp b/CPP/7zip/Common/StreamUtils.cpp
index a79de23..24eed36 100644
--- a/CPP/7zip/Common/StreamUtils.cpp
+++ b/CPP/7zip/Common/StreamUtils.cpp
@@ -1,56 +1,101 @@
-// StreamUtils.cpp
-
-#include "StdAfx.h"
-
-#include "StreamUtils.h"
-
-static const UInt32 kBlockSize = ((UInt32)1 << 31);
-
-HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *processedSize) throw()
-{
- size_t size = *processedSize;
- *processedSize = 0;
- while (size != 0)
- {
- UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize;
- UInt32 processedSizeLoc;
- HRESULT res = stream->Read(data, curSize, &processedSizeLoc);
- *processedSize += processedSizeLoc;
- data = (void *)((Byte *)data + processedSizeLoc);
- size -= processedSizeLoc;
- RINOK(res);
- if (processedSizeLoc == 0)
- return S_OK;
- }
- return S_OK;
-}
-
-HRESULT ReadStream_FALSE(ISequentialInStream *stream, void *data, size_t size) throw()
-{
- size_t processedSize = size;
- RINOK(ReadStream(stream, data, &processedSize));
- return (size == processedSize) ? S_OK : S_FALSE;
-}
-
-HRESULT ReadStream_FAIL(ISequentialInStream *stream, void *data, size_t size) throw()
-{
- size_t processedSize = size;
- RINOK(ReadStream(stream, data, &processedSize));
- return (size == processedSize) ? S_OK : E_FAIL;
-}
-
-HRESULT WriteStream(ISequentialOutStream *stream, const void *data, size_t size) throw()
-{
- while (size != 0)
- {
- UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize;
- UInt32 processedSizeLoc;
- HRESULT res = stream->Write(data, curSize, &processedSizeLoc);
- data = (const void *)((const Byte *)data + processedSizeLoc);
- size -= processedSizeLoc;
- RINOK(res);
- if (processedSizeLoc == 0)
- return E_FAIL;
- }
- return S_OK;
-}
+// StreamUtils.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyCom.h"
+
+#include "StreamUtils.h"
+
+static const UInt32 kBlockSize = ((UInt32)1 << 31);
+
+
+HRESULT InStream_SeekToBegin(IInStream *stream) throw()
+{
+ return InStream_SeekSet(stream, 0);
+}
+
+
+HRESULT InStream_AtBegin_GetSize(IInStream *stream, UInt64 &sizeRes) throw()
+{
+#ifdef _WIN32
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IStreamGetSize,
+ streamGetSize, stream)
+ if (streamGetSize && streamGetSize->GetSize(&sizeRes) == S_OK)
+ return S_OK;
+ }
+#endif
+ const HRESULT hres = InStream_GetSize_SeekToEnd(stream, sizeRes);
+ const HRESULT hres2 = InStream_SeekToBegin(stream);
+ return hres != S_OK ? hres : hres2;
+}
+
+
+HRESULT InStream_GetPos_GetSize(IInStream *stream, UInt64 &curPosRes, UInt64 &sizeRes) throw()
+{
+ RINOK(InStream_GetPos(stream, curPosRes))
+#ifdef _WIN32
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IStreamGetSize,
+ streamGetSize, stream)
+ if (streamGetSize && streamGetSize->GetSize(&sizeRes) == S_OK)
+ return S_OK;
+ }
+#endif
+ const HRESULT hres = InStream_GetSize_SeekToEnd(stream, sizeRes);
+ const HRESULT hres2 = InStream_SeekSet(stream, curPosRes);
+ return hres != S_OK ? hres : hres2;
+}
+
+
+
+HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *processedSize) throw()
+{
+ size_t size = *processedSize;
+ *processedSize = 0;
+ while (size != 0)
+ {
+ UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize;
+ UInt32 processedSizeLoc;
+ HRESULT res = stream->Read(data, curSize, &processedSizeLoc);
+ *processedSize += processedSizeLoc;
+ data = (void *)((Byte *)data + processedSizeLoc);
+ size -= processedSizeLoc;
+ RINOK(res)
+ if (processedSizeLoc == 0)
+ return S_OK;
+ }
+ return S_OK;
+}
+
+HRESULT ReadStream_FALSE(ISequentialInStream *stream, void *data, size_t size) throw()
+{
+ size_t processedSize = size;
+ RINOK(ReadStream(stream, data, &processedSize))
+ return (size == processedSize) ? S_OK : S_FALSE;
+}
+
+HRESULT ReadStream_FAIL(ISequentialInStream *stream, void *data, size_t size) throw()
+{
+ size_t processedSize = size;
+ RINOK(ReadStream(stream, data, &processedSize))
+ return (size == processedSize) ? S_OK : E_FAIL;
+}
+
+HRESULT WriteStream(ISequentialOutStream *stream, const void *data, size_t size) throw()
+{
+ while (size != 0)
+ {
+ UInt32 curSize = (size < kBlockSize) ? (UInt32)size : kBlockSize;
+ UInt32 processedSizeLoc;
+ HRESULT res = stream->Write(data, curSize, &processedSizeLoc);
+ data = (const void *)((const Byte *)data + processedSizeLoc);
+ size -= processedSizeLoc;
+ RINOK(res)
+ if (processedSizeLoc == 0)
+ return E_FAIL;
+ }
+ return S_OK;
+}
diff --git a/CPP/7zip/Common/StreamUtils.h b/CPP/7zip/Common/StreamUtils.h
index 799a8b9..35a62ed 100644
--- a/CPP/7zip/Common/StreamUtils.h
+++ b/CPP/7zip/Common/StreamUtils.h
@@ -1,13 +1,31 @@
-// StreamUtils.h
-
-#ifndef __STREAM_UTILS_H
-#define __STREAM_UTILS_H
-
-#include "../IStream.h"
-
-HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *size) throw();
-HRESULT ReadStream_FALSE(ISequentialInStream *stream, void *data, size_t size) throw();
-HRESULT ReadStream_FAIL(ISequentialInStream *stream, void *data, size_t size) throw();
-HRESULT WriteStream(ISequentialOutStream *stream, const void *data, size_t size) throw();
-
-#endif
+// StreamUtils.h
+
+#ifndef ZIP7_INC_STREAM_UTILS_H
+#define ZIP7_INC_STREAM_UTILS_H
+
+#include "../IStream.h"
+
+inline HRESULT InStream_SeekSet(IInStream *stream, UInt64 offset) throw()
+ { return stream->Seek((Int64)offset, STREAM_SEEK_SET, NULL); }
+inline HRESULT InStream_GetPos(IInStream *stream, UInt64 &curPosRes) throw()
+ { return stream->Seek(0, STREAM_SEEK_CUR, &curPosRes); }
+inline HRESULT InStream_GetSize_SeekToEnd(IInStream *stream, UInt64 &sizeRes) throw()
+ { return stream->Seek(0, STREAM_SEEK_END, &sizeRes); }
+
+HRESULT InStream_SeekToBegin(IInStream *stream) throw();
+HRESULT InStream_AtBegin_GetSize(IInStream *stream, UInt64 &size) throw();
+HRESULT InStream_GetPos_GetSize(IInStream *stream, UInt64 &curPosRes, UInt64 &sizeRes) throw();
+
+inline HRESULT InStream_GetSize_SeekToBegin(IInStream *stream, UInt64 &sizeRes) throw()
+{
+ RINOK(InStream_SeekToBegin(stream))
+ return InStream_AtBegin_GetSize(stream, sizeRes);
+}
+
+
+HRESULT ReadStream(ISequentialInStream *stream, void *data, size_t *size) throw();
+HRESULT ReadStream_FALSE(ISequentialInStream *stream, void *data, size_t size) throw();
+HRESULT ReadStream_FAIL(ISequentialInStream *stream, void *data, size_t size) throw();
+HRESULT WriteStream(ISequentialOutStream *stream, const void *data, size_t size) throw();
+
+#endif
diff --git a/CPP/7zip/Common/UniqBlocks.cpp b/CPP/7zip/Common/UniqBlocks.cpp
index 5baf1a4..32dc276 100644
--- a/CPP/7zip/Common/UniqBlocks.cpp
+++ b/CPP/7zip/Common/UniqBlocks.cpp
@@ -1,57 +1,57 @@
-// UniqBlocks.cpp
-
-#include "StdAfx.h"
-
-#include <string.h>
-
-#include "UniqBlocks.h"
-
-unsigned CUniqBlocks::AddUniq(const Byte *data, size_t size)
-{
- unsigned left = 0, right = Sorted.Size();
- while (left != right)
- {
- unsigned mid = (left + right) / 2;
- unsigned index = Sorted[mid];
- const CByteBuffer &buf = Bufs[index];
- size_t sizeMid = buf.Size();
- if (size < sizeMid)
- right = mid;
- else if (size > sizeMid)
- left = mid + 1;
- else
- {
- if (size == 0)
- return index;
- int cmp = memcmp(data, buf, size);
- if (cmp == 0)
- return index;
- if (cmp < 0)
- right = mid;
- else
- left = mid + 1;
- }
- }
- unsigned index = Bufs.Size();
- Sorted.Insert(left, index);
- Bufs.AddNew().CopyFrom(data, size);
- return index;
-}
-
-UInt64 CUniqBlocks::GetTotalSizeInBytes() const
-{
- UInt64 size = 0;
- FOR_VECTOR (i, Bufs)
- size += Bufs[i].Size();
- return size;
-}
-
-void CUniqBlocks::GetReverseMap()
-{
- unsigned num = Sorted.Size();
- BufIndexToSortedIndex.ClearAndSetSize(num);
- unsigned *p = &BufIndexToSortedIndex[0];
- const unsigned *sorted = &Sorted[0];
- for (unsigned i = 0; i < num; i++)
- p[sorted[i]] = i;
-}
+// UniqBlocks.cpp
+
+#include "StdAfx.h"
+
+#include <string.h>
+
+#include "UniqBlocks.h"
+
+unsigned CUniqBlocks::AddUniq(const Byte *data, size_t size)
+{
+ unsigned left = 0, right = Sorted.Size();
+ while (left != right)
+ {
+ const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const unsigned index = Sorted[mid];
+ const CByteBuffer &buf = Bufs[index];
+ const size_t sizeMid = buf.Size();
+ if (size < sizeMid)
+ right = mid;
+ else if (size > sizeMid)
+ left = mid + 1;
+ else
+ {
+ if (size == 0)
+ return index;
+ const int cmp = memcmp(data, buf, size);
+ if (cmp == 0)
+ return index;
+ if (cmp < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ }
+ unsigned index = Bufs.Size();
+ Sorted.Insert(left, index);
+ Bufs.AddNew().CopyFrom(data, size);
+ return index;
+}
+
+UInt64 CUniqBlocks::GetTotalSizeInBytes() const
+{
+ UInt64 size = 0;
+ FOR_VECTOR (i, Bufs)
+ size += Bufs[i].Size();
+ return size;
+}
+
+void CUniqBlocks::GetReverseMap()
+{
+ unsigned num = Sorted.Size();
+ BufIndexToSortedIndex.ClearAndSetSize(num);
+ unsigned *p = &BufIndexToSortedIndex[0];
+ const unsigned *sorted = &Sorted[0];
+ for (unsigned i = 0; i < num; i++)
+ p[sorted[i]] = i;
+}
diff --git a/CPP/7zip/Common/UniqBlocks.h b/CPP/7zip/Common/UniqBlocks.h
index d9ec17d..66c7fa2 100644
--- a/CPP/7zip/Common/UniqBlocks.h
+++ b/CPP/7zip/Common/UniqBlocks.h
@@ -1,26 +1,41 @@
-// UniqBlocks.h
-
-#ifndef __UNIQ_BLOCKS_H
-#define __UNIQ_BLOCKS_H
-
-#include "../../Common/MyTypes.h"
-#include "../../Common/MyBuffer.h"
-#include "../../Common/MyVector.h"
-
-struct CUniqBlocks
-{
- CObjectVector<CByteBuffer> Bufs;
- CUIntVector Sorted;
- CUIntVector BufIndexToSortedIndex;
-
- unsigned AddUniq(const Byte *data, size_t size);
- UInt64 GetTotalSizeInBytes() const;
- void GetReverseMap();
-
- bool IsOnlyEmpty() const
- {
- return (Bufs.Size() == 0 || Bufs.Size() == 1 && Bufs[0].Size() == 0);
- }
-};
-
-#endif
+// UniqBlocks.h
+
+#ifndef ZIP7_INC_UNIQ_BLOCKS_H
+#define ZIP7_INC_UNIQ_BLOCKS_H
+
+#include "../../Common/MyBuffer.h"
+#include "../../Common/MyString.h"
+
+struct C_UInt32_UString_Map
+{
+ CRecordVector<UInt32> Numbers;
+ UStringVector Strings;
+
+ void Add_UInt32(const UInt32 n)
+ {
+ Numbers.AddToUniqueSorted(n);
+ }
+ int Find(const UInt32 n)
+ {
+ return Numbers.FindInSorted(n);
+ }
+};
+
+
+struct CUniqBlocks
+{
+ CObjectVector<CByteBuffer> Bufs;
+ CUIntVector Sorted;
+ CUIntVector BufIndexToSortedIndex;
+
+ unsigned AddUniq(const Byte *data, size_t size);
+ UInt64 GetTotalSizeInBytes() const;
+ void GetReverseMap();
+
+ bool IsOnlyEmpty() const
+ {
+ return (Bufs.Size() == 0 || (Bufs.Size() == 1 && Bufs[0].Size() == 0));
+ }
+};
+
+#endif
diff --git a/CPP/7zip/Common/VirtThread.cpp b/CPP/7zip/Common/VirtThread.cpp
index 3cf9acd..3cf7296 100644
--- a/CPP/7zip/Common/VirtThread.cpp
+++ b/CPP/7zip/Common/VirtThread.cpp
@@ -1,48 +1,47 @@
-// VirtThread.cpp
-
-#include "StdAfx.h"
-
-#include "VirtThread.h"
-
-static THREAD_FUNC_DECL CoderThread(void *p)
-{
- for (;;)
- {
- CVirtThread *t = (CVirtThread *)p;
- t->StartEvent.Lock();
- if (t->Exit)
- return 0;
- t->Execute();
- t->FinishedEvent.Set();
- }
-}
-
-WRes CVirtThread::Create()
-{
- RINOK(StartEvent.CreateIfNotCreated());
- RINOK(FinishedEvent.CreateIfNotCreated());
- StartEvent.Reset();
- FinishedEvent.Reset();
- Exit = false;
- if (Thread.IsCreated())
- return S_OK;
- return Thread.Create(CoderThread, this);
-}
-
-void CVirtThread::Start()
-{
- Exit = false;
- StartEvent.Set();
-}
-
-void CVirtThread::WaitThreadFinish()
-{
- Exit = true;
- if (StartEvent.IsCreated())
- StartEvent.Set();
- if (Thread.IsCreated())
- {
- Thread.Wait();
- Thread.Close();
- }
-}
+// VirtThread.cpp
+
+#include "StdAfx.h"
+
+#include "VirtThread.h"
+
+static THREAD_FUNC_DECL CoderThread(void *p)
+{
+ for (;;)
+ {
+ CVirtThread *t = (CVirtThread *)p;
+ t->StartEvent.Lock();
+ if (t->Exit)
+ return THREAD_FUNC_RET_ZERO;
+ t->Execute();
+ t->FinishedEvent.Set();
+ }
+}
+
+WRes CVirtThread::Create()
+{
+ RINOK_WRes(StartEvent.CreateIfNotCreated_Reset())
+ RINOK_WRes(FinishedEvent.CreateIfNotCreated_Reset())
+ // StartEvent.Reset();
+ // FinishedEvent.Reset();
+ Exit = false;
+ if (Thread.IsCreated())
+ return S_OK;
+ return Thread.Create(CoderThread, this);
+}
+
+WRes CVirtThread::Start()
+{
+ Exit = false;
+ return StartEvent.Set();
+}
+
+void CVirtThread::WaitThreadFinish()
+{
+ Exit = true;
+ if (StartEvent.IsCreated())
+ StartEvent.Set();
+ if (Thread.IsCreated())
+ {
+ Thread.Wait_Close();
+ }
+}
diff --git a/CPP/7zip/Common/VirtThread.h b/CPP/7zip/Common/VirtThread.h
index a271103..809b356 100644
--- a/CPP/7zip/Common/VirtThread.h
+++ b/CPP/7zip/Common/VirtThread.h
@@ -1,24 +1,24 @@
-// VirtThread.h
-
-#ifndef __VIRT_THREAD_H
-#define __VIRT_THREAD_H
-
-#include "../../Windows/Synchronization.h"
-#include "../../Windows/Thread.h"
-
-struct CVirtThread
-{
- NWindows::NSynchronization::CAutoResetEvent StartEvent;
- NWindows::NSynchronization::CAutoResetEvent FinishedEvent;
- NWindows::CThread Thread;
- bool Exit;
-
- ~CVirtThread() { WaitThreadFinish(); }
- void WaitThreadFinish(); // call it in destructor of child class !
- WRes Create();
- void Start();
- virtual void Execute() = 0;
- void WaitExecuteFinish() { FinishedEvent.Lock(); }
-};
-
-#endif
+// VirtThread.h
+
+#ifndef ZIP7_INC_VIRT_THREAD_H
+#define ZIP7_INC_VIRT_THREAD_H
+
+#include "../../Windows/Synchronization.h"
+#include "../../Windows/Thread.h"
+
+struct CVirtThread
+{
+ NWindows::NSynchronization::CAutoResetEvent StartEvent;
+ NWindows::NSynchronization::CAutoResetEvent FinishedEvent;
+ NWindows::CThread Thread;
+ bool Exit;
+
+ virtual ~CVirtThread() { WaitThreadFinish(); }
+ void WaitThreadFinish(); // call it in destructor of child class !
+ WRes Create();
+ WRes Start();
+ virtual void Execute() = 0;
+ WRes WaitExecuteFinish() { return FinishedEvent.Lock(); }
+};
+
+#endif
diff --git a/CPP/7zip/Compress/BZip2Const.h b/CPP/7zip/Compress/BZip2Const.h
new file mode 100644
index 0000000..0dfcfe5
--- /dev/null
+++ b/CPP/7zip/Compress/BZip2Const.h
@@ -0,0 +1,71 @@
+// Compress/BZip2Const.h
+
+#ifndef ZIP7_INC_COMPRESS_BZIP2_CONST_H
+#define ZIP7_INC_COMPRESS_BZIP2_CONST_H
+
+namespace NCompress {
+namespace NBZip2 {
+
+const Byte kArSig0 = 'B';
+const Byte kArSig1 = 'Z';
+const Byte kArSig2 = 'h';
+const Byte kArSig3 = '0';
+
+const Byte kFinSig0 = 0x17;
+const Byte kFinSig1 = 0x72;
+const Byte kFinSig2 = 0x45;
+const Byte kFinSig3 = 0x38;
+const Byte kFinSig4 = 0x50;
+const Byte kFinSig5 = 0x90;
+
+const Byte kBlockSig0 = 0x31;
+const Byte kBlockSig1 = 0x41;
+const Byte kBlockSig2 = 0x59;
+const Byte kBlockSig3 = 0x26;
+const Byte kBlockSig4 = 0x53;
+const Byte kBlockSig5 = 0x59;
+
+const unsigned kNumOrigBits = 24;
+
+const unsigned kNumTablesBits = 3;
+const unsigned kNumTablesMin = 2;
+const unsigned kNumTablesMax = 6;
+
+const unsigned kNumLevelsBits = 5;
+
+const unsigned kMaxHuffmanLen = 20; // Check it
+
+const unsigned kMaxAlphaSize = 258;
+
+const unsigned kGroupSize = 50;
+
+const unsigned kBlockSizeMultMin = 1;
+const unsigned kBlockSizeMultMax = 9;
+
+const UInt32 kBlockSizeStep = 100000;
+const UInt32 kBlockSizeMax = kBlockSizeMultMax * kBlockSizeStep;
+
+const unsigned kNumSelectorsBits = 15;
+const UInt32 kNumSelectorsMax = (2 + (kBlockSizeMax / kGroupSize));
+
+const unsigned kRleModeRepSize = 4;
+
+/*
+The number of selectors stored in bzip2 block:
+(numSelectors <= 18001) - must work with any decoder.
+(numSelectors == 18002) - works with bzip2 1.0.6 decoder and all derived decoders.
+(numSelectors > 18002)
+ lbzip2 2.5: encoder can write up to (18001 + 7) selectors.
+
+ 7-Zip before 19.03: decoder doesn't support it.
+ 7-Zip 19.03: decoder allows 8 additional selector records for lbzip2 compatibility.
+
+ bzip2 1.0.6: decoder can overflow selector[18002] arrays. But there are another
+ arrays after selector arrays. So the compiled code works.
+ bzip2 1.0.7: decoder doesn't support it.
+ bzip2 1.0.8: decoder allows additional selector records for lbzip2 compatibility.
+*/
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/BZip2Crc.cpp b/CPP/7zip/Compress/BZip2Crc.cpp
new file mode 100644
index 0000000..9639c7b
--- /dev/null
+++ b/CPP/7zip/Compress/BZip2Crc.cpp
@@ -0,0 +1,27 @@
+// BZip2Crc.cpp
+
+#include "StdAfx.h"
+
+#include "BZip2Crc.h"
+
+UInt32 CBZip2Crc::Table[256];
+
+static const UInt32 kBZip2CrcPoly = 0x04c11db7; /* AUTODIN II, Ethernet, & FDDI */
+
+void CBZip2Crc::InitTable()
+{
+ for (UInt32 i = 0; i < 256; i++)
+ {
+ UInt32 r = (i << 24);
+ for (unsigned j = 0; j < 8; j++)
+ r = (r << 1) ^ (kBZip2CrcPoly & ((UInt32)0 - (r >> 31)));
+ Table[i] = r;
+ }
+}
+
+static
+class CBZip2CrcTableInit
+{
+public:
+ CBZip2CrcTableInit() { CBZip2Crc::InitTable(); }
+} g_BZip2CrcTableInit;
diff --git a/CPP/7zip/Compress/BZip2Crc.h b/CPP/7zip/Compress/BZip2Crc.h
new file mode 100644
index 0000000..10e147b
--- /dev/null
+++ b/CPP/7zip/Compress/BZip2Crc.h
@@ -0,0 +1,31 @@
+// BZip2Crc.h
+
+#ifndef ZIP7_INC_BZIP2_CRC_H
+#define ZIP7_INC_BZIP2_CRC_H
+
+#include "../../Common/MyTypes.h"
+
+class CBZip2Crc
+{
+ UInt32 _value;
+ static UInt32 Table[256];
+public:
+ static void InitTable();
+ CBZip2Crc(UInt32 initVal = 0xFFFFFFFF): _value(initVal) {}
+ void Init(UInt32 initVal = 0xFFFFFFFF) { _value = initVal; }
+ void UpdateByte(Byte b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); }
+ void UpdateByte(unsigned b) { _value = Table[(_value >> 24) ^ b] ^ (_value << 8); }
+ UInt32 GetDigest() const { return _value ^ 0xFFFFFFFF; }
+};
+
+class CBZip2CombinedCrc
+{
+ UInt32 _value;
+public:
+ CBZip2CombinedCrc(): _value(0) {}
+ void Init() { _value = 0; }
+ void Update(UInt32 v) { _value = ((_value << 1) | (_value >> 31)) ^ v; }
+ UInt32 GetDigest() const { return _value ; }
+};
+
+#endif
diff --git a/CPP/7zip/Compress/BZip2Decoder.cpp b/CPP/7zip/Compress/BZip2Decoder.cpp
new file mode 100644
index 0000000..b28da5f
--- /dev/null
+++ b/CPP/7zip/Compress/BZip2Decoder.cpp
@@ -0,0 +1,1797 @@
+// BZip2Decoder.cpp
+
+#include "StdAfx.h"
+
+// #include "CopyCoder.h"
+
+/*
+#include <stdio.h>
+#include "../../../C/CpuTicks.h"
+*/
+#define TICKS_START
+#define TICKS_UPDATE(n)
+
+
+/*
+#define PRIN(s) printf(s "\n"); fflush(stdout);
+#define PRIN_VAL(s, val) printf(s " = %u \n", val); fflush(stdout);
+*/
+
+#define PRIN(s)
+#define PRIN_VAL(s, val)
+
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "BZip2Decoder.h"
+
+
+namespace NCompress {
+namespace NBZip2 {
+
+// #undef NO_INLINE
+#define NO_INLINE Z7_NO_INLINE
+
+#define BZIP2_BYTE_MODE
+
+
+static const UInt32 kInBufSize = (UInt32)1 << 17;
+static const size_t kOutBufSize = (size_t)1 << 20;
+
+static const UInt32 kProgressStep = (UInt32)1 << 16;
+
+
+static const UInt16 kRandNums[512] = {
+ 619, 720, 127, 481, 931, 816, 813, 233, 566, 247,
+ 985, 724, 205, 454, 863, 491, 741, 242, 949, 214,
+ 733, 859, 335, 708, 621, 574, 73, 654, 730, 472,
+ 419, 436, 278, 496, 867, 210, 399, 680, 480, 51,
+ 878, 465, 811, 169, 869, 675, 611, 697, 867, 561,
+ 862, 687, 507, 283, 482, 129, 807, 591, 733, 623,
+ 150, 238, 59, 379, 684, 877, 625, 169, 643, 105,
+ 170, 607, 520, 932, 727, 476, 693, 425, 174, 647,
+ 73, 122, 335, 530, 442, 853, 695, 249, 445, 515,
+ 909, 545, 703, 919, 874, 474, 882, 500, 594, 612,
+ 641, 801, 220, 162, 819, 984, 589, 513, 495, 799,
+ 161, 604, 958, 533, 221, 400, 386, 867, 600, 782,
+ 382, 596, 414, 171, 516, 375, 682, 485, 911, 276,
+ 98, 553, 163, 354, 666, 933, 424, 341, 533, 870,
+ 227, 730, 475, 186, 263, 647, 537, 686, 600, 224,
+ 469, 68, 770, 919, 190, 373, 294, 822, 808, 206,
+ 184, 943, 795, 384, 383, 461, 404, 758, 839, 887,
+ 715, 67, 618, 276, 204, 918, 873, 777, 604, 560,
+ 951, 160, 578, 722, 79, 804, 96, 409, 713, 940,
+ 652, 934, 970, 447, 318, 353, 859, 672, 112, 785,
+ 645, 863, 803, 350, 139, 93, 354, 99, 820, 908,
+ 609, 772, 154, 274, 580, 184, 79, 626, 630, 742,
+ 653, 282, 762, 623, 680, 81, 927, 626, 789, 125,
+ 411, 521, 938, 300, 821, 78, 343, 175, 128, 250,
+ 170, 774, 972, 275, 999, 639, 495, 78, 352, 126,
+ 857, 956, 358, 619, 580, 124, 737, 594, 701, 612,
+ 669, 112, 134, 694, 363, 992, 809, 743, 168, 974,
+ 944, 375, 748, 52, 600, 747, 642, 182, 862, 81,
+ 344, 805, 988, 739, 511, 655, 814, 334, 249, 515,
+ 897, 955, 664, 981, 649, 113, 974, 459, 893, 228,
+ 433, 837, 553, 268, 926, 240, 102, 654, 459, 51,
+ 686, 754, 806, 760, 493, 403, 415, 394, 687, 700,
+ 946, 670, 656, 610, 738, 392, 760, 799, 887, 653,
+ 978, 321, 576, 617, 626, 502, 894, 679, 243, 440,
+ 680, 879, 194, 572, 640, 724, 926, 56, 204, 700,
+ 707, 151, 457, 449, 797, 195, 791, 558, 945, 679,
+ 297, 59, 87, 824, 713, 663, 412, 693, 342, 606,
+ 134, 108, 571, 364, 631, 212, 174, 643, 304, 329,
+ 343, 97, 430, 751, 497, 314, 983, 374, 822, 928,
+ 140, 206, 73, 263, 980, 736, 876, 478, 430, 305,
+ 170, 514, 364, 692, 829, 82, 855, 953, 676, 246,
+ 369, 970, 294, 750, 807, 827, 150, 790, 288, 923,
+ 804, 378, 215, 828, 592, 281, 565, 555, 710, 82,
+ 896, 831, 547, 261, 524, 462, 293, 465, 502, 56,
+ 661, 821, 976, 991, 658, 869, 905, 758, 745, 193,
+ 768, 550, 608, 933, 378, 286, 215, 979, 792, 961,
+ 61, 688, 793, 644, 986, 403, 106, 366, 905, 644,
+ 372, 567, 466, 434, 645, 210, 389, 550, 919, 135,
+ 780, 773, 635, 389, 707, 100, 626, 958, 165, 504,
+ 920, 176, 193, 713, 857, 265, 203, 50, 668, 108,
+ 645, 990, 626, 197, 510, 357, 358, 850, 858, 364,
+ 936, 638
+};
+
+
+
+enum EState
+{
+ STATE_STREAM_SIGNATURE,
+ STATE_BLOCK_SIGNATURE,
+
+ STATE_BLOCK_START,
+ STATE_ORIG_BITS,
+ STATE_IN_USE,
+ STATE_IN_USE2,
+ STATE_NUM_TABLES,
+ STATE_NUM_SELECTORS,
+ STATE_SELECTORS,
+ STATE_LEVELS,
+
+ STATE_BLOCK_SYMBOLS,
+
+ STATE_STREAM_FINISHED
+};
+
+
+#define UPDATE_VAL_2(val) { \
+ val |= (UInt32)(*_buf) << (24 - _numBits); \
+ _numBits += 8; \
+ _buf++; \
+}
+
+#define UPDATE_VAL UPDATE_VAL_2(VAL)
+
+#define READ_BITS(res, num) { \
+ while (_numBits < num) { \
+ if (_buf == _lim) return SZ_OK; \
+ UPDATE_VAL_2(_value) } \
+ res = _value >> (32 - num); \
+ _value <<= num; \
+ _numBits -= num; \
+}
+
+#define READ_BITS_8(res, num) { \
+ if (_numBits < num) { \
+ if (_buf == _lim) return SZ_OK; \
+ UPDATE_VAL_2(_value) } \
+ res = _value >> (32 - num); \
+ _value <<= num; \
+ _numBits -= num; \
+}
+
+#define READ_BIT(res) READ_BITS_8(res, 1)
+
+
+
+#define VAL _value2
+#define BLOCK_SIZE blockSize2
+#define RUN_COUNTER runCounter2
+
+#define LOAD_LOCAL \
+ UInt32 VAL = this->_value; \
+ UInt32 BLOCK_SIZE = this->blockSize; \
+ UInt32 RUN_COUNTER = this->runCounter; \
+
+#define SAVE_LOCAL \
+ this->_value = VAL; \
+ this->blockSize = BLOCK_SIZE; \
+ this->runCounter = RUN_COUNTER; \
+
+
+
+SRes CBitDecoder::ReadByte(int &b)
+{
+ b = -1;
+ READ_BITS_8(b, 8)
+ return SZ_OK;
+}
+
+
+NO_INLINE
+SRes CBase::ReadStreamSignature2()
+{
+ for (;;)
+ {
+ unsigned b;
+ READ_BITS_8(b, 8)
+
+ if ( (state2 == 0 && b != kArSig0)
+ || (state2 == 1 && b != kArSig1)
+ || (state2 == 2 && b != kArSig2)
+ || (state2 == 3 && (b <= kArSig3 || b > kArSig3 + kBlockSizeMultMax)))
+ return SZ_ERROR_DATA;
+ state2++;
+
+ if (state2 == 4)
+ {
+ blockSizeMax = (UInt32)(b - kArSig3) * kBlockSizeStep;
+ CombinedCrc.Init();
+ state = STATE_BLOCK_SIGNATURE;
+ state2 = 0;
+ return SZ_OK;
+ }
+ }
+}
+
+
+bool IsEndSig(const Byte *p) throw()
+{
+ return
+ p[0] == kFinSig0 &&
+ p[1] == kFinSig1 &&
+ p[2] == kFinSig2 &&
+ p[3] == kFinSig3 &&
+ p[4] == kFinSig4 &&
+ p[5] == kFinSig5;
+}
+
+bool IsBlockSig(const Byte *p) throw()
+{
+ return
+ p[0] == kBlockSig0 &&
+ p[1] == kBlockSig1 &&
+ p[2] == kBlockSig2 &&
+ p[3] == kBlockSig3 &&
+ p[4] == kBlockSig4 &&
+ p[5] == kBlockSig5;
+}
+
+
+NO_INLINE
+SRes CBase::ReadBlockSignature2()
+{
+ while (state2 < 10)
+ {
+ unsigned b;
+ READ_BITS_8(b, 8)
+ temp[state2] = (Byte)b;
+ state2++;
+ }
+
+ crc = 0;
+ for (unsigned i = 0; i < 4; i++)
+ {
+ crc <<= 8;
+ crc |= temp[6 + i];
+ }
+
+ if (IsBlockSig(temp))
+ {
+ if (!IsBz)
+ NumStreams++;
+ NumBlocks++;
+ IsBz = true;
+ CombinedCrc.Update(crc);
+ state = STATE_BLOCK_START;
+ return SZ_OK;
+ }
+
+ if (!IsEndSig(temp))
+ return SZ_ERROR_DATA;
+
+ if (!IsBz)
+ NumStreams++;
+ IsBz = true;
+
+ if (_value != 0)
+ MinorError = true;
+
+ AlignToByte();
+
+ state = STATE_STREAM_FINISHED;
+ if (crc != CombinedCrc.GetDigest())
+ {
+ StreamCrcError = true;
+ return SZ_ERROR_DATA;
+ }
+ return SZ_OK;
+}
+
+
+NO_INLINE
+SRes CBase::ReadBlock2()
+{
+ if (state != STATE_BLOCK_SYMBOLS) {
+ PRIN("ReadBlock2")
+
+ if (state == STATE_BLOCK_START)
+ {
+ if (Props.randMode)
+ {
+ READ_BIT(Props.randMode)
+ }
+ state = STATE_ORIG_BITS;
+ // g_Tick = GetCpuTicks();
+ }
+
+ if (state == STATE_ORIG_BITS)
+ {
+ READ_BITS(Props.origPtr, kNumOrigBits)
+ if (Props.origPtr >= blockSizeMax)
+ return SZ_ERROR_DATA;
+ state = STATE_IN_USE;
+ }
+
+ // why original code compares origPtr to (UInt32)(10 + blockSizeMax)) ?
+
+ if (state == STATE_IN_USE)
+ {
+ READ_BITS(state2, 16)
+ state = STATE_IN_USE2;
+ state3 = 0;
+ numInUse = 0;
+ mtf.StartInit();
+ }
+
+ if (state == STATE_IN_USE2)
+ {
+ for (; state3 < 256; state3++)
+ if (state2 & ((UInt32)0x8000 >> (state3 >> 4)))
+ {
+ unsigned b;
+ READ_BIT(b)
+ if (b)
+ mtf.Add(numInUse++, (Byte)state3);
+ }
+ if (numInUse == 0)
+ return SZ_ERROR_DATA;
+ state = STATE_NUM_TABLES;
+ }
+
+
+ if (state == STATE_NUM_TABLES)
+ {
+ READ_BITS_8(numTables, kNumTablesBits)
+ state = STATE_NUM_SELECTORS;
+ if (numTables < kNumTablesMin || numTables > kNumTablesMax)
+ return SZ_ERROR_DATA;
+ }
+
+ if (state == STATE_NUM_SELECTORS)
+ {
+ READ_BITS(numSelectors, kNumSelectorsBits)
+ state = STATE_SELECTORS;
+ state2 = 0x543210;
+ state3 = 0;
+ state4 = 0;
+ // lbzip2 can write small number of additional selectors,
+ // 20.01: we allow big number of selectors here like bzip2-1.0.8
+ if (numSelectors == 0
+ // || numSelectors > kNumSelectorsMax_Decoder
+ )
+ return SZ_ERROR_DATA;
+ }
+
+ if (state == STATE_SELECTORS)
+ {
+ const unsigned kMtfBits = 4;
+ const UInt32 kMtfMask = (1 << kMtfBits) - 1;
+ do
+ {
+ for (;;)
+ {
+ unsigned b;
+ READ_BIT(b)
+ if (!b)
+ break;
+ if (++state4 >= numTables)
+ return SZ_ERROR_DATA;
+ }
+ UInt32 tmp = (state2 >> (kMtfBits * state4)) & kMtfMask;
+ UInt32 mask = ((UInt32)1 << ((state4 + 1) * kMtfBits)) - 1;
+ state4 = 0;
+ state2 = ((state2 << kMtfBits) & mask) | (state2 & ~mask) | tmp;
+ // 20.01: here we keep compatibility with bzip2-1.0.8 decoder:
+ if (state3 < kNumSelectorsMax)
+ selectors[state3] = (Byte)tmp;
+ }
+ while (++state3 < numSelectors);
+
+ // we allowed additional dummy selector records filled above to support lbzip2's archives.
+ // but we still don't allow to use these additional dummy selectors in the code bellow
+ // bzip2 1.0.8 decoder also has similar restriction.
+
+ if (numSelectors > kNumSelectorsMax)
+ numSelectors = kNumSelectorsMax;
+
+ state = STATE_LEVELS;
+ state2 = 0;
+ state3 = 0;
+ }
+
+ if (state == STATE_LEVELS)
+ {
+ do
+ {
+ if (state3 == 0)
+ {
+ READ_BITS_8(state3, kNumLevelsBits)
+ state4 = 0;
+ state5 = 0;
+ }
+ const unsigned alphaSize = numInUse + 2;
+ for (; state4 < alphaSize; state4++)
+ {
+ for (;;)
+ {
+ if (state3 < 1 || state3 > kMaxHuffmanLen)
+ return SZ_ERROR_DATA;
+
+ if (state5 == 0)
+ {
+ unsigned b;
+ READ_BIT(b)
+ if (!b)
+ break;
+ }
+
+ state5 = 1;
+ unsigned b;
+ READ_BIT(b)
+
+ state5 = 0;
+ state3++;
+ state3 -= (b << 1);
+ }
+ lens[state4] = (Byte)state3;
+ state5 = 0;
+ }
+
+ // 19.03: we use Build() instead of BuildFull() to support lbzip2 archives
+ // lbzip2 2.5 can produce dummy tree, where lens[i] = kMaxHuffmanLen
+ // BuildFull() returns error for such tree
+ for (unsigned i = state4; i < kMaxAlphaSize; i++)
+ lens[i] = 0;
+ if (!huffs[state2].Build(lens))
+ /*
+ if (!huffs[state2].BuildFull(lens, state4))
+ */
+ return SZ_ERROR_DATA;
+ state3 = 0;
+ }
+ while (++state2 < numTables);
+
+ {
+ UInt32 *counters = this->Counters;
+ for (unsigned i = 0; i < 256; i++)
+ counters[i] = 0;
+ }
+
+ state = STATE_BLOCK_SYMBOLS;
+
+ groupIndex = 0;
+ groupSize = kGroupSize;
+ runPower = 0;
+ runCounter = 0;
+ blockSize = 0;
+ }
+
+ if (state != STATE_BLOCK_SYMBOLS)
+ return SZ_ERROR_DATA;
+
+ // g_Ticks[3] += GetCpuTicks() - g_Tick;
+
+ }
+
+ {
+ LOAD_LOCAL
+ const CHuffmanDecoder *huff = &huffs[selectors[groupIndex]];
+
+ for (;;)
+ {
+ if (groupSize == 0)
+ {
+ if (++groupIndex >= numSelectors)
+ return SZ_ERROR_DATA;
+ huff = &huffs[selectors[groupIndex]];
+ groupSize = kGroupSize;
+ }
+
+ if (_numBits <= 8 &&
+ _buf != _lim) { UPDATE_VAL
+ if (_buf != _lim) { UPDATE_VAL
+ if (_buf != _lim) { UPDATE_VAL }}}
+
+ UInt32 sym;
+ UInt32 val = VAL >> (32 - kMaxHuffmanLen);
+ if (val >= huff->_limits[kNumTableBits])
+ {
+ if (_numBits <= kMaxHuffmanLen && _buf != _lim) { UPDATE_VAL
+ if (_numBits <= kMaxHuffmanLen && _buf != _lim) { UPDATE_VAL }}
+
+ val = VAL >> (32 - kMaxHuffmanLen);
+ unsigned len;
+ for (len = kNumTableBits + 1; val >= huff->_limits[len]; len++);
+
+ // 19.03: we use that check to support partial trees created Build() for lbzip2 archives
+ if (len > kNumBitsMax)
+ return SZ_ERROR_DATA; // that check is required, if NHuffman::Build() was used instead of BuildFull()
+
+ if (_numBits < len)
+ {
+ SAVE_LOCAL
+ return SZ_OK;
+ }
+ sym = huff->_symbols[huff->_poses[len] + ((val - huff->_limits[(size_t)len - 1]) >> (kNumBitsMax - len))];
+ VAL <<= len;
+ _numBits -= len;
+ }
+ else
+ {
+ sym = huff->_lens[val >> (kMaxHuffmanLen - kNumTableBits)];
+ unsigned len = (sym & NHuffman::kPairLenMask);
+ sym >>= NHuffman::kNumPairLenBits;
+ if (_numBits < len)
+ {
+ SAVE_LOCAL
+ return SZ_OK;
+ }
+ VAL <<= len;
+ _numBits -= len;
+ }
+
+ groupSize--;
+
+ if (sym < 2)
+ {
+ RUN_COUNTER += ((UInt32)(sym + 1) << runPower);
+ runPower++;
+ if (blockSizeMax - BLOCK_SIZE < RUN_COUNTER)
+ return SZ_ERROR_DATA;
+ continue;
+ }
+
+ UInt32 *counters = this->Counters;
+ if (RUN_COUNTER != 0)
+ {
+ UInt32 b = (UInt32)(mtf.Buf[0] & 0xFF);
+ counters[b] += RUN_COUNTER;
+ runPower = 0;
+ #ifdef BZIP2_BYTE_MODE
+ Byte *dest = (Byte *)(&counters[256 + kBlockSizeMax]) + BLOCK_SIZE;
+ const Byte *limit = dest + RUN_COUNTER;
+ BLOCK_SIZE += RUN_COUNTER;
+ RUN_COUNTER = 0;
+ do
+ {
+ dest[0] = (Byte)b;
+ dest[1] = (Byte)b;
+ dest[2] = (Byte)b;
+ dest[3] = (Byte)b;
+ dest += 4;
+ }
+ while (dest < limit);
+ #else
+ UInt32 *dest = &counters[256 + BLOCK_SIZE];
+ const UInt32 *limit = dest + RUN_COUNTER;
+ BLOCK_SIZE += RUN_COUNTER;
+ RUN_COUNTER = 0;
+ do
+ {
+ dest[0] = b;
+ dest[1] = b;
+ dest[2] = b;
+ dest[3] = b;
+ dest += 4;
+ }
+ while (dest < limit);
+ #endif
+ }
+
+ sym -= 1;
+ if (sym < numInUse)
+ {
+ if (BLOCK_SIZE >= blockSizeMax)
+ return SZ_ERROR_DATA;
+
+ // UInt32 b = (UInt32)mtf.GetAndMove((unsigned)sym);
+
+ const unsigned lim = sym >> Z7_MTF_MOVS;
+ const unsigned pos = (sym & Z7_MTF_MASK) << 3;
+ CMtfVar next = mtf.Buf[lim];
+ CMtfVar prev = (next >> pos) & 0xFF;
+
+ #ifdef BZIP2_BYTE_MODE
+ ((Byte *)(counters + 256 + kBlockSizeMax))[BLOCK_SIZE++] = (Byte)prev;
+ #else
+ (counters + 256)[BLOCK_SIZE++] = (UInt32)prev;
+ #endif
+ counters[prev]++;
+
+ CMtfVar *m = mtf.Buf;
+ CMtfVar *mLim = m + lim;
+ if (lim != 0)
+ {
+ do
+ {
+ CMtfVar n0 = *m;
+ *m = (n0 << 8) | prev;
+ prev = (n0 >> (Z7_MTF_MASK << 3));
+ }
+ while (++m != mLim);
+ }
+
+ CMtfVar mask = (((CMtfVar)0x100 << pos) - 1);
+ *mLim = (next & ~mask) | (((next << 8) | prev) & mask);
+ continue;
+ }
+
+ if (sym != numInUse)
+ return SZ_ERROR_DATA;
+ break;
+ }
+
+ // we write additional item that will be read in DecodeBlock1 for prefetching
+ #ifdef BZIP2_BYTE_MODE
+ ((Byte *)(Counters + 256 + kBlockSizeMax))[BLOCK_SIZE] = 0;
+ #else
+ (counters + 256)[BLOCK_SIZE] = 0;
+ #endif
+
+ SAVE_LOCAL
+ Props.blockSize = blockSize;
+ state = STATE_BLOCK_SIGNATURE;
+ state2 = 0;
+
+ PRIN_VAL("origPtr", Props.origPtr);
+ PRIN_VAL("blockSize", Props.blockSize);
+
+ return (Props.origPtr < Props.blockSize) ? SZ_OK : SZ_ERROR_DATA;
+ }
+}
+
+
+NO_INLINE
+static void DecodeBlock1(UInt32 *counters, UInt32 blockSize)
+{
+ {
+ UInt32 sum = 0;
+ for (UInt32 i = 0; i < 256; i++)
+ {
+ const UInt32 v = counters[i];
+ counters[i] = sum;
+ sum += v;
+ }
+ }
+
+ UInt32 *tt = counters + 256;
+ // Compute the T^(-1) vector
+
+ // blockSize--;
+
+ #ifdef BZIP2_BYTE_MODE
+
+ unsigned c = ((const Byte *)(tt + kBlockSizeMax))[0];
+
+ for (UInt32 i = 0; i < blockSize; i++)
+ {
+ unsigned c1 = c;
+ const UInt32 pos = counters[c];
+ c = ((const Byte *)(tt + kBlockSizeMax))[(size_t)i + 1];
+ counters[c1] = pos + 1;
+ tt[pos] = (i << 8) | ((const Byte *)(tt + kBlockSizeMax))[pos];
+ }
+
+ /*
+ // last iteration without next character prefetching
+ {
+ const UInt32 pos = counters[c];
+ counters[c] = pos + 1;
+ tt[pos] = (blockSize << 8) | ((const Byte *)(tt + kBlockSizeMax))[pos];
+ }
+ */
+
+ #else
+
+ unsigned c = (unsigned)(tt[0] & 0xFF);
+
+ for (UInt32 i = 0; i < blockSize; i++)
+ {
+ unsigned c1 = c;
+ const UInt32 pos = counters[c];
+ c = (unsigned)(tt[(size_t)i + 1] & 0xFF);
+ counters[c1] = pos + 1;
+ tt[pos] |= (i << 8);
+ }
+
+ /*
+ {
+ const UInt32 pos = counters[c];
+ counters[c] = pos + 1;
+ tt[pos] |= (blockSize << 8);
+ }
+ */
+
+ #endif
+
+
+ /*
+ for (UInt32 i = 0; i < blockSize; i++)
+ {
+ #ifdef BZIP2_BYTE_MODE
+ const unsigned c = ((const Byte *)(tt + kBlockSizeMax))[i];
+ const UInt32 pos = counters[c]++;
+ tt[pos] = (i << 8) | ((const Byte *)(tt + kBlockSizeMax))[pos];
+ #else
+ const unsigned c = (unsigned)(tt[i] & 0xFF);
+ const UInt32 pos = counters[c]++;
+ tt[pos] |= (i << 8);
+ #endif
+ }
+ */
+}
+
+
+void CSpecState::Init(UInt32 origPtr, unsigned randMode) throw()
+{
+ _tPos = _tt[_tt[origPtr] >> 8];
+ _prevByte = (unsigned)(_tPos & 0xFF);
+ _reps = 0;
+ _randIndex = 0;
+ _randToGo = -1;
+ if (randMode)
+ {
+ _randIndex = 1;
+ _randToGo = kRandNums[0] - 2;
+ }
+ _crc.Init();
+}
+
+
+
+NO_INLINE
+Byte * CSpecState::Decode(Byte *data, size_t size) throw()
+{
+ if (size == 0)
+ return data;
+
+ unsigned prevByte = _prevByte;
+ int reps = _reps;
+ CBZip2Crc crc = _crc;
+ const Byte *lim = data + size;
+
+ while (reps > 0)
+ {
+ reps--;
+ *data++ = (Byte)prevByte;
+ crc.UpdateByte(prevByte);
+ if (data == lim)
+ break;
+ }
+
+ UInt32 tPos = _tPos;
+ UInt32 blockSize = _blockSize;
+ const UInt32 *tt = _tt;
+
+ if (data != lim && blockSize)
+
+ for (;;)
+ {
+ unsigned b = (unsigned)(tPos & 0xFF);
+ tPos = tt[tPos >> 8];
+ blockSize--;
+
+ if (_randToGo >= 0)
+ {
+ if (_randToGo == 0)
+ {
+ b ^= 1;
+ _randToGo = kRandNums[_randIndex];
+ _randIndex++;
+ _randIndex &= 0x1FF;
+ }
+ _randToGo--;
+ }
+
+ if (reps != -(int)kRleModeRepSize)
+ {
+ if (b != prevByte)
+ reps = 0;
+ reps--;
+ prevByte = b;
+ *data++ = (Byte)b;
+ crc.UpdateByte(b);
+ if (data == lim || blockSize == 0)
+ break;
+ continue;
+ }
+
+ reps = (int)b;
+ while (reps)
+ {
+ reps--;
+ *data++ = (Byte)prevByte;
+ crc.UpdateByte(prevByte);
+ if (data == lim)
+ break;
+ }
+ if (data == lim)
+ break;
+ if (blockSize == 0)
+ break;
+ }
+
+ if (blockSize == 1 && reps == -(int)kRleModeRepSize)
+ {
+ unsigned b = (unsigned)(tPos & 0xFF);
+ tPos = tt[tPos >> 8];
+ blockSize--;
+
+ if (_randToGo >= 0)
+ {
+ if (_randToGo == 0)
+ {
+ b ^= 1;
+ _randToGo = kRandNums[_randIndex];
+ _randIndex++;
+ _randIndex &= 0x1FF;
+ }
+ _randToGo--;
+ }
+
+ reps = (int)b;
+ }
+
+ _tPos = tPos;
+ _prevByte = prevByte;
+ _reps = reps;
+ _crc = crc;
+ _blockSize = blockSize;
+
+ return data;
+}
+
+
+HRESULT CDecoder::Flush()
+{
+ if (_writeRes == S_OK)
+ {
+ _writeRes = WriteStream(_outStream, _outBuf, _outPos);
+ _outWritten += _outPos;
+ _outPos = 0;
+ }
+ return _writeRes;
+}
+
+
+NO_INLINE
+HRESULT CDecoder::DecodeBlock(const CBlockProps &props)
+{
+ _calcedBlockCrc = 0;
+ _blockFinished = false;
+
+ CSpecState block;
+
+ block._blockSize = props.blockSize;
+ block._tt = _counters + 256;
+
+ block.Init(props.origPtr, props.randMode);
+
+ for (;;)
+ {
+ Byte *data = _outBuf + _outPos;
+ size_t size = kOutBufSize - _outPos;
+
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outPosTotal;
+ if (size >= rem)
+ {
+ size = (size_t)rem;
+ if (size == 0)
+ return FinishMode ? S_FALSE : S_OK;
+ }
+ }
+
+ TICKS_START
+ const size_t processed = (size_t)(block.Decode(data, size) - data);
+ TICKS_UPDATE(2)
+
+ _outPosTotal += processed;
+ _outPos += processed;
+
+ if (processed >= size)
+ {
+ RINOK(Flush())
+ }
+
+ if (block.Finished())
+ {
+ _blockFinished = true;
+ _calcedBlockCrc = block._crc.GetDigest();
+ return S_OK;
+ }
+ }
+}
+
+
+CDecoder::CDecoder():
+ _outBuf(NULL),
+ FinishMode(false),
+ _outSizeDefined(false),
+ _counters(NULL),
+ _inBuf(NULL),
+ _inProcessed(0)
+{
+ #ifndef Z7_ST
+ MtMode = false;
+ NeedWaitScout = false;
+ // ScoutRes = S_OK;
+ #endif
+}
+
+
+CDecoder::~CDecoder()
+{
+ PRIN("\n~CDecoder()");
+
+ #ifndef Z7_ST
+
+ if (Thread.IsCreated())
+ {
+ WaitScout();
+
+ _block.StopScout = true;
+
+ PRIN("\nScoutEvent.Set()");
+ ScoutEvent.Set();
+
+ PRIN("\nThread.Wait()()");
+ Thread.Wait_Close();
+ PRIN("\n after Thread.Wait()()");
+
+ // if (ScoutRes != S_OK) throw ScoutRes;
+ }
+
+ #endif
+
+ BigFree(_counters);
+ MidFree(_outBuf);
+ MidFree(_inBuf);
+}
+
+
+HRESULT CDecoder::ReadInput()
+{
+ if (Base._buf != Base._lim || _inputFinished || _inputRes != S_OK)
+ return _inputRes;
+
+ _inProcessed += (size_t)(Base._buf - _inBuf);
+ Base._buf = _inBuf;
+ Base._lim = _inBuf;
+ UInt32 size = 0;
+ _inputRes = Base.InStream->Read(_inBuf, kInBufSize, &size);
+ _inputFinished = (size == 0);
+ Base._lim = _inBuf + size;
+ return _inputRes;
+}
+
+
+void CDecoder::StartNewStream()
+{
+ Base.state = STATE_STREAM_SIGNATURE;
+ Base.state2 = 0;
+ Base.IsBz = false;
+}
+
+
+HRESULT CDecoder::ReadStreamSignature()
+{
+ for (;;)
+ {
+ RINOK(ReadInput())
+ SRes res = Base.ReadStreamSignature2();
+ if (res != SZ_OK)
+ return S_FALSE;
+ if (Base.state == STATE_BLOCK_SIGNATURE)
+ return S_OK;
+ if (_inputFinished)
+ {
+ Base.NeedMoreInput = true;
+ return S_FALSE;
+ }
+ }
+}
+
+
+HRESULT CDecoder::StartRead()
+{
+ StartNewStream();
+ return ReadStreamSignature();
+}
+
+
+HRESULT CDecoder::ReadBlockSignature()
+{
+ for (;;)
+ {
+ RINOK(ReadInput())
+
+ SRes res = Base.ReadBlockSignature2();
+
+ if (Base.state == STATE_STREAM_FINISHED)
+ Base.FinishedPackSize = GetInputProcessedSize();
+ if (res != SZ_OK)
+ return S_FALSE;
+ if (Base.state != STATE_BLOCK_SIGNATURE)
+ return S_OK;
+ if (_inputFinished)
+ {
+ Base.NeedMoreInput = true;
+ return S_FALSE;
+ }
+ }
+}
+
+
+HRESULT CDecoder::ReadBlock()
+{
+ for (;;)
+ {
+ RINOK(ReadInput())
+
+ SRes res = Base.ReadBlock2();
+
+ if (res != SZ_OK)
+ return S_FALSE;
+ if (Base.state == STATE_BLOCK_SIGNATURE)
+ return S_OK;
+ if (_inputFinished)
+ {
+ Base.NeedMoreInput = true;
+ return S_FALSE;
+ }
+ }
+}
+
+
+
+HRESULT CDecoder::DecodeStreams(ICompressProgressInfo *progress)
+{
+ {
+ #ifndef Z7_ST
+ _block.StopScout = false;
+ #endif
+ }
+
+ RINOK(StartRead())
+
+ UInt64 inPrev = 0;
+ UInt64 outPrev = 0;
+
+ {
+ #ifndef Z7_ST
+ CWaitScout_Releaser waitScout_Releaser(this);
+
+ bool useMt = false;
+ #endif
+
+ bool wasFinished = false;
+
+ UInt32 crc = 0;
+ UInt32 nextCrc = 0;
+ HRESULT nextRes = S_OK;
+
+ UInt64 packPos = 0;
+
+ CBlockProps props;
+
+ props.blockSize = 0;
+
+ for (;;)
+ {
+ if (progress)
+ {
+ const UInt64 outCur = GetOutProcessedSize();
+ if (packPos - inPrev >= kProgressStep || outCur - outPrev >= kProgressStep)
+ {
+ RINOK(progress->SetRatioInfo(&packPos, &outCur))
+ inPrev = packPos;
+ outPrev = outCur;
+ }
+ }
+
+ if (props.blockSize == 0)
+ if (wasFinished || nextRes != S_OK)
+ return nextRes;
+
+ if (
+ #ifndef Z7_ST
+ !useMt &&
+ #endif
+ !wasFinished && Base.state == STATE_BLOCK_SIGNATURE)
+ {
+ nextRes = ReadBlockSignature();
+ nextCrc = Base.crc;
+ packPos = GetInputProcessedSize();
+
+ wasFinished = true;
+
+ if (nextRes != S_OK)
+ continue;
+
+ if (Base.state == STATE_STREAM_FINISHED)
+ {
+ if (!Base.DecodeAllStreams)
+ {
+ wasFinished = true;
+ continue;
+ }
+
+ nextRes = StartRead();
+
+ if (Base.NeedMoreInput)
+ {
+ if (Base.state2 == 0)
+ Base.NeedMoreInput = false;
+ wasFinished = true;
+ nextRes = S_OK;
+ continue;
+ }
+
+ if (nextRes != S_OK)
+ continue;
+
+ wasFinished = false;
+ continue;
+ }
+
+ wasFinished = false;
+
+ #ifndef Z7_ST
+ if (MtMode)
+ if (props.blockSize != 0)
+ {
+ // we start multithreading, if next block is big enough.
+ const UInt32 k_Mt_BlockSize_Threshold = (1 << 12); // (1 << 13)
+ if (props.blockSize > k_Mt_BlockSize_Threshold)
+ {
+ if (!Thread.IsCreated())
+ {
+ PRIN("=== MT_MODE");
+ RINOK(CreateThread())
+ }
+ useMt = true;
+ }
+ }
+ #endif
+ }
+
+ if (props.blockSize == 0)
+ {
+ crc = nextCrc;
+
+ #ifndef Z7_ST
+ if (useMt)
+ {
+ PRIN("DecoderEvent.Lock()");
+ {
+ WRes wres = DecoderEvent.Lock();
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ }
+ NeedWaitScout = false;
+ PRIN("-- DecoderEvent.Lock()");
+ props = _block.Props;
+ nextCrc = _block.NextCrc;
+ if (_block.Crc_Defined)
+ crc = _block.Crc;
+ packPos = _block.PackPos;
+ wasFinished = _block.WasFinished;
+ RINOK(_block.Res)
+ }
+ else
+ #endif
+ {
+ if (Base.state != STATE_BLOCK_START)
+ return E_FAIL;
+
+ TICKS_START
+ Base.Props.randMode = 1;
+ RINOK(ReadBlock())
+ TICKS_UPDATE(0)
+
+ props = Base.Props;
+ continue;
+ }
+ }
+
+ if (props.blockSize != 0)
+ {
+ TICKS_START
+ DecodeBlock1(_counters, props.blockSize);
+ TICKS_UPDATE(1)
+ }
+
+ #ifndef Z7_ST
+ if (useMt && !wasFinished)
+ {
+ /*
+ if (props.blockSize == 0)
+ {
+ // this codes switches back to single-threadMode
+ useMt = false;
+ PRIN("=== ST_MODE");
+ continue;
+ }
+ */
+
+ PRIN("ScoutEvent.Set()");
+ {
+ WRes wres = ScoutEvent.Set();
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ }
+ NeedWaitScout = true;
+ }
+ #endif
+
+ if (props.blockSize == 0)
+ continue;
+
+ RINOK(DecodeBlock(props))
+
+ if (!_blockFinished)
+ return nextRes;
+
+ props.blockSize = 0;
+ if (_calcedBlockCrc != crc)
+ {
+ BlockCrcError = true;
+ return S_FALSE;
+ }
+ }
+ }
+}
+
+
+
+
+bool CDecoder::CreateInputBufer()
+{
+ if (!_inBuf)
+ {
+ _inBuf = (Byte *)MidAlloc(kInBufSize);
+ if (!_inBuf)
+ return false;
+ Base._buf = _inBuf;
+ Base._lim = _inBuf;
+ }
+ if (!_counters)
+ {
+ const size_t size = (256 + kBlockSizeMax) * sizeof(UInt32)
+ #ifdef BZIP2_BYTE_MODE
+ + kBlockSizeMax
+ #endif
+ + 256;
+ _counters = (UInt32 *)::BigAlloc(size);
+ if (!_counters)
+ return false;
+ Base.Counters = _counters;
+ }
+ return true;
+}
+
+
+void CDecoder::InitOutSize(const UInt64 *outSize)
+{
+ _outPosTotal = 0;
+
+ _outSizeDefined = false;
+ _outSize = 0;
+ if (outSize)
+ {
+ _outSize = *outSize;
+ _outSizeDefined = true;
+ }
+
+ BlockCrcError = false;
+
+ Base.InitNumStreams2();
+}
+
+
+Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ /*
+ {
+ RINOK(SetInStream(inStream));
+ RINOK(SetOutStreamSize(outSize));
+
+ RINOK(CopyStream(this, outStream, progress));
+ return ReleaseInStream();
+ }
+ */
+
+ _inputFinished = false;
+ _inputRes = S_OK;
+ _writeRes = S_OK;
+
+ try {
+
+ InitOutSize(outSize);
+
+ // we can request data from InputBuffer after Code().
+ // so we init InputBuffer before any function return.
+
+ InitInputBuffer();
+
+ if (!CreateInputBufer())
+ return E_OUTOFMEMORY;
+
+ if (!_outBuf)
+ {
+ _outBuf = (Byte *)MidAlloc(kOutBufSize);
+ if (!_outBuf)
+ return E_OUTOFMEMORY;
+ }
+
+ Base.InStream = inStream;
+
+ // InitInputBuffer();
+
+ _outStream = outStream;
+ _outWritten = 0;
+ _outPos = 0;
+
+ HRESULT res = DecodeStreams(progress);
+
+ Flush();
+
+ Base.InStream = NULL;
+ _outStream = NULL;
+
+ /*
+ if (res == S_OK)
+ if (FinishMode && inSize && *inSize != GetInputProcessedSize())
+ res = S_FALSE;
+ */
+
+ if (res != S_OK)
+ return res;
+
+ } catch(...) { return E_FAIL; }
+
+ return _writeRes;
+}
+
+
+Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
+{
+ FinishMode = (finishMode != 0);
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value))
+{
+ *value = GetInStreamSize();
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CDecoder::ReadUnusedFromInBuf(void *data, UInt32 size, UInt32 *processedSize))
+{
+ Base.AlignToByte();
+ UInt32 i;
+ for (i = 0; i < size; i++)
+ {
+ int b;
+ Base.ReadByte(b);
+ if (b < 0)
+ break;
+ ((Byte *)data)[i] = (Byte)b;
+ }
+ if (processedSize)
+ *processedSize = i;
+ return S_OK;
+}
+
+
+#ifndef Z7_ST
+
+#define PRIN_MT(s) PRIN(" " s)
+
+// #define RINOK_THREAD(x) { WRes __result_ = (x); if (__result_ != 0) return __result_; }
+
+static THREAD_FUNC_DECL RunScout2(void *p) { ((CDecoder *)p)->RunScout(); return 0; }
+
+HRESULT CDecoder::CreateThread()
+{
+ WRes wres = DecoderEvent.CreateIfNotCreated_Reset();
+ if (wres == 0) { wres = ScoutEvent.CreateIfNotCreated_Reset();
+ if (wres == 0) { wres = Thread.Create(RunScout2, this); }}
+ return HRESULT_FROM_WIN32(wres);
+}
+
+void CDecoder::RunScout()
+{
+ for (;;)
+ {
+ {
+ PRIN_MT("ScoutEvent.Lock()")
+ WRes wres = ScoutEvent.Lock();
+ PRIN_MT("-- ScoutEvent.Lock()")
+ if (wres != 0)
+ {
+ // ScoutRes = wres;
+ return;
+ }
+ }
+
+ CBlock &block = _block;
+
+ if (block.StopScout)
+ {
+ // ScoutRes = S_OK;
+ return;
+ }
+
+ block.Res = S_OK;
+ block.WasFinished = false;
+
+ HRESULT res = S_OK;
+
+ try
+ {
+ UInt64 packPos = GetInputProcessedSize();
+
+ block.Props.blockSize = 0;
+ block.Crc_Defined = false;
+ // block.NextCrc_Defined = false;
+ block.NextCrc = 0;
+
+ for (;;)
+ {
+ if (Base.state == STATE_BLOCK_SIGNATURE)
+ {
+ res = ReadBlockSignature();
+
+ if (res != S_OK)
+ break;
+
+ if (block.Props.blockSize == 0)
+ {
+ block.Crc = Base.crc;
+ block.Crc_Defined = true;
+ }
+ else
+ {
+ block.NextCrc = Base.crc;
+ // block.NextCrc_Defined = true;
+ }
+
+ continue;
+ }
+
+ if (Base.state == STATE_BLOCK_START)
+ {
+ if (block.Props.blockSize != 0)
+ break;
+
+ Base.Props.randMode = 1;
+
+ res = ReadBlock();
+
+ PRIN_MT("-- Base.ReadBlock")
+ if (res != S_OK)
+ break;
+ block.Props = Base.Props;
+ continue;
+ }
+
+ if (Base.state == STATE_STREAM_FINISHED)
+ {
+ if (!Base.DecodeAllStreams)
+ {
+ block.WasFinished = true;
+ break;
+ }
+
+ res = StartRead();
+
+ if (Base.NeedMoreInput)
+ {
+ if (Base.state2 == 0)
+ Base.NeedMoreInput = false;
+ block.WasFinished = true;
+ res = S_OK;
+ break;
+ }
+
+ if (res != S_OK)
+ break;
+
+ if (GetInputProcessedSize() - packPos > 0) // kProgressStep
+ break;
+ continue;
+ }
+
+ // throw 1;
+ res = E_FAIL;
+ break;
+ }
+ }
+
+ catch (...) { res = E_FAIL; }
+
+ if (res != S_OK)
+ {
+ PRIN_MT("error")
+ block.Res = res;
+ block.WasFinished = true;
+ }
+
+ block.PackPos = GetInputProcessedSize();
+ PRIN_MT("DecoderEvent.Set()")
+ WRes wres = DecoderEvent.Set();
+ if (wres != 0)
+ {
+ // ScoutRes = wres;
+ return;
+ }
+ }
+}
+
+
+Z7_COM7F_IMF(CDecoder::SetNumberOfThreads(UInt32 numThreads))
+{
+ MtMode = (numThreads > 1);
+
+ #ifndef BZIP2_BYTE_MODE
+ MtMode = false;
+ #endif
+
+ // MtMode = false;
+ return S_OK;
+}
+
+#endif
+
+
+
+#ifndef Z7_NO_READ_FROM_CODER
+
+
+Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream))
+{
+ Base.InStreamRef = inStream;
+ Base.InStream = inStream;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CDecoder::ReleaseInStream())
+{
+ Base.InStreamRef.Release();
+ Base.InStream = NULL;
+ return S_OK;
+}
+
+
+
+Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize))
+{
+ InitOutSize(outSize);
+
+ InitInputBuffer();
+
+ if (!CreateInputBufer())
+ return E_OUTOFMEMORY;
+
+ // InitInputBuffer();
+
+ StartNewStream();
+
+ _blockFinished = true;
+
+ ErrorResult = S_OK;
+
+ _inputFinished = false;
+ _inputRes = S_OK;
+
+ return S_OK;
+}
+
+
+
+Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ *processedSize = 0;
+
+ try {
+
+ if (ErrorResult != S_OK)
+ return ErrorResult;
+
+ for (;;)
+ {
+ if (Base.state == STATE_STREAM_FINISHED)
+ {
+ if (!Base.DecodeAllStreams)
+ return ErrorResult;
+ StartNewStream();
+ continue;
+ }
+
+ if (Base.state == STATE_STREAM_SIGNATURE)
+ {
+ ErrorResult = ReadStreamSignature();
+
+ if (Base.NeedMoreInput)
+ if (Base.state2 == 0 && Base.NumStreams != 0)
+ {
+ Base.NeedMoreInput = false;
+ ErrorResult = S_OK;
+ return S_OK;
+ }
+ if (ErrorResult != S_OK)
+ return ErrorResult;
+ continue;
+ }
+
+ if (_blockFinished && Base.state == STATE_BLOCK_SIGNATURE)
+ {
+ ErrorResult = ReadBlockSignature();
+
+ if (ErrorResult != S_OK)
+ return ErrorResult;
+
+ continue;
+ }
+
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outPosTotal;
+ if (size >= rem)
+ size = (UInt32)rem;
+ }
+ if (size == 0)
+ return S_OK;
+
+ if (_blockFinished)
+ {
+ if (Base.state != STATE_BLOCK_START)
+ {
+ ErrorResult = E_FAIL;
+ return ErrorResult;
+ }
+
+ Base.Props.randMode = 1;
+ ErrorResult = ReadBlock();
+
+ if (ErrorResult != S_OK)
+ return ErrorResult;
+
+ DecodeBlock1(_counters, Base.Props.blockSize);
+
+ _spec._blockSize = Base.Props.blockSize;
+ _spec._tt = _counters + 256;
+ _spec.Init(Base.Props.origPtr, Base.Props.randMode);
+
+ _blockFinished = false;
+ }
+
+ {
+ Byte *ptr = _spec.Decode((Byte *)data, size);
+
+ const UInt32 processed = (UInt32)(ptr - (Byte *)data);
+ data = ptr;
+ size -= processed;
+ (*processedSize) += processed;
+ _outPosTotal += processed;
+
+ if (_spec.Finished())
+ {
+ _blockFinished = true;
+ if (Base.crc != _spec._crc.GetDigest())
+ {
+ BlockCrcError = true;
+ ErrorResult = S_FALSE;
+ return ErrorResult;
+ }
+ }
+ }
+ }
+
+ } catch(...) { ErrorResult = S_FALSE; return S_FALSE; }
+}
+
+
+
+// ---------- NSIS ----------
+
+Z7_COM7F_IMF(CNsisDecoder::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ *processedSize = 0;
+
+ try {
+
+ if (ErrorResult != S_OK)
+ return ErrorResult;
+
+ if (Base.state == STATE_STREAM_FINISHED)
+ return S_OK;
+
+ if (Base.state == STATE_STREAM_SIGNATURE)
+ {
+ Base.blockSizeMax = 9 * kBlockSizeStep;
+ Base.state = STATE_BLOCK_SIGNATURE;
+ // Base.state2 = 0;
+ }
+
+ for (;;)
+ {
+ if (_blockFinished && Base.state == STATE_BLOCK_SIGNATURE)
+ {
+ ErrorResult = ReadInput();
+ if (ErrorResult != S_OK)
+ return ErrorResult;
+
+ int b;
+ Base.ReadByte(b);
+ if (b < 0)
+ {
+ ErrorResult = S_FALSE;
+ return ErrorResult;
+ }
+
+ if (b == kFinSig0)
+ {
+ /*
+ if (!Base.AreRemainByteBitsEmpty())
+ ErrorResult = S_FALSE;
+ */
+ Base.state = STATE_STREAM_FINISHED;
+ return ErrorResult;
+ }
+
+ if (b != kBlockSig0)
+ {
+ ErrorResult = S_FALSE;
+ return ErrorResult;
+ }
+
+ Base.state = STATE_BLOCK_START;
+ }
+
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outPosTotal;
+ if (size >= rem)
+ size = (UInt32)rem;
+ }
+ if (size == 0)
+ return S_OK;
+
+ if (_blockFinished)
+ {
+ if (Base.state != STATE_BLOCK_START)
+ {
+ ErrorResult = E_FAIL;
+ return ErrorResult;
+ }
+
+ Base.Props.randMode = 0;
+ ErrorResult = ReadBlock();
+
+ if (ErrorResult != S_OK)
+ return ErrorResult;
+
+ DecodeBlock1(_counters, Base.Props.blockSize);
+
+ _spec._blockSize = Base.Props.blockSize;
+ _spec._tt = _counters + 256;
+ _spec.Init(Base.Props.origPtr, Base.Props.randMode);
+
+ _blockFinished = false;
+ }
+
+ {
+ Byte *ptr = _spec.Decode((Byte *)data, size);
+
+ const UInt32 processed = (UInt32)(ptr - (Byte *)data);
+ data = ptr;
+ size -= processed;
+ (*processedSize) += processed;
+ _outPosTotal += processed;
+
+ if (_spec.Finished())
+ _blockFinished = true;
+ }
+ }
+
+ } catch(...) { ErrorResult = S_FALSE; return S_FALSE; }
+}
+
+#endif
+
+}}
diff --git a/CPP/7zip/Compress/BZip2Decoder.h b/CPP/7zip/Compress/BZip2Decoder.h
new file mode 100644
index 0000000..a8ef700
--- /dev/null
+++ b/CPP/7zip/Compress/BZip2Decoder.h
@@ -0,0 +1,389 @@
+// Compress/BZip2Decoder.h
+
+#ifndef ZIP7_INC_COMPRESS_BZIP2_DECODER_H
+#define ZIP7_INC_COMPRESS_BZIP2_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+// #define Z7_NO_READ_FROM_CODER
+// #define Z7_ST
+
+#ifndef Z7_ST
+#include "../../Windows/Synchronization.h"
+#include "../../Windows/Thread.h"
+#endif
+
+#include "../ICoder.h"
+
+#include "BZip2Const.h"
+#include "BZip2Crc.h"
+#include "HuffmanDecoder.h"
+#include "Mtf8.h"
+
+namespace NCompress {
+namespace NBZip2 {
+
+bool IsEndSig(const Byte *p) throw();
+bool IsBlockSig(const Byte *p) throw();
+
+const unsigned kNumTableBits = 9;
+const unsigned kNumBitsMax = kMaxHuffmanLen;
+
+typedef NHuffman::CDecoder<kMaxHuffmanLen, kMaxAlphaSize, kNumTableBits> CHuffmanDecoder;
+
+
+struct CBlockProps
+{
+ UInt32 blockSize;
+ UInt32 origPtr;
+ unsigned randMode;
+
+ CBlockProps(): blockSize(0), origPtr(0), randMode(0) {}
+};
+
+
+struct CBitDecoder
+{
+ unsigned _numBits;
+ UInt32 _value;
+ const Byte *_buf;
+ const Byte *_lim;
+
+ void InitBitDecoder()
+ {
+ _numBits = 0;
+ _value = 0;
+ }
+
+ void AlignToByte()
+ {
+ unsigned bits = _numBits & 7;
+ _numBits -= bits;
+ _value <<= bits;
+ }
+
+ /*
+ bool AreRemainByteBitsEmpty() const
+ {
+ unsigned bits = _numBits & 7;
+ if (bits != 0)
+ return (_value >> (32 - bits)) == 0;
+ return true;
+ }
+ */
+
+ SRes ReadByte(int &b);
+
+ CBitDecoder():
+ _buf(NULL),
+ _lim(NULL)
+ {
+ InitBitDecoder();
+ }
+};
+
+
+// 19.03: we allow additional 8 selectors to support files created by lbzip2.
+const UInt32 kNumSelectorsMax_Decoder = kNumSelectorsMax + 8;
+
+struct CBase: public CBitDecoder
+{
+ unsigned numInUse;
+ UInt32 groupIndex;
+ UInt32 groupSize;
+ unsigned runPower;
+ UInt32 runCounter;
+ UInt32 blockSize;
+
+ UInt32 *Counters;
+ UInt32 blockSizeMax;
+
+ unsigned state;
+ unsigned state2;
+ unsigned state3;
+ unsigned state4;
+ unsigned state5;
+ unsigned numTables;
+ UInt32 numSelectors;
+
+ CBlockProps Props;
+
+private:
+ CMtf8Decoder mtf;
+ Byte selectors[kNumSelectorsMax_Decoder];
+ CHuffmanDecoder huffs[kNumTablesMax];
+
+ Byte lens[kMaxAlphaSize];
+
+ Byte temp[10];
+
+public:
+ UInt32 crc;
+ CBZip2CombinedCrc CombinedCrc;
+
+ bool IsBz;
+ bool StreamCrcError;
+ bool MinorError;
+ bool NeedMoreInput;
+
+ bool DecodeAllStreams;
+
+ UInt64 NumStreams;
+ UInt64 NumBlocks;
+ UInt64 FinishedPackSize;
+
+ ISequentialInStream *InStream;
+
+ #ifndef Z7_NO_READ_FROM_CODER
+ CMyComPtr<ISequentialInStream> InStreamRef;
+ #endif
+
+ CBase():
+ StreamCrcError(false),
+ MinorError(false),
+ NeedMoreInput(false),
+
+ DecodeAllStreams(false),
+
+ NumStreams(0),
+ NumBlocks(0),
+ FinishedPackSize(0)
+ {}
+
+ void InitNumStreams2()
+ {
+ StreamCrcError = false;
+ MinorError = false;
+ NeedMoreInput = 0;
+ NumStreams = 0;
+ NumBlocks = 0;
+ FinishedPackSize = 0;
+ }
+
+ SRes ReadStreamSignature2();
+ SRes ReadBlockSignature2();
+
+ /* ReadBlock2() : Props->randMode:
+ in: need read randMode bit
+ out: randMode status */
+ SRes ReadBlock2();
+};
+
+
+class CSpecState
+{
+ UInt32 _tPos;
+ unsigned _prevByte;
+ int _reps;
+
+public:
+ CBZip2Crc _crc;
+ UInt32 _blockSize;
+ UInt32 *_tt;
+
+ int _randToGo;
+ unsigned _randIndex;
+
+ void Init(UInt32 origPtr, unsigned randMode) throw();
+
+ bool Finished() const { return _reps <= 0 && _blockSize == 0; }
+
+ Byte *Decode(Byte *data, size_t size) throw();
+};
+
+
+
+
+class CDecoder:
+ public ICompressCoder,
+ public ICompressSetFinishMode,
+ public ICompressGetInStreamProcessedSize,
+ public ICompressReadUnusedFromInBuf,
+#ifndef Z7_NO_READ_FROM_CODER
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public ISequentialInStream,
+#endif
+#ifndef Z7_ST
+ public ICompressSetCoderMt,
+#endif
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(ICompressCoder)
+ Z7_COM_QI_ENTRY(ICompressSetFinishMode)
+ Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize)
+ Z7_COM_QI_ENTRY(ICompressReadUnusedFromInBuf)
+#ifndef Z7_NO_READ_FROM_CODER
+ Z7_COM_QI_ENTRY(ICompressSetInStream)
+ Z7_COM_QI_ENTRY(ICompressSetOutStreamSize)
+ Z7_COM_QI_ENTRY(ISequentialInStream)
+#endif
+#ifndef Z7_ST
+ Z7_COM_QI_ENTRY(ICompressSetCoderMt)
+#endif
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(ICompressCoder)
+ Z7_IFACE_COM7_IMP(ICompressSetFinishMode)
+ Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize)
+ Z7_IFACE_COM7_IMP(ICompressReadUnusedFromInBuf)
+#ifndef Z7_NO_READ_FROM_CODER
+ Z7_IFACE_COM7_IMP(ICompressSetInStream)
+ Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize)
+ Z7_IFACE_COM7_IMP_NONFINAL(ISequentialInStream)
+#endif
+public:
+#ifndef Z7_ST
+ Z7_IFACE_COM7_IMP(ICompressSetCoderMt)
+#endif
+
+private:
+ Byte *_outBuf;
+ size_t _outPos;
+ UInt64 _outWritten;
+ ISequentialOutStream *_outStream;
+ HRESULT _writeRes;
+
+protected:
+ HRESULT ErrorResult; // for ISequentialInStream::Read mode only
+
+public:
+
+ UInt32 _calcedBlockCrc;
+ bool _blockFinished;
+ bool BlockCrcError;
+
+ bool FinishMode;
+ bool _outSizeDefined;
+ UInt64 _outSize;
+ UInt64 _outPosTotal;
+
+ CSpecState _spec;
+ UInt32 *_counters;
+
+ #ifndef Z7_ST
+
+ struct CBlock
+ {
+ bool StopScout;
+
+ bool WasFinished;
+ bool Crc_Defined;
+ // bool NextCrc_Defined;
+
+ UInt32 Crc;
+ UInt32 NextCrc;
+ HRESULT Res;
+ UInt64 PackPos;
+
+ CBlockProps Props;
+ };
+
+ CBlock _block;
+
+ bool NeedWaitScout;
+ bool MtMode;
+
+ NWindows::CThread Thread;
+ NWindows::NSynchronization::CAutoResetEvent DecoderEvent;
+ NWindows::NSynchronization::CAutoResetEvent ScoutEvent;
+ // HRESULT ScoutRes;
+
+ Byte MtPad[1 << 7]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
+
+
+ void RunScout();
+
+ void WaitScout()
+ {
+ if (NeedWaitScout)
+ {
+ DecoderEvent.Lock();
+ NeedWaitScout = false;
+ }
+ }
+
+ class CWaitScout_Releaser
+ {
+ CDecoder *_decoder;
+ public:
+ CWaitScout_Releaser(CDecoder *decoder): _decoder(decoder) {}
+ ~CWaitScout_Releaser() { _decoder->WaitScout(); }
+ };
+
+ HRESULT CreateThread();
+
+ #endif
+
+ Byte *_inBuf;
+ UInt64 _inProcessed;
+ bool _inputFinished;
+ HRESULT _inputRes;
+
+ CBase Base;
+
+ bool GetCrcError() const { return BlockCrcError || Base.StreamCrcError; }
+
+ void InitOutSize(const UInt64 *outSize);
+
+ bool CreateInputBufer();
+
+ void InitInputBuffer()
+ {
+ // We use InitInputBuffer() before stream init.
+ // So don't read from stream here
+ _inProcessed = 0;
+ Base._buf = _inBuf;
+ Base._lim = _inBuf;
+ Base.InitBitDecoder();
+ }
+
+ UInt64 GetInputProcessedSize() const
+ {
+ // for NSIS case : we need also look the number of bits in bitDecoder
+ return _inProcessed + (size_t)(Base._buf - _inBuf);
+ }
+
+ UInt64 GetInStreamSize() const
+ {
+ return _inProcessed + (size_t)(Base._buf - _inBuf) - (Base._numBits >> 3);
+ }
+
+ UInt64 GetOutProcessedSize() const { return _outWritten + _outPos; }
+
+ HRESULT ReadInput();
+
+ void StartNewStream();
+
+ HRESULT ReadStreamSignature();
+ HRESULT StartRead();
+
+ HRESULT ReadBlockSignature();
+ HRESULT ReadBlock();
+
+ HRESULT Flush();
+ HRESULT DecodeBlock(const CBlockProps &props);
+ HRESULT DecodeStreams(ICompressProgressInfo *progress);
+
+ UInt64 GetNumStreams() const { return Base.NumStreams; }
+ UInt64 GetNumBlocks() const { return Base.NumBlocks; }
+
+ CDecoder();
+ virtual ~CDecoder();
+};
+
+
+
+#ifndef Z7_NO_READ_FROM_CODER
+
+class CNsisDecoder Z7_final: public CDecoder
+{
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+};
+
+#endif
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/BZip2Encoder.cpp b/CPP/7zip/Compress/BZip2Encoder.cpp
new file mode 100644
index 0000000..ef2555a
--- /dev/null
+++ b/CPP/7zip/Compress/BZip2Encoder.cpp
@@ -0,0 +1,919 @@
+// BZip2Encoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+#include "../../../C/BwtSort.h"
+#include "../../../C/HuffEnc.h"
+
+#include "BZip2Crc.h"
+#include "BZip2Encoder.h"
+#include "Mtf8.h"
+
+namespace NCompress {
+namespace NBZip2 {
+
+const unsigned kMaxHuffmanLenForEncoding = 16; // it must be < kMaxHuffmanLen = 20
+
+static const UInt32 kBufferSize = (1 << 17);
+static const unsigned kNumHuffPasses = 4;
+
+bool CThreadInfo::Alloc()
+{
+ if (!m_BlockSorterIndex)
+ {
+ m_BlockSorterIndex = (UInt32 *)::BigAlloc(BLOCK_SORT_BUF_SIZE(kBlockSizeMax) * sizeof(UInt32));
+ if (!m_BlockSorterIndex)
+ return false;
+ }
+
+ if (!m_Block)
+ {
+ m_Block = (Byte *)::MidAlloc(kBlockSizeMax * 5 + kBlockSizeMax / 10 + (20 << 10));
+ if (!m_Block)
+ return false;
+ m_MtfArray = m_Block + kBlockSizeMax;
+ m_TempArray = m_MtfArray + kBlockSizeMax * 2 + 2;
+ }
+ return true;
+}
+
+void CThreadInfo::Free()
+{
+ ::BigFree(m_BlockSorterIndex);
+ m_BlockSorterIndex = NULL;
+ ::MidFree(m_Block);
+ m_Block = NULL;
+}
+
+#ifndef Z7_ST
+
+static THREAD_FUNC_DECL MFThread(void *threadCoderInfo)
+{
+ return ((CThreadInfo *)threadCoderInfo)->ThreadFunc();
+}
+
+HRESULT CThreadInfo::Create()
+{
+ WRes wres = StreamWasFinishedEvent.Create();
+ if (wres == 0) { wres = WaitingWasStartedEvent.Create();
+ if (wres == 0) { wres = CanWriteEvent.Create();
+ if (wres == 0)
+ {
+ if (Encoder->_props.Affinity != 0)
+ wres = Thread.Create_With_Affinity(MFThread, this, (CAffinityMask)Encoder->_props.Affinity);
+ else
+ wres = Thread.Create(MFThread, this);
+ }}}
+ return HRESULT_FROM_WIN32(wres);
+}
+
+void CThreadInfo::FinishStream(bool needLeave)
+{
+ Encoder->StreamWasFinished = true;
+ StreamWasFinishedEvent.Set();
+ if (needLeave)
+ Encoder->CS.Leave();
+ Encoder->CanStartWaitingEvent.Lock();
+ WaitingWasStartedEvent.Set();
+}
+
+THREAD_FUNC_RET_TYPE CThreadInfo::ThreadFunc()
+{
+ for (;;)
+ {
+ Encoder->CanProcessEvent.Lock();
+ Encoder->CS.Enter();
+ if (Encoder->CloseThreads)
+ {
+ Encoder->CS.Leave();
+ return 0;
+ }
+ if (Encoder->StreamWasFinished)
+ {
+ FinishStream(true);
+ continue;
+ }
+ HRESULT res = S_OK;
+ bool needLeave = true;
+ try
+ {
+ const UInt32 blockSize = Encoder->ReadRleBlock(m_Block);
+ m_UnpackSize = Encoder->m_InStream.GetProcessedSize();
+ m_BlockIndex = Encoder->NextBlockIndex;
+ if (++Encoder->NextBlockIndex == Encoder->NumThreads)
+ Encoder->NextBlockIndex = 0;
+ if (blockSize == 0)
+ {
+ FinishStream(true);
+ continue;
+ }
+ Encoder->CS.Leave();
+ needLeave = false;
+ res = EncodeBlock3(blockSize);
+ }
+ catch(const CInBufferException &e) { res = e.ErrorCode; }
+ catch(const COutBufferException &e) { res = e.ErrorCode; }
+ catch(...) { res = E_FAIL; }
+ if (res != S_OK)
+ {
+ Encoder->Result = res;
+ FinishStream(needLeave);
+ continue;
+ }
+ }
+}
+
+#endif
+
+void CEncProps::Normalize(int level)
+{
+ if (level < 0) level = 5;
+ if (level > 9) level = 9;
+
+ if (NumPasses == (UInt32)(Int32)-1)
+ NumPasses = (level >= 9 ? 7 : (level >= 7 ? 2 : 1));
+ if (NumPasses < 1) NumPasses = 1;
+ if (NumPasses > kNumPassesMax) NumPasses = kNumPassesMax;
+
+ if (BlockSizeMult == (UInt32)(Int32)-1)
+ BlockSizeMult = (level >= 5 ? 9 : (level >= 1 ? (unsigned)level * 2 - 1: 1));
+ if (BlockSizeMult < kBlockSizeMultMin) BlockSizeMult = kBlockSizeMultMin;
+ if (BlockSizeMult > kBlockSizeMultMax) BlockSizeMult = kBlockSizeMultMax;
+}
+
+CEncoder::CEncoder()
+{
+ _props.Normalize(-1);
+
+ #ifndef Z7_ST
+ ThreadsInfo = NULL;
+ m_NumThreadsPrev = 0;
+ NumThreads = 1;
+ #endif
+}
+
+#ifndef Z7_ST
+CEncoder::~CEncoder()
+{
+ Free();
+}
+
+HRESULT CEncoder::Create()
+{
+ {
+ WRes wres = CanProcessEvent.CreateIfNotCreated_Reset();
+ if (wres == 0) { wres = CanStartWaitingEvent.CreateIfNotCreated_Reset(); }
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ }
+
+ if (ThreadsInfo && m_NumThreadsPrev == NumThreads)
+ return S_OK;
+ try
+ {
+ Free();
+ MtMode = (NumThreads > 1);
+ m_NumThreadsPrev = NumThreads;
+ ThreadsInfo = new CThreadInfo[NumThreads];
+ if (!ThreadsInfo)
+ return E_OUTOFMEMORY;
+ }
+ catch(...) { return E_OUTOFMEMORY; }
+ for (UInt32 t = 0; t < NumThreads; t++)
+ {
+ CThreadInfo &ti = ThreadsInfo[t];
+ ti.Encoder = this;
+ if (MtMode)
+ {
+ HRESULT res = ti.Create();
+ if (res != S_OK)
+ {
+ NumThreads = t;
+ Free();
+ return res;
+ }
+ }
+ }
+ return S_OK;
+}
+
+void CEncoder::Free()
+{
+ if (!ThreadsInfo)
+ return;
+ CloseThreads = true;
+ CanProcessEvent.Set();
+ for (UInt32 t = 0; t < NumThreads; t++)
+ {
+ CThreadInfo &ti = ThreadsInfo[t];
+ if (MtMode)
+ ti.Thread.Wait_Close();
+ ti.Free();
+ }
+ delete []ThreadsInfo;
+ ThreadsInfo = NULL;
+}
+#endif
+
+UInt32 CEncoder::ReadRleBlock(Byte *buffer)
+{
+ UInt32 i = 0;
+ Byte prevByte;
+ if (m_InStream.ReadByte(prevByte))
+ {
+ NumBlocks++;
+ const UInt32 blockSize = _props.BlockSizeMult * kBlockSizeStep - 1;
+ unsigned numReps = 1;
+ buffer[i++] = prevByte;
+ while (i < blockSize) // "- 1" to support RLE
+ {
+ Byte b;
+ if (!m_InStream.ReadByte(b))
+ break;
+ if (b != prevByte)
+ {
+ if (numReps >= kRleModeRepSize)
+ buffer[i++] = (Byte)(numReps - kRleModeRepSize);
+ buffer[i++] = b;
+ numReps = 1;
+ prevByte = b;
+ continue;
+ }
+ numReps++;
+ if (numReps <= kRleModeRepSize)
+ buffer[i++] = b;
+ else if (numReps == kRleModeRepSize + 255)
+ {
+ buffer[i++] = (Byte)(numReps - kRleModeRepSize);
+ numReps = 0;
+ }
+ }
+ // it's to support original BZip2 decoder
+ if (numReps >= kRleModeRepSize)
+ buffer[i++] = (Byte)(numReps - kRleModeRepSize);
+ }
+ return i;
+}
+
+void CThreadInfo::WriteBits2(UInt32 value, unsigned numBits) { m_OutStreamCurrent->WriteBits(value, numBits); }
+void CThreadInfo::WriteByte2(Byte b) { WriteBits2(b, 8); }
+void CThreadInfo::WriteBit2(Byte v) { WriteBits2(v, 1); }
+void CThreadInfo::WriteCrc2(UInt32 v)
+{
+ for (unsigned i = 0; i < 4; i++)
+ WriteByte2(((Byte)(v >> (24 - i * 8))));
+}
+
+void CEncoder::WriteBits(UInt32 value, unsigned numBits) { m_OutStream.WriteBits(value, numBits); }
+void CEncoder::WriteByte(Byte b) { WriteBits(b, 8); }
+// void CEncoder::WriteBit(Byte v) { WriteBits(v, 1); }
+void CEncoder::WriteCrc(UInt32 v)
+{
+ for (unsigned i = 0; i < 4; i++)
+ WriteByte(((Byte)(v >> (24 - i * 8))));
+}
+
+
+// blockSize > 0
+void CThreadInfo::EncodeBlock(const Byte *block, UInt32 blockSize)
+{
+ WriteBit2(0); // Randomised = false
+
+ {
+ UInt32 origPtr = BlockSort(m_BlockSorterIndex, block, blockSize);
+ // if (m_BlockSorterIndex[origPtr] != 0) throw 1;
+ m_BlockSorterIndex[origPtr] = blockSize;
+ WriteBits2(origPtr, kNumOrigBits);
+ }
+
+ CMtf8Encoder mtf;
+ unsigned numInUse = 0;
+ {
+ Byte inUse[256];
+ Byte inUse16[16];
+ UInt32 i;
+ for (i = 0; i < 256; i++)
+ inUse[i] = 0;
+ for (i = 0; i < 16; i++)
+ inUse16[i] = 0;
+ for (i = 0; i < blockSize; i++)
+ inUse[block[i]] = 1;
+ for (i = 0; i < 256; i++)
+ if (inUse[i])
+ {
+ inUse16[i >> 4] = 1;
+ mtf.Buf[numInUse++] = (Byte)i;
+ }
+ for (i = 0; i < 16; i++)
+ WriteBit2(inUse16[i]);
+ for (i = 0; i < 256; i++)
+ if (inUse16[i >> 4])
+ WriteBit2(inUse[i]);
+ }
+ unsigned alphaSize = numInUse + 2;
+
+ Byte *mtfs = m_MtfArray;
+ UInt32 mtfArraySize = 0;
+ UInt32 symbolCounts[kMaxAlphaSize];
+ {
+ for (unsigned i = 0; i < kMaxAlphaSize; i++)
+ symbolCounts[i] = 0;
+ }
+
+ {
+ UInt32 rleSize = 0;
+ UInt32 i = 0;
+ const UInt32 *bsIndex = m_BlockSorterIndex;
+ block--;
+ do
+ {
+ unsigned pos = mtf.FindAndMove(block[bsIndex[i]]);
+ if (pos == 0)
+ rleSize++;
+ else
+ {
+ while (rleSize != 0)
+ {
+ rleSize--;
+ mtfs[mtfArraySize++] = (Byte)(rleSize & 1);
+ symbolCounts[rleSize & 1]++;
+ rleSize >>= 1;
+ }
+ if (pos >= 0xFE)
+ {
+ mtfs[mtfArraySize++] = 0xFF;
+ mtfs[mtfArraySize++] = (Byte)(pos - 0xFE);
+ }
+ else
+ mtfs[mtfArraySize++] = (Byte)(pos + 1);
+ symbolCounts[(size_t)pos + 1]++;
+ }
+ }
+ while (++i < blockSize);
+
+ while (rleSize != 0)
+ {
+ rleSize--;
+ mtfs[mtfArraySize++] = (Byte)(rleSize & 1);
+ symbolCounts[rleSize & 1]++;
+ rleSize >>= 1;
+ }
+
+ if (alphaSize < 256)
+ mtfs[mtfArraySize++] = (Byte)(alphaSize - 1);
+ else
+ {
+ mtfs[mtfArraySize++] = 0xFF;
+ mtfs[mtfArraySize++] = (Byte)(alphaSize - 256);
+ }
+ symbolCounts[(size_t)alphaSize - 1]++;
+ }
+
+ UInt32 numSymbols = 0;
+ {
+ for (unsigned i = 0; i < kMaxAlphaSize; i++)
+ numSymbols += symbolCounts[i];
+ }
+
+ unsigned bestNumTables = kNumTablesMin;
+ UInt32 bestPrice = 0xFFFFFFFF;
+ UInt32 startPos = m_OutStreamCurrent->GetPos();
+ Byte startCurByte = m_OutStreamCurrent->GetCurByte();
+ for (unsigned nt = kNumTablesMin; nt <= kNumTablesMax + 1; nt++)
+ {
+ unsigned numTables;
+
+ if (m_OptimizeNumTables)
+ {
+ m_OutStreamCurrent->SetPos(startPos);
+ m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte);
+ if (nt <= kNumTablesMax)
+ numTables = nt;
+ else
+ numTables = bestNumTables;
+ }
+ else
+ {
+ if (numSymbols < 200) numTables = 2;
+ else if (numSymbols < 600) numTables = 3;
+ else if (numSymbols < 1200) numTables = 4;
+ else if (numSymbols < 2400) numTables = 5;
+ else numTables = 6;
+ }
+
+ WriteBits2(numTables, kNumTablesBits);
+
+ UInt32 numSelectors = (numSymbols + kGroupSize - 1) / kGroupSize;
+ WriteBits2(numSelectors, kNumSelectorsBits);
+
+ {
+ UInt32 remFreq = numSymbols;
+ unsigned gs = 0;
+ unsigned t = numTables;
+ do
+ {
+ UInt32 tFreq = remFreq / t;
+ unsigned ge = gs;
+ UInt32 aFreq = 0;
+ while (aFreq < tFreq) // && ge < alphaSize)
+ aFreq += symbolCounts[ge++];
+
+ if (ge > gs + 1 && t != numTables && t != 1 && (((numTables - t) & 1) == 1))
+ aFreq -= symbolCounts[--ge];
+
+ Byte *lens = Lens[(size_t)t - 1];
+ unsigned i = 0;
+ do
+ lens[i] = (Byte)((i >= gs && i < ge) ? 0 : 1);
+ while (++i < alphaSize);
+ gs = ge;
+ remFreq -= aFreq;
+ }
+ while (--t != 0);
+ }
+
+
+ for (unsigned pass = 0; pass < kNumHuffPasses; pass++)
+ {
+ {
+ unsigned t = 0;
+ do
+ memset(Freqs[t], 0, sizeof(Freqs[t]));
+ while (++t < numTables);
+ }
+
+ {
+ UInt32 mtfPos = 0;
+ UInt32 g = 0;
+ do
+ {
+ UInt32 symbols[kGroupSize];
+ unsigned i = 0;
+ do
+ {
+ UInt32 symbol = mtfs[mtfPos++];
+ if (symbol >= 0xFF)
+ symbol += mtfs[mtfPos++];
+ symbols[i] = symbol;
+ }
+ while (++i < kGroupSize && mtfPos < mtfArraySize);
+
+ UInt32 bestPrice2 = 0xFFFFFFFF;
+ unsigned t = 0;
+ do
+ {
+ const Byte *lens = Lens[t];
+ UInt32 price = 0;
+ unsigned j = 0;
+ do
+ price += lens[symbols[j]];
+ while (++j < i);
+ if (price < bestPrice2)
+ {
+ m_Selectors[g] = (Byte)t;
+ bestPrice2 = price;
+ }
+ }
+ while (++t < numTables);
+ UInt32 *freqs = Freqs[m_Selectors[g++]];
+ unsigned j = 0;
+ do
+ freqs[symbols[j]]++;
+ while (++j < i);
+ }
+ while (mtfPos < mtfArraySize);
+ }
+
+ unsigned t = 0;
+ do
+ {
+ UInt32 *freqs = Freqs[t];
+ unsigned i = 0;
+ do
+ if (freqs[i] == 0)
+ freqs[i] = 1;
+ while (++i < alphaSize);
+ Huffman_Generate(freqs, Codes[t], Lens[t], kMaxAlphaSize, kMaxHuffmanLenForEncoding);
+ }
+ while (++t < numTables);
+ }
+
+ {
+ Byte mtfSel[kNumTablesMax];
+ {
+ unsigned t = 0;
+ do
+ mtfSel[t] = (Byte)t;
+ while (++t < numTables);
+ }
+
+ UInt32 i = 0;
+ do
+ {
+ Byte sel = m_Selectors[i];
+ unsigned pos;
+ for (pos = 0; mtfSel[pos] != sel; pos++)
+ WriteBit2(1);
+ WriteBit2(0);
+ for (; pos > 0; pos--)
+ mtfSel[pos] = mtfSel[(size_t)pos - 1];
+ mtfSel[0] = sel;
+ }
+ while (++i < numSelectors);
+ }
+
+ {
+ unsigned t = 0;
+ do
+ {
+ const Byte *lens = Lens[t];
+ UInt32 len = lens[0];
+ WriteBits2(len, kNumLevelsBits);
+ unsigned i = 0;
+ do
+ {
+ UInt32 level = lens[i];
+ while (len != level)
+ {
+ WriteBit2(1);
+ if (len < level)
+ {
+ WriteBit2(0);
+ len++;
+ }
+ else
+ {
+ WriteBit2(1);
+ len--;
+ }
+ }
+ WriteBit2(0);
+ }
+ while (++i < alphaSize);
+ }
+ while (++t < numTables);
+ }
+
+ {
+ UInt32 groupSize = 0;
+ UInt32 groupIndex = 0;
+ const Byte *lens = NULL;
+ const UInt32 *codes = NULL;
+ UInt32 mtfPos = 0;
+ do
+ {
+ UInt32 symbol = mtfs[mtfPos++];
+ if (symbol >= 0xFF)
+ symbol += mtfs[mtfPos++];
+ if (groupSize == 0)
+ {
+ groupSize = kGroupSize;
+ unsigned t = m_Selectors[groupIndex++];
+ lens = Lens[t];
+ codes = Codes[t];
+ }
+ groupSize--;
+ m_OutStreamCurrent->WriteBits(codes[symbol], lens[symbol]);
+ }
+ while (mtfPos < mtfArraySize);
+ }
+
+ if (!m_OptimizeNumTables)
+ break;
+ UInt32 price = m_OutStreamCurrent->GetPos() - startPos;
+ if (price <= bestPrice)
+ {
+ if (nt == kNumTablesMax)
+ break;
+ bestPrice = price;
+ bestNumTables = nt;
+ }
+ }
+}
+
+// blockSize > 0
+UInt32 CThreadInfo::EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize)
+{
+ WriteByte2(kBlockSig0);
+ WriteByte2(kBlockSig1);
+ WriteByte2(kBlockSig2);
+ WriteByte2(kBlockSig3);
+ WriteByte2(kBlockSig4);
+ WriteByte2(kBlockSig5);
+
+ CBZip2Crc crc;
+ unsigned numReps = 0;
+ Byte prevByte = block[0];
+ UInt32 i = 0;
+ do
+ {
+ Byte b = block[i];
+ if (numReps == kRleModeRepSize)
+ {
+ for (; b > 0; b--)
+ crc.UpdateByte(prevByte);
+ numReps = 0;
+ continue;
+ }
+ if (prevByte == b)
+ numReps++;
+ else
+ {
+ numReps = 1;
+ prevByte = b;
+ }
+ crc.UpdateByte(b);
+ }
+ while (++i < blockSize);
+ UInt32 crcRes = crc.GetDigest();
+ WriteCrc2(crcRes);
+ EncodeBlock(block, blockSize);
+ return crcRes;
+}
+
+void CThreadInfo::EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses)
+{
+ UInt32 numCrcs = m_NumCrcs;
+ bool needCompare = false;
+
+ UInt32 startBytePos = m_OutStreamCurrent->GetBytePos();
+ UInt32 startPos = m_OutStreamCurrent->GetPos();
+ Byte startCurByte = m_OutStreamCurrent->GetCurByte();
+ Byte endCurByte = 0;
+ UInt32 endPos = 0;
+ if (numPasses > 1 && blockSize >= (1 << 10))
+ {
+ UInt32 blockSize0 = blockSize / 2; // ????
+
+ for (; (block[blockSize0] == block[(size_t)blockSize0 - 1]
+ || block[(size_t)blockSize0 - 1] == block[(size_t)blockSize0 - 2])
+ && blockSize0 < blockSize;
+ blockSize0++);
+
+ if (blockSize0 < blockSize)
+ {
+ EncodeBlock2(block, blockSize0, numPasses - 1);
+ EncodeBlock2(block + blockSize0, blockSize - blockSize0, numPasses - 1);
+ endPos = m_OutStreamCurrent->GetPos();
+ endCurByte = m_OutStreamCurrent->GetCurByte();
+ if ((endPos & 7) > 0)
+ WriteBits2(0, 8 - (endPos & 7));
+ m_OutStreamCurrent->SetCurState((startPos & 7), startCurByte);
+ needCompare = true;
+ }
+ }
+
+ UInt32 startBytePos2 = m_OutStreamCurrent->GetBytePos();
+ UInt32 startPos2 = m_OutStreamCurrent->GetPos();
+ UInt32 crcVal = EncodeBlockWithHeaders(block, blockSize);
+ UInt32 endPos2 = m_OutStreamCurrent->GetPos();
+
+ if (needCompare)
+ {
+ UInt32 size2 = endPos2 - startPos2;
+ if (size2 < endPos - startPos)
+ {
+ UInt32 numBytes = m_OutStreamCurrent->GetBytePos() - startBytePos2;
+ Byte *buffer = m_OutStreamCurrent->GetStream();
+ for (UInt32 i = 0; i < numBytes; i++)
+ buffer[startBytePos + i] = buffer[startBytePos2 + i];
+ m_OutStreamCurrent->SetPos(startPos + endPos2 - startPos2);
+ m_NumCrcs = numCrcs;
+ m_CRCs[m_NumCrcs++] = crcVal;
+ }
+ else
+ {
+ m_OutStreamCurrent->SetPos(endPos);
+ m_OutStreamCurrent->SetCurState((endPos & 7), endCurByte);
+ }
+ }
+ else
+ {
+ m_NumCrcs = numCrcs;
+ m_CRCs[m_NumCrcs++] = crcVal;
+ }
+}
+
+HRESULT CThreadInfo::EncodeBlock3(UInt32 blockSize)
+{
+ CMsbfEncoderTemp outStreamTemp;
+ outStreamTemp.SetStream(m_TempArray);
+ outStreamTemp.Init();
+ m_OutStreamCurrent = &outStreamTemp;
+
+ m_NumCrcs = 0;
+
+ EncodeBlock2(m_Block, blockSize, Encoder->_props.NumPasses);
+
+ #ifndef Z7_ST
+ if (Encoder->MtMode)
+ Encoder->ThreadsInfo[m_BlockIndex].CanWriteEvent.Lock();
+ #endif
+ for (UInt32 i = 0; i < m_NumCrcs; i++)
+ Encoder->CombinedCrc.Update(m_CRCs[i]);
+ Encoder->WriteBytes(m_TempArray, outStreamTemp.GetPos(), outStreamTemp.GetCurByte());
+ HRESULT res = S_OK;
+ #ifndef Z7_ST
+ if (Encoder->MtMode)
+ {
+ UInt32 blockIndex = m_BlockIndex + 1;
+ if (blockIndex == Encoder->NumThreads)
+ blockIndex = 0;
+
+ if (Encoder->Progress)
+ {
+ const UInt64 packSize = Encoder->m_OutStream.GetProcessedSize();
+ res = Encoder->Progress->SetRatioInfo(&m_UnpackSize, &packSize);
+ }
+
+ Encoder->ThreadsInfo[blockIndex].CanWriteEvent.Set();
+ }
+ #endif
+ return res;
+}
+
+void CEncoder::WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte)
+{
+ UInt32 bytesSize = (sizeInBits >> 3);
+ for (UInt32 i = 0; i < bytesSize; i++)
+ m_OutStream.WriteBits(data[i], 8);
+ WriteBits(lastByte, (sizeInBits & 7));
+}
+
+
+HRESULT CEncoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ NumBlocks = 0;
+ #ifndef Z7_ST
+ Progress = progress;
+ RINOK(Create())
+ for (UInt32 t = 0; t < NumThreads; t++)
+ #endif
+ {
+ #ifndef Z7_ST
+ CThreadInfo &ti = ThreadsInfo[t];
+ if (MtMode)
+ {
+ WRes wres = ti.StreamWasFinishedEvent.Reset();
+ if (wres == 0) { wres = ti.WaitingWasStartedEvent.Reset();
+ if (wres == 0) { wres = ti.CanWriteEvent.Reset(); }}
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ }
+ #else
+ CThreadInfo &ti = ThreadsInfo;
+ ti.Encoder = this;
+ #endif
+
+ ti.m_OptimizeNumTables = _props.DoOptimizeNumTables();
+
+ if (!ti.Alloc())
+ return E_OUTOFMEMORY;
+ }
+
+
+ if (!m_InStream.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+ if (!m_OutStream.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+
+
+ m_InStream.SetStream(inStream);
+ m_InStream.Init();
+
+ m_OutStream.SetStream(outStream);
+ m_OutStream.Init();
+
+ CombinedCrc.Init();
+ #ifndef Z7_ST
+ NextBlockIndex = 0;
+ StreamWasFinished = false;
+ CloseThreads = false;
+ CanStartWaitingEvent.Reset();
+ #endif
+
+ WriteByte(kArSig0);
+ WriteByte(kArSig1);
+ WriteByte(kArSig2);
+ WriteByte((Byte)(kArSig3 + _props.BlockSizeMult));
+
+ #ifndef Z7_ST
+
+ if (MtMode)
+ {
+ ThreadsInfo[0].CanWriteEvent.Set();
+ Result = S_OK;
+ CanProcessEvent.Set();
+ UInt32 t;
+ for (t = 0; t < NumThreads; t++)
+ ThreadsInfo[t].StreamWasFinishedEvent.Lock();
+ CanProcessEvent.Reset();
+ CanStartWaitingEvent.Set();
+ for (t = 0; t < NumThreads; t++)
+ ThreadsInfo[t].WaitingWasStartedEvent.Lock();
+ CanStartWaitingEvent.Reset();
+ RINOK(Result)
+ }
+ else
+ #endif
+ {
+ for (;;)
+ {
+ CThreadInfo &ti =
+ #ifndef Z7_ST
+ ThreadsInfo[0];
+ #else
+ ThreadsInfo;
+ #endif
+ UInt32 blockSize = ReadRleBlock(ti.m_Block);
+ if (blockSize == 0)
+ break;
+ RINOK(ti.EncodeBlock3(blockSize))
+ if (progress)
+ {
+ const UInt64 unpackSize = m_InStream.GetProcessedSize();
+ const UInt64 packSize = m_OutStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&unpackSize, &packSize))
+ }
+ }
+ }
+ WriteByte(kFinSig0);
+ WriteByte(kFinSig1);
+ WriteByte(kFinSig2);
+ WriteByte(kFinSig3);
+ WriteByte(kFinSig4);
+ WriteByte(kFinSig5);
+
+ WriteCrc(CombinedCrc.GetDigest());
+ RINOK(Flush())
+ if (!m_InStream.WasFinished())
+ return E_FAIL;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps))
+{
+ int level = -1;
+ CEncProps props;
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = coderProps[i];
+ PROPID propID = propIDs[i];
+
+ if (propID == NCoderPropID::kAffinity)
+ {
+ if (prop.vt == VT_UI8)
+ props.Affinity = prop.uhVal.QuadPart;
+ else
+ return E_INVALIDARG;
+ continue;
+ }
+
+ if (propID >= NCoderPropID::kReduceSize)
+ continue;
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 v = (UInt32)prop.ulVal;
+ switch (propID)
+ {
+ case NCoderPropID::kNumPasses: props.NumPasses = v; break;
+ case NCoderPropID::kDictionarySize: props.BlockSizeMult = v / kBlockSizeStep; break;
+ case NCoderPropID::kLevel: level = (int)v; break;
+ case NCoderPropID::kNumThreads:
+ {
+ #ifndef Z7_ST
+ SetNumberOfThreads(v);
+ #endif
+ break;
+ }
+ default: return E_INVALIDARG;
+ }
+ }
+ props.Normalize(level);
+ _props = props;
+ return S_OK;
+}
+
+#ifndef Z7_ST
+Z7_COM7F_IMF(CEncoder::SetNumberOfThreads(UInt32 numThreads))
+{
+ const UInt32 kNumThreadsMax = 64;
+ if (numThreads < 1) numThreads = 1;
+ if (numThreads > kNumThreadsMax) numThreads = kNumThreadsMax;
+ NumThreads = numThreads;
+ return S_OK;
+}
+#endif
+
+}}
diff --git a/CPP/7zip/Compress/BZip2Encoder.h b/CPP/7zip/Compress/BZip2Encoder.h
new file mode 100644
index 0000000..4a04fbd
--- /dev/null
+++ b/CPP/7zip/Compress/BZip2Encoder.h
@@ -0,0 +1,247 @@
+// BZip2Encoder.h
+
+#ifndef ZIP7_INC_COMPRESS_BZIP2_ENCODER_H
+#define ZIP7_INC_COMPRESS_BZIP2_ENCODER_H
+
+#include "../../Common/Defs.h"
+#include "../../Common/MyCom.h"
+
+#ifndef Z7_ST
+#include "../../Windows/Synchronization.h"
+#include "../../Windows/Thread.h"
+#endif
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/OutBuffer.h"
+
+#include "BitmEncoder.h"
+#include "BZip2Const.h"
+#include "BZip2Crc.h"
+
+namespace NCompress {
+namespace NBZip2 {
+
+class CMsbfEncoderTemp
+{
+ UInt32 _pos;
+ unsigned _bitPos;
+ Byte _curByte;
+ Byte *_buf;
+public:
+ void SetStream(Byte *buf) { _buf = buf; }
+ Byte *GetStream() const { return _buf; }
+
+ void Init()
+ {
+ _pos = 0;
+ _bitPos = 8;
+ _curByte = 0;
+ }
+
+ void Flush()
+ {
+ if (_bitPos < 8)
+ WriteBits(0, _bitPos);
+ }
+
+ void WriteBits(UInt32 value, unsigned numBits)
+ {
+ while (numBits > 0)
+ {
+ unsigned numNewBits = MyMin(numBits, _bitPos);
+ numBits -= numNewBits;
+
+ _curByte = (Byte)(_curByte << numNewBits);
+ UInt32 newBits = value >> numBits;
+ _curByte |= Byte(newBits);
+ value -= (newBits << numBits);
+
+ _bitPos -= numNewBits;
+
+ if (_bitPos == 0)
+ {
+ _buf[_pos++] = _curByte;
+ _bitPos = 8;
+ }
+ }
+ }
+
+ UInt32 GetBytePos() const { return _pos ; }
+ UInt32 GetPos() const { return _pos * 8 + (8 - _bitPos); }
+ Byte GetCurByte() const { return _curByte; }
+ void SetPos(UInt32 bitPos)
+ {
+ _pos = bitPos >> 3;
+ _bitPos = 8 - ((unsigned)bitPos & 7);
+ }
+ void SetCurState(unsigned bitPos, Byte curByte)
+ {
+ _bitPos = 8 - bitPos;
+ _curByte = curByte;
+ }
+};
+
+class CEncoder;
+
+const unsigned kNumPassesMax = 10;
+
+class CThreadInfo
+{
+public:
+ Byte *m_Block;
+private:
+ Byte *m_MtfArray;
+ Byte *m_TempArray;
+ UInt32 *m_BlockSorterIndex;
+
+ CMsbfEncoderTemp *m_OutStreamCurrent;
+
+ Byte Lens[kNumTablesMax][kMaxAlphaSize];
+ UInt32 Freqs[kNumTablesMax][kMaxAlphaSize];
+ UInt32 Codes[kNumTablesMax][kMaxAlphaSize];
+
+ Byte m_Selectors[kNumSelectorsMax];
+
+ UInt32 m_CRCs[1 << kNumPassesMax];
+ UInt32 m_NumCrcs;
+
+ void WriteBits2(UInt32 value, unsigned numBits);
+ void WriteByte2(Byte b);
+ void WriteBit2(Byte v);
+ void WriteCrc2(UInt32 v);
+
+ void EncodeBlock(const Byte *block, UInt32 blockSize);
+ UInt32 EncodeBlockWithHeaders(const Byte *block, UInt32 blockSize);
+ void EncodeBlock2(const Byte *block, UInt32 blockSize, UInt32 numPasses);
+public:
+ bool m_OptimizeNumTables;
+ CEncoder *Encoder;
+ #ifndef Z7_ST
+ NWindows::CThread Thread;
+
+ NWindows::NSynchronization::CAutoResetEvent StreamWasFinishedEvent;
+ NWindows::NSynchronization::CAutoResetEvent WaitingWasStartedEvent;
+
+ // it's not member of this thread. We just need one event per thread
+ NWindows::NSynchronization::CAutoResetEvent CanWriteEvent;
+
+private:
+ UInt32 m_BlockIndex;
+ UInt64 m_UnpackSize;
+public:
+ Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
+ HRESULT Create();
+ void FinishStream(bool needLeave);
+ THREAD_FUNC_RET_TYPE ThreadFunc();
+ #endif
+
+ CThreadInfo(): m_Block(NULL), m_BlockSorterIndex(NULL) {}
+ ~CThreadInfo() { Free(); }
+ bool Alloc();
+ void Free();
+
+ HRESULT EncodeBlock3(UInt32 blockSize);
+};
+
+struct CEncProps
+{
+ UInt32 BlockSizeMult;
+ UInt32 NumPasses;
+ UInt64 Affinity;
+
+ CEncProps()
+ {
+ BlockSizeMult = (UInt32)(Int32)-1;
+ NumPasses = (UInt32)(Int32)-1;
+ Affinity = 0;
+ }
+ void Normalize(int level);
+ bool DoOptimizeNumTables() const { return NumPasses > 1; }
+};
+
+class CEncoder Z7_final:
+ public ICompressCoder,
+ public ICompressSetCoderProperties,
+ #ifndef Z7_ST
+ public ICompressSetCoderMt,
+ #endif
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(ICompressCoder)
+ Z7_COM_QI_ENTRY(ICompressSetCoderProperties)
+ #ifndef Z7_ST
+ Z7_COM_QI_ENTRY(ICompressSetCoderMt)
+ #endif
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(ICompressCoder)
+ Z7_IFACE_COM7_IMP(ICompressSetCoderProperties)
+ #ifndef Z7_ST
+ Z7_IFACE_COM7_IMP(ICompressSetCoderMt)
+ #endif
+
+ #ifndef Z7_ST
+ UInt32 m_NumThreadsPrev;
+ #endif
+public:
+ CInBuffer m_InStream;
+ #ifndef Z7_ST
+ Byte MtPad[1 << 8]; // It's pad for Multi-Threading. Must be >= Cache_Line_Size.
+ #endif
+ CBitmEncoder<COutBuffer> m_OutStream;
+ CEncProps _props;
+ CBZip2CombinedCrc CombinedCrc;
+
+ #ifndef Z7_ST
+ CThreadInfo *ThreadsInfo;
+ NWindows::NSynchronization::CManualResetEvent CanProcessEvent;
+ NWindows::NSynchronization::CCriticalSection CS;
+ UInt32 NumThreads;
+ bool MtMode;
+ UInt32 NextBlockIndex;
+
+ bool CloseThreads;
+ bool StreamWasFinished;
+ NWindows::NSynchronization::CManualResetEvent CanStartWaitingEvent;
+
+ HRESULT Result;
+ ICompressProgressInfo *Progress;
+ #else
+ CThreadInfo ThreadsInfo;
+ #endif
+
+ UInt64 NumBlocks;
+
+ UInt64 GetInProcessedSize() const { return m_InStream.GetProcessedSize(); }
+
+ UInt32 ReadRleBlock(Byte *buf);
+ void WriteBytes(const Byte *data, UInt32 sizeInBits, Byte lastByte);
+
+ void WriteBits(UInt32 value, unsigned numBits);
+ void WriteByte(Byte b);
+ // void WriteBit(Byte v);
+ void WriteCrc(UInt32 v);
+
+ #ifndef Z7_ST
+ HRESULT Create();
+ void Free();
+ #endif
+
+public:
+ CEncoder();
+ #ifndef Z7_ST
+ ~CEncoder();
+ #endif
+
+ HRESULT Flush() { return m_OutStream.Flush(); }
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/BZip2Register.cpp b/CPP/7zip/Compress/BZip2Register.cpp
new file mode 100644
index 0000000..83b911d
--- /dev/null
+++ b/CPP/7zip/Compress/BZip2Register.cpp
@@ -0,0 +1,25 @@
+// BZip2Register.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "BZip2Decoder.h"
+#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_BZIP2_EXTRACT_ONLY)
+#include "BZip2Encoder.h"
+#endif
+
+namespace NCompress {
+namespace NBZip2 {
+
+REGISTER_CODEC_CREATE(CreateDec, CDecoder)
+
+#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_BZIP2_EXTRACT_ONLY)
+REGISTER_CODEC_CREATE(CreateEnc, CEncoder)
+#else
+#define CreateEnc NULL
+#endif
+
+REGISTER_CODEC_2(BZip2, CreateDec, CreateEnc, 0x40202, "BZip2")
+
+}}
diff --git a/CPP/7zip/Compress/Bcj2Coder.cpp b/CPP/7zip/Compress/Bcj2Coder.cpp
index 4e083bf..27e78b0 100644
--- a/CPP/7zip/Compress/Bcj2Coder.cpp
+++ b/CPP/7zip/Compress/Bcj2Coder.cpp
@@ -1,666 +1,853 @@
-// Bcj2Coder.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/Alloc.h"
-
-#include "../Common/StreamUtils.h"
-
-#include "Bcj2Coder.h"
-
-namespace NCompress {
-namespace NBcj2 {
-
-CBaseCoder::CBaseCoder()
-{
- for (int i = 0; i < BCJ2_NUM_STREAMS + 1; i++)
- {
- _bufs[i] = NULL;
- _bufsCurSizes[i] = 0;
- _bufsNewSizes[i] = (1 << 18);
- }
-}
-
-CBaseCoder::~CBaseCoder()
-{
- for (int i = 0; i < BCJ2_NUM_STREAMS + 1; i++)
- ::MidFree(_bufs[i]);
-}
-
-HRESULT CBaseCoder::Alloc(bool allocForOrig)
-{
- unsigned num = allocForOrig ? BCJ2_NUM_STREAMS + 1 : BCJ2_NUM_STREAMS;
- for (unsigned i = 0; i < num; i++)
- {
- UInt32 newSize = _bufsNewSizes[i];
- const UInt32 kMinBufSize = 1;
- if (newSize < kMinBufSize)
- newSize = kMinBufSize;
- if (!_bufs[i] || newSize != _bufsCurSizes[i])
- {
- if (_bufs[i])
- {
- ::MidFree(_bufs[i]);
- _bufs[i] = 0;
- }
- _bufsCurSizes[i] = 0;
- Byte *buf = (Byte *)::MidAlloc(newSize);
- _bufs[i] = buf;
- if (!buf)
- return E_OUTOFMEMORY;
- _bufsCurSizes[i] = newSize;
- }
- }
- return S_OK;
-}
-
-
-
-#ifndef EXTRACT_ONLY
-
-CEncoder::CEncoder(): _relatLim(BCJ2_RELAT_LIMIT) {}
-CEncoder::~CEncoder() {}
-
-STDMETHODIMP CEncoder::SetInBufSize(UInt32, UInt32 size) { _bufsNewSizes[BCJ2_NUM_STREAMS] = size; return S_OK; }
-STDMETHODIMP CEncoder::SetOutBufSize(UInt32 streamIndex, UInt32 size) { _bufsNewSizes[streamIndex] = size; return S_OK; }
-
-STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
-{
- UInt32 relatLim = BCJ2_RELAT_LIMIT;
-
- for (UInt32 i = 0; i < numProps; i++)
- {
- const PROPVARIANT &prop = props[i];
- PROPID propID = propIDs[i];
- if (propID >= NCoderPropID::kReduceSize)
- continue;
- switch (propID)
- {
- /*
- case NCoderPropID::kDefaultProp:
- {
- if (prop.vt != VT_UI4)
- return E_INVALIDARG;
- UInt32 v = prop.ulVal;
- if (v > 31)
- return E_INVALIDARG;
- relatLim = (UInt32)1 << v;
- break;
- }
- */
- case NCoderPropID::kDictionarySize:
- {
- if (prop.vt != VT_UI4)
- return E_INVALIDARG;
- relatLim = prop.ulVal;
- if (relatLim > ((UInt32)1 << 31))
- return E_INVALIDARG;
- break;
- }
-
- case NCoderPropID::kNumThreads:
- continue;
- case NCoderPropID::kLevel:
- continue;
-
- default: return E_INVALIDARG;
- }
- }
-
- _relatLim = relatLim;
-
- return S_OK;
-}
-
-
-HRESULT CEncoder::CodeReal(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
- ISequentialOutStream * const *outStreams, const UInt64 * const * /* outSizes */, UInt32 numOutStreams,
- ICompressProgressInfo *progress)
-{
- if (numInStreams != 1 || numOutStreams != BCJ2_NUM_STREAMS)
- return E_INVALIDARG;
-
- RINOK(Alloc());
-
- UInt32 fileSize_for_Conv = 0;
- if (inSizes && inSizes[0])
- {
- UInt64 inSize = *inSizes[0];
- if (inSize <= BCJ2_FileSize_MAX)
- fileSize_for_Conv = (UInt32)inSize;
- }
-
- CMyComPtr<ICompressGetSubStreamSize> getSubStreamSize;
- inStreams[0]->QueryInterface(IID_ICompressGetSubStreamSize, (void **)&getSubStreamSize);
-
- CBcj2Enc enc;
-
- enc.src = _bufs[BCJ2_NUM_STREAMS];
- enc.srcLim = enc.src;
-
- {
- for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
- {
- enc.bufs[i] = _bufs[i];
- enc.lims[i] = _bufs[i] + _bufsCurSizes[i];
- }
- }
-
- size_t numBytes_in_ReadBuf = 0;
- UInt64 prevProgress = 0;
- UInt64 totalStreamRead = 0; // size read from InputStream
- UInt64 currentInPos = 0; // data that was processed, it doesn't include data in input buffer and data in enc.temp
- UInt64 outSizeRc = 0;
-
- Bcj2Enc_Init(&enc);
-
- enc.fileIp = 0;
- enc.fileSize = fileSize_for_Conv;
-
- enc.relatLimit = _relatLim;
-
- enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
-
- bool needSubSize = false;
- UInt64 subStreamIndex = 0;
- UInt64 subStreamStartPos = 0;
- bool readWasFinished = false;
-
- for (;;)
- {
- if (needSubSize && getSubStreamSize)
- {
- enc.fileIp = 0;
- enc.fileSize = fileSize_for_Conv;
- enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
-
- for (;;)
- {
- UInt64 subStreamSize = 0;
- HRESULT result = getSubStreamSize->GetSubStreamSize(subStreamIndex, &subStreamSize);
- needSubSize = false;
-
- if (result == S_OK)
- {
- UInt64 newEndPos = subStreamStartPos + subStreamSize;
-
- bool isAccurateEnd = (newEndPos < totalStreamRead ||
- (newEndPos <= totalStreamRead && readWasFinished));
-
- if (newEndPos <= currentInPos && isAccurateEnd)
- {
- subStreamStartPos = newEndPos;
- subStreamIndex++;
- continue;
- }
-
- enc.srcLim = _bufs[BCJ2_NUM_STREAMS] + numBytes_in_ReadBuf;
-
- if (isAccurateEnd)
- {
- // data in enc.temp is possible here
- size_t rem = (size_t)(totalStreamRead - newEndPos);
-
- /* Pos_of(enc.src) <= old newEndPos <= newEndPos
- in another case, it's fail in some code */
- if ((size_t)(enc.srcLim - enc.src) < rem)
- return E_FAIL;
-
- enc.srcLim -= rem;
- enc.finishMode = BCJ2_ENC_FINISH_MODE_END_BLOCK;
- }
-
- if (subStreamSize <= BCJ2_FileSize_MAX)
- {
- enc.fileIp = enc.ip + (UInt32)(subStreamStartPos - currentInPos);
- enc.fileSize = (UInt32)subStreamSize;
- }
- break;
- }
-
- if (result == S_FALSE)
- break;
- if (result == E_NOTIMPL)
- {
- getSubStreamSize.Release();
- break;
- }
- return result;
- }
- }
-
- if (readWasFinished && totalStreamRead - currentInPos == Bcj2Enc_Get_InputData_Size(&enc))
- enc.finishMode = BCJ2_ENC_FINISH_MODE_END_STREAM;
-
- Bcj2Enc_Encode(&enc);
-
- currentInPos = totalStreamRead - numBytes_in_ReadBuf + (enc.src - _bufs[BCJ2_NUM_STREAMS]) - enc.tempPos;
-
- if (Bcj2Enc_IsFinished(&enc))
- break;
-
- if (enc.state < BCJ2_NUM_STREAMS)
- {
- size_t curSize = enc.bufs[enc.state] - _bufs[enc.state];
- // printf("Write stream = %2d %6d\n", enc.state, curSize);
- RINOK(WriteStream(outStreams[enc.state], _bufs[enc.state], curSize));
- if (enc.state == BCJ2_STREAM_RC)
- outSizeRc += curSize;
-
- enc.bufs[enc.state] = _bufs[enc.state];
- enc.lims[enc.state] = _bufs[enc.state] + _bufsCurSizes[enc.state];
- }
- else if (enc.state != BCJ2_ENC_STATE_ORIG)
- return E_FAIL;
- else
- {
- needSubSize = true;
-
- if (numBytes_in_ReadBuf != (size_t)(enc.src - _bufs[BCJ2_NUM_STREAMS]))
- {
- enc.srcLim = _bufs[BCJ2_NUM_STREAMS] + numBytes_in_ReadBuf;
- continue;
- }
-
- if (readWasFinished)
- continue;
-
- numBytes_in_ReadBuf = 0;
- enc.src = _bufs[BCJ2_NUM_STREAMS];
- enc.srcLim = _bufs[BCJ2_NUM_STREAMS];
-
- UInt32 curSize = _bufsCurSizes[BCJ2_NUM_STREAMS];
- RINOK(inStreams[0]->Read(_bufs[BCJ2_NUM_STREAMS], curSize, &curSize));
-
- // printf("Read %6d bytes\n", curSize);
- if (curSize == 0)
- {
- readWasFinished = true;
- continue;
- }
-
- numBytes_in_ReadBuf = curSize;
- totalStreamRead += numBytes_in_ReadBuf;
- enc.srcLim = _bufs[BCJ2_NUM_STREAMS] + numBytes_in_ReadBuf;
- }
-
- if (progress && currentInPos - prevProgress >= (1 << 20))
- {
- UInt64 outSize2 = currentInPos + outSizeRc + enc.bufs[BCJ2_STREAM_RC] - enc.bufs[BCJ2_STREAM_RC];
- prevProgress = currentInPos;
- // printf("progress %8d, %8d\n", (int)inSize2, (int)outSize2);
- RINOK(progress->SetRatioInfo(&currentInPos, &outSize2));
- }
- }
-
- for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
- {
- RINOK(WriteStream(outStreams[i], _bufs[i], enc.bufs[i] - _bufs[i]));
- }
-
- // if (currentInPos != subStreamStartPos + subStreamSize) return E_FAIL;
-
- return S_OK;
-}
-
-STDMETHODIMP CEncoder::Code(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
- ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
- ICompressProgressInfo *progress)
-{
- try
- {
- return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress);
- }
- catch(...) { return E_FAIL; }
-}
-
-#endif
-
-
-
-
-
-
-STDMETHODIMP CDecoder::SetInBufSize(UInt32 streamIndex, UInt32 size) { _bufsNewSizes[streamIndex] = size; return S_OK; }
-STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _bufsNewSizes[BCJ2_NUM_STREAMS] = size; return S_OK; }
-
-CDecoder::CDecoder(): _finishMode(false), _outSizeDefined(false), _outSize(0)
-{}
-
-STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
-{
- _finishMode = (finishMode != 0);
- return S_OK;
-}
-
-void CDecoder::InitCommon()
-{
- {
- for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
- dec.lims[i] = dec.bufs[i] = _bufs[i];
- }
-
- {
- for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
- {
- _extraReadSizes[i] = 0;
- _inStreamsProcessed[i] = 0;
- _readRes[i] = S_OK;
- }
- }
-
- Bcj2Dec_Init(&dec);
-}
-
-HRESULT CDecoder::Code(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
- ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
- ICompressProgressInfo *progress)
-{
- if (numInStreams != BCJ2_NUM_STREAMS || numOutStreams != 1)
- return E_INVALIDARG;
-
- RINOK(Alloc());
-
- InitCommon();
-
- dec.destLim = dec.dest = _bufs[BCJ2_NUM_STREAMS];
-
- UInt64 outSizeProcessed = 0;
- UInt64 prevProgress = 0;
-
- HRESULT res = S_OK;
-
- for (;;)
- {
- if (Bcj2Dec_Decode(&dec) != SZ_OK)
- return S_FALSE;
-
- if (dec.state < BCJ2_NUM_STREAMS)
- {
- size_t totalRead = _extraReadSizes[dec.state];
- {
- Byte *buf = _bufs[dec.state];
- for (size_t i = 0; i < totalRead; i++)
- buf[i] = dec.bufs[dec.state][i];
- dec.lims[dec.state] =
- dec.bufs[dec.state] = buf;
- }
-
- if (_readRes[dec.state] != S_OK)
- {
- res = _readRes[dec.state];
- break;
- }
-
- do
- {
- UInt32 curSize = _bufsCurSizes[dec.state] - (UInt32)totalRead;
- /*
- we want to call Read even even if size is 0
- if (inSizes && inSizes[dec.state])
- {
- UInt64 rem = *inSizes[dec.state] - _inStreamsProcessed[dec.state];
- if (curSize > rem)
- curSize = (UInt32)rem;
- }
- */
-
- HRESULT res2 = inStreams[dec.state]->Read(_bufs[dec.state] + totalRead, curSize, &curSize);
- _readRes[dec.state] = res2;
- if (curSize == 0)
- break;
- _inStreamsProcessed[dec.state] += curSize;
- totalRead += curSize;
- if (res2 != S_OK)
- break;
- }
- while (totalRead < 4 && BCJ2_IS_32BIT_STREAM(dec.state));
-
- if (_readRes[dec.state] != S_OK)
- res = _readRes[dec.state];
-
- if (totalRead == 0)
- break;
-
- // res == S_OK;
-
- if (BCJ2_IS_32BIT_STREAM(dec.state))
- {
- unsigned extraSize = ((unsigned)totalRead & 3);
- _extraReadSizes[dec.state] = extraSize;
- if (totalRead < 4)
- {
- res = (_readRes[dec.state] != S_OK) ? _readRes[dec.state] : S_FALSE;
- break;
- }
- totalRead -= extraSize;
- }
-
- dec.lims[dec.state] = _bufs[dec.state] + totalRead;
- }
- else // if (dec.state <= BCJ2_STATE_ORIG)
- {
- size_t curSize = dec.dest - _bufs[BCJ2_NUM_STREAMS];
- if (curSize != 0)
- {
- outSizeProcessed += curSize;
- RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize));
- }
- dec.dest = _bufs[BCJ2_NUM_STREAMS];
- {
- size_t rem = _bufsCurSizes[BCJ2_NUM_STREAMS];
- if (outSizes && outSizes[0])
- {
- UInt64 outSize = *outSizes[0] - outSizeProcessed;
- if (rem > outSize)
- rem = (size_t)outSize;
- }
- dec.destLim = dec.dest + rem;
- if (rem == 0)
- break;
- }
- }
-
- if (progress)
- {
- const UInt64 outSize2 = outSizeProcessed + (dec.dest - _bufs[BCJ2_NUM_STREAMS]);
- if (outSize2 - prevProgress >= (1 << 22))
- {
- const UInt64 inSize2 = outSize2 + _inStreamsProcessed[BCJ2_STREAM_RC] - (dec.lims[BCJ2_STREAM_RC] - dec.bufs[BCJ2_STREAM_RC]);
- RINOK(progress->SetRatioInfo(&inSize2, &outSize2));
- prevProgress = outSize2;
- }
- }
- }
-
- size_t curSize = dec.dest - _bufs[BCJ2_NUM_STREAMS];
- if (curSize != 0)
- {
- outSizeProcessed += curSize;
- RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize));
- }
-
- if (res != S_OK)
- return res;
-
- if (_finishMode)
- {
- if (!Bcj2Dec_IsFinished(&dec))
- return S_FALSE;
-
- // we still allow the cases when input streams are larger than required for decoding.
- // so the case (dec.state == BCJ2_STATE_ORIG) is also allowed, if MAIN stream is larger than required.
- if (dec.state != BCJ2_STREAM_MAIN &&
- dec.state != BCJ2_DEC_STATE_ORIG)
- return S_FALSE;
-
- if (inSizes)
- {
- for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
- {
- size_t rem = dec.lims[i] - dec.bufs[i] + _extraReadSizes[i];
- /*
- if (rem != 0)
- return S_FALSE;
- */
- if (inSizes[i] && *inSizes[i] != _inStreamsProcessed[i] - rem)
- return S_FALSE;
- }
- }
- }
-
- return S_OK;
-}
-
-STDMETHODIMP CDecoder::SetInStream2(UInt32 streamIndex, ISequentialInStream *inStream)
-{
- _inStreams[streamIndex] = inStream;
- return S_OK;
-}
-
-STDMETHODIMP CDecoder::ReleaseInStream2(UInt32 streamIndex)
-{
- _inStreams[streamIndex].Release();
- return S_OK;
-}
-
-STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
-{
- _outSizeDefined = (outSize != NULL);
- _outSize = 0;
- if (_outSizeDefined)
- _outSize = *outSize;
-
- _outSize_Processed = 0;
-
- HRESULT res = Alloc(false);
-
- InitCommon();
- dec.destLim = dec.dest = NULL;
-
- return res;
-}
-
-
-STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
-
- if (size == 0)
- return S_OK;
-
- UInt32 totalProcessed = 0;
-
- if (_outSizeDefined)
- {
- UInt64 rem = _outSize - _outSize_Processed;
- if (size > rem)
- size = (UInt32)rem;
- }
- dec.dest = (Byte *)data;
- dec.destLim = (const Byte *)data + size;
-
- HRESULT res = S_OK;
-
- for (;;)
- {
- SRes sres = Bcj2Dec_Decode(&dec);
- if (sres != SZ_OK)
- return S_FALSE;
-
- {
- UInt32 curSize = (UInt32)(dec.dest - (Byte *)data);
- if (curSize != 0)
- {
- totalProcessed += curSize;
- if (processedSize)
- *processedSize = totalProcessed;
- data = (void *)((Byte *)data + curSize);
- size -= curSize;
- _outSize_Processed += curSize;
- }
- }
-
- if (dec.state >= BCJ2_NUM_STREAMS)
- break;
-
- {
- size_t totalRead = _extraReadSizes[dec.state];
- {
- Byte *buf = _bufs[dec.state];
- for (size_t i = 0; i < totalRead; i++)
- buf[i] = dec.bufs[dec.state][i];
- dec.lims[dec.state] =
- dec.bufs[dec.state] = buf;
- }
-
- if (_readRes[dec.state] != S_OK)
- return _readRes[dec.state];
-
- do
- {
- UInt32 curSize = _bufsCurSizes[dec.state] - (UInt32)totalRead;
- HRESULT res2 = _inStreams[dec.state]->Read(_bufs[dec.state] + totalRead, curSize, &curSize);
- _readRes[dec.state] = res2;
- if (curSize == 0)
- break;
- _inStreamsProcessed[dec.state] += curSize;
- totalRead += curSize;
- if (res2 != S_OK)
- break;
- }
- while (totalRead < 4 && BCJ2_IS_32BIT_STREAM(dec.state));
-
- if (totalRead == 0)
- {
- if (totalProcessed == 0)
- res = _readRes[dec.state];
- break;
- }
-
- if (BCJ2_IS_32BIT_STREAM(dec.state))
- {
- unsigned extraSize = ((unsigned)totalRead & 3);
- _extraReadSizes[dec.state] = extraSize;
- if (totalRead < 4)
- {
- if (totalProcessed != 0)
- return S_OK;
- return (_readRes[dec.state] != S_OK) ? _readRes[dec.state] : S_FALSE;
- }
- totalRead -= extraSize;
- }
-
- dec.lims[dec.state] = _bufs[dec.state] + totalRead;
- }
- }
-
- if (_finishMode && _outSizeDefined && _outSize == _outSize_Processed)
- {
- if (!Bcj2Dec_IsFinished(&dec))
- return S_FALSE;
-
- if (dec.state != BCJ2_STREAM_MAIN &&
- dec.state != BCJ2_DEC_STATE_ORIG)
- return S_FALSE;
-
- /*
- for (int i = 0; i < BCJ2_NUM_STREAMS; i++)
- if (dec.bufs[i] != dec.lims[i] || _extraReadSizes[i] != 0)
- return S_FALSE;
- */
- }
-
- return res;
-}
-
-
-STDMETHODIMP CDecoder::GetInStreamProcessedSize2(UInt32 streamIndex, UInt64 *value)
-{
- const size_t rem = dec.lims[streamIndex] - dec.bufs[streamIndex] + _extraReadSizes[streamIndex];
- *value = _inStreamsProcessed[streamIndex] - rem;
- return S_OK;
-}
-
-}}
+// Bcj2Coder.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "Bcj2Coder.h"
+
+namespace NCompress {
+namespace NBcj2 {
+
+CBaseCoder::CBaseCoder()
+{
+ for (unsigned i = 0; i < BCJ2_NUM_STREAMS + 1; i++)
+ {
+ _bufs[i] = NULL;
+ _bufsSizes[i] = 0;
+ _bufsSizes_New[i] = (1 << 18);
+ }
+}
+
+CBaseCoder::~CBaseCoder()
+{
+ for (unsigned i = 0; i < BCJ2_NUM_STREAMS + 1; i++)
+ ::MidFree(_bufs[i]);
+}
+
+HRESULT CBaseCoder::Alloc(bool allocForOrig)
+{
+ const unsigned num = allocForOrig ? BCJ2_NUM_STREAMS + 1 : BCJ2_NUM_STREAMS;
+ for (unsigned i = 0; i < num; i++)
+ {
+ UInt32 size = _bufsSizes_New[i];
+ /* buffer sizes for BCJ2_STREAM_CALL and BCJ2_STREAM_JUMP streams
+ must be aligned for 4 */
+ size &= ~(UInt32)3;
+ const UInt32 kMinBufSize = 4;
+ if (size < kMinBufSize)
+ size = kMinBufSize;
+ // size = 4 * 100; // for debug
+ // if (BCJ2_IS_32BIT_STREAM(i) == 1) size = 4 * 1; // for debug
+ if (!_bufs[i] || size != _bufsSizes[i])
+ {
+ if (_bufs[i])
+ {
+ ::MidFree(_bufs[i]);
+ _bufs[i] = NULL;
+ }
+ _bufsSizes[i] = 0;
+ Byte *buf = (Byte *)::MidAlloc(size);
+ if (!buf)
+ return E_OUTOFMEMORY;
+ _bufs[i] = buf;
+ _bufsSizes[i] = size;
+ }
+ }
+ return S_OK;
+}
+
+
+
+#ifndef Z7_EXTRACT_ONLY
+
+CEncoder::CEncoder():
+ _relatLim(BCJ2_ENC_RELAT_LIMIT_DEFAULT)
+ // , _excludeRangeBits(BCJ2_RELAT_EXCLUDE_NUM_BITS)
+ {}
+CEncoder::~CEncoder() {}
+
+Z7_COM7F_IMF(CEncoder::SetInBufSize(UInt32, UInt32 size))
+ { _bufsSizes_New[BCJ2_NUM_STREAMS] = size; return S_OK; }
+Z7_COM7F_IMF(CEncoder::SetOutBufSize(UInt32 streamIndex, UInt32 size))
+ { _bufsSizes_New[streamIndex] = size; return S_OK; }
+
+Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps))
+{
+ UInt32 relatLim = BCJ2_ENC_RELAT_LIMIT_DEFAULT;
+ // UInt32 excludeRangeBits = BCJ2_RELAT_EXCLUDE_NUM_BITS;
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = props[i];
+ const PROPID propID = propIDs[i];
+ if (propID >= NCoderPropID::kReduceSize
+ // && propID != NCoderPropID::kHashBits
+ )
+ continue;
+ switch (propID)
+ {
+ /*
+ case NCoderPropID::kDefaultProp:
+ {
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 v = prop.ulVal;
+ if (v > 31)
+ return E_INVALIDARG;
+ relatLim = (UInt32)1 << v;
+ break;
+ }
+ case NCoderPropID::kHashBits:
+ {
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 v = prop.ulVal;
+ if (v > 31)
+ return E_INVALIDARG;
+ excludeRangeBits = v;
+ break;
+ }
+ */
+ case NCoderPropID::kDictionarySize:
+ {
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ relatLim = prop.ulVal;
+ if (relatLim > BCJ2_ENC_RELAT_LIMIT_MAX)
+ return E_INVALIDARG;
+ break;
+ }
+ case NCoderPropID::kNumThreads:
+ case NCoderPropID::kLevel:
+ continue;
+ default: return E_INVALIDARG;
+ }
+ }
+ _relatLim = relatLim;
+ // _excludeRangeBits = excludeRangeBits;
+ return S_OK;
+}
+
+
+HRESULT CEncoder::CodeReal(
+ ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
+ ISequentialOutStream * const *outStreams, const UInt64 * const * /* outSizes */, UInt32 numOutStreams,
+ ICompressProgressInfo *progress)
+{
+ if (numInStreams != 1 || numOutStreams != BCJ2_NUM_STREAMS)
+ return E_INVALIDARG;
+
+ RINOK(Alloc())
+
+ CBcj2Enc_ip_unsigned fileSize_minus1 = BCJ2_ENC_FileSizeField_UNLIMITED;
+ if (inSizes && inSizes[0])
+ {
+ const UInt64 inSize = *inSizes[0];
+ #ifdef BCJ2_ENC_FileSize_MAX
+ if (inSize <= BCJ2_ENC_FileSize_MAX)
+ #endif
+ fileSize_minus1 = BCJ2_ENC_GET_FileSizeField_VAL_FROM_FileSize(inSize);
+ }
+
+ Z7_DECL_CMyComPtr_QI_FROM(ICompressGetSubStreamSize, getSubStreamSize, inStreams[0])
+
+ CBcj2Enc enc;
+ enc.src = _bufs[BCJ2_NUM_STREAMS];
+ enc.srcLim = enc.src;
+ {
+ for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++)
+ {
+ enc.bufs[i] = _bufs[i];
+ enc.lims[i] = _bufs[i] + _bufsSizes[i];
+ }
+ }
+ Bcj2Enc_Init(&enc);
+ enc.fileIp64 = 0;
+ enc.fileSize64_minus1 = fileSize_minus1;
+ enc.relatLimit = _relatLim;
+ // enc.relatExcludeBits = _excludeRangeBits;
+ enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
+
+ // Varibales that correspond processed data in input stream:
+ UInt64 inPos_without_Temp = 0; // it doesn't include data in enc.temp[]
+ UInt64 inPos_with_Temp = 0; // it includes data in enc.temp[]
+
+ UInt64 prevProgress = 0;
+ UInt64 totalRead = 0; // size read from input stream
+ UInt64 outSizeRc = 0;
+ UInt64 subStream_Index = 0;
+ UInt64 subStream_StartPos = 0; // global start offset of subStreams[subStream_Index]
+ UInt64 subStream_Size = 0;
+ const Byte *srcLim_Read = _bufs[BCJ2_NUM_STREAMS];
+ bool readWasFinished = false;
+ bool isAccurate = false;
+ bool wasUnknownSize = false;
+
+ for (;;)
+ {
+ if (readWasFinished && enc.srcLim == srcLim_Read)
+ enc.finishMode = BCJ2_ENC_FINISH_MODE_END_STREAM;
+
+ // for debug:
+ // for (int y=0;y<100;y++) { CBcj2Enc enc2 = enc; Bcj2Enc_Encode(&enc2); }
+
+ Bcj2Enc_Encode(&enc);
+
+ inPos_with_Temp = totalRead - (size_t)(srcLim_Read - enc.src);
+ inPos_without_Temp = inPos_with_Temp - Bcj2Enc_Get_AvailInputSize_in_Temp(&enc);
+
+ // if (inPos_without_Temp != enc.ip64) return E_FAIL;
+
+ if (Bcj2Enc_IsFinished(&enc))
+ break;
+
+ if (enc.state < BCJ2_NUM_STREAMS)
+ {
+ if (enc.bufs[enc.state] != enc.lims[enc.state])
+ return E_FAIL;
+ const size_t curSize = (size_t)(enc.bufs[enc.state] - _bufs[enc.state]);
+ // printf("Write stream = %2d %6d\n", enc.state, curSize);
+ RINOK(WriteStream(outStreams[enc.state], _bufs[enc.state], curSize))
+ if (enc.state == BCJ2_STREAM_RC)
+ outSizeRc += curSize;
+ enc.bufs[enc.state] = _bufs[enc.state];
+ enc.lims[enc.state] = _bufs[enc.state] + _bufsSizes[enc.state];
+ }
+ else
+ {
+ if (enc.state != BCJ2_ENC_STATE_ORIG)
+ return E_FAIL;
+ // (enc.state == BCJ2_ENC_STATE_ORIG)
+ if (enc.src != enc.srcLim)
+ return E_FAIL;
+ if (enc.finishMode != BCJ2_ENC_FINISH_MODE_CONTINUE
+ && Bcj2Enc_Get_AvailInputSize_in_Temp(&enc) != 0)
+ return E_FAIL;
+
+ if (enc.src == srcLim_Read)
+ {
+ if (readWasFinished)
+ return E_FAIL;
+ UInt32 curSize = _bufsSizes[BCJ2_NUM_STREAMS];
+ RINOK(inStreams[0]->Read(_bufs[BCJ2_NUM_STREAMS], curSize, &curSize))
+ // printf("Read %6u bytes\n", curSize);
+ if (curSize == 0)
+ readWasFinished = true;
+ totalRead += curSize;
+ enc.src = _bufs[BCJ2_NUM_STREAMS];
+ srcLim_Read = _bufs[BCJ2_NUM_STREAMS] + curSize;
+ }
+ enc.srcLim = srcLim_Read;
+
+ if (getSubStreamSize)
+ {
+ /* we set base default conversions options that will be used,
+ if subStream related options will be not OK */
+ enc.fileIp64 = 0;
+ enc.fileSize64_minus1 = fileSize_minus1;
+ for (;;)
+ {
+ UInt64 nextPos;
+ if (isAccurate)
+ nextPos = subStream_StartPos + subStream_Size;
+ else
+ {
+ const HRESULT hres = getSubStreamSize->GetSubStreamSize(subStream_Index, &subStream_Size);
+ if (hres != S_OK)
+ {
+ enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
+ /* if sub-stream size is unknown, we use default settings.
+ We still can recover to normal mode for next sub-stream,
+ if GetSubStreamSize() will return S_OK, when current
+ sub-stream will be finished.
+ */
+ if (hres == S_FALSE)
+ {
+ wasUnknownSize = true;
+ break;
+ }
+ if (hres == E_NOTIMPL)
+ {
+ getSubStreamSize.Release();
+ break;
+ }
+ return hres;
+ }
+ // printf("GetSubStreamSize %6u : %6u \n", (unsigned)subStream_Index, (unsigned)subStream_Size);
+ nextPos = subStream_StartPos + subStream_Size;
+ if ((Int64)subStream_Size == -1)
+ {
+ /* it's not expected, but (-1) can mean unknown size. */
+ enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
+ wasUnknownSize = true;
+ break;
+ }
+ if (nextPos < subStream_StartPos)
+ return E_FAIL;
+ isAccurate =
+ (nextPos < totalRead
+ || (nextPos <= totalRead && readWasFinished));
+ }
+
+ /* (nextPos) is estimated end position of current sub_stream.
+ But only (totalRead) and (readWasFinished) values
+ can confirm that this estimated end position is accurate.
+ That end position is accurate, if it can't be changed in
+ further calls of GetSubStreamSize() */
+
+ /* (nextPos < inPos_with_Temp) is unexpected case here, that we
+ can get if from some incorrect ICompressGetSubStreamSize object,
+ where new GetSubStreamSize() call returns smaller size than
+ confirmed by Read() size from previous GetSubStreamSize() call.
+ */
+ if (nextPos < inPos_with_Temp)
+ {
+ if (wasUnknownSize)
+ {
+ /* that case can be complicated for recovering.
+ so we disable sub-streams requesting. */
+ enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
+ getSubStreamSize.Release();
+ break;
+ }
+ return E_FAIL; // to stop after failure
+ }
+
+ if (nextPos <= inPos_with_Temp)
+ {
+ // (nextPos == inPos_with_Temp)
+ /* CBcj2Enc encoder requires to finish each [non-empty] block (sub-stream)
+ with BCJ2_ENC_FINISH_MODE_END_BLOCK
+ or with BCJ2_ENC_FINISH_MODE_END_STREAM for last block:
+ And we send data of new block to CBcj2Enc, only if previous block was finished.
+ So we switch to next sub-stream if after Bcj2Enc_Encode() call we have
+ && (enc.finishMode != BCJ2_ENC_FINISH_MODE_CONTINUE)
+ && (nextPos == inPos_with_Temp)
+ && (enc.state == BCJ2_ENC_STATE_ORIG)
+ */
+ if (enc.finishMode != BCJ2_ENC_FINISH_MODE_CONTINUE)
+ {
+ /* subStream_StartPos is increased only here.
+ (subStream_StartPos == inPos_with_Temp) : at start
+ (subStream_StartPos <= inPos_with_Temp) : will be later
+ */
+ subStream_StartPos = nextPos;
+ subStream_Size = 0;
+ wasUnknownSize = false;
+ subStream_Index++;
+ isAccurate = false;
+ // we don't change finishMode here
+ continue;
+ }
+ }
+
+ enc.finishMode = BCJ2_ENC_FINISH_MODE_CONTINUE;
+ /* for (!isAccurate) case:
+ (totalRead <= real_end_of_subStream)
+ so we can use BCJ2_ENC_FINISH_MODE_CONTINUE up to (totalRead)
+ // we don't change settings at the end of substream, if settings were unknown,
+ */
+
+ /* if (wasUnknownSize) then we can't trust size of that sub-stream.
+ so we use default settings instead */
+ if (!wasUnknownSize)
+ #ifdef BCJ2_ENC_FileSize_MAX
+ if (subStream_Size <= BCJ2_ENC_FileSize_MAX)
+ #endif
+ {
+ enc.fileIp64 =
+ (CBcj2Enc_ip_unsigned)(
+ (CBcj2Enc_ip_signed)enc.ip64 +
+ (CBcj2Enc_ip_signed)(subStream_StartPos - inPos_without_Temp));
+ Bcj2Enc_SET_FileSize(&enc, subStream_Size)
+ }
+
+ if (isAccurate)
+ {
+ /* (real_end_of_subStream == nextPos <= totalRead)
+ So we can use BCJ2_ENC_FINISH_MODE_END_BLOCK up to (nextPos). */
+ const size_t rem = (size_t)(totalRead - nextPos);
+ if ((size_t)(enc.srcLim - enc.src) < rem)
+ return E_FAIL;
+ enc.srcLim -= rem;
+ enc.finishMode = BCJ2_ENC_FINISH_MODE_END_BLOCK;
+ }
+
+ break;
+ } // for() loop
+ } // getSubStreamSize
+ }
+
+ if (progress && inPos_without_Temp - prevProgress >= (1 << 22))
+ {
+ prevProgress = inPos_without_Temp;
+ const UInt64 outSize2 = inPos_without_Temp + outSizeRc +
+ (size_t)(enc.bufs[BCJ2_STREAM_RC] - _bufs[BCJ2_STREAM_RC]);
+ // printf("progress %8u, %8u\n", (unsigned)inSize2, (unsigned)outSize2);
+ RINOK(progress->SetRatioInfo(&inPos_without_Temp, &outSize2))
+ }
+ }
+
+ for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++)
+ {
+ RINOK(WriteStream(outStreams[i], _bufs[i], (size_t)(enc.bufs[i] - _bufs[i])))
+ }
+ // if (inPos_without_Temp != subStream_StartPos + subStream_Size) return E_FAIL;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CEncoder::Code(
+ ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
+ ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress))
+{
+ try
+ {
+ return CodeReal(inStreams, inSizes, numInStreams, outStreams, outSizes,numOutStreams, progress);
+ }
+ catch(...) { return E_FAIL; }
+}
+
+#endif
+
+
+
+
+
+
+CDecoder::CDecoder():
+ _finishMode(false)
+#ifndef Z7_NO_READ_FROM_CODER
+ , _outSizeDefined(false)
+ , _outSize(0)
+ , _outSize_Processed(0)
+#endif
+{}
+
+Z7_COM7F_IMF(CDecoder::SetInBufSize(UInt32 streamIndex, UInt32 size))
+ { _bufsSizes_New[streamIndex] = size; return S_OK; }
+Z7_COM7F_IMF(CDecoder::SetOutBufSize(UInt32, UInt32 size))
+ { _bufsSizes_New[BCJ2_NUM_STREAMS] = size; return S_OK; }
+
+Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
+{
+ _finishMode = (finishMode != 0);
+ return S_OK;
+}
+
+void CBaseDecoder::InitCommon()
+{
+ for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++)
+ {
+ dec.lims[i] = dec.bufs[i] = _bufs[i];
+ _readRes[i] = S_OK;
+ _extraSizes[i] = 0;
+ _readSizes[i] = 0;
+ }
+ Bcj2Dec_Init(&dec);
+}
+
+
+/* call ReadInStream() only after Bcj2Dec_Decode().
+ input requirement:
+ (dec.state < BCJ2_NUM_STREAMS)
+*/
+void CBaseDecoder::ReadInStream(ISequentialInStream *inStream)
+{
+ const unsigned state = dec.state;
+ UInt32 total;
+ {
+ Byte *buf = _bufs[state];
+ const Byte *cur = dec.bufs[state];
+ // if (cur != dec.lims[state]) throw 1; // unexpected case
+ dec.lims[state] =
+ dec.bufs[state] = buf;
+ total = (UInt32)_extraSizes[state];
+ for (UInt32 i = 0; i < total; i++)
+ buf[i] = cur[i];
+ }
+
+ if (_readRes[state] != S_OK)
+ return;
+
+ do
+ {
+ UInt32 curSize = _bufsSizes[state] - total;
+ // if (state == 0) curSize = 0; // for debug
+ // curSize = 7; // for debug
+ /* even if we have reached provided inSizes[state] limit,
+ we call Read() with (curSize != 0), because
+ we want the called handler of stream->Read() could
+ execute required Init/Flushing code even for empty stream.
+ In another way we could call Read() with (curSize == 0) for
+ finished streams, but some Read() handlers can ignore Read(size=0) calls.
+ */
+ const HRESULT hres = inStream->Read(_bufs[state] + total, curSize, &curSize);
+ _readRes[state] = hres;
+ if (curSize == 0)
+ break;
+ _readSizes[state] += curSize;
+ total += curSize;
+ if (hres != S_OK)
+ break;
+ }
+ while (total < 4 && BCJ2_IS_32BIT_STREAM(state));
+
+ /* we exit from decoding loop here, if we can't
+ provide new data for input stream.
+ Usually it's normal exit after full stream decoding. */
+ if (total == 0)
+ return;
+
+ if (BCJ2_IS_32BIT_STREAM(state))
+ {
+ const unsigned extra = ((unsigned)total & 3);
+ _extraSizes[state] = extra;
+ if (total < 4)
+ {
+ if (_readRes[state] == S_OK)
+ _readRes[state] = S_FALSE; // actually it's stream error. So maybe we need another error code.
+ return;
+ }
+ total -= extra;
+ }
+
+ dec.lims[state] += total; // = _bufs[state] + total;
+}
+
+
+Z7_COM7F_IMF(CDecoder::Code(
+ ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
+ ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress))
+{
+ if (numInStreams != BCJ2_NUM_STREAMS || numOutStreams != 1)
+ return E_INVALIDARG;
+
+ RINOK(Alloc())
+ InitCommon();
+
+ dec.destLim = dec.dest = _bufs[BCJ2_NUM_STREAMS];
+
+ UInt64 outSizeWritten = 0;
+ UInt64 prevProgress = 0;
+
+ HRESULT hres_Crit = S_OK; // critical hres status (mostly from input stream reading)
+ HRESULT hres_Weak = S_OK; // first non-critical error code from input stream reading
+
+ for (;;)
+ {
+ if (Bcj2Dec_Decode(&dec) != SZ_OK)
+ {
+ /* it's possible only at start (first 5 bytes in RC stream) */
+ hres_Crit = S_FALSE;
+ break;
+ }
+ if (dec.state < BCJ2_NUM_STREAMS)
+ {
+ ReadInStream(inStreams[dec.state]);
+ const unsigned state = dec.state;
+ const HRESULT hres = _readRes[state];
+ if (dec.lims[state] == _bufs[state])
+ {
+ // we break decoding, if there are no new data in input stream
+ hres_Crit = hres;
+ break;
+ }
+ if (hres != S_OK && hres_Weak == S_OK)
+ hres_Weak = hres;
+ }
+ else // (BCJ2_DEC_STATE_ORIG_0 <= state <= BCJ2_STATE_ORIG)
+ {
+ {
+ const size_t curSize = (size_t)(dec.dest - _bufs[BCJ2_NUM_STREAMS]);
+ if (curSize != 0)
+ {
+ outSizeWritten += curSize;
+ RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize))
+ }
+ }
+ {
+ UInt32 rem = _bufsSizes[BCJ2_NUM_STREAMS];
+ if (outSizes && outSizes[0])
+ {
+ const UInt64 outSize = *outSizes[0] - outSizeWritten;
+ if (rem > outSize)
+ rem = (UInt32)outSize;
+ }
+ dec.dest = _bufs[BCJ2_NUM_STREAMS];
+ dec.destLim = dec.dest + rem;
+ /* we exit from decoding loop here,
+ if (outSizes[0]) limit for output stream was reached */
+ if (rem == 0)
+ break;
+ }
+ }
+
+ if (progress)
+ {
+ // here we don't count additional data in dec.temp (up to 4 bytes for output stream)
+ const UInt64 processed = outSizeWritten + (size_t)(dec.dest - _bufs[BCJ2_NUM_STREAMS]);
+ if (processed - prevProgress >= (1 << 24))
+ {
+ prevProgress = processed;
+ const UInt64 inSize = processed +
+ _readSizes[BCJ2_STREAM_RC] - (size_t)(
+ dec.lims[BCJ2_STREAM_RC] -
+ dec.bufs[BCJ2_STREAM_RC]);
+ RINOK(progress->SetRatioInfo(&inSize, &prevProgress))
+ }
+ }
+ }
+
+ {
+ const size_t curSize = (size_t)(dec.dest - _bufs[BCJ2_NUM_STREAMS]);
+ if (curSize != 0)
+ {
+ outSizeWritten += curSize;
+ RINOK(WriteStream(outStreams[0], _bufs[BCJ2_NUM_STREAMS], curSize))
+ }
+ }
+
+ if (hres_Crit == S_OK) hres_Crit = hres_Weak;
+ if (hres_Crit != S_OK) return hres_Crit;
+
+ if (_finishMode)
+ {
+ if (!Bcj2Dec_IsMaybeFinished_code(&dec))
+ return S_FALSE;
+
+ /* here we support two correct ways to finish full stream decoding
+ with one of the following conditions:
+ - the end of input stream MAIN was reached
+ - the end of output stream ORIG was reached
+ Currently 7-Zip/7z code ends with (state == BCJ2_STREAM_MAIN),
+ because the sizes of MAIN and ORIG streams are known and these
+ sizes are stored in 7z archive headers.
+ And Bcj2Dec_Decode() exits with (state == BCJ2_STREAM_MAIN),
+ if both MAIN and ORIG streams have reached buffers limits.
+ But if the size of MAIN stream is not known or if the
+ size of MAIN stream includes some padding after payload data,
+ then we still can correctly finish decoding with
+ (state == BCJ2_DEC_STATE_ORIG), if we know the exact size
+ of output ORIG stream.
+ */
+ if (dec.state != BCJ2_STREAM_MAIN)
+ if (dec.state != BCJ2_DEC_STATE_ORIG)
+ return S_FALSE;
+
+ /* the caller also will know written size.
+ So the following check is optional: */
+ if (outSizes && outSizes[0] && *outSizes[0] != outSizeWritten)
+ return S_FALSE;
+
+ if (inSizes)
+ {
+ for (unsigned i = 0; i < BCJ2_NUM_STREAMS; i++)
+ {
+ /* if (inSizes[i]) is defined, we do full check for processed stream size. */
+ if (inSizes[i] && *inSizes[i] != GetProcessedSize_ForInStream(i))
+ return S_FALSE;
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize2(UInt32 streamIndex, UInt64 *value))
+{
+ *value = GetProcessedSize_ForInStream(streamIndex);
+ return S_OK;
+}
+
+
+#ifndef Z7_NO_READ_FROM_CODER
+
+Z7_COM7F_IMF(CDecoder::SetInStream2(UInt32 streamIndex, ISequentialInStream *inStream))
+{
+ _inStreams[streamIndex] = inStream;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CDecoder::ReleaseInStream2(UInt32 streamIndex))
+{
+ _inStreams[streamIndex].Release();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize))
+{
+ _outSizeDefined = (outSize != NULL);
+ _outSize = 0;
+ if (_outSizeDefined)
+ _outSize = *outSize;
+ _outSize_Processed = 0;
+
+ const HRESULT res = Alloc(false); // allocForOrig
+ InitCommon();
+ dec.destLim = dec.dest = NULL;
+ return res;
+}
+
+
+Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+
+ /* Note the case:
+ The output (ORIG) stream can be empty.
+ But BCJ2_STREAM_RC stream always is not empty.
+ And we want to support full data processing for all streams.
+ We disable check (size == 0) here.
+ So if the caller calls this CDecoder::Read() with (size == 0),
+ we execute required Init/Flushing code in this CDecoder object.
+ Also this CDecoder::Read() function will call Read() for input streams.
+ So the handlers of input streams objects also can do Init/Flushing.
+ */
+ // if (size == 0) return S_OK; // disabled to allow (size == 0) processing
+
+ UInt32 totalProcessed = 0;
+
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outSize_Processed;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+ dec.dest = (Byte *)data;
+ dec.destLim = (const Byte *)data + size;
+
+ HRESULT res = S_OK;
+
+ for (;;)
+ {
+ if (Bcj2Dec_Decode(&dec) != SZ_OK)
+ return S_FALSE; // this error can be only at start of stream
+ {
+ const UInt32 curSize = (UInt32)(size_t)(dec.dest - (Byte *)data);
+ if (curSize != 0)
+ {
+ data = (void *)((Byte *)data + curSize);
+ size -= curSize;
+ _outSize_Processed += curSize;
+ totalProcessed += curSize;
+ if (processedSize)
+ *processedSize = totalProcessed;
+ }
+ }
+ if (dec.state >= BCJ2_NUM_STREAMS)
+ break;
+ ReadInStream(_inStreams[dec.state]);
+ if (dec.lims[dec.state] == _bufs[dec.state])
+ {
+ /* we break decoding, if there are no new data in input stream.
+ and we ignore error code, if some data were written to output buffer. */
+ if (totalProcessed == 0)
+ res = _readRes[dec.state];
+ break;
+ }
+ }
+
+ if (res == S_OK)
+ if (_finishMode && _outSizeDefined && _outSize == _outSize_Processed)
+ {
+ if (!Bcj2Dec_IsMaybeFinished_code(&dec))
+ return S_FALSE;
+ if (dec.state != BCJ2_STREAM_MAIN)
+ if (dec.state != BCJ2_DEC_STATE_ORIG)
+ return S_FALSE;
+ }
+
+ return res;
+}
+
+#endif
+
+}}
+
+
+/*
+extern "C"
+{
+extern UInt32 bcj2_stats[256 + 2][2];
+}
+
+static class CBcj2Stat
+{
+public:
+ ~CBcj2Stat()
+ {
+ printf("\nBCJ2 stat:");
+ unsigned sums[2] = { 0, 0 };
+ int i;
+ for (i = 2; i < 256 + 2; i++)
+ {
+ sums[0] += bcj2_stats[i][0];
+ sums[1] += bcj2_stats[i][1];
+ }
+ const unsigned sums2 = sums[0] + sums[1];
+ for (int vi = 0; vi < 256 + 3; vi++)
+ {
+ printf("\n");
+ UInt32 n0, n1;
+ if (vi < 4)
+ printf("\n");
+
+ if (vi < 2)
+ i = vi;
+ else if (vi == 2)
+ i = -1;
+ else
+ i = vi - 1;
+
+ if (i < 0)
+ {
+ n0 = sums[0];
+ n1 = sums[1];
+ printf("calls :");
+ }
+ else
+ {
+ if (i == 0)
+ printf("jcc :");
+ else if (i == 1)
+ printf("jump :");
+ else
+ printf("call %02x :", i - 2);
+ n0 = bcj2_stats[i][0];
+ n1 = bcj2_stats[i][1];
+ }
+
+ const UInt32 sum = n0 + n1;
+ printf(" %10u", sum);
+
+ #define PRINT_PERC(val, sum) \
+ { UInt32 _sum = sum; if (_sum == 0) _sum = 1; \
+ printf(" %7.3f %%", (double)((double)val * (double)100 / (double)_sum )); }
+
+ if (i >= 2 || i < 0)
+ {
+ PRINT_PERC(sum, sums2);
+ }
+ else
+ printf("%10s", "");
+
+ printf(" :%10u", n0);
+ PRINT_PERC(n0, sum);
+
+ printf(" :%10u", n1);
+ PRINT_PERC(n1, sum);
+ }
+ printf("\n\n");
+ fflush(stdout);
+ }
+} g_CBcjStat;
+*/
diff --git a/CPP/7zip/Compress/Bcj2Coder.h b/CPP/7zip/Compress/Bcj2Coder.h
index 666bf8c..2ab91bc 100644
--- a/CPP/7zip/Compress/Bcj2Coder.h
+++ b/CPP/7zip/Compress/Bcj2Coder.h
@@ -1,120 +1,127 @@
-// Bcj2Coder.h
-
-#ifndef __COMPRESS_BCJ2_CODER_H
-#define __COMPRESS_BCJ2_CODER_H
-
-#include "../../../C/Bcj2.h"
-
-#include "../../Common/MyCom.h"
-
-#include "../ICoder.h"
-
-namespace NCompress {
-namespace NBcj2 {
-
-class CBaseCoder
-{
-protected:
- Byte *_bufs[BCJ2_NUM_STREAMS + 1];
- UInt32 _bufsCurSizes[BCJ2_NUM_STREAMS + 1];
- UInt32 _bufsNewSizes[BCJ2_NUM_STREAMS + 1];
-
- HRESULT Alloc(bool allocForOrig = true);
-public:
- CBaseCoder();
- ~CBaseCoder();
-};
-
-
-#ifndef EXTRACT_ONLY
-
-class CEncoder:
- public ICompressCoder2,
- public ICompressSetCoderProperties,
- public ICompressSetBufSize,
- public CMyUnknownImp,
- public CBaseCoder
-{
- UInt32 _relatLim;
-
- HRESULT CodeReal(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
- ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
- ICompressProgressInfo *progress);
-
-public:
- MY_UNKNOWN_IMP3(ICompressCoder2, ICompressSetCoderProperties, ICompressSetBufSize)
-
- STDMETHOD(Code)(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
- ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
- ICompressProgressInfo *progress);
-
- STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
-
- STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);
- STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);
-
- CEncoder();
- ~CEncoder();
-};
-
-#endif
-
-class CDecoder:
- public ICompressCoder2,
- public ICompressSetFinishMode,
- public ICompressGetInStreamProcessedSize2,
- public ICompressSetInStream2,
- public ISequentialInStream,
- public ICompressSetOutStreamSize,
- public ICompressSetBufSize,
- public CMyUnknownImp,
- public CBaseCoder
-{
- unsigned _extraReadSizes[BCJ2_NUM_STREAMS];
- UInt64 _inStreamsProcessed[BCJ2_NUM_STREAMS];
- HRESULT _readRes[BCJ2_NUM_STREAMS];
- CMyComPtr<ISequentialInStream> _inStreams[BCJ2_NUM_STREAMS];
-
- bool _finishMode;
- bool _outSizeDefined;
- UInt64 _outSize;
- UInt64 _outSize_Processed;
- CBcj2Dec dec;
-
- void InitCommon();
- // HRESULT ReadSpec();
-
-public:
- MY_UNKNOWN_IMP7(
- ICompressCoder2,
- ICompressSetFinishMode,
- ICompressGetInStreamProcessedSize2,
- ICompressSetInStream2,
- ISequentialInStream,
- ICompressSetOutStreamSize,
- ICompressSetBufSize
- );
-
- STDMETHOD(Code)(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
- ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
- ICompressProgressInfo *progress);
-
- STDMETHOD(SetFinishMode)(UInt32 finishMode);
- STDMETHOD(GetInStreamProcessedSize2)(UInt32 streamIndex, UInt64 *value);
-
- STDMETHOD(SetInStream2)(UInt32 streamIndex, ISequentialInStream *inStream);
- STDMETHOD(ReleaseInStream2)(UInt32 streamIndex);
-
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
-
- STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
-
- STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);
- STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);
-
- CDecoder();
-};
-
-}}
-
-#endif
+// Bcj2Coder.h
+
+#ifndef ZIP7_INC_COMPRESS_BCJ2_CODER_H
+#define ZIP7_INC_COMPRESS_BCJ2_CODER_H
+
+#include "../../../C/Bcj2.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NBcj2 {
+
+class CBaseCoder
+{
+protected:
+ Byte *_bufs[BCJ2_NUM_STREAMS + 1];
+ UInt32 _bufsSizes[BCJ2_NUM_STREAMS + 1];
+ UInt32 _bufsSizes_New[BCJ2_NUM_STREAMS + 1];
+
+ HRESULT Alloc(bool allocForOrig = true);
+public:
+ CBaseCoder();
+ ~CBaseCoder();
+};
+
+
+#ifndef Z7_EXTRACT_ONLY
+
+class CEncoder Z7_final:
+ public ICompressCoder2,
+ public ICompressSetCoderProperties,
+ public ICompressSetBufSize,
+ public CMyUnknownImp,
+ public CBaseCoder
+{
+ Z7_IFACES_IMP_UNK_3(
+ ICompressCoder2,
+ ICompressSetCoderProperties,
+ ICompressSetBufSize)
+
+ UInt32 _relatLim;
+ // UInt32 _excludeRangeBits;
+
+ HRESULT CodeReal(
+ ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
+ ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
+ ICompressProgressInfo *progress);
+public:
+ CEncoder();
+ ~CEncoder();
+};
+
+#endif
+
+
+
+class CBaseDecoder: public CBaseCoder
+{
+protected:
+ HRESULT _readRes[BCJ2_NUM_STREAMS];
+ unsigned _extraSizes[BCJ2_NUM_STREAMS];
+ UInt64 _readSizes[BCJ2_NUM_STREAMS];
+
+ CBcj2Dec dec;
+
+ UInt64 GetProcessedSize_ForInStream(unsigned i) const
+ {
+ return _readSizes[i] - ((size_t)(dec.lims[i] - dec.bufs[i]) + _extraSizes[i]);
+ }
+ void InitCommon();
+ void ReadInStream(ISequentialInStream *inStream);
+};
+
+
+class CDecoder Z7_final:
+ public ICompressCoder2,
+ public ICompressSetFinishMode,
+ public ICompressGetInStreamProcessedSize2,
+ public ICompressSetBufSize,
+#ifndef Z7_NO_READ_FROM_CODER
+ public ICompressSetInStream2,
+ public ICompressSetOutStreamSize,
+ public ISequentialInStream,
+#endif
+ public CMyUnknownImp,
+ public CBaseDecoder
+{
+ Z7_COM_QI_BEGIN2(ICompressCoder2)
+ Z7_COM_QI_ENTRY(ICompressSetFinishMode)
+ Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize2)
+ Z7_COM_QI_ENTRY(ICompressSetBufSize)
+ #ifndef Z7_NO_READ_FROM_CODER
+ Z7_COM_QI_ENTRY(ICompressSetInStream2)
+ Z7_COM_QI_ENTRY(ICompressSetOutStreamSize)
+ Z7_COM_QI_ENTRY(ISequentialInStream)
+ #endif
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(ICompressCoder2)
+ Z7_IFACE_COM7_IMP(ICompressSetFinishMode)
+ Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize2)
+ Z7_IFACE_COM7_IMP(ICompressSetBufSize)
+#ifndef Z7_NO_READ_FROM_CODER
+ Z7_IFACE_COM7_IMP(ICompressSetInStream2)
+ Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize)
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+#endif
+
+ bool _finishMode;
+
+#ifndef Z7_NO_READ_FROM_CODER
+ bool _outSizeDefined;
+ UInt64 _outSize;
+ UInt64 _outSize_Processed;
+ CMyComPtr<ISequentialInStream> _inStreams[BCJ2_NUM_STREAMS];
+#endif
+
+public:
+ CDecoder();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/Bcj2Register.cpp b/CPP/7zip/Compress/Bcj2Register.cpp
index bce6178..1ce4dec 100644
--- a/CPP/7zip/Compress/Bcj2Register.cpp
+++ b/CPP/7zip/Compress/Bcj2Register.cpp
@@ -1,24 +1,24 @@
-// Bcj2Register.cpp
-
-#include "StdAfx.h"
-
-#include "../Common/RegisterCodec.h"
-
-#include "Bcj2Coder.h"
-
-namespace NCompress {
-namespace NBcj2 {
-
-REGISTER_CODEC_CREATE_2(CreateCodec, CDecoder(), ICompressCoder2)
-#ifndef EXTRACT_ONLY
-REGISTER_CODEC_CREATE_2(CreateCodecOut, CEncoder(), ICompressCoder2)
-#else
-#define CreateCodecOut NULL
-#endif
-
-REGISTER_CODEC_VAR
- { CreateCodec, CreateCodecOut, 0x303011B, "BCJ2", 4, false };
-
-REGISTER_CODEC(BCJ2)
-
-}}
+// Bcj2Register.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "Bcj2Coder.h"
+
+namespace NCompress {
+namespace NBcj2 {
+
+REGISTER_CODEC_CREATE_2(CreateCodec, CDecoder(), ICompressCoder2)
+#ifndef Z7_EXTRACT_ONLY
+REGISTER_CODEC_CREATE_2(CreateCodecOut, CEncoder(), ICompressCoder2)
+#else
+#define CreateCodecOut NULL
+#endif
+
+REGISTER_CODEC_VAR(BCJ2)
+ { CreateCodec, CreateCodecOut, 0x303011B, "BCJ2", 4, false };
+
+REGISTER_CODEC(BCJ2)
+
+}}
diff --git a/CPP/7zip/Compress/BcjCoder.cpp b/CPP/7zip/Compress/BcjCoder.cpp
index a50360c..0047874 100644
--- a/CPP/7zip/Compress/BcjCoder.cpp
+++ b/CPP/7zip/Compress/BcjCoder.cpp
@@ -1,24 +1,24 @@
-// BcjCoder.cpp
-
-#include "StdAfx.h"
-
-#include "BcjCoder.h"
-
-namespace NCompress {
-namespace NBcj {
-
-STDMETHODIMP CCoder::Init()
-{
- _bufferPos = 0;
- x86_Convert_Init(_prevMask);
- return S_OK;
-}
-
-STDMETHODIMP_(UInt32) CCoder::Filter(Byte *data, UInt32 size)
-{
- UInt32 processed = (UInt32)::x86_Convert(data, size, _bufferPos, &_prevMask, _encode);
- _bufferPos += processed;
- return processed;
-}
-
-}}
+// BcjCoder.cpp
+
+#include "StdAfx.h"
+
+#include "BcjCoder.h"
+
+namespace NCompress {
+namespace NBcj {
+
+Z7_COM7F_IMF(CCoder2::Init())
+{
+ _pc = 0;
+ _state = Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL;
+ return S_OK;
+}
+
+Z7_COM7F_IMF2(UInt32, CCoder2::Filter(Byte *data, UInt32 size))
+{
+ const UInt32 processed = (UInt32)(size_t)(_convFunc(data, size, _pc, &_state) - data);
+ _pc += processed;
+ return processed;
+}
+
+}}
diff --git a/CPP/7zip/Compress/BcjCoder.h b/CPP/7zip/Compress/BcjCoder.h
index 475dfe5..734a278 100644
--- a/CPP/7zip/Compress/BcjCoder.h
+++ b/CPP/7zip/Compress/BcjCoder.h
@@ -1,31 +1,37 @@
-// BcjCoder.h
-
-#ifndef __COMPRESS_BCJ_CODER_H
-#define __COMPRESS_BCJ_CODER_H
-
-#include "../../../C/Bra.h"
-
-#include "../../Common/MyCom.h"
-
-#include "../ICoder.h"
-
-namespace NCompress {
-namespace NBcj {
-
-class CCoder:
- public ICompressFilter,
- public CMyUnknownImp
-{
- UInt32 _bufferPos;
- UInt32 _prevMask;
- int _encode;
-public:
- MY_UNKNOWN_IMP1(ICompressFilter);
- INTERFACE_ICompressFilter(;)
-
- CCoder(int encode): _bufferPos(0), _encode(encode) { x86_Convert_Init(_prevMask); }
-};
-
-}}
-
-#endif
+// BcjCoder.h
+
+#ifndef ZIP7_INC_COMPRESS_BCJ_CODER_H
+#define ZIP7_INC_COMPRESS_BCJ_CODER_H
+
+#include "../../../C/Bra.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NBcj {
+
+/* CCoder in old versions used another constructor parameter CCoder(int encode).
+ And some code called it as CCoder(0).
+ We have changed constructor parameter type.
+ So we have changed the name of class also to CCoder2. */
+
+Z7_CLASS_IMP_COM_1(
+ CCoder2
+ , ICompressFilter
+)
+ UInt32 _pc;
+ UInt32 _state;
+ z7_Func_BranchConvSt _convFunc;
+public:
+ CCoder2(z7_Func_BranchConvSt convFunc):
+ _pc(0),
+ _state(Z7_BRANCH_CONV_ST_X86_STATE_INIT_VAL),
+ _convFunc(convFunc)
+ {}
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/BcjRegister.cpp b/CPP/7zip/Compress/BcjRegister.cpp
index 48cc057..0348f64 100644
--- a/CPP/7zip/Compress/BcjRegister.cpp
+++ b/CPP/7zip/Compress/BcjRegister.cpp
@@ -1,17 +1,17 @@
-// BcjRegister.cpp
-
-#include "StdAfx.h"
-
-#include "../Common/RegisterCodec.h"
-
-#include "BcjCoder.h"
-
-namespace NCompress {
-namespace NBcj {
-
-REGISTER_FILTER_E(BCJ,
- CCoder(false),
- CCoder(true),
- 0x3030103, "BCJ")
-
-}}
+// BcjRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "BcjCoder.h"
+
+namespace NCompress {
+namespace NBcj {
+
+REGISTER_FILTER_E(BCJ,
+ CCoder2(z7_BranchConvSt_X86_Dec),
+ CCoder2(z7_BranchConvSt_X86_Enc),
+ 0x3030103, "BCJ")
+
+}}
diff --git a/CPP/7zip/Compress/BitlDecoder.cpp b/CPP/7zip/Compress/BitlDecoder.cpp
new file mode 100644
index 0000000..876e649
--- /dev/null
+++ b/CPP/7zip/Compress/BitlDecoder.cpp
@@ -0,0 +1,25 @@
+// BitlDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "BitlDecoder.h"
+
+namespace NBitl {
+
+Byte kInvertTable[256];
+
+static
+struct CInverterTableInitializer
+{
+ CInverterTableInitializer()
+ {
+ for (unsigned i = 0; i < 256; i++)
+ {
+ unsigned x = ((i & 0x55) << 1) | ((i & 0xAA) >> 1);
+ x = ((x & 0x33) << 2) | ((x & 0xCC) >> 2);
+ kInvertTable[i] = (Byte)(((x & 0x0F) << 4) | ((x & 0xF0) >> 4));
+ }
+ }
+} g_InverterTableInitializer;
+
+}
diff --git a/CPP/7zip/Compress/BitlDecoder.h b/CPP/7zip/Compress/BitlDecoder.h
new file mode 100644
index 0000000..789ad1f
--- /dev/null
+++ b/CPP/7zip/Compress/BitlDecoder.h
@@ -0,0 +1,172 @@
+// BitlDecoder.h -- the Least Significant Bit of byte is First
+
+#ifndef ZIP7_INC_BITL_DECODER_H
+#define ZIP7_INC_BITL_DECODER_H
+
+#include "../IStream.h"
+
+namespace NBitl {
+
+const unsigned kNumBigValueBits = 8 * 4;
+const unsigned kNumValueBytes = 3;
+const unsigned kNumValueBits = 8 * kNumValueBytes;
+
+const UInt32 kMask = (1 << kNumValueBits) - 1;
+
+extern Byte kInvertTable[256];
+
+/* TInByte must support "Extra Bytes" (bytes that can be read after the end of stream
+ TInByte::ReadByte() returns 0xFF after the end of stream
+ TInByte::NumExtraBytes contains the number "Extra Bytes"
+
+ Bitl decoder can read up to 4 bytes ahead to internal buffer. */
+
+template<class TInByte>
+class CBaseDecoder
+{
+protected:
+ unsigned _bitPos;
+ UInt32 _value;
+ TInByte _stream;
+public:
+ bool Create(UInt32 bufSize) { return _stream.Create(bufSize); }
+ void SetStream(ISequentialInStream *inStream) { _stream.SetStream(inStream); }
+ void Init()
+ {
+ _stream.Init();
+ _bitPos = kNumBigValueBits;
+ _value = 0;
+ }
+
+ // the size of portion data in real stream that was already read from this object.
+ // it doesn't include unused data in BitStream object buffer (up to 4 bytes)
+ // it doesn't include unused data in TInByte buffers
+ // it doesn't include virtual Extra bytes after the end of real stream data
+ UInt64 GetStreamSize() const
+ {
+ return ExtraBitsWereRead() ?
+ _stream.GetStreamSize():
+ GetProcessedSize();
+ }
+
+ // the size of virtual data that was read from this object.
+ UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() - ((kNumBigValueBits - _bitPos) >> 3); }
+
+ bool ThereAreDataInBitsBuffer() const { return this->_bitPos != kNumBigValueBits; }
+
+ Z7_FORCE_INLINE
+ void Normalize()
+ {
+ for (; _bitPos >= 8; _bitPos -= 8)
+ _value = ((UInt32)_stream.ReadByte() << (kNumBigValueBits - _bitPos)) | _value;
+ }
+
+ Z7_FORCE_INLINE
+ UInt32 ReadBits(unsigned numBits)
+ {
+ Normalize();
+ UInt32 res = _value & ((1 << numBits) - 1);
+ _bitPos += numBits;
+ _value >>= numBits;
+ return res;
+ }
+
+ bool ExtraBitsWereRead() const
+ {
+ return (_stream.NumExtraBytes > 4 || kNumBigValueBits - _bitPos < (_stream.NumExtraBytes << 3));
+ }
+
+ bool ExtraBitsWereRead_Fast() const
+ {
+ // full version is not inlined in vc6.
+ // return _stream.NumExtraBytes != 0 && (_stream.NumExtraBytes > 4 || kNumBigValueBits - _bitPos < (_stream.NumExtraBytes << 3));
+
+ // (_stream.NumExtraBytes > 4) is fast overread detection. It's possible that
+ // it doesn't return true, if small number of extra bits were read.
+ return (_stream.NumExtraBytes > 4);
+ }
+
+ // it must be fixed !!! with extra bits
+ // UInt32 GetNumExtraBytes() const { return _stream.NumExtraBytes; }
+};
+
+template<class TInByte>
+class CDecoder: public CBaseDecoder<TInByte>
+{
+ UInt32 _normalValue;
+
+public:
+ void Init()
+ {
+ CBaseDecoder<TInByte>::Init();
+ _normalValue = 0;
+ }
+
+ Z7_FORCE_INLINE
+ void Normalize()
+ {
+ for (; this->_bitPos >= 8; this->_bitPos -= 8)
+ {
+ Byte b = this->_stream.ReadByte();
+ _normalValue = ((UInt32)b << (kNumBigValueBits - this->_bitPos)) | _normalValue;
+ this->_value = (this->_value << 8) | kInvertTable[b];
+ }
+ }
+
+ Z7_FORCE_INLINE
+ UInt32 GetValue(unsigned numBits)
+ {
+ Normalize();
+ return ((this->_value >> (8 - this->_bitPos)) & kMask) >> (kNumValueBits - numBits);
+ }
+
+ Z7_FORCE_INLINE
+ void MovePos(unsigned numBits)
+ {
+ this->_bitPos += numBits;
+ _normalValue >>= numBits;
+ }
+
+ Z7_FORCE_INLINE
+ UInt32 ReadBits(unsigned numBits)
+ {
+ Normalize();
+ UInt32 res = _normalValue & ((1 << numBits) - 1);
+ MovePos(numBits);
+ return res;
+ }
+
+ void AlignToByte() { MovePos((32 - this->_bitPos) & 7); }
+
+ Z7_FORCE_INLINE
+ Byte ReadDirectByte() { return this->_stream.ReadByte(); }
+
+ Z7_FORCE_INLINE
+ Byte ReadAlignedByte()
+ {
+ if (this->_bitPos == kNumBigValueBits)
+ return this->_stream.ReadByte();
+ Byte b = (Byte)(_normalValue & 0xFF);
+ MovePos(8);
+ return b;
+ }
+
+ // call it only if the object is aligned for byte.
+ Z7_FORCE_INLINE
+ bool ReadAlignedByte_FromBuf(Byte &b)
+ {
+ if (this->_stream.NumExtraBytes != 0)
+ if (this->_stream.NumExtraBytes >= 4
+ || kNumBigValueBits - this->_bitPos <= (this->_stream.NumExtraBytes << 3))
+ return false;
+ if (this->_bitPos == kNumBigValueBits)
+ return this->_stream.ReadByte_FromBuf(b);
+ b = (Byte)(_normalValue & 0xFF);
+ MovePos(8);
+ return true;
+ }
+};
+
+}
+
+#endif
diff --git a/CPP/7zip/Compress/BitlEncoder.h b/CPP/7zip/Compress/BitlEncoder.h
new file mode 100644
index 0000000..67b1428
--- /dev/null
+++ b/CPP/7zip/Compress/BitlEncoder.h
@@ -0,0 +1,56 @@
+// BitlEncoder.h -- the Least Significant Bit of byte is First
+
+#ifndef ZIP7_INC_BITL_ENCODER_H
+#define ZIP7_INC_BITL_ENCODER_H
+
+#include "../Common/OutBuffer.h"
+
+class CBitlEncoder
+{
+ COutBuffer _stream;
+ unsigned _bitPos;
+ Byte _curByte;
+public:
+ bool Create(UInt32 bufSize) { return _stream.Create(bufSize); }
+ void SetStream(ISequentialOutStream *outStream) { _stream.SetStream(outStream); }
+ // unsigned GetBitPosition() const { return (8 - _bitPos); }
+ UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() + ((8 - _bitPos + 7) >> 3); }
+ void Init()
+ {
+ _stream.Init();
+ _bitPos = 8;
+ _curByte = 0;
+ }
+ HRESULT Flush()
+ {
+ FlushByte();
+ return _stream.Flush();
+ }
+ void FlushByte()
+ {
+ if (_bitPos < 8)
+ _stream.WriteByte(_curByte);
+ _bitPos = 8;
+ _curByte = 0;
+ }
+ void WriteBits(UInt32 value, unsigned numBits)
+ {
+ while (numBits > 0)
+ {
+ if (numBits < _bitPos)
+ {
+ _curByte |= (Byte)((value & ((1 << numBits) - 1)) << (8 - _bitPos));
+ _bitPos -= numBits;
+ return;
+ }
+ numBits -= _bitPos;
+ _stream.WriteByte((Byte)(_curByte | (value << (8 - _bitPos))));
+ value >>= _bitPos;
+ _bitPos = 8;
+ _curByte = 0;
+ }
+ }
+ void WriteByte(Byte b) { _stream.WriteByte(b);}
+};
+
+#endif
diff --git a/CPP/7zip/Compress/BitmDecoder.h b/CPP/7zip/Compress/BitmDecoder.h
new file mode 100644
index 0000000..199a228
--- /dev/null
+++ b/CPP/7zip/Compress/BitmDecoder.h
@@ -0,0 +1,100 @@
+// BitmDecoder.h -- the Most Significant Bit of byte is First
+
+#ifndef ZIP7_INC_BITM_DECODER_H
+#define ZIP7_INC_BITM_DECODER_H
+
+#include "../IStream.h"
+
+namespace NBitm {
+
+const unsigned kNumBigValueBits = 8 * 4;
+const unsigned kNumValueBytes = 3;
+const unsigned kNumValueBits = 8 * kNumValueBytes;
+
+const UInt32 kMask = (1 << kNumValueBits) - 1;
+
+// _bitPos - the number of free bits (high bits in _value)
+// (kNumBigValueBits - _bitPos) = (32 - _bitPos) == the number of ready to read bits (low bits of _value)
+
+template<class TInByte>
+class CDecoder
+{
+ unsigned _bitPos;
+ UInt32 _value;
+ TInByte _stream;
+public:
+ bool Create(UInt32 bufSize) { return _stream.Create(bufSize); }
+ void SetStream(ISequentialInStream *inStream) { _stream.SetStream(inStream);}
+
+ void Init()
+ {
+ _stream.Init();
+ _bitPos = kNumBigValueBits;
+ _value = 0;
+ Normalize();
+ }
+
+ UInt64 GetStreamSize() const { return _stream.GetStreamSize(); }
+ UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() - ((kNumBigValueBits - _bitPos) >> 3); }
+
+ bool ExtraBitsWereRead() const
+ {
+ return (_stream.NumExtraBytes > 4 || kNumBigValueBits - _bitPos < (_stream.NumExtraBytes << 3));
+ }
+
+ bool ExtraBitsWereRead_Fast() const
+ {
+ return (_stream.NumExtraBytes > 4);
+ }
+
+ Z7_FORCE_INLINE
+ void Normalize()
+ {
+ for (; _bitPos >= 8; _bitPos -= 8)
+ _value = (_value << 8) | _stream.ReadByte();
+ }
+
+ Z7_FORCE_INLINE
+ UInt32 GetValue(unsigned numBits) const
+ {
+ // return (_value << _bitPos) >> (kNumBigValueBits - numBits);
+ return ((_value >> (8 - _bitPos)) & kMask) >> (kNumValueBits - numBits);
+ }
+
+ Z7_FORCE_INLINE
+ void MovePos(unsigned numBits)
+ {
+ _bitPos += numBits;
+ Normalize();
+ }
+
+ Z7_FORCE_INLINE
+ UInt32 ReadBits(unsigned numBits)
+ {
+ UInt32 res = GetValue(numBits);
+ MovePos(numBits);
+ return res;
+ }
+
+ /*
+ unsigned ReadBit()
+ {
+ UInt32 res = ((_value >> (8 - _bitPos)) & kMask) >> (kNumValueBits - 1);
+ if (++_bitPos >= 8)
+ {
+ _value = (_value << 8) | _stream.ReadByte();
+ _bitPos -= 8;
+ }
+ return (unsigned)res;
+ }
+ */
+
+ void AlignToByte() { MovePos((kNumBigValueBits - _bitPos) & 7); }
+
+ Z7_FORCE_INLINE
+ UInt32 ReadAlignBits() { return ReadBits((kNumBigValueBits - _bitPos) & 7); }
+};
+
+}
+
+#endif
diff --git a/CPP/7zip/Compress/BitmEncoder.h b/CPP/7zip/Compress/BitmEncoder.h
new file mode 100644
index 0000000..978ee1c
--- /dev/null
+++ b/CPP/7zip/Compress/BitmEncoder.h
@@ -0,0 +1,49 @@
+// BitmEncoder.h -- the Most Significant Bit of byte is First
+
+#ifndef ZIP7_INC_BITM_ENCODER_H
+#define ZIP7_INC_BITM_ENCODER_H
+
+#include "../IStream.h"
+
+template<class TOutByte>
+class CBitmEncoder
+{
+ unsigned _bitPos;
+ Byte _curByte;
+ TOutByte _stream;
+public:
+ bool Create(UInt32 bufferSize) { return _stream.Create(bufferSize); }
+ void SetStream(ISequentialOutStream *outStream) { _stream.SetStream(outStream);}
+ UInt64 GetProcessedSize() const { return _stream.GetProcessedSize() + ((8 - _bitPos + 7) >> 3); }
+ void Init()
+ {
+ _stream.Init();
+ _bitPos = 8;
+ _curByte = 0;
+ }
+ HRESULT Flush()
+ {
+ if (_bitPos < 8)
+ WriteBits(0, _bitPos);
+ return _stream.Flush();
+ }
+ void WriteBits(UInt32 value, unsigned numBits)
+ {
+ while (numBits > 0)
+ {
+ if (numBits < _bitPos)
+ {
+ _curByte = (Byte)(_curByte | (value << (_bitPos -= numBits)));
+ return;
+ }
+ numBits -= _bitPos;
+ UInt32 newBits = (value >> numBits);
+ value -= (newBits << numBits);
+ _stream.WriteByte((Byte)(_curByte | newBits));
+ _bitPos = 8;
+ _curByte = 0;
+ }
+ }
+};
+
+#endif
diff --git a/CPP/7zip/Compress/BranchMisc.cpp b/CPP/7zip/Compress/BranchMisc.cpp
index d5a90f1..d9fec8c 100644
--- a/CPP/7zip/Compress/BranchMisc.cpp
+++ b/CPP/7zip/Compress/BranchMisc.cpp
@@ -1,23 +1,110 @@
-// BranchMisc.cpp
-
-#include "StdAfx.h"
-
-#include "BranchMisc.h"
-
-namespace NCompress {
-namespace NBranch {
-
-STDMETHODIMP CCoder::Init()
-{
- _bufferPos = 0;
- return S_OK;
-}
-
-STDMETHODIMP_(UInt32) CCoder::Filter(Byte *data, UInt32 size)
-{
- UInt32 processed = (UInt32)BraFunc(data, size, _bufferPos, _encode);
- _bufferPos += processed;
- return processed;
-}
-
-}}
+// BranchMisc.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "BranchMisc.h"
+
+namespace NCompress {
+namespace NBranch {
+
+Z7_COM7F_IMF(CCoder::Init())
+{
+ _pc = 0;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF2(UInt32, CCoder::Filter(Byte *data, UInt32 size))
+{
+ const UInt32 processed = (UInt32)(size_t)(BraFunc(data, size, _pc) - data);
+ _pc += processed;
+ return processed;
+}
+
+
+namespace NArm64 {
+
+#ifndef Z7_EXTRACT_ONLY
+
+Z7_COM7F_IMF(CEncoder::Init())
+{
+ _pc = _pc_Init;
+ return S_OK;
+}
+
+Z7_COM7F_IMF2(UInt32, CEncoder::Filter(Byte *data, UInt32 size))
+{
+ const UInt32 processed = (UInt32)(size_t)(Z7_BRANCH_CONV_ENC(ARM64)(data, size, _pc) - data);
+ _pc += processed;
+ return processed;
+}
+
+Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps))
+{
+ UInt32 pc = 0;
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPID propID = propIDs[i];
+ if (propID == NCoderPropID::kDefaultProp ||
+ propID == NCoderPropID::kBranchOffset)
+ {
+ const PROPVARIANT &prop = props[i];
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ pc = prop.ulVal;
+ if ((pc & 3) != 0)
+ return E_INVALIDARG;
+ }
+ }
+ _pc_Init = pc;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream))
+{
+ if (_pc_Init == 0)
+ return S_OK;
+ Byte buf[4];
+ SetUi32(buf, _pc_Init)
+ return WriteStream(outStream, buf, 4);
+}
+
+#endif
+
+
+Z7_COM7F_IMF(CDecoder::Init())
+{
+ _pc = _pc_Init;
+ return S_OK;
+}
+
+Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size))
+{
+ const UInt32 processed = (UInt32)(size_t)(Z7_BRANCH_CONV_DEC(ARM64)(data, size, _pc) - data);
+ _pc += processed;
+ return processed;
+}
+
+Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size))
+{
+ UInt32 val = 0;
+ if (size != 0)
+ {
+ if (size != 4)
+ return E_NOTIMPL;
+ val = GetUi32(props);
+ if ((val & 3) != 0)
+ return E_NOTIMPL;
+ }
+ _pc_Init = val;
+ return S_OK;
+}
+
+}
+
+}}
diff --git a/CPP/7zip/Compress/BranchMisc.h b/CPP/7zip/Compress/BranchMisc.h
index 02a56c3..a5793f7 100644
--- a/CPP/7zip/Compress/BranchMisc.h
+++ b/CPP/7zip/Compress/BranchMisc.h
@@ -1,35 +1,57 @@
-// BranchMisc.h
-
-#ifndef __COMPRESS_BRANCH_MISC_H
-#define __COMPRESS_BRANCH_MISC_H
-
-#include "../../Common/MyCom.h"
-
-#include "../ICoder.h"
-
-EXTERN_C_BEGIN
-
-typedef SizeT (*Func_Bra)(Byte *data, SizeT size, UInt32 ip, int encoding);
-
-EXTERN_C_END
-
-namespace NCompress {
-namespace NBranch {
-
-class CCoder:
- public ICompressFilter,
- public CMyUnknownImp
-{
- UInt32 _bufferPos;
- int _encode;
- Func_Bra BraFunc;
-public:
- MY_UNKNOWN_IMP1(ICompressFilter);
- INTERFACE_ICompressFilter(;)
-
- CCoder(Func_Bra bra, int encode): _bufferPos(0), _encode(encode), BraFunc(bra) {}
-};
-
-}}
-
-#endif
+// BranchMisc.h
+
+#ifndef ZIP7_INC_COMPRESS_BRANCH_MISC_H
+#define ZIP7_INC_COMPRESS_BRANCH_MISC_H
+#include "../../../C/Bra.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NBranch {
+
+Z7_CLASS_IMP_COM_1(
+ CCoder
+ , ICompressFilter
+)
+ UInt32 _pc;
+ z7_Func_BranchConv BraFunc;
+public:
+ CCoder(z7_Func_BranchConv bra): _pc(0), BraFunc(bra) {}
+};
+
+namespace NArm64 {
+
+#ifndef Z7_EXTRACT_ONLY
+
+Z7_CLASS_IMP_COM_3(
+ CEncoder
+ , ICompressFilter
+ , ICompressSetCoderProperties
+ , ICompressWriteCoderProperties
+)
+ UInt32 _pc;
+ UInt32 _pc_Init;
+public:
+ CEncoder(): _pc(0), _pc_Init(0) {}
+};
+
+#endif
+
+Z7_CLASS_IMP_COM_2(
+ CDecoder
+ , ICompressFilter
+ , ICompressSetDecoderProperties2
+)
+ UInt32 _pc;
+ UInt32 _pc_Init;
+public:
+ CDecoder(): _pc(0), _pc_Init(0) {}
+};
+
+}
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/BranchRegister.cpp b/CPP/7zip/Compress/BranchRegister.cpp
index b83c6bc..80fbf60 100644
--- a/CPP/7zip/Compress/BranchRegister.cpp
+++ b/CPP/7zip/Compress/BranchRegister.cpp
@@ -1,41 +1,55 @@
-// BranchRegister.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/Bra.h"
-
-#include "../Common/RegisterCodec.h"
-
-#include "BranchMisc.h"
-
-namespace NCompress {
-namespace NBranch {
-
-#define CREATE_BRA(n) \
- REGISTER_FILTER_CREATE(CreateBra_Decoder_ ## n, CCoder(n ## _Convert, false)) \
- REGISTER_FILTER_CREATE(CreateBra_Encoder_ ## n, CCoder(n ## _Convert, true)) \
-
-CREATE_BRA(PPC)
-CREATE_BRA(IA64)
-CREATE_BRA(ARM)
-CREATE_BRA(ARMT)
-CREATE_BRA(SPARC)
-
-#define METHOD_ITEM(n, id, name) \
- REGISTER_FILTER_ITEM( \
- CreateBra_Decoder_ ## n, \
- CreateBra_Encoder_ ## n, \
- 0x3030000 + id, name)
-
-REGISTER_CODECS_VAR
-{
- METHOD_ITEM(PPC, 0x205, "PPC"),
- METHOD_ITEM(IA64, 0x401, "IA64"),
- METHOD_ITEM(ARM, 0x501, "ARM"),
- METHOD_ITEM(ARMT, 0x701, "ARMT"),
- METHOD_ITEM(SPARC, 0x805, "SPARC")
-};
-
-REGISTER_CODECS(Branch)
-
-}}
+// BranchRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "BranchMisc.h"
+
+namespace NCompress {
+namespace NBranch {
+
+#ifdef Z7_EXTRACT_ONLY
+#define GET_CREATE_FUNC(x) NULL
+#define CREATE_BRA_E(n)
+#else
+#define GET_CREATE_FUNC(x) x
+#define CREATE_BRA_E(n) \
+ REGISTER_FILTER_CREATE(CreateBra_Encoder_ ## n, CCoder(Z7_BRANCH_CONV_ENC(n)))
+#endif
+
+#define CREATE_BRA(n) \
+ REGISTER_FILTER_CREATE(CreateBra_Decoder_ ## n, CCoder(Z7_BRANCH_CONV_DEC(n))) \
+ CREATE_BRA_E(n)
+
+CREATE_BRA(PPC)
+CREATE_BRA(IA64)
+CREATE_BRA(ARM)
+CREATE_BRA(ARMT)
+CREATE_BRA(SPARC)
+
+#define METHOD_ITEM(n, id, name) \
+ REGISTER_FILTER_ITEM( \
+ CreateBra_Decoder_ ## n, GET_CREATE_FUNC( \
+ CreateBra_Encoder_ ## n), \
+ 0x3030000 + id, name)
+
+REGISTER_CODECS_VAR
+{
+ METHOD_ITEM(PPC, 0x205, "PPC"),
+ METHOD_ITEM(IA64, 0x401, "IA64"),
+ METHOD_ITEM(ARM, 0x501, "ARM"),
+ METHOD_ITEM(ARMT, 0x701, "ARMT"),
+ METHOD_ITEM(SPARC, 0x805, "SPARC")
+};
+
+REGISTER_CODECS(Branch)
+
+namespace NArm64 {
+REGISTER_FILTER_E(ARM64,
+ CDecoder(),
+ CEncoder(),
+ 0xa, "ARM64")
+}
+
+}}
diff --git a/CPP/7zip/Compress/ByteSwap.cpp b/CPP/7zip/Compress/ByteSwap.cpp
index ee103af..cc28d8b 100644
--- a/CPP/7zip/Compress/ByteSwap.cpp
+++ b/CPP/7zip/Compress/ByteSwap.cpp
@@ -1,92 +1,91 @@
-// ByteSwap.cpp
-
-#include "StdAfx.h"
-
-#include "../../Common/MyCom.h"
-
-#include "../ICoder.h"
-
-#include "../Common/RegisterCodec.h"
-
-namespace NCompress {
-namespace NByteSwap {
-
-class CByteSwap2:
- public ICompressFilter,
- public CMyUnknownImp
-{
-public:
- MY_UNKNOWN_IMP1(ICompressFilter);
- INTERFACE_ICompressFilter(;)
-};
-
-class CByteSwap4:
- public ICompressFilter,
- public CMyUnknownImp
-{
-public:
- MY_UNKNOWN_IMP1(ICompressFilter);
- INTERFACE_ICompressFilter(;)
-};
-
-STDMETHODIMP CByteSwap2::Init() { return S_OK; }
-
-STDMETHODIMP_(UInt32) CByteSwap2::Filter(Byte *data, UInt32 size)
-{
- const UInt32 kStep = 2;
- if (size < kStep)
- return 0;
- size &= ~(kStep - 1);
-
- const Byte *end = data + (size_t)size;
-
- do
- {
- Byte b0 = data[0];
- data[0] = data[1];
- data[1] = b0;
- data += kStep;
- }
- while (data != end);
-
- return size;
-}
-
-STDMETHODIMP CByteSwap4::Init() { return S_OK; }
-
-STDMETHODIMP_(UInt32) CByteSwap4::Filter(Byte *data, UInt32 size)
-{
- const UInt32 kStep = 4;
- if (size < kStep)
- return 0;
- size &= ~(kStep - 1);
-
- const Byte *end = data + (size_t)size;
-
- do
- {
- Byte b0 = data[0];
- Byte b1 = data[1];
- data[0] = data[3];
- data[1] = data[2];
- data[2] = b1;
- data[3] = b0;
- data += kStep;
- }
- while (data != end);
-
- return size;
-}
-
-REGISTER_FILTER_CREATE(CreateFilter2, CByteSwap2())
-REGISTER_FILTER_CREATE(CreateFilter4, CByteSwap4())
-
-REGISTER_CODECS_VAR
-{
- REGISTER_FILTER_ITEM(CreateFilter2, CreateFilter2, 0x20302, "Swap2"),
- REGISTER_FILTER_ITEM(CreateFilter4, CreateFilter4, 0x20304, "Swap4")
-};
-
-REGISTER_CODECS(ByteSwap)
-
-}}
+// ByteSwap.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/SwapBytes.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/RegisterCodec.h"
+
+namespace NCompress {
+namespace NByteSwap {
+
+Z7_CLASS_IMP_COM_1(CByteSwap2, ICompressFilter) };
+Z7_CLASS_IMP_COM_1(CByteSwap4, ICompressFilter) };
+
+Z7_COM7F_IMF(CByteSwap2::Init()) { return S_OK; }
+
+Z7_COM7F_IMF2(UInt32, CByteSwap2::Filter(Byte *data, UInt32 size))
+{
+ const UInt32 kMask = 2 - 1;
+ size &= ~kMask;
+ /*
+ if ((unsigned)(ptrdiff_t)data & kMask)
+ {
+ if (size == 0)
+ return 0;
+ const Byte *end = data + (size_t)size;
+ do
+ {
+ const Byte b0 = data[0];
+ data[0] = data[1];
+ data[1] = b0;
+ data += kStep;
+ }
+ while (data != end);
+ }
+ else
+ */
+ z7_SwapBytes2((UInt16 *)(void *)data, size >> 1);
+ return size;
+}
+
+
+Z7_COM7F_IMF(CByteSwap4::Init()) { return S_OK; }
+
+Z7_COM7F_IMF2(UInt32, CByteSwap4::Filter(Byte *data, UInt32 size))
+{
+ const UInt32 kMask = 4 - 1;
+ size &= ~kMask;
+ /*
+ if ((unsigned)(ptrdiff_t)data & kMask)
+ {
+ if (size == 0)
+ return 0;
+ const Byte *end = data + (size_t)size;
+ do
+ {
+ const Byte b0 = data[0];
+ const Byte b1 = data[1];
+ data[0] = data[3];
+ data[1] = data[2];
+ data[2] = b1;
+ data[3] = b0;
+ data += kStep;
+ }
+ while (data != end);
+ }
+ else
+ */
+ z7_SwapBytes4((UInt32 *)(void *)data, size >> 2);
+ return size;
+}
+
+static struct C_SwapBytesPrepare { C_SwapBytesPrepare() { z7_SwapBytesPrepare(); } } g_SwapBytesPrepare;
+
+
+REGISTER_FILTER_CREATE(CreateFilter2, CByteSwap2())
+REGISTER_FILTER_CREATE(CreateFilter4, CByteSwap4())
+
+REGISTER_CODECS_VAR
+{
+ REGISTER_FILTER_ITEM(CreateFilter2, CreateFilter2, 0x20302, "Swap2"),
+ REGISTER_FILTER_ITEM(CreateFilter4, CreateFilter4, 0x20304, "Swap4"),
+};
+
+REGISTER_CODECS(ByteSwap)
+
+}}
diff --git a/CPP/7zip/Compress/Codec.def b/CPP/7zip/Compress/Codec.def
new file mode 100644
index 0000000..e2bc0df
--- /dev/null
+++ b/CPP/7zip/Compress/Codec.def
@@ -0,0 +1,7 @@
+EXPORTS
+ CreateObject PRIVATE
+ GetNumberOfMethods PRIVATE
+ GetMethodProperty PRIVATE
+ CreateDecoder PRIVATE
+ CreateEncoder PRIVATE
+ GetModuleProp PRIVATE
diff --git a/CPP/7zip/Compress/CodecExports.cpp b/CPP/7zip/Compress/CodecExports.cpp
index 7be496c..e37ae14 100644
--- a/CPP/7zip/Compress/CodecExports.cpp
+++ b/CPP/7zip/Compress/CodecExports.cpp
@@ -1,344 +1,378 @@
-// CodecExports.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/CpuArch.h"
-
-#include "../../Common/ComTry.h"
-#include "../../Common/MyCom.h"
-
-#include "../../Windows/Defs.h"
-
-#include "../ICoder.h"
-
-#include "../Common/RegisterCodec.h"
-
-extern unsigned g_NumCodecs;
-extern const CCodecInfo *g_Codecs[];
-
-extern unsigned g_NumHashers;
-extern const CHasherInfo *g_Hashers[];
-
-static void SetPropFromAscii(const char *s, PROPVARIANT *prop) throw()
-{
- UINT len = (UINT)strlen(s);
- BSTR dest = ::SysAllocStringLen(NULL, len);
- if (dest)
- {
- for (UINT i = 0; i <= len; i++)
- dest[i] = (Byte)s[i];
- prop->bstrVal = dest;
- prop->vt = VT_BSTR;
- }
-}
-
-static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value) throw()
-{
- if ((value->bstrVal = ::SysAllocStringByteLen((const char *)&guid, sizeof(guid))) != NULL)
- value->vt = VT_BSTR;
- return S_OK;
-}
-
-static HRESULT MethodToClassID(UInt16 typeId, CMethodId id, PROPVARIANT *value) throw()
-{
- GUID clsId;
- clsId.Data1 = k_7zip_GUID_Data1;
- clsId.Data2 = k_7zip_GUID_Data2;
- clsId.Data3 = typeId;
- SetUi64(clsId.Data4, id);
- return SetPropGUID(clsId, value);
-}
-
-static HRESULT FindCodecClassId(const GUID *clsid, bool isCoder2, bool isFilter, bool &encode, int &index) throw()
-{
- index = -1;
- if (clsid->Data1 != k_7zip_GUID_Data1 ||
- clsid->Data2 != k_7zip_GUID_Data2)
- return S_OK;
-
- encode = true;
-
- if (clsid->Data3 == k_7zip_GUID_Data3_Decoder) encode = false;
- else if (clsid->Data3 != k_7zip_GUID_Data3_Encoder) return S_OK;
-
- UInt64 id = GetUi64(clsid->Data4);
-
- for (unsigned i = 0; i < g_NumCodecs; i++)
- {
- const CCodecInfo &codec = *g_Codecs[i];
-
- if (id != codec.Id
- || (encode ? !codec.CreateEncoder : !codec.CreateDecoder)
- || (isFilter ? !codec.IsFilter : codec.IsFilter))
- continue;
-
- if (codec.NumStreams == 1 ? isCoder2 : !isCoder2)
- return E_NOINTERFACE;
-
- index = i;
- return S_OK;
- }
-
- return S_OK;
-}
-
-static HRESULT CreateCoderMain(unsigned index, bool encode, void **coder)
-{
- COM_TRY_BEGIN
-
- const CCodecInfo &codec = *g_Codecs[index];
-
- void *c;
- if (encode)
- c = codec.CreateEncoder();
- else
- c = codec.CreateDecoder();
-
- if (c)
- {
- IUnknown *unk;
- if (codec.IsFilter)
- unk = (IUnknown *)(ICompressFilter *)c;
- else if (codec.NumStreams != 1)
- unk = (IUnknown *)(ICompressCoder2 *)c;
- else
- unk = (IUnknown *)(ICompressCoder *)c;
- unk->AddRef();
- *coder = c;
- }
- return S_OK;
-
- COM_TRY_END
-}
-
-static HRESULT CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject)
-{
- *outObject = NULL;
-
- const CCodecInfo &codec = *g_Codecs[index];
-
- if (encode ? !codec.CreateEncoder : !codec.CreateDecoder)
- return CLASS_E_CLASSNOTAVAILABLE;
-
- if (codec.IsFilter)
- {
- if (*iid != IID_ICompressFilter) return E_NOINTERFACE;
- }
- else if (codec.NumStreams != 1)
- {
- if (*iid != IID_ICompressCoder2) return E_NOINTERFACE;
- }
- else
- {
- if (*iid != IID_ICompressCoder) return E_NOINTERFACE;
- }
-
- return CreateCoderMain(index, encode, outObject);
-}
-
-STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject)
-{
- return CreateCoder2(false, index, iid, outObject);
-}
-
-STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject)
-{
- return CreateCoder2(true, index, iid, outObject);
-}
-
-STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject)
-{
- *outObject = NULL;
-
- bool isFilter = false;
- bool isCoder2 = false;
- bool isCoder = (*iid == IID_ICompressCoder) != 0;
- if (!isCoder)
- {
- isFilter = (*iid == IID_ICompressFilter) != 0;
- if (!isFilter)
- {
- isCoder2 = (*iid == IID_ICompressCoder2) != 0;
- if (!isCoder2)
- return E_NOINTERFACE;
- }
- }
-
- bool encode;
- int codecIndex;
- HRESULT res = FindCodecClassId(clsid, isCoder2, isFilter, encode, codecIndex);
- if (res != S_OK)
- return res;
- if (codecIndex < 0)
- return CLASS_E_CLASSNOTAVAILABLE;
-
- return CreateCoderMain(codecIndex, encode, outObject);
-}
-
-STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value)
-{
- ::VariantClear((VARIANTARG *)value);
- const CCodecInfo &codec = *g_Codecs[codecIndex];
- switch (propID)
- {
- case NMethodPropID::kID:
- value->uhVal.QuadPart = (UInt64)codec.Id;
- value->vt = VT_UI8;
- break;
- case NMethodPropID::kName:
- SetPropFromAscii(codec.Name, value);
- break;
- case NMethodPropID::kDecoder:
- if (codec.CreateDecoder)
- return MethodToClassID(k_7zip_GUID_Data3_Decoder, codec.Id, value);
- break;
- case NMethodPropID::kEncoder:
- if (codec.CreateEncoder)
- return MethodToClassID(k_7zip_GUID_Data3_Encoder, codec.Id, value);
- break;
- case NMethodPropID::kDecoderIsAssigned:
- value->vt = VT_BOOL;
- value->boolVal = BoolToVARIANT_BOOL(codec.CreateDecoder != NULL);
- break;
- case NMethodPropID::kEncoderIsAssigned:
- value->vt = VT_BOOL;
- value->boolVal = BoolToVARIANT_BOOL(codec.CreateEncoder != NULL);
- break;
- case NMethodPropID::kPackStreams:
- if (codec.NumStreams != 1)
- {
- value->vt = VT_UI4;
- value->ulVal = (ULONG)codec.NumStreams;
- }
- break;
- /*
- case NMethodPropID::kIsFilter:
- // if (codec.IsFilter)
- {
- value->vt = VT_BOOL;
- value->boolVal = BoolToVARIANT_BOOL(codec.IsFilter);
- }
- break;
- */
- /*
- case NMethodPropID::kDecoderFlags:
- {
- value->vt = VT_UI4;
- value->ulVal = (ULONG)codec.DecoderFlags;
- }
- break;
- case NMethodPropID::kEncoderFlags:
- {
- value->vt = VT_UI4;
- value->ulVal = (ULONG)codec.EncoderFlags;
- }
- break;
- */
- }
- return S_OK;
-}
-
-STDAPI GetNumberOfMethods(UINT32 *numCodecs)
-{
- *numCodecs = g_NumCodecs;
- return S_OK;
-}
-
-
-// ---------- Hashers ----------
-
-static int FindHasherClassId(const GUID *clsid) throw()
-{
- if (clsid->Data1 != k_7zip_GUID_Data1 ||
- clsid->Data2 != k_7zip_GUID_Data2 ||
- clsid->Data3 != k_7zip_GUID_Data3_Hasher)
- return -1;
- UInt64 id = GetUi64(clsid->Data4);
- for (unsigned i = 0; i < g_NumCodecs; i++)
- if (id == g_Hashers[i]->Id)
- return i;
- return -1;
-}
-
-static HRESULT CreateHasher2(UInt32 index, IHasher **hasher)
-{
- COM_TRY_BEGIN
- *hasher = g_Hashers[index]->CreateHasher();
- if (*hasher)
- (*hasher)->AddRef();
- return S_OK;
- COM_TRY_END
-}
-
-STDAPI CreateHasher(const GUID *clsid, IHasher **outObject)
-{
- COM_TRY_BEGIN
- *outObject = 0;
- int index = FindHasherClassId(clsid);
- if (index < 0)
- return CLASS_E_CLASSNOTAVAILABLE;
- return CreateHasher2(index, outObject);
- COM_TRY_END
-}
-
-STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value)
-{
- ::VariantClear((VARIANTARG *)value);
- const CHasherInfo &codec = *g_Hashers[codecIndex];
- switch (propID)
- {
- case NMethodPropID::kID:
- value->uhVal.QuadPart = (UInt64)codec.Id;
- value->vt = VT_UI8;
- break;
- case NMethodPropID::kName:
- SetPropFromAscii(codec.Name, value);
- break;
- case NMethodPropID::kEncoder:
- if (codec.CreateHasher)
- return MethodToClassID(k_7zip_GUID_Data3_Hasher, codec.Id, value);
- break;
- case NMethodPropID::kDigestSize:
- value->ulVal = (ULONG)codec.DigestSize;
- value->vt = VT_UI4;
- break;
- }
- return S_OK;
-}
-
-class CHashers:
- public IHashers,
- public CMyUnknownImp
-{
-public:
- MY_UNKNOWN_IMP1(IHashers)
-
- STDMETHOD_(UInt32, GetNumHashers)();
- STDMETHOD(GetHasherProp)(UInt32 index, PROPID propID, PROPVARIANT *value);
- STDMETHOD(CreateHasher)(UInt32 index, IHasher **hasher);
-};
-
-STDAPI GetHashers(IHashers **hashers)
-{
- COM_TRY_BEGIN
- *hashers = new CHashers;
- if (*hashers)
- (*hashers)->AddRef();
- return S_OK;
- COM_TRY_END
-}
-
-STDMETHODIMP_(UInt32) CHashers::GetNumHashers()
-{
- return g_NumHashers;
-}
-
-STDMETHODIMP CHashers::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)
-{
- return ::GetHasherProp(index, propID, value);
-}
-
-STDMETHODIMP CHashers::CreateHasher(UInt32 index, IHasher **hasher)
-{
- return ::CreateHasher2(index, hasher);
-}
+// CodecExports.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+#include "../../../C/7zVersion.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/MyCom.h"
+
+#include "../../Windows/Defs.h"
+#include "../../Windows/PropVariant.h"
+
+#include "../ICoder.h"
+
+#include "../Common/RegisterCodec.h"
+
+extern unsigned g_NumCodecs;
+extern const CCodecInfo *g_Codecs[];
+
+extern unsigned g_NumHashers;
+extern const CHasherInfo *g_Hashers[];
+
+static void SetPropFromAscii(const char *s, PROPVARIANT *prop) throw()
+{
+ const UINT len = (UINT)strlen(s);
+ BSTR dest = ::SysAllocStringLen(NULL, len);
+ if (dest)
+ {
+ for (UINT i = 0; i <= len; i++)
+ dest[i] = (Byte)s[i];
+ prop->bstrVal = dest;
+ prop->vt = VT_BSTR;
+ }
+}
+
+static inline HRESULT SetPropGUID(const GUID &guid, PROPVARIANT *value) throw()
+{
+ if ((value->bstrVal = ::SysAllocStringByteLen((const char *)&guid, sizeof(guid))) != NULL)
+ value->vt = VT_BSTR;
+ return S_OK;
+}
+
+static HRESULT MethodToClassID(UInt16 typeId, CMethodId id, PROPVARIANT *value) throw()
+{
+ GUID clsId;
+ clsId.Data1 = k_7zip_GUID_Data1;
+ clsId.Data2 = k_7zip_GUID_Data2;
+ clsId.Data3 = typeId;
+ SetUi64(clsId.Data4, id)
+ return SetPropGUID(clsId, value);
+}
+
+static HRESULT FindCodecClassId(const GUID *clsid, bool isCoder2, bool isFilter, bool &encode, int &index) throw()
+{
+ index = -1;
+ if (clsid->Data1 != k_7zip_GUID_Data1 ||
+ clsid->Data2 != k_7zip_GUID_Data2)
+ return S_OK;
+
+ encode = true;
+
+ if (clsid->Data3 == k_7zip_GUID_Data3_Decoder) encode = false;
+ else if (clsid->Data3 != k_7zip_GUID_Data3_Encoder) return S_OK;
+
+ const UInt64 id = GetUi64(clsid->Data4);
+
+ for (unsigned i = 0; i < g_NumCodecs; i++)
+ {
+ const CCodecInfo &codec = *g_Codecs[i];
+
+ if (id != codec.Id
+ || (encode ? !codec.CreateEncoder : !codec.CreateDecoder)
+ || (isFilter ? !codec.IsFilter : codec.IsFilter))
+ continue;
+
+ if (codec.NumStreams == 1 ? isCoder2 : !isCoder2)
+ return E_NOINTERFACE;
+
+ index = (int)i;
+ return S_OK;
+ }
+
+ return S_OK;
+}
+
+/*
+#ifdef __GNUC__
+#ifndef __clang__
+#pragma GCC diagnostic ignored "-Wduplicated-branches"
+#endif
+#endif
+*/
+
+static HRESULT CreateCoderMain(unsigned index, bool encode, void **coder)
+{
+ COM_TRY_BEGIN
+
+ const CCodecInfo &codec = *g_Codecs[index];
+
+ void *c;
+ if (encode)
+ c = codec.CreateEncoder();
+ else
+ c = codec.CreateDecoder();
+
+ if (c)
+ {
+ IUnknown *unk;
+ unk = (IUnknown *)c;
+ /*
+ if (codec.IsFilter)
+ unk = (IUnknown *)(ICompressFilter *)c;
+ else if (codec.NumStreams != 1)
+ unk = (IUnknown *)(ICompressCoder2 *)c;
+ else
+ unk = (IUnknown *)(ICompressCoder *)c;
+ */
+ unk->AddRef();
+ *coder = c;
+ }
+ return S_OK;
+
+ COM_TRY_END
+}
+
+static HRESULT CreateCoder2(bool encode, UInt32 index, const GUID *iid, void **outObject)
+{
+ *outObject = NULL;
+
+ const CCodecInfo &codec = *g_Codecs[index];
+
+ if (encode ? !codec.CreateEncoder : !codec.CreateDecoder)
+ return CLASS_E_CLASSNOTAVAILABLE;
+
+ if (codec.IsFilter)
+ {
+ if (*iid != IID_ICompressFilter) return E_NOINTERFACE;
+ }
+ else if (codec.NumStreams != 1)
+ {
+ if (*iid != IID_ICompressCoder2) return E_NOINTERFACE;
+ }
+ else
+ {
+ if (*iid != IID_ICompressCoder) return E_NOINTERFACE;
+ }
+
+ return CreateCoderMain(index, encode, outObject);
+}
+
+
+STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject);
+STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject)
+{
+ return CreateCoder2(false, index, iid, outObject);
+}
+
+
+STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject);
+STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject)
+{
+ return CreateCoder2(true, index, iid, outObject);
+}
+
+
+STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject);
+STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject)
+{
+ *outObject = NULL;
+
+ bool isFilter = false;
+ bool isCoder2 = false;
+ const bool isCoder = (*iid == IID_ICompressCoder) != 0;
+ if (!isCoder)
+ {
+ isFilter = (*iid == IID_ICompressFilter) != 0;
+ if (!isFilter)
+ {
+ isCoder2 = (*iid == IID_ICompressCoder2) != 0;
+ if (!isCoder2)
+ return E_NOINTERFACE;
+ }
+ }
+
+ bool encode;
+ int codecIndex;
+ const HRESULT res = FindCodecClassId(clsid, isCoder2, isFilter, encode, codecIndex);
+ if (res != S_OK)
+ return res;
+ if (codecIndex < 0)
+ return CLASS_E_CLASSNOTAVAILABLE;
+
+ return CreateCoderMain((unsigned)codecIndex, encode, outObject);
+}
+
+
+STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
+STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value)
+{
+ ::VariantClear((VARIANTARG *)value);
+ const CCodecInfo &codec = *g_Codecs[codecIndex];
+ switch (propID)
+ {
+ case NMethodPropID::kID:
+ value->uhVal.QuadPart = (UInt64)codec.Id;
+ value->vt = VT_UI8;
+ break;
+ case NMethodPropID::kName:
+ SetPropFromAscii(codec.Name, value);
+ break;
+ case NMethodPropID::kDecoder:
+ if (codec.CreateDecoder)
+ return MethodToClassID(k_7zip_GUID_Data3_Decoder, codec.Id, value);
+ break;
+ case NMethodPropID::kEncoder:
+ if (codec.CreateEncoder)
+ return MethodToClassID(k_7zip_GUID_Data3_Encoder, codec.Id, value);
+ break;
+ case NMethodPropID::kDecoderIsAssigned:
+ value->vt = VT_BOOL;
+ value->boolVal = BoolToVARIANT_BOOL(codec.CreateDecoder != NULL);
+ break;
+ case NMethodPropID::kEncoderIsAssigned:
+ value->vt = VT_BOOL;
+ value->boolVal = BoolToVARIANT_BOOL(codec.CreateEncoder != NULL);
+ break;
+ case NMethodPropID::kPackStreams:
+ if (codec.NumStreams != 1)
+ {
+ value->vt = VT_UI4;
+ value->ulVal = (ULONG)codec.NumStreams;
+ }
+ break;
+ case NMethodPropID::kIsFilter:
+ {
+ value->vt = VT_BOOL;
+ value->boolVal = BoolToVARIANT_BOOL(codec.IsFilter);
+ }
+ break;
+ /*
+ case NMethodPropID::kDecoderFlags:
+ {
+ value->vt = VT_UI4;
+ value->ulVal = (ULONG)codec.DecoderFlags;
+ }
+ break;
+ case NMethodPropID::kEncoderFlags:
+ {
+ value->vt = VT_UI4;
+ value->ulVal = (ULONG)codec.EncoderFlags;
+ }
+ break;
+ */
+ }
+ return S_OK;
+}
+
+
+STDAPI GetNumberOfMethods(UInt32 *numCodecs);
+STDAPI GetNumberOfMethods(UInt32 *numCodecs)
+{
+ *numCodecs = g_NumCodecs;
+ return S_OK;
+}
+
+
+// ---------- Hashers ----------
+
+static int FindHasherClassId(const GUID *clsid) throw()
+{
+ if (clsid->Data1 != k_7zip_GUID_Data1 ||
+ clsid->Data2 != k_7zip_GUID_Data2 ||
+ clsid->Data3 != k_7zip_GUID_Data3_Hasher)
+ return -1;
+ const UInt64 id = GetUi64(clsid->Data4);
+ for (unsigned i = 0; i < g_NumCodecs; i++)
+ if (id == g_Hashers[i]->Id)
+ return (int)i;
+ return -1;
+}
+
+static HRESULT CreateHasher2(UInt32 index, IHasher **hasher)
+{
+ COM_TRY_BEGIN
+ *hasher = g_Hashers[index]->CreateHasher();
+ if (*hasher)
+ (*hasher)->AddRef();
+ return S_OK;
+ COM_TRY_END
+}
+
+STDAPI CreateHasher(const GUID *clsid, IHasher **outObject);
+STDAPI CreateHasher(const GUID *clsid, IHasher **outObject)
+{
+ COM_TRY_BEGIN
+ *outObject = NULL;
+ const int index = FindHasherClassId(clsid);
+ if (index < 0)
+ return CLASS_E_CLASSNOTAVAILABLE;
+ return CreateHasher2((UInt32)(unsigned)index, outObject);
+ COM_TRY_END
+}
+
+STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
+STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value)
+{
+ ::VariantClear((VARIANTARG *)value);
+ const CHasherInfo &codec = *g_Hashers[codecIndex];
+ switch (propID)
+ {
+ case NMethodPropID::kID:
+ value->uhVal.QuadPart = (UInt64)codec.Id;
+ value->vt = VT_UI8;
+ break;
+ case NMethodPropID::kName:
+ SetPropFromAscii(codec.Name, value);
+ break;
+ case NMethodPropID::kEncoder:
+ if (codec.CreateHasher)
+ return MethodToClassID(k_7zip_GUID_Data3_Hasher, codec.Id, value);
+ break;
+ case NMethodPropID::kDigestSize:
+ value->ulVal = (ULONG)codec.DigestSize;
+ value->vt = VT_UI4;
+ break;
+ }
+ return S_OK;
+}
+
+Z7_CLASS_IMP_COM_1(CHashers, IHashers) };
+
+STDAPI GetHashers(IHashers **hashers);
+STDAPI GetHashers(IHashers **hashers)
+{
+ COM_TRY_BEGIN
+ *hashers = new CHashers;
+ if (*hashers)
+ (*hashers)->AddRef();
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF2(UInt32, CHashers::GetNumHashers())
+{
+ return g_NumHashers;
+}
+
+Z7_COM7F_IMF(CHashers::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ return ::GetHasherProp(index, propID, value);
+}
+
+Z7_COM7F_IMF(CHashers::CreateHasher(UInt32 index, IHasher **hasher))
+{
+ return ::CreateHasher2(index, hasher);
+}
+
+
+STDAPI GetModuleProp(PROPID propID, PROPVARIANT *value);
+STDAPI GetModuleProp(PROPID propID, PROPVARIANT *value)
+{
+ ::VariantClear((VARIANTARG *)value);
+ switch (propID)
+ {
+ case NModulePropID::kInterfaceType:
+ {
+ NWindows::NCOM::PropVarEm_Set_UInt32(value, NModuleInterfaceType::k_IUnknown_VirtDestructor_ThisModule);
+ break;
+ }
+ case NModulePropID::kVersion:
+ {
+ NWindows::NCOM::PropVarEm_Set_UInt32(value, (MY_VER_MAJOR << 16) | MY_VER_MINOR);
+ break;
+ }
+ }
+ return S_OK;
+}
diff --git a/CPP/7zip/Compress/CopyCoder.cpp b/CPP/7zip/Compress/CopyCoder.cpp
index 89b5237..b779e08 100644
--- a/CPP/7zip/Compress/CopyCoder.cpp
+++ b/CPP/7zip/Compress/CopyCoder.cpp
@@ -1,120 +1,153 @@
-// Compress/CopyCoder.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/Alloc.h"
-
-#include "CopyCoder.h"
-
-namespace NCompress {
-
-static const UInt32 kBufSize = 1 << 17;
-
-CCopyCoder::~CCopyCoder()
-{
- ::MidFree(_buf);
-}
-
-STDMETHODIMP CCopyCoder::SetFinishMode(UInt32 /* finishMode */)
-{
- return S_OK;
-}
-
-STDMETHODIMP CCopyCoder::Code(ISequentialInStream *inStream,
- ISequentialOutStream *outStream,
- const UInt64 * /* inSize */, const UInt64 *outSize,
- ICompressProgressInfo *progress)
-{
- if (!_buf)
- {
- _buf = (Byte *)::MidAlloc(kBufSize);
- if (!_buf)
- return E_OUTOFMEMORY;
- }
-
- TotalSize = 0;
-
- for (;;)
- {
- UInt32 size = kBufSize;
- if (outSize && size > *outSize - TotalSize)
- size = (UInt32)(*outSize - TotalSize);
- if (size == 0)
- return S_OK;
-
- HRESULT readRes = inStream->Read(_buf, size, &size);
-
- if (size == 0)
- return readRes;
-
- if (outStream)
- {
- UInt32 pos = 0;
- do
- {
- UInt32 curSize = size - pos;
- HRESULT res = outStream->Write(_buf + pos, curSize, &curSize);
- pos += curSize;
- TotalSize += curSize;
- RINOK(res);
- if (curSize == 0)
- return E_FAIL;
- }
- while (pos < size);
- }
- else
- TotalSize += size;
-
- RINOK(readRes);
-
- if (progress)
- {
- RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize));
- }
- }
-}
-
-STDMETHODIMP CCopyCoder::SetInStream(ISequentialInStream *inStream)
-{
- _inStream = inStream;
- TotalSize = 0;
- return S_OK;
-}
-
-STDMETHODIMP CCopyCoder::ReleaseInStream()
-{
- _inStream.Release();
- return S_OK;
-}
-
-STDMETHODIMP CCopyCoder::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- UInt32 realProcessedSize = 0;
- HRESULT res = _inStream->Read(data, size, &realProcessedSize);
- TotalSize += realProcessedSize;
- if (processedSize)
- *processedSize = realProcessedSize;
- return res;
-}
-
-STDMETHODIMP CCopyCoder::GetInStreamProcessedSize(UInt64 *value)
-{
- *value = TotalSize;
- return S_OK;
-}
-
-HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)
-{
- CMyComPtr<ICompressCoder> copyCoder = new CCopyCoder;
- return copyCoder->Code(inStream, outStream, NULL, NULL, progress);
-}
-
-HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress)
-{
- NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
- CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
- RINOK(copyCoder->Code(inStream, outStream, NULL, &size, progress));
- return copyCoderSpec->TotalSize == size ? S_OK : E_FAIL;
-}
-
-}
+// Compress/CopyCoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "CopyCoder.h"
+
+namespace NCompress {
+
+static const UInt32 kBufSize = 1 << 17;
+
+CCopyCoder::~CCopyCoder()
+{
+ ::MidFree(_buf);
+}
+
+Z7_COM7F_IMF(CCopyCoder::SetFinishMode(UInt32 /* finishMode */))
+{
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CCopyCoder::Code(ISequentialInStream *inStream,
+ ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize,
+ ICompressProgressInfo *progress))
+{
+ if (!_buf)
+ {
+ _buf = (Byte *)::MidAlloc(kBufSize);
+ if (!_buf)
+ return E_OUTOFMEMORY;
+ }
+
+ TotalSize = 0;
+
+ for (;;)
+ {
+ UInt32 size = kBufSize;
+ if (outSize)
+ {
+ const UInt64 rem = *outSize - TotalSize;
+ if (size > rem)
+ {
+ size = (UInt32)rem;
+ if (size == 0)
+ {
+ /* if we enable the following check,
+ we will make one call of Read(_buf, 0) for empty stream */
+ // if (TotalSize != 0)
+ return S_OK;
+ }
+ }
+ }
+
+ HRESULT readRes;
+ {
+ UInt32 pos = 0;
+ do
+ {
+ const UInt32 curSize = size - pos;
+ UInt32 processed = 0;
+ readRes = inStream->Read(_buf + pos, curSize, &processed);
+ if (processed > curSize)
+ return E_FAIL; // internal code failure
+ pos += processed;
+ if (readRes != S_OK || processed == 0)
+ break;
+ }
+ while (pos < kBufSize);
+ size = pos;
+ }
+
+ if (size == 0)
+ return readRes;
+
+ if (outStream)
+ {
+ UInt32 pos = 0;
+ do
+ {
+ const UInt32 curSize = size - pos;
+ UInt32 processed = 0;
+ const HRESULT res = outStream->Write(_buf + pos, curSize, &processed);
+ if (processed > curSize)
+ return E_FAIL; // internal code failure
+ pos += processed;
+ TotalSize += processed;
+ RINOK(res)
+ if (processed == 0)
+ return E_FAIL;
+ }
+ while (pos < size);
+ }
+ else
+ TotalSize += size;
+
+ RINOK(readRes)
+
+ if (size != kBufSize)
+ return S_OK;
+
+ if (progress && (TotalSize & (((UInt32)1 << 22) - 1)) == 0)
+ {
+ RINOK(progress->SetRatioInfo(&TotalSize, &TotalSize))
+ }
+ }
+}
+
+Z7_COM7F_IMF(CCopyCoder::SetInStream(ISequentialInStream *inStream))
+{
+ _inStream = inStream;
+ TotalSize = 0;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CCopyCoder::ReleaseInStream())
+{
+ _inStream.Release();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CCopyCoder::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ UInt32 realProcessedSize = 0;
+ HRESULT res = _inStream->Read(data, size, &realProcessedSize);
+ TotalSize += realProcessedSize;
+ if (processedSize)
+ *processedSize = realProcessedSize;
+ return res;
+}
+
+Z7_COM7F_IMF(CCopyCoder::GetInStreamProcessedSize(UInt64 *value))
+{
+ *value = TotalSize;
+ return S_OK;
+}
+
+HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)
+{
+ CMyComPtr<ICompressCoder> copyCoder = new CCopyCoder;
+ return copyCoder->Code(inStream, outStream, NULL, NULL, progress);
+}
+
+HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress)
+{
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder;
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+ RINOK(copyCoder->Code(inStream, outStream, NULL, &size, progress))
+ return copyCoderSpec->TotalSize == size ? S_OK : E_FAIL;
+}
+
+}
diff --git a/CPP/7zip/Compress/CopyCoder.h b/CPP/7zip/Compress/CopyCoder.h
index b2fa491..cb93e4e 100644
--- a/CPP/7zip/Compress/CopyCoder.h
+++ b/CPP/7zip/Compress/CopyCoder.h
@@ -1,49 +1,34 @@
-// Compress/CopyCoder.h
-
-#ifndef __COMPRESS_COPY_CODER_H
-#define __COMPRESS_COPY_CODER_H
-
-#include "../../Common/MyCom.h"
-
-#include "../ICoder.h"
-
-namespace NCompress {
-
-class CCopyCoder:
- public ICompressCoder,
- public ICompressSetInStream,
- public ISequentialInStream,
- public ICompressSetFinishMode,
- public ICompressGetInStreamProcessedSize,
- public CMyUnknownImp
-{
- Byte *_buf;
- CMyComPtr<ISequentialInStream> _inStream;
-public:
- UInt64 TotalSize;
-
- CCopyCoder(): _buf(0), TotalSize(0) {};
- ~CCopyCoder();
-
- MY_UNKNOWN_IMP5(
- ICompressCoder,
- ICompressSetInStream,
- ISequentialInStream,
- ICompressSetFinishMode,
- ICompressGetInStreamProcessedSize)
-
- STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
- STDMETHOD(SetInStream)(ISequentialInStream *inStream);
- STDMETHOD(ReleaseInStream)();
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(SetFinishMode)(UInt32 finishMode);
- STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
-};
-
-HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
-HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress);
-
-}
-
-#endif
+// Compress/CopyCoder.h
+
+#ifndef ZIP7_INC_COMPRESS_COPY_CODER_H
+#define ZIP7_INC_COMPRESS_COPY_CODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+
+Z7_CLASS_IMP_COM_5(
+ CCopyCoder
+ , ICompressCoder
+ , ICompressSetInStream
+ , ISequentialInStream
+ , ICompressSetFinishMode
+ , ICompressGetInStreamProcessedSize
+)
+ Byte *_buf;
+ CMyComPtr<ISequentialInStream> _inStream;
+public:
+ UInt64 TotalSize;
+
+ CCopyCoder(): _buf(NULL), TotalSize(0) {}
+ ~CCopyCoder();
+};
+
+HRESULT CopyStream(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
+HRESULT CopyStream_ExactSize(ISequentialInStream *inStream, ISequentialOutStream *outStream, UInt64 size, ICompressProgressInfo *progress);
+
+}
+
+#endif
diff --git a/CPP/7zip/Compress/CopyRegister.cpp b/CPP/7zip/Compress/CopyRegister.cpp
index 1c59fe0..7141ab5 100644
--- a/CPP/7zip/Compress/CopyRegister.cpp
+++ b/CPP/7zip/Compress/CopyRegister.cpp
@@ -1,15 +1,15 @@
-// CopyRegister.cpp
-
-#include "StdAfx.h"
-
-#include "../Common/RegisterCodec.h"
-
-#include "CopyCoder.h"
-
-namespace NCompress {
-
-REGISTER_CODEC_CREATE(CreateCodec, CCopyCoder())
-
-REGISTER_CODEC_2(Copy, CreateCodec, CreateCodec, 0, "Copy")
-
-}
+// CopyRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "CopyCoder.h"
+
+namespace NCompress {
+
+REGISTER_CODEC_CREATE(CreateCodec, CCopyCoder())
+
+REGISTER_CODEC_2(Copy, CreateCodec, CreateCodec, 0, "Copy")
+
+}
diff --git a/CPP/7zip/Compress/Deflate64Register.cpp b/CPP/7zip/Compress/Deflate64Register.cpp
new file mode 100644
index 0000000..7f6bae0
--- /dev/null
+++ b/CPP/7zip/Compress/Deflate64Register.cpp
@@ -0,0 +1,25 @@
+// Deflate64Register.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "DeflateDecoder.h"
+#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_DEFLATE_EXTRACT_ONLY)
+#include "DeflateEncoder.h"
+#endif
+
+namespace NCompress {
+namespace NDeflate {
+
+REGISTER_CODEC_CREATE(CreateDec, NDecoder::CCOMCoder64())
+
+#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_DEFLATE_EXTRACT_ONLY)
+REGISTER_CODEC_CREATE(CreateEnc, NEncoder::CCOMCoder64())
+#else
+#define CreateEnc NULL
+#endif
+
+REGISTER_CODEC_2(Deflate64, CreateDec, CreateEnc, 0x40109, "Deflate64")
+
+}}
diff --git a/CPP/7zip/Compress/DeflateConst.h b/CPP/7zip/Compress/DeflateConst.h
new file mode 100644
index 0000000..a73d8ff
--- /dev/null
+++ b/CPP/7zip/Compress/DeflateConst.h
@@ -0,0 +1,131 @@
+// DeflateConst.h
+
+#ifndef ZIP7_INC_DEFLATE_CONST_H
+#define ZIP7_INC_DEFLATE_CONST_H
+
+namespace NCompress {
+namespace NDeflate {
+
+const unsigned kNumHuffmanBits = 15;
+
+const UInt32 kHistorySize32 = (1 << 15);
+const UInt32 kHistorySize64 = (1 << 16);
+
+const unsigned kDistTableSize32 = 30;
+const unsigned kDistTableSize64 = 32;
+
+const unsigned kNumLenSymbols32 = 256;
+const unsigned kNumLenSymbols64 = 255; // don't change it. It must be <= 255.
+const unsigned kNumLenSymbolsMax = kNumLenSymbols32;
+
+const unsigned kNumLenSlots = 29;
+
+const unsigned kFixedDistTableSize = 32;
+const unsigned kFixedLenTableSize = 31;
+
+const unsigned kSymbolEndOfBlock = 0x100;
+const unsigned kSymbolMatch = kSymbolEndOfBlock + 1;
+
+const unsigned kMainTableSize = kSymbolMatch + kNumLenSlots;
+const unsigned kFixedMainTableSize = kSymbolMatch + kFixedLenTableSize;
+
+const unsigned kLevelTableSize = 19;
+
+const unsigned kTableDirectLevels = 16;
+const unsigned kTableLevelRepNumber = kTableDirectLevels;
+const unsigned kTableLevel0Number = kTableLevelRepNumber + 1;
+const unsigned kTableLevel0Number2 = kTableLevel0Number + 1;
+
+const unsigned kLevelMask = 0xF;
+
+const Byte kLenStart32[kFixedLenTableSize] =
+ {0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224, 255, 0, 0};
+const Byte kLenStart64[kFixedLenTableSize] =
+ {0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224, 0, 0, 0};
+
+const Byte kLenDirectBits32[kFixedLenTableSize] =
+ {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0};
+const Byte kLenDirectBits64[kFixedLenTableSize] =
+ {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 16, 0, 0};
+
+const UInt32 kDistStart[kDistTableSize64] =
+ {0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,
+ 1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768,49152};
+const Byte kDistDirectBits[kDistTableSize64] =
+ {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14};
+
+const Byte kLevelDirectBits[3] = {2, 3, 7};
+
+const Byte kCodeLengthAlphabetOrder[kLevelTableSize] = {16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15};
+
+const unsigned kMatchMinLen = 3;
+const unsigned kMatchMaxLen32 = kNumLenSymbols32 + kMatchMinLen - 1; // 256 + 2
+const unsigned kMatchMaxLen64 = kNumLenSymbols64 + kMatchMinLen - 1; // 255 + 2
+const unsigned kMatchMaxLen = kMatchMaxLen32;
+
+const unsigned kFinalBlockFieldSize = 1;
+
+namespace NFinalBlockField
+{
+ enum
+ {
+ kNotFinalBlock = 0,
+ kFinalBlock = 1
+ };
+}
+
+const unsigned kBlockTypeFieldSize = 2;
+
+namespace NBlockType
+{
+ enum
+ {
+ kStored = 0,
+ kFixedHuffman = 1,
+ kDynamicHuffman = 2
+ };
+}
+
+const unsigned kNumLenCodesFieldSize = 5;
+const unsigned kNumDistCodesFieldSize = 5;
+const unsigned kNumLevelCodesFieldSize = 4;
+
+const unsigned kNumLitLenCodesMin = 257;
+const unsigned kNumDistCodesMin = 1;
+const unsigned kNumLevelCodesMin = 4;
+
+const unsigned kLevelFieldSize = 3;
+
+const unsigned kStoredBlockLengthFieldSize = 16;
+
+struct CLevels
+{
+ Byte litLenLevels[kFixedMainTableSize];
+ Byte distLevels[kFixedDistTableSize];
+
+ void SubClear()
+ {
+ unsigned i;
+ for (i = kNumLitLenCodesMin; i < kFixedMainTableSize; i++)
+ litLenLevels[i] = 0;
+ for (i = 0; i < kFixedDistTableSize; i++)
+ distLevels[i] = 0;
+ }
+
+ void SetFixedLevels()
+ {
+ unsigned i = 0;
+
+ for (; i < 144; i++) litLenLevels[i] = 8;
+ for (; i < 256; i++) litLenLevels[i] = 9;
+ for (; i < 280; i++) litLenLevels[i] = 7;
+ for (; i < 288; i++) litLenLevels[i] = 8;
+
+ for (i = 0; i < kFixedDistTableSize; i++) // test it: InfoZip only uses kDistTableSize
+ distLevels[i] = 5;
+ }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/DeflateDecoder.cpp b/CPP/7zip/Compress/DeflateDecoder.cpp
new file mode 100644
index 0000000..017b694
--- /dev/null
+++ b/CPP/7zip/Compress/DeflateDecoder.cpp
@@ -0,0 +1,541 @@
+// DeflateDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "DeflateDecoder.h"
+
+namespace NCompress {
+namespace NDeflate {
+namespace NDecoder {
+
+CCoder::CCoder(bool deflate64Mode):
+ _deflateNSIS(false),
+ _deflate64Mode(deflate64Mode),
+ _keepHistory(false),
+ _needFinishInput(false),
+ _needInitInStream(true),
+ _outSizeDefined(false),
+ _outStartPos(0),
+ ZlibMode(false) {}
+
+UInt32 CCoder::ReadBits(unsigned numBits)
+{
+ return m_InBitStream.ReadBits(numBits);
+}
+
+Byte CCoder::ReadAlignedByte()
+{
+ return m_InBitStream.ReadAlignedByte();
+}
+
+bool CCoder::DecodeLevels(Byte *levels, unsigned numSymbols)
+{
+ unsigned i = 0;
+
+ do
+ {
+ UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream);
+ if (sym < kTableDirectLevels)
+ levels[i++] = (Byte)sym;
+ else
+ {
+ if (sym >= kLevelTableSize)
+ return false;
+
+ unsigned num;
+ unsigned numBits;
+ Byte symbol;
+
+ if (sym == kTableLevelRepNumber)
+ {
+ if (i == 0)
+ return false;
+ numBits = 2;
+ num = 0;
+ symbol = levels[(size_t)i - 1];
+ }
+ else
+ {
+ sym -= kTableLevel0Number;
+ sym <<= 2;
+ numBits = 3 + (unsigned)sym;
+ num = ((unsigned)sym << 1);
+ symbol = 0;
+ }
+
+ num += i + 3 + ReadBits(numBits);
+ if (num > numSymbols)
+ return false;
+ do
+ levels[i++] = symbol;
+ while (i < num);
+ }
+ }
+ while (i < numSymbols);
+
+ return true;
+}
+
+#define RIF(x) { if (!(x)) return false; }
+
+bool CCoder::ReadTables(void)
+{
+ m_FinalBlock = (ReadBits(kFinalBlockFieldSize) == NFinalBlockField::kFinalBlock);
+ if (m_InBitStream.ExtraBitsWereRead())
+ return false;
+ const UInt32 blockType = ReadBits(kBlockTypeFieldSize);
+ if (blockType > NBlockType::kDynamicHuffman)
+ return false;
+ if (m_InBitStream.ExtraBitsWereRead())
+ return false;
+
+ if (blockType == NBlockType::kStored)
+ {
+ m_StoredMode = true;
+ m_InBitStream.AlignToByte();
+ m_StoredBlockSize = ReadAligned_UInt16(); // ReadBits(kStoredBlockLengthFieldSize)
+ if (_deflateNSIS)
+ return true;
+ return (m_StoredBlockSize == (UInt16)~ReadAligned_UInt16());
+ }
+
+ m_StoredMode = false;
+
+ CLevels levels;
+ if (blockType == NBlockType::kFixedHuffman)
+ {
+ levels.SetFixedLevels();
+ _numDistLevels = _deflate64Mode ? kDistTableSize64 : kDistTableSize32;
+ }
+ else
+ {
+ const unsigned numLitLenLevels = ReadBits(kNumLenCodesFieldSize) + kNumLitLenCodesMin;
+ _numDistLevels = ReadBits(kNumDistCodesFieldSize) + kNumDistCodesMin;
+ const unsigned numLevelCodes = ReadBits(kNumLevelCodesFieldSize) + kNumLevelCodesMin;
+
+ if (!_deflate64Mode)
+ if (_numDistLevels > kDistTableSize32)
+ return false;
+
+ Byte levelLevels[kLevelTableSize];
+ for (unsigned i = 0; i < kLevelTableSize; i++)
+ {
+ const unsigned position = kCodeLengthAlphabetOrder[i];
+ if (i < numLevelCodes)
+ levelLevels[position] = (Byte)ReadBits(kLevelFieldSize);
+ else
+ levelLevels[position] = 0;
+ }
+
+ if (m_InBitStream.ExtraBitsWereRead())
+ return false;
+
+ RIF(m_LevelDecoder.Build(levelLevels))
+
+ Byte tmpLevels[kFixedMainTableSize + kFixedDistTableSize];
+ if (!DecodeLevels(tmpLevels, numLitLenLevels + _numDistLevels))
+ return false;
+
+ if (m_InBitStream.ExtraBitsWereRead())
+ return false;
+
+ levels.SubClear();
+ memcpy(levels.litLenLevels, tmpLevels, numLitLenLevels);
+ memcpy(levels.distLevels, tmpLevels + numLitLenLevels, _numDistLevels);
+ }
+ RIF(m_MainDecoder.Build(levels.litLenLevels))
+ return m_DistDecoder.Build(levels.distLevels);
+}
+
+
+HRESULT CCoder::InitInStream(bool needInit)
+{
+ if (needInit)
+ {
+ // for HDD-Windows:
+ // (1 << 15) - best for reading only prefetch
+ // (1 << 22) - best for real reading / writing
+ if (!m_InBitStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ m_InBitStream.Init();
+ _needInitInStream = false;
+ }
+ return S_OK;
+}
+
+
+HRESULT CCoder::CodeSpec(UInt32 curSize, bool finishInputStream, UInt32 inputProgressLimit)
+{
+ if (_remainLen == kLenIdFinished)
+ return S_OK;
+
+ if (_remainLen == kLenIdNeedInit)
+ {
+ if (!_keepHistory)
+ if (!m_OutWindowStream.Create(_deflate64Mode ? kHistorySize64: kHistorySize32))
+ return E_OUTOFMEMORY;
+ RINOK(InitInStream(_needInitInStream))
+ m_OutWindowStream.Init(_keepHistory);
+
+ m_FinalBlock = false;
+ _remainLen = 0;
+ _needReadTable = true;
+ }
+
+ while (_remainLen > 0 && curSize > 0)
+ {
+ _remainLen--;
+ const Byte b = m_OutWindowStream.GetByte(_rep0);
+ m_OutWindowStream.PutByte(b);
+ curSize--;
+ }
+
+ UInt64 inputStart = 0;
+ if (inputProgressLimit != 0)
+ inputStart = m_InBitStream.GetProcessedSize();
+
+ while (curSize > 0 || finishInputStream)
+ {
+ if (m_InBitStream.ExtraBitsWereRead())
+ return S_FALSE;
+
+ if (_needReadTable)
+ {
+ if (m_FinalBlock)
+ {
+ _remainLen = kLenIdFinished;
+ break;
+ }
+
+ if (inputProgressLimit != 0)
+ if (m_InBitStream.GetProcessedSize() - inputStart >= inputProgressLimit)
+ return S_OK;
+
+ if (!ReadTables())
+ return S_FALSE;
+ if (m_InBitStream.ExtraBitsWereRead())
+ return S_FALSE;
+ _needReadTable = false;
+ }
+
+ if (m_StoredMode)
+ {
+ if (finishInputStream && curSize == 0 && m_StoredBlockSize != 0)
+ return S_FALSE;
+ /* NSIS version contains some bits in bitl bits buffer.
+ So we must read some first bytes via ReadAlignedByte */
+ for (; m_StoredBlockSize > 0 && curSize > 0 && m_InBitStream.ThereAreDataInBitsBuffer(); m_StoredBlockSize--, curSize--)
+ m_OutWindowStream.PutByte(ReadAlignedByte());
+ for (; m_StoredBlockSize > 0 && curSize > 0; m_StoredBlockSize--, curSize--)
+ m_OutWindowStream.PutByte(m_InBitStream.ReadDirectByte());
+ _needReadTable = (m_StoredBlockSize == 0);
+ continue;
+ }
+
+ while (curSize > 0)
+ {
+ if (m_InBitStream.ExtraBitsWereRead_Fast())
+ return S_FALSE;
+
+ UInt32 sym = m_MainDecoder.Decode(&m_InBitStream);
+
+ if (sym < 0x100)
+ {
+ m_OutWindowStream.PutByte((Byte)sym);
+ curSize--;
+ continue;
+ }
+ else if (sym == kSymbolEndOfBlock)
+ {
+ _needReadTable = true;
+ break;
+ }
+ else if (sym < kMainTableSize)
+ {
+ sym -= kSymbolMatch;
+ UInt32 len;
+ {
+ unsigned numBits;
+ if (_deflate64Mode)
+ {
+ len = kLenStart64[sym];
+ numBits = kLenDirectBits64[sym];
+ }
+ else
+ {
+ len = kLenStart32[sym];
+ numBits = kLenDirectBits32[sym];
+ }
+ len += kMatchMinLen + m_InBitStream.ReadBits(numBits);
+ }
+ UInt32 locLen = len;
+ if (locLen > curSize)
+ locLen = (UInt32)curSize;
+ sym = m_DistDecoder.Decode(&m_InBitStream);
+ if (sym >= _numDistLevels)
+ return S_FALSE;
+ sym = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]);
+ /*
+ if (sym >= 4)
+ {
+ // sym &= 31;
+ const unsigned numDirectBits = (unsigned)(((sym >> 1) - 1));
+ sym = (2 | (sym & 1)) << numDirectBits;
+ sym += m_InBitStream.ReadBits(numDirectBits);
+ }
+ */
+ if (!m_OutWindowStream.CopyBlock(sym, locLen))
+ return S_FALSE;
+ curSize -= locLen;
+ len -= locLen;
+ if (len != 0)
+ {
+ _remainLen = (Int32)len;
+ _rep0 = sym;
+ break;
+ }
+ }
+ else
+ return S_FALSE;
+ }
+
+ if (finishInputStream && curSize == 0)
+ {
+ if (m_MainDecoder.Decode(&m_InBitStream) != kSymbolEndOfBlock)
+ return S_FALSE;
+ _needReadTable = true;
+ }
+ }
+
+ if (m_InBitStream.ExtraBitsWereRead())
+ return S_FALSE;
+
+ return S_OK;
+}
+
+
+#ifdef Z7_NO_EXCEPTIONS
+
+#define DEFLATE_TRY_BEGIN
+#define DEFLATE_TRY_END(res)
+
+#else
+
+#define DEFLATE_TRY_BEGIN try {
+#define DEFLATE_TRY_END(res) } \
+ catch(const CSystemException &e) { res = e.ErrorCode; } \
+ catch(...) { res = S_FALSE; }
+
+ // catch(const CInBufferException &e) { res = e.ErrorCode; }
+ // catch(const CLzOutWindowException &e) { res = e.ErrorCode; }
+
+#endif
+
+
+HRESULT CCoder::CodeReal(ISequentialOutStream *outStream, ICompressProgressInfo *progress)
+{
+ HRESULT res;
+
+ DEFLATE_TRY_BEGIN
+
+ m_OutWindowStream.SetStream(outStream);
+ CCoderReleaser flusher(this);
+
+ const UInt64 inStart = _needInitInStream ? 0 : m_InBitStream.GetProcessedSize();
+
+ for (;;)
+ {
+ const UInt32 kInputProgressLimit = 1 << 21;
+ UInt32 curSize = 1 << 20;
+ bool finishInputStream = false;
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - GetOutProcessedCur();
+ if (curSize >= rem)
+ {
+ curSize = (UInt32)rem;
+ if (ZlibMode || _needFinishInput)
+ finishInputStream = true;
+ }
+ }
+ if (!finishInputStream && curSize == 0)
+ break;
+
+ RINOK(CodeSpec(curSize, finishInputStream, progress ? kInputProgressLimit : 0))
+
+ if (_remainLen == kLenIdFinished)
+ break;
+
+ if (progress)
+ {
+ const UInt64 inSize = m_InBitStream.GetProcessedSize() - inStart;
+ const UInt64 nowPos64 = GetOutProcessedCur();
+ RINOK(progress->SetRatioInfo(&inSize, &nowPos64))
+ }
+ }
+
+ if (_remainLen == kLenIdFinished && ZlibMode)
+ {
+ m_InBitStream.AlignToByte();
+ for (unsigned i = 0; i < 4; i++)
+ ZlibFooter[i] = ReadAlignedByte();
+ }
+
+ flusher.NeedFlush = false;
+ res = Flush();
+ if (res == S_OK && _remainLen != kLenIdNeedInit && InputEofError())
+ return S_FALSE;
+
+ DEFLATE_TRY_END(res)
+
+ return res;
+}
+
+
+Z7_COM7F_IMF(CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ SetInStream(inStream);
+ SetOutStreamSize(outSize);
+ const HRESULT res = CodeReal(outStream, progress);
+ ReleaseInStream();
+ /*
+ if (res == S_OK)
+ if (_needFinishInput && inSize && *inSize != m_InBitStream.GetProcessedSize())
+ res = S_FALSE;
+ */
+ return res;
+}
+
+
+Z7_COM7F_IMF(CCoder::SetFinishMode(UInt32 finishMode))
+{
+ Set_NeedFinishInput(finishMode != 0);
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CCoder::GetInStreamProcessedSize(UInt64 *value))
+{
+ *value = m_InBitStream.GetStreamSize();
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CCoder::ReadUnusedFromInBuf(void *data, UInt32 size, UInt32 *processedSize))
+{
+ AlignToByte();
+ UInt32 i = 0;
+ {
+ for (i = 0; i < size; i++)
+ {
+ if (!m_InBitStream.ReadAlignedByte_FromBuf(((Byte *)data)[i]))
+ break;
+ }
+ }
+ if (processedSize)
+ *processedSize = i;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CCoder::SetInStream(ISequentialInStream *inStream))
+{
+ m_InStreamRef = inStream;
+ m_InBitStream.SetStream(inStream);
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CCoder::ReleaseInStream())
+{
+ m_InStreamRef.Release();
+ return S_OK;
+}
+
+
+void CCoder::SetOutStreamSizeResume(const UInt64 *outSize)
+{
+ _outSizeDefined = (outSize != NULL);
+ _outSize = 0;
+ if (_outSizeDefined)
+ _outSize = *outSize;
+
+ m_OutWindowStream.Init(_keepHistory);
+ _outStartPos = m_OutWindowStream.GetProcessedSize();
+
+ _remainLen = kLenIdNeedInit;
+}
+
+
+Z7_COM7F_IMF(CCoder::SetOutStreamSize(const UInt64 *outSize))
+{
+ /*
+ 18.06:
+ We want to support GetInputProcessedSize() before CCoder::Read()
+ So we call m_InBitStream.Init() even before buffer allocations
+ m_InBitStream.Init() just sets variables to default values
+ But later we will call m_InBitStream.Init() again with real buffer pointers
+ */
+ m_InBitStream.Init();
+ _needInitInStream = true;
+ SetOutStreamSizeResume(outSize);
+ return S_OK;
+}
+
+
+#ifndef Z7_NO_READ_FROM_CODER
+
+Z7_COM7F_IMF(CCoder::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ HRESULT res;
+
+ if (processedSize)
+ *processedSize = 0;
+ const UInt64 outPos = GetOutProcessedCur();
+
+ bool finishInputStream = false;
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - outPos;
+ if (size >= rem)
+ {
+ size = (UInt32)rem;
+ if (ZlibMode || _needFinishInput)
+ finishInputStream = true;
+ }
+ }
+ if (!finishInputStream && size == 0)
+ return S_OK;
+
+ DEFLATE_TRY_BEGIN
+
+ m_OutWindowStream.SetMemStream((Byte *)data);
+
+ res = CodeSpec(size, finishInputStream);
+
+ DEFLATE_TRY_END(res)
+
+ {
+ const HRESULT res2 = Flush();
+ if (res2 != S_OK)
+ res = res2;
+ }
+
+ if (processedSize)
+ *processedSize = (UInt32)(GetOutProcessedCur() - outPos);
+
+ m_OutWindowStream.SetMemStream(NULL);
+ return res;
+}
+
+#endif
+
+
+HRESULT CCoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ SetOutStreamSizeResume(outSize);
+ return CodeReal(outStream, progress);
+}
+
+}}}
diff --git a/CPP/7zip/Compress/DeflateDecoder.h b/CPP/7zip/Compress/DeflateDecoder.h
new file mode 100644
index 0000000..d31f299
--- /dev/null
+++ b/CPP/7zip/Compress/DeflateDecoder.h
@@ -0,0 +1,153 @@
+// DeflateDecoder.h
+
+#ifndef ZIP7_INC_DEFLATE_DECODER_H
+#define ZIP7_INC_DEFLATE_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitlDecoder.h"
+#include "DeflateConst.h"
+#include "HuffmanDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NDeflate {
+namespace NDecoder {
+
+const int kLenIdFinished = -1;
+const int kLenIdNeedInit = -2;
+
+class CCoder:
+ public ICompressCoder,
+ public ICompressSetFinishMode,
+ public ICompressGetInStreamProcessedSize,
+ public ICompressReadUnusedFromInBuf,
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ #ifndef Z7_NO_READ_FROM_CODER
+ public ISequentialInStream,
+ #endif
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(ICompressCoder)
+ Z7_COM_QI_ENTRY(ICompressSetFinishMode)
+ Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize)
+ Z7_COM_QI_ENTRY(ICompressReadUnusedFromInBuf)
+ Z7_COM_QI_ENTRY(ICompressSetInStream)
+ Z7_COM_QI_ENTRY(ICompressSetOutStreamSize)
+ #ifndef Z7_NO_READ_FROM_CODER
+ Z7_COM_QI_ENTRY(ISequentialInStream)
+ #endif
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(ICompressCoder)
+ Z7_IFACE_COM7_IMP(ICompressSetFinishMode)
+ Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize)
+ Z7_IFACE_COM7_IMP(ICompressReadUnusedFromInBuf)
+public:
+ Z7_IFACE_COM7_IMP(ICompressSetInStream)
+private:
+ Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize)
+ #ifndef Z7_NO_READ_FROM_CODER
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+ #endif
+
+ CLzOutWindow m_OutWindowStream;
+ CMyComPtr<ISequentialInStream> m_InStreamRef;
+ NBitl::CDecoder<CInBuffer> m_InBitStream;
+ NCompress::NHuffman::CDecoder<kNumHuffmanBits, kFixedMainTableSize> m_MainDecoder;
+ NCompress::NHuffman::CDecoder<kNumHuffmanBits, kFixedDistTableSize> m_DistDecoder;
+ NCompress::NHuffman::CDecoder7b<kLevelTableSize> m_LevelDecoder;
+
+ UInt32 m_StoredBlockSize;
+
+ UInt32 _numDistLevels;
+ bool m_FinalBlock;
+ bool m_StoredMode;
+
+ bool _deflateNSIS;
+ bool _deflate64Mode;
+ bool _keepHistory;
+ bool _needFinishInput;
+
+ bool _needInitInStream;
+ bool _needReadTable;
+ Int32 _remainLen;
+ UInt32 _rep0;
+
+ bool _outSizeDefined;
+ UInt64 _outSize;
+ UInt64 _outStartPos;
+
+ void SetOutStreamSizeResume(const UInt64 *outSize);
+ UInt64 GetOutProcessedCur() const { return m_OutWindowStream.GetProcessedSize() - _outStartPos; }
+
+ UInt32 ReadBits(unsigned numBits);
+
+ bool DecodeLevels(Byte *levels, unsigned numSymbols);
+ bool ReadTables();
+
+ HRESULT Flush() { return m_OutWindowStream.Flush(); }
+ class CCoderReleaser
+ {
+ CCoder *_coder;
+ public:
+ bool NeedFlush;
+ CCoderReleaser(CCoder *coder): _coder(coder), NeedFlush(true) {}
+ ~CCoderReleaser()
+ {
+ if (NeedFlush)
+ _coder->Flush();
+ }
+ };
+ friend class CCoderReleaser;
+
+ HRESULT CodeSpec(UInt32 curSize, bool finishInputStream, UInt32 inputProgressLimit = 0);
+public:
+ bool ZlibMode;
+ Byte ZlibFooter[4];
+
+ CCoder(bool deflate64Mode);
+ virtual ~CCoder() {}
+
+ void SetNsisMode(bool nsisMode) { _deflateNSIS = nsisMode; }
+
+ void Set_KeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
+ void Set_NeedFinishInput(bool needFinishInput) { _needFinishInput = needFinishInput; }
+
+ bool IsFinished() const { return _remainLen == kLenIdFinished; }
+ bool IsFinalBlock() const { return m_FinalBlock; }
+
+ HRESULT CodeReal(ISequentialOutStream *outStream, ICompressProgressInfo *progress);
+
+public:
+ HRESULT CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress);
+ HRESULT InitInStream(bool needInit);
+
+ void AlignToByte() { m_InBitStream.AlignToByte(); }
+ Byte ReadAlignedByte();
+ UInt32 ReadAligned_UInt16() // aligned for Byte range
+ {
+ UInt32 v = m_InBitStream.ReadAlignedByte();
+ return v | ((UInt32)m_InBitStream.ReadAlignedByte() << 8);
+ }
+ bool InputEofError() const { return m_InBitStream.ExtraBitsWereRead(); }
+
+ // size of used real data from input stream
+ UInt64 GetStreamSize() const { return m_InBitStream.GetStreamSize(); }
+
+ // size of virtual input stream processed
+ UInt64 GetInputProcessedSize() const { return m_InBitStream.GetProcessedSize(); }
+};
+
+class CCOMCoder : public CCoder { public: CCOMCoder(): CCoder(false) {} };
+class CCOMCoder64 : public CCoder { public: CCOMCoder64(): CCoder(true) {} };
+
+}}}
+
+#endif
diff --git a/CPP/7zip/Compress/DeflateEncoder.cpp b/CPP/7zip/Compress/DeflateEncoder.cpp
new file mode 100644
index 0000000..e277ad6
--- /dev/null
+++ b/CPP/7zip/Compress/DeflateEncoder.cpp
@@ -0,0 +1,1019 @@
+// DeflateEncoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+#include "../../../C/HuffEnc.h"
+
+#include "../../Common/ComTry.h"
+
+#include "../Common/CWrappers.h"
+
+#include "DeflateEncoder.h"
+
+#undef NO_INLINE
+
+#ifdef _MSC_VER
+#define NO_INLINE Z7_NO_INLINE
+#else
+#define NO_INLINE
+#endif
+
+namespace NCompress {
+namespace NDeflate {
+namespace NEncoder {
+
+static const unsigned kNumDivPassesMax = 10; // [0, 16); ratio/speed/ram tradeoff; use big value for better compression ratio.
+static const UInt32 kNumTables = (1 << kNumDivPassesMax);
+
+static const UInt32 kFixedHuffmanCodeBlockSizeMax = (1 << 8); // [0, (1 << 32)); ratio/speed tradeoff; use big value for better compression ratio.
+static const UInt32 kDivideCodeBlockSizeMin = (1 << 7); // [1, (1 << 32)); ratio/speed tradeoff; use small value for better compression ratio.
+static const UInt32 kDivideBlockSizeMin = (1 << 6); // [1, (1 << 32)); ratio/speed tradeoff; use small value for better compression ratio.
+
+static const UInt32 kMaxUncompressedBlockSize = ((1 << 16) - 1) * 1; // [1, (1 << 32))
+static const UInt32 kMatchArraySize = kMaxUncompressedBlockSize * 10; // [kMatchMaxLen * 2, (1 << 32))
+static const UInt32 kMatchArrayLimit = kMatchArraySize - kMatchMaxLen * 4 * sizeof(UInt16);
+static const UInt32 kBlockUncompressedSizeThreshold = kMaxUncompressedBlockSize -
+ kMatchMaxLen - kNumOpts;
+
+// static const unsigned kMaxCodeBitLength = 11;
+static const unsigned kMaxLevelBitLength = 7;
+
+static const Byte kNoLiteralStatPrice = 11;
+static const Byte kNoLenStatPrice = 11;
+static const Byte kNoPosStatPrice = 6;
+
+static Byte g_LenSlots[kNumLenSymbolsMax];
+
+#define kNumLogBits 9 // do not change it
+static Byte g_FastPos[1 << kNumLogBits];
+
+class CFastPosInit
+{
+public:
+ CFastPosInit()
+ {
+ unsigned i;
+ for (i = 0; i < kNumLenSlots; i++)
+ {
+ unsigned c = kLenStart32[i];
+ unsigned j = 1 << kLenDirectBits32[i];
+ for (unsigned k = 0; k < j; k++, c++)
+ g_LenSlots[c] = (Byte)i;
+ }
+
+ const unsigned kFastSlots = kNumLogBits * 2;
+ unsigned c = 0;
+ for (Byte slotFast = 0; slotFast < kFastSlots; slotFast++)
+ {
+ UInt32 k = (1 << kDistDirectBits[slotFast]);
+ for (UInt32 j = 0; j < k; j++, c++)
+ g_FastPos[c] = slotFast;
+ }
+ }
+};
+
+static CFastPosInit g_FastPosInit;
+
+inline UInt32 GetPosSlot(UInt32 pos)
+{
+ /*
+ if (pos < 0x200)
+ return g_FastPos[pos];
+ return g_FastPos[pos >> 8] + 16;
+ */
+ // const unsigned zz = (pos < ((UInt32)1 << (kNumLogBits))) ? 0 : 8;
+ /*
+ const unsigned zz = (kNumLogBits - 1) &
+ ((UInt32)0 - (((((UInt32)1 << kNumLogBits) - 1) - pos) >> 31));
+ */
+ const unsigned zz = (kNumLogBits - 1) &
+ (((((UInt32)1 << kNumLogBits) - 1) - pos) >> (31 - 3));
+ return g_FastPos[pos >> zz] + (zz * 2);
+}
+
+
+void CEncProps::Normalize()
+{
+ int level = Level;
+ if (level < 0) level = 5;
+ Level = level;
+ if (algo < 0) algo = (level < 5 ? 0 : 1);
+ if (fb < 0) fb = (level < 7 ? 32 : (level < 9 ? 64 : 128));
+ if (btMode < 0) btMode = (algo == 0 ? 0 : 1);
+ if (mc == 0) mc = (16 + ((unsigned)fb >> 1));
+ if (numPasses == (UInt32)(Int32)-1) numPasses = (level < 7 ? 1 : (level < 9 ? 3 : 10));
+}
+
+void CCoder::SetProps(const CEncProps *props2)
+{
+ CEncProps props = *props2;
+ props.Normalize();
+
+ m_MatchFinderCycles = props.mc;
+ {
+ unsigned fb = (unsigned)props.fb;
+ if (fb < kMatchMinLen)
+ fb = kMatchMinLen;
+ if (fb > m_MatchMaxLen)
+ fb = m_MatchMaxLen;
+ m_NumFastBytes = fb;
+ }
+ _fastMode = (props.algo == 0);
+ _btMode = (props.btMode != 0);
+
+ m_NumDivPasses = props.numPasses;
+ if (m_NumDivPasses == 0)
+ m_NumDivPasses = 1;
+ if (m_NumDivPasses == 1)
+ m_NumPasses = 1;
+ else if (m_NumDivPasses <= kNumDivPassesMax)
+ m_NumPasses = 2;
+ else
+ {
+ m_NumPasses = 2 + (m_NumDivPasses - kNumDivPassesMax);
+ m_NumDivPasses = kNumDivPassesMax;
+ }
+}
+
+CCoder::CCoder(bool deflate64Mode):
+ m_Values(NULL),
+ m_OnePosMatchesMemory(NULL),
+ m_DistanceMemory(NULL),
+ m_Created(false),
+ m_Deflate64Mode(deflate64Mode),
+ m_Tables(NULL)
+{
+ m_MatchMaxLen = deflate64Mode ? kMatchMaxLen64 : kMatchMaxLen32;
+ m_NumLenCombinations = deflate64Mode ? kNumLenSymbols64 : kNumLenSymbols32;
+ m_LenStart = deflate64Mode ? kLenStart64 : kLenStart32;
+ m_LenDirectBits = deflate64Mode ? kLenDirectBits64 : kLenDirectBits32;
+ {
+ CEncProps props;
+ SetProps(&props);
+ }
+ MatchFinder_Construct(&_lzInWindow);
+}
+
+HRESULT CCoder::Create()
+{
+ // COM_TRY_BEGIN
+ if (!m_Values)
+ {
+ m_Values = (CCodeValue *)MyAlloc((kMaxUncompressedBlockSize) * sizeof(CCodeValue));
+ if (!m_Values)
+ return E_OUTOFMEMORY;
+ }
+ if (!m_Tables)
+ {
+ m_Tables = (CTables *)MyAlloc((kNumTables) * sizeof(CTables));
+ if (!m_Tables)
+ return E_OUTOFMEMORY;
+ }
+
+ if (m_IsMultiPass)
+ {
+ if (!m_OnePosMatchesMemory)
+ {
+ m_OnePosMatchesMemory = (UInt16 *)::MidAlloc(kMatchArraySize * sizeof(UInt16));
+ if (!m_OnePosMatchesMemory)
+ return E_OUTOFMEMORY;
+ }
+ }
+ else
+ {
+ if (!m_DistanceMemory)
+ {
+ m_DistanceMemory = (UInt16 *)MyAlloc((kMatchMaxLen + 2) * 2 * sizeof(UInt16));
+ if (!m_DistanceMemory)
+ return E_OUTOFMEMORY;
+ m_MatchDistances = m_DistanceMemory;
+ }
+ }
+
+ if (!m_Created)
+ {
+ _lzInWindow.btMode = (Byte)(_btMode ? 1 : 0);
+ _lzInWindow.numHashBytes = 3;
+ _lzInWindow.numHashBytes_Min = 3;
+ if (!MatchFinder_Create(&_lzInWindow,
+ m_Deflate64Mode ? kHistorySize64 : kHistorySize32,
+ kNumOpts + kMaxUncompressedBlockSize,
+ m_NumFastBytes, m_MatchMaxLen - m_NumFastBytes, &g_AlignedAlloc))
+ return E_OUTOFMEMORY;
+ if (!m_OutStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ }
+ if (m_MatchFinderCycles != 0)
+ _lzInWindow.cutValue = m_MatchFinderCycles;
+ m_Created = true;
+ return S_OK;
+ // COM_TRY_END
+}
+
+HRESULT CCoder::BaseSetEncoderProperties2(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)
+{
+ CEncProps props;
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = coderProps[i];
+ PROPID propID = propIDs[i];
+ if (propID >= NCoderPropID::kReduceSize)
+ continue;
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ UInt32 v = (UInt32)prop.ulVal;
+ switch (propID)
+ {
+ case NCoderPropID::kNumPasses: props.numPasses = v; break;
+ case NCoderPropID::kNumFastBytes: props.fb = (int)v; break;
+ case NCoderPropID::kMatchFinderCycles: props.mc = v; break;
+ case NCoderPropID::kAlgorithm: props.algo = (int)v; break;
+ case NCoderPropID::kLevel: props.Level = (int)v; break;
+ case NCoderPropID::kNumThreads: break;
+ default: return E_INVALIDARG;
+ }
+ }
+ SetProps(&props);
+ return S_OK;
+}
+
+void CCoder::Free()
+{
+ ::MidFree(m_OnePosMatchesMemory); m_OnePosMatchesMemory = NULL;
+ ::MyFree(m_DistanceMemory); m_DistanceMemory = NULL;
+ ::MyFree(m_Values); m_Values = NULL;
+ ::MyFree(m_Tables); m_Tables = NULL;
+}
+
+CCoder::~CCoder()
+{
+ Free();
+ MatchFinder_Free(&_lzInWindow, &g_AlignedAlloc);
+}
+
+NO_INLINE void CCoder::GetMatches()
+{
+ if (m_IsMultiPass)
+ {
+ m_MatchDistances = m_OnePosMatchesMemory + m_Pos;
+ if (m_SecondPass)
+ {
+ m_Pos += *m_MatchDistances + 1;
+ return;
+ }
+ }
+
+ UInt32 distanceTmp[kMatchMaxLen * 2 + 3];
+
+ const UInt32 numPairs = (UInt32)((_btMode ?
+ Bt3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp):
+ Hc3Zip_MatchFinder_GetMatches(&_lzInWindow, distanceTmp)) - distanceTmp);
+
+ *m_MatchDistances = (UInt16)numPairs;
+
+ if (numPairs != 0)
+ {
+ UInt32 i;
+ for (i = 0; i < numPairs; i += 2)
+ {
+ m_MatchDistances[(size_t)i + 1] = (UInt16)distanceTmp[i];
+ m_MatchDistances[(size_t)i + 2] = (UInt16)distanceTmp[(size_t)i + 1];
+ }
+ UInt32 len = distanceTmp[(size_t)numPairs - 2];
+ if (len == m_NumFastBytes && m_NumFastBytes != m_MatchMaxLen)
+ {
+ UInt32 numAvail = Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) + 1;
+ const Byte *pby = Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) - 1;
+ const Byte *pby2 = pby - (distanceTmp[(size_t)numPairs - 1] + 1);
+ if (numAvail > m_MatchMaxLen)
+ numAvail = m_MatchMaxLen;
+ for (; len < numAvail && pby[len] == pby2[len]; len++);
+ m_MatchDistances[(size_t)i - 1] = (UInt16)len;
+ }
+ }
+ if (m_IsMultiPass)
+ m_Pos += numPairs + 1;
+ if (!m_SecondPass)
+ m_AdditionalOffset++;
+}
+
+void CCoder::MovePos(UInt32 num)
+{
+ if (!m_SecondPass && num > 0)
+ {
+ if (_btMode)
+ Bt3Zip_MatchFinder_Skip(&_lzInWindow, num);
+ else
+ Hc3Zip_MatchFinder_Skip(&_lzInWindow, num);
+ m_AdditionalOffset += num;
+ }
+}
+
+static const UInt32 kIfinityPrice = 0xFFFFFFF;
+
+NO_INLINE UInt32 CCoder::Backward(UInt32 &backRes, UInt32 cur)
+{
+ m_OptimumEndIndex = cur;
+ UInt32 posMem = m_Optimum[cur].PosPrev;
+ UInt16 backMem = m_Optimum[cur].BackPrev;
+ do
+ {
+ UInt32 posPrev = posMem;
+ UInt16 backCur = backMem;
+ backMem = m_Optimum[posPrev].BackPrev;
+ posMem = m_Optimum[posPrev].PosPrev;
+ m_Optimum[posPrev].BackPrev = backCur;
+ m_Optimum[posPrev].PosPrev = (UInt16)cur;
+ cur = posPrev;
+ }
+ while (cur > 0);
+ backRes = m_Optimum[0].BackPrev;
+ m_OptimumCurrentIndex = m_Optimum[0].PosPrev;
+ return m_OptimumCurrentIndex;
+}
+
+NO_INLINE UInt32 CCoder::GetOptimal(UInt32 &backRes)
+{
+ if (m_OptimumEndIndex != m_OptimumCurrentIndex)
+ {
+ UInt32 len = m_Optimum[m_OptimumCurrentIndex].PosPrev - m_OptimumCurrentIndex;
+ backRes = m_Optimum[m_OptimumCurrentIndex].BackPrev;
+ m_OptimumCurrentIndex = m_Optimum[m_OptimumCurrentIndex].PosPrev;
+ return len;
+ }
+ m_OptimumCurrentIndex = m_OptimumEndIndex = 0;
+
+ GetMatches();
+
+ UInt32 lenEnd;
+ {
+ const UInt32 numDistancePairs = m_MatchDistances[0];
+ if (numDistancePairs == 0)
+ return 1;
+ const UInt16 *matchDistances = m_MatchDistances + 1;
+ lenEnd = matchDistances[(size_t)numDistancePairs - 2];
+
+ if (lenEnd > m_NumFastBytes)
+ {
+ backRes = matchDistances[(size_t)numDistancePairs - 1];
+ MovePos(lenEnd - 1);
+ return lenEnd;
+ }
+
+ m_Optimum[1].Price = m_LiteralPrices[*(Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) - m_AdditionalOffset)];
+ m_Optimum[1].PosPrev = 0;
+
+ m_Optimum[2].Price = kIfinityPrice;
+ m_Optimum[2].PosPrev = 1;
+
+ UInt32 offs = 0;
+
+ for (UInt32 i = kMatchMinLen; i <= lenEnd; i++)
+ {
+ UInt32 distance = matchDistances[(size_t)offs + 1];
+ m_Optimum[i].PosPrev = 0;
+ m_Optimum[i].BackPrev = (UInt16)distance;
+ m_Optimum[i].Price = m_LenPrices[(size_t)i - kMatchMinLen] + m_PosPrices[GetPosSlot(distance)];
+ if (i == matchDistances[offs])
+ offs += 2;
+ }
+ }
+
+ UInt32 cur = 0;
+
+ for (;;)
+ {
+ ++cur;
+ if (cur == lenEnd || cur == kNumOptsBase || m_Pos >= kMatchArrayLimit)
+ return Backward(backRes, cur);
+ GetMatches();
+ const UInt16 *matchDistances = m_MatchDistances + 1;
+ const UInt32 numDistancePairs = m_MatchDistances[0];
+ UInt32 newLen = 0;
+ if (numDistancePairs != 0)
+ {
+ newLen = matchDistances[(size_t)numDistancePairs - 2];
+ if (newLen > m_NumFastBytes)
+ {
+ UInt32 len = Backward(backRes, cur);
+ m_Optimum[cur].BackPrev = matchDistances[(size_t)numDistancePairs - 1];
+ m_OptimumEndIndex = cur + newLen;
+ m_Optimum[cur].PosPrev = (UInt16)m_OptimumEndIndex;
+ MovePos(newLen - 1);
+ return len;
+ }
+ }
+ UInt32 curPrice = m_Optimum[cur].Price;
+ {
+ const UInt32 curAnd1Price = curPrice + m_LiteralPrices[*(Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) + cur - m_AdditionalOffset)];
+ COptimal &optimum = m_Optimum[(size_t)cur + 1];
+ if (curAnd1Price < optimum.Price)
+ {
+ optimum.Price = curAnd1Price;
+ optimum.PosPrev = (UInt16)cur;
+ }
+ }
+ if (numDistancePairs == 0)
+ continue;
+ while (lenEnd < cur + newLen)
+ m_Optimum[++lenEnd].Price = kIfinityPrice;
+ UInt32 offs = 0;
+ UInt32 distance = matchDistances[(size_t)offs + 1];
+ curPrice += m_PosPrices[GetPosSlot(distance)];
+ for (UInt32 lenTest = kMatchMinLen; ; lenTest++)
+ {
+ UInt32 curAndLenPrice = curPrice + m_LenPrices[(size_t)lenTest - kMatchMinLen];
+ COptimal &optimum = m_Optimum[cur + lenTest];
+ if (curAndLenPrice < optimum.Price)
+ {
+ optimum.Price = curAndLenPrice;
+ optimum.PosPrev = (UInt16)cur;
+ optimum.BackPrev = (UInt16)distance;
+ }
+ if (lenTest == matchDistances[offs])
+ {
+ offs += 2;
+ if (offs == numDistancePairs)
+ break;
+ curPrice -= m_PosPrices[GetPosSlot(distance)];
+ distance = matchDistances[(size_t)offs + 1];
+ curPrice += m_PosPrices[GetPosSlot(distance)];
+ }
+ }
+ }
+}
+
+UInt32 CCoder::GetOptimalFast(UInt32 &backRes)
+{
+ GetMatches();
+ UInt32 numDistancePairs = m_MatchDistances[0];
+ if (numDistancePairs == 0)
+ return 1;
+ UInt32 lenMain = m_MatchDistances[(size_t)numDistancePairs - 1];
+ backRes = m_MatchDistances[numDistancePairs];
+ MovePos(lenMain - 1);
+ return lenMain;
+}
+
+void CTables::InitStructures()
+{
+ UInt32 i;
+ for (i = 0; i < 256; i++)
+ litLenLevels[i] = 8;
+ litLenLevels[i++] = 13;
+ for (;i < kFixedMainTableSize; i++)
+ litLenLevels[i] = 5;
+ for (i = 0; i < kFixedDistTableSize; i++)
+ distLevels[i] = 5;
+}
+
+NO_INLINE void CCoder::LevelTableDummy(const Byte *levels, unsigned numLevels, UInt32 *freqs)
+{
+ unsigned prevLen = 0xFF;
+ unsigned nextLen = levels[0];
+ unsigned count = 0;
+ unsigned maxCount = 7;
+ unsigned minCount = 4;
+
+ if (nextLen == 0)
+ {
+ maxCount = 138;
+ minCount = 3;
+ }
+
+ for (unsigned n = 0; n < numLevels; n++)
+ {
+ unsigned curLen = nextLen;
+ nextLen = (n < numLevels - 1) ? levels[(size_t)n + 1] : 0xFF;
+ count++;
+ if (count < maxCount && curLen == nextLen)
+ continue;
+
+ if (count < minCount)
+ freqs[curLen] += (UInt32)count;
+ else if (curLen != 0)
+ {
+ if (curLen != prevLen)
+ {
+ freqs[curLen]++;
+ count--;
+ }
+ freqs[kTableLevelRepNumber]++;
+ }
+ else if (count <= 10)
+ freqs[kTableLevel0Number]++;
+ else
+ freqs[kTableLevel0Number2]++;
+
+ count = 0;
+ prevLen = curLen;
+
+ if (nextLen == 0)
+ {
+ maxCount = 138;
+ minCount = 3;
+ }
+ else if (curLen == nextLen)
+ {
+ maxCount = 6;
+ minCount = 3;
+ }
+ else
+ {
+ maxCount = 7;
+ minCount = 4;
+ }
+ }
+}
+
+NO_INLINE void CCoder::WriteBits(UInt32 value, unsigned numBits)
+{
+ m_OutStream.WriteBits(value, numBits);
+}
+
+#define WRITE_HF2(codes, lens, i) m_OutStream.WriteBits(codes[i], lens[i])
+#define WRITE_HF(i) WriteBits(codes[i], lens[i])
+
+NO_INLINE void CCoder::LevelTableCode(const Byte *levels, unsigned numLevels, const Byte *lens, const UInt32 *codes)
+{
+ unsigned prevLen = 0xFF;
+ unsigned nextLen = levels[0];
+ unsigned count = 0;
+ unsigned maxCount = 7;
+ unsigned minCount = 4;
+
+ if (nextLen == 0)
+ {
+ maxCount = 138;
+ minCount = 3;
+ }
+
+ for (unsigned n = 0; n < numLevels; n++)
+ {
+ unsigned curLen = nextLen;
+ nextLen = (n < numLevels - 1) ? levels[(size_t)n + 1] : 0xFF;
+ count++;
+ if (count < maxCount && curLen == nextLen)
+ continue;
+
+ if (count < minCount)
+ for (unsigned i = 0; i < count; i++)
+ WRITE_HF(curLen);
+ else if (curLen != 0)
+ {
+ if (curLen != prevLen)
+ {
+ WRITE_HF(curLen);
+ count--;
+ }
+ WRITE_HF(kTableLevelRepNumber);
+ WriteBits(count - 3, 2);
+ }
+ else if (count <= 10)
+ {
+ WRITE_HF(kTableLevel0Number);
+ WriteBits(count - 3, 3);
+ }
+ else
+ {
+ WRITE_HF(kTableLevel0Number2);
+ WriteBits(count - 11, 7);
+ }
+
+ count = 0;
+ prevLen = curLen;
+
+ if (nextLen == 0)
+ {
+ maxCount = 138;
+ minCount = 3;
+ }
+ else if (curLen == nextLen)
+ {
+ maxCount = 6;
+ minCount = 3;
+ }
+ else
+ {
+ maxCount = 7;
+ minCount = 4;
+ }
+ }
+}
+
+NO_INLINE void CCoder::MakeTables(unsigned maxHuffLen)
+{
+ Huffman_Generate(mainFreqs, mainCodes, m_NewLevels.litLenLevels, kFixedMainTableSize, maxHuffLen);
+ Huffman_Generate(distFreqs, distCodes, m_NewLevels.distLevels, kDistTableSize64, maxHuffLen);
+}
+
+static NO_INLINE UInt32 Huffman_GetPrice(const UInt32 *freqs, const Byte *lens, UInt32 num)
+{
+ UInt32 price = 0;
+ UInt32 i;
+ for (i = 0; i < num; i++)
+ price += lens[i] * freqs[i];
+ return price;
+}
+
+static NO_INLINE UInt32 Huffman_GetPrice_Spec(const UInt32 *freqs, const Byte *lens, UInt32 num, const Byte *extraBits, UInt32 extraBase)
+{
+ return Huffman_GetPrice(freqs, lens, num) +
+ Huffman_GetPrice(freqs + extraBase, extraBits, num - extraBase);
+}
+
+NO_INLINE UInt32 CCoder::GetLzBlockPrice() const
+{
+ return
+ Huffman_GetPrice_Spec(mainFreqs, m_NewLevels.litLenLevels, kFixedMainTableSize, m_LenDirectBits, kSymbolMatch) +
+ Huffman_GetPrice_Spec(distFreqs, m_NewLevels.distLevels, kDistTableSize64, kDistDirectBits, 0);
+}
+
+NO_INLINE void CCoder::TryBlock()
+{
+ memset(mainFreqs, 0, sizeof(mainFreqs));
+ memset(distFreqs, 0, sizeof(distFreqs));
+
+ m_ValueIndex = 0;
+ UInt32 blockSize = BlockSizeRes;
+ BlockSizeRes = 0;
+ for (;;)
+ {
+ if (m_OptimumCurrentIndex == m_OptimumEndIndex)
+ {
+ if (m_Pos >= kMatchArrayLimit
+ || BlockSizeRes >= blockSize
+ || (!m_SecondPass && ((Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) == 0) || m_ValueIndex >= m_ValueBlockSize)))
+ break;
+ }
+ UInt32 pos;
+ UInt32 len;
+ if (_fastMode)
+ len = GetOptimalFast(pos);
+ else
+ len = GetOptimal(pos);
+ CCodeValue &codeValue = m_Values[m_ValueIndex++];
+ if (len >= kMatchMinLen)
+ {
+ UInt32 newLen = len - kMatchMinLen;
+ codeValue.Len = (UInt16)newLen;
+ mainFreqs[kSymbolMatch + (size_t)g_LenSlots[newLen]]++;
+ codeValue.Pos = (UInt16)pos;
+ distFreqs[GetPosSlot(pos)]++;
+ }
+ else
+ {
+ Byte b = *(Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow) - m_AdditionalOffset);
+ mainFreqs[b]++;
+ codeValue.SetAsLiteral();
+ codeValue.Pos = b;
+ }
+ m_AdditionalOffset -= len;
+ BlockSizeRes += len;
+ }
+ mainFreqs[kSymbolEndOfBlock]++;
+ m_AdditionalOffset += BlockSizeRes;
+ m_SecondPass = true;
+}
+
+NO_INLINE void CCoder::SetPrices(const CLevels &levels)
+{
+ if (_fastMode)
+ return;
+ UInt32 i;
+ for (i = 0; i < 256; i++)
+ {
+ Byte price = levels.litLenLevels[i];
+ m_LiteralPrices[i] = ((price != 0) ? price : kNoLiteralStatPrice);
+ }
+
+ for (i = 0; i < m_NumLenCombinations; i++)
+ {
+ UInt32 slot = g_LenSlots[i];
+ Byte price = levels.litLenLevels[kSymbolMatch + (size_t)slot];
+ m_LenPrices[i] = (Byte)(((price != 0) ? price : kNoLenStatPrice) + m_LenDirectBits[slot]);
+ }
+
+ for (i = 0; i < kDistTableSize64; i++)
+ {
+ Byte price = levels.distLevels[i];
+ m_PosPrices[i] = (Byte)(((price != 0) ? price: kNoPosStatPrice) + kDistDirectBits[i]);
+ }
+}
+
+static NO_INLINE void Huffman_ReverseBits(UInt32 *codes, const Byte *lens, UInt32 num)
+{
+ for (UInt32 i = 0; i < num; i++)
+ {
+ UInt32 x = codes[i];
+ x = ((x & 0x5555) << 1) | ((x & 0xAAAA) >> 1);
+ x = ((x & 0x3333) << 2) | ((x & 0xCCCC) >> 2);
+ x = ((x & 0x0F0F) << 4) | ((x & 0xF0F0) >> 4);
+ codes[i] = (((x & 0x00FF) << 8) | ((x & 0xFF00) >> 8)) >> (16 - lens[i]);
+ }
+}
+
+NO_INLINE void CCoder::WriteBlock()
+{
+ Huffman_ReverseBits(mainCodes, m_NewLevels.litLenLevels, kFixedMainTableSize);
+ Huffman_ReverseBits(distCodes, m_NewLevels.distLevels, kDistTableSize64);
+
+ for (UInt32 i = 0; i < m_ValueIndex; i++)
+ {
+ const CCodeValue &codeValue = m_Values[i];
+ if (codeValue.IsLiteral())
+ WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, codeValue.Pos);
+ else
+ {
+ UInt32 len = codeValue.Len;
+ UInt32 lenSlot = g_LenSlots[len];
+ WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, kSymbolMatch + lenSlot);
+ m_OutStream.WriteBits(len - m_LenStart[lenSlot], m_LenDirectBits[lenSlot]);
+ UInt32 dist = codeValue.Pos;
+ UInt32 posSlot = GetPosSlot(dist);
+ WRITE_HF2(distCodes, m_NewLevels.distLevels, posSlot);
+ m_OutStream.WriteBits(dist - kDistStart[posSlot], kDistDirectBits[posSlot]);
+ }
+ }
+ WRITE_HF2(mainCodes, m_NewLevels.litLenLevels, kSymbolEndOfBlock);
+}
+
+static UInt32 GetStorePrice(UInt32 blockSize, unsigned bitPosition)
+{
+ UInt32 price = 0;
+ do
+ {
+ UInt32 nextBitPosition = (bitPosition + kFinalBlockFieldSize + kBlockTypeFieldSize) & 7;
+ unsigned numBitsForAlign = nextBitPosition > 0 ? (8 - nextBitPosition): 0;
+ UInt32 curBlockSize = (blockSize < (1 << 16)) ? blockSize : (1 << 16) - 1;
+ price += kFinalBlockFieldSize + kBlockTypeFieldSize + numBitsForAlign + (2 + 2) * 8 + curBlockSize * 8;
+ bitPosition = 0;
+ blockSize -= curBlockSize;
+ }
+ while (blockSize != 0);
+ return price;
+}
+
+void CCoder::WriteStoreBlock(UInt32 blockSize, UInt32 additionalOffset, bool finalBlock)
+{
+ do
+ {
+ UInt32 curBlockSize = (blockSize < (1 << 16)) ? blockSize : (1 << 16) - 1;
+ blockSize -= curBlockSize;
+ WriteBits((finalBlock && (blockSize == 0) ? NFinalBlockField::kFinalBlock: NFinalBlockField::kNotFinalBlock), kFinalBlockFieldSize);
+ WriteBits(NBlockType::kStored, kBlockTypeFieldSize);
+ m_OutStream.FlushByte();
+ WriteBits((UInt16)curBlockSize, kStoredBlockLengthFieldSize);
+ WriteBits((UInt16)~curBlockSize, kStoredBlockLengthFieldSize);
+ const Byte *data = Inline_MatchFinder_GetPointerToCurrentPos(&_lzInWindow)- additionalOffset;
+ for (UInt32 i = 0; i < curBlockSize; i++)
+ m_OutStream.WriteByte(data[i]);
+ additionalOffset -= curBlockSize;
+ }
+ while (blockSize != 0);
+}
+
+NO_INLINE UInt32 CCoder::TryDynBlock(unsigned tableIndex, UInt32 numPasses)
+{
+ CTables &t = m_Tables[tableIndex];
+ BlockSizeRes = t.BlockSizeRes;
+ UInt32 posTemp = t.m_Pos;
+ SetPrices(t);
+
+ for (UInt32 p = 0; p < numPasses; p++)
+ {
+ m_Pos = posTemp;
+ TryBlock();
+ unsigned numHuffBits =
+ (m_ValueIndex > 18000 ? 12 :
+ (m_ValueIndex > 7000 ? 11 :
+ (m_ValueIndex > 2000 ? 10 : 9)));
+ MakeTables(numHuffBits);
+ SetPrices(m_NewLevels);
+ }
+
+ (CLevels &)t = m_NewLevels;
+
+ m_NumLitLenLevels = kMainTableSize;
+ while (m_NumLitLenLevels > kNumLitLenCodesMin && m_NewLevels.litLenLevels[(size_t)m_NumLitLenLevels - 1] == 0)
+ m_NumLitLenLevels--;
+
+ m_NumDistLevels = kDistTableSize64;
+ while (m_NumDistLevels > kNumDistCodesMin && m_NewLevels.distLevels[(size_t)m_NumDistLevels - 1] == 0)
+ m_NumDistLevels--;
+
+ UInt32 levelFreqs[kLevelTableSize];
+ memset(levelFreqs, 0, sizeof(levelFreqs));
+
+ LevelTableDummy(m_NewLevels.litLenLevels, m_NumLitLenLevels, levelFreqs);
+ LevelTableDummy(m_NewLevels.distLevels, m_NumDistLevels, levelFreqs);
+
+ Huffman_Generate(levelFreqs, levelCodes, levelLens, kLevelTableSize, kMaxLevelBitLength);
+
+ m_NumLevelCodes = kNumLevelCodesMin;
+ for (UInt32 i = 0; i < kLevelTableSize; i++)
+ {
+ Byte level = levelLens[kCodeLengthAlphabetOrder[i]];
+ if (level > 0 && i >= m_NumLevelCodes)
+ m_NumLevelCodes = i + 1;
+ m_LevelLevels[i] = level;
+ }
+
+ return GetLzBlockPrice() +
+ Huffman_GetPrice_Spec(levelFreqs, levelLens, kLevelTableSize, kLevelDirectBits, kTableDirectLevels) +
+ kNumLenCodesFieldSize + kNumDistCodesFieldSize + kNumLevelCodesFieldSize +
+ m_NumLevelCodes * kLevelFieldSize + kFinalBlockFieldSize + kBlockTypeFieldSize;
+}
+
+NO_INLINE UInt32 CCoder::TryFixedBlock(unsigned tableIndex)
+{
+ CTables &t = m_Tables[tableIndex];
+ BlockSizeRes = t.BlockSizeRes;
+ m_Pos = t.m_Pos;
+ m_NewLevels.SetFixedLevels();
+ SetPrices(m_NewLevels);
+ TryBlock();
+ return kFinalBlockFieldSize + kBlockTypeFieldSize + GetLzBlockPrice();
+}
+
+NO_INLINE UInt32 CCoder::GetBlockPrice(unsigned tableIndex, unsigned numDivPasses)
+{
+ CTables &t = m_Tables[tableIndex];
+ t.StaticMode = false;
+ UInt32 price = TryDynBlock(tableIndex, m_NumPasses);
+ t.BlockSizeRes = BlockSizeRes;
+ UInt32 numValues = m_ValueIndex;
+ UInt32 posTemp = m_Pos;
+ UInt32 additionalOffsetEnd = m_AdditionalOffset;
+
+ if (m_CheckStatic && m_ValueIndex <= kFixedHuffmanCodeBlockSizeMax)
+ {
+ const UInt32 fixedPrice = TryFixedBlock(tableIndex);
+ t.StaticMode = (fixedPrice < price);
+ if (t.StaticMode)
+ price = fixedPrice;
+ }
+
+ const UInt32 storePrice = GetStorePrice(BlockSizeRes, 0); // bitPosition
+ t.StoreMode = (storePrice <= price);
+ if (t.StoreMode)
+ price = storePrice;
+
+ t.UseSubBlocks = false;
+
+ if (numDivPasses > 1 && numValues >= kDivideCodeBlockSizeMin)
+ {
+ CTables &t0 = m_Tables[(tableIndex << 1)];
+ (CLevels &)t0 = t;
+ t0.BlockSizeRes = t.BlockSizeRes >> 1;
+ t0.m_Pos = t.m_Pos;
+ UInt32 subPrice = GetBlockPrice((tableIndex << 1), numDivPasses - 1);
+
+ UInt32 blockSize2 = t.BlockSizeRes - t0.BlockSizeRes;
+ if (t0.BlockSizeRes >= kDivideBlockSizeMin && blockSize2 >= kDivideBlockSizeMin)
+ {
+ CTables &t1 = m_Tables[(tableIndex << 1) + 1];
+ (CLevels &)t1 = t;
+ t1.BlockSizeRes = blockSize2;
+ t1.m_Pos = m_Pos;
+ m_AdditionalOffset -= t0.BlockSizeRes;
+ subPrice += GetBlockPrice((tableIndex << 1) + 1, numDivPasses - 1);
+ t.UseSubBlocks = (subPrice < price);
+ if (t.UseSubBlocks)
+ price = subPrice;
+ }
+ }
+
+ m_AdditionalOffset = additionalOffsetEnd;
+ m_Pos = posTemp;
+ return price;
+}
+
+void CCoder::CodeBlock(unsigned tableIndex, bool finalBlock)
+{
+ CTables &t = m_Tables[tableIndex];
+ if (t.UseSubBlocks)
+ {
+ CodeBlock((tableIndex << 1), false);
+ CodeBlock((tableIndex << 1) + 1, finalBlock);
+ }
+ else
+ {
+ if (t.StoreMode)
+ WriteStoreBlock(t.BlockSizeRes, m_AdditionalOffset, finalBlock);
+ else
+ {
+ WriteBits((finalBlock ? NFinalBlockField::kFinalBlock: NFinalBlockField::kNotFinalBlock), kFinalBlockFieldSize);
+ if (t.StaticMode)
+ {
+ WriteBits(NBlockType::kFixedHuffman, kBlockTypeFieldSize);
+ TryFixedBlock(tableIndex);
+ unsigned i;
+ const unsigned kMaxStaticHuffLen = 9;
+ for (i = 0; i < kFixedMainTableSize; i++)
+ mainFreqs[i] = (UInt32)1 << (kMaxStaticHuffLen - m_NewLevels.litLenLevels[i]);
+ for (i = 0; i < kFixedDistTableSize; i++)
+ distFreqs[i] = (UInt32)1 << (kMaxStaticHuffLen - m_NewLevels.distLevels[i]);
+ MakeTables(kMaxStaticHuffLen);
+ }
+ else
+ {
+ if (m_NumDivPasses > 1 || m_CheckStatic)
+ TryDynBlock(tableIndex, 1);
+ WriteBits(NBlockType::kDynamicHuffman, kBlockTypeFieldSize);
+ WriteBits(m_NumLitLenLevels - kNumLitLenCodesMin, kNumLenCodesFieldSize);
+ WriteBits(m_NumDistLevels - kNumDistCodesMin, kNumDistCodesFieldSize);
+ WriteBits(m_NumLevelCodes - kNumLevelCodesMin, kNumLevelCodesFieldSize);
+
+ for (UInt32 i = 0; i < m_NumLevelCodes; i++)
+ WriteBits(m_LevelLevels[i], kLevelFieldSize);
+
+ Huffman_ReverseBits(levelCodes, levelLens, kLevelTableSize);
+ LevelTableCode(m_NewLevels.litLenLevels, m_NumLitLenLevels, levelLens, levelCodes);
+ LevelTableCode(m_NewLevels.distLevels, m_NumDistLevels, levelLens, levelCodes);
+ }
+ WriteBlock();
+ }
+ m_AdditionalOffset -= t.BlockSizeRes;
+ }
+}
+
+
+HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */ , const UInt64 * /* outSize */ , ICompressProgressInfo *progress)
+{
+ m_CheckStatic = (m_NumPasses != 1 || m_NumDivPasses != 1);
+ m_IsMultiPass = (m_CheckStatic || (m_NumPasses != 1 || m_NumDivPasses != 1));
+
+ /* we can set stream mode before MatchFinder_Create
+ if default MatchFinder mode was not STREAM_MODE) */
+ // MatchFinder_SET_STREAM_MODE(&_lzInWindow);
+
+ CSeqInStreamWrap _seqInStream;
+ _seqInStream.Init(inStream);
+ MatchFinder_SET_STREAM(&_lzInWindow, &_seqInStream.vt)
+
+ RINOK(Create())
+
+ m_ValueBlockSize = (7 << 10) + (1 << 12) * m_NumDivPasses;
+
+ UInt64 nowPos = 0;
+
+ MatchFinder_Init(&_lzInWindow);
+ m_OutStream.SetStream(outStream);
+ m_OutStream.Init();
+
+ m_OptimumEndIndex = m_OptimumCurrentIndex = 0;
+
+ CTables &t = m_Tables[1];
+ t.m_Pos = 0;
+ t.InitStructures();
+
+ m_AdditionalOffset = 0;
+ do
+ {
+ t.BlockSizeRes = kBlockUncompressedSizeThreshold;
+ m_SecondPass = false;
+ GetBlockPrice(1, m_NumDivPasses);
+ CodeBlock(1, Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) == 0);
+ nowPos += m_Tables[1].BlockSizeRes;
+ if (progress != NULL)
+ {
+ UInt64 packSize = m_OutStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&nowPos, &packSize))
+ }
+ }
+ while (Inline_MatchFinder_GetNumAvailableBytes(&_lzInWindow) != 0);
+
+ if (_seqInStream.Res != S_OK)
+ return _seqInStream.Res;
+
+ if (_lzInWindow.result != SZ_OK)
+ return SResToHRESULT(_lzInWindow.result);
+ return m_OutStream.Flush();
+}
+
+HRESULT CCoder::BaseCode(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return E_FAIL; }
+}
+
+Z7_COM7F_IMF(CCOMCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
+ { return BaseCode(inStream, outStream, inSize, outSize, progress); }
+
+Z7_COM7F_IMF(CCOMCoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps))
+ { return BaseSetEncoderProperties2(propIDs, props, numProps); }
+
+Z7_COM7F_IMF(CCOMCoder64::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
+ { return BaseCode(inStream, outStream, inSize, outSize, progress); }
+
+Z7_COM7F_IMF(CCOMCoder64::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps))
+ { return BaseSetEncoderProperties2(propIDs, props, numProps); }
+
+}}}
diff --git a/CPP/7zip/Compress/DeflateEncoder.h b/CPP/7zip/Compress/DeflateEncoder.h
new file mode 100644
index 0000000..be181e1
--- /dev/null
+++ b/CPP/7zip/Compress/DeflateEncoder.h
@@ -0,0 +1,203 @@
+// DeflateEncoder.h
+
+#ifndef ZIP7_INC_DEFLATE_ENCODER_H
+#define ZIP7_INC_DEFLATE_ENCODER_H
+
+#include "../../../C/LzFind.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "BitlEncoder.h"
+#include "DeflateConst.h"
+
+namespace NCompress {
+namespace NDeflate {
+namespace NEncoder {
+
+struct CCodeValue
+{
+ UInt16 Len;
+ UInt16 Pos;
+ void SetAsLiteral() { Len = (1 << 15); }
+ bool IsLiteral() const { return (Len >= (1 << 15)); }
+};
+
+struct COptimal
+{
+ UInt32 Price;
+ UInt16 PosPrev;
+ UInt16 BackPrev;
+};
+
+const UInt32 kNumOptsBase = 1 << 12;
+const UInt32 kNumOpts = kNumOptsBase + kMatchMaxLen;
+
+class CCoder;
+
+struct CTables: public CLevels
+{
+ bool UseSubBlocks;
+ bool StoreMode;
+ bool StaticMode;
+ UInt32 BlockSizeRes;
+ UInt32 m_Pos;
+ void InitStructures();
+};
+
+
+struct CEncProps
+{
+ int Level;
+ int algo;
+ int fb;
+ int btMode;
+ UInt32 mc;
+ UInt32 numPasses;
+
+ CEncProps()
+ {
+ Level = -1;
+ mc = 0;
+ algo = fb = btMode = -1;
+ numPasses = (UInt32)(Int32)-1;
+ }
+ void Normalize();
+};
+
+class CCoder
+{
+ CMatchFinder _lzInWindow;
+ CBitlEncoder m_OutStream;
+
+public:
+ CCodeValue *m_Values;
+
+ UInt16 *m_MatchDistances;
+ UInt32 m_NumFastBytes;
+ bool _fastMode;
+ bool _btMode;
+
+ UInt16 *m_OnePosMatchesMemory;
+ UInt16 *m_DistanceMemory;
+
+ UInt32 m_Pos;
+
+ unsigned m_NumPasses;
+ unsigned m_NumDivPasses;
+ bool m_CheckStatic;
+ bool m_IsMultiPass;
+ UInt32 m_ValueBlockSize;
+
+ UInt32 m_NumLenCombinations;
+ UInt32 m_MatchMaxLen;
+ const Byte *m_LenStart;
+ const Byte *m_LenDirectBits;
+
+ bool m_Created;
+ bool m_Deflate64Mode;
+
+ Byte m_LevelLevels[kLevelTableSize];
+ unsigned m_NumLitLenLevels;
+ unsigned m_NumDistLevels;
+ UInt32 m_NumLevelCodes;
+ UInt32 m_ValueIndex;
+
+ bool m_SecondPass;
+ UInt32 m_AdditionalOffset;
+
+ UInt32 m_OptimumEndIndex;
+ UInt32 m_OptimumCurrentIndex;
+
+ Byte m_LiteralPrices[256];
+ Byte m_LenPrices[kNumLenSymbolsMax];
+ Byte m_PosPrices[kDistTableSize64];
+
+ CLevels m_NewLevels;
+ UInt32 mainFreqs[kFixedMainTableSize];
+ UInt32 distFreqs[kDistTableSize64];
+ UInt32 mainCodes[kFixedMainTableSize];
+ UInt32 distCodes[kDistTableSize64];
+ UInt32 levelCodes[kLevelTableSize];
+ Byte levelLens[kLevelTableSize];
+
+ UInt32 BlockSizeRes;
+
+ CTables *m_Tables;
+ COptimal m_Optimum[kNumOpts];
+
+ UInt32 m_MatchFinderCycles;
+
+ void GetMatches();
+ void MovePos(UInt32 num);
+ UInt32 Backward(UInt32 &backRes, UInt32 cur);
+ UInt32 GetOptimal(UInt32 &backRes);
+ UInt32 GetOptimalFast(UInt32 &backRes);
+
+ void LevelTableDummy(const Byte *levels, unsigned numLevels, UInt32 *freqs);
+
+ void WriteBits(UInt32 value, unsigned numBits);
+ void LevelTableCode(const Byte *levels, unsigned numLevels, const Byte *lens, const UInt32 *codes);
+
+ void MakeTables(unsigned maxHuffLen);
+ UInt32 GetLzBlockPrice() const;
+ void TryBlock();
+ UInt32 TryDynBlock(unsigned tableIndex, UInt32 numPasses);
+
+ UInt32 TryFixedBlock(unsigned tableIndex);
+
+ void SetPrices(const CLevels &levels);
+ void WriteBlock();
+
+ HRESULT Create();
+ void Free();
+
+ void WriteStoreBlock(UInt32 blockSize, UInt32 additionalOffset, bool finalBlock);
+ void WriteTables(bool writeMode, bool finalBlock);
+
+ void WriteBlockData(bool writeMode, bool finalBlock);
+
+ UInt32 GetBlockPrice(unsigned tableIndex, unsigned numDivPasses);
+ void CodeBlock(unsigned tableIndex, bool finalBlock);
+
+ void SetProps(const CEncProps *props2);
+public:
+ CCoder(bool deflate64Mode = false);
+ ~CCoder();
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ HRESULT BaseCode(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+ HRESULT BaseSetEncoderProperties2(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
+};
+
+
+class CCOMCoder Z7_final:
+ public ICompressCoder,
+ public ICompressSetCoderProperties,
+ public CMyUnknownImp,
+ public CCoder
+{
+ Z7_IFACES_IMP_UNK_2(ICompressCoder, ICompressSetCoderProperties)
+public:
+ CCOMCoder(): CCoder(false) {}
+};
+
+class CCOMCoder64 Z7_final:
+ public ICompressCoder,
+ public ICompressSetCoderProperties,
+ public CMyUnknownImp,
+ public CCoder
+{
+ Z7_IFACES_IMP_UNK_2(ICompressCoder, ICompressSetCoderProperties)
+public:
+ CCOMCoder64(): CCoder(true) {}
+};
+
+}}}
+
+#endif
diff --git a/CPP/7zip/Compress/DeflateRegister.cpp b/CPP/7zip/Compress/DeflateRegister.cpp
new file mode 100644
index 0000000..eaedb84
--- /dev/null
+++ b/CPP/7zip/Compress/DeflateRegister.cpp
@@ -0,0 +1,25 @@
+// DeflateRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "DeflateDecoder.h"
+#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_DEFLATE_EXTRACT_ONLY)
+#include "DeflateEncoder.h"
+#endif
+
+namespace NCompress {
+namespace NDeflate {
+
+REGISTER_CODEC_CREATE(CreateDec, NDecoder::CCOMCoder)
+
+#if !defined(Z7_EXTRACT_ONLY) && !defined(Z7_DEFLATE_EXTRACT_ONLY)
+REGISTER_CODEC_CREATE(CreateEnc, NEncoder::CCOMCoder)
+#else
+#define CreateEnc NULL
+#endif
+
+REGISTER_CODEC_2(Deflate, CreateDec, CreateEnc, 0x40108, "Deflate")
+
+}}
diff --git a/CPP/7zip/Compress/DeltaFilter.cpp b/CPP/7zip/Compress/DeltaFilter.cpp
index cdbd33d..35b77ba 100644
--- a/CPP/7zip/Compress/DeltaFilter.cpp
+++ b/CPP/7zip/Compress/DeltaFilter.cpp
@@ -1,128 +1,126 @@
-// DeltaFilter.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/Delta.h"
-
-#include "../../Common/MyCom.h"
-
-#include "../ICoder.h"
-
-#include "../Common/RegisterCodec.h"
-
-namespace NCompress {
-namespace NDelta {
-
-struct CDelta
-{
- unsigned _delta;
- Byte _state[DELTA_STATE_SIZE];
-
- CDelta(): _delta(1) {}
- void DeltaInit() { Delta_Init(_state); }
-};
-
-
-#ifndef EXTRACT_ONLY
-
-class CEncoder:
- public ICompressFilter,
- public ICompressSetCoderProperties,
- public ICompressWriteCoderProperties,
- CDelta,
- public CMyUnknownImp
-{
-public:
- MY_UNKNOWN_IMP3(ICompressFilter, ICompressSetCoderProperties, ICompressWriteCoderProperties)
- INTERFACE_ICompressFilter(;)
- STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
- STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
-};
-
-STDMETHODIMP CEncoder::Init()
-{
- DeltaInit();
- return S_OK;
-}
-
-STDMETHODIMP_(UInt32) CEncoder::Filter(Byte *data, UInt32 size)
-{
- Delta_Encode(_state, _delta, data, size);
- return size;
-}
-
-STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps)
-{
- UInt32 delta = _delta;
- for (UInt32 i = 0; i < numProps; i++)
- {
- const PROPVARIANT &prop = props[i];
- PROPID propID = propIDs[i];
- if (propID >= NCoderPropID::kReduceSize)
- continue;
- if (prop.vt != VT_UI4)
- return E_INVALIDARG;
- switch (propID)
- {
- case NCoderPropID::kDefaultProp:
- delta = (UInt32)prop.ulVal;
- if (delta < 1 || delta > 256)
- return E_INVALIDARG;
- break;
- case NCoderPropID::kNumThreads: break;
- case NCoderPropID::kLevel: break;
- default: return E_INVALIDARG;
- }
- }
- _delta = delta;
- return S_OK;
-}
-
-STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
-{
- Byte prop = (Byte)(_delta - 1);
- return outStream->Write(&prop, 1, NULL);
-}
-
-#endif
-
-
-class CDecoder:
- public ICompressFilter,
- public ICompressSetDecoderProperties2,
- CDelta,
- public CMyUnknownImp
-{
-public:
- MY_UNKNOWN_IMP2(ICompressFilter, ICompressSetDecoderProperties2)
- INTERFACE_ICompressFilter(;)
- STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
-};
-
-STDMETHODIMP CDecoder::Init()
-{
- DeltaInit();
- return S_OK;
-}
-
-STDMETHODIMP_(UInt32) CDecoder::Filter(Byte *data, UInt32 size)
-{
- Delta_Decode(_state, _delta, data, size);
- return size;
-}
-
-STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)
-{
- if (size != 1)
- return E_INVALIDARG;
- _delta = (unsigned)props[0] + 1;
- return S_OK;
-}
-
-
-REGISTER_FILTER_E(Delta,
- CDecoder(),
- CEncoder(),
- 3, "Delta")
-
-}}
+// DeltaFilter.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Delta.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/RegisterCodec.h"
+
+namespace NCompress {
+namespace NDelta {
+
+struct CDelta
+{
+ unsigned _delta;
+ Byte _state[DELTA_STATE_SIZE];
+
+ CDelta(): _delta(1) {}
+ void DeltaInit() { Delta_Init(_state); }
+};
+
+
+#ifndef Z7_EXTRACT_ONLY
+
+class CEncoder Z7_final:
+ public ICompressFilter,
+ public ICompressSetCoderProperties,
+ public ICompressWriteCoderProperties,
+ public CMyUnknownImp,
+ CDelta
+{
+ Z7_IFACES_IMP_UNK_3(
+ ICompressFilter,
+ ICompressSetCoderProperties,
+ ICompressWriteCoderProperties)
+};
+
+Z7_COM7F_IMF(CEncoder::Init())
+{
+ DeltaInit();
+ return S_OK;
+}
+
+Z7_COM7F_IMF2(UInt32, CEncoder::Filter(Byte *data, UInt32 size))
+{
+ Delta_Encode(_state, _delta, data, size);
+ return size;
+}
+
+Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps))
+{
+ UInt32 delta = _delta;
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = props[i];
+ const PROPID propID = propIDs[i];
+ if (propID >= NCoderPropID::kReduceSize)
+ continue;
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ switch (propID)
+ {
+ case NCoderPropID::kDefaultProp:
+ delta = (UInt32)prop.ulVal;
+ if (delta < 1 || delta > 256)
+ return E_INVALIDARG;
+ break;
+ case NCoderPropID::kNumThreads: break;
+ case NCoderPropID::kLevel: break;
+ default: return E_INVALIDARG;
+ }
+ }
+ _delta = delta;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream))
+{
+ const Byte prop = (Byte)(_delta - 1);
+ return outStream->Write(&prop, 1, NULL);
+}
+
+#endif
+
+
+class CDecoder Z7_final:
+ public ICompressFilter,
+ public ICompressSetDecoderProperties2,
+ public CMyUnknownImp,
+ CDelta
+{
+ Z7_IFACES_IMP_UNK_2(
+ ICompressFilter,
+ ICompressSetDecoderProperties2)
+};
+
+Z7_COM7F_IMF(CDecoder::Init())
+{
+ DeltaInit();
+ return S_OK;
+}
+
+Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size))
+{
+ Delta_Decode(_state, _delta, data, size);
+ return size;
+}
+
+Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size))
+{
+ if (size != 1)
+ return E_INVALIDARG;
+ _delta = (unsigned)props[0] + 1;
+ return S_OK;
+}
+
+
+REGISTER_FILTER_E(Delta,
+ CDecoder(),
+ CEncoder(),
+ 3, "Delta")
+
+}}
diff --git a/CPP/7zip/Compress/DllExports2Compress.cpp b/CPP/7zip/Compress/DllExports2Compress.cpp
new file mode 100644
index 0000000..a6ff690
--- /dev/null
+++ b/CPP/7zip/Compress/DllExports2Compress.cpp
@@ -0,0 +1,28 @@
+// DllExports2Compress.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyInitGuid.h"
+
+#include "../ICoder.h"
+
+#include "../Common/RegisterCodec.h"
+
+extern "C"
+BOOL WINAPI DllMain(
+ #ifdef UNDER_CE
+ HANDLE
+ #else
+ HINSTANCE
+ #endif
+ /* hInstance */, DWORD /* dwReason */, LPVOID /*lpReserved*/)
+{
+ return TRUE;
+}
+
+STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject);
+
+STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
+{
+ return CreateCoder(clsid, iid, outObject);
+}
diff --git a/CPP/7zip/Compress/DllExportsCompress.cpp b/CPP/7zip/Compress/DllExportsCompress.cpp
new file mode 100644
index 0000000..24749d2
--- /dev/null
+++ b/CPP/7zip/Compress/DllExportsCompress.cpp
@@ -0,0 +1,59 @@
+// DllExportsCompress.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/MyInitGuid.h"
+
+#include "../ICoder.h"
+
+#include "../Common/RegisterCodec.h"
+
+static const unsigned kNumCodecsMax = 48;
+unsigned g_NumCodecs = 0;
+const CCodecInfo *g_Codecs[kNumCodecsMax];
+void RegisterCodec(const CCodecInfo *codecInfo) throw()
+{
+ if (g_NumCodecs < kNumCodecsMax)
+ g_Codecs[g_NumCodecs++] = codecInfo;
+}
+
+static const unsigned kNumHashersMax = 16;
+unsigned g_NumHashers = 0;
+const CHasherInfo *g_Hashers[kNumHashersMax];
+void RegisterHasher(const CHasherInfo *hashInfo) throw()
+{
+ if (g_NumHashers < kNumHashersMax)
+ g_Hashers[g_NumHashers++] = hashInfo;
+}
+
+#ifdef _WIN32
+
+extern "C"
+BOOL WINAPI DllMain(
+ #ifdef UNDER_CE
+ HANDLE
+ #else
+ HINSTANCE
+ #endif
+ , DWORD /* dwReason */, LPVOID /*lpReserved*/);
+
+extern "C"
+BOOL WINAPI DllMain(
+ #ifdef UNDER_CE
+ HANDLE
+ #else
+ HINSTANCE
+ #endif
+ , DWORD /* dwReason */, LPVOID /*lpReserved*/)
+{
+ return TRUE;
+}
+#endif
+
+STDAPI CreateCoder(const GUID *clsid, const GUID *iid, void **outObject);
+
+STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject);
+STDAPI CreateObject(const GUID *clsid, const GUID *iid, void **outObject)
+{
+ return CreateCoder(clsid, iid, outObject);
+}
diff --git a/CPP/7zip/Compress/HuffmanDecoder.h b/CPP/7zip/Compress/HuffmanDecoder.h
new file mode 100644
index 0000000..4b8169f
--- /dev/null
+++ b/CPP/7zip/Compress/HuffmanDecoder.h
@@ -0,0 +1,278 @@
+// Compress/HuffmanDecoder.h
+
+#ifndef ZIP7_INC_COMPRESS_HUFFMAN_DECODER_H
+#define ZIP7_INC_COMPRESS_HUFFMAN_DECODER_H
+
+#include "../../Common/MyTypes.h"
+
+namespace NCompress {
+namespace NHuffman {
+
+const unsigned kNumPairLenBits = 4;
+const unsigned kPairLenMask = (1 << kNumPairLenBits) - 1;
+
+template <unsigned kNumBitsMax, UInt32 m_NumSymbols, unsigned kNumTableBits = 9>
+class CDecoder
+{
+public:
+ UInt32 _limits[kNumBitsMax + 2];
+ UInt32 _poses[kNumBitsMax + 1];
+ UInt16 _lens[1 << kNumTableBits];
+ UInt16 _symbols[m_NumSymbols];
+
+ bool Build(const Byte *lens) throw()
+ {
+ UInt32 counts[kNumBitsMax + 1];
+
+ unsigned i;
+ for (i = 0; i <= kNumBitsMax; i++)
+ counts[i] = 0;
+
+ UInt32 sym;
+
+ for (sym = 0; sym < m_NumSymbols; sym++)
+ counts[lens[sym]]++;
+
+ const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
+
+ _limits[0] = 0;
+
+ UInt32 startPos = 0;
+ UInt32 sum = 0;
+
+ for (i = 1; i <= kNumBitsMax; i++)
+ {
+ const UInt32 cnt = counts[i];
+ startPos += cnt << (kNumBitsMax - i);
+ if (startPos > kMaxValue)
+ return false;
+ _limits[i] = startPos;
+ counts[i] = sum;
+ _poses[i] = sum;
+ sum += cnt;
+ }
+
+ counts[0] = sum;
+ _poses[0] = sum;
+ _limits[kNumBitsMax + 1] = kMaxValue;
+
+ for (sym = 0; sym < m_NumSymbols; sym++)
+ {
+ unsigned len = lens[sym];
+ if (len == 0)
+ continue;
+
+ unsigned offset = counts[len]++;
+ _symbols[offset] = (UInt16)sym;
+
+ if (len <= kNumTableBits)
+ {
+ offset -= _poses[len];
+ UInt32 num = (UInt32)1 << (kNumTableBits - len);
+ UInt16 val = (UInt16)((sym << kNumPairLenBits) | len);
+ UInt16 *dest = _lens + (_limits[(size_t)len - 1] >> (kNumBitsMax - kNumTableBits)) + (offset << (kNumTableBits - len));
+ for (UInt32 k = 0; k < num; k++)
+ dest[k] = val;
+ }
+ }
+
+ return true;
+ }
+
+
+ bool BuildFull(const Byte *lens, UInt32 numSymbols = m_NumSymbols) throw()
+ {
+ UInt32 counts[kNumBitsMax + 1];
+
+ unsigned i;
+ for (i = 0; i <= kNumBitsMax; i++)
+ counts[i] = 0;
+
+ UInt32 sym;
+
+ for (sym = 0; sym < numSymbols; sym++)
+ counts[lens[sym]]++;
+
+ const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
+
+ _limits[0] = 0;
+
+ UInt32 startPos = 0;
+ UInt32 sum = 0;
+
+ for (i = 1; i <= kNumBitsMax; i++)
+ {
+ const UInt32 cnt = counts[i];
+ startPos += cnt << (kNumBitsMax - i);
+ if (startPos > kMaxValue)
+ return false;
+ _limits[i] = startPos;
+ counts[i] = sum;
+ _poses[i] = sum;
+ sum += cnt;
+ }
+
+ counts[0] = sum;
+ _poses[0] = sum;
+ _limits[kNumBitsMax + 1] = kMaxValue;
+
+ for (sym = 0; sym < numSymbols; sym++)
+ {
+ unsigned len = lens[sym];
+ if (len == 0)
+ continue;
+
+ unsigned offset = counts[len]++;
+ _symbols[offset] = (UInt16)sym;
+
+ if (len <= kNumTableBits)
+ {
+ offset -= _poses[len];
+ UInt32 num = (UInt32)1 << (kNumTableBits - len);
+ UInt16 val = (UInt16)((sym << kNumPairLenBits) | len);
+ UInt16 *dest = _lens + (_limits[(size_t)len - 1] >> (kNumBitsMax - kNumTableBits)) + (offset << (kNumTableBits - len));
+ for (UInt32 k = 0; k < num; k++)
+ dest[k] = val;
+ }
+ }
+
+ return startPos == kMaxValue;
+ }
+
+
+ template <class TBitDecoder>
+ Z7_FORCE_INLINE
+ UInt32 Decode(TBitDecoder *bitStream) const
+ {
+ UInt32 val = bitStream->GetValue(kNumBitsMax);
+
+ if (val < _limits[kNumTableBits])
+ {
+ UInt32 pair = _lens[val >> (kNumBitsMax - kNumTableBits)];
+ bitStream->MovePos((unsigned)(pair & kPairLenMask));
+ return pair >> kNumPairLenBits;
+ }
+
+ unsigned numBits;
+ for (numBits = kNumTableBits + 1; val >= _limits[numBits]; numBits++);
+
+ if (numBits > kNumBitsMax)
+ return 0xFFFFFFFF;
+
+ bitStream->MovePos(numBits);
+ UInt32 index = _poses[numBits] + ((val - _limits[(size_t)numBits - 1]) >> (kNumBitsMax - numBits));
+ return _symbols[index];
+ }
+
+
+ template <class TBitDecoder>
+ Z7_FORCE_INLINE
+ UInt32 DecodeFull(TBitDecoder *bitStream) const
+ {
+ UInt32 val = bitStream->GetValue(kNumBitsMax);
+
+ if (val < _limits[kNumTableBits])
+ {
+ UInt32 pair = _lens[val >> (kNumBitsMax - kNumTableBits)];
+ bitStream->MovePos((unsigned)(pair & kPairLenMask));
+ return pair >> kNumPairLenBits;
+ }
+
+ unsigned numBits;
+ for (numBits = kNumTableBits + 1; val >= _limits[numBits]; numBits++);
+
+ bitStream->MovePos(numBits);
+ UInt32 index = _poses[numBits] + ((val - _limits[(size_t)numBits - 1]) >> (kNumBitsMax - numBits));
+ return _symbols[index];
+ }
+};
+
+
+
+template <UInt32 m_NumSymbols>
+class CDecoder7b
+{
+ Byte _lens[1 << 7];
+public:
+
+ bool Build(const Byte *lens) throw()
+ {
+ const unsigned kNumBitsMax = 7;
+
+ UInt32 counts[kNumBitsMax + 1];
+ UInt32 _poses[kNumBitsMax + 1];
+ UInt32 _limits[kNumBitsMax + 1];
+
+ unsigned i;
+ for (i = 0; i <= kNumBitsMax; i++)
+ counts[i] = 0;
+
+ UInt32 sym;
+
+ for (sym = 0; sym < m_NumSymbols; sym++)
+ counts[lens[sym]]++;
+
+ const UInt32 kMaxValue = (UInt32)1 << kNumBitsMax;
+
+ _limits[0] = 0;
+
+ UInt32 startPos = 0;
+ UInt32 sum = 0;
+
+ for (i = 1; i <= kNumBitsMax; i++)
+ {
+ const UInt32 cnt = counts[i];
+ startPos += cnt << (kNumBitsMax - i);
+ if (startPos > kMaxValue)
+ return false;
+ _limits[i] = startPos;
+ counts[i] = sum;
+ _poses[i] = sum;
+ sum += cnt;
+ }
+
+ counts[0] = sum;
+ _poses[0] = sum;
+
+ for (sym = 0; sym < m_NumSymbols; sym++)
+ {
+ unsigned len = lens[sym];
+ if (len == 0)
+ continue;
+
+ unsigned offset = counts[len]++;
+
+ {
+ offset -= _poses[len];
+ UInt32 num = (UInt32)1 << (kNumBitsMax - len);
+ Byte val = (Byte)((sym << 3) | len);
+ Byte *dest = _lens + (_limits[(size_t)len - 1]) + (offset << (kNumBitsMax - len));
+ for (UInt32 k = 0; k < num; k++)
+ dest[k] = val;
+ }
+ }
+
+ {
+ UInt32 limit = _limits[kNumBitsMax];
+ UInt32 num = ((UInt32)1 << kNumBitsMax) - limit;
+ Byte *dest = _lens + limit;
+ for (UInt32 k = 0; k < num; k++)
+ dest[k] = (Byte)(0x1F << 3);
+ }
+
+ return true;
+ }
+
+ template <class TBitDecoder>
+ UInt32 Decode(TBitDecoder *bitStream) const
+ {
+ UInt32 val = bitStream->GetValue(7);
+ UInt32 pair = _lens[val];
+ bitStream->MovePos((unsigned)(pair & 0x7));
+ return pair >> 3;
+ }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/ImplodeDecoder.cpp b/CPP/7zip/Compress/ImplodeDecoder.cpp
new file mode 100644
index 0000000..12f2dce
--- /dev/null
+++ b/CPP/7zip/Compress/ImplodeDecoder.cpp
@@ -0,0 +1,258 @@
+// ImplodeDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/Defs.h"
+
+#include "ImplodeDecoder.h"
+
+namespace NCompress {
+namespace NImplode {
+namespace NDecoder {
+
+bool CHuffmanDecoder::Build(const Byte *lens, unsigned numSymbols) throw()
+{
+ unsigned counts[kNumHuffmanBits + 1];
+
+ unsigned i;
+ for (i = 0; i <= kNumHuffmanBits; i++)
+ counts[i] = 0;
+
+ unsigned sym;
+ for (sym = 0; sym < numSymbols; sym++)
+ counts[lens[sym]]++;
+
+ const UInt32 kMaxValue = (UInt32)1 << kNumHuffmanBits;
+
+ // _limits[0] = kMaxValue;
+
+ UInt32 startPos = kMaxValue;
+ UInt32 sum = 0;
+
+ for (i = 1; i <= kNumHuffmanBits; i++)
+ {
+ const UInt32 cnt = counts[i];
+ const UInt32 range = cnt << (kNumHuffmanBits - i);
+ if (startPos < range)
+ return false;
+ startPos -= range;
+ _limits[i] = startPos;
+ _poses[i] = sum;
+ sum += cnt;
+ counts[i] = sum;
+ }
+
+ // counts[0] += sum;
+
+ if (startPos != 0)
+ return false;
+
+ for (sym = 0; sym < numSymbols; sym++)
+ {
+ const unsigned len = lens[sym];
+ if (len != 0)
+ _symbols[--counts[len]] = (Byte)sym;
+ }
+
+ return true;
+}
+
+
+UInt32 CHuffmanDecoder::Decode(CInBit *inStream) const throw()
+{
+ const UInt32 val = inStream->GetValue(kNumHuffmanBits);
+ unsigned numBits;
+ for (numBits = 1; val < _limits[numBits]; numBits++);
+ const UInt32 sym = _symbols[_poses[numBits] + ((val - _limits[numBits]) >> (kNumHuffmanBits - numBits))];
+ inStream->MovePos(numBits);
+ return sym;
+}
+
+
+
+static const unsigned kNumLenDirectBits = 8;
+
+static const unsigned kNumDistDirectBitsSmall = 6;
+static const unsigned kNumDistDirectBitsBig = 7;
+
+static const unsigned kLitTableSize = (1 << 8);
+static const unsigned kDistTableSize = 64;
+static const unsigned kLenTableSize = 64;
+
+static const UInt32 kHistorySize = (1 << kNumDistDirectBitsBig) * kDistTableSize; // 8 KB
+
+
+CCoder::CCoder():
+ _flags(0),
+ _fullStreamMode(false)
+{}
+
+
+bool CCoder::BuildHuff(CHuffmanDecoder &decoder, unsigned numSymbols)
+{
+ Byte levels[kMaxHuffTableSize];
+ unsigned numRecords = (unsigned)_inBitStream.ReadAlignedByte() + 1;
+ unsigned index = 0;
+ do
+ {
+ const unsigned b = (unsigned)_inBitStream.ReadAlignedByte();
+ const Byte level = (Byte)((b & 0xF) + 1);
+ const unsigned rep = ((unsigned)b >> 4) + 1;
+ if (index + rep > numSymbols)
+ return false;
+ for (unsigned j = 0; j < rep; j++)
+ levels[index++] = level;
+ }
+ while (--numRecords);
+
+ if (index != numSymbols)
+ return false;
+ return decoder.Build(levels, numSymbols);
+}
+
+
+HRESULT CCoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (!_inBitStream.Create(1 << 18))
+ return E_OUTOFMEMORY;
+ if (!_outWindowStream.Create(kHistorySize << 1)) // 16 KB
+ return E_OUTOFMEMORY;
+ if (!outSize)
+ return E_INVALIDARG;
+
+ _outWindowStream.SetStream(outStream);
+ _outWindowStream.Init(false);
+ _inBitStream.SetStream(inStream);
+ _inBitStream.Init();
+
+ const unsigned numDistDirectBits = (_flags & 2) ?
+ kNumDistDirectBitsBig:
+ kNumDistDirectBitsSmall;
+ const bool literalsOn = ((_flags & 4) != 0);
+ const UInt32 minMatchLen = (literalsOn ? 3 : 2);
+
+ if (literalsOn)
+ if (!BuildHuff(_litDecoder, kLitTableSize))
+ return S_FALSE;
+ if (!BuildHuff(_lenDecoder, kLenTableSize))
+ return S_FALSE;
+ if (!BuildHuff(_distDecoder, kDistTableSize))
+ return S_FALSE;
+
+ UInt64 prevProgress = 0;
+ bool moreOut = false;
+ UInt64 pos = 0, unPackSize = *outSize;
+
+ while (pos < unPackSize)
+ {
+ if (progress && (pos - prevProgress) >= (1 << 18))
+ {
+ const UInt64 packSize = _inBitStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &pos))
+ prevProgress = pos;
+ }
+
+ if (_inBitStream.ReadBits(1) != 0)
+ {
+ Byte b;
+ if (literalsOn)
+ {
+ const UInt32 sym = _litDecoder.Decode(&_inBitStream);
+ // if (sym >= kLitTableSize) break;
+ b = (Byte)sym;
+ }
+ else
+ b = (Byte)_inBitStream.ReadBits(8);
+ _outWindowStream.PutByte(b);
+ pos++;
+ }
+ else
+ {
+ const UInt32 lowDistBits = _inBitStream.ReadBits(numDistDirectBits);
+ UInt32 dist = _distDecoder.Decode(&_inBitStream);
+ // if (dist >= kDistTableSize) break;
+ dist = (dist << numDistDirectBits) + lowDistBits;
+ UInt32 len = _lenDecoder.Decode(&_inBitStream);
+ // if (len >= kLenTableSize) break;
+ if (len == kLenTableSize - 1)
+ len += _inBitStream.ReadBits(kNumLenDirectBits);
+ len += minMatchLen;
+
+ {
+ const UInt64 limit = unPackSize - pos;
+ if (len > limit)
+ {
+ moreOut = true;
+ len = (UInt32)limit;
+ }
+ }
+
+ while (dist >= pos && len != 0)
+ {
+ _outWindowStream.PutByte(0);
+ pos++;
+ len--;
+ }
+
+ if (len != 0)
+ {
+ _outWindowStream.CopyBlock(dist, len);
+ pos += len;
+ }
+ }
+ }
+
+ HRESULT res = _outWindowStream.Flush();
+
+ if (res == S_OK)
+ {
+ if (_fullStreamMode)
+ {
+ if (moreOut)
+ res = S_FALSE;
+ if (inSize && *inSize != _inBitStream.GetProcessedSize())
+ res = S_FALSE;
+ }
+ if (pos != unPackSize)
+ res = S_FALSE;
+ }
+
+ return res;
+}
+
+
+Z7_COM7F_IMF(CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ // catch(const CInBufferException &e) { return e.ErrorCode; }
+ // catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(const CSystemException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+
+Z7_COM7F_IMF(CCoder::SetDecoderProperties2(const Byte *data, UInt32 size))
+{
+ if (size == 0)
+ return E_NOTIMPL;
+ _flags = data[0];
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CCoder::SetFinishMode(UInt32 finishMode))
+{
+ _fullStreamMode = (finishMode != 0);
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CCoder::GetInStreamProcessedSize(UInt64 *value))
+{
+ *value = _inBitStream.GetProcessedSize();
+ return S_OK;
+}
+
+}}}
diff --git a/CPP/7zip/Compress/ImplodeDecoder.h b/CPP/7zip/Compress/ImplodeDecoder.h
new file mode 100644
index 0000000..ec70045
--- /dev/null
+++ b/CPP/7zip/Compress/ImplodeDecoder.h
@@ -0,0 +1,61 @@
+// ImplodeDecoder.h
+
+#ifndef ZIP7_INC_COMPRESS_IMPLODE_DECODER_H
+#define ZIP7_INC_COMPRESS_IMPLODE_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitlDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NImplode {
+namespace NDecoder {
+
+typedef NBitl::CDecoder<CInBuffer> CInBit;
+
+const unsigned kNumHuffmanBits = 16;
+const unsigned kMaxHuffTableSize = 1 << 8;
+
+class CHuffmanDecoder
+{
+ UInt32 _limits[kNumHuffmanBits + 1];
+ UInt32 _poses[kNumHuffmanBits + 1];
+ Byte _symbols[kMaxHuffTableSize];
+public:
+ bool Build(const Byte *lens, unsigned numSymbols) throw();
+ UInt32 Decode(CInBit *inStream) const throw();
+};
+
+
+Z7_CLASS_IMP_NOQIB_4(
+ CCoder
+ , ICompressCoder
+ , ICompressSetDecoderProperties2
+ , ICompressSetFinishMode
+ , ICompressGetInStreamProcessedSize
+)
+ CLzOutWindow _outWindowStream;
+ CInBit _inBitStream;
+
+ CHuffmanDecoder _litDecoder;
+ CHuffmanDecoder _lenDecoder;
+ CHuffmanDecoder _distDecoder;
+
+ Byte _flags;
+ bool _fullStreamMode;
+
+ bool BuildHuff(CHuffmanDecoder &table, unsigned numSymbols);
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+public:
+ CCoder();
+};
+
+}}}
+
+#endif
diff --git a/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp b/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp
new file mode 100644
index 0000000..7d31bb9
--- /dev/null
+++ b/CPP/7zip/Compress/ImplodeHuffmanDecoder.cpp
@@ -0,0 +1,3 @@
+// ImplodeHuffmanDecoder.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/Compress/ImplodeHuffmanDecoder.h b/CPP/7zip/Compress/ImplodeHuffmanDecoder.h
new file mode 100644
index 0000000..dcf8ac6
--- /dev/null
+++ b/CPP/7zip/Compress/ImplodeHuffmanDecoder.h
@@ -0,0 +1,6 @@
+// ImplodeHuffmanDecoder.h
+
+#ifndef ZIP7_INC_IMPLODE_HUFFMAN_DECODER_H
+#define ZIP7_INC_IMPLODE_HUFFMAN_DECODER_H
+
+#endif
diff --git a/CPP/7zip/Compress/LzOutWindow.cpp b/CPP/7zip/Compress/LzOutWindow.cpp
new file mode 100644
index 0000000..aae02eb
--- /dev/null
+++ b/CPP/7zip/Compress/LzOutWindow.cpp
@@ -0,0 +1,14 @@
+// LzOutWindow.cpp
+
+#include "StdAfx.h"
+
+#include "LzOutWindow.h"
+
+void CLzOutWindow::Init(bool solid) throw()
+{
+ if (!solid)
+ COutBuffer::Init();
+ #ifdef Z7_NO_EXCEPTIONS
+ ErrorCode = S_OK;
+ #endif
+}
diff --git a/CPP/7zip/Compress/LzOutWindow.h b/CPP/7zip/Compress/LzOutWindow.h
new file mode 100644
index 0000000..599b124
--- /dev/null
+++ b/CPP/7zip/Compress/LzOutWindow.h
@@ -0,0 +1,102 @@
+// LzOutWindow.h
+
+#ifndef ZIP7_INC_LZ_OUT_WINDOW_H
+#define ZIP7_INC_LZ_OUT_WINDOW_H
+
+#include "../Common/OutBuffer.h"
+
+#ifndef Z7_NO_EXCEPTIONS
+typedef COutBufferException CLzOutWindowException;
+#endif
+
+class CLzOutWindow: public COutBuffer
+{
+public:
+ void Init(bool solid = false) throw();
+
+ // distance >= 0, len > 0,
+ bool CopyBlock(UInt32 distance, UInt32 len)
+ {
+ UInt32 pos = _pos - distance - 1;
+ if (distance >= _pos)
+ {
+ if (!_overDict || distance >= _bufSize)
+ return false;
+ pos += _bufSize;
+ }
+ if (_limitPos - _pos > len && _bufSize - pos > len)
+ {
+ const Byte *src = _buf + pos;
+ Byte *dest = _buf + _pos;
+ _pos += len;
+ do
+ *dest++ = *src++;
+ while (--len != 0);
+ }
+ else do
+ {
+ UInt32 pos2;
+ if (pos == _bufSize)
+ pos = 0;
+ pos2 = _pos;
+ _buf[pos2++] = _buf[pos++];
+ _pos = pos2;
+ if (pos2 == _limitPos)
+ FlushWithCheck();
+ }
+ while (--len != 0);
+ return true;
+ }
+
+ void PutByte(Byte b)
+ {
+ UInt32 pos = _pos;
+ _buf[pos++] = b;
+ _pos = pos;
+ if (pos == _limitPos)
+ FlushWithCheck();
+ }
+
+ void PutBytes(const Byte *data, UInt32 size)
+ {
+ if (size == 0)
+ return;
+ UInt32 pos = _pos;
+ Byte *buf = _buf;
+ buf[pos++] = *data++;
+ size--;
+ for (;;)
+ {
+ UInt32 limitPos = _limitPos;
+ UInt32 rem = limitPos - pos;
+ if (rem == 0)
+ {
+ _pos = pos;
+ FlushWithCheck();
+ pos = _pos;
+ continue;
+ }
+
+ if (size == 0)
+ break;
+
+ if (rem > size)
+ rem = size;
+ size -= rem;
+ do
+ buf[pos++] = *data++;
+ while (--rem);
+ }
+ _pos = pos;
+ }
+
+ Byte GetByte(UInt32 distance) const
+ {
+ UInt32 pos = _pos - distance - 1;
+ if (distance >= _pos)
+ pos += _bufSize;
+ return _buf[pos];
+ }
+};
+
+#endif
diff --git a/CPP/7zip/Compress/LzfseDecoder.cpp b/CPP/7zip/Compress/LzfseDecoder.cpp
new file mode 100644
index 0000000..236d5bd
--- /dev/null
+++ b/CPP/7zip/Compress/LzfseDecoder.cpp
@@ -0,0 +1,942 @@
+// LzfseDecoder.cpp
+
+/*
+This code implements LZFSE data decompressing.
+The code from "LZFSE compression library" was used.
+
+2018 : Igor Pavlov : BSD 3-clause License : the code in this file
+2015-2017 : Apple Inc : BSD 3-clause License : original "LZFSE compression library" code
+
+The code in the "LZFSE compression library" is licensed under the "BSD 3-clause License":
+----
+Copyright (c) 2015-2016, Apple Inc. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the distribution.
+
+3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+----
+*/
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#endif
+
+#ifdef SHOW_DEBUG_INFO
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#include "../../../C/CpuArch.h"
+
+#include "LzfseDecoder.h"
+
+namespace NCompress {
+namespace NLzfse {
+
+static const Byte kSignature_LZFSE_V1 = 0x31; // '1'
+static const Byte kSignature_LZFSE_V2 = 0x32; // '2'
+
+
+HRESULT CDecoder::GetUInt32(UInt32 &val)
+{
+ Byte b[4];
+ for (unsigned i = 0; i < 4; i++)
+ if (!m_InStream.ReadByte(b[i]))
+ return S_FALSE;
+ val = GetUi32(b);
+ return S_OK;
+}
+
+
+
+HRESULT CDecoder::DecodeUncompressed(UInt32 unpackSize)
+{
+ PRF(printf("\nUncompressed %7u\n", unpackSize));
+
+ const unsigned kBufSize = 1 << 8;
+ Byte buf[kBufSize];
+ for (;;)
+ {
+ if (unpackSize == 0)
+ return S_OK;
+ UInt32 cur = unpackSize;
+ if (cur > kBufSize)
+ cur = kBufSize;
+ UInt32 cur2 = (UInt32)m_InStream.ReadBytes(buf, cur);
+ m_OutWindowStream.PutBytes(buf, cur2);
+ if (cur != cur2)
+ return S_FALSE;
+ }
+}
+
+
+
+HRESULT CDecoder::DecodeLzvn(UInt32 unpackSize, UInt32 packSize)
+{
+ PRF(printf("\nLZVN %7u %7u", unpackSize, packSize));
+
+ UInt32 D = 0;
+
+ for (;;)
+ {
+ if (packSize == 0)
+ return S_FALSE;
+ Byte b;
+ if (!m_InStream.ReadByte(b))
+ return S_FALSE;
+ packSize--;
+
+ UInt32 M;
+ UInt32 L;
+
+ if (b >= 0xE0)
+ {
+ /*
+ large L - 11100000 LLLLLLLL <LITERALS>
+ small L - 1110LLLL <LITERALS>
+
+ large Rep - 11110000 MMMMMMMM
+ small Rep - 1111MMMM
+ */
+
+ M = b & 0xF;
+ if (M == 0)
+ {
+ if (packSize == 0)
+ return S_FALSE;
+ Byte b1;
+ if (!m_InStream.ReadByte(b1))
+ return S_FALSE;
+ packSize--;
+ M = (UInt32)b1 + 16;
+ }
+ L = 0;
+ if ((b & 0x10) == 0)
+ {
+ // Literals only
+ L = M;
+ M = 0;
+ }
+ }
+
+ // ERROR codes
+ else if ((b & 0xF0) == 0x70) // 0111xxxx
+ return S_FALSE;
+ else if ((b & 0xF0) == 0xD0) // 1101xxxx
+ return S_FALSE;
+
+ else
+ {
+ if ((b & 0xE0) == 0xA0)
+ {
+ // medium - 101LLMMM DDDDDDMM DDDDDDDD <LITERALS>
+ if (packSize < 2)
+ return S_FALSE;
+ Byte b1;
+ if (!m_InStream.ReadByte(b1))
+ return S_FALSE;
+ packSize--;
+
+ Byte b2;
+ if (!m_InStream.ReadByte(b2))
+ return S_FALSE;
+ packSize--;
+ L = (((UInt32)b >> 3) & 3);
+ M = (((UInt32)b & 7) << 2) + (b1 & 3);
+ D = ((UInt32)b1 >> 2) + ((UInt32)b2 << 6);
+ }
+ else
+ {
+ L = (UInt32)b >> 6;
+ M = ((UInt32)b >> 3) & 7;
+ if ((b & 0x7) == 6)
+ {
+ // REP - LLMMM110 <LITERALS>
+ if (L == 0)
+ {
+ // spec
+ if (M == 0)
+ break; // EOS
+ if (M <= 2)
+ continue; // NOP
+ return S_FALSE; // UNDEFINED
+ }
+ }
+ else
+ {
+ if (packSize == 0)
+ return S_FALSE;
+ Byte b1;
+ if (!m_InStream.ReadByte(b1))
+ return S_FALSE;
+ packSize--;
+
+ // large - LLMMM111 DDDDDDDD DDDDDDDD <LITERALS>
+ // small - LLMMMDDD DDDDDDDD <LITERALS>
+ D = ((UInt32)b & 7);
+ if (D == 7)
+ {
+ if (packSize == 0)
+ return S_FALSE;
+ Byte b2;
+ if (!m_InStream.ReadByte(b2))
+ return S_FALSE;
+ packSize--;
+ D = b2;
+ }
+ D = (D << 8) + b1;
+ }
+ }
+
+ M += 3;
+ }
+ {
+ for (unsigned i = 0; i < L; i++)
+ {
+ if (packSize == 0 || unpackSize == 0)
+ return S_FALSE;
+ Byte b1;
+ if (!m_InStream.ReadByte(b1))
+ return S_FALSE;
+ packSize--;
+ m_OutWindowStream.PutByte(b1);
+ unpackSize--;
+ }
+ }
+
+ if (M != 0)
+ {
+ if (unpackSize == 0 || D == 0)
+ return S_FALSE;
+ unsigned cur = M;
+ if (cur > unpackSize)
+ cur = (unsigned)unpackSize;
+ if (!m_OutWindowStream.CopyBlock(D - 1, cur))
+ return S_FALSE;
+ unpackSize -= cur;
+ if (cur != M)
+ return S_FALSE;
+ }
+ }
+
+ if (unpackSize != 0)
+ return S_FALSE;
+
+ // LZVN encoder writes 7 additional zero bytes
+ if (packSize != 7)
+ return S_FALSE;
+ do
+ {
+ Byte b;
+ if (!m_InStream.ReadByte(b))
+ return S_FALSE;
+ packSize--;
+ if (b != 0)
+ return S_FALSE;
+ }
+ while (packSize != 0);
+
+ return S_OK;
+}
+
+
+
+// ---------- LZFSE ----------
+
+#define MATCHES_PER_BLOCK 10000
+#define LITERALS_PER_BLOCK (4 * MATCHES_PER_BLOCK)
+
+#define NUM_L_SYMBOLS 20
+#define NUM_M_SYMBOLS 20
+#define NUM_D_SYMBOLS 64
+#define NUM_LIT_SYMBOLS 256
+
+#define NUM_SYMBOLS ( \
+ NUM_L_SYMBOLS + \
+ NUM_M_SYMBOLS + \
+ NUM_D_SYMBOLS + \
+ NUM_LIT_SYMBOLS)
+
+#define NUM_L_STATES (1 << 6)
+#define NUM_M_STATES (1 << 6)
+#define NUM_D_STATES (1 << 8)
+#define NUM_LIT_STATES (1 << 10)
+
+
+typedef UInt32 CFseState;
+
+
+static UInt32 SumFreqs(const UInt16 *freqs, unsigned num)
+{
+ UInt32 sum = 0;
+ for (unsigned i = 0; i < num; i++)
+ sum += (UInt32)freqs[i];
+ return sum;
+}
+
+
+static Z7_FORCE_INLINE unsigned CountZeroBits(UInt32 val, UInt32 mask)
+{
+ for (unsigned i = 0;;)
+ {
+ if (val & mask)
+ return i;
+ i++;
+ mask >>= 1;
+ }
+}
+
+
+static Z7_FORCE_INLINE void InitLitTable(const UInt16 *freqs, UInt32 *table)
+{
+ for (unsigned i = 0; i < NUM_LIT_SYMBOLS; i++)
+ {
+ unsigned f = freqs[i];
+ if (f == 0)
+ continue;
+
+ // 0 < f <= numStates
+ // 0 <= k <= numStatesLog
+ // numStates <= (f<<k) < numStates * 2
+ // 0 < j0 <= f
+ // (f + j0) = next_power_of_2 for f
+ unsigned k = CountZeroBits(f, NUM_LIT_STATES);
+ unsigned j0 = (((unsigned)NUM_LIT_STATES * 2) >> k) - f;
+
+ /*
+ CEntry
+ {
+ Byte k;
+ Byte symbol;
+ UInt16 delta;
+ };
+ */
+
+ UInt32 e = ((UInt32)i << 8) + k;
+ k += 16;
+ UInt32 d = e + ((UInt32)f << k) - ((UInt32)NUM_LIT_STATES << 16);
+ UInt32 step = (UInt32)1 << k;
+
+ unsigned j = 0;
+ do
+ {
+ *table++ = d;
+ d += step;
+ }
+ while (++j < j0);
+
+ e--;
+ step >>= 1;
+
+ for (j = j0; j < f; j++)
+ {
+ *table++ = e;
+ e += step;
+ }
+ }
+}
+
+
+typedef struct
+{
+ Byte totalBits;
+ Byte extraBits;
+ UInt16 delta;
+ UInt32 vbase;
+} CExtraEntry;
+
+
+static void InitExtraDecoderTable(unsigned numStates,
+ unsigned numSymbols,
+ const UInt16 *freqs,
+ const Byte *vbits,
+ CExtraEntry *table)
+{
+ UInt32 vbase = 0;
+
+ for (unsigned i = 0; i < numSymbols; i++)
+ {
+ unsigned f = freqs[i];
+ unsigned extraBits = vbits[i];
+
+ if (f != 0)
+ {
+ unsigned k = CountZeroBits(f, numStates);
+ unsigned j0 = ((2 * numStates) >> k) - f;
+
+ unsigned j = 0;
+ do
+ {
+ CExtraEntry *e = table++;
+ e->totalBits = (Byte)(k + extraBits);
+ e->extraBits = (Byte)extraBits;
+ e->delta = (UInt16)(((f + j) << k) - numStates);
+ e->vbase = vbase;
+ }
+ while (++j < j0);
+
+ f -= j0;
+ k--;
+
+ for (j = 0; j < f; j++)
+ {
+ CExtraEntry *e = table++;
+ e->totalBits = (Byte)(k + extraBits);
+ e->extraBits = (Byte)extraBits;
+ e->delta = (UInt16)(j << k);
+ e->vbase = vbase;
+ }
+ }
+
+ vbase += ((UInt32)1 << extraBits);
+ }
+}
+
+
+static const Byte k_L_extra[NUM_L_SYMBOLS] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 5, 8
+};
+
+static const Byte k_M_extra[NUM_M_SYMBOLS] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 5, 8, 11
+};
+
+static const Byte k_D_extra[NUM_D_SYMBOLS] =
+{
+ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
+ 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
+ 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
+ 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15
+};
+
+
+
+// ---------- CBitStream ----------
+
+typedef struct
+{
+ UInt32 accum;
+ unsigned numBits; // [0, 31] - Number of valid bits in (accum), other bits are 0
+} CBitStream;
+
+
+static Z7_FORCE_INLINE int FseInStream_Init(CBitStream *s,
+ int n, // [-7, 0], (-n == number_of_unused_bits) in last byte
+ const Byte **pbuf)
+{
+ *pbuf -= 4;
+ s->accum = GetUi32(*pbuf);
+ if (n)
+ {
+ s->numBits = (unsigned)(n + 32);
+ if ((s->accum >> s->numBits) != 0)
+ return -1; // ERROR, encoder should have zeroed the upper bits
+ }
+ else
+ {
+ *pbuf += 1;
+ s->accum >>= 8;
+ s->numBits = 24;
+ }
+ return 0; // OK
+}
+
+
+// 0 <= numBits < 32
+#define mask31(x, numBits) ((x) & (((UInt32)1 << (numBits)) - 1))
+
+#define FseInStream_FLUSH \
+ { const unsigned nbits = (31 - in.numBits) & (unsigned)-8; \
+ if (nbits) { \
+ buf -= (nbits >> 3); \
+ if (buf < buf_check) return S_FALSE; \
+ UInt32 v = GetUi32(buf); \
+ in.accum = (in.accum << nbits) | mask31(v, nbits); \
+ in.numBits += nbits; }}
+
+
+
+static Z7_FORCE_INLINE UInt32 BitStream_Pull(CBitStream *s, unsigned numBits)
+{
+ s->numBits -= numBits;
+ UInt32 v = s->accum >> s->numBits;
+ s->accum = mask31(s->accum, s->numBits);
+ return v;
+}
+
+
+#define DECODE_LIT(dest, pstate) { \
+ UInt32 e = lit_decoder[pstate]; \
+ pstate = (CFseState)((e >> 16) + BitStream_Pull(&in, e & 0xff)); \
+ dest = (Byte)(e >> 8); }
+
+
+static Z7_FORCE_INLINE UInt32 FseDecodeExtra(CFseState *pstate,
+ const CExtraEntry *table,
+ CBitStream *s)
+{
+ const CExtraEntry *e = &table[*pstate];
+ UInt32 v = BitStream_Pull(s, e->totalBits);
+ unsigned extraBits = e->extraBits;
+ *pstate = (CFseState)(e->delta + (v >> extraBits));
+ return e->vbase + mask31(v, extraBits);
+}
+
+
+#define freqs_L (freqs)
+#define freqs_M (freqs_L + NUM_L_SYMBOLS)
+#define freqs_D (freqs_M + NUM_M_SYMBOLS)
+#define freqs_LIT (freqs_D + NUM_D_SYMBOLS)
+
+#define GET_BITS_64(v, offset, num, dest) dest = (UInt32) ((v >> (offset)) & ((1 << (num)) - 1));
+#define GET_BITS_64_Int32(v, offset, num, dest) dest = (Int32)((v >> (offset)) & ((1 << (num)) - 1));
+#define GET_BITS_32(v, offset, num, dest) dest = (CFseState)((v >> (offset)) & ((1 << (num)) - 1));
+
+
+HRESULT CDecoder::DecodeLzfse(UInt32 unpackSize, Byte version)
+{
+ PRF(printf("\nLZFSE-%d %7u", version - '0', unpackSize));
+
+ UInt32 numLiterals;
+ UInt32 litPayloadSize;
+ Int32 literal_bits;
+
+ UInt32 lit_state_0;
+ UInt32 lit_state_1;
+ UInt32 lit_state_2;
+ UInt32 lit_state_3;
+
+ UInt32 numMatches;
+ UInt32 lmdPayloadSize;
+ Int32 lmd_bits;
+
+ CFseState l_state;
+ CFseState m_state;
+ CFseState d_state;
+
+ UInt16 freqs[NUM_SYMBOLS];
+
+ if (version == kSignature_LZFSE_V1)
+ {
+ return E_NOTIMPL;
+ // we need examples to test LZFSE-V1 code
+ /*
+ const unsigned k_v1_SubHeaderSize = 7 * 4 + 7 * 2;
+ const unsigned k_v1_HeaderSize = k_v1_SubHeaderSize + NUM_SYMBOLS * 2;
+ _buffer.AllocAtLeast(k_v1_HeaderSize);
+ if (m_InStream.ReadBytes(_buffer, k_v1_HeaderSize) != k_v1_HeaderSize)
+ return S_FALSE;
+
+ const Byte *buf = _buffer;
+ #define GET_32(offs, dest) dest = GetUi32(buf + offs)
+ #define GET_16(offs, dest) dest = GetUi16(buf + offs)
+
+ UInt32 payload_bytes;
+ GET_32(0, payload_bytes);
+ GET_32(4, numLiterals);
+ GET_32(8, numMatches);
+ GET_32(12, litPayloadSize);
+ GET_32(16, lmdPayloadSize);
+ if (litPayloadSize > (1 << 20) || lmdPayloadSize > (1 << 20))
+ return S_FALSE;
+ GET_32(20, literal_bits);
+ if (literal_bits < -7 || literal_bits > 0)
+ return S_FALSE;
+
+ GET_16(24, lit_state_0);
+ GET_16(26, lit_state_1);
+ GET_16(28, lit_state_2);
+ GET_16(30, lit_state_3);
+
+ GET_32(32, lmd_bits);
+ if (lmd_bits < -7 || lmd_bits > 0)
+ return S_FALSE;
+
+ GET_16(36, l_state);
+ GET_16(38, m_state);
+ GET_16(40, d_state);
+
+ for (unsigned i = 0; i < NUM_SYMBOLS; i++)
+ freqs[i] = GetUi16(buf + k_v1_SubHeaderSize + i * 2);
+ */
+ }
+ else
+ {
+ UInt32 headerSize;
+ {
+ const unsigned kPreHeaderSize = 4 * 2; // signature and upackSize
+ const unsigned kHeaderSize = 8 * 3;
+ Byte temp[kHeaderSize];
+ if (m_InStream.ReadBytes(temp, kHeaderSize) != kHeaderSize)
+ return S_FALSE;
+
+ UInt64 v;
+
+ v = GetUi64(temp);
+ GET_BITS_64(v, 0, 20, numLiterals)
+ GET_BITS_64(v, 20, 20, litPayloadSize)
+ GET_BITS_64(v, 40, 20, numMatches)
+ GET_BITS_64_Int32(v, 60, 3 + 1, literal_bits) // (NumberOfUsedBits - 1)
+ literal_bits -= 7; // (-NumberOfUnusedBits)
+ if (literal_bits > 0)
+ return S_FALSE;
+ // GET_BITS_64(v, 63, 1, unused);
+
+ v = GetUi64(temp + 8);
+ GET_BITS_64(v, 0, 10, lit_state_0)
+ GET_BITS_64(v, 10, 10, lit_state_1)
+ GET_BITS_64(v, 20, 10, lit_state_2)
+ GET_BITS_64(v, 30, 10, lit_state_3)
+ GET_BITS_64(v, 40, 20, lmdPayloadSize)
+ GET_BITS_64_Int32(v, 60, 3 + 1, lmd_bits)
+ lmd_bits -= 7;
+ if (lmd_bits > 0)
+ return S_FALSE;
+ // GET_BITS_64(v, 63, 1, unused)
+
+ UInt32 v32 = GetUi32(temp + 20);
+ // (total header size in bytes; this does not
+ // correspond to a field in the uncompressed header version,
+ // but is required; we wouldn't know the size of the
+ // compresssed header otherwise.
+ GET_BITS_32(v32, 0, 10, l_state)
+ GET_BITS_32(v32, 10, 10, m_state)
+ GET_BITS_32(v32, 20, 10 + 2, d_state)
+ // GET_BITS_64(v, 62, 2, unused)
+
+ headerSize = GetUi32(temp + 16);
+ if (headerSize <= kPreHeaderSize + kHeaderSize)
+ return S_FALSE;
+ headerSize -= kPreHeaderSize + kHeaderSize;
+ }
+
+ // no freqs case is not allowed ?
+ // memset(freqs, 0, sizeof(freqs));
+ // if (headerSize != 0)
+ {
+ static const Byte numBitsTable[32] =
+ {
+ 2, 3, 2, 5, 2, 3, 2, 8, 2, 3, 2, 5, 2, 3, 2, 14,
+ 2, 3, 2, 5, 2, 3, 2, 8, 2, 3, 2, 5, 2, 3, 2, 14
+ };
+
+ static const Byte valueTable[32] =
+ {
+ 0, 2, 1, 4, 0, 3, 1, 8, 0, 2, 1, 5, 0, 3, 1, 24,
+ 0, 2, 1, 6, 0, 3, 1, 8, 0, 2, 1, 7, 0, 3, 1, 24
+ };
+
+ UInt32 accum = 0;
+ unsigned numBits = 0;
+
+ for (unsigned i = 0; i < NUM_SYMBOLS; i++)
+ {
+ while (numBits <= 14 && headerSize != 0)
+ {
+ Byte b;
+ if (!m_InStream.ReadByte(b))
+ return S_FALSE;
+ accum |= (UInt32)b << numBits;
+ numBits += 8;
+ headerSize--;
+ }
+
+ unsigned b = (unsigned)accum & 31;
+ unsigned n = numBitsTable[b];
+ if (numBits < n)
+ return S_FALSE;
+ numBits -= n;
+ UInt32 f = valueTable[b];
+ if (n >= 8)
+ f += ((accum >> 4) & (0x3ff >> (14 - n)));
+ accum >>= n;
+ freqs[i] = (UInt16)f;
+ }
+
+ if (numBits >= 8 || headerSize != 0)
+ return S_FALSE;
+ }
+ }
+
+ PRF(printf(" Literals=%6u Matches=%6u", numLiterals, numMatches));
+
+ if (numLiterals > LITERALS_PER_BLOCK
+ || (numLiterals & 3) != 0
+ || numMatches > MATCHES_PER_BLOCK
+ || lit_state_0 >= NUM_LIT_STATES
+ || lit_state_1 >= NUM_LIT_STATES
+ || lit_state_2 >= NUM_LIT_STATES
+ || lit_state_3 >= NUM_LIT_STATES
+ || l_state >= NUM_L_STATES
+ || m_state >= NUM_M_STATES
+ || d_state >= NUM_D_STATES)
+ return S_FALSE;
+
+ // only full table is allowed ?
+ if ( SumFreqs(freqs_L, NUM_L_SYMBOLS) != NUM_L_STATES
+ || SumFreqs(freqs_M, NUM_M_SYMBOLS) != NUM_M_STATES
+ || SumFreqs(freqs_D, NUM_D_SYMBOLS) != NUM_D_STATES
+ || SumFreqs(freqs_LIT, NUM_LIT_SYMBOLS) != NUM_LIT_STATES)
+ return S_FALSE;
+
+
+ const unsigned kPad = 16;
+
+ // ---------- Decode literals ----------
+
+ {
+ _literals.AllocAtLeast(LITERALS_PER_BLOCK + 16);
+ _buffer.AllocAtLeast(kPad + litPayloadSize);
+ memset(_buffer, 0, kPad);
+
+ if (m_InStream.ReadBytes(_buffer + kPad, litPayloadSize) != litPayloadSize)
+ return S_FALSE;
+
+ UInt32 lit_decoder[NUM_LIT_STATES];
+ InitLitTable(freqs_LIT, lit_decoder);
+
+ const Byte *buf_start = _buffer + kPad;
+ const Byte *buf_check = buf_start - 4;
+ const Byte *buf = buf_start + litPayloadSize;
+ CBitStream in;
+ if (FseInStream_Init(&in, literal_bits, &buf) != 0)
+ return S_FALSE;
+
+ Byte *lit = _literals;
+ const Byte *lit_limit = lit + numLiterals;
+ for (; lit < lit_limit; lit += 4)
+ {
+ FseInStream_FLUSH
+ DECODE_LIT (lit[0], lit_state_0)
+ DECODE_LIT (lit[1], lit_state_1)
+ FseInStream_FLUSH
+ DECODE_LIT (lit[2], lit_state_2)
+ DECODE_LIT (lit[3], lit_state_3)
+ }
+
+ if ((buf_start - buf) * 8 != (int)in.numBits)
+ return S_FALSE;
+ }
+
+
+ // ---------- Decode LMD ----------
+
+ _buffer.AllocAtLeast(kPad + lmdPayloadSize);
+ memset(_buffer, 0, kPad);
+ if (m_InStream.ReadBytes(_buffer + kPad, lmdPayloadSize) != lmdPayloadSize)
+ return S_FALSE;
+
+ CExtraEntry l_decoder[NUM_L_STATES];
+ CExtraEntry m_decoder[NUM_M_STATES];
+ CExtraEntry d_decoder[NUM_D_STATES];
+
+ InitExtraDecoderTable(NUM_L_STATES, NUM_L_SYMBOLS, freqs_L, k_L_extra, l_decoder);
+ InitExtraDecoderTable(NUM_M_STATES, NUM_M_SYMBOLS, freqs_M, k_M_extra, m_decoder);
+ InitExtraDecoderTable(NUM_D_STATES, NUM_D_SYMBOLS, freqs_D, k_D_extra, d_decoder);
+
+ const Byte *buf_start = _buffer + kPad;
+ const Byte *buf_check = buf_start - 4;
+ const Byte *buf = buf_start + lmdPayloadSize;
+ CBitStream in;
+ if (FseInStream_Init(&in, lmd_bits, &buf))
+ return S_FALSE;
+
+ const Byte *lit = _literals;
+ const Byte *lit_limit = lit + numLiterals;
+
+ UInt32 D = 0;
+
+ for (;;)
+ {
+ if (numMatches == 0)
+ break;
+ numMatches--;
+
+ FseInStream_FLUSH
+
+ unsigned L = (unsigned)FseDecodeExtra(&l_state, l_decoder, &in);
+
+ FseInStream_FLUSH
+
+ unsigned M = (unsigned)FseDecodeExtra(&m_state, m_decoder, &in);
+
+ FseInStream_FLUSH
+
+ {
+ UInt32 new_D = FseDecodeExtra(&d_state, d_decoder, &in);
+ if (new_D)
+ D = new_D;
+ }
+
+ if (L != 0)
+ {
+ if (L > (size_t)(lit_limit - lit))
+ return S_FALSE;
+ unsigned cur = L;
+ if (cur > unpackSize)
+ cur = (unsigned)unpackSize;
+ m_OutWindowStream.PutBytes(lit, cur);
+ unpackSize -= cur;
+ lit += cur;
+ if (cur != L)
+ return S_FALSE;
+ }
+
+ if (M != 0)
+ {
+ if (unpackSize == 0 || D == 0)
+ return S_FALSE;
+ unsigned cur = M;
+ if (cur > unpackSize)
+ cur = (unsigned)unpackSize;
+ if (!m_OutWindowStream.CopyBlock(D - 1, cur))
+ return S_FALSE;
+ unpackSize -= cur;
+ if (cur != M)
+ return S_FALSE;
+ }
+ }
+
+ if (unpackSize != 0)
+ return S_FALSE;
+
+ // LZFSE encoder writes 8 additional zero bytes before LMD payload
+ // We test it:
+ if ((size_t)(buf - buf_start) * 8 + in.numBits != 64)
+ return S_FALSE;
+ if (GetUi64(buf_start) != 0)
+ return S_FALSE;
+
+ return S_OK;
+}
+
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ PRF(printf("\n\nLzfseDecoder %7u %7u\n", (unsigned)*outSize, (unsigned)*inSize));
+
+ const UInt32 kLzfseDictSize = 1 << 18;
+ if (!m_OutWindowStream.Create(kLzfseDictSize))
+ return E_OUTOFMEMORY;
+ if (!m_InStream.Create(1 << 18))
+ return E_OUTOFMEMORY;
+
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(false);
+ m_InStream.SetStream(inStream);
+ m_InStream.Init();
+
+ CCoderReleaser coderReleaser(this);
+
+ UInt64 prevOut = 0;
+ UInt64 prevIn = 0;
+
+ if (LzvnMode)
+ {
+ if (!outSize || !inSize)
+ return E_NOTIMPL;
+ const UInt64 unpackSize = *outSize;
+ const UInt64 packSize = *inSize;
+ if (unpackSize > (UInt32)(Int32)-1
+ || packSize > (UInt32)(Int32)-1)
+ return S_FALSE;
+ RINOK(DecodeLzvn((UInt32)unpackSize, (UInt32)packSize))
+ }
+ else
+ for (;;)
+ {
+ const UInt64 pos = m_OutWindowStream.GetProcessedSize();
+ const UInt64 packPos = m_InStream.GetProcessedSize();
+
+ if (progress && ((pos - prevOut) >= (1 << 22) || (packPos - prevIn) >= (1 << 22)))
+ {
+ RINOK(progress->SetRatioInfo(&packPos, &pos))
+ prevIn = packPos;
+ prevOut = pos;
+ }
+
+ UInt32 v;
+ RINOK(GetUInt32(v))
+ if ((v & 0xFFFFFF) != 0x787662) // bvx
+ return S_FALSE;
+ v >>= 24;
+
+ if (v == 0x24) // '$', end of stream
+ break;
+
+ UInt32 unpackSize;
+ RINOK(GetUInt32(unpackSize))
+
+ UInt32 cur = unpackSize;
+ if (outSize)
+ {
+ const UInt64 rem = *outSize - pos;
+ if (cur > rem)
+ cur = (UInt32)rem;
+ }
+ unpackSize -= cur;
+
+ HRESULT res;
+ if (v == kSignature_LZFSE_V1 || v == kSignature_LZFSE_V2)
+ res = DecodeLzfse(cur, (Byte)v);
+ else if (v == 0x6E) // 'n'
+ {
+ UInt32 packSize;
+ res = GetUInt32(packSize);
+ if (res == S_OK)
+ res = DecodeLzvn(cur, packSize);
+ }
+ else if (v == 0x2D) // '-'
+ res = DecodeUncompressed(cur);
+ else
+ return E_NOTIMPL;
+
+ if (res != S_OK)
+ return res;
+
+ if (unpackSize != 0)
+ return S_FALSE;
+ }
+
+ coderReleaser.NeedFlush = false;
+ HRESULT res = m_OutWindowStream.Flush();
+ if (res == S_OK)
+ if ((inSize && *inSize != m_InStream.GetProcessedSize())
+ || (outSize && *outSize != m_OutWindowStream.GetProcessedSize()))
+ res = S_FALSE;
+ return res;
+}
+
+
+Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return E_OUTOFMEMORY; }
+ // catch(...) { return S_FALSE; }
+}
+
+}}
diff --git a/CPP/7zip/Compress/LzfseDecoder.h b/CPP/7zip/Compress/LzfseDecoder.h
new file mode 100644
index 0000000..b7227dc
--- /dev/null
+++ b/CPP/7zip/Compress/LzfseDecoder.h
@@ -0,0 +1,63 @@
+// LzfseDecoder.h
+
+#ifndef ZIP7_INC_LZFSE_DECODER_H
+#define ZIP7_INC_LZFSE_DECODER_H
+
+#include "../../Common/MyBuffer.h"
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NLzfse {
+
+Z7_CLASS_IMP_NOQIB_1(
+ CDecoder
+ , ICompressCoder
+)
+ CLzOutWindow m_OutWindowStream;
+ CInBuffer m_InStream;
+ CByteBuffer _literals;
+ CByteBuffer _buffer;
+
+ class CCoderReleaser
+ {
+ CDecoder *m_Coder;
+ public:
+ bool NeedFlush;
+ CCoderReleaser(CDecoder *coder): m_Coder(coder), NeedFlush(true) {}
+ ~CCoderReleaser()
+ {
+ if (NeedFlush)
+ m_Coder->m_OutWindowStream.Flush();
+ }
+ };
+ friend class CCoderReleaser;
+
+ HRESULT GetUInt32(UInt32 &val);
+
+ HRESULT DecodeUncompressed(UInt32 unpackSize);
+ HRESULT DecodeLzvn(UInt32 unpackSize, UInt32 packSize);
+ HRESULT DecodeLzfse(UInt32 unpackSize, Byte version);
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+public:
+ bool LzvnMode;
+
+ CDecoder():
+ LzvnMode(false)
+ {}
+
+ // sizes are checked in Code()
+ // UInt64 GetInputProcessedSize() const { return m_InStream.GetProcessedSize(); }
+ // UInt64 GetOutputProcessedSize() const { return m_OutWindowStream.GetProcessedSize(); }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/LzhDecoder.cpp b/CPP/7zip/Compress/LzhDecoder.cpp
new file mode 100644
index 0000000..064bc55
--- /dev/null
+++ b/CPP/7zip/Compress/LzhDecoder.cpp
@@ -0,0 +1,252 @@
+// LzhDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "LzhDecoder.h"
+
+namespace NCompress{
+namespace NLzh {
+namespace NDecoder {
+
+static const UInt32 kWindowSizeMin = 1 << 16;
+
+static bool CheckCodeLens(const Byte *lens, unsigned num)
+{
+ UInt32 sum = 0;
+ for (unsigned i = 0; i < num; i++)
+ {
+ const unsigned len = lens[i];
+ if (len != 0)
+ sum += ((UInt32)1 << (NUM_CODE_BITS - len));
+ }
+ return sum == ((UInt32)1 << NUM_CODE_BITS);
+}
+
+bool CCoder::ReadTP(unsigned num, unsigned numBits, int spec)
+{
+ _symbolT = -1;
+
+ const UInt32 n = _inBitStream.ReadBits(numBits);
+ if (n == 0)
+ {
+ const unsigned s = _inBitStream.ReadBits(numBits);
+ _symbolT = (int)s;
+ return (s < num);
+ }
+
+ if (n > num)
+ return false;
+
+ {
+ Byte lens[NPT];
+ unsigned i;
+ for (i = 0; i < NPT; i++)
+ lens[i] = 0;
+
+ i = 0;
+
+ do
+ {
+ const UInt32 val = _inBitStream.GetValue(16);
+ unsigned c = val >> 13;
+
+ if (c == 7)
+ {
+ UInt32 mask = 1 << 12;
+ while (mask & val)
+ {
+ mask >>= 1;
+ c++;
+ }
+ if (c > 16)
+ return false;
+ }
+
+ _inBitStream.MovePos(c < 7 ? 3 : c - 3);
+ lens[i++] = (Byte)c;
+
+ if (i == (unsigned)spec)
+ i += _inBitStream.ReadBits(2);
+ }
+ while (i < n);
+
+ if (!CheckCodeLens(lens, NPT))
+ return false;
+ return _decoderT.Build(lens);
+ }
+}
+
+static const unsigned NUM_C_BITS = 9;
+
+bool CCoder::ReadC()
+{
+ _symbolC = -1;
+
+ unsigned n = _inBitStream.ReadBits(NUM_C_BITS);
+
+ if (n == 0)
+ {
+ const unsigned s = _inBitStream.ReadBits(NUM_C_BITS);
+ _symbolC = (int)s;
+ return (s < NC);
+ }
+
+ if (n > NC)
+ return false;
+
+ {
+ Byte lens[NC];
+
+ unsigned i = 0;
+
+ do
+ {
+ UInt32 c = (unsigned)_symbolT;
+ if (_symbolT < 0)
+ c = _decoderT.Decode(&_inBitStream);
+
+ if (c <= 2)
+ {
+ if (c == 0)
+ c = 1;
+ else if (c == 1)
+ c = _inBitStream.ReadBits(4) + 3;
+ else
+ c = _inBitStream.ReadBits(NUM_C_BITS) + 20;
+
+ if (i + c > n)
+ return false;
+
+ do
+ lens[i++] = 0;
+ while (--c);
+ }
+ else
+ lens[i++] = (Byte)(c - 2);
+ }
+ while (i < n);
+
+ while (i < NC)
+ lens[i++] = 0;
+
+ if (!CheckCodeLens(lens, NC))
+ return false;
+ return _decoderC.Build(lens);
+ }
+}
+
+HRESULT CCoder::CodeReal(UInt64 rem, ICompressProgressInfo *progress)
+{
+ const unsigned pbit = (DictSize <= (1 << 14) ? 4 : 5);
+
+ UInt32 blockSize = 0;
+
+ while (rem != 0)
+ {
+ if (blockSize == 0)
+ {
+ if (_inBitStream.ExtraBitsWereRead())
+ return S_FALSE;
+
+ if (progress)
+ {
+ const UInt64 packSize = _inBitStream.GetProcessedSize();
+ const UInt64 pos = _outWindow.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &pos))
+ }
+
+ blockSize = _inBitStream.ReadBits(16);
+ if (blockSize == 0)
+ return S_FALSE;
+
+ if (!ReadTP(NT, 5, 3))
+ return S_FALSE;
+ if (!ReadC())
+ return S_FALSE;
+ if (!ReadTP(NP, pbit, -1))
+ return S_FALSE;
+ }
+
+ blockSize--;
+
+ UInt32 number = (unsigned)_symbolC;
+ if (_symbolC < 0)
+ number = _decoderC.Decode(&_inBitStream);
+
+ if (number < 256)
+ {
+ _outWindow.PutByte((Byte)number);
+ rem--;
+ }
+ else
+ {
+ UInt32 len = number - 256 + kMatchMinLen;
+
+ UInt32 dist = (unsigned)_symbolT;
+ if (_symbolT < 0)
+ dist = _decoderT.Decode(&_inBitStream);
+
+ if (dist > 1)
+ {
+ dist--;
+ dist = ((UInt32)1 << dist) + _inBitStream.ReadBits((unsigned)dist);
+ }
+
+ if (dist >= DictSize)
+ return S_FALSE;
+
+ if (len > rem)
+ len = (UInt32)rem;
+
+ if (!_outWindow.CopyBlock(dist, len))
+ return S_FALSE;
+ rem -= len;
+ }
+ }
+
+ if (FinishMode)
+ {
+ if (blockSize != 0)
+ return S_FALSE;
+ if (_inBitStream.ReadAlignBits() != 0)
+ return S_FALSE;
+ }
+
+ if (_inBitStream.ExtraBitsWereRead())
+ return S_FALSE;
+
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CCoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ try
+ {
+ if (!outSize)
+ return E_INVALIDARG;
+
+ if (!_outWindow.Create(DictSize > kWindowSizeMin ? DictSize : kWindowSizeMin))
+ return E_OUTOFMEMORY;
+ if (!_inBitStream.Create(1 << 17))
+ return E_OUTOFMEMORY;
+
+ _outWindow.SetStream(outStream);
+ _outWindow.Init(false);
+ _inBitStream.SetStream(inStream);
+ _inBitStream.Init();
+
+ CCoderReleaser coderReleaser(this);
+
+ RINOK(CodeReal(*outSize, progress))
+
+ coderReleaser.Disable();
+ return _outWindow.Flush();
+ }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+}}}
diff --git a/CPP/7zip/Compress/LzhDecoder.h b/CPP/7zip/Compress/LzhDecoder.h
new file mode 100644
index 0000000..491212e
--- /dev/null
+++ b/CPP/7zip/Compress/LzhDecoder.h
@@ -0,0 +1,69 @@
+// LzhDecoder.h
+
+#ifndef ZIP7_INC_COMPRESS_LZH_DECODER_H
+#define ZIP7_INC_COMPRESS_LZH_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitmDecoder.h"
+#include "HuffmanDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NLzh {
+namespace NDecoder {
+
+const unsigned kMatchMinLen = 3;
+const unsigned kMatchMaxLen = 256;
+const unsigned NC = (256 + kMatchMaxLen - kMatchMinLen + 1);
+const unsigned NUM_CODE_BITS = 16;
+const unsigned NUM_DIC_BITS_MAX = 25;
+const unsigned NT = (NUM_CODE_BITS + 3);
+const unsigned NP = (NUM_DIC_BITS_MAX + 1);
+const unsigned NPT = NP; // Max(NT, NP)
+
+Z7_CLASS_IMP_NOQIB_1(
+ CCoder
+ , ICompressCoder
+)
+ CLzOutWindow _outWindow;
+ NBitm::CDecoder<CInBuffer> _inBitStream;
+
+ int _symbolT;
+ int _symbolC;
+
+ NHuffman::CDecoder<NUM_CODE_BITS, NPT> _decoderT;
+ NHuffman::CDecoder<NUM_CODE_BITS, NC> _decoderC;
+
+ class CCoderReleaser
+ {
+ CCoder *_coder;
+ public:
+ CCoderReleaser(CCoder *coder): _coder(coder) {}
+ void Disable() { _coder = NULL; }
+ ~CCoderReleaser() { if (_coder) _coder->_outWindow.Flush(); }
+ };
+ friend class CCoderReleaser;
+
+ bool ReadTP(unsigned num, unsigned numBits, int spec);
+ bool ReadC();
+
+ HRESULT CodeReal(UInt64 outSize, ICompressProgressInfo *progress);
+public:
+ UInt32 DictSize;
+ bool FinishMode;
+
+ void SetDictSize(unsigned dictSize) { DictSize = dictSize; }
+
+ CCoder(): DictSize(1 << 16), FinishMode(false) {}
+
+ UInt64 GetInputProcessedSize() const { return _inBitStream.GetProcessedSize(); }
+};
+
+}}}
+
+#endif
diff --git a/CPP/7zip/Compress/Lzma2Decoder.cpp b/CPP/7zip/Compress/Lzma2Decoder.cpp
index bb631c5..eab7800 100644
--- a/CPP/7zip/Compress/Lzma2Decoder.cpp
+++ b/CPP/7zip/Compress/Lzma2Decoder.cpp
@@ -1,265 +1,267 @@
-// Lzma2Decoder.cpp
-
-#include "StdAfx.h"
-
-// #include <stdio.h>
-
-#include "../../../C/Alloc.h"
-// #include "../../../C/CpuTicks.h"
-
-#include "../Common/StreamUtils.h"
-
-#include "Lzma2Decoder.h"
-
-namespace NCompress {
-namespace NLzma2 {
-
-CDecoder::CDecoder():
- _dec(NULL)
- , _inProcessed(0)
- , _prop(0xFF)
- , _finishMode(false)
- , _inBufSize(1 << 20)
- , _outStep(1 << 20)
- #ifndef _7ZIP_ST
- , _tryMt(1)
- , _numThreads(1)
- , _memUsage((UInt64)(sizeof(size_t)) << 28)
- #endif
-{}
-
-CDecoder::~CDecoder()
-{
- if (_dec)
- Lzma2DecMt_Destroy(_dec);
-}
-
-STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSize = size; return S_OK; }
-STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outStep = size; return S_OK; }
-
-STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
-{
- if (size != 1)
- return E_NOTIMPL;
- if (prop[0] > 40)
- return E_NOTIMPL;
- _prop = prop[0];
- return S_OK;
-}
-
-
-STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
-{
- _finishMode = (finishMode != 0);
- return S_OK;
-}
-
-
-
-#ifndef _7ZIP_ST
-
-static UInt64 Get_ExpectedBlockSize_From_Dict(UInt32 dictSize)
-{
- const UInt32 kMinSize = (UInt32)1 << 20;
- const UInt32 kMaxSize = (UInt32)1 << 28;
- UInt64 blockSize = (UInt64)dictSize << 2;
- if (blockSize < kMinSize) blockSize = kMinSize;
- if (blockSize > kMaxSize) blockSize = kMaxSize;
- if (blockSize < dictSize) blockSize = dictSize;
- blockSize += (kMinSize - 1);
- blockSize &= ~(UInt64)(kMinSize - 1);
- return blockSize;
-}
-
-#define LZMA2_DIC_SIZE_FROM_PROP_FULL(p) ((p) == 40 ? 0xFFFFFFFF : (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)))
-
-#endif
-
-#define RET_IF_WRAP_ERROR_CONFIRMED(wrapRes, sRes, sResErrorCode) \
- if (wrapRes != S_OK && sRes == sResErrorCode) return wrapRes;
-
-#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
- if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
-
-STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
-{
- _inProcessed = 0;
-
- if (!_dec)
- {
- _dec = Lzma2DecMt_Create(
- // &g_AlignedAlloc,
- &g_Alloc,
- &g_MidAlloc);
- if (!_dec)
- return E_OUTOFMEMORY;
- }
-
- CLzma2DecMtProps props;
- Lzma2DecMtProps_Init(&props);
-
- props.inBufSize_ST = _inBufSize;
- props.outStep_ST = _outStep;
-
- #ifndef _7ZIP_ST
- {
- props.numThreads = 1;
- UInt32 numThreads = _numThreads;
-
- if (_tryMt && numThreads >= 1)
- {
- UInt64 useLimit = _memUsage;
- UInt32 dictSize = LZMA2_DIC_SIZE_FROM_PROP_FULL(_prop);
- UInt64 expectedBlockSize64 = Get_ExpectedBlockSize_From_Dict(dictSize);
- size_t expectedBlockSize = (size_t)expectedBlockSize64;
- size_t inBlockMax = expectedBlockSize + expectedBlockSize / 16;
- if (expectedBlockSize == expectedBlockSize64 && inBlockMax >= expectedBlockSize)
- {
- props.outBlockMax = expectedBlockSize;
- props.inBlockMax = inBlockMax;
- const size_t kOverheadSize = props.inBufSize_MT + (1 << 16);
- UInt64 okThreads = useLimit / (props.outBlockMax + props.inBlockMax + kOverheadSize);
- if (numThreads > okThreads)
- numThreads = (UInt32)okThreads;
- if (numThreads == 0)
- numThreads = 1;
- props.numThreads = numThreads;
- }
- }
- }
- #endif
-
- CSeqInStreamWrap inWrap;
- CSeqOutStreamWrap outWrap;
- CCompressProgressWrap progressWrap;
-
- inWrap.Init(inStream);
- outWrap.Init(outStream);
- progressWrap.Init(progress);
-
- SRes res;
-
- UInt64 inProcessed = 0;
- int isMT = False;
-
- #ifndef _7ZIP_ST
- isMT = _tryMt;
- #endif
-
- // UInt64 cpuTicks = GetCpuTicks();
-
- res = Lzma2DecMt_Decode(_dec, _prop, &props,
- &outWrap.vt, outSize, _finishMode,
- &inWrap.vt,
- &inProcessed,
- &isMT,
- progress ? &progressWrap.vt : NULL);
-
- /*
- cpuTicks = GetCpuTicks() - cpuTicks;
- printf("\n ticks = %10I64u\n", cpuTicks / 1000000);
- */
-
-
- #ifndef _7ZIP_ST
- /* we reset _tryMt, only if p->props.numThreads was changed */
- if (props.numThreads > 1)
- _tryMt = isMT;
- #endif
-
- _inProcessed = inProcessed;
-
- RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
- RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
- RET_IF_WRAP_ERROR_CONFIRMED(inWrap.Res, res, SZ_ERROR_READ)
-
- if (res == SZ_OK && _finishMode)
- {
- if (inSize && *inSize != inProcessed)
- res = SZ_ERROR_DATA;
- if (outSize && *outSize != outWrap.Processed)
- res = SZ_ERROR_DATA;
- }
-
- return SResToHRESULT(res);
-}
-
-
-STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
-{
- *value = _inProcessed;
- return S_OK;
-}
-
-
-#ifndef _7ZIP_ST
-
-STDMETHODIMP CDecoder::SetNumberOfThreads(UInt32 numThreads)
-{
- _numThreads = numThreads;
- return S_OK;
-}
-
-STDMETHODIMP CDecoder::SetMemLimit(UInt64 memUsage)
-{
- _memUsage = memUsage;
- return S_OK;
-}
-
-#endif
-
-
-#ifndef NO_READ_FROM_CODER
-
-STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
-{
- CLzma2DecMtProps props;
- Lzma2DecMtProps_Init(&props);
- props.inBufSize_ST = _inBufSize;
- props.outStep_ST = _outStep;
-
- _inProcessed = 0;
-
- if (!_dec)
- {
- _dec = Lzma2DecMt_Create(&g_AlignedAlloc, &g_MidAlloc);
- if (!_dec)
- return E_OUTOFMEMORY;
- }
-
- _inWrap.Init(_inStream);
-
- SRes res = Lzma2DecMt_Init(_dec, _prop, &props, outSize, _finishMode, &_inWrap.vt);
-
- if (res != SZ_OK)
- return SResToHRESULT(res);
- return S_OK;
-}
-
-
-STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }
-STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }
-
-
-STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
-
- size_t size2 = size;
- UInt64 inProcessed = 0;
-
- SRes res = Lzma2DecMt_Read(_dec, (Byte *)data, &size2, &inProcessed);
-
- _inProcessed += inProcessed;
- if (processedSize)
- *processedSize = (UInt32)size2;
- if (res != SZ_OK)
- return SResToHRESULT(res);
- return S_OK;
-}
-
-#endif
-
-}}
+// Lzma2Decoder.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../C/Alloc.h"
+// #include "../../../C/CpuTicks.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "Lzma2Decoder.h"
+
+namespace NCompress {
+namespace NLzma2 {
+
+CDecoder::CDecoder():
+ _dec(NULL)
+ , _inProcessed(0)
+ , _prop(0xFF)
+ , _finishMode(false)
+ , _inBufSize(1 << 20)
+ , _outStep(1 << 20)
+ #ifndef Z7_ST
+ , _tryMt(1)
+ , _numThreads(1)
+ , _memUsage((UInt64)(sizeof(size_t)) << 28)
+ #endif
+{}
+
+CDecoder::~CDecoder()
+{
+ if (_dec)
+ Lzma2DecMt_Destroy(_dec);
+}
+
+Z7_COM7F_IMF(CDecoder::SetInBufSize(UInt32 , UInt32 size)) { _inBufSize = size; return S_OK; }
+Z7_COM7F_IMF(CDecoder::SetOutBufSize(UInt32 , UInt32 size)) { _outStep = size; return S_OK; }
+
+Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size))
+{
+ if (size != 1)
+ return E_NOTIMPL;
+ if (prop[0] > 40)
+ return E_NOTIMPL;
+ _prop = prop[0];
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
+{
+ _finishMode = (finishMode != 0);
+ return S_OK;
+}
+
+
+
+#ifndef Z7_ST
+
+static UInt64 Get_ExpectedBlockSize_From_Dict(UInt32 dictSize)
+{
+ const UInt32 kMinSize = (UInt32)1 << 20;
+ const UInt32 kMaxSize = (UInt32)1 << 28;
+ UInt64 blockSize = (UInt64)dictSize << 2;
+ if (blockSize < kMinSize) blockSize = kMinSize;
+ if (blockSize > kMaxSize) blockSize = kMaxSize;
+ if (blockSize < dictSize) blockSize = dictSize;
+ blockSize += (kMinSize - 1);
+ blockSize &= ~(UInt64)(kMinSize - 1);
+ return blockSize;
+}
+
+#define LZMA2_DIC_SIZE_FROM_PROP_FULL(p) ((p) == 40 ? 0xFFFFFFFF : (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11)))
+
+#endif
+
+#define RET_IF_WRAP_ERROR_CONFIRMED(wrapRes, sRes, sResErrorCode) \
+ if (wrapRes != S_OK && sRes == sResErrorCode) return wrapRes;
+
+#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
+ if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
+
+Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ _inProcessed = 0;
+
+ if (!_dec)
+ {
+ _dec = Lzma2DecMt_Create(
+ // &g_AlignedAlloc,
+ &g_Alloc,
+ &g_MidAlloc);
+ if (!_dec)
+ return E_OUTOFMEMORY;
+ }
+
+ CLzma2DecMtProps props;
+ Lzma2DecMtProps_Init(&props);
+
+ props.inBufSize_ST = _inBufSize;
+ props.outStep_ST = _outStep;
+
+ #ifndef Z7_ST
+ {
+ props.numThreads = 1;
+ UInt32 numThreads = _numThreads;
+
+ if (_tryMt && numThreads >= 1)
+ {
+ const UInt64 useLimit = _memUsage;
+ const UInt32 dictSize = LZMA2_DIC_SIZE_FROM_PROP_FULL(_prop);
+ const UInt64 expectedBlockSize64 = Get_ExpectedBlockSize_From_Dict(dictSize);
+ const size_t expectedBlockSize = (size_t)expectedBlockSize64;
+ const size_t inBlockMax = expectedBlockSize + expectedBlockSize / 16;
+ if (expectedBlockSize == expectedBlockSize64 && inBlockMax >= expectedBlockSize)
+ {
+ props.outBlockMax = expectedBlockSize;
+ props.inBlockMax = inBlockMax;
+ const size_t kOverheadSize = props.inBufSize_MT + (1 << 16);
+ const UInt64 okThreads = useLimit / (props.outBlockMax + props.inBlockMax + kOverheadSize);
+ if (numThreads > okThreads)
+ numThreads = (UInt32)okThreads;
+ if (numThreads == 0)
+ numThreads = 1;
+ props.numThreads = numThreads;
+ }
+ }
+ }
+ #endif
+
+ CSeqInStreamWrap inWrap;
+ CSeqOutStreamWrap outWrap;
+ CCompressProgressWrap progressWrap;
+
+ inWrap.Init(inStream);
+ outWrap.Init(outStream);
+ progressWrap.Init(progress);
+
+ SRes res;
+
+ UInt64 inProcessed = 0;
+ int isMT = False;
+
+ #ifndef Z7_ST
+ isMT = _tryMt;
+ #endif
+
+ // UInt64 cpuTicks = GetCpuTicks();
+
+ res = Lzma2DecMt_Decode(_dec, _prop, &props,
+ &outWrap.vt, outSize, _finishMode,
+ &inWrap.vt,
+ &inProcessed,
+ &isMT,
+ progress ? &progressWrap.vt : NULL);
+
+ /*
+ cpuTicks = GetCpuTicks() - cpuTicks;
+ printf("\n ticks = %10I64u\n", cpuTicks / 1000000);
+ */
+
+
+ #ifndef Z7_ST
+ /* we reset _tryMt, only if p->props.numThreads was changed */
+ if (props.numThreads > 1)
+ _tryMt = isMT;
+ #endif
+
+ _inProcessed = inProcessed;
+
+ RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
+ RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
+ RET_IF_WRAP_ERROR_CONFIRMED(inWrap.Res, res, SZ_ERROR_READ)
+
+ if (res == SZ_OK && _finishMode)
+ {
+ if (inSize && *inSize != inProcessed)
+ res = SZ_ERROR_DATA;
+ if (outSize && *outSize != outWrap.Processed)
+ res = SZ_ERROR_DATA;
+ }
+
+ return SResToHRESULT(res);
+}
+
+
+Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value))
+{
+ *value = _inProcessed;
+ return S_OK;
+}
+
+
+#ifndef Z7_ST
+
+Z7_COM7F_IMF(CDecoder::SetNumberOfThreads(UInt32 numThreads))
+{
+ _numThreads = numThreads;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CDecoder::SetMemLimit(UInt64 memUsage))
+{
+ _memUsage = memUsage;
+ return S_OK;
+}
+
+#endif
+
+
+#ifndef Z7_NO_READ_FROM_CODER
+
+Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize))
+{
+ CLzma2DecMtProps props;
+ Lzma2DecMtProps_Init(&props);
+ props.inBufSize_ST = _inBufSize;
+ props.outStep_ST = _outStep;
+
+ _inProcessed = 0;
+
+ if (!_dec)
+ {
+ _dec = Lzma2DecMt_Create(&g_AlignedAlloc, &g_MidAlloc);
+ if (!_dec)
+ return E_OUTOFMEMORY;
+ }
+
+ _inWrap.Init(_inStream);
+
+ const SRes res = Lzma2DecMt_Init(_dec, _prop, &props, outSize, _finishMode, &_inWrap.vt);
+
+ if (res != SZ_OK)
+ return SResToHRESULT(res);
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream))
+ { _inStream = inStream; return S_OK; }
+Z7_COM7F_IMF(CDecoder::ReleaseInStream())
+ { _inStream.Release(); return S_OK; }
+
+
+Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+
+ size_t size2 = size;
+ UInt64 inProcessed = 0;
+
+ const SRes res = Lzma2DecMt_Read(_dec, (Byte *)data, &size2, &inProcessed);
+
+ _inProcessed += inProcessed;
+ if (processedSize)
+ *processedSize = (UInt32)size2;
+ if (res != SZ_OK)
+ return SResToHRESULT(res);
+ return S_OK;
+}
+
+#endif
+
+}}
diff --git a/CPP/7zip/Compress/Lzma2Decoder.h b/CPP/7zip/Compress/Lzma2Decoder.h
index b56488e..7ca717e 100644
--- a/CPP/7zip/Compress/Lzma2Decoder.h
+++ b/CPP/7zip/Compress/Lzma2Decoder.h
@@ -1,96 +1,87 @@
-// Lzma2Decoder.h
-
-#ifndef __LZMA2_DECODER_H
-#define __LZMA2_DECODER_H
-
-#include "../../../C/Lzma2DecMt.h"
-
-#include "../Common/CWrappers.h"
-
-namespace NCompress {
-namespace NLzma2 {
-
-class CDecoder:
- public ICompressCoder,
- public ICompressSetDecoderProperties2,
- public ICompressSetFinishMode,
- public ICompressGetInStreamProcessedSize,
- public ICompressSetBufSize,
-
- #ifndef NO_READ_FROM_CODER
- public ICompressSetInStream,
- public ICompressSetOutStreamSize,
- public ISequentialInStream,
- #endif
-
- #ifndef _7ZIP_ST
- public ICompressSetCoderMt,
- public ICompressSetMemLimit,
- #endif
-
- public CMyUnknownImp
-{
- CLzma2DecMtHandle _dec;
- UInt64 _inProcessed;
- Byte _prop;
- int _finishMode;
- UInt32 _inBufSize;
- UInt32 _outStep;
-
-public:
- MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
- MY_QUERYINTERFACE_ENTRY(ICompressSetDecoderProperties2)
- MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)
- MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)
- MY_QUERYINTERFACE_ENTRY(ICompressSetBufSize)
-
- #ifndef NO_READ_FROM_CODER
- MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
- MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)
- MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
- #endif
-
- #ifndef _7ZIP_ST
- MY_QUERYINTERFACE_ENTRY(ICompressSetCoderMt)
- MY_QUERYINTERFACE_ENTRY(ICompressSetMemLimit)
- #endif
-
- MY_QUERYINTERFACE_END
- MY_ADDREF_RELEASE
-
- STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
- STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
- STDMETHOD(SetFinishMode)(UInt32 finishMode);
- STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
- STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);
- STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);
-
- #ifndef _7ZIP_ST
-private:
- int _tryMt;
- UInt32 _numThreads;
- UInt64 _memUsage;
-public:
- STDMETHOD(SetNumberOfThreads)(UInt32 numThreads);
- STDMETHOD(SetMemLimit)(UInt64 memUsage);
- #endif
-
- #ifndef NO_READ_FROM_CODER
-private:
- CMyComPtr<ISequentialInStream> _inStream;
- CSeqInStreamWrap _inWrap;
-public:
- STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
- STDMETHOD(SetInStream)(ISequentialInStream *inStream);
- STDMETHOD(ReleaseInStream)();
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- #endif
-
- CDecoder();
- virtual ~CDecoder();
-};
-
-}}
-
-#endif
+// Lzma2Decoder.h
+
+#ifndef ZIP7_INC_LZMA2_DECODER_H
+#define ZIP7_INC_LZMA2_DECODER_H
+
+#include "../../../C/Lzma2DecMt.h"
+
+#include "../Common/CWrappers.h"
+
+namespace NCompress {
+namespace NLzma2 {
+
+class CDecoder Z7_final:
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public ICompressSetFinishMode,
+ public ICompressGetInStreamProcessedSize,
+ public ICompressSetBufSize,
+ #ifndef Z7_NO_READ_FROM_CODER
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public ISequentialInStream,
+ #endif
+ #ifndef Z7_ST
+ public ICompressSetCoderMt,
+ public ICompressSetMemLimit,
+ #endif
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(ICompressCoder)
+ Z7_COM_QI_ENTRY(ICompressSetDecoderProperties2)
+ Z7_COM_QI_ENTRY(ICompressSetFinishMode)
+ Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize)
+ Z7_COM_QI_ENTRY(ICompressSetBufSize)
+ #ifndef Z7_NO_READ_FROM_CODER
+ Z7_COM_QI_ENTRY(ICompressSetInStream)
+ Z7_COM_QI_ENTRY(ICompressSetOutStreamSize)
+ Z7_COM_QI_ENTRY(ISequentialInStream)
+ #endif
+ #ifndef Z7_ST
+ Z7_COM_QI_ENTRY(ICompressSetCoderMt)
+ Z7_COM_QI_ENTRY(ICompressSetMemLimit)
+ #endif
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(ICompressCoder)
+ Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2)
+ Z7_IFACE_COM7_IMP(ICompressSetFinishMode)
+ Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize)
+ Z7_IFACE_COM7_IMP(ICompressSetBufSize)
+ #ifndef Z7_NO_READ_FROM_CODER
+ Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize)
+ Z7_IFACE_COM7_IMP(ICompressSetInStream)
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+ #endif
+ #ifndef Z7_ST
+ Z7_IFACE_COM7_IMP(ICompressSetCoderMt)
+ Z7_IFACE_COM7_IMP(ICompressSetMemLimit)
+ #endif
+
+ CLzma2DecMtHandle _dec;
+ UInt64 _inProcessed;
+ Byte _prop;
+ int _finishMode;
+ UInt32 _inBufSize;
+ UInt32 _outStep;
+
+ #ifndef Z7_ST
+ int _tryMt;
+ UInt32 _numThreads;
+ UInt64 _memUsage;
+ #endif
+
+ #ifndef Z7_NO_READ_FROM_CODER
+ CMyComPtr<ISequentialInStream> _inStream;
+ CSeqInStreamWrap _inWrap;
+ #endif
+
+public:
+ CDecoder();
+ ~CDecoder();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/Lzma2Encoder.cpp b/CPP/7zip/Compress/Lzma2Encoder.cpp
index 18f7d02..0dc7e23 100644
--- a/CPP/7zip/Compress/Lzma2Encoder.cpp
+++ b/CPP/7zip/Compress/Lzma2Encoder.cpp
@@ -1,122 +1,126 @@
-// Lzma2Encoder.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/Alloc.h"
-
-#include "../Common/CWrappers.h"
-#include "../Common/StreamUtils.h"
-
-#include "Lzma2Encoder.h"
-
-namespace NCompress {
-
-namespace NLzma {
-
-HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep);
-
-}
-
-namespace NLzma2 {
-
-CEncoder::CEncoder()
-{
- _encoder = NULL;
- _encoder = Lzma2Enc_Create(&g_AlignedAlloc, &g_BigAlloc);
- if (!_encoder)
- throw 1;
-}
-
-CEncoder::~CEncoder()
-{
- if (_encoder)
- Lzma2Enc_Destroy(_encoder);
-}
-
-
-HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props)
-{
- switch (propID)
- {
- case NCoderPropID::kBlockSize:
- {
- if (prop.vt == VT_UI4)
- lzma2Props.blockSize = prop.ulVal;
- else if (prop.vt == VT_UI8)
- lzma2Props.blockSize = prop.uhVal.QuadPart;
- else
- return E_INVALIDARG;
- break;
- }
- case NCoderPropID::kNumThreads:
- if (prop.vt != VT_UI4) return E_INVALIDARG; lzma2Props.numTotalThreads = (int)(prop.ulVal); break;
- default:
- RINOK(NLzma::SetLzmaProp(propID, prop, lzma2Props.lzmaProps));
- }
- return S_OK;
-}
-
-
-STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
- const PROPVARIANT *coderProps, UInt32 numProps)
-{
- CLzma2EncProps lzma2Props;
- Lzma2EncProps_Init(&lzma2Props);
-
- for (UInt32 i = 0; i < numProps; i++)
- {
- RINOK(SetLzma2Prop(propIDs[i], coderProps[i], lzma2Props));
- }
- return SResToHRESULT(Lzma2Enc_SetProps(_encoder, &lzma2Props));
-}
-
-
-STDMETHODIMP CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs,
- const PROPVARIANT *coderProps, UInt32 numProps)
-{
- for (UInt32 i = 0; i < numProps; i++)
- {
- const PROPVARIANT &prop = coderProps[i];
- PROPID propID = propIDs[i];
- if (propID == NCoderPropID::kExpectedDataSize)
- if (prop.vt == VT_UI8)
- Lzma2Enc_SetDataSize(_encoder, prop.uhVal.QuadPart);
- }
- return S_OK;
-}
-
-
-STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
-{
- Byte prop = Lzma2Enc_WriteProperties(_encoder);
- return WriteStream(outStream, &prop, 1);
-}
-
-
-#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
- if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
-
-STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
-{
- CSeqInStreamWrap inWrap;
- CSeqOutStreamWrap outWrap;
- CCompressProgressWrap progressWrap;
-
- inWrap.Init(inStream);
- outWrap.Init(outStream);
- progressWrap.Init(progress);
-
- SRes res = Lzma2Enc_Encode2(_encoder,
- &outWrap.vt, NULL, NULL,
- &inWrap.vt, NULL, 0,
- progress ? &progressWrap.vt : NULL);
-
- RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ)
- RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
- RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
-
- return SResToHRESULT(res);
-}
-
-}}
+// Lzma2Encoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/CWrappers.h"
+#include "../Common/StreamUtils.h"
+
+#include "Lzma2Encoder.h"
+
+namespace NCompress {
+
+namespace NLzma {
+
+HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep);
+
+}
+
+namespace NLzma2 {
+
+CEncoder::CEncoder()
+{
+ _encoder = NULL;
+ _encoder = Lzma2Enc_Create(&g_AlignedAlloc, &g_BigAlloc);
+ if (!_encoder)
+ throw 1;
+}
+
+CEncoder::~CEncoder()
+{
+ if (_encoder)
+ Lzma2Enc_Destroy(_encoder);
+}
+
+
+HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props);
+HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props)
+{
+ switch (propID)
+ {
+ case NCoderPropID::kBlockSize:
+ {
+ if (prop.vt == VT_UI4)
+ lzma2Props.blockSize = prop.ulVal;
+ else if (prop.vt == VT_UI8)
+ lzma2Props.blockSize = prop.uhVal.QuadPart;
+ else
+ return E_INVALIDARG;
+ break;
+ }
+ case NCoderPropID::kNumThreads:
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ lzma2Props.numTotalThreads = (int)(prop.ulVal);
+ break;
+ default:
+ RINOK(NLzma::SetLzmaProp(propID, prop, lzma2Props.lzmaProps))
+ }
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs,
+ const PROPVARIANT *coderProps, UInt32 numProps))
+{
+ CLzma2EncProps lzma2Props;
+ Lzma2EncProps_Init(&lzma2Props);
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ RINOK(SetLzma2Prop(propIDs[i], coderProps[i], lzma2Props))
+ }
+ return SResToHRESULT(Lzma2Enc_SetProps(_encoder, &lzma2Props));
+}
+
+
+Z7_COM7F_IMF(CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs,
+ const PROPVARIANT *coderProps, UInt32 numProps))
+{
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = coderProps[i];
+ const PROPID propID = propIDs[i];
+ if (propID == NCoderPropID::kExpectedDataSize)
+ if (prop.vt == VT_UI8)
+ Lzma2Enc_SetDataSize(_encoder, prop.uhVal.QuadPart);
+ }
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream))
+{
+ const Byte prop = Lzma2Enc_WriteProperties(_encoder);
+ return WriteStream(outStream, &prop, 1);
+}
+
+
+#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
+ if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
+
+Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress))
+{
+ CSeqInStreamWrap inWrap;
+ CSeqOutStreamWrap outWrap;
+ CCompressProgressWrap progressWrap;
+
+ inWrap.Init(inStream);
+ outWrap.Init(outStream);
+ progressWrap.Init(progress);
+
+ SRes res = Lzma2Enc_Encode2(_encoder,
+ &outWrap.vt, NULL, NULL,
+ &inWrap.vt, NULL, 0,
+ progress ? &progressWrap.vt : NULL);
+
+ RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ)
+ RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
+ RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
+
+ return SResToHRESULT(res);
+}
+
+}}
diff --git a/CPP/7zip/Compress/Lzma2Encoder.h b/CPP/7zip/Compress/Lzma2Encoder.h
index 6539e73..18c29e1 100644
--- a/CPP/7zip/Compress/Lzma2Encoder.h
+++ b/CPP/7zip/Compress/Lzma2Encoder.h
@@ -1,42 +1,30 @@
-// Lzma2Encoder.h
-
-#ifndef __LZMA2_ENCODER_H
-#define __LZMA2_ENCODER_H
-
-#include "../../../C/Lzma2Enc.h"
-
-#include "../../Common/MyCom.h"
-
-#include "../ICoder.h"
-
-namespace NCompress {
-namespace NLzma2 {
-
-class CEncoder:
- public ICompressCoder,
- public ICompressSetCoderProperties,
- public ICompressWriteCoderProperties,
- public ICompressSetCoderPropertiesOpt,
- public CMyUnknownImp
-{
- CLzma2EncHandle _encoder;
-public:
- MY_UNKNOWN_IMP4(
- ICompressCoder,
- ICompressSetCoderProperties,
- ICompressWriteCoderProperties,
- ICompressSetCoderPropertiesOpt)
-
- STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
- STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
- STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
- STDMETHOD(SetCoderPropertiesOpt)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
-
- CEncoder();
- virtual ~CEncoder();
-};
-
-}}
-
-#endif
+// Lzma2Encoder.h
+
+#ifndef ZIP7_INC_LZMA2_ENCODER_H
+#define ZIP7_INC_LZMA2_ENCODER_H
+
+#include "../../../C/Lzma2Enc.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NLzma2 {
+
+Z7_CLASS_IMP_COM_4(
+ CEncoder
+ , ICompressCoder
+ , ICompressSetCoderProperties
+ , ICompressWriteCoderProperties
+ , ICompressSetCoderPropertiesOpt
+)
+ CLzma2EncHandle _encoder;
+public:
+ CEncoder();
+ ~CEncoder();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/Lzma2Register.cpp b/CPP/7zip/Compress/Lzma2Register.cpp
index 4367105..fe53346 100644
--- a/CPP/7zip/Compress/Lzma2Register.cpp
+++ b/CPP/7zip/Compress/Lzma2Register.cpp
@@ -1,22 +1,22 @@
-// Lzma2Register.cpp
-
-#include "StdAfx.h"
-
-#include "../Common/RegisterCodec.h"
-
-#include "Lzma2Decoder.h"
-
-#ifndef EXTRACT_ONLY
-#include "Lzma2Encoder.h"
-#endif
-
-namespace NCompress {
-namespace NLzma2 {
-
-REGISTER_CODEC_E(LZMA2,
- CDecoder(),
- CEncoder(),
- 0x21,
- "LZMA2")
-
-}}
+// Lzma2Register.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "Lzma2Decoder.h"
+
+#ifndef Z7_EXTRACT_ONLY
+#include "Lzma2Encoder.h"
+#endif
+
+namespace NCompress {
+namespace NLzma2 {
+
+REGISTER_CODEC_E(LZMA2,
+ CDecoder(),
+ CEncoder(),
+ 0x21,
+ "LZMA2")
+
+}}
diff --git a/CPP/7zip/Compress/LzmaDecoder.cpp b/CPP/7zip/Compress/LzmaDecoder.cpp
index b6a8d3f..4f05b48 100644
--- a/CPP/7zip/Compress/LzmaDecoder.cpp
+++ b/CPP/7zip/Compress/LzmaDecoder.cpp
@@ -1,343 +1,349 @@
-// LzmaDecoder.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/Alloc.h"
-
-#include "../Common/StreamUtils.h"
-
-#include "LzmaDecoder.h"
-
-static HRESULT SResToHRESULT(SRes res)
-{
- switch (res)
- {
- case SZ_OK: return S_OK;
- case SZ_ERROR_MEM: return E_OUTOFMEMORY;
- case SZ_ERROR_PARAM: return E_INVALIDARG;
- case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL;
- case SZ_ERROR_DATA: return S_FALSE;
- }
- return E_FAIL;
-}
-
-namespace NCompress {
-namespace NLzma {
-
-CDecoder::CDecoder():
- _inBuf(NULL),
- _lzmaStatus(LZMA_STATUS_NOT_SPECIFIED),
- FinishStream(false),
- _propsWereSet(false),
- _outSizeDefined(false),
- _outStep(1 << 20),
- _inBufSize(0),
- _inBufSizeNew(1 << 20)
-{
- _inProcessed = 0;
- _inPos = _inLim = 0;
-
- /*
- AlignOffsetAlloc_CreateVTable(&_alloc);
- _alloc.numAlignBits = 7;
- _alloc.offset = 0;
- */
- LzmaDec_Construct(&_state);
-}
-
-CDecoder::~CDecoder()
-{
- LzmaDec_Free(&_state, &g_AlignedAlloc); // &_alloc.vt
- MyFree(_inBuf);
-}
-
-STDMETHODIMP CDecoder::SetInBufSize(UInt32 , UInt32 size) { _inBufSizeNew = size; return S_OK; }
-STDMETHODIMP CDecoder::SetOutBufSize(UInt32 , UInt32 size) { _outStep = size; return S_OK; }
-
-HRESULT CDecoder::CreateInputBuffer()
-{
- if (!_inBuf || _inBufSizeNew != _inBufSize)
- {
- MyFree(_inBuf);
- _inBufSize = 0;
- _inBuf = (Byte *)MyAlloc(_inBufSizeNew);
- if (!_inBuf)
- return E_OUTOFMEMORY;
- _inBufSize = _inBufSizeNew;
- }
- return S_OK;
-}
-
-
-STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size)
-{
- RINOK(SResToHRESULT(LzmaDec_Allocate(&_state, prop, size, &g_AlignedAlloc))) // &_alloc.vt
- _propsWereSet = true;
- return CreateInputBuffer();
-}
-
-
-void CDecoder::SetOutStreamSizeResume(const UInt64 *outSize)
-{
- _outSizeDefined = (outSize != NULL);
- _outSize = 0;
- if (_outSizeDefined)
- _outSize = *outSize;
- _outProcessed = 0;
- _lzmaStatus = LZMA_STATUS_NOT_SPECIFIED;
-
- LzmaDec_Init(&_state);
-}
-
-
-STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
-{
- _inProcessed = 0;
- _inPos = _inLim = 0;
- SetOutStreamSizeResume(outSize);
- return S_OK;
-}
-
-
-STDMETHODIMP CDecoder::SetFinishMode(UInt32 finishMode)
-{
- FinishStream = (finishMode != 0);
- return S_OK;
-}
-
-
-STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
-{
- *value = _inProcessed;
- return S_OK;
-}
-
-
-HRESULT CDecoder::CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)
-{
- if (!_inBuf || !_propsWereSet)
- return S_FALSE;
-
- const UInt64 startInProgress = _inProcessed;
- SizeT wrPos = _state.dicPos;
- HRESULT readRes = S_OK;
-
- for (;;)
- {
- if (_inPos == _inLim && readRes == S_OK)
- {
- _inPos = _inLim = 0;
- readRes = inStream->Read(_inBuf, _inBufSize, &_inLim);
- }
-
- const SizeT dicPos = _state.dicPos;
- SizeT size;
- {
- SizeT next = _state.dicBufSize;
- if (next - wrPos > _outStep)
- next = wrPos + _outStep;
- size = next - dicPos;
- }
-
- ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
- if (_outSizeDefined)
- {
- const UInt64 rem = _outSize - _outProcessed;
- if (size >= rem)
- {
- size = (SizeT)rem;
- if (FinishStream)
- finishMode = LZMA_FINISH_END;
- }
- }
-
- SizeT inProcessed = _inLim - _inPos;
- ELzmaStatus status;
-
- SRes res = LzmaDec_DecodeToDic(&_state, dicPos + size, _inBuf + _inPos, &inProcessed, finishMode, &status);
-
- _lzmaStatus = status;
- _inPos += (UInt32)inProcessed;
- _inProcessed += inProcessed;
- const SizeT outProcessed = _state.dicPos - dicPos;
- _outProcessed += outProcessed;
-
- // we check for LZMA_STATUS_NEEDS_MORE_INPUT to allow RangeCoder initialization, if (_outSizeDefined && _outSize == 0)
- bool outFinished = (_outSizeDefined && _outProcessed >= _outSize);
-
- bool needStop = (res != 0
- || (inProcessed == 0 && outProcessed == 0)
- || status == LZMA_STATUS_FINISHED_WITH_MARK
- || (outFinished && status != LZMA_STATUS_NEEDS_MORE_INPUT));
-
- if (needStop || outProcessed >= size)
- {
- HRESULT res2 = WriteStream(outStream, _state.dic + wrPos, _state.dicPos - wrPos);
-
- if (_state.dicPos == _state.dicBufSize)
- _state.dicPos = 0;
- wrPos = _state.dicPos;
-
- RINOK(res2);
-
- if (needStop)
- {
- if (res != 0)
- return S_FALSE;
-
- if (status == LZMA_STATUS_FINISHED_WITH_MARK)
- {
- if (FinishStream)
- if (_outSizeDefined && _outSize != _outProcessed)
- return S_FALSE;
- return readRes;
- }
-
- if (outFinished && status != LZMA_STATUS_NEEDS_MORE_INPUT)
- if (!FinishStream || status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
- return readRes;
-
- return S_FALSE;
- }
- }
-
- if (progress)
- {
- const UInt64 inSize = _inProcessed - startInProgress;
- RINOK(progress->SetRatioInfo(&inSize, &_outProcessed));
- }
- }
-}
-
-
-STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
-{
- if (!_inBuf)
- return E_INVALIDARG;
- SetOutStreamSize(outSize);
- HRESULT res = CodeSpec(inStream, outStream, progress);
- if (res == S_OK)
- if (FinishStream && inSize && *inSize != _inProcessed)
- res = S_FALSE;
- return res;
-}
-
-
-#ifndef NO_READ_FROM_CODER
-
-STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream) { _inStream = inStream; return S_OK; }
-STDMETHODIMP CDecoder::ReleaseInStream() { _inStream.Release(); return S_OK; }
-
-
-STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
-
- ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
- if (_outSizeDefined)
- {
- const UInt64 rem = _outSize - _outProcessed;
- if (size >= rem)
- {
- size = (UInt32)rem;
- if (FinishStream)
- finishMode = LZMA_FINISH_END;
- }
- }
-
- HRESULT readRes = S_OK;
-
- for (;;)
- {
- if (_inPos == _inLim && readRes == S_OK)
- {
- _inPos = _inLim = 0;
- readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim);
- }
-
- SizeT inProcessed = _inLim - _inPos;
- SizeT outProcessed = size;
- ELzmaStatus status;
-
- SRes res = LzmaDec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,
- _inBuf + _inPos, &inProcessed, finishMode, &status);
-
- _lzmaStatus = status;
- _inPos += (UInt32)inProcessed;
- _inProcessed += inProcessed;
- _outProcessed += outProcessed;
- size -= (UInt32)outProcessed;
- data = (Byte *)data + outProcessed;
- if (processedSize)
- *processedSize += (UInt32)outProcessed;
-
- if (res != 0)
- return S_FALSE;
-
- /*
- if (status == LZMA_STATUS_FINISHED_WITH_MARK)
- return readRes;
-
- if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT)
- {
- if (FinishStream
- && _outSizeDefined && _outProcessed >= _outSize
- && status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
- return S_FALSE;
- return readRes;
- }
- */
-
- if (inProcessed == 0 && outProcessed == 0)
- return readRes;
- }
-}
-
-
-HRESULT CDecoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)
-{
- SetOutStreamSizeResume(outSize);
- return CodeSpec(_inStream, outStream, progress);
-}
-
-
-HRESULT CDecoder::ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize)
-{
- RINOK(CreateInputBuffer());
-
- if (processedSize)
- *processedSize = 0;
-
- HRESULT readRes = S_OK;
-
- while (size != 0)
- {
- if (_inPos == _inLim)
- {
- _inPos = _inLim = 0;
- if (readRes == S_OK)
- readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim);
- if (_inLim == 0)
- break;
- }
-
- UInt32 cur = _inLim - _inPos;
- if (cur > size)
- cur = size;
- memcpy(data, _inBuf + _inPos, cur);
- _inPos += cur;
- _inProcessed += cur;
- size -= cur;
- data = (Byte *)data + cur;
- if (processedSize)
- *processedSize += cur;
- }
-
- return readRes;
-}
-
-#endif
-
-}}
+// LzmaDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "LzmaDecoder.h"
+
+static HRESULT SResToHRESULT(SRes res)
+{
+ switch (res)
+ {
+ case SZ_OK: return S_OK;
+ case SZ_ERROR_MEM: return E_OUTOFMEMORY;
+ case SZ_ERROR_PARAM: return E_INVALIDARG;
+ case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL;
+ case SZ_ERROR_DATA: return S_FALSE;
+ }
+ return E_FAIL;
+}
+
+namespace NCompress {
+namespace NLzma {
+
+CDecoder::CDecoder():
+ FinishStream(false),
+ _propsWereSet(false),
+ _outSizeDefined(false),
+ _outStep(1 << 20),
+ _inBufSize(0),
+ _inBufSizeNew(1 << 20),
+ _lzmaStatus(LZMA_STATUS_NOT_SPECIFIED),
+ _inBuf(NULL)
+{
+ _inProcessed = 0;
+ _inPos = _inLim = 0;
+
+ /*
+ AlignOffsetAlloc_CreateVTable(&_alloc);
+ _alloc.numAlignBits = 7;
+ _alloc.offset = 0;
+ */
+ LzmaDec_CONSTRUCT(&_state)
+}
+
+CDecoder::~CDecoder()
+{
+ LzmaDec_Free(&_state, &g_AlignedAlloc); // &_alloc.vt
+ MyFree(_inBuf);
+}
+
+Z7_COM7F_IMF(CDecoder::SetInBufSize(UInt32 , UInt32 size))
+ { _inBufSizeNew = size; return S_OK; }
+Z7_COM7F_IMF(CDecoder::SetOutBufSize(UInt32 , UInt32 size))
+ { _outStep = size; return S_OK; }
+
+HRESULT CDecoder::CreateInputBuffer()
+{
+ if (!_inBuf || _inBufSizeNew != _inBufSize)
+ {
+ MyFree(_inBuf);
+ _inBufSize = 0;
+ _inBuf = (Byte *)MyAlloc(_inBufSizeNew);
+ if (!_inBuf)
+ return E_OUTOFMEMORY;
+ _inBufSize = _inBufSizeNew;
+ }
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *prop, UInt32 size))
+{
+ RINOK(SResToHRESULT(LzmaDec_Allocate(&_state, prop, size, &g_AlignedAlloc))) // &_alloc.vt
+ _propsWereSet = true;
+ return CreateInputBuffer();
+}
+
+
+void CDecoder::SetOutStreamSizeResume(const UInt64 *outSize)
+{
+ _outSizeDefined = (outSize != NULL);
+ _outSize = 0;
+ if (_outSizeDefined)
+ _outSize = *outSize;
+ _outProcessed = 0;
+ _lzmaStatus = LZMA_STATUS_NOT_SPECIFIED;
+
+ LzmaDec_Init(&_state);
+}
+
+
+Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize))
+{
+ _inProcessed = 0;
+ _inPos = _inLim = 0;
+ SetOutStreamSizeResume(outSize);
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
+{
+ FinishStream = (finishMode != 0);
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value))
+{
+ *value = _inProcessed;
+ return S_OK;
+}
+
+
+HRESULT CDecoder::CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress)
+{
+ if (!_inBuf || !_propsWereSet)
+ return S_FALSE;
+
+ const UInt64 startInProgress = _inProcessed;
+ SizeT wrPos = _state.dicPos;
+ HRESULT readRes = S_OK;
+
+ for (;;)
+ {
+ if (_inPos == _inLim && readRes == S_OK)
+ {
+ _inPos = _inLim = 0;
+ readRes = inStream->Read(_inBuf, _inBufSize, &_inLim);
+ }
+
+ const SizeT dicPos = _state.dicPos;
+ SizeT size;
+ {
+ SizeT next = _state.dicBufSize;
+ if (next - wrPos > _outStep)
+ next = wrPos + _outStep;
+ size = next - dicPos;
+ }
+
+ ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outProcessed;
+ if (size >= rem)
+ {
+ size = (SizeT)rem;
+ if (FinishStream)
+ finishMode = LZMA_FINISH_END;
+ }
+ }
+
+ SizeT inProcessed = _inLim - _inPos;
+ ELzmaStatus status;
+
+ const SRes res = LzmaDec_DecodeToDic(&_state, dicPos + size, _inBuf + _inPos, &inProcessed, finishMode, &status);
+
+ _lzmaStatus = status;
+ _inPos += (UInt32)inProcessed;
+ _inProcessed += inProcessed;
+ const SizeT outProcessed = _state.dicPos - dicPos;
+ _outProcessed += outProcessed;
+
+ // we check for LZMA_STATUS_NEEDS_MORE_INPUT to allow RangeCoder initialization, if (_outSizeDefined && _outSize == 0)
+ const bool outFinished = (_outSizeDefined && _outProcessed >= _outSize);
+
+ const bool needStop = (res != 0
+ || (inProcessed == 0 && outProcessed == 0)
+ || status == LZMA_STATUS_FINISHED_WITH_MARK
+ || (outFinished && status != LZMA_STATUS_NEEDS_MORE_INPUT));
+
+ if (needStop || outProcessed >= size)
+ {
+ const HRESULT res2 = WriteStream(outStream, _state.dic + wrPos, _state.dicPos - wrPos);
+
+ if (_state.dicPos == _state.dicBufSize)
+ _state.dicPos = 0;
+ wrPos = _state.dicPos;
+
+ RINOK(res2)
+
+ if (needStop)
+ {
+ if (res != 0)
+ {
+ // return SResToHRESULT(res);
+ return S_FALSE;
+ }
+
+ if (status == LZMA_STATUS_FINISHED_WITH_MARK)
+ {
+ if (FinishStream)
+ if (_outSizeDefined && _outSize != _outProcessed)
+ return S_FALSE;
+ return readRes;
+ }
+
+ if (outFinished && status != LZMA_STATUS_NEEDS_MORE_INPUT)
+ if (!FinishStream || status == LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
+ return readRes;
+
+ return S_FALSE;
+ }
+ }
+
+ if (progress)
+ {
+ const UInt64 inSize = _inProcessed - startInProgress;
+ RINOK(progress->SetRatioInfo(&inSize, &_outProcessed))
+ }
+ }
+}
+
+
+Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ if (!_inBuf)
+ return E_INVALIDARG;
+ SetOutStreamSize(outSize);
+ HRESULT res = CodeSpec(inStream, outStream, progress);
+ if (res == S_OK)
+ if (FinishStream && inSize && *inSize != _inProcessed)
+ res = S_FALSE;
+ return res;
+}
+
+
+#ifndef Z7_NO_READ_FROM_CODER
+
+Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream))
+ { _inStream = inStream; return S_OK; }
+Z7_COM7F_IMF(CDecoder::ReleaseInStream())
+ { _inStream.Release(); return S_OK; }
+
+Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+
+ ELzmaFinishMode finishMode = LZMA_FINISH_ANY;
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _outProcessed;
+ if (size >= rem)
+ {
+ size = (UInt32)rem;
+ if (FinishStream)
+ finishMode = LZMA_FINISH_END;
+ }
+ }
+
+ HRESULT readRes = S_OK;
+
+ for (;;)
+ {
+ if (_inPos == _inLim && readRes == S_OK)
+ {
+ _inPos = _inLim = 0;
+ readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim);
+ }
+
+ SizeT inProcessed = _inLim - _inPos;
+ SizeT outProcessed = size;
+ ELzmaStatus status;
+
+ const SRes res = LzmaDec_DecodeToBuf(&_state, (Byte *)data, &outProcessed,
+ _inBuf + _inPos, &inProcessed, finishMode, &status);
+
+ _lzmaStatus = status;
+ _inPos += (UInt32)inProcessed;
+ _inProcessed += inProcessed;
+ _outProcessed += outProcessed;
+ size -= (UInt32)outProcessed;
+ data = (Byte *)data + outProcessed;
+ if (processedSize)
+ *processedSize += (UInt32)outProcessed;
+
+ if (res != 0)
+ return S_FALSE;
+
+ /*
+ if (status == LZMA_STATUS_FINISHED_WITH_MARK)
+ return readRes;
+
+ if (size == 0 && status != LZMA_STATUS_NEEDS_MORE_INPUT)
+ {
+ if (FinishStream
+ && _outSizeDefined && _outProcessed >= _outSize
+ && status != LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK)
+ return S_FALSE;
+ return readRes;
+ }
+ */
+
+ if (inProcessed == 0 && outProcessed == 0)
+ return readRes;
+ }
+}
+
+
+HRESULT CDecoder::CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ SetOutStreamSizeResume(outSize);
+ return CodeSpec(_inStream, outStream, progress);
+}
+
+
+HRESULT CDecoder::ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize)
+{
+ RINOK(CreateInputBuffer())
+
+ if (processedSize)
+ *processedSize = 0;
+
+ HRESULT readRes = S_OK;
+
+ while (size != 0)
+ {
+ if (_inPos == _inLim)
+ {
+ _inPos = _inLim = 0;
+ if (readRes == S_OK)
+ readRes = _inStream->Read(_inBuf, _inBufSize, &_inLim);
+ if (_inLim == 0)
+ break;
+ }
+
+ UInt32 cur = _inLim - _inPos;
+ if (cur > size)
+ cur = size;
+ memcpy(data, _inBuf + _inPos, cur);
+ _inPos += cur;
+ _inProcessed += cur;
+ size -= cur;
+ data = (Byte *)data + cur;
+ if (processedSize)
+ *processedSize += cur;
+ }
+
+ return readRes;
+}
+
+#endif
+
+}}
diff --git a/CPP/7zip/Compress/LzmaDecoder.h b/CPP/7zip/Compress/LzmaDecoder.h
index 08b7c1b..095e76f 100644
--- a/CPP/7zip/Compress/LzmaDecoder.h
+++ b/CPP/7zip/Compress/LzmaDecoder.h
@@ -1,113 +1,113 @@
-// LzmaDecoder.h
-
-#ifndef __LZMA_DECODER_H
-#define __LZMA_DECODER_H
-
-// #include "../../../C/Alloc.h"
-#include "../../../C/LzmaDec.h"
-
-#include "../../Common/MyCom.h"
-#include "../ICoder.h"
-
-namespace NCompress {
-namespace NLzma {
-
-class CDecoder:
- public ICompressCoder,
- public ICompressSetDecoderProperties2,
- public ICompressSetFinishMode,
- public ICompressGetInStreamProcessedSize,
- public ICompressSetBufSize,
- #ifndef NO_READ_FROM_CODER
- public ICompressSetInStream,
- public ICompressSetOutStreamSize,
- public ISequentialInStream,
- #endif
- public CMyUnknownImp
-{
- Byte *_inBuf;
- UInt32 _inPos;
- UInt32 _inLim;
-
- ELzmaStatus _lzmaStatus;
-
-public:
- bool FinishStream; // set it before decoding, if you need to decode full LZMA stream
-
-private:
- bool _propsWereSet;
- bool _outSizeDefined;
- UInt64 _outSize;
- UInt64 _inProcessed;
- UInt64 _outProcessed;
-
- UInt32 _outStep;
- UInt32 _inBufSize;
- UInt32 _inBufSizeNew;
-
- // CAlignOffsetAlloc _alloc;
-
- CLzmaDec _state;
-
- HRESULT CreateInputBuffer();
- HRESULT CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
- void SetOutStreamSizeResume(const UInt64 *outSize);
-
-public:
- MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
- MY_QUERYINTERFACE_ENTRY(ICompressSetDecoderProperties2)
- MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)
- MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)
- MY_QUERYINTERFACE_ENTRY(ICompressSetBufSize)
- #ifndef NO_READ_FROM_CODER
- MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
- MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)
- MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
- #endif
- MY_QUERYINTERFACE_END
- MY_ADDREF_RELEASE
-
- STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
- STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
- STDMETHOD(SetFinishMode)(UInt32 finishMode);
- STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
- STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
- STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size);
- STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size);
-
- #ifndef NO_READ_FROM_CODER
-
-private:
- CMyComPtr<ISequentialInStream> _inStream;
-public:
-
- STDMETHOD(SetInStream)(ISequentialInStream *inStream);
- STDMETHOD(ReleaseInStream)();
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
-
- HRESULT CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress);
- HRESULT ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize);
-
- #endif
-
- UInt64 GetInputProcessedSize() const { return _inProcessed; }
-
- CDecoder();
- virtual ~CDecoder();
-
- UInt64 GetOutputProcessedSize() const { return _outProcessed; }
-
- bool NeedsMoreInput() const { return _lzmaStatus == LZMA_STATUS_NEEDS_MORE_INPUT; }
-
- bool CheckFinishStatus(bool withEndMark) const
- {
- return _lzmaStatus == (withEndMark ?
- LZMA_STATUS_FINISHED_WITH_MARK :
- LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK);
- }
-};
-
-}}
-
-#endif
+// LzmaDecoder.h
+
+#ifndef ZIP7_INC_LZMA_DECODER_H
+#define ZIP7_INC_LZMA_DECODER_H
+
+// #include "../../../C/Alloc.h"
+#include "../../../C/LzmaDec.h"
+
+#include "../../Common/MyCom.h"
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NLzma {
+
+class CDecoder Z7_final:
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public ICompressSetFinishMode,
+ public ICompressGetInStreamProcessedSize,
+ public ICompressSetBufSize,
+ #ifndef Z7_NO_READ_FROM_CODER
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public ISequentialInStream,
+ #endif
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(ICompressCoder)
+ Z7_COM_QI_ENTRY(ICompressSetDecoderProperties2)
+ Z7_COM_QI_ENTRY(ICompressSetFinishMode)
+ Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize)
+ Z7_COM_QI_ENTRY(ICompressSetBufSize)
+ #ifndef Z7_NO_READ_FROM_CODER
+ Z7_COM_QI_ENTRY(ICompressSetInStream)
+ Z7_COM_QI_ENTRY(ICompressSetOutStreamSize)
+ Z7_COM_QI_ENTRY(ISequentialInStream)
+ #endif
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(ICompressCoder)
+public:
+ Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2)
+private:
+ Z7_IFACE_COM7_IMP(ICompressSetFinishMode)
+ Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize)
+ // Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize)
+
+ Z7_IFACE_COM7_IMP(ICompressSetBufSize)
+
+ #ifndef Z7_NO_READ_FROM_CODER
+public:
+ Z7_IFACE_COM7_IMP(ICompressSetInStream)
+private:
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+ Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize)
+ #else
+ Z7_COM7F_IMF(SetOutStreamSize(const UInt64 *outSize));
+ #endif
+
+public:
+ bool FinishStream; // set it before decoding, if you need to decode full LZMA stream
+private:
+ bool _propsWereSet;
+ bool _outSizeDefined;
+
+ UInt32 _outStep;
+ UInt32 _inBufSize;
+ UInt32 _inBufSizeNew;
+
+ ELzmaStatus _lzmaStatus;
+ UInt32 _inPos;
+ UInt32 _inLim;
+ Byte *_inBuf;
+
+ UInt64 _outSize;
+ UInt64 _inProcessed;
+ UInt64 _outProcessed;
+
+ // CAlignOffsetAlloc _alloc;
+
+ CLzmaDec _state;
+
+ HRESULT CreateInputBuffer();
+ HRESULT CodeSpec(ISequentialInStream *inStream, ISequentialOutStream *outStream, ICompressProgressInfo *progress);
+ void SetOutStreamSizeResume(const UInt64 *outSize);
+
+ #ifndef Z7_NO_READ_FROM_CODER
+private:
+ CMyComPtr<ISequentialInStream> _inStream;
+public:
+ HRESULT CodeResume(ISequentialOutStream *outStream, const UInt64 *outSize, ICompressProgressInfo *progress);
+ HRESULT ReadFromInputStream(void *data, UInt32 size, UInt32 *processedSize);
+ #endif
+
+public:
+ CDecoder();
+ ~CDecoder();
+
+ UInt64 GetInputProcessedSize() const { return _inProcessed; }
+ UInt64 GetOutputProcessedSize() const { return _outProcessed; }
+ bool NeedsMoreInput() const { return _lzmaStatus == LZMA_STATUS_NEEDS_MORE_INPUT; }
+ bool CheckFinishStatus(bool withEndMark) const
+ {
+ return _lzmaStatus == (withEndMark ?
+ LZMA_STATUS_FINISHED_WITH_MARK :
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK);
+ }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/LzmaEncoder.cpp b/CPP/7zip/Compress/LzmaEncoder.cpp
index 3151c3d..08e3ba5 100644
--- a/CPP/7zip/Compress/LzmaEncoder.cpp
+++ b/CPP/7zip/Compress/LzmaEncoder.cpp
@@ -1,182 +1,356 @@
-// LzmaEncoder.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/Alloc.h"
-
-#include "../Common/CWrappers.h"
-#include "../Common/StreamUtils.h"
-
-#include "LzmaEncoder.h"
-
-namespace NCompress {
-namespace NLzma {
-
-CEncoder::CEncoder()
-{
- _encoder = NULL;
- _encoder = LzmaEnc_Create(&g_AlignedAlloc);
- if (!_encoder)
- throw 1;
-}
-
-CEncoder::~CEncoder()
-{
- if (_encoder)
- LzmaEnc_Destroy(_encoder, &g_AlignedAlloc, &g_BigAlloc);
-}
-
-static inline wchar_t GetUpperChar(wchar_t c)
-{
- if (c >= 'a' && c <= 'z')
- c -= 0x20;
- return c;
-}
-
-static int ParseMatchFinder(const wchar_t *s, int *btMode, int *numHashBytes)
-{
- wchar_t c = GetUpperChar(*s++);
- if (c == L'H')
- {
- if (GetUpperChar(*s++) != L'C')
- return 0;
- int numHashBytesLoc = (int)(*s++ - L'0');
- if (numHashBytesLoc < 4 || numHashBytesLoc > 4)
- return 0;
- if (*s != 0)
- return 0;
- *btMode = 0;
- *numHashBytes = numHashBytesLoc;
- return 1;
- }
-
- if (c != L'B')
- return 0;
- if (GetUpperChar(*s++) != L'T')
- return 0;
- int numHashBytesLoc = (int)(*s++ - L'0');
- if (numHashBytesLoc < 2 || numHashBytesLoc > 4)
- return 0;
- if (*s != 0)
- return 0;
- *btMode = 1;
- *numHashBytes = numHashBytesLoc;
- return 1;
-}
-
-#define SET_PROP_32(_id_, _dest_) case NCoderPropID::_id_: ep._dest_ = v; break;
-
-HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep)
-{
- if (propID == NCoderPropID::kMatchFinder)
- {
- if (prop.vt != VT_BSTR)
- return E_INVALIDARG;
- return ParseMatchFinder(prop.bstrVal, &ep.btMode, &ep.numHashBytes) ? S_OK : E_INVALIDARG;
- }
-
- if (propID > NCoderPropID::kReduceSize)
- return S_OK;
-
- if (propID == NCoderPropID::kReduceSize)
- {
- if (prop.vt == VT_UI8)
- ep.reduceSize = prop.uhVal.QuadPart;
- else
- return E_INVALIDARG;
- return S_OK;
- }
-
- if (prop.vt != VT_UI4)
- return E_INVALIDARG;
- UInt32 v = prop.ulVal;
- switch (propID)
- {
- case NCoderPropID::kDefaultProp: if (v > 31) return E_INVALIDARG; ep.dictSize = (UInt32)1 << (unsigned)v; break;
- SET_PROP_32(kLevel, level)
- SET_PROP_32(kNumFastBytes, fb)
- SET_PROP_32(kMatchFinderCycles, mc)
- SET_PROP_32(kAlgorithm, algo)
- SET_PROP_32(kDictionarySize, dictSize)
- SET_PROP_32(kPosStateBits, pb)
- SET_PROP_32(kLitPosBits, lp)
- SET_PROP_32(kLitContextBits, lc)
- SET_PROP_32(kNumThreads, numThreads)
- default: return E_INVALIDARG;
- }
- return S_OK;
-}
-
-STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
- const PROPVARIANT *coderProps, UInt32 numProps)
-{
- CLzmaEncProps props;
- LzmaEncProps_Init(&props);
-
- for (UInt32 i = 0; i < numProps; i++)
- {
- const PROPVARIANT &prop = coderProps[i];
- PROPID propID = propIDs[i];
- switch (propID)
- {
- case NCoderPropID::kEndMarker:
- if (prop.vt != VT_BOOL) return E_INVALIDARG; props.writeEndMark = (prop.boolVal != VARIANT_FALSE); break;
- default:
- RINOK(SetLzmaProp(propID, prop, props));
- }
- }
- return SResToHRESULT(LzmaEnc_SetProps(_encoder, &props));
-}
-
-
-STDMETHODIMP CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs,
- const PROPVARIANT *coderProps, UInt32 numProps)
-{
- for (UInt32 i = 0; i < numProps; i++)
- {
- const PROPVARIANT &prop = coderProps[i];
- PROPID propID = propIDs[i];
- if (propID == NCoderPropID::kExpectedDataSize)
- if (prop.vt == VT_UI8)
- LzmaEnc_SetDataSize(_encoder, prop.uhVal.QuadPart);
- }
- return S_OK;
-}
-
-
-STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
-{
- Byte props[LZMA_PROPS_SIZE];
- size_t size = LZMA_PROPS_SIZE;
- RINOK(LzmaEnc_WriteProperties(_encoder, props, &size));
- return WriteStream(outStream, props, size);
-}
-
-
-#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
- if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
-
-STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
-{
- CSeqInStreamWrap inWrap;
- CSeqOutStreamWrap outWrap;
- CCompressProgressWrap progressWrap;
-
- inWrap.Init(inStream);
- outWrap.Init(outStream);
- progressWrap.Init(progress);
-
- SRes res = LzmaEnc_Encode(_encoder, &outWrap.vt, &inWrap.vt,
- progress ? &progressWrap.vt : NULL, &g_AlignedAlloc, &g_BigAlloc);
-
- _inputProcessed = inWrap.Processed;
-
- RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ)
- RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
- RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
-
- return SResToHRESULT(res);
-}
-
-}}
+// LzmaEncoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/CWrappers.h"
+#include "../Common/StreamUtils.h"
+
+#include "LzmaEncoder.h"
+
+// #define LOG_LZMA_THREADS
+
+#ifdef LOG_LZMA_THREADS
+
+#include <stdio.h>
+
+#include "../../Common/IntToString.h"
+#include "../../Windows/TimeUtils.h"
+
+EXTERN_C_BEGIN
+void LzmaEnc_GetLzThreads(CLzmaEncHandle pp, HANDLE lz_threads[2]);
+EXTERN_C_END
+
+#endif
+
+namespace NCompress {
+namespace NLzma {
+
+CEncoder::CEncoder()
+{
+ _encoder = NULL;
+ _encoder = LzmaEnc_Create(&g_AlignedAlloc);
+ if (!_encoder)
+ throw 1;
+}
+
+CEncoder::~CEncoder()
+{
+ if (_encoder)
+ LzmaEnc_Destroy(_encoder, &g_AlignedAlloc, &g_BigAlloc);
+}
+
+static inline wchar_t GetLowCharFast(wchar_t c)
+{
+ return c |= 0x20;
+}
+
+static int ParseMatchFinder(const wchar_t *s, int *btMode, int *numHashBytes)
+{
+ const wchar_t c = GetLowCharFast(*s++);
+ if (c == 'h')
+ {
+ if (GetLowCharFast(*s++) != 'c')
+ return 0;
+ const int num = (int)(*s++ - L'0');
+ if (num < 4 || num > 5)
+ return 0;
+ if (*s != 0)
+ return 0;
+ *btMode = 0;
+ *numHashBytes = num;
+ return 1;
+ }
+
+ if (c != 'b')
+ return 0;
+ {
+ if (GetLowCharFast(*s++) != 't')
+ return 0;
+ const int num = (int)(*s++ - L'0');
+ if (num < 2 || num > 5)
+ return 0;
+ if (*s != 0)
+ return 0;
+ *btMode = 1;
+ *numHashBytes = num;
+ return 1;
+ }
+}
+
+#define SET_PROP_32(_id_, _dest_) case NCoderPropID::_id_: ep._dest_ = (int)v; break;
+#define SET_PROP_32U(_id_, _dest_) case NCoderPropID::_id_: ep._dest_ = v; break;
+
+HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep);
+HRESULT SetLzmaProp(PROPID propID, const PROPVARIANT &prop, CLzmaEncProps &ep)
+{
+ if (propID == NCoderPropID::kMatchFinder)
+ {
+ if (prop.vt != VT_BSTR)
+ return E_INVALIDARG;
+ return ParseMatchFinder(prop.bstrVal, &ep.btMode, &ep.numHashBytes) ? S_OK : E_INVALIDARG;
+ }
+
+ if (propID == NCoderPropID::kAffinity)
+ {
+ if (prop.vt == VT_UI8)
+ ep.affinity = prop.uhVal.QuadPart;
+ else
+ return E_INVALIDARG;
+ return S_OK;
+ }
+
+ if (propID == NCoderPropID::kHashBits)
+ {
+ if (prop.vt == VT_UI4)
+ ep.numHashOutBits = prop.ulVal;
+ else
+ return E_INVALIDARG;
+ return S_OK;
+ }
+
+ if (propID > NCoderPropID::kReduceSize)
+ return S_OK;
+
+ if (propID == NCoderPropID::kReduceSize)
+ {
+ if (prop.vt == VT_UI8)
+ ep.reduceSize = prop.uhVal.QuadPart;
+ else
+ return E_INVALIDARG;
+ return S_OK;
+ }
+
+ if (propID == NCoderPropID::kDictionarySize)
+ {
+ if (prop.vt == VT_UI8)
+ {
+ // 21.03 : we support 64-bit VT_UI8 for dictionary and (dict == 4 GiB)
+ const UInt64 v = prop.uhVal.QuadPart;
+ if (v > ((UInt64)1 << 32))
+ return E_INVALIDARG;
+ UInt32 dict;
+ if (v == ((UInt64)1 << 32))
+ dict = (UInt32)(Int32)-1;
+ else
+ dict = (UInt32)v;
+ ep.dictSize = dict;
+ return S_OK;
+ }
+ }
+
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ const UInt32 v = prop.ulVal;
+ switch (propID)
+ {
+ case NCoderPropID::kDefaultProp:
+ if (v > 32)
+ return E_INVALIDARG;
+ ep.dictSize = (v == 32) ? (UInt32)(Int32)-1 : (UInt32)1 << (unsigned)v;
+ break;
+ SET_PROP_32(kLevel, level)
+ SET_PROP_32(kNumFastBytes, fb)
+ SET_PROP_32U(kMatchFinderCycles, mc)
+ SET_PROP_32(kAlgorithm, algo)
+ SET_PROP_32U(kDictionarySize, dictSize)
+ SET_PROP_32(kPosStateBits, pb)
+ SET_PROP_32(kLitPosBits, lp)
+ SET_PROP_32(kLitContextBits, lc)
+ SET_PROP_32(kNumThreads, numThreads)
+ default: return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs,
+ const PROPVARIANT *coderProps, UInt32 numProps))
+{
+ CLzmaEncProps props;
+ LzmaEncProps_Init(&props);
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = coderProps[i];
+ const PROPID propID = propIDs[i];
+ switch (propID)
+ {
+ case NCoderPropID::kEndMarker:
+ if (prop.vt != VT_BOOL)
+ return E_INVALIDARG;
+ props.writeEndMark = (prop.boolVal != VARIANT_FALSE);
+ break;
+ default:
+ RINOK(SetLzmaProp(propID, prop, props))
+ }
+ }
+ return SResToHRESULT(LzmaEnc_SetProps(_encoder, &props));
+}
+
+
+Z7_COM7F_IMF(CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs,
+ const PROPVARIANT *coderProps, UInt32 numProps))
+{
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = coderProps[i];
+ const PROPID propID = propIDs[i];
+ if (propID == NCoderPropID::kExpectedDataSize)
+ if (prop.vt == VT_UI8)
+ LzmaEnc_SetDataSize(_encoder, prop.uhVal.QuadPart);
+ }
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream))
+{
+ Byte props[LZMA_PROPS_SIZE];
+ SizeT size = LZMA_PROPS_SIZE;
+ RINOK(LzmaEnc_WriteProperties(_encoder, props, &size))
+ return WriteStream(outStream, props, size);
+}
+
+
+#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
+ if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
+
+
+
+#ifdef LOG_LZMA_THREADS
+
+static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }
+
+static void PrintNum(UInt64 val, unsigned numDigits, char c = ' ')
+{
+ char temp[64];
+ char *p = temp + 32;
+ ConvertUInt64ToString(val, p);
+ unsigned len = (unsigned)strlen(p);
+ for (; len < numDigits; len++)
+ *--p = c;
+ printf("%s", p);
+}
+
+static void PrintTime(const char *s, UInt64 val, UInt64 total)
+{
+ printf(" %s :", s);
+ const UInt32 kFreq = 10000000;
+ UInt64 sec = val / kFreq;
+ PrintNum(sec, 6);
+ printf(" .");
+ UInt32 ms = (UInt32)(val - (sec * kFreq)) / (kFreq / 1000);
+ PrintNum(ms, 3, '0');
+
+ while (val > ((UInt64)1 << 56))
+ {
+ val >>= 1;
+ total >>= 1;
+ }
+
+ UInt64 percent = 0;
+ if (total != 0)
+ percent = val * 100 / total;
+ printf(" =");
+ PrintNum(percent, 4);
+ printf("%%");
+}
+
+
+struct CBaseStat
+{
+ UInt64 kernelTime, userTime;
+
+ BOOL Get(HANDLE thread, const CBaseStat *prevStat)
+ {
+ FILETIME creationTimeFT, exitTimeFT, kernelTimeFT, userTimeFT;
+ BOOL res = GetThreadTimes(thread
+ , &creationTimeFT, &exitTimeFT, &kernelTimeFT, &userTimeFT);
+ if (res)
+ {
+ kernelTime = GetTime64(kernelTimeFT);
+ userTime = GetTime64(userTimeFT);
+ if (prevStat)
+ {
+ kernelTime -= prevStat->kernelTime;
+ userTime -= prevStat->userTime;
+ }
+ }
+ return res;
+ }
+};
+
+
+static void PrintStat(HANDLE thread, UInt64 totalTime, const CBaseStat *prevStat)
+{
+ CBaseStat newStat;
+ if (!newStat.Get(thread, prevStat))
+ return;
+
+ PrintTime("K", newStat.kernelTime, totalTime);
+
+ const UInt64 processTime = newStat.kernelTime + newStat.userTime;
+
+ PrintTime("U", newStat.userTime, totalTime);
+ PrintTime("S", processTime, totalTime);
+ printf("\n");
+ // PrintTime("G ", totalTime, totalTime);
+}
+
+#endif
+
+
+
+Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress))
+{
+ CSeqInStreamWrap inWrap;
+ CSeqOutStreamWrap outWrap;
+ CCompressProgressWrap progressWrap;
+
+ inWrap.Init(inStream);
+ outWrap.Init(outStream);
+ progressWrap.Init(progress);
+
+ #ifdef LOG_LZMA_THREADS
+
+ FILETIME startTimeFT;
+ NWindows::NTime::GetCurUtcFileTime(startTimeFT);
+ UInt64 totalTime = GetTime64(startTimeFT);
+ CBaseStat oldStat;
+ if (!oldStat.Get(GetCurrentThread(), NULL))
+ return E_FAIL;
+
+ #endif
+
+
+ SRes res = LzmaEnc_Encode(_encoder, &outWrap.vt, &inWrap.vt,
+ progress ? &progressWrap.vt : NULL, &g_AlignedAlloc, &g_BigAlloc);
+
+ _inputProcessed = inWrap.Processed;
+
+ RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ)
+ RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
+ RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
+
+
+ #ifdef LOG_LZMA_THREADS
+
+ NWindows::NTime::GetCurUtcFileTime(startTimeFT);
+ totalTime = GetTime64(startTimeFT) - totalTime;
+ HANDLE lz_threads[2];
+ LzmaEnc_GetLzThreads(_encoder, lz_threads);
+ printf("\n");
+ printf("Main: "); PrintStat(GetCurrentThread(), totalTime, &oldStat);
+ printf("Hash: "); PrintStat(lz_threads[0], totalTime, NULL);
+ printf("BinT: "); PrintStat(lz_threads[1], totalTime, NULL);
+ // PrintTime("Total: ", totalTime, totalTime);
+ printf("\n");
+
+ #endif
+
+ return SResToHRESULT(res);
+}
+
+}}
diff --git a/CPP/7zip/Compress/LzmaEncoder.h b/CPP/7zip/Compress/LzmaEncoder.h
index 7b31c66..2836d7d 100644
--- a/CPP/7zip/Compress/LzmaEncoder.h
+++ b/CPP/7zip/Compress/LzmaEncoder.h
@@ -1,46 +1,45 @@
-// LzmaEncoder.h
-
-#ifndef __LZMA_ENCODER_H
-#define __LZMA_ENCODER_H
-
-#include "../../../C/LzmaEnc.h"
-
-#include "../../Common/MyCom.h"
-
-#include "../ICoder.h"
-
-namespace NCompress {
-namespace NLzma {
-
-class CEncoder:
- public ICompressCoder,
- public ICompressSetCoderProperties,
- public ICompressWriteCoderProperties,
- public ICompressSetCoderPropertiesOpt,
- public CMyUnknownImp
-{
- CLzmaEncHandle _encoder;
- UInt64 _inputProcessed;
-public:
- MY_UNKNOWN_IMP4(
- ICompressCoder,
- ICompressSetCoderProperties,
- ICompressWriteCoderProperties,
- ICompressSetCoderPropertiesOpt)
-
- STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
- STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
- STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
- STDMETHOD(SetCoderPropertiesOpt)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
-
- CEncoder();
- virtual ~CEncoder();
-
- UInt64 GetInputProcessedSize() const { return _inputProcessed; }
- bool IsWriteEndMark() const { return LzmaEnc_IsWriteEndMark(_encoder) != 0; }
-};
-
-}}
-
-#endif
+// LzmaEncoder.h
+
+#ifndef ZIP7_INC_LZMA_ENCODER_H
+#define ZIP7_INC_LZMA_ENCODER_H
+
+#include "../../../C/LzmaEnc.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NLzma {
+
+class CEncoder Z7_final:
+ public ICompressCoder,
+ public ICompressSetCoderProperties,
+ public ICompressWriteCoderProperties,
+ public ICompressSetCoderPropertiesOpt,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_4(
+ ICompressCoder,
+ ICompressSetCoderProperties,
+ ICompressWriteCoderProperties,
+ ICompressSetCoderPropertiesOpt)
+ Z7_IFACE_COM7_IMP(ICompressCoder)
+public:
+ Z7_IFACE_COM7_IMP(ICompressSetCoderProperties)
+ Z7_IFACE_COM7_IMP(ICompressWriteCoderProperties)
+ Z7_IFACE_COM7_IMP(ICompressSetCoderPropertiesOpt)
+
+ CLzmaEncHandle _encoder;
+ UInt64 _inputProcessed;
+
+ CEncoder();
+ ~CEncoder();
+
+ UInt64 GetInputProcessedSize() const { return _inputProcessed; }
+ bool IsWriteEndMark() const { return LzmaEnc_IsWriteEndMark(_encoder) != 0; }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/LzmaRegister.cpp b/CPP/7zip/Compress/LzmaRegister.cpp
index 4397595..887f7a2 100644
--- a/CPP/7zip/Compress/LzmaRegister.cpp
+++ b/CPP/7zip/Compress/LzmaRegister.cpp
@@ -1,22 +1,22 @@
-// LzmaRegister.cpp
-
-#include "StdAfx.h"
-
-#include "../Common/RegisterCodec.h"
-
-#include "LzmaDecoder.h"
-
-#ifndef EXTRACT_ONLY
-#include "LzmaEncoder.h"
-#endif
-
-namespace NCompress {
-namespace NLzma {
-
-REGISTER_CODEC_E(LZMA,
- CDecoder(),
- CEncoder(),
- 0x30101,
- "LZMA")
-
-}}
+// LzmaRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "LzmaDecoder.h"
+
+#ifndef Z7_EXTRACT_ONLY
+#include "LzmaEncoder.h"
+#endif
+
+namespace NCompress {
+namespace NLzma {
+
+REGISTER_CODEC_E(LZMA,
+ CDecoder(),
+ CEncoder(),
+ 0x30101,
+ "LZMA")
+
+}}
diff --git a/CPP/7zip/Compress/LzmsDecoder.cpp b/CPP/7zip/Compress/LzmsDecoder.cpp
new file mode 100644
index 0000000..38c0408
--- /dev/null
+++ b/CPP/7zip/Compress/LzmsDecoder.cpp
@@ -0,0 +1,576 @@
+// LzmsDecoder.cpp
+// The code is based on LZMS description from wimlib code
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "LzmsDecoder.h"
+
+namespace NCompress {
+namespace NLzms {
+
+static UInt32 g_PosBases[k_NumPosSyms /* + 1 */];
+
+static Byte g_PosDirectBits[k_NumPosSyms];
+
+static const Byte k_PosRuns[31] =
+{
+ 8, 0, 9, 7, 10, 15, 15, 20, 20, 30, 33, 40, 42, 45, 60, 73,
+ 80, 85, 95, 105, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
+};
+
+static UInt32 g_LenBases[k_NumLenSyms];
+
+static const Byte k_LenDirectBits[k_NumLenSyms] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2,
+ 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 6,
+ 7, 8, 9, 10, 16, 30,
+};
+
+static struct CInit
+{
+ CInit()
+ {
+ {
+ unsigned sum = 0;
+ for (unsigned i = 0; i < sizeof(k_PosRuns); i++)
+ {
+ unsigned t = k_PosRuns[i];
+ for (unsigned y = 0; y < t; y++)
+ g_PosDirectBits[sum + y] = (Byte)i;
+ sum += t;
+ }
+ }
+ {
+ UInt32 sum = 1;
+ for (unsigned i = 0; i < k_NumPosSyms; i++)
+ {
+ g_PosBases[i] = sum;
+ sum += (UInt32)1 << g_PosDirectBits[i];
+ }
+ // g_PosBases[k_NumPosSyms] = sum;
+ }
+ {
+ UInt32 sum = 1;
+ for (unsigned i = 0; i < k_NumLenSyms; i++)
+ {
+ g_LenBases[i] = sum;
+ sum += (UInt32)1 << k_LenDirectBits[i];
+ }
+ }
+ }
+} g_Init;
+
+static unsigned GetNumPosSlots(size_t size)
+{
+ if (size < 2)
+ return 0;
+
+ size--;
+
+ if (size >= g_PosBases[k_NumPosSyms - 1])
+ return k_NumPosSyms;
+ unsigned left = 0;
+ unsigned right = k_NumPosSyms;
+ for (;;)
+ {
+ const unsigned m = (left + right) / 2;
+ if (left == m)
+ return m + 1;
+ if (size >= g_PosBases[m])
+ left = m;
+ else
+ right = m;
+ }
+}
+
+
+static const Int32 k_x86_WindowSize = 65535;
+static const Int32 k_x86_TransOffset = 1023;
+
+static const size_t k_x86_HistorySize = (1 << 16);
+
+static void x86_Filter(Byte *data, UInt32 size, Int32 *history)
+{
+ if (size <= 17)
+ return;
+
+ Byte isCode[256];
+ memset(isCode, 0, 256);
+ isCode[0x48] = 1;
+ isCode[0x4C] = 1;
+ isCode[0xE8] = 1;
+ isCode[0xE9] = 1;
+ isCode[0xF0] = 1;
+ isCode[0xFF] = 1;
+
+ {
+ for (size_t i = 0; i < k_x86_HistorySize; i++)
+ history[i] = -(Int32)k_x86_WindowSize - 1;
+ }
+
+ size -= 16;
+ const unsigned kSave = 6;
+ const Byte savedByte = data[(size_t)size + kSave];
+ data[(size_t)size + kSave] = 0xE8;
+ Int32 last_x86_pos = -k_x86_TransOffset - 1;
+
+ // first byte is ignored
+ Int32 i = 0;
+
+ for (;;)
+ {
+ Byte *p = data + (UInt32)i;
+
+ for (;;)
+ {
+ if (isCode[*(++p)]) break;
+ if (isCode[*(++p)]) break;
+ }
+
+ i = (Int32)(p - data);
+ if ((UInt32)i >= size)
+ break;
+
+ UInt32 codeLen;
+
+ Int32 maxTransOffset = k_x86_TransOffset;
+
+ const Byte b = p[0];
+
+ if (b == 0x48)
+ {
+ if (p[1] == 0x8B)
+ {
+ if ((p[2] & 0xF7) != 0x5)
+ continue;
+ // MOV RAX / RCX, [RIP + disp32]
+ }
+ else if (p[1] == 0x8D) // LEA
+ {
+ if ((p[2] & 0x7) != 0x5)
+ continue;
+ // LEA R**, []
+ }
+ else
+ continue;
+ codeLen = 3;
+ }
+ else if (b == 0x4C)
+ {
+ if (p[1] != 0x8D || (p[2] & 0x7) != 0x5)
+ continue;
+ // LEA R*, []
+ codeLen = 3;
+ }
+ else if (b == 0xE8)
+ {
+ // CALL
+ codeLen = 1;
+ maxTransOffset /= 2;
+ }
+ else if (b == 0xE9)
+ {
+ // JUMP
+ i += 4;
+ continue;
+ }
+ else if (b == 0xF0)
+ {
+ if (p[1] != 0x83 || p[2] != 0x05)
+ continue;
+ // LOCK ADD [RIP + disp32], imm8
+ // LOCK ADD [disp32], imm8
+ codeLen = 3;
+ }
+ else
+ // if (b == 0xFF)
+ {
+ if (p[1] != 0x15)
+ continue;
+ // CALL [RIP + disp32];
+ // CALL [disp32];
+ codeLen = 2;
+ }
+
+ Int32 *target;
+ {
+ Byte *p2 = p + codeLen;
+ UInt32 n = GetUi32(p2);
+ if (i - last_x86_pos <= maxTransOffset)
+ {
+ n = (UInt32)((Int32)n - i);
+ SetUi32(p2, n)
+ }
+ target = history + (((UInt32)i + n) & 0xFFFF);
+ }
+
+ i += (Int32)(codeLen + sizeof(UInt32) - 1);
+
+ if (i - *target <= k_x86_WindowSize)
+ last_x86_pos = i;
+ *target = i;
+ }
+
+ data[(size_t)size + kSave] = savedByte;
+}
+
+
+
+// static const int kLenIdNeedInit = -2;
+
+CDecoder::CDecoder():
+ _x86_history(NULL)
+{
+}
+
+CDecoder::~CDecoder()
+{
+ ::MidFree(_x86_history);
+}
+
+// #define RIF(x) { if (!(x)) return false; }
+
+#define LIMIT_CHECK if (_bs._buf < _rc.cur) return S_FALSE;
+// #define LIMIT_CHECK
+
+#define READ_BITS_CHECK(numDirectBits) \
+ if (_bs._buf < _rc.cur) return S_FALSE; \
+ if ((size_t)(_bs._buf - _rc.cur) < (numDirectBits >> 3)) return S_FALSE;
+
+
+#define HUFF_DEC(sym, pp) \
+ sym = pp.DecodeFull(&_bs); \
+ pp.Freqs[sym]++; \
+ if (--pp.RebuildRem == 0) pp.Rebuild();
+
+
+HRESULT CDecoder::CodeReal(const Byte *in, size_t inSize, Byte *_win, size_t outSize)
+{
+ // size_t inSizeT = (size_t)(inSize);
+ // Byte *_win;
+ // size_t _pos;
+ _pos = 0;
+
+ CBitDecoder _bs;
+ CRangeDecoder _rc;
+
+ if (inSize < 8 || (inSize & 1) != 0)
+ return S_FALSE;
+ _rc.Init(in, inSize);
+ if (_rc.code >= _rc.range)
+ return S_FALSE;
+ _bs.Init(in, inSize);
+
+ {
+ {
+ {
+ for (unsigned i = 0 ; i < k_NumReps + 1; i++)
+ _reps[i] = i + 1;
+ }
+
+ {
+ for (unsigned i = 0 ; i < k_NumReps + 1; i++)
+ _deltaReps[i] = i + 1;
+ }
+
+ mainState = 0;
+ matchState = 0;
+
+ { for (size_t i = 0; i < k_NumMainProbs; i++) mainProbs[i].Init(); }
+ { for (size_t i = 0; i < k_NumMatchProbs; i++) matchProbs[i].Init(); }
+
+ {
+ for (size_t k = 0; k < k_NumReps; k++)
+ {
+ lzRepStates[k] = 0;
+ for (size_t i = 0; i < k_NumRepProbs; i++)
+ lzRepProbs[k][i].Init();
+ }
+ }
+ {
+ for (size_t k = 0; k < k_NumReps; k++)
+ {
+ deltaRepStates[k] = 0;
+ for (size_t i = 0; i < k_NumRepProbs; i++)
+ deltaRepProbs[k][i].Init();
+ }
+ }
+
+ m_LitDecoder.Init();
+ m_LenDecoder.Init();
+ m_PowerDecoder.Init();
+ unsigned numPosSyms = GetNumPosSlots(outSize);
+ if (numPosSyms < 2)
+ numPosSyms = 2;
+ m_PosDecoder.Init(numPosSyms);
+ m_DeltaDecoder.Init(numPosSyms);
+ }
+ }
+
+ {
+ unsigned prevType = 0;
+
+ while (_pos < outSize)
+ {
+ if (_rc.Decode(&mainState, k_NumMainProbs, mainProbs) == 0)
+ {
+ UInt32 number;
+ HUFF_DEC(number, m_LitDecoder)
+ LIMIT_CHECK
+ _win[_pos++] = (Byte)number;
+ prevType = 0;
+ }
+ else if (_rc.Decode(&matchState, k_NumMatchProbs, matchProbs) == 0)
+ {
+ UInt32 distance;
+
+ if (_rc.Decode(&lzRepStates[0], k_NumRepProbs, lzRepProbs[0]) == 0)
+ {
+ UInt32 number;
+ HUFF_DEC(number, m_PosDecoder)
+ LIMIT_CHECK
+
+ const unsigned numDirectBits = g_PosDirectBits[number];
+ distance = g_PosBases[number];
+ READ_BITS_CHECK(numDirectBits)
+ distance += _bs.ReadBits32(numDirectBits);
+ // LIMIT_CHECK
+ _reps[3] = _reps[2];
+ _reps[2] = _reps[1];
+ _reps[1] = _reps[0];
+ _reps[0] = distance;
+ }
+ else
+ {
+ if (_rc.Decode(&lzRepStates[1], k_NumRepProbs, lzRepProbs[1]) == 0)
+ {
+ if (prevType != 1)
+ distance = _reps[0];
+ else
+ {
+ distance = _reps[1];
+ _reps[1] = _reps[0];
+ _reps[0] = distance;
+ }
+ }
+ else if (_rc.Decode(&lzRepStates[2], k_NumRepProbs, lzRepProbs[2]) == 0)
+ {
+ if (prevType != 1)
+ {
+ distance = _reps[1];
+ _reps[1] = _reps[0];
+ _reps[0] = distance;
+ }
+ else
+ {
+ distance = _reps[2];
+ _reps[2] = _reps[1];
+ _reps[1] = _reps[0];
+ _reps[0] = distance;
+ }
+ }
+ else
+ {
+ if (prevType != 1)
+ {
+ distance = _reps[2];
+ _reps[2] = _reps[1];
+ _reps[1] = _reps[0];
+ _reps[0] = distance;
+ }
+ else
+ {
+ distance = _reps[3];
+ _reps[3] = _reps[2];
+ _reps[2] = _reps[1];
+ _reps[1] = _reps[0];
+ _reps[0] = distance;
+ }
+ }
+ }
+
+ UInt32 lenSlot;
+ HUFF_DEC(lenSlot, m_LenDecoder)
+ LIMIT_CHECK
+
+ UInt32 len = g_LenBases[lenSlot];
+ {
+ const unsigned numDirectBits = k_LenDirectBits[lenSlot];
+ READ_BITS_CHECK(numDirectBits)
+ len += _bs.ReadBits32(numDirectBits);
+ }
+ // LIMIT_CHECK
+
+ if (len > outSize - _pos)
+ return S_FALSE;
+
+ if (distance > _pos)
+ return S_FALSE;
+
+ Byte *dest = _win + _pos;
+ const Byte *src = dest - distance;
+ _pos += len;
+ do
+ *dest++ = *src++;
+ while (--len);
+
+ prevType = 1;
+ }
+ else
+ {
+ UInt64 distance;
+
+ UInt32 power;
+ UInt32 distance32;
+
+ if (_rc.Decode(&deltaRepStates[0], k_NumRepProbs, deltaRepProbs[0]) == 0)
+ {
+ HUFF_DEC(power, m_PowerDecoder)
+ LIMIT_CHECK
+
+ UInt32 number;
+ HUFF_DEC(number, m_DeltaDecoder)
+ LIMIT_CHECK
+
+ const unsigned numDirectBits = g_PosDirectBits[number];
+ distance32 = g_PosBases[number];
+ READ_BITS_CHECK(numDirectBits)
+ distance32 += _bs.ReadBits32(numDirectBits);
+ // LIMIT_CHECK
+
+ distance = ((UInt64)power << 32) | distance32;
+
+ _deltaReps[3] = _deltaReps[2];
+ _deltaReps[2] = _deltaReps[1];
+ _deltaReps[1] = _deltaReps[0];
+ _deltaReps[0] = distance;
+ }
+ else
+ {
+ if (_rc.Decode(&deltaRepStates[1], k_NumRepProbs, deltaRepProbs[1]) == 0)
+ {
+ if (prevType != 2)
+ distance = _deltaReps[0];
+ else
+ {
+ distance = _deltaReps[1];
+ _deltaReps[1] = _deltaReps[0];
+ _deltaReps[0] = distance;
+ }
+ }
+ else if (_rc.Decode(&deltaRepStates[2], k_NumRepProbs, deltaRepProbs[2]) == 0)
+ {
+ if (prevType != 2)
+ {
+ distance = _deltaReps[1];
+ _deltaReps[1] = _deltaReps[0];
+ _deltaReps[0] = distance;
+ }
+ else
+ {
+ distance = _deltaReps[2];
+ _deltaReps[2] = _deltaReps[1];
+ _deltaReps[1] = _deltaReps[0];
+ _deltaReps[0] = distance;
+ }
+ }
+ else
+ {
+ if (prevType != 2)
+ {
+ distance = _deltaReps[2];
+ _deltaReps[2] = _deltaReps[1];
+ _deltaReps[1] = _deltaReps[0];
+ _deltaReps[0] = distance;
+ }
+ else
+ {
+ distance = _deltaReps[3];
+ _deltaReps[3] = _deltaReps[2];
+ _deltaReps[2] = _deltaReps[1];
+ _deltaReps[1] = _deltaReps[0];
+ _deltaReps[0] = distance;
+ }
+ }
+ distance32 = (UInt32)_deltaReps[0] & 0xFFFFFFFF;
+ power = (UInt32)(_deltaReps[0] >> 32);
+ }
+
+ const UInt32 dist = (distance32 << power);
+
+ UInt32 lenSlot;
+ HUFF_DEC(lenSlot, m_LenDecoder)
+ LIMIT_CHECK
+
+ UInt32 len = g_LenBases[lenSlot];
+ {
+ unsigned numDirectBits = k_LenDirectBits[lenSlot];
+ READ_BITS_CHECK(numDirectBits)
+ len += _bs.ReadBits32(numDirectBits);
+ }
+ // LIMIT_CHECK
+
+ if (len > outSize - _pos)
+ return S_FALSE;
+
+ size_t span = (size_t)1 << power;
+ if ((UInt64)dist + span > _pos)
+ return S_FALSE;
+ Byte *dest = _win + _pos - span;
+ const Byte *src = dest - dist;
+ _pos += len;
+ do
+ {
+ *(dest + span) = (Byte)(*(dest) + *(src + span) - *(src));
+ src++;
+ dest++;
+ }
+ while (--len);
+
+ prevType = 2;
+ }
+ }
+ }
+
+ _rc.Normalize();
+ if (_rc.code != 0)
+ return S_FALSE;
+ if (_rc.cur > _bs._buf
+ || (_rc.cur == _bs._buf && _bs._bitPos != 0))
+ return S_FALSE;
+
+ /*
+ int delta = (int)(_bs._buf - _rc.cur);
+ if (_bs._bitPos != 0)
+ delta--;
+ if ((delta & 1))
+ delta--;
+ printf("%d ", delta);
+ */
+
+ return S_OK;
+}
+
+HRESULT CDecoder::Code(const Byte *in, size_t inSize, Byte *out, size_t outSize)
+{
+ if (!_x86_history)
+ {
+ _x86_history = (Int32 *)::MidAlloc(sizeof(Int32) * k_x86_HistorySize);
+ if (!_x86_history)
+ return E_OUTOFMEMORY;
+ }
+ HRESULT res;
+ // try
+ {
+ res = CodeReal(in, inSize, out, outSize);
+ }
+ // catch (...) { res = S_FALSE; }
+ x86_Filter(out, (UInt32)_pos, _x86_history);
+ return res;
+}
+
+}}
diff --git a/CPP/7zip/Compress/LzmsDecoder.h b/CPP/7zip/Compress/LzmsDecoder.h
new file mode 100644
index 0000000..e173c97
--- /dev/null
+++ b/CPP/7zip/Compress/LzmsDecoder.h
@@ -0,0 +1,271 @@
+// LzmsDecoder.h
+// The code is based on LZMS description from wimlib code
+
+#ifndef ZIP7_INC_LZMS_DECODER_H
+#define ZIP7_INC_LZMS_DECODER_H
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#define PRF(x) x
+#else
+// #define PRF(x)
+#endif
+
+#include "../../../C/CpuArch.h"
+#include "../../../C/HuffEnc.h"
+
+#include "../../Common/MyBuffer.h"
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "HuffmanDecoder.h"
+
+namespace NCompress {
+namespace NLzms {
+
+class CBitDecoder
+{
+public:
+ const Byte *_buf;
+ unsigned _bitPos;
+
+ void Init(const Byte *buf, size_t size) throw()
+ {
+ _buf = buf + size;
+ _bitPos = 0;
+ }
+
+ UInt32 GetValue(unsigned numBits) const
+ {
+ UInt32 v = ((UInt32)_buf[-1] << 16) | ((UInt32)_buf[-2] << 8) | (UInt32)_buf[-3];
+ v >>= (24 - numBits - _bitPos);
+ return v & ((1 << numBits) - 1);
+ }
+
+ void MovePos(unsigned numBits)
+ {
+ _bitPos += numBits;
+ _buf -= (_bitPos >> 3);
+ _bitPos &= 7;
+ }
+
+ UInt32 ReadBits32(unsigned numBits)
+ {
+ UInt32 mask = (((UInt32)1 << numBits) - 1);
+ numBits += _bitPos;
+ const Byte *buf = _buf;
+ UInt32 v = GetUi32(buf - 4);
+ if (numBits > 32)
+ {
+ v <<= (numBits - 32);
+ v |= (UInt32)buf[-5] >> (40 - numBits);
+ }
+ else
+ v >>= (32 - numBits);
+ _buf = buf - (numBits >> 3);
+ _bitPos = numBits & 7;
+ return v & mask;
+ }
+};
+
+
+const unsigned k_NumLitSyms = 256;
+const unsigned k_NumLenSyms = 54;
+const unsigned k_NumPosSyms = 799;
+const unsigned k_NumPowerSyms = 8;
+
+const unsigned k_NumProbBits = 6;
+const unsigned k_ProbLimit = 1 << k_NumProbBits;
+const unsigned k_InitialProb = 48;
+const UInt32 k_InitialHist = 0x55555555;
+
+const unsigned k_NumReps = 3;
+
+const unsigned k_NumMainProbs = 16;
+const unsigned k_NumMatchProbs = 32;
+const unsigned k_NumRepProbs = 64;
+
+const unsigned k_NumHuffmanBits = 15;
+
+template <UInt32 m_NumSyms, UInt32 m_RebuildFreq, unsigned numTableBits>
+class CHuffDecoder: public NCompress::NHuffman::CDecoder<k_NumHuffmanBits, m_NumSyms, numTableBits>
+{
+public:
+ UInt32 RebuildRem;
+ UInt32 NumSyms;
+ UInt32 Freqs[m_NumSyms];
+
+ void Generate() throw()
+ {
+ UInt32 vals[m_NumSyms];
+ Byte levels[m_NumSyms];
+
+ // We need to check that our algorithm is OK, when optimal Huffman tree uses more than 15 levels !!!
+ Huffman_Generate(Freqs, vals, levels, NumSyms, k_NumHuffmanBits);
+
+ /*
+ for (UInt32 i = NumSyms; i < m_NumSyms; i++)
+ levels[i] = 0;
+ */
+ this->BuildFull(levels, NumSyms);
+ }
+
+ void Rebuild() throw()
+ {
+ Generate();
+ RebuildRem = m_RebuildFreq;
+ UInt32 num = NumSyms;
+ for (UInt32 i = 0; i < num; i++)
+ Freqs[i] = (Freqs[i] >> 1) + 1;
+ }
+
+public:
+ void Init(UInt32 numSyms = m_NumSyms) throw()
+ {
+ RebuildRem = m_RebuildFreq;
+ NumSyms = numSyms;
+ for (UInt32 i = 0; i < numSyms; i++)
+ Freqs[i] = 1;
+ // for (; i < m_NumSyms; i++) Freqs[i] = 0;
+ Generate();
+ }
+};
+
+
+struct CProbEntry
+{
+ UInt32 Prob;
+ UInt64 Hist;
+
+ void Init()
+ {
+ Prob = k_InitialProb;
+ Hist = k_InitialHist;
+ }
+
+ UInt32 GetProb() const throw()
+ {
+ UInt32 prob = Prob;
+ if (prob == 0)
+ prob = 1;
+ else if (prob == k_ProbLimit)
+ prob = k_ProbLimit - 1;
+ return prob;
+ }
+
+ void Update(unsigned bit) throw()
+ {
+ Prob += (UInt32)((Int32)(Hist >> (k_ProbLimit - 1)) - (Int32)bit);
+ Hist = (Hist << 1) | bit;
+ }
+};
+
+
+struct CRangeDecoder
+{
+ UInt32 range;
+ UInt32 code;
+ const Byte *cur;
+ // const Byte *end;
+
+ void Init(const Byte *data, size_t /* size */) throw()
+ {
+ range = 0xFFFFFFFF;
+ code = (((UInt32)GetUi16(data)) << 16) | GetUi16(data + 2);
+ cur = data + 4;
+ // end = data + size;
+ }
+
+ void Normalize()
+ {
+ if (range <= 0xFFFF)
+ {
+ range <<= 16;
+ code <<= 16;
+ // if (cur >= end) throw 1;
+ code |= GetUi16(cur);
+ cur += 2;
+ }
+ }
+
+ unsigned Decode(UInt32 *state, UInt32 numStates, struct CProbEntry *probs)
+ {
+ UInt32 st = *state;
+ CProbEntry *entry = &probs[st];
+ st = (st << 1) & (numStates - 1);
+
+ UInt32 prob = entry->GetProb();
+
+ if (range <= 0xFFFF)
+ {
+ range <<= 16;
+ code <<= 16;
+ // if (cur >= end) throw 1;
+ code |= GetUi16(cur);
+ cur += 2;
+ }
+
+ UInt32 bound = (range >> k_NumProbBits) * prob;
+
+ if (code < bound)
+ {
+ range = bound;
+ *state = st;
+ entry->Update(0);
+ return 0;
+ }
+ else
+ {
+ range -= bound;
+ code -= bound;
+ *state = st | 1;
+ entry->Update(1);
+ return 1;
+ }
+ }
+};
+
+
+class CDecoder
+{
+ // CRangeDecoder _rc;
+ // CBitDecoder _bs;
+ size_t _pos;
+
+ UInt32 _reps[k_NumReps + 1];
+ UInt64 _deltaReps[k_NumReps + 1];
+
+ UInt32 mainState;
+ UInt32 matchState;
+ UInt32 lzRepStates[k_NumReps];
+ UInt32 deltaRepStates[k_NumReps];
+
+ struct CProbEntry mainProbs[k_NumMainProbs];
+ struct CProbEntry matchProbs[k_NumMatchProbs];
+
+ struct CProbEntry lzRepProbs[k_NumReps][k_NumRepProbs];
+ struct CProbEntry deltaRepProbs[k_NumReps][k_NumRepProbs];
+
+ CHuffDecoder<k_NumLitSyms, 1024, 9> m_LitDecoder;
+ CHuffDecoder<k_NumPosSyms, 1024, 9> m_PosDecoder;
+ CHuffDecoder<k_NumLenSyms, 512, 8> m_LenDecoder;
+ CHuffDecoder<k_NumPowerSyms, 512, 6> m_PowerDecoder;
+ CHuffDecoder<k_NumPosSyms, 1024, 9> m_DeltaDecoder;
+
+ Int32 *_x86_history;
+
+ HRESULT CodeReal(const Byte *in, size_t inSize, Byte *out, size_t outSize);
+public:
+ CDecoder();
+ ~CDecoder();
+
+ HRESULT Code(const Byte *in, size_t inSize, Byte *out, size_t outSize);
+ size_t GetUnpackSize() const { return _pos; }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/Lzx.h b/CPP/7zip/Compress/Lzx.h
new file mode 100644
index 0000000..2532088
--- /dev/null
+++ b/CPP/7zip/Compress/Lzx.h
@@ -0,0 +1,59 @@
+// Lzx.h
+
+#ifndef ZIP7_INC_COMPRESS_LZX_H
+#define ZIP7_INC_COMPRESS_LZX_H
+
+#include "../../Common/MyTypes.h"
+
+namespace NCompress {
+namespace NLzx {
+
+const unsigned kBlockType_NumBits = 3;
+const unsigned kBlockType_Verbatim = 1;
+const unsigned kBlockType_Aligned = 2;
+const unsigned kBlockType_Uncompressed = 3;
+
+const unsigned kNumHuffmanBits = 16;
+const unsigned kNumReps = 3;
+
+const unsigned kNumLenSlots = 8;
+const unsigned kMatchMinLen = 2;
+const unsigned kNumLenSymbols = 249;
+const unsigned kMatchMaxLen = kMatchMinLen + (kNumLenSlots - 1) + kNumLenSymbols - 1;
+
+const unsigned kNumAlignLevelBits = 3;
+const unsigned kNumAlignBits = 3;
+const unsigned kAlignTableSize = 1 << kNumAlignBits;
+
+const unsigned kNumPosSlots = 50;
+const unsigned kNumPosLenSlots = kNumPosSlots * kNumLenSlots;
+
+const unsigned kMainTableSize = 256 + kNumPosLenSlots;
+const unsigned kLevelTableSize = 20;
+const unsigned kMaxTableSize = kMainTableSize;
+
+const unsigned kNumLevelBits = 4;
+
+const unsigned kLevelSym_Zero1 = 17;
+const unsigned kLevelSym_Zero2 = 18;
+const unsigned kLevelSym_Same = 19;
+
+const unsigned kLevelSym_Zero1_Start = 4;
+const unsigned kLevelSym_Zero1_NumBits = 4;
+
+const unsigned kLevelSym_Zero2_Start = kLevelSym_Zero1_Start + (1 << kLevelSym_Zero1_NumBits);
+const unsigned kLevelSym_Zero2_NumBits = 5;
+
+const unsigned kLevelSym_Same_NumBits = 1;
+const unsigned kLevelSym_Same_Start = 4;
+
+const unsigned kNumDictBits_Min = 15;
+const unsigned kNumDictBits_Max = 21;
+const UInt32 kDictSize_Max = (UInt32)1 << kNumDictBits_Max;
+
+const unsigned kNumLinearPosSlotBits = 17;
+const unsigned kNumPowerPosSlots = 38;
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/LzxDecoder.cpp b/CPP/7zip/Compress/LzxDecoder.cpp
new file mode 100644
index 0000000..b50d863
--- /dev/null
+++ b/CPP/7zip/Compress/LzxDecoder.cpp
@@ -0,0 +1,529 @@
+// LzxDecoder.cpp
+
+#include "StdAfx.h"
+
+#include <string.h>
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+
+#include "../../../C/Alloc.h"
+
+#include "LzxDecoder.h"
+
+namespace NCompress {
+namespace NLzx {
+
+static void x86_Filter(Byte *data, UInt32 size, UInt32 processedSize, UInt32 translationSize)
+{
+ const UInt32 kResidue = 10;
+ if (size <= kResidue)
+ return;
+ size -= kResidue;
+
+ const Byte save = data[(size_t)size + 4];
+ data[(size_t)size + 4] = 0xE8;
+
+ for (UInt32 i = 0;;)
+ {
+ Byte *p = data + i;
+ for (;;)
+ {
+ if (*p++ == 0xE8) break;
+ if (*p++ == 0xE8) break;
+ if (*p++ == 0xE8) break;
+ if (*p++ == 0xE8) break;
+ }
+
+ i = (UInt32)(p - data);
+
+ if (i > size)
+ break;
+ {
+ Int32 v = (Int32)GetUi32(p);
+ Int32 pos = (Int32)((Int32)1 - (Int32)(processedSize + i));
+ i += 4;
+ if (v >= pos && v < (Int32)translationSize)
+ {
+ v += (v >= 0 ? pos : (Int32)translationSize);
+ SetUi32(p, (UInt32)v)
+ }
+ }
+ }
+
+ data[(size_t)size + 4] = save;
+}
+
+
+CDecoder::CDecoder(bool wimMode):
+ _win(NULL),
+ _skipByte(false),
+ _unpackBlockSize(0),
+ KeepHistoryForNext(true),
+ NeedAlloc(true),
+ _keepHistory(false),
+ _wimMode(wimMode),
+ _numDictBits(15),
+ _x86_buf(NULL),
+ _x86_translationSize(0),
+ _unpackedData(NULL)
+{
+}
+
+CDecoder::~CDecoder()
+{
+ if (NeedAlloc)
+ ::MidFree(_win);
+ ::MidFree(_x86_buf);
+}
+
+HRESULT CDecoder::Flush()
+{
+ if (_x86_translationSize != 0)
+ {
+ Byte *destData = _win + _writePos;
+ const UInt32 curSize = _pos - _writePos;
+ if (KeepHistoryForNext)
+ {
+ if (!_x86_buf)
+ {
+ // we must change it to support another chunk sizes
+ const size_t kChunkSize = (size_t)1 << 15;
+ if (curSize > kChunkSize)
+ return E_NOTIMPL;
+ _x86_buf = (Byte *)::MidAlloc(kChunkSize);
+ if (!_x86_buf)
+ return E_OUTOFMEMORY;
+ }
+ memcpy(_x86_buf, destData, curSize);
+ _unpackedData = _x86_buf;
+ destData = _x86_buf;
+ }
+ x86_Filter(destData, (UInt32)curSize, _x86_processedSize, _x86_translationSize);
+ _x86_processedSize += (UInt32)curSize;
+ if (_x86_processedSize >= ((UInt32)1 << 30))
+ _x86_translationSize = 0;
+ }
+
+ return S_OK;
+}
+
+
+UInt32 CDecoder::ReadBits(unsigned numBits) { return _bitStream.ReadBitsSmall(numBits); }
+
+#define RIF(x) { if (!(x)) return false; }
+
+bool CDecoder::ReadTable(Byte *levels, unsigned numSymbols)
+{
+ {
+ Byte levels2[kLevelTableSize];
+ for (unsigned i = 0; i < kLevelTableSize; i++)
+ levels2[i] = (Byte)ReadBits(kNumLevelBits);
+ RIF(_levelDecoder.Build(levels2))
+ }
+
+ unsigned i = 0;
+ do
+ {
+ UInt32 sym = _levelDecoder.Decode(&_bitStream);
+ if (sym <= kNumHuffmanBits)
+ {
+ int delta = (int)levels[i] - (int)sym;
+ delta += (delta < 0) ? (kNumHuffmanBits + 1) : 0;
+ levels[i++] = (Byte)delta;
+ continue;
+ }
+
+ unsigned num;
+ Byte symbol;
+
+ if (sym < kLevelSym_Same)
+ {
+ sym -= kLevelSym_Zero1;
+ num = kLevelSym_Zero1_Start + ((unsigned)sym << kLevelSym_Zero1_NumBits) +
+ (unsigned)ReadBits(kLevelSym_Zero1_NumBits + sym);
+ symbol = 0;
+ }
+ else if (sym == kLevelSym_Same)
+ {
+ num = kLevelSym_Same_Start + (unsigned)ReadBits(kLevelSym_Same_NumBits);
+ sym = _levelDecoder.Decode(&_bitStream);
+ if (sym > kNumHuffmanBits)
+ return false;
+ int delta = (int)levels[i] - (int)sym;
+ delta += (delta < 0) ? (kNumHuffmanBits + 1) : 0;
+ symbol = (Byte)delta;
+ }
+ else
+ return false;
+
+ const unsigned limit = i + num;
+ if (limit > numSymbols)
+ return false;
+
+ do
+ levels[i++] = symbol;
+ while (i < limit);
+ }
+ while (i < numSymbols);
+
+ return true;
+}
+
+
+bool CDecoder::ReadTables(void)
+{
+ {
+ if (_skipByte)
+ {
+ if (_bitStream.DirectReadByte() != 0)
+ return false;
+ }
+
+ _bitStream.NormalizeBig();
+
+ const unsigned blockType = (unsigned)ReadBits(kBlockType_NumBits);
+ if (blockType > kBlockType_Uncompressed)
+ return false;
+
+ _unpackBlockSize = (1 << 15);
+ if (!_wimMode || ReadBits(1) == 0)
+ {
+ _unpackBlockSize = ReadBits(16);
+ // wimlib supports chunks larger than 32KB (unsupported my MS wim).
+ if (!_wimMode || _numDictBits >= 16)
+ {
+ _unpackBlockSize <<= 8;
+ _unpackBlockSize |= ReadBits(8);
+ }
+ }
+
+ PRF(printf("\nBlockSize = %6d %s ", _unpackBlockSize, (_pos & 1) ? "@@@" : " "));
+
+ _isUncompressedBlock = (blockType == kBlockType_Uncompressed);
+
+ _skipByte = false;
+
+ if (_isUncompressedBlock)
+ {
+ _skipByte = ((_unpackBlockSize & 1) != 0);
+
+ PRF(printf(" UncompressedBlock "));
+ if (_unpackBlockSize & 1)
+ {
+ PRF(printf(" ######### "));
+ }
+
+ if (!_bitStream.PrepareUncompressed())
+ return false;
+ if (_bitStream.GetRem() < kNumReps * 4)
+ return false;
+
+ for (unsigned i = 0; i < kNumReps; i++)
+ {
+ const UInt32 rep = _bitStream.ReadUInt32();
+ if (rep > _winSize)
+ return false;
+ _reps[i] = rep;
+ }
+
+ return true;
+ }
+
+ _numAlignBits = 64;
+
+ if (blockType == kBlockType_Aligned)
+ {
+ Byte levels[kAlignTableSize];
+ _numAlignBits = kNumAlignBits;
+ for (unsigned i = 0; i < kAlignTableSize; i++)
+ levels[i] = (Byte)ReadBits(kNumAlignLevelBits);
+ RIF(_alignDecoder.Build(levels))
+ }
+ }
+
+ RIF(ReadTable(_mainLevels, 256))
+ RIF(ReadTable(_mainLevels + 256, _numPosLenSlots))
+ unsigned end = 256 + _numPosLenSlots;
+ memset(_mainLevels + end, 0, kMainTableSize - end);
+ RIF(_mainDecoder.Build(_mainLevels))
+ RIF(ReadTable(_lenLevels, kNumLenSymbols))
+ return _lenDecoder.Build(_lenLevels);
+}
+
+
+HRESULT CDecoder::CodeSpec(UInt32 curSize)
+{
+ if (!_keepHistory || !_isUncompressedBlock)
+ _bitStream.NormalizeBig();
+
+ if (!_keepHistory)
+ {
+ _skipByte = false;
+ _unpackBlockSize = 0;
+
+ memset(_mainLevels, 0, kMainTableSize);
+ memset(_lenLevels, 0, kNumLenSymbols);
+
+ {
+ _x86_translationSize = 12000000;
+ if (!_wimMode)
+ {
+ _x86_translationSize = 0;
+ if (ReadBits(1) != 0)
+ {
+ UInt32 v = ReadBits(16) << 16;
+ v |= ReadBits(16);
+ _x86_translationSize = v;
+ }
+ }
+
+ _x86_processedSize = 0;
+ }
+
+ _reps[0] = 1;
+ _reps[1] = 1;
+ _reps[2] = 1;
+ }
+
+ while (curSize > 0)
+ {
+ if (_bitStream.WasExtraReadError_Fast())
+ return S_FALSE;
+
+ if (_unpackBlockSize == 0)
+ {
+ if (!ReadTables())
+ return S_FALSE;
+ continue;
+ }
+
+ UInt32 next = _unpackBlockSize;
+ if (next > curSize)
+ next = curSize;
+
+ if (_isUncompressedBlock)
+ {
+ const size_t rem = _bitStream.GetRem();
+ if (rem == 0)
+ return S_FALSE;
+ if (next > rem)
+ next = (UInt32)rem;
+ _bitStream.CopyTo(_win + _pos, next);
+ _pos += next;
+ curSize -= next;
+ _unpackBlockSize -= next;
+
+ /* we don't know where skipByte can be placed, if it's end of chunk:
+ 1) in current chunk - there are such cab archives, if chunk is last
+ 2) in next chunk - are there such archives ? */
+
+ if (_skipByte
+ && _unpackBlockSize == 0
+ && curSize == 0
+ && _bitStream.IsOneDirectByteLeft())
+ {
+ _skipByte = false;
+ if (_bitStream.DirectReadByte() != 0)
+ return S_FALSE;
+ }
+
+ continue;
+ }
+
+ curSize -= next;
+ _unpackBlockSize -= next;
+
+ Byte *win = _win;
+
+ while (next > 0)
+ {
+ if (_bitStream.WasExtraReadError_Fast())
+ return S_FALSE;
+
+ UInt32 sym = _mainDecoder.Decode(&_bitStream);
+
+ if (sym < 256)
+ {
+ win[_pos++] = (Byte)sym;
+ next--;
+ continue;
+ }
+ {
+ sym -= 256;
+ if (sym >= _numPosLenSlots)
+ return S_FALSE;
+ const UInt32 posSlot = sym / kNumLenSlots;
+ const UInt32 lenSlot = sym % kNumLenSlots;
+ UInt32 len = kMatchMinLen + lenSlot;
+
+ if (lenSlot == kNumLenSlots - 1)
+ {
+ UInt32 lenTemp = _lenDecoder.Decode(&_bitStream);
+ if (lenTemp >= kNumLenSymbols)
+ return S_FALSE;
+ len = kMatchMinLen + kNumLenSlots - 1 + lenTemp;
+ }
+
+ UInt32 dist;
+
+ if (posSlot < kNumReps)
+ {
+ dist = _reps[posSlot];
+ _reps[posSlot] = _reps[0];
+ _reps[0] = dist;
+ }
+ else
+ {
+ unsigned numDirectBits;
+
+ if (posSlot < kNumPowerPosSlots)
+ {
+ numDirectBits = (unsigned)(posSlot >> 1) - 1;
+ dist = ((2 | (posSlot & 1)) << numDirectBits);
+ }
+ else
+ {
+ numDirectBits = kNumLinearPosSlotBits;
+ dist = ((posSlot - 0x22) << kNumLinearPosSlotBits);
+ }
+
+ if (numDirectBits >= _numAlignBits)
+ {
+ dist += (_bitStream.ReadBitsSmall(numDirectBits - kNumAlignBits) << kNumAlignBits);
+ const UInt32 alignTemp = _alignDecoder.Decode(&_bitStream);
+ if (alignTemp >= kAlignTableSize)
+ return S_FALSE;
+ dist += alignTemp;
+ }
+ else
+ dist += _bitStream.ReadBitsBig(numDirectBits);
+
+ dist -= kNumReps - 1;
+ _reps[2] = _reps[1];
+ _reps[1] = _reps[0];
+ _reps[0] = dist;
+ }
+
+ if (len > next)
+ return S_FALSE;
+
+ if (dist > _pos && !_overDict)
+ return S_FALSE;
+
+ Byte *dest = win + _pos;
+ const UInt32 mask = (_winSize - 1);
+ UInt32 srcPos = (_pos - dist) & mask;
+
+ next -= len;
+
+ if (len > _winSize - srcPos)
+ {
+ _pos += len;
+ do
+ {
+ *dest++ = win[srcPos++];
+ srcPos &= mask;
+ }
+ while (--len);
+ }
+ else
+ {
+ const ptrdiff_t src = (ptrdiff_t)srcPos - (ptrdiff_t)_pos;
+ _pos += len;
+ const Byte *lim = dest + len;
+ *(dest) = *(dest + src);
+ dest++;
+ do
+ *(dest) = *(dest + src);
+ while (++dest != lim);
+ }
+ }
+ }
+ }
+
+ if (!_bitStream.WasFinishedOK())
+ return S_FALSE;
+
+ return S_OK;
+}
+
+
+HRESULT CDecoder::Code(const Byte *inData, size_t inSize, UInt32 outSize)
+{
+ if (!_keepHistory)
+ {
+ _pos = 0;
+ _overDict = false;
+ }
+ else if (_pos == _winSize)
+ {
+ _pos = 0;
+ _overDict = true;
+ }
+
+ _writePos = _pos;
+ _unpackedData = _win + _pos;
+
+ if (outSize > _winSize - _pos)
+ return S_FALSE;
+
+ PRF(printf("\ninSize = %d", inSize));
+ if ((inSize & 1) != 0)
+ {
+ PRF(printf(" ---------"));
+ }
+
+ if (inSize < 1)
+ return S_FALSE;
+
+ _bitStream.Init(inData, inSize);
+
+ const HRESULT res = CodeSpec(outSize);
+ const HRESULT res2 = Flush();
+ return (res == S_OK ? res2 : res);
+}
+
+
+HRESULT CDecoder::SetParams2(unsigned numDictBits)
+{
+ _numDictBits = numDictBits;
+ if (numDictBits < kNumDictBits_Min || numDictBits > kNumDictBits_Max)
+ return E_INVALIDARG;
+ const unsigned numPosSlots = (numDictBits < 20) ?
+ numDictBits * 2 :
+ 34 + ((unsigned)1 << (numDictBits - 17));
+ _numPosLenSlots = numPosSlots * kNumLenSlots;
+ return S_OK;
+}
+
+
+HRESULT CDecoder::SetParams_and_Alloc(unsigned numDictBits)
+{
+ RINOK(SetParams2(numDictBits))
+
+ const UInt32 newWinSize = (UInt32)1 << numDictBits;
+
+ if (NeedAlloc)
+ {
+ if (!_win || newWinSize != _winSize)
+ {
+ ::MidFree(_win);
+ _winSize = 0;
+ _win = (Byte *)::MidAlloc(newWinSize);
+ if (!_win)
+ return E_OUTOFMEMORY;
+ }
+ }
+
+ _winSize = (UInt32)newWinSize;
+ return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Compress/LzxDecoder.h b/CPP/7zip/Compress/LzxDecoder.h
new file mode 100644
index 0000000..ab114e5
--- /dev/null
+++ b/CPP/7zip/Compress/LzxDecoder.h
@@ -0,0 +1,243 @@
+// LzxDecoder.h
+
+#ifndef ZIP7_INC_LZX_DECODER_H
+#define ZIP7_INC_LZX_DECODER_H
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/MyCom.h"
+
+#include "HuffmanDecoder.h"
+#include "Lzx.h"
+
+namespace NCompress {
+namespace NLzx {
+
+class CBitDecoder
+{
+ unsigned _bitPos;
+ UInt32 _value;
+ const Byte *_buf;
+ const Byte *_bufLim;
+ UInt32 _extraSize;
+public:
+
+ void Init(const Byte *data, size_t size)
+ {
+ _buf = data;
+ _bufLim = data + size - 1;
+ _bitPos = 0;
+ _extraSize = 0;
+ }
+
+ size_t GetRem() const { return (size_t)(_bufLim + 1 - _buf); }
+ bool WasExtraReadError_Fast() const { return _extraSize > 4; }
+
+ bool WasFinishedOK() const
+ {
+ if (_buf != _bufLim + 1)
+ return false;
+ if ((_bitPos >> 4) * 2 != _extraSize)
+ return false;
+ unsigned numBits = _bitPos & 15;
+ return (((_value >> (_bitPos - numBits)) & (((UInt32)1 << numBits) - 1)) == 0);
+ }
+
+ void NormalizeSmall()
+ {
+ if (_bitPos <= 16)
+ {
+ UInt32 val;
+ if (_buf >= _bufLim)
+ {
+ val = 0xFFFF;
+ _extraSize += 2;
+ }
+ else
+ {
+ val = GetUi16(_buf);
+ _buf += 2;
+ }
+ _value = (_value << 16) | val;
+ _bitPos += 16;
+ }
+ }
+
+ void NormalizeBig()
+ {
+ if (_bitPos <= 16)
+ {
+ {
+ UInt32 val;
+ if (_buf >= _bufLim)
+ {
+ val = 0xFFFF;
+ _extraSize += 2;
+ }
+ else
+ {
+ val = GetUi16(_buf);
+ _buf += 2;
+ }
+ _value = (_value << 16) | val;
+ _bitPos += 16;
+ }
+ if (_bitPos <= 16)
+ {
+ UInt32 val;
+ if (_buf >= _bufLim)
+ {
+ val = 0xFFFF;
+ _extraSize += 2;
+ }
+ else
+ {
+ val = GetUi16(_buf);
+ _buf += 2;
+ }
+ _value = (_value << 16) | val;
+ _bitPos += 16;
+ }
+ }
+ }
+
+ UInt32 GetValue(unsigned numBits) const
+ {
+ return (_value >> (_bitPos - numBits)) & (((UInt32)1 << numBits) - 1);
+ }
+
+ void MovePos(unsigned numBits)
+ {
+ _bitPos -= numBits;
+ NormalizeSmall();
+ }
+
+ UInt32 ReadBitsSmall(unsigned numBits)
+ {
+ _bitPos -= numBits;
+ UInt32 val = (_value >> _bitPos) & (((UInt32)1 << numBits) - 1);
+ NormalizeSmall();
+ return val;
+ }
+
+ UInt32 ReadBitsBig(unsigned numBits)
+ {
+ _bitPos -= numBits;
+ UInt32 val = (_value >> _bitPos) & (((UInt32)1 << numBits) - 1);
+ NormalizeBig();
+ return val;
+ }
+
+ bool PrepareUncompressed()
+ {
+ if (_extraSize != 0)
+ return false;
+ unsigned numBits = _bitPos - 16;
+ if (((_value >> 16) & (((UInt32)1 << numBits) - 1)) != 0)
+ return false;
+ _buf -= 2;
+ _bitPos = 0;
+ return true;
+ }
+
+ UInt32 ReadUInt32()
+ {
+ UInt32 v = GetUi32(_buf);
+ _buf += 4;
+ return v;
+ }
+
+ void CopyTo(Byte *dest, size_t size)
+ {
+ memcpy(dest, _buf, size);
+ _buf += size;
+ }
+
+ bool IsOneDirectByteLeft() const { return _buf == _bufLim && _extraSize == 0; }
+
+ Byte DirectReadByte()
+ {
+ if (_buf > _bufLim)
+ {
+ _extraSize++;
+ return 0xFF;
+ }
+ return *_buf++;
+ }
+};
+
+
+Z7_CLASS_IMP_COM_0(
+ CDecoder
+)
+ CBitDecoder _bitStream;
+ Byte *_win;
+ UInt32 _pos;
+ UInt32 _winSize;
+
+ bool _overDict;
+ bool _isUncompressedBlock;
+ bool _skipByte;
+ unsigned _numAlignBits;
+
+ UInt32 _reps[kNumReps];
+ UInt32 _numPosLenSlots;
+ UInt32 _unpackBlockSize;
+
+public:
+ bool KeepHistoryForNext;
+ bool NeedAlloc;
+private:
+ bool _keepHistory;
+ bool _wimMode;
+ unsigned _numDictBits;
+ UInt32 _writePos;
+
+ Byte *_x86_buf;
+ UInt32 _x86_translationSize;
+ UInt32 _x86_processedSize;
+
+ Byte *_unpackedData;
+
+ NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> _mainDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kNumLenSymbols> _lenDecoder;
+ NHuffman::CDecoder7b<kAlignTableSize> _alignDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize, 7> _levelDecoder;
+
+ Byte _mainLevels[kMainTableSize];
+ Byte _lenLevels[kNumLenSymbols];
+
+ HRESULT Flush();
+
+ UInt32 ReadBits(unsigned numBits);
+ bool ReadTable(Byte *levels, unsigned numSymbols);
+ bool ReadTables();
+
+ HRESULT CodeSpec(UInt32 size);
+ HRESULT SetParams2(unsigned numDictBits);
+public:
+ CDecoder(bool wimMode = false);
+ ~CDecoder();
+
+ HRESULT SetExternalWindow(Byte *win, unsigned numDictBits)
+ {
+ NeedAlloc = false;
+ _win = win;
+ _winSize = (UInt32)1 << numDictBits;
+ return SetParams2(numDictBits);
+ }
+
+ void SetKeepHistory(bool keepHistory) { _keepHistory = keepHistory; }
+
+ HRESULT SetParams_and_Alloc(unsigned numDictBits);
+
+ HRESULT Code(const Byte *inData, size_t inSize, UInt32 outSize);
+
+ bool WasBlockFinished() const { return _unpackBlockSize == 0; }
+ const Byte *GetUnpackData() const { return _unpackedData; }
+ UInt32 GetUnpackSize() const { return _pos - _writePos; }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/Mtf8.h b/CPP/7zip/Compress/Mtf8.h
new file mode 100644
index 0000000..1b44d00
--- /dev/null
+++ b/CPP/7zip/Compress/Mtf8.h
@@ -0,0 +1,212 @@
+// Mtf8.h
+
+#ifndef ZIP7_INC_COMPRESS_MTF8_H
+#define ZIP7_INC_COMPRESS_MTF8_H
+
+#include "../../../C/CpuArch.h"
+
+namespace NCompress {
+
+struct CMtf8Encoder
+{
+ Byte Buf[256];
+
+ unsigned FindAndMove(Byte v) throw()
+ {
+ size_t pos;
+ for (pos = 0; Buf[pos] != v; pos++);
+ const unsigned resPos = (unsigned)pos;
+ for (; pos >= 8; pos -= 8)
+ {
+ Buf[pos] = Buf[pos - 1];
+ Buf[pos - 1] = Buf[pos - 2];
+ Buf[pos - 2] = Buf[pos - 3];
+ Buf[pos - 3] = Buf[pos - 4];
+ Buf[pos - 4] = Buf[pos - 5];
+ Buf[pos - 5] = Buf[pos - 6];
+ Buf[pos - 6] = Buf[pos - 7];
+ Buf[pos - 7] = Buf[pos - 8];
+ }
+ for (; pos != 0; pos--)
+ Buf[pos] = Buf[pos - 1];
+ Buf[0] = v;
+ return resPos;
+ }
+};
+
+/*
+struct CMtf8Decoder
+{
+ Byte Buf[256];
+
+ void StartInit() { memset(Buf, 0, sizeof(Buf)); }
+ void Add(unsigned pos, Byte val) { Buf[pos] = val; }
+ Byte GetHead() const { return Buf[0]; }
+ Byte GetAndMove(unsigned pos)
+ {
+ Byte res = Buf[pos];
+ for (; pos >= 8; pos -= 8)
+ {
+ Buf[pos] = Buf[pos - 1];
+ Buf[pos - 1] = Buf[pos - 2];
+ Buf[pos - 2] = Buf[pos - 3];
+ Buf[pos - 3] = Buf[pos - 4];
+ Buf[pos - 4] = Buf[pos - 5];
+ Buf[pos - 5] = Buf[pos - 6];
+ Buf[pos - 6] = Buf[pos - 7];
+ Buf[pos - 7] = Buf[pos - 8];
+ }
+ for (; pos > 0; pos--)
+ Buf[pos] = Buf[pos - 1];
+ Buf[0] = res;
+ return res;
+ }
+};
+*/
+
+#ifdef MY_CPU_64BIT
+ typedef UInt64 CMtfVar;
+ #define Z7_MTF_MOVS 3
+#else
+ typedef UInt32 CMtfVar;
+ #define Z7_MTF_MOVS 2
+#endif
+
+#define Z7_MTF_MASK ((1 << Z7_MTF_MOVS) - 1)
+
+
+struct CMtf8Decoder
+{
+ CMtfVar Buf[256 >> Z7_MTF_MOVS];
+
+ void StartInit() { memset(Buf, 0, sizeof(Buf)); }
+ void Add(unsigned pos, Byte val) { Buf[pos >> Z7_MTF_MOVS] |= ((CMtfVar)val << ((pos & Z7_MTF_MASK) << 3)); }
+ Byte GetHead() const { return (Byte)Buf[0]; }
+
+ Z7_FORCE_INLINE
+ Byte GetAndMove(unsigned pos) throw()
+ {
+ const UInt32 lim = ((UInt32)pos >> Z7_MTF_MOVS);
+ pos = (pos & Z7_MTF_MASK) << 3;
+ CMtfVar prev = (Buf[lim] >> pos) & 0xFF;
+
+ UInt32 i = 0;
+
+
+ /*
+ if ((lim & 1) != 0)
+ {
+ CMtfVar next = Buf[0];
+ Buf[0] = (next << 8) | prev;
+ prev = (next >> (Z7_MTF_MASK << 3));
+ i = 1;
+ lim -= 1;
+ }
+ for (; i < lim; i += 2)
+ {
+ CMtfVar n0 = Buf[i];
+ CMtfVar n1 = Buf[i + 1];
+ Buf[i ] = (n0 << 8) | prev;
+ Buf[i + 1] = (n1 << 8) | (n0 >> (Z7_MTF_MASK << 3));
+ prev = (n1 >> (Z7_MTF_MASK << 3));
+ }
+ */
+
+ for (; i < lim; i++)
+ {
+ const CMtfVar n0 = Buf[i];
+ Buf[i ] = (n0 << 8) | prev;
+ prev = (n0 >> (Z7_MTF_MASK << 3));
+ }
+
+
+ const CMtfVar next = Buf[i];
+ const CMtfVar mask = (((CMtfVar)0x100 << pos) - 1);
+ Buf[i] = (next & ~mask) | (((next << 8) | prev) & mask);
+ return (Byte)Buf[0];
+ }
+};
+
+/*
+const int kSmallSize = 64;
+class CMtf8Decoder
+{
+ Byte SmallBuffer[kSmallSize];
+ int SmallSize;
+ int Counts[16];
+ int Size;
+public:
+ Byte Buf[256];
+
+ Byte GetHead() const
+ {
+ if (SmallSize > 0)
+ return SmallBuffer[kSmallSize - SmallSize];
+ return Buf[0];
+ }
+
+ void Init(int size)
+ {
+ Size = size;
+ SmallSize = 0;
+ for (int i = 0; i < 16; i++)
+ {
+ Counts[i] = ((size >= 16) ? 16 : size);
+ size -= Counts[i];
+ }
+ }
+
+ void Add(unsigned pos, Byte val)
+ {
+ Buf[pos] = val;
+ }
+
+ Byte GetAndMove(int pos)
+ {
+ if (pos < SmallSize)
+ {
+ Byte *p = SmallBuffer + kSmallSize - SmallSize;
+ Byte res = p[pos];
+ for (; pos > 0; pos--)
+ p[pos] = p[pos - 1];
+ SmallBuffer[kSmallSize - SmallSize] = res;
+ return res;
+ }
+ if (SmallSize == kSmallSize)
+ {
+ int i = Size - 1;
+ int g = 16;
+ do
+ {
+ g--;
+ int offset = (g << 4);
+ for (int t = Counts[g] - 1; t >= 0; t--, i--)
+ Buf[i] = Buf[offset + t];
+ }
+ while (g != 0);
+
+ for (i = kSmallSize - 1; i >= 0; i--)
+ Buf[i] = SmallBuffer[i];
+ Init(Size);
+ }
+ pos -= SmallSize;
+ int g;
+ for (g = 0; pos >= Counts[g]; g++)
+ pos -= Counts[g];
+ int offset = (g << 4);
+ Byte res = Buf[offset + pos];
+ for (pos; pos < 16 - 1; pos++)
+ Buf[offset + pos] = Buf[offset + pos + 1];
+
+ SmallSize++;
+ SmallBuffer[kSmallSize - SmallSize] = res;
+
+ Counts[g]--;
+ return res;
+ }
+};
+*/
+
+}
+
+#endif
diff --git a/CPP/7zip/Compress/PpmdDecoder.cpp b/CPP/7zip/Compress/PpmdDecoder.cpp
index 4820c0a..1238df6 100644
--- a/CPP/7zip/Compress/PpmdDecoder.cpp
+++ b/CPP/7zip/Compress/PpmdDecoder.cpp
@@ -1,170 +1,218 @@
-// PpmdDecoder.cpp
-// 2009-03-11 : Igor Pavlov : Public domain
-
-#include "StdAfx.h"
-
-#include "../../../C/Alloc.h"
-#include "../../../C/CpuArch.h"
-
-#include "../Common/StreamUtils.h"
-
-#include "PpmdDecoder.h"
-
-namespace NCompress {
-namespace NPpmd {
-
-static const UInt32 kBufSize = (1 << 20);
-
-enum
-{
- kStatus_NeedInit,
- kStatus_Normal,
- kStatus_Finished,
- kStatus_Error
-};
-
-CDecoder::~CDecoder()
-{
- ::MidFree(_outBuf);
- Ppmd7_Free(&_ppmd, &g_BigAlloc);
-}
-
-STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size)
-{
- if (size < 5)
- return E_INVALIDARG;
- _order = props[0];
- UInt32 memSize = GetUi32(props + 1);
- if (_order < PPMD7_MIN_ORDER ||
- _order > PPMD7_MAX_ORDER ||
- memSize < PPMD7_MIN_MEM_SIZE ||
- memSize > PPMD7_MAX_MEM_SIZE)
- return E_NOTIMPL;
- if (!_inStream.Alloc(1 << 20))
- return E_OUTOFMEMORY;
- if (!Ppmd7_Alloc(&_ppmd, memSize, &g_BigAlloc))
- return E_OUTOFMEMORY;
- return S_OK;
-}
-
-HRESULT CDecoder::CodeSpec(Byte *memStream, UInt32 size)
-{
- switch (_status)
- {
- case kStatus_Finished: return S_OK;
- case kStatus_Error: return S_FALSE;
- case kStatus_NeedInit:
- _inStream.Init();
- if (!Ppmd7z_RangeDec_Init(&_rangeDec))
- {
- _status = kStatus_Error;
- return S_FALSE;
- }
- _status = kStatus_Normal;
- Ppmd7_Init(&_ppmd, _order);
- break;
- }
- if (_outSizeDefined)
- {
- const UInt64 rem = _outSize - _processedSize;
- if (size > rem)
- size = (UInt32)rem;
- }
-
- UInt32 i;
- int sym = 0;
- for (i = 0; i != size; i++)
- {
- sym = Ppmd7_DecodeSymbol(&_ppmd, &_rangeDec.vt);
- if (_inStream.Extra || sym < 0)
- break;
- memStream[i] = (Byte)sym;
- }
-
- _processedSize += i;
- if (_inStream.Extra)
- {
- _status = kStatus_Error;
- return _inStream.Res;
- }
- if (sym < 0)
- _status = (sym < -1) ? kStatus_Error : kStatus_Finished;
- return S_OK;
-}
-
-STDMETHODIMP CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
-{
- if (!_outBuf)
- {
- _outBuf = (Byte *)::MidAlloc(kBufSize);
- if (!_outBuf)
- return E_OUTOFMEMORY;
- }
-
- _inStream.Stream = inStream;
- SetOutStreamSize(outSize);
-
- do
- {
- const UInt64 startPos = _processedSize;
- HRESULT res = CodeSpec(_outBuf, kBufSize);
- size_t processed = (size_t)(_processedSize - startPos);
- RINOK(WriteStream(outStream, _outBuf, processed));
- RINOK(res);
- if (_status == kStatus_Finished)
- break;
- if (progress)
- {
- UInt64 inSize = _inStream.GetProcessed();
- RINOK(progress->SetRatioInfo(&inSize, &_processedSize));
- }
- }
- while (!_outSizeDefined || _processedSize < _outSize);
- return S_OK;
-}
-
-STDMETHODIMP CDecoder::SetOutStreamSize(const UInt64 *outSize)
-{
- _outSizeDefined = (outSize != NULL);
- if (_outSizeDefined)
- _outSize = *outSize;
- _processedSize = 0;
- _status = kStatus_NeedInit;
- return S_OK;
-}
-
-
-STDMETHODIMP CDecoder::GetInStreamProcessedSize(UInt64 *value)
-{
- *value = _inStream.GetProcessed();
- return S_OK;
-}
-
-#ifndef NO_READ_FROM_CODER
-
-STDMETHODIMP CDecoder::SetInStream(ISequentialInStream *inStream)
-{
- InSeqStream = inStream;
- _inStream.Stream = inStream;
- return S_OK;
-}
-
-STDMETHODIMP CDecoder::ReleaseInStream()
-{
- InSeqStream.Release();
- return S_OK;
-}
-
-STDMETHODIMP CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- const UInt64 startPos = _processedSize;
- HRESULT res = CodeSpec((Byte *)data, size);
- if (processedSize)
- *processedSize = (UInt32)(_processedSize - startPos);
- return res;
-}
-
-#endif
-
-}}
+// PpmdDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+#include "../../../C/CpuArch.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "PpmdDecoder.h"
+
+namespace NCompress {
+namespace NPpmd {
+
+static const UInt32 kBufSize = (1 << 16);
+
+enum
+{
+ kStatus_NeedInit,
+ kStatus_Normal,
+ kStatus_Finished_With_Mark,
+ kStatus_Error
+};
+
+CDecoder::~CDecoder()
+{
+ ::MidFree(_outBuf);
+ Ppmd7_Free(&_ppmd, &g_BigAlloc);
+}
+
+Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *props, UInt32 size))
+{
+ if (size < 5)
+ return E_INVALIDARG;
+ _order = props[0];
+ const UInt32 memSize = GetUi32(props + 1);
+ if (_order < PPMD7_MIN_ORDER ||
+ _order > PPMD7_MAX_ORDER ||
+ memSize < PPMD7_MIN_MEM_SIZE ||
+ memSize > PPMD7_MAX_MEM_SIZE)
+ return E_NOTIMPL;
+ if (!_inStream.Alloc(1 << 20))
+ return E_OUTOFMEMORY;
+ if (!Ppmd7_Alloc(&_ppmd, memSize, &g_BigAlloc))
+ return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+#define MY_rangeDec _ppmd.rc.dec
+
+#define CHECK_EXTRA_ERROR \
+ if (_inStream.Extra) { \
+ _status = kStatus_Error; \
+ return (_res = (_inStream.Res != SZ_OK ? _inStream.Res: S_FALSE)); }
+
+
+HRESULT CDecoder::CodeSpec(Byte *memStream, UInt32 size)
+{
+ if (_res != S_OK)
+ return _res;
+
+ switch (_status)
+ {
+ case kStatus_Finished_With_Mark: return S_OK;
+ case kStatus_Error: return S_FALSE;
+ case kStatus_NeedInit:
+ _inStream.Init();
+ if (!Ppmd7z_RangeDec_Init(&MY_rangeDec))
+ {
+ _status = kStatus_Error;
+ return (_res = S_FALSE);
+ }
+ CHECK_EXTRA_ERROR
+ _status = kStatus_Normal;
+ Ppmd7_Init(&_ppmd, _order);
+ break;
+ }
+
+ if (_outSizeDefined)
+ {
+ const UInt64 rem = _outSize - _processedSize;
+ if (size > rem)
+ size = (UInt32)rem;
+ }
+
+ int sym = 0;
+ {
+ Byte *buf = memStream;
+ const Byte *lim = buf + size;
+ for (; buf != lim; buf++)
+ {
+ sym = Ppmd7z_DecodeSymbol(&_ppmd);
+ if (_inStream.Extra || sym < 0)
+ break;
+ *buf = (Byte)sym;
+ }
+ /*
+ buf = Ppmd7z_DecodeSymbols(&_ppmd, buf, lim);
+ sym = _ppmd.LastSymbol;
+ */
+ _processedSize += (size_t)(buf - memStream);
+ }
+
+ CHECK_EXTRA_ERROR
+
+ if (sym >= 0)
+ {
+ if (!FinishStream
+ || !_outSizeDefined
+ || _outSize != _processedSize
+ || MY_rangeDec.Code == 0)
+ return S_OK;
+ /*
+ // We can decode additional End Marker here:
+ sym = Ppmd7z_DecodeSymbol(&_ppmd);
+ CHECK_EXTRA_ERROR
+ */
+ }
+
+ if (sym != PPMD7_SYM_END || MY_rangeDec.Code != 0)
+ {
+ _status = kStatus_Error;
+ return (_res = S_FALSE);
+ }
+
+ _status = kStatus_Finished_With_Mark;
+ return S_OK;
+}
+
+
+
+Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ if (!_outBuf)
+ {
+ _outBuf = (Byte *)::MidAlloc(kBufSize);
+ if (!_outBuf)
+ return E_OUTOFMEMORY;
+ }
+
+ _inStream.Stream = inStream;
+ SetOutStreamSize(outSize);
+
+ do
+ {
+ const UInt64 startPos = _processedSize;
+ const HRESULT res = CodeSpec(_outBuf, kBufSize);
+ const size_t processed = (size_t)(_processedSize - startPos);
+ RINOK(WriteStream(outStream, _outBuf, processed))
+ RINOK(res)
+ if (_status == kStatus_Finished_With_Mark)
+ break;
+ if (progress)
+ {
+ const UInt64 inProcessed = _inStream.GetProcessed();
+ RINOK(progress->SetRatioInfo(&inProcessed, &_processedSize))
+ }
+ }
+ while (!_outSizeDefined || _processedSize < _outSize);
+
+ if (FinishStream && inSize && *inSize != _inStream.GetProcessed())
+ return S_FALSE;
+
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CDecoder::SetOutStreamSize(const UInt64 *outSize))
+{
+ _outSizeDefined = (outSize != NULL);
+ if (_outSizeDefined)
+ _outSize = *outSize;
+ _processedSize = 0;
+ _status = kStatus_NeedInit;
+ _res = SZ_OK;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
+{
+ FinishStream = (finishMode != 0);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value))
+{
+ *value = _inStream.GetProcessed();
+ return S_OK;
+}
+
+#ifndef Z7_NO_READ_FROM_CODER
+
+Z7_COM7F_IMF(CDecoder::SetInStream(ISequentialInStream *inStream))
+{
+ InSeqStream = inStream;
+ _inStream.Stream = inStream;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CDecoder::ReleaseInStream())
+{
+ InSeqStream.Release();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CDecoder::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ const UInt64 startPos = _processedSize;
+ const HRESULT res = CodeSpec((Byte *)data, size);
+ if (processedSize)
+ *processedSize = (UInt32)(_processedSize - startPos);
+ return res;
+}
+
+#endif
+
+}}
diff --git a/CPP/7zip/Compress/PpmdDecoder.h b/CPP/7zip/Compress/PpmdDecoder.h
index 3c2f493..22e5bd4 100644
--- a/CPP/7zip/Compress/PpmdDecoder.h
+++ b/CPP/7zip/Compress/PpmdDecoder.h
@@ -1,86 +1,87 @@
-// PpmdDecoder.h
-// 2009-03-11 : Igor Pavlov : Public domain
-
-#ifndef __COMPRESS_PPMD_DECODER_H
-#define __COMPRESS_PPMD_DECODER_H
-
-#include "../../../C/Ppmd7.h"
-
-#include "../../Common/MyCom.h"
-
-#include "../Common/CWrappers.h"
-
-#include "../ICoder.h"
-
-namespace NCompress {
-namespace NPpmd {
-
-class CDecoder :
- public ICompressCoder,
- public ICompressSetDecoderProperties2,
- public ICompressGetInStreamProcessedSize,
- #ifndef NO_READ_FROM_CODER
- public ICompressSetInStream,
- public ICompressSetOutStreamSize,
- public ISequentialInStream,
- #endif
- public CMyUnknownImp
-{
- Byte *_outBuf;
- CPpmd7z_RangeDec _rangeDec;
- CByteInBufWrap _inStream;
- CPpmd7 _ppmd;
-
- Byte _order;
- bool _outSizeDefined;
- int _status;
- UInt64 _outSize;
- UInt64 _processedSize;
-
- HRESULT CodeSpec(Byte *memStream, UInt32 size);
-
-public:
-
- #ifndef NO_READ_FROM_CODER
- CMyComPtr<ISequentialInStream> InSeqStream;
- #endif
-
- MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
- MY_QUERYINTERFACE_ENTRY(ICompressSetDecoderProperties2)
- // MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)
- MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)
- #ifndef NO_READ_FROM_CODER
- MY_QUERYINTERFACE_ENTRY(ICompressSetInStream)
- MY_QUERYINTERFACE_ENTRY(ICompressSetOutStreamSize)
- MY_QUERYINTERFACE_ENTRY(ISequentialInStream)
- #endif
- MY_QUERYINTERFACE_END
- MY_ADDREF_RELEASE
-
-
- STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
- STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
- STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
-
- STDMETHOD(SetOutStreamSize)(const UInt64 *outSize);
-
- #ifndef NO_READ_FROM_CODER
- STDMETHOD(SetInStream)(ISequentialInStream *inStream);
- STDMETHOD(ReleaseInStream)();
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
- #endif
-
- CDecoder(): _outBuf(NULL), _outSizeDefined(false)
- {
- Ppmd7z_RangeDec_CreateVTable(&_rangeDec);
- _rangeDec.Stream = &_inStream.vt;
- Ppmd7_Construct(&_ppmd);
- }
-
- ~CDecoder();
-};
-
-}}
-
-#endif
+// PpmdDecoder.h
+
+#ifndef ZIP7_INC_COMPRESS_PPMD_DECODER_H
+#define ZIP7_INC_COMPRESS_PPMD_DECODER_H
+
+#include "../../../C/Ppmd7.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/CWrappers.h"
+
+namespace NCompress {
+namespace NPpmd {
+
+class CDecoder Z7_final:
+ public ICompressCoder,
+ public ICompressSetDecoderProperties2,
+ public ICompressSetFinishMode,
+ public ICompressGetInStreamProcessedSize,
+ #ifndef Z7_NO_READ_FROM_CODER
+ public ICompressSetInStream,
+ public ICompressSetOutStreamSize,
+ public ISequentialInStream,
+ #endif
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(ICompressCoder)
+ Z7_COM_QI_ENTRY(ICompressSetDecoderProperties2)
+ Z7_COM_QI_ENTRY(ICompressSetFinishMode)
+ Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize)
+ #ifndef Z7_NO_READ_FROM_CODER
+ Z7_COM_QI_ENTRY(ICompressSetInStream)
+ Z7_COM_QI_ENTRY(ICompressSetOutStreamSize)
+ Z7_COM_QI_ENTRY(ISequentialInStream)
+ #endif
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(ICompressCoder)
+ Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2)
+ Z7_IFACE_COM7_IMP(ICompressSetFinishMode)
+ Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize)
+ #ifndef Z7_NO_READ_FROM_CODER
+ Z7_IFACE_COM7_IMP(ICompressSetOutStreamSize)
+ Z7_IFACE_COM7_IMP(ICompressSetInStream)
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+ #else
+ Z7_COM7F_IMF(SetOutStreamSize(const UInt64 *outSize));
+ #endif
+
+ Byte *_outBuf;
+ CByteInBufWrap _inStream;
+ CPpmd7 _ppmd;
+
+ Byte _order;
+ bool FinishStream;
+ bool _outSizeDefined;
+ HRESULT _res;
+ int _status;
+ UInt64 _outSize;
+ UInt64 _processedSize;
+
+ HRESULT CodeSpec(Byte *memStream, UInt32 size);
+
+public:
+
+ #ifndef Z7_NO_READ_FROM_CODER
+ CMyComPtr<ISequentialInStream> InSeqStream;
+ #endif
+
+ CDecoder():
+ _outBuf(NULL),
+ FinishStream(false),
+ _outSizeDefined(false)
+ {
+ Ppmd7_Construct(&_ppmd);
+ _ppmd.rc.dec.Stream = &_inStream.vt;
+ }
+
+ ~CDecoder();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/PpmdEncoder.cpp b/CPP/7zip/Compress/PpmdEncoder.cpp
index 0aef701..2dfca6d 100644
--- a/CPP/7zip/Compress/PpmdEncoder.cpp
+++ b/CPP/7zip/Compress/PpmdEncoder.cpp
@@ -1,152 +1,193 @@
-// PpmdEncoder.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/Alloc.h"
-#include "../../../C/CpuArch.h"
-
-#include "../Common/StreamUtils.h"
-
-#include "PpmdEncoder.h"
-
-namespace NCompress {
-namespace NPpmd {
-
-static const UInt32 kBufSize = (1 << 20);
-
-static const Byte kOrders[10] = { 3, 4, 4, 5, 5, 6, 8, 16, 24, 32 };
-
-void CEncProps::Normalize(int level)
-{
- if (level < 0) level = 5;
- if (level > 9) level = 9;
- if (MemSize == (UInt32)(Int32)-1)
- MemSize = level >= 9 ? ((UInt32)192 << 20) : ((UInt32)1 << (level + 19));
- const unsigned kMult = 16;
- if (MemSize / kMult > ReduceSize)
- {
- for (unsigned i = 16; i <= 31; i++)
- {
- UInt32 m = (UInt32)1 << i;
- if (ReduceSize <= m / kMult)
- {
- if (MemSize > m)
- MemSize = m;
- break;
- }
- }
- }
- if (Order == -1) Order = kOrders[(unsigned)level];
-}
-
-CEncoder::CEncoder():
- _inBuf(NULL)
-{
- _props.Normalize(-1);
- _rangeEnc.Stream = &_outStream.vt;
- Ppmd7_Construct(&_ppmd);
-}
-
-CEncoder::~CEncoder()
-{
- ::MidFree(_inBuf);
- Ppmd7_Free(&_ppmd, &g_BigAlloc);
-}
-
-STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)
-{
- int level = -1;
- CEncProps props;
- for (UInt32 i = 0; i < numProps; i++)
- {
- const PROPVARIANT &prop = coderProps[i];
- PROPID propID = propIDs[i];
- if (propID > NCoderPropID::kReduceSize)
- continue;
- if (propID == NCoderPropID::kReduceSize)
- {
- if (prop.vt == VT_UI8 && prop.uhVal.QuadPart < (UInt32)(Int32)-1)
- props.ReduceSize = (UInt32)prop.uhVal.QuadPart;
- continue;
- }
- if (prop.vt != VT_UI4)
- return E_INVALIDARG;
- UInt32 v = (UInt32)prop.ulVal;
- switch (propID)
- {
- case NCoderPropID::kUsedMemorySize:
- if (v < (1 << 16) || v > PPMD7_MAX_MEM_SIZE || (v & 3) != 0)
- return E_INVALIDARG;
- props.MemSize = v;
- break;
- case NCoderPropID::kOrder:
- if (v < 2 || v > 32)
- return E_INVALIDARG;
- props.Order = (Byte)v;
- break;
- case NCoderPropID::kNumThreads: break;
- case NCoderPropID::kLevel: level = (int)v; break;
- default: return E_INVALIDARG;
- }
- }
- props.Normalize(level);
- _props = props;
- return S_OK;
-}
-
-STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
-{
- const UInt32 kPropSize = 5;
- Byte props[kPropSize];
- props[0] = (Byte)_props.Order;
- SetUi32(props + 1, _props.MemSize);
- return WriteStream(outStream, props, kPropSize);
-}
-
-HRESULT CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
-{
- if (!_inBuf)
- {
- _inBuf = (Byte *)::MidAlloc(kBufSize);
- if (!_inBuf)
- return E_OUTOFMEMORY;
- }
- if (!_outStream.Alloc(1 << 20))
- return E_OUTOFMEMORY;
- if (!Ppmd7_Alloc(&_ppmd, _props.MemSize, &g_BigAlloc))
- return E_OUTOFMEMORY;
-
- _outStream.Stream = outStream;
- _outStream.Init();
-
- Ppmd7z_RangeEnc_Init(&_rangeEnc);
- Ppmd7_Init(&_ppmd, _props.Order);
-
- UInt64 processed = 0;
- for (;;)
- {
- UInt32 size;
- RINOK(inStream->Read(_inBuf, kBufSize, &size));
- if (size == 0)
- {
- // We don't write EndMark in PPMD-7z.
- // Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, -1);
- Ppmd7z_RangeEnc_FlushData(&_rangeEnc);
- return _outStream.Flush();
- }
- for (UInt32 i = 0; i < size; i++)
- {
- Ppmd7_EncodeSymbol(&_ppmd, &_rangeEnc, _inBuf[i]);
- RINOK(_outStream.Res);
- }
- processed += size;
- if (progress)
- {
- UInt64 outSize = _outStream.GetProcessed();
- RINOK(progress->SetRatioInfo(&processed, &outSize));
- }
- }
-}
-
-}}
+// PpmdEncoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "PpmdEncoder.h"
+
+namespace NCompress {
+namespace NPpmd {
+
+static const UInt32 kBufSize = (1 << 20);
+
+static const Byte kOrders[10] = { 3, 4, 4, 5, 5, 6, 8, 16, 24, 32 };
+
+void CEncProps::Normalize(int level)
+{
+ if (level < 0) level = 5;
+ if (level > 9) level = 9;
+ if (MemSize == (UInt32)(Int32)-1)
+ MemSize = (UInt32)1 << (level + 19);
+ const unsigned kMult = 16;
+ if (MemSize / kMult > ReduceSize)
+ {
+ for (unsigned i = 16; i < 32; i++)
+ {
+ UInt32 m = (UInt32)1 << i;
+ if (ReduceSize <= m / kMult)
+ {
+ if (MemSize > m)
+ MemSize = m;
+ break;
+ }
+ }
+ }
+ if (Order == -1) Order = kOrders[(unsigned)level];
+}
+
+CEncoder::CEncoder():
+ _inBuf(NULL)
+{
+ _props.Normalize(-1);
+ Ppmd7_Construct(&_ppmd);
+ _ppmd.rc.enc.Stream = &_outStream.vt;
+}
+
+CEncoder::~CEncoder()
+{
+ ::MidFree(_inBuf);
+ Ppmd7_Free(&_ppmd, &g_BigAlloc);
+}
+
+Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps))
+{
+ int level = -1;
+ CEncProps props;
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = coderProps[i];
+ const PROPID propID = propIDs[i];
+ if (propID > NCoderPropID::kReduceSize)
+ continue;
+ if (propID == NCoderPropID::kReduceSize)
+ {
+ if (prop.vt == VT_UI8 && prop.uhVal.QuadPart < (UInt32)(Int32)-1)
+ props.ReduceSize = (UInt32)prop.uhVal.QuadPart;
+ continue;
+ }
+
+ if (propID == NCoderPropID::kUsedMemorySize)
+ {
+ // here we have selected (4 GiB - 1 KiB) as replacement for (4 GiB) MEM_SIZE.
+ const UInt32 kPpmd_Default_4g = (UInt32)0 - ((UInt32)1 << 10);
+ UInt32 v;
+ if (prop.vt == VT_UI8)
+ {
+ // 21.03 : we support 64-bit values (for 4 GiB value)
+ const UInt64 v64 = prop.uhVal.QuadPart;
+ if (v64 > ((UInt64)1 << 32))
+ return E_INVALIDARG;
+ if (v64 == ((UInt64)1 << 32))
+ v = kPpmd_Default_4g;
+ else
+ v = (UInt32)v64;
+ }
+ else if (prop.vt == VT_UI4)
+ v = (UInt32)prop.ulVal;
+ else
+ return E_INVALIDARG;
+ if (v > PPMD7_MAX_MEM_SIZE)
+ v = kPpmd_Default_4g;
+
+ /* here we restrict MEM_SIZE for Encoder.
+ It's for better performance of encoding and decoding.
+ The Decoder still supports more MEM_SIZE values. */
+ if (v < ((UInt32)1 << 16) || (v & 3) != 0)
+ return E_INVALIDARG;
+ // if (v < PPMD7_MIN_MEM_SIZE) return E_INVALIDARG; // (1 << 11)
+ /*
+ Supported MEM_SIZE range :
+ [ (1 << 11) , 0xFFFFFFFF - 12 * 3 ] - current 7-Zip's Ppmd7 constants
+ [ 1824 , 0xFFFFFFFF ] - real limits of Ppmd7 code
+ */
+ props.MemSize = v;
+ continue;
+ }
+
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ const UInt32 v = (UInt32)prop.ulVal;
+ switch (propID)
+ {
+ case NCoderPropID::kOrder:
+ if (v < 2 || v > 32)
+ return E_INVALIDARG;
+ props.Order = (Byte)v;
+ break;
+ case NCoderPropID::kNumThreads: break;
+ case NCoderPropID::kLevel: level = (int)v; break;
+ default: return E_INVALIDARG;
+ }
+ }
+ props.Normalize(level);
+ _props = props;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream))
+{
+ const UInt32 kPropSize = 5;
+ Byte props[kPropSize];
+ props[0] = (Byte)_props.Order;
+ SetUi32(props + 1, _props.MemSize)
+ return WriteStream(outStream, props, kPropSize);
+}
+
+Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress))
+{
+ if (!_inBuf)
+ {
+ _inBuf = (Byte *)::MidAlloc(kBufSize);
+ if (!_inBuf)
+ return E_OUTOFMEMORY;
+ }
+ if (!_outStream.Alloc(1 << 20))
+ return E_OUTOFMEMORY;
+ if (!Ppmd7_Alloc(&_ppmd, _props.MemSize, &g_BigAlloc))
+ return E_OUTOFMEMORY;
+
+ _outStream.Stream = outStream;
+ _outStream.Init();
+
+ Ppmd7z_Init_RangeEnc(&_ppmd);
+ Ppmd7_Init(&_ppmd, (unsigned)_props.Order);
+
+ UInt64 processed = 0;
+ for (;;)
+ {
+ UInt32 size;
+ RINOK(inStream->Read(_inBuf, kBufSize, &size))
+ if (size == 0)
+ {
+ // We don't write EndMark in PPMD-7z.
+ // Ppmd7z_EncodeSymbol(&_ppmd, -1);
+ Ppmd7z_Flush_RangeEnc(&_ppmd);
+ return _outStream.Flush();
+ }
+ const Byte *buf = _inBuf;
+ const Byte *lim = buf + size;
+ /*
+ for (; buf < lim; buf++)
+ {
+ Ppmd7z_EncodeSymbol(&_ppmd, *buf);
+ RINOK(_outStream.Res);
+ }
+ */
+
+ Ppmd7z_EncodeSymbols(&_ppmd, buf, lim);
+ RINOK(_outStream.Res)
+
+ processed += size;
+ if (progress)
+ {
+ const UInt64 outSize = _outStream.GetProcessed();
+ RINOK(progress->SetRatioInfo(&processed, &outSize))
+ }
+ }
+}
+
+}}
diff --git a/CPP/7zip/Compress/PpmdEncoder.h b/CPP/7zip/Compress/PpmdEncoder.h
index cdb0352..057cccb 100644
--- a/CPP/7zip/Compress/PpmdEncoder.h
+++ b/CPP/7zip/Compress/PpmdEncoder.h
@@ -1,58 +1,49 @@
-// PpmdEncoder.h
-
-#ifndef __COMPRESS_PPMD_ENCODER_H
-#define __COMPRESS_PPMD_ENCODER_H
-
-#include "../../../C/Ppmd7.h"
-
-#include "../../Common/MyCom.h"
-
-#include "../ICoder.h"
-
-#include "../Common/CWrappers.h"
-
-namespace NCompress {
-namespace NPpmd {
-
-struct CEncProps
-{
- UInt32 MemSize;
- UInt32 ReduceSize;
- int Order;
-
- CEncProps()
- {
- MemSize = (UInt32)(Int32)-1;
- ReduceSize = (UInt32)(Int32)-1;
- Order = -1;
- }
- void Normalize(int level);
-};
-
-class CEncoder :
- public ICompressCoder,
- public ICompressSetCoderProperties,
- public ICompressWriteCoderProperties,
- public CMyUnknownImp
-{
- Byte *_inBuf;
- CByteOutBufWrap _outStream;
- CPpmd7z_RangeEnc _rangeEnc;
- CPpmd7 _ppmd;
- CEncProps _props;
-public:
- MY_UNKNOWN_IMP3(
- ICompressCoder,
- ICompressSetCoderProperties,
- ICompressWriteCoderProperties)
- STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
- STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
- STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
- CEncoder();
- ~CEncoder();
-};
-
-}}
-
-#endif
+// PpmdEncoder.h
+
+#ifndef ZIP7_INC_COMPRESS_PPMD_ENCODER_H
+#define ZIP7_INC_COMPRESS_PPMD_ENCODER_H
+
+#include "../../../C/Ppmd7.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/CWrappers.h"
+
+namespace NCompress {
+namespace NPpmd {
+
+struct CEncProps
+{
+ UInt32 MemSize;
+ UInt32 ReduceSize;
+ int Order;
+
+ CEncProps()
+ {
+ MemSize = (UInt32)(Int32)-1;
+ ReduceSize = (UInt32)(Int32)-1;
+ Order = -1;
+ }
+ void Normalize(int level);
+};
+
+Z7_CLASS_IMP_COM_3(
+ CEncoder
+ , ICompressCoder
+ , ICompressSetCoderProperties
+ , ICompressWriteCoderProperties
+)
+ Byte *_inBuf;
+ CByteOutBufWrap _outStream;
+ CPpmd7 _ppmd;
+ CEncProps _props;
+public:
+ CEncoder();
+ ~CEncoder();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/PpmdRegister.cpp b/CPP/7zip/Compress/PpmdRegister.cpp
index c748696..fb5619c 100644
--- a/CPP/7zip/Compress/PpmdRegister.cpp
+++ b/CPP/7zip/Compress/PpmdRegister.cpp
@@ -1,22 +1,22 @@
-// PpmdRegister.cpp
-
-#include "StdAfx.h"
-
-#include "../Common/RegisterCodec.h"
-
-#include "PpmdDecoder.h"
-
-#ifndef EXTRACT_ONLY
-#include "PpmdEncoder.h"
-#endif
-
-namespace NCompress {
-namespace NPpmd {
-
-REGISTER_CODEC_E(PPMD,
- CDecoder(),
- CEncoder(),
- 0x30401,
- "PPMD")
-
-}}
+// PpmdRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "PpmdDecoder.h"
+
+#ifndef Z7_EXTRACT_ONLY
+#include "PpmdEncoder.h"
+#endif
+
+namespace NCompress {
+namespace NPpmd {
+
+REGISTER_CODEC_E(PPMD,
+ CDecoder(),
+ CEncoder(),
+ 0x30401,
+ "PPMD")
+
+}}
diff --git a/CPP/7zip/Compress/PpmdZip.cpp b/CPP/7zip/Compress/PpmdZip.cpp
new file mode 100644
index 0000000..5039131
--- /dev/null
+++ b/CPP/7zip/Compress/PpmdZip.cpp
@@ -0,0 +1,300 @@
+// PpmdZip.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../Common/RegisterCodec.h"
+#include "../Common/StreamUtils.h"
+
+#include "PpmdZip.h"
+
+namespace NCompress {
+namespace NPpmdZip {
+
+CDecoder::CDecoder(bool fullFileMode):
+ _fullFileMode(fullFileMode)
+{
+ Ppmd8_Construct(&_ppmd);
+ _ppmd.Stream.In = &_inStream.vt;
+}
+
+CDecoder::~CDecoder()
+{
+ Ppmd8_Free(&_ppmd, &g_BigAlloc);
+}
+
+Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ // try {
+
+ if (!_outStream.Alloc())
+ return E_OUTOFMEMORY;
+ if (!_inStream.Alloc(1 << 20))
+ return E_OUTOFMEMORY;
+
+ _inStream.Stream = inStream;
+ _inStream.Init();
+
+ {
+ Byte buf[2];
+ for (int i = 0; i < 2; i++)
+ buf[i] = _inStream.ReadByte();
+ if (_inStream.Extra)
+ return S_FALSE;
+
+ const UInt32 val = GetUi16(buf);
+ const unsigned order = (val & 0xF) + 1;
+ const UInt32 mem = ((val >> 4) & 0xFF) + 1;
+ const unsigned restor = (val >> 12);
+ if (order < 2 || restor > 2)
+ return S_FALSE;
+
+ #ifndef PPMD8_FREEZE_SUPPORT
+ if (restor == 2)
+ return E_NOTIMPL;
+ #endif
+
+ if (!Ppmd8_Alloc(&_ppmd, mem << 20, &g_BigAlloc))
+ return E_OUTOFMEMORY;
+
+ if (!Ppmd8_Init_RangeDec(&_ppmd))
+ return S_FALSE;
+ Ppmd8_Init(&_ppmd, order, restor);
+ }
+
+ bool wasFinished = false;
+ UInt64 processedSize = 0;
+
+ for (;;)
+ {
+ size_t size = kBufSize;
+ if (outSize)
+ {
+ const UInt64 rem = *outSize - processedSize;
+ if (size > rem)
+ {
+ size = (size_t)rem;
+ if (size == 0)
+ break;
+ }
+ }
+
+ int sym;
+ Byte *buf = _outStream.Buf;
+ const Byte *lim = buf + size;
+
+ do
+ {
+ sym = Ppmd8_DecodeSymbol(&_ppmd);
+ if (_inStream.Extra || sym < 0)
+ break;
+ *buf++ = (Byte)sym;
+ }
+ while (buf != lim);
+
+ const size_t cur = (size_t)(buf - _outStream.Buf);
+ processedSize += cur;
+
+ RINOK(WriteStream(outStream, _outStream.Buf, cur))
+
+ RINOK(_inStream.Res)
+ if (_inStream.Extra)
+ return S_FALSE;
+
+ if (sym < 0)
+ {
+ if (sym != -1)
+ return S_FALSE;
+ wasFinished = true;
+ break;
+ }
+
+ if (progress)
+ {
+ const UInt64 inProccessed = _inStream.GetProcessed();
+ RINOK(progress->SetRatioInfo(&inProccessed, &processedSize))
+ }
+ }
+
+ RINOK(_inStream.Res)
+
+ if (_fullFileMode)
+ {
+ if (!wasFinished)
+ {
+ const int res = Ppmd8_DecodeSymbol(&_ppmd);
+ RINOK(_inStream.Res)
+ if (_inStream.Extra || res != -1)
+ return S_FALSE;
+ }
+ if (!Ppmd8_RangeDec_IsFinishedOK(&_ppmd))
+ return S_FALSE;
+
+ if (inSize && *inSize != _inStream.GetProcessed())
+ return S_FALSE;
+ }
+
+ return S_OK;
+
+ // } catch (...) { return E_FAIL; }
+}
+
+
+Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
+{
+ _fullFileMode = (finishMode != 0);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value))
+{
+ *value = _inStream.GetProcessed();
+ return S_OK;
+}
+
+
+
+// ---------- Encoder ----------
+
+void CEncProps::Normalize(int level)
+{
+ if (level < 0) level = 5;
+ if (level == 0) level = 1;
+ if (level > 9) level = 9;
+ if (MemSizeMB == (UInt32)(Int32)-1)
+ MemSizeMB = 1 << (level - 1);
+ const unsigned kMult = 16;
+ for (UInt32 m = 1; m < MemSizeMB; m <<= 1)
+ if (ReduceSize <= (m << 20) / kMult)
+ {
+ MemSizeMB = m;
+ break;
+ }
+ if (Order == -1) Order = 3 + level;
+ if (Restor == -1)
+ Restor = level < 7 ?
+ PPMD8_RESTORE_METHOD_RESTART :
+ PPMD8_RESTORE_METHOD_CUT_OFF;
+}
+
+CEncoder::~CEncoder()
+{
+ Ppmd8_Free(&_ppmd, &g_BigAlloc);
+}
+
+Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps))
+{
+ int level = -1;
+ CEncProps props;
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = coderProps[i];
+ const PROPID propID = propIDs[i];
+ if (propID > NCoderPropID::kReduceSize)
+ continue;
+ if (propID == NCoderPropID::kReduceSize)
+ {
+ props.ReduceSize = (UInt32)(Int32)-1;
+ if (prop.vt == VT_UI8 && prop.uhVal.QuadPart < (UInt32)(Int32)-1)
+ props.ReduceSize = (UInt32)prop.uhVal.QuadPart;
+ continue;
+ }
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ const UInt32 v = (UInt32)prop.ulVal;
+ switch (propID)
+ {
+ case NCoderPropID::kUsedMemorySize:
+ if (v < (1 << 20) || v > (1 << 28))
+ return E_INVALIDARG;
+ props.MemSizeMB = v >> 20;
+ break;
+ case NCoderPropID::kOrder:
+ if (v < PPMD8_MIN_ORDER || v > PPMD8_MAX_ORDER)
+ return E_INVALIDARG;
+ props.Order = (Byte)v;
+ break;
+ case NCoderPropID::kNumThreads: break;
+ case NCoderPropID::kLevel: level = (int)v; break;
+ case NCoderPropID::kAlgorithm:
+ if (v >= PPMD8_RESTORE_METHOD_UNSUPPPORTED)
+ return E_INVALIDARG;
+ props.Restor = (int)v;
+ break;
+ default: return E_INVALIDARG;
+ }
+ }
+ props.Normalize(level);
+ _props = props;
+ return S_OK;
+}
+
+CEncoder::CEncoder()
+{
+ _props.Normalize(-1);
+ _ppmd.Stream.Out = &_outStream.vt;
+ Ppmd8_Construct(&_ppmd);
+}
+
+Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress))
+{
+ if (!_inStream.Alloc())
+ return E_OUTOFMEMORY;
+ if (!_outStream.Alloc(1 << 20))
+ return E_OUTOFMEMORY;
+ if (!Ppmd8_Alloc(&_ppmd, _props.MemSizeMB << 20, &g_BigAlloc))
+ return E_OUTOFMEMORY;
+
+ _outStream.Stream = outStream;
+ _outStream.Init();
+
+ Ppmd8_Init_RangeEnc(&_ppmd)
+ Ppmd8_Init(&_ppmd, (unsigned)_props.Order, (unsigned)_props.Restor);
+
+ {
+ const UInt32 val = (UInt32)(((unsigned)_props.Order - 1) + ((_props.MemSizeMB - 1) << 4) + ((unsigned)_props.Restor << 12));
+ _outStream.WriteByte((Byte)(val & 0xFF));
+ _outStream.WriteByte((Byte)(val >> 8));
+ }
+ RINOK(_outStream.Res)
+
+ UInt64 processed = 0;
+ for (;;)
+ {
+ UInt32 size;
+ RINOK(inStream->Read(_inStream.Buf, kBufSize, &size))
+ if (size == 0)
+ {
+ Ppmd8_EncodeSymbol(&_ppmd, -1);
+ Ppmd8_Flush_RangeEnc(&_ppmd);
+ return _outStream.Flush();
+ }
+
+ processed += size;
+ const Byte *buf = _inStream.Buf;
+ const Byte *lim = buf + size;
+ do
+ {
+ Ppmd8_EncodeSymbol(&_ppmd, *buf);
+ if (_outStream.Res != S_OK)
+ break;
+ }
+ while (++buf != lim);
+
+ RINOK(_outStream.Res)
+
+ if (progress)
+ {
+ const UInt64 outProccessed = _outStream.GetProcessed();
+ RINOK(progress->SetRatioInfo(&processed, &outProccessed))
+ }
+ }
+}
+
+
+
+
+}}
diff --git a/CPP/7zip/Compress/PpmdZip.h b/CPP/7zip/Compress/PpmdZip.h
new file mode 100644
index 0000000..a23d008
--- /dev/null
+++ b/CPP/7zip/Compress/PpmdZip.h
@@ -0,0 +1,85 @@
+// PpmdZip.h
+
+#ifndef ZIP7_INC_COMPRESS_PPMD_ZIP_H
+#define ZIP7_INC_COMPRESS_PPMD_ZIP_H
+
+#include "../../../C/Alloc.h"
+#include "../../../C/Ppmd8.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/CWrappers.h"
+
+namespace NCompress {
+namespace NPpmdZip {
+
+static const UInt32 kBufSize = (1 << 20);
+
+struct CBuf
+{
+ Byte *Buf;
+
+ CBuf(): Buf(NULL) {}
+ ~CBuf() { ::MidFree(Buf); }
+ bool Alloc()
+ {
+ if (!Buf)
+ Buf = (Byte *)::MidAlloc(kBufSize);
+ return (Buf != NULL);
+ }
+};
+
+
+Z7_CLASS_IMP_NOQIB_3(
+ CDecoder
+ , ICompressCoder
+ , ICompressSetFinishMode
+ , ICompressGetInStreamProcessedSize
+)
+ CByteInBufWrap _inStream;
+ CBuf _outStream;
+ CPpmd8 _ppmd;
+ bool _fullFileMode;
+public:
+ CDecoder(bool fullFileMode = true);
+ ~CDecoder();
+};
+
+
+struct CEncProps
+{
+ UInt32 MemSizeMB;
+ UInt32 ReduceSize;
+ int Order;
+ int Restor;
+
+ CEncProps()
+ {
+ MemSizeMB = (UInt32)(Int32)-1;
+ ReduceSize = (UInt32)(Int32)-1;
+ Order = -1;
+ Restor = -1;
+ }
+ void Normalize(int level);
+};
+
+
+Z7_CLASS_IMP_NOQIB_2(
+ CEncoder
+ , ICompressCoder
+ , ICompressSetCoderProperties
+)
+ CByteOutBufWrap _outStream;
+ CBuf _inStream;
+ CPpmd8 _ppmd;
+ CEncProps _props;
+public:
+ CEncoder();
+ ~CEncoder();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/QuantumDecoder.cpp b/CPP/7zip/Compress/QuantumDecoder.cpp
new file mode 100644
index 0000000..16ef0fc
--- /dev/null
+++ b/CPP/7zip/Compress/QuantumDecoder.cpp
@@ -0,0 +1,195 @@
+// QuantumDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../Common/Defs.h"
+
+#include "QuantumDecoder.h"
+
+namespace NCompress {
+namespace NQuantum {
+
+static const unsigned kNumLenSymbols = 27;
+static const unsigned kMatchMinLen = 3;
+static const unsigned kNumSimplePosSlots = 4;
+static const unsigned kNumSimpleLenSlots = 6;
+
+static const UInt16 kUpdateStep = 8;
+static const UInt16 kFreqSumMax = 3800;
+static const unsigned kReorderCountStart = 4;
+static const unsigned kReorderCount = 50;
+
+void CModelDecoder::Init(unsigned numItems)
+{
+ NumItems = numItems;
+ ReorderCount = kReorderCountStart;
+ for (unsigned i = 0; i < numItems; i++)
+ {
+ Freqs[i] = (UInt16)(numItems - i);
+ Vals[i] = (Byte)i;
+ }
+ Freqs[numItems] = 0;
+}
+
+unsigned CModelDecoder::Decode(CRangeDecoder *rc)
+{
+ const UInt32 threshold = rc->GetThreshold(Freqs[0]);
+ unsigned i;
+ for (i = 1; Freqs[i] > threshold; i++);
+
+ rc->Decode(Freqs[i], Freqs[(size_t)i - 1], Freqs[0]);
+ const unsigned res = Vals[--i];
+
+ do
+ Freqs[i] = (UInt16)(Freqs[i] + kUpdateStep);
+ while (i--);
+
+ if (Freqs[0] > kFreqSumMax)
+ {
+ if (--ReorderCount == 0)
+ {
+ ReorderCount = kReorderCount;
+ for (i = 0; i < NumItems; i++)
+ Freqs[i] = (UInt16)(((Freqs[i] - Freqs[(size_t)i + 1]) + 1) >> 1);
+ for (i = 0; i < NumItems - 1; i++)
+ for (unsigned j = i + 1; j < NumItems; j++)
+ if (Freqs[i] < Freqs[j])
+ {
+ const UInt16 tmpFreq = Freqs[i];
+ const Byte tmpVal = Vals[i];
+ Freqs[i] = Freqs[j];
+ Vals[i] = Vals[j];
+ Freqs[j] = tmpFreq;
+ Vals[j] = tmpVal;
+ }
+
+ do
+ Freqs[i] = (UInt16)(Freqs[i] + Freqs[(size_t)i + 1]);
+ while (i--);
+ }
+ else
+ {
+ i = NumItems - 1;
+ do
+ {
+ Freqs[i] = (UInt16)(Freqs[i] >> 1);
+ if (Freqs[i] <= Freqs[(size_t)i + 1])
+ Freqs[i] = (UInt16)(Freqs[(size_t)i + 1] + 1);
+ }
+ while (i--);
+ }
+ }
+
+ return res;
+}
+
+
+void CDecoder::Init()
+{
+ m_Selector.Init(kNumSelectors);
+ unsigned i;
+ for (i = 0; i < kNumLitSelectors; i++)
+ m_Literals[i].Init(kNumLitSymbols);
+ const unsigned numItems = (_numDictBits == 0 ? 1 : (_numDictBits << 1));
+ const unsigned kNumPosSymbolsMax[kNumMatchSelectors] = { 24, 36, 42 };
+ for (i = 0; i < kNumMatchSelectors; i++)
+ m_PosSlot[i].Init(MyMin(numItems, kNumPosSymbolsMax[i]));
+ m_LenSlot.Init(kNumLenSymbols);
+}
+
+
+HRESULT CDecoder::CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize)
+{
+ if (inSize < 2)
+ return S_FALSE;
+
+ CRangeDecoder rc;
+ rc.Stream.SetStreamAndInit(inData, inSize);
+ rc.Init();
+
+ while (outSize != 0)
+ {
+ if (rc.Stream.WasExtraRead())
+ return S_FALSE;
+
+ unsigned selector = m_Selector.Decode(&rc);
+
+ if (selector < kNumLitSelectors)
+ {
+ const Byte b = (Byte)((selector << (8 - kNumLitSelectorBits)) + m_Literals[selector].Decode(&rc));
+ _outWindow.PutByte(b);
+ outSize--;
+ }
+ else
+ {
+ selector -= kNumLitSelectors;
+ unsigned len = selector + kMatchMinLen;
+
+ if (selector == 2)
+ {
+ unsigned lenSlot = m_LenSlot.Decode(&rc);
+ if (lenSlot >= kNumSimpleLenSlots)
+ {
+ lenSlot -= 2;
+ const unsigned numDirectBits = (unsigned)(lenSlot >> 2);
+ len += ((4 | (lenSlot & 3)) << numDirectBits) - 2;
+ if (numDirectBits < 6)
+ len += rc.Stream.ReadBits(numDirectBits);
+ }
+ else
+ len += lenSlot;
+ }
+
+ UInt32 dist = m_PosSlot[selector].Decode(&rc);
+
+ if (dist >= kNumSimplePosSlots)
+ {
+ unsigned numDirectBits = (unsigned)((dist >> 1) - 1);
+ dist = ((2 | (dist & 1)) << numDirectBits) + rc.Stream.ReadBits(numDirectBits);
+ }
+
+ unsigned locLen = len;
+ if (len > outSize)
+ locLen = (unsigned)outSize;
+ if (!_outWindow.CopyBlock(dist, locLen))
+ return S_FALSE;
+ outSize -= locLen;
+ len -= locLen;
+ if (len != 0)
+ return S_FALSE;
+ }
+ }
+
+ return rc.Finish() ? S_OK : S_FALSE;
+}
+
+HRESULT CDecoder::Code(const Byte *inData, size_t inSize,
+ ISequentialOutStream *outStream, UInt32 outSize,
+ bool keepHistory)
+{
+ try
+ {
+ _outWindow.SetStream(outStream);
+ _outWindow.Init(keepHistory);
+ if (!keepHistory)
+ Init();
+
+ const HRESULT res = CodeSpec(inData, inSize, outSize);
+ const HRESULT res2 = _outWindow.Flush();
+ return res != S_OK ? res : res2;
+ }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+HRESULT CDecoder::SetParams(unsigned numDictBits)
+{
+ if (numDictBits > 21)
+ return E_INVALIDARG;
+ _numDictBits = numDictBits;
+ if (!_outWindow.Create((UInt32)1 << _numDictBits))
+ return E_OUTOFMEMORY;
+ return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Compress/QuantumDecoder.h b/CPP/7zip/Compress/QuantumDecoder.h
new file mode 100644
index 0000000..925989a
--- /dev/null
+++ b/CPP/7zip/Compress/QuantumDecoder.h
@@ -0,0 +1,169 @@
+// QuantumDecoder.h
+
+#ifndef ZIP7_INC_COMPRESS_QUANTUM_DECODER_H
+#define ZIP7_INC_COMPRESS_QUANTUM_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NQuantum {
+
+class CBitDecoder
+{
+ UInt32 Value;
+ bool _extra;
+ const Byte *_buf;
+ const Byte *_bufLim;
+public:
+ void SetStreamAndInit(const Byte *inData, size_t inSize)
+ {
+ _buf = inData;
+ _bufLim = inData + inSize;
+ Value = 0x10000;
+ _extra = false;
+ }
+
+ bool WasExtraRead() const { return _extra; }
+
+ bool WasFinishedOK() const
+ {
+ return !_extra && _buf == _bufLim;
+ }
+
+ UInt32 ReadBit()
+ {
+ if (Value >= 0x10000)
+ {
+ Byte b;
+ if (_buf >= _bufLim)
+ {
+ b = 0xFF;
+ _extra = true;
+ }
+ else
+ b = *_buf++;
+ Value = 0x100 | b;
+ }
+ UInt32 res = (Value >> 7) & 1;
+ Value <<= 1;
+ return res;
+ }
+
+ UInt32 ReadStart16Bits()
+ {
+ // we use check for extra read in another code.
+ UInt32 val = ((UInt32)*_buf << 8) | _buf[1];
+ _buf += 2;
+ return val;
+ }
+
+ UInt32 ReadBits(unsigned numBits) // numBits > 0
+ {
+ UInt32 res = 0;
+ do
+ res = (res << 1) | ReadBit();
+ while (--numBits);
+ return res;
+ }
+};
+
+
+class CRangeDecoder
+{
+ UInt32 Low;
+ UInt32 Range;
+ UInt32 Code;
+public:
+ CBitDecoder Stream;
+
+ void Init()
+ {
+ Low = 0;
+ Range = 0x10000;
+ Code = Stream.ReadStart16Bits();
+ }
+
+ bool Finish()
+ {
+ // do all streams use these two bits at end?
+ if (Stream.ReadBit() != 0) return false;
+ if (Stream.ReadBit() != 0) return false;
+ return Stream.WasFinishedOK();
+ }
+
+ UInt32 GetThreshold(UInt32 total) const
+ {
+ return ((Code + 1) * total - 1) / Range; // & 0xFFFF is not required;
+ }
+
+ void Decode(UInt32 start, UInt32 end, UInt32 total)
+ {
+ UInt32 high = Low + end * Range / total - 1;
+ UInt32 offset = start * Range / total;
+ Code -= offset;
+ Low += offset;
+ for (;;)
+ {
+ if ((Low & 0x8000) != (high & 0x8000))
+ {
+ if ((Low & 0x4000) == 0 || (high & 0x4000) != 0)
+ break;
+ Low &= 0x3FFF;
+ high |= 0x4000;
+ }
+ Low = (Low << 1) & 0xFFFF;
+ high = ((high << 1) | 1) & 0xFFFF;
+ Code = ((Code << 1) | Stream.ReadBit());
+ }
+ Range = high - Low + 1;
+ }
+};
+
+
+const unsigned kNumLitSelectorBits = 2;
+const unsigned kNumLitSelectors = (1 << kNumLitSelectorBits);
+const unsigned kNumLitSymbols = 1 << (8 - kNumLitSelectorBits);
+const unsigned kNumMatchSelectors = 3;
+const unsigned kNumSelectors = kNumLitSelectors + kNumMatchSelectors;
+const unsigned kNumSymbolsMax = kNumLitSymbols; // 64
+
+
+class CModelDecoder
+{
+ unsigned NumItems;
+ unsigned ReorderCount;
+ UInt16 Freqs[kNumSymbolsMax + 1];
+ Byte Vals[kNumSymbolsMax];
+public:
+ void Init(unsigned numItems);
+ unsigned Decode(CRangeDecoder *rc);
+};
+
+
+Z7_CLASS_IMP_COM_0(
+ CDecoder
+)
+ CLzOutWindow _outWindow;
+ unsigned _numDictBits;
+
+ CModelDecoder m_Selector;
+ CModelDecoder m_Literals[kNumLitSelectors];
+ CModelDecoder m_PosSlot[kNumMatchSelectors];
+ CModelDecoder m_LenSlot;
+
+ void Init();
+ HRESULT CodeSpec(const Byte *inData, size_t inSize, UInt32 outSize);
+public:
+ HRESULT Code(const Byte *inData, size_t inSize,
+ ISequentialOutStream *outStream, UInt32 outSize,
+ bool keepHistory);
+ HRESULT SetParams(unsigned numDictBits);
+
+ CDecoder(): _numDictBits(0) {}
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/Rar1Decoder.cpp b/CPP/7zip/Compress/Rar1Decoder.cpp
new file mode 100644
index 0000000..050cde2
--- /dev/null
+++ b/CPP/7zip/Compress/Rar1Decoder.cpp
@@ -0,0 +1,518 @@
+// Rar1Decoder.cpp
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#include "StdAfx.h"
+
+#include "Rar1Decoder.h"
+
+namespace NCompress {
+namespace NRar1 {
+
+static const unsigned kNumBits = 12;
+
+static const Byte kShortLen1[16 * 3] =
+{
+ 0,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xfe,0xff,0xc0,0x80,0x90,0x98,0x9c,0xb0,0,
+ 1,3,4,4,5,6,7,8,8,4,4,5,6,6,0,0,
+ 1,4,4,4,5,6,7,8,8,4,4,5,6,6,4,0
+};
+
+static const Byte kShortLen2[16 * 3] =
+{
+ 0,0x40,0x60,0xa0,0xd0,0xe0,0xf0,0xf8,0xfc,0xc0,0x80,0x90,0x98,0x9c,0xb0,0,
+ 2,3,3,3,4,4,5,6,6,4,4,5,6,6,0,0,
+ 2,3,3,4,4,4,5,6,6,4,4,5,6,6,4,0
+};
+
+static const Byte PosL1[kNumBits + 1] = { 0,0,2,1,2,2,4,5,4,4,8,0,224 };
+static const Byte PosL2[kNumBits + 1] = { 0,0,0,5,2,2,4,5,4,4,8,2,220 };
+
+static const Byte PosHf0[kNumBits + 1] = { 0,0,0,0,8,8,8,9,0,0,0,0,224 };
+static const Byte PosHf1[kNumBits + 1] = { 0,0,0,0,0,4,40,16,16,4,0,47,130 };
+static const Byte PosHf2[kNumBits + 1] = { 0,0,0,0,0,2,5,46,64,116,24,0,0 };
+static const Byte PosHf3[kNumBits + 1] = { 0,0,0,0,0,0,2,14,202,33,6,0,0 };
+static const Byte PosHf4[kNumBits + 1] = { 0,0,0,0,0,0,0,0,255,2,0,0,0 };
+
+static const UInt32 kHistorySize = (1 << 16);
+
+CDecoder::CDecoder():
+ _isSolid(false),
+ _solidAllowed(false)
+ {}
+
+UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); }
+
+HRESULT CDecoder::CopyBlock(UInt32 distance, UInt32 len)
+{
+ if (len == 0)
+ return S_FALSE;
+ if (m_UnpackSize < len)
+ return S_FALSE;
+ m_UnpackSize -= len;
+ return m_OutWindowStream.CopyBlock(distance, len) ? S_OK : S_FALSE;
+}
+
+
+UInt32 CDecoder::DecodeNum(const Byte *numTab)
+{
+ /*
+ {
+ // we can check that tables are correct
+ UInt32 sum = 0;
+ for (unsigned i = 0; i <= kNumBits; i++)
+ sum += ((UInt32)numTab[i] << (kNumBits - i));
+ if (sum != (1 << kNumBits))
+ throw 111;
+ }
+ */
+
+ UInt32 val = m_InBitStream.GetValue(kNumBits);
+ UInt32 sum = 0;
+ unsigned i = 2;
+
+ for (;;)
+ {
+ const UInt32 num = numTab[i];
+ const UInt32 cur = num << (kNumBits - i);
+ if (val < cur)
+ break;
+ i++;
+ val -= cur;
+ sum += num;
+ }
+ m_InBitStream.MovePos(i);
+ return ((val >> (kNumBits - i)) + sum);
+}
+
+
+HRESULT CDecoder::ShortLZ()
+{
+ NumHuf = 0;
+
+ if (LCount == 2)
+ {
+ if (ReadBits(1))
+ return CopyBlock(LastDist, LastLength);
+ LCount = 0;
+ }
+
+ UInt32 bitField = m_InBitStream.GetValue(8);
+
+ UInt32 len, dist;
+ {
+ const Byte *xors = (AvrLn1 < 37) ? kShortLen1 : kShortLen2;
+ const Byte *lens = xors + 16 + Buf60;
+ for (len = 0; ((bitField ^ xors[len]) >> (8 - lens[len])) != 0; len++);
+ m_InBitStream.MovePos(lens[len]);
+ }
+
+ if (len >= 9)
+ {
+ if (len == 9)
+ {
+ LCount++;
+ return CopyBlock(LastDist, LastLength);
+ }
+
+ LCount = 0;
+
+ if (len == 14)
+ {
+ len = DecodeNum(PosL2) + 5;
+ dist = 0x8000 + ReadBits(15) - 1;
+ LastLength = len;
+ LastDist = dist;
+ return CopyBlock(dist, len);
+ }
+
+ const UInt32 saveLen = len;
+ dist = m_RepDists[(m_RepDistPtr - (len - 9)) & 3];
+
+ len = DecodeNum(PosL1);
+
+ if (len == 0xff && saveLen == 10)
+ {
+ Buf60 ^= 16;
+ return S_OK;
+ }
+ if (dist >= 256)
+ {
+ len++;
+ if (dist >= MaxDist3 - 1)
+ len++;
+ }
+ }
+ else
+ {
+ LCount = 0;
+ AvrLn1 += len;
+ AvrLn1 -= AvrLn1 >> 4;
+
+ unsigned distancePlace = DecodeNum(PosHf2) & 0xff;
+
+ dist = ChSetA[distancePlace];
+
+ if (distancePlace != 0)
+ {
+ PlaceA[dist]--;
+ UInt32 lastDistance = ChSetA[(size_t)distancePlace - 1];
+ PlaceA[lastDistance]++;
+ ChSetA[distancePlace] = lastDistance;
+ ChSetA[(size_t)distancePlace - 1] = dist;
+ }
+ }
+
+ m_RepDists[m_RepDistPtr++] = dist;
+ m_RepDistPtr &= 3;
+ len += 2;
+ LastLength = len;
+ LastDist = dist;
+ return CopyBlock(dist, len);
+}
+
+
+HRESULT CDecoder::LongLZ()
+{
+ UInt32 len;
+ UInt32 dist;
+ UInt32 distancePlace, newDistancePlace;
+ UInt32 oldAvr2, oldAvr3;
+
+ NumHuf = 0;
+ Nlzb += 16;
+ if (Nlzb > 0xff)
+ {
+ Nlzb = 0x90;
+ Nhfb >>= 1;
+ }
+ oldAvr2 = AvrLn2;
+
+ if (AvrLn2 >= 64)
+ len = DecodeNum(AvrLn2 < 122 ? PosL1 : PosL2);
+ else
+ {
+ UInt32 bitField = m_InBitStream.GetValue(16);
+ if (bitField < 0x100)
+ {
+ len = bitField;
+ m_InBitStream.MovePos(16);
+ }
+ else
+ {
+ for (len = 0; ((bitField << len) & 0x8000) == 0; len++);
+
+ m_InBitStream.MovePos(len + 1);
+ }
+ }
+
+ AvrLn2 += len;
+ AvrLn2 -= AvrLn2 >> 5;
+
+ {
+ const Byte *tab;
+ if (AvrPlcB >= 0x2900) tab = PosHf2;
+ else if (AvrPlcB >= 0x0700) tab = PosHf1;
+ else tab = PosHf0;
+ distancePlace = DecodeNum(tab); // [0, 256]
+ }
+
+ AvrPlcB += distancePlace;
+ AvrPlcB -= AvrPlcB >> 8;
+
+ distancePlace &= 0xff;
+
+ for (;;)
+ {
+ dist = ChSetB[distancePlace];
+ newDistancePlace = NToPlB[dist++ & 0xff]++;
+ if (dist & 0xff)
+ break;
+ CorrHuff(ChSetB,NToPlB);
+ }
+
+ ChSetB[distancePlace] = ChSetB[newDistancePlace];
+ ChSetB[newDistancePlace] = dist;
+
+ dist = ((dist & 0xff00) >> 1) | ReadBits(7);
+
+ oldAvr3 = AvrLn3;
+
+ if (len != 1 && len != 4)
+ {
+ if (len == 0 && dist <= MaxDist3)
+ {
+ AvrLn3++;
+ AvrLn3 -= AvrLn3 >> 8;
+ }
+ else if (AvrLn3 > 0)
+ AvrLn3--;
+ }
+
+ len += 3;
+
+ if (dist >= MaxDist3)
+ len++;
+ if (dist <= 256)
+ len += 8;
+
+ if (oldAvr3 > 0xb0 || (AvrPlc >= 0x2a00 && oldAvr2 < 0x40))
+ MaxDist3 = 0x7f00;
+ else
+ MaxDist3 = 0x2001;
+
+ m_RepDists[m_RepDistPtr++] = --dist;
+ m_RepDistPtr &= 3;
+ LastLength = len;
+ LastDist = dist;
+
+ return CopyBlock(dist, len);
+}
+
+
+HRESULT CDecoder::HuffDecode()
+{
+ UInt32 curByte, newBytePlace;
+ UInt32 len;
+ UInt32 dist;
+ unsigned bytePlace;
+ {
+ const Byte *tab;
+
+ if (AvrPlc >= 0x7600) tab = PosHf4;
+ else if (AvrPlc >= 0x5e00) tab = PosHf3;
+ else if (AvrPlc >= 0x3600) tab = PosHf2;
+ else if (AvrPlc >= 0x0e00) tab = PosHf1;
+ else tab = PosHf0;
+
+ bytePlace = DecodeNum(tab); // [0, 256]
+ }
+
+ if (StMode)
+ {
+ if (bytePlace == 0)
+ {
+ if (ReadBits(1))
+ {
+ NumHuf = 0;
+ StMode = false;
+ return S_OK;
+ }
+ len = ReadBits(1) + 3;
+ dist = DecodeNum(PosHf2);
+ dist = (dist << 5) | ReadBits(5);
+ if (dist == 0)
+ return S_FALSE;
+ return CopyBlock(dist - 1, len);
+ }
+ bytePlace--; // bytePlace is [0, 255]
+ }
+ else if (NumHuf++ >= 16 && FlagsCnt == 0)
+ StMode = true;
+
+ bytePlace &= 0xff;
+ AvrPlc += bytePlace;
+ AvrPlc -= AvrPlc >> 8;
+ Nhfb += 16;
+
+ if (Nhfb > 0xff)
+ {
+ Nhfb = 0x90;
+ Nlzb >>= 1;
+ }
+
+ m_UnpackSize--;
+ m_OutWindowStream.PutByte((Byte)(ChSet[bytePlace] >> 8));
+
+ for (;;)
+ {
+ curByte = ChSet[bytePlace];
+ newBytePlace = NToPl[curByte++ & 0xff]++;
+ if ((curByte & 0xff) <= 0xa1)
+ break;
+ CorrHuff(ChSet, NToPl);
+ }
+
+ ChSet[bytePlace] = ChSet[newBytePlace];
+ ChSet[newBytePlace] = curByte;
+ return S_OK;
+}
+
+
+void CDecoder::GetFlagsBuf()
+{
+ UInt32 flags, newFlagsPlace;
+ const UInt32 flagsPlace = DecodeNum(PosHf2); // [0, 256]
+
+ if (flagsPlace >= Z7_ARRAY_SIZE(ChSetC))
+ return;
+
+ for (;;)
+ {
+ flags = ChSetC[flagsPlace];
+ FlagBuf = flags >> 8;
+ newFlagsPlace = NToPlC[flags++ & 0xff]++;
+ if ((flags & 0xff) != 0)
+ break;
+ CorrHuff(ChSetC, NToPlC);
+ }
+
+ ChSetC[flagsPlace] = ChSetC[newFlagsPlace];
+ ChSetC[newFlagsPlace] = flags;
+}
+
+
+void CDecoder::CorrHuff(UInt32 *CharSet, UInt32 *NumToPlace)
+{
+ int i;
+ for (i = 7; i >= 0; i--)
+ for (unsigned j = 0; j < 32; j++, CharSet++)
+ *CharSet = (*CharSet & ~(UInt32)0xff) | (unsigned)i;
+ memset(NumToPlace, 0, sizeof(NToPl));
+ for (i = 6; i >= 0; i--)
+ NumToPlace[i] = (7 - (unsigned)i) * 32;
+}
+
+
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo * /* progress */)
+{
+ if (!inSize || !outSize)
+ return E_INVALIDARG;
+
+ if (_isSolid && !_solidAllowed)
+ return S_FALSE;
+
+ _solidAllowed = false;
+
+ if (!m_OutWindowStream.Create(kHistorySize))
+ return E_OUTOFMEMORY;
+ if (!m_InBitStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+
+ m_UnpackSize = *outSize;
+
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(_isSolid);
+ m_InBitStream.SetStream(inStream);
+ m_InBitStream.Init();
+
+ // InitData
+
+ FlagsCnt = 0;
+ FlagBuf = 0;
+ StMode = false;
+ LCount = 0;
+
+ if (!_isSolid)
+ {
+ AvrPlcB = AvrLn1 = AvrLn2 = AvrLn3 = NumHuf = Buf60 = 0;
+ AvrPlc = 0x3500;
+ MaxDist3 = 0x2001;
+ Nhfb = Nlzb = 0x80;
+
+ {
+ // InitStructures
+ for (unsigned i = 0; i < kNumRepDists; i++)
+ m_RepDists[i] = 0;
+ m_RepDistPtr = 0;
+ LastLength = 0;
+ LastDist = 0;
+ }
+
+ // InitHuff
+
+ for (UInt32 i = 0; i < 256; i++)
+ {
+ Place[i] = PlaceA[i] = PlaceB[i] = i;
+ UInt32 c = (~i + 1) & 0xff;
+ PlaceC[i] = c;
+ ChSet[i] = ChSetB[i] = i << 8;
+ ChSetA[i] = i;
+ ChSetC[i] = c << 8;
+ }
+ memset(NToPl, 0, sizeof(NToPl));
+ memset(NToPlB, 0, sizeof(NToPlB));
+ memset(NToPlC, 0, sizeof(NToPlC));
+ CorrHuff(ChSetB, NToPlB);
+ }
+
+ if (m_UnpackSize > 0)
+ {
+ GetFlagsBuf();
+ FlagsCnt = 8;
+ }
+
+ while (m_UnpackSize != 0)
+ {
+ if (!StMode)
+ {
+ if (--FlagsCnt < 0)
+ {
+ GetFlagsBuf();
+ FlagsCnt = 7;
+ }
+
+ if (FlagBuf & 0x80)
+ {
+ FlagBuf <<= 1;
+ if (Nlzb > Nhfb)
+ {
+ RINOK(LongLZ())
+ continue;
+ }
+ }
+ else
+ {
+ FlagBuf <<= 1;
+
+ if (--FlagsCnt < 0)
+ {
+ GetFlagsBuf();
+ FlagsCnt = 7;
+ }
+
+ if ((FlagBuf & 0x80) == 0)
+ {
+ FlagBuf <<= 1;
+ RINOK(ShortLZ())
+ continue;
+ }
+
+ FlagBuf <<= 1;
+
+ if (Nlzb <= Nhfb)
+ {
+ RINOK(LongLZ())
+ continue;
+ }
+ }
+ }
+
+ RINOK(HuffDecode())
+ }
+
+ _solidAllowed = true;
+ return m_OutWindowStream.Flush();
+}
+
+
+Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size))
+{
+ if (size < 1)
+ return E_INVALIDARG;
+ _isSolid = ((data[0] & 1) != 0);
+ return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Compress/Rar1Decoder.h b/CPP/7zip/Compress/Rar1Decoder.h
new file mode 100644
index 0000000..6d0e31d
--- /dev/null
+++ b/CPP/7zip/Compress/Rar1Decoder.h
@@ -0,0 +1,71 @@
+// Rar1Decoder.h
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#ifndef ZIP7_INC_COMPRESS_RAR1_DECODER_H
+#define ZIP7_INC_COMPRESS_RAR1_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitmDecoder.h"
+#include "HuffmanDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NRar1 {
+
+const UInt32 kNumRepDists = 4;
+
+Z7_CLASS_IMP_COM_2(
+ CDecoder
+ , ICompressCoder
+ , ICompressSetDecoderProperties2
+)
+ CLzOutWindow m_OutWindowStream;
+ NBitm::CDecoder<CInBuffer> m_InBitStream;
+
+ UInt64 m_UnpackSize;
+
+ UInt32 LastDist;
+ UInt32 LastLength;
+
+ UInt32 m_RepDistPtr;
+ UInt32 m_RepDists[kNumRepDists];
+
+ bool _isSolid;
+ bool _solidAllowed;
+
+ bool StMode;
+ int FlagsCnt;
+ UInt32 FlagBuf, AvrPlc, AvrPlcB, AvrLn1, AvrLn2, AvrLn3;
+ unsigned Buf60, NumHuf, LCount;
+ UInt32 Nhfb, Nlzb, MaxDist3;
+
+ UInt32 ChSet[256], ChSetA[256], ChSetB[256], ChSetC[256];
+ UInt32 Place[256], PlaceA[256], PlaceB[256], PlaceC[256];
+ UInt32 NToPl[256], NToPlB[256], NToPlC[256];
+
+ UInt32 ReadBits(unsigned numBits);
+ HRESULT CopyBlock(UInt32 distance, UInt32 len);
+ UInt32 DecodeNum(const Byte *numTab);
+ HRESULT ShortLZ();
+ HRESULT LongLZ();
+ HRESULT HuffDecode();
+ void GetFlagsBuf();
+ void CorrHuff(UInt32 *CharSet, UInt32 *NumToPlace);
+ void OldUnpWriteBuf();
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+public:
+ CDecoder();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/Rar2Decoder.cpp b/CPP/7zip/Compress/Rar2Decoder.cpp
new file mode 100644
index 0000000..92404b6
--- /dev/null
+++ b/CPP/7zip/Compress/Rar2Decoder.cpp
@@ -0,0 +1,441 @@
+// Rar2Decoder.cpp
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#include "StdAfx.h"
+
+#include <stdlib.h>
+
+#include "Rar2Decoder.h"
+
+namespace NCompress {
+namespace NRar2 {
+
+namespace NMultimedia {
+
+#define my_abs(x) (unsigned)abs(x)
+
+Byte CFilter::Decode(int &channelDelta, Byte deltaByte)
+{
+ D4 = D3;
+ D3 = D2;
+ D2 = LastDelta - D1;
+ D1 = LastDelta;
+ const int predictedValue = ((8 * LastChar + K1 * D1 + K2 * D2 + K3 * D3 + K4 * D4 + K5 * channelDelta) >> 3);
+
+ const Byte realValue = (Byte)(predictedValue - deltaByte);
+
+ {
+ const int i = ((int)(signed char)deltaByte) << 3;
+
+ Dif[0] += my_abs(i);
+ Dif[1] += my_abs(i - D1);
+ Dif[2] += my_abs(i + D1);
+ Dif[3] += my_abs(i - D2);
+ Dif[4] += my_abs(i + D2);
+ Dif[5] += my_abs(i - D3);
+ Dif[6] += my_abs(i + D3);
+ Dif[7] += my_abs(i - D4);
+ Dif[8] += my_abs(i + D4);
+ Dif[9] += my_abs(i - channelDelta);
+ Dif[10] += my_abs(i + channelDelta);
+ }
+
+ channelDelta = LastDelta = (signed char)(realValue - LastChar);
+ LastChar = realValue;
+
+ if (((++ByteCount) & 0x1F) == 0)
+ {
+ UInt32 minDif = Dif[0];
+ UInt32 numMinDif = 0;
+ Dif[0] = 0;
+
+ for (unsigned i = 1; i < Z7_ARRAY_SIZE(Dif); i++)
+ {
+ if (Dif[i] < minDif)
+ {
+ minDif = Dif[i];
+ numMinDif = i;
+ }
+ Dif[i] = 0;
+ }
+
+ switch (numMinDif)
+ {
+ case 1: if (K1 >= -16) K1--; break;
+ case 2: if (K1 < 16) K1++; break;
+ case 3: if (K2 >= -16) K2--; break;
+ case 4: if (K2 < 16) K2++; break;
+ case 5: if (K3 >= -16) K3--; break;
+ case 6: if (K3 < 16) K3++; break;
+ case 7: if (K4 >= -16) K4--; break;
+ case 8: if (K4 < 16) K4++; break;
+ case 9: if (K5 >= -16) K5--; break;
+ case 10:if (K5 < 16) K5++; break;
+ }
+ }
+
+ return realValue;
+}
+}
+
+static const UInt32 kHistorySize = 1 << 20;
+
+// static const UInt32 kWindowReservSize = (1 << 22) + 256;
+
+CDecoder::CDecoder():
+ _isSolid(false),
+ _solidAllowed(false),
+ m_TablesOK(false)
+{
+}
+
+void CDecoder::InitStructures()
+{
+ m_MmFilter.Init();
+ for (unsigned i = 0; i < kNumRepDists; i++)
+ m_RepDists[i] = 0;
+ m_RepDistPtr = 0;
+ m_LastLength = 0;
+ memset(m_LastLevels, 0, kMaxTableSize);
+}
+
+UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.ReadBits(numBits); }
+
+#define RIF(x) { if (!(x)) return false; }
+
+bool CDecoder::ReadTables(void)
+{
+ m_TablesOK = false;
+
+ Byte levelLevels[kLevelTableSize];
+ Byte lens[kMaxTableSize];
+
+ m_AudioMode = (ReadBits(1) == 1);
+
+ if (ReadBits(1) == 0)
+ memset(m_LastLevels, 0, kMaxTableSize);
+
+ unsigned numLevels;
+
+ if (m_AudioMode)
+ {
+ m_NumChannels = ReadBits(2) + 1;
+ if (m_MmFilter.CurrentChannel >= m_NumChannels)
+ m_MmFilter.CurrentChannel = 0;
+ numLevels = m_NumChannels * kMMTableSize;
+ }
+ else
+ numLevels = kHeapTablesSizesSum;
+
+ unsigned i;
+ for (i = 0; i < kLevelTableSize; i++)
+ levelLevels[i] = (Byte)ReadBits(4);
+ RIF(m_LevelDecoder.Build(levelLevels))
+
+ i = 0;
+
+ do
+ {
+ const UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream);
+ if (sym < kTableDirectLevels)
+ {
+ lens[i] = (Byte)((sym + m_LastLevels[i]) & kLevelMask);
+ i++;
+ }
+ else
+ {
+ if (sym == kTableLevelRepNumber)
+ {
+ unsigned num = ReadBits(2) + 3;
+ if (i == 0)
+ return false;
+ num += i;
+ if (num > numLevels)
+ {
+ // return false;
+ num = numLevels; // original unRAR
+ }
+ const Byte v = lens[(size_t)i - 1];
+ do
+ lens[i++] = v;
+ while (i < num);
+ }
+ else
+ {
+ unsigned num;
+ if (sym == kTableLevel0Number)
+ num = ReadBits(3) + 3;
+ else if (sym == kTableLevel0Number2)
+ num = ReadBits(7) + 11;
+ else
+ return false;
+ num += i;
+ if (num > numLevels)
+ {
+ // return false;
+ num = numLevels; // original unRAR
+ }
+ do
+ lens[i++] = 0;
+ while (i < num);
+ }
+ }
+ }
+ while (i < numLevels);
+
+ if (m_InBitStream.ExtraBitsWereRead())
+ return false;
+
+ if (m_AudioMode)
+ for (i = 0; i < m_NumChannels; i++)
+ {
+ RIF(m_MMDecoders[i].Build(&lens[i * kMMTableSize]))
+ }
+ else
+ {
+ RIF(m_MainDecoder.Build(&lens[0]))
+ RIF(m_DistDecoder.Build(&lens[kMainTableSize]))
+ RIF(m_LenDecoder.Build(&lens[kMainTableSize + kDistTableSize]))
+ }
+
+ memcpy(m_LastLevels, lens, kMaxTableSize);
+
+ m_TablesOK = true;
+
+ return true;
+}
+
+bool CDecoder::ReadLastTables()
+{
+ // it differs a little from pure RAR sources;
+ // UInt64 ttt = m_InBitStream.GetProcessedSize() + 2;
+ // + 2 works for: return 0xFF; in CInBuffer::ReadByte.
+ if (m_InBitStream.GetProcessedSize() + 7 <= m_PackSize) // test it: probably incorrect;
+ // if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect;
+ {
+ if (m_AudioMode)
+ {
+ const UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream);
+ if (symbol == 256)
+ return ReadTables();
+ if (symbol >= kMMTableSize)
+ return false;
+ }
+ else
+ {
+ const UInt32 sym = m_MainDecoder.Decode(&m_InBitStream);
+ if (sym == kReadTableNumber)
+ return ReadTables();
+ if (sym >= kMainTableSize)
+ return false;
+ }
+ }
+ return true;
+}
+
+
+bool CDecoder::DecodeMm(UInt32 pos)
+{
+ while (pos-- != 0)
+ {
+ const UInt32 symbol = m_MMDecoders[m_MmFilter.CurrentChannel].Decode(&m_InBitStream);
+ if (m_InBitStream.ExtraBitsWereRead())
+ return false;
+ if (symbol >= 256)
+ return symbol == 256;
+ /*
+ Byte byPredict = m_Predictor.Predict();
+ Byte byReal = (Byte)(byPredict - (Byte)symbol);
+ m_Predictor.Update(byReal, byPredict);
+ */
+ const Byte byReal = m_MmFilter.Decode((Byte)symbol);
+ m_OutWindowStream.PutByte(byReal);
+ if (++m_MmFilter.CurrentChannel == m_NumChannels)
+ m_MmFilter.CurrentChannel = 0;
+ }
+ return true;
+}
+
+bool CDecoder::DecodeLz(Int32 pos)
+{
+ while (pos > 0)
+ {
+ UInt32 sym = m_MainDecoder.Decode(&m_InBitStream);
+ if (m_InBitStream.ExtraBitsWereRead())
+ return false;
+ UInt32 length, distance;
+ if (sym < 256)
+ {
+ m_OutWindowStream.PutByte(Byte(sym));
+ pos--;
+ continue;
+ }
+ else if (sym >= kMatchNumber)
+ {
+ if (sym >= kMainTableSize)
+ return false;
+ sym -= kMatchNumber;
+ length = kNormalMatchMinLen + UInt32(kLenStart[sym]) +
+ m_InBitStream.ReadBits(kLenDirectBits[sym]);
+ sym = m_DistDecoder.Decode(&m_InBitStream);
+ if (sym >= kDistTableSize)
+ return false;
+ distance = kDistStart[sym] + m_InBitStream.ReadBits(kDistDirectBits[sym]);
+ if (distance >= kDistLimit3)
+ {
+ length += 2 - ((distance - kDistLimit4) >> 31);
+ // length++;
+ // if (distance >= kDistLimit4)
+ // length++;
+ }
+ }
+ else if (sym == kRepBothNumber)
+ {
+ length = m_LastLength;
+ if (length == 0)
+ return false;
+ distance = m_RepDists[(m_RepDistPtr + 4 - 1) & 3];
+ }
+ else if (sym < kLen2Number)
+ {
+ distance = m_RepDists[(m_RepDistPtr - (sym - kRepNumber + 1)) & 3];
+ sym = m_LenDecoder.Decode(&m_InBitStream);
+ if (sym >= kLenTableSize)
+ return false;
+ length = 2 + kLenStart[sym] + m_InBitStream.ReadBits(kLenDirectBits[sym]);
+ if (distance >= kDistLimit2)
+ {
+ length++;
+ if (distance >= kDistLimit3)
+ {
+ length += 2 - ((distance - kDistLimit4) >> 31);
+ // length++;
+ // if (distance >= kDistLimit4)
+ // length++;
+ }
+ }
+ }
+ else if (sym < kReadTableNumber)
+ {
+ sym -= kLen2Number;
+ distance = kLen2DistStarts[sym] +
+ m_InBitStream.ReadBits(kLen2DistDirectBits[sym]);
+ length = 2;
+ }
+ else // (sym == kReadTableNumber)
+ return true;
+
+ m_RepDists[m_RepDistPtr++ & 3] = distance;
+ m_LastLength = length;
+ if (!m_OutWindowStream.CopyBlock(distance, length))
+ return false;
+ pos -= length;
+ }
+ return true;
+}
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ if (!inSize || !outSize)
+ return E_INVALIDARG;
+
+ if (_isSolid && !_solidAllowed)
+ return S_FALSE;
+ _solidAllowed = false;
+
+ if (!m_OutWindowStream.Create(kHistorySize))
+ return E_OUTOFMEMORY;
+ if (!m_InBitStream.Create(1 << 20))
+ return E_OUTOFMEMORY;
+
+ m_PackSize = *inSize;
+
+ UInt64 pos = 0, unPackSize = *outSize;
+
+ m_OutWindowStream.SetStream(outStream);
+ m_OutWindowStream.Init(_isSolid);
+ m_InBitStream.SetStream(inStream);
+ m_InBitStream.Init();
+
+ // CCoderReleaser coderReleaser(this);
+ if (!_isSolid)
+ {
+ InitStructures();
+ if (unPackSize == 0)
+ {
+ if (m_InBitStream.GetProcessedSize() + 2 <= m_PackSize) // test it: probably incorrect;
+ if (!ReadTables())
+ return S_FALSE;
+ _solidAllowed = true;
+ return S_OK;
+ }
+ ReadTables();
+ }
+
+ if (!m_TablesOK)
+ return S_FALSE;
+
+ const UInt64 startPos = m_OutWindowStream.GetProcessedSize();
+ while (pos < unPackSize)
+ {
+ UInt32 blockSize = 1 << 20;
+ if (blockSize > unPackSize - pos)
+ blockSize = (UInt32)(unPackSize - pos);
+ UInt64 blockStartPos = m_OutWindowStream.GetProcessedSize();
+ if (m_AudioMode)
+ {
+ if (!DecodeMm(blockSize))
+ return S_FALSE;
+ }
+ else
+ {
+ if (!DecodeLz((Int32)blockSize))
+ return S_FALSE;
+ }
+
+ if (m_InBitStream.ExtraBitsWereRead())
+ return S_FALSE;
+
+ const UInt64 globalPos = m_OutWindowStream.GetProcessedSize();
+ pos = globalPos - blockStartPos;
+ if (pos < blockSize)
+ if (!ReadTables())
+ return S_FALSE;
+ pos = globalPos - startPos;
+ if (progress)
+ {
+ const UInt64 packSize = m_InBitStream.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &pos))
+ }
+ }
+ if (pos > unPackSize)
+ return S_FALSE;
+
+ if (!ReadLastTables())
+ return S_FALSE;
+
+ _solidAllowed = true;
+
+ return m_OutWindowStream.Flush();
+}
+
+Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const CLzOutWindowException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size))
+{
+ if (size < 1)
+ return E_INVALIDARG;
+ _isSolid = ((data[0] & 1) != 0);
+ return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Compress/Rar2Decoder.h b/CPP/7zip/Compress/Rar2Decoder.h
new file mode 100644
index 0000000..d77bfc1
--- /dev/null
+++ b/CPP/7zip/Compress/Rar2Decoder.h
@@ -0,0 +1,164 @@
+// Rar2Decoder.h
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#ifndef ZIP7_INC_COMPRESS_RAR2_DECODER_H
+#define ZIP7_INC_COMPRESS_RAR2_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitmDecoder.h"
+#include "HuffmanDecoder.h"
+#include "LzOutWindow.h"
+
+namespace NCompress {
+namespace NRar2 {
+
+const unsigned kNumRepDists = 4;
+const unsigned kDistTableSize = 48;
+
+const unsigned kMMTableSize = 256 + 1;
+
+const UInt32 kMainTableSize = 298;
+const UInt32 kLenTableSize = 28;
+
+const UInt32 kDistTableStart = kMainTableSize;
+const UInt32 kLenTableStart = kDistTableStart + kDistTableSize;
+
+const UInt32 kHeapTablesSizesSum = kMainTableSize + kDistTableSize + kLenTableSize;
+
+const UInt32 kLevelTableSize = 19;
+
+const UInt32 kMMTablesSizesSum = kMMTableSize * 4;
+
+const UInt32 kMaxTableSize = kMMTablesSizesSum;
+
+const UInt32 kTableDirectLevels = 16;
+const UInt32 kTableLevelRepNumber = kTableDirectLevels;
+const UInt32 kTableLevel0Number = kTableLevelRepNumber + 1;
+const UInt32 kTableLevel0Number2 = kTableLevel0Number + 1;
+
+const UInt32 kLevelMask = 0xF;
+
+
+const UInt32 kRepBothNumber = 256;
+const UInt32 kRepNumber = kRepBothNumber + 1;
+const UInt32 kLen2Number = kRepNumber + 4;
+
+const UInt32 kLen2NumNumbers = 8;
+const UInt32 kReadTableNumber = kLen2Number + kLen2NumNumbers;
+const UInt32 kMatchNumber = kReadTableNumber + 1;
+
+const Byte kLenStart [kLenTableSize] = {0,1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32,40,48,56,64,80,96,112,128,160,192,224};
+const Byte kLenDirectBits[kLenTableSize] = {0,0,0,0,0,0,0,0,1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5};
+
+const UInt32 kDistStart [kDistTableSize] = {0,1,2,3,4,6,8,12,16,24,32,48,64,96,128,192,256,384,512,768,1024,1536,2048,3072,4096,6144,8192,12288,16384,24576,32768U,49152U,65536,98304,131072,196608,262144,327680,393216,458752,524288,589824,655360,720896,786432,851968,917504,983040};
+const Byte kDistDirectBits[kDistTableSize] = {0,0,0,0,1,1,2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16};
+
+const Byte kLevelDirectBits[kLevelTableSize] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 7};
+
+const Byte kLen2DistStarts[kLen2NumNumbers]={0,4,8,16,32,64,128,192};
+const Byte kLen2DistDirectBits[kLen2NumNumbers]={2,2,3, 4, 5, 6, 6, 6};
+
+const UInt32 kDistLimit2 = 0x101 - 1;
+const UInt32 kDistLimit3 = 0x2000 - 1;
+const UInt32 kDistLimit4 = 0x40000 - 1;
+
+const UInt32 kMatchMaxLen = 255 + 2;
+const UInt32 kMatchMaxLenMax = 255 + 5;
+const UInt32 kNormalMatchMinLen = 3;
+
+namespace NMultimedia {
+
+struct CFilter
+{
+ int K1,K2,K3,K4,K5;
+ int D1,D2,D3,D4;
+ int LastDelta;
+ UInt32 Dif[11];
+ UInt32 ByteCount;
+ int LastChar;
+
+ Byte Decode(int &channelDelta, Byte delta);
+
+ void Init() { memset(this, 0, sizeof(*this)); }
+
+};
+
+const unsigned kNumChanelsMax = 4;
+
+class CFilter2
+{
+public:
+ CFilter m_Filters[kNumChanelsMax];
+ int m_ChannelDelta;
+ unsigned CurrentChannel;
+
+ void Init() { memset(this, 0, sizeof(*this)); }
+ Byte Decode(Byte delta)
+ {
+ return m_Filters[CurrentChannel].Decode(m_ChannelDelta, delta);
+ }
+
+};
+
+}
+
+typedef NBitm::CDecoder<CInBuffer> CBitDecoder;
+
+const unsigned kNumHuffmanBits = 15;
+
+Z7_CLASS_IMP_NOQIB_2(
+ CDecoder
+ , ICompressCoder
+ , ICompressSetDecoderProperties2
+)
+ CLzOutWindow m_OutWindowStream;
+ CBitDecoder m_InBitStream;
+
+ UInt32 m_RepDistPtr;
+ UInt32 m_RepDists[kNumRepDists];
+
+ UInt32 m_LastLength;
+
+ bool _isSolid;
+ bool _solidAllowed;
+ bool m_TablesOK;
+ bool m_AudioMode;
+
+ NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kDistTableSize> m_DistDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kLenTableSize> m_LenDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kMMTableSize> m_MMDecoders[NMultimedia::kNumChanelsMax];
+ NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
+
+ UInt64 m_PackSize;
+
+ unsigned m_NumChannels;
+ NMultimedia::CFilter2 m_MmFilter;
+
+ Byte m_LastLevels[kMaxTableSize];
+
+
+ void InitStructures();
+ UInt32 ReadBits(unsigned numBits);
+ bool ReadTables();
+ bool ReadLastTables();
+
+ bool DecodeMm(UInt32 pos);
+ bool DecodeLz(Int32 pos);
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+
+public:
+ CDecoder();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/Rar3Decoder.cpp b/CPP/7zip/Compress/Rar3Decoder.cpp
new file mode 100644
index 0000000..a4943ad
--- /dev/null
+++ b/CPP/7zip/Compress/Rar3Decoder.cpp
@@ -0,0 +1,935 @@
+// Rar3Decoder.cpp
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+/* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "Rar3Decoder.h"
+
+namespace NCompress {
+namespace NRar3 {
+
+static const UInt32 kNumAlignReps = 15;
+
+static const UInt32 kSymbolReadTable = 256;
+static const UInt32 kSymbolRep = 259;
+
+static const Byte kDistDirectBits[kDistTableSize] =
+ {0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,
+ 16,16,16,16,16,16,16,16,16,16,16,16,16,16,
+ 18,18,18,18,18,18,18,18,18,18,18,18};
+
+static const Byte kLen2DistStarts[kNumLen2Symbols] = {0,4,8,16,32,64,128,192};
+static const Byte kLen2DistDirectBits[kNumLen2Symbols] = {2,2,3, 4, 5, 6, 6, 6};
+
+static const UInt32 kDistLimit3 = 0x2000 - 2;
+static const UInt32 kDistLimit4 = 0x40000 - 2;
+
+static const UInt32 kNormalMatchMinLen = 3;
+
+static const UInt32 kVmDataSizeMax = 1 << 16;
+static const UInt32 kVmCodeSizeMax = 1 << 16;
+
+extern "C" {
+
+static Byte Wrap_ReadByte(IByteInPtr pp) throw()
+{
+ CByteIn *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CByteIn, IByteIn_obj);
+ return p->BitDecoder.Stream.ReadByte();
+}
+
+static Byte Wrap_ReadBits8(IByteInPtr pp) throw()
+{
+ CByteIn *p = Z7_CONTAINER_FROM_VTBL_CLS(pp, CByteIn, IByteIn_obj);
+ return (Byte)p->BitDecoder.ReadByteFromAligned();
+}
+
+}
+
+
+CDecoder::CDecoder():
+ _window(NULL),
+ _winPos(0),
+ _wrPtr(0),
+ _lzSize(0),
+ _writtenFileSize(0),
+ _vmData(NULL),
+ _vmCode(NULL),
+ _isSolid(false),
+ _solidAllowed(false)
+{
+ Ppmd7_Construct(&_ppmd);
+
+ UInt32 start = 0;
+ for (UInt32 i = 0; i < kDistTableSize; i++)
+ {
+ kDistStart[i] = start;
+ start += ((UInt32)1 << kDistDirectBits[i]);
+ }
+}
+
+CDecoder::~CDecoder()
+{
+ InitFilters();
+ ::MidFree(_vmData);
+ ::MidFree(_window);
+ Ppmd7_Free(&_ppmd, &g_BigAlloc);
+}
+
+HRESULT CDecoder::WriteDataToStream(const Byte *data, UInt32 size)
+{
+ return WriteStream(_outStream, data, size);
+}
+
+HRESULT CDecoder::WriteData(const Byte *data, UInt32 size)
+{
+ HRESULT res = S_OK;
+ if (_writtenFileSize < _unpackSize)
+ {
+ UInt32 curSize = size;
+ UInt64 remain = _unpackSize - _writtenFileSize;
+ if (remain < curSize)
+ curSize = (UInt32)remain;
+ res = WriteDataToStream(data, curSize);
+ }
+ _writtenFileSize += size;
+ return res;
+}
+
+HRESULT CDecoder::WriteArea(UInt32 startPtr, UInt32 endPtr)
+{
+ if (startPtr <= endPtr)
+ return WriteData(_window + startPtr, endPtr - startPtr);
+ RINOK(WriteData(_window + startPtr, kWindowSize - startPtr))
+ return WriteData(_window, endPtr);
+}
+
+void CDecoder::ExecuteFilter(unsigned tempFilterIndex, NVm::CBlockRef &outBlockRef)
+{
+ CTempFilter *tempFilter = _tempFilters[tempFilterIndex];
+ tempFilter->InitR[6] = (UInt32)_writtenFileSize;
+ NVm::SetValue32(&tempFilter->GlobalData[0x24], (UInt32)_writtenFileSize);
+ NVm::SetValue32(&tempFilter->GlobalData[0x28], (UInt32)(_writtenFileSize >> 32));
+ CFilter *filter = _filters[tempFilter->FilterIndex];
+ if (!filter->IsSupported)
+ _unsupportedFilter = true;
+ if (!_vm.Execute(filter, tempFilter, outBlockRef, filter->GlobalData))
+ _unsupportedFilter = true;
+ delete tempFilter;
+ _tempFilters[tempFilterIndex] = NULL;
+ _numEmptyTempFilters++;
+}
+
+HRESULT CDecoder::WriteBuf()
+{
+ UInt32 writtenBorder = _wrPtr;
+ UInt32 writeSize = (_winPos - writtenBorder) & kWindowMask;
+ FOR_VECTOR (i, _tempFilters)
+ {
+ CTempFilter *filter = _tempFilters[i];
+ if (!filter)
+ continue;
+ if (filter->NextWindow)
+ {
+ filter->NextWindow = false;
+ continue;
+ }
+ UInt32 blockStart = filter->BlockStart;
+ UInt32 blockSize = filter->BlockSize;
+ if (((blockStart - writtenBorder) & kWindowMask) < writeSize)
+ {
+ if (writtenBorder != blockStart)
+ {
+ RINOK(WriteArea(writtenBorder, blockStart))
+ writtenBorder = blockStart;
+ writeSize = (_winPos - writtenBorder) & kWindowMask;
+ }
+ if (blockSize <= writeSize)
+ {
+ UInt32 blockEnd = (blockStart + blockSize) & kWindowMask;
+ if (blockStart < blockEnd || blockEnd == 0)
+ _vm.SetMemory(0, _window + blockStart, blockSize);
+ else
+ {
+ UInt32 tailSize = kWindowSize - blockStart;
+ _vm.SetMemory(0, _window + blockStart, tailSize);
+ _vm.SetMemory(tailSize, _window, blockEnd);
+ }
+ NVm::CBlockRef outBlockRef;
+ ExecuteFilter(i, outBlockRef);
+ while (i + 1 < _tempFilters.Size())
+ {
+ CTempFilter *nextFilter = _tempFilters[i + 1];
+ if (!nextFilter
+ || nextFilter->BlockStart != blockStart
+ || nextFilter->BlockSize != outBlockRef.Size
+ || nextFilter->NextWindow)
+ break;
+ _vm.SetMemory(0, _vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size);
+ ExecuteFilter(++i, outBlockRef);
+ }
+ WriteDataToStream(_vm.GetDataPointer(outBlockRef.Offset), outBlockRef.Size);
+ _writtenFileSize += outBlockRef.Size;
+ writtenBorder = blockEnd;
+ writeSize = (_winPos - writtenBorder) & kWindowMask;
+ }
+ else
+ {
+ for (unsigned j = i; j < _tempFilters.Size(); j++)
+ {
+ CTempFilter *filter2 = _tempFilters[j];
+ if (filter2 && filter2->NextWindow)
+ filter2->NextWindow = false;
+ }
+ _wrPtr = writtenBorder;
+ return S_OK; // check it
+ }
+ }
+ }
+
+ _wrPtr = _winPos;
+ return WriteArea(writtenBorder, _winPos);
+}
+
+void CDecoder::InitFilters()
+{
+ _lastFilter = 0;
+ _numEmptyTempFilters = 0;
+ unsigned i;
+ for (i = 0; i < _tempFilters.Size(); i++)
+ delete _tempFilters[i];
+ _tempFilters.Clear();
+ for (i = 0; i < _filters.Size(); i++)
+ delete _filters[i];
+ _filters.Clear();
+}
+
+static const unsigned MAX_UNPACK_FILTERS = 8192;
+
+bool CDecoder::AddVmCode(UInt32 firstByte, UInt32 codeSize)
+{
+ CMemBitDecoder inp;
+ inp.Init(_vmData, codeSize);
+
+ UInt32 filterIndex;
+
+ if (firstByte & 0x80)
+ {
+ filterIndex = inp.ReadEncodedUInt32();
+ if (filterIndex == 0)
+ InitFilters();
+ else
+ filterIndex--;
+ }
+ else
+ filterIndex = _lastFilter;
+
+ if (filterIndex > (UInt32)_filters.Size())
+ return false;
+ _lastFilter = filterIndex;
+ bool newFilter = (filterIndex == (UInt32)_filters.Size());
+
+ CFilter *filter;
+ if (newFilter)
+ {
+ // check if too many filters
+ if (filterIndex > MAX_UNPACK_FILTERS)
+ return false;
+ filter = new CFilter;
+ _filters.Add(filter);
+ }
+ else
+ {
+ filter = _filters[filterIndex];
+ filter->ExecCount++;
+ }
+
+ if (_numEmptyTempFilters != 0)
+ {
+ unsigned num = _tempFilters.Size();
+ CTempFilter **tempFilters = &_tempFilters.Front();
+
+ unsigned w = 0;
+ for (unsigned i = 0; i < num; i++)
+ {
+ CTempFilter *tf = tempFilters[i];
+ if (tf)
+ tempFilters[w++] = tf;
+ }
+
+ _tempFilters.DeleteFrom(w);
+ _numEmptyTempFilters = 0;
+ }
+
+ if (_tempFilters.Size() > MAX_UNPACK_FILTERS)
+ return false;
+ CTempFilter *tempFilter = new CTempFilter;
+ _tempFilters.Add(tempFilter);
+ tempFilter->FilterIndex = filterIndex;
+
+ UInt32 blockStart = inp.ReadEncodedUInt32();
+ if (firstByte & 0x40)
+ blockStart += 258;
+ tempFilter->BlockStart = (blockStart + _winPos) & kWindowMask;
+ if (firstByte & 0x20)
+ filter->BlockSize = inp.ReadEncodedUInt32();
+ tempFilter->BlockSize = filter->BlockSize;
+ tempFilter->NextWindow = _wrPtr != _winPos && ((_wrPtr - _winPos) & kWindowMask) <= blockStart;
+
+ memset(tempFilter->InitR, 0, sizeof(tempFilter->InitR));
+ tempFilter->InitR[3] = NVm::kGlobalOffset;
+ tempFilter->InitR[4] = tempFilter->BlockSize;
+ tempFilter->InitR[5] = filter->ExecCount;
+ if (firstByte & 0x10)
+ {
+ UInt32 initMask = inp.ReadBits(NVm::kNumGpRegs);
+ for (unsigned i = 0; i < NVm::kNumGpRegs; i++)
+ if (initMask & (1 << i))
+ tempFilter->InitR[i] = inp.ReadEncodedUInt32();
+ }
+
+ bool isOK = true;
+ if (newFilter)
+ {
+ UInt32 vmCodeSize = inp.ReadEncodedUInt32();
+ if (vmCodeSize >= kVmCodeSizeMax || vmCodeSize == 0)
+ return false;
+ for (UInt32 i = 0; i < vmCodeSize; i++)
+ _vmCode[i] = (Byte)inp.ReadBits(8);
+ isOK = filter->PrepareProgram(_vmCode, vmCodeSize);
+ }
+
+ {
+ Byte *globalData = &tempFilter->GlobalData[0];
+ for (unsigned i = 0; i < NVm::kNumGpRegs; i++)
+ NVm::SetValue32(&globalData[i * 4], tempFilter->InitR[i]);
+ NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockSize], tempFilter->BlockSize);
+ NVm::SetValue32(&globalData[NVm::NGlobalOffset::kBlockPos], 0); // It was commented. why?
+ NVm::SetValue32(&globalData[NVm::NGlobalOffset::kExecCount], filter->ExecCount);
+ }
+
+ if (firstByte & 8)
+ {
+ UInt32 dataSize = inp.ReadEncodedUInt32();
+ if (dataSize > NVm::kGlobalSize - NVm::kFixedGlobalSize)
+ return false;
+ CRecordVector<Byte> &globalData = tempFilter->GlobalData;
+ unsigned requiredSize = (unsigned)(dataSize + NVm::kFixedGlobalSize);
+ if (globalData.Size() < requiredSize)
+ globalData.ChangeSize_KeepData(requiredSize);
+ Byte *dest = &globalData[NVm::kFixedGlobalSize];
+ for (UInt32 i = 0; i < dataSize; i++)
+ dest[i] = (Byte)inp.ReadBits(8);
+ }
+
+ return isOK;
+}
+
+bool CDecoder::ReadVmCodeLZ()
+{
+ UInt32 firstByte = ReadBits(8);
+ UInt32 len = (firstByte & 7) + 1;
+ if (len == 7)
+ len = ReadBits(8) + 7;
+ else if (len == 8)
+ len = ReadBits(16);
+ if (len > kVmDataSizeMax)
+ return false;
+ for (UInt32 i = 0; i < len; i++)
+ _vmData[i] = (Byte)ReadBits(8);
+ return AddVmCode(firstByte, len);
+}
+
+
+// int CDecoder::DecodePpmSymbol() { return Ppmd7a_DecodeSymbol(&_ppmd); }
+#define DecodePpmSymbol() Ppmd7a_DecodeSymbol(&_ppmd)
+
+
+bool CDecoder::ReadVmCodePPM()
+{
+ const int firstByte = DecodePpmSymbol();
+ if (firstByte < 0)
+ return false;
+ UInt32 len = (firstByte & 7) + 1;
+ if (len == 7)
+ {
+ const int b1 = DecodePpmSymbol();
+ if (b1 < 0)
+ return false;
+ len = (unsigned)b1 + 7;
+ }
+ else if (len == 8)
+ {
+ const int b1 = DecodePpmSymbol();
+ if (b1 < 0)
+ return false;
+ const int b2 = DecodePpmSymbol();
+ if (b2 < 0)
+ return false;
+ len = (unsigned)b1 * 256 + (unsigned)b2;
+ }
+ if (len > kVmDataSizeMax)
+ return false;
+ if (InputEofError_Fast())
+ return false;
+ for (UInt32 i = 0; i < len; i++)
+ {
+ const int b = DecodePpmSymbol();
+ if (b < 0)
+ return false;
+ _vmData[i] = (Byte)b;
+ }
+ return AddVmCode((unsigned)firstByte, len);
+}
+
+#define RIF(x) { if (!(x)) return S_FALSE; }
+
+UInt32 CDecoder::ReadBits(unsigned numBits) { return m_InBitStream.BitDecoder.ReadBits(numBits); }
+
+// ---------- PPM ----------
+
+HRESULT CDecoder::InitPPM()
+{
+ unsigned maxOrder = (unsigned)ReadBits(7);
+
+ const bool reset = ((maxOrder & 0x20) != 0);
+ UInt32 maxMB = 0;
+ if (reset)
+ maxMB = (Byte)Wrap_ReadBits8(&m_InBitStream.IByteIn_obj);
+ else
+ {
+ if (PpmError || !Ppmd7_WasAllocated(&_ppmd))
+ return S_FALSE;
+ }
+ if (maxOrder & 0x40)
+ PpmEscChar = (Byte)Wrap_ReadBits8(&m_InBitStream.IByteIn_obj);
+
+ _ppmd.rc.dec.Stream = &m_InBitStream.IByteIn_obj;
+ m_InBitStream.IByteIn_obj.Read = Wrap_ReadBits8;
+
+ Ppmd7a_RangeDec_Init(&_ppmd.rc.dec);
+
+ m_InBitStream.IByteIn_obj.Read = Wrap_ReadByte;
+
+ if (reset)
+ {
+ PpmError = true;
+ maxOrder = (maxOrder & 0x1F) + 1;
+ if (maxOrder > 16)
+ maxOrder = 16 + (maxOrder - 16) * 3;
+ if (maxOrder == 1)
+ {
+ Ppmd7_Free(&_ppmd, &g_BigAlloc);
+ return S_FALSE;
+ }
+ if (!Ppmd7_Alloc(&_ppmd, (maxMB + 1) << 20, &g_BigAlloc))
+ return E_OUTOFMEMORY;
+ Ppmd7_Init(&_ppmd, maxOrder);
+ PpmError = false;
+ }
+ return S_OK;
+}
+
+
+HRESULT CDecoder::DecodePPM(Int32 num, bool &keepDecompressing)
+{
+ keepDecompressing = false;
+ if (PpmError)
+ return S_FALSE;
+ do
+ {
+ if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos)
+ {
+ RINOK(WriteBuf())
+ if (_writtenFileSize > _unpackSize)
+ {
+ keepDecompressing = false;
+ return S_OK;
+ }
+ }
+ if (InputEofError_Fast())
+ return false;
+ const int c = DecodePpmSymbol();
+ if (c < 0)
+ {
+ PpmError = true;
+ return S_FALSE;
+ }
+ if (c == PpmEscChar)
+ {
+ const int nextCh = DecodePpmSymbol();
+ if (nextCh < 0)
+ {
+ PpmError = true;
+ return S_FALSE;
+ }
+ if (nextCh == 0)
+ return ReadTables(keepDecompressing);
+ if (nextCh == 2 || nextCh == -1)
+ return S_OK;
+ if (nextCh == 3)
+ {
+ if (!ReadVmCodePPM())
+ {
+ PpmError = true;
+ return S_FALSE;
+ }
+ continue;
+ }
+ if (nextCh == 4 || nextCh == 5)
+ {
+ UInt32 dist = 0;
+ UInt32 len = 4;
+ if (nextCh == 4)
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ const int c2 = DecodePpmSymbol();
+ if (c2 < 0)
+ {
+ PpmError = true;
+ return S_FALSE;
+ }
+ dist = (dist << 8) + (Byte)c2;
+ }
+ dist++;
+ len += 28;
+ }
+ const int c2 = DecodePpmSymbol();
+ if (c2 < 0)
+ {
+ PpmError = true;
+ return S_FALSE;
+ }
+ len += (unsigned)c2;
+ if (dist >= _lzSize)
+ return S_FALSE;
+ CopyBlock(dist, len);
+ num -= (Int32)len;
+ continue;
+ }
+ }
+ PutByte((Byte)c);
+ num--;
+ }
+ while (num >= 0);
+ keepDecompressing = true;
+ return S_OK;
+}
+
+// ---------- LZ ----------
+
+HRESULT CDecoder::ReadTables(bool &keepDecompressing)
+{
+ keepDecompressing = true;
+ m_InBitStream.BitDecoder.AlignToByte();
+ if (ReadBits(1) != 0)
+ {
+ _lzMode = false;
+ return InitPPM();
+ }
+
+ TablesRead = false;
+ TablesOK = false;
+
+ _lzMode = true;
+ PrevAlignBits = 0;
+ PrevAlignCount = 0;
+
+ Byte levelLevels[kLevelTableSize];
+ Byte lens[kTablesSizesSum];
+
+ if (ReadBits(1) == 0)
+ memset(m_LastLevels, 0, kTablesSizesSum);
+
+ unsigned i;
+
+ for (i = 0; i < kLevelTableSize; i++)
+ {
+ const UInt32 len = ReadBits(4);
+ if (len == 15)
+ {
+ UInt32 zeroCount = ReadBits(4);
+ if (zeroCount != 0)
+ {
+ zeroCount += 2;
+ while (zeroCount-- > 0 && i < kLevelTableSize)
+ levelLevels[i++]=0;
+ i--;
+ continue;
+ }
+ }
+ levelLevels[i] = (Byte)len;
+ }
+
+ RIF(m_LevelDecoder.Build(levelLevels))
+
+ i = 0;
+
+ do
+ {
+ const UInt32 sym = m_LevelDecoder.Decode(&m_InBitStream.BitDecoder);
+ if (sym < 16)
+ {
+ lens[i] = Byte((sym + m_LastLevels[i]) & 15);
+ i++;
+ }
+ else if (sym > kLevelTableSize)
+ return S_FALSE;
+ else
+ {
+ unsigned num = ((sym - 16) & 1) * 4;
+ num += num + 3 + (unsigned)ReadBits(num + 3);
+ num += i;
+ if (num > kTablesSizesSum)
+ num = kTablesSizesSum;
+ Byte v = 0;
+ if (sym < 16 + 2)
+ {
+ if (i == 0)
+ return S_FALSE;
+ v = lens[(size_t)i - 1];
+ }
+ do
+ lens[i++] = v;
+ while (i < num);
+ }
+ }
+ while (i < kTablesSizesSum);
+
+ if (InputEofError())
+ return S_FALSE;
+
+ TablesRead = true;
+
+ // original code has check here:
+ /*
+ if (InAddr > ReadTop)
+ {
+ keepDecompressing = false;
+ return true;
+ }
+ */
+
+ RIF(m_MainDecoder.Build(&lens[0]))
+ RIF(m_DistDecoder.Build(&lens[kMainTableSize]))
+ RIF(m_AlignDecoder.Build(&lens[kMainTableSize + kDistTableSize]))
+ RIF(m_LenDecoder.Build(&lens[kMainTableSize + kDistTableSize + kAlignTableSize]))
+
+ memcpy(m_LastLevels, lens, kTablesSizesSum);
+
+ TablesOK = true;
+
+ return S_OK;
+}
+
+/*
+class CCoderReleaser
+{
+ CDecoder *m_Coder;
+public:
+ CCoderReleaser(CDecoder *coder): m_Coder(coder) {}
+ ~CCoderReleaser()
+ {
+ m_Coder->ReleaseStreams();
+ }
+};
+*/
+
+HRESULT CDecoder::ReadEndOfBlock(bool &keepDecompressing)
+{
+ if (ReadBits(1) == 0)
+ {
+ // new file
+ keepDecompressing = false;
+ TablesRead = (ReadBits(1) == 0);
+ return S_OK;
+ }
+ TablesRead = false;
+ return ReadTables(keepDecompressing);
+}
+
+
+HRESULT CDecoder::DecodeLZ(bool &keepDecompressing)
+{
+ UInt32 rep0 = _reps[0];
+ UInt32 rep1 = _reps[1];
+ UInt32 rep2 = _reps[2];
+ UInt32 rep3 = _reps[3];
+ UInt32 len = _lastLength;
+ for (;;)
+ {
+ if (((_wrPtr - _winPos) & kWindowMask) < 260 && _wrPtr != _winPos)
+ {
+ RINOK(WriteBuf())
+ if (_writtenFileSize > _unpackSize)
+ {
+ keepDecompressing = false;
+ return S_OK;
+ }
+ }
+
+ if (InputEofError_Fast())
+ return S_FALSE;
+
+ UInt32 sym = m_MainDecoder.Decode(&m_InBitStream.BitDecoder);
+ if (sym < 256)
+ {
+ PutByte((Byte)sym);
+ continue;
+ }
+ else if (sym == kSymbolReadTable)
+ {
+ RINOK(ReadEndOfBlock(keepDecompressing))
+ break;
+ }
+ else if (sym == 257)
+ {
+ if (!ReadVmCodeLZ())
+ return S_FALSE;
+ continue;
+ }
+ else if (sym == 258)
+ {
+ if (len == 0)
+ return S_FALSE;
+ }
+ else if (sym < kSymbolRep + 4)
+ {
+ if (sym != kSymbolRep)
+ {
+ UInt32 dist;
+ if (sym == kSymbolRep + 1)
+ dist = rep1;
+ else
+ {
+ if (sym == kSymbolRep + 2)
+ dist = rep2;
+ else
+ {
+ dist = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = dist;
+ }
+
+ const UInt32 sym2 = m_LenDecoder.Decode(&m_InBitStream.BitDecoder);
+ if (sym2 >= kLenTableSize)
+ return S_FALSE;
+ len = 2 + sym2;
+ if (sym2 >= 8)
+ {
+ unsigned num = (sym2 >> 2) - 1;
+ len = 2 + ((4 + (sym2 & 3)) << num) + m_InBitStream.BitDecoder.ReadBits_upto8(num);
+ }
+ }
+ else
+ {
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ if (sym < 271)
+ {
+ sym -= 263;
+ rep0 = kLen2DistStarts[sym] + m_InBitStream.BitDecoder.ReadBits_upto8(kLen2DistDirectBits[sym]);
+ len = 2;
+ }
+ else if (sym < 299)
+ {
+ sym -= 271;
+ len = kNormalMatchMinLen + sym;
+ if (sym >= 8)
+ {
+ const unsigned num = (sym >> 2) - 1;
+ len = kNormalMatchMinLen + ((4 + (sym & 3)) << num) + m_InBitStream.BitDecoder.ReadBits_upto8(num);
+ }
+ const UInt32 sym2 = m_DistDecoder.Decode(&m_InBitStream.BitDecoder);
+ if (sym2 >= kDistTableSize)
+ return S_FALSE;
+ rep0 = kDistStart[sym2];
+ unsigned numBits = kDistDirectBits[sym2];
+ if (sym2 >= (kNumAlignBits * 2) + 2)
+ {
+ if (numBits > kNumAlignBits)
+ rep0 += (m_InBitStream.BitDecoder.ReadBits(numBits - kNumAlignBits) << kNumAlignBits);
+ if (PrevAlignCount > 0)
+ {
+ PrevAlignCount--;
+ rep0 += PrevAlignBits;
+ }
+ else
+ {
+ const UInt32 sym3 = m_AlignDecoder.Decode(&m_InBitStream.BitDecoder);
+ if (sym3 < (1 << kNumAlignBits))
+ {
+ rep0 += sym3;
+ PrevAlignBits = sym3;
+ }
+ else if (sym3 == (1 << kNumAlignBits))
+ {
+ PrevAlignCount = kNumAlignReps;
+ rep0 += PrevAlignBits;
+ }
+ else
+ return S_FALSE;
+ }
+ }
+ else
+ rep0 += m_InBitStream.BitDecoder.ReadBits_upto8(numBits);
+ len += ((UInt32)(kDistLimit4 - rep0) >> 31) + ((UInt32)(kDistLimit3 - rep0) >> 31);
+ }
+ else
+ return S_FALSE;
+ }
+ if (rep0 >= _lzSize)
+ return S_FALSE;
+ CopyBlock(rep0, len);
+ }
+ _reps[0] = rep0;
+ _reps[1] = rep1;
+ _reps[2] = rep2;
+ _reps[3] = rep3;
+ _lastLength = len;
+
+ return S_OK;
+}
+
+
+HRESULT CDecoder::CodeReal(ICompressProgressInfo *progress)
+{
+ _writtenFileSize = 0;
+ _unsupportedFilter = false;
+
+ if (!_isSolid)
+ {
+ _lzSize = 0;
+ _winPos = 0;
+ _wrPtr = 0;
+ for (unsigned i = 0; i < kNumReps; i++)
+ _reps[i] = 0;
+ _lastLength = 0;
+ memset(m_LastLevels, 0, kTablesSizesSum);
+ TablesRead = false;
+ PpmEscChar = 2;
+ PpmError = true;
+ InitFilters();
+ // _errorMode = false;
+ }
+
+ /*
+ if (_errorMode)
+ return S_FALSE;
+ */
+
+ if (!_isSolid || !TablesRead)
+ {
+ bool keepDecompressing;
+ RINOK(ReadTables(keepDecompressing))
+ if (!keepDecompressing)
+ {
+ _solidAllowed = true;
+ return S_OK;
+ }
+ }
+
+ for (;;)
+ {
+ bool keepDecompressing;
+ if (_lzMode)
+ {
+ if (!TablesOK)
+ return S_FALSE;
+ RINOK(DecodeLZ(keepDecompressing))
+ }
+ else
+ {
+ RINOK(DecodePPM(1 << 18, keepDecompressing))
+ }
+
+ if (InputEofError())
+ return S_FALSE;
+
+ const UInt64 packSize = m_InBitStream.BitDecoder.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize))
+ if (!keepDecompressing)
+ break;
+ }
+
+ _solidAllowed = true;
+
+ RINOK(WriteBuf())
+ const UInt64 packSize = m_InBitStream.BitDecoder.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &_writtenFileSize))
+ if (_writtenFileSize < _unpackSize)
+ return S_FALSE;
+
+ if (_unsupportedFilter)
+ return E_NOTIMPL;
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ try
+ {
+ if (!inSize)
+ return E_INVALIDARG;
+
+ if (_isSolid && !_solidAllowed)
+ return S_FALSE;
+ _solidAllowed = false;
+
+ if (!_vmData)
+ {
+ _vmData = (Byte *)::MidAlloc(kVmDataSizeMax + kVmCodeSizeMax);
+ if (!_vmData)
+ return E_OUTOFMEMORY;
+ _vmCode = _vmData + kVmDataSizeMax;
+ }
+
+ if (!_window)
+ {
+ _window = (Byte *)::MidAlloc(kWindowSize);
+ if (!_window)
+ return E_OUTOFMEMORY;
+ }
+ if (!m_InBitStream.BitDecoder.Create(1 << 20))
+ return E_OUTOFMEMORY;
+ if (!_vm.Create())
+ return E_OUTOFMEMORY;
+
+
+ m_InBitStream.BitDecoder.SetStream(inStream);
+ m_InBitStream.BitDecoder.Init();
+ _outStream = outStream;
+
+ // CCoderReleaser coderReleaser(this);
+ _unpackSize = outSize ? *outSize : (UInt64)(Int64)-1;
+ return CodeReal(progress);
+ }
+ catch(const CInBufferException &e) { /* _errorMode = true; */ return e.ErrorCode; }
+ catch(...) { /* _errorMode = true; */ return S_FALSE; }
+ // CNewException is possible here. But probably CNewException is caused
+ // by error in data stream.
+}
+
+Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size))
+{
+ if (size < 1)
+ return E_INVALIDARG;
+ _isSolid = ((data[0] & 1) != 0);
+ return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Compress/Rar3Decoder.h b/CPP/7zip/Compress/Rar3Decoder.h
new file mode 100644
index 0000000..4711052
--- /dev/null
+++ b/CPP/7zip/Compress/Rar3Decoder.h
@@ -0,0 +1,275 @@
+// Rar3Decoder.h
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+/* This code uses Carryless rangecoder (1999): Dmitry Subbotin : Public domain */
+
+#ifndef ZIP7_INC_COMPRESS_RAR3_DECODER_H
+#define ZIP7_INC_COMPRESS_RAR3_DECODER_H
+
+#include "../../../C/Ppmd7.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+#include "../Common/InBuffer.h"
+
+#include "BitmDecoder.h"
+#include "HuffmanDecoder.h"
+#include "Rar3Vm.h"
+
+namespace NCompress {
+namespace NRar3 {
+
+const UInt32 kWindowSize = 1 << 22;
+const UInt32 kWindowMask = (kWindowSize - 1);
+
+const UInt32 kNumReps = 4;
+const UInt32 kNumLen2Symbols = 8;
+const UInt32 kLenTableSize = 28;
+const UInt32 kMainTableSize = 256 + 1 + 1 + 1 + kNumReps + kNumLen2Symbols + kLenTableSize;
+const UInt32 kDistTableSize = 60;
+
+const unsigned kNumAlignBits = 4;
+const UInt32 kAlignTableSize = (1 << kNumAlignBits) + 1;
+
+const UInt32 kLevelTableSize = 20;
+
+const UInt32 kTablesSizesSum = kMainTableSize + kDistTableSize + kAlignTableSize + kLenTableSize;
+
+class CBitDecoder
+{
+ UInt32 _value;
+ unsigned _bitPos;
+public:
+ CInBuffer Stream;
+
+ bool Create(UInt32 bufSize) { return Stream.Create(bufSize); }
+ void SetStream(ISequentialInStream *inStream) { Stream.SetStream(inStream);}
+
+ void Init()
+ {
+ Stream.Init();
+ _bitPos = 0;
+ _value = 0;
+ }
+
+ bool ExtraBitsWereRead() const
+ {
+ return (Stream.NumExtraBytes > 4 || _bitPos < (Stream.NumExtraBytes << 3));
+ }
+
+ UInt64 GetProcessedSize() const { return Stream.GetProcessedSize() - (_bitPos >> 3); }
+
+ void AlignToByte()
+ {
+ _bitPos &= ~(unsigned)7;
+ _value = _value & ((1 << _bitPos) - 1);
+ }
+
+ UInt32 GetValue(unsigned numBits)
+ {
+ if (_bitPos < numBits)
+ {
+ _bitPos += 8;
+ _value = (_value << 8) | Stream.ReadByte();
+ if (_bitPos < numBits)
+ {
+ _bitPos += 8;
+ _value = (_value << 8) | Stream.ReadByte();
+ }
+ }
+ return _value >> (_bitPos - numBits);
+ }
+
+ void MovePos(unsigned numBits)
+ {
+ _bitPos -= numBits;
+ _value = _value & ((1 << _bitPos) - 1);
+ }
+
+ UInt32 ReadBits(unsigned numBits)
+ {
+ UInt32 res = GetValue(numBits);
+ MovePos(numBits);
+ return res;
+ }
+
+ UInt32 ReadBits_upto8(unsigned numBits)
+ {
+ if (_bitPos < numBits)
+ {
+ _bitPos += 8;
+ _value = (_value << 8) | Stream.ReadByte();
+ }
+ _bitPos -= numBits;
+ UInt32 res = _value >> _bitPos;
+ _value = _value & ((1 << _bitPos) - 1);
+ return res;
+ }
+
+ Byte ReadByteFromAligned()
+ {
+ if (_bitPos == 0)
+ return Stream.ReadByte();
+ unsigned bitsPos = _bitPos - 8;
+ Byte b = (Byte)(_value >> bitsPos);
+ _value = _value & ((1 << bitsPos) - 1);
+ _bitPos = bitsPos;
+ return b;
+ }
+};
+
+
+struct CByteIn
+{
+ IByteIn IByteIn_obj;
+ CBitDecoder BitDecoder;
+};
+
+
+struct CFilter: public NVm::CProgram
+{
+ CRecordVector<Byte> GlobalData;
+ UInt32 BlockStart;
+ UInt32 BlockSize;
+ UInt32 ExecCount;
+
+ CFilter(): BlockStart(0), BlockSize(0), ExecCount(0) {}
+};
+
+struct CTempFilter: public NVm::CProgramInitState
+{
+ UInt32 BlockStart;
+ UInt32 BlockSize;
+ bool NextWindow;
+
+ UInt32 FilterIndex;
+
+ CTempFilter()
+ {
+ // all filters must contain at least FixedGlobal block
+ AllocateEmptyFixedGlobal();
+ }
+};
+
+const unsigned kNumHuffmanBits = 15;
+
+Z7_CLASS_IMP_NOQIB_2(
+ CDecoder
+ , ICompressCoder
+ , ICompressSetDecoderProperties2
+)
+ CByteIn m_InBitStream;
+ Byte *_window;
+ UInt32 _winPos;
+ UInt32 _wrPtr;
+ UInt64 _lzSize;
+ UInt64 _unpackSize;
+ UInt64 _writtenFileSize; // if it's > _unpackSize, then _unpackSize only written
+ ISequentialOutStream *_outStream;
+ NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
+ UInt32 kDistStart[kDistTableSize];
+ NHuffman::CDecoder<kNumHuffmanBits, kDistTableSize> m_DistDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kAlignTableSize> m_AlignDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kLenTableSize> m_LenDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
+
+ UInt32 _reps[kNumReps];
+ UInt32 _lastLength;
+
+ Byte m_LastLevels[kTablesSizesSum];
+
+ Byte *_vmData;
+ Byte *_vmCode;
+ NVm::CVm _vm;
+ CRecordVector<CFilter *> _filters;
+ CRecordVector<CTempFilter *> _tempFilters;
+ unsigned _numEmptyTempFilters;
+ UInt32 _lastFilter;
+
+ bool _isSolid;
+ bool _solidAllowed;
+ // bool _errorMode;
+
+ bool _lzMode;
+ bool _unsupportedFilter;
+
+ UInt32 PrevAlignBits;
+ UInt32 PrevAlignCount;
+
+ bool TablesRead;
+ bool TablesOK;
+
+ CPpmd7 _ppmd;
+ int PpmEscChar;
+ bool PpmError;
+
+ HRESULT WriteDataToStream(const Byte *data, UInt32 size);
+ HRESULT WriteData(const Byte *data, UInt32 size);
+ HRESULT WriteArea(UInt32 startPtr, UInt32 endPtr);
+ void ExecuteFilter(unsigned tempFilterIndex, NVm::CBlockRef &outBlockRef);
+ HRESULT WriteBuf();
+
+ void InitFilters();
+ bool AddVmCode(UInt32 firstByte, UInt32 codeSize);
+ bool ReadVmCodeLZ();
+ bool ReadVmCodePPM();
+
+ UInt32 ReadBits(unsigned numBits);
+
+ HRESULT InitPPM();
+ // int DecodePpmSymbol();
+ HRESULT DecodePPM(Int32 num, bool &keepDecompressing);
+
+ HRESULT ReadTables(bool &keepDecompressing);
+ HRESULT ReadEndOfBlock(bool &keepDecompressing);
+ HRESULT DecodeLZ(bool &keepDecompressing);
+ HRESULT CodeReal(ICompressProgressInfo *progress);
+
+ bool InputEofError() const { return m_InBitStream.BitDecoder.ExtraBitsWereRead(); }
+ bool InputEofError_Fast() const { return (m_InBitStream.BitDecoder.Stream.NumExtraBytes > 2); }
+
+ void CopyBlock(UInt32 dist, UInt32 len)
+ {
+ _lzSize += len;
+ UInt32 pos = (_winPos - dist - 1) & kWindowMask;
+ Byte *window = _window;
+ UInt32 winPos = _winPos;
+ if (kWindowSize - winPos > len && kWindowSize - pos > len)
+ {
+ const Byte *src = window + pos;
+ Byte *dest = window + winPos;
+ _winPos += len;
+ do
+ *dest++ = *src++;
+ while (--len != 0);
+ return;
+ }
+ do
+ {
+ window[winPos] = window[pos];
+ winPos = (winPos + 1) & kWindowMask;
+ pos = (pos + 1) & kWindowMask;
+ }
+ while (--len != 0);
+ _winPos = winPos;
+ }
+
+ void PutByte(Byte b)
+ {
+ const UInt32 wp = _winPos;
+ _window[wp] = b;
+ _winPos = (wp + 1) & kWindowMask;
+ _lzSize++;
+ }
+
+public:
+ CDecoder();
+ ~CDecoder();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/Rar3Vm.cpp b/CPP/7zip/Compress/Rar3Vm.cpp
new file mode 100644
index 0000000..9b728ef
--- /dev/null
+++ b/CPP/7zip/Compress/Rar3Vm.cpp
@@ -0,0 +1,1153 @@
+// Rar3Vm.cpp
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+/*
+Note:
+ Due to performance considerations Rar VM may set Flags C incorrectly
+ for some operands (SHL x, 0, ... ).
+ Check implementation of concrete VM command
+ to see if it sets flags right.
+*/
+
+#include "StdAfx.h"
+
+#include <stdlib.h>
+
+#include "../../../C/7zCrc.h"
+#include "../../../C/Alloc.h"
+
+#include "../../Common/Defs.h"
+
+#include "Rar3Vm.h"
+
+namespace NCompress {
+namespace NRar3 {
+
+UInt32 CMemBitDecoder::ReadBits(unsigned numBits)
+{
+ UInt32 res = 0;
+ for (;;)
+ {
+ const unsigned b = _bitPos < _bitSize ? (unsigned)_data[_bitPos >> 3] : 0;
+ const unsigned avail = (unsigned)(8 - (_bitPos & 7));
+ if (numBits <= avail)
+ {
+ _bitPos += numBits;
+ return res | ((b >> (avail - numBits)) & ((1 << numBits) - 1));
+ }
+ numBits -= avail;
+ res |= (UInt32)(b & ((1 << avail) - 1)) << numBits;
+ _bitPos += avail;
+ }
+}
+
+UInt32 CMemBitDecoder::ReadBit() { return ReadBits(1); }
+
+UInt32 CMemBitDecoder::ReadEncodedUInt32()
+{
+ const unsigned v = (unsigned)ReadBits(2);
+ UInt32 res = ReadBits(4u << v);
+ if (v == 1 && res < 16)
+ res = 0xFFFFFF00 | (res << 4) | ReadBits(4);
+ return res;
+}
+
+namespace NVm {
+
+static const UInt32 kStackRegIndex = kNumRegs - 1;
+
+#ifdef Z7_RARVM_VM_ENABLE
+
+#if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40400) \
+ || defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30000)
+// enumeration values not explicitly handled in switch
+#pragma GCC diagnostic ignored "-Wswitch-enum"
+#endif
+
+static const UInt32 FLAG_C = 1;
+static const UInt32 FLAG_Z = 2;
+static const UInt32 FLAG_S = 0x80000000;
+
+static const Byte CF_OP0 = 0;
+static const Byte CF_OP1 = 1;
+static const Byte CF_OP2 = 2;
+static const Byte CF_OPMASK = 3;
+static const Byte CF_BYTEMODE = 4;
+static const Byte CF_JUMP = 8;
+static const Byte CF_PROC = 16;
+static const Byte CF_USEFLAGS = 32;
+static const Byte CF_CHFLAGS = 64;
+
+static const Byte kCmdFlags[]=
+{
+ /* CMD_MOV */ CF_OP2 | CF_BYTEMODE,
+ /* CMD_CMP */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_ADD */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_SUB */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_JZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_JNZ */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_INC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_DEC */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_JMP */ CF_OP1 | CF_JUMP,
+ /* CMD_XOR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_AND */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_OR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_TEST */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_JS */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_JNS */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_JB */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_JBE */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_JA */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_JAE */ CF_OP1 | CF_JUMP | CF_USEFLAGS,
+ /* CMD_PUSH */ CF_OP1,
+ /* CMD_POP */ CF_OP1,
+ /* CMD_CALL */ CF_OP1 | CF_PROC,
+ /* CMD_RET */ CF_OP0 | CF_PROC,
+ /* CMD_NOT */ CF_OP1 | CF_BYTEMODE,
+ /* CMD_SHL */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_SHR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_SAR */ CF_OP2 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_NEG */ CF_OP1 | CF_BYTEMODE | CF_CHFLAGS,
+ /* CMD_PUSHA */ CF_OP0,
+ /* CMD_POPA */ CF_OP0,
+ /* CMD_PUSHF */ CF_OP0 | CF_USEFLAGS,
+ /* CMD_POPF */ CF_OP0 | CF_CHFLAGS,
+ /* CMD_MOVZX */ CF_OP2,
+ /* CMD_MOVSX */ CF_OP2,
+ /* CMD_XCHG */ CF_OP2 | CF_BYTEMODE,
+ /* CMD_MUL */ CF_OP2 | CF_BYTEMODE,
+ /* CMD_DIV */ CF_OP2 | CF_BYTEMODE,
+ /* CMD_ADC */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS ,
+ /* CMD_SBB */ CF_OP2 | CF_BYTEMODE | CF_USEFLAGS | CF_CHFLAGS ,
+ /* CMD_PRINT */ CF_OP0
+};
+
+#endif
+
+
+CVm::CVm(): Mem(NULL) {}
+
+bool CVm::Create()
+{
+ if (!Mem)
+ Mem = (Byte *)::MyAlloc(kSpaceSize + 4);
+ return (Mem != NULL);
+}
+
+CVm::~CVm()
+{
+ ::MyFree(Mem);
+}
+
+// CVm::Execute can change CProgram object: it clears progarm if VM returns error.
+
+bool CVm::Execute(CProgram *prg, const CProgramInitState *initState,
+ CBlockRef &outBlockRef, CRecordVector<Byte> &outGlobalData)
+{
+ memcpy(R, initState->InitR, sizeof(initState->InitR));
+ R[kStackRegIndex] = kSpaceSize;
+ R[kNumRegs] = 0;
+ Flags = 0;
+
+ const UInt32 globalSize = MyMin((UInt32)initState->GlobalData.Size(), kGlobalSize);
+ if (globalSize != 0)
+ memcpy(Mem + kGlobalOffset, &initState->GlobalData[0], globalSize);
+ UInt32 staticSize = MyMin((UInt32)prg->StaticData.Size(), kGlobalSize - globalSize);
+ if (staticSize != 0)
+ memcpy(Mem + kGlobalOffset + globalSize, &prg->StaticData[0], staticSize);
+
+ bool res = true;
+
+ #ifdef Z7_RARVM_STANDARD_FILTERS
+ if (prg->StandardFilterIndex >= 0)
+ res = ExecuteStandardFilter((unsigned)prg->StandardFilterIndex);
+ else
+ #endif
+ {
+ #ifdef Z7_RARVM_VM_ENABLE
+ res = ExecuteCode(prg);
+ if (!res)
+ {
+ prg->Commands.Clear();
+ prg->Commands.Add(CCommand());
+ prg->Commands.Back().OpCode = CMD_RET;
+ }
+ #else
+ res = false;
+ #endif
+ }
+
+ UInt32 newBlockPos = GetFixedGlobalValue32(NGlobalOffset::kBlockPos) & kSpaceMask;
+ UInt32 newBlockSize = GetFixedGlobalValue32(NGlobalOffset::kBlockSize) & kSpaceMask;
+ if (newBlockPos + newBlockSize >= kSpaceSize)
+ newBlockPos = newBlockSize = 0;
+ outBlockRef.Offset = newBlockPos;
+ outBlockRef.Size = newBlockSize;
+
+ outGlobalData.Clear();
+ UInt32 dataSize = GetFixedGlobalValue32(NGlobalOffset::kGlobalMemOutSize);
+ dataSize = MyMin(dataSize, kGlobalSize - kFixedGlobalSize);
+ if (dataSize != 0)
+ {
+ dataSize += kFixedGlobalSize;
+ outGlobalData.ClearAndSetSize(dataSize);
+ memcpy(&outGlobalData[0], Mem + kGlobalOffset, dataSize);
+ }
+
+ return res;
+}
+
+#ifdef Z7_RARVM_VM_ENABLE
+
+#define SET_IP(IP) \
+ if ((IP) >= numCommands) return true; \
+ if (--maxOpCount <= 0) return false; \
+ cmd = commands + (IP);
+
+#define GET_FLAG_S_B(res) (((res) & 0x80) ? FLAG_S : 0)
+#define SET_IP_OP1 { const UInt32 val = GetOperand32(&cmd->Op1); SET_IP(val) }
+#define FLAGS_UPDATE_SZ Flags = res == 0 ? FLAG_Z : res & FLAG_S
+#define FLAGS_UPDATE_SZ_B Flags = (res & 0xFF) == 0 ? FLAG_Z : GET_FLAG_S_B(res)
+
+UInt32 CVm::GetOperand32(const COperand *op) const
+{
+ switch (op->Type)
+ {
+ case OP_TYPE_REG: return R[op->Data];
+ case OP_TYPE_REGMEM: return GetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask]);
+ default: return op->Data;
+ }
+}
+
+void CVm::SetOperand32(const COperand *op, UInt32 val)
+{
+ switch (op->Type)
+ {
+ case OP_TYPE_REG: R[op->Data] = val; return;
+ case OP_TYPE_REGMEM: SetValue32(&Mem[(op->Base + R[op->Data]) & kSpaceMask], val); return;
+ default: break;
+ }
+}
+
+Byte CVm::GetOperand8(const COperand *op) const
+{
+ switch (op->Type)
+ {
+ case OP_TYPE_REG: return (Byte)R[op->Data];
+ case OP_TYPE_REGMEM: return Mem[(op->Base + R[op->Data]) & kSpaceMask];
+ default: return (Byte)op->Data;
+ }
+}
+
+void CVm::SetOperand8(const COperand *op, Byte val)
+{
+ switch (op->Type)
+ {
+ case OP_TYPE_REG: R[op->Data] = (R[op->Data] & 0xFFFFFF00) | val; return;
+ case OP_TYPE_REGMEM: Mem[(op->Base + R[op->Data]) & kSpaceMask] = val; return;
+ default: break;
+ }
+}
+
+UInt32 CVm::GetOperand(bool byteMode, const COperand *op) const
+{
+ if (byteMode)
+ return GetOperand8(op);
+ return GetOperand32(op);
+}
+
+void CVm::SetOperand(bool byteMode, const COperand *op, UInt32 val)
+{
+ if (byteMode)
+ SetOperand8(op, (Byte)(val & 0xFF));
+ else
+ SetOperand32(op, val);
+}
+
+bool CVm::ExecuteCode(const CProgram *prg)
+{
+ Int32 maxOpCount = 25000000;
+ const CCommand *commands = &prg->Commands[0];
+ const CCommand *cmd = commands;
+ const UInt32 numCommands = prg->Commands.Size();
+ if (numCommands == 0)
+ return false;
+
+ for (;;)
+ {
+ switch (cmd->OpCode)
+ {
+ case CMD_MOV:
+ SetOperand32(&cmd->Op1, GetOperand32(&cmd->Op2));
+ break;
+ case CMD_MOVB:
+ SetOperand8(&cmd->Op1, GetOperand8(&cmd->Op2));
+ break;
+ case CMD_CMP:
+ {
+ const UInt32 v1 = GetOperand32(&cmd->Op1);
+ const UInt32 res = v1 - GetOperand32(&cmd->Op2);
+ Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
+ }
+ break;
+ case CMD_CMPB:
+ {
+ const Byte v1 = GetOperand8(&cmd->Op1);
+ const Byte res = (Byte)((v1 - GetOperand8(&cmd->Op2)) & 0xFF);
+ Flags = res == 0 ? FLAG_Z : (res > v1) | GET_FLAG_S_B(res);
+ }
+ break;
+ case CMD_ADD:
+ {
+ const UInt32 v1 = GetOperand32(&cmd->Op1);
+ const UInt32 res = v1 + GetOperand32(&cmd->Op2);
+ SetOperand32(&cmd->Op1, res);
+ Flags = (res < v1) | (res == 0 ? FLAG_Z : (res & FLAG_S));
+ }
+ break;
+ case CMD_ADDB:
+ {
+ const Byte v1 = GetOperand8(&cmd->Op1);
+ const Byte res = (Byte)((v1 + GetOperand8(&cmd->Op2)) & 0xFF);
+ SetOperand8(&cmd->Op1, (Byte)res);
+ Flags = (res < v1) | (res == 0 ? FLAG_Z : GET_FLAG_S_B(res));
+ }
+ break;
+ case CMD_ADC:
+ {
+ const UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
+ const UInt32 FC = (Flags & FLAG_C);
+ UInt32 res = v1 + GetOperand(cmd->ByteMode, &cmd->Op2) + FC;
+ if (cmd->ByteMode)
+ res &= 0xFF;
+ SetOperand(cmd->ByteMode, &cmd->Op1, res);
+ Flags = (res < v1 || (res == v1 && FC)) | (res == 0 ? FLAG_Z : (res & FLAG_S));
+ }
+ break;
+ case CMD_SUB:
+ {
+ const UInt32 v1 = GetOperand32(&cmd->Op1);
+ const UInt32 res = v1 - GetOperand32(&cmd->Op2);
+ SetOperand32(&cmd->Op1, res);
+ Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
+ }
+ break;
+ case CMD_SUBB:
+ {
+ const UInt32 v1 = GetOperand8(&cmd->Op1);
+ const UInt32 res = v1 - GetOperand8(&cmd->Op2);
+ SetOperand8(&cmd->Op1, (Byte)res);
+ Flags = res == 0 ? FLAG_Z : (res > v1) | (res & FLAG_S);
+ }
+ break;
+ case CMD_SBB:
+ {
+ const UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
+ const UInt32 FC = (Flags & FLAG_C);
+ UInt32 res = v1 - GetOperand(cmd->ByteMode, &cmd->Op2) - FC;
+ // Flags = res == 0 ? FLAG_Z : (res > v1 || res == v1 && FC) | (res & FLAG_S);
+ if (cmd->ByteMode)
+ res &= 0xFF;
+ SetOperand(cmd->ByteMode, &cmd->Op1, res);
+ Flags = (res > v1 || (res == v1 && FC)) | (res == 0 ? FLAG_Z : (res & FLAG_S));
+ }
+ break;
+ case CMD_INC:
+ {
+ const UInt32 res = GetOperand32(&cmd->Op1) + 1;
+ SetOperand32(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ;
+ }
+ break;
+ case CMD_INCB:
+ {
+ const Byte res = (Byte)(GetOperand8(&cmd->Op1) + 1);
+ SetOperand8(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ_B;
+ }
+ break;
+ case CMD_DEC:
+ {
+ const UInt32 res = GetOperand32(&cmd->Op1) - 1;
+ SetOperand32(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ;
+ }
+ break;
+ case CMD_DECB:
+ {
+ const Byte res = (Byte)(GetOperand8(&cmd->Op1) - 1);
+ SetOperand8(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ_B;
+ }
+ break;
+ case CMD_XOR:
+ {
+ const UInt32 res = GetOperand32(&cmd->Op1) ^ GetOperand32(&cmd->Op2);
+ SetOperand32(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ;
+ }
+ break;
+ case CMD_XORB:
+ {
+ const Byte res = (Byte)(GetOperand8(&cmd->Op1) ^ GetOperand8(&cmd->Op2));
+ SetOperand8(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ_B;
+ }
+ break;
+ case CMD_AND:
+ {
+ const UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2);
+ SetOperand32(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ;
+ }
+ break;
+ case CMD_ANDB:
+ {
+ const Byte res = (Byte)(GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2));
+ SetOperand8(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ_B;
+ }
+ break;
+ case CMD_OR:
+ {
+ const UInt32 res = GetOperand32(&cmd->Op1) | GetOperand32(&cmd->Op2);
+ SetOperand32(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ;
+ }
+ break;
+ case CMD_ORB:
+ {
+ const Byte res = (Byte)(GetOperand8(&cmd->Op1) | GetOperand8(&cmd->Op2));
+ SetOperand8(&cmd->Op1, res);
+ FLAGS_UPDATE_SZ_B;
+ }
+ break;
+ case CMD_TEST:
+ {
+ const UInt32 res = GetOperand32(&cmd->Op1) & GetOperand32(&cmd->Op2);
+ FLAGS_UPDATE_SZ;
+ }
+ break;
+ case CMD_TESTB:
+ {
+ const Byte res = (Byte)(GetOperand8(&cmd->Op1) & GetOperand8(&cmd->Op2));
+ FLAGS_UPDATE_SZ_B;
+ }
+ break;
+ case CMD_NOT:
+ SetOperand(cmd->ByteMode, &cmd->Op1, ~GetOperand(cmd->ByteMode, &cmd->Op1));
+ break;
+ case CMD_NEG:
+ {
+ const UInt32 res = 0 - GetOperand32(&cmd->Op1);
+ SetOperand32(&cmd->Op1, res);
+ Flags = res == 0 ? FLAG_Z : FLAG_C | (res & FLAG_S);
+ }
+ break;
+ case CMD_NEGB:
+ {
+ const Byte res = (Byte)(0 - GetOperand8(&cmd->Op1));
+ SetOperand8(&cmd->Op1, res);
+ Flags = res == 0 ? FLAG_Z : FLAG_C | GET_FLAG_S_B(res);
+ }
+ break;
+
+ case CMD_SHL:
+ {
+ const UInt32 v1 = GetOperand32(&cmd->Op1);
+ const int v2 = (int)GetOperand32(&cmd->Op2);
+ const UInt32 res = v1 << v2;
+ SetOperand32(&cmd->Op1, res);
+ Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 << (v2 - 1)) & 0x80000000 ? FLAG_C : 0);
+ }
+ break;
+ case CMD_SHLB:
+ {
+ const Byte v1 = GetOperand8(&cmd->Op1);
+ const int v2 = (int)GetOperand8(&cmd->Op2);
+ const Byte res = (Byte)(v1 << v2);
+ SetOperand8(&cmd->Op1, res);
+ Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 << (v2 - 1)) & 0x80 ? FLAG_C : 0);
+ }
+ break;
+ case CMD_SHR:
+ {
+ const UInt32 v1 = GetOperand32(&cmd->Op1);
+ const int v2 = (int)GetOperand32(&cmd->Op2);
+ const UInt32 res = v1 >> v2;
+ SetOperand32(&cmd->Op1, res);
+ Flags = (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C);
+ }
+ break;
+ case CMD_SHRB:
+ {
+ const Byte v1 = GetOperand8(&cmd->Op1);
+ const int v2 = (int)GetOperand8(&cmd->Op2);
+ const Byte res = (Byte)(v1 >> v2);
+ SetOperand8(&cmd->Op1, res);
+ Flags = (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C);
+ }
+ break;
+ case CMD_SAR:
+ {
+ const UInt32 v1 = GetOperand32(&cmd->Op1);
+ const int v2 = (int)GetOperand32(&cmd->Op2);
+ const UInt32 res = UInt32(((Int32)v1) >> v2);
+ SetOperand32(&cmd->Op1, res);
+ Flags= (res == 0 ? FLAG_Z : (res & FLAG_S)) | ((v1 >> (v2 - 1)) & FLAG_C);
+ }
+ break;
+ case CMD_SARB:
+ {
+ const Byte v1 = GetOperand8(&cmd->Op1);
+ const int v2 = (int)GetOperand8(&cmd->Op2);
+ const Byte res = (Byte)(((signed char)v1) >> v2);
+ SetOperand8(&cmd->Op1, res);
+ Flags= (res == 0 ? FLAG_Z : GET_FLAG_S_B(res)) | ((v1 >> (v2 - 1)) & FLAG_C);
+ }
+ break;
+
+ case CMD_JMP:
+ SET_IP_OP1
+ continue;
+ case CMD_JZ:
+ if ((Flags & FLAG_Z) != 0)
+ {
+ SET_IP_OP1
+ continue;
+ }
+ break;
+ case CMD_JNZ:
+ if ((Flags & FLAG_Z) == 0)
+ {
+ SET_IP_OP1
+ continue;
+ }
+ break;
+ case CMD_JS:
+ if ((Flags & FLAG_S) != 0)
+ {
+ SET_IP_OP1
+ continue;
+ }
+ break;
+ case CMD_JNS:
+ if ((Flags & FLAG_S) == 0)
+ {
+ SET_IP_OP1
+ continue;
+ }
+ break;
+ case CMD_JB:
+ if ((Flags & FLAG_C) != 0)
+ {
+ SET_IP_OP1
+ continue;
+ }
+ break;
+ case CMD_JBE:
+ if ((Flags & (FLAG_C | FLAG_Z)) != 0)
+ {
+ SET_IP_OP1
+ continue;
+ }
+ break;
+ case CMD_JA:
+ if ((Flags & (FLAG_C | FLAG_Z)) == 0)
+ {
+ SET_IP_OP1
+ continue;
+ }
+ break;
+ case CMD_JAE:
+ if ((Flags & FLAG_C) == 0)
+ {
+ SET_IP_OP1
+ continue;
+ }
+ break;
+
+ case CMD_PUSH:
+ R[kStackRegIndex] -= 4;
+ SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], GetOperand32(&cmd->Op1));
+ break;
+ case CMD_POP:
+ SetOperand32(&cmd->Op1, GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]));
+ R[kStackRegIndex] += 4;
+ break;
+ case CMD_CALL:
+ R[kStackRegIndex] -= 4;
+ SetValue32(&Mem[R[kStackRegIndex] & kSpaceMask], (UInt32)(cmd - commands + 1));
+ SET_IP_OP1
+ continue;
+
+ case CMD_PUSHA:
+ {
+ for (UInt32 i = 0, SP = R[kStackRegIndex] - 4; i < kNumRegs; i++, SP -= 4)
+ SetValue32(&Mem[SP & kSpaceMask], R[i]);
+ R[kStackRegIndex] -= kNumRegs * 4;
+ }
+ break;
+ case CMD_POPA:
+ {
+ for (UInt32 i = 0, SP = R[kStackRegIndex]; i < kNumRegs; i++, SP += 4)
+ R[kStackRegIndex - i] = GetValue32(&Mem[SP & kSpaceMask]);
+ }
+ break;
+ case CMD_PUSHF:
+ R[kStackRegIndex] -= 4;
+ SetValue32(&Mem[R[kStackRegIndex]&kSpaceMask], Flags);
+ break;
+ case CMD_POPF:
+ Flags = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]);
+ R[kStackRegIndex] += 4;
+ break;
+
+ case CMD_MOVZX:
+ SetOperand32(&cmd->Op1, GetOperand8(&cmd->Op2));
+ break;
+ case CMD_MOVSX:
+ SetOperand32(&cmd->Op1, (UInt32)(Int32)(signed char)GetOperand8(&cmd->Op2));
+ break;
+ case CMD_XCHG:
+ {
+ const UInt32 v1 = GetOperand(cmd->ByteMode, &cmd->Op1);
+ SetOperand(cmd->ByteMode, &cmd->Op1, GetOperand(cmd->ByteMode, &cmd->Op2));
+ SetOperand(cmd->ByteMode, &cmd->Op2, v1);
+ }
+ break;
+ case CMD_MUL:
+ {
+ const UInt32 res = GetOperand32(&cmd->Op1) * GetOperand32(&cmd->Op2);
+ SetOperand32(&cmd->Op1, res);
+ }
+ break;
+ case CMD_MULB:
+ {
+ const Byte res = (Byte)(GetOperand8(&cmd->Op1) * GetOperand8(&cmd->Op2));
+ SetOperand8(&cmd->Op1, res);
+ }
+ break;
+ case CMD_DIV:
+ {
+ const UInt32 divider = GetOperand(cmd->ByteMode, &cmd->Op2);
+ if (divider != 0)
+ {
+ const UInt32 res = GetOperand(cmd->ByteMode, &cmd->Op1) / divider;
+ SetOperand(cmd->ByteMode, &cmd->Op1, res);
+ }
+ }
+ break;
+
+ case CMD_RET:
+ {
+ if (R[kStackRegIndex] >= kSpaceSize)
+ return true;
+ const UInt32 ip = GetValue32(&Mem[R[kStackRegIndex] & kSpaceMask]);
+ SET_IP(ip)
+ R[kStackRegIndex] += 4;
+ continue;
+ }
+ case CMD_PRINT:
+ break;
+ }
+ cmd++;
+ --maxOpCount;
+ }
+}
+
+//////////////////////////////////////////////////////
+// Read program
+
+static void DecodeArg(CMemBitDecoder &inp, COperand &op, bool byteMode)
+{
+ if (inp.ReadBit())
+ {
+ op.Type = OP_TYPE_REG;
+ op.Data = inp.ReadBits(kNumRegBits);
+ }
+ else if (inp.ReadBit() == 0)
+ {
+ op.Type = OP_TYPE_INT;
+ if (byteMode)
+ op.Data = inp.ReadBits(8);
+ else
+ op.Data = inp.ReadEncodedUInt32();
+ }
+ else
+ {
+ op.Type = OP_TYPE_REGMEM;
+ if (inp.ReadBit() == 0)
+ {
+ op.Data = inp.ReadBits(kNumRegBits);
+ op.Base = 0;
+ }
+ else
+ {
+ if (inp.ReadBit() == 0)
+ op.Data = inp.ReadBits(kNumRegBits);
+ else
+ op.Data = kNumRegs;
+ op.Base = inp.ReadEncodedUInt32();
+ }
+ }
+}
+
+void CProgram::ReadProgram(const Byte *code, UInt32 codeSize)
+{
+ CMemBitDecoder inp;
+ inp.Init(code, codeSize);
+
+ StaticData.Clear();
+
+ if (inp.ReadBit())
+ {
+ const UInt32 dataSize = inp.ReadEncodedUInt32() + 1;
+ for (UInt32 i = 0; inp.Avail() && i < dataSize; i++)
+ StaticData.Add((Byte)inp.ReadBits(8));
+ }
+
+ while (inp.Avail())
+ {
+ Commands.Add(CCommand());
+ CCommand *cmd = &Commands.Back();
+
+ unsigned opCode;
+ if (inp.ReadBit() == 0)
+ opCode = inp.ReadBits(3);
+ else
+ opCode = 8 + inp.ReadBits(5);
+ cmd->OpCode = (ECommand)opCode;
+ const unsigned cmdFlags = kCmdFlags[opCode];
+ if (cmdFlags & CF_BYTEMODE)
+ cmd->ByteMode = (inp.ReadBit()) ? true : false;
+ else
+ cmd->ByteMode = 0;
+
+ const unsigned opNum = (cmdFlags & CF_OPMASK);
+
+ if (opNum)
+ {
+ DecodeArg(inp, cmd->Op1, cmd->ByteMode);
+ if (opNum == 2)
+ DecodeArg(inp, cmd->Op2, cmd->ByteMode);
+ else
+ {
+ if (cmd->Op1.Type == OP_TYPE_INT && (cmdFlags & (CF_JUMP | CF_PROC)))
+ {
+ Int32 dist = (Int32)cmd->Op1.Data;
+ if (dist >= 256)
+ dist -= 256;
+ else
+ {
+ if (dist >= 136)
+ dist -= 264;
+ else if (dist >= 16)
+ dist -= 8;
+ else if (dist >= 8)
+ dist -= 16;
+ dist += Commands.Size() - 1;
+ }
+ cmd->Op1.Data = (UInt32)dist;
+ }
+ }
+ }
+
+ if (cmd->ByteMode)
+ {
+ switch (cmd->OpCode)
+ {
+ case CMD_MOV: cmd->OpCode = CMD_MOVB; break;
+ case CMD_CMP: cmd->OpCode = CMD_CMPB; break;
+ case CMD_ADD: cmd->OpCode = CMD_ADDB; break;
+ case CMD_SUB: cmd->OpCode = CMD_SUBB; break;
+ case CMD_INC: cmd->OpCode = CMD_INCB; break;
+ case CMD_DEC: cmd->OpCode = CMD_DECB; break;
+ case CMD_XOR: cmd->OpCode = CMD_XORB; break;
+ case CMD_AND: cmd->OpCode = CMD_ANDB; break;
+ case CMD_OR: cmd->OpCode = CMD_ORB; break;
+ case CMD_TEST: cmd->OpCode = CMD_TESTB; break;
+ case CMD_NEG: cmd->OpCode = CMD_NEGB; break;
+ case CMD_SHL: cmd->OpCode = CMD_SHLB; break;
+ case CMD_SHR: cmd->OpCode = CMD_SHRB; break;
+ case CMD_SAR: cmd->OpCode = CMD_SARB; break;
+ case CMD_MUL: cmd->OpCode = CMD_MULB; break;
+ default: break;
+ }
+ }
+ }
+}
+
+#endif
+
+
+#ifdef Z7_RARVM_STANDARD_FILTERS
+
+enum EStandardFilter
+{
+ SF_E8,
+ SF_E8E9,
+ SF_ITANIUM,
+ SF_RGB,
+ SF_AUDIO,
+ SF_DELTA
+ // SF_UPCASE
+};
+
+static const struct CStandardFilterSignature
+{
+ UInt32 Length;
+ UInt32 CRC;
+ EStandardFilter Type;
+}
+kStdFilters[]=
+{
+ { 53, 0xad576887, SF_E8 },
+ { 57, 0x3cd7e57e, SF_E8E9 },
+ { 120, 0x3769893f, SF_ITANIUM },
+ { 29, 0x0e06077d, SF_DELTA },
+ { 149, 0x1c2c5dc8, SF_RGB },
+ { 216, 0xbc85e701, SF_AUDIO }
+ // { 40, 0x46b9c560, SF_UPCASE }
+};
+
+static int FindStandardFilter(const Byte *code, UInt32 codeSize)
+{
+ // return -1; // for debug VM execution
+ const UInt32 crc = CrcCalc(code, codeSize);
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(kStdFilters); i++)
+ {
+ const CStandardFilterSignature &sfs = kStdFilters[i];
+ if (sfs.CRC == crc && sfs.Length == codeSize)
+ return (int)i;
+ }
+ return -1;
+}
+
+#endif
+
+
+bool CProgram::PrepareProgram(const Byte *code, UInt32 codeSize)
+{
+ IsSupported = false;
+
+ #ifdef Z7_RARVM_VM_ENABLE
+ Commands.Clear();
+ #endif
+
+ #ifdef Z7_RARVM_STANDARD_FILTERS
+ StandardFilterIndex = -1;
+ #endif
+
+ bool isOK = false;
+
+ Byte xorSum = 0;
+ for (UInt32 i = 0; i < codeSize; i++)
+ xorSum ^= code[i];
+
+ if (xorSum == 0 && codeSize != 0)
+ {
+ IsSupported = true;
+ isOK = true;
+ #ifdef Z7_RARVM_STANDARD_FILTERS
+ StandardFilterIndex = FindStandardFilter(code, codeSize);
+ if (StandardFilterIndex >= 0)
+ return true;
+ #endif
+
+ #ifdef Z7_RARVM_VM_ENABLE
+ ReadProgram(code + 1, codeSize - 1);
+ #else
+ IsSupported = false;
+ #endif
+ }
+
+ #ifdef Z7_RARVM_VM_ENABLE
+ Commands.Add(CCommand());
+ Commands.Back().OpCode = CMD_RET;
+ #endif
+
+ return isOK;
+}
+
+void CVm::SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize)
+{
+ if (pos < kSpaceSize && data != Mem + pos)
+ memmove(Mem + pos, data, MyMin(dataSize, kSpaceSize - pos));
+}
+
+#ifdef Z7_RARVM_STANDARD_FILTERS
+
+static void E8E9Decode(Byte *data, UInt32 dataSize, UInt32 fileOffset, bool e9)
+{
+ if (dataSize <= 4)
+ return;
+ dataSize -= 4;
+ const UInt32 kFileSize = 0x1000000;
+ const Byte cmpMask = (Byte)(e9 ? 0xFE : 0xFF);
+ for (UInt32 curPos = 0; curPos < dataSize;)
+ {
+ curPos++;
+ if (((*data++) & cmpMask) == 0xE8)
+ {
+ UInt32 offset = curPos + fileOffset;
+ UInt32 addr = GetValue32(data);
+ if (addr < kFileSize)
+ SetValue32(data, addr - offset);
+ else if ((addr & 0x80000000) != 0 && ((addr + offset) & 0x80000000) == 0)
+ SetValue32(data, addr + kFileSize);
+ data += 4;
+ curPos += 4;
+ }
+ }
+}
+
+
+static void ItaniumDecode(Byte *data, UInt32 dataSize, UInt32 fileOffset)
+{
+ if (dataSize <= 21)
+ return;
+ fileOffset >>= 4;
+ dataSize -= 21;
+ dataSize += 15;
+ dataSize >>= 4;
+ dataSize += fileOffset;
+ do
+ {
+ unsigned m = ((UInt32)0x334B0000 >> (data[0] & 0x1E)) & 3;
+ if (m)
+ {
+ m++;
+ do
+ {
+ Byte *p = data + ((size_t)m * 5 - 8);
+ if (((p[3] >> m) & 15) == 5)
+ {
+ const UInt32 kMask = 0xFFFFF;
+ // UInt32 raw = ((UInt32)p[0]) | ((UInt32)p[1] << 8) | ((UInt32)p[2] << 16);
+ UInt32 raw = GetUi32(p);
+ UInt32 v = raw >> m;
+ v -= fileOffset;
+ v &= kMask;
+ raw &= ~(kMask << m);
+ raw |= (v << m);
+ // p[0] = (Byte)raw; p[1] = (Byte)(raw >> 8); p[2] = (Byte)(raw >> 16);
+ SetUi32(p, raw)
+ }
+ }
+ while (++m <= 4);
+ }
+ data += 16;
+ }
+ while (++fileOffset != dataSize);
+}
+
+
+static void DeltaDecode(Byte *data, UInt32 dataSize, UInt32 numChannels)
+{
+ UInt32 srcPos = 0;
+ const UInt32 border = dataSize * 2;
+ for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
+ {
+ Byte prevByte = 0;
+ for (UInt32 destPos = dataSize + curChannel; destPos < border; destPos += numChannels)
+ data[destPos] = (prevByte = (Byte)(prevByte - data[srcPos++]));
+ }
+}
+
+static void RgbDecode(Byte *srcData, UInt32 dataSize, UInt32 width, UInt32 posR)
+{
+ Byte *destData = srcData + dataSize;
+ const UInt32 kNumChannels = 3;
+
+ for (UInt32 curChannel = 0; curChannel < kNumChannels; curChannel++)
+ {
+ Byte prevByte = 0;
+
+ for (UInt32 i = curChannel; i < dataSize; i += kNumChannels)
+ {
+ unsigned int predicted;
+ if (i < width)
+ predicted = prevByte;
+ else
+ {
+ const unsigned int upperLeftByte = destData[i - width];
+ const unsigned int upperByte = destData[i - width + 3];
+ predicted = prevByte + upperByte - upperLeftByte;
+ const int pa = abs((int)(predicted - prevByte));
+ const int pb = abs((int)(predicted - upperByte));
+ const int pc = abs((int)(predicted - upperLeftByte));
+ if (pa <= pb && pa <= pc)
+ predicted = prevByte;
+ else
+ if (pb <= pc)
+ predicted = upperByte;
+ else
+ predicted = upperLeftByte;
+ }
+ destData[i] = prevByte = (Byte)(predicted - *(srcData++));
+ }
+ }
+ if (dataSize < 3)
+ return;
+ const UInt32 border = dataSize - 2;
+ for (UInt32 i = posR; i < border; i += 3)
+ {
+ const Byte g = destData[i + 1];
+ destData[i ] = (Byte)(destData[i ] + g);
+ destData[i + 2] = (Byte)(destData[i + 2] + g);
+ }
+}
+
+#define my_abs(x) (unsigned)abs(x)
+
+static void AudioDecode(Byte *srcData, UInt32 dataSize, UInt32 numChannels)
+{
+ Byte *destData = srcData + dataSize;
+ for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
+ {
+ UInt32 prevByte = 0, prevDelta = 0, dif[7];
+ Int32 D1 = 0, D2 = 0, D3;
+ Int32 K1 = 0, K2 = 0, K3 = 0;
+ memset(dif, 0, sizeof(dif));
+
+ for (UInt32 i = curChannel, byteCount = 0; i < dataSize; i += numChannels, byteCount++)
+ {
+ D3 = D2;
+ D2 = (Int32)prevDelta - D1;
+ D1 = (Int32)prevDelta;
+
+ UInt32 predicted = (UInt32)((Int32)(8 * prevByte) + K1 * D1 + K2 * D2 + K3 * D3);
+ predicted = (predicted >> 3) & 0xFF;
+
+ const UInt32 curByte = *(srcData++);
+
+ predicted -= curByte;
+ destData[i] = (Byte)predicted;
+ prevDelta = (UInt32)(Int32)(signed char)(predicted - prevByte);
+ prevByte = predicted;
+
+ const Int32 D = ((Int32)(signed char)curByte) << 3;
+
+ dif[0] += my_abs(D);
+ dif[1] += my_abs(D - D1);
+ dif[2] += my_abs(D + D1);
+ dif[3] += my_abs(D - D2);
+ dif[4] += my_abs(D + D2);
+ dif[5] += my_abs(D - D3);
+ dif[6] += my_abs(D + D3);
+
+ if ((byteCount & 0x1F) == 0)
+ {
+ UInt32 minDif = dif[0], numMinDif = 0;
+ dif[0] = 0;
+ for (unsigned j = 1; j < Z7_ARRAY_SIZE(dif); j++)
+ {
+ if (dif[j] < minDif)
+ {
+ minDif = dif[j];
+ numMinDif = j;
+ }
+ dif[j] = 0;
+ }
+ switch (numMinDif)
+ {
+ case 1: if (K1 >= -16) K1--; break;
+ case 2: if (K1 < 16) K1++; break;
+ case 3: if (K2 >= -16) K2--; break;
+ case 4: if (K2 < 16) K2++; break;
+ case 5: if (K3 >= -16) K3--; break;
+ case 6: if (K3 < 16) K3++; break;
+ }
+ }
+ }
+ }
+}
+
+/*
+static UInt32 UpCaseDecode(Byte *data, UInt32 dataSize)
+{
+ UInt32 srcPos = 0, destPos = dataSize;
+ while (srcPos < dataSize)
+ {
+ Byte curByte = data[srcPos++];
+ if (curByte == 2 && (curByte = data[srcPos++]) != 2)
+ curByte -= 32;
+ data[destPos++] = curByte;
+ }
+ return destPos - dataSize;
+}
+*/
+
+bool CVm::ExecuteStandardFilter(unsigned filterIndex)
+{
+ const UInt32 dataSize = R[4];
+ if (dataSize >= kGlobalOffset)
+ return false;
+ EStandardFilter filterType = kStdFilters[filterIndex].Type;
+
+ switch (filterType)
+ {
+ case SF_E8:
+ case SF_E8E9:
+ E8E9Decode(Mem, dataSize, R[6], (filterType == SF_E8E9));
+ break;
+
+ case SF_ITANIUM:
+ ItaniumDecode(Mem, dataSize, R[6]);
+ break;
+
+ case SF_DELTA:
+ {
+ if (dataSize >= kGlobalOffset / 2)
+ return false;
+ const UInt32 numChannels = R[0];
+ if (numChannels == 0 || numChannels > 1024) // unrar 5.5.5
+ return false;
+ SetBlockPos(dataSize);
+ DeltaDecode(Mem, dataSize, numChannels);
+ break;
+ }
+
+ case SF_RGB:
+ {
+ if (dataSize >= kGlobalOffset / 2 || dataSize < 3) // unrar 5.5.5
+ return false;
+ const UInt32 width = R[0];
+ const UInt32 posR = R[1];
+ if (width < 3 || width - 3 > dataSize || posR > 2) // unrar 5.5.5
+ return false;
+ SetBlockPos(dataSize);
+ RgbDecode(Mem, dataSize, width, posR);
+ break;
+ }
+
+ case SF_AUDIO:
+ {
+ if (dataSize >= kGlobalOffset / 2)
+ return false;
+ const UInt32 numChannels = R[0];
+ if (numChannels == 0 || numChannels > 128) // unrar 5.5.5
+ return false;
+ SetBlockPos(dataSize);
+ AudioDecode(Mem, dataSize, numChannels);
+ break;
+ }
+
+ /*
+ case SF_UPCASE:
+ if (dataSize >= kGlobalOffset / 2)
+ return false;
+ UInt32 destSize = UpCaseDecode(Mem, dataSize);
+ SetBlockSize(destSize);
+ SetBlockPos(dataSize);
+ break;
+ */
+ }
+ return true;
+}
+
+#endif
+
+}}}
diff --git a/CPP/7zip/Compress/Rar3Vm.h b/CPP/7zip/Compress/Rar3Vm.h
new file mode 100644
index 0000000..fde7e95
--- /dev/null
+++ b/CPP/7zip/Compress/Rar3Vm.h
@@ -0,0 +1,195 @@
+// Rar3Vm.h
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#ifndef ZIP7_INC_COMPRESS_RAR3_VM_H
+#define ZIP7_INC_COMPRESS_RAR3_VM_H
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/MyVector.h"
+
+#define Z7_RARVM_STANDARD_FILTERS
+// #define Z7_RARVM_VM_ENABLE
+
+namespace NCompress {
+namespace NRar3 {
+
+class CMemBitDecoder
+{
+ const Byte *_data;
+ UInt32 _bitSize;
+ UInt32 _bitPos;
+public:
+ void Init(const Byte *data, UInt32 byteSize)
+ {
+ _data = data;
+ _bitSize = (byteSize << 3);
+ _bitPos = 0;
+ }
+ UInt32 ReadBits(unsigned numBits);
+ UInt32 ReadBit();
+ bool Avail() const { return (_bitPos < _bitSize); }
+
+ UInt32 ReadEncodedUInt32();
+};
+
+namespace NVm {
+
+inline UInt32 GetValue32(const void *addr) { return GetUi32(addr); }
+inline void SetValue32(void *addr, UInt32 value) { SetUi32(addr, value) }
+
+const unsigned kNumRegBits = 3;
+const UInt32 kNumRegs = 1 << kNumRegBits;
+const UInt32 kNumGpRegs = kNumRegs - 1;
+
+const UInt32 kSpaceSize = 0x40000;
+const UInt32 kSpaceMask = kSpaceSize - 1;
+const UInt32 kGlobalOffset = 0x3C000;
+const UInt32 kGlobalSize = 0x2000;
+const UInt32 kFixedGlobalSize = 64;
+
+namespace NGlobalOffset
+{
+ const UInt32 kBlockSize = 0x1C;
+ const UInt32 kBlockPos = 0x20;
+ const UInt32 kExecCount = 0x2C;
+ const UInt32 kGlobalMemOutSize = 0x30;
+}
+
+
+#ifdef Z7_RARVM_VM_ENABLE
+
+enum ECommand
+{
+ CMD_MOV, CMD_CMP, CMD_ADD, CMD_SUB, CMD_JZ, CMD_JNZ, CMD_INC, CMD_DEC,
+ CMD_JMP, CMD_XOR, CMD_AND, CMD_OR, CMD_TEST, CMD_JS, CMD_JNS, CMD_JB,
+ CMD_JBE, CMD_JA, CMD_JAE, CMD_PUSH, CMD_POP, CMD_CALL, CMD_RET, CMD_NOT,
+ CMD_SHL, CMD_SHR, CMD_SAR, CMD_NEG, CMD_PUSHA,CMD_POPA, CMD_PUSHF,CMD_POPF,
+ CMD_MOVZX,CMD_MOVSX,CMD_XCHG, CMD_MUL, CMD_DIV, CMD_ADC, CMD_SBB, CMD_PRINT,
+
+ CMD_MOVB, CMD_CMPB, CMD_ADDB, CMD_SUBB, CMD_INCB, CMD_DECB,
+ CMD_XORB, CMD_ANDB, CMD_ORB, CMD_TESTB,CMD_NEGB,
+ CMD_SHLB, CMD_SHRB, CMD_SARB, CMD_MULB
+};
+
+enum EOpType {OP_TYPE_REG, OP_TYPE_INT, OP_TYPE_REGMEM, OP_TYPE_NONE};
+
+// Addr in COperand object can link (point) to CVm object!!!
+
+struct COperand
+{
+ EOpType Type;
+ UInt32 Data;
+ UInt32 Base;
+ COperand(): Type(OP_TYPE_NONE), Data(0), Base(0) {}
+};
+
+struct CCommand
+{
+ ECommand OpCode;
+ bool ByteMode;
+ COperand Op1, Op2;
+};
+
+#endif
+
+
+struct CBlockRef
+{
+ UInt32 Offset;
+ UInt32 Size;
+};
+
+
+class CProgram
+{
+ #ifdef Z7_RARVM_VM_ENABLE
+ void ReadProgram(const Byte *code, UInt32 codeSize);
+public:
+ CRecordVector<CCommand> Commands;
+ #endif
+
+public:
+ #ifdef Z7_RARVM_STANDARD_FILTERS
+ int StandardFilterIndex;
+ #endif
+
+ bool IsSupported;
+ CRecordVector<Byte> StaticData;
+
+ bool PrepareProgram(const Byte *code, UInt32 codeSize);
+};
+
+
+struct CProgramInitState
+{
+ UInt32 InitR[kNumGpRegs];
+ CRecordVector<Byte> GlobalData;
+
+ void AllocateEmptyFixedGlobal()
+ {
+ GlobalData.ClearAndSetSize(NVm::kFixedGlobalSize);
+ memset(&GlobalData[0], 0, NVm::kFixedGlobalSize);
+ }
+};
+
+
+class CVm
+{
+ static UInt32 GetValue(bool byteMode, const void *addr)
+ {
+ if (byteMode)
+ return(*(const Byte *)addr);
+ else
+ return GetUi32(addr);
+ }
+
+ static void SetValue(bool byteMode, void *addr, UInt32 value)
+ {
+ if (byteMode)
+ *(Byte *)addr = (Byte)value;
+ else
+ SetUi32(addr, value)
+ }
+
+ UInt32 GetFixedGlobalValue32(UInt32 globalOffset) { return GetValue(false, &Mem[kGlobalOffset + globalOffset]); }
+
+ void SetBlockSize(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockSize], v); }
+ void SetBlockPos(UInt32 v) { SetValue(&Mem[kGlobalOffset + NGlobalOffset::kBlockPos], v); }
+public:
+ static void SetValue(void *addr, UInt32 value) { SetValue(false, addr, value); }
+
+private:
+
+ #ifdef Z7_RARVM_VM_ENABLE
+ UInt32 GetOperand32(const COperand *op) const;
+ void SetOperand32(const COperand *op, UInt32 val);
+ Byte GetOperand8(const COperand *op) const;
+ void SetOperand8(const COperand *op, Byte val);
+ UInt32 GetOperand(bool byteMode, const COperand *op) const;
+ void SetOperand(bool byteMode, const COperand *op, UInt32 val);
+ bool ExecuteCode(const CProgram *prg);
+ #endif
+
+ #ifdef Z7_RARVM_STANDARD_FILTERS
+ bool ExecuteStandardFilter(unsigned filterIndex);
+ #endif
+
+ Byte *Mem;
+ UInt32 R[kNumRegs + 1]; // R[kNumRegs] = 0 always (speed optimization)
+ UInt32 Flags;
+
+public:
+ CVm();
+ ~CVm();
+ bool Create();
+ void SetMemory(UInt32 pos, const Byte *data, UInt32 dataSize);
+ bool Execute(CProgram *prg, const CProgramInitState *initState,
+ CBlockRef &outBlockRef, CRecordVector<Byte> &outGlobalData);
+ const Byte *GetDataPointer(UInt32 offset) const { return Mem + offset; }
+};
+
+#endif
+
+}}}
diff --git a/CPP/7zip/Compress/Rar5Decoder.cpp b/CPP/7zip/Compress/Rar5Decoder.cpp
new file mode 100644
index 0000000..e55d7de
--- /dev/null
+++ b/CPP/7zip/Compress/Rar5Decoder.cpp
@@ -0,0 +1,980 @@
+// Rar5Decoder.cpp
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../Common/StreamUtils.h"
+
+#include "Rar5Decoder.h"
+
+namespace NCompress {
+namespace NRar5 {
+
+static const size_t kInputBufSize = 1 << 20;
+
+void CBitDecoder::Prepare2() throw()
+{
+ const unsigned kSize = 16;
+ if (_buf > _bufLim)
+ return;
+
+ size_t rem = (size_t)(_bufLim - _buf);
+ if (rem != 0)
+ memmove(_bufBase, _buf, rem);
+
+ _bufLim = _bufBase + rem;
+ _processedSize += (size_t)(_buf - _bufBase);
+ _buf = _bufBase;
+
+ if (!_wasFinished)
+ {
+ UInt32 processed = (UInt32)(kInputBufSize - rem);
+ _hres = _stream->Read(_bufLim, (UInt32)processed, &processed);
+ _bufLim += processed;
+ _wasFinished = (processed == 0);
+ if (_hres != S_OK)
+ {
+ _wasFinished = true;
+ // throw CInBufferException(result);
+ }
+ }
+
+ rem = (size_t)(_bufLim - _buf);
+ _bufCheck = _buf;
+ if (rem < kSize)
+ memset(_bufLim, 0xFF, kSize - rem);
+ else
+ _bufCheck = _bufLim - kSize;
+
+ SetCheck2();
+}
+
+
+enum FilterType
+{
+ FILTER_DELTA = 0,
+ FILTER_E8,
+ FILTER_E8E9,
+ FILTER_ARM
+};
+
+static const size_t kWriteStep = (size_t)1 << 22;
+
+CDecoder::CDecoder():
+ _isSolid(false),
+ _solidAllowed(false),
+ _wasInit(false),
+ _dictSizeLog(0),
+ _window(NULL),
+ _winPos(0),
+ _lzSize(0),
+ _lzEnd(0),
+ _writtenFileSize(0),
+ _winSizeAllocated(0),
+ _inputBuf(NULL)
+{
+}
+
+CDecoder::~CDecoder()
+{
+ ::MidFree(_window);
+ ::MidFree(_inputBuf);
+}
+
+HRESULT CDecoder::WriteData(const Byte *data, size_t size)
+{
+ HRESULT res = S_OK;
+ if (!_unpackSize_Defined || _writtenFileSize < _unpackSize)
+ {
+ size_t cur = size;
+ if (_unpackSize_Defined)
+ {
+ const UInt64 rem = _unpackSize - _writtenFileSize;
+ if (cur > rem)
+ cur = (size_t)rem;
+ }
+ res = WriteStream(_outStream, data, cur);
+ if (res != S_OK)
+ _writeError = true;
+ }
+ _writtenFileSize += size;
+ return res;
+}
+
+HRESULT CDecoder::ExecuteFilter(const CFilter &f)
+{
+ bool useDest = false;
+
+ Byte *data = _filterSrc;
+ UInt32 dataSize = f.Size;
+
+ // printf("\nType = %d offset = %9d size = %5d", f.Type, (unsigned)(f.Start - _lzFileStart), dataSize);
+
+ switch (f.Type)
+ {
+ case FILTER_E8:
+ case FILTER_E8E9:
+ {
+ // printf(" FILTER_E8");
+ if (dataSize > 4)
+ {
+ dataSize -= 4;
+ const UInt32 fileOffset = (UInt32)(f.Start - _lzFileStart);
+
+ const UInt32 kFileSize = (UInt32)1 << 24;
+ const Byte cmpMask = (Byte)(f.Type == FILTER_E8 ? 0xFF : 0xFE);
+
+ for (UInt32 curPos = 0; curPos < dataSize;)
+ {
+ curPos++;
+ if (((*data++) & cmpMask) == 0xE8)
+ {
+ const UInt32 offset = (curPos + fileOffset) & (kFileSize - 1);
+ const UInt32 addr = GetUi32(data);
+
+ if (addr < kFileSize)
+ {
+ SetUi32(data, addr - offset)
+ }
+ else if (addr > ((UInt32)0xFFFFFFFF - offset)) // (addr > ~(offset))
+ {
+ SetUi32(data, addr + kFileSize)
+ }
+
+ data += 4;
+ curPos += 4;
+ }
+ }
+ }
+ break;
+ }
+
+ case FILTER_ARM:
+ {
+ if (dataSize >= 4)
+ {
+ dataSize -= 4;
+ const UInt32 fileOffset = (UInt32)(f.Start - _lzFileStart);
+
+ for (UInt32 curPos = 0; curPos <= dataSize; curPos += 4)
+ {
+ Byte *d = data + curPos;
+ if (d[3] == 0xEB)
+ {
+ UInt32 offset = d[0] | ((UInt32)d[1] << 8) | ((UInt32)d[2] << 16);
+ offset -= (fileOffset + curPos) >> 2;
+ d[0] = (Byte)offset;
+ d[1] = (Byte)(offset >> 8);
+ d[2] = (Byte)(offset >> 16);
+ }
+ }
+ }
+ break;
+ }
+
+ case FILTER_DELTA:
+ {
+ // printf(" channels = %d", f.Channels);
+ _filterDst.AllocAtLeast(dataSize);
+ if (!_filterDst.IsAllocated())
+ return E_OUTOFMEMORY;
+
+ Byte *dest = _filterDst;
+ const UInt32 numChannels = f.Channels;
+
+ for (UInt32 curChannel = 0; curChannel < numChannels; curChannel++)
+ {
+ Byte prevByte = 0;
+ for (UInt32 destPos = curChannel; destPos < dataSize; destPos += numChannels)
+ dest[destPos] = (prevByte = (Byte)(prevByte - *data++));
+ }
+ useDest = true;
+ break;
+ }
+
+ default:
+ _unsupportedFilter = true;
+ memset(_filterSrc, 0, f.Size);
+ // return S_OK; // unrar
+ }
+
+ return WriteData(useDest ?
+ (const Byte *)_filterDst :
+ (const Byte *)_filterSrc,
+ f.Size);
+}
+
+
+HRESULT CDecoder::WriteBuf()
+{
+ DeleteUnusedFilters();
+
+ for (unsigned i = 0; i < _filters.Size();)
+ {
+ const CFilter &f = _filters[i];
+
+ const UInt64 blockStart = f.Start;
+
+ const size_t lzAvail = (size_t)(_lzSize - _lzWritten);
+ if (lzAvail == 0)
+ break;
+
+ if (blockStart > _lzWritten)
+ {
+ const UInt64 rem = blockStart - _lzWritten;
+ size_t size = lzAvail;
+ if (size > rem)
+ size = (size_t)rem;
+ if (size != 0)
+ {
+ RINOK(WriteData(_window + _winPos - lzAvail, size))
+ _lzWritten += size;
+ }
+ continue;
+ }
+
+ const UInt32 blockSize = f.Size;
+ size_t offset = (size_t)(_lzWritten - blockStart);
+ if (offset == 0)
+ {
+ _filterSrc.AllocAtLeast(blockSize);
+ if (!_filterSrc.IsAllocated())
+ return E_OUTOFMEMORY;
+ }
+
+ const size_t blockRem = (size_t)blockSize - offset;
+ size_t size = lzAvail;
+ if (size > blockRem)
+ size = blockRem;
+ memcpy(_filterSrc + offset, _window + _winPos - lzAvail, size);
+ _lzWritten += size;
+ offset += size;
+ if (offset != blockSize)
+ return S_OK;
+
+ _numUnusedFilters = ++i;
+ RINOK(ExecuteFilter(f))
+ }
+
+ DeleteUnusedFilters();
+
+ if (!_filters.IsEmpty())
+ return S_OK;
+
+ const size_t lzAvail = (size_t)(_lzSize - _lzWritten);
+ RINOK(WriteData(_window + _winPos - lzAvail, lzAvail))
+ _lzWritten += lzAvail;
+ return S_OK;
+}
+
+
+static UInt32 ReadUInt32(CBitDecoder &bi)
+{
+ const unsigned numBytes = bi.ReadBits9fix(2) + 1;
+ UInt32 v = 0;
+ for (unsigned i = 0; i < numBytes; i++)
+ v += ((UInt32)bi.ReadBits9fix(8) << (i * 8));
+ return v;
+}
+
+
+static const unsigned MAX_UNPACK_FILTERS = 8192;
+
+HRESULT CDecoder::AddFilter(CBitDecoder &_bitStream)
+{
+ DeleteUnusedFilters();
+
+ if (_filters.Size() >= MAX_UNPACK_FILTERS)
+ {
+ RINOK(WriteBuf())
+ DeleteUnusedFilters();
+ if (_filters.Size() >= MAX_UNPACK_FILTERS)
+ {
+ _unsupportedFilter = true;
+ InitFilters();
+ }
+ }
+
+ _bitStream.Prepare();
+
+ CFilter f;
+ const UInt32 blockStart = ReadUInt32(_bitStream);
+ f.Size = ReadUInt32(_bitStream);
+
+ if (f.Size > ((UInt32)1 << 22))
+ {
+ _unsupportedFilter = true;
+ f.Size = 0; // unrar 5.5.5
+ }
+
+ f.Type = (Byte)_bitStream.ReadBits9fix(3);
+ f.Channels = 0;
+ if (f.Type == FILTER_DELTA)
+ f.Channels = (Byte)(_bitStream.ReadBits9fix(5) + 1);
+ f.Start = _lzSize + blockStart;
+
+ if (f.Start < _filterEnd)
+ _unsupportedFilter = true;
+ else
+ {
+ _filterEnd = f.Start + f.Size;
+ if (f.Size != 0)
+ _filters.Add(f);
+ }
+
+ return S_OK;
+}
+
+
+#define RIF(x) { if (!(x)) return S_FALSE; }
+
+HRESULT CDecoder::ReadTables(CBitDecoder &_bitStream)
+{
+ if (_progress)
+ {
+ const UInt64 packSize = _bitStream.GetProcessedSize();
+ RINOK(_progress->SetRatioInfo(&packSize, &_writtenFileSize))
+ }
+
+ _bitStream.AlignToByte();
+ _bitStream.Prepare();
+
+ {
+ const unsigned flags = _bitStream.ReadByteInAligned();
+ unsigned checkSum = _bitStream.ReadByteInAligned();
+ checkSum ^= flags;
+ const unsigned num = (flags >> 3) & 3;
+ if (num == 3)
+ return S_FALSE;
+ UInt32 blockSize = _bitStream.ReadByteInAligned();
+ checkSum ^= blockSize;
+
+ if (num != 0)
+ {
+ unsigned b = _bitStream.ReadByteInAligned();
+ checkSum ^= b;
+ blockSize += (UInt32)b << 8;
+ if (num > 1)
+ {
+ b = _bitStream.ReadByteInAligned();
+ checkSum ^= b;
+ blockSize += (UInt32)b << 16;
+ }
+ }
+
+ if (checkSum != 0x5A)
+ return S_FALSE;
+
+ unsigned blockSizeBits7 = (flags & 7) + 1;
+ blockSize += (blockSizeBits7 >> 3);
+ if (blockSize == 0)
+ return S_FALSE;
+ blockSize--;
+ blockSizeBits7 &= 7;
+
+ _bitStream._blockEndBits7 = (Byte)blockSizeBits7;
+ _bitStream._blockEnd = _bitStream.GetProcessedSize_Round() + blockSize;
+
+ _bitStream.SetCheck2();
+
+ _isLastBlock = ((flags & 0x40) != 0);
+
+ if ((flags & 0x80) == 0)
+ {
+ if (!_tableWasFilled)
+ if (blockSize != 0 || blockSizeBits7 != 0)
+ return S_FALSE;
+ return S_OK;
+ }
+
+ _tableWasFilled = false;
+ }
+
+ {
+ Byte lens2[kLevelTableSize];
+
+ for (unsigned i = 0; i < kLevelTableSize;)
+ {
+ _bitStream.Prepare();
+ const unsigned len = (unsigned)_bitStream.ReadBits9fix(4);
+ if (len == 15)
+ {
+ unsigned num = (unsigned)_bitStream.ReadBits9fix(4);
+ if (num != 0)
+ {
+ num += 2;
+ num += i;
+ if (num > kLevelTableSize)
+ num = kLevelTableSize;
+ do
+ lens2[i++] = 0;
+ while (i < num);
+ continue;
+ }
+ }
+ lens2[i++] = (Byte)len;
+ }
+
+ if (_bitStream.IsBlockOverRead())
+ return S_FALSE;
+
+ RIF(m_LevelDecoder.Build(lens2))
+ }
+
+ Byte lens[kTablesSizesSum];
+ unsigned i = 0;
+
+ do
+ {
+ if (_bitStream._buf >= _bitStream._bufCheck2)
+ {
+ if (_bitStream._buf >= _bitStream._bufCheck)
+ _bitStream.Prepare();
+ if (_bitStream.IsBlockOverRead())
+ return S_FALSE;
+ }
+
+ const UInt32 sym = m_LevelDecoder.Decode(&_bitStream);
+
+ if (sym < 16)
+ lens[i++] = (Byte)sym;
+ else if (sym > kLevelTableSize)
+ return S_FALSE;
+ else
+ {
+ unsigned num = ((sym - 16) & 1) * 4;
+ num += num + 3 + (unsigned)_bitStream.ReadBits9(num + 3);
+ num += i;
+ if (num > kTablesSizesSum)
+ num = kTablesSizesSum;
+ Byte v = 0;
+ if (sym < 16 + 2)
+ {
+ if (i == 0)
+ return S_FALSE;
+ v = lens[(size_t)i - 1];
+ }
+ do
+ lens[i++] = v;
+ while (i < num);
+ }
+ }
+ while (i < kTablesSizesSum);
+
+ if (_bitStream.IsBlockOverRead())
+ return S_FALSE;
+ if (_bitStream.InputEofError())
+ return S_FALSE;
+
+ RIF(m_MainDecoder.Build(&lens[0]))
+ RIF(m_DistDecoder.Build(&lens[kMainTableSize]))
+ RIF(m_AlignDecoder.Build(&lens[kMainTableSize + kDistTableSize]))
+ RIF(m_LenDecoder.Build(&lens[kMainTableSize + kDistTableSize + kAlignTableSize]))
+
+ _useAlignBits = false;
+ // _useAlignBits = true;
+ for (i = 0; i < kAlignTableSize; i++)
+ if (lens[kMainTableSize + kDistTableSize + (size_t)i] != kNumAlignBits)
+ {
+ _useAlignBits = true;
+ break;
+ }
+
+ _tableWasFilled = true;
+ return S_OK;
+}
+
+
+static inline unsigned SlotToLen(CBitDecoder &_bitStream, unsigned slot)
+{
+ if (slot < 8)
+ return slot + 2;
+ const unsigned numBits = (slot >> 2) - 1;
+ return 2 + ((4 | (slot & 3)) << numBits) + _bitStream.ReadBits9(numBits);
+}
+
+
+static const UInt32 kSymbolRep = 258;
+// static const unsigned kMaxMatchLen = 0x1001 + 3;
+
+HRESULT CDecoder::DecodeLZ()
+{
+ CBitDecoder _bitStream;
+ _bitStream._stream = _inStream;
+ _bitStream._bufBase = _inputBuf;
+ _bitStream.Init();
+
+ UInt32 rep0 = _reps[0];
+
+ UInt32 remLen = 0;
+
+ size_t limit;
+ {
+ size_t rem = _winSize - _winPos;
+ if (rem > kWriteStep)
+ rem = kWriteStep;
+ limit = _winPos + rem;
+ }
+
+ for (;;)
+ {
+ if (_winPos >= limit)
+ {
+ RINOK(WriteBuf())
+ if (_unpackSize_Defined && _writtenFileSize > _unpackSize)
+ break; // return S_FALSE;
+
+ {
+ size_t rem = _winSize - _winPos;
+
+ if (rem == 0)
+ {
+ _winPos = 0;
+ rem = _winSize;
+ }
+ if (rem > kWriteStep)
+ rem = kWriteStep;
+ limit = _winPos + rem;
+ }
+
+ if (remLen != 0)
+ {
+ size_t winPos = _winPos;
+ const size_t winMask = _winMask;
+ size_t pos = (winPos - (size_t)rep0 - 1) & winMask;
+
+ Byte *win = _window;
+ do
+ {
+ if (winPos >= limit)
+ break;
+ win[winPos] = win[pos];
+ winPos++;
+ pos = (pos + 1) & winMask;
+ }
+ while (--remLen != 0);
+
+ _lzSize += winPos - _winPos;
+ _winPos = winPos;
+ continue;
+ }
+ }
+
+ if (_bitStream._buf >= _bitStream._bufCheck2)
+ {
+ if (_bitStream.InputEofError())
+ break; // return S_FALSE;
+ if (_bitStream._buf >= _bitStream._bufCheck)
+ _bitStream.Prepare2();
+
+ const UInt64 processed = _bitStream.GetProcessedSize_Round();
+ if (processed >= _bitStream._blockEnd)
+ {
+ if (processed > _bitStream._blockEnd)
+ break; // return S_FALSE;
+ {
+ const unsigned bits7 = _bitStream.GetProcessedBits7();
+ if (bits7 > _bitStream._blockEndBits7)
+ break; // return S_FALSE;
+ if (bits7 == _bitStream._blockEndBits7)
+ {
+ if (_isLastBlock)
+ {
+ _reps[0] = rep0;
+
+ if (_bitStream.InputEofError())
+ break;
+
+ /*
+ // packSize can be 15 bytes larger for encrypted archive
+ if (_packSize_Defined && _packSize < _bitStream.GetProcessedSize())
+ break;
+ */
+
+ return _bitStream._hres;
+ // break;
+ }
+ RINOK(ReadTables(_bitStream))
+ continue;
+ }
+ }
+ }
+
+ // that check is not required, but it can help, if there is BUG in another code
+ if (!_tableWasFilled)
+ break; // return S_FALSE;
+ }
+
+ const UInt32 sym = m_MainDecoder.Decode(&_bitStream);
+
+ if (sym < 256)
+ {
+ size_t winPos = _winPos;
+ _window[winPos] = (Byte)sym;
+ _winPos = winPos + 1;
+ _lzSize++;
+ continue;
+ }
+
+ UInt32 len;
+
+ if (sym < kSymbolRep + kNumReps)
+ {
+ if (sym >= kSymbolRep)
+ {
+ if (sym != kSymbolRep)
+ {
+ UInt32 dist;
+ if (sym == kSymbolRep + 1)
+ dist = _reps[1];
+ else
+ {
+ if (sym == kSymbolRep + 2)
+ dist = _reps[2];
+ else
+ {
+ dist = _reps[3];
+ _reps[3] = _reps[2];
+ }
+ _reps[2] = _reps[1];
+ }
+ _reps[1] = rep0;
+ rep0 = dist;
+ }
+
+ const UInt32 sym2 = m_LenDecoder.Decode(&_bitStream);
+ if (sym2 >= kLenTableSize)
+ break; // return S_FALSE;
+ len = SlotToLen(_bitStream, sym2);
+ }
+ else
+ {
+ if (sym == 256)
+ {
+ RINOK(AddFilter(_bitStream))
+ continue;
+ }
+ else // if (sym == 257)
+ {
+ len = _lastLen;
+ // if (len = 0), we ignore that symbol, like original unRAR code, but it can mean error in stream.
+ // if (len == 0) return S_FALSE;
+ if (len == 0)
+ continue;
+ }
+ }
+ }
+ else if (sym >= kMainTableSize)
+ break; // return S_FALSE;
+ else
+ {
+ _reps[3] = _reps[2];
+ _reps[2] = _reps[1];
+ _reps[1] = rep0;
+ len = SlotToLen(_bitStream, sym - (kSymbolRep + kNumReps));
+
+ rep0 = m_DistDecoder.Decode(&_bitStream);
+
+ if (rep0 >= 4)
+ {
+ if (rep0 >= _numCorrectDistSymbols)
+ break; // return S_FALSE;
+ const unsigned numBits = (rep0 >> 1) - 1;
+ rep0 = (2 | (rep0 & 1)) << numBits;
+
+ if (numBits < kNumAlignBits)
+ rep0 += _bitStream.ReadBits9(numBits);
+ else
+ {
+ len += (numBits >= 7);
+ len += (numBits >= 12);
+ len += (numBits >= 17);
+
+ if (_useAlignBits)
+ {
+ // if (numBits > kNumAlignBits)
+ rep0 += (_bitStream.ReadBits32(numBits - kNumAlignBits) << kNumAlignBits);
+ const UInt32 a = m_AlignDecoder.Decode(&_bitStream);
+ if (a >= kAlignTableSize)
+ break; // return S_FALSE;
+ rep0 += a;
+ }
+ else
+ rep0 += _bitStream.ReadBits32(numBits);
+ }
+ }
+ }
+
+ _lastLen = len;
+
+ if (rep0 >= _lzSize)
+ _lzError = true;
+
+ {
+ UInt32 lenCur = len;
+ size_t winPos = _winPos;
+ size_t pos = (winPos - (size_t)rep0 - 1) & _winMask;
+ {
+ const size_t rem = limit - winPos;
+ // size_t rem = _winSize - winPos;
+
+ if (lenCur > rem)
+ {
+ lenCur = (UInt32)rem;
+ remLen = len - lenCur;
+ }
+ }
+
+ Byte *win = _window;
+ _lzSize += lenCur;
+ _winPos = winPos + lenCur;
+ if (_winSize - pos >= lenCur)
+ {
+ const Byte *src = win + pos;
+ Byte *dest = win + winPos;
+ do
+ *dest++ = *src++;
+ while (--lenCur != 0);
+ }
+ else
+ {
+ do
+ {
+ win[winPos] = win[pos];
+ winPos++;
+ pos = (pos + 1) & _winMask;
+ }
+ while (--lenCur != 0);
+ }
+ }
+ }
+
+ if (_bitStream._hres != S_OK)
+ return _bitStream._hres;
+
+ return S_FALSE;
+}
+
+
+HRESULT CDecoder::CodeReal()
+{
+ _unsupportedFilter = false;
+ _lzError = false;
+ _writeError = false;
+
+ if (!_isSolid || !_wasInit)
+ {
+ size_t clearSize = _winSize;
+ if (_lzSize < _winSize)
+ clearSize = (size_t)_lzSize;
+ memset(_window, 0, clearSize);
+
+ _wasInit = true;
+ _lzSize = 0;
+ _lzWritten = 0;
+ _winPos = 0;
+
+ for (unsigned i = 0; i < kNumReps; i++)
+ _reps[i] = (UInt32)0 - 1;
+
+ _lastLen = 0;
+ _tableWasFilled = false;
+ }
+
+ _isLastBlock = false;
+
+ InitFilters();
+
+ _filterEnd = 0;
+ _writtenFileSize = 0;
+
+ _lzFileStart = _lzSize;
+ _lzWritten = _lzSize;
+
+ HRESULT res = DecodeLZ();
+
+ HRESULT res2 = S_OK;
+ if (!_writeError && res != E_OUTOFMEMORY)
+ res2 = WriteBuf();
+
+ /*
+ if (res == S_OK)
+ if (InputEofError())
+ res = S_FALSE;
+ */
+
+ if (res == S_OK)
+ {
+ _solidAllowed = true;
+ res = res2;
+ }
+
+ if (res == S_OK && _unpackSize_Defined && _writtenFileSize != _unpackSize)
+ return S_FALSE;
+ return res;
+}
+
+
+// Original unRAR claims that maximum possible filter block size is (1 << 16) now,
+// and (1 << 17) is minimum win size required to support filter.
+// Original unRAR uses (1 << 18) for "extra safety and possible filter area size expansion"
+// We can use any win size.
+
+static const unsigned kWinSize_Log_Min = 17;
+
+Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ try
+ {
+ if (_isSolid && !_solidAllowed)
+ return S_FALSE;
+ _solidAllowed = false;
+
+ if (_dictSizeLog >= sizeof(size_t) * 8)
+ return E_NOTIMPL;
+
+ if (!_isSolid)
+ _lzEnd = 0;
+ else
+ {
+ if (_lzSize < _lzEnd)
+ {
+ if (_window)
+ {
+ UInt64 rem = _lzEnd - _lzSize;
+ if (rem >= _winSize)
+ memset(_window, 0, _winSize);
+ else
+ {
+ const size_t pos = (size_t)_lzSize & _winSize;
+ size_t rem2 = _winSize - pos;
+ if (rem2 > rem)
+ rem2 = (size_t)rem;
+ memset(_window + pos, 0, rem2);
+ rem -= rem2;
+ memset(_window, 0, (size_t)rem);
+ }
+ }
+ _lzEnd &= ((((UInt64)1) << 33) - 1);
+ _lzSize = _lzEnd;
+ _winPos = (size_t)(_lzSize & _winSize);
+ }
+ _lzEnd = _lzSize;
+ }
+
+ size_t newSize;
+ {
+ unsigned newSizeLog = _dictSizeLog;
+ if (newSizeLog < kWinSize_Log_Min)
+ newSizeLog = kWinSize_Log_Min;
+ newSize = (size_t)1 << newSizeLog;
+ _numCorrectDistSymbols = newSizeLog * 2;
+ }
+
+ // If dictionary was reduced, we use allocated dictionary block
+ // for compatibility with original unRAR decoder.
+
+ if (_window && newSize < _winSizeAllocated)
+ _winSize = _winSizeAllocated;
+ else if (!_window || _winSize != newSize)
+ {
+ if (!_isSolid)
+ {
+ ::MidFree(_window);
+ _window = NULL;
+ _winSizeAllocated = 0;
+ }
+
+ Byte *win;
+
+ {
+ win = (Byte *)::MidAlloc(newSize);
+ if (!win)
+ return E_OUTOFMEMORY;
+ memset(win, 0, newSize);
+ }
+
+ if (_isSolid && _window)
+ {
+ // original unRAR claims:
+ // "Archiving code guarantees that win size does not grow in the same solid stream",
+ // but the original unRAR decoder still supports such grow case.
+
+ Byte *winOld = _window;
+ const size_t oldSize = _winSize;
+ const size_t newMask = newSize - 1;
+ const size_t oldMask = _winSize - 1;
+ const size_t winPos = _winPos;
+ for (size_t i = 1; i <= oldSize; i++)
+ win[(winPos - i) & newMask] = winOld[(winPos - i) & oldMask];
+ ::MidFree(_window);
+ }
+
+ _window = win;
+ _winSizeAllocated = newSize;
+ _winSize = newSize;
+ }
+
+ _winMask = _winSize - 1;
+ _winPos &= _winMask;
+
+ if (!_inputBuf)
+ {
+ _inputBuf = (Byte *)::MidAlloc(kInputBufSize);
+ if (!_inputBuf)
+ return E_OUTOFMEMORY;
+ }
+
+ _inStream = inStream;
+ _outStream = outStream;
+
+ /*
+ _packSize = 0;
+ _packSize_Defined = (inSize != NULL);
+ if (_packSize_Defined)
+ _packSize = *inSize;
+ */
+
+ _unpackSize = 0;
+ _unpackSize_Defined = (outSize != NULL);
+ if (_unpackSize_Defined)
+ _unpackSize = *outSize;
+
+ if ((Int64)_unpackSize >= 0)
+ _lzEnd += _unpackSize;
+ else
+ _lzEnd = 0;
+
+ _progress = progress;
+
+ const HRESULT res = CodeReal();
+
+ if (res != S_OK)
+ return res;
+ if (_lzError)
+ return S_FALSE;
+ if (_unsupportedFilter)
+ return E_NOTIMPL;
+ return S_OK;
+ }
+ // catch(const CInBufferException &e) { return e.ErrorCode; }
+ // catch(...) { return S_FALSE; }
+ catch(...) { return E_OUTOFMEMORY; }
+ // CNewException is possible here. But probably CNewException is caused
+ // by error in data stream.
+}
+
+Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size))
+{
+ if (size != 2)
+ return E_NOTIMPL;
+ _dictSizeLog = (Byte)((data[0] & 0xF) + 17);
+ _isSolid = ((data[1] & 1) != 0);
+ return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Compress/Rar5Decoder.h b/CPP/7zip/Compress/Rar5Decoder.h
new file mode 100644
index 0000000..daf05dd
--- /dev/null
+++ b/CPP/7zip/Compress/Rar5Decoder.h
@@ -0,0 +1,299 @@
+// Rar5Decoder.h
+// According to unRAR license, this code may not be used to develop
+// a program that creates RAR archives
+
+#ifndef ZIP7_INC_COMPRESS_RAR5_DECODER_H
+#define ZIP7_INC_COMPRESS_RAR5_DECODER_H
+
+#include "../../../C/CpuArch.h"
+
+#include "../../Common/MyBuffer2.h"
+#include "../../Common/MyCom.h"
+#include "../../Common/MyException.h"
+#include "../../Common/MyVector.h"
+
+#include "../ICoder.h"
+
+#include "HuffmanDecoder.h"
+
+namespace NCompress {
+namespace NRar5 {
+
+/*
+struct CInBufferException: public CSystemException
+{
+ CInBufferException(HRESULT errorCode): CSystemException(errorCode) {}
+};
+*/
+
+class CBitDecoder
+{
+public:
+ const Byte *_buf;
+ unsigned _bitPos;
+ bool _wasFinished;
+ Byte _blockEndBits7;
+ const Byte *_bufCheck2;
+ const Byte *_bufCheck;
+ Byte *_bufLim;
+ Byte *_bufBase;
+
+ UInt64 _processedSize;
+ UInt64 _blockEnd;
+
+ ISequentialInStream *_stream;
+ HRESULT _hres;
+
+ void SetCheck2()
+ {
+ _bufCheck2 = _bufCheck;
+ if (_bufCheck > _buf)
+ {
+ UInt64 processed = GetProcessedSize_Round();
+ if (_blockEnd < processed)
+ _bufCheck2 = _buf;
+ else
+ {
+ const UInt64 delta = _blockEnd - processed;
+ if ((size_t)(_bufCheck - _buf) > delta)
+ _bufCheck2 = _buf + (size_t)delta;
+ }
+ }
+ }
+
+ bool IsBlockOverRead() const
+ {
+ const UInt64 v = GetProcessedSize_Round();
+ if (v < _blockEnd)
+ return false;
+ if (v > _blockEnd)
+ return true;
+ return _bitPos > _blockEndBits7;
+ }
+
+ /*
+ CBitDecoder() throw():
+ _buf(0),
+ _bufLim(0),
+ _bufBase(0),
+ _stream(0),
+ _processedSize(0),
+ _wasFinished(false)
+ {}
+ */
+
+ void Init() throw()
+ {
+ _blockEnd = 0;
+ _blockEndBits7 = 0;
+
+ _bitPos = 0;
+ _processedSize = 0;
+ _buf = _bufBase;
+ _bufLim = _bufBase;
+ _bufCheck = _buf;
+ _bufCheck2 = _buf;
+ _wasFinished = false;
+ }
+
+ void Prepare2() throw();
+
+ void Prepare() throw()
+ {
+ if (_buf >= _bufCheck)
+ Prepare2();
+ }
+
+ bool ExtraBitsWereRead() const
+ {
+ return _buf >= _bufLim && (_buf > _bufLim || _bitPos != 0);
+ }
+
+ bool InputEofError() const { return ExtraBitsWereRead(); }
+
+ unsigned GetProcessedBits7() const { return _bitPos; }
+ UInt64 GetProcessedSize_Round() const { return _processedSize + (size_t)(_buf - _bufBase); }
+ UInt64 GetProcessedSize() const { return _processedSize + (size_t)(_buf - _bufBase) + ((_bitPos + 7) >> 3); }
+
+ void AlignToByte()
+ {
+ _buf += (_bitPos + 7) >> 3;
+ _bitPos = 0;
+ }
+
+ Byte ReadByteInAligned()
+ {
+ return *_buf++;
+ }
+
+ UInt32 GetValue(unsigned numBits) const
+ {
+ UInt32 v = ((UInt32)_buf[0] << 16) | ((UInt32)_buf[1] << 8) | (UInt32)_buf[2];
+ v >>= (24 - numBits - _bitPos);
+ return v & ((1 << numBits) - 1);
+ }
+
+ void MovePos(unsigned numBits)
+ {
+ _bitPos += numBits;
+ _buf += (_bitPos >> 3);
+ _bitPos &= 7;
+ }
+
+ UInt32 ReadBits9(unsigned numBits)
+ {
+ const Byte *buf = _buf;
+ UInt32 v = ((UInt32)buf[0] << 8) | (UInt32)buf[1];
+ v &= ((UInt32)0xFFFF >> _bitPos);
+ numBits += _bitPos;
+ v >>= (16 - numBits);
+ _buf = buf + (numBits >> 3);
+ _bitPos = numBits & 7;
+ return v;
+ }
+
+ UInt32 ReadBits9fix(unsigned numBits)
+ {
+ const Byte *buf = _buf;
+ UInt32 v = ((UInt32)buf[0] << 8) | (UInt32)buf[1];
+ const UInt32 mask = ((1 << numBits) - 1);
+ numBits += _bitPos;
+ v >>= (16 - numBits);
+ _buf = buf + (numBits >> 3);
+ _bitPos = numBits & 7;
+ return v & mask;
+ }
+
+ UInt32 ReadBits32(unsigned numBits)
+ {
+ const UInt32 mask = ((1 << numBits) - 1);
+ numBits += _bitPos;
+ const Byte *buf = _buf;
+ UInt32 v = GetBe32(buf);
+ if (numBits > 32)
+ {
+ v <<= (numBits - 32);
+ v |= (UInt32)buf[4] >> (40 - numBits);
+ }
+ else
+ v >>= (32 - numBits);
+ _buf = buf + (numBits >> 3);
+ _bitPos = numBits & 7;
+ return v & mask;
+ }
+};
+
+
+struct CFilter
+{
+ Byte Type;
+ Byte Channels;
+ UInt32 Size;
+ UInt64 Start;
+};
+
+
+const unsigned kNumReps = 4;
+const unsigned kLenTableSize = 11 * 4;
+const unsigned kMainTableSize = 256 + 1 + 1 + kNumReps + kLenTableSize;
+const unsigned kDistTableSize = 64;
+const unsigned kNumAlignBits = 4;
+const unsigned kAlignTableSize = (1 << kNumAlignBits);
+const unsigned kLevelTableSize = 20;
+const unsigned kTablesSizesSum = kMainTableSize + kDistTableSize + kAlignTableSize + kLenTableSize;
+
+const unsigned kNumHuffmanBits = 15;
+
+Z7_CLASS_IMP_NOQIB_2(
+ CDecoder
+ , ICompressCoder
+ , ICompressSetDecoderProperties2
+)
+ bool _useAlignBits;
+ bool _isLastBlock;
+ bool _unpackSize_Defined;
+ // bool _packSize_Defined;
+
+ bool _unsupportedFilter;
+ bool _lzError;
+ bool _writeError;
+
+ bool _isSolid;
+ bool _solidAllowed;
+ bool _tableWasFilled;
+ bool _wasInit;
+
+ Byte _dictSizeLog;
+
+ // CBitDecoder _bitStream;
+ Byte *_window;
+ size_t _winPos;
+ size_t _winSize;
+ size_t _winMask;
+
+ UInt64 _lzSize;
+
+ unsigned _numCorrectDistSymbols;
+ unsigned _numUnusedFilters;
+
+ UInt64 _lzWritten;
+ UInt64 _lzFileStart;
+ UInt64 _unpackSize;
+ // UInt64 _packSize;
+ UInt64 _lzEnd;
+ UInt64 _writtenFileSize;
+ size_t _winSizeAllocated;
+
+ UInt32 _reps[kNumReps];
+ UInt32 _lastLen;
+
+ UInt64 _filterEnd;
+ CMidBuffer _filterSrc;
+ CMidBuffer _filterDst;
+
+ CRecordVector<CFilter> _filters;
+
+ ISequentialInStream *_inStream;
+ ISequentialOutStream *_outStream;
+ ICompressProgressInfo *_progress;
+ Byte *_inputBuf;
+
+ NHuffman::CDecoder<kNumHuffmanBits, kMainTableSize> m_MainDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kDistTableSize> m_DistDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kAlignTableSize> m_AlignDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kLenTableSize> m_LenDecoder;
+ NHuffman::CDecoder<kNumHuffmanBits, kLevelTableSize> m_LevelDecoder;
+
+
+ void InitFilters()
+ {
+ _numUnusedFilters = 0;
+ _filters.Clear();
+ }
+
+ void DeleteUnusedFilters()
+ {
+ if (_numUnusedFilters != 0)
+ {
+ _filters.DeleteFrontal(_numUnusedFilters);
+ _numUnusedFilters = 0;
+ }
+ }
+
+ HRESULT WriteData(const Byte *data, size_t size);
+ HRESULT ExecuteFilter(const CFilter &f);
+ HRESULT WriteBuf();
+ HRESULT AddFilter(CBitDecoder &_bitStream);
+
+ HRESULT ReadTables(CBitDecoder &_bitStream);
+ HRESULT DecodeLZ();
+ HRESULT CodeReal();
+
+public:
+ CDecoder();
+ ~CDecoder();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/RarCodecsRegister.cpp b/CPP/7zip/Compress/RarCodecsRegister.cpp
new file mode 100644
index 0000000..e1bc3d9
--- /dev/null
+++ b/CPP/7zip/Compress/RarCodecsRegister.cpp
@@ -0,0 +1,33 @@
+// RarCodecsRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "Rar1Decoder.h"
+#include "Rar2Decoder.h"
+#include "Rar3Decoder.h"
+#include "Rar5Decoder.h"
+
+namespace NCompress {
+
+#define CREATE_CODEC(x) REGISTER_CODEC_CREATE(CreateCodec ## x, NRar ## x::CDecoder())
+
+CREATE_CODEC(1)
+CREATE_CODEC(2)
+CREATE_CODEC(3)
+CREATE_CODEC(5)
+
+#define RAR_CODEC(x, name) { CreateCodec ## x, NULL, 0x40300 + x, "Rar" name, 1, false }
+
+REGISTER_CODECS_VAR
+{
+ RAR_CODEC(1, "1"),
+ RAR_CODEC(2, "2"),
+ RAR_CODEC(3, "3"),
+ RAR_CODEC(5, "5"),
+};
+
+REGISTER_CODECS(Rar)
+
+}
diff --git a/CPP/7zip/Compress/ShrinkDecoder.cpp b/CPP/7zip/Compress/ShrinkDecoder.cpp
new file mode 100644
index 0000000..c8e2083
--- /dev/null
+++ b/CPP/7zip/Compress/ShrinkDecoder.cpp
@@ -0,0 +1,244 @@
+// ShrinkDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/OutBuffer.h"
+
+#include "BitlDecoder.h"
+#include "ShrinkDecoder.h"
+
+namespace NCompress {
+namespace NShrink {
+
+static const UInt32 kEmpty = 256; // kNumItems;
+static const UInt32 kBufferSize = (1 << 18);
+static const unsigned kNumMinBits = 9;
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress)
+{
+ NBitl::CBaseDecoder<CInBuffer> inBuffer;
+ COutBuffer outBuffer;
+
+ if (!inBuffer.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+ if (!outBuffer.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+
+ inBuffer.SetStream(inStream);
+ inBuffer.Init();
+
+ outBuffer.SetStream(outStream);
+ outBuffer.Init();
+
+ {
+ for (unsigned i = 0; i < kNumItems; i++)
+ _parents[i] = kEmpty;
+ }
+
+ UInt64 outPrev = 0, inPrev = 0;
+ unsigned numBits = kNumMinBits;
+ unsigned head = 257;
+ int lastSym = -1;
+ Byte lastChar = 0;
+ bool moreOut = false;
+
+ HRESULT res = S_FALSE;
+
+ for (;;)
+ {
+ _inProcessed = inBuffer.GetProcessedSize();
+ const UInt64 nowPos = outBuffer.GetProcessedSize();
+
+ bool eofCheck = false;
+
+ if (outSize && nowPos >= *outSize)
+ {
+ if (!_fullStreamMode || moreOut)
+ {
+ res = S_OK;
+ break;
+ }
+ eofCheck = true;
+ // Is specSym(=256) allowed after end of stream ?
+ // Do we need to read it here ?
+ }
+
+ if (progress)
+ {
+ if (nowPos - outPrev >= (1 << 20) || _inProcessed - inPrev >= (1 << 20))
+ {
+ outPrev = nowPos;
+ inPrev = _inProcessed;
+ res = progress->SetRatioInfo(&_inProcessed, &nowPos);
+ if (res != SZ_OK)
+ {
+ // break;
+ return res;
+ }
+ }
+ }
+
+ UInt32 sym = inBuffer.ReadBits(numBits);
+
+ if (inBuffer.ExtraBitsWereRead())
+ {
+ res = S_OK;
+ break;
+ }
+
+ if (sym == 256)
+ {
+ sym = inBuffer.ReadBits(numBits);
+
+ if (inBuffer.ExtraBitsWereRead())
+ break;
+
+ if (sym == 1)
+ {
+ if (numBits >= kNumMaxBits)
+ break;
+ numBits++;
+ continue;
+ }
+ if (sym != 2)
+ {
+ break;
+ // continue; // info-zip just ignores such code
+ }
+ {
+ /*
+ ---------- Free leaf nodes ----------
+ Note : that code can mark _parents[lastSym] as free, and next
+ inserted node will be Orphan in that case.
+ */
+
+ unsigned i;
+ for (i = 256; i < kNumItems; i++)
+ _stack[i] = 0;
+ for (i = 257; i < kNumItems; i++)
+ {
+ unsigned par = _parents[i];
+ if (par != kEmpty)
+ _stack[par] = 1;
+ }
+ for (i = 257; i < kNumItems; i++)
+ if (_stack[i] == 0)
+ _parents[i] = kEmpty;
+ head = 257;
+ continue;
+ }
+ }
+
+ if (eofCheck)
+ {
+ // It's can be error case.
+ // That error can be detected later in (*inSize != _inProcessed) check.
+ res = S_OK;
+ break;
+ }
+
+ bool needPrev = false;
+ if (head < kNumItems && lastSym >= 0)
+ {
+ while (head < kNumItems && _parents[head] != kEmpty)
+ head++;
+ if (head < kNumItems)
+ {
+ /*
+ if (head == lastSym), it updates Orphan to self-linked Orphan and creates two problems:
+ 1) we must check _stack[i++] overflow in code that walks tree nodes.
+ 2) self-linked node can not be removed. So such self-linked nodes can occupy all _parents items.
+ */
+ needPrev = true;
+ _parents[head] = (UInt16)lastSym;
+ _suffixes[head] = (Byte)lastChar;
+ head++;
+ }
+ }
+
+ lastSym = (int)sym;
+ unsigned cur = sym;
+ unsigned i = 0;
+
+ while (cur >= 256)
+ {
+ _stack[i++] = _suffixes[cur];
+ cur = _parents[cur];
+ // don't change that code:
+ // Orphan Check and self-linked Orphan check (_stack overflow check);
+ if (cur == kEmpty || i >= kNumItems)
+ break;
+ }
+
+ if (cur == kEmpty || i >= kNumItems)
+ break;
+
+ _stack[i++] = (Byte)cur;
+ lastChar = (Byte)cur;
+
+ if (needPrev)
+ _suffixes[(size_t)head - 1] = (Byte)cur;
+
+ if (outSize)
+ {
+ const UInt64 limit = *outSize - nowPos;
+ if (i > limit)
+ {
+ moreOut = true;
+ i = (unsigned)limit;
+ }
+ }
+
+ do
+ outBuffer.WriteByte(_stack[--i]);
+ while (i);
+ }
+
+ RINOK(outBuffer.Flush())
+
+ if (res == S_OK)
+ if (_fullStreamMode)
+ {
+ if (moreOut)
+ res = S_FALSE;
+ const UInt64 nowPos = outBuffer.GetProcessedSize();
+ if (outSize && *outSize != nowPos)
+ res = S_FALSE;
+ if (inSize && *inSize != _inProcessed)
+ res = S_FALSE;
+ }
+
+ return res;
+}
+
+
+Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ // catch(const CInBufferException &e) { return e.ErrorCode; }
+ // catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(const CSystemException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+
+Z7_COM7F_IMF(CDecoder::SetFinishMode(UInt32 finishMode))
+{
+ _fullStreamMode = (finishMode != 0);
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CDecoder::GetInStreamProcessedSize(UInt64 *value))
+{
+ *value = _inProcessed;
+ return S_OK;
+}
+
+
+}}
diff --git a/CPP/7zip/Compress/ShrinkDecoder.h b/CPP/7zip/Compress/ShrinkDecoder.h
new file mode 100644
index 0000000..5e7f78f
--- /dev/null
+++ b/CPP/7zip/Compress/ShrinkDecoder.h
@@ -0,0 +1,35 @@
+// ShrinkDecoder.h
+
+#ifndef ZIP7_INC_COMPRESS_SHRINK_DECODER_H
+#define ZIP7_INC_COMPRESS_SHRINK_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NShrink {
+
+const unsigned kNumMaxBits = 13;
+const unsigned kNumItems = 1 << kNumMaxBits;
+
+Z7_CLASS_IMP_NOQIB_3(
+ CDecoder
+ , ICompressCoder
+ , ICompressSetFinishMode
+ , ICompressGetInStreamProcessedSize
+)
+ bool _fullStreamMode;
+ UInt64 _inProcessed;
+
+ UInt16 _parents[kNumItems];
+ Byte _suffixes[kNumItems];
+ Byte _stack[kNumItems];
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/StdAfx.h b/CPP/7zip/Compress/StdAfx.h
index 42a088f..8086655 100644
--- a/CPP/7zip/Compress/StdAfx.h
+++ b/CPP/7zip/Compress/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "../../Common/Common.h"
-
-#endif
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Compress/XpressDecoder.cpp b/CPP/7zip/Compress/XpressDecoder.cpp
new file mode 100644
index 0000000..8816a12
--- /dev/null
+++ b/CPP/7zip/Compress/XpressDecoder.cpp
@@ -0,0 +1,131 @@
+// XpressDecoder.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../C/CpuArch.h"
+
+#include "HuffmanDecoder.h"
+#include "XpressDecoder.h"
+
+namespace NCompress {
+namespace NXpress {
+
+struct CBitStream
+{
+ UInt32 Value;
+ unsigned BitPos;
+
+ UInt32 GetValue(unsigned numBits) const
+ {
+ return (Value >> (BitPos - numBits)) & ((1 << numBits) - 1);
+ }
+
+ void MovePos(unsigned numBits)
+ {
+ BitPos -= numBits;
+ }
+};
+
+#define BIT_STREAM_NORMALIZE \
+ if (bs.BitPos < 16) { \
+ if (in >= lim) return S_FALSE; \
+ bs.Value = (bs.Value << 16) | GetUi16(in); \
+ in += 2; bs.BitPos += 16; }
+
+static const unsigned kNumHuffBits = 15;
+static const unsigned kNumLenBits = 4;
+static const unsigned kLenMask = (1 << kNumLenBits) - 1;
+static const unsigned kNumPosSlots = 16;
+static const unsigned kNumSyms = 256 + (kNumPosSlots << kNumLenBits);
+
+HRESULT Decode(const Byte *in, size_t inSize, Byte *out, size_t outSize)
+{
+ NCompress::NHuffman::CDecoder<kNumHuffBits, kNumSyms> huff;
+
+ if (inSize < kNumSyms / 2 + 4)
+ return S_FALSE;
+ {
+ Byte levels[kNumSyms];
+ for (unsigned i = 0; i < kNumSyms / 2; i++)
+ {
+ const Byte b = in[i];
+ levels[(size_t)i * 2] = (Byte)(b & 0xF);
+ levels[(size_t)i * 2 + 1] = (Byte)(b >> 4);
+ }
+ if (!huff.BuildFull(levels))
+ return S_FALSE;
+ }
+
+
+ CBitStream bs;
+
+ const Byte *lim = in + inSize - 1;
+
+ in += kNumSyms / 2;
+ bs.Value = ((UInt32)GetUi16(in) << 16) | GetUi16(in + 2);
+ in += 4;
+ bs.BitPos = 32;
+
+ size_t pos = 0;
+
+ for (;;)
+ {
+ // printf("\n%d", pos);
+ UInt32 sym = huff.DecodeFull(&bs);
+ // printf(" sym = %d", sym);
+ BIT_STREAM_NORMALIZE
+
+ if (pos >= outSize)
+ return (sym == 256 && in == lim + 1) ? S_OK : S_FALSE;
+
+ if (sym < 256)
+ out[pos++] = (Byte)sym;
+ else
+ {
+ sym -= 256;
+ UInt32 dist = sym >> kNumLenBits;
+ UInt32 len = sym & kLenMask;
+
+ if (len == kLenMask)
+ {
+ if (in > lim)
+ return S_FALSE;
+ len = *in++;
+ if (len == 0xFF)
+ {
+ if (in >= lim)
+ return S_FALSE;
+ len = GetUi16(in);
+ in += 2;
+ }
+ else
+ len += kLenMask;
+ }
+
+ bs.BitPos -= dist;
+ dist = (UInt32)1 << dist;
+ dist += ((bs.Value >> bs.BitPos) & (dist - 1));
+
+ BIT_STREAM_NORMALIZE
+
+ if (len + 3 > outSize - pos)
+ return S_FALSE;
+ if (dist > pos)
+ return S_FALSE;
+
+ Byte *dest = out + pos;
+ const Byte *src = dest - dist;
+ pos += len + 3;
+ len += 1;
+ *dest++ = *src++;
+ *dest++ = *src++;
+ do
+ *dest++ = *src++;
+ while (--len);
+ }
+ }
+}
+
+}}
diff --git a/CPP/7zip/Compress/XpressDecoder.h b/CPP/7zip/Compress/XpressDecoder.h
new file mode 100644
index 0000000..aaa5b25
--- /dev/null
+++ b/CPP/7zip/Compress/XpressDecoder.h
@@ -0,0 +1,15 @@
+// XpressDecoder.h
+
+#ifndef ZIP7_INC_XPRESS_DECODER_H
+#define ZIP7_INC_XPRESS_DECODER_H
+
+#include "../../Common/MyWindows.h"
+
+namespace NCompress {
+namespace NXpress {
+
+HRESULT Decode(const Byte *in, size_t inSize, Byte *out, size_t outSize);
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/XzDecoder.cpp b/CPP/7zip/Compress/XzDecoder.cpp
index 4fcd09f..420bd71 100644
--- a/CPP/7zip/Compress/XzDecoder.cpp
+++ b/CPP/7zip/Compress/XzDecoder.cpp
@@ -1,150 +1,150 @@
-// XzDecoder.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/Alloc.h"
-
-#include "../Common/CWrappers.h"
-
-#include "XzDecoder.h"
-
-namespace NCompress {
-namespace NXz {
-
-#define RET_IF_WRAP_ERROR_CONFIRMED(wrapRes, sRes, sResErrorCode) \
- if (wrapRes != S_OK && sRes == sResErrorCode) return wrapRes;
-
-#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
- if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
-
-static HRESULT SResToHRESULT_Code(SRes res) throw()
-{
- if (res < 0)
- return res;
- switch (res)
- {
- case SZ_OK: return S_OK;
- case SZ_ERROR_MEM: return E_OUTOFMEMORY;
- case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL;
- }
- return S_FALSE;
-}
-
-
-HRESULT CDecoder::Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream,
- const UInt64 *outSizeLimit, bool finishStream, ICompressProgressInfo *progress)
-{
- MainDecodeSRes = S_OK;
- MainDecodeSRes_wasUsed = false;
- XzStatInfo_Clear(&Stat);
-
- if (!xz)
- {
- xz = XzDecMt_Create(&g_Alloc, &g_MidAlloc);
- if (!xz)
- return E_OUTOFMEMORY;
- }
-
- CXzDecMtProps props;
- XzDecMtProps_Init(&props);
-
- int isMT = False;
-
- #ifndef _7ZIP_ST
- {
- props.numThreads = 1;
- UInt32 numThreads = _numThreads;
-
- if (_tryMt && numThreads > 1)
- {
- size_t memUsage = (size_t)_memUsage;
- if (memUsage != _memUsage)
- memUsage = (size_t)0 - 1;
- props.memUseMax = memUsage;
- isMT = (numThreads > 1);
- }
-
- props.numThreads = numThreads;
- }
- #endif
-
- CSeqInStreamWrap inWrap;
- CSeqOutStreamWrap outWrap;
- CCompressProgressWrap progressWrap;
-
- inWrap.Init(seqInStream);
- outWrap.Init(outStream);
- progressWrap.Init(progress);
-
- SRes res = XzDecMt_Decode(xz,
- &props,
- outSizeLimit, finishStream,
- &outWrap.vt,
- &inWrap.vt,
- &Stat,
- &isMT,
- progress ? &progressWrap.vt : NULL);
-
- MainDecodeSRes = res;
-
- #ifndef _7ZIP_ST
- // _tryMt = isMT;
- #endif
-
- RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
- RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
- RET_IF_WRAP_ERROR_CONFIRMED(inWrap.Res, res, SZ_ERROR_READ)
-
- // return E_OUTOFMEMORY;
-
- MainDecodeSRes_wasUsed = true;
-
- if (res == SZ_OK && finishStream)
- {
- /*
- if (inSize && *inSize != Stat.PhySize)
- res = SZ_ERROR_DATA;
- */
- if (outSizeLimit && *outSizeLimit != outWrap.Processed)
- res = SZ_ERROR_DATA;
- }
-
- return SResToHRESULT_Code(res);
-}
-
-
-HRESULT CComDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress)
-{
- return Decode(inStream, outStream, outSize, _finishStream, progress);
-}
-
-STDMETHODIMP CComDecoder::SetFinishMode(UInt32 finishMode)
-{
- _finishStream = (finishMode != 0);
- return S_OK;
-}
-
-STDMETHODIMP CComDecoder::GetInStreamProcessedSize(UInt64 *value)
-{
- *value = Stat.InSize;
- return S_OK;
-}
-
-#ifndef _7ZIP_ST
-
-STDMETHODIMP CComDecoder::SetNumberOfThreads(UInt32 numThreads)
-{
- _numThreads = numThreads;
- return S_OK;
-}
-
-STDMETHODIMP CComDecoder::SetMemLimit(UInt64 memUsage)
-{
- _memUsage = memUsage;
- return S_OK;
-}
-
-#endif
-
-}}
+// XzDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/CWrappers.h"
+
+#include "XzDecoder.h"
+
+namespace NCompress {
+namespace NXz {
+
+#define RET_IF_WRAP_ERROR_CONFIRMED(wrapRes, sRes, sResErrorCode) \
+ if (wrapRes != S_OK && sRes == sResErrorCode) return wrapRes;
+
+#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
+ if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
+
+static HRESULT SResToHRESULT_Code(SRes res) throw()
+{
+ if (res < 0)
+ return res;
+ switch (res)
+ {
+ case SZ_OK: return S_OK;
+ case SZ_ERROR_MEM: return E_OUTOFMEMORY;
+ case SZ_ERROR_UNSUPPORTED: return E_NOTIMPL;
+ }
+ return S_FALSE;
+}
+
+
+HRESULT CDecoder::Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream,
+ const UInt64 *outSizeLimit, bool finishStream, ICompressProgressInfo *progress)
+{
+ MainDecodeSRes = SZ_OK;
+ MainDecodeSRes_wasUsed = false;
+ XzStatInfo_Clear(&Stat);
+
+ if (!xz)
+ {
+ xz = XzDecMt_Create(&g_Alloc, &g_MidAlloc);
+ if (!xz)
+ return E_OUTOFMEMORY;
+ }
+
+ CXzDecMtProps props;
+ XzDecMtProps_Init(&props);
+
+ int isMT = False;
+
+ #ifndef Z7_ST
+ {
+ props.numThreads = 1;
+ const UInt32 numThreads = _numThreads;
+
+ if (_tryMt && numThreads > 1)
+ {
+ size_t memUsage = (size_t)_memUsage;
+ if (memUsage != _memUsage)
+ memUsage = (size_t)0 - 1;
+ props.memUseMax = memUsage;
+ isMT = (numThreads > 1);
+ }
+
+ props.numThreads = numThreads;
+ }
+ #endif
+
+ CSeqInStreamWrap inWrap;
+ CSeqOutStreamWrap outWrap;
+ CCompressProgressWrap progressWrap;
+
+ inWrap.Init(seqInStream);
+ outWrap.Init(outStream);
+ progressWrap.Init(progress);
+
+ SRes res = XzDecMt_Decode(xz,
+ &props,
+ outSizeLimit, finishStream,
+ &outWrap.vt,
+ &inWrap.vt,
+ &Stat,
+ &isMT,
+ progress ? &progressWrap.vt : NULL);
+
+ MainDecodeSRes = res;
+
+ #ifndef Z7_ST
+ // _tryMt = isMT;
+ #endif
+
+ RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
+ RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
+ RET_IF_WRAP_ERROR_CONFIRMED(inWrap.Res, res, SZ_ERROR_READ)
+
+ // return E_OUTOFMEMORY; // for debug check
+
+ MainDecodeSRes_wasUsed = true;
+
+ if (res == SZ_OK && finishStream)
+ {
+ /*
+ if (inSize && *inSize != Stat.PhySize)
+ res = SZ_ERROR_DATA;
+ */
+ if (outSizeLimit && *outSizeLimit != outWrap.Processed)
+ res = SZ_ERROR_DATA;
+ }
+
+ return SResToHRESULT_Code(res);
+}
+
+
+Z7_COM7F_IMF(CComDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ return Decode(inStream, outStream, outSize, _finishStream, progress);
+}
+
+Z7_COM7F_IMF(CComDecoder::SetFinishMode(UInt32 finishMode))
+{
+ _finishStream = (finishMode != 0);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CComDecoder::GetInStreamProcessedSize(UInt64 *value))
+{
+ *value = Stat.InSize;
+ return S_OK;
+}
+
+#ifndef Z7_ST
+
+Z7_COM7F_IMF(CComDecoder::SetNumberOfThreads(UInt32 numThreads))
+{
+ _numThreads = numThreads;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CComDecoder::SetMemLimit(UInt64 memUsage))
+{
+ _memUsage = memUsage;
+ return S_OK;
+}
+
+#endif
+
+}}
diff --git a/CPP/7zip/Compress/XzDecoder.h b/CPP/7zip/Compress/XzDecoder.h
index 76694ee..40ed4f5 100644
--- a/CPP/7zip/Compress/XzDecoder.h
+++ b/CPP/7zip/Compress/XzDecoder.h
@@ -1,92 +1,86 @@
-// XzDecoder.h
-
-#ifndef __XZ_DECODER_H
-#define __XZ_DECODER_H
-
-#include "../../../C/Xz.h"
-
-#include "../../Common/MyCom.h"
-
-#include "../ICoder.h"
-
-namespace NCompress {
-namespace NXz {
-
-struct CDecoder
-{
- CXzDecMtHandle xz;
- int _tryMt;
- UInt32 _numThreads;
- UInt64 _memUsage;
-
- SRes MainDecodeSRes; // it's not HRESULT
- bool MainDecodeSRes_wasUsed;
- CXzStatInfo Stat;
-
- CDecoder():
- xz(NULL),
- _tryMt(True),
- _numThreads(1),
- _memUsage((UInt64)(sizeof(size_t)) << 28),
- MainDecodeSRes(SZ_OK),
- MainDecodeSRes_wasUsed(false)
- {}
-
- ~CDecoder()
- {
- if (xz)
- XzDecMt_Destroy(xz);
- }
-
- /* Decode() can return ERROR code only if there is progress or stream error.
- Decode() returns S_OK in case of xz decoding error, but DecodeRes and CStatInfo contain error information */
- HRESULT Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream,
- const UInt64 *outSizeLimit, bool finishStream, ICompressProgressInfo *compressProgress);
-};
-
-
-class CComDecoder:
- public ICompressCoder,
- public ICompressSetFinishMode,
- public ICompressGetInStreamProcessedSize,
-
- #ifndef _7ZIP_ST
- public ICompressSetCoderMt,
- public ICompressSetMemLimit,
- #endif
-
- public CMyUnknownImp,
- public CDecoder
-{
- bool _finishStream;
-
-public:
- MY_QUERYINTERFACE_BEGIN2(ICompressCoder)
-
- MY_QUERYINTERFACE_ENTRY(ICompressSetFinishMode)
- MY_QUERYINTERFACE_ENTRY(ICompressGetInStreamProcessedSize)
-
- #ifndef _7ZIP_ST
- MY_QUERYINTERFACE_ENTRY(ICompressSetCoderMt)
- MY_QUERYINTERFACE_ENTRY(ICompressSetMemLimit)
- #endif
-
- MY_QUERYINTERFACE_END
- MY_ADDREF_RELEASE
-
- STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
- STDMETHOD(SetFinishMode)(UInt32 finishMode);
- STDMETHOD(GetInStreamProcessedSize)(UInt64 *value);
-
- #ifndef _7ZIP_ST
- STDMETHOD(SetNumberOfThreads)(UInt32 numThreads);
- STDMETHOD(SetMemLimit)(UInt64 memUsage);
- #endif
-
- CComDecoder(): _finishStream(false) {}
-};
-
-}}
-
-#endif
+// XzDecoder.h
+
+#ifndef ZIP7_INC_XZ_DECODER_H
+#define ZIP7_INC_XZ_DECODER_H
+
+#include "../../../C/Xz.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NXz {
+
+struct CDecoder
+{
+ CXzDecMtHandle xz;
+ int _tryMt;
+ UInt32 _numThreads;
+ UInt64 _memUsage;
+
+ SRes MainDecodeSRes; // it's not HRESULT
+ bool MainDecodeSRes_wasUsed;
+ CXzStatInfo Stat;
+
+ CDecoder():
+ xz(NULL),
+ _tryMt(True),
+ _numThreads(1),
+ _memUsage((UInt64)(sizeof(size_t)) << 28),
+ MainDecodeSRes(SZ_OK),
+ MainDecodeSRes_wasUsed(false)
+ {}
+
+ ~CDecoder()
+ {
+ if (xz)
+ XzDecMt_Destroy(xz);
+ }
+
+ /* Decode() can return S_OK, if there is data after good xz streams, and that data is not new xz stream.
+ check also (Stat.DataAfterEnd) flag */
+
+ HRESULT Decode(ISequentialInStream *seqInStream, ISequentialOutStream *outStream,
+ const UInt64 *outSizeLimit, bool finishStream, ICompressProgressInfo *compressProgress);
+};
+
+
+class CComDecoder Z7_final:
+ public ICompressCoder,
+ public ICompressSetFinishMode,
+ public ICompressGetInStreamProcessedSize,
+ #ifndef Z7_ST
+ public ICompressSetCoderMt,
+ public ICompressSetMemLimit,
+ #endif
+ public CMyUnknownImp,
+ public CDecoder
+{
+ Z7_COM_QI_BEGIN2(ICompressCoder)
+ Z7_COM_QI_ENTRY(ICompressSetFinishMode)
+ Z7_COM_QI_ENTRY(ICompressGetInStreamProcessedSize)
+ #ifndef Z7_ST
+ Z7_COM_QI_ENTRY(ICompressSetCoderMt)
+ Z7_COM_QI_ENTRY(ICompressSetMemLimit)
+ #endif
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(ICompressCoder)
+ Z7_IFACE_COM7_IMP(ICompressSetFinishMode)
+ Z7_IFACE_COM7_IMP(ICompressGetInStreamProcessedSize)
+ #ifndef Z7_ST
+ Z7_IFACE_COM7_IMP(ICompressSetCoderMt)
+ Z7_IFACE_COM7_IMP(ICompressSetMemLimit)
+ #endif
+
+ bool _finishStream;
+
+public:
+ CComDecoder(): _finishStream(false) {}
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/XzEncoder.cpp b/CPP/7zip/Compress/XzEncoder.cpp
index 458a928..33f0bde 100644
--- a/CPP/7zip/Compress/XzEncoder.cpp
+++ b/CPP/7zip/Compress/XzEncoder.cpp
@@ -1,245 +1,243 @@
-// XzEncoder.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/Alloc.h"
-
-#include "../../Common/MyString.h"
-#include "../../Common/StringToInt.h"
-
-#include "../Common/CWrappers.h"
-#include "../Common/StreamUtils.h"
-
-#include "XzEncoder.h"
-
-namespace NCompress {
-
-namespace NLzma2 {
-
-HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props);
-
-}
-
-namespace NXz {
-
-void CEncoder::InitCoderProps()
-{
- XzProps_Init(&xzProps);
-}
-
-CEncoder::CEncoder()
-{
- XzProps_Init(&xzProps);
- _encoder = NULL;
- _encoder = XzEnc_Create(&g_Alloc, &g_BigAlloc);
- if (!_encoder)
- throw 1;
-}
-
-CEncoder::~CEncoder()
-{
- if (_encoder)
- XzEnc_Destroy(_encoder);
-}
-
-
-struct CMethodNamePair
-{
- UInt32 Id;
- const char *Name;
-};
-
-static const CMethodNamePair g_NamePairs[] =
-{
- { XZ_ID_Delta, "Delta" },
- { XZ_ID_X86, "BCJ" },
- { XZ_ID_PPC, "PPC" },
- { XZ_ID_IA64, "IA64" },
- { XZ_ID_ARM, "ARM" },
- { XZ_ID_ARMT, "ARMT" },
- { XZ_ID_SPARC, "SPARC" }
- // { XZ_ID_LZMA2, "LZMA2" }
-};
-
-static int FilterIdFromName(const wchar_t *name)
-{
- for (unsigned i = 0; i < ARRAY_SIZE(g_NamePairs); i++)
- {
- const CMethodNamePair &pair = g_NamePairs[i];
- if (StringsAreEqualNoCase_Ascii(name, pair.Name))
- return (int)pair.Id;
- }
- return -1;
-}
-
-
-HRESULT CEncoder::SetCheckSize(UInt32 checkSizeInBytes)
-{
- unsigned id;
- switch (checkSizeInBytes)
- {
- case 0: id = XZ_CHECK_NO; break;
- case 4: id = XZ_CHECK_CRC32; break;
- case 8: id = XZ_CHECK_CRC64; break;
- case 32: id = XZ_CHECK_SHA256; break;
- default: return E_INVALIDARG;
- }
- xzProps.checkId = id;
- return S_OK;
-}
-
-
-HRESULT CEncoder::SetCoderProp(PROPID propID, const PROPVARIANT &prop)
-{
- if (propID == NCoderPropID::kNumThreads)
- {
- if (prop.vt != VT_UI4)
- return E_INVALIDARG;
- xzProps.numTotalThreads = (int)(prop.ulVal);
- return S_OK;
- }
-
- if (propID == NCoderPropID::kCheckSize)
- {
- if (prop.vt != VT_UI4)
- return E_INVALIDARG;
- return SetCheckSize(prop.ulVal);
- }
-
- if (propID == NCoderPropID::kBlockSize2)
- {
- if (prop.vt == VT_UI4)
- xzProps.blockSize = prop.ulVal;
- else if (prop.vt == VT_UI8)
- xzProps.blockSize = prop.uhVal.QuadPart;
- else
- return E_INVALIDARG;
- return S_OK;
- }
-
- if (propID == NCoderPropID::kReduceSize)
- {
- if (prop.vt == VT_UI8)
- xzProps.reduceSize = prop.uhVal.QuadPart;
- else
- return E_INVALIDARG;
- return S_OK;
- }
-
- if (propID == NCoderPropID::kFilter)
- {
- if (prop.vt == VT_UI4)
- {
- UInt32 id32 = prop.ulVal;
- if (id32 == XZ_ID_Delta)
- return E_INVALIDARG;
- xzProps.filterProps.id = prop.ulVal;
- }
- else
- {
- if (prop.vt != VT_BSTR)
- return E_INVALIDARG;
-
- const wchar_t *name = prop.bstrVal;
- const wchar_t *end;
-
- UInt32 id32 = ConvertStringToUInt32(name, &end);
-
- if (end != name)
- name = end;
- else
- {
- if (IsString1PrefixedByString2_NoCase_Ascii(name, "Delta"))
- {
- name += 5; // strlen("Delta");
- id32 = XZ_ID_Delta;
- }
- else
- {
- int filterId = FilterIdFromName(prop.bstrVal);
- if (filterId < 0 /* || filterId == XZ_ID_LZMA2 */)
- return E_INVALIDARG;
- id32 = filterId;
- }
- }
-
- if (id32 == XZ_ID_Delta)
- {
- wchar_t c = *name;
- if (c != '-' && c != ':')
- return E_INVALIDARG;
- name++;
- UInt32 delta = ConvertStringToUInt32(name, &end);
- if (end == name || *end != 0 || delta == 0 || delta > 256)
- return E_INVALIDARG;
- xzProps.filterProps.delta = delta;
- }
-
- xzProps.filterProps.id = id32;
- }
-
- return S_OK;
- }
-
- return NLzma2::SetLzma2Prop(propID, prop, xzProps.lzma2Props);
-}
-
-
-STDMETHODIMP CEncoder::SetCoderProperties(const PROPID *propIDs,
- const PROPVARIANT *coderProps, UInt32 numProps)
-{
- XzProps_Init(&xzProps);
-
- for (UInt32 i = 0; i < numProps; i++)
- {
- RINOK(SetCoderProp(propIDs[i], coderProps[i]));
- }
-
- return S_OK;
- // return SResToHRESULT(XzEnc_SetProps(_encoder, &xzProps));
-}
-
-
-STDMETHODIMP CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs,
- const PROPVARIANT *coderProps, UInt32 numProps)
-{
- for (UInt32 i = 0; i < numProps; i++)
- {
- const PROPVARIANT &prop = coderProps[i];
- PROPID propID = propIDs[i];
- if (propID == NCoderPropID::kExpectedDataSize)
- if (prop.vt == VT_UI8)
- XzEnc_SetDataSize(_encoder, prop.uhVal.QuadPart);
- }
- return S_OK;
-}
-
-
-#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
- if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
-
-STDMETHODIMP CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
-{
- CSeqInStreamWrap inWrap;
- CSeqOutStreamWrap outWrap;
- CCompressProgressWrap progressWrap;
-
- inWrap.Init(inStream);
- outWrap.Init(outStream);
- progressWrap.Init(progress);
-
- SRes res = XzEnc_SetProps(_encoder, &xzProps);
- if (res == SZ_OK)
- res = XzEnc_Encode(_encoder, &outWrap.vt, &inWrap.vt, progress ? &progressWrap.vt : NULL);
-
- // SRes res = Xz_Encode(&outWrap.vt, &inWrap.vt, &xzProps, progress ? &progressWrap.vt : NULL);
-
- RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ)
- RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
- RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
-
- return SResToHRESULT(res);
-}
-
-}}
+// XzEncoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/Alloc.h"
+
+#include "../../Common/MyString.h"
+#include "../../Common/StringToInt.h"
+
+#include "../Common/CWrappers.h"
+#include "../Common/StreamUtils.h"
+
+#include "XzEncoder.h"
+
+namespace NCompress {
+
+namespace NLzma2 {
+HRESULT SetLzma2Prop(PROPID propID, const PROPVARIANT &prop, CLzma2EncProps &lzma2Props);
+}
+
+namespace NXz {
+
+void CEncoder::InitCoderProps()
+{
+ XzProps_Init(&xzProps);
+}
+
+CEncoder::CEncoder()
+{
+ XzProps_Init(&xzProps);
+ _encoder = NULL;
+ _encoder = XzEnc_Create(&g_Alloc, &g_BigAlloc);
+ if (!_encoder)
+ throw 1;
+}
+
+CEncoder::~CEncoder()
+{
+ if (_encoder)
+ XzEnc_Destroy(_encoder);
+}
+
+
+struct CMethodNamePair
+{
+ UInt32 Id;
+ const char *Name;
+};
+
+static const CMethodNamePair g_NamePairs[] =
+{
+ { XZ_ID_Delta, "Delta" },
+ { XZ_ID_X86, "BCJ" },
+ { XZ_ID_PPC, "PPC" },
+ { XZ_ID_IA64, "IA64" },
+ { XZ_ID_ARM, "ARM" },
+ { XZ_ID_ARMT, "ARMT" },
+ { XZ_ID_SPARC, "SPARC" }
+ // { XZ_ID_LZMA2, "LZMA2" }
+};
+
+static int FilterIdFromName(const wchar_t *name)
+{
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_NamePairs); i++)
+ {
+ const CMethodNamePair &pair = g_NamePairs[i];
+ if (StringsAreEqualNoCase_Ascii(name, pair.Name))
+ return (int)pair.Id;
+ }
+ return -1;
+}
+
+
+HRESULT CEncoder::SetCheckSize(UInt32 checkSizeInBytes)
+{
+ unsigned id;
+ switch (checkSizeInBytes)
+ {
+ case 0: id = XZ_CHECK_NO; break;
+ case 4: id = XZ_CHECK_CRC32; break;
+ case 8: id = XZ_CHECK_CRC64; break;
+ case 32: id = XZ_CHECK_SHA256; break;
+ default: return E_INVALIDARG;
+ }
+ xzProps.checkId = id;
+ return S_OK;
+}
+
+
+HRESULT CEncoder::SetCoderProp(PROPID propID, const PROPVARIANT &prop)
+{
+ if (propID == NCoderPropID::kNumThreads)
+ {
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ xzProps.numTotalThreads = (int)(prop.ulVal);
+ return S_OK;
+ }
+
+ if (propID == NCoderPropID::kCheckSize)
+ {
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ return SetCheckSize(prop.ulVal);
+ }
+
+ if (propID == NCoderPropID::kBlockSize2)
+ {
+ if (prop.vt == VT_UI4)
+ xzProps.blockSize = prop.ulVal;
+ else if (prop.vt == VT_UI8)
+ xzProps.blockSize = prop.uhVal.QuadPart;
+ else
+ return E_INVALIDARG;
+ return S_OK;
+ }
+
+ if (propID == NCoderPropID::kReduceSize)
+ {
+ if (prop.vt == VT_UI8)
+ xzProps.reduceSize = prop.uhVal.QuadPart;
+ else
+ return E_INVALIDARG;
+ return S_OK;
+ }
+
+ if (propID == NCoderPropID::kFilter)
+ {
+ if (prop.vt == VT_UI4)
+ {
+ const UInt32 id32 = prop.ulVal;
+ if (id32 == XZ_ID_Delta)
+ return E_INVALIDARG;
+ xzProps.filterProps.id = prop.ulVal;
+ }
+ else
+ {
+ if (prop.vt != VT_BSTR)
+ return E_INVALIDARG;
+
+ const wchar_t *name = prop.bstrVal;
+ const wchar_t *end;
+
+ UInt32 id32 = ConvertStringToUInt32(name, &end);
+
+ if (end != name)
+ name = end;
+ else
+ {
+ if (IsString1PrefixedByString2_NoCase_Ascii(name, "Delta"))
+ {
+ name += 5; // strlen("Delta");
+ id32 = XZ_ID_Delta;
+ }
+ else
+ {
+ const int filterId = FilterIdFromName(prop.bstrVal);
+ if (filterId < 0 /* || filterId == XZ_ID_LZMA2 */)
+ return E_INVALIDARG;
+ id32 = (unsigned)filterId;
+ }
+ }
+
+ if (id32 == XZ_ID_Delta)
+ {
+ const wchar_t c = *name;
+ if (c != '-' && c != ':')
+ return E_INVALIDARG;
+ name++;
+ const UInt32 delta = ConvertStringToUInt32(name, &end);
+ if (end == name || *end != 0 || delta == 0 || delta > 256)
+ return E_INVALIDARG;
+ xzProps.filterProps.delta = delta;
+ }
+
+ xzProps.filterProps.id = id32;
+ }
+
+ return S_OK;
+ }
+
+ return NLzma2::SetLzma2Prop(propID, prop, xzProps.lzma2Props);
+}
+
+
+Z7_COM7F_IMF(CEncoder::SetCoderProperties(const PROPID *propIDs,
+ const PROPVARIANT *coderProps, UInt32 numProps))
+{
+ XzProps_Init(&xzProps);
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ RINOK(SetCoderProp(propIDs[i], coderProps[i]))
+ }
+
+ return S_OK;
+ // return SResToHRESULT(XzEnc_SetProps(_encoder, &xzProps));
+}
+
+
+Z7_COM7F_IMF(CEncoder::SetCoderPropertiesOpt(const PROPID *propIDs,
+ const PROPVARIANT *coderProps, UInt32 numProps))
+{
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ const PROPVARIANT &prop = coderProps[i];
+ const PROPID propID = propIDs[i];
+ if (propID == NCoderPropID::kExpectedDataSize)
+ if (prop.vt == VT_UI8)
+ XzEnc_SetDataSize(_encoder, prop.uhVal.QuadPart);
+ }
+ return S_OK;
+}
+
+
+#define RET_IF_WRAP_ERROR(wrapRes, sRes, sResErrorCode) \
+ if (wrapRes != S_OK /* && (sRes == SZ_OK || sRes == sResErrorCode) */) return wrapRes;
+
+Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress))
+{
+ CSeqInStreamWrap inWrap;
+ CSeqOutStreamWrap outWrap;
+ CCompressProgressWrap progressWrap;
+
+ inWrap.Init(inStream);
+ outWrap.Init(outStream);
+ progressWrap.Init(progress);
+
+ SRes res = XzEnc_SetProps(_encoder, &xzProps);
+ if (res == SZ_OK)
+ res = XzEnc_Encode(_encoder, &outWrap.vt, &inWrap.vt, progress ? &progressWrap.vt : NULL);
+
+ // SRes res = Xz_Encode(&outWrap.vt, &inWrap.vt, &xzProps, progress ? &progressWrap.vt : NULL);
+
+ RET_IF_WRAP_ERROR(inWrap.Res, res, SZ_ERROR_READ)
+ RET_IF_WRAP_ERROR(outWrap.Res, res, SZ_ERROR_WRITE)
+ RET_IF_WRAP_ERROR(progressWrap.Res, res, SZ_ERROR_PROGRESS)
+
+ return SResToHRESULT(res);
+}
+
+}}
diff --git a/CPP/7zip/Compress/XzEncoder.h b/CPP/7zip/Compress/XzEncoder.h
index 79d81f7..434f582 100644
--- a/CPP/7zip/Compress/XzEncoder.h
+++ b/CPP/7zip/Compress/XzEncoder.h
@@ -1,46 +1,35 @@
-// XzEncoder.h
-
-#ifndef __XZ_ENCODER_H
-#define __XZ_ENCODER_H
-
-#include "../../../C/XzEnc.h"
-
-#include "../../Common/MyCom.h"
-
-#include "../ICoder.h"
-
-namespace NCompress {
-namespace NXz {
-
-
-class CEncoder:
- public ICompressCoder,
- public ICompressSetCoderProperties,
- public ICompressSetCoderPropertiesOpt,
- public CMyUnknownImp
-{
- CXzEncHandle _encoder;
-public:
- CXzProps xzProps;
-
- MY_UNKNOWN_IMP3(
- ICompressCoder,
- ICompressSetCoderProperties,
- ICompressSetCoderPropertiesOpt)
-
- void InitCoderProps();
- HRESULT SetCheckSize(UInt32 checkSizeInBytes);
- HRESULT SetCoderProp(PROPID propID, const PROPVARIANT &prop);
-
- STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
- STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
- STDMETHOD(SetCoderPropertiesOpt)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
-
- CEncoder();
- virtual ~CEncoder();
-};
-
-}}
-
-#endif
+// XzEncoder.h
+
+#ifndef ZIP7_INC_XZ_ENCODER_H
+#define ZIP7_INC_XZ_ENCODER_H
+
+#include "../../../C/XzEnc.h"
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NXz {
+
+Z7_CLASS_IMP_COM_3(
+ CEncoder
+ , ICompressCoder
+ , ICompressSetCoderProperties
+ , ICompressSetCoderPropertiesOpt
+)
+ CXzEncHandle _encoder;
+public:
+ CXzProps xzProps;
+
+ void InitCoderProps();
+ HRESULT SetCheckSize(UInt32 checkSizeInBytes);
+ HRESULT SetCoderProp(PROPID propID, const PROPVARIANT &prop);
+
+ CEncoder();
+ ~CEncoder();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/ZDecoder.cpp b/CPP/7zip/Compress/ZDecoder.cpp
new file mode 100644
index 0000000..07c5fe5
--- /dev/null
+++ b/CPP/7zip/Compress/ZDecoder.cpp
@@ -0,0 +1,237 @@
+// ZDecoder.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "../../../C/Alloc.h"
+
+#include "../Common/InBuffer.h"
+#include "../Common/OutBuffer.h"
+
+#include "ZDecoder.h"
+
+namespace NCompress {
+namespace NZ {
+
+static const UInt32 kBufferSize = (1 << 20);
+static const Byte kNumBitsMask = 0x1F;
+static const Byte kBlockModeMask = 0x80;
+static const unsigned kNumMinBits = 9;
+static const unsigned kNumMaxBits = 16;
+
+void CDecoder::Free()
+{
+ MyFree(_parents); _parents = NULL;
+ MyFree(_suffixes); _suffixes = NULL;
+ MyFree(_stack); _stack = NULL;
+}
+
+CDecoder::~CDecoder() { Free(); }
+
+HRESULT CDecoder::CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 * /* inSize */, const UInt64 * /* outSize */, ICompressProgressInfo *progress)
+{
+ CInBuffer inBuffer;
+ COutBuffer outBuffer;
+
+ PackSize = 0;
+
+ if (!inBuffer.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+ inBuffer.SetStream(inStream);
+ inBuffer.Init();
+
+ if (!outBuffer.Create(kBufferSize))
+ return E_OUTOFMEMORY;
+ outBuffer.SetStream(outStream);
+ outBuffer.Init();
+
+ Byte buf[kNumMaxBits + 4];
+ {
+ if (inBuffer.ReadBytes(buf, 3) < 3)
+ return S_FALSE;
+ if (buf[0] != 0x1F || buf[1] != 0x9D)
+ return S_FALSE;
+ }
+ Byte prop = buf[2];
+
+ if ((prop & 0x60) != 0)
+ return S_FALSE;
+ const unsigned maxbits = prop & kNumBitsMask;
+ if (maxbits < kNumMinBits || maxbits > kNumMaxBits)
+ return S_FALSE;
+ const UInt32 numItems = 1 << maxbits;
+ // Speed optimization: blockSymbol can contain unused velue.
+
+ if (maxbits != _numMaxBits || !_parents || !_suffixes || !_stack)
+ {
+ Free();
+ _parents = (UInt16 *)MyAlloc(numItems * sizeof(UInt16)); if (!_parents) return E_OUTOFMEMORY;
+ _suffixes = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (!_suffixes) return E_OUTOFMEMORY;
+ _stack = (Byte *)MyAlloc(numItems * sizeof(Byte)); if (!_stack) return E_OUTOFMEMORY;
+ _numMaxBits = maxbits;
+ }
+
+ UInt64 prevPos = 0;
+ const UInt32 blockSymbol = ((prop & kBlockModeMask) != 0) ? 256 : ((UInt32)1 << kNumMaxBits);
+ unsigned numBits = kNumMinBits;
+ UInt32 head = (blockSymbol == 256) ? 257 : 256;
+ bool needPrev = false;
+ unsigned bitPos = 0;
+ unsigned numBufBits = 0;
+
+ _parents[256] = 0; // virus protection
+ _suffixes[256] = 0;
+ HRESULT res = S_OK;
+
+ for (;;)
+ {
+ if (numBufBits == bitPos)
+ {
+ numBufBits = (unsigned)inBuffer.ReadBytes(buf, numBits) * 8;
+ bitPos = 0;
+ const UInt64 nowPos = outBuffer.GetProcessedSize();
+ if (progress && nowPos - prevPos >= (1 << 13))
+ {
+ prevPos = nowPos;
+ const UInt64 packSize = inBuffer.GetProcessedSize();
+ RINOK(progress->SetRatioInfo(&packSize, &nowPos))
+ }
+ }
+ const unsigned bytePos = bitPos >> 3;
+ UInt32 symbol = buf[bytePos] | ((UInt32)buf[(size_t)bytePos + 1] << 8) | ((UInt32)buf[(size_t)bytePos + 2] << 16);
+ symbol >>= (bitPos & 7);
+ symbol &= (1 << numBits) - 1;
+ bitPos += numBits;
+ if (bitPos > numBufBits)
+ break;
+ if (symbol >= head)
+ {
+ res = S_FALSE;
+ break;
+ }
+ if (symbol == blockSymbol)
+ {
+ numBufBits = bitPos = 0;
+ numBits = kNumMinBits;
+ head = 257;
+ needPrev = false;
+ continue;
+ }
+ UInt32 cur = symbol;
+ unsigned i = 0;
+ while (cur >= 256)
+ {
+ _stack[i++] = _suffixes[cur];
+ cur = _parents[cur];
+ }
+ _stack[i++] = (Byte)cur;
+ if (needPrev)
+ {
+ _suffixes[(size_t)head - 1] = (Byte)cur;
+ if (symbol == head - 1)
+ _stack[0] = (Byte)cur;
+ }
+ do
+ outBuffer.WriteByte((_stack[--i]));
+ while (i > 0);
+ if (head < numItems)
+ {
+ needPrev = true;
+ _parents[head++] = (UInt16)symbol;
+ if (head > ((UInt32)1 << numBits))
+ {
+ if (numBits < maxbits)
+ {
+ numBufBits = bitPos = 0;
+ numBits++;
+ }
+ }
+ }
+ else
+ needPrev = false;
+ }
+ PackSize = inBuffer.GetProcessedSize();
+ const HRESULT res2 = outBuffer.Flush();
+ return (res == S_OK) ? res2 : res;
+}
+
+Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ try { return CodeReal(inStream, outStream, inSize, outSize, progress); }
+ catch(const CInBufferException &e) { return e.ErrorCode; }
+ catch(const COutBufferException &e) { return e.ErrorCode; }
+ catch(...) { return S_FALSE; }
+}
+
+bool CheckStream(const Byte *data, size_t size)
+{
+ if (size < 3)
+ return false;
+ if (data[0] != 0x1F || data[1] != 0x9D)
+ return false;
+ const Byte prop = data[2];
+ if ((prop & 0x60) != 0)
+ return false;
+ const unsigned maxbits = prop & kNumBitsMask;
+ if (maxbits < kNumMinBits || maxbits > kNumMaxBits)
+ return false;
+ const UInt32 numItems = 1 << maxbits;
+ const UInt32 blockSymbol = ((prop & kBlockModeMask) != 0) ? 256 : ((UInt32)1 << kNumMaxBits);
+ unsigned numBits = kNumMinBits;
+ UInt32 head = (blockSymbol == 256) ? 257 : 256;
+ unsigned bitPos = 0;
+ unsigned numBufBits = 0;
+ Byte buf[kNumMaxBits + 4];
+ data += 3;
+ size -= 3;
+ // printf("\n\n");
+ for (;;)
+ {
+ if (numBufBits == bitPos)
+ {
+ const unsigned num = (numBits < size) ? numBits : (unsigned)size;
+ memcpy(buf, data, num);
+ data += num;
+ size -= num;
+ numBufBits = num * 8;
+ bitPos = 0;
+ }
+ const unsigned bytePos = bitPos >> 3;
+ UInt32 symbol = buf[bytePos] | ((UInt32)buf[bytePos + 1] << 8) | ((UInt32)buf[bytePos + 2] << 16);
+ symbol >>= (bitPos & 7);
+ symbol &= (1 << numBits) - 1;
+ bitPos += numBits;
+ if (bitPos > numBufBits)
+ {
+ // printf(" OK", symbol);
+ return true;
+ }
+ // printf("%3X ", symbol);
+ if (symbol >= head)
+ return false;
+ if (symbol == blockSymbol)
+ {
+ numBufBits = bitPos = 0;
+ numBits = kNumMinBits;
+ head = 257;
+ continue;
+ }
+ if (head < numItems)
+ {
+ head++;
+ if (head > ((UInt32)1 << numBits))
+ {
+ if (numBits < maxbits)
+ {
+ numBufBits = bitPos = 0;
+ numBits++;
+ }
+ }
+ }
+ }
+}
+
+}}
diff --git a/CPP/7zip/Compress/ZDecoder.h b/CPP/7zip/Compress/ZDecoder.h
new file mode 100644
index 0000000..390b013
--- /dev/null
+++ b/CPP/7zip/Compress/ZDecoder.h
@@ -0,0 +1,49 @@
+// ZDecoder.h
+
+#ifndef ZIP7_INC_COMPRESS_Z_DECODER_H
+#define ZIP7_INC_COMPRESS_Z_DECODER_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCompress {
+namespace NZ {
+
+// Z decoder decodes Z data stream, including 3 bytes of header.
+
+Z7_CLASS_IMP_COM_1(
+ CDecoder
+ , ICompressCoder
+)
+ UInt16 *_parents;
+ Byte *_suffixes;
+ Byte *_stack;
+ unsigned _numMaxBits;
+
+public:
+ CDecoder(): _parents(NULL), _suffixes(NULL), _stack(NULL), /* _prop(0), */ _numMaxBits(0) {}
+ ~CDecoder();
+ void Free();
+ UInt64 PackSize;
+
+ HRESULT CodeReal(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress);
+};
+
+/*
+ There is no end_of_payload_marker in Z stream.
+ Z decoder stops decoding, if it reaches end of input stream.
+
+ CheckStream function:
+ (size) must be at least 3 bytes (size of Z header).
+ if (size) is larger than size of real Z stream in (data), CheckStream can return false.
+*/
+
+const unsigned kRecommendedCheckSize = 64;
+
+bool CheckStream(const Byte *data, size_t size);
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/ZlibDecoder.cpp b/CPP/7zip/Compress/ZlibDecoder.cpp
new file mode 100644
index 0000000..a066932
--- /dev/null
+++ b/CPP/7zip/Compress/ZlibDecoder.cpp
@@ -0,0 +1,95 @@
+// ZlibDecoder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "ZlibDecoder.h"
+
+namespace NCompress {
+namespace NZlib {
+
+#define DEFLATE_TRY_BEGIN try {
+#define DEFLATE_TRY_END } catch(...) { return S_FALSE; }
+
+#define ADLER_MOD 65521
+#define ADLER_LOOP_MAX 5550
+
+UInt32 Adler32_Update(UInt32 adler, const Byte *buf, size_t size);
+UInt32 Adler32_Update(UInt32 adler, const Byte *buf, size_t size)
+{
+ UInt32 a = adler & 0xFFFF;
+ UInt32 b = (adler >> 16) & 0xFFFF;
+ while (size > 0)
+ {
+ const unsigned curSize = (size > ADLER_LOOP_MAX) ? ADLER_LOOP_MAX : (unsigned )size;
+ unsigned i;
+ for (i = 0; i < curSize; i++)
+ {
+ a += buf[i];
+ b += a;
+ }
+ buf += curSize;
+ size -= curSize;
+ a %= ADLER_MOD;
+ b %= ADLER_MOD;
+ }
+ return (b << 16) + a;
+}
+
+Z7_COM7F_IMF(COutStreamWithAdler::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ HRESULT result = S_OK;
+ if (_stream)
+ result = _stream->Write(data, size, &size);
+ _adler = Adler32_Update(_adler, (const Byte *)data, size);
+ _size += size;
+ if (processedSize)
+ *processedSize = size;
+ return result;
+}
+
+Z7_COM7F_IMF(CDecoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 *outSize, ICompressProgressInfo *progress))
+{
+ DEFLATE_TRY_BEGIN
+ if (!AdlerStream)
+ AdlerStream = AdlerSpec = new COutStreamWithAdler;
+ if (!DeflateDecoder)
+ {
+ DeflateDecoderSpec = new NDeflate::NDecoder::CCOMCoder;
+ DeflateDecoderSpec->ZlibMode = true;
+ DeflateDecoder = DeflateDecoderSpec;
+ }
+
+ if (inSize && *inSize < 2)
+ return S_FALSE;
+ Byte buf[2];
+ RINOK(ReadStream_FALSE(inStream, buf, 2))
+ if (!IsZlib(buf))
+ return S_FALSE;
+
+ AdlerSpec->SetStream(outStream);
+ AdlerSpec->Init();
+
+ UInt64 inSize2 = 0;
+ if (inSize)
+ inSize2 = *inSize - 2;
+
+ const HRESULT res = DeflateDecoder->Code(inStream, AdlerStream, inSize ? &inSize2 : NULL, outSize, progress);
+ AdlerSpec->ReleaseStream();
+
+ if (res == S_OK)
+ {
+ const Byte *p = DeflateDecoderSpec->ZlibFooter;
+ const UInt32 adler = GetBe32(p);
+ if (adler != AdlerSpec->GetAdler())
+ return S_FALSE;
+ }
+ return res;
+ DEFLATE_TRY_END
+}
+
+}}
diff --git a/CPP/7zip/Compress/ZlibDecoder.h b/CPP/7zip/Compress/ZlibDecoder.h
new file mode 100644
index 0000000..1dc5c67
--- /dev/null
+++ b/CPP/7zip/Compress/ZlibDecoder.h
@@ -0,0 +1,71 @@
+// ZlibDecoder.h
+
+#ifndef ZIP7_INC_ZLIB_DECODER_H
+#define ZIP7_INC_ZLIB_DECODER_H
+
+#include "DeflateDecoder.h"
+
+namespace NCompress {
+namespace NZlib {
+
+const UInt32 ADLER_INIT_VAL = 1;
+
+Z7_CLASS_IMP_NOQIB_1(
+ COutStreamWithAdler
+ , ISequentialOutStream
+)
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt32 _adler;
+ UInt64 _size;
+public:
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init() { _adler = ADLER_INIT_VAL; _size = 0; }
+ UInt32 GetAdler() const { return _adler; }
+ UInt64 GetSize() const { return _size; }
+};
+
+Z7_CLASS_IMP_NOQIB_1(
+ CDecoder
+ , ICompressCoder
+)
+ COutStreamWithAdler *AdlerSpec;
+ CMyComPtr<ISequentialOutStream> AdlerStream;
+ NCompress::NDeflate::NDecoder::CCOMCoder *DeflateDecoderSpec;
+ CMyComPtr<ICompressCoder> DeflateDecoder;
+public:
+ UInt64 GetInputProcessedSize() const { return DeflateDecoderSpec->GetInputProcessedSize() + 2; }
+ UInt64 GetOutputProcessedSize() const { return AdlerSpec->GetSize(); }
+};
+
+static bool inline IsZlib(const Byte *p)
+{
+ if ((p[0] & 0xF) != 8) // method
+ return false;
+ if (((unsigned)p[0] >> 4) > 7) // logar_window_size minus 8.
+ return false;
+ if ((p[1] & 0x20) != 0) // dictPresent
+ return false;
+ if ((((UInt32)p[0] << 8) + p[1]) % 31 != 0)
+ return false;
+ return true;
+}
+
+// IsZlib_3bytes checks 2 bytes of zlib header and starting byte of Deflate stream
+
+static bool inline IsZlib_3bytes(const Byte *p)
+{
+ if (!IsZlib(p))
+ return false;
+ const unsigned val = p[2];
+ const unsigned blockType = (val >> 1) & 0x3;
+ if (blockType == 3) // unsupported block type for deflate
+ return false;
+ if (blockType == NCompress::NDeflate::NBlockType::kStored && (val >> 3) != 0)
+ return false;
+ return true;
+}
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/ZlibEncoder.cpp b/CPP/7zip/Compress/ZlibEncoder.cpp
new file mode 100644
index 0000000..3670d30
--- /dev/null
+++ b/CPP/7zip/Compress/ZlibEncoder.cpp
@@ -0,0 +1,61 @@
+// ZlibEncoder.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "ZlibEncoder.h"
+
+namespace NCompress {
+namespace NZlib {
+
+#define DEFLATE_TRY_BEGIN try {
+#define DEFLATE_TRY_END } catch(...) { return S_FALSE; }
+
+UInt32 Adler32_Update(UInt32 adler, const Byte *buf, size_t size);
+
+Z7_COM7F_IMF(CInStreamWithAdler::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ const HRESULT result = _stream->Read(data, size, &size);
+ _adler = Adler32_Update(_adler, (const Byte *)data, size);
+ _size += size;
+ if (processedSize)
+ *processedSize = size;
+ return result;
+}
+
+void CEncoder::Create()
+{
+ if (!DeflateEncoder)
+ DeflateEncoder = DeflateEncoderSpec = new NDeflate::NEncoder::CCOMCoder;
+}
+
+Z7_COM7F_IMF(CEncoder::Code(ISequentialInStream *inStream, ISequentialOutStream *outStream,
+ const UInt64 *inSize, const UInt64 * /* outSize */, ICompressProgressInfo *progress))
+{
+ DEFLATE_TRY_BEGIN
+ if (!AdlerStream)
+ AdlerStream = AdlerSpec = new CInStreamWithAdler;
+ Create();
+
+ {
+ Byte buf[2] = { 0x78, 0xDA };
+ RINOK(WriteStream(outStream, buf, 2))
+ }
+
+ AdlerSpec->SetStream(inStream);
+ AdlerSpec->Init();
+ const HRESULT res = DeflateEncoder->Code(AdlerStream, outStream, inSize, NULL, progress);
+ AdlerSpec->ReleaseStream();
+
+ RINOK(res)
+
+ {
+ const UInt32 a = AdlerSpec->GetAdler();
+ const Byte buf[4] = { (Byte)(a >> 24), (Byte)(a >> 16), (Byte)(a >> 8), (Byte)(a) };
+ return WriteStream(outStream, buf, 4);
+ }
+ DEFLATE_TRY_END
+}
+
+}}
diff --git a/CPP/7zip/Compress/ZlibEncoder.h b/CPP/7zip/Compress/ZlibEncoder.h
new file mode 100644
index 0000000..484a307
--- /dev/null
+++ b/CPP/7zip/Compress/ZlibEncoder.h
@@ -0,0 +1,42 @@
+// ZlibEncoder.h
+
+#ifndef ZIP7_INC_ZLIB_ENCODER_H
+#define ZIP7_INC_ZLIB_ENCODER_H
+
+#include "DeflateEncoder.h"
+
+namespace NCompress {
+namespace NZlib {
+
+Z7_CLASS_IMP_NOQIB_1(
+ CInStreamWithAdler
+ , ISequentialInStream
+)
+ CMyComPtr<ISequentialInStream> _stream;
+ UInt32 _adler;
+ UInt64 _size;
+public:
+ void SetStream(ISequentialInStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init() { _adler = 1; _size = 0; } // ADLER_INIT_VAL
+ UInt32 GetAdler() const { return _adler; }
+ UInt64 GetSize() const { return _size; }
+};
+
+Z7_CLASS_IMP_NOQIB_1(
+ CEncoder
+ , ICompressCoder
+)
+ CInStreamWithAdler *AdlerSpec;
+ CMyComPtr<ISequentialInStream> AdlerStream;
+ CMyComPtr<ICompressCoder> DeflateEncoder;
+public:
+ NCompress::NDeflate::NEncoder::CCOMCoder *DeflateEncoderSpec;
+
+ void Create();
+ UInt64 GetInputProcessedSize() const { return AdlerSpec->GetSize(); }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Compress/makefile b/CPP/7zip/Compress/makefile
new file mode 100644
index 0000000..e981319
--- /dev/null
+++ b/CPP/7zip/Compress/makefile
@@ -0,0 +1,7 @@
+DIRS = \
+ LZMA_Alone\~ \
+
+all: $(DIRS)
+
+$(DIRS):
+!include "../SubBuild.mak"
diff --git a/CPP/7zip/Crc.mak b/CPP/7zip/Crc.mak
index 66b35c1..815142d 100644
--- a/CPP/7zip/Crc.mak
+++ b/CPP/7zip/Crc.mak
@@ -1,8 +1,8 @@
-C_OBJS = $(C_OBJS) \
- $O\7zCrc.obj
-!IF "$(PLATFORM)" == "ia64" || "$(PLATFORM)" == "mips" || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64"
-C_OBJS = $(C_OBJS) \
-!ELSE
-ASM_OBJS = $(ASM_OBJS) \
-!ENDIF
- $O\7zCrcOpt.obj
+C_OBJS = $(C_OBJS) \
+ $O\7zCrc.obj
+!IF "$(PLATFORM)" == "ia64" || "$(PLATFORM)" == "mips" || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64"
+C_OBJS = $(C_OBJS) \
+!ELSE
+ASM_OBJS = $(ASM_OBJS) \
+!ENDIF
+ $O\7zCrcOpt.obj
diff --git a/CPP/7zip/Crc64.mak b/CPP/7zip/Crc64.mak
index 6df9b40..d58a483 100644
--- a/CPP/7zip/Crc64.mak
+++ b/CPP/7zip/Crc64.mak
@@ -1,8 +1,8 @@
-C_OBJS = $(C_OBJS) \
- $O\XzCrc64.obj
-!IF "$(PLATFORM)" == "ia64" || "$(PLATFORM)" == "mips" || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64"
-C_OBJS = $(C_OBJS) \
-!ELSE
-ASM_OBJS = $(ASM_OBJS) \
-!ENDIF
- $O\XzCrc64Opt.obj
+C_OBJS = $(C_OBJS) \
+ $O\XzCrc64.obj
+!IF "$(PLATFORM)" == "ia64" || "$(PLATFORM)" == "mips" || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64"
+C_OBJS = $(C_OBJS) \
+!ELSE
+ASM_OBJS = $(ASM_OBJS) \
+!ENDIF
+ $O\XzCrc64Opt.obj
diff --git a/CPP/7zip/Crypto/7zAes.cpp b/CPP/7zip/Crypto/7zAes.cpp
index 55e40f3..6b1c648 100644
--- a/CPP/7zip/Crypto/7zAes.cpp
+++ b/CPP/7zip/Crypto/7zAes.cpp
@@ -1,280 +1,317 @@
-// 7zAes.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/Sha256.h"
-
-#include "../../Common/ComTry.h"
-
-#ifndef _7ZIP_ST
-#include "../../Windows/Synchronization.h"
-#endif
-
-#include "../Common/StreamUtils.h"
-
-#include "7zAes.h"
-#include "MyAes.h"
-
-#ifndef EXTRACT_ONLY
-#include "RandGen.h"
-#endif
-
-namespace NCrypto {
-namespace N7z {
-
-static const unsigned k_NumCyclesPower_Supported_MAX = 24;
-
-bool CKeyInfo::IsEqualTo(const CKeyInfo &a) const
-{
- if (SaltSize != a.SaltSize || NumCyclesPower != a.NumCyclesPower)
- return false;
- for (unsigned i = 0; i < SaltSize; i++)
- if (Salt[i] != a.Salt[i])
- return false;
- return (Password == a.Password);
-}
-
-void CKeyInfo::CalcKey()
-{
- if (NumCyclesPower == 0x3F)
- {
- unsigned pos;
- for (pos = 0; pos < SaltSize; pos++)
- Key[pos] = Salt[pos];
- for (unsigned i = 0; i < Password.Size() && pos < kKeySize; i++)
- Key[pos++] = Password[i];
- for (; pos < kKeySize; pos++)
- Key[pos] = 0;
- }
- else
- {
- size_t bufSize = 8 + SaltSize + Password.Size();
- CObjArray<Byte> buf(bufSize);
- memcpy(buf, Salt, SaltSize);
- memcpy(buf + SaltSize, Password, Password.Size());
-
- CSha256 sha;
- Sha256_Init(&sha);
-
- Byte *ctr = buf + SaltSize + Password.Size();
-
- for (unsigned i = 0; i < 8; i++)
- ctr[i] = 0;
-
- UInt64 numRounds = (UInt64)1 << NumCyclesPower;
-
- do
- {
- Sha256_Update(&sha, buf, bufSize);
- for (unsigned i = 0; i < 8; i++)
- if (++(ctr[i]) != 0)
- break;
- }
- while (--numRounds != 0);
-
- Sha256_Final(&sha, Key);
- }
-}
-
-bool CKeyInfoCache::GetKey(CKeyInfo &key)
-{
- FOR_VECTOR (i, Keys)
- {
- const CKeyInfo &cached = Keys[i];
- if (key.IsEqualTo(cached))
- {
- for (unsigned j = 0; j < kKeySize; j++)
- key.Key[j] = cached.Key[j];
- if (i != 0)
- Keys.MoveToFront(i);
- return true;
- }
- }
- return false;
-}
-
-void CKeyInfoCache::FindAndAdd(const CKeyInfo &key)
-{
- FOR_VECTOR (i, Keys)
- {
- const CKeyInfo &cached = Keys[i];
- if (key.IsEqualTo(cached))
- {
- if (i != 0)
- Keys.MoveToFront(i);
- return;
- }
- }
- Add(key);
-}
-
-void CKeyInfoCache::Add(const CKeyInfo &key)
-{
- if (Keys.Size() >= Size)
- Keys.DeleteBack();
- Keys.Insert(0, key);
-}
-
-static CKeyInfoCache g_GlobalKeyCache(32);
-
-#ifndef _7ZIP_ST
- static NWindows::NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection;
- #define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection);
-#else
- #define MT_LOCK
-#endif
-
-CBase::CBase():
- _cachedKeys(16),
- _ivSize(0)
-{
- for (unsigned i = 0; i < sizeof(_iv); i++)
- _iv[i] = 0;
-}
-
-void CBase::PrepareKey()
-{
- // BCJ2 threads use same password. So we use long lock.
- MT_LOCK
-
- bool finded = false;
- if (!_cachedKeys.GetKey(_key))
- {
- finded = g_GlobalKeyCache.GetKey(_key);
- if (!finded)
- _key.CalcKey();
- _cachedKeys.Add(_key);
- }
- if (!finded)
- g_GlobalKeyCache.FindAndAdd(_key);
-}
-
-#ifndef EXTRACT_ONLY
-
-/*
-STDMETHODIMP CEncoder::ResetSalt()
-{
- _key.SaltSize = 4;
- g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
- return S_OK;
-}
-*/
-
-STDMETHODIMP CEncoder::ResetInitVector()
-{
- for (unsigned i = 0; i < sizeof(_iv); i++)
- _iv[i] = 0;
- _ivSize = 16;
- MY_RAND_GEN(_iv, _ivSize);
- return S_OK;
-}
-
-STDMETHODIMP CEncoder::WriteCoderProperties(ISequentialOutStream *outStream)
-{
- Byte props[2 + sizeof(_key.Salt) + sizeof(_iv)];
- unsigned propsSize = 1;
-
- props[0] = (Byte)(_key.NumCyclesPower
- | (_key.SaltSize == 0 ? 0 : (1 << 7))
- | (_ivSize == 0 ? 0 : (1 << 6)));
-
- if (_key.SaltSize != 0 || _ivSize != 0)
- {
- props[1] = (Byte)(
- ((_key.SaltSize == 0 ? 0 : _key.SaltSize - 1) << 4)
- | (_ivSize == 0 ? 0 : _ivSize - 1));
- memcpy(props + 2, _key.Salt, _key.SaltSize);
- propsSize = 2 + _key.SaltSize;
- memcpy(props + propsSize, _iv, _ivSize);
- propsSize += _ivSize;
- }
-
- return WriteStream(outStream, props, propsSize);
-}
-
-CEncoder::CEncoder()
-{
- // _key.SaltSize = 4; g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
- // _key.NumCyclesPower = 0x3F;
- _key.NumCyclesPower = 19;
- _aesFilter = new CAesCbcEncoder(kKeySize);
-}
-
-#endif
-
-CDecoder::CDecoder()
-{
- _aesFilter = new CAesCbcDecoder(kKeySize);
-}
-
-STDMETHODIMP CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
-{
- _key.ClearProps();
-
- _ivSize = 0;
- unsigned i;
- for (i = 0; i < sizeof(_iv); i++)
- _iv[i] = 0;
-
- if (size == 0)
- return S_OK;
-
- Byte b0 = data[0];
-
- _key.NumCyclesPower = b0 & 0x3F;
- if ((b0 & 0xC0) == 0)
- return size == 1 ? S_OK : E_INVALIDARG;
-
- if (size <= 1)
- return E_INVALIDARG;
-
- Byte b1 = data[1];
-
- unsigned saltSize = ((b0 >> 7) & 1) + (b1 >> 4);
- unsigned ivSize = ((b0 >> 6) & 1) + (b1 & 0x0F);
-
- if (size != 2 + saltSize + ivSize)
- return E_INVALIDARG;
- _key.SaltSize = saltSize;
- data += 2;
- for (i = 0; i < saltSize; i++)
- _key.Salt[i] = *data++;
- for (i = 0; i < ivSize; i++)
- _iv[i] = *data++;
- return (_key.NumCyclesPower <= k_NumCyclesPower_Supported_MAX
- || _key.NumCyclesPower == 0x3F) ? S_OK : E_NOTIMPL;
-}
-
-
-STDMETHODIMP CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size)
-{
- COM_TRY_BEGIN
-
- _key.Password.CopyFrom(data, (size_t)size);
- return S_OK;
-
- COM_TRY_END
-}
-
-STDMETHODIMP CBaseCoder::Init()
-{
- COM_TRY_BEGIN
-
- PrepareKey();
- CMyComPtr<ICryptoProperties> cp;
- RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp));
- if (!cp)
- return E_FAIL;
- RINOK(cp->SetKey(_key.Key, kKeySize));
- RINOK(cp->SetInitVector(_iv, sizeof(_iv)));
- return _aesFilter->Init();
-
- COM_TRY_END
-}
-
-STDMETHODIMP_(UInt32) CBaseCoder::Filter(Byte *data, UInt32 size)
-{
- return _aesFilter->Filter(data, size);
-}
-
-}}
+// 7zAes.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+#include "../../../C/Sha256.h"
+
+#include "../../Common/ComTry.h"
+#include "../../Common/MyBuffer2.h"
+
+#ifndef Z7_ST
+#include "../../Windows/Synchronization.h"
+#endif
+
+#include "../Common/StreamUtils.h"
+
+#include "7zAes.h"
+#include "MyAes.h"
+
+#ifndef Z7_EXTRACT_ONLY
+#include "RandGen.h"
+#endif
+
+namespace NCrypto {
+namespace N7z {
+
+static const unsigned k_NumCyclesPower_Supported_MAX = 24;
+
+bool CKeyInfo::IsEqualTo(const CKeyInfo &a) const
+{
+ if (SaltSize != a.SaltSize || NumCyclesPower != a.NumCyclesPower)
+ return false;
+ for (unsigned i = 0; i < SaltSize; i++)
+ if (Salt[i] != a.Salt[i])
+ return false;
+ return (Password == a.Password);
+}
+
+void CKeyInfo::CalcKey()
+{
+ if (NumCyclesPower == 0x3F)
+ {
+ unsigned pos;
+ for (pos = 0; pos < SaltSize; pos++)
+ Key[pos] = Salt[pos];
+ for (unsigned i = 0; i < Password.Size() && pos < kKeySize; i++)
+ Key[pos++] = Password[i];
+ for (; pos < kKeySize; pos++)
+ Key[pos] = 0;
+ }
+ else
+ {
+ const unsigned kUnrPow = 6;
+ const UInt32 numUnroll = (UInt32)1 << (NumCyclesPower <= kUnrPow ? (unsigned)NumCyclesPower : kUnrPow);
+
+ const size_t bufSize = 8 + SaltSize + Password.Size();
+ const size_t unrollSize = bufSize * numUnroll;
+
+ // MY_ALIGN (16)
+ // CSha256 sha;
+ CAlignedBuffer sha(sizeof(CSha256) + unrollSize + bufSize * 2);
+ Byte *buf = sha + sizeof(CSha256);
+
+ memcpy(buf, Salt, SaltSize);
+ memcpy(buf + SaltSize, Password, Password.Size());
+ memset(buf + bufSize - 8, 0, 8);
+
+ Sha256_Init((CSha256 *)(void *)(Byte *)sha);
+
+ {
+ {
+ Byte *dest = buf;
+ for (UInt32 i = 1; i < numUnroll; i++)
+ {
+ dest += bufSize;
+ memcpy(dest, buf, bufSize);
+ }
+ }
+
+ const UInt32 numRounds = (UInt32)1 << NumCyclesPower;
+ UInt32 r = 0;
+ do
+ {
+ Byte *dest = buf + bufSize - 8;
+ UInt32 i = r;
+ r += numUnroll;
+ do
+ {
+ SetUi32(dest, i) i++; dest += bufSize;
+ // SetUi32(dest, i) i++; dest += bufSize;
+ }
+ while (i < r);
+ Sha256_Update((CSha256 *)(void *)(Byte *)sha, buf, unrollSize);
+ }
+ while (r < numRounds);
+ }
+ /*
+ UInt64 numRounds = (UInt64)1 << NumCyclesPower;
+
+ do
+ {
+ Sha256_Update((CSha256 *)(Byte *)sha, buf, bufSize);
+ for (unsigned i = 0; i < 8; i++)
+ if (++(ctr[i]) != 0)
+ break;
+ }
+ while (--numRounds != 0);
+ */
+
+ Sha256_Final((CSha256 *)(void *)(Byte *)sha, Key);
+ memset(sha, 0, sha.Size());
+ }
+}
+
+bool CKeyInfoCache::GetKey(CKeyInfo &key)
+{
+ FOR_VECTOR (i, Keys)
+ {
+ const CKeyInfo &cached = Keys[i];
+ if (key.IsEqualTo(cached))
+ {
+ for (unsigned j = 0; j < kKeySize; j++)
+ key.Key[j] = cached.Key[j];
+ if (i != 0)
+ Keys.MoveToFront(i);
+ return true;
+ }
+ }
+ return false;
+}
+
+void CKeyInfoCache::FindAndAdd(const CKeyInfo &key)
+{
+ FOR_VECTOR (i, Keys)
+ {
+ const CKeyInfo &cached = Keys[i];
+ if (key.IsEqualTo(cached))
+ {
+ if (i != 0)
+ Keys.MoveToFront(i);
+ return;
+ }
+ }
+ Add(key);
+}
+
+void CKeyInfoCache::Add(const CKeyInfo &key)
+{
+ if (Keys.Size() >= Size)
+ Keys.DeleteBack();
+ Keys.Insert(0, key);
+}
+
+static CKeyInfoCache g_GlobalKeyCache(32);
+
+#ifndef Z7_ST
+ static NWindows::NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection;
+ #define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection);
+#else
+ #define MT_LOCK
+#endif
+
+CBase::CBase():
+ _cachedKeys(16),
+ _ivSize(0)
+{
+ for (unsigned i = 0; i < sizeof(_iv); i++)
+ _iv[i] = 0;
+}
+
+void CBase::PrepareKey()
+{
+ // BCJ2 threads use same password. So we use long lock.
+ MT_LOCK
+
+ bool finded = false;
+ if (!_cachedKeys.GetKey(_key))
+ {
+ finded = g_GlobalKeyCache.GetKey(_key);
+ if (!finded)
+ _key.CalcKey();
+ _cachedKeys.Add(_key);
+ }
+ if (!finded)
+ g_GlobalKeyCache.FindAndAdd(_key);
+}
+
+#ifndef Z7_EXTRACT_ONLY
+
+/*
+Z7_COM7F_IMF(CEncoder::ResetSalt())
+{
+ _key.SaltSize = 4;
+ g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
+ return S_OK;
+}
+*/
+
+Z7_COM7F_IMF(CEncoder::ResetInitVector())
+{
+ for (unsigned i = 0; i < sizeof(_iv); i++)
+ _iv[i] = 0;
+ _ivSize = 16;
+ MY_RAND_GEN(_iv, _ivSize);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CEncoder::WriteCoderProperties(ISequentialOutStream *outStream))
+{
+ Byte props[2 + sizeof(_key.Salt) + sizeof(_iv)];
+ unsigned propsSize = 1;
+
+ props[0] = (Byte)(_key.NumCyclesPower
+ | (_key.SaltSize == 0 ? 0 : (1 << 7))
+ | (_ivSize == 0 ? 0 : (1 << 6)));
+
+ if (_key.SaltSize != 0 || _ivSize != 0)
+ {
+ props[1] = (Byte)(
+ ((_key.SaltSize == 0 ? 0 : _key.SaltSize - 1) << 4)
+ | (_ivSize == 0 ? 0 : _ivSize - 1));
+ memcpy(props + 2, _key.Salt, _key.SaltSize);
+ propsSize = 2 + _key.SaltSize;
+ memcpy(props + propsSize, _iv, _ivSize);
+ propsSize += _ivSize;
+ }
+
+ return WriteStream(outStream, props, propsSize);
+}
+
+CEncoder::CEncoder()
+{
+ // _key.SaltSize = 4; g_RandomGenerator.Generate(_key.Salt, _key.SaltSize);
+ // _key.NumCyclesPower = 0x3F;
+ _key.NumCyclesPower = 19;
+ _aesFilter = new CAesCbcEncoder(kKeySize);
+}
+
+#endif
+
+CDecoder::CDecoder()
+{
+ _aesFilter = new CAesCbcDecoder(kKeySize);
+}
+
+Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size))
+{
+ _key.ClearProps();
+
+ _ivSize = 0;
+ unsigned i;
+ for (i = 0; i < sizeof(_iv); i++)
+ _iv[i] = 0;
+
+ if (size == 0)
+ return S_OK;
+
+ Byte b0 = data[0];
+
+ _key.NumCyclesPower = b0 & 0x3F;
+ if ((b0 & 0xC0) == 0)
+ return size == 1 ? S_OK : E_INVALIDARG;
+
+ if (size <= 1)
+ return E_INVALIDARG;
+
+ Byte b1 = data[1];
+
+ unsigned saltSize = ((b0 >> 7) & 1) + (b1 >> 4);
+ unsigned ivSize = ((b0 >> 6) & 1) + (b1 & 0x0F);
+
+ if (size != 2 + saltSize + ivSize)
+ return E_INVALIDARG;
+ _key.SaltSize = saltSize;
+ data += 2;
+ for (i = 0; i < saltSize; i++)
+ _key.Salt[i] = *data++;
+ for (i = 0; i < ivSize; i++)
+ _iv[i] = *data++;
+ return (_key.NumCyclesPower <= k_NumCyclesPower_Supported_MAX
+ || _key.NumCyclesPower == 0x3F) ? S_OK : E_NOTIMPL;
+}
+
+
+Z7_COM7F_IMF(CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size))
+{
+ COM_TRY_BEGIN
+
+ _key.Password.Wipe();
+ _key.Password.CopyFrom(data, (size_t)size);
+ return S_OK;
+
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CBaseCoder::Init())
+{
+ COM_TRY_BEGIN
+
+ PrepareKey();
+ CMyComPtr<ICryptoProperties> cp;
+ RINOK(_aesFilter.QueryInterface(IID_ICryptoProperties, &cp))
+ if (!cp)
+ return E_FAIL;
+ RINOK(cp->SetKey(_key.Key, kKeySize))
+ RINOK(cp->SetInitVector(_iv, sizeof(_iv)))
+ return _aesFilter->Init();
+
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF2(UInt32, CBaseCoder::Filter(Byte *data, UInt32 size))
+{
+ return _aesFilter->Filter(data, size);
+}
+
+}}
diff --git a/CPP/7zip/Crypto/7zAes.h b/CPP/7zip/Crypto/7zAes.h
index 5a09436..8f7bf03 100644
--- a/CPP/7zip/Crypto/7zAes.h
+++ b/CPP/7zip/Crypto/7zAes.h
@@ -1,118 +1,130 @@
-// 7zAes.h
-
-#ifndef __CRYPTO_7Z_AES_H
-#define __CRYPTO_7Z_AES_H
-
-#include "../../Common/MyBuffer.h"
-#include "../../Common/MyCom.h"
-#include "../../Common/MyVector.h"
-
-#include "../ICoder.h"
-#include "../IPassword.h"
-
-namespace NCrypto {
-namespace N7z {
-
-const unsigned kKeySize = 32;
-const unsigned kSaltSizeMax = 16;
-const unsigned kIvSizeMax = 16; // AES_BLOCK_SIZE;
-
-class CKeyInfo
-{
-public:
- unsigned NumCyclesPower;
- unsigned SaltSize;
- Byte Salt[kSaltSizeMax];
- CByteBuffer Password;
- Byte Key[kKeySize];
-
- bool IsEqualTo(const CKeyInfo &a) const;
- void CalcKey();
-
- CKeyInfo() { ClearProps(); }
- void ClearProps()
- {
- NumCyclesPower = 0;
- SaltSize = 0;
- for (unsigned i = 0; i < sizeof(Salt); i++)
- Salt[i] = 0;
- }
-};
-
-class CKeyInfoCache
-{
- unsigned Size;
- CObjectVector<CKeyInfo> Keys;
-public:
- CKeyInfoCache(unsigned size): Size(size) {}
- bool GetKey(CKeyInfo &key);
- void Add(const CKeyInfo &key);
- void FindAndAdd(const CKeyInfo &key);
-};
-
-class CBase
-{
- CKeyInfoCache _cachedKeys;
-protected:
- CKeyInfo _key;
- Byte _iv[kIvSizeMax];
- unsigned _ivSize;
-
- void PrepareKey();
- CBase();
-};
-
-class CBaseCoder:
- public ICompressFilter,
- public ICryptoSetPassword,
- public CMyUnknownImp,
- public CBase
-{
-protected:
- CMyComPtr<ICompressFilter> _aesFilter;
-
-public:
- INTERFACE_ICompressFilter(;)
-
- STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size);
-};
-
-#ifndef EXTRACT_ONLY
-
-class CEncoder:
- public CBaseCoder,
- public ICompressWriteCoderProperties,
- // public ICryptoResetSalt,
- public ICryptoResetInitVector
-{
-public:
- MY_UNKNOWN_IMP4(
- ICompressFilter,
- ICryptoSetPassword,
- ICompressWriteCoderProperties,
- // ICryptoResetSalt,
- ICryptoResetInitVector)
- STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream);
- // STDMETHOD(ResetSalt)();
- STDMETHOD(ResetInitVector)();
- CEncoder();
-};
-
-#endif
-
-class CDecoder:
- public CBaseCoder,
- public ICompressSetDecoderProperties2
-{
-public:
- MY_UNKNOWN_IMP3(
- ICompressFilter,
- ICryptoSetPassword,
- ICompressSetDecoderProperties2)
- STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size);
- CDecoder();
-};
-
-}}
-
-#endif
+// 7zAes.h
+
+#ifndef ZIP7_INC_CRYPTO_7Z_AES_H
+#define ZIP7_INC_CRYPTO_7Z_AES_H
+
+#include "../../Common/MyBuffer.h"
+#include "../../Common/MyCom.h"
+#include "../../Common/MyVector.h"
+
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+namespace NCrypto {
+namespace N7z {
+
+const unsigned kKeySize = 32;
+const unsigned kSaltSizeMax = 16;
+const unsigned kIvSizeMax = 16; // AES_BLOCK_SIZE;
+
+class CKeyInfo
+{
+public:
+ unsigned NumCyclesPower;
+ unsigned SaltSize;
+ Byte Salt[kSaltSizeMax];
+ CByteBuffer Password;
+ Byte Key[kKeySize];
+
+ bool IsEqualTo(const CKeyInfo &a) const;
+ void CalcKey();
+
+ CKeyInfo() { ClearProps(); }
+ void ClearProps()
+ {
+ NumCyclesPower = 0;
+ SaltSize = 0;
+ for (unsigned i = 0; i < sizeof(Salt); i++)
+ Salt[i] = 0;
+ }
+
+ void Wipe()
+ {
+ Password.Wipe();
+ NumCyclesPower = 0;
+ SaltSize = 0;
+ Z7_memset_0_ARRAY(Salt);
+ Z7_memset_0_ARRAY(Key);
+ }
+
+#ifdef Z7_CPP_IS_SUPPORTED_default
+ CKeyInfo(const CKeyInfo &) = default;
+#endif
+ ~CKeyInfo() { Wipe(); }
+};
+
+class CKeyInfoCache
+{
+ unsigned Size;
+ CObjectVector<CKeyInfo> Keys;
+public:
+ CKeyInfoCache(unsigned size): Size(size) {}
+ bool GetKey(CKeyInfo &key);
+ void Add(const CKeyInfo &key);
+ void FindAndAdd(const CKeyInfo &key);
+};
+
+class CBase
+{
+ CKeyInfoCache _cachedKeys;
+protected:
+ CKeyInfo _key;
+ Byte _iv[kIvSizeMax];
+ unsigned _ivSize;
+
+ void PrepareKey();
+ CBase();
+};
+
+class CBaseCoder:
+ public ICompressFilter,
+ public ICryptoSetPassword,
+ public CMyUnknownImp,
+ public CBase
+{
+ Z7_IFACE_COM7_IMP(ICompressFilter)
+ Z7_IFACE_COM7_IMP(ICryptoSetPassword)
+protected:
+ virtual ~CBaseCoder() {}
+ CMyComPtr<ICompressFilter> _aesFilter;
+};
+
+#ifndef Z7_EXTRACT_ONLY
+
+class CEncoder Z7_final:
+ public CBaseCoder,
+ public ICompressWriteCoderProperties,
+ // public ICryptoResetSalt,
+ public ICryptoResetInitVector
+{
+ Z7_COM_UNKNOWN_IMP_4(
+ ICompressFilter,
+ ICryptoSetPassword,
+ ICompressWriteCoderProperties,
+ // ICryptoResetSalt,
+ ICryptoResetInitVector)
+ Z7_IFACE_COM7_IMP(ICompressWriteCoderProperties)
+ // Z7_IFACE_COM7_IMP(ICryptoResetSalt)
+ Z7_IFACE_COM7_IMP(ICryptoResetInitVector)
+public:
+ CEncoder();
+};
+
+#endif
+
+class CDecoder Z7_final:
+ public CBaseCoder,
+ public ICompressSetDecoderProperties2
+{
+ Z7_COM_UNKNOWN_IMP_3(
+ ICompressFilter,
+ ICryptoSetPassword,
+ ICompressSetDecoderProperties2)
+ Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2)
+public:
+ CDecoder();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Crypto/7zAesRegister.cpp b/CPP/7zip/Crypto/7zAesRegister.cpp
index c0b2060..69d0890 100644
--- a/CPP/7zip/Crypto/7zAesRegister.cpp
+++ b/CPP/7zip/Crypto/7zAesRegister.cpp
@@ -1,17 +1,17 @@
-// 7zAesRegister.cpp
-
-#include "StdAfx.h"
-
-#include "../Common/RegisterCodec.h"
-
-#include "7zAes.h"
-
-namespace NCrypto {
-namespace N7z {
-
-REGISTER_FILTER_E(7zAES,
- CDecoder(),
- CEncoder(),
- 0x6F10701, "7zAES")
-
-}}
+// 7zAesRegister.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "7zAes.h"
+
+namespace NCrypto {
+namespace N7z {
+
+REGISTER_FILTER_E(SzAES,
+ CDecoder,
+ CEncoder,
+ 0x6F10701, "7zAES")
+
+}}
diff --git a/CPP/7zip/Crypto/Codec.def b/CPP/7zip/Crypto/Codec.def
new file mode 100644
index 0000000..ebf73a3
--- /dev/null
+++ b/CPP/7zip/Crypto/Codec.def
@@ -0,0 +1,4 @@
+EXPORTS
+ CreateObject PRIVATE
+ GetNumberOfMethods PRIVATE
+ GetMethodProperty PRIVATE
diff --git a/CPP/7zip/Crypto/HmacSha1.cpp b/CPP/7zip/Crypto/HmacSha1.cpp
new file mode 100644
index 0000000..30b1a8f
--- /dev/null
+++ b/CPP/7zip/Crypto/HmacSha1.cpp
@@ -0,0 +1,94 @@
+// HmacSha1.cpp
+
+#include "StdAfx.h"
+
+#include <string.h>
+
+#include "../../../C/CpuArch.h"
+
+#include "HmacSha1.h"
+
+namespace NCrypto {
+namespace NSha1 {
+
+void CHmac::SetKey(const Byte *key, size_t keySize)
+{
+ MY_ALIGN (16)
+ UInt32 temp[SHA1_NUM_BLOCK_WORDS];
+ size_t i;
+
+ for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++)
+ temp[i] = 0;
+
+ if (keySize > kBlockSize)
+ {
+ _sha.Init();
+ _sha.Update(key, keySize);
+ _sha.Final((Byte *)temp);
+ }
+ else
+ memcpy(temp, key, keySize);
+
+ for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++)
+ temp[i] ^= 0x36363636;
+
+ _sha.Init();
+ _sha.Update((const Byte *)temp, kBlockSize);
+
+ for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++)
+ temp[i] ^= 0x36363636 ^ 0x5C5C5C5C;
+
+ _sha2.Init();
+ _sha2.Update((const Byte *)temp, kBlockSize);
+}
+
+
+void CHmac::Final(Byte *mac)
+{
+ _sha.Final(mac);
+ _sha2.Update(mac, kDigestSize);
+ _sha2.Final(mac);
+}
+
+
+void CHmac::GetLoopXorDigest1(void *mac, UInt32 numIteration)
+{
+ MY_ALIGN (16) UInt32 block [SHA1_NUM_BLOCK_WORDS];
+ MY_ALIGN (16) UInt32 block2[SHA1_NUM_BLOCK_WORDS];
+ MY_ALIGN (16) UInt32 mac2 [SHA1_NUM_BLOCK_WORDS];
+
+ _sha. PrepareBlock((Byte *)block, SHA1_DIGEST_SIZE);
+ _sha2.PrepareBlock((Byte *)block2, SHA1_DIGEST_SIZE);
+
+ block[0] = ((const UInt32 *)mac)[0];
+ block[1] = ((const UInt32 *)mac)[1];
+ block[2] = ((const UInt32 *)mac)[2];
+ block[3] = ((const UInt32 *)mac)[3];
+ block[4] = ((const UInt32 *)mac)[4];
+
+ mac2[0] = block[0];
+ mac2[1] = block[1];
+ mac2[2] = block[2];
+ mac2[3] = block[3];
+ mac2[4] = block[4];
+
+ for (UInt32 i = 0; i < numIteration; i++)
+ {
+ _sha. GetBlockDigest((const Byte *)block, (Byte *)block2);
+ _sha2.GetBlockDigest((const Byte *)block2, (Byte *)block);
+
+ mac2[0] ^= block[0];
+ mac2[1] ^= block[1];
+ mac2[2] ^= block[2];
+ mac2[3] ^= block[3];
+ mac2[4] ^= block[4];
+ }
+
+ ((UInt32 *)mac)[0] = mac2[0];
+ ((UInt32 *)mac)[1] = mac2[1];
+ ((UInt32 *)mac)[2] = mac2[2];
+ ((UInt32 *)mac)[3] = mac2[3];
+ ((UInt32 *)mac)[4] = mac2[4];
+}
+
+}}
diff --git a/CPP/7zip/Crypto/HmacSha1.h b/CPP/7zip/Crypto/HmacSha1.h
new file mode 100644
index 0000000..a36c78e
--- /dev/null
+++ b/CPP/7zip/Crypto/HmacSha1.h
@@ -0,0 +1,31 @@
+// HmacSha1.h
+// Implements HMAC-SHA-1 (RFC2104, FIPS-198)
+
+#ifndef ZIP7_INC_CRYPTO_HMAC_SHA1_H
+#define ZIP7_INC_CRYPTO_HMAC_SHA1_H
+
+#include "Sha1Cls.h"
+
+namespace NCrypto {
+namespace NSha1 {
+
+// Use: SetKey(key, keySize); for () Update(data, size); FinalFull(mac);
+
+class CHmac
+{
+ CContext _sha;
+ CContext _sha2;
+public:
+ void SetKey(const Byte *key, size_t keySize);
+ void Update(const Byte *data, size_t dataSize) { _sha.Update(data, dataSize); }
+
+ // Final() : mac is recommended to be aligned for 4 bytes
+ // GetLoopXorDigest1() : mac is required to be aligned for 4 bytes
+ // The caller can use: UInt32 mac[NSha1::kNumDigestWords] and typecast to (Byte *) and (void *);
+ void Final(Byte *mac);
+ void GetLoopXorDigest1(void *mac, UInt32 numIteration);
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Crypto/HmacSha256.cpp b/CPP/7zip/Crypto/HmacSha256.cpp
new file mode 100644
index 0000000..56f8ede
--- /dev/null
+++ b/CPP/7zip/Crypto/HmacSha256.cpp
@@ -0,0 +1,53 @@
+// HmacSha256.cpp
+
+#include "StdAfx.h"
+
+#include <string.h>
+
+#include "../../../C/CpuArch.h"
+
+#include "HmacSha256.h"
+
+namespace NCrypto {
+namespace NSha256 {
+
+void CHmac::SetKey(const Byte *key, size_t keySize)
+{
+ MY_ALIGN (16)
+ UInt32 temp[SHA256_NUM_BLOCK_WORDS];
+ size_t i;
+
+ for (i = 0; i < SHA256_NUM_BLOCK_WORDS; i++)
+ temp[i] = 0;
+
+ if (keySize > kBlockSize)
+ {
+ Sha256_Init(&_sha);
+ Sha256_Update(&_sha, key, keySize);
+ Sha256_Final(&_sha, (Byte *)temp);
+ }
+ else
+ memcpy(temp, key, keySize);
+
+ for (i = 0; i < SHA256_NUM_BLOCK_WORDS; i++)
+ temp[i] ^= 0x36363636;
+
+ Sha256_Init(&_sha);
+ Sha256_Update(&_sha, (const Byte *)temp, kBlockSize);
+
+ for (i = 0; i < SHA256_NUM_BLOCK_WORDS; i++)
+ temp[i] ^= 0x36363636 ^ 0x5C5C5C5C;
+
+ Sha256_Init(&_sha2);
+ Sha256_Update(&_sha2, (const Byte *)temp, kBlockSize);
+}
+
+
+void CHmac::Final(Byte *mac)
+{
+ Sha256_Final(&_sha, mac);
+ Sha256_Update(&_sha2, mac, SHA256_DIGEST_SIZE);
+ Sha256_Final(&_sha2, mac);
+}
+
+}}
diff --git a/CPP/7zip/Crypto/HmacSha256.h b/CPP/7zip/Crypto/HmacSha256.h
new file mode 100644
index 0000000..4039c0c
--- /dev/null
+++ b/CPP/7zip/Crypto/HmacSha256.h
@@ -0,0 +1,27 @@
+// HmacSha256.h
+// Implements HMAC-SHA-256 (RFC2104, FIPS-198)
+
+#ifndef ZIP7_INC_CRYPTO_HMAC_SHA256_H
+#define ZIP7_INC_CRYPTO_HMAC_SHA256_H
+
+#include "../../../C/Sha256.h"
+
+namespace NCrypto {
+namespace NSha256 {
+
+const unsigned kBlockSize = SHA256_BLOCK_SIZE;
+const unsigned kDigestSize = SHA256_DIGEST_SIZE;
+
+class CHmac
+{
+ CSha256 _sha;
+ CSha256 _sha2;
+public:
+ void SetKey(const Byte *key, size_t keySize);
+ void Update(const Byte *data, size_t dataSize) { Sha256_Update(&_sha, data, dataSize); }
+ void Final(Byte *mac);
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Crypto/MyAes.cpp b/CPP/7zip/Crypto/MyAes.cpp
index 1d399d7..6abc388 100644
--- a/CPP/7zip/Crypto/MyAes.cpp
+++ b/CPP/7zip/Crypto/MyAes.cpp
@@ -1,112 +1,246 @@
-// Crypto/MyAes.cpp
-
-#include "StdAfx.h"
-
-#include "../../../C/CpuArch.h"
-
-#include "MyAes.h"
-
-namespace NCrypto {
-
-static struct CAesTabInit { CAesTabInit() { AesGenTables();} } g_AesTabInit;
-
-CAesCbcCoder::CAesCbcCoder(bool encodeMode, unsigned keySize):
- _keySize(keySize),
- _keyIsSet(false),
- _encodeMode(encodeMode)
-{
- _offset = ((0 - (unsigned)(ptrdiff_t)_aes) & 0xF) / sizeof(UInt32);
- memset(_iv, 0, AES_BLOCK_SIZE);
- SetFunctions(0);
-}
-
-STDMETHODIMP CAesCbcCoder::Init()
-{
- AesCbc_Init(_aes + _offset, _iv);
- return _keyIsSet ? S_OK : E_FAIL;
-}
-
-STDMETHODIMP_(UInt32) CAesCbcCoder::Filter(Byte *data, UInt32 size)
-{
- if (!_keyIsSet)
- return 0;
- if (size == 0)
- return 0;
- if (size < AES_BLOCK_SIZE)
- return AES_BLOCK_SIZE;
- size >>= 4;
- _codeFunc(_aes + _offset, data, size);
- return size << 4;
-}
-
-STDMETHODIMP CAesCbcCoder::SetKey(const Byte *data, UInt32 size)
-{
- if ((size & 0x7) != 0 || size < 16 || size > 32)
- return E_INVALIDARG;
- if (_keySize != 0 && size != _keySize)
- return E_INVALIDARG;
- AES_SET_KEY_FUNC setKeyFunc = _encodeMode ? Aes_SetKey_Enc : Aes_SetKey_Dec;
- setKeyFunc(_aes + _offset + 4, data, size);
- _keyIsSet = true;
- return S_OK;
-}
-
-STDMETHODIMP CAesCbcCoder::SetInitVector(const Byte *data, UInt32 size)
-{
- if (size != AES_BLOCK_SIZE)
- return E_INVALIDARG;
- memcpy(_iv, data, size);
- CAesCbcCoder::Init(); // don't call virtual function here !!!
- return S_OK;
-}
-
-EXTERN_C_BEGIN
-
-void MY_FAST_CALL AesCbc_Encode(UInt32 *ivAes, Byte *data, size_t numBlocks);
-void MY_FAST_CALL AesCbc_Decode(UInt32 *ivAes, Byte *data, size_t numBlocks);
-void MY_FAST_CALL AesCtr_Code(UInt32 *ivAes, Byte *data, size_t numBlocks);
-
-void MY_FAST_CALL AesCbc_Encode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);
-void MY_FAST_CALL AesCbc_Decode_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);
-void MY_FAST_CALL AesCtr_Code_Intel(UInt32 *ivAes, Byte *data, size_t numBlocks);
-
-EXTERN_C_END
-
-bool CAesCbcCoder::SetFunctions(UInt32 algo)
-{
- _codeFunc = _encodeMode ?
- g_AesCbc_Encode :
- g_AesCbc_Decode;
- if (algo == 1)
- {
- _codeFunc = _encodeMode ?
- AesCbc_Encode:
- AesCbc_Decode;
- }
- if (algo == 2)
- {
- #ifdef MY_CPU_X86_OR_AMD64
- if (g_AesCbc_Encode != AesCbc_Encode_Intel)
- #endif
- return false;
- }
- return true;
-}
-
-STDMETHODIMP CAesCbcCoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)
-{
- for (UInt32 i = 0; i < numProps; i++)
- {
- const PROPVARIANT &prop = coderProps[i];
- if (propIDs[i] == NCoderPropID::kDefaultProp)
- {
- if (prop.vt != VT_UI4)
- return E_INVALIDARG;
- if (!SetFunctions(prop.ulVal))
- return E_NOTIMPL;
- }
- }
- return S_OK;
-}
-
-}
+// Crypto/MyAes.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "MyAes.h"
+
+namespace NCrypto {
+
+static struct CAesTabInit { CAesTabInit() { AesGenTables();} } g_AesTabInit;
+
+CAesCoder::CAesCoder(
+ // bool encodeMode,
+ unsigned keySize
+ // , bool ctrMode
+ ):
+ _keyIsSet(false),
+ // _encodeMode(encodeMode),
+ // _ctrMode(ctrMode),
+ _keySize(keySize),
+ // _ctrPos(0), // _ctrPos =0 will be set in Init()
+ _aes(AES_NUM_IVMRK_WORDS * 4 + AES_BLOCK_SIZE * 2)
+{
+ // _offset = ((0 - (unsigned)(ptrdiff_t)_aes) & 0xF) / sizeof(UInt32);
+ memset(_iv, 0, AES_BLOCK_SIZE);
+ /*
+ // we can use the following code to test 32-bit overflow case for AES-CTR
+ for (unsigned i = 0; i < 16; i++) _iv[i] = (Byte)(i + 1);
+ _iv[0] = 0xFE; _iv[1] = _iv[2] = _iv[3] = 0xFF;
+ */
+}
+
+Z7_COM7F_IMF(CAesCoder::Init())
+{
+ _ctrPos = 0;
+ AesCbc_Init(Aes(), _iv);
+ return _keyIsSet ? S_OK : E_NOTIMPL; // E_FAIL
+}
+
+Z7_COM7F_IMF2(UInt32, CAesCoder::Filter(Byte *data, UInt32 size))
+{
+ if (!_keyIsSet)
+ return 0;
+ if (size < AES_BLOCK_SIZE)
+ {
+ if (size == 0)
+ return 0;
+ return AES_BLOCK_SIZE;
+ }
+ size >>= 4;
+ // (data) must be aligned for 16-bytes here
+ _codeFunc(Aes(), data, size);
+ return size << 4;
+}
+
+
+Z7_COM7F_IMF(CAesCoder::SetKey(const Byte *data, UInt32 size))
+{
+ if ((size & 0x7) != 0 || size < 16 || size > 32)
+ return E_INVALIDARG;
+ if (_keySize != 0 && size != _keySize)
+ return E_INVALIDARG;
+ _setKeyFunc(Aes() + 4, data, size);
+ _keyIsSet = true;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CAesCoder::SetInitVector(const Byte *data, UInt32 size))
+{
+ if (size != AES_BLOCK_SIZE)
+ return E_INVALIDARG;
+ memcpy(_iv, data, size);
+ /* we allow SetInitVector() call before SetKey() call.
+ so we ignore possible error in Init() here */
+ CAesCoder::Init(); // don't call virtual function here !!!
+ return S_OK;
+}
+
+
+#ifndef Z7_SFX
+
+/*
+Z7_COM7F_IMF(CAesCtrCoder::Init())
+{
+ _ctrPos = 0;
+ return CAesCoder::Init();
+}
+*/
+
+Z7_COM7F_IMF2(UInt32, CAesCtrCoder::Filter(Byte *data, UInt32 size))
+{
+ if (!_keyIsSet)
+ return 0;
+ if (size == 0)
+ return 0;
+
+ if (_ctrPos != 0)
+ {
+ /* Optimized caller will not call here */
+ const Byte *ctr = (Byte *)(Aes() + AES_NUM_IVMRK_WORDS);
+ unsigned num = 0;
+ for (unsigned i = _ctrPos; i != AES_BLOCK_SIZE; i++)
+ {
+ if (num == size)
+ {
+ _ctrPos = i;
+ return num;
+ }
+ data[num++] ^= ctr[i];
+ }
+ _ctrPos = 0;
+ /* if (num < size) {
+ we can filter more data with _codeFunc().
+ But it's supposed that the caller can work correctly,
+ even if we do only partial filtering here.
+ So we filter data only for current 16-byte block. }
+ */
+ /*
+ size -= num;
+ size >>= 4;
+ // (data) must be aligned for 16-bytes here
+ _codeFunc(Aes(), data + num, size);
+ return num + (size << 4);
+ */
+ return num;
+ }
+
+ if (size < AES_BLOCK_SIZE)
+ {
+ /* The good optimized caller can call here only in last Filter() call.
+ But we support also non-optimized callers,
+ where another Filter() calls are allowed after this call.
+ */
+ Byte *ctr = (Byte *)(Aes() + AES_NUM_IVMRK_WORDS);
+ memset(ctr, 0, AES_BLOCK_SIZE);
+ memcpy(ctr, data, size);
+ _codeFunc(Aes(), ctr, 1);
+ memcpy(data, ctr, size);
+ _ctrPos = size;
+ return size;
+ }
+
+ size >>= 4;
+ // (data) must be aligned for 16-bytes here
+ _codeFunc(Aes(), data, size);
+ return size << 4;
+}
+
+#endif // Z7_SFX
+
+
+#ifndef Z7_EXTRACT_ONLY
+
+#ifdef MY_CPU_X86_OR_AMD64
+ #define USE_HW_AES
+#elif defined(MY_CPU_ARM_OR_ARM64) && defined(MY_CPU_LE)
+ #if defined(__clang__)
+ #if (__clang_major__ >= 8) // fix that check
+ #define USE_HW_AES
+ #endif
+ #elif defined(__GNUC__)
+ #if (__GNUC__ >= 6) // fix that check
+ #define USE_HW_AES
+ #endif
+ #elif defined(_MSC_VER)
+ #if _MSC_VER >= 1910
+ #define USE_HW_AES
+ #endif
+ #endif
+#endif
+
+#ifdef USE_HW_AES
+ #define SET_AES_FUNC_2(f2) \
+ if (algo == 2) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW) \
+ { f = f2; }
+ #ifdef MY_CPU_X86_OR_AMD64
+ #define SET_AES_FUNC_23(f2, f3) \
+ SET_AES_FUNC_2(f2) \
+ if (algo == 3) if (g_Aes_SupportedFunctions_Flags & k_Aes_SupportedFunctions_HW_256) \
+ { f = f3; }
+ #else // MY_CPU_X86_OR_AMD64
+ #define SET_AES_FUNC_23(f2, f3) \
+ SET_AES_FUNC_2(f2)
+ #endif // MY_CPU_X86_OR_AMD64
+#else // USE_HW_AES
+ #define SET_AES_FUNC_23(f2, f3)
+#endif // USE_HW_AES
+
+#define SET_AES_FUNCS(c, f0, f1, f2, f3) \
+ bool c::SetFunctions(UInt32 algo) { \
+ _codeFunc = f0; if (algo < 1) return true; \
+ AES_CODE_FUNC f = NULL; \
+ if (algo == 1) { f = f1; } \
+ SET_AES_FUNC_23(f2, f3) \
+ if (f) { _codeFunc = f; return true; } \
+ return false; }
+
+
+
+#ifndef Z7_SFX
+SET_AES_FUNCS(
+ CAesCtrCoder,
+ g_AesCtr_Code,
+ AesCtr_Code,
+ AesCtr_Code_HW,
+ AesCtr_Code_HW_256)
+#endif
+
+SET_AES_FUNCS(
+ CAesCbcEncoder,
+ g_AesCbc_Encode,
+ AesCbc_Encode,
+ AesCbc_Encode_HW,
+ AesCbc_Encode_HW)
+
+SET_AES_FUNCS(
+ CAesCbcDecoder,
+ g_AesCbc_Decode,
+ AesCbc_Decode,
+ AesCbc_Decode_HW,
+ AesCbc_Decode_HW_256)
+
+Z7_COM7F_IMF(CAesCoder::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps))
+{
+ UInt32 algo = 0;
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ if (propIDs[i] == NCoderPropID::kDefaultProp)
+ {
+ const PROPVARIANT &prop = coderProps[i];
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ if (prop.ulVal > 3)
+ return E_NOTIMPL;
+ algo = prop.ulVal;
+ }
+ }
+ if (!SetFunctions(algo))
+ return E_NOTIMPL;
+ return S_OK;
+}
+
+#endif // Z7_EXTRACT_ONLY
+
+}
diff --git a/CPP/7zip/Crypto/MyAes.h b/CPP/7zip/Crypto/MyAes.h
index 8d5ed98..a3c1c27 100644
--- a/CPP/7zip/Crypto/MyAes.h
+++ b/CPP/7zip/Crypto/MyAes.h
@@ -1,57 +1,122 @@
-// Crypto/MyAes.h
-
-#ifndef __CRYPTO_MY_AES_H
-#define __CRYPTO_MY_AES_H
-
-#include "../../../C/Aes.h"
-
-#include "../../Common/MyCom.h"
-
-#include "../ICoder.h"
-
-namespace NCrypto {
-
-class CAesCbcCoder:
- public ICompressFilter,
- public ICryptoProperties,
- public ICompressSetCoderProperties,
- public CMyUnknownImp
-{
- AES_CODE_FUNC _codeFunc;
- unsigned _offset;
- unsigned _keySize;
- bool _keyIsSet;
- bool _encodeMode;
- UInt32 _aes[AES_NUM_IVMRK_WORDS + 3];
- Byte _iv[AES_BLOCK_SIZE];
-
- bool SetFunctions(UInt32 algo);
-
-public:
- CAesCbcCoder(bool encodeMode, unsigned keySize);
-
- virtual ~CAesCbcCoder() {}; // we need virtual destructor for derived classes
-
- MY_UNKNOWN_IMP3(ICompressFilter, ICryptoProperties, ICompressSetCoderProperties)
-
- INTERFACE_ICompressFilter(;)
-
- STDMETHOD(SetKey)(const Byte *data, UInt32 size);
- STDMETHOD(SetInitVector)(const Byte *data, UInt32 size);
-
- STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
-};
-
-struct CAesCbcEncoder: public CAesCbcCoder
-{
- CAesCbcEncoder(unsigned keySize = 0): CAesCbcCoder(true, keySize) {}
-};
-
-struct CAesCbcDecoder: public CAesCbcCoder
-{
- CAesCbcDecoder(unsigned keySize = 0): CAesCbcCoder(false, keySize) {}
-};
-
-}
-
-#endif
+// Crypto/MyAes.h
+
+#ifndef ZIP7_INC_CRYPTO_MY_AES_H
+#define ZIP7_INC_CRYPTO_MY_AES_H
+
+#include "../../../C/Aes.h"
+
+#include "../../Common/MyBuffer2.h"
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCrypto {
+
+#ifdef Z7_EXTRACT_ONLY
+#define Z7_IFACEN_IAesCoderSetFunctions(x)
+#else
+#define Z7_IFACEN_IAesCoderSetFunctions(x) \
+ virtual bool SetFunctions(UInt32 algo) x
+#endif
+
+
+class CAesCoder:
+ public ICompressFilter,
+ public ICryptoProperties,
+ #ifndef Z7_EXTRACT_ONLY
+ public ICompressSetCoderProperties,
+ #endif
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(ICompressFilter)
+ Z7_COM_QI_ENTRY(ICryptoProperties)
+ #ifndef Z7_EXTRACT_ONLY
+ Z7_COM_QI_ENTRY(ICompressSetCoderProperties)
+ #endif
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+public:
+ Z7_IFACE_COM7_IMP_NONFINAL(ICompressFilter)
+ Z7_IFACE_COM7_IMP(ICryptoProperties)
+private:
+ #ifndef Z7_EXTRACT_ONLY
+ Z7_IFACE_COM7_IMP(ICompressSetCoderProperties)
+ #endif
+
+protected:
+ bool _keyIsSet;
+ // bool _encodeMode;
+ // bool _ctrMode;
+ // unsigned _offset;
+ unsigned _keySize;
+ unsigned _ctrPos; // we need _ctrPos here for Init() / SetInitVector()
+ AES_CODE_FUNC _codeFunc;
+ AES_SET_KEY_FUNC _setKeyFunc;
+private:
+ // UInt32 _aes[AES_NUM_IVMRK_WORDS + 3];
+ CAlignedBuffer1 _aes;
+
+ Byte _iv[AES_BLOCK_SIZE];
+
+ // UInt32 *Aes() { return _aes + _offset; }
+protected:
+ UInt32 *Aes() { return (UInt32 *)(void *)(Byte *)_aes; }
+
+ Z7_IFACE_PURE(IAesCoderSetFunctions)
+
+public:
+ CAesCoder(
+ // bool encodeMode,
+ unsigned keySize
+ // , bool ctrMode
+ );
+ virtual ~CAesCoder() {} // we need virtual destructor for derived classes
+ void SetKeySize(unsigned size) { _keySize = size; }
+};
+
+
+#ifndef Z7_EXTRACT_ONLY
+struct CAesCbcEncoder: public CAesCoder
+{
+ CAesCbcEncoder(unsigned keySize = 0): CAesCoder(keySize)
+ {
+ _setKeyFunc = Aes_SetKey_Enc;
+ _codeFunc = g_AesCbc_Encode;
+ }
+ Z7_IFACE_IMP(IAesCoderSetFunctions)
+};
+#endif
+
+struct CAesCbcDecoder: public CAesCoder
+{
+ CAesCbcDecoder(unsigned keySize = 0): CAesCoder(keySize)
+ {
+ _setKeyFunc = Aes_SetKey_Dec;
+ _codeFunc = g_AesCbc_Decode;
+ }
+ Z7_IFACE_IMP(IAesCoderSetFunctions)
+};
+
+#ifndef Z7_SFX
+struct CAesCtrCoder: public CAesCoder
+{
+private:
+ // unsigned _ctrPos;
+ // Z7_IFACE_COM7_IMP(ICompressFilter)
+ // Z7_COM7F_IMP(Init())
+ Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size))
+public:
+ CAesCtrCoder(unsigned keySize = 0): CAesCoder(keySize)
+ {
+ _ctrPos = 0;
+ _setKeyFunc = Aes_SetKey_Enc;
+ _codeFunc = g_AesCtr_Code;
+ }
+ Z7_IFACE_IMP(IAesCoderSetFunctions)
+};
+#endif
+
+}
+
+#endif
diff --git a/CPP/7zip/Crypto/MyAesReg.cpp b/CPP/7zip/Crypto/MyAesReg.cpp
index 3427ad6..e2b4f72 100644
--- a/CPP/7zip/Crypto/MyAesReg.cpp
+++ b/CPP/7zip/Crypto/MyAesReg.cpp
@@ -1,16 +1,29 @@
-// MyAesReg.cpp
-
-#include "StdAfx.h"
-
-#include "../Common/RegisterCodec.h"
-
-#include "MyAes.h"
-
-namespace NCrypto {
-
-REGISTER_FILTER_E(AES256CBC,
- CAesCbcDecoder(32),
- CAesCbcEncoder(32),
- 0x6F00181, "AES256CBC")
-
-}
+// MyAesReg.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/RegisterCodec.h"
+
+#include "MyAes.h"
+
+namespace NCrypto {
+
+#ifndef Z7_SFX
+
+#define REGISTER_AES_2(name, nameString, keySize) \
+ REGISTER_FILTER_E(name, \
+ CAesCbcDecoder(keySize), \
+ CAesCbcEncoder(keySize), \
+ 0x6F00100 | ((keySize - 16) * 8) | (/* isCtr */ 0 ? 4 : 1), \
+ nameString) \
+
+#define REGISTER_AES(name, nameString) \
+ /* REGISTER_AES_2(AES128 ## name, "AES128" nameString, 16) */ \
+ /* REGISTER_AES_2(AES192 ## name, "AES192" nameString, 24) */ \
+ REGISTER_AES_2(AES256 ## name, "AES256" nameString, 32) \
+
+REGISTER_AES(CBC, "CBC")
+
+#endif
+
+}
diff --git a/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp b/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp
new file mode 100644
index 0000000..3d9e4c1
--- /dev/null
+++ b/CPP/7zip/Crypto/Pbkdf2HmacSha1.cpp
@@ -0,0 +1,48 @@
+// Pbkdf2HmacSha1.cpp
+
+#include "StdAfx.h"
+
+#include <string.h>
+
+#include "../../../C/CpuArch.h"
+
+#include "HmacSha1.h"
+#include "Pbkdf2HmacSha1.h"
+
+namespace NCrypto {
+namespace NSha1 {
+
+void Pbkdf2Hmac(const Byte *pwd, size_t pwdSize,
+ const Byte *salt, size_t saltSize,
+ UInt32 numIterations,
+ Byte *key, size_t keySize)
+{
+ MY_ALIGN (16)
+ CHmac baseCtx;
+ baseCtx.SetKey(pwd, pwdSize);
+
+ for (UInt32 i = 1; keySize != 0; i++)
+ {
+ MY_ALIGN (16)
+ CHmac ctx;
+ ctx = baseCtx;
+ ctx.Update(salt, saltSize);
+
+ MY_ALIGN (16)
+ UInt32 u[kNumDigestWords];
+ SetBe32(u, i)
+
+ ctx.Update((const Byte *)u, 4);
+ ctx.Final((Byte *)u);
+
+ ctx = baseCtx;
+ ctx.GetLoopXorDigest1((void *)u, numIterations - 1);
+
+ const unsigned curSize = (keySize < kDigestSize) ? (unsigned)keySize : kDigestSize;
+ memcpy(key, (const Byte *)u, curSize);
+ key += curSize;
+ keySize -= curSize;
+ }
+}
+
+}}
diff --git a/CPP/7zip/Crypto/Pbkdf2HmacSha1.h b/CPP/7zip/Crypto/Pbkdf2HmacSha1.h
new file mode 100644
index 0000000..89cbe41
--- /dev/null
+++ b/CPP/7zip/Crypto/Pbkdf2HmacSha1.h
@@ -0,0 +1,19 @@
+// Pbkdf2HmacSha1.h
+// Password-Based Key Derivation Function (RFC 2898, PKCS #5) based on HMAC-SHA-1
+
+#ifndef ZIP7_INC_CRYPTO_PBKDF2_HMAC_SHA1_H
+#define ZIP7_INC_CRYPTO_PBKDF2_HMAC_SHA1_H
+
+#include <stddef.h>
+
+#include "../../Common/MyTypes.h"
+
+namespace NCrypto {
+namespace NSha1 {
+
+void Pbkdf2Hmac(const Byte *pwd, size_t pwdSize, const Byte *salt, size_t saltSize,
+ UInt32 numIterations, Byte *key, size_t keySize);
+
+}}
+
+#endif
diff --git a/CPP/7zip/Crypto/RandGen.cpp b/CPP/7zip/Crypto/RandGen.cpp
index 791275f..05a6c06 100644
--- a/CPP/7zip/Crypto/RandGen.cpp
+++ b/CPP/7zip/Crypto/RandGen.cpp
@@ -1,233 +1,241 @@
-// RandGen.cpp
-
-#include "StdAfx.h"
-
-#include "RandGen.h"
-
-#ifndef USE_STATIC_SYSTEM_RAND
-
-#ifndef _7ZIP_ST
-#include "../../Windows/Synchronization.h"
-#endif
-
-
-#ifdef _WIN32
-
-#ifdef _WIN64
-#define USE_STATIC_RtlGenRandom
-#endif
-
-#ifdef USE_STATIC_RtlGenRandom
-
-#include <ntsecapi.h>
-
-EXTERN_C_BEGIN
-#ifndef RtlGenRandom
- #define RtlGenRandom SystemFunction036
- BOOLEAN WINAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength);
-#endif
-EXTERN_C_END
-
-#else
-EXTERN_C_BEGIN
-typedef BOOLEAN (WINAPI * Func_RtlGenRandom)(PVOID RandomBuffer, ULONG RandomBufferLength);
-EXTERN_C_END
-#endif
-
-
-#else
-#include <unistd.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#define USE_POSIX_TIME
-#define USE_POSIX_TIME2
-#endif
-
-#ifdef USE_POSIX_TIME
-#include <time.h>
-#ifdef USE_POSIX_TIME2
-#include <sys/time.h>
-#endif
-#endif
-
-// The seed and first generated data block depend from processID,
-// theadID, timer and system random generator, if available.
-// Other generated data blocks depend from previous state
-
-#define HASH_UPD(x) Sha256_Update(&hash, (const Byte *)&x, sizeof(x));
-
-void CRandomGenerator::Init()
-{
- CSha256 hash;
- Sha256_Init(&hash);
-
- unsigned numIterations = 1000;
-
- {
- #ifndef UNDER_CE
- const unsigned kNumIterations_Small = 100;
- const unsigned kBufSize = 32;
- Byte buf[kBufSize];
- #endif
-
- #ifdef _WIN32
-
- DWORD w = ::GetCurrentProcessId();
- HASH_UPD(w);
- w = ::GetCurrentThreadId();
- HASH_UPD(w);
-
- #ifdef UNDER_CE
- /*
- if (CeGenRandom(kBufSize, buf))
- {
- numIterations = kNumIterations_Small;
- Sha256_Update(&hash, buf, kBufSize);
- }
- */
- #elif defined(USE_STATIC_RtlGenRandom)
- if (RtlGenRandom(buf, kBufSize))
- {
- numIterations = kNumIterations_Small;
- Sha256_Update(&hash, buf, kBufSize);
- }
- #else
- {
- HMODULE hModule = ::LoadLibrary(TEXT("Advapi32.dll"));
- if (hModule)
- {
- // SystemFunction036() is real name of RtlGenRandom() function
- Func_RtlGenRandom my_RtlGenRandom = (Func_RtlGenRandom)GetProcAddress(hModule, "SystemFunction036");
- if (my_RtlGenRandom)
- {
- if (my_RtlGenRandom(buf, kBufSize))
- {
- numIterations = kNumIterations_Small;
- Sha256_Update(&hash, buf, kBufSize);
- }
- }
- ::FreeLibrary(hModule);
- }
- }
- #endif
-
- #else
-
- pid_t pid = getpid();
- HASH_UPD(pid);
- pid = getppid();
- HASH_UPD(pid);
-
- {
- int f = open("/dev/urandom", O_RDONLY);
- unsigned numBytes = kBufSize;
- if (f >= 0)
- {
- do
- {
- int n = read(f, buf, numBytes);
- if (n <= 0)
- break;
- Sha256_Update(&hash, buf, n);
- numBytes -= n;
- }
- while (numBytes);
- close(f);
- if (numBytes == 0)
- numIterations = kNumIterations_Small;
- }
- }
- /*
- {
- int n = getrandom(buf, kBufSize, 0);
- if (n > 0)
- {
- Sha256_Update(&hash, buf, n);
- if (n == kBufSize)
- numIterations = kNumIterations_Small;
- }
- }
- */
-
- #endif
- }
-
- #ifdef _DEBUG
- numIterations = 2;
- #endif
-
- do
- {
- #ifdef _WIN32
- LARGE_INTEGER v;
- if (::QueryPerformanceCounter(&v))
- HASH_UPD(v.QuadPart);
- #endif
-
- #ifdef USE_POSIX_TIME
- #ifdef USE_POSIX_TIME2
- timeval v;
- if (gettimeofday(&v, 0) == 0)
- {
- HASH_UPD(v.tv_sec);
- HASH_UPD(v.tv_usec);
- }
- #endif
- time_t v2 = time(NULL);
- HASH_UPD(v2);
- #endif
-
- #ifdef _WIN32
- DWORD tickCount = ::GetTickCount();
- HASH_UPD(tickCount);
- #endif
-
- for (unsigned j = 0; j < 100; j++)
- {
- Sha256_Final(&hash, _buff);
- Sha256_Init(&hash);
- Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
- }
- }
- while (--numIterations);
-
- Sha256_Final(&hash, _buff);
- _needInit = false;
-}
-
-#ifndef _7ZIP_ST
- static NWindows::NSynchronization::CCriticalSection g_CriticalSection;
- #define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
-#else
- #define MT_LOCK
-#endif
-
-void CRandomGenerator::Generate(Byte *data, unsigned size)
-{
- MT_LOCK
-
- if (_needInit)
- Init();
- while (size != 0)
- {
- CSha256 hash;
-
- Sha256_Init(&hash);
- Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
- Sha256_Final(&hash, _buff);
-
- Sha256_Init(&hash);
- UInt32 salt = 0xF672ABD1;
- HASH_UPD(salt);
- Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
- Byte buff[SHA256_DIGEST_SIZE];
- Sha256_Final(&hash, buff);
- for (unsigned i = 0; i < SHA256_DIGEST_SIZE && size != 0; i++, size--)
- *data++ = buff[i];
- }
-}
-
-CRandomGenerator g_RandomGenerator;
-
-#endif
+// RandGen.cpp
+
+#include "StdAfx.h"
+
+#include "RandGen.h"
+
+#ifndef USE_STATIC_SYSTEM_RAND
+
+#ifndef Z7_ST
+#include "../../Windows/Synchronization.h"
+#endif
+
+
+#ifdef _WIN32
+
+#ifdef _WIN64
+#define USE_STATIC_RtlGenRandom
+#endif
+
+#ifdef USE_STATIC_RtlGenRandom
+
+// #include <NTSecAPI.h>
+
+EXTERN_C_BEGIN
+#ifndef RtlGenRandom
+ #define RtlGenRandom SystemFunction036
+ BOOLEAN WINAPI RtlGenRandom(PVOID RandomBuffer, ULONG RandomBufferLength);
+#endif
+EXTERN_C_END
+
+#else
+EXTERN_C_BEGIN
+typedef BOOLEAN (WINAPI * Func_RtlGenRandom)(PVOID RandomBuffer, ULONG RandomBufferLength);
+EXTERN_C_END
+#endif
+
+
+#else
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#define USE_POSIX_TIME
+#define USE_POSIX_TIME2
+#endif
+
+#ifdef USE_POSIX_TIME
+#include <time.h>
+#ifdef USE_POSIX_TIME2
+#include <sys/time.h>
+#endif
+#endif
+
+// The seed and first generated data block depend from processID,
+// theadID, timer and system random generator, if available.
+// Other generated data blocks depend from previous state
+
+#define HASH_UPD(x) Sha256_Update(&hash, (const Byte *)&x, sizeof(x));
+
+void CRandomGenerator::Init()
+{
+ MY_ALIGN (16)
+ CSha256 hash;
+ Sha256_Init(&hash);
+
+ unsigned numIterations = 1000;
+
+ {
+ #ifndef UNDER_CE
+ const unsigned kNumIterations_Small = 100;
+ const unsigned kBufSize = 32;
+ MY_ALIGN (16)
+ Byte buf[kBufSize];
+ #endif
+
+ #ifdef _WIN32
+
+ DWORD w = ::GetCurrentProcessId();
+ HASH_UPD(w)
+ w = ::GetCurrentThreadId();
+ HASH_UPD(w)
+
+ #ifdef UNDER_CE
+ /*
+ if (CeGenRandom(kBufSize, buf))
+ {
+ numIterations = kNumIterations_Small;
+ Sha256_Update(&hash, buf, kBufSize);
+ }
+ */
+ #elif defined(USE_STATIC_RtlGenRandom)
+ if (RtlGenRandom(buf, kBufSize))
+ {
+ numIterations = kNumIterations_Small;
+ Sha256_Update(&hash, buf, kBufSize);
+ }
+ #else
+ {
+ const HMODULE hModule = ::LoadLibrary(TEXT("advapi32.dll"));
+ if (hModule)
+ {
+ // SystemFunction036() is real name of RtlGenRandom() function
+ const
+ Func_RtlGenRandom
+ my_RtlGenRandom = Z7_GET_PROC_ADDRESS(
+ Func_RtlGenRandom, hModule, "SystemFunction036");
+ if (my_RtlGenRandom)
+ {
+ if (my_RtlGenRandom(buf, kBufSize))
+ {
+ numIterations = kNumIterations_Small;
+ Sha256_Update(&hash, buf, kBufSize);
+ }
+ }
+ ::FreeLibrary(hModule);
+ }
+ }
+ #endif
+
+ #else
+
+ pid_t pid = getpid();
+ HASH_UPD(pid)
+ pid = getppid();
+ HASH_UPD(pid)
+
+ {
+ int f = open("/dev/urandom", O_RDONLY);
+ unsigned numBytes = kBufSize;
+ if (f >= 0)
+ {
+ do
+ {
+ ssize_t n = read(f, buf, numBytes);
+ if (n <= 0)
+ break;
+ Sha256_Update(&hash, buf, (size_t)n);
+ numBytes -= (unsigned)n;
+ }
+ while (numBytes);
+ close(f);
+ if (numBytes == 0)
+ numIterations = kNumIterations_Small;
+ }
+ }
+ /*
+ {
+ int n = getrandom(buf, kBufSize, 0);
+ if (n > 0)
+ {
+ Sha256_Update(&hash, buf, n);
+ if (n == kBufSize)
+ numIterations = kNumIterations_Small;
+ }
+ }
+ */
+
+ #endif
+ }
+
+ #ifdef _DEBUG
+ numIterations = 2;
+ #endif
+
+ do
+ {
+ #ifdef _WIN32
+ LARGE_INTEGER v;
+ if (::QueryPerformanceCounter(&v))
+ HASH_UPD(v.QuadPart)
+ #endif
+
+ #ifdef USE_POSIX_TIME
+ #ifdef USE_POSIX_TIME2
+ timeval v;
+ if (gettimeofday(&v, NULL) == 0)
+ {
+ HASH_UPD(v.tv_sec)
+ HASH_UPD(v.tv_usec)
+ }
+ #endif
+ const time_t v2 = time(NULL);
+ HASH_UPD(v2)
+ #endif
+
+ #ifdef _WIN32
+ const DWORD tickCount = ::GetTickCount();
+ HASH_UPD(tickCount)
+ #endif
+
+ for (unsigned j = 0; j < 100; j++)
+ {
+ Sha256_Final(&hash, _buff);
+ Sha256_Init(&hash);
+ Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
+ }
+ }
+ while (--numIterations);
+
+ Sha256_Final(&hash, _buff);
+ _needInit = false;
+}
+
+#ifndef Z7_ST
+ static NWindows::NSynchronization::CCriticalSection g_CriticalSection;
+ #define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
+#else
+ #define MT_LOCK
+#endif
+
+void CRandomGenerator::Generate(Byte *data, unsigned size)
+{
+ MT_LOCK
+
+ if (_needInit)
+ Init();
+ while (size != 0)
+ {
+ MY_ALIGN (16)
+ CSha256 hash;
+
+ Sha256_Init(&hash);
+ Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
+ Sha256_Final(&hash, _buff);
+
+ Sha256_Init(&hash);
+ UInt32 salt = 0xF672ABD1;
+ HASH_UPD(salt)
+ Sha256_Update(&hash, _buff, SHA256_DIGEST_SIZE);
+ MY_ALIGN (16)
+ Byte buff[SHA256_DIGEST_SIZE];
+ Sha256_Final(&hash, buff);
+ for (unsigned i = 0; i < SHA256_DIGEST_SIZE && size != 0; i++, size--)
+ *data++ = buff[i];
+ }
+}
+
+MY_ALIGN (16)
+CRandomGenerator g_RandomGenerator;
+
+#endif
diff --git a/CPP/7zip/Crypto/RandGen.h b/CPP/7zip/Crypto/RandGen.h
index dc5a338..3bd69ec 100644
--- a/CPP/7zip/Crypto/RandGen.h
+++ b/CPP/7zip/Crypto/RandGen.h
@@ -1,40 +1,41 @@
-// RandGen.h
-
-#ifndef __CRYPTO_RAND_GEN_H
-#define __CRYPTO_RAND_GEN_H
-
-#include "../../../C/Sha256.h"
-
-#ifdef _WIN64
-// #define USE_STATIC_SYSTEM_RAND
-#endif
-
-#ifdef USE_STATIC_SYSTEM_RAND
-
-#ifdef _WIN32
-#include <ntsecapi.h>
-#define MY_RAND_GEN(data, size) RtlGenRandom(data, size)
-#else
-#define MY_RAND_GEN(data, size) getrandom(data, size, 0)
-#endif
-
-#else
-
-class CRandomGenerator
-{
- Byte _buff[SHA256_DIGEST_SIZE];
- bool _needInit;
-
- void Init();
-public:
- CRandomGenerator(): _needInit(true) {};
- void Generate(Byte *data, unsigned size);
-};
-
-extern CRandomGenerator g_RandomGenerator;
-
-#define MY_RAND_GEN(data, size) g_RandomGenerator.Generate(data, size)
-
-#endif
-
-#endif
+// RandGen.h
+
+#ifndef ZIP7_INC_CRYPTO_RAND_GEN_H
+#define ZIP7_INC_CRYPTO_RAND_GEN_H
+
+#include "../../../C/Sha256.h"
+
+#ifdef _WIN64
+// #define USE_STATIC_SYSTEM_RAND
+#endif
+
+#ifdef USE_STATIC_SYSTEM_RAND
+
+#ifdef _WIN32
+#include <ntsecapi.h>
+#define MY_RAND_GEN(data, size) RtlGenRandom(data, size)
+#else
+#define MY_RAND_GEN(data, size) getrandom(data, size, 0)
+#endif
+
+#else
+
+class CRandomGenerator
+{
+ Byte _buff[SHA256_DIGEST_SIZE];
+ bool _needInit;
+
+ void Init();
+public:
+ CRandomGenerator(): _needInit(true) {}
+ void Generate(Byte *data, unsigned size);
+};
+
+MY_ALIGN (16)
+extern CRandomGenerator g_RandomGenerator;
+
+#define MY_RAND_GEN(data, size) g_RandomGenerator.Generate(data, size)
+
+#endif
+
+#endif
diff --git a/CPP/7zip/Crypto/Rar20Crypto.cpp b/CPP/7zip/Crypto/Rar20Crypto.cpp
new file mode 100644
index 0000000..8e55763
--- /dev/null
+++ b/CPP/7zip/Crypto/Rar20Crypto.cpp
@@ -0,0 +1,130 @@
+// Crypto/Rar20Crypto.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+#include "../../../C/CpuArch.h"
+#include "../../../C/RotateDefs.h"
+
+#include "Rar20Crypto.h"
+
+namespace NCrypto {
+namespace NRar2 {
+
+static const unsigned kNumRounds = 32;
+
+static const Byte g_InitSubstTable[256] = {
+ 215, 19,149, 35, 73,197,192,205,249, 28, 16,119, 48,221, 2, 42,
+ 232, 1,177,233, 14, 88,219, 25,223,195,244, 90, 87,239,153,137,
+ 255,199,147, 70, 92, 66,246, 13,216, 40, 62, 29,217,230, 86, 6,
+ 71, 24,171,196,101,113,218,123, 93, 91,163,178,202, 67, 44,235,
+ 107,250, 75,234, 49,167,125,211, 83,114,157,144, 32,193,143, 36,
+ 158,124,247,187, 89,214,141, 47,121,228, 61,130,213,194,174,251,
+ 97,110, 54,229,115, 57,152, 94,105,243,212, 55,209,245, 63, 11,
+ 164,200, 31,156, 81,176,227, 21, 76, 99,139,188,127, 17,248, 51,
+ 207,120,189,210, 8,226, 41, 72,183,203,135,165,166, 60, 98, 7,
+ 122, 38,155,170, 69,172,252,238, 39,134, 59,128,236, 27,240, 80,
+ 131, 3, 85,206,145, 79,154,142,159,220,201,133, 74, 64, 20,129,
+ 224,185,138,103,173,182, 43, 34,254, 82,198,151,231,180, 58, 10,
+ 118, 26,102, 12, 50,132, 22,191,136,111,162,179, 45, 4,148,108,
+ 161, 56, 78,126,242,222, 15,175,146, 23, 33,241,181,190, 77,225,
+ 0, 46,169,186, 68, 95,237, 65, 53,208,253,168, 9, 18,100, 52,
+ 116,184,160, 96,109, 37, 30,106,140,104,150, 5,204,117,112, 84
+};
+
+void CData::UpdateKeys(const Byte *data)
+{
+ for (unsigned i = 0; i < 16; i += 4)
+ for (unsigned j = 0; j < 4; j++)
+ Keys[j] ^= g_CrcTable[data[i + j]];
+}
+
+static inline void Swap(Byte &b1, Byte &b2)
+{
+ Byte b = b1;
+ b1 = b2;
+ b2 = b;
+}
+
+void CData::SetPassword(const Byte *data, unsigned size)
+{
+ Keys[0] = 0xD3A3B879L;
+ Keys[1] = 0x3F6D12F7L;
+ Keys[2] = 0x7515A235L;
+ Keys[3] = 0xA4E7F123L;
+
+ Byte psw[128];
+ Z7_memset_0_ARRAY(psw);
+ if (size != 0)
+ {
+ if (size >= sizeof(psw))
+ size = sizeof(psw) - 1;
+ memcpy(psw, data, size);
+ }
+
+ memcpy(SubstTable, g_InitSubstTable, sizeof(SubstTable));
+
+ for (unsigned j = 0; j < 256; j++)
+ for (unsigned i = 0; i < size; i += 2)
+ {
+ unsigned n1 = (Byte)g_CrcTable[(psw[i] - j) & 0xFF];
+ unsigned n2 = (Byte)g_CrcTable[(psw[(size_t)i + 1] + j) & 0xFF];
+ for (unsigned k = 1; (n1 & 0xFF) != n2; n1++, k++)
+ Swap(SubstTable[n1 & 0xFF], SubstTable[(n1 + i + k) & 0xFF]);
+ }
+
+ for (unsigned i = 0; i < size; i += 16)
+ EncryptBlock(psw + i);
+}
+
+void CData::CryptBlock(Byte *buf, bool encrypt)
+{
+ Byte inBuf[16];
+ UInt32 A, B, C, D;
+
+ A = GetUi32(buf + 0) ^ Keys[0];
+ B = GetUi32(buf + 4) ^ Keys[1];
+ C = GetUi32(buf + 8) ^ Keys[2];
+ D = GetUi32(buf + 12) ^ Keys[3];
+
+ if (!encrypt)
+ memcpy(inBuf, buf, sizeof(inBuf));
+
+ for (unsigned i = 0; i < kNumRounds; i++)
+ {
+ UInt32 key = Keys[(encrypt ? i : (kNumRounds - 1 - i)) & 3];
+ UInt32 TA = A ^ SubstLong((C + rotlFixed(D, 11)) ^ key);
+ UInt32 TB = B ^ SubstLong((D ^ rotlFixed(C, 17)) + key);
+ A = C; C = TA;
+ B = D; D = TB;
+ }
+
+ SetUi32(buf + 0, C ^ Keys[0])
+ SetUi32(buf + 4, D ^ Keys[1])
+ SetUi32(buf + 8, A ^ Keys[2])
+ SetUi32(buf + 12, B ^ Keys[3])
+
+ UpdateKeys(encrypt ? buf : inBuf);
+}
+
+Z7_COM7F_IMF(CDecoder::Init())
+{
+ return S_OK;
+}
+
+static const UInt32 kBlockSize = 16;
+
+Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size))
+{
+ if (size == 0)
+ return 0;
+ if (size < kBlockSize)
+ return kBlockSize;
+ size -= kBlockSize;
+ UInt32 i;
+ for (i = 0; i <= size; i += kBlockSize)
+ DecryptBlock(data + i);
+ return i;
+}
+
+}}
diff --git a/CPP/7zip/Crypto/Rar20Crypto.h b/CPP/7zip/Crypto/Rar20Crypto.h
new file mode 100644
index 0000000..8550718
--- /dev/null
+++ b/CPP/7zip/Crypto/Rar20Crypto.h
@@ -0,0 +1,54 @@
+// Crypto/Rar20Crypto.h
+
+#ifndef ZIP7_INC_CRYPTO_RAR20_CRYPTO_H
+#define ZIP7_INC_CRYPTO_RAR20_CRYPTO_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+
+namespace NCrypto {
+namespace NRar2 {
+
+/* ICompressFilter::Init() does nothing for this filter.
+ Call SetPassword() to initialize filter. */
+
+class CData
+{
+ Byte SubstTable[256];
+ UInt32 Keys[4];
+
+ UInt32 SubstLong(UInt32 t) const
+ {
+ return (UInt32)SubstTable[(unsigned)t & 255]
+ | ((UInt32)SubstTable[(unsigned)(t >> 8) & 255] << 8)
+ | ((UInt32)SubstTable[(unsigned)(t >> 16) & 255] << 16)
+ | ((UInt32)SubstTable[(unsigned)(t >> 24) ] << 24);
+ }
+ void UpdateKeys(const Byte *data);
+ void CryptBlock(Byte *buf, bool encrypt);
+public:
+ ~CData() { Wipe(); }
+ void Wipe()
+ {
+ Z7_memset_0_ARRAY(SubstTable);
+ Z7_memset_0_ARRAY(Keys);
+ }
+
+ void EncryptBlock(Byte *buf) { CryptBlock(buf, true); }
+ void DecryptBlock(Byte *buf) { CryptBlock(buf, false); }
+ void SetPassword(const Byte *password, unsigned passwordLen);
+};
+
+class CDecoder Z7_final:
+ public ICompressFilter,
+ public CMyUnknownImp,
+ public CData
+{
+ Z7_COM_UNKNOWN_IMP_0
+ Z7_IFACE_COM7_IMP(ICompressFilter)
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Crypto/Rar5Aes.cpp b/CPP/7zip/Crypto/Rar5Aes.cpp
new file mode 100644
index 0000000..26c6100
--- /dev/null
+++ b/CPP/7zip/Crypto/Rar5Aes.cpp
@@ -0,0 +1,265 @@
+// Crypto/Rar5Aes.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#ifndef Z7_ST
+#include "../../Windows/Synchronization.h"
+#endif
+
+#include "Rar5Aes.h"
+#include "HmacSha256.h"
+
+namespace NCrypto {
+namespace NRar5 {
+
+static const unsigned kNumIterationsLog_Max = 24;
+
+static const unsigned kPswCheckCsumSize = 4;
+static const unsigned kCheckSize = kPswCheckSize + kPswCheckCsumSize;
+
+CKey::CKey():
+ _needCalc(true),
+ _numIterationsLog(0)
+{
+ for (unsigned i = 0; i < sizeof(_salt); i++)
+ _salt[i] = 0;
+}
+
+CDecoder::CDecoder(): CAesCbcDecoder(kAesKeySize) {}
+
+static unsigned ReadVarInt(const Byte *p, unsigned maxSize, UInt64 *val)
+{
+ *val = 0;
+
+ for (unsigned i = 0; i < maxSize && i < 10;)
+ {
+ Byte b = p[i];
+ *val |= (UInt64)(b & 0x7F) << (7 * i);
+ i++;
+ if ((b & 0x80) == 0)
+ return i;
+ }
+ return 0;
+}
+
+HRESULT CDecoder::SetDecoderProps(const Byte *p, unsigned size, bool includeIV, bool isService)
+{
+ UInt64 Version;
+
+ unsigned num = ReadVarInt(p, size, &Version);
+ if (num == 0)
+ return E_NOTIMPL;
+ p += num;
+ size -= num;
+
+ if (Version != 0)
+ return E_NOTIMPL;
+
+ num = ReadVarInt(p, size, &Flags);
+ if (num == 0)
+ return E_NOTIMPL;
+ p += num;
+ size -= num;
+
+ bool isCheck = IsThereCheck();
+ if (size != 1 + kSaltSize + (includeIV ? AES_BLOCK_SIZE : 0) + (unsigned)(isCheck ? kCheckSize : 0))
+ return E_NOTIMPL;
+
+ if (_numIterationsLog != p[0])
+ {
+ _numIterationsLog = p[0];
+ _needCalc = true;
+ }
+
+ p++;
+
+ if (memcmp(_salt, p, kSaltSize) != 0)
+ {
+ memcpy(_salt, p, kSaltSize);
+ _needCalc = true;
+ }
+
+ p += kSaltSize;
+
+ if (includeIV)
+ {
+ memcpy(_iv, p, AES_BLOCK_SIZE);
+ p += AES_BLOCK_SIZE;
+ }
+
+ _canCheck = true;
+
+ if (isCheck)
+ {
+ memcpy(_check, p, kPswCheckSize);
+ CSha256 sha;
+ Byte digest[SHA256_DIGEST_SIZE];
+ Sha256_Init(&sha);
+ Sha256_Update(&sha, _check, kPswCheckSize);
+ Sha256_Final(&sha, digest);
+ _canCheck = (memcmp(digest, p + kPswCheckSize, kPswCheckCsumSize) == 0);
+ if (_canCheck && isService)
+ {
+ // There was bug in RAR 5.21- : PswCheck field in service records ("QO") contained zeros.
+ // so we disable password checking for such bad records.
+ _canCheck = false;
+ for (unsigned i = 0; i < kPswCheckSize; i++)
+ if (p[i] != 0)
+ {
+ _canCheck = true;
+ break;
+ }
+ }
+ }
+
+ return (_numIterationsLog <= kNumIterationsLog_Max ? S_OK : E_NOTIMPL);
+}
+
+
+void CDecoder::SetPassword(const Byte *data, size_t size)
+{
+ if (size != _password.Size() || memcmp(data, _password, size) != 0)
+ {
+ _needCalc = true;
+ _password.Wipe();
+ _password.CopyFrom(data, size);
+ }
+}
+
+
+Z7_COM7F_IMF(CDecoder::Init())
+{
+ CalcKey_and_CheckPassword();
+ RINOK(SetKey(_key, kAesKeySize))
+ RINOK(SetInitVector(_iv, AES_BLOCK_SIZE))
+ return CAesCoder::Init();
+}
+
+
+UInt32 CDecoder::Hmac_Convert_Crc32(UInt32 crc) const
+{
+ MY_ALIGN (16)
+ NSha256::CHmac ctx;
+ ctx.SetKey(_hashKey, NSha256::kDigestSize);
+ UInt32 v;
+ SetUi32(&v, crc)
+ ctx.Update((const Byte *)&v, 4);
+ MY_ALIGN (16)
+ UInt32 h[SHA256_NUM_DIGEST_WORDS];
+ ctx.Final((Byte *)h);
+ crc = 0;
+ for (unsigned i = 0; i < SHA256_NUM_DIGEST_WORDS; i++)
+ crc ^= (UInt32)GetUi32(h + i);
+ return crc;
+}
+
+
+void CDecoder::Hmac_Convert_32Bytes(Byte *data) const
+{
+ MY_ALIGN (16)
+ NSha256::CHmac ctx;
+ ctx.SetKey(_hashKey, NSha256::kDigestSize);
+ ctx.Update(data, NSha256::kDigestSize);
+ ctx.Final(data);
+}
+
+
+static CKey g_Key;
+
+#ifndef Z7_ST
+ static NWindows::NSynchronization::CCriticalSection g_GlobalKeyCacheCriticalSection;
+ #define MT_LOCK NWindows::NSynchronization::CCriticalSectionLock lock(g_GlobalKeyCacheCriticalSection);
+#else
+ #define MT_LOCK
+#endif
+
+bool CDecoder::CalcKey_and_CheckPassword()
+{
+ if (_needCalc)
+ {
+ {
+ MT_LOCK
+ if (!g_Key._needCalc && IsKeyEqualTo(g_Key))
+ {
+ CopyCalcedKeysFrom(g_Key);
+ _needCalc = false;
+ }
+ }
+
+ if (_needCalc)
+ {
+ Byte pswCheck[SHA256_DIGEST_SIZE];
+
+ {
+ // Pbkdf HMAC-SHA-256
+
+ MY_ALIGN (16)
+ NSha256::CHmac baseCtx;
+ baseCtx.SetKey(_password, _password.Size());
+
+ NSha256::CHmac ctx = baseCtx;
+ ctx.Update(_salt, sizeof(_salt));
+
+ MY_ALIGN (16)
+ Byte u[NSha256::kDigestSize];
+ MY_ALIGN (16)
+ Byte key[NSha256::kDigestSize];
+
+ u[0] = 0;
+ u[1] = 0;
+ u[2] = 0;
+ u[3] = 1;
+
+ ctx.Update(u, 4);
+ ctx.Final(u);
+
+ memcpy(key, u, NSha256::kDigestSize);
+
+ UInt32 numIterations = ((UInt32)1 << _numIterationsLog) - 1;
+
+ for (unsigned i = 0; i < 3; i++)
+ {
+ UInt32 j = numIterations;
+
+ for (; j != 0; j--)
+ {
+ ctx = baseCtx;
+ ctx.Update(u, NSha256::kDigestSize);
+ ctx.Final(u);
+ for (unsigned s = 0; s < NSha256::kDigestSize; s++)
+ key[s] ^= u[s];
+ }
+
+ // RAR uses additional iterations for additional keys
+ memcpy((i == 0 ? _key : (i == 1 ? _hashKey : pswCheck)), key, NSha256::kDigestSize);
+ numIterations = 16;
+ }
+ }
+
+ {
+ unsigned i;
+
+ for (i = 0; i < kPswCheckSize; i++)
+ _check_Calced[i] = pswCheck[i];
+
+ for (i = kPswCheckSize; i < SHA256_DIGEST_SIZE; i++)
+ _check_Calced[i & (kPswCheckSize - 1)] ^= pswCheck[i];
+ }
+
+ _needCalc = false;
+
+ {
+ MT_LOCK
+ g_Key = *this;
+ }
+ }
+ }
+
+ if (IsThereCheck() && _canCheck)
+ return (memcmp(_check_Calced, _check, kPswCheckSize) == 0);
+ return true;
+}
+
+}}
diff --git a/CPP/7zip/Crypto/Rar5Aes.h b/CPP/7zip/Crypto/Rar5Aes.h
new file mode 100644
index 0000000..3cd7992
--- /dev/null
+++ b/CPP/7zip/Crypto/Rar5Aes.h
@@ -0,0 +1,98 @@
+// Crypto/Rar5Aes.h
+
+#ifndef ZIP7_INC_CRYPTO_RAR5_AES_H
+#define ZIP7_INC_CRYPTO_RAR5_AES_H
+
+#include "../../../C/Sha256.h"
+
+#include "../../Common/MyBuffer.h"
+
+#include "MyAes.h"
+
+namespace NCrypto {
+namespace NRar5 {
+
+const unsigned kSaltSize = 16;
+const unsigned kPswCheckSize = 8;
+const unsigned kAesKeySize = 32;
+
+namespace NCryptoFlags
+{
+ const unsigned kPswCheck = 1 << 0;
+ const unsigned kUseMAC = 1 << 1;
+}
+
+struct CKey
+{
+ bool _needCalc;
+
+ unsigned _numIterationsLog;
+ Byte _salt[kSaltSize];
+ CByteBuffer _password;
+
+ Byte _key[kAesKeySize];
+ Byte _check_Calced[kPswCheckSize];
+ Byte _hashKey[SHA256_DIGEST_SIZE];
+
+ void CopyCalcedKeysFrom(const CKey &k)
+ {
+ memcpy(_key, k._key, sizeof(_key));
+ memcpy(_check_Calced, k._check_Calced, sizeof(_check_Calced));
+ memcpy(_hashKey, k._hashKey, sizeof(_hashKey));
+ }
+
+ bool IsKeyEqualTo(const CKey &key)
+ {
+ return (_numIterationsLog == key._numIterationsLog
+ && memcmp(_salt, key._salt, sizeof(_salt)) == 0
+ && _password == key._password);
+ }
+
+ CKey();
+
+ void Wipe()
+ {
+ _password.Wipe();
+ Z7_memset_0_ARRAY(_salt);
+ Z7_memset_0_ARRAY(_key);
+ Z7_memset_0_ARRAY(_check_Calced);
+ Z7_memset_0_ARRAY(_hashKey);
+ }
+
+#ifdef Z7_CPP_IS_SUPPORTED_default
+ // CKey(const CKey &) = default;
+ CKey& operator =(const CKey &) = default;
+#endif
+ ~CKey() { Wipe(); }
+};
+
+
+class CDecoder Z7_final:
+ public CAesCbcDecoder,
+ public CKey
+{
+ Byte _check[kPswCheckSize];
+ bool _canCheck;
+ UInt64 Flags;
+
+ bool IsThereCheck() const { return ((Flags & NCryptoFlags::kPswCheck) != 0); }
+public:
+ Byte _iv[AES_BLOCK_SIZE];
+
+ CDecoder();
+
+ Z7_COM7F_IMP(Init())
+
+ void SetPassword(const Byte *data, size_t size);
+ HRESULT SetDecoderProps(const Byte *data, unsigned size, bool includeIV, bool isService);
+
+ bool CalcKey_and_CheckPassword();
+
+ bool UseMAC() const { return (Flags & NCryptoFlags::kUseMAC) != 0; }
+ UInt32 Hmac_Convert_Crc32(UInt32 crc) const;
+ void Hmac_Convert_32Bytes(Byte *data) const;
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Crypto/RarAes.cpp b/CPP/7zip/Crypto/RarAes.cpp
new file mode 100644
index 0000000..878ea3a
--- /dev/null
+++ b/CPP/7zip/Crypto/RarAes.cpp
@@ -0,0 +1,194 @@
+// Crypto/RarAes.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+#include "../../../C/RotateDefs.h"
+
+#include "RarAes.h"
+#include "Sha1Cls.h"
+
+namespace NCrypto {
+namespace NRar3 {
+
+CDecoder::CDecoder():
+ CAesCbcDecoder(kAesKeySize),
+ _thereIsSalt(false),
+ _needCalc(true)
+ // _rar350Mode(false)
+{
+ for (unsigned i = 0; i < sizeof(_salt); i++)
+ _salt[i] = 0;
+}
+
+HRESULT CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size)
+{
+ bool prev = _thereIsSalt;
+ _thereIsSalt = false;
+ if (size == 0)
+ {
+ if (!_needCalc && prev)
+ _needCalc = true;
+ return S_OK;
+ }
+ if (size < 8)
+ return E_INVALIDARG;
+ _thereIsSalt = true;
+ bool same = false;
+ if (_thereIsSalt == prev)
+ {
+ same = true;
+ if (_thereIsSalt)
+ {
+ for (unsigned i = 0; i < sizeof(_salt); i++)
+ if (_salt[i] != data[i])
+ {
+ same = false;
+ break;
+ }
+ }
+ }
+ for (unsigned i = 0; i < sizeof(_salt); i++)
+ _salt[i] = data[i];
+ if (!_needCalc && !same)
+ _needCalc = true;
+ return S_OK;
+}
+
+static const unsigned kPasswordLen_Bytes_MAX = 127 * 2;
+
+void CDecoder::SetPassword(const Byte *data, unsigned size)
+{
+ if (size > kPasswordLen_Bytes_MAX)
+ size = kPasswordLen_Bytes_MAX;
+ bool same = false;
+ if (size == _password.Size())
+ {
+ same = true;
+ for (UInt32 i = 0; i < size; i++)
+ if (data[i] != _password[i])
+ {
+ same = false;
+ break;
+ }
+ }
+ if (!_needCalc && !same)
+ _needCalc = true;
+ _password.Wipe();
+ _password.CopyFrom(data, (size_t)size);
+}
+
+Z7_COM7F_IMF(CDecoder::Init())
+{
+ CalcKey();
+ RINOK(SetKey(_key, kAesKeySize))
+ RINOK(SetInitVector(_iv, AES_BLOCK_SIZE))
+ return CAesCoder::Init();
+}
+
+
+// if (password_size_in_bytes + SaltSize > 64),
+// the original rar code updates password_with_salt buffer
+// with some generated data from SHA1 code.
+
+// #define RAR_SHA1_REDUCE
+
+#ifdef RAR_SHA1_REDUCE
+ #define kNumW 16
+ #define WW(i) W[(i)&15]
+#else
+ #define kNumW 80
+ #define WW(i) W[i]
+#endif
+
+static void UpdatePswDataSha1(Byte *data)
+{
+ UInt32 W[kNumW];
+ size_t i;
+
+ for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++)
+ W[i] = GetBe32(data + i * 4);
+
+ for (i = 16; i < 80; i++)
+ {
+ WW(i) = rotlFixed(WW((i)-3) ^ WW((i)-8) ^ WW((i)-14) ^ WW((i)-16), 1);
+ }
+
+ for (i = 0; i < SHA1_NUM_BLOCK_WORDS; i++)
+ {
+ SetUi32(data + i * 4, W[kNumW - SHA1_NUM_BLOCK_WORDS + i])
+ }
+}
+
+
+void CDecoder::CalcKey()
+{
+ if (!_needCalc)
+ return;
+
+ const unsigned kSaltSize = 8;
+
+ Byte buf[kPasswordLen_Bytes_MAX + kSaltSize];
+
+ if (_password.Size() != 0)
+ memcpy(buf, _password, _password.Size());
+
+ size_t rawSize = _password.Size();
+
+ if (_thereIsSalt)
+ {
+ memcpy(buf + rawSize, _salt, kSaltSize);
+ rawSize += kSaltSize;
+ }
+
+ MY_ALIGN (16)
+ NSha1::CContext sha;
+ sha.Init();
+
+ MY_ALIGN (16)
+ Byte digest[NSha1::kDigestSize];
+ // rar reverts hash for sha.
+ const UInt32 kNumRounds = ((UInt32)1 << 18);
+ UInt32 pos = 0;
+ UInt32 i;
+ for (i = 0; i < kNumRounds; i++)
+ {
+ sha.Update(buf, rawSize);
+ // if (_rar350Mode)
+ {
+ const UInt32 kBlockSize = 64;
+ const UInt32 endPos = (pos + (UInt32)rawSize) & ~(kBlockSize - 1);
+ if (endPos > pos + kBlockSize)
+ {
+ UInt32 curPos = pos & ~(kBlockSize - 1);
+ curPos += kBlockSize;
+ do
+ {
+ UpdatePswDataSha1(buf + (curPos - pos));
+ curPos += kBlockSize;
+ }
+ while (curPos != endPos);
+ }
+ }
+ pos += (UInt32)rawSize;
+ Byte pswNum[3] = { (Byte)i, (Byte)(i >> 8), (Byte)(i >> 16) };
+ sha.Update(pswNum, 3);
+ pos += 3;
+ if (i % (kNumRounds / 16) == 0)
+ {
+ MY_ALIGN (16)
+ NSha1::CContext shaTemp = sha;
+ shaTemp.Final(digest);
+ _iv[i / (kNumRounds / 16)] = (Byte)digest[4 * 4 + 3];
+ }
+ }
+
+ sha.Final(digest);
+ for (i = 0; i < 4; i++)
+ for (unsigned j = 0; j < 4; j++)
+ _key[i * 4 + j] = (digest[i * 4 + 3 - j]);
+
+ _needCalc = false;
+}
+
+}}
diff --git a/CPP/7zip/Crypto/RarAes.h b/CPP/7zip/Crypto/RarAes.h
new file mode 100644
index 0000000..d3c104c
--- /dev/null
+++ b/CPP/7zip/Crypto/RarAes.h
@@ -0,0 +1,54 @@
+// Crypto/RarAes.h
+
+#ifndef ZIP7_INC_CRYPTO_RAR_AES_H
+#define ZIP7_INC_CRYPTO_RAR_AES_H
+
+#include "../../../C/Aes.h"
+
+#include "../../Common/MyBuffer.h"
+
+#include "../IPassword.h"
+
+#include "MyAes.h"
+
+namespace NCrypto {
+namespace NRar3 {
+
+const unsigned kAesKeySize = 16;
+
+class CDecoder Z7_final:
+ public CAesCbcDecoder
+{
+ Byte _salt[8];
+ bool _thereIsSalt;
+ bool _needCalc;
+ // bool _rar350Mode;
+
+ CByteBuffer _password;
+
+ Byte _key[kAesKeySize];
+ Byte _iv[AES_BLOCK_SIZE];
+
+ void CalcKey();
+public:
+ Z7_COM7F_IMP(Init())
+
+ void SetPassword(const Byte *data, unsigned size);
+ HRESULT SetDecoderProperties2(const Byte *data, UInt32 size);
+
+ CDecoder();
+
+ ~CDecoder() Z7_DESTRUCTOR_override { Wipe(); }
+ void Wipe()
+ {
+ _password.Wipe();
+ Z7_memset_0_ARRAY(_salt);
+ Z7_memset_0_ARRAY(_key);
+ Z7_memset_0_ARRAY(_iv);
+ }
+ // void SetRar350Mode(bool rar350Mode) { _rar350Mode = rar350Mode; }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Crypto/Sha1Cls.h b/CPP/7zip/Crypto/Sha1Cls.h
new file mode 100644
index 0000000..56ae040
--- /dev/null
+++ b/CPP/7zip/Crypto/Sha1Cls.h
@@ -0,0 +1,37 @@
+// Crypto/Sha1Cls.h
+
+#ifndef ZIP7_INC_CRYPTO_SHA1_CLS_H
+#define ZIP7_INC_CRYPTO_SHA1_CLS_H
+
+#include "../../../C/Sha1.h"
+
+namespace NCrypto {
+namespace NSha1 {
+
+const unsigned kNumBlockWords = SHA1_NUM_BLOCK_WORDS;
+const unsigned kNumDigestWords = SHA1_NUM_DIGEST_WORDS;
+
+const unsigned kBlockSize = SHA1_BLOCK_SIZE;
+const unsigned kDigestSize = SHA1_DIGEST_SIZE;
+
+class CContext
+{
+ CSha1 _s;
+
+public:
+ void Init() throw() { Sha1_Init(&_s); }
+ void Update(const Byte *data, size_t size) throw() { Sha1_Update(&_s, data, size); }
+ void Final(Byte *digest) throw() { Sha1_Final(&_s, digest); }
+ void PrepareBlock(Byte *block, unsigned size) const throw()
+ {
+ Sha1_PrepareBlock(&_s, block, size);
+ }
+ void GetBlockDigest(const Byte *blockData, Byte *destDigest) const throw()
+ {
+ Sha1_GetBlockDigest(&_s, blockData, destDigest);
+ }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Crypto/StdAfx.h b/CPP/7zip/Crypto/StdAfx.h
index 42a088f..8086655 100644
--- a/CPP/7zip/Crypto/StdAfx.h
+++ b/CPP/7zip/Crypto/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "../../Common/Common.h"
-
-#endif
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/Crypto/WzAes.cpp b/CPP/7zip/Crypto/WzAes.cpp
new file mode 100644
index 0000000..3f2adab
--- /dev/null
+++ b/CPP/7zip/Crypto/WzAes.cpp
@@ -0,0 +1,231 @@
+// Crypto/WzAes.cpp
+/*
+This code implements Brian Gladman's scheme
+specified in "A Password Based File Encryption Utility".
+
+Note: you must include MyAes.cpp to project to initialize AES tables
+*/
+
+#include "StdAfx.h"
+
+#include "../../../C/CpuArch.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "Pbkdf2HmacSha1.h"
+#include "RandGen.h"
+#include "WzAes.h"
+
+namespace NCrypto {
+namespace NWzAes {
+
+const unsigned kAesKeySizeMax = 32;
+
+static const UInt32 kNumKeyGenIterations = 1000;
+
+Z7_COM7F_IMF(CBaseCoder::CryptoSetPassword(const Byte *data, UInt32 size))
+{
+ if (size > kPasswordSizeMax)
+ return E_INVALIDARG;
+ _key.Password.Wipe();
+ _key.Password.CopyFrom(data, (size_t)size);
+ return S_OK;
+}
+
+void CBaseCoder::Init2()
+{
+ _hmacOverCalc = 0;
+ const unsigned dkSizeMax32 = (2 * kAesKeySizeMax + kPwdVerifSize + 3) / 4;
+ Byte dk[dkSizeMax32 * 4];
+
+ const unsigned keySize = _key.GetKeySize();
+ const unsigned dkSize = 2 * keySize + ((kPwdVerifSize + 3) & ~(unsigned)3);
+
+ // for (unsigned ii = 0; ii < 1000; ii++)
+ {
+ NSha1::Pbkdf2Hmac(
+ _key.Password, _key.Password.Size(),
+ _key.Salt, _key.GetSaltSize(),
+ kNumKeyGenIterations,
+ dk, dkSize);
+ }
+
+ Hmac()->SetKey(dk + keySize, keySize);
+ memcpy(_key.PwdVerifComputed, dk + 2 * keySize, kPwdVerifSize);
+
+ // Aes_SetKey_Enc(_aes.Aes() + 8, dk, keySize);
+ // AesCtr2_Init(&_aes);
+ _aesCoderSpec->SetKeySize(keySize);
+ if (_aesCoderSpec->SetKey(dk, keySize) != S_OK) throw 2;
+ if (_aesCoderSpec->Init() != S_OK) throw 3;
+}
+
+Z7_COM7F_IMF(CBaseCoder::Init())
+{
+ return S_OK;
+}
+
+HRESULT CEncoder::WriteHeader(ISequentialOutStream *outStream)
+{
+ unsigned saltSize = _key.GetSaltSize();
+ MY_RAND_GEN(_key.Salt, saltSize);
+ Init2();
+ RINOK(WriteStream(outStream, _key.Salt, saltSize))
+ return WriteStream(outStream, _key.PwdVerifComputed, kPwdVerifSize);
+}
+
+HRESULT CEncoder::WriteFooter(ISequentialOutStream *outStream)
+{
+ MY_ALIGN (16)
+ UInt32 mac[NSha1::kNumDigestWords];
+ Hmac()->Final((Byte *)mac);
+ return WriteStream(outStream, mac, kMacSize);
+}
+
+/*
+Z7_COM7F_IMF(CDecoder::SetDecoderProperties2(const Byte *data, UInt32 size))
+{
+ if (size != 1)
+ return E_INVALIDARG;
+ _key.Init();
+ return SetKeyMode(data[0]) ? S_OK : E_INVALIDARG;
+}
+*/
+
+HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream)
+{
+ const unsigned saltSize = _key.GetSaltSize();
+ const unsigned extraSize = saltSize + kPwdVerifSize;
+ Byte temp[kSaltSizeMax + kPwdVerifSize];
+ RINOK(ReadStream_FAIL(inStream, temp, extraSize))
+ unsigned i;
+ for (i = 0; i < saltSize; i++)
+ _key.Salt[i] = temp[i];
+ for (i = 0; i < kPwdVerifSize; i++)
+ _pwdVerifFromArchive[i] = temp[saltSize + i];
+ return S_OK;
+}
+
+static inline bool CompareArrays(const Byte *p1, const Byte *p2, unsigned size)
+{
+ for (unsigned i = 0; i < size; i++)
+ if (p1[i] != p2[i])
+ return false;
+ return true;
+}
+
+bool CDecoder::Init_and_CheckPassword()
+{
+ Init2();
+ return CompareArrays(_key.PwdVerifComputed, _pwdVerifFromArchive, kPwdVerifSize);
+}
+
+HRESULT CDecoder::CheckMac(ISequentialInStream *inStream, bool &isOK)
+{
+ isOK = false;
+ MY_ALIGN (16)
+ Byte mac1[kMacSize];
+ RINOK(ReadStream_FAIL(inStream, mac1, kMacSize))
+ MY_ALIGN (16)
+ UInt32 mac2[NSha1::kNumDigestWords];
+ Hmac()->Final((Byte *)mac2);
+ isOK = CompareArrays(mac1, (const Byte *)mac2, kMacSize);
+ if (_hmacOverCalc)
+ isOK = false;
+ return S_OK;
+}
+
+/*
+
+CAesCtr2::CAesCtr2():
+ aes((4 + AES_NUM_IVMRK_WORDS) * 4)
+{
+ // offset = ((0 - (unsigned)(ptrdiff_t)aes) & 0xF) / sizeof(UInt32);
+ // first 16 bytes are buffer for last block data.
+ // so the ivAES is aligned for (Align + 16).
+}
+
+void AesCtr2_Init(CAesCtr2 *p)
+{
+ UInt32 *ctr = p->Aes() + 4;
+ unsigned i;
+ for (i = 0; i < 4; i++)
+ ctr[i] = 0;
+ p->pos = AES_BLOCK_SIZE;
+}
+
+// (size != 16 * N) is allowed only for last call
+
+void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size)
+{
+ unsigned pos = p->pos;
+ UInt32 *buf32 = p->Aes();
+ if (size == 0)
+ return;
+
+ if (pos != AES_BLOCK_SIZE)
+ {
+ const Byte *buf = (const Byte *)buf32;
+ do
+ *data++ ^= buf[pos++];
+ while (--size != 0 && pos != AES_BLOCK_SIZE);
+ }
+
+ // (size == 0 || pos == AES_BLOCK_SIZE)
+
+ if (size >= 16)
+ {
+ SizeT size2 = size >> 4;
+ g_AesCtr_Code(buf32 + 4, data, size2);
+ size2 <<= 4;
+ data += size2;
+ size -= size2;
+ // (pos == AES_BLOCK_SIZE)
+ }
+
+ // (size < 16)
+
+ if (size != 0)
+ {
+ unsigned j;
+ const Byte *buf;
+ for (j = 0; j < 4; j++)
+ buf32[j] = 0;
+ g_AesCtr_Code(buf32 + 4, (Byte *)buf32, 1);
+ buf = (const Byte *)buf32;
+ pos = 0;
+ do
+ *data++ ^= buf[pos++];
+ while (--size != 0);
+ }
+
+ p->pos = pos;
+}
+*/
+
+/* (size != 16 * N) is allowed only for last Filter() call */
+
+Z7_COM7F_IMF2(UInt32, CEncoder::Filter(Byte *data, UInt32 size))
+{
+ // AesCtr2_Code(&_aes, data, size);
+ size = _aesCoder->Filter(data, size);
+ Hmac()->Update(data, size);
+ return size;
+}
+
+Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size))
+{
+ if (size >= 16)
+ size &= ~(UInt32)15;
+ if (_hmacOverCalc < size)
+ {
+ Hmac()->Update(data + _hmacOverCalc, size - _hmacOverCalc);
+ _hmacOverCalc = size;
+ }
+ // AesCtr2_Code(&_aes, data, size);
+ size = _aesCoder->Filter(data, size);
+ _hmacOverCalc -= size;
+ return size;
+}
+
+}}
diff --git a/CPP/7zip/Crypto/WzAes.h b/CPP/7zip/Crypto/WzAes.h
new file mode 100644
index 0000000..113ec81
--- /dev/null
+++ b/CPP/7zip/Crypto/WzAes.h
@@ -0,0 +1,161 @@
+// Crypto/WzAes.h
+/*
+This code implements Brian Gladman's scheme
+specified in "A Password Based File Encryption Utility":
+ - AES encryption (128,192,256-bit) in Counter (CTR) mode.
+ - HMAC-SHA1 authentication for encrypted data (10 bytes)
+ - Keys are derived by PPKDF2(RFC2898)-HMAC-SHA1 from ASCII password and
+ Salt (saltSize = aesKeySize / 2).
+ - 2 bytes contain Password Verifier's Code
+*/
+
+#ifndef ZIP7_INC_CRYPTO_WZ_AES_H
+#define ZIP7_INC_CRYPTO_WZ_AES_H
+
+#include "../../Common/MyBuffer.h"
+
+#include "../IPassword.h"
+
+#include "HmacSha1.h"
+#include "MyAes.h"
+
+namespace NCrypto {
+namespace NWzAes {
+
+/* ICompressFilter::Init() does nothing for this filter.
+
+ Call to init:
+ Encoder:
+ CryptoSetPassword();
+ WriteHeader();
+ Decoder:
+ [CryptoSetPassword();]
+ ReadHeader();
+ [CryptoSetPassword();] Init_and_CheckPassword();
+ [CryptoSetPassword();] Init_and_CheckPassword();
+*/
+
+const UInt32 kPasswordSizeMax = 99; // 128;
+
+const unsigned kSaltSizeMax = 16;
+const unsigned kPwdVerifSize = 2;
+const unsigned kMacSize = 10;
+
+enum EKeySizeMode
+{
+ kKeySizeMode_AES128 = 1,
+ kKeySizeMode_AES192 = 2,
+ kKeySizeMode_AES256 = 3
+};
+
+struct CKeyInfo
+{
+ EKeySizeMode KeySizeMode;
+ Byte Salt[kSaltSizeMax];
+ Byte PwdVerifComputed[kPwdVerifSize];
+
+ CByteBuffer Password;
+
+ unsigned GetKeySize() const { return (8 * KeySizeMode + 8); }
+ unsigned GetSaltSize() const { return (4 * KeySizeMode + 4); }
+ unsigned GetNumSaltWords() const { return (KeySizeMode + 1); }
+
+ CKeyInfo(): KeySizeMode(kKeySizeMode_AES256) {}
+
+ void Wipe()
+ {
+ Password.Wipe();
+ Z7_memset_0_ARRAY(Salt);
+ Z7_memset_0_ARRAY(PwdVerifComputed);
+ }
+
+ ~CKeyInfo() { Wipe(); }
+};
+
+/*
+struct CAesCtr2
+{
+ unsigned pos;
+ CAlignedBuffer aes;
+ UInt32 *Aes() { return (UInt32 *)(Byte *)aes; }
+
+ // unsigned offset;
+ // UInt32 aes[4 + AES_NUM_IVMRK_WORDS + 3];
+ // UInt32 *Aes() { return aes + offset; }
+ CAesCtr2();
+};
+
+void AesCtr2_Init(CAesCtr2 *p);
+void AesCtr2_Code(CAesCtr2 *p, Byte *data, SizeT size);
+*/
+
+class CBaseCoder:
+ public ICompressFilter,
+ public ICryptoSetPassword,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_1(ICryptoSetPassword)
+ Z7_COM7F_IMP(Init())
+public:
+ Z7_IFACE_COM7_IMP(ICryptoSetPassword)
+protected:
+ CKeyInfo _key;
+
+ // NSha1::CHmac _hmac;
+ // NSha1::CHmac *Hmac() { return &_hmac; }
+ CAlignedBuffer1 _hmacBuf;
+ UInt32 _hmacOverCalc;
+
+ NSha1::CHmac *Hmac() { return (NSha1::CHmac *)(void *)(Byte *)_hmacBuf; }
+
+ // CAesCtr2 _aes;
+ CAesCoder *_aesCoderSpec;
+ CMyComPtr<ICompressFilter> _aesCoder;
+ CBaseCoder():
+ _hmacBuf(sizeof(NSha1::CHmac))
+ {
+ _aesCoderSpec = new CAesCtrCoder(32);
+ _aesCoder = _aesCoderSpec;
+ }
+
+ void Init2();
+public:
+ unsigned GetHeaderSize() const { return _key.GetSaltSize() + kPwdVerifSize; }
+ unsigned GetAddPackSize() const { return GetHeaderSize() + kMacSize; }
+
+ bool SetKeyMode(unsigned mode)
+ {
+ if (mode < kKeySizeMode_AES128 || mode > kKeySizeMode_AES256)
+ return false;
+ _key.KeySizeMode = (EKeySizeMode)mode;
+ return true;
+ }
+
+ virtual ~CBaseCoder() {}
+};
+
+class CEncoder Z7_final:
+ public CBaseCoder
+{
+ Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size))
+public:
+ HRESULT WriteHeader(ISequentialOutStream *outStream);
+ HRESULT WriteFooter(ISequentialOutStream *outStream);
+};
+
+class CDecoder Z7_final:
+ public CBaseCoder
+ // public ICompressSetDecoderProperties2
+{
+ Byte _pwdVerifFromArchive[kPwdVerifSize];
+ Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size))
+public:
+ // Z7_IFACE_COM7_IMP(ICompressSetDecoderProperties2)
+ HRESULT ReadHeader(ISequentialInStream *inStream);
+ bool Init_and_CheckPassword();
+ HRESULT CheckMac(ISequentialInStream *inStream, bool &isOK);
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Crypto/ZipCrypto.cpp b/CPP/7zip/Crypto/ZipCrypto.cpp
new file mode 100644
index 0000000..047e2bd
--- /dev/null
+++ b/CPP/7zip/Crypto/ZipCrypto.cpp
@@ -0,0 +1,114 @@
+// Crypto/ZipCrypto.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "RandGen.h"
+#include "ZipCrypto.h"
+
+namespace NCrypto {
+namespace NZip {
+
+#define UPDATE_KEYS(b) { \
+ key0 = CRC_UPDATE_BYTE(key0, b); \
+ key1 = (key1 + (key0 & 0xFF)) * 0x8088405 + 1; \
+ key2 = CRC_UPDATE_BYTE(key2, (Byte)(key1 >> 24)); } \
+
+#define DECRYPT_BYTE_1 UInt32 temp = key2 | 2;
+#define DECRYPT_BYTE_2 ((Byte)((temp * (temp ^ 1)) >> 8))
+
+Z7_COM7F_IMF(CCipher::CryptoSetPassword(const Byte *data, UInt32 size))
+{
+ UInt32 key0 = 0x12345678;
+ UInt32 key1 = 0x23456789;
+ UInt32 key2 = 0x34567890;
+
+ for (UInt32 i = 0; i < size; i++)
+ UPDATE_KEYS(data[i])
+
+ KeyMem0 = key0;
+ KeyMem1 = key1;
+ KeyMem2 = key2;
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CCipher::Init())
+{
+ return S_OK;
+}
+
+HRESULT CEncoder::WriteHeader_Check16(ISequentialOutStream *outStream, UInt16 crc)
+{
+ Byte h[kHeaderSize];
+
+ /* PKZIP before 2.0 used 2 byte CRC check.
+ PKZIP 2.0+ used 1 byte CRC check. It's more secure.
+ We also use 1 byte CRC. */
+
+ MY_RAND_GEN(h, kHeaderSize - 1);
+ // h[kHeaderSize - 2] = (Byte)(crc);
+ h[kHeaderSize - 1] = (Byte)(crc >> 8);
+
+ RestoreKeys();
+ Filter(h, kHeaderSize);
+ return WriteStream(outStream, h, kHeaderSize);
+}
+
+Z7_COM7F_IMF2(UInt32, CEncoder::Filter(Byte *data, UInt32 size))
+{
+ UInt32 key0 = this->Key0;
+ UInt32 key1 = this->Key1;
+ UInt32 key2 = this->Key2;
+
+ for (UInt32 i = 0; i < size; i++)
+ {
+ Byte b = data[i];
+ DECRYPT_BYTE_1
+ data[i] = (Byte)(b ^ DECRYPT_BYTE_2);
+ UPDATE_KEYS(b)
+ }
+
+ this->Key0 = key0;
+ this->Key1 = key1;
+ this->Key2 = key2;
+
+ return size;
+}
+
+HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream)
+{
+ return ReadStream_FAIL(inStream, _header, kHeaderSize);
+}
+
+void CDecoder::Init_BeforeDecode()
+{
+ RestoreKeys();
+ Filter(_header, kHeaderSize);
+}
+
+Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size))
+{
+ UInt32 key0 = this->Key0;
+ UInt32 key1 = this->Key1;
+ UInt32 key2 = this->Key2;
+
+ for (UInt32 i = 0; i < size; i++)
+ {
+ DECRYPT_BYTE_1
+ Byte b = (Byte)(data[i] ^ DECRYPT_BYTE_2);
+ UPDATE_KEYS(b)
+ data[i] = b;
+ }
+
+ this->Key0 = key0;
+ this->Key1 = key1;
+ this->Key2 = key2;
+
+ return size;
+}
+
+}}
diff --git a/CPP/7zip/Crypto/ZipCrypto.h b/CPP/7zip/Crypto/ZipCrypto.h
new file mode 100644
index 0000000..485470e
--- /dev/null
+++ b/CPP/7zip/Crypto/ZipCrypto.h
@@ -0,0 +1,80 @@
+// Crypto/ZipCrypto.h
+
+#ifndef ZIP7_INC_CRYPTO_ZIP_CRYPTO_H
+#define ZIP7_INC_CRYPTO_ZIP_CRYPTO_H
+
+#include "../../Common/MyCom.h"
+
+#include "../ICoder.h"
+#include "../IPassword.h"
+
+namespace NCrypto {
+namespace NZip {
+
+const unsigned kHeaderSize = 12;
+
+/* ICompressFilter::Init() does nothing for this filter.
+ Call to init:
+ Encoder:
+ CryptoSetPassword();
+ WriteHeader();
+ Decoder:
+ [CryptoSetPassword();]
+ ReadHeader();
+ [CryptoSetPassword();] Init_and_GetCrcByte();
+ [CryptoSetPassword();] Init_and_GetCrcByte();
+*/
+
+class CCipher:
+ public ICompressFilter,
+ public ICryptoSetPassword,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_1(ICryptoSetPassword)
+ Z7_COM7F_IMP(Init())
+public:
+ Z7_IFACE_COM7_IMP(ICryptoSetPassword)
+protected:
+ UInt32 Key0;
+ UInt32 Key1;
+ UInt32 Key2;
+
+ UInt32 KeyMem0;
+ UInt32 KeyMem1;
+ UInt32 KeyMem2;
+
+ void RestoreKeys()
+ {
+ Key0 = KeyMem0;
+ Key1 = KeyMem1;
+ Key2 = KeyMem2;
+ }
+
+public:
+ virtual ~CCipher()
+ {
+ Key0 = KeyMem0 =
+ Key1 = KeyMem1 =
+ Key2 = KeyMem2 = 0;
+ }
+};
+
+class CEncoder Z7_final: public CCipher
+{
+ Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size))
+public:
+ HRESULT WriteHeader_Check16(ISequentialOutStream *outStream, UInt16 crc);
+};
+
+class CDecoder Z7_final: public CCipher
+{
+ Z7_COM7F_IMP2(UInt32, Filter(Byte *data, UInt32 size))
+public:
+ Byte _header[kHeaderSize];
+ HRESULT ReadHeader(ISequentialInStream *inStream);
+ void Init_BeforeDecode();
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/Crypto/ZipStrong.cpp b/CPP/7zip/Crypto/ZipStrong.cpp
new file mode 100644
index 0000000..59698d8
--- /dev/null
+++ b/CPP/7zip/Crypto/ZipStrong.cpp
@@ -0,0 +1,264 @@
+// Crypto/ZipStrong.cpp
+
+#include "StdAfx.h"
+
+#include "../../../C/7zCrc.h"
+#include "../../../C/CpuArch.h"
+
+#include "../Common/StreamUtils.h"
+
+#include "Sha1Cls.h"
+#include "ZipStrong.h"
+
+namespace NCrypto {
+namespace NZipStrong {
+
+static const UInt16 kAES128 = 0x660E;
+
+/*
+ DeriveKey() function is similar to CryptDeriveKey() from Windows.
+ New version of MSDN contains the following condition in CryptDeriveKey() description:
+ "If the hash is not a member of the SHA-2 family and the required key is for either 3DES or AES".
+ Now we support ZipStrong for AES only. And it uses SHA1.
+ Our DeriveKey() code is equal to CryptDeriveKey() in Windows for such conditions: (SHA1 + AES).
+ if (method != AES && method != 3DES), probably we need another code.
+*/
+
+static void DeriveKey2(const Byte *digest, Byte c, Byte *dest)
+{
+ MY_ALIGN (16)
+ Byte buf[64];
+ memset(buf, c, 64);
+ for (unsigned i = 0; i < NSha1::kDigestSize; i++)
+ buf[i] ^= digest[i];
+ MY_ALIGN (16)
+ NSha1::CContext sha;
+ sha.Init();
+ sha.Update(buf, 64);
+ sha.Final(dest);
+}
+
+static void DeriveKey(NSha1::CContext &sha, Byte *key)
+{
+ MY_ALIGN (16)
+ Byte digest[NSha1::kDigestSize];
+ sha.Final(digest);
+ MY_ALIGN (16)
+ Byte temp[NSha1::kDigestSize * 2];
+ DeriveKey2(digest, 0x36, temp);
+ DeriveKey2(digest, 0x5C, temp + NSha1::kDigestSize);
+ memcpy(key, temp, 32);
+}
+
+void CKeyInfo::SetPassword(const Byte *data, UInt32 size)
+{
+ MY_ALIGN (16)
+ NSha1::CContext sha;
+ sha.Init();
+ sha.Update(data, size);
+ DeriveKey(sha, MasterKey);
+}
+
+
+
+CDecoder::CDecoder()
+{
+ CAesCbcDecoder *d = new CAesCbcDecoder();
+ _cbcDecoder = d;
+ _aesFilter = d;
+}
+
+Z7_COM7F_IMF(CDecoder::CryptoSetPassword(const Byte *data, UInt32 size))
+{
+ _key.SetPassword(data, size);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CDecoder::Init())
+{
+ return S_OK;
+}
+
+Z7_COM7F_IMF2(UInt32, CDecoder::Filter(Byte *data, UInt32 size))
+{
+ return _aesFilter->Filter(data, size);
+}
+
+
+HRESULT CDecoder::ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize)
+{
+ Byte temp[4];
+ RINOK(ReadStream_FALSE(inStream, temp, 2))
+ _ivSize = GetUi16(temp);
+ if (_ivSize == 0)
+ {
+ memset(_iv, 0, 16);
+ SetUi32(_iv + 0, crc)
+ SetUi64(_iv + 4, unpackSize)
+ _ivSize = 12;
+ }
+ else if (_ivSize == 16)
+ {
+ RINOK(ReadStream_FALSE(inStream, _iv, _ivSize))
+ }
+ else
+ return E_NOTIMPL;
+ RINOK(ReadStream_FALSE(inStream, temp, 4))
+ _remSize = GetUi32(temp);
+ // const UInt32 kAlign = 16;
+ if (_remSize < 16 || _remSize > (1 << 18))
+ return E_NOTIMPL;
+ if (_remSize > _bufAligned.Size())
+ {
+ _bufAligned.AllocAtLeast(_remSize);
+ if (!(Byte *)_bufAligned)
+ return E_OUTOFMEMORY;
+ }
+ return ReadStream_FALSE(inStream, _bufAligned, _remSize);
+}
+
+HRESULT CDecoder::Init_and_CheckPassword(bool &passwOK)
+{
+ passwOK = false;
+ if (_remSize < 16)
+ return E_NOTIMPL;
+ Byte *p = _bufAligned;
+ const unsigned format = GetUi16(p);
+ if (format != 3)
+ return E_NOTIMPL;
+ unsigned algId = GetUi16(p + 2);
+ if (algId < kAES128)
+ return E_NOTIMPL;
+ algId -= kAES128;
+ if (algId > 2)
+ return E_NOTIMPL;
+ const unsigned bitLen = GetUi16(p + 4);
+ const unsigned flags = GetUi16(p + 6);
+ if (algId * 64 + 128 != bitLen)
+ return E_NOTIMPL;
+ _key.KeySize = 16 + algId * 8;
+ const bool cert = ((flags & 2) != 0);
+
+ if ((flags & 0x4000) != 0)
+ {
+ // Use 3DES for rd data
+ return E_NOTIMPL;
+ }
+
+ if (cert)
+ {
+ return E_NOTIMPL;
+ }
+ else
+ {
+ if ((flags & 1) == 0)
+ return E_NOTIMPL;
+ }
+
+ UInt32 rdSize = GetUi16(p + 8);
+
+ if (rdSize + 16 > _remSize)
+ return E_NOTIMPL;
+
+ const unsigned kPadSize = kAesPadAllign; // is equal to blockSize of cipher for rd
+
+ /*
+ if (cert)
+ {
+ if ((rdSize & 0x7) != 0)
+ return E_NOTIMPL;
+ }
+ else
+ */
+ {
+ // PKCS7 padding
+ if (rdSize < kPadSize)
+ return E_NOTIMPL;
+ if ((rdSize & (kPadSize - 1)) != 0)
+ return E_NOTIMPL;
+ }
+
+ memmove(p, p + 10, rdSize);
+ const Byte *p2 = p + rdSize + 10;
+ UInt32 reserved = GetUi32(p2);
+ p2 += 4;
+
+ /*
+ if (cert)
+ {
+ UInt32 numRecipients = reserved;
+
+ if (numRecipients == 0)
+ return E_NOTIMPL;
+
+ {
+ UInt32 hashAlg = GetUi16(p2);
+ hashAlg = hashAlg;
+ UInt32 hashSize = GetUi16(p2 + 2);
+ hashSize = hashSize;
+ p2 += 4;
+
+ reserved = reserved;
+ // return E_NOTIMPL;
+
+ for (unsigned r = 0; r < numRecipients; r++)
+ {
+ UInt32 specSize = GetUi16(p2);
+ p2 += 2;
+ p2 += specSize;
+ }
+ }
+ }
+ else
+ */
+ {
+ if (reserved != 0)
+ return E_NOTIMPL;
+ }
+
+ UInt32 validSize = GetUi16(p2);
+ p2 += 2;
+ const size_t validOffset = (size_t)(p2 - p);
+ if ((validSize & 0xF) != 0 || validOffset + validSize != _remSize)
+ return E_NOTIMPL;
+
+ {
+ RINOK(_cbcDecoder->SetKey(_key.MasterKey, _key.KeySize))
+ RINOK(_cbcDecoder->SetInitVector(_iv, 16))
+ // SetInitVector() calls also Init()
+ RINOK(_cbcDecoder->Init()) // it's optional
+ Filter(p, rdSize);
+
+ rdSize -= kPadSize;
+ for (unsigned i = 0; i < kPadSize; i++)
+ if (p[(size_t)rdSize + i] != kPadSize)
+ return S_OK; // passwOK = false;
+ }
+
+ MY_ALIGN (16)
+ Byte fileKey[32];
+ MY_ALIGN (16)
+ NSha1::CContext sha;
+ sha.Init();
+ sha.Update(_iv, _ivSize);
+ sha.Update(p, rdSize);
+ DeriveKey(sha, fileKey);
+
+ RINOK(_cbcDecoder->SetKey(fileKey, _key.KeySize))
+ RINOK(_cbcDecoder->SetInitVector(_iv, 16))
+ // SetInitVector() calls also Init()
+ RINOK(_cbcDecoder->Init()) // it's optional
+
+ memmove(p, p + validOffset, validSize);
+ Filter(p, validSize);
+
+ if (validSize < 4)
+ return E_NOTIMPL;
+ validSize -= 4;
+ if (GetUi32(p + validSize) != CrcCalc(p, validSize))
+ return S_OK;
+ passwOK = true;
+ return S_OK;
+}
+
+}}
diff --git a/CPP/7zip/Crypto/ZipStrong.h b/CPP/7zip/Crypto/ZipStrong.h
new file mode 100644
index 0000000..a2b5cdd
--- /dev/null
+++ b/CPP/7zip/Crypto/ZipStrong.h
@@ -0,0 +1,73 @@
+// Crypto/ZipStrong.h
+
+#ifndef ZIP7_INC_CRYPTO_ZIP_STRONG_H
+#define ZIP7_INC_CRYPTO_ZIP_STRONG_H
+
+#include "../../Common/MyBuffer2.h"
+
+#include "../IPassword.h"
+
+#include "MyAes.h"
+
+namespace NCrypto {
+namespace NZipStrong {
+
+/* ICompressFilter::Init() does nothing for this filter.
+ Call to init:
+ Decoder:
+ [CryptoSetPassword();]
+ ReadHeader();
+ [CryptoSetPassword();] Init_and_CheckPassword();
+ [CryptoSetPassword();] Init_and_CheckPassword();
+*/
+
+struct CKeyInfo
+{
+ Byte MasterKey[32];
+ UInt32 KeySize;
+
+ void SetPassword(const Byte *data, UInt32 size);
+
+ void Wipe()
+ {
+ Z7_memset_0_ARRAY(MasterKey);
+ }
+};
+
+
+const unsigned kAesPadAllign = AES_BLOCK_SIZE;
+
+Z7_CLASS_IMP_COM_2(
+ CDecoder
+ , ICompressFilter
+ , ICryptoSetPassword
+)
+ CAesCbcDecoder *_cbcDecoder;
+ CMyComPtr<ICompressFilter> _aesFilter;
+ CKeyInfo _key;
+ CAlignedBuffer _bufAligned;
+
+ UInt32 _ivSize;
+ Byte _iv[16];
+ UInt32 _remSize;
+public:
+ HRESULT ReadHeader(ISequentialInStream *inStream, UInt32 crc, UInt64 unpackSize);
+ HRESULT Init_and_CheckPassword(bool &passwOK);
+ UInt32 GetPadSize(UInt32 packSize32) const
+ {
+ // Padding is to align to blockSize of cipher.
+ // Change it, if is not AES
+ return kAesPadAllign - (packSize32 & (kAesPadAllign - 1));
+ }
+ CDecoder();
+ ~CDecoder() { Wipe(); }
+ void Wipe()
+ {
+ Z7_memset_0_ARRAY(_iv);
+ _key.Wipe();
+ }
+};
+
+}}
+
+#endif
diff --git a/CPP/7zip/GuiCommon.rc b/CPP/7zip/GuiCommon.rc
index 565ee70..b67409b 100644
--- a/CPP/7zip/GuiCommon.rc
+++ b/CPP/7zip/GuiCommon.rc
@@ -1,84 +1,84 @@
-#include <windows.h>
-
-// #include <winnt.h>
-// #include <WinUser.h>
-
-// for Windows CE:
-#include <CommCtrl.h>
-
-
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-
-#undef m
-#undef bxs
-#undef bys
-#undef bxsDots
-#undef y
-#undef xc
-#undef yc
-#undef xs
-#undef ys
-#undef bx
-#undef bx1
-#undef bx2
-#undef bx3
-#undef by
-#undef by1
-#undef by2
-#undef by3
-#undef gSpace
-#undef gSize
-#undef marg2
-#undef marg3
-
-#undef MY_DIALOG
-#undef MY_RESIZE_DIALOG
-#undef MY_PAGE
-
-#define m 8
-#define bxs 64
-#define bys 16
-#define bxsDots 20
-
-#define xs (xc + m + m)
-#define ys (yc + m + m)
-
-#define bx1 (xs - m - bxs)
-#define bx2 (bx1 - m - bxs)
-#define bx3 (bx2 - m - bxs)
-#define bx bx1
-
-#define by1 (ys - m - bys)
-#define by2 (by1 - m - bys)
-#define by by1
-
-
-#define MY_MODAL_DIALOG_STYLE STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
-
-#define MY_MODAL_RESIZE_DIALOG_STYLE MY_MODAL_DIALOG_STYLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SIZEBOX | WS_THICKFRAME
-
-#define MY_PAGE_STYLE STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
-
-#define MY_FONT FONT 8, "MS Shell Dlg"
-
-#define SMALL_PAGE_SIZE_X 120
-
-// #define MY_DIALOG DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
-// #define MY_RESIZE_DIALOG DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT
-#define MY_PAGE DIALOG 0, 0, xs, ys MY_PAGE_STYLE MY_FONT
-
-#define OK_CANCEL \
- DEFPUSHBUTTON "OK", IDOK, bx2, by, bxs, bys \
- PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys
-
-#define MY_BUTTON__CLOSE \
- DEFPUSHBUTTON "&Close", IDCLOSE, bx1, by, bxs, bys
-
-
-#define MY_COMBO CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
-#define MY_COMBO_SORTED MY_COMBO | CBS_SORT
-#define MY_COMBO_WITH_EDIT CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
-
-#define MY_CHECKBOX "Button", BS_AUTOCHECKBOX | WS_TABSTOP
-
-#define MY_TEXT_NOPREFIX 8, SS_NOPREFIX
+#include <windows.h>
+
+// #include <winnt.h>
+// #include <WinUser.h>
+
+// for Windows CE:
+#include <CommCtrl.h>
+
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+#undef m
+#undef bxs
+#undef bys
+#undef bxsDots
+#undef y
+#undef xc
+#undef yc
+#undef xs
+#undef ys
+#undef bx
+#undef bx1
+#undef bx2
+#undef bx3
+#undef by
+#undef by1
+#undef by2
+#undef by3
+#undef gSpace
+#undef gSize
+#undef marg2
+#undef marg3
+
+#undef MY_DIALOG
+#undef MY_RESIZE_DIALOG
+#undef MY_PAGE
+
+#define m 8
+#define bxs 64
+#define bys 16
+#define bxsDots 20
+
+#define xs (xc + m + m)
+#define ys (yc + m + m)
+
+#define bx1 (xs - m - bxs)
+#define bx2 (bx1 - m - bxs)
+#define bx3 (bx2 - m - bxs)
+#define bx bx1
+
+#define by1 (ys - m - bys)
+#define by2 (by1 - m - bys)
+#define by by1
+
+
+#define MY_MODAL_DIALOG_STYLE STYLE DS_MODALFRAME | DS_CENTER | WS_POPUP | WS_CAPTION | WS_SYSMENU
+
+#define MY_MODAL_RESIZE_DIALOG_STYLE MY_MODAL_DIALOG_STYLE | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_SIZEBOX | WS_THICKFRAME
+
+#define MY_PAGE_STYLE STYLE WS_CHILD | WS_DISABLED | WS_CAPTION
+
+#define MY_FONT FONT 8, "MS Shell Dlg"
+
+#define SMALL_PAGE_SIZE_X 120
+
+// #define MY_DIALOG DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
+// #define MY_RESIZE_DIALOG DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT
+#define MY_PAGE DIALOG 0, 0, xs, ys MY_PAGE_STYLE MY_FONT
+
+#define OK_CANCEL \
+ DEFPUSHBUTTON "OK", IDOK, bx2, by, bxs, bys \
+ PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys
+
+#define MY_BUTTON__CLOSE \
+ DEFPUSHBUTTON "&Close", IDCLOSE, bx1, by, bxs, bys
+
+
+#define MY_COMBO CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+#define MY_COMBO_SORTED MY_COMBO | CBS_SORT
+#define MY_COMBO_WITH_EDIT CBS_DROPDOWN | CBS_AUTOHSCROLL | WS_VSCROLL | WS_TABSTOP
+
+#define MY_CHECKBOX "Button", BS_AUTOCHECKBOX | WS_TABSTOP
+
+#define MY_TEXT_NOPREFIX 8, SS_NOPREFIX
diff --git a/CPP/7zip/Guid.txt b/CPP/7zip/Guid.txt
index e5e0612..eee28f7 100644
--- a/CPP/7zip/Guid.txt
+++ b/CPP/7zip/Guid.txt
@@ -1,220 +1,237 @@
-{23170F69-40C1-278A-0000-00yy00xx0000}
-
-00 IProgress.h
-
- 05 IProgress
- // 050002 IProgress2
-
-01 IFolderArchive.h
-
- // 05 IArchiveFolder // old
- // 06 IInFolderArchive // old
- 07 IFileExtractCallback.h::IFolderArchiveExtractCallback
- 08 IFileExtractCallback.h::IFolderArchiveExtractCallback2
- // 0A IOutFolderArchive
- 0B IFolderArchiveUpdateCallback
- 0C Agent.h::IArchiveFolderInternal
- 0D IArchiveFolder
- 0E IInFolderArchive
- 0F IOutFolderArchive
- 10 IFolderArchiveUpdateCallback2
- 11 IFolderScanProgress
-
- 20 IFileExtractCallback.h::IGetProp
- 30 IFileExtractCallback.h::IFolderExtractToStreamCallback
-
-03 IStream.h
-
- 01 ISequentialInStream
- 02 ISequentialOutStream
- 03 IInStream
- 04 IOutStream
- 06 IStreamGetSize
- 07 IOutStreamFinish
- 08 IStreamGetProps
- 09 IStreamGetProps2
-
-
-04 ICoder.h
-
- 04 ICompressProgressInfo
- 05 ICompressCoder
- 18 ICompressCoder2
- 1F ICompressSetCoderPropertiesOpt
- 20 ICompressSetCoderProperties
- 21 ICompressSetDecoderProperties //
- 22 ICompressSetDecoderProperties2
- 23 ICompressWriteCoderProperties
- 24 ICompressGetInStreamProcessedSize
- 25 ICompressSetCoderMt
- 26 ICompressSetFinishMode
- 27 ICompressGetInStreamProcessedSize2
- 28 ICompressSetMemLimit
-
- 30 ICompressGetSubStreamSize
- 31 ICompressSetInStream
- 32 ICompressSetOutStream
-// 33 ICompressSetInStreamSize
- 34 ICompressSetOutStreamSize
- 35 ICompressSetBufSize
- 36 ICompressInitEncoder
- 37 ICompressSetInStream2
-// 38 ICompressSetOutStream2
-// 39 SetInStreamSize2
-// 3A SetOutStreamSize2
-
- 40 ICompressFilter
- 60 ICompressCodecsInfo
- 61 ISetCompressCodecsInfo
- 80 ICryptoProperties
- 88 ICryptoResetSalt
- 8C ICryptoResetInitVector
- 90 ICryptoSetPassword
- A0 ICryptoSetCRC
- C0 IHasher
- C1 IHashers
-
-
-05 IPassword.h
-
- 10 ICryptoGetTextPassword
- 11 ICryptoGetTextPassword2
-
-
-06 IArchive.h
-
- 03 ISetProperties
- 04 IArchiveKeepModeForNextOpen
- 05 IArchiveAllowTail
-
- 10 IArchiveOpenCallback
-
- 20 IArchiveExtractCallback
- 21 IArchiveExtractCallbackMessage
-
- 30 IArchiveOpenVolumeCallback
- 40 IInArchiveGetStream
- 50 IArchiveOpenSetSubArchiveName
- 60 IInArchive
- 61 IArchiveOpenSeq
- 70 IArchiveGetRawProps
- 71 IArchiveGetRootProps
-
- 80 IArchiveUpdateCallback
- 82 IArchiveUpdateCallback2
- 83 IArchiveUpdateCallbackFile
-
- A0 IOutArchive
-
-
-
-08 IFolder.h
-
- 00 IFolderFolder
- 01 IEnumProperties
- 02 IFolderGetTypeID
- 03 IFolderGetPath
- 04 IFolderWasChanged
- 05 // IFolderReload
- 06 // IFolderOperations old
- 07 IFolderGetSystemIconIndex
- 08 IFolderGetItemFullSize
- 09 IFolderClone
- 0A IFolderSetFlatMode
- 0B IFolderOperationsExtractCallback
- 0C //
- 0D //
- 0E IFolderProperties
- 0F
- 10 IFolderArcProps
- 11 IGetFolderArcProps
- 12 // IFolderOperations
- 13 IFolderOperations
- 14 IFolderCalcItemFullSize
- 15 IFolderCompare
- 16 IFolderGetItemName
- 17 IFolderAltStreams
-
-
-09 IFolder.h :: FOLDER_MANAGER_INTERFACE
-
- 00 - 04 // old IFolderManager
- 05 IFolderManager
-
-
-// 0A PluginInterface.h
- 00 IInitContextMenu
- 01 IPluginOptionsCallback
- 02 IPluginOptions
-
-
-Handler GUIDs:
-
-{23170F69-40C1-278A-1000-000110xx0000}
-
- 01 Zip
- 02 BZip2
- 03 Rar
- 04 Arj
- 05 Z
- 06 Lzh
- 07 7z
- 08 Cab
- 09 Nsis
- 0A lzma
- 0B lzma86
- 0C xz
- 0D ppmd
-
- C6 COFF
- C7 Ext
- C8 VMDK
- C9 VDI
- CA Qcow
- CB GPT
- CC Rar5
- CD IHex
- CE Hxs
- CF TE
- D0 UEFIc
- D1 UEFIs
- D2 SquashFS
- D3 CramFS
- D4 APM
- D5 Mslz
- D6 Flv
- D7 Swf
- D8 Swfc
- D9 Ntfs
- DA Fat
- DB Mbr
- DC Vhd
- DD Pe
- DE Elf
- DF Mach-O
- E0 Udf
- E1 Xar
- E2 Mub
- E3 Hfs
- E4 Dmg
- E5 Compound
- E6 Wim
- E7 Iso
- E8
- E9 Chm
- EA Split
- EB Rpm
- EC Deb
- ED Cpio
- EE Tar
- EF GZip
-
-{23170F69-40C1-278A-1000-000100020000} ContextMenu.h::CZipContextMenu
-
-// {23170F69-40C1-278A-1000-000100030000} // CAgentArchiveHandler
-// {23170F69-40C1-278B- old codecs clsids
-// {23170F69-40C1-278D-1000-000100020000} OptionsDialog.h::CLSID_CSevenZipOptions
-
-{23170F69-40C1-2790-id} Codec Decoders
-{23170F69-40C1-2791-id} Codec Encoders
-{23170F69-40C1-2792-id} Hashers
+{23170F69-40C1-278A-0000-00yy00xx0000}
+
+00 IProgress.h
+
+ 05 IProgress
+ // 050002 IProgress2
+
+01 IFolderArchive.h
+
+ // 05 IArchiveFolder // old
+ // 06 IInFolderArchive // old
+ 07 IFileExtractCallback.h::IFolderArchiveExtractCallback
+ 08 IFileExtractCallback.h::IFolderArchiveExtractCallback2
+ // 0A IOutFolderArchive
+ 0B IFolderArchiveUpdateCallback
+ 0C Agent.h::IArchiveFolderInternal
+ 0D IArchiveFolder
+ 0E IInFolderArchive
+ 0F IOutFolderArchive
+ 10 IFolderArchiveUpdateCallback2
+ 11 IFolderScanProgress
+ 12 IFolderSetZoneIdMode
+
+ 20 IFileExtractCallback.h::IGetProp
+ 30 IFileExtractCallback.h::IFolderExtractToStreamCallback (old)
+ 31 IFileExtractCallback.h::IFolderExtractToStreamCallback (new 21.04)
+
+03 IStream.h
+
+ 01 ISequentialInStream
+ 02 ISequentialOutStream
+ 03 IInStream
+ 04 IOutStream
+
+ 06 IStreamGetSize
+ 07 IOutStreamFinish
+ 08 IStreamGetProps
+ 09 IStreamGetProps2
+ 0A IStreamGetProp
+
+ 10 IStreamSetRestriction
+
+
+04 ICoder.h
+
+ 04 ICompressProgressInfo
+ 05 ICompressCoder
+ 18 ICompressCoder2
+ 1F ICompressSetCoderPropertiesOpt
+ 20 ICompressSetCoderProperties
+ 21 ICompressSetDecoderProperties //
+ 22 ICompressSetDecoderProperties2
+ 23 ICompressWriteCoderProperties
+ 24 ICompressGetInStreamProcessedSize
+ 25 ICompressSetCoderMt
+ 26 ICompressSetFinishMode
+ 27 ICompressGetInStreamProcessedSize2
+ 28 ICompressSetMemLimit
+ 29 ICompressReadUnusedFromInBuf
+
+ 30 ICompressGetSubStreamSize
+ 31 ICompressSetInStream
+ 32 ICompressSetOutStream
+// 33 ICompressSetInStreamSize
+ 34 ICompressSetOutStreamSize
+ 35 ICompressSetBufSize
+ 36 ICompressInitEncoder
+ 37 ICompressSetInStream2
+// 38 ICompressSetOutStream2
+// 39 SetInStreamSize2
+// 3A SetOutStreamSize2
+
+ 40 ICompressFilter
+ 60 ICompressCodecsInfo
+ 61 ISetCompressCodecsInfo
+ 80 ICryptoProperties
+ 88 ICryptoResetSalt
+ 8C ICryptoResetInitVector
+ 90 ICryptoSetPassword
+ A0 ICryptoSetCRC
+ C0 IHasher
+ C1 IHashers
+
+
+05 IPassword.h
+
+ 10 ICryptoGetTextPassword
+ 11 ICryptoGetTextPassword2
+
+
+06 IArchive.h
+
+ 03 ISetProperties
+ 04 IArchiveKeepModeForNextOpen
+ 05 IArchiveAllowTail
+
+ 10 IArchiveOpenCallback
+
+ 20 IArchiveExtractCallback
+ 21 IArchiveExtractCallbackMessage (deprecated in v23)
+ 22 IArchiveExtractCallbackMessage2 (new in v23)
+
+ 30 IArchiveOpenVolumeCallback
+ 40 IInArchiveGetStream
+ 50 IArchiveOpenSetSubArchiveName
+ 60 IInArchive
+ 61 IArchiveOpenSeq
+ 70 IArchiveGetRawProps
+ 71 IArchiveGetRootProps
+
+ 80 IArchiveUpdateCallback
+ 82 IArchiveUpdateCallback2
+ 83 IArchiveUpdateCallbackFile
+ 84 IArchiveGetDiskProperty
+ 85 IArchiveUpdateCallbackArcProp (Reserved)
+
+
+ A0 IOutArchive
+
+
+
+08 IFolder.h
+
+ 00 IFolderFolder
+ 01 IEnumProperties
+ 02 IFolderGetTypeID
+ 03 IFolderGetPath
+ 04 IFolderWasChanged
+ 05 // IFolderReload
+ 06 // IFolderOperations old
+ 07 IFolderGetSystemIconIndex
+ 08 IFolderGetItemFullSize
+ 09 IFolderClone
+ 0A IFolderSetFlatMode
+ 0B IFolderOperationsExtractCallback
+ 0C //
+ 0D //
+ 0E IFolderProperties
+ 0F
+ 10 IFolderArcProps
+ 11 IGetFolderArcProps
+ 12 // IFolderOperations
+ 13 IFolderOperations
+ 14 IFolderCalcItemFullSize
+ 15 IFolderCompare
+ 16 IFolderGetItemName
+ 17 IFolderAltStreams
+
+
+09 IFolder.h :: FOLDER_MANAGER_INTERFACE
+
+ 00 - 04 // old IFolderManager
+ 05 IFolderManager
+
+
+// 0A PluginInterface.h
+ 00 IInitContextMenu
+ 01 IPluginOptionsCallback
+ 02 IPluginOptions
+
+
+Handler GUIDs:
+
+{23170F69-40C1-278A-1000-000110xx0000}
+
+ 01 Zip
+ 02 BZip2
+ 03 Rar
+ 04 Arj
+ 05 Z
+ 06 Lzh
+ 07 7z
+ 08 Cab
+ 09 Nsis
+ 0A lzma
+ 0B lzma86
+ 0C xz
+ 0D ppmd
+
+ C0 AVB
+ C1 LP
+ C2 Sparse
+ C3 APFS
+ C4 Vhdx
+ C5 Base64
+ C6 COFF
+ C7 Ext
+ C8 VMDK
+ C9 VDI
+ CA Qcow
+ CB GPT
+ CC Rar5
+ CD IHex
+ CE Hxs
+ CF TE
+ D0 UEFIc
+ D1 UEFIs
+ D2 SquashFS
+ D3 CramFS
+ D4 APM
+ D5 Mslz
+ D6 Flv
+ D7 Swf
+ D8 Swfc
+ D9 Ntfs
+ DA Fat
+ DB Mbr
+ DC Vhd
+ DD Pe
+ DE Elf
+ DF Mach-O
+ E0 Udf
+ E1 Xar
+ E2 Mub
+ E3 Hfs
+ E4 Dmg
+ E5 Compound
+ E6 Wim
+ E7 Iso
+ E8
+ E9 Chm
+ EA Split
+ EB Rpm
+ EC Deb
+ ED Cpio
+ EE Tar
+ EF GZip
+
+{23170F69-40C1-278A-1000-000100020000} ContextMenu.h::CZipContextMenu
+
+// {23170F69-40C1-278A-1000-000100030000} // CAgentArchiveHandler
+// {23170F69-40C1-278B- old codecs clsids
+// {23170F69-40C1-278D-1000-000100020000} OptionsDialog.h::CLSID_CSevenZipOptions
+
+{23170F69-40C1-2790-id} Codec Decoders
+{23170F69-40C1-2791-id} Codec Encoders
+{23170F69-40C1-2792-id} Hashers
diff --git a/CPP/7zip/ICoder.h b/CPP/7zip/ICoder.h
index 54b2476..aec2834 100644
--- a/CPP/7zip/ICoder.h
+++ b/CPP/7zip/ICoder.h
@@ -1,399 +1,477 @@
-// ICoder.h
-
-#ifndef __ICODER_H
-#define __ICODER_H
-
-#include "IStream.h"
-
-#define CODER_INTERFACE(i, x) DECL_INTERFACE(i, 4, x)
-
-CODER_INTERFACE(ICompressProgressInfo, 0x04)
-{
- STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize) PURE;
-
- /* (inSize) can be NULL, if unknown
- (outSize) can be NULL, if unknown
-
- returns:
- S_OK
- E_ABORT : Break by user
- another error codes
- */
-};
-
-CODER_INTERFACE(ICompressCoder, 0x05)
-{
- STDMETHOD(Code)(ISequentialInStream *inStream, ISequentialOutStream *outStream,
- const UInt64 *inSize, const UInt64 *outSize,
- ICompressProgressInfo *progress) PURE;
-};
-
-CODER_INTERFACE(ICompressCoder2, 0x18)
-{
- STDMETHOD(Code)(ISequentialInStream * const *inStreams, const UInt64 * const *inSizes, UInt32 numInStreams,
- ISequentialOutStream * const *outStreams, const UInt64 * const *outSizes, UInt32 numOutStreams,
- ICompressProgressInfo *progress) PURE;
-};
-
-/*
- ICompressCoder::Code
- ICompressCoder2::Code
-
- returns:
- S_OK : OK
- S_FALSE : data error (for decoders)
- E_OUTOFMEMORY : memory allocation error
- E_NOTIMPL : unsupported encoding method (for decoders)
- another error code : some error. For example, it can be error code received from inStream or outStream function.
-
- Parameters:
- (inStream != NULL)
- (outStream != NULL)
-
- if (inSize != NULL)
- {
- Encoders in 7-Zip ignore (inSize).
- Decoder can use (*inSize) to check that stream was decoded correctly.
- Some decoder in 7-Zip check it, if (full_decoding mode was set via ICompressSetFinishMode)
- }
-
- If it's required to limit the reading from input stream (inStream), it can
- be done with ISequentialInStream implementation.
-
- if (outSize != NULL)
- {
- Encoders in 7-Zip ignore (outSize).
- Decoder unpacks no more than (*outSize) bytes.
- }
-
- (progress == NULL) is allowed.
-
-
- Decoding with Code() function
- -----------------------------
-
- You can request some interfaces before decoding
- - ICompressSetDecoderProperties2
- - ICompressSetFinishMode
-
- If you need to decode full stream:
- {
- 1) try to set full_decoding mode with ICompressSetFinishMode::SetFinishMode(1);
- 2) call the Code() function with specified (inSize) and (outSize), if these sizes are known.
- }
-
- If you need to decode only part of stream:
- {
- 1) try to set partial_decoding mode with ICompressSetFinishMode::SetFinishMode(0);
- 2) Call the Code() function with specified (inSize = NULL) and specified (outSize).
- }
-
- Encoding with Code() function
- -----------------------------
-
- You can request some interfaces :
- - ICompressSetCoderProperties - use it before encoding to set properties
- - ICompressWriteCoderProperties - use it before or after encoding to request encoded properties.
-
- ICompressCoder2 is used when (numInStreams != 1 || numOutStreams != 1)
- The rules are similar to ICompressCoder rules
-*/
-
-
-namespace NCoderPropID
-{
- enum EEnum
- {
- kDefaultProp = 0,
- kDictionarySize, // VT_UI4
- kUsedMemorySize, // VT_UI4
- kOrder, // VT_UI4
- kBlockSize, // VT_UI4 or VT_UI8
- kPosStateBits, // VT_UI4
- kLitContextBits, // VT_UI4
- kLitPosBits, // VT_UI4
- kNumFastBytes, // VT_UI4
- kMatchFinder, // VT_BSTR
- kMatchFinderCycles, // VT_UI4
- kNumPasses, // VT_UI4
- kAlgorithm, // VT_UI4
- kNumThreads, // VT_UI4
- kEndMarker, // VT_BOOL
- kLevel, // VT_UI4
- kReduceSize, // VT_UI8 : it's estimated size of largest data stream that will be compressed
- // encoder can use this value to reduce dictionary size and allocate data buffers
-
- kExpectedDataSize, // VT_UI8 : for ICompressSetCoderPropertiesOpt :
- // it's estimated size of current data stream
- // real data size can differ from that size
- // encoder can use this value to optimize encoder initialization
-
- kBlockSize2, // VT_UI4 or VT_UI8
- kCheckSize, // VT_UI4 : size of digest in bytes
- kFilter, // VT_BSTR
- kMemUse // VT_UI8
- };
-}
-
-CODER_INTERFACE(ICompressSetCoderPropertiesOpt, 0x1F)
-{
- STDMETHOD(SetCoderPropertiesOpt)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) PURE;
-};
-
-CODER_INTERFACE(ICompressSetCoderProperties, 0x20)
-{
- STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps) PURE;
-};
-
-/*
-CODER_INTERFACE(ICompressSetCoderProperties, 0x21)
-{
- STDMETHOD(SetDecoderProperties)(ISequentialInStream *inStream) PURE;
-};
-*/
-
-CODER_INTERFACE(ICompressSetDecoderProperties2, 0x22)
-{
- /* returns:
- S_OK
- E_NOTIMP : unsupported properties
- E_INVALIDARG : incorrect (or unsupported) properties
- E_OUTOFMEMORY : memory allocation error
- */
- STDMETHOD(SetDecoderProperties2)(const Byte *data, UInt32 size) PURE;
-};
-
-CODER_INTERFACE(ICompressWriteCoderProperties, 0x23)
-{
- STDMETHOD(WriteCoderProperties)(ISequentialOutStream *outStream) PURE;
-};
-
-CODER_INTERFACE(ICompressGetInStreamProcessedSize, 0x24)
-{
- STDMETHOD(GetInStreamProcessedSize)(UInt64 *value) PURE;
-};
-
-CODER_INTERFACE(ICompressSetCoderMt, 0x25)
-{
- STDMETHOD(SetNumberOfThreads)(UInt32 numThreads) PURE;
-};
-
-CODER_INTERFACE(ICompressSetFinishMode, 0x26)
-{
- STDMETHOD(SetFinishMode)(UInt32 finishMode) PURE;
-
- /* finishMode:
- 0 : partial decoding is allowed. It's default mode for ICompressCoder::Code(), if (outSize) is defined.
- 1 : full decoding. The stream must be finished at the end of decoding. */
-};
-
-CODER_INTERFACE(ICompressGetInStreamProcessedSize2, 0x27)
-{
- STDMETHOD(GetInStreamProcessedSize2)(UInt32 streamIndex, UInt64 *value) PURE;
-};
-
-CODER_INTERFACE(ICompressSetMemLimit, 0x28)
-{
- STDMETHOD(SetMemLimit)(UInt64 memUsage) PURE;
-};
-
-
-
-CODER_INTERFACE(ICompressGetSubStreamSize, 0x30)
-{
- STDMETHOD(GetSubStreamSize)(UInt64 subStream, UInt64 *value) PURE;
-
- /* returns:
- S_OK : (*value) contains the size or estimated size (can be incorrect size)
- S_FALSE : size is undefined
- E_NOTIMP : the feature is not implemented
-
- Let's (read_size) is size of data that was already read by ISequentialInStream::Read().
- The caller should call GetSubStreamSize() after each Read() and check sizes:
- if (start_of_subStream + *value < read_size)
- {
- // (*value) is correct, and it's allowed to call GetSubStreamSize() for next subStream:
- start_of_subStream += *value;
- subStream++;
- }
- */
-};
-
-CODER_INTERFACE(ICompressSetInStream, 0x31)
-{
- STDMETHOD(SetInStream)(ISequentialInStream *inStream) PURE;
- STDMETHOD(ReleaseInStream)() PURE;
-};
-
-CODER_INTERFACE(ICompressSetOutStream, 0x32)
-{
- STDMETHOD(SetOutStream)(ISequentialOutStream *outStream) PURE;
- STDMETHOD(ReleaseOutStream)() PURE;
-};
-
-/*
-CODER_INTERFACE(ICompressSetInStreamSize, 0x33)
-{
- STDMETHOD(SetInStreamSize)(const UInt64 *inSize) PURE;
-};
-*/
-
-CODER_INTERFACE(ICompressSetOutStreamSize, 0x34)
-{
- STDMETHOD(SetOutStreamSize)(const UInt64 *outSize) PURE;
-
- /* That function initializes decoder structures.
- Call this function only for stream version of decoder.
- if (outSize == NULL), then output size is unknown
- if (outSize != NULL), then the decoder must stop decoding after (*outSize) bytes. */
-};
-
-CODER_INTERFACE(ICompressSetBufSize, 0x35)
-{
- STDMETHOD(SetInBufSize)(UInt32 streamIndex, UInt32 size) PURE;
- STDMETHOD(SetOutBufSize)(UInt32 streamIndex, UInt32 size) PURE;
-};
-
-CODER_INTERFACE(ICompressInitEncoder, 0x36)
-{
- STDMETHOD(InitEncoder)() PURE;
-
- /* That function initializes encoder structures.
- Call this function only for stream version of encoder. */
-};
-
-CODER_INTERFACE(ICompressSetInStream2, 0x37)
-{
- STDMETHOD(SetInStream2)(UInt32 streamIndex, ISequentialInStream *inStream) PURE;
- STDMETHOD(ReleaseInStream2)(UInt32 streamIndex) PURE;
-};
-
-/*
-CODER_INTERFACE(ICompressSetOutStream2, 0x38)
-{
- STDMETHOD(SetOutStream2)(UInt32 streamIndex, ISequentialOutStream *outStream) PURE;
- STDMETHOD(ReleaseOutStream2)(UInt32 streamIndex) PURE;
-};
-
-CODER_INTERFACE(ICompressSetInStreamSize2, 0x39)
-{
- STDMETHOD(SetInStreamSize2)(UInt32 streamIndex, const UInt64 *inSize) PURE;
-};
-*/
-
-
-/*
- ICompressFilter
- Filter() converts as most as possible bytes
- returns: (outSize):
- if (outSize <= size) : Filter have converted outSize bytes
- if (outSize > size) : Filter have not converted anything.
- and it needs at least outSize bytes to convert one block
- (it's for crypto block algorithms).
-*/
-
-#define INTERFACE_ICompressFilter(x) \
- STDMETHOD(Init)() x; \
- STDMETHOD_(UInt32, Filter)(Byte *data, UInt32 size) x; \
-
-CODER_INTERFACE(ICompressFilter, 0x40)
-{
- INTERFACE_ICompressFilter(PURE);
-};
-
-
-CODER_INTERFACE(ICompressCodecsInfo, 0x60)
-{
- STDMETHOD(GetNumMethods)(UInt32 *numMethods) PURE;
- STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value) PURE;
- STDMETHOD(CreateDecoder)(UInt32 index, const GUID *iid, void **coder) PURE;
- STDMETHOD(CreateEncoder)(UInt32 index, const GUID *iid, void **coder) PURE;
-};
-
-CODER_INTERFACE(ISetCompressCodecsInfo, 0x61)
-{
- STDMETHOD(SetCompressCodecsInfo)(ICompressCodecsInfo *compressCodecsInfo) PURE;
-};
-
-CODER_INTERFACE(ICryptoProperties, 0x80)
-{
- STDMETHOD(SetKey)(const Byte *data, UInt32 size) PURE;
- STDMETHOD(SetInitVector)(const Byte *data, UInt32 size) PURE;
-};
-
-/*
-CODER_INTERFACE(ICryptoResetSalt, 0x88)
-{
- STDMETHOD(ResetSalt)() PURE;
-};
-*/
-
-CODER_INTERFACE(ICryptoResetInitVector, 0x8C)
-{
- STDMETHOD(ResetInitVector)() PURE;
-
- /* Call ResetInitVector() only for encoding.
- Call ResetInitVector() before encoding and before WriteCoderProperties().
- Crypto encoder can create random IV in that function. */
-};
-
-CODER_INTERFACE(ICryptoSetPassword, 0x90)
-{
- STDMETHOD(CryptoSetPassword)(const Byte *data, UInt32 size) PURE;
-};
-
-CODER_INTERFACE(ICryptoSetCRC, 0xA0)
-{
- STDMETHOD(CryptoSetCRC)(UInt32 crc) PURE;
-};
-
-
-namespace NMethodPropID
-{
- enum EEnum
- {
- kID,
- kName,
- kDecoder,
- kEncoder,
- kPackStreams,
- kUnpackStreams,
- kDescription,
- kDecoderIsAssigned,
- kEncoderIsAssigned,
- kDigestSize
- };
-}
-
-
-#define INTERFACE_IHasher(x) \
- STDMETHOD_(void, Init)() throw() x; \
- STDMETHOD_(void, Update)(const void *data, UInt32 size) throw() x; \
- STDMETHOD_(void, Final)(Byte *digest) throw() x; \
- STDMETHOD_(UInt32, GetDigestSize)() throw() x; \
-
-CODER_INTERFACE(IHasher, 0xC0)
-{
- INTERFACE_IHasher(PURE)
-};
-
-CODER_INTERFACE(IHashers, 0xC1)
-{
- STDMETHOD_(UInt32, GetNumHashers)() PURE;
- STDMETHOD(GetHasherProp)(UInt32 index, PROPID propID, PROPVARIANT *value) PURE;
- STDMETHOD(CreateHasher)(UInt32 index, IHasher **hasher) PURE;
-};
-
-extern "C"
-{
- typedef HRESULT (WINAPI *Func_GetNumberOfMethods)(UInt32 *numMethods);
- typedef HRESULT (WINAPI *Func_GetMethodProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
- typedef HRESULT (WINAPI *Func_CreateDecoder)(UInt32 index, const GUID *iid, void **outObject);
- typedef HRESULT (WINAPI *Func_CreateEncoder)(UInt32 index, const GUID *iid, void **outObject);
-
- typedef HRESULT (WINAPI *Func_GetHashers)(IHashers **hashers);
-
- typedef HRESULT (WINAPI *Func_SetCodecs)(ICompressCodecsInfo *compressCodecsInfo);
-}
-
-#endif
+// ICoder.h
+
+#ifndef ZIP7_INC_ICODER_H
+#define ZIP7_INC_ICODER_H
+
+#include "IStream.h"
+
+Z7_PURE_INTERFACES_BEGIN
+
+#define Z7_IFACE_CONSTR_CODER(i, n) \
+ Z7_DECL_IFACE_7ZIP(i, 4, n) \
+ { Z7_IFACE_COM7_PURE(i) };
+
+#define Z7_IFACEM_ICompressProgressInfo(x) \
+ x(SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
+Z7_IFACE_CONSTR_CODER(ICompressProgressInfo, 0x04)
+ /*
+ SetRatioInfo()
+ (inSize) can be NULL, if unknown
+ (outSize) can be NULL, if unknown
+ returns:
+ S_OK
+ E_ABORT : Break by user
+ another error codes
+ */
+
+#define Z7_IFACEM_ICompressCoder(x) \
+ x(Code(ISequentialInStream *inStream, ISequentialOutStream *outStream, \
+ const UInt64 *inSize, const UInt64 *outSize, \
+ ICompressProgressInfo *progress))
+Z7_IFACE_CONSTR_CODER(ICompressCoder, 0x05)
+
+#define Z7_IFACEM_ICompressCoder2(x) \
+ x(Code(ISequentialInStream * const *inStreams, const UInt64 *const *inSizes, UInt32 numInStreams, \
+ ISequentialOutStream *const *outStreams, const UInt64 *const *outSizes, UInt32 numOutStreams, \
+ ICompressProgressInfo *progress))
+Z7_IFACE_CONSTR_CODER(ICompressCoder2, 0x18)
+
+/*
+ ICompressCoder::Code
+ ICompressCoder2::Code
+
+ returns:
+ S_OK : OK
+ S_FALSE : data error (for decoders)
+ E_OUTOFMEMORY : memory allocation error
+ E_NOTIMPL : unsupported encoding method (for decoders)
+ another error code : some error. For example, it can be error code received from inStream or outStream function.
+
+ Parameters:
+ (inStream != NULL)
+ (outStream != NULL)
+
+ if (inSize != NULL)
+ {
+ Encoders in 7-Zip ignore (inSize).
+ Decoder can use (*inSize) to check that stream was decoded correctly.
+ Some decoders in 7-Zip check it, if (full_decoding mode was set via ICompressSetFinishMode)
+ }
+
+ If it's required to limit the reading from input stream (inStream), it can
+ be done with ISequentialInStream implementation.
+
+ if (outSize != NULL)
+ {
+ Encoders in 7-Zip ignore (outSize).
+ Decoder unpacks no more than (*outSize) bytes.
+ }
+
+ (progress == NULL) is allowed.
+
+
+ Decoding with Code() function
+ -----------------------------
+
+ You can request some interfaces before decoding
+ - ICompressSetDecoderProperties2
+ - ICompressSetFinishMode
+
+ If you need to decode full stream:
+ {
+ 1) try to set full_decoding mode with ICompressSetFinishMode::SetFinishMode(1);
+ 2) call the Code() function with specified (inSize) and (outSize), if these sizes are known.
+ }
+
+ If you need to decode only part of stream:
+ {
+ 1) try to set partial_decoding mode with ICompressSetFinishMode::SetFinishMode(0);
+ 2) Call the Code() function with specified (inSize = NULL) and specified (outSize).
+ }
+
+ Encoding with Code() function
+ -----------------------------
+
+ You can request some interfaces :
+ - ICompressSetCoderProperties - use it before encoding to set properties
+ - ICompressWriteCoderProperties - use it before or after encoding to request encoded properties.
+
+ ICompressCoder2 is used when (numInStreams != 1 || numOutStreams != 1)
+ The rules are similar to ICompressCoder rules
+*/
+
+
+namespace NCoderPropID
+{
+ enum EEnum
+ {
+ kDefaultProp = 0,
+ kDictionarySize, // VT_UI4
+ kUsedMemorySize, // VT_UI4
+ kOrder, // VT_UI4
+ kBlockSize, // VT_UI4 or VT_UI8
+ kPosStateBits, // VT_UI4
+ kLitContextBits, // VT_UI4
+ kLitPosBits, // VT_UI4
+ kNumFastBytes, // VT_UI4
+ kMatchFinder, // VT_BSTR
+ kMatchFinderCycles, // VT_UI4
+ kNumPasses, // VT_UI4
+ kAlgorithm, // VT_UI4
+ kNumThreads, // VT_UI4
+ kEndMarker, // VT_BOOL
+ kLevel, // VT_UI4
+ kReduceSize, // VT_UI8 : it's estimated size of largest data stream that will be compressed
+ // encoder can use this value to reduce dictionary size and allocate data buffers
+
+ kExpectedDataSize, // VT_UI8 : for ICompressSetCoderPropertiesOpt :
+ // it's estimated size of current data stream
+ // real data size can differ from that size
+ // encoder can use this value to optimize encoder initialization
+
+ kBlockSize2, // VT_UI4 or VT_UI8
+ kCheckSize, // VT_UI4 : size of digest in bytes
+ kFilter, // VT_BSTR
+ kMemUse, // VT_UI8
+ kAffinity, // VT_UI8
+ kBranchOffset, // VT_UI4
+ kHashBits, // VT_UI4
+ /*
+ // kHash3Bits, // VT_UI4
+ // kHash2Bits, // VT_UI4
+ // kChainBits, // VT_UI4
+ kChainSize, // VT_UI4
+ kNativeLevel, // VT_UI4
+ kFast, // VT_UI4
+ kMinMatch, // VT_UI4 The minimum slen is 3 and the maximum is 7.
+ kOverlapLog, // VT_UI4 The minimum ovlog is 0 and the maximum is 9. (default: 6)
+ kRowMatchFinder, // VT_BOOL
+ kLdmEnable, // VT_BOOL
+ // kLdmWindowSizeLog, // VT_UI4
+ kLdmWindowSize, // VT_UI4
+ kLdmHashLog, // VT_UI4 The minimum ldmhlog is 6 and the maximum is 26 (default: 20).
+ kLdmMinMatchLength, // VT_UI4 The minimum ldmslen is 4 and the maximum is 4096 (default: 64).
+ kLdmBucketSizeLog, // VT_UI4 The minimum ldmblog is 0 and the maximum is 8 (default: 3).
+ kLdmHashRateLog, // VT_UI4 The default value is wlog - ldmhlog.
+ kWriteUnpackSizeFlag, // VT_BOOL
+ kUsePledged, // VT_BOOL
+ kUseSizeHintPledgedForSmall, // VT_BOOL
+ kUseSizeHintForEach, // VT_BOOL
+ kUseSizeHintGlobal, // VT_BOOL
+ kParamSelectMode, // VT_UI4
+ // kSearchLog, // VT_UI4 The minimum slog is 1 and the maximum is 26
+ // kTargetLen, // VT_UI4 The minimum tlen is 0 and the maximum is 999.
+ */
+ k_NUM_DEFINED
+ };
+}
+
+#define Z7_IFACEM_ICompressSetCoderPropertiesOpt(x) \
+ x(SetCoderPropertiesOpt(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps))
+Z7_IFACE_CONSTR_CODER(ICompressSetCoderPropertiesOpt, 0x1F)
+
+
+#define Z7_IFACEM_ICompressSetCoderProperties(x) \
+ x(SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps))
+Z7_IFACE_CONSTR_CODER(ICompressSetCoderProperties, 0x20)
+
+/*
+#define Z7_IFACEM_ICompressSetDecoderProperties(x) \
+ x(SetDecoderProperties(ISequentialInStream *inStream))
+Z7_IFACE_CONSTR_CODER(ICompressSetDecoderProperties, 0x21)
+*/
+
+#define Z7_IFACEM_ICompressSetDecoderProperties2(x) \
+ x(SetDecoderProperties2(const Byte *data, UInt32 size))
+Z7_IFACE_CONSTR_CODER(ICompressSetDecoderProperties2, 0x22)
+ /* returns:
+ S_OK
+ E_NOTIMP : unsupported properties
+ E_INVALIDARG : incorrect (or unsupported) properties
+ E_OUTOFMEMORY : memory allocation error
+ */
+
+
+#define Z7_IFACEM_ICompressWriteCoderProperties(x) \
+ x(WriteCoderProperties(ISequentialOutStream *outStream))
+Z7_IFACE_CONSTR_CODER(ICompressWriteCoderProperties, 0x23)
+
+#define Z7_IFACEM_ICompressGetInStreamProcessedSize(x) \
+ x(GetInStreamProcessedSize(UInt64 *value))
+Z7_IFACE_CONSTR_CODER(ICompressGetInStreamProcessedSize, 0x24)
+
+#define Z7_IFACEM_ICompressSetCoderMt(x) \
+ x(SetNumberOfThreads(UInt32 numThreads))
+Z7_IFACE_CONSTR_CODER(ICompressSetCoderMt, 0x25)
+
+#define Z7_IFACEM_ICompressSetFinishMode(x) \
+ x(SetFinishMode(UInt32 finishMode))
+Z7_IFACE_CONSTR_CODER(ICompressSetFinishMode, 0x26)
+ /* finishMode:
+ 0 : partial decoding is allowed. It's default mode for ICompressCoder::Code(), if (outSize) is defined.
+ 1 : full decoding. The stream must be finished at the end of decoding. */
+
+#define Z7_IFACEM_ICompressGetInStreamProcessedSize2(x) \
+ x(GetInStreamProcessedSize2(UInt32 streamIndex, UInt64 *value))
+Z7_IFACE_CONSTR_CODER(ICompressGetInStreamProcessedSize2, 0x27)
+
+#define Z7_IFACEM_ICompressSetMemLimit(x) \
+ x(SetMemLimit(UInt64 memUsage))
+Z7_IFACE_CONSTR_CODER(ICompressSetMemLimit, 0x28)
+
+
+/*
+ ICompressReadUnusedFromInBuf is supported by ICoder object
+ call ReadUnusedFromInBuf() after ICoder::Code(inStream, ...).
+ ICoder::Code(inStream, ...) decodes data, and the ICoder object is allowed
+ to read from inStream to internal buffers more data than minimal data required for decoding.
+ So we can call ReadUnusedFromInBuf() from same ICoder object to read unused input
+ data from the internal buffer.
+ in ReadUnusedFromInBuf(): the Coder is not allowed to use (ISequentialInStream *inStream) object, that was sent to ICoder::Code().
+*/
+#define Z7_IFACEM_ICompressReadUnusedFromInBuf(x) \
+ x(ReadUnusedFromInBuf(void *data, UInt32 size, UInt32 *processedSize))
+Z7_IFACE_CONSTR_CODER(ICompressReadUnusedFromInBuf, 0x29)
+
+
+#define Z7_IFACEM_ICompressGetSubStreamSize(x) \
+ x(GetSubStreamSize(UInt64 subStream, UInt64 *value))
+Z7_IFACE_CONSTR_CODER(ICompressGetSubStreamSize, 0x30)
+ /* returns:
+ S_OK : (*value) contains the size or estimated size (can be incorrect size)
+ S_FALSE : size is undefined
+ E_NOTIMP : the feature is not implemented
+ Let's (read_size) is size of data that was already read by ISequentialInStream::Read().
+ The caller should call GetSubStreamSize() after each Read() and check sizes:
+ if (start_of_subStream + *value < read_size)
+ {
+ // (*value) is correct, and it's allowed to call GetSubStreamSize() for next subStream:
+ start_of_subStream += *value;
+ subStream++;
+ }
+ */
+
+#define Z7_IFACEM_ICompressSetInStream(x) \
+ x(SetInStream(ISequentialInStream *inStream)) \
+ x(ReleaseInStream())
+Z7_IFACE_CONSTR_CODER(ICompressSetInStream, 0x31)
+
+#define Z7_IFACEM_ICompressSetOutStream(x) \
+ x(SetOutStream(ISequentialOutStream *outStream)) \
+ x(ReleaseOutStream())
+Z7_IFACE_CONSTR_CODER(ICompressSetOutStream, 0x32)
+
+/*
+#define Z7_IFACEM_ICompressSetInStreamSize(x) \
+ x(SetInStreamSize(const UInt64 *inSize)) \
+Z7_IFACE_CONSTR_CODER(ICompressSetInStreamSize, 0x33)
+*/
+
+#define Z7_IFACEM_ICompressSetOutStreamSize(x) \
+ x(SetOutStreamSize(const UInt64 *outSize))
+Z7_IFACE_CONSTR_CODER(ICompressSetOutStreamSize, 0x34)
+ /* That function initializes decoder structures.
+ Call this function only for stream version of decoder.
+ if (outSize == NULL), then output size is unknown
+ if (outSize != NULL), then the decoder must stop decoding after (*outSize) bytes. */
+
+#define Z7_IFACEM_ICompressSetBufSize(x) \
+ x(SetInBufSize(UInt32 streamIndex, UInt32 size)) \
+ x(SetOutBufSize(UInt32 streamIndex, UInt32 size))
+
+Z7_IFACE_CONSTR_CODER(ICompressSetBufSize, 0x35)
+
+#define Z7_IFACEM_ICompressInitEncoder(x) \
+ x(InitEncoder())
+Z7_IFACE_CONSTR_CODER(ICompressInitEncoder, 0x36)
+ /* That function initializes encoder structures.
+ Call this function only for stream version of encoder. */
+
+#define Z7_IFACEM_ICompressSetInStream2(x) \
+ x(SetInStream2(UInt32 streamIndex, ISequentialInStream *inStream)) \
+ x(ReleaseInStream2(UInt32 streamIndex))
+Z7_IFACE_CONSTR_CODER(ICompressSetInStream2, 0x37)
+
+/*
+#define Z7_IFACEM_ICompressSetOutStream2(x) \
+ x(SetOutStream2(UInt32 streamIndex, ISequentialOutStream *outStream))
+ x(ReleaseOutStream2(UInt32 streamIndex))
+Z7_IFACE_CONSTR_CODER(ICompressSetOutStream2, 0x38)
+
+#define Z7_IFACEM_ICompressSetInStreamSize2(x) \
+ x(SetInStreamSize2(UInt32 streamIndex, const UInt64 *inSize))
+Z7_IFACE_CONSTR_CODER(ICompressSetInStreamSize2, 0x39)
+*/
+
+/*
+#define Z7_IFACEM_ICompressInSubStreams(x) \
+ x(GetNextInSubStream(UInt64 *streamIndexRes, ISequentialInStream **stream))
+Z7_IFACE_CONSTR_CODER(ICompressInSubStreams, 0x3A)
+
+#define Z7_IFACEM_ICompressOutSubStreams(x) \
+ x(GetNextOutSubStream(UInt64 *streamIndexRes, ISequentialOutStream **stream))
+Z7_IFACE_CONSTR_CODER(ICompressOutSubStreams, 0x3B)
+*/
+
+/*
+ ICompressFilter
+ Filter(Byte *data, UInt32 size)
+ (size)
+ converts as most as possible bytes required for fast processing.
+ Some filters have (smallest_fast_block).
+ For example, (smallest_fast_block == 16) for AES CBC/CTR filters.
+ If data stream is not finished, caller must call Filter() for larger block:
+ where (size >= smallest_fast_block).
+ if (size >= smallest_fast_block)
+ {
+ The filter can leave some bytes at the end of data without conversion:
+ if there are data alignment reasons or speed reasons.
+ The caller can read additional data from stream and call Filter() again.
+ }
+ If data stream was finished, caller can call Filter() for (size < smallest_fast_block)
+
+ (data) parameter:
+ Some filters require alignment for any Filter() call:
+ 1) (stream_offset % alignment_size) == (data % alignment_size)
+ 2) (alignment_size == 2^N)
+ where (stream_offset) - is the number of bytes that were already filtered before.
+ The callers of Filter() are required to meet these requirements.
+ (alignment_size) can be different:
+ 16 : for AES filters
+ 4 or 2 : for some branch convert filters
+ 1 : for another filters
+ (alignment_size >= 16) is enough for all current filters of 7-Zip.
+ But the caller can use larger (alignment_size).
+ Recommended alignment for (data) of Filter() call is (alignment_size == 64).
+ Also it's recommended to use aligned value for (size):
+ (size % alignment_size == 0),
+ if it's not last call of Filter() for current stream.
+
+ returns: (outSize):
+ if (outSize == 0) : Filter have not converted anything.
+ So the caller can stop processing, if data stream was finished.
+ if (outSize <= size) : Filter have converted outSize bytes
+ if (outSize > size) : Filter have not converted anything.
+ and it needs at least outSize bytes to convert one block
+ (it's for crypto block algorithms).
+*/
+
+#define Z7_IFACEM_ICompressFilter(x) \
+ x(Init()) \
+ x##2(UInt32, Filter(Byte *data, UInt32 size))
+Z7_IFACE_CONSTR_CODER(ICompressFilter, 0x40)
+
+
+#define Z7_IFACEM_ICompressCodecsInfo(x) \
+ x(GetNumMethods(UInt32 *numMethods)) \
+ x(GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)) \
+ x(CreateDecoder(UInt32 index, const GUID *iid, void* *coder)) \
+ x(CreateEncoder(UInt32 index, const GUID *iid, void* *coder))
+Z7_IFACE_CONSTR_CODER(ICompressCodecsInfo, 0x60)
+
+#define Z7_IFACEM_ISetCompressCodecsInfo(x) \
+ x(SetCompressCodecsInfo(ICompressCodecsInfo *compressCodecsInfo))
+Z7_IFACE_CONSTR_CODER(ISetCompressCodecsInfo, 0x61)
+
+#define Z7_IFACEM_ICryptoProperties(x) \
+ x(SetKey(const Byte *data, UInt32 size)) \
+ x(SetInitVector(const Byte *data, UInt32 size))
+Z7_IFACE_CONSTR_CODER(ICryptoProperties, 0x80)
+
+/*
+ x(ResetSalt())
+Z7_IFACE_CONSTR_CODER(ICryptoResetSalt, 0x88)
+*/
+
+#define Z7_IFACEM_ICryptoResetInitVector(x) \
+ x(ResetInitVector())
+Z7_IFACE_CONSTR_CODER(ICryptoResetInitVector, 0x8C)
+ /* Call ResetInitVector() only for encoding.
+ Call ResetInitVector() before encoding and before WriteCoderProperties().
+ Crypto encoder can create random IV in that function. */
+
+#define Z7_IFACEM_ICryptoSetPassword(x) \
+ x(CryptoSetPassword(const Byte *data, UInt32 size))
+Z7_IFACE_CONSTR_CODER(ICryptoSetPassword, 0x90)
+
+#define Z7_IFACEM_ICryptoSetCRC(x) \
+ x(CryptoSetCRC(UInt32 crc))
+Z7_IFACE_CONSTR_CODER(ICryptoSetCRC, 0xA0)
+
+
+namespace NMethodPropID
+{
+ enum EEnum
+ {
+ kID,
+ kName,
+ kDecoder,
+ kEncoder,
+ kPackStreams,
+ kUnpackStreams,
+ kDescription,
+ kDecoderIsAssigned,
+ kEncoderIsAssigned,
+ kDigestSize,
+ kIsFilter
+ };
+}
+
+namespace NModuleInterfaceType
+{
+ /*
+ virtual destructor in IUnknown:
+ - no : 7-Zip (Windows)
+ - no : 7-Zip (Linux) (v23) in default mode
+ - yes : p7zip
+ - yes : 7-Zip (Linux) before v23
+ - yes : 7-Zip (Linux) (v23), if Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN is defined
+ */
+ const UInt32 k_IUnknown_VirtDestructor_No = 0;
+ const UInt32 k_IUnknown_VirtDestructor_Yes = 1;
+ const UInt32 k_IUnknown_VirtDestructor_ThisModule =
+ #if !defined(_WIN32) && defined(Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN)
+ k_IUnknown_VirtDestructor_Yes;
+ #else
+ k_IUnknown_VirtDestructor_No;
+ #endif
+}
+
+namespace NModulePropID
+{
+ enum EEnum
+ {
+ kInterfaceType, // VT_UI4
+ kVersion // VT_UI4
+ };
+}
+
+
+#define Z7_IFACEM_IHasher(x) \
+ x##2(void, Init()) \
+ x##2(void, Update(const void *data, UInt32 size)) \
+ x##2(void, Final(Byte *digest)) \
+ x##2(UInt32, GetDigestSize())
+Z7_IFACE_CONSTR_CODER(IHasher, 0xC0)
+
+#define Z7_IFACEM_IHashers(x) \
+ x##2(UInt32, GetNumHashers()) \
+ x(GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)) \
+ x(CreateHasher(UInt32 index, IHasher **hasher))
+Z7_IFACE_CONSTR_CODER(IHashers, 0xC1)
+
+extern "C"
+{
+ typedef HRESULT (WINAPI *Func_GetNumberOfMethods)(UInt32 *numMethods);
+ typedef HRESULT (WINAPI *Func_GetMethodProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
+ typedef HRESULT (WINAPI *Func_CreateDecoder)(UInt32 index, const GUID *iid, void **outObject);
+ typedef HRESULT (WINAPI *Func_CreateEncoder)(UInt32 index, const GUID *iid, void **outObject);
+
+ typedef HRESULT (WINAPI *Func_GetHashers)(IHashers **hashers);
+
+ typedef HRESULT (WINAPI *Func_SetCodecs)(ICompressCodecsInfo *compressCodecsInfo);
+ typedef HRESULT (WINAPI *Func_GetModuleProp)(PROPID propID, PROPVARIANT *value);
+}
+
+Z7_PURE_INTERFACES_END
+#endif
diff --git a/CPP/7zip/IDecl.h b/CPP/7zip/IDecl.h
index 5a34b0e..c4d4541 100644
--- a/CPP/7zip/IDecl.h
+++ b/CPP/7zip/IDecl.h
@@ -1,28 +1,76 @@
-// IDecl.h
-
-#ifndef __IDECL_H
-#define __IDECL_H
-
-#include "../Common/MyUnknown.h"
-
-#define k_7zip_GUID_Data1 0x23170F69
-#define k_7zip_GUID_Data2 0x40C1
-
-#define k_7zip_GUID_Data3_Common 0x278A
-
-#define k_7zip_GUID_Data3_Decoder 0x2790
-#define k_7zip_GUID_Data3_Encoder 0x2791
-#define k_7zip_GUID_Data3_Hasher 0x2792
-
-
-#define DECL_INTERFACE_SUB(i, base, groupId, subId) \
- DEFINE_GUID(IID_ ## i, \
- k_7zip_GUID_Data1, \
- k_7zip_GUID_Data2, \
- k_7zip_GUID_Data3_Common, \
- 0, 0, 0, (groupId), 0, (subId), 0, 0); \
- struct i: public base
-
-#define DECL_INTERFACE(i, groupId, subId) DECL_INTERFACE_SUB(i, IUnknown, groupId, subId)
-
-#endif
+// IDecl.h
+
+#ifndef ZIP7_INC_IDECL_H
+#define ZIP7_INC_IDECL_H
+
+#include "../Common/Common.h"
+#include "../Common/MyUnknown.h"
+
+#define k_7zip_GUID_Data1 0x23170F69
+#define k_7zip_GUID_Data2 0x40C1
+
+#define k_7zip_GUID_Data3_Common 0x278A
+
+#define k_7zip_GUID_Data3_Decoder 0x2790
+#define k_7zip_GUID_Data3_Encoder 0x2791
+#define k_7zip_GUID_Data3_Hasher 0x2792
+
+#define Z7_DECL_IFACE_7ZIP_SUB(i, _base, groupId, subId) \
+ Z7_DEFINE_GUID(IID_ ## i, \
+ k_7zip_GUID_Data1, \
+ k_7zip_GUID_Data2, \
+ k_7zip_GUID_Data3_Common, \
+ 0, 0, 0, (groupId), 0, (subId), 0, 0); \
+ struct Z7_DECLSPEC_NOVTABLE i: public _base
+
+#define Z7_DECL_IFACE_7ZIP(i, groupId, subId) \
+ Z7_DECL_IFACE_7ZIP_SUB(i, IUnknown, groupId, subId)
+
+
+#ifdef COM_DECLSPEC_NOTHROW
+#define Z7_COMWF_B COM_DECLSPEC_NOTHROW STDMETHODIMP
+#define Z7_COMWF_B_(t) COM_DECLSPEC_NOTHROW STDMETHODIMP_(t)
+#else
+#define Z7_COMWF_B STDMETHODIMP
+#define Z7_COMWF_B_(t) STDMETHODIMP_(t)
+#endif
+
+#if defined(_MSC_VER) && !defined(COM_DECLSPEC_NOTHROW)
+#define Z7_COM7F_B __declspec(nothrow) STDMETHODIMP
+#define Z7_COM7F_B_(t) __declspec(nothrow) STDMETHODIMP_(t)
+#else
+#define Z7_COM7F_B Z7_COMWF_B
+#define Z7_COM7F_B_(t) Z7_COMWF_B_(t)
+#endif
+
+// #define Z7_COM7F_E Z7_noexcept
+#define Z7_COM7F_E throw()
+#define Z7_COM7F_EO Z7_COM7F_E Z7_override
+#define Z7_COM7F_EOF Z7_COM7F_EO Z7_final
+#define Z7_COM7F_IMF(f) Z7_COM7F_B f Z7_COM7F_E
+#define Z7_COM7F_IMF2(t, f) Z7_COM7F_B_(t) f Z7_COM7F_E
+
+#define Z7_COM7F_PURE(f) virtual Z7_COM7F_IMF(f) =0;
+#define Z7_COM7F_PURE2(t, f) virtual Z7_COM7F_IMF2(t, f) =0;
+#define Z7_COM7F_IMP(f) Z7_COM7F_IMF(f) Z7_override Z7_final;
+#define Z7_COM7F_IMP2(t, f) Z7_COM7F_IMF2(t, f) Z7_override Z7_final;
+#define Z7_COM7F_IMP_NONFINAL(f) Z7_COM7F_IMF(f) Z7_override;
+#define Z7_COM7F_IMP_NONFINAL2(t, f) Z7_COM7F_IMF2(t, f) Z7_override;
+
+#define Z7_IFACE_PURE(name) Z7_IFACEN_ ## name(=0;)
+#define Z7_IFACE_IMP(name) Z7_IFACEN_ ## name(Z7_override Z7_final;)
+
+#define Z7_IFACE_COM7_PURE(name) Z7_IFACEM_ ## name(Z7_COM7F_PURE)
+#define Z7_IFACE_COM7_IMP(name) Z7_IFACEM_ ## name(Z7_COM7F_IMP)
+#define Z7_IFACE_COM7_IMP_NONFINAL(name) Z7_IFACEM_ ## name(Z7_COM7F_IMP_NONFINAL)
+
+
+#define Z7_IFACE_DECL_PURE(name) \
+ DECLARE_INTERFACE(name) \
+ { Z7_IFACE_PURE(name) };
+
+#define Z7_IFACE_DECL_PURE_(name, baseiface) \
+ DECLARE_INTERFACE_(name, baseiface) \
+ { Z7_IFACE_PURE(name) };
+
+#endif
diff --git a/CPP/7zip/IPassword.h b/CPP/7zip/IPassword.h
index e366007..689f08c 100644
--- a/CPP/7zip/IPassword.h
+++ b/CPP/7zip/IPassword.h
@@ -1,23 +1,54 @@
-// IPassword.h
-
-#ifndef __IPASSWORD_H
-#define __IPASSWORD_H
-
-#include "../Common/MyTypes.h"
-#include "../Common/MyUnknown.h"
-
-#include "IDecl.h"
-
-#define PASSWORD_INTERFACE(i, x) DECL_INTERFACE(i, 5, x)
-
-PASSWORD_INTERFACE(ICryptoGetTextPassword, 0x10)
-{
- STDMETHOD(CryptoGetTextPassword)(BSTR *password) PURE;
-};
-
-PASSWORD_INTERFACE(ICryptoGetTextPassword2, 0x11)
-{
- STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password) PURE;
-};
-
-#endif
+// IPassword.h
+
+#ifndef ZIP7_INC_IPASSWORD_H
+#define ZIP7_INC_IPASSWORD_H
+
+#include "../Common/MyTypes.h"
+
+#include "IDecl.h"
+
+Z7_PURE_INTERFACES_BEGIN
+
+#define Z7_IFACE_CONSTR_PASSWORD(i, n) \
+ Z7_DECL_IFACE_7ZIP(i, 5, n) \
+ { Z7_IFACE_COM7_PURE(i) };
+
+/*
+How to use output parameter (BSTR *password):
+
+in: The caller is required to set BSTR value as NULL (no string).
+ The callee (in 7-Zip code) ignores the input value stored in BSTR variable,
+
+out: The callee rewrites BSTR variable (*password) with new allocated string pointer.
+ The caller must free BSTR string with function SysFreeString();
+*/
+
+#define Z7_IFACEM_ICryptoGetTextPassword(x) \
+ x(CryptoGetTextPassword(BSTR *password))
+Z7_IFACE_CONSTR_PASSWORD(ICryptoGetTextPassword, 0x10)
+
+
+/*
+CryptoGetTextPassword2()
+in:
+ The caller is required to set BSTR value as NULL (no string).
+ The caller is not required to set (*passwordIsDefined) value.
+
+out:
+ Return code: != S_OK : error code
+ Return code: S_OK : success
+
+ if (*passwordIsDefined == 1), the variable (*password) contains password string
+
+ if (*passwordIsDefined == 0), the password is not defined,
+ but the callee still could set (*password) to some allocated string, for example, as empty string.
+
+ The caller must free BSTR string with function SysFreeString()
+*/
+
+#define Z7_IFACEM_ICryptoGetTextPassword2(x) \
+ x(CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password))
+Z7_IFACE_CONSTR_PASSWORD(ICryptoGetTextPassword2, 0x11)
+
+Z7_PURE_INTERFACES_END
+#endif
diff --git a/CPP/7zip/IProgress.h b/CPP/7zip/IProgress.h
index d54529c..6714983 100644
--- a/CPP/7zip/IProgress.h
+++ b/CPP/7zip/IProgress.h
@@ -1,19 +1,20 @@
-// IProgress.h
-
-#ifndef __IPROGRESS_H
-#define __IPROGRESS_H
-
-#include "../Common/MyTypes.h"
-
-#include "IDecl.h"
-
-#define INTERFACE_IProgress(x) \
- STDMETHOD(SetTotal)(UInt64 total) x; \
- STDMETHOD(SetCompleted)(const UInt64 *completeValue) x; \
-
-DECL_INTERFACE(IProgress, 0, 5)
-{
- INTERFACE_IProgress(PURE)
-};
-
-#endif
+// IProgress.h
+
+#ifndef ZIP7_INC_IPROGRESS_H
+#define ZIP7_INC_IPROGRESS_H
+
+#include "../Common/MyTypes.h"
+
+#include "IDecl.h"
+
+Z7_PURE_INTERFACES_BEGIN
+
+#define Z7_IFACEM_IProgress(x) \
+ x(SetTotal(UInt64 total)) \
+ x(SetCompleted(const UInt64 *completeValue)) \
+
+Z7_DECL_IFACE_7ZIP(IProgress, 0, 5)
+ { Z7_IFACE_COM7_PURE(IProgress) };
+
+Z7_PURE_INTERFACES_END
+#endif
diff --git a/CPP/7zip/IStream.h b/CPP/7zip/IStream.h
index 436e919..4a58bc9 100644
--- a/CPP/7zip/IStream.h
+++ b/CPP/7zip/IStream.h
@@ -1,127 +1,207 @@
-// IStream.h
-
-#ifndef __ISTREAM_H
-#define __ISTREAM_H
-
-#include "../Common/MyTypes.h"
-#include "../Common/MyWindows.h"
-
-#include "IDecl.h"
-
-#define STREAM_INTERFACE_SUB(i, base, x) DECL_INTERFACE_SUB(i, base, 3, x)
-#define STREAM_INTERFACE(i, x) STREAM_INTERFACE_SUB(i, IUnknown, x)
-
-STREAM_INTERFACE(ISequentialInStream, 0x01)
-{
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize) PURE;
-
- /*
- The requirement for caller: (processedSize != NULL).
- The callee can allow (processedSize == NULL) for compatibility reasons.
-
- if (size == 0), this function returns S_OK and (*processedSize) is set to 0.
-
- if (size != 0)
- {
- Partial read is allowed: (*processedSize <= avail_size && *processedSize <= size),
- where (avail_size) is the size of remaining bytes in stream.
- If (avail_size != 0), this function must read at least 1 byte: (*processedSize > 0).
- You must call Read() in loop, if you need to read exact amount of data.
- }
-
- If seek pointer before Read() call was changed to position past the end of stream:
- if (seek_pointer >= stream_size), this function returns S_OK and (*processedSize) is set to 0.
-
- ERROR CASES:
- If the function returns error code, then (*processedSize) is size of
- data written to (data) buffer (it can be data before error or data with errors).
- The recommended way for callee to work with reading errors:
- 1) write part of data before error to (data) buffer and return S_OK.
- 2) return error code for further calls of Read().
- */
-};
-
-STREAM_INTERFACE(ISequentialOutStream, 0x02)
-{
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize) PURE;
-
- /*
- The requirement for caller: (processedSize != NULL).
- The callee can allow (processedSize == NULL) for compatibility reasons.
-
- if (size != 0)
- {
- Partial write is allowed: (*processedSize <= size),
- but this function must write at least 1 byte: (*processedSize > 0).
- You must call Write() in loop, if you need to write exact amount of data.
- }
-
- ERROR CASES:
- If the function returns error code, then (*processedSize) is size of
- data written from (data) buffer.
- */
-};
-
-#ifdef __HRESULT_FROM_WIN32
-#define HRESULT_WIN32_ERROR_NEGATIVE_SEEK __HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK)
-#else
-#define HRESULT_WIN32_ERROR_NEGATIVE_SEEK HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK)
-#endif
-
-/* Seek() Function
- If you seek before the beginning of the stream, Seek() function returns error code:
- Recommended error code is __HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK).
- or STG_E_INVALIDFUNCTION
-
- It is allowed to seek past the end of the stream.
-
-
- if Seek() returns error, then the value of *newPosition is undefined.
-*/
-
-STREAM_INTERFACE_SUB(IInStream, ISequentialInStream, 0x03)
-{
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE;
-};
-
-STREAM_INTERFACE_SUB(IOutStream, ISequentialOutStream, 0x04)
-{
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition) PURE;
- STDMETHOD(SetSize)(UInt64 newSize) PURE;
-};
-
-STREAM_INTERFACE(IStreamGetSize, 0x06)
-{
- STDMETHOD(GetSize)(UInt64 *size) PURE;
-};
-
-STREAM_INTERFACE(IOutStreamFinish, 0x07)
-{
- STDMETHOD(OutStreamFinish)() PURE;
-};
-
-
-STREAM_INTERFACE(IStreamGetProps, 0x08)
-{
- STDMETHOD(GetProps)(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib) PURE;
-};
-
-struct CStreamFileProps
-{
- UInt64 Size;
- UInt64 VolID;
- UInt64 FileID_Low;
- UInt64 FileID_High;
- UInt32 NumLinks;
- UInt32 Attrib;
- FILETIME CTime;
- FILETIME ATime;
- FILETIME MTime;
-};
-
-STREAM_INTERFACE(IStreamGetProps2, 0x09)
-{
- STDMETHOD(GetProps2)(CStreamFileProps *props) PURE;
-};
-
-#endif
+// IStream.h
+
+#ifndef ZIP7_INC_ISTREAM_H
+#define ZIP7_INC_ISTREAM_H
+
+#include "../Common/MyTypes.h"
+#include "../Common/MyWindows.h"
+
+#include "IDecl.h"
+
+Z7_PURE_INTERFACES_BEGIN
+
+#define Z7_IFACE_CONSTR_STREAM_SUB(i, base, n) \
+ Z7_DECL_IFACE_7ZIP_SUB(i, base, 3, n) \
+ { Z7_IFACE_COM7_PURE(i) };
+
+#define Z7_IFACE_CONSTR_STREAM(i, n) \
+ Z7_IFACE_CONSTR_STREAM_SUB(i, IUnknown, n)
+
+
+/*
+ISequentialInStream::Read()
+ The requirement for caller: (processedSize != NULL).
+ The callee can allow (processedSize == NULL) for compatibility reasons.
+
+ if (size == 0), this function returns S_OK and (*processedSize) is set to 0.
+
+ if (size != 0)
+ {
+ Partial read is allowed: (*processedSize <= avail_size && *processedSize <= size),
+ where (avail_size) is the size of remaining bytes in stream.
+ If (avail_size != 0), this function must read at least 1 byte: (*processedSize > 0).
+ You must call Read() in loop, if you need to read exact amount of data.
+ }
+
+ If seek pointer before Read() call was changed to position past the end of stream:
+ if (seek_pointer >= stream_size), this function returns S_OK and (*processedSize) is set to 0.
+
+ ERROR CASES:
+ If the function returns error code, then (*processedSize) is size of
+ data written to (data) buffer (it can be data before error or data with errors).
+ The recommended way for callee to work with reading errors:
+ 1) write part of data before error to (data) buffer and return S_OK.
+ 2) return error code for further calls of Read().
+*/
+#define Z7_IFACEM_ISequentialInStream(x) \
+ x(Read(void *data, UInt32 size, UInt32 *processedSize))
+Z7_IFACE_CONSTR_STREAM(ISequentialInStream, 0x01)
+
+
+/*
+ISequentialOutStream::Write()
+ The requirement for caller: (processedSize != NULL).
+ The callee can allow (processedSize == NULL) for compatibility reasons.
+
+ if (size != 0)
+ {
+ Partial write is allowed: (*processedSize <= size),
+ but this function must write at least 1 byte: (*processedSize > 0).
+ You must call Write() in loop, if you need to write exact amount of data.
+ }
+
+ ERROR CASES:
+ If the function returns error code, then (*processedSize) is size of
+ data written from (data) buffer.
+*/
+#define Z7_IFACEM_ISequentialOutStream(x) \
+ x(Write(const void *data, UInt32 size, UInt32 *processedSize))
+Z7_IFACE_CONSTR_STREAM(ISequentialOutStream, 0x02)
+
+
+#ifdef _WIN32
+
+#ifdef __HRESULT_FROM_WIN32
+#define HRESULT_WIN32_ERROR_NEGATIVE_SEEK __HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK)
+#else
+#define HRESULT_WIN32_ERROR_NEGATIVE_SEEK HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK)
+#endif
+
+#else
+
+#define HRESULT_WIN32_ERROR_NEGATIVE_SEEK MY_E_ERROR_NEGATIVE_SEEK
+
+#endif
+
+
+/*
+IInStream::Seek() / IOutStream::Seek()
+ If you seek to position before the beginning of the stream,
+ Seek() function returns error code:
+ Recommended error code is __HRESULT_FROM_WIN32(ERROR_NEGATIVE_SEEK).
+ or STG_E_INVALIDFUNCTION
+ It is allowed to seek past the end of the stream.
+ if Seek() returns error, then the value of *newPosition is undefined.
+*/
+
+#define Z7_IFACEM_IInStream(x) \
+ x(Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+Z7_IFACE_CONSTR_STREAM_SUB(IInStream, ISequentialInStream, 0x03)
+
+#define Z7_IFACEM_IOutStream(x) \
+ x(Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)) \
+ x(SetSize(UInt64 newSize))
+Z7_IFACE_CONSTR_STREAM_SUB(IOutStream, ISequentialOutStream, 0x04)
+
+#define Z7_IFACEM_IStreamGetSize(x) \
+ x(GetSize(UInt64 *size))
+Z7_IFACE_CONSTR_STREAM(IStreamGetSize, 0x06)
+
+#define Z7_IFACEM_IOutStreamFinish(x) \
+ x(OutStreamFinish())
+Z7_IFACE_CONSTR_STREAM(IOutStreamFinish, 0x07)
+
+#define Z7_IFACEM_IStreamGetProps(x) \
+ x(GetProps(UInt64 *size, FILETIME *cTime, FILETIME *aTime, FILETIME *mTime, UInt32 *attrib))
+Z7_IFACE_CONSTR_STREAM(IStreamGetProps, 0x08)
+
+
+struct CStreamFileProps
+{
+ UInt64 Size;
+ UInt64 VolID;
+ UInt64 FileID_Low;
+ UInt64 FileID_High;
+ UInt32 NumLinks;
+ UInt32 Attrib;
+ FILETIME CTime;
+ FILETIME ATime;
+ FILETIME MTime;
+};
+
+
+#define Z7_IFACEM_IStreamGetProps2(x) \
+ x(GetProps2(CStreamFileProps *props))
+Z7_IFACE_CONSTR_STREAM(IStreamGetProps2, 0x09)
+
+#define Z7_IFACEM_IStreamGetProp(x) \
+ x(GetProperty(PROPID propID, PROPVARIANT *value)) \
+ x(ReloadProps())
+Z7_IFACE_CONSTR_STREAM(IStreamGetProp, 0x0a)
+
+
+/*
+IStreamSetRestriction::SetRestriction(UInt64 begin, UInt64 end)
+
+ It sets region of data in output stream that is restricted.
+ For restricted region it's expected (or allowed)
+ to change data with different calls of Write()/SetSize().
+ Another regions of output stream will be supposed as non-restricted:
+ - The callee usually doesn't flush the data in restricted region.
+ - The callee usually can flush data from non-restricted region.
+
+inputs:
+
+ (begin > end) is not allowed, and returns E_FAIL;
+
+ if (begin == end)
+ {
+ it means that there is no region restriction for flushing.
+ The callee is allowed to flush already written data and
+ is allowed to flush all data in future calls of
+ ISequentialOutStream::Write(), but before next call of SetRestriction().
+ The pair of values (begin == 0 && end == 0) is recommended to
+ remove all restrictions.
+ }
+
+ if (begin < end)
+ {
+ it means that callee must NOT to flush any data in region [begin, end).
+ The caller is allowed to Seek() to that region and rewrite the
+ data in that restriction region.
+ if (end == (UInt64(Int64)-1)
+ {
+ there is no upper bound for restricted region.
+ So non-restricted region will be [0, begin) in that case
+ }
+
+ Note: it's not expected that some already written region was marked as
+ non-restricted by old call SetRestriction() and later the part of
+ that region was marked as restricted with new call SetRestriction().
+ For example, for different calls with non-empty restricted regions:
+ (begin_new >= begin_old) is expected :
+ {
+ SetRestriction(begin_old, ...)
+ ...
+ SetRestriction(begin_new, ...)
+ }
+ }
+
+ returns:
+ - if (begin > end) it return ERROR code (E_FAIL)
+ - S_OK : if no errors.
+ - Also the call of SetRestriction() can initiate the flushing of already written data.
+ So it can return the result of that flushing.
+
+ Note: IOutStream::SetSize() also can change the data.
+ So it's not expected the call
+ IOutStream::SetSize() to unrestricted already written region.
+*/
+
+#define Z7_IFACEM_IStreamSetRestriction(x) \
+ x(SetRestriction(UInt64 begin, UInt64 end)) \
+
+Z7_IFACE_CONSTR_STREAM(IStreamSetRestriction, 0x10)
+
+Z7_PURE_INTERFACES_END
+#endif
diff --git a/CPP/7zip/LzFindOpt.mak b/CPP/7zip/LzFindOpt.mak
new file mode 100644
index 0000000..169e10f
--- /dev/null
+++ b/CPP/7zip/LzFindOpt.mak
@@ -0,0 +1,7 @@
+!IF defined(USE_C_LZFINDOPT) || "$(PLATFORM)" != "x64"
+C_OBJS = $(C_OBJS) \
+ $O\LzFindOpt.obj
+!ELSE
+ASM_OBJS = $(ASM_OBJS) \
+ $O\LzFindOpt.obj
+!ENDIF
diff --git a/CPP/7zip/LzmaDec.mak b/CPP/7zip/LzmaDec.mak
index 9aa3086..3beb505 100644
--- a/CPP/7zip/LzmaDec.mak
+++ b/CPP/7zip/LzmaDec.mak
@@ -1,5 +1,7 @@
-!IF "$(PLATFORM)" == "x64"
-CFLAGS_C_SPEC = -D_LZMA_DEC_OPT
-ASM_OBJS = $(ASM_OBJS) \
- $O\LzmaDecOpt.obj
-!ENDIF
+!IF "$(PLATFORM)" == "x64"
+!IFNDEF NO_ASM
+CFLAGS_C_SPEC = -DZ7_LZMA_DEC_OPT
+ASM_OBJS = $(ASM_OBJS) \
+ $O\LzmaDecOpt.obj
+!ENDIF
+!ENDIF
diff --git a/CPP/7zip/LzmaDec_gcc.mak b/CPP/7zip/LzmaDec_gcc.mak
new file mode 100644
index 0000000..51924f5
--- /dev/null
+++ b/CPP/7zip/LzmaDec_gcc.mak
@@ -0,0 +1,14 @@
+ifdef USE_ASM
+ifdef IS_X64
+USE_LZMA_DEC_ASM=1
+endif
+ifdef IS_ARM64
+USE_LZMA_DEC_ASM=1
+endif
+endif
+
+ifdef USE_LZMA_DEC_ASM
+
+LZMA_DEC_OPT_OBJS= $O/LzmaDecOpt.o
+
+endif
diff --git a/CPP/7zip/MyVersion.h b/CPP/7zip/MyVersion.h
index 0d50f94..8f52a12 100644
--- a/CPP/7zip/MyVersion.h
+++ b/CPP/7zip/MyVersion.h
@@ -1,2 +1,2 @@
-#define USE_COPYRIGHT_CR
-#include "../../C/7zVersion.h"
+#define USE_COPYRIGHT_CR
+#include "../../C/7zVersion.h"
diff --git a/CPP/7zip/MyVersionInfo.rc b/CPP/7zip/MyVersionInfo.rc
index eddf893..fc63d79 100644
--- a/CPP/7zip/MyVersionInfo.rc
+++ b/CPP/7zip/MyVersionInfo.rc
@@ -1,2 +1,2 @@
-#include "MyVersion.h"
-#include "..\..\C\7zVersion.rc"
+#include "MyVersion.h"
+#include "../../C/7zVersion.rc"
diff --git a/CPP/7zip/PropID.h b/CPP/7zip/PropID.h
index 126af67..e074794 100644
--- a/CPP/7zip/PropID.h
+++ b/CPP/7zip/PropID.h
@@ -1,127 +1,178 @@
-// PropID.h
-
-#ifndef __7ZIP_PROP_ID_H
-#define __7ZIP_PROP_ID_H
-
-#include "../Common/MyTypes.h"
-
-enum
-{
- kpidNoProperty = 0,
- kpidMainSubfile,
- kpidHandlerItemIndex,
- kpidPath,
- kpidName,
- kpidExtension,
- kpidIsDir,
- kpidSize,
- kpidPackSize,
- kpidAttrib,
- kpidCTime,
- kpidATime,
- kpidMTime,
- kpidSolid,
- kpidCommented,
- kpidEncrypted,
- kpidSplitBefore,
- kpidSplitAfter,
- kpidDictionarySize,
- kpidCRC,
- kpidType,
- kpidIsAnti,
- kpidMethod,
- kpidHostOS,
- kpidFileSystem,
- kpidUser,
- kpidGroup,
- kpidBlock,
- kpidComment,
- kpidPosition,
- kpidPrefix,
- kpidNumSubDirs,
- kpidNumSubFiles,
- kpidUnpackVer,
- kpidVolume,
- kpidIsVolume,
- kpidOffset,
- kpidLinks,
- kpidNumBlocks,
- kpidNumVolumes,
- kpidTimeType,
- kpidBit64,
- kpidBigEndian,
- kpidCpu,
- kpidPhySize,
- kpidHeadersSize,
- kpidChecksum,
- kpidCharacts,
- kpidVa,
- kpidId,
- kpidShortName,
- kpidCreatorApp,
- kpidSectorSize,
- kpidPosixAttrib,
- kpidSymLink,
- kpidError,
- kpidTotalSize,
- kpidFreeSpace,
- kpidClusterSize,
- kpidVolumeName,
- kpidLocalName,
- kpidProvider,
- kpidNtSecure,
- kpidIsAltStream,
- kpidIsAux,
- kpidIsDeleted,
- kpidIsTree,
- kpidSha1,
- kpidSha256,
- kpidErrorType,
- kpidNumErrors,
- kpidErrorFlags,
- kpidWarningFlags,
- kpidWarning,
- kpidNumStreams,
- kpidNumAltStreams,
- kpidAltStreamsSize,
- kpidVirtualSize,
- kpidUnpackSize,
- kpidTotalPhySize,
- kpidVolumeIndex,
- kpidSubType,
- kpidShortComment,
- kpidCodePage,
- kpidIsNotArcType,
- kpidPhySizeCantBeDetected,
- kpidZerosTailIsAllowed,
- kpidTailSize,
- kpidEmbeddedStubSize,
- kpidNtReparse,
- kpidHardLink,
- kpidINode,
- kpidStreamId,
- kpidReadOnly,
- kpidOutName,
- kpidCopyLink,
-
- kpid_NUM_DEFINED,
-
- kpidUserDefined = 0x10000
-};
-
-extern const Byte k7z_PROPID_To_VARTYPE[kpid_NUM_DEFINED]; // VARTYPE
-
-const UInt32 kpv_ErrorFlags_IsNotArc = 1 << 0;
-const UInt32 kpv_ErrorFlags_HeadersError = 1 << 1;
-const UInt32 kpv_ErrorFlags_EncryptedHeadersError = 1 << 2;
-const UInt32 kpv_ErrorFlags_UnavailableStart = 1 << 3;
-const UInt32 kpv_ErrorFlags_UnconfirmedStart = 1 << 4;
-const UInt32 kpv_ErrorFlags_UnexpectedEnd = 1 << 5;
-const UInt32 kpv_ErrorFlags_DataAfterEnd = 1 << 6;
-const UInt32 kpv_ErrorFlags_UnsupportedMethod = 1 << 7;
-const UInt32 kpv_ErrorFlags_UnsupportedFeature = 1 << 8;
-const UInt32 kpv_ErrorFlags_DataError = 1 << 9;
-const UInt32 kpv_ErrorFlags_CrcError = 1 << 10;
-// const UInt32 kpv_ErrorFlags_Unsupported = 1 << 11;
-
-#endif
+// PropID.h
+
+#ifndef ZIP7_INC_7ZIP_PROP_ID_H
+#define ZIP7_INC_7ZIP_PROP_ID_H
+
+#include "../Common/MyTypes.h"
+
+enum
+{
+ kpidNoProperty = 0,
+ kpidMainSubfile,
+ kpidHandlerItemIndex,
+ kpidPath,
+ kpidName,
+ kpidExtension,
+ kpidIsDir,
+ kpidSize,
+ kpidPackSize,
+ kpidAttrib,
+ kpidCTime,
+ kpidATime,
+ kpidMTime,
+ kpidSolid,
+ kpidCommented,
+ kpidEncrypted,
+ kpidSplitBefore,
+ kpidSplitAfter,
+ kpidDictionarySize,
+ kpidCRC,
+ kpidType,
+ kpidIsAnti,
+ kpidMethod,
+ kpidHostOS,
+ kpidFileSystem,
+ kpidUser,
+ kpidGroup,
+ kpidBlock,
+ kpidComment,
+ kpidPosition,
+ kpidPrefix,
+ kpidNumSubDirs,
+ kpidNumSubFiles,
+ kpidUnpackVer,
+ kpidVolume,
+ kpidIsVolume,
+ kpidOffset,
+ kpidLinks,
+ kpidNumBlocks,
+ kpidNumVolumes,
+ kpidTimeType,
+ kpidBit64,
+ kpidBigEndian,
+ kpidCpu,
+ kpidPhySize,
+ kpidHeadersSize,
+ kpidChecksum,
+ kpidCharacts,
+ kpidVa,
+ kpidId,
+ kpidShortName,
+ kpidCreatorApp,
+ kpidSectorSize,
+ kpidPosixAttrib,
+ kpidSymLink,
+ kpidError,
+ kpidTotalSize,
+ kpidFreeSpace,
+ kpidClusterSize,
+ kpidVolumeName,
+ kpidLocalName,
+ kpidProvider,
+ kpidNtSecure,
+ kpidIsAltStream,
+ kpidIsAux,
+ kpidIsDeleted,
+ kpidIsTree,
+ kpidSha1,
+ kpidSha256,
+ kpidErrorType,
+ kpidNumErrors,
+ kpidErrorFlags,
+ kpidWarningFlags,
+ kpidWarning,
+ kpidNumStreams,
+ kpidNumAltStreams,
+ kpidAltStreamsSize,
+ kpidVirtualSize,
+ kpidUnpackSize,
+ kpidTotalPhySize,
+ kpidVolumeIndex,
+ kpidSubType,
+ kpidShortComment,
+ kpidCodePage,
+ kpidIsNotArcType,
+ kpidPhySizeCantBeDetected,
+ kpidZerosTailIsAllowed,
+ kpidTailSize,
+ kpidEmbeddedStubSize,
+ kpidNtReparse,
+ kpidHardLink,
+ kpidINode,
+ kpidStreamId,
+ kpidReadOnly,
+ kpidOutName,
+ kpidCopyLink,
+ kpidArcFileName,
+ kpidIsHash,
+ kpidChangeTime,
+ kpidUserId,
+ kpidGroupId,
+ kpidDeviceMajor,
+ kpidDeviceMinor,
+ kpidDevMajor,
+ kpidDevMinor,
+
+ kpid_NUM_DEFINED,
+
+ kpidUserDefined = 0x10000
+};
+
+extern const Byte k7z_PROPID_To_VARTYPE[kpid_NUM_DEFINED]; // VARTYPE
+
+const UInt32 kpv_ErrorFlags_IsNotArc = 1 << 0;
+const UInt32 kpv_ErrorFlags_HeadersError = 1 << 1;
+const UInt32 kpv_ErrorFlags_EncryptedHeadersError = 1 << 2;
+const UInt32 kpv_ErrorFlags_UnavailableStart = 1 << 3;
+const UInt32 kpv_ErrorFlags_UnconfirmedStart = 1 << 4;
+const UInt32 kpv_ErrorFlags_UnexpectedEnd = 1 << 5;
+const UInt32 kpv_ErrorFlags_DataAfterEnd = 1 << 6;
+const UInt32 kpv_ErrorFlags_UnsupportedMethod = 1 << 7;
+const UInt32 kpv_ErrorFlags_UnsupportedFeature = 1 << 8;
+const UInt32 kpv_ErrorFlags_DataError = 1 << 9;
+const UInt32 kpv_ErrorFlags_CrcError = 1 << 10;
+// const UInt32 kpv_ErrorFlags_Unsupported = 1 << 11;
+
+/*
+linux ctime :
+ file metadata was last changed.
+ changing the file modification time
+ counts as a metadata change, so will also have the side effect of updating the ctime.
+
+PROPVARIANT for timestamps in 7-Zip:
+{
+ vt = VT_FILETIME
+ wReserved1: set precision level
+ 0 : base value (backward compatibility value)
+ only filetime is used (7 digits precision).
+ wReserved2 and wReserved3 can contain random data
+ 1 : Unix (1 sec)
+ 2 : DOS (2 sec)
+ 3 : High Precision (1 ns)
+ 16 - 3 : (reserved) = 1 day
+ 16 - 2 : (reserved) = 1 hour
+ 16 - 1 : (reserved) = 1 minute
+ 16 + 0 : 1 sec (0 digits after point)
+ 16 + (1,2,3,4,5,6,7,8,9) : set subsecond precision level :
+ (number of decimal digits after point)
+ 16 + 9 : 1 ns (9 digits after point)
+ wReserved2 = ns % 100 : if (8 or 9 digits pecision)
+ = 0 : if not (8 or 9 digits pecision)
+ wReserved3 = 0;
+ filetime
+}
+
+NOTE: TAR-PAX archives created by GNU TAR don't keep
+ whole information about original level of precision,
+ and timestamp are stored in reduced form, where tail zero
+ digits after point are removed.
+ So 7-Zip can return different precision levels for different items for such TAR archives.
+*/
+
+/*
+TimePrec returned by IOutArchive::GetFileTimeType()
+is used only for updating, when we compare MTime timestamp
+from archive with timestamp from directory.
+*/
+
+#endif
diff --git a/CPP/7zip/Sha1.mak b/CPP/7zip/Sha1.mak
new file mode 100644
index 0000000..1b5f605
--- /dev/null
+++ b/CPP/7zip/Sha1.mak
@@ -0,0 +1,13 @@
+COMMON_OBJS = $(COMMON_OBJS) \
+ $O\Sha1Prepare.obj
+
+C_OBJS = $(C_OBJS) \
+ $O\Sha1.obj
+
+!IF defined(USE_C_SHA) || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64"
+C_OBJS = $(C_OBJS) \
+ $O\Sha1Opt.obj
+!ELSEIF "$(PLATFORM)" != "ia64" && "$(PLATFORM)" != "mips" && "$(PLATFORM)" != "arm" && "$(PLATFORM)" != "arm64"
+ASM_OBJS = $(ASM_OBJS) \
+ $O\Sha1Opt.obj
+!ENDIF
diff --git a/CPP/7zip/Sha256.mak b/CPP/7zip/Sha256.mak
new file mode 100644
index 0000000..0bdbcb6
--- /dev/null
+++ b/CPP/7zip/Sha256.mak
@@ -0,0 +1,13 @@
+COMMON_OBJS = $(COMMON_OBJS) \
+ $O\Sha256Prepare.obj
+
+C_OBJS = $(C_OBJS) \
+ $O\Sha256.obj
+
+!IF defined(USE_C_SHA) || "$(PLATFORM)" == "arm" || "$(PLATFORM)" == "arm64"
+C_OBJS = $(C_OBJS) \
+ $O\Sha256Opt.obj
+!ELSEIF "$(PLATFORM)" != "ia64" && "$(PLATFORM)" != "mips" && "$(PLATFORM)" != "arm" && "$(PLATFORM)" != "arm64"
+ASM_OBJS = $(ASM_OBJS) \
+ $O\Sha256Opt.obj
+!ENDIF
diff --git a/CPP/7zip/SubBuild.mak b/CPP/7zip/SubBuild.mak
index 0c49d3b..f86ce43 100644
--- a/CPP/7zip/SubBuild.mak
+++ b/CPP/7zip/SubBuild.mak
@@ -1,3 +1,3 @@
- cd $(@D)
- $(MAKE) -nologo $(TARGETS)
- cd ..
+ cd $(@D)
+ $(MAKE) -nologo $(TARGETS)
+ cd ..
diff --git a/CPP/7zip/UI/Agent/Agent.cpp b/CPP/7zip/UI/Agent/Agent.cpp
new file mode 100644
index 0000000..6761b28
--- /dev/null
+++ b/CPP/7zip/UI/Agent/Agent.cpp
@@ -0,0 +1,1966 @@
+// Agent.cpp
+
+#include "StdAfx.h"
+
+#include <wchar.h>
+
+#include "../../../../C/Sort.h"
+
+#include "../../../Common/ComTry.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/PropVariantConv.h"
+
+#ifndef Z7_ST
+#include "../../../Windows/Synchronization.h"
+#endif
+
+#include "../Common/ArchiveExtractCallback.h"
+#include "../FileManager/RegistryUtils.h"
+
+#include "Agent.h"
+
+using namespace NWindows;
+
+CCodecs *g_CodecsObj;
+
+static const bool k_keepEmptyDirPrefixes =
+ false; // 22.00
+ // true; // 21.07
+
+#ifdef Z7_EXTERNAL_CODECS
+ extern
+ CExternalCodecs g_ExternalCodecs;
+ CExternalCodecs g_ExternalCodecs;
+ extern
+ const CExternalCodecs *g_ExternalCodecs_Ptr;
+ const CExternalCodecs *g_ExternalCodecs_Ptr;
+ static CCodecs::CReleaser g_CodecsReleaser;
+#else
+ extern
+ CMyComPtr<IUnknown> g_CodecsRef;
+ CMyComPtr<IUnknown> g_CodecsRef;
+#endif
+
+#ifndef Z7_ST
+static NSynchronization::CCriticalSection g_CriticalSection;
+#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
+#else
+#define MT_LOCK
+#endif
+
+void FreeGlobalCodecs()
+{
+ MT_LOCK
+
+ #ifdef Z7_EXTERNAL_CODECS
+ if (g_CodecsObj)
+ {
+ g_CodecsObj->CloseLibs();
+ }
+ g_CodecsReleaser.Set(NULL);
+ g_CodecsObj = NULL;
+ g_ExternalCodecs.ClearAndRelease();
+ g_ExternalCodecs_Ptr = NULL;
+ #else
+ g_CodecsRef.Release();
+ #endif
+}
+
+HRESULT LoadGlobalCodecs()
+{
+ MT_LOCK
+
+ if (g_CodecsObj)
+ return S_OK;
+
+ g_CodecsObj = new CCodecs;
+
+ #ifdef Z7_EXTERNAL_CODECS
+ g_ExternalCodecs.GetCodecs = g_CodecsObj;
+ g_ExternalCodecs.GetHashers = g_CodecsObj;
+ g_CodecsReleaser.Set(g_CodecsObj);
+ #else
+ g_CodecsRef.Release();
+ g_CodecsRef = g_CodecsObj;
+ #endif
+
+ RINOK(g_CodecsObj->Load())
+ if (g_CodecsObj->Formats.IsEmpty())
+ {
+ FreeGlobalCodecs();
+ return E_NOTIMPL;
+ }
+
+ Codecs_AddHashArcHandler(g_CodecsObj);
+
+ #ifdef Z7_EXTERNAL_CODECS
+ RINOK(g_ExternalCodecs.Load())
+ g_ExternalCodecs_Ptr = &g_ExternalCodecs;
+ #endif
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CAgentFolder::GetAgentFolder(CAgentFolder **agentFolder))
+{
+ *agentFolder = this;
+ return S_OK;
+}
+
+void CAgentFolder::LoadFolder(unsigned proxyDirIndex)
+{
+ CProxyItem item;
+ item.DirIndex = proxyDirIndex;
+
+ if (_proxy2)
+ {
+ const CProxyDir2 &dir = _proxy2->Dirs[proxyDirIndex];
+ FOR_VECTOR (i, dir.Items)
+ {
+ item.Index = i;
+ _items.Add(item);
+ const CProxyFile2 &file = _proxy2->Files[dir.Items[i]];
+ if (file.DirIndex != -1)
+ LoadFolder((unsigned)file.DirIndex);
+ if (_loadAltStreams && file.AltDirIndex != -1)
+ LoadFolder((unsigned)file.AltDirIndex);
+ }
+ return;
+ }
+
+ const CProxyDir &dir = _proxy->Dirs[proxyDirIndex];
+ unsigned i;
+ for (i = 0; i < dir.SubDirs.Size(); i++)
+ {
+ item.Index = i;
+ _items.Add(item);
+ LoadFolder(dir.SubDirs[i]);
+ }
+
+ unsigned start = dir.SubDirs.Size();
+ for (i = 0; i < dir.SubFiles.Size(); i++)
+ {
+ item.Index = start + i;
+ _items.Add(item);
+ }
+}
+
+Z7_COM7F_IMF(CAgentFolder::LoadItems())
+{
+ if (!_agentSpec->_archiveLink.IsOpen)
+ return E_FAIL;
+ _items.Clear();
+ if (_flatMode)
+ {
+ LoadFolder(_proxyDirIndex);
+ if (_proxy2 && _loadAltStreams)
+ {
+ if (_proxyDirIndex == k_Proxy2_RootDirIndex)
+ LoadFolder(k_Proxy2_AltRootDirIndex);
+ }
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CAgentFolder::GetNumberOfItems(UInt32 *numItems))
+{
+ if (_flatMode)
+ *numItems = _items.Size();
+ else if (_proxy2)
+ *numItems = _proxy2->Dirs[_proxyDirIndex].Items.Size();
+ else
+ {
+ const CProxyDir *dir = &_proxy->Dirs[_proxyDirIndex];
+ *numItems = dir->SubDirs.Size() + dir->SubFiles.Size();
+ }
+ return S_OK;
+}
+
+#define SET_realIndex_AND_dir \
+ unsigned realIndex; const CProxyDir *dir; \
+ if (_flatMode) { const CProxyItem &item = _items[index]; dir = &_proxy->Dirs[item.DirIndex]; realIndex = item.Index; } \
+ else { dir = &_proxy->Dirs[_proxyDirIndex]; realIndex = index; }
+
+#define SET_realIndex_AND_dir_2 \
+ unsigned realIndex; const CProxyDir2 *dir; \
+ if (_flatMode) { const CProxyItem &item = _items[index]; dir = &_proxy2->Dirs[item.DirIndex]; realIndex = item.Index; } \
+ else { dir = &_proxy2->Dirs[_proxyDirIndex]; realIndex = index; }
+
+UString CAgentFolder::GetName(UInt32 index) const
+{
+ if (_proxy2)
+ {
+ SET_realIndex_AND_dir_2
+ return _proxy2->Files[dir->Items[realIndex]].Name;
+ }
+ SET_realIndex_AND_dir
+ if (realIndex < dir->SubDirs.Size())
+ return _proxy->Dirs[dir->SubDirs[realIndex]].Name;
+ return _proxy->Files[dir->SubFiles[realIndex - dir->SubDirs.Size()]].Name;
+}
+
+void CAgentFolder::GetPrefix(UInt32 index, UString &prefix) const
+{
+ if (!_flatMode)
+ {
+ prefix.Empty();
+ return;
+ }
+
+ const CProxyItem &item = _items[index];
+ unsigned proxyIndex = item.DirIndex;
+
+ if (_proxy2)
+ {
+ // that code is unused. 7-Zip gets prefix via GetItemPrefix() .
+
+ unsigned len = 0;
+ while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs)
+ {
+ const CProxyFile2 &file = _proxy2->Files[(unsigned)_proxy2->Dirs[proxyIndex].ArcIndex];
+ len += file.NameLen + 1;
+ proxyIndex = (file.Parent == -1) ? 0 : (unsigned)_proxy2->Files[(unsigned)file.Parent].GetDirIndex(file.IsAltStream);
+ }
+
+ wchar_t *p = prefix.GetBuf_SetEnd(len) + len;
+ proxyIndex = item.DirIndex;
+ while (proxyIndex != _proxyDirIndex && proxyIndex >= k_Proxy2_NumRootDirs)
+ {
+ const CProxyFile2 &file = _proxy2->Files[(unsigned)_proxy2->Dirs[proxyIndex].ArcIndex];
+ p--;
+ *p = WCHAR_PATH_SEPARATOR;
+ p -= file.NameLen;
+ wmemcpy(p, file.Name, file.NameLen);
+ proxyIndex = (file.Parent == -1) ? 0 : (unsigned)_proxy2->Files[(unsigned)file.Parent].GetDirIndex(file.IsAltStream);
+ }
+ }
+ else
+ {
+ unsigned len = 0;
+ while (proxyIndex != _proxyDirIndex)
+ {
+ const CProxyDir *dir = &_proxy->Dirs[proxyIndex];
+ len += dir->NameLen + 1;
+ proxyIndex = (unsigned)dir->ParentDir;
+ }
+
+ wchar_t *p = prefix.GetBuf_SetEnd(len) + len;
+ proxyIndex = item.DirIndex;
+ while (proxyIndex != _proxyDirIndex)
+ {
+ const CProxyDir *dir = &_proxy->Dirs[proxyIndex];
+ p--;
+ *p = WCHAR_PATH_SEPARATOR;
+ p -= dir->NameLen;
+ wmemcpy(p, dir->Name, dir->NameLen);
+ proxyIndex = (unsigned)dir->ParentDir;
+ }
+ }
+}
+
+UString CAgentFolder::GetFullPrefix(UInt32 index) const
+{
+ unsigned foldIndex = _proxyDirIndex;
+
+ if (_flatMode)
+ foldIndex = _items[index].DirIndex;
+
+ if (_proxy2)
+ return _proxy2->Dirs[foldIndex].PathPrefix;
+ else
+ return _proxy->GetDirPath_as_Prefix(foldIndex);
+}
+
+Z7_COM7F_IMF2(UInt64, CAgentFolder::GetItemSize(UInt32 index))
+{
+ unsigned arcIndex;
+ if (_proxy2)
+ {
+ SET_realIndex_AND_dir_2
+ arcIndex = dir->Items[realIndex];
+ const CProxyFile2 &item = _proxy2->Files[arcIndex];
+ if (item.IsDir())
+ {
+ const CProxyDir2 &itemFolder = _proxy2->Dirs[item.DirIndex];
+ if (!_flatMode)
+ return itemFolder.Size;
+ }
+ }
+ else
+ {
+ SET_realIndex_AND_dir
+ if (realIndex < dir->SubDirs.Size())
+ {
+ const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]];
+ if (!_flatMode)
+ return item.Size;
+ if (!item.IsLeaf())
+ return 0;
+ arcIndex = (unsigned)item.ArcIndex;
+ }
+ else
+ {
+ arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()];
+ }
+ }
+ NCOM::CPropVariant prop;
+ _agentSpec->GetArchive()->GetProperty(arcIndex, kpidSize, &prop);
+ if (prop.vt == VT_UI8)
+ return prop.uhVal.QuadPart;
+ else
+ return 0;
+}
+
+Z7_COM7F_IMF(CAgentFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ if (propID == kpidPrefix)
+ {
+ if (_flatMode)
+ {
+ UString prefix;
+ GetPrefix(index, prefix);
+ prop = prefix;
+ }
+ }
+ else if (_proxy2)
+ {
+ SET_realIndex_AND_dir_2
+ unsigned arcIndex = dir->Items[realIndex];
+ const CProxyFile2 &item = _proxy2->Files[arcIndex];
+ /*
+ if (propID == kpidNumAltStreams)
+ {
+ if (item.AltDirIndex != -1)
+ prop = _proxy2->Dirs[item.AltDirIndex].Items.Size();
+ }
+ else
+ */
+ if (!item.IsDir())
+ {
+ switch (propID)
+ {
+ case kpidIsDir: prop = false; break;
+ case kpidName: prop = item.Name; break;
+ default: return _agentSpec->GetArchive()->GetProperty(arcIndex, propID, value);
+ }
+ }
+ else
+ {
+ const CProxyDir2 &itemFolder = _proxy2->Dirs[item.DirIndex];
+ if (!_flatMode && propID == kpidSize)
+ prop = itemFolder.Size;
+ else if (!_flatMode && propID == kpidPackSize)
+ prop = itemFolder.PackSize;
+ else switch (propID)
+ {
+ case kpidIsDir: prop = true; break;
+ case kpidNumSubDirs: prop = itemFolder.NumSubDirs; break;
+ case kpidNumSubFiles: prop = itemFolder.NumSubFiles; break;
+ case kpidName: prop = item.Name; break;
+ case kpidCRC:
+ {
+ // if (itemFolder.IsLeaf)
+ if (!item.Ignore)
+ {
+ RINOK(_agentSpec->GetArchive()->GetProperty(arcIndex, propID, value))
+ }
+ if (itemFolder.CrcIsDefined && value->vt == VT_EMPTY)
+ prop = itemFolder.Crc;
+ break;
+ }
+ default:
+ // if (itemFolder.IsLeaf)
+ if (!item.Ignore)
+ return _agentSpec->GetArchive()->GetProperty(arcIndex, propID, value);
+ }
+ }
+ }
+ else
+ {
+ SET_realIndex_AND_dir
+ if (realIndex < dir->SubDirs.Size())
+ {
+ const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]];
+ if (!_flatMode && propID == kpidSize)
+ prop = item.Size;
+ else if (!_flatMode && propID == kpidPackSize)
+ prop = item.PackSize;
+ else
+ switch (propID)
+ {
+ case kpidIsDir: prop = true; break;
+ case kpidNumSubDirs: prop = item.NumSubDirs; break;
+ case kpidNumSubFiles: prop = item.NumSubFiles; break;
+ case kpidName: prop = item.Name; break;
+ case kpidCRC:
+ {
+ if (item.IsLeaf())
+ {
+ RINOK(_agentSpec->GetArchive()->GetProperty((unsigned)item.ArcIndex, propID, value))
+ }
+ if (item.CrcIsDefined && value->vt == VT_EMPTY)
+ prop = item.Crc;
+ break;
+ }
+ default:
+ if (item.IsLeaf())
+ return _agentSpec->GetArchive()->GetProperty((unsigned)item.ArcIndex, propID, value);
+ }
+ }
+ else
+ {
+ unsigned arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()];
+ switch (propID)
+ {
+ case kpidIsDir: prop = false; break;
+ case kpidName: prop = _proxy->Files[arcIndex].Name; break;
+ default:
+ return _agentSpec->GetArchive()->GetProperty(arcIndex, propID, value);
+ }
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+static UInt64 GetUInt64Prop(IInArchive *archive, UInt32 index, PROPID propID)
+{
+ NCOM::CPropVariant prop;
+ if (archive->GetProperty(index, propID, &prop) != S_OK)
+ throw 111233443;
+ UInt64 v = 0;
+ if (ConvertPropVariantToUInt64(prop, v))
+ return v;
+ return 0;
+}
+
+Z7_COM7F_IMF(CAgentFolder::GetItemName(UInt32 index, const wchar_t **name, unsigned *len))
+{
+ if (_proxy2)
+ {
+ SET_realIndex_AND_dir_2
+ unsigned arcIndex = dir->Items[realIndex];
+ const CProxyFile2 &item = _proxy2->Files[arcIndex];
+ *name = item.Name;
+ *len = item.NameLen;
+ return S_OK;
+ }
+ else
+ {
+ SET_realIndex_AND_dir
+ if (realIndex < dir->SubDirs.Size())
+ {
+ const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]];
+ *name = item.Name;
+ *len = item.NameLen;
+ return S_OK;
+ }
+ else
+ {
+ const CProxyFile &item = _proxy->Files[dir->SubFiles[realIndex - dir->SubDirs.Size()]];
+ *name = item.Name;
+ *len = item.NameLen;
+ return S_OK;
+ }
+ }
+}
+
+Z7_COM7F_IMF(CAgentFolder::GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len))
+{
+ *name = NULL;
+ *len = 0;
+ if (!_flatMode)
+ return S_OK;
+
+ if (_proxy2)
+ {
+ const CProxyItem &item = _items[index];
+ const UString &s = _proxy2->Dirs[item.DirIndex].PathPrefix;
+ unsigned baseLen = _proxy2->Dirs[_proxyDirIndex].PathPrefix.Len();
+ if (baseLen <= s.Len())
+ {
+ *name = (const wchar_t *)s + baseLen;
+ *len = s.Len() - baseLen;
+ }
+ else
+ {
+ return E_FAIL;
+ // throw 111l;
+ }
+ }
+ return S_OK;
+}
+
+static int CompareRawProps(IArchiveGetRawProps *rawProps, unsigned arcIndex1, unsigned arcIndex2, PROPID propID)
+{
+ // if (propID == kpidSha1)
+ if (rawProps)
+ {
+ const void *p1, *p2;
+ UInt32 size1, size2;
+ UInt32 propType1, propType2;
+ const HRESULT res1 = rawProps->GetRawProp(arcIndex1, propID, &p1, &size1, &propType1);
+ const HRESULT res2 = rawProps->GetRawProp(arcIndex2, propID, &p2, &size2, &propType2);
+ if (res1 == S_OK && res2 == S_OK)
+ {
+ for (UInt32 i = 0; i < size1 && i < size2; i++)
+ {
+ const Byte b1 = ((const Byte *)p1)[i];
+ const Byte b2 = ((const Byte *)p2)[i];
+ if (b1 < b2) return -1;
+ if (b1 > b2) return 1;
+ }
+ if (size1 < size2) return -1;
+ if (size1 > size2) return 1;
+ return 0;
+ }
+ }
+ return 0;
+}
+
+// returns pointer to extension including '.'
+
+static const wchar_t *GetExtension(const wchar_t *name)
+{
+ for (const wchar_t *dotPtr = NULL;; name++)
+ {
+ wchar_t c = *name;
+ if (c == 0)
+ return dotPtr ? dotPtr : name;
+ if (c == '.')
+ dotPtr = name;
+ }
+}
+
+
+int CAgentFolder::CompareItems3(UInt32 index1, UInt32 index2, PROPID propID)
+{
+ NCOM::CPropVariant prop1, prop2;
+ // Name must be first property
+ GetProperty(index1, propID, &prop1);
+ GetProperty(index2, propID, &prop2);
+ if (prop1.vt != prop2.vt)
+ return MyCompare(prop1.vt, prop2.vt);
+ if (prop1.vt == VT_BSTR)
+ return MyStringCompareNoCase(prop1.bstrVal, prop2.bstrVal);
+ return prop1.Compare(prop2);
+}
+
+
+int CAgentFolder::CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw)
+{
+ unsigned realIndex1, realIndex2;
+ const CProxyDir2 *dir1, *dir2;
+
+ if (_flatMode)
+ {
+ const CProxyItem &item1 = _items[index1];
+ const CProxyItem &item2 = _items[index2];
+ dir1 = &_proxy2->Dirs[item1.DirIndex];
+ dir2 = &_proxy2->Dirs[item2.DirIndex];
+ realIndex1 = item1.Index;
+ realIndex2 = item2.Index;
+ }
+ else
+ {
+ dir2 = dir1 = &_proxy2->Dirs[_proxyDirIndex];
+ realIndex1 = index1;
+ realIndex2 = index2;
+ }
+
+ UInt32 arcIndex1;
+ UInt32 arcIndex2;
+ bool isDir1, isDir2;
+ arcIndex1 = dir1->Items[realIndex1];
+ arcIndex2 = dir2->Items[realIndex2];
+ const CProxyFile2 &prox1 = _proxy2->Files[arcIndex1];
+ const CProxyFile2 &prox2 = _proxy2->Files[arcIndex2];
+
+ if (propID == kpidName)
+ {
+ return CompareFileNames_ForFolderList(prox1.Name, prox2.Name);
+ }
+
+ if (propID == kpidPrefix)
+ {
+ if (!_flatMode)
+ return 0;
+ return CompareFileNames_ForFolderList(
+ _proxy2->Dirs[_items[index1].DirIndex].PathPrefix,
+ _proxy2->Dirs[_items[index2].DirIndex].PathPrefix);
+ }
+
+ if (propID == kpidExtension)
+ {
+ return CompareFileNames_ForFolderList(
+ GetExtension(prox1.Name),
+ GetExtension(prox2.Name));
+ }
+
+ isDir1 = prox1.IsDir();
+ isDir2 = prox2.IsDir();
+
+ if (propID == kpidIsDir)
+ {
+ if (isDir1 == isDir2)
+ return 0;
+ return isDir1 ? -1 : 1;
+ }
+
+ const CProxyDir2 *proxFolder1 = NULL;
+ const CProxyDir2 *proxFolder2 = NULL;
+ if (isDir1) proxFolder1 = &_proxy2->Dirs[prox1.DirIndex];
+ if (isDir2) proxFolder2 = &_proxy2->Dirs[prox2.DirIndex];
+
+ if (propID == kpidNumSubDirs)
+ {
+ UInt32 n1 = 0;
+ UInt32 n2 = 0;
+ if (isDir1) n1 = proxFolder1->NumSubDirs;
+ if (isDir2) n2 = proxFolder2->NumSubDirs;
+ return MyCompare(n1, n2);
+ }
+
+ if (propID == kpidNumSubFiles)
+ {
+ UInt32 n1 = 0;
+ UInt32 n2 = 0;
+ if (isDir1) n1 = proxFolder1->NumSubFiles;
+ if (isDir2) n2 = proxFolder2->NumSubFiles;
+ return MyCompare(n1, n2);
+ }
+
+ if (propID == kpidSize)
+ {
+ UInt64 n1, n2;
+ if (isDir1)
+ n1 = _flatMode ? 0 : proxFolder1->Size;
+ else
+ n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidSize);
+ if (isDir2)
+ n2 = _flatMode ? 0 : proxFolder2->Size;
+ else
+ n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidSize);
+ return MyCompare(n1, n2);
+ }
+
+ if (propID == kpidPackSize)
+ {
+ UInt64 n1, n2;
+ if (isDir1)
+ n1 = _flatMode ? 0 : proxFolder1->PackSize;
+ else
+ n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidPackSize);
+ if (isDir2)
+ n2 = _flatMode ? 0 : proxFolder2->PackSize;
+ else
+ n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidPackSize);
+ return MyCompare(n1, n2);
+ }
+
+ if (propID == kpidCRC)
+ {
+ UInt64 n1, n2;
+ if (!isDir1 || !prox1.Ignore)
+ n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidCRC);
+ else
+ n1 = proxFolder1->Crc;
+ if (!isDir2 || !prox2.Ignore)
+ n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidCRC);
+ else
+ n2 = proxFolder2->Crc;
+ return MyCompare(n1, n2);
+ }
+
+ if (propIsRaw)
+ return CompareRawProps(_agentSpec->_archiveLink.GetArchiveGetRawProps(), arcIndex1, arcIndex2, propID);
+
+ return CompareItems3(index1, index2, propID);
+}
+
+
+Z7_COM7F_IMF2(Int32, CAgentFolder::CompareItems(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw))
+{
+ try {
+ if (_proxy2)
+ return CompareItems2(index1, index2, propID, propIsRaw);
+
+ unsigned realIndex1, realIndex2;
+ const CProxyDir *dir1, *dir2;
+
+ if (_flatMode)
+ {
+ const CProxyItem &item1 = _items[index1];
+ const CProxyItem &item2 = _items[index2];
+ dir1 = &_proxy->Dirs[item1.DirIndex];
+ dir2 = &_proxy->Dirs[item2.DirIndex];
+ realIndex1 = item1.Index;
+ realIndex2 = item2.Index;
+ }
+ else
+ {
+ dir2 = dir1 = &_proxy->Dirs[_proxyDirIndex];
+ realIndex1 = index1;
+ realIndex2 = index2;
+ }
+
+ if (propID == kpidPrefix)
+ {
+ if (!_flatMode)
+ return 0;
+ UString prefix1, prefix2;
+ GetPrefix(index1, prefix1);
+ GetPrefix(index2, prefix2);
+ return CompareFileNames_ForFolderList(prefix1, prefix2);
+ }
+
+ UInt32 arcIndex1;
+ UInt32 arcIndex2;
+
+ const CProxyDir *proxFolder1 = NULL;
+ const CProxyDir *proxFolder2 = NULL;
+
+ if (realIndex1 < dir1->SubDirs.Size())
+ {
+ proxFolder1 = &_proxy->Dirs[dir1->SubDirs[realIndex1]];
+ arcIndex1 = (unsigned)proxFolder1->ArcIndex;
+ }
+ else
+ arcIndex1 = dir1->SubFiles[realIndex1 - dir1->SubDirs.Size()];
+
+ if (realIndex2 < dir2->SubDirs.Size())
+ {
+ proxFolder2 = &_proxy->Dirs[dir2->SubDirs[realIndex2]];
+ arcIndex2 = (unsigned)proxFolder2->ArcIndex;
+ }
+ else
+ arcIndex2 = dir2->SubFiles[realIndex2 - dir2->SubDirs.Size()];
+
+ if (propID == kpidName)
+ return CompareFileNames_ForFolderList(
+ proxFolder1 ? proxFolder1->Name : _proxy->Files[arcIndex1].Name,
+ proxFolder2 ? proxFolder2->Name : _proxy->Files[arcIndex2].Name);
+
+ if (propID == kpidExtension)
+ return CompareFileNames_ForFolderList(
+ GetExtension(proxFolder1 ? proxFolder1->Name : _proxy->Files[arcIndex1].Name),
+ GetExtension(proxFolder2 ? proxFolder2->Name : _proxy->Files[arcIndex2].Name));
+
+ if (propID == kpidIsDir)
+ {
+ if (proxFolder1)
+ return proxFolder2 ? 0 : -1;
+ return proxFolder2 ? 1 : 0;
+ }
+
+ if (propID == kpidNumSubDirs)
+ {
+ UInt32 n1 = 0;
+ UInt32 n2 = 0;
+ if (proxFolder1) n1 = proxFolder1->NumSubDirs;
+ if (proxFolder2) n2 = proxFolder2->NumSubDirs;
+ return MyCompare(n1, n2);
+ }
+
+ if (propID == kpidNumSubFiles)
+ {
+ UInt32 n1 = 0;
+ UInt32 n2 = 0;
+ if (proxFolder1) n1 = proxFolder1->NumSubFiles;
+ if (proxFolder2) n2 = proxFolder2->NumSubFiles;
+ return MyCompare(n1, n2);
+ }
+
+ if (propID == kpidSize)
+ {
+ UInt64 n1, n2;
+ if (proxFolder1)
+ n1 = _flatMode ? 0 : proxFolder1->Size;
+ else
+ n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidSize);
+ if (proxFolder2)
+ n2 = _flatMode ? 0 : proxFolder2->Size;
+ else
+ n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidSize);
+ return MyCompare(n1, n2);
+ }
+
+ if (propID == kpidPackSize)
+ {
+ UInt64 n1, n2;
+ if (proxFolder1)
+ n1 = _flatMode ? 0 : proxFolder1->PackSize;
+ else
+ n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidPackSize);
+ if (proxFolder2)
+ n2 = _flatMode ? 0 : proxFolder2->PackSize;
+ else
+ n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidPackSize);
+ return MyCompare(n1, n2);
+ }
+
+ if (propID == kpidCRC)
+ {
+ UInt64 n1, n2;
+ if (proxFolder1 && !proxFolder1->IsLeaf())
+ n1 = proxFolder1->Crc;
+ else
+ n1 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex1, kpidCRC);
+ if (proxFolder2 && !proxFolder2->IsLeaf())
+ n2 = proxFolder2->Crc;
+ else
+ n2 = GetUInt64Prop(_agentSpec->GetArchive(), arcIndex2, kpidCRC);
+ return MyCompare(n1, n2);
+ }
+
+ if (propIsRaw)
+ {
+ bool isVirt1 = (proxFolder1 && !proxFolder1->IsLeaf());
+ bool isVirt2 = (proxFolder2 && !proxFolder2->IsLeaf());
+ if (isVirt1)
+ return isVirt2 ? 0 : -1;
+ if (isVirt2)
+ return 1;
+ return CompareRawProps(_agentSpec->_archiveLink.GetArchiveGetRawProps(), arcIndex1, arcIndex2, propID);
+ }
+
+ return CompareItems3(index1, index2, propID);
+
+ } catch(...) { return 0; }
+}
+
+
+HRESULT CAgentFolder::BindToFolder_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder)
+{
+ /*
+ CMyComPtr<IFolderFolder> parentFolder;
+
+ if (_proxy2)
+ {
+ const CProxyDir2 &dir = _proxy2->Dirs[proxyDirIndex];
+ int par = _proxy2->GetParentFolderOfFile(dir.ArcIndex);
+ if (par != (int)_proxyDirIndex)
+ {
+ RINOK(BindToFolder_Internal(par, &parentFolder));
+ }
+ else
+ parentFolder = this;
+ }
+ else
+ {
+ const CProxyDir &dir = _proxy->Dirs[proxyDirIndex];
+ if (dir.Parent != (int)_proxyDirIndex)
+ {
+ RINOK(BindToFolder_Internal(dir.Parent, &parentFolder));
+ }
+ else
+ parentFolder = this;
+ }
+ */
+ CAgentFolder *folderSpec = new CAgentFolder;
+ CMyComPtr<IFolderFolder> agentFolder = folderSpec;
+ folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec);
+ *resultFolder = agentFolder.Detach();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CAgentFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder))
+{
+ COM_TRY_BEGIN
+ if (_proxy2)
+ {
+ SET_realIndex_AND_dir_2
+ const unsigned arcIndex = dir->Items[realIndex];
+ const CProxyFile2 &item = _proxy2->Files[arcIndex];
+ if (!item.IsDir())
+ return E_INVALIDARG;
+ return BindToFolder_Internal((unsigned)item.DirIndex, resultFolder);
+ }
+ SET_realIndex_AND_dir
+ if (realIndex >= (UInt32)dir->SubDirs.Size())
+ return E_INVALIDARG;
+ return BindToFolder_Internal(dir->SubDirs[realIndex], resultFolder);
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CAgentFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder))
+{
+ COM_TRY_BEGIN
+ if (_proxy2)
+ {
+ const int index = _proxy2->FindItem(_proxyDirIndex, name, true);
+ if (index == -1)
+ return E_INVALIDARG;
+ return BindToFolder_Internal((unsigned)_proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]].DirIndex, resultFolder);
+ }
+ const int index = _proxy->FindSubDir(_proxyDirIndex, name);
+ if (index == -1)
+ return E_INVALIDARG;
+ return BindToFolder_Internal((unsigned)index, resultFolder);
+ COM_TRY_END
+}
+
+
+
+// ---------- IFolderAltStreams ----------
+
+HRESULT CAgentFolder::BindToAltStreams_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder)
+{
+ *resultFolder = NULL;
+ if (!_proxy2)
+ return S_OK;
+
+ /*
+ CMyComPtr<IFolderFolder> parentFolder;
+
+ int par = _proxy2->GetParentFolderOfFile(_proxy2->Dirs[proxyDirIndex].ArcIndex);
+ if (par != (int)_proxyDirIndex)
+ {
+ RINOK(BindToFolder_Internal(par, &parentFolder));
+ if (!parentFolder)
+ return S_OK;
+ }
+ else
+ parentFolder = this;
+ */
+
+ CAgentFolder *folderSpec = new CAgentFolder;
+ CMyComPtr<IFolderFolder> agentFolder = folderSpec;
+ folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec);
+ *resultFolder = agentFolder.Detach();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CAgentFolder::BindToAltStreams(UInt32 index, IFolderFolder **resultFolder))
+{
+ COM_TRY_BEGIN
+
+ *resultFolder = NULL;
+
+ if (!_proxy2)
+ return S_OK;
+
+ if (_proxy2->IsAltDir(_proxyDirIndex))
+ return S_OK;
+
+ {
+ if (index == (UInt32)(Int32)-1)
+ {
+ unsigned altDirIndex;
+ // IFolderFolder *parentFolder;
+
+ if (_proxyDirIndex == k_Proxy2_RootDirIndex)
+ {
+ altDirIndex = k_Proxy2_AltRootDirIndex;
+ // parentFolder = this; // we want to use Root dir as parent for alt root
+ }
+ else
+ {
+ const unsigned arcIndex = (unsigned)_proxy2->Dirs[_proxyDirIndex].ArcIndex;
+ const CProxyFile2 &item = _proxy2->Files[arcIndex];
+ if (item.AltDirIndex == -1)
+ return S_OK;
+ altDirIndex = (unsigned)item.AltDirIndex;
+ // parentFolder = _parentFolder;
+ }
+
+ CAgentFolder *folderSpec = new CAgentFolder;
+ CMyComPtr<IFolderFolder> agentFolder = folderSpec;
+ folderSpec->Init(_proxy, _proxy2, altDirIndex, /* parentFolder, */ _agentSpec);
+ *resultFolder = agentFolder.Detach();
+ return S_OK;
+ }
+
+ SET_realIndex_AND_dir_2
+ const unsigned arcIndex = dir->Items[realIndex];
+ const CProxyFile2 &item = _proxy2->Files[arcIndex];
+ if (item.AltDirIndex == -1)
+ return S_OK;
+ return BindToAltStreams_Internal((unsigned)item.AltDirIndex, resultFolder);
+ }
+
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CAgentFolder::BindToAltStreams(const wchar_t *name, IFolderFolder **resultFolder))
+{
+ COM_TRY_BEGIN
+
+ *resultFolder = NULL;
+
+ if (!_proxy2)
+ return S_OK;
+
+ if (_proxy2->IsAltDir(_proxyDirIndex))
+ return S_OK;
+
+ if (name[0] == 0)
+ return BindToAltStreams((UInt32)(Int32)-1, resultFolder);
+
+ {
+ const CProxyDir2 &dir = _proxy2->Dirs[_proxyDirIndex];
+ FOR_VECTOR (i, dir.Items)
+ {
+ const CProxyFile2 &file = _proxy2->Files[dir.Items[i]];
+ if (file.AltDirIndex != -1)
+ if (CompareFileNames(file.Name, name) == 0)
+ return BindToAltStreams_Internal((unsigned)file.AltDirIndex, resultFolder);
+ }
+ return E_INVALIDARG;
+ }
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CAgentFolder::AreAltStreamsSupported(UInt32 index, Int32 *isSupported))
+{
+ *isSupported = BoolToInt(false);
+
+ if (!_proxy2)
+ return S_OK;
+
+ if (_proxy2->IsAltDir(_proxyDirIndex))
+ return S_OK;
+
+ unsigned arcIndex;
+
+ if (index == (UInt32)(Int32)-1)
+ {
+ if (_proxyDirIndex == k_Proxy2_RootDirIndex)
+ {
+ *isSupported = BoolToInt(true);
+ return S_OK;
+ }
+ arcIndex = (unsigned)_proxy2->Dirs[_proxyDirIndex].ArcIndex;
+ }
+ else
+ {
+ SET_realIndex_AND_dir_2
+ arcIndex = dir->Items[realIndex];
+ }
+
+ if (_proxy2->Files[arcIndex].AltDirIndex != -1)
+ *isSupported = BoolToInt(true);
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CAgentFolder::BindToParentFolder(IFolderFolder **resultFolder))
+{
+ COM_TRY_BEGIN
+ /*
+ CMyComPtr<IFolderFolder> parentFolder = _parentFolder;
+ *resultFolder = parentFolder.Detach();
+ */
+ *resultFolder = NULL;
+
+ unsigned proxyDirIndex;
+
+ if (_proxy2)
+ {
+ if (_proxyDirIndex == k_Proxy2_RootDirIndex)
+ return S_OK;
+ if (_proxyDirIndex == k_Proxy2_AltRootDirIndex)
+ proxyDirIndex = k_Proxy2_RootDirIndex;
+ else
+ {
+ const CProxyDir2 &fold = _proxy2->Dirs[_proxyDirIndex];
+ const CProxyFile2 &file = _proxy2->Files[(unsigned)fold.ArcIndex];
+ const int parentIndex = file.Parent;
+ if (parentIndex == -1)
+ proxyDirIndex = k_Proxy2_RootDirIndex;
+ else
+ proxyDirIndex = (unsigned)_proxy2->Files[(unsigned)parentIndex].DirIndex;
+ }
+ }
+ else
+ {
+ const int parent = _proxy->Dirs[_proxyDirIndex].ParentDir;
+ if (parent == -1)
+ return S_OK;
+ proxyDirIndex = (unsigned)parent;
+ }
+
+ CAgentFolder *folderSpec = new CAgentFolder;
+ CMyComPtr<IFolderFolder> agentFolder = folderSpec;
+ folderSpec->Init(_proxy, _proxy2, proxyDirIndex, /* parentFolder, */ _agentSpec);
+ *resultFolder = agentFolder.Detach();
+
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CAgentFolder::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IInArchiveGetStream,
+ getStream, _agentSpec->GetArchive())
+ if (!getStream)
+ return S_OK;
+
+ UInt32 arcIndex;
+ if (_proxy2)
+ {
+ SET_realIndex_AND_dir_2
+ arcIndex = dir->Items[realIndex];
+ }
+ else
+ {
+ SET_realIndex_AND_dir
+
+ if (realIndex < dir->SubDirs.Size())
+ {
+ const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]];
+ if (!item.IsLeaf())
+ return S_OK;
+ arcIndex = (unsigned)item.ArcIndex;
+ }
+ else
+ arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()];
+ }
+ return getStream->GetStream(arcIndex, stream);
+}
+
+// static const unsigned k_FirstOptionalProp = 2;
+
+static const PROPID kProps[] =
+{
+ kpidNumSubDirs,
+ kpidNumSubFiles,
+
+ // kpidNumAltStreams,
+ kpidPrefix
+};
+
+struct CArchiveItemPropertyTemp
+{
+ UString Name;
+ PROPID ID;
+ VARTYPE Type;
+};
+
+Z7_COM7F_IMF(CAgentFolder::GetNumberOfProperties(UInt32 *numProps))
+{
+ COM_TRY_BEGIN
+ RINOK(_agentSpec->GetArchive()->GetNumberOfProperties(numProps))
+ *numProps += Z7_ARRAY_SIZE(kProps);
+ if (!_flatMode)
+ (*numProps)--;
+ /*
+ if (!_agentSpec->ThereIsAltStreamProp)
+ (*numProps)--;
+ */
+ /*
+ bool thereIsPathProp = _proxy2 ?
+ _agentSpec->_proxy2->ThereIsPathProp :
+ _agentSpec->_proxy->ThereIsPathProp;
+ */
+
+ // if there is kpidPath, we change kpidPath to kpidName
+ // if there is no kpidPath, we add kpidName.
+ if (!_agentSpec->ThereIsPathProp)
+ (*numProps)++;
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CAgentFolder::GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType))
+{
+ COM_TRY_BEGIN
+ UInt32 numProps;
+ _agentSpec->GetArchive()->GetNumberOfProperties(&numProps);
+
+ /*
+ bool thereIsPathProp = _proxy2 ?
+ _agentSpec->_proxy2->ThereIsPathProp :
+ _agentSpec->_proxy->ThereIsPathProp;
+ */
+
+ if (!_agentSpec->ThereIsPathProp)
+ {
+ if (index == 0)
+ {
+ *propID = kpidName;
+ *varType = VT_BSTR;
+ *name = NULL;
+ return S_OK;
+ }
+ index--;
+ }
+
+ if (index < numProps)
+ {
+ RINOK(_agentSpec->GetArchive()->GetPropertyInfo(index, name, propID, varType))
+ if (*propID == kpidPath)
+ *propID = kpidName;
+ }
+ else
+ {
+ index -= numProps;
+ /*
+ if (index >= k_FirstOptionalProp)
+ {
+ if (!_agentSpec->ThereIsAltStreamProp)
+ index++;
+ }
+ */
+ *propID = kProps[index];
+ *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID];
+ *name = NULL;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+static const PROPID kFolderProps[] =
+{
+ kpidSize,
+ kpidPackSize,
+ kpidNumSubDirs,
+ kpidNumSubFiles,
+ kpidCRC
+};
+
+Z7_COM7F_IMF(CAgentFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+
+ NWindows::NCOM::CPropVariant prop;
+
+ if (propID == kpidReadOnly)
+ {
+ if (_agentSpec->Is_Attrib_ReadOnly())
+ prop = true;
+ else
+ prop = _agentSpec->IsThere_ReadOnlyArc();
+ }
+ else if (propID == kpidIsHash)
+ {
+ prop = _agentSpec->_isHashHandler;
+ }
+ else if (_proxy2)
+ {
+ const CProxyDir2 &dir = _proxy2->Dirs[_proxyDirIndex];
+ if (propID == kpidName)
+ {
+ if (dir.ArcIndex != -1)
+ prop = _proxy2->Files[(unsigned)dir.ArcIndex].Name;
+ }
+ else if (propID == kpidPath)
+ {
+ bool isAltStreamFolder = false;
+ prop = _proxy2->GetDirPath_as_Prefix(_proxyDirIndex, isAltStreamFolder);
+ }
+ else switch (propID)
+ {
+ case kpidSize: prop = dir.Size; break;
+ case kpidPackSize: prop = dir.PackSize; break;
+ case kpidNumSubDirs: prop = dir.NumSubDirs; break;
+ case kpidNumSubFiles: prop = dir.NumSubFiles; break;
+ // case kpidName: prop = dir.Name; break;
+ // case kpidPath: prop = _proxy2->GetFullPathPrefix(_proxyDirIndex); break;
+ case kpidType: prop = UString("7-Zip.") + _agentSpec->ArchiveType; break;
+ case kpidCRC: if (dir.CrcIsDefined) { prop = dir.Crc; } break;
+ }
+
+ }
+ else
+ {
+ const CProxyDir &dir = _proxy->Dirs[_proxyDirIndex];
+ switch (propID)
+ {
+ case kpidSize: prop = dir.Size; break;
+ case kpidPackSize: prop = dir.PackSize; break;
+ case kpidNumSubDirs: prop = dir.NumSubDirs; break;
+ case kpidNumSubFiles: prop = dir.NumSubFiles; break;
+ case kpidName: prop = dir.Name; break;
+ case kpidPath: prop = _proxy->GetDirPath_as_Prefix(_proxyDirIndex); break;
+ case kpidType: prop = UString("7-Zip.") + _agentSpec->ArchiveType; break;
+ case kpidCRC: if (dir.CrcIsDefined) prop = dir.Crc; break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CAgentFolder::GetNumberOfFolderProperties(UInt32 *numProps))
+{
+ *numProps = Z7_ARRAY_SIZE(kFolderProps);
+ return S_OK;
+}
+
+IMP_IFolderFolder_GetProp(
+ CAgentFolder::GetFolderPropertyInfo,
+ kFolderProps)
+
+Z7_COM7F_IMF(CAgentFolder::GetParent(UInt32 /* index */, UInt32 * /* parent */, UInt32 * /* parentType */))
+{
+ return E_FAIL;
+}
+
+
+Z7_COM7F_IMF(CAgentFolder::GetNumRawProps(UInt32 *numProps))
+{
+ IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps();
+ if (rawProps)
+ return rawProps->GetNumRawProps(numProps);
+ *numProps = 0;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CAgentFolder::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID))
+{
+ IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps();
+ if (rawProps)
+ return rawProps->GetRawPropInfo(index, name, propID);
+ return E_FAIL;
+}
+
+Z7_COM7F_IMF(CAgentFolder::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
+{
+ IArchiveGetRawProps *rawProps = _agentSpec->_archiveLink.GetArchiveGetRawProps();
+ if (rawProps)
+ {
+ unsigned arcIndex;
+ if (_proxy2)
+ {
+ SET_realIndex_AND_dir_2
+ arcIndex = dir->Items[realIndex];
+ }
+ else
+ {
+ SET_realIndex_AND_dir
+ if (realIndex < dir->SubDirs.Size())
+ {
+ const CProxyDir &item = _proxy->Dirs[dir->SubDirs[realIndex]];
+ if (!item.IsLeaf())
+ {
+ *data = NULL;
+ *dataSize = 0;
+ *propType = 0;
+ return S_OK;
+ }
+ arcIndex = (unsigned)item.ArcIndex;
+ }
+ else
+ arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()];
+ }
+ return rawProps->GetRawProp(arcIndex, propID, data, dataSize, propType);
+ }
+ *data = NULL;
+ *dataSize = 0;
+ *propType = 0;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CAgentFolder::GetFolderArcProps(IFolderArcProps **object))
+{
+ CMyComPtr<IFolderArcProps> temp = _agentSpec;
+ *object = temp.Detach();
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CAgentFolder::SetFlatMode(Int32 flatMode))
+{
+ _flatMode = IntToBool(flatMode);
+ return S_OK;
+}
+
+
+int CAgentFolder::GetRealIndex(unsigned index) const
+{
+ if (!_flatMode)
+ {
+ if (_proxy2)
+ return (int)_proxy2->GetRealIndex(_proxyDirIndex, index);
+ else
+ return _proxy->GetRealIndex(_proxyDirIndex, index);
+ }
+ {
+ const CProxyItem &item = _items[index];
+ if (_proxy2)
+ {
+ const CProxyDir2 *dir = &_proxy2->Dirs[item.DirIndex];
+ return (int)dir->Items[item.Index];
+ }
+ else
+ {
+ const CProxyDir *dir = &_proxy->Dirs[item.DirIndex];
+ const unsigned realIndex = item.Index;
+ if (realIndex < dir->SubDirs.Size())
+ {
+ const CProxyDir &f = _proxy->Dirs[dir->SubDirs[realIndex]];
+ if (!f.IsLeaf())
+ return -1;
+ return f.ArcIndex;
+ }
+ return (int)dir->SubFiles[realIndex - dir->SubDirs.Size()];
+ }
+ }
+}
+
+void CAgentFolder::GetRealIndices(const UInt32 *indices, UInt32 numItems, bool includeAltStreams, bool includeFolderSubItemsInFlatMode, CUIntVector &realIndices) const
+{
+ if (!_flatMode)
+ {
+ if (_proxy2)
+ _proxy2->GetRealIndices(_proxyDirIndex, indices, numItems, includeAltStreams, realIndices);
+ else
+ _proxy->GetRealIndices(_proxyDirIndex, indices, numItems, realIndices);
+ return;
+ }
+
+ realIndices.Clear();
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ const CProxyItem &item = _items[indices[i]];
+ if (_proxy2)
+ {
+ const CProxyDir2 *dir = &_proxy2->Dirs[item.DirIndex];
+ _proxy2->AddRealIndices_of_ArcItem(dir->Items[item.Index], includeAltStreams, realIndices);
+ continue;
+ }
+ UInt32 arcIndex;
+ {
+ const CProxyDir *dir = &_proxy->Dirs[item.DirIndex];
+ unsigned realIndex = item.Index;
+ if (realIndex < dir->SubDirs.Size())
+ {
+ if (includeFolderSubItemsInFlatMode)
+ {
+ _proxy->AddRealIndices(dir->SubDirs[realIndex], realIndices);
+ continue;
+ }
+ const CProxyDir &f = _proxy->Dirs[dir->SubDirs[realIndex]];
+ if (!f.IsLeaf())
+ continue;
+ arcIndex = (unsigned)f.ArcIndex;
+ }
+ else
+ arcIndex = dir->SubFiles[realIndex - dir->SubDirs.Size()];
+ }
+ realIndices.Add(arcIndex);
+ }
+
+ HeapSort(&realIndices.Front(), realIndices.Size());
+}
+
+Z7_COM7F_IMF(CAgentFolder::Extract(const UInt32 *indices,
+ UInt32 numItems,
+ Int32 includeAltStreams,
+ Int32 replaceAltStreamColon,
+ NExtract::NPathMode::EEnum pathMode,
+ NExtract::NOverwriteMode::EEnum overwriteMode,
+ const wchar_t *path,
+ Int32 testMode,
+ IFolderArchiveExtractCallback *extractCallback2))
+{
+ COM_TRY_BEGIN
+
+ if (!testMode && _agentSpec->_isHashHandler)
+ return E_NOTIMPL;
+
+ CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
+ CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
+ UStringVector pathParts;
+ bool isAltStreamFolder = false;
+ if (_proxy2)
+ _proxy2->GetDirPathParts(_proxyDirIndex, pathParts, isAltStreamFolder);
+ else
+ _proxy->GetDirPathParts(_proxyDirIndex, pathParts);
+
+ /*
+ if (_flatMode)
+ pathMode = NExtract::NPathMode::kNoPathnames;
+ */
+
+ extractCallbackSpec->InitForMulti(
+ false, // multiArchives
+ pathMode,
+ overwriteMode,
+ _zoneMode,
+ k_keepEmptyDirPrefixes);
+
+ if (extractCallback2)
+ extractCallback2->SetTotal(_agentSpec->GetArc().GetEstmatedPhySize());
+
+ FString pathU;
+ if (path)
+ {
+ pathU = us2fs(path);
+ if (!pathU.IsEmpty())
+ if (!NFile::NName::IsAltStreamPrefixWithColon(pathU))
+ {
+ NFile::NName::NormalizeDirPathPrefix(pathU);
+ NFile::NDir::CreateComplexDir(pathU);
+ }
+ }
+
+ CExtractNtOptions extractNtOptions;
+ extractNtOptions.AltStreams.Val = IntToBool(includeAltStreams); // change it!!!
+ extractNtOptions.AltStreams.Def = true;
+
+ extractNtOptions.ReplaceColonForAltStream = IntToBool(replaceAltStreamColon);
+
+ extractCallbackSpec->InitBeforeNewArchive();
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (_zoneMode != NExtract::NZoneIdMode::kNone)
+ {
+ ReadZoneFile_Of_BaseFile(us2fs(_agentSpec->_archiveFilePath), extractCallbackSpec->ZoneBuf);
+ }
+ #endif
+
+ extractCallbackSpec->Init(
+ extractNtOptions,
+ NULL, &_agentSpec->GetArc(),
+ extractCallback2,
+ false, // stdOutMode
+ IntToBool(testMode),
+ pathU,
+ pathParts, isAltStreamFolder,
+ (UInt64)(Int64)-1);
+
+ if (_proxy2)
+ extractCallbackSpec->SetBaseParentFolderIndex((unsigned)_proxy2->Dirs[_proxyDirIndex].ArcIndex);
+
+ // do we need another base folder for subfolders ?
+ extractCallbackSpec->DirPathPrefix_for_HashFiles = _agentSpec->_hashBaseFolderPrefix;
+
+ CUIntVector realIndices;
+ GetRealIndices(indices, numItems, IntToBool(includeAltStreams),
+ false, // includeFolderSubItemsInFlatMode
+ realIndices); //
+
+ #ifdef SUPPORT_LINKS
+
+ if (!testMode)
+ {
+ RINOK(extractCallbackSpec->PrepareHardLinks(&realIndices))
+ }
+
+ #endif
+
+ {
+ CArchiveExtractCallback_Closer ecsCloser(extractCallbackSpec);
+
+ HRESULT res = _agentSpec->GetArchive()->Extract(&realIndices.Front(),
+ realIndices.Size(), testMode, extractCallback);
+
+ HRESULT res2 = ecsCloser.Close();
+ if (res == S_OK)
+ res = res2;
+ return res;
+ }
+
+ COM_TRY_END
+}
+
+/////////////////////////////////////////
+// CAgent
+
+CAgent::CAgent():
+ _proxy(NULL),
+ _proxy2(NULL),
+ _updatePathPrefix_is_AltFolder(false),
+ _isDeviceFile(false),
+ _isHashHandler(false)
+{
+}
+
+CAgent::~CAgent()
+{
+ if (_proxy)
+ delete _proxy;
+ if (_proxy2)
+ delete _proxy2;
+}
+
+bool CAgent::CanUpdate() const
+{
+ // FAR plugin uses empty agent to create new archive !!!
+ if (_archiveLink.Arcs.Size() == 0)
+ return true;
+ if (_isDeviceFile)
+ return false;
+ if (_archiveLink.Arcs.Size() != 1)
+ return false;
+ if (_archiveLink.Arcs[0].ErrorInfo.ThereIsTail)
+ return false;
+ return true;
+}
+
+Z7_COM7F_IMF(CAgent::Open(
+ IInStream *inStream,
+ const wchar_t *filePath,
+ const wchar_t *arcFormat,
+ BSTR *archiveType,
+ IArchiveOpenCallback *openArchiveCallback))
+{
+ COM_TRY_BEGIN
+ _archiveFilePath = filePath;
+ _hashBaseFolderPrefix.Empty();
+ _attrib = 0;
+ _isDeviceFile = false;
+ _isHashHandler = false;
+ NFile::NFind::CFileInfo fi;
+ if (!inStream)
+ {
+ if (!fi.Find(us2fs(_archiveFilePath)))
+ return GetLastError_noZero_HRESULT();
+ if (fi.IsDir())
+ return E_FAIL;
+ _attrib = fi.Attrib;
+ _isDeviceFile = fi.IsDevice;
+ FString dirPrefix, fileName;
+ if (NFile::NDir::GetFullPathAndSplit(us2fs(_archiveFilePath), dirPrefix, fileName))
+ {
+ NFile::NName::NormalizeDirPathPrefix(dirPrefix);
+ _hashBaseFolderPrefix = dirPrefix;
+ }
+ }
+ CArcInfoEx archiverInfo0, archiverInfo1;
+
+ RINOK(LoadGlobalCodecs())
+
+ CObjectVector<COpenType> types;
+ if (!ParseOpenTypes(*g_CodecsObj, arcFormat, types))
+ return S_FALSE;
+
+ /*
+ CObjectVector<COptionalOpenProperties> optProps;
+ if (Read_ShowDeleted())
+ {
+ COptionalOpenProperties &optPair = optProps.AddNew();
+ optPair.FormatName = "ntfs";
+ // optPair.Props.AddNew().Name = "LS";
+ optPair.Props.AddNew().Name = "LD";
+ }
+ */
+
+ COpenOptions options;
+ options.props = NULL;
+ options.codecs = g_CodecsObj;
+ options.types = &types;
+ CIntVector exl;
+ options.excludedFormats = &exl;
+ options.stdInMode = false;
+ options.stream = inStream;
+ options.filePath = _archiveFilePath;
+ options.callback = openArchiveCallback;
+
+ HRESULT res = _archiveLink.Open(options);
+
+ if (!_archiveLink.Arcs.IsEmpty())
+ {
+ CArc &arc = _archiveLink.Arcs.Back();
+ if (!inStream)
+ {
+ arc.MTime.Set_From_FiTime(fi.MTime);
+ arc.MTime.Def = !fi.IsDevice;
+ }
+
+ ArchiveType = GetTypeOfArc(arc);
+ if (archiveType)
+ {
+ RINOK(StringToBstr(ArchiveType, archiveType))
+ }
+
+ if (arc.IsHashHandler(options))
+ _isHashHandler = true;
+ }
+
+ return res;
+
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CAgent::ReOpen(IArchiveOpenCallback *openArchiveCallback))
+{
+ COM_TRY_BEGIN
+ if (_proxy2)
+ {
+ delete _proxy2;
+ _proxy2 = NULL;
+ }
+ if (_proxy)
+ {
+ delete _proxy;
+ _proxy = NULL;
+ }
+
+ CObjectVector<COpenType> incl;
+ CIntVector exl;
+
+ COpenOptions options;
+ options.props = NULL;
+ options.codecs = g_CodecsObj;
+ options.types = &incl;
+ options.excludedFormats = &exl;
+ options.stdInMode = false;
+ options.filePath = _archiveFilePath;
+ options.callback = openArchiveCallback;
+
+ RINOK(_archiveLink.ReOpen(options))
+ return ReadItems();
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CAgent::Close())
+{
+ COM_TRY_BEGIN
+ return _archiveLink.Close();
+ COM_TRY_END
+}
+
+/*
+Z7_COM7F_IMF(CAgent::EnumProperties(IEnumSTATPROPSTG **EnumProperties)
+{
+ return _archive->EnumProperties(EnumProperties);
+}
+*/
+
+HRESULT CAgent::ReadItems()
+{
+ if (_proxy || _proxy2)
+ return S_OK;
+
+ const CArc &arc = GetArc();
+ bool useProxy2 = (arc.GetRawProps && arc.IsTree);
+
+ // useProxy2 = false;
+
+ if (useProxy2)
+ _proxy2 = new CProxyArc2();
+ else
+ _proxy = new CProxyArc();
+
+ {
+ ThereIsPathProp = false;
+ // ThereIsAltStreamProp = false;
+ UInt32 numProps;
+ arc.Archive->GetNumberOfProperties(&numProps);
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE varType;
+ RINOK(arc.Archive->GetPropertyInfo(i, &name, &propID, &varType))
+ if (propID == kpidPath)
+ ThereIsPathProp = true;
+ /*
+ if (propID == kpidIsAltStream)
+ ThereIsAltStreamProp = true;
+ */
+ }
+ }
+
+ if (_proxy2)
+ return _proxy2->Load(GetArc(), NULL);
+ return _proxy->Load(GetArc(), NULL);
+}
+
+Z7_COM7F_IMF(CAgent::BindToRootFolder(IFolderFolder **resultFolder))
+{
+ COM_TRY_BEGIN
+ if (!_archiveLink.Arcs.IsEmpty())
+ {
+ RINOK(ReadItems())
+ }
+ CAgentFolder *folderSpec = new CAgentFolder;
+ CMyComPtr<IFolderFolder> rootFolder = folderSpec;
+ folderSpec->Init(_proxy, _proxy2, k_Proxy_RootDirIndex, /* NULL, */ this);
+ *resultFolder = rootFolder.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CAgent::Extract(
+ NExtract::NPathMode::EEnum pathMode,
+ NExtract::NOverwriteMode::EEnum overwriteMode,
+ const wchar_t *path,
+ Int32 testMode,
+ IFolderArchiveExtractCallback *extractCallback2))
+{
+ COM_TRY_BEGIN
+
+ if (!testMode && _isHashHandler)
+ return E_NOTIMPL;
+
+ CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
+ CMyComPtr<IArchiveExtractCallback> extractCallback = extractCallbackSpec;
+ extractCallbackSpec->InitForMulti(
+ false, // multiArchives
+ pathMode,
+ overwriteMode,
+ NExtract::NZoneIdMode::kNone,
+ k_keepEmptyDirPrefixes);
+
+ CExtractNtOptions extractNtOptions;
+ extractNtOptions.AltStreams.Val = true; // change it!!!
+ extractNtOptions.AltStreams.Def = true; // change it!!!
+ extractNtOptions.ReplaceColonForAltStream = false; // change it!!!
+
+ extractCallbackSpec->Init(
+ extractNtOptions,
+ NULL, &GetArc(),
+ extractCallback2,
+ false, // stdOutMode
+ IntToBool(testMode),
+ us2fs(path),
+ UStringVector(), false,
+ (UInt64)(Int64)-1);
+
+ extractCallbackSpec->DirPathPrefix_for_HashFiles = _hashBaseFolderPrefix;
+
+ #ifdef SUPPORT_LINKS
+
+ if (!testMode)
+ {
+ RINOK(extractCallbackSpec->PrepareHardLinks(NULL)) // NULL means all items
+ }
+
+ #endif
+
+ return GetArchive()->Extract(NULL, (UInt32)(Int32)-1, testMode, extractCallback);
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CAgent::GetNumberOfProperties(UInt32 *numProps))
+{
+ COM_TRY_BEGIN
+ return GetArchive()->GetNumberOfProperties(numProps);
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CAgent::GetPropertyInfo(UInt32 index,
+ BSTR *name, PROPID *propID, VARTYPE *varType))
+{
+ COM_TRY_BEGIN
+ RINOK(GetArchive()->GetPropertyInfo(index, name, propID, varType))
+ if (*propID == kpidPath)
+ *propID = kpidName;
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CAgent::GetArcNumLevels(UInt32 *numLevels))
+{
+ *numLevels = _archiveLink.Arcs.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CAgent::GetArcProp(UInt32 level, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ if (level > (UInt32)_archiveLink.Arcs.Size())
+ return E_INVALIDARG;
+ if (level == (UInt32)_archiveLink.Arcs.Size())
+ {
+ switch (propID)
+ {
+ case kpidPath:
+ if (!_archiveLink.NonOpen_ArcPath.IsEmpty())
+ prop = _archiveLink.NonOpen_ArcPath;
+ break;
+ case kpidErrorType:
+ if (_archiveLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
+ prop = g_CodecsObj->Formats[_archiveLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name;
+ break;
+ case kpidErrorFlags:
+ {
+ UInt32 flags = _archiveLink.NonOpen_ErrorInfo.GetErrorFlags();
+ if (flags != 0)
+ prop = flags;
+ break;
+ }
+ case kpidWarningFlags:
+ {
+ UInt32 flags = _archiveLink.NonOpen_ErrorInfo.GetWarningFlags();
+ if (flags != 0)
+ prop = flags;
+ break;
+ }
+ }
+ }
+ else
+ {
+ const CArc &arc = _archiveLink.Arcs[level];
+ switch (propID)
+ {
+ case kpidType: prop = GetTypeOfArc(arc); break;
+ case kpidPath: prop = arc.Path; break;
+ case kpidErrorType:
+ if (arc.ErrorInfo.ErrorFormatIndex >= 0)
+ prop = g_CodecsObj->Formats[arc.ErrorInfo.ErrorFormatIndex].Name;
+ break;
+ case kpidErrorFlags:
+ {
+ const UInt32 flags = arc.ErrorInfo.GetErrorFlags();
+ if (flags != 0)
+ prop = flags;
+ break;
+ }
+ case kpidWarningFlags:
+ {
+ const UInt32 flags = arc.ErrorInfo.GetWarningFlags();
+ if (flags != 0)
+ prop = flags;
+ break;
+ }
+ case kpidOffset:
+ {
+ const Int64 v = arc.GetGlobalOffset();
+ if (v != 0)
+ prop.Set_Int64(v);
+ break;
+ }
+ case kpidTailSize:
+ {
+ if (arc.ErrorInfo.TailSize != 0)
+ prop = arc.ErrorInfo.TailSize;
+ break;
+ }
+ default: return arc.Archive->GetArchiveProperty(propID, value);
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CAgent::GetArcNumProps(UInt32 level, UInt32 *numProps))
+{
+ return _archiveLink.Arcs[level].Archive->GetNumberOfArchiveProperties(numProps);
+}
+
+Z7_COM7F_IMF(CAgent::GetArcPropInfo(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType))
+{
+ return _archiveLink.Arcs[level].Archive->GetArchivePropertyInfo(index, name, propID, varType);
+}
+
+// MainItemProperty
+Z7_COM7F_IMF(CAgent::GetArcProp2(UInt32 level, PROPID propID, PROPVARIANT *value))
+{
+ return _archiveLink.Arcs[level - 1].Archive->GetProperty(_archiveLink.Arcs[level].SubfileIndex, propID, value);
+}
+
+Z7_COM7F_IMF(CAgent::GetArcNumProps2(UInt32 level, UInt32 *numProps))
+{
+ return _archiveLink.Arcs[level - 1].Archive->GetNumberOfProperties(numProps);
+}
+
+Z7_COM7F_IMF(CAgent::GetArcPropInfo2(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType))
+{
+ return _archiveLink.Arcs[level - 1].Archive->GetPropertyInfo(index, name, propID, varType);
+}
diff --git a/CPP/7zip/UI/Agent/Agent.h b/CPP/7zip/UI/Agent/Agent.h
new file mode 100644
index 0000000..ea81aa8
--- /dev/null
+++ b/CPP/7zip/UI/Agent/Agent.h
@@ -0,0 +1,353 @@
+// Agent/Agent.h
+
+#ifndef ZIP7_INC_AGENT_AGENT_H
+#define ZIP7_INC_AGENT_AGENT_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#include "../Common/LoadCodecs.h"
+#include "../Common/OpenArchive.h"
+#include "../Common/UpdateAction.h"
+
+#include "../FileManager/IFolder.h"
+
+#include "AgentProxy.h"
+#include "IFolderArchive.h"
+
+extern CCodecs *g_CodecsObj;
+HRESULT LoadGlobalCodecs();
+void FreeGlobalCodecs();
+
+class CAgentFolder;
+
+Z7_PURE_INTERFACES_BEGIN
+
+#define Z7_IFACEM_IArchiveFolderInternal(x) \
+ x(GetAgentFolder(CAgentFolder **agentFolder))
+Z7_IFACE_CONSTR_FOLDERARC(IArchiveFolderInternal, 0xC)
+
+Z7_PURE_INTERFACES_END
+
+struct CProxyItem
+{
+ unsigned DirIndex;
+ unsigned Index;
+};
+
+class CAgent;
+
+enum AGENT_OP
+{
+ AGENT_OP_Uni,
+ AGENT_OP_Delete,
+ AGENT_OP_CreateFolder,
+ AGENT_OP_Rename,
+ AGENT_OP_CopyFromFile,
+ AGENT_OP_Comment
+};
+
+class CAgentFolder Z7_final:
+ public IFolderFolder,
+ public IFolderAltStreams,
+ public IFolderProperties,
+ public IArchiveGetRawProps,
+ public IGetFolderArcProps,
+ public IFolderCompare,
+ public IFolderGetItemName,
+ public IArchiveFolder,
+ public IArchiveFolderInternal,
+ public IInArchiveGetStream,
+ public IFolderSetZoneIdMode,
+ public IFolderOperations,
+ public IFolderSetFlatMode,
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(IFolderFolder)
+ Z7_COM_QI_ENTRY(IFolderAltStreams)
+ Z7_COM_QI_ENTRY(IFolderProperties)
+ Z7_COM_QI_ENTRY(IArchiveGetRawProps)
+ Z7_COM_QI_ENTRY(IGetFolderArcProps)
+ Z7_COM_QI_ENTRY(IFolderCompare)
+ Z7_COM_QI_ENTRY(IFolderGetItemName)
+ Z7_COM_QI_ENTRY(IArchiveFolder)
+ Z7_COM_QI_ENTRY(IArchiveFolderInternal)
+ Z7_COM_QI_ENTRY(IInArchiveGetStream)
+ Z7_COM_QI_ENTRY(IFolderSetZoneIdMode)
+ Z7_COM_QI_ENTRY(IFolderOperations)
+ Z7_COM_QI_ENTRY(IFolderSetFlatMode)
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(IFolderFolder)
+ Z7_IFACE_COM7_IMP(IFolderAltStreams)
+ Z7_IFACE_COM7_IMP(IFolderProperties)
+ Z7_IFACE_COM7_IMP(IArchiveGetRawProps)
+ Z7_IFACE_COM7_IMP(IGetFolderArcProps)
+ Z7_IFACE_COM7_IMP(IFolderCompare)
+ Z7_IFACE_COM7_IMP(IFolderGetItemName)
+ Z7_IFACE_COM7_IMP(IArchiveFolder)
+ Z7_IFACE_COM7_IMP(IArchiveFolderInternal)
+ Z7_IFACE_COM7_IMP(IInArchiveGetStream)
+ Z7_IFACE_COM7_IMP(IFolderSetZoneIdMode)
+ Z7_IFACE_COM7_IMP(IFolderOperations)
+ Z7_IFACE_COM7_IMP(IFolderSetFlatMode)
+
+ void LoadFolder(unsigned proxyDirIndex);
+public:
+ HRESULT BindToFolder_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder);
+ HRESULT BindToAltStreams_Internal(unsigned proxyDirIndex, IFolderFolder **resultFolder);
+ int GetRealIndex(unsigned index) const;
+ void GetRealIndices(const UInt32 *indices, UInt32 numItems,
+ bool includeAltStreams, bool includeFolderSubItemsInFlatMode, CUIntVector &realIndices) const;
+
+ int CompareItems3(UInt32 index1, UInt32 index2, PROPID propID);
+ int CompareItems2(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw);
+
+ CAgentFolder():
+ _proxyDirIndex(0),
+ _isAltStreamFolder(false),
+ _flatMode(false),
+ _loadAltStreams(false) // _loadAltStreams alt streams works in flat mode, but we don't use it now
+ , _zoneMode(NExtract::NZoneIdMode::kNone)
+ /* , _replaceAltStreamCharsMode(0) */
+ {}
+
+ void Init(const CProxyArc *proxy, const CProxyArc2 *proxy2,
+ unsigned proxyDirIndex,
+ /* IFolderFolder *parentFolder, */
+ CAgent *agent)
+ {
+ _proxy = proxy;
+ _proxy2 = proxy2;
+ _proxyDirIndex = proxyDirIndex;
+ _isAltStreamFolder = false;
+ if (_proxy2)
+ _isAltStreamFolder = _proxy2->IsAltDir(proxyDirIndex);
+ // _parentFolder = parentFolder;
+ _agent = (IInFolderArchive *)agent;
+ _agentSpec = agent;
+ }
+
+ void GetPathParts(UStringVector &pathParts, bool &isAltStreamFolder);
+ HRESULT CommonUpdateOperation(
+ AGENT_OP operation,
+ bool moveMode,
+ const wchar_t *newItemName,
+ const NUpdateArchive::CActionSet *actionSet,
+ const UInt32 *indices, UInt32 numItems,
+ IProgress *progress);
+
+
+ void GetPrefix(UInt32 index, UString &prefix) const;
+ UString GetName(UInt32 index) const;
+ UString GetFullPrefix(UInt32 index) const; // relative too root folder of archive
+
+public:
+ const CProxyArc *_proxy;
+ const CProxyArc2 *_proxy2;
+ unsigned _proxyDirIndex;
+ bool _isAltStreamFolder;
+ // CMyComPtr<IFolderFolder> _parentFolder;
+ CMyComPtr<IInFolderArchive> _agent;
+ CAgent *_agentSpec;
+
+ CRecordVector<CProxyItem> _items;
+ bool _flatMode;
+ bool _loadAltStreams; // in Flat mode
+ // Int32 _replaceAltStreamCharsMode;
+ NExtract::NZoneIdMode::EEnum _zoneMode;
+};
+
+class CAgent Z7_final:
+ public IInFolderArchive,
+ public IFolderArcProps,
+ #ifndef Z7_EXTRACT_ONLY
+ public IOutFolderArchive,
+ public ISetProperties,
+ #endif
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(IInFolderArchive)
+ Z7_COM_QI_ENTRY(IFolderArcProps)
+ #ifndef Z7_EXTRACT_ONLY
+ Z7_COM_QI_ENTRY(IOutFolderArchive)
+ Z7_COM_QI_ENTRY(ISetProperties)
+ #endif
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(IInFolderArchive)
+ Z7_IFACE_COM7_IMP(IFolderArcProps)
+
+ #ifndef Z7_EXTRACT_ONLY
+ Z7_IFACE_COM7_IMP(ISetProperties)
+
+public:
+ Z7_IFACE_COM7_IMP(IOutFolderArchive)
+ HRESULT CommonUpdate(ISequentialOutStream *outArchiveStream,
+ unsigned numUpdateItems, IArchiveUpdateCallback *updateCallback);
+
+ HRESULT CreateFolder(ISequentialOutStream *outArchiveStream,
+ const wchar_t *folderName, IFolderArchiveUpdateCallback *updateCallback100);
+
+ HRESULT RenameItem(ISequentialOutStream *outArchiveStream,
+ const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName,
+ IFolderArchiveUpdateCallback *updateCallback100);
+
+ HRESULT CommentItem(ISequentialOutStream *outArchiveStream,
+ const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName,
+ IFolderArchiveUpdateCallback *updateCallback100);
+
+ HRESULT UpdateOneFile(ISequentialOutStream *outArchiveStream,
+ const UInt32 *indices, UInt32 numItems, const wchar_t *diskFilePath,
+ IFolderArchiveUpdateCallback *updateCallback100);
+ #endif
+
+private:
+ HRESULT ReadItems();
+
+public:
+ CProxyArc *_proxy;
+ CProxyArc2 *_proxy2;
+ CArchiveLink _archiveLink;
+
+ bool ThereIsPathProp;
+ // bool ThereIsAltStreamProp;
+
+ UString ArchiveType;
+
+ FStringVector _names;
+ FString _folderPrefix; // for new files from disk
+
+ bool _updatePathPrefix_is_AltFolder;
+ UString _updatePathPrefix;
+ CAgentFolder *_agentFolder;
+
+ UString _archiveFilePath;
+ DWORD _attrib;
+ bool _isDeviceFile;
+ bool _isHashHandler;
+ FString _hashBaseFolderPrefix;
+
+ #ifndef Z7_EXTRACT_ONLY
+ CObjectVector<UString> m_PropNames;
+ CObjectVector<NWindows::NCOM::CPropVariant> m_PropValues;
+ #endif
+
+ CAgent();
+ ~CAgent();
+
+ const CArc &GetArc() const { return _archiveLink.Arcs.Back(); }
+ IInArchive *GetArchive() const { if ( _archiveLink.Arcs.IsEmpty()) return NULL; return GetArc().Archive; }
+ bool CanUpdate() const;
+
+ bool Is_Attrib_ReadOnly() const
+ {
+ return _attrib != INVALID_FILE_ATTRIBUTES && (_attrib & FILE_ATTRIBUTE_READONLY);
+ }
+
+ bool IsThere_ReadOnlyArc() const
+ {
+ FOR_VECTOR (i, _archiveLink.Arcs)
+ {
+ const CArc &arc = _archiveLink.Arcs[i];
+ if (arc.FormatIndex < 0
+ || arc.IsReadOnly
+ || !g_CodecsObj->Formats[arc.FormatIndex].UpdateEnabled)
+ return true;
+ }
+ return false;
+ }
+
+ UString GetTypeOfArc(const CArc &arc) const
+ {
+ if (arc.FormatIndex < 0)
+ return UString("Parser");
+ return g_CodecsObj->GetFormatNamePtr(arc.FormatIndex);
+ }
+
+ UString GetErrorMessage() const
+ {
+ UString s;
+ for (int i = (int)_archiveLink.Arcs.Size() - 1; i >= 0; i--)
+ {
+ const CArc &arc = _archiveLink.Arcs[i];
+
+ UString s2;
+ if (arc.ErrorInfo.ErrorFormatIndex >= 0)
+ {
+ if (arc.ErrorInfo.ErrorFormatIndex == arc.FormatIndex)
+ s2 += "Warning: The archive is open with offset";
+ else
+ {
+ s2 += "Cannot open the file as [";
+ s2 += g_CodecsObj->GetFormatNamePtr(arc.ErrorInfo.ErrorFormatIndex);
+ s2 += "] archive";
+ }
+ }
+
+ if (!arc.ErrorInfo.ErrorMessage.IsEmpty())
+ {
+ if (!s2.IsEmpty())
+ s2.Add_LF();
+ s2 += "\n[";
+ s2 += GetTypeOfArc(arc);
+ s2 += "]: ";
+ s2 += arc.ErrorInfo.ErrorMessage;
+ }
+
+ if (!s2.IsEmpty())
+ {
+ if (!s.IsEmpty())
+ s += "--------------------\n";
+ s += arc.Path;
+ s.Add_LF();
+ s += s2;
+ s.Add_LF();
+ }
+ }
+ return s;
+ }
+
+ void KeepModeForNextOpen() { _archiveLink.KeepModeForNextOpen(); }
+};
+
+
+// #ifdef NEW_FOLDER_INTERFACE
+
+struct CCodecIcons
+{
+ struct CIconPair
+ {
+ UString Ext;
+ int IconIndex;
+ };
+ CObjectVector<CIconPair> IconPairs;
+
+ // void Clear() { IconPairs.Clear(); }
+ void LoadIcons(HMODULE m);
+ bool FindIconIndex(const UString &ext, int &iconIndex) const;
+};
+
+
+Z7_CLASS_IMP_COM_1(
+ CArchiveFolderManager
+ , IFolderManager
+)
+ CObjectVector<CCodecIcons> CodecIconsVector;
+ CCodecIcons InternalIcons;
+ bool WasLoaded;
+
+ void LoadFormats();
+ // int FindFormat(const UString &type);
+public:
+ CArchiveFolderManager():
+ WasLoaded(false)
+ {}
+};
+
+// #endif
+
+#endif
diff --git a/CPP/7zip/UI/Agent/AgentOut.cpp b/CPP/7zip/UI/Agent/AgentOut.cpp
new file mode 100644
index 0000000..b5a25a3
--- /dev/null
+++ b/CPP/7zip/UI/Agent/AgentOut.cpp
@@ -0,0 +1,725 @@
+// AgentOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/TimeUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../../Common/FileStreams.h"
+
+#include "../../Archive/Common/ItemNameUtils.h"
+
+#include "Agent.h"
+#include "UpdateCallbackAgent.h"
+
+using namespace NWindows;
+using namespace NCOM;
+
+Z7_COM7F_IMF(CAgent::SetFolder(IFolderFolder *folder))
+{
+ _updatePathPrefix.Empty();
+ _updatePathPrefix_is_AltFolder = false;
+ _agentFolder = NULL;
+
+ if (!folder)
+ return S_OK;
+
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IArchiveFolderInternal,
+ afi, folder)
+ if (afi)
+ {
+ RINOK(afi->GetAgentFolder(&_agentFolder))
+ }
+ if (!_agentFolder)
+ return E_FAIL;
+ }
+
+ if (_proxy2)
+ _updatePathPrefix = _proxy2->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex, _updatePathPrefix_is_AltFolder);
+ else
+ _updatePathPrefix = _proxy->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CAgent::SetFiles(const wchar_t *folderPrefix,
+ const wchar_t * const *names, UInt32 numNames))
+{
+ _folderPrefix = us2fs(folderPrefix);
+ _names.ClearAndReserve(numNames);
+ for (UInt32 i = 0; i < numNames; i++)
+ _names.AddInReserved(us2fs(names[i]));
+ return S_OK;
+}
+
+static HRESULT EnumerateArchiveItems(CAgent *agent,
+ const CProxyDir &item,
+ const UString &prefix,
+ CObjectVector<CArcItem> &arcItems)
+{
+ unsigned i;
+
+ for (i = 0; i < item.SubFiles.Size(); i++)
+ {
+ unsigned arcIndex = item.SubFiles[i];
+ const CProxyFile &fileItem = agent->_proxy->Files[arcIndex];
+ CArcItem ai;
+ RINOK(agent->GetArc().GetItem_MTime(arcIndex, ai.MTime))
+ RINOK(agent->GetArc().GetItem_Size(arcIndex, ai.Size, ai.Size_Defined))
+ ai.IsDir = false;
+ ai.Name = prefix + fileItem.Name;
+ ai.Censored = true; // test it
+ ai.IndexInServer = arcIndex;
+ arcItems.Add(ai);
+ }
+
+ for (i = 0; i < item.SubDirs.Size(); i++)
+ {
+ const CProxyDir &dirItem = agent->_proxy->Dirs[item.SubDirs[i]];
+ UString fullName = prefix + dirItem.Name;
+ if (dirItem.IsLeaf())
+ {
+ CArcItem ai;
+ RINOK(agent->GetArc().GetItem_MTime((unsigned)dirItem.ArcIndex, ai.MTime))
+ ai.IsDir = true;
+ ai.Size_Defined = false;
+ ai.Name = fullName;
+ ai.Censored = true; // test it
+ ai.IndexInServer = (unsigned)dirItem.ArcIndex;
+ arcItems.Add(ai);
+ }
+ RINOK(EnumerateArchiveItems(agent, dirItem, fullName + WCHAR_PATH_SEPARATOR, arcItems))
+ }
+
+ return S_OK;
+}
+
+static HRESULT EnumerateArchiveItems2(const CAgent *agent,
+ unsigned dirIndex,
+ const UString &prefix,
+ CObjectVector<CArcItem> &arcItems)
+{
+ const CProxyDir2 &dir = agent->_proxy2->Dirs[dirIndex];
+ FOR_VECTOR (i, dir.Items)
+ {
+ unsigned arcIndex = dir.Items[i];
+ const CProxyFile2 &file = agent->_proxy2->Files[arcIndex];
+ CArcItem ai;
+ ai.IndexInServer = arcIndex;
+ ai.Name = prefix + file.Name;
+ ai.Censored = true; // test it
+ RINOK(agent->GetArc().GetItem_MTime(arcIndex, ai.MTime))
+ ai.IsDir = file.IsDir();
+ ai.Size_Defined = false;
+ ai.IsAltStream = file.IsAltStream;
+ if (!ai.IsDir)
+ {
+ RINOK(agent->GetArc().GetItem_Size(arcIndex, ai.Size, ai.Size_Defined))
+ ai.IsDir = false;
+ }
+ arcItems.Add(ai);
+
+ if (file.AltDirIndex != -1)
+ {
+ RINOK(EnumerateArchiveItems2(agent, (unsigned)file.AltDirIndex, ai.Name + L':', arcItems))
+ }
+
+ if (ai.IsDir)
+ {
+ RINOK(EnumerateArchiveItems2(agent, (unsigned)file.DirIndex, ai.Name + WCHAR_PATH_SEPARATOR, arcItems))
+ }
+ }
+ return S_OK;
+}
+
+struct CAgUpCallbackImp Z7_final: public IUpdateProduceCallback
+{
+ const CObjectVector<CArcItem> *_arcItems;
+ IFolderArchiveUpdateCallback *_callback;
+
+ CAgUpCallbackImp(const CObjectVector<CArcItem> *a,
+ IFolderArchiveUpdateCallback *callback): _arcItems(a), _callback(callback) {}
+ HRESULT ShowDeleteFile(unsigned arcIndex) Z7_override;
+};
+
+HRESULT CAgUpCallbackImp::ShowDeleteFile(unsigned arcIndex)
+{
+ return _callback->DeleteOperation((*_arcItems)[arcIndex].Name);
+}
+
+
+static void SetInArchiveInterfaces(CAgent *agent, CArchiveUpdateCallback *upd)
+{
+ if (agent->_archiveLink.Arcs.IsEmpty())
+ return;
+ const CArc &arc = agent->GetArc();
+ upd->Arc = &arc;
+ upd->Archive = arc.Archive;
+
+ upd->ArcFileName = ExtractFileNameFromPath(arc.Path);
+}
+
+struct CDirItemsCallback_AgentOut Z7_final: public IDirItemsCallback
+{
+ CMyComPtr<IFolderScanProgress> FolderScanProgress;
+ IFolderArchiveUpdateCallback *FolderArchiveUpdateCallback;
+ HRESULT ErrorCode;
+
+ CDirItemsCallback_AgentOut(): FolderArchiveUpdateCallback(NULL), ErrorCode(S_OK) {}
+
+ HRESULT ScanError(const FString &name, DWORD systemError) Z7_override
+ {
+ const HRESULT hres = HRESULT_FROM_WIN32(systemError);
+ if (FolderArchiveUpdateCallback)
+ return FolderScanProgress->ScanError(fs2us(name), hres);
+ ErrorCode = hres;
+ return ErrorCode;
+ }
+
+ HRESULT ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir) Z7_override
+ {
+ if (FolderScanProgress)
+ return FolderScanProgress->ScanProgress(st.NumDirs, st.NumFiles + st.NumAltStreams,
+ st.GetTotalBytes(), fs2us(path), BoolToInt(isDir));
+ if (FolderArchiveUpdateCallback)
+ return FolderArchiveUpdateCallback->SetNumFiles(st.NumFiles);
+ return S_OK;
+ }
+};
+
+
+Z7_COM7F_IMF(CAgent::DoOperation(
+ FStringVector *requestedPaths,
+ FStringVector *processedPaths,
+ CCodecs *codecs,
+ int formatIndex,
+ ISequentialOutStream *outArchiveStream,
+ const Byte *stateActions,
+ const wchar_t *sfxModule,
+ IFolderArchiveUpdateCallback *updateCallback100))
+{
+ if (!CanUpdate())
+ return E_NOTIMPL;
+
+ NUpdateArchive::CActionSet actionSet;
+ {
+ for (unsigned i = 0; i < NUpdateArchive::NPairState::kNumValues; i++)
+ actionSet.StateActions[i] = (NUpdateArchive::NPairAction::EEnum)stateActions[i];
+ }
+
+ CDirItemsCallback_AgentOut enumCallback;
+ if (updateCallback100)
+ {
+ enumCallback.FolderArchiveUpdateCallback = updateCallback100;
+ updateCallback100->QueryInterface(IID_IFolderScanProgress, (void **)&enumCallback.FolderScanProgress);
+ }
+
+ CDirItems dirItems;
+ dirItems.Callback = &enumCallback;
+
+ {
+ FString folderPrefix = _folderPrefix;
+ if (!NFile::NName::IsAltStreamPrefixWithColon(fs2us(folderPrefix)))
+ NFile::NName::NormalizeDirPathPrefix(folderPrefix);
+
+ RINOK(dirItems.EnumerateItems2(folderPrefix, _updatePathPrefix, _names, requestedPaths))
+
+ if (_updatePathPrefix_is_AltFolder)
+ {
+ FOR_VECTOR(i, dirItems.Items)
+ {
+ CDirItem &item = dirItems.Items[i];
+ if (item.IsDir())
+ return E_NOTIMPL;
+ item.IsAltStream = true;
+ }
+ }
+ }
+
+ CMyComPtr<IOutArchive> outArchive;
+
+ if (GetArchive())
+ {
+ RINOK(GetArchive()->QueryInterface(IID_IOutArchive, (void **)&outArchive))
+ }
+ else
+ {
+ if (formatIndex < 0)
+ return E_FAIL;
+ RINOK(codecs->CreateOutArchive((unsigned)formatIndex, outArchive))
+
+ #ifdef Z7_EXTERNAL_CODECS
+ {
+ CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+ outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+ if (setCompressCodecsInfo)
+ {
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs))
+ }
+ }
+ #endif
+ }
+
+ NFileTimeType::EEnum fileTimeType = NFileTimeType::kNotDefined;
+ UInt32 value;
+ RINOK(outArchive->GetFileTimeType(&value))
+ // we support any future fileType here.
+ // 22.00:
+ fileTimeType = (NFileTimeType::EEnum)value;
+ /*
+ switch (value)
+ {
+ case NFileTimeType::kWindows:
+ case NFileTimeType::kDOS:
+ case NFileTimeType::kUnix:
+ fileTimeType = NFileTimeType::EEnum(value);
+ break;
+ default:
+ {
+ return E_FAIL;
+ }
+ }
+ */
+
+
+ CObjectVector<CArcItem> arcItems;
+ if (GetArchive())
+ {
+ RINOK(ReadItems())
+ if (_proxy2)
+ {
+ RINOK(EnumerateArchiveItems2(this, k_Proxy2_RootDirIndex, L"", arcItems))
+ RINOK(EnumerateArchiveItems2(this, k_Proxy2_AltRootDirIndex, L":", arcItems))
+ }
+ else
+ {
+ RINOK(EnumerateArchiveItems(this, _proxy->Dirs[0], L"", arcItems))
+ }
+ }
+
+ CRecordVector<CUpdatePair2> updatePairs2;
+
+ {
+ CRecordVector<CUpdatePair> updatePairs;
+ GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs);
+ CAgUpCallbackImp upCallback(&arcItems, updateCallback100);
+ UpdateProduce(updatePairs, actionSet, updatePairs2, &upCallback);
+ }
+
+ UInt32 numFiles = 0;
+ {
+ FOR_VECTOR (i, updatePairs2)
+ if (updatePairs2[i].NewData)
+ numFiles++;
+ }
+
+ if (updateCallback100)
+ {
+ RINOK(updateCallback100->SetNumFiles(numFiles))
+ }
+
+ CUpdateCallbackAgent updateCallbackAgent;
+ updateCallbackAgent.SetCallback(updateCallback100);
+ CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+ CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec );
+
+ updateCallbackSpec->DirItems = &dirItems;
+ updateCallbackSpec->ArcItems = &arcItems;
+ updateCallbackSpec->UpdatePairs = &updatePairs2;
+
+ SetInArchiveInterfaces(this, updateCallbackSpec);
+
+ updateCallbackSpec->Callback = &updateCallbackAgent;
+
+ CByteBuffer processedItems;
+ if (processedPaths)
+ {
+ unsigned num = dirItems.Items.Size();
+ processedItems.Alloc(num);
+ for (unsigned i = 0; i < num; i++)
+ processedItems[i] = 0;
+ updateCallbackSpec->ProcessedItemsStatuses = processedItems;
+ }
+
+ Z7_DECL_CMyComPtr_QI_FROM(
+ ISetProperties,
+ setProperties, outArchive)
+ if (setProperties)
+ {
+ if (m_PropNames.Size() == 0)
+ {
+ RINOK(setProperties->SetProperties(NULL, NULL, 0))
+ }
+ else
+ {
+ CRecordVector<const wchar_t *> names;
+ FOR_VECTOR (i, m_PropNames)
+ names.Add((const wchar_t *)m_PropNames[i]);
+
+ CPropVariant *propValues = new CPropVariant[m_PropValues.Size()];
+ try
+ {
+ FOR_VECTOR (i, m_PropValues)
+ propValues[i] = m_PropValues[i];
+ RINOK(setProperties->SetProperties(&names.Front(), propValues, names.Size()))
+ }
+ catch(...)
+ {
+ delete []propValues;
+ return E_FAIL;
+ }
+ delete []propValues;
+ }
+ }
+ m_PropNames.Clear();
+ m_PropValues.Clear();
+
+ if (sfxModule != NULL)
+ {
+ CInFileStream *sfxStreamSpec = new CInFileStream;
+ CMyComPtr<IInStream> sfxStream(sfxStreamSpec);
+ if (!sfxStreamSpec->Open(us2fs(sfxModule)))
+ return E_FAIL;
+ // throw "Can't open sfx module";
+ RINOK(NCompress::CopyStream(sfxStream, outArchiveStream, NULL))
+ }
+
+ HRESULT res = outArchive->UpdateItems(outArchiveStream, updatePairs2.Size(), updateCallback);
+ if (res == S_OK && processedPaths)
+ {
+ {
+ /* OutHandler for 7z archives doesn't report compression operation for empty files.
+ So we must include these files manually */
+ FOR_VECTOR(i, updatePairs2)
+ {
+ const CUpdatePair2 &up = updatePairs2[i];
+ if (up.DirIndex != -1 && up.NewData)
+ {
+ const CDirItem &di = dirItems.Items[(unsigned)up.DirIndex];
+ if (!di.IsDir() && di.Size == 0)
+ processedItems[(unsigned)up.DirIndex] = 1;
+ }
+ }
+ }
+
+ FOR_VECTOR (i, dirItems.Items)
+ if (processedItems[i] != 0)
+ processedPaths->Add(dirItems.GetPhyPath(i));
+ }
+ return res;
+}
+
+Z7_COM7F_IMF(CAgent::DoOperation2(
+ FStringVector *requestedPaths,
+ FStringVector *processedPaths,
+ ISequentialOutStream *outArchiveStream,
+ const Byte *stateActions, const wchar_t *sfxModule, IFolderArchiveUpdateCallback *updateCallback100))
+{
+ return DoOperation(requestedPaths, processedPaths, g_CodecsObj, -1, outArchiveStream, stateActions, sfxModule, updateCallback100);
+}
+
+HRESULT CAgent::CommonUpdate(ISequentialOutStream *outArchiveStream,
+ unsigned numUpdateItems, IArchiveUpdateCallback *updateCallback)
+{
+ if (!CanUpdate())
+ return E_NOTIMPL;
+ CMyComPtr<IOutArchive> outArchive;
+ RINOK(GetArchive()->QueryInterface(IID_IOutArchive, (void **)&outArchive))
+ return outArchive->UpdateItems(outArchiveStream, numUpdateItems, updateCallback);
+}
+
+Z7_COM7F_IMF(CAgent::DeleteItems(ISequentialOutStream *outArchiveStream,
+ const UInt32 *indices, UInt32 numItems,
+ IFolderArchiveUpdateCallback *updateCallback100))
+{
+ if (!CanUpdate())
+ return E_NOTIMPL;
+ CRecordVector<CUpdatePair2> updatePairs;
+ CUpdateCallbackAgent updateCallbackAgent;
+ updateCallbackAgent.SetCallback(updateCallback100);
+ CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+ CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+
+ CUIntVector realIndices;
+ _agentFolder->GetRealIndices(indices, numItems,
+ true, // includeAltStreams
+ false, // includeFolderSubItemsInFlatMode, we don't want to delete subItems in Flat Mode
+ realIndices);
+ unsigned curIndex = 0;
+ UInt32 numItemsInArchive;
+ RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive))
+
+ UString deletePath;
+
+ for (UInt32 i = 0; i < numItemsInArchive; i++)
+ {
+ if (curIndex < realIndices.Size())
+ if (realIndices[curIndex] == i)
+ {
+ RINOK(GetArc().GetItem_Path2(i, deletePath))
+ RINOK(updateCallback100->DeleteOperation(deletePath))
+
+ curIndex++;
+ continue;
+ }
+ CUpdatePair2 up2;
+ up2.SetAs_NoChangeArcItem(i);
+ updatePairs.Add(up2);
+ }
+ updateCallbackSpec->UpdatePairs = &updatePairs;
+
+ SetInArchiveInterfaces(this, updateCallbackSpec);
+
+ updateCallbackSpec->Callback = &updateCallbackAgent;
+ return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback);
+}
+
+HRESULT CAgent::CreateFolder(ISequentialOutStream *outArchiveStream,
+ const wchar_t *folderName, IFolderArchiveUpdateCallback *updateCallback100)
+{
+ if (!CanUpdate())
+ return E_NOTIMPL;
+ CRecordVector<CUpdatePair2> updatePairs;
+ CDirItems dirItems;
+ CUpdateCallbackAgent updateCallbackAgent;
+ updateCallbackAgent.SetCallback(updateCallback100);
+ CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+ CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+
+ UInt32 numItemsInArchive;
+ RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive))
+ for (UInt32 i = 0; i < numItemsInArchive; i++)
+ {
+ CUpdatePair2 up2;
+ up2.SetAs_NoChangeArcItem(i);
+ updatePairs.Add(up2);
+ }
+ CUpdatePair2 up2;
+ up2.NewData = up2.NewProps = true;
+ up2.UseArcProps = false;
+ up2.DirIndex = 0;
+
+ updatePairs.Add(up2);
+
+ updatePairs.ReserveDown();
+
+ CDirItem di;
+
+ di.Attrib = FILE_ATTRIBUTE_DIRECTORY;
+ di.Size = 0;
+ bool isAltStreamFolder = false;
+ if (_proxy2)
+ di.Name = _proxy2->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex, isAltStreamFolder);
+ else
+ di.Name = _proxy->GetDirPath_as_Prefix(_agentFolder->_proxyDirIndex);
+ di.Name += folderName;
+
+ FILETIME ft;
+ NTime::GetCurUtcFileTime(ft);
+ di.CTime = di.ATime = di.MTime = ft;
+
+ dirItems.Items.Add(di);
+
+ updateCallbackSpec->Callback = &updateCallbackAgent;
+ updateCallbackSpec->DirItems = &dirItems;
+ updateCallbackSpec->UpdatePairs = &updatePairs;
+
+ SetInArchiveInterfaces(this, updateCallbackSpec);
+
+ return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback);
+}
+
+
+HRESULT CAgent::RenameItem(ISequentialOutStream *outArchiveStream,
+ const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName,
+ IFolderArchiveUpdateCallback *updateCallback100)
+{
+ if (!CanUpdate())
+ return E_NOTIMPL;
+ if (numItems != 1)
+ return E_INVALIDARG;
+ if (!_archiveLink.IsOpen)
+ return E_FAIL;
+ CRecordVector<CUpdatePair2> updatePairs;
+ CUpdateCallbackAgent updateCallbackAgent;
+ updateCallbackAgent.SetCallback(updateCallback100);
+ CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+ CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+
+ CUIntVector realIndices;
+ _agentFolder->GetRealIndices(indices, numItems,
+ true, // includeAltStreams
+ true, // includeFolderSubItemsInFlatMode
+ realIndices);
+
+ const UInt32 ind0 = indices[0];
+ const int mainRealIndex = _agentFolder->GetRealIndex(ind0);
+ const UString fullPrefix = _agentFolder->GetFullPrefix(ind0);
+ UString name = _agentFolder->GetName(ind0);
+ // 22.00 : we normalize name
+ NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name);
+ const UString oldItemPath = fullPrefix + name;
+ const UString newItemPath = fullPrefix + newItemName;
+
+ UStringVector newNames;
+
+ unsigned curIndex = 0;
+ UInt32 numItemsInArchive;
+ RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive))
+
+ for (UInt32 i = 0; i < numItemsInArchive; i++)
+ {
+ CUpdatePair2 up2;
+ up2.SetAs_NoChangeArcItem(i);
+ if (curIndex < realIndices.Size())
+ if (realIndices[curIndex] == i)
+ {
+ up2.NewProps = true;
+ RINOK(GetArc().IsItem_Anti(i, up2.IsAnti)) // it must work without that line too.
+
+ UString oldFullPath;
+ RINOK(GetArc().GetItem_Path2(i, oldFullPath))
+
+ if (!IsPath1PrefixedByPath2(oldFullPath, oldItemPath))
+ return E_INVALIDARG;
+
+ up2.NewNameIndex = (int)newNames.Add(newItemPath + oldFullPath.Ptr(oldItemPath.Len()));
+ up2.IsMainRenameItem = (mainRealIndex == (int)i);
+ curIndex++;
+ }
+ updatePairs.Add(up2);
+ }
+
+ updateCallbackSpec->Callback = &updateCallbackAgent;
+ updateCallbackSpec->UpdatePairs = &updatePairs;
+ updateCallbackSpec->NewNames = &newNames;
+
+ SetInArchiveInterfaces(this, updateCallbackSpec);
+
+ return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback);
+}
+
+
+HRESULT CAgent::CommentItem(ISequentialOutStream *outArchiveStream,
+ const UInt32 *indices, UInt32 numItems, const wchar_t *newItemName,
+ IFolderArchiveUpdateCallback *updateCallback100)
+{
+ if (!CanUpdate())
+ return E_NOTIMPL;
+ if (numItems != 1)
+ return E_INVALIDARG;
+ if (!_archiveLink.IsOpen)
+ return E_FAIL;
+
+ CRecordVector<CUpdatePair2> updatePairs;
+ CUpdateCallbackAgent updateCallbackAgent;
+ updateCallbackAgent.SetCallback(updateCallback100);
+ CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+ CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+
+ const int mainRealIndex = _agentFolder->GetRealIndex(indices[0]);
+
+ if (mainRealIndex < 0)
+ return E_NOTIMPL;
+
+ UInt32 numItemsInArchive;
+ RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive))
+
+ UString newName = newItemName;
+
+ for (UInt32 i = 0; i < numItemsInArchive; i++)
+ {
+ CUpdatePair2 up2;
+ up2.SetAs_NoChangeArcItem(i);
+ if ((int)i == mainRealIndex)
+ up2.NewProps = true;
+ updatePairs.Add(up2);
+ }
+
+ updateCallbackSpec->Callback = &updateCallbackAgent;
+ updateCallbackSpec->UpdatePairs = &updatePairs;
+ updateCallbackSpec->CommentIndex = mainRealIndex;
+ updateCallbackSpec->Comment = &newName;
+
+ SetInArchiveInterfaces(this, updateCallbackSpec);
+
+ return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback);
+}
+
+
+
+HRESULT CAgent::UpdateOneFile(ISequentialOutStream *outArchiveStream,
+ const UInt32 *indices, UInt32 numItems, const wchar_t *diskFilePath,
+ IFolderArchiveUpdateCallback *updateCallback100)
+{
+ if (!CanUpdate())
+ return E_NOTIMPL;
+ CRecordVector<CUpdatePair2> updatePairs;
+ CDirItems dirItems;
+ CUpdateCallbackAgent updateCallbackAgent;
+ updateCallbackAgent.SetCallback(updateCallback100);
+ CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+ CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+
+ UInt32 realIndex;
+ {
+ CUIntVector realIndices;
+ _agentFolder->GetRealIndices(indices, numItems,
+ false, // includeAltStreams // we update only main stream of file
+ false, // includeFolderSubItemsInFlatMode
+ realIndices);
+ if (realIndices.Size() != 1)
+ return E_FAIL;
+ realIndex = realIndices[0];
+ }
+
+ {
+ FStringVector filePaths;
+ filePaths.Add(us2fs(diskFilePath));
+ dirItems.EnumerateItems2(FString(), UString(), filePaths, NULL);
+ if (dirItems.Items.Size() != 1)
+ return E_FAIL;
+ }
+
+ UInt32 numItemsInArchive;
+ RINOK(GetArchive()->GetNumberOfItems(&numItemsInArchive))
+ for (UInt32 i = 0; i < numItemsInArchive; i++)
+ {
+ CUpdatePair2 up2;
+ up2.SetAs_NoChangeArcItem(i);
+ if (realIndex == i)
+ {
+ up2.DirIndex = 0;
+ up2.NewData = true;
+ up2.NewProps = true;
+ up2.UseArcProps = false;
+ }
+ updatePairs.Add(up2);
+ }
+ updateCallbackSpec->DirItems = &dirItems;
+ updateCallbackSpec->Callback = &updateCallbackAgent;
+ updateCallbackSpec->UpdatePairs = &updatePairs;
+
+ SetInArchiveInterfaces(this, updateCallbackSpec);
+
+ updateCallbackSpec->KeepOriginalItemNames = true;
+ return CommonUpdate(outArchiveStream, updatePairs.Size(), updateCallback);
+}
+
+Z7_COM7F_IMF(CAgent::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
+{
+ m_PropNames.Clear();
+ m_PropValues.Clear();
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ m_PropNames.Add(names[i]);
+ m_PropValues.Add(values[i]);
+ }
+ return S_OK;
+}
diff --git a/CPP/7zip/UI/Agent/AgentProxy.cpp b/CPP/7zip/UI/Agent/AgentProxy.cpp
new file mode 100644
index 0000000..df9f315
--- /dev/null
+++ b/CPP/7zip/UI/Agent/AgentProxy.cpp
@@ -0,0 +1,752 @@
+// AgentProxy.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+#ifdef _WIN32
+#include <wchar.h>
+#else
+#include <ctype.h>
+#endif
+
+#include "../../../../C/Sort.h"
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/UTFConvert.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/PropVariantConv.h"
+
+#include "../../Archive/Common/ItemNameUtils.h"
+
+#include "AgentProxy.h"
+
+using namespace NWindows;
+
+int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &insertPos) const
+{
+ const CRecordVector<unsigned> &subDirs = Dirs[dirIndex].SubDirs;
+ unsigned left = 0, right = subDirs.Size();
+ for (;;)
+ {
+ if (left == right)
+ {
+ insertPos = left;
+ return -1;
+ }
+ const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const unsigned dirIndex2 = subDirs[mid];
+ const int comp = CompareFileNames(name, Dirs[dirIndex2].Name);
+ if (comp == 0)
+ return (int)dirIndex2;
+ if (comp < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+}
+
+int CProxyArc::FindSubDir(unsigned dirIndex, const wchar_t *name) const
+{
+ unsigned insertPos;
+ return FindSubDir(dirIndex, name, insertPos);
+}
+
+static const wchar_t *AllocStringAndCopy(const wchar_t *s, size_t len)
+{
+ wchar_t *p = new wchar_t[len + 1];
+ MyStringCopy(p, s);
+ return p;
+}
+
+static const wchar_t *AllocStringAndCopy(const UString &s)
+{
+ return AllocStringAndCopy(s, s.Len());
+}
+
+unsigned CProxyArc::AddDir(unsigned dirIndex, int arcIndex, const UString &name)
+{
+ unsigned insertPos;
+ int subDirIndex = FindSubDir(dirIndex, name, insertPos);
+ if (subDirIndex != -1)
+ {
+ if (arcIndex != -1)
+ {
+ CProxyDir &item = Dirs[(unsigned)subDirIndex];
+ if (item.ArcIndex == -1)
+ item.ArcIndex = arcIndex;
+ }
+ return (unsigned)subDirIndex;
+ }
+ subDirIndex = (int)Dirs.Size();
+ Dirs[dirIndex].SubDirs.Insert(insertPos, (unsigned)subDirIndex);
+ CProxyDir &item = Dirs.AddNew();
+
+ item.NameLen = name.Len();
+ item.Name = AllocStringAndCopy(name);
+
+ item.ArcIndex = arcIndex;
+ item.ParentDir = (int)dirIndex;
+ return (unsigned)subDirIndex;
+}
+
+void CProxyDir::Clear()
+{
+ SubDirs.Clear();
+ SubFiles.Clear();
+}
+
+void CProxyArc::GetDirPathParts(unsigned dirIndex, UStringVector &pathParts) const
+{
+ pathParts.Clear();
+ // while (dirIndex != -1)
+ for (;;)
+ {
+ const CProxyDir &dir = Dirs[dirIndex];
+ dirIndex = (unsigned)dir.ParentDir;
+ if (dir.ParentDir == -1)
+ break;
+ pathParts.Insert(0, dir.Name);
+ // 22.00: we normalize name
+ NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(pathParts[0]);
+ }
+}
+
+UString CProxyArc::GetDirPath_as_Prefix(unsigned dirIndex) const
+{
+ UString s;
+ // while (dirIndex != -1)
+ for (;;)
+ {
+ const CProxyDir &dir = Dirs[dirIndex];
+ dirIndex = (unsigned)dir.ParentDir;
+ if (dir.ParentDir == -1)
+ break;
+ s.InsertAtFront(WCHAR_PATH_SEPARATOR);
+ s.Insert(0, dir.Name);
+ // 22.00: we normalize name
+ NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(s.GetBuf(), MyStringLen(dir.Name));
+ }
+ return s;
+}
+
+void CProxyArc::AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) const
+{
+ const CProxyDir &dir = Dirs[dirIndex];
+ if (dir.IsLeaf())
+ realIndices.Add((unsigned)dir.ArcIndex);
+ unsigned i;
+ for (i = 0; i < dir.SubDirs.Size(); i++)
+ AddRealIndices(dir.SubDirs[i], realIndices);
+ for (i = 0; i < dir.SubFiles.Size(); i++)
+ realIndices.Add(dir.SubFiles[i]);
+}
+
+int CProxyArc::GetRealIndex(unsigned dirIndex, unsigned index) const
+{
+ const CProxyDir &dir = Dirs[dirIndex];
+ unsigned numDirItems = dir.SubDirs.Size();
+ if (index < numDirItems)
+ {
+ const CProxyDir &f = Dirs[dir.SubDirs[index]];
+ if (f.IsLeaf())
+ return f.ArcIndex;
+ return -1;
+ }
+ return (int)dir.SubFiles[index - numDirItems];
+}
+
+void CProxyArc::GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, CUIntVector &realIndices) const
+{
+ const CProxyDir &dir = Dirs[dirIndex];
+ realIndices.Clear();
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ UInt32 index = indices[i];
+ unsigned numDirItems = dir.SubDirs.Size();
+ if (index < numDirItems)
+ AddRealIndices(dir.SubDirs[index], realIndices);
+ else
+ realIndices.Add(dir.SubFiles[index - numDirItems]);
+ }
+ HeapSort(&realIndices.Front(), realIndices.Size());
+}
+
+///////////////////////////////////////////////
+// CProxyArc
+
+static bool GetSize(IInArchive *archive, UInt32 index, PROPID propID, UInt64 &size)
+{
+ size = 0;
+ NCOM::CPropVariant prop;
+ if (archive->GetProperty(index, propID, &prop) != S_OK)
+ throw 20120228;
+ return ConvertPropVariantToUInt64(prop, size);
+}
+
+void CProxyArc::CalculateSizes(unsigned dirIndex, IInArchive *archive)
+{
+ CProxyDir &dir = Dirs[dirIndex];
+ dir.Size = dir.PackSize = 0;
+ dir.NumSubDirs = dir.SubDirs.Size();
+ dir.NumSubFiles = dir.SubFiles.Size();
+ dir.CrcIsDefined = true;
+ dir.Crc = 0;
+
+ unsigned i;
+
+ for (i = 0; i < dir.SubFiles.Size(); i++)
+ {
+ UInt32 index = (UInt32)dir.SubFiles[i];
+ UInt64 size, packSize;
+ bool sizeDefined = GetSize(archive, index, kpidSize, size);
+ dir.Size += size;
+ GetSize(archive, index, kpidPackSize, packSize);
+ dir.PackSize += packSize;
+ {
+ NCOM::CPropVariant prop;
+ if (archive->GetProperty(index, kpidCRC, &prop) == S_OK)
+ {
+ if (prop.vt == VT_UI4)
+ dir.Crc += prop.ulVal;
+ else if (prop.vt != VT_EMPTY || size != 0 || !sizeDefined)
+ dir.CrcIsDefined = false;
+ }
+ else
+ dir.CrcIsDefined = false;
+ }
+ }
+
+ for (i = 0; i < dir.SubDirs.Size(); i++)
+ {
+ unsigned subDirIndex = dir.SubDirs[i];
+ CalculateSizes(subDirIndex, archive);
+ CProxyDir &f = Dirs[subDirIndex];
+ dir.Size += f.Size;
+ dir.PackSize += f.PackSize;
+ dir.NumSubFiles += f.NumSubFiles;
+ dir.NumSubDirs += f.NumSubDirs;
+ dir.Crc += f.Crc;
+ if (!f.CrcIsDefined)
+ dir.CrcIsDefined = false;
+ }
+}
+
+HRESULT CProxyArc::Load(const CArc &arc, IProgress *progress)
+{
+ // DWORD tickCount = GetTickCount(); for (int ttt = 0; ttt < 1; ttt++) {
+
+ Files.Free();
+ Dirs.Clear();
+
+ Dirs.AddNew();
+ IInArchive *archive = arc.Archive;
+
+ UInt32 numItems;
+ RINOK(archive->GetNumberOfItems(&numItems))
+
+ if (progress)
+ RINOK(progress->SetTotal(numItems))
+
+ Files.Alloc(numItems);
+
+ UString path;
+ UString name;
+ NCOM::CPropVariant prop;
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ if (progress && (i & 0xFFFF) == 0)
+ {
+ const UInt64 currentItemIndex = i;
+ RINOK(progress->SetCompleted(&currentItemIndex))
+ }
+
+ const wchar_t *s = NULL;
+ unsigned len = 0;
+ bool isPtrName = false;
+
+ #if WCHAR_PATH_SEPARATOR != L'/'
+ wchar_t separatorChar = WCHAR_PATH_SEPARATOR;
+ #endif
+
+ #if defined(MY_CPU_LE) && defined(_WIN32)
+ // it works only if (sizeof(wchar_t) == 2)
+ if (arc.GetRawProps)
+ {
+ const void *p;
+ UInt32 size;
+ UInt32 propType;
+ if (arc.GetRawProps->GetRawProp(i, kpidPath, &p, &size, &propType) == S_OK
+ && propType == NPropDataType::kUtf16z
+ && size > 2)
+ {
+ // is (size <= 2), it's empty name, and we call default arc.GetItemPath();
+ len = size / 2 - 1;
+ s = (const wchar_t *)p;
+ isPtrName = true;
+ #if WCHAR_PATH_SEPARATOR != L'/'
+ separatorChar = L'/'; // 0
+ #endif
+ }
+ }
+ if (!s)
+ #endif
+ {
+ prop.Clear();
+ RINOK(arc.Archive->GetProperty(i, kpidPath, &prop))
+ if (prop.vt == VT_BSTR)
+ {
+ s = prop.bstrVal;
+ len = ::SysStringLen(prop.bstrVal);
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ if (len == 0)
+ {
+ RINOK(arc.GetItem_DefaultPath(i, path))
+ len = path.Len();
+ s = path;
+ }
+
+ /*
+ RINOK(arc.GetItemPath(i, path));
+ len = path.Len();
+ s = path;
+ */
+ }
+
+ unsigned curItem = 0;
+
+ /*
+ if (arc.Ask_Deleted)
+ {
+ bool isDeleted = false;
+ RINOK(Archive_IsItem_Deleted(archive, i, isDeleted));
+ if (isDeleted)
+ curItem = AddDirSubItem(curItem, (UInt32)(Int32)-1, false, L"[DELETED]");
+ }
+ */
+
+ unsigned namePos = 0;
+
+ unsigned numLevels = 0;
+
+ for (unsigned j = 0; j < len; j++)
+ {
+ const wchar_t c = s[j];
+ if (c == L'/'
+ #if WCHAR_PATH_SEPARATOR != L'/'
+ || (c == separatorChar)
+ #endif
+ )
+ {
+ const unsigned kLevelLimit = 1 << 10;
+ if (numLevels <= kLevelLimit)
+ {
+ if (numLevels == kLevelLimit)
+ name = "[LONG_PATH]";
+ else
+ name.SetFrom(s + namePos, j - namePos);
+ // 22.00: we can normalize dir here
+ // NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name);
+ curItem = AddDir(curItem, -1, name);
+ }
+ namePos = j + 1;
+ numLevels++;
+ }
+ }
+
+ /*
+ that code must be implemeted to hide alt streams in list.
+ if (arc.Ask_AltStreams)
+ {
+ bool isAltStream;
+ RINOK(Archive_IsItem_AltStream(archive, i, isAltStream));
+ if (isAltStream)
+ {
+
+ }
+ }
+ */
+
+ bool isDir;
+ RINOK(Archive_IsItem_Dir(archive, i, isDir))
+
+ CProxyFile &f = Files[i];
+
+ f.NameLen = len - namePos;
+ s += namePos;
+
+ if (isPtrName)
+ f.Name = s;
+ else
+ {
+ f.Name = AllocStringAndCopy(s, f.NameLen);
+ f.NeedDeleteName = true;
+ }
+
+ if (isDir)
+ {
+ name = s;
+ // 22.00: we can normalize dir here
+ // NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(name);
+ AddDir(curItem, (int)i, name);
+ }
+ else
+ Dirs[curItem].SubFiles.Add(i);
+ }
+
+ CalculateSizes(0, archive);
+
+ // } char s[128]; sprintf(s, "Load archive: %7d ms", GetTickCount() - tickCount); OutputDebugStringA(s);
+
+ return S_OK;
+}
+
+
+
+// ---------- for Tree-mode archive ----------
+
+void CProxyArc2::GetDirPathParts(unsigned dirIndex, UStringVector &pathParts, bool &isAltStreamDir) const
+{
+ pathParts.Clear();
+
+ isAltStreamDir = false;
+
+ if (dirIndex == k_Proxy2_RootDirIndex)
+ return;
+ if (dirIndex == k_Proxy2_AltRootDirIndex)
+ {
+ isAltStreamDir = true;
+ return;
+ }
+
+ while (dirIndex >= k_Proxy2_NumRootDirs)
+ {
+ const CProxyDir2 &dir = Dirs[dirIndex];
+ const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex];
+ if (pathParts.IsEmpty() && (int)dirIndex == file.AltDirIndex)
+ isAltStreamDir = true;
+ pathParts.Insert(0, file.Name);
+ const int par = file.Parent;
+ if (par == -1)
+ break;
+ dirIndex = (unsigned)Files[(unsigned)par].DirIndex;
+ // if ((int)dirIndex == -1) break;
+ }
+}
+
+bool CProxyArc2::IsAltDir(unsigned dirIndex) const
+{
+ if (dirIndex == k_Proxy2_RootDirIndex)
+ return false;
+ if (dirIndex == k_Proxy2_AltRootDirIndex)
+ return true;
+ const CProxyDir2 &dir = Dirs[dirIndex];
+ const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex];
+ return ((int)dirIndex == file.AltDirIndex);
+}
+
+UString CProxyArc2::GetDirPath_as_Prefix(unsigned dirIndex, bool &isAltStreamDir) const
+{
+ isAltStreamDir = false;
+ const CProxyDir2 &dir = Dirs[dirIndex];
+ if (dirIndex == k_Proxy2_AltRootDirIndex)
+ isAltStreamDir = true;
+ else if (dirIndex >= k_Proxy2_NumRootDirs)
+ {
+ const CProxyFile2 &file = Files[(unsigned)dir.ArcIndex];
+ isAltStreamDir = ((int)dirIndex == file.AltDirIndex);
+ }
+ return dir.PathPrefix;
+}
+
+void CProxyArc2::AddRealIndices_of_ArcItem(unsigned arcIndex, bool includeAltStreams, CUIntVector &realIndices) const
+{
+ realIndices.Add(arcIndex);
+ const CProxyFile2 &file = Files[arcIndex];
+ if (file.DirIndex != -1)
+ AddRealIndices_of_Dir((unsigned)file.DirIndex, includeAltStreams, realIndices);
+ if (includeAltStreams && file.AltDirIndex != -1)
+ AddRealIndices_of_Dir((unsigned)file.AltDirIndex, includeAltStreams, realIndices);
+}
+
+void CProxyArc2::AddRealIndices_of_Dir(unsigned dirIndex, bool includeAltStreams, CUIntVector &realIndices) const
+{
+ const CRecordVector<unsigned> &subFiles = Dirs[dirIndex].Items;
+ FOR_VECTOR (i, subFiles)
+ {
+ AddRealIndices_of_ArcItem(subFiles[i], includeAltStreams, realIndices);
+ }
+}
+
+unsigned CProxyArc2::GetRealIndex(unsigned dirIndex, unsigned index) const
+{
+ return Dirs[dirIndex].Items[index];
+}
+
+void CProxyArc2::GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, bool includeAltStreams, CUIntVector &realIndices) const
+{
+ const CProxyDir2 &dir = Dirs[dirIndex];
+ realIndices.Clear();
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ AddRealIndices_of_ArcItem(dir.Items[indices[i]], includeAltStreams, realIndices);
+ }
+ HeapSort(&realIndices.Front(), realIndices.Size());
+}
+
+void CProxyArc2::CalculateSizes(unsigned dirIndex, IInArchive *archive)
+{
+ CProxyDir2 &dir = Dirs[dirIndex];
+ dir.Size = dir.PackSize = 0;
+ dir.NumSubDirs = 0; // dir.SubDirs.Size();
+ dir.NumSubFiles = 0; // dir.Files.Size();
+ dir.CrcIsDefined = true;
+ dir.Crc = 0;
+
+ FOR_VECTOR (i, dir.Items)
+ {
+ UInt32 index = dir.Items[i];
+ UInt64 size, packSize;
+ bool sizeDefined = GetSize(archive, index, kpidSize, size);
+ dir.Size += size;
+ GetSize(archive, index, kpidPackSize, packSize);
+ dir.PackSize += packSize;
+ {
+ NCOM::CPropVariant prop;
+ if (archive->GetProperty(index, kpidCRC, &prop) == S_OK)
+ {
+ if (prop.vt == VT_UI4)
+ dir.Crc += prop.ulVal;
+ else if (prop.vt != VT_EMPTY || size != 0 || !sizeDefined)
+ dir.CrcIsDefined = false;
+ }
+ else
+ dir.CrcIsDefined = false;
+ }
+
+ const CProxyFile2 &subFile = Files[index];
+ if (subFile.DirIndex == -1)
+ {
+ dir.NumSubFiles++;
+ }
+ else
+ {
+ // 22.00: we normalize name
+ UString s = subFile.Name;
+ NArchive::NItemName::NormalizeSlashes_in_FileName_for_OsPath(s);
+ dir.NumSubDirs++;
+ CProxyDir2 &f = Dirs[subFile.DirIndex];
+ f.PathPrefix = dir.PathPrefix + s + WCHAR_PATH_SEPARATOR;
+ CalculateSizes((unsigned)subFile.DirIndex, archive);
+ dir.Size += f.Size;
+ dir.PackSize += f.PackSize;
+ dir.NumSubFiles += f.NumSubFiles;
+ dir.NumSubDirs += f.NumSubDirs;
+ dir.Crc += f.Crc;
+ if (!f.CrcIsDefined)
+ dir.CrcIsDefined = false;
+ }
+
+ if (subFile.AltDirIndex == -1)
+ {
+ // dir.NumSubFiles++;
+ }
+ else
+ {
+ // dir.NumSubDirs++;
+ CProxyDir2 &f = Dirs[subFile.AltDirIndex];
+ f.PathPrefix = dir.PathPrefix + subFile.Name + L':';
+ CalculateSizes((unsigned)subFile.AltDirIndex, archive);
+ }
+ }
+}
+
+
+bool CProxyArc2::IsThere_SubDir(unsigned dirIndex, const UString &name) const
+{
+ const CRecordVector<unsigned> &subFiles = Dirs[dirIndex].Items;
+ FOR_VECTOR (i, subFiles)
+ {
+ const CProxyFile2 &file = Files[subFiles[i]];
+ if (file.IsDir())
+ if (CompareFileNames(name, file.Name) == 0)
+ return true;
+ }
+ return false;
+}
+
+HRESULT CProxyArc2::Load(const CArc &arc, IProgress *progress)
+{
+ if (!arc.GetRawProps)
+ return E_FAIL;
+
+ // DWORD tickCount = GetTickCount(); for (int ttt = 0; ttt < 1; ttt++) {
+
+ Dirs.Clear();
+ Files.Free();
+
+ IInArchive *archive = arc.Archive;
+
+ UInt32 numItems;
+ RINOK(archive->GetNumberOfItems(&numItems))
+ if (progress)
+ RINOK(progress->SetTotal(numItems))
+ UString fileName;
+
+
+ {
+ // Dirs[0] - root dir
+ /* CProxyDir2 &dir = */ Dirs.AddNew();
+ }
+
+ {
+ // Dirs[1] - for alt streams of root dir
+ CProxyDir2 &dir = Dirs.AddNew();
+ dir.PathPrefix = ':';
+ }
+
+ Files.Alloc(numItems);
+
+ UString tempUString;
+ AString tempAString;
+
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ if (progress && (i & 0xFFFFF) == 0)
+ {
+ UInt64 currentItemIndex = i;
+ RINOK(progress->SetCompleted(&currentItemIndex))
+ }
+
+ CProxyFile2 &file = Files[i];
+
+ const void *p;
+ UInt32 size;
+ UInt32 propType;
+ RINOK(arc.GetRawProps->GetRawProp(i, kpidName, &p, &size, &propType))
+
+ #ifdef MY_CPU_LE
+ if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE)
+ {
+ file.Name = (const wchar_t *)p;
+ file.NameLen = 0;
+ if (size >= sizeof(wchar_t))
+ file.NameLen = size / sizeof(wchar_t) - 1;
+ }
+ else
+ #endif
+ if (p && propType == NPropDataType::kUtf8z)
+ {
+ tempAString = (const char *)p;
+ ConvertUTF8ToUnicode(tempAString, tempUString);
+ file.NameLen = tempUString.Len();
+ file.Name = AllocStringAndCopy(tempUString);
+ file.NeedDeleteName = true;
+ }
+ else
+ {
+ NCOM::CPropVariant prop;
+ RINOK(arc.Archive->GetProperty(i, kpidName, &prop))
+ const wchar_t *s;
+ if (prop.vt == VT_BSTR)
+ s = prop.bstrVal;
+ else if (prop.vt == VT_EMPTY)
+ s = L"[Content]";
+ else
+ return E_FAIL;
+ file.NameLen = MyStringLen(s);
+ file.Name = AllocStringAndCopy(s, file.NameLen);
+ file.NeedDeleteName = true;
+ }
+
+ UInt32 parent = (UInt32)(Int32)-1;
+ UInt32 parentType = 0;
+ RINOK(arc.GetRawProps->GetParent(i, &parent, &parentType))
+ file.Parent = (Int32)parent;
+
+ if (arc.Ask_Deleted)
+ {
+ bool isDeleted = false;
+ RINOK(Archive_IsItem_Deleted(archive, i, isDeleted))
+ if (isDeleted)
+ {
+ // continue;
+ // curItem = AddDirSubItem(curItem, (UInt32)(Int32)-1, false, L"[DELETED]");
+ }
+ }
+
+ bool isDir;
+ RINOK(Archive_IsItem_Dir(archive, i, isDir))
+
+ if (isDir)
+ {
+ file.DirIndex = (int)Dirs.Size();
+ CProxyDir2 &dir = Dirs.AddNew();
+ dir.ArcIndex = (int)i;
+ }
+ if (arc.Ask_AltStream)
+ RINOK(Archive_IsItem_AltStream(archive, i, file.IsAltStream))
+ }
+
+ for (i = 0; i < numItems; i++)
+ {
+ CProxyFile2 &file = Files[i];
+ int dirIndex;
+
+ if (file.IsAltStream)
+ {
+ if (file.Parent == -1)
+ dirIndex = k_Proxy2_AltRootDirIndex;
+ else
+ {
+ int &folderIndex2 = Files[(unsigned)file.Parent].AltDirIndex;
+ if (folderIndex2 == -1)
+ {
+ folderIndex2 = (int)Dirs.Size();
+ CProxyDir2 &dir = Dirs.AddNew();
+ dir.ArcIndex = file.Parent;
+ }
+ dirIndex = folderIndex2;
+ }
+ }
+ else
+ {
+ if (file.Parent == -1)
+ dirIndex = k_Proxy2_RootDirIndex;
+ else
+ {
+ dirIndex = Files[(unsigned)file.Parent].DirIndex;
+ if (dirIndex == -1)
+ return E_FAIL;
+ }
+ }
+
+ Dirs[dirIndex].Items.Add(i);
+ }
+
+ for (i = 0; i < k_Proxy2_NumRootDirs; i++)
+ CalculateSizes(i, archive);
+
+ // } char s[128]; sprintf(s, "Load archive: %7d ms", GetTickCount() - tickCount); OutputDebugStringA(s);
+
+ return S_OK;
+}
+
+int CProxyArc2::FindItem(unsigned dirIndex, const wchar_t *name, bool foldersOnly) const
+{
+ const CProxyDir2 &dir = Dirs[dirIndex];
+ FOR_VECTOR (i, dir.Items)
+ {
+ const CProxyFile2 &file = Files[dir.Items[i]];
+ if (foldersOnly && file.DirIndex == -1)
+ continue;
+ if (CompareFileNames(file.Name, name) == 0)
+ return (int)i;
+ }
+ return -1;
+}
diff --git a/CPP/7zip/UI/Agent/AgentProxy.h b/CPP/7zip/UI/Agent/AgentProxy.h
new file mode 100644
index 0000000..c24dd91
--- /dev/null
+++ b/CPP/7zip/UI/Agent/AgentProxy.h
@@ -0,0 +1,162 @@
+// AgentProxy.h
+
+#ifndef ZIP7_INC_AGENT_PROXY_H
+#define ZIP7_INC_AGENT_PROXY_H
+
+#include "../Common/OpenArchive.h"
+
+struct CProxyFile
+{
+ const wchar_t *Name;
+ unsigned NameLen;
+ bool NeedDeleteName;
+
+ CProxyFile(): Name(NULL), NameLen(0), NeedDeleteName(false) {}
+ ~CProxyFile() { if (NeedDeleteName) delete [](wchar_t *)(void *)Name; } // delete [](wchar_t *)Name;
+};
+
+const unsigned k_Proxy_RootDirIndex = 0;
+
+struct CProxyDir
+{
+ const wchar_t *Name;
+ unsigned NameLen;
+
+ int ArcIndex; // index in proxy->Files[] ; -1 if there is no item for that folder
+ int ParentDir; // index in proxy->Dirs[] ; -1 for root folder; ;
+ CRecordVector<unsigned> SubDirs;
+ CRecordVector<unsigned> SubFiles;
+
+ UInt64 Size;
+ UInt64 PackSize;
+ UInt32 Crc;
+ UInt32 NumSubDirs;
+ UInt32 NumSubFiles;
+ bool CrcIsDefined;
+
+ CProxyDir(): Name(NULL), NameLen(0), ParentDir(-1) {}
+ ~CProxyDir() { delete [](wchar_t *)(void *)Name; }
+
+ void Clear();
+ bool IsLeaf() const { return ArcIndex != -1; }
+};
+
+class CProxyArc
+{
+ int FindSubDir(unsigned dirIndex, const wchar_t *name, unsigned &insertPos) const;
+
+ void CalculateSizes(unsigned dirIndex, IInArchive *archive);
+ unsigned AddDir(unsigned dirIndex, int arcIndex, const UString &name);
+public:
+ CObjectVector<CProxyDir> Dirs; // Dirs[0] - root
+ CObjArray<CProxyFile> Files; // all items from archive in same order
+
+ // returns index in Dirs[], or -1,
+ int FindSubDir(unsigned dirIndex, const wchar_t *name) const;
+
+ void GetDirPathParts(unsigned dirIndex, UStringVector &pathParts) const;
+ // returns full path of Dirs[dirIndex], including back slash
+ UString GetDirPath_as_Prefix(unsigned dirIndex) const;
+
+ // AddRealIndices DOES ADD also item represented by dirIndex (if it's Leaf)
+ void AddRealIndices(unsigned dirIndex, CUIntVector &realIndices) const;
+ int GetRealIndex(unsigned dirIndex, unsigned index) const;
+ void GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, CUIntVector &realIndices) const;
+
+ HRESULT Load(const CArc &arc, IProgress *progress);
+};
+
+
+// ---------- for Tree-mode archive ----------
+
+struct CProxyFile2
+{
+ int DirIndex; // >= 0 for dir. (index in ProxyArchive2->Dirs)
+ int AltDirIndex; // >= 0 if there are alt streams. (index in ProxyArchive2->Dirs)
+ int Parent; // >= 0 if there is parent. (index in archive and in ProxyArchive2->Files)
+ const wchar_t *Name;
+ unsigned NameLen;
+ bool NeedDeleteName;
+ bool Ignore;
+ bool IsAltStream;
+
+ int GetDirIndex(bool forAltStreams) const { return forAltStreams ? AltDirIndex : DirIndex; }
+
+ bool IsDir() const { return DirIndex != -1; }
+ CProxyFile2():
+ DirIndex(-1), AltDirIndex(-1), Parent(-1),
+ Name(NULL), NameLen(0),
+ NeedDeleteName(false),
+ Ignore(false),
+ IsAltStream(false)
+ {}
+ ~CProxyFile2()
+ {
+ if (NeedDeleteName)
+ delete [](wchar_t *)(void *)Name;
+ }
+};
+
+struct CProxyDir2
+{
+ int ArcIndex; // = -1 for root folders, index in proxy->Files[]
+ CRecordVector<unsigned> Items;
+ UString PathPrefix;
+ UInt64 Size;
+ UInt64 PackSize;
+ bool CrcIsDefined;
+ UInt32 Crc;
+ UInt32 NumSubDirs;
+ UInt32 NumSubFiles;
+
+ CProxyDir2(): ArcIndex(-1) {}
+ void AddFileSubItem(UInt32 index, const UString &name);
+ void Clear();
+};
+
+const unsigned k_Proxy2_RootDirIndex = k_Proxy_RootDirIndex;
+const unsigned k_Proxy2_AltRootDirIndex = 1;
+const unsigned k_Proxy2_NumRootDirs = 2;
+
+class CProxyArc2
+{
+ void CalculateSizes(unsigned dirIndex, IInArchive *archive);
+ // AddRealIndices_of_Dir DOES NOT ADD item itself represented by dirIndex
+ void AddRealIndices_of_Dir(unsigned dirIndex, bool includeAltStreams, CUIntVector &realIndices) const;
+public:
+ CObjectVector<CProxyDir2> Dirs; // Dirs[0] - root folder
+ // Dirs[1] - for alt streams of root dir
+ CObjArray<CProxyFile2> Files; // all items from archive in same order
+
+ bool IsThere_SubDir(unsigned dirIndex, const UString &name) const;
+
+ void GetDirPathParts(unsigned dirIndex, UStringVector &pathParts, bool &isAltStreamDir) const;
+ UString GetDirPath_as_Prefix(unsigned dirIndex, bool &isAltStreamDir) const;
+ bool IsAltDir(unsigned dirIndex) const;
+
+ // AddRealIndices_of_ArcItem DOES ADD item and subItems
+ void AddRealIndices_of_ArcItem(unsigned arcIndex, bool includeAltStreams, CUIntVector &realIndices) const;
+ unsigned GetRealIndex(unsigned dirIndex, unsigned index) const;
+ void GetRealIndices(unsigned dirIndex, const UInt32 *indices, UInt32 numItems, bool includeAltStreams, CUIntVector &realIndices) const;
+
+ HRESULT Load(const CArc &arc, IProgress *progress);
+
+ int GetParentDirOfFile(UInt32 arcIndex) const
+ {
+ const CProxyFile2 &file = Files[arcIndex];
+
+ if (file.Parent == -1)
+ return file.IsAltStream ?
+ k_Proxy2_AltRootDirIndex :
+ k_Proxy2_RootDirIndex;
+
+ const CProxyFile2 &parentFile = Files[file.Parent];
+ return file.IsAltStream ?
+ parentFile.AltDirIndex :
+ parentFile.DirIndex;
+ }
+
+ int FindItem(unsigned dirIndex, const wchar_t *name, bool foldersOnly) const;
+};
+
+#endif
diff --git a/CPP/7zip/UI/Agent/ArchiveFolder.cpp b/CPP/7zip/UI/Agent/ArchiveFolder.cpp
new file mode 100644
index 0000000..89b20dc
--- /dev/null
+++ b/CPP/7zip/UI/Agent/ArchiveFolder.cpp
@@ -0,0 +1,51 @@
+// Agent/ArchiveFolder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/ComTry.h"
+
+#include "../Common/ArchiveExtractCallback.h"
+
+#include "Agent.h"
+
+/*
+Z7_COM7F_IMF(CAgentFolder::SetReplaceAltStreamCharsMode(Int32 replaceAltStreamCharsMode))
+{
+ _replaceAltStreamCharsMode = replaceAltStreamCharsMode;
+ return S_OK;
+}
+*/
+
+Z7_COM7F_IMF(CAgentFolder::SetZoneIdMode(NExtract::NZoneIdMode::EEnum zoneMode))
+{
+ _zoneMode = zoneMode;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CAgentFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems,
+ Int32 includeAltStreams, Int32 replaceAltStreamCharsMode,
+ const wchar_t *path, IFolderOperationsExtractCallback *callback))
+{
+ if (moveMode)
+ return E_NOTIMPL;
+ COM_TRY_BEGIN
+ CMyComPtr<IFolderArchiveExtractCallback> extractCallback2;
+ {
+ CMyComPtr<IFolderOperationsExtractCallback> callbackWrap = callback;
+ RINOK(callbackWrap.QueryInterface(IID_IFolderArchiveExtractCallback, &extractCallback2))
+ }
+ NExtract::NPathMode::EEnum pathMode;
+ if (!_flatMode)
+ pathMode = NExtract::NPathMode::kCurPaths;
+ else
+ pathMode = (_proxy2 && _loadAltStreams) ?
+ NExtract::NPathMode::kNoPathsAlt :
+ NExtract::NPathMode::kNoPaths;
+
+ return Extract(indices, numItems,
+ includeAltStreams, replaceAltStreamCharsMode,
+ pathMode, NExtract::NOverwriteMode::kAsk,
+ path, BoolToInt(false), extractCallback2);
+ COM_TRY_END
+}
diff --git a/CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp b/CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp
new file mode 100644
index 0000000..3fa027d
--- /dev/null
+++ b/CPP/7zip/UI/Agent/ArchiveFolderOpen.cpp
@@ -0,0 +1,231 @@
+// Agent/ArchiveFolderOpen.cpp
+
+#include "StdAfx.h"
+
+// #ifdef NEW_FOLDER_INTERFACE
+
+#include "../../../Common/StringToInt.h"
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/ResourceString.h"
+
+#include "Agent.h"
+
+extern HINSTANCE g_hInstance;
+static const UINT kIconTypesResId = 100;
+
+void CCodecIcons::LoadIcons(HMODULE m)
+{
+ IconPairs.Clear();
+ UString iconTypes;
+ NWindows::MyLoadString(m, kIconTypesResId, iconTypes);
+ UStringVector pairs;
+ SplitString(iconTypes, pairs);
+ FOR_VECTOR (i, pairs)
+ {
+ const UString &s = pairs[i];
+ int pos = s.Find(L':');
+ CIconPair iconPair;
+ iconPair.IconIndex = -1;
+ if (pos < 0)
+ pos = (int)s.Len();
+ else
+ {
+ const UString num = s.Ptr((unsigned)pos + 1);
+ if (!num.IsEmpty())
+ {
+ const wchar_t *end;
+ iconPair.IconIndex = (int)ConvertStringToUInt32(num, &end);
+ if (*end != 0)
+ continue;
+ }
+ }
+ iconPair.Ext = s.Left((unsigned)pos);
+ IconPairs.Add(iconPair);
+ }
+}
+
+bool CCodecIcons::FindIconIndex(const UString &ext, int &iconIndex) const
+{
+ iconIndex = -1;
+ FOR_VECTOR (i, IconPairs)
+ {
+ const CIconPair &pair = IconPairs[i];
+ if (ext.IsEqualTo_NoCase(pair.Ext))
+ {
+ iconIndex = pair.IconIndex;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void CArchiveFolderManager::LoadFormats()
+{
+ if (WasLoaded)
+ return;
+
+ LoadGlobalCodecs();
+
+ #ifdef Z7_EXTERNAL_CODECS
+ CodecIconsVector.Clear();
+ FOR_VECTOR (i, g_CodecsObj->Libs)
+ {
+ CCodecIcons &ci = CodecIconsVector.AddNew();
+ ci.LoadIcons(g_CodecsObj->Libs[i].Lib.Get_HMODULE());
+ }
+ #endif
+ InternalIcons.LoadIcons(g_hInstance);
+ WasLoaded = true;
+}
+
+/*
+int CArchiveFolderManager::FindFormat(const UString &type)
+{
+ FOR_VECTOR (i, g_CodecsObj->Formats)
+ if (type.IsEqualTo_NoCase(g_CodecsObj->Formats[i].Name))
+ return (int)i;
+ return -1;
+}
+*/
+
+Z7_COM7F_IMF(CArchiveFolderManager::OpenFolderFile(IInStream *inStream,
+ const wchar_t *filePath, const wchar_t *arcFormat,
+ IFolderFolder **resultFolder, IProgress *progress))
+{
+ CMyComPtr<IArchiveOpenCallback> openArchiveCallback;
+ if (progress)
+ {
+ CMyComPtr<IProgress> progressWrapper = progress;
+ progressWrapper.QueryInterface(IID_IArchiveOpenCallback, &openArchiveCallback);
+ }
+ CAgent *agent = new CAgent();
+ CMyComPtr<IInFolderArchive> archive = agent;
+
+ const HRESULT res = archive->Open(inStream, filePath, arcFormat, NULL, openArchiveCallback);
+
+ if (res != S_OK)
+ {
+ if (res != S_FALSE)
+ return res;
+ /* 20.01: we create folder even for Non-Open cases, if there is NonOpen_ErrorInfo information.
+ So we can get error information from that IFolderFolder later. */
+ if (!agent->_archiveLink.NonOpen_ErrorInfo.IsThereErrorOrWarning())
+ return res;
+ }
+
+ RINOK(archive->BindToRootFolder(resultFolder))
+ return res;
+}
+
+/*
+HRESULT CAgent::FolderReOpen(
+ IArchiveOpenCallback *openArchiveCallback)
+{
+ return ReOpenArchive(_archive, _archiveFilePath);
+}
+*/
+
+
+/*
+Z7_COM7F_IMF(CArchiveFolderManager::GetExtensions(const wchar_t *type, BSTR *extensions))
+{
+ *extensions = 0;
+ int formatIndex = FindFormat(type);
+ if (formatIndex < 0)
+ return E_INVALIDARG;
+ // Exts[0].Ext;
+ return StringToBstr(g_CodecsObj.Formats[formatIndex].GetAllExtensions(), extensions);
+}
+*/
+
+static void AddIconExt(const CCodecIcons &lib, UString &dest)
+{
+ FOR_VECTOR (i, lib.IconPairs)
+ {
+ dest.Add_Space_if_NotEmpty();
+ dest += lib.IconPairs[i].Ext;
+ }
+}
+
+
+Z7_COM7F_IMF(CArchiveFolderManager::GetExtensions(BSTR *extensions))
+{
+ *extensions = NULL;
+ LoadFormats();
+ UString res;
+
+ #ifdef Z7_EXTERNAL_CODECS
+ /*
+ FOR_VECTOR (i, g_CodecsObj->Libs)
+ AddIconExt(g_CodecsObj->Libs[i].CodecIcons, res);
+ */
+ FOR_VECTOR (i, CodecIconsVector)
+ AddIconExt(CodecIconsVector[i], res);
+ #endif
+
+ AddIconExt(
+ // g_CodecsObj->
+ InternalIcons, res);
+
+ return StringToBstr(res, extensions);
+}
+
+
+Z7_COM7F_IMF(CArchiveFolderManager::GetIconPath(const wchar_t *ext, BSTR *iconPath, Int32 *iconIndex))
+{
+ *iconPath = NULL;
+ *iconIndex = 0;
+ LoadFormats();
+
+ #ifdef Z7_EXTERNAL_CODECS
+ // FOR_VECTOR (i, g_CodecsObj->Libs)
+ FOR_VECTOR (i, CodecIconsVector)
+ {
+ int ii;
+ if (CodecIconsVector[i].FindIconIndex(ext, ii))
+ {
+ const CCodecLib &lib = g_CodecsObj->Libs[i];
+ *iconIndex = ii;
+ return StringToBstr(fs2us(lib.Path), iconPath);
+ }
+ }
+ #endif
+
+ int ii;
+ if (InternalIcons.FindIconIndex(ext, ii))
+ {
+ FString path;
+ if (NWindows::NDLL::MyGetModuleFileName(path))
+ {
+ *iconIndex = ii;
+ return StringToBstr(fs2us(path), iconPath);
+ }
+ }
+ return S_OK;
+}
+
+/*
+Z7_COM7F_IMF(CArchiveFolderManager::GetTypes(BSTR *types))
+{
+ LoadFormats();
+ UString typesStrings;
+ FOR_VECTOR(i, g_CodecsObj.Formats)
+ {
+ const CArcInfoEx &ai = g_CodecsObj.Formats[i];
+ if (ai.AssociateExts.Size() == 0)
+ continue;
+ if (i != 0)
+ typesStrings.Add_Space();
+ typesStrings += ai.Name;
+ }
+ return StringToBstr(typesStrings, types);
+}
+Z7_COM7F_IMF(CArchiveFolderManager::CreateFolderFile(const wchar_t * type,
+ const wchar_t * filePath, IProgress progress))
+{
+ return E_NOTIMPL;
+}
+*/
+
+// #endif
diff --git a/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp
new file mode 100644
index 0000000..0189224
--- /dev/null
+++ b/CPP/7zip/UI/Agent/ArchiveFolderOut.cpp
@@ -0,0 +1,386 @@
+// ArchiveFolderOut.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/ComTry.h"
+
+#include "../../../Windows/FileDir.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Common/LimitedStreams.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../Common/WorkDir.h"
+
+#include "Agent.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+void CAgentFolder::GetPathParts(UStringVector &pathParts, bool &isAltStreamFolder)
+{
+ if (_proxy2)
+ _proxy2->GetDirPathParts(_proxyDirIndex, pathParts, isAltStreamFolder);
+ else
+ _proxy->GetDirPathParts(_proxyDirIndex, pathParts);
+}
+
+static bool Delete_EmptyFolder_And_EmptySubFolders(const FString &path)
+{
+ {
+ const FString pathPrefix = path + FCHAR_PATH_SEPARATOR;
+ CObjectVector<FString> names;
+ {
+ NFind::CDirEntry fileInfo;
+ NFind::CEnumerator enumerator;
+ enumerator.SetDirPrefix(pathPrefix);
+ for (;;)
+ {
+ bool found;
+ if (!enumerator.Next(fileInfo, found))
+ return false;
+ if (!found)
+ break;
+ if (fileInfo.IsDir())
+ names.Add(fileInfo.Name);
+ }
+ }
+ bool res = true;
+ FOR_VECTOR (i, names)
+ {
+ if (!Delete_EmptyFolder_And_EmptySubFolders(pathPrefix + names[i]))
+ res = false;
+ }
+ if (!res)
+ return false;
+ }
+ // we clear read-only attrib to remove read-only dir
+ if (!SetFileAttrib(path, 0))
+ return false;
+ return RemoveDir(path);
+}
+
+HRESULT CAgentFolder::CommonUpdateOperation(
+ AGENT_OP operation,
+ bool moveMode,
+ const wchar_t *newItemName,
+ const NUpdateArchive::CActionSet *actionSet,
+ const UInt32 *indices, UInt32 numItems,
+ IProgress *progress)
+{
+ if (moveMode && _agentSpec->_isHashHandler)
+ return E_NOTIMPL;
+
+ if (!_agentSpec->CanUpdate())
+ return E_NOTIMPL;
+
+ CMyComPtr<IFolderArchiveUpdateCallback> updateCallback100;
+ if (progress)
+ progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&updateCallback100);
+
+ try
+ {
+
+ RINOK(_agentSpec->SetFolder(this))
+
+ // ---------- Save FolderItem ----------
+
+ UStringVector pathParts;
+ bool isAltStreamFolder = false;
+ GetPathParts(pathParts, isAltStreamFolder);
+
+ FStringVector requestedPaths;
+ FStringVector processedPaths;
+
+ CWorkDirTempFile tempFile;
+ RINOK(tempFile.CreateTempFile(us2fs(_agentSpec->_archiveFilePath)))
+ {
+ CMyComPtr<IOutStream> tailStream;
+ const CArc &arc = *_agentSpec->_archiveLink.GetArc();
+
+ if (arc.ArcStreamOffset == 0)
+ tailStream = tempFile.OutStream;
+ else
+ {
+ if (arc.Offset < 0)
+ return E_NOTIMPL;
+ RINOK(arc.InStream->Seek(0, STREAM_SEEK_SET, NULL))
+ RINOK(NCompress::CopyStream_ExactSize(arc.InStream, tempFile.OutStream, arc.ArcStreamOffset, NULL))
+ CTailOutStream *tailStreamSpec = new CTailOutStream;
+ tailStream = tailStreamSpec;
+ tailStreamSpec->Stream = tempFile.OutStream;
+ tailStreamSpec->Offset = arc.ArcStreamOffset;
+ tailStreamSpec->Init();
+ }
+
+ HRESULT result;
+
+ switch ((int)operation)
+ {
+ case AGENT_OP_Delete:
+ result = _agentSpec->DeleteItems(tailStream, indices, numItems, updateCallback100);
+ break;
+ case AGENT_OP_CreateFolder:
+ result = _agentSpec->CreateFolder(tailStream, newItemName, updateCallback100);
+ break;
+ case AGENT_OP_Rename:
+ result = _agentSpec->RenameItem(tailStream, indices, numItems, newItemName, updateCallback100);
+ break;
+ case AGENT_OP_Comment:
+ result = _agentSpec->CommentItem(tailStream, indices, numItems, newItemName, updateCallback100);
+ break;
+ case AGENT_OP_CopyFromFile:
+ result = _agentSpec->UpdateOneFile(tailStream, indices, numItems, newItemName, updateCallback100);
+ break;
+ case AGENT_OP_Uni:
+ {
+ Byte actionSetByte[NUpdateArchive::NPairState::kNumValues];
+ for (unsigned i = 0; i < NUpdateArchive::NPairState::kNumValues; i++)
+ actionSetByte[i] = (Byte)actionSet->StateActions[i];
+ result = _agentSpec->DoOperation2(
+ moveMode ? &requestedPaths : NULL,
+ moveMode ? &processedPaths : NULL,
+ tailStream, actionSetByte, NULL, updateCallback100);
+ break;
+ }
+ default:
+ return E_FAIL;
+ }
+
+ RINOK(result)
+ }
+
+ _agentSpec->KeepModeForNextOpen();
+ _agent->Close();
+
+ // before 9.26: if there was error for MoveToOriginal archive was closed.
+ // now: we reopen archive after close
+
+ // m_FolderItem = NULL;
+
+ const HRESULT res = tempFile.MoveToOriginal(true);
+
+ // RINOK(res);
+ if (res == S_OK)
+ {
+ if (moveMode)
+ {
+ unsigned i;
+ for (i = 0; i < processedPaths.Size(); i++)
+ {
+ DeleteFileAlways(processedPaths[i]);
+ }
+ for (i = 0; i < requestedPaths.Size(); i++)
+ {
+ const FString &fs = requestedPaths[i];
+ if (NFind::DoesDirExist(fs))
+ Delete_EmptyFolder_And_EmptySubFolders(fs);
+ }
+ }
+ }
+
+ {
+ CMyComPtr<IArchiveOpenCallback> openCallback;
+ if (updateCallback100)
+ updateCallback100->QueryInterface(IID_IArchiveOpenCallback, (void **)&openCallback);
+ RINOK(_agent->ReOpen(openCallback))
+ }
+
+ // CAgent::ReOpen() deletes _proxy and _proxy2
+ _items.Clear();
+ _proxy = NULL;
+ _proxy2 = NULL;
+ _proxyDirIndex = k_Proxy_RootDirIndex;
+ _isAltStreamFolder = false;
+
+
+ // ---------- Restore FolderItem ----------
+
+ CMyComPtr<IFolderFolder> archiveFolder;
+ RINOK(_agent->BindToRootFolder(&archiveFolder))
+
+ // CAgent::BindToRootFolder() changes _proxy and _proxy2
+ _proxy = _agentSpec->_proxy;
+ _proxy2 = _agentSpec->_proxy2;
+
+ if (_proxy)
+ {
+ FOR_VECTOR (i, pathParts)
+ {
+ const int next = _proxy->FindSubDir(_proxyDirIndex, pathParts[i]);
+ if (next == -1)
+ break;
+ _proxyDirIndex = (unsigned)next;
+ }
+ }
+
+ if (_proxy2)
+ {
+ if (pathParts.IsEmpty() && isAltStreamFolder)
+ {
+ _proxyDirIndex = k_Proxy2_AltRootDirIndex;
+ }
+ else FOR_VECTOR (i, pathParts)
+ {
+ const bool dirOnly = (i + 1 < pathParts.Size() || !isAltStreamFolder);
+ const int index = _proxy2->FindItem(_proxyDirIndex, pathParts[i], dirOnly);
+ if (index == -1)
+ break;
+
+ const CProxyFile2 &file = _proxy2->Files[_proxy2->Dirs[_proxyDirIndex].Items[index]];
+
+ if (dirOnly)
+ _proxyDirIndex = (unsigned)file.DirIndex;
+ else
+ {
+ if (file.AltDirIndex != -1)
+ _proxyDirIndex = (unsigned)file.AltDirIndex;
+ break;
+ }
+ }
+ }
+
+ /*
+ if (pathParts.IsEmpty() && isAltStreamFolder)
+ {
+ CMyComPtr<IFolderAltStreams> folderAltStreams;
+ archiveFolder.QueryInterface(IID_IFolderAltStreams, &folderAltStreams);
+ if (folderAltStreams)
+ {
+ CMyComPtr<IFolderFolder> newFolder;
+ folderAltStreams->BindToAltStreams((UInt32)(Int32)-1, &newFolder);
+ if (newFolder)
+ archiveFolder = newFolder;
+ }
+ }
+
+ FOR_VECTOR (i, pathParts)
+ {
+ CMyComPtr<IFolderFolder> newFolder;
+
+ if (isAltStreamFolder && i == pathParts.Size() - 1)
+ {
+ CMyComPtr<IFolderAltStreams> folderAltStreams;
+ archiveFolder.QueryInterface(IID_IFolderAltStreams, &folderAltStreams);
+ if (folderAltStreams)
+ folderAltStreams->BindToAltStreams(pathParts[i], &newFolder);
+ }
+ else
+ archiveFolder->BindToFolder(pathParts[i], &newFolder);
+
+ if (!newFolder)
+ break;
+ archiveFolder = newFolder;
+ }
+
+ CMyComPtr<IArchiveFolderInternal> archiveFolderInternal;
+ RINOK(archiveFolder.QueryInterface(IID_IArchiveFolderInternal, &archiveFolderInternal));
+ CAgentFolder *agentFolder;
+ RINOK(archiveFolderInternal->GetAgentFolder(&agentFolder));
+ _proxyDirIndex = agentFolder->_proxyDirIndex;
+ // _parentFolder = agentFolder->_parentFolder;
+ */
+
+ if (_proxy2)
+ _isAltStreamFolder = _proxy2->IsAltDir(_proxyDirIndex);
+
+ return res;
+
+ }
+ catch(const UString &s)
+ {
+ if (updateCallback100)
+ {
+ UString s2 ("Error: ");
+ s2 += s;
+ RINOK(updateCallback100->UpdateErrorMessage(s2))
+ return E_FAIL;
+ }
+ throw;
+ }
+}
+
+
+Z7_COM7F_IMF(CAgentFolder::CopyFrom(Int32 moveMode,
+ const wchar_t *fromFolderPath, /* test it */
+ const wchar_t * const *itemsPaths,
+ UInt32 numItems,
+ IProgress *progress))
+{
+ COM_TRY_BEGIN
+ {
+ RINOK(_agentSpec->SetFiles(fromFolderPath, itemsPaths, numItems))
+ return CommonUpdateOperation(AGENT_OP_Uni, (moveMode != 0), NULL,
+ &NUpdateArchive::k_ActionSet_Add,
+ NULL, 0, progress);
+ }
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CAgentFolder::CopyFromFile(UInt32 destIndex, const wchar_t *itemPath, IProgress *progress))
+{
+ COM_TRY_BEGIN
+ return CommonUpdateOperation(AGENT_OP_CopyFromFile, false, itemPath,
+ &NUpdateArchive::k_ActionSet_Add,
+ &destIndex, 1, progress);
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CAgentFolder::Delete(const UInt32 *indices, UInt32 numItems, IProgress *progress))
+{
+ COM_TRY_BEGIN
+ return CommonUpdateOperation(AGENT_OP_Delete, false, NULL,
+ &NUpdateArchive::k_ActionSet_Delete, indices, numItems, progress);
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CAgentFolder::CreateFolder(const wchar_t *name, IProgress *progress))
+{
+ COM_TRY_BEGIN
+
+ if (_isAltStreamFolder)
+ return E_NOTIMPL;
+
+ if (_proxy2)
+ {
+ if (_proxy2->IsThere_SubDir(_proxyDirIndex, name))
+ return ERROR_ALREADY_EXISTS;
+ }
+ else
+ {
+ if (_proxy->FindSubDir(_proxyDirIndex, name) != -1)
+ return ERROR_ALREADY_EXISTS;
+ }
+
+ return CommonUpdateOperation(AGENT_OP_CreateFolder, false, name, NULL, NULL, 0, progress);
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CAgentFolder::Rename(UInt32 index, const wchar_t *newName, IProgress *progress))
+{
+ COM_TRY_BEGIN
+ return CommonUpdateOperation(AGENT_OP_Rename, false, newName, NULL,
+ &index, 1, progress);
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CAgentFolder::CreateFile(const wchar_t * /* name */, IProgress * /* progress */))
+{
+ return E_NOTIMPL;
+}
+
+Z7_COM7F_IMF(CAgentFolder::SetProperty(UInt32 index, PROPID propID,
+ const PROPVARIANT *value, IProgress *progress))
+{
+ COM_TRY_BEGIN
+ if (propID != kpidComment || value->vt != VT_BSTR)
+ return E_NOTIMPL;
+ if (!_agentSpec || !_agentSpec->GetTypeOfArc(_agentSpec->GetArc()).IsEqualTo_Ascii_NoCase("zip"))
+ return E_NOTIMPL;
+
+ return CommonUpdateOperation(AGENT_OP_Comment, false, value->bstrVal, NULL,
+ &index, 1, progress);
+ COM_TRY_END
+}
diff --git a/CPP/7zip/UI/Agent/IFolderArchive.h b/CPP/7zip/UI/Agent/IFolderArchive.h
new file mode 100644
index 0000000..55f1423
--- /dev/null
+++ b/CPP/7zip/UI/Agent/IFolderArchive.h
@@ -0,0 +1,107 @@
+// IFolderArchive.h
+
+#ifndef ZIP7_INC_IFOLDER_ARCHIVE_H
+#define ZIP7_INC_IFOLDER_ARCHIVE_H
+
+#include "../../../Common/MyString.h"
+
+#include "../../Archive/IArchive.h"
+#include "../../UI/Common/LoadCodecs.h"
+#include "../../UI/FileManager/IFolder.h"
+
+#include "../Common/ExtractMode.h"
+#include "../Common/IFileExtractCallback.h"
+
+Z7_PURE_INTERFACES_BEGIN
+
+/* ---------- IArchiveFolder ----------
+IArchiveFolder is implemented by CAgentFolder (Agent/Agent.h)
+IArchiveFolder is used by:
+ - FileManager/PanelCopy.cpp
+ CPanel::CopyTo(), if (options->testMode)
+ - FAR/PluginRead.cpp
+ CPlugin::ExtractFiles
+*/
+
+#define Z7_IFACEM_IArchiveFolder(x) \
+ x(Extract(const UInt32 *indices, UInt32 numItems, \
+ Int32 includeAltStreams, \
+ Int32 replaceAltStreamCharsMode, \
+ NExtract::NPathMode::EEnum pathMode, \
+ NExtract::NOverwriteMode::EEnum overwriteMode, \
+ const wchar_t *path, Int32 testMode, \
+ IFolderArchiveExtractCallback *extractCallback2)) \
+
+Z7_IFACE_CONSTR_FOLDERARC(IArchiveFolder, 0x0D)
+
+
+/* ---------- IInFolderArchive ----------
+IInFolderArchive is implemented by CAgent (Agent/Agent.h)
+IInFolderArchive Is used by FAR/Plugin
+*/
+
+#define Z7_IFACEM_IInFolderArchive(x) \
+ x(Open(IInStream *inStream, const wchar_t *filePath, const wchar_t *arcFormat, BSTR *archiveTypeRes, IArchiveOpenCallback *openArchiveCallback)) \
+ x(ReOpen(IArchiveOpenCallback *openArchiveCallback)) \
+ x(Close()) \
+ x(GetNumberOfProperties(UInt32 *numProperties)) \
+ x(GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \
+ x(BindToRootFolder(IFolderFolder **resultFolder)) \
+ x(Extract(NExtract::NPathMode::EEnum pathMode, \
+ NExtract::NOverwriteMode::EEnum overwriteMode, const wchar_t *path, \
+ Int32 testMode, IFolderArchiveExtractCallback *extractCallback2)) \
+
+Z7_IFACE_CONSTR_FOLDERARC(IInFolderArchive, 0x0E)
+
+#define Z7_IFACEM_IFolderArchiveUpdateCallback(x) \
+ x(CompressOperation(const wchar_t *name)) \
+ x(DeleteOperation(const wchar_t *name)) \
+ x(OperationResult(Int32 opRes)) \
+ x(UpdateErrorMessage(const wchar_t *message)) \
+ x(SetNumFiles(UInt64 numFiles)) \
+
+Z7_IFACE_CONSTR_FOLDERARC_SUB(IFolderArchiveUpdateCallback, IProgress, 0x0B)
+
+#define Z7_IFACEM_IOutFolderArchive(x) \
+ x(SetFolder(IFolderFolder *folder)) \
+ x(SetFiles(const wchar_t *folderPrefix, const wchar_t * const *names, UInt32 numNames)) \
+ x(DeleteItems(ISequentialOutStream *outArchiveStream, \
+ const UInt32 *indices, UInt32 numItems, IFolderArchiveUpdateCallback *updateCallback)) \
+ x(DoOperation( \
+ FStringVector *requestedPaths, \
+ FStringVector *processedPaths, \
+ CCodecs *codecs, int index, \
+ ISequentialOutStream *outArchiveStream, const Byte *stateActions, const wchar_t *sfxModule, \
+ IFolderArchiveUpdateCallback *updateCallback)) \
+ x(DoOperation2( \
+ FStringVector *requestedPaths, \
+ FStringVector *processedPaths, \
+ ISequentialOutStream *outArchiveStream, const Byte *stateActions, const wchar_t *sfxModule, \
+ IFolderArchiveUpdateCallback *updateCallback)) \
+
+Z7_IFACE_CONSTR_FOLDERARC(IOutFolderArchive, 0x0F)
+
+
+#define Z7_IFACEM_IFolderArchiveUpdateCallback2(x) \
+ x(OpenFileError(const wchar_t *path, HRESULT errorCode)) \
+ x(ReadingFileError(const wchar_t *path, HRESULT errorCode)) \
+ x(ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *path)) \
+ x(ReportUpdateOperation(UInt32 notifyOp, const wchar_t *path, Int32 isDir)) \
+
+Z7_IFACE_CONSTR_FOLDERARC(IFolderArchiveUpdateCallback2, 0x10)
+
+
+#define Z7_IFACEM_IFolderScanProgress(x) \
+ x(ScanError(const wchar_t *path, HRESULT errorCode)) \
+ x(ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, Int32 isDir)) \
+
+Z7_IFACE_CONSTR_FOLDERARC(IFolderScanProgress, 0x11)
+
+
+#define Z7_IFACEM_IFolderSetZoneIdMode(x) \
+ x(SetZoneIdMode(NExtract::NZoneIdMode::EEnum zoneMode)) \
+
+Z7_IFACE_CONSTR_FOLDERARC(IFolderSetZoneIdMode, 0x12)
+
+Z7_PURE_INTERFACES_END
+#endif
diff --git a/CPP/7zip/UI/Agent/StdAfx.h b/CPP/7zip/UI/Agent/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/UI/Agent/StdAfx.h
@@ -0,0 +1,11 @@
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp b/CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp
new file mode 100644
index 0000000..8299902
--- /dev/null
+++ b/CPP/7zip/UI/Agent/UpdateCallbackAgent.cpp
@@ -0,0 +1,208 @@
+// UpdateCallbackAgent.h
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+
+#include "../../../Windows/ErrorMsg.h"
+
+#include "UpdateCallbackAgent.h"
+
+using namespace NWindows;
+
+void CUpdateCallbackAgent::SetCallback(IFolderArchiveUpdateCallback *callback)
+{
+ Callback = callback;
+ _compressProgress.Release();
+ Callback2.Release();
+ if (Callback)
+ {
+ Callback.QueryInterface(IID_ICompressProgressInfo, &_compressProgress);
+ Callback.QueryInterface(IID_IFolderArchiveUpdateCallback2, &Callback2);
+ }
+}
+
+HRESULT CUpdateCallbackAgent::SetNumItems(const CArcToDoStat &stat)
+{
+ if (Callback)
+ return Callback->SetNumFiles(stat.Get_NumDataItems_Total());
+ return S_OK;
+}
+
+
+HRESULT CUpdateCallbackAgent::WriteSfx(const wchar_t * /* name */, UInt64 /* size */)
+{
+ return S_OK;
+}
+
+
+HRESULT CUpdateCallbackAgent::SetTotal(UINT64 size)
+{
+ if (Callback)
+ return Callback->SetTotal(size);
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackAgent::SetCompleted(const UINT64 *completeValue)
+{
+ if (Callback)
+ return Callback->SetCompleted(completeValue);
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackAgent::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ if (_compressProgress)
+ return _compressProgress->SetRatioInfo(inSize, outSize);
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackAgent::CheckBreak()
+{
+ return S_OK;
+}
+
+/*
+HRESULT CUpdateCallbackAgent::Finalize()
+{
+ return S_OK;
+}
+*/
+
+HRESULT CUpdateCallbackAgent::OpenFileError(const FString &path, DWORD systemError)
+{
+ const HRESULT hres = HRESULT_FROM_WIN32(systemError);
+ // if (systemError == ERROR_SHARING_VIOLATION)
+ {
+ if (Callback2)
+ {
+ RINOK(Callback2->OpenFileError(fs2us(path), hres))
+ return S_FALSE;
+ }
+
+ if (Callback)
+ {
+ UString s ("WARNING: ");
+ s += NError::MyFormatMessage(systemError);
+ s += ": ";
+ s += fs2us(path);
+ RINOK(Callback->UpdateErrorMessage(s))
+ return S_FALSE;
+ }
+ }
+ // FailedFiles.Add(name);
+ return hres;
+}
+
+HRESULT CUpdateCallbackAgent::ReadingFileError(const FString &path, DWORD systemError)
+{
+ const HRESULT hres = HRESULT_FROM_WIN32(systemError);
+
+ // if (systemError == ERROR_SHARING_VIOLATION)
+ {
+ if (Callback2)
+ {
+ RINOK(Callback2->ReadingFileError(fs2us(path), hres))
+ }
+ else if (Callback)
+ {
+ UString s ("ERROR: ");
+ s += NError::MyFormatMessage(systemError);
+ s += ": ";
+ s += fs2us(path);
+ RINOK(Callback->UpdateErrorMessage(s))
+ }
+ }
+ // FailedFiles.Add(name);
+ return hres;
+}
+
+HRESULT CUpdateCallbackAgent::GetStream(const wchar_t *name, bool isDir, bool /* isAnti */, UInt32 mode)
+{
+ if (Callback2)
+ return Callback2->ReportUpdateOperation(mode, name, BoolToInt(isDir));
+ if (Callback)
+ return Callback->CompressOperation(name);
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackAgent::SetOperationResult(Int32 operationResult)
+{
+ if (Callback)
+ return Callback->OperationResult(operationResult);
+ return S_OK;
+}
+
+void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s);
+
+HRESULT CUpdateCallbackAgent::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name)
+{
+ if (Callback2)
+ {
+ return Callback2->ReportExtractResult(opRes, isEncrypted, name);
+ }
+ /*
+ if (mode != NArchive::NExtract::NOperationResult::kOK)
+ {
+ Int32 encrypted = 0;
+ UString s;
+ SetExtractErrorMessage(mode, encrypted, name, s);
+ // ProgressDialog->Sync.AddError_Message(s);
+ }
+ */
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackAgent::ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir)
+{
+ if (Callback2)
+ {
+ return Callback2->ReportUpdateOperation(op, name, BoolToInt(isDir));
+ }
+ return S_OK;
+}
+
+/*
+HRESULT CUpdateCallbackAgent::SetPassword(const UString &
+ #ifndef Z7_NO_CRYPTO
+ password
+ #endif
+ )
+{
+ #ifndef Z7_NO_CRYPTO
+ PasswordIsDefined = true;
+ Password = password;
+ #endif
+ return S_OK;
+}
+*/
+
+HRESULT CUpdateCallbackAgent::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
+{
+ *password = NULL;
+ *passwordIsDefined = BoolToInt(false);
+ if (!_cryptoGetTextPassword)
+ {
+ if (!Callback)
+ return S_OK;
+ Callback.QueryInterface(IID_ICryptoGetTextPassword2, &_cryptoGetTextPassword);
+ if (!_cryptoGetTextPassword)
+ return S_OK;
+ }
+ return _cryptoGetTextPassword->CryptoGetTextPassword2(passwordIsDefined, password);
+}
+
+HRESULT CUpdateCallbackAgent::CryptoGetTextPassword(BSTR *password)
+{
+ *password = NULL;
+ CMyComPtr<ICryptoGetTextPassword> getTextPassword;
+ Callback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
+ if (!getTextPassword)
+ return E_NOTIMPL;
+ return getTextPassword->CryptoGetTextPassword(password);
+}
+
+HRESULT CUpdateCallbackAgent::ShowDeleteFile(const wchar_t *name, bool /* isDir */)
+{
+ return Callback->DeleteOperation(name);
+}
diff --git a/CPP/7zip/UI/Agent/UpdateCallbackAgent.h b/CPP/7zip/UI/Agent/UpdateCallbackAgent.h
new file mode 100644
index 0000000..179ce98
--- /dev/null
+++ b/CPP/7zip/UI/Agent/UpdateCallbackAgent.h
@@ -0,0 +1,22 @@
+// UpdateCallbackAgent.h
+
+#ifndef ZIP7_INC_UPDATE_CALLBACK_AGENT_H
+#define ZIP7_INC_UPDATE_CALLBACK_AGENT_H
+
+#include "../Common/UpdateCallback.h"
+
+#include "IFolderArchive.h"
+
+class CUpdateCallbackAgent Z7_final: public IUpdateCallbackUI
+{
+ Z7_IFACE_IMP(IUpdateCallbackUI)
+
+ CMyComPtr<ICryptoGetTextPassword2> _cryptoGetTextPassword;
+ CMyComPtr<IFolderArchiveUpdateCallback> Callback;
+ CMyComPtr<IFolderArchiveUpdateCallback2> Callback2;
+ CMyComPtr<ICompressProgressInfo> _compressProgress;
+public:
+ void SetCallback(IFolderArchiveUpdateCallback *callback);
+};
+
+#endif
diff --git a/CPP/7zip/UI/Client7z/Client7z.cpp b/CPP/7zip/UI/Client7z/Client7z.cpp
index 9a06cdc..121a2f1 100644
--- a/CPP/7zip/UI/Client7z/Client7z.cpp
+++ b/CPP/7zip/UI/Client7z/Client7z.cpp
@@ -1,993 +1,1122 @@
-// Client7z.cpp
-
-#include "StdAfx.h"
-
-#include <stdio.h>
-
-#include "../../../Common/MyWindows.h"
-
-#include "../../../Common/Defs.h"
-#include "../../../Common/MyInitGuid.h"
-
-#include "../../../Common/IntToString.h"
-#include "../../../Common/StringConvert.h"
-
-#include "../../../Windows/DLL.h"
-#include "../../../Windows/FileDir.h"
-#include "../../../Windows/FileFind.h"
-#include "../../../Windows/FileName.h"
-#include "../../../Windows/NtCheck.h"
-#include "../../../Windows/PropVariant.h"
-#include "../../../Windows/PropVariantConv.h"
-
-#include "../../Common/FileStreams.h"
-
-#include "../../Archive/IArchive.h"
-
-#include "../../IPassword.h"
-#include "../../../../C/7zVersion.h"
-
-#ifdef _WIN32
-HINSTANCE g_hInstance = 0;
-#endif
-
-// Tou can find the list of all GUIDs in Guid.txt file.
-// use another CLSIDs, if you want to support other formats (zip, rar, ...).
-// {23170F69-40C1-278A-1000-000110070000}
-
-DEFINE_GUID(CLSID_CFormat7z,
- 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x07, 0x00, 0x00);
-DEFINE_GUID(CLSID_CFormatXz,
- 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, 0x0C, 0x00, 0x00);
-
-#define CLSID_Format CLSID_CFormat7z
-// #define CLSID_Format CLSID_CFormatXz
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NDir;
-
-#define kDllName "7z.dll"
-
-static const char * const kCopyrightString =
- "\n"
- "7-Zip"
- " (" kDllName " client)"
- " " MY_VERSION
- " : " MY_COPYRIGHT_DATE
- "\n";
-
-static const char * const kHelpString =
-"Usage: 7zcl.exe [a | l | x] archive.7z [fileName ...]\n"
-"Examples:\n"
-" 7zcl.exe a archive.7z f1.txt f2.txt : compress two files to archive.7z\n"
-" 7zcl.exe l archive.7z : List contents of archive.7z\n"
-" 7zcl.exe x archive.7z : eXtract files from archive.7z\n";
-
-
-static void Convert_UString_to_AString(const UString &s, AString &temp)
-{
- int codePage = CP_OEMCP;
- /*
- int g_CodePage = -1;
- int codePage = g_CodePage;
- if (codePage == -1)
- codePage = CP_OEMCP;
- if (codePage == CP_UTF8)
- ConvertUnicodeToUTF8(s, temp);
- else
- */
- UnicodeStringToMultiByte2(temp, s, (UINT)codePage);
-}
-
-static FString CmdStringToFString(const char *s)
-{
- return us2fs(GetUnicodeString(s));
-}
-
-static void Print(const char *s)
-{
- fputs(s, stdout);
-}
-
-static void Print(const AString &s)
-{
- Print(s.Ptr());
-}
-
-static void Print(const UString &s)
-{
- AString as;
- Convert_UString_to_AString(s, as);
- Print(as);
-}
-
-static void Print(const wchar_t *s)
-{
- Print(UString(s));
-}
-
-static void PrintNewLine()
-{
- Print("\n");
-}
-
-static void PrintStringLn(const char *s)
-{
- Print(s);
- PrintNewLine();
-}
-
-static void PrintError(const char *message)
-{
- Print("Error: ");
- PrintNewLine();
- Print(message);
- PrintNewLine();
-}
-
-static void PrintError(const char *message, const FString &name)
-{
- PrintError(message);
- Print(name);
-}
-
-
-static HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result)
-{
- NCOM::CPropVariant prop;
- RINOK(archive->GetProperty(index, propID, &prop));
- if (prop.vt == VT_BOOL)
- result = VARIANT_BOOLToBool(prop.boolVal);
- else if (prop.vt == VT_EMPTY)
- result = false;
- else
- return E_FAIL;
- return S_OK;
-}
-
-static HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result)
-{
- return IsArchiveItemProp(archive, index, kpidIsDir, result);
-}
-
-
-static const wchar_t * const kEmptyFileAlias = L"[Content]";
-
-
-//////////////////////////////////////////////////////////////
-// Archive Open callback class
-
-
-class CArchiveOpenCallback:
- public IArchiveOpenCallback,
- public ICryptoGetTextPassword,
- public CMyUnknownImp
-{
-public:
- MY_UNKNOWN_IMP1(ICryptoGetTextPassword)
-
- STDMETHOD(SetTotal)(const UInt64 *files, const UInt64 *bytes);
- STDMETHOD(SetCompleted)(const UInt64 *files, const UInt64 *bytes);
-
- STDMETHOD(CryptoGetTextPassword)(BSTR *password);
-
- bool PasswordIsDefined;
- UString Password;
-
- CArchiveOpenCallback() : PasswordIsDefined(false) {}
-};
-
-STDMETHODIMP CArchiveOpenCallback::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */)
-{
- return S_OK;
-}
-
-STDMETHODIMP CArchiveOpenCallback::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */)
-{
- return S_OK;
-}
-
-STDMETHODIMP CArchiveOpenCallback::CryptoGetTextPassword(BSTR *password)
-{
- if (!PasswordIsDefined)
- {
- // You can ask real password here from user
- // Password = GetPassword(OutStream);
- // PasswordIsDefined = true;
- PrintError("Password is not defined");
- return E_ABORT;
- }
- return StringToBstr(Password, password);
-}
-
-
-
-static const char * const kIncorrectCommand = "incorrect command";
-
-//////////////////////////////////////////////////////////////
-// Archive Extracting callback class
-
-static const char * const kTestingString = "Testing ";
-static const char * const kExtractingString = "Extracting ";
-static const char * const kSkippingString = "Skipping ";
-
-static const char * const kUnsupportedMethod = "Unsupported Method";
-static const char * const kCRCFailed = "CRC Failed";
-static const char * const kDataError = "Data Error";
-static const char * const kUnavailableData = "Unavailable data";
-static const char * const kUnexpectedEnd = "Unexpected end of data";
-static const char * const kDataAfterEnd = "There are some data after the end of the payload data";
-static const char * const kIsNotArc = "Is not archive";
-static const char * const kHeadersError = "Headers Error";
-
-
-class CArchiveExtractCallback:
- public IArchiveExtractCallback,
- public ICryptoGetTextPassword,
- public CMyUnknownImp
-{
-public:
- MY_UNKNOWN_IMP1(ICryptoGetTextPassword)
-
- // IProgress
- STDMETHOD(SetTotal)(UInt64 size);
- STDMETHOD(SetCompleted)(const UInt64 *completeValue);
-
- // IArchiveExtractCallback
- STDMETHOD(GetStream)(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode);
- STDMETHOD(PrepareOperation)(Int32 askExtractMode);
- STDMETHOD(SetOperationResult)(Int32 resultEOperationResult);
-
- // ICryptoGetTextPassword
- STDMETHOD(CryptoGetTextPassword)(BSTR *aPassword);
-
-private:
- CMyComPtr<IInArchive> _archiveHandler;
- FString _directoryPath; // Output directory
- UString _filePath; // name inside arcvhive
- FString _diskFilePath; // full path to file on disk
- bool _extractMode;
- struct CProcessedFileInfo
- {
- FILETIME MTime;
- UInt32 Attrib;
- bool isDir;
- bool AttribDefined;
- bool MTimeDefined;
- } _processedFileInfo;
-
- COutFileStream *_outFileStreamSpec;
- CMyComPtr<ISequentialOutStream> _outFileStream;
-
-public:
- void Init(IInArchive *archiveHandler, const FString &directoryPath);
-
- UInt64 NumErrors;
- bool PasswordIsDefined;
- UString Password;
-
- CArchiveExtractCallback() : PasswordIsDefined(false) {}
-};
-
-void CArchiveExtractCallback::Init(IInArchive *archiveHandler, const FString &directoryPath)
-{
- NumErrors = 0;
- _archiveHandler = archiveHandler;
- _directoryPath = directoryPath;
- NName::NormalizeDirPathPrefix(_directoryPath);
-}
-
-STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 /* size */)
-{
- return S_OK;
-}
-
-STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 * /* completeValue */)
-{
- return S_OK;
-}
-
-STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index,
- ISequentialOutStream **outStream, Int32 askExtractMode)
-{
- *outStream = 0;
- _outFileStream.Release();
-
- {
- // Get Name
- NCOM::CPropVariant prop;
- RINOK(_archiveHandler->GetProperty(index, kpidPath, &prop));
-
- UString fullPath;
- if (prop.vt == VT_EMPTY)
- fullPath = kEmptyFileAlias;
- else
- {
- if (prop.vt != VT_BSTR)
- return E_FAIL;
- fullPath = prop.bstrVal;
- }
- _filePath = fullPath;
- }
-
- if (askExtractMode != NArchive::NExtract::NAskMode::kExtract)
- return S_OK;
-
- {
- // Get Attrib
- NCOM::CPropVariant prop;
- RINOK(_archiveHandler->GetProperty(index, kpidAttrib, &prop));
- if (prop.vt == VT_EMPTY)
- {
- _processedFileInfo.Attrib = 0;
- _processedFileInfo.AttribDefined = false;
- }
- else
- {
- if (prop.vt != VT_UI4)
- return E_FAIL;
- _processedFileInfo.Attrib = prop.ulVal;
- _processedFileInfo.AttribDefined = true;
- }
- }
-
- RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.isDir));
-
- {
- // Get Modified Time
- NCOM::CPropVariant prop;
- RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop));
- _processedFileInfo.MTimeDefined = false;
- switch (prop.vt)
- {
- case VT_EMPTY:
- // _processedFileInfo.MTime = _utcMTimeDefault;
- break;
- case VT_FILETIME:
- _processedFileInfo.MTime = prop.filetime;
- _processedFileInfo.MTimeDefined = true;
- break;
- default:
- return E_FAIL;
- }
-
- }
- {
- // Get Size
- NCOM::CPropVariant prop;
- RINOK(_archiveHandler->GetProperty(index, kpidSize, &prop));
- UInt64 newFileSize;
- /* bool newFileSizeDefined = */ ConvertPropVariantToUInt64(prop, newFileSize);
- }
-
-
- {
- // Create folders for file
- int slashPos = _filePath.ReverseFind_PathSepar();
- if (slashPos >= 0)
- CreateComplexDir(_directoryPath + us2fs(_filePath.Left(slashPos)));
- }
-
- FString fullProcessedPath = _directoryPath + us2fs(_filePath);
- _diskFilePath = fullProcessedPath;
-
- if (_processedFileInfo.isDir)
- {
- CreateComplexDir(fullProcessedPath);
- }
- else
- {
- NFind::CFileInfo fi;
- if (fi.Find(fullProcessedPath))
- {
- if (!DeleteFileAlways(fullProcessedPath))
- {
- PrintError("Can not delete output file", fullProcessedPath);
- return E_ABORT;
- }
- }
-
- _outFileStreamSpec = new COutFileStream;
- CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
- if (!_outFileStreamSpec->Open(fullProcessedPath, CREATE_ALWAYS))
- {
- PrintError("Can not open output file", fullProcessedPath);
- return E_ABORT;
- }
- _outFileStream = outStreamLoc;
- *outStream = outStreamLoc.Detach();
- }
- return S_OK;
-}
-
-STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)
-{
- _extractMode = false;
- switch (askExtractMode)
- {
- case NArchive::NExtract::NAskMode::kExtract: _extractMode = true; break;
- };
- switch (askExtractMode)
- {
- case NArchive::NExtract::NAskMode::kExtract: Print(kExtractingString); break;
- case NArchive::NExtract::NAskMode::kTest: Print(kTestingString); break;
- case NArchive::NExtract::NAskMode::kSkip: Print(kSkippingString); break;
- };
- Print(_filePath);
- return S_OK;
-}
-
-STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 operationResult)
-{
- switch (operationResult)
- {
- case NArchive::NExtract::NOperationResult::kOK:
- break;
- default:
- {
- NumErrors++;
- Print(" : ");
- const char *s = NULL;
- switch (operationResult)
- {
- case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
- s = kUnsupportedMethod;
- break;
- case NArchive::NExtract::NOperationResult::kCRCError:
- s = kCRCFailed;
- break;
- case NArchive::NExtract::NOperationResult::kDataError:
- s = kDataError;
- break;
- case NArchive::NExtract::NOperationResult::kUnavailable:
- s = kUnavailableData;
- break;
- case NArchive::NExtract::NOperationResult::kUnexpectedEnd:
- s = kUnexpectedEnd;
- break;
- case NArchive::NExtract::NOperationResult::kDataAfterEnd:
- s = kDataAfterEnd;
- break;
- case NArchive::NExtract::NOperationResult::kIsNotArc:
- s = kIsNotArc;
- break;
- case NArchive::NExtract::NOperationResult::kHeadersError:
- s = kHeadersError;
- break;
- }
- if (s)
- {
- Print("Error : ");
- Print(s);
- }
- else
- {
- char temp[16];
- ConvertUInt32ToString(operationResult, temp);
- Print("Error #");
- Print(temp);
- }
- }
- }
-
- if (_outFileStream)
- {
- if (_processedFileInfo.MTimeDefined)
- _outFileStreamSpec->SetMTime(&_processedFileInfo.MTime);
- RINOK(_outFileStreamSpec->Close());
- }
- _outFileStream.Release();
- if (_extractMode && _processedFileInfo.AttribDefined)
- SetFileAttrib_PosixHighDetect(_diskFilePath, _processedFileInfo.Attrib);
- PrintNewLine();
- return S_OK;
-}
-
-
-STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)
-{
- if (!PasswordIsDefined)
- {
- // You can ask real password here from user
- // Password = GetPassword(OutStream);
- // PasswordIsDefined = true;
- PrintError("Password is not defined");
- return E_ABORT;
- }
- return StringToBstr(Password, password);
-}
-
-
-
-//////////////////////////////////////////////////////////////
-// Archive Creating callback class
-
-struct CDirItem
-{
- UInt64 Size;
- FILETIME CTime;
- FILETIME ATime;
- FILETIME MTime;
- UString Name;
- FString FullPath;
- UInt32 Attrib;
-
- bool isDir() const { return (Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ; }
-};
-
-class CArchiveUpdateCallback:
- public IArchiveUpdateCallback2,
- public ICryptoGetTextPassword2,
- public CMyUnknownImp
-{
-public:
- MY_UNKNOWN_IMP2(IArchiveUpdateCallback2, ICryptoGetTextPassword2)
-
- // IProgress
- STDMETHOD(SetTotal)(UInt64 size);
- STDMETHOD(SetCompleted)(const UInt64 *completeValue);
-
- // IUpdateCallback2
- STDMETHOD(GetUpdateItemInfo)(UInt32 index,
- Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive);
- STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
- STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **inStream);
- STDMETHOD(SetOperationResult)(Int32 operationResult);
- STDMETHOD(GetVolumeSize)(UInt32 index, UInt64 *size);
- STDMETHOD(GetVolumeStream)(UInt32 index, ISequentialOutStream **volumeStream);
-
- STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password);
-
-public:
- CRecordVector<UInt64> VolumesSizes;
- UString VolName;
- UString VolExt;
-
- FString DirPrefix;
- const CObjectVector<CDirItem> *DirItems;
-
- bool PasswordIsDefined;
- UString Password;
- bool AskPassword;
-
- bool m_NeedBeClosed;
-
- FStringVector FailedFiles;
- CRecordVector<HRESULT> FailedCodes;
-
- CArchiveUpdateCallback(): PasswordIsDefined(false), AskPassword(false), DirItems(0) {};
-
- ~CArchiveUpdateCallback() { Finilize(); }
- HRESULT Finilize();
-
- void Init(const CObjectVector<CDirItem> *dirItems)
- {
- DirItems = dirItems;
- m_NeedBeClosed = false;
- FailedFiles.Clear();
- FailedCodes.Clear();
- }
-};
-
-STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 /* size */)
-{
- return S_OK;
-}
-
-STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 * /* completeValue */)
-{
- return S_OK;
-}
-
-STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 /* index */,
- Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive)
-{
- if (newData)
- *newData = BoolToInt(true);
- if (newProperties)
- *newProperties = BoolToInt(true);
- if (indexInArchive)
- *indexInArchive = (UInt32)(Int32)-1;
- return S_OK;
-}
-
-STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
-{
- NCOM::CPropVariant prop;
-
- if (propID == kpidIsAnti)
- {
- prop = false;
- prop.Detach(value);
- return S_OK;
- }
-
- {
- const CDirItem &dirItem = (*DirItems)[index];
- switch (propID)
- {
- case kpidPath: prop = dirItem.Name; break;
- case kpidIsDir: prop = dirItem.isDir(); break;
- case kpidSize: prop = dirItem.Size; break;
- case kpidAttrib: prop = dirItem.Attrib; break;
- case kpidCTime: prop = dirItem.CTime; break;
- case kpidATime: prop = dirItem.ATime; break;
- case kpidMTime: prop = dirItem.MTime; break;
- }
- }
- prop.Detach(value);
- return S_OK;
-}
-
-HRESULT CArchiveUpdateCallback::Finilize()
-{
- if (m_NeedBeClosed)
- {
- PrintNewLine();
- m_NeedBeClosed = false;
- }
- return S_OK;
-}
-
-static void GetStream2(const wchar_t *name)
-{
- Print("Compressing ");
- if (name[0] == 0)
- name = kEmptyFileAlias;
- Print(name);
-}
-
-STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)
-{
- RINOK(Finilize());
-
- const CDirItem &dirItem = (*DirItems)[index];
- GetStream2(dirItem.Name);
-
- if (dirItem.isDir())
- return S_OK;
-
- {
- CInFileStream *inStreamSpec = new CInFileStream;
- CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
- FString path = DirPrefix + dirItem.FullPath;
- if (!inStreamSpec->Open(path))
- {
- DWORD sysError = ::GetLastError();
- FailedCodes.Add(sysError);
- FailedFiles.Add(path);
- // if (systemError == ERROR_SHARING_VIOLATION)
- {
- PrintNewLine();
- PrintError("WARNING: can't open file");
- // Print(NError::MyFormatMessageW(systemError));
- return S_FALSE;
- }
- // return sysError;
- }
- *inStream = inStreamLoc.Detach();
- }
- return S_OK;
-}
-
-STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 /* operationResult */)
-{
- m_NeedBeClosed = true;
- return S_OK;
-}
-
-STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)
-{
- if (VolumesSizes.Size() == 0)
- return S_FALSE;
- if (index >= (UInt32)VolumesSizes.Size())
- index = VolumesSizes.Size() - 1;
- *size = VolumesSizes[index];
- return S_OK;
-}
-
-STDMETHODIMP CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)
-{
- wchar_t temp[16];
- ConvertUInt32ToString(index + 1, temp);
- UString res = temp;
- while (res.Len() < 2)
- res.InsertAtFront(L'0');
- UString fileName = VolName;
- fileName += '.';
- fileName += res;
- fileName += VolExt;
- COutFileStream *streamSpec = new COutFileStream;
- CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
- if (!streamSpec->Create(us2fs(fileName), false))
- return ::GetLastError();
- *volumeStream = streamLoc.Detach();
- return S_OK;
-}
-
-STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
-{
- if (!PasswordIsDefined)
- {
- if (AskPassword)
- {
- // You can ask real password here from user
- // Password = GetPassword(OutStream);
- // PasswordIsDefined = true;
- PrintError("Password is not defined");
- return E_ABORT;
- }
- }
- *passwordIsDefined = BoolToInt(PasswordIsDefined);
- return StringToBstr(Password, password);
-}
-
-
-// Main function
-
-#define NT_CHECK_FAIL_ACTION PrintError("Unsupported Windows version"); return 1;
-
-int MY_CDECL main(int numArgs, const char *args[])
-{
- NT_CHECK
-
- PrintStringLn(kCopyrightString);
-
- if (numArgs < 2)
- {
- PrintStringLn(kHelpString);
- return 0;
- }
-
- if (numArgs < 3)
- {
- PrintError(kIncorrectCommand);
- return 1;
- }
-
-
- NDLL::CLibrary lib;
- if (!lib.Load(NDLL::GetModuleDirPrefix() + FTEXT(kDllName)))
- {
- PrintError("Can not load 7-zip library");
- return 1;
- }
-
- Func_CreateObject createObjectFunc = (Func_CreateObject)lib.GetProc("CreateObject");
- if (!createObjectFunc)
- {
- PrintError("Can not get CreateObject");
- return 1;
- }
-
- char c;
- {
- AString command (args[1]);
- if (command.Len() != 1)
- {
- PrintError(kIncorrectCommand);
- return 1;
- }
- c = (char)MyCharLower_Ascii(command[0]);
- }
-
- FString archiveName = CmdStringToFString(args[2]);
-
- if (c == 'a')
- {
- // create archive command
- if (numArgs < 4)
- {
- PrintError(kIncorrectCommand);
- return 1;
- }
- CObjectVector<CDirItem> dirItems;
- {
- int i;
- for (i = 3; i < numArgs; i++)
- {
- CDirItem di;
- FString name = CmdStringToFString(args[i]);
-
- NFind::CFileInfo fi;
- if (!fi.Find(name))
- {
- PrintError("Can't find file", name);
- return 1;
- }
-
- di.Attrib = fi.Attrib;
- di.Size = fi.Size;
- di.CTime = fi.CTime;
- di.ATime = fi.ATime;
- di.MTime = fi.MTime;
- di.Name = fs2us(name);
- di.FullPath = name;
- dirItems.Add(di);
- }
- }
-
- COutFileStream *outFileStreamSpec = new COutFileStream;
- CMyComPtr<IOutStream> outFileStream = outFileStreamSpec;
- if (!outFileStreamSpec->Create(archiveName, false))
- {
- PrintError("can't create archive file");
- return 1;
- }
-
- CMyComPtr<IOutArchive> outArchive;
- if (createObjectFunc(&CLSID_Format, &IID_IOutArchive, (void **)&outArchive) != S_OK)
- {
- PrintError("Can not get class object");
- return 1;
- }
-
- CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
- CMyComPtr<IArchiveUpdateCallback2> updateCallback(updateCallbackSpec);
- updateCallbackSpec->Init(&dirItems);
- // updateCallbackSpec->PasswordIsDefined = true;
- // updateCallbackSpec->Password = L"1";
-
- /*
- {
- const wchar_t *names[] =
- {
- L"s",
- L"x"
- };
- const unsigned kNumProps = ARRAY_SIZE(names);
- NCOM::CPropVariant values[kNumProps] =
- {
- false, // solid mode OFF
- (UInt32)9 // compression level = 9 - ultra
- };
- CMyComPtr<ISetProperties> setProperties;
- outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties);
- if (!setProperties)
- {
- PrintError("ISetProperties unsupported");
- return 1;
- }
- RINOK(setProperties->SetProperties(names, values, kNumProps));
- }
- */
-
- HRESULT result = outArchive->UpdateItems(outFileStream, dirItems.Size(), updateCallback);
-
- updateCallbackSpec->Finilize();
-
- if (result != S_OK)
- {
- PrintError("Update Error");
- return 1;
- }
-
- FOR_VECTOR (i, updateCallbackSpec->FailedFiles)
- {
- PrintNewLine();
- PrintError("Error for file", updateCallbackSpec->FailedFiles[i]);
- }
-
- if (updateCallbackSpec->FailedFiles.Size() != 0)
- return 1;
- }
- else
- {
- if (numArgs != 3)
- {
- PrintError(kIncorrectCommand);
- return 1;
- }
-
- bool listCommand;
-
- if (c == 'l')
- listCommand = true;
- else if (c == 'x')
- listCommand = false;
- else
- {
- PrintError(kIncorrectCommand);
- return 1;
- }
-
- CMyComPtr<IInArchive> archive;
- if (createObjectFunc(&CLSID_Format, &IID_IInArchive, (void **)&archive) != S_OK)
- {
- PrintError("Can not get class object");
- return 1;
- }
-
- CInFileStream *fileSpec = new CInFileStream;
- CMyComPtr<IInStream> file = fileSpec;
-
- if (!fileSpec->Open(archiveName))
- {
- PrintError("Can not open archive file", archiveName);
- return 1;
- }
-
- {
- CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback;
- CMyComPtr<IArchiveOpenCallback> openCallback(openCallbackSpec);
- openCallbackSpec->PasswordIsDefined = false;
- // openCallbackSpec->PasswordIsDefined = true;
- // openCallbackSpec->Password = L"1";
-
- const UInt64 scanSize = 1 << 23;
- if (archive->Open(file, &scanSize, openCallback) != S_OK)
- {
- PrintError("Can not open file as archive", archiveName);
- return 1;
- }
- }
-
- if (listCommand)
- {
- // List command
- UInt32 numItems = 0;
- archive->GetNumberOfItems(&numItems);
- for (UInt32 i = 0; i < numItems; i++)
- {
- {
- // Get uncompressed size of file
- NCOM::CPropVariant prop;
- archive->GetProperty(i, kpidSize, &prop);
- char s[32];
- ConvertPropVariantToShortString(prop, s);
- Print(s);
- Print(" ");
- }
- {
- // Get name of file
- NCOM::CPropVariant prop;
- archive->GetProperty(i, kpidPath, &prop);
- if (prop.vt == VT_BSTR)
- Print(prop.bstrVal);
- else if (prop.vt != VT_EMPTY)
- Print("ERROR!");
- }
- PrintNewLine();
- }
- }
- else
- {
- // Extract command
- CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
- CMyComPtr<IArchiveExtractCallback> extractCallback(extractCallbackSpec);
- extractCallbackSpec->Init(archive, FString()); // second parameter is output folder path
- extractCallbackSpec->PasswordIsDefined = false;
- // extractCallbackSpec->PasswordIsDefined = true;
- // extractCallbackSpec->Password = "1";
-
- /*
- const wchar_t *names[] =
- {
- L"mt",
- L"mtf"
- };
- const unsigned kNumProps = sizeof(names) / sizeof(names[0]);
- NCOM::CPropVariant values[kNumProps] =
- {
- (UInt32)1,
- false
- };
- CMyComPtr<ISetProperties> setProperties;
- archive->QueryInterface(IID_ISetProperties, (void **)&setProperties);
- if (setProperties)
- setProperties->SetProperties(names, values, kNumProps);
- */
-
- HRESULT result = archive->Extract(NULL, (UInt32)(Int32)(-1), false, extractCallback);
-
- if (result != S_OK)
- {
- PrintError("Extract Error");
- return 1;
- }
- }
- }
-
- return 0;
-}
+// Client7z.cpp
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/MyInitGuid.h"
+
+#include "../../../Common/Defs.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/NtCheck.h"
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/PropVariantConv.h"
+
+#include "../../Common/FileStreams.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "../../IPassword.h"
+#include "../../../../C/7zVersion.h"
+
+#ifdef _WIN32
+extern
+HINSTANCE g_hInstance;
+HINSTANCE g_hInstance = NULL;
+#endif
+
+// You can find full list of all GUIDs supported by 7-Zip in Guid.txt file.
+// 7z format GUID: {23170F69-40C1-278A-1000-000110070000}
+
+#define DEFINE_GUID_ARC(name, id) Z7_DEFINE_GUID(name, \
+ 0x23170F69, 0x40C1, 0x278A, 0x10, 0x00, 0x00, 0x01, 0x10, id, 0x00, 0x00);
+
+enum
+{
+ kId_Zip = 1,
+ kId_BZip2 = 2,
+ kId_7z = 7,
+ kId_Xz = 0xC,
+ kId_Tar = 0xEE,
+ kId_GZip = 0xEF
+};
+
+// use another id, if you want to support other formats (zip, Xz, ...).
+// DEFINE_GUID_ARC (CLSID_Format, kId_Zip)
+// DEFINE_GUID_ARC (CLSID_Format, kId_BZip2)
+// DEFINE_GUID_ARC (CLSID_Format, kId_Xz)
+// DEFINE_GUID_ARC (CLSID_Format, kId_Tar)
+// DEFINE_GUID_ARC (CLSID_Format, kId_GZip)
+DEFINE_GUID_ARC (CLSID_Format, kId_7z)
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+#ifdef _WIN32
+#define kDllName "7z.dll"
+#else
+#define kDllName "7z.so"
+#endif
+
+static const char * const kCopyrightString =
+ "\n"
+ "7-Zip"
+ " (" kDllName " client)"
+ " " MY_VERSION
+ " : " MY_COPYRIGHT_DATE
+ "\n";
+
+static const char * const kHelpString =
+"Usage: 7zcl.exe [a | l | x] archive.7z [fileName ...]\n"
+"Examples:\n"
+" 7zcl.exe a archive.7z f1.txt f2.txt : compress two files to archive.7z\n"
+" 7zcl.exe l archive.7z : List contents of archive.7z\n"
+" 7zcl.exe x archive.7z : eXtract files from archive.7z\n";
+
+
+static void Convert_UString_to_AString(const UString &s, AString &temp)
+{
+ int codePage = CP_OEMCP;
+ /*
+ int g_CodePage = -1;
+ int codePage = g_CodePage;
+ if (codePage == -1)
+ codePage = CP_OEMCP;
+ if (codePage == CP_UTF8)
+ ConvertUnicodeToUTF8(s, temp);
+ else
+ */
+ UnicodeStringToMultiByte2(temp, s, (UINT)codePage);
+}
+
+static FString CmdStringToFString(const char *s)
+{
+ return us2fs(GetUnicodeString(s));
+}
+
+static void Print(const char *s)
+{
+ fputs(s, stdout);
+}
+
+static void Print(const AString &s)
+{
+ Print(s.Ptr());
+}
+
+static void Print(const UString &s)
+{
+ AString as;
+ Convert_UString_to_AString(s, as);
+ Print(as);
+}
+
+static void Print(const wchar_t *s)
+{
+ Print(UString(s));
+}
+
+static void PrintNewLine()
+{
+ Print("\n");
+}
+
+static void PrintStringLn(const char *s)
+{
+ Print(s);
+ PrintNewLine();
+}
+
+static void PrintError(const char *message)
+{
+ Print("Error: ");
+ PrintNewLine();
+ Print(message);
+ PrintNewLine();
+}
+
+static void PrintError(const char *message, const FString &name)
+{
+ PrintError(message);
+ Print(name);
+}
+
+
+static HRESULT IsArchiveItemProp(IInArchive *archive, UInt32 index, PROPID propID, bool &result)
+{
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, propID, &prop))
+ if (prop.vt == VT_BOOL)
+ result = VARIANT_BOOLToBool(prop.boolVal);
+ else if (prop.vt == VT_EMPTY)
+ result = false;
+ else
+ return E_FAIL;
+ return S_OK;
+}
+
+static HRESULT IsArchiveItemFolder(IInArchive *archive, UInt32 index, bool &result)
+{
+ return IsArchiveItemProp(archive, index, kpidIsDir, result);
+}
+
+
+static const wchar_t * const kEmptyFileAlias = L"[Content]";
+
+
+//////////////////////////////////////////////////////////////
+// Archive Open callback class
+
+
+class CArchiveOpenCallback Z7_final:
+ public IArchiveOpenCallback,
+ public ICryptoGetTextPassword,
+ public CMyUnknownImp
+{
+ Z7_IFACES_IMP_UNK_2(IArchiveOpenCallback, ICryptoGetTextPassword)
+public:
+
+ bool PasswordIsDefined;
+ UString Password;
+
+ CArchiveOpenCallback() : PasswordIsDefined(false) {}
+};
+
+Z7_COM7F_IMF(CArchiveOpenCallback::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */))
+{
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveOpenCallback::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */))
+{
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveOpenCallback::CryptoGetTextPassword(BSTR *password))
+{
+ if (!PasswordIsDefined)
+ {
+ // You can ask real password here from user
+ // Password = GetPassword(OutStream);
+ // PasswordIsDefined = true;
+ PrintError("Password is not defined");
+ return E_ABORT;
+ }
+ return StringToBstr(Password, password);
+}
+
+
+
+static const char * const kIncorrectCommand = "incorrect command";
+
+//////////////////////////////////////////////////////////////
+// Archive Extracting callback class
+
+static const char * const kTestingString = "Testing ";
+static const char * const kExtractingString = "Extracting ";
+static const char * const kSkippingString = "Skipping ";
+static const char * const kReadingString = "Reading ";
+
+static const char * const kUnsupportedMethod = "Unsupported Method";
+static const char * const kCRCFailed = "CRC Failed";
+static const char * const kDataError = "Data Error";
+static const char * const kUnavailableData = "Unavailable data";
+static const char * const kUnexpectedEnd = "Unexpected end of data";
+static const char * const kDataAfterEnd = "There are some data after the end of the payload data";
+static const char * const kIsNotArc = "Is not archive";
+static const char * const kHeadersError = "Headers Error";
+
+
+struct CArcTime
+{
+ FILETIME FT;
+ UInt16 Prec;
+ Byte Ns100;
+ bool Def;
+
+ CArcTime()
+ {
+ Clear();
+ }
+
+ void Clear()
+ {
+ FT.dwHighDateTime = FT.dwLowDateTime = 0;
+ Prec = 0;
+ Ns100 = 0;
+ Def = false;
+ }
+
+ bool IsZero() const
+ {
+ return FT.dwLowDateTime == 0 && FT.dwHighDateTime == 0 && Ns100 == 0;
+ }
+
+ int GetNumDigits() const
+ {
+ if (Prec == k_PropVar_TimePrec_Unix ||
+ Prec == k_PropVar_TimePrec_DOS)
+ return 0;
+ if (Prec == k_PropVar_TimePrec_HighPrec)
+ return 9;
+ if (Prec == k_PropVar_TimePrec_0)
+ return 7;
+ int digits = (int)Prec - (int)k_PropVar_TimePrec_Base;
+ if (digits < 0)
+ digits = 0;
+ return digits;
+ }
+
+ void Write_To_FiTime(CFiTime &dest) const
+ {
+ #ifdef _WIN32
+ dest = FT;
+ #else
+ if (FILETIME_To_timespec(FT, dest))
+ if ((Prec == k_PropVar_TimePrec_Base + 8 ||
+ Prec == k_PropVar_TimePrec_Base + 9)
+ && Ns100 != 0)
+ {
+ dest.tv_nsec += Ns100;
+ }
+ #endif
+ }
+
+ void Set_From_Prop(const PROPVARIANT &prop)
+ {
+ FT = prop.filetime;
+ unsigned prec = 0;
+ unsigned ns100 = 0;
+ const unsigned prec_Temp = prop.wReserved1;
+ if (prec_Temp != 0
+ && prec_Temp <= k_PropVar_TimePrec_1ns
+ && prop.wReserved3 == 0)
+ {
+ const unsigned ns100_Temp = prop.wReserved2;
+ if (ns100_Temp < 100)
+ {
+ ns100 = ns100_Temp;
+ prec = prec_Temp;
+ }
+ }
+ Prec = (UInt16)prec;
+ Ns100 = (Byte)ns100;
+ Def = true;
+ }
+};
+
+
+
+class CArchiveExtractCallback Z7_final:
+ public IArchiveExtractCallback,
+ public ICryptoGetTextPassword,
+ public CMyUnknownImp
+{
+ Z7_IFACES_IMP_UNK_2(IArchiveExtractCallback, ICryptoGetTextPassword)
+ Z7_IFACE_COM7_IMP(IProgress)
+
+ CMyComPtr<IInArchive> _archiveHandler;
+ FString _directoryPath; // Output directory
+ UString _filePath; // name inside arcvhive
+ FString _diskFilePath; // full path to file on disk
+ bool _extractMode;
+ struct CProcessedFileInfo
+ {
+ CArcTime MTime;
+ UInt32 Attrib;
+ bool isDir;
+ bool Attrib_Defined;
+ } _processedFileInfo;
+
+ COutFileStream *_outFileStreamSpec;
+ CMyComPtr<ISequentialOutStream> _outFileStream;
+
+public:
+ void Init(IInArchive *archiveHandler, const FString &directoryPath);
+
+ UInt64 NumErrors;
+ bool PasswordIsDefined;
+ UString Password;
+
+ CArchiveExtractCallback() : PasswordIsDefined(false) {}
+};
+
+void CArchiveExtractCallback::Init(IInArchive *archiveHandler, const FString &directoryPath)
+{
+ NumErrors = 0;
+ _archiveHandler = archiveHandler;
+ _directoryPath = directoryPath;
+ NName::NormalizeDirPathPrefix(_directoryPath);
+}
+
+Z7_COM7F_IMF(CArchiveExtractCallback::SetTotal(UInt64 /* size */))
+{
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveExtractCallback::SetCompleted(const UInt64 * /* completeValue */))
+{
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index,
+ ISequentialOutStream **outStream, Int32 askExtractMode))
+{
+ *outStream = NULL;
+ _outFileStream.Release();
+
+ {
+ // Get Name
+ NCOM::CPropVariant prop;
+ RINOK(_archiveHandler->GetProperty(index, kpidPath, &prop))
+
+ UString fullPath;
+ if (prop.vt == VT_EMPTY)
+ fullPath = kEmptyFileAlias;
+ else
+ {
+ if (prop.vt != VT_BSTR)
+ return E_FAIL;
+ fullPath = prop.bstrVal;
+ }
+ _filePath = fullPath;
+ }
+
+ if (askExtractMode != NArchive::NExtract::NAskMode::kExtract)
+ return S_OK;
+
+ {
+ // Get Attrib
+ NCOM::CPropVariant prop;
+ RINOK(_archiveHandler->GetProperty(index, kpidAttrib, &prop))
+ if (prop.vt == VT_EMPTY)
+ {
+ _processedFileInfo.Attrib = 0;
+ _processedFileInfo.Attrib_Defined = false;
+ }
+ else
+ {
+ if (prop.vt != VT_UI4)
+ return E_FAIL;
+ _processedFileInfo.Attrib = prop.ulVal;
+ _processedFileInfo.Attrib_Defined = true;
+ }
+ }
+
+ RINOK(IsArchiveItemFolder(_archiveHandler, index, _processedFileInfo.isDir))
+
+ {
+ _processedFileInfo.MTime.Clear();
+ // Get Modified Time
+ NCOM::CPropVariant prop;
+ RINOK(_archiveHandler->GetProperty(index, kpidMTime, &prop))
+ switch (prop.vt)
+ {
+ case VT_EMPTY:
+ // _processedFileInfo.MTime = _utcMTimeDefault;
+ break;
+ case VT_FILETIME:
+ _processedFileInfo.MTime.Set_From_Prop(prop);
+ break;
+ default:
+ return E_FAIL;
+ }
+
+ }
+ {
+ // Get Size
+ NCOM::CPropVariant prop;
+ RINOK(_archiveHandler->GetProperty(index, kpidSize, &prop))
+ UInt64 newFileSize;
+ /* bool newFileSizeDefined = */ ConvertPropVariantToUInt64(prop, newFileSize);
+ }
+
+
+ {
+ // Create folders for file
+ int slashPos = _filePath.ReverseFind_PathSepar();
+ if (slashPos >= 0)
+ CreateComplexDir(_directoryPath + us2fs(_filePath.Left(slashPos)));
+ }
+
+ FString fullProcessedPath = _directoryPath + us2fs(_filePath);
+ _diskFilePath = fullProcessedPath;
+
+ if (_processedFileInfo.isDir)
+ {
+ CreateComplexDir(fullProcessedPath);
+ }
+ else
+ {
+ NFind::CFileInfo fi;
+ if (fi.Find(fullProcessedPath))
+ {
+ if (!DeleteFileAlways(fullProcessedPath))
+ {
+ PrintError("Cannot delete output file", fullProcessedPath);
+ return E_ABORT;
+ }
+ }
+
+ _outFileStreamSpec = new COutFileStream;
+ CMyComPtr<ISequentialOutStream> outStreamLoc(_outFileStreamSpec);
+ if (!_outFileStreamSpec->Open(fullProcessedPath, CREATE_ALWAYS))
+ {
+ PrintError("Cannot open output file", fullProcessedPath);
+ return E_ABORT;
+ }
+ _outFileStream = outStreamLoc;
+ *outStream = outStreamLoc.Detach();
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode))
+{
+ _extractMode = false;
+ switch (askExtractMode)
+ {
+ case NArchive::NExtract::NAskMode::kExtract: _extractMode = true; break;
+ }
+ switch (askExtractMode)
+ {
+ case NArchive::NExtract::NAskMode::kExtract: Print(kExtractingString); break;
+ case NArchive::NExtract::NAskMode::kTest: Print(kTestingString); break;
+ case NArchive::NExtract::NAskMode::kSkip: Print(kSkippingString); break;
+ case NArchive::NExtract::NAskMode::kReadExternal: Print(kReadingString); break;
+ default:
+ Print("??? "); break;
+ }
+ Print(_filePath);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 operationResult))
+{
+ switch (operationResult)
+ {
+ case NArchive::NExtract::NOperationResult::kOK:
+ break;
+ default:
+ {
+ NumErrors++;
+ Print(" : ");
+ const char *s = NULL;
+ switch (operationResult)
+ {
+ case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
+ s = kUnsupportedMethod;
+ break;
+ case NArchive::NExtract::NOperationResult::kCRCError:
+ s = kCRCFailed;
+ break;
+ case NArchive::NExtract::NOperationResult::kDataError:
+ s = kDataError;
+ break;
+ case NArchive::NExtract::NOperationResult::kUnavailable:
+ s = kUnavailableData;
+ break;
+ case NArchive::NExtract::NOperationResult::kUnexpectedEnd:
+ s = kUnexpectedEnd;
+ break;
+ case NArchive::NExtract::NOperationResult::kDataAfterEnd:
+ s = kDataAfterEnd;
+ break;
+ case NArchive::NExtract::NOperationResult::kIsNotArc:
+ s = kIsNotArc;
+ break;
+ case NArchive::NExtract::NOperationResult::kHeadersError:
+ s = kHeadersError;
+ break;
+ }
+ if (s)
+ {
+ Print("Error : ");
+ Print(s);
+ }
+ else
+ {
+ char temp[16];
+ ConvertUInt32ToString((UInt32)operationResult, temp);
+ Print("Error #");
+ Print(temp);
+ }
+ }
+ }
+
+ if (_outFileStream)
+ {
+ if (_processedFileInfo.MTime.Def)
+ {
+ CFiTime ft;
+ _processedFileInfo.MTime.Write_To_FiTime(ft);
+ _outFileStreamSpec->SetMTime(&ft);
+ }
+ RINOK(_outFileStreamSpec->Close())
+ }
+ _outFileStream.Release();
+ if (_extractMode && _processedFileInfo.Attrib_Defined)
+ SetFileAttrib_PosixHighDetect(_diskFilePath, _processedFileInfo.Attrib);
+ PrintNewLine();
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password))
+{
+ if (!PasswordIsDefined)
+ {
+ // You can ask real password here from user
+ // Password = GetPassword(OutStream);
+ // PasswordIsDefined = true;
+ PrintError("Password is not defined");
+ return E_ABORT;
+ }
+ return StringToBstr(Password, password);
+}
+
+
+
+//////////////////////////////////////////////////////////////
+// Archive Creating callback class
+
+struct CDirItem: public NWindows::NFile::NFind::CFileInfoBase
+{
+ UString Path_For_Handler;
+ FString FullPath; // for filesystem
+
+ CDirItem(const NWindows::NFile::NFind::CFileInfo &fi):
+ CFileInfoBase(fi)
+ {}
+};
+
+class CArchiveUpdateCallback Z7_final:
+ public IArchiveUpdateCallback2,
+ public ICryptoGetTextPassword2,
+ public CMyUnknownImp
+{
+ Z7_IFACES_IMP_UNK_2(IArchiveUpdateCallback2, ICryptoGetTextPassword2)
+ Z7_IFACE_COM7_IMP(IProgress)
+ Z7_IFACE_COM7_IMP(IArchiveUpdateCallback)
+
+public:
+ CRecordVector<UInt64> VolumesSizes;
+ UString VolName;
+ UString VolExt;
+
+ FString DirPrefix;
+ const CObjectVector<CDirItem> *DirItems;
+
+ bool PasswordIsDefined;
+ UString Password;
+ bool AskPassword;
+
+ bool m_NeedBeClosed;
+
+ FStringVector FailedFiles;
+ CRecordVector<HRESULT> FailedCodes;
+
+ CArchiveUpdateCallback():
+ DirItems(NULL),
+ PasswordIsDefined(false),
+ AskPassword(false)
+ {}
+
+ ~CArchiveUpdateCallback() { Finilize(); }
+ HRESULT Finilize();
+
+ void Init(const CObjectVector<CDirItem> *dirItems)
+ {
+ DirItems = dirItems;
+ m_NeedBeClosed = false;
+ FailedFiles.Clear();
+ FailedCodes.Clear();
+ }
+};
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::SetTotal(UInt64 /* size */))
+{
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::SetCompleted(const UInt64 * /* completeValue */))
+{
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 /* index */,
+ Int32 *newData, Int32 *newProperties, UInt32 *indexInArchive))
+{
+ if (newData)
+ *newData = BoolToInt(true);
+ if (newProperties)
+ *newProperties = BoolToInt(true);
+ if (indexInArchive)
+ *indexInArchive = (UInt32)(Int32)-1;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+
+ if (propID == kpidIsAnti)
+ {
+ prop = false;
+ prop.Detach(value);
+ return S_OK;
+ }
+
+ {
+ const CDirItem &di = (*DirItems)[index];
+ switch (propID)
+ {
+ case kpidPath: prop = di.Path_For_Handler; break;
+ case kpidIsDir: prop = di.IsDir(); break;
+ case kpidSize: prop = di.Size; break;
+ case kpidCTime: PropVariant_SetFrom_FiTime(prop, di.CTime); break;
+ case kpidATime: PropVariant_SetFrom_FiTime(prop, di.ATime); break;
+ case kpidMTime: PropVariant_SetFrom_FiTime(prop, di.MTime); break;
+ case kpidAttrib: prop = (UInt32)di.GetWinAttrib(); break;
+ case kpidPosixAttrib: prop = (UInt32)di.GetPosixAttrib(); break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+HRESULT CArchiveUpdateCallback::Finilize()
+{
+ if (m_NeedBeClosed)
+ {
+ PrintNewLine();
+ m_NeedBeClosed = false;
+ }
+ return S_OK;
+}
+
+static void GetStream2(const wchar_t *name)
+{
+ Print("Compressing ");
+ if (name[0] == 0)
+ name = kEmptyFileAlias;
+ Print(name);
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream))
+{
+ RINOK(Finilize())
+
+ const CDirItem &dirItem = (*DirItems)[index];
+ GetStream2(dirItem.Path_For_Handler);
+
+ if (dirItem.IsDir())
+ return S_OK;
+
+ {
+ CInFileStream *inStreamSpec = new CInFileStream;
+ CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
+ FString path = DirPrefix + dirItem.FullPath;
+ if (!inStreamSpec->Open(path))
+ {
+ const DWORD sysError = ::GetLastError();
+ FailedCodes.Add(HRESULT_FROM_WIN32(sysError));
+ FailedFiles.Add(path);
+ // if (systemError == ERROR_SHARING_VIOLATION)
+ {
+ PrintNewLine();
+ PrintError("WARNING: can't open file");
+ // Print(NError::MyFormatMessageW(systemError));
+ return S_FALSE;
+ }
+ // return sysError;
+ }
+ *inStream = inStreamLoc.Detach();
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::SetOperationResult(Int32 /* operationResult */))
+{
+ m_NeedBeClosed = true;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size))
+{
+ if (VolumesSizes.Size() == 0)
+ return S_FALSE;
+ if (index >= (UInt32)VolumesSizes.Size())
+ index = VolumesSizes.Size() - 1;
+ *size = VolumesSizes[index];
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream))
+{
+ wchar_t temp[16];
+ ConvertUInt32ToString(index + 1, temp);
+ UString res = temp;
+ while (res.Len() < 2)
+ res.InsertAtFront(L'0');
+ UString fileName = VolName;
+ fileName.Add_Dot();
+ fileName += res;
+ fileName += VolExt;
+ COutFileStream *streamSpec = new COutFileStream;
+ CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
+ if (!streamSpec->Create(us2fs(fileName), false))
+ return GetLastError_noZero_HRESULT();
+ *volumeStream = streamLoc.Detach();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password))
+{
+ if (!PasswordIsDefined)
+ {
+ if (AskPassword)
+ {
+ // You can ask real password here from user
+ // Password = GetPassword(OutStream);
+ // PasswordIsDefined = true;
+ PrintError("Password is not defined");
+ return E_ABORT;
+ }
+ }
+ *passwordIsDefined = BoolToInt(PasswordIsDefined);
+ return StringToBstr(Password, password);
+}
+
+
+// Main function
+
+#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE)
+#define NT_CHECK_FAIL_ACTION PrintError("Unsupported Windows version"); return 1;
+#endif
+
+int Z7_CDECL main(int numArgs, const char *args[])
+{
+ NT_CHECK
+
+ #ifdef ENV_HAVE_LOCALE
+ MY_SetLocale();
+ #endif
+
+ PrintStringLn(kCopyrightString);
+
+ if (numArgs < 2)
+ {
+ PrintStringLn(kHelpString);
+ return 0;
+ }
+
+ FString dllPrefix;
+
+ #ifdef _WIN32
+ dllPrefix = NDLL::GetModuleDirPrefix();
+ #else
+ {
+ AString s (args[0]);
+ int sep = s.ReverseFind_PathSepar();
+ s.DeleteFrom(sep + 1);
+ dllPrefix = s;
+ }
+ #endif
+
+ NDLL::CLibrary lib;
+ if (!lib.Load(dllPrefix + FTEXT(kDllName)))
+ {
+ PrintError("Cannot load 7-zip library");
+ return 1;
+ }
+
+ Func_CreateObject
+ f_CreateObject = Z7_GET_PROC_ADDRESS(
+ Func_CreateObject, lib.Get_HMODULE(),
+ "CreateObject");
+ if (!f_CreateObject)
+ {
+ PrintError("Cannot get CreateObject");
+ return 1;
+ }
+
+ char c = 0;
+ UString password;
+ bool passwordIsDefined = false;
+ CObjectVector<FString> params;
+
+ for (int curCmd = 1; curCmd < numArgs; curCmd++)
+ {
+ AString a(args[curCmd]);
+
+ if (!a.IsEmpty())
+ {
+ if (a[0] == '-')
+ {
+ if (!passwordIsDefined && a[1] == 'p')
+ {
+ password = GetUnicodeString(a.Ptr(2));
+ passwordIsDefined = true;
+ continue;
+ }
+ }
+ else
+ {
+ if (c)
+ {
+ params.Add(CmdStringToFString(a));
+ continue;
+ }
+ if (a.Len() == 1)
+ {
+ c = (char)MyCharLower_Ascii(a[0]);
+ continue;
+ }
+ }
+ }
+ {
+ PrintError(kIncorrectCommand);
+ return 1;
+ }
+ }
+
+ if (!c || params.Size() < 1)
+ {
+ PrintError(kIncorrectCommand);
+ return 1;
+ }
+
+ const FString &archiveName = params[0];
+
+ if (c == 'a')
+ {
+ // create archive command
+ if (params.Size() < 2)
+ {
+ PrintError(kIncorrectCommand);
+ return 1;
+ }
+ CObjectVector<CDirItem> dirItems;
+ {
+ unsigned i;
+ for (i = 1; i < params.Size(); i++)
+ {
+ const FString &name = params[i];
+
+ NFind::CFileInfo fi;
+ if (!fi.Find(name))
+ {
+ PrintError("Can't find file", name);
+ return 1;
+ }
+
+ CDirItem di(fi);
+
+ di.Path_For_Handler = fs2us(name);
+ di.FullPath = name;
+ dirItems.Add(di);
+ }
+ }
+
+ COutFileStream *outFileStreamSpec = new COutFileStream;
+ CMyComPtr<IOutStream> outFileStream = outFileStreamSpec;
+ if (!outFileStreamSpec->Create(archiveName, false))
+ {
+ PrintError("can't create archive file");
+ return 1;
+ }
+
+ CMyComPtr<IOutArchive> outArchive;
+ if (f_CreateObject(&CLSID_Format, &IID_IOutArchive, (void **)&outArchive) != S_OK)
+ {
+ PrintError("Cannot get class object");
+ return 1;
+ }
+
+ CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+ CMyComPtr<IArchiveUpdateCallback2> updateCallback(updateCallbackSpec);
+ updateCallbackSpec->Init(&dirItems);
+ updateCallbackSpec->PasswordIsDefined = passwordIsDefined;
+ updateCallbackSpec->Password = password;
+
+ /*
+ {
+ const wchar_t *names[] =
+ {
+ L"m",
+ L"s",
+ L"x"
+ };
+ const unsigned kNumProps = Z7_ARRAY_SIZE(names);
+ NCOM::CPropVariant values[kNumProps] =
+ {
+ L"lzma",
+ false, // solid mode OFF
+ (UInt32)9 // compression level = 9 - ultra
+ };
+ CMyComPtr<ISetProperties> setProperties;
+ outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties);
+ if (!setProperties)
+ {
+ PrintError("ISetProperties unsupported");
+ return 1;
+ }
+ if (setProperties->SetProperties(names, values, kNumProps) != S_OK)
+ {
+ PrintError("SetProperties() error");
+ return 1;
+ }
+ }
+ */
+
+ HRESULT result = outArchive->UpdateItems(outFileStream, dirItems.Size(), updateCallback);
+
+ updateCallbackSpec->Finilize();
+
+ if (result != S_OK)
+ {
+ PrintError("Update Error");
+ return 1;
+ }
+
+ FOR_VECTOR (i, updateCallbackSpec->FailedFiles)
+ {
+ PrintNewLine();
+ PrintError("Error for file", updateCallbackSpec->FailedFiles[i]);
+ }
+
+ if (updateCallbackSpec->FailedFiles.Size() != 0)
+ return 1;
+ }
+ else
+ {
+ if (params.Size() != 1)
+ {
+ PrintError(kIncorrectCommand);
+ return 1;
+ }
+
+ bool listCommand;
+
+ if (c == 'l')
+ listCommand = true;
+ else if (c == 'x')
+ listCommand = false;
+ else
+ {
+ PrintError(kIncorrectCommand);
+ return 1;
+ }
+
+ CMyComPtr<IInArchive> archive;
+ if (f_CreateObject(&CLSID_Format, &IID_IInArchive, (void **)&archive) != S_OK)
+ {
+ PrintError("Cannot get class object");
+ return 1;
+ }
+
+ CInFileStream *fileSpec = new CInFileStream;
+ CMyComPtr<IInStream> file = fileSpec;
+
+ if (!fileSpec->Open(archiveName))
+ {
+ PrintError("Cannot open archive file", archiveName);
+ return 1;
+ }
+
+ {
+ CArchiveOpenCallback *openCallbackSpec = new CArchiveOpenCallback;
+ CMyComPtr<IArchiveOpenCallback> openCallback(openCallbackSpec);
+ openCallbackSpec->PasswordIsDefined = passwordIsDefined;
+ openCallbackSpec->Password = password;
+
+ const UInt64 scanSize = 1 << 23;
+ if (archive->Open(file, &scanSize, openCallback) != S_OK)
+ {
+ PrintError("Cannot open file as archive", archiveName);
+ return 1;
+ }
+ }
+
+ if (listCommand)
+ {
+ // List command
+ UInt32 numItems = 0;
+ archive->GetNumberOfItems(&numItems);
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ {
+ // Get uncompressed size of file
+ NCOM::CPropVariant prop;
+ archive->GetProperty(i, kpidSize, &prop);
+ char s[32];
+ ConvertPropVariantToShortString(prop, s);
+ Print(s);
+ Print(" ");
+ }
+ {
+ // Get name of file
+ NCOM::CPropVariant prop;
+ archive->GetProperty(i, kpidPath, &prop);
+ if (prop.vt == VT_BSTR)
+ Print(prop.bstrVal);
+ else if (prop.vt != VT_EMPTY)
+ Print("ERROR!");
+ }
+ PrintNewLine();
+ }
+ }
+ else
+ {
+ // Extract command
+ CArchiveExtractCallback *extractCallbackSpec = new CArchiveExtractCallback;
+ CMyComPtr<IArchiveExtractCallback> extractCallback(extractCallbackSpec);
+ extractCallbackSpec->Init(archive, FString()); // second parameter is output folder path
+ extractCallbackSpec->PasswordIsDefined = passwordIsDefined;
+ extractCallbackSpec->Password = password;
+
+ /*
+ const wchar_t *names[] =
+ {
+ L"mt",
+ L"mtf"
+ };
+ const unsigned kNumProps = sizeof(names) / sizeof(names[0]);
+ NCOM::CPropVariant values[kNumProps] =
+ {
+ (UInt32)1,
+ false
+ };
+ CMyComPtr<ISetProperties> setProperties;
+ archive->QueryInterface(IID_ISetProperties, (void **)&setProperties);
+ if (setProperties)
+ {
+ if (setProperties->SetProperties(names, values, kNumProps) != S_OK)
+ {
+ PrintError("SetProperties() error");
+ return 1;
+ }
+ }
+ */
+
+ HRESULT result = archive->Extract(NULL, (UInt32)(Int32)(-1), false, extractCallback);
+
+ if (result != S_OK)
+ {
+ PrintError("Extract Error");
+ return 1;
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/CPP/7zip/UI/Client7z/Client7z.dsp b/CPP/7zip/UI/Client7z/Client7z.dsp
index d9ec4ca..d46300f 100644
--- a/CPP/7zip/UI/Client7z/Client7z.dsp
+++ b/CPP/7zip/UI/Client7z/Client7z.dsp
@@ -1,235 +1,327 @@
-# Microsoft Developer Studio Project File - Name="Client7z" - Package Owner=<4>
-# Microsoft Developer Studio Generated Build File, Format Version 6.00
-# ** DO NOT EDIT **
-
-# TARGTYPE "Win32 (x86) Console Application" 0x0103
-
-CFG=Client7z - Win32 Debug
-!MESSAGE This is not a valid makefile. To build this project using NMAKE,
-!MESSAGE use the Export Makefile command and run
-!MESSAGE
-!MESSAGE NMAKE /f "Client7z.mak".
-!MESSAGE
-!MESSAGE You can specify a configuration when running NMAKE
-!MESSAGE by defining the macro CFG on the command line. For example:
-!MESSAGE
-!MESSAGE NMAKE /f "Client7z.mak" CFG="Client7z - Win32 Debug"
-!MESSAGE
-!MESSAGE Possible choices for configuration are:
-!MESSAGE
-!MESSAGE "Client7z - Win32 Release" (based on "Win32 (x86) Console Application")
-!MESSAGE "Client7z - Win32 Debug" (based on "Win32 (x86) Console Application")
-!MESSAGE
-
-# Begin Project
-# PROP AllowPerConfigDependencies 0
-# PROP Scc_ProjName ""
-# PROP Scc_LocalPath ""
-CPP=cl.exe
-RSC=rc.exe
-
-!IF "$(CFG)" == "Client7z - Win32 Release"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 0
-# PROP BASE Output_Dir "Release"
-# PROP BASE Intermediate_Dir "Release"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 0
-# PROP Output_Dir "Release"
-# PROP Intermediate_Dir "Release"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
-# ADD CPP /nologo /MD /W4 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
-# ADD BASE RSC /l 0x419 /d "NDEBUG"
-# ADD RSC /l 0x419 /d "NDEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"Release/7zcl.exe"
-
-!ELSEIF "$(CFG)" == "Client7z - Win32 Debug"
-
-# PROP BASE Use_MFC 0
-# PROP BASE Use_Debug_Libraries 1
-# PROP BASE Output_Dir "Debug"
-# PROP BASE Intermediate_Dir "Debug"
-# PROP BASE Target_Dir ""
-# PROP Use_MFC 0
-# PROP Use_Debug_Libraries 1
-# PROP Output_Dir "Debug"
-# PROP Intermediate_Dir "Debug"
-# PROP Ignore_Export_Lib 0
-# PROP Target_Dir ""
-# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
-# ADD CPP /nologo /MDd /W4 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
-# ADD BASE RSC /l 0x419 /d "_DEBUG"
-# ADD RSC /l 0x419 /d "_DEBUG"
-BSC32=bscmake.exe
-# ADD BASE BSC32 /nologo
-# ADD BSC32 /nologo
-LINK32=link.exe
-# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
-# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/7zcl.exe" /pdbtype:sept
-
-!ENDIF
-
-# Begin Target
-
-# Name "Client7z - Win32 Release"
-# Name "Client7z - Win32 Debug"
-# Begin Group "Spec"
-
-# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
-# Begin Source File
-
-SOURCE=.\resource.rc
-# End Source File
-# Begin Source File
-
-SOURCE=.\StdAfx.cpp
-# ADD CPP /Yc"stdafx.h"
-# End Source File
-# Begin Source File
-
-SOURCE=.\StdAfx.h
-# End Source File
-# End Group
-# Begin Group "Windows"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\Windows\DLL.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\DLL.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileDir.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileDir.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileFind.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileFind.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileIO.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileIO.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileName.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\FileName.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariant.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariant.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariantConv.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Windows\PropVariantConv.h
-# End Source File
-# End Group
-# Begin Group "Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\..\Common\IntToString.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\IntToString.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyString.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyString.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyVector.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\MyVector.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\NewHandler.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\NewHandler.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StringConvert.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\StringConvert.h
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\Wildcard.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\Common\Wildcard.h
-# End Source File
-# End Group
-# Begin Group "7zip Common"
-
-# PROP Default_Filter ""
-# Begin Source File
-
-SOURCE=..\..\Common\FileStreams.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\Common\FileStreams.h
-# End Source File
-# End Group
-# Begin Source File
-
-SOURCE=.\Client7z.cpp
-# End Source File
-# Begin Source File
-
-SOURCE=..\..\..\..\C\Sort.h
-# End Source File
-# End Target
-# End Project
+# Microsoft Developer Studio Project File - Name="Client7z" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=Client7z - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "Client7z.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "Client7z.mak" CFG="Client7z - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Client7z - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "Client7z - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "Client7z - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
+# ADD CPP /nologo /MD /W4 /WX /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"Release/7zcl.exe"
+
+!ELSEIF "$(CFG)" == "Client7z - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
+# ADD CPP /nologo /MDd /W4 /WX /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"Debug/7zcl.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "Client7z - Win32 Release"
+# Name "Client7z - Win32 Debug"
+# Begin Group "Spec"
+
+# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"stdafx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\NtCheck.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\TimeUtils.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\Common.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyCom.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyInitGuid.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyLinux.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.h
+# End Source File
+# End Group
+# Begin Group "7zip Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\UniqBlocks.h
+# End Source File
+# End Group
+# Begin Group "C"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zVersion.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.h
+# End Source File
+# End Group
+# Begin Group "7zip"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\IDecl.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IPassword.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IProgress.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\PropID.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\Client7z.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\IArchive.h
+# End Source File
+# End Target
+# End Project
diff --git a/CPP/7zip/UI/Client7z/Client7z.dsw b/CPP/7zip/UI/Client7z/Client7z.dsw
index 4c26851..598a6d3 100644
--- a/CPP/7zip/UI/Client7z/Client7z.dsw
+++ b/CPP/7zip/UI/Client7z/Client7z.dsw
@@ -1,29 +1,29 @@
-Microsoft Developer Studio Workspace File, Format Version 6.00
-# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
-
-###############################################################################
-
-Project: "Client7z"=.\Client7z.dsp - Package Owner=<4>
-
-Package=<5>
-{{{
-}}}
-
-Package=<4>
-{{{
-}}}
-
-###############################################################################
-
-Global:
-
-Package=<5>
-{{{
-}}}
-
-Package=<3>
-{{{
-}}}
-
-###############################################################################
-
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "Client7z"=.\Client7z.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/UI/Client7z/StdAfx.cpp b/CPP/7zip/UI/Client7z/StdAfx.cpp
index c6d3b1f..d0feea8 100644
--- a/CPP/7zip/UI/Client7z/StdAfx.cpp
+++ b/CPP/7zip/UI/Client7z/StdAfx.cpp
@@ -1,3 +1,3 @@
-// StdAfx.cpp
-
-#include "StdAfx.h"
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/UI/Client7z/StdAfx.h b/CPP/7zip/UI/Client7z/StdAfx.h
index 59d9ac1..035267c 100644
--- a/CPP/7zip/UI/Client7z/StdAfx.h
+++ b/CPP/7zip/UI/Client7z/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "../../../Common/Common.h"
-
-#endif
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/UI/Client7z/makefile b/CPP/7zip/UI/Client7z/makefile
index 9f68f16..988701e 100644
--- a/CPP/7zip/UI/Client7z/makefile
+++ b/CPP/7zip/UI/Client7z/makefile
@@ -1,28 +1,28 @@
-PROG = 7zcl.exe
-MY_CONSOLE = 1
-
-CURRENT_OBJS = \
- $O\Client7z.obj \
-
-COMMON_OBJS = \
- $O\IntToString.obj \
- $O\NewHandler.obj \
- $O\MyString.obj \
- $O\StringConvert.obj \
- $O\StringToInt.obj \
- $O\MyVector.obj \
- $O\Wildcard.obj \
-
-WIN_OBJS = \
- $O\DLL.obj \
- $O\FileDir.obj \
- $O\FileFind.obj \
- $O\FileIO.obj \
- $O\FileName.obj \
- $O\PropVariant.obj \
- $O\PropVariantConv.obj \
-
-7ZIP_COMMON_OBJS = \
- $O\FileStreams.obj \
-
-!include "../../7zip.mak"
+PROG = 7zcl.exe
+MY_CONSOLE = 1
+
+CURRENT_OBJS = \
+ $O\Client7z.obj \
+
+COMMON_OBJS = \
+ $O\IntToString.obj \
+ $O\NewHandler.obj \
+ $O\MyString.obj \
+ $O\MyVector.obj \
+ $O\StringConvert.obj \
+ $O\StringToInt.obj \
+ $O\Wildcard.obj \
+
+WIN_OBJS = \
+ $O\DLL.obj \
+ $O\FileDir.obj \
+ $O\FileFind.obj \
+ $O\FileIO.obj \
+ $O\FileName.obj \
+ $O\PropVariant.obj \
+ $O\PropVariantConv.obj \
+
+7ZIP_COMMON_OBJS = \
+ $O\FileStreams.obj \
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/UI/Client7z/makefile.gcc b/CPP/7zip/UI/Client7z/makefile.gcc
new file mode 100644
index 0000000..3f97205
--- /dev/null
+++ b/CPP/7zip/UI/Client7z/makefile.gcc
@@ -0,0 +1,69 @@
+PROG = 7zcl
+IS_NOT_STANDALONE = 1
+
+# IS_X64 = 1
+
+
+
+ifdef SystemDrive
+IS_MINGW = 1
+else
+ifdef SYSTEMDRIVE
+# ifdef OS
+IS_MINGW = 1
+endif
+endif
+
+
+ifdef IS_MINGW
+
+SYS_OBJS = \
+ $O/resource.o \
+
+else
+
+SYS_OBJS = \
+ $O/MyWindows.o \
+ $O/TimeUtils.o \
+
+endif
+
+
+LOCAL_FLAGS = \
+
+
+CURRENT_OBJS = \
+ $O/Client7z.o \
+
+COMMON_OBJS = \
+ $O/IntToString.o \
+ $O/MyString.o \
+ $O/MyVector.o \
+ $O/NewHandler.o \
+ $O/StringConvert.o \
+ $O/StringToInt.o \
+ $O/UTFConvert.o \
+ $O/Wildcard.o \
+
+WIN_OBJS = \
+ $O/DLL.o \
+ $O/FileDir.o \
+ $O/FileFind.o \
+ $O/FileIO.o \
+ $O/FileName.o \
+ $O/PropVariant.o \
+ $O/PropVariantConv.o \
+
+7ZIP_COMMON_OBJS = \
+ $O/FileStreams.o \
+
+
+OBJS = \
+ $(COMMON_OBJS) \
+ $(WIN_OBJS) \
+ $(SYS_OBJS) \
+ $(7ZIP_COMMON_OBJS) \
+ $(CURRENT_OBJS) \
+
+
+include ../../7zip_gcc.mak
diff --git a/CPP/7zip/UI/Client7z/resource.rc b/CPP/7zip/UI/Client7z/resource.rc
index 701a783..462df6f 100644
--- a/CPP/7zip/UI/Client7z/resource.rc
+++ b/CPP/7zip/UI/Client7z/resource.rc
@@ -1,3 +1,3 @@
-#include "../../MyVersionInfo.rc"
-
-MY_VERSION_INFO_APP("7-Zip client" , "7zcl")
+#include "../../MyVersionInfo.rc"
+
+MY_VERSION_INFO_APP("7-Zip client" , "7zcl")
diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
index 35dbd74..2bdbc41 100644
--- a/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
+++ b/CPP/7zip/UI/Common/ArchiveCommandLine.cpp
@@ -1,1295 +1,1700 @@
-// ArchiveCommandLine.cpp
-
-#include "StdAfx.h"
-#undef printf
-#undef sprintf
-
-#ifdef _WIN32
-#ifndef UNDER_CE
-#include <io.h>
-#endif
-#else
-// for isatty()
-#include <unistd.h>
-#endif
-
-#include <stdio.h>
-
-#ifdef _7ZIP_LARGE_PAGES
-#include "../../../../C/Alloc.h"
-#endif
-
-#include "../../../Common/ListFileUtils.h"
-#include "../../../Common/StringConvert.h"
-#include "../../../Common/StringToInt.h"
-
-#include "../../../Windows/ErrorMsg.h"
-#include "../../../Windows/FileDir.h"
-#include "../../../Windows/FileName.h"
-#ifdef _WIN32
-#include "../../../Windows/FileMapping.h"
-#include "../../../Windows/MemoryLock.h"
-#include "../../../Windows/Synchronization.h"
-#endif
-
-#include "ArchiveCommandLine.h"
-#include "EnumDirItems.h"
-#include "Update.h"
-#include "UpdateAction.h"
-
-extern bool g_CaseSensitive;
-extern bool g_PathTrailReplaceMode;
-
-#ifdef _7ZIP_LARGE_PAGES
-bool g_LargePagesMode = false;
-#endif
-
-#ifdef UNDER_CE
-
-#define MY_IS_TERMINAL(x) false;
-
-#else
-
-#if _MSC_VER >= 1400
-#define MY_isatty_fileno(x) _isatty(_fileno(x))
-#else
-#define MY_isatty_fileno(x) isatty(fileno(x))
-#endif
-
-#define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0);
-
-#endif
-
-using namespace NCommandLineParser;
-using namespace NWindows;
-using namespace NFile;
-
-static bool StringToUInt32(const wchar_t *s, UInt32 &v)
-{
- if (*s == 0)
- return false;
- const wchar_t *end;
- v = ConvertStringToUInt32(s, &end);
- return *end == 0;
-}
-
-
-int g_CodePage = -1;
-
-namespace NKey {
-enum Enum
-{
- kHelp1 = 0,
- kHelp2,
- kHelp3,
-
- kDisableHeaders,
- kDisablePercents,
- kShowTime,
- kLogLevel,
-
- kOutStream,
- kErrStream,
- kPercentStream,
-
- kYes,
-
- kShowDialog,
- kOverwrite,
-
- kArchiveType,
- kExcludedArcType,
-
- kProperty,
- kOutputDir,
- kWorkingDir,
-
- kInclude,
- kExclude,
- kArInclude,
- kArExclude,
- kNoArName,
-
- kUpdate,
- kVolume,
- kRecursed,
-
- kAffinity,
- kSfx,
- kEmail,
- kHash,
-
- kStdIn,
- kStdOut,
-
- kLargePages,
- kListfileCharSet,
- kConsoleCharSet,
- kTechMode,
-
- kShareForWrite,
- kStopAfterOpenError,
- kCaseSensitive,
- kArcNameMode,
-
- kDisableWildcardParsing,
- kElimDup,
- kFullPathMode,
-
- kHardLinks,
- kSymLinks,
- kNtSecurity,
-
- kAltStreams,
- kReplaceColonForAltStream,
- kWriteToAltStreamIfColon,
-
- kNameTrailReplace,
-
- kDeleteAfterCompressing,
- kSetArcMTime
-
- #ifndef _NO_CRYPTO
- , kPassword
- #endif
-};
-
-}
-
-
-static const wchar_t kRecursedIDChar = 'r';
-static const char * const kRecursedPostCharSet = "0-";
-
-static const char * const k_ArcNameMode_PostCharSet = "sea";
-
-static const char * const k_Stream_PostCharSet = "012";
-
-static inline const EArcNameMode ParseArcNameMode(int postCharIndex)
-{
- switch (postCharIndex)
- {
- case 1: return k_ArcNameMode_Exact;
- case 2: return k_ArcNameMode_Add;
- default: return k_ArcNameMode_Smart;
- }
-}
-
-namespace NRecursedPostCharIndex {
- enum EEnum
- {
- kWildcardRecursionOnly = 0,
- kNoRecursion = 1
- };
-}
-
-static const char kImmediateNameID = '!';
-static const char kMapNameID = '#';
-static const char kFileListID = '@';
-
-static const char kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be
-static const char kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be
-
-static const char * const kOverwritePostCharSet = "asut";
-
-static const NExtract::NOverwriteMode::EEnum k_OverwriteModes[] =
-{
- NExtract::NOverwriteMode::kOverwrite,
- NExtract::NOverwriteMode::kSkip,
- NExtract::NOverwriteMode::kRename,
- NExtract::NOverwriteMode::kRenameExisting
-};
-
-static const CSwitchForm kSwitchForms[] =
-{
- { "?" },
- { "h" },
- { "-help" },
-
- { "ba" },
- { "bd" },
- { "bt" },
- { "bb", NSwitchType::kString, false, 0 },
-
- { "bso", NSwitchType::kChar, false, 1, k_Stream_PostCharSet },
- { "bse", NSwitchType::kChar, false, 1, k_Stream_PostCharSet },
- { "bsp", NSwitchType::kChar, false, 1, k_Stream_PostCharSet },
-
- { "y" },
-
- { "ad" },
- { "ao", NSwitchType::kChar, false, 1, kOverwritePostCharSet},
-
- { "t", NSwitchType::kString, false, 1 },
- { "stx", NSwitchType::kString, true, 1 },
-
- { "m", NSwitchType::kString, true, 1 },
- { "o", NSwitchType::kString, false, 1 },
- { "w", NSwitchType::kString },
-
- { "i", NSwitchType::kString, true, kSomeCludePostStringMinSize},
- { "x", NSwitchType::kString, true, kSomeCludePostStringMinSize},
- { "ai", NSwitchType::kString, true, kSomeCludePostStringMinSize},
- { "ax", NSwitchType::kString, true, kSomeCludePostStringMinSize},
- { "an" },
-
- { "u", NSwitchType::kString, true, 1},
- { "v", NSwitchType::kString, true, 1},
- { "r", NSwitchType::kChar, false, 0, kRecursedPostCharSet },
-
- { "stm", NSwitchType::kString },
- { "sfx", NSwitchType::kString },
- { "seml", NSwitchType::kString, false, 0},
- { "scrc", NSwitchType::kString, true, 0 },
-
- { "si", NSwitchType::kString },
- { "so" },
-
- { "slp", NSwitchType::kString },
- { "scs", NSwitchType::kString },
- { "scc", NSwitchType::kString },
- { "slt" },
-
- { "ssw" },
- { "sse" },
- { "ssc", NSwitchType::kMinus },
- { "sa", NSwitchType::kChar, false, 1, k_ArcNameMode_PostCharSet },
-
- { "spd" },
- { "spe", NSwitchType::kMinus },
- { "spf", NSwitchType::kString, false, 0 },
-
- { "snh", NSwitchType::kMinus },
- { "snl", NSwitchType::kMinus },
- { "sni" },
-
- { "sns", NSwitchType::kMinus },
- { "snr" },
- { "snc" },
-
- { "snt", NSwitchType::kMinus },
-
- { "sdel" },
- { "stl" }
-
- #ifndef _NO_CRYPTO
- , { "p", NSwitchType::kString }
- #endif
-};
-
-static const char * const kUniversalWildcard = "*";
-static const unsigned kMinNonSwitchWords = 1;
-static const unsigned kCommandIndex = 0;
-
-// static const char * const kUserErrorMessage = "Incorrect command line";
-static const char * const kCannotFindListFile = "Cannot find listfile";
-static const char * const kIncorrectListFile = "Incorrect item in listfile.\nCheck charset encoding and -scs switch.";
-static const char * const kTerminalOutError = "I won't write compressed data to a terminal";
-static const char * const kSameTerminalError = "I won't write data and program's messages to same stream";
-static const char * const kEmptyFilePath = "Empty file path";
-
-bool CArcCommand::IsFromExtractGroup() const
-{
- switch (CommandType)
- {
- case NCommandType::kTest:
- case NCommandType::kExtract:
- case NCommandType::kExtractFull:
- return true;
- }
- return false;
-}
-
-NExtract::NPathMode::EEnum CArcCommand::GetPathMode() const
-{
- switch (CommandType)
- {
- case NCommandType::kTest:
- case NCommandType::kExtractFull:
- return NExtract::NPathMode::kFullPaths;
- }
- return NExtract::NPathMode::kNoPaths;
-}
-
-bool CArcCommand::IsFromUpdateGroup() const
-{
- switch (CommandType)
- {
- case NCommandType::kAdd:
- case NCommandType::kUpdate:
- case NCommandType::kDelete:
- case NCommandType::kRename:
- return true;
- }
- return false;
-}
-
-static NRecursedType::EEnum GetRecursedTypeFromIndex(int index)
-{
- switch (index)
- {
- case NRecursedPostCharIndex::kWildcardRecursionOnly:
- return NRecursedType::kWildcardOnlyRecursed;
- case NRecursedPostCharIndex::kNoRecursion:
- return NRecursedType::kNonRecursed;
- default:
- return NRecursedType::kRecursed;
- }
-}
-
-static const char *g_Commands = "audtexlbih";
-
-static bool ParseArchiveCommand(const UString &commandString, CArcCommand &command)
-{
- UString s (commandString);
- s.MakeLower_Ascii();
- if (s.Len() == 1)
- {
- if (s[0] > 0x7F)
- return false;
- int index = FindCharPosInString(g_Commands, (char)s[0]);
- if (index < 0)
- return false;
- command.CommandType = (NCommandType::EEnum)index;
- return true;
- }
- if (s.Len() == 2 && s[0] == 'r' && s[1] == 'n')
- {
- command.CommandType = (NCommandType::kRename);
- return true;
- }
- return false;
-}
-
-// ------------------------------------------------------------------
-// filenames functions
-
-static void AddNameToCensor(NWildcard::CCensor &censor,
- const UString &name, bool include, NRecursedType::EEnum type, bool wildcardMatching)
-{
- bool recursed = false;
-
- switch (type)
- {
- case NRecursedType::kWildcardOnlyRecursed:
- recursed = DoesNameContainWildcard(name);
- break;
- case NRecursedType::kRecursed:
- recursed = true;
- break;
- }
- censor.AddPreItem(include, name, recursed, wildcardMatching);
-}
-
-static void AddRenamePair(CObjectVector<CRenamePair> *renamePairs,
- const UString &oldName, const UString &newName, NRecursedType::EEnum type,
- bool wildcardMatching)
-{
- CRenamePair &pair = renamePairs->AddNew();
- pair.OldName = oldName;
- pair.NewName = newName;
- pair.RecursedType = type;
- pair.WildcardParsing = wildcardMatching;
-
- if (!pair.Prepare())
- {
- UString val;
- val += pair.OldName;
- val.Add_LF();
- val += pair.NewName;
- val.Add_LF();
- if (type == NRecursedType::kRecursed)
- val += "-r";
- else if (type == NRecursedType::kWildcardOnlyRecursed)
- val += "-r0";
- throw CArcCmdLineException("Unsupported rename command:", val);
- }
-}
-
-static void AddToCensorFromListFile(
- CObjectVector<CRenamePair> *renamePairs,
- NWildcard::CCensor &censor,
- LPCWSTR fileName, bool include, NRecursedType::EEnum type, bool wildcardMatching, Int32 codePage)
-{
- UStringVector names;
- if (!NFind::DoesFileExist(us2fs(fileName)))
- throw CArcCmdLineException(kCannotFindListFile, fileName);
- DWORD lastError = 0;
- if (!ReadNamesFromListFile2(us2fs(fileName), names, codePage, lastError))
- {
- if (lastError != 0)
- {
- UString m;
- m = "The file operation error for listfile";
- m.Add_LF();
- m += NError::MyFormatMessage(lastError);
- throw CArcCmdLineException(m, fileName);
- }
- throw CArcCmdLineException(kIncorrectListFile, fileName);
- }
- if (renamePairs)
- {
- if ((names.Size() & 1) != 0)
- throw CArcCmdLineException(kIncorrectListFile, fileName);
- for (unsigned i = 0; i < names.Size(); i += 2)
- {
- // change type !!!!
- AddRenamePair(renamePairs, names[i], names[i + 1], type, wildcardMatching);
- }
- }
- else
- FOR_VECTOR (i, names)
- AddNameToCensor(censor, names[i], include, type, wildcardMatching);
-}
-
-static void AddToCensorFromNonSwitchesStrings(
- CObjectVector<CRenamePair> *renamePairs,
- unsigned startIndex,
- NWildcard::CCensor &censor,
- const UStringVector &nonSwitchStrings,
- int stopSwitchIndex,
- NRecursedType::EEnum type,
- bool wildcardMatching,
- bool thereAreSwitchIncludes, Int32 codePage)
-{
- if ((renamePairs || nonSwitchStrings.Size() == startIndex) && !thereAreSwitchIncludes)
- AddNameToCensor(censor, UString(kUniversalWildcard), true, type,
- true // wildcardMatching
- );
-
- int oldIndex = -1;
-
- if (stopSwitchIndex < 0)
- stopSwitchIndex = nonSwitchStrings.Size();
-
- for (unsigned i = startIndex; i < nonSwitchStrings.Size(); i++)
- {
- const UString &s = nonSwitchStrings[i];
- if (s.IsEmpty())
- throw CArcCmdLineException(kEmptyFilePath);
- if (i < (unsigned)stopSwitchIndex && s[0] == kFileListID)
- AddToCensorFromListFile(renamePairs, censor, s.Ptr(1), true, type, wildcardMatching, codePage);
- else if (renamePairs)
- {
- if (oldIndex == -1)
- oldIndex = i;
- else
- {
- // NRecursedType::EEnum type is used for global wildcard (-i! switches)
- AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, NRecursedType::kNonRecursed, wildcardMatching);
- // AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, type);
- oldIndex = -1;
- }
- }
- else
- AddNameToCensor(censor, s, true, type, wildcardMatching);
- }
-
- if (oldIndex != -1)
- {
- throw CArcCmdLineException("There is no second file name for rename pair:", nonSwitchStrings[oldIndex]);
- }
-}
-
-#ifdef _WIN32
-
-struct CEventSetEnd
-{
- UString Name;
-
- CEventSetEnd(const wchar_t *name): Name(name) {}
- ~CEventSetEnd()
- {
- NSynchronization::CManualResetEvent event;
- if (event.Open(EVENT_MODIFY_STATE, false, GetSystemString(Name)) == 0)
- event.Set();
- }
-};
-
-static const char * const k_IncorrectMapCommand = "Incorrect Map command";
-
-static const char *ParseMapWithPaths(
- NWildcard::CCensor &censor,
- const UString &s2, bool include,
- NRecursedType::EEnum commonRecursedType,
- bool wildcardMatching)
-{
- UString s (s2);
- int pos = s.Find(L':');
- if (pos < 0)
- return k_IncorrectMapCommand;
- int pos2 = s.Find(L':', pos + 1);
- if (pos2 < 0)
- return k_IncorrectMapCommand;
-
- CEventSetEnd eventSetEnd((const wchar_t *)s + ((unsigned)pos2 + 1));
- s.DeleteFrom(pos2);
- UInt32 size;
- if (!StringToUInt32(s.Ptr(pos + 1), size)
- || size < sizeof(wchar_t)
- || size > ((UInt32)1 << 31)
- || size % sizeof(wchar_t) != 0)
- return "Unsupported Map data size";
-
- s.DeleteFrom(pos);
- CFileMapping map;
- if (map.Open(FILE_MAP_READ, GetSystemString(s)) != 0)
- return "Can not open mapping";
- LPVOID data = map.Map(FILE_MAP_READ, 0, size);
- if (!data)
- return "MapViewOfFile error";
- CFileUnmapper unmapper(data);
-
- UString name;
- const wchar_t *p = (const wchar_t *)data;
- if (*p != 0) // data format marker
- return "Unsupported Map data";
- UInt32 numChars = size / sizeof(wchar_t);
- for (UInt32 i = 1; i < numChars; i++)
- {
- wchar_t c = p[i];
- if (c == 0)
- {
- // MessageBoxW(0, name, L"7-Zip", 0);
- AddNameToCensor(censor, name, include, commonRecursedType, wildcardMatching);
- name.Empty();
- }
- else
- name += c;
- }
- if (!name.IsEmpty())
- return "Map data error";
-
- return NULL;
-}
-
-#endif
-
-static void AddSwitchWildcardsToCensor(
- NWildcard::CCensor &censor,
- const UStringVector &strings, bool include,
- NRecursedType::EEnum commonRecursedType,
- bool wildcardMatching,
- Int32 codePage)
-{
- const char *errorMessage = NULL;
- unsigned i;
- for (i = 0; i < strings.Size(); i++)
- {
- const UString &name = strings[i];
- NRecursedType::EEnum recursedType;
- unsigned pos = 0;
-
- if (name.Len() < kSomeCludePostStringMinSize)
- {
- errorMessage = "Too short switch";
- break;
- }
-
- if (::MyCharLower_Ascii(name[pos]) == kRecursedIDChar)
- {
- pos++;
- wchar_t c = name[pos];
- int index = -1;
- if (c <= 0x7F)
- index = FindCharPosInString(kRecursedPostCharSet, (char)c);
- recursedType = GetRecursedTypeFromIndex(index);
- if (index >= 0)
- pos++;
- }
- else
- recursedType = commonRecursedType;
-
- if (name.Len() < pos + kSomeCludeAfterRecursedPostStringMinSize)
- {
- errorMessage = "Too short switch";
- break;
- }
-
- const UString tail = name.Ptr(pos + 1);
-
- if (name[pos] == kImmediateNameID)
- AddNameToCensor(censor, tail, include, recursedType, wildcardMatching);
- else if (name[pos] == kFileListID)
- AddToCensorFromListFile(NULL, censor, tail, include, recursedType, wildcardMatching, codePage);
- #ifdef _WIN32
- else if (name[pos] == kMapNameID)
- {
- errorMessage = ParseMapWithPaths(censor, tail, include, recursedType, wildcardMatching);
- if (errorMessage)
- break;
- }
- #endif
- else
- {
- errorMessage = "Incorrect wildcard type marker";
- break;
- }
- }
- if (i != strings.Size())
- throw CArcCmdLineException(errorMessage, strings[i]);
-}
-
-/*
-static NUpdateArchive::NPairAction::EEnum GetUpdatePairActionType(int i)
-{
- switch (i)
- {
- case NUpdateArchive::NPairAction::kIgnore: return NUpdateArchive::NPairAction::kIgnore;
- case NUpdateArchive::NPairAction::kCopy: return NUpdateArchive::NPairAction::kCopy;
- case NUpdateArchive::NPairAction::kCompress: return NUpdateArchive::NPairAction::kCompress;
- case NUpdateArchive::NPairAction::kCompressAsAnti: return NUpdateArchive::NPairAction::kCompressAsAnti;
- }
- throw 98111603;
-}
-*/
-
-static const char * const kUpdatePairStateIDSet = "pqrxyzw";
-static const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1};
-
-static const unsigned kNumUpdatePairActions = 4;
-static const char * const kUpdateIgnoreItselfPostStringID = "-";
-static const wchar_t kUpdateNewArchivePostCharID = '!';
-
-
-static bool ParseUpdateCommandString2(const UString &command,
- NUpdateArchive::CActionSet &actionSet, UString &postString)
-{
- for (unsigned i = 0; i < command.Len();)
- {
- wchar_t c = MyCharLower_Ascii(command[i]);
- int statePos = FindCharPosInString(kUpdatePairStateIDSet, (char)c);
- if (c > 0x7F || statePos < 0)
- {
- postString = command.Ptr(i);
- return true;
- }
- i++;
- if (i >= command.Len())
- return false;
- c = command[i];
- if (c < '0' || c >= '0' + kNumUpdatePairActions)
- return false;
- unsigned actionPos = c - '0';
- actionSet.StateActions[(unsigned)statePos] = (NUpdateArchive::NPairAction::EEnum)(actionPos);
- if (kUpdatePairStateNotSupportedActions[(unsigned)statePos] == (int)actionPos)
- return false;
- i++;
- }
- postString.Empty();
- return true;
-}
-
-static void ParseUpdateCommandString(CUpdateOptions &options,
- const UStringVector &updatePostStrings,
- const NUpdateArchive::CActionSet &defaultActionSet)
-{
- const char *errorMessage = "incorrect update switch command";
- unsigned i;
- for (i = 0; i < updatePostStrings.Size(); i++)
- {
- const UString &updateString = updatePostStrings[i];
- if (updateString.IsEqualTo(kUpdateIgnoreItselfPostStringID))
- {
- if (options.UpdateArchiveItself)
- {
- options.UpdateArchiveItself = false;
- options.Commands.Delete(0);
- }
- }
- else
- {
- NUpdateArchive::CActionSet actionSet = defaultActionSet;
-
- UString postString;
- if (!ParseUpdateCommandString2(updateString, actionSet, postString))
- break;
- if (postString.IsEmpty())
- {
- if (options.UpdateArchiveItself)
- options.Commands[0].ActionSet = actionSet;
- }
- else
- {
- if (postString[0] != kUpdateNewArchivePostCharID)
- break;
- CUpdateArchiveCommand uc;
- UString archivePath = postString.Ptr(1);
- if (archivePath.IsEmpty())
- break;
- uc.UserArchivePath = archivePath;
- uc.ActionSet = actionSet;
- options.Commands.Add(uc);
- }
- }
- }
- if (i != updatePostStrings.Size())
- throw CArcCmdLineException(errorMessage, updatePostStrings[i]);
-}
-
-bool ParseComplexSize(const wchar_t *s, UInt64 &result);
-
-static void SetAddCommandOptions(
- NCommandType::EEnum commandType,
- const CParser &parser,
- CUpdateOptions &options)
-{
- NUpdateArchive::CActionSet defaultActionSet;
- switch (commandType)
- {
- case NCommandType::kAdd:
- defaultActionSet = NUpdateArchive::k_ActionSet_Add;
- break;
- case NCommandType::kDelete:
- defaultActionSet = NUpdateArchive::k_ActionSet_Delete;
- break;
- default:
- defaultActionSet = NUpdateArchive::k_ActionSet_Update;
- }
-
- options.UpdateArchiveItself = true;
-
- options.Commands.Clear();
- CUpdateArchiveCommand updateMainCommand;
- updateMainCommand.ActionSet = defaultActionSet;
- options.Commands.Add(updateMainCommand);
- if (parser[NKey::kUpdate].ThereIs)
- ParseUpdateCommandString(options, parser[NKey::kUpdate].PostStrings,
- defaultActionSet);
- if (parser[NKey::kWorkingDir].ThereIs)
- {
- const UString &postString = parser[NKey::kWorkingDir].PostStrings[0];
- if (postString.IsEmpty())
- NDir::MyGetTempPath(options.WorkingDir);
- else
- options.WorkingDir = us2fs(postString);
- }
- options.SfxMode = parser[NKey::kSfx].ThereIs;
- if (options.SfxMode)
- options.SfxModule = us2fs(parser[NKey::kSfx].PostStrings[0]);
-
- if (parser[NKey::kVolume].ThereIs)
- {
- const UStringVector &sv = parser[NKey::kVolume].PostStrings;
- FOR_VECTOR (i, sv)
- {
- UInt64 size;
- if (!ParseComplexSize(sv[i], size) || size == 0)
- throw CArcCmdLineException("Incorrect volume size:", sv[i]);
- options.VolumesSizes.Add(size);
- }
- }
-}
-
-static void SetMethodOptions(const CParser &parser, CObjectVector<CProperty> &properties)
-{
- if (parser[NKey::kProperty].ThereIs)
- {
- FOR_VECTOR (i, parser[NKey::kProperty].PostStrings)
- {
- CProperty prop;
- prop.Name = parser[NKey::kProperty].PostStrings[i];
- int index = prop.Name.Find(L'=');
- if (index >= 0)
- {
- prop.Value = prop.Name.Ptr(index + 1);
- prop.Name.DeleteFrom(index);
- }
- properties.Add(prop);
- }
- }
-}
-
-
-static inline void SetStreamMode(const CSwitchResult &sw, unsigned &res)
-{
- if (sw.ThereIs)
- res = sw.PostCharIndex;
-}
-
-
-void CArcCmdLineParser::Parse1(const UStringVector &commandStrings,
- CArcCmdLineOptions &options)
-{
- if (!parser.ParseStrings(kSwitchForms, ARRAY_SIZE(kSwitchForms), commandStrings))
- throw CArcCmdLineException(parser.ErrorMessage, parser.ErrorLine);
-
- options.IsInTerminal = MY_IS_TERMINAL(stdin);
- options.IsStdOutTerminal = MY_IS_TERMINAL(stdout);
- options.IsStdErrTerminal = MY_IS_TERMINAL(stderr);
-
- options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs || parser[NKey::kHelp3].ThereIs;
-
- options.StdInMode = parser[NKey::kStdIn].ThereIs;
- options.StdOutMode = parser[NKey::kStdOut].ThereIs;
- options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs;
- options.TechMode = parser[NKey::kTechMode].ThereIs;
- options.ShowTime = parser[NKey::kShowTime].ThereIs;
-
- if (parser[NKey::kDisablePercents].ThereIs
- || options.StdOutMode
- || !options.IsStdOutTerminal)
- options.Number_for_Percents = k_OutStream_disabled;
-
- if (options.StdOutMode)
- options.Number_for_Out = k_OutStream_disabled;
-
- SetStreamMode(parser[NKey::kOutStream], options.Number_for_Out);
- SetStreamMode(parser[NKey::kErrStream], options.Number_for_Errors);
- SetStreamMode(parser[NKey::kPercentStream], options.Number_for_Percents);
-
- if (parser[NKey::kLogLevel].ThereIs)
- {
- const UString &s = parser[NKey::kLogLevel].PostStrings[0];
- if (s.IsEmpty())
- options.LogLevel = 1;
- else
- {
- UInt32 v;
- if (!StringToUInt32(s, v))
- throw CArcCmdLineException("Unsupported switch postfix -bb", s);
- options.LogLevel = (unsigned)v;
- }
- }
-
- if (parser[NKey::kCaseSensitive].ThereIs)
- {
- g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus;
- options.CaseSensitiveChange = true;
- options.CaseSensitive = g_CaseSensitive;
- }
-
-
- #if defined(_WIN32) && !defined(UNDER_CE)
- NSecurity::EnablePrivilege_SymLink();
- #endif
-
- // options.LargePages = false;
-
- if (parser[NKey::kLargePages].ThereIs)
- {
- unsigned slp = 0;
- const UString &s = parser[NKey::kLargePages].PostStrings[0];
- if (s.IsEmpty())
- slp = 1;
- else if (s != L"-")
- {
- if (!StringToUInt32(s, slp))
- throw CArcCmdLineException("Unsupported switch postfix for -slp", s);
- }
-
- #ifdef _7ZIP_LARGE_PAGES
- if (slp >
- #ifndef UNDER_CE
- (unsigned)NSecurity::Get_LargePages_RiskLevel()
- #else
- 0
- #endif
- )
- {
- SetLargePageSize();
- // note: this process also can inherit that Privilege from parent process
- g_LargePagesMode =
- #if defined(_WIN32) && !defined(UNDER_CE)
- NSecurity::EnablePrivilege_LockMemory();
- #else
- true;
- #endif
- }
- #endif
- }
-
-
- #ifndef UNDER_CE
-
- if (parser[NKey::kAffinity].ThereIs)
- {
- const UString &s = parser[NKey::kAffinity].PostStrings[0];
- if (!s.IsEmpty())
- {
- UInt32 v = 0;
- AString a;
- a.SetFromWStr_if_Ascii(s);
- if (!a.IsEmpty())
- {
- const char *end;
- v = ConvertHexStringToUInt32(a, &end);
- if (*end != 0)
- a.Empty();
- }
- if (a.IsEmpty())
- throw CArcCmdLineException("Unsupported switch postfix -stm", s);
-
- #ifdef _WIN32
- SetProcessAffinityMask(GetCurrentProcess(), v);
- #endif
- }
- }
-
- #endif
-}
-
-struct CCodePagePair
-{
- const char *Name;
- Int32 CodePage;
-};
-
-static const unsigned kNumByteOnlyCodePages = 3;
-
-static const CCodePagePair g_CodePagePairs[] =
-{
- { "utf-8", CP_UTF8 },
- { "win", CP_ACP },
- { "dos", CP_OEMCP },
- { "utf-16le", MY__CP_UTF16 },
- { "utf-16be", MY__CP_UTF16BE }
-};
-
-static Int32 FindCharset(const NCommandLineParser::CParser &parser, unsigned keyIndex,
- bool byteOnlyCodePages, Int32 defaultVal)
-{
- if (!parser[keyIndex].ThereIs)
- return defaultVal;
-
- UString name (parser[keyIndex].PostStrings.Back());
- UInt32 v;
- if (StringToUInt32(name, v))
- if (v < ((UInt32)1 << 16))
- return (Int32)v;
- name.MakeLower_Ascii();
- unsigned num = byteOnlyCodePages ? kNumByteOnlyCodePages : ARRAY_SIZE(g_CodePagePairs);
- for (unsigned i = 0;; i++)
- {
- if (i == num) // to disable warnings from different compilers
- throw CArcCmdLineException("Unsupported charset:", name);
- const CCodePagePair &pair = g_CodePagePairs[i];
- if (name.IsEqualTo(pair.Name))
- return pair.CodePage;
- }
-}
-
-
-static void SetBoolPair(NCommandLineParser::CParser &parser, unsigned switchID, CBoolPair &bp)
-{
- bp.Def = parser[switchID].ThereIs;
- if (bp.Def)
- bp.Val = !parser[switchID].WithMinus;
-}
-
-void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
-{
- const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
- const unsigned numNonSwitchStrings = nonSwitchStrings.Size();
- if (numNonSwitchStrings < kMinNonSwitchWords)
- throw CArcCmdLineException("The command must be specified");
-
- if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command))
- throw CArcCmdLineException("Unsupported command:", nonSwitchStrings[kCommandIndex]);
-
- if (parser[NKey::kHash].ThereIs)
- options.HashMethods = parser[NKey::kHash].PostStrings;
-
- if (parser[NKey::kElimDup].ThereIs)
- {
- options.ExtractOptions.ElimDup.Def = true;
- options.ExtractOptions.ElimDup.Val = !parser[NKey::kElimDup].WithMinus;
- }
-
- NWildcard::ECensorPathMode censorPathMode = NWildcard::k_RelatPath;
- bool fullPathMode = parser[NKey::kFullPathMode].ThereIs;
- if (fullPathMode)
- {
- censorPathMode = NWildcard::k_AbsPath;
- const UString &s = parser[NKey::kFullPathMode].PostStrings[0];
- if (!s.IsEmpty())
- {
- if (s == L"2")
- censorPathMode = NWildcard::k_FullPath;
- else
- throw CArcCmdLineException("Unsupported -spf:", s);
- }
- }
-
- if (parser[NKey::kNameTrailReplace].ThereIs)
- g_PathTrailReplaceMode = !parser[NKey::kNameTrailReplace].WithMinus;
-
- NRecursedType::EEnum recursedType;
- if (parser[NKey::kRecursed].ThereIs)
- recursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex);
- else
- recursedType = NRecursedType::kNonRecursed;
-
- bool wildcardMatching = true;
- if (parser[NKey::kDisableWildcardParsing].ThereIs)
- wildcardMatching = false;
-
- g_CodePage = FindCharset(parser, NKey::kConsoleCharSet, true, -1);
- Int32 codePage = FindCharset(parser, NKey::kListfileCharSet, false, CP_UTF8);
-
- bool thereAreSwitchIncludes = false;
-
- if (parser[NKey::kInclude].ThereIs)
- {
- thereAreSwitchIncludes = true;
- AddSwitchWildcardsToCensor(options.Censor,
- parser[NKey::kInclude].PostStrings, true, recursedType, wildcardMatching, codePage);
- }
-
- if (parser[NKey::kExclude].ThereIs)
- AddSwitchWildcardsToCensor(options.Censor,
- parser[NKey::kExclude].PostStrings, false, recursedType, wildcardMatching, codePage);
-
- unsigned curCommandIndex = kCommandIndex + 1;
- bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs &&
- options.Command.CommandType != NCommandType::kBenchmark &&
- options.Command.CommandType != NCommandType::kInfo &&
- options.Command.CommandType != NCommandType::kHash;
-
- bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
- bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList;
- bool isRename = options.Command.CommandType == NCommandType::kRename;
-
- if ((isExtractOrList || isRename) && options.StdInMode)
- thereIsArchiveName = false;
-
- if (parser[NKey::kArcNameMode].ThereIs)
- options.UpdateOptions.ArcNameMode = ParseArcNameMode(parser[NKey::kArcNameMode].PostCharIndex);
-
- if (thereIsArchiveName)
- {
- if (curCommandIndex >= numNonSwitchStrings)
- throw CArcCmdLineException("Cannot find archive name");
- options.ArchiveName = nonSwitchStrings[curCommandIndex++];
- if (options.ArchiveName.IsEmpty())
- throw CArcCmdLineException("Archive name cannot by empty");
- #ifdef _WIN32
- // options.ArchiveName.Replace(L'/', WCHAR_PATH_SEPARATOR);
- #endif
- }
-
- AddToCensorFromNonSwitchesStrings(isRename ? &options.UpdateOptions.RenamePairs : NULL,
- curCommandIndex, options.Censor,
- nonSwitchStrings, parser.StopSwitchIndex,
- recursedType, wildcardMatching,
- thereAreSwitchIncludes, codePage);
-
- options.YesToAll = parser[NKey::kYes].ThereIs;
-
-
- #ifndef _NO_CRYPTO
- options.PasswordEnabled = parser[NKey::kPassword].ThereIs;
- if (options.PasswordEnabled)
- options.Password = parser[NKey::kPassword].PostStrings[0];
- #endif
-
- options.ShowDialog = parser[NKey::kShowDialog].ThereIs;
-
- if (parser[NKey::kArchiveType].ThereIs)
- options.ArcType = parser[NKey::kArchiveType].PostStrings[0];
-
- options.ExcludedArcTypes = parser[NKey::kExcludedArcType].PostStrings;
-
- SetMethodOptions(parser, options.Properties);
-
- if (parser[NKey::kNtSecurity].ThereIs) options.NtSecurity.SetTrueTrue();
-
- SetBoolPair(parser, NKey::kAltStreams, options.AltStreams);
- SetBoolPair(parser, NKey::kHardLinks, options.HardLinks);
- SetBoolPair(parser, NKey::kSymLinks, options.SymLinks);
-
- if (isExtractOrList)
- {
- CExtractOptionsBase &eo = options.ExtractOptions;
-
- {
- CExtractNtOptions &nt = eo.NtOptions;
- nt.NtSecurity = options.NtSecurity;
-
- nt.AltStreams = options.AltStreams;
- if (!options.AltStreams.Def)
- nt.AltStreams.Val = true;
-
- nt.HardLinks = options.HardLinks;
- if (!options.HardLinks.Def)
- nt.HardLinks.Val = true;
-
- nt.SymLinks = options.SymLinks;
- if (!options.SymLinks.Def)
- nt.SymLinks.Val = true;
-
- nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs;
- nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs;
- }
-
- options.Censor.AddPathsToCensor(NWildcard::k_AbsPath);
- options.Censor.ExtendExclude();
-
- // are there paths that look as non-relative (!Prefix.IsEmpty())
- if (!options.Censor.AllAreRelative())
- throw CArcCmdLineException("Cannot use absolute pathnames for this command");
-
- NWildcard::CCensor &arcCensor = options.arcCensor;
-
- if (parser[NKey::kArInclude].ThereIs)
- AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArInclude].PostStrings, true, NRecursedType::kNonRecursed, wildcardMatching, codePage);
- if (parser[NKey::kArExclude].ThereIs)
- AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArExclude].PostStrings, false, NRecursedType::kNonRecursed, wildcardMatching, codePage);
-
- if (thereIsArchiveName)
- AddNameToCensor(arcCensor, options.ArchiveName, true, NRecursedType::kNonRecursed, wildcardMatching);
-
- arcCensor.AddPathsToCensor(NWildcard::k_RelatPath);
-
- #ifdef _WIN32
- ConvertToLongNames(arcCensor);
- #endif
-
- arcCensor.ExtendExclude();
-
- if (options.StdInMode)
- options.ArcName_for_StdInMode = parser[NKey::kStdIn].PostStrings.Front();
-
- if (isExtractGroupCommand)
- {
- if (options.StdOutMode)
- {
- if (
- options.Number_for_Percents == k_OutStream_stdout
- // || options.Number_for_Out == k_OutStream_stdout
- // || options.Number_for_Errors == k_OutStream_stdout
- ||
- (
- (options.IsStdOutTerminal && options.IsStdErrTerminal)
- &&
- (
- options.Number_for_Percents != k_OutStream_disabled
- // || options.Number_for_Out != k_OutStream_disabled
- // || options.Number_for_Errors != k_OutStream_disabled
- )
- )
- )
- throw CArcCmdLineException(kSameTerminalError);
- }
-
- if (parser[NKey::kOutputDir].ThereIs)
- {
- eo.OutputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]);
- NFile::NName::NormalizeDirPathPrefix(eo.OutputDir);
- }
-
- eo.OverwriteMode = NExtract::NOverwriteMode::kAsk;
- if (parser[NKey::kOverwrite].ThereIs)
- {
- eo.OverwriteMode = k_OverwriteModes[(unsigned)parser[NKey::kOverwrite].PostCharIndex];
- eo.OverwriteMode_Force = true;
- }
- else if (options.YesToAll)
- {
- eo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite;
- eo.OverwriteMode_Force = true;
- }
- }
-
- eo.PathMode = options.Command.GetPathMode();
- if (censorPathMode == NWildcard::k_AbsPath)
- {
- eo.PathMode = NExtract::NPathMode::kAbsPaths;
- eo.PathMode_Force = true;
- }
- else if (censorPathMode == NWildcard::k_FullPath)
- {
- eo.PathMode = NExtract::NPathMode::kFullPaths;
- eo.PathMode_Force = true;
- }
- }
- else if (options.Command.IsFromUpdateGroup())
- {
- if (parser[NKey::kArInclude].ThereIs)
- throw CArcCmdLineException("-ai switch is not supported for this command");
-
- CUpdateOptions &updateOptions = options.UpdateOptions;
-
- SetAddCommandOptions(options.Command.CommandType, parser, updateOptions);
-
- updateOptions.MethodMode.Properties = options.Properties;
-
- if (parser[NKey::kShareForWrite].ThereIs)
- updateOptions.OpenShareForWrite = true;
- if (parser[NKey::kStopAfterOpenError].ThereIs)
- updateOptions.StopAfterOpenError = true;
-
- updateOptions.PathMode = censorPathMode;
-
- updateOptions.AltStreams = options.AltStreams;
- updateOptions.NtSecurity = options.NtSecurity;
- updateOptions.HardLinks = options.HardLinks;
- updateOptions.SymLinks = options.SymLinks;
-
- updateOptions.EMailMode = parser[NKey::kEmail].ThereIs;
- if (updateOptions.EMailMode)
- {
- updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front();
- if (updateOptions.EMailAddress.Len() > 0)
- if (updateOptions.EMailAddress[0] == L'.')
- {
- updateOptions.EMailRemoveAfter = true;
- updateOptions.EMailAddress.Delete(0);
- }
- }
-
- updateOptions.StdOutMode = options.StdOutMode;
- updateOptions.StdInMode = options.StdInMode;
-
- updateOptions.DeleteAfterCompressing = parser[NKey::kDeleteAfterCompressing].ThereIs;
- updateOptions.SetArcMTime = parser[NKey::kSetArcMTime].ThereIs;
-
- if (updateOptions.StdOutMode && updateOptions.EMailMode)
- throw CArcCmdLineException("stdout mode and email mode cannot be combined");
-
- if (updateOptions.StdOutMode)
- {
- if (options.IsStdOutTerminal)
- throw CArcCmdLineException(kTerminalOutError);
-
- if (options.Number_for_Percents == k_OutStream_stdout
- || options.Number_for_Out == k_OutStream_stdout
- || options.Number_for_Errors == k_OutStream_stdout)
- throw CArcCmdLineException(kSameTerminalError);
- }
-
- if (updateOptions.StdInMode)
- updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front();
-
- if (options.Command.CommandType == NCommandType::kRename)
- if (updateOptions.Commands.Size() != 1)
- throw CArcCmdLineException("Only one archive can be created with rename command");
- }
- else if (options.Command.CommandType == NCommandType::kBenchmark)
- {
- options.NumIterations = 1;
- if (curCommandIndex < numNonSwitchStrings)
- {
- if (!StringToUInt32(nonSwitchStrings[curCommandIndex], options.NumIterations))
- throw CArcCmdLineException("Incorrect Number of benmchmark iterations", nonSwitchStrings[curCommandIndex]);
- curCommandIndex++;
- }
- }
- else if (options.Command.CommandType == NCommandType::kHash)
- {
- options.Censor.AddPathsToCensor(censorPathMode);
- options.Censor.ExtendExclude();
-
- CHashOptions &hashOptions = options.HashOptions;
- hashOptions.PathMode = censorPathMode;
- hashOptions.Methods = options.HashMethods;
- if (parser[NKey::kShareForWrite].ThereIs)
- hashOptions.OpenShareForWrite = true;
- hashOptions.StdInMode = options.StdInMode;
- hashOptions.AltStreamsMode = options.AltStreams.Val;
- }
- else if (options.Command.CommandType == NCommandType::kInfo)
- {
- }
- else
- throw 20150919;
-}
+// ArchiveCommandLine.cpp
+
+#include "StdAfx.h"
+#undef printf
+#undef sprintf
+
+#ifdef _WIN32
+#ifndef UNDER_CE
+#include <io.h>
+#endif
+#else
+// for isatty()
+#include <unistd.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef Z7_LARGE_PAGES
+#include "../../../../C/Alloc.h"
+#endif
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/ListFileUtils.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/System.h"
+#ifdef _WIN32
+#include "../../../Windows/FileMapping.h"
+#include "../../../Windows/MemoryLock.h"
+#include "../../../Windows/Synchronization.h"
+#endif
+
+#include "ArchiveCommandLine.h"
+#include "EnumDirItems.h"
+#include "Update.h"
+#include "UpdateAction.h"
+
+extern bool g_CaseSensitive;
+extern bool g_PathTrailReplaceMode;
+
+#ifdef Z7_LARGE_PAGES
+extern
+bool g_LargePagesMode;
+bool g_LargePagesMode = false;
+#endif
+
+/*
+#ifdef ENV_HAVE_LSTAT
+EXTERN_C_BEGIN
+extern int global_use_lstat;
+EXTERN_C_END
+#endif
+*/
+
+#ifdef UNDER_CE
+
+#define MY_IS_TERMINAL(x) false;
+
+#else
+
+// #define MY_isatty_fileno(x) (isatty(fileno(x)))
+// #define MY_IS_TERMINAL(x) (MY_isatty_fileno(x) != 0);
+static inline bool MY_IS_TERMINAL(FILE *x)
+{
+ return (
+ #if defined(_MSC_VER) && (_MSC_VER >= 1400)
+ _isatty(_fileno(x))
+ #else
+ isatty(fileno(x))
+ #endif
+ != 0);
+}
+
+#endif
+
+using namespace NCommandLineParser;
+using namespace NWindows;
+using namespace NFile;
+
+static bool StringToUInt32(const wchar_t *s, UInt32 &v)
+{
+ if (*s == 0)
+ return false;
+ const wchar_t *end;
+ v = ConvertStringToUInt32(s, &end);
+ return *end == 0;
+}
+
+
+namespace NKey {
+enum Enum
+{
+ kHelp1 = 0,
+ kHelp2,
+ kHelp3,
+
+ kDisableHeaders,
+ kDisablePercents,
+ kShowTime,
+ kLogLevel,
+
+ kOutStream,
+ kErrStream,
+ kPercentStream,
+
+ kYes,
+
+ kShowDialog,
+ kOverwrite,
+
+ kArchiveType,
+ kExcludedArcType,
+
+ kProperty,
+ kOutputDir,
+ kWorkingDir,
+
+ kInclude,
+ kExclude,
+ kArInclude,
+ kArExclude,
+ kNoArName,
+
+ kUpdate,
+ kVolume,
+ kRecursed,
+
+ kAffinity,
+ kSfx,
+ kEmail,
+ kHash,
+ // kHashGenFile,
+ kHashDir,
+
+ kStdIn,
+ kStdOut,
+
+ kLargePages,
+ kListfileCharSet,
+ kConsoleCharSet,
+ kTechMode,
+ kListFields,
+
+ kPreserveATime,
+ kShareForWrite,
+ kStopAfterOpenError,
+ kCaseSensitive,
+ kArcNameMode,
+
+ kUseSlashMark,
+ kDisableWildcardParsing,
+ kElimDup,
+ kFullPathMode,
+
+ kHardLinks,
+ kSymLinks_AllowDangerous,
+ kSymLinks,
+ kNtSecurity,
+
+ kStoreOwnerId,
+ kStoreOwnerName,
+
+ kZoneFile,
+ kAltStreams,
+ kReplaceColonForAltStream,
+ kWriteToAltStreamIfColon,
+
+ kNameTrailReplace,
+
+ kDeleteAfterCompressing,
+ kSetArcMTime
+
+ #ifndef Z7_NO_CRYPTO
+ , kPassword
+ #endif
+};
+
+}
+
+
+static const wchar_t kRecursedIDChar = 'r';
+static const char * const kRecursedPostCharSet = "0-";
+
+static const char * const k_ArcNameMode_PostCharSet = "sea";
+
+static const char * const k_Stream_PostCharSet = "012";
+
+static inline EArcNameMode ParseArcNameMode(int postCharIndex)
+{
+ switch (postCharIndex)
+ {
+ case 1: return k_ArcNameMode_Exact;
+ case 2: return k_ArcNameMode_Add;
+ default: return k_ArcNameMode_Smart;
+ }
+}
+
+namespace NRecursedPostCharIndex {
+ enum EEnum
+ {
+ kWildcardRecursionOnly = 0,
+ kNoRecursion = 1
+ };
+}
+
+// static const char
+#define kImmediateNameID '!'
+#ifdef _WIN32
+#define kMapNameID '#'
+#endif
+#define kFileListID '@'
+
+static const Byte kSomeCludePostStringMinSize = 2; // at least <@|!><N>ame must be
+static const Byte kSomeCludeAfterRecursedPostStringMinSize = 2; // at least <@|!><N>ame must be
+
+static const char * const kOverwritePostCharSet = "asut";
+
+static const NExtract::NOverwriteMode::EEnum k_OverwriteModes[] =
+{
+ NExtract::NOverwriteMode::kOverwrite,
+ NExtract::NOverwriteMode::kSkip,
+ NExtract::NOverwriteMode::kRename,
+ NExtract::NOverwriteMode::kRenameExisting
+};
+
+
+
+#define SWFRM_3(t, mu, mi) t, mu, mi, NULL
+
+#define SWFRM_1(t) SWFRM_3(t, false, 0)
+#define SWFRM_SIMPLE SWFRM_1(NSwitchType::kSimple)
+#define SWFRM_MINUS SWFRM_1(NSwitchType::kMinus)
+#define SWFRM_STRING SWFRM_1(NSwitchType::kString)
+
+#define SWFRM_STRING_SINGL(mi) SWFRM_3(NSwitchType::kString, false, mi)
+#define SWFRM_STRING_MULT(mi) SWFRM_3(NSwitchType::kString, true, mi)
+
+
+static const CSwitchForm kSwitchForms[] =
+{
+ { "?", SWFRM_SIMPLE },
+ { "h", SWFRM_SIMPLE },
+ { "-help", SWFRM_SIMPLE },
+
+ { "ba", SWFRM_SIMPLE },
+ { "bd", SWFRM_SIMPLE },
+ { "bt", SWFRM_SIMPLE },
+ { "bb", SWFRM_STRING_SINGL(0) },
+
+ { "bso", NSwitchType::kChar, false, 1, k_Stream_PostCharSet },
+ { "bse", NSwitchType::kChar, false, 1, k_Stream_PostCharSet },
+ { "bsp", NSwitchType::kChar, false, 1, k_Stream_PostCharSet },
+
+ { "y", SWFRM_SIMPLE },
+
+ { "ad", SWFRM_SIMPLE },
+ { "ao", NSwitchType::kChar, false, 1, kOverwritePostCharSet},
+
+ { "t", SWFRM_STRING_SINGL(1) },
+ { "stx", SWFRM_STRING_MULT(1) },
+
+ { "m", SWFRM_STRING_MULT(1) },
+ { "o", SWFRM_STRING_SINGL(1) },
+ { "w", SWFRM_STRING },
+
+ { "i", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) },
+ { "x", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) },
+ { "ai", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) },
+ { "ax", SWFRM_STRING_MULT(kSomeCludePostStringMinSize) },
+ { "an", SWFRM_SIMPLE },
+
+ { "u", SWFRM_STRING_MULT(1) },
+ { "v", SWFRM_STRING_MULT(1) },
+ { "r", NSwitchType::kChar, false, 0, kRecursedPostCharSet },
+
+ { "stm", SWFRM_STRING },
+ { "sfx", SWFRM_STRING },
+ { "seml", SWFRM_STRING_SINGL(0) },
+ { "scrc", SWFRM_STRING_MULT(0) },
+ // { "scrf", SWFRM_STRING_SINGL(1) },
+ { "shd", SWFRM_STRING_SINGL(1) },
+
+ { "si", SWFRM_STRING },
+ { "so", SWFRM_SIMPLE },
+
+ { "slp", SWFRM_STRING },
+ { "scs", SWFRM_STRING },
+ { "scc", SWFRM_STRING },
+ { "slt", SWFRM_SIMPLE },
+ { "slf", SWFRM_STRING_SINGL(1) },
+
+ { "ssp", SWFRM_SIMPLE },
+ { "ssw", SWFRM_SIMPLE },
+ { "sse", SWFRM_SIMPLE },
+ { "ssc", SWFRM_MINUS },
+ { "sa", NSwitchType::kChar, false, 1, k_ArcNameMode_PostCharSet },
+
+ { "spm", SWFRM_STRING_SINGL(0) },
+ { "spd", SWFRM_SIMPLE },
+ { "spe", SWFRM_MINUS },
+ { "spf", SWFRM_STRING_SINGL(0) },
+
+ { "snh", SWFRM_MINUS },
+ { "snld", SWFRM_MINUS },
+ { "snl", SWFRM_MINUS },
+ { "sni", SWFRM_SIMPLE },
+
+ { "snoi", SWFRM_MINUS },
+ { "snon", SWFRM_MINUS },
+
+ { "snz", SWFRM_STRING_SINGL(0) },
+ { "sns", SWFRM_MINUS },
+ { "snr", SWFRM_SIMPLE },
+ { "snc", SWFRM_SIMPLE },
+
+ { "snt", SWFRM_MINUS },
+
+ { "sdel", SWFRM_SIMPLE },
+ { "stl", SWFRM_SIMPLE }
+
+ #ifndef Z7_NO_CRYPTO
+ , { "p", SWFRM_STRING }
+ #endif
+};
+
+static const char * const kUniversalWildcard = "*";
+static const unsigned kMinNonSwitchWords = 1;
+static const unsigned kCommandIndex = 0;
+
+// static const char * const kUserErrorMessage = "Incorrect command line";
+// static const char * const kCannotFindListFile = "Cannot find listfile";
+static const char * const kIncorrectListFile = "Incorrect item in listfile.\nCheck charset encoding and -scs switch.";
+static const char * const kTerminalOutError = "I won't write compressed data to a terminal";
+static const char * const kSameTerminalError = "I won't write data and program's messages to same stream";
+static const char * const kEmptyFilePath = "Empty file path";
+
+bool CArcCommand::IsFromExtractGroup() const
+{
+ switch ((int)CommandType)
+ {
+ case NCommandType::kTest:
+ case NCommandType::kExtract:
+ case NCommandType::kExtractFull:
+ return true;
+ default:
+ return false;
+ }
+}
+
+NExtract::NPathMode::EEnum CArcCommand::GetPathMode() const
+{
+ switch ((int)CommandType)
+ {
+ case NCommandType::kTest:
+ case NCommandType::kExtractFull:
+ return NExtract::NPathMode::kFullPaths;
+ default:
+ return NExtract::NPathMode::kNoPaths;
+ }
+}
+
+bool CArcCommand::IsFromUpdateGroup() const
+{
+ switch ((int)CommandType)
+ {
+ case NCommandType::kAdd:
+ case NCommandType::kUpdate:
+ case NCommandType::kDelete:
+ case NCommandType::kRename:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static NRecursedType::EEnum GetRecursedTypeFromIndex(int index)
+{
+ switch (index)
+ {
+ case NRecursedPostCharIndex::kWildcardRecursionOnly:
+ return NRecursedType::kWildcardOnlyRecursed;
+ case NRecursedPostCharIndex::kNoRecursion:
+ return NRecursedType::kNonRecursed;
+ default:
+ return NRecursedType::kRecursed;
+ }
+}
+
+static const char *g_Commands = "audtexlbih";
+
+static bool ParseArchiveCommand(const UString &commandString, CArcCommand &command)
+{
+ UString s (commandString);
+ s.MakeLower_Ascii();
+ if (s.Len() == 1)
+ {
+ if (s[0] > 0x7F)
+ return false;
+ int index = FindCharPosInString(g_Commands, (char)s[0]);
+ if (index < 0)
+ return false;
+ command.CommandType = (NCommandType::EEnum)index;
+ return true;
+ }
+ if (s.Len() == 2 && s[0] == 'r' && s[1] == 'n')
+ {
+ command.CommandType = (NCommandType::kRename);
+ return true;
+ }
+ return false;
+}
+
+// ------------------------------------------------------------------
+// filenames functions
+
+struct CNameOption
+{
+ bool Include;
+ bool WildcardMatching;
+ Byte MarkMode;
+ NRecursedType::EEnum RecursedType;
+
+ CNameOption():
+ Include(true),
+ WildcardMatching(true),
+ MarkMode(NWildcard::kMark_FileOrDir),
+ RecursedType(NRecursedType::kNonRecursed)
+ {}
+};
+
+
+static void AddNameToCensor(NWildcard::CCensor &censor,
+ const CNameOption &nop, const UString &name)
+{
+ bool recursed = false;
+
+ switch ((int)nop.RecursedType)
+ {
+ case NRecursedType::kWildcardOnlyRecursed:
+ recursed = DoesNameContainWildcard(name);
+ break;
+ case NRecursedType::kRecursed:
+ recursed = true;
+ break;
+ default:
+ break;
+ }
+
+ NWildcard::CCensorPathProps props;
+ props.Recursive = recursed;
+ props.WildcardMatching = nop.WildcardMatching;
+ props.MarkMode = nop.MarkMode;
+ censor.AddPreItem(nop.Include, name, props);
+}
+
+static void AddRenamePair(CObjectVector<CRenamePair> *renamePairs,
+ const UString &oldName, const UString &newName, NRecursedType::EEnum type,
+ bool wildcardMatching)
+{
+ CRenamePair &pair = renamePairs->AddNew();
+ pair.OldName = oldName;
+ pair.NewName = newName;
+ pair.RecursedType = type;
+ pair.WildcardParsing = wildcardMatching;
+
+ if (!pair.Prepare())
+ {
+ UString val;
+ val += pair.OldName;
+ val.Add_LF();
+ val += pair.NewName;
+ val.Add_LF();
+ if (type == NRecursedType::kRecursed)
+ val += "-r";
+ else if (type == NRecursedType::kWildcardOnlyRecursed)
+ val += "-r0";
+ throw CArcCmdLineException("Unsupported rename command:", val);
+ }
+}
+
+static void AddToCensorFromListFile(
+ CObjectVector<CRenamePair> *renamePairs,
+ NWildcard::CCensor &censor,
+ const CNameOption &nop, LPCWSTR fileName, UInt32 codePage)
+{
+ UStringVector names;
+ /*
+ if (!NFind::DoesFileExist_FollowLink(us2fs(fileName)))
+ throw CArcCmdLineException(kCannotFindListFile, fileName);
+ */
+ DWORD lastError = 0;
+ if (!ReadNamesFromListFile2(us2fs(fileName), names, codePage, lastError))
+ {
+ if (lastError != 0)
+ {
+ UString m;
+ m = "The file operation error for listfile";
+ m.Add_LF();
+ m += NError::MyFormatMessage(lastError);
+ throw CArcCmdLineException(m, fileName);
+ }
+ throw CArcCmdLineException(kIncorrectListFile, fileName);
+ }
+ if (renamePairs)
+ {
+ if ((names.Size() & 1) != 0)
+ throw CArcCmdLineException(kIncorrectListFile, fileName);
+ for (unsigned i = 0; i < names.Size(); i += 2)
+ {
+ // change type !!!!
+ AddRenamePair(renamePairs, names[i], names[i + 1], nop.RecursedType, nop.WildcardMatching);
+ }
+ }
+ else
+ FOR_VECTOR (i, names)
+ AddNameToCensor(censor, nop, names[i]);
+}
+
+static void AddToCensorFromNonSwitchesStrings(
+ CObjectVector<CRenamePair> *renamePairs,
+ unsigned startIndex,
+ NWildcard::CCensor &censor,
+ const UStringVector &nonSwitchStrings,
+ int stopSwitchIndex,
+ const CNameOption &nop,
+ bool thereAreSwitchIncludes, UInt32 codePage)
+{
+ // another default
+ if ((renamePairs || nonSwitchStrings.Size() == startIndex) && !thereAreSwitchIncludes)
+ {
+ /* for rename command: -i switch sets the mask for archive item reading.
+ if (thereAreSwitchIncludes), { we don't use UniversalWildcard. }
+ also for non-rename command: we set UniversalWildcard, only if there are no nonSwitches. */
+ // we use default fileds in (CNameOption) for UniversalWildcard.
+ CNameOption nop2;
+ // recursive mode is not important for UniversalWildcard (*)
+ // nop2.RecursedType = nop.RecursedType; // we don't need it
+ /*
+ nop2.RecursedType = NRecursedType::kNonRecursed;
+ nop2.Include = true;
+ nop2.WildcardMatching = true;
+ nop2.MarkMode = NWildcard::kMark_FileOrDir;
+ */
+ AddNameToCensor(censor, nop2, UString(kUniversalWildcard));
+ }
+
+ int oldIndex = -1;
+
+ if (stopSwitchIndex < 0)
+ stopSwitchIndex = (int)nonSwitchStrings.Size();
+
+ for (unsigned i = startIndex; i < nonSwitchStrings.Size(); i++)
+ {
+ const UString &s = nonSwitchStrings[i];
+ if (s.IsEmpty())
+ throw CArcCmdLineException(kEmptyFilePath);
+ if (i < (unsigned)stopSwitchIndex && s[0] == kFileListID)
+ AddToCensorFromListFile(renamePairs, censor, nop, s.Ptr(1), codePage);
+ else if (renamePairs)
+ {
+ if (oldIndex == -1)
+ oldIndex = (int)i;
+ else
+ {
+ // NRecursedType::EEnum type is used for global wildcard (-i! switches)
+ AddRenamePair(renamePairs, nonSwitchStrings[(unsigned)oldIndex], s, NRecursedType::kNonRecursed, nop.WildcardMatching);
+ // AddRenamePair(renamePairs, nonSwitchStrings[oldIndex], s, type);
+ oldIndex = -1;
+ }
+ }
+ else
+ AddNameToCensor(censor, nop, s);
+ }
+
+ if (oldIndex != -1)
+ {
+ throw CArcCmdLineException("There is no second file name for rename pair:", nonSwitchStrings[(unsigned)oldIndex]);
+ }
+}
+
+#ifdef _WIN32
+
+struct CEventSetEnd
+{
+ UString Name;
+
+ CEventSetEnd(const wchar_t *name): Name(name) {}
+ ~CEventSetEnd()
+ {
+ NSynchronization::CManualResetEvent event;
+ if (event.Open(EVENT_MODIFY_STATE, false, GetSystemString(Name)) == 0)
+ event.Set();
+ }
+};
+
+static const char * const k_IncorrectMapCommand = "Incorrect Map command";
+
+static const char *ParseMapWithPaths(
+ NWildcard::CCensor &censor,
+ const UString &s2,
+ const CNameOption &nop)
+{
+ UString s (s2);
+ int pos = s.Find(L':');
+ if (pos < 0)
+ return k_IncorrectMapCommand;
+ int pos2 = s.Find(L':', (unsigned)(pos + 1));
+ if (pos2 < 0)
+ return k_IncorrectMapCommand;
+
+ CEventSetEnd eventSetEnd((const wchar_t *)s + (unsigned)(pos2 + 1));
+ s.DeleteFrom((unsigned)pos2);
+ UInt32 size;
+ if (!StringToUInt32(s.Ptr((unsigned)(pos + 1)), size)
+ || size < sizeof(wchar_t)
+ || size > ((UInt32)1 << 31)
+ || size % sizeof(wchar_t) != 0)
+ return "Unsupported Map data size";
+
+ s.DeleteFrom((unsigned)pos);
+ CFileMapping map;
+ if (map.Open(FILE_MAP_READ, GetSystemString(s)) != 0)
+ return "Cannot open mapping";
+ LPVOID data = map.Map(FILE_MAP_READ, 0, size);
+ if (!data)
+ return "MapViewOfFile error";
+ CFileUnmapper unmapper(data);
+
+ UString name;
+ const wchar_t *p = (const wchar_t *)data;
+ if (*p != 0) // data format marker
+ return "Unsupported Map data";
+ UInt32 numChars = size / sizeof(wchar_t);
+ for (UInt32 i = 1; i < numChars; i++)
+ {
+ wchar_t c = p[i];
+ if (c == 0)
+ {
+ // MessageBoxW(0, name, L"7-Zip", 0);
+ AddNameToCensor(censor, nop, name);
+ name.Empty();
+ }
+ else
+ name += c;
+ }
+ if (!name.IsEmpty())
+ return "Map data error";
+
+ return NULL;
+}
+
+#endif
+
+static void AddSwitchWildcardsToCensor(
+ NWildcard::CCensor &censor,
+ const UStringVector &strings,
+ const CNameOption &nop,
+ UInt32 codePage)
+{
+ const char *errorMessage = NULL;
+ unsigned i;
+ for (i = 0; i < strings.Size(); i++)
+ {
+ const UString &name = strings[i];
+ unsigned pos = 0;
+
+ if (name.Len() < kSomeCludePostStringMinSize)
+ {
+ errorMessage = "Too short switch";
+ break;
+ }
+
+ if (!nop.Include)
+ {
+ if (name.IsEqualTo_Ascii_NoCase("td"))
+ {
+ censor.ExcludeDirItems = true;
+ continue;
+ }
+ if (name.IsEqualTo_Ascii_NoCase("tf"))
+ {
+ censor.ExcludeFileItems = true;
+ continue;
+ }
+ }
+
+ CNameOption nop2 = nop;
+
+ bool type_WasUsed = false;
+ bool recursed_WasUsed = false;
+ bool matching_WasUsed = false;
+ bool error = false;
+
+ for (;;)
+ {
+ wchar_t c = ::MyCharLower_Ascii(name[pos]);
+ if (c == kRecursedIDChar)
+ {
+ if (recursed_WasUsed)
+ {
+ error = true;
+ break;
+ }
+ recursed_WasUsed = true;
+ pos++;
+ c = name[pos];
+ int index = -1;
+ if (c <= 0x7F)
+ index = FindCharPosInString(kRecursedPostCharSet, (char)c);
+ nop2.RecursedType = GetRecursedTypeFromIndex(index);
+ if (index >= 0)
+ {
+ pos++;
+ continue;
+ }
+ }
+
+ if (c == 'w')
+ {
+ if (matching_WasUsed)
+ {
+ error = true;
+ break;
+ }
+ matching_WasUsed = true;
+ nop2.WildcardMatching = true;
+ pos++;
+ if (name[pos] == '-')
+ {
+ nop2.WildcardMatching = false;
+ pos++;
+ }
+ }
+ else if (c == 'm')
+ {
+ if (type_WasUsed)
+ {
+ error = true;
+ break;
+ }
+ type_WasUsed = true;
+ pos++;
+ nop2.MarkMode = NWildcard::kMark_StrictFile;
+ c = name[pos];
+ if (c == '-')
+ {
+ nop2.MarkMode = NWildcard::kMark_FileOrDir;
+ pos++;
+ }
+ else if (c == '2')
+ {
+ nop2.MarkMode = NWildcard::kMark_StrictFile_IfWildcard;
+ pos++;
+ }
+ }
+ else
+ break;
+ }
+
+ if (error)
+ {
+ errorMessage = "inorrect switch";
+ break;
+ }
+
+ if (name.Len() < pos + kSomeCludeAfterRecursedPostStringMinSize)
+ {
+ errorMessage = "Too short switch";
+ break;
+ }
+
+ const UString tail = name.Ptr(pos + 1);
+
+ const wchar_t c = name[pos];
+
+ if (c == kImmediateNameID)
+ AddNameToCensor(censor, nop2, tail);
+ else if (c == kFileListID)
+ AddToCensorFromListFile(NULL, censor, nop2, tail, codePage);
+ #ifdef _WIN32
+ else if (c == kMapNameID)
+ {
+ errorMessage = ParseMapWithPaths(censor, tail, nop2);
+ if (errorMessage)
+ break;
+ }
+ #endif
+ else
+ {
+ errorMessage = "Incorrect wildcard type marker";
+ break;
+ }
+ }
+
+ if (i != strings.Size())
+ throw CArcCmdLineException(errorMessage, strings[i]);
+}
+
+/*
+static NUpdateArchive::NPairAction::EEnum GetUpdatePairActionType(int i)
+{
+ switch (i)
+ {
+ case NUpdateArchive::NPairAction::kIgnore: return NUpdateArchive::NPairAction::kIgnore;
+ case NUpdateArchive::NPairAction::kCopy: return NUpdateArchive::NPairAction::kCopy;
+ case NUpdateArchive::NPairAction::kCompress: return NUpdateArchive::NPairAction::kCompress;
+ case NUpdateArchive::NPairAction::kCompressAsAnti: return NUpdateArchive::NPairAction::kCompressAsAnti;
+ }
+ throw 98111603;
+}
+*/
+
+static const char * const kUpdatePairStateIDSet = "pqrxyzw";
+static const int kUpdatePairStateNotSupportedActions[] = {2, 2, 1, -1, -1, -1, -1};
+
+static const unsigned kNumUpdatePairActions = 4;
+static const char * const kUpdateIgnoreItselfPostStringID = "-";
+static const wchar_t kUpdateNewArchivePostCharID = '!';
+
+
+static bool ParseUpdateCommandString2(const UString &command,
+ NUpdateArchive::CActionSet &actionSet, UString &postString)
+{
+ for (unsigned i = 0; i < command.Len();)
+ {
+ wchar_t c = MyCharLower_Ascii(command[i]);
+ int statePos = FindCharPosInString(kUpdatePairStateIDSet, (char)c);
+ if (c > 0x7F || statePos < 0)
+ {
+ postString = command.Ptr(i);
+ return true;
+ }
+ i++;
+ if (i >= command.Len())
+ return false;
+ c = command[i];
+ if (c < '0' || c >= (wchar_t)('0' + kNumUpdatePairActions))
+ return false;
+ unsigned actionPos = (unsigned)(c - '0');
+ actionSet.StateActions[(unsigned)statePos] = (NUpdateArchive::NPairAction::EEnum)(actionPos);
+ if (kUpdatePairStateNotSupportedActions[(unsigned)statePos] == (int)actionPos)
+ return false;
+ i++;
+ }
+ postString.Empty();
+ return true;
+}
+
+static void ParseUpdateCommandString(CUpdateOptions &options,
+ const UStringVector &updatePostStrings,
+ const NUpdateArchive::CActionSet &defaultActionSet)
+{
+ const char *errorMessage = "incorrect update switch command";
+ unsigned i;
+ for (i = 0; i < updatePostStrings.Size(); i++)
+ {
+ const UString &updateString = updatePostStrings[i];
+ if (updateString.IsEqualTo(kUpdateIgnoreItselfPostStringID))
+ {
+ if (options.UpdateArchiveItself)
+ {
+ options.UpdateArchiveItself = false;
+ options.Commands.Delete(0);
+ }
+ }
+ else
+ {
+ NUpdateArchive::CActionSet actionSet = defaultActionSet;
+
+ UString postString;
+ if (!ParseUpdateCommandString2(updateString, actionSet, postString))
+ break;
+ if (postString.IsEmpty())
+ {
+ if (options.UpdateArchiveItself)
+ options.Commands[0].ActionSet = actionSet;
+ }
+ else
+ {
+ if (postString[0] != kUpdateNewArchivePostCharID)
+ break;
+ CUpdateArchiveCommand uc;
+ UString archivePath = postString.Ptr(1);
+ if (archivePath.IsEmpty())
+ break;
+ uc.UserArchivePath = archivePath;
+ uc.ActionSet = actionSet;
+ options.Commands.Add(uc);
+ }
+ }
+ }
+ if (i != updatePostStrings.Size())
+ throw CArcCmdLineException(errorMessage, updatePostStrings[i]);
+}
+
+bool ParseComplexSize(const wchar_t *s, UInt64 &result);
+
+static void SetAddCommandOptions(
+ NCommandType::EEnum commandType,
+ const CParser &parser,
+ CUpdateOptions &options)
+{
+ NUpdateArchive::CActionSet defaultActionSet;
+ switch ((int)commandType)
+ {
+ case NCommandType::kAdd:
+ defaultActionSet = NUpdateArchive::k_ActionSet_Add;
+ break;
+ case NCommandType::kDelete:
+ defaultActionSet = NUpdateArchive::k_ActionSet_Delete;
+ break;
+ default:
+ defaultActionSet = NUpdateArchive::k_ActionSet_Update;
+ }
+
+ options.UpdateArchiveItself = true;
+
+ options.Commands.Clear();
+ CUpdateArchiveCommand updateMainCommand;
+ updateMainCommand.ActionSet = defaultActionSet;
+ options.Commands.Add(updateMainCommand);
+ if (parser[NKey::kUpdate].ThereIs)
+ ParseUpdateCommandString(options, parser[NKey::kUpdate].PostStrings,
+ defaultActionSet);
+ if (parser[NKey::kWorkingDir].ThereIs)
+ {
+ const UString &postString = parser[NKey::kWorkingDir].PostStrings[0];
+ if (postString.IsEmpty())
+ NDir::MyGetTempPath(options.WorkingDir);
+ else
+ options.WorkingDir = us2fs(postString);
+ }
+ options.SfxMode = parser[NKey::kSfx].ThereIs;
+ if (options.SfxMode)
+ options.SfxModule = us2fs(parser[NKey::kSfx].PostStrings[0]);
+
+ if (parser[NKey::kVolume].ThereIs)
+ {
+ const UStringVector &sv = parser[NKey::kVolume].PostStrings;
+ FOR_VECTOR (i, sv)
+ {
+ UInt64 size;
+ if (!ParseComplexSize(sv[i], size))
+ throw CArcCmdLineException("Incorrect volume size:", sv[i]);
+ if (i == sv.Size() - 1 && size == 0)
+ throw CArcCmdLineException("zero size last volume is not allowed");
+ options.VolumesSizes.Add(size);
+ }
+ }
+}
+
+static void SetMethodOptions(const CParser &parser, CObjectVector<CProperty> &properties)
+{
+ if (parser[NKey::kProperty].ThereIs)
+ {
+ FOR_VECTOR (i, parser[NKey::kProperty].PostStrings)
+ {
+ CProperty prop;
+ prop.Name = parser[NKey::kProperty].PostStrings[i];
+ int index = prop.Name.Find(L'=');
+ if (index >= 0)
+ {
+ prop.Value = prop.Name.Ptr((unsigned)(index + 1));
+ prop.Name.DeleteFrom((unsigned)index);
+ }
+ properties.Add(prop);
+ }
+ }
+}
+
+
+static inline void SetStreamMode(const CSwitchResult &sw, unsigned &res)
+{
+ if (sw.ThereIs)
+ res = (unsigned)sw.PostCharIndex;
+}
+
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+static void PrintHex(UString &s, UInt64 v)
+{
+ char temp[32];
+ ConvertUInt64ToHex(v, temp);
+ s += temp;
+}
+#endif
+
+
+void CArcCmdLineParser::Parse1(const UStringVector &commandStrings,
+ CArcCmdLineOptions &options)
+{
+ Parse1Log.Empty();
+ if (!parser.ParseStrings(kSwitchForms, Z7_ARRAY_SIZE(kSwitchForms), commandStrings))
+ throw CArcCmdLineException(parser.ErrorMessage, parser.ErrorLine);
+
+ options.IsInTerminal = MY_IS_TERMINAL(stdin);
+ options.IsStdOutTerminal = MY_IS_TERMINAL(stdout);
+ options.IsStdErrTerminal = MY_IS_TERMINAL(stderr);
+
+ options.HelpMode = parser[NKey::kHelp1].ThereIs || parser[NKey::kHelp2].ThereIs || parser[NKey::kHelp3].ThereIs;
+
+ options.StdInMode = parser[NKey::kStdIn].ThereIs;
+ options.StdOutMode = parser[NKey::kStdOut].ThereIs;
+ options.EnableHeaders = !parser[NKey::kDisableHeaders].ThereIs;
+ if (parser[NKey::kListFields].ThereIs)
+ {
+ const UString &s = parser[NKey::kListFields].PostStrings[0];
+ options.ListFields = GetAnsiString(s);
+ }
+ options.TechMode = parser[NKey::kTechMode].ThereIs;
+ options.ShowTime = parser[NKey::kShowTime].ThereIs;
+
+ if (parser[NKey::kDisablePercents].ThereIs
+ || options.StdOutMode
+ || !options.IsStdOutTerminal)
+ options.Number_for_Percents = k_OutStream_disabled;
+
+ if (options.StdOutMode)
+ options.Number_for_Out = k_OutStream_disabled;
+
+ SetStreamMode(parser[NKey::kOutStream], options.Number_for_Out);
+ SetStreamMode(parser[NKey::kErrStream], options.Number_for_Errors);
+ SetStreamMode(parser[NKey::kPercentStream], options.Number_for_Percents);
+
+ if (parser[NKey::kLogLevel].ThereIs)
+ {
+ const UString &s = parser[NKey::kLogLevel].PostStrings[0];
+ if (s.IsEmpty())
+ options.LogLevel = 1;
+ else
+ {
+ UInt32 v;
+ if (!StringToUInt32(s, v))
+ throw CArcCmdLineException("Unsupported switch postfix -bb", s);
+ options.LogLevel = (unsigned)v;
+ }
+ }
+
+ if (parser[NKey::kCaseSensitive].ThereIs)
+ {
+ options.CaseSensitive =
+ g_CaseSensitive = !parser[NKey::kCaseSensitive].WithMinus;
+ options.CaseSensitive_Change = true;
+ }
+
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ NSecurity::EnablePrivilege_SymLink();
+ #endif
+
+ // options.LargePages = false;
+
+ if (parser[NKey::kLargePages].ThereIs)
+ {
+ UInt32 slp = 0;
+ const UString &s = parser[NKey::kLargePages].PostStrings[0];
+ if (s.IsEmpty())
+ slp = 1;
+ else if (s != L"-")
+ {
+ if (!StringToUInt32(s, slp))
+ throw CArcCmdLineException("Unsupported switch postfix for -slp", s);
+ }
+
+ #ifdef Z7_LARGE_PAGES
+ if (slp >
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ (unsigned)NSecurity::Get_LargePages_RiskLevel()
+ #else
+ 0
+ #endif
+ )
+ {
+ #ifdef _WIN32 // change it !
+ SetLargePageSize();
+ #endif
+ // note: this process also can inherit that Privilege from parent process
+ g_LargePagesMode =
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ NSecurity::EnablePrivilege_LockMemory();
+ #else
+ true;
+ #endif
+ }
+ #endif
+ }
+
+
+ #ifndef UNDER_CE
+
+ if (parser[NKey::kAffinity].ThereIs)
+ {
+ const UString &s = parser[NKey::kAffinity].PostStrings[0];
+ if (!s.IsEmpty())
+ {
+ AString a;
+ a.SetFromWStr_if_Ascii(s);
+ Parse1Log += "Set process affinity mask: ";
+
+ #ifdef _WIN32
+
+ UInt64 v = 0;
+ {
+ const char *end;
+ v = ConvertHexStringToUInt64(a, &end);
+ if (*end != 0)
+ a.Empty();
+ }
+ if (a.IsEmpty())
+ throw CArcCmdLineException("Unsupported switch postfix -stm", s);
+
+ {
+ #ifndef _WIN64
+ if (v >= ((UInt64)1 << 32))
+ throw CArcCmdLineException("unsupported value -stm", s);
+ #endif
+ {
+ PrintHex(Parse1Log, v);
+ if (!SetProcessAffinityMask(GetCurrentProcess(), (DWORD_PTR)v))
+ {
+ DWORD lastError = GetLastError();
+ Parse1Log += " : ERROR : ";
+ Parse1Log += NError::MyFormatMessage(lastError);
+ }
+ }
+ }
+
+ #else // _WIN32
+
+ {
+ Parse1Log += a;
+ NSystem::CProcessAffinity aff;
+ aff.CpuZero();
+ for (unsigned i = 0; i < a.Len(); i++)
+ {
+ char c = a[i];
+ unsigned v;
+ if (c >= '0' && c <= '9') v = (unsigned)(c - '0');
+ else if (c >= 'A' && c <= 'F') v = 10 + (unsigned)(c - 'A');
+ else if (c >= 'a' && c <= 'f') v = 10 + (unsigned)(c - 'a');
+ else
+ throw CArcCmdLineException("Unsupported switch postfix -stm", s);
+ for (unsigned k = 0; k < 4; k++)
+ {
+ const unsigned cpu = (a.Len() - 1 - i) * 4 + k;
+ if (v & ((unsigned)1 << k))
+ aff.CpuSet(cpu);
+ }
+ }
+
+ if (!aff.SetProcAffinity())
+ {
+ DWORD lastError = GetLastError();
+ Parse1Log += " : ERROR : ";
+ Parse1Log += NError::MyFormatMessage(lastError);
+ }
+ }
+ #endif // _WIN32
+
+ Parse1Log.Add_LF();
+ }
+ }
+
+ #endif
+}
+
+
+
+struct CCodePagePair
+{
+ const char *Name;
+ UInt32 CodePage;
+};
+
+static const unsigned kNumByteOnlyCodePages = 3;
+
+static const CCodePagePair g_CodePagePairs[] =
+{
+ { "utf-8", CP_UTF8 },
+ { "win", CP_ACP },
+ { "dos", CP_OEMCP },
+ { "utf-16le", Z7_WIN_CP_UTF16 },
+ { "utf-16be", Z7_WIN_CP_UTF16BE }
+};
+
+static Int32 FindCharset(const NCommandLineParser::CParser &parser, unsigned keyIndex,
+ bool byteOnlyCodePages, Int32 defaultVal)
+{
+ if (!parser[keyIndex].ThereIs)
+ return defaultVal;
+
+ UString name (parser[keyIndex].PostStrings.Back());
+ UInt32 v;
+ if (StringToUInt32(name, v))
+ if (v < ((UInt32)1 << 16))
+ return (Int32)v;
+ name.MakeLower_Ascii();
+ const unsigned num = byteOnlyCodePages ? kNumByteOnlyCodePages : Z7_ARRAY_SIZE(g_CodePagePairs);
+ for (unsigned i = 0;; i++)
+ {
+ if (i == num) // to disable warnings from different compilers
+ throw CArcCmdLineException("Unsupported charset:", name);
+ const CCodePagePair &pair = g_CodePagePairs[i];
+ if (name.IsEqualTo(pair.Name))
+ return (Int32)pair.CodePage;
+ }
+}
+
+
+static void SetBoolPair(NCommandLineParser::CParser &parser, unsigned switchID, CBoolPair &bp)
+{
+ bp.Def = parser[switchID].ThereIs;
+ if (bp.Def)
+ bp.Val = !parser[switchID].WithMinus;
+}
+
+void CArcCmdLineParser::Parse2(CArcCmdLineOptions &options)
+{
+ const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
+ const unsigned numNonSwitchStrings = nonSwitchStrings.Size();
+ if (numNonSwitchStrings < kMinNonSwitchWords)
+ throw CArcCmdLineException("The command must be specified");
+
+ if (!ParseArchiveCommand(nonSwitchStrings[kCommandIndex], options.Command))
+ throw CArcCmdLineException("Unsupported command:", nonSwitchStrings[kCommandIndex]);
+
+ if (parser[NKey::kHash].ThereIs)
+ options.HashMethods = parser[NKey::kHash].PostStrings;
+
+ /*
+ if (parser[NKey::kHashGenFile].ThereIs)
+ {
+ const UString &s = parser[NKey::kHashGenFile].PostStrings[0];
+ for (unsigned i = 0 ; i < s.Len();)
+ {
+ const wchar_t c = s[i++];
+ if (!options.HashOptions.ParseFlagCharOption(c, true))
+ {
+ if (c != '=')
+ throw CArcCmdLineException("Unsupported hash mode switch:", s);
+ options.HashOptions.HashFilePath = s.Ptr(i);
+ break;
+ }
+ }
+ }
+ */
+
+ if (parser[NKey::kHashDir].ThereIs)
+ options.ExtractOptions.HashDir = parser[NKey::kHashDir].PostStrings[0];
+
+ if (parser[NKey::kElimDup].ThereIs)
+ {
+ options.ExtractOptions.ElimDup.Def = true;
+ options.ExtractOptions.ElimDup.Val = !parser[NKey::kElimDup].WithMinus;
+ }
+
+ NWildcard::ECensorPathMode censorPathMode = NWildcard::k_RelatPath;
+ bool fullPathMode = parser[NKey::kFullPathMode].ThereIs;
+ if (fullPathMode)
+ {
+ censorPathMode = NWildcard::k_AbsPath;
+ const UString &s = parser[NKey::kFullPathMode].PostStrings[0];
+ if (!s.IsEmpty())
+ {
+ if (s == L"2")
+ censorPathMode = NWildcard::k_FullPath;
+ else
+ throw CArcCmdLineException("Unsupported -spf:", s);
+ }
+ }
+
+ if (parser[NKey::kNameTrailReplace].ThereIs)
+ g_PathTrailReplaceMode = !parser[NKey::kNameTrailReplace].WithMinus;
+
+ CNameOption nop;
+
+ if (parser[NKey::kRecursed].ThereIs)
+ nop.RecursedType = GetRecursedTypeFromIndex(parser[NKey::kRecursed].PostCharIndex);
+
+ if (parser[NKey::kDisableWildcardParsing].ThereIs)
+ nop.WildcardMatching = false;
+
+ if (parser[NKey::kUseSlashMark].ThereIs)
+ {
+ const UString &s = parser[NKey::kUseSlashMark].PostStrings[0];
+ if (s.IsEmpty())
+ nop.MarkMode = NWildcard::kMark_StrictFile;
+ else if (s.IsEqualTo_Ascii_NoCase("-"))
+ nop.MarkMode = NWildcard::kMark_FileOrDir;
+ else if (s.IsEqualTo_Ascii_NoCase("2"))
+ nop.MarkMode = NWildcard::kMark_StrictFile_IfWildcard;
+ else
+ throw CArcCmdLineException("Unsupported -spm:", s);
+ }
+
+
+ options.ConsoleCodePage = FindCharset(parser, NKey::kConsoleCharSet, true, -1);
+
+ UInt32 codePage = (UInt32)FindCharset(parser, NKey::kListfileCharSet, false, CP_UTF8);
+
+ bool thereAreSwitchIncludes = false;
+
+ if (parser[NKey::kInclude].ThereIs)
+ {
+ thereAreSwitchIncludes = true;
+ nop.Include = true;
+ AddSwitchWildcardsToCensor(options.Censor,
+ parser[NKey::kInclude].PostStrings, nop, codePage);
+ }
+
+ if (parser[NKey::kExclude].ThereIs)
+ {
+ nop.Include = false;
+ AddSwitchWildcardsToCensor(options.Censor,
+ parser[NKey::kExclude].PostStrings, nop, codePage);
+ }
+
+ unsigned curCommandIndex = kCommandIndex + 1;
+ bool thereIsArchiveName = !parser[NKey::kNoArName].ThereIs &&
+ options.Command.CommandType != NCommandType::kBenchmark &&
+ options.Command.CommandType != NCommandType::kInfo &&
+ options.Command.CommandType != NCommandType::kHash;
+
+ const bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
+ const bool isExtractOrList = isExtractGroupCommand || options.Command.CommandType == NCommandType::kList;
+ const bool isRename = options.Command.CommandType == NCommandType::kRename;
+
+ if ((isExtractOrList || isRename) && options.StdInMode)
+ thereIsArchiveName = false;
+
+ if (parser[NKey::kArcNameMode].ThereIs)
+ options.UpdateOptions.ArcNameMode = ParseArcNameMode(parser[NKey::kArcNameMode].PostCharIndex);
+
+ if (thereIsArchiveName)
+ {
+ if (curCommandIndex >= numNonSwitchStrings)
+ throw CArcCmdLineException("Cannot find archive name");
+ options.ArchiveName = nonSwitchStrings[curCommandIndex++];
+ if (options.ArchiveName.IsEmpty())
+ throw CArcCmdLineException("Archive name cannot by empty");
+ #ifdef _WIN32
+ // options.ArchiveName.Replace(L'/', WCHAR_PATH_SEPARATOR);
+ #endif
+ }
+
+ nop.Include = true;
+ AddToCensorFromNonSwitchesStrings(isRename ? &options.UpdateOptions.RenamePairs : NULL,
+ curCommandIndex, options.Censor,
+ nonSwitchStrings, parser.StopSwitchIndex,
+ nop,
+ thereAreSwitchIncludes, codePage);
+
+ options.YesToAll = parser[NKey::kYes].ThereIs;
+
+
+ #ifndef Z7_NO_CRYPTO
+ options.PasswordEnabled = parser[NKey::kPassword].ThereIs;
+ if (options.PasswordEnabled)
+ options.Password = parser[NKey::kPassword].PostStrings[0];
+ #endif
+
+ options.ShowDialog = parser[NKey::kShowDialog].ThereIs;
+
+ if (parser[NKey::kArchiveType].ThereIs)
+ options.ArcType = parser[NKey::kArchiveType].PostStrings[0];
+
+ options.ExcludedArcTypes = parser[NKey::kExcludedArcType].PostStrings;
+
+ SetMethodOptions(parser, options.Properties);
+
+ if (parser[NKey::kNtSecurity].ThereIs) options.NtSecurity.SetTrueTrue();
+
+ SetBoolPair(parser, NKey::kAltStreams, options.AltStreams);
+ SetBoolPair(parser, NKey::kHardLinks, options.HardLinks);
+ SetBoolPair(parser, NKey::kSymLinks, options.SymLinks);
+
+ SetBoolPair(parser, NKey::kStoreOwnerId, options.StoreOwnerId);
+ SetBoolPair(parser, NKey::kStoreOwnerName, options.StoreOwnerName);
+
+ CBoolPair symLinks_AllowDangerous;
+ SetBoolPair(parser, NKey::kSymLinks_AllowDangerous, symLinks_AllowDangerous);
+
+
+ /*
+ bool supportSymLink = options.SymLinks.Val;
+
+ if (!options.SymLinks.Def)
+ {
+ if (isExtractOrList)
+ supportSymLink = true;
+ else
+ supportSymLink = false;
+ }
+
+ #ifdef ENV_HAVE_LSTAT
+ if (supportSymLink)
+ global_use_lstat = 1;
+ else
+ global_use_lstat = 0;
+ #endif
+ */
+
+
+ if (isExtractOrList)
+ {
+ CExtractOptionsBase &eo = options.ExtractOptions;
+
+ eo.ExcludeDirItems = options.Censor.ExcludeDirItems;
+ eo.ExcludeFileItems = options.Censor.ExcludeFileItems;
+
+ {
+ CExtractNtOptions &nt = eo.NtOptions;
+ nt.NtSecurity = options.NtSecurity;
+
+ nt.AltStreams = options.AltStreams;
+ if (!options.AltStreams.Def)
+ nt.AltStreams.Val = true;
+
+ nt.HardLinks = options.HardLinks;
+ if (!options.HardLinks.Def)
+ nt.HardLinks.Val = true;
+
+ nt.SymLinks = options.SymLinks;
+ if (!options.SymLinks.Def)
+ nt.SymLinks.Val = true;
+
+ nt.SymLinks_AllowDangerous = symLinks_AllowDangerous;
+
+ nt.ReplaceColonForAltStream = parser[NKey::kReplaceColonForAltStream].ThereIs;
+ nt.WriteToAltStreamIfColon = parser[NKey::kWriteToAltStreamIfColon].ThereIs;
+
+ nt.ExtractOwner = options.StoreOwnerId.Val; // StoreOwnerName
+
+ if (parser[NKey::kPreserveATime].ThereIs)
+ nt.PreserveATime = true;
+ if (parser[NKey::kShareForWrite].ThereIs)
+ nt.OpenShareForWrite = true;
+ }
+
+ if (parser[NKey::kZoneFile].ThereIs)
+ {
+ eo.ZoneMode = NExtract::NZoneIdMode::kAll;
+ const UString &s = parser[NKey::kZoneFile].PostStrings[0];
+ if (!s.IsEmpty())
+ {
+ if (s == L"0") eo.ZoneMode = NExtract::NZoneIdMode::kNone;
+ else if (s == L"1") eo.ZoneMode = NExtract::NZoneIdMode::kAll;
+ else if (s == L"2") eo.ZoneMode = NExtract::NZoneIdMode::kOffice;
+ else
+ throw CArcCmdLineException("Unsupported -snz:", s);
+ }
+ }
+
+ options.Censor.AddPathsToCensor(NWildcard::k_AbsPath);
+ options.Censor.ExtendExclude();
+
+ // are there paths that look as non-relative (!Prefix.IsEmpty())
+ if (!options.Censor.AllAreRelative())
+ throw CArcCmdLineException("Cannot use absolute pathnames for this command");
+
+ NWildcard::CCensor &arcCensor = options.arcCensor;
+
+ CNameOption nopArc;
+ // nopArc.RecursedType = NRecursedType::kNonRecursed; // default: we don't want recursing for archives, if -r specified
+ // is it OK, external switches can disable WildcardMatching and MarcMode for arc.
+ nopArc.WildcardMatching = nop.WildcardMatching;
+ nopArc.MarkMode = nop.MarkMode;
+
+ if (parser[NKey::kArInclude].ThereIs)
+ {
+ nopArc.Include = true;
+ AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArInclude].PostStrings, nopArc, codePage);
+ }
+ if (parser[NKey::kArExclude].ThereIs)
+ {
+ nopArc.Include = false;
+ AddSwitchWildcardsToCensor(arcCensor, parser[NKey::kArExclude].PostStrings, nopArc, codePage);
+ }
+
+ if (thereIsArchiveName)
+ {
+ nopArc.Include = true;
+ AddNameToCensor(arcCensor, nopArc, options.ArchiveName);
+ }
+
+ arcCensor.AddPathsToCensor(NWildcard::k_RelatPath);
+
+ #ifdef _WIN32
+ ConvertToLongNames(arcCensor);
+ #endif
+
+ arcCensor.ExtendExclude();
+
+ if (options.StdInMode)
+ options.ArcName_for_StdInMode = parser[NKey::kStdIn].PostStrings.Front();
+
+ if (isExtractGroupCommand)
+ {
+ if (options.StdOutMode)
+ {
+ if (
+ options.Number_for_Percents == k_OutStream_stdout
+ // || options.Number_for_Out == k_OutStream_stdout
+ // || options.Number_for_Errors == k_OutStream_stdout
+ ||
+ (
+ (options.IsStdOutTerminal && options.IsStdErrTerminal)
+ &&
+ (
+ options.Number_for_Percents != k_OutStream_disabled
+ // || options.Number_for_Out != k_OutStream_disabled
+ // || options.Number_for_Errors != k_OutStream_disabled
+ )
+ )
+ )
+ throw CArcCmdLineException(kSameTerminalError);
+ }
+
+ if (parser[NKey::kOutputDir].ThereIs)
+ {
+ eo.OutputDir = us2fs(parser[NKey::kOutputDir].PostStrings[0]);
+ #ifdef _WIN32
+ NFile::NName::NormalizeDirSeparators(eo.OutputDir);
+ #endif
+ NFile::NName::NormalizeDirPathPrefix(eo.OutputDir);
+ }
+
+ eo.OverwriteMode = NExtract::NOverwriteMode::kAsk;
+ if (parser[NKey::kOverwrite].ThereIs)
+ {
+ eo.OverwriteMode = k_OverwriteModes[(unsigned)parser[NKey::kOverwrite].PostCharIndex];
+ eo.OverwriteMode_Force = true;
+ }
+ else if (options.YesToAll)
+ {
+ eo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite;
+ eo.OverwriteMode_Force = true;
+ }
+ }
+
+ eo.PathMode = options.Command.GetPathMode();
+ if (censorPathMode == NWildcard::k_AbsPath)
+ {
+ eo.PathMode = NExtract::NPathMode::kAbsPaths;
+ eo.PathMode_Force = true;
+ }
+ else if (censorPathMode == NWildcard::k_FullPath)
+ {
+ eo.PathMode = NExtract::NPathMode::kFullPaths;
+ eo.PathMode_Force = true;
+ }
+ }
+ else if (options.Command.IsFromUpdateGroup())
+ {
+ if (parser[NKey::kArInclude].ThereIs)
+ throw CArcCmdLineException("-ai switch is not supported for this command");
+
+ CUpdateOptions &updateOptions = options.UpdateOptions;
+
+ SetAddCommandOptions(options.Command.CommandType, parser, updateOptions);
+
+ updateOptions.MethodMode.Properties = options.Properties;
+
+ if (parser[NKey::kPreserveATime].ThereIs)
+ updateOptions.PreserveATime = true;
+ if (parser[NKey::kShareForWrite].ThereIs)
+ updateOptions.OpenShareForWrite = true;
+ if (parser[NKey::kStopAfterOpenError].ThereIs)
+ updateOptions.StopAfterOpenError = true;
+
+ updateOptions.PathMode = censorPathMode;
+
+ updateOptions.AltStreams = options.AltStreams;
+ updateOptions.NtSecurity = options.NtSecurity;
+ updateOptions.HardLinks = options.HardLinks;
+ updateOptions.SymLinks = options.SymLinks;
+
+ updateOptions.StoreOwnerId = options.StoreOwnerId;
+ updateOptions.StoreOwnerName = options.StoreOwnerName;
+
+ updateOptions.EMailMode = parser[NKey::kEmail].ThereIs;
+ if (updateOptions.EMailMode)
+ {
+ updateOptions.EMailAddress = parser[NKey::kEmail].PostStrings.Front();
+ if (updateOptions.EMailAddress.Len() > 0)
+ if (updateOptions.EMailAddress[0] == L'.')
+ {
+ updateOptions.EMailRemoveAfter = true;
+ updateOptions.EMailAddress.Delete(0);
+ }
+ }
+
+ updateOptions.StdOutMode = options.StdOutMode;
+ updateOptions.StdInMode = options.StdInMode;
+
+ updateOptions.DeleteAfterCompressing = parser[NKey::kDeleteAfterCompressing].ThereIs;
+ updateOptions.SetArcMTime = parser[NKey::kSetArcMTime].ThereIs;
+
+ if (updateOptions.StdOutMode && updateOptions.EMailMode)
+ throw CArcCmdLineException("stdout mode and email mode cannot be combined");
+
+ if (updateOptions.StdOutMode)
+ {
+ if (options.IsStdOutTerminal)
+ throw CArcCmdLineException(kTerminalOutError);
+
+ if (options.Number_for_Percents == k_OutStream_stdout
+ || options.Number_for_Out == k_OutStream_stdout
+ || options.Number_for_Errors == k_OutStream_stdout)
+ throw CArcCmdLineException(kSameTerminalError);
+ }
+
+ if (updateOptions.StdInMode)
+ updateOptions.StdInFileName = parser[NKey::kStdIn].PostStrings.Front();
+
+ if (options.Command.CommandType == NCommandType::kRename)
+ if (updateOptions.Commands.Size() != 1)
+ throw CArcCmdLineException("Only one archive can be created with rename command");
+ }
+ else if (options.Command.CommandType == NCommandType::kBenchmark)
+ {
+ options.NumIterations = 1;
+ options.NumIterations_Defined = false;
+ if (curCommandIndex < numNonSwitchStrings)
+ {
+ if (!StringToUInt32(nonSwitchStrings[curCommandIndex], options.NumIterations))
+ throw CArcCmdLineException("Incorrect number of benchmark iterations", nonSwitchStrings[curCommandIndex]);
+ curCommandIndex++;
+ options.NumIterations_Defined = true;
+ }
+ }
+ else if (options.Command.CommandType == NCommandType::kHash)
+ {
+ options.Censor.AddPathsToCensor(censorPathMode);
+ options.Censor.ExtendExclude();
+
+ CHashOptions &hashOptions = options.HashOptions;
+ hashOptions.PathMode = censorPathMode;
+ hashOptions.Methods = options.HashMethods;
+ // hashOptions.HashFilePath = options.HashFilePath;
+ if (parser[NKey::kPreserveATime].ThereIs)
+ hashOptions.PreserveATime = true;
+ if (parser[NKey::kShareForWrite].ThereIs)
+ hashOptions.OpenShareForWrite = true;
+ hashOptions.StdInMode = options.StdInMode;
+ hashOptions.AltStreamsMode = options.AltStreams.Val;
+ hashOptions.SymLinks = options.SymLinks;
+ }
+ else if (options.Command.CommandType == NCommandType::kInfo)
+ {
+ }
+ else
+ throw 20150919;
+}
+
+
+
+#ifndef _WIN32
+
+static AString g_ModuleDirPrefix;
+
+void Set_ModuleDirPrefix_From_ProgArg0(const char *s);
+void Set_ModuleDirPrefix_From_ProgArg0(const char *s)
+{
+ AString a (s);
+ int sep = a.ReverseFind_PathSepar();
+ a.DeleteFrom((unsigned)(sep + 1));
+ g_ModuleDirPrefix = a;
+}
+
+namespace NWindows {
+namespace NDLL {
+
+FString GetModuleDirPrefix();
+FString GetModuleDirPrefix()
+{
+ FString s;
+
+ s = fas2fs(g_ModuleDirPrefix);
+ if (s.IsEmpty())
+ s = FTEXT(".") FSTRING_PATH_SEPARATOR;
+ return s;
+ /*
+ setenv("_7ZIP_HOME_DIR", "/test/", 0);
+ const char *home = getenv("_7ZIP_HOME_DIR");
+ if (home)
+ s = home;
+ else
+ s = FTEXT(".") FSTRING_PATH_SEPARATOR;
+ return s;
+ */
+}
+
+}}
+
+#endif // ! _WIN32
diff --git a/CPP/7zip/UI/Common/ArchiveCommandLine.h b/CPP/7zip/UI/Common/ArchiveCommandLine.h
index bba3c98..9e375b5 100644
--- a/CPP/7zip/UI/Common/ArchiveCommandLine.h
+++ b/CPP/7zip/UI/Common/ArchiveCommandLine.h
@@ -1,136 +1,160 @@
-// ArchiveCommandLine.h
-
-#ifndef __ARCHIVE_COMMAND_LINE_H
-#define __ARCHIVE_COMMAND_LINE_H
-
-#include "../../../Common/CommandLineParser.h"
-#include "../../../Common/Wildcard.h"
-
-#include "EnumDirItems.h"
-
-#include "Extract.h"
-#include "HashCalc.h"
-#include "Update.h"
-
-typedef CMessagePathException CArcCmdLineException;
-
-namespace NCommandType { enum EEnum
-{
- kAdd = 0,
- kUpdate,
- kDelete,
- kTest,
- kExtract,
- kExtractFull,
- kList,
- kBenchmark,
- kInfo,
- kHash,
- kRename
-};}
-
-struct CArcCommand
-{
- NCommandType::EEnum CommandType;
-
- bool IsFromExtractGroup() const;
- bool IsFromUpdateGroup() const;
- bool IsTestCommand() const { return CommandType == NCommandType::kTest; }
- NExtract::NPathMode::EEnum GetPathMode() const;
-};
-
-enum
-{
- k_OutStream_disabled = 0,
- k_OutStream_stdout = 1,
- k_OutStream_stderr = 2
-};
-
-struct CArcCmdLineOptions
-{
- bool HelpMode;
-
- // bool LargePages;
- bool CaseSensitiveChange;
- bool CaseSensitive;
-
- bool IsInTerminal;
- bool IsStdOutTerminal;
- bool IsStdErrTerminal;
- bool StdInMode;
- bool StdOutMode;
- bool EnableHeaders;
-
- bool YesToAll;
- bool ShowDialog;
- NWildcard::CCensor Censor;
-
- CArcCommand Command;
- UString ArchiveName;
-
- #ifndef _NO_CRYPTO
- bool PasswordEnabled;
- UString Password;
- #endif
-
- bool TechMode;
- bool ShowTime;
-
- UStringVector HashMethods;
-
- bool AppendName;
- // UStringVector ArchivePathsSorted;
- // UStringVector ArchivePathsFullSorted;
- NWildcard::CCensor arcCensor;
- UString ArcName_for_StdInMode;
-
- CObjectVector<CProperty> Properties;
-
- CExtractOptionsBase ExtractOptions;
-
- CBoolPair NtSecurity;
- CBoolPair AltStreams;
- CBoolPair HardLinks;
- CBoolPair SymLinks;
-
- CUpdateOptions UpdateOptions;
- CHashOptions HashOptions;
- UString ArcType;
- UStringVector ExcludedArcTypes;
-
- unsigned Number_for_Out;
- unsigned Number_for_Errors;
- unsigned Number_for_Percents;
- unsigned LogLevel;
-
- // bool IsOutAllowed() const { return Number_for_Out != k_OutStream_disabled; }
-
- // Benchmark
- UInt32 NumIterations;
-
- CArcCmdLineOptions():
- // LargePages(false),
- CaseSensitiveChange(false),
- CaseSensitive(false),
-
- StdInMode(false),
- StdOutMode(false),
-
- Number_for_Out(k_OutStream_stdout),
- Number_for_Errors(k_OutStream_stderr),
- Number_for_Percents(k_OutStream_stdout),
-
- LogLevel(0)
- {
- };
-};
-
-class CArcCmdLineParser
-{
- NCommandLineParser::CParser parser;
-public:
- void Parse1(const UStringVector &commandStrings, CArcCmdLineOptions &options);
- void Parse2(CArcCmdLineOptions &options);
-};
-
-#endif
+// ArchiveCommandLine.h
+
+#ifndef ZIP7_INC_ARCHIVE_COMMAND_LINE_H
+#define ZIP7_INC_ARCHIVE_COMMAND_LINE_H
+
+#include "../../../Common/CommandLineParser.h"
+#include "../../../Common/Wildcard.h"
+
+#include "EnumDirItems.h"
+
+#include "Extract.h"
+#include "HashCalc.h"
+#include "Update.h"
+
+typedef CMessagePathException CArcCmdLineException;
+
+namespace NCommandType { enum EEnum
+{
+ kAdd = 0,
+ kUpdate,
+ kDelete,
+ kTest,
+ kExtract,
+ kExtractFull,
+ kList,
+ kBenchmark,
+ kInfo,
+ kHash,
+ kRename
+};}
+
+struct CArcCommand
+{
+ NCommandType::EEnum CommandType;
+
+ bool IsFromExtractGroup() const;
+ bool IsFromUpdateGroup() const;
+ bool IsTestCommand() const { return CommandType == NCommandType::kTest; }
+ NExtract::NPathMode::EEnum GetPathMode() const;
+};
+
+enum
+{
+ k_OutStream_disabled = 0,
+ k_OutStream_stdout = 1,
+ k_OutStream_stderr = 2
+};
+
+struct CArcCmdLineOptions
+{
+ bool HelpMode;
+
+ // bool LargePages;
+ bool CaseSensitive_Change;
+ bool CaseSensitive;
+
+ bool IsInTerminal;
+ bool IsStdOutTerminal;
+ bool IsStdErrTerminal;
+ bool StdInMode;
+ bool StdOutMode;
+ bool EnableHeaders;
+
+ bool YesToAll;
+ bool ShowDialog;
+ bool TechMode;
+ bool ShowTime;
+
+ CBoolPair NtSecurity;
+ CBoolPair AltStreams;
+ CBoolPair HardLinks;
+ CBoolPair SymLinks;
+
+ CBoolPair StoreOwnerId;
+ CBoolPair StoreOwnerName;
+
+ AString ListFields;
+
+ int ConsoleCodePage;
+
+ NWildcard::CCensor Censor;
+
+ CArcCommand Command;
+ UString ArchiveName;
+
+ #ifndef Z7_NO_CRYPTO
+ bool PasswordEnabled;
+ UString Password;
+ #endif
+
+ UStringVector HashMethods;
+ // UString HashFilePath;
+
+ // bool AppendName;
+ // UStringVector ArchivePathsSorted;
+ // UStringVector ArchivePathsFullSorted;
+ NWildcard::CCensor arcCensor;
+ UString ArcName_for_StdInMode;
+
+ CObjectVector<CProperty> Properties;
+
+ CExtractOptionsBase ExtractOptions;
+
+ CUpdateOptions UpdateOptions;
+ CHashOptions HashOptions;
+ UString ArcType;
+ UStringVector ExcludedArcTypes;
+
+ unsigned Number_for_Out;
+ unsigned Number_for_Errors;
+ unsigned Number_for_Percents;
+ unsigned LogLevel;
+
+ // bool IsOutAllowed() const { return Number_for_Out != k_OutStream_disabled; }
+
+ // Benchmark
+ UInt32 NumIterations;
+ bool NumIterations_Defined;
+
+ CArcCmdLineOptions():
+ HelpMode(false),
+ // LargePages(false),
+ CaseSensitive_Change(false),
+ CaseSensitive(false),
+
+ IsInTerminal(false),
+ IsStdOutTerminal(false),
+ IsStdErrTerminal(false),
+
+ StdInMode(false),
+ StdOutMode(false),
+
+ EnableHeaders(false),
+
+ YesToAll(false),
+ ShowDialog(false),
+ TechMode(false),
+ ShowTime(false),
+
+ ConsoleCodePage(-1),
+
+ Number_for_Out(k_OutStream_stdout),
+ Number_for_Errors(k_OutStream_stderr),
+ Number_for_Percents(k_OutStream_stdout),
+
+ LogLevel(0)
+ {
+ }
+};
+
+class CArcCmdLineParser
+{
+ NCommandLineParser::CParser parser;
+public:
+ UString Parse1Log;
+ void Parse1(const UStringVector &commandStrings, CArcCmdLineOptions &options);
+ void Parse2(CArcCmdLineOptions &options);
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
index aae08ad..4b0cbed 100644
--- a/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
+++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.cpp
@@ -1,1715 +1,2592 @@
-// ArchiveExtractCallback.cpp
-
-#include "StdAfx.h"
-
-#undef sprintf
-#undef printf
-
-// #include <stdio.h>
-// #include "../../../../C/CpuTicks.h"
-
-#include "../../../../C/Alloc.h"
-#include "../../../../C/CpuArch.h"
-
-
-#include "../../../Common/ComTry.h"
-#include "../../../Common/IntToString.h"
-#include "../../../Common/StringConvert.h"
-#include "../../../Common/Wildcard.h"
-
-#include "../../../Windows/ErrorMsg.h"
-#include "../../../Windows/FileDir.h"
-#include "../../../Windows/FileFind.h"
-#include "../../../Windows/FileName.h"
-#include "../../../Windows/PropVariant.h"
-#include "../../../Windows/PropVariantConv.h"
-
-#if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX)
-#define _USE_SECURITY_CODE
-#include "../../../Windows/SecurityUtils.h"
-#endif
-
-#include "../../Common/FilePathAutoRename.h"
-// #include "../../Common/StreamUtils.h"
-
-#include "../Common/ExtractingFilePath.h"
-#include "../Common/PropIDUtils.h"
-
-#include "ArchiveExtractCallback.h"
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NDir;
-
-static const char * const kCantAutoRename = "Can not create file with auto name";
-static const char * const kCantRenameFile = "Can not rename existing file";
-static const char * const kCantDeleteOutputFile = "Can not delete output file";
-static const char * const kCantDeleteOutputDir = "Can not delete output folder";
-static const char * const kCantCreateHardLink = "Can not create hard link";
-static const char * const kCantCreateSymLink = "Can not create symbolic link";
-static const char * const kCantOpenOutFile = "Can not open output file";
-static const char * const kCantSetFileLen = "Can not set length for output file";
-
-
-#ifndef _SFX
-
-STDMETHODIMP COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- HRESULT result = S_OK;
- if (_stream)
- result = _stream->Write(data, size, &size);
- if (_calculate)
- _hash->Update(data, size);
- _size += size;
- if (processedSize)
- *processedSize = size;
- return result;
-}
-
-#endif
-
-#ifdef _USE_SECURITY_CODE
-bool InitLocalPrivileges()
-{
- NSecurity::CAccessToken token;
- if (!token.OpenProcessToken(GetCurrentProcess(),
- TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES))
- return false;
-
- TOKEN_PRIVILEGES tp;
-
- tp.PrivilegeCount = 1;
- tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
-
- if (!::LookupPrivilegeValue(NULL, SE_SECURITY_NAME, &tp.Privileges[0].Luid))
- return false;
- if (!token.AdjustPrivileges(&tp))
- return false;
- return (GetLastError() == ERROR_SUCCESS);
-}
-#endif
-
-#ifdef SUPPORT_LINKS
-
-int CHardLinkNode::Compare(const CHardLinkNode &a) const
-{
- if (StreamId < a.StreamId) return -1;
- if (StreamId > a.StreamId) return 1;
- return MyCompare(INode, a.INode);
-}
-
-static HRESULT Archive_Get_HardLinkNode(IInArchive *archive, UInt32 index, CHardLinkNode &h, bool &defined)
-{
- h.INode = 0;
- h.StreamId = (UInt64)(Int64)-1;
- defined = false;
- {
- NCOM::CPropVariant prop;
- RINOK(archive->GetProperty(index, kpidINode, &prop));
- if (!ConvertPropVariantToUInt64(prop, h.INode))
- return S_OK;
- }
- {
- NCOM::CPropVariant prop;
- RINOK(archive->GetProperty(index, kpidStreamId, &prop));
- ConvertPropVariantToUInt64(prop, h.StreamId);
- }
- defined = true;
- return S_OK;
-}
-
-
-HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector<UInt32> *realIndices)
-{
- _hardLinks.Clear();
-
- if (!_arc->Ask_INode)
- return S_OK;
-
- IInArchive *archive = _arc->Archive;
- CRecordVector<CHardLinkNode> &hardIDs = _hardLinks.IDs;
-
- {
- UInt32 numItems;
- if (realIndices)
- numItems = realIndices->Size();
- else
- {
- RINOK(archive->GetNumberOfItems(&numItems));
- }
-
- for (UInt32 i = 0; i < numItems; i++)
- {
- CHardLinkNode h;
- bool defined;
- UInt32 realIndex = realIndices ? (*realIndices)[i] : i;
-
- RINOK(Archive_Get_HardLinkNode(archive, realIndex, h, defined));
- if (defined)
- {
- bool isAltStream = false;
- RINOK(Archive_IsItem_AltStream(archive, realIndex, isAltStream));
- if (!isAltStream)
- hardIDs.Add(h);
- }
- }
- }
-
- hardIDs.Sort2();
-
- {
- // wee keep only items that have 2 or more items
- unsigned k = 0;
- unsigned numSame = 1;
- for (unsigned i = 1; i < hardIDs.Size(); i++)
- {
- if (hardIDs[i].Compare(hardIDs[i - 1]) != 0)
- numSame = 1;
- else if (++numSame == 2)
- {
- if (i - 1 != k)
- hardIDs[k] = hardIDs[i - 1];
- k++;
- }
- }
- hardIDs.DeleteFrom(k);
- }
-
- _hardLinks.PrepareLinks();
- return S_OK;
-}
-
-#endif
-
-CArchiveExtractCallback::CArchiveExtractCallback():
- _arc(NULL),
- WriteCTime(true),
- WriteATime(true),
- WriteMTime(true),
- _multiArchives(false)
-{
- LocalProgressSpec = new CLocalProgress();
- _localProgress = LocalProgressSpec;
-
- #ifdef _USE_SECURITY_CODE
- _saclEnabled = InitLocalPrivileges();
- #endif
-}
-
-void CArchiveExtractCallback::Init(
- const CExtractNtOptions &ntOptions,
- const NWildcard::CCensorNode *wildcardCensor,
- const CArc *arc,
- IFolderArchiveExtractCallback *extractCallback2,
- bool stdOutMode, bool testMode,
- const FString &directoryPath,
- const UStringVector &removePathParts, bool removePartsForAltStreams,
- UInt64 packSize)
-{
- ClearExtractedDirsInfo();
- _outFileStream.Release();
-
- #ifdef SUPPORT_LINKS
- _hardLinks.Clear();
- #endif
-
- #ifdef SUPPORT_ALT_STREAMS
- _renamedFiles.Clear();
- #endif
-
- _ntOptions = ntOptions;
- _wildcardCensor = wildcardCensor;
-
- _stdOutMode = stdOutMode;
- _testMode = testMode;
-
- // _progressTotal = 0;
- // _progressTotal_Defined = false;
-
- _packTotal = packSize;
- _progressTotal = packSize;
- _progressTotal_Defined = true;
-
- _extractCallback2 = extractCallback2;
- _compressProgress.Release();
- _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress);
- _extractCallback2.QueryInterface(IID_IArchiveExtractCallbackMessage, &_callbackMessage);
- _extractCallback2.QueryInterface(IID_IFolderArchiveExtractCallback2, &_folderArchiveExtractCallback2);
-
- #ifndef _SFX
-
- _extractCallback2.QueryInterface(IID_IFolderExtractToStreamCallback, &ExtractToStreamCallback);
- if (ExtractToStreamCallback)
- {
- Int32 useStreams = 0;
- if (ExtractToStreamCallback->UseExtractToStream(&useStreams) != S_OK)
- useStreams = 0;
- if (useStreams == 0)
- ExtractToStreamCallback.Release();
- }
-
- #endif
-
- LocalProgressSpec->Init(extractCallback2, true);
- LocalProgressSpec->SendProgress = false;
-
- _removePathParts = removePathParts;
- _removePartsForAltStreams = removePartsForAltStreams;
-
- #ifndef _SFX
- _baseParentFolder = (UInt32)(Int32)-1;
- _use_baseParentFolder_mode = false;
- #endif
-
- _arc = arc;
- _dirPathPrefix = directoryPath;
- _dirPathPrefix_Full = directoryPath;
- #if defined(_WIN32) && !defined(UNDER_CE)
- if (!NName::IsAltPathPrefix(_dirPathPrefix))
- #endif
- {
- NName::NormalizeDirPathPrefix(_dirPathPrefix);
- NDir::MyGetFullPathName(directoryPath, _dirPathPrefix_Full);
- NName::NormalizeDirPathPrefix(_dirPathPrefix_Full);
- }
-}
-
-STDMETHODIMP CArchiveExtractCallback::SetTotal(UInt64 size)
-{
- COM_TRY_BEGIN
- _progressTotal = size;
- _progressTotal_Defined = true;
- if (!_multiArchives && _extractCallback2)
- return _extractCallback2->SetTotal(size);
- return S_OK;
- COM_TRY_END
-}
-
-static void NormalizeVals(UInt64 &v1, UInt64 &v2)
-{
- const UInt64 kMax = (UInt64)1 << 31;
- while (v1 > kMax)
- {
- v1 >>= 1;
- v2 >>= 1;
- }
-}
-
-static UInt64 MyMultDiv64(UInt64 unpCur, UInt64 unpTotal, UInt64 packTotal)
-{
- NormalizeVals(packTotal, unpTotal);
- NormalizeVals(unpCur, unpTotal);
- if (unpTotal == 0)
- unpTotal = 1;
- return unpCur * packTotal / unpTotal;
-}
-
-STDMETHODIMP CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue)
-{
- COM_TRY_BEGIN
-
- if (!_extractCallback2)
- return S_OK;
-
- UInt64 packCur;
- if (_multiArchives)
- {
- packCur = LocalProgressSpec->InSize;
- if (completeValue && _progressTotal_Defined)
- packCur += MyMultDiv64(*completeValue, _progressTotal, _packTotal);
- completeValue = &packCur;
- }
- return _extractCallback2->SetCompleted(completeValue);
-
- COM_TRY_END
-}
-
-STDMETHODIMP CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
-{
- COM_TRY_BEGIN
- return _localProgress->SetRatioInfo(inSize, outSize);
- COM_TRY_END
-}
-
-void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath)
-{
- bool isAbsPath = false;
-
- if (!dirPathParts.IsEmpty())
- {
- const UString &s = dirPathParts[0];
- if (s.IsEmpty())
- isAbsPath = true;
- #if defined(_WIN32) && !defined(UNDER_CE)
- else
- {
- if (NName::IsDrivePath2(s))
- isAbsPath = true;
- }
- #endif
- }
-
- if (_pathMode == NExtract::NPathMode::kAbsPaths && isAbsPath)
- fullPath.Empty();
- else
- fullPath = _dirPathPrefix;
-
- FOR_VECTOR (i, dirPathParts)
- {
- if (i != 0)
- fullPath.Add_PathSepar();
- const UString &s = dirPathParts[i];
- fullPath += us2fs(s);
- #if defined(_WIN32) && !defined(UNDER_CE)
- if (_pathMode == NExtract::NPathMode::kAbsPaths)
- if (i == 0 && s.Len() == 2 && NName::IsDrivePath2(s))
- continue;
- #endif
- CreateDir(fullPath);
- }
-}
-
-HRESULT CArchiveExtractCallback::GetTime(UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined)
-{
- filetimeIsDefined = false;
- filetime.dwLowDateTime = 0;
- filetime.dwHighDateTime = 0;
- NCOM::CPropVariant prop;
- RINOK(_arc->Archive->GetProperty(index, propID, &prop));
- if (prop.vt == VT_FILETIME)
- {
- filetime = prop.filetime;
- filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0);
- }
- else if (prop.vt != VT_EMPTY)
- return E_FAIL;
- return S_OK;
-}
-
-HRESULT CArchiveExtractCallback::GetUnpackSize()
-{
- return _arc->GetItemSize(_index, _curSize, _curSizeDefined);
-}
-
-static void AddPathToMessage(UString &s, const FString &path)
-{
- s += " : ";
- s += fs2us(path);
-}
-
-HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path)
-{
- UString s (message);
- AddPathToMessage(s, path);
- return _extractCallback2->MessageError(s);
-}
-
-HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path)
-{
- DWORD errorCode = GetLastError();
- UString s (message);
- if (errorCode != 0)
- {
- s += " : ";
- s += NError::MyFormatMessage(errorCode);
- }
- AddPathToMessage(s, path);
- return _extractCallback2->MessageError(s);
-}
-
-HRESULT CArchiveExtractCallback::SendMessageError2(const char *message, const FString &path1, const FString &path2)
-{
- UString s (message);
- AddPathToMessage(s, path1);
- AddPathToMessage(s, path2);
- return _extractCallback2->MessageError(s);
-}
-
-#ifndef _SFX
-
-STDMETHODIMP CGetProp::GetProp(PROPID propID, PROPVARIANT *value)
-{
- /*
- if (propID == kpidName)
- {
- COM_TRY_BEGIN
- NCOM::CPropVariant prop = Name;
- prop.Detach(value);
- return S_OK;
- COM_TRY_END
- }
- */
- return Arc->Archive->GetProperty(IndexInArc, propID, value);
-}
-
-#endif
-
-
-#ifdef SUPPORT_LINKS
-
-static UString GetDirPrefixOf(const UString &src)
-{
- UString s (src);
- if (!s.IsEmpty())
- {
- if (IsPathSepar(s.Back()))
- s.DeleteBack();
- int pos = s.ReverseFind_PathSepar();
- s.DeleteFrom(pos + 1);
- }
- return s;
-}
-
-#endif
-
-
-bool IsSafePath(const UString &path)
-{
- if (NName::IsAbsolutePath(path))
- return false;
-
- UStringVector parts;
- SplitPathToParts(path, parts);
- unsigned level = 0;
-
- FOR_VECTOR (i, parts)
- {
- const UString &s = parts[i];
- if (s.IsEmpty())
- {
- if (i == 0)
- return false;
- continue;
- }
- if (s == L".")
- continue;
- if (s == L"..")
- {
- if (level == 0)
- return false;
- level--;
- }
- else
- level++;
- }
-
- return level > 0;
-}
-
-
-bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include)
-{
- bool found = false;
-
- if (node.CheckPathVect(item.PathParts, !item.MainIsDir, include))
- {
- if (!include)
- return true;
-
- #ifdef SUPPORT_ALT_STREAMS
- if (!item.IsAltStream)
- return true;
- #endif
-
- found = true;
- }
-
- #ifdef SUPPORT_ALT_STREAMS
-
- if (!item.IsAltStream)
- return false;
-
- UStringVector pathParts2 = item.PathParts;
- if (pathParts2.IsEmpty())
- pathParts2.AddNew();
- UString &back = pathParts2.Back();
- back += ':';
- back += item.AltStreamName;
- bool include2;
-
- if (node.CheckPathVect(pathParts2,
- true, // isFile,
- include2))
- {
- include = include2;
- return true;
- }
-
- #endif
-
- return found;
-}
-
-bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item)
-{
- bool include;
- if (CensorNode_CheckPath2(node, item, include))
- return include;
- return false;
-}
-
-static FString MakePath_from_2_Parts(const FString &prefix, const FString &path)
-{
- FString s (prefix);
- #if defined(_WIN32) && !defined(UNDER_CE)
- if (!path.IsEmpty() && path[0] == ':' && !prefix.IsEmpty() && IsPathSepar(prefix.Back()))
- {
- if (!NName::IsDriveRootPath_SuperAllowed(prefix))
- s.DeleteBack();
- }
- #endif
- s += path;
- return s;
-}
-
-
-/*
-#ifdef SUPPORT_LINKS
-
-struct CTempMidBuffer
-{
- void *Buf;
-
- CTempMidBuffer(size_t size): Buf(NULL) { Buf = ::MidAlloc(size); }
- ~CTempMidBuffer() { ::MidFree(Buf); }
-};
-
-HRESULT CArchiveExtractCallback::MyCopyFile(ISequentialOutStream *outStream)
-{
- const size_t kBufSize = 1 << 16;
- CTempMidBuffer buf(kBufSize);
- if (!buf.Buf)
- return E_OUTOFMEMORY;
-
- NIO::CInFile inFile;
- NIO::COutFile outFile;
-
- if (!inFile.Open(_CopyFile_Path))
- return SendMessageError_with_LastError("Open error", _CopyFile_Path);
-
- for (;;)
- {
- UInt32 num;
-
- if (!inFile.Read(buf.Buf, kBufSize, num))
- return SendMessageError_with_LastError("Read error", _CopyFile_Path);
-
- if (num == 0)
- return S_OK;
-
-
- RINOK(WriteStream(outStream, buf.Buf, num));
- }
-}
-
-#endif
-*/
-
-
-STDMETHODIMP CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode)
-{
- COM_TRY_BEGIN
-
- *outStream = NULL;
-
- #ifndef _SFX
- if (_hashStream)
- _hashStreamSpec->ReleaseStream();
- _hashStreamWasUsed = false;
- #endif
-
- _outFileStream.Release();
-
- _encrypted = false;
- _position = 0;
- _isSplit = false;
-
- _curSize = 0;
- _curSizeDefined = false;
- _fileLengthWasSet = false;
- _index = index;
-
- _diskFilePath.Empty();
-
- // _fi.Clear();
-
- #ifdef SUPPORT_LINKS
- // _CopyFile_Path.Empty();
- linkPath.Empty();
- #endif
-
- IInArchive *archive = _arc->Archive;
-
- #ifndef _SFX
- _item._use_baseParentFolder_mode = _use_baseParentFolder_mode;
- if (_use_baseParentFolder_mode)
- {
- _item._baseParentFolder = _baseParentFolder;
- if (_pathMode == NExtract::NPathMode::kFullPaths ||
- _pathMode == NExtract::NPathMode::kAbsPaths)
- _item._baseParentFolder = -1;
- }
- #endif
-
- #ifdef SUPPORT_ALT_STREAMS
- _item.WriteToAltStreamIfColon = _ntOptions.WriteToAltStreamIfColon;
- #endif
-
- RINOK(_arc->GetItem(index, _item));
-
- {
- NCOM::CPropVariant prop;
- RINOK(archive->GetProperty(index, kpidPosition, &prop));
- if (prop.vt != VT_EMPTY)
- {
- if (prop.vt != VT_UI8)
- return E_FAIL;
- _position = prop.uhVal.QuadPart;
- _isSplit = true;
- }
- }
-
- #ifdef SUPPORT_LINKS
-
- // bool isCopyLink = false;
- bool isHardLink = false;
- bool isJunction = false;
- bool isRelative = false;
-
- {
- NCOM::CPropVariant prop;
- RINOK(archive->GetProperty(index, kpidHardLink, &prop));
- if (prop.vt == VT_BSTR)
- {
- isHardLink = true;
- // isCopyLink = false;
- isRelative = false; // RAR5, TAR: hard links are from root folder of archive
- linkPath.SetFromBstr(prop.bstrVal);
- }
- else if (prop.vt != VT_EMPTY)
- return E_FAIL;
- }
-
- /*
- {
- NCOM::CPropVariant prop;
- RINOK(archive->GetProperty(index, kpidCopyLink, &prop));
- if (prop.vt == VT_BSTR)
- {
- isHardLink = false;
- isCopyLink = true;
- isRelative = false; // RAR5: copy links are from root folder of archive
- linkPath.SetFromBstr(prop.bstrVal);
- }
- else if (prop.vt != VT_EMPTY)
- return E_FAIL;
- }
- */
-
- {
- NCOM::CPropVariant prop;
- RINOK(archive->GetProperty(index, kpidSymLink, &prop));
- if (prop.vt == VT_BSTR)
- {
- isHardLink = false;
- // isCopyLink = false;
- isRelative = true; // RAR5, TAR: symbolic links can be relative
- linkPath.SetFromBstr(prop.bstrVal);
- }
- else if (prop.vt != VT_EMPTY)
- return E_FAIL;
- }
-
-
- bool isOkReparse = false;
-
- if (linkPath.IsEmpty() && _arc->GetRawProps)
- {
- const void *data;
- UInt32 dataSize;
- UInt32 propType;
-
- _arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType);
-
- if (dataSize != 0)
- {
- if (propType != NPropDataType::kRaw)
- return E_FAIL;
- UString s;
- CReparseAttr reparse;
- DWORD errorCode = 0;
- isOkReparse = reparse.Parse((const Byte *)data, dataSize, errorCode);
- if (isOkReparse)
- {
- isHardLink = false;
- // isCopyLink = false;
- linkPath = reparse.GetPath();
- isJunction = reparse.IsMountPoint();
- isRelative = reparse.IsRelative();
- #ifndef _WIN32
- linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
- #endif
- }
- }
- }
-
- if (!linkPath.IsEmpty())
- {
- #ifdef _WIN32
- linkPath.Replace(L'/', WCHAR_PATH_SEPARATOR);
- #endif
-
- // rar5 uses "\??\" prefix for absolute links
- if (linkPath.IsPrefixedBy(WSTRING_PATH_SEPARATOR L"??" WSTRING_PATH_SEPARATOR))
- {
- isRelative = false;
- linkPath.DeleteFrontal(4);
- }
-
- for (;;)
- // while (NName::IsAbsolutePath(linkPath))
- {
- unsigned n = NName::GetRootPrefixSize(linkPath);
- if (n == 0)
- break;
- isRelative = false;
- linkPath.DeleteFrontal(n);
- }
- }
-
- if (!linkPath.IsEmpty() && !isRelative && _removePathParts.Size() != 0)
- {
- UStringVector pathParts;
- SplitPathToParts(linkPath, pathParts);
- bool badPrefix = false;
- FOR_VECTOR (i, _removePathParts)
- {
- if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0)
- {
- badPrefix = true;
- break;
- }
- }
- if (!badPrefix)
- pathParts.DeleteFrontal(_removePathParts.Size());
- linkPath = MakePathFromParts(pathParts);
- }
-
- #endif
-
- RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted));
-
- RINOK(GetUnpackSize());
-
- #ifdef SUPPORT_ALT_STREAMS
-
- if (!_ntOptions.AltStreams.Val && _item.IsAltStream)
- return S_OK;
-
- #endif
-
-
- UStringVector &pathParts = _item.PathParts;
-
- if (_wildcardCensor)
- {
- if (!CensorNode_CheckPath(*_wildcardCensor, _item))
- return S_OK;
- }
-
- #ifndef _SFX
- if (_use_baseParentFolder_mode)
- {
- if (!pathParts.IsEmpty())
- {
- unsigned numRemovePathParts = 0;
-
- #ifdef SUPPORT_ALT_STREAMS
- if (_pathMode == NExtract::NPathMode::kNoPathsAlt && _item.IsAltStream)
- numRemovePathParts = pathParts.Size();
- else
- #endif
- if (_pathMode == NExtract::NPathMode::kNoPaths ||
- _pathMode == NExtract::NPathMode::kNoPathsAlt)
- numRemovePathParts = pathParts.Size() - 1;
- pathParts.DeleteFrontal(numRemovePathParts);
- }
- }
- else
- #endif
- {
- if (pathParts.IsEmpty())
- {
- if (_item.IsDir)
- return S_OK;
- /*
- #ifdef SUPPORT_ALT_STREAMS
- if (!_item.IsAltStream)
- #endif
- return E_FAIL;
- */
- }
-
- unsigned numRemovePathParts = 0;
-
- switch (_pathMode)
- {
- case NExtract::NPathMode::kFullPaths:
- case NExtract::NPathMode::kCurPaths:
- {
- if (_removePathParts.IsEmpty())
- break;
- bool badPrefix = false;
-
- if (pathParts.Size() < _removePathParts.Size())
- badPrefix = true;
- else
- {
- if (pathParts.Size() == _removePathParts.Size())
- {
- if (_removePartsForAltStreams)
- {
- #ifdef SUPPORT_ALT_STREAMS
- if (!_item.IsAltStream)
- #endif
- badPrefix = true;
- }
- else
- {
- if (!_item.MainIsDir)
- badPrefix = true;
- }
- }
-
- if (!badPrefix)
- FOR_VECTOR (i, _removePathParts)
- {
- if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0)
- {
- badPrefix = true;
- break;
- }
- }
- }
-
- if (badPrefix)
- {
- if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode)
- return E_FAIL;
- }
- else
- numRemovePathParts = _removePathParts.Size();
- break;
- }
-
- case NExtract::NPathMode::kNoPaths:
- {
- if (!pathParts.IsEmpty())
- numRemovePathParts = pathParts.Size() - 1;
- break;
- }
- case NExtract::NPathMode::kNoPathsAlt:
- {
- #ifdef SUPPORT_ALT_STREAMS
- if (_item.IsAltStream)
- numRemovePathParts = pathParts.Size();
- else
- #endif
- if (!pathParts.IsEmpty())
- numRemovePathParts = pathParts.Size() - 1;
- break;
- }
- /*
- case NExtract::NPathMode::kFullPaths:
- case NExtract::NPathMode::kAbsPaths:
- break;
- */
- }
-
- pathParts.DeleteFrontal(numRemovePathParts);
- }
-
- #ifndef _SFX
-
- if (ExtractToStreamCallback)
- {
- if (!GetProp)
- {
- GetProp_Spec = new CGetProp;
- GetProp = GetProp_Spec;
- }
- GetProp_Spec->Arc = _arc;
- GetProp_Spec->IndexInArc = index;
- UString name (MakePathFromParts(pathParts));
-
- #ifdef SUPPORT_ALT_STREAMS
- if (_item.IsAltStream)
- {
- if (!pathParts.IsEmpty() || (!_removePartsForAltStreams && _pathMode != NExtract::NPathMode::kNoPathsAlt))
- name += ':';
- name += _item.AltStreamName;
- }
- #endif
-
- return ExtractToStreamCallback->GetStream7(name, BoolToInt(_item.IsDir), outStream, askExtractMode, GetProp);
- }
-
- #endif
-
- CMyComPtr<ISequentialOutStream> outStreamLoc;
-
-if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode)
-{
- if (_stdOutMode)
- {
- outStreamLoc = new CStdOutFileStream;
- }
- else
- {
- {
- NCOM::CPropVariant prop;
- RINOK(archive->GetProperty(index, kpidAttrib, &prop));
- if (prop.vt == VT_UI4)
- {
- _fi.Attrib = prop.ulVal;
- _fi.AttribDefined = true;
- }
- else if (prop.vt == VT_EMPTY)
- _fi.AttribDefined = false;
- else
- return E_FAIL;
- }
-
- RINOK(GetTime(index, kpidCTime, _fi.CTime, _fi.CTimeDefined));
- RINOK(GetTime(index, kpidATime, _fi.ATime, _fi.ATimeDefined));
- RINOK(GetTime(index, kpidMTime, _fi.MTime, _fi.MTimeDefined));
-
- bool isAnti = false;
- RINOK(_arc->IsItemAnti(index, isAnti));
-
- #ifdef SUPPORT_ALT_STREAMS
- if (!_item.IsAltStream
- || !pathParts.IsEmpty()
- || !(_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt))
- #endif
- Correct_FsPath(_pathMode == NExtract::NPathMode::kAbsPaths, _keepAndReplaceEmptyDirPrefixes, pathParts, _item.MainIsDir);
-
- #ifdef SUPPORT_ALT_STREAMS
-
- if (_item.IsAltStream)
- {
- UString s (_item.AltStreamName);
- Correct_AltStream_Name(s);
- bool needColon = true;
-
- if (pathParts.IsEmpty())
- {
- pathParts.AddNew();
- if (_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt)
- needColon = false;
- }
- else if (_pathMode == NExtract::NPathMode::kAbsPaths &&
- NWildcard::GetNumPrefixParts_if_DrivePath(pathParts) == pathParts.Size())
- pathParts.AddNew();
-
- UString &name = pathParts.Back();
- if (needColon)
- name += (char)(_ntOptions.ReplaceColonForAltStream ? '_' : ':');
- name += s;
- }
-
- #endif
-
- UString processedPath (MakePathFromParts(pathParts));
-
- if (!isAnti)
- {
- if (!_item.IsDir)
- {
- if (!pathParts.IsEmpty())
- pathParts.DeleteBack();
- }
-
- if (!pathParts.IsEmpty())
- {
- FString fullPathNew;
- CreateComplexDirectory(pathParts, fullPathNew);
-
- if (_item.IsDir)
- {
- CDirPathTime &pt = _extractedFolders.AddNew();
-
- pt.CTime = _fi.CTime;
- pt.CTimeDefined = (WriteCTime && _fi.CTimeDefined);
-
- pt.ATime = _fi.ATime;
- pt.ATimeDefined = (WriteATime && _fi.ATimeDefined);
-
- pt.MTimeDefined = false;
-
- if (WriteMTime)
- {
- if (_fi.MTimeDefined)
- {
- pt.MTime = _fi.MTime;
- pt.MTimeDefined = true;
- }
- else if (_arc->MTimeDefined)
- {
- pt.MTime = _arc->MTime;
- pt.MTimeDefined = true;
- }
- }
-
- pt.Path = fullPathNew;
-
- pt.SetDirTime();
- }
- }
- }
-
-
- FString fullProcessedPath (us2fs(processedPath));
- if (_pathMode != NExtract::NPathMode::kAbsPaths
- || !NName::IsAbsolutePath(processedPath))
- {
- fullProcessedPath = MakePath_from_2_Parts(_dirPathPrefix, fullProcessedPath);
- }
-
- #ifdef SUPPORT_ALT_STREAMS
-
- if (_item.IsAltStream && _item.ParentIndex != (UInt32)(Int32)-1)
- {
- int renIndex = _renamedFiles.FindInSorted(CIndexToPathPair(_item.ParentIndex));
- if (renIndex >= 0)
- {
- const CIndexToPathPair &pair = _renamedFiles[renIndex];
- fullProcessedPath = pair.Path;
- fullProcessedPath += ':';
- UString s (_item.AltStreamName);
- Correct_AltStream_Name(s);
- fullProcessedPath += us2fs(s);
- }
- }
-
- #endif
-
- bool isRenamed = false;
-
- if (_item.IsDir)
- {
- _diskFilePath = fullProcessedPath;
- if (isAnti)
- RemoveDir(_diskFilePath);
- #ifdef SUPPORT_LINKS
- if (linkPath.IsEmpty())
- #endif
- return S_OK;
- }
- else if (!_isSplit)
- {
-
- // ----- Is file (not split) -----
- NFind::CFileInfo fileInfo;
- if (fileInfo.Find(fullProcessedPath))
- {
- switch (_overwriteMode)
- {
- case NExtract::NOverwriteMode::kSkip:
- return S_OK;
- case NExtract::NOverwriteMode::kAsk:
- {
- int slashPos = fullProcessedPath.ReverseFind_PathSepar();
- FString realFullProcessedPath (fullProcessedPath.Left(slashPos + 1) + fileInfo.Name);
-
- Int32 overwriteResult;
- RINOK(_extractCallback2->AskOverwrite(
- fs2us(realFullProcessedPath), &fileInfo.MTime, &fileInfo.Size, _item.Path,
- _fi.MTimeDefined ? &_fi.MTime : NULL,
- _curSizeDefined ? &_curSize : NULL,
- &overwriteResult))
-
- switch (overwriteResult)
- {
- case NOverwriteAnswer::kCancel: return E_ABORT;
- case NOverwriteAnswer::kNo: return S_OK;
- case NOverwriteAnswer::kNoToAll: _overwriteMode = NExtract::NOverwriteMode::kSkip; return S_OK;
- case NOverwriteAnswer::kYes: break;
- case NOverwriteAnswer::kYesToAll: _overwriteMode = NExtract::NOverwriteMode::kOverwrite; break;
- case NOverwriteAnswer::kAutoRename: _overwriteMode = NExtract::NOverwriteMode::kRename; break;
- default:
- return E_FAIL;
- }
- }
- }
- if (_overwriteMode == NExtract::NOverwriteMode::kRename)
- {
- if (!AutoRenamePath(fullProcessedPath))
- {
- RINOK(SendMessageError(kCantAutoRename, fullProcessedPath));
- return E_FAIL;
- }
- isRenamed = true;
- }
- else if (_overwriteMode == NExtract::NOverwriteMode::kRenameExisting)
- {
- FString existPath (fullProcessedPath);
- if (!AutoRenamePath(existPath))
- {
- RINOK(SendMessageError(kCantAutoRename, fullProcessedPath));
- return E_FAIL;
- }
- // MyMoveFile can raname folders. So it's OK to use it for folders too
- if (!MyMoveFile(fullProcessedPath, existPath))
- {
- RINOK(SendMessageError2(kCantRenameFile, existPath, fullProcessedPath));
- return E_FAIL;
- }
- }
- else
- {
- if (fileInfo.IsDir())
- {
- // do we need to delete all files in folder?
- if (!RemoveDir(fullProcessedPath))
- {
- RINOK(SendMessageError_with_LastError(kCantDeleteOutputDir, fullProcessedPath));
- return S_OK;
- }
- }
- else
- {
- bool needDelete = true;
- if (needDelete)
- {
- if (NFind::DoesFileExist(fullProcessedPath))
- if (!DeleteFileAlways(fullProcessedPath))
- if (GetLastError() != ERROR_FILE_NOT_FOUND)
- {
- RINOK(SendMessageError_with_LastError(kCantDeleteOutputFile, fullProcessedPath));
- return S_OK;
- // return E_FAIL;
- }
- }
- }
- }
- }
- else // not Find(fullProcessedPath)
- {
- // we need to clear READ-ONLY of parent before creating alt stream
- #if defined(_WIN32) && !defined(UNDER_CE)
- int colonPos = NName::FindAltStreamColon(fullProcessedPath);
- if (colonPos >= 0 && fullProcessedPath[(unsigned)colonPos + 1] != 0)
- {
- FString parentFsPath (fullProcessedPath);
- parentFsPath.DeleteFrom(colonPos);
- NFind::CFileInfo parentFi;
- if (parentFi.Find(parentFsPath))
- {
- if (parentFi.IsReadOnly())
- SetFileAttrib(parentFsPath, parentFi.Attrib & ~FILE_ATTRIBUTE_READONLY);
- }
- }
- #endif
- }
- // ----- END of code for Is file (not split) -----
-
- }
- _diskFilePath = fullProcessedPath;
-
-
- if (!isAnti)
- {
- #ifdef SUPPORT_LINKS
-
- if (!linkPath.IsEmpty())
- {
- #ifndef UNDER_CE
-
- UString relatPath;
- if (isRelative)
- relatPath = GetDirPrefixOf(_item.Path);
- relatPath += linkPath;
-
- if (!IsSafePath(relatPath))
- {
- RINOK(SendMessageError("Dangerous link path was ignored", us2fs(relatPath)));
- }
- else
- {
- FString existPath;
- if (isHardLink /* || isCopyLink */ || !isRelative)
- {
- if (!NName::GetFullPath(_dirPathPrefix_Full, us2fs(relatPath), existPath))
- {
- RINOK(SendMessageError("Incorrect path", us2fs(relatPath)));
- }
- }
- else
- {
- existPath = us2fs(linkPath);
- }
-
- if (!existPath.IsEmpty())
- {
- if (isHardLink /* || isCopyLink */)
- {
- // if (isHardLink)
- {
- if (!MyCreateHardLink(fullProcessedPath, existPath))
- {
- RINOK(SendMessageError2(kCantCreateHardLink, fullProcessedPath, existPath));
- // return S_OK;
- }
- }
- /*
- else
- {
- NFind::CFileInfo fi;
- if (!fi.Find(existPath))
- {
- RINOK(SendMessageError2("Can not find the file for copying", existPath, fullProcessedPath));
- }
- else
- {
- if (_curSizeDefined && _curSize == fi.Size)
- _CopyFile_Path = existPath;
- else
- {
- RINOK(SendMessageError2("File size collision for file copying", existPath, fullProcessedPath));
- }
-
- // RINOK(MyCopyFile(existPath, fullProcessedPath));
- }
- }
- */
- }
- else if (_ntOptions.SymLinks.Val)
- {
- // bool isSymLink = true; // = false for junction
- if (_item.IsDir && !isRelative)
- {
- // if it's before Vista we use Junction Point
- // isJunction = true;
- // convertToAbs = true;
- }
-
- CByteBuffer data;
- if (FillLinkData(data, fs2us(existPath), !isJunction))
- {
- CReparseAttr attr;
- DWORD errorCode = 0;
- if (!attr.Parse(data, data.Size(), errorCode))
- {
- RINOK(SendMessageError("Internal error for symbolic link file", us2fs(_item.Path)));
- // return E_FAIL;
- }
- else
- if (!NFile::NIO::SetReparseData(fullProcessedPath, _item.IsDir, data, (DWORD)data.Size()))
- {
- RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath));
- }
- }
- }
- }
- }
-
- #endif
- }
-
- if (linkPath.IsEmpty() /* || !_CopyFile_Path.IsEmpty() */)
- #endif // SUPPORT_LINKS
- {
- bool needWriteFile = true;
-
- #ifdef SUPPORT_LINKS
- if (!_hardLinks.IDs.IsEmpty() && !_item.IsAltStream)
- {
- CHardLinkNode h;
- bool defined;
- RINOK(Archive_Get_HardLinkNode(archive, index, h, defined));
- if (defined)
- {
- {
- int linkIndex = _hardLinks.IDs.FindInSorted2(h);
- if (linkIndex >= 0)
- {
- FString &hl = _hardLinks.Links[linkIndex];
- if (hl.IsEmpty())
- hl = fullProcessedPath;
- else
- {
- if (!MyCreateHardLink(fullProcessedPath, hl))
- {
- RINOK(SendMessageError2(kCantCreateHardLink, fullProcessedPath, hl));
- return S_OK;
- }
- needWriteFile = false;
- }
- }
- }
- }
- }
- #endif
-
- if (needWriteFile)
- {
- _outFileStreamSpec = new COutFileStream;
- CMyComPtr<ISequentialOutStream> outStreamLoc2(_outFileStreamSpec);
- if (!_outFileStreamSpec->Open(fullProcessedPath, _isSplit ? OPEN_ALWAYS: CREATE_ALWAYS))
- {
- // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit)
- {
- RINOK(SendMessageError_with_LastError(kCantOpenOutFile, fullProcessedPath));
- return S_OK;
- }
- }
-
- if (_ntOptions.PreAllocateOutFile && !_isSplit && _curSizeDefined && _curSize > (1 << 12))
- {
- // UInt64 ticks = GetCpuTicks();
- bool res = _outFileStreamSpec->File.SetLength(_curSize);
- _fileLengthWasSet = res;
-
- // ticks = GetCpuTicks() - ticks;
- // printf("\nticks = %10d\n", (unsigned)ticks);
- if (!res)
- {
- RINOK(SendMessageError_with_LastError(kCantSetFileLen, fullProcessedPath));
- }
-
- /*
- _outFileStreamSpec->File.Close();
- ticks = GetCpuTicks() - ticks;
- printf("\nticks = %10d\n", (unsigned)ticks);
- return S_FALSE;
- */
-
- /*
- File.SetLength() on FAT (xp64): is fast, but then File.Close() can be slow,
- if we don't write any data.
- File.SetLength() for remote share file (exFAT) can be slow in some cases,
- and the Windows can return "network error" after 1 minute,
- while remote file still can grow.
- We need some way to detect such bad cases and disable PreAllocateOutFile mode.
- */
-
- res = _outFileStreamSpec->File.SeekToBegin();
- if (!res)
- {
- RINOK(SendMessageError_with_LastError("Can not seek to begin of file", fullProcessedPath));
- }
- }
-
- #ifdef SUPPORT_ALT_STREAMS
- if (isRenamed && !_item.IsAltStream)
- {
- CIndexToPathPair pair(index, fullProcessedPath);
- unsigned oldSize = _renamedFiles.Size();
- unsigned insertIndex = _renamedFiles.AddToUniqueSorted(pair);
- if (oldSize == _renamedFiles.Size())
- _renamedFiles[insertIndex].Path = fullProcessedPath;
- }
- #endif
-
- if (_isSplit)
- {
- RINOK(_outFileStreamSpec->Seek(_position, STREAM_SEEK_SET, NULL));
- }
-
- _outFileStream = outStreamLoc2;
- }
- }
- }
-
- outStreamLoc = _outFileStream;
- }
-}
-
- #ifndef _SFX
-
- if (_hashStream)
- {
- if (askExtractMode == NArchive::NExtract::NAskMode::kExtract ||
- askExtractMode == NArchive::NExtract::NAskMode::kTest)
- {
- _hashStreamSpec->SetStream(outStreamLoc);
- outStreamLoc = _hashStream;
- _hashStreamSpec->Init(true);
- _hashStreamWasUsed = true;
- }
- }
-
- #endif
-
-
- if (outStreamLoc)
- {
- /*
- #ifdef SUPPORT_LINKS
-
- if (!_CopyFile_Path.IsEmpty())
- {
- RINOK(PrepareOperation(askExtractMode));
- RINOK(MyCopyFile(outStreamLoc));
- return SetOperationResult(NArchive::NExtract::NOperationResult::kOK);
- }
-
- if (isCopyLink && _testMode)
- return S_OK;
-
- #endif
- */
-
- *outStream = outStreamLoc.Detach();
- }
-
- return S_OK;
-
- COM_TRY_END
-}
-
-
-STDMETHODIMP CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode)
-{
- COM_TRY_BEGIN
-
- #ifndef _SFX
- if (ExtractToStreamCallback)
- return ExtractToStreamCallback->PrepareOperation7(askExtractMode);
- #endif
-
- _extractMode = false;
-
- switch (askExtractMode)
- {
- case NArchive::NExtract::NAskMode::kExtract:
- if (_testMode)
- askExtractMode = NArchive::NExtract::NAskMode::kTest;
- else
- _extractMode = true;
- break;
- };
-
- return _extractCallback2->PrepareOperation(_item.Path, BoolToInt(_item.IsDir),
- askExtractMode, _isSplit ? &_position: 0);
-
- COM_TRY_END
-}
-
-
-HRESULT CArchiveExtractCallback::CloseFile()
-{
- if (!_outFileStream)
- return S_OK;
-
- HRESULT hres = S_OK;
- _outFileStreamSpec->SetTime(
- (WriteCTime && _fi.CTimeDefined) ? &_fi.CTime : NULL,
- (WriteATime && _fi.ATimeDefined) ? &_fi.ATime : NULL,
- (WriteMTime && _fi.MTimeDefined) ? &_fi.MTime : (_arc->MTimeDefined ? &_arc->MTime : NULL));
-
- const UInt64 processedSize = _outFileStreamSpec->ProcessedSize;
- if (_fileLengthWasSet && _curSize > processedSize)
- {
- bool res = _outFileStreamSpec->File.SetLength(processedSize);
- _fileLengthWasSet = res;
- if (!res)
- hres = SendMessageError_with_LastError(kCantSetFileLen, us2fs(_item.Path));
- }
- _curSize = processedSize;
- _curSizeDefined = true;
- RINOK(_outFileStreamSpec->Close());
- _outFileStream.Release();
- return hres;
-}
-
-
-STDMETHODIMP CArchiveExtractCallback::SetOperationResult(Int32 opRes)
-{
- COM_TRY_BEGIN
-
- #ifndef _SFX
- if (ExtractToStreamCallback)
- return ExtractToStreamCallback->SetOperationResult7(opRes, BoolToInt(_encrypted));
- #endif
-
- #ifndef _SFX
-
- if (_hashStreamWasUsed)
- {
- _hashStreamSpec->_hash->Final(_item.IsDir,
- #ifdef SUPPORT_ALT_STREAMS
- _item.IsAltStream
- #else
- false
- #endif
- , _item.Path);
- _curSize = _hashStreamSpec->GetSize();
- _curSizeDefined = true;
- _hashStreamSpec->ReleaseStream();
- _hashStreamWasUsed = false;
- }
-
- #endif
-
- RINOK(CloseFile());
-
- #ifdef _USE_SECURITY_CODE
- if (!_stdOutMode && _extractMode && _ntOptions.NtSecurity.Val && _arc->GetRawProps)
- {
- const void *data;
- UInt32 dataSize;
- UInt32 propType;
- _arc->GetRawProps->GetRawProp(_index, kpidNtSecure, &data, &dataSize, &propType);
- if (dataSize != 0)
- {
- if (propType != NPropDataType::kRaw)
- return E_FAIL;
- if (CheckNtSecure((const Byte *)data, dataSize))
- {
- SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION;
- if (_saclEnabled)
- securInfo |= SACL_SECURITY_INFORMATION;
- ::SetFileSecurityW(fs2us(_diskFilePath), securInfo, (PSECURITY_DESCRIPTOR)(void *)data);
- }
- }
- }
- #endif
-
- if (!_curSizeDefined)
- GetUnpackSize();
-
- if (_curSizeDefined)
- {
- #ifdef SUPPORT_ALT_STREAMS
- if (_item.IsAltStream)
- AltStreams_UnpackSize += _curSize;
- else
- #endif
- UnpackSize += _curSize;
- }
-
- if (_item.IsDir)
- NumFolders++;
- #ifdef SUPPORT_ALT_STREAMS
- else if (_item.IsAltStream)
- NumAltStreams++;
- #endif
- else
- NumFiles++;
-
- if (!_stdOutMode && _extractMode && _fi.AttribDefined)
- SetFileAttrib_PosixHighDetect(_diskFilePath, _fi.Attrib);
-
- RINOK(_extractCallback2->SetOperationResult(opRes, BoolToInt(_encrypted)));
-
- return S_OK;
-
- COM_TRY_END
-}
-
-STDMETHODIMP CArchiveExtractCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)
-{
- if (_folderArchiveExtractCallback2)
- {
- bool isEncrypted = false;
- UString s;
-
- if (indexType == NArchive::NEventIndexType::kInArcIndex && index != (UInt32)(Int32)-1)
- {
- CReadArcItem item;
- RINOK(_arc->GetItem(index, item));
- s = item.Path;
- RINOK(Archive_GetItemBoolProp(_arc->Archive, index, kpidEncrypted, isEncrypted));
- }
- else
- {
- s = '#';
- s.Add_UInt32(index);
- // if (indexType == NArchive::NEventIndexType::kBlockIndex) {}
- }
-
- return _folderArchiveExtractCallback2->ReportExtractResult(opRes, isEncrypted, s);
- }
-
- return S_OK;
-}
-
-
-STDMETHODIMP CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password)
-{
- COM_TRY_BEGIN
- if (!_cryptoGetTextPassword)
- {
- RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword,
- &_cryptoGetTextPassword));
- }
- return _cryptoGetTextPassword->CryptoGetTextPassword(password);
- COM_TRY_END
-}
-
-
-void CDirPathSortPair::SetNumSlashes(const FChar *s)
-{
- for (unsigned numSlashes = 0;;)
- {
- FChar c = *s++;
- if (c == 0)
- {
- Len = numSlashes;
- return;
- }
- if (IS_PATH_SEPAR(c))
- numSlashes++;
- }
-}
-
-
-bool CDirPathTime::SetDirTime()
-{
- return NDir::SetDirTime(Path,
- CTimeDefined ? &CTime : NULL,
- ATimeDefined ? &ATime : NULL,
- MTimeDefined ? &MTime : NULL);
-}
-
-
-HRESULT CArchiveExtractCallback::SetDirsTimes()
-{
- if (!_arc)
- return S_OK;
-
- CRecordVector<CDirPathSortPair> pairs;
- pairs.ClearAndSetSize(_extractedFolders.Size());
- unsigned i;
-
- for (i = 0; i < _extractedFolders.Size(); i++)
- {
- CDirPathSortPair &pair = pairs[i];
- pair.Index = i;
- pair.SetNumSlashes(_extractedFolders[i].Path);
- }
-
- pairs.Sort2();
-
- for (i = 0; i < pairs.Size(); i++)
- {
- _extractedFolders[pairs[i].Index].SetDirTime();
- // if (!) return GetLastError();
- }
-
- ClearExtractedDirsInfo();
- return S_OK;
-}
-
-
-HRESULT CArchiveExtractCallback::CloseArc()
-{
- HRESULT res = CloseFile();
- HRESULT res2 = SetDirsTimes();
- if (res == S_OK)
- res = res2;
- _arc = NULL;
- return res;
-}
+// ArchiveExtractCallback.cpp
+
+#include "StdAfx.h"
+
+#undef sprintf
+#undef printf
+
+// #include <stdio.h>
+// #include "../../../../C/CpuTicks.h"
+
+#include "../../../../C/Alloc.h"
+#include "../../../../C/CpuArch.h"
+
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/UTFConvert.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/PropVariantConv.h"
+
+#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
+#define Z7_USE_SECURITY_CODE
+#include "../../../Windows/SecurityUtils.h"
+#endif
+
+#include "../../Common/FilePathAutoRename.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../Common/ExtractingFilePath.h"
+#include "../Common/PropIDUtils.h"
+
+#include "ArchiveExtractCallback.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+static const char * const kCantAutoRename = "Cannot create file with auto name";
+static const char * const kCantRenameFile = "Cannot rename existing file";
+static const char * const kCantDeleteOutputFile = "Cannot delete output file";
+static const char * const kCantDeleteOutputDir = "Cannot delete output folder";
+static const char * const kCantOpenOutFile = "Cannot open output file";
+static const char * const kCantOpenInFile = "Cannot open input file";
+static const char * const kCantSetFileLen = "Cannot set length for output file";
+#ifdef SUPPORT_LINKS
+static const char * const kCantCreateHardLink = "Cannot create hard link";
+static const char * const kCantCreateSymLink = "Cannot create symbolic link";
+#endif
+
+#ifndef Z7_SFX
+
+Z7_COM7F_IMF(COutStreamWithHash::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ HRESULT result = S_OK;
+ if (_stream)
+ result = _stream->Write(data, size, &size);
+ if (_calculate)
+ _hash->Update(data, size);
+ _size += size;
+ if (processedSize)
+ *processedSize = size;
+ return result;
+}
+
+#endif // Z7_SFX
+
+
+#ifdef Z7_USE_SECURITY_CODE
+bool InitLocalPrivileges();
+bool InitLocalPrivileges()
+{
+ NSecurity::CAccessToken token;
+ if (!token.OpenProcessToken(GetCurrentProcess(),
+ TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES))
+ return false;
+
+ TOKEN_PRIVILEGES tp;
+
+ tp.PrivilegeCount = 1;
+ tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+
+ if (!::LookupPrivilegeValue(NULL, SE_SECURITY_NAME, &tp.Privileges[0].Luid))
+ return false;
+ if (!token.AdjustPrivileges(&tp))
+ return false;
+ return (GetLastError() == ERROR_SUCCESS);
+}
+#endif // Z7_USE_SECURITY_CODE
+
+
+
+#if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
+
+static const char * const kOfficeExtensions =
+ " doc dot wbk"
+ " docx docm dotx dotm docb wll wwl"
+ " xls xlt xlm"
+ " xlsx xlsm xltx xltm xlsb xla xlam"
+ " ppt pot pps ppa ppam"
+ " pptx pptm potx potm ppam ppsx ppsm sldx sldm"
+ " ";
+
+static bool FindExt2(const char *p, const UString &name)
+{
+ const int pathPos = name.ReverseFind_PathSepar();
+ const int dotPos = name.ReverseFind_Dot();
+ if (dotPos < 0
+ || dotPos < pathPos
+ || dotPos == (int)name.Len() - 1)
+ return false;
+
+ AString s;
+ for (unsigned pos = (unsigned)(dotPos + 1);; pos++)
+ {
+ const wchar_t c = name[pos];
+ if (c <= 0)
+ break;
+ if (c >= 0x80)
+ return false;
+ s += (char)MyCharLower_Ascii((char)c);
+ }
+ for (unsigned i = 0; p[i] != 0;)
+ {
+ unsigned j;
+ for (j = i; p[j] != ' '; j++);
+ if (s.Len() == j - i && memcmp(p + i, (const char *)s, s.Len()) == 0)
+ return true;
+ i = j + 1;
+ }
+ return false;
+}
+
+
+static const FChar * const k_ZoneId_StreamName = FTEXT(":Zone.Identifier");
+
+void ReadZoneFile_Of_BaseFile(CFSTR fileName2, CByteBuffer &buf)
+{
+ FString fileName (fileName2);
+ fileName += k_ZoneId_StreamName;
+
+ buf.Free();
+ NIO::CInFile file;
+ if (!file.Open(fileName))
+ return;
+ UInt64 fileSize;
+ if (!file.GetLength(fileSize))
+ return;
+ if (fileSize == 0 || fileSize >= ((UInt32)1 << 16))
+ return;
+ buf.Alloc((size_t)fileSize);
+ size_t processed;
+ if (file.ReadFull(buf, (size_t)fileSize, processed) && processed == fileSize)
+ return;
+ buf.Free();
+}
+
+static bool WriteZoneFile(CFSTR fileName, const CByteBuffer &buf)
+{
+ NIO::COutFile file;
+ if (!file.Create(fileName, true))
+ return false;
+ return file.WriteFull(buf, buf.Size());
+}
+
+#endif
+
+
+#ifdef SUPPORT_LINKS
+
+int CHardLinkNode::Compare(const CHardLinkNode &a) const
+{
+ if (StreamId < a.StreamId) return -1;
+ if (StreamId > a.StreamId) return 1;
+ return MyCompare(INode, a.INode);
+}
+
+static HRESULT Archive_Get_HardLinkNode(IInArchive *archive, UInt32 index, CHardLinkNode &h, bool &defined)
+{
+ h.INode = 0;
+ h.StreamId = (UInt64)(Int64)-1;
+ defined = false;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidINode, &prop))
+ if (!ConvertPropVariantToUInt64(prop, h.INode))
+ return S_OK;
+ }
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidStreamId, &prop))
+ ConvertPropVariantToUInt64(prop, h.StreamId);
+ }
+ defined = true;
+ return S_OK;
+}
+
+
+HRESULT CArchiveExtractCallback::PrepareHardLinks(const CRecordVector<UInt32> *realIndices)
+{
+ _hardLinks.Clear();
+
+ if (!_arc->Ask_INode)
+ return S_OK;
+
+ IInArchive *archive = _arc->Archive;
+ CRecordVector<CHardLinkNode> &hardIDs = _hardLinks.IDs;
+
+ {
+ UInt32 numItems;
+ if (realIndices)
+ numItems = realIndices->Size();
+ else
+ {
+ RINOK(archive->GetNumberOfItems(&numItems))
+ }
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ CHardLinkNode h;
+ bool defined;
+ const UInt32 realIndex = realIndices ? (*realIndices)[i] : i;
+
+ RINOK(Archive_Get_HardLinkNode(archive, realIndex, h, defined))
+ if (defined)
+ {
+ bool isAltStream = false;
+ RINOK(Archive_IsItem_AltStream(archive, realIndex, isAltStream))
+ if (!isAltStream)
+ {
+ bool isDir = false;
+ RINOK(Archive_IsItem_Dir(archive, realIndex, isDir))
+ if (!isDir)
+ hardIDs.Add(h);
+ }
+ }
+ }
+ }
+
+ hardIDs.Sort2();
+
+ {
+ // we keep only items that have 2 or more items
+ unsigned k = 0;
+ unsigned numSame = 1;
+ for (unsigned i = 1; i < hardIDs.Size(); i++)
+ {
+ if (hardIDs[i].Compare(hardIDs[i - 1]) != 0)
+ numSame = 1;
+ else if (++numSame == 2)
+ {
+ if (i - 1 != k)
+ hardIDs[k] = hardIDs[i - 1];
+ k++;
+ }
+ }
+ hardIDs.DeleteFrom(k);
+ }
+
+ _hardLinks.PrepareLinks();
+ return S_OK;
+}
+
+#endif // SUPPORT_LINKS
+
+
+CArchiveExtractCallback::CArchiveExtractCallback():
+ _arc(NULL),
+ Write_CTime(true),
+ Write_ATime(true),
+ Write_MTime(true),
+ _multiArchives(false)
+{
+ LocalProgressSpec = new CLocalProgress();
+ _localProgress = LocalProgressSpec;
+
+ #ifdef Z7_USE_SECURITY_CODE
+ _saclEnabled = InitLocalPrivileges();
+ #endif
+}
+
+
+void CArchiveExtractCallback::InitBeforeNewArchive()
+{
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ ZoneBuf.Free();
+ #endif
+}
+
+void CArchiveExtractCallback::Init(
+ const CExtractNtOptions &ntOptions,
+ const NWildcard::CCensorNode *wildcardCensor,
+ const CArc *arc,
+ IFolderArchiveExtractCallback *extractCallback2,
+ bool stdOutMode, bool testMode,
+ const FString &directoryPath,
+ const UStringVector &removePathParts, bool removePartsForAltStreams,
+ UInt64 packSize)
+{
+ ClearExtractedDirsInfo();
+ _outFileStream.Release();
+ _bufPtrSeqOutStream.Release();
+
+ #ifdef SUPPORT_LINKS
+ _hardLinks.Clear();
+ #endif
+
+ #ifdef SUPPORT_ALT_STREAMS
+ _renamedFiles.Clear();
+ #endif
+
+ _ntOptions = ntOptions;
+ _wildcardCensor = wildcardCensor;
+
+ _stdOutMode = stdOutMode;
+ _testMode = testMode;
+
+ // _progressTotal = 0;
+ // _progressTotal_Defined = false;
+
+ _packTotal = packSize;
+ _progressTotal = packSize;
+ _progressTotal_Defined = true;
+
+ _extractCallback2 = extractCallback2;
+
+ /*
+ _compressProgress.Release();
+ _extractCallback2.QueryInterface(IID_ICompressProgressInfo, &_compressProgress);
+
+ _callbackMessage.Release();
+ _extractCallback2.QueryInterface(IID_IArchiveExtractCallbackMessage2, &_callbackMessage);
+ */
+
+ _folderArchiveExtractCallback2.Release();
+ _extractCallback2.QueryInterface(IID_IFolderArchiveExtractCallback2, &_folderArchiveExtractCallback2);
+
+ #ifndef Z7_SFX
+
+ ExtractToStreamCallback.Release();
+ _extractCallback2.QueryInterface(IID_IFolderExtractToStreamCallback, &ExtractToStreamCallback);
+ if (ExtractToStreamCallback)
+ {
+ Int32 useStreams = 0;
+ if (ExtractToStreamCallback->UseExtractToStream(&useStreams) != S_OK)
+ useStreams = 0;
+ if (useStreams == 0)
+ ExtractToStreamCallback.Release();
+ }
+
+ #endif
+
+ LocalProgressSpec->Init(extractCallback2, true);
+ LocalProgressSpec->SendProgress = false;
+
+ _removePathParts = removePathParts;
+ _removePartsForAltStreams = removePartsForAltStreams;
+
+ #ifndef Z7_SFX
+ _baseParentFolder = (UInt32)(Int32)-1;
+ _use_baseParentFolder_mode = false;
+ #endif
+
+ _arc = arc;
+ _dirPathPrefix = directoryPath;
+ _dirPathPrefix_Full = directoryPath;
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (!NName::IsAltPathPrefix(_dirPathPrefix))
+ #endif
+ {
+ NName::NormalizeDirPathPrefix(_dirPathPrefix);
+ NDir::MyGetFullPathName(directoryPath, _dirPathPrefix_Full);
+ NName::NormalizeDirPathPrefix(_dirPathPrefix_Full);
+ }
+}
+
+
+Z7_COM7F_IMF(CArchiveExtractCallback::SetTotal(UInt64 size))
+{
+ COM_TRY_BEGIN
+ _progressTotal = size;
+ _progressTotal_Defined = true;
+ if (!_multiArchives && _extractCallback2)
+ return _extractCallback2->SetTotal(size);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+static void NormalizeVals(UInt64 &v1, UInt64 &v2)
+{
+ const UInt64 kMax = (UInt64)1 << 31;
+ while (v1 > kMax)
+ {
+ v1 >>= 1;
+ v2 >>= 1;
+ }
+}
+
+
+static UInt64 MyMultDiv64(UInt64 unpCur, UInt64 unpTotal, UInt64 packTotal)
+{
+ NormalizeVals(packTotal, unpTotal);
+ NormalizeVals(unpCur, unpTotal);
+ if (unpTotal == 0)
+ unpTotal = 1;
+ return unpCur * packTotal / unpTotal;
+}
+
+
+Z7_COM7F_IMF(CArchiveExtractCallback::SetCompleted(const UInt64 *completeValue))
+{
+ COM_TRY_BEGIN
+
+ if (!_extractCallback2)
+ return S_OK;
+
+ UInt64 packCur;
+ if (_multiArchives)
+ {
+ packCur = LocalProgressSpec->InSize;
+ if (completeValue && _progressTotal_Defined)
+ packCur += MyMultDiv64(*completeValue, _progressTotal, _packTotal);
+ completeValue = &packCur;
+ }
+ return _extractCallback2->SetCompleted(completeValue);
+
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CArchiveExtractCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
+{
+ COM_TRY_BEGIN
+ return _localProgress->SetRatioInfo(inSize, outSize);
+ COM_TRY_END
+}
+
+
+void CArchiveExtractCallback::CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath)
+{
+ // we use (_item.IsDir) in this function
+
+ bool isAbsPath = false;
+
+ if (!dirPathParts.IsEmpty())
+ {
+ const UString &s = dirPathParts[0];
+ if (s.IsEmpty())
+ isAbsPath = true;
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ else
+ {
+ if (NName::IsDrivePath2(s))
+ isAbsPath = true;
+ }
+ #endif
+ }
+
+ if (_pathMode == NExtract::NPathMode::kAbsPaths && isAbsPath)
+ fullPath.Empty();
+ else
+ fullPath = _dirPathPrefix;
+
+ FOR_VECTOR (i, dirPathParts)
+ {
+ if (i != 0)
+ fullPath.Add_PathSepar();
+ const UString &s = dirPathParts[i];
+ fullPath += us2fs(s);
+
+ const bool isFinalDir = (i == dirPathParts.Size() - 1 && _item.IsDir);
+
+ if (fullPath.IsEmpty())
+ {
+ if (isFinalDir)
+ _itemFailure = true;
+ continue;
+ }
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (_pathMode == NExtract::NPathMode::kAbsPaths)
+ if (i == 0 && s.Len() == 2 && NName::IsDrivePath2(s))
+ {
+ if (isFinalDir)
+ {
+ // we don't want to call SetAttrib() for root drive path
+ _itemFailure = true;
+ }
+ continue;
+ }
+ #endif
+
+ // bool res =
+ CreateDir(fullPath);
+ // if (!res)
+ if (isFinalDir)
+ {
+ if (!NFile::NFind::DoesDirExist(fullPath))
+ {
+ _itemFailure = true;
+ SendMessageError("Cannot create folder", fullPath);
+ // SendMessageError_with_LastError()
+ }
+ }
+ }
+}
+
+
+HRESULT CArchiveExtractCallback::GetTime(UInt32 index, PROPID propID, CArcTime &ft)
+{
+ ft.Clear();
+ NCOM::CPropVariant prop;
+ RINOK(_arc->Archive->GetProperty(index, propID, &prop))
+ if (prop.vt == VT_FILETIME)
+ ft.Set_From_Prop(prop);
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+
+HRESULT CArchiveExtractCallback::GetUnpackSize()
+{
+ return _arc->GetItem_Size(_index, _curSize, _curSize_Defined);
+}
+
+static void AddPathToMessage(UString &s, const FString &path)
+{
+ s += " : ";
+ s += fs2us(path);
+}
+
+HRESULT CArchiveExtractCallback::SendMessageError(const char *message, const FString &path)
+{
+ UString s (message);
+ AddPathToMessage(s, path);
+ return _extractCallback2->MessageError(s);
+}
+
+HRESULT CArchiveExtractCallback::SendMessageError_with_LastError(const char *message, const FString &path)
+{
+ DWORD errorCode = GetLastError();
+ if (errorCode == 0)
+ errorCode = (DWORD)E_FAIL;
+ UString s (message);
+ {
+ s += " : ";
+ s += NError::MyFormatMessage(errorCode);
+ }
+ AddPathToMessage(s, path);
+ return _extractCallback2->MessageError(s);
+}
+
+HRESULT CArchiveExtractCallback::SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2)
+{
+ UString s (message);
+ if (errorCode != 0)
+ {
+ s += " : ";
+ s += NError::MyFormatMessage(errorCode);
+ }
+ AddPathToMessage(s, path1);
+ AddPathToMessage(s, path2);
+ return _extractCallback2->MessageError(s);
+}
+
+#ifndef Z7_SFX
+
+Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value))
+{
+ /*
+ if (propID == kpidName)
+ {
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop = Name;
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+ }
+ */
+ return Arc->Archive->GetProperty(IndexInArc, propID, value);
+}
+
+#endif // Z7_SFX
+
+
+#ifdef SUPPORT_LINKS
+
+static UString GetDirPrefixOf(const UString &src)
+{
+ UString s (src);
+ if (!s.IsEmpty())
+ {
+ if (IsPathSepar(s.Back()))
+ s.DeleteBack();
+ int pos = s.ReverseFind_PathSepar();
+ s.DeleteFrom((unsigned)(pos + 1));
+ }
+ return s;
+}
+
+#endif // SUPPORT_LINKS
+
+struct CLinkLevelsInfo
+{
+ bool IsAbsolute;
+ int LowLevel;
+ int FinalLevel;
+
+ void Parse(const UString &path);
+};
+
+void CLinkLevelsInfo::Parse(const UString &path)
+{
+ IsAbsolute = NName::IsAbsolutePath(path);
+
+ LowLevel = 0;
+ FinalLevel = 0;
+
+ UStringVector parts;
+ SplitPathToParts(path, parts);
+ int level = 0;
+
+ FOR_VECTOR (i, parts)
+ {
+ const UString &s = parts[i];
+ if (s.IsEmpty())
+ {
+ if (i == 0)
+ IsAbsolute = true;
+ continue;
+ }
+ if (s == L".")
+ continue;
+ if (s == L"..")
+ {
+ level--;
+ if (LowLevel > level)
+ LowLevel = level;
+ }
+ else
+ level++;
+ }
+
+ FinalLevel = level;
+}
+
+
+bool IsSafePath(const UString &path);
+bool IsSafePath(const UString &path)
+{
+ CLinkLevelsInfo levelsInfo;
+ levelsInfo.Parse(path);
+ return !levelsInfo.IsAbsolute
+ && levelsInfo.LowLevel >= 0
+ && levelsInfo.FinalLevel > 0;
+}
+
+
+bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include);
+bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include)
+{
+ bool found = false;
+
+ // CheckPathVect() doesn't check path to Parent nodes
+ if (node.CheckPathVect(item.PathParts, !item.MainIsDir, include))
+ {
+ if (!include)
+ return true;
+
+ #ifdef SUPPORT_ALT_STREAMS
+ if (!item.IsAltStream)
+ return true;
+ #endif
+
+ found = true;
+ }
+
+ #ifdef SUPPORT_ALT_STREAMS
+
+ if (!item.IsAltStream)
+ return false;
+
+ UStringVector pathParts2 = item.PathParts;
+ if (pathParts2.IsEmpty())
+ pathParts2.AddNew();
+ UString &back = pathParts2.Back();
+ back += ':';
+ back += item.AltStreamName;
+ bool include2;
+
+ if (node.CheckPathVect(pathParts2,
+ true, // isFile,
+ include2))
+ {
+ include = include2;
+ return true;
+ }
+
+ #endif // SUPPORT_ALT_STREAMS
+
+ return found;
+}
+
+
+bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item)
+{
+ bool include;
+ if (CensorNode_CheckPath2(node, item, include))
+ return include;
+ return false;
+}
+
+
+static FString MakePath_from_2_Parts(const FString &prefix, const FString &path)
+{
+ FString s (prefix);
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (!path.IsEmpty() && path[0] == ':' && !prefix.IsEmpty() && IsPathSepar(prefix.Back()))
+ {
+ if (!NName::IsDriveRootPath_SuperAllowed(prefix))
+ s.DeleteBack();
+ }
+ #endif
+ s += path;
+ return s;
+}
+
+
+
+#ifdef SUPPORT_LINKS
+
+/*
+struct CTempMidBuffer
+{
+ void *Buf;
+
+ CTempMidBuffer(size_t size): Buf(NULL) { Buf = ::MidAlloc(size); }
+ ~CTempMidBuffer() { ::MidFree(Buf); }
+};
+
+HRESULT CArchiveExtractCallback::MyCopyFile(ISequentialOutStream *outStream)
+{
+ const size_t kBufSize = 1 << 16;
+ CTempMidBuffer buf(kBufSize);
+ if (!buf.Buf)
+ return E_OUTOFMEMORY;
+
+ NIO::CInFile inFile;
+ NIO::COutFile outFile;
+
+ if (!inFile.Open(_copyFile_Path))
+ return SendMessageError_with_LastError("Open error", _copyFile_Path);
+
+ for (;;)
+ {
+ UInt32 num;
+
+ if (!inFile.Read(buf.Buf, kBufSize, num))
+ return SendMessageError_with_LastError("Read error", _copyFile_Path);
+
+ if (num == 0)
+ return S_OK;
+
+
+ RINOK(WriteStream(outStream, buf.Buf, num));
+ }
+}
+*/
+
+
+HRESULT CArchiveExtractCallback::ReadLink()
+{
+ IInArchive *archive = _arc->Archive;
+ const UInt32 index = _index;
+ _link.Clear();
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidHardLink, &prop))
+ if (prop.vt == VT_BSTR)
+ {
+ _link.isHardLink = true;
+ // _link.isCopyLink = false;
+ _link.isRelative = false; // RAR5, TAR: hard links are from root folder of archive
+ _link.linkPath.SetFromBstr(prop.bstrVal);
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ }
+
+ /*
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidCopyLink, &prop));
+ if (prop.vt == VT_BSTR)
+ {
+ _link.isHardLink = false;
+ _link.isCopyLink = true;
+ _link.isRelative = false; // RAR5: copy links are from root folder of archive
+ _link.linkPath.SetFromBstr(prop.bstrVal);
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ }
+ */
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidSymLink, &prop))
+ if (prop.vt == VT_BSTR)
+ {
+ _link.isHardLink = false;
+ // _link.isCopyLink = false;
+ _link.isRelative = true; // RAR5, TAR: symbolic links can be relative
+ _link.linkPath.SetFromBstr(prop.bstrVal);
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ }
+
+ NtReparse_Data = NULL;
+ NtReparse_Size = 0;
+
+ if (_link.linkPath.IsEmpty() && _arc->GetRawProps)
+ {
+ const void *data;
+ UInt32 dataSize;
+ UInt32 propType;
+
+ _arc->GetRawProps->GetRawProp(_index, kpidNtReparse, &data, &dataSize, &propType);
+
+ // if (dataSize == 1234567) // for debug: unpacking without reparse
+ if (dataSize != 0)
+ {
+ if (propType != NPropDataType::kRaw)
+ return E_FAIL;
+
+ // 21.06: we need kpidNtReparse in linux for wim archives created in Windows
+ // #ifdef _WIN32
+
+ NtReparse_Data = data;
+ NtReparse_Size = dataSize;
+
+ CReparseAttr reparse;
+ bool isOkReparse = reparse.Parse((const Byte *)data, dataSize);
+ if (isOkReparse)
+ {
+ _link.isHardLink = false;
+ // _link.isCopyLink = false;
+ _link.linkPath = reparse.GetPath();
+ _link.isJunction = reparse.IsMountPoint();
+
+ if (reparse.IsSymLink_WSL())
+ {
+ _link.isWSL = true;
+ _link.isRelative = reparse.IsRelative_WSL();
+ }
+ else
+ _link.isRelative = reparse.IsRelative_Win();
+
+ // const AString s = GetAnsiString(_link.linkPath);
+ // printf("\n_link.linkPath: %s\n", s.Ptr());
+
+ #ifndef _WIN32
+ _link.linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
+ #endif
+ }
+ // #endif
+ }
+ }
+
+ if (_link.linkPath.IsEmpty())
+ return S_OK;
+
+ {
+ #ifdef _WIN32
+ _link.linkPath.Replace(L'/', WCHAR_PATH_SEPARATOR);
+ #endif
+
+ // rar5 uses "\??\" prefix for absolute links
+ if (_link.linkPath.IsPrefixedBy(WSTRING_PATH_SEPARATOR L"??" WSTRING_PATH_SEPARATOR))
+ {
+ _link.isRelative = false;
+ _link.linkPath.DeleteFrontal(4);
+ }
+
+ for (;;)
+ // while (NName::IsAbsolutePath(linkPath))
+ {
+ unsigned n = NName::GetRootPrefixSize(_link.linkPath);
+ if (n == 0)
+ break;
+ _link.isRelative = false;
+ _link.linkPath.DeleteFrontal(n);
+ }
+ }
+
+ if (_link.linkPath.IsEmpty())
+ return S_OK;
+
+ if (!_link.isRelative && _removePathParts.Size() != 0)
+ {
+ UStringVector pathParts;
+ SplitPathToParts(_link.linkPath, pathParts);
+ bool badPrefix = false;
+ FOR_VECTOR (i, _removePathParts)
+ {
+ if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0)
+ {
+ badPrefix = true;
+ break;
+ }
+ }
+ if (!badPrefix)
+ pathParts.DeleteFrontal(_removePathParts.Size());
+ _link.linkPath = MakePathFromParts(pathParts);
+ }
+
+ /*
+ if (!_link.linkPath.IsEmpty())
+ {
+ printf("\n_link %s to -> %s\n", GetOemString(_item.Path).Ptr(), GetOemString(_link.linkPath).Ptr());
+ }
+ */
+
+ return S_OK;
+}
+
+#endif // SUPPORT_LINKS
+
+
+#ifndef _WIN32
+
+static HRESULT GetOwner(IInArchive *archive,
+ UInt32 index, UInt32 pidName, UInt32 pidId, COwnerInfo &res)
+{
+ {
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, pidId, &prop))
+ if (prop.vt == VT_UI4)
+ {
+ res.Id_Defined = true;
+ res.Id = prop.ulVal; // for debug
+ // res.Id++; // for debug
+ // if (pidId == kpidGroupId) res.Id += 7; // for debug
+ // res.Id = 0; // for debug
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ {
+ NWindows::NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, pidName, &prop))
+ if (prop.vt == VT_BSTR)
+ {
+ const UString s = prop.bstrVal;
+ ConvertUnicodeToUTF8(s, res.Name);
+ }
+ else if (prop.vt == VT_UI4)
+ {
+ res.Id_Defined = true;
+ res.Id = prop.ulVal;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ }
+ return S_OK;
+}
+
+#endif
+
+
+HRESULT CArchiveExtractCallback::Read_fi_Props()
+{
+ IInArchive *archive = _arc->Archive;
+ const UInt32 index = _index;
+
+ _fi.Attrib_Defined = false;
+
+ #ifndef _WIN32
+ _fi.Owner.Clear();
+ _fi.Group.Clear();
+ #endif
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidPosixAttrib, &prop))
+ if (prop.vt == VT_UI4)
+ {
+ _fi.SetFromPosixAttrib(prop.ulVal);
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidAttrib, &prop))
+ if (prop.vt == VT_UI4)
+ {
+ _fi.Attrib = prop.ulVal;
+ _fi.Attrib_Defined = true;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ }
+
+ RINOK(GetTime(index, kpidCTime, _fi.CTime))
+ RINOK(GetTime(index, kpidATime, _fi.ATime))
+ RINOK(GetTime(index, kpidMTime, _fi.MTime))
+
+ #ifndef _WIN32
+ if (_ntOptions.ExtractOwner)
+ {
+ // SendMessageError_with_LastError("_ntOptions.ExtractOwner", _diskFilePath);
+ GetOwner(archive, index, kpidUser, kpidUserId, _fi.Owner);
+ GetOwner(archive, index, kpidGroup, kpidGroupId, _fi.Group);
+ }
+ #endif
+
+ return S_OK;
+}
+
+
+
+void CArchiveExtractCallback::CorrectPathParts()
+{
+ UStringVector &pathParts = _item.PathParts;
+
+ #ifdef SUPPORT_ALT_STREAMS
+ if (!_item.IsAltStream
+ || !pathParts.IsEmpty()
+ || !(_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt))
+ #endif
+ Correct_FsPath(_pathMode == NExtract::NPathMode::kAbsPaths, _keepAndReplaceEmptyDirPrefixes, pathParts, _item.MainIsDir);
+
+ #ifdef SUPPORT_ALT_STREAMS
+
+ if (_item.IsAltStream)
+ {
+ UString s (_item.AltStreamName);
+ Correct_AltStream_Name(s);
+ bool needColon = true;
+
+ if (pathParts.IsEmpty())
+ {
+ pathParts.AddNew();
+ if (_removePartsForAltStreams || _pathMode == NExtract::NPathMode::kNoPathsAlt)
+ needColon = false;
+ }
+ #ifdef _WIN32
+ else if (_pathMode == NExtract::NPathMode::kAbsPaths &&
+ NWildcard::GetNumPrefixParts_if_DrivePath(pathParts) == pathParts.Size())
+ pathParts.AddNew();
+ #endif
+
+ UString &name = pathParts.Back();
+ if (needColon)
+ name += (char)(_ntOptions.ReplaceColonForAltStream ? '_' : ':');
+ name += s;
+ }
+
+ #endif // SUPPORT_ALT_STREAMS
+}
+
+
+void CArchiveExtractCallback::GetFiTimesCAM(CFiTimesCAM &pt)
+{
+ pt.CTime_Defined = false;
+ pt.ATime_Defined = false;
+ pt.MTime_Defined = false;
+
+ if (Write_MTime)
+ {
+ if (_fi.MTime.Def)
+ {
+ _fi.MTime.Write_To_FiTime(pt.MTime);
+ pt.MTime_Defined = true;
+ }
+ else if (_arc->MTime.Def)
+ {
+ _arc->MTime.Write_To_FiTime(pt.MTime);
+ pt.MTime_Defined = true;
+ }
+ }
+
+ if (Write_CTime && _fi.CTime.Def)
+ {
+ _fi.CTime.Write_To_FiTime(pt.CTime);
+ pt.CTime_Defined = true;
+ }
+
+ if (Write_ATime && _fi.ATime.Def)
+ {
+ _fi.ATime.Write_To_FiTime(pt.ATime);
+ pt.ATime_Defined = true;
+ }
+}
+
+
+void CArchiveExtractCallback::CreateFolders()
+{
+ // 21.04 : we don't change original (_item.PathParts) here
+ UStringVector pathParts = _item.PathParts;
+
+ if (!pathParts.IsEmpty())
+ {
+ /* v23: if we extract symlink, and we know that it links to dir:
+ Linux: we don't create dir item (symlink_from_path) here.
+ Windows: SetReparseData() will create dir item, if it doesn't exist,
+ but if we create dir item here, it's not problem. */
+ if (!_item.IsDir
+ #ifdef SUPPORT_LINKS
+ #ifndef WIN32
+ || !_link.linkPath.IsEmpty()
+ #endif
+ #endif
+ )
+ pathParts.DeleteBack();
+ }
+
+ if (pathParts.IsEmpty())
+ return;
+
+ FString fullPathNew;
+ CreateComplexDirectory(pathParts, fullPathNew);
+
+ if (!_item.IsDir)
+ return;
+
+ if (_itemFailure)
+ return;
+
+ CDirPathTime pt;
+ GetFiTimesCAM(pt);
+
+ if (pt.IsSomeTimeDefined())
+ {
+ pt.Path = fullPathNew;
+ pt.SetDirTime();
+ _extractedFolders.Add(pt);
+ }
+}
+
+
+
+/*
+ CheckExistFile(fullProcessedPath)
+ it can change: fullProcessedPath, _isRenamed, _overwriteMode
+ (needExit = true) means that we must exit GetStream() even for S_OK result.
+*/
+
+HRESULT CArchiveExtractCallback::CheckExistFile(FString &fullProcessedPath, bool &needExit)
+{
+ needExit = true; // it was set already before
+
+ NFind::CFileInfo fileInfo;
+
+ if (fileInfo.Find(fullProcessedPath))
+ {
+ if (_overwriteMode == NExtract::NOverwriteMode::kSkip)
+ return S_OK;
+
+ if (_overwriteMode == NExtract::NOverwriteMode::kAsk)
+ {
+ const int slashPos = fullProcessedPath.ReverseFind_PathSepar();
+ const FString realFullProcessedPath = fullProcessedPath.Left((unsigned)(slashPos + 1)) + fileInfo.Name;
+
+ /* (fileInfo) can be symbolic link.
+ we can show final file properties here. */
+
+ FILETIME ft1;
+ FiTime_To_FILETIME(fileInfo.MTime, ft1);
+
+ Int32 overwriteResult;
+ RINOK(_extractCallback2->AskOverwrite(
+ fs2us(realFullProcessedPath), &ft1, &fileInfo.Size, _item.Path,
+ _fi.MTime.Def ? &_fi.MTime.FT : NULL,
+ _curSize_Defined ? &_curSize : NULL,
+ &overwriteResult))
+
+ switch (overwriteResult)
+ {
+ case NOverwriteAnswer::kCancel:
+ return E_ABORT;
+ case NOverwriteAnswer::kNo:
+ return S_OK;
+ case NOverwriteAnswer::kNoToAll:
+ _overwriteMode = NExtract::NOverwriteMode::kSkip;
+ return S_OK;
+
+ case NOverwriteAnswer::kYes:
+ break;
+ case NOverwriteAnswer::kYesToAll:
+ _overwriteMode = NExtract::NOverwriteMode::kOverwrite;
+ break;
+ case NOverwriteAnswer::kAutoRename:
+ _overwriteMode = NExtract::NOverwriteMode::kRename;
+ break;
+ default:
+ return E_FAIL;
+ }
+ } // NExtract::NOverwriteMode::kAsk
+
+ if (_overwriteMode == NExtract::NOverwriteMode::kRename)
+ {
+ if (!AutoRenamePath(fullProcessedPath))
+ {
+ RINOK(SendMessageError(kCantAutoRename, fullProcessedPath))
+ return E_FAIL;
+ }
+ _isRenamed = true;
+ }
+ else if (_overwriteMode == NExtract::NOverwriteMode::kRenameExisting)
+ {
+ FString existPath (fullProcessedPath);
+ if (!AutoRenamePath(existPath))
+ {
+ RINOK(SendMessageError(kCantAutoRename, fullProcessedPath))
+ return E_FAIL;
+ }
+ // MyMoveFile can rename folders. So it's OK to use it for folders too
+ if (!MyMoveFile(fullProcessedPath, existPath))
+ {
+ HRESULT errorCode = GetLastError_noZero_HRESULT();
+ RINOK(SendMessageError2(errorCode, kCantRenameFile, existPath, fullProcessedPath))
+ return E_FAIL;
+ }
+ }
+ else // not Rename*
+ {
+ if (fileInfo.IsDir())
+ {
+ // do we need to delete all files in folder?
+ if (!RemoveDir(fullProcessedPath))
+ {
+ RINOK(SendMessageError_with_LastError(kCantDeleteOutputDir, fullProcessedPath))
+ return S_OK;
+ }
+ }
+ else // fileInfo is not Dir
+ {
+ if (NFind::DoesFileExist_Raw(fullProcessedPath))
+ if (!DeleteFileAlways(fullProcessedPath))
+ if (GetLastError() != ERROR_FILE_NOT_FOUND) // check it in linux
+ {
+ RINOK(SendMessageError_with_LastError(kCantDeleteOutputFile, fullProcessedPath))
+ return S_OK;
+ // return E_FAIL;
+ }
+ } // fileInfo is not Dir
+ } // not Rename*
+ }
+ else // not Find(fullProcessedPath)
+ {
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ // we need to clear READ-ONLY of parent before creating alt stream
+ int colonPos = NName::FindAltStreamColon(fullProcessedPath);
+ if (colonPos >= 0 && fullProcessedPath[(unsigned)colonPos + 1] != 0)
+ {
+ FString parentFsPath (fullProcessedPath);
+ parentFsPath.DeleteFrom((unsigned)colonPos);
+ NFind::CFileInfo parentFi;
+ if (parentFi.Find(parentFsPath))
+ {
+ if (parentFi.IsReadOnly())
+ SetFileAttrib(parentFsPath, parentFi.Attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY);
+ }
+ }
+ #endif // defined(_WIN32) && !defined(UNDER_CE)
+ }
+
+ needExit = false;
+ return S_OK;
+}
+
+
+
+
+
+
+HRESULT CArchiveExtractCallback::GetExtractStream(CMyComPtr<ISequentialOutStream> &outStreamLoc, bool &needExit)
+{
+ needExit = true;
+
+ RINOK(Read_fi_Props())
+
+ #ifdef SUPPORT_LINKS
+ IInArchive *archive = _arc->Archive;
+ #endif
+
+ const UInt32 index = _index;
+
+ bool isAnti = false;
+ RINOK(_arc->IsItem_Anti(index, isAnti))
+
+ CorrectPathParts();
+ UString processedPath (MakePathFromParts(_item.PathParts));
+
+ if (!isAnti)
+ {
+ // 21.04: CreateFolders doesn't change (_item.PathParts)
+ CreateFolders();
+ }
+
+ FString fullProcessedPath (us2fs(processedPath));
+ if (_pathMode != NExtract::NPathMode::kAbsPaths
+ || !NName::IsAbsolutePath(processedPath))
+ {
+ fullProcessedPath = MakePath_from_2_Parts(_dirPathPrefix, fullProcessedPath);
+ }
+
+ #ifdef SUPPORT_ALT_STREAMS
+ if (_item.IsAltStream && _item.ParentIndex != (UInt32)(Int32)-1)
+ {
+ const int renIndex = _renamedFiles.FindInSorted(CIndexToPathPair(_item.ParentIndex));
+ if (renIndex != -1)
+ {
+ const CIndexToPathPair &pair = _renamedFiles[(unsigned)renIndex];
+ fullProcessedPath = pair.Path;
+ fullProcessedPath += ':';
+ UString s (_item.AltStreamName);
+ Correct_AltStream_Name(s);
+ fullProcessedPath += us2fs(s);
+ }
+ }
+ #endif // SUPPORT_ALT_STREAMS
+
+ if (_item.IsDir)
+ {
+ _diskFilePath = fullProcessedPath;
+ if (isAnti)
+ RemoveDir(_diskFilePath);
+ #ifdef SUPPORT_LINKS
+ if (_link.linkPath.IsEmpty())
+ #endif
+ {
+ if (!isAnti)
+ SetAttrib();
+ return S_OK;
+ }
+ }
+ else if (!_isSplit)
+ {
+ RINOK(CheckExistFile(fullProcessedPath, needExit))
+ if (needExit)
+ return S_OK;
+ needExit = true;
+ }
+
+ _diskFilePath = fullProcessedPath;
+
+
+ if (isAnti)
+ {
+ needExit = false;
+ return S_OK;
+ }
+
+ // not anti
+
+ #ifdef SUPPORT_LINKS
+
+ if (!_link.linkPath.IsEmpty())
+ {
+ #ifndef UNDER_CE
+ {
+ bool linkWasSet = false;
+ RINOK(SetFromLinkPath(fullProcessedPath, _link, linkWasSet))
+ if (linkWasSet)
+ {
+ _isSymLinkCreated = _link.IsSymLink();
+ SetAttrib();
+ // printf("\nlinkWasSet %s\n", GetAnsiString(_diskFilePath));
+ }
+ }
+ #endif // UNDER_CE
+
+ // if (_copyFile_Path.IsEmpty())
+ {
+ needExit = false;
+ return S_OK;
+ }
+ }
+
+ if (!_hardLinks.IDs.IsEmpty() && !_item.IsAltStream && !_item.IsDir)
+ {
+ CHardLinkNode h;
+ bool defined;
+ RINOK(Archive_Get_HardLinkNode(archive, index, h, defined))
+ if (defined)
+ {
+ const int linkIndex = _hardLinks.IDs.FindInSorted2(h);
+ if (linkIndex != -1)
+ {
+ FString &hl = _hardLinks.Links[(unsigned)linkIndex];
+ if (hl.IsEmpty())
+ hl = fullProcessedPath;
+ else
+ {
+ if (!MyCreateHardLink(fullProcessedPath, hl))
+ {
+ HRESULT errorCode = GetLastError_noZero_HRESULT();
+ RINOK(SendMessageError2(errorCode, kCantCreateHardLink, fullProcessedPath, hl))
+ return S_OK;
+ }
+
+ // printf("\nHard linkWasSet Archive_Get_HardLinkNode %s\n", GetAnsiString(_diskFilePath));
+ // _needSetAttrib = true; // do we need to set attribute ?
+ SetAttrib();
+ needExit = false;
+ return S_OK;
+ }
+ }
+ }
+ }
+
+ #endif // SUPPORT_LINKS
+
+
+ // ---------- CREATE WRITE FILE -----
+
+ _outFileStreamSpec = new COutFileStream;
+ CMyComPtr<IOutStream> outFileStream_Loc(_outFileStreamSpec);
+
+ if (!_outFileStreamSpec->Open(fullProcessedPath, _isSplit ? OPEN_ALWAYS: CREATE_ALWAYS))
+ {
+ // if (::GetLastError() != ERROR_FILE_EXISTS || !isSplit)
+ {
+ RINOK(SendMessageError_with_LastError(kCantOpenOutFile, fullProcessedPath))
+ return S_OK;
+ }
+ }
+
+ _needSetAttrib = true;
+
+ bool is_SymLink_in_Data = false;
+
+ if (_curSize_Defined && _curSize > 0 && _curSize < (1 << 12))
+ {
+ if (_fi.IsLinuxSymLink())
+ {
+ is_SymLink_in_Data = true;
+ _is_SymLink_in_Data_Linux = true;
+ }
+ else if (_fi.IsReparse())
+ {
+ is_SymLink_in_Data = true;
+ _is_SymLink_in_Data_Linux = false;
+ }
+ }
+
+ if (is_SymLink_in_Data)
+ {
+ _outMemBuf.Alloc((size_t)_curSize);
+ _bufPtrSeqOutStream_Spec = new CBufPtrSeqOutStream;
+ _bufPtrSeqOutStream = _bufPtrSeqOutStream_Spec;
+ _bufPtrSeqOutStream_Spec->Init(_outMemBuf, _outMemBuf.Size());
+ outStreamLoc = _bufPtrSeqOutStream;
+ }
+ else // not reprase
+ {
+ if (_ntOptions.PreAllocateOutFile && !_isSplit && _curSize_Defined && _curSize > (1 << 12))
+ {
+ // UInt64 ticks = GetCpuTicks();
+ _fileLength_that_WasSet = _curSize;
+ bool res = _outFileStreamSpec->File.SetLength(_curSize);
+ _fileLength_WasSet = res;
+
+ // ticks = GetCpuTicks() - ticks;
+ // printf("\nticks = %10d\n", (unsigned)ticks);
+ if (!res)
+ {
+ RINOK(SendMessageError_with_LastError(kCantSetFileLen, fullProcessedPath))
+ }
+
+ /*
+ _outFileStreamSpec->File.Close();
+ ticks = GetCpuTicks() - ticks;
+ printf("\nticks = %10d\n", (unsigned)ticks);
+ return S_FALSE;
+ */
+
+ /*
+ File.SetLength() on FAT (xp64): is fast, but then File.Close() can be slow,
+ if we don't write any data.
+ File.SetLength() for remote share file (exFAT) can be slow in some cases,
+ and the Windows can return "network error" after 1 minute,
+ while remote file still can grow.
+ We need some way to detect such bad cases and disable PreAllocateOutFile mode.
+ */
+
+ res = _outFileStreamSpec->SeekToBegin_bool();
+ if (!res)
+ {
+ RINOK(SendMessageError_with_LastError("Cannot seek to begin of file", fullProcessedPath))
+ }
+ } // PreAllocateOutFile
+
+ #ifdef SUPPORT_ALT_STREAMS
+ if (_isRenamed && !_item.IsAltStream)
+ {
+ CIndexToPathPair pair(index, fullProcessedPath);
+ unsigned oldSize = _renamedFiles.Size();
+ unsigned insertIndex = _renamedFiles.AddToUniqueSorted(pair);
+ if (oldSize == _renamedFiles.Size())
+ _renamedFiles[insertIndex].Path = fullProcessedPath;
+ }
+ #endif // SUPPORT_ALT_STREAMS
+
+ if (_isSplit)
+ {
+ RINOK(outFileStream_Loc->Seek((Int64)_position, STREAM_SEEK_SET, NULL))
+ }
+ outStreamLoc = outFileStream_Loc;
+ } // if not reprase
+
+ _outFileStream = outFileStream_Loc;
+
+ needExit = false;
+ return S_OK;
+}
+
+
+
+HRESULT CArchiveExtractCallback::GetItem(UInt32 index)
+{
+ #ifndef Z7_SFX
+ _item._use_baseParentFolder_mode = _use_baseParentFolder_mode;
+ if (_use_baseParentFolder_mode)
+ {
+ _item._baseParentFolder = (int)_baseParentFolder;
+ if (_pathMode == NExtract::NPathMode::kFullPaths ||
+ _pathMode == NExtract::NPathMode::kAbsPaths)
+ _item._baseParentFolder = -1;
+ }
+ #endif // Z7_SFX
+
+ #ifdef SUPPORT_ALT_STREAMS
+ _item.WriteToAltStreamIfColon = _ntOptions.WriteToAltStreamIfColon;
+ #endif
+
+ return _arc->GetItem(index, _item);
+}
+
+
+Z7_COM7F_IMF(CArchiveExtractCallback::GetStream(UInt32 index, ISequentialOutStream **outStream, Int32 askExtractMode))
+{
+ COM_TRY_BEGIN
+
+ *outStream = NULL;
+
+ #ifndef Z7_SFX
+ if (_hashStream)
+ _hashStreamSpec->ReleaseStream();
+ _hashStreamWasUsed = false;
+ #endif
+
+ _outFileStream.Release();
+ _bufPtrSeqOutStream.Release();
+
+ _encrypted = false;
+ _position = 0;
+ _isSplit = false;
+
+ _curSize = 0;
+ _curSize_Defined = false;
+ _fileLength_WasSet = false;
+ _fileLength_that_WasSet = 0;
+ _index = index;
+
+ _diskFilePath.Empty();
+
+ _isRenamed = false;
+
+ // _fi.Clear();
+
+ // _is_SymLink_in_Data = false;
+ _is_SymLink_in_Data_Linux = false;
+
+ _needSetAttrib = false;
+ _isSymLinkCreated = false;
+ _itemFailure = false;
+
+ #ifdef SUPPORT_LINKS
+ // _copyFile_Path.Empty();
+ _link.Clear();
+ #endif
+
+ _extractMode = false;
+
+ switch (askExtractMode)
+ {
+ case NArchive::NExtract::NAskMode::kExtract:
+ if (_testMode)
+ {
+ // askExtractMode = NArchive::NExtract::NAskMode::kTest;
+ }
+ else
+ _extractMode = true;
+ break;
+ }
+
+
+ IInArchive *archive = _arc->Archive;
+
+ RINOK(GetItem(index))
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidPosition, &prop))
+ if (prop.vt != VT_EMPTY)
+ {
+ if (prop.vt != VT_UI8)
+ return E_FAIL;
+ _position = prop.uhVal.QuadPart;
+ _isSplit = true;
+ }
+ }
+
+ #ifdef SUPPORT_LINKS
+ RINOK(ReadLink())
+ #endif // SUPPORT_LINKS
+
+
+ RINOK(Archive_GetItemBoolProp(archive, index, kpidEncrypted, _encrypted))
+
+ RINOK(GetUnpackSize())
+
+ #ifdef SUPPORT_ALT_STREAMS
+ if (!_ntOptions.AltStreams.Val && _item.IsAltStream)
+ return S_OK;
+ #endif // SUPPORT_ALT_STREAMS
+
+ // we can change (_item.PathParts) in this function
+ UStringVector &pathParts = _item.PathParts;
+
+ if (_wildcardCensor)
+ {
+ if (!CensorNode_CheckPath(*_wildcardCensor, _item))
+ return S_OK;
+ }
+
+ #ifndef Z7_SFX
+ if (_use_baseParentFolder_mode)
+ {
+ if (!pathParts.IsEmpty())
+ {
+ unsigned numRemovePathParts = 0;
+
+ #ifdef SUPPORT_ALT_STREAMS
+ if (_pathMode == NExtract::NPathMode::kNoPathsAlt && _item.IsAltStream)
+ numRemovePathParts = pathParts.Size();
+ else
+ #endif
+ if (_pathMode == NExtract::NPathMode::kNoPaths ||
+ _pathMode == NExtract::NPathMode::kNoPathsAlt)
+ numRemovePathParts = pathParts.Size() - 1;
+ pathParts.DeleteFrontal(numRemovePathParts);
+ }
+ }
+ else
+ #endif // Z7_SFX
+ {
+ if (pathParts.IsEmpty())
+ {
+ if (_item.IsDir)
+ return S_OK;
+ /*
+ #ifdef SUPPORT_ALT_STREAMS
+ if (!_item.IsAltStream)
+ #endif
+ return E_FAIL;
+ */
+ }
+
+ unsigned numRemovePathParts = 0;
+
+ switch (_pathMode)
+ {
+ case NExtract::NPathMode::kFullPaths:
+ case NExtract::NPathMode::kCurPaths:
+ {
+ if (_removePathParts.IsEmpty())
+ break;
+ bool badPrefix = false;
+
+ if (pathParts.Size() < _removePathParts.Size())
+ badPrefix = true;
+ else
+ {
+ if (pathParts.Size() == _removePathParts.Size())
+ {
+ if (_removePartsForAltStreams)
+ {
+ #ifdef SUPPORT_ALT_STREAMS
+ if (!_item.IsAltStream)
+ #endif
+ badPrefix = true;
+ }
+ else
+ {
+ if (!_item.MainIsDir)
+ badPrefix = true;
+ }
+ }
+
+ if (!badPrefix)
+ FOR_VECTOR (i, _removePathParts)
+ {
+ if (CompareFileNames(_removePathParts[i], pathParts[i]) != 0)
+ {
+ badPrefix = true;
+ break;
+ }
+ }
+ }
+
+ if (badPrefix)
+ {
+ if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode)
+ return E_FAIL;
+ }
+ else
+ numRemovePathParts = _removePathParts.Size();
+ break;
+ }
+
+ case NExtract::NPathMode::kNoPaths:
+ {
+ if (!pathParts.IsEmpty())
+ numRemovePathParts = pathParts.Size() - 1;
+ break;
+ }
+ case NExtract::NPathMode::kNoPathsAlt:
+ {
+ #ifdef SUPPORT_ALT_STREAMS
+ if (_item.IsAltStream)
+ numRemovePathParts = pathParts.Size();
+ else
+ #endif
+ if (!pathParts.IsEmpty())
+ numRemovePathParts = pathParts.Size() - 1;
+ break;
+ }
+ case NExtract::NPathMode::kAbsPaths:
+ // default:
+ break;
+ }
+
+ pathParts.DeleteFrontal(numRemovePathParts);
+ }
+
+
+ #ifndef Z7_SFX
+
+ if (ExtractToStreamCallback)
+ {
+ if (!GetProp)
+ {
+ GetProp_Spec = new CGetProp;
+ GetProp = GetProp_Spec;
+ }
+ GetProp_Spec->Arc = _arc;
+ GetProp_Spec->IndexInArc = index;
+ UString name (MakePathFromParts(pathParts));
+
+ #ifdef SUPPORT_ALT_STREAMS
+ if (_item.IsAltStream)
+ {
+ if (!pathParts.IsEmpty() || (!_removePartsForAltStreams && _pathMode != NExtract::NPathMode::kNoPathsAlt))
+ name += ':';
+ name += _item.AltStreamName;
+ }
+ #endif
+
+ return ExtractToStreamCallback->GetStream7(name, BoolToInt(_item.IsDir), outStream, askExtractMode, GetProp);
+ }
+
+ #endif // Z7_SFX
+
+
+ CMyComPtr<ISequentialOutStream> outStreamLoc;
+
+ if (askExtractMode == NArchive::NExtract::NAskMode::kExtract && !_testMode)
+ {
+ if (_stdOutMode)
+ outStreamLoc = new CStdOutFileStream;
+ else
+ {
+ bool needExit = true;
+ RINOK(GetExtractStream(outStreamLoc, needExit))
+ if (needExit)
+ return S_OK;
+ }
+ }
+
+ #ifndef Z7_SFX
+ if (_hashStream)
+ {
+ if (askExtractMode == NArchive::NExtract::NAskMode::kExtract ||
+ askExtractMode == NArchive::NExtract::NAskMode::kTest)
+ {
+ _hashStreamSpec->SetStream(outStreamLoc);
+ outStreamLoc = _hashStream;
+ _hashStreamSpec->Init(true);
+ _hashStreamWasUsed = true;
+ }
+ }
+ #endif // Z7_SFX
+
+ if (outStreamLoc)
+ {
+ /*
+ #ifdef SUPPORT_LINKS
+ if (!_copyFile_Path.IsEmpty())
+ {
+ RINOK(PrepareOperation(askExtractMode));
+ RINOK(MyCopyFile(outStreamLoc));
+ return SetOperationResult(NArchive::NExtract::NOperationResult::kOK);
+ }
+ if (_link.isCopyLink && _testMode)
+ return S_OK;
+ #endif
+ */
+ *outStream = outStreamLoc.Detach();
+ }
+
+ return S_OK;
+
+ COM_TRY_END
+}
+
+
+
+
+
+
+
+
+
+
+
+Z7_COM7F_IMF(CArchiveExtractCallback::PrepareOperation(Int32 askExtractMode))
+{
+ COM_TRY_BEGIN
+
+ #ifndef Z7_SFX
+ if (ExtractToStreamCallback)
+ return ExtractToStreamCallback->PrepareOperation7(askExtractMode);
+ #endif
+
+ _extractMode = false;
+
+ switch (askExtractMode)
+ {
+ case NArchive::NExtract::NAskMode::kExtract:
+ if (_testMode)
+ askExtractMode = NArchive::NExtract::NAskMode::kTest;
+ else
+ _extractMode = true;
+ break;
+ }
+
+ return _extractCallback2->PrepareOperation(_item.Path, BoolToInt(_item.IsDir),
+ askExtractMode, _isSplit ? &_position: NULL);
+
+ COM_TRY_END
+}
+
+
+
+
+
+HRESULT CArchiveExtractCallback::CloseFile()
+{
+ if (!_outFileStream)
+ return S_OK;
+
+ HRESULT hres = S_OK;
+
+ const UInt64 processedSize = _outFileStreamSpec->ProcessedSize;
+ if (_fileLength_WasSet && _fileLength_that_WasSet > processedSize)
+ {
+ const bool res = _outFileStreamSpec->File.SetLength(processedSize);
+ _fileLength_WasSet = res;
+ if (!res)
+ {
+ const HRESULT hres2 = SendMessageError_with_LastError(kCantSetFileLen, us2fs(_item.Path));
+ if (hres == S_OK)
+ hres = hres2;
+ }
+ }
+
+ _curSize = processedSize;
+ _curSize_Defined = true;
+
+ #if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
+ if (ZoneBuf.Size() != 0
+ && !_item.IsAltStream)
+ {
+ // if (NFind::DoesFileExist_Raw(tempFilePath))
+ if (ZoneMode != NExtract::NZoneIdMode::kOffice ||
+ FindExt2(kOfficeExtensions, fs2us(_diskFilePath)))
+ {
+ // we must write zone file before setting of timestamps
+ const FString path = _diskFilePath + k_ZoneId_StreamName;
+ if (!WriteZoneFile(path, ZoneBuf))
+ {
+ // we can't write it in FAT
+ // SendMessageError_with_LastError("Can't write Zone.Identifier stream", path);
+ }
+ }
+ }
+ #endif
+
+ CFiTimesCAM t;
+ GetFiTimesCAM(t);
+
+ // #ifdef _WIN32
+ if (t.IsSomeTimeDefined())
+ _outFileStreamSpec->SetTime(
+ t.CTime_Defined ? &t.CTime : NULL,
+ t.ATime_Defined ? &t.ATime : NULL,
+ t.MTime_Defined ? &t.MTime : NULL);
+ // #endif
+
+ RINOK(_outFileStreamSpec->Close())
+ _outFileStream.Release();
+ return hres;
+}
+
+
+#ifdef SUPPORT_LINKS
+
+
+HRESULT CArchiveExtractCallback::SetFromLinkPath(
+ const FString &fullProcessedPath,
+ const CLinkInfo &linkInfo,
+ bool &linkWasSet)
+{
+ linkWasSet = false;
+ if (!_ntOptions.SymLinks.Val && !linkInfo.isHardLink)
+ return S_OK;
+
+ UString relatPath;
+
+ /* if (linkInfo.isRelative)
+ linkInfo.linkPath is final link path that must be stored to file link field
+ else
+ linkInfo.linkPath is path from root of archive. So we must add _dirPathPrefix_Full before linkPath.
+ */
+
+ if (linkInfo.isRelative)
+ relatPath = GetDirPrefixOf(_item.Path);
+ relatPath += linkInfo.linkPath;
+
+ if (!IsSafePath(relatPath))
+ {
+ return SendMessageError2(
+ 0, // errorCode
+ "Dangerous link path was ignored",
+ us2fs(_item.Path),
+ us2fs(linkInfo.linkPath)); // us2fs(relatPath)
+ }
+
+ FString existPath;
+ if (linkInfo.isHardLink /* || linkInfo.IsCopyLink */ || !linkInfo.isRelative)
+ {
+ if (!NName::GetFullPath(_dirPathPrefix_Full, us2fs(relatPath), existPath))
+ {
+ RINOK(SendMessageError("Incorrect path", us2fs(relatPath)))
+ }
+ }
+ else
+ {
+ existPath = us2fs(linkInfo.linkPath);
+ // printf("\nlinkPath = : %s\n", GetOemString(linkInfo.linkPath).Ptr());
+ }
+
+ if (existPath.IsEmpty())
+ return SendMessageError("Empty link", fullProcessedPath);
+
+ if (linkInfo.isHardLink /* || linkInfo.IsCopyLink */)
+ {
+ // if (linkInfo.isHardLink)
+ {
+ if (!MyCreateHardLink(fullProcessedPath, existPath))
+ {
+ const HRESULT errorCode = GetLastError_noZero_HRESULT();
+ RINOK(SendMessageError2(errorCode, kCantCreateHardLink, fullProcessedPath, existPath))
+ }
+ linkWasSet = true;
+ return S_OK;
+ }
+ /*
+ // IsCopyLink
+ {
+ NFind::CFileInfo fi;
+ if (!fi.Find(existPath))
+ {
+ RINOK(SendMessageError2("Cannot find the file for copying", existPath, fullProcessedPath));
+ }
+ else
+ {
+ if (_curSize_Defined && _curSize == fi.Size)
+ _copyFile_Path = existPath;
+ else
+ {
+ RINOK(SendMessageError2("File size collision for file copying", existPath, fullProcessedPath));
+ }
+ // RINOK(MyCopyFile(existPath, fullProcessedPath));
+ }
+ }
+ */
+ }
+
+ // is Symbolic link
+
+ /*
+ if (_item.IsDir && !isRelative)
+ {
+ // Windows before Vista doesn't support symbolic links.
+ // we could convert such symbolic links to Junction Points
+ // isJunction = true;
+ // convertToAbs = true;
+ }
+ */
+
+ if (!_ntOptions.SymLinks_AllowDangerous.Val)
+ {
+ #ifdef _WIN32
+ if (_item.IsDir)
+ #endif
+ if (linkInfo.isRelative)
+ {
+ CLinkLevelsInfo levelsInfo;
+ levelsInfo.Parse(linkInfo.linkPath);
+ if (levelsInfo.FinalLevel < 1 || levelsInfo.IsAbsolute)
+ {
+ return SendMessageError2(
+ 0, // errorCode
+ "Dangerous symbolic link path was ignored",
+ us2fs(_item.Path),
+ us2fs(linkInfo.linkPath));
+ }
+ }
+ }
+
+
+ #ifdef _WIN32
+
+ CByteBuffer data;
+ // printf("\nFillLinkData(): %s\n", GetOemString(existPath).Ptr());
+ if (!FillLinkData(data, fs2us(existPath), !linkInfo.isJunction, linkInfo.isWSL))
+ return SendMessageError("Cannot fill link data", us2fs(_item.Path));
+
+ /*
+ if (NtReparse_Size != data.Size() || memcmp(NtReparse_Data, data, data.Size()) != 0)
+ {
+ SendMessageError("reconstructed Reparse is different", fs2us(existPath));
+ }
+ */
+
+ CReparseAttr attr;
+ if (!attr.Parse(data, data.Size()))
+ {
+ RINOK(SendMessageError("Internal error for symbolic link file", us2fs(_item.Path)))
+ return S_OK;
+ }
+ if (!NFile::NIO::SetReparseData(fullProcessedPath, _item.IsDir, data, (DWORD)data.Size()))
+ {
+ RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath))
+ return S_OK;
+ }
+ linkWasSet = true;
+
+ return S_OK;
+
+
+ #else // ! _WIN32
+
+ if (!NFile::NIO::SetSymLink(fullProcessedPath, existPath))
+ {
+ RINOK(SendMessageError_with_LastError(kCantCreateSymLink, fullProcessedPath))
+ return S_OK;
+ }
+ linkWasSet = true;
+
+ return S_OK;
+
+ #endif // ! _WIN32
+}
+
+
+bool CLinkInfo::Parse(const Byte *data, size_t dataSize, bool isLinuxData)
+{
+ Clear();
+ // this->isLinux = isLinuxData;
+
+ if (isLinuxData)
+ {
+ isJunction = false;
+ isHardLink = false;
+ AString utf;
+ if (dataSize >= (1 << 12))
+ return false;
+ utf.SetFrom_CalcLen((const char *)data, (unsigned)dataSize);
+ UString u;
+ if (!ConvertUTF8ToUnicode(utf, u))
+ return false;
+ linkPath = u;
+
+ // in linux symbolic data: we expect that linux separator '/' is used
+ // if windows link was created, then we also must use linux separator
+ if (u.IsEmpty())
+ return false;
+ const wchar_t c = u[0];
+ isRelative = !IS_PATH_SEPAR(c);
+ return true;
+ }
+
+ CReparseAttr reparse;
+ if (!reparse.Parse(data, dataSize))
+ return false;
+ isHardLink = false;
+ // isCopyLink = false;
+ linkPath = reparse.GetPath();
+ isJunction = reparse.IsMountPoint();
+
+ if (reparse.IsSymLink_WSL())
+ {
+ isWSL = true;
+ isRelative = reparse.IsRelative_WSL();
+ }
+ else
+ isRelative = reparse.IsRelative_Win();
+
+ // FIXME !!!
+ #ifndef _WIN32
+ linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
+ #endif
+
+ return true;
+}
+
+#endif // SUPPORT_LINKS
+
+
+HRESULT CArchiveExtractCallback::CloseReparseAndFile()
+{
+ HRESULT res = S_OK;
+
+ #ifdef SUPPORT_LINKS
+
+ size_t reparseSize = 0;
+ bool repraseMode = false;
+ bool needSetReparse = false;
+ CLinkInfo linkInfo;
+
+ if (_bufPtrSeqOutStream)
+ {
+ repraseMode = true;
+ reparseSize = _bufPtrSeqOutStream_Spec->GetPos();
+ if (_curSize_Defined && reparseSize == _outMemBuf.Size())
+ {
+ /*
+ CReparseAttr reparse;
+ DWORD errorCode = 0;
+ needSetReparse = reparse.Parse(_outMemBuf, reparseSize, errorCode);
+ if (needSetReparse)
+ {
+ UString linkPath = reparse.GetPath();
+ #ifndef _WIN32
+ linkPath.Replace(L'\\', WCHAR_PATH_SEPARATOR);
+ #endif
+ }
+ */
+ needSetReparse = linkInfo.Parse(_outMemBuf, reparseSize, _is_SymLink_in_Data_Linux);
+ if (!needSetReparse)
+ res = SendMessageError_with_LastError("Incorrect reparse stream", us2fs(_item.Path));
+ }
+ else
+ {
+ res = SendMessageError_with_LastError("Unknown reparse stream", us2fs(_item.Path));
+ }
+ if (!needSetReparse && _outFileStream)
+ {
+ const HRESULT res2 = WriteStream(_outFileStream, _outMemBuf, reparseSize);
+ if (res == S_OK)
+ res = res2;
+ }
+ _bufPtrSeqOutStream.Release();
+ }
+
+ #endif // SUPPORT_LINKS
+
+
+ const HRESULT res2 = CloseFile();
+
+ if (res == S_OK)
+ res = res2;
+
+ RINOK(res)
+
+ #ifdef SUPPORT_LINKS
+ if (repraseMode)
+ {
+ _curSize = reparseSize;
+ _curSize_Defined = true;
+
+ #ifdef SUPPORT_LINKS
+ if (needSetReparse)
+ {
+ // in Linux : we must delete empty file before symbolic link creation
+ // in Windows : we can create symbolic link even without file deleting
+ if (!DeleteFileAlways(_diskFilePath))
+ {
+ RINOK(SendMessageError_with_LastError("can't delete file", _diskFilePath))
+ }
+ {
+ /*
+ // for DEBUG ONLY: we can extract sym links as WSL links
+ // to eliminate (non-admin) errors for sym links.
+ #ifdef _WIN32
+ if (!linkInfo.isHardLink && !linkInfo.isJunction)
+ linkInfo.isWSL = true;
+ #endif
+ */
+ bool linkWasSet = false;
+ RINOK(SetFromLinkPath(_diskFilePath, linkInfo, linkWasSet))
+ if (linkWasSet)
+ _isSymLinkCreated = linkInfo.IsSymLink();
+ else
+ _needSetAttrib = false;
+ }
+ /*
+ if (!NFile::NIO::SetReparseData(_diskFilePath, _item.IsDir, ))
+ {
+ res = SendMessageError_with_LastError(kCantCreateSymLink, _diskFilePath);
+ }
+ */
+ }
+ #endif
+ }
+ #endif
+ return res;
+}
+
+
+void CArchiveExtractCallback::SetAttrib()
+{
+ #ifndef _WIN32
+ // Linux now doesn't support permissions for symlinks
+ if (_isSymLinkCreated)
+ return;
+ #endif
+
+ if (_itemFailure
+ || _diskFilePath.IsEmpty()
+ || _stdOutMode
+ || !_extractMode)
+ return;
+
+ #ifndef _WIN32
+ if (_fi.Owner.Id_Defined &&
+ _fi.Group.Id_Defined)
+ {
+ if (my_chown(_diskFilePath, _fi.Owner.Id, _fi.Group.Id) != 0)
+ {
+ SendMessageError_with_LastError("Cannot set owner", _diskFilePath);
+ }
+ }
+ #endif
+
+ if (_fi.Attrib_Defined)
+ {
+ // const AString s = GetAnsiString(_diskFilePath);
+ // printf("\nSetFileAttrib_PosixHighDetect: %s: hex:%x\n", s.Ptr(), _fi.Attrib);
+ bool res = SetFileAttrib_PosixHighDetect(_diskFilePath, _fi.Attrib);
+ if (!res)
+ {
+ // do we need error message here in Windows and in posix?
+ SendMessageError_with_LastError("Cannot set file attribute", _diskFilePath);
+ }
+ }
+}
+
+
+Z7_COM7F_IMF(CArchiveExtractCallback::SetOperationResult(Int32 opRes))
+{
+ COM_TRY_BEGIN
+
+ // printf("\nCArchiveExtractCallback::SetOperationResult: %d %s\n", opRes, GetAnsiString(_diskFilePath));
+
+ #ifndef Z7_SFX
+ if (ExtractToStreamCallback)
+ {
+ GetUnpackSize();
+ return ExtractToStreamCallback->SetOperationResult8(opRes, BoolToInt(_encrypted), _curSize);
+ }
+ #endif
+
+ #ifndef Z7_SFX
+
+ if (_hashStreamWasUsed)
+ {
+ _hashStreamSpec->_hash->Final(_item.IsDir,
+ #ifdef SUPPORT_ALT_STREAMS
+ _item.IsAltStream
+ #else
+ false
+ #endif
+ , _item.Path);
+ _curSize = _hashStreamSpec->GetSize();
+ _curSize_Defined = true;
+ _hashStreamSpec->ReleaseStream();
+ _hashStreamWasUsed = false;
+ }
+
+ #endif // Z7_SFX
+
+ RINOK(CloseReparseAndFile())
+
+ #ifdef Z7_USE_SECURITY_CODE
+ if (!_stdOutMode && _extractMode && _ntOptions.NtSecurity.Val && _arc->GetRawProps)
+ {
+ const void *data;
+ UInt32 dataSize;
+ UInt32 propType;
+ _arc->GetRawProps->GetRawProp(_index, kpidNtSecure, &data, &dataSize, &propType);
+ if (dataSize != 0)
+ {
+ if (propType != NPropDataType::kRaw)
+ return E_FAIL;
+ if (CheckNtSecure((const Byte *)data, dataSize))
+ {
+ SECURITY_INFORMATION securInfo = DACL_SECURITY_INFORMATION | GROUP_SECURITY_INFORMATION | OWNER_SECURITY_INFORMATION;
+ if (_saclEnabled)
+ securInfo |= SACL_SECURITY_INFORMATION;
+ ::SetFileSecurityW(fs2us(_diskFilePath), securInfo, (PSECURITY_DESCRIPTOR)(void *)(const Byte *)(data));
+ }
+ }
+ }
+ #endif // Z7_USE_SECURITY_CODE
+
+ if (!_curSize_Defined)
+ GetUnpackSize();
+
+ if (_curSize_Defined)
+ {
+ #ifdef SUPPORT_ALT_STREAMS
+ if (_item.IsAltStream)
+ AltStreams_UnpackSize += _curSize;
+ else
+ #endif
+ UnpackSize += _curSize;
+ }
+
+ if (_item.IsDir)
+ NumFolders++;
+ #ifdef SUPPORT_ALT_STREAMS
+ else if (_item.IsAltStream)
+ NumAltStreams++;
+ #endif
+ else
+ NumFiles++;
+
+ if (_needSetAttrib)
+ SetAttrib();
+
+ RINOK(_extractCallback2->SetOperationResult(opRes, BoolToInt(_encrypted)))
+
+ return S_OK;
+
+ COM_TRY_END
+}
+
+
+
+Z7_COM7F_IMF(CArchiveExtractCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes))
+{
+ if (_folderArchiveExtractCallback2)
+ {
+ bool isEncrypted = false;
+ UString s;
+
+ if (indexType == NArchive::NEventIndexType::kInArcIndex && index != (UInt32)(Int32)-1)
+ {
+ CReadArcItem item;
+ RINOK(_arc->GetItem(index, item))
+ s = item.Path;
+ RINOK(Archive_GetItemBoolProp(_arc->Archive, index, kpidEncrypted, isEncrypted))
+ }
+ else
+ {
+ s = '#';
+ s.Add_UInt32(index);
+ // if (indexType == NArchive::NEventIndexType::kBlockIndex) {}
+ }
+
+ return _folderArchiveExtractCallback2->ReportExtractResult(opRes, isEncrypted, s);
+ }
+
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CArchiveExtractCallback::CryptoGetTextPassword(BSTR *password))
+{
+ COM_TRY_BEGIN
+ if (!_cryptoGetTextPassword)
+ {
+ RINOK(_extractCallback2.QueryInterface(IID_ICryptoGetTextPassword,
+ &_cryptoGetTextPassword))
+ }
+ return _cryptoGetTextPassword->CryptoGetTextPassword(password);
+ COM_TRY_END
+}
+
+
+// ---------- HASH functions ----------
+
+FString CArchiveExtractCallback::Hash_GetFullFilePath()
+{
+ // this function changes _item.PathParts.
+ CorrectPathParts();
+ const UStringVector &pathParts = _item.PathParts;
+ const UString processedPath (MakePathFromParts(pathParts));
+ FString fullProcessedPath (us2fs(processedPath));
+ if (_pathMode != NExtract::NPathMode::kAbsPaths
+ || !NName::IsAbsolutePath(processedPath))
+ {
+ fullProcessedPath = MakePath_from_2_Parts(
+ DirPathPrefix_for_HashFiles,
+ // _dirPathPrefix,
+ fullProcessedPath);
+ }
+ return fullProcessedPath;
+}
+
+
+Z7_COM7F_IMF(CArchiveExtractCallback::GetDiskProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ if (propID == kpidSize)
+ {
+ RINOK(GetItem(index))
+ const FString fullProcessedPath = Hash_GetFullFilePath();
+ NFile::NFind::CFileInfo fi;
+ if (fi.Find_FollowLink(fullProcessedPath))
+ if (!fi.IsDir())
+ prop = (UInt64)fi.Size;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CArchiveExtractCallback::GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 mode))
+{
+ COM_TRY_BEGIN
+ *inStream = NULL;
+ // if (index != _index) return E_FAIL;
+ if (mode != NUpdateNotifyOp::kHashRead)
+ return E_FAIL;
+
+ RINOK(GetItem(index))
+ const FString fullProcessedPath = Hash_GetFullFilePath();
+
+ CInFileStream *inStreamSpec = new CInFileStream;
+ CMyComPtr<ISequentialInStream> inStreamRef = inStreamSpec;
+ inStreamSpec->Set_PreserveATime(_ntOptions.PreserveATime);
+ if (!inStreamSpec->OpenShared(fullProcessedPath, _ntOptions.OpenShareForWrite))
+ {
+ RINOK(SendMessageError_with_LastError(kCantOpenInFile, fullProcessedPath))
+ return S_OK;
+ }
+ *inStream = inStreamRef.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CArchiveExtractCallback::ReportOperation(
+ UInt32 /* indexType */, UInt32 /* index */, UInt32 /* op */))
+{
+ // COM_TRY_BEGIN
+ return S_OK;
+ // COM_TRY_END
+}
+
+
+// ------------ After Extracting functions ------------
+
+void CDirPathSortPair::SetNumSlashes(const FChar *s)
+{
+ for (unsigned numSlashes = 0;;)
+ {
+ FChar c = *s++;
+ if (c == 0)
+ {
+ Len = numSlashes;
+ return;
+ }
+ if (IS_PATH_SEPAR(c))
+ numSlashes++;
+ }
+}
+
+
+bool CDirPathTime::SetDirTime() const
+{
+ return NDir::SetDirTime(Path,
+ CTime_Defined ? &CTime : NULL,
+ ATime_Defined ? &ATime : NULL,
+ MTime_Defined ? &MTime : NULL);
+}
+
+
+HRESULT CArchiveExtractCallback::SetDirsTimes()
+{
+ if (!_arc)
+ return S_OK;
+
+ CRecordVector<CDirPathSortPair> pairs;
+ pairs.ClearAndSetSize(_extractedFolders.Size());
+ unsigned i;
+
+ for (i = 0; i < _extractedFolders.Size(); i++)
+ {
+ CDirPathSortPair &pair = pairs[i];
+ pair.Index = i;
+ pair.SetNumSlashes(_extractedFolders[i].Path);
+ }
+
+ pairs.Sort2();
+
+ HRESULT res = S_OK;
+
+ for (i = 0; i < pairs.Size(); i++)
+ {
+ const CDirPathTime &dpt = _extractedFolders[pairs[i].Index];
+ if (!dpt.SetDirTime())
+ {
+ // result = E_FAIL;
+ // do we need error message here in Windows and in posix?
+ // SendMessageError_with_LastError("Cannot set directory time", dpt.Path);
+ }
+ }
+
+ /*
+ #ifndef _WIN32
+ for (i = 0; i < _delayedSymLinks.Size(); i++)
+ {
+ const CDelayedSymLink &link = _delayedSymLinks[i];
+ if (!link.Create())
+ {
+ if (res == S_OK)
+ res = GetLastError_noZero_HRESULT();
+ // res = E_FAIL;
+ // do we need error message here in Windows and in posix?
+ SendMessageError_with_LastError("Cannot create Symbolic Link", link._source);
+ }
+ }
+ #endif // _WIN32
+ */
+
+ ClearExtractedDirsInfo();
+ return res;
+}
+
+
+HRESULT CArchiveExtractCallback::CloseArc()
+{
+ HRESULT res = CloseReparseAndFile();
+ const HRESULT res2 = SetDirsTimes();
+ if (res == S_OK)
+ res = res2;
+ _arc = NULL;
+ return res;
+}
diff --git a/CPP/7zip/UI/Common/ArchiveExtractCallback.h b/CPP/7zip/UI/Common/ArchiveExtractCallback.h
index af38f13..5ed20f3 100644
--- a/CPP/7zip/UI/Common/ArchiveExtractCallback.h
+++ b/CPP/7zip/UI/Common/ArchiveExtractCallback.h
@@ -1,403 +1,584 @@
-// ArchiveExtractCallback.h
-
-#ifndef __ARCHIVE_EXTRACT_CALLBACK_H
-#define __ARCHIVE_EXTRACT_CALLBACK_H
-
-#include "../../../Common/MyCom.h"
-#include "../../../Common/Wildcard.h"
-
-#include "../../IPassword.h"
-
-#include "../../Common/FileStreams.h"
-#include "../../Common/ProgressUtils.h"
-
-#include "../../Archive/IArchive.h"
-
-#include "ExtractMode.h"
-#include "IFileExtractCallback.h"
-#include "OpenArchive.h"
-
-#include "HashCalc.h"
-
-#ifndef _SFX
-
-class COutStreamWithHash:
- public ISequentialOutStream,
- public CMyUnknownImp
-{
- CMyComPtr<ISequentialOutStream> _stream;
- UInt64 _size;
- bool _calculate;
-public:
- IHashCalc *_hash;
-
- MY_UNKNOWN_IMP
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
- void SetStream(ISequentialOutStream *stream) { _stream = stream; }
- void ReleaseStream() { _stream.Release(); }
- void Init(bool calculate = true)
- {
- InitCRC();
- _size = 0;
- _calculate = calculate;
- }
- void EnableCalc(bool calculate) { _calculate = calculate; }
- void InitCRC() { _hash->InitForNewFile(); }
- UInt64 GetSize() const { return _size; }
-};
-
-#endif
-
-struct CExtractNtOptions
-{
- CBoolPair NtSecurity;
- CBoolPair SymLinks;
- CBoolPair HardLinks;
- CBoolPair AltStreams;
- bool ReplaceColonForAltStream;
- bool WriteToAltStreamIfColon;
-
- bool PreAllocateOutFile;
-
- CExtractNtOptions():
- ReplaceColonForAltStream(false),
- WriteToAltStreamIfColon(false)
- {
- SymLinks.Val = true;
- HardLinks.Val = true;
- AltStreams.Val = true;
-
- PreAllocateOutFile =
- #ifdef _WIN32
- true;
- #else
- false;
- #endif
- }
-};
-
-#ifndef _SFX
-
-class CGetProp:
- public IGetProp,
- public CMyUnknownImp
-{
-public:
- const CArc *Arc;
- UInt32 IndexInArc;
- // UString Name; // relative path
-
- MY_UNKNOWN_IMP1(IGetProp)
- INTERFACE_IGetProp(;)
-};
-
-#endif
-
-#ifndef _SFX
-#ifndef UNDER_CE
-
-#define SUPPORT_LINKS
-
-#endif
-#endif
-
-
-#ifdef SUPPORT_LINKS
-
-struct CHardLinkNode
-{
- UInt64 StreamId;
- UInt64 INode;
-
- int Compare(const CHardLinkNode &a) const;
-};
-
-class CHardLinks
-{
-public:
- CRecordVector<CHardLinkNode> IDs;
- CObjectVector<FString> Links;
-
- void Clear()
- {
- IDs.Clear();
- Links.Clear();
- }
-
- void PrepareLinks()
- {
- while (Links.Size() < IDs.Size())
- Links.AddNew();
- }
-};
-
-#endif
-
-#ifdef SUPPORT_ALT_STREAMS
-
-struct CIndexToPathPair
-{
- UInt32 Index;
- FString Path;
-
- CIndexToPathPair(UInt32 index): Index(index) {}
- CIndexToPathPair(UInt32 index, const FString &path): Index(index), Path(path) {}
-
- int Compare(const CIndexToPathPair &pair) const
- {
- return MyCompare(Index, pair.Index);
- }
-};
-
-#endif
-
-
-
-struct CDirPathTime
-{
- FILETIME CTime;
- FILETIME ATime;
- FILETIME MTime;
-
- bool CTimeDefined;
- bool ATimeDefined;
- bool MTimeDefined;
-
- FString Path;
-
- bool SetDirTime();
-};
-
-
-
-class CArchiveExtractCallback:
- public IArchiveExtractCallback,
- public IArchiveExtractCallbackMessage,
- public ICryptoGetTextPassword,
- public ICompressProgressInfo,
- public CMyUnknownImp
-{
- const CArc *_arc;
- CExtractNtOptions _ntOptions;
-
- const NWildcard::CCensorNode *_wildcardCensor; // we need wildcard for single pass mode (stdin)
- CMyComPtr<IFolderArchiveExtractCallback> _extractCallback2;
- CMyComPtr<ICompressProgressInfo> _compressProgress;
- CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword;
- CMyComPtr<IArchiveExtractCallbackMessage> _callbackMessage;
- CMyComPtr<IFolderArchiveExtractCallback2> _folderArchiveExtractCallback2;
-
- FString _dirPathPrefix;
- FString _dirPathPrefix_Full;
- NExtract::NPathMode::EEnum _pathMode;
- NExtract::NOverwriteMode::EEnum _overwriteMode;
- bool _keepAndReplaceEmptyDirPrefixes; // replace them to "_";
-
- #ifndef _SFX
-
- CMyComPtr<IFolderExtractToStreamCallback> ExtractToStreamCallback;
- CGetProp *GetProp_Spec;
- CMyComPtr<IGetProp> GetProp;
-
- #endif
-
- CReadArcItem _item;
- FString _diskFilePath;
- UInt64 _position;
- bool _isSplit;
-
- bool _extractMode;
-
- bool WriteCTime;
- bool WriteATime;
- bool WriteMTime;
-
- bool _encrypted;
-
- struct CProcessedFileInfo
- {
- FILETIME CTime;
- FILETIME ATime;
- FILETIME MTime;
- UInt32 Attrib;
-
- bool CTimeDefined;
- bool ATimeDefined;
- bool MTimeDefined;
- bool AttribDefined;
- } _fi;
-
- UInt32 _index;
- UInt64 _curSize;
- bool _curSizeDefined;
- bool _fileLengthWasSet;
- COutFileStream *_outFileStreamSpec;
- CMyComPtr<ISequentialOutStream> _outFileStream;
-
- #ifndef _SFX
-
- COutStreamWithHash *_hashStreamSpec;
- CMyComPtr<ISequentialOutStream> _hashStream;
- bool _hashStreamWasUsed;
-
- #endif
-
- bool _removePartsForAltStreams;
- UStringVector _removePathParts;
-
- #ifndef _SFX
- bool _use_baseParentFolder_mode;
- UInt32 _baseParentFolder;
- #endif
-
- bool _stdOutMode;
- bool _testMode;
- bool _multiArchives;
-
- CMyComPtr<ICompressProgressInfo> _localProgress;
- UInt64 _packTotal;
-
- UInt64 _progressTotal;
- bool _progressTotal_Defined;
-
- CObjectVector<CDirPathTime> _extractedFolders;
-
- #if defined(_WIN32) && !defined(UNDER_CE) && !defined(_SFX)
- bool _saclEnabled;
- #endif
-
- void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath);
- HRESULT GetTime(UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined);
- HRESULT GetUnpackSize();
-
- HRESULT SendMessageError(const char *message, const FString &path);
- HRESULT SendMessageError_with_LastError(const char *message, const FString &path);
- HRESULT SendMessageError2(const char *message, const FString &path1, const FString &path2);
-
-public:
-
- CLocalProgress *LocalProgressSpec;
-
- UInt64 NumFolders;
- UInt64 NumFiles;
- UInt64 NumAltStreams;
- UInt64 UnpackSize;
- UInt64 AltStreams_UnpackSize;
-
- MY_UNKNOWN_IMP3(IArchiveExtractCallbackMessage, ICryptoGetTextPassword, ICompressProgressInfo)
-
- INTERFACE_IArchiveExtractCallback(;)
- INTERFACE_IArchiveExtractCallbackMessage(;)
-
- STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
-
- STDMETHOD(CryptoGetTextPassword)(BSTR *password);
-
- CArchiveExtractCallback();
-
- void InitForMulti(bool multiArchives,
- NExtract::NPathMode::EEnum pathMode,
- NExtract::NOverwriteMode::EEnum overwriteMode,
- bool keepAndReplaceEmptyDirPrefixes)
- {
- _multiArchives = multiArchives;
- _pathMode = pathMode;
- _overwriteMode = overwriteMode;
- _keepAndReplaceEmptyDirPrefixes = keepAndReplaceEmptyDirPrefixes;
- NumFolders = NumFiles = NumAltStreams = UnpackSize = AltStreams_UnpackSize = 0;
- }
-
- #ifndef _SFX
-
- void SetHashMethods(IHashCalc *hash)
- {
- if (!hash)
- return;
- _hashStreamSpec = new COutStreamWithHash;
- _hashStream = _hashStreamSpec;
- _hashStreamSpec->_hash = hash;
- }
-
- #endif
-
- void Init(
- const CExtractNtOptions &ntOptions,
- const NWildcard::CCensorNode *wildcardCensor,
- const CArc *arc,
- IFolderArchiveExtractCallback *extractCallback2,
- bool stdOutMode, bool testMode,
- const FString &directoryPath,
- const UStringVector &removePathParts, bool removePartsForAltStreams,
- UInt64 packSize);
-
-
- #ifdef SUPPORT_LINKS
-
-private:
- CHardLinks _hardLinks;
- UString linkPath;
-
- // FString _CopyFile_Path;
- // HRESULT MyCopyFile(ISequentialOutStream *outStream);
-
-public:
- // call PrepareHardLinks() after Init()
- HRESULT PrepareHardLinks(const CRecordVector<UInt32> *realIndices); // NULL means all items
-
- #endif
-
-
- #ifdef SUPPORT_ALT_STREAMS
- CObjectVector<CIndexToPathPair> _renamedFiles;
- #endif
-
- // call it after Init()
-
- #ifndef _SFX
- void SetBaseParentFolderIndex(UInt32 indexInArc)
- {
- _baseParentFolder = indexInArc;
- _use_baseParentFolder_mode = true;
- }
- #endif
-
- HRESULT CloseArc();
-
-private:
- void ClearExtractedDirsInfo()
- {
- _extractedFolders.Clear();
- }
-
- HRESULT CloseFile();
- HRESULT SetDirsTimes();
-};
-
-
-struct CArchiveExtractCallback_Closer
-{
- CArchiveExtractCallback *_ref;
-
- CArchiveExtractCallback_Closer(CArchiveExtractCallback *ref): _ref(ref) {}
-
- HRESULT Close()
- {
- HRESULT res = S_OK;
- if (_ref)
- {
- res = _ref->CloseArc();
- _ref = NULL;
- }
- return res;
- }
-
- ~CArchiveExtractCallback_Closer()
- {
- Close();
- }
-};
-
-
-bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item);
-
-#endif
+// ArchiveExtractCallback.h
+
+#ifndef ZIP7_INC_ARCHIVE_EXTRACT_CALLBACK_H
+#define ZIP7_INC_ARCHIVE_EXTRACT_CALLBACK_H
+
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyLinux.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../../IPassword.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamObjects.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "ExtractMode.h"
+#include "IFileExtractCallback.h"
+#include "OpenArchive.h"
+
+#include "HashCalc.h"
+
+#ifndef Z7_SFX
+
+Z7_CLASS_IMP_NOQIB_1(
+ COutStreamWithHash
+ , ISequentialOutStream
+)
+ CMyComPtr<ISequentialOutStream> _stream;
+ UInt64 _size;
+ bool _calculate;
+public:
+ IHashCalc *_hash;
+
+ void SetStream(ISequentialOutStream *stream) { _stream = stream; }
+ void ReleaseStream() { _stream.Release(); }
+ void Init(bool calculate = true)
+ {
+ InitCRC();
+ _size = 0;
+ _calculate = calculate;
+ }
+ void EnableCalc(bool calculate) { _calculate = calculate; }
+ void InitCRC() { _hash->InitForNewFile(); }
+ UInt64 GetSize() const { return _size; }
+};
+
+#endif
+
+struct CExtractNtOptions
+{
+ CBoolPair NtSecurity;
+ CBoolPair SymLinks;
+ CBoolPair SymLinks_AllowDangerous;
+ CBoolPair HardLinks;
+ CBoolPair AltStreams;
+ bool ReplaceColonForAltStream;
+ bool WriteToAltStreamIfColon;
+
+ bool ExtractOwner;
+
+ bool PreAllocateOutFile;
+
+ // used for hash arcs only, when we open external files
+ bool PreserveATime;
+ bool OpenShareForWrite;
+
+ CExtractNtOptions():
+ ReplaceColonForAltStream(false),
+ WriteToAltStreamIfColon(false),
+ ExtractOwner(false),
+ PreserveATime(false),
+ OpenShareForWrite(false)
+ {
+ SymLinks.Val = true;
+ SymLinks_AllowDangerous.Val = false;
+ HardLinks.Val = true;
+ AltStreams.Val = true;
+
+ PreAllocateOutFile =
+ #ifdef _WIN32
+ true;
+ #else
+ false;
+ #endif
+ }
+};
+
+#ifndef Z7_SFX
+
+Z7_CLASS_IMP_COM_1(
+ CGetProp
+ , IGetProp
+)
+public:
+ UInt32 IndexInArc;
+ const CArc *Arc;
+ // UString Name; // relative path
+};
+
+#endif
+
+#ifndef Z7_SFX
+#ifndef UNDER_CE
+
+#define SUPPORT_LINKS
+
+#endif
+#endif
+
+
+#ifdef SUPPORT_LINKS
+
+struct CHardLinkNode
+{
+ UInt64 StreamId;
+ UInt64 INode;
+
+ int Compare(const CHardLinkNode &a) const;
+};
+
+class CHardLinks
+{
+public:
+ CRecordVector<CHardLinkNode> IDs;
+ CObjectVector<FString> Links;
+
+ void Clear()
+ {
+ IDs.Clear();
+ Links.Clear();
+ }
+
+ void PrepareLinks()
+ {
+ while (Links.Size() < IDs.Size())
+ Links.AddNew();
+ }
+};
+
+#endif
+
+#ifdef SUPPORT_ALT_STREAMS
+
+struct CIndexToPathPair
+{
+ UInt32 Index;
+ FString Path;
+
+ CIndexToPathPair(UInt32 index): Index(index) {}
+ CIndexToPathPair(UInt32 index, const FString &path): Index(index), Path(path) {}
+
+ int Compare(const CIndexToPathPair &pair) const
+ {
+ return MyCompare(Index, pair.Index);
+ }
+};
+
+#endif
+
+
+
+struct CFiTimesCAM
+{
+ CFiTime CTime;
+ CFiTime ATime;
+ CFiTime MTime;
+
+ bool CTime_Defined;
+ bool ATime_Defined;
+ bool MTime_Defined;
+
+ bool IsSomeTimeDefined() const
+ {
+ return
+ CTime_Defined |
+ ATime_Defined |
+ MTime_Defined;
+ }
+};
+
+struct CDirPathTime: public CFiTimesCAM
+{
+ FString Path;
+
+ bool SetDirTime() const;
+};
+
+
+#ifdef SUPPORT_LINKS
+
+struct CLinkInfo
+{
+ // bool isCopyLink;
+ bool isHardLink;
+ bool isJunction;
+ bool isRelative;
+ bool isWSL;
+ UString linkPath;
+
+ bool IsSymLink() const { return !isHardLink; }
+
+ CLinkInfo():
+ // IsCopyLink(false),
+ isHardLink(false),
+ isJunction(false),
+ isRelative(false),
+ isWSL(false)
+ {}
+
+ void Clear()
+ {
+ // IsCopyLink = false;
+ isHardLink = false;
+ isJunction = false;
+ isRelative = false;
+ isWSL = false;
+ linkPath.Empty();
+ }
+
+ bool Parse(const Byte *data, size_t dataSize, bool isLinuxData);
+};
+
+#endif // SUPPORT_LINKS
+
+
+#ifndef _WIN32
+
+struct COwnerInfo
+{
+ bool Id_Defined;
+ UInt32 Id;
+ AString Name;
+
+ void Clear()
+ {
+ Id_Defined = false;
+ Id = 0;
+ Name.Empty();
+ }
+};
+
+#endif
+
+
+class CArchiveExtractCallback Z7_final:
+ public IArchiveExtractCallback,
+ public IArchiveExtractCallbackMessage2,
+ public ICryptoGetTextPassword,
+ public ICompressProgressInfo,
+ public IArchiveUpdateCallbackFile,
+ public IArchiveGetDiskProperty,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_5(
+ /* IArchiveExtractCallback, */
+ IArchiveExtractCallbackMessage2,
+ ICryptoGetTextPassword,
+ ICompressProgressInfo,
+ IArchiveUpdateCallbackFile,
+ IArchiveGetDiskProperty)
+
+ Z7_IFACE_COM7_IMP(IProgress)
+ Z7_IFACE_COM7_IMP(IArchiveExtractCallback)
+ Z7_IFACE_COM7_IMP(IArchiveExtractCallbackMessage2)
+ Z7_IFACE_COM7_IMP(ICryptoGetTextPassword)
+ Z7_IFACE_COM7_IMP(ICompressProgressInfo)
+ Z7_IFACE_COM7_IMP(IArchiveUpdateCallbackFile)
+ Z7_IFACE_COM7_IMP(IArchiveGetDiskProperty)
+
+ const CArc *_arc;
+ CExtractNtOptions _ntOptions;
+
+ bool _isSplit;
+
+ bool _extractMode;
+
+ bool Write_CTime;
+ bool Write_ATime;
+ bool Write_MTime;
+ bool _keepAndReplaceEmptyDirPrefixes; // replace them to "_";
+
+ bool _encrypted;
+
+ // bool _is_SymLink_in_Data;
+ bool _is_SymLink_in_Data_Linux; // false = WIN32, true = LINUX
+
+ bool _needSetAttrib;
+ bool _isSymLinkCreated;
+ bool _itemFailure;
+
+ bool _curSize_Defined;
+ bool _fileLength_WasSet;
+
+ bool _removePartsForAltStreams;
+
+ bool _stdOutMode;
+ bool _testMode;
+ bool _multiArchives;
+
+ NExtract::NPathMode::EEnum _pathMode;
+ NExtract::NOverwriteMode::EEnum _overwriteMode;
+
+ const NWildcard::CCensorNode *_wildcardCensor; // we need wildcard for single pass mode (stdin)
+ CMyComPtr<IFolderArchiveExtractCallback> _extractCallback2;
+ // CMyComPtr<ICompressProgressInfo> _compressProgress;
+ // CMyComPtr<IArchiveExtractCallbackMessage2> _callbackMessage;
+ CMyComPtr<IFolderArchiveExtractCallback2> _folderArchiveExtractCallback2;
+ CMyComPtr<ICryptoGetTextPassword> _cryptoGetTextPassword;
+
+ FString _dirPathPrefix;
+ FString _dirPathPrefix_Full;
+
+ #ifndef Z7_SFX
+
+ CMyComPtr<IFolderExtractToStreamCallback> ExtractToStreamCallback;
+ CGetProp *GetProp_Spec;
+ CMyComPtr<IGetProp> GetProp;
+
+ #endif
+
+ CReadArcItem _item;
+ FString _diskFilePath;
+ UInt64 _position;
+
+ struct CProcessedFileInfo
+ {
+ CArcTime CTime;
+ CArcTime ATime;
+ CArcTime MTime;
+ UInt32 Attrib;
+ bool Attrib_Defined;
+
+ #ifndef _WIN32
+ COwnerInfo Owner;
+ COwnerInfo Group;
+ #endif
+
+ bool IsReparse() const
+ {
+ return (Attrib_Defined && (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0);
+ }
+
+ bool IsLinuxSymLink() const
+ {
+ return (Attrib_Defined && MY_LIN_S_ISLNK(Attrib >> 16));
+ }
+
+ void SetFromPosixAttrib(UInt32 a)
+ {
+ // here we set only part of combined attribute required by SetFileAttrib() call
+ #ifdef _WIN32
+ // Windows sets FILE_ATTRIBUTE_NORMAL, if we try to set 0 as attribute.
+ Attrib = MY_LIN_S_ISDIR(a) ?
+ FILE_ATTRIBUTE_DIRECTORY :
+ FILE_ATTRIBUTE_ARCHIVE;
+ if ((a & 0222) == 0) // (& S_IWUSR) in p7zip
+ Attrib |= FILE_ATTRIBUTE_READONLY;
+ // 22.00 : we need type bits for (MY_LIN_S_IFLNK) for IsLinuxSymLink()
+ a &= MY_LIN_S_IFMT;
+ if (a == MY_LIN_S_IFLNK)
+ Attrib |= (a << 16);
+ #else
+ Attrib = (a << 16) | FILE_ATTRIBUTE_UNIX_EXTENSION;
+ #endif
+ Attrib_Defined = true;
+ }
+ } _fi;
+
+ UInt32 _index;
+ UInt64 _curSize;
+ UInt64 _fileLength_that_WasSet;
+
+ COutFileStream *_outFileStreamSpec;
+ CMyComPtr<ISequentialOutStream> _outFileStream;
+
+ CByteBuffer _outMemBuf;
+ CBufPtrSeqOutStream *_bufPtrSeqOutStream_Spec;
+ CMyComPtr<ISequentialOutStream> _bufPtrSeqOutStream;
+
+
+ #ifndef Z7_SFX
+
+ COutStreamWithHash *_hashStreamSpec;
+ CMyComPtr<ISequentialOutStream> _hashStream;
+ bool _hashStreamWasUsed;
+
+ bool _use_baseParentFolder_mode;
+ UInt32 _baseParentFolder;
+ #endif
+
+ UStringVector _removePathParts;
+
+ CMyComPtr<ICompressProgressInfo> _localProgress;
+ UInt64 _packTotal;
+
+ UInt64 _progressTotal;
+ bool _progressTotal_Defined;
+
+ CObjectVector<CDirPathTime> _extractedFolders;
+
+ #ifndef _WIN32
+ // CObjectVector<NWindows::NFile::NDir::CDelayedSymLink> _delayedSymLinks;
+ #endif
+
+ #if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
+ bool _saclEnabled;
+ #endif
+
+ void CreateComplexDirectory(const UStringVector &dirPathParts, FString &fullPath);
+ HRESULT GetTime(UInt32 index, PROPID propID, CArcTime &ft);
+ HRESULT GetUnpackSize();
+
+ FString Hash_GetFullFilePath();
+
+ void SetAttrib();
+
+public:
+ HRESULT SendMessageError(const char *message, const FString &path);
+ HRESULT SendMessageError_with_LastError(const char *message, const FString &path);
+ HRESULT SendMessageError2(HRESULT errorCode, const char *message, const FString &path1, const FString &path2);
+
+public:
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ NExtract::NZoneIdMode::EEnum ZoneMode;
+ CByteBuffer ZoneBuf;
+ #endif
+
+ CLocalProgress *LocalProgressSpec;
+
+ UInt64 NumFolders;
+ UInt64 NumFiles;
+ UInt64 NumAltStreams;
+ UInt64 UnpackSize;
+ UInt64 AltStreams_UnpackSize;
+
+ FString DirPathPrefix_for_HashFiles;
+
+ CArchiveExtractCallback();
+
+ void InitForMulti(bool multiArchives,
+ NExtract::NPathMode::EEnum pathMode,
+ NExtract::NOverwriteMode::EEnum overwriteMode,
+ NExtract::NZoneIdMode::EEnum zoneMode,
+ bool keepAndReplaceEmptyDirPrefixes)
+ {
+ _multiArchives = multiArchives;
+ _pathMode = pathMode;
+ _overwriteMode = overwriteMode;
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ ZoneMode = zoneMode;
+ #else
+ UNUSED_VAR(zoneMode)
+ #endif
+ _keepAndReplaceEmptyDirPrefixes = keepAndReplaceEmptyDirPrefixes;
+ NumFolders = NumFiles = NumAltStreams = UnpackSize = AltStreams_UnpackSize = 0;
+ }
+
+ #ifndef Z7_SFX
+
+ void SetHashMethods(IHashCalc *hash)
+ {
+ if (!hash)
+ return;
+ _hashStreamSpec = new COutStreamWithHash;
+ _hashStream = _hashStreamSpec;
+ _hashStreamSpec->_hash = hash;
+ }
+
+ #endif
+
+ void InitBeforeNewArchive();
+
+ void Init(
+ const CExtractNtOptions &ntOptions,
+ const NWildcard::CCensorNode *wildcardCensor,
+ const CArc *arc,
+ IFolderArchiveExtractCallback *extractCallback2,
+ bool stdOutMode, bool testMode,
+ const FString &directoryPath,
+ const UStringVector &removePathParts, bool removePartsForAltStreams,
+ UInt64 packSize);
+
+
+ #ifdef SUPPORT_LINKS
+
+private:
+ CHardLinks _hardLinks;
+ CLinkInfo _link;
+
+ // FString _copyFile_Path;
+ // HRESULT MyCopyFile(ISequentialOutStream *outStream);
+ HRESULT Link(const FString &fullProcessedPath);
+ HRESULT ReadLink();
+
+public:
+ // call PrepareHardLinks() after Init()
+ HRESULT PrepareHardLinks(const CRecordVector<UInt32> *realIndices); // NULL means all items
+
+ #endif
+
+
+ #ifdef SUPPORT_ALT_STREAMS
+ CObjectVector<CIndexToPathPair> _renamedFiles;
+ #endif
+
+ // call it after Init()
+
+ #ifndef Z7_SFX
+ void SetBaseParentFolderIndex(UInt32 indexInArc)
+ {
+ _baseParentFolder = indexInArc;
+ _use_baseParentFolder_mode = true;
+ }
+ #endif
+
+ HRESULT CloseArc();
+
+private:
+ void ClearExtractedDirsInfo()
+ {
+ _extractedFolders.Clear();
+ #ifndef _WIN32
+ // _delayedSymLinks.Clear();
+ #endif
+ }
+
+ HRESULT Read_fi_Props();
+ void CorrectPathParts();
+ void GetFiTimesCAM(CFiTimesCAM &pt);
+ void CreateFolders();
+
+ bool _isRenamed;
+ HRESULT CheckExistFile(FString &fullProcessedPath, bool &needExit);
+ HRESULT GetExtractStream(CMyComPtr<ISequentialOutStream> &outStreamLoc, bool &needExit);
+ HRESULT GetItem(UInt32 index);
+
+ HRESULT CloseFile();
+ HRESULT CloseReparseAndFile();
+ HRESULT CloseReparseAndFile2();
+ HRESULT SetDirsTimes();
+
+ const void *NtReparse_Data;
+ UInt32 NtReparse_Size;
+
+ #ifdef SUPPORT_LINKS
+ HRESULT SetFromLinkPath(
+ const FString &fullProcessedPath,
+ const CLinkInfo &linkInfo,
+ bool &linkWasSet);
+ #endif
+};
+
+
+struct CArchiveExtractCallback_Closer
+{
+ CArchiveExtractCallback *_ref;
+
+ CArchiveExtractCallback_Closer(CArchiveExtractCallback *ref): _ref(ref) {}
+
+ HRESULT Close()
+ {
+ HRESULT res = S_OK;
+ if (_ref)
+ {
+ res = _ref->CloseArc();
+ _ref = NULL;
+ }
+ return res;
+ }
+
+ ~CArchiveExtractCallback_Closer()
+ {
+ Close();
+ }
+};
+
+
+bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item);
+
+void ReadZoneFile_Of_BaseFile(CFSTR fileName2, CByteBuffer &buf);
+
+#endif
diff --git a/CPP/7zip/UI/Common/ArchiveName.cpp b/CPP/7zip/UI/Common/ArchiveName.cpp
index b07d46c..1c0c3a8 100644
--- a/CPP/7zip/UI/Common/ArchiveName.cpp
+++ b/CPP/7zip/UI/Common/ArchiveName.cpp
@@ -1,155 +1,176 @@
-// ArchiveName.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/Wildcard.h"
-
-#include "../../../Windows/FileDir.h"
-#include "../../../Windows/FileName.h"
-
-#include "ExtractingFilePath.h"
-#include "ArchiveName.h"
-
-using namespace NWindows;
-using namespace NFile;
-
-static UString CreateArchiveName(const NFind::CFileInfo &fi, bool keepName)
-{
- FString resultName = fi.Name;
- if (!fi.IsDir() && !keepName)
- {
- int dotPos = resultName.ReverseFind_Dot();
- if (dotPos > 0)
- {
- FString archiveName2 = resultName.Left(dotPos);
- if (archiveName2.ReverseFind_Dot() < 0)
- resultName = archiveName2;
- }
- }
- return Get_Correct_FsFile_Name(fs2us(resultName));
-}
-
-static FString CreateArchiveName2(const FString &path, bool fromPrev, bool keepName)
-{
- FString resultName ("Archive");
- if (fromPrev)
- {
- FString dirPrefix;
- if (NDir::GetOnlyDirPrefix(path, dirPrefix))
- {
- if (!dirPrefix.IsEmpty() && IsPathSepar(dirPrefix.Back()))
- {
- #if defined(_WIN32) && !defined(UNDER_CE)
- if (NName::IsDriveRootPath_SuperAllowed(dirPrefix))
- resultName = dirPrefix[dirPrefix.Len() - 3]; // only letter
- else
- #endif
- {
- dirPrefix.DeleteBack();
- NFind::CFileInfo fi;
- if (fi.Find(dirPrefix))
- resultName = fi.Name;
- }
- }
- }
- }
- else
- {
- NFind::CFileInfo fi;
- if (fi.Find(path))
- {
- resultName = fi.Name;
- if (!fi.IsDir() && !keepName)
- {
- int dotPos = resultName.ReverseFind_Dot();
- if (dotPos > 0)
- {
- FString name2 = resultName.Left(dotPos);
- if (name2.ReverseFind_Dot() < 0)
- resultName = name2;
- }
- }
- }
- }
- return resultName;
-}
-
-
-UString CreateArchiveName(const UStringVector &paths, const NFind::CFileInfo *fi)
-{
- bool keepName = false;
- /*
- if (paths.Size() == 1)
- {
- const UString &name = paths[0];
- if (name.Len() > 4)
- if (CompareFileNames(name.RightPtr(4), L".tar") == 0)
- keepName = true;
- }
- */
-
- UString name;
- if (fi)
- name = CreateArchiveName(*fi, keepName);
- else
- {
- if (paths.IsEmpty())
- return L"archive";
- bool fromPrev = (paths.Size() > 1);
- name = Get_Correct_FsFile_Name(fs2us(CreateArchiveName2(us2fs(paths.Front()), fromPrev, keepName)));
- }
-
- UStringVector names;
-
- {
- FOR_VECTOR (i, paths)
- {
- NFind::CFileInfo fi2;
- const NFind::CFileInfo *fp;
- if (fi && paths.Size() == 1)
- fp = fi;
- else
- {
- if (!fi2.Find(us2fs(paths[i])))
- continue;
- fp = &fi2;
- }
- names.Add(fs2us(fp->Name));
- }
- }
-
- UString postfix;
- UInt32 index = 1;
-
- for (;;)
- {
- // we don't want cases when we include archive to itself.
- // so we find first available name for archive
- const UString name2 = name + postfix;
- const UString name2_zip = name2 + L".zip";
- const UString name2_7z = name2 + L".7z";
- const UString name2_tar = name2 + L".tar";
- const UString name2_wim = name2 + L".wim";
-
- unsigned i = 0;
-
- for (i = 0; i < names.Size(); i++)
- {
- const UString &fname = names[i];
- if ( 0 == CompareFileNames(fname, name2_zip)
- || 0 == CompareFileNames(fname, name2_7z)
- || 0 == CompareFileNames(fname, name2_tar)
- || 0 == CompareFileNames(fname, name2_wim))
- break;
- }
-
- if (i == names.Size())
- break;
- index++;
- postfix = "_";
- postfix.Add_UInt32(index);
- }
-
- name += postfix;
- return name;
-}
+// ArchiveName.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Sort.h"
+
+#include "../../../Common/Wildcard.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileName.h"
+
+#include "ArchiveName.h"
+#include "ExtractingFilePath.h"
+
+using namespace NWindows;
+using namespace NFile;
+
+
+static const char *g_ArcExts =
+ "7z"
+ "\0" "zip"
+ "\0" "tar"
+ "\0" "wim"
+ "\0";
+
+static const char *g_HashExts =
+ "sha256"
+ "\0";
+
+
+UString CreateArchiveName(
+ const UStringVector &paths,
+ bool isHash,
+ const NFind::CFileInfo *fi,
+ UString &baseName)
+{
+ bool keepName = isHash;
+ /*
+ if (paths.Size() == 1)
+ {
+ const UString &name = paths[0];
+ if (name.Len() > 4)
+ if (CompareFileNames(name.RightPtr(4), L".tar") == 0)
+ keepName = true;
+ }
+ */
+
+ UString name ("Archive");
+ NFind::CFileInfo fi3;
+ if (paths.Size() > 1)
+ fi = NULL;
+ if (!fi && paths.Size() != 0)
+ {
+ const UString &path = paths.Front();
+ if (paths.Size() == 1)
+ {
+ if (fi3.Find(us2fs(path)))
+ fi = &fi3;
+ }
+ else
+ {
+ // we try to use name of parent folder
+ FString dirPrefix;
+ if (NDir::GetOnlyDirPrefix(us2fs(path), dirPrefix))
+ {
+ if (!dirPrefix.IsEmpty() && IsPathSepar(dirPrefix.Back()))
+ {
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (NName::IsDriveRootPath_SuperAllowed(dirPrefix))
+ {
+ if (path != fs2us(dirPrefix))
+ name = dirPrefix[dirPrefix.Len() - 3]; // only letter
+ }
+ else
+ #endif
+ {
+ dirPrefix.DeleteBack();
+ if (!dirPrefix.IsEmpty())
+ {
+ const int slash = dirPrefix.ReverseFind_PathSepar();
+ if (slash >= 0 && slash != (int)dirPrefix.Len() - 1)
+ name = dirPrefix.Ptr(slash + 1);
+ else if (fi3.Find(dirPrefix))
+ name = fs2us(fi3.Name);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (fi)
+ {
+ name = fs2us(fi->Name);
+ if (!fi->IsDir() && !keepName)
+ {
+ const int dotPos = name.Find(L'.');
+ if (dotPos > 0 && name.Find(L'.', (unsigned)dotPos + 1) < 0)
+ name.DeleteFrom((unsigned)dotPos);
+ }
+ }
+ name = Get_Correct_FsFile_Name(name);
+
+ CRecordVector<UInt32> ids;
+ bool simple_IsAllowed = true;
+ // for (int y = 0; y < 10000; y++) // for debug
+ {
+ // ids.Clear();
+ UString n;
+
+ FOR_VECTOR (i, paths)
+ {
+ const UString &a = paths[i];
+ const int slash = a.ReverseFind_PathSepar();
+ // if (name.Len() >= a.Len() - slash + 1) continue;
+ const wchar_t *s = a.Ptr(slash + 1);
+ if (!IsPath1PrefixedByPath2(s, name))
+ continue;
+ s += name.Len();
+ const char *exts = isHash ? g_HashExts : g_ArcExts;
+
+ for (;;)
+ {
+ const char *ext = exts;
+ const unsigned len = MyStringLen(ext);
+ if (len == 0)
+ break;
+ exts += len + 1;
+ n = s;
+ if (n.Len() <= len)
+ continue;
+ if (!StringsAreEqualNoCase_Ascii(n.RightPtr(len), ext))
+ continue;
+ n.DeleteFrom(n.Len() - len);
+ if (n.Back() != '.')
+ continue;
+ n.DeleteBack();
+ if (n.IsEmpty())
+ {
+ simple_IsAllowed = false;
+ break;
+ }
+ if (n.Len() < 2)
+ continue;
+ if (n[0] != '_')
+ continue;
+ const wchar_t *end;
+ const UInt32 v = ConvertStringToUInt32(n.Ptr(1), &end);
+ if (*end != 0)
+ continue;
+ ids.Add(v);
+ break;
+ }
+ }
+ }
+
+ baseName = name;
+ if (!simple_IsAllowed)
+ {
+ HeapSort(&ids.Front(), ids.Size());
+ UInt32 v = 2;
+ const unsigned num = ids.Size();
+ for (unsigned i = 0; i < num; i++)
+ {
+ const UInt32 id = ids[i];
+ if (id > v)
+ break;
+ if (id == v)
+ v = id + 1;
+ }
+ name += '_';
+ name.Add_UInt32(v);
+ }
+ return name;
+}
diff --git a/CPP/7zip/UI/Common/ArchiveName.h b/CPP/7zip/UI/Common/ArchiveName.h
index ce2d192..9b6b7fe 100644
--- a/CPP/7zip/UI/Common/ArchiveName.h
+++ b/CPP/7zip/UI/Common/ArchiveName.h
@@ -1,10 +1,16 @@
-// ArchiveName.h
-
-#ifndef __ARCHIVE_NAME_H
-#define __ARCHIVE_NAME_H
-
-#include "../../../Windows/FileFind.h"
-
-UString CreateArchiveName(const UStringVector &paths, const NWindows::NFile::NFind::CFileInfo *fi = NULL);
-
-#endif
+// ArchiveName.h
+
+#ifndef ZIP7_INC_ARCHIVE_NAME_H
+#define ZIP7_INC_ARCHIVE_NAME_H
+
+#include "../../../Windows/FileFind.h"
+
+/* (fi != NULL) only if (paths.Size() == 1) */
+
+UString CreateArchiveName(
+ const UStringVector &paths,
+ bool isHash,
+ const NWindows::NFile::NFind::CFileInfo *fi,
+ UString &baseName);
+
+#endif
diff --git a/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp b/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
index fd8f9f8..4e5f1f5 100644
--- a/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
+++ b/CPP/7zip/UI/Common/ArchiveOpenCallback.cpp
@@ -1,161 +1,393 @@
-// ArchiveOpenCallback.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/ComTry.h"
-
-#include "../../../Windows/FileName.h"
-#include "../../../Windows/PropVariant.h"
-
-#include "../../Common/FileStreams.h"
-
-#include "ArchiveOpenCallback.h"
-
-using namespace NWindows;
-
-STDMETHODIMP COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes)
-{
- COM_TRY_BEGIN
- if (ReOpenCallback)
- return ReOpenCallback->SetTotal(files, bytes);
- if (!Callback)
- return S_OK;
- return Callback->Open_SetTotal(files, bytes);
- COM_TRY_END
-}
-
-STDMETHODIMP COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes)
-{
- COM_TRY_BEGIN
- if (ReOpenCallback)
- return ReOpenCallback->SetCompleted(files, bytes);
- if (!Callback)
- return S_OK;
- return Callback->Open_SetCompleted(files, bytes);
- COM_TRY_END
-}
-
-STDMETHODIMP COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value)
-{
- COM_TRY_BEGIN
- NCOM::CPropVariant prop;
- if (_subArchiveMode)
- switch (propID)
- {
- case kpidName: prop = _subArchiveName; break;
- // case kpidSize: prop = _subArchiveSize; break; // we don't use it now
- }
- else
- switch (propID)
- {
- case kpidName: prop = _fileInfo.Name; break;
- case kpidIsDir: prop = _fileInfo.IsDir(); break;
- case kpidSize: prop = _fileInfo.Size; break;
- case kpidAttrib: prop = (UInt32)_fileInfo.Attrib; break;
- case kpidCTime: prop = _fileInfo.CTime; break;
- case kpidATime: prop = _fileInfo.ATime; break;
- case kpidMTime: prop = _fileInfo.MTime; break;
- }
- prop.Detach(value);
- return S_OK;
- COM_TRY_END
-}
-
-struct CInFileStreamVol: public CInFileStream
-{
- int FileNameIndex;
- COpenCallbackImp *OpenCallbackImp;
- CMyComPtr<IArchiveOpenCallback> OpenCallbackRef;
-
- ~CInFileStreamVol()
- {
- if (OpenCallbackRef)
- OpenCallbackImp->FileNames_WasUsed[FileNameIndex] = false;
- }
-};
-
-
-// from ArchiveExtractCallback.cpp
-bool IsSafePath(const UString &path);
-
-STDMETHODIMP COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStream)
-{
- COM_TRY_BEGIN
- *inStream = NULL;
-
- if (_subArchiveMode)
- return S_FALSE;
- if (Callback)
- {
- RINOK(Callback->Open_CheckBreak());
- }
-
- UString name2 = name;
-
-
- #ifndef _SFX
-
- #ifdef _WIN32
- name2.Replace(L'/', WCHAR_PATH_SEPARATOR);
- #endif
-
- // if (!allowAbsVolPaths)
- if (!IsSafePath(name2))
- return S_FALSE;
-
- // #ifdef _WIN32
- // we don't want to support wildcards in names here here
- if (name2.Find(L'?') >= 0 ||
- name2.Find(L'*') >= 0)
- return S_FALSE;
- // #endif
-
- #endif
-
-
- FString fullPath;
- if (!NFile::NName::GetFullPath(_folderPrefix, us2fs(name2), fullPath))
- return S_FALSE;
- if (!_fileInfo.Find(fullPath))
- return S_FALSE;
- if (_fileInfo.IsDir())
- return S_FALSE;
- CInFileStreamVol *inFile = new CInFileStreamVol;
- CMyComPtr<IInStream> inStreamTemp = inFile;
- if (!inFile->Open(fullPath))
- {
- DWORD lastError = ::GetLastError();
- if (lastError == 0)
- return E_FAIL;
- return HRESULT_FROM_WIN32(lastError);
- }
-
- FileSizes.Add(_fileInfo.Size);
- FileNames.Add(name2);
- inFile->FileNameIndex = FileNames_WasUsed.Add(true);
- inFile->OpenCallbackImp = this;
- inFile->OpenCallbackRef = this;
- // TotalSize += _fileInfo.Size;
- *inStream = inStreamTemp.Detach();
- return S_OK;
- COM_TRY_END
-}
-
-#ifndef _NO_CRYPTO
-STDMETHODIMP COpenCallbackImp::CryptoGetTextPassword(BSTR *password)
-{
- COM_TRY_BEGIN
- if (ReOpenCallback)
- {
- CMyComPtr<ICryptoGetTextPassword> getTextPassword;
- ReOpenCallback.QueryInterface(IID_ICryptoGetTextPassword, &getTextPassword);
- if (getTextPassword)
- return getTextPassword->CryptoGetTextPassword(password);
- }
- if (!Callback)
- return E_NOTIMPL;
- PasswordWasAsked = true;
- return Callback->Open_CryptoGetTextPassword(password);
- COM_TRY_END
-}
-#endif
+// ArchiveOpenCallback.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/ComTry.h"
+
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/System.h"
+
+#include "../../Common/StreamUtils.h"
+
+#include "ArchiveOpenCallback.h"
+
+// #define DEBUG_VOLUMES
+
+#ifdef DEBUG_VOLUMES
+#include <stdio.h>
+#endif
+
+
+#ifdef DEBUG_VOLUMES
+ #define PRF(x) x
+#else
+ #define PRF(x)
+#endif
+
+using namespace NWindows;
+
+HRESULT COpenCallbackImp::Init2(const FString &folderPrefix, const FString &fileName)
+{
+ Volumes.Init();
+ FileNames.Clear();
+ FileNames_WasUsed.Clear();
+ FileSizes.Clear();
+ _subArchiveMode = false;
+ // TotalSize = 0;
+ PasswordWasAsked = false;
+ _folderPrefix = folderPrefix;
+ if (!_fileInfo.Find_FollowLink(_folderPrefix + fileName))
+ {
+ // throw 20121118;
+ return GetLastError_noZero_HRESULT();
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(COpenCallbackImp::SetSubArchiveName(const wchar_t *name))
+{
+ _subArchiveMode = true;
+ _subArchiveName = name;
+ // TotalSize = 0;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(COpenCallbackImp::SetTotal(const UInt64 *files, const UInt64 *bytes))
+{
+ COM_TRY_BEGIN
+ if (ReOpenCallback)
+ return ReOpenCallback->SetTotal(files, bytes);
+ if (!Callback)
+ return S_OK;
+ return Callback->Open_SetTotal(files, bytes);
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(COpenCallbackImp::SetCompleted(const UInt64 *files, const UInt64 *bytes))
+{
+ COM_TRY_BEGIN
+ if (ReOpenCallback)
+ return ReOpenCallback->SetCompleted(files, bytes);
+ if (!Callback)
+ return S_OK;
+ return Callback->Open_SetCompleted(files, bytes);
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(COpenCallbackImp::GetProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ if (_subArchiveMode)
+ switch (propID)
+ {
+ case kpidName: prop = _subArchiveName; break;
+ // case kpidSize: prop = _subArchiveSize; break; // we don't use it now
+ }
+ else
+ switch (propID)
+ {
+ case kpidName: prop = fs2us(_fileInfo.Name); break;
+ case kpidIsDir: prop = _fileInfo.IsDir(); break;
+ case kpidSize: prop = _fileInfo.Size; break;
+ case kpidAttrib: prop = (UInt32)_fileInfo.GetWinAttrib(); break;
+ case kpidPosixAttrib: prop = (UInt32)_fileInfo.GetPosixAttrib(); break;
+ case kpidCTime: PropVariant_SetFrom_FiTime(prop, _fileInfo.CTime); break;
+ case kpidATime: PropVariant_SetFrom_FiTime(prop, _fileInfo.ATime); break;
+ case kpidMTime: PropVariant_SetFrom_FiTime(prop, _fileInfo.MTime); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+// ---------- CInFileStreamVol ----------
+
+Z7_CLASS_IMP_COM_2(
+ CInFileStreamVol
+ , IInStream
+ , IStreamGetSize
+)
+ Z7_IFACE_COM7_IMP(ISequentialInStream)
+public:
+ unsigned FileIndex;
+ COpenCallbackImp *OpenCallbackImp;
+ CMyComPtr<IArchiveOpenCallback> OpenCallbackRef;
+
+ HRESULT EnsureOpen()
+ {
+ return OpenCallbackImp->Volumes.EnsureOpen(FileIndex);
+ }
+
+ ~CInFileStreamVol()
+ {
+ if (OpenCallbackRef)
+ OpenCallbackImp->AtCloseFile(FileIndex);
+ }
+};
+
+
+void CMultiStreams::InsertToList(unsigned index)
+{
+ {
+ CSubStream &s = Streams[index];
+ s.Next = Head;
+ s.Prev = -1;
+ }
+ if (Head != -1)
+ Streams[(unsigned)Head].Prev = (int)index;
+ else
+ {
+ // if (Tail != -1) throw 1;
+ Tail = (int)index;
+ }
+ Head = (int)index;
+ NumListItems++;
+}
+
+// s must bee in List
+void CMultiStreams::RemoveFromList(CSubStream &s)
+{
+ if (s.Next != -1) Streams[(unsigned)s.Next].Prev = s.Prev; else Tail = s.Prev;
+ if (s.Prev != -1) Streams[(unsigned)s.Prev].Next = s.Next; else Head = s.Next;
+ s.Next = -1; // optional
+ s.Prev = -1; // optional
+ NumListItems--;
+}
+
+void CMultiStreams::CloseFile(unsigned index)
+{
+ CSubStream &s = Streams[index];
+ if (s.Stream)
+ {
+ s.Stream.Release();
+ RemoveFromList(s);
+ // s.InFile->Close();
+ // s.IsOpen = false;
+ #ifdef DEBUG_VOLUMES
+ static int numClosing = 0;
+ numClosing++;
+ printf("\nCloseFile %u, total_closes = %u, num_open_files = %u\n", index, numClosing, NumListItems);
+ #endif
+ }
+}
+
+void CMultiStreams::Init()
+{
+ Head = -1;
+ Tail = -1;
+ NumListItems = 0;
+ Streams.Clear();
+}
+
+CMultiStreams::CMultiStreams():
+ Head(-1),
+ Tail(-1),
+ NumListItems(0)
+{
+ NumOpenFiles_AllowedMax = NSystem::Get_File_OPEN_MAX_Reduced_for_3_tasks();
+ PRF(printf("\nNumOpenFiles_Limit = %u\n", NumOpenFiles_AllowedMax));
+}
+
+
+HRESULT CMultiStreams::PrepareToOpenNew()
+{
+ if (NumListItems < NumOpenFiles_AllowedMax)
+ return S_OK;
+ if (Tail == -1)
+ return E_FAIL;
+ CMultiStreams::CSubStream &tailStream = Streams[(unsigned)Tail];
+ RINOK(InStream_GetPos(tailStream.Stream, tailStream.LocalPos))
+ CloseFile((unsigned)Tail);
+ return S_OK;
+}
+
+
+HRESULT CMultiStreams::EnsureOpen(unsigned index)
+{
+ CMultiStreams::CSubStream &s = Streams[index];
+ if (s.Stream)
+ {
+ if ((int)index != Head)
+ {
+ RemoveFromList(s);
+ InsertToList(index);
+ }
+ }
+ else
+ {
+ RINOK(PrepareToOpenNew())
+ {
+ CInFileStream *inFile = new CInFileStream;
+ CMyComPtr<IInStream> inStreamTemp = inFile;
+ if (!inFile->Open(s.Path))
+ return GetLastError_noZero_HRESULT();
+ s.FileSpec = inFile;
+ s.Stream = s.FileSpec;
+ InsertToList(index);
+ }
+ // s.IsOpen = true;
+ if (s.LocalPos != 0)
+ {
+ RINOK(s.Stream->Seek((Int64)s.LocalPos, STREAM_SEEK_SET, &s.LocalPos))
+ }
+ #ifdef DEBUG_VOLUMES
+ static int numOpens = 0;
+ numOpens++;
+ printf("\n-- %u, ReOpen, total_reopens = %u, num_open_files = %u\n", index, numOpens, NumListItems);
+ #endif
+ }
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CInFileStreamVol::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ RINOK(EnsureOpen())
+ CMultiStreams::CSubStream &s = OpenCallbackImp->Volumes.Streams[FileIndex];
+ PRF(printf("\n== %u, Read =%u \n", FileIndex, size));
+ return s.Stream->Read(data, size, processedSize);
+}
+
+Z7_COM7F_IMF(CInFileStreamVol::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition))
+{
+ // if (seekOrigin >= 3) return STG_E_INVALIDFUNCTION;
+ RINOK(EnsureOpen())
+ CMultiStreams::CSubStream &s = OpenCallbackImp->Volumes.Streams[FileIndex];
+ PRF(printf("\n-- %u, Seek seekOrigin=%u Seek =%u\n", FileIndex, seekOrigin, (unsigned)offset));
+ return s.Stream->Seek(offset, seekOrigin, newPosition);
+}
+
+Z7_COM7F_IMF(CInFileStreamVol::GetSize(UInt64 *size))
+{
+ RINOK(EnsureOpen())
+ CMultiStreams::CSubStream &s = OpenCallbackImp->Volumes.Streams[FileIndex];
+ return s.FileSpec->GetSize(size);
+}
+
+
+// from ArchiveExtractCallback.cpp
+bool IsSafePath(const UString &path);
+
+Z7_COM7F_IMF(COpenCallbackImp::GetStream(const wchar_t *name, IInStream **inStream))
+{
+ COM_TRY_BEGIN
+ *inStream = NULL;
+
+ if (_subArchiveMode)
+ return S_FALSE;
+ if (Callback)
+ {
+ RINOK(Callback->Open_CheckBreak())
+ }
+
+ UString name2 = name;
+
+
+ #ifndef Z7_SFX
+
+ #ifdef _WIN32
+ name2.Replace(L'/', WCHAR_PATH_SEPARATOR);
+ #endif
+
+ // if (!allowAbsVolPaths)
+ if (!IsSafePath(name2))
+ return S_FALSE;
+
+ #ifdef _WIN32
+ /* WIN32 allows wildcards in Find() function
+ and doesn't allow wildcard in File.Open()
+ so we can work without the following wildcard check here */
+ if (name2.Find(L'*') >= 0)
+ return S_FALSE;
+ {
+ unsigned startPos = 0;
+ if (name2.IsPrefixedBy_Ascii_NoCase("\\\\?\\"))
+ startPos = 3;
+ if (name2.Find(L'?', startPos) >= 0)
+ return S_FALSE;
+ }
+ #endif
+
+ #endif
+
+
+ FString fullPath;
+ if (!NFile::NName::GetFullPath(_folderPrefix, us2fs(name2), fullPath))
+ return S_FALSE;
+ if (!_fileInfo.Find_FollowLink(fullPath))
+ return S_FALSE;
+ if (_fileInfo.IsDir())
+ return S_FALSE;
+
+ CMultiStreams::CSubStream s;
+
+ {
+ CInFileStream *inFile = new CInFileStream;
+ CMyComPtr<IInStream> inStreamTemp = inFile;
+ if (!inFile->Open(fullPath))
+ return GetLastError_noZero_HRESULT();
+ RINOK(Volumes.PrepareToOpenNew())
+ s.FileSpec = inFile;
+ s.Stream = s.FileSpec;
+ s.Path = fullPath;
+ // s.Size = _fileInfo.Size;
+ // s.IsOpen = true;
+ }
+
+ const unsigned fileIndex = Volumes.Streams.Add(s);
+ Volumes.InsertToList(fileIndex);
+
+ FileSizes.Add(_fileInfo.Size);
+ FileNames.Add(name2);
+ FileNames_WasUsed.Add(true);
+
+ CInFileStreamVol *inFile = new CInFileStreamVol;
+ CMyComPtr<IInStream> inStreamTemp = inFile;
+ inFile->FileIndex = fileIndex;
+ inFile->OpenCallbackImp = this;
+ inFile->OpenCallbackRef = this;
+ // TotalSize += _fileInfo.Size;
+ *inStream = inStreamTemp.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+
+#ifndef Z7_NO_CRYPTO
+Z7_COM7F_IMF(COpenCallbackImp::CryptoGetTextPassword(BSTR *password))
+{
+ COM_TRY_BEGIN
+ if (ReOpenCallback)
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ ICryptoGetTextPassword,
+ getTextPassword, ReOpenCallback)
+ if (getTextPassword)
+ return getTextPassword->CryptoGetTextPassword(password);
+ }
+ if (!Callback)
+ return E_NOTIMPL;
+ PasswordWasAsked = true;
+ return Callback->Open_CryptoGetTextPassword(password);
+ COM_TRY_END
+}
+#endif
+
+// IProgress
+Z7_COM7F_IMF(COpenCallbackImp::SetTotal(const UInt64 /* total */))
+{
+ return S_OK;
+}
+
+Z7_COM7F_IMF(COpenCallbackImp::SetCompleted(const UInt64 * /* completed */))
+{
+ return S_OK;
+}
diff --git a/CPP/7zip/UI/Common/ArchiveOpenCallback.h b/CPP/7zip/UI/Common/ArchiveOpenCallback.h
index 7f7548f..4e44c9d 100644
--- a/CPP/7zip/UI/Common/ArchiveOpenCallback.h
+++ b/CPP/7zip/UI/Common/ArchiveOpenCallback.h
@@ -1,112 +1,181 @@
-// ArchiveOpenCallback.h
-
-#ifndef __ARCHIVE_OPEN_CALLBACK_H
-#define __ARCHIVE_OPEN_CALLBACK_H
-
-#include "../../../Common/MyCom.h"
-
-#include "../../../Windows/FileFind.h"
-
-#ifndef _NO_CRYPTO
-#include "../../IPassword.h"
-#endif
-#include "../../Archive/IArchive.h"
-
-#ifdef _NO_CRYPTO
-
-#define INTERFACE_IOpenCallbackUI_Crypto(x)
-
-#else
-
-#define INTERFACE_IOpenCallbackUI_Crypto(x) \
- virtual HRESULT Open_CryptoGetTextPassword(BSTR *password) x; \
- /* virtual HRESULT Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password) x; */ \
- /* virtual bool Open_WasPasswordAsked() x; */ \
- /* virtual void Open_Clear_PasswordWasAsked_Flag() x; */ \
-
-#endif
-
-#define INTERFACE_IOpenCallbackUI(x) \
- virtual HRESULT Open_CheckBreak() x; \
- virtual HRESULT Open_SetTotal(const UInt64 *files, const UInt64 *bytes) x; \
- virtual HRESULT Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) x; \
- virtual HRESULT Open_Finished() x; \
- INTERFACE_IOpenCallbackUI_Crypto(x)
-
-struct IOpenCallbackUI
-{
- INTERFACE_IOpenCallbackUI(=0)
-};
-
-class COpenCallbackImp:
- public IArchiveOpenCallback,
- public IArchiveOpenVolumeCallback,
- public IArchiveOpenSetSubArchiveName,
- #ifndef _NO_CRYPTO
- public ICryptoGetTextPassword,
- #endif
- public CMyUnknownImp
-{
-public:
- MY_QUERYINTERFACE_BEGIN2(IArchiveOpenVolumeCallback)
- MY_QUERYINTERFACE_ENTRY(IArchiveOpenSetSubArchiveName)
- #ifndef _NO_CRYPTO
- MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword)
- #endif
- MY_QUERYINTERFACE_END
- MY_ADDREF_RELEASE
-
- INTERFACE_IArchiveOpenCallback(;)
- INTERFACE_IArchiveOpenVolumeCallback(;)
-
- #ifndef _NO_CRYPTO
- STDMETHOD(CryptoGetTextPassword)(BSTR *password);
- #endif
-
- STDMETHOD(SetSubArchiveName(const wchar_t *name))
- {
- _subArchiveMode = true;
- _subArchiveName = name;
- // TotalSize = 0;
- return S_OK;
- }
-
-private:
- FString _folderPrefix;
- NWindows::NFile::NFind::CFileInfo _fileInfo;
- bool _subArchiveMode;
- UString _subArchiveName;
-
-public:
- UStringVector FileNames;
- CBoolVector FileNames_WasUsed;
- CRecordVector<UInt64> FileSizes;
-
- bool PasswordWasAsked;
-
- IOpenCallbackUI *Callback;
- CMyComPtr<IArchiveOpenCallback> ReOpenCallback;
- // UInt64 TotalSize;
-
- COpenCallbackImp(): Callback(NULL), _subArchiveMode(false) {}
-
- void Init(const FString &folderPrefix, const FString &fileName)
- {
- _folderPrefix = folderPrefix;
- if (!_fileInfo.Find(_folderPrefix + fileName))
- throw 20121118;
- FileNames.Clear();
- FileNames_WasUsed.Clear();
- FileSizes.Clear();
- _subArchiveMode = false;
- // TotalSize = 0;
- PasswordWasAsked = false;
- }
-
- bool SetSecondFileInfo(CFSTR newName)
- {
- return _fileInfo.Find(newName) && !_fileInfo.IsDir();
- }
-};
-
-#endif
+// ArchiveOpenCallback.h
+
+#ifndef ZIP7_INC_ARCHIVE_OPEN_CALLBACK_H
+#define ZIP7_INC_ARCHIVE_OPEN_CALLBACK_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../../Windows/FileFind.h"
+
+#include "../../Common/FileStreams.h"
+
+#ifndef Z7_NO_CRYPTO
+#include "../../IPassword.h"
+#endif
+#include "../../Archive/IArchive.h"
+
+Z7_PURE_INTERFACES_BEGIN
+
+#ifdef Z7_NO_CRYPTO
+
+#define Z7_IFACEM_IOpenCallbackUI_Crypto(x)
+
+#else
+
+#define Z7_IFACEM_IOpenCallbackUI_Crypto(x) \
+ virtual HRESULT Open_CryptoGetTextPassword(BSTR *password) x \
+ /* virtual HRESULT Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password) x */ \
+ /* virtual bool Open_WasPasswordAsked() x */ \
+ /* virtual void Open_Clear_PasswordWasAsked_Flag() x */ \
+
+#endif
+
+#define Z7_IFACEN_IOpenCallbackUI(x) \
+ virtual HRESULT Open_CheckBreak() x \
+ virtual HRESULT Open_SetTotal(const UInt64 *files, const UInt64 *bytes) x \
+ virtual HRESULT Open_SetCompleted(const UInt64 *files, const UInt64 *bytes) x \
+ virtual HRESULT Open_Finished() x \
+ Z7_IFACEM_IOpenCallbackUI_Crypto(x)
+
+Z7_IFACE_DECL_PURE(IOpenCallbackUI)
+
+Z7_PURE_INTERFACES_END
+
+
+class CMultiStreams Z7_final
+{
+public:
+ struct CSubStream
+ {
+ CMyComPtr<IInStream> Stream;
+ CInFileStream *FileSpec;
+ FString Path;
+ // UInt64 Size;
+ UInt64 LocalPos;
+ int Next; // next older
+ int Prev; // prev newer
+ // bool IsOpen;
+
+ CSubStream():
+ FileSpec(NULL),
+ // Size(0),
+ LocalPos(0),
+ Next(-1),
+ Prev(-1)
+ // IsOpen(false)
+ {}
+ };
+
+ CObjectVector<CSubStream> Streams;
+private:
+ // we must use critical section here, if we want to access from different volumnes simultaneously
+ int Head; // newest
+ int Tail; // oldest
+ unsigned NumListItems;
+ unsigned NumOpenFiles_AllowedMax;
+public:
+
+ CMultiStreams();
+ void Init();
+ HRESULT PrepareToOpenNew();
+ void InsertToList(unsigned index);
+ void RemoveFromList(CSubStream &s);
+ void CloseFile(unsigned index);
+ HRESULT EnsureOpen(unsigned index);
+};
+
+
+/*
+ We need COpenCallbackImp class for multivolume processing.
+ Also we use it as proxy from COM interfaces (IArchiveOpenCallback) to internal (IOpenCallbackUI) interfaces.
+ If archive is multivolume:
+ COpenCallbackImp object will exist after Open stage.
+ COpenCallbackImp object will be deleted when last reference
+ from each volume object (CInFileStreamVol) will be closed (when archive will be closed).
+*/
+
+class COpenCallbackImp Z7_final:
+ public IArchiveOpenCallback,
+ public IArchiveOpenVolumeCallback,
+ public IArchiveOpenSetSubArchiveName,
+ #ifndef Z7_NO_CRYPTO
+ public ICryptoGetTextPassword,
+ #endif
+ public IProgress, // IProgress is used for 7zFM
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(IArchiveOpenCallback)
+ Z7_COM_QI_ENTRY(IArchiveOpenVolumeCallback)
+ Z7_COM_QI_ENTRY(IArchiveOpenSetSubArchiveName)
+ #ifndef Z7_NO_CRYPTO
+ Z7_COM_QI_ENTRY(ICryptoGetTextPassword)
+ #endif
+ // Z7_COM_QI_ENTRY(IProgress) // the code doesn't require it
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(IArchiveOpenCallback)
+ Z7_IFACE_COM7_IMP(IArchiveOpenVolumeCallback)
+ Z7_IFACE_COM7_IMP(IProgress)
+public:
+ Z7_IFACE_COM7_IMP(IArchiveOpenSetSubArchiveName)
+private:
+ #ifndef Z7_NO_CRYPTO
+ Z7_IFACE_COM7_IMP(ICryptoGetTextPassword)
+ #endif
+
+ bool _subArchiveMode;
+
+public:
+ bool PasswordWasAsked;
+ UStringVector FileNames;
+ CBoolVector FileNames_WasUsed;
+ CRecordVector<UInt64> FileSizes;
+
+ void AtCloseFile(unsigned fileIndex)
+ {
+ FileNames_WasUsed[fileIndex] = false;
+ Volumes.CloseFile(fileIndex);
+ }
+
+ /* we have two ways to Callback from this object
+ 1) IArchiveOpenCallback * ReOpenCallback - for ReOpen function, when IOpenCallbackUI is not available
+ 2) IOpenCallbackUI *Callback - for usual callback
+ we can't transfer IOpenCallbackUI pointer via internal interface,
+ so we use ReOpenCallback to callback without IOpenCallbackUI.
+ */
+
+ /* we use Callback/ReOpenCallback only at Open stage.
+ So the CMyComPtr reference counter is not required,
+ and we don't want additional reference to unused object,
+ if COpenCallbackImp is not closed
+ */
+ IArchiveOpenCallback *ReOpenCallback;
+ // CMyComPtr<IArchiveOpenCallback> ReOpenCallback;
+ IOpenCallbackUI *Callback;
+ // CMyComPtr<IUnknown> Callback_Ref;
+
+private:
+ FString _folderPrefix;
+ UString _subArchiveName;
+ NWindows::NFile::NFind::CFileInfo _fileInfo;
+
+public:
+ CMultiStreams Volumes;
+
+ // UInt64 TotalSize;
+
+ COpenCallbackImp():
+ _subArchiveMode(false),
+ ReOpenCallback(NULL),
+ Callback(NULL) {}
+
+ HRESULT Init2(const FString &folderPrefix, const FString &fileName);
+
+ bool SetSecondFileInfo(CFSTR newName)
+ {
+ return _fileInfo.Find_FollowLink(newName) && !_fileInfo.IsDir();
+ }
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/Bench.cpp b/CPP/7zip/UI/Common/Bench.cpp
index 3fb0758..5da9783 100644
--- a/CPP/7zip/UI/Common/Bench.cpp
+++ b/CPP/7zip/UI/Common/Bench.cpp
@@ -1,3618 +1,4872 @@
-// Bench.cpp
-
-#include "StdAfx.h"
-
-#include <stdio.h>
-
-#ifndef _WIN32
-#define USE_POSIX_TIME
-#define USE_POSIX_TIME2
-#endif
-
-#ifdef USE_POSIX_TIME
-#include <time.h>
-#ifdef USE_POSIX_TIME2
-#include <sys/time.h>
-#endif
-#endif
-
-#ifdef _WIN32
-#define USE_ALLOCA
-#endif
-
-#ifdef USE_ALLOCA
-#ifdef _WIN32
-#include <malloc.h>
-#else
-#include <stdlib.h>
-#endif
-#endif
-
-#include "../../../../C/7zCrc.h"
-#include "../../../../C/CpuArch.h"
-
-#ifndef _7ZIP_ST
-#include "../../../Windows/Synchronization.h"
-#include "../../../Windows/Thread.h"
-#endif
-
-#if defined(_WIN32) || defined(UNIX_USE_WIN_FILE)
-#define USE_WIN_FILE
-#endif
-
-#ifdef USE_WIN_FILE
-#include "../../../Windows/FileIO.h"
-#endif
-
-
-#include "../../../Common/IntToString.h"
-#include "../../../Common/MyBuffer2.h"
-#include "../../../Common/StringConvert.h"
-#include "../../../Common/StringToInt.h"
-
-#include "../../Common/MethodProps.h"
-#include "../../Common/StreamUtils.h"
-
-#include "Bench.h"
-
-using namespace NWindows;
-
-static const UInt32 k_LZMA = 0x030101;
-
-static const UInt64 kComplexInCommands = (UInt64)1 <<
- #ifdef UNDER_CE
- 31;
- #else
- 34;
- #endif
-
-static const UInt32 kComplexInSeconds = 4;
-
-static void SetComplexCommands(UInt32 complexInSeconds,
- bool isSpecifiedFreq, UInt64 cpuFreq, UInt64 &complexInCommands)
-{
- complexInCommands = kComplexInCommands;
- const UInt64 kMinFreq = (UInt64)1000000 * 4;
- const UInt64 kMaxFreq = (UInt64)1000000 * 20000;
- if (cpuFreq < kMinFreq && !isSpecifiedFreq)
- cpuFreq = kMinFreq;
- if (cpuFreq < kMaxFreq || isSpecifiedFreq)
- {
- if (complexInSeconds != 0)
- complexInCommands = complexInSeconds * cpuFreq;
- else
- complexInCommands = cpuFreq >> 2;
- }
-}
-
-static const unsigned kNumHashDictBits = 17;
-static const UInt32 kFilterUnpackSize = (48 << 10);
-
-static const unsigned kOldLzmaDictBits = 30;
-
-static const UInt32 kAdditionalSize = (1 << 16);
-static const UInt32 kCompressedAdditionalSize = (1 << 10);
-static const UInt32 kMaxLzmaPropSize = 5;
-
-
-
-#define ALLOC_WITH_HRESULT(_buffer_, _size_) \
- (_buffer_)->Alloc(_size_); \
- if (!(_buffer_)->IsAllocated()) return E_OUTOFMEMORY;
-
-
-class CBaseRandomGenerator
-{
- UInt32 A1;
- UInt32 A2;
- UInt32 Salt;
-public:
- CBaseRandomGenerator(UInt32 salt = 0): Salt(salt) { Init(); }
- void Init() { A1 = 362436069; A2 = 521288629;}
- UInt32 GetRnd()
- {
- return Salt ^
- (
- ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) +
- ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) )
- );
- }
-};
-
-
-class CBenchRandomGenerator: public CAlignedBuffer
-{
- static UInt32 GetVal(UInt32 &res, unsigned numBits)
- {
- UInt32 val = res & (((UInt32)1 << numBits) - 1);
- res >>= numBits;
- return val;
- }
-
- static UInt32 GetLen(UInt32 &r)
- {
- UInt32 len = GetVal(r, 2);
- return GetVal(r, 1 + len);
- }
-
-public:
-
- void GenerateSimpleRandom(UInt32 salt)
- {
- CBaseRandomGenerator rg(salt);
- const size_t bufSize = Size();
- Byte *buf = (Byte *)*this;
- for (size_t i = 0; i < bufSize; i++)
- buf[i] = (Byte)rg.GetRnd();
- }
-
- void GenerateLz(unsigned dictBits, UInt32 salt)
- {
- CBaseRandomGenerator rg(salt);
- UInt32 pos = 0;
- UInt32 rep0 = 1;
- const size_t bufSize = Size();
- Byte *buf = (Byte *)*this;
- unsigned posBits = 1;
-
- while (pos < bufSize)
- {
- UInt32 r = rg.GetRnd();
- if (GetVal(r, 1) == 0 || pos < 1024)
- buf[pos++] = (Byte)(r & 0xFF);
- else
- {
- UInt32 len;
- len = 1 + GetLen(r);
-
- if (GetVal(r, 3) != 0)
- {
- len += GetLen(r);
-
- while (((UInt32)1 << posBits) < pos)
- posBits++;
-
- unsigned numBitsMax = dictBits;
- if (numBitsMax > posBits)
- numBitsMax = posBits;
-
- const unsigned kAddBits = 6;
- unsigned numLogBits = 5;
- if (numBitsMax <= (1 << 4) - 1 + kAddBits)
- numLogBits = 4;
-
- for (;;)
- {
- UInt32 ppp = GetVal(r, numLogBits) + kAddBits;
- r = rg.GetRnd();
- if (ppp > numBitsMax)
- continue;
- rep0 = GetVal(r, ppp);
- if (rep0 < pos)
- break;
- r = rg.GetRnd();
- }
- rep0++;
- }
-
- {
- UInt32 rem = (UInt32)bufSize - pos;
- if (len > rem)
- len = rem;
- }
- Byte *dest = buf + pos;
- const Byte *src = dest - rep0;
- pos += len;
- for (UInt32 i = 0; i < len; i++)
- *dest++ = *src++;
- }
- }
- }
-};
-
-
-class CBenchmarkInStream:
- public ISequentialInStream,
- public CMyUnknownImp
-{
- const Byte *Data;
- size_t Pos;
- size_t Size;
-public:
- MY_UNKNOWN_IMP
- void Init(const Byte *data, size_t size)
- {
- Data = data;
- Size = size;
- Pos = 0;
- }
- STDMETHOD(Read)(void *data, UInt32 size, UInt32 *processedSize);
-};
-
-STDMETHODIMP CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize)
-{
- size_t remain = Size - Pos;
- UInt32 kMaxBlockSize = (1 << 20);
- if (size > kMaxBlockSize)
- size = kMaxBlockSize;
- if (size > remain)
- size = (UInt32)remain;
- for (UInt32 i = 0; i < size; i++)
- ((Byte *)data)[i] = Data[Pos + i];
- Pos += size;
- if (processedSize)
- *processedSize = size;
- return S_OK;
-}
-
-class CBenchmarkOutStream:
- public ISequentialOutStream,
- public CAlignedBuffer,
- public CMyUnknownImp
-{
- // bool _overflow;
-public:
- size_t Pos;
- bool RealCopy;
- bool CalcCrc;
- UInt32 Crc;
-
- // CBenchmarkOutStream(): _overflow(false) {}
- void Init(bool realCopy, bool calcCrc)
- {
- Crc = CRC_INIT_VAL;
- RealCopy = realCopy;
- CalcCrc = calcCrc;
- // _overflow = false;
- Pos = 0;
- }
-
- // void Print() { printf("\n%8d %8d\n", (unsigned)BufferSize, (unsigned)Pos); }
-
- MY_UNKNOWN_IMP
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
-};
-
-STDMETHODIMP CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- size_t curSize = Size() - Pos;
- if (curSize > size)
- curSize = size;
- if (curSize != 0)
- {
- if (RealCopy)
- memcpy(((Byte *)*this) + Pos, data, curSize);
- if (CalcCrc)
- Crc = CrcUpdate(Crc, data, curSize);
- Pos += curSize;
- }
- if (processedSize)
- *processedSize = (UInt32)curSize;
- if (curSize != size)
- {
- // _overflow = true;
- return E_FAIL;
- }
- return S_OK;
-}
-
-class CCrcOutStream:
- public ISequentialOutStream,
- public CMyUnknownImp
-{
-public:
- bool CalcCrc;
- UInt32 Crc;
- MY_UNKNOWN_IMP
-
- CCrcOutStream(): CalcCrc(true) {};
- void Init() { Crc = CRC_INIT_VAL; }
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
-};
-
-STDMETHODIMP CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- if (CalcCrc)
- Crc = CrcUpdate(Crc, data, size);
- if (processedSize)
- *processedSize = size;
- return S_OK;
-}
-
-static UInt64 GetTimeCount()
-{
- #ifdef USE_POSIX_TIME
- #ifdef USE_POSIX_TIME2
- timeval v;
- if (gettimeofday(&v, 0) == 0)
- return (UInt64)(v.tv_sec) * 1000000 + v.tv_usec;
- return (UInt64)time(NULL) * 1000000;
- #else
- return time(NULL);
- #endif
- #else
- /*
- LARGE_INTEGER value;
- if (::QueryPerformanceCounter(&value))
- return value.QuadPart;
- */
- return GetTickCount();
- #endif
-}
-
-static UInt64 GetFreq()
-{
- #ifdef USE_POSIX_TIME
- #ifdef USE_POSIX_TIME2
- return 1000000;
- #else
- return 1;
- #endif
- #else
- /*
- LARGE_INTEGER value;
- if (::QueryPerformanceFrequency(&value))
- return value.QuadPart;
- */
- return 1000;
- #endif
-}
-
-#ifdef USE_POSIX_TIME
-
-struct CUserTime
-{
- UInt64 Sum;
- clock_t Prev;
-
- void Init()
- {
- Prev = clock();
- Sum = 0;
- }
-
- UInt64 GetUserTime()
- {
- clock_t v = clock();
- Sum += v - Prev;
- Prev = v;
- return Sum;
- }
-};
-
-#else
-
-static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }
-UInt64 GetWinUserTime()
-{
- FILETIME creationTime, exitTime, kernelTime, userTime;
- if (
- #ifdef UNDER_CE
- ::GetThreadTimes(::GetCurrentThread()
- #else
- ::GetProcessTimes(::GetCurrentProcess()
- #endif
- , &creationTime, &exitTime, &kernelTime, &userTime) != 0)
- return GetTime64(userTime) + GetTime64(kernelTime);
- return (UInt64)GetTickCount() * 10000;
-}
-
-struct CUserTime
-{
- UInt64 StartTime;
-
- void Init() { StartTime = GetWinUserTime(); }
- UInt64 GetUserTime() { return GetWinUserTime() - StartTime; }
-};
-
-#endif
-
-static UInt64 GetUserFreq()
-{
- #ifdef USE_POSIX_TIME
- return CLOCKS_PER_SEC;
- #else
- return 10000000;
- #endif
-}
-
-class CBenchProgressStatus
-{
- #ifndef _7ZIP_ST
- NSynchronization::CCriticalSection CS;
- #endif
-public:
- HRESULT Res;
- bool EncodeMode;
- void SetResult(HRESULT res)
- {
- #ifndef _7ZIP_ST
- NSynchronization::CCriticalSectionLock lock(CS);
- #endif
- Res = res;
- }
- HRESULT GetResult()
- {
- #ifndef _7ZIP_ST
- NSynchronization::CCriticalSectionLock lock(CS);
- #endif
- return Res;
- }
-};
-
-struct CBenchInfoCalc
-{
- CBenchInfo BenchInfo;
- CUserTime UserTime;
-
- void SetStartTime();
- void SetFinishTime(CBenchInfo &dest);
-};
-
-void CBenchInfoCalc::SetStartTime()
-{
- BenchInfo.GlobalFreq = GetFreq();
- BenchInfo.UserFreq = GetUserFreq();
- BenchInfo.GlobalTime = ::GetTimeCount();
- BenchInfo.UserTime = 0;
- UserTime.Init();
-}
-
-void CBenchInfoCalc::SetFinishTime(CBenchInfo &dest)
-{
- dest = BenchInfo;
- dest.GlobalTime = ::GetTimeCount() - BenchInfo.GlobalTime;
- dest.UserTime = UserTime.GetUserTime();
-}
-
-class CBenchProgressInfo:
- public ICompressProgressInfo,
- public CMyUnknownImp,
- public CBenchInfoCalc
-{
-public:
- CBenchProgressStatus *Status;
- IBenchCallback *Callback;
-
- CBenchProgressInfo(): Callback(NULL) {}
- MY_UNKNOWN_IMP
- STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
-};
-
-STDMETHODIMP CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
-{
- HRESULT res = Status->GetResult();
- if (res != S_OK)
- return res;
- if (!Callback)
- return res;
- CBenchInfo info;
- SetFinishTime(info);
- if (Status->EncodeMode)
- {
- info.UnpackSize = BenchInfo.UnpackSize + *inSize;
- info.PackSize = BenchInfo.PackSize + *outSize;
- res = Callback->SetEncodeResult(info, false);
- }
- else
- {
- info.PackSize = BenchInfo.PackSize + *inSize;
- info.UnpackSize = BenchInfo.UnpackSize + *outSize;
- res = Callback->SetDecodeResult(info, false);
- }
- if (res != S_OK)
- Status->SetResult(res);
- return res;
-}
-
-static const unsigned kSubBits = 8;
-
-static UInt32 GetLogSize(UInt32 size)
-{
- for (unsigned i = kSubBits; i < 32; i++)
- for (UInt32 j = 0; j < (1 << kSubBits); j++)
- if (size <= (((UInt32)1) << i) + (j << (i - kSubBits)))
- return (i << kSubBits) + j;
- return (32 << kSubBits);
-}
-
-static void NormalizeVals(UInt64 &v1, UInt64 &v2)
-{
- while (v1 > 1000000)
- {
- v1 >>= 1;
- v2 >>= 1;
- }
-}
-
-UInt64 CBenchInfo::GetUsage() const
-{
- UInt64 userTime = UserTime;
- UInt64 userFreq = UserFreq;
- UInt64 globalTime = GlobalTime;
- UInt64 globalFreq = GlobalFreq;
- NormalizeVals(userTime, userFreq);
- NormalizeVals(globalFreq, globalTime);
- if (userFreq == 0)
- userFreq = 1;
- if (globalTime == 0)
- globalTime = 1;
- return userTime * globalFreq * 1000000 / userFreq / globalTime;
-}
-
-UInt64 CBenchInfo::GetRatingPerUsage(UInt64 rating) const
-{
- UInt64 userTime = UserTime;
- UInt64 userFreq = UserFreq;
- UInt64 globalTime = GlobalTime;
- UInt64 globalFreq = GlobalFreq;
- NormalizeVals(userFreq, userTime);
- NormalizeVals(globalTime, globalFreq);
- if (globalFreq == 0)
- globalFreq = 1;
- if (userTime == 0)
- userTime = 1;
- return userFreq * globalTime / globalFreq * rating / userTime;
-}
-
-static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime, UInt64 freq)
-{
- UInt64 elTime = elapsedTime;
- NormalizeVals(freq, elTime);
- if (elTime == 0)
- elTime = 1;
- return value * freq / elTime;
-}
-
-UInt64 CBenchInfo::GetSpeed(UInt64 numCommands) const
-{
- return MyMultDiv64(numCommands, GlobalTime, GlobalFreq);
-}
-
-struct CBenchProps
-{
- bool LzmaRatingMode;
-
- UInt32 EncComplex;
- UInt32 DecComplexCompr;
- UInt32 DecComplexUnc;
-
- CBenchProps(): LzmaRatingMode(false) {}
- void SetLzmaCompexity();
-
- UInt64 GeComprCommands(UInt64 unpackSize)
- {
- return unpackSize * EncComplex;
- }
-
- UInt64 GeDecomprCommands(UInt64 packSize, UInt64 unpackSize)
- {
- return (packSize * DecComplexCompr + unpackSize * DecComplexUnc);
- }
-
- UInt64 GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size);
- UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations);
-};
-
-void CBenchProps::SetLzmaCompexity()
-{
- EncComplex = 1200;
- DecComplexUnc = 4;
- DecComplexCompr = 190;
- LzmaRatingMode = true;
-}
-
-UInt64 CBenchProps::GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size)
-{
- if (dictSize < (1 << kBenchMinDicLogSize))
- dictSize = (1 << kBenchMinDicLogSize);
- UInt64 encComplex = EncComplex;
- if (LzmaRatingMode)
- {
- UInt64 t = GetLogSize(dictSize) - (kBenchMinDicLogSize << kSubBits);
- encComplex = 870 + ((t * t * 5) >> (2 * kSubBits));
- }
- UInt64 numCommands = (UInt64)size * encComplex;
- return MyMultDiv64(numCommands, elapsedTime, freq);
-}
-
-UInt64 CBenchProps::GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations)
-{
- UInt64 numCommands = (inSize * DecComplexCompr + outSize * DecComplexUnc) * numIterations;
- return MyMultDiv64(numCommands, elapsedTime, freq);
-}
-
-UInt64 GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size)
-{
- CBenchProps props;
- props.SetLzmaCompexity();
- return props.GetCompressRating(dictSize, elapsedTime, freq, size);
-}
-
-UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations)
-{
- CBenchProps props;
- props.SetLzmaCompexity();
- return props.GetDecompressRating(elapsedTime, freq, outSize, inSize, numIterations);
-}
-
-
-
-
-#ifndef _7ZIP_ST
-struct CBenchSyncCommon
-{
- bool ExitMode;
- NSynchronization::CManualResetEvent StartEvent;
-
- CBenchSyncCommon(): ExitMode(false) {}
-};
-#endif
-
-
-struct CEncoderInfo;
-
-struct CEncoderInfo
-{
- #ifndef _7ZIP_ST
- NWindows::CThread thread[2];
- NSynchronization::CManualResetEvent ReadyEvent;
- UInt32 NumDecoderSubThreads;
- CBenchSyncCommon *Common;
- #endif
-
- CMyComPtr<ICompressCoder> _encoder;
- CMyComPtr<ICompressFilter> _encoderFilter;
- CBenchProgressInfo *progressInfoSpec[2];
- CMyComPtr<ICompressProgressInfo> progressInfo[2];
- UInt64 NumIterations;
-
- UInt32 Salt;
-
- #ifdef USE_ALLOCA
- size_t AllocaSize;
- #endif
-
- Byte _key[32];
- Byte _iv[16];
- Byte _psw[16];
- bool CheckCrc_Enc;
- bool CheckCrc_Dec;
-
- struct CDecoderInfo
- {
- CEncoderInfo *Encoder;
- UInt32 DecoderIndex;
- bool CallbackMode;
-
- #ifdef USE_ALLOCA
- size_t AllocaSize;
- #endif
- };
- CDecoderInfo decodersInfo[2];
-
- CMyComPtr<ICompressCoder> _decoders[2];
- CMyComPtr<ICompressFilter> _decoderFilter;
-
- HRESULT Results[2];
- CBenchmarkOutStream *outStreamSpec;
- CMyComPtr<ISequentialOutStream> outStream;
- IBenchCallback *callback;
- IBenchPrintCallback *printCallback;
- UInt32 crc;
- size_t kBufferSize;
- size_t compressedSize;
- const Byte *uncompressedDataPtr;
-
- const Byte *fileData;
- CBenchRandomGenerator rg;
-
- CAlignedBuffer rgCopy; // it must be 16-byte aligned !!!
- CBenchmarkOutStream *propStreamSpec;
- CMyComPtr<ISequentialOutStream> propStream;
-
- unsigned generateDictBits;
- COneMethodInfo _method;
-
- // for decode
- size_t _uncompressedDataSize;
-
- HRESULT Generate();
- HRESULT Encode();
- HRESULT Decode(UInt32 decoderIndex);
-
- CEncoderInfo():
- #ifndef _7ZIP_ST
- Common(NULL),
- #endif
- Salt(0),
- fileData(NULL),
- CheckCrc_Enc(true),
- CheckCrc_Dec(true),
- outStreamSpec(NULL), callback(NULL), printCallback(NULL), propStreamSpec(NULL) {}
-
- #ifndef _7ZIP_ST
-
- static THREAD_FUNC_DECL EncodeThreadFunction(void *param)
- {
- HRESULT res;
- CEncoderInfo *encoder = (CEncoderInfo *)param;
- try
- {
- #ifdef USE_ALLOCA
- alloca(encoder->AllocaSize);
- #endif
-
- res = encoder->Encode();
- }
- catch(...)
- {
- res = E_FAIL;
- }
- encoder->Results[0] = res;
- if (res != S_OK)
- encoder->progressInfoSpec[0]->Status->SetResult(res);
- encoder->ReadyEvent.Set();
- return 0;
- }
-
- static THREAD_FUNC_DECL DecodeThreadFunction(void *param)
- {
- CDecoderInfo *decoder = (CDecoderInfo *)param;
-
- #ifdef USE_ALLOCA
- alloca(decoder->AllocaSize);
- #endif
-
- CEncoderInfo *encoder = decoder->Encoder;
- encoder->Results[decoder->DecoderIndex] = encoder->Decode(decoder->DecoderIndex);
- return 0;
- }
-
- HRESULT CreateEncoderThread()
- {
- WRes res = 0;
- if (!ReadyEvent.IsCreated())
- res = ReadyEvent.Create();
- if (res == 0)
- res = thread[0].Create(EncodeThreadFunction, this);
- return HRESULT_FROM_WIN32(res);
- }
-
- HRESULT CreateDecoderThread(unsigned index, bool callbackMode
- #ifdef USE_ALLOCA
- , size_t allocaSize
- #endif
- )
- {
- CDecoderInfo &decoder = decodersInfo[index];
- decoder.DecoderIndex = index;
- decoder.Encoder = this;
-
- #ifdef USE_ALLOCA
- decoder.AllocaSize = allocaSize;
- #endif
-
- decoder.CallbackMode = callbackMode;
- return thread[index].Create(DecodeThreadFunction, &decoder);
- }
-
- #endif
-};
-
-
-HRESULT CEncoderInfo::Generate()
-{
- const COneMethodInfo &method = _method;
-
- // we need extra space, if input data is already compressed
- const size_t kCompressedBufferSize =
- kCompressedAdditionalSize +
- kBufferSize + kBufferSize / 16;
- // kBufferSize / 2;
-
- if (kCompressedBufferSize < kBufferSize)
- return E_FAIL;
-
- uncompressedDataPtr = fileData;
-
- if (!fileData)
- {
- ALLOC_WITH_HRESULT(&rg, kBufferSize);
-
- // DWORD ttt = GetTickCount();
- if (generateDictBits == 0)
- rg.GenerateSimpleRandom(Salt);
- else
- rg.GenerateLz(generateDictBits, Salt);
- // printf("\n%d\n ", GetTickCount() - ttt);
-
- crc = CrcCalc((const Byte *)rg, rg.Size());
- uncompressedDataPtr = (const Byte *)rg;
- }
-
- if (_encoderFilter)
- {
- ALLOC_WITH_HRESULT(&rgCopy, kBufferSize);
- }
-
-
- if (!outStream)
- {
- outStreamSpec = new CBenchmarkOutStream;
- outStream = outStreamSpec;
- }
-
- ALLOC_WITH_HRESULT(outStreamSpec, kCompressedBufferSize)
-
- if (!propStream)
- {
- propStreamSpec = new CBenchmarkOutStream;
- propStream = propStreamSpec;
- }
- ALLOC_WITH_HRESULT(propStreamSpec, kMaxLzmaPropSize);
- propStreamSpec->Init(true, false);
-
-
- CMyComPtr<IUnknown> coder;
- if (_encoderFilter)
- coder = _encoderFilter;
- else
- coder = _encoder;
- {
- CMyComPtr<ICompressSetCoderProperties> scp;
- coder.QueryInterface(IID_ICompressSetCoderProperties, &scp);
- if (scp)
- {
- UInt64 reduceSize = kBufferSize;
- RINOK(method.SetCoderProps(scp, &reduceSize));
- }
- else
- {
- if (method.AreThereNonOptionalProps())
- return E_INVALIDARG;
- }
-
- CMyComPtr<ICompressWriteCoderProperties> writeCoderProps;
- coder.QueryInterface(IID_ICompressWriteCoderProperties, &writeCoderProps);
- if (writeCoderProps)
- {
- RINOK(writeCoderProps->WriteCoderProperties(propStream));
- }
-
- {
- CMyComPtr<ICryptoSetPassword> sp;
- coder.QueryInterface(IID_ICryptoSetPassword, &sp);
- if (sp)
- {
- RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw)));
-
- // we must call encoding one time to calculate password key for key cache.
- // it must be after WriteCoderProperties!
- Byte temp[16];
- memset(temp, 0, sizeof(temp));
-
- if (_encoderFilter)
- {
- _encoderFilter->Init();
- _encoderFilter->Filter(temp, sizeof(temp));
- }
- else
- {
- CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
- CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
- inStreamSpec->Init(temp, sizeof(temp));
-
- CCrcOutStream *crcStreamSpec = new CCrcOutStream;
- CMyComPtr<ISequentialOutStream> crcStream = crcStreamSpec;
- crcStreamSpec->Init();
-
- RINOK(_encoder->Code(inStream, crcStream, 0, 0, NULL));
- }
- }
- }
- }
-
- return S_OK;
-}
-
-
-static void My_FilterBench(ICompressFilter *filter, Byte *data, size_t size)
-{
- while (size != 0)
- {
- UInt32 cur = (UInt32)1 << 31;
- if (cur > size)
- cur = (UInt32)size;
- UInt32 processed = filter->Filter(data, cur);
- data += processed;
- // if (processed > size) (in AES filter), we must fill last block with zeros.
- // but it is not important for benchmark. So we just copy that data without filtering.
- if (processed > size || processed == 0)
- break;
- size -= processed;
- }
-}
-
-
-HRESULT CEncoderInfo::Encode()
-{
- RINOK(Generate());
-
- #ifndef _7ZIP_ST
- if (Common)
- {
- Results[0] = S_OK;
- WRes wres = ReadyEvent.Set();
- if (wres == 0)
- wres = Common->StartEvent.Lock();
- if (wres != 0)
- return HRESULT_FROM_WIN32(wres);
- if (Common->ExitMode)
- return S_OK;
- }
- else
- #endif
- {
- CBenchProgressInfo *bpi = progressInfoSpec[0];
- bpi->SetStartTime();
- }
-
-
- CBenchInfo &bi = progressInfoSpec[0]->BenchInfo;
- bi.UnpackSize = 0;
- bi.PackSize = 0;
- CMyComPtr<ICryptoProperties> cp;
- CMyComPtr<IUnknown> coder;
- if (_encoderFilter)
- coder = _encoderFilter;
- else
- coder = _encoder;
- coder.QueryInterface(IID_ICryptoProperties, &cp);
- CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
- CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
- UInt64 prev = 0;
-
- UInt32 crcPrev = 0;
-
- if (cp)
- {
- RINOK(cp->SetKey(_key, sizeof(_key)));
- RINOK(cp->SetInitVector(_iv, sizeof(_iv)));
- }
-
- for (UInt64 i = 0; i < NumIterations; i++)
- {
- if (printCallback && bi.UnpackSize - prev > (1 << 20))
- {
- RINOK(printCallback->CheckBreak());
- prev = bi.UnpackSize;
- }
-
- bool isLast = (i == NumIterations - 1);
- bool calcCrc = ((isLast || (i & 0x7F) == 0 || CheckCrc_Enc) && NumIterations != 1);
- outStreamSpec->Init(isLast, calcCrc);
-
- if (_encoderFilter)
- {
- memcpy((Byte *)rgCopy, uncompressedDataPtr, kBufferSize);
- _encoderFilter->Init();
- My_FilterBench(_encoderFilter, (Byte *)rgCopy, kBufferSize);
- RINOK(WriteStream(outStream, (const Byte *)rgCopy, kBufferSize));
- }
- else
- {
- inStreamSpec->Init(uncompressedDataPtr, kBufferSize);
- RINOK(_encoder->Code(inStream, outStream, NULL, NULL, progressInfo[0]));
- }
-
- // outStreamSpec->Print();
-
- UInt32 crcNew = CRC_GET_DIGEST(outStreamSpec->Crc);
- if (i == 0)
- crcPrev = crcNew;
- else if (calcCrc && crcPrev != crcNew)
- return E_FAIL;
-
- compressedSize = outStreamSpec->Pos;
- bi.UnpackSize += kBufferSize;
- bi.PackSize += compressedSize;
- }
-
- _encoder.Release();
- _encoderFilter.Release();
- return S_OK;
-}
-
-
-HRESULT CEncoderInfo::Decode(UInt32 decoderIndex)
-{
- CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
- CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
- CMyComPtr<ICompressCoder> &decoder = _decoders[decoderIndex];
- CMyComPtr<IUnknown> coder;
- if (_decoderFilter)
- {
- if (decoderIndex != 0)
- return E_FAIL;
- coder = _decoderFilter;
- }
- else
- coder = decoder;
-
- CMyComPtr<ICompressSetDecoderProperties2> setDecProps;
- coder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecProps);
- if (!setDecProps && propStreamSpec->Pos != 0)
- return E_FAIL;
-
- CCrcOutStream *crcOutStreamSpec = new CCrcOutStream;
- CMyComPtr<ISequentialOutStream> crcOutStream = crcOutStreamSpec;
-
- CBenchProgressInfo *pi = progressInfoSpec[decoderIndex];
- pi->BenchInfo.UnpackSize = 0;
- pi->BenchInfo.PackSize = 0;
-
- #ifndef _7ZIP_ST
- {
- CMyComPtr<ICompressSetCoderMt> setCoderMt;
- coder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
- if (setCoderMt)
- {
- RINOK(setCoderMt->SetNumberOfThreads(NumDecoderSubThreads));
- }
- }
- #endif
-
- CMyComPtr<ICompressSetCoderProperties> scp;
- coder.QueryInterface(IID_ICompressSetCoderProperties, &scp);
- if (scp)
- {
- UInt64 reduceSize = _uncompressedDataSize;
- RINOK(_method.SetCoderProps(scp, &reduceSize));
- }
-
- CMyComPtr<ICryptoProperties> cp;
- coder.QueryInterface(IID_ICryptoProperties, &cp);
-
- if (setDecProps)
- {
- RINOK(setDecProps->SetDecoderProperties2((const Byte *)*propStreamSpec, (UInt32)propStreamSpec->Pos));
- }
-
- {
- CMyComPtr<ICryptoSetPassword> sp;
- coder.QueryInterface(IID_ICryptoSetPassword, &sp);
- if (sp)
- {
- RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw)));
- }
- }
-
- UInt64 prev = 0;
-
- if (cp)
- {
- RINOK(cp->SetKey(_key, sizeof(_key)));
- RINOK(cp->SetInitVector(_iv, sizeof(_iv)));
- }
-
- for (UInt64 i = 0; i < NumIterations; i++)
- {
- if (printCallback && pi->BenchInfo.UnpackSize - prev > (1 << 20))
- {
- RINOK(printCallback->CheckBreak());
- prev = pi->BenchInfo.UnpackSize;
- }
-
- inStreamSpec->Init((const Byte *)*outStreamSpec, compressedSize);
- crcOutStreamSpec->Init();
-
- UInt64 outSize = kBufferSize;
- crcOutStreamSpec->CalcCrc = ((i & 0x7F) == 0 || CheckCrc_Dec);
-
- if (_decoderFilter)
- {
- if (compressedSize > rgCopy.Size())
- return E_FAIL;
- memcpy((Byte *)rgCopy, (const Byte *)*outStreamSpec, compressedSize);
- _decoderFilter->Init();
- My_FilterBench(_decoderFilter, (Byte *)rgCopy, compressedSize);
- RINOK(WriteStream(crcOutStream, (const Byte *)rgCopy, compressedSize));
- }
- else
- {
- RINOK(decoder->Code(inStream, crcOutStream, 0, &outSize, progressInfo[decoderIndex]));
- }
-
- if (crcOutStreamSpec->CalcCrc && CRC_GET_DIGEST(crcOutStreamSpec->Crc) != crc)
- return S_FALSE;
- pi->BenchInfo.UnpackSize += kBufferSize;
- pi->BenchInfo.PackSize += compressedSize;
- }
-
- decoder.Release();
- _decoderFilter.Release();
- return S_OK;
-}
-
-
-static const UInt32 kNumThreadsMax = (1 << 12);
-
-struct CBenchEncoders
-{
- CEncoderInfo *encoders;
- CBenchEncoders(UInt32 num): encoders(NULL) { encoders = new CEncoderInfo[num]; }
- ~CBenchEncoders() { delete []encoders; }
-};
-
-
-static UInt64 GetNumIterations(UInt64 numCommands, UInt64 complexInCommands)
-{
- if (numCommands < (1 << 4))
- numCommands = (1 << 4);
- UInt64 res = complexInCommands / numCommands;
- return (res == 0 ? 1 : res);
-}
-
-
-
-#ifndef _7ZIP_ST
-
-// ---------- CBenchThreadsFlusher ----------
-
-struct CBenchThreadsFlusher
-{
- CBenchEncoders *EncodersSpec;
- CBenchSyncCommon Common;
- unsigned NumThreads;
- bool NeedClose;
-
- CBenchThreadsFlusher(): NumThreads(0), NeedClose(false) {}
-
- ~CBenchThreadsFlusher()
- {
- StartAndWait(true);
- }
-
- WRes StartAndWait(bool exitMode = false);
-};
-
-
-WRes CBenchThreadsFlusher::StartAndWait(bool exitMode)
-{
- if (!NeedClose)
- return 0;
-
- Common.ExitMode = exitMode;
- WRes res = Common.StartEvent.Set();
-
- for (unsigned i = 0; i < NumThreads; i++)
- {
- NWindows::CThread &t = EncodersSpec->encoders[i].thread[0];
- if (t.IsCreated())
- {
- WRes res2 = t.Wait();
- if (res2 == 0)
- res2 = t.Close();
- if (res == S_OK)
- res = res2;
- }
- }
- NeedClose = false;
- return res;
-}
-
-#endif
-
-
-
-static HRESULT MethodBench(
- DECL_EXTERNAL_CODECS_LOC_VARS
- UInt64 complexInCommands,
- bool
- #ifndef _7ZIP_ST
- oldLzmaBenchMode
- #endif
- ,
- UInt32
- #ifndef _7ZIP_ST
- numThreads
- #endif
- ,
- const COneMethodInfo &method2,
- size_t uncompressedDataSize,
- const Byte *fileData,
- unsigned generateDictBits,
-
- IBenchPrintCallback *printCallback,
- IBenchCallback *callback,
- CBenchProps *benchProps)
-{
- COneMethodInfo method = method2;
- UInt64 methodId;
- UInt32 numStreams;
- int codecIndex = FindMethod_Index(
- EXTERNAL_CODECS_LOC_VARS
- method.MethodName, true,
- methodId, numStreams);
- if (codecIndex < 0)
- return E_NOTIMPL;
- if (numStreams != 1)
- return E_INVALIDARG;
-
- UInt32 numEncoderThreads = 1;
- UInt32 numSubDecoderThreads = 1;
-
- #ifndef _7ZIP_ST
- numEncoderThreads = numThreads;
-
- if (oldLzmaBenchMode && methodId == k_LZMA)
- {
- if (numThreads == 1 && method.Get_NumThreads() < 0)
- method.AddProp_NumThreads(1);
- const UInt32 numLzmaThreads = method.Get_Lzma_NumThreads();
- if (numThreads > 1 && numLzmaThreads > 1)
- {
- numEncoderThreads = numThreads / 2;
- numSubDecoderThreads = 2;
- }
- }
-
- bool mtEncMode = (numEncoderThreads > 1);
- #endif
-
- CBenchEncoders encodersSpec(numEncoderThreads);
- CEncoderInfo *encoders = encodersSpec.encoders;
-
- UInt32 i;
-
- for (i = 0; i < numEncoderThreads; i++)
- {
- CEncoderInfo &encoder = encoders[i];
- encoder.callback = (i == 0) ? callback : 0;
- encoder.printCallback = printCallback;
-
- {
- CCreatedCoder cod;
- RINOK(CreateCoder_Index(EXTERNAL_CODECS_LOC_VARS codecIndex, true, encoder._encoderFilter, cod));
- encoder._encoder = cod.Coder;
- if (!encoder._encoder && !encoder._encoderFilter)
- return E_NOTIMPL;
- }
-
- encoder.CheckCrc_Enc = (benchProps->EncComplex) > 30 ;
- encoder.CheckCrc_Dec = (benchProps->DecComplexCompr + benchProps->DecComplexUnc) > 30 ;
-
- memset(encoder._iv, 0, sizeof(encoder._iv));
- memset(encoder._key, 0, sizeof(encoder._key));
- memset(encoder._psw, 0, sizeof(encoder._psw));
-
- for (UInt32 j = 0; j < numSubDecoderThreads; j++)
- {
- CCreatedCoder cod;
- CMyComPtr<ICompressCoder> &decoder = encoder._decoders[j];
- RINOK(CreateCoder_Id(EXTERNAL_CODECS_LOC_VARS methodId, false, encoder._decoderFilter, cod));
- decoder = cod.Coder;
- if (!encoder._decoderFilter && !decoder)
- return E_NOTIMPL;
- }
- }
-
- UInt32 crc = 0;
- if (fileData)
- crc = CrcCalc(fileData, uncompressedDataSize);
-
- for (i = 0; i < numEncoderThreads; i++)
- {
- CEncoderInfo &encoder = encoders[i];
- encoder._method = method;
- encoder.generateDictBits = generateDictBits;
- encoder._uncompressedDataSize = uncompressedDataSize;
- encoder.kBufferSize = uncompressedDataSize;
- encoder.fileData = fileData;
- encoder.crc = crc;
- }
-
- CBenchProgressStatus status;
- status.Res = S_OK;
- status.EncodeMode = true;
-
- #ifndef _7ZIP_ST
- CBenchThreadsFlusher encoderFlusher;
- if (mtEncMode)
- {
- WRes wres = encoderFlusher.Common.StartEvent.Create();
- if (wres != 0)
- return HRESULT_FROM_WIN32(wres);
- encoderFlusher.NumThreads = numEncoderThreads;
- encoderFlusher.EncodersSpec = &encodersSpec;
- encoderFlusher.NeedClose = true;
- }
- #endif
-
- for (i = 0; i < numEncoderThreads; i++)
- {
- CEncoderInfo &encoder = encoders[i];
- encoder.NumIterations = GetNumIterations(benchProps->GeComprCommands(uncompressedDataSize), complexInCommands);
- encoder.Salt = g_CrcTable[i & 0xFF];
- encoder.Salt ^= (g_CrcTable[(i >> 8) & 0xFF] << 3);
- // (g_CrcTable[0] == 0), and (encoder.Salt == 0) for first thread
- // printf(" %8x", encoder.Salt);
-
- for (int j = 0; j < 2; j++)
- {
- CBenchProgressInfo *spec = new CBenchProgressInfo;
- encoder.progressInfoSpec[j] = spec;
- encoder.progressInfo[j] = spec;
- spec->Status = &status;
- }
-
- if (i == 0)
- {
- CBenchProgressInfo *bpi = encoder.progressInfoSpec[0];
- bpi->Callback = callback;
- bpi->BenchInfo.NumIterations = numEncoderThreads;
- }
-
- #ifndef _7ZIP_ST
- if (mtEncMode)
- {
- #ifdef USE_ALLOCA
- encoder.AllocaSize = (i * 16 * 21) & 0x7FF;
- #endif
-
- encoder.Common = &encoderFlusher.Common;
- RINOK(encoder.CreateEncoderThread())
- }
- #endif
- }
-
- if (printCallback)
- {
- RINOK(printCallback->CheckBreak());
- }
-
- #ifndef _7ZIP_ST
- if (mtEncMode)
- {
- for (i = 0; i < numEncoderThreads; i++)
- {
- CEncoderInfo &encoder = encoders[i];
- WRes wres = encoder.ReadyEvent.Lock();
- if (wres != 0)
- return HRESULT_FROM_WIN32(wres);
- RINOK(encoder.Results[0]);
- }
-
- CBenchProgressInfo *bpi = encoders[0].progressInfoSpec[0];
- bpi->SetStartTime();
-
- WRes wres = encoderFlusher.StartAndWait();
- if (status.Res == 0 && wres != 0)
- return HRESULT_FROM_WIN32(wres);
- }
- else
- #endif
- {
- RINOK(encoders[0].Encode());
- }
-
- RINOK(status.Res);
-
- CBenchInfo info;
-
- encoders[0].progressInfoSpec[0]->SetFinishTime(info);
- info.UnpackSize = 0;
- info.PackSize = 0;
- info.NumIterations = encoders[0].NumIterations;
-
- for (i = 0; i < numEncoderThreads; i++)
- {
- CEncoderInfo &encoder = encoders[i];
- info.UnpackSize += encoder.kBufferSize;
- info.PackSize += encoder.compressedSize;
- // printf("\n%7d\n", encoder.compressedSize);
- }
-
- RINOK(callback->SetEncodeResult(info, true));
-
-
-
-
- // ---------- Decode ----------
-
- status.Res = S_OK;
- status.EncodeMode = false;
-
- UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads;
-
- for (i = 0; i < numEncoderThreads; i++)
- {
- CEncoderInfo &encoder = encoders[i];
-
- if (i == 0)
- {
- encoder.NumIterations = GetNumIterations(benchProps->GeDecomprCommands(encoder.compressedSize, encoder.kBufferSize), complexInCommands);
- CBenchProgressInfo *bpi = encoder.progressInfoSpec[0];
- bpi->Callback = callback;
- bpi->BenchInfo.NumIterations = numDecoderThreads;
- bpi->SetStartTime();
- }
- else
- encoder.NumIterations = encoders[0].NumIterations;
-
- #ifndef _7ZIP_ST
- {
- int numSubThreads = method.Get_NumThreads();
- encoder.NumDecoderSubThreads = (numSubThreads <= 0) ? 1 : numSubThreads;
- }
- if (numDecoderThreads > 1)
- {
- for (UInt32 j = 0; j < numSubDecoderThreads; j++)
- {
- HRESULT res = encoder.CreateDecoderThread(j, (i == 0 && j == 0)
- #ifdef USE_ALLOCA
- , ((i * numSubDecoderThreads + j) * 16 * 21) & 0x7FF
- #endif
- );
- RINOK(res);
- }
- }
- else
- #endif
- {
- RINOK(encoder.Decode(0));
- }
- }
-
- #ifndef _7ZIP_ST
- HRESULT res = S_OK;
- if (numDecoderThreads > 1)
- for (i = 0; i < numEncoderThreads; i++)
- for (UInt32 j = 0; j < numSubDecoderThreads; j++)
- {
- CEncoderInfo &encoder = encoders[i];
- encoder.thread[j].Wait();
- if (encoder.Results[j] != S_OK)
- res = encoder.Results[j];
- }
- RINOK(res);
- #endif
-
- RINOK(status.Res);
- encoders[0].progressInfoSpec[0]->SetFinishTime(info);
-
- #ifndef _7ZIP_ST
- #ifdef UNDER_CE
- if (numDecoderThreads > 1)
- for (i = 0; i < numEncoderThreads; i++)
- for (UInt32 j = 0; j < numSubDecoderThreads; j++)
- {
- FILETIME creationTime, exitTime, kernelTime, userTime;
- if (::GetThreadTimes(encoders[i].thread[j], &creationTime, &exitTime, &kernelTime, &userTime) != 0)
- info.UserTime += GetTime64(userTime) + GetTime64(kernelTime);
- }
- #endif
- #endif
-
- info.UnpackSize = 0;
- info.PackSize = 0;
- info.NumIterations = numSubDecoderThreads * encoders[0].NumIterations;
-
- for (i = 0; i < numEncoderThreads; i++)
- {
- CEncoderInfo &encoder = encoders[i];
- info.UnpackSize += encoder.kBufferSize;
- info.PackSize += encoder.compressedSize;
- }
-
- RINOK(callback->SetDecodeResult(info, false));
- RINOK(callback->SetDecodeResult(info, true));
-
- return S_OK;
-}
-
-
-static inline UInt64 GetLZMAUsage(bool multiThread, UInt32 dictionary)
-{
- UInt32 hs = dictionary - 1;
- hs |= (hs >> 1);
- hs |= (hs >> 2);
- hs |= (hs >> 4);
- hs |= (hs >> 8);
- hs >>= 1;
- hs |= 0xFFFF;
- if (hs > (1 << 24))
- hs >>= 1;
- hs++;
- return ((hs + (1 << 16)) + (UInt64)dictionary * 2) * 4 + (UInt64)dictionary * 3 / 2 +
- (1 << 20) + (multiThread ? (6 << 20) : 0);
-}
-
-UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary, bool totalBench)
-{
- const UInt32 kBufferSize = dictionary;
- const UInt32 kCompressedBufferSize = kBufferSize; // / 2;
- bool lzmaMt = (totalBench || numThreads > 1);
- UInt32 numBigThreads = numThreads;
- if (!totalBench && lzmaMt)
- numBigThreads /= 2;
- return ((UInt64)kBufferSize + kCompressedBufferSize +
- GetLZMAUsage(lzmaMt, dictionary) + (2 << 20)) * numBigThreads;
-}
-
-static HRESULT CrcBig(const void *data, UInt32 size, UInt64 numIterations,
- const UInt32 *checkSum, IHasher *hf,
- IBenchPrintCallback *callback)
-{
- Byte hash[64];
- UInt64 i;
- for (i = 0; i < sizeof(hash); i++)
- hash[i] = 0;
- for (i = 0; i < numIterations; i++)
- {
- if (callback && (i & 0xFF) == 0)
- {
- RINOK(callback->CheckBreak());
- }
- hf->Init();
- hf->Update(data, size);
- hf->Final(hash);
- UInt32 hashSize = hf->GetDigestSize();
- if (hashSize > sizeof(hash))
- return S_FALSE;
- UInt32 sum = 0;
- for (UInt32 j = 0; j < hashSize; j += 4)
- sum ^= GetUi32(hash + j);
- if (checkSum && sum != *checkSum)
- {
- return S_FALSE;
- }
- }
- return S_OK;
-}
-
-UInt32 g_BenchCpuFreqTemp = 1;
-
-#define YY1 sum += val; sum ^= val;
-#define YY3 YY1 YY1 YY1 YY1
-#define YY5 YY3 YY3 YY3 YY3
-#define YY7 YY5 YY5 YY5 YY5
-static const UInt32 kNumFreqCommands = 128;
-
-EXTERN_C_BEGIN
-
-static UInt32 CountCpuFreq(UInt32 sum, UInt32 num, UInt32 val)
-{
- for (UInt32 i = 0; i < num; i++)
- {
- YY7
- }
- return sum;
-}
-
-EXTERN_C_END
-
-
-#ifndef _7ZIP_ST
-
-struct CFreqInfo
-{
- NWindows::CThread Thread;
- IBenchPrintCallback *Callback;
- HRESULT CallbackRes;
- UInt32 ValRes;
- UInt32 Size;
- UInt64 NumIterations;
-
- void Wait()
- {
- Thread.Wait();
- Thread.Close();
- }
-};
-
-static THREAD_FUNC_DECL FreqThreadFunction(void *param)
-{
- CFreqInfo *p = (CFreqInfo *)param;
-
- UInt32 sum = g_BenchCpuFreqTemp;
- for (UInt64 k = p->NumIterations; k > 0; k--)
- {
- p->CallbackRes = p->Callback->CheckBreak();
- if (p->CallbackRes != S_OK)
- return 0;
- sum = CountCpuFreq(sum, p->Size, g_BenchCpuFreqTemp);
- }
- p->ValRes = sum;
- return 0;
-}
-
-struct CFreqThreads
-{
- CFreqInfo *Items;
- UInt32 NumThreads;
-
- CFreqThreads(): Items(NULL), NumThreads(0) {}
- void WaitAll()
- {
- for (UInt32 i = 0; i < NumThreads; i++)
- Items[i].Wait();
- NumThreads = 0;
- }
- ~CFreqThreads()
- {
- WaitAll();
- delete []Items;
- }
-};
-
-struct CCrcInfo
-{
- NWindows::CThread Thread;
- IBenchPrintCallback *Callback;
- HRESULT CallbackRes;
-
- const Byte *Data;
- UInt32 Size;
- UInt64 NumIterations;
- bool CheckSumDefined;
- UInt32 CheckSum;
- CMyComPtr<IHasher> Hasher;
- HRESULT Res;
-
- #ifdef USE_ALLOCA
- size_t AllocaSize;
- #endif
-
- void Wait()
- {
- Thread.Wait();
- Thread.Close();
- }
-};
-
-static THREAD_FUNC_DECL CrcThreadFunction(void *param)
-{
- CCrcInfo *p = (CCrcInfo *)param;
-
- #ifdef USE_ALLOCA
- alloca(p->AllocaSize);
- #endif
-
- p->Res = CrcBig(p->Data, p->Size, p->NumIterations,
- p->CheckSumDefined ? &p->CheckSum : NULL, p->Hasher,
- p->Callback);
- return 0;
-}
-
-struct CCrcThreads
-{
- CCrcInfo *Items;
- UInt32 NumThreads;
-
- CCrcThreads(): Items(NULL), NumThreads(0) {}
- void WaitAll()
- {
- for (UInt32 i = 0; i < NumThreads; i++)
- Items[i].Wait();
- NumThreads = 0;
- }
- ~CCrcThreads()
- {
- WaitAll();
- delete []Items;
- }
-};
-
-#endif
-
-static UInt32 CrcCalc1(const Byte *buf, size_t size)
-{
- UInt32 crc = CRC_INIT_VAL;;
- for (size_t i = 0; i < size; i++)
- crc = CRC_UPDATE_BYTE(crc, buf[i]);
- return CRC_GET_DIGEST(crc);
-}
-
-static void RandGen(Byte *buf, size_t size, CBaseRandomGenerator &RG)
-{
- for (size_t i = 0; i < size; i++)
- buf[i] = (Byte)RG.GetRnd();
-}
-
-static UInt32 RandGenCrc(Byte *buf, size_t size, CBaseRandomGenerator &RG)
-{
- RandGen(buf, size, RG);
- return CrcCalc1(buf, size);
-}
-
-bool CrcInternalTest()
-{
- CAlignedBuffer buffer;
- const size_t kBufferSize0 = (1 << 8);
- const size_t kBufferSize1 = (1 << 10);
- const unsigned kCheckSize = (1 << 5);
- buffer.Alloc(kBufferSize0 + kBufferSize1);
- if (!buffer.IsAllocated())
- return false;
- Byte *buf = (Byte *)buffer;
- size_t i;
- for (i = 0; i < kBufferSize0; i++)
- buf[i] = (Byte)i;
- UInt32 crc1 = CrcCalc1(buf, kBufferSize0);
- if (crc1 != 0x29058C73)
- return false;
- CBaseRandomGenerator RG;
- RandGen(buf + kBufferSize0, kBufferSize1, RG);
- for (i = 0; i < kBufferSize0 + kBufferSize1 - kCheckSize; i++)
- for (unsigned j = 0; j < kCheckSize; j++)
- if (CrcCalc1(buf + i, j) != CrcCalc(buf + i, j))
- return false;
- return true;
-}
-
-struct CBenchMethod
-{
- unsigned Weight;
- unsigned DictBits;
- UInt32 EncComplex;
- UInt32 DecComplexCompr;
- UInt32 DecComplexUnc;
- const char *Name;
-};
-
-static const CBenchMethod g_Bench[] =
-{
- { 40, 17, 357, 145, 20, "LZMA:x1" },
- { 80, 24, 1220, 145, 20, "LZMA:x5:mt1" },
- { 80, 24, 1220, 145, 20, "LZMA:x5:mt2" },
-
- { 10, 16, 124, 40, 14, "Deflate:x1" },
- { 20, 16, 376, 40, 14, "Deflate:x5" },
- { 10, 16, 1082, 40, 14, "Deflate:x7" },
- { 10, 17, 422, 40, 14, "Deflate64:x5" },
-
- { 10, 15, 590, 69, 69, "BZip2:x1" },
- { 20, 19, 815, 122, 122, "BZip2:x5" },
- { 10, 19, 815, 122, 122, "BZip2:x5:mt2" },
- { 10, 19, 2530, 122, 122, "BZip2:x7" },
-
- { 10, 18, 1010, 0, 1150, "PPMD:x1" },
- { 10, 22, 1655, 0, 1830, "PPMD:x5" },
-
- { 2, 0, 6, 0, 6, "Delta:4" },
- { 2, 0, 4, 0, 4, "BCJ" },
-
- { 10, 0, 24, 0, 24, "AES256CBC:1" },
- { 2, 0, 8, 0, 2, "AES256CBC:2" }
-};
-
-struct CBenchHash
-{
- unsigned Weight;
- UInt32 Complex;
- UInt32 CheckSum;
- const char *Name;
-};
-
-static const CBenchHash g_Hash[] =
-{
- { 1, 1820, 0x8F8FEDAB, "CRC32:1" },
- { 10, 558, 0x8F8FEDAB, "CRC32:4" },
- { 10, 339, 0x8F8FEDAB, "CRC32:8" },
- { 10, 512, 0xDF1C17CC, "CRC64" },
- { 10, 5100, 0x2D79FF2E, "SHA256" },
- { 10, 2340, 0x4C25132B, "SHA1" },
- { 2, 5500, 0xE084E913, "BLAKE2sp" }
-};
-
-struct CTotalBenchRes
-{
- // UInt64 NumIterations1; // for Usage
- UInt64 NumIterations2; // for Rating / RPU
-
- UInt64 Rating;
- UInt64 Usage;
- UInt64 RPU;
-
- void Init() { /* NumIterations1 = 0; */ NumIterations2 = 0; Rating = 0; Usage = 0; RPU = 0; }
-
- void SetSum(const CTotalBenchRes &r1, const CTotalBenchRes &r2)
- {
- Rating = (r1.Rating + r2.Rating);
- Usage = (r1.Usage + r2.Usage);
- RPU = (r1.RPU + r2.RPU);
- // NumIterations1 = (r1.NumIterations1 + r2.NumIterations1);
- NumIterations2 = (r1.NumIterations2 + r2.NumIterations2);
- }
-};
-
-static void PrintNumber(IBenchPrintCallback &f, UInt64 value, unsigned size)
-{
- char s[128];
- unsigned startPos = (unsigned)sizeof(s) - 32;
- memset(s, ' ', startPos);
- ConvertUInt64ToString(value, s + startPos);
- // if (withSpace)
- {
- startPos--;
- size++;
- }
- unsigned len = (unsigned)strlen(s + startPos);
- if (size > len)
- {
- startPos -= (size - len);
- if (startPos < 0)
- startPos = 0;
- }
- f.Print(s + startPos);
-}
-
-static const unsigned kFieldSize_Name = 12;
-static const unsigned kFieldSize_SmallName = 4;
-static const unsigned kFieldSize_Speed = 9;
-static const unsigned kFieldSize_Usage = 5;
-static const unsigned kFieldSize_RU = 6;
-static const unsigned kFieldSize_Rating = 6;
-static const unsigned kFieldSize_EU = 5;
-static const unsigned kFieldSize_Effec = 5;
-
-static const unsigned kFieldSize_TotalSize = 4 + kFieldSize_Speed + kFieldSize_Usage + kFieldSize_RU + kFieldSize_Rating;
-static const unsigned kFieldSize_EUAndEffec = 2 + kFieldSize_EU + kFieldSize_Effec;
-
-
-static void PrintRating(IBenchPrintCallback &f, UInt64 rating, unsigned size)
-{
- PrintNumber(f, (rating + 500000) / 1000000, size);
-}
-
-
-static void PrintPercents(IBenchPrintCallback &f, UInt64 val, UInt64 divider, unsigned size)
-{
- PrintNumber(f, (val * 100 + divider / 2) / divider, size);
-}
-
-static void PrintChars(IBenchPrintCallback &f, char c, unsigned size)
-{
- char s[256];
- memset(s, (Byte)c, size);
- s[size] = 0;
- f.Print(s);
-}
-
-static void PrintSpaces(IBenchPrintCallback &f, unsigned size)
-{
- PrintChars(f, ' ', size);
-}
-
-static void PrintResults(IBenchPrintCallback &f, UInt64 usage, UInt64 rpu, UInt64 rating, bool showFreq, UInt64 cpuFreq)
-{
- PrintNumber(f, (usage + 5000) / 10000, kFieldSize_Usage);
- PrintRating(f, rpu, kFieldSize_RU);
- PrintRating(f, rating, kFieldSize_Rating);
- if (showFreq)
- {
- if (cpuFreq == 0)
- PrintSpaces(f, kFieldSize_EUAndEffec);
- else
- {
- UInt64 ddd = cpuFreq * usage / 100;
- if (ddd == 0)
- ddd = 1;
- PrintPercents(f, (rating * 10000), ddd, kFieldSize_EU);
- PrintPercents(f, rating, cpuFreq, kFieldSize_Effec);
- }
- }
-}
-
-static void PrintResults(IBenchPrintCallback *f,
- const CBenchInfo &info,
- unsigned weight,
- UInt64 rating,
- bool showFreq, UInt64 cpuFreq,
- CTotalBenchRes *res)
-{
- UInt64 speed = info.GetSpeed(info.UnpackSize * info.NumIterations);
- if (f)
- {
- if (speed != 0)
- PrintNumber(*f, speed / 1024, kFieldSize_Speed);
- else
- PrintSpaces(*f, 1 + kFieldSize_Speed);
- }
- UInt64 usage = info.GetUsage();
- UInt64 rpu = info.GetRatingPerUsage(rating);
- if (f)
- {
- PrintResults(*f, usage, rpu, rating, showFreq, cpuFreq);
- }
-
- if (res)
- {
- // res->NumIterations1++;
- res->NumIterations2 += weight;
- res->RPU += (rpu * weight);
- res->Rating += (rating * weight);
- res->Usage += (usage * weight);
- }
-}
-
-static void PrintTotals(IBenchPrintCallback &f, bool showFreq, UInt64 cpuFreq, const CTotalBenchRes &res)
-{
- PrintSpaces(f, 1 + kFieldSize_Speed);
- // UInt64 numIterations1 = res.NumIterations1; if (numIterations1 == 0) numIterations1 = 1;
- UInt64 numIterations2 = res.NumIterations2; if (numIterations2 == 0) numIterations2 = 1;
- PrintResults(f, res.Usage / numIterations2, res.RPU / numIterations2, res.Rating / numIterations2, showFreq, cpuFreq);
-}
-
-
-static void PrintHex(AString &s, UInt64 v)
-{
- char temp[32];
- ConvertUInt64ToHex(v, temp);
- s += temp;
-}
-
-AString GetProcessThreadsInfo(const NSystem::CProcessAffinity &ti)
-{
- AString s;
- // s.Add_UInt32(ti.numProcessThreads);
- if (ti.processAffinityMask != ti.systemAffinityMask)
- {
- // if (ti.numProcessThreads != ti.numSysThreads)
- {
- s += " / ";
- s.Add_UInt32(ti.GetNumSystemThreads());
- }
- s += " : ";
- PrintHex(s, ti.processAffinityMask);
- s += " / ";
- PrintHex(s, ti.systemAffinityMask);
- }
- return s;
-}
-
-
-static void PrintSize(AString &s, UInt64 v)
-{
- char c = 0;
- if ((v & 0x3FF) == 0) { v >>= 10; c = 'K';
- if ((v & 0x3FF) == 0) { v >>= 10; c = 'M';
- if ((v & 0x3FF) == 0) { v >>= 10; c = 'G';
- if ((v & 0x3FF) == 0) { v >>= 10; c = 'T';
- }}}}
- else
- {
- PrintHex(s, v);
- return;
- }
- char temp[32];
- ConvertUInt64ToString(v, temp);
- s += temp;
- if (c)
- s += c;
-}
-
-
-#ifdef _7ZIP_LARGE_PAGES
-
-extern bool g_LargePagesMode;
-
-extern "C"
-{
- extern SIZE_T g_LargePageSize;
-}
-
-void Add_LargePages_String(AString &s)
-{
- if (g_LargePagesMode || g_LargePageSize != 0)
- {
- s += " (LP-";
- PrintSize(s, g_LargePageSize);
- #ifdef MY_CPU_X86_OR_AMD64
- if (CPU_IsSupported_PageGB())
- s += "-1G";
- #endif
- if (!g_LargePagesMode)
- s += "-NA";
- s += ")";
- }
-}
-
-#endif
-
-
-
-static void PrintRequirements(IBenchPrintCallback &f, const char *sizeString,
- bool size_Defined, UInt64 size, const char *threadsString, UInt32 numThreads)
-{
- f.Print("RAM ");
- f.Print(sizeString);
- if (size_Defined)
- PrintNumber(f, (size >> 20), 6);
- else
- f.Print(" ?");
- f.Print(" MB");
-
- #ifdef _7ZIP_LARGE_PAGES
- {
- AString s;
- Add_LargePages_String(s);
- f.Print(s);
- }
- #endif
-
- f.Print(", # ");
- f.Print(threadsString);
- PrintNumber(f, numThreads, 3);
-}
-
-
-
-struct CBenchCallbackToPrint: public IBenchCallback
-{
- CBenchProps BenchProps;
- CTotalBenchRes EncodeRes;
- CTotalBenchRes DecodeRes;
- IBenchPrintCallback *_file;
- UInt32 DictSize;
-
- bool Use2Columns;
- unsigned NameFieldSize;
-
- bool ShowFreq;
- UInt64 CpuFreq;
-
- unsigned EncodeWeight;
- unsigned DecodeWeight;
-
- CBenchCallbackToPrint():
- Use2Columns(false),
- NameFieldSize(0),
- ShowFreq(false),
- CpuFreq(0),
- EncodeWeight(1),
- DecodeWeight(1)
- {}
-
- void Init() { EncodeRes.Init(); DecodeRes.Init(); }
- void Print(const char *s);
- void NewLine();
-
- HRESULT SetFreq(bool showFreq, UInt64 cpuFreq);
- HRESULT SetEncodeResult(const CBenchInfo &info, bool final);
- HRESULT SetDecodeResult(const CBenchInfo &info, bool final);
-};
-
-HRESULT CBenchCallbackToPrint::SetFreq(bool showFreq, UInt64 cpuFreq)
-{
- ShowFreq = showFreq;
- CpuFreq = cpuFreq;
- return S_OK;
-}
-
-HRESULT CBenchCallbackToPrint::SetEncodeResult(const CBenchInfo &info, bool final)
-{
- RINOK(_file->CheckBreak());
- if (final)
- {
- UInt64 rating = BenchProps.GetCompressRating(DictSize, info.GlobalTime, info.GlobalFreq, info.UnpackSize * info.NumIterations);
- PrintResults(_file, info,
- EncodeWeight, rating,
- ShowFreq, CpuFreq, &EncodeRes);
- if (!Use2Columns)
- _file->NewLine();
- }
- return S_OK;
-}
-
-static const char * const kSep = " | ";
-
-HRESULT CBenchCallbackToPrint::SetDecodeResult(const CBenchInfo &info, bool final)
-{
- RINOK(_file->CheckBreak());
- if (final)
- {
- UInt64 rating = BenchProps.GetDecompressRating(info.GlobalTime, info.GlobalFreq, info.UnpackSize, info.PackSize, info.NumIterations);
- if (Use2Columns)
- _file->Print(kSep);
- else
- PrintSpaces(*_file, NameFieldSize);
- CBenchInfo info2 = info;
- info2.UnpackSize *= info2.NumIterations;
- info2.PackSize *= info2.NumIterations;
- info2.NumIterations = 1;
- PrintResults(_file, info2,
- DecodeWeight, rating,
- ShowFreq, CpuFreq, &DecodeRes);
- }
- return S_OK;
-}
-
-void CBenchCallbackToPrint::Print(const char *s)
-{
- _file->Print(s);
-}
-
-void CBenchCallbackToPrint::NewLine()
-{
- _file->NewLine();
-}
-
-void PrintLeft(IBenchPrintCallback &f, const char *s, unsigned size)
-{
- f.Print(s);
- int numSpaces = size - MyStringLen(s);
- if (numSpaces > 0)
- PrintSpaces(f, numSpaces);
-}
-
-void PrintRight(IBenchPrintCallback &f, const char *s, unsigned size)
-{
- int numSpaces = size - MyStringLen(s);
- if (numSpaces > 0)
- PrintSpaces(f, numSpaces);
- f.Print(s);
-}
-
-static HRESULT TotalBench(
- DECL_EXTERNAL_CODECS_LOC_VARS
- UInt64 complexInCommands,
- UInt32 numThreads,
- bool forceUnpackSize,
- size_t unpackSize,
- const Byte *fileData,
- IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback)
-{
- for (unsigned i = 0; i < ARRAY_SIZE(g_Bench); i++)
- {
- const CBenchMethod &bench = g_Bench[i];
- PrintLeft(*callback->_file, bench.Name, kFieldSize_Name);
- callback->BenchProps.DecComplexUnc = bench.DecComplexUnc;
- callback->BenchProps.DecComplexCompr = bench.DecComplexCompr;
- callback->BenchProps.EncComplex = bench.EncComplex;
-
- COneMethodInfo method;
- NCOM::CPropVariant propVariant;
- propVariant = bench.Name;
- RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant));
-
- size_t unpackSize2 = unpackSize;
- if (!forceUnpackSize && bench.DictBits == 0)
- unpackSize2 = kFilterUnpackSize;
-
- callback->EncodeWeight = bench.Weight;
- callback->DecodeWeight = bench.Weight;
-
- HRESULT res = MethodBench(
- EXTERNAL_CODECS_LOC_VARS
- complexInCommands,
- false, numThreads, method,
- unpackSize2, fileData,
- bench.DictBits,
- printCallback, callback, &callback->BenchProps);
-
- if (res == E_NOTIMPL)
- {
- // callback->Print(" ---");
- // we need additional empty line as line for decompression results
- if (!callback->Use2Columns)
- callback->NewLine();
- }
- else
- {
- RINOK(res);
- }
-
- callback->NewLine();
- }
- return S_OK;
-}
-
-
-static HRESULT FreqBench(
- UInt64 complexInCommands,
- UInt32 numThreads,
- IBenchPrintCallback *_file,
- bool showFreq,
- UInt64 specifiedFreq,
- UInt64 &cpuFreq,
- UInt32 &res)
-{
- res = 0;
- cpuFreq = 0;
-
- UInt32 bufferSize = 1 << 20;
- UInt32 complexity = kNumFreqCommands;
- if (numThreads == 0)
- numThreads = 1;
-
- #ifdef _7ZIP_ST
- numThreads = 1;
- #endif
-
- UInt32 bsize = (bufferSize == 0 ? 1 : bufferSize);
- UInt64 numIterations = complexInCommands / complexity / bsize;
- if (numIterations == 0)
- numIterations = 1;
-
- CBenchInfoCalc progressInfoSpec;
-
- #ifndef _7ZIP_ST
- CFreqThreads threads;
- if (numThreads > 1)
- {
- threads.Items = new CFreqInfo[numThreads];
- UInt32 i;
- for (i = 0; i < numThreads; i++)
- {
- CFreqInfo &info = threads.Items[i];
- info.Callback = _file;
- info.CallbackRes = S_OK;
- info.NumIterations = numIterations;
- info.Size = bufferSize;
- }
- progressInfoSpec.SetStartTime();
- for (i = 0; i < numThreads; i++)
- {
- CFreqInfo &info = threads.Items[i];
- RINOK(info.Thread.Create(FreqThreadFunction, &info));
- threads.NumThreads++;
- }
- threads.WaitAll();
- for (i = 0; i < numThreads; i++)
- {
- RINOK(threads.Items[i].CallbackRes);
- }
- }
- else
- #endif
- {
- progressInfoSpec.SetStartTime();
- UInt32 sum = g_BenchCpuFreqTemp;
- for (UInt64 k = numIterations; k > 0; k--)
- {
- RINOK(_file->CheckBreak());
- sum = CountCpuFreq(sum, bufferSize, g_BenchCpuFreqTemp);
- }
- res += sum;
- }
-
- CBenchInfo info;
- progressInfoSpec.SetFinishTime(info);
-
- info.UnpackSize = 0;
- info.PackSize = 0;
- info.NumIterations = 1;
-
- if (_file)
- {
- {
- UInt64 numCommands = (UInt64)numIterations * bufferSize * numThreads * complexity;
- UInt64 rating = info.GetSpeed(numCommands);
- cpuFreq = rating / numThreads;
- PrintResults(_file, info,
- 0, // weight
- rating,
- showFreq, showFreq ? (specifiedFreq != 0 ? specifiedFreq : cpuFreq) : 0, NULL);
- }
- RINOK(_file->CheckBreak());
- }
-
- return S_OK;
-}
-
-
-
-static HRESULT CrcBench(
- DECL_EXTERNAL_CODECS_LOC_VARS
- UInt64 complexInCommands,
- UInt32 numThreads, UInt32 bufferSize,
- UInt64 &speed,
- UInt32 complexity, unsigned benchWeight,
- const UInt32 *checkSum,
- const COneMethodInfo &method,
- IBenchPrintCallback *_file,
- CTotalBenchRes *encodeRes,
- bool showFreq, UInt64 cpuFreq)
-{
- if (numThreads == 0)
- numThreads = 1;
-
- #ifdef _7ZIP_ST
- numThreads = 1;
- #endif
-
- const AString &methodName = method.MethodName;
- // methodName.RemoveChar(L'-');
- CMethodId hashID;
- if (!FindHashMethod(
- EXTERNAL_CODECS_LOC_VARS
- methodName, hashID))
- return E_NOTIMPL;
-
- CAlignedBuffer buffer;
- size_t totalSize = (size_t)bufferSize * numThreads;
- if (totalSize / numThreads != bufferSize)
- return E_OUTOFMEMORY;
- ALLOC_WITH_HRESULT(&buffer, totalSize)
-
- Byte *buf = (Byte *)buffer;
- CBaseRandomGenerator RG;
- UInt32 bsize = (bufferSize == 0 ? 1 : bufferSize);
- UInt64 numIterations = complexInCommands * 256 / complexity / bsize;
- if (numIterations == 0)
- numIterations = 1;
-
- CBenchInfoCalc progressInfoSpec;
-
- #ifndef _7ZIP_ST
- CCrcThreads threads;
- if (numThreads > 1)
- {
- threads.Items = new CCrcInfo[numThreads];
-
- UInt32 i;
- for (i = 0; i < numThreads; i++)
- {
- CCrcInfo &info = threads.Items[i];
- AString name;
- RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, info.Hasher));
- if (!info.Hasher)
- return E_NOTIMPL;
- CMyComPtr<ICompressSetCoderProperties> scp;
- info.Hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp);
- if (scp)
- {
- UInt64 reduceSize = 1;
- RINOK(method.SetCoderProps(scp, &reduceSize));
- }
-
- Byte *data = buf + (size_t)bufferSize * i;
- info.Callback = _file;
- info.Data = data;
- info.NumIterations = numIterations;
- info.Size = bufferSize;
- /* info.Crc = */ RandGenCrc(data, bufferSize, RG);
- info.CheckSumDefined = false;
- if (checkSum)
- {
- info.CheckSum = *checkSum;
- info.CheckSumDefined = (checkSum && (i == 0));
- }
-
- #ifdef USE_ALLOCA
- info.AllocaSize = (i * 16 * 21) & 0x7FF;
- #endif
- }
-
- progressInfoSpec.SetStartTime();
-
- for (i = 0; i < numThreads; i++)
- {
- CCrcInfo &info = threads.Items[i];
- RINOK(info.Thread.Create(CrcThreadFunction, &info));
- threads.NumThreads++;
- }
- threads.WaitAll();
- for (i = 0; i < numThreads; i++)
- {
- RINOK(threads.Items[i].Res);
- }
- }
- else
- #endif
- {
- /* UInt32 crc = */ RandGenCrc(buf, bufferSize, RG);
- progressInfoSpec.SetStartTime();
- CMyComPtr<IHasher> hasher;
- AString name;
- RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, hasher));
- if (!hasher)
- return E_NOTIMPL;
- CMyComPtr<ICompressSetCoderProperties> scp;
- hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp);
- if (scp)
- {
- UInt64 reduceSize = 1;
- RINOK(method.SetCoderProps(scp, &reduceSize));
- }
- RINOK(CrcBig(buf, bufferSize, numIterations, checkSum, hasher, _file));
- }
-
- CBenchInfo info;
- progressInfoSpec.SetFinishTime(info);
-
- UInt64 unpSize = numIterations * bufferSize;
- UInt64 unpSizeThreads = unpSize * numThreads;
- info.UnpackSize = unpSizeThreads;
- info.PackSize = unpSizeThreads;
- info.NumIterations = 1;
-
- if (_file)
- {
- {
- UInt64 numCommands = unpSizeThreads * complexity / 256;
- UInt64 rating = info.GetSpeed(numCommands);
- PrintResults(_file, info,
- benchWeight, rating,
- showFreq, cpuFreq, encodeRes);
- }
- RINOK(_file->CheckBreak());
- }
-
- speed = info.GetSpeed(unpSizeThreads);
-
- return S_OK;
-}
-
-static HRESULT TotalBench_Hash(
- DECL_EXTERNAL_CODECS_LOC_VARS
- UInt64 complexInCommands,
- UInt32 numThreads, UInt32 bufSize,
- IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback,
- CTotalBenchRes *encodeRes,
- bool showFreq, UInt64 cpuFreq)
-{
- for (unsigned i = 0; i < ARRAY_SIZE(g_Hash); i++)
- {
- const CBenchHash &bench = g_Hash[i];
- PrintLeft(*callback->_file, bench.Name, kFieldSize_Name);
- // callback->BenchProps.DecComplexUnc = bench.DecComplexUnc;
- // callback->BenchProps.DecComplexCompr = bench.DecComplexCompr;
- // callback->BenchProps.EncComplex = bench.EncComplex;
-
- COneMethodInfo method;
- NCOM::CPropVariant propVariant;
- propVariant = bench.Name;
- RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant));
-
- UInt64 speed;
- HRESULT res = CrcBench(
- EXTERNAL_CODECS_LOC_VARS
- complexInCommands,
- numThreads, bufSize,
- speed,
- bench.Complex, bench.Weight,
- &bench.CheckSum, method,
- printCallback, encodeRes, showFreq, cpuFreq);
- if (res == E_NOTIMPL)
- {
- // callback->Print(" ---");
- }
- else
- {
- RINOK(res);
- }
- callback->NewLine();
- }
- return S_OK;
-}
-
-struct CTempValues
-{
- UInt64 *Values;
- CTempValues(UInt32 num) { Values = new UInt64[num]; }
- ~CTempValues() { delete []Values; }
-};
-
-static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop)
-{
- const wchar_t *end;
- UInt64 result = ConvertStringToUInt64(s, &end);
- if (*end != 0 || s.IsEmpty())
- prop = s;
- else if (result <= (UInt32)0xFFFFFFFF)
- prop = (UInt32)result;
- else
- prop = result;
-}
-
-static UInt32 GetNumThreadsNext(unsigned i, UInt32 numThreads)
-{
- if (i < 2)
- return i + 1;
- i -= 1;
- UInt32 num = (UInt32)(2 + (i & 1)) << (i >> 1);
- return (num <= numThreads) ? num : numThreads;
-}
-
-static bool AreSameMethodNames(const char *fullName, const char *shortName)
-{
- return StringsAreEqualNoCase_Ascii(fullName, shortName);
-}
-
-
-#ifdef MY_CPU_X86_OR_AMD64
-
-static void PrintCpuChars(AString &s, UInt32 v)
-{
- for (int j = 0; j < 4; j++)
- {
- Byte b = (Byte)(v & 0xFF);
- v >>= 8;
- if (b == 0)
- break;
- s += (char)b;
- }
-}
-
-static void x86cpuid_to_String(const Cx86cpuid &c, AString &s)
-{
- s.Empty();
-
- UInt32 maxFunc2 = 0;
- UInt32 t[3];
-
- MyCPUID(0x80000000, &maxFunc2, &t[0], &t[1], &t[2]);
-
- bool fullNameIsAvail = (maxFunc2 >= 0x80000004);
-
- if (!fullNameIsAvail)
- {
- for (int i = 0; i < 3; i++)
- PrintCpuChars(s, c.vendor[i]);
- }
- else
- {
- for (int i = 0; i < 3; i++)
- {
- UInt32 d[4] = { 0 };
- MyCPUID(0x80000002 + i, &d[0], &d[1], &d[2], &d[3]);
- for (int j = 0; j < 4; j++)
- PrintCpuChars(s, d[j]);
- }
- }
-
- s.Add_Space_if_NotEmpty();
- {
- char temp[32];
- ConvertUInt32ToHex(c.ver, temp);
- s += '(';
- s += temp;
- s += ')';
- }
-}
-
-#endif
-
-
-
-static const char * const k_PROCESSOR_ARCHITECTURE[] =
-{
- "x86" // "INTEL"
- , "MIPS"
- , "ALPHA"
- , "PPC"
- , "SHX"
- , "ARM"
- , "IA64"
- , "ALPHA64"
- , "MSIL"
- , "x64" // "AMD64"
- , "IA32_ON_WIN64"
- , "NEUTRAL"
- , "ARM64"
- , "ARM32_ON_WIN64"
-};
-
-#define MY__PROCESSOR_ARCHITECTURE_INTEL 0
-#define MY__PROCESSOR_ARCHITECTURE_AMD64 9
-
-
-#define MY__PROCESSOR_INTEL_PENTIUM 586
-#define MY__PROCESSOR_AMD_X8664 8664
-
-/*
-static const CUInt32PCharPair k_PROCESSOR[] =
-{
- { 2200, "IA64" },
- { 8664, "x64" }
-};
-
-#define PROCESSOR_INTEL_386 386
-#define PROCESSOR_INTEL_486 486
-#define PROCESSOR_INTEL_PENTIUM 586
-#define PROCESSOR_INTEL_860 860
-#define PROCESSOR_INTEL_IA64 2200
-#define PROCESSOR_AMD_X8664 8664
-#define PROCESSOR_MIPS_R2000 2000
-#define PROCESSOR_MIPS_R3000 3000
-#define PROCESSOR_MIPS_R4000 4000
-#define PROCESSOR_ALPHA_21064 21064
-#define PROCESSOR_PPC_601 601
-#define PROCESSOR_PPC_603 603
-#define PROCESSOR_PPC_604 604
-#define PROCESSOR_PPC_620 620
-#define PROCESSOR_HITACHI_SH3 10003
-#define PROCESSOR_HITACHI_SH3E 10004
-#define PROCESSOR_HITACHI_SH4 10005
-#define PROCESSOR_MOTOROLA_821 821
-#define PROCESSOR_SHx_SH3 103
-#define PROCESSOR_SHx_SH4 104
-#define PROCESSOR_STRONGARM 2577 // 0xA11
-#define PROCESSOR_ARM720 1824 // 0x720
-#define PROCESSOR_ARM820 2080 // 0x820
-#define PROCESSOR_ARM920 2336 // 0x920
-#define PROCESSOR_ARM_7TDMI 70001
-#define PROCESSOR_OPTIL 18767 // 0x494f
-*/
-
-#ifdef _WIN32
-
-static const char * const k_PF[] =
-{
- "FP_ERRATA"
- , "FP_EMU"
- , "CMPXCHG"
- , "MMX"
- , "PPC_MOVEMEM_64BIT"
- , "ALPHA_BYTE"
- , "SSE"
- , "3DNOW"
- , "RDTSC"
- , "PAE"
- , "SSE2"
- , "SSE_DAZ"
- , "NX"
- , "SSE3"
- , "CMPXCHG16B"
- , "CMP8XCHG16"
- , "CHANNELS"
- , "XSAVE"
- , "ARM_VFP_32"
- , "ARM_NEON"
- , "L2AT"
- , "VIRT_FIRMWARE"
- , "RDWRFSGSBASE"
- , "FASTFAIL"
- , "ARM_DIVIDE"
- , "ARM_64BIT_LOADSTORE_ATOMIC"
- , "ARM_EXTERNAL_CACHE"
- , "ARM_FMAC"
- , "RDRAND"
- , "ARM_V8"
- , "ARM_V8_CRYPTO"
- , "ARM_V8_CRC32"
- , "RDTSCP"
-};
-
-#endif
-
-
-
-
-static void PrintPage(AString &s, UInt32 v)
-{
- if ((v & 0x3FF) == 0)
- {
- s.Add_UInt32(v >> 10);
- s += "K";
- }
- else
- s.Add_UInt32(v >> 10);
-}
-
-static AString TypeToString2(const char * const table[], unsigned num, UInt32 value)
-{
- char sz[16];
- const char *p = NULL;
- if (value < num)
- p = table[value];
- if (!p)
- {
- ConvertUInt32ToString(value, sz);
- p = sz;
- }
- return (AString)p;
-}
-
-#ifdef _WIN32
-
-static void SysInfo_To_String(AString &s, const SYSTEM_INFO &si)
-{
- s += TypeToString2(k_PROCESSOR_ARCHITECTURE, ARRAY_SIZE(k_PROCESSOR_ARCHITECTURE), si.wProcessorArchitecture);
-
- if (!( si.wProcessorArchitecture == MY__PROCESSOR_ARCHITECTURE_INTEL && si.dwProcessorType == MY__PROCESSOR_INTEL_PENTIUM
- || si.wProcessorArchitecture == MY__PROCESSOR_ARCHITECTURE_AMD64 && si.dwProcessorType == MY__PROCESSOR_AMD_X8664))
- {
- s += " ";
- // s += TypePairToString(k_PROCESSOR, ARRAY_SIZE(k_PROCESSOR), si.dwProcessorType);
- s.Add_UInt32(si.dwProcessorType);
- }
- s += " ";
- PrintHex(s, si.wProcessorLevel);
- s += ".";
- PrintHex(s, si.wProcessorRevision);
- if ((UInt64)si.dwActiveProcessorMask + 1 != ((UInt64)1 << si.dwNumberOfProcessors))
- if ((UInt64)si.dwActiveProcessorMask + 1 != 0 || si.dwNumberOfProcessors != sizeof(UInt64) * 8)
- {
- s += " act:";
- PrintHex(s, si.dwActiveProcessorMask);
- }
- s += " cpus:";
- s.Add_UInt32(si.dwNumberOfProcessors);
- if (si.dwPageSize != 1 << 12)
- {
- s += " page:";
- PrintPage(s, si.dwPageSize);
- }
- if (si.dwAllocationGranularity != 1 << 16)
- {
- s += " gran:";
- PrintPage(s, si.dwAllocationGranularity);
- }
- s += " ";
-
- DWORD_PTR minAdd = (DWORD_PTR)si.lpMinimumApplicationAddress;
- UInt64 maxSize = (UInt64)(DWORD_PTR)si.lpMaximumApplicationAddress + 1;
- const UInt32 kReserveSize = ((UInt32)1 << 16);
- if (minAdd != kReserveSize)
- {
- PrintSize(s, minAdd);
- s += "-";
- }
- else
- {
- if ((maxSize & (kReserveSize - 1)) == 0)
- maxSize += kReserveSize;
- }
- PrintSize(s, maxSize);
-}
-
-#ifndef _WIN64
-typedef VOID (WINAPI *Func_GetNativeSystemInfo)(LPSYSTEM_INFO lpSystemInfo);
-#endif
-
-#endif
-
-void GetSysInfo(AString &s1, AString &s2)
-{
- s1.Empty();
- s2.Empty();
-
- #ifdef _WIN32
- SYSTEM_INFO si;
- GetSystemInfo(&si);
- {
- SysInfo_To_String(s1, si);
- // s += " : ";
- }
-
- #if !defined(_WIN64) && !defined(UNDER_CE)
- Func_GetNativeSystemInfo fn_GetNativeSystemInfo = (Func_GetNativeSystemInfo)GetProcAddress(
- GetModuleHandleA("kernel32.dll"), "GetNativeSystemInfo");
- if (fn_GetNativeSystemInfo)
- {
- SYSTEM_INFO si2;
- fn_GetNativeSystemInfo(&si2);
- // if (memcmp(&si, &si2, sizeof(si)) != 0)
- {
- // s += " - ";
- SysInfo_To_String(s2, si2);
- }
- }
- #endif
- #endif
-}
-
-
-void GetCpuName(AString &s)
-{
- s.Empty();
-
- #ifdef MY_CPU_X86_OR_AMD64
- {
- Cx86cpuid cpuid;
- if (x86cpuid_CheckAndRead(&cpuid))
- {
- AString s2;
- x86cpuid_to_String(cpuid, s2);
- s += s2;
- }
- else
- {
- #ifdef MY_CPU_AMD64
- s += "x64";
- #else
- s += "x86";
- #endif
- }
- }
- #else
-
- #ifdef MY_CPU_LE
- s += "LE";
- #elif defined(MY_CPU_BE)
- s += "BE";
- #endif
-
- #endif
-
- #ifdef _7ZIP_LARGE_PAGES
- Add_LargePages_String(s);
- #endif
-}
-
-
-void GetCpuFeatures(AString &s)
-{
- s.Empty();
-
- #ifdef _WIN32
- const unsigned kNumFeatures_Extra = 32; // we check also for unknown features
- const unsigned kNumFeatures = ARRAY_SIZE(k_PF) + kNumFeatures_Extra;
- for (unsigned i = 0; i < kNumFeatures; i++)
- {
- if (IsProcessorFeaturePresent(i))
- {
- s.Add_Space_if_NotEmpty();
- s += TypeToString2(k_PF, ARRAY_SIZE(k_PF), i);
- }
- }
- #endif
-}
-
-
-#ifdef _WIN32
-#ifndef UNDER_CE
-
-typedef void (WINAPI * Func_RtlGetVersion) (OSVERSIONINFOEXW *);
-
-static BOOL My_RtlGetVersion(OSVERSIONINFOEXW *vi)
-{
- HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll");
- if (!ntdll)
- return FALSE;
- Func_RtlGetVersion func = (Func_RtlGetVersion)GetProcAddress(ntdll, "RtlGetVersion");
- if (!func)
- return FALSE;
- func(vi);
- return TRUE;
-}
-
-#endif
-#endif
-
-
-HRESULT Bench(
- DECL_EXTERNAL_CODECS_LOC_VARS
- IBenchPrintCallback *printCallback,
- IBenchCallback *benchCallback,
- // IBenchFreqCallback *freqCallback,
- const CObjectVector<CProperty> &props,
- UInt32 numIterations,
- bool multiDict)
-{
- if (!CrcInternalTest())
- return E_FAIL;
-
- UInt32 numCPUs = 1;
- UInt64 ramSize = (UInt64)(sizeof(size_t)) << 29;
-
- NSystem::CProcessAffinity threadsInfo;
- threadsInfo.InitST();
-
- #ifndef _7ZIP_ST
-
- if (threadsInfo.Get() && threadsInfo.processAffinityMask != 0)
- numCPUs = threadsInfo.GetNumProcessThreads();
- else
- numCPUs = NSystem::GetNumberOfProcessors();
-
- #endif
-
- bool ramSize_Defined = NSystem::GetRamSize(ramSize);
-
- UInt32 numThreadsSpecified = numCPUs;
-
- UInt32 testTime = kComplexInSeconds;
-
- UInt64 specifiedFreq = 0;
-
- bool multiThreadTests = false;
-
- COneMethodInfo method;
-
- CAlignedBuffer fileDataBuffer;
-
- {
- unsigned i;
- for (i = 0; i < props.Size(); i++)
- {
- const CProperty &property = props[i];
- UString name (property.Name);
- name.MakeLower_Ascii();
-
- if (name.IsEqualTo("file"))
- {
- if (property.Value.IsEmpty())
- return E_INVALIDARG;
-
- #ifdef USE_WIN_FILE
-
- NFile::NIO::CInFile file;
- if (!file.Open(us2fs(property.Value)))
- return E_INVALIDARG;
- UInt64 len;
- if (!file.GetLength(len))
- return E_FAIL;
- if (len >= ((UInt32)1 << 31) || len == 0)
- return E_INVALIDARG;
- ALLOC_WITH_HRESULT(&fileDataBuffer, (size_t)len);
- UInt32 processedSize;
- file.Read((Byte *)fileDataBuffer, (UInt32)len, processedSize);
- if (processedSize != len)
- return E_FAIL;
- if (printCallback)
- {
- printCallback->Print("file size =");
- PrintNumber(*printCallback, len, 0);
- printCallback->NewLine();
- }
- continue;
-
- #else
-
- return E_NOTIMPL;
-
- #endif
- }
-
- NCOM::CPropVariant propVariant;
- if (!property.Value.IsEmpty())
- ParseNumberString(property.Value, propVariant);
-
- if (name.IsEqualTo("time"))
- {
- RINOK(ParsePropToUInt32(UString(), propVariant, testTime));
- continue;
- }
-
- if (name.IsEqualTo("freq"))
- {
- UInt32 freq32 = 0;
- RINOK(ParsePropToUInt32(UString(), propVariant, freq32));
- if (freq32 == 0)
- return E_INVALIDARG;
- specifiedFreq = (UInt64)freq32 * 1000000;
-
- if (printCallback)
- {
- printCallback->Print("freq=");
- PrintNumber(*printCallback, freq32, 0);
- printCallback->NewLine();
- }
-
- continue;
- }
-
- if (name.IsPrefixedBy_Ascii_NoCase("mt"))
- {
- UString s = name.Ptr(2);
- if (s.IsEqualTo("*")
- || s.IsEmpty() && propVariant.vt == VT_BSTR && StringsAreEqual_Ascii(propVariant.bstrVal, "*"))
- {
- multiThreadTests = true;
- continue;
- }
- #ifndef _7ZIP_ST
- RINOK(ParseMtProp(s, propVariant, numCPUs, numThreadsSpecified));
- #endif
- continue;
- }
-
- RINOK(method.ParseMethodFromPROPVARIANT(name, propVariant));
- }
- }
-
- if (printCallback)
- {
- #ifdef _WIN32
- #ifndef UNDER_CE
- {
- AString s;
- // OSVERSIONINFO vi;
- OSVERSIONINFOEXW vi;
- vi.dwOSVersionInfoSize = sizeof(vi);
- // if (::GetVersionEx(&vi))
- if (My_RtlGetVersion(&vi))
- {
- s += "Windows";
- if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT)
- s.Add_UInt32(vi.dwPlatformId);
- s += " "; s.Add_UInt32(vi.dwMajorVersion);
- s += "."; s.Add_UInt32(vi.dwMinorVersion);
- s += " "; s.Add_UInt32(vi.dwBuildNumber);
- // s += " "; s += GetAnsiString(vi.szCSDVersion);
- }
- printCallback->Print(s);
- printCallback->NewLine();
- }
- #endif
- #endif
-
- {
- AString s1, s2;
- GetSysInfo(s1, s2);
- if (!s1.IsEmpty() || !s2.IsEmpty())
- {
- printCallback->Print(s1);
- if (s1 != s2 && !s2.IsEmpty())
- {
- printCallback->Print(" - ");
- printCallback->Print(s2);
- }
- printCallback->NewLine();
- }
- }
- {
- AString s;
- GetCpuFeatures(s);
- if (!s.IsEmpty())
- {
- printCallback->Print(s);
- printCallback->NewLine();
- }
- }
- {
- AString s;
- GetCpuName(s);
- if (!s.IsEmpty())
- {
- printCallback->Print(s);
- printCallback->NewLine();
- }
- }
- }
-
- if (printCallback)
- {
- printCallback->Print("CPU Freq:");
- }
-
- UInt64 complexInCommands = kComplexInCommands;
-
- if (printCallback /* || freqCallback */)
- {
- UInt64 numMilCommands = 1 << 6;
- if (specifiedFreq != 0)
- {
- while (numMilCommands > 1 && specifiedFreq < (numMilCommands * 1000000))
- numMilCommands >>= 1;
- }
-
- for (int jj = 0;; jj++)
- {
- if (printCallback)
- RINOK(printCallback->CheckBreak());
-
- UInt64 start = ::GetTimeCount();
- UInt32 sum = (UInt32)start;
- sum = CountCpuFreq(sum, (UInt32)(numMilCommands * 1000000 / kNumFreqCommands), g_BenchCpuFreqTemp);
- if (sum == 0xF1541213)
- if (printCallback)
- printCallback->Print("");
- const UInt64 realDelta = ::GetTimeCount() - start;
- start = realDelta;
- if (start == 0)
- start = 1;
- UInt64 freq = GetFreq();
- // mips is constant in some compilers
- const UInt64 mipsVal = numMilCommands * freq / start;
- if (printCallback)
- {
- if (realDelta == 0)
- {
- printCallback->Print(" -");
- }
- else
- {
- // PrintNumber(*printCallback, start, 0);
- PrintNumber(*printCallback, mipsVal, 5);
- }
- }
- /*
- if (freqCallback)
- freqCallback->AddCpuFreq(mipsVal);
- */
-
- if (jj >= 3)
- {
- SetComplexCommands(testTime, false, mipsVal * 1000000, complexInCommands);
- if (jj >= 8 || start >= freq)
- break;
- // break; // change it
- numMilCommands <<= 1;
- }
- }
- }
-
- if (printCallback)
- {
- printCallback->NewLine();
- printCallback->NewLine();
- PrintRequirements(*printCallback, "size: ", ramSize_Defined, ramSize, "CPU hardware threads:", numCPUs);
- printCallback->Print(GetProcessThreadsInfo(threadsInfo));
- printCallback->NewLine();
- }
-
- if (numThreadsSpecified < 1 || numThreadsSpecified > kNumThreadsMax)
- return E_INVALIDARG;
-
- UInt32 dict;
- bool dictIsDefined = method.Get_DicSize(dict);
-
- if (method.MethodName.IsEmpty())
- method.MethodName = "LZMA";
-
- if (benchCallback)
- {
- CBenchProps benchProps;
- benchProps.SetLzmaCompexity();
- UInt32 dictSize = method.Get_Lzma_DicSize();
- UInt32 uncompressedDataSize = kAdditionalSize + dictSize;
- return MethodBench(
- EXTERNAL_CODECS_LOC_VARS
- complexInCommands,
- true, numThreadsSpecified,
- method,
- uncompressedDataSize, (const Byte *)fileDataBuffer,
- kOldLzmaDictBits, printCallback, benchCallback, &benchProps);
- }
-
- AString methodName (method.MethodName);
- if (methodName.IsEqualTo_Ascii_NoCase("CRC"))
- methodName = "crc32";
- method.MethodName = methodName;
- CMethodId hashID;
-
- if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS methodName, hashID))
- {
- if (!printCallback)
- return S_FALSE;
- IBenchPrintCallback &f = *printCallback;
- if (!dictIsDefined)
- dict = (1 << 24);
-
-
- // methhodName.RemoveChar(L'-');
- UInt32 complexity = 10000;
- const UInt32 *checkSum = NULL;
- {
- unsigned i;
- for (i = 0; i < ARRAY_SIZE(g_Hash); i++)
- {
- const CBenchHash &h = g_Hash[i];
- AString benchMethod (h.Name);
- AString benchProps;
- int propPos = benchMethod.Find(':');
- if (propPos >= 0)
- {
- benchProps = benchMethod.Ptr(propPos + 1);
- benchMethod.DeleteFrom(propPos);
- }
-
- if (AreSameMethodNames(benchMethod, methodName))
- {
- if (benchProps.IsEmpty()
- || benchMethod.IsEqualTo_Ascii_NoCase("crc32") && benchProps == "8" && method.PropsString.IsEmpty()
- || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps))
- {
- complexity = h.Complex;
- checkSum = &h.CheckSum;
- if (method.PropsString.IsEqualTo_Ascii_NoCase(benchProps))
- break;
- }
- }
- }
- if (i == ARRAY_SIZE(g_Hash))
- return E_NOTIMPL;
- }
-
- f.NewLine();
- f.Print("Size");
- const unsigned kFieldSize_CrcSpeed = 6;
- unsigned numThreadsTests = 0;
- for (;;)
- {
- UInt32 t = GetNumThreadsNext(numThreadsTests, numThreadsSpecified);
- PrintNumber(f, t, kFieldSize_CrcSpeed);
- numThreadsTests++;
- if (t >= numThreadsSpecified)
- break;
- }
- f.NewLine();
- f.NewLine();
- CTempValues speedTotals(numThreadsTests);
- {
- for (unsigned ti = 0; ti < numThreadsTests; ti++)
- speedTotals.Values[ti] = 0;
- }
-
- UInt64 numSteps = 0;
- for (UInt32 i = 0; i < numIterations; i++)
- {
- for (unsigned pow = 10; pow < 32; pow++)
- {
- UInt32 bufSize = (UInt32)1 << pow;
- if (bufSize > dict)
- break;
- char s[16];
- ConvertUInt32ToString(pow, s);
- unsigned pos = MyStringLen(s);
- s[pos++] = ':';
- s[pos++] = ' ';
- s[pos] = 0;
- f.Print(s);
-
- for (unsigned ti = 0; ti < numThreadsTests; ti++)
- {
- RINOK(f.CheckBreak());
- UInt32 t = GetNumThreadsNext(ti, numThreadsSpecified);
- UInt64 speed = 0;
- RINOK(CrcBench(EXTERNAL_CODECS_LOC_VARS complexInCommands,
- t, bufSize, speed,
- complexity,
- 1, // benchWeight,
- (pow == kNumHashDictBits) ? checkSum : NULL, method, NULL, NULL, false, 0));
- PrintNumber(f, (speed >> 20), kFieldSize_CrcSpeed);
- speedTotals.Values[ti] += speed;
- }
- f.NewLine();
- numSteps++;
- }
- }
- if (numSteps != 0)
- {
- f.NewLine();
- f.Print("Avg:");
- for (unsigned ti = 0; ti < numThreadsTests; ti++)
- {
- PrintNumber(f, ((speedTotals.Values[ti] / numSteps) >> 20), kFieldSize_CrcSpeed);
- }
- f.NewLine();
- }
- return S_OK;
- }
-
- bool use2Columns = false;
-
- bool totalBenchMode = (method.MethodName.IsEqualTo_Ascii_NoCase("*"));
- bool onlyHashBench = false;
- if (method.MethodName.IsEqualTo_Ascii_NoCase("hash"))
- {
- onlyHashBench = true;
- totalBenchMode = true;
- }
-
- // ---------- Threads loop ----------
- for (unsigned threadsPassIndex = 0; threadsPassIndex < 3; threadsPassIndex++)
- {
-
- UInt32 numThreads = numThreadsSpecified;
-
- if (!multiThreadTests)
- {
- if (threadsPassIndex != 0)
- break;
- }
- else
- {
- numThreads = 1;
- if (threadsPassIndex != 0)
- {
- if (numCPUs < 2)
- break;
- numThreads = numCPUs;
- if (threadsPassIndex == 1)
- {
- if (numCPUs >= 4)
- numThreads = numCPUs / 2;
- }
- else if (numCPUs < 4)
- break;
- }
- }
-
- CBenchCallbackToPrint callback;
- callback.Init();
- callback._file = printCallback;
-
- IBenchPrintCallback &f = *printCallback;
-
- if (threadsPassIndex > 0)
- {
- f.NewLine();
- f.NewLine();
- }
-
- if (!dictIsDefined)
- {
- const unsigned dicSizeLog_Main = (totalBenchMode ? 24 : 25);
- unsigned dicSizeLog = dicSizeLog_Main;
-
- #ifdef UNDER_CE
- dicSizeLog = (UInt64)1 << 20;
- #endif
-
- if (ramSize_Defined)
- for (; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--)
- if (GetBenchMemoryUsage(numThreads, ((UInt32)1 << dicSizeLog), totalBenchMode) + (8 << 20) <= ramSize)
- break;
-
- dict = (UInt32)1 << dicSizeLog;
-
- if (totalBenchMode && dicSizeLog != dicSizeLog_Main)
- {
- f.Print("Dictionary reduced to: ");
- PrintNumber(f, dicSizeLog, 1);
- f.NewLine();
- }
- }
-
- PrintRequirements(f, "usage:", true, GetBenchMemoryUsage(numThreads, dict, totalBenchMode), "Benchmark threads: ", numThreads);
- f.NewLine();
-
- f.NewLine();
-
- if (totalBenchMode)
- {
- callback.NameFieldSize = kFieldSize_Name;
- use2Columns = false;
- }
- else
- {
- callback.NameFieldSize = kFieldSize_SmallName;
- use2Columns = true;
- }
- callback.Use2Columns = use2Columns;
-
- bool showFreq = false;
- UInt64 cpuFreq = 0;
-
- if (totalBenchMode)
- {
- showFreq = true;
- }
-
- unsigned fileldSize = kFieldSize_TotalSize;
- if (showFreq)
- fileldSize += kFieldSize_EUAndEffec;
-
- if (use2Columns)
- {
- PrintSpaces(f, callback.NameFieldSize);
- PrintRight(f, "Compressing", fileldSize);
- f.Print(kSep);
- PrintRight(f, "Decompressing", fileldSize);
- }
- f.NewLine();
- PrintLeft(f, totalBenchMode ? "Method" : "Dict", callback.NameFieldSize);
-
- int j;
-
- for (j = 0; j < 2; j++)
- {
- PrintRight(f, "Speed", kFieldSize_Speed + 1);
- PrintRight(f, "Usage", kFieldSize_Usage + 1);
- PrintRight(f, "R/U", kFieldSize_RU + 1);
- PrintRight(f, "Rating", kFieldSize_Rating + 1);
- if (showFreq)
- {
- PrintRight(f, "E/U", kFieldSize_EU + 1);
- PrintRight(f, "Effec", kFieldSize_Effec + 1);
- }
- if (!use2Columns)
- break;
- if (j == 0)
- f.Print(kSep);
- }
-
- f.NewLine();
- PrintSpaces(f, callback.NameFieldSize);
-
- for (j = 0; j < 2; j++)
- {
- PrintRight(f, "KiB/s", kFieldSize_Speed + 1);
- PrintRight(f, "%", kFieldSize_Usage + 1);
- PrintRight(f, "MIPS", kFieldSize_RU + 1);
- PrintRight(f, "MIPS", kFieldSize_Rating + 1);
- if (showFreq)
- {
- PrintRight(f, "%", kFieldSize_EU + 1);
- PrintRight(f, "%", kFieldSize_Effec + 1);
- }
- if (!use2Columns)
- break;
- if (j == 0)
- f.Print(kSep);
- }
-
- f.NewLine();
- f.NewLine();
-
- if (specifiedFreq != 0)
- cpuFreq = specifiedFreq;
-
-
- if (totalBenchMode)
- {
- for (UInt32 i = 0; i < numIterations; i++)
- {
- if (i != 0)
- printCallback->NewLine();
- HRESULT res;
-
- const unsigned kNumCpuTests = 3;
- for (unsigned freqTest = 0; freqTest < kNumCpuTests; freqTest++)
- {
- PrintLeft(f, "CPU", kFieldSize_Name);
- UInt32 resVal;
- RINOK(FreqBench(complexInCommands, numThreads, printCallback,
- (freqTest == kNumCpuTests - 1 || specifiedFreq != 0), // showFreq
- specifiedFreq,
- cpuFreq, resVal));
- callback.NewLine();
-
- if (specifiedFreq != 0)
- cpuFreq = specifiedFreq;
-
- if (freqTest == kNumCpuTests - 1)
- SetComplexCommands(testTime, specifiedFreq != 0, cpuFreq, complexInCommands);
- }
- callback.NewLine();
-
- callback.SetFreq(true, cpuFreq);
-
- if (!onlyHashBench)
- {
- res = TotalBench(EXTERNAL_CODECS_LOC_VARS
- complexInCommands, numThreads,
- dictIsDefined || fileDataBuffer.IsAllocated(), // forceUnpackSize
- fileDataBuffer.IsAllocated() ? fileDataBuffer.Size() : dict,
- (const Byte *)fileDataBuffer,
- printCallback, &callback);
- RINOK(res);
- }
-
- res = TotalBench_Hash(EXTERNAL_CODECS_LOC_VARS complexInCommands, numThreads,
- 1 << kNumHashDictBits, printCallback, &callback, &callback.EncodeRes, true, cpuFreq);
- RINOK(res);
-
- callback.NewLine();
- {
- PrintLeft(f, "CPU", kFieldSize_Name);
- UInt32 resVal;
- UInt64 cpuFreqLastTemp = cpuFreq;
- RINOK(FreqBench(complexInCommands, numThreads, printCallback,
- specifiedFreq != 0, // showFreq
- specifiedFreq,
- cpuFreqLastTemp, resVal));
- callback.NewLine();
- }
- }
- }
- else
- {
- bool needSetComplexity = true;
- if (!methodName.IsEqualTo_Ascii_NoCase("LZMA"))
- {
- unsigned i;
- for (i = 0; i < ARRAY_SIZE(g_Bench); i++)
- {
- const CBenchMethod &h = g_Bench[i];
- AString benchMethod (h.Name);
- AString benchProps;
- int propPos = benchMethod.Find(':');
- if (propPos >= 0)
- {
- benchProps = benchMethod.Ptr(propPos + 1);
- benchMethod.DeleteFrom(propPos);
- }
-
- if (AreSameMethodNames(benchMethod, methodName))
- {
- if (benchProps.IsEmpty()
- || benchProps == "x5" && method.PropsString.IsEmpty()
- || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps))
- {
- callback.BenchProps.EncComplex = h.EncComplex;
- callback.BenchProps.DecComplexCompr = h.DecComplexCompr;
- callback.BenchProps.DecComplexUnc = h.DecComplexUnc;;
- needSetComplexity = false;
- break;
- }
- }
- }
- if (i == ARRAY_SIZE(g_Bench))
- return E_NOTIMPL;
- }
- if (needSetComplexity)
- callback.BenchProps.SetLzmaCompexity();
-
- for (unsigned i = 0; i < numIterations; i++)
- {
- const unsigned kStartDicLog = 22;
- unsigned pow = (dict < ((UInt32)1 << kStartDicLog)) ? kBenchMinDicLogSize : kStartDicLog;
- if (!multiDict)
- pow = 31;
- while (((UInt32)1 << pow) > dict && pow > 0)
- pow--;
- for (; ((UInt32)1 << pow) <= dict; pow++)
- {
- char s[16];
- ConvertUInt32ToString(pow, s);
- unsigned pos = MyStringLen(s);
- s[pos++] = ':';
- s[pos] = 0;
- PrintLeft(f, s, kFieldSize_SmallName);
- callback.DictSize = (UInt32)1 << pow;
-
- COneMethodInfo method2 = method;
-
- if (StringsAreEqualNoCase_Ascii(method2.MethodName, "LZMA"))
- {
- // We add dictionary size property.
- // method2 can have two different dictionary size properties.
- // And last property is main.
- NCOM::CPropVariant propVariant = (UInt32)pow;
- RINOK(method2.ParseMethodFromPROPVARIANT((UString)"d", propVariant));
- }
-
- size_t uncompressedDataSize;
- if (fileDataBuffer.IsAllocated())
- {
- uncompressedDataSize = fileDataBuffer.Size();
- }
- else
- {
- uncompressedDataSize = callback.DictSize;
- if (uncompressedDataSize >= (1 << 18))
- uncompressedDataSize += kAdditionalSize;
- }
-
- HRESULT res = MethodBench(
- EXTERNAL_CODECS_LOC_VARS
- complexInCommands,
- true, numThreads,
- method2,
- uncompressedDataSize, (const Byte *)fileDataBuffer,
- kOldLzmaDictBits, printCallback, &callback, &callback.BenchProps);
- f.NewLine();
- RINOK(res);
- if (!multiDict)
- break;
- }
- }
- }
-
- PrintChars(f, '-', callback.NameFieldSize + fileldSize);
-
- if (use2Columns)
- {
- f.Print(kSep);
- PrintChars(f, '-', fileldSize);
- }
-
- f.NewLine();
-
- if (use2Columns)
- {
- PrintLeft(f, "Avr:", callback.NameFieldSize);
- PrintTotals(f, showFreq, cpuFreq, callback.EncodeRes);
- f.Print(kSep);
- PrintTotals(f, showFreq, cpuFreq, callback.DecodeRes);
- f.NewLine();
- }
-
- PrintLeft(f, "Tot:", callback.NameFieldSize);
- CTotalBenchRes midRes;
- midRes.SetSum(callback.EncodeRes, callback.DecodeRes);
- PrintTotals(f, showFreq, cpuFreq, midRes);
- f.NewLine();
-
- }
- return S_OK;
-}
+// Bench.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+// #include <stdio.h>
+
+#ifndef _WIN32
+
+#define USE_POSIX_TIME
+#define USE_POSIX_TIME2
+#endif // _WIN32
+
+#ifdef USE_POSIX_TIME
+#include <time.h>
+#include <unistd.h>
+#ifdef USE_POSIX_TIME2
+#include <sys/time.h>
+#include <sys/times.h>
+#endif
+#endif // USE_POSIX_TIME
+
+#ifdef _WIN32
+#define USE_ALLOCA
+#endif
+
+#ifdef USE_ALLOCA
+#ifdef _WIN32
+#include <malloc.h>
+#else
+#include <stdlib.h>
+#endif
+#endif
+
+#include "../../../../C/7zCrc.h"
+#include "../../../../C/RotateDefs.h"
+
+#ifndef Z7_ST
+#include "../../../Windows/Synchronization.h"
+#include "../../../Windows/Thread.h"
+#endif
+
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/FileIO.h"
+#include "../../../Windows/SystemInfo.h"
+
+#include "../../../Common/MyBuffer2.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/StringToInt.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../../Common/MethodProps.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+
+#include "Bench.h"
+
+using namespace NWindows;
+
+#ifndef Z7_ST
+static const UInt32 k_LZMA = 0x030101;
+#endif
+
+static const UInt64 kComplexInCommands = (UInt64)1 <<
+ #ifdef UNDER_CE
+ 31;
+ #else
+ 34;
+ #endif
+
+static const UInt32 kComplexInMs = 4000;
+
+static void SetComplexCommandsMs(UInt32 complexInMs,
+ bool isSpecifiedFreq, UInt64 cpuFreq, UInt64 &complexInCommands)
+{
+ complexInCommands = kComplexInCommands;
+ const UInt64 kMinFreq = (UInt64)1000000 * 4;
+ const UInt64 kMaxFreq = (UInt64)1000000 * 20000;
+ if (cpuFreq < kMinFreq && !isSpecifiedFreq)
+ cpuFreq = kMinFreq;
+ if (cpuFreq < kMaxFreq || isSpecifiedFreq)
+ {
+ if (complexInMs != 0)
+ complexInCommands = complexInMs * cpuFreq / 1000;
+ else
+ complexInCommands = cpuFreq >> 2;
+ }
+}
+
+// const UInt64 kBenchmarkUsageMult = 1000000; // for debug
+static const unsigned kBenchmarkUsageMultBits = 16;
+static const UInt64 kBenchmarkUsageMult = 1 << kBenchmarkUsageMultBits;
+
+UInt64 Benchmark_GetUsage_Percents(UInt64 usage)
+{
+ return (100 * usage + kBenchmarkUsageMult / 2) / kBenchmarkUsageMult;
+}
+
+static const unsigned kNumHashDictBits = 17;
+static const UInt32 kFilterUnpackSize = (47 << 10); // + 5; // for test
+
+static const unsigned kOldLzmaDictBits = 32;
+
+// static const size_t kAdditionalSize = (size_t)1 << 32; // for debug
+static const size_t kAdditionalSize = (size_t)1 << 16;
+static const UInt32 kCompressedAdditionalSize = (1 << 10);
+
+static const UInt32 kMaxMethodPropSize = (1 << 6);
+
+
+#define ALLOC_WITH_HRESULT(_buffer_, _size_) \
+ { (_buffer_)->Alloc(_size_); \
+ if (_size_ && !(_buffer_)->IsAllocated()) return E_OUTOFMEMORY; }
+
+
+class CBaseRandomGenerator
+{
+ UInt32 A1;
+ UInt32 A2;
+ UInt32 Salt;
+public:
+ CBaseRandomGenerator(UInt32 salt = 0): Salt(salt) { Init(); }
+ void Init() { A1 = 362436069; A2 = 521288629;}
+ Z7_FORCE_INLINE
+ UInt32 GetRnd()
+ {
+ return Salt ^
+ (
+ ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) +
+ ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)) )
+ );
+ }
+};
+
+
+Z7_NO_INLINE
+static void RandGen(Byte *buf, size_t size)
+{
+ CBaseRandomGenerator RG;
+ const size_t size4 = size & ~((size_t)3);
+ size_t i;
+ for (i = 0; i < size4; i += 4)
+ {
+ const UInt32 v = RG.GetRnd();
+ SetUi32(buf + i, v)
+ }
+ UInt32 v = RG.GetRnd();
+ for (; i < size; i++)
+ {
+ buf[i] = (Byte)v;
+ v >>= 8;
+ }
+}
+
+
+class CBenchRandomGenerator: public CMidAlignedBuffer
+{
+ static UInt32 GetVal(UInt32 &res, unsigned numBits)
+ {
+ UInt32 val = res & (((UInt32)1 << numBits) - 1);
+ res >>= numBits;
+ return val;
+ }
+
+ static UInt32 GetLen(UInt32 &r)
+ {
+ UInt32 len = GetVal(r, 2);
+ return GetVal(r, 1 + len);
+ }
+
+public:
+
+ void GenerateSimpleRandom(UInt32 salt)
+ {
+ CBaseRandomGenerator rg(salt);
+ const size_t bufSize = Size();
+ Byte *buf = (Byte *)*this;
+ for (size_t i = 0; i < bufSize; i++)
+ buf[i] = (Byte)rg.GetRnd();
+ }
+
+ void GenerateLz(unsigned dictBits, UInt32 salt)
+ {
+ CBaseRandomGenerator rg(salt);
+ size_t pos = 0;
+ size_t rep0 = 1;
+ const size_t bufSize = Size();
+ Byte *buf = (Byte *)*this;
+ unsigned posBits = 1;
+
+ // printf("\n dictBits = %d\n", (UInt32)dictBits);
+ // printf("\n bufSize = 0x%p\n", (const void *)bufSize);
+
+ while (pos < bufSize)
+ {
+ /*
+ if (pos >= ((UInt32)1 << 31))
+ printf(" %x\n", pos);
+ */
+ UInt32 r = rg.GetRnd();
+ if (GetVal(r, 1) == 0 || pos < 1024)
+ buf[pos++] = (Byte)(r & 0xFF);
+ else
+ {
+ UInt32 len;
+ len = 1 + GetLen(r);
+
+ if (GetVal(r, 3) != 0)
+ {
+ len += GetLen(r);
+
+ while (((size_t)1 << posBits) < pos)
+ posBits++;
+
+ unsigned numBitsMax = dictBits;
+ if (numBitsMax > posBits)
+ numBitsMax = posBits;
+
+ const unsigned kAddBits = 6;
+ unsigned numLogBits = 5;
+ if (numBitsMax <= (1 << 4) - 1 + kAddBits)
+ numLogBits = 4;
+
+ for (;;)
+ {
+ const UInt32 ppp = GetVal(r, numLogBits) + kAddBits;
+ r = rg.GetRnd();
+ if (ppp > numBitsMax)
+ continue;
+ // rep0 = GetVal(r, ppp);
+ rep0 = r & (((size_t)1 << ppp) - 1);
+ if (rep0 < pos)
+ break;
+ r = rg.GetRnd();
+ }
+ rep0++;
+ }
+
+ // len *= 300; // for debug
+ {
+ const size_t rem = bufSize - pos;
+ if (len > rem)
+ len = (UInt32)rem;
+ }
+ Byte *dest = buf + pos;
+ const Byte *src = dest - rep0;
+ pos += len;
+ for (UInt32 i = 0; i < len; i++)
+ *dest++ = *src++;
+ }
+ }
+ // printf("\n CRC = %x\n", CrcCalc(buf, bufSize));
+ }
+};
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ CBenchmarkInStream
+ , ISequentialInStream
+)
+ const Byte *Data;
+ size_t Pos;
+ size_t Size;
+public:
+ void Init(const Byte *data, size_t size)
+ {
+ Data = data;
+ Size = size;
+ Pos = 0;
+ }
+ bool WasFinished() const { return Pos == Size; }
+};
+
+Z7_COM7F_IMF(CBenchmarkInStream::Read(void *data, UInt32 size, UInt32 *processedSize))
+{
+ const UInt32 kMaxBlockSize = (1 << 20);
+ if (size > kMaxBlockSize)
+ size = kMaxBlockSize;
+ const size_t remain = Size - Pos;
+ if (size > remain)
+ size = (UInt32)remain;
+
+ if (size != 0)
+ memcpy(data, Data + Pos, size);
+
+ Pos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+}
+
+
+class CBenchmarkOutStream Z7_final:
+ public ISequentialOutStream,
+ public CMyUnknownImp,
+ public CMidAlignedBuffer
+{
+ Z7_COM_UNKNOWN_IMP_0
+ Z7_IFACE_COM7_IMP(ISequentialOutStream)
+ // bool _overflow;
+public:
+ size_t Pos;
+ bool RealCopy;
+ bool CalcCrc;
+ UInt32 Crc;
+
+ // CBenchmarkOutStream(): _overflow(false) {}
+ void Init(bool realCopy, bool calcCrc)
+ {
+ Crc = CRC_INIT_VAL;
+ RealCopy = realCopy;
+ CalcCrc = calcCrc;
+ // _overflow = false;
+ Pos = 0;
+ }
+
+ void InitCrc()
+ {
+ Crc = CRC_INIT_VAL;
+ }
+
+ void Calc(const void *data, size_t size)
+ {
+ Crc = CrcUpdate(Crc, data, size);
+ }
+
+ size_t GetPos() const { return Pos; }
+
+ // void Print() { printf("\n%8d %8d\n", (unsigned)BufferSize, (unsigned)Pos); }
+};
+
+Z7_COM7F_IMF(CBenchmarkOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ size_t curSize = Size() - Pos;
+ if (curSize > size)
+ curSize = size;
+ if (curSize != 0)
+ {
+ if (RealCopy)
+ memcpy(((Byte *)*this) + Pos, data, curSize);
+ if (CalcCrc)
+ Calc(data, curSize);
+ Pos += curSize;
+ }
+ if (processedSize)
+ *processedSize = (UInt32)curSize;
+ if (curSize != size)
+ {
+ // _overflow = true;
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ CCrcOutStream
+ , ISequentialOutStream
+)
+public:
+ bool CalcCrc;
+ UInt32 Crc;
+ UInt64 Pos;
+
+ CCrcOutStream(): CalcCrc(true) {}
+ void Init() { Crc = CRC_INIT_VAL; Pos = 0; }
+ void Calc(const void *data, size_t size)
+ {
+ Crc = CrcUpdate(Crc, data, size);
+ }
+};
+
+Z7_COM7F_IMF(CCrcOutStream::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (CalcCrc)
+ Calc(data, size);
+ Pos += size;
+ if (processedSize)
+ *processedSize = size;
+ return S_OK;
+}
+
+// #include "../../../../C/My_sys_time.h"
+
+static UInt64 GetTimeCount()
+{
+ #ifdef USE_POSIX_TIME
+ #ifdef USE_POSIX_TIME2
+ timeval v;
+ if (gettimeofday(&v, NULL) == 0)
+ return (UInt64)(v.tv_sec) * 1000000 + (UInt64)v.tv_usec;
+ return (UInt64)time(NULL) * 1000000;
+ #else
+ return time(NULL);
+ #endif
+ #else
+ LARGE_INTEGER value;
+ if (::QueryPerformanceCounter(&value))
+ return (UInt64)value.QuadPart;
+ return GetTickCount();
+ #endif
+}
+
+static UInt64 GetFreq()
+{
+ #ifdef USE_POSIX_TIME
+ #ifdef USE_POSIX_TIME2
+ return 1000000;
+ #else
+ return 1;
+ #endif
+ #else
+ LARGE_INTEGER value;
+ if (::QueryPerformanceFrequency(&value))
+ return (UInt64)value.QuadPart;
+ return 1000;
+ #endif
+}
+
+
+#ifdef USE_POSIX_TIME
+
+struct CUserTime
+{
+ UInt64 Sum;
+ clock_t Prev;
+
+ void Init()
+ {
+ // Prev = clock();
+ Sum = 0;
+ Prev = 0;
+ Update();
+ Sum = 0;
+ }
+
+ void Update()
+ {
+ tms t;
+ /* clock_t res = */ times(&t);
+ clock_t newVal = t.tms_utime + t.tms_stime;
+ Sum += (UInt64)(newVal - Prev);
+ Prev = newVal;
+
+ /*
+ clock_t v = clock();
+ if (v != -1)
+ {
+ Sum += v - Prev;
+ Prev = v;
+ }
+ */
+ }
+ UInt64 GetUserTime()
+ {
+ Update();
+ return Sum;
+ }
+};
+
+#else
+
+
+struct CUserTime
+{
+ bool UseTick;
+ DWORD Prev_Tick;
+ UInt64 Prev;
+ UInt64 Sum;
+
+ void Init()
+ {
+ UseTick = false;
+ Prev_Tick = 0;
+ Prev = 0;
+ Sum = 0;
+ Update();
+ Sum = 0;
+ }
+ UInt64 GetUserTime()
+ {
+ Update();
+ return Sum;
+ }
+ void Update();
+};
+
+static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }
+
+void CUserTime::Update()
+{
+ DWORD new_Tick = GetTickCount();
+ FILETIME creationTime, exitTime, kernelTime, userTime;
+ if (!UseTick &&
+ #ifdef UNDER_CE
+ ::GetThreadTimes(::GetCurrentThread()
+ #else
+ ::GetProcessTimes(::GetCurrentProcess()
+ #endif
+ , &creationTime, &exitTime, &kernelTime, &userTime))
+ {
+ UInt64 newVal = GetTime64(userTime) + GetTime64(kernelTime);
+ Sum += newVal - Prev;
+ Prev = newVal;
+ }
+ else
+ {
+ UseTick = true;
+ Sum += (UInt64)(new_Tick - (DWORD)Prev_Tick) * 10000;
+ }
+ Prev_Tick = new_Tick;
+}
+
+
+#endif
+
+static UInt64 GetUserFreq()
+{
+ #ifdef USE_POSIX_TIME
+ // return CLOCKS_PER_SEC;
+ return (UInt64)sysconf(_SC_CLK_TCK);
+ #else
+ return 10000000;
+ #endif
+}
+
+class CBenchProgressStatus Z7_final
+{
+ #ifndef Z7_ST
+ NSynchronization::CCriticalSection CS;
+ #endif
+public:
+ HRESULT Res;
+ bool EncodeMode;
+ void SetResult(HRESULT res)
+ {
+ #ifndef Z7_ST
+ NSynchronization::CCriticalSectionLock lock(CS);
+ #endif
+ Res = res;
+ }
+ HRESULT GetResult()
+ {
+ #ifndef Z7_ST
+ NSynchronization::CCriticalSectionLock lock(CS);
+ #endif
+ return Res;
+ }
+};
+
+struct CBenchInfoCalc
+{
+ CBenchInfo BenchInfo;
+ CUserTime UserTime;
+
+ void SetStartTime();
+ void SetFinishTime(CBenchInfo &dest);
+};
+
+void CBenchInfoCalc::SetStartTime()
+{
+ BenchInfo.GlobalFreq = GetFreq();
+ BenchInfo.UserFreq = GetUserFreq();
+ BenchInfo.GlobalTime = ::GetTimeCount();
+ BenchInfo.UserTime = 0;
+ UserTime.Init();
+}
+
+void CBenchInfoCalc::SetFinishTime(CBenchInfo &dest)
+{
+ dest = BenchInfo;
+ dest.GlobalTime = ::GetTimeCount() - BenchInfo.GlobalTime;
+ dest.UserTime = UserTime.GetUserTime();
+}
+
+class CBenchProgressInfo Z7_final:
+ public ICompressProgressInfo,
+ public CMyUnknownImp,
+ public CBenchInfoCalc
+{
+ Z7_COM_UNKNOWN_IMP_0
+ Z7_IFACE_COM7_IMP(ICompressProgressInfo)
+public:
+ CBenchProgressStatus *Status;
+ IBenchCallback *Callback;
+
+ CBenchProgressInfo(): Callback(NULL) {}
+};
+
+
+Z7_COM7F_IMF(CBenchProgressInfo::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
+{
+ HRESULT res = Status->GetResult();
+ if (res != S_OK)
+ return res;
+ if (!Callback)
+ return res;
+
+ /*
+ static UInt64 inSizePrev = 0;
+ static UInt64 outSizePrev = 0;
+ UInt64 delta1 = 0, delta2 = 0, val1 = 0, val2 = 0;
+ if (inSize) { val1 = *inSize; delta1 = val1 - inSizePrev; inSizePrev = val1; }
+ if (outSize) { val2 = *outSize; delta2 = val2 - outSizePrev; outSizePrev = val2; }
+ UInt64 percents = delta2 * 1000;
+ if (delta1 != 0)
+ percents /= delta1;
+ printf("=== %7d %7d %7d %7d ratio = %4d\n",
+ (unsigned)(val1 >> 10), (unsigned)(delta1 >> 10),
+ (unsigned)(val2 >> 10), (unsigned)(delta2 >> 10),
+ (unsigned)percents);
+ */
+
+ CBenchInfo info;
+ SetFinishTime(info);
+ if (Status->EncodeMode)
+ {
+ info.UnpackSize = BenchInfo.UnpackSize + *inSize;
+ info.PackSize = BenchInfo.PackSize + *outSize;
+ res = Callback->SetEncodeResult(info, false);
+ }
+ else
+ {
+ info.PackSize = BenchInfo.PackSize + *inSize;
+ info.UnpackSize = BenchInfo.UnpackSize + *outSize;
+ res = Callback->SetDecodeResult(info, false);
+ }
+ if (res != S_OK)
+ Status->SetResult(res);
+ return res;
+}
+
+static const unsigned kSubBits = 8;
+
+static unsigned GetLogSize(UInt64 size)
+{
+ unsigned i = 0;
+ for (;;)
+ {
+ i++; size >>= 1; if (size == 0) break;
+ }
+ return i;
+}
+
+
+static UInt32 GetLogSize_Sub(UInt64 size)
+{
+ if (size <= 1)
+ return 0;
+ const unsigned i = GetLogSize(size) - 1;
+ UInt32 v;
+ if (i <= kSubBits)
+ v = (UInt32)(size) << (kSubBits - i);
+ else
+ v = (UInt32)(size >> (i - kSubBits));
+ return ((UInt32)i << kSubBits) + (v & (((UInt32)1 << kSubBits) - 1));
+}
+
+
+static UInt64 Get_UInt64_from_double(double v)
+{
+ const UInt64 kMaxVal = (UInt64)1 << 62;
+ if (v > (double)(Int64)kMaxVal)
+ return kMaxVal;
+ return (UInt64)v;
+}
+
+static UInt64 MyMultDiv64(UInt64 m1, UInt64 m2, UInt64 d)
+{
+ if (d == 0)
+ d = 1;
+ const double v =
+ (double)(Int64)m1 *
+ (double)(Int64)m2 /
+ (double)(Int64)d;
+ return Get_UInt64_from_double(v);
+ /*
+ unsigned n1 = GetLogSize(m1);
+ unsigned n2 = GetLogSize(m2);
+ while (n1 + n2 > 64)
+ {
+ if (n1 >= n2)
+ {
+ m1 >>= 1;
+ n1--;
+ }
+ else
+ {
+ m2 >>= 1;
+ n2--;
+ }
+ d >>= 1;
+ }
+
+ if (d == 0)
+ d = 1;
+ return m1 * m2 / d;
+ */
+}
+
+
+UInt64 CBenchInfo::GetUsage() const
+{
+ UInt64 userTime = UserTime;
+ UInt64 userFreq = UserFreq;
+ UInt64 globalTime = GlobalTime;
+ UInt64 globalFreq = GlobalFreq;
+
+ if (userFreq == 0)
+ userFreq = 1;
+ if (globalTime == 0)
+ globalTime = 1;
+
+ const double v =
+ ((double)(Int64)userTime / (double)(Int64)userFreq)
+ * ((double)(Int64)globalFreq / (double)(Int64)globalTime)
+ * (double)(Int64)kBenchmarkUsageMult;
+ return Get_UInt64_from_double(v);
+ /*
+ return MyMultDiv64(
+ MyMultDiv64(kBenchmarkUsageMult, userTime, userFreq),
+ globalFreq, globalTime);
+ */
+}
+
+
+UInt64 CBenchInfo::GetRatingPerUsage(UInt64 rating) const
+{
+ if (UserTime == 0)
+ {
+ return 0;
+ // userTime = 1;
+ }
+ UInt64 globalFreq = GlobalFreq;
+ if (globalFreq == 0)
+ globalFreq = 1;
+
+ const double v =
+ ((double)(Int64)GlobalTime / (double)(Int64)globalFreq)
+ * ((double)(Int64)UserFreq / (double)(Int64)UserTime)
+ * (double)(Int64)rating;
+ return Get_UInt64_from_double(v);
+ /*
+ return MyMultDiv64(
+ MyMultDiv64(rating, UserFreq, UserTime),
+ GlobalTime, globalFreq);
+ */
+}
+
+
+UInt64 CBenchInfo::GetSpeed(UInt64 numUnits) const
+{
+ return MyMultDiv64(numUnits, GlobalFreq, GlobalTime);
+}
+
+static UInt64 GetNumCommands_from_Size_and_Complexity(UInt64 size, Int32 complexity)
+{
+ return complexity >= 0 ?
+ size * (UInt32)complexity :
+ size / (UInt32)(-complexity);
+}
+
+struct CBenchProps
+{
+ bool LzmaRatingMode;
+
+ Int32 EncComplex;
+ Int32 DecComplexCompr;
+ Int32 DecComplexUnc;
+
+ unsigned KeySize;
+
+ CBenchProps():
+ LzmaRatingMode(false),
+ KeySize(0)
+ {}
+
+ void SetLzmaCompexity();
+
+ UInt64 GetNumCommands_Enc(UInt64 unpackSize) const
+ {
+ const UInt32 kMinSize = 100;
+ if (unpackSize < kMinSize)
+ unpackSize = kMinSize;
+ return GetNumCommands_from_Size_and_Complexity(unpackSize, EncComplex);
+ }
+
+ UInt64 GetNumCommands_Dec(UInt64 packSize, UInt64 unpackSize) const
+ {
+ return
+ GetNumCommands_from_Size_and_Complexity(packSize, DecComplexCompr) +
+ GetNumCommands_from_Size_and_Complexity(unpackSize, DecComplexUnc);
+ }
+
+ UInt64 GetRating_Enc(UInt64 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size) const;
+ UInt64 GetRating_Dec(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations) const;
+};
+
+void CBenchProps::SetLzmaCompexity()
+{
+ EncComplex = 1200;
+ DecComplexUnc = 4;
+ DecComplexCompr = 190;
+ LzmaRatingMode = true;
+}
+
+UInt64 CBenchProps::GetRating_Enc(UInt64 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size) const
+{
+ if (dictSize < (1 << kBenchMinDicLogSize))
+ dictSize = (1 << kBenchMinDicLogSize);
+ Int32 encComplex = EncComplex;
+ if (LzmaRatingMode)
+ {
+ /*
+ for (UInt64 uu = 0; uu < (UInt64)0xf << 60;)
+ {
+ unsigned rr = GetLogSize_Sub(uu);
+ printf("\n%16I64x , log = %4x", uu, rr);
+ uu += 1;
+ uu += uu / 50;
+ }
+ */
+ // throw 1;
+ const UInt32 t = GetLogSize_Sub(dictSize) - (kBenchMinDicLogSize << kSubBits);
+ encComplex = 870 + ((t * t * 5) >> (2 * kSubBits));
+ }
+ const UInt64 numCommands = GetNumCommands_from_Size_and_Complexity(size, encComplex);
+ return MyMultDiv64(numCommands, freq, elapsedTime);
+}
+
+UInt64 CBenchProps::GetRating_Dec(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations) const
+{
+ const UInt64 numCommands = GetNumCommands_Dec(inSize, outSize) * numIterations;
+ return MyMultDiv64(numCommands, freq, elapsedTime);
+}
+
+
+
+UInt64 CBenchInfo::GetRating_LzmaEnc(UInt64 dictSize) const
+{
+ CBenchProps props;
+ props.SetLzmaCompexity();
+ return props.GetRating_Enc(dictSize, GlobalTime, GlobalFreq, UnpackSize * NumIterations);
+}
+
+UInt64 CBenchInfo::GetRating_LzmaDec() const
+{
+ CBenchProps props;
+ props.SetLzmaCompexity();
+ return props.GetRating_Dec(GlobalTime, GlobalFreq, UnpackSize, PackSize, NumIterations);
+}
+
+
+#ifndef Z7_ST
+
+#define NUM_CPU_LEVELS_MAX 3
+
+struct CAffinityMode
+{
+ unsigned NumBundleThreads;
+ unsigned NumLevels;
+ unsigned NumCoreThreads;
+ unsigned NumCores;
+ // unsigned DivideNum;
+ UInt32 Sizes[NUM_CPU_LEVELS_MAX];
+
+ void SetLevels(unsigned numCores, unsigned numCoreThreads);
+ DWORD_PTR GetAffinityMask(UInt32 bundleIndex, CCpuSet *cpuSet) const;
+ bool NeedAffinity() const { return NumBundleThreads != 0; }
+
+ WRes CreateThread_WithAffinity(NWindows::CThread &thread, THREAD_FUNC_TYPE startAddress, LPVOID parameter, UInt32 bundleIndex) const
+ {
+ if (NeedAffinity())
+ {
+ CCpuSet cpuSet;
+ GetAffinityMask(bundleIndex, &cpuSet);
+ return thread.Create_With_CpuSet(startAddress, parameter, &cpuSet);
+ }
+ return thread.Create(startAddress, parameter);
+ }
+
+ CAffinityMode():
+ NumBundleThreads(0),
+ NumLevels(0),
+ NumCoreThreads(1)
+ // DivideNum(1)
+ {}
+};
+
+void CAffinityMode::SetLevels(unsigned numCores, unsigned numCoreThreads)
+{
+ NumCores = numCores;
+ NumCoreThreads = numCoreThreads;
+ NumLevels = 0;
+ if (numCoreThreads == 0 || numCores == 0 || numCores % numCoreThreads != 0)
+ return;
+ UInt32 c = numCores / numCoreThreads;
+ UInt32 c2 = 1;
+ while ((c & 1) == 0)
+ {
+ c >>= 1;
+ c2 <<= 1;
+ }
+ if (c2 != 1)
+ Sizes[NumLevels++] = c2;
+ if (c != 1)
+ Sizes[NumLevels++] = c;
+ if (numCoreThreads != 1)
+ Sizes[NumLevels++] = numCoreThreads;
+ if (NumLevels == 0)
+ Sizes[NumLevels++] = 1;
+
+ /*
+ printf("\n Cores:");
+ for (unsigned i = 0; i < NumLevels; i++)
+ {
+ printf(" %d", Sizes[i]);
+ }
+ printf("\n");
+ */
+}
+
+
+DWORD_PTR CAffinityMode::GetAffinityMask(UInt32 bundleIndex, CCpuSet *cpuSet) const
+{
+ CpuSet_Zero(cpuSet);
+
+ if (NumLevels == 0)
+ return 0;
+
+ // printf("\n%2d", bundleIndex);
+
+ /*
+ UInt32 low = 0;
+ if (DivideNum != 1)
+ {
+ low = bundleIndex % DivideNum;
+ bundleIndex /= DivideNum;
+ }
+ */
+
+ UInt32 numGroups = NumCores / NumBundleThreads;
+ UInt32 m = bundleIndex % numGroups;
+ UInt32 v = 0;
+ for (unsigned i = 0; i < NumLevels; i++)
+ {
+ UInt32 size = Sizes[i];
+ while ((size & 1) == 0)
+ {
+ v *= 2;
+ v |= (m & 1);
+ m >>= 1;
+ size >>= 1;
+ }
+ v *= size;
+ v += m % size;
+ m /= size;
+ }
+
+ // UInt32 nb = NumBundleThreads / DivideNum;
+ UInt32 nb = NumBundleThreads;
+
+ DWORD_PTR mask = ((DWORD_PTR)1 << nb) - 1;
+ // v += low;
+ mask <<= v;
+
+ // printf(" %2d %8x \n ", v, (unsigned)mask);
+ #ifdef _WIN32
+ *cpuSet = mask;
+ #else
+ {
+ for (unsigned k = 0; k < nb; k++)
+ CpuSet_Set(cpuSet, v + k);
+ }
+ #endif
+
+ return mask;
+}
+
+
+struct CBenchSyncCommon
+{
+ bool ExitMode;
+ NSynchronization::CManualResetEvent StartEvent;
+
+ CBenchSyncCommon(): ExitMode(false) {}
+};
+
+#endif
+
+
+
+enum E_CheckCrcMode
+{
+ k_CheckCrcMode_Never = 0,
+ k_CheckCrcMode_Always = 1,
+ k_CheckCrcMode_FirstPass = 2
+};
+
+class CEncoderInfo;
+
+class CEncoderInfo Z7_final
+{
+ Z7_CLASS_NO_COPY(CEncoderInfo)
+
+public:
+
+ #ifndef Z7_ST
+ NWindows::CThread thread[2];
+ NSynchronization::CManualResetEvent ReadyEvent;
+ UInt32 NumDecoderSubThreads;
+ CBenchSyncCommon *Common;
+ UInt32 EncoderIndex;
+ UInt32 NumEncoderInternalThreads;
+ CAffinityMode AffinityMode;
+ bool IsGlobalMtMode; // if more than one benchmark encoder threads
+ #endif
+
+ CMyComPtr<ICompressCoder> _encoder;
+ CMyComPtr<ICompressFilter> _encoderFilter;
+ CBenchProgressInfo *progressInfoSpec[2];
+ CMyComPtr<ICompressProgressInfo> progressInfo[2];
+ UInt64 NumIterations;
+
+ UInt32 Salt;
+
+ #ifdef USE_ALLOCA
+ size_t AllocaSize;
+ #endif
+
+ unsigned KeySize;
+ Byte _key[32];
+ Byte _iv[16];
+
+ HRESULT Set_Key_and_IV(ICryptoProperties *cp)
+ {
+ RINOK(cp->SetKey(_key, KeySize))
+ return cp->SetInitVector(_iv, sizeof(_iv));
+ }
+
+ Byte _psw[16];
+
+ bool CheckCrc_Enc; /* = 1, if we want to check packed data crcs after each pass
+ used for filter and usual coders */
+ bool UseRealData_Enc; /* = 1, if we want to use only original data for each pass
+ used only for filter */
+ E_CheckCrcMode CheckCrcMode_Dec;
+
+ struct CDecoderInfo
+ {
+ CEncoderInfo *Encoder;
+ UInt32 DecoderIndex;
+ bool CallbackMode;
+
+ #ifdef USE_ALLOCA
+ size_t AllocaSize;
+ #endif
+ };
+ CDecoderInfo decodersInfo[2];
+
+ CMyComPtr<ICompressCoder> _decoders[2];
+ CMyComPtr<ICompressFilter> _decoderFilter;
+
+ HRESULT Results[2];
+ CBenchmarkOutStream *outStreamSpec;
+ CMyComPtr<ISequentialOutStream> outStream;
+ IBenchCallback *callback;
+ IBenchPrintCallback *printCallback;
+ UInt32 crc;
+ size_t kBufferSize;
+ size_t compressedSize;
+ const Byte *uncompressedDataPtr;
+
+ const Byte *fileData;
+ CBenchRandomGenerator rg;
+
+ CMidAlignedBuffer rgCopy; // it must be 16-byte aligned !!!
+
+ // CBenchmarkOutStream *propStreamSpec;
+ Byte propsData[kMaxMethodPropSize];
+ CBufPtrSeqOutStream *propStreamSpec;
+ CMyComPtr<ISequentialOutStream> propStream;
+
+ unsigned generateDictBits;
+ COneMethodInfo _method;
+
+ // for decode
+ size_t _uncompressedDataSize;
+
+ HRESULT Generate();
+ HRESULT Encode();
+ HRESULT Decode(UInt32 decoderIndex);
+
+ CEncoderInfo():
+ #ifndef Z7_ST
+ Common(NULL),
+ IsGlobalMtMode(true),
+ #endif
+ Salt(0),
+ KeySize(0),
+ CheckCrc_Enc(true),
+ UseRealData_Enc(true),
+ CheckCrcMode_Dec(k_CheckCrcMode_Always),
+ outStreamSpec(NULL),
+ callback(NULL),
+ printCallback(NULL),
+ fileData(NULL),
+ propStreamSpec(NULL)
+ {}
+
+ #ifndef Z7_ST
+
+ static THREAD_FUNC_DECL EncodeThreadFunction(void *param)
+ {
+ HRESULT res;
+ CEncoderInfo *encoder = (CEncoderInfo *)param;
+ try
+ {
+ #ifdef USE_ALLOCA
+ alloca(encoder->AllocaSize);
+ #endif
+
+ res = encoder->Encode();
+ }
+ catch(...)
+ {
+ res = E_FAIL;
+ }
+ encoder->Results[0] = res;
+ if (res != S_OK)
+ encoder->progressInfoSpec[0]->Status->SetResult(res);
+ encoder->ReadyEvent.Set();
+ return THREAD_FUNC_RET_ZERO;
+ }
+
+ static THREAD_FUNC_DECL DecodeThreadFunction(void *param)
+ {
+ CDecoderInfo *decoder = (CDecoderInfo *)param;
+
+ #ifdef USE_ALLOCA
+ alloca(decoder->AllocaSize);
+ #endif
+
+ CEncoderInfo *encoder = decoder->Encoder;
+ encoder->Results[decoder->DecoderIndex] = encoder->Decode(decoder->DecoderIndex);
+ return THREAD_FUNC_RET_ZERO;
+ }
+
+ HRESULT CreateEncoderThread()
+ {
+ WRes res = 0;
+ if (!ReadyEvent.IsCreated())
+ res = ReadyEvent.Create();
+ if (res == 0)
+ res = AffinityMode.CreateThread_WithAffinity(thread[0], EncodeThreadFunction, this,
+ EncoderIndex);
+ return HRESULT_FROM_WIN32(res);
+ }
+
+ HRESULT CreateDecoderThread(unsigned index, bool callbackMode
+ #ifdef USE_ALLOCA
+ , size_t allocaSize
+ #endif
+ )
+ {
+ CDecoderInfo &decoder = decodersInfo[index];
+ decoder.DecoderIndex = index;
+ decoder.Encoder = this;
+
+ #ifdef USE_ALLOCA
+ decoder.AllocaSize = allocaSize;
+ #endif
+
+ decoder.CallbackMode = callbackMode;
+
+ WRes res = AffinityMode.CreateThread_WithAffinity(thread[index], DecodeThreadFunction, &decoder,
+ // EncoderIndex * NumEncoderInternalThreads + index
+ EncoderIndex
+ );
+
+ return HRESULT_FROM_WIN32(res);
+ }
+
+ #endif
+};
+
+
+
+
+static size_t GetBenchCompressedSize(size_t bufferSize)
+{
+ return kCompressedAdditionalSize + bufferSize + bufferSize / 16;
+ // kBufferSize / 2;
+}
+
+
+HRESULT CEncoderInfo::Generate()
+{
+ const COneMethodInfo &method = _method;
+
+ // we need extra space, if input data is already compressed
+ const size_t kCompressedBufferSize = _encoderFilter ?
+ kBufferSize :
+ GetBenchCompressedSize(kBufferSize);
+
+ if (kCompressedBufferSize < kBufferSize)
+ return E_FAIL;
+
+ uncompressedDataPtr = fileData;
+ if (fileData)
+ {
+ #if !defined(Z7_ST)
+ if (IsGlobalMtMode)
+ {
+ /* we copy the data to local buffer of thread to eliminate
+ using of shared buffer by different threads */
+ ALLOC_WITH_HRESULT(&rg, kBufferSize)
+ memcpy((Byte *)rg, fileData, kBufferSize);
+ uncompressedDataPtr = (const Byte *)rg;
+ }
+ #endif
+ }
+ else
+ {
+ ALLOC_WITH_HRESULT(&rg, kBufferSize)
+ // DWORD ttt = GetTickCount();
+ if (generateDictBits == 0)
+ rg.GenerateSimpleRandom(Salt);
+ else
+ {
+ if (generateDictBits >= sizeof(size_t) * 8
+ && kBufferSize > ((size_t)1 << (sizeof(size_t) * 8 - 1)))
+ return E_INVALIDARG;
+ rg.GenerateLz(generateDictBits, Salt);
+ // return E_ABORT; // for debug
+ }
+ // printf("\n%d\n ", GetTickCount() - ttt);
+
+ crc = CrcCalc((const Byte *)rg, rg.Size());
+ uncompressedDataPtr = (const Byte *)rg;
+ }
+
+ if (!outStream)
+ {
+ outStreamSpec = new CBenchmarkOutStream;
+ outStream = outStreamSpec;
+ }
+
+ ALLOC_WITH_HRESULT(outStreamSpec, kCompressedBufferSize)
+
+ if (_encoderFilter)
+ {
+ /* we try to reduce the number of memcpy() in main encoding loop.
+ so we copy data to temp buffers here */
+ ALLOC_WITH_HRESULT(&rgCopy, kBufferSize)
+ memcpy((Byte *)*outStreamSpec, uncompressedDataPtr, kBufferSize);
+ memcpy((Byte *)rgCopy, uncompressedDataPtr, kBufferSize);
+ }
+
+ if (!propStream)
+ {
+ propStreamSpec = new CBufPtrSeqOutStream; // CBenchmarkOutStream;
+ propStream = propStreamSpec;
+ }
+ // ALLOC_WITH_HRESULT_2(propStreamSpec, kMaxMethodPropSize);
+ // propStreamSpec->Init(true, false);
+ propStreamSpec->Init(propsData, sizeof(propsData));
+
+
+ CMyComPtr<IUnknown> coder;
+ if (_encoderFilter)
+ coder = _encoderFilter;
+ else
+ coder = _encoder;
+ {
+ CMyComPtr<ICompressSetCoderProperties> scp;
+ coder.QueryInterface(IID_ICompressSetCoderProperties, &scp);
+ if (scp)
+ {
+ const UInt64 reduceSize = kBufferSize;
+
+ /* in posix new thread uses same affinity as parent thread,
+ so we don't need to send affinity to coder in posix */
+ UInt64 affMask;
+ #if !defined(Z7_ST) && defined(_WIN32)
+ {
+ CCpuSet cpuSet;
+ affMask = AffinityMode.GetAffinityMask(EncoderIndex, &cpuSet);
+ }
+ #else
+ affMask = 0;
+ #endif
+ // affMask <<= 3; // debug line: to test no affinity in coder;
+ // affMask = 0;
+
+ RINOK(method.SetCoderProps_DSReduce_Aff(scp, &reduceSize, (affMask != 0 ? &affMask : NULL)))
+ }
+ else
+ {
+ if (method.AreThereNonOptionalProps())
+ return E_INVALIDARG;
+ }
+
+ CMyComPtr<ICompressWriteCoderProperties> writeCoderProps;
+ coder.QueryInterface(IID_ICompressWriteCoderProperties, &writeCoderProps);
+ if (writeCoderProps)
+ {
+ RINOK(writeCoderProps->WriteCoderProperties(propStream))
+ }
+
+ {
+ CMyComPtr<ICryptoSetPassword> sp;
+ coder.QueryInterface(IID_ICryptoSetPassword, &sp);
+ if (sp)
+ {
+ RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw)))
+
+ // we must call encoding one time to calculate password key for key cache.
+ // it must be after WriteCoderProperties!
+ Byte temp[16];
+ memset(temp, 0, sizeof(temp));
+
+ if (_encoderFilter)
+ {
+ _encoderFilter->Init();
+ _encoderFilter->Filter(temp, sizeof(temp));
+ }
+ else
+ {
+ CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
+ CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+ inStreamSpec->Init(temp, sizeof(temp));
+
+ CCrcOutStream *crcStreamSpec = new CCrcOutStream;
+ CMyComPtr<ISequentialOutStream> crcStream = crcStreamSpec;
+ crcStreamSpec->Init();
+
+ RINOK(_encoder->Code(inStream, crcStream, NULL, NULL, NULL))
+ }
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+
+static void My_FilterBench(ICompressFilter *filter, Byte *data, size_t size, UInt32 *crc)
+{
+ while (size != 0)
+ {
+ UInt32 cur = crc ? 1 << 17 : 1 << 24;
+ if (cur > size)
+ cur = (UInt32)size;
+ UInt32 processed = filter->Filter(data, cur);
+ /* if (processed > size) (in AES filter), we must fill last block with zeros.
+ but it is not important for benchmark. So we just copy that data without filtering.
+ if (processed == 0) then filter can't process more */
+ if (processed > size || processed == 0)
+ processed = (UInt32)size;
+ if (crc)
+ *crc = CrcUpdate(*crc, data, processed);
+ data += processed;
+ size -= processed;
+ }
+}
+
+
+HRESULT CEncoderInfo::Encode()
+{
+ // printf("\nCEncoderInfo::Generate\n");
+
+ RINOK(Generate())
+
+ // printf("\n2222\n");
+
+ #ifndef Z7_ST
+ if (Common)
+ {
+ Results[0] = S_OK;
+ WRes wres = ReadyEvent.Set();
+ if (wres == 0)
+ wres = Common->StartEvent.Lock();
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ if (Common->ExitMode)
+ return S_OK;
+ }
+ else
+ #endif
+ {
+ CBenchProgressInfo *bpi = progressInfoSpec[0];
+ bpi->SetStartTime();
+ }
+
+
+ CBenchInfo &bi = progressInfoSpec[0]->BenchInfo;
+ bi.UnpackSize = 0;
+ bi.PackSize = 0;
+ CMyComPtr<ICryptoProperties> cp;
+ CMyComPtr<IUnknown> coder;
+ if (_encoderFilter)
+ coder = _encoderFilter;
+ else
+ coder = _encoder;
+ coder.QueryInterface(IID_ICryptoProperties, &cp);
+ CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
+ CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+
+ if (cp)
+ {
+ RINOK(Set_Key_and_IV(cp))
+ }
+
+ compressedSize = 0;
+ if (_encoderFilter)
+ compressedSize = kBufferSize;
+
+ // CBenchmarkOutStream *outStreamSpec = this->outStreamSpec;
+ UInt64 prev = 0;
+
+ const UInt32 mask = (CheckCrc_Enc ? 0 : 0xFFFF);
+ const bool useCrc = (mask < NumIterations);
+ bool crcPrev_defined = false;
+ UInt32 crcPrev = 0;
+
+ bool useRealData_Enc = UseRealData_Enc;
+ bool data_Was_Changed = false;
+ if (useRealData_Enc)
+ {
+ /* we want memcpy() for each iteration including first iteration.
+ So results will be equal for different number of iterations */
+ data_Was_Changed = true;
+ }
+
+ const UInt64 numIterations = NumIterations;
+ UInt64 i = numIterations;
+ // printCallback->NewLine();
+
+ while (i != 0)
+ {
+ i--;
+ if (printCallback && bi.UnpackSize - prev >= (1 << 26))
+ {
+ prev = bi.UnpackSize;
+ RINOK(printCallback->CheckBreak())
+ }
+
+ /*
+ CBenchInfo info;
+ progressInfoSpec[0]->SetStartTime();
+ */
+
+ bool calcCrc = false;
+ if (useCrc)
+ calcCrc = (((UInt32)i & mask) == 0);
+
+ if (_encoderFilter)
+ {
+ Byte *filterData = rgCopy;
+ if (i == numIterations - 1 || calcCrc || useRealData_Enc)
+ {
+ filterData = (Byte *)*outStreamSpec;
+ if (data_Was_Changed)
+ memcpy(filterData, uncompressedDataPtr, kBufferSize);
+ data_Was_Changed = true;
+ }
+ _encoderFilter->Init();
+ if (calcCrc)
+ outStreamSpec->InitCrc();
+ My_FilterBench(_encoderFilter, filterData, kBufferSize,
+ calcCrc ? &outStreamSpec->Crc : NULL);
+ }
+ else
+ {
+ outStreamSpec->Init(true, calcCrc); // write real data for speed consistency at any number of iterations
+ inStreamSpec->Init(uncompressedDataPtr, kBufferSize);
+ RINOK(_encoder->Code(inStream, outStream, NULL, NULL, progressInfo[0]))
+ if (!inStreamSpec->WasFinished())
+ return E_FAIL;
+ if (compressedSize != outStreamSpec->Pos)
+ {
+ if (compressedSize != 0)
+ return E_FAIL;
+ compressedSize = outStreamSpec->Pos;
+ }
+ }
+
+ // outStreamSpec->Print();
+
+ if (calcCrc)
+ {
+ const UInt32 crc2 = CRC_GET_DIGEST(outStreamSpec->Crc);
+ if (crcPrev_defined && crcPrev != crc2)
+ return E_FAIL;
+ crcPrev = crc2;
+ crcPrev_defined = true;
+ }
+
+ bi.UnpackSize += kBufferSize;
+ bi.PackSize += compressedSize;
+
+ /*
+ {
+ progressInfoSpec[0]->SetFinishTime(info);
+ info.UnpackSize = 0;
+ info.PackSize = 0;
+ info.NumIterations = 1;
+
+ info.UnpackSize = kBufferSize;
+ info.PackSize = compressedSize;
+ // printf("\n%7d\n", encoder.compressedSize);
+
+ RINOK(callback->SetEncodeResult(info, true))
+ printCallback->NewLine();
+ }
+ */
+
+ }
+
+ _encoder.Release();
+ _encoderFilter.Release();
+ return S_OK;
+}
+
+
+HRESULT CEncoderInfo::Decode(UInt32 decoderIndex)
+{
+ CBenchmarkInStream *inStreamSpec = new CBenchmarkInStream;
+ CMyComPtr<ISequentialInStream> inStream = inStreamSpec;
+ CMyComPtr<ICompressCoder> &decoder = _decoders[decoderIndex];
+ CMyComPtr<IUnknown> coder;
+ if (_decoderFilter)
+ {
+ if (decoderIndex != 0)
+ return E_FAIL;
+ coder = _decoderFilter;
+ }
+ else
+ coder = decoder;
+
+ CMyComPtr<ICompressSetDecoderProperties2> setDecProps;
+ coder.QueryInterface(IID_ICompressSetDecoderProperties2, &setDecProps);
+ if (!setDecProps && propStreamSpec->GetPos() != 0)
+ return E_FAIL;
+
+ CCrcOutStream *crcOutStreamSpec = new CCrcOutStream;
+ CMyComPtr<ISequentialOutStream> crcOutStream = crcOutStreamSpec;
+
+ CBenchProgressInfo *pi = progressInfoSpec[decoderIndex];
+ pi->BenchInfo.UnpackSize = 0;
+ pi->BenchInfo.PackSize = 0;
+
+ #ifndef Z7_ST
+ {
+ CMyComPtr<ICompressSetCoderMt> setCoderMt;
+ coder.QueryInterface(IID_ICompressSetCoderMt, &setCoderMt);
+ if (setCoderMt)
+ {
+ RINOK(setCoderMt->SetNumberOfThreads(NumDecoderSubThreads))
+ }
+ }
+ #endif
+
+ CMyComPtr<ICompressSetCoderProperties> scp;
+ coder.QueryInterface(IID_ICompressSetCoderProperties, &scp);
+ if (scp)
+ {
+ const UInt64 reduceSize = _uncompressedDataSize;
+ RINOK(_method.SetCoderProps(scp, &reduceSize))
+ }
+
+ CMyComPtr<ICryptoProperties> cp;
+ coder.QueryInterface(IID_ICryptoProperties, &cp);
+
+ if (setDecProps)
+ {
+ RINOK(setDecProps->SetDecoderProperties2(
+ /* (const Byte *)*propStreamSpec, */
+ propsData,
+ (UInt32)propStreamSpec->GetPos()))
+ }
+
+ {
+ CMyComPtr<ICryptoSetPassword> sp;
+ coder.QueryInterface(IID_ICryptoSetPassword, &sp);
+ if (sp)
+ {
+ RINOK(sp->CryptoSetPassword(_psw, sizeof(_psw)))
+ }
+ }
+
+ UInt64 prev = 0;
+
+ if (cp)
+ {
+ RINOK(Set_Key_and_IV(cp))
+ }
+
+ CMyComPtr<ICompressSetFinishMode> setFinishMode;
+
+ if (_decoderFilter)
+ {
+ if (compressedSize > rgCopy.Size())
+ return E_FAIL;
+ }
+ else
+ {
+ decoder->QueryInterface(IID_ICompressSetFinishMode, (void **)&setFinishMode);
+ }
+
+ const UInt64 numIterations = NumIterations;
+ const E_CheckCrcMode checkCrcMode = CheckCrcMode_Dec;
+
+ for (UInt64 i = 0; i < numIterations; i++)
+ {
+ if (printCallback && pi->BenchInfo.UnpackSize - prev >= (1 << 26))
+ {
+ RINOK(printCallback->CheckBreak())
+ prev = pi->BenchInfo.UnpackSize;
+ }
+
+ const UInt64 outSize = kBufferSize;
+ bool calcCrc = (checkCrcMode != k_CheckCrcMode_Never);
+
+ crcOutStreamSpec->Init();
+
+ if (_decoderFilter)
+ {
+ Byte *filterData = (Byte *)*outStreamSpec;
+ if (calcCrc)
+ {
+ calcCrc = (i == 0);
+ if (checkCrcMode == k_CheckCrcMode_Always)
+ {
+ calcCrc = true;
+ memcpy((Byte *)rgCopy, (const Byte *)*outStreamSpec, compressedSize);
+ filterData = rgCopy;
+ }
+ }
+ _decoderFilter->Init();
+ My_FilterBench(_decoderFilter, filterData, compressedSize,
+ calcCrc ? &crcOutStreamSpec->Crc : NULL);
+ }
+ else
+ {
+ crcOutStreamSpec->CalcCrc = calcCrc;
+ inStreamSpec->Init((const Byte *)*outStreamSpec, compressedSize);
+
+ if (setFinishMode)
+ {
+ RINOK(setFinishMode->SetFinishMode(BoolToUInt(true)))
+ }
+
+ RINOK(decoder->Code(inStream, crcOutStream, NULL, &outSize, progressInfo[decoderIndex]))
+
+ if (setFinishMode)
+ {
+ if (!inStreamSpec->WasFinished())
+ return S_FALSE;
+
+ CMyComPtr<ICompressGetInStreamProcessedSize> getInStreamProcessedSize;
+ decoder.QueryInterface(IID_ICompressGetInStreamProcessedSize, (void **)&getInStreamProcessedSize);
+
+ if (getInStreamProcessedSize)
+ {
+ UInt64 processed;
+ RINOK(getInStreamProcessedSize->GetInStreamProcessedSize(&processed))
+ if (processed != compressedSize)
+ return S_FALSE;
+ }
+ }
+
+ if (crcOutStreamSpec->Pos != outSize)
+ return S_FALSE;
+ }
+
+ if (calcCrc && CRC_GET_DIGEST(crcOutStreamSpec->Crc) != crc)
+ return S_FALSE;
+
+ pi->BenchInfo.UnpackSize += kBufferSize;
+ pi->BenchInfo.PackSize += compressedSize;
+ }
+
+ decoder.Release();
+ _decoderFilter.Release();
+ return S_OK;
+}
+
+
+static const UInt32 kNumThreadsMax = (1 << 12);
+
+struct CBenchEncoders
+{
+ CEncoderInfo *encoders;
+ CBenchEncoders(UInt32 num): encoders(NULL) { encoders = new CEncoderInfo[num]; }
+ ~CBenchEncoders() { delete []encoders; }
+};
+
+
+static UInt64 GetNumIterations(UInt64 numCommands, UInt64 complexInCommands)
+{
+ if (numCommands < (1 << 4))
+ numCommands = (1 << 4);
+ UInt64 res = complexInCommands / numCommands;
+ return (res == 0 ? 1 : res);
+}
+
+
+
+#ifndef Z7_ST
+
+// ---------- CBenchThreadsFlusher ----------
+
+struct CBenchThreadsFlusher
+{
+ CBenchEncoders *EncodersSpec;
+ CBenchSyncCommon Common;
+ unsigned NumThreads;
+ bool NeedClose;
+
+ CBenchThreadsFlusher(): NumThreads(0), NeedClose(false) {}
+
+ ~CBenchThreadsFlusher()
+ {
+ StartAndWait(true);
+ }
+
+ WRes StartAndWait(bool exitMode = false);
+};
+
+
+WRes CBenchThreadsFlusher::StartAndWait(bool exitMode)
+{
+ if (!NeedClose)
+ return 0;
+
+ Common.ExitMode = exitMode;
+ WRes res = Common.StartEvent.Set();
+
+ for (unsigned i = 0; i < NumThreads; i++)
+ {
+ NWindows::CThread &t = EncodersSpec->encoders[i].thread[0];
+ if (t.IsCreated())
+ {
+ WRes res2 = t.Wait_Close();
+ if (res == 0)
+ res = res2;
+ }
+ }
+ NeedClose = false;
+ return res;
+}
+
+#endif // Z7_ST
+
+
+
+static void SetPseudoRand(Byte *data, size_t size, UInt32 startValue)
+{
+ for (size_t i = 0; i < size; i++)
+ {
+ data[i] = (Byte)startValue;
+ startValue++;
+ }
+}
+
+
+
+static HRESULT MethodBench(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ UInt64 complexInCommands,
+ #ifndef Z7_ST
+ bool oldLzmaBenchMode,
+ UInt32 numThreads,
+ const CAffinityMode *affinityMode,
+ #endif
+ const COneMethodInfo &method2,
+ size_t uncompressedDataSize,
+ const Byte *fileData,
+ unsigned generateDictBits,
+
+ IBenchPrintCallback *printCallback,
+ IBenchCallback *callback,
+ CBenchProps *benchProps)
+{
+ COneMethodInfo method = method2;
+ UInt64 methodId;
+ UInt32 numStreams;
+ bool isFilter;
+ const int codecIndex = FindMethod_Index(
+ EXTERNAL_CODECS_LOC_VARS
+ method.MethodName, true,
+ methodId, numStreams, isFilter);
+ if (codecIndex < 0)
+ return E_NOTIMPL;
+ if (numStreams != 1)
+ return E_INVALIDARG;
+
+ UInt32 numEncoderThreads = 1;
+ UInt32 numSubDecoderThreads = 1;
+
+ #ifndef Z7_ST
+ numEncoderThreads = numThreads;
+
+ if (oldLzmaBenchMode)
+ if (methodId == k_LZMA)
+ {
+ if (numThreads == 1 && method.Get_NumThreads() < 0)
+ method.AddProp_NumThreads(1);
+ const UInt32 numLzmaThreads = method.Get_Lzma_NumThreads();
+ if (numThreads > 1 && numLzmaThreads > 1)
+ {
+ numEncoderThreads = (numThreads + 1) / 2; // 20.03
+ numSubDecoderThreads = 2;
+ }
+ }
+
+ const bool mtEncMode = (numEncoderThreads > 1) || affinityMode->NeedAffinity();
+
+ #endif
+
+ CBenchEncoders encodersSpec(numEncoderThreads);
+ CEncoderInfo *encoders = encodersSpec.encoders;
+
+ UInt32 i;
+
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ encoder.callback = (i == 0) ? callback : NULL;
+ encoder.printCallback = printCallback;
+
+ #ifndef Z7_ST
+ encoder.EncoderIndex = i;
+ encoder.NumEncoderInternalThreads = numSubDecoderThreads;
+ encoder.AffinityMode = *affinityMode;
+
+ /*
+ if (numSubDecoderThreads > 1)
+ if (encoder.AffinityMode.NeedAffinity()
+ && encoder.AffinityMode.NumBundleThreads == 1)
+ {
+ // if old LZMA benchmark uses two threads in coder, we increase (NumBundleThreads) for old LZMA benchmark uses two threads instead of one
+ if (encoder.AffinityMode.NumBundleThreads * 2 <= encoder.AffinityMode.NumCores)
+ encoder.AffinityMode.NumBundleThreads *= 2;
+ }
+ */
+
+ #endif
+
+ {
+ CCreatedCoder cod;
+ RINOK(CreateCoder_Index(EXTERNAL_CODECS_LOC_VARS (unsigned)codecIndex, true, encoder._encoderFilter, cod))
+ encoder._encoder = cod.Coder;
+ if (!encoder._encoder && !encoder._encoderFilter)
+ return E_NOTIMPL;
+ }
+
+ SetPseudoRand(encoder._iv, sizeof(encoder._iv), 17);
+ SetPseudoRand(encoder._key, sizeof(encoder._key), 51);
+ SetPseudoRand(encoder._psw, sizeof(encoder._psw), 123);
+
+ for (UInt32 j = 0; j < numSubDecoderThreads; j++)
+ {
+ CCreatedCoder cod;
+ CMyComPtr<ICompressCoder> &decoder = encoder._decoders[j];
+ RINOK(CreateCoder_Id(EXTERNAL_CODECS_LOC_VARS methodId, false, encoder._decoderFilter, cod))
+ decoder = cod.Coder;
+ if (!encoder._decoderFilter && !decoder)
+ return E_NOTIMPL;
+ }
+
+ encoder.UseRealData_Enc =
+ encoder.CheckCrc_Enc = (benchProps->EncComplex) > 30;
+
+ encoder.CheckCrcMode_Dec = k_CheckCrcMode_Always;
+ if (benchProps->DecComplexCompr +
+ benchProps->DecComplexUnc <= 30)
+ encoder.CheckCrcMode_Dec =
+ k_CheckCrcMode_FirstPass; // for filters
+ // k_CheckCrcMode_Never; // for debug
+ // k_CheckCrcMode_Always; // for debug
+ if (fileData)
+ {
+ encoder.UseRealData_Enc = true;
+ encoder.CheckCrcMode_Dec = k_CheckCrcMode_Always;
+ }
+ }
+
+ UInt32 crc = 0;
+ if (fileData)
+ crc = CrcCalc(fileData, uncompressedDataSize);
+
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ encoder._method = method;
+ encoder.generateDictBits = generateDictBits;
+ encoder._uncompressedDataSize = uncompressedDataSize;
+ encoder.kBufferSize = uncompressedDataSize;
+ encoder.fileData = fileData;
+ encoder.crc = crc;
+ }
+
+ CBenchProgressStatus status;
+ status.Res = S_OK;
+ status.EncodeMode = true;
+
+ #ifndef Z7_ST
+ CBenchThreadsFlusher encoderFlusher;
+ if (mtEncMode)
+ {
+ WRes wres = encoderFlusher.Common.StartEvent.Create();
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ encoderFlusher.NumThreads = numEncoderThreads;
+ encoderFlusher.EncodersSpec = &encodersSpec;
+ encoderFlusher.NeedClose = true;
+ }
+ #endif
+
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ encoder.NumIterations = GetNumIterations(benchProps->GetNumCommands_Enc(uncompressedDataSize), complexInCommands);
+ // encoder.NumIterations = 3;
+ encoder.Salt = g_CrcTable[i & 0xFF];
+ encoder.Salt ^= (g_CrcTable[(i >> 8) & 0xFF] << 3);
+ // (g_CrcTable[0] == 0), and (encoder.Salt == 0) for first thread
+ // printf(" %8x", encoder.Salt);
+
+ encoder.KeySize = benchProps->KeySize;
+
+ for (int j = 0; j < 2; j++)
+ {
+ CBenchProgressInfo *spec = new CBenchProgressInfo;
+ encoder.progressInfoSpec[j] = spec;
+ encoder.progressInfo[j] = spec;
+ spec->Status = &status;
+ }
+
+ if (i == 0)
+ {
+ CBenchProgressInfo *bpi = encoder.progressInfoSpec[0];
+ bpi->Callback = callback;
+ bpi->BenchInfo.NumIterations = numEncoderThreads;
+ }
+
+ #ifndef Z7_ST
+ if (mtEncMode)
+ {
+ #ifdef USE_ALLOCA
+ encoder.AllocaSize = (i * 16 * 21) & 0x7FF;
+ #endif
+
+ encoder.Common = &encoderFlusher.Common;
+ encoder.IsGlobalMtMode = numEncoderThreads > 1;
+ RINOK(encoder.CreateEncoderThread())
+ }
+ #endif
+ }
+
+ if (printCallback)
+ {
+ RINOK(printCallback->CheckBreak())
+ }
+
+ #ifndef Z7_ST
+ if (mtEncMode)
+ {
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ const WRes wres = encoder.ReadyEvent.Lock();
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ RINOK(encoder.Results[0])
+ }
+
+ CBenchProgressInfo *bpi = encoders[0].progressInfoSpec[0];
+ bpi->SetStartTime();
+
+ const WRes wres = encoderFlusher.StartAndWait();
+ if (status.Res == 0 && wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ }
+ else
+ #endif
+ {
+ RINOK(encoders[0].Encode())
+ }
+
+ RINOK(status.Res)
+
+ CBenchInfo info;
+
+ encoders[0].progressInfoSpec[0]->SetFinishTime(info);
+ info.UnpackSize = 0;
+ info.PackSize = 0;
+ info.NumIterations = encoders[0].NumIterations;
+
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ const CEncoderInfo &encoder = encoders[i];
+ info.UnpackSize += encoder.kBufferSize;
+ info.PackSize += encoder.compressedSize;
+ // printf("\n%7d\n", encoder.compressedSize);
+ }
+
+ RINOK(callback->SetEncodeResult(info, true))
+
+
+
+
+ // ---------- Decode ----------
+
+ status.Res = S_OK;
+ status.EncodeMode = false;
+
+ const UInt32 numDecoderThreads = numEncoderThreads * numSubDecoderThreads;
+ #ifndef Z7_ST
+ const bool mtDecoderMode = (numDecoderThreads > 1) || affinityMode->NeedAffinity();
+ #endif
+
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+
+ /*
+ #ifndef Z7_ST
+ // encoder.affinityMode = *affinityMode;
+ if (encoder.NumEncoderInternalThreads != 1)
+ encoder.AffinityMode.DivideNum = encoder.NumEncoderInternalThreads;
+ #endif
+ */
+
+
+ if (i == 0)
+ {
+ encoder.NumIterations = GetNumIterations(
+ benchProps->GetNumCommands_Dec(
+ encoder.compressedSize,
+ encoder.kBufferSize),
+ complexInCommands);
+ CBenchProgressInfo *bpi = encoder.progressInfoSpec[0];
+ bpi->Callback = callback;
+ bpi->BenchInfo.NumIterations = numDecoderThreads;
+ bpi->SetStartTime();
+ }
+ else
+ encoder.NumIterations = encoders[0].NumIterations;
+
+ #ifndef Z7_ST
+ {
+ int numSubThreads = method.Get_NumThreads();
+ encoder.NumDecoderSubThreads = (numSubThreads <= 0) ? 1 : (unsigned)numSubThreads;
+ }
+ if (mtDecoderMode)
+ {
+ for (UInt32 j = 0; j < numSubDecoderThreads; j++)
+ {
+ const HRESULT res = encoder.CreateDecoderThread(j, (i == 0 && j == 0)
+ #ifdef USE_ALLOCA
+ , ((i * numSubDecoderThreads + j) * 16 * 21) & 0x7FF
+ #endif
+ );
+ RINOK(res)
+ }
+ }
+ else
+ #endif
+ {
+ RINOK(encoder.Decode(0))
+ }
+ }
+
+ #ifndef Z7_ST
+ if (mtDecoderMode)
+ {
+ WRes wres = 0;
+ HRESULT res = S_OK;
+ for (i = 0; i < numEncoderThreads; i++)
+ for (UInt32 j = 0; j < numSubDecoderThreads; j++)
+ {
+ CEncoderInfo &encoder = encoders[i];
+ const WRes wres2 = encoder.thread[j].
+ // Wait(); // later we can get thread times from thread in UNDER_CE
+ Wait_Close();
+ if (wres == 0 && wres2 != 0)
+ wres = wres2;
+ const HRESULT res2 = encoder.Results[j];
+ if (res == 0 && res2 != 0)
+ res = res2;
+ }
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ RINOK(res)
+ }
+ #endif // Z7_ST
+
+ RINOK(status.Res)
+ encoders[0].progressInfoSpec[0]->SetFinishTime(info);
+
+ /*
+ #ifndef Z7_ST
+ #ifdef UNDER_CE
+ if (mtDecoderMode)
+ for (i = 0; i < numEncoderThreads; i++)
+ for (UInt32 j = 0; j < numSubDecoderThreads; j++)
+ {
+ FILETIME creationTime, exitTime, kernelTime, userTime;
+ if (::GetThreadTimes(encoders[i].thread[j], &creationTime, &exitTime, &kernelTime, &userTime) != 0)
+ info.UserTime += GetTime64(userTime) + GetTime64(kernelTime);
+ }
+ #endif
+ #endif
+ */
+
+ info.UnpackSize = 0;
+ info.PackSize = 0;
+ info.NumIterations = numSubDecoderThreads * encoders[0].NumIterations;
+
+ for (i = 0; i < numEncoderThreads; i++)
+ {
+ const CEncoderInfo &encoder = encoders[i];
+ info.UnpackSize += encoder.kBufferSize;
+ info.PackSize += encoder.compressedSize;
+ }
+
+ // RINOK(callback->SetDecodeResult(info, false)) // why we called before 21.03 ??
+ RINOK(callback->SetDecodeResult(info, true))
+
+ return S_OK;
+}
+
+
+
+static inline UInt64 GetDictSizeFromLog(unsigned dictSizeLog)
+{
+ /*
+ if (dictSizeLog < 32)
+ return (UInt32)1 << dictSizeLog;
+ else
+ return (UInt32)(Int32)-1;
+ */
+ return (UInt64)1 << dictSizeLog;
+}
+
+
+// it's limit of current LZMA implementation that can be changed later
+#define kLzmaMaxDictSize ((UInt32)15 << 28)
+
+static inline UInt64 GetLZMAUsage(bool multiThread, int btMode, UInt64 dict)
+{
+ if (dict == 0)
+ dict = 1;
+ if (dict > kLzmaMaxDictSize)
+ dict = kLzmaMaxDictSize;
+ UInt32 hs = (UInt32)dict - 1;
+ hs |= (hs >> 1);
+ hs |= (hs >> 2);
+ hs |= (hs >> 4);
+ hs |= (hs >> 8);
+ hs >>= 1;
+ hs |= 0xFFFF;
+ if (hs > (1 << 24))
+ hs >>= 1;
+ hs++;
+ hs += (1 << 16);
+
+ const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)(1 << 16);
+ UInt64 blockSize = (UInt64)dict + (1 << 16)
+ + (multiThread ? (1 << 20) : 0);
+ blockSize += (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2));
+ if (blockSize >= kBlockSizeMax)
+ blockSize = kBlockSizeMax;
+
+ UInt64 son = (UInt64)dict;
+ if (btMode)
+ son *= 2;
+ const UInt64 v = (hs + son) * 4 + blockSize +
+ (1 << 20) + (multiThread ? (6 << 20) : 0);
+
+ // printf("\nGetLZMAUsage = %d\n", (UInt32)(v >> 20));
+ // printf("\nblockSize = %d\n", (UInt32)(blockSize >> 20));
+ return v;
+}
+
+
+UInt64 GetBenchMemoryUsage(UInt32 numThreads, int level, UInt64 dictionary, bool totalBench)
+{
+ const size_t kBufferSize = (size_t)dictionary + kAdditionalSize;
+ const UInt64 kCompressedBufferSize = GetBenchCompressedSize(kBufferSize); // / 2;
+ if (level < 0)
+ level = 5;
+ const int algo = (level < 5 ? 0 : 1);
+ const int btMode = (algo == 0 ? 0 : 1);
+
+ UInt32 numBigThreads = numThreads;
+ bool lzmaMt = (totalBench || (numThreads > 1 && btMode));
+ if (btMode)
+ {
+ if (!totalBench && lzmaMt)
+ numBigThreads /= 2;
+ }
+ return ((UInt64)kBufferSize + kCompressedBufferSize +
+ GetLZMAUsage(lzmaMt, btMode, dictionary) + (2 << 20)) * numBigThreads;
+}
+
+static UInt64 GetBenchMemoryUsage_Hash(UInt32 numThreads, UInt64 dictionary)
+{
+ // dictionary += (dictionary >> 9); // for page tables (virtual memory)
+ return (UInt64)(dictionary + (1 << 15)) * numThreads + (2 << 20);
+}
+
+
+// ---------- CRC and HASH ----------
+
+struct CCrcInfo_Base
+{
+ CMidAlignedBuffer Buffer;
+ const Byte *Data;
+ size_t Size;
+ bool CreateLocalBuf;
+ UInt32 CheckSum_Res;
+
+ CCrcInfo_Base(): CreateLocalBuf(true), CheckSum_Res(0) {}
+
+ HRESULT Generate(const Byte *data, size_t size);
+ HRESULT CrcProcess(UInt64 numIterations,
+ const UInt32 *checkSum, IHasher *hf,
+ IBenchPrintCallback *callback);
+};
+
+
+HRESULT CCrcInfo_Base::Generate(const Byte *data, size_t size)
+{
+ Size = size;
+ Data = data;
+ if (!data || CreateLocalBuf)
+ {
+ ALLOC_WITH_HRESULT(&Buffer, size)
+ Data = Buffer;
+ }
+ if (!data)
+ RandGen(Buffer, size);
+ else if (CreateLocalBuf && size != 0)
+ memcpy(Buffer, data, size);
+ return S_OK;
+}
+
+
+HRESULT CCrcInfo_Base::CrcProcess(UInt64 numIterations,
+ const UInt32 *checkSum, IHasher *hf,
+ IBenchPrintCallback *callback)
+{
+ MY_ALIGN(16)
+ Byte hash[64];
+ memset(hash, 0, sizeof(hash));
+
+ CheckSum_Res = 0;
+
+ const UInt32 hashSize = hf->GetDigestSize();
+ if (hashSize > sizeof(hash))
+ return S_FALSE;
+
+ const Byte *buf = Data;
+ const size_t size = Size;
+ UInt32 checkSum_Prev = 0;
+
+ UInt64 prev = 0;
+ UInt64 cur = 0;
+
+ for (UInt64 i = 0; i < numIterations; i++)
+ {
+ hf->Init();
+ size_t pos = 0;
+ do
+ {
+ const size_t rem = size - pos;
+ const UInt32 kStep = ((UInt32)1 << 31);
+ const UInt32 curSize = (rem < kStep) ? (UInt32)rem : kStep;
+ hf->Update(buf + pos, curSize);
+ pos += curSize;
+ }
+ while (pos != size);
+
+ hf->Final(hash);
+ UInt32 sum = 0;
+ for (UInt32 j = 0; j < hashSize; j += 4)
+ {
+ sum = rotlFixed(sum, 11);
+ sum += GetUi32(hash + j);
+ }
+ if (checkSum)
+ {
+ if (sum != *checkSum)
+ return S_FALSE;
+ }
+ else
+ {
+ checkSum_Prev = sum;
+ checkSum = &checkSum_Prev;
+ }
+ if (callback)
+ {
+ cur += size;
+ if (cur - prev >= ((UInt32)1 << 30))
+ {
+ prev = cur;
+ RINOK(callback->CheckBreak())
+ }
+ }
+ }
+ CheckSum_Res = checkSum_Prev;
+ return S_OK;
+}
+
+extern
+UInt32 g_BenchCpuFreqTemp; // we need non-static variavble to disable compiler optimization
+UInt32 g_BenchCpuFreqTemp = 1;
+
+#define YY1 sum += val; sum ^= val;
+#define YY3 YY1 YY1 YY1 YY1
+#define YY5 YY3 YY3 YY3 YY3
+#define YY7 YY5 YY5 YY5 YY5
+static const UInt32 kNumFreqCommands = 128;
+
+EXTERN_C_BEGIN
+
+static UInt32 CountCpuFreq(UInt32 sum, UInt32 num, UInt32 val)
+{
+ for (UInt32 i = 0; i < num; i++)
+ {
+ YY7
+ }
+ return sum;
+}
+
+EXTERN_C_END
+
+
+#ifndef Z7_ST
+
+struct CBaseThreadInfo
+{
+ NWindows::CThread Thread;
+ IBenchPrintCallback *Callback;
+ HRESULT CallbackRes;
+
+ WRes Wait_If_Created()
+ {
+ if (!Thread.IsCreated())
+ return 0;
+ return Thread.Wait_Close();
+ }
+};
+
+struct CFreqInfo: public CBaseThreadInfo
+{
+ UInt32 ValRes;
+ UInt32 Size;
+ UInt64 NumIterations;
+};
+
+static THREAD_FUNC_DECL FreqThreadFunction(void *param)
+{
+ CFreqInfo *p = (CFreqInfo *)param;
+
+ UInt32 sum = g_BenchCpuFreqTemp;
+ for (UInt64 k = p->NumIterations; k > 0; k--)
+ {
+ if (p->Callback)
+ {
+ p->CallbackRes = p->Callback->CheckBreak();
+ if (p->CallbackRes != S_OK)
+ break;
+ }
+ sum = CountCpuFreq(sum, p->Size, g_BenchCpuFreqTemp);
+ }
+ p->ValRes = sum;
+ return THREAD_FUNC_RET_ZERO;
+}
+
+struct CFreqThreads
+{
+ CFreqInfo *Items;
+ UInt32 NumThreads;
+
+ CFreqThreads(): Items(NULL), NumThreads(0) {}
+
+ WRes WaitAll()
+ {
+ WRes wres = 0;
+ for (UInt32 i = 0; i < NumThreads; i++)
+ {
+ WRes wres2 = Items[i].Wait_If_Created();
+ if (wres == 0 && wres2 != 0)
+ wres = wres2;
+ }
+ NumThreads = 0;
+ return wres;
+ }
+
+ ~CFreqThreads()
+ {
+ WaitAll();
+ delete []Items;
+ }
+};
+
+
+static THREAD_FUNC_DECL CrcThreadFunction(void *param);
+
+struct CCrcInfo: public CBaseThreadInfo
+{
+ const Byte *Data;
+ size_t Size;
+ UInt64 NumIterations;
+ bool CheckSumDefined;
+ UInt32 CheckSum;
+ CMyComPtr<IHasher> Hasher;
+ HRESULT Res;
+ UInt32 CheckSum_Res;
+
+ #ifndef Z7_ST
+ NSynchronization::CManualResetEvent ReadyEvent;
+ UInt32 ThreadIndex;
+ CBenchSyncCommon *Common;
+ CAffinityMode AffinityMode;
+ #endif
+
+ // we want to call CCrcInfo_Base::Buffer.Free() in main thread.
+ // so we uses non-local CCrcInfo_Base.
+ CCrcInfo_Base crcib;
+
+ HRESULT CreateThread()
+ {
+ WRes res = 0;
+ if (!ReadyEvent.IsCreated())
+ res = ReadyEvent.Create();
+ if (res == 0)
+ res = AffinityMode.CreateThread_WithAffinity(Thread, CrcThreadFunction, this,
+ ThreadIndex);
+ return HRESULT_FROM_WIN32(res);
+ }
+
+ #ifdef USE_ALLOCA
+ size_t AllocaSize;
+ #endif
+
+ void Process();
+
+ CCrcInfo(): Res(E_FAIL) {}
+};
+
+static const bool k_Crc_CreateLocalBuf_For_File = true; // for total BW test
+// static const bool k_Crc_CreateLocalBuf_For_File = false; // for shared memory read test
+
+void CCrcInfo::Process()
+{
+ crcib.CreateLocalBuf = k_Crc_CreateLocalBuf_For_File;
+ // we can use additional Generate() passes to reduce some time effects for new page allocation
+ // for (unsigned y = 0; y < 10; y++)
+ Res = crcib.Generate(Data, Size);
+
+ // if (Common)
+ {
+ WRes wres = ReadyEvent.Set();
+ if (wres != 0)
+ {
+ if (Res == 0)
+ Res = HRESULT_FROM_WIN32(wres);
+ return;
+ }
+ if (Res != 0)
+ return;
+
+ wres = Common->StartEvent.Lock();
+
+ if (wres != 0)
+ {
+ Res = HRESULT_FROM_WIN32(wres);
+ return;
+ }
+ if (Common->ExitMode)
+ return;
+ }
+
+ Res = crcib.CrcProcess(NumIterations,
+ CheckSumDefined ? &CheckSum : NULL, Hasher,
+ Callback);
+ CheckSum_Res = crcib.CheckSum_Res;
+ /*
+ We don't want to include the time of slow CCrcInfo_Base::Buffer.Free()
+ to time of benchmark. So we don't free Buffer here
+ */
+ // crcib.Buffer.Free();
+}
+
+
+static THREAD_FUNC_DECL CrcThreadFunction(void *param)
+{
+ CCrcInfo *p = (CCrcInfo *)param;
+
+ #ifdef USE_ALLOCA
+ alloca(p->AllocaSize);
+ #endif
+ p->Process();
+ return THREAD_FUNC_RET_ZERO;
+}
+
+
+struct CCrcThreads
+{
+ CCrcInfo *Items;
+ unsigned NumThreads;
+ CBenchSyncCommon Common;
+ bool NeedClose;
+
+ CCrcThreads(): Items(NULL), NumThreads(0), NeedClose(false) {}
+
+ WRes StartAndWait(bool exitMode = false);
+
+ ~CCrcThreads()
+ {
+ StartAndWait(true);
+ delete []Items;
+ }
+};
+
+
+WRes CCrcThreads::StartAndWait(bool exitMode)
+{
+ if (!NeedClose)
+ return 0;
+
+ Common.ExitMode = exitMode;
+ WRes wres = Common.StartEvent.Set();
+
+ for (unsigned i = 0; i < NumThreads; i++)
+ {
+ WRes wres2 = Items[i].Wait_If_Created();
+ if (wres == 0 && wres2 != 0)
+ wres = wres2;
+ }
+ NumThreads = 0;
+ NeedClose = false;
+ return wres;
+}
+
+#endif
+
+
+static UInt32 CrcCalc1(const Byte *buf, size_t size)
+{
+ UInt32 crc = CRC_INIT_VAL;
+ for (size_t i = 0; i < size; i++)
+ crc = CRC_UPDATE_BYTE(crc, buf[i]);
+ return CRC_GET_DIGEST(crc);
+}
+
+/*
+static UInt32 RandGenCrc(Byte *buf, size_t size, CBaseRandomGenerator &RG)
+{
+ RandGen(buf, size, RG);
+ return CrcCalc1(buf, size);
+}
+*/
+
+static bool CrcInternalTest()
+{
+ CAlignedBuffer buffer;
+ const size_t kBufferSize0 = (1 << 8);
+ const size_t kBufferSize1 = (1 << 10);
+ const unsigned kCheckSize = (1 << 5);
+ buffer.Alloc(kBufferSize0 + kBufferSize1);
+ if (!buffer.IsAllocated())
+ return false;
+ Byte *buf = (Byte *)buffer;
+ size_t i;
+ for (i = 0; i < kBufferSize0; i++)
+ buf[i] = (Byte)i;
+ UInt32 crc1 = CrcCalc1(buf, kBufferSize0);
+ if (crc1 != 0x29058C73)
+ return false;
+ RandGen(buf + kBufferSize0, kBufferSize1);
+ for (i = 0; i < kBufferSize0 + kBufferSize1 - kCheckSize; i++)
+ for (unsigned j = 0; j < kCheckSize; j++)
+ if (CrcCalc1(buf + i, j) != CrcCalc(buf + i, j))
+ return false;
+ return true;
+}
+
+struct CBenchMethod
+{
+ unsigned Weight;
+ unsigned DictBits;
+ Int32 EncComplex;
+ Int32 DecComplexCompr;
+ Int32 DecComplexUnc;
+ const char *Name;
+ // unsigned KeySize;
+};
+
+// #define USE_SW_CMPLX
+
+#ifdef USE_SW_CMPLX
+#define CMPLX(x) ((x) * 1000)
+#else
+#define CMPLX(x) (x)
+#endif
+
+static const CBenchMethod g_Bench[] =
+{
+ // { 40, 17, 357, 145, 20, "LZMA:x1" },
+ // { 20, 18, 360, 145, 20, "LZMA2:x1:mt2" },
+
+ { 20, 18, 360, 145, 20, "LZMA:x1" },
+ { 20, 22, 600, 145, 20, "LZMA:x3" },
+
+ { 80, 24, 1220, 145, 20, "LZMA:x5:mt1" },
+ { 80, 24, 1220, 145, 20, "LZMA:x5:mt2" },
+
+ { 10, 16, 124, 40, 14, "Deflate:x1" },
+ { 20, 16, 376, 40, 14, "Deflate:x5" },
+ { 10, 16, 1082, 40, 14, "Deflate:x7" },
+ { 10, 17, 422, 40, 14, "Deflate64:x5" },
+
+ { 10, 15, 590, 69, 69, "BZip2:x1" },
+ { 20, 19, 815, 122, 122, "BZip2:x5" },
+ { 10, 19, 815, 122, 122, "BZip2:x5:mt2" },
+ { 10, 19, 2530, 122, 122, "BZip2:x7" },
+
+ // { 10, 18, 1010, 0, 1150, "PPMDZip:x1" },
+ { 10, 18, 1010, 0, 1150, "PPMD:x1" },
+ // { 10, 22, 1655, 0, 1830, "PPMDZip:x5" },
+ { 10, 22, 1655, 0, 1830, "PPMD:x5" },
+
+ // { 2, 0, -16, 0, -16, "Swap2" },
+ { 2, 0, -16, 0, -16, "Swap4" },
+
+ // { 2, 0, 3, 0, 4, "Delta:1" },
+ // { 2, 0, 3, 0, 4, "Delta:2" },
+ // { 2, 0, 3, 0, 4, "Delta:3" },
+ { 2, 0, 3, 0, 4, "Delta:4" },
+ // { 2, 0, 3, 0, 4, "Delta:8" },
+ // { 2, 0, 3, 0, 4, "Delta:32" },
+
+ { 2, 0, 2, 0, 2, "BCJ" },
+ { 2, 0, 1, 0, 1, "ARM64" },
+
+ // { 10, 0, 18, 0, 18, "AES128CBC:1" },
+ // { 10, 0, 21, 0, 21, "AES192CBC:1" },
+ { 10, 0, 24, 0, 24, "AES256CBC:1" },
+
+ // { 10, 0, 18, 0, 18, "AES128CTR:1" },
+ // { 10, 0, 21, 0, 21, "AES192CTR:1" },
+ // { 10, 0, 24, 0, 24, "AES256CTR:1" },
+ // { 2, 0, CMPLX(6), 0, CMPLX(1), "AES128CBC:2" },
+ // { 2, 0, CMPLX(7), 0, CMPLX(1), "AES192CBC:2" },
+ { 2, 0, CMPLX(8), 0, CMPLX(1), "AES256CBC:2" },
+
+ // { 2, 0, CMPLX(1), 0, CMPLX(1), "AES128CTR:2" },
+ // { 2, 0, CMPLX(1), 0, CMPLX(1), "AES192CTR:2" },
+ // { 2, 0, CMPLX(1), 0, CMPLX(1), "AES256CTR:2" },
+
+ // { 1, 0, CMPLX(6), 0, CMPLX(1), "AES128CBC:3" },
+ // { 1, 0, CMPLX(7), 0, CMPLX(1), "AES192CBC:3" },
+ { 1, 0, CMPLX(8), 0, CMPLX(1), "AES256CBC:3" }
+
+ // { 1, 0, CMPLX(1), 0, CMPLX(1), "AES128CTR:3" },
+ // { 1, 0, CMPLX(1), 0, CMPLX(1), "AES192CTR:3" },
+ // { 1, 0, CMPLX(1), 0, CMPLX(1), "AES256CTR:3" },
+};
+
+struct CBenchHash
+{
+ unsigned Weight;
+ UInt32 Complex;
+ UInt32 CheckSum;
+ const char *Name;
+};
+
+// #define ARM_CRC_MUL 100
+#define ARM_CRC_MUL 1
+
+#define k_Hash_Complex_Mult 256
+
+static const CBenchHash g_Hash[] =
+{
+ // { 1, 1820, 0x21e207bb, "CRC32:1" },
+ // { 10, 558, 0x21e207bb, "CRC32:4" },
+ { 20, 339, 0x21e207bb, "CRC32:8" } ,
+ { 2, 128 *ARM_CRC_MUL, 0x21e207bb, "CRC32:32" },
+ { 2, 64 *ARM_CRC_MUL, 0x21e207bb, "CRC32:64" },
+ { 10, 512, 0x41b901d1, "CRC64" },
+
+ { 10, 5100, 0x7913ba03, "SHA256:1" },
+ { 2, CMPLX((32 * 4 + 1) * 4 + 4), 0x7913ba03, "SHA256:2" },
+
+ { 10, 2340, 0xff769021, "SHA1:1" },
+ { 2, CMPLX((20 * 6 + 1) * 4 + 4), 0xff769021, "SHA1:2" },
+
+ { 2, 5500, 0x85189d02, "BLAKE2sp" }
+};
+
+static void PrintNumber(IBenchPrintCallback &f, UInt64 value, unsigned size)
+{
+ char s[128];
+ unsigned startPos = (unsigned)sizeof(s) - 32;
+ memset(s, ' ', startPos);
+ ConvertUInt64ToString(value, s + startPos);
+ // if (withSpace)
+ {
+ startPos--;
+ size++;
+ }
+ unsigned len = (unsigned)strlen(s + startPos);
+ if (size > len)
+ {
+ size -= len;
+ if (startPos < size)
+ startPos = 0;
+ else
+ startPos -= size;
+ }
+ f.Print(s + startPos);
+}
+
+static const unsigned kFieldSize_Name = 12;
+static const unsigned kFieldSize_SmallName = 4;
+static const unsigned kFieldSize_Speed = 9;
+static const unsigned kFieldSize_Usage = 5;
+static const unsigned kFieldSize_RU = 6;
+static const unsigned kFieldSize_Rating = 6;
+static const unsigned kFieldSize_EU = 5;
+static const unsigned kFieldSize_Effec = 5;
+static const unsigned kFieldSize_CrcSpeed = 8;
+
+
+static const unsigned kFieldSize_TotalSize = 4 + kFieldSize_Speed + kFieldSize_Usage + kFieldSize_RU + kFieldSize_Rating;
+static const unsigned kFieldSize_EUAndEffec = 2 + kFieldSize_EU + kFieldSize_Effec;
+
+
+static void PrintRating(IBenchPrintCallback &f, UInt64 rating, unsigned size)
+{
+ PrintNumber(f, (rating + 500000) / 1000000, size);
+}
+
+
+static void PrintPercents(IBenchPrintCallback &f, UInt64 val, UInt64 divider, unsigned size)
+{
+ UInt64 v = 0;
+ if (divider != 0)
+ v = (val * 100 + divider / 2) / divider;
+ PrintNumber(f, v, size);
+}
+
+static void PrintChars(IBenchPrintCallback &f, char c, unsigned size)
+{
+ char s[256];
+ memset(s, (Byte)c, size);
+ s[size] = 0;
+ f.Print(s);
+}
+
+static void PrintSpaces(IBenchPrintCallback &f, unsigned size)
+{
+ PrintChars(f, ' ', size);
+}
+
+static void PrintUsage(IBenchPrintCallback &f, UInt64 usage, unsigned size)
+{
+ PrintNumber(f, Benchmark_GetUsage_Percents(usage), size);
+}
+
+static void PrintResults(IBenchPrintCallback &f, UInt64 usage, UInt64 rpu, UInt64 rating, bool showFreq, UInt64 cpuFreq)
+{
+ PrintUsage(f, usage, kFieldSize_Usage);
+ PrintRating(f, rpu, kFieldSize_RU);
+ PrintRating(f, rating, kFieldSize_Rating);
+ if (showFreq)
+ {
+ if (cpuFreq == 0)
+ PrintSpaces(f, kFieldSize_EUAndEffec);
+ else
+ {
+ PrintPercents(f, rating, cpuFreq * usage / kBenchmarkUsageMult, kFieldSize_EU);
+ PrintPercents(f, rating, cpuFreq, kFieldSize_Effec);
+ }
+ }
+}
+
+
+void CTotalBenchRes::Generate_From_BenchInfo(const CBenchInfo &info)
+{
+ Speed = info.GetUnpackSizeSpeed();
+ Usage = info.GetUsage();
+ RPU = info.GetRatingPerUsage(Rating);
+}
+
+void CTotalBenchRes::Mult_For_Weight(unsigned weight)
+{
+ NumIterations2 *= weight;
+ RPU *= weight;
+ Rating *= weight;
+ Usage *= weight;
+ Speed *= weight;
+}
+
+void CTotalBenchRes::Update_With_Res(const CTotalBenchRes &r)
+{
+ Rating += r.Rating;
+ Usage += r.Usage;
+ RPU += r.RPU;
+ Speed += r.Speed;
+ // NumIterations1 = (r1.NumIterations1 + r2.NumIterations1);
+ NumIterations2 += r.NumIterations2;
+}
+
+static void PrintResults(IBenchPrintCallback *f,
+ const CBenchInfo &info,
+ unsigned weight,
+ UInt64 rating,
+ bool showFreq, UInt64 cpuFreq,
+ CTotalBenchRes *res)
+{
+ CTotalBenchRes t;
+ t.Rating = rating;
+ t.NumIterations2 = 1;
+ t.Generate_From_BenchInfo(info);
+
+ if (f)
+ {
+ if (t.Speed != 0)
+ PrintNumber(*f, t.Speed / 1024, kFieldSize_Speed);
+ else
+ PrintSpaces(*f, 1 + kFieldSize_Speed);
+ }
+ if (f)
+ {
+ PrintResults(*f, t.Usage, t.RPU, rating, showFreq, cpuFreq);
+ }
+
+ if (res)
+ {
+ // res->NumIterations1++;
+ t.Mult_For_Weight(weight);
+ res->Update_With_Res(t);
+ }
+}
+
+static void PrintTotals(IBenchPrintCallback &f,
+ bool showFreq, UInt64 cpuFreq, bool showSpeed, const CTotalBenchRes &res)
+{
+ const UInt64 numIterations2 = res.NumIterations2 ? res.NumIterations2 : 1;
+ const UInt64 speed = res.Speed / numIterations2;
+ if (showSpeed && speed != 0)
+ PrintNumber(f, speed / 1024, kFieldSize_Speed);
+ else
+ PrintSpaces(f, 1 + kFieldSize_Speed);
+
+ // PrintSpaces(f, 1 + kFieldSize_Speed);
+ // UInt64 numIterations1 = res.NumIterations1; if (numIterations1 == 0) numIterations1 = 1;
+ PrintResults(f, res.Usage / numIterations2, res.RPU / numIterations2, res.Rating / numIterations2, showFreq, cpuFreq);
+}
+
+
+static void PrintHex(AString &s, UInt64 v)
+{
+ char temp[32];
+ ConvertUInt64ToHex(v, temp);
+ s += temp;
+}
+
+AString GetProcessThreadsInfo(const NSystem::CProcessAffinity &ti)
+{
+ AString s;
+ // s.Add_UInt32(ti.numProcessThreads);
+ unsigned numSysThreads = ti.GetNumSystemThreads();
+ if (ti.GetNumProcessThreads() != numSysThreads)
+ {
+ // if (ti.numProcessThreads != ti.numSysThreads)
+ {
+ s += " / ";
+ s.Add_UInt32(numSysThreads);
+ }
+ s += " : ";
+ #ifdef _WIN32
+ PrintHex(s, ti.processAffinityMask);
+ s += " / ";
+ PrintHex(s, ti.systemAffinityMask);
+ #else
+ unsigned i = (numSysThreads + 3) & ~(unsigned)3;
+ if (i == 0)
+ i = 4;
+ for (; i >= 4; )
+ {
+ i -= 4;
+ unsigned val = 0;
+ for (unsigned k = 0; k < 4; k++)
+ {
+ const unsigned bit = (ti.IsCpuSet(i + k) ? 1 : 0);
+ val += (bit << k);
+ }
+ PrintHex(s, val);
+ }
+ #endif
+ }
+ return s;
+}
+
+
+#ifdef Z7_LARGE_PAGES
+
+#ifdef _WIN32
+extern bool g_LargePagesMode;
+extern "C"
+{
+ extern SIZE_T g_LargePageSize;
+}
+#endif
+
+void Add_LargePages_String(AString &s)
+{
+ #ifdef _WIN32
+ if (g_LargePagesMode || g_LargePageSize != 0)
+ {
+ s.Add_OptSpaced("(LP-");
+ PrintSize_KMGT_Or_Hex(s, g_LargePageSize);
+ #ifdef MY_CPU_X86_OR_AMD64
+ if (CPU_IsSupported_PageGB())
+ s += "-1G";
+ #endif
+ if (!g_LargePagesMode)
+ s += "-NA";
+ s += ")";
+ }
+ #else
+ s += "";
+ #endif
+}
+
+#endif
+
+
+
+static void PrintRequirements(IBenchPrintCallback &f, const char *sizeString,
+ bool size_Defined, UInt64 size, const char *threadsString, UInt32 numThreads)
+{
+ f.Print("RAM ");
+ f.Print(sizeString);
+ if (size_Defined)
+ PrintNumber(f, (size >> 20), 6);
+ else
+ f.Print(" ?");
+ f.Print(" MB");
+
+ #ifdef Z7_LARGE_PAGES
+ {
+ AString s;
+ Add_LargePages_String(s);
+ f.Print(s);
+ }
+ #endif
+
+ f.Print(", # ");
+ f.Print(threadsString);
+ PrintNumber(f, numThreads, 3);
+}
+
+
+
+struct CBenchCallbackToPrint Z7_final: public IBenchCallback
+{
+ bool NeedPrint;
+ bool Use2Columns;
+ bool ShowFreq;
+ unsigned NameFieldSize;
+
+ unsigned EncodeWeight;
+ unsigned DecodeWeight;
+
+ UInt64 CpuFreq;
+ UInt64 DictSize;
+
+ IBenchPrintCallback *_file;
+ CBenchProps BenchProps;
+ CTotalBenchRes EncodeRes;
+ CTotalBenchRes DecodeRes;
+
+ CBenchInfo BenchInfo_Results[2];
+
+ CBenchCallbackToPrint():
+ NeedPrint(true),
+ Use2Columns(false),
+ ShowFreq(false),
+ NameFieldSize(0),
+ EncodeWeight(1),
+ DecodeWeight(1),
+ CpuFreq(0)
+ {}
+
+ void Init() { EncodeRes.Init(); DecodeRes.Init(); }
+ void Print(const char *s);
+ void NewLine();
+
+ HRESULT SetFreq(bool showFreq, UInt64 cpuFreq);
+ HRESULT SetEncodeResult(const CBenchInfo &info, bool final) Z7_override;
+ HRESULT SetDecodeResult(const CBenchInfo &info, bool final) Z7_override;
+};
+
+HRESULT CBenchCallbackToPrint::SetFreq(bool showFreq, UInt64 cpuFreq)
+{
+ ShowFreq = showFreq;
+ CpuFreq = cpuFreq;
+ return S_OK;
+}
+
+HRESULT CBenchCallbackToPrint::SetEncodeResult(const CBenchInfo &info, bool final)
+{
+ RINOK(_file->CheckBreak())
+ if (final)
+ BenchInfo_Results[0] = info;
+ if (final)
+ if (NeedPrint)
+ {
+ const UInt64 rating = BenchProps.GetRating_Enc(DictSize, info.GlobalTime, info.GlobalFreq, info.UnpackSize * info.NumIterations);
+ PrintResults(_file, info,
+ EncodeWeight, rating,
+ ShowFreq, CpuFreq, &EncodeRes);
+ if (!Use2Columns)
+ _file->NewLine();
+ }
+ return S_OK;
+}
+
+static const char * const kSep = " | ";
+
+HRESULT CBenchCallbackToPrint::SetDecodeResult(const CBenchInfo &info, bool final)
+{
+ RINOK(_file->CheckBreak())
+ if (final)
+ BenchInfo_Results[1] = info;
+ if (final)
+ if (NeedPrint)
+ {
+ const UInt64 rating = BenchProps.GetRating_Dec(info.GlobalTime, info.GlobalFreq, info.UnpackSize, info.PackSize, info.NumIterations);
+ if (Use2Columns)
+ _file->Print(kSep);
+ else
+ PrintSpaces(*_file, NameFieldSize);
+ CBenchInfo info2 = info;
+ info2.UnpackSize *= info2.NumIterations;
+ info2.PackSize *= info2.NumIterations;
+ info2.NumIterations = 1;
+ PrintResults(_file, info2,
+ DecodeWeight, rating,
+ ShowFreq, CpuFreq, &DecodeRes);
+ }
+ return S_OK;
+}
+
+void CBenchCallbackToPrint::Print(const char *s)
+{
+ _file->Print(s);
+}
+
+void CBenchCallbackToPrint::NewLine()
+{
+ _file->NewLine();
+}
+
+static void PrintLeft(IBenchPrintCallback &f, const char *s, unsigned size)
+{
+ f.Print(s);
+ int numSpaces = (int)size - (int)MyStringLen(s);
+ if (numSpaces > 0)
+ PrintSpaces(f, (unsigned)numSpaces);
+}
+
+static void PrintRight(IBenchPrintCallback &f, const char *s, unsigned size)
+{
+ int numSpaces = (int)size - (int)MyStringLen(s);
+ if (numSpaces > 0)
+ PrintSpaces(f, (unsigned)numSpaces);
+ f.Print(s);
+}
+
+
+static bool DoesWildcardMatchName_NoCase(const AString &mask, const char *name)
+{
+ UString wildc = GetUnicodeString(mask);
+ UString bname = GetUnicodeString(name);
+ wildc.MakeLower_Ascii();
+ bname.MakeLower_Ascii();
+ return DoesWildcardMatchName(wildc, bname);
+}
+
+
+static HRESULT TotalBench(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const COneMethodInfo &methodMask,
+ UInt64 complexInCommands,
+ #ifndef Z7_ST
+ UInt32 numThreads,
+ const CAffinityMode *affinityMode,
+ #endif
+ bool forceUnpackSize,
+ size_t unpackSize,
+ const Byte *fileData,
+ IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback)
+{
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Bench); i++)
+ {
+ const CBenchMethod &bench = g_Bench[i];
+ if (!DoesWildcardMatchName_NoCase(methodMask.MethodName, bench.Name))
+ continue;
+ PrintLeft(*callback->_file, bench.Name, kFieldSize_Name);
+ {
+ unsigned keySize = 32;
+ if (IsString1PrefixedByString2(bench.Name, "AES128")) keySize = 16;
+ else if (IsString1PrefixedByString2(bench.Name, "AES192")) keySize = 24;
+ callback->BenchProps.KeySize = keySize;
+ }
+ callback->BenchProps.DecComplexUnc = bench.DecComplexUnc;
+ callback->BenchProps.DecComplexCompr = bench.DecComplexCompr;
+ callback->BenchProps.EncComplex = bench.EncComplex;
+
+ COneMethodInfo method;
+ NCOM::CPropVariant propVariant;
+ propVariant = bench.Name;
+ RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant))
+
+ size_t unpackSize2 = unpackSize;
+ if (!forceUnpackSize && bench.DictBits == 0)
+ unpackSize2 = kFilterUnpackSize;
+
+ callback->EncodeWeight = bench.Weight;
+ callback->DecodeWeight = bench.Weight;
+
+ const HRESULT res = MethodBench(
+ EXTERNAL_CODECS_LOC_VARS
+ complexInCommands,
+ #ifndef Z7_ST
+ false, numThreads, affinityMode,
+ #endif
+ method,
+ unpackSize2, fileData,
+ bench.DictBits,
+ printCallback, callback, &callback->BenchProps);
+
+ if (res == E_NOTIMPL)
+ {
+ // callback->Print(" ---");
+ // we need additional empty line as line for decompression results
+ if (!callback->Use2Columns)
+ callback->NewLine();
+ }
+ else
+ {
+ RINOK(res)
+ }
+
+ callback->NewLine();
+ }
+ return S_OK;
+}
+
+
+struct CFreqBench
+{
+ // in:
+ UInt64 complexInCommands;
+ UInt32 numThreads;
+ bool showFreq;
+ UInt64 specifiedFreq;
+
+ // out:
+ UInt64 CpuFreqRes;
+ UInt64 UsageRes;
+ UInt32 res;
+
+ CFreqBench()
+ {}
+
+ HRESULT FreqBench(IBenchPrintCallback *_file
+ #ifndef Z7_ST
+ , const CAffinityMode *affinityMode
+ #endif
+ );
+};
+
+
+HRESULT CFreqBench::FreqBench(IBenchPrintCallback *_file
+ #ifndef Z7_ST
+ , const CAffinityMode *affinityMode
+ #endif
+ )
+{
+ res = 0;
+ CpuFreqRes = 0;
+ UsageRes = 0;
+
+ if (numThreads == 0)
+ numThreads = 1;
+
+ #ifdef Z7_ST
+ numThreads = 1;
+ #endif
+
+ const UInt32 complexity = kNumFreqCommands;
+ UInt64 numIterations = complexInCommands / complexity;
+ UInt32 numIterations2 = 1 << 30;
+ if (numIterations > numIterations2)
+ numIterations /= numIterations2;
+ else
+ {
+ numIterations2 = (UInt32)numIterations;
+ numIterations = 1;
+ }
+
+ CBenchInfoCalc progressInfoSpec;
+
+ #ifndef Z7_ST
+
+ bool mtMode = (numThreads > 1) || affinityMode->NeedAffinity();
+
+ if (mtMode)
+ {
+ CFreqThreads threads;
+ threads.Items = new CFreqInfo[numThreads];
+ UInt32 i;
+ for (i = 0; i < numThreads; i++)
+ {
+ CFreqInfo &info = threads.Items[i];
+ info.Callback = _file;
+ info.CallbackRes = S_OK;
+ info.NumIterations = numIterations;
+ info.Size = numIterations2;
+ }
+ progressInfoSpec.SetStartTime();
+ for (i = 0; i < numThreads; i++)
+ {
+ // Sleep(10);
+ CFreqInfo &info = threads.Items[i];
+ WRes wres = affinityMode->CreateThread_WithAffinity(info.Thread, FreqThreadFunction, &info, i);
+ if (info.Thread.IsCreated())
+ threads.NumThreads++;
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ }
+ WRes wres = threads.WaitAll();
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ for (i = 0; i < numThreads; i++)
+ {
+ RINOK(threads.Items[i].CallbackRes)
+ }
+ }
+ else
+ #endif
+ {
+ progressInfoSpec.SetStartTime();
+ UInt32 sum = g_BenchCpuFreqTemp;
+ for (UInt64 k = numIterations; k > 0; k--)
+ {
+ sum = CountCpuFreq(sum, numIterations2, g_BenchCpuFreqTemp);
+ if (_file)
+ {
+ RINOK(_file->CheckBreak())
+ }
+ }
+ res += sum;
+ }
+
+ if (res == 0x12345678)
+ if (_file)
+ {
+ RINOK(_file->CheckBreak())
+ }
+
+ CBenchInfo info;
+ progressInfoSpec.SetFinishTime(info);
+
+ info.UnpackSize = 0;
+ info.PackSize = 0;
+ info.NumIterations = 1;
+
+ const UInt64 numCommands = (UInt64)numIterations * numIterations2 * numThreads * complexity;
+ const UInt64 rating = info.GetSpeed(numCommands);
+ CpuFreqRes = rating / numThreads;
+ UsageRes = info.GetUsage();
+
+ if (_file)
+ {
+ PrintResults(_file, info,
+ 0, // weight
+ rating,
+ showFreq, showFreq ? (specifiedFreq != 0 ? specifiedFreq : CpuFreqRes) : 0, NULL);
+ RINOK(_file->CheckBreak())
+ }
+
+ return S_OK;
+}
+
+
+
+static HRESULT CrcBench(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ UInt64 complexInCommands,
+ UInt32 numThreads,
+ const size_t bufferSize,
+ const Byte *fileData,
+
+ UInt64 &speed,
+ UInt64 &usage,
+
+ UInt32 complexity, unsigned benchWeight,
+ const UInt32 *checkSum,
+ const COneMethodInfo &method,
+ IBenchPrintCallback *_file,
+ #ifndef Z7_ST
+ const CAffinityMode *affinityMode,
+ #endif
+ bool showRating,
+ CTotalBenchRes *encodeRes,
+ bool showFreq, UInt64 cpuFreq)
+{
+ if (numThreads == 0)
+ numThreads = 1;
+
+ #ifdef Z7_ST
+ numThreads = 1;
+ #endif
+
+ const AString &methodName = method.MethodName;
+ // methodName.RemoveChar(L'-');
+ CMethodId hashID;
+ if (!FindHashMethod(
+ EXTERNAL_CODECS_LOC_VARS
+ methodName, hashID))
+ return E_NOTIMPL;
+
+ /*
+ // if will generate random data in each thread, instead of global data
+ CMidAlignedBuffer buffer;
+ if (!fileData)
+ {
+ ALLOC_WITH_HRESULT(&buffer, bufferSize)
+ RandGen(buffer, bufferSize);
+ fileData = buffer;
+ }
+ */
+
+ const size_t bsize = (bufferSize == 0 ? 1 : bufferSize);
+ UInt64 numIterations = complexInCommands * k_Hash_Complex_Mult / complexity / bsize;
+ if (numIterations == 0)
+ numIterations = 1;
+
+ CBenchInfoCalc progressInfoSpec;
+ CBenchInfo info;
+
+ #ifndef Z7_ST
+ bool mtEncMode = (numThreads > 1) || affinityMode->NeedAffinity();
+
+ if (mtEncMode)
+ {
+ CCrcThreads threads;
+ threads.Items = new CCrcInfo[numThreads];
+ {
+ WRes wres = threads.Common.StartEvent.Create();
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ threads.NeedClose = true;
+ }
+
+ UInt32 i;
+ for (i = 0; i < numThreads; i++)
+ {
+ CCrcInfo &ci = threads.Items[i];
+ AString name;
+ RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, ci.Hasher))
+ if (!ci.Hasher)
+ return E_NOTIMPL;
+ CMyComPtr<ICompressSetCoderProperties> scp;
+ ci.Hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp);
+ if (scp)
+ {
+ RINOK(method.SetCoderProps(scp))
+ }
+
+ ci.Callback = _file;
+ ci.Data = fileData;
+ ci.NumIterations = numIterations;
+ ci.Size = bufferSize;
+ ci.CheckSumDefined = false;
+ if (checkSum)
+ {
+ ci.CheckSum = *checkSum;
+ ci.CheckSumDefined = true;
+ }
+
+ #ifdef USE_ALLOCA
+ ci.AllocaSize = (i * 16 * 21) & 0x7FF;
+ #endif
+ }
+
+ for (i = 0; i < numThreads; i++)
+ {
+ CCrcInfo &ci = threads.Items[i];
+ ci.ThreadIndex = i;
+ ci.Common = &threads.Common;
+ ci.AffinityMode = *affinityMode;
+ HRESULT hres = ci.CreateThread();
+ if (ci.Thread.IsCreated())
+ threads.NumThreads++;
+ if (hres != 0)
+ return hres;
+ }
+
+ for (i = 0; i < numThreads; i++)
+ {
+ CCrcInfo &ci = threads.Items[i];
+ WRes wres = ci.ReadyEvent.Lock();
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ RINOK(ci.Res)
+ }
+
+ progressInfoSpec.SetStartTime();
+
+ WRes wres = threads.StartAndWait();
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+
+ progressInfoSpec.SetFinishTime(info);
+
+ for (i = 0; i < numThreads; i++)
+ {
+ RINOK(threads.Items[i].Res)
+ if (i != 0)
+ if (threads.Items[i].CheckSum_Res !=
+ threads.Items[i - 1].CheckSum_Res)
+ return S_FALSE;
+ }
+ }
+ else
+ #endif
+ {
+ CMyComPtr<IHasher> hasher;
+ AString name;
+ RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS hashID, name, hasher))
+ if (!hasher)
+ return E_NOTIMPL;
+ CMyComPtr<ICompressSetCoderProperties> scp;
+ hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp);
+ if (scp)
+ {
+ RINOK(method.SetCoderProps(scp))
+ }
+ CCrcInfo_Base crcib;
+ crcib.CreateLocalBuf = false;
+ RINOK(crcib.Generate(fileData, bufferSize))
+ progressInfoSpec.SetStartTime();
+ RINOK(crcib.CrcProcess(numIterations, checkSum, hasher, _file))
+ progressInfoSpec.SetFinishTime(info);
+ }
+
+
+ UInt64 unpSize = numIterations * bufferSize;
+ UInt64 unpSizeThreads = unpSize * numThreads;
+ info.UnpackSize = unpSizeThreads;
+ info.PackSize = unpSizeThreads;
+ info.NumIterations = 1;
+
+ if (_file)
+ {
+ if (showRating)
+ {
+ UInt64 unpSizeThreads2 = unpSizeThreads;
+ if (unpSizeThreads2 == 0)
+ unpSizeThreads2 = numIterations * 1 * numThreads;
+ const UInt64 numCommands = unpSizeThreads2 * complexity / 256;
+ const UInt64 rating = info.GetSpeed(numCommands);
+ PrintResults(_file, info,
+ benchWeight, rating,
+ showFreq, cpuFreq, encodeRes);
+ }
+ RINOK(_file->CheckBreak())
+ }
+
+ speed = info.GetSpeed(unpSizeThreads);
+ usage = info.GetUsage();
+
+ return S_OK;
+}
+
+
+
+static HRESULT TotalBench_Hash(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const COneMethodInfo &methodMask,
+ UInt64 complexInCommands,
+ UInt32 numThreads,
+ size_t bufSize,
+ const Byte *fileData,
+ IBenchPrintCallback *printCallback, CBenchCallbackToPrint *callback,
+ #ifndef Z7_ST
+ const CAffinityMode *affinityMode,
+ #endif
+ CTotalBenchRes *encodeRes,
+ bool showFreq, UInt64 cpuFreq)
+{
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Hash); i++)
+ {
+ const CBenchHash &bench = g_Hash[i];
+ if (!DoesWildcardMatchName_NoCase(methodMask.MethodName, bench.Name))
+ continue;
+ PrintLeft(*callback->_file, bench.Name, kFieldSize_Name);
+ // callback->BenchProps.DecComplexUnc = bench.DecComplexUnc;
+ // callback->BenchProps.DecComplexCompr = bench.DecComplexCompr;
+ // callback->BenchProps.EncComplex = bench.EncComplex;
+
+ COneMethodInfo method;
+ NCOM::CPropVariant propVariant;
+ propVariant = bench.Name;
+ RINOK(method.ParseMethodFromPROPVARIANT(UString(), propVariant))
+
+ UInt64 speed, usage;
+
+ const HRESULT res = CrcBench(
+ EXTERNAL_CODECS_LOC_VARS
+ complexInCommands,
+ numThreads, bufSize, fileData,
+ speed, usage,
+ bench.Complex, bench.Weight,
+ (!fileData && bufSize == (1 << kNumHashDictBits)) ? &bench.CheckSum : NULL,
+ method,
+ printCallback,
+ #ifndef Z7_ST
+ affinityMode,
+ #endif
+ true, // showRating
+ encodeRes, showFreq, cpuFreq);
+ if (res == E_NOTIMPL)
+ {
+ // callback->Print(" ---");
+ }
+ else
+ {
+ RINOK(res)
+ }
+ callback->NewLine();
+ }
+ return S_OK;
+}
+
+struct CTempValues
+{
+ UInt64 *Values;
+ CTempValues(): Values(NULL) {}
+ void Alloc(UInt32 num) { Values = new UInt64[num]; }
+ ~CTempValues() { delete []Values; }
+};
+
+static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop)
+{
+ const wchar_t *end;
+ UInt64 result = ConvertStringToUInt64(s, &end);
+ if (*end != 0 || s.IsEmpty())
+ prop = s;
+ else if (result <= (UInt32)0xFFFFFFFF)
+ prop = (UInt32)result;
+ else
+ prop = result;
+}
+
+
+static bool AreSameMethodNames(const char *fullName, const char *shortName)
+{
+ return StringsAreEqualNoCase_Ascii(fullName, shortName);
+}
+
+
+
+
+static void Print_Usage_and_Threads(IBenchPrintCallback &f, UInt64 usage, UInt32 threads)
+{
+ PrintRequirements(f, "usage:", true, usage, "Benchmark threads: ", threads);
+}
+
+
+static void Print_Delimiter(IBenchPrintCallback &f)
+{
+ f.Print(" |");
+}
+
+static void Print_Pow(IBenchPrintCallback &f, unsigned pow)
+{
+ char s[16];
+ ConvertUInt32ToString(pow, s);
+ unsigned pos = MyStringLen(s);
+ s[pos++] = ':';
+ s[pos] = 0;
+ PrintLeft(f, s, kFieldSize_SmallName); // 4
+}
+
+static void Bench_BW_Print_Usage_Speed(IBenchPrintCallback &f,
+ UInt64 usage, UInt64 speed)
+{
+ PrintUsage(f, usage, kFieldSize_Usage);
+ PrintNumber(f, speed / 1000000, kFieldSize_CrcSpeed);
+}
+
+
+HRESULT Bench(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IBenchPrintCallback *printCallback,
+ IBenchCallback *benchCallback,
+ const CObjectVector<CProperty> &props,
+ UInt32 numIterations,
+ bool multiDict,
+ IBenchFreqCallback *freqCallback)
+{
+ if (!CrcInternalTest())
+ return E_FAIL;
+
+ UInt32 numCPUs = 1;
+ UInt64 ramSize = (UInt64)(sizeof(size_t)) << 29;
+
+ NSystem::CProcessAffinity threadsInfo;
+ threadsInfo.InitST();
+
+ #ifndef Z7_ST
+
+ if (threadsInfo.Get() && threadsInfo.GetNumProcessThreads() != 0)
+ numCPUs = threadsInfo.GetNumProcessThreads();
+ else
+ numCPUs = NSystem::GetNumberOfProcessors();
+
+ #endif
+
+ // numCPUs = 24;
+ /*
+ {
+ DWORD_PTR mask = (1 << 0);
+ DWORD_PTR old = SetThreadAffinityMask(GetCurrentThread(), mask);
+ old = old;
+ DWORD_PTR old2 = SetThreadAffinityMask(GetCurrentThread(), mask);
+ old2 = old2;
+ return 0;
+ }
+ */
+
+ bool ramSize_Defined = NSystem::GetRamSize(ramSize);
+
+ UInt32 numThreadsSpecified = numCPUs;
+ bool needSetComplexity = false;
+ UInt32 testTimeMs = kComplexInMs;
+ UInt32 startDicLog = 22;
+ bool startDicLog_Defined = false;
+ UInt64 specifiedFreq = 0;
+ bool multiThreadTests = false;
+ UInt64 complexInCommands = kComplexInCommands;
+ UInt32 numThreads_Start = 1;
+
+ #ifndef Z7_ST
+ CAffinityMode affinityMode;
+ #endif
+
+
+ COneMethodInfo method;
+
+ CMidAlignedBuffer fileDataBuffer;
+ bool use_fileData = false;
+ bool isFixedDict = false;
+
+ {
+ unsigned i;
+
+ if (printCallback)
+ {
+ for (i = 0; i < props.Size(); i++)
+ {
+ const CProperty &property = props[i];
+ printCallback->Print(" ");
+ printCallback->Print(GetAnsiString(property.Name));
+ if (!property.Value.IsEmpty())
+ {
+ printCallback->Print("=");
+ printCallback->Print(GetAnsiString(property.Value));
+ }
+ }
+ if (!props.IsEmpty())
+ printCallback->NewLine();
+ }
+
+
+ for (i = 0; i < props.Size(); i++)
+ {
+ const CProperty &property = props[i];
+ UString name (property.Name);
+ name.MakeLower_Ascii();
+
+ if (name.IsEqualTo("file"))
+ {
+ if (property.Value.IsEmpty())
+ return E_INVALIDARG;
+
+ NFile::NIO::CInFile file;
+ if (!file.Open(us2fs(property.Value)))
+ return GetLastError_noZero_HRESULT();
+ size_t len;
+ {
+ UInt64 len64;
+ if (!file.GetLength(len64))
+ return GetLastError_noZero_HRESULT();
+ if (printCallback)
+ {
+ printCallback->Print("file size =");
+ PrintNumber(*printCallback, len64, 0);
+ printCallback->NewLine();
+ }
+ len = (size_t)len64;
+ if (len != len64)
+ return E_INVALIDARG;
+ }
+
+ // (len == 0) is allowed. Also it's allowed if Alloc(0) returns NULL here
+
+ ALLOC_WITH_HRESULT(&fileDataBuffer, len)
+ use_fileData = true;
+
+ {
+ size_t processed;
+ if (!file.ReadFull((Byte *)fileDataBuffer, len, processed))
+ return GetLastError_noZero_HRESULT();
+ if (processed != len)
+ return E_FAIL;
+ }
+ continue;
+ }
+
+ NCOM::CPropVariant propVariant;
+ if (!property.Value.IsEmpty())
+ ParseNumberString(property.Value, propVariant);
+
+ if (name.IsEqualTo("time"))
+ {
+ RINOK(ParsePropToUInt32(UString(), propVariant, testTimeMs))
+ needSetComplexity = true;
+ testTimeMs *= 1000;
+ continue;
+ }
+
+ if (name.IsEqualTo("timems"))
+ {
+ RINOK(ParsePropToUInt32(UString(), propVariant, testTimeMs))
+ needSetComplexity = true;
+ continue;
+ }
+
+ if (name.IsEqualTo("tic"))
+ {
+ UInt32 v;
+ RINOK(ParsePropToUInt32(UString(), propVariant, v))
+ if (v >= 64)
+ return E_INVALIDARG;
+ complexInCommands = (UInt64)1 << v;
+ continue;
+ }
+
+ const bool isCurrent_fixedDict = name.IsEqualTo("df");
+ if (isCurrent_fixedDict)
+ isFixedDict = true;
+ if (isCurrent_fixedDict || name.IsEqualTo("ds"))
+ {
+ RINOK(ParsePropToUInt32(UString(), propVariant, startDicLog))
+ if (startDicLog > 32)
+ return E_INVALIDARG;
+ startDicLog_Defined = true;
+ continue;
+ }
+
+ if (name.IsEqualTo("mts"))
+ {
+ RINOK(ParsePropToUInt32(UString(), propVariant, numThreads_Start))
+ continue;
+ }
+
+ if (name.IsEqualTo("af"))
+ {
+ UInt32 bundle;
+ RINOK(ParsePropToUInt32(UString(), propVariant, bundle))
+ if (bundle > 0 && bundle < numCPUs)
+ {
+ #ifndef Z7_ST
+ affinityMode.SetLevels(numCPUs, 2);
+ affinityMode.NumBundleThreads = bundle;
+ #endif
+ }
+ continue;
+ }
+
+ if (name.IsEqualTo("freq"))
+ {
+ UInt32 freq32 = 0;
+ RINOK(ParsePropToUInt32(UString(), propVariant, freq32))
+ if (freq32 == 0)
+ return E_INVALIDARG;
+ specifiedFreq = (UInt64)freq32 * 1000000;
+
+ if (printCallback)
+ {
+ printCallback->Print("freq=");
+ PrintNumber(*printCallback, freq32, 0);
+ printCallback->NewLine();
+ }
+
+ continue;
+ }
+
+ if (name.IsPrefixedBy_Ascii_NoCase("mt"))
+ {
+ const UString s = name.Ptr(2);
+ if (s.IsEqualTo("*")
+ || (s.IsEmpty()
+ && propVariant.vt == VT_BSTR
+ && StringsAreEqual_Ascii(propVariant.bstrVal, "*")))
+ {
+ multiThreadTests = true;
+ continue;
+ }
+ #ifndef Z7_ST
+ RINOK(ParseMtProp(s, propVariant, numCPUs, numThreadsSpecified))
+ #endif
+ continue;
+ }
+
+ RINOK(method.ParseMethodFromPROPVARIANT(name, propVariant))
+ }
+ }
+
+ if (printCallback)
+ {
+ AString s;
+
+ #ifndef _WIN32
+ s += "Compiler: ";
+ GetCompiler(s);
+ printCallback->Print(s);
+ printCallback->NewLine();
+ s.Empty();
+ #endif
+
+ GetSystemInfoText(s);
+ printCallback->Print(s);
+ printCallback->NewLine();
+ }
+
+ if (printCallback)
+ {
+ printCallback->Print("1T CPU Freq (MHz):");
+ }
+
+ if (printCallback || freqCallback)
+ {
+ UInt64 numMilCommands = 1 << 6;
+ if (specifiedFreq != 0)
+ {
+ while (numMilCommands > 1 && specifiedFreq < (numMilCommands * 1000000))
+ numMilCommands >>= 1;
+ }
+
+ for (int jj = 0;; jj++)
+ {
+ if (printCallback)
+ RINOK(printCallback->CheckBreak())
+
+ UInt64 start = ::GetTimeCount();
+ UInt32 sum = (UInt32)start;
+ sum = CountCpuFreq(sum, (UInt32)(numMilCommands * 1000000 / kNumFreqCommands), g_BenchCpuFreqTemp);
+ if (sum == 0xF1541213)
+ if (printCallback)
+ printCallback->Print("");
+ const UInt64 realDelta = ::GetTimeCount() - start;
+ start = realDelta;
+ if (start == 0)
+ start = 1;
+ if (start > (UInt64)1 << 61)
+ start = 1;
+ const UInt64 freq = GetFreq();
+ // mips is constant in some compilers
+ const UInt64 hz = MyMultDiv64(numMilCommands * 1000000, freq, start);
+ const UInt64 mipsVal = numMilCommands * freq / start;
+ if (printCallback)
+ {
+ if (realDelta == 0)
+ {
+ printCallback->Print(" -");
+ }
+ else
+ {
+ // PrintNumber(*printCallback, start, 0);
+ PrintNumber(*printCallback, mipsVal, 5);
+ }
+ }
+ if (freqCallback)
+ {
+ RINOK(freqCallback->AddCpuFreq(1, hz, kBenchmarkUsageMult))
+ }
+
+ if (jj >= 1)
+ {
+ bool needStop = (numMilCommands >= (1 <<
+ #ifdef _DEBUG
+ 7
+ #else
+ 11
+ #endif
+ ));
+ if (start >= freq * 16)
+ {
+ printCallback->Print(" (Cmplx)");
+ if (!freqCallback) // we don't want complexity change for old gui lzma benchmark
+ {
+ needSetComplexity = true;
+ }
+ needStop = true;
+ }
+ if (needSetComplexity)
+ SetComplexCommandsMs(testTimeMs, false, mipsVal * 1000000, complexInCommands);
+ if (needStop)
+ break;
+ numMilCommands <<= 1;
+ }
+ }
+ if (freqCallback)
+ {
+ RINOK(freqCallback->FreqsFinished(1))
+ }
+ }
+
+ if (numThreadsSpecified >= 2)
+ if (printCallback || freqCallback)
+ {
+ if (printCallback)
+ printCallback->NewLine();
+
+ /* it can show incorrect frequency for HT threads.
+ so we reduce freq test to (numCPUs / 2) */
+
+ UInt32 numThreads = numThreadsSpecified >= numCPUs / 2 ? numCPUs / 2: numThreadsSpecified;
+ if (numThreads < 1)
+ numThreads = 1;
+
+ if (printCallback)
+ {
+ char s[128];
+ ConvertUInt64ToString(numThreads, s);
+ printCallback->Print(s);
+ printCallback->Print("T CPU Freq (MHz):");
+ }
+ UInt64 numMilCommands = 1 <<
+ #ifdef _DEBUG
+ 7;
+ #else
+ 10;
+ #endif
+
+ if (specifiedFreq != 0)
+ {
+ while (numMilCommands > 1 && specifiedFreq < (numMilCommands * 1000000))
+ numMilCommands >>= 1;
+ }
+
+ // for (int jj = 0;; jj++)
+ for (;;)
+ {
+ if (printCallback)
+ RINOK(printCallback->CheckBreak())
+
+ {
+ // PrintLeft(f, "CPU", kFieldSize_Name);
+
+ // UInt32 resVal;
+
+ CFreqBench fb;
+ fb.complexInCommands = numMilCommands * 1000000;
+ fb.numThreads = numThreads;
+ // showFreq;
+ // fb.showFreq = (freqTest == kNumCpuTests - 1 || specifiedFreq != 0);
+ fb.showFreq = true;
+ fb.specifiedFreq = 1;
+
+ const HRESULT res = fb.FreqBench(NULL /* printCallback */
+ #ifndef Z7_ST
+ , &affinityMode
+ #endif
+ );
+ RINOK(res)
+
+ if (freqCallback)
+ {
+ RINOK(freqCallback->AddCpuFreq(numThreads, fb.CpuFreqRes, fb.UsageRes))
+ }
+
+ if (printCallback)
+ {
+ /*
+ if (realDelta == 0)
+ {
+ printCallback->Print(" -");
+ }
+ else
+ */
+ {
+ // PrintNumber(*printCallback, start, 0);
+ PrintUsage(*printCallback, fb.UsageRes, 3);
+ printCallback->Print("%");
+ PrintNumber(*printCallback, fb.CpuFreqRes / 1000000, 0);
+ printCallback->Print(" ");
+
+ // PrintNumber(*printCallback, fb.UsageRes, 5);
+ }
+ }
+ }
+ // if (jj >= 1)
+ {
+ const bool needStop = (numMilCommands >= (1 <<
+ #ifdef _DEBUG
+ 7
+ #else
+ 11
+ #endif
+ ));
+ if (needStop)
+ break;
+ numMilCommands <<= 1;
+ }
+ }
+ if (freqCallback)
+ {
+ RINOK(freqCallback->FreqsFinished(numThreads))
+ }
+ }
+
+
+ if (printCallback)
+ {
+ printCallback->NewLine();
+ printCallback->NewLine();
+ PrintRequirements(*printCallback, "size: ", ramSize_Defined, ramSize, "CPU hardware threads:", numCPUs);
+ printCallback->Print(GetProcessThreadsInfo(threadsInfo));
+ printCallback->NewLine();
+ }
+
+ if (numThreadsSpecified < 1 || numThreadsSpecified > kNumThreadsMax)
+ return E_INVALIDARG;
+
+ UInt64 dict = (UInt64)1 << startDicLog;
+ const bool dictIsDefined = (isFixedDict || method.Get_DicSize(dict));
+
+ const unsigned level = method.GetLevel();
+
+ AString &methodName = method.MethodName;
+ const AString original_MethodName = methodName;
+ if (methodName.IsEmpty())
+ methodName = "LZMA";
+
+ if (benchCallback)
+ {
+ CBenchProps benchProps;
+ benchProps.SetLzmaCompexity();
+ const UInt64 dictSize = method.Get_Lzma_DicSize();
+
+ size_t uncompressedDataSize;
+ if (use_fileData)
+ {
+ uncompressedDataSize = fileDataBuffer.Size();
+ }
+ else
+ {
+ uncompressedDataSize = kAdditionalSize + (size_t)dictSize;
+ if (uncompressedDataSize < dictSize)
+ return E_INVALIDARG;
+ }
+
+ return MethodBench(
+ EXTERNAL_CODECS_LOC_VARS
+ complexInCommands,
+ #ifndef Z7_ST
+ true, numThreadsSpecified,
+ &affinityMode,
+ #endif
+ method,
+ uncompressedDataSize, (const Byte *)fileDataBuffer,
+ kOldLzmaDictBits, printCallback, benchCallback, &benchProps);
+ }
+
+ if (methodName.IsEqualTo_Ascii_NoCase("CRC"))
+ methodName = "crc32";
+
+ CMethodId hashID;
+ const bool isHashMethod = FindHashMethod(EXTERNAL_CODECS_LOC_VARS methodName, hashID);
+ int codecIndex = -1;
+ bool isFilter = false;
+ if (!isHashMethod)
+ {
+ UInt32 numStreams;
+ codecIndex = FindMethod_Index(EXTERNAL_CODECS_LOC_VARS original_MethodName,
+ true, // encode
+ hashID, numStreams, isFilter);
+ // we can allow non filter for BW tests
+ if (!isFilter) codecIndex = -1;
+ }
+
+ CBenchCallbackToPrint callback;
+ callback.Init();
+ callback._file = printCallback;
+
+ if (isHashMethod || codecIndex != -1)
+ {
+ if (!printCallback)
+ return S_FALSE;
+ IBenchPrintCallback &f = *printCallback;
+
+ UInt64 dict64 = dict;
+ if (!dictIsDefined)
+ dict64 = (1 << 27);
+ if (use_fileData)
+ {
+ if (!dictIsDefined)
+ dict64 = fileDataBuffer.Size();
+ else if (dict64 > fileDataBuffer.Size())
+ dict64 = fileDataBuffer.Size();
+ }
+
+ for (;;)
+ {
+ const int index = method.FindProp(NCoderPropID::kDictionarySize);
+ if (index < 0)
+ break;
+ method.Props.Delete((unsigned)index);
+ }
+
+ // methodName.RemoveChar(L'-');
+ Int32 complexity = 16 * k_Hash_Complex_Mult; // for unknown hash method
+ const UInt32 *checkSum = NULL;
+ int benchIndex = -1;
+
+ if (isHashMethod)
+ {
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Hash); i++)
+ {
+ const CBenchHash &h = g_Hash[i];
+ AString benchMethod (h.Name);
+ AString benchProps;
+ const int propPos = benchMethod.Find(':');
+ if (propPos >= 0)
+ {
+ benchProps = benchMethod.Ptr((unsigned)(propPos + 1));
+ benchMethod.DeleteFrom((unsigned)propPos);
+ }
+
+ if (AreSameMethodNames(benchMethod, methodName))
+ {
+ const bool sameProps = method.PropsString.IsEqualTo_Ascii_NoCase(benchProps);
+ /*
+ bool isMainMethod = method.PropsString.IsEmpty();
+ if (isMainMethod)
+ isMainMethod = !checkSum
+ || (benchMethod.IsEqualTo_Ascii_NoCase("crc32") && benchProps.IsEqualTo_Ascii_NoCase("8"));
+ if (sameProps || isMainMethod)
+ */
+ {
+ complexity = (Int32)h.Complex;
+ checkSum = &h.CheckSum;
+ if (sameProps)
+ break;
+ /*
+ if property. is not specified, we use the complexity
+ for latest fastest method (crc32:64)
+ */
+ }
+ }
+ }
+ // if (!checkSum) return E_NOTIMPL;
+ }
+ else
+ {
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Bench); i++)
+ {
+ const CBenchMethod &bench = g_Bench[i];
+ AString benchMethod (bench.Name);
+ AString benchProps;
+ const int propPos = benchMethod.Find(':');
+ if (propPos >= 0)
+ {
+ benchProps = benchMethod.Ptr((unsigned)(propPos + 1));
+ benchMethod.DeleteFrom((unsigned)propPos);
+ }
+
+ if (AreSameMethodNames(benchMethod, methodName))
+ {
+ const bool sameProps = method.PropsString.IsEqualTo_Ascii_NoCase(benchProps);
+ // bool isMainMethod = method.PropsString.IsEmpty();
+ // if (sameProps || isMainMethod)
+ {
+ benchIndex = (int)i;
+ if (sameProps)
+ break;
+ }
+ }
+ }
+ // if (benchIndex < 0) return E_NOTIMPL;
+ }
+
+ {
+ /* we count usage only for crc and filter. non-filters are not supported */
+ UInt64 usage = (1 << 20);
+ UInt64 bufSize = dict64;
+ UInt32 numBlocks = isHashMethod ? 1 : 3;
+ if (use_fileData)
+ {
+ usage += fileDataBuffer.Size();
+ if (bufSize > fileDataBuffer.Size())
+ bufSize = fileDataBuffer.Size();
+ if (isHashMethod)
+ {
+ numBlocks = 0;
+ #ifndef Z7_ST
+ if (numThreadsSpecified != 1)
+ numBlocks = (k_Crc_CreateLocalBuf_For_File ? 1 : 0);
+ #endif
+ }
+ }
+ usage += numThreadsSpecified * bufSize * numBlocks;
+ Print_Usage_and_Threads(f, usage, numThreadsSpecified);
+ }
+
+ CUIntVector numThreadsVector;
+ {
+ unsigned nt = numThreads_Start;
+ for (;;)
+ {
+ if (nt > numThreadsSpecified)
+ break;
+ numThreadsVector.Add(nt);
+ const unsigned next = nt * 2;
+ const UInt32 ntHalf= numThreadsSpecified / 2;
+ if (ntHalf > nt && ntHalf < next)
+ numThreadsVector.Add(ntHalf);
+ if (numThreadsSpecified > nt && numThreadsSpecified < next)
+ numThreadsVector.Add(numThreadsSpecified);
+ nt = next;
+ }
+ }
+
+ unsigned numColumns = isHashMethod ? 1 : 2;
+ CTempValues speedTotals;
+ CTempValues usageTotals;
+ {
+ const unsigned numItems = numThreadsVector.Size() * numColumns;
+ speedTotals.Alloc(numItems);
+ usageTotals.Alloc(numItems);
+ for (unsigned i = 0; i < numItems; i++)
+ {
+ speedTotals.Values[i] = 0;
+ usageTotals.Values[i] = 0;
+ }
+ }
+
+ f.NewLine();
+ for (unsigned line = 0; line < 3; line++)
+ {
+ f.NewLine();
+ f.Print(line == 0 ? "THRD" : line == 1 ? " " : "Size");
+ FOR_VECTOR (ti, numThreadsVector)
+ {
+ if (ti != 0)
+ Print_Delimiter(f);
+ if (line == 0)
+ {
+ PrintSpaces(f, (kFieldSize_CrcSpeed + kFieldSize_Usage + 2) * (numColumns - 1));
+ PrintNumber(f, numThreadsVector[ti], 1 + kFieldSize_Usage + kFieldSize_CrcSpeed);
+ }
+ else
+ {
+ for (unsigned c = 0; c < numColumns; c++)
+ {
+ PrintRight(f, line == 1 ? "Usage" : "%", kFieldSize_Usage + 1);
+ PrintRight(f, line == 1 ? "BW" : "MB/s", kFieldSize_CrcSpeed + 1);
+ }
+ }
+ }
+ }
+ f.NewLine();
+
+ UInt64 numSteps = 0;
+
+ // for (UInt32 iter = 0; iter < numIterations; iter++)
+ // {
+ unsigned pow = 10; // kNumHashDictBits
+ if (startDicLog_Defined)
+ pow = startDicLog;
+
+ // #define NUM_SUB_BITS 2
+ // pow <<= NUM_SUB_BITS;
+ for (;; pow++)
+ {
+ const UInt64 bufSize = (UInt64)1 << pow;
+ // UInt64 bufSize = (UInt64)1 << (pow >> NUM_SUB_BITS);
+ // bufSize += ((UInt64)pow & ((1 << NUM_SUB_BITS) - 1)) << ((pow >> NUM_SUB_BITS) - NUM_SUB_BITS);
+
+ size_t dataSize = fileDataBuffer.Size();
+ if (dataSize > bufSize || !use_fileData)
+ dataSize = (size_t)bufSize;
+
+ for (UInt32 iter = 0; iter < numIterations; iter++)
+ {
+ Print_Pow(f, pow);
+ // PrintNumber(f, bufSize >> 10, 4);
+
+ FOR_VECTOR (ti, numThreadsVector)
+ {
+ RINOK(f.CheckBreak())
+ const UInt32 numThreads = numThreadsVector[ti];
+ if (isHashMethod)
+ {
+ UInt64 speed = 0;
+ UInt64 usage = 0;
+ const HRESULT res = CrcBench(EXTERNAL_CODECS_LOC_VARS complexInCommands,
+ numThreads,
+ dataSize, (const Byte *)fileDataBuffer,
+ speed, usage,
+ (UInt32)complexity,
+ 1, // benchWeight,
+ (pow == kNumHashDictBits && !use_fileData) ? checkSum : NULL,
+ method,
+ &f,
+ #ifndef Z7_ST
+ &affinityMode,
+ #endif
+ false, // showRating
+ NULL, false, 0);
+ RINOK(res)
+
+ if (ti != 0)
+ Print_Delimiter(f);
+
+ Bench_BW_Print_Usage_Speed(f, usage, speed);
+ speedTotals.Values[ti] += speed;
+ usageTotals.Values[ti] += usage;
+ }
+ else
+ {
+ {
+ unsigned keySize = 32;
+ if (IsString1PrefixedByString2(methodName, "AES128")) keySize = 16;
+ else if (IsString1PrefixedByString2(methodName, "AES192")) keySize = 24;
+ callback.BenchProps.KeySize = keySize;
+ }
+
+ COneMethodInfo method2 = method;
+ unsigned bench_DictBits;
+
+ if (benchIndex >= 0)
+ {
+ const CBenchMethod &bench = g_Bench[benchIndex];
+ callback.BenchProps.EncComplex = bench.EncComplex;
+ callback.BenchProps.DecComplexUnc = bench.DecComplexUnc;
+ callback.BenchProps.DecComplexCompr = bench.DecComplexCompr;
+ bench_DictBits = bench.DictBits;
+ // bench_DictBits = kOldLzmaDictBits; = 32 default : for debug
+ }
+ else
+ {
+ bench_DictBits = kOldLzmaDictBits; // = 32 default
+ if (isFilter)
+ {
+ const unsigned k_UnknownCoderComplexity = 4;
+ callback.BenchProps.EncComplex = k_UnknownCoderComplexity;
+ callback.BenchProps.DecComplexUnc = k_UnknownCoderComplexity;
+ }
+ else
+ {
+ callback.BenchProps.EncComplex = 1 << 10;
+ callback.BenchProps.DecComplexUnc = 1 << 6;
+ }
+ callback.BenchProps.DecComplexCompr = 0;
+ }
+ callback.NeedPrint = false;
+
+ if (StringsAreEqualNoCase_Ascii(method2.MethodName, "LZMA"))
+ {
+ const NCOM::CPropVariant propVariant = (UInt32)pow;
+ RINOK(method2.ParseMethodFromPROPVARIANT((UString)"d", propVariant))
+ }
+
+ const HRESULT res = MethodBench(
+ EXTERNAL_CODECS_LOC_VARS
+ complexInCommands,
+ #ifndef Z7_ST
+ false, // oldLzmaBenchMode
+ numThreadsVector[ti],
+ &affinityMode,
+ #endif
+ method2,
+ dataSize, (const Byte *)fileDataBuffer,
+ bench_DictBits,
+ printCallback,
+ &callback,
+ &callback.BenchProps);
+ RINOK(res)
+
+ if (ti != 0)
+ Print_Delimiter(f);
+
+ for (unsigned i = 0; i < 2; i++)
+ {
+ const CBenchInfo &bi = callback.BenchInfo_Results[i];
+ const UInt64 usage = bi.GetUsage();
+ const UInt64 speed = bi.GetUnpackSizeSpeed();
+ usageTotals.Values[ti * 2 + i] += usage;
+ speedTotals.Values[ti * 2 + i] += speed;
+ Bench_BW_Print_Usage_Speed(f, usage, speed);
+ }
+ }
+ }
+
+ f.NewLine();
+ numSteps++;
+ }
+ if (dataSize >= dict64)
+ break;
+ }
+
+ if (numSteps != 0)
+ {
+ f.Print("Avg:");
+ for (unsigned ti = 0; ti < numThreadsVector.Size(); ti++)
+ {
+ if (ti != 0)
+ Print_Delimiter(f);
+ for (unsigned i = 0; i < numColumns; i++)
+ Bench_BW_Print_Usage_Speed(f,
+ usageTotals.Values[ti * numColumns + i] / numSteps,
+ speedTotals.Values[ti * numColumns + i] / numSteps);
+ }
+ f.NewLine();
+ }
+
+ return S_OK;
+ }
+
+ bool use2Columns = false;
+
+ bool totalBenchMode = false;
+ bool onlyHashBench = false;
+ if (methodName.IsEqualTo_Ascii_NoCase("hash"))
+ {
+ onlyHashBench = true;
+ methodName = "*";
+ totalBenchMode = true;
+ }
+ else if (methodName.Find('*') >= 0)
+ totalBenchMode = true;
+
+ // ---------- Threads loop ----------
+ for (unsigned threadsPassIndex = 0; threadsPassIndex < 3; threadsPassIndex++)
+ {
+
+ UInt32 numThreads = numThreadsSpecified;
+
+ if (!multiThreadTests)
+ {
+ if (threadsPassIndex != 0)
+ break;
+ }
+ else
+ {
+ numThreads = 1;
+ if (threadsPassIndex != 0)
+ {
+ if (numCPUs < 2)
+ break;
+ numThreads = numCPUs;
+ if (threadsPassIndex == 1)
+ {
+ if (numCPUs >= 4)
+ numThreads = numCPUs / 2;
+ }
+ else if (numCPUs < 4)
+ break;
+ }
+ }
+
+ IBenchPrintCallback &f = *printCallback;
+
+ if (threadsPassIndex > 0)
+ {
+ f.NewLine();
+ f.NewLine();
+ }
+
+ if (!dictIsDefined && !onlyHashBench)
+ {
+ const unsigned dicSizeLog_Main = (totalBenchMode ? 24 : 25);
+ unsigned dicSizeLog = dicSizeLog_Main;
+
+ #ifdef UNDER_CE
+ dicSizeLog = (UInt64)1 << 20;
+ #endif
+
+ if (ramSize_Defined)
+ for (; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--)
+ if (GetBenchMemoryUsage(numThreads, (int)level, ((UInt64)1 << dicSizeLog), totalBenchMode) + (8 << 20) <= ramSize)
+ break;
+
+ dict = (UInt64)1 << dicSizeLog;
+
+ if (totalBenchMode && dicSizeLog != dicSizeLog_Main)
+ {
+ f.Print("Dictionary reduced to: ");
+ PrintNumber(f, dicSizeLog, 1);
+ f.NewLine();
+ }
+ }
+
+ Print_Usage_and_Threads(f,
+ onlyHashBench ?
+ GetBenchMemoryUsage_Hash(numThreads, dict) :
+ GetBenchMemoryUsage(numThreads, (int)level, dict, totalBenchMode),
+ numThreads);
+
+ f.NewLine();
+
+ f.NewLine();
+
+ if (totalBenchMode)
+ {
+ callback.NameFieldSize = kFieldSize_Name;
+ use2Columns = false;
+ }
+ else
+ {
+ callback.NameFieldSize = kFieldSize_SmallName;
+ use2Columns = true;
+ }
+ callback.Use2Columns = use2Columns;
+
+ bool showFreq = false;
+ UInt64 cpuFreq = 0;
+
+ if (totalBenchMode)
+ {
+ showFreq = true;
+ }
+
+ unsigned fileldSize = kFieldSize_TotalSize;
+ if (showFreq)
+ fileldSize += kFieldSize_EUAndEffec;
+
+ if (use2Columns)
+ {
+ PrintSpaces(f, callback.NameFieldSize);
+ PrintRight(f, "Compressing", fileldSize);
+ f.Print(kSep);
+ PrintRight(f, "Decompressing", fileldSize);
+ }
+ f.NewLine();
+ PrintLeft(f, totalBenchMode ? "Method" : "Dict", callback.NameFieldSize);
+
+ int j;
+
+ for (j = 0; j < 2; j++)
+ {
+ PrintRight(f, "Speed", kFieldSize_Speed + 1);
+ PrintRight(f, "Usage", kFieldSize_Usage + 1);
+ PrintRight(f, "R/U", kFieldSize_RU + 1);
+ PrintRight(f, "Rating", kFieldSize_Rating + 1);
+ if (showFreq)
+ {
+ PrintRight(f, "E/U", kFieldSize_EU + 1);
+ PrintRight(f, "Effec", kFieldSize_Effec + 1);
+ }
+ if (!use2Columns)
+ break;
+ if (j == 0)
+ f.Print(kSep);
+ }
+
+ f.NewLine();
+ PrintSpaces(f, callback.NameFieldSize);
+
+ for (j = 0; j < 2; j++)
+ {
+ PrintRight(f, "KiB/s", kFieldSize_Speed + 1);
+ PrintRight(f, "%", kFieldSize_Usage + 1);
+ PrintRight(f, "MIPS", kFieldSize_RU + 1);
+ PrintRight(f, "MIPS", kFieldSize_Rating + 1);
+ if (showFreq)
+ {
+ PrintRight(f, "%", kFieldSize_EU + 1);
+ PrintRight(f, "%", kFieldSize_Effec + 1);
+ }
+ if (!use2Columns)
+ break;
+ if (j == 0)
+ f.Print(kSep);
+ }
+
+ f.NewLine();
+ f.NewLine();
+
+ if (specifiedFreq != 0)
+ cpuFreq = specifiedFreq;
+
+ // bool showTotalSpeed = false;
+
+ if (totalBenchMode)
+ {
+ for (UInt32 i = 0; i < numIterations; i++)
+ {
+ if (i != 0)
+ printCallback->NewLine();
+
+ const unsigned kNumCpuTests = 3;
+ for (unsigned freqTest = 0; freqTest < kNumCpuTests; freqTest++)
+ {
+ PrintLeft(f, "CPU", kFieldSize_Name);
+
+ // UInt32 resVal;
+
+ CFreqBench fb;
+ fb.complexInCommands = complexInCommands;
+ fb.numThreads = numThreads;
+ // showFreq;
+ fb.showFreq = (freqTest == kNumCpuTests - 1 || specifiedFreq != 0);
+ fb.specifiedFreq = specifiedFreq;
+
+ const HRESULT res = fb.FreqBench(printCallback
+ #ifndef Z7_ST
+ , &affinityMode
+ #endif
+ );
+ RINOK(res)
+
+ cpuFreq = fb.CpuFreqRes;
+ callback.NewLine();
+
+ if (specifiedFreq != 0)
+ cpuFreq = specifiedFreq;
+
+ if (testTimeMs >= 1000)
+ if (freqTest == kNumCpuTests - 1)
+ {
+ // SetComplexCommandsMs(testTimeMs, specifiedFreq != 0, cpuFreq, complexInCommands);
+ }
+ }
+ callback.NewLine();
+
+ // return S_OK; // change it
+
+ callback.SetFreq(true, cpuFreq);
+
+ if (!onlyHashBench)
+ {
+ size_t dataSize = (size_t)dict;
+ if (use_fileData)
+ {
+ dataSize = fileDataBuffer.Size();
+ if (dictIsDefined && dataSize > dict)
+ dataSize = (size_t)dict;
+ }
+
+ const HRESULT res = TotalBench(EXTERNAL_CODECS_LOC_VARS
+ method, complexInCommands,
+ #ifndef Z7_ST
+ numThreads,
+ &affinityMode,
+ #endif
+ dictIsDefined || use_fileData, // forceUnpackSize
+ dataSize,
+ (const Byte *)fileDataBuffer,
+ printCallback, &callback);
+ RINOK(res)
+ }
+
+ {
+ size_t dataSize = (size_t)1 << kNumHashDictBits;
+ if (dictIsDefined)
+ {
+ dataSize = (size_t)dict;
+ if (dataSize != dict)
+ return E_OUTOFMEMORY;
+ }
+ if (use_fileData)
+ {
+ dataSize = fileDataBuffer.Size();
+ if (dictIsDefined && dataSize > dict)
+ dataSize = (size_t)dict;
+ }
+
+ const HRESULT res = TotalBench_Hash(EXTERNAL_CODECS_LOC_VARS
+ method, complexInCommands,
+ numThreads,
+ dataSize, (const Byte *)fileDataBuffer,
+ printCallback, &callback,
+ #ifndef Z7_ST
+ &affinityMode,
+ #endif
+ &callback.EncodeRes, true, cpuFreq);
+ RINOK(res)
+ }
+
+ callback.NewLine();
+ {
+ PrintLeft(f, "CPU", kFieldSize_Name);
+
+ CFreqBench fb;
+ fb.complexInCommands = complexInCommands;
+ fb.numThreads = numThreads;
+ // showFreq;
+ fb.showFreq = (specifiedFreq != 0);
+ fb.specifiedFreq = specifiedFreq;
+
+ const HRESULT res = fb.FreqBench(printCallback
+ #ifndef Z7_ST
+ , &affinityMode
+ #endif
+ );
+ RINOK(res)
+ callback.NewLine();
+ }
+ }
+ }
+ else
+ {
+ needSetComplexity = true;
+ if (!methodName.IsEqualTo_Ascii_NoCase("LZMA"))
+ {
+ unsigned i;
+ for (i = 0; i < Z7_ARRAY_SIZE(g_Bench); i++)
+ {
+ const CBenchMethod &h = g_Bench[i];
+ AString benchMethod (h.Name);
+ AString benchProps;
+ const int propPos = benchMethod.Find(':');
+ if (propPos >= 0)
+ {
+ benchProps = benchMethod.Ptr((unsigned)(propPos + 1));
+ benchMethod.DeleteFrom((unsigned)propPos);
+ }
+
+ if (AreSameMethodNames(benchMethod, methodName))
+ {
+ if (benchProps.IsEmpty()
+ || (benchProps == "x5" && method.PropsString.IsEmpty())
+ || method.PropsString.IsPrefixedBy_Ascii_NoCase(benchProps))
+ {
+ callback.BenchProps.EncComplex = h.EncComplex;
+ callback.BenchProps.DecComplexCompr = h.DecComplexCompr;
+ callback.BenchProps.DecComplexUnc = h.DecComplexUnc;
+ needSetComplexity = false;
+ break;
+ }
+ }
+ }
+ /*
+ if (i == Z7_ARRAY_SIZE(g_Bench))
+ return E_NOTIMPL;
+ */
+ }
+ if (needSetComplexity)
+ callback.BenchProps.SetLzmaCompexity();
+
+ if (startDicLog < kBenchMinDicLogSize)
+ startDicLog = kBenchMinDicLogSize;
+
+ for (unsigned i = 0; i < numIterations; i++)
+ {
+ unsigned pow = (dict < GetDictSizeFromLog(startDicLog)) ? kBenchMinDicLogSize : (unsigned)startDicLog;
+ if (!multiDict)
+ pow = 32;
+ while (GetDictSizeFromLog(pow) > dict && pow > 0)
+ pow--;
+ for (; GetDictSizeFromLog(pow) <= dict; pow++)
+ {
+ Print_Pow(f, pow);
+ callback.DictSize = (UInt64)1 << pow;
+
+ COneMethodInfo method2 = method;
+
+ if (StringsAreEqualNoCase_Ascii(method2.MethodName, "LZMA"))
+ {
+ // We add dictionary size property.
+ // method2 can have two different dictionary size properties.
+ // And last property is main.
+ NCOM::CPropVariant propVariant = (UInt32)pow;
+ RINOK(method2.ParseMethodFromPROPVARIANT((UString)"d", propVariant))
+ }
+
+ size_t uncompressedDataSize;
+ if (use_fileData)
+ {
+ uncompressedDataSize = fileDataBuffer.Size();
+ }
+ else
+ {
+ uncompressedDataSize = (size_t)callback.DictSize;
+ if (uncompressedDataSize != callback.DictSize)
+ return E_OUTOFMEMORY;
+ if (uncompressedDataSize >= (1 << 18))
+ uncompressedDataSize += kAdditionalSize;
+ }
+
+ const HRESULT res = MethodBench(
+ EXTERNAL_CODECS_LOC_VARS
+ complexInCommands,
+ #ifndef Z7_ST
+ true, numThreads,
+ &affinityMode,
+ #endif
+ method2,
+ uncompressedDataSize, (const Byte *)fileDataBuffer,
+ kOldLzmaDictBits, printCallback, &callback, &callback.BenchProps);
+ f.NewLine();
+ RINOK(res)
+ if (!multiDict)
+ break;
+ }
+ }
+ }
+
+ PrintChars(f, '-', callback.NameFieldSize + fileldSize);
+
+ if (use2Columns)
+ {
+ f.Print(kSep);
+ PrintChars(f, '-', fileldSize);
+ }
+
+ f.NewLine();
+
+ if (use2Columns)
+ {
+ PrintLeft(f, "Avr:", callback.NameFieldSize);
+ PrintTotals(f, showFreq, cpuFreq, !totalBenchMode, callback.EncodeRes);
+ f.Print(kSep);
+ PrintTotals(f, showFreq, cpuFreq, !totalBenchMode, callback.DecodeRes);
+ f.NewLine();
+ }
+
+ PrintLeft(f, "Tot:", callback.NameFieldSize);
+ CTotalBenchRes midRes;
+ midRes = callback.EncodeRes;
+ midRes.Update_With_Res(callback.DecodeRes);
+
+ // midRes.SetSum(callback.EncodeRes, callback.DecodeRes);
+ PrintTotals(f, showFreq, cpuFreq, false, midRes);
+ f.NewLine();
+
+ }
+ return S_OK;
+}
diff --git a/CPP/7zip/UI/Common/Bench.h b/CPP/7zip/UI/Common/Bench.h
index 1d052aa..313676d 100644
--- a/CPP/7zip/UI/Common/Bench.h
+++ b/CPP/7zip/UI/Common/Bench.h
@@ -1,77 +1,121 @@
-// Bench.h
-
-#ifndef __7ZIP_BENCH_H
-#define __7ZIP_BENCH_H
-
-#include "../../../Windows/System.h"
-
-#include "../../Common/CreateCoder.h"
-#include "../../UI/Common/Property.h"
-
-struct CBenchInfo
-{
- UInt64 GlobalTime;
- UInt64 GlobalFreq;
- UInt64 UserTime;
- UInt64 UserFreq;
- UInt64 UnpackSize;
- UInt64 PackSize;
- UInt64 NumIterations;
-
- CBenchInfo(): NumIterations(0) {}
- UInt64 GetUsage() const;
- UInt64 GetRatingPerUsage(UInt64 rating) const;
- UInt64 GetSpeed(UInt64 numCommands) const;
-};
-
-struct IBenchCallback
-{
- virtual HRESULT SetFreq(bool showFreq, UInt64 cpuFreq) = 0;
- virtual HRESULT SetEncodeResult(const CBenchInfo &info, bool final) = 0;
- virtual HRESULT SetDecodeResult(const CBenchInfo &info, bool final) = 0;
-};
-
-UInt64 GetCompressRating(UInt32 dictSize, UInt64 elapsedTime, UInt64 freq, UInt64 size);
-UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 freq, UInt64 outSize, UInt64 inSize, UInt64 numIterations);
-
-const unsigned kBenchMinDicLogSize = 18;
-
-UInt64 GetBenchMemoryUsage(UInt32 numThreads, UInt32 dictionary, bool totalBench = false);
-
-struct IBenchPrintCallback
-{
- virtual void Print(const char *s) = 0;
- virtual void NewLine() = 0;
- virtual HRESULT CheckBreak() = 0;
-};
-
-/*
-struct IBenchFreqCallback
-{
- virtual void AddCpuFreq(UInt64 freq) = 0;
-};
-*/
-
-HRESULT Bench(
- DECL_EXTERNAL_CODECS_LOC_VARS
- IBenchPrintCallback *printCallback,
- IBenchCallback *benchCallback,
- // IBenchFreqCallback *freqCallback,
- const CObjectVector<CProperty> &props,
- UInt32 numIterations,
- bool multiDict
- );
-
-AString GetProcessThreadsInfo(const NWindows::NSystem::CProcessAffinity &ti);
-
-void GetSysInfo(AString &s1, AString &s2);
-void GetCpuName(AString &s);
-void GetCpuFeatures(AString &s);
-
-#ifdef _7ZIP_LARGE_PAGES
-void Add_LargePages_String(AString &s);
-#else
-// #define Add_LargePages_String
-#endif
-
-#endif
+// Bench.h
+
+#ifndef ZIP7_INC_7ZIP_BENCH_H
+#define ZIP7_INC_7ZIP_BENCH_H
+
+#include "../../../Windows/System.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../UI/Common/Property.h"
+
+UInt64 Benchmark_GetUsage_Percents(UInt64 usage);
+
+struct CBenchInfo
+{
+ UInt64 GlobalTime;
+ UInt64 GlobalFreq;
+ UInt64 UserTime;
+ UInt64 UserFreq;
+ UInt64 UnpackSize;
+ UInt64 PackSize;
+ UInt64 NumIterations;
+
+ /*
+ during Code(): we track benchInfo only from one thread (theads with index[0])
+ NumIterations means number of threads
+ UnpackSize and PackSize are total sizes of all iterations of current thread
+ after Code():
+ NumIterations means the number of Iterations
+ UnpackSize and PackSize are total sizes of all threads
+ */
+
+ CBenchInfo(): NumIterations(0) {}
+
+ UInt64 GetUsage() const;
+ UInt64 GetRatingPerUsage(UInt64 rating) const;
+ UInt64 GetSpeed(UInt64 numUnits) const;
+ UInt64 GetUnpackSizeSpeed() const { return GetSpeed(UnpackSize * NumIterations); }
+
+ UInt64 Get_UnpackSize_Full() const { return UnpackSize * NumIterations; }
+
+ UInt64 GetRating_LzmaEnc(UInt64 dictSize) const;
+ UInt64 GetRating_LzmaDec() const;
+};
+
+
+struct CTotalBenchRes
+{
+ // UInt64 NumIterations1; // for Usage
+ UInt64 NumIterations2; // for Rating / RPU
+
+ UInt64 Rating;
+ UInt64 Usage;
+ UInt64 RPU;
+ UInt64 Speed;
+
+ void Init() { /* NumIterations1 = 0; */ NumIterations2 = 0; Rating = 0; Usage = 0; RPU = 0; Speed = 0; }
+
+ void SetSum(const CTotalBenchRes &r1, const CTotalBenchRes &r2)
+ {
+ Rating = (r1.Rating + r2.Rating);
+ Usage = (r1.Usage + r2.Usage);
+ RPU = (r1.RPU + r2.RPU);
+ Speed = (r1.Speed + r2.Speed);
+ // NumIterations1 = (r1.NumIterations1 + r2.NumIterations1);
+ NumIterations2 = (r1.NumIterations2 + r2.NumIterations2);
+ }
+
+ void Generate_From_BenchInfo(const CBenchInfo &info);
+ void Mult_For_Weight(unsigned weight);
+ void Update_With_Res(const CTotalBenchRes &r);
+};
+
+
+const unsigned kBenchMinDicLogSize = 18;
+
+UInt64 GetBenchMemoryUsage(UInt32 numThreads, int level, UInt64 dictionary, bool totalBench);
+
+Z7_PURE_INTERFACES_BEGIN
+DECLARE_INTERFACE(IBenchCallback)
+{
+ // virtual HRESULT SetFreq(bool showFreq, UInt64 cpuFreq) = 0;
+ virtual HRESULT SetEncodeResult(const CBenchInfo &info, bool final) = 0;
+ virtual HRESULT SetDecodeResult(const CBenchInfo &info, bool final) = 0;
+};
+
+DECLARE_INTERFACE(IBenchPrintCallback)
+{
+ virtual void Print(const char *s) = 0;
+ virtual void NewLine() = 0;
+ virtual HRESULT CheckBreak() = 0;
+};
+
+DECLARE_INTERFACE(IBenchFreqCallback)
+{
+ virtual HRESULT AddCpuFreq(unsigned numThreads, UInt64 freq, UInt64 usage) = 0;
+ virtual HRESULT FreqsFinished(unsigned numThreads) = 0;
+};
+Z7_PURE_INTERFACES_END
+
+HRESULT Bench(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ IBenchPrintCallback *printCallback,
+ IBenchCallback *benchCallback,
+ const CObjectVector<CProperty> &props,
+ UInt32 numIterations,
+ bool multiDict,
+ IBenchFreqCallback *freqCallback = NULL);
+
+AString GetProcessThreadsInfo(const NWindows::NSystem::CProcessAffinity &ti);
+
+void GetSysInfo(AString &s1, AString &s2);
+void GetCpuName(AString &s);
+void AddCpuFeatures(AString &s);
+
+#ifdef Z7_LARGE_PAGES
+void Add_LargePages_String(AString &s);
+#else
+// #define Add_LargePages_String
+#endif
+
+#endif
diff --git a/CPP/7zip/UI/Common/CompressCall.cpp b/CPP/7zip/UI/Common/CompressCall.cpp
new file mode 100644
index 0000000..42bae2a
--- /dev/null
+++ b/CPP/7zip/UI/Common/CompressCall.cpp
@@ -0,0 +1,343 @@
+// CompressCall.cpp
+
+#include "StdAfx.h"
+
+#include <wchar.h>
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/MyCom.h"
+#include "../../../Common/Random.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileMapping.h"
+#include "../../../Windows/MemoryLock.h"
+#include "../../../Windows/ProcessUtils.h"
+#include "../../../Windows/Synchronization.h"
+
+#include "../FileManager/RegistryUtils.h"
+
+#include "CompressCall.h"
+
+using namespace NWindows;
+
+#define MY_TRY_BEGIN try {
+
+#define MY_TRY_FINISH } \
+ catch(...) { ErrorMessageHRESULT(E_FAIL); return E_FAIL; }
+
+#define MY_TRY_FINISH_VOID } \
+ catch(...) { ErrorMessageHRESULT(E_FAIL); }
+
+#define k7zGui "7zG.exe"
+
+// 21.07 : we can disable wildcard
+// #define ISWITCH_NO_WILDCARD_POSTFIX "w-"
+#define ISWITCH_NO_WILDCARD_POSTFIX
+
+#define kShowDialogSwitch " -ad"
+#define kEmailSwitch " -seml."
+#define kArchiveTypeSwitch " -t"
+#define kIncludeSwitch " -i" ISWITCH_NO_WILDCARD_POSTFIX
+#define kArcIncludeSwitches " -an -ai" ISWITCH_NO_WILDCARD_POSTFIX
+#define kHashIncludeSwitches kIncludeSwitch
+#define kStopSwitchParsing " --"
+
+extern HWND g_HWND;
+
+UString GetQuotedString(const UString &s)
+{
+ UString s2 ('\"');
+ s2 += s;
+ s2 += '\"';
+ return s2;
+}
+
+static void ErrorMessage(LPCWSTR message)
+{
+ MessageBoxW(g_HWND, message, L"7-Zip", MB_ICONERROR | MB_OK);
+}
+
+static void ErrorMessageHRESULT(HRESULT res, LPCWSTR s = NULL)
+{
+ UString s2 = NError::MyFormatMessage(res);
+ if (s)
+ {
+ s2.Add_LF();
+ s2 += s;
+ }
+ ErrorMessage(s2);
+}
+
+static HRESULT Call7zGui(const UString &params,
+ // LPCWSTR curDir,
+ bool waitFinish,
+ NSynchronization::CBaseEvent *event)
+{
+ UString imageName = fs2us(NWindows::NDLL::GetModuleDirPrefix());
+ imageName += k7zGui;
+
+ CProcess process;
+ const WRes wres = process.Create(imageName, params, NULL); // curDir);
+ if (wres != 0)
+ {
+ const HRESULT hres = HRESULT_FROM_WIN32(wres);
+ ErrorMessageHRESULT(hres, imageName);
+ return hres;
+ }
+ if (waitFinish)
+ process.Wait();
+ else if (event != NULL)
+ {
+ HANDLE handles[] = { process, *event };
+ ::WaitForMultipleObjects(Z7_ARRAY_SIZE(handles), handles, FALSE, INFINITE);
+ }
+ return S_OK;
+}
+
+static void AddLagePagesSwitch(UString &params)
+{
+ if (ReadLockMemoryEnable())
+ #ifndef UNDER_CE
+ if (NSecurity::Get_LargePages_RiskLevel() == 0)
+ #endif
+ params += " -slp";
+}
+
+class CRandNameGenerator
+{
+ CRandom _random;
+public:
+ CRandNameGenerator() { _random.Init(); }
+ void GenerateName(UString &s, const char *prefix)
+ {
+ s += prefix;
+ s.Add_UInt32((UInt32)(unsigned)_random.Generate());
+ }
+};
+
+static HRESULT CreateMap(const UStringVector &names,
+ CFileMapping &fileMapping, NSynchronization::CManualResetEvent &event,
+ UString &params)
+{
+ size_t totalSize = 1;
+ {
+ FOR_VECTOR (i, names)
+ totalSize += (names[i].Len() + 1);
+ }
+ totalSize *= sizeof(wchar_t);
+
+ CRandNameGenerator random;
+
+ UString mappingName;
+ for (;;)
+ {
+ random.GenerateName(mappingName, "7zMap");
+ const WRes wres = fileMapping.Create(PAGE_READWRITE, totalSize, GetSystemString(mappingName));
+ if (fileMapping.IsCreated() && wres == 0)
+ break;
+ if (wres != ERROR_ALREADY_EXISTS)
+ return HRESULT_FROM_WIN32(wres);
+ fileMapping.Close();
+ }
+
+ UString eventName;
+ for (;;)
+ {
+ random.GenerateName(eventName, "7zEvent");
+ const WRes wres = event.CreateWithName(false, GetSystemString(eventName));
+ if (event.IsCreated() && wres == 0)
+ break;
+ if (wres != ERROR_ALREADY_EXISTS)
+ return HRESULT_FROM_WIN32(wres);
+ event.Close();
+ }
+
+ params += '#';
+ params += mappingName;
+ params += ':';
+ char temp[32];
+ ConvertUInt64ToString(totalSize, temp);
+ params += temp;
+
+ params += ':';
+ params += eventName;
+
+ LPVOID data = fileMapping.Map(FILE_MAP_WRITE, 0, totalSize);
+ if (!data)
+ return E_FAIL;
+ CFileUnmapper unmapper(data);
+ {
+ wchar_t *cur = (wchar_t *)data;
+ *cur++ = 0; // it means wchar_t strings (UTF-16 in WIN32)
+ FOR_VECTOR (i, names)
+ {
+ const UString &s = names[i];
+ const unsigned len = s.Len() + 1;
+ wmemcpy(cur, (const wchar_t *)s, len);
+ cur += len;
+ }
+ }
+ return S_OK;
+}
+
+HRESULT CompressFiles(
+ const UString &arcPathPrefix,
+ const UString &arcName,
+ const UString &arcType,
+ bool addExtension,
+ const UStringVector &names,
+ bool email, bool showDialog, bool waitFinish)
+{
+ MY_TRY_BEGIN
+ UString params ('a');
+
+ CFileMapping fileMapping;
+ NSynchronization::CManualResetEvent event;
+ params += kIncludeSwitch;
+ RINOK(CreateMap(names, fileMapping, event, params))
+
+ if (!arcType.IsEmpty())
+ {
+ params += kArchiveTypeSwitch;
+ params += arcType;
+ }
+
+ if (email)
+ params += kEmailSwitch;
+
+ if (showDialog)
+ params += kShowDialogSwitch;
+
+ AddLagePagesSwitch(params);
+
+ if (arcName.IsEmpty())
+ params += " -an";
+
+ if (addExtension)
+ params += " -saa";
+ else
+ params += " -sae";
+
+ params += kStopSwitchParsing;
+ params.Add_Space();
+
+ if (!arcName.IsEmpty())
+ {
+ params += GetQuotedString(
+ // #ifdef UNDER_CE
+ arcPathPrefix +
+ // #endif
+ arcName);
+ }
+
+ return Call7zGui(params,
+ // (arcPathPrefix.IsEmpty()? 0: (LPCWSTR)arcPathPrefix),
+ waitFinish, &event);
+ MY_TRY_FINISH
+}
+
+static void ExtractGroupCommand(const UStringVector &arcPaths, UString &params, bool isHash)
+{
+ AddLagePagesSwitch(params);
+ params += (isHash ? kHashIncludeSwitches : kArcIncludeSwitches);
+ CFileMapping fileMapping;
+ NSynchronization::CManualResetEvent event;
+ HRESULT result = CreateMap(arcPaths, fileMapping, event, params);
+ if (result == S_OK)
+ result = Call7zGui(params, false, &event);
+ if (result != S_OK)
+ ErrorMessageHRESULT(result);
+}
+
+void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup, UInt32 writeZone)
+{
+ MY_TRY_BEGIN
+ UString params ('x');
+ if (!outFolder.IsEmpty())
+ {
+ params += " -o";
+ params += GetQuotedString(outFolder);
+ }
+ if (elimDup)
+ params += " -spe";
+ if (writeZone != (UInt32)(Int32)-1)
+ {
+ params += " -snz";
+ params.Add_UInt32(writeZone);
+ }
+ if (showDialog)
+ params += kShowDialogSwitch;
+ ExtractGroupCommand(arcPaths, params, false);
+ MY_TRY_FINISH_VOID
+}
+
+
+void TestArchives(const UStringVector &arcPaths, bool hashMode)
+{
+ MY_TRY_BEGIN
+ UString params ('t');
+ if (hashMode)
+ {
+ params += kArchiveTypeSwitch;
+ params += "hash";
+ }
+ ExtractGroupCommand(arcPaths, params, false);
+ MY_TRY_FINISH_VOID
+}
+
+
+void CalcChecksum(const UStringVector &paths,
+ const UString &methodName,
+ const UString &arcPathPrefix,
+ const UString &arcFileName)
+{
+ MY_TRY_BEGIN
+
+ if (!arcFileName.IsEmpty())
+ {
+ CompressFiles(
+ arcPathPrefix,
+ arcFileName,
+ UString("hash"),
+ false, // addExtension,
+ paths,
+ false, // email,
+ false, // showDialog,
+ false // waitFinish
+ );
+ return;
+ }
+
+ UString params ('h');
+ if (!methodName.IsEmpty())
+ {
+ params += " -scrc";
+ params += methodName;
+ /*
+ if (!arcFileName.IsEmpty())
+ {
+ // not used alternate method of generating file
+ params += " -scrf=";
+ params += GetQuotedString(arcPathPrefix + arcFileName);
+ }
+ */
+ }
+ ExtractGroupCommand(paths, params, true);
+ MY_TRY_FINISH_VOID
+}
+
+void Benchmark(bool totalMode)
+{
+ MY_TRY_BEGIN
+ UString params ('b');
+ if (totalMode)
+ params += " -mm=*";
+ AddLagePagesSwitch(params);
+ const HRESULT result = Call7zGui(params, false, NULL);
+ if (result != S_OK)
+ ErrorMessageHRESULT(result);
+ MY_TRY_FINISH_VOID
+}
diff --git a/CPP/7zip/UI/Common/CompressCall.h b/CPP/7zip/UI/Common/CompressCall.h
new file mode 100644
index 0000000..f2da163
--- /dev/null
+++ b/CPP/7zip/UI/Common/CompressCall.h
@@ -0,0 +1,28 @@
+// CompressCall.h
+
+#ifndef ZIP7_INC_COMPRESS_CALL_H
+#define ZIP7_INC_COMPRESS_CALL_H
+
+#include "../../../Common/MyString.h"
+
+UString GetQuotedString(const UString &s);
+
+HRESULT CompressFiles(
+ const UString &arcPathPrefix,
+ const UString &arcName,
+ const UString &arcType,
+ bool addExtension,
+ const UStringVector &names,
+ bool email, bool showDialog, bool waitFinish);
+
+void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder, bool showDialog, bool elimDup, UInt32 writeZone);
+void TestArchives(const UStringVector &arcPaths, bool hashMode = false);
+
+void CalcChecksum(const UStringVector &paths,
+ const UString &methodName,
+ const UString &arcPathPrefix,
+ const UString &arcFileName);
+
+void Benchmark(bool totalMode);
+
+#endif
diff --git a/CPP/7zip/UI/Common/CompressCall2.cpp b/CPP/7zip/UI/Common/CompressCall2.cpp
new file mode 100644
index 0000000..21eb472
--- /dev/null
+++ b/CPP/7zip/UI/Common/CompressCall2.cpp
@@ -0,0 +1,327 @@
+// CompressCall2.cpp
+
+#include "StdAfx.h"
+
+#ifndef Z7_EXTERNAL_CODECS
+
+#include "../../../Common/MyException.h"
+
+#include "../../UI/Common/EnumDirItems.h"
+
+#include "../../UI/FileManager/LangUtils.h"
+
+#include "../../UI/GUI/BenchmarkDialog.h"
+#include "../../UI/GUI/ExtractGUI.h"
+#include "../../UI/GUI/UpdateGUI.h"
+#include "../../UI/GUI/HashGUI.h"
+
+#include "../../UI/GUI/ExtractRes.h"
+
+#include "CompressCall.h"
+
+extern HWND g_HWND;
+
+#define MY_TRY_BEGIN HRESULT result; try {
+#define MY_TRY_FINISH } \
+ catch(CSystemException &e) { result = e.ErrorCode; } \
+ catch(UString &s) { ErrorMessage(s); result = E_FAIL; } \
+ catch(...) { result = E_FAIL; } \
+ if (result != S_OK && result != E_ABORT) \
+ ErrorMessageHRESULT(result);
+
+static void ThrowException_if_Error(HRESULT res)
+{
+ if (res != S_OK)
+ throw CSystemException(res);
+}
+
+#ifdef Z7_EXTERNAL_CODECS
+
+#define CREATE_CODECS \
+ CCodecs *codecs = new CCodecs; \
+ CMyComPtr<ICompressCodecsInfo> compressCodecsInfo = codecs; \
+ ThrowException_if_Error(codecs->Load()); \
+ Codecs_AddHashArcHandler(codecs);
+
+#define LOAD_EXTERNAL_CODECS \
+ CExternalCodecs _externalCodecs; \
+ _externalCodecs.GetCodecs = codecs; \
+ _externalCodecs.GetHashers = codecs; \
+ ThrowException_if_Error(_externalCodecs.Load());
+
+#else
+
+#define CREATE_CODECS \
+ CCodecs *codecs = new CCodecs; \
+ CMyComPtr<IUnknown> compressCodecsInfo = codecs; \
+ ThrowException_if_Error(codecs->Load()); \
+ Codecs_AddHashArcHandler(codecs);
+
+#define LOAD_EXTERNAL_CODECS
+
+#endif
+
+
+
+
+UString GetQuotedString(const UString &s)
+{
+ UString s2 ('\"');
+ s2 += s;
+ s2 += '\"';
+ return s2;
+}
+
+static void ErrorMessage(LPCWSTR message)
+{
+ MessageBoxW(g_HWND, message, L"7-Zip", MB_ICONERROR);
+}
+
+static void ErrorMessageHRESULT(HRESULT res)
+{
+ ErrorMessage(HResultToMessage(res));
+}
+
+static void ErrorLangMessage(UINT resourceID)
+{
+ ErrorMessage(LangString(resourceID));
+}
+
+HRESULT CompressFiles(
+ const UString &arcPathPrefix,
+ const UString &arcName,
+ const UString &arcType,
+ bool addExtension,
+ const UStringVector &names,
+ bool email, bool showDialog, bool /* waitFinish */)
+{
+ MY_TRY_BEGIN
+
+ CREATE_CODECS
+
+ CUpdateCallbackGUI callback;
+
+ callback.Init();
+
+ CUpdateOptions uo;
+ uo.EMailMode = email;
+ uo.SetActionCommand_Add();
+
+ uo.ArcNameMode = (addExtension ? k_ArcNameMode_Add : k_ArcNameMode_Exact);
+
+ CObjectVector<COpenType> formatIndices;
+ if (!ParseOpenTypes(*codecs, arcType, formatIndices))
+ {
+ ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE);
+ return E_FAIL;
+ }
+ const UString arcPath = arcPathPrefix + arcName;
+ if (!uo.InitFormatIndex(codecs, formatIndices, arcPath) ||
+ !uo.SetArcPath(codecs, arcPath))
+ {
+ ErrorLangMessage(IDS_UPDATE_NOT_SUPPORTED);
+ return E_FAIL;
+ }
+
+ NWildcard::CCensor censor;
+ FOR_VECTOR (i, names)
+ {
+ censor.AddPreItem_NoWildcard(names[i]);
+ }
+
+ bool messageWasDisplayed = false;
+
+ result = UpdateGUI(codecs,
+ formatIndices, arcPath,
+ censor, uo, showDialog, messageWasDisplayed, &callback, g_HWND);
+
+ if (result != S_OK)
+ {
+ if (result != E_ABORT && messageWasDisplayed)
+ return E_FAIL;
+ throw CSystemException(result);
+ }
+ if (callback.FailedFiles.Size() > 0)
+ {
+ if (!messageWasDisplayed)
+ throw CSystemException(E_FAIL);
+ return E_FAIL;
+ }
+
+ MY_TRY_FINISH
+ return S_OK;
+}
+
+
+static HRESULT ExtractGroupCommand(const UStringVector &arcPaths,
+ bool showDialog, CExtractOptions &eo, const char *kType = NULL)
+{
+ MY_TRY_BEGIN
+
+ CREATE_CODECS
+
+ CExtractCallbackImp *ecs = new CExtractCallbackImp;
+ CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
+
+ ecs->Init();
+
+ // eo.CalcCrc = options.CalcCrc;
+
+ UStringVector arcPathsSorted;
+ UStringVector arcFullPathsSorted;
+ {
+ NWildcard::CCensor arcCensor;
+ FOR_VECTOR (i, arcPaths)
+ {
+ arcCensor.AddPreItem_NoWildcard(arcPaths[i]);
+ }
+ arcCensor.AddPathsToCensor(NWildcard::k_RelatPath);
+ CDirItemsStat st;
+ EnumerateDirItemsAndSort(arcCensor, NWildcard::k_RelatPath, UString(),
+ arcPathsSorted, arcFullPathsSorted,
+ st,
+ NULL // &scan: change it!!!!
+ );
+ }
+
+ CObjectVector<COpenType> formatIndices;
+ if (kType)
+ {
+ if (!ParseOpenTypes(*codecs, UString(kType), formatIndices))
+ {
+ throw CSystemException(E_INVALIDARG);
+ // ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE);
+ // return E_INVALIDARG;
+ }
+ }
+
+ NWildcard::CCensor censor;
+ {
+ censor.AddPreItem_Wildcard();
+ }
+
+ censor.AddPathsToCensor(NWildcard::k_RelatPath);
+
+ bool messageWasDisplayed = false;
+
+ ecs->MultiArcMode = (arcPathsSorted.Size() > 1);
+
+ result = ExtractGUI(codecs,
+ formatIndices, CIntVector(),
+ arcPathsSorted, arcFullPathsSorted,
+ censor.Pairs.Front().Head, eo, NULL, showDialog, messageWasDisplayed, ecs, g_HWND);
+
+ if (result != S_OK)
+ {
+ if (result != E_ABORT && messageWasDisplayed)
+ return E_FAIL;
+ throw CSystemException(result);
+ }
+ return ecs->IsOK() ? S_OK : E_FAIL;
+
+ MY_TRY_FINISH
+ return result;
+}
+
+void ExtractArchives(const UStringVector &arcPaths, const UString &outFolder,
+ bool showDialog, bool elimDup, UInt32 writeZone)
+{
+ CExtractOptions eo;
+ eo.OutputDir = us2fs(outFolder);
+ eo.TestMode = false;
+ eo.ElimDup.Val = elimDup;
+ eo.ElimDup.Def = elimDup;
+ if (writeZone != (UInt32)(Int32)-1)
+ eo.ZoneMode = (NExtract::NZoneIdMode::EEnum)writeZone;
+ ExtractGroupCommand(arcPaths, showDialog, eo);
+}
+
+void TestArchives(const UStringVector &arcPaths, bool hashMode)
+{
+ CExtractOptions eo;
+ eo.TestMode = true;
+ ExtractGroupCommand(arcPaths,
+ true, // showDialog
+ eo,
+ hashMode ? "hash" : NULL);
+}
+
+void CalcChecksum(const UStringVector &paths,
+ const UString &methodName,
+ const UString &arcPathPrefix,
+ const UString &arcFileName)
+{
+ MY_TRY_BEGIN
+
+ if (!arcFileName.IsEmpty())
+ {
+ CompressFiles(
+ arcPathPrefix,
+ arcFileName,
+ UString("hash"),
+ false, // addExtension,
+ paths,
+ false, // email,
+ false, // showDialog,
+ false // waitFinish
+ );
+ return;
+ }
+
+ CREATE_CODECS
+ LOAD_EXTERNAL_CODECS
+
+ NWildcard::CCensor censor;
+ FOR_VECTOR (i, paths)
+ {
+ censor.AddPreItem_NoWildcard(paths[i]);
+ }
+
+ censor.AddPathsToCensor(NWildcard::k_RelatPath);
+ bool messageWasDisplayed = false;
+
+ CHashOptions options;
+ options.Methods.Add(methodName);
+
+ /*
+ if (!arcFileName.IsEmpty())
+ options.HashFilePath = arcPathPrefix + arcFileName;
+ */
+
+ result = HashCalcGUI(EXTERNAL_CODECS_VARS_L censor, options, messageWasDisplayed);
+ if (result != S_OK)
+ {
+ if (result != E_ABORT && messageWasDisplayed)
+ return; // E_FAIL;
+ throw CSystemException(result);
+ }
+
+ MY_TRY_FINISH
+ return; // result;
+}
+
+void Benchmark(bool totalMode)
+{
+ MY_TRY_BEGIN
+
+ CREATE_CODECS
+ LOAD_EXTERNAL_CODECS
+
+ CObjectVector<CProperty> props;
+ if (totalMode)
+ {
+ CProperty prop;
+ prop.Name = "m";
+ prop.Value = "*";
+ props.Add(prop);
+ }
+ result = Benchmark(
+ EXTERNAL_CODECS_VARS_L
+ props,
+ k_NumBenchIterations_Default,
+ g_HWND);
+
+ MY_TRY_FINISH
+}
+
+#endif
diff --git a/CPP/7zip/UI/Common/DefaultName.cpp b/CPP/7zip/UI/Common/DefaultName.cpp
index 0c13e9e..8c34ffc 100644
--- a/CPP/7zip/UI/Common/DefaultName.cpp
+++ b/CPP/7zip/UI/Common/DefaultName.cpp
@@ -1,37 +1,37 @@
-// DefaultName.cpp
-
-#include "StdAfx.h"
-
-#include "DefaultName.h"
-
-static UString GetDefaultName3(const UString &fileName,
- const UString &extension, const UString &addSubExtension)
-{
- const unsigned extLen = extension.Len();
- const unsigned fileNameLen = fileName.Len();
-
- if (fileNameLen > extLen + 1)
- {
- const unsigned dotPos = fileNameLen - (extLen + 1);
- if (fileName[dotPos] == '.')
- if (extension.IsEqualTo_NoCase(fileName.Ptr(dotPos + 1)))
- return fileName.Left(dotPos) + addSubExtension;
- }
-
- int dotPos = fileName.ReverseFind_Dot();
- if (dotPos > 0)
- return fileName.Left(dotPos) + addSubExtension;
-
- if (addSubExtension.IsEmpty())
- return fileName + L'~';
- else
- return fileName + addSubExtension;
-}
-
-UString GetDefaultName2(const UString &fileName,
- const UString &extension, const UString &addSubExtension)
-{
- UString name = GetDefaultName3(fileName, extension, addSubExtension);
- name.TrimRight();
- return name;
-}
+// DefaultName.cpp
+
+#include "StdAfx.h"
+
+#include "DefaultName.h"
+
+static UString GetDefaultName3(const UString &fileName,
+ const UString &extension, const UString &addSubExtension)
+{
+ const unsigned extLen = extension.Len();
+ const unsigned fileNameLen = fileName.Len();
+
+ if (fileNameLen > extLen + 1)
+ {
+ const unsigned dotPos = fileNameLen - (extLen + 1);
+ if (fileName[dotPos] == '.')
+ if (extension.IsEqualTo_NoCase(fileName.Ptr(dotPos + 1)))
+ return fileName.Left(dotPos) + addSubExtension;
+ }
+
+ int dotPos = fileName.ReverseFind_Dot();
+ if (dotPos > 0)
+ return fileName.Left((unsigned)dotPos) + addSubExtension;
+
+ if (addSubExtension.IsEmpty())
+ return fileName + L'~';
+ else
+ return fileName + addSubExtension;
+}
+
+UString GetDefaultName2(const UString &fileName,
+ const UString &extension, const UString &addSubExtension)
+{
+ UString name = GetDefaultName3(fileName, extension, addSubExtension);
+ name.TrimRight();
+ return name;
+}
diff --git a/CPP/7zip/UI/Common/DefaultName.h b/CPP/7zip/UI/Common/DefaultName.h
index 4484c3b..46f6e9e 100644
--- a/CPP/7zip/UI/Common/DefaultName.h
+++ b/CPP/7zip/UI/Common/DefaultName.h
@@ -1,11 +1,11 @@
-// DefaultName.h
-
-#ifndef __DEFAULT_NAME_H
-#define __DEFAULT_NAME_H
-
-#include "../../../Common/MyString.h"
-
-UString GetDefaultName2(const UString &fileName,
- const UString &extension, const UString &addSubExtension);
-
-#endif
+// DefaultName.h
+
+#ifndef ZIP7_INC_DEFAULT_NAME_H
+#define ZIP7_INC_DEFAULT_NAME_H
+
+#include "../../../Common/MyString.h"
+
+UString GetDefaultName2(const UString &fileName,
+ const UString &extension, const UString &addSubExtension);
+
+#endif
diff --git a/CPP/7zip/UI/Common/DirItem.h b/CPP/7zip/UI/Common/DirItem.h
index 47485be..ae84937 100644
--- a/CPP/7zip/UI/Common/DirItem.h
+++ b/CPP/7zip/UI/Common/DirItem.h
@@ -1,190 +1,404 @@
-// DirItem.h
-
-#ifndef __DIR_ITEM_H
-#define __DIR_ITEM_H
-
-#include "../../../Common/MyString.h"
-
-#include "../../../Windows/FileFind.h"
-
-#include "../../Common/UniqBlocks.h"
-
-#include "../../Archive/IArchive.h"
-
-struct CDirItemsStat
-{
- UInt64 NumDirs;
- UInt64 NumFiles;
- UInt64 NumAltStreams;
- UInt64 FilesSize;
- UInt64 AltStreamsSize;
-
- UInt64 NumErrors;
-
- // UInt64 Get_NumItems() const { return NumDirs + NumFiles + NumAltStreams; }
- UInt64 Get_NumDataItems() const { return NumFiles + NumAltStreams; }
- UInt64 GetTotalBytes() const { return FilesSize + AltStreamsSize; }
-
- bool IsEmpty() const { return
- 0 == NumDirs
- && 0 == NumFiles
- && 0 == NumAltStreams
- && 0 == FilesSize
- && 0 == AltStreamsSize
- && 0 == NumErrors; }
-
- CDirItemsStat():
- NumDirs(0),
- NumFiles(0),
- NumAltStreams(0),
- FilesSize(0),
- AltStreamsSize(0),
- NumErrors(0)
- {}
-};
-
-
-struct CDirItemsStat2: public CDirItemsStat
-{
- UInt64 Anti_NumDirs;
- UInt64 Anti_NumFiles;
- UInt64 Anti_NumAltStreams;
-
- // UInt64 Get_NumItems() const { return Anti_NumDirs + Anti_NumFiles + Anti_NumAltStreams + CDirItemsStat::Get_NumItems(); }
- UInt64 Get_NumDataItems2() const { return Anti_NumFiles + Anti_NumAltStreams + CDirItemsStat::Get_NumDataItems(); }
-
- bool IsEmpty() const { return CDirItemsStat::IsEmpty()
- && 0 == Anti_NumDirs
- && 0 == Anti_NumFiles
- && 0 == Anti_NumAltStreams; }
-
- CDirItemsStat2():
- Anti_NumDirs(0),
- Anti_NumFiles(0),
- Anti_NumAltStreams(0)
- {}
-};
-
-
-
-#define INTERFACE_IDirItemsCallback(x) \
- virtual HRESULT ScanError(const FString &path, DWORD systemError) x; \
- virtual HRESULT ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir) x; \
-
-struct IDirItemsCallback
-{
- INTERFACE_IDirItemsCallback(=0)
-};
-
-struct CDirItem
-{
- UInt64 Size;
- FILETIME CTime;
- FILETIME ATime;
- FILETIME MTime;
- UString Name;
-
- #if defined(_WIN32) && !defined(UNDER_CE)
- // UString ShortName;
- CByteBuffer ReparseData;
- CByteBuffer ReparseData2; // fixed (reduced) absolute links
-
- bool AreReparseData() const { return ReparseData.Size() != 0 || ReparseData2.Size() != 0; }
- #endif
-
- UInt32 Attrib;
- int PhyParent;
- int LogParent;
- int SecureIndex;
-
- bool IsAltStream;
-
- CDirItem(): PhyParent(-1), LogParent(-1), SecureIndex(-1), IsAltStream(false) {}
- bool IsDir() const { return (Attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 ; }
-};
-
-class CDirItems
-{
- UStringVector Prefixes;
- CIntVector PhyParents;
- CIntVector LogParents;
-
- UString GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const;
-
- HRESULT EnumerateDir(int phyParent, int logParent, const FString &phyPrefix);
-
-public:
- CObjectVector<CDirItem> Items;
-
- bool SymLinks;
-
- bool ScanAltStreams;
-
- CDirItemsStat Stat;
-
- #ifndef UNDER_CE
- HRESULT SetLinkInfo(CDirItem &dirItem, const NWindows::NFile::NFind::CFileInfo &fi,
- const FString &phyPrefix);
- #endif
-
-
- #if defined(_WIN32) && !defined(UNDER_CE)
-
- CUniqBlocks SecureBlocks;
- CByteBuffer TempSecureBuf;
- bool _saclEnabled;
- bool ReadSecure;
-
- HRESULT AddSecurityItem(const FString &path, int &secureIndex);
-
- #endif
-
- IDirItemsCallback *Callback;
-
- CDirItems();
-
- void AddDirFileInfo(int phyParent, int logParent, int secureIndex,
- const NWindows::NFile::NFind::CFileInfo &fi);
-
- HRESULT AddError(const FString &path, DWORD errorCode);
- HRESULT AddError(const FString &path);
-
- HRESULT ScanProgress(const FString &path);
-
- // unsigned GetNumFolders() const { return Prefixes.Size(); }
- FString GetPhyPath(unsigned index) const;
- UString GetLogPath(unsigned index) const;
-
- unsigned AddPrefix(int phyParent, int logParent, const UString &prefix);
- void DeleteLastPrefix();
-
- HRESULT EnumerateItems2(
- const FString &phyPrefix,
- const UString &logPrefix,
- const FStringVector &filePaths,
- FStringVector *requestedPaths);
-
- #if defined(_WIN32) && !defined(UNDER_CE)
- void FillFixedReparse();
- #endif
-
- void ReserveDown();
-};
-
-struct CArcItem
-{
- UInt64 Size;
- FILETIME MTime;
- UString Name;
- bool IsDir;
- bool IsAltStream;
- bool SizeDefined;
- bool MTimeDefined;
- bool Censored;
- UInt32 IndexInServer;
- int TimeType;
-
- CArcItem(): IsDir(false), IsAltStream(false), SizeDefined(false), MTimeDefined(false), Censored(false), TimeType(-1) {}
-};
-
-#endif
+// DirItem.h
+
+#ifndef ZIP7_INC_DIR_ITEM_H
+#define ZIP7_INC_DIR_ITEM_H
+
+#ifdef _WIN32
+#include "../../../Common/MyLinux.h"
+#endif
+
+#include "../../../Common/MyString.h"
+
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/TimeUtils.h"
+
+#include "../../Common/UniqBlocks.h"
+
+#include "../../Archive/IArchive.h"
+
+struct CDirItemsStat
+{
+ UInt64 NumDirs;
+ UInt64 NumFiles;
+ UInt64 NumAltStreams;
+ UInt64 FilesSize;
+ UInt64 AltStreamsSize;
+
+ UInt64 NumErrors;
+
+ // UInt64 Get_NumItems() const { return NumDirs + NumFiles + NumAltStreams; }
+ UInt64 Get_NumDataItems() const { return NumFiles + NumAltStreams; }
+ UInt64 GetTotalBytes() const { return FilesSize + AltStreamsSize; }
+
+ bool IsEmpty() const { return
+ 0 == NumDirs
+ && 0 == NumFiles
+ && 0 == NumAltStreams
+ && 0 == FilesSize
+ && 0 == AltStreamsSize
+ && 0 == NumErrors; }
+
+ CDirItemsStat():
+ NumDirs(0),
+ NumFiles(0),
+ NumAltStreams(0),
+ FilesSize(0),
+ AltStreamsSize(0),
+ NumErrors(0)
+ {}
+};
+
+
+struct CDirItemsStat2: public CDirItemsStat
+{
+ UInt64 Anti_NumDirs;
+ UInt64 Anti_NumFiles;
+ UInt64 Anti_NumAltStreams;
+
+ // UInt64 Get_NumItems() const { return Anti_NumDirs + Anti_NumFiles + Anti_NumAltStreams + CDirItemsStat::Get_NumItems(); }
+ UInt64 Get_NumDataItems2() const { return Anti_NumFiles + Anti_NumAltStreams + CDirItemsStat::Get_NumDataItems(); }
+
+ bool IsEmpty() const { return CDirItemsStat::IsEmpty()
+ && 0 == Anti_NumDirs
+ && 0 == Anti_NumFiles
+ && 0 == Anti_NumAltStreams; }
+
+ CDirItemsStat2():
+ Anti_NumDirs(0),
+ Anti_NumFiles(0),
+ Anti_NumAltStreams(0)
+ {}
+};
+
+
+Z7_PURE_INTERFACES_BEGIN
+
+#define Z7_IFACEN_IDirItemsCallback(x) \
+ virtual HRESULT ScanError(const FString &path, DWORD systemError) x \
+ virtual HRESULT ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir) x \
+
+Z7_IFACE_DECL_PURE(IDirItemsCallback)
+
+Z7_PURE_INTERFACES_END
+
+
+struct CArcTime
+{
+ FILETIME FT;
+ UInt16 Prec;
+ Byte Ns100;
+ bool Def;
+
+ CArcTime()
+ {
+ Clear();
+ }
+
+ void Clear()
+ {
+ FT.dwHighDateTime = FT.dwLowDateTime = 0;
+ Prec = 0;
+ Ns100 = 0;
+ Def = false;
+ }
+
+ bool IsZero() const
+ {
+ return FT.dwLowDateTime == 0 && FT.dwHighDateTime == 0 && Ns100 == 0;
+ }
+
+ int CompareWith(const CArcTime &a) const
+ {
+ const int res = CompareFileTime(&FT, &a.FT);
+ if (res != 0)
+ return res;
+ if (Ns100 < a.Ns100) return -1;
+ if (Ns100 > a.Ns100) return 1;
+ return 0;
+ }
+
+ UInt64 Get_FILETIME_as_UInt64() const
+ {
+ return (((UInt64)FT.dwHighDateTime) << 32) + FT.dwLowDateTime;
+ }
+
+ UInt32 Get_DosTime() const
+ {
+ FILETIME ft2 = FT;
+ if ((Prec == k_PropVar_TimePrec_Base + 8 ||
+ Prec == k_PropVar_TimePrec_Base + 9)
+ && Ns100 != 0)
+ {
+ UInt64 u64 = Get_FILETIME_as_UInt64();
+ // we round up even small (ns < 100ns) as FileTimeToDosTime()
+ if (u64 % 20000000 == 0)
+ {
+ u64++;
+ ft2.dwHighDateTime = (DWORD)(u64 >> 32);
+ ft2.dwHighDateTime = (DWORD)u64;
+ }
+ }
+ // FileTimeToDosTime() is expected to round up in Windows
+ UInt32 dosTime;
+ // we use simplified code with utctime->dos.
+ // do we need local time instead here?
+ NWindows::NTime::FileTime_To_DosTime(ft2, dosTime);
+ return dosTime;
+ }
+
+ int GetNumDigits() const
+ {
+ if (Prec == k_PropVar_TimePrec_Unix ||
+ Prec == k_PropVar_TimePrec_DOS)
+ return 0;
+ if (Prec == k_PropVar_TimePrec_HighPrec)
+ return 9;
+ if (Prec == k_PropVar_TimePrec_0)
+ return 7;
+ int digits = (int)Prec - (int)k_PropVar_TimePrec_Base;
+ if (digits < 0)
+ digits = 0;
+ return digits;
+ }
+
+ void Write_To_FiTime(CFiTime &dest) const
+ {
+ #ifdef _WIN32
+ dest = FT;
+ #else
+ if (FILETIME_To_timespec(FT, dest))
+ if ((Prec == k_PropVar_TimePrec_Base + 8 ||
+ Prec == k_PropVar_TimePrec_Base + 9)
+ && Ns100 != 0)
+ {
+ dest.tv_nsec += Ns100;
+ }
+ #endif
+ }
+
+ // (Def) is not set
+ void Set_From_FILETIME(const FILETIME &ft)
+ {
+ FT = ft;
+ // Prec = k_PropVar_TimePrec_CompatNTFS;
+ Prec = k_PropVar_TimePrec_Base + 7;
+ Ns100 = 0;
+ }
+
+ // (Def) is not set
+ // it set full form precision: k_PropVar_TimePrec_Base + numDigits
+ void Set_From_FiTime(const CFiTime &ts)
+ {
+ #ifdef _WIN32
+ FT = ts;
+ Prec = k_PropVar_TimePrec_Base + 7;
+ // Prec = k_PropVar_TimePrec_Base; // for debug
+ // Prec = 0; // for debug
+ Ns100 = 0;
+ #else
+ unsigned ns100;
+ FiTime_To_FILETIME_ns100(ts, FT, ns100);
+ Ns100 = (Byte)ns100;
+ Prec = k_PropVar_TimePrec_Base + 9;
+ #endif
+ }
+
+ void Set_From_Prop(const PROPVARIANT &prop)
+ {
+ FT = prop.filetime;
+ unsigned prec = 0;
+ unsigned ns100 = 0;
+ const unsigned prec_Temp = prop.wReserved1;
+ if (prec_Temp != 0
+ && prec_Temp <= k_PropVar_TimePrec_1ns
+ && prop.wReserved3 == 0)
+ {
+ const unsigned ns100_Temp = prop.wReserved2;
+ if (ns100_Temp < 100)
+ {
+ ns100 = ns100_Temp;
+ prec = prec_Temp;
+ }
+ }
+ Prec = (UInt16)prec;
+ Ns100 = (Byte)ns100;
+ Def = true;
+ }
+};
+
+
+struct CDirItem: public NWindows::NFile::NFind::CFileInfoBase
+{
+ UString Name;
+
+ #ifndef UNDER_CE
+ CByteBuffer ReparseData;
+
+ #ifdef _WIN32
+ // UString ShortName;
+ CByteBuffer ReparseData2; // fixed (reduced) absolute links for WIM format
+ bool AreReparseData() const { return ReparseData.Size() != 0 || ReparseData2.Size() != 0; }
+ #else
+ bool AreReparseData() const { return ReparseData.Size() != 0; }
+ #endif // _WIN32
+
+ #endif // !UNDER_CE
+
+ void Copy_From_FileInfoBase(const NWindows::NFile::NFind::CFileInfoBase &fi)
+ {
+ (NWindows::NFile::NFind::CFileInfoBase &)*this = fi;
+ }
+
+ int PhyParent;
+ int LogParent;
+ int SecureIndex;
+
+ #ifdef _WIN32
+ #else
+ int OwnerNameIndex;
+ int OwnerGroupIndex;
+ #endif
+
+ CDirItem():
+ PhyParent(-1)
+ , LogParent(-1)
+ , SecureIndex(-1)
+ #ifdef _WIN32
+ #else
+ , OwnerNameIndex(-1)
+ , OwnerGroupIndex(-1)
+ #endif
+ {
+ }
+
+
+ CDirItem(const NWindows::NFile::NFind::CFileInfo &fi,
+ int phyParent, int logParent, int secureIndex):
+ CFileInfoBase(fi)
+ , Name(fs2us(fi.Name))
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ // , ShortName(fs2us(fi.ShortName))
+ #endif
+ , PhyParent(phyParent)
+ , LogParent(logParent)
+ , SecureIndex(secureIndex)
+ #ifdef _WIN32
+ #else
+ , OwnerNameIndex(-1)
+ , OwnerGroupIndex(-1)
+ #endif
+ {}
+};
+
+
+
+class CDirItems
+{
+ UStringVector Prefixes;
+ CIntVector PhyParents;
+ CIntVector LogParents;
+
+ UString GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const;
+
+ HRESULT EnumerateDir(int phyParent, int logParent, const FString &phyPrefix);
+
+public:
+ CObjectVector<CDirItem> Items;
+
+ bool SymLinks;
+ bool ScanAltStreams;
+ bool ExcludeDirItems;
+ bool ExcludeFileItems;
+ bool ShareForWrite;
+
+ /* it must be called after anotrher checks */
+ bool CanIncludeItem(bool isDir) const
+ {
+ return isDir ? !ExcludeDirItems : !ExcludeFileItems;
+ }
+
+
+ CDirItemsStat Stat;
+
+ #if !defined(UNDER_CE)
+ HRESULT SetLinkInfo(CDirItem &dirItem, const NWindows::NFile::NFind::CFileInfo &fi,
+ const FString &phyPrefix);
+ #endif
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+
+ CUniqBlocks SecureBlocks;
+ CByteBuffer TempSecureBuf;
+ bool _saclEnabled;
+ bool ReadSecure;
+
+ HRESULT AddSecurityItem(const FString &path, int &secureIndex);
+ HRESULT FillFixedReparse();
+
+ #endif
+
+ #ifndef _WIN32
+
+ C_UInt32_UString_Map OwnerNameMap;
+ C_UInt32_UString_Map OwnerGroupMap;
+ bool StoreOwnerName;
+
+ HRESULT FillDeviceSizes();
+
+ #endif
+
+ IDirItemsCallback *Callback;
+
+ CDirItems();
+
+ void AddDirFileInfo(int phyParent, int logParent, int secureIndex,
+ const NWindows::NFile::NFind::CFileInfo &fi);
+
+ HRESULT AddError(const FString &path, DWORD errorCode);
+ HRESULT AddError(const FString &path);
+
+ HRESULT ScanProgress(const FString &path);
+
+ // unsigned GetNumFolders() const { return Prefixes.Size(); }
+ FString GetPhyPath(unsigned index) const;
+ UString GetLogPath(unsigned index) const;
+
+ unsigned AddPrefix(int phyParent, int logParent, const UString &prefix);
+ void DeleteLastPrefix();
+
+ // HRESULT EnumerateOneDir(const FString &phyPrefix, CObjectVector<NWindows::NFile::NFind::CDirEntry> &files);
+ HRESULT EnumerateOneDir(const FString &phyPrefix, CObjectVector<NWindows::NFile::NFind::CFileInfo> &files);
+
+ HRESULT EnumerateItems2(
+ const FString &phyPrefix,
+ const UString &logPrefix,
+ const FStringVector &filePaths,
+ FStringVector *requestedPaths);
+
+ void ReserveDown();
+};
+
+
+
+
+struct CArcItem
+{
+ UInt64 Size;
+ UString Name;
+ CArcTime MTime; // it can be mtime of archive file, if MTime is not defined for item in archive
+ bool IsDir;
+ bool IsAltStream;
+ bool Size_Defined;
+ bool Censored;
+ UInt32 IndexInServer;
+
+ CArcItem():
+ IsDir(false),
+ IsAltStream(false),
+ Size_Defined(false),
+ Censored(false)
+ {}
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/EnumDirItems.cpp b/CPP/7zip/UI/Common/EnumDirItems.cpp
index 2c941e1..d536c47 100644
--- a/CPP/7zip/UI/Common/EnumDirItems.cpp
+++ b/CPP/7zip/UI/Common/EnumDirItems.cpp
@@ -1,1096 +1,1656 @@
-// EnumDirItems.cpp
-
-#include "StdAfx.h"
-
-#include <wchar.h>
-
-#include "../../../Common/Wildcard.h"
-
-#include "../../../Windows/FileDir.h"
-#include "../../../Windows/FileIO.h"
-#include "../../../Windows/FileName.h"
-
-#if defined(_WIN32) && !defined(UNDER_CE)
-#define _USE_SECURITY_CODE
-#include "../../../Windows/SecurityUtils.h"
-#endif
-
-#include "EnumDirItems.h"
-#include "SortUtils.h"
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NName;
-
-void CDirItems::AddDirFileInfo(int phyParent, int logParent, int secureIndex,
- const NFind::CFileInfo &fi)
-{
- CDirItem di;
- di.Size = fi.Size;
- di.CTime = fi.CTime;
- di.ATime = fi.ATime;
- di.MTime = fi.MTime;
- di.Attrib = fi.Attrib;
- di.IsAltStream = fi.IsAltStream;
- di.PhyParent = phyParent;
- di.LogParent = logParent;
- di.SecureIndex = secureIndex;
- di.Name = fs2us(fi.Name);
- #if defined(_WIN32) && !defined(UNDER_CE)
- // di.ShortName = fs2us(fi.ShortName);
- #endif
- Items.Add(di);
-
- if (fi.IsDir())
- Stat.NumDirs++;
- else if (fi.IsAltStream)
- {
- Stat.NumAltStreams++;
- Stat.AltStreamsSize += fi.Size;
- }
- else
- {
- Stat.NumFiles++;
- Stat.FilesSize += fi.Size;
- }
-}
-
-HRESULT CDirItems::AddError(const FString &path, DWORD errorCode)
-{
- Stat.NumErrors++;
- if (Callback)
- return Callback->ScanError(path, errorCode);
- return S_OK;
-}
-
-HRESULT CDirItems::AddError(const FString &path)
-{
- return AddError(path, ::GetLastError());
-}
-
-static const unsigned kScanProgressStepMask = (1 << 12) - 1;
-
-HRESULT CDirItems::ScanProgress(const FString &dirPath)
-{
- if (Callback)
- return Callback->ScanProgress(Stat, dirPath, true);
- return S_OK;
-}
-
-UString CDirItems::GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const
-{
- UString path;
- unsigned len = name.Len();
-
- int i;
- for (i = index; i >= 0; i = parents[i])
- len += Prefixes[i].Len();
-
- wchar_t *p = path.GetBuf_SetEnd(len) + len;
-
- p -= name.Len();
- wmemcpy(p, (const wchar_t *)name, name.Len());
-
- for (i = index; i >= 0; i = parents[i])
- {
- const UString &s = Prefixes[i];
- p -= s.Len();
- wmemcpy(p, (const wchar_t *)s, s.Len());
- }
-
- return path;
-}
-
-FString CDirItems::GetPhyPath(unsigned index) const
-{
- const CDirItem &di = Items[index];
- return us2fs(GetPrefixesPath(PhyParents, di.PhyParent, di.Name));
-}
-
-UString CDirItems::GetLogPath(unsigned index) const
-{
- const CDirItem &di = Items[index];
- return GetPrefixesPath(LogParents, di.LogParent, di.Name);
-}
-
-void CDirItems::ReserveDown()
-{
- Prefixes.ReserveDown();
- PhyParents.ReserveDown();
- LogParents.ReserveDown();
- Items.ReserveDown();
-}
-
-unsigned CDirItems::AddPrefix(int phyParent, int logParent, const UString &prefix)
-{
- PhyParents.Add(phyParent);
- LogParents.Add(logParent);
- return Prefixes.Add(prefix);
-}
-
-void CDirItems::DeleteLastPrefix()
-{
- PhyParents.DeleteBack();
- LogParents.DeleteBack();
- Prefixes.DeleteBack();
-}
-
-bool InitLocalPrivileges();
-
-CDirItems::CDirItems():
- SymLinks(false),
- ScanAltStreams(false)
- #ifdef _USE_SECURITY_CODE
- , ReadSecure(false)
- #endif
- , Callback(NULL)
-{
- #ifdef _USE_SECURITY_CODE
- _saclEnabled = InitLocalPrivileges();
- #endif
-}
-
-#ifdef _USE_SECURITY_CODE
-
-HRESULT CDirItems::AddSecurityItem(const FString &path, int &secureIndex)
-{
- secureIndex = -1;
-
- SECURITY_INFORMATION securInfo =
- DACL_SECURITY_INFORMATION |
- GROUP_SECURITY_INFORMATION |
- OWNER_SECURITY_INFORMATION;
- if (_saclEnabled)
- securInfo |= SACL_SECURITY_INFORMATION;
-
- DWORD errorCode = 0;
- DWORD secureSize;
-
- BOOL res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize);
-
- if (res)
- {
- if (secureSize == 0)
- return S_OK;
- if (secureSize > TempSecureBuf.Size())
- errorCode = ERROR_INVALID_FUNCTION;
- }
- else
- {
- errorCode = GetLastError();
- if (errorCode == ERROR_INSUFFICIENT_BUFFER)
- {
- if (secureSize <= TempSecureBuf.Size())
- errorCode = ERROR_INVALID_FUNCTION;
- else
- {
- TempSecureBuf.Alloc(secureSize);
- res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize);
- if (res)
- {
- if (secureSize != TempSecureBuf.Size())
- errorCode = ERROR_INVALID_FUNCTION;;
- }
- else
- errorCode = GetLastError();
- }
- }
- }
-
- if (res)
- {
- secureIndex = SecureBlocks.AddUniq(TempSecureBuf, secureSize);
- return S_OK;
- }
-
- if (errorCode == 0)
- errorCode = ERROR_INVALID_FUNCTION;
- return AddError(path, errorCode);
-}
-
-#endif
-
-HRESULT CDirItems::EnumerateDir(int phyParent, int logParent, const FString &phyPrefix)
-{
- RINOK(ScanProgress(phyPrefix));
-
- NFind::CEnumerator enumerator;
- enumerator.SetDirPrefix(phyPrefix);
- for (unsigned ttt = 0; ; ttt++)
- {
- NFind::CFileInfo fi;
- bool found;
- if (!enumerator.Next(fi, found))
- {
- return AddError(phyPrefix);
- }
- if (!found)
- return S_OK;
-
- int secureIndex = -1;
- #ifdef _USE_SECURITY_CODE
- if (ReadSecure)
- {
- RINOK(AddSecurityItem(phyPrefix + fi.Name, secureIndex));
- }
- #endif
-
- AddDirFileInfo(phyParent, logParent, secureIndex, fi);
-
- if (Callback && (ttt & kScanProgressStepMask) == kScanProgressStepMask)
- {
- RINOK(ScanProgress(phyPrefix));
- }
-
- if (fi.IsDir())
- {
- const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR;
- unsigned parent = AddPrefix(phyParent, logParent, fs2us(name2));
- RINOK(EnumerateDir(parent, parent, phyPrefix + name2));
- }
- }
-}
-
-HRESULT CDirItems::EnumerateItems2(
- const FString &phyPrefix,
- const UString &logPrefix,
- const FStringVector &filePaths,
- FStringVector *requestedPaths)
-{
- int phyParent = phyPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, fs2us(phyPrefix));
- int logParent = logPrefix.IsEmpty() ? -1 : AddPrefix(-1, -1, logPrefix);
-
- FOR_VECTOR (i, filePaths)
- {
- const FString &filePath = filePaths[i];
- NFind::CFileInfo fi;
- const FString phyPath = phyPrefix + filePath;
- if (!fi.Find(phyPath))
- {
- RINOK(AddError(phyPath));
- continue;
- }
- if (requestedPaths)
- requestedPaths->Add(phyPath);
-
- int delimiter = filePath.ReverseFind_PathSepar();
- FString phyPrefixCur;
- int phyParentCur = phyParent;
- if (delimiter >= 0)
- {
- phyPrefixCur.SetFrom(filePath, delimiter + 1);
- phyParentCur = AddPrefix(phyParent, logParent, fs2us(phyPrefixCur));
- }
-
- int secureIndex = -1;
- #ifdef _USE_SECURITY_CODE
- if (ReadSecure)
- {
- RINOK(AddSecurityItem(phyPath, secureIndex));
- }
- #endif
-
- AddDirFileInfo(phyParentCur, logParent, secureIndex, fi);
-
- if (fi.IsDir())
- {
- const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR;
- unsigned parent = AddPrefix(phyParentCur, logParent, fs2us(name2));
- RINOK(EnumerateDir(parent, parent, phyPrefix + phyPrefixCur + name2));
- }
- }
-
- ReserveDown();
- return S_OK;
-}
-
-
-
-
-
-
-static HRESULT EnumerateDirItems(
- const NWildcard::CCensorNode &curNode,
- int phyParent, int logParent, const FString &phyPrefix,
- const UStringVector &addArchivePrefix,
- CDirItems &dirItems,
- bool enterToSubFolders);
-
-static HRESULT EnumerateDirItems_Spec(
- const NWildcard::CCensorNode &curNode,
- int phyParent, int logParent, const FString &curFolderName,
- const FString &phyPrefix,
- const UStringVector &addArchivePrefix,
- CDirItems &dirItems,
- bool enterToSubFolders)
-{
- const FString name2 = curFolderName + FCHAR_PATH_SEPARATOR;
- unsigned parent = dirItems.AddPrefix(phyParent, logParent, fs2us(name2));
- unsigned numItems = dirItems.Items.Size();
- HRESULT res = EnumerateDirItems(
- curNode, parent, parent, phyPrefix + name2,
- addArchivePrefix, dirItems, enterToSubFolders);
- if (numItems == dirItems.Items.Size())
- dirItems.DeleteLastPrefix();
- return res;
-}
-
-#ifndef UNDER_CE
-
-#ifdef _WIN32
-
-static HRESULT EnumerateAltStreams(
- const NFind::CFileInfo &fi,
- const NWildcard::CCensorNode &curNode,
- int phyParent, int logParent, const FString &fullPath,
- const UStringVector &addArchivePrefix, // prefix from curNode
- bool addAllItems,
- CDirItems &dirItems)
-{
- NFind::CStreamEnumerator enumerator(fullPath);
- for (;;)
- {
- NFind::CStreamInfo si;
- bool found;
- if (!enumerator.Next(si, found))
- {
- return dirItems.AddError(fullPath + FTEXT(":*")); // , (DWORD)E_FAIL
- }
- if (!found)
- return S_OK;
- if (si.IsMainStream())
- continue;
- UStringVector addArchivePrefixNew = addArchivePrefix;
- UString reducedName = si.GetReducedName();
- addArchivePrefixNew.Back() += reducedName;
- if (curNode.CheckPathToRoot(false, addArchivePrefixNew, true))
- continue;
- if (!addAllItems)
- if (!curNode.CheckPathToRoot(true, addArchivePrefixNew, true))
- continue;
-
- NFind::CFileInfo fi2 = fi;
- fi2.Name += us2fs(reducedName);
- fi2.Size = si.Size;
- fi2.Attrib &= ~FILE_ATTRIBUTE_DIRECTORY;
- fi2.IsAltStream = true;
- dirItems.AddDirFileInfo(phyParent, logParent, -1, fi2);
- }
-}
-
-#endif
-
-HRESULT CDirItems::SetLinkInfo(CDirItem &dirItem, const NFind::CFileInfo &fi,
- const FString &phyPrefix)
-{
- if (!SymLinks || !fi.HasReparsePoint())
- return S_OK;
- const FString path = phyPrefix + fi.Name;
- CByteBuffer &buf = dirItem.ReparseData;
- DWORD res = 0;
- if (NIO::GetReparseData(path, buf))
- {
- CReparseAttr attr;
- if (attr.Parse(buf, buf.Size(), res))
- return S_OK;
- // we ignore unknown reparse points
- if (res != ERROR_INVALID_REPARSE_DATA)
- res = 0;
- }
- else
- {
- res = ::GetLastError();
- if (res == 0)
- res = ERROR_INVALID_FUNCTION;
- }
-
- buf.Free();
- if (res == 0)
- return S_OK;
- return AddError(path, res);
-}
-
-#endif
-
-static HRESULT EnumerateForItem(
- NFind::CFileInfo &fi,
- const NWildcard::CCensorNode &curNode,
- int phyParent, int logParent, const FString &phyPrefix,
- const UStringVector &addArchivePrefix, // prefix from curNode
- CDirItems &dirItems,
- bool enterToSubFolders)
-{
- const UString name = fs2us(fi.Name);
- bool enterToSubFolders2 = enterToSubFolders;
- UStringVector addArchivePrefixNew = addArchivePrefix;
- addArchivePrefixNew.Add(name);
- {
- UStringVector addArchivePrefixNewTemp(addArchivePrefixNew);
- if (curNode.CheckPathToRoot(false, addArchivePrefixNewTemp, !fi.IsDir()))
- return S_OK;
- }
- int dirItemIndex = -1;
-
- bool addAllSubStreams = false;
-
- if (curNode.CheckPathToRoot(true, addArchivePrefixNew, !fi.IsDir()))
- {
- int secureIndex = -1;
- #ifdef _USE_SECURITY_CODE
- if (dirItems.ReadSecure)
- {
- RINOK(dirItems.AddSecurityItem(phyPrefix + fi.Name, secureIndex));
- }
- #endif
-
- dirItemIndex = dirItems.Items.Size();
- dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi);
- if (fi.IsDir())
- enterToSubFolders2 = true;
-
- addAllSubStreams = true;
- }
-
- #ifndef UNDER_CE
- if (dirItems.ScanAltStreams)
- {
- RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent,
- phyPrefix + fi.Name,
- addArchivePrefixNew,
- addAllSubStreams,
- dirItems));
- }
-
- if (dirItemIndex >= 0)
- {
- CDirItem &dirItem = dirItems.Items[dirItemIndex];
- RINOK(dirItems.SetLinkInfo(dirItem, fi, phyPrefix));
- if (dirItem.ReparseData.Size() != 0)
- return S_OK;
- }
- #endif
-
- if (!fi.IsDir())
- return S_OK;
-
- const NWildcard::CCensorNode *nextNode = 0;
- if (addArchivePrefix.IsEmpty())
- {
- int index = curNode.FindSubNode(name);
- if (index >= 0)
- nextNode = &curNode.SubNodes[index];
- }
- if (!enterToSubFolders2 && nextNode == 0)
- return S_OK;
-
- addArchivePrefixNew = addArchivePrefix;
- if (nextNode == 0)
- {
- nextNode = &curNode;
- addArchivePrefixNew.Add(name);
- }
-
- return EnumerateDirItems_Spec(
- *nextNode, phyParent, logParent, fi.Name, phyPrefix,
- addArchivePrefixNew,
- dirItems,
- enterToSubFolders2);
-}
-
-
-static bool CanUseFsDirect(const NWildcard::CCensorNode &curNode)
-{
- FOR_VECTOR (i, curNode.IncludeItems)
- {
- const NWildcard::CItem &item = curNode.IncludeItems[i];
- if (item.Recursive || item.PathParts.Size() != 1)
- return false;
- const UString &name = item.PathParts.Front();
- /*
- if (name.IsEmpty())
- return false;
- */
-
- /* Windows doesn't support file name with wildcard
- But if another system supports file name with wildcard,
- and wildcard mode is disabled, we can ignore wildcard in name */
- /*
- if (!item.WildcardParsing)
- continue;
- */
- if (DoesNameContainWildcard(name))
- return false;
- }
- return true;
-}
-
-
-#if defined(_WIN32) && !defined(UNDER_CE)
-
-static bool IsVirtualFsFolder(const FString &prefix, const UString &name)
-{
- UString s = fs2us(prefix);
- s += name;
- s.Add_PathSepar();
- return IsPathSepar(s[0]) && GetRootPrefixSize(s) == 0;
-}
-
-#endif
-
-static HRESULT EnumerateDirItems(
- const NWildcard::CCensorNode &curNode,
- int phyParent, int logParent, const FString &phyPrefix,
- const UStringVector &addArchivePrefix, // prefix from curNode
- CDirItems &dirItems,
- bool enterToSubFolders)
-{
- if (!enterToSubFolders)
- if (curNode.NeedCheckSubDirs())
- enterToSubFolders = true;
-
- RINOK(dirItems.ScanProgress(phyPrefix));
-
- // try direct_names case at first
- if (addArchivePrefix.IsEmpty() && !enterToSubFolders)
- {
- if (CanUseFsDirect(curNode))
- {
- // all names are direct (no wildcards)
- // so we don't need file_system's dir enumerator
- CRecordVector<bool> needEnterVector;
- unsigned i;
-
- for (i = 0; i < curNode.IncludeItems.Size(); i++)
- {
- const NWildcard::CItem &item = curNode.IncludeItems[i];
- const UString &name = item.PathParts.Front();
- FString fullPath = phyPrefix + us2fs(name);
-
- #if defined(_WIN32) && !defined(UNDER_CE)
- bool needAltStreams = true;
- #endif
-
- #ifdef _USE_SECURITY_CODE
- bool needSecurity = true;
- #endif
-
- if (phyPrefix.IsEmpty())
- {
- if (!item.ForFile)
- {
- /* we don't like some names for alt streams inside archive:
- ":sname" for "\"
- "c:::sname" for "C:\"
- So we ignore alt streams for these cases */
- if (name.IsEmpty())
- {
- #if defined(_WIN32) && !defined(UNDER_CE)
- needAltStreams = false;
- #endif
-
- /*
- // do we need to ignore security info for "\\" folder ?
- #ifdef _USE_SECURITY_CODE
- needSecurity = false;
- #endif
- */
-
- fullPath = CHAR_PATH_SEPARATOR;
- }
- #if defined(_WIN32) && !defined(UNDER_CE)
- else if (item.IsDriveItem())
- {
- needAltStreams = false;
- fullPath.Add_PathSepar();
- }
- #endif
- }
- }
-
- NFind::CFileInfo fi;
- #if defined(_WIN32) && !defined(UNDER_CE)
- if (IsVirtualFsFolder(phyPrefix, name))
- {
- fi.SetAsDir();
- fi.Name = us2fs(name);
- }
- else
- #endif
- if (!fi.Find(fullPath))
- {
- RINOK(dirItems.AddError(fullPath));
- continue;
- }
-
- bool isDir = fi.IsDir();
- if (isDir && !item.ForDir || !isDir && !item.ForFile)
- {
- RINOK(dirItems.AddError(fullPath, (DWORD)E_FAIL));
- continue;
- }
- {
- UStringVector pathParts;
- pathParts.Add(fs2us(fi.Name));
- if (curNode.CheckPathToRoot(false, pathParts, !isDir))
- continue;
- }
-
- int secureIndex = -1;
- #ifdef _USE_SECURITY_CODE
- if (needSecurity && dirItems.ReadSecure)
- {
- RINOK(dirItems.AddSecurityItem(fullPath, secureIndex));
- }
- #endif
-
- dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi);
-
- #ifndef UNDER_CE
- {
- CDirItem &dirItem = dirItems.Items.Back();
- RINOK(dirItems.SetLinkInfo(dirItem, fi, phyPrefix));
- if (dirItem.ReparseData.Size() != 0)
- {
- if (fi.IsAltStream)
- dirItems.Stat.AltStreamsSize -= fi.Size;
- else
- dirItems.Stat.FilesSize -= fi.Size;
- continue;
- }
- }
- #endif
-
-
- #ifndef UNDER_CE
- if (needAltStreams && dirItems.ScanAltStreams)
- {
- UStringVector pathParts;
- pathParts.Add(fs2us(fi.Name));
- RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent,
- fullPath, pathParts,
- true, /* addAllSubStreams */
- dirItems));
- }
- #endif
-
- if (!isDir)
- continue;
-
- UStringVector addArchivePrefixNew;
- const NWildcard::CCensorNode *nextNode = 0;
- int index = curNode.FindSubNode(name);
- if (index >= 0)
- {
- for (int t = needEnterVector.Size(); t <= index; t++)
- needEnterVector.Add(true);
- needEnterVector[index] = false;
- nextNode = &curNode.SubNodes[index];
- }
- else
- {
- nextNode = &curNode;
- addArchivePrefixNew.Add(name); // don't change it to fi.Name. It's for shortnames support
- }
-
- RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix,
- addArchivePrefixNew, dirItems, true));
- }
-
- for (i = 0; i < curNode.SubNodes.Size(); i++)
- {
- if (i < needEnterVector.Size())
- if (!needEnterVector[i])
- continue;
- const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i];
- FString fullPath = phyPrefix + us2fs(nextNode.Name);
- NFind::CFileInfo fi;
-
- if (phyPrefix.IsEmpty())
- {
- {
- if (nextNode.Name.IsEmpty())
- fullPath = CHAR_PATH_SEPARATOR;
- #ifdef _WIN32
- else if (NWildcard::IsDriveColonName(nextNode.Name))
- fullPath.Add_PathSepar();
- #endif
- }
- }
-
- // we don't want to call fi.Find() for root folder or virtual folder
- if (phyPrefix.IsEmpty() && nextNode.Name.IsEmpty()
- #if defined(_WIN32) && !defined(UNDER_CE)
- || IsVirtualFsFolder(phyPrefix, nextNode.Name)
- #endif
- )
- {
- fi.SetAsDir();
- fi.Name = us2fs(nextNode.Name);
- }
- else
- {
- if (!fi.Find(fullPath))
- {
- if (!nextNode.AreThereIncludeItems())
- continue;
- RINOK(dirItems.AddError(fullPath));
- continue;
- }
-
- if (!fi.IsDir())
- {
- RINOK(dirItems.AddError(fullPath, (DWORD)E_FAIL));
- continue;
- }
- }
-
- RINOK(EnumerateDirItems_Spec(nextNode, phyParent, logParent, fi.Name, phyPrefix,
- UStringVector(), dirItems, false));
- }
-
- return S_OK;
- }
- }
-
- #ifdef _WIN32
- #ifndef UNDER_CE
-
- // scan drives, if wildcard is "*:\"
-
- if (phyPrefix.IsEmpty() && curNode.IncludeItems.Size() > 0)
- {
- unsigned i;
- for (i = 0; i < curNode.IncludeItems.Size(); i++)
- {
- const NWildcard::CItem &item = curNode.IncludeItems[i];
- if (item.PathParts.Size() < 1)
- break;
- const UString &name = item.PathParts.Front();
- if (name.Len() != 2 || name[1] != ':')
- break;
- if (item.PathParts.Size() == 1)
- if (item.ForFile || !item.ForDir)
- break;
- if (NWildcard::IsDriveColonName(name))
- continue;
- if (name[0] != '*' && name[0] != '?')
- break;
- }
- if (i == curNode.IncludeItems.Size())
- {
- FStringVector driveStrings;
- NFind::MyGetLogicalDriveStrings(driveStrings);
- for (i = 0; i < driveStrings.Size(); i++)
- {
- FString driveName = driveStrings[i];
- if (driveName.Len() < 3 || driveName.Back() != '\\')
- return E_FAIL;
- driveName.DeleteBack();
- NFind::CFileInfo fi;
- fi.SetAsDir();
- fi.Name = driveName;
-
- RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix,
- addArchivePrefix, dirItems, enterToSubFolders));
- }
- return S_OK;
- }
- }
-
- #endif
- #endif
-
- NFind::CEnumerator enumerator;
- enumerator.SetDirPrefix(phyPrefix);
-
- for (unsigned ttt = 0; ; ttt++)
- {
- NFind::CFileInfo fi;
- bool found;
- if (!enumerator.Next(fi, found))
- {
- RINOK(dirItems.AddError(phyPrefix));
- break;
- }
- if (!found)
- break;
-
- if (dirItems.Callback && (ttt & kScanProgressStepMask) == kScanProgressStepMask)
- {
- RINOK(dirItems.ScanProgress(phyPrefix));
- }
-
- RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix,
- addArchivePrefix, dirItems, enterToSubFolders));
- }
-
- return S_OK;
-}
-
-HRESULT EnumerateItems(
- const NWildcard::CCensor &censor,
- const NWildcard::ECensorPathMode pathMode,
- const UString &addPathPrefix,
- CDirItems &dirItems)
-{
- FOR_VECTOR (i, censor.Pairs)
- {
- const NWildcard::CPair &pair = censor.Pairs[i];
- int phyParent = pair.Prefix.IsEmpty() ? -1 : dirItems.AddPrefix(-1, -1, pair.Prefix);
- int logParent = -1;
-
- if (pathMode == NWildcard::k_AbsPath)
- logParent = phyParent;
- else
- {
- if (!addPathPrefix.IsEmpty())
- logParent = dirItems.AddPrefix(-1, -1, addPathPrefix);
- }
-
- RINOK(EnumerateDirItems(pair.Head, phyParent, logParent, us2fs(pair.Prefix), UStringVector(),
- dirItems,
- false // enterToSubFolders
- ));
- }
- dirItems.ReserveDown();
-
- #if defined(_WIN32) && !defined(UNDER_CE)
- dirItems.FillFixedReparse();
- #endif
-
- return S_OK;
-}
-
-#if defined(_WIN32) && !defined(UNDER_CE)
-
-void CDirItems::FillFixedReparse()
-{
- /* imagex/WIM reduces absolute pathes in links (raparse data),
- if we archive non root folder. We do same thing here */
-
- if (!SymLinks)
- return;
-
- FOR_VECTOR(i, Items)
- {
- CDirItem &item = Items[i];
- if (item.ReparseData.Size() == 0)
- continue;
-
- CReparseAttr attr;
- DWORD errorCode = 0;
- if (!attr.Parse(item.ReparseData, item.ReparseData.Size(), errorCode))
- continue;
- if (attr.IsRelative())
- continue;
-
- const UString &link = attr.GetPath();
- if (!IsDrivePath(link))
- continue;
- // maybe we need to support networks paths also ?
-
- FString fullPathF;
- if (!NDir::MyGetFullPathName(GetPhyPath(i), fullPathF))
- continue;
- UString fullPath = fs2us(fullPathF);
- const UString logPath = GetLogPath(i);
- if (logPath.Len() >= fullPath.Len())
- continue;
- if (CompareFileNames(logPath, fullPath.RightPtr(logPath.Len())) != 0)
- continue;
-
- const UString prefix = fullPath.Left(fullPath.Len() - logPath.Len());
- if (!IsPathSepar(prefix.Back()))
- continue;
-
- unsigned rootPrefixSize = GetRootPrefixSize(prefix);
- if (rootPrefixSize == 0)
- continue;
- if (rootPrefixSize == prefix.Len())
- continue; // simple case: paths are from root
-
- if (link.Len() <= prefix.Len())
- continue;
-
- if (CompareFileNames(link.Left(prefix.Len()), prefix) != 0)
- continue;
-
- UString newLink = prefix.Left(rootPrefixSize);
- newLink += link.Ptr(prefix.Len());
-
- CByteBuffer data;
- if (!FillLinkData(data, newLink, attr.IsSymLink()))
- continue;
- item.ReparseData2 = data;
- }
-}
-
-#endif
-
-
-
-static const char * const kCannotFindArchive = "Cannot find archive";
-
-HRESULT EnumerateDirItemsAndSort(
- NWildcard::CCensor &censor,
- NWildcard::ECensorPathMode censorPathMode,
- const UString &addPathPrefix,
- UStringVector &sortedPaths,
- UStringVector &sortedFullPaths,
- CDirItemsStat &st,
- IDirItemsCallback *callback)
-{
- FStringVector paths;
-
- {
- CDirItems dirItems;
- dirItems.Callback = callback;
- {
- HRESULT res = EnumerateItems(censor, censorPathMode, addPathPrefix, dirItems);
- st = dirItems.Stat;
- RINOK(res);
- }
-
- FOR_VECTOR (i, dirItems.Items)
- {
- const CDirItem &dirItem = dirItems.Items[i];
- if (!dirItem.IsDir())
- paths.Add(dirItems.GetPhyPath(i));
- }
- }
-
- if (paths.Size() == 0)
- {
- // return S_OK;
- throw CMessagePathException(kCannotFindArchive);
- }
-
- UStringVector fullPaths;
-
- unsigned i;
-
- for (i = 0; i < paths.Size(); i++)
- {
- FString fullPath;
- NFile::NDir::MyGetFullPathName(paths[i], fullPath);
- fullPaths.Add(fs2us(fullPath));
- }
-
- CUIntVector indices;
- SortFileNames(fullPaths, indices);
- sortedPaths.ClearAndReserve(indices.Size());
- sortedFullPaths.ClearAndReserve(indices.Size());
-
- for (i = 0; i < indices.Size(); i++)
- {
- unsigned index = indices[i];
- sortedPaths.AddInReserved(fs2us(paths[index]));
- sortedFullPaths.AddInReserved(fullPaths[index]);
- if (i > 0 && CompareFileNames(sortedFullPaths[i], sortedFullPaths[i - 1]) == 0)
- throw CMessagePathException("Duplicate archive path:", sortedFullPaths[i]);
- }
-
- return S_OK;
-}
-
-
-
-
-#ifdef _WIN32
-
-// This code converts all short file names to long file names.
-
-static void ConvertToLongName(const UString &prefix, UString &name)
-{
- if (name.IsEmpty() || DoesNameContainWildcard(name))
- return;
- NFind::CFileInfo fi;
- const FString path (us2fs(prefix + name));
- #ifndef UNDER_CE
- if (NFile::NName::IsDevicePath(path))
- return;
- #endif
- if (fi.Find(path))
- name = fs2us(fi.Name);
-}
-
-static void ConvertToLongNames(const UString &prefix, CObjectVector<NWildcard::CItem> &items)
-{
- FOR_VECTOR (i, items)
- {
- NWildcard::CItem &item = items[i];
- if (item.Recursive || item.PathParts.Size() != 1)
- continue;
- if (prefix.IsEmpty() && item.IsDriveItem())
- continue;
- ConvertToLongName(prefix, item.PathParts.Front());
- }
-}
-
-static void ConvertToLongNames(const UString &prefix, NWildcard::CCensorNode &node)
-{
- ConvertToLongNames(prefix, node.IncludeItems);
- ConvertToLongNames(prefix, node.ExcludeItems);
- unsigned i;
- for (i = 0; i < node.SubNodes.Size(); i++)
- {
- UString &name = node.SubNodes[i].Name;
- if (prefix.IsEmpty() && NWildcard::IsDriveColonName(name))
- continue;
- ConvertToLongName(prefix, name);
- }
- // mix folders with same name
- for (i = 0; i < node.SubNodes.Size(); i++)
- {
- NWildcard::CCensorNode &nextNode1 = node.SubNodes[i];
- for (unsigned j = i + 1; j < node.SubNodes.Size();)
- {
- const NWildcard::CCensorNode &nextNode2 = node.SubNodes[j];
- if (nextNode1.Name.IsEqualTo_NoCase(nextNode2.Name))
- {
- nextNode1.IncludeItems += nextNode2.IncludeItems;
- nextNode1.ExcludeItems += nextNode2.ExcludeItems;
- node.SubNodes.Delete(j);
- }
- else
- j++;
- }
- }
- for (i = 0; i < node.SubNodes.Size(); i++)
- {
- NWildcard::CCensorNode &nextNode = node.SubNodes[i];
- ConvertToLongNames(prefix + nextNode.Name + WCHAR_PATH_SEPARATOR, nextNode);
- }
-}
-
-void ConvertToLongNames(NWildcard::CCensor &censor)
-{
- FOR_VECTOR (i, censor.Pairs)
- {
- NWildcard::CPair &pair = censor.Pairs[i];
- ConvertToLongNames(pair.Prefix, pair.Head);
- }
-}
-
-#endif
-
-
-CMessagePathException::CMessagePathException(const char *a, const wchar_t *u)
-{
- (*this) += a;
- if (u)
- {
- Add_LF();
- (*this) += u;
- }
-}
-
-CMessagePathException::CMessagePathException(const wchar_t *a, const wchar_t *u)
-{
- (*this) += a;
- if (u)
- {
- Add_LF();
- (*this) += u;
- }
-}
+// EnumDirItems.cpp
+
+#include "StdAfx.h"
+
+#include <wchar.h>
+// #include <stdio.h>
+
+#ifndef _WIN32
+#include <grp.h>
+#include <pwd.h>
+#include "../../../Common/UTFConvert.h"
+#endif
+
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileIO.h"
+#include "../../../Windows/FileName.h"
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+#define Z7_USE_SECURITY_CODE
+#include "../../../Windows/SecurityUtils.h"
+#endif
+
+#include "EnumDirItems.h"
+#include "SortUtils.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NName;
+
+
+static bool FindFile_KeepDots(NFile::NFind::CFileInfo &fi, const FString &path, bool followLink)
+{
+ const bool res = fi.Find(path, followLink);
+ if (!res)
+ return res;
+ if (path.IsEmpty())
+ return res;
+ // we keep name "." and "..", if it's without tail slash
+ const FChar *p = path.RightPtr(1);
+ if (*p != '.')
+ return res;
+ if (p != path.Ptr())
+ {
+ FChar c = p[-1];
+ if (!IS_PATH_SEPAR(c))
+ {
+ if (c != '.')
+ return res;
+ p--;
+ if (p != path.Ptr())
+ {
+ c = p[-1];
+ if (!IS_PATH_SEPAR(c))
+ return res;
+ }
+ }
+ }
+ fi.Name = p;
+ return res;
+}
+
+
+void CDirItems::AddDirFileInfo(int phyParent, int logParent, int secureIndex,
+ const NFind::CFileInfo &fi)
+{
+ /*
+ CDirItem di(fi);
+ di.PhyParent = phyParent;
+ di.LogParent = logParent;
+ di.SecureIndex = secureIndex;
+ Items.Add(di);
+ */
+ VECTOR_ADD_NEW_OBJECT (Items, CDirItem(fi, phyParent, logParent, secureIndex))
+
+ if (fi.IsDir())
+ Stat.NumDirs++;
+ #ifdef _WIN32
+ else if (fi.IsAltStream)
+ {
+ Stat.NumAltStreams++;
+ Stat.AltStreamsSize += fi.Size;
+ }
+ #endif
+ else
+ {
+ Stat.NumFiles++;
+ Stat.FilesSize += fi.Size;
+ }
+}
+
+// (DWORD)E_FAIL
+#define DI_DEFAULT_ERROR ERROR_INVALID_FUNCTION
+
+HRESULT CDirItems::AddError(const FString &path, DWORD errorCode)
+{
+ if (errorCode == 0)
+ errorCode = DI_DEFAULT_ERROR;
+ Stat.NumErrors++;
+ if (Callback)
+ return Callback->ScanError(path, errorCode);
+ return S_OK;
+}
+
+HRESULT CDirItems::AddError(const FString &path)
+{
+ return AddError(path, ::GetLastError());
+}
+
+static const unsigned kScanProgressStepMask = (1 << 12) - 1;
+
+HRESULT CDirItems::ScanProgress(const FString &dirPath)
+{
+ if (Callback)
+ return Callback->ScanProgress(Stat, dirPath, true);
+ return S_OK;
+}
+
+UString CDirItems::GetPrefixesPath(const CIntVector &parents, int index, const UString &name) const
+{
+ UString path;
+ unsigned len = name.Len();
+
+ int i;
+ for (i = index; i >= 0; i = parents[(unsigned)i])
+ len += Prefixes[(unsigned)i].Len();
+
+ wchar_t *p = path.GetBuf_SetEnd(len) + len;
+
+ p -= name.Len();
+ wmemcpy(p, (const wchar_t *)name, name.Len());
+
+ for (i = index; i >= 0; i = parents[(unsigned)i])
+ {
+ const UString &s = Prefixes[(unsigned)i];
+ p -= s.Len();
+ wmemcpy(p, (const wchar_t *)s, s.Len());
+ }
+
+ return path;
+}
+
+FString CDirItems::GetPhyPath(unsigned index) const
+{
+ const CDirItem &di = Items[index];
+ return us2fs(GetPrefixesPath(PhyParents, di.PhyParent, di.Name));
+}
+
+UString CDirItems::GetLogPath(unsigned index) const
+{
+ const CDirItem &di = Items[index];
+ return GetPrefixesPath(LogParents, di.LogParent, di.Name);
+}
+
+void CDirItems::ReserveDown()
+{
+ Prefixes.ReserveDown();
+ PhyParents.ReserveDown();
+ LogParents.ReserveDown();
+ Items.ReserveDown();
+}
+
+unsigned CDirItems::AddPrefix(int phyParent, int logParent, const UString &prefix)
+{
+ PhyParents.Add(phyParent);
+ LogParents.Add(logParent);
+ return Prefixes.Add(prefix);
+}
+
+void CDirItems::DeleteLastPrefix()
+{
+ PhyParents.DeleteBack();
+ LogParents.DeleteBack();
+ Prefixes.DeleteBack();
+}
+
+bool InitLocalPrivileges();
+
+CDirItems::CDirItems():
+ SymLinks(false),
+ ScanAltStreams(false)
+ , ExcludeDirItems(false)
+ , ExcludeFileItems(false)
+ , ShareForWrite(false)
+ #ifdef Z7_USE_SECURITY_CODE
+ , ReadSecure(false)
+ #endif
+ #ifndef _WIN32
+ , StoreOwnerName(false)
+ #endif
+ , Callback(NULL)
+{
+ #ifdef Z7_USE_SECURITY_CODE
+ _saclEnabled = InitLocalPrivileges();
+ #endif
+}
+
+
+#ifdef Z7_USE_SECURITY_CODE
+
+HRESULT CDirItems::AddSecurityItem(const FString &path, int &secureIndex)
+{
+ secureIndex = -1;
+
+ SECURITY_INFORMATION securInfo =
+ DACL_SECURITY_INFORMATION |
+ GROUP_SECURITY_INFORMATION |
+ OWNER_SECURITY_INFORMATION;
+ if (_saclEnabled)
+ securInfo |= SACL_SECURITY_INFORMATION;
+
+ DWORD errorCode = 0;
+ DWORD secureSize;
+
+ BOOL res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(void *)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize);
+
+ if (res)
+ {
+ if (secureSize == 0)
+ return S_OK;
+ if (secureSize > TempSecureBuf.Size())
+ errorCode = ERROR_INVALID_FUNCTION;
+ }
+ else
+ {
+ errorCode = GetLastError();
+ if (errorCode == ERROR_INSUFFICIENT_BUFFER)
+ {
+ if (secureSize <= TempSecureBuf.Size())
+ errorCode = ERROR_INVALID_FUNCTION;
+ else
+ {
+ TempSecureBuf.Alloc(secureSize);
+ res = ::GetFileSecurityW(fs2us(path), securInfo, (PSECURITY_DESCRIPTOR)(void *)(Byte *)TempSecureBuf, (DWORD)TempSecureBuf.Size(), &secureSize);
+ if (res)
+ {
+ if (secureSize != TempSecureBuf.Size())
+ errorCode = ERROR_INVALID_FUNCTION;
+ }
+ else
+ errorCode = GetLastError();
+ }
+ }
+ }
+
+ if (res)
+ {
+ secureIndex = (int)SecureBlocks.AddUniq(TempSecureBuf, secureSize);
+ return S_OK;
+ }
+
+ return AddError(path, errorCode);
+}
+
+#endif // Z7_USE_SECURITY_CODE
+
+
+HRESULT CDirItems::EnumerateOneDir(const FString &phyPrefix, CObjectVector<NFind::CFileInfo> &files)
+{
+ NFind::CEnumerator enumerator;
+ // printf("\n enumerator.SetDirPrefix(phyPrefix) \n");
+
+ enumerator.SetDirPrefix(phyPrefix);
+
+ #ifdef _WIN32
+
+ NFind::CFileInfo fi;
+
+ for (unsigned ttt = 0; ; ttt++)
+ {
+ bool found;
+ if (!enumerator.Next(fi, found))
+ return AddError(phyPrefix);
+ if (!found)
+ return S_OK;
+ files.Add(fi);
+ if (Callback && (ttt & kScanProgressStepMask) == kScanProgressStepMask)
+ {
+ RINOK(ScanProgress(phyPrefix))
+ }
+ }
+
+ #else // _WIN32
+
+ // enumerator.SolveLinks = !SymLinks;
+
+ CObjectVector<NFind::CDirEntry> entries;
+
+ for (unsigned ttt = 0; ; ttt++)
+ {
+ bool found;
+ NFind::CDirEntry de;
+ if (!enumerator.Next(de, found))
+ {
+ return AddError(phyPrefix);
+ }
+ if (!found)
+ break;
+ entries.Add(de);
+ }
+
+ FOR_VECTOR(i, entries)
+ {
+ const NFind::CDirEntry &de = entries[i];
+ NFind::CFileInfo fi;
+ if (!enumerator.Fill_FileInfo(de, fi, !SymLinks))
+ // if (!fi.Find_AfterEnumerator(path))
+ {
+ const FString path = phyPrefix + de.Name;
+ {
+ RINOK(AddError(path))
+ continue;
+ }
+ }
+
+ files.Add(fi);
+
+ if (Callback && (i & kScanProgressStepMask) == kScanProgressStepMask)
+ {
+ RINOK(ScanProgress(phyPrefix))
+ }
+ }
+
+ return S_OK;
+
+ #endif // _WIN32
+}
+
+
+
+
+HRESULT CDirItems::EnumerateDir(int phyParent, int logParent, const FString &phyPrefix)
+{
+ RINOK(ScanProgress(phyPrefix))
+
+ CObjectVector<NFind::CFileInfo> files;
+ RINOK(EnumerateOneDir(phyPrefix, files))
+
+ FOR_VECTOR (i, files)
+ {
+ #ifdef _WIN32
+ const NFind::CFileInfo &fi = files[i];
+ #else
+ const NFind::CFileInfo &fi = files[i];
+ /*
+ NFind::CFileInfo fi;
+ {
+ const NFind::CDirEntry &di = files[i];
+ const FString path = phyPrefix + di.Name;
+ if (!fi.Find_AfterEnumerator(path))
+ {
+ RINOK(AddError(path));
+ continue;
+ }
+ fi.Name = di.Name;
+ }
+ */
+ #endif
+
+ if (CanIncludeItem(fi.IsDir()))
+ {
+ int secureIndex = -1;
+ #ifdef Z7_USE_SECURITY_CODE
+ if (ReadSecure)
+ {
+ RINOK(AddSecurityItem(phyPrefix + fi.Name, secureIndex))
+ }
+ #endif
+ AddDirFileInfo(phyParent, logParent, secureIndex, fi);
+ }
+
+ if (Callback && (i & kScanProgressStepMask) == kScanProgressStepMask)
+ {
+ RINOK(ScanProgress(phyPrefix))
+ }
+
+ if (fi.IsDir())
+ {
+ const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR;
+ unsigned parent = AddPrefix(phyParent, logParent, fs2us(name2));
+ RINOK(EnumerateDir((int)parent, (int)parent, phyPrefix + name2))
+ }
+ }
+ return S_OK;
+}
+
+
+/*
+EnumerateItems2()
+ const FStringVector &filePaths - are path without tail slashes.
+ All dir prefixes of filePaths will be not stores in logical paths
+fix it: we can scan AltStream also.
+*/
+
+#ifdef _WIN32
+// #define FOLLOW_LINK_PARAM
+// #define FOLLOW_LINK_PARAM2
+#define FOLLOW_LINK_PARAM , (!SymLinks)
+#define FOLLOW_LINK_PARAM2 , (!dirItems.SymLinks)
+#else
+#define FOLLOW_LINK_PARAM , (!SymLinks)
+#define FOLLOW_LINK_PARAM2 , (!dirItems.SymLinks)
+#endif
+
+HRESULT CDirItems::EnumerateItems2(
+ const FString &phyPrefix,
+ const UString &logPrefix,
+ const FStringVector &filePaths,
+ FStringVector *requestedPaths)
+{
+ const int phyParent = phyPrefix.IsEmpty() ? -1 : (int)AddPrefix(-1, -1, fs2us(phyPrefix));
+ const int logParent = logPrefix.IsEmpty() ? -1 : (int)AddPrefix(-1, -1, logPrefix);
+
+ #ifdef _WIN32
+ const bool phyPrefix_isAltStreamPrefix =
+ NFile::NName::IsAltStreamPrefixWithColon(fs2us(phyPrefix));
+ #endif
+
+ FOR_VECTOR (i, filePaths)
+ {
+ const FString &filePath = filePaths[i];
+ NFind::CFileInfo fi;
+ const FString phyPath = phyPrefix + filePath;
+ if (!FindFile_KeepDots(fi, phyPath FOLLOW_LINK_PARAM))
+ {
+ RINOK(AddError(phyPath))
+ continue;
+ }
+ if (requestedPaths)
+ requestedPaths->Add(phyPath);
+
+ const int delimiter = filePath.ReverseFind_PathSepar();
+ FString phyPrefixCur;
+ int phyParentCur = phyParent;
+ if (delimiter >= 0)
+ {
+ phyPrefixCur.SetFrom(filePath, (unsigned)(delimiter + 1));
+ phyParentCur = (int)AddPrefix(phyParent, logParent, fs2us(phyPrefixCur));
+ }
+
+ if (CanIncludeItem(fi.IsDir()))
+ {
+ int secureIndex = -1;
+ #ifdef Z7_USE_SECURITY_CODE
+ if (ReadSecure)
+ {
+ RINOK(AddSecurityItem(phyPath, secureIndex))
+ }
+ #endif
+ #ifdef _WIN32
+ if (phyPrefix_isAltStreamPrefix && fi.IsAltStream)
+ {
+ const int pos = fi.Name.Find(FChar(':'));
+ if (pos >= 0)
+ fi.Name.DeleteFrontal((unsigned)pos + 1);
+ }
+ #endif
+ AddDirFileInfo(phyParentCur, logParent, secureIndex, fi);
+ }
+
+ if (fi.IsDir())
+ {
+ const FString name2 = fi.Name + FCHAR_PATH_SEPARATOR;
+ const unsigned parent = AddPrefix(phyParentCur, logParent, fs2us(name2));
+ RINOK(EnumerateDir((int)parent, (int)parent, phyPrefix + phyPrefixCur + name2))
+ }
+ }
+
+ ReserveDown();
+ return S_OK;
+}
+
+
+
+
+static HRESULT EnumerateDirItems(
+ const NWildcard::CCensorNode &curNode,
+ const int phyParent, const int logParent,
+ const FString &phyPrefix,
+ const UStringVector &addParts, // additional parts from curNode
+ CDirItems &dirItems,
+ bool enterToSubFolders);
+
+
+/* EnumerateDirItems_Spec()
+ adds new Dir item prefix, and enumerates dir items,
+ then it can remove that Dir item prefix, if there are no items in that dir.
+*/
+
+
+/*
+ EnumerateDirItems_Spec()
+ it's similar to EnumerateDirItems, but phyPrefix doesn't include (curFolderName)
+*/
+
+static HRESULT EnumerateDirItems_Spec(
+ const NWildcard::CCensorNode &curNode,
+ const int phyParent, const int logParent, const FString &curFolderName,
+ const FString &phyPrefix, // without (curFolderName)
+ const UStringVector &addParts, // (curNode + addParts) includes (curFolderName)
+ CDirItems &dirItems,
+ bool enterToSubFolders)
+{
+ const FString name2 = curFolderName + FCHAR_PATH_SEPARATOR;
+ const unsigned parent = dirItems.AddPrefix(phyParent, logParent, fs2us(name2));
+ const unsigned numItems = dirItems.Items.Size();
+ HRESULT res = EnumerateDirItems(
+ curNode, (int)parent, (int)parent, phyPrefix + name2,
+ addParts, dirItems, enterToSubFolders);
+ if (numItems == dirItems.Items.Size())
+ dirItems.DeleteLastPrefix();
+ return res;
+}
+
+
+#ifndef UNDER_CE
+
+#ifdef _WIN32
+
+static HRESULT EnumerateAltStreams(
+ const NFind::CFileInfo &fi,
+ const NWildcard::CCensorNode &curNode,
+ const int phyParent, const int logParent,
+ const FString &phyPath, // with (fi.Name), without tail slash for folders
+ const UStringVector &addParts, // with (fi.Name), prefix parts from curNode
+ bool addAllSubStreams,
+ CDirItems &dirItems)
+{
+ // we don't use (ExcludeFileItems) rules for AltStreams
+ // if (dirItems.ExcludeFileItems) return S_OK;
+
+ NFind::CStreamEnumerator enumerator(phyPath);
+ for (;;)
+ {
+ NFind::CStreamInfo si;
+ bool found;
+ if (!enumerator.Next(si, found))
+ {
+ return dirItems.AddError(phyPath + FTEXT(":*")); // , (DWORD)E_FAIL
+ }
+ if (!found)
+ return S_OK;
+ if (si.IsMainStream())
+ continue;
+ UStringVector parts = addParts;
+ const UString reducedName = si.GetReducedName();
+ parts.Back() += reducedName;
+ if (curNode.CheckPathToRoot(false, parts, true))
+ continue;
+ if (!addAllSubStreams)
+ if (!curNode.CheckPathToRoot(true, parts, true))
+ continue;
+
+ NFind::CFileInfo fi2 = fi;
+ fi2.Name += us2fs(reducedName);
+ fi2.Size = si.Size;
+ fi2.Attrib &= ~(DWORD)(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT);
+ fi2.IsAltStream = true;
+ dirItems.AddDirFileInfo(phyParent, logParent, -1, fi2);
+ }
+}
+
+#endif // _WIN32
+
+
+/* We get Reparse data and parse it.
+ If there is Reparse error, we free dirItem.Reparse data.
+ Do we need to work with empty reparse data?
+*/
+
+HRESULT CDirItems::SetLinkInfo(CDirItem &dirItem, const NFind::CFileInfo &fi,
+ const FString &phyPrefix)
+{
+ if (!SymLinks)
+ return S_OK;
+
+ #ifdef _WIN32
+ if (!fi.HasReparsePoint() || fi.IsAltStream)
+ #else // _WIN32
+ if (!fi.IsPosixLink())
+ #endif // _WIN32
+ return S_OK;
+
+ const FString path = phyPrefix + fi.Name;
+ CByteBuffer &buf = dirItem.ReparseData;
+ if (NIO::GetReparseData(path, buf))
+ {
+ // if (dirItem.ReparseData.Size() != 0)
+ Stat.FilesSize -= fi.Size;
+ return S_OK;
+ }
+
+ DWORD res = ::GetLastError();
+ buf.Free();
+ return AddError(path, res);
+}
+
+#endif // UNDER_CE
+
+
+
+static HRESULT EnumerateForItem(
+ const NFind::CFileInfo &fi,
+ const NWildcard::CCensorNode &curNode,
+ const int phyParent, const int logParent, const FString &phyPrefix,
+ const UStringVector &addParts, // additional parts from curNode, without (fi.Name)
+ CDirItems &dirItems,
+ bool enterToSubFolders)
+{
+ const UString name = fs2us(fi.Name);
+ UStringVector newParts = addParts;
+ newParts.Add(name);
+
+ // check the path in exclude rules
+ if (curNode.CheckPathToRoot(false, newParts, !fi.IsDir()))
+ return S_OK;
+
+ #if !defined(UNDER_CE)
+ int dirItemIndex = -1;
+ #if defined(_WIN32)
+ bool addAllSubStreams = false;
+ bool needAltStreams = true;
+ #endif // _WIN32
+ #endif // !defined(UNDER_CE)
+
+ // check the path in inlcude rules
+ if (curNode.CheckPathToRoot(true, newParts, !fi.IsDir()))
+ {
+ #if !defined(UNDER_CE)
+ // dirItemIndex = (int)dirItems.Items.Size();
+ #if defined(_WIN32)
+ // we will not check include rules for substreams.
+ addAllSubStreams = true;
+ #endif // _WIN32
+ #endif // !defined(UNDER_CE)
+
+ if (dirItems.CanIncludeItem(fi.IsDir()))
+ {
+ int secureIndex = -1;
+ #ifdef Z7_USE_SECURITY_CODE
+ if (dirItems.ReadSecure)
+ {
+ RINOK(dirItems.AddSecurityItem(phyPrefix + fi.Name, secureIndex))
+ }
+ #endif
+ #if !defined(UNDER_CE)
+ dirItemIndex = (int)dirItems.Items.Size();
+ #endif // !defined(UNDER_CE)
+ dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi);
+ }
+ else
+ {
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ needAltStreams = false;
+ #endif
+ }
+
+ if (fi.IsDir())
+ enterToSubFolders = true;
+ }
+
+ #if !defined(UNDER_CE)
+
+ // we don't scan AltStreams for link files
+
+ if (dirItemIndex >= 0)
+ {
+ CDirItem &dirItem = dirItems.Items[(unsigned)dirItemIndex];
+ RINOK(dirItems.SetLinkInfo(dirItem, fi, phyPrefix))
+ if (dirItem.ReparseData.Size() != 0)
+ return S_OK;
+ }
+
+ #if defined(_WIN32)
+ if (needAltStreams && dirItems.ScanAltStreams)
+ {
+ RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent,
+ phyPrefix + fi.Name, // with (fi.Name)
+ newParts, // with (fi.Name)
+ addAllSubStreams,
+ dirItems))
+ }
+ #endif
+
+ #endif // !defined(UNDER_CE)
+
+
+ #ifndef _WIN32
+ if (!fi.IsPosixLink()) // posix link can follow to dir
+ #endif
+ if (!fi.IsDir())
+ return S_OK;
+
+ const NWildcard::CCensorNode *nextNode = NULL;
+
+ if (addParts.IsEmpty())
+ {
+ int index = curNode.FindSubNode(name);
+ if (index >= 0)
+ {
+ nextNode = &curNode.SubNodes[(unsigned)index];
+ newParts.Clear();
+ }
+ }
+
+ if (!nextNode)
+ {
+ if (!enterToSubFolders)
+ return S_OK;
+
+ #ifndef _WIN32
+ if (fi.IsPosixLink())
+ {
+ // here we can try to resolve posix link
+ // if the link to dir, then can we follow it
+ return S_OK; // we don't follow posix link
+ }
+ #else
+ if (dirItems.SymLinks && fi.HasReparsePoint())
+ {
+ /* 20.03: in SymLinks mode: we don't enter to directory that
+ has reparse point and has no CCensorNode
+ NOTE: (curNode and parent nodes) still can have wildcard rules
+ to include some items of target directory (of reparse point),
+ but we ignore these rules here.
+ */
+ return S_OK;
+ }
+ #endif
+ nextNode = &curNode;
+ }
+
+ return EnumerateDirItems_Spec(
+ *nextNode, phyParent, logParent, fi.Name,
+ phyPrefix, // without (fi.Name)
+ newParts, // relative to (*nextNode). (*nextNode + newParts) includes (fi.Name)
+ dirItems,
+ enterToSubFolders);
+}
+
+
+static bool CanUseFsDirect(const NWildcard::CCensorNode &curNode)
+{
+ FOR_VECTOR (i, curNode.IncludeItems)
+ {
+ const NWildcard::CItem &item = curNode.IncludeItems[i];
+ if (item.Recursive || item.PathParts.Size() != 1)
+ return false;
+ const UString &name = item.PathParts.Front();
+ /*
+ if (name.IsEmpty())
+ return false;
+ */
+
+ /* Windows doesn't support file name with wildcard
+ But if another system supports file name with wildcard,
+ and wildcard mode is disabled, we can ignore wildcard in name
+ */
+ /*
+ #ifndef _WIN32
+ if (!item.WildcardParsing)
+ continue;
+ #endif
+ */
+ if (DoesNameContainWildcard(name))
+ return false;
+ }
+ return true;
+}
+
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+
+static bool IsVirtualFsFolder(const FString &prefix, const UString &name)
+{
+ UString s = fs2us(prefix);
+ s += name;
+ s.Add_PathSepar();
+ // it returns (true) for non real FS folder path like - "\\SERVER\"
+ return IsPathSepar(s[0]) && GetRootPrefixSize(s) == 0;
+}
+
+#endif
+
+
+
+static HRESULT EnumerateDirItems(
+ const NWildcard::CCensorNode &curNode,
+ const int phyParent, const int logParent, const FString &phyPrefix,
+ const UStringVector &addParts, // prefix from curNode including
+ CDirItems &dirItems,
+ bool enterToSubFolders)
+{
+ if (!enterToSubFolders)
+ {
+ /* if there are IncludeItems censor rules that affect items in subdirs,
+ then we will enter to all subfolders */
+ if (curNode.NeedCheckSubDirs())
+ enterToSubFolders = true;
+ }
+
+ RINOK(dirItems.ScanProgress(phyPrefix))
+
+ // try direct_names case at first
+ if (addParts.IsEmpty() && !enterToSubFolders)
+ {
+ if (CanUseFsDirect(curNode))
+ {
+ // all names are direct (no wildcards)
+ // so we don't need file_system's dir enumerator
+ CRecordVector<bool> needEnterVector;
+ unsigned i;
+
+ for (i = 0; i < curNode.IncludeItems.Size(); i++)
+ {
+ const NWildcard::CItem &item = curNode.IncludeItems[i];
+ const UString &name = item.PathParts.Front();
+ FString fullPath = phyPrefix + us2fs(name);
+
+ /*
+ // not possible now
+ if (!item.ForDir && !item.ForFile)
+ {
+ RINOK(dirItems.AddError(fullPath, ERROR_INVALID_PARAMETER));
+ continue;
+ }
+ */
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ bool needAltStreams = true;
+ #endif
+
+ #ifdef Z7_USE_SECURITY_CODE
+ bool needSecurity = true;
+ #endif
+
+ if (phyPrefix.IsEmpty())
+ {
+ if (!item.ForFile)
+ {
+ /* we don't like some names for alt streams inside archive:
+ ":sname" for "\"
+ "c:::sname" for "C:\"
+ So we ignore alt streams for these cases */
+ if (name.IsEmpty())
+ {
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ needAltStreams = false;
+ #endif
+
+ /*
+ // do we need to ignore security info for "\\" folder ?
+ #ifdef Z7_USE_SECURITY_CODE
+ needSecurity = false;
+ #endif
+ */
+
+ fullPath = CHAR_PATH_SEPARATOR;
+ }
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ else if (item.IsDriveItem())
+ {
+ needAltStreams = false;
+ fullPath.Add_PathSepar();
+ }
+ #endif
+ }
+ }
+
+ NFind::CFileInfo fi;
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (IsVirtualFsFolder(phyPrefix, name))
+ {
+ fi.SetAsDir();
+ fi.Name = us2fs(name);
+ }
+ else
+ #endif
+ if (!FindFile_KeepDots(fi, fullPath FOLLOW_LINK_PARAM2))
+ {
+ RINOK(dirItems.AddError(fullPath))
+ continue;
+ }
+
+ /*
+ #ifdef _WIN32
+ #define MY_ERROR_IS_DIR ERROR_FILE_NOT_FOUND
+ #define MY_ERROR_NOT_DIR DI_DEFAULT_ERROR
+ #else
+ #define MY_ERROR_IS_DIR EISDIR
+ #define MY_ERROR_NOT_DIR ENOTDIR
+ #endif
+ */
+
+ const bool isDir = fi.IsDir();
+ if (isDir ? !item.ForDir : !item.ForFile)
+ {
+ // RINOK(dirItems.AddError(fullPath, isDir ? MY_ERROR_IS_DIR: MY_ERROR_NOT_DIR));
+ RINOK(dirItems.AddError(fullPath, DI_DEFAULT_ERROR))
+ continue;
+ }
+ {
+ UStringVector pathParts;
+ pathParts.Add(fs2us(fi.Name));
+ if (curNode.CheckPathToRoot(false, pathParts, !isDir))
+ continue;
+ }
+
+
+ if (dirItems.CanIncludeItem(fi.IsDir()))
+ {
+ int secureIndex = -1;
+ #ifdef Z7_USE_SECURITY_CODE
+ if (needSecurity && dirItems.ReadSecure)
+ {
+ RINOK(dirItems.AddSecurityItem(fullPath, secureIndex))
+ }
+ #endif
+
+ dirItems.AddDirFileInfo(phyParent, logParent, secureIndex, fi);
+
+ // we don't scan AltStreams for link files
+
+ #if !defined(UNDER_CE)
+ {
+ CDirItem &dirItem = dirItems.Items.Back();
+ RINOK(dirItems.SetLinkInfo(dirItem, fi, phyPrefix))
+ if (dirItem.ReparseData.Size() != 0)
+ continue;
+ }
+
+ #if defined(_WIN32)
+ if (needAltStreams && dirItems.ScanAltStreams)
+ {
+ UStringVector pathParts;
+ pathParts.Add(fs2us(fi.Name));
+ RINOK(EnumerateAltStreams(fi, curNode, phyParent, logParent,
+ fullPath, // including (name)
+ pathParts, // including (fi.Name)
+ true, /* addAllSubStreams */
+ dirItems))
+ }
+ #endif // defined(_WIN32)
+
+ #endif // !defined(UNDER_CE)
+ }
+
+
+ #ifndef _WIN32
+ if (!fi.IsPosixLink()) // posix link can follow to dir
+ #endif
+ if (!isDir)
+ continue;
+
+ UStringVector newParts;
+ const NWildcard::CCensorNode *nextNode = NULL;
+ int index = curNode.FindSubNode(name);
+ if (index >= 0)
+ {
+ for (int t = (int)needEnterVector.Size(); t <= index; t++)
+ needEnterVector.Add(true);
+ needEnterVector[(unsigned)index] = false;
+ nextNode = &curNode.SubNodes[(unsigned)index];
+ }
+ else
+ {
+ #ifndef _WIN32
+ if (fi.IsPosixLink())
+ {
+ // here we can try to resolve posix link
+ // if the link to dir, then can we follow it
+ continue; // we don't follow posix link
+ }
+ #else
+ if (dirItems.SymLinks)
+ {
+ if (fi.HasReparsePoint())
+ {
+ /* 20.03: in SymLinks mode: we don't enter to directory that
+ has reparse point and has no CCensorNode */
+ continue;
+ }
+ }
+ #endif
+ nextNode = &curNode;
+ newParts.Add(name); // don't change it to fi.Name. It's for shortnames support
+ }
+
+ RINOK(EnumerateDirItems_Spec(*nextNode, phyParent, logParent, fi.Name, phyPrefix,
+ newParts, dirItems, true))
+ }
+
+ for (i = 0; i < curNode.SubNodes.Size(); i++)
+ {
+ if (i < needEnterVector.Size())
+ if (!needEnterVector[i])
+ continue;
+ const NWildcard::CCensorNode &nextNode = curNode.SubNodes[i];
+ FString fullPath = phyPrefix + us2fs(nextNode.Name);
+ NFind::CFileInfo fi;
+
+ if (nextNode.Name.IsEmpty())
+ {
+ if (phyPrefix.IsEmpty())
+ fullPath = CHAR_PATH_SEPARATOR;
+ }
+ #ifdef _WIN32
+ else if(phyPrefix.IsEmpty()
+ || (phyPrefix.Len() == NName::kSuperPathPrefixSize
+ && IsSuperPath(phyPrefix)))
+ {
+ if (NWildcard::IsDriveColonName(nextNode.Name))
+ fullPath.Add_PathSepar();
+ }
+ #endif
+
+ // we don't want to call fi.Find() for root folder or virtual folder
+ if ((phyPrefix.IsEmpty() && nextNode.Name.IsEmpty())
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ || IsVirtualFsFolder(phyPrefix, nextNode.Name)
+ #endif
+ )
+ {
+ fi.SetAsDir();
+ fi.Name = us2fs(nextNode.Name);
+ }
+ else
+ {
+ if (!FindFile_KeepDots(fi, fullPath FOLLOW_LINK_PARAM2))
+ {
+ if (!nextNode.AreThereIncludeItems())
+ continue;
+ RINOK(dirItems.AddError(fullPath))
+ continue;
+ }
+
+ if (!fi.IsDir())
+ {
+ RINOK(dirItems.AddError(fullPath, DI_DEFAULT_ERROR))
+ continue;
+ }
+ }
+
+ RINOK(EnumerateDirItems_Spec(nextNode, phyParent, logParent, fi.Name, phyPrefix,
+ UStringVector(), dirItems, false))
+ }
+
+ return S_OK;
+ }
+ }
+
+ #ifdef _WIN32
+ #ifndef UNDER_CE
+
+ // scan drives, if wildcard is "*:\"
+
+ if (phyPrefix.IsEmpty() && curNode.IncludeItems.Size() > 0)
+ {
+ unsigned i;
+ for (i = 0; i < curNode.IncludeItems.Size(); i++)
+ {
+ const NWildcard::CItem &item = curNode.IncludeItems[i];
+ if (item.PathParts.Size() < 1)
+ break;
+ const UString &name = item.PathParts.Front();
+ if (name.Len() != 2 || name[1] != ':')
+ break;
+ if (item.PathParts.Size() == 1)
+ if (item.ForFile || !item.ForDir)
+ break;
+ if (NWildcard::IsDriveColonName(name))
+ continue;
+ if (name[0] != '*' && name[0] != '?')
+ break;
+ }
+ if (i == curNode.IncludeItems.Size())
+ {
+ FStringVector driveStrings;
+ NFind::MyGetLogicalDriveStrings(driveStrings);
+ for (i = 0; i < driveStrings.Size(); i++)
+ {
+ FString driveName = driveStrings[i];
+ if (driveName.Len() < 3 || driveName.Back() != '\\')
+ return E_FAIL;
+ driveName.DeleteBack();
+ NFind::CFileInfo fi;
+ fi.SetAsDir();
+ fi.Name = driveName;
+
+ RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix,
+ addParts, dirItems, enterToSubFolders))
+ }
+ return S_OK;
+ }
+ }
+
+ #endif
+ #endif
+
+
+ CObjectVector<NFind::CFileInfo> files;
+
+ // for (int y = 0; y < 1; y++)
+ {
+ // files.Clear();
+ RINOK(dirItems.EnumerateOneDir(phyPrefix, files))
+ /*
+ FOR_VECTOR (i, files)
+ {
+ #ifdef _WIN32
+ // const NFind::CFileInfo &fi = files[i];
+ #else
+ NFind::CFileInfo &fi = files[i];
+ {
+ const NFind::CFileInfo &di = files[i];
+ const FString path = phyPrefix + di.Name;
+ if (!fi.Find_AfterEnumerator(path))
+ {
+ RINOK(dirItems.AddError(path));
+ continue;
+ }
+ fi.Name = di.Name;
+ }
+ #endif
+
+ }
+ */
+ }
+
+ FOR_VECTOR (i, files)
+ {
+ #ifdef _WIN32
+ const NFind::CFileInfo &fi = files[i];
+ #else
+ const NFind::CFileInfo &fi = files[i];
+ /*
+ NFind::CFileInfo fi;
+ {
+ const NFind::CDirEntry &di = files[i];
+ const FString path = phyPrefix + di.Name;
+ if (!fi.Find_AfterEnumerator(path))
+ {
+ RINOK(dirItems.AddError(path));
+ continue;
+ }
+ fi.Name = di.Name;
+ }
+ */
+ #endif
+
+ RINOK(EnumerateForItem(fi, curNode, phyParent, logParent, phyPrefix,
+ addParts, dirItems, enterToSubFolders))
+ if (dirItems.Callback && (i & kScanProgressStepMask) == kScanProgressStepMask)
+ {
+ RINOK(dirItems.ScanProgress(phyPrefix))
+ }
+ }
+
+ return S_OK;
+}
+
+
+
+
+HRESULT EnumerateItems(
+ const NWildcard::CCensor &censor,
+ const NWildcard::ECensorPathMode pathMode,
+ const UString &addPathPrefix, // prefix that will be added to Logical Path
+ CDirItems &dirItems)
+{
+ FOR_VECTOR (i, censor.Pairs)
+ {
+ const NWildcard::CPair &pair = censor.Pairs[i];
+ const int phyParent = pair.Prefix.IsEmpty() ? -1 : (int)dirItems.AddPrefix(-1, -1, pair.Prefix);
+ int logParent = -1;
+
+ if (pathMode == NWildcard::k_AbsPath)
+ logParent = phyParent;
+ else
+ {
+ if (!addPathPrefix.IsEmpty())
+ logParent = (int)dirItems.AddPrefix(-1, -1, addPathPrefix);
+ }
+
+ RINOK(EnumerateDirItems(pair.Head, phyParent, logParent, us2fs(pair.Prefix), UStringVector(),
+ dirItems,
+ false // enterToSubFolders
+ ))
+ }
+ dirItems.ReserveDown();
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ RINOK(dirItems.FillFixedReparse())
+ #endif
+
+ #ifndef _WIN32
+ RINOK(dirItems.FillDeviceSizes())
+ #endif
+
+ return S_OK;
+}
+
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+
+HRESULT CDirItems::FillFixedReparse()
+{
+ FOR_VECTOR(i, Items)
+ {
+ CDirItem &item = Items[i];
+
+ if (!SymLinks)
+ {
+ // continue; // for debug
+ if (!item.Has_Attrib_ReparsePoint())
+ continue;
+
+ // if (item.IsDir()) continue;
+
+ const FString phyPath = GetPhyPath(i);
+
+ NFind::CFileInfo fi;
+ if (fi.Fill_From_ByHandleFileInfo(phyPath)) // item.IsDir()
+ {
+ item.Size = fi.Size;
+ item.CTime = fi.CTime;
+ item.ATime = fi.ATime;
+ item.MTime = fi.MTime;
+ item.Attrib = fi.Attrib;
+ continue;
+ }
+
+ /*
+ // we request properties of target file instead of properies of symbolic link
+ // here we also can manually parse unsupported links (like WSL links)
+ NIO::CInFile inFile;
+ if (inFile.Open(phyPath))
+ {
+ BY_HANDLE_FILE_INFORMATION info;
+ if (inFile.GetFileInformation(&info))
+ {
+ // Stat.FilesSize doesn't contain item.Size already
+ // Stat.FilesSize -= item.Size;
+ item.Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
+ Stat.FilesSize += item.Size;
+ item.CTime = info.ftCreationTime;
+ item.ATime = info.ftLastAccessTime;
+ item.MTime = info.ftLastWriteTime;
+ item.Attrib = info.dwFileAttributes;
+ continue;
+ }
+ }
+ */
+
+ RINOK(AddError(phyPath))
+ continue;
+ }
+
+ // (SymLinks == true) here
+
+ if (item.ReparseData.Size() == 0)
+ continue;
+
+ // if (item.Size == 0)
+ {
+ // 20.03: we use Reparse Data instead of real data
+ item.Size = item.ReparseData.Size();
+ }
+
+ CReparseAttr attr;
+ if (!attr.Parse(item.ReparseData, item.ReparseData.Size()))
+ {
+ const FString phyPath = GetPhyPath(i);
+ AddError(phyPath, attr.ErrorCode);
+ continue;
+ }
+
+ /* imagex/WIM reduces absolute paths in links (raparse data),
+ if we archive non root folder. We do same thing here */
+
+ bool isWSL = false;
+ if (attr.IsSymLink_WSL())
+ {
+ // isWSL = true;
+ // we don't change WSL symlinks
+ continue;
+ }
+ else
+ {
+ if (attr.IsRelative_Win())
+ continue;
+ }
+
+ const UString &link = attr.GetPath();
+ if (!IsDrivePath(link))
+ continue;
+ // maybe we need to support networks paths also ?
+
+ FString fullPathF;
+ if (!NDir::MyGetFullPathName(GetPhyPath(i), fullPathF))
+ continue;
+ const UString fullPath = fs2us(fullPathF);
+ const UString logPath = GetLogPath(i);
+ if (logPath.Len() >= fullPath.Len())
+ continue;
+ if (CompareFileNames(logPath, fullPath.RightPtr(logPath.Len())) != 0)
+ continue;
+
+ const UString prefix = fullPath.Left(fullPath.Len() - logPath.Len());
+ if (!IsPathSepar(prefix.Back()))
+ continue;
+
+ const unsigned rootPrefixSize = GetRootPrefixSize(prefix);
+ if (rootPrefixSize == 0)
+ continue;
+ if (rootPrefixSize == prefix.Len())
+ continue; // simple case: paths are from root
+
+ if (link.Len() <= prefix.Len())
+ continue;
+
+ if (CompareFileNames(link.Left(prefix.Len()), prefix) != 0)
+ continue;
+
+ UString newLink = prefix.Left(rootPrefixSize);
+ newLink += link.Ptr(prefix.Len());
+
+ CByteBuffer data;
+ bool isSymLink = !attr.IsMountPoint();
+ if (!FillLinkData(data, newLink, isSymLink, isWSL))
+ continue;
+ item.ReparseData2 = data;
+ }
+ return S_OK;
+}
+
+#endif
+
+
+#ifndef _WIN32
+
+HRESULT CDirItems::FillDeviceSizes()
+{
+ {
+ FOR_VECTOR (i, Items)
+ {
+ CDirItem &item = Items[i];
+
+ if (S_ISBLK(item.mode) && item.Size == 0)
+ {
+ const FString phyPath = GetPhyPath(i);
+ NIO::CInFile inFile;
+ inFile.PreserveATime = true;
+ if (inFile.OpenShared(phyPath, ShareForWrite)) // fixme: OpenShared ??
+ {
+ UInt64 size = 0;
+ if (inFile.GetLength(size))
+ item.Size = size;
+ }
+ }
+ if (StoreOwnerName)
+ {
+ OwnerNameMap.Add_UInt32(item.uid);
+ OwnerGroupMap.Add_UInt32(item.gid);
+ }
+ }
+ }
+
+ if (StoreOwnerName)
+ {
+ UString u;
+ AString a;
+ {
+ FOR_VECTOR (i, OwnerNameMap.Numbers)
+ {
+ // 200K/sec speed
+ u.Empty();
+ const passwd *pw = getpwuid(OwnerNameMap.Numbers[i]);
+ // printf("\ngetpwuid=%s\n", pw->pw_name);
+ if (pw)
+ {
+ a = pw->pw_name;
+ ConvertUTF8ToUnicode(a, u);
+ }
+ OwnerNameMap.Strings.Add(u);
+ }
+ }
+ {
+ FOR_VECTOR (i, OwnerGroupMap.Numbers)
+ {
+ u.Empty();
+ const group *gr = getgrgid(OwnerGroupMap.Numbers[i]);
+ if (gr)
+ {
+ // printf("\ngetgrgid %d %s\n", OwnerGroupMap.Numbers[i], gr->gr_name);
+ a = gr->gr_name;
+ ConvertUTF8ToUnicode(a, u);
+ }
+ OwnerGroupMap.Strings.Add(u);
+ }
+ }
+
+ FOR_VECTOR (i, Items)
+ {
+ CDirItem &item = Items[i];
+ {
+ const int index = OwnerNameMap.Find(item.uid);
+ if (index < 0) throw 1;
+ item.OwnerNameIndex = index;
+ }
+ {
+ const int index = OwnerGroupMap.Find(item.gid);
+ if (index < 0) throw 1;
+ item.OwnerGroupIndex = index;
+ }
+ }
+ }
+
+
+ // if (NeedOwnerNames)
+ {
+ /*
+ {
+ for (unsigned i = 0 ; i < 10000; i++)
+ {
+ const passwd *pw = getpwuid(i);
+ if (pw)
+ {
+ UString u;
+ ConvertUTF8ToUnicode(AString(pw->pw_name), u);
+ OwnerNameMap.Add(i, u);
+ OwnerNameMap.Add(i, u);
+ OwnerNameMap.Add(i, u);
+ }
+ const group *gr = getgrgid(i);
+ if (gr)
+ {
+ // we can use utf-8 here.
+ UString u;
+ ConvertUTF8ToUnicode(AString(gr->gr_name), u);
+ OwnerGroupMap.Add(i, u);
+ }
+ }
+ }
+ */
+ /*
+ {
+ FOR_VECTOR (i, OwnerNameMap.Strings)
+ {
+ AString s;
+ ConvertUnicodeToUTF8(OwnerNameMap.Strings[i], s);
+ printf("\n%5d %s", (unsigned)OwnerNameMap.Numbers[i], s.Ptr());
+ }
+ }
+ {
+ printf("\n\n=========Groups\n");
+ FOR_VECTOR (i, OwnerGroupMap.Strings)
+ {
+ AString s;
+ ConvertUnicodeToUTF8(OwnerGroupMap.Strings[i], s);
+ printf("\n%5d %s", (unsigned)OwnerGroupMap.Numbers[i], s.Ptr());
+ }
+ }
+ */
+ }
+ /*
+ for (unsigned i = 0 ; i < 100000000; i++)
+ {
+ // const passwd *pw = getpwuid(1000);
+ // pw = pw;
+ int pos = OwnerNameMap.Find(1000);
+ if (pos < 0 - (int)i)
+ throw 1;
+ }
+ */
+
+ return S_OK;
+}
+
+#endif
+
+
+
+static const char * const kCannotFindArchive = "Cannot find archive";
+
+HRESULT EnumerateDirItemsAndSort(
+ NWildcard::CCensor &censor,
+ NWildcard::ECensorPathMode censorPathMode,
+ const UString &addPathPrefix,
+ UStringVector &sortedPaths,
+ UStringVector &sortedFullPaths,
+ CDirItemsStat &st,
+ IDirItemsCallback *callback)
+{
+ FStringVector paths;
+
+ {
+ CDirItems dirItems;
+ dirItems.Callback = callback;
+ {
+ HRESULT res = EnumerateItems(censor, censorPathMode, addPathPrefix, dirItems);
+ st = dirItems.Stat;
+ RINOK(res)
+ }
+
+ FOR_VECTOR (i, dirItems.Items)
+ {
+ const CDirItem &dirItem = dirItems.Items[i];
+ if (!dirItem.IsDir())
+ paths.Add(dirItems.GetPhyPath(i));
+ }
+ }
+
+ if (paths.Size() == 0)
+ {
+ // return S_OK;
+ throw CMessagePathException(kCannotFindArchive);
+ }
+
+ UStringVector fullPaths;
+
+ unsigned i;
+
+ for (i = 0; i < paths.Size(); i++)
+ {
+ FString fullPath;
+ NFile::NDir::MyGetFullPathName(paths[i], fullPath);
+ fullPaths.Add(fs2us(fullPath));
+ }
+
+ CUIntVector indices;
+ SortFileNames(fullPaths, indices);
+ sortedPaths.ClearAndReserve(indices.Size());
+ sortedFullPaths.ClearAndReserve(indices.Size());
+
+ for (i = 0; i < indices.Size(); i++)
+ {
+ unsigned index = indices[i];
+ sortedPaths.AddInReserved(fs2us(paths[index]));
+ sortedFullPaths.AddInReserved(fullPaths[index]);
+ if (i > 0 && CompareFileNames(sortedFullPaths[i], sortedFullPaths[i - 1]) == 0)
+ throw CMessagePathException("Duplicate archive path:", sortedFullPaths[i]);
+ }
+
+ return S_OK;
+}
+
+
+
+
+#ifdef _WIN32
+
+static bool IsDotsName(const wchar_t *s)
+{
+ return s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0));
+}
+
+// This code converts all short file names to long file names.
+
+static void ConvertToLongName(const UString &prefix, UString &name)
+{
+ if (name.IsEmpty()
+ || DoesNameContainWildcard(name)
+ || IsDotsName(name))
+ return;
+ NFind::CFileInfo fi;
+ const FString path (us2fs(prefix + name));
+ #ifndef UNDER_CE
+ if (NFile::NName::IsDevicePath(path))
+ return;
+ #endif
+ if (fi.Find(path))
+ name = fs2us(fi.Name);
+}
+
+static void ConvertToLongNames(const UString &prefix, CObjectVector<NWildcard::CItem> &items)
+{
+ FOR_VECTOR (i, items)
+ {
+ NWildcard::CItem &item = items[i];
+ if (item.Recursive || item.PathParts.Size() != 1)
+ continue;
+ if (prefix.IsEmpty() && item.IsDriveItem())
+ continue;
+ ConvertToLongName(prefix, item.PathParts.Front());
+ }
+}
+
+static void ConvertToLongNames(const UString &prefix, NWildcard::CCensorNode &node)
+{
+ ConvertToLongNames(prefix, node.IncludeItems);
+ ConvertToLongNames(prefix, node.ExcludeItems);
+ unsigned i;
+ for (i = 0; i < node.SubNodes.Size(); i++)
+ {
+ UString &name = node.SubNodes[i].Name;
+ if (prefix.IsEmpty() && NWildcard::IsDriveColonName(name))
+ continue;
+ ConvertToLongName(prefix, name);
+ }
+ // mix folders with same name
+ for (i = 0; i < node.SubNodes.Size(); i++)
+ {
+ NWildcard::CCensorNode &nextNode1 = node.SubNodes[i];
+ for (unsigned j = i + 1; j < node.SubNodes.Size();)
+ {
+ const NWildcard::CCensorNode &nextNode2 = node.SubNodes[j];
+ if (nextNode1.Name.IsEqualTo_NoCase(nextNode2.Name))
+ {
+ nextNode1.IncludeItems += nextNode2.IncludeItems;
+ nextNode1.ExcludeItems += nextNode2.ExcludeItems;
+ node.SubNodes.Delete(j);
+ }
+ else
+ j++;
+ }
+ }
+ for (i = 0; i < node.SubNodes.Size(); i++)
+ {
+ NWildcard::CCensorNode &nextNode = node.SubNodes[i];
+ ConvertToLongNames(prefix + nextNode.Name + WCHAR_PATH_SEPARATOR, nextNode);
+ }
+}
+
+void ConvertToLongNames(NWildcard::CCensor &censor)
+{
+ FOR_VECTOR (i, censor.Pairs)
+ {
+ NWildcard::CPair &pair = censor.Pairs[i];
+ ConvertToLongNames(pair.Prefix, pair.Head);
+ }
+}
+
+#endif
+
+
+CMessagePathException::CMessagePathException(const char *a, const wchar_t *u)
+{
+ (*this) += a;
+ if (u)
+ {
+ Add_LF();
+ (*this) += u;
+ }
+}
+
+CMessagePathException::CMessagePathException(const wchar_t *a, const wchar_t *u)
+{
+ (*this) += a;
+ if (u)
+ {
+ Add_LF();
+ (*this) += u;
+ }
+}
diff --git a/CPP/7zip/UI/Common/EnumDirItems.h b/CPP/7zip/UI/Common/EnumDirItems.h
index ae1d226..24f1c8b 100644
--- a/CPP/7zip/UI/Common/EnumDirItems.h
+++ b/CPP/7zip/UI/Common/EnumDirItems.h
@@ -1,42 +1,38 @@
-// EnumDirItems.h
-
-#ifndef __ENUM_DIR_ITEMS_H
-#define __ENUM_DIR_ITEMS_H
-
-#include "../../../Common/Wildcard.h"
-
-#include "../../../Windows/FileFind.h"
-
-#include "DirItem.h"
-
-void AddDirFileInfo(int phyParent, int logParent, int secureIndex,
- const NWindows::NFile::NFind::CFileInfo &fi, CObjectVector<CDirItem> &dirItems);
-
-HRESULT EnumerateItems(
- const NWildcard::CCensor &censor,
- NWildcard::ECensorPathMode pathMode,
- const UString &addPathPrefix,
- CDirItems &dirItems);
-
-
-struct CMessagePathException: public UString
-{
- CMessagePathException(const char *a, const wchar_t *u = NULL);
- CMessagePathException(const wchar_t *a, const wchar_t *u = NULL);
-};
-
-
-HRESULT EnumerateDirItemsAndSort(
- NWildcard::CCensor &censor,
- NWildcard::ECensorPathMode pathMode,
- const UString &addPathPrefix,
- UStringVector &sortedPaths,
- UStringVector &sortedFullPaths,
- CDirItemsStat &st,
- IDirItemsCallback *callback);
-
-#ifdef _WIN32
-void ConvertToLongNames(NWildcard::CCensor &censor);
-#endif
-
-#endif
+// EnumDirItems.h
+
+#ifndef ZIP7_INC_ENUM_DIR_ITEMS_H
+#define ZIP7_INC_ENUM_DIR_ITEMS_H
+
+#include "../../../Common/Wildcard.h"
+
+#include "DirItem.h"
+
+
+HRESULT EnumerateItems(
+ const NWildcard::CCensor &censor,
+ NWildcard::ECensorPathMode pathMode,
+ const UString &addPathPrefix,
+ CDirItems &dirItems);
+
+
+struct CMessagePathException: public UString
+{
+ CMessagePathException(const char *a, const wchar_t *u = NULL);
+ CMessagePathException(const wchar_t *a, const wchar_t *u = NULL);
+};
+
+
+HRESULT EnumerateDirItemsAndSort(
+ NWildcard::CCensor &censor,
+ NWildcard::ECensorPathMode pathMode,
+ const UString &addPathPrefix,
+ UStringVector &sortedPaths,
+ UStringVector &sortedFullPaths,
+ CDirItemsStat &st,
+ IDirItemsCallback *callback);
+
+#ifdef _WIN32
+void ConvertToLongNames(NWildcard::CCensor &censor);
+#endif
+
+#endif
diff --git a/CPP/7zip/UI/Common/ExitCode.h b/CPP/7zip/UI/Common/ExitCode.h
index d03ec6d..2d7b029 100644
--- a/CPP/7zip/UI/Common/ExitCode.h
+++ b/CPP/7zip/UI/Common/ExitCode.h
@@ -1,27 +1,27 @@
-// ExitCode.h
-
-#ifndef __EXIT_CODE_H
-#define __EXIT_CODE_H
-
-namespace NExitCode {
-
-enum EEnum {
-
- kSuccess = 0, // Successful operation
- kWarning = 1, // Non fatal error(s) occurred
- kFatalError = 2, // A fatal error occurred
- // kCRCError = 3, // A CRC error occurred when unpacking
- // kLockedArchive = 4, // Attempt to modify an archive previously locked
- // kWriteError = 5, // Write to disk error
- // kOpenError = 6, // Open file error
- kUserError = 7, // Command line option error
- kMemoryError = 8, // Not enough memory for operation
- // kCreateFileError = 9, // Create file error
-
- kUserBreak = 255 // User stopped the process
-
-};
-
-}
-
-#endif
+// ExitCode.h
+
+#ifndef ZIP7_INC_EXIT_CODE_H
+#define ZIP7_INC_EXIT_CODE_H
+
+namespace NExitCode {
+
+enum EEnum {
+
+ kSuccess = 0, // Successful operation
+ kWarning = 1, // Non fatal error(s) occurred
+ kFatalError = 2, // A fatal error occurred
+ // kCRCError = 3, // A CRC error occurred when unpacking
+ // kLockedArchive = 4, // Attempt to modify an archive previously locked
+ // kWriteError = 5, // Write to disk error
+ // kOpenError = 6, // Open file error
+ kUserError = 7, // Command line option error
+ kMemoryError = 8, // Not enough memory for operation
+ // kCreateFileError = 9, // Create file error
+
+ kUserBreak = 255 // User stopped the process
+
+};
+
+}
+
+#endif
diff --git a/CPP/7zip/UI/Common/Extract.cpp b/CPP/7zip/UI/Common/Extract.cpp
index 2cb2c9b..34b4871 100644
--- a/CPP/7zip/UI/Common/Extract.cpp
+++ b/CPP/7zip/UI/Common/Extract.cpp
@@ -1,482 +1,570 @@
-// Extract.cpp
-
-#include "StdAfx.h"
-
-#include "../../../../C/Sort.h"
-
-#include "../../../Common/StringConvert.h"
-
-#include "../../../Windows/FileDir.h"
-#include "../../../Windows/PropVariant.h"
-#include "../../../Windows/PropVariantConv.h"
-
-#include "../Common/ExtractingFilePath.h"
-
-#include "Extract.h"
-#include "SetProperties.h"
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NDir;
-
-static HRESULT DecompressArchive(
- CCodecs *codecs,
- const CArchiveLink &arcLink,
- UInt64 packSize,
- const NWildcard::CCensorNode &wildcardCensor,
- const CExtractOptions &options,
- bool calcCrc,
- IExtractCallbackUI *callback,
- CArchiveExtractCallback *ecs,
- UString &errorMessage,
- UInt64 &stdInProcessed)
-{
- const CArc &arc = arcLink.Arcs.Back();
- stdInProcessed = 0;
- IInArchive *archive = arc.Archive;
- CRecordVector<UInt32> realIndices;
-
- UStringVector removePathParts;
-
- FString outDir = options.OutputDir;
- UString replaceName = arc.DefaultName;
-
- if (arcLink.Arcs.Size() > 1)
- {
- // Most "pe" archives have same name of archive subfile "[0]" or ".rsrc_1".
- // So it extracts different archives to one folder.
- // We will use top level archive name
- const CArc &arc0 = arcLink.Arcs[0];
- if (StringsAreEqualNoCase_Ascii(codecs->Formats[arc0.FormatIndex].Name, "pe"))
- replaceName = arc0.DefaultName;
- }
-
- outDir.Replace(FString("*"), us2fs(Get_Correct_FsFile_Name(replaceName)));
-
- bool elimIsPossible = false;
- UString elimPrefix; // only pure name without dir delimiter
- FString outDirReduced = outDir;
-
- if (options.ElimDup.Val && options.PathMode != NExtract::NPathMode::kAbsPaths)
- {
- UString dirPrefix;
- SplitPathToParts_Smart(fs2us(outDir), dirPrefix, elimPrefix);
- if (!elimPrefix.IsEmpty())
- {
- if (IsPathSepar(elimPrefix.Back()))
- elimPrefix.DeleteBack();
- if (!elimPrefix.IsEmpty())
- {
- outDirReduced = us2fs(dirPrefix);
- elimIsPossible = true;
- }
- }
- }
-
- bool allFilesAreAllowed = wildcardCensor.AreAllAllowed();
-
- if (!options.StdInMode)
- {
- UInt32 numItems;
- RINOK(archive->GetNumberOfItems(&numItems));
-
- CReadArcItem item;
-
- for (UInt32 i = 0; i < numItems; i++)
- {
- if (elimIsPossible || !allFilesAreAllowed)
- {
- RINOK(arc.GetItem(i, item));
- }
- else
- {
- #ifdef SUPPORT_ALT_STREAMS
- item.IsAltStream = false;
- if (!options.NtOptions.AltStreams.Val && arc.Ask_AltStream)
- {
- RINOK(Archive_IsItem_AltStream(arc.Archive, i, item.IsAltStream));
- }
- #endif
- }
-
- #ifdef SUPPORT_ALT_STREAMS
- if (!options.NtOptions.AltStreams.Val && item.IsAltStream)
- continue;
- #endif
-
- if (elimIsPossible)
- {
- const UString &s =
- #ifdef SUPPORT_ALT_STREAMS
- item.MainPath;
- #else
- item.Path;
- #endif
- if (!IsPath1PrefixedByPath2(s, elimPrefix))
- elimIsPossible = false;
- else
- {
- wchar_t c = s[elimPrefix.Len()];
- if (c == 0)
- {
- if (!item.MainIsDir)
- elimIsPossible = false;
- }
- else if (!IsPathSepar(c))
- elimIsPossible = false;
- }
- }
-
- if (!allFilesAreAllowed)
- {
- if (!CensorNode_CheckPath(wildcardCensor, item))
- continue;
- }
-
- realIndices.Add(i);
- }
-
- if (realIndices.Size() == 0)
- {
- callback->ThereAreNoFiles();
- return callback->ExtractResult(S_OK);
- }
- }
-
- if (elimIsPossible)
- {
- removePathParts.Add(elimPrefix);
- // outDir = outDirReduced;
- }
-
- #ifdef _WIN32
- // GetCorrectFullFsPath doesn't like "..".
- // outDir.TrimRight();
- // outDir = GetCorrectFullFsPath(outDir);
- #endif
-
- if (outDir.IsEmpty())
- outDir = "." STRING_PATH_SEPARATOR;
- /*
- #ifdef _WIN32
- else if (NName::IsAltPathPrefix(outDir)) {}
- #endif
- */
- else if (!CreateComplexDir(outDir))
- {
- HRESULT res = ::GetLastError();
- if (res == S_OK)
- res = E_FAIL;
- errorMessage = "Can not create output directory: ";
- errorMessage += fs2us(outDir);
- return res;
- }
-
- ecs->Init(
- options.NtOptions,
- options.StdInMode ? &wildcardCensor : NULL,
- &arc,
- callback,
- options.StdOutMode, options.TestMode,
- outDir,
- removePathParts, false,
- packSize);
-
-
- #ifdef SUPPORT_LINKS
-
- if (!options.StdInMode &&
- !options.TestMode &&
- options.NtOptions.HardLinks.Val)
- {
- RINOK(ecs->PrepareHardLinks(&realIndices));
- }
-
- #endif
-
-
- HRESULT result;
- Int32 testMode = (options.TestMode && !calcCrc) ? 1: 0;
-
- CArchiveExtractCallback_Closer ecsCloser(ecs);
-
- if (options.StdInMode)
- {
- result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, ecs);
- NCOM::CPropVariant prop;
- if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK)
- ConvertPropVariantToUInt64(prop, stdInProcessed);
- }
- else
- result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, ecs);
-
- HRESULT res2 = ecsCloser.Close();
- if (result == S_OK)
- result = res2;
-
- return callback->ExtractResult(result);
-}
-
-/* v9.31: BUG was fixed:
- Sorted list for file paths was sorted with case insensitive compare function.
- But FindInSorted function did binary search via case sensitive compare function */
-
-int Find_FileName_InSortedVector(const UStringVector &fileName, const UString &name)
-{
- unsigned left = 0, right = fileName.Size();
- while (left != right)
- {
- unsigned mid = (left + right) / 2;
- const UString &midValue = fileName[mid];
- int compare = CompareFileNames(name, midValue);
- if (compare == 0)
- return mid;
- if (compare < 0)
- right = mid;
- else
- left = mid + 1;
- }
- return -1;
-}
-
-HRESULT Extract(
- CCodecs *codecs,
- const CObjectVector<COpenType> &types,
- const CIntVector &excludedFormats,
- UStringVector &arcPaths, UStringVector &arcPathsFull,
- const NWildcard::CCensorNode &wildcardCensor,
- const CExtractOptions &options,
- IOpenCallbackUI *openCallback,
- IExtractCallbackUI *extractCallback,
- #ifndef _SFX
- IHashCalc *hash,
- #endif
- UString &errorMessage,
- CDecompressStat &st)
-{
- st.Clear();
- UInt64 totalPackSize = 0;
- CRecordVector<UInt64> arcSizes;
-
- unsigned numArcs = options.StdInMode ? 1 : arcPaths.Size();
-
- unsigned i;
-
- for (i = 0; i < numArcs; i++)
- {
- NFind::CFileInfo fi;
- fi.Size = 0;
- if (!options.StdInMode)
- {
- const FString &arcPath = us2fs(arcPaths[i]);
- if (!fi.Find(arcPath))
- throw "there is no such archive";
- if (fi.IsDir())
- throw "can't decompress folder";
- }
- arcSizes.Add(fi.Size);
- totalPackSize += fi.Size;
- }
-
- CBoolArr skipArcs(numArcs);
- for (i = 0; i < numArcs; i++)
- skipArcs[i] = false;
-
- CArchiveExtractCallback *ecs = new CArchiveExtractCallback;
- CMyComPtr<IArchiveExtractCallback> ec(ecs);
- bool multi = (numArcs > 1);
- ecs->InitForMulti(multi, options.PathMode, options.OverwriteMode,
- false // keepEmptyDirParts
- );
- #ifndef _SFX
- ecs->SetHashMethods(hash);
- #endif
-
- if (multi)
- {
- RINOK(extractCallback->SetTotal(totalPackSize));
- }
-
- UInt64 totalPackProcessed = 0;
- bool thereAreNotOpenArcs = false;
-
- for (i = 0; i < numArcs; i++)
- {
- if (skipArcs[i])
- continue;
-
- const UString &arcPath = arcPaths[i];
- NFind::CFileInfo fi;
- if (options.StdInMode)
- {
- fi.Size = 0;
- fi.Attrib = 0;
- }
- else
- {
- if (!fi.Find(us2fs(arcPath)) || fi.IsDir())
- throw "there is no such archive";
- }
-
- /*
- #ifndef _NO_CRYPTO
- openCallback->Open_Clear_PasswordWasAsked_Flag();
- #endif
- */
-
- RINOK(extractCallback->BeforeOpen(arcPath, options.TestMode));
- CArchiveLink arcLink;
-
- CObjectVector<COpenType> types2 = types;
- /*
- #ifndef _SFX
- if (types.IsEmpty())
- {
- int pos = arcPath.ReverseFind(L'.');
- if (pos >= 0)
- {
- UString s = arcPath.Ptr(pos + 1);
- int index = codecs->FindFormatForExtension(s);
- if (index >= 0 && s == L"001")
- {
- s = arcPath.Left(pos);
- pos = s.ReverseFind(L'.');
- if (pos >= 0)
- {
- int index2 = codecs->FindFormatForExtension(s.Ptr(pos + 1));
- if (index2 >= 0) // && s.CompareNoCase(L"rar") != 0
- {
- types2.Add(index2);
- types2.Add(index);
- }
- }
- }
- }
- }
- #endif
- */
-
- COpenOptions op;
- #ifndef _SFX
- op.props = &options.Properties;
- #endif
- op.codecs = codecs;
- op.types = &types2;
- op.excludedFormats = &excludedFormats;
- op.stdInMode = options.StdInMode;
- op.stream = NULL;
- op.filePath = arcPath;
-
- HRESULT result = arcLink.Open_Strict(op, openCallback);
-
- if (result == E_ABORT)
- return result;
-
- // arcLink.Set_ErrorsText();
- RINOK(extractCallback->OpenResult(codecs, arcLink, arcPath, result));
-
- if (result != S_OK)
- {
- thereAreNotOpenArcs = true;
- if (!options.StdInMode)
- {
- NFind::CFileInfo fi2;
- if (fi2.Find(us2fs(arcPath)))
- if (!fi2.IsDir())
- totalPackProcessed += fi2.Size;
- }
- continue;
- }
-
- if (!options.StdInMode)
- {
- // numVolumes += arcLink.VolumePaths.Size();
- // arcLink.VolumesSize;
-
- // totalPackSize -= DeleteUsedFileNamesFromList(arcLink, i + 1, arcPaths, arcPathsFull, &arcSizes);
- // numArcs = arcPaths.Size();
- if (arcLink.VolumePaths.Size() != 0)
- {
- Int64 correctionSize = arcLink.VolumesSize;
- FOR_VECTOR (v, arcLink.VolumePaths)
- {
- int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]);
- if (index >= 0)
- {
- if ((unsigned)index > i)
- {
- skipArcs[(unsigned)index] = true;
- correctionSize -= arcSizes[(unsigned)index];
- }
- }
- }
- if (correctionSize != 0)
- {
- Int64 newPackSize = (Int64)totalPackSize + correctionSize;
- if (newPackSize < 0)
- newPackSize = 0;
- totalPackSize = newPackSize;
- RINOK(extractCallback->SetTotal(totalPackSize));
- }
- }
- }
-
- /*
- // Now openCallback and extractCallback use same object. So we don't need to send password.
-
- #ifndef _NO_CRYPTO
- bool passwordIsDefined;
- UString password;
- RINOK(openCallback->Open_GetPasswordIfAny(passwordIsDefined, password));
- if (passwordIsDefined)
- {
- RINOK(extractCallback->SetPassword(password));
- }
- #endif
- */
-
- CArc &arc = arcLink.Arcs.Back();
- arc.MTimeDefined = (!options.StdInMode && !fi.IsDevice);
- arc.MTime = fi.MTime;
-
- UInt64 packProcessed;
- bool calcCrc =
- #ifndef _SFX
- (hash != NULL);
- #else
- false;
- #endif
-
- RINOK(DecompressArchive(
- codecs,
- arcLink,
- fi.Size + arcLink.VolumesSize,
- wildcardCensor,
- options,
- calcCrc,
- extractCallback, ecs, errorMessage, packProcessed));
-
- if (!options.StdInMode)
- packProcessed = fi.Size + arcLink.VolumesSize;
- totalPackProcessed += packProcessed;
- ecs->LocalProgressSpec->InSize += packProcessed;
- ecs->LocalProgressSpec->OutSize = ecs->UnpackSize;
- if (!errorMessage.IsEmpty())
- return E_FAIL;
- }
-
- if (multi || thereAreNotOpenArcs)
- {
- RINOK(extractCallback->SetTotal(totalPackSize));
- RINOK(extractCallback->SetCompleted(&totalPackProcessed));
- }
-
- st.NumFolders = ecs->NumFolders;
- st.NumFiles = ecs->NumFiles;
- st.NumAltStreams = ecs->NumAltStreams;
- st.UnpackSize = ecs->UnpackSize;
- st.AltStreams_UnpackSize = ecs->AltStreams_UnpackSize;
- st.NumArchives = arcPaths.Size();
- st.PackSize = ecs->LocalProgressSpec->InSize;
- return S_OK;
-}
+// Extract.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Sort.h"
+
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/PropVariantConv.h"
+
+#include "../Common/ExtractingFilePath.h"
+#include "../Common/HashCalc.h"
+
+#include "Extract.h"
+#include "SetProperties.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+
+static void SetErrorMessage(const char *message,
+ const FString &path, HRESULT errorCode,
+ UString &s)
+{
+ s = message;
+ s += " : ";
+ s += NError::MyFormatMessage(errorCode);
+ s += " : ";
+ s += fs2us(path);
+}
+
+
+static HRESULT DecompressArchive(
+ CCodecs *codecs,
+ const CArchiveLink &arcLink,
+ UInt64 packSize,
+ const NWildcard::CCensorNode &wildcardCensor,
+ const CExtractOptions &options,
+ bool calcCrc,
+ IExtractCallbackUI *callback,
+ IFolderArchiveExtractCallback *callbackFAE,
+ CArchiveExtractCallback *ecs,
+ UString &errorMessage,
+ UInt64 &stdInProcessed)
+{
+ const CArc &arc = arcLink.Arcs.Back();
+ stdInProcessed = 0;
+ IInArchive *archive = arc.Archive;
+ CRecordVector<UInt32> realIndices;
+
+ UStringVector removePathParts;
+
+ FString outDir = options.OutputDir;
+ UString replaceName = arc.DefaultName;
+
+ if (arcLink.Arcs.Size() > 1)
+ {
+ // Most "pe" archives have same name of archive subfile "[0]" or ".rsrc_1".
+ // So it extracts different archives to one folder.
+ // We will use top level archive name
+ const CArc &arc0 = arcLink.Arcs[0];
+ if (arc0.FormatIndex >= 0 && StringsAreEqualNoCase_Ascii(codecs->Formats[(unsigned)arc0.FormatIndex].Name, "pe"))
+ replaceName = arc0.DefaultName;
+ }
+
+ outDir.Replace(FString("*"), us2fs(Get_Correct_FsFile_Name(replaceName)));
+
+ bool elimIsPossible = false;
+ UString elimPrefix; // only pure name without dir delimiter
+ FString outDirReduced = outDir;
+
+ if (options.ElimDup.Val && options.PathMode != NExtract::NPathMode::kAbsPaths)
+ {
+ UString dirPrefix;
+ SplitPathToParts_Smart(fs2us(outDir), dirPrefix, elimPrefix);
+ if (!elimPrefix.IsEmpty())
+ {
+ if (IsPathSepar(elimPrefix.Back()))
+ elimPrefix.DeleteBack();
+ if (!elimPrefix.IsEmpty())
+ {
+ outDirReduced = us2fs(dirPrefix);
+ elimIsPossible = true;
+ }
+ }
+ }
+
+ const bool allFilesAreAllowed = wildcardCensor.AreAllAllowed();
+
+ if (!options.StdInMode)
+ {
+ UInt32 numItems;
+ RINOK(archive->GetNumberOfItems(&numItems))
+
+ CReadArcItem item;
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ if (elimIsPossible
+ || !allFilesAreAllowed
+ || options.ExcludeDirItems
+ || options.ExcludeFileItems)
+ {
+ RINOK(arc.GetItem(i, item))
+ if (item.IsDir ? options.ExcludeDirItems : options.ExcludeFileItems)
+ continue;
+ }
+ else
+ {
+ #ifdef SUPPORT_ALT_STREAMS
+ item.IsAltStream = false;
+ if (!options.NtOptions.AltStreams.Val && arc.Ask_AltStream)
+ {
+ RINOK(Archive_IsItem_AltStream(arc.Archive, i, item.IsAltStream))
+ }
+ #endif
+ }
+
+ #ifdef SUPPORT_ALT_STREAMS
+ if (!options.NtOptions.AltStreams.Val && item.IsAltStream)
+ continue;
+ #endif
+
+ if (elimIsPossible)
+ {
+ const UString &s =
+ #ifdef SUPPORT_ALT_STREAMS
+ item.MainPath;
+ #else
+ item.Path;
+ #endif
+ if (!IsPath1PrefixedByPath2(s, elimPrefix))
+ elimIsPossible = false;
+ else
+ {
+ wchar_t c = s[elimPrefix.Len()];
+ if (c == 0)
+ {
+ if (!item.MainIsDir)
+ elimIsPossible = false;
+ }
+ else if (!IsPathSepar(c))
+ elimIsPossible = false;
+ }
+ }
+
+ if (!allFilesAreAllowed)
+ {
+ if (!CensorNode_CheckPath(wildcardCensor, item))
+ continue;
+ }
+
+ realIndices.Add(i);
+ }
+
+ if (realIndices.Size() == 0)
+ {
+ callback->ThereAreNoFiles();
+ return callback->ExtractResult(S_OK);
+ }
+ }
+
+ if (elimIsPossible)
+ {
+ removePathParts.Add(elimPrefix);
+ // outDir = outDirReduced;
+ }
+
+ #ifdef _WIN32
+ // GetCorrectFullFsPath doesn't like "..".
+ // outDir.TrimRight();
+ // outDir = GetCorrectFullFsPath(outDir);
+ #endif
+
+ if (outDir.IsEmpty())
+ outDir = "." STRING_PATH_SEPARATOR;
+ /*
+ #ifdef _WIN32
+ else if (NName::IsAltPathPrefix(outDir)) {}
+ #endif
+ */
+ else if (!CreateComplexDir(outDir))
+ {
+ const HRESULT res = GetLastError_noZero_HRESULT();
+ SetErrorMessage("Cannot create output directory", outDir, res, errorMessage);
+ return res;
+ }
+
+ ecs->Init(
+ options.NtOptions,
+ options.StdInMode ? &wildcardCensor : NULL,
+ &arc,
+ callbackFAE,
+ options.StdOutMode, options.TestMode,
+ outDir,
+ removePathParts, false,
+ packSize);
+
+
+ #ifdef SUPPORT_LINKS
+
+ if (!options.StdInMode &&
+ !options.TestMode &&
+ options.NtOptions.HardLinks.Val)
+ {
+ RINOK(ecs->PrepareHardLinks(&realIndices))
+ }
+
+ #endif
+
+
+ HRESULT result;
+ const Int32 testMode = (options.TestMode && !calcCrc) ? 1: 0;
+
+ CArchiveExtractCallback_Closer ecsCloser(ecs);
+
+ if (options.StdInMode)
+ {
+ result = archive->Extract(NULL, (UInt32)(Int32)-1, testMode, ecs);
+ NCOM::CPropVariant prop;
+ if (archive->GetArchiveProperty(kpidPhySize, &prop) == S_OK)
+ ConvertPropVariantToUInt64(prop, stdInProcessed);
+ }
+ else
+ result = archive->Extract(&realIndices.Front(), realIndices.Size(), testMode, ecs);
+
+ const HRESULT res2 = ecsCloser.Close();
+ if (result == S_OK)
+ result = res2;
+
+ return callback->ExtractResult(result);
+}
+
+/* v9.31: BUG was fixed:
+ Sorted list for file paths was sorted with case insensitive compare function.
+ But FindInSorted function did binary search via case sensitive compare function */
+
+int Find_FileName_InSortedVector(const UStringVector &fileNames, const UString &name);
+int Find_FileName_InSortedVector(const UStringVector &fileNames, const UString &name)
+{
+ unsigned left = 0, right = fileNames.Size();
+ while (left != right)
+ {
+ const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const UString &midVal = fileNames[mid];
+ const int comp = CompareFileNames(name, midVal);
+ if (comp == 0)
+ return (int)mid;
+ if (comp < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+}
+
+
+
+HRESULT Extract(
+ // DECL_EXTERNAL_CODECS_LOC_VARS
+ CCodecs *codecs,
+ const CObjectVector<COpenType> &types,
+ const CIntVector &excludedFormats,
+ UStringVector &arcPaths, UStringVector &arcPathsFull,
+ const NWildcard::CCensorNode &wildcardCensor,
+ const CExtractOptions &options,
+ IOpenCallbackUI *openCallback,
+ IExtractCallbackUI *extractCallback,
+ IFolderArchiveExtractCallback *faeCallback,
+ #ifndef Z7_SFX
+ IHashCalc *hash,
+ #endif
+ UString &errorMessage,
+ CDecompressStat &st)
+{
+ st.Clear();
+ UInt64 totalPackSize = 0;
+ CRecordVector<UInt64> arcSizes;
+
+ unsigned numArcs = options.StdInMode ? 1 : arcPaths.Size();
+
+ unsigned i;
+
+ for (i = 0; i < numArcs; i++)
+ {
+ NFind::CFileInfo fi;
+ fi.Size = 0;
+ if (!options.StdInMode)
+ {
+ const FString arcPath = us2fs(arcPaths[i]);
+ if (!fi.Find_FollowLink(arcPath))
+ {
+ const HRESULT errorCode = GetLastError_noZero_HRESULT();
+ SetErrorMessage("Cannot find archive file", arcPath, errorCode, errorMessage);
+ return errorCode;
+ }
+ if (fi.IsDir())
+ {
+ HRESULT errorCode = E_FAIL;
+ SetErrorMessage("The item is a directory", arcPath, errorCode, errorMessage);
+ return errorCode;
+ }
+ }
+ arcSizes.Add(fi.Size);
+ totalPackSize += fi.Size;
+ }
+
+ CBoolArr skipArcs(numArcs);
+ for (i = 0; i < numArcs; i++)
+ skipArcs[i] = false;
+
+ CArchiveExtractCallback *ecs = new CArchiveExtractCallback;
+ CMyComPtr<IArchiveExtractCallback> ec(ecs);
+
+ const bool multi = (numArcs > 1);
+
+ ecs->InitForMulti(multi,
+ options.PathMode,
+ options.OverwriteMode,
+ options.ZoneMode,
+ false // keepEmptyDirParts
+ );
+ #ifndef Z7_SFX
+ ecs->SetHashMethods(hash);
+ #endif
+
+ if (multi)
+ {
+ RINOK(faeCallback->SetTotal(totalPackSize))
+ }
+
+ UInt64 totalPackProcessed = 0;
+ bool thereAreNotOpenArcs = false;
+
+ for (i = 0; i < numArcs; i++)
+ {
+ if (skipArcs[i])
+ continue;
+
+ ecs->InitBeforeNewArchive();
+
+ const UString &arcPath = arcPaths[i];
+ NFind::CFileInfo fi;
+ if (options.StdInMode)
+ {
+ // do we need ctime and mtime?
+ fi.ClearBase();
+ fi.Size = 0; // (UInt64)(Int64)-1;
+ fi.SetAsFile();
+ // NTime::GetCurUtc_FiTime(fi.MTime);
+ // fi.CTime = fi.ATime = fi.MTime;
+ }
+ else
+ {
+ if (!fi.Find_FollowLink(us2fs(arcPath)) || fi.IsDir())
+ {
+ const HRESULT errorCode = GetLastError_noZero_HRESULT();
+ SetErrorMessage("Cannot find archive file", us2fs(arcPath), errorCode, errorMessage);
+ return errorCode;
+ }
+ }
+
+ /*
+ #ifndef Z7_NO_CRYPTO
+ openCallback->Open_Clear_PasswordWasAsked_Flag();
+ #endif
+ */
+
+ RINOK(extractCallback->BeforeOpen(arcPath, options.TestMode))
+ CArchiveLink arcLink;
+
+ CObjectVector<COpenType> types2 = types;
+ /*
+ #ifndef Z7_SFX
+ if (types.IsEmpty())
+ {
+ int pos = arcPath.ReverseFind(L'.');
+ if (pos >= 0)
+ {
+ UString s = arcPath.Ptr(pos + 1);
+ int index = codecs->FindFormatForExtension(s);
+ if (index >= 0 && s == L"001")
+ {
+ s = arcPath.Left(pos);
+ pos = s.ReverseFind(L'.');
+ if (pos >= 0)
+ {
+ int index2 = codecs->FindFormatForExtension(s.Ptr(pos + 1));
+ if (index2 >= 0) // && s.CompareNoCase(L"rar") != 0
+ {
+ types2.Add(index2);
+ types2.Add(index);
+ }
+ }
+ }
+ }
+ }
+ #endif
+ */
+
+ COpenOptions op;
+ #ifndef Z7_SFX
+ op.props = &options.Properties;
+ #endif
+ op.codecs = codecs;
+ op.types = &types2;
+ op.excludedFormats = &excludedFormats;
+ op.stdInMode = options.StdInMode;
+ op.stream = NULL;
+ op.filePath = arcPath;
+
+ HRESULT result = arcLink.Open_Strict(op, openCallback);
+
+ if (result == E_ABORT)
+ return result;
+
+ // arcLink.Set_ErrorsText();
+ RINOK(extractCallback->OpenResult(codecs, arcLink, arcPath, result))
+
+ if (result != S_OK)
+ {
+ thereAreNotOpenArcs = true;
+ if (!options.StdInMode)
+ totalPackProcessed += fi.Size;
+ continue;
+ }
+
+ #if defined(_WIN32) && !defined(UNDER_CE) && !defined(Z7_SFX)
+ if (options.ZoneMode != NExtract::NZoneIdMode::kNone
+ && !options.StdInMode)
+ {
+ ReadZoneFile_Of_BaseFile(us2fs(arcPath), ecs->ZoneBuf);
+ }
+ #endif
+
+
+ if (arcLink.Arcs.Size() != 0)
+ {
+ if (arcLink.GetArc()->IsHashHandler(op))
+ {
+ if (!options.TestMode)
+ {
+ /* real Extracting to files is possible.
+ But user can think that hash archive contains real files.
+ So we block extracting here. */
+ // v23.00 : we don't break process.
+ RINOK(extractCallback->OpenResult(codecs, arcLink, arcPath, E_NOTIMPL))
+ thereAreNotOpenArcs = true;
+ if (!options.StdInMode)
+ totalPackProcessed += fi.Size;
+ continue;
+ // return E_NOTIMPL; // before v23
+ }
+ FString dirPrefix = us2fs(options.HashDir);
+ if (dirPrefix.IsEmpty())
+ {
+ if (!NFile::NDir::GetOnlyDirPrefix(us2fs(arcPath), dirPrefix))
+ {
+ // return GetLastError_noZero_HRESULT();
+ }
+ }
+ if (!dirPrefix.IsEmpty())
+ NName::NormalizeDirPathPrefix(dirPrefix);
+ ecs->DirPathPrefix_for_HashFiles = dirPrefix;
+ }
+ }
+
+ if (!options.StdInMode)
+ {
+ // numVolumes += arcLink.VolumePaths.Size();
+ // arcLink.VolumesSize;
+
+ // totalPackSize -= DeleteUsedFileNamesFromList(arcLink, i + 1, arcPaths, arcPathsFull, &arcSizes);
+ // numArcs = arcPaths.Size();
+ if (arcLink.VolumePaths.Size() != 0)
+ {
+ Int64 correctionSize = (Int64)arcLink.VolumesSize;
+ FOR_VECTOR (v, arcLink.VolumePaths)
+ {
+ int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]);
+ if (index >= 0)
+ {
+ if ((unsigned)index > i)
+ {
+ skipArcs[(unsigned)index] = true;
+ correctionSize -= arcSizes[(unsigned)index];
+ }
+ }
+ }
+ if (correctionSize != 0)
+ {
+ Int64 newPackSize = (Int64)totalPackSize + correctionSize;
+ if (newPackSize < 0)
+ newPackSize = 0;
+ totalPackSize = (UInt64)newPackSize;
+ RINOK(faeCallback->SetTotal(totalPackSize))
+ }
+ }
+ }
+
+ /*
+ // Now openCallback and extractCallback use same object. So we don't need to send password.
+
+ #ifndef Z7_NO_CRYPTO
+ bool passwordIsDefined;
+ UString password;
+ RINOK(openCallback->Open_GetPasswordIfAny(passwordIsDefined, password))
+ if (passwordIsDefined)
+ {
+ RINOK(extractCallback->SetPassword(password))
+ }
+ #endif
+ */
+
+ CArc &arc = arcLink.Arcs.Back();
+ arc.MTime.Def = !options.StdInMode
+ #ifdef _WIN32
+ && !fi.IsDevice
+ #endif
+ ;
+ if (arc.MTime.Def)
+ arc.MTime.Set_From_FiTime(fi.MTime);
+
+ UInt64 packProcessed;
+ const bool calcCrc =
+ #ifndef Z7_SFX
+ (hash != NULL);
+ #else
+ false;
+ #endif
+
+ RINOK(DecompressArchive(
+ codecs,
+ arcLink,
+ fi.Size + arcLink.VolumesSize,
+ wildcardCensor,
+ options,
+ calcCrc,
+ extractCallback, faeCallback, ecs,
+ errorMessage, packProcessed))
+
+ if (!options.StdInMode)
+ packProcessed = fi.Size + arcLink.VolumesSize;
+ totalPackProcessed += packProcessed;
+ ecs->LocalProgressSpec->InSize += packProcessed;
+ ecs->LocalProgressSpec->OutSize = ecs->UnpackSize;
+ if (!errorMessage.IsEmpty())
+ return E_FAIL;
+ }
+
+ if (multi || thereAreNotOpenArcs)
+ {
+ RINOK(faeCallback->SetTotal(totalPackSize))
+ RINOK(faeCallback->SetCompleted(&totalPackProcessed))
+ }
+
+ st.NumFolders = ecs->NumFolders;
+ st.NumFiles = ecs->NumFiles;
+ st.NumAltStreams = ecs->NumAltStreams;
+ st.UnpackSize = ecs->UnpackSize;
+ st.AltStreams_UnpackSize = ecs->AltStreams_UnpackSize;
+ st.NumArchives = arcPaths.Size();
+ st.PackSize = ecs->LocalProgressSpec->InSize;
+ return S_OK;
+}
diff --git a/CPP/7zip/UI/Common/Extract.h b/CPP/7zip/UI/Common/Extract.h
index 9c806be..b20f607 100644
--- a/CPP/7zip/UI/Common/Extract.h
+++ b/CPP/7zip/UI/Common/Extract.h
@@ -1,94 +1,106 @@
-// Extract.h
-
-#ifndef __EXTRACT_H
-#define __EXTRACT_H
-
-#include "../../../Windows/FileFind.h"
-
-#include "../../Archive/IArchive.h"
-
-#include "ArchiveExtractCallback.h"
-#include "ArchiveOpenCallback.h"
-#include "ExtractMode.h"
-#include "Property.h"
-
-#include "../Common/LoadCodecs.h"
-
-struct CExtractOptionsBase
-{
- CBoolPair ElimDup;
-
- bool PathMode_Force;
- bool OverwriteMode_Force;
- NExtract::NPathMode::EEnum PathMode;
- NExtract::NOverwriteMode::EEnum OverwriteMode;
-
- FString OutputDir;
- CExtractNtOptions NtOptions;
-
- CExtractOptionsBase():
- PathMode_Force(false),
- OverwriteMode_Force(false),
- PathMode(NExtract::NPathMode::kFullPaths),
- OverwriteMode(NExtract::NOverwriteMode::kAsk)
- {}
-};
-
-struct CExtractOptions: public CExtractOptionsBase
-{
- bool StdInMode;
- bool StdOutMode;
- bool YesToAll;
- bool TestMode;
-
- // bool ShowDialog;
- // bool PasswordEnabled;
- // UString Password;
- #ifndef _SFX
- CObjectVector<CProperty> Properties;
- #endif
-
- #ifdef EXTERNAL_CODECS
- CCodecs *Codecs;
- #endif
-
- CExtractOptions():
- TestMode(false),
- StdInMode(false),
- StdOutMode(false),
- YesToAll(false)
- {}
-};
-
-struct CDecompressStat
-{
- UInt64 NumArchives;
- UInt64 UnpackSize;
- UInt64 AltStreams_UnpackSize;
- UInt64 PackSize;
- UInt64 NumFolders;
- UInt64 NumFiles;
- UInt64 NumAltStreams;
-
- void Clear()
- {
- NumArchives = UnpackSize = AltStreams_UnpackSize = PackSize = NumFolders = NumFiles = NumAltStreams = 0;
- }
-};
-
-HRESULT Extract(
- CCodecs *codecs,
- const CObjectVector<COpenType> &types,
- const CIntVector &excludedFormats,
- UStringVector &archivePaths, UStringVector &archivePathsFull,
- const NWildcard::CCensorNode &wildcardCensor,
- const CExtractOptions &options,
- IOpenCallbackUI *openCallback,
- IExtractCallbackUI *extractCallback,
- #ifndef _SFX
- IHashCalc *hash,
- #endif
- UString &errorMessage,
- CDecompressStat &st);
-
-#endif
+// Extract.h
+
+#ifndef ZIP7_INC_EXTRACT_H
+#define ZIP7_INC_EXTRACT_H
+
+#include "../../../Windows/FileFind.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "ArchiveExtractCallback.h"
+#include "ArchiveOpenCallback.h"
+#include "ExtractMode.h"
+#include "Property.h"
+
+#include "../Common/LoadCodecs.h"
+
+struct CExtractOptionsBase
+{
+ CBoolPair ElimDup;
+
+ bool ExcludeDirItems;
+ bool ExcludeFileItems;
+
+ bool PathMode_Force;
+ bool OverwriteMode_Force;
+ NExtract::NPathMode::EEnum PathMode;
+ NExtract::NOverwriteMode::EEnum OverwriteMode;
+ NExtract::NZoneIdMode::EEnum ZoneMode;
+
+ FString OutputDir;
+ CExtractNtOptions NtOptions;
+ UString HashDir;
+
+ CExtractOptionsBase():
+ ExcludeDirItems(false),
+ ExcludeFileItems(false),
+ PathMode_Force(false),
+ OverwriteMode_Force(false),
+ PathMode(NExtract::NPathMode::kFullPaths),
+ OverwriteMode(NExtract::NOverwriteMode::kAsk),
+ ZoneMode(NExtract::NZoneIdMode::kNone)
+ {}
+};
+
+struct CExtractOptions: public CExtractOptionsBase
+{
+ bool StdInMode;
+ bool StdOutMode;
+ bool YesToAll;
+ bool TestMode;
+
+ // bool ShowDialog;
+ // bool PasswordEnabled;
+ // UString Password;
+ #ifndef Z7_SFX
+ CObjectVector<CProperty> Properties;
+ #endif
+
+ /*
+ #ifdef Z7_EXTERNAL_CODECS
+ CCodecs *Codecs;
+ #endif
+ */
+
+ CExtractOptions():
+ StdInMode(false),
+ StdOutMode(false),
+ YesToAll(false),
+ TestMode(false)
+ {}
+};
+
+struct CDecompressStat
+{
+ UInt64 NumArchives;
+ UInt64 UnpackSize;
+ UInt64 AltStreams_UnpackSize;
+ UInt64 PackSize;
+ UInt64 NumFolders;
+ UInt64 NumFiles;
+ UInt64 NumAltStreams;
+
+ void Clear()
+ {
+ NumArchives = UnpackSize = AltStreams_UnpackSize = PackSize = NumFolders = NumFiles = NumAltStreams = 0;
+ }
+};
+
+HRESULT Extract(
+ // DECL_EXTERNAL_CODECS_LOC_VARS
+ CCodecs *codecs,
+ const CObjectVector<COpenType> &types,
+ const CIntVector &excludedFormats,
+ UStringVector &archivePaths, UStringVector &archivePathsFull,
+ const NWildcard::CCensorNode &wildcardCensor,
+ const CExtractOptions &options,
+ IOpenCallbackUI *openCallback,
+ IExtractCallbackUI *extractCallback,
+ IFolderArchiveExtractCallback *faeCallback,
+ #ifndef Z7_SFX
+ IHashCalc *hash,
+ #endif
+ UString &errorMessage,
+ CDecompressStat &st);
+
+#endif
diff --git a/CPP/7zip/UI/Common/ExtractMode.h b/CPP/7zip/UI/Common/ExtractMode.h
index c28b7cc..6e38f26 100644
--- a/CPP/7zip/UI/Common/ExtractMode.h
+++ b/CPP/7zip/UI/Common/ExtractMode.h
@@ -1,34 +1,44 @@
-// ExtractMode.h
-
-#ifndef __EXTRACT_MODE_H
-#define __EXTRACT_MODE_H
-
-namespace NExtract {
-
-namespace NPathMode
-{
- enum EEnum
- {
- kFullPaths,
- kCurPaths,
- kNoPaths,
- kAbsPaths,
- kNoPathsAlt // alt streams must be extracted without name of base file
- };
-}
-
-namespace NOverwriteMode
-{
- enum EEnum
- {
- kAsk,
- kOverwrite,
- kSkip,
- kRename,
- kRenameExisting
- };
-}
-
-}
-
-#endif
+// ExtractMode.h
+
+#ifndef ZIP7_INC_EXTRACT_MODE_H
+#define ZIP7_INC_EXTRACT_MODE_H
+
+namespace NExtract {
+
+namespace NPathMode
+{
+ enum EEnum
+ {
+ kFullPaths,
+ kCurPaths,
+ kNoPaths,
+ kAbsPaths,
+ kNoPathsAlt // alt streams must be extracted without name of base file
+ };
+}
+
+namespace NOverwriteMode
+{
+ enum EEnum
+ {
+ kAsk,
+ kOverwrite,
+ kSkip,
+ kRename,
+ kRenameExisting
+ };
+}
+
+namespace NZoneIdMode
+{
+ enum EEnum
+ {
+ kNone,
+ kAll,
+ kOffice
+ };
+}
+
+}
+
+#endif
diff --git a/CPP/7zip/UI/Common/ExtractingFilePath.cpp b/CPP/7zip/UI/Common/ExtractingFilePath.cpp
index 13665de..88da4ad 100644
--- a/CPP/7zip/UI/Common/ExtractingFilePath.cpp
+++ b/CPP/7zip/UI/Common/ExtractingFilePath.cpp
@@ -1,280 +1,296 @@
-// ExtractingFilePath.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/Wildcard.h"
-
-#include "../../../Windows/FileName.h"
-
-#include "ExtractingFilePath.h"
-
-bool g_PathTrailReplaceMode =
- #ifdef _WIN32
- true
- #else
- false
- #endif
- ;
-
-
-static void ReplaceIncorrectChars(UString &s)
-{
- {
- for (unsigned i = 0; i < s.Len(); i++)
- {
- wchar_t c = s[i];
- if (
- #ifdef _WIN32
- c == ':' || c == '*' || c == '?' || c < 0x20 || c == '<' || c == '>' || c == '|' || c == '"'
- || c == '/'
- // || c == 0x202E // RLO
- ||
- #endif
- c == WCHAR_PATH_SEPARATOR)
- s.ReplaceOneCharAtPos(i, '_');
- }
- }
-
- if (g_PathTrailReplaceMode)
- {
- /*
- // if (g_PathTrailReplaceMode == 1)
- {
- if (!s.IsEmpty())
- {
- wchar_t c = s.Back();
- if (c == '.' || c == ' ')
- {
- // s += (wchar_t)(0x9c); // STRING TERMINATOR
- s += (wchar_t)'_';
- }
- }
- }
- else
- */
- {
- unsigned i;
- for (i = s.Len(); i != 0;)
- {
- wchar_t c = s[i - 1];
- if (c != '.' && c != ' ')
- break;
- i--;
- s.ReplaceOneCharAtPos(i, '_');
- // s.ReplaceOneCharAtPos(i, (c == ' ' ? (wchar_t)(0x2423) : (wchar_t)0x00B7));
- }
- /*
- if (g_PathTrailReplaceMode > 1 && i != s.Len())
- {
- s.DeleteFrom(i);
- }
- */
- }
- }
-}
-
-#ifdef _WIN32
-
-/* WinXP-64 doesn't support ':', '\\' and '/' symbols in name of alt stream.
- But colon in postfix ":$DATA" is allowed.
- WIN32 functions don't allow empty alt stream name "name:" */
-
-void Correct_AltStream_Name(UString &s)
-{
- unsigned len = s.Len();
- const unsigned kPostfixSize = 6;
- if (s.Len() >= kPostfixSize
- && StringsAreEqualNoCase_Ascii(s.RightPtr(kPostfixSize), ":$DATA"))
- len -= kPostfixSize;
- for (unsigned i = 0; i < len; i++)
- {
- wchar_t c = s[i];
- if (c == ':' || c == '\\' || c == '/'
- || c == 0x202E // RLO
- )
- s.ReplaceOneCharAtPos(i, '_');
- }
- if (s.IsEmpty())
- s = '_';
-}
-
-static const unsigned g_ReservedWithNum_Index = 4;
-
-static const char * const g_ReservedNames[] =
-{
- "CON", "PRN", "AUX", "NUL",
- "COM", "LPT"
-};
-
-static bool IsSupportedName(const UString &name)
-{
- for (unsigned i = 0; i < ARRAY_SIZE(g_ReservedNames); i++)
- {
- const char *reservedName = g_ReservedNames[i];
- unsigned len = MyStringLen(reservedName);
- if (name.Len() < len)
- continue;
- if (!name.IsPrefixedBy_Ascii_NoCase(reservedName))
- continue;
- if (i >= g_ReservedWithNum_Index)
- {
- wchar_t c = name[len];
- if (c < L'0' || c > L'9')
- continue;
- len++;
- }
- for (;;)
- {
- wchar_t c = name[len++];
- if (c == 0 || c == '.')
- return false;
- if (c != ' ')
- break;
- }
- }
- return true;
-}
-
-static void CorrectUnsupportedName(UString &name)
-{
- if (!IsSupportedName(name))
- name.InsertAtFront(L'_');
-}
-
-#endif
-
-static void Correct_PathPart(UString &s)
-{
- // "." and ".."
- if (s.IsEmpty())
- return;
-
- if (s[0] == '.' && (s[1] == 0 || s[1] == '.' && s[2] == 0))
- s.Empty();
- #ifdef _WIN32
- else
- ReplaceIncorrectChars(s);
- #endif
-}
-
-// static const char * const k_EmptyReplaceName = "[]";
-static const char k_EmptyReplaceName = '_';
-
-UString Get_Correct_FsFile_Name(const UString &name)
-{
- UString res = name;
- Correct_PathPart(res);
-
- #ifdef _WIN32
- CorrectUnsupportedName(res);
- #endif
-
- if (res.IsEmpty())
- res = k_EmptyReplaceName;
- return res;
-}
-
-
-void Correct_FsPath(bool absIsAllowed, bool keepAndReplaceEmptyPrefixes, UStringVector &parts, bool isDir)
-{
- unsigned i = 0;
-
- if (absIsAllowed)
- {
- #if defined(_WIN32) && !defined(UNDER_CE)
- bool isDrive = false;
- #endif
-
- if (parts[0].IsEmpty())
- {
- i = 1;
- #if defined(_WIN32) && !defined(UNDER_CE)
- if (parts.Size() > 1 && parts[1].IsEmpty())
- {
- i = 2;
- if (parts.Size() > 2 && parts[2] == L"?")
- {
- i = 3;
- if (parts.Size() > 3 && NWindows::NFile::NName::IsDrivePath2(parts[3]))
- {
- isDrive = true;
- i = 4;
- }
- }
- }
- #endif
- }
- #if defined(_WIN32) && !defined(UNDER_CE)
- else if (NWindows::NFile::NName::IsDrivePath2(parts[0]))
- {
- isDrive = true;
- i = 1;
- }
-
- if (isDrive)
- {
- // we convert "c:name" to "c:\name", if absIsAllowed path.
- UString &ds = parts[i - 1];
- if (ds.Len() > 2)
- {
- parts.Insert(i, ds.Ptr(2));
- ds.DeleteFrom(2);
- }
- }
- #endif
- }
-
- if (i != 0)
- keepAndReplaceEmptyPrefixes = false;
-
- for (; i < parts.Size();)
- {
- UString &s = parts[i];
-
- Correct_PathPart(s);
-
- if (s.IsEmpty())
- {
- if (!keepAndReplaceEmptyPrefixes)
- if (isDir || i != parts.Size() - 1)
- {
- parts.Delete(i);
- continue;
- }
- s = k_EmptyReplaceName;
- }
- else
- {
- keepAndReplaceEmptyPrefixes = false;
- #ifdef _WIN32
- CorrectUnsupportedName(s);
- #endif
- }
-
- i++;
- }
-
- if (!isDir)
- {
- if (parts.IsEmpty())
- parts.Add((UString)k_EmptyReplaceName);
- else
- {
- UString &s = parts.Back();
- if (s.IsEmpty())
- s = k_EmptyReplaceName;
- }
- }
-}
-
-UString MakePathFromParts(const UStringVector &parts)
-{
- UString s;
- FOR_VECTOR (i, parts)
- {
- if (i != 0)
- s.Add_PathSepar();
- s += parts[i];
- }
- return s;
-}
+// ExtractingFilePath.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/FileName.h"
+
+#include "ExtractingFilePath.h"
+
+extern
+bool g_PathTrailReplaceMode;
+bool g_PathTrailReplaceMode =
+ #ifdef _WIN32
+ true
+ #else
+ false
+ #endif
+ ;
+
+
+#ifdef _WIN32
+static void ReplaceIncorrectChars(UString &s)
+{
+ {
+ for (unsigned i = 0; i < s.Len(); i++)
+ {
+ wchar_t c = s[i];
+ if (
+ #ifdef _WIN32
+ c == ':' || c == '*' || c == '?' || c < 0x20 || c == '<' || c == '>' || c == '|' || c == '"'
+ || c == '/'
+ // || c == 0x202E // RLO
+ ||
+ #endif
+ c == WCHAR_PATH_SEPARATOR)
+ {
+ #if WCHAR_PATH_SEPARATOR != L'/'
+ // 22.00 : WSL replacement for backslash
+ if (c == WCHAR_PATH_SEPARATOR)
+ c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT;
+ else
+ #endif
+ c = '_';
+ s.ReplaceOneCharAtPos(i,
+ c
+ // (wchar_t)(0xf000 + c) // 21.02 debug: WSL encoding for unsupported characters
+ );
+ }
+ }
+ }
+
+ if (g_PathTrailReplaceMode)
+ {
+ /*
+ // if (g_PathTrailReplaceMode == 1)
+ {
+ if (!s.IsEmpty())
+ {
+ wchar_t c = s.Back();
+ if (c == '.' || c == ' ')
+ {
+ // s += (wchar_t)(0x9c); // STRING TERMINATOR
+ s += (wchar_t)'_';
+ }
+ }
+ }
+ else
+ */
+ {
+ unsigned i;
+ for (i = s.Len(); i != 0;)
+ {
+ wchar_t c = s[i - 1];
+ if (c != '.' && c != ' ')
+ break;
+ i--;
+ s.ReplaceOneCharAtPos(i, '_');
+ // s.ReplaceOneCharAtPos(i, (c == ' ' ? (wchar_t)(0x2423) : (wchar_t)0x00B7));
+ }
+ /*
+ if (g_PathTrailReplaceMode > 1 && i != s.Len())
+ {
+ s.DeleteFrom(i);
+ }
+ */
+ }
+ }
+}
+#endif
+
+/* WinXP-64 doesn't support ':', '\\' and '/' symbols in name of alt stream.
+ But colon in postfix ":$DATA" is allowed.
+ WIN32 functions don't allow empty alt stream name "name:" */
+
+void Correct_AltStream_Name(UString &s)
+{
+ unsigned len = s.Len();
+ const unsigned kPostfixSize = 6;
+ if (s.Len() >= kPostfixSize
+ && StringsAreEqualNoCase_Ascii(s.RightPtr(kPostfixSize), ":$DATA"))
+ len -= kPostfixSize;
+ for (unsigned i = 0; i < len; i++)
+ {
+ wchar_t c = s[i];
+ if (c == ':' || c == '\\' || c == '/'
+ || c == 0x202E // RLO
+ )
+ s.ReplaceOneCharAtPos(i, '_');
+ }
+ if (s.IsEmpty())
+ s = '_';
+}
+
+#ifdef _WIN32
+
+static const unsigned g_ReservedWithNum_Index = 4;
+
+static const char * const g_ReservedNames[] =
+{
+ "CON", "PRN", "AUX", "NUL",
+ "COM", "LPT"
+};
+
+static bool IsSupportedName(const UString &name)
+{
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_ReservedNames); i++)
+ {
+ const char *reservedName = g_ReservedNames[i];
+ unsigned len = MyStringLen(reservedName);
+ if (name.Len() < len)
+ continue;
+ if (!name.IsPrefixedBy_Ascii_NoCase(reservedName))
+ continue;
+ if (i >= g_ReservedWithNum_Index)
+ {
+ wchar_t c = name[len];
+ if (c < L'0' || c > L'9')
+ continue;
+ len++;
+ }
+ for (;;)
+ {
+ wchar_t c = name[len++];
+ if (c == 0 || c == '.')
+ return false;
+ if (c != ' ')
+ break;
+ }
+ }
+ return true;
+}
+
+static void CorrectUnsupportedName(UString &name)
+{
+ if (!IsSupportedName(name))
+ name.InsertAtFront(L'_');
+}
+
+#endif
+
+static void Correct_PathPart(UString &s)
+{
+ // "." and ".."
+ if (s.IsEmpty())
+ return;
+
+ if (s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0)))
+ s.Empty();
+ #ifdef _WIN32
+ else
+ ReplaceIncorrectChars(s);
+ #endif
+}
+
+// static const char * const k_EmptyReplaceName = "[]";
+static const char k_EmptyReplaceName = '_';
+
+UString Get_Correct_FsFile_Name(const UString &name)
+{
+ UString res = name;
+ Correct_PathPart(res);
+
+ #ifdef _WIN32
+ CorrectUnsupportedName(res);
+ #endif
+
+ if (res.IsEmpty())
+ res = k_EmptyReplaceName;
+ return res;
+}
+
+
+void Correct_FsPath(bool absIsAllowed, bool keepAndReplaceEmptyPrefixes, UStringVector &parts, bool isDir)
+{
+ unsigned i = 0;
+
+ if (absIsAllowed)
+ {
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ bool isDrive = false;
+ #endif
+
+ if (parts[0].IsEmpty())
+ {
+ i = 1;
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (parts.Size() > 1 && parts[1].IsEmpty())
+ {
+ i = 2;
+ if (parts.Size() > 2 && parts[2] == L"?")
+ {
+ i = 3;
+ if (parts.Size() > 3 && NWindows::NFile::NName::IsDrivePath2(parts[3]))
+ {
+ isDrive = true;
+ i = 4;
+ }
+ }
+ }
+ #endif
+ }
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ else if (NWindows::NFile::NName::IsDrivePath2(parts[0]))
+ {
+ isDrive = true;
+ i = 1;
+ }
+
+ if (isDrive)
+ {
+ // we convert "c:name" to "c:\name", if absIsAllowed path.
+ UString &ds = parts[i - 1];
+ if (ds.Len() > 2)
+ {
+ parts.Insert(i, ds.Ptr(2));
+ ds.DeleteFrom(2);
+ }
+ }
+ #endif
+ }
+
+ if (i != 0)
+ keepAndReplaceEmptyPrefixes = false;
+
+ for (; i < parts.Size();)
+ {
+ UString &s = parts[i];
+
+ Correct_PathPart(s);
+
+ if (s.IsEmpty())
+ {
+ if (!keepAndReplaceEmptyPrefixes)
+ if (isDir || i != parts.Size() - 1)
+ {
+ parts.Delete(i);
+ continue;
+ }
+ s = k_EmptyReplaceName;
+ }
+ else
+ {
+ keepAndReplaceEmptyPrefixes = false;
+ #ifdef _WIN32
+ CorrectUnsupportedName(s);
+ #endif
+ }
+
+ i++;
+ }
+
+ if (!isDir)
+ {
+ if (parts.IsEmpty())
+ parts.Add((UString)k_EmptyReplaceName);
+ else
+ {
+ UString &s = parts.Back();
+ if (s.IsEmpty())
+ s = k_EmptyReplaceName;
+ }
+ }
+}
+
+UString MakePathFromParts(const UStringVector &parts)
+{
+ UString s;
+ FOR_VECTOR (i, parts)
+ {
+ if (i != 0)
+ s.Add_PathSepar();
+ s += parts[i];
+ }
+ return s;
+}
diff --git a/CPP/7zip/UI/Common/ExtractingFilePath.h b/CPP/7zip/UI/Common/ExtractingFilePath.h
index 12eb0ba..bb1732f 100644
--- a/CPP/7zip/UI/Common/ExtractingFilePath.h
+++ b/CPP/7zip/UI/Common/ExtractingFilePath.h
@@ -1,31 +1,31 @@
-// ExtractingFilePath.h
-
-#ifndef __EXTRACTING_FILE_PATH_H
-#define __EXTRACTING_FILE_PATH_H
-
-#include "../../../Common/MyString.h"
-
-#ifdef _WIN32
-void Correct_AltStream_Name(UString &s);
-#endif
-
-// replaces unsuported characters, and replaces "." , ".." and "" to "[]"
-UString Get_Correct_FsFile_Name(const UString &name);
-
-/*
- Correct_FsPath() corrects path parts to prepare it for File System operations.
- It also corrects empty path parts like "\\\\":
- - frontal empty path parts : it removes them or changes them to "_"
- - another empty path parts : it removes them
- if (absIsAllowed && path is absolute) : it removes empty path parts after start absolute path prefix marker
- else
- {
- if (!keepAndReplaceEmptyPrefixes) : it removes empty path parts
- if ( keepAndReplaceEmptyPrefixes) : it changes each empty frontal path part to "_"
- }
-*/
-void Correct_FsPath(bool absIsAllowed, bool keepAndReplaceEmptyPrefixes, UStringVector &parts, bool isDir);
-
-UString MakePathFromParts(const UStringVector &parts);
-
-#endif
+// ExtractingFilePath.h
+
+#ifndef ZIP7_INC_EXTRACTING_FILE_PATH_H
+#define ZIP7_INC_EXTRACTING_FILE_PATH_H
+
+#include "../../../Common/MyString.h"
+
+// #ifdef _WIN32
+void Correct_AltStream_Name(UString &s);
+// #endif
+
+// replaces unsuported characters, and replaces "." , ".." and "" to "[]"
+UString Get_Correct_FsFile_Name(const UString &name);
+
+/*
+ Correct_FsPath() corrects path parts to prepare it for File System operations.
+ It also corrects empty path parts like "\\\\":
+ - frontal empty path parts : it removes them or changes them to "_"
+ - another empty path parts : it removes them
+ if (absIsAllowed && path is absolute) : it removes empty path parts after start absolute path prefix marker
+ else
+ {
+ if (!keepAndReplaceEmptyPrefixes) : it removes empty path parts
+ if ( keepAndReplaceEmptyPrefixes) : it changes each empty frontal path part to "_"
+ }
+*/
+void Correct_FsPath(bool absIsAllowed, bool keepAndReplaceEmptyPrefixes, UStringVector &parts, bool isDir);
+
+UString MakePathFromParts(const UStringVector &parts);
+
+#endif
diff --git a/CPP/7zip/UI/Common/HashCalc.cpp b/CPP/7zip/UI/Common/HashCalc.cpp
index 822018d..94c8a06 100644
--- a/CPP/7zip/UI/Common/HashCalc.cpp
+++ b/CPP/7zip/UI/Common/HashCalc.cpp
@@ -1,347 +1,2110 @@
-// HashCalc.cpp
-
-#include "StdAfx.h"
-
-#include "../../../../C/Alloc.h"
-
-#include "../../../Common/StringToInt.h"
-
-#include "../../Common/FileStreams.h"
-#include "../../Common/StreamUtils.h"
-
-#include "EnumDirItems.h"
-#include "HashCalc.h"
-
-using namespace NWindows;
-
-class CHashMidBuf
-{
- void *_data;
-public:
- CHashMidBuf(): _data(0) {}
- operator void *() { return _data; }
- bool Alloc(size_t size)
- {
- if (_data != 0)
- return false;
- _data = ::MidAlloc(size);
- return _data != 0;
- }
- ~CHashMidBuf() { ::MidFree(_data); }
-};
-
-static const char * const k_DefaultHashMethod = "CRC32";
-
-HRESULT CHashBundle::SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &hashMethods)
-{
- UStringVector names = hashMethods;
- if (names.IsEmpty())
- names.Add(UString(k_DefaultHashMethod));
-
- CRecordVector<CMethodId> ids;
- CObjectVector<COneMethodInfo> methods;
-
- unsigned i;
- for (i = 0; i < names.Size(); i++)
- {
- COneMethodInfo m;
- RINOK(m.ParseMethodFromString(names[i]));
-
- if (m.MethodName.IsEmpty())
- m.MethodName = k_DefaultHashMethod;
-
- if (m.MethodName == "*")
- {
- CRecordVector<CMethodId> tempMethods;
- GetHashMethods(EXTERNAL_CODECS_LOC_VARS tempMethods);
- methods.Clear();
- ids.Clear();
- FOR_VECTOR (t, tempMethods)
- {
- unsigned index = ids.AddToUniqueSorted(tempMethods[t]);
- if (ids.Size() != methods.Size())
- methods.Insert(index, m);
- }
- break;
- }
- else
- {
- // m.MethodName.RemoveChar(L'-');
- CMethodId id;
- if (!FindHashMethod(EXTERNAL_CODECS_LOC_VARS m.MethodName, id))
- return E_NOTIMPL;
- unsigned index = ids.AddToUniqueSorted(id);
- if (ids.Size() != methods.Size())
- methods.Insert(index, m);
- }
- }
-
- for (i = 0; i < ids.Size(); i++)
- {
- CMyComPtr<IHasher> hasher;
- AString name;
- RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS ids[i], name, hasher));
- if (!hasher)
- throw "Can't create hasher";
- const COneMethodInfo &m = methods[i];
- {
- CMyComPtr<ICompressSetCoderProperties> scp;
- hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp);
- if (scp)
- RINOK(m.SetCoderProps(scp, NULL));
- }
- UInt32 digestSize = hasher->GetDigestSize();
- if (digestSize > k_HashCalc_DigestSize_Max)
- return E_NOTIMPL;
- CHasherState &h = Hashers.AddNew();
- h.Hasher = hasher;
- h.Name = name;
- h.DigestSize = digestSize;
- for (unsigned k = 0; k < k_HashCalc_NumGroups; k++)
- memset(h.Digests[k], 0, digestSize);
- }
-
- return S_OK;
-}
-
-void CHashBundle::InitForNewFile()
-{
- CurSize = 0;
- FOR_VECTOR (i, Hashers)
- {
- CHasherState &h = Hashers[i];
- h.Hasher->Init();
- memset(h.Digests[k_HashCalc_Index_Current], 0, h.DigestSize);
- }
-}
-
-void CHashBundle::Update(const void *data, UInt32 size)
-{
- CurSize += size;
- FOR_VECTOR (i, Hashers)
- Hashers[i].Hasher->Update(data, size);
-}
-
-void CHashBundle::SetSize(UInt64 size)
-{
- CurSize = size;
-}
-
-static void AddDigests(Byte *dest, const Byte *src, UInt32 size)
-{
- unsigned next = 0;
- for (UInt32 i = 0; i < size; i++)
- {
- next += (unsigned)dest[i] + (unsigned)src[i];
- dest[i] = (Byte)next;
- next >>= 8;
- }
-}
-
-void CHashBundle::Final(bool isDir, bool isAltStream, const UString &path)
-{
- if (isDir)
- NumDirs++;
- else if (isAltStream)
- {
- NumAltStreams++;
- AltStreamsSize += CurSize;
- }
- else
- {
- NumFiles++;
- FilesSize += CurSize;
- }
-
- Byte pre[16];
- memset(pre, 0, sizeof(pre));
- if (isDir)
- pre[0] = 1;
-
- FOR_VECTOR (i, Hashers)
- {
- CHasherState &h = Hashers[i];
- if (!isDir)
- {
- h.Hasher->Final(h.Digests[0]);
- if (!isAltStream)
- AddDigests(h.Digests[k_HashCalc_Index_DataSum], h.Digests[0], h.DigestSize);
- }
-
- h.Hasher->Init();
- h.Hasher->Update(pre, sizeof(pre));
- h.Hasher->Update(h.Digests[0], h.DigestSize);
-
- for (unsigned k = 0; k < path.Len(); k++)
- {
- wchar_t c = path[k];
- Byte temp[2] = { (Byte)(c & 0xFF), (Byte)((c >> 8) & 0xFF) };
- h.Hasher->Update(temp, 2);
- }
-
- Byte tempDigest[k_HashCalc_DigestSize_Max];
- h.Hasher->Final(tempDigest);
- if (!isAltStream)
- AddDigests(h.Digests[k_HashCalc_Index_NamesSum], tempDigest, h.DigestSize);
- AddDigests(h.Digests[k_HashCalc_Index_StreamsSum], tempDigest, h.DigestSize);
- }
-}
-
-
-HRESULT HashCalc(
- DECL_EXTERNAL_CODECS_LOC_VARS
- const NWildcard::CCensor &censor,
- const CHashOptions &options,
- AString &errorInfo,
- IHashCallbackUI *callback)
-{
- CDirItems dirItems;
- dirItems.Callback = callback;
-
- if (options.StdInMode)
- {
- CDirItem di;
- di.Size = (UInt64)(Int64)-1;
- di.Attrib = 0;
- di.MTime.dwLowDateTime = 0;
- di.MTime.dwHighDateTime = 0;
- di.CTime = di.ATime = di.MTime;
- dirItems.Items.Add(di);
- }
- else
- {
- RINOK(callback->StartScanning());
- dirItems.ScanAltStreams = options.AltStreamsMode;
-
- HRESULT res = EnumerateItems(censor,
- options.PathMode,
- UString(),
- dirItems);
-
- if (res != S_OK)
- {
- if (res != E_ABORT)
- errorInfo = "Scanning error";
- return res;
- }
- RINOK(callback->FinishScanning(dirItems.Stat));
- }
-
- unsigned i;
- CHashBundle hb;
- RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS options.Methods));
- // hb.Init();
-
- hb.NumErrors = dirItems.Stat.NumErrors;
-
- if (options.StdInMode)
- {
- RINOK(callback->SetNumFiles(1));
- }
- else
- {
- RINOK(callback->SetTotal(dirItems.Stat.GetTotalBytes()));
- }
-
- const UInt32 kBufSize = 1 << 15;
- CHashMidBuf buf;
- if (!buf.Alloc(kBufSize))
- return E_OUTOFMEMORY;
-
- UInt64 completeValue = 0;
-
- RINOK(callback->BeforeFirstFile(hb));
-
- for (i = 0; i < dirItems.Items.Size(); i++)
- {
- CMyComPtr<ISequentialInStream> inStream;
- UString path;
- bool isDir = false;
- bool isAltStream = false;
- if (options.StdInMode)
- {
- inStream = new CStdInFileStream;
- }
- else
- {
- CInFileStream *inStreamSpec = new CInFileStream;
- inStream = inStreamSpec;
- const CDirItem &dirItem = dirItems.Items[i];
- isDir = dirItem.IsDir();
- isAltStream = dirItem.IsAltStream;
- path = dirItems.GetLogPath(i);
- if (!isDir)
- {
- FString phyPath = dirItems.GetPhyPath(i);
- if (!inStreamSpec->OpenShared(phyPath, options.OpenShareForWrite))
- {
- HRESULT res = callback->OpenFileError(phyPath, ::GetLastError());
- hb.NumErrors++;
- if (res != S_FALSE)
- return res;
- continue;
- }
- }
- }
- RINOK(callback->GetStream(path, isDir));
- UInt64 fileSize = 0;
-
- hb.InitForNewFile();
- if (!isDir)
- {
- for (UInt32 step = 0;; step++)
- {
- if ((step & 0xFF) == 0)
- RINOK(callback->SetCompleted(&completeValue));
- UInt32 size;
- RINOK(inStream->Read(buf, kBufSize, &size));
- if (size == 0)
- break;
- hb.Update(buf, size);
- fileSize += size;
- completeValue += size;
- }
- }
- hb.Final(isDir, isAltStream, path);
- RINOK(callback->SetOperationResult(fileSize, hb, !isDir));
- RINOK(callback->SetCompleted(&completeValue));
- }
- return callback->AfterLastFile(hb);
-}
-
-
-static inline char GetHex(unsigned v)
-{
- return (char)((v < 10) ? ('0' + v) : ('A' + (v - 10)));
-}
-
-void AddHashHexToString(char *dest, const Byte *data, UInt32 size)
-{
- dest[size * 2] = 0;
-
- if (!data)
- {
- for (UInt32 i = 0; i < size; i++)
- {
- dest[0] = ' ';
- dest[1] = ' ';
- dest += 2;
- }
- return;
- }
-
- int step = 2;
- if (size <= 8)
- {
- step = -2;
- dest += size * 2 - 2;
- }
-
- for (UInt32 i = 0; i < size; i++)
- {
- unsigned b = data[i];
- dest[0] = GetHex((b >> 4) & 0xF);
- dest[1] = GetHex(b & 0xF);
- dest += step;
- }
-}
+// HashCalc.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Alloc.h"
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/DynLimBuf.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamObjects.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Archive/Common/ItemNameUtils.h"
+#include "../../Archive/IArchive.h"
+
+#include "EnumDirItems.h"
+#include "HashCalc.h"
+
+using namespace NWindows;
+
+#ifdef Z7_EXTERNAL_CODECS
+extern const CExternalCodecs *g_ExternalCodecs_Ptr;
+#endif
+
+class CHashMidBuf
+{
+ void *_data;
+public:
+ CHashMidBuf(): _data(NULL) {}
+ operator void *() { return _data; }
+ bool Alloc(size_t size)
+ {
+ if (_data)
+ return false;
+ _data = ::MidAlloc(size);
+ return _data != NULL;
+ }
+ ~CHashMidBuf() { ::MidFree(_data); }
+};
+
+static const char * const k_DefaultHashMethod = "CRC32";
+
+HRESULT CHashBundle::SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &hashMethods)
+{
+ UStringVector names = hashMethods;
+ if (names.IsEmpty())
+ names.Add(UString(k_DefaultHashMethod));
+
+ CRecordVector<CMethodId> ids;
+ CObjectVector<COneMethodInfo> methods;
+
+ unsigned i;
+ for (i = 0; i < names.Size(); i++)
+ {
+ COneMethodInfo m;
+ RINOK(m.ParseMethodFromString(names[i]))
+
+ if (m.MethodName.IsEmpty())
+ m.MethodName = k_DefaultHashMethod;
+
+ if (m.MethodName == "*")
+ {
+ CRecordVector<CMethodId> tempMethods;
+ GetHashMethods(EXTERNAL_CODECS_LOC_VARS tempMethods);
+ methods.Clear();
+ ids.Clear();
+ FOR_VECTOR (t, tempMethods)
+ {
+ unsigned index = ids.AddToUniqueSorted(tempMethods[t]);
+ if (ids.Size() != methods.Size())
+ methods.Insert(index, m);
+ }
+ break;
+ }
+ else
+ {
+ // m.MethodName.RemoveChar(L'-');
+ CMethodId id;
+ if (!FindHashMethod(EXTERNAL_CODECS_LOC_VARS m.MethodName, id))
+ return E_NOTIMPL;
+ unsigned index = ids.AddToUniqueSorted(id);
+ if (ids.Size() != methods.Size())
+ methods.Insert(index, m);
+ }
+ }
+
+ for (i = 0; i < ids.Size(); i++)
+ {
+ CMyComPtr<IHasher> hasher;
+ AString name;
+ RINOK(CreateHasher(EXTERNAL_CODECS_LOC_VARS ids[i], name, hasher))
+ if (!hasher)
+ throw "Can't create hasher";
+ const COneMethodInfo &m = methods[i];
+ {
+ CMyComPtr<ICompressSetCoderProperties> scp;
+ hasher.QueryInterface(IID_ICompressSetCoderProperties, &scp);
+ if (scp)
+ RINOK(m.SetCoderProps(scp, NULL))
+ }
+ const UInt32 digestSize = hasher->GetDigestSize();
+ if (digestSize > k_HashCalc_DigestSize_Max)
+ return E_NOTIMPL;
+ CHasherState &h = Hashers.AddNew();
+ h.DigestSize = digestSize;
+ h.Hasher = hasher;
+ h.Name = name;
+ for (unsigned k = 0; k < k_HashCalc_NumGroups; k++)
+ h.InitDigestGroup(k);
+ }
+
+ return S_OK;
+}
+
+void CHashBundle::InitForNewFile()
+{
+ CurSize = 0;
+ FOR_VECTOR (i, Hashers)
+ {
+ CHasherState &h = Hashers[i];
+ h.Hasher->Init();
+ h.InitDigestGroup(k_HashCalc_Index_Current);
+ }
+}
+
+void CHashBundle::Update(const void *data, UInt32 size)
+{
+ CurSize += size;
+ FOR_VECTOR (i, Hashers)
+ Hashers[i].Hasher->Update(data, size);
+}
+
+void CHashBundle::SetSize(UInt64 size)
+{
+ CurSize = size;
+}
+
+static void AddDigests(Byte *dest, const Byte *src, UInt32 size)
+{
+ unsigned next = 0;
+ /*
+ // we could use big-endian addition for sha-1 and sha-256
+ // but another hashers are little-endian
+ if (size > 8)
+ {
+ for (unsigned i = size; i != 0;)
+ {
+ i--;
+ next += (unsigned)dest[i] + (unsigned)src[i];
+ dest[i] = (Byte)next;
+ next >>= 8;
+ }
+ }
+ else
+ */
+ {
+ for (unsigned i = 0; i < size; i++)
+ {
+ next += (unsigned)dest[i] + (unsigned)src[i];
+ dest[i] = (Byte)next;
+ next >>= 8;
+ }
+ }
+
+ // we use little-endian to store extra bytes
+ dest += k_HashCalc_DigestSize_Max;
+ for (unsigned i = 0; i < k_HashCalc_ExtraSize; i++)
+ {
+ next += (unsigned)dest[i];
+ dest[i] = (Byte)next;
+ next >>= 8;
+ }
+}
+
+void CHasherState::AddDigest(unsigned groupIndex, const Byte *data)
+{
+ NumSums[groupIndex]++;
+ AddDigests(Digests[groupIndex], data, DigestSize);
+}
+
+void CHashBundle::Final(bool isDir, bool isAltStream, const UString &path)
+{
+ if (isDir)
+ NumDirs++;
+ else if (isAltStream)
+ {
+ NumAltStreams++;
+ AltStreamsSize += CurSize;
+ }
+ else
+ {
+ NumFiles++;
+ FilesSize += CurSize;
+ }
+
+ Byte pre[16];
+ memset(pre, 0, sizeof(pre));
+ if (isDir)
+ pre[0] = 1;
+
+ FOR_VECTOR (i, Hashers)
+ {
+ CHasherState &h = Hashers[i];
+ if (!isDir)
+ {
+ h.Hasher->Final(h.Digests[0]); // k_HashCalc_Index_Current
+ if (!isAltStream)
+ h.AddDigest(k_HashCalc_Index_DataSum, h.Digests[0]);
+ }
+
+ h.Hasher->Init();
+ h.Hasher->Update(pre, sizeof(pre));
+ h.Hasher->Update(h.Digests[0], h.DigestSize);
+
+ for (unsigned k = 0; k < path.Len(); k++)
+ {
+ wchar_t c = path[k];
+
+ // 21.04: we want same hash for linux and windows paths
+ #if CHAR_PATH_SEPARATOR != '/'
+ if (c == CHAR_PATH_SEPARATOR)
+ c = '/';
+ // if (c == (wchar_t)('\\' + 0xf000)) c = '\\'; // to debug WSL
+ // if (c > 0xf000 && c < 0xf080) c -= 0xf000; // to debug WSL
+ #endif
+
+ Byte temp[2] = { (Byte)(c & 0xFF), (Byte)((c >> 8) & 0xFF) };
+ h.Hasher->Update(temp, 2);
+ }
+
+ Byte tempDigest[k_HashCalc_DigestSize_Max];
+ h.Hasher->Final(tempDigest);
+ if (!isAltStream)
+ h.AddDigest(k_HashCalc_Index_NamesSum, tempDigest);
+ h.AddDigest(k_HashCalc_Index_StreamsSum, tempDigest);
+ }
+}
+
+
+static void CSum_Name_OriginalToEscape(const AString &src, AString &dest)
+{
+ dest.Empty();
+ for (unsigned i = 0; i < src.Len();)
+ {
+ char c = src[i++];
+ if (c == '\n')
+ {
+ dest += '\\';
+ c = 'n';
+ }
+ else if (c == '\\')
+ dest += '\\';
+ dest += c;
+ }
+}
+
+
+static bool CSum_Name_EscapeToOriginal(const char *s, AString &dest)
+{
+ bool isOK = true;
+ dest.Empty();
+ for (;;)
+ {
+ char c = *s++;
+ if (c == 0)
+ break;
+ if (c == '\\')
+ {
+ const char c1 = *s;
+ if (c1 == 'n')
+ {
+ c = '\n';
+ s++;
+ }
+ else if (c1 == '\\')
+ {
+ c = c1;
+ s++;
+ }
+ else
+ {
+ // original md5sum returns NULL for such bad strings
+ isOK = false;
+ }
+ }
+ dest += c;
+ }
+ return isOK;
+}
+
+
+
+static void SetSpacesAndNul(char *s, unsigned num)
+{
+ for (unsigned i = 0; i < num; i++)
+ s[i] = ' ';
+ s[num] = 0;
+}
+
+static const unsigned kHashColumnWidth_Min = 4 * 2;
+
+static unsigned GetColumnWidth(unsigned digestSize)
+{
+ const unsigned width = digestSize * 2;
+ return width < kHashColumnWidth_Min ? kHashColumnWidth_Min: width;
+}
+
+
+static void AddHashResultLine(
+ AString &_s,
+ // bool showHash,
+ // UInt64 fileSize, bool showSize,
+ const CObjectVector<CHasherState> &hashers
+ // unsigned digestIndex, = k_HashCalc_Index_Current
+ )
+{
+ FOR_VECTOR (i, hashers)
+ {
+ const CHasherState &h = hashers[i];
+ char s[k_HashCalc_DigestSize_Max * 2 + 64];
+ s[0] = 0;
+ // if (showHash)
+ HashHexToString(s, h.Digests[k_HashCalc_Index_Current], h.DigestSize);
+ const unsigned pos = (unsigned)strlen(s);
+ const int numSpaces = (int)GetColumnWidth(h.DigestSize) - (int)pos;
+ if (numSpaces > 0)
+ SetSpacesAndNul(s + pos, (unsigned)numSpaces);
+ if (i != 0)
+ _s.Add_Space();
+ _s += s;
+ }
+
+ /*
+ if (showSize)
+ {
+ _s.Add_Space();
+ static const unsigned kSizeField_Len = 13; // same as in HashCon.cpp
+ char s[kSizeField_Len + 32];
+ char *p = s;
+ SetSpacesAndNul(s, kSizeField_Len);
+ p = s + kSizeField_Len;
+ ConvertUInt64ToString(fileSize, p);
+ int numSpaces = (int)kSizeField_Len - (int)strlen(p);
+ if (numSpaces > 0)
+ p -= (unsigned)numSpaces;
+ _s += p;
+ }
+ */
+}
+
+
+static void Add_LF(CDynLimBuf &hashFileString, const CHashOptionsLocal &options)
+{
+ hashFileString += (char)(options.HashMode_Zero.Val ? 0 : '\n');
+}
+
+
+
+
+static void WriteLine(CDynLimBuf &hashFileString,
+ const CHashOptionsLocal &options,
+ const UString &path2,
+ bool isDir,
+ const AString &methodName,
+ const AString &hashesString)
+{
+ if (options.HashMode_OnlyHash.Val)
+ {
+ hashFileString += hashesString;
+ Add_LF(hashFileString, options);
+ return;
+ }
+
+ UString path = path2;
+
+ bool isBin = false;
+ const bool zeroMode = options.HashMode_Zero.Val;
+ const bool tagMode = options.HashMode_Tag.Val;
+
+#if CHAR_PATH_SEPARATOR != '/'
+ path.Replace(WCHAR_PATH_SEPARATOR, L'/');
+ // path.Replace((wchar_t)('\\' + 0xf000), L'\\'); // to debug WSL
+#endif
+
+ AString utf8;
+ ConvertUnicodeToUTF8(path, utf8);
+
+ AString esc;
+ CSum_Name_OriginalToEscape(utf8, esc);
+
+ if (!zeroMode)
+ {
+ if (esc != utf8)
+ {
+ /* Original md5sum writes escape in that case.
+ We do same for compatibility with original md5sum. */
+ hashFileString += '\\';
+ }
+ }
+
+ if (isDir && !esc.IsEmpty() && esc.Back() != '/')
+ esc += '/';
+
+ if (tagMode)
+ {
+ if (!methodName.IsEmpty())
+ {
+ hashFileString += methodName;
+ hashFileString += ' ';
+ }
+ hashFileString += '(';
+ hashFileString += esc;
+ hashFileString += ')';
+ hashFileString += " = ";
+ }
+
+ hashFileString += hashesString;
+
+ if (!tagMode)
+ {
+ hashFileString += ' ';
+ hashFileString += (char)(isBin ? '*' : ' ');
+ hashFileString += esc;
+ }
+
+ Add_LF(hashFileString, options);
+}
+
+
+
+static void WriteLine(CDynLimBuf &hashFileString,
+ const CHashOptionsLocal &options,
+ const UString &path,
+ bool isDir,
+ const CHashBundle &hb)
+{
+ AString methodName;
+ if (!hb.Hashers.IsEmpty())
+ methodName = hb.Hashers[0].Name;
+
+ AString hashesString;
+ AddHashResultLine(hashesString, hb.Hashers);
+ WriteLine(hashFileString, options, path, isDir, methodName, hashesString);
+}
+
+
+HRESULT HashCalc(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const NWildcard::CCensor &censor,
+ const CHashOptions &options,
+ AString &errorInfo,
+ IHashCallbackUI *callback)
+{
+ CDirItems dirItems;
+ dirItems.Callback = callback;
+
+ if (options.StdInMode)
+ {
+ CDirItem di;
+ di.Size = (UInt64)(Int64)-1;
+ di.SetAsFile();
+ dirItems.Items.Add(di);
+ }
+ else
+ {
+ RINOK(callback->StartScanning())
+
+ dirItems.SymLinks = options.SymLinks.Val;
+ dirItems.ScanAltStreams = options.AltStreamsMode;
+ dirItems.ExcludeDirItems = censor.ExcludeDirItems;
+ dirItems.ExcludeFileItems = censor.ExcludeFileItems;
+
+ dirItems.ShareForWrite = options.OpenShareForWrite;
+
+ HRESULT res = EnumerateItems(censor,
+ options.PathMode,
+ UString(),
+ dirItems);
+
+ if (res != S_OK)
+ {
+ if (res != E_ABORT)
+ errorInfo = "Scanning error";
+ return res;
+ }
+ RINOK(callback->FinishScanning(dirItems.Stat))
+ }
+
+ unsigned i;
+ CHashBundle hb;
+ RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS options.Methods))
+ // hb.Init();
+
+ hb.NumErrors = dirItems.Stat.NumErrors;
+
+ UInt64 totalSize = 0;
+ if (options.StdInMode)
+ {
+ RINOK(callback->SetNumFiles(1))
+ }
+ else
+ {
+ totalSize = dirItems.Stat.GetTotalBytes();
+ RINOK(callback->SetTotal(totalSize))
+ }
+
+ const UInt32 kBufSize = 1 << 15;
+ CHashMidBuf buf;
+ if (!buf.Alloc(kBufSize))
+ return E_OUTOFMEMORY;
+
+ UInt64 completeValue = 0;
+
+ RINOK(callback->BeforeFirstFile(hb))
+
+ /*
+ CDynLimBuf hashFileString((size_t)1 << 31);
+ const bool needGenerate = !options.HashFilePath.IsEmpty();
+ */
+
+ for (i = 0; i < dirItems.Items.Size(); i++)
+ {
+ CMyComPtr<ISequentialInStream> inStream;
+ UString path;
+ bool isDir = false;
+ bool isAltStream = false;
+
+ if (options.StdInMode)
+ {
+ inStream = new CStdInFileStream;
+ }
+ else
+ {
+ path = dirItems.GetLogPath(i);
+ const CDirItem &di = dirItems.Items[i];
+ #ifdef _WIN32
+ isAltStream = di.IsAltStream;
+ #endif
+
+ #ifndef UNDER_CE
+ // if (di.AreReparseData())
+ if (di.ReparseData.Size() != 0)
+ {
+ CBufInStream *inStreamSpec = new CBufInStream();
+ inStream = inStreamSpec;
+ inStreamSpec->Init(di.ReparseData, di.ReparseData.Size());
+ }
+ else
+ #endif
+ {
+ CInFileStream *inStreamSpec = new CInFileStream;
+ inStreamSpec->Set_PreserveATime(options.PreserveATime);
+ inStream = inStreamSpec;
+ isDir = di.IsDir();
+ if (!isDir)
+ {
+ const FString phyPath = dirItems.GetPhyPath(i);
+ if (!inStreamSpec->OpenShared(phyPath, options.OpenShareForWrite))
+ {
+ HRESULT res = callback->OpenFileError(phyPath, ::GetLastError());
+ hb.NumErrors++;
+ if (res != S_FALSE)
+ return res;
+ continue;
+ }
+ if (!options.StdInMode)
+ {
+ UInt64 curSize = 0;
+ if (inStreamSpec->GetSize(&curSize) == S_OK)
+ {
+ if (curSize > di.Size)
+ {
+ totalSize += curSize - di.Size;
+ RINOK(callback->SetTotal(totalSize))
+ // printf("\ntotal = %d MiB\n", (unsigned)(totalSize >> 20));
+ }
+ }
+ }
+ // inStreamSpec->ReloadProps();
+ }
+ }
+ }
+
+ RINOK(callback->GetStream(path, isDir))
+ UInt64 fileSize = 0;
+
+ hb.InitForNewFile();
+
+ if (!isDir)
+ {
+ for (UInt32 step = 0;; step++)
+ {
+ if ((step & 0xFF) == 0)
+ {
+ // printf("\ncompl = %d\n", (unsigned)(completeValue >> 20));
+ RINOK(callback->SetCompleted(&completeValue))
+ }
+ UInt32 size;
+ RINOK(inStream->Read(buf, kBufSize, &size))
+ if (size == 0)
+ break;
+ hb.Update(buf, size);
+ fileSize += size;
+ completeValue += size;
+ }
+ }
+
+ hb.Final(isDir, isAltStream, path);
+
+ /*
+ if (needGenerate
+ && (options.HashMode_Dirs.Val || !isDir))
+ {
+ WriteLine(hashFileString,
+ options,
+ path, // change it
+ isDir,
+ hb);
+
+ if (hashFileString.IsError())
+ return E_OUTOFMEMORY;
+ }
+ */
+
+ RINOK(callback->SetOperationResult(fileSize, hb, !isDir))
+ RINOK(callback->SetCompleted(&completeValue))
+ }
+
+ /*
+ if (needGenerate)
+ {
+ NFile::NIO::COutFile file;
+ if (!file.Create(us2fs(options.HashFilePath), true)) // createAlways
+ return GetLastError_noZero_HRESULT();
+ if (!file.WriteFull(hashFileString, hashFileString.Len()))
+ return GetLastError_noZero_HRESULT();
+ }
+ */
+
+ return callback->AfterLastFile(hb);
+}
+
+
+static inline char GetHex_Upper(unsigned v)
+{
+ return (char)((v < 10) ? ('0' + v) : ('A' + (v - 10)));
+}
+
+static inline char GetHex_Lower(unsigned v)
+{
+ return (char)((v < 10) ? ('0' + v) : ('a' + (v - 10)));
+}
+
+void HashHexToString(char *dest, const Byte *data, UInt32 size)
+{
+ dest[size * 2] = 0;
+
+ if (!data)
+ {
+ for (UInt32 i = 0; i < size; i++)
+ {
+ dest[0] = ' ';
+ dest[1] = ' ';
+ dest += 2;
+ }
+ return;
+ }
+
+ if (size <= 8)
+ {
+ dest += size * 2;
+ for (UInt32 i = 0; i < size; i++)
+ {
+ const unsigned b = data[i];
+ dest -= 2;
+ dest[0] = GetHex_Upper((b >> 4) & 0xF);
+ dest[1] = GetHex_Upper(b & 0xF);
+ }
+ }
+ else
+ {
+ for (UInt32 i = 0; i < size; i++)
+ {
+ const unsigned b = data[i];
+ dest[0] = GetHex_Lower((b >> 4) & 0xF);
+ dest[1] = GetHex_Lower(b & 0xF);
+ dest += 2;
+ }
+ }
+}
+
+void CHasherState::WriteToString(unsigned digestIndex, char *s) const
+{
+ HashHexToString(s, Digests[digestIndex], DigestSize);
+
+ if (digestIndex != 0 && NumSums[digestIndex] != 1)
+ {
+ unsigned numExtraBytes = GetNumExtraBytes_for_Group(digestIndex);
+ if (numExtraBytes > 4)
+ numExtraBytes = 8;
+ else // if (numExtraBytes >= 0)
+ numExtraBytes = 4;
+ // if (numExtraBytes != 0)
+ {
+ s += strlen(s);
+ *s++ = '-';
+ // *s = 0;
+ HashHexToString(s, GetExtraData_for_Group(digestIndex), numExtraBytes);
+ }
+ }
+}
+
+
+
+// ---------- Hash Handler ----------
+
+namespace NHash {
+
+static size_t ParseHexString(const char *s, Byte *dest) throw()
+{
+ size_t num;
+ for (num = 0;; num++, s += 2)
+ {
+ unsigned c = (Byte)s[0];
+ unsigned v0;
+ if (c >= '0' && c <= '9') v0 = (c - '0');
+ else if (c >= 'A' && c <= 'F') v0 = 10 + (c - 'A');
+ else if (c >= 'a' && c <= 'f') v0 = 10 + (c - 'a');
+ else
+ return num;
+ c = (Byte)s[1];
+ unsigned v1;
+ if (c >= '0' && c <= '9') v1 = (c - '0');
+ else if (c >= 'A' && c <= 'F') v1 = 10 + (c - 'A');
+ else if (c >= 'a' && c <= 'f') v1 = 10 + (c - 'a');
+ else
+ return num;
+ if (dest)
+ dest[num] = (Byte)(v1 | (v0 << 4));
+ }
+}
+
+
+#define IsWhite(c) ((c) == ' ' || (c) == '\t')
+
+bool CHashPair::IsDir() const
+{
+ if (Name.IsEmpty() || Name.Back() != '/')
+ return false;
+ // here we expect that Dir items contain only zeros or no Hash
+ for (size_t i = 0; i < Hash.Size(); i++)
+ if (Hash[i] != 0)
+ return false;
+ return true;
+}
+
+
+bool CHashPair::ParseCksum(const char *s)
+{
+ const char *end;
+
+ const UInt32 crc = ConvertStringToUInt32(s, &end);
+ if (*end != ' ')
+ return false;
+ end++;
+
+ const UInt64 size = ConvertStringToUInt64(end, &end);
+ if (*end != ' ')
+ return false;
+ end++;
+
+ Name = end;
+
+ Hash.Alloc(4);
+ SetBe32(Hash, crc)
+
+ Size_from_Arc = size;
+ Size_from_Arc_Defined = true;
+
+ return true;
+}
+
+
+
+static const char *SkipWhite(const char *s)
+{
+ while (IsWhite(*s))
+ s++;
+ return s;
+}
+
+static const char * const k_CsumMethodNames[] =
+{
+ "sha256"
+ , "sha224"
+// , "sha512/224"
+// , "sha512/256"
+ , "sha512"
+ , "sha384"
+ , "sha1"
+ , "md5"
+ , "blake2b"
+ , "crc64"
+ , "crc32"
+ , "cksum"
+};
+
+static UString GetMethod_from_FileName(const UString &name)
+{
+ AString s;
+ ConvertUnicodeToUTF8(name, s);
+ const int dotPos = s.ReverseFind_Dot();
+ const char *src = s.Ptr();
+ bool isExtension = false;
+ if (dotPos >= 0)
+ {
+ isExtension = true;
+ src = s.Ptr(dotPos + 1);
+ }
+ const char *m = "";
+ unsigned i;
+ for (i = 0; i < Z7_ARRAY_SIZE(k_CsumMethodNames); i++)
+ {
+ m = k_CsumMethodNames[i];
+ if (isExtension)
+ {
+ if (StringsAreEqual_Ascii(src, m))
+ break;
+ }
+ else if (IsString1PrefixedByString2_NoCase_Ascii(src, m))
+ if (StringsAreEqual_Ascii(src + strlen(m), "sums"))
+ break;
+ }
+ UString res;
+ if (i != Z7_ARRAY_SIZE(k_CsumMethodNames))
+ res = m;
+ return res;
+}
+
+
+bool CHashPair::Parse(const char *s)
+{
+ // here we keep compatibility with original md5sum / shasum
+ bool escape = false;
+
+ s = SkipWhite(s);
+
+ if (*s == '\\')
+ {
+ s++;
+ escape = true;
+ }
+
+ // const char *kMethod = GetMethod_from_FileName(s);
+ // if (kMethod)
+ if (ParseHexString(s, NULL) < 4)
+ {
+ // BSD-style checksum line
+ {
+ const char *s2 = s;
+ for (; *s2 != 0; s2++)
+ {
+ const char c = *s2;
+ if (c == 0)
+ return false;
+ if (c == ' ' || c == '(')
+ break;
+ }
+ Method.SetFrom(s, (unsigned)(s2 - s));
+ s = s2;
+ }
+ IsBSD = true;
+ if (*s == ' ')
+ s++;
+ if (*s != '(')
+ return false;
+ s++;
+ {
+ const char *s2 = s;
+ for (; *s2 != 0; s2++)
+ {}
+ for (;;)
+ {
+ s2--;
+ if (s2 < s)
+ return false;
+ if (*s2 == ')')
+ break;
+ }
+ Name.SetFrom(s, (unsigned)(s2 - s));
+ s = s2 + 1;
+ }
+
+ s = SkipWhite(s);
+ if (*s != '=')
+ return false;
+ s++;
+ s = SkipWhite(s);
+ }
+
+ {
+ const size_t num = ParseHexString(s, NULL);
+ Hash.Alloc(num);
+ ParseHexString(s, Hash);
+ const size_t numChars = num * 2;
+ HashString.SetFrom(s, (unsigned)numChars);
+ s += numChars;
+ }
+
+ if (IsBSD)
+ {
+ if (*s != 0)
+ return false;
+ if (escape)
+ {
+ const AString temp (Name);
+ return CSum_Name_EscapeToOriginal(temp, Name);
+ }
+ return true;
+ }
+
+ if (*s == 0)
+ return true;
+
+ if (*s != ' ')
+ return false;
+ s++;
+ const char c = *s;
+ if (c != ' '
+ && c != '*'
+ && c != 'U' // shasum Universal
+ && c != '^' // shasum 0/1
+ )
+ return false;
+ Mode = c;
+ s++;
+ if (escape)
+ return CSum_Name_EscapeToOriginal(s, Name);
+ Name = s;
+ return true;
+}
+
+
+static bool GetLine(CByteBuffer &buf, bool zeroMode, bool cr_lf_Mode, size_t &posCur, AString &s)
+{
+ s.Empty();
+ size_t pos = posCur;
+ const Byte *p = buf;
+ unsigned numDigits = 0;
+ for (; pos < buf.Size(); pos++)
+ {
+ const Byte b = p[pos];
+ if (b == 0)
+ {
+ numDigits = 1;
+ break;
+ }
+ if (zeroMode)
+ continue;
+ if (b == 0x0a)
+ {
+ numDigits = 1;
+ break;
+ }
+ if (!cr_lf_Mode)
+ continue;
+ if (b == 0x0d)
+ {
+ if (pos + 1 >= buf.Size())
+ {
+ numDigits = 1;
+ break;
+ // return false;
+ }
+ if (p[pos + 1] == 0x0a)
+ {
+ numDigits = 2;
+ break;
+ }
+ }
+ }
+ s.SetFrom((const char *)(p + posCur), (unsigned)(pos - posCur));
+ posCur = pos + numDigits;
+ return true;
+}
+
+
+static bool Is_CR_LF_Data(const Byte *buf, size_t size)
+{
+ bool isCrLf = false;
+ for (size_t i = 0; i < size;)
+ {
+ const Byte b = buf[i];
+ if (b == 0x0a)
+ return false;
+ if (b == 0x0d)
+ {
+ if (i == size - 1)
+ return false;
+ if (buf[i + 1] != 0x0a)
+ return false;
+ isCrLf = true;
+ i += 2;
+ }
+ else
+ i++;
+ }
+ return isCrLf;
+}
+
+
+static const Byte kArcProps[] =
+{
+ // kpidComment,
+ kpidCharacts
+};
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidPackSize,
+ kpidMethod
+};
+
+static const Byte kRawProps[] =
+{
+ kpidChecksum
+};
+
+
+Z7_COM7F_IMF(CHandler::GetParent(UInt32 /* index */ , UInt32 *parent, UInt32 *parentType))
+{
+ *parentType = NParentType::kDir;
+ *parent = (UInt32)(Int32)-1;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumRawProps(UInt32 *numProps))
+{
+ *numProps = Z7_ARRAY_SIZE(kRawProps);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetRawPropInfo(UInt32 index, BSTR *name, PROPID *propID))
+{
+ *propID = kRawProps[index];
+ *name = NULL;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
+{
+ *data = NULL;
+ *dataSize = 0;
+ *propType = 0;
+
+ if (propID == kpidChecksum)
+ {
+ const CHashPair &hp = HashPairs[index];
+ if (hp.Hash.Size() > 0)
+ {
+ *data = hp.Hash;
+ *dataSize = (UInt32)hp.Hash.Size();
+ *propType = NPropDataType::kRaw;
+ }
+ return S_OK;
+ }
+
+ return S_OK;
+}
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = HashPairs.Size();
+ return S_OK;
+}
+
+static void Add_OptSpace_String(UString &dest, const char *src)
+{
+ dest.Add_Space_if_NotEmpty();
+ dest += src;
+}
+
+Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
+{
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidPhySize: if (_phySize != 0) prop = _phySize; break;
+ /*
+ case kpidErrorFlags:
+ {
+ UInt32 v = 0;
+ if (!_isArc) v |= kpv_ErrorFlags_IsNotArc;
+ // if (_sres == k_Base64_RES_NeedMoreInput) v |= kpv_ErrorFlags_UnexpectedEnd;
+ if (v != 0)
+ prop = v;
+ break;
+ }
+ */
+ case kpidCharacts:
+ {
+ UString s;
+ if (_hashSize_Defined)
+ {
+ s.Add_Space_if_NotEmpty();
+ s.Add_UInt32(_hashSize * 8);
+ s += "-bit";
+ }
+ if (!_nameExtenstion.IsEmpty())
+ {
+ s.Add_Space_if_NotEmpty();
+ s += _nameExtenstion;
+ }
+ if (_is_PgpMethod)
+ {
+ Add_OptSpace_String(s, "PGP");
+ if (!_pgpMethod.IsEmpty())
+ {
+ s += ":";
+ s += _pgpMethod;
+ }
+ }
+ if (_is_ZeroMode)
+ Add_OptSpace_String(s, "ZERO");
+ if (_are_there_Tags)
+ Add_OptSpace_String(s, "TAG");
+ if (_are_there_Dirs)
+ Add_OptSpace_String(s, "DIRS");
+ prop = s;
+ break;
+ }
+
+ case kpidReadOnly:
+ {
+ if (_isArc)
+ if (!CanUpdate())
+ prop = true;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ // COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ CHashPair &hp = HashPairs[index];
+ switch (propID)
+ {
+ case kpidIsDir:
+ {
+ prop = hp.IsDir();
+ break;
+ }
+ case kpidPath:
+ {
+ UString path;
+ hp.Get_UString_Path(path);
+
+ NArchive::NItemName::ReplaceToOsSlashes_Remove_TailSlash(path,
+ true); // useBackslashReplacement
+
+ prop = path;
+ break;
+ }
+ case kpidSize:
+ {
+ // client needs processed size of last file
+ if (hp.Size_from_Disk_Defined)
+ prop = (UInt64)hp.Size_from_Disk;
+ else if (hp.Size_from_Arc_Defined)
+ prop = (UInt64)hp.Size_from_Arc;
+ break;
+ }
+ case kpidPackSize:
+ {
+ prop = (UInt64)hp.Hash.Size();
+ break;
+ }
+ case kpidMethod:
+ {
+ if (!hp.Method.IsEmpty())
+ prop = hp.Method;
+ break;
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ // COM_TRY_END
+}
+
+
+static HRESULT ReadStream_to_Buf(IInStream *stream, CByteBuffer &buf, IArchiveOpenCallback *openCallback)
+{
+ buf.Free();
+ UInt64 len;
+ RINOK(InStream_AtBegin_GetSize(stream, len))
+ if (len == 0 || len >= ((UInt64)1 << 31))
+ return S_FALSE;
+ buf.Alloc((size_t)len);
+ UInt64 pos = 0;
+ // return ReadStream_FALSE(stream, buf, (size_t)len);
+ for (;;)
+ {
+ const UInt32 kBlockSize = ((UInt32)1 << 24);
+ const UInt32 curSize = (len < kBlockSize) ? (UInt32)len : kBlockSize;
+ UInt32 processedSizeLoc;
+ RINOK(stream->Read((Byte *)buf + pos, curSize, &processedSizeLoc))
+ if (processedSizeLoc == 0)
+ return E_FAIL;
+ len -= processedSizeLoc;
+ pos += processedSizeLoc;
+ if (len == 0)
+ return S_OK;
+ if (openCallback)
+ {
+ const UInt64 files = 0;
+ RINOK(openCallback->SetCompleted(&files, &pos))
+ }
+ }
+}
+
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback *openCallback))
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+
+ CByteBuffer buf;
+ RINOK(ReadStream_to_Buf(stream, buf, openCallback))
+
+ CObjectVector<CHashPair> &pairs = HashPairs;
+
+ bool zeroMode = false;
+ bool cr_lf_Mode = false;
+ {
+ for (size_t i = 0; i < buf.Size(); i++)
+ if (buf[i] == 0)
+ {
+ zeroMode = true;
+ break;
+ }
+ }
+ _is_ZeroMode = zeroMode;
+ if (!zeroMode)
+ cr_lf_Mode = Is_CR_LF_Data(buf, buf.Size());
+
+ if (openCallback)
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IArchiveOpenVolumeCallback,
+ openVolumeCallback, openCallback)
+ if (openVolumeCallback)
+ {
+ NCOM::CPropVariant prop;
+ RINOK(openVolumeCallback->GetProperty(kpidName, &prop))
+ if (prop.vt == VT_BSTR)
+ _nameExtenstion = GetMethod_from_FileName(prop.bstrVal);
+ }
+ }
+
+ bool cksumMode = false;
+ if (_nameExtenstion.IsEqualTo_Ascii_NoCase("cksum"))
+ cksumMode = true;
+ _is_CksumMode = cksumMode;
+
+ size_t pos = 0;
+ AString s;
+ bool minusMode = false;
+ unsigned numLines = 0;
+
+ while (pos < buf.Size())
+ {
+ if (!GetLine(buf, zeroMode, cr_lf_Mode, pos, s))
+ return S_FALSE;
+ numLines++;
+ if (s.IsEmpty())
+ continue;
+
+ if (s.IsPrefixedBy_Ascii_NoCase("; "))
+ {
+ if (numLines != 1)
+ return S_FALSE;
+ // comment line of FileVerifier++
+ continue;
+ }
+
+ if (s.IsPrefixedBy_Ascii_NoCase("-----"))
+ {
+ if (minusMode)
+ break; // end of pgp mode
+ minusMode = true;
+ if (s.IsPrefixedBy_Ascii_NoCase("-----BEGIN PGP SIGNED MESSAGE"))
+ {
+ if (_is_PgpMethod)
+ return S_FALSE;
+ if (!GetLine(buf, zeroMode, cr_lf_Mode, pos, s))
+ return S_FALSE;
+ const char *kStart = "Hash: ";
+ if (!s.IsPrefixedBy_Ascii_NoCase(kStart))
+ return S_FALSE;
+ _pgpMethod = s.Ptr((unsigned)strlen(kStart));
+ _is_PgpMethod = true;
+ }
+ continue;
+ }
+
+ CHashPair pair;
+ pair.FullLine = s;
+ if (cksumMode)
+ {
+ if (!pair.ParseCksum(s))
+ return S_FALSE;
+ }
+ else if (!pair.Parse(s))
+ return S_FALSE;
+ pairs.Add(pair);
+ }
+
+ {
+ unsigned hashSize = 0;
+ bool hashSize_Dismatch = false;
+ for (unsigned i = 0; i < HashPairs.Size(); i++)
+ {
+ const CHashPair &hp = HashPairs[i];
+ if (i == 0)
+ hashSize = (unsigned)hp.Hash.Size();
+ else
+ if (hashSize != hp.Hash.Size())
+ hashSize_Dismatch = true;
+
+ if (hp.IsBSD)
+ _are_there_Tags = true;
+ if (!_are_there_Dirs && hp.IsDir())
+ _are_there_Dirs = true;
+ }
+ if (!hashSize_Dismatch && hashSize != 0)
+ {
+ _hashSize = hashSize;
+ _hashSize_Defined = true;
+ }
+ }
+
+ _phySize = buf.Size();
+ _isArc = true;
+ return S_OK;
+ }
+ COM_TRY_END
+}
+
+
+void CHandler::ClearVars()
+{
+ _phySize = 0;
+ _isArc = false;
+ _is_CksumMode = false;
+ _is_PgpMethod = false;
+ _is_ZeroMode = false;
+ _are_there_Tags = false;
+ _are_there_Dirs = false;
+ _hashSize_Defined = false;
+ _hashSize = 0;
+}
+
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ ClearVars();
+ _nameExtenstion.Empty();
+ _pgpMethod.Empty();
+ HashPairs.Clear();
+ return S_OK;
+}
+
+
+static bool CheckDigests(const Byte *a, const Byte *b, size_t size)
+{
+ if (size <= 8)
+ {
+ /* we use reversed order for one digest, when text representation
+ uses big-order for crc-32 and crc-64 */
+ for (size_t i = 0; i < size; i++)
+ if (a[i] != b[size - 1 - i])
+ return false;
+ return true;
+ }
+ {
+ for (size_t i = 0; i < size; i++)
+ if (a[i] != b[i])
+ return false;
+ return true;
+ }
+}
+
+
+static void AddDefaultMethod(UStringVector &methods, unsigned size)
+{
+ const char *m = NULL;
+ if (size == 32) m = "sha256";
+ else if (size == 20) m = "sha1";
+ else if (size == 16) m = "md5";
+ else if (size == 8) m = "crc64";
+ else if (size == 4) m = "crc32";
+ else
+ return;
+ #ifdef Z7_EXTERNAL_CODECS
+ const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr;
+ #endif
+ CMethodId id;
+ if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS
+ AString(m), id))
+ methods.Add(UString(m));
+}
+
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+
+ /*
+ if (testMode == 0)
+ return E_NOTIMPL;
+ */
+
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = HashPairs.Size();
+ if (numItems == 0)
+ return S_OK;
+
+ #ifdef Z7_EXTERNAL_CODECS
+ const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr;
+ #endif
+
+ CHashBundle hb_Glob;
+ // UStringVector methods = options.Methods;
+ UStringVector methods;
+
+ if (methods.IsEmpty() && !_nameExtenstion.IsEmpty())
+ {
+ AString utf;
+ ConvertUnicodeToUTF8(_nameExtenstion, utf);
+ CMethodId id;
+ if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS utf, id))
+ methods.Add(_nameExtenstion);
+ }
+
+ if (methods.IsEmpty() && !_pgpMethod.IsEmpty())
+ {
+ CMethodId id;
+ if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS _pgpMethod, id))
+ methods.Add(UString(_pgpMethod));
+ }
+
+ if (methods.IsEmpty() && _pgpMethod.IsEmpty() && _hashSize_Defined)
+ AddDefaultMethod(methods, _hashSize);
+
+ RINOK(hb_Glob.SetMethods(
+ EXTERNAL_CODECS_LOC_VARS
+ methods))
+
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IArchiveUpdateCallbackFile,
+ updateCallbackFile, extractCallback)
+ if (!updateCallbackFile)
+ return E_NOTIMPL;
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IArchiveGetDiskProperty,
+ GetDiskProperty, extractCallback)
+ if (GetDiskProperty)
+ {
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CHashPair &hp = HashPairs[index];
+ if (hp.IsDir())
+ continue;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(GetDiskProperty->GetDiskProperty(index, kpidSize, &prop))
+ if (prop.vt != VT_UI8)
+ continue;
+ totalSize += prop.uhVal.QuadPart;
+ }
+ }
+ RINOK(extractCallback->SetTotal(totalSize))
+ // RINOK(Hash_SetTotalUnpacked->Hash_SetTotalUnpacked(indices, numItems));
+ }
+ }
+
+ const UInt32 kBufSize = 1 << 15;
+ CHashMidBuf buf;
+ if (!buf.Alloc(kBufSize))
+ return E_OUTOFMEMORY;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+ lps->InSize = lps->OutSize = 0;
+
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ RINOK(lps->SetCur())
+ const UInt32 index = allFilesMode ? i : indices[i];
+
+ CHashPair &hp = HashPairs[index];
+
+ UString path;
+ hp.Get_UString_Path(path);
+
+ CMyComPtr<ISequentialInStream> inStream;
+ const bool isDir = hp.IsDir();
+ if (!isDir)
+ {
+ RINOK(updateCallbackFile->GetStream2(index, &inStream, NUpdateNotifyOp::kHashRead))
+ if (!inStream)
+ {
+ continue; // we have shown error in GetStream2()
+ }
+ // askMode = NArchive::NExtract::NAskMode::kSkip;
+ }
+
+ Int32 askMode = testMode ?
+ NArchive::NExtract::NAskMode::kTest :
+ NArchive::NExtract::NAskMode::kExtract;
+
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+
+ /* PrepareOperation() can expect kExtract to set
+ Attrib and security of output file */
+ askMode = NArchive::NExtract::NAskMode::kReadExternal;
+
+ extractCallback->PrepareOperation(askMode);
+
+ const bool isAltStream = false;
+
+ UInt64 fileSize = 0;
+
+ CHashBundle hb_Loc;
+
+ CHashBundle *hb_Use = &hb_Glob;
+
+ HRESULT res_SetMethods = S_OK;
+
+ UStringVector methods_loc;
+
+ if (!hp.Method.IsEmpty())
+ {
+ hb_Use = &hb_Loc;
+ CMethodId id;
+ if (FindHashMethod(EXTERNAL_CODECS_LOC_VARS hp.Method, id))
+ {
+ methods_loc.Add(UString(hp.Method));
+ RINOK(hb_Loc.SetMethods(
+ EXTERNAL_CODECS_LOC_VARS
+ methods_loc))
+ }
+ else
+ res_SetMethods = E_NOTIMPL;
+ }
+ else if (methods.IsEmpty())
+ {
+ AddDefaultMethod(methods_loc, (unsigned)hp.Hash.Size());
+ if (!methods_loc.IsEmpty())
+ {
+ hb_Use = &hb_Loc;
+ RINOK(hb_Loc.SetMethods(
+ EXTERNAL_CODECS_LOC_VARS
+ methods_loc))
+ }
+ }
+
+ const bool isSupportedMode = hp.IsSupportedMode();
+ hb_Use->InitForNewFile();
+
+ if (inStream)
+ {
+ for (UInt32 step = 0;; step++)
+ {
+ if ((step & 0xFF) == 0)
+ {
+ RINOK(progress->SetRatioInfo(NULL, &fileSize))
+ }
+ UInt32 size;
+ RINOK(inStream->Read(buf, kBufSize, &size))
+ if (size == 0)
+ break;
+ hb_Use->Update(buf, size);
+ if (realOutStream)
+ {
+ RINOK(WriteStream(realOutStream, buf, size))
+ }
+ fileSize += size;
+ }
+
+ hp.Size_from_Disk = fileSize;
+ hp.Size_from_Disk_Defined = true;
+ }
+
+ realOutStream.Release();
+ inStream.Release();
+
+ lps->InSize += hp.Hash.Size();
+ lps->OutSize += fileSize;
+
+ hb_Use->Final(isDir, isAltStream, path);
+
+ Int32 opRes = NArchive::NExtract::NOperationResult::kUnsupportedMethod;
+ if (isSupportedMode
+ && res_SetMethods != E_NOTIMPL
+ && hb_Use->Hashers.Size() > 0
+ )
+ {
+ const CHasherState &hs = hb_Use->Hashers[0];
+ if (hs.DigestSize == hp.Hash.Size())
+ {
+ opRes = NArchive::NExtract::NOperationResult::kCRCError;
+ if (CheckDigests(hp.Hash, hs.Digests[0], hs.DigestSize))
+ if (!hp.Size_from_Arc_Defined || hp.Size_from_Arc == fileSize)
+ opRes = NArchive::NExtract::NOperationResult::kOK;
+ }
+ }
+
+ RINOK(extractCallback->SetOperationResult(opRes))
+ }
+
+ return lps->SetCur();
+
+ COM_TRY_END
+}
+
+
+// ---------- UPDATE ----------
+
+struct CUpdateItem
+{
+ int IndexInArc;
+ unsigned IndexInClient;
+ UInt64 Size;
+ bool NewData;
+ bool NewProps;
+ bool IsDir;
+ UString Path;
+
+ CUpdateItem(): Size(0), IsDir(false) {}
+};
+
+
+static HRESULT GetPropString(IArchiveUpdateCallback *callback, UInt32 index, PROPID propId,
+ UString &res,
+ bool convertSlash)
+{
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(index, propId, &prop))
+ if (prop.vt == VT_BSTR)
+ {
+ res = prop.bstrVal;
+ if (convertSlash)
+ NArchive::NItemName::ReplaceSlashes_OsToUnix(res);
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::GetFileTimeType(UInt32 *type))
+{
+ *type = NFileTimeType::kUnix;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CHandler::UpdateItems(ISequentialOutStream *outStream, UInt32 numItems,
+ IArchiveUpdateCallback *callback))
+{
+ COM_TRY_BEGIN
+
+ if (_isArc && !CanUpdate())
+ return E_NOTIMPL;
+
+ /*
+ Z7_DECL_CMyComPtr_QI_FROM(IArchiveUpdateCallbackArcProp,
+ reportArcProp, callback)
+ */
+
+ CObjectVector<CUpdateItem> updateItems;
+
+ UInt64 complexity = 0;
+
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ CUpdateItem ui;
+ Int32 newData;
+ Int32 newProps;
+ UInt32 indexInArc;
+
+ if (!callback)
+ return E_FAIL;
+
+ RINOK(callback->GetUpdateItemInfo(i, &newData, &newProps, &indexInArc))
+
+ ui.NewProps = IntToBool(newProps);
+ ui.NewData = IntToBool(newData);
+ ui.IndexInArc = (int)indexInArc;
+ ui.IndexInClient = i;
+ if (IntToBool(newProps))
+ {
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidIsDir, &prop))
+ if (prop.vt == VT_EMPTY)
+ ui.IsDir = false;
+ else if (prop.vt != VT_BOOL)
+ return E_INVALIDARG;
+ else
+ ui.IsDir = (prop.boolVal != VARIANT_FALSE);
+ }
+
+ RINOK(GetPropString(callback, i, kpidPath, ui.Path,
+ true)) // convertSlash
+ /*
+ if (ui.IsDir && !ui.Name.IsEmpty() && ui.Name.Back() != '/')
+ ui.Name += '/';
+ */
+ }
+
+ if (IntToBool(newData))
+ {
+ NCOM::CPropVariant prop;
+ RINOK(callback->GetProperty(i, kpidSize, &prop))
+ if (prop.vt == VT_UI8)
+ {
+ ui.Size = prop.uhVal.QuadPart;
+ complexity += ui.Size;
+ }
+ else if (prop.vt == VT_EMPTY)
+ ui.Size = (UInt64)(Int64)-1;
+ else
+ return E_INVALIDARG;
+ }
+
+ updateItems.Add(ui);
+ }
+
+ if (complexity != 0)
+ {
+ RINOK(callback->SetTotal(complexity))
+ }
+
+ #ifdef Z7_EXTERNAL_CODECS
+ const CExternalCodecs *_externalCodecs = g_ExternalCodecs_Ptr;
+ #endif
+
+ CHashBundle hb;
+ UStringVector methods;
+ if (!_methods.IsEmpty())
+ {
+ FOR_VECTOR(k, _methods)
+ {
+ methods.Add(_methods[k]);
+ }
+ }
+ else if (_crcSize_WasSet)
+ {
+ AddDefaultMethod(methods, _crcSize);
+ }
+ else
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IArchiveGetRootProps,
+ getRootProps, callback)
+ if (getRootProps)
+ {
+ NCOM::CPropVariant prop;
+ RINOK(getRootProps->GetRootProp(kpidArcFileName, &prop))
+ if (prop.vt == VT_BSTR)
+ {
+ const UString method = GetMethod_from_FileName(prop.bstrVal);
+ if (!method.IsEmpty())
+ methods.Add(method);
+ }
+ }
+ }
+
+ RINOK(hb.SetMethods(EXTERNAL_CODECS_LOC_VARS methods))
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(callback, true);
+
+ const UInt32 kBufSize = 1 << 15;
+ CHashMidBuf buf;
+ if (!buf.Alloc(kBufSize))
+ return E_OUTOFMEMORY;
+
+ CDynLimBuf hashFileString((size_t)1 << 31);
+
+ CHashOptionsLocal options = _options;
+
+ if (_isArc)
+ {
+ if (!options.HashMode_Zero.Def && _is_ZeroMode)
+ options.HashMode_Zero.Val = true;
+ if (!options.HashMode_Tag.Def && _are_there_Tags)
+ options.HashMode_Tag.Val = true;
+ if (!options.HashMode_Dirs.Def && _are_there_Dirs)
+ options.HashMode_Dirs.Val = true;
+ }
+ if (options.HashMode_OnlyHash.Val && updateItems.Size() != 1)
+ options.HashMode_OnlyHash.Val = false;
+
+ lps->OutSize = 0;
+ complexity = 0;
+
+ for (i = 0; i < updateItems.Size(); i++)
+ {
+ lps->InSize = complexity;
+ RINOK(lps->SetCur())
+
+ const CUpdateItem &ui = updateItems[i];
+
+ /*
+ CHashPair item;
+ if (!ui.NewProps)
+ item = HashPairs[(unsigned)ui.IndexInArc];
+ */
+
+ if (ui.NewData)
+ {
+ UInt64 currentComplexity = ui.Size;
+ UInt64 fileSize = 0;
+
+ CMyComPtr<ISequentialInStream> fileInStream;
+ bool needWrite = true;
+ {
+ HRESULT res = callback->GetStream(ui.IndexInClient, &fileInStream);
+
+ if (res == S_FALSE)
+ needWrite = false;
+ else
+ {
+ RINOK(res)
+
+ if (fileInStream)
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IStreamGetSize,
+ streamGetSize, fileInStream)
+ if (streamGetSize)
+ {
+ UInt64 size;
+ if (streamGetSize->GetSize(&size) == S_OK)
+ currentComplexity = size;
+ }
+ /*
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IStreamGetProps,
+ getProps, fileInStream)
+ if (getProps)
+ {
+ FILETIME mTime;
+ UInt64 size2;
+ if (getProps->GetProps(&size2, NULL, NULL, &mTime, NULL) == S_OK)
+ {
+ currentComplexity = size2;
+ // item.MTime = NWindows::NTime::FileTimeToUnixTime64(mTime);;
+ }
+ }
+ */
+ }
+ else
+ {
+ currentComplexity = 0;
+ }
+ }
+ }
+
+ hb.InitForNewFile();
+ const bool isDir = ui.IsDir;
+
+ if (needWrite && fileInStream && !isDir)
+ {
+ for (UInt32 step = 0;; step++)
+ {
+ if ((step & 0xFF) == 0)
+ {
+ RINOK(progress->SetRatioInfo(&fileSize, NULL))
+ // RINOK(callback->SetCompleted(&completeValue));
+ }
+ UInt32 size;
+ RINOK(fileInStream->Read(buf, kBufSize, &size))
+ if (size == 0)
+ break;
+ hb.Update(buf, size);
+ fileSize += size;
+ }
+ currentComplexity = fileSize;
+ }
+
+ fileInStream.Release();
+ const bool isAltStream = false;
+ hb.Final(isDir, isAltStream, ui.Path);
+
+ if (options.HashMode_Dirs.Val || !isDir)
+ {
+ if (!hb.Hashers.IsEmpty())
+ lps->OutSize += hb.Hashers[0].DigestSize;
+ WriteLine(hashFileString,
+ options,
+ ui.Path,
+ isDir,
+ hb);
+ if (hashFileString.IsError())
+ return E_OUTOFMEMORY;
+ }
+
+ complexity += currentComplexity;
+
+ /*
+ if (reportArcProp)
+ {
+ PROPVARIANT prop;
+ prop.vt = VT_EMPTY;
+ prop.wReserved1 = 0;
+
+ NCOM::PropVarEm_Set_UInt64(&prop, fileSize);
+ RINOK(reportArcProp->ReportProp(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, kpidSize, &prop));
+
+ for (unsigned k = 0; k < hb.Hashers.Size(); k++)
+ {
+ const CHasherState &hs = hb.Hashers[k];
+
+ if (hs.DigestSize == 4 && hs.Name.IsEqualTo_Ascii_NoCase("crc32"))
+ {
+ NCOM::PropVarEm_Set_UInt32(&prop, GetUi32(hs.Digests[k_HashCalc_Index_Current]));
+ RINOK(reportArcProp->ReportProp(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, kpidCRC, &prop));
+ }
+ else
+ {
+ RINOK(reportArcProp->ReportRawProp(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient,
+ kpidChecksum, hs.Digests[k_HashCalc_Index_Current],
+ hs.DigestSize, NPropDataType::kRaw));
+ }
+ RINOK(reportArcProp->ReportFinished(NArchive::NEventIndexType::kOutArcIndex, ui.IndexInClient, NArchive::NUpdate::NOperationResult::kOK));
+ }
+ }
+ */
+ RINOK(callback->SetOperationResult(NArchive::NUpdate::NOperationResult::kOK))
+ }
+ else
+ {
+ // old data
+ const CHashPair &existItem = HashPairs[(unsigned)ui.IndexInArc];
+ if (ui.NewProps)
+ {
+ WriteLine(hashFileString,
+ options,
+ ui.Path,
+ ui.IsDir,
+ existItem.Method, existItem.HashString
+ );
+ }
+ else
+ {
+ hashFileString += existItem.FullLine;
+ Add_LF(hashFileString, options);
+ }
+ }
+ if (hashFileString.IsError())
+ return E_OUTOFMEMORY;
+ }
+
+ RINOK(WriteStream(outStream, hashFileString, hashFileString.Len()))
+
+ return S_OK;
+ COM_TRY_END
+}
+
+
+
+HRESULT CHandler::SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value)
+{
+ UString name = nameSpec;
+ name.MakeLower_Ascii();
+ if (name.IsEmpty())
+ return E_INVALIDARG;
+
+ if (name.IsEqualTo("m")) // "hm" hash method
+ {
+ // COneMethodInfo omi;
+ // RINOK(omi.ParseMethodFromPROPVARIANT(L"", value));
+ // _methods.Add(omi.MethodName); // change it. use omi.PropsString
+ if (value.vt != VT_BSTR)
+ return E_INVALIDARG;
+ UString s (value.bstrVal);
+ _methods.Add(s);
+ return S_OK;
+ }
+
+ if (name.IsEqualTo("flags"))
+ {
+ if (value.vt != VT_BSTR)
+ return E_INVALIDARG;
+ if (!_options.ParseString(value.bstrVal))
+ return E_INVALIDARG;
+ return S_OK;
+ }
+
+ if (name.IsPrefixedBy_Ascii_NoCase("crc"))
+ {
+ name.Delete(0, 3);
+ _crcSize = 4;
+ _crcSize_WasSet = true;
+ return ParsePropToUInt32(name, value, _crcSize);
+ }
+
+ // common properties
+ if (name.IsPrefixedBy_Ascii_NoCase("mt")
+ || name.IsPrefixedBy_Ascii_NoCase("memuse"))
+ return S_OK;
+
+ return E_INVALIDARG;
+}
+
+
+Z7_COM7F_IMF(CHandler::SetProperties(const wchar_t * const *names, const PROPVARIANT *values, UInt32 numProps))
+{
+ COM_TRY_BEGIN
+
+ InitProps();
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ RINOK(SetProperty(names[i], values[i]))
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+CHandler::CHandler()
+{
+ ClearVars();
+ InitProps();
+}
+
+}
+
+
+
+static IInArchive *CreateHashHandler_In() { return new NHash::CHandler; }
+static IOutArchive *CreateHashHandler_Out() { return new NHash::CHandler; }
+
+void Codecs_AddHashArcHandler(CCodecs *codecs)
+{
+ {
+ CArcInfoEx item;
+
+ item.Name = "Hash";
+ item.CreateInArchive = CreateHashHandler_In;
+ item.CreateOutArchive = CreateHashHandler_Out;
+ item.IsArcFunc = NULL;
+ item.Flags =
+ NArcInfoFlags::kKeepName
+ | NArcInfoFlags::kStartOpen
+ | NArcInfoFlags::kByExtOnlyOpen
+ // | NArcInfoFlags::kPureStartOpen
+ | NArcInfoFlags::kHashHandler
+ ;
+
+ // ubuntu uses "SHA256SUMS" file
+ item.AddExts(UString (
+ "sha256 sha512 sha224 sha384 sha1 sha md5"
+ // "b2sum"
+ " crc32 crc64"
+ " asc"
+ " cksum"
+ ),
+ UString());
+
+ item.UpdateEnabled = (item.CreateOutArchive != NULL);
+ item.SignatureOffset = 0;
+ // item.Version = MY_VER_MIX;
+ item.NewInterface = true;
+
+ item.Signatures.AddNew().CopyFrom(NULL, 0);
+
+ codecs->Formats.Add(item);
+ }
+}
diff --git a/CPP/7zip/UI/Common/HashCalc.h b/CPP/7zip/UI/Common/HashCalc.h
index 524bd3b..0b527c1 100644
--- a/CPP/7zip/UI/Common/HashCalc.h
+++ b/CPP/7zip/UI/Common/HashCalc.h
@@ -1,110 +1,328 @@
-// HashCalc.h
-
-#ifndef __HASH_CALC_H
-#define __HASH_CALC_H
-
-#include "../../../Common/Wildcard.h"
-
-#include "../../Common/CreateCoder.h"
-#include "../../Common/MethodProps.h"
-
-#include "DirItem.h"
-
-const unsigned k_HashCalc_DigestSize_Max = 64;
-
-const unsigned k_HashCalc_NumGroups = 4;
-
-enum
-{
- k_HashCalc_Index_Current,
- k_HashCalc_Index_DataSum,
- k_HashCalc_Index_NamesSum,
- k_HashCalc_Index_StreamsSum
-};
-
-struct CHasherState
-{
- CMyComPtr<IHasher> Hasher;
- AString Name;
- UInt32 DigestSize;
- Byte Digests[k_HashCalc_NumGroups][k_HashCalc_DigestSize_Max];
-};
-
-struct IHashCalc
-{
- virtual void InitForNewFile() = 0;
- virtual void Update(const void *data, UInt32 size) = 0;
- virtual void SetSize(UInt64 size) = 0;
- virtual void Final(bool isDir, bool isAltStream, const UString &path) = 0;
-};
-
-struct CHashBundle: public IHashCalc
-{
- CObjectVector<CHasherState> Hashers;
-
- UInt64 NumDirs;
- UInt64 NumFiles;
- UInt64 NumAltStreams;
- UInt64 FilesSize;
- UInt64 AltStreamsSize;
- UInt64 NumErrors;
-
- UInt64 CurSize;
-
- UString MainName;
- UString FirstFileName;
-
- HRESULT SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &methods);
-
- // void Init() {}
- CHashBundle()
- {
- NumDirs = NumFiles = NumAltStreams = FilesSize = AltStreamsSize = NumErrors = 0;
- }
-
- void InitForNewFile();
- void Update(const void *data, UInt32 size);
- void SetSize(UInt64 size);
- void Final(bool isDir, bool isAltStream, const UString &path);
-};
-
-#define INTERFACE_IHashCallbackUI(x) \
- INTERFACE_IDirItemsCallback(x) \
- virtual HRESULT StartScanning() x; \
- virtual HRESULT FinishScanning(const CDirItemsStat &st) x; \
- virtual HRESULT SetNumFiles(UInt64 numFiles) x; \
- virtual HRESULT SetTotal(UInt64 size) x; \
- virtual HRESULT SetCompleted(const UInt64 *completeValue) x; \
- virtual HRESULT CheckBreak() x; \
- virtual HRESULT BeforeFirstFile(const CHashBundle &hb) x; \
- virtual HRESULT GetStream(const wchar_t *name, bool isFolder) x; \
- virtual HRESULT OpenFileError(const FString &path, DWORD systemError) x; \
- virtual HRESULT SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash) x; \
- virtual HRESULT AfterLastFile(CHashBundle &hb) x; \
-
-struct IHashCallbackUI: public IDirItemsCallback
-{
- INTERFACE_IHashCallbackUI(=0)
-};
-
-struct CHashOptions
-{
- UStringVector Methods;
- bool OpenShareForWrite;
- bool StdInMode;
- bool AltStreamsMode;
- NWildcard::ECensorPathMode PathMode;
-
- CHashOptions(): StdInMode(false), OpenShareForWrite(false), AltStreamsMode(false), PathMode(NWildcard::k_RelatPath) {};
-};
-
-HRESULT HashCalc(
- DECL_EXTERNAL_CODECS_LOC_VARS
- const NWildcard::CCensor &censor,
- const CHashOptions &options,
- AString &errorInfo,
- IHashCallbackUI *callback);
-
-void AddHashHexToString(char *dest, const Byte *data, UInt32 size);
-
-#endif
+// HashCalc.h
+
+#ifndef ZIP7_INC_HASH_CALC_H
+#define ZIP7_INC_HASH_CALC_H
+
+#include "../../../Common/UTFConvert.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../../Common/CreateCoder.h"
+#include "../../Common/MethodProps.h"
+
+#include "DirItem.h"
+#include "IFileExtractCallback.h"
+
+const unsigned k_HashCalc_DigestSize_Max = 64;
+const unsigned k_HashCalc_ExtraSize = 8;
+const unsigned k_HashCalc_NumGroups = 4;
+
+/*
+ if (size <= 8) : upper case : reversed byte order : it shows 32-bit/64-bit number, if data contains little-endian number
+ if (size > 8) : lower case : original byte order (as big-endian byte sequence)
+*/
+void HashHexToString(char *dest, const Byte *data, UInt32 size);
+
+enum
+{
+ k_HashCalc_Index_Current,
+ k_HashCalc_Index_DataSum,
+ k_HashCalc_Index_NamesSum,
+ k_HashCalc_Index_StreamsSum
+};
+
+struct CHasherState
+{
+ CMyComPtr<IHasher> Hasher;
+ AString Name;
+ UInt32 DigestSize;
+ UInt64 NumSums[k_HashCalc_NumGroups];
+ Byte Digests[k_HashCalc_NumGroups][k_HashCalc_DigestSize_Max + k_HashCalc_ExtraSize];
+
+ void InitDigestGroup(unsigned groupIndex)
+ {
+ NumSums[groupIndex] = 0;
+ memset(Digests[groupIndex], 0, sizeof(Digests[groupIndex]));
+ }
+
+ const Byte *GetExtraData_for_Group(unsigned groupIndex) const
+ {
+ return Digests[groupIndex] + k_HashCalc_DigestSize_Max;
+ }
+
+ unsigned GetNumExtraBytes_for_Group(unsigned groupIndex) const
+ {
+ const Byte *p = GetExtraData_for_Group(groupIndex);
+ // we use little-endian to read extra bytes
+ for (unsigned i = k_HashCalc_ExtraSize; i != 0; i--)
+ if (p[i - 1] != 0)
+ return i;
+ return 0;
+ }
+
+ void AddDigest(unsigned groupIndex, const Byte *data);
+
+ void WriteToString(unsigned digestIndex, char *s) const;
+};
+
+
+Z7_PURE_INTERFACES_BEGIN
+
+
+DECLARE_INTERFACE(IHashCalc)
+{
+ virtual void InitForNewFile() = 0;
+ virtual void Update(const void *data, UInt32 size) = 0;
+ virtual void SetSize(UInt64 size) = 0;
+ virtual void Final(bool isDir, bool isAltStream, const UString &path) = 0;
+};
+
+Z7_PURE_INTERFACES_END
+
+struct CHashBundle Z7_final: public IHashCalc
+{
+ CObjectVector<CHasherState> Hashers;
+
+ UInt64 NumDirs;
+ UInt64 NumFiles;
+ UInt64 NumAltStreams;
+ UInt64 FilesSize;
+ UInt64 AltStreamsSize;
+ UInt64 NumErrors;
+
+ UInt64 CurSize;
+
+ UString MainName;
+ UString FirstFileName;
+
+ HRESULT SetMethods(DECL_EXTERNAL_CODECS_LOC_VARS const UStringVector &methods);
+
+ // void Init() {}
+ CHashBundle()
+ {
+ NumDirs = NumFiles = NumAltStreams = FilesSize = AltStreamsSize = NumErrors = 0;
+ }
+
+ void InitForNewFile() Z7_override;
+ void Update(const void *data, UInt32 size) Z7_override;
+ void SetSize(UInt64 size) Z7_override;
+ void Final(bool isDir, bool isAltStream, const UString &path) Z7_override;
+};
+
+Z7_PURE_INTERFACES_BEGIN
+
+// INTERFACE_IDirItemsCallback(x)
+
+#define Z7_IFACEN_IHashCallbackUI(x) \
+ virtual HRESULT StartScanning() x \
+ virtual HRESULT FinishScanning(const CDirItemsStat &st) x \
+ virtual HRESULT SetNumFiles(UInt64 numFiles) x \
+ virtual HRESULT SetTotal(UInt64 size) x \
+ virtual HRESULT SetCompleted(const UInt64 *completeValue) x \
+ virtual HRESULT CheckBreak() x \
+ virtual HRESULT BeforeFirstFile(const CHashBundle &hb) x \
+ virtual HRESULT GetStream(const wchar_t *name, bool isFolder) x \
+ virtual HRESULT OpenFileError(const FString &path, DWORD systemError) x \
+ virtual HRESULT SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash) x \
+ virtual HRESULT AfterLastFile(CHashBundle &hb) x \
+
+Z7_IFACE_DECL_PURE_(IHashCallbackUI, IDirItemsCallback)
+
+Z7_PURE_INTERFACES_END
+
+
+struct CHashOptionsLocal
+{
+ CBoolPair HashMode_Zero;
+ CBoolPair HashMode_Tag;
+ CBoolPair HashMode_Dirs;
+ CBoolPair HashMode_OnlyHash;
+
+ void Init_HashOptionsLocal()
+ {
+ HashMode_Zero.Init();
+ HashMode_Tag.Init();
+ HashMode_Dirs.Init();
+ HashMode_OnlyHash.Init();
+ // HashMode_Dirs = true; // for debug
+ }
+
+ CHashOptionsLocal()
+ {
+ Init_HashOptionsLocal();
+ }
+
+ bool ParseFlagCharOption(wchar_t c, bool val)
+ {
+ c = MyCharLower_Ascii(c);
+ if (c == 'z') HashMode_Zero.SetVal_as_Defined(val);
+ else if (c == 't') HashMode_Tag.SetVal_as_Defined(val);
+ else if (c == 'd') HashMode_Dirs.SetVal_as_Defined(val);
+ else if (c == 'h') HashMode_OnlyHash.SetVal_as_Defined(val);
+ else return false;
+ return true;
+ }
+
+ bool ParseString(const UString &s)
+ {
+ for (unsigned i = 0; i < s.Len();)
+ {
+ const wchar_t c = s[i++];
+ bool val = true;
+ if (i < s.Len())
+ {
+ const wchar_t next = s[i];
+ if (next == '-')
+ {
+ val = false;
+ i++;
+ }
+ }
+ if (!ParseFlagCharOption(c, val))
+ return false;
+ }
+ return true;
+ }
+};
+
+
+struct CHashOptions
+ // : public CHashOptionsLocal
+{
+ UStringVector Methods;
+ // UString HashFilePath;
+
+ bool PreserveATime;
+ bool OpenShareForWrite;
+ bool StdInMode;
+ bool AltStreamsMode;
+ CBoolPair SymLinks;
+
+ NWildcard::ECensorPathMode PathMode;
+
+ CHashOptions():
+ PreserveATime(false),
+ OpenShareForWrite(false),
+ StdInMode(false),
+ AltStreamsMode(false),
+ PathMode(NWildcard::k_RelatPath) {}
+};
+
+
+HRESULT HashCalc(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const NWildcard::CCensor &censor,
+ const CHashOptions &options,
+ AString &errorInfo,
+ IHashCallbackUI *callback);
+
+
+
+#ifndef Z7_SFX
+
+namespace NHash {
+
+struct CHashPair
+{
+ CByteBuffer Hash;
+ char Mode;
+ bool IsBSD;
+ bool Size_from_Arc_Defined;
+ bool Size_from_Disk_Defined;
+ AString Method;
+ AString Name;
+
+ AString FullLine;
+ AString HashString;
+ // unsigned HashLengthInBits;
+
+ // AString MethodName;
+ UInt64 Size_from_Arc;
+ UInt64 Size_from_Disk;
+
+ bool IsDir() const;
+
+ void Get_UString_Path(UString &path) const
+ {
+ path.Empty();
+ if (!ConvertUTF8ToUnicode(Name, path))
+ return;
+ }
+
+ bool ParseCksum(const char *s);
+ bool Parse(const char *s);
+
+ bool IsSupportedMode() const
+ {
+ return Mode != 'U' && Mode != '^';
+ }
+
+ CHashPair():
+ Mode(0)
+ , IsBSD(false)
+ , Size_from_Arc_Defined(false)
+ , Size_from_Disk_Defined(false)
+ // , HashLengthInBits(0)
+ , Size_from_Arc(0)
+ , Size_from_Disk(0)
+ {}
+};
+
+
+Z7_CLASS_IMP_CHandler_IInArchive_3(
+ IArchiveGetRawProps,
+ /* public IGetArchiveHashHandler, */
+ IOutArchive,
+ ISetProperties
+)
+ bool _isArc;
+ UInt64 _phySize;
+ CObjectVector<CHashPair> HashPairs;
+ UString _nameExtenstion;
+ // UString _method_fromName;
+ AString _pgpMethod;
+ bool _is_CksumMode;
+ bool _is_PgpMethod;
+ bool _is_ZeroMode;
+ bool _are_there_Tags;
+ bool _are_there_Dirs;
+ bool _hashSize_Defined;
+ unsigned _hashSize;
+
+ bool _crcSize_WasSet;
+ UInt32 _crcSize;
+ UStringVector _methods;
+
+ void ClearVars();
+
+ void InitProps()
+ {
+ _crcSize_WasSet = false;
+ _crcSize = 4;
+ _methods.Clear();
+ _options.Init_HashOptionsLocal();
+ }
+
+ CHashOptionsLocal _options;
+
+ bool CanUpdate() const
+ {
+ if (!_isArc || _is_PgpMethod || _is_CksumMode)
+ return false;
+ return true;
+
+ }
+
+ HRESULT SetProperty(const wchar_t *nameSpec, const PROPVARIANT &value);
+
+public:
+ CHandler();
+};
+
+}
+
+void Codecs_AddHashArcHandler(CCodecs *codecs);
+
+#endif
+
+
+#endif
diff --git a/CPP/7zip/UI/Common/IFileExtractCallback.h b/CPP/7zip/UI/Common/IFileExtractCallback.h
index 3f554ef..dd5c0d7 100644
--- a/CPP/7zip/UI/Common/IFileExtractCallback.h
+++ b/CPP/7zip/UI/Common/IFileExtractCallback.h
@@ -1,114 +1,112 @@
-// IFileExtractCallback.h
-
-#ifndef __I_FILE_EXTRACT_CALLBACK_H
-#define __I_FILE_EXTRACT_CALLBACK_H
-
-#include "../../../Common/MyString.h"
-
-#include "../../IDecl.h"
-
-#include "LoadCodecs.h"
-#include "OpenArchive.h"
-
-namespace NOverwriteAnswer
-{
- enum EEnum
- {
- kYes,
- kYesToAll,
- kNo,
- kNoToAll,
- kAutoRename,
- kCancel
- };
-}
-
-
-/* ---------- IFolderArchiveExtractCallback ----------
-is implemented by
- Console/ExtractCallbackConsole.h CExtractCallbackConsole
- FileManager/ExtractCallback.h CExtractCallbackImp
- FAR/ExtractEngine.cpp CExtractCallBackImp: (QueryInterface is not supported)
-
-IID_IFolderArchiveExtractCallback is requested by:
- - Agent/ArchiveFolder.cpp
- CAgentFolder::CopyTo(..., IFolderOperationsExtractCallback *callback)
- is sent to IArchiveFolder::Extract()
-
- - FileManager/PanelCopy.cpp
- CPanel::CopyTo(), if (options->testMode)
- is sent to IArchiveFolder::Extract()
-
- IFolderArchiveExtractCallback is used by Common/ArchiveExtractCallback.cpp
-*/
-
-#define INTERFACE_IFolderArchiveExtractCallback(x) \
- STDMETHOD(AskOverwrite)( \
- const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize, \
- const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize, \
- Int32 *answer) x; \
- STDMETHOD(PrepareOperation)(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 *position) x; \
- STDMETHOD(MessageError)(const wchar_t *message) x; \
- STDMETHOD(SetOperationResult)(Int32 opRes, Int32 encrypted) x; \
-
-DECL_INTERFACE_SUB(IFolderArchiveExtractCallback, IProgress, 0x01, 0x07)
-{
- INTERFACE_IFolderArchiveExtractCallback(PURE)
-};
-
-#define INTERFACE_IFolderArchiveExtractCallback2(x) \
- STDMETHOD(ReportExtractResult)(Int32 opRes, Int32 encrypted, const wchar_t *name) x; \
-
-DECL_INTERFACE_SUB(IFolderArchiveExtractCallback2, IUnknown, 0x01, 0x08)
-{
- INTERFACE_IFolderArchiveExtractCallback2(PURE)
-};
-
-/* ---------- IExtractCallbackUI ----------
-is implemented by
- Console/ExtractCallbackConsole.h CExtractCallbackConsole
- FileManager/ExtractCallback.h CExtractCallbackImp
-*/
-
-#ifdef _NO_CRYPTO
- #define INTERFACE_IExtractCallbackUI_Crypto(x)
-#else
- #define INTERFACE_IExtractCallbackUI_Crypto(x) \
- virtual HRESULT SetPassword(const UString &password) x;
-#endif
-
-#define INTERFACE_IExtractCallbackUI(x) \
- virtual HRESULT BeforeOpen(const wchar_t *name, bool testMode) x; \
- virtual HRESULT OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) x; \
- virtual HRESULT ThereAreNoFiles() x; \
- virtual HRESULT ExtractResult(HRESULT result) x; \
- INTERFACE_IExtractCallbackUI_Crypto(x)
-
-struct IExtractCallbackUI: IFolderArchiveExtractCallback
-{
- INTERFACE_IExtractCallbackUI(PURE)
-};
-
-
-
-#define INTERFACE_IGetProp(x) \
- STDMETHOD(GetProp)(PROPID propID, PROPVARIANT *value) x; \
-
-DECL_INTERFACE_SUB(IGetProp, IUnknown, 0x01, 0x20)
-{
- INTERFACE_IGetProp(PURE)
-};
-
-#define INTERFACE_IFolderExtractToStreamCallback(x) \
- STDMETHOD(UseExtractToStream)(Int32 *res) x; \
- STDMETHOD(GetStream7)(const wchar_t *name, Int32 isDir, ISequentialOutStream **outStream, Int32 askExtractMode, IGetProp *getProp) x; \
- STDMETHOD(PrepareOperation7)(Int32 askExtractMode) x; \
- STDMETHOD(SetOperationResult7)(Int32 resultEOperationResult, Int32 encrypted) x; \
-
-DECL_INTERFACE_SUB(IFolderExtractToStreamCallback, IUnknown, 0x01, 0x30)
-{
- INTERFACE_IFolderExtractToStreamCallback(PURE)
-};
-
-
-#endif
+// IFileExtractCallback.h
+
+#ifndef ZIP7_INC_I_FILE_EXTRACT_CALLBACK_H
+#define ZIP7_INC_I_FILE_EXTRACT_CALLBACK_H
+
+#include "../../../Common/MyString.h"
+
+#include "../../IDecl.h"
+
+#include "LoadCodecs.h"
+#include "OpenArchive.h"
+
+Z7_PURE_INTERFACES_BEGIN
+
+#define Z7_IFACE_CONSTR_FOLDERARC_SUB(i, base, n) \
+ Z7_DECL_IFACE_7ZIP_SUB(i, base, 1, n) \
+ { Z7_IFACE_COM7_PURE(i) };
+
+#define Z7_IFACE_CONSTR_FOLDERARC(i, n) \
+ Z7_IFACE_CONSTR_FOLDERARC_SUB(i, IUnknown, n)
+
+namespace NOverwriteAnswer
+{
+ enum EEnum
+ {
+ kYes,
+ kYesToAll,
+ kNo,
+ kNoToAll,
+ kAutoRename,
+ kCancel
+ };
+}
+
+
+/* ---------- IFolderArchiveExtractCallback ----------
+is implemented by
+ Console/ExtractCallbackConsole.h CExtractCallbackConsole
+ FileManager/ExtractCallback.h CExtractCallbackImp
+ FAR/ExtractEngine.cpp CExtractCallBackImp: (QueryInterface is not supported)
+
+IID_IFolderArchiveExtractCallback is requested by:
+ - Agent/ArchiveFolder.cpp
+ CAgentFolder::CopyTo(..., IFolderOperationsExtractCallback *callback)
+ is sent to IArchiveFolder::Extract()
+
+ - FileManager/PanelCopy.cpp
+ CPanel::CopyTo(), if (options->testMode)
+ is sent to IArchiveFolder::Extract()
+
+ IFolderArchiveExtractCallback is used by Common/ArchiveExtractCallback.cpp
+*/
+
+#define Z7_IFACEM_IFolderArchiveExtractCallback(x) \
+ x(AskOverwrite( \
+ const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize, \
+ const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize, \
+ Int32 *answer)) \
+ x(PrepareOperation(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 *position)) \
+ x(MessageError(const wchar_t *message)) \
+ x(SetOperationResult(Int32 opRes, Int32 encrypted)) \
+
+Z7_IFACE_CONSTR_FOLDERARC_SUB(IFolderArchiveExtractCallback, IProgress, 0x07)
+
+#define Z7_IFACEM_IFolderArchiveExtractCallback2(x) \
+ x(ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)) \
+
+Z7_IFACE_CONSTR_FOLDERARC(IFolderArchiveExtractCallback2, 0x08)
+
+/* ---------- IExtractCallbackUI ----------
+is implemented by
+ Console/ExtractCallbackConsole.h CExtractCallbackConsole
+ FileManager/ExtractCallback.h CExtractCallbackImp
+*/
+
+#ifdef Z7_NO_CRYPTO
+ #define Z7_IFACEM_IExtractCallbackUI_Crypto(px)
+#else
+ #define Z7_IFACEM_IExtractCallbackUI_Crypto(px) \
+ virtual HRESULT SetPassword(const UString &password) px
+#endif
+
+#define Z7_IFACEN_IExtractCallbackUI(px) \
+ virtual HRESULT BeforeOpen(const wchar_t *name, bool testMode) px \
+ virtual HRESULT OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) px \
+ virtual HRESULT ThereAreNoFiles() px \
+ virtual HRESULT ExtractResult(HRESULT result) px \
+ Z7_IFACEM_IExtractCallbackUI_Crypto(px)
+
+// IExtractCallbackUI - is non-COM interface
+// IFolderArchiveExtractCallback - is COM interface
+// Z7_IFACE_DECL_PURE_(IExtractCallbackUI, IFolderArchiveExtractCallback)
+Z7_IFACE_DECL_PURE(IExtractCallbackUI)
+
+
+
+#define Z7_IFACEM_IGetProp(x) \
+ x(GetProp(PROPID propID, PROPVARIANT *value)) \
+
+Z7_IFACE_CONSTR_FOLDERARC(IGetProp, 0x20)
+
+#define Z7_IFACEM_IFolderExtractToStreamCallback(x) \
+ x(UseExtractToStream(Int32 *res)) \
+ x(GetStream7(const wchar_t *name, Int32 isDir, ISequentialOutStream **outStream, Int32 askExtractMode, IGetProp *getProp)) \
+ x(PrepareOperation7(Int32 askExtractMode)) \
+ x(SetOperationResult8(Int32 resultEOperationResult, Int32 encrypted, UInt64 size)) \
+
+Z7_IFACE_CONSTR_FOLDERARC(IFolderExtractToStreamCallback, 0x31)
+
+Z7_PURE_INTERFACES_END
+
+#endif
diff --git a/CPP/7zip/UI/Common/LoadCodecs.cpp b/CPP/7zip/UI/Common/LoadCodecs.cpp
index d31e05f..5a65bdc 100644
--- a/CPP/7zip/UI/Common/LoadCodecs.cpp
+++ b/CPP/7zip/UI/Common/LoadCodecs.cpp
@@ -1,1074 +1,1333 @@
-// LoadCodecs.cpp
-
-/*
-EXTERNAL_CODECS
----------------
- CCodecs::Load() tries to detect the directory with plugins.
- It stops the checking, if it can find any of the following items:
- - 7z.dll file
- - "Formats" subdir
- - "Codecs" subdir
- The order of check:
- 1) directory of client executable
- 2) WIN32: directory for REGISTRY item [HKEY_*\Software\7-Zip\Path**]
- The order for HKEY_* : Path** :
- - HKEY_CURRENT_USER : PathXX
- - HKEY_LOCAL_MACHINE : PathXX
- - HKEY_CURRENT_USER : Path
- - HKEY_LOCAL_MACHINE : Path
- PathXX is Path32 in 32-bit code
- PathXX is Path64 in 64-bit code
-
-
-EXPORT_CODECS
--------------
- if (EXTERNAL_CODECS) is defined, then the code exports internal
- codecs of client from CCodecs object to external plugins.
- 7-Zip doesn't use that feature. 7-Zip uses the scheme:
- - client application without internal plugins.
- - 7z.dll module contains all (or almost all) plugins.
- 7z.dll can use codecs from another plugins, if required.
-*/
-
-
-#include "StdAfx.h"
-
-#include "../../../../C/7zVersion.h"
-
-#include "../../../Common/MyCom.h"
-#include "../../../Common/StringToInt.h"
-#include "../../../Common/StringConvert.h"
-
-#include "../../../Windows/PropVariant.h"
-
-#include "LoadCodecs.h"
-
-using namespace NWindows;
-
-#ifdef NEW_FOLDER_INTERFACE
-#include "../../../Common/StringToInt.h"
-#endif
-
-#include "../../ICoder.h"
-#include "../../Common/RegisterArc.h"
-
-#ifdef EXTERNAL_CODECS
-
-// #define EXPORT_CODECS
-
-#endif
-
-#ifdef NEW_FOLDER_INTERFACE
-extern HINSTANCE g_hInstance;
-#include "../../../Windows/ResourceString.h"
-static const UINT kIconTypesResId = 100;
-#endif
-
-#ifdef EXTERNAL_CODECS
-
-#include "../../../Windows/FileFind.h"
-#include "../../../Windows/DLL.h"
-
-#ifdef _WIN32
-#include "../../../Windows/FileName.h"
-#include "../../../Windows/Registry.h"
-#endif
-
-using namespace NFile;
-
-
-#define kCodecsFolderName FTEXT("Codecs")
-#define kFormatsFolderName FTEXT("Formats")
-
-
-static CFSTR const kMainDll =
- // #ifdef _WIN32
- FTEXT("7z.dll");
- // #else
- // FTEXT("7z.so");
- // #endif
-
-
-#ifdef _WIN32
-
-static LPCTSTR const kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip");
-static LPCWSTR const kProgramPathValue = L"Path";
-static LPCWSTR const kProgramPath2Value = L"Path"
- #ifdef _WIN64
- L"64";
- #else
- L"32";
- #endif
-
-static bool ReadPathFromRegistry(HKEY baseKey, LPCWSTR value, FString &path)
-{
- NRegistry::CKey key;
- if (key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS)
- {
- UString pathU;
- if (key.QueryValue(value, pathU) == ERROR_SUCCESS)
- {
- path = us2fs(pathU);
- NName::NormalizeDirPathPrefix(path);
- return NFind::DoesFileExist(path + kMainDll);
- }
- }
- return false;
-}
-
-#endif // _WIN32
-
-#endif // EXTERNAL_CODECS
-
-
-static const unsigned kNumArcsMax = 64;
-static unsigned g_NumArcs = 0;
-static const CArcInfo *g_Arcs[kNumArcsMax];
-
-void RegisterArc(const CArcInfo *arcInfo) throw()
-{
- if (g_NumArcs < kNumArcsMax)
- {
- g_Arcs[g_NumArcs] = arcInfo;
- g_NumArcs++;
- }
-}
-
-static void SplitString(const UString &srcString, UStringVector &destStrings)
-{
- destStrings.Clear();
- UString s;
- unsigned len = srcString.Len();
- if (len == 0)
- return;
- for (unsigned i = 0; i < len; i++)
- {
- wchar_t c = srcString[i];
- if (c == L' ')
- {
- if (!s.IsEmpty())
- {
- destStrings.Add(s);
- s.Empty();
- }
- }
- else
- s += c;
- }
- if (!s.IsEmpty())
- destStrings.Add(s);
-}
-
-int CArcInfoEx::FindExtension(const UString &ext) const
-{
- FOR_VECTOR (i, Exts)
- if (ext.IsEqualTo_NoCase(Exts[i].Ext))
- return i;
- return -1;
-}
-
-void CArcInfoEx::AddExts(const UString &ext, const UString &addExt)
-{
- UStringVector exts, addExts;
- SplitString(ext, exts);
- SplitString(addExt, addExts);
- FOR_VECTOR (i, exts)
- {
- CArcExtInfo extInfo;
- extInfo.Ext = exts[i];
- if (i < addExts.Size())
- {
- extInfo.AddExt = addExts[i];
- if (extInfo.AddExt == L"*")
- extInfo.AddExt.Empty();
- }
- Exts.Add(extInfo);
- }
-}
-
-#ifndef _SFX
-
-static bool ParseSignatures(const Byte *data, unsigned size, CObjectVector<CByteBuffer> &signatures)
-{
- signatures.Clear();
- while (size > 0)
- {
- unsigned len = *data++;
- size--;
- if (len > size)
- return false;
- signatures.AddNew().CopyFrom(data, len);
- data += len;
- size -= len;
- }
- return true;
-}
-
-#endif // _SFX
-
-#ifdef EXTERNAL_CODECS
-
-static FString GetBaseFolderPrefixFromRegistry()
-{
- FString moduleFolderPrefix = NDLL::GetModuleDirPrefix();
- #ifdef _WIN32
- if (!NFind::DoesFileExist(moduleFolderPrefix + kMainDll) &&
- !NFind::DoesDirExist(moduleFolderPrefix + kCodecsFolderName) &&
- !NFind::DoesDirExist(moduleFolderPrefix + kFormatsFolderName))
- {
- FString path;
- if (ReadPathFromRegistry(HKEY_CURRENT_USER, kProgramPath2Value, path)) return path;
- if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPath2Value, path)) return path;
- if (ReadPathFromRegistry(HKEY_CURRENT_USER, kProgramPathValue, path)) return path;
- if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPathValue, path)) return path;
- }
- #endif
- return moduleFolderPrefix;
-}
-
-
-static HRESULT GetCoderClass(Func_GetMethodProperty getMethodProperty, UInt32 index,
- PROPID propId, CLSID &clsId, bool &isAssigned)
-{
- NCOM::CPropVariant prop;
- isAssigned = false;
- RINOK(getMethodProperty(index, propId, &prop));
- if (prop.vt == VT_BSTR)
- {
- if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID))
- return E_FAIL;
- isAssigned = true;
- clsId = *(const GUID *)prop.bstrVal;
- }
- else if (prop.vt != VT_EMPTY)
- return E_FAIL;
- return S_OK;
-}
-
-HRESULT CCodecs::LoadCodecs()
-{
- CCodecLib &lib = Libs.Back();
-
- lib.CreateDecoder = (Func_CreateDecoder)lib.Lib.GetProc("CreateDecoder");
- lib.CreateEncoder = (Func_CreateEncoder)lib.Lib.GetProc("CreateEncoder");
- lib.GetMethodProperty = (Func_GetMethodProperty)lib.Lib.GetProc("GetMethodProperty");
-
- if (lib.GetMethodProperty)
- {
- UInt32 numMethods = 1;
- Func_GetNumberOfMethods getNumberOfMethods = (Func_GetNumberOfMethods)lib.Lib.GetProc("GetNumberOfMethods");
- if (getNumberOfMethods)
- {
- RINOK(getNumberOfMethods(&numMethods));
- }
- for (UInt32 i = 0; i < numMethods; i++)
- {
- CDllCodecInfo info;
- info.LibIndex = Libs.Size() - 1;
- info.CodecIndex = i;
- RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kEncoder, info.Encoder, info.EncoderIsAssigned));
- RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kDecoder, info.Decoder, info.DecoderIsAssigned));
- Codecs.Add(info);
- }
- }
-
- Func_GetHashers getHashers = (Func_GetHashers)lib.Lib.GetProc("GetHashers");
- if (getHashers)
- {
- RINOK(getHashers(&lib.ComHashers));
- if (lib.ComHashers)
- {
- UInt32 numMethods = lib.ComHashers->GetNumHashers();
- for (UInt32 i = 0; i < numMethods; i++)
- {
- CDllHasherInfo info;
- info.LibIndex = Libs.Size() - 1;
- info.HasherIndex = i;
- Hashers.Add(info);
- }
- }
- }
-
- return S_OK;
-}
-
-static HRESULT GetProp(
- Func_GetHandlerProperty getProp,
- Func_GetHandlerProperty2 getProp2,
- UInt32 index, PROPID propID, NCOM::CPropVariant &prop)
-{
- if (getProp2)
- return getProp2(index, propID, &prop);;
- return getProp(propID, &prop);
-}
-
-static HRESULT GetProp_Bool(
- Func_GetHandlerProperty getProp,
- Func_GetHandlerProperty2 getProp2,
- UInt32 index, PROPID propID, bool &res)
-{
- res = false;
- NCOM::CPropVariant prop;
- RINOK(GetProp(getProp, getProp2, index, propID, prop));
- if (prop.vt == VT_BOOL)
- res = VARIANT_BOOLToBool(prop.boolVal);
- else if (prop.vt != VT_EMPTY)
- return E_FAIL;
- return S_OK;
-}
-
-static HRESULT GetProp_UInt32(
- Func_GetHandlerProperty getProp,
- Func_GetHandlerProperty2 getProp2,
- UInt32 index, PROPID propID, UInt32 &res, bool &defined)
-{
- res = 0;
- defined = false;
- NCOM::CPropVariant prop;
- RINOK(GetProp(getProp, getProp2, index, propID, prop));
- if (prop.vt == VT_UI4)
- {
- res = prop.ulVal;
- defined = true;
- }
- else if (prop.vt != VT_EMPTY)
- return E_FAIL;
- return S_OK;
-}
-
-static HRESULT GetProp_String(
- Func_GetHandlerProperty getProp,
- Func_GetHandlerProperty2 getProp2,
- UInt32 index, PROPID propID, UString &res)
-{
- res.Empty();
- NCOM::CPropVariant prop;
- RINOK(GetProp(getProp, getProp2, index, propID, prop));
- if (prop.vt == VT_BSTR)
- res.SetFromBstr(prop.bstrVal);
- else if (prop.vt != VT_EMPTY)
- return E_FAIL;
- return S_OK;
-}
-
-static HRESULT GetProp_RawData(
- Func_GetHandlerProperty getProp,
- Func_GetHandlerProperty2 getProp2,
- UInt32 index, PROPID propID, CByteBuffer &bb)
-{
- bb.Free();
- NCOM::CPropVariant prop;
- RINOK(GetProp(getProp, getProp2, index, propID, prop));
- if (prop.vt == VT_BSTR)
- {
- UINT len = ::SysStringByteLen(prop.bstrVal);
- bb.CopyFrom((const Byte *)prop.bstrVal, len);
- }
- else if (prop.vt != VT_EMPTY)
- return E_FAIL;
- return S_OK;
-}
-
-static const UInt32 kArcFlagsPars[] =
-{
- NArchive::NHandlerPropID::kKeepName, NArcInfoFlags::kKeepName,
- NArchive::NHandlerPropID::kAltStreams, NArcInfoFlags::kAltStreams,
- NArchive::NHandlerPropID::kNtSecure, NArcInfoFlags::kNtSecure
-};
-
-HRESULT CCodecs::LoadFormats()
-{
- const NDLL::CLibrary &lib = Libs.Back().Lib;
-
- Func_GetHandlerProperty getProp = NULL;
- Func_GetHandlerProperty2 getProp2 = (Func_GetHandlerProperty2)lib.GetProc("GetHandlerProperty2");
- Func_GetIsArc getIsArc = (Func_GetIsArc)lib.GetProc("GetIsArc");
-
- UInt32 numFormats = 1;
-
- if (getProp2)
- {
- Func_GetNumberOfFormats getNumberOfFormats = (Func_GetNumberOfFormats)lib.GetProc("GetNumberOfFormats");
- if (getNumberOfFormats)
- {
- RINOK(getNumberOfFormats(&numFormats));
- }
- }
- else
- {
- getProp = (Func_GetHandlerProperty)lib.GetProc("GetHandlerProperty");
- if (!getProp)
- return S_OK;
- }
-
- for (UInt32 i = 0; i < numFormats; i++)
- {
- CArcInfoEx item;
- item.LibIndex = Libs.Size() - 1;
- item.FormatIndex = i;
-
- RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kName, item.Name));
-
- {
- NCOM::CPropVariant prop;
- if (GetProp(getProp, getProp2, i, NArchive::NHandlerPropID::kClassID, prop) != S_OK)
- continue;
- if (prop.vt != VT_BSTR)
- continue;
- if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID))
- return E_FAIL;
- item.ClassID = *(const GUID *)prop.bstrVal;
- prop.Clear();
- }
-
- UString ext, addExt;
- RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kExtension, ext));
- RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kAddExtension, addExt));
- item.AddExts(ext, addExt);
-
- GetProp_Bool(getProp, getProp2, i, NArchive::NHandlerPropID::kUpdate, item.UpdateEnabled);
- bool flags_Defined = false;
- RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kFlags, item.Flags, flags_Defined));
- item.NewInterface = flags_Defined;
- if (!flags_Defined) // && item.UpdateEnabled
- {
- // support for DLL version before 9.31:
- for (unsigned j = 0; j < ARRAY_SIZE(kArcFlagsPars); j += 2)
- {
- bool val = false;
- GetProp_Bool(getProp, getProp2, i, kArcFlagsPars[j], val);
- if (val)
- item.Flags |= kArcFlagsPars[j + 1];
- }
- }
-
- CByteBuffer sig;
- RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kSignature, sig));
- if (sig.Size() != 0)
- item.Signatures.Add(sig);
- else
- {
- RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kMultiSignature, sig));
- ParseSignatures(sig, (unsigned)sig.Size(), item.Signatures);
- }
-
- bool signatureOffset_Defined;
- RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kSignatureOffset, item.SignatureOffset, signatureOffset_Defined));
-
- // bool version_Defined;
- // RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kVersion, item.Version, version_Defined));
-
- if (getIsArc)
- getIsArc(i, &item.IsArcFunc);
-
- Formats.Add(item);
- }
- return S_OK;
-}
-
-#ifdef _7ZIP_LARGE_PAGES
-extern "C"
-{
- extern SIZE_T g_LargePageSize;
-}
-#endif
-
-HRESULT CCodecs::LoadDll(const FString &dllPath, bool needCheckDll, bool *loadedOK)
-{
- if (loadedOK)
- *loadedOK = false;
-
- if (needCheckDll)
- {
- NDLL::CLibrary lib;
- if (!lib.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE))
- return S_OK;
- }
-
- Libs.AddNew();
- CCodecLib &lib = Libs.Back();
- lib.Path = dllPath;
- bool used = false;
- HRESULT res = S_OK;
-
- if (lib.Lib.Load(dllPath))
- {
- if (loadedOK)
- *loadedOK = true;
- #ifdef NEW_FOLDER_INTERFACE
- lib.LoadIcons();
- #endif
-
- #ifdef _7ZIP_LARGE_PAGES
- if (g_LargePageSize != 0)
- {
- Func_SetLargePageMode setLargePageMode = (Func_SetLargePageMode)lib.Lib.GetProc("SetLargePageMode");
- if (setLargePageMode)
- setLargePageMode();
- }
- #endif
-
- if (CaseSensitiveChange)
- {
- Func_SetCaseSensitive setCaseSensitive = (Func_SetCaseSensitive)lib.Lib.GetProc("SetCaseSensitive");
- if (setCaseSensitive)
- setCaseSensitive(CaseSensitive ? 1 : 0);
- }
-
- lib.CreateObject = (Func_CreateObject)lib.Lib.GetProc("CreateObject");
- {
- unsigned startSize = Codecs.Size() + Hashers.Size();
- res = LoadCodecs();
- used = (startSize != Codecs.Size() + Hashers.Size());
- if (res == S_OK && lib.CreateObject)
- {
- startSize = Formats.Size();
- res = LoadFormats();
- if (startSize != Formats.Size())
- used = true;
- }
- }
- }
-
- if (!used)
- Libs.DeleteBack();
-
- return res;
-}
-
-HRESULT CCodecs::LoadDllsFromFolder(const FString &folderPrefix)
-{
- NFile::NFind::CEnumerator enumerator;
- enumerator.SetDirPrefix(folderPrefix);
- NFile::NFind::CFileInfo fi;
- while (enumerator.Next(fi))
- {
- if (fi.IsDir())
- continue;
- RINOK(LoadDll(folderPrefix + fi.Name, true));
- }
- return S_OK;
-}
-
-void CCodecs::CloseLibs()
-{
- // OutputDebugStringA("~CloseLibs start");
- /*
- WIN32: FreeLibrary() (CLibrary::Free()) function doesn't work as expected,
- if it's called from another FreeLibrary() call.
- So we need to call FreeLibrary() before global destructors.
-
- Also we free global links from DLLs to object of this module before CLibrary::Free() call.
- */
-
- FOR_VECTOR(i, Libs)
- {
- const CCodecLib &lib = Libs[i];
- if (lib.SetCodecs)
- lib.SetCodecs(NULL);
- }
-
- // OutputDebugStringA("~CloseLibs after SetCodecs");
- Libs.Clear();
- // OutputDebugStringA("~CloseLibs end");
-}
-
-#endif // EXTERNAL_CODECS
-
-
-HRESULT CCodecs::Load()
-{
- #ifdef NEW_FOLDER_INTERFACE
- InternalIcons.LoadIcons(g_hInstance);
- #endif
-
- Formats.Clear();
-
- #ifdef EXTERNAL_CODECS
- MainDll_ErrorPath.Empty();
- Codecs.Clear();
- Hashers.Clear();
- #endif
-
- for (UInt32 i = 0; i < g_NumArcs; i++)
- {
- const CArcInfo &arc = *g_Arcs[i];
- CArcInfoEx item;
-
- item.Name = arc.Name;
- item.CreateInArchive = arc.CreateInArchive;
- item.IsArcFunc = arc.IsArc;
- item.Flags = arc.Flags;
-
- {
- UString e, ae;
- if (arc.Ext)
- e = arc.Ext;
- if (arc.AddExt)
- ae = arc.AddExt;
- item.AddExts(e, ae);
- }
-
- #ifndef _SFX
-
- item.CreateOutArchive = arc.CreateOutArchive;
- item.UpdateEnabled = (arc.CreateOutArchive != NULL);
- item.SignatureOffset = arc.SignatureOffset;
- // item.Version = MY_VER_MIX;
- item.NewInterface = true;
-
- if (arc.IsMultiSignature())
- ParseSignatures(arc.Signature, arc.SignatureSize, item.Signatures);
- else
- item.Signatures.AddNew().CopyFrom(arc.Signature, arc.SignatureSize);
-
- #endif
-
- Formats.Add(item);
- }
-
- #ifdef EXTERNAL_CODECS
- const FString baseFolder = GetBaseFolderPrefixFromRegistry();
- {
- bool loadedOK;
- RINOK(LoadDll(baseFolder + kMainDll, false, &loadedOK));
- if (!loadedOK)
- MainDll_ErrorPath = kMainDll;
- }
- RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName FSTRING_PATH_SEPARATOR));
- RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName FSTRING_PATH_SEPARATOR));
-
- NeedSetLibCodecs = true;
-
- if (Libs.Size() == 0)
- NeedSetLibCodecs = false;
- else if (Libs.Size() == 1)
- {
- // we don't need to set ISetCompressCodecsInfo, if all arcs and codecs are in one external module.
- #ifndef EXPORT_CODECS
- if (g_NumArcs == 0)
- NeedSetLibCodecs = false;
- #endif
- }
-
- if (NeedSetLibCodecs)
- {
- /* 15.00: now we call global function in DLL: SetCompressCodecsInfo(c)
- old versions called only ISetCompressCodecsInfo::SetCompressCodecsInfo(c) for each archive handler */
-
- FOR_VECTOR(i, Libs)
- {
- CCodecLib &lib = Libs[i];
- lib.SetCodecs = (Func_SetCodecs)lib.Lib.GetProc("SetCodecs");
- if (lib.SetCodecs)
- {
- RINOK(lib.SetCodecs(this));
- }
- }
- }
-
- #endif
-
- return S_OK;
-}
-
-#ifndef _SFX
-
-int CCodecs::FindFormatForArchiveName(const UString &arcPath) const
-{
- int dotPos = arcPath.ReverseFind_Dot();
- if (dotPos <= arcPath.ReverseFind_PathSepar())
- return -1;
- const UString ext = arcPath.Ptr(dotPos + 1);
- if (ext.IsEmpty())
- return -1;
- if (ext.IsEqualTo_Ascii_NoCase("exe"))
- return -1;
- FOR_VECTOR (i, Formats)
- {
- const CArcInfoEx &arc = Formats[i];
- /*
- if (!arc.UpdateEnabled)
- continue;
- */
- if (arc.FindExtension(ext) >= 0)
- return i;
- }
- return -1;
-}
-
-int CCodecs::FindFormatForExtension(const UString &ext) const
-{
- if (ext.IsEmpty())
- return -1;
- FOR_VECTOR (i, Formats)
- if (Formats[i].FindExtension(ext) >= 0)
- return i;
- return -1;
-}
-
-int CCodecs::FindFormatForArchiveType(const UString &arcType) const
-{
- FOR_VECTOR (i, Formats)
- if (Formats[i].Name.IsEqualTo_NoCase(arcType))
- return i;
- return -1;
-}
-
-bool CCodecs::FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const
-{
- formatIndices.Clear();
- for (unsigned pos = 0; pos < arcType.Len();)
- {
- int pos2 = arcType.Find(L'.', pos);
- if (pos2 < 0)
- pos2 = arcType.Len();
- const UString name = arcType.Mid(pos, pos2 - pos);
- if (name.IsEmpty())
- return false;
- int index = FindFormatForArchiveType(name);
- if (index < 0 && name != L"*")
- {
- formatIndices.Clear();
- return false;
- }
- formatIndices.Add(index);
- pos = pos2 + 1;
- }
- return true;
-}
-
-#endif // _SFX
-
-
-#ifdef NEW_FOLDER_INTERFACE
-
-void CCodecIcons::LoadIcons(HMODULE m)
-{
- UString iconTypes;
- MyLoadString(m, kIconTypesResId, iconTypes);
- UStringVector pairs;
- SplitString(iconTypes, pairs);
- FOR_VECTOR (i, pairs)
- {
- const UString &s = pairs[i];
- int pos = s.Find(L':');
- CIconPair iconPair;
- iconPair.IconIndex = -1;
- if (pos < 0)
- pos = s.Len();
- else
- {
- UString num = s.Ptr(pos + 1);
- if (!num.IsEmpty())
- {
- const wchar_t *end;
- iconPair.IconIndex = ConvertStringToUInt32(num, &end);
- if (*end != 0)
- continue;
- }
- }
- iconPair.Ext = s.Left(pos);
- IconPairs.Add(iconPair);
- }
-}
-
-bool CCodecIcons::FindIconIndex(const UString &ext, int &iconIndex) const
-{
- iconIndex = -1;
- FOR_VECTOR (i, IconPairs)
- {
- const CIconPair &pair = IconPairs[i];
- if (ext.IsEqualTo_NoCase(pair.Ext))
- {
- iconIndex = pair.IconIndex;
- return true;
- }
- }
- return false;
-}
-
-#endif // NEW_FOLDER_INTERFACE
-
-
-#ifdef EXTERNAL_CODECS
-
-// #define EXPORT_CODECS
-
-#ifdef EXPORT_CODECS
-
-extern unsigned g_NumCodecs;
-STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject);
-STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject);
-STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
-#define NUM_EXPORT_CODECS g_NumCodecs
-
-extern unsigned g_NumHashers;
-STDAPI CreateHasher(UInt32 index, IHasher **hasher);
-STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
-#define NUM_EXPORT_HASHERS g_NumHashers
-
-#else // EXPORT_CODECS
-
-#define NUM_EXPORT_CODECS 0
-#define NUM_EXPORT_HASHERS 0
-
-#endif // EXPORT_CODECS
-
-STDMETHODIMP CCodecs::GetNumMethods(UInt32 *numMethods)
-{
- *numMethods = NUM_EXPORT_CODECS
- #ifdef EXTERNAL_CODECS
- + Codecs.Size()
- #endif
- ;
- return S_OK;
-}
-
-STDMETHODIMP CCodecs::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
-{
- #ifdef EXPORT_CODECS
- if (index < g_NumCodecs)
- return GetMethodProperty(index, propID, value);
- #endif
-
- #ifdef EXTERNAL_CODECS
- const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
-
- if (propID == NMethodPropID::kDecoderIsAssigned ||
- propID == NMethodPropID::kEncoderIsAssigned)
- {
- NCOM::CPropVariant prop;
- prop = (bool)((propID == NMethodPropID::kDecoderIsAssigned) ?
- ci.DecoderIsAssigned :
- ci.EncoderIsAssigned);
- prop.Detach(value);
- return S_OK;
- }
- const CCodecLib &lib = Libs[ci.LibIndex];
- return lib.GetMethodProperty(ci.CodecIndex, propID, value);
- #else
- return E_FAIL;
- #endif
-}
-
-STDMETHODIMP CCodecs::CreateDecoder(UInt32 index, const GUID *iid, void **coder)
-{
- #ifdef EXPORT_CODECS
- if (index < g_NumCodecs)
- return CreateDecoder(index, iid, coder);
- #endif
-
- #ifdef EXTERNAL_CODECS
- const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
- if (ci.DecoderIsAssigned)
- {
- const CCodecLib &lib = Libs[ci.LibIndex];
- if (lib.CreateDecoder)
- return lib.CreateDecoder(ci.CodecIndex, iid, (void **)coder);
- if (lib.CreateObject)
- return lib.CreateObject(&ci.Decoder, iid, (void **)coder);
- }
- return S_OK;
- #else
- return E_FAIL;
- #endif
-}
-
-STDMETHODIMP CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder)
-{
- #ifdef EXPORT_CODECS
- if (index < g_NumCodecs)
- return CreateEncoder(index, iid, coder);
- #endif
-
- #ifdef EXTERNAL_CODECS
- const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
- if (ci.EncoderIsAssigned)
- {
- const CCodecLib &lib = Libs[ci.LibIndex];
- if (lib.CreateEncoder)
- return lib.CreateEncoder(ci.CodecIndex, iid, (void **)coder);
- if (lib.CreateObject)
- return lib.CreateObject(&ci.Encoder, iid, (void **)coder);
- }
- return S_OK;
- #else
- return E_FAIL;
- #endif
-}
-
-
-STDMETHODIMP_(UInt32) CCodecs::GetNumHashers()
-{
- return NUM_EXPORT_HASHERS
- #ifdef EXTERNAL_CODECS
- + Hashers.Size()
- #endif
- ;
-}
-
-STDMETHODIMP CCodecs::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value)
-{
- #ifdef EXPORT_CODECS
- if (index < g_NumHashers)
- return ::GetHasherProp(index, propID, value);
- #endif
-
- #ifdef EXTERNAL_CODECS
- const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
- return Libs[ci.LibIndex].ComHashers->GetHasherProp(ci.HasherIndex, propID, value);
- #else
- return E_FAIL;
- #endif
-}
-
-STDMETHODIMP CCodecs::CreateHasher(UInt32 index, IHasher **hasher)
-{
- #ifdef EXPORT_CODECS
- if (index < g_NumHashers)
- return CreateHasher(index, hasher);
- #endif
- #ifdef EXTERNAL_CODECS
- const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
- return Libs[ci.LibIndex].ComHashers->CreateHasher(ci.HasherIndex, hasher);
- #else
- return E_FAIL;
- #endif
-}
-
-int CCodecs::GetCodec_LibIndex(UInt32 index) const
-{
- #ifdef EXPORT_CODECS
- if (index < g_NumCodecs)
- return -1;
- #endif
-
- #ifdef EXTERNAL_CODECS
- const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
- return ci.LibIndex;
- #else
- return -1;
- #endif
-}
-
-int CCodecs::GetHasherLibIndex(UInt32 index)
-{
- #ifdef EXPORT_CODECS
- if (index < g_NumHashers)
- return -1;
- #endif
-
- #ifdef EXTERNAL_CODECS
- const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
- return ci.LibIndex;
- #else
- return -1;
- #endif
-}
-
-bool CCodecs::GetCodec_DecoderIsAssigned(UInt32 index) const
-{
- #ifdef EXPORT_CODECS
- if (index < g_NumCodecs)
- {
- NCOM::CPropVariant prop;
- if (GetProperty(index, NMethodPropID::kDecoderIsAssigned, &prop) == S_OK)
- {
- if (prop.vt == VT_BOOL)
- return VARIANT_BOOLToBool(prop.boolVal);
- }
- return false;
- }
- #endif
-
- #ifdef EXTERNAL_CODECS
- return Codecs[index - NUM_EXPORT_CODECS].DecoderIsAssigned;
- #else
- return false;
- #endif
-}
-
-bool CCodecs::GetCodec_EncoderIsAssigned(UInt32 index) const
-{
- #ifdef EXPORT_CODECS
- if (index < g_NumCodecs)
- {
- NCOM::CPropVariant prop;
- if (GetProperty(index, NMethodPropID::kEncoderIsAssigned, &prop) == S_OK)
- {
- if (prop.vt == VT_BOOL)
- return VARIANT_BOOLToBool(prop.boolVal);
- }
- return false;
- }
- #endif
-
- #ifdef EXTERNAL_CODECS
- return Codecs[index - NUM_EXPORT_CODECS].EncoderIsAssigned;
- #else
- return false;
- #endif
-}
-
-UInt32 CCodecs::GetCodec_NumStreams(UInt32 index)
-{
- NCOM::CPropVariant prop;
- RINOK(GetProperty(index, NMethodPropID::kPackStreams, &prop));
- if (prop.vt == VT_UI4)
- return (UInt32)prop.ulVal;
- if (prop.vt == VT_EMPTY)
- return 1;
- return 0;
-}
-
-HRESULT CCodecs::GetCodec_Id(UInt32 index, UInt64 &id)
-{
- NCOM::CPropVariant prop;
- RINOK(GetProperty(index, NMethodPropID::kID, &prop));
- if (prop.vt != VT_UI8)
- return E_INVALIDARG;
- id = prop.uhVal.QuadPart;
- return S_OK;
-}
-
-AString CCodecs::GetCodec_Name(UInt32 index)
-{
- AString s;
- NCOM::CPropVariant prop;
- if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK)
- if (prop.vt == VT_BSTR)
- s.SetFromWStr_if_Ascii(prop.bstrVal);
- return s;
-}
-
-UInt64 CCodecs::GetHasherId(UInt32 index)
-{
- NCOM::CPropVariant prop;
- if (GetHasherProp(index, NMethodPropID::kID, &prop) != S_OK)
- return 0;
- if (prop.vt != VT_UI8)
- return 0;
- return prop.uhVal.QuadPart;
-}
-
-AString CCodecs::GetHasherName(UInt32 index)
-{
- AString s;
- NCOM::CPropVariant prop;
- if (GetHasherProp(index, NMethodPropID::kName, &prop) == S_OK)
- if (prop.vt == VT_BSTR)
- s.SetFromWStr_if_Ascii(prop.bstrVal);
- return s;
-}
-
-UInt32 CCodecs::GetHasherDigestSize(UInt32 index)
-{
- NCOM::CPropVariant prop;
- RINOK(GetHasherProp(index, NMethodPropID::kDigestSize, &prop));
- if (prop.vt != VT_UI4)
- return 0;
- return prop.ulVal;
-}
-
-#endif // EXTERNAL_CODECS
+// LoadCodecs.cpp
+
+/*
+Z7_EXTERNAL_CODECS
+---------------
+ CCodecs::Load() tries to detect the directory with plugins.
+ It stops the checking, if it can find any of the following items:
+ - 7z.dll file
+ - "Formats" subdir
+ - "Codecs" subdir
+ The order of check:
+ 1) directory of client executable
+ 2) WIN32: directory for REGISTRY item [HKEY_*\Software\7-Zip\Path**]
+ The order for HKEY_* : Path** :
+ - HKEY_CURRENT_USER : PathXX
+ - HKEY_LOCAL_MACHINE : PathXX
+ - HKEY_CURRENT_USER : Path
+ - HKEY_LOCAL_MACHINE : Path
+ PathXX is Path32 in 32-bit code
+ PathXX is Path64 in 64-bit code
+
+
+EXPORT_CODECS
+-------------
+ if (Z7_EXTERNAL_CODECS) is defined, then the code exports internal
+ codecs of client from CCodecs object to external plugins.
+ 7-Zip doesn't use that feature. 7-Zip uses the scheme:
+ - client application without internal plugins.
+ - 7z.dll module contains all (or almost all) plugins.
+ 7z.dll can use codecs from another plugins, if required.
+*/
+
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyCom.h"
+#include "../../../Common/StringToInt.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/FileIO.h"
+#include "../../../Windows/PropVariant.h"
+
+#include "LoadCodecs.h"
+
+#include "../../ICoder.h"
+#include "../../Common/RegisterArc.h"
+#include "../../Common/RegisterCodec.h"
+
+#ifdef Z7_EXTERNAL_CODECS
+// #define EXPORT_CODECS
+#endif
+
+#ifdef Z7_EXTERNAL_CODECS
+
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/DLL.h"
+
+#ifdef _WIN32
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/Registry.h"
+#endif
+
+using namespace NWindows;
+using namespace NFile;
+
+
+#define kCodecsFolderName FTEXT("Codecs")
+#define kFormatsFolderName FTEXT("Formats")
+
+
+static CFSTR const kMainDll =
+ #ifdef _WIN32
+ FTEXT("7z.dll");
+ #else
+ FTEXT("7z.so");
+ #endif
+
+
+#ifdef _WIN32
+
+static LPCTSTR const kRegistryPath = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-zip");
+static LPCWSTR const kProgramPathValue = L"Path";
+static LPCWSTR const kProgramPath2Value = L"Path"
+ #ifdef _WIN64
+ L"64";
+ #else
+ L"32";
+ #endif
+
+static bool ReadPathFromRegistry(HKEY baseKey, LPCWSTR value, FString &path)
+{
+ NRegistry::CKey key;
+ if (key.Open(baseKey, kRegistryPath, KEY_READ) == ERROR_SUCCESS)
+ {
+ UString pathU;
+ if (key.QueryValue(value, pathU) == ERROR_SUCCESS)
+ {
+ path = us2fs(pathU);
+ NName::NormalizeDirPathPrefix(path);
+ return NFind::DoesFileExist_Raw(path + kMainDll);
+ }
+ }
+ return false;
+}
+
+#endif // _WIN32
+
+#endif // Z7_EXTERNAL_CODECS
+
+
+static const unsigned kNumArcsMax = 72;
+static unsigned g_NumArcs = 0;
+static const CArcInfo *g_Arcs[kNumArcsMax];
+
+void RegisterArc(const CArcInfo *arcInfo) throw()
+{
+ if (g_NumArcs < kNumArcsMax)
+ {
+ g_Arcs[g_NumArcs] = arcInfo;
+ g_NumArcs++;
+ }
+ // else throw 1;
+}
+
+/*
+static void SplitString(const UString &srcString, UStringVector &destStrings)
+{
+ destStrings.Clear();
+ UString s;
+ unsigned len = srcString.Len();
+ if (len == 0)
+ return;
+ for (unsigned i = 0; i < len; i++)
+ {
+ wchar_t c = srcString[i];
+ if (c == L' ')
+ {
+ if (!s.IsEmpty())
+ {
+ destStrings.Add(s);
+ s.Empty();
+ }
+ }
+ else
+ s += c;
+ }
+ if (!s.IsEmpty())
+ destStrings.Add(s);
+}
+*/
+
+int CArcInfoEx::FindExtension(const UString &ext) const
+{
+ FOR_VECTOR (i, Exts)
+ if (ext.IsEqualTo_NoCase(Exts[i].Ext))
+ return (int)i;
+ return -1;
+}
+
+void CArcInfoEx::AddExts(const UString &ext, const UString &addExt)
+{
+ UStringVector exts, addExts;
+ SplitString(ext, exts);
+ SplitString(addExt, addExts);
+ FOR_VECTOR (i, exts)
+ {
+ CArcExtInfo extInfo;
+ extInfo.Ext = exts[i];
+ if (i < addExts.Size())
+ {
+ extInfo.AddExt = addExts[i];
+ if (extInfo.AddExt == L"*")
+ extInfo.AddExt.Empty();
+ }
+ Exts.Add(extInfo);
+ }
+}
+
+#ifndef Z7_SFX
+
+static bool ParseSignatures(const Byte *data, unsigned size, CObjectVector<CByteBuffer> &signatures)
+{
+ signatures.Clear();
+ while (size != 0)
+ {
+ const unsigned len = *data++;
+ size--;
+ if (len > size)
+ return false;
+ signatures.AddNew().CopyFrom(data, len);
+ data += len;
+ size -= len;
+ }
+ return true;
+}
+
+#endif // Z7_SFX
+
+// #include <stdio.h>
+
+#ifdef Z7_EXTERNAL_CODECS
+
+static FString GetBaseFolderPrefixFromRegistry()
+{
+ FString moduleFolderPrefix = NDLL::GetModuleDirPrefix();
+
+ #ifdef _WIN32
+ if ( !NFind::DoesFileOrDirExist(moduleFolderPrefix + kMainDll)
+ && !NFind::DoesFileOrDirExist(moduleFolderPrefix + kCodecsFolderName)
+ && !NFind::DoesFileOrDirExist(moduleFolderPrefix + kFormatsFolderName))
+ {
+ FString path;
+ if (ReadPathFromRegistry(HKEY_CURRENT_USER, kProgramPath2Value, path)) return path;
+ if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPath2Value, path)) return path;
+ if (ReadPathFromRegistry(HKEY_CURRENT_USER, kProgramPathValue, path)) return path;
+ if (ReadPathFromRegistry(HKEY_LOCAL_MACHINE, kProgramPathValue, path)) return path;
+ }
+ #endif
+
+ // printf("\nmoduleFolderPrefix = %s\n", (const char *)GetAnsiString(moduleFolderPrefix));
+ return moduleFolderPrefix;
+}
+
+
+static HRESULT GetCoderClass(Func_GetMethodProperty getMethodProperty, UInt32 index,
+ PROPID propId, CLSID &clsId, bool &isAssigned)
+{
+ NCOM::CPropVariant prop;
+ isAssigned = false;
+ RINOK(getMethodProperty(index, propId, &prop))
+ if (prop.vt == VT_BSTR)
+ {
+ if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID))
+ return E_FAIL;
+ isAssigned = true;
+ clsId = *(const GUID *)(const void *)prop.bstrVal;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+
+static HRESULT GetMethodBoolProp(Func_GetMethodProperty getMethodProperty, UInt32 index,
+ PROPID propId, bool &resVal, bool &isAssigned)
+{
+ NCOM::CPropVariant prop;
+ resVal = false;
+ isAssigned = false;
+ RINOK(getMethodProperty(index, propId, &prop))
+ if (prop.vt == VT_BOOL)
+ {
+ isAssigned = true;
+ resVal = VARIANT_BOOLToBool(prop.boolVal);
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+#if defined(__clang__)
+#pragma GCC diagnostic ignored "-Wc++98-compat-pedantic"
+#endif
+
+#define MY_GET_FUNC(dest, type, lib, func) \
+ dest = Z7_GET_PROC_ADDRESS(type, lib.Get_HMODULE(), func);
+// #define MY_GET_FUNC(dest, type, func) dest = (type)(func);
+
+#define MY_GET_FUNC_LOC(dest, type, lib, func) \
+ type dest; MY_GET_FUNC(dest, type, lib, func)
+
+HRESULT CCodecs::LoadCodecs()
+{
+ CCodecLib &lib = Libs.Back();
+
+ MY_GET_FUNC (lib.CreateDecoder, Func_CreateDecoder, lib.Lib, "CreateDecoder")
+ MY_GET_FUNC (lib.CreateEncoder, Func_CreateEncoder, lib.Lib, "CreateEncoder")
+ MY_GET_FUNC (lib.GetMethodProperty, Func_GetMethodProperty, lib.Lib, "GetMethodProperty")
+
+ if (lib.GetMethodProperty)
+ {
+ UInt32 numMethods = 1;
+ MY_GET_FUNC_LOC (getNumberOfMethods, Func_GetNumberOfMethods, lib.Lib, "GetNumberOfMethods")
+ if (getNumberOfMethods)
+ {
+ RINOK(getNumberOfMethods(&numMethods))
+ }
+ for (UInt32 i = 0; i < numMethods; i++)
+ {
+ CDllCodecInfo info;
+ info.LibIndex = Libs.Size() - 1;
+ info.CodecIndex = i;
+ RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kEncoder, info.Encoder, info.EncoderIsAssigned))
+ RINOK(GetCoderClass(lib.GetMethodProperty, i, NMethodPropID::kDecoder, info.Decoder, info.DecoderIsAssigned))
+ RINOK(GetMethodBoolProp(lib.GetMethodProperty, i, NMethodPropID::kIsFilter, info.IsFilter, info.IsFilter_Assigned))
+ Codecs.Add(info);
+ }
+ }
+
+ MY_GET_FUNC_LOC (getHashers, Func_GetHashers, lib.Lib, "GetHashers")
+ if (getHashers)
+ {
+ RINOK(getHashers(&lib.ComHashers))
+ if (lib.ComHashers)
+ {
+ UInt32 numMethods = lib.ComHashers->GetNumHashers();
+ for (UInt32 i = 0; i < numMethods; i++)
+ {
+ CDllHasherInfo info;
+ info.LibIndex = Libs.Size() - 1;
+ info.HasherIndex = i;
+ Hashers.Add(info);
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+static HRESULT GetProp(
+ Func_GetHandlerProperty getProp,
+ Func_GetHandlerProperty2 getProp2,
+ UInt32 index, PROPID propID, NCOM::CPropVariant &prop)
+{
+ if (getProp2)
+ return getProp2(index, propID, &prop);
+ return getProp(propID, &prop);
+}
+
+static HRESULT GetProp_Bool(
+ Func_GetHandlerProperty getProp,
+ Func_GetHandlerProperty2 getProp2,
+ UInt32 index, PROPID propID, bool &res)
+{
+ res = false;
+ NCOM::CPropVariant prop;
+ RINOK(GetProp(getProp, getProp2, index, propID, prop))
+ if (prop.vt == VT_BOOL)
+ res = VARIANT_BOOLToBool(prop.boolVal);
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+static HRESULT GetProp_UInt32(
+ Func_GetHandlerProperty getProp,
+ Func_GetHandlerProperty2 getProp2,
+ UInt32 index, PROPID propID, UInt32 &res, bool &defined)
+{
+ res = 0;
+ defined = false;
+ NCOM::CPropVariant prop;
+ RINOK(GetProp(getProp, getProp2, index, propID, prop))
+ if (prop.vt == VT_UI4)
+ {
+ res = prop.ulVal;
+ defined = true;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+static HRESULT GetProp_String(
+ Func_GetHandlerProperty getProp,
+ Func_GetHandlerProperty2 getProp2,
+ UInt32 index, PROPID propID, UString &res)
+{
+ res.Empty();
+ NCOM::CPropVariant prop;
+ RINOK(GetProp(getProp, getProp2, index, propID, prop))
+ if (prop.vt == VT_BSTR)
+ res.SetFromBstr(prop.bstrVal);
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+static HRESULT GetProp_RawData(
+ Func_GetHandlerProperty getProp,
+ Func_GetHandlerProperty2 getProp2,
+ UInt32 index, PROPID propID, CByteBuffer &bb)
+{
+ bb.Free();
+ NCOM::CPropVariant prop;
+ RINOK(GetProp(getProp, getProp2, index, propID, prop))
+ if (prop.vt == VT_BSTR)
+ {
+ UINT len = ::SysStringByteLen(prop.bstrVal);
+ bb.CopyFrom((const Byte *)prop.bstrVal, len);
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+static const UInt32 kArcFlagsPars[] =
+{
+ NArchive::NHandlerPropID::kKeepName, NArcInfoFlags::kKeepName,
+ NArchive::NHandlerPropID::kAltStreams, NArcInfoFlags::kAltStreams,
+ NArchive::NHandlerPropID::kNtSecure, NArcInfoFlags::kNtSecure
+};
+
+HRESULT CCodecs::LoadFormats()
+{
+ const NDLL::CLibrary &lib = Libs.Back().Lib;
+
+ Func_GetHandlerProperty getProp = NULL;
+ MY_GET_FUNC_LOC (getProp2, Func_GetHandlerProperty2, lib, "GetHandlerProperty2")
+ MY_GET_FUNC_LOC (getIsArc, Func_GetIsArc, lib, "GetIsArc")
+
+ UInt32 numFormats = 1;
+
+ if (getProp2)
+ {
+ MY_GET_FUNC_LOC (getNumberOfFormats, Func_GetNumberOfFormats, lib, "GetNumberOfFormats")
+ if (getNumberOfFormats)
+ {
+ RINOK(getNumberOfFormats(&numFormats))
+ }
+ }
+ else
+ {
+ MY_GET_FUNC (getProp, Func_GetHandlerProperty, lib, "GetHandlerProperty")
+ if (!getProp)
+ return S_OK;
+ }
+
+ for (UInt32 i = 0; i < numFormats; i++)
+ {
+ CArcInfoEx item;
+ item.LibIndex = (int)(Libs.Size() - 1);
+ item.FormatIndex = i;
+
+ RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kName, item.Name))
+
+ {
+ NCOM::CPropVariant prop;
+ if (GetProp(getProp, getProp2, i, NArchive::NHandlerPropID::kClassID, prop) != S_OK)
+ continue;
+ if (prop.vt != VT_BSTR)
+ continue;
+ if (::SysStringByteLen(prop.bstrVal) != sizeof(GUID))
+ return E_FAIL;
+ item.ClassID = *(const GUID *)(const void *)prop.bstrVal;
+ prop.Clear();
+ }
+
+ UString ext, addExt;
+ RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kExtension, ext))
+ RINOK(GetProp_String(getProp, getProp2, i, NArchive::NHandlerPropID::kAddExtension, addExt))
+ item.AddExts(ext, addExt);
+
+ GetProp_Bool(getProp, getProp2, i, NArchive::NHandlerPropID::kUpdate, item.UpdateEnabled);
+ bool flags_Defined = false;
+ RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kFlags, item.Flags, flags_Defined))
+ item.NewInterface = flags_Defined;
+ if (!flags_Defined) // && item.UpdateEnabled
+ {
+ // support for DLL version before 9.31:
+ for (unsigned j = 0; j < Z7_ARRAY_SIZE(kArcFlagsPars); j += 2)
+ {
+ bool val = false;
+ GetProp_Bool(getProp, getProp2, i, kArcFlagsPars[j], val);
+ if (val)
+ item.Flags |= kArcFlagsPars[j + 1];
+ }
+ }
+
+ {
+ bool defined = false;
+ RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kTimeFlags, item.TimeFlags, defined))
+ }
+
+ CByteBuffer sig;
+ RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kSignature, sig))
+ if (sig.Size() != 0)
+ item.Signatures.Add(sig);
+ else
+ {
+ RINOK(GetProp_RawData(getProp, getProp2, i, NArchive::NHandlerPropID::kMultiSignature, sig))
+ ParseSignatures(sig, (unsigned)sig.Size(), item.Signatures);
+ }
+
+ bool signatureOffset_Defined;
+ RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kSignatureOffset, item.SignatureOffset, signatureOffset_Defined))
+
+ // bool version_Defined;
+ // RINOK(GetProp_UInt32(getProp, getProp2, i, NArchive::NHandlerPropID::kVersion, item.Version, version_Defined));
+
+ if (getIsArc)
+ getIsArc(i, &item.IsArcFunc);
+
+ Formats.Add(item);
+ }
+ return S_OK;
+}
+
+#ifdef Z7_LARGE_PAGES
+extern "C"
+{
+ extern SIZE_T g_LargePageSize;
+}
+#endif
+
+
+void CCodecs::AddLastError(const FString &path)
+{
+ const HRESULT res = GetLastError_noZero_HRESULT();
+ CCodecError &error = Errors.AddNew();
+ error.Path = path;
+ error.ErrorCode = res;
+}
+
+
+static bool IsSupportedDll(CCodecLib &lib)
+{
+ MY_GET_FUNC_LOC (
+ f_GetModuleProp,
+ Func_GetModuleProp, lib.Lib,
+ "GetModuleProp")
+ /* p7zip and 7-Zip before v23 used virtual destructor in IUnknown,
+ if _WIN32 is not defined */
+ UInt32 flags =
+ #ifdef _WIN32
+ NModuleInterfaceType::k_IUnknown_VirtDestructor_No;
+ #else
+ NModuleInterfaceType::k_IUnknown_VirtDestructor_Yes;
+ #endif
+ if (f_GetModuleProp)
+ {
+ {
+ NCOM::CPropVariant prop;
+ if (f_GetModuleProp(NModulePropID::kInterfaceType, &prop) == S_OK)
+ {
+ if (prop.vt == VT_UI4)
+ flags = prop.ulVal;
+ else if (prop.vt != VT_EMPTY)
+ return false;
+ }
+ }
+ {
+ NCOM::CPropVariant prop;
+ if (f_GetModuleProp(NModulePropID::kVersion, &prop) == S_OK)
+ {
+ if (prop.vt == VT_UI4)
+ lib.Version = prop.ulVal;
+ }
+ }
+ }
+ if (
+ flags
+ // (flags & NModuleFlags::kMask)
+ != NModuleInterfaceType::k_IUnknown_VirtDestructor_ThisModule)
+ return false;
+ return true;
+}
+
+
+HRESULT CCodecs::LoadDll(const FString &dllPath, bool needCheckDll, bool *loadedOK)
+{
+ if (loadedOK)
+ *loadedOK = false;
+
+ // needCheckDll = 1;
+
+ #ifdef _WIN32
+ if (needCheckDll)
+ {
+ NDLL::CLibrary lib;
+ if (!lib.LoadEx(dllPath, LOAD_LIBRARY_AS_DATAFILE))
+ {
+ /* if is not win32
+ // %1 is not a valid Win32 application.
+ // #define ERROR_BAD_EXE_FORMAT 193L
+ */
+ // return GetLastError_noZero_HRESULT();
+ const DWORD lastError = GetLastError();
+ if (lastError != ERROR_BAD_EXE_FORMAT)
+ {
+ CCodecError &error = Errors.AddNew();
+ error.Path = dllPath;
+ error.Message = "cannot load file as datafile library";
+ error.ErrorCode = HRESULT_FROM_WIN32(lastError);
+ }
+ return S_OK;
+ }
+ }
+ #else
+ UNUSED_VAR(needCheckDll)
+ #endif
+
+ Libs.AddNew();
+ CCodecLib &lib = Libs.Back();
+ lib.Path = dllPath;
+ bool used = false;
+ // HRESULT res = S_OK;
+
+ if (lib.Lib.Load(dllPath))
+ {
+ if (!IsSupportedDll(lib))
+ {
+ CCodecError &error = Errors.AddNew();
+ error.Path = dllPath;
+ error.Message = "the module is not compatible with program";
+ }
+ else
+ {
+ if (loadedOK)
+ *loadedOK = true;
+ /*
+ #ifdef NEW_FOLDER_INTERFACE
+ lib.LoadIcons();
+ #endif
+ */
+
+ /*
+ {
+ MY_GET_FUNC_LOC (_libStartup, Func_libStartup, lib.Lib, "LibStartup")
+ if (_libStartup)
+ {
+ HRESULT res = _libStartup();
+ if (res != 0)
+ {
+ CCodecError &error = Errors.AddNew();
+ error.Path = dllPath;
+ error.ErrorCode = res;
+ }
+ }
+ }
+ */
+
+ #ifdef Z7_LARGE_PAGES
+ if (g_LargePageSize != 0)
+ {
+ MY_GET_FUNC_LOC (setLargePageMode, Func_SetLargePageMode, lib.Lib, "SetLargePageMode")
+ if (setLargePageMode)
+ setLargePageMode();
+ }
+ #endif
+
+ if (CaseSensitive_Change)
+ {
+ MY_GET_FUNC_LOC (setCaseSensitive, Func_SetCaseSensitive, lib.Lib, "SetCaseSensitive")
+ if (setCaseSensitive)
+ setCaseSensitive(CaseSensitive ? 1 : 0);
+ }
+
+ /*
+ {
+ MY_GET_FUNC_LOC (setClientVersion, Func_SetClientVersion, lib.Lib, "SetClientVersion")
+ if (setClientVersion)
+ {
+ // const UInt32 kVersion = (MY_VER_MAJOR << 16) | MY_VER_MINOR;
+ setClientVersion(g_ClientVersion);
+ }
+ }
+ */
+
+
+ MY_GET_FUNC (lib.CreateObject, Func_CreateObject, lib.Lib, "CreateObject")
+ {
+ unsigned startSize = Codecs.Size() + Hashers.Size();
+ HRESULT res = LoadCodecs();
+ if (startSize != Codecs.Size() + Hashers.Size())
+ used = true;
+ if (res == S_OK && lib.CreateObject)
+ {
+ startSize = Formats.Size();
+ res = LoadFormats();
+ if (startSize != Formats.Size())
+ used = true;
+ }
+ if (res != S_OK)
+ {
+ CCodecError &error = Errors.AddNew();
+ error.Path = dllPath;
+ error.ErrorCode = res;
+ }
+ }
+ // plugins can use non-7-zip dlls, so we silently ignore non7zip DLLs
+ /*
+ if (!used)
+ {
+ CCodecError &error = Errors.AddNew();
+ error.Path = dllPath;
+ error.Message = "no 7-Zip code";
+ }
+ */
+ }
+ }
+ else
+ {
+ AddLastError(dllPath);
+ }
+
+ if (!used)
+ Libs.DeleteBack();
+
+ return S_OK;
+}
+
+HRESULT CCodecs::LoadDllsFromFolder(const FString &folderPath)
+{
+ if (!NFile::NFind::DoesDirExist_FollowLink(folderPath))
+ // if (!NFile::NFind::DoesDirExist(folderPath))
+ {
+ // AddLastError(folderPath);
+ return S_OK;
+ }
+
+ FString folderPrefix = folderPath;
+ folderPrefix.Add_PathSepar();
+
+ NFile::NFind::CEnumerator enumerator;
+ enumerator.SetDirPrefix(folderPrefix);
+ NFile::NFind::CDirEntry fi;
+ for (;;)
+ {
+ bool found;
+ if (!enumerator.Next(fi, found))
+ {
+ // it can be wrong Symbolic link to folder here
+ AddLastError(folderPath);
+ break;
+ // return GetLastError_noZero_HRESULT();
+ }
+ if (!found)
+ break;
+ #ifdef _WIN32
+ if (fi.IsDir())
+ continue;
+ #else
+ if (enumerator.DirEntry_IsDir(fi, true)) // followLink
+ continue;
+ #endif
+
+ RINOK(LoadDll(folderPrefix + fi.Name, true))
+ }
+ return S_OK;
+}
+
+void CCodecs::CloseLibs()
+{
+ // OutputDebugStringA("~CloseLibs start");
+ /*
+ WIN32: FreeLibrary() (CLibrary::Free()) function doesn't work as expected,
+ if it's called from another FreeLibrary() call.
+ So we need to call FreeLibrary() before global destructors.
+
+ Also we free global links from DLLs to object of this module before CLibrary::Free() call.
+ */
+
+ FOR_VECTOR(i, Libs)
+ {
+ const CCodecLib &lib = Libs[i];
+ if (lib.SetCodecs)
+ lib.SetCodecs(NULL);
+ }
+
+ // OutputDebugStringA("~CloseLibs after SetCodecs");
+ Libs.Clear();
+ // OutputDebugStringA("~CloseLibs end");
+}
+
+#endif // Z7_EXTERNAL_CODECS
+
+
+HRESULT CCodecs::Load()
+{
+ /*
+ #ifdef NEW_FOLDER_INTERFACE
+ InternalIcons.LoadIcons(g_hInstance);
+ #endif
+ */
+
+ Formats.Clear();
+
+ #ifdef Z7_EXTERNAL_CODECS
+ Errors.Clear();
+ MainDll_ErrorPath.Empty();
+ Codecs.Clear();
+ Hashers.Clear();
+ #endif
+
+ for (UInt32 i = 0; i < g_NumArcs; i++)
+ {
+ const CArcInfo &arc = *g_Arcs[i];
+ CArcInfoEx item;
+
+ item.Name = arc.Name;
+ item.CreateInArchive = arc.CreateInArchive;
+ item.IsArcFunc = arc.IsArc;
+ item.Flags = arc.Flags;
+
+ {
+ UString e, ae;
+ if (arc.Ext)
+ e = arc.Ext;
+ if (arc.AddExt)
+ ae = arc.AddExt;
+ item.AddExts(e, ae);
+ }
+
+ #ifndef Z7_SFX
+
+ item.CreateOutArchive = arc.CreateOutArchive;
+ item.UpdateEnabled = (arc.CreateOutArchive != NULL);
+ item.SignatureOffset = arc.SignatureOffset;
+ // item.Version = MY_VER_MIX;
+ item.NewInterface = true;
+
+ if (arc.IsMultiSignature())
+ ParseSignatures(arc.Signature, arc.SignatureSize, item.Signatures);
+ else
+ {
+ if (arc.SignatureSize != 0) // 21.04
+ item.Signatures.AddNew().CopyFrom(arc.Signature, arc.SignatureSize);
+ }
+
+ #endif
+
+ Formats.Add(item);
+ }
+
+ // printf("\nLoad codecs \n");
+
+ #ifdef Z7_EXTERNAL_CODECS
+ const FString baseFolder = GetBaseFolderPrefixFromRegistry();
+ {
+ bool loadedOK;
+ RINOK(LoadDll(baseFolder + kMainDll, false, &loadedOK))
+ if (!loadedOK)
+ MainDll_ErrorPath = kMainDll;
+ }
+ RINOK(LoadDllsFromFolder(baseFolder + kCodecsFolderName))
+ RINOK(LoadDllsFromFolder(baseFolder + kFormatsFolderName))
+
+ NeedSetLibCodecs = true;
+
+ if (Libs.Size() == 0)
+ NeedSetLibCodecs = false;
+ else if (Libs.Size() == 1)
+ {
+ // we don't need to set ISetCompressCodecsInfo, if all arcs and codecs are in one external module.
+ #ifndef EXPORT_CODECS
+ if (g_NumArcs == 0)
+ NeedSetLibCodecs = false;
+ #endif
+ }
+
+ if (NeedSetLibCodecs)
+ {
+ /* 15.00: now we call global function in DLL: SetCompressCodecsInfo(c)
+ old versions called only ISetCompressCodecsInfo::SetCompressCodecsInfo(c) for each archive handler */
+
+ FOR_VECTOR(i, Libs)
+ {
+ CCodecLib &lib = Libs[i];
+ MY_GET_FUNC (lib.SetCodecs, Func_SetCodecs, lib.Lib, "SetCodecs")
+ if (lib.SetCodecs)
+ {
+ RINOK(lib.SetCodecs(this))
+ }
+ }
+ }
+
+ #endif
+
+ // we sort Formats to get fixed order of Formats after compilation.
+ Formats.Sort();
+ return S_OK;
+}
+
+#ifndef Z7_SFX
+
+int CCodecs::FindFormatForArchiveName(const UString &arcPath) const
+{
+ int dotPos = arcPath.ReverseFind_Dot();
+ if (dotPos <= arcPath.ReverseFind_PathSepar())
+ return -1;
+ const UString ext = arcPath.Ptr((unsigned)(dotPos + 1));
+ if (ext.IsEmpty())
+ return -1;
+ if (ext.IsEqualTo_Ascii_NoCase("exe"))
+ return -1;
+ FOR_VECTOR (i, Formats)
+ {
+ const CArcInfoEx &arc = Formats[i];
+ /*
+ if (!arc.UpdateEnabled)
+ continue;
+ */
+ if (arc.FindExtension(ext) >= 0)
+ return (int)i;
+ }
+ return -1;
+}
+
+int CCodecs::FindFormatForExtension(const UString &ext) const
+{
+ if (ext.IsEmpty())
+ return -1;
+ FOR_VECTOR (i, Formats)
+ if (Formats[i].FindExtension(ext) >= 0)
+ return (int)i;
+ return -1;
+}
+
+int CCodecs::FindFormatForArchiveType(const UString &arcType) const
+{
+ FOR_VECTOR (i, Formats)
+ if (Formats[i].Name.IsEqualTo_NoCase(arcType))
+ return (int)i;
+ return -1;
+}
+
+bool CCodecs::FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const
+{
+ formatIndices.Clear();
+ for (unsigned pos = 0; pos < arcType.Len();)
+ {
+ int pos2 = arcType.Find(L'.', pos);
+ if (pos2 < 0)
+ pos2 = (int)arcType.Len();
+ const UString name = arcType.Mid(pos, (unsigned)pos2 - pos);
+ if (name.IsEmpty())
+ return false;
+ int index = FindFormatForArchiveType(name);
+ if (index < 0 && name != L"*")
+ {
+ formatIndices.Clear();
+ return false;
+ }
+ formatIndices.Add(index);
+ pos = (unsigned)pos2 + 1;
+ }
+ return true;
+}
+
+#endif // Z7_SFX
+
+
+#ifdef Z7_EXTERNAL_CODECS
+
+// #define EXPORT_CODECS
+
+#ifdef EXPORT_CODECS
+
+extern unsigned g_NumCodecs;
+STDAPI CreateDecoder(UInt32 index, const GUID *iid, void **outObject);
+STDAPI CreateEncoder(UInt32 index, const GUID *iid, void **outObject);
+STDAPI GetMethodProperty(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
+#define NUM_EXPORT_CODECS g_NumCodecs
+
+extern unsigned g_NumHashers;
+STDAPI CreateHasher(UInt32 index, IHasher **hasher);
+STDAPI GetHasherProp(UInt32 codecIndex, PROPID propID, PROPVARIANT *value);
+#define NUM_EXPORT_HASHERS g_NumHashers
+
+#else // EXPORT_CODECS
+
+#define NUM_EXPORT_CODECS 0
+#define NUM_EXPORT_HASHERS 0
+
+#endif // EXPORT_CODECS
+
+Z7_COM7F_IMF(CCodecs::GetNumMethods(UInt32 *numMethods))
+{
+ *numMethods = NUM_EXPORT_CODECS
+ #ifdef Z7_EXTERNAL_CODECS
+ + Codecs.Size()
+ #endif
+ ;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CCodecs::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumCodecs)
+ return GetMethodProperty(index, propID, value);
+ #endif
+
+ #ifdef Z7_EXTERNAL_CODECS
+ const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
+
+ if (propID == NMethodPropID::kDecoderIsAssigned ||
+ propID == NMethodPropID::kEncoderIsAssigned)
+ {
+ NCOM::CPropVariant prop;
+ prop = (bool)((propID == NMethodPropID::kDecoderIsAssigned) ?
+ ci.DecoderIsAssigned :
+ ci.EncoderIsAssigned);
+ prop.Detach(value);
+ return S_OK;
+ }
+
+ if (propID == NMethodPropID::kIsFilter && ci.IsFilter_Assigned)
+ {
+ NCOM::CPropVariant prop;
+ prop = (bool)ci.IsFilter;
+ prop.Detach(value);
+ return S_OK;
+ }
+
+ const CCodecLib &lib = Libs[ci.LibIndex];
+ return lib.GetMethodProperty(ci.CodecIndex, propID, value);
+ #else
+ return E_FAIL;
+ #endif
+}
+
+Z7_COM7F_IMF(CCodecs::CreateDecoder(UInt32 index, const GUID *iid, void **coder))
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumCodecs)
+ return CreateDecoder(index, iid, coder);
+ #endif
+
+ #ifdef Z7_EXTERNAL_CODECS
+ const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
+ if (ci.DecoderIsAssigned)
+ {
+ const CCodecLib &lib = Libs[ci.LibIndex];
+ if (lib.CreateDecoder)
+ return lib.CreateDecoder(ci.CodecIndex, iid, (void **)coder);
+ if (lib.CreateObject)
+ return lib.CreateObject(&ci.Decoder, iid, (void **)coder);
+ }
+ return S_OK;
+ #else
+ return E_FAIL;
+ #endif
+}
+
+Z7_COM7F_IMF(CCodecs::CreateEncoder(UInt32 index, const GUID *iid, void **coder))
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumCodecs)
+ return CreateEncoder(index, iid, coder);
+ #endif
+
+ #ifdef Z7_EXTERNAL_CODECS
+ const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
+ if (ci.EncoderIsAssigned)
+ {
+ const CCodecLib &lib = Libs[ci.LibIndex];
+ if (lib.CreateEncoder)
+ return lib.CreateEncoder(ci.CodecIndex, iid, (void **)coder);
+ if (lib.CreateObject)
+ return lib.CreateObject(&ci.Encoder, iid, (void **)coder);
+ }
+ return S_OK;
+ #else
+ return E_FAIL;
+ #endif
+}
+
+
+Z7_COM7F_IMF2(UInt32, CCodecs::GetNumHashers())
+{
+ return NUM_EXPORT_HASHERS
+ #ifdef Z7_EXTERNAL_CODECS
+ + Hashers.Size()
+ #endif
+ ;
+}
+
+Z7_COM7F_IMF(CCodecs::GetHasherProp(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumHashers)
+ return ::GetHasherProp(index, propID, value);
+ #endif
+
+ #ifdef Z7_EXTERNAL_CODECS
+ const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
+ return Libs[ci.LibIndex].ComHashers->GetHasherProp(ci.HasherIndex, propID, value);
+ #else
+ return E_FAIL;
+ #endif
+}
+
+Z7_COM7F_IMF(CCodecs::CreateHasher(UInt32 index, IHasher **hasher))
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumHashers)
+ return CreateHasher(index, hasher);
+ #endif
+ #ifdef Z7_EXTERNAL_CODECS
+ const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
+ return Libs[ci.LibIndex].ComHashers->CreateHasher(ci.HasherIndex, hasher);
+ #else
+ return E_FAIL;
+ #endif
+}
+
+int CCodecs::GetCodec_LibIndex(UInt32 index) const
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumCodecs)
+ return -1;
+ #endif
+
+ #ifdef Z7_EXTERNAL_CODECS
+ const CDllCodecInfo &ci = Codecs[index - NUM_EXPORT_CODECS];
+ return (int)ci.LibIndex;
+ #else
+ return -1;
+ #endif
+}
+
+int CCodecs::GetHasherLibIndex(UInt32 index)
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumHashers)
+ return -1;
+ #endif
+
+ #ifdef Z7_EXTERNAL_CODECS
+ const CDllHasherInfo &ci = Hashers[index - NUM_EXPORT_HASHERS];
+ return (int)ci.LibIndex;
+ #else
+ return -1;
+ #endif
+}
+
+bool CCodecs::GetCodec_DecoderIsAssigned(UInt32 index) const
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumCodecs)
+ {
+ NCOM::CPropVariant prop;
+ if (GetProperty(index, NMethodPropID::kDecoderIsAssigned, &prop) == S_OK)
+ {
+ if (prop.vt == VT_BOOL)
+ return VARIANT_BOOLToBool(prop.boolVal);
+ }
+ return false;
+ }
+ #endif
+
+ #ifdef Z7_EXTERNAL_CODECS
+ return Codecs[index - NUM_EXPORT_CODECS].DecoderIsAssigned;
+ #else
+ return false;
+ #endif
+}
+
+
+bool CCodecs::GetCodec_EncoderIsAssigned(UInt32 index) const
+{
+ #ifdef EXPORT_CODECS
+ if (index < g_NumCodecs)
+ {
+ NCOM::CPropVariant prop;
+ if (GetProperty(index, NMethodPropID::kEncoderIsAssigned, &prop) == S_OK)
+ {
+ if (prop.vt == VT_BOOL)
+ return VARIANT_BOOLToBool(prop.boolVal);
+ }
+ return false;
+ }
+ #endif
+
+ #ifdef Z7_EXTERNAL_CODECS
+ return Codecs[index - NUM_EXPORT_CODECS].EncoderIsAssigned;
+ #else
+ return false;
+ #endif
+}
+
+
+bool CCodecs::GetCodec_IsFilter(UInt32 index, bool &isAssigned) const
+{
+ isAssigned = false;
+ #ifdef EXPORT_CODECS
+ if (index < g_NumCodecs)
+ {
+ NCOM::CPropVariant prop;
+ if (GetProperty(index, NMethodPropID::kIsFilter, &prop) == S_OK)
+ {
+ if (prop.vt == VT_BOOL)
+ {
+ isAssigned = true;
+ return VARIANT_BOOLToBool(prop.boolVal);
+ }
+ }
+ return false;
+ }
+ #endif
+
+ #ifdef Z7_EXTERNAL_CODECS
+ {
+ const CDllCodecInfo &c = Codecs[index - NUM_EXPORT_CODECS];
+ isAssigned = c.IsFilter_Assigned;
+ return c.IsFilter;
+ }
+ #else
+ return false;
+ #endif
+}
+
+
+UInt32 CCodecs::GetCodec_NumStreams(UInt32 index)
+{
+ NCOM::CPropVariant prop;
+ if (GetProperty(index, NMethodPropID::kPackStreams, &prop) != S_OK)
+ return 0;
+ if (prop.vt == VT_UI4)
+ return (UInt32)prop.ulVal;
+ if (prop.vt == VT_EMPTY)
+ return 1;
+ return 0;
+}
+
+HRESULT CCodecs::GetCodec_Id(UInt32 index, UInt64 &id)
+{
+ NCOM::CPropVariant prop;
+ RINOK(GetProperty(index, NMethodPropID::kID, &prop))
+ if (prop.vt != VT_UI8)
+ return E_INVALIDARG;
+ id = prop.uhVal.QuadPart;
+ return S_OK;
+}
+
+AString CCodecs::GetCodec_Name(UInt32 index)
+{
+ AString s;
+ NCOM::CPropVariant prop;
+ if (GetProperty(index, NMethodPropID::kName, &prop) == S_OK)
+ if (prop.vt == VT_BSTR)
+ s.SetFromWStr_if_Ascii(prop.bstrVal);
+ return s;
+}
+
+UInt64 CCodecs::GetHasherId(UInt32 index)
+{
+ NCOM::CPropVariant prop;
+ if (GetHasherProp(index, NMethodPropID::kID, &prop) != S_OK)
+ return 0;
+ if (prop.vt != VT_UI8)
+ return 0;
+ return prop.uhVal.QuadPart;
+}
+
+AString CCodecs::GetHasherName(UInt32 index)
+{
+ AString s;
+ NCOM::CPropVariant prop;
+ if (GetHasherProp(index, NMethodPropID::kName, &prop) == S_OK)
+ if (prop.vt == VT_BSTR)
+ s.SetFromWStr_if_Ascii(prop.bstrVal);
+ return s;
+}
+
+UInt32 CCodecs::GetHasherDigestSize(UInt32 index)
+{
+ NCOM::CPropVariant prop;
+ if (GetHasherProp(index, NMethodPropID::kDigestSize, &prop) != S_OK)
+ return 0;
+ if (prop.vt != VT_UI4)
+ return 0;
+ return prop.ulVal;
+}
+
+void CCodecs::GetCodecsErrorMessage(UString &s)
+{
+ s.Empty();
+ FOR_VECTOR (i, Errors)
+ {
+ const CCodecError &ce = Errors[i];
+ s += "Codec Load Error: ";
+ s += fs2us(ce.Path);
+ if (ce.ErrorCode != 0)
+ {
+ s += " : ";
+ s += NWindows::NError::MyFormatMessage(ce.ErrorCode);
+ }
+ if (!ce.Message.IsEmpty())
+ {
+ s += " : ";
+ s += ce.Message;
+ }
+ s.Add_LF();
+ }
+}
+
+#endif // Z7_EXTERNAL_CODECS
+
+#ifndef Z7_SFX
+
+extern unsigned g_NumCodecs;
+extern const CCodecInfo *g_Codecs[];
+
+void CCodecs::Get_CodecsInfoUser_Vector(CObjectVector<CCodecInfoUser> &v)
+{
+ v.Clear();
+ {
+ for (unsigned i = 0; i < g_NumCodecs; i++)
+ {
+ const CCodecInfo &cod = *g_Codecs[i];
+ CCodecInfoUser &u = v.AddNew();
+ u.EncoderIsAssigned = (cod.CreateEncoder != NULL);
+ u.DecoderIsAssigned = (cod.CreateDecoder != NULL);
+ u.IsFilter_Assigned = true;
+ u.IsFilter = cod.IsFilter;
+ u.NumStreams = cod.NumStreams;
+ u.Name = cod.Name;
+ }
+ }
+
+
+ #ifdef Z7_EXTERNAL_CODECS
+ {
+ UInt32 numMethods;
+ if (GetNumMethods(&numMethods) == S_OK)
+ for (UInt32 j = 0; j < numMethods; j++)
+ {
+ CCodecInfoUser &u = v.AddNew();
+ u.EncoderIsAssigned = GetCodec_EncoderIsAssigned(j);
+ u.DecoderIsAssigned = GetCodec_DecoderIsAssigned(j);
+ u.IsFilter = GetCodec_IsFilter(j, u.IsFilter_Assigned);
+ u.NumStreams = GetCodec_NumStreams(j);
+ u.Name = GetCodec_Name(j);
+ }
+ }
+ #endif
+}
+
+#endif
diff --git a/CPP/7zip/UI/Common/LoadCodecs.h b/CPP/7zip/UI/Common/LoadCodecs.h
index 9ba36d3..a81bb5c 100644
--- a/CPP/7zip/UI/Common/LoadCodecs.h
+++ b/CPP/7zip/UI/Common/LoadCodecs.h
@@ -1,424 +1,482 @@
-// LoadCodecs.h
-
-#ifndef __LOAD_CODECS_H
-#define __LOAD_CODECS_H
-
-/*
-Client application uses LoadCodecs.* to load plugins to
-CCodecs object, that contains 3 lists of plugins:
- 1) Formats - internal and external archive handlers
- 2) Codecs - external codecs
- 3) Hashers - external hashers
-
-EXTERNAL_CODECS
----------------
-
- if EXTERNAL_CODECS is defined, then the code tries to load external
- plugins from DLL files (shared libraries).
-
- There are two types of executables in 7-Zip:
-
- 1) Executable that uses external plugins must be compiled
- with EXTERNAL_CODECS defined:
- - 7z.exe, 7zG.exe, 7zFM.exe
-
- Note: EXTERNAL_CODECS is used also in CPP/7zip/Common/CreateCoder.h
- that code is used in plugin module (7z.dll).
-
- 2) Standalone modules are compiled without EXTERNAL_CODECS:
- - SFX modules: 7z.sfx, 7zCon.sfx
- - standalone versions of console 7-Zip: 7za.exe, 7zr.exe
-
- if EXTERNAL_CODECS is defined, CCodecs class implements interfaces:
- - ICompressCodecsInfo : for Codecs
- - IHashers : for Hashers
-
- The client application can send CCodecs object to each plugin module.
- And plugin module can use ICompressCodecsInfo or IHashers interface to access
- another plugins.
-
- There are 2 ways to send (ICompressCodecsInfo * compressCodecsInfo) to plugin
- 1) for old versions:
- a) request ISetCompressCodecsInfo from created archive handler.
- b) call ISetCompressCodecsInfo::SetCompressCodecsInfo(compressCodecsInfo)
- 2) for new versions:
- a) request "SetCodecs" function from DLL file
- b) call SetCodecs(compressCodecsInfo) function from DLL file
-*/
-
-#include "../../../Common/MyBuffer.h"
-#include "../../../Common/MyCom.h"
-#include "../../../Common/MyString.h"
-#include "../../../Common/ComTry.h"
-
-#ifdef EXTERNAL_CODECS
-#include "../../../Windows/DLL.h"
-#endif
-
-#include "../../ICoder.h"
-
-#include "../../Archive/IArchive.h"
-
-
-#ifdef EXTERNAL_CODECS
-
-struct CDllCodecInfo
-{
- unsigned LibIndex;
- UInt32 CodecIndex;
- bool EncoderIsAssigned;
- bool DecoderIsAssigned;
- CLSID Encoder;
- CLSID Decoder;
-};
-
-struct CDllHasherInfo
-{
- unsigned LibIndex;
- UInt32 HasherIndex;
-};
-
-#endif
-
-struct CArcExtInfo
-{
- UString Ext;
- UString AddExt;
-
- CArcExtInfo() {}
- CArcExtInfo(const UString &ext): Ext(ext) {}
- CArcExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {}
-};
-
-
-struct CArcInfoEx
-{
- UInt32 Flags;
-
- Func_CreateInArchive CreateInArchive;
- Func_IsArc IsArcFunc;
-
- UString Name;
- CObjectVector<CArcExtInfo> Exts;
-
- #ifndef _SFX
- Func_CreateOutArchive CreateOutArchive;
- bool UpdateEnabled;
- bool NewInterface;
- // UInt32 Version;
- UInt32 SignatureOffset;
- CObjectVector<CByteBuffer> Signatures;
- #ifdef NEW_FOLDER_INTERFACE
- UStringVector AssociateExts;
- #endif
- #endif
-
- #ifdef EXTERNAL_CODECS
- int LibIndex;
- UInt32 FormatIndex;
- CLSID ClassID;
- #endif
-
- bool Flags_KeepName() const { return (Flags & NArcInfoFlags::kKeepName) != 0; }
- bool Flags_FindSignature() const { return (Flags & NArcInfoFlags::kFindSignature) != 0; }
-
- bool Flags_AltStreams() const { return (Flags & NArcInfoFlags::kAltStreams) != 0; }
- bool Flags_NtSecure() const { return (Flags & NArcInfoFlags::kNtSecure) != 0; }
- bool Flags_SymLinks() const { return (Flags & NArcInfoFlags::kSymLinks) != 0; }
- bool Flags_HardLinks() const { return (Flags & NArcInfoFlags::kHardLinks) != 0; }
-
- bool Flags_UseGlobalOffset() const { return (Flags & NArcInfoFlags::kUseGlobalOffset) != 0; }
- bool Flags_StartOpen() const { return (Flags & NArcInfoFlags::kStartOpen) != 0; }
- bool Flags_BackwardOpen() const { return (Flags & NArcInfoFlags::kBackwardOpen) != 0; }
- bool Flags_PreArc() const { return (Flags & NArcInfoFlags::kPreArc) != 0; }
- bool Flags_PureStartOpen() const { return (Flags & NArcInfoFlags::kPureStartOpen) != 0; }
-
- UString GetMainExt() const
- {
- if (Exts.IsEmpty())
- return UString();
- return Exts[0].Ext;
- }
- int FindExtension(const UString &ext) const;
-
- /*
- UString GetAllExtensions() const
- {
- UString s;
- for (int i = 0; i < Exts.Size(); i++)
- {
- if (i > 0)
- s += ' ';
- s += Exts[i].Ext;
- }
- return s;
- }
- */
-
- void AddExts(const UString &ext, const UString &addExt);
-
- bool IsSplit() const { return StringsAreEqualNoCase_Ascii(Name, "Split"); }
- // bool IsRar() const { return StringsAreEqualNoCase_Ascii(Name, "Rar"); }
-
- CArcInfoEx():
- Flags(0),
- CreateInArchive(NULL),
- IsArcFunc(NULL)
- #ifndef _SFX
- , CreateOutArchive(NULL)
- , UpdateEnabled(false)
- , NewInterface(false)
- // , Version(0)
- , SignatureOffset(0)
- #endif
- #ifdef EXTERNAL_CODECS
- , LibIndex(-1)
- #endif
- {}
-};
-
-#ifdef NEW_FOLDER_INTERFACE
-
-struct CCodecIcons
-{
- struct CIconPair
- {
- UString Ext;
- int IconIndex;
- };
- CObjectVector<CIconPair> IconPairs;
-
- void LoadIcons(HMODULE m);
- bool FindIconIndex(const UString &ext, int &iconIndex) const;
-};
-
-#endif
-
-#ifdef EXTERNAL_CODECS
-
-struct CCodecLib
- #ifdef NEW_FOLDER_INTERFACE
- : public CCodecIcons
- #endif
-{
- NWindows::NDLL::CLibrary Lib;
- FString Path;
-
- Func_CreateObject CreateObject;
- Func_GetMethodProperty GetMethodProperty;
- Func_CreateDecoder CreateDecoder;
- Func_CreateEncoder CreateEncoder;
- Func_SetCodecs SetCodecs;
-
- CMyComPtr<IHashers> ComHashers;
-
- #ifdef NEW_FOLDER_INTERFACE
- void LoadIcons() { CCodecIcons::LoadIcons((HMODULE)Lib); }
- #endif
-
- CCodecLib():
- CreateObject(NULL),
- GetMethodProperty(NULL),
- CreateDecoder(NULL),
- CreateEncoder(NULL),
- SetCodecs(NULL)
- {}
-};
-
-#endif
-
-
-class CCodecs:
- #ifdef EXTERNAL_CODECS
- public ICompressCodecsInfo,
- public IHashers,
- #else
- public IUnknown,
- #endif
- public CMyUnknownImp
-{
- CLASS_NO_COPY(CCodecs);
-public:
- #ifdef EXTERNAL_CODECS
-
- CObjectVector<CCodecLib> Libs;
- FString MainDll_ErrorPath;
-
- void CloseLibs();
-
- class CReleaser
- {
- CLASS_NO_COPY(CReleaser);
-
- /* CCodecsReleaser object releases CCodecs links.
- 1) CCodecs is COM object that is deleted when all links to that object will be released/
- 2) CCodecs::Libs[i] can hold (ICompressCodecsInfo *) link to CCodecs object itself.
- To break that reference loop, we must close all CCodecs::Libs in CCodecsReleaser desttructor. */
-
- CCodecs *_codecs;
-
- public:
- CReleaser(): _codecs(NULL) {}
- void Set(CCodecs *codecs) { _codecs = codecs; }
- ~CReleaser() { if (_codecs) _codecs->CloseLibs(); }
- };
-
- bool NeedSetLibCodecs; // = false, if we don't need to set codecs for archive handler via ISetCompressCodecsInfo
-
- HRESULT LoadCodecs();
- HRESULT LoadFormats();
- HRESULT LoadDll(const FString &path, bool needCheckDll, bool *loadedOK = NULL);
- HRESULT LoadDllsFromFolder(const FString &folderPrefix);
-
- HRESULT CreateArchiveHandler(const CArcInfoEx &ai, bool outHandler, void **archive) const
- {
- return Libs[ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive);
- }
-
- #endif
-
- #ifdef NEW_FOLDER_INTERFACE
- CCodecIcons InternalIcons;
- #endif
-
- CObjectVector<CArcInfoEx> Formats;
-
- #ifdef EXTERNAL_CODECS
- CRecordVector<CDllCodecInfo> Codecs;
- CRecordVector<CDllHasherInfo> Hashers;
- #endif
-
- bool CaseSensitiveChange;
- bool CaseSensitive;
-
- CCodecs():
- #ifdef EXTERNAL_CODECS
- NeedSetLibCodecs(true),
- #endif
- CaseSensitiveChange(false),
- CaseSensitive(false)
- {}
-
- ~CCodecs()
- {
- // OutputDebugStringA("~CCodecs");
- }
-
- const wchar_t *GetFormatNamePtr(int formatIndex) const
- {
- return formatIndex < 0 ? L"#" : (const wchar_t *)Formats[formatIndex].Name;
- }
-
- HRESULT Load();
-
- #ifndef _SFX
- int FindFormatForArchiveName(const UString &arcPath) const;
- int FindFormatForExtension(const UString &ext) const;
- int FindFormatForArchiveType(const UString &arcType) const;
- bool FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const;
- #endif
-
- #ifdef EXTERNAL_CODECS
-
- MY_UNKNOWN_IMP2(ICompressCodecsInfo, IHashers)
-
- STDMETHOD(GetNumMethods)(UInt32 *numMethods);
- STDMETHOD(GetProperty)(UInt32 index, PROPID propID, PROPVARIANT *value);
- STDMETHOD(CreateDecoder)(UInt32 index, const GUID *iid, void **coder);
- STDMETHOD(CreateEncoder)(UInt32 index, const GUID *iid, void **coder);
-
- STDMETHOD_(UInt32, GetNumHashers)();
- STDMETHOD(GetHasherProp)(UInt32 index, PROPID propID, PROPVARIANT *value);
- STDMETHOD(CreateHasher)(UInt32 index, IHasher **hasher);
-
- #else
-
- MY_UNKNOWN_IMP
-
- #endif // EXTERNAL_CODECS
-
-
- #ifdef EXTERNAL_CODECS
-
- int GetCodec_LibIndex(UInt32 index) const;
- bool GetCodec_DecoderIsAssigned(UInt32 index) const;
- bool GetCodec_EncoderIsAssigned(UInt32 index) const;
- UInt32 GetCodec_NumStreams(UInt32 index);
- HRESULT GetCodec_Id(UInt32 index, UInt64 &id);
- AString GetCodec_Name(UInt32 index);
-
- int GetHasherLibIndex(UInt32 index);
- UInt64 GetHasherId(UInt32 index);
- AString GetHasherName(UInt32 index);
- UInt32 GetHasherDigestSize(UInt32 index);
-
- #endif
-
- HRESULT CreateInArchive(unsigned formatIndex, CMyComPtr<IInArchive> &archive) const
- {
- const CArcInfoEx &ai = Formats[formatIndex];
- #ifdef EXTERNAL_CODECS
- if (ai.LibIndex < 0)
- #endif
- {
- COM_TRY_BEGIN
- archive = ai.CreateInArchive();
- return S_OK;
- COM_TRY_END
- }
- #ifdef EXTERNAL_CODECS
- return CreateArchiveHandler(ai, false, (void **)&archive);
- #endif
- }
-
- #ifndef _SFX
-
- HRESULT CreateOutArchive(unsigned formatIndex, CMyComPtr<IOutArchive> &archive) const
- {
- const CArcInfoEx &ai = Formats[formatIndex];
- #ifdef EXTERNAL_CODECS
- if (ai.LibIndex < 0)
- #endif
- {
- COM_TRY_BEGIN
- archive = ai.CreateOutArchive();
- return S_OK;
- COM_TRY_END
- }
-
- #ifdef EXTERNAL_CODECS
- return CreateArchiveHandler(ai, true, (void **)&archive);
- #endif
- }
-
- int FindOutFormatFromName(const UString &name) const
- {
- FOR_VECTOR (i, Formats)
- {
- const CArcInfoEx &arc = Formats[i];
- if (!arc.UpdateEnabled)
- continue;
- if (arc.Name.IsEqualTo_NoCase(name))
- return i;
- }
- return -1;
- }
-
- #endif // _SFX
-};
-
-#ifdef EXTERNAL_CODECS
- #define CREATE_CODECS_OBJECT \
- CCodecs *codecs = new CCodecs; \
- CExternalCodecs __externalCodecs; \
- __externalCodecs.GetCodecs = codecs; \
- __externalCodecs.GetHashers = codecs; \
- CCodecs::CReleaser codecsReleaser; \
- codecsReleaser.Set(codecs);
-#else
- #define CREATE_CODECS_OBJECT \
- CCodecs *codecs = new CCodecs; \
- CMyComPtr<IUnknown> __codecsRef = codecs;
-#endif
-
-#endif
+// LoadCodecs.h
+
+#ifndef ZIP7_INC_LOAD_CODECS_H
+#define ZIP7_INC_LOAD_CODECS_H
+
+/*
+Client application uses LoadCodecs.* to load plugins to
+CCodecs object, that contains 3 lists of plugins:
+ 1) Formats - internal and external archive handlers
+ 2) Codecs - external codecs
+ 3) Hashers - external hashers
+
+Z7_EXTERNAL_CODECS
+---------------
+
+ if Z7_EXTERNAL_CODECS is defined, then the code tries to load external
+ plugins from DLL files (shared libraries).
+
+ There are two types of executables in 7-Zip:
+
+ 1) Executable that uses external plugins must be compiled
+ with Z7_EXTERNAL_CODECS defined:
+ - 7z.exe, 7zG.exe, 7zFM.exe
+
+ Note: Z7_EXTERNAL_CODECS is used also in CPP/7zip/Common/CreateCoder.h
+ that code is used in plugin module (7z.dll).
+
+ 2) Standalone modules are compiled without Z7_EXTERNAL_CODECS:
+ - SFX modules: 7z.sfx, 7zCon.sfx
+ - standalone versions of console 7-Zip: 7za.exe, 7zr.exe
+
+ if Z7_EXTERNAL_CODECS is defined, CCodecs class implements interfaces:
+ - ICompressCodecsInfo : for Codecs
+ - IHashers : for Hashers
+
+ The client application can send CCodecs object to each plugin module.
+ And plugin module can use ICompressCodecsInfo or IHashers interface to access
+ another plugins.
+
+ There are 2 ways to send (ICompressCodecsInfo * compressCodecsInfo) to plugin
+ 1) for old versions:
+ a) request ISetCompressCodecsInfo from created archive handler.
+ b) call ISetCompressCodecsInfo::SetCompressCodecsInfo(compressCodecsInfo)
+ 2) for new versions:
+ a) request "SetCodecs" function from DLL file
+ b) call SetCodecs(compressCodecsInfo) function from DLL file
+*/
+
+#include "../../../Common/MyBuffer.h"
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyString.h"
+#include "../../../Common/ComTry.h"
+
+#ifdef Z7_EXTERNAL_CODECS
+#include "../../../Windows/DLL.h"
+#endif
+
+#include "../../ICoder.h"
+
+#include "../../Archive/IArchive.h"
+
+
+#ifdef Z7_EXTERNAL_CODECS
+
+struct CDllCodecInfo
+{
+ unsigned LibIndex;
+ UInt32 CodecIndex;
+ bool EncoderIsAssigned;
+ bool DecoderIsAssigned;
+ bool IsFilter;
+ bool IsFilter_Assigned;
+ CLSID Encoder;
+ CLSID Decoder;
+};
+
+struct CDllHasherInfo
+{
+ unsigned LibIndex;
+ UInt32 HasherIndex;
+};
+
+#endif
+
+struct CArcExtInfo
+{
+ UString Ext;
+ UString AddExt;
+
+ CArcExtInfo() {}
+ CArcExtInfo(const UString &ext): Ext(ext) {}
+ CArcExtInfo(const UString &ext, const UString &addExt): Ext(ext), AddExt(addExt) {}
+};
+
+
+struct CArcInfoEx
+{
+ UInt32 Flags;
+ UInt32 TimeFlags;
+
+ Func_CreateInArchive CreateInArchive;
+ Func_IsArc IsArcFunc;
+
+ UString Name;
+ CObjectVector<CArcExtInfo> Exts;
+
+ #ifndef Z7_SFX
+ Func_CreateOutArchive CreateOutArchive;
+ bool UpdateEnabled;
+ bool NewInterface;
+ // UInt32 Version;
+ UInt32 SignatureOffset;
+ CObjectVector<CByteBuffer> Signatures;
+ /*
+ #ifdef NEW_FOLDER_INTERFACE
+ UStringVector AssociateExts;
+ #endif
+ */
+ #endif
+
+ #ifdef Z7_EXTERNAL_CODECS
+ int LibIndex;
+ UInt32 FormatIndex;
+ CLSID ClassID;
+ #endif
+
+ int Compare(const CArcInfoEx &a) const
+ {
+ const int res = Name.Compare(a.Name);
+ if (res != 0)
+ return res;
+ #ifdef Z7_EXTERNAL_CODECS
+ return MyCompare(LibIndex, a.LibIndex);
+ #else
+ return 0;
+ #endif
+ /*
+ if (LibIndex < a.LibIndex) return -1;
+ if (LibIndex > a.LibIndex) return 1;
+ return 0;
+ */
+ }
+
+ bool Flags_KeepName() const { return (Flags & NArcInfoFlags::kKeepName) != 0; }
+ bool Flags_FindSignature() const { return (Flags & NArcInfoFlags::kFindSignature) != 0; }
+
+ bool Flags_AltStreams() const { return (Flags & NArcInfoFlags::kAltStreams) != 0; }
+ bool Flags_NtSecurity() const { return (Flags & NArcInfoFlags::kNtSecure) != 0; }
+ bool Flags_SymLinks() const { return (Flags & NArcInfoFlags::kSymLinks) != 0; }
+ bool Flags_HardLinks() const { return (Flags & NArcInfoFlags::kHardLinks) != 0; }
+
+ bool Flags_UseGlobalOffset() const { return (Flags & NArcInfoFlags::kUseGlobalOffset) != 0; }
+ bool Flags_StartOpen() const { return (Flags & NArcInfoFlags::kStartOpen) != 0; }
+ bool Flags_BackwardOpen() const { return (Flags & NArcInfoFlags::kBackwardOpen) != 0; }
+ bool Flags_PreArc() const { return (Flags & NArcInfoFlags::kPreArc) != 0; }
+ bool Flags_PureStartOpen() const { return (Flags & NArcInfoFlags::kPureStartOpen) != 0; }
+ bool Flags_ByExtOnlyOpen() const { return (Flags & NArcInfoFlags::kByExtOnlyOpen) != 0; }
+ bool Flags_HashHandler() const { return (Flags & NArcInfoFlags::kHashHandler) != 0; }
+
+ bool Flags_CTime() const { return (Flags & NArcInfoFlags::kCTime) != 0; }
+ bool Flags_ATime() const { return (Flags & NArcInfoFlags::kATime) != 0; }
+ bool Flags_MTime() const { return (Flags & NArcInfoFlags::kMTime) != 0; }
+
+ bool Flags_CTime_Default() const { return (Flags & NArcInfoFlags::kCTime_Default) != 0; }
+ bool Flags_ATime_Default() const { return (Flags & NArcInfoFlags::kATime_Default) != 0; }
+ bool Flags_MTime_Default() const { return (Flags & NArcInfoFlags::kMTime_Default) != 0; }
+
+ UInt32 Get_TimePrecFlags() const
+ {
+ return (TimeFlags >> NArcInfoTimeFlags::kTime_Prec_Mask_bit_index) &
+ (((UInt32)1 << NArcInfoTimeFlags::kTime_Prec_Mask_num_bits) - 1);
+ }
+
+ UInt32 Get_DefaultTimePrec() const
+ {
+ return (TimeFlags >> NArcInfoTimeFlags::kTime_Prec_Default_bit_index) &
+ (((UInt32)1 << NArcInfoTimeFlags::kTime_Prec_Default_num_bits) - 1);
+ }
+
+
+ UString GetMainExt() const
+ {
+ if (Exts.IsEmpty())
+ return UString();
+ return Exts[0].Ext;
+ }
+ int FindExtension(const UString &ext) const;
+
+ bool Is_7z() const { return Name.IsEqualTo_Ascii_NoCase("7z"); }
+ bool Is_Split() const { return Name.IsEqualTo_Ascii_NoCase("Split"); }
+ bool Is_Xz() const { return Name.IsEqualTo_Ascii_NoCase("xz"); }
+ bool Is_BZip2() const { return Name.IsEqualTo_Ascii_NoCase("bzip2"); }
+ bool Is_GZip() const { return Name.IsEqualTo_Ascii_NoCase("gzip"); }
+ bool Is_Tar() const { return Name.IsEqualTo_Ascii_NoCase("tar"); }
+ bool Is_Zip() const { return Name.IsEqualTo_Ascii_NoCase("zip"); }
+ bool Is_Rar() const { return Name.IsEqualTo_Ascii_NoCase("rar"); }
+ bool Is_Zstd() const { return Name.IsEqualTo_Ascii_NoCase("zstd"); }
+
+ /*
+ UString GetAllExtensions() const
+ {
+ UString s;
+ for (int i = 0; i < Exts.Size(); i++)
+ {
+ if (i > 0)
+ s.Add_Space();
+ s += Exts[i].Ext;
+ }
+ return s;
+ }
+ */
+
+ void AddExts(const UString &ext, const UString &addExt);
+
+
+ CArcInfoEx():
+ Flags(0),
+ TimeFlags(0),
+ CreateInArchive(NULL),
+ IsArcFunc(NULL)
+ #ifndef Z7_SFX
+ , CreateOutArchive(NULL)
+ , UpdateEnabled(false)
+ , NewInterface(false)
+ // , Version(0)
+ , SignatureOffset(0)
+ #endif
+ #ifdef Z7_EXTERNAL_CODECS
+ , LibIndex(-1)
+ #endif
+ {}
+};
+
+
+#ifdef Z7_EXTERNAL_CODECS
+
+struct CCodecLib
+{
+ NWindows::NDLL::CLibrary Lib;
+ FString Path;
+
+ Func_CreateObject CreateObject;
+ Func_GetMethodProperty GetMethodProperty;
+ Func_CreateDecoder CreateDecoder;
+ Func_CreateEncoder CreateEncoder;
+ Func_SetCodecs SetCodecs;
+
+ CMyComPtr<IHashers> ComHashers;
+
+ UInt32 Version;
+
+ /*
+ #ifdef NEW_FOLDER_INTERFACE
+ CCodecIcons CodecIcons;
+ void LoadIcons() { CodecIcons.LoadIcons((HMODULE)Lib); }
+ #endif
+ */
+
+ CCodecLib():
+ CreateObject(NULL),
+ GetMethodProperty(NULL),
+ CreateDecoder(NULL),
+ CreateEncoder(NULL),
+ SetCodecs(NULL),
+ Version(0)
+ {}
+};
+
+#endif
+
+struct CCodecError
+{
+ FString Path;
+ HRESULT ErrorCode;
+ AString Message;
+ CCodecError(): ErrorCode(0) {}
+};
+
+
+struct CCodecInfoUser
+{
+ // unsigned LibIndex;
+ // UInt32 CodecIndex;
+ // UInt64 id;
+ bool EncoderIsAssigned;
+ bool DecoderIsAssigned;
+ bool IsFilter;
+ bool IsFilter_Assigned;
+ UInt32 NumStreams;
+ AString Name;
+};
+
+
+class CCodecs Z7_final:
+ #ifdef Z7_EXTERNAL_CODECS
+ public ICompressCodecsInfo,
+ public IHashers,
+ #else
+ public IUnknown,
+ #endif
+ public CMyUnknownImp
+{
+#ifdef Z7_EXTERNAL_CODECS
+ Z7_IFACES_IMP_UNK_2(ICompressCodecsInfo, IHashers)
+#else
+ Z7_COM_UNKNOWN_IMP_0
+#endif // Z7_EXTERNAL_CODECS
+
+ Z7_CLASS_NO_COPY(CCodecs)
+public:
+ #ifdef Z7_EXTERNAL_CODECS
+
+ CObjectVector<CCodecLib> Libs;
+ FString MainDll_ErrorPath;
+ CObjectVector<CCodecError> Errors;
+
+ void AddLastError(const FString &path);
+ void CloseLibs();
+
+ class CReleaser
+ {
+ Z7_CLASS_NO_COPY(CReleaser)
+
+ /* CCodecsReleaser object releases CCodecs links.
+ 1) CCodecs is COM object that is deleted when all links to that object will be released/
+ 2) CCodecs::Libs[i] can hold (ICompressCodecsInfo *) link to CCodecs object itself.
+ To break that reference loop, we must close all CCodecs::Libs in CCodecsReleaser desttructor. */
+
+ CCodecs *_codecs;
+
+ public:
+ CReleaser(): _codecs(NULL) {}
+ void Set(CCodecs *codecs) { _codecs = codecs; }
+ ~CReleaser() { if (_codecs) _codecs->CloseLibs(); }
+ };
+
+ bool NeedSetLibCodecs; // = false, if we don't need to set codecs for archive handler via ISetCompressCodecsInfo
+
+ HRESULT LoadCodecs();
+ HRESULT LoadFormats();
+ HRESULT LoadDll(const FString &path, bool needCheckDll, bool *loadedOK = NULL);
+ HRESULT LoadDllsFromFolder(const FString &folderPrefix);
+
+ HRESULT CreateArchiveHandler(const CArcInfoEx &ai, bool outHandler, void **archive) const
+ {
+ return Libs[(unsigned)ai.LibIndex].CreateObject(&ai.ClassID, outHandler ? &IID_IOutArchive : &IID_IInArchive, (void **)archive);
+ }
+
+ #endif
+
+ /*
+ #ifdef NEW_FOLDER_INTERFACE
+ CCodecIcons InternalIcons;
+ #endif
+ */
+
+ CObjectVector<CArcInfoEx> Formats;
+
+ #ifdef Z7_EXTERNAL_CODECS
+ CRecordVector<CDllCodecInfo> Codecs;
+ CRecordVector<CDllHasherInfo> Hashers;
+ #endif
+
+ bool CaseSensitive_Change;
+ bool CaseSensitive;
+
+ CCodecs():
+ #ifdef Z7_EXTERNAL_CODECS
+ NeedSetLibCodecs(true),
+ #endif
+ CaseSensitive_Change(false),
+ CaseSensitive(false)
+ {}
+
+ ~CCodecs()
+ {
+ // OutputDebugStringA("~CCodecs");
+ }
+
+ const wchar_t *GetFormatNamePtr(int formatIndex) const
+ {
+ return formatIndex < 0 ? L"#" : (const wchar_t *)Formats[(unsigned)formatIndex].Name;
+ }
+
+ HRESULT Load();
+
+ #ifndef Z7_SFX
+ int FindFormatForArchiveName(const UString &arcPath) const;
+ int FindFormatForExtension(const UString &ext) const;
+ int FindFormatForArchiveType(const UString &arcType) const;
+ bool FindFormatForArchiveType(const UString &arcType, CIntVector &formatIndices) const;
+ #endif
+
+ #ifdef Z7_EXTERNAL_CODECS
+
+ int GetCodec_LibIndex(UInt32 index) const;
+ bool GetCodec_DecoderIsAssigned(UInt32 index) const;
+ bool GetCodec_EncoderIsAssigned(UInt32 index) const;
+ bool GetCodec_IsFilter(UInt32 index, bool &isAssigned) const;
+ UInt32 GetCodec_NumStreams(UInt32 index);
+ HRESULT GetCodec_Id(UInt32 index, UInt64 &id);
+ AString GetCodec_Name(UInt32 index);
+
+ int GetHasherLibIndex(UInt32 index);
+ UInt64 GetHasherId(UInt32 index);
+ AString GetHasherName(UInt32 index);
+ UInt32 GetHasherDigestSize(UInt32 index);
+
+ void GetCodecsErrorMessage(UString &s);
+
+ #endif
+
+ HRESULT CreateInArchive(unsigned formatIndex, CMyComPtr<IInArchive> &archive) const
+ {
+ const CArcInfoEx &ai = Formats[formatIndex];
+ #ifdef Z7_EXTERNAL_CODECS
+ if (ai.LibIndex < 0)
+ #endif
+ {
+ COM_TRY_BEGIN
+ archive = ai.CreateInArchive();
+ return S_OK;
+ COM_TRY_END
+ }
+ #ifdef Z7_EXTERNAL_CODECS
+ return CreateArchiveHandler(ai, false, (void **)&archive);
+ #endif
+ }
+
+ #ifndef Z7_SFX
+
+ HRESULT CreateOutArchive(unsigned formatIndex, CMyComPtr<IOutArchive> &archive) const
+ {
+ const CArcInfoEx &ai = Formats[formatIndex];
+ #ifdef Z7_EXTERNAL_CODECS
+ if (ai.LibIndex < 0)
+ #endif
+ {
+ COM_TRY_BEGIN
+ archive = ai.CreateOutArchive();
+ return S_OK;
+ COM_TRY_END
+ }
+
+ #ifdef Z7_EXTERNAL_CODECS
+ return CreateArchiveHandler(ai, true, (void **)&archive);
+ #endif
+ }
+
+ int FindOutFormatFromName(const UString &name) const
+ {
+ FOR_VECTOR (i, Formats)
+ {
+ const CArcInfoEx &arc = Formats[i];
+ if (!arc.UpdateEnabled)
+ continue;
+ if (arc.Name.IsEqualTo_NoCase(name))
+ return (int)i;
+ }
+ return -1;
+ }
+
+ void Get_CodecsInfoUser_Vector(CObjectVector<CCodecInfoUser> &v);
+
+ #endif // Z7_SFX
+};
+
+#ifdef Z7_EXTERNAL_CODECS
+ #define CREATE_CODECS_OBJECT \
+ CCodecs *codecs = new CCodecs; \
+ CExternalCodecs _externalCodecs; \
+ _externalCodecs.GetCodecs = codecs; \
+ _externalCodecs.GetHashers = codecs; \
+ CCodecs::CReleaser codecsReleaser; \
+ codecsReleaser.Set(codecs);
+#else
+ #define CREATE_CODECS_OBJECT \
+ CCodecs *codecs = new CCodecs; \
+ CMyComPtr<IUnknown> _codecsRef = codecs;
+#endif
+
+#endif
diff --git a/CPP/7zip/UI/Common/OpenArchive.cpp b/CPP/7zip/UI/Common/OpenArchive.cpp
index d72454c..a501b86 100644
--- a/CPP/7zip/UI/Common/OpenArchive.cpp
+++ b/CPP/7zip/UI/Common/OpenArchive.cpp
@@ -1,3553 +1,3695 @@
-// OpenArchive.cpp
-
-#include "StdAfx.h"
-
-// #define SHOW_DEBUG_INFO
-
-#ifdef SHOW_DEBUG_INFO
-#include <stdio.h>
-#endif
-
-#include "../../../../C/CpuArch.h"
-
-#include "../../../Common/ComTry.h"
-#include "../../../Common/IntToString.h"
-#include "../../../Common/StringConvert.h"
-#include "../../../Common/StringToInt.h"
-#include "../../../Common/Wildcard.h"
-
-#include "../../../Windows/FileDir.h"
-
-#include "../../Common/FileStreams.h"
-#include "../../Common/LimitedStreams.h"
-#include "../../Common/ProgressUtils.h"
-#include "../../Common/StreamUtils.h"
-
-#include "../../Compress/CopyCoder.h"
-
-#include "DefaultName.h"
-#include "OpenArchive.h"
-
-#ifndef _SFX
-#include "SetProperties.h"
-#endif
-
-#ifdef SHOW_DEBUG_INFO
-#define PRF(x) x
-#else
-#define PRF(x)
-#endif
-
-// increase it, if you need to support larger SFX stubs
-static const UInt64 kMaxCheckStartPosition = 1 << 23;
-
-/*
-Open:
- - formatIndex >= 0 (exact Format)
- 1) Open with main type. Archive handler is allowed to use archive start finder.
- Warning, if there is tail.
-
- - formatIndex = -1 (Parser:0) (default)
- - same as #1 but doesn't return Parser
-
- - formatIndex = -2 (#1)
- - file has supported extension (like a.7z)
- Open with that main type (only starting from start of file).
- - open OK:
- - if there is no tail - return OK
- - if there is tail:
- - archive is not "Self Exe" - return OK with Warning, that there is tail
- - archive is "Self Exe"
- ignore "Self Exe" stub, and tries to open tail
- - tail can be open as archive - shows that archive and stub size property.
- - tail can't be open as archive - shows Parser ???
- - open FAIL:
- Try to open with all other types from offset 0 only.
- If some open type is OK and physical archive size is uequal or larger
- than file size, then return that archive with warning that can not be open as [extension type].
- If extension was EXE, it will try to open as unknown_extension case
- - file has unknown extension (like a.hhh)
- It tries to open via parser code.
- - if there is full archive or tail archive and unknown block or "Self Exe"
- at front, it shows tail archive and stub size property.
- - in another cases, if there is some archive inside file, it returns parser/
- - in another cases, it retuens S_FALSE
-
-
- - formatIndex = -3 (#2)
- - same as #1, but
- - stub (EXE) + archive is open in Parser
-
- - formatIndex = -4 (#3)
- - returns only Parser. skip full file archive. And show other sub-archives
-
- - formatIndex = -5 (#4)
- - returns only Parser. skip full file archive. And show other sub-archives for each byte pos
-
-*/
-
-
-
-
-using namespace NWindows;
-
-/*
-#ifdef _SFX
-#define OPEN_PROPS_PARAM
-#else
-#define OPEN_PROPS_PARAM , props
-#endif
-*/
-
-/*
-CArc::~CArc()
-{
- GetRawProps.Release();
- Archive.Release();
- printf("\nCArc::~CArc()\n");
-}
-*/
-
-#ifndef _SFX
-
-namespace NArchive {
-namespace NParser {
-
-struct CParseItem
-{
- UInt64 Offset;
- UInt64 Size;
- // UInt64 OkSize;
- UString Name;
- UString Extension;
- FILETIME FileTime;
- UString Comment;
- UString ArcType;
-
- bool FileTime_Defined;
- bool UnpackSize_Defined;
- bool NumSubDirs_Defined;
- bool NumSubFiles_Defined;
-
- bool IsSelfExe;
- bool IsNotArcType;
-
- UInt64 UnpackSize;
- UInt64 NumSubDirs;
- UInt64 NumSubFiles;
-
- int FormatIndex;
-
- bool LenIsUnknown;
-
- CParseItem():
- LenIsUnknown(false),
- FileTime_Defined(false),
- UnpackSize_Defined(false),
- NumSubFiles_Defined(false),
- NumSubDirs_Defined(false),
- IsSelfExe(false),
- IsNotArcType(false)
- // OkSize(0)
- {}
-
- /*
- bool IsEqualTo(const CParseItem &item) const
- {
- return Offset == item.Offset && Size == item.Size;
- }
- */
-
- void NormalizeOffset()
- {
- if ((Int64)Offset < 0)
- {
- Size += Offset;
- // OkSize += Offset;
- Offset = 0;
- }
- }
-};
-
-class CHandler:
- public IInArchive,
- public IInArchiveGetStream,
- public CMyUnknownImp
-{
-public:
- CObjectVector<CParseItem> _items;
- UInt64 _maxEndOffset;
- CMyComPtr<IInStream> _stream;
-
- MY_UNKNOWN_IMP2(
- IInArchive,
- IInArchiveGetStream)
-
- INTERFACE_IInArchive(;)
- STDMETHOD(GetStream)(UInt32 index, ISequentialInStream **stream);
-
- UInt64 GetLastEnd() const
- {
- if (_items.IsEmpty())
- return 0;
- const CParseItem &back = _items.Back();
- return back.Offset + back.Size;
- }
-
- void AddUnknownItem(UInt64 next);
- int FindInsertPos(const CParseItem &item) const;
- void AddItem(const CParseItem &item);
-
- CHandler(): _maxEndOffset(0) {}
-};
-
-int CHandler::FindInsertPos(const CParseItem &item) const
-{
- unsigned left = 0, right = _items.Size();
- while (left != right)
- {
- unsigned mid = (left + right) / 2;
- const CParseItem & midItem = _items[mid];
- if (item.Offset < midItem.Offset)
- right = mid;
- else if (item.Offset > midItem.Offset)
- left = mid + 1;
- else if (item.Size < midItem.Size)
- right = mid;
- else if (item.Size > midItem.Size)
- left = mid + 1;
- else
- {
- left = mid + 1;
- // return -1;
- }
- }
- return left;
-}
-
-void CHandler::AddUnknownItem(UInt64 next)
-{
- /*
- UInt64 prevEnd = 0;
- if (!_items.IsEmpty())
- {
- const CParseItem &back = _items.Back();
- prevEnd = back.Offset + back.Size;
- }
- */
- if (_maxEndOffset < next)
- {
- CParseItem item2;
- item2.Offset = _maxEndOffset;
- item2.Size = next - _maxEndOffset;
- _maxEndOffset = next;
- _items.Add(item2);
- }
- else if (_maxEndOffset > next && !_items.IsEmpty())
- {
- CParseItem &back = _items.Back();
- if (back.LenIsUnknown)
- {
- back.Size = next - back.Offset;
- _maxEndOffset = next;
- }
- }
-}
-
-void CHandler::AddItem(const CParseItem &item)
-{
- AddUnknownItem(item.Offset);
- int pos = FindInsertPos(item);
- if (pos >= 0)
- {
- _items.Insert(pos, item);
- UInt64 next = item.Offset + item.Size;
- if (_maxEndOffset < next)
- _maxEndOffset = next;
- }
-}
-
-/*
-static const CStatProp kProps[] =
-{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidType, VT_BSTR},
- { NULL, kpidComment, VT_BSTR},
- { NULL, kpidOffset, VT_UI8},
- { NULL, kpidUnpackSize, VT_UI8},
-// { NULL, kpidNumSubDirs, VT_UI8},
-};
-*/
-
-static const Byte kProps[] =
-{
- kpidPath,
- kpidSize,
- kpidMTime,
- kpidType,
- kpidComment,
- kpidOffset,
- kpidUnpackSize
-};
-
-IMP_IInArchive_Props
-IMP_IInArchive_ArcProps_NO
-
-STDMETHODIMP CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* openArchiveCallback */)
-{
- COM_TRY_BEGIN
- {
- Close();
- _stream = stream;
- }
- return S_OK;
- COM_TRY_END
-}
-
-STDMETHODIMP CHandler::Close()
-{
- _items.Clear();
- _stream.Release();
- return S_OK;
-}
-
-STDMETHODIMP CHandler::GetNumberOfItems(UInt32 *numItems)
-{
- *numItems = _items.Size();
- return S_OK;
-}
-
-STDMETHODIMP CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
-{
- COM_TRY_BEGIN
- NCOM::CPropVariant prop;
-
- const CParseItem &item = _items[index];
-
- switch (propID)
- {
- case kpidPath:
- {
- char sz[32];
- ConvertUInt32ToString(index + 1, sz);
- UString s(sz);
- if (!item.Name.IsEmpty())
- {
- s += '.';
- s += item.Name;
- }
- if (!item.Extension.IsEmpty())
- {
- s += '.';
- s += item.Extension;
- }
- prop = s; break;
- }
- case kpidSize:
- case kpidPackSize: prop = item.Size; break;
- case kpidOffset: prop = item.Offset; break;
- case kpidUnpackSize: if (item.UnpackSize_Defined) prop = item.UnpackSize; break;
- case kpidNumSubFiles: if (item.NumSubFiles_Defined) prop = item.NumSubFiles; break;
- case kpidNumSubDirs: if (item.NumSubDirs_Defined) prop = item.NumSubDirs; break;
- case kpidMTime: if (item.FileTime_Defined) prop = item.FileTime; break;
- case kpidComment: if (!item.Comment.IsEmpty()) prop = item.Comment; break;
- case kpidType: if (!item.ArcType.IsEmpty()) prop = item.ArcType; break;
- }
- prop.Detach(value);
- return S_OK;
- COM_TRY_END
-}
-
-HRESULT CHandler::Extract(const UInt32 *indices, UInt32 numItems,
- Int32 testMode, IArchiveExtractCallback *extractCallback)
-{
- COM_TRY_BEGIN
-
- bool allFilesMode = (numItems == (UInt32)(Int32)-1);
- if (allFilesMode)
- numItems = _items.Size();
- if (_stream && numItems == 0)
- return S_OK;
- UInt64 totalSize = 0;
- UInt32 i;
- for (i = 0; i < numItems; i++)
- totalSize += _items[allFilesMode ? i : indices[i]].Size;
- extractCallback->SetTotal(totalSize);
-
- totalSize = 0;
-
- CLocalProgress *lps = new CLocalProgress;
- CMyComPtr<ICompressProgressInfo> progress = lps;
- lps->Init(extractCallback, false);
-
- CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
- CMyComPtr<ISequentialInStream> inStream(streamSpec);
- streamSpec->SetStream(_stream);
-
- CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
- CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
-
- NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
- CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
-
- for (i = 0; i < numItems; i++)
- {
- lps->InSize = totalSize;
- lps->OutSize = totalSize;
- RINOK(lps->SetCur());
- CMyComPtr<ISequentialOutStream> realOutStream;
- Int32 askMode = testMode ?
- NExtract::NAskMode::kTest :
- NExtract::NAskMode::kExtract;
- Int32 index = allFilesMode ? i : indices[i];
- const CParseItem &item = _items[index];
-
- RINOK(extractCallback->GetStream(index, &realOutStream, askMode));
- UInt64 unpackSize = item.Size;
- totalSize += unpackSize;
- bool skipMode = false;
- if (!testMode && !realOutStream)
- continue;
- RINOK(extractCallback->PrepareOperation(askMode));
-
- outStreamSpec->SetStream(realOutStream);
- realOutStream.Release();
- outStreamSpec->Init(skipMode ? 0 : unpackSize, true);
-
- Int32 opRes = NExtract::NOperationResult::kOK;
- RINOK(_stream->Seek(item.Offset, STREAM_SEEK_SET, NULL));
- streamSpec->Init(unpackSize);
- RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress));
-
- if (outStreamSpec->GetRem() != 0)
- opRes = NExtract::NOperationResult::kDataError;
- outStreamSpec->ReleaseStream();
- RINOK(extractCallback->SetOperationResult(opRes));
- }
-
- return S_OK;
-
- COM_TRY_END
-}
-
-
-STDMETHODIMP CHandler::GetStream(UInt32 index, ISequentialInStream **stream)
-{
- COM_TRY_BEGIN
- const CParseItem &item = _items[index];
- return CreateLimitedInStream(_stream, item.Offset, item.Size, stream);
- COM_TRY_END
-}
-
-}}
-
-#endif
-
-HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw()
-{
- NCOM::CPropVariant prop;
- result = false;
- RINOK(arc->GetProperty(index, propID, &prop));
- if (prop.vt == VT_BOOL)
- result = VARIANT_BOOLToBool(prop.boolVal);
- else if (prop.vt != VT_EMPTY)
- return E_FAIL;
- return S_OK;
-}
-
-HRESULT Archive_IsItem_Dir(IInArchive *arc, UInt32 index, bool &result) throw()
-{
- return Archive_GetItemBoolProp(arc, index, kpidIsDir, result);
-}
-
-HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw()
-{
- return Archive_GetItemBoolProp(arc, index, kpidIsAux, result);
-}
-
-HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw()
-{
- return Archive_GetItemBoolProp(arc, index, kpidIsAltStream, result);
-}
-
-HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &result) throw()
-{
- return Archive_GetItemBoolProp(arc, index, kpidIsDeleted, result);
-}
-
-static HRESULT Archive_GetArcBoolProp(IInArchive *arc, PROPID propid, bool &result) throw()
-{
- NCOM::CPropVariant prop;
- result = false;
- RINOK(arc->GetArchiveProperty(propid, &prop));
- if (prop.vt == VT_BOOL)
- result = VARIANT_BOOLToBool(prop.boolVal);
- else if (prop.vt != VT_EMPTY)
- return E_FAIL;
- return S_OK;
-}
-
-static HRESULT Archive_GetArcProp_UInt(IInArchive *arc, PROPID propid, UInt64 &result, bool &defined)
-{
- defined = false;
- NCOM::CPropVariant prop;
- RINOK(arc->GetArchiveProperty(propid, &prop));
- switch (prop.vt)
- {
- case VT_UI4: result = prop.ulVal; defined = true; break;
- case VT_I4: result = (Int64)prop.lVal; defined = true; break;
- case VT_UI8: result = (UInt64)prop.uhVal.QuadPart; defined = true; break;
- case VT_I8: result = (UInt64)prop.hVal.QuadPart; defined = true; break;
- case VT_EMPTY: break;
- default: return E_FAIL;
- }
- return S_OK;
-}
-
-static HRESULT Archive_GetArcProp_Int(IInArchive *arc, PROPID propid, Int64 &result, bool &defined)
-{
- defined = false;
- NCOM::CPropVariant prop;
- RINOK(arc->GetArchiveProperty(propid, &prop));
- switch (prop.vt)
- {
- case VT_UI4: result = prop.ulVal; defined = true; break;
- case VT_I4: result = prop.lVal; defined = true; break;
- case VT_UI8: result = (Int64)prop.uhVal.QuadPart; defined = true; break;
- case VT_I8: result = (Int64)prop.hVal.QuadPart; defined = true; break;
- case VT_EMPTY: break;
- default: return E_FAIL;
- }
- return S_OK;
-}
-
-#ifndef _SFX
-
-HRESULT CArc::GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const
-{
- if (!GetRawProps)
- return E_FAIL;
- if (index == parent)
- return S_OK;
- UInt32 curIndex = index;
-
- UString s;
-
- bool prevWasAltStream = false;
-
- for (;;)
- {
- #ifdef MY_CPU_LE
- const void *p;
- UInt32 size;
- UInt32 propType;
- RINOK(GetRawProps->GetRawProp(curIndex, kpidName, &p, &size, &propType));
- if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE)
- s = (const wchar_t *)p;
- else
- #endif
- {
- NCOM::CPropVariant prop;
- RINOK(Archive->GetProperty(curIndex, kpidName, &prop));
- if (prop.vt == VT_BSTR && prop.bstrVal)
- s.SetFromBstr(prop.bstrVal);
- else if (prop.vt == VT_EMPTY)
- s.Empty();
- else
- return E_FAIL;
- }
-
- UInt32 curParent = (UInt32)(Int32)-1;
- UInt32 parentType = 0;
- RINOK(GetRawProps->GetParent(curIndex, &curParent, &parentType));
-
- // 18.06: fixed : we don't want to split name to parts
- /*
- if (parentType != NParentType::kAltStream)
- {
- for (;;)
- {
- int pos = s.ReverseFind_PathSepar();
- if (pos < 0)
- {
- break;
- }
- parts.Insert(0, s.Ptr(pos + 1));
- s.DeleteFrom(pos);
- }
- }
- */
-
- parts.Insert(0, s);
-
- if (prevWasAltStream)
- {
- {
- UString &s2 = parts[parts.Size() - 2];
- s2 += ':';
- s2 += parts.Back();
- }
- parts.DeleteBack();
- }
-
- if (parent == curParent)
- return S_OK;
-
- prevWasAltStream = false;
- if (parentType == NParentType::kAltStream)
- prevWasAltStream = true;
-
- if (curParent == (UInt32)(Int32)-1)
- return E_FAIL;
- curIndex = curParent;
- }
-}
-
-#endif
-
-HRESULT CArc::GetItemPath(UInt32 index, UString &result) const
-{
- #ifdef MY_CPU_LE
- if (GetRawProps)
- {
- const void *p;
- UInt32 size;
- UInt32 propType;
- if (!IsTree)
- {
- if (GetRawProps->GetRawProp(index, kpidPath, &p, &size, &propType) == S_OK &&
- propType == NPropDataType::kUtf16z)
- {
- unsigned len = size / 2 - 1;
- wchar_t *s = result.GetBuf(len);
- for (unsigned i = 0; i < len; i++)
- {
- wchar_t c = GetUi16(p);
- p = (const void *)((const Byte *)p + 2);
- #if WCHAR_PATH_SEPARATOR != L'/'
- if (c == L'/')
- c = WCHAR_PATH_SEPARATOR;
- #endif
- *s++ = c;
- }
- *s = 0;
- result.ReleaseBuf_SetLen(len);
- if (len != 0)
- return S_OK;
- }
- }
- /*
- else if (GetRawProps->GetRawProp(index, kpidName, &p, &size, &propType) == S_OK &&
- p && propType == NPropDataType::kUtf16z)
- {
- size -= 2;
- UInt32 totalSize = size;
- bool isOK = false;
-
- {
- UInt32 index2 = index;
- for (;;)
- {
- UInt32 parent = (UInt32)(Int32)-1;
- UInt32 parentType = 0;
- if (GetRawProps->GetParent(index2, &parent, &parentType) != S_OK)
- break;
- if (parent == (UInt32)(Int32)-1)
- {
- if (parentType != 0)
- totalSize += 2;
- isOK = true;
- break;
- }
- index2 = parent;
- UInt32 size2;
- const void *p2;
- if (GetRawProps->GetRawProp(index2, kpidName, &p2, &size2, &propType) != S_OK &&
- p2 && propType == NPropDataType::kUtf16z)
- break;
- totalSize += size2;
- }
- }
-
- if (isOK)
- {
- wchar_t *sz = result.GetBuf_SetEnd(totalSize / 2);
- UInt32 pos = totalSize - size;
- memcpy((Byte *)sz + pos, p, size);
- UInt32 index2 = index;
- for (;;)
- {
- UInt32 parent = (UInt32)(Int32)-1;
- UInt32 parentType = 0;
- if (GetRawProps->GetParent(index2, &parent, &parentType) != S_OK)
- break;
- if (parent == (UInt32)(Int32)-1)
- {
- if (parentType != 0)
- sz[pos / 2 - 1] = L':';
- break;
- }
- index2 = parent;
- UInt32 size2;
- const void *p2;
- if (GetRawProps->GetRawProp(index2, kpidName, &p2, &size2, &propType) != S_OK)
- break;
- pos -= size2;
- memcpy((Byte *)sz + pos, p2, size2);
- sz[(pos + size2 - 2) / 2] = (parentType == 0) ? WCHAR_PATH_SEPARATOR : L':';
- }
- #ifdef _WIN32
- // result.Replace(L'/', WCHAR_PATH_SEPARATOR);
- #endif
- return S_OK;
- }
- }
- */
- }
- #endif
-
- {
- NCOM::CPropVariant prop;
- RINOK(Archive->GetProperty(index, kpidPath, &prop));
- if (prop.vt == VT_BSTR && prop.bstrVal)
- result.SetFromBstr(prop.bstrVal);
- else if (prop.vt == VT_EMPTY)
- result.Empty();
- else
- return E_FAIL;
- }
-
- if (result.IsEmpty())
- return GetDefaultItemPath(index, result);
- return S_OK;
-}
-
-HRESULT CArc::GetDefaultItemPath(UInt32 index, UString &result) const
-{
- result.Empty();
- bool isDir;
- RINOK(Archive_IsItem_Dir(Archive, index, isDir));
- if (!isDir)
- {
- result = DefaultName;
- NCOM::CPropVariant prop;
- RINOK(Archive->GetProperty(index, kpidExtension, &prop));
- if (prop.vt == VT_BSTR)
- {
- result += '.';
- result += prop.bstrVal;
- }
- else if (prop.vt != VT_EMPTY)
- return E_FAIL;
- }
- return S_OK;
-}
-
-HRESULT CArc::GetItemPath2(UInt32 index, UString &result) const
-{
- RINOK(GetItemPath(index, result));
- if (Ask_Deleted)
- {
- bool isDeleted = false;
- RINOK(Archive_IsItem_Deleted(Archive, index, isDeleted));
- if (isDeleted)
- result.Insert(0, L"[DELETED]" WSTRING_PATH_SEPARATOR);
- }
- return S_OK;
-}
-
-#ifdef SUPPORT_ALT_STREAMS
-
-int FindAltStreamColon_in_Path(const wchar_t *path)
-{
- unsigned i = 0;
- int colonPos = -1;
- for (;; i++)
- {
- wchar_t c = path[i];
- if (c == 0)
- return colonPos;
- if (c == ':')
- {
- if (colonPos < 0)
- colonPos = i;
- continue;
- }
- if (c == WCHAR_PATH_SEPARATOR)
- colonPos = -1;
- }
-}
-
-#endif
-
-HRESULT CArc::GetItem(UInt32 index, CReadArcItem &item) const
-{
- #ifdef SUPPORT_ALT_STREAMS
- item.IsAltStream = false;
- item.AltStreamName.Empty();
- item.MainPath.Empty();
- #endif
-
- item.IsDir = false;
- item.Path.Empty();
- item.ParentIndex = (UInt32)(Int32)-1;
-
- item.PathParts.Clear();
-
- RINOK(Archive_IsItem_Dir(Archive, index, item.IsDir));
- item.MainIsDir = item.IsDir;
-
- RINOK(GetItemPath2(index, item.Path));
-
- #ifndef _SFX
- UInt32 mainIndex = index;
- #endif
-
- #ifdef SUPPORT_ALT_STREAMS
-
- item.MainPath = item.Path;
- if (Ask_AltStream)
- {
- RINOK(Archive_IsItem_AltStream(Archive, index, item.IsAltStream));
- }
-
- bool needFindAltStream = false;
-
- if (item.IsAltStream)
- {
- needFindAltStream = true;
- if (GetRawProps)
- {
- UInt32 parentType = 0;
- UInt32 parentIndex;
- RINOK(GetRawProps->GetParent(index, &parentIndex, &parentType));
- if (parentType == NParentType::kAltStream)
- {
- NCOM::CPropVariant prop;
- RINOK(Archive->GetProperty(index, kpidName, &prop));
- if (prop.vt == VT_BSTR && prop.bstrVal)
- item.AltStreamName.SetFromBstr(prop.bstrVal);
- else if (prop.vt != VT_EMPTY)
- return E_FAIL;
- else
- {
- // item.IsAltStream = false;
- }
- /*
- if (item.AltStreamName.IsEmpty())
- item.IsAltStream = false;
- */
-
- needFindAltStream = false;
- item.ParentIndex = parentIndex;
- mainIndex = parentIndex;
-
- if (parentIndex == (UInt32)(Int32)-1)
- {
- item.MainPath.Empty();
- item.MainIsDir = true;
- }
- else
- {
- RINOK(GetItemPath2(parentIndex, item.MainPath));
- RINOK(Archive_IsItem_Dir(Archive, parentIndex, item.MainIsDir));
- }
- }
- }
- }
-
- if (item.WriteToAltStreamIfColon || needFindAltStream)
- {
- /* Good handler must support GetRawProps::GetParent for alt streams.
- So the following code currently is not used */
- int colon = FindAltStreamColon_in_Path(item.Path);
- if (colon >= 0)
- {
- item.MainPath.DeleteFrom(colon);
- item.AltStreamName = item.Path.Ptr(colon + 1);
- item.MainIsDir = (colon == 0 || IsPathSepar(item.Path[(unsigned)colon - 1]));
- item.IsAltStream = true;
- }
- }
-
- #endif
-
- #ifndef _SFX
- if (item._use_baseParentFolder_mode)
- {
- RINOK(GetItemPathToParent(mainIndex, item._baseParentFolder, item.PathParts));
-
- #ifdef SUPPORT_ALT_STREAMS
- if ((item.WriteToAltStreamIfColon || needFindAltStream) && !item.PathParts.IsEmpty())
- {
- int colon;
- {
- UString &s = item.PathParts.Back();
- colon = FindAltStreamColon_in_Path(s);
- if (colon >= 0)
- {
- item.AltStreamName = s.Ptr(colon + 1);
- item.MainIsDir = (colon == 0 || IsPathSepar(s[(unsigned)colon - 1]));
- item.IsAltStream = true;
- s.DeleteFrom(colon);
- }
- }
- if (colon == 0)
- item.PathParts.DeleteBack();
- }
- #endif
-
- }
- else
- #endif
- SplitPathToParts(
- #ifdef SUPPORT_ALT_STREAMS
- item.MainPath
- #else
- item.Path
- #endif
- , item.PathParts);
-
- return S_OK;
-}
-
-#ifndef _SFX
-
-static HRESULT Archive_GetItem_Size(IInArchive *archive, UInt32 index, UInt64 &size, bool &defined)
-{
- NCOM::CPropVariant prop;
- defined = false;
- size = 0;
- RINOK(archive->GetProperty(index, kpidSize, &prop));
- switch (prop.vt)
- {
- case VT_UI1: size = prop.bVal; break;
- case VT_UI2: size = prop.uiVal; break;
- case VT_UI4: size = prop.ulVal; break;
- case VT_UI8: size = (UInt64)prop.uhVal.QuadPart; break;
- case VT_EMPTY: return S_OK;
- default: return E_FAIL;
- }
- defined = true;
- return S_OK;
-}
-
-#endif
-
-HRESULT CArc::GetItemSize(UInt32 index, UInt64 &size, bool &defined) const
-{
- NCOM::CPropVariant prop;
- defined = false;
- size = 0;
- RINOK(Archive->GetProperty(index, kpidSize, &prop));
- switch (prop.vt)
- {
- case VT_UI1: size = prop.bVal; break;
- case VT_UI2: size = prop.uiVal; break;
- case VT_UI4: size = prop.ulVal; break;
- case VT_UI8: size = (UInt64)prop.uhVal.QuadPart; break;
- case VT_EMPTY: return S_OK;
- default: return E_FAIL;
- }
- defined = true;
- return S_OK;
-}
-
-HRESULT CArc::GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const
-{
- NCOM::CPropVariant prop;
- defined = false;
- ft.dwHighDateTime = ft.dwLowDateTime = 0;
- RINOK(Archive->GetProperty(index, kpidMTime, &prop));
- if (prop.vt == VT_FILETIME)
- {
- ft = prop.filetime;
- defined = true;
- }
- else if (prop.vt != VT_EMPTY)
- return E_FAIL;
- else if (MTimeDefined)
- {
- ft = MTime;
- defined = true;
- }
- return S_OK;
-}
-
-#ifndef _SFX
-
-static inline bool TestSignature(const Byte *p1, const Byte *p2, size_t size)
-{
- for (size_t i = 0; i < size; i++)
- if (p1[i] != p2[i])
- return false;
- return true;
-}
-
-static void MakeCheckOrder(CCodecs *codecs,
- CIntVector &orderIndices, unsigned numTypes, CIntVector &orderIndices2,
- const Byte *data, size_t dataSize)
-{
- for (unsigned i = 0; i < numTypes; i++)
- {
- int index = orderIndices[i];
- if (index < 0)
- continue;
- const CArcInfoEx &ai = codecs->Formats[(unsigned)index];
- if (ai.SignatureOffset != 0)
- {
- orderIndices2.Add(index);
- orderIndices[i] = -1;
- continue;
- }
-
- const CObjectVector<CByteBuffer> &sigs = ai.Signatures;
- FOR_VECTOR (k, sigs)
- {
- const CByteBuffer &sig = sigs[k];
- if (sig.Size() == 0 && dataSize == 0 ||
- sig.Size() != 0 && sig.Size() <= dataSize &&
- TestSignature(data, sig, sig.Size()))
- {
- orderIndices2.Add(index);
- orderIndices[i] = -1;
- break;
- }
- }
- }
-}
-
-#endif
-
-#ifdef UNDER_CE
- static const unsigned kNumHashBytes = 1;
- #define HASH_VAL(buf) ((buf)[0])
-#else
- static const unsigned kNumHashBytes = 2;
- // #define HASH_VAL(buf) ((buf)[0] | ((UInt32)(buf)[1] << 8))
- #define HASH_VAL(buf) GetUi16(buf)
-#endif
-
-
-#ifndef _SFX
-
-static bool IsExeExt(const UString &ext)
-{
- return ext.IsEqualTo_Ascii_NoCase("exe");
-}
-
-static const char * const k_PreArcFormats[] =
-{
- "pe"
- , "elf"
- , "macho"
- , "mub"
- , "te"
-};
-
-static bool IsNameFromList(const UString &s, const char * const names[], size_t num)
-{
- for (unsigned i = 0; i < num; i++)
- if (StringsAreEqualNoCase_Ascii(s, names[i]))
- return true;
- return false;
-}
-
-
-static bool IsPreArcFormat(const CArcInfoEx &ai)
-{
- if (ai.Flags_PreArc())
- return true;
- return IsNameFromList(ai.Name, k_PreArcFormats, ARRAY_SIZE(k_PreArcFormats));
-}
-
-static const char * const k_Formats_with_simple_signuature[] =
-{
- "7z"
- , "xz"
- , "rar"
- , "bzip2"
- , "gzip"
- , "cab"
- , "wim"
- , "rpm"
- , "vhd"
- , "xar"
-};
-
-static bool IsNewStyleSignature(const CArcInfoEx &ai)
-{
- // if (ai.Version >= 0x91F)
- if (ai.NewInterface)
- return true;
- return IsNameFromList(ai.Name, k_Formats_with_simple_signuature, ARRAY_SIZE(k_Formats_with_simple_signuature));
-}
-
-class CArchiveOpenCallback_Offset:
- public IArchiveOpenCallback,
- public IArchiveOpenVolumeCallback,
- #ifndef _NO_CRYPTO
- public ICryptoGetTextPassword,
- #endif
- public CMyUnknownImp
-{
-public:
- CMyComPtr<IArchiveOpenCallback> Callback;
- CMyComPtr<IArchiveOpenVolumeCallback> OpenVolumeCallback;
- UInt64 Files;
- UInt64 Offset;
-
- #ifndef _NO_CRYPTO
- CMyComPtr<ICryptoGetTextPassword> GetTextPassword;
- #endif
-
- MY_QUERYINTERFACE_BEGIN2(IArchiveOpenCallback)
- MY_QUERYINTERFACE_ENTRY(IArchiveOpenVolumeCallback)
- #ifndef _NO_CRYPTO
- MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword)
- #endif
- MY_QUERYINTERFACE_END
- MY_ADDREF_RELEASE
-
- INTERFACE_IArchiveOpenCallback(;)
- INTERFACE_IArchiveOpenVolumeCallback(;)
- #ifndef _NO_CRYPTO
- STDMETHOD(CryptoGetTextPassword)(BSTR *password);
- #endif
-};
-
-#ifndef _NO_CRYPTO
-STDMETHODIMP CArchiveOpenCallback_Offset::CryptoGetTextPassword(BSTR *password)
-{
- COM_TRY_BEGIN
- if (GetTextPassword)
- return GetTextPassword->CryptoGetTextPassword(password);
- return E_NOTIMPL;
- COM_TRY_END
-}
-#endif
-
-STDMETHODIMP CArchiveOpenCallback_Offset::SetTotal(const UInt64 *, const UInt64 *)
-{
- return S_OK;
-}
-
-STDMETHODIMP CArchiveOpenCallback_Offset::SetCompleted(const UInt64 *, const UInt64 *bytes)
-{
- if (!Callback)
- return S_OK;
- UInt64 value = Offset;
- if (bytes)
- value += *bytes;
- return Callback->SetCompleted(&Files, &value);
-}
-
-STDMETHODIMP CArchiveOpenCallback_Offset::GetProperty(PROPID propID, PROPVARIANT *value)
-{
- if (OpenVolumeCallback)
- return OpenVolumeCallback->GetProperty(propID, value);
- NCOM::PropVariant_Clear(value);
- return S_OK;
- // return E_NOTIMPL;
-}
-
-STDMETHODIMP CArchiveOpenCallback_Offset::GetStream(const wchar_t *name, IInStream **inStream)
-{
- if (OpenVolumeCallback)
- return OpenVolumeCallback->GetStream(name, inStream);
- return S_FALSE;
-}
-
-#endif
-
-
-UInt32 GetOpenArcErrorFlags(const NCOM::CPropVariant &prop, bool *isDefinedProp)
-{
- if (isDefinedProp != NULL)
- *isDefinedProp = false;
-
- switch (prop.vt)
- {
- case VT_UI8: if (isDefinedProp) *isDefinedProp = true; return (UInt32)prop.uhVal.QuadPart;
- case VT_UI4: if (isDefinedProp) *isDefinedProp = true; return prop.ulVal;
- case VT_EMPTY: return 0;
- default: throw 151199;
- }
-}
-
-void CArcErrorInfo::ClearErrors()
-{
- // ErrorFormatIndex = -1; // we don't need to clear ErrorFormatIndex here !!!
-
- ThereIsTail = false;
- UnexpecedEnd = false;
- IgnoreTail = false;
- // NonZerosTail = false;
- ErrorFlags_Defined = false;
- ErrorFlags = 0;
- WarningFlags = 0;
- TailSize = 0;
-
- ErrorMessage.Empty();
- WarningMessage.Empty();
-}
-
-HRESULT CArc::ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes)
-{
- // OkPhySize_Defined = false;
- PhySizeDefined = false;
- PhySize = 0;
- Offset = 0;
- AvailPhySize = FileSize - startPos;
-
- ErrorInfo.ClearErrors();
- {
- NCOM::CPropVariant prop;
- RINOK(archive->GetArchiveProperty(kpidErrorFlags, &prop));
- ErrorInfo.ErrorFlags = GetOpenArcErrorFlags(prop, &ErrorInfo.ErrorFlags_Defined);
- }
- {
- NCOM::CPropVariant prop;
- RINOK(archive->GetArchiveProperty(kpidWarningFlags, &prop));
- ErrorInfo.WarningFlags = GetOpenArcErrorFlags(prop);
- }
-
- {
- NCOM::CPropVariant prop;
- RINOK(archive->GetArchiveProperty(kpidError, &prop));
- if (prop.vt != VT_EMPTY)
- ErrorInfo.ErrorMessage = (prop.vt == VT_BSTR ? prop.bstrVal : L"Unknown error");
- }
-
- {
- NCOM::CPropVariant prop;
- RINOK(archive->GetArchiveProperty(kpidWarning, &prop));
- if (prop.vt != VT_EMPTY)
- ErrorInfo.WarningMessage = (prop.vt == VT_BSTR ? prop.bstrVal : L"Unknown warning");
- }
-
- if (openRes == S_OK || ErrorInfo.IsArc_After_NonOpen())
- {
- RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, PhySize, PhySizeDefined));
- /*
- RINOK(Archive_GetArcProp_UInt(archive, kpidOkPhySize, OkPhySize, OkPhySize_Defined));
- if (!OkPhySize_Defined)
- {
- OkPhySize_Defined = PhySizeDefined;
- OkPhySize = PhySize;
- }
- */
-
- bool offsetDefined;
- RINOK(Archive_GetArcProp_Int(archive, kpidOffset, Offset, offsetDefined));
-
- Int64 globalOffset = startPos + Offset;
- AvailPhySize = FileSize - globalOffset;
- if (PhySizeDefined)
- {
- UInt64 endPos = globalOffset + PhySize;
- if (endPos < FileSize)
- {
- AvailPhySize = PhySize;
- ErrorInfo.ThereIsTail = true;
- ErrorInfo.TailSize = FileSize - endPos;
- }
- else if (endPos > FileSize)
- ErrorInfo.UnexpecedEnd = true;
- }
- }
-
- return S_OK;
-}
-
-/*
-static PrintNumber(const char *s, int n)
-{
- char temp[100];
- sprintf(temp, "%s %d", s, n);
- OutputDebugStringA(temp);
-}
-*/
-
-HRESULT CArc::PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr<IInArchive> &archive)
-{
- // OutputDebugStringA("a1");
- // PrintNumber("formatIndex", formatIndex);
-
- RINOK(op.codecs->CreateInArchive(formatIndex, archive));
- // OutputDebugStringA("a2");
- if (!archive)
- return S_OK;
-
- #ifdef EXTERNAL_CODECS
- if (op.codecs->NeedSetLibCodecs)
- {
- const CArcInfoEx &ai = op.codecs->Formats[formatIndex];
- if (ai.LibIndex >= 0 ?
- !op.codecs->Libs[ai.LibIndex].SetCodecs :
- !op.codecs->Libs.IsEmpty())
- {
- CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
- archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
- if (setCompressCodecsInfo)
- {
- RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(op.codecs));
- }
- }
- }
- #endif
-
-
- #ifndef _SFX
-
- const CArcInfoEx &ai = op.codecs->Formats[formatIndex];
-
- // OutputDebugStringW(ai.Name);
- // OutputDebugStringA("a3");
-
- if (ai.Flags_PreArc())
- {
- /* we notify parsers that extract executables, that they don't need
- to open archive, if there is tail after executable (for SFX cases) */
- CMyComPtr<IArchiveAllowTail> allowTail;
- archive.QueryInterface(IID_IArchiveAllowTail, (void **)&allowTail);
- if (allowTail)
- allowTail->AllowTail(BoolToInt(true));
- }
-
- if (op.props)
- {
- /*
- FOR_VECTOR (y, op.props)
- {
- const COptionalOpenProperties &optProps = (*op.props)[y];
- if (optProps.FormatName.IsEmpty() || optProps.FormatName.CompareNoCase(ai.Name) == 0)
- {
- RINOK(SetProperties(archive, optProps.Props));
- break;
- }
- }
- */
- RINOK(SetProperties(archive, *op.props));
- }
-
- #endif
- return S_OK;
-}
-
-#ifndef _SFX
-
-static HRESULT ReadParseItemProps(IInArchive *archive, const CArcInfoEx &ai, NArchive::NParser::CParseItem &pi)
-{
- pi.Extension = ai.GetMainExt();
- pi.FileTime_Defined = false;
- pi.ArcType = ai.Name;
-
- RINOK(Archive_GetArcBoolProp(archive, kpidIsNotArcType, pi.IsNotArcType));
-
- // RINOK(Archive_GetArcBoolProp(archive, kpidIsSelfExe, pi.IsSelfExe));
- pi.IsSelfExe = ai.Flags_PreArc();
-
- {
- NCOM::CPropVariant prop;
- RINOK(archive->GetArchiveProperty(kpidMTime, &prop));
- if (prop.vt == VT_FILETIME)
- {
- pi.FileTime_Defined = true;
- pi.FileTime = prop.filetime;
- }
- }
-
- if (!pi.FileTime_Defined)
- {
- NCOM::CPropVariant prop;
- RINOK(archive->GetArchiveProperty(kpidCTime, &prop));
- if (prop.vt == VT_FILETIME)
- {
- pi.FileTime_Defined = true;
- pi.FileTime = prop.filetime;
- }
- }
-
- {
- NCOM::CPropVariant prop;
- RINOK(archive->GetArchiveProperty(kpidName, &prop));
- if (prop.vt == VT_BSTR)
- {
- pi.Name.SetFromBstr(prop.bstrVal);
- pi.Extension.Empty();
- }
- else
- {
- RINOK(archive->GetArchiveProperty(kpidExtension, &prop));
- if (prop.vt == VT_BSTR)
- pi.Extension.SetFromBstr(prop.bstrVal);
- }
- }
-
- {
- NCOM::CPropVariant prop;
- RINOK(archive->GetArchiveProperty(kpidShortComment, &prop));
- if (prop.vt == VT_BSTR)
- pi.Comment.SetFromBstr(prop.bstrVal);
- }
-
-
- UInt32 numItems;
- RINOK(archive->GetNumberOfItems(&numItems));
-
- // pi.NumSubFiles = numItems;
- // RINOK(Archive_GetArcProp_UInt(archive, kpidUnpackSize, pi.UnpackSize, pi.UnpackSize_Defined));
- // if (!pi.UnpackSize_Defined)
- {
- pi.NumSubFiles = 0;
- pi.NumSubDirs = 0;
- pi.UnpackSize = 0;
- for (UInt32 i = 0; i < numItems; i++)
- {
- UInt64 size = 0;
- bool defined = false;
- Archive_GetItem_Size(archive, i, size, defined);
- if (defined)
- {
- pi.UnpackSize_Defined = true;
- pi.UnpackSize += size;
- }
-
- bool isDir = false;
- Archive_IsItem_Dir(archive, i, isDir);
- if (isDir)
- pi.NumSubDirs++;
- else
- pi.NumSubFiles++;
- }
- if (pi.NumSubDirs != 0)
- pi.NumSubDirs_Defined = true;
- pi.NumSubFiles_Defined = true;
- }
-
- return S_OK;
-}
-
-#endif
-
-HRESULT CArc::CheckZerosTail(const COpenOptions &op, UInt64 offset)
-{
- if (!op.stream)
- return S_OK;
- RINOK(op.stream->Seek(offset, STREAM_SEEK_SET, NULL));
- const UInt32 kBufSize = 1 << 11;
- Byte buf[kBufSize];
-
- for (;;)
- {
- UInt32 processed = 0;
- RINOK(op.stream->Read(buf, kBufSize, &processed));
- if (processed == 0)
- {
- // ErrorInfo.NonZerosTail = false;
- ErrorInfo.IgnoreTail = true;
- return S_OK;
- }
- for (size_t i = 0; i < processed; i++)
- {
- if (buf[i] != 0)
- {
- // ErrorInfo.IgnoreTail = false;
- // ErrorInfo.NonZerosTail = true;
- return S_OK;
- }
- }
- }
-}
-
-#ifndef _SFX
-
-class CExtractCallback_To_OpenCallback:
- public IArchiveExtractCallback,
- public ICompressProgressInfo,
- public CMyUnknownImp
-{
-public:
- CMyComPtr<IArchiveOpenCallback> Callback;
- UInt64 Files;
- UInt64 Offset;
-
- MY_UNKNOWN_IMP2(IArchiveExtractCallback, ICompressProgressInfo)
- INTERFACE_IArchiveExtractCallback(;)
- STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
- void Init(IArchiveOpenCallback *callback)
- {
- Callback = callback;
- Files = 0;
- Offset = 0;
- }
-};
-
-STDMETHODIMP CExtractCallback_To_OpenCallback::SetTotal(UInt64 /* size */)
-{
- return S_OK;
-}
-
-STDMETHODIMP CExtractCallback_To_OpenCallback::SetCompleted(const UInt64 * /* completeValue */)
-{
- return S_OK;
-}
-
-STDMETHODIMP CExtractCallback_To_OpenCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */)
-{
- if (Callback)
- {
- UInt64 value = Offset;
- if (inSize)
- value += *inSize;
- return Callback->SetCompleted(&Files, &value);
- }
- return S_OK;
-}
-
-STDMETHODIMP CExtractCallback_To_OpenCallback::GetStream(UInt32 /* index */, ISequentialOutStream **outStream, Int32 /* askExtractMode */)
-{
- *outStream = 0;
- return S_OK;
-}
-
-STDMETHODIMP CExtractCallback_To_OpenCallback::PrepareOperation(Int32 /* askExtractMode */)
-{
- return S_OK;
-}
-
-STDMETHODIMP CExtractCallback_To_OpenCallback::SetOperationResult(Int32 /* operationResult */)
-{
- return S_OK;
-}
-
-static HRESULT OpenArchiveSpec(IInArchive *archive, bool needPhySize,
- IInStream *stream, const UInt64 *maxCheckStartPosition,
- IArchiveOpenCallback *openCallback,
- IArchiveExtractCallback *extractCallback)
-{
- /*
- if (needPhySize)
- {
- CMyComPtr<IArchiveOpen2> open2;
- archive->QueryInterface(IID_IArchiveOpen2, (void **)&open2);
- if (open2)
- return open2->ArcOpen2(stream, kOpenFlags_RealPhySize, openCallback);
- }
- */
- RINOK(archive->Open(stream, maxCheckStartPosition, openCallback));
- if (needPhySize)
- {
- bool phySize_Defined = false;
- UInt64 phySize = 0;
- RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, phySize, phySize_Defined));
- if (phySize_Defined)
- return S_OK;
-
- bool phySizeCantBeDetected = false;;
- RINOK(Archive_GetArcBoolProp(archive, kpidPhySizeCantBeDetected, phySizeCantBeDetected));
-
- if (!phySizeCantBeDetected)
- {
- RINOK(archive->Extract(0, (UInt32)(Int32)-1, BoolToInt(true), extractCallback));
- }
- }
- return S_OK;
-}
-
-static int FindFormatForArchiveType(CCodecs *codecs, CIntVector orderIndices, const char *name)
-{
- FOR_VECTOR (i, orderIndices)
- if (StringsAreEqualNoCase_Ascii(codecs->Formats[orderIndices[i]].Name, name))
- return i;
- return -1;
-}
-
-#endif
-
-HRESULT CArc::OpenStream2(const COpenOptions &op)
-{
- // fprintf(stdout, "\nOpen: %S", Path); fflush(stdout);
-
- Archive.Release();
- GetRawProps.Release();
- GetRootProps.Release();
-
- ErrorInfo.ClearErrors();
- ErrorInfo.ErrorFormatIndex = -1;
-
- IsParseArc = false;
- ArcStreamOffset = 0;
-
- // OutputDebugStringA("1");
- // OutputDebugStringW(Path);
-
- const UString fileName = ExtractFileNameFromPath(Path);
- UString extension;
- {
- int dotPos = fileName.ReverseFind_Dot();
- if (dotPos >= 0)
- extension = fileName.Ptr(dotPos + 1);
- }
-
- CIntVector orderIndices;
-
- bool searchMarkerInHandler = false;
- #ifdef _SFX
- searchMarkerInHandler = true;
- #endif
-
- CBoolArr isMainFormatArr(op.codecs->Formats.Size());
- {
- FOR_VECTOR(i, op.codecs->Formats)
- isMainFormatArr[i] = false;
- }
-
- UInt64 maxStartOffset =
- op.openType.MaxStartOffset_Defined ?
- op.openType.MaxStartOffset :
- kMaxCheckStartPosition;
-
- #ifndef _SFX
- bool isUnknownExt = false;
- #endif
-
- bool isForced = false;
- unsigned numMainTypes = 0;
- int formatIndex = op.openType.FormatIndex;
-
- if (formatIndex >= 0)
- {
- isForced = true;
- orderIndices.Add(formatIndex);
- numMainTypes = 1;
- isMainFormatArr[(unsigned)formatIndex] = true;
-
- searchMarkerInHandler = true;
- }
- else
- {
- unsigned numFinded = 0;
- #ifndef _SFX
- bool isPrearcExt = false;
- #endif
-
- {
- #ifndef _SFX
-
- bool isZip = false;
- bool isRar = false;
-
- const wchar_t c = extension[0];
- if (c == 'z' || c == 'Z' || c == 'r' || c == 'R')
- {
- bool isNumber = false;
- for (unsigned k = 1;; k++)
- {
- const wchar_t d = extension[k];
- if (d == 0)
- break;
- if (d < '0' || d > '9')
- {
- isNumber = false;
- break;
- }
- isNumber = true;
- }
- if (isNumber)
- if (c == 'z' || c == 'Z')
- isZip = true;
- else
- isRar = true;
- }
-
- #endif
-
- FOR_VECTOR (i, op.codecs->Formats)
- {
- const CArcInfoEx &ai = op.codecs->Formats[i];
-
- if (IgnoreSplit || !op.openType.CanReturnArc)
- if (ai.IsSplit())
- continue;
- if (op.excludedFormats->FindInSorted(i) >= 0)
- continue;
-
- #ifndef _SFX
- if (IsPreArcFormat(ai))
- isPrearcExt = true;
- #endif
-
- if (ai.FindExtension(extension) >= 0
- #ifndef _SFX
- || isZip && StringsAreEqualNoCase_Ascii(ai.Name, "zip")
- || isRar && StringsAreEqualNoCase_Ascii(ai.Name, "rar")
- #endif
- )
- {
- // PrintNumber("orderIndices.Insert", i);
- orderIndices.Insert(numFinded++, i);
- isMainFormatArr[i] = true;
- }
- else
- orderIndices.Add(i);
- }
- }
-
- if (!op.stream)
- {
- if (numFinded != 1)
- return E_NOTIMPL;
- orderIndices.DeleteFrom(1);
- }
- // PrintNumber("numFinded", numFinded );
-
- /*
- if (op.openOnlySpecifiedByExtension)
- {
- if (numFinded != 0 && !IsExeExt(extension))
- orderIndices.DeleteFrom(numFinded);
- }
- */
-
- #ifndef _SFX
-
- if (op.stream && orderIndices.Size() >= 2)
- {
- RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
- CByteBuffer byteBuffer;
- CIntVector orderIndices2;
- if (numFinded == 0 || IsExeExt(extension))
- {
- // signature search was here
- }
- else if (extension.IsEqualTo("000") || extension.IsEqualTo("001"))
- {
- int i = FindFormatForArchiveType(op.codecs, orderIndices, "rar");
- if (i >= 0)
- {
- const size_t kBufSize = (1 << 10);
- byteBuffer.Alloc(kBufSize);
- size_t processedSize = kBufSize;
- RINOK(ReadStream(op.stream, byteBuffer, &processedSize));
- if (processedSize >= 16)
- {
- const Byte *buf = byteBuffer;
- const Byte kRarHeader[] = { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 };
- if (TestSignature(buf, kRarHeader, 7) && buf[9] == 0x73 && (buf[10] & 1) != 0)
- {
- orderIndices2.Add(orderIndices[i]);
- orderIndices[i] = -1;
- if (i >= (int)numFinded)
- numFinded++;
- }
- }
- }
- }
- else
- {
- const size_t kBufSize = (1 << 10);
- byteBuffer.Alloc(kBufSize);
- size_t processedSize = kBufSize;
- RINOK(ReadStream(op.stream, byteBuffer, &processedSize));
- if (processedSize == 0)
- return S_FALSE;
-
- /*
- check type order:
- 1) matched extension, no signuature
- 2) matched extension, matched signuature
- // 3) no signuature
- // 4) matched signuature
- */
-
- MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, NULL, 0);
- MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, byteBuffer, processedSize);
- // MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, NULL, 0);
- // MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, byteBuffer, processedSize);
- }
-
- FOR_VECTOR (i, orderIndices)
- {
- int val = orderIndices[i];
- if (val != -1)
- orderIndices2.Add(val);
- }
- orderIndices = orderIndices2;
- }
-
- if (orderIndices.Size() >= 2)
- {
- int iIso = FindFormatForArchiveType(op.codecs, orderIndices, "iso");
- int iUdf = FindFormatForArchiveType(op.codecs, orderIndices, "udf");
- if (iUdf > iIso && iIso >= 0)
- {
- int isoIndex = orderIndices[iIso];
- int udfIndex = orderIndices[iUdf];
- orderIndices[iUdf] = isoIndex;
- orderIndices[iIso] = udfIndex;
- }
- }
-
- numMainTypes = numFinded;
- isUnknownExt = (numMainTypes == 0) || isPrearcExt;
-
- #else // _SFX
-
- numMainTypes = orderIndices.Size();
-
- // we need correct numMainTypes for mutlivolume SFX (if some volume is missing)
- if (numFinded != 0)
- numMainTypes = numFinded;
-
- #endif
- }
-
- UInt64 fileSize = 0;
- if (op.stream)
- {
- RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize));
- RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
- }
- FileSize = fileSize;
-
-
- #ifndef _SFX
-
- CBoolArr skipFrontalFormat(op.codecs->Formats.Size());
- {
- FOR_VECTOR(i, op.codecs->Formats)
- skipFrontalFormat[i] = false;
- }
-
- #endif
-
- const COpenType &mode = op.openType;
-
-
-
-
-
- if (mode.CanReturnArc)
- {
- // ---------- OPEN main type by extenssion ----------
-
- unsigned numCheckTypes = orderIndices.Size();
- if (formatIndex >= 0)
- numCheckTypes = numMainTypes;
-
- for (unsigned i = 0; i < numCheckTypes; i++)
- {
- FormatIndex = orderIndices[i];
-
- bool exactOnly = false;
-
- #ifndef _SFX
-
- const CArcInfoEx &ai = op.codecs->Formats[FormatIndex];
- // OutputDebugStringW(ai.Name);
- if (i >= numMainTypes)
- {
- if (!ai.Flags_BackwardOpen()
- // && !ai.Flags_PureStartOpen()
- )
- continue;
- exactOnly = true;
- }
-
- #endif
-
- // Some handlers do not set total bytes. So we set it here
- if (op.callback)
- RINOK(op.callback->SetTotal(NULL, &fileSize));
-
- if (op.stream)
- {
- RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
- }
-
- CMyComPtr<IInArchive> archive;
-
- RINOK(PrepareToOpen(op, FormatIndex, archive));
- if (!archive)
- continue;
-
- HRESULT result;
- if (op.stream)
- {
- UInt64 searchLimit = (!exactOnly && searchMarkerInHandler) ? maxStartOffset: 0;
- result = archive->Open(op.stream, &searchLimit, op.callback);
- }
- else
- {
- CMyComPtr<IArchiveOpenSeq> openSeq;
- archive.QueryInterface(IID_IArchiveOpenSeq, (void **)&openSeq);
- if (!openSeq)
- return E_NOTIMPL;
- result = openSeq->OpenSeq(op.seqStream);
- }
-
- RINOK(ReadBasicProps(archive, 0, result));
-
- if (result == S_FALSE)
- {
- bool isArc = ErrorInfo.IsArc_After_NonOpen();
-
- #ifndef _SFX
- // if it's archive, we allow another open attempt for parser
- if (!mode.CanReturnParser || !isArc)
- skipFrontalFormat[(unsigned)FormatIndex] = true;
- #endif
-
- if (exactOnly)
- continue;
-
- if (i == 0 && numMainTypes == 1)
- {
- // we set NonOpenErrorInfo, only if there is only one main format (defined by extension).
- ErrorInfo.ErrorFormatIndex = FormatIndex;
- NonOpen_ErrorInfo = ErrorInfo;
-
- if (!mode.CanReturnParser && isArc)
- {
- // if (formatIndex < 0 && !searchMarkerInHandler)
- {
- // if bad archive was detected, we don't need additional open attempts
- #ifndef _SFX
- if (!IsPreArcFormat(ai) /* || !mode.SkipSfxStub */)
- #endif
- return S_FALSE;
- }
- }
- }
-
- /*
- #ifndef _SFX
- if (IsExeExt(extension) || ai.Flags_PreArc())
- {
- // openOnlyFullArc = false;
- // canReturnTailArc = true;
- // limitSignatureSearch = true;
- }
- #endif
- */
-
- continue;
- }
-
- RINOK(result);
-
- #ifndef _SFX
-
- bool isMainFormat = isMainFormatArr[(unsigned)FormatIndex];
- const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt);
-
- bool thereIsTail = ErrorInfo.ThereIsTail;
- if (thereIsTail && mode.ZerosTailIsAllowed)
- {
- RINOK(CheckZerosTail(op, Offset + PhySize));
- if (ErrorInfo.IgnoreTail)
- thereIsTail = false;
- }
-
- if (Offset > 0)
- {
- if (exactOnly
- || !searchMarkerInHandler
- || !specFlags.CanReturn_NonStart()
- || (mode.MaxStartOffset_Defined && (UInt64)Offset > mode.MaxStartOffset))
- continue;
- }
- if (thereIsTail)
- {
- if (Offset > 0)
- {
- if (!specFlags.CanReturnMid)
- continue;
- }
- else if (!specFlags.CanReturnFrontal)
- continue;
- }
-
- if (Offset > 0 || thereIsTail)
- {
- if (formatIndex < 0)
- {
- if (IsPreArcFormat(ai))
- {
- // openOnlyFullArc = false;
- // canReturnTailArc = true;
- /*
- if (mode.SkipSfxStub)
- limitSignatureSearch = true;
- */
- // if (mode.SkipSfxStub)
- {
- // skipFrontalFormat[FormatIndex] = true;
- continue;
- }
- }
- }
- }
-
- #endif
-
- Archive = archive;
- return S_OK;
- }
- }
-
-
-
- #ifndef _SFX
-
- if (!op.stream)
- return S_FALSE;
-
- if (formatIndex >= 0 && !mode.CanReturnParser)
- {
- if (mode.MaxStartOffset_Defined)
- {
- if (mode.MaxStartOffset == 0)
- return S_FALSE;
- }
- else
- {
- const CArcInfoEx &ai = op.codecs->Formats[(unsigned)formatIndex];
- if (ai.FindExtension(extension) >= 0)
- {
- if (ai.Flags_FindSignature() && searchMarkerInHandler)
- return S_FALSE;
- }
- }
- }
-
- NArchive::NParser::CHandler *handlerSpec = new NArchive::NParser::CHandler;
- CMyComPtr<IInArchive> handler = handlerSpec;
-
- CExtractCallback_To_OpenCallback *extractCallback_To_OpenCallback_Spec = new CExtractCallback_To_OpenCallback;
- CMyComPtr<IArchiveExtractCallback> extractCallback_To_OpenCallback = extractCallback_To_OpenCallback_Spec;
- extractCallback_To_OpenCallback_Spec->Init(op.callback);
-
- {
- // ---------- Check all possible START archives ----------
- // this code is better for full file archives than Parser's code.
-
- CByteBuffer byteBuffer;
- bool endOfFile = false;
- size_t processedSize;
- {
- size_t bufSize = 1 << 20; // it must be larger than max signature offset or IsArcFunc offset ((1 << 19) + x for UDF)
- if (bufSize > fileSize)
- {
- bufSize = (size_t)fileSize;
- endOfFile = true;
- }
- byteBuffer.Alloc(bufSize);
- RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
- processedSize = bufSize;
- RINOK(ReadStream(op.stream, byteBuffer, &processedSize));
- if (processedSize == 0)
- return S_FALSE;
- if (processedSize < bufSize)
- endOfFile = true;
- }
- CUIntVector sortedFormats;
-
- unsigned i;
-
- int splitIndex = -1;
-
- for (i = 0; i < orderIndices.Size(); i++)
- {
- unsigned form = orderIndices[i];
- if (skipFrontalFormat[form])
- continue;
- const CArcInfoEx &ai = op.codecs->Formats[form];
- if (ai.IsSplit())
- {
- splitIndex = form;
- continue;
- }
-
- if (ai.IsArcFunc)
- {
- UInt32 isArcRes = ai.IsArcFunc(byteBuffer, processedSize);
- if (isArcRes == k_IsArc_Res_NO)
- continue;
- if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile)
- continue;
- // if (isArcRes == k_IsArc_Res_YES_LOW_PROB) continue;
- sortedFormats.Insert(0, form);
- continue;
- }
-
- bool isNewStyleSignature = IsNewStyleSignature(ai);
- bool needCheck = !isNewStyleSignature
- || ai.Signatures.IsEmpty()
- || ai.Flags_PureStartOpen()
- || ai.Flags_StartOpen()
- || ai.Flags_BackwardOpen();
-
- if (isNewStyleSignature && !ai.Signatures.IsEmpty())
- {
- unsigned k;
- for (k = 0; k < ai.Signatures.Size(); k++)
- {
- const CByteBuffer &sig = ai.Signatures[k];
- UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size();
- if (processedSize < signatureEnd)
- {
- if (!endOfFile)
- needCheck = true;
- }
- else if (memcmp(sig, byteBuffer + ai.SignatureOffset, sig.Size()) == 0)
- break;
- }
- if (k != ai.Signatures.Size())
- {
- sortedFormats.Insert(0, form);
- continue;
- }
- }
- if (needCheck)
- sortedFormats.Add(form);
- }
-
- if (splitIndex >= 0)
- sortedFormats.Insert(0, splitIndex);
-
- for (i = 0; i < sortedFormats.Size(); i++)
- {
- FormatIndex = sortedFormats[i];
- const CArcInfoEx &ai = op.codecs->Formats[FormatIndex];
-
- if (op.callback)
- RINOK(op.callback->SetTotal(NULL, &fileSize));
-
- RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
-
- CMyComPtr<IInArchive> archive;
- RINOK(PrepareToOpen(op, FormatIndex, archive));
- if (!archive)
- continue;
-
- PRF(printf("\nSorted Open %S", (const wchar_t *)ai.Name));
- HRESULT result;
- {
- UInt64 searchLimit = 0;
- /*
- if (mode.CanReturnArc)
- result = archive->Open(op.stream, &searchLimit, op.callback);
- else
- */
- result = OpenArchiveSpec(archive, !mode.CanReturnArc, op.stream, &searchLimit, op.callback, extractCallback_To_OpenCallback);
- }
-
- if (result == S_FALSE)
- {
- skipFrontalFormat[(unsigned)FormatIndex] = true;
- // FIXME: maybe we must use LenIsUnknown.
- // printf(" OpenForSize Error");
- continue;
- }
- RINOK(result);
-
- RINOK(ReadBasicProps(archive, 0, result));
-
- if (Offset > 0)
- {
- continue; // good handler doesn't return such Offset > 0
- // but there are some cases like false prefixed PK00 archive, when
- // we can support it?
- }
-
- NArchive::NParser::CParseItem pi;
- pi.Offset = Offset;
- pi.Size = AvailPhySize;
-
- // bool needScan = false;
-
- if (!PhySizeDefined)
- {
- // it's for Z format
- pi.LenIsUnknown = true;
- // needScan = true;
- // phySize = arcRem;
- // nextNeedCheckStartOpen = false;
- }
-
- /*
- if (OkPhySize_Defined)
- pi.OkSize = pi.OkPhySize;
- else
- pi.OkSize = pi.Size;
- */
-
- pi.NormalizeOffset();
- // printf(" phySize = %8d", (unsigned)phySize);
-
-
- if (mode.CanReturnArc)
- {
- bool isMainFormat = isMainFormatArr[(unsigned)FormatIndex];
- const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt);
- bool openCur = false;
-
- if (!ErrorInfo.ThereIsTail)
- openCur = true;
- else
- {
- if (mode.ZerosTailIsAllowed)
- {
- RINOK(CheckZerosTail(op, Offset + PhySize));
- if (ErrorInfo.IgnoreTail)
- openCur = true;
- }
- if (!openCur)
- {
- openCur = specFlags.CanReturnFrontal;
- if (formatIndex < 0) // format is not forced
- {
- if (IsPreArcFormat(ai))
- {
- // if (mode.SkipSfxStub)
- {
- openCur = false;
- }
- }
- }
- }
- }
-
- if (openCur)
- {
- InStream = op.stream;
- Archive = archive;
- return S_OK;
- }
- }
-
- skipFrontalFormat[(unsigned)FormatIndex] = true;
-
-
- // if (!mode.CanReturnArc)
- /*
- if (!ErrorInfo.ThereIsTail)
- continue;
- */
- if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize)
- continue;
-
- // printf("\nAdd offset = %d", (int)pi.Offset);
- RINOK(ReadParseItemProps(archive, ai, pi));
- handlerSpec->AddItem(pi);
- }
- }
-
-
-
-
-
- // ---------- PARSER ----------
-
- CUIntVector arc2sig; // formatIndex to signatureIndex
- CUIntVector sig2arc; // signatureIndex to formatIndex;
- {
- unsigned sum = 0;
- FOR_VECTOR (i, op.codecs->Formats)
- {
- arc2sig.Add(sum);
- const CObjectVector<CByteBuffer> &sigs = op.codecs->Formats[i].Signatures;
- sum += sigs.Size();
- FOR_VECTOR (k, sigs)
- sig2arc.Add(i);
- }
- }
-
- {
- const size_t kBeforeSize = 1 << 16;
- const size_t kAfterSize = 1 << 20;
- const size_t kBufSize = 1 << 22; // it must be more than kBeforeSize + kAfterSize
-
- const UInt32 kNumVals = (UInt32)1 << (kNumHashBytes * 8);
- CByteArr hashBuffer(kNumVals);
- Byte *hash = hashBuffer;
- memset(hash, 0xFF, kNumVals);
- Byte prevs[256];
- memset(prevs, 0xFF, sizeof(prevs));
- if (sig2arc.Size() >= 0xFF)
- return S_FALSE;
-
- CUIntVector difficultFormats;
- CBoolArr difficultBools(256);
- {
- for (unsigned i = 0; i < 256; i++)
- difficultBools[i] = false;
- }
-
- bool thereAreHandlersForSearch = false;
-
- // UInt32 maxSignatureEnd = 0;
-
- FOR_VECTOR (i, orderIndices)
- {
- int index = orderIndices[i];
- if (index < 0)
- continue;
- const CArcInfoEx &ai = op.codecs->Formats[(unsigned)index];
- bool isDifficult = false;
- // if (ai.Version < 0x91F) // we don't use parser with old DLL (before 9.31)
- if (!ai.NewInterface)
- isDifficult = true;
- else
- {
- if (ai.Flags_StartOpen())
- isDifficult = true;
- FOR_VECTOR (k, ai.Signatures)
- {
- const CByteBuffer &sig = ai.Signatures[k];
- /*
- UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size();
- if (maxSignatureEnd < signatureEnd)
- maxSignatureEnd = signatureEnd;
- */
- if (sig.Size() < kNumHashBytes)
- {
- isDifficult = true;
- continue;
- }
- thereAreHandlersForSearch = true;
- UInt32 v = HASH_VAL(sig);
- unsigned sigIndex = arc2sig[(unsigned)index] + k;
- prevs[sigIndex] = hash[v];
- hash[v] = (Byte)sigIndex;
- }
- }
- if (isDifficult)
- {
- difficultFormats.Add(index);
- difficultBools[(unsigned)index] = true;
- }
- }
-
- if (!thereAreHandlersForSearch)
- {
- // openOnlyFullArc = true;
- // canReturnTailArc = true;
- }
-
- RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
-
- CLimitedCachedInStream *limitedStreamSpec = new CLimitedCachedInStream;
- CMyComPtr<IInStream> limitedStream = limitedStreamSpec;
- limitedStreamSpec->SetStream(op.stream);
-
- CArchiveOpenCallback_Offset *openCallback_Offset_Spec = NULL;
- CMyComPtr<IArchiveOpenCallback> openCallback_Offset;
- if (op.callback)
- {
- openCallback_Offset_Spec = new CArchiveOpenCallback_Offset;
- openCallback_Offset = openCallback_Offset_Spec;
- openCallback_Offset_Spec->Callback = op.callback;
- openCallback_Offset_Spec->Callback.QueryInterface(IID_IArchiveOpenVolumeCallback, &openCallback_Offset_Spec->OpenVolumeCallback);
- #ifndef _NO_CRYPTO
- openCallback_Offset_Spec->Callback.QueryInterface(IID_ICryptoGetTextPassword, &openCallback_Offset_Spec->GetTextPassword);
- #endif
- }
-
- if (op.callback)
- RINOK(op.callback->SetTotal(NULL, &fileSize));
-
- CByteBuffer &byteBuffer = limitedStreamSpec->Buffer;
- byteBuffer.Alloc(kBufSize);
-
- UInt64 callbackPrev = 0;
- bool needCheckStartOpen = true; // = true, if we need to test all archives types for current pos.
-
- bool endOfFile = false;
- UInt64 bufPhyPos = 0;
- size_t bytesInBuf = 0;
- // UInt64 prevPos = 0;
-
- // ---------- Main Scan Loop ----------
-
- UInt64 pos = 0;
-
- if (!mode.EachPos && handlerSpec->_items.Size() == 1)
- {
- NArchive::NParser::CParseItem &pi = handlerSpec->_items[0];
- if (!pi.LenIsUnknown && pi.Offset == 0)
- pos = pi.Size;
- }
-
- for (;;)
- {
- // printf("\nPos = %d", (int)pos);
- UInt64 posInBuf = pos - bufPhyPos;
-
- // if (pos > ((UInt64)1 << 35)) break;
-
- if (!endOfFile)
- {
- if (bytesInBuf < kBufSize)
- {
- size_t processedSize = kBufSize - bytesInBuf;
- // printf("\nRead ask = %d", (unsigned)processedSize);
- UInt64 seekPos = bufPhyPos + bytesInBuf;
- RINOK(op.stream->Seek(bufPhyPos + bytesInBuf, STREAM_SEEK_SET, NULL));
- RINOK(ReadStream(op.stream, byteBuffer + bytesInBuf, &processedSize));
- // printf(" processed = %d", (unsigned)processedSize);
- if (processedSize == 0)
- {
- fileSize = seekPos;
- endOfFile = true;
- }
- else
- {
- bytesInBuf += processedSize;
- limitedStreamSpec->SetCache(processedSize, (size_t)bufPhyPos);
- }
- continue;
- }
-
- if (bytesInBuf < posInBuf)
- {
- UInt64 skipSize = posInBuf - bytesInBuf;
- if (skipSize <= kBeforeSize)
- {
- size_t keepSize = (size_t)(kBeforeSize - skipSize);
- // printf("\nmemmove skip = %d", (int)keepSize);
- memmove(byteBuffer, byteBuffer + bytesInBuf - keepSize, keepSize);
- bytesInBuf = keepSize;
- bufPhyPos = pos - keepSize;
- continue;
- }
- // printf("\nSkip %d", (int)(skipSize - kBeforeSize));
- // RINOK(op.stream->Seek(skipSize - kBeforeSize, STREAM_SEEK_CUR, NULL));
- bytesInBuf = 0;
- bufPhyPos = pos - kBeforeSize;
- continue;
- }
-
- if (bytesInBuf - posInBuf < kAfterSize)
- {
- size_t beg = (size_t)posInBuf - kBeforeSize;
- // printf("\nmemmove for after beg = %d", (int)beg);
- memmove(byteBuffer, byteBuffer + beg, bytesInBuf - beg);
- bufPhyPos += beg;
- bytesInBuf -= beg;
- continue;
- }
- }
-
- if (bytesInBuf <= (size_t)posInBuf)
- break;
-
- bool useOffsetCallback = false;
- if (openCallback_Offset)
- {
- openCallback_Offset_Spec->Files = handlerSpec->_items.Size();
- openCallback_Offset_Spec->Offset = pos;
-
- useOffsetCallback = (!op.openType.CanReturnArc || handlerSpec->_items.Size() > 1);
-
- if (pos >= callbackPrev + (1 << 23))
- {
- RINOK(openCallback_Offset_Spec->SetCompleted(NULL, NULL));
- callbackPrev = pos;
- }
- }
-
- {
- UInt64 endPos = bufPhyPos + bytesInBuf;
- if (fileSize < endPos)
- {
- FileSize = fileSize; // why ????
- fileSize = endPos;
- }
- }
-
- size_t availSize = bytesInBuf - (size_t)posInBuf;
- if (availSize < kNumHashBytes)
- break;
- size_t scanSize = availSize -
- ((availSize >= kAfterSize) ? kAfterSize : kNumHashBytes);
-
- {
- /*
- UInt64 scanLimit = openOnlyFullArc ?
- maxSignatureEnd :
- op.openType.ScanSize + maxSignatureEnd;
- */
- if (!mode.CanReturnParser)
- {
- if (pos > maxStartOffset)
- break;
- UInt64 remScan = maxStartOffset - pos;
- if (scanSize > remScan)
- scanSize = (size_t)remScan;
- }
- }
-
- scanSize++;
-
- const Byte *buf = byteBuffer + (size_t)posInBuf;
- const Byte *bufLimit = buf + scanSize;
- size_t ppp = 0;
-
- if (!needCheckStartOpen)
- {
- for (; buf < bufLimit && hash[HASH_VAL(buf)] == 0xFF; buf++);
- ppp = buf - (byteBuffer + (size_t)posInBuf);
- pos += ppp;
- if (buf == bufLimit)
- continue;
- }
-
- UInt32 v = HASH_VAL(buf);
- bool nextNeedCheckStartOpen = true;
- unsigned i = hash[v];
- unsigned indexOfDifficult = 0;
-
- // ---------- Open Loop for Current Pos ----------
- bool wasOpen = false;
-
- for (;;)
- {
- unsigned index;
- bool isDifficult;
- if (needCheckStartOpen && indexOfDifficult < difficultFormats.Size())
- {
- index = difficultFormats[indexOfDifficult++];
- isDifficult = true;
- }
- else
- {
- if (i == 0xFF)
- break;
- index = sig2arc[i];
- unsigned sigIndex = i - arc2sig[index];
- i = prevs[i];
- if (needCheckStartOpen && difficultBools[index])
- continue;
- const CArcInfoEx &ai = op.codecs->Formats[index];
-
- if (pos < ai.SignatureOffset)
- continue;
-
- /*
- if (openOnlyFullArc)
- if (pos != ai.SignatureOffset)
- continue;
- */
-
- const CByteBuffer &sig = ai.Signatures[sigIndex];
-
- if (ppp + sig.Size() > availSize
- || !TestSignature(buf, sig, sig.Size()))
- continue;
- // printf("\nSignature OK: %10S %8x %5d", (const wchar_t *)ai.Name, (int)pos, (int)(pos - prevPos));
- // prevPos = pos;
- isDifficult = false;
- }
-
- const CArcInfoEx &ai = op.codecs->Formats[index];
-
-
- if ((isDifficult && pos == 0) || ai.SignatureOffset == pos)
- {
- // we don't check same archive second time */
- if (skipFrontalFormat[index])
- continue;
- }
-
- UInt64 startArcPos = pos;
- if (!isDifficult)
- {
- if (pos < ai.SignatureOffset)
- continue;
- startArcPos = pos - ai.SignatureOffset;
- /*
- // we don't need the check for Z files
- if (startArcPos < handlerSpec->GetLastEnd())
- continue;
- */
- }
-
- if (ai.IsArcFunc && startArcPos >= bufPhyPos)
- {
- size_t offsetInBuf = (size_t)(startArcPos - bufPhyPos);
- if (offsetInBuf < bytesInBuf)
- {
- UInt32 isArcRes = ai.IsArcFunc(byteBuffer + offsetInBuf, bytesInBuf - offsetInBuf);
- if (isArcRes == k_IsArc_Res_NO)
- continue;
- if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile)
- continue;
- /*
- if (isArcRes == k_IsArc_Res_YES_LOW_PROB)
- {
- // if (pos != ai.SignatureOffset)
- continue;
- }
- */
- }
- // printf("\nIsArc OK: %S", (const wchar_t *)ai.Name);
- }
-
- /*
- if (pos == 67109888)
- pos = pos;
- */
- PRF(printf("\npos = %9I64d : %S", pos, (const wchar_t *)ai.Name));
-
- bool isMainFormat = isMainFormatArr[index];
- const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt);
-
- CMyComPtr<IInArchive> archive;
- RINOK(PrepareToOpen(op, index, archive));
- if (!archive)
- return E_FAIL;
-
- // OutputDebugStringW(ai.Name);
-
- UInt64 rem = fileSize - startArcPos;
-
- UInt64 arcStreamOffset = 0;
-
- if (ai.Flags_UseGlobalOffset())
- {
- limitedStreamSpec->InitAndSeek(0, fileSize);
- limitedStream->Seek(startArcPos, STREAM_SEEK_SET, NULL);
- }
- else
- {
- limitedStreamSpec->InitAndSeek(startArcPos, rem);
- arcStreamOffset = startArcPos;
- }
-
- UInt64 maxCheckStartPosition = 0;
-
- if (openCallback_Offset)
- {
- openCallback_Offset_Spec->Files = handlerSpec->_items.Size();
- openCallback_Offset_Spec->Offset = startArcPos;
- }
-
- // HRESULT result = archive->Open(limitedStream, &maxCheckStartPosition, openCallback_Offset);
- extractCallback_To_OpenCallback_Spec->Files = 0;
- extractCallback_To_OpenCallback_Spec->Offset = startArcPos;
-
- HRESULT result = OpenArchiveSpec(archive, true, limitedStream, &maxCheckStartPosition,
- useOffsetCallback ? (IArchiveOpenCallback *)openCallback_Offset : (IArchiveOpenCallback *)op.callback,
- extractCallback_To_OpenCallback);
-
- RINOK(ReadBasicProps(archive, ai.Flags_UseGlobalOffset() ? 0 : startArcPos, result));
-
- bool isOpen = false;
- if (result == S_FALSE)
- {
- if (!mode.CanReturnParser)
- {
- if (formatIndex < 0 && ErrorInfo.IsArc_After_NonOpen())
- {
- ErrorInfo.ErrorFormatIndex = index;
- NonOpen_ErrorInfo = ErrorInfo;
- // if archive was detected, we don't need additional open attempts
- return S_FALSE;
- }
- continue;
- }
- if (!ErrorInfo.IsArc_After_NonOpen() || !PhySizeDefined || PhySize == 0)
- continue;
- }
- else
- {
- isOpen = true;
- RINOK(result);
- PRF(printf(" OK "));
- }
-
- // fprintf(stderr, "\n %8X %S", startArcPos, Path);
- // printf("\nOpen OK: %S", ai.Name);
-
-
- NArchive::NParser::CParseItem pi;
- pi.Offset = startArcPos;
-
- if (ai.Flags_UseGlobalOffset())
- pi.Offset = Offset;
- else if (Offset != 0)
- return E_FAIL;
- UInt64 arcRem = FileSize - pi.Offset;
- UInt64 phySize = arcRem;
- bool phySizeDefined = PhySizeDefined;
- if (phySizeDefined)
- {
- if (pi.Offset + PhySize > FileSize)
- {
- // ErrorInfo.ThereIsTail = true;
- PhySize = FileSize - pi.Offset;
- }
- phySize = PhySize;
- }
- if (phySize == 0 || (UInt64)phySize > ((UInt64)1 << 63))
- return E_FAIL;
-
- /*
- if (!ai.UseGlobalOffset)
- {
- if (phySize > arcRem)
- {
- ThereIsTail = true;
- phySize = arcRem;
- }
- }
- */
-
- bool needScan = false;
-
-
- if (isOpen && !phySizeDefined)
- {
- // it's for Z format
- pi.LenIsUnknown = true;
- needScan = true;
- phySize = arcRem;
- nextNeedCheckStartOpen = false;
- }
-
- pi.Size = phySize;
- /*
- if (OkPhySize_Defined)
- pi.OkSize = OkPhySize;
- */
- pi.NormalizeOffset();
- // printf(" phySize = %8d", (unsigned)phySize);
-
- /*
- if (needSkipFullArc)
- if (pi.Offset == 0 && phySizeDefined && pi.Size >= fileSize)
- continue;
- */
- if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize)
- {
- // it's possible for dmg archives
- if (!mode.CanReturnArc)
- continue;
- }
-
- if (mode.EachPos)
- pos++;
- else if (needScan)
- {
- pos++;
- /*
- if (!OkPhySize_Defined)
- pos++;
- else
- pos = pi.Offset + pi.OkSize;
- */
- }
- else
- pos = pi.Offset + pi.Size;
-
-
- RINOK(ReadParseItemProps(archive, ai, pi));
-
- if (pi.Offset < startArcPos && !mode.EachPos /* && phySizeDefined */)
- {
- /* It's for DMG format.
- This code deletes all previous items that are included to current item */
-
- while (!handlerSpec->_items.IsEmpty())
- {
- {
- const NArchive::NParser::CParseItem &back = handlerSpec->_items.Back();
- if (back.Offset < pi.Offset)
- break;
- if (back.Offset + back.Size > pi.Offset + pi.Size)
- break;
- }
- handlerSpec->_items.DeleteBack();
- }
- }
-
-
- if (isOpen && mode.CanReturnArc && phySizeDefined)
- {
- // if (pi.Offset + pi.Size >= fileSize)
- bool openCur = false;
-
- bool thereIsTail = ErrorInfo.ThereIsTail;
- if (thereIsTail && mode.ZerosTailIsAllowed)
- {
- RINOK(CheckZerosTail(op, arcStreamOffset + Offset + PhySize));
- if (ErrorInfo.IgnoreTail)
- thereIsTail = false;
- }
-
- if (pi.Offset != 0)
- {
- if (!pi.IsNotArcType)
- if (thereIsTail)
- openCur = specFlags.CanReturnMid;
- else
- openCur = specFlags.CanReturnTail;
- }
- else
- {
- if (!thereIsTail)
- openCur = true;
- else
- openCur = specFlags.CanReturnFrontal;
-
-
- if (formatIndex >= -2)
- openCur = true;
- }
- if (formatIndex < 0 && pi.IsSelfExe /* && mode.SkipSfxStub */)
- openCur = false;
-
- // We open file as SFX, if there is front archive or first archive is "Self Executable"
- if (!openCur && !pi.IsSelfExe && !thereIsTail &&
- (!pi.IsNotArcType || pi.Offset == 0))
- {
- if (handlerSpec->_items.IsEmpty())
- {
- if (specFlags.CanReturnTail)
- openCur = true;
- }
- else if (handlerSpec->_items.Size() == 1)
- {
- if (handlerSpec->_items[0].IsSelfExe)
- {
- if (mode.SpecUnknownExt.CanReturnTail)
- openCur = true;
- }
- }
- }
-
- if (openCur)
- {
- InStream = op.stream;
- Archive = archive;
- FormatIndex = index;
- ArcStreamOffset = arcStreamOffset;
- return S_OK;
- }
- }
-
- /*
- if (openOnlyFullArc)
- {
- ErrorInfo.ClearErrors();
- return S_FALSE;
- }
- */
-
- pi.FormatIndex = index;
-
- // printf("\nAdd offset = %d", (int)pi.Offset);
- handlerSpec->AddItem(pi);
- wasOpen = true;
- break;
- }
- // ---------- End of Open Loop for Current Pos ----------
-
- if (!wasOpen)
- pos++;
- needCheckStartOpen = (nextNeedCheckStartOpen && wasOpen);
- }
- // ---------- End of Main Scan Loop ----------
-
- /*
- if (handlerSpec->_items.Size() == 1)
- {
- const NArchive::NParser::CParseItem &pi = handlerSpec->_items[0];
- if (pi.Size == fileSize && pi.Offset == 0)
- {
- Archive = archive;
- FormatIndex2 = pi.FormatIndex;
- return S_OK;
- }
- }
- */
-
- if (mode.CanReturnParser)
- {
- bool returnParser = (handlerSpec->_items.Size() == 1); // it's possible if fileSize was not correct at start of parsing
- handlerSpec->AddUnknownItem(fileSize);
- if (handlerSpec->_items.Size() == 0)
- return S_FALSE;
- if (returnParser || handlerSpec->_items.Size() != 1)
- {
- // return S_FALSE;
- handlerSpec->_stream = op.stream;
- Archive = handler;
- ErrorInfo.ClearErrors();
- IsParseArc = true;
- FormatIndex = -1; // It's parser
- Offset = 0;
- return S_OK;
- }
- }
- }
-
- #endif
-
- if (!Archive)
- return S_FALSE;
- return S_OK;
-}
-
-HRESULT CArc::OpenStream(const COpenOptions &op)
-{
- RINOK(OpenStream2(op));
- // PrintNumber("op.formatIndex 3", op.formatIndex);
-
- if (Archive)
- {
- GetRawProps.Release();
- GetRootProps.Release();
- Archive->QueryInterface(IID_IArchiveGetRawProps, (void **)&GetRawProps);
- Archive->QueryInterface(IID_IArchiveGetRootProps, (void **)&GetRootProps);
-
- RINOK(Archive_GetArcBoolProp(Archive, kpidIsTree, IsTree));
- RINOK(Archive_GetArcBoolProp(Archive, kpidIsDeleted, Ask_Deleted));
- RINOK(Archive_GetArcBoolProp(Archive, kpidIsAltStream, Ask_AltStream));
- RINOK(Archive_GetArcBoolProp(Archive, kpidIsAux, Ask_Aux));
- RINOK(Archive_GetArcBoolProp(Archive, kpidINode, Ask_INode));
- RINOK(Archive_GetArcBoolProp(Archive, kpidReadOnly, IsReadOnly));
-
- const UString fileName = ExtractFileNameFromPath(Path);
- UString extension;
- {
- int dotPos = fileName.ReverseFind_Dot();
- if (dotPos >= 0)
- extension = fileName.Ptr(dotPos + 1);
- }
-
- DefaultName.Empty();
- if (FormatIndex >= 0)
- {
- const CArcInfoEx &ai = op.codecs->Formats[FormatIndex];
- if (ai.Exts.Size() == 0)
- DefaultName = GetDefaultName2(fileName, UString(), UString());
- else
- {
- int subExtIndex = ai.FindExtension(extension);
- if (subExtIndex < 0)
- subExtIndex = 0;
- const CArcExtInfo &extInfo = ai.Exts[subExtIndex];
- DefaultName = GetDefaultName2(fileName, extInfo.Ext, extInfo.AddExt);
- }
- }
- }
-
- return S_OK;
-}
-
-#ifdef _SFX
-
-#ifdef _WIN32
- #define k_ExeExt ".exe"
- static const unsigned k_ExeExt_Len = 4;
-#else
- #define k_ExeExt ""
- static const unsigned k_ExeExt_Len = 0;
-#endif
-
-#endif
-
-HRESULT CArc::OpenStreamOrFile(COpenOptions &op)
-{
- CMyComPtr<IInStream> fileStream;
- CMyComPtr<ISequentialInStream> seqStream;
- CInFileStream *fileStreamSpec = NULL;
-
- if (op.stdInMode)
- {
- seqStream = new CStdInFileStream;
- op.seqStream = seqStream;
- }
- else if (!op.stream)
- {
- fileStreamSpec = new CInFileStream;
- fileStream = fileStreamSpec;
- Path = filePath;
- if (!fileStreamSpec->Open(us2fs(Path)))
- {
- return GetLastError();
- }
- op.stream = fileStream;
- #ifdef _SFX
- IgnoreSplit = true;
- #endif
- }
-
- /*
- if (callback)
- {
- UInt64 fileSize;
- RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize));
- RINOK(op.callback->SetTotal(NULL, &fileSize))
- }
- */
-
- HRESULT res = OpenStream(op);
- IgnoreSplit = false;
-
- #ifdef _SFX
-
- if (res != S_FALSE
- || !fileStreamSpec
- || !op.callbackSpec
- || NonOpen_ErrorInfo.IsArc_After_NonOpen())
- return res;
-
- {
- if (filePath.Len() > k_ExeExt_Len
- && StringsAreEqualNoCase_Ascii(filePath.RightPtr(k_ExeExt_Len), k_ExeExt))
- {
- const UString path2 = filePath.Left(filePath.Len() - k_ExeExt_Len);
- FOR_VECTOR (i, op.codecs->Formats)
- {
- const CArcInfoEx &ai = op.codecs->Formats[i];
- if (ai.IsSplit())
- continue;
- UString path3 = path2;
- path3 += '.';
- path3 += ai.GetMainExt(); // "7z" for SFX.
- Path = path3;
- Path += ".001";
- bool isOk = op.callbackSpec->SetSecondFileInfo(us2fs(Path));
- if (!isOk)
- {
- Path = path3;
- isOk = op.callbackSpec->SetSecondFileInfo(us2fs(Path));
- }
- if (isOk)
- {
- if (fileStreamSpec->Open(us2fs(Path)))
- {
- op.stream = fileStream;
- NonOpen_ErrorInfo.ClearErrors_Full();
- if (OpenStream(op) == S_OK)
- return S_OK;
- }
- }
- }
- }
- }
-
- #endif
-
- return res;
-}
-
-void CArchiveLink::KeepModeForNextOpen()
-{
- for (unsigned i = Arcs.Size(); i != 0;)
- {
- i--;
- CMyComPtr<IArchiveKeepModeForNextOpen> keep;
- Arcs[i].Archive->QueryInterface(IID_IArchiveKeepModeForNextOpen, (void **)&keep);
- if (keep)
- keep->KeepModeForNextOpen();
- }
-}
-
-HRESULT CArchiveLink::Close()
-{
- for (unsigned i = Arcs.Size(); i != 0;)
- {
- i--;
- RINOK(Arcs[i].Close());
- }
- IsOpen = false;
- // ErrorsText.Empty();
- return S_OK;
-}
-
-void CArchiveLink::Release()
-{
- // NonOpenErrorFormatIndex = -1;
- NonOpen_ErrorInfo.ClearErrors();
- NonOpen_ArcPath.Empty();
- while (!Arcs.IsEmpty())
- Arcs.DeleteBack();
-}
-
-/*
-void CArchiveLink::Set_ErrorsText()
-{
- FOR_VECTOR(i, Arcs)
- {
- const CArc &arc = Arcs[i];
- if (!arc.ErrorFlagsText.IsEmpty())
- {
- if (!ErrorsText.IsEmpty())
- ErrorsText.Add_LF();
- ErrorsText += GetUnicodeString(arc.ErrorFlagsText);
- }
- if (!arc.ErrorMessage.IsEmpty())
- {
- if (!ErrorsText.IsEmpty())
- ErrorsText.Add_LF();
- ErrorsText += arc.ErrorMessage;
- }
-
- if (!arc.WarningMessage.IsEmpty())
- {
- if (!ErrorsText.IsEmpty())
- ErrorsText.Add_LF();
- ErrorsText += arc.WarningMessage;
- }
- }
-}
-*/
-
-HRESULT CArchiveLink::Open(COpenOptions &op)
-{
- Release();
- if (op.types->Size() >= 32)
- return E_NOTIMPL;
-
- HRESULT resSpec;
-
- for (;;)
- {
- resSpec = S_OK;
-
- op.openType = COpenType();
- if (op.types->Size() >= 1)
- {
- COpenType latest;
- if (Arcs.Size() < op.types->Size())
- latest = (*op.types)[op.types->Size() - Arcs.Size() - 1];
- else
- {
- latest = (*op.types)[0];
- if (!latest.Recursive)
- break;
- }
- op.openType = latest;
- }
- else if (Arcs.Size() >= 32)
- break;
-
- /*
- op.formatIndex = -1;
- if (op.types->Size() >= 1)
- {
- int latest;
- if (Arcs.Size() < op.types->Size())
- latest = (*op.types)[op.types->Size() - Arcs.Size() - 1];
- else
- {
- latest = (*op.types)[0];
- if (latest != -2 && latest != -3)
- break;
- }
- if (latest >= 0)
- op.formatIndex = latest;
- else if (latest == -1 || latest == -2)
- {
- // default
- }
- else if (latest == -3)
- op.formatIndex = -2;
- else
- op.formatIndex = latest + 2;
- }
- else if (Arcs.Size() >= 32)
- break;
- */
-
- if (Arcs.IsEmpty())
- {
- CArc arc;
- arc.filePath = op.filePath;
- arc.Path = op.filePath;
- arc.SubfileIndex = (UInt32)(Int32)-1;
- HRESULT result = arc.OpenStreamOrFile(op);
- if (result != S_OK)
- {
- if (result == S_FALSE)
- {
- NonOpen_ErrorInfo = arc.NonOpen_ErrorInfo;
- // NonOpenErrorFormatIndex = arc.ErrorFormatIndex;
- NonOpen_ArcPath = arc.Path;
- }
- return result;
- }
- Arcs.Add(arc);
- continue;
- }
-
- // PrintNumber("op.formatIndex 11", op.formatIndex);
-
- const CArc &arc = Arcs.Back();
-
- if (op.types->Size() > Arcs.Size())
- resSpec = E_NOTIMPL;
-
- UInt32 mainSubfile;
- {
- NCOM::CPropVariant prop;
- RINOK(arc.Archive->GetArchiveProperty(kpidMainSubfile, &prop));
- if (prop.vt == VT_UI4)
- mainSubfile = prop.ulVal;
- else
- break;
- UInt32 numItems;
- RINOK(arc.Archive->GetNumberOfItems(&numItems));
- if (mainSubfile >= numItems)
- break;
- }
-
-
- CMyComPtr<IInArchiveGetStream> getStream;
- if (arc.Archive->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream) != S_OK || !getStream)
- break;
-
- CMyComPtr<ISequentialInStream> subSeqStream;
- if (getStream->GetStream(mainSubfile, &subSeqStream) != S_OK || !subSeqStream)
- break;
-
- CMyComPtr<IInStream> subStream;
- if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK || !subStream)
- break;
-
- CArc arc2;
- RINOK(arc.GetItemPath(mainSubfile, arc2.Path));
-
- bool zerosTailIsAllowed;
- RINOK(Archive_GetItemBoolProp(arc.Archive, mainSubfile, kpidZerosTailIsAllowed, zerosTailIsAllowed));
-
-
- if (op.callback)
- {
- CMyComPtr<IArchiveOpenSetSubArchiveName> setSubArchiveName;
- op.callback->QueryInterface(IID_IArchiveOpenSetSubArchiveName, (void **)&setSubArchiveName);
- if (setSubArchiveName)
- setSubArchiveName->SetSubArchiveName(arc2.Path);
- }
-
- arc2.SubfileIndex = mainSubfile;
-
- // CIntVector incl;
- CIntVector excl;
-
- COpenOptions op2;
- #ifndef _SFX
- op2.props = op.props;
- #endif
- op2.codecs = op.codecs;
- // op2.types = &incl;
- op2.openType = op.openType;
- op2.openType.ZerosTailIsAllowed = zerosTailIsAllowed;
- op2.excludedFormats = &excl;
- op2.stdInMode = false;
- op2.stream = subStream;
- op2.filePath = arc2.Path;
- op2.callback = op.callback;
- op2.callbackSpec = op.callbackSpec;
-
-
- HRESULT result = arc2.OpenStream(op2);
- resSpec = (op.types->Size() == 0 ? S_OK : S_FALSE);
- if (result == S_FALSE)
- {
- NonOpen_ErrorInfo = arc2.ErrorInfo;
- NonOpen_ArcPath = arc2.Path;
- break;
- }
- RINOK(result);
- RINOK(arc.GetItemMTime(mainSubfile, arc2.MTime, arc2.MTimeDefined));
- Arcs.Add(arc2);
- }
- IsOpen = !Arcs.IsEmpty();
- return resSpec;
-}
-
-HRESULT CArchiveLink::Open2(COpenOptions &op, IOpenCallbackUI *callbackUI)
-{
- VolumesSize = 0;
- COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
- CMyComPtr<IArchiveOpenCallback> callback = openCallbackSpec;
- openCallbackSpec->Callback = callbackUI;
-
- FString prefix, name;
-
- if (!op.stream && !op.stdInMode)
- {
- NFile::NDir::GetFullPathAndSplit(us2fs(op.filePath), prefix, name);
- openCallbackSpec->Init(prefix, name);
- }
- else
- {
- openCallbackSpec->SetSubArchiveName(op.filePath);
- }
-
- op.callback = callback;
- op.callbackSpec = openCallbackSpec;
-
- HRESULT res = Open(op);
-
- PasswordWasAsked = openCallbackSpec->PasswordWasAsked;
- // Password = openCallbackSpec->Password;
-
- RINOK(res);
- // VolumePaths.Add(fs2us(prefix + name));
-
- FOR_VECTOR (i, openCallbackSpec->FileNames_WasUsed)
- {
- if (openCallbackSpec->FileNames_WasUsed[i])
- {
- VolumePaths.Add(fs2us(prefix) + openCallbackSpec->FileNames[i]);
- VolumesSize += openCallbackSpec->FileSizes[i];
- }
- }
- // VolumesSize = openCallbackSpec->TotalSize;
- return S_OK;
-}
-
-HRESULT CArc::ReOpen(const COpenOptions &op)
-{
- ErrorInfo.ClearErrors();
- ErrorInfo.ErrorFormatIndex = -1;
-
- UInt64 fileSize = 0;
- if (op.stream)
- {
- RINOK(op.stream->Seek(0, STREAM_SEEK_END, &fileSize));
- RINOK(op.stream->Seek(0, STREAM_SEEK_SET, NULL));
- }
- FileSize = fileSize;
-
- CMyComPtr<IInStream> stream2;
- Int64 globalOffset = GetGlobalOffset();
- if (globalOffset <= 0)
- stream2 = op.stream;
- else
- {
- CTailInStream *tailStreamSpec = new CTailInStream;
- stream2 = tailStreamSpec;
- tailStreamSpec->Stream = op.stream;
- tailStreamSpec->Offset = globalOffset;
- tailStreamSpec->Init();
- RINOK(tailStreamSpec->SeekToStart());
- }
-
- // There are archives with embedded STUBs (like ZIP), so we must support signature scanning
- // But for another archives we can use 0 here. So the code can be fixed !!!
- UInt64 maxStartPosition = kMaxCheckStartPosition;
- HRESULT res = Archive->Open(stream2, &maxStartPosition, op.callback);
-
- if (res == S_OK)
- {
- RINOK(ReadBasicProps(Archive, globalOffset, res));
- ArcStreamOffset = globalOffset;
- if (ArcStreamOffset != 0)
- InStream = op.stream;
- }
- return res;
-}
-
-HRESULT CArchiveLink::Open3(COpenOptions &op, IOpenCallbackUI *callbackUI)
-{
- HRESULT res = Open2(op, callbackUI);
- if (callbackUI)
- {
- RINOK(callbackUI->Open_Finished());
- }
- return res;
-}
-
-HRESULT CArchiveLink::ReOpen(COpenOptions &op)
-{
- if (Arcs.Size() > 1)
- return E_NOTIMPL;
-
- CObjectVector<COpenType> inc;
- CIntVector excl;
-
- op.types = &inc;
- op.excludedFormats = &excl;
- op.stdInMode = false;
- op.stream = NULL;
- if (Arcs.Size() == 0) // ???
- return Open2(op, NULL);
-
- COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
- CMyComPtr<IArchiveOpenCallback> openCallbackNew = openCallbackSpec;
-
- openCallbackSpec->Callback = NULL;
- openCallbackSpec->ReOpenCallback = op.callback;
- {
- FString dirPrefix, fileName;
- NFile::NDir::GetFullPathAndSplit(us2fs(op.filePath), dirPrefix, fileName);
- openCallbackSpec->Init(dirPrefix, fileName);
- }
-
-
- CInFileStream *fileStreamSpec = new CInFileStream;
- CMyComPtr<IInStream> stream(fileStreamSpec);
- if (!fileStreamSpec->Open(us2fs(op.filePath)))
- return GetLastError();
- op.stream = stream;
-
- CArc &arc = Arcs[0];
- HRESULT res = arc.ReOpen(op);
-
- PasswordWasAsked = openCallbackSpec->PasswordWasAsked;
- // Password = openCallbackSpec->Password;
-
- IsOpen = (res == S_OK);
- return res;
-}
-
-#ifndef _SFX
-
-bool ParseComplexSize(const wchar_t *s, UInt64 &result)
-{
- result = 0;
- const wchar_t *end;
- UInt64 number = ConvertStringToUInt64(s, &end);
- if (end == s)
- return false;
- if (*end == 0)
- {
- result = number;
- return true;
- }
- if (end[1] != 0)
- return false;
- unsigned numBits;
- switch (MyCharLower_Ascii(*end))
- {
- case 'b': result = number; return true;
- case 'k': numBits = 10; break;
- case 'm': numBits = 20; break;
- case 'g': numBits = 30; break;
- case 't': numBits = 40; break;
- default: return false;
- }
- if (number >= ((UInt64)1 << (64 - numBits)))
- return false;
- result = number << numBits;
- return true;
-}
-
-static bool ParseTypeParams(const UString &s, COpenType &type)
-{
- if (s[0] == 0)
- return true;
- if (s[1] == 0)
- {
- switch ((unsigned)(Byte)s[0])
- {
- case 'e': type.EachPos = true; return true;
- case 'a': type.CanReturnArc = true; return true;
- case 'r': type.Recursive = true; return true;
- }
- return false;
- }
- if (s[0] == 's')
- {
- UInt64 result;
- if (!ParseComplexSize(s.Ptr(1), result))
- return false;
- type.MaxStartOffset = result;
- type.MaxStartOffset_Defined = true;
- return true;
- }
-
- return false;
-}
-
-bool ParseType(CCodecs &codecs, const UString &s, COpenType &type)
-{
- int pos2 = s.Find(L':');
-
- {
- UString name;
- if (pos2 < 0)
- {
- name = s;
- pos2 = s.Len();
- }
- else
- {
- name = s.Left(pos2);
- pos2++;
- }
-
- int index = codecs.FindFormatForArchiveType(name);
- type.Recursive = false;
-
- if (index < 0)
- {
- if (name[0] == '*')
- {
- if (name[1] != 0)
- return false;
- }
- else if (name[0] == '#')
- {
- if (name[1] != 0)
- return false;
- type.CanReturnArc = false;
- type.CanReturnParser = true;
- }
- else
- return false;
- }
-
- type.FormatIndex = index;
-
- }
-
- for (unsigned i = pos2; i < s.Len();)
- {
- int next = s.Find(L':', i);
- if (next < 0)
- next = s.Len();
- const UString name = s.Mid(i, next - i);
- if (name.IsEmpty())
- return false;
- if (!ParseTypeParams(name, type))
- return false;
- i = next + 1;
- }
-
- return true;
-}
-
-bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector<COpenType> &types)
-{
- types.Clear();
- for (unsigned pos = 0; pos < s.Len();)
- {
- int pos2 = s.Find(L'.', pos);
- if (pos2 < 0)
- pos2 = s.Len();
- UString name = s.Mid(pos, pos2 - pos);
- if (name.IsEmpty())
- return false;
- COpenType type;
- if (!ParseType(codecs, name, type))
- return false;
- types.Add(type);
- pos = pos2 + 1;
- }
- return true;
-}
-
-#endif
+// OpenArchive.cpp
+
+#include "StdAfx.h"
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+#include <stdio.h>
+#endif
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/StringToInt.h"
+#include "../../../Common/UTFConvert.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/FileDir.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/ProgressUtils.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "DefaultName.h"
+#include "OpenArchive.h"
+
+#ifndef Z7_SFX
+#include "SetProperties.h"
+#endif
+
+#ifndef Z7_SFX
+#ifdef SHOW_DEBUG_INFO
+#define PRF(x) x
+#else
+#define PRF(x)
+#endif
+#endif
+
+// increase it, if you need to support larger SFX stubs
+static const UInt64 kMaxCheckStartPosition = 1 << 23;
+
+/*
+Open:
+ - formatIndex >= 0 (exact Format)
+ 1) Open with main type. Archive handler is allowed to use archive start finder.
+ Warning, if there is tail.
+
+ - formatIndex = -1 (Parser:0) (default)
+ - same as #1 but doesn't return Parser
+
+ - formatIndex = -2 (#1)
+ - file has supported extension (like a.7z)
+ Open with that main type (only starting from start of file).
+ - open OK:
+ - if there is no tail - return OK
+ - if there is tail:
+ - archive is not "Self Exe" - return OK with Warning, that there is tail
+ - archive is "Self Exe"
+ ignore "Self Exe" stub, and tries to open tail
+ - tail can be open as archive - shows that archive and stub size property.
+ - tail can't be open as archive - shows Parser ???
+ - open FAIL:
+ Try to open with all other types from offset 0 only.
+ If some open type is OK and physical archive size is uequal or larger
+ than file size, then return that archive with warning that cannot be open as [extension type].
+ If extension was EXE, it will try to open as unknown_extension case
+ - file has unknown extension (like a.hhh)
+ It tries to open via parser code.
+ - if there is full archive or tail archive and unknown block or "Self Exe"
+ at front, it shows tail archive and stub size property.
+ - in another cases, if there is some archive inside file, it returns parser/
+ - in another cases, it retuens S_FALSE
+
+
+ - formatIndex = -3 (#2)
+ - same as #1, but
+ - stub (EXE) + archive is open in Parser
+
+ - formatIndex = -4 (#3)
+ - returns only Parser. skip full file archive. And show other sub-archives
+
+ - formatIndex = -5 (#4)
+ - returns only Parser. skip full file archive. And show other sub-archives for each byte pos
+
+*/
+
+
+
+
+using namespace NWindows;
+
+/*
+#ifdef Z7_SFX
+#define OPEN_PROPS_PARAM
+#else
+#define OPEN_PROPS_PARAM , props
+#endif
+*/
+
+/*
+CArc::~CArc()
+{
+ GetRawProps.Release();
+ Archive.Release();
+ printf("\nCArc::~CArc()\n");
+}
+*/
+
+#ifndef Z7_SFX
+
+namespace NArchive {
+namespace NParser {
+
+struct CParseItem
+{
+ UInt64 Offset;
+ UInt64 Size;
+ // UInt64 OkSize;
+ UString Name;
+ UString Extension;
+ FILETIME FileTime;
+ UString Comment;
+ UString ArcType;
+
+ bool FileTime_Defined;
+ bool UnpackSize_Defined;
+ bool NumSubDirs_Defined;
+ bool NumSubFiles_Defined;
+
+ bool IsSelfExe;
+ bool IsNotArcType;
+
+ UInt64 UnpackSize;
+ UInt64 NumSubDirs;
+ UInt64 NumSubFiles;
+
+ int FormatIndex;
+
+ bool LenIsUnknown;
+
+ CParseItem():
+ // OkSize(0),
+ FileTime_Defined(false),
+ UnpackSize_Defined(false),
+ NumSubDirs_Defined(false),
+ NumSubFiles_Defined(false),
+ IsSelfExe(false),
+ IsNotArcType(false),
+ LenIsUnknown(false)
+ {}
+
+ /*
+ bool IsEqualTo(const CParseItem &item) const
+ {
+ return Offset == item.Offset && Size == item.Size;
+ }
+ */
+
+ void NormalizeOffset()
+ {
+ if ((Int64)Offset < 0)
+ {
+ Size += Offset;
+ // OkSize += Offset;
+ Offset = 0;
+ }
+ }
+};
+
+Z7_CLASS_IMP_CHandler_IInArchive_1(
+ IInArchiveGetStream
+)
+public:
+ CObjectVector<CParseItem> _items;
+ UInt64 _maxEndOffset;
+ CMyComPtr<IInStream> _stream;
+
+ UInt64 GetLastEnd() const
+ {
+ if (_items.IsEmpty())
+ return 0;
+ const CParseItem &back = _items.Back();
+ return back.Offset + back.Size;
+ }
+
+ void AddUnknownItem(UInt64 next);
+ int FindInsertPos(const CParseItem &item) const;
+ void AddItem(const CParseItem &item);
+
+ CHandler(): _maxEndOffset(0) {}
+};
+
+int CHandler::FindInsertPos(const CParseItem &item) const
+{
+ unsigned left = 0, right = _items.Size();
+ while (left != right)
+ {
+ const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const CParseItem &midItem = _items[mid];
+ if (item.Offset < midItem.Offset)
+ right = mid;
+ else if (item.Offset > midItem.Offset)
+ left = mid + 1;
+ else if (item.Size < midItem.Size)
+ right = mid;
+ /*
+ else if (item.Size > midItem.Size)
+ left = mid + 1;
+ */
+ else
+ {
+ left = mid + 1;
+ // return -1;
+ }
+ }
+ return (int)left;
+}
+
+void CHandler::AddUnknownItem(UInt64 next)
+{
+ /*
+ UInt64 prevEnd = 0;
+ if (!_items.IsEmpty())
+ {
+ const CParseItem &back = _items.Back();
+ prevEnd = back.Offset + back.Size;
+ }
+ */
+ if (_maxEndOffset < next)
+ {
+ CParseItem item2;
+ item2.Offset = _maxEndOffset;
+ item2.Size = next - _maxEndOffset;
+ _maxEndOffset = next;
+ _items.Add(item2);
+ }
+ else if (_maxEndOffset > next && !_items.IsEmpty())
+ {
+ CParseItem &back = _items.Back();
+ if (back.LenIsUnknown)
+ {
+ back.Size = next - back.Offset;
+ _maxEndOffset = next;
+ }
+ }
+}
+
+void CHandler::AddItem(const CParseItem &item)
+{
+ AddUnknownItem(item.Offset);
+ const int pos = FindInsertPos(item);
+ if (pos != -1)
+ {
+ _items.Insert((unsigned)pos, item);
+ UInt64 next = item.Offset + item.Size;
+ if (_maxEndOffset < next)
+ _maxEndOffset = next;
+ }
+}
+
+/*
+static const CStatProp kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidType, VT_BSTR},
+ { NULL, kpidComment, VT_BSTR},
+ { NULL, kpidOffset, VT_UI8},
+ { NULL, kpidUnpackSize, VT_UI8},
+// { NULL, kpidNumSubDirs, VT_UI8},
+};
+*/
+
+static const Byte kProps[] =
+{
+ kpidPath,
+ kpidSize,
+ kpidMTime,
+ kpidType,
+ kpidComment,
+ kpidOffset,
+ kpidUnpackSize
+};
+
+IMP_IInArchive_Props
+IMP_IInArchive_ArcProps_NO
+
+Z7_COM7F_IMF(CHandler::Open(IInStream *stream, const UInt64 *, IArchiveOpenCallback * /* openArchiveCallback */))
+{
+ COM_TRY_BEGIN
+ {
+ Close();
+ _stream = stream;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Close())
+{
+ _items.Clear();
+ _stream.Release();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CHandler::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+
+ const CParseItem &item = _items[index];
+
+ switch (propID)
+ {
+ case kpidPath:
+ {
+ char sz[32];
+ ConvertUInt32ToString(index + 1, sz);
+ UString s(sz);
+ if (!item.Name.IsEmpty())
+ {
+ s.Add_Dot();
+ s += item.Name;
+ }
+ if (!item.Extension.IsEmpty())
+ {
+ s.Add_Dot();
+ s += item.Extension;
+ }
+ prop = s; break;
+ }
+ case kpidSize:
+ case kpidPackSize: prop = item.Size; break;
+ case kpidOffset: prop = item.Offset; break;
+ case kpidUnpackSize: if (item.UnpackSize_Defined) prop = item.UnpackSize; break;
+ case kpidNumSubFiles: if (item.NumSubFiles_Defined) prop = item.NumSubFiles; break;
+ case kpidNumSubDirs: if (item.NumSubDirs_Defined) prop = item.NumSubDirs; break;
+ case kpidMTime: if (item.FileTime_Defined) prop = item.FileTime; break;
+ case kpidComment: if (!item.Comment.IsEmpty()) prop = item.Comment; break;
+ case kpidType: if (!item.ArcType.IsEmpty()) prop = item.ArcType; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CHandler::Extract(const UInt32 *indices, UInt32 numItems,
+ Int32 testMode, IArchiveExtractCallback *extractCallback))
+{
+ COM_TRY_BEGIN
+
+ const bool allFilesMode = (numItems == (UInt32)(Int32)-1);
+ if (allFilesMode)
+ numItems = _items.Size();
+ if (_stream && numItems == 0)
+ return S_OK;
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ totalSize += _items[allFilesMode ? i : indices[i]].Size;
+ extractCallback->SetTotal(totalSize);
+
+ totalSize = 0;
+
+ CLocalProgress *lps = new CLocalProgress;
+ CMyComPtr<ICompressProgressInfo> progress = lps;
+ lps->Init(extractCallback, false);
+
+ CLimitedSequentialInStream *streamSpec = new CLimitedSequentialInStream;
+ CMyComPtr<ISequentialInStream> inStream(streamSpec);
+ streamSpec->SetStream(_stream);
+
+ CLimitedSequentialOutStream *outStreamSpec = new CLimitedSequentialOutStream;
+ CMyComPtr<ISequentialOutStream> outStream(outStreamSpec);
+
+ NCompress::CCopyCoder *copyCoderSpec = new NCompress::CCopyCoder();
+ CMyComPtr<ICompressCoder> copyCoder = copyCoderSpec;
+
+ for (i = 0; i < numItems; i++)
+ {
+ lps->InSize = totalSize;
+ lps->OutSize = totalSize;
+ RINOK(lps->SetCur())
+ CMyComPtr<ISequentialOutStream> realOutStream;
+ const Int32 askMode = testMode ?
+ NExtract::NAskMode::kTest :
+ NExtract::NAskMode::kExtract;
+ const UInt32 index = allFilesMode ? i : indices[i];
+ const CParseItem &item = _items[index];
+
+ RINOK(extractCallback->GetStream(index, &realOutStream, askMode))
+ UInt64 unpackSize = item.Size;
+ totalSize += unpackSize;
+ bool skipMode = false;
+ if (!testMode && !realOutStream)
+ continue;
+ RINOK(extractCallback->PrepareOperation(askMode))
+
+ outStreamSpec->SetStream(realOutStream);
+ realOutStream.Release();
+ outStreamSpec->Init(skipMode ? 0 : unpackSize, true);
+
+ Int32 opRes = NExtract::NOperationResult::kOK;
+ RINOK(InStream_SeekSet(_stream, item.Offset))
+ streamSpec->Init(unpackSize);
+ RINOK(copyCoder->Code(inStream, outStream, NULL, NULL, progress))
+
+ if (outStreamSpec->GetRem() != 0)
+ opRes = NExtract::NOperationResult::kDataError;
+ outStreamSpec->ReleaseStream();
+ RINOK(extractCallback->SetOperationResult(opRes))
+ }
+
+ return S_OK;
+
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CHandler::GetStream(UInt32 index, ISequentialInStream **stream))
+{
+ COM_TRY_BEGIN
+ const CParseItem &item = _items[index];
+ return CreateLimitedInStream(_stream, item.Offset, item.Size, stream);
+ COM_TRY_END
+}
+
+}}
+
+#endif
+
+HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw()
+{
+ NCOM::CPropVariant prop;
+ result = false;
+ RINOK(arc->GetProperty(index, propID, &prop))
+ if (prop.vt == VT_BOOL)
+ result = VARIANT_BOOLToBool(prop.boolVal);
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+HRESULT Archive_IsItem_Dir(IInArchive *arc, UInt32 index, bool &result) throw()
+{
+ return Archive_GetItemBoolProp(arc, index, kpidIsDir, result);
+}
+
+HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw()
+{
+ return Archive_GetItemBoolProp(arc, index, kpidIsAux, result);
+}
+
+HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw()
+{
+ return Archive_GetItemBoolProp(arc, index, kpidIsAltStream, result);
+}
+
+HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &result) throw()
+{
+ return Archive_GetItemBoolProp(arc, index, kpidIsDeleted, result);
+}
+
+static HRESULT Archive_GetArcProp_Bool(IInArchive *arc, PROPID propid, bool &result) throw()
+{
+ NCOM::CPropVariant prop;
+ result = false;
+ RINOK(arc->GetArchiveProperty(propid, &prop))
+ if (prop.vt == VT_BOOL)
+ result = VARIANT_BOOLToBool(prop.boolVal);
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+static HRESULT Archive_GetArcProp_UInt(IInArchive *arc, PROPID propid, UInt64 &result, bool &defined)
+{
+ defined = false;
+ NCOM::CPropVariant prop;
+ RINOK(arc->GetArchiveProperty(propid, &prop))
+ switch (prop.vt)
+ {
+ case VT_UI4: result = prop.ulVal; break;
+ case VT_I4: result = (UInt64)(Int64)prop.lVal; break;
+ case VT_UI8: result = (UInt64)prop.uhVal.QuadPart; break;
+ case VT_I8: result = (UInt64)prop.hVal.QuadPart; break;
+ case VT_EMPTY: return S_OK;
+ default: return E_FAIL;
+ }
+ defined = true;
+ return S_OK;
+}
+
+static HRESULT Archive_GetArcProp_Int(IInArchive *arc, PROPID propid, Int64 &result, bool &defined)
+{
+ defined = false;
+ NCOM::CPropVariant prop;
+ RINOK(arc->GetArchiveProperty(propid, &prop))
+ switch (prop.vt)
+ {
+ case VT_UI4: result = prop.ulVal; break;
+ case VT_I4: result = prop.lVal; break;
+ case VT_UI8: result = (Int64)prop.uhVal.QuadPart; break;
+ case VT_I8: result = (Int64)prop.hVal.QuadPart; break;
+ case VT_EMPTY: return S_OK;
+ default: return E_FAIL;
+ }
+ defined = true;
+ return S_OK;
+}
+
+#ifndef Z7_SFX
+
+HRESULT CArc::GetItem_PathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const
+{
+ if (!GetRawProps)
+ return E_FAIL;
+ if (index == parent)
+ return S_OK;
+ UInt32 curIndex = index;
+
+ UString s;
+
+ bool prevWasAltStream = false;
+
+ for (;;)
+ {
+ #ifdef MY_CPU_LE
+ const void *p;
+ UInt32 size;
+ UInt32 propType;
+ RINOK(GetRawProps->GetRawProp(curIndex, kpidName, &p, &size, &propType))
+ if (p && propType == PROP_DATA_TYPE_wchar_t_PTR_Z_LE)
+ s = (const wchar_t *)p;
+ else
+ #endif
+ {
+ NCOM::CPropVariant prop;
+ RINOK(Archive->GetProperty(curIndex, kpidName, &prop))
+ if (prop.vt == VT_BSTR && prop.bstrVal)
+ s.SetFromBstr(prop.bstrVal);
+ else if (prop.vt == VT_EMPTY)
+ s.Empty();
+ else
+ return E_FAIL;
+ }
+
+ UInt32 curParent = (UInt32)(Int32)-1;
+ UInt32 parentType = 0;
+ RINOK(GetRawProps->GetParent(curIndex, &curParent, &parentType))
+
+ // 18.06: fixed : we don't want to split name to parts
+ /*
+ if (parentType != NParentType::kAltStream)
+ {
+ for (;;)
+ {
+ int pos = s.ReverseFind_PathSepar();
+ if (pos < 0)
+ {
+ break;
+ }
+ parts.Insert(0, s.Ptr(pos + 1));
+ s.DeleteFrom(pos);
+ }
+ }
+ */
+
+ parts.Insert(0, s);
+
+ if (prevWasAltStream)
+ {
+ {
+ UString &s2 = parts[parts.Size() - 2];
+ s2 += ':';
+ s2 += parts.Back();
+ }
+ parts.DeleteBack();
+ }
+
+ if (parent == curParent)
+ return S_OK;
+
+ prevWasAltStream = false;
+ if (parentType == NParentType::kAltStream)
+ prevWasAltStream = true;
+
+ if (curParent == (UInt32)(Int32)-1)
+ return E_FAIL;
+ curIndex = curParent;
+ }
+}
+
+#endif
+
+
+
+HRESULT CArc::GetItem_Path(UInt32 index, UString &result) const
+{
+ #ifdef MY_CPU_LE
+ if (GetRawProps)
+ {
+ const void *p;
+ UInt32 size;
+ UInt32 propType;
+ if (!IsTree)
+ {
+ if (GetRawProps->GetRawProp(index, kpidPath, &p, &size, &propType) == S_OK &&
+ propType == NPropDataType::kUtf16z)
+ {
+ unsigned len = size / 2 - 1;
+ // (len) doesn't include null terminator
+
+ /*
+ #if WCHAR_MAX > 0xffff
+ len = (unsigned)Utf16LE__Get_Num_WCHARs(p, len);
+
+ wchar_t *s = result.GetBuf(len);
+ wchar_t *sEnd = Utf16LE__To_WCHARs_Sep(p, len, s);
+ if (s + len != sEnd) return E_FAIL;
+ *sEnd = 0;
+
+ #else
+ */
+
+ wchar_t *s = result.GetBuf(len);
+ for (unsigned i = 0; i < len; i++)
+ {
+ wchar_t c = GetUi16(p);
+ p = (const void *)((const Byte *)p + 2);
+
+ #if WCHAR_PATH_SEPARATOR != L'/'
+ if (c == L'/')
+ c = WCHAR_PATH_SEPARATOR;
+ else if (c == L'\\')
+ c = WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT; // WSL scheme
+ #endif
+
+ *s++ = c;
+ }
+ *s = 0;
+
+ // #endif
+
+ result.ReleaseBuf_SetLen(len);
+
+ Convert_UnicodeEsc16_To_UnicodeEscHigh(result);
+ if (len != 0)
+ return S_OK;
+ }
+ }
+ /*
+ else if (GetRawProps->GetRawProp(index, kpidName, &p, &size, &propType) == S_OK &&
+ p && propType == NPropDataType::kUtf16z)
+ {
+ size -= 2;
+ UInt32 totalSize = size;
+ bool isOK = false;
+
+ {
+ UInt32 index2 = index;
+ for (;;)
+ {
+ UInt32 parent = (UInt32)(Int32)-1;
+ UInt32 parentType = 0;
+ if (GetRawProps->GetParent(index2, &parent, &parentType) != S_OK)
+ break;
+ if (parent == (UInt32)(Int32)-1)
+ {
+ if (parentType != 0)
+ totalSize += 2;
+ isOK = true;
+ break;
+ }
+ index2 = parent;
+ UInt32 size2;
+ const void *p2;
+ if (GetRawProps->GetRawProp(index2, kpidName, &p2, &size2, &propType) != S_OK &&
+ p2 && propType == NPropDataType::kUtf16z)
+ break;
+ totalSize += size2;
+ }
+ }
+
+ if (isOK)
+ {
+ wchar_t *sz = result.GetBuf_SetEnd(totalSize / 2);
+ UInt32 pos = totalSize - size;
+ memcpy((Byte *)sz + pos, p, size);
+ UInt32 index2 = index;
+ for (;;)
+ {
+ UInt32 parent = (UInt32)(Int32)-1;
+ UInt32 parentType = 0;
+ if (GetRawProps->GetParent(index2, &parent, &parentType) != S_OK)
+ break;
+ if (parent == (UInt32)(Int32)-1)
+ {
+ if (parentType != 0)
+ sz[pos / 2 - 1] = L':';
+ break;
+ }
+ index2 = parent;
+ UInt32 size2;
+ const void *p2;
+ if (GetRawProps->GetRawProp(index2, kpidName, &p2, &size2, &propType) != S_OK)
+ break;
+ pos -= size2;
+ memcpy((Byte *)sz + pos, p2, size2);
+ sz[(pos + size2 - 2) / 2] = (parentType == 0) ? WCHAR_PATH_SEPARATOR : L':';
+ }
+ #ifdef _WIN32
+ // result.Replace(L'/', WCHAR_PATH_SEPARATOR);
+ #endif
+ return S_OK;
+ }
+ }
+ */
+ }
+ #endif
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(Archive->GetProperty(index, kpidPath, &prop))
+ if (prop.vt == VT_BSTR && prop.bstrVal)
+ result.SetFromBstr(prop.bstrVal);
+ else if (prop.vt == VT_EMPTY)
+ result.Empty();
+ else
+ return E_FAIL;
+ }
+
+ if (result.IsEmpty())
+ return GetItem_DefaultPath(index, result);
+
+ Convert_UnicodeEsc16_To_UnicodeEscHigh(result);
+ return S_OK;
+}
+
+HRESULT CArc::GetItem_DefaultPath(UInt32 index, UString &result) const
+{
+ result.Empty();
+ bool isDir;
+ RINOK(Archive_IsItem_Dir(Archive, index, isDir))
+ if (!isDir)
+ {
+ result = DefaultName;
+ NCOM::CPropVariant prop;
+ RINOK(Archive->GetProperty(index, kpidExtension, &prop))
+ if (prop.vt == VT_BSTR)
+ {
+ result.Add_Dot();
+ result += prop.bstrVal;
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+HRESULT CArc::GetItem_Path2(UInt32 index, UString &result) const
+{
+ RINOK(GetItem_Path(index, result))
+ if (Ask_Deleted)
+ {
+ bool isDeleted = false;
+ RINOK(Archive_IsItem_Deleted(Archive, index, isDeleted))
+ if (isDeleted)
+ result.Insert(0, L"[DELETED]" WSTRING_PATH_SEPARATOR);
+ }
+ return S_OK;
+}
+
+#ifdef SUPPORT_ALT_STREAMS
+
+int FindAltStreamColon_in_Path(const wchar_t *path)
+{
+ unsigned i = 0;
+ int colonPos = -1;
+ for (;; i++)
+ {
+ wchar_t c = path[i];
+ if (c == 0)
+ return colonPos;
+ if (c == ':')
+ {
+ if (colonPos < 0)
+ colonPos = (int)i;
+ continue;
+ }
+ if (c == WCHAR_PATH_SEPARATOR)
+ colonPos = -1;
+ }
+}
+
+#endif
+
+HRESULT CArc::GetItem(UInt32 index, CReadArcItem &item) const
+{
+ #ifdef SUPPORT_ALT_STREAMS
+ item.IsAltStream = false;
+ item.AltStreamName.Empty();
+ item.MainPath.Empty();
+ #endif
+
+ item.IsDir = false;
+ item.Path.Empty();
+ item.ParentIndex = (UInt32)(Int32)-1;
+
+ item.PathParts.Clear();
+
+ RINOK(Archive_IsItem_Dir(Archive, index, item.IsDir))
+ item.MainIsDir = item.IsDir;
+
+ RINOK(GetItem_Path2(index, item.Path))
+
+ #ifndef Z7_SFX
+ UInt32 mainIndex = index;
+ #endif
+
+ #ifdef SUPPORT_ALT_STREAMS
+
+ item.MainPath = item.Path;
+ if (Ask_AltStream)
+ {
+ RINOK(Archive_IsItem_AltStream(Archive, index, item.IsAltStream))
+ }
+
+ bool needFindAltStream = false;
+
+ if (item.IsAltStream)
+ {
+ needFindAltStream = true;
+ if (GetRawProps)
+ {
+ UInt32 parentType = 0;
+ UInt32 parentIndex;
+ RINOK(GetRawProps->GetParent(index, &parentIndex, &parentType))
+ if (parentType == NParentType::kAltStream)
+ {
+ NCOM::CPropVariant prop;
+ RINOK(Archive->GetProperty(index, kpidName, &prop))
+ if (prop.vt == VT_BSTR && prop.bstrVal)
+ item.AltStreamName.SetFromBstr(prop.bstrVal);
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ else
+ {
+ // item.IsAltStream = false;
+ }
+ /*
+ if (item.AltStreamName.IsEmpty())
+ item.IsAltStream = false;
+ */
+
+ needFindAltStream = false;
+ item.ParentIndex = parentIndex;
+ mainIndex = parentIndex;
+
+ if (parentIndex == (UInt32)(Int32)-1)
+ {
+ item.MainPath.Empty();
+ item.MainIsDir = true;
+ }
+ else
+ {
+ RINOK(GetItem_Path2(parentIndex, item.MainPath))
+ RINOK(Archive_IsItem_Dir(Archive, parentIndex, item.MainIsDir))
+ }
+ }
+ }
+ }
+
+ if (item.WriteToAltStreamIfColon || needFindAltStream)
+ {
+ /* Good handler must support GetRawProps::GetParent for alt streams.
+ So the following code currently is not used */
+ int colon = FindAltStreamColon_in_Path(item.Path);
+ if (colon >= 0)
+ {
+ item.MainPath.DeleteFrom((unsigned)colon);
+ item.AltStreamName = item.Path.Ptr((unsigned)(colon + 1));
+ item.MainIsDir = (colon == 0 || IsPathSepar(item.Path[(unsigned)colon - 1]));
+ item.IsAltStream = true;
+ }
+ }
+
+ #endif
+
+ #ifndef Z7_SFX
+ if (item._use_baseParentFolder_mode)
+ {
+ RINOK(GetItem_PathToParent(mainIndex, (unsigned)item._baseParentFolder, item.PathParts))
+
+ #ifdef SUPPORT_ALT_STREAMS
+ if ((item.WriteToAltStreamIfColon || needFindAltStream) && !item.PathParts.IsEmpty())
+ {
+ int colon;
+ {
+ UString &s = item.PathParts.Back();
+ colon = FindAltStreamColon_in_Path(s);
+ if (colon >= 0)
+ {
+ item.AltStreamName = s.Ptr((unsigned)(colon + 1));
+ item.MainIsDir = (colon == 0 || IsPathSepar(s[(unsigned)colon - 1]));
+ item.IsAltStream = true;
+ s.DeleteFrom((unsigned)colon);
+ }
+ }
+ if (colon == 0)
+ item.PathParts.DeleteBack();
+ }
+ #endif
+
+ }
+ else
+ #endif
+ SplitPathToParts(
+ #ifdef SUPPORT_ALT_STREAMS
+ item.MainPath
+ #else
+ item.Path
+ #endif
+ , item.PathParts);
+
+ return S_OK;
+}
+
+#ifndef Z7_SFX
+
+static HRESULT Archive_GetItem_Size(IInArchive *archive, UInt32 index, UInt64 &size, bool &defined)
+{
+ NCOM::CPropVariant prop;
+ defined = false;
+ size = 0;
+ RINOK(archive->GetProperty(index, kpidSize, &prop))
+ switch (prop.vt)
+ {
+ case VT_UI1: size = prop.bVal; break;
+ case VT_UI2: size = prop.uiVal; break;
+ case VT_UI4: size = prop.ulVal; break;
+ case VT_UI8: size = (UInt64)prop.uhVal.QuadPart; break;
+ case VT_EMPTY: return S_OK;
+ default: return E_FAIL;
+ }
+ defined = true;
+ return S_OK;
+}
+
+#endif
+
+HRESULT CArc::GetItem_Size(UInt32 index, UInt64 &size, bool &defined) const
+{
+ NCOM::CPropVariant prop;
+ defined = false;
+ size = 0;
+ RINOK(Archive->GetProperty(index, kpidSize, &prop))
+ switch (prop.vt)
+ {
+ case VT_UI1: size = prop.bVal; break;
+ case VT_UI2: size = prop.uiVal; break;
+ case VT_UI4: size = prop.ulVal; break;
+ case VT_UI8: size = (UInt64)prop.uhVal.QuadPart; break;
+ case VT_EMPTY: return S_OK;
+ default: return E_FAIL;
+ }
+ defined = true;
+ return S_OK;
+}
+
+HRESULT CArc::GetItem_MTime(UInt32 index, CArcTime &at) const
+{
+ at.Clear();
+ NCOM::CPropVariant prop;
+ RINOK(Archive->GetProperty(index, kpidMTime, &prop))
+
+ if (prop.vt == VT_FILETIME)
+ {
+ /*
+ // for debug
+ if (FILETIME_IsZero(prop.at) && MTime.Def)
+ {
+ at = MTime;
+ return S_OK;
+ }
+ */
+ at.Set_From_Prop(prop);
+ if (at.Prec == 0)
+ {
+ // (at.Prec == 0) before version 22.
+ // so kpidTimeType is required for that code
+ prop.Clear();
+ RINOK(Archive->GetProperty(index, kpidTimeType, &prop))
+ if (prop.vt == VT_UI4)
+ {
+ UInt32 val = prop.ulVal;
+ if (val == NFileTimeType::kWindows)
+ val = k_PropVar_TimePrec_100ns;
+ /*
+ else if (val > k_PropVar_TimePrec_1ns)
+ {
+ val = k_PropVar_TimePrec_100ns;
+ // val = k_PropVar_TimePrec_1ns;
+ // return E_FAIL; // for debug
+ }
+ */
+ at.Prec = (UInt16)val;
+ }
+ }
+ return S_OK;
+ }
+
+ if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ if (MTime.Def)
+ at = MTime;
+ return S_OK;
+}
+
+#ifndef Z7_SFX
+
+static inline bool TestSignature(const Byte *p1, const Byte *p2, size_t size)
+{
+ for (size_t i = 0; i < size; i++)
+ if (p1[i] != p2[i])
+ return false;
+ return true;
+}
+
+
+static void MakeCheckOrder(CCodecs *codecs,
+ CIntVector &orderIndices, unsigned numTypes, CIntVector &orderIndices2,
+ const Byte *data, size_t dataSize)
+{
+ for (unsigned i = 0; i < numTypes; i++)
+ {
+ const int index = orderIndices[i];
+ if (index < 0)
+ continue;
+ const CArcInfoEx &ai = codecs->Formats[(unsigned)index];
+ if (ai.SignatureOffset == 0)
+ {
+ if (ai.Signatures.IsEmpty())
+ {
+ if (dataSize != 0) // 21.04: no Signature means Empty Signature
+ continue;
+ }
+ else
+ {
+ unsigned k;
+ const CObjectVector<CByteBuffer> &sigs = ai.Signatures;
+ for (k = 0; k < sigs.Size(); k++)
+ {
+ const CByteBuffer &sig = sigs[k];
+ if (sig.Size() <= dataSize && TestSignature(data, sig, sig.Size()))
+ break;
+ }
+ if (k == sigs.Size())
+ continue;
+ }
+ }
+ orderIndices2.Add(index);
+ orderIndices[i] = -1;
+ }
+}
+
+#ifdef UNDER_CE
+ static const unsigned kNumHashBytes = 1;
+ #define HASH_VAL(buf) ((buf)[0])
+#else
+ static const unsigned kNumHashBytes = 2;
+ // #define HASH_VAL(buf) ((buf)[0] | ((UInt32)(buf)[1] << 8))
+ #define HASH_VAL(buf) GetUi16(buf)
+#endif
+
+static bool IsExeExt(const UString &ext)
+{
+ return ext.IsEqualTo_Ascii_NoCase("exe");
+}
+
+static const char * const k_PreArcFormats[] =
+{
+ "pe"
+ , "elf"
+ , "macho"
+ , "mub"
+ , "te"
+};
+
+static bool IsNameFromList(const UString &s, const char * const names[], size_t num)
+{
+ for (unsigned i = 0; i < num; i++)
+ if (StringsAreEqualNoCase_Ascii(s, names[i]))
+ return true;
+ return false;
+}
+
+
+static bool IsPreArcFormat(const CArcInfoEx &ai)
+{
+ if (ai.Flags_PreArc())
+ return true;
+ return IsNameFromList(ai.Name, k_PreArcFormats, Z7_ARRAY_SIZE(k_PreArcFormats));
+}
+
+static const char * const k_Formats_with_simple_signuature[] =
+{
+ "7z"
+ , "xz"
+ , "rar"
+ , "bzip2"
+ , "gzip"
+ , "cab"
+ , "wim"
+ , "rpm"
+ , "vhd"
+ , "xar"
+};
+
+static bool IsNewStyleSignature(const CArcInfoEx &ai)
+{
+ // if (ai.Version >= 0x91F)
+ if (ai.NewInterface)
+ return true;
+ return IsNameFromList(ai.Name, k_Formats_with_simple_signuature, Z7_ARRAY_SIZE(k_Formats_with_simple_signuature));
+}
+
+
+
+class CArchiveOpenCallback_Offset Z7_final:
+ public IArchiveOpenCallback,
+ public IArchiveOpenVolumeCallback,
+ #ifndef Z7_NO_CRYPTO
+ public ICryptoGetTextPassword,
+ #endif
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(IArchiveOpenCallback)
+ Z7_COM_QI_ENTRY(IArchiveOpenVolumeCallback)
+ #ifndef Z7_NO_CRYPTO
+ Z7_COM_QI_ENTRY(ICryptoGetTextPassword)
+ #endif
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(IArchiveOpenCallback)
+ Z7_IFACE_COM7_IMP(IArchiveOpenVolumeCallback)
+ #ifndef Z7_NO_CRYPTO
+ Z7_IFACE_COM7_IMP(ICryptoGetTextPassword)
+ #endif
+
+public:
+ CMyComPtr<IArchiveOpenCallback> Callback;
+ CMyComPtr<IArchiveOpenVolumeCallback> OpenVolumeCallback;
+ UInt64 Files;
+ UInt64 Offset;
+
+ #ifndef Z7_NO_CRYPTO
+ CMyComPtr<ICryptoGetTextPassword> GetTextPassword;
+ #endif
+};
+
+#ifndef Z7_NO_CRYPTO
+Z7_COM7F_IMF(CArchiveOpenCallback_Offset::CryptoGetTextPassword(BSTR *password))
+{
+ COM_TRY_BEGIN
+ if (GetTextPassword)
+ return GetTextPassword->CryptoGetTextPassword(password);
+ return E_NOTIMPL;
+ COM_TRY_END
+}
+#endif
+
+Z7_COM7F_IMF(CArchiveOpenCallback_Offset::SetTotal(const UInt64 *, const UInt64 *))
+{
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveOpenCallback_Offset::SetCompleted(const UInt64 *, const UInt64 *bytes))
+{
+ if (!Callback)
+ return S_OK;
+ UInt64 value = Offset;
+ if (bytes)
+ value += *bytes;
+ return Callback->SetCompleted(&Files, &value);
+}
+
+Z7_COM7F_IMF(CArchiveOpenCallback_Offset::GetProperty(PROPID propID, PROPVARIANT *value))
+{
+ if (OpenVolumeCallback)
+ return OpenVolumeCallback->GetProperty(propID, value);
+ NCOM::PropVariant_Clear(value);
+ return S_OK;
+ // return E_NOTIMPL;
+}
+
+Z7_COM7F_IMF(CArchiveOpenCallback_Offset::GetStream(const wchar_t *name, IInStream **inStream))
+{
+ if (OpenVolumeCallback)
+ return OpenVolumeCallback->GetStream(name, inStream);
+ return S_FALSE;
+}
+
+#endif
+
+
+UInt32 GetOpenArcErrorFlags(const NCOM::CPropVariant &prop, bool *isDefinedProp)
+{
+ if (isDefinedProp != NULL)
+ *isDefinedProp = false;
+
+ switch (prop.vt)
+ {
+ case VT_UI8: if (isDefinedProp) *isDefinedProp = true; return (UInt32)prop.uhVal.QuadPart;
+ case VT_UI4: if (isDefinedProp) *isDefinedProp = true; return prop.ulVal;
+ case VT_EMPTY: return 0;
+ default: throw 151199;
+ }
+}
+
+void CArcErrorInfo::ClearErrors()
+{
+ // ErrorFormatIndex = -1; // we don't need to clear ErrorFormatIndex here !!!
+
+ ThereIsTail = false;
+ UnexpecedEnd = false;
+ IgnoreTail = false;
+ // NonZerosTail = false;
+ ErrorFlags_Defined = false;
+ ErrorFlags = 0;
+ WarningFlags = 0;
+ TailSize = 0;
+
+ ErrorMessage.Empty();
+ WarningMessage.Empty();
+}
+
+HRESULT CArc::ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes)
+{
+ // OkPhySize_Defined = false;
+ PhySize_Defined = false;
+ PhySize = 0;
+ Offset = 0;
+ AvailPhySize = FileSize - startPos;
+
+ ErrorInfo.ClearErrors();
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetArchiveProperty(kpidErrorFlags, &prop))
+ ErrorInfo.ErrorFlags = GetOpenArcErrorFlags(prop, &ErrorInfo.ErrorFlags_Defined);
+ }
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetArchiveProperty(kpidWarningFlags, &prop))
+ ErrorInfo.WarningFlags = GetOpenArcErrorFlags(prop);
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetArchiveProperty(kpidError, &prop))
+ if (prop.vt != VT_EMPTY)
+ ErrorInfo.ErrorMessage = (prop.vt == VT_BSTR ? prop.bstrVal : L"Unknown error");
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetArchiveProperty(kpidWarning, &prop))
+ if (prop.vt != VT_EMPTY)
+ ErrorInfo.WarningMessage = (prop.vt == VT_BSTR ? prop.bstrVal : L"Unknown warning");
+ }
+
+ if (openRes == S_OK || ErrorInfo.IsArc_After_NonOpen())
+ {
+ RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, PhySize, PhySize_Defined))
+ /*
+ RINOK(Archive_GetArcProp_UInt(archive, kpidOkPhySize, OkPhySize, OkPhySize_Defined));
+ if (!OkPhySize_Defined)
+ {
+ OkPhySize_Defined = PhySize_Defined;
+ OkPhySize = PhySize;
+ }
+ */
+
+ bool offsetDefined;
+ RINOK(Archive_GetArcProp_Int(archive, kpidOffset, Offset, offsetDefined))
+
+ Int64 globalOffset = (Int64)startPos + Offset;
+ AvailPhySize = (UInt64)((Int64)FileSize - globalOffset);
+ if (PhySize_Defined)
+ {
+ UInt64 endPos = (UInt64)(globalOffset + (Int64)PhySize);
+ if (endPos < FileSize)
+ {
+ AvailPhySize = PhySize;
+ ErrorInfo.ThereIsTail = true;
+ ErrorInfo.TailSize = FileSize - endPos;
+ }
+ else if (endPos > FileSize)
+ ErrorInfo.UnexpecedEnd = true;
+ }
+ }
+
+ return S_OK;
+}
+
+/*
+static void PrintNumber(const char *s, int n)
+{
+ char temp[100];
+ sprintf(temp, "%s %d", s, n);
+ // OutputDebugStringA(temp);
+ printf(temp);
+}
+*/
+
+HRESULT CArc::PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr<IInArchive> &archive)
+{
+ // OutputDebugStringA("a1");
+ // PrintNumber("formatIndex", formatIndex);
+
+ RINOK(op.codecs->CreateInArchive(formatIndex, archive))
+ // OutputDebugStringA("a2");
+ if (!archive)
+ return S_OK;
+
+ #ifdef Z7_EXTERNAL_CODECS
+ if (op.codecs->NeedSetLibCodecs)
+ {
+ const CArcInfoEx &ai = op.codecs->Formats[formatIndex];
+ if (ai.LibIndex >= 0 ?
+ !op.codecs->Libs[(unsigned)ai.LibIndex].SetCodecs :
+ !op.codecs->Libs.IsEmpty())
+ {
+ CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+ archive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+ if (setCompressCodecsInfo)
+ {
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(op.codecs))
+ }
+ }
+ }
+ #endif
+
+
+ #ifndef Z7_SFX
+
+ const CArcInfoEx &ai = op.codecs->Formats[formatIndex];
+
+ // OutputDebugStringW(ai.Name);
+ // OutputDebugStringA("a3");
+
+ if (ai.Flags_PreArc())
+ {
+ /* we notify parsers that extract executables, that they don't need
+ to open archive, if there is tail after executable (for SFX cases) */
+ CMyComPtr<IArchiveAllowTail> allowTail;
+ archive.QueryInterface(IID_IArchiveAllowTail, (void **)&allowTail);
+ if (allowTail)
+ allowTail->AllowTail(BoolToInt(true));
+ }
+
+ if (op.props)
+ {
+ /*
+ FOR_VECTOR (y, op.props)
+ {
+ const COptionalOpenProperties &optProps = (*op.props)[y];
+ if (optProps.FormatName.IsEmpty() || optProps.FormatName.CompareNoCase(ai.Name) == 0)
+ {
+ RINOK(SetProperties(archive, optProps.Props));
+ break;
+ }
+ }
+ */
+ RINOK(SetProperties(archive, *op.props))
+ }
+
+ #endif
+ return S_OK;
+}
+
+#ifndef Z7_SFX
+
+static HRESULT ReadParseItemProps(IInArchive *archive, const CArcInfoEx &ai, NArchive::NParser::CParseItem &pi)
+{
+ pi.Extension = ai.GetMainExt();
+ pi.FileTime_Defined = false;
+ pi.ArcType = ai.Name;
+
+ RINOK(Archive_GetArcProp_Bool(archive, kpidIsNotArcType, pi.IsNotArcType))
+
+ // RINOK(Archive_GetArcProp_Bool(archive, kpidIsSelfExe, pi.IsSelfExe));
+ pi.IsSelfExe = ai.Flags_PreArc();
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetArchiveProperty(kpidMTime, &prop))
+ if (prop.vt == VT_FILETIME)
+ {
+ pi.FileTime_Defined = true;
+ pi.FileTime = prop.filetime;
+ }
+ }
+
+ if (!pi.FileTime_Defined)
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetArchiveProperty(kpidCTime, &prop))
+ if (prop.vt == VT_FILETIME)
+ {
+ pi.FileTime_Defined = true;
+ pi.FileTime = prop.filetime;
+ }
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetArchiveProperty(kpidName, &prop))
+ if (prop.vt == VT_BSTR)
+ {
+ pi.Name.SetFromBstr(prop.bstrVal);
+ pi.Extension.Empty();
+ }
+ else
+ {
+ RINOK(archive->GetArchiveProperty(kpidExtension, &prop))
+ if (prop.vt == VT_BSTR)
+ pi.Extension.SetFromBstr(prop.bstrVal);
+ }
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ RINOK(archive->GetArchiveProperty(kpidShortComment, &prop))
+ if (prop.vt == VT_BSTR)
+ pi.Comment.SetFromBstr(prop.bstrVal);
+ }
+
+
+ UInt32 numItems;
+ RINOK(archive->GetNumberOfItems(&numItems))
+
+ // pi.NumSubFiles = numItems;
+ // RINOK(Archive_GetArcProp_UInt(archive, kpidUnpackSize, pi.UnpackSize, pi.UnpackSize_Defined));
+ // if (!pi.UnpackSize_Defined)
+ {
+ pi.NumSubFiles = 0;
+ pi.NumSubDirs = 0;
+ pi.UnpackSize = 0;
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ UInt64 size = 0;
+ bool defined = false;
+ Archive_GetItem_Size(archive, i, size, defined);
+ if (defined)
+ {
+ pi.UnpackSize_Defined = true;
+ pi.UnpackSize += size;
+ }
+
+ bool isDir = false;
+ Archive_IsItem_Dir(archive, i, isDir);
+ if (isDir)
+ pi.NumSubDirs++;
+ else
+ pi.NumSubFiles++;
+ }
+ if (pi.NumSubDirs != 0)
+ pi.NumSubDirs_Defined = true;
+ pi.NumSubFiles_Defined = true;
+ }
+
+ return S_OK;
+}
+
+#endif
+
+HRESULT CArc::CheckZerosTail(const COpenOptions &op, UInt64 offset)
+{
+ if (!op.stream)
+ return S_OK;
+ RINOK(InStream_SeekSet(op.stream, offset))
+ const UInt32 kBufSize = 1 << 11;
+ Byte buf[kBufSize];
+
+ for (;;)
+ {
+ UInt32 processed = 0;
+ RINOK(op.stream->Read(buf, kBufSize, &processed))
+ if (processed == 0)
+ {
+ // ErrorInfo.NonZerosTail = false;
+ ErrorInfo.IgnoreTail = true;
+ return S_OK;
+ }
+ for (size_t i = 0; i < processed; i++)
+ {
+ if (buf[i] != 0)
+ {
+ // ErrorInfo.IgnoreTail = false;
+ // ErrorInfo.NonZerosTail = true;
+ return S_OK;
+ }
+ }
+ }
+}
+
+
+
+#ifndef Z7_SFX
+
+Z7_CLASS_IMP_COM_2(
+ CExtractCallback_To_OpenCallback
+ , IArchiveExtractCallback
+ , ICompressProgressInfo
+)
+ Z7_IFACE_COM7_IMP(IProgress)
+public:
+ CMyComPtr<IArchiveOpenCallback> Callback;
+ UInt64 Files;
+ UInt64 Offset;
+
+ void Init(IArchiveOpenCallback *callback)
+ {
+ Callback = callback;
+ Files = 0;
+ Offset = 0;
+ }
+};
+
+Z7_COM7F_IMF(CExtractCallback_To_OpenCallback::SetTotal(UInt64 /* size */))
+{
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CExtractCallback_To_OpenCallback::SetCompleted(const UInt64 * /* completeValue */))
+{
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CExtractCallback_To_OpenCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 * /* outSize */))
+{
+ if (Callback)
+ {
+ UInt64 value = Offset;
+ if (inSize)
+ value += *inSize;
+ return Callback->SetCompleted(&Files, &value);
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CExtractCallback_To_OpenCallback::GetStream(UInt32 /* index */, ISequentialOutStream **outStream, Int32 /* askExtractMode */))
+{
+ *outStream = NULL;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CExtractCallback_To_OpenCallback::PrepareOperation(Int32 /* askExtractMode */))
+{
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CExtractCallback_To_OpenCallback::SetOperationResult(Int32 /* operationResult */))
+{
+ return S_OK;
+}
+
+
+static HRESULT OpenArchiveSpec(IInArchive *archive, bool needPhySize,
+ IInStream *stream, const UInt64 *maxCheckStartPosition,
+ IArchiveOpenCallback *openCallback,
+ IArchiveExtractCallback *extractCallback)
+{
+ /*
+ if (needPhySize)
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IArchiveOpen2,
+ open2, archive)
+ if (open2)
+ return open2->ArcOpen2(stream, kOpenFlags_RealPhySize, openCallback);
+ }
+ */
+ RINOK(archive->Open(stream, maxCheckStartPosition, openCallback))
+ if (needPhySize)
+ {
+ bool phySize_Defined = false;
+ UInt64 phySize = 0;
+ RINOK(Archive_GetArcProp_UInt(archive, kpidPhySize, phySize, phySize_Defined))
+ if (phySize_Defined)
+ return S_OK;
+
+ bool phySizeCantBeDetected = false;
+ RINOK(Archive_GetArcProp_Bool(archive, kpidPhySizeCantBeDetected, phySizeCantBeDetected))
+
+ if (!phySizeCantBeDetected)
+ {
+ PRF(printf("\n-- !phySize_Defined after Open, call archive->Extract()"));
+ // It's for bzip2/gz and some xz archives, where Open operation doesn't know phySize.
+ // But the Handler will know phySize after full archive testing.
+ RINOK(archive->Extract(NULL, (UInt32)(Int32)-1, BoolToInt(true), extractCallback))
+ PRF(printf("\n-- OK"));
+ }
+ }
+ return S_OK;
+}
+
+
+
+static int FindFormatForArchiveType(CCodecs *codecs, CIntVector orderIndices, const char *name)
+{
+ FOR_VECTOR (i, orderIndices)
+ {
+ int oi = orderIndices[i];
+ if (oi >= 0)
+ if (StringsAreEqualNoCase_Ascii(codecs->Formats[(unsigned)oi].Name, name))
+ return (int)i;
+ }
+ return -1;
+}
+
+#endif
+
+HRESULT CArc::OpenStream2(const COpenOptions &op)
+{
+ // fprintf(stdout, "\nOpen: %S", Path); fflush(stdout);
+
+ Archive.Release();
+ GetRawProps.Release();
+ GetRootProps.Release();
+
+ ErrorInfo.ClearErrors();
+ ErrorInfo.ErrorFormatIndex = -1;
+
+ IsParseArc = false;
+ ArcStreamOffset = 0;
+
+ // OutputDebugStringA("1");
+ // OutputDebugStringW(Path);
+
+ const UString fileName = ExtractFileNameFromPath(Path);
+ UString extension;
+ {
+ const int dotPos = fileName.ReverseFind_Dot();
+ if (dotPos >= 0)
+ extension = fileName.Ptr((unsigned)(dotPos + 1));
+ }
+
+ CIntVector orderIndices;
+
+ bool searchMarkerInHandler = false;
+ #ifdef Z7_SFX
+ searchMarkerInHandler = true;
+ #endif
+
+ CBoolArr isMainFormatArr(op.codecs->Formats.Size());
+ {
+ FOR_VECTOR(i, op.codecs->Formats)
+ isMainFormatArr[i] = false;
+ }
+
+ const UInt64 maxStartOffset =
+ op.openType.MaxStartOffset_Defined ?
+ op.openType.MaxStartOffset :
+ kMaxCheckStartPosition;
+
+ #ifndef Z7_SFX
+ bool isUnknownExt = false;
+ #endif
+
+ #ifndef Z7_SFX
+ bool isForced = false;
+ #endif
+
+ unsigned numMainTypes = 0;
+ const int formatIndex = op.openType.FormatIndex;
+
+ if (formatIndex >= 0)
+ {
+ #ifndef Z7_SFX
+ isForced = true;
+ #endif
+ orderIndices.Add(formatIndex);
+ numMainTypes = 1;
+ isMainFormatArr[(unsigned)formatIndex] = true;
+
+ searchMarkerInHandler = true;
+ }
+ else
+ {
+ unsigned numFinded = 0;
+ #ifndef Z7_SFX
+ bool isPrearcExt = false;
+ #endif
+
+ {
+ #ifndef Z7_SFX
+
+ bool isZip = false;
+ bool isRar = false;
+
+ const wchar_t c = extension[0];
+ if (c == 'z' || c == 'Z' || c == 'r' || c == 'R')
+ {
+ bool isNumber = false;
+ for (unsigned k = 1;; k++)
+ {
+ const wchar_t d = extension[k];
+ if (d == 0)
+ break;
+ if (d < '0' || d > '9')
+ {
+ isNumber = false;
+ break;
+ }
+ isNumber = true;
+ }
+ if (isNumber)
+ {
+ if (c == 'z' || c == 'Z')
+ isZip = true;
+ else
+ isRar = true;
+ }
+ }
+
+ #endif
+
+ FOR_VECTOR (i, op.codecs->Formats)
+ {
+ const CArcInfoEx &ai = op.codecs->Formats[i];
+
+ if (IgnoreSplit || !op.openType.CanReturnArc)
+ if (ai.Is_Split())
+ continue;
+ if (op.excludedFormats->FindInSorted((int)i) >= 0)
+ continue;
+
+ #ifndef Z7_SFX
+ if (IsPreArcFormat(ai))
+ isPrearcExt = true;
+ #endif
+
+ if (ai.FindExtension(extension) >= 0
+ #ifndef Z7_SFX
+ || (isZip && ai.Is_Zip())
+ || (isRar && ai.Is_Rar())
+ #endif
+ )
+ {
+ // PrintNumber("orderIndices.Insert", i);
+ orderIndices.Insert(numFinded++, (int)i);
+ isMainFormatArr[i] = true;
+ }
+ else
+ orderIndices.Add((int)i);
+ }
+ }
+
+ if (!op.stream)
+ {
+ if (numFinded != 1)
+ return E_NOTIMPL;
+ orderIndices.DeleteFrom(1);
+ }
+ // PrintNumber("numFinded", numFinded );
+
+ /*
+ if (op.openOnlySpecifiedByExtension)
+ {
+ if (numFinded != 0 && !IsExeExt(extension))
+ orderIndices.DeleteFrom(numFinded);
+ }
+ */
+
+ #ifndef Z7_SFX
+
+ if (op.stream && orderIndices.Size() >= 2)
+ {
+ RINOK(InStream_SeekToBegin(op.stream))
+ CByteBuffer byteBuffer;
+ CIntVector orderIndices2;
+ if (numFinded == 0 || IsExeExt(extension))
+ {
+ // signature search was here
+ }
+ else if (extension.IsEqualTo("000") || extension.IsEqualTo("001"))
+ {
+ const int i = FindFormatForArchiveType(op.codecs, orderIndices, "rar");
+ if (i >= 0)
+ {
+ const size_t kBufSize = (1 << 10);
+ byteBuffer.Alloc(kBufSize);
+ size_t processedSize = kBufSize;
+ RINOK(ReadStream(op.stream, byteBuffer, &processedSize))
+ if (processedSize >= 16)
+ {
+ const Byte *buf = byteBuffer;
+ const Byte kRarHeader[] = { 0x52 , 0x61, 0x72, 0x21, 0x1a, 0x07, 0x00 };
+ if (TestSignature(buf, kRarHeader, 7) && buf[9] == 0x73 && (buf[10] & 1) != 0)
+ {
+ orderIndices2.Add(orderIndices[(unsigned)i]);
+ orderIndices[(unsigned)i] = -1;
+ if (i >= (int)numFinded)
+ numFinded++;
+ }
+ }
+ }
+ }
+ else
+ {
+ const size_t kBufSize = (1 << 10);
+ byteBuffer.Alloc(kBufSize);
+ size_t processedSize = kBufSize;
+ RINOK(ReadStream(op.stream, byteBuffer, &processedSize))
+ if (processedSize == 0)
+ return S_FALSE;
+
+ /*
+ check type order:
+ 0) matched_extension && Backward
+ 1) matched_extension && (no_signuature || SignatureOffset != 0)
+ 2) matched_extension && (matched_signature)
+ // 3) no signuature
+ // 4) matched signuature
+ */
+ // we move index from orderIndices to orderIndices2 for priority handlers.
+
+ for (unsigned i = 0; i < numFinded; i++)
+ {
+ const int index = orderIndices[i];
+ if (index < 0)
+ continue;
+ const CArcInfoEx &ai = op.codecs->Formats[(unsigned)index];
+ if (ai.Flags_BackwardOpen())
+ {
+ // backward doesn't need start signatures
+ orderIndices2.Add(index);
+ orderIndices[i] = -1;
+ }
+ }
+
+ MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, NULL, 0);
+ MakeCheckOrder(op.codecs, orderIndices, numFinded, orderIndices2, byteBuffer, processedSize);
+ // MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, NULL, 0);
+ // MakeCheckOrder(op.codecs, orderIndices, orderIndices.Size(), orderIndices2, byteBuffer, processedSize);
+ }
+
+ FOR_VECTOR (i, orderIndices)
+ {
+ const int val = orderIndices[i];
+ if (val != -1)
+ orderIndices2.Add(val);
+ }
+ orderIndices = orderIndices2;
+ }
+
+ if (orderIndices.Size() >= 2)
+ {
+ const int iIso = FindFormatForArchiveType(op.codecs, orderIndices, "iso");
+ const int iUdf = FindFormatForArchiveType(op.codecs, orderIndices, "udf");
+ if (iUdf > iIso && iIso >= 0)
+ {
+ const int isoIndex = orderIndices[(unsigned)iIso];
+ const int udfIndex = orderIndices[(unsigned)iUdf];
+ orderIndices[(unsigned)iUdf] = isoIndex;
+ orderIndices[(unsigned)iIso] = udfIndex;
+ }
+ }
+
+ numMainTypes = numFinded;
+ isUnknownExt = (numMainTypes == 0) || isPrearcExt;
+
+ #else // Z7_SFX
+
+ numMainTypes = orderIndices.Size();
+
+ // we need correct numMainTypes for mutlivolume SFX (if some volume is missing)
+ if (numFinded != 0)
+ numMainTypes = numFinded;
+
+ #endif
+ }
+
+ UInt64 fileSize = 0;
+ if (op.stream)
+ {
+ RINOK(InStream_GetSize_SeekToBegin(op.stream, fileSize))
+ }
+ FileSize = fileSize;
+
+
+ #ifndef Z7_SFX
+
+ CBoolArr skipFrontalFormat(op.codecs->Formats.Size());
+ {
+ FOR_VECTOR(i, op.codecs->Formats)
+ skipFrontalFormat[i] = false;
+ }
+
+ #endif
+
+ const COpenType &mode = op.openType;
+
+
+
+
+
+ if (mode.CanReturnArc)
+ {
+ // ---------- OPEN main type by extenssion ----------
+
+ unsigned numCheckTypes = orderIndices.Size();
+ if (formatIndex >= 0)
+ numCheckTypes = numMainTypes;
+
+ for (unsigned i = 0; i < numCheckTypes; i++)
+ {
+ FormatIndex = orderIndices[i];
+
+ // orderIndices[] item cannot be negative here
+
+ bool exactOnly = false;
+
+ #ifndef Z7_SFX
+
+ const CArcInfoEx &ai = op.codecs->Formats[(unsigned)FormatIndex];
+ // OutputDebugStringW(ai.Name);
+ if (i >= numMainTypes)
+ {
+ // here we allow mismatched extension only for backward handlers
+ if (!ai.Flags_BackwardOpen()
+ // && !ai.Flags_PureStartOpen()
+ )
+ continue;
+ exactOnly = true;
+ }
+
+ #endif
+
+ // Some handlers do not set total bytes. So we set it here
+ if (op.callback)
+ RINOK(op.callback->SetTotal(NULL, &fileSize))
+
+ if (op.stream)
+ {
+ RINOK(InStream_SeekToBegin(op.stream))
+ }
+
+ CMyComPtr<IInArchive> archive;
+
+ RINOK(PrepareToOpen(op, (unsigned)FormatIndex, archive))
+ if (!archive)
+ continue;
+
+ HRESULT result;
+ if (op.stream)
+ {
+ UInt64 searchLimit = (!exactOnly && searchMarkerInHandler) ? maxStartOffset: 0;
+ result = archive->Open(op.stream, &searchLimit, op.callback);
+ }
+ else
+ {
+ CMyComPtr<IArchiveOpenSeq> openSeq;
+ archive.QueryInterface(IID_IArchiveOpenSeq, (void **)&openSeq);
+ if (!openSeq)
+ return E_NOTIMPL;
+ result = openSeq->OpenSeq(op.seqStream);
+ }
+
+ RINOK(ReadBasicProps(archive, 0, result))
+
+ if (result == S_FALSE)
+ {
+ bool isArc = ErrorInfo.IsArc_After_NonOpen();
+
+ #ifndef Z7_SFX
+ // if it's archive, we allow another open attempt for parser
+ if (!mode.CanReturnParser || !isArc)
+ skipFrontalFormat[(unsigned)FormatIndex] = true;
+ #endif
+
+ if (exactOnly)
+ continue;
+
+ if (i == 0 && numMainTypes == 1)
+ {
+ // we set NonOpenErrorInfo, only if there is only one main format (defined by extension).
+ ErrorInfo.ErrorFormatIndex = FormatIndex;
+ NonOpen_ErrorInfo = ErrorInfo;
+
+ if (!mode.CanReturnParser && isArc)
+ {
+ // if (formatIndex < 0 && !searchMarkerInHandler)
+ {
+ // if bad archive was detected, we don't need additional open attempts
+ #ifndef Z7_SFX
+ if (!IsPreArcFormat(ai) /* || !mode.SkipSfxStub */)
+ #endif
+ return S_FALSE;
+ }
+ }
+ }
+
+ /*
+ #ifndef Z7_SFX
+ if (IsExeExt(extension) || ai.Flags_PreArc())
+ {
+ // openOnlyFullArc = false;
+ // canReturnTailArc = true;
+ // limitSignatureSearch = true;
+ }
+ #endif
+ */
+
+ continue;
+ }
+
+ RINOK(result)
+
+ #ifndef Z7_SFX
+
+ bool isMainFormat = isMainFormatArr[(unsigned)FormatIndex];
+ const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt);
+
+ bool thereIsTail = ErrorInfo.ThereIsTail;
+ if (thereIsTail && mode.ZerosTailIsAllowed)
+ {
+ RINOK(CheckZerosTail(op, (UInt64)(Offset + (Int64)PhySize)))
+ if (ErrorInfo.IgnoreTail)
+ thereIsTail = false;
+ }
+
+ if (Offset > 0)
+ {
+ if (exactOnly
+ || !searchMarkerInHandler
+ || !specFlags.CanReturn_NonStart()
+ || (mode.MaxStartOffset_Defined && (UInt64)Offset > mode.MaxStartOffset))
+ continue;
+ }
+ if (thereIsTail)
+ {
+ if (Offset > 0)
+ {
+ if (!specFlags.CanReturnMid)
+ continue;
+ }
+ else if (!specFlags.CanReturnFrontal)
+ continue;
+ }
+
+ if (Offset > 0 || thereIsTail)
+ {
+ if (formatIndex < 0)
+ {
+ if (IsPreArcFormat(ai))
+ {
+ // openOnlyFullArc = false;
+ // canReturnTailArc = true;
+ /*
+ if (mode.SkipSfxStub)
+ limitSignatureSearch = true;
+ */
+ // if (mode.SkipSfxStub)
+ {
+ // skipFrontalFormat[FormatIndex] = true;
+ continue;
+ }
+ }
+ }
+ }
+
+ #endif
+
+ Archive = archive;
+ return S_OK;
+ }
+ }
+
+
+
+ #ifndef Z7_SFX
+
+ if (!op.stream)
+ return S_FALSE;
+
+ if (formatIndex >= 0 && !mode.CanReturnParser)
+ {
+ if (mode.MaxStartOffset_Defined)
+ {
+ if (mode.MaxStartOffset == 0)
+ return S_FALSE;
+ }
+ else
+ {
+ const CArcInfoEx &ai = op.codecs->Formats[(unsigned)formatIndex];
+ if (ai.FindExtension(extension) >= 0)
+ {
+ if (ai.Flags_FindSignature() && searchMarkerInHandler)
+ return S_FALSE;
+ }
+ }
+ }
+
+ NArchive::NParser::CHandler *handlerSpec = new NArchive::NParser::CHandler;
+ CMyComPtr<IInArchive> handler = handlerSpec;
+
+ CExtractCallback_To_OpenCallback *extractCallback_To_OpenCallback_Spec = new CExtractCallback_To_OpenCallback;
+ CMyComPtr<IArchiveExtractCallback> extractCallback_To_OpenCallback = extractCallback_To_OpenCallback_Spec;
+ extractCallback_To_OpenCallback_Spec->Init(op.callback);
+
+ {
+ // ---------- Check all possible START archives ----------
+ // this code is better for full file archives than Parser's code.
+
+ CByteBuffer byteBuffer;
+ bool endOfFile = false;
+ size_t processedSize;
+ {
+ size_t bufSize = 1 << 20; // it must be larger than max signature offset or IsArcFunc offset ((1 << 19) + x for UDF)
+ if (bufSize > fileSize)
+ {
+ bufSize = (size_t)fileSize;
+ endOfFile = true;
+ }
+ byteBuffer.Alloc(bufSize);
+ RINOK(InStream_SeekToBegin(op.stream))
+ processedSize = bufSize;
+ RINOK(ReadStream(op.stream, byteBuffer, &processedSize))
+ if (processedSize == 0)
+ return S_FALSE;
+ if (processedSize < bufSize)
+ endOfFile = true;
+ }
+ CUIntVector sortedFormats;
+
+ unsigned i;
+
+ int splitIndex = -1;
+
+ for (i = 0; i < orderIndices.Size(); i++)
+ {
+ // orderIndices[] item cannot be negative here
+ unsigned form = (unsigned)orderIndices[i];
+ if (skipFrontalFormat[form])
+ continue;
+
+ const CArcInfoEx &ai = op.codecs->Formats[form];
+
+ if (ai.Is_Split())
+ {
+ splitIndex = (int)form;
+ continue;
+ }
+
+ if (ai.Flags_ByExtOnlyOpen())
+ continue;
+
+ if (ai.IsArcFunc)
+ {
+ UInt32 isArcRes = ai.IsArcFunc(byteBuffer, processedSize);
+ if (isArcRes == k_IsArc_Res_NO)
+ continue;
+ if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile)
+ continue;
+ // if (isArcRes == k_IsArc_Res_YES_LOW_PROB) continue;
+ sortedFormats.Insert(0, form);
+ continue;
+ }
+
+ const bool isNewStyleSignature = IsNewStyleSignature(ai);
+ bool needCheck = !isNewStyleSignature
+ || ai.Signatures.IsEmpty()
+ || ai.Flags_PureStartOpen()
+ || ai.Flags_StartOpen()
+ || ai.Flags_BackwardOpen();
+
+ if (isNewStyleSignature && !ai.Signatures.IsEmpty())
+ {
+ unsigned k;
+ for (k = 0; k < ai.Signatures.Size(); k++)
+ {
+ const CByteBuffer &sig = ai.Signatures[k];
+ if (processedSize < ai.SignatureOffset + sig.Size())
+ {
+ if (!endOfFile)
+ needCheck = true;
+ }
+ else if (TestSignature(sig, byteBuffer + ai.SignatureOffset, sig.Size()))
+ break;
+ }
+ if (k != ai.Signatures.Size())
+ {
+ sortedFormats.Insert(0, form);
+ continue;
+ }
+ }
+ if (needCheck)
+ sortedFormats.Add(form);
+ }
+
+ if (splitIndex >= 0)
+ sortedFormats.Insert(0, (unsigned)splitIndex);
+
+ for (i = 0; i < sortedFormats.Size(); i++)
+ {
+ FormatIndex = (int)sortedFormats[i];
+ const CArcInfoEx &ai = op.codecs->Formats[(unsigned)FormatIndex];
+
+ if (op.callback)
+ RINOK(op.callback->SetTotal(NULL, &fileSize))
+
+ RINOK(InStream_SeekToBegin(op.stream))
+
+ CMyComPtr<IInArchive> archive;
+ RINOK(PrepareToOpen(op, (unsigned)FormatIndex, archive))
+ if (!archive)
+ continue;
+
+ PRF(printf("\nSorted Open %S", (const wchar_t *)ai.Name));
+ HRESULT result;
+ {
+ UInt64 searchLimit = 0;
+ /*
+ if (mode.CanReturnArc)
+ result = archive->Open(op.stream, &searchLimit, op.callback);
+ else
+ */
+ // if (!CanReturnArc), it's ParserMode, and we need phy size
+ result = OpenArchiveSpec(archive,
+ !mode.CanReturnArc, // needPhySize
+ op.stream, &searchLimit, op.callback, extractCallback_To_OpenCallback);
+ }
+
+ if (result == S_FALSE)
+ {
+ skipFrontalFormat[(unsigned)FormatIndex] = true;
+ // FIXME: maybe we must use LenIsUnknown.
+ // printf(" OpenForSize Error");
+ continue;
+ }
+ RINOK(result)
+
+ RINOK(ReadBasicProps(archive, 0, result))
+
+ if (Offset > 0)
+ {
+ continue; // good handler doesn't return such Offset > 0
+ // but there are some cases like false prefixed PK00 archive, when
+ // we can support it?
+ }
+
+ NArchive::NParser::CParseItem pi;
+ pi.Offset = (UInt64)Offset;
+ pi.Size = AvailPhySize;
+
+ // bool needScan = false;
+
+ if (!PhySize_Defined)
+ {
+ // it's for Z format
+ pi.LenIsUnknown = true;
+ // needScan = true;
+ // phySize = arcRem;
+ // nextNeedCheckStartOpen = false;
+ }
+
+ /*
+ if (OkPhySize_Defined)
+ pi.OkSize = pi.OkPhySize;
+ else
+ pi.OkSize = pi.Size;
+ */
+
+ pi.NormalizeOffset();
+ // printf(" phySize = %8d", (unsigned)phySize);
+
+
+ if (mode.CanReturnArc)
+ {
+ const bool isMainFormat = isMainFormatArr[(unsigned)FormatIndex];
+ const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt);
+ bool openCur = false;
+
+ if (!ErrorInfo.ThereIsTail)
+ openCur = true;
+ else
+ {
+ if (mode.ZerosTailIsAllowed)
+ {
+ RINOK(CheckZerosTail(op, (UInt64)(Offset + (Int64)PhySize)))
+ if (ErrorInfo.IgnoreTail)
+ openCur = true;
+ }
+ if (!openCur)
+ {
+ openCur = specFlags.CanReturnFrontal;
+ if (formatIndex < 0) // format is not forced
+ {
+ if (IsPreArcFormat(ai))
+ {
+ // if (mode.SkipSfxStub)
+ {
+ openCur = false;
+ }
+ }
+ }
+ }
+ }
+
+ if (openCur)
+ {
+ InStream = op.stream;
+ Archive = archive;
+ return S_OK;
+ }
+ }
+
+ skipFrontalFormat[(unsigned)FormatIndex] = true;
+
+
+ // if (!mode.CanReturnArc)
+ /*
+ if (!ErrorInfo.ThereIsTail)
+ continue;
+ */
+ if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize)
+ continue;
+
+ // printf("\nAdd offset = %d", (int)pi.Offset);
+ RINOK(ReadParseItemProps(archive, ai, pi))
+ handlerSpec->AddItem(pi);
+ }
+ }
+
+
+
+
+
+ // ---------- PARSER ----------
+
+ CUIntVector arc2sig; // formatIndex to signatureIndex
+ CUIntVector sig2arc; // signatureIndex to formatIndex;
+ {
+ unsigned sum = 0;
+ FOR_VECTOR (i, op.codecs->Formats)
+ {
+ arc2sig.Add(sum);
+ const CObjectVector<CByteBuffer> &sigs = op.codecs->Formats[i].Signatures;
+ sum += sigs.Size();
+ FOR_VECTOR (k, sigs)
+ sig2arc.Add(i);
+ }
+ }
+
+ {
+ const size_t kBeforeSize = 1 << 16;
+ const size_t kAfterSize = 1 << 20;
+ const size_t kBufSize = 1 << 22; // it must be more than kBeforeSize + kAfterSize
+
+ const UInt32 kNumVals = (UInt32)1 << (kNumHashBytes * 8);
+ CByteArr hashBuffer(kNumVals);
+ Byte *hash = hashBuffer;
+ memset(hash, 0xFF, kNumVals);
+ Byte prevs[256];
+ memset(prevs, 0xFF, sizeof(prevs));
+ if (sig2arc.Size() >= 0xFF)
+ return S_FALSE;
+
+ CUIntVector difficultFormats;
+ CBoolArr difficultBools(256);
+ {
+ for (unsigned i = 0; i < 256; i++)
+ difficultBools[i] = false;
+ }
+
+ bool thereAreHandlersForSearch = false;
+
+ // UInt32 maxSignatureEnd = 0;
+
+ FOR_VECTOR (i, orderIndices)
+ {
+ int index = orderIndices[i];
+ if (index < 0)
+ continue;
+ const CArcInfoEx &ai = op.codecs->Formats[(unsigned)index];
+ if (ai.Flags_ByExtOnlyOpen())
+ continue;
+ bool isDifficult = false;
+ // if (ai.Version < 0x91F) // we don't use parser with old DLL (before 9.31)
+ if (!ai.NewInterface)
+ isDifficult = true;
+ else
+ {
+ if (ai.Flags_StartOpen())
+ isDifficult = true;
+ FOR_VECTOR (k, ai.Signatures)
+ {
+ const CByteBuffer &sig = ai.Signatures[k];
+ /*
+ UInt32 signatureEnd = ai.SignatureOffset + (UInt32)sig.Size();
+ if (maxSignatureEnd < signatureEnd)
+ maxSignatureEnd = signatureEnd;
+ */
+ if (sig.Size() < kNumHashBytes)
+ {
+ isDifficult = true;
+ continue;
+ }
+ thereAreHandlersForSearch = true;
+ UInt32 v = HASH_VAL(sig);
+ unsigned sigIndex = arc2sig[(unsigned)index] + k;
+ prevs[sigIndex] = hash[v];
+ hash[v] = (Byte)sigIndex;
+ }
+ }
+ if (isDifficult)
+ {
+ difficultFormats.Add((unsigned)index);
+ difficultBools[(unsigned)index] = true;
+ }
+ }
+
+ if (!thereAreHandlersForSearch)
+ {
+ // openOnlyFullArc = true;
+ // canReturnTailArc = true;
+ }
+
+ RINOK(InStream_SeekToBegin(op.stream))
+
+ CLimitedCachedInStream *limitedStreamSpec = new CLimitedCachedInStream;
+ CMyComPtr<IInStream> limitedStream = limitedStreamSpec;
+ limitedStreamSpec->SetStream(op.stream);
+
+ CArchiveOpenCallback_Offset *openCallback_Offset_Spec = NULL;
+ CMyComPtr<IArchiveOpenCallback> openCallback_Offset;
+ if (op.callback)
+ {
+ openCallback_Offset_Spec = new CArchiveOpenCallback_Offset;
+ openCallback_Offset = openCallback_Offset_Spec;
+ openCallback_Offset_Spec->Callback = op.callback;
+ openCallback_Offset_Spec->Callback.QueryInterface(IID_IArchiveOpenVolumeCallback, &openCallback_Offset_Spec->OpenVolumeCallback);
+ #ifndef Z7_NO_CRYPTO
+ openCallback_Offset_Spec->Callback.QueryInterface(IID_ICryptoGetTextPassword, &openCallback_Offset_Spec->GetTextPassword);
+ #endif
+ }
+
+ if (op.callback)
+ RINOK(op.callback->SetTotal(NULL, &fileSize))
+
+ CByteBuffer &byteBuffer = limitedStreamSpec->Buffer;
+ byteBuffer.Alloc(kBufSize);
+
+ UInt64 callbackPrev = 0;
+ bool needCheckStartOpen = true; // = true, if we need to test all archives types for current pos.
+
+ bool endOfFile = false;
+ UInt64 bufPhyPos = 0;
+ size_t bytesInBuf = 0;
+ // UInt64 prevPos = 0;
+
+ // ---------- Main Scan Loop ----------
+
+ UInt64 pos = 0;
+
+ if (!mode.EachPos && handlerSpec->_items.Size() == 1)
+ {
+ NArchive::NParser::CParseItem &pi = handlerSpec->_items[0];
+ if (!pi.LenIsUnknown && pi.Offset == 0)
+ pos = pi.Size;
+ }
+
+ for (;;)
+ {
+ // printf("\nPos = %d", (int)pos);
+ UInt64 posInBuf = pos - bufPhyPos;
+
+ // if (pos > ((UInt64)1 << 35)) break;
+
+ if (!endOfFile)
+ {
+ if (bytesInBuf < kBufSize)
+ {
+ size_t processedSize = kBufSize - bytesInBuf;
+ // printf("\nRead ask = %d", (unsigned)processedSize);
+ UInt64 seekPos = bufPhyPos + bytesInBuf;
+ RINOK(InStream_SeekSet(op.stream, bufPhyPos + bytesInBuf))
+ RINOK(ReadStream(op.stream, byteBuffer + bytesInBuf, &processedSize))
+ // printf(" processed = %d", (unsigned)processedSize);
+ if (processedSize == 0)
+ {
+ fileSize = seekPos;
+ endOfFile = true;
+ }
+ else
+ {
+ bytesInBuf += processedSize;
+ limitedStreamSpec->SetCache(processedSize, (size_t)bufPhyPos);
+ }
+ continue;
+ }
+
+ if (bytesInBuf < posInBuf)
+ {
+ UInt64 skipSize = posInBuf - bytesInBuf;
+ if (skipSize <= kBeforeSize)
+ {
+ size_t keepSize = (size_t)(kBeforeSize - skipSize);
+ // printf("\nmemmove skip = %d", (int)keepSize);
+ memmove(byteBuffer, byteBuffer + bytesInBuf - keepSize, keepSize);
+ bytesInBuf = keepSize;
+ bufPhyPos = pos - keepSize;
+ continue;
+ }
+ // printf("\nSkip %d", (int)(skipSize - kBeforeSize));
+ // RINOK(op.stream->Seek(skipSize - kBeforeSize, STREAM_SEEK_CUR, NULL));
+ bytesInBuf = 0;
+ bufPhyPos = pos - kBeforeSize;
+ continue;
+ }
+
+ if (bytesInBuf - posInBuf < kAfterSize)
+ {
+ size_t beg = (size_t)posInBuf - kBeforeSize;
+ // printf("\nmemmove for after beg = %d", (int)beg);
+ memmove(byteBuffer, byteBuffer + beg, bytesInBuf - beg);
+ bufPhyPos += beg;
+ bytesInBuf -= beg;
+ continue;
+ }
+ }
+
+ if (bytesInBuf <= (size_t)posInBuf)
+ break;
+
+ bool useOffsetCallback = false;
+ if (openCallback_Offset)
+ {
+ openCallback_Offset_Spec->Files = handlerSpec->_items.Size();
+ openCallback_Offset_Spec->Offset = pos;
+
+ useOffsetCallback = (!op.openType.CanReturnArc || handlerSpec->_items.Size() > 1);
+
+ if (pos >= callbackPrev + (1 << 23))
+ {
+ RINOK(openCallback_Offset->SetCompleted(NULL, NULL))
+ callbackPrev = pos;
+ }
+ }
+
+ {
+ UInt64 endPos = bufPhyPos + bytesInBuf;
+ if (fileSize < endPos)
+ {
+ FileSize = fileSize; // why ????
+ fileSize = endPos;
+ }
+ }
+
+ const size_t availSize = bytesInBuf - (size_t)posInBuf;
+ if (availSize < kNumHashBytes)
+ break;
+ size_t scanSize = availSize -
+ ((availSize >= kAfterSize) ? kAfterSize : kNumHashBytes);
+
+ {
+ /*
+ UInt64 scanLimit = openOnlyFullArc ?
+ maxSignatureEnd :
+ op.openType.ScanSize + maxSignatureEnd;
+ */
+ if (!mode.CanReturnParser)
+ {
+ if (pos > maxStartOffset)
+ break;
+ UInt64 remScan = maxStartOffset - pos;
+ if (scanSize > remScan)
+ scanSize = (size_t)remScan;
+ }
+ }
+
+ scanSize++;
+
+ const Byte *buf = byteBuffer + (size_t)posInBuf;
+ const Byte *bufLimit = buf + scanSize;
+ size_t ppp = 0;
+
+ if (!needCheckStartOpen)
+ {
+ for (; buf < bufLimit && hash[HASH_VAL(buf)] == 0xFF; buf++);
+ ppp = (size_t)(buf - (byteBuffer + (size_t)posInBuf));
+ pos += ppp;
+ if (buf == bufLimit)
+ continue;
+ }
+
+ UInt32 v = HASH_VAL(buf);
+ bool nextNeedCheckStartOpen = true;
+ unsigned i = hash[v];
+ unsigned indexOfDifficult = 0;
+
+ // ---------- Open Loop for Current Pos ----------
+ bool wasOpen = false;
+
+ for (;;)
+ {
+ unsigned index;
+ bool isDifficult;
+ if (needCheckStartOpen && indexOfDifficult < difficultFormats.Size())
+ {
+ index = difficultFormats[indexOfDifficult++];
+ isDifficult = true;
+ }
+ else
+ {
+ if (i == 0xFF)
+ break;
+ index = sig2arc[i];
+ unsigned sigIndex = i - arc2sig[index];
+ i = prevs[i];
+ if (needCheckStartOpen && difficultBools[index])
+ continue;
+ const CArcInfoEx &ai = op.codecs->Formats[index];
+
+ if (pos < ai.SignatureOffset)
+ continue;
+
+ /*
+ if (openOnlyFullArc)
+ if (pos != ai.SignatureOffset)
+ continue;
+ */
+
+ const CByteBuffer &sig = ai.Signatures[sigIndex];
+
+ if (ppp + sig.Size() > availSize
+ || !TestSignature(buf, sig, sig.Size()))
+ continue;
+ // printf("\nSignature OK: %10S %8x %5d", (const wchar_t *)ai.Name, (int)pos, (int)(pos - prevPos));
+ // prevPos = pos;
+ isDifficult = false;
+ }
+
+ const CArcInfoEx &ai = op.codecs->Formats[index];
+
+
+ if ((isDifficult && pos == 0) || ai.SignatureOffset == pos)
+ {
+ // we don't check same archive second time */
+ if (skipFrontalFormat[index])
+ continue;
+ }
+
+ UInt64 startArcPos = pos;
+ if (!isDifficult)
+ {
+ if (pos < ai.SignatureOffset)
+ continue;
+ startArcPos = pos - ai.SignatureOffset;
+ /*
+ // we don't need the check for Z files
+ if (startArcPos < handlerSpec->GetLastEnd())
+ continue;
+ */
+ }
+
+ if (ai.IsArcFunc && startArcPos >= bufPhyPos)
+ {
+ const size_t offsetInBuf = (size_t)(startArcPos - bufPhyPos);
+ if (offsetInBuf < bytesInBuf)
+ {
+ const UInt32 isArcRes = ai.IsArcFunc(byteBuffer + offsetInBuf, bytesInBuf - offsetInBuf);
+ if (isArcRes == k_IsArc_Res_NO)
+ continue;
+ if (isArcRes == k_IsArc_Res_NEED_MORE && endOfFile)
+ continue;
+ /*
+ if (isArcRes == k_IsArc_Res_YES_LOW_PROB)
+ {
+ // if (pos != ai.SignatureOffset)
+ continue;
+ }
+ */
+ }
+ // printf("\nIsArc OK: %S", (const wchar_t *)ai.Name);
+ }
+
+ PRF(printf("\npos = %9I64d : %S", pos, (const wchar_t *)ai.Name));
+
+ const bool isMainFormat = isMainFormatArr[index];
+ const COpenSpecFlags &specFlags = mode.GetSpec(isForced, isMainFormat, isUnknownExt);
+
+ CMyComPtr<IInArchive> archive;
+ RINOK(PrepareToOpen(op, index, archive))
+ if (!archive)
+ return E_FAIL;
+
+ // OutputDebugStringW(ai.Name);
+
+ const UInt64 rem = fileSize - startArcPos;
+
+ UInt64 arcStreamOffset = 0;
+
+ if (ai.Flags_UseGlobalOffset())
+ {
+ RINOK(limitedStreamSpec->InitAndSeek(0, fileSize))
+ RINOK(InStream_SeekSet(limitedStream, startArcPos))
+ }
+ else
+ {
+ RINOK(limitedStreamSpec->InitAndSeek(startArcPos, rem))
+ arcStreamOffset = startArcPos;
+ }
+
+ UInt64 maxCheckStartPosition = 0;
+
+ if (openCallback_Offset)
+ {
+ openCallback_Offset_Spec->Files = handlerSpec->_items.Size();
+ openCallback_Offset_Spec->Offset = startArcPos;
+ }
+
+ // HRESULT result = archive->Open(limitedStream, &maxCheckStartPosition, openCallback_Offset);
+ extractCallback_To_OpenCallback_Spec->Files = 0;
+ extractCallback_To_OpenCallback_Spec->Offset = startArcPos;
+
+ HRESULT result = OpenArchiveSpec(archive,
+ true, // needPhySize
+ limitedStream, &maxCheckStartPosition,
+ useOffsetCallback ? (IArchiveOpenCallback *)openCallback_Offset : (IArchiveOpenCallback *)op.callback,
+ extractCallback_To_OpenCallback);
+
+ RINOK(ReadBasicProps(archive, ai.Flags_UseGlobalOffset() ? 0 : startArcPos, result))
+
+ bool isOpen = false;
+
+ if (result == S_FALSE)
+ {
+ if (!mode.CanReturnParser)
+ {
+ if (formatIndex < 0 && ErrorInfo.IsArc_After_NonOpen())
+ {
+ ErrorInfo.ErrorFormatIndex = (int)index;
+ NonOpen_ErrorInfo = ErrorInfo;
+ // if archive was detected, we don't need additional open attempts
+ return S_FALSE;
+ }
+ continue;
+ }
+ if (!ErrorInfo.IsArc_After_NonOpen() || !PhySize_Defined || PhySize == 0)
+ continue;
+ }
+ else
+ {
+ if (PhySize_Defined && PhySize == 0)
+ {
+ PRF(printf(" phySize_Defined && PhySize == 0 "));
+ // we skip that epmty archive case with unusual unexpected (PhySize == 0) from Code function.
+ continue;
+ }
+ isOpen = true;
+ RINOK(result)
+ PRF(printf(" OK "));
+ }
+
+ // fprintf(stderr, "\n %8X %S", startArcPos, Path);
+ // printf("\nOpen OK: %S", ai.Name);
+
+
+ NArchive::NParser::CParseItem pi;
+ pi.Offset = startArcPos;
+
+ if (ai.Flags_UseGlobalOffset())
+ pi.Offset = (UInt64)Offset;
+ else if (Offset != 0)
+ return E_FAIL;
+
+ const UInt64 arcRem = FileSize - pi.Offset;
+ UInt64 phySize = arcRem;
+ const bool phySize_Defined = PhySize_Defined;
+ if (phySize_Defined)
+ {
+ if (pi.Offset + PhySize > FileSize)
+ {
+ // ErrorInfo.ThereIsTail = true;
+ PhySize = FileSize - pi.Offset;
+ }
+ phySize = PhySize;
+ }
+ if (phySize == 0 || (UInt64)phySize > ((UInt64)1 << 63))
+ return E_FAIL;
+
+ /*
+ if (!ai.UseGlobalOffset)
+ {
+ if (phySize > arcRem)
+ {
+ ThereIsTail = true;
+ phySize = arcRem;
+ }
+ }
+ */
+
+ bool needScan = false;
+
+
+ if (isOpen && !phySize_Defined)
+ {
+ // it's for Z format, or bzip2,gz,xz with phySize that was not detected
+ pi.LenIsUnknown = true;
+ needScan = true;
+ phySize = arcRem;
+ nextNeedCheckStartOpen = false;
+ }
+
+ pi.Size = phySize;
+ /*
+ if (OkPhySize_Defined)
+ pi.OkSize = OkPhySize;
+ */
+ pi.NormalizeOffset();
+ // printf(" phySize = %8d", (unsigned)phySize);
+
+ /*
+ if (needSkipFullArc)
+ if (pi.Offset == 0 && phySize_Defined && pi.Size >= fileSize)
+ continue;
+ */
+ if (pi.Offset == 0 && !pi.LenIsUnknown && pi.Size >= FileSize)
+ {
+ // it's possible for dmg archives
+ if (!mode.CanReturnArc)
+ continue;
+ }
+
+ if (mode.EachPos)
+ pos++;
+ else if (needScan)
+ {
+ pos++;
+ /*
+ if (!OkPhySize_Defined)
+ pos++;
+ else
+ pos = pi.Offset + pi.OkSize;
+ */
+ }
+ else
+ pos = pi.Offset + pi.Size;
+
+
+ RINOK(ReadParseItemProps(archive, ai, pi))
+
+ if (pi.Offset < startArcPos && !mode.EachPos /* && phySize_Defined */)
+ {
+ /* It's for DMG format.
+ This code deletes all previous items that are included to current item */
+
+ while (!handlerSpec->_items.IsEmpty())
+ {
+ {
+ const NArchive::NParser::CParseItem &back = handlerSpec->_items.Back();
+ if (back.Offset < pi.Offset)
+ break;
+ if (back.Offset + back.Size > pi.Offset + pi.Size)
+ break;
+ }
+ handlerSpec->_items.DeleteBack();
+ }
+ }
+
+
+ if (isOpen && mode.CanReturnArc && phySize_Defined)
+ {
+ // if (pi.Offset + pi.Size >= fileSize)
+ bool openCur = false;
+
+ bool thereIsTail = ErrorInfo.ThereIsTail;
+ if (thereIsTail && mode.ZerosTailIsAllowed)
+ {
+ RINOK(CheckZerosTail(op, (UInt64)((Int64)arcStreamOffset + Offset + (Int64)PhySize)))
+ if (ErrorInfo.IgnoreTail)
+ thereIsTail = false;
+ }
+
+ if (pi.Offset != 0)
+ {
+ if (!pi.IsNotArcType)
+ {
+ if (thereIsTail)
+ openCur = specFlags.CanReturnMid;
+ else
+ openCur = specFlags.CanReturnTail;
+ }
+ }
+ else
+ {
+ if (!thereIsTail)
+ openCur = true;
+ else
+ openCur = specFlags.CanReturnFrontal;
+
+ if (formatIndex >= -2)
+ openCur = true;
+ }
+
+ if (formatIndex < 0 && pi.IsSelfExe /* && mode.SkipSfxStub */)
+ openCur = false;
+
+ // We open file as SFX, if there is front archive or first archive is "Self Executable"
+ if (!openCur && !pi.IsSelfExe && !thereIsTail &&
+ (!pi.IsNotArcType || pi.Offset == 0))
+ {
+ if (handlerSpec->_items.IsEmpty())
+ {
+ if (specFlags.CanReturnTail)
+ openCur = true;
+ }
+ else if (handlerSpec->_items.Size() == 1)
+ {
+ if (handlerSpec->_items[0].IsSelfExe)
+ {
+ if (mode.SpecUnknownExt.CanReturnTail)
+ openCur = true;
+ }
+ }
+ }
+
+ if (openCur)
+ {
+ InStream = op.stream;
+ Archive = archive;
+ FormatIndex = (int)index;
+ ArcStreamOffset = arcStreamOffset;
+ return S_OK;
+ }
+ }
+
+ /*
+ if (openOnlyFullArc)
+ {
+ ErrorInfo.ClearErrors();
+ return S_FALSE;
+ }
+ */
+
+ pi.FormatIndex = (int)index;
+
+ // printf("\nAdd offset = %d", (int)pi.Offset);
+ handlerSpec->AddItem(pi);
+ wasOpen = true;
+ break;
+ }
+ // ---------- End of Open Loop for Current Pos ----------
+
+ if (!wasOpen)
+ pos++;
+ needCheckStartOpen = (nextNeedCheckStartOpen && wasOpen);
+ }
+ // ---------- End of Main Scan Loop ----------
+
+ /*
+ if (handlerSpec->_items.Size() == 1)
+ {
+ const NArchive::NParser::CParseItem &pi = handlerSpec->_items[0];
+ if (pi.Size == fileSize && pi.Offset == 0)
+ {
+ Archive = archive;
+ FormatIndex2 = pi.FormatIndex;
+ return S_OK;
+ }
+ }
+ */
+
+ if (mode.CanReturnParser)
+ {
+ bool returnParser = (handlerSpec->_items.Size() == 1); // it's possible if fileSize was not correct at start of parsing
+ handlerSpec->AddUnknownItem(fileSize);
+ if (handlerSpec->_items.Size() == 0)
+ return S_FALSE;
+ if (returnParser || handlerSpec->_items.Size() != 1)
+ {
+ // return S_FALSE;
+ handlerSpec->_stream = op.stream;
+ Archive = handler;
+ ErrorInfo.ClearErrors();
+ IsParseArc = true;
+ FormatIndex = -1; // It's parser
+ Offset = 0;
+ return S_OK;
+ }
+ }
+ }
+
+ #endif
+
+ if (!Archive)
+ return S_FALSE;
+ return S_OK;
+}
+
+
+
+
+HRESULT CArc::OpenStream(const COpenOptions &op)
+{
+ RINOK(OpenStream2(op))
+ // PrintNumber("op.formatIndex 3", op.formatIndex);
+
+ if (Archive)
+ {
+ GetRawProps.Release();
+ GetRootProps.Release();
+ Archive->QueryInterface(IID_IArchiveGetRawProps, (void **)&GetRawProps);
+ Archive->QueryInterface(IID_IArchiveGetRootProps, (void **)&GetRootProps);
+
+ RINOK(Archive_GetArcProp_Bool(Archive, kpidIsTree, IsTree))
+ RINOK(Archive_GetArcProp_Bool(Archive, kpidIsDeleted, Ask_Deleted))
+ RINOK(Archive_GetArcProp_Bool(Archive, kpidIsAltStream, Ask_AltStream))
+ RINOK(Archive_GetArcProp_Bool(Archive, kpidIsAux, Ask_Aux))
+ RINOK(Archive_GetArcProp_Bool(Archive, kpidINode, Ask_INode))
+ RINOK(Archive_GetArcProp_Bool(Archive, kpidReadOnly, IsReadOnly))
+
+ const UString fileName = ExtractFileNameFromPath(Path);
+ UString extension;
+ {
+ int dotPos = fileName.ReverseFind_Dot();
+ if (dotPos >= 0)
+ extension = fileName.Ptr((unsigned)(dotPos + 1));
+ }
+
+ DefaultName.Empty();
+ if (FormatIndex >= 0)
+ {
+ const CArcInfoEx &ai = op.codecs->Formats[(unsigned)FormatIndex];
+ if (ai.Exts.Size() == 0)
+ DefaultName = GetDefaultName2(fileName, UString(), UString());
+ else
+ {
+ int subExtIndex = ai.FindExtension(extension);
+ if (subExtIndex < 0)
+ subExtIndex = 0;
+ const CArcExtInfo &extInfo = ai.Exts[(unsigned)subExtIndex];
+ DefaultName = GetDefaultName2(fileName, extInfo.Ext, extInfo.AddExt);
+ }
+ }
+ }
+
+ return S_OK;
+}
+
+#ifdef Z7_SFX
+
+#ifdef _WIN32
+ #define k_ExeExt ".exe"
+ static const unsigned k_ExeExt_Len = 4;
+#else
+ #define k_ExeExt ""
+ static const unsigned k_ExeExt_Len = 0;
+#endif
+
+#endif
+
+HRESULT CArc::OpenStreamOrFile(COpenOptions &op)
+{
+ CMyComPtr<IInStream> fileStream;
+ CMyComPtr<ISequentialInStream> seqStream;
+ CInFileStream *fileStreamSpec = NULL;
+
+ if (op.stdInMode)
+ {
+ seqStream = new CStdInFileStream;
+ op.seqStream = seqStream;
+ }
+ else if (!op.stream)
+ {
+ fileStreamSpec = new CInFileStream;
+ fileStream = fileStreamSpec;
+ Path = filePath;
+ if (!fileStreamSpec->Open(us2fs(Path)))
+ return GetLastError_noZero_HRESULT();
+ op.stream = fileStream;
+ #ifdef Z7_SFX
+ IgnoreSplit = true;
+ #endif
+ }
+
+ /*
+ if (callback)
+ {
+ UInt64 fileSize;
+ RINOK(InStream_GetSize_SeekToEnd(op.stream, fileSize));
+ RINOK(op.callback->SetTotal(NULL, &fileSize))
+ }
+ */
+
+ HRESULT res = OpenStream(op);
+ IgnoreSplit = false;
+
+ #ifdef Z7_SFX
+
+ if (res != S_FALSE
+ || !fileStreamSpec
+ || !op.callbackSpec
+ || NonOpen_ErrorInfo.IsArc_After_NonOpen())
+ return res;
+
+ {
+ if (filePath.Len() > k_ExeExt_Len
+ && StringsAreEqualNoCase_Ascii(filePath.RightPtr(k_ExeExt_Len), k_ExeExt))
+ {
+ const UString path2 = filePath.Left(filePath.Len() - k_ExeExt_Len);
+ FOR_VECTOR (i, op.codecs->Formats)
+ {
+ const CArcInfoEx &ai = op.codecs->Formats[i];
+ if (ai.Is_Split())
+ continue;
+ UString path3 = path2;
+ path3.Add_Dot();
+ path3 += ai.GetMainExt(); // "7z" for SFX.
+ Path = path3;
+ Path += ".001";
+ bool isOk = op.callbackSpec->SetSecondFileInfo(us2fs(Path));
+ if (!isOk)
+ {
+ Path = path3;
+ isOk = op.callbackSpec->SetSecondFileInfo(us2fs(Path));
+ }
+ if (isOk)
+ {
+ if (fileStreamSpec->Open(us2fs(Path)))
+ {
+ op.stream = fileStream;
+ NonOpen_ErrorInfo.ClearErrors_Full();
+ if (OpenStream(op) == S_OK)
+ return S_OK;
+ }
+ }
+ }
+ }
+ }
+
+ #endif
+
+ return res;
+}
+
+void CArchiveLink::KeepModeForNextOpen()
+{
+ for (unsigned i = Arcs.Size(); i != 0;)
+ {
+ i--;
+ CMyComPtr<IArchiveKeepModeForNextOpen> keep;
+ Arcs[i].Archive->QueryInterface(IID_IArchiveKeepModeForNextOpen, (void **)&keep);
+ if (keep)
+ keep->KeepModeForNextOpen();
+ }
+}
+
+HRESULT CArchiveLink::Close()
+{
+ for (unsigned i = Arcs.Size(); i != 0;)
+ {
+ i--;
+ RINOK(Arcs[i].Close())
+ }
+ IsOpen = false;
+ // ErrorsText.Empty();
+ return S_OK;
+}
+
+void CArchiveLink::Release()
+{
+ // NonOpenErrorFormatIndex = -1;
+ NonOpen_ErrorInfo.ClearErrors();
+ NonOpen_ArcPath.Empty();
+ while (!Arcs.IsEmpty())
+ Arcs.DeleteBack();
+}
+
+/*
+void CArchiveLink::Set_ErrorsText()
+{
+ FOR_VECTOR(i, Arcs)
+ {
+ const CArc &arc = Arcs[i];
+ if (!arc.ErrorFlagsText.IsEmpty())
+ {
+ if (!ErrorsText.IsEmpty())
+ ErrorsText.Add_LF();
+ ErrorsText += GetUnicodeString(arc.ErrorFlagsText);
+ }
+ if (!arc.ErrorMessage.IsEmpty())
+ {
+ if (!ErrorsText.IsEmpty())
+ ErrorsText.Add_LF();
+ ErrorsText += arc.ErrorMessage;
+ }
+
+ if (!arc.WarningMessage.IsEmpty())
+ {
+ if (!ErrorsText.IsEmpty())
+ ErrorsText.Add_LF();
+ ErrorsText += arc.WarningMessage;
+ }
+ }
+}
+*/
+
+HRESULT CArchiveLink::Open(COpenOptions &op)
+{
+ Release();
+ if (op.types->Size() >= 32)
+ return E_NOTIMPL;
+
+ HRESULT resSpec;
+
+ for (;;)
+ {
+ resSpec = S_OK;
+
+ op.openType = COpenType();
+ if (op.types->Size() >= 1)
+ {
+ COpenType latest;
+ if (Arcs.Size() < op.types->Size())
+ latest = (*op.types)[op.types->Size() - Arcs.Size() - 1];
+ else
+ {
+ latest = (*op.types)[0];
+ if (!latest.Recursive)
+ break;
+ }
+ op.openType = latest;
+ }
+ else if (Arcs.Size() >= 32)
+ break;
+
+ /*
+ op.formatIndex = -1;
+ if (op.types->Size() >= 1)
+ {
+ int latest;
+ if (Arcs.Size() < op.types->Size())
+ latest = (*op.types)[op.types->Size() - Arcs.Size() - 1];
+ else
+ {
+ latest = (*op.types)[0];
+ if (latest != -2 && latest != -3)
+ break;
+ }
+ if (latest >= 0)
+ op.formatIndex = latest;
+ else if (latest == -1 || latest == -2)
+ {
+ // default
+ }
+ else if (latest == -3)
+ op.formatIndex = -2;
+ else
+ op.formatIndex = latest + 2;
+ }
+ else if (Arcs.Size() >= 32)
+ break;
+ */
+
+ if (Arcs.IsEmpty())
+ {
+ CArc arc;
+ arc.filePath = op.filePath;
+ arc.Path = op.filePath;
+ arc.SubfileIndex = (UInt32)(Int32)-1;
+ HRESULT result = arc.OpenStreamOrFile(op);
+ if (result != S_OK)
+ {
+ if (result == S_FALSE)
+ {
+ NonOpen_ErrorInfo = arc.NonOpen_ErrorInfo;
+ // NonOpenErrorFormatIndex = arc.ErrorFormatIndex;
+ NonOpen_ArcPath = arc.Path;
+ }
+ return result;
+ }
+ Arcs.Add(arc);
+ continue;
+ }
+
+ // PrintNumber("op.formatIndex 11", op.formatIndex);
+
+ const CArc &arc = Arcs.Back();
+
+ if (op.types->Size() > Arcs.Size())
+ resSpec = E_NOTIMPL;
+
+ UInt32 mainSubfile;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(arc.Archive->GetArchiveProperty(kpidMainSubfile, &prop))
+ if (prop.vt == VT_UI4)
+ mainSubfile = prop.ulVal;
+ else
+ break;
+ UInt32 numItems;
+ RINOK(arc.Archive->GetNumberOfItems(&numItems))
+ if (mainSubfile >= numItems)
+ break;
+ }
+
+
+ CMyComPtr<IInArchiveGetStream> getStream;
+ if (arc.Archive->QueryInterface(IID_IInArchiveGetStream, (void **)&getStream) != S_OK || !getStream)
+ break;
+
+ CMyComPtr<ISequentialInStream> subSeqStream;
+ if (getStream->GetStream(mainSubfile, &subSeqStream) != S_OK || !subSeqStream)
+ break;
+
+ CMyComPtr<IInStream> subStream;
+ if (subSeqStream.QueryInterface(IID_IInStream, &subStream) != S_OK || !subStream)
+ break;
+
+ CArc arc2;
+ RINOK(arc.GetItem_Path(mainSubfile, arc2.Path))
+
+ bool zerosTailIsAllowed;
+ RINOK(Archive_GetItemBoolProp(arc.Archive, mainSubfile, kpidZerosTailIsAllowed, zerosTailIsAllowed))
+
+
+ if (op.callback)
+ {
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IArchiveOpenSetSubArchiveName,
+ setSubArchiveName, op.callback)
+ if (setSubArchiveName)
+ setSubArchiveName->SetSubArchiveName(arc2.Path);
+ }
+
+ arc2.SubfileIndex = mainSubfile;
+
+ // CIntVector incl;
+ CIntVector excl;
+
+ COpenOptions op2;
+ #ifndef Z7_SFX
+ op2.props = op.props;
+ #endif
+ op2.codecs = op.codecs;
+ // op2.types = &incl;
+ op2.openType = op.openType;
+ op2.openType.ZerosTailIsAllowed = zerosTailIsAllowed;
+ op2.excludedFormats = &excl;
+ op2.stdInMode = false;
+ op2.stream = subStream;
+ op2.filePath = arc2.Path;
+ op2.callback = op.callback;
+ op2.callbackSpec = op.callbackSpec;
+
+
+ HRESULT result = arc2.OpenStream(op2);
+ resSpec = (op.types->Size() == 0 ? S_OK : S_FALSE);
+ if (result == S_FALSE)
+ {
+ NonOpen_ErrorInfo = arc2.ErrorInfo;
+ NonOpen_ArcPath = arc2.Path;
+ break;
+ }
+ RINOK(result)
+ RINOK(arc.GetItem_MTime(mainSubfile, arc2.MTime))
+ Arcs.Add(arc2);
+ }
+ IsOpen = !Arcs.IsEmpty();
+ return resSpec;
+}
+
+HRESULT CArchiveLink::Open2(COpenOptions &op, IOpenCallbackUI *callbackUI)
+{
+ VolumesSize = 0;
+ COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
+ CMyComPtr<IArchiveOpenCallback> callback = openCallbackSpec;
+ openCallbackSpec->Callback = callbackUI;
+
+ FString prefix, name;
+
+ if (!op.stream && !op.stdInMode)
+ {
+ NFile::NDir::GetFullPathAndSplit(us2fs(op.filePath), prefix, name);
+ RINOK(openCallbackSpec->Init2(prefix, name))
+ }
+ else
+ {
+ openCallbackSpec->SetSubArchiveName(op.filePath);
+ }
+
+ op.callback = callback;
+ op.callbackSpec = openCallbackSpec;
+
+ HRESULT res = Open(op);
+
+ PasswordWasAsked = openCallbackSpec->PasswordWasAsked;
+ // Password = openCallbackSpec->Password;
+
+ RINOK(res)
+ // VolumePaths.Add(fs2us(prefix + name));
+
+ FOR_VECTOR (i, openCallbackSpec->FileNames_WasUsed)
+ {
+ if (openCallbackSpec->FileNames_WasUsed[i])
+ {
+ VolumePaths.Add(fs2us(prefix) + openCallbackSpec->FileNames[i]);
+ VolumesSize += openCallbackSpec->FileSizes[i];
+ }
+ }
+ // VolumesSize = openCallbackSpec->TotalSize;
+ return S_OK;
+}
+
+HRESULT CArc::ReOpen(const COpenOptions &op, IArchiveOpenCallback *openCallback_Additional)
+{
+ ErrorInfo.ClearErrors();
+ ErrorInfo.ErrorFormatIndex = -1;
+
+ UInt64 fileSize = 0;
+ if (op.stream)
+ {
+ RINOK(InStream_SeekToBegin(op.stream))
+ RINOK(InStream_AtBegin_GetSize(op.stream, fileSize))
+ // RINOK(InStream_GetSize_SeekToBegin(op.stream, fileSize))
+ }
+ FileSize = fileSize;
+
+ CMyComPtr<IInStream> stream2;
+ Int64 globalOffset = GetGlobalOffset();
+ if (globalOffset <= 0)
+ stream2 = op.stream;
+ else
+ {
+ CTailInStream *tailStreamSpec = new CTailInStream;
+ stream2 = tailStreamSpec;
+ tailStreamSpec->Stream = op.stream;
+ tailStreamSpec->Offset = (UInt64)globalOffset;
+ tailStreamSpec->Init();
+ RINOK(tailStreamSpec->SeekToStart())
+ }
+
+ // There are archives with embedded STUBs (like ZIP), so we must support signature scanning
+ // But for another archives we can use 0 here. So the code can be fixed !!!
+ UInt64 maxStartPosition = kMaxCheckStartPosition;
+ IArchiveOpenCallback *openCallback = openCallback_Additional;
+ if (!openCallback)
+ openCallback = op.callback;
+ HRESULT res = Archive->Open(stream2, &maxStartPosition, openCallback);
+
+ if (res == S_OK)
+ {
+ RINOK(ReadBasicProps(Archive, (UInt64)globalOffset, res))
+ ArcStreamOffset = (UInt64)globalOffset;
+ if (ArcStreamOffset != 0)
+ InStream = op.stream;
+ }
+ return res;
+}
+
+HRESULT CArchiveLink::Open3(COpenOptions &op, IOpenCallbackUI *callbackUI)
+{
+ HRESULT res = Open2(op, callbackUI);
+ if (callbackUI)
+ {
+ RINOK(callbackUI->Open_Finished())
+ }
+ return res;
+}
+
+HRESULT CArchiveLink::ReOpen(COpenOptions &op)
+{
+ if (Arcs.Size() > 1)
+ return E_NOTIMPL;
+
+ CObjectVector<COpenType> inc;
+ CIntVector excl;
+
+ op.types = &inc;
+ op.excludedFormats = &excl;
+ op.stdInMode = false;
+ op.stream = NULL;
+ if (Arcs.Size() == 0) // ???
+ return Open2(op, NULL);
+
+ /* if archive is multivolume (unsupported here still)
+ COpenCallbackImp object will exist after Open stage. */
+ COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
+ CMyComPtr<IArchiveOpenCallback> openCallbackNew = openCallbackSpec;
+
+ openCallbackSpec->Callback = NULL;
+ openCallbackSpec->ReOpenCallback = op.callback;
+ {
+ FString dirPrefix, fileName;
+ NFile::NDir::GetFullPathAndSplit(us2fs(op.filePath), dirPrefix, fileName);
+ RINOK(openCallbackSpec->Init2(dirPrefix, fileName))
+ }
+
+
+ CInFileStream *fileStreamSpec = new CInFileStream;
+ CMyComPtr<IInStream> stream(fileStreamSpec);
+ if (!fileStreamSpec->Open(us2fs(op.filePath)))
+ return GetLastError_noZero_HRESULT();
+ op.stream = stream;
+
+ CArc &arc = Arcs[0];
+ const HRESULT res = arc.ReOpen(op, openCallbackNew);
+
+ openCallbackSpec->ReOpenCallback = NULL;
+
+ PasswordWasAsked = openCallbackSpec->PasswordWasAsked;
+ // Password = openCallbackSpec->Password;
+
+ IsOpen = (res == S_OK);
+ return res;
+}
+
+#ifndef Z7_SFX
+
+bool ParseComplexSize(const wchar_t *s, UInt64 &result);
+bool ParseComplexSize(const wchar_t *s, UInt64 &result)
+{
+ result = 0;
+ const wchar_t *end;
+ UInt64 number = ConvertStringToUInt64(s, &end);
+ if (end == s)
+ return false;
+ if (*end == 0)
+ {
+ result = number;
+ return true;
+ }
+ if (end[1] != 0)
+ return false;
+ unsigned numBits;
+ switch (MyCharLower_Ascii(*end))
+ {
+ case 'b': result = number; return true;
+ case 'k': numBits = 10; break;
+ case 'm': numBits = 20; break;
+ case 'g': numBits = 30; break;
+ case 't': numBits = 40; break;
+ default: return false;
+ }
+ if (number >= ((UInt64)1 << (64 - numBits)))
+ return false;
+ result = number << numBits;
+ return true;
+}
+
+static bool ParseTypeParams(const UString &s, COpenType &type)
+{
+ if (s[0] == 0)
+ return true;
+ if (s[1] == 0)
+ {
+ switch ((unsigned)(Byte)s[0])
+ {
+ case 'e': type.EachPos = true; return true;
+ case 'a': type.CanReturnArc = true; return true;
+ case 'r': type.Recursive = true; return true;
+ }
+ return false;
+ }
+ if (s[0] == 's')
+ {
+ UInt64 result;
+ if (!ParseComplexSize(s.Ptr(1), result))
+ return false;
+ type.MaxStartOffset = result;
+ type.MaxStartOffset_Defined = true;
+ return true;
+ }
+
+ return false;
+}
+
+static bool ParseType(CCodecs &codecs, const UString &s, COpenType &type)
+{
+ int pos2 = s.Find(L':');
+
+ {
+ UString name;
+ if (pos2 < 0)
+ {
+ name = s;
+ pos2 = (int)s.Len();
+ }
+ else
+ {
+ name = s.Left((unsigned)pos2);
+ pos2++;
+ }
+
+ int index = codecs.FindFormatForArchiveType(name);
+ type.Recursive = false;
+
+ if (index < 0)
+ {
+ if (name[0] == '*')
+ {
+ if (name[1] != 0)
+ return false;
+ }
+ else if (name[0] == '#')
+ {
+ if (name[1] != 0)
+ return false;
+ type.CanReturnArc = false;
+ type.CanReturnParser = true;
+ }
+ else if (name.IsEqualTo_Ascii_NoCase("hash"))
+ {
+ // type.CanReturnArc = false;
+ // type.CanReturnParser = false;
+ type.IsHashType = true;
+ }
+ else
+ return false;
+ }
+
+ type.FormatIndex = index;
+
+ }
+
+ for (unsigned i = (unsigned)pos2; i < s.Len();)
+ {
+ int next = s.Find(L':', i);
+ if (next < 0)
+ next = (int)s.Len();
+ const UString name = s.Mid(i, (unsigned)next - i);
+ if (name.IsEmpty())
+ return false;
+ if (!ParseTypeParams(name, type))
+ return false;
+ i = (unsigned)next + 1;
+ }
+
+ return true;
+}
+
+bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector<COpenType> &types)
+{
+ types.Clear();
+ bool isHashType = false;
+ for (unsigned pos = 0; pos < s.Len();)
+ {
+ int pos2 = s.Find(L'.', pos);
+ if (pos2 < 0)
+ pos2 = (int)s.Len();
+ UString name = s.Mid(pos, (unsigned)pos2 - pos);
+ if (name.IsEmpty())
+ return false;
+ COpenType type;
+ if (!ParseType(codecs, name, type))
+ return false;
+ if (isHashType)
+ return false;
+ if (type.IsHashType)
+ isHashType = true;
+ types.Add(type);
+ pos = (unsigned)pos2 + 1;
+ }
+ return true;
+}
+
+/*
+bool IsHashType(const CObjectVector<COpenType> &types)
+{
+ if (types.Size() != 1)
+ return false;
+ return types[0].IsHashType;
+}
+*/
+
+
+#endif
diff --git a/CPP/7zip/UI/Common/OpenArchive.h b/CPP/7zip/UI/Common/OpenArchive.h
index 033cb96..5c3bfe5 100644
--- a/CPP/7zip/UI/Common/OpenArchive.h
+++ b/CPP/7zip/UI/Common/OpenArchive.h
@@ -1,436 +1,469 @@
-// OpenArchive.h
-
-#ifndef __OPEN_ARCHIVE_H
-#define __OPEN_ARCHIVE_H
-
-#include "../../../Windows/PropVariant.h"
-
-#include "ArchiveOpenCallback.h"
-#include "LoadCodecs.h"
-#include "Property.h"
-
-#ifndef _SFX
-
-#define SUPPORT_ALT_STREAMS
-
-#endif
-
-HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw();
-HRESULT Archive_IsItem_Dir(IInArchive *arc, UInt32 index, bool &result) throw();
-HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw();
-HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw();
-HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &deleted) throw();
-
-#ifdef SUPPORT_ALT_STREAMS
-int FindAltStreamColon_in_Path(const wchar_t *path);
-#endif
-
-/*
-struct COptionalOpenProperties
-{
- UString FormatName;
- CObjectVector<CProperty> Props;
-};
-*/
-
-#ifdef _SFX
-#define OPEN_PROPS_DECL
-#else
-#define OPEN_PROPS_DECL const CObjectVector<CProperty> *props;
-// #define OPEN_PROPS_DECL , const CObjectVector<COptionalOpenProperties> *props
-#endif
-
-struct COpenSpecFlags
-{
- // bool CanReturnFull;
- bool CanReturnFrontal;
- bool CanReturnTail;
- bool CanReturnMid;
-
- bool CanReturn_NonStart() const { return CanReturnTail || CanReturnMid; }
-
- COpenSpecFlags():
- // CanReturnFull(true),
- CanReturnFrontal(false),
- CanReturnTail(false),
- CanReturnMid(false)
- {}
-};
-
-struct COpenType
-{
- int FormatIndex;
-
- COpenSpecFlags SpecForcedType;
- COpenSpecFlags SpecMainType;
- COpenSpecFlags SpecWrongExt;
- COpenSpecFlags SpecUnknownExt;
-
- bool Recursive;
-
- bool CanReturnArc;
- bool CanReturnParser;
- bool EachPos;
-
- // bool SkipSfxStub;
- // bool ExeAsUnknown;
-
- bool ZerosTailIsAllowed;
-
- bool MaxStartOffset_Defined;
- UInt64 MaxStartOffset;
-
- const COpenSpecFlags &GetSpec(bool isForced, bool isMain, bool isUnknown) const
- {
- return isForced ? SpecForcedType : (isMain ? SpecMainType : (isUnknown ? SpecUnknownExt : SpecWrongExt));
- }
-
- COpenType():
- FormatIndex(-1),
- Recursive(true),
- EachPos(false),
- CanReturnArc(true),
- CanReturnParser(false),
- // SkipSfxStub(true),
- // ExeAsUnknown(true),
- ZerosTailIsAllowed(false),
- MaxStartOffset_Defined(false),
- MaxStartOffset(0)
- {
- SpecForcedType.CanReturnFrontal = true;
- SpecForcedType.CanReturnTail = true;
- SpecForcedType.CanReturnMid = true;
-
- SpecMainType.CanReturnFrontal = true;
-
- SpecUnknownExt.CanReturnTail = true; // for sfx
- SpecUnknownExt.CanReturnMid = true;
- SpecUnknownExt.CanReturnFrontal = true; // for alt streams of sfx with pad
-
- // ZerosTailIsAllowed = true;
- }
-};
-
-struct COpenOptions
-{
- CCodecs *codecs;
- COpenType openType;
- const CObjectVector<COpenType> *types;
- const CIntVector *excludedFormats;
-
- IInStream *stream;
- ISequentialInStream *seqStream;
- IArchiveOpenCallback *callback;
- COpenCallbackImp *callbackSpec;
- OPEN_PROPS_DECL
- // bool openOnlySpecifiedByExtension,
-
- bool stdInMode;
- UString filePath;
-
- COpenOptions():
- codecs(NULL),
- types(NULL),
- excludedFormats(NULL),
- stream(NULL),
- seqStream(NULL),
- callback(NULL),
- callbackSpec(NULL),
- stdInMode(false)
- {}
-
-};
-
-UInt32 GetOpenArcErrorFlags(const NWindows::NCOM::CPropVariant &prop, bool *isDefinedProp = NULL);
-
-struct CArcErrorInfo
-{
- bool ThereIsTail;
- bool UnexpecedEnd;
- bool IgnoreTail; // all are zeros
- // bool NonZerosTail;
- bool ErrorFlags_Defined;
- UInt32 ErrorFlags;
- UInt32 WarningFlags;
- int ErrorFormatIndex; // - 1 means no Error.
- // if FormatIndex == ErrorFormatIndex, the archive is open with offset
- UInt64 TailSize;
-
- /* if CArc is Open OK with some format:
- - ErrorFormatIndex shows error format index, if extension is incorrect
- - other variables show message and warnings of archive that is open */
-
- UString ErrorMessage;
- UString WarningMessage;
-
- // call IsArc_After_NonOpen only if Open returns S_FALSE
- bool IsArc_After_NonOpen() const
- {
- return (ErrorFlags_Defined && (ErrorFlags & kpv_ErrorFlags_IsNotArc) == 0);
- }
-
-
- CArcErrorInfo():
- ThereIsTail(false),
- UnexpecedEnd(false),
- IgnoreTail(false),
- // NonZerosTail(false),
- ErrorFlags_Defined(false),
- ErrorFlags(0),
- WarningFlags(0),
- ErrorFormatIndex(-1),
- TailSize(0)
- {}
-
- void ClearErrors();
-
- void ClearErrors_Full()
- {
- ErrorFormatIndex = -1;
- ClearErrors();
- }
-
- bool IsThereErrorOrWarning() const
- {
- return ErrorFlags != 0
- || WarningFlags != 0
- || NeedTailWarning()
- || UnexpecedEnd
- || !ErrorMessage.IsEmpty()
- || !WarningMessage.IsEmpty();
- }
-
- bool AreThereErrors() const { return ErrorFlags != 0 || UnexpecedEnd; }
- bool AreThereWarnings() const { return WarningFlags != 0 || NeedTailWarning(); }
-
- bool NeedTailWarning() const { return !IgnoreTail && ThereIsTail; }
-
- UInt32 GetWarningFlags() const
- {
- UInt32 a = WarningFlags;
- if (NeedTailWarning() && (ErrorFlags & kpv_ErrorFlags_DataAfterEnd) == 0)
- a |= kpv_ErrorFlags_DataAfterEnd;
- return a;
- }
-
- UInt32 GetErrorFlags() const
- {
- UInt32 a = ErrorFlags;
- if (UnexpecedEnd)
- a |= kpv_ErrorFlags_UnexpectedEnd;
- return a;
- }
-};
-
-struct CReadArcItem
-{
- UString Path; // Path from root (including alt stream name, if alt stream)
- UStringVector PathParts; // without altStream name, path from root or from _baseParentFolder, if _use_baseParentFolder_mode
-
- #ifdef SUPPORT_ALT_STREAMS
- UString MainPath;
- /* MainPath = Path for non-AltStream,
- MainPath = Path of parent, if there is parent for AltStream. */
- UString AltStreamName;
- bool IsAltStream;
- bool WriteToAltStreamIfColon;
- #endif
-
- bool IsDir;
- bool MainIsDir;
- UInt32 ParentIndex; // use it, if IsAltStream
-
- #ifndef _SFX
- bool _use_baseParentFolder_mode;
- int _baseParentFolder;
- #endif
-
- CReadArcItem()
- {
- #ifdef SUPPORT_ALT_STREAMS
- WriteToAltStreamIfColon = false;
- #endif
-
- #ifndef _SFX
- _use_baseParentFolder_mode = false;
- _baseParentFolder = -1;
- #endif
- }
-};
-
-class CArc
-{
- HRESULT PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr<IInArchive> &archive);
- HRESULT CheckZerosTail(const COpenOptions &op, UInt64 offset);
- HRESULT OpenStream2(const COpenOptions &options);
-
- #ifndef _SFX
- // parts.Back() can contain alt stream name "nams:AltName"
- HRESULT GetItemPathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const;
- #endif
-
-public:
- CMyComPtr<IInArchive> Archive;
- CMyComPtr<IInStream> InStream;
- // we use InStream in 2 cases (ArcStreamOffset != 0):
- // 1) if we use additional cache stream
- // 2) we reopen sfx archive with CTailInStream
-
- CMyComPtr<IArchiveGetRawProps> GetRawProps;
- CMyComPtr<IArchiveGetRootProps> GetRootProps;
-
- CArcErrorInfo ErrorInfo; // for OK archives
- CArcErrorInfo NonOpen_ErrorInfo; // ErrorInfo for mainArchive (false OPEN)
-
- UString Path;
- UString filePath;
- UString DefaultName;
- int FormatIndex; // - 1 means Parser.
- int SubfileIndex;
- FILETIME MTime;
- bool MTimeDefined;
-
- Int64 Offset; // it's offset of start of archive inside stream that is open by Archive Handler
- UInt64 PhySize;
- // UInt64 OkPhySize;
- bool PhySizeDefined;
- // bool OkPhySize_Defined;
- UInt64 FileSize;
- UInt64 AvailPhySize; // PhySize, but it's reduced if exceed end of file
- // bool offsetDefined;
-
- UInt64 GetEstmatedPhySize() const { return PhySizeDefined ? PhySize : FileSize; }
-
- UInt64 ArcStreamOffset; // offset of stream that is open by Archive Handler
- Int64 GetGlobalOffset() const { return ArcStreamOffset + Offset; } // it's global offset of archive
-
- // AString ErrorFlagsText;
-
- bool IsParseArc;
-
- bool IsTree;
- bool IsReadOnly;
-
- bool Ask_Deleted;
- bool Ask_AltStream;
- bool Ask_Aux;
- bool Ask_INode;
-
- bool IgnoreSplit; // don't try split handler
-
- // void Set_ErrorFlagsText();
-
- CArc():
- MTimeDefined(false),
- IsTree(false),
- IsReadOnly(false),
- Ask_Deleted(false),
- Ask_AltStream(false),
- Ask_Aux(false),
- Ask_INode(false),
- IgnoreSplit(false)
- {}
-
- HRESULT ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes);
-
- // ~CArc();
-
- HRESULT Close()
- {
- InStream.Release();
- return Archive->Close();
- }
-
- HRESULT GetItemPath(UInt32 index, UString &result) const;
- HRESULT GetDefaultItemPath(UInt32 index, UString &result) const;
-
- // GetItemPath2 adds [DELETED] dir prefix for deleted items.
- HRESULT GetItemPath2(UInt32 index, UString &result) const;
-
- HRESULT GetItem(UInt32 index, CReadArcItem &item) const;
-
- HRESULT GetItemSize(UInt32 index, UInt64 &size, bool &defined) const;
- HRESULT GetItemMTime(UInt32 index, FILETIME &ft, bool &defined) const;
- HRESULT IsItemAnti(UInt32 index, bool &result) const
- { return Archive_GetItemBoolProp(Archive, index, kpidIsAnti, result); }
-
-
- HRESULT OpenStream(const COpenOptions &options);
- HRESULT OpenStreamOrFile(COpenOptions &options);
-
- HRESULT ReOpen(const COpenOptions &options);
-
- HRESULT CreateNewTailStream(CMyComPtr<IInStream> &stream);
-};
-
-struct CArchiveLink
-{
- CObjectVector<CArc> Arcs;
- UStringVector VolumePaths;
- UInt64 VolumesSize;
- bool IsOpen;
-
- bool PasswordWasAsked;
- // UString Password;
-
- // int NonOpenErrorFormatIndex; // - 1 means no Error.
- UString NonOpen_ArcPath;
-
- CArcErrorInfo NonOpen_ErrorInfo;
-
- // UString ErrorsText;
- // void Set_ErrorsText();
-
- CArchiveLink():
- VolumesSize(0),
- IsOpen(false),
- PasswordWasAsked(false)
- {}
-
- void KeepModeForNextOpen();
- HRESULT Close();
- void Release();
- ~CArchiveLink() { Release(); }
-
- const CArc *GetArc() const { return &Arcs.Back(); }
- IInArchive *GetArchive() const { return Arcs.Back().Archive; }
- IArchiveGetRawProps *GetArchiveGetRawProps() const { return Arcs.Back().GetRawProps; }
- IArchiveGetRootProps *GetArchiveGetRootProps() const { return Arcs.Back().GetRootProps; }
-
- HRESULT Open(COpenOptions &options);
- HRESULT Open2(COpenOptions &options, IOpenCallbackUI *callbackUI);
- HRESULT Open3(COpenOptions &options, IOpenCallbackUI *callbackUI);
-
- HRESULT Open_Strict(COpenOptions &options, IOpenCallbackUI *callbackUI)
- {
- HRESULT result = Open3(options, callbackUI);
- if (result == S_OK && NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
- result = S_FALSE;
- return result;
- }
-
- HRESULT ReOpen(COpenOptions &options);
-};
-
-bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector<COpenType> &types);
-
-
-struct CDirPathSortPair
-{
- unsigned Len;
- unsigned Index;
-
- void SetNumSlashes(const FChar *s);
-
- int Compare(const CDirPathSortPair &a) const
- {
- // We need sorting order where parent items will be after child items
- if (Len < a.Len) return 1;
- if (Len > a.Len) return -1;
- if (Index < a.Index) return -1;
- if (Index > a.Index) return 1;
- return 0;
- }
-};
-
-#endif
+// OpenArchive.h
+
+#ifndef ZIP7_INC_OPEN_ARCHIVE_H
+#define ZIP7_INC_OPEN_ARCHIVE_H
+
+#include "../../../Windows/PropVariant.h"
+
+#include "ArchiveOpenCallback.h"
+#include "LoadCodecs.h"
+#include "Property.h"
+#include "DirItem.h"
+
+#ifndef Z7_SFX
+
+#define SUPPORT_ALT_STREAMS
+
+#endif
+
+HRESULT Archive_GetItemBoolProp(IInArchive *arc, UInt32 index, PROPID propID, bool &result) throw();
+HRESULT Archive_IsItem_Dir(IInArchive *arc, UInt32 index, bool &result) throw();
+HRESULT Archive_IsItem_Aux(IInArchive *arc, UInt32 index, bool &result) throw();
+HRESULT Archive_IsItem_AltStream(IInArchive *arc, UInt32 index, bool &result) throw();
+HRESULT Archive_IsItem_Deleted(IInArchive *arc, UInt32 index, bool &deleted) throw();
+
+#ifdef SUPPORT_ALT_STREAMS
+int FindAltStreamColon_in_Path(const wchar_t *path);
+#endif
+
+/*
+struct COptionalOpenProperties
+{
+ UString FormatName;
+ CObjectVector<CProperty> Props;
+};
+*/
+
+#ifdef Z7_SFX
+#define OPEN_PROPS_DECL
+#else
+#define OPEN_PROPS_DECL const CObjectVector<CProperty> *props;
+// #define OPEN_PROPS_DECL , const CObjectVector<COptionalOpenProperties> *props
+#endif
+
+struct COpenSpecFlags
+{
+ // bool CanReturnFull;
+ bool CanReturnFrontal;
+ bool CanReturnTail;
+ bool CanReturnMid;
+
+ bool CanReturn_NonStart() const { return CanReturnTail || CanReturnMid; }
+
+ COpenSpecFlags():
+ // CanReturnFull(true),
+ CanReturnFrontal(false),
+ CanReturnTail(false),
+ CanReturnMid(false)
+ {}
+};
+
+struct COpenType
+{
+ int FormatIndex;
+
+ COpenSpecFlags SpecForcedType;
+ COpenSpecFlags SpecMainType;
+ COpenSpecFlags SpecWrongExt;
+ COpenSpecFlags SpecUnknownExt;
+
+ bool Recursive;
+
+ bool CanReturnArc;
+ bool CanReturnParser;
+ bool IsHashType;
+ bool EachPos;
+
+ // bool SkipSfxStub;
+ // bool ExeAsUnknown;
+
+ bool ZerosTailIsAllowed;
+
+ bool MaxStartOffset_Defined;
+ UInt64 MaxStartOffset;
+
+ const COpenSpecFlags &GetSpec(bool isForced, bool isMain, bool isUnknown) const
+ {
+ return isForced ? SpecForcedType : (isMain ? SpecMainType : (isUnknown ? SpecUnknownExt : SpecWrongExt));
+ }
+
+ COpenType():
+ FormatIndex(-1),
+ Recursive(true),
+ CanReturnArc(true),
+ CanReturnParser(false),
+ IsHashType(false),
+ EachPos(false),
+ // SkipSfxStub(true),
+ // ExeAsUnknown(true),
+ ZerosTailIsAllowed(false),
+ MaxStartOffset_Defined(false),
+ MaxStartOffset(0)
+ {
+ SpecForcedType.CanReturnFrontal = true;
+ SpecForcedType.CanReturnTail = true;
+ SpecForcedType.CanReturnMid = true;
+
+ SpecMainType.CanReturnFrontal = true;
+
+ SpecUnknownExt.CanReturnTail = true; // for sfx
+ SpecUnknownExt.CanReturnMid = true;
+ SpecUnknownExt.CanReturnFrontal = true; // for alt streams of sfx with pad
+
+ // ZerosTailIsAllowed = true;
+ }
+};
+
+struct COpenOptions
+{
+ CCodecs *codecs;
+ COpenType openType;
+ const CObjectVector<COpenType> *types;
+ const CIntVector *excludedFormats;
+
+ IInStream *stream;
+ ISequentialInStream *seqStream;
+ IArchiveOpenCallback *callback;
+ COpenCallbackImp *callbackSpec; // it's used for SFX only
+ OPEN_PROPS_DECL
+ // bool openOnlySpecifiedByExtension,
+
+ bool stdInMode;
+ UString filePath;
+
+ COpenOptions():
+ codecs(NULL),
+ types(NULL),
+ excludedFormats(NULL),
+ stream(NULL),
+ seqStream(NULL),
+ callback(NULL),
+ callbackSpec(NULL),
+ stdInMode(false)
+ {}
+
+};
+
+UInt32 GetOpenArcErrorFlags(const NWindows::NCOM::CPropVariant &prop, bool *isDefinedProp = NULL);
+
+struct CArcErrorInfo
+{
+ bool ThereIsTail;
+ bool UnexpecedEnd;
+ bool IgnoreTail; // all are zeros
+ // bool NonZerosTail;
+ bool ErrorFlags_Defined;
+ UInt32 ErrorFlags;
+ UInt32 WarningFlags;
+ int ErrorFormatIndex; // - 1 means no Error.
+ // if FormatIndex == ErrorFormatIndex, the archive is open with offset
+ UInt64 TailSize;
+
+ /* if CArc is Open OK with some format:
+ - ErrorFormatIndex shows error format index, if extension is incorrect
+ - other variables show message and warnings of archive that is open */
+
+ UString ErrorMessage;
+ UString WarningMessage;
+
+ // call IsArc_After_NonOpen only if Open returns S_FALSE
+ bool IsArc_After_NonOpen() const
+ {
+ return (ErrorFlags_Defined && (ErrorFlags & kpv_ErrorFlags_IsNotArc) == 0);
+ }
+
+
+ CArcErrorInfo():
+ ThereIsTail(false),
+ UnexpecedEnd(false),
+ IgnoreTail(false),
+ // NonZerosTail(false),
+ ErrorFlags_Defined(false),
+ ErrorFlags(0),
+ WarningFlags(0),
+ ErrorFormatIndex(-1),
+ TailSize(0)
+ {}
+
+ void ClearErrors();
+
+ void ClearErrors_Full()
+ {
+ ErrorFormatIndex = -1;
+ ClearErrors();
+ }
+
+ bool IsThereErrorOrWarning() const
+ {
+ return ErrorFlags != 0
+ || WarningFlags != 0
+ || NeedTailWarning()
+ || UnexpecedEnd
+ || !ErrorMessage.IsEmpty()
+ || !WarningMessage.IsEmpty();
+ }
+
+ bool AreThereErrors() const { return ErrorFlags != 0 || UnexpecedEnd; }
+ bool AreThereWarnings() const { return WarningFlags != 0 || NeedTailWarning(); }
+
+ bool NeedTailWarning() const { return !IgnoreTail && ThereIsTail; }
+
+ UInt32 GetWarningFlags() const
+ {
+ UInt32 a = WarningFlags;
+ if (NeedTailWarning() && (ErrorFlags & kpv_ErrorFlags_DataAfterEnd) == 0)
+ a |= kpv_ErrorFlags_DataAfterEnd;
+ return a;
+ }
+
+ UInt32 GetErrorFlags() const
+ {
+ UInt32 a = ErrorFlags;
+ if (UnexpecedEnd)
+ a |= kpv_ErrorFlags_UnexpectedEnd;
+ return a;
+ }
+};
+
+struct CReadArcItem
+{
+ UString Path; // Path from root (including alt stream name, if alt stream)
+ UStringVector PathParts; // without altStream name, path from root or from _baseParentFolder, if _use_baseParentFolder_mode
+
+ #ifdef SUPPORT_ALT_STREAMS
+ UString MainPath;
+ /* MainPath = Path for non-AltStream,
+ MainPath = Path of parent, if there is parent for AltStream. */
+ UString AltStreamName;
+ bool IsAltStream;
+ bool WriteToAltStreamIfColon;
+ #endif
+
+ bool IsDir;
+ bool MainIsDir;
+ UInt32 ParentIndex; // use it, if IsAltStream
+
+ #ifndef Z7_SFX
+ bool _use_baseParentFolder_mode;
+ int _baseParentFolder;
+ #endif
+
+ CReadArcItem()
+ {
+ #ifdef SUPPORT_ALT_STREAMS
+ WriteToAltStreamIfColon = false;
+ #endif
+
+ #ifndef Z7_SFX
+ _use_baseParentFolder_mode = false;
+ _baseParentFolder = -1;
+ #endif
+ }
+};
+
+
+
+
+class CArc
+{
+ HRESULT PrepareToOpen(const COpenOptions &op, unsigned formatIndex, CMyComPtr<IInArchive> &archive);
+ HRESULT CheckZerosTail(const COpenOptions &op, UInt64 offset);
+ HRESULT OpenStream2(const COpenOptions &options);
+
+ #ifndef Z7_SFX
+ // parts.Back() can contain alt stream name "nams:AltName"
+ HRESULT GetItem_PathToParent(UInt32 index, UInt32 parent, UStringVector &parts) const;
+ #endif
+
+public:
+ CMyComPtr<IInArchive> Archive;
+ CMyComPtr<IInStream> InStream;
+ // we use InStream in 2 cases (ArcStreamOffset != 0):
+ // 1) if we use additional cache stream
+ // 2) we reopen sfx archive with CTailInStream
+
+ CMyComPtr<IArchiveGetRawProps> GetRawProps;
+ CMyComPtr<IArchiveGetRootProps> GetRootProps;
+
+ bool IsParseArc;
+
+ bool IsTree;
+ bool IsReadOnly;
+
+ bool Ask_Deleted;
+ bool Ask_AltStream;
+ bool Ask_Aux;
+ bool Ask_INode;
+
+ bool IgnoreSplit; // don't try split handler
+
+ UString Path;
+ UString filePath;
+ UString DefaultName;
+ int FormatIndex; // -1 means Parser
+ UInt32 SubfileIndex; // (UInt32)(Int32)-1; means no subfile
+
+ // CFiTime MTime;
+ // bool MTime_Defined;
+ CArcTime MTime;
+
+ Int64 Offset; // it's offset of start of archive inside stream that is open by Archive Handler
+ UInt64 PhySize;
+ // UInt64 OkPhySize;
+ bool PhySize_Defined;
+ // bool OkPhySize_Defined;
+ UInt64 FileSize;
+ UInt64 AvailPhySize; // PhySize, but it's reduced if exceed end of file
+
+ CArcErrorInfo ErrorInfo; // for OK archives
+ CArcErrorInfo NonOpen_ErrorInfo; // ErrorInfo for mainArchive (false OPEN)
+
+ UInt64 GetEstmatedPhySize() const { return PhySize_Defined ? PhySize : FileSize; }
+
+ UInt64 ArcStreamOffset; // offset of stream that is open by Archive Handler
+ Int64 GetGlobalOffset() const { return (Int64)ArcStreamOffset + Offset; } // it's global offset of archive
+
+ // AString ErrorFlagsText;
+
+ // void Set_ErrorFlagsText();
+
+ CArc():
+ // MTime_Defined(false),
+ IsTree(false),
+ IsReadOnly(false),
+ Ask_Deleted(false),
+ Ask_AltStream(false),
+ Ask_Aux(false),
+ Ask_INode(false),
+ IgnoreSplit(false)
+ {}
+
+ HRESULT ReadBasicProps(IInArchive *archive, UInt64 startPos, HRESULT openRes);
+
+ HRESULT Close()
+ {
+ InStream.Release();
+ return Archive->Close();
+ }
+
+ HRESULT GetItem_Path(UInt32 index, UString &result) const;
+ HRESULT GetItem_DefaultPath(UInt32 index, UString &result) const;
+
+ // GetItemPath2 adds [DELETED] dir prefix for deleted items.
+ HRESULT GetItem_Path2(UInt32 index, UString &result) const;
+
+ HRESULT GetItem(UInt32 index, CReadArcItem &item) const;
+
+ HRESULT GetItem_Size(UInt32 index, UInt64 &size, bool &defined) const;
+
+ /* if (GetProperty() returns vt==VT_EMPTY), this function sets
+ timestamp from archive file timestamp (MTime).
+ So (at) will be set in most cases (at.Def == true)
+ if (at.Prec == 0)
+ {
+ it means that (Prec == 0) was returned for (kpidMTime),
+ and no value was returned for (kpidTimeType).
+ it can mean Windows precision or unknown precision.
+ }
+ */
+ HRESULT GetItem_MTime(UInt32 index, CArcTime &at) const;
+
+ HRESULT IsItem_Anti(UInt32 index, bool &result) const
+ { return Archive_GetItemBoolProp(Archive, index, kpidIsAnti, result); }
+
+
+ HRESULT OpenStream(const COpenOptions &options);
+ HRESULT OpenStreamOrFile(COpenOptions &options);
+
+ HRESULT ReOpen(const COpenOptions &options, IArchiveOpenCallback *openCallback_Additional);
+
+ HRESULT CreateNewTailStream(CMyComPtr<IInStream> &stream);
+
+ bool IsHashHandler(const COpenOptions &options) const
+ {
+ if (FormatIndex < 0)
+ return false;
+ return options.codecs->Formats[(unsigned)FormatIndex].Flags_HashHandler();
+ }
+};
+
+struct CArchiveLink
+{
+ CObjectVector<CArc> Arcs;
+ UStringVector VolumePaths;
+ UInt64 VolumesSize;
+ bool IsOpen;
+
+ bool PasswordWasAsked;
+ // UString Password;
+
+ // int NonOpenErrorFormatIndex; // - 1 means no Error.
+ UString NonOpen_ArcPath;
+
+ CArcErrorInfo NonOpen_ErrorInfo;
+
+ // UString ErrorsText;
+ // void Set_ErrorsText();
+
+ CArchiveLink():
+ VolumesSize(0),
+ IsOpen(false),
+ PasswordWasAsked(false)
+ {}
+
+ void KeepModeForNextOpen();
+ HRESULT Close();
+ void Release();
+ ~CArchiveLink() { Release(); }
+
+ const CArc *GetArc() const { return &Arcs.Back(); }
+ IInArchive *GetArchive() const { return Arcs.Back().Archive; }
+ IArchiveGetRawProps *GetArchiveGetRawProps() const { return Arcs.Back().GetRawProps; }
+ IArchiveGetRootProps *GetArchiveGetRootProps() const { return Arcs.Back().GetRootProps; }
+
+ /*
+ Open() opens archive and COpenOptions::callback
+ Open2() uses COpenCallbackImp that implements Volumes and password callback
+ Open3() calls Open2() and callbackUI->Open_Finished();
+ Open_Strict() returns S_FALSE also in case, if there is non-open expected nested archive.
+ */
+
+ HRESULT Open(COpenOptions &options);
+ HRESULT Open2(COpenOptions &options, IOpenCallbackUI *callbackUI);
+ HRESULT Open3(COpenOptions &options, IOpenCallbackUI *callbackUI);
+
+ HRESULT Open_Strict(COpenOptions &options, IOpenCallbackUI *callbackUI)
+ {
+ HRESULT result = Open3(options, callbackUI);
+ if (result == S_OK && NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
+ result = S_FALSE;
+ return result;
+ }
+
+ HRESULT ReOpen(COpenOptions &options);
+};
+
+bool ParseOpenTypes(CCodecs &codecs, const UString &s, CObjectVector<COpenType> &types);
+
+// bool IsHashType(const CObjectVector<COpenType> &types);
+
+
+struct CDirPathSortPair
+{
+ unsigned Len;
+ unsigned Index;
+
+ void SetNumSlashes(const FChar *s);
+
+ int Compare(const CDirPathSortPair &a) const
+ {
+ // We need sorting order where parent items will be after child items
+ if (Len < a.Len) return 1;
+ if (Len > a.Len) return -1;
+ if (Index < a.Index) return -1;
+ if (Index > a.Index) return 1;
+ return 0;
+ }
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/PropIDUtils.cpp b/CPP/7zip/UI/Common/PropIDUtils.cpp
index bb9c89f..ee9ff32 100644
--- a/CPP/7zip/UI/Common/PropIDUtils.cpp
+++ b/CPP/7zip/UI/Common/PropIDUtils.cpp
@@ -1,668 +1,741 @@
-// PropIDUtils.cpp
-
-#include "StdAfx.h"
-
-#include "../../../../C/CpuArch.h"
-
-#include "../../../Common/IntToString.h"
-#include "../../../Common/StringConvert.h"
-
-#include "../../../Windows/FileIO.h"
-#include "../../../Windows/PropVariantConv.h"
-
-#include "../../PropID.h"
-
-#include "PropIDUtils.h"
-
-#define Get16(x) GetUi16(x)
-#define Get32(x) GetUi32(x)
-
-using namespace NWindows;
-
-static const unsigned kNumWinAtrribFlags = 21;
-static const char g_WinAttribChars[kNumWinAtrribFlags + 1] = "RHS8DAdNTsLCOIEV.X.PU";
-
-/*
-FILE_ATTRIBUTE_
-
-0 READONLY
-1 HIDDEN
-2 SYSTEM
-3 (Volume label - obsolete)
-4 DIRECTORY
-5 ARCHIVE
-6 DEVICE
-7 NORMAL
-8 TEMPORARY
-9 SPARSE_FILE
-10 REPARSE_POINT
-11 COMPRESSED
-12 OFFLINE
-13 NOT_CONTENT_INDEXED (I - Win10 attrib/Explorer)
-14 ENCRYPTED
-15 INTEGRITY_STREAM (V - ReFS Win8/Win2012)
-16 VIRTUAL (reserved)
-17 NO_SCRUB_DATA (X - ReFS Win8/Win2012 attrib)
-18 RECALL_ON_OPEN or EA
-19 PINNED
-20 UNPINNED
-21 STRICTLY_SEQUENTIAL
-22 RECALL_ON_DATA_ACCESS
-*/
-
-
-static const char kPosixTypes[16] = { '0', 'p', 'c', '3', 'd', '5', 'b', '7', '-', '9', 'l', 'B', 's', 'D', 'E', 'F' };
-#define MY_ATTR_CHAR(a, n, c) ((a) & (1 << (n))) ? c : '-';
-
-static void ConvertPosixAttribToString(char *s, UInt32 a) throw()
-{
- s[0] = kPosixTypes[(a >> 12) & 0xF];
- for (int i = 6; i >= 0; i -= 3)
- {
- s[7 - i] = MY_ATTR_CHAR(a, i + 2, 'r');
- s[8 - i] = MY_ATTR_CHAR(a, i + 1, 'w');
- s[9 - i] = MY_ATTR_CHAR(a, i + 0, 'x');
- }
- if ((a & 0x800) != 0) s[3] = ((a & (1 << 6)) ? 's' : 'S');
- if ((a & 0x400) != 0) s[6] = ((a & (1 << 3)) ? 's' : 'S');
- if ((a & 0x200) != 0) s[9] = ((a & (1 << 0)) ? 't' : 'T');
- s[10] = 0;
-
- a &= ~(UInt32)0xFFFF;
- if (a != 0)
- {
- s[10] = ' ';
- ConvertUInt32ToHex8Digits(a, s + 11);
- }
-}
-
-
-void ConvertWinAttribToString(char *s, UInt32 wa) throw()
-{
- /*
- some programs store posix attributes in high 16 bits.
- p7zip - stores additional 0x8000 flag marker.
- macos - stores additional 0x4000 flag marker.
- info-zip - no additional marker.
- */
-
- bool isPosix = ((wa & 0xF0000000) != 0);
-
- UInt32 posix = 0;
- if (isPosix)
- {
- posix = wa >> 16;
- wa &= (UInt32)0x3FFF;
- }
-
- for (unsigned i = 0; i < kNumWinAtrribFlags; i++)
- {
- UInt32 flag = (1 << i);
- if ((wa & flag) != 0)
- {
- char c = g_WinAttribChars[i];
- if (c != '.')
- {
- wa &= ~flag;
- // if (i != 7) // we can disable N (NORMAL) printing
- *s++ = c;
- }
- }
- }
-
- if (wa != 0)
- {
- *s++ = ' ';
- ConvertUInt32ToHex8Digits(wa, s);
- s += strlen(s);
- }
-
- *s = 0;
-
- if (isPosix)
- {
- *s++ = ' ';
- ConvertPosixAttribToString(s, posix);
- }
-}
-
-
-void ConvertPropertyToShortString2(char *dest, const PROPVARIANT &prop, PROPID propID, int level) throw()
-{
- *dest = 0;
-
- if (prop.vt == VT_FILETIME)
- {
- const FILETIME &ft = prop.filetime;
- if ((ft.dwHighDateTime == 0 &&
- ft.dwLowDateTime == 0))
- return;
- ConvertUtcFileTimeToString(prop.filetime, dest, level);
- return;
- }
-
- switch (propID)
- {
- case kpidCRC:
- {
- if (prop.vt != VT_UI4)
- break;
- ConvertUInt32ToHex8Digits(prop.ulVal, dest);
- return;
- }
- case kpidAttrib:
- {
- if (prop.vt != VT_UI4)
- break;
- UInt32 a = prop.ulVal;
-
- /*
- if ((a & 0x8000) && (a & 0x7FFF) == 0)
- ConvertPosixAttribToString(dest, a >> 16);
- else
- */
- ConvertWinAttribToString(dest, a);
- return;
- }
- case kpidPosixAttrib:
- {
- if (prop.vt != VT_UI4)
- break;
- ConvertPosixAttribToString(dest, prop.ulVal);
- return;
- }
- case kpidINode:
- {
- if (prop.vt != VT_UI8)
- break;
- ConvertUInt32ToString((UInt32)(prop.uhVal.QuadPart >> 48), dest);
- dest += strlen(dest);
- *dest++ = '-';
- UInt64 low = prop.uhVal.QuadPart & (((UInt64)1 << 48) - 1);
- ConvertUInt64ToString(low, dest);
- return;
- }
- case kpidVa:
- {
- UInt64 v = 0;
- if (prop.vt == VT_UI4)
- v = prop.ulVal;
- else if (prop.vt == VT_UI8)
- v = (UInt64)prop.uhVal.QuadPart;
- else
- break;
- dest[0] = '0';
- dest[1] = 'x';
- ConvertUInt64ToHex(v, dest + 2);
- return;
- }
- }
-
- ConvertPropVariantToShortString(prop, dest);
-}
-
-void ConvertPropertyToString2(UString &dest, const PROPVARIANT &prop, PROPID propID, int level)
-{
- if (prop.vt == VT_BSTR)
- {
- dest.SetFromBstr(prop.bstrVal);
- return;
- }
- char temp[64];
- ConvertPropertyToShortString2(temp, prop, propID, level);
- dest = temp;
-}
-
-static inline unsigned GetHex(unsigned v)
-{
- return (v < 10) ? ('0' + v) : ('A' + (v - 10));
-}
-
-#ifndef _SFX
-
-static inline void AddHexToString(AString &res, unsigned v)
-{
- res += (char)GetHex(v >> 4);
- res += (char)GetHex(v & 0xF);
-}
-
-/*
-static AString Data_To_Hex(const Byte *data, size_t size)
-{
- AString s;
- for (size_t i = 0; i < size; i++)
- AddHexToString(s, data[i]);
- return s;
-}
-*/
-
-static const char * const sidNames[] =
-{
- "0"
- , "Dialup"
- , "Network"
- , "Batch"
- , "Interactive"
- , "Logon" // S-1-5-5-X-Y
- , "Service"
- , "Anonymous"
- , "Proxy"
- , "EnterpriseDC"
- , "Self"
- , "AuthenticatedUsers"
- , "RestrictedCode"
- , "TerminalServer"
- , "RemoteInteractiveLogon"
- , "ThisOrganization"
- , "16"
- , "IUserIIS"
- , "LocalSystem"
- , "LocalService"
- , "NetworkService"
- , "Domains"
-};
-
-struct CSecID2Name
-{
- UInt32 n;
- const char *sz;
-};
-
-static int FindPairIndex(const CSecID2Name * pairs, unsigned num, UInt32 id)
-{
- for (unsigned i = 0; i < num; i++)
- if (pairs[i].n == id)
- return i;
- return -1;
-}
-
-static const CSecID2Name sid_32_Names[] =
-{
- { 544, "Administrators" },
- { 545, "Users" },
- { 546, "Guests" },
- { 547, "PowerUsers" },
- { 548, "AccountOperators" },
- { 549, "ServerOperators" },
- { 550, "PrintOperators" },
- { 551, "BackupOperators" },
- { 552, "Replicators" },
- { 553, "Backup Operators" },
- { 554, "PreWindows2000CompatibleAccess" },
- { 555, "RemoteDesktopUsers" },
- { 556, "NetworkConfigurationOperators" },
- { 557, "IncomingForestTrustBuilders" },
- { 558, "PerformanceMonitorUsers" },
- { 559, "PerformanceLogUsers" },
- { 560, "WindowsAuthorizationAccessGroup" },
- { 561, "TerminalServerLicenseServers" },
- { 562, "DistributedCOMUsers" },
- { 569, "CryptographicOperators" },
- { 573, "EventLogReaders" },
- { 574, "CertificateServiceDCOMAccess" }
-};
-
-static const CSecID2Name sid_21_Names[] =
-{
- { 500, "Administrator" },
- { 501, "Guest" },
- { 502, "KRBTGT" },
- { 512, "DomainAdmins" },
- { 513, "DomainUsers" },
- { 515, "DomainComputers" },
- { 516, "DomainControllers" },
- { 517, "CertPublishers" },
- { 518, "SchemaAdmins" },
- { 519, "EnterpriseAdmins" },
- { 520, "GroupPolicyCreatorOwners" },
- { 553, "RASandIASServers" },
- { 553, "RASandIASServers" },
- { 571, "AllowedRODCPasswordReplicationGroup" },
- { 572, "DeniedRODCPasswordReplicationGroup" }
-};
-
-struct CServicesToName
-{
- UInt32 n[5];
- const char *sz;
-};
-
-static const CServicesToName services_to_name[] =
-{
- { { 0x38FB89B5, 0xCBC28419, 0x6D236C5C, 0x6E770057, 0x876402C0 } , "TrustedInstaller" }
-};
-
-static void ParseSid(AString &s, const Byte *p, UInt32 lim, UInt32 &sidSize)
-{
- sidSize = 0;
- if (lim < 8)
- {
- s += "ERROR";
- return;
- }
- UInt32 rev = p[0];
- if (rev != 1)
- {
- s += "UNSUPPORTED";
- return;
- }
- UInt32 num = p[1];
- if (8 + num * 4 > lim)
- {
- s += "ERROR";
- return;
- }
- sidSize = 8 + num * 4;
- UInt32 authority = GetBe32(p + 4);
-
- if (p[2] == 0 && p[3] == 0 && authority == 5 && num >= 1)
- {
- UInt32 v0 = Get32(p + 8);
- if (v0 < ARRAY_SIZE(sidNames))
- {
- s += sidNames[v0];
- return;
- }
- if (v0 == 32 && num == 2)
- {
- UInt32 v1 = Get32(p + 12);
- int index = FindPairIndex(sid_32_Names, ARRAY_SIZE(sid_32_Names), v1);
- if (index >= 0)
- {
- s += sid_32_Names[(unsigned)index].sz;
- return;
- }
- }
- if (v0 == 21 && num == 5)
- {
- UInt32 v4 = Get32(p + 8 + 4 * 4);
- int index = FindPairIndex(sid_21_Names, ARRAY_SIZE(sid_21_Names), v4);
- if (index >= 0)
- {
- s += sid_21_Names[(unsigned)index].sz;
- return;
- }
- }
- if (v0 == 80 && num == 6)
- {
- for (unsigned i = 0; i < ARRAY_SIZE(services_to_name); i++)
- {
- const CServicesToName &sn = services_to_name[i];
- int j;
- for (j = 0; j < 5 && sn.n[j] == Get32(p + 8 + 4 + j * 4); j++);
- if (j == 5)
- {
- s += sn.sz;
- return;
- }
- }
- }
- }
-
- s += "S-1-";
- if (p[2] == 0 && p[3] == 0)
- s.Add_UInt32(authority);
- else
- {
- s += "0x";
- for (int i = 2; i < 8; i++)
- AddHexToString(s, p[i]);
- }
- for (UInt32 i = 0; i < num; i++)
- {
- s += '-';
- s.Add_UInt32(Get32(p + 8 + i * 4));
- }
-}
-
-static void ParseOwner(AString &s, const Byte *p, UInt32 size, UInt32 pos)
-{
- if (pos > size)
- {
- s += "ERROR";
- return;
- }
- UInt32 sidSize = 0;
- ParseSid(s, p + pos, size - pos, sidSize);
-}
-
-static void ParseAcl(AString &s, const Byte *p, UInt32 size, const char *strName, UInt32 flags, UInt32 offset)
-{
- UInt32 control = Get16(p + 2);
- if ((flags & control) == 0)
- return;
- UInt32 pos = Get32(p + offset);
- s.Add_Space();
- s += strName;
- if (pos >= size)
- return;
- p += pos;
- size -= pos;
- if (size < 8)
- return;
- if (Get16(p) != 2) // revision
- return;
- UInt32 num = Get32(p + 4);
- s.Add_UInt32(num);
-
- /*
- UInt32 aclSize = Get16(p + 2);
- if (num >= (1 << 16))
- return;
- if (aclSize > size)
- return;
- size = aclSize;
- size -= 8;
- p += 8;
- for (UInt32 i = 0 ; i < num; i++)
- {
- if (size <= 8)
- return;
- // Byte type = p[0];
- // Byte flags = p[1];
- // UInt32 aceSize = Get16(p + 2);
- // UInt32 mask = Get32(p + 4);
- p += 8;
- size -= 8;
-
- UInt32 sidSize = 0;
- s.Add_Space();
- ParseSid(s, p, size, sidSize);
- if (sidSize == 0)
- return;
- p += sidSize;
- size -= sidSize;
- }
-
- // the tail can contain zeros. So (size != 0) is not ERROR
- // if (size != 0) s += " ERROR";
- */
-}
-
-#define MY_SE_OWNER_DEFAULTED (0x0001)
-#define MY_SE_GROUP_DEFAULTED (0x0002)
-#define MY_SE_DACL_PRESENT (0x0004)
-#define MY_SE_DACL_DEFAULTED (0x0008)
-#define MY_SE_SACL_PRESENT (0x0010)
-#define MY_SE_SACL_DEFAULTED (0x0020)
-#define MY_SE_DACL_AUTO_INHERIT_REQ (0x0100)
-#define MY_SE_SACL_AUTO_INHERIT_REQ (0x0200)
-#define MY_SE_DACL_AUTO_INHERITED (0x0400)
-#define MY_SE_SACL_AUTO_INHERITED (0x0800)
-#define MY_SE_DACL_PROTECTED (0x1000)
-#define MY_SE_SACL_PROTECTED (0x2000)
-#define MY_SE_RM_CONTROL_VALID (0x4000)
-#define MY_SE_SELF_RELATIVE (0x8000)
-
-void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s)
-{
- s.Empty();
- if (size < 20 || size > (1 << 18))
- {
- s += "ERROR";
- return;
- }
- if (Get16(data) != 1) // revision
- {
- s += "UNSUPPORTED";
- return;
- }
- ParseOwner(s, data, size, Get32(data + 4));
- s.Add_Space();
- ParseOwner(s, data, size, Get32(data + 8));
- ParseAcl(s, data, size, "s:", MY_SE_SACL_PRESENT, 12);
- ParseAcl(s, data, size, "d:", MY_SE_DACL_PRESENT, 16);
- s.Add_Space();
- s.Add_UInt32(size);
- // s += '\n';
- // s += Data_To_Hex(data, size);
-}
-
-#ifdef _WIN32
-
-static bool CheckSid(const Byte *data, UInt32 size, UInt32 pos) throw()
-{
- if (pos >= size)
- return false;
- size -= pos;
- if (size < 8)
- return false;
- UInt32 rev = data[pos];
- if (rev != 1)
- return false;
- UInt32 num = data[pos + 1];
- return (8 + num * 4 <= size);
-}
-
-static bool CheckAcl(const Byte *p, UInt32 size, UInt32 flags, UInt32 offset) throw()
-{
- UInt32 control = Get16(p + 2);
- if ((flags & control) == 0)
- return true;
- UInt32 pos = Get32(p + offset);
- if (pos >= size)
- return false;
- p += pos;
- size -= pos;
- if (size < 8)
- return false;
- UInt32 aclSize = Get16(p + 2);
- return (aclSize <= size);
-}
-
-bool CheckNtSecure(const Byte *data, UInt32 size) throw()
-{
- if (size < 20)
- return false;
- if (Get16(data) != 1) // revision
- return true; // windows function can handle such error, so we allow it
- if (size > (1 << 18))
- return false;
- if (!CheckSid(data, size, Get32(data + 4))) return false;
- if (!CheckSid(data, size, Get32(data + 8))) return false;
- if (!CheckAcl(data, size, MY_SE_SACL_PRESENT, 12)) return false;
- if (!CheckAcl(data, size, MY_SE_DACL_PRESENT, 16)) return false;
- return true;
-}
-
-#endif
-
-
-
-// IO_REPARSE_TAG_*
-
-static const CSecID2Name k_ReparseTags[] =
-{
- { 0xA0000003, "MOUNT_POINT" },
- { 0xC0000004, "HSM" },
- { 0x80000005, "DRIVE_EXTENDER" },
- { 0x80000006, "HSM2" },
- { 0x80000007, "SIS" },
- { 0x80000008, "WIM" },
- { 0x80000009, "CSV" },
- { 0x8000000A, "DFS" },
- { 0x8000000B, "FILTER_MANAGER" },
- { 0xA000000C, "SYMLINK" },
- { 0xA0000010, "IIS_CACHE" },
- { 0x80000012, "DFSR" },
- { 0x80000013, "DEDUP" },
- { 0xC0000014, "APPXSTRM" },
- { 0x80000014, "NFS" },
- { 0x80000015, "FILE_PLACEHOLDER" },
- { 0x80000016, "DFM" },
- { 0x80000017, "WOF" }
-};
-
-bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s)
-{
- s.Empty();
- NFile::CReparseAttr attr;
- DWORD errorCode = 0;
- if (attr.Parse(data, size, errorCode))
- {
- if (!attr.IsSymLink())
- s += "Junction: ";
- s += attr.GetPath();
- if (!attr.IsOkNamePair())
- {
- s += " : ";
- s += attr.PrintName;
- }
- return true;
- }
-
- if (size < 8)
- return false;
- UInt32 tag = Get32(data);
- UInt32 len = Get16(data + 4);
- if (len + 8 > size)
- return false;
- if (Get16(data + 6) != 0) // padding
- return false;
-
- /*
- #define _my_IO_REPARSE_TAG_DEDUP (0x80000013L)
- if (tag == _my_IO_REPARSE_TAG_DEDUP)
- {
- }
- */
-
- {
- int index = FindPairIndex(k_ReparseTags, ARRAY_SIZE(k_ReparseTags), tag);
- if (index >= 0)
- s += k_ReparseTags[(unsigned)index].sz;
- else
- {
- s += "REPARSE:";
- char hex[16];
- ConvertUInt32ToHex8Digits(tag, hex);
- s += hex;
- }
- }
-
- s += ":";
- s.Add_UInt32(len);
-
- if (len != 0)
- {
- s.Add_Space();
-
- data += 8;
-
- for (UInt32 i = 0; i < len; i++)
- {
- if (i >= 8)
- {
- s += "...";
- break;
- }
- unsigned b = data[i];
- s += (char)GetHex((b >> 4) & 0xF);
- s += (char)GetHex(b & 0xF);
- }
- }
-
- return true;
-}
-
-#endif
+// PropIDUtils.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/FileIO.h"
+#include "../../../Windows/PropVariantConv.h"
+
+#include "../../PropID.h"
+
+#include "PropIDUtils.h"
+
+#ifndef Z7_SFX
+#define Get16(x) GetUi16(x)
+#define Get32(x) GetUi32(x)
+#endif
+
+using namespace NWindows;
+
+static const unsigned kNumWinAtrribFlags = 21;
+static const char g_WinAttribChars[kNumWinAtrribFlags + 1] = "RHS8DAdNTsLCOIEV.X.PU";
+
+/*
+FILE_ATTRIBUTE_
+
+0 READONLY
+1 HIDDEN
+2 SYSTEM
+3 (Volume label - obsolete)
+4 DIRECTORY
+5 ARCHIVE
+6 DEVICE
+7 NORMAL
+8 TEMPORARY
+9 SPARSE_FILE
+10 REPARSE_POINT
+11 COMPRESSED
+12 OFFLINE
+13 NOT_CONTENT_INDEXED (I - Win10 attrib/Explorer)
+14 ENCRYPTED
+15 INTEGRITY_STREAM (V - ReFS Win8/Win2012)
+16 VIRTUAL (reserved)
+17 NO_SCRUB_DATA (X - ReFS Win8/Win2012 attrib)
+18 RECALL_ON_OPEN or EA
+19 PINNED
+20 UNPINNED
+21 STRICTLY_SEQUENTIAL
+22 RECALL_ON_DATA_ACCESS
+*/
+
+
+static const char kPosixTypes[16] = { '0', 'p', 'c', '3', 'd', '5', 'b', '7', '-', '9', 'l', 'B', 's', 'D', 'E', 'F' };
+#define MY_ATTR_CHAR(a, n, c) (((a) & (1 << (n))) ? c : '-')
+
+static void ConvertPosixAttribToString(char *s, UInt32 a) throw()
+{
+ s[0] = kPosixTypes[(a >> 12) & 0xF];
+ for (int i = 6; i >= 0; i -= 3)
+ {
+ s[7 - i] = MY_ATTR_CHAR(a, i + 2, 'r');
+ s[8 - i] = MY_ATTR_CHAR(a, i + 1, 'w');
+ s[9 - i] = MY_ATTR_CHAR(a, i + 0, 'x');
+ }
+ if ((a & 0x800) != 0) s[3] = ((a & (1 << 6)) ? 's' : 'S'); // S_ISUID
+ if ((a & 0x400) != 0) s[6] = ((a & (1 << 3)) ? 's' : 'S'); // S_ISGID
+ if ((a & 0x200) != 0) s[9] = ((a & (1 << 0)) ? 't' : 'T'); // S_ISVTX
+ s[10] = 0;
+
+ a &= ~(UInt32)0xFFFF;
+ if (a != 0)
+ {
+ s[10] = ' ';
+ ConvertUInt32ToHex8Digits(a, s + 11);
+ }
+}
+
+
+void ConvertWinAttribToString(char *s, UInt32 wa) throw()
+{
+ /*
+ some programs store posix attributes in high 16 bits.
+ p7zip - stores additional 0x8000 flag marker.
+ macos - stores additional 0x4000 flag marker.
+ info-zip - no additional marker.
+ */
+
+ const bool isPosix = ((wa & 0xF0000000) != 0);
+
+ UInt32 posix = 0;
+ if (isPosix)
+ {
+ posix = wa >> 16;
+ wa &= (UInt32)0x3FFF;
+ }
+
+ for (unsigned i = 0; i < kNumWinAtrribFlags; i++)
+ {
+ UInt32 flag = (1 << i);
+ if ((wa & flag) != 0)
+ {
+ char c = g_WinAttribChars[i];
+ if (c != '.')
+ {
+ wa &= ~flag;
+ // if (i != 7) // we can disable N (NORMAL) printing
+ *s++ = c;
+ }
+ }
+ }
+
+ if (wa != 0)
+ {
+ *s++ = ' ';
+ ConvertUInt32ToHex8Digits(wa, s);
+ s += strlen(s);
+ }
+
+ *s = 0;
+
+ if (isPosix)
+ {
+ *s++ = ' ';
+ ConvertPosixAttribToString(s, posix);
+ }
+}
+
+
+void ConvertPropertyToShortString2(char *dest, const PROPVARIANT &prop, PROPID propID, int level) throw()
+{
+ *dest = 0;
+
+ if (prop.vt == VT_FILETIME)
+ {
+ const FILETIME &ft = prop.filetime;
+ unsigned ns100 = 0;
+ int numDigits = kTimestampPrintLevel_NTFS;
+ const unsigned prec = prop.wReserved1;
+ const unsigned ns100_Temp = prop.wReserved2;
+ if (prec != 0
+ && prec <= k_PropVar_TimePrec_1ns
+ && ns100_Temp < 100
+ && prop.wReserved3 == 0)
+ {
+ ns100 = ns100_Temp;
+ if (prec == k_PropVar_TimePrec_Unix ||
+ prec == k_PropVar_TimePrec_DOS)
+ numDigits = 0;
+ else if (prec == k_PropVar_TimePrec_HighPrec)
+ numDigits = 9;
+ else
+ {
+ numDigits = (int)prec - (int)k_PropVar_TimePrec_Base;
+ if (
+ // numDigits < kTimestampPrintLevel_DAY // for debuf
+ numDigits < kTimestampPrintLevel_SEC
+ )
+
+ numDigits = kTimestampPrintLevel_NTFS;
+ }
+ }
+ if (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0 && ns100 == 0)
+ return;
+ if (level > numDigits)
+ level = numDigits;
+ ConvertUtcFileTimeToString2(ft, ns100, dest, level);
+ return;
+ }
+
+ switch (propID)
+ {
+ case kpidCRC:
+ {
+ if (prop.vt != VT_UI4)
+ break;
+ ConvertUInt32ToHex8Digits(prop.ulVal, dest);
+ return;
+ }
+ case kpidAttrib:
+ {
+ if (prop.vt != VT_UI4)
+ break;
+ const UInt32 a = prop.ulVal;
+
+ /*
+ if ((a & 0x8000) && (a & 0x7FFF) == 0)
+ ConvertPosixAttribToString(dest, a >> 16);
+ else
+ */
+ ConvertWinAttribToString(dest, a);
+ return;
+ }
+ case kpidPosixAttrib:
+ {
+ if (prop.vt != VT_UI4)
+ break;
+ ConvertPosixAttribToString(dest, prop.ulVal);
+ return;
+ }
+ case kpidINode:
+ {
+ if (prop.vt != VT_UI8)
+ break;
+ ConvertUInt32ToString((UInt32)(prop.uhVal.QuadPart >> 48), dest);
+ dest += strlen(dest);
+ *dest++ = '-';
+ const UInt64 low = prop.uhVal.QuadPart & (((UInt64)1 << 48) - 1);
+ ConvertUInt64ToString(low, dest);
+ return;
+ }
+ case kpidVa:
+ {
+ UInt64 v = 0;
+ if (prop.vt == VT_UI4)
+ v = prop.ulVal;
+ else if (prop.vt == VT_UI8)
+ v = (UInt64)prop.uhVal.QuadPart;
+ else
+ break;
+ dest[0] = '0';
+ dest[1] = 'x';
+ ConvertUInt64ToHex(v, dest + 2);
+ return;
+ }
+
+ /*
+ case kpidDevice:
+ {
+ UInt64 v = 0;
+ if (prop.vt == VT_UI4)
+ v = prop.ulVal;
+ else if (prop.vt == VT_UI8)
+ v = (UInt64)prop.uhVal.QuadPart;
+ else
+ break;
+ ConvertUInt32ToString(MY_dev_major(v), dest);
+ dest += strlen(dest);
+ *dest++ = ',';
+ ConvertUInt32ToString(MY_dev_minor(v), dest);
+ return;
+ }
+ */
+ }
+
+ ConvertPropVariantToShortString(prop, dest);
+}
+
+void ConvertPropertyToString2(UString &dest, const PROPVARIANT &prop, PROPID propID, int level)
+{
+ if (prop.vt == VT_BSTR)
+ {
+ dest.SetFromBstr(prop.bstrVal);
+ return;
+ }
+ char temp[64];
+ ConvertPropertyToShortString2(temp, prop, propID, level);
+ dest = temp;
+}
+
+#ifndef Z7_SFX
+
+static inline unsigned GetHex(unsigned v)
+{
+ return (v < 10) ? ('0' + v) : ('A' + (v - 10));
+}
+
+static inline void AddHexToString(AString &res, unsigned v)
+{
+ res += (char)GetHex(v >> 4);
+ res += (char)GetHex(v & 0xF);
+}
+
+/*
+static AString Data_To_Hex(const Byte *data, size_t size)
+{
+ AString s;
+ for (size_t i = 0; i < size; i++)
+ AddHexToString(s, data[i]);
+ return s;
+}
+*/
+
+static const char * const sidNames[] =
+{
+ "0"
+ , "Dialup"
+ , "Network"
+ , "Batch"
+ , "Interactive"
+ , "Logon" // S-1-5-5-X-Y
+ , "Service"
+ , "Anonymous"
+ , "Proxy"
+ , "EnterpriseDC"
+ , "Self"
+ , "AuthenticatedUsers"
+ , "RestrictedCode"
+ , "TerminalServer"
+ , "RemoteInteractiveLogon"
+ , "ThisOrganization"
+ , "16"
+ , "IUserIIS"
+ , "LocalSystem"
+ , "LocalService"
+ , "NetworkService"
+ , "Domains"
+};
+
+struct CSecID2Name
+{
+ UInt32 n;
+ const char *sz;
+};
+
+static int FindPairIndex(const CSecID2Name * pairs, unsigned num, UInt32 id)
+{
+ for (unsigned i = 0; i < num; i++)
+ if (pairs[i].n == id)
+ return (int)i;
+ return -1;
+}
+
+static const CSecID2Name sid_32_Names[] =
+{
+ { 544, "Administrators" },
+ { 545, "Users" },
+ { 546, "Guests" },
+ { 547, "PowerUsers" },
+ { 548, "AccountOperators" },
+ { 549, "ServerOperators" },
+ { 550, "PrintOperators" },
+ { 551, "BackupOperators" },
+ { 552, "Replicators" },
+ { 553, "Backup Operators" },
+ { 554, "PreWindows2000CompatibleAccess" },
+ { 555, "RemoteDesktopUsers" },
+ { 556, "NetworkConfigurationOperators" },
+ { 557, "IncomingForestTrustBuilders" },
+ { 558, "PerformanceMonitorUsers" },
+ { 559, "PerformanceLogUsers" },
+ { 560, "WindowsAuthorizationAccessGroup" },
+ { 561, "TerminalServerLicenseServers" },
+ { 562, "DistributedCOMUsers" },
+ { 569, "CryptographicOperators" },
+ { 573, "EventLogReaders" },
+ { 574, "CertificateServiceDCOMAccess" }
+};
+
+static const CSecID2Name sid_21_Names[] =
+{
+ { 500, "Administrator" },
+ { 501, "Guest" },
+ { 502, "KRBTGT" },
+ { 512, "DomainAdmins" },
+ { 513, "DomainUsers" },
+ { 515, "DomainComputers" },
+ { 516, "DomainControllers" },
+ { 517, "CertPublishers" },
+ { 518, "SchemaAdmins" },
+ { 519, "EnterpriseAdmins" },
+ { 520, "GroupPolicyCreatorOwners" },
+ { 553, "RASandIASServers" },
+ { 553, "RASandIASServers" },
+ { 571, "AllowedRODCPasswordReplicationGroup" },
+ { 572, "DeniedRODCPasswordReplicationGroup" }
+};
+
+struct CServicesToName
+{
+ UInt32 n[5];
+ const char *sz;
+};
+
+static const CServicesToName services_to_name[] =
+{
+ { { 0x38FB89B5, 0xCBC28419, 0x6D236C5C, 0x6E770057, 0x876402C0 } , "TrustedInstaller" }
+};
+
+static void ParseSid(AString &s, const Byte *p, UInt32 lim, UInt32 &sidSize)
+{
+ sidSize = 0;
+ if (lim < 8)
+ {
+ s += "ERROR";
+ return;
+ }
+ const UInt32 rev = p[0];
+ if (rev != 1)
+ {
+ s += "UNSUPPORTED";
+ return;
+ }
+ const UInt32 num = p[1];
+ if (8 + num * 4 > lim)
+ {
+ s += "ERROR";
+ return;
+ }
+ sidSize = 8 + num * 4;
+ const UInt32 authority = GetBe32(p + 4);
+
+ if (p[2] == 0 && p[3] == 0 && authority == 5 && num >= 1)
+ {
+ const UInt32 v0 = Get32(p + 8);
+ if (v0 < Z7_ARRAY_SIZE(sidNames))
+ {
+ s += sidNames[v0];
+ return;
+ }
+ if (v0 == 32 && num == 2)
+ {
+ const UInt32 v1 = Get32(p + 12);
+ const int index = FindPairIndex(sid_32_Names, Z7_ARRAY_SIZE(sid_32_Names), v1);
+ if (index >= 0)
+ {
+ s += sid_32_Names[(unsigned)index].sz;
+ return;
+ }
+ }
+ if (v0 == 21 && num == 5)
+ {
+ UInt32 v4 = Get32(p + 8 + 4 * 4);
+ const int index = FindPairIndex(sid_21_Names, Z7_ARRAY_SIZE(sid_21_Names), v4);
+ if (index >= 0)
+ {
+ s += sid_21_Names[(unsigned)index].sz;
+ return;
+ }
+ }
+ if (v0 == 80 && num == 6)
+ {
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(services_to_name); i++)
+ {
+ const CServicesToName &sn = services_to_name[i];
+ int j;
+ for (j = 0; j < 5 && sn.n[j] == Get32(p + 8 + 4 + j * 4); j++);
+ if (j == 5)
+ {
+ s += sn.sz;
+ return;
+ }
+ }
+ }
+ }
+
+ s += "S-1-";
+ if (p[2] == 0 && p[3] == 0)
+ s.Add_UInt32(authority);
+ else
+ {
+ s += "0x";
+ for (int i = 2; i < 8; i++)
+ AddHexToString(s, p[i]);
+ }
+ for (UInt32 i = 0; i < num; i++)
+ {
+ s.Add_Minus();
+ s.Add_UInt32(Get32(p + 8 + i * 4));
+ }
+}
+
+static void ParseOwner(AString &s, const Byte *p, UInt32 size, UInt32 pos)
+{
+ if (pos > size)
+ {
+ s += "ERROR";
+ return;
+ }
+ UInt32 sidSize = 0;
+ ParseSid(s, p + pos, size - pos, sidSize);
+}
+
+static void ParseAcl(AString &s, const Byte *p, UInt32 size, const char *strName, UInt32 flags, UInt32 offset)
+{
+ const UInt32 control = Get16(p + 2);
+ if ((flags & control) == 0)
+ return;
+ const UInt32 pos = Get32(p + offset);
+ s.Add_Space();
+ s += strName;
+ if (pos >= size)
+ return;
+ p += pos;
+ size -= pos;
+ if (size < 8)
+ return;
+ if (Get16(p) != 2) // revision
+ return;
+ const UInt32 num = Get32(p + 4);
+ s.Add_UInt32(num);
+
+ /*
+ UInt32 aclSize = Get16(p + 2);
+ if (num >= (1 << 16))
+ return;
+ if (aclSize > size)
+ return;
+ size = aclSize;
+ size -= 8;
+ p += 8;
+ for (UInt32 i = 0 ; i < num; i++)
+ {
+ if (size <= 8)
+ return;
+ // Byte type = p[0];
+ // Byte flags = p[1];
+ // UInt32 aceSize = Get16(p + 2);
+ // UInt32 mask = Get32(p + 4);
+ p += 8;
+ size -= 8;
+
+ UInt32 sidSize = 0;
+ s.Add_Space();
+ ParseSid(s, p, size, sidSize);
+ if (sidSize == 0)
+ return;
+ p += sidSize;
+ size -= sidSize;
+ }
+
+ // the tail can contain zeros. So (size != 0) is not ERROR
+ // if (size != 0) s += " ERROR";
+ */
+}
+
+/*
+#define MY_SE_OWNER_DEFAULTED (0x0001)
+#define MY_SE_GROUP_DEFAULTED (0x0002)
+*/
+#define MY_SE_DACL_PRESENT (0x0004)
+/*
+#define MY_SE_DACL_DEFAULTED (0x0008)
+*/
+#define MY_SE_SACL_PRESENT (0x0010)
+/*
+#define MY_SE_SACL_DEFAULTED (0x0020)
+#define MY_SE_DACL_AUTO_INHERIT_REQ (0x0100)
+#define MY_SE_SACL_AUTO_INHERIT_REQ (0x0200)
+#define MY_SE_DACL_AUTO_INHERITED (0x0400)
+#define MY_SE_SACL_AUTO_INHERITED (0x0800)
+#define MY_SE_DACL_PROTECTED (0x1000)
+#define MY_SE_SACL_PROTECTED (0x2000)
+#define MY_SE_RM_CONTROL_VALID (0x4000)
+#define MY_SE_SELF_RELATIVE (0x8000)
+*/
+
+void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s)
+{
+ s.Empty();
+ if (size < 20 || size > (1 << 18))
+ {
+ s += "ERROR";
+ return;
+ }
+ if (Get16(data) != 1) // revision
+ {
+ s += "UNSUPPORTED";
+ return;
+ }
+ ParseOwner(s, data, size, Get32(data + 4));
+ s.Add_Space();
+ ParseOwner(s, data, size, Get32(data + 8));
+ ParseAcl(s, data, size, "s:", MY_SE_SACL_PRESENT, 12);
+ ParseAcl(s, data, size, "d:", MY_SE_DACL_PRESENT, 16);
+ s.Add_Space();
+ s.Add_UInt32(size);
+ // s += '\n';
+ // s += Data_To_Hex(data, size);
+}
+
+#ifdef _WIN32
+
+static bool CheckSid(const Byte *data, UInt32 size, UInt32 pos) throw()
+{
+ if (pos >= size)
+ return false;
+ size -= pos;
+ if (size < 8)
+ return false;
+ const UInt32 rev = data[pos];
+ if (rev != 1)
+ return false;
+ const UInt32 num = data[pos + 1];
+ return (8 + num * 4 <= size);
+}
+
+static bool CheckAcl(const Byte *p, UInt32 size, UInt32 flags, UInt32 offset) throw()
+{
+ const UInt32 control = Get16(p + 2);
+ if ((flags & control) == 0)
+ return true;
+ const UInt32 pos = Get32(p + offset);
+ if (pos >= size)
+ return false;
+ p += pos;
+ size -= pos;
+ if (size < 8)
+ return false;
+ const UInt32 aclSize = Get16(p + 2);
+ return (aclSize <= size);
+}
+
+bool CheckNtSecure(const Byte *data, UInt32 size) throw()
+{
+ if (size < 20)
+ return false;
+ if (Get16(data) != 1) // revision
+ return true; // windows function can handle such error, so we allow it
+ if (size > (1 << 18))
+ return false;
+ if (!CheckSid(data, size, Get32(data + 4))) return false;
+ if (!CheckSid(data, size, Get32(data + 8))) return false;
+ if (!CheckAcl(data, size, MY_SE_SACL_PRESENT, 12)) return false;
+ if (!CheckAcl(data, size, MY_SE_DACL_PRESENT, 16)) return false;
+ return true;
+}
+
+#endif
+
+
+
+// IO_REPARSE_TAG_*
+
+static const CSecID2Name k_ReparseTags[] =
+{
+ { 0xA0000003, "MOUNT_POINT" },
+ { 0xC0000004, "HSM" },
+ { 0x80000005, "DRIVE_EXTENDER" },
+ { 0x80000006, "HSM2" },
+ { 0x80000007, "SIS" },
+ { 0x80000008, "WIM" },
+ { 0x80000009, "CSV" },
+ { 0x8000000A, "DFS" },
+ { 0x8000000B, "FILTER_MANAGER" },
+ { 0xA000000C, "SYMLINK" },
+ { 0xA0000010, "IIS_CACHE" },
+ { 0x80000012, "DFSR" },
+ { 0x80000013, "DEDUP" },
+ { 0xC0000014, "APPXSTRM" },
+ { 0x80000014, "NFS" },
+ { 0x80000015, "FILE_PLACEHOLDER" },
+ { 0x80000016, "DFM" },
+ { 0x80000017, "WOF" },
+ { 0x80000018, "WCI" },
+ { 0x8000001B, "APPEXECLINK" },
+ { 0xA000001D, "LX_SYMLINK" },
+ { 0x80000023, "AF_UNIX" },
+ { 0x80000024, "LX_FIFO" },
+ { 0x80000025, "LX_CHR" },
+ { 0x80000026, "LX_BLK" }
+};
+
+bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s)
+{
+ s.Empty();
+ NFile::CReparseAttr attr;
+
+ if (attr.Parse(data, size))
+ {
+ if (attr.IsSymLink_WSL())
+ {
+ s += "WSL: ";
+ s += attr.GetPath();
+ }
+ else
+ {
+ if (!attr.IsSymLink_Win())
+ s += "Junction: ";
+ s += attr.GetPath();
+ if (s.IsEmpty())
+ s += "Link: ";
+ if (!attr.IsOkNamePair())
+ {
+ s += " : ";
+ s += attr.PrintName;
+ }
+ }
+ if (attr.MinorError)
+ s += " : MINOR_ERROR";
+ return true;
+ // s += " "; // for debug
+ }
+
+ if (size < 8)
+ return false;
+ const UInt32 tag = Get32(data);
+ const UInt32 len = Get16(data + 4);
+ if (len + 8 > size)
+ return false;
+ if (Get16(data + 6) != 0) // padding
+ return false;
+
+ /*
+ #define my_IO_REPARSE_TAG_DEDUP (0x80000013L)
+ if (tag == my_IO_REPARSE_TAG_DEDUP)
+ {
+ }
+ */
+
+ {
+ const int index = FindPairIndex(k_ReparseTags, Z7_ARRAY_SIZE(k_ReparseTags), tag);
+ if (index >= 0)
+ s += k_ReparseTags[(unsigned)index].sz;
+ else
+ {
+ s += "REPARSE:";
+ char hex[16];
+ ConvertUInt32ToHex8Digits(tag, hex);
+ s += hex;
+ }
+ }
+
+ s += ":";
+ s.Add_UInt32(len);
+
+ if (len != 0)
+ {
+ s.Add_Space();
+
+ data += 8;
+
+ for (UInt32 i = 0; i < len; i++)
+ {
+ if (i >= 16)
+ {
+ s += "...";
+ break;
+ }
+ const unsigned b = data[i];
+ s += (char)GetHex((b >> 4) & 0xF);
+ s += (char)GetHex(b & 0xF);
+ }
+ }
+
+ return true;
+}
+
+#endif
diff --git a/CPP/7zip/UI/Common/PropIDUtils.h b/CPP/7zip/UI/Common/PropIDUtils.h
index e94e6d7..6df1e94 100644
--- a/CPP/7zip/UI/Common/PropIDUtils.h
+++ b/CPP/7zip/UI/Common/PropIDUtils.h
@@ -1,18 +1,18 @@
-// PropIDUtils.h
-
-#ifndef __PROPID_UTILS_H
-#define __PROPID_UTILS_H
-
-#include "../../../Common/MyString.h"
-
-// provide at least 64 bytes for buffer including zero-end
-void ConvertPropertyToShortString2(char *dest, const PROPVARIANT &propVariant, PROPID propID, int level = 0) throw();
-void ConvertPropertyToString2(UString &dest, const PROPVARIANT &propVariant, PROPID propID, int level = 0);
-
-bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s);
-void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s);
-bool CheckNtSecure(const Byte *data, UInt32 size) throw();;
-
-void ConvertWinAttribToString(char *s, UInt32 wa) throw();
-
-#endif
+// PropIDUtils.h
+
+#ifndef ZIP7_INC_PROPID_UTILS_H
+#define ZIP7_INC_PROPID_UTILS_H
+
+#include "../../../Common/MyString.h"
+
+// provide at least 64 bytes for buffer including zero-end
+void ConvertPropertyToShortString2(char *dest, const PROPVARIANT &propVariant, PROPID propID, int level = 0) throw();
+void ConvertPropertyToString2(UString &dest, const PROPVARIANT &propVariant, PROPID propID, int level = 0);
+
+bool ConvertNtReparseToString(const Byte *data, UInt32 size, UString &s);
+void ConvertNtSecureToString(const Byte *data, UInt32 size, AString &s);
+bool CheckNtSecure(const Byte *data, UInt32 size) throw();
+
+void ConvertWinAttribToString(char *s, UInt32 wa) throw();
+
+#endif
diff --git a/CPP/7zip/UI/Common/Property.h b/CPP/7zip/UI/Common/Property.h
index 31234ad..0462809 100644
--- a/CPP/7zip/UI/Common/Property.h
+++ b/CPP/7zip/UI/Common/Property.h
@@ -1,14 +1,14 @@
-// Property.h
-
-#ifndef __7Z_PROPERTY_H
-#define __7Z_PROPERTY_H
-
-#include "../../../Common/MyString.h"
-
-struct CProperty
-{
- UString Name;
- UString Value;
-};
-
-#endif
+// Property.h
+
+#ifndef ZIP7_INC_7Z_PROPERTY_H
+#define ZIP7_INC_7Z_PROPERTY_H
+
+#include "../../../Common/MyString.h"
+
+struct CProperty
+{
+ UString Name;
+ UString Value;
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/SetProperties.cpp b/CPP/7zip/UI/Common/SetProperties.cpp
index 3cd4d57..5e15d9c 100644
--- a/CPP/7zip/UI/Common/SetProperties.cpp
+++ b/CPP/7zip/UI/Common/SetProperties.cpp
@@ -1,80 +1,88 @@
-// SetProperties.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/MyCom.h"
-#include "../../../Common/MyString.h"
-#include "../../../Common/StringToInt.h"
-
-#include "../../../Windows/PropVariant.h"
-
-#include "../../Archive/IArchive.h"
-
-#include "SetProperties.h"
-
-using namespace NWindows;
-using namespace NCOM;
-
-static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop)
-{
- const wchar_t *end;
- UInt64 result = ConvertStringToUInt64(s, &end);
- if (*end != 0 || s.IsEmpty())
- prop = s;
- else if (result <= (UInt32)0xFFFFFFFF)
- prop = (UInt32)result;
- else
- prop = result;
-}
-
-HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties)
-{
- if (properties.IsEmpty())
- return S_OK;
- CMyComPtr<ISetProperties> setProperties;
- unknown->QueryInterface(IID_ISetProperties, (void **)&setProperties);
- if (!setProperties)
- return S_OK;
-
- UStringVector realNames;
- CPropVariant *values = new CPropVariant[properties.Size()];
- try
- {
- unsigned i;
- for (i = 0; i < properties.Size(); i++)
- {
- const CProperty &property = properties[i];
- NCOM::CPropVariant propVariant;
- UString name = property.Name;
- if (property.Value.IsEmpty())
- {
- if (!name.IsEmpty())
- {
- wchar_t c = name.Back();
- if (c == L'-')
- propVariant = false;
- else if (c == L'+')
- propVariant = true;
- if (propVariant.vt != VT_EMPTY)
- name.DeleteBack();
- }
- }
- else
- ParseNumberString(property.Value, propVariant);
- realNames.Add(name);
- values[i] = propVariant;
- }
- CRecordVector<const wchar_t *> names;
- for (i = 0; i < realNames.Size(); i++)
- names.Add((const wchar_t *)realNames[i]);
-
- RINOK(setProperties->SetProperties(&names.Front(), values, names.Size()));
- }
- catch(...)
- {
- delete []values;
- throw;
- }
- delete []values;
- return S_OK;
-}
+// SetProperties.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyString.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "SetProperties.h"
+
+using namespace NWindows;
+using namespace NCOM;
+
+static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop)
+{
+ const wchar_t *end;
+ const UInt64 result = ConvertStringToUInt64(s, &end);
+ if (*end != 0 || s.IsEmpty())
+ prop = s;
+ else if (result <= (UInt32)0xFFFFFFFF)
+ prop = (UInt32)result;
+ else
+ prop = result;
+}
+
+
+struct CPropPropetiesVector
+{
+ CPropVariant *values;
+ CPropPropetiesVector(unsigned num)
+ {
+ values = new CPropVariant[num];
+ }
+ ~CPropPropetiesVector()
+ {
+ delete []values;
+ }
+};
+
+
+HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties)
+{
+ if (properties.IsEmpty())
+ return S_OK;
+ Z7_DECL_CMyComPtr_QI_FROM(
+ ISetProperties,
+ setProperties, unknown)
+ if (!setProperties)
+ return S_OK;
+
+ UStringVector realNames;
+ CPropPropetiesVector values(properties.Size());
+ {
+ unsigned i;
+ for (i = 0; i < properties.Size(); i++)
+ {
+ const CProperty &property = properties[i];
+ NCOM::CPropVariant propVariant;
+ UString name = property.Name;
+ if (property.Value.IsEmpty())
+ {
+ if (!name.IsEmpty())
+ {
+ const wchar_t c = name.Back();
+ if (c == L'-')
+ propVariant = false;
+ else if (c == L'+')
+ propVariant = true;
+ if (propVariant.vt != VT_EMPTY)
+ name.DeleteBack();
+ }
+ }
+ else
+ ParseNumberString(property.Value, propVariant);
+ realNames.Add(name);
+ values.values[i] = propVariant;
+ }
+ CRecordVector<const wchar_t *> names;
+ for (i = 0; i < realNames.Size(); i++)
+ names.Add((const wchar_t *)realNames[i]);
+
+ return setProperties->SetProperties(&names.Front(), values.values, names.Size());
+ }
+}
diff --git a/CPP/7zip/UI/Common/SetProperties.h b/CPP/7zip/UI/Common/SetProperties.h
index 64c947c..0676c45 100644
--- a/CPP/7zip/UI/Common/SetProperties.h
+++ b/CPP/7zip/UI/Common/SetProperties.h
@@ -1,10 +1,10 @@
-// SetProperties.h
-
-#ifndef __SETPROPERTIES_H
-#define __SETPROPERTIES_H
-
-#include "Property.h"
-
-HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties);
-
-#endif
+// SetProperties.h
+
+#ifndef ZIP7_INC_SETPROPERTIES_H
+#define ZIP7_INC_SETPROPERTIES_H
+
+#include "Property.h"
+
+HRESULT SetProperties(IUnknown *unknown, const CObjectVector<CProperty> &properties);
+
+#endif
diff --git a/CPP/7zip/UI/Common/SortUtils.cpp b/CPP/7zip/UI/Common/SortUtils.cpp
index f73ece8..5f29249 100644
--- a/CPP/7zip/UI/Common/SortUtils.cpp
+++ b/CPP/7zip/UI/Common/SortUtils.cpp
@@ -1,25 +1,25 @@
-// SortUtils.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/Wildcard.h"
-
-#include "SortUtils.h"
-
-static int CompareStrings(const unsigned *p1, const unsigned *p2, void *param)
-{
- const UStringVector &strings = *(const UStringVector *)param;
- return CompareFileNames(strings[*p1], strings[*p2]);
-}
-
-void SortFileNames(const UStringVector &strings, CUIntVector &indices)
-{
- const unsigned numItems = strings.Size();
- indices.ClearAndSetSize(numItems);
- if (numItems == 0)
- return;
- unsigned *vals = &indices[0];
- for (unsigned i = 0; i < numItems; i++)
- vals[i] = i;
- indices.Sort(CompareStrings, (void *)&strings);
-}
+// SortUtils.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/Wildcard.h"
+
+#include "SortUtils.h"
+
+static int CompareStrings(const unsigned *p1, const unsigned *p2, void *param)
+{
+ const UStringVector &strings = *(const UStringVector *)param;
+ return CompareFileNames(strings[*p1], strings[*p2]);
+}
+
+void SortFileNames(const UStringVector &strings, CUIntVector &indices)
+{
+ const unsigned numItems = strings.Size();
+ indices.ClearAndSetSize(numItems);
+ if (numItems == 0)
+ return;
+ unsigned *vals = &indices[0];
+ for (unsigned i = 0; i < numItems; i++)
+ vals[i] = i;
+ indices.Sort(CompareStrings, (void *)&strings);
+}
diff --git a/CPP/7zip/UI/Common/SortUtils.h b/CPP/7zip/UI/Common/SortUtils.h
index 82d5e4c..07aa24d 100644
--- a/CPP/7zip/UI/Common/SortUtils.h
+++ b/CPP/7zip/UI/Common/SortUtils.h
@@ -1,10 +1,10 @@
-// SortUtils.h
-
-#ifndef __SORT_UTLS_H
-#define __SORT_UTLS_H
-
-#include "../../../Common/MyString.h"
-
-void SortFileNames(const UStringVector &strings, CUIntVector &indices);
-
-#endif
+// SortUtils.h
+
+#ifndef ZIP7_INC_SORT_UTLS_H
+#define ZIP7_INC_SORT_UTLS_H
+
+#include "../../../Common/MyString.h"
+
+void SortFileNames(const UStringVector &strings, CUIntVector &indices);
+
+#endif
diff --git a/CPP/7zip/UI/Common/StdAfx.h b/CPP/7zip/UI/Common/StdAfx.h
index 59d9ac1..035267c 100644
--- a/CPP/7zip/UI/Common/StdAfx.h
+++ b/CPP/7zip/UI/Common/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "../../../Common/Common.h"
-
-#endif
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/UI/Common/TempFiles.cpp b/CPP/7zip/UI/Common/TempFiles.cpp
index 56bba9a..2f86838 100644
--- a/CPP/7zip/UI/Common/TempFiles.cpp
+++ b/CPP/7zip/UI/Common/TempFiles.cpp
@@ -1,19 +1,19 @@
-// TempFiles.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Windows/FileDir.h"
-
-#include "TempFiles.h"
-
-using namespace NWindows;
-using namespace NFile;
-
-void CTempFiles::Clear()
-{
- while (!Paths.IsEmpty())
- {
- NDir::DeleteFileAlways(Paths.Back());
- Paths.DeleteBack();
- }
-}
+// TempFiles.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Windows/FileDir.h"
+
+#include "TempFiles.h"
+
+using namespace NWindows;
+using namespace NFile;
+
+void CTempFiles::Clear()
+{
+ while (!Paths.IsEmpty())
+ {
+ NDir::DeleteFileAlways(Paths.Back());
+ Paths.DeleteBack();
+ }
+}
diff --git a/CPP/7zip/UI/Common/TempFiles.h b/CPP/7zip/UI/Common/TempFiles.h
index f62192d..dd4ac20 100644
--- a/CPP/7zip/UI/Common/TempFiles.h
+++ b/CPP/7zip/UI/Common/TempFiles.h
@@ -1,16 +1,16 @@
-// TempFiles.h
-
-#ifndef __TEMP_FILES_H
-#define __TEMP_FILES_H
-
-#include "../../../Common/MyString.h"
-
-class CTempFiles
-{
- void Clear();
-public:
- FStringVector Paths;
- ~CTempFiles() { Clear(); }
-};
-
-#endif
+// TempFiles.h
+
+#ifndef ZIP7_INC_TEMP_FILES_H
+#define ZIP7_INC_TEMP_FILES_H
+
+#include "../../../Common/MyString.h"
+
+class CTempFiles
+{
+ void Clear();
+public:
+ FStringVector Paths;
+ ~CTempFiles() { Clear(); }
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/Update.cpp b/CPP/7zip/UI/Common/Update.cpp
index 2f1b365..27625ae 100644
--- a/CPP/7zip/UI/Common/Update.cpp
+++ b/CPP/7zip/UI/Common/Update.cpp
@@ -1,1704 +1,1857 @@
-// Update.cpp
-
-#include "StdAfx.h"
-
-#include "Update.h"
-
-#include "../../../Common/StringConvert.h"
-
-#include "../../../Windows/DLL.h"
-#include "../../../Windows/FileDir.h"
-#include "../../../Windows/FileFind.h"
-#include "../../../Windows/FileName.h"
-#include "../../../Windows/PropVariant.h"
-#include "../../../Windows/PropVariantConv.h"
-#include "../../../Windows/TimeUtils.h"
-
-#include "../../Common/FileStreams.h"
-#include "../../Common/LimitedStreams.h"
-
-#include "../../Compress/CopyCoder.h"
-
-#include "../Common/DirItem.h"
-#include "../Common/EnumDirItems.h"
-#include "../Common/OpenArchive.h"
-#include "../Common/UpdateProduce.h"
-
-#include "EnumDirItems.h"
-#include "SetProperties.h"
-#include "TempFiles.h"
-#include "UpdateCallback.h"
-
-static const char * const kUpdateIsNotSupoorted =
- "update operations are not supported for this archive";
-
-static const char * const kUpdateIsNotSupoorted_MultiVol =
- "Updating for multivolume archives is not implemented";
-
-using namespace NWindows;
-using namespace NCOM;
-using namespace NFile;
-using namespace NDir;
-using namespace NName;
-
-static CFSTR const kTempFolderPrefix = FTEXT("7zE");
-
-
-void CUpdateErrorInfo::SetFromLastError(const char *message)
-{
- SystemError = ::GetLastError();
- Message = message;
-}
-
-HRESULT CUpdateErrorInfo::SetFromLastError(const char *message, const FString &fileName)
-{
- SetFromLastError(message);
- FileNames.Add(fileName);
- return Get_HRESULT_Error();
-}
-
-static bool DeleteEmptyFolderAndEmptySubFolders(const FString &path)
-{
- NFind::CFileInfo fileInfo;
- FString pathPrefix = path + FCHAR_PATH_SEPARATOR;
- {
- NFind::CEnumerator enumerator;
- enumerator.SetDirPrefix(pathPrefix);
- while (enumerator.Next(fileInfo))
- {
- if (fileInfo.IsDir())
- if (!DeleteEmptyFolderAndEmptySubFolders(pathPrefix + fileInfo.Name))
- return false;
- }
- }
- /*
- // we don't need clear read-only for folders
- if (!MySetFileAttributes(path, 0))
- return false;
- */
- return RemoveDir(path);
-}
-
-
-using namespace NUpdateArchive;
-
-class COutMultiVolStream:
- public IOutStream,
- public CMyUnknownImp
-{
- unsigned _streamIndex; // required stream
- UInt64 _offsetPos; // offset from start of _streamIndex index
- UInt64 _absPos;
- UInt64 _length;
-
- struct CAltStreamInfo
- {
- COutFileStream *StreamSpec;
- CMyComPtr<IOutStream> Stream;
- FString Name;
- UInt64 Pos;
- UInt64 RealSize;
- };
- CObjectVector<CAltStreamInfo> Streams;
-public:
- // CMyComPtr<IArchiveUpdateCallback2> VolumeCallback;
- CRecordVector<UInt64> Sizes;
- FString Prefix;
- CTempFiles *TempFiles;
-
- void Init()
- {
- _streamIndex = 0;
- _offsetPos = 0;
- _absPos = 0;
- _length = 0;
- }
-
- bool SetMTime(const FILETIME *mTime);
- HRESULT Close();
-
- UInt64 GetSize() const { return _length; }
-
- MY_UNKNOWN_IMP1(IOutStream)
-
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
- STDMETHOD(Seek)(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition);
- STDMETHOD(SetSize)(UInt64 newSize);
-};
-
-// static NSynchronization::CCriticalSection g_TempPathsCS;
-
-HRESULT COutMultiVolStream::Close()
-{
- HRESULT res = S_OK;
- FOR_VECTOR (i, Streams)
- {
- COutFileStream *s = Streams[i].StreamSpec;
- if (s)
- {
- HRESULT res2 = s->Close();
- if (res2 != S_OK)
- res = res2;
- }
- }
- return res;
-}
-
-bool COutMultiVolStream::SetMTime(const FILETIME *mTime)
-{
- bool res = true;
- FOR_VECTOR (i, Streams)
- {
- COutFileStream *s = Streams[i].StreamSpec;
- if (s)
- if (!s->SetMTime(mTime))
- res = false;
- }
- return res;
-}
-
-STDMETHODIMP COutMultiVolStream::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
- while (size > 0)
- {
- if (_streamIndex >= Streams.Size())
- {
- CAltStreamInfo altStream;
-
- FString name;
- name.Add_UInt32(_streamIndex + 1);
- while (name.Len() < 3)
- name.InsertAtFront(FTEXT('0'));
- name.Insert(0, Prefix);
- altStream.StreamSpec = new COutFileStream;
- altStream.Stream = altStream.StreamSpec;
- if (!altStream.StreamSpec->Create(name, false))
- return ::GetLastError();
- {
- // NSynchronization::CCriticalSectionLock lock(g_TempPathsCS);
- TempFiles->Paths.Add(name);
- }
-
- altStream.Pos = 0;
- altStream.RealSize = 0;
- altStream.Name = name;
- Streams.Add(altStream);
- continue;
- }
- CAltStreamInfo &altStream = Streams[_streamIndex];
-
- unsigned index = _streamIndex;
- if (index >= Sizes.Size())
- index = Sizes.Size() - 1;
- UInt64 volSize = Sizes[index];
-
- if (_offsetPos >= volSize)
- {
- _offsetPos -= volSize;
- _streamIndex++;
- continue;
- }
- if (_offsetPos != altStream.Pos)
- {
- // CMyComPtr<IOutStream> outStream;
- // RINOK(altStream.Stream.QueryInterface(IID_IOutStream, &outStream));
- RINOK(altStream.Stream->Seek(_offsetPos, STREAM_SEEK_SET, NULL));
- altStream.Pos = _offsetPos;
- }
-
- UInt32 curSize = (UInt32)MyMin((UInt64)size, volSize - altStream.Pos);
- UInt32 realProcessed;
- RINOK(altStream.Stream->Write(data, curSize, &realProcessed));
- data = (void *)((Byte *)data + realProcessed);
- size -= realProcessed;
- altStream.Pos += realProcessed;
- _offsetPos += realProcessed;
- _absPos += realProcessed;
- if (_absPos > _length)
- _length = _absPos;
- if (_offsetPos > altStream.RealSize)
- altStream.RealSize = _offsetPos;
- if (processedSize)
- *processedSize += realProcessed;
- if (altStream.Pos == volSize)
- {
- _streamIndex++;
- _offsetPos = 0;
- }
- if (realProcessed == 0 && curSize != 0)
- return E_FAIL;
- break;
- }
- return S_OK;
-}
-
-STDMETHODIMP COutMultiVolStream::Seek(Int64 offset, UInt32 seekOrigin, UInt64 *newPosition)
-{
- if (seekOrigin >= 3)
- return STG_E_INVALIDFUNCTION;
- switch (seekOrigin)
- {
- case STREAM_SEEK_SET: _absPos = offset; break;
- case STREAM_SEEK_CUR: _absPos += offset; break;
- case STREAM_SEEK_END: _absPos = _length + offset; break;
- }
- _offsetPos = _absPos;
- if (newPosition)
- *newPosition = _absPos;
- _streamIndex = 0;
- return S_OK;
-}
-
-STDMETHODIMP COutMultiVolStream::SetSize(UInt64 newSize)
-{
- unsigned i = 0;
- while (i < Streams.Size())
- {
- CAltStreamInfo &altStream = Streams[i++];
- if ((UInt64)newSize < altStream.RealSize)
- {
- RINOK(altStream.Stream->SetSize(newSize));
- altStream.RealSize = newSize;
- break;
- }
- newSize -= altStream.RealSize;
- }
- while (i < Streams.Size())
- {
- {
- CAltStreamInfo &altStream = Streams.Back();
- altStream.Stream.Release();
- DeleteFileAlways(altStream.Name);
- }
- Streams.DeleteBack();
- }
- _offsetPos = _absPos;
- _streamIndex = 0;
- _length = newSize;
- return S_OK;
-}
-
-void CArchivePath::ParseFromPath(const UString &path, EArcNameMode mode)
-{
- OriginalPath = path;
-
- SplitPathToParts_2(path, Prefix, Name);
-
- if (mode == k_ArcNameMode_Add)
- return;
-
- if (mode != k_ArcNameMode_Exact)
- {
- int dotPos = Name.ReverseFind_Dot();
- if (dotPos < 0)
- return;
- if ((unsigned)dotPos == Name.Len() - 1)
- Name.DeleteBack();
- else
- {
- const UString ext = Name.Ptr(dotPos + 1);
- if (BaseExtension.IsEqualTo_NoCase(ext))
- {
- BaseExtension = ext;
- Name.DeleteFrom(dotPos);
- return;
- }
- }
- }
-
- BaseExtension.Empty();
-}
-
-UString CArchivePath::GetFinalPath() const
-{
- UString path = GetPathWithoutExt();
- if (!BaseExtension.IsEmpty())
- {
- path += '.';
- path += BaseExtension;
- }
- return path;
-}
-
-UString CArchivePath::GetFinalVolPath() const
-{
- UString path = GetPathWithoutExt();
- // if BaseExtension is empty, we must ignore VolExtension also.
- if (!BaseExtension.IsEmpty())
- {
- path += '.';
- path += VolExtension;
- }
- return path;
-}
-
-FString CArchivePath::GetTempPath() const
-{
- FString path = TempPrefix;
- path += us2fs(Name);
- if (!BaseExtension.IsEmpty())
- {
- path += '.';
- path += us2fs(BaseExtension);
- }
- path += ".tmp";
- path += TempPostfix;
- return path;
-}
-
-static const char * const kDefaultArcType = "7z";
-static const char * const kDefaultArcExt = "7z";
-static const char * const kSFXExtension =
- #ifdef _WIN32
- "exe";
- #else
- "";
- #endif
-
-bool CUpdateOptions::InitFormatIndex(const CCodecs *codecs,
- const CObjectVector<COpenType> &types, const UString &arcPath)
-{
- if (types.Size() > 1)
- return false;
- // int arcTypeIndex = -1;
- if (types.Size() != 0)
- {
- MethodMode.Type = types[0];
- MethodMode.Type_Defined = true;
- }
- if (MethodMode.Type.FormatIndex < 0)
- {
- // MethodMode.Type = -1;
- MethodMode.Type = COpenType();
- if (ArcNameMode != k_ArcNameMode_Add)
- {
- MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveName(arcPath);
- if (MethodMode.Type.FormatIndex >= 0)
- MethodMode.Type_Defined = true;
- }
- }
- return true;
-}
-
-bool CUpdateOptions::SetArcPath(const CCodecs *codecs, const UString &arcPath)
-{
- UString typeExt;
- int formatIndex = MethodMode.Type.FormatIndex;
- if (formatIndex < 0)
- {
- typeExt = kDefaultArcExt;
- }
- else
- {
- const CArcInfoEx &arcInfo = codecs->Formats[formatIndex];
- if (!arcInfo.UpdateEnabled)
- return false;
- typeExt = arcInfo.GetMainExt();
- }
- UString ext = typeExt;
- if (SfxMode)
- ext = kSFXExtension;
- ArchivePath.BaseExtension = ext;
- ArchivePath.VolExtension = typeExt;
- ArchivePath.ParseFromPath(arcPath, ArcNameMode);
- FOR_VECTOR (i, Commands)
- {
- CUpdateArchiveCommand &uc = Commands[i];
- uc.ArchivePath.BaseExtension = ext;
- uc.ArchivePath.VolExtension = typeExt;
- uc.ArchivePath.ParseFromPath(uc.UserArchivePath, ArcNameMode);
- }
- return true;
-}
-
-
-struct CUpdateProduceCallbackImp: public IUpdateProduceCallback
-{
- const CObjectVector<CArcItem> *_arcItems;
- IUpdateCallbackUI *_callback;
- CDirItemsStat *_stat;
-
- CUpdateProduceCallbackImp(
- const CObjectVector<CArcItem> *a,
- CDirItemsStat *stat,
- IUpdateCallbackUI *callback):
- _arcItems(a),
- _stat(stat),
- _callback(callback) {}
-
- virtual HRESULT ShowDeleteFile(unsigned arcIndex);
-};
-
-
-HRESULT CUpdateProduceCallbackImp::ShowDeleteFile(unsigned arcIndex)
-{
- const CArcItem &ai = (*_arcItems)[arcIndex];
- {
- CDirItemsStat &stat = *_stat;
- if (ai.IsDir)
- stat.NumDirs++;
- else if (ai.IsAltStream)
- {
- stat.NumAltStreams++;
- stat.AltStreamsSize += ai.Size;
- }
- else
- {
- stat.NumFiles++;
- stat.FilesSize += ai.Size;
- }
- }
- return _callback->ShowDeleteFile(ai.Name, ai.IsDir);
-}
-
-bool CRenamePair::Prepare()
-{
- if (RecursedType != NRecursedType::kNonRecursed)
- return false;
- if (!WildcardParsing)
- return true;
- return !DoesNameContainWildcard(OldName);
-}
-
-extern bool g_CaseSensitive;
-
-static unsigned CompareTwoNames(const wchar_t *s1, const wchar_t *s2)
-{
- for (unsigned i = 0;; i++)
- {
- wchar_t c1 = s1[i];
- wchar_t c2 = s2[i];
- if (c1 == 0 || c2 == 0)
- return i;
- if (c1 == c2)
- continue;
- if (!g_CaseSensitive && (MyCharUpper(c1) == MyCharUpper(c2)))
- continue;
- if (IsPathSepar(c1) && IsPathSepar(c2))
- continue;
- return i;
- }
-}
-
-bool CRenamePair::GetNewPath(bool isFolder, const UString &src, UString &dest) const
-{
- unsigned num = CompareTwoNames(OldName, src);
- if (OldName[num] == 0)
- {
- if (src[num] != 0 && !IsPathSepar(src[num]) && num != 0 && !IsPathSepar(src[num - 1]))
- return false;
- }
- else
- {
- // OldName[num] != 0
- // OldName = "1\1a.txt"
- // src = "1"
-
- if (!isFolder
- || src[num] != 0
- || !IsPathSepar(OldName[num])
- || OldName[num + 1] != 0)
- return false;
- }
- dest = NewName + src.Ptr(num);
- return true;
-}
-
-#ifdef SUPPORT_ALT_STREAMS
-int FindAltStreamColon_in_Path(const wchar_t *path);
-#endif
-
-static HRESULT Compress(
- const CUpdateOptions &options,
- bool isUpdatingItself,
- CCodecs *codecs,
- const CActionSet &actionSet,
- const CArc *arc,
- CArchivePath &archivePath,
- const CObjectVector<CArcItem> &arcItems,
- Byte *processedItemsStatuses,
- const CDirItems &dirItems,
- const CDirItem *parentDirItem,
- CTempFiles &tempFiles,
- CUpdateErrorInfo &errorInfo,
- IUpdateCallbackUI *callback,
- CFinishArchiveStat &st)
-{
- CMyComPtr<IOutArchive> outArchive;
- int formatIndex = options.MethodMode.Type.FormatIndex;
-
- if (arc)
- {
- formatIndex = arc->FormatIndex;
- if (formatIndex < 0)
- return E_NOTIMPL;
- CMyComPtr<IInArchive> archive2 = arc->Archive;
- HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive);
- if (result != S_OK)
- throw kUpdateIsNotSupoorted;
- }
- else
- {
- RINOK(codecs->CreateOutArchive(formatIndex, outArchive));
-
- #ifdef EXTERNAL_CODECS
- {
- CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
- outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
- if (setCompressCodecsInfo)
- {
- RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs));
- }
- }
- #endif
- }
-
- if (outArchive == 0)
- throw kUpdateIsNotSupoorted;
-
- NFileTimeType::EEnum fileTimeType;
- {
- UInt32 value;
- RINOK(outArchive->GetFileTimeType(&value));
-
- switch (value)
- {
- case NFileTimeType::kWindows:
- case NFileTimeType::kUnix:
- case NFileTimeType::kDOS:
- fileTimeType = (NFileTimeType::EEnum)value;
- break;
- default:
- return E_FAIL;
- }
- }
-
- {
- const CArcInfoEx &arcInfo = codecs->Formats[formatIndex];
- if (options.AltStreams.Val && !arcInfo.Flags_AltStreams())
- return E_NOTIMPL;
- if (options.NtSecurity.Val && !arcInfo.Flags_NtSecure())
- return E_NOTIMPL;
- }
-
- CRecordVector<CUpdatePair2> updatePairs2;
-
- UStringVector newNames;
-
- CArcToDoStat stat2;
-
- if (options.RenamePairs.Size() != 0)
- {
- FOR_VECTOR (i, arcItems)
- {
- const CArcItem &ai = arcItems[i];
- bool needRename = false;
- UString dest;
-
- if (ai.Censored)
- {
- FOR_VECTOR (j, options.RenamePairs)
- {
- const CRenamePair &rp = options.RenamePairs[j];
- if (rp.GetNewPath(ai.IsDir, ai.Name, dest))
- {
- needRename = true;
- break;
- }
-
- #ifdef SUPPORT_ALT_STREAMS
- if (ai.IsAltStream)
- {
- int colonPos = FindAltStreamColon_in_Path(ai.Name);
- if (colonPos >= 0)
- {
- UString mainName = ai.Name.Left(colonPos);
- /*
- actually we must improve that code to support cases
- with folder renaming like: rn arc dir1\ dir2\
- */
- if (rp.GetNewPath(false, mainName, dest))
- {
- needRename = true;
- dest += ':';
- dest += ai.Name.Ptr(colonPos + 1);
- break;
- }
- }
- }
- #endif
- }
- }
-
- CUpdatePair2 up2;
- up2.SetAs_NoChangeArcItem(ai.IndexInServer);
- if (needRename)
- {
- up2.NewProps = true;
- RINOK(arc->IsItemAnti(i, up2.IsAnti));
- up2.NewNameIndex = newNames.Add(dest);
- }
- updatePairs2.Add(up2);
- }
- }
- else
- {
- CRecordVector<CUpdatePair> updatePairs;
- GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs); // must be done only once!!!
- CUpdateProduceCallbackImp upCallback(&arcItems, &stat2.DeleteData, callback);
-
- UpdateProduce(updatePairs, actionSet, updatePairs2, isUpdatingItself ? &upCallback : NULL);
- }
-
- {
- FOR_VECTOR (i, updatePairs2)
- {
- const CUpdatePair2 &up = updatePairs2[i];
-
- // 17.01: anti-item is (up.NewData && (p.UseArcProps in most cases))
-
- if (up.NewData && !up.UseArcProps)
- {
- if (up.ExistOnDisk())
- {
- CDirItemsStat2 &stat = stat2.NewData;
- const CDirItem &di = dirItems.Items[up.DirIndex];
- if (di.IsDir())
- {
- if (up.IsAnti)
- stat.Anti_NumDirs++;
- else
- stat.NumDirs++;
- }
- else if (di.IsAltStream)
- {
- if (up.IsAnti)
- stat.Anti_NumAltStreams++;
- else
- {
- stat.NumAltStreams++;
- stat.AltStreamsSize += di.Size;
- }
- }
- else
- {
- if (up.IsAnti)
- stat.Anti_NumFiles++;
- else
- {
- stat.NumFiles++;
- stat.FilesSize += di.Size;
- }
- }
- }
- }
- else if (up.ArcIndex >= 0)
- {
- CDirItemsStat2 &stat = *(up.NewData ? &stat2.NewData : &stat2.OldData);
- const CArcItem &ai = arcItems[up.ArcIndex];
- if (ai.IsDir)
- {
- if (up.IsAnti)
- stat.Anti_NumDirs++;
- else
- stat.NumDirs++;
- }
- else if (ai.IsAltStream)
- {
- if (up.IsAnti)
- stat.Anti_NumAltStreams++;
- else
- {
- stat.NumAltStreams++;
- stat.AltStreamsSize += ai.Size;
- }
- }
- else
- {
- if (up.IsAnti)
- stat.Anti_NumFiles++;
- else
- {
- stat.NumFiles++;
- stat.FilesSize += ai.Size;
- }
- }
- }
- }
- RINOK(callback->SetNumItems(stat2));
- }
-
- CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
- CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
-
- updateCallbackSpec->ShareForWrite = options.OpenShareForWrite;
- updateCallbackSpec->StopAfterOpenError = options.StopAfterOpenError;
- updateCallbackSpec->StdInMode = options.StdInMode;
- updateCallbackSpec->Callback = callback;
-
- if (arc)
- {
- // we set Archive to allow to transfer GetProperty requests back to DLL.
- updateCallbackSpec->Archive = arc->Archive;
- }
-
- updateCallbackSpec->DirItems = &dirItems;
- updateCallbackSpec->ParentDirItem = parentDirItem;
-
- updateCallbackSpec->StoreNtSecurity = options.NtSecurity.Val;
- updateCallbackSpec->StoreHardLinks = options.HardLinks.Val;
- updateCallbackSpec->StoreSymLinks = options.SymLinks.Val;
-
- updateCallbackSpec->Arc = arc;
- updateCallbackSpec->ArcItems = &arcItems;
- updateCallbackSpec->UpdatePairs = &updatePairs2;
-
- updateCallbackSpec->ProcessedItemsStatuses = processedItemsStatuses;
-
- if (options.RenamePairs.Size() != 0)
- updateCallbackSpec->NewNames = &newNames;
-
- CMyComPtr<IOutStream> outSeekStream;
- CMyComPtr<ISequentialOutStream> outStream;
-
- if (!options.StdOutMode)
- {
- FString dirPrefix;
- if (!GetOnlyDirPrefix(us2fs(archivePath.GetFinalPath()), dirPrefix))
- throw 1417161;
- CreateComplexDir(dirPrefix);
- }
-
- COutFileStream *outStreamSpec = NULL;
- CStdOutFileStream *stdOutFileStreamSpec = NULL;
- COutMultiVolStream *volStreamSpec = NULL;
-
- if (options.VolumesSizes.Size() == 0)
- {
- if (options.StdOutMode)
- {
- stdOutFileStreamSpec = new CStdOutFileStream;
- outStream = stdOutFileStreamSpec;
- }
- else
- {
- outStreamSpec = new COutFileStream;
- outSeekStream = outStreamSpec;
- outStream = outSeekStream;
- bool isOK = false;
- FString realPath;
-
- for (unsigned i = 0; i < (1 << 16); i++)
- {
- if (archivePath.Temp)
- {
- if (i > 0)
- {
- archivePath.TempPostfix.Empty();
- archivePath.TempPostfix.Add_UInt32(i);
- }
- realPath = archivePath.GetTempPath();
- }
- else
- realPath = us2fs(archivePath.GetFinalPath());
- if (outStreamSpec->Create(realPath, false))
- {
- tempFiles.Paths.Add(realPath);
- isOK = true;
- break;
- }
- if (::GetLastError() != ERROR_FILE_EXISTS)
- break;
- if (!archivePath.Temp)
- break;
- }
-
- if (!isOK)
- return errorInfo.SetFromLastError("cannot open file", realPath);
- }
- }
- else
- {
- if (options.StdOutMode)
- return E_FAIL;
- if (arc && arc->GetGlobalOffset() > 0)
- return E_NOTIMPL;
-
- volStreamSpec = new COutMultiVolStream;
- outSeekStream = volStreamSpec;
- outStream = outSeekStream;
- volStreamSpec->Sizes = options.VolumesSizes;
- volStreamSpec->Prefix = us2fs(archivePath.GetFinalVolPath());
- volStreamSpec->Prefix += '.';
- volStreamSpec->TempFiles = &tempFiles;
- volStreamSpec->Init();
-
- /*
- updateCallbackSpec->VolumesSizes = volumesSizes;
- updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name;
- if (!archivePath.VolExtension.IsEmpty())
- updateCallbackSpec->VolExt = UString('.') + archivePath.VolExtension;
- */
- }
-
- RINOK(SetProperties(outArchive, options.MethodMode.Properties));
-
- if (options.SfxMode)
- {
- CInFileStream *sfxStreamSpec = new CInFileStream;
- CMyComPtr<IInStream> sfxStream(sfxStreamSpec);
- if (!sfxStreamSpec->Open(options.SfxModule))
- return errorInfo.SetFromLastError("cannot open SFX module", options.SfxModule);
-
- CMyComPtr<ISequentialOutStream> sfxOutStream;
- COutFileStream *outStreamSpec2 = NULL;
- if (options.VolumesSizes.Size() == 0)
- sfxOutStream = outStream;
- else
- {
- outStreamSpec2 = new COutFileStream;
- sfxOutStream = outStreamSpec2;
- FString realPath = us2fs(archivePath.GetFinalPath());
- if (!outStreamSpec2->Create(realPath, false))
- return errorInfo.SetFromLastError("cannot open file", realPath);
- }
-
- {
- UInt64 sfxSize;
- RINOK(sfxStreamSpec->GetSize(&sfxSize));
- RINOK(callback->WriteSfx(fs2us(options.SfxModule), sfxSize));
- }
-
- RINOK(NCompress::CopyStream(sfxStream, sfxOutStream, NULL));
-
- if (outStreamSpec2)
- {
- RINOK(outStreamSpec2->Close());
- }
- }
-
- CMyComPtr<ISequentialOutStream> tailStream;
-
- if (options.SfxMode || !arc || arc->ArcStreamOffset == 0)
- tailStream = outStream;
- else
- {
- // Int64 globalOffset = arc->GetGlobalOffset();
- RINOK(arc->InStream->Seek(0, STREAM_SEEK_SET, NULL));
- RINOK(NCompress::CopyStream_ExactSize(arc->InStream, outStream, arc->ArcStreamOffset, NULL));
- if (options.StdOutMode)
- tailStream = outStream;
- else
- {
- CTailOutStream *tailStreamSpec = new CTailOutStream;
- tailStream = tailStreamSpec;
- tailStreamSpec->Stream = outSeekStream;
- tailStreamSpec->Offset = arc->ArcStreamOffset;
- tailStreamSpec->Init();
- }
- }
-
-
- HRESULT result = outArchive->UpdateItems(tailStream, updatePairs2.Size(), updateCallback);
- // callback->Finalize();
- RINOK(result);
-
- if (!updateCallbackSpec->AreAllFilesClosed())
- {
- errorInfo.Message = "There are unclosed input file:";
- errorInfo.FileNames = updateCallbackSpec->_openFiles_Paths;
- return E_FAIL;
- }
-
- if (options.SetArcMTime)
- {
- FILETIME ft;
- ft.dwLowDateTime = 0;
- ft.dwHighDateTime = 0;
- FOR_VECTOR (i, updatePairs2)
- {
- CUpdatePair2 &pair2 = updatePairs2[i];
- const FILETIME *ft2 = NULL;
- if (pair2.NewProps && pair2.DirIndex >= 0)
- ft2 = &dirItems.Items[pair2.DirIndex].MTime;
- else if (pair2.UseArcProps && pair2.ArcIndex >= 0)
- ft2 = &arcItems[pair2.ArcIndex].MTime;
- if (ft2)
- {
- if (::CompareFileTime(&ft, ft2) < 0)
- ft = *ft2;
- }
- }
- if (ft.dwLowDateTime != 0 || ft.dwHighDateTime != 0)
- {
- if (outStreamSpec)
- outStreamSpec->SetMTime(&ft);
- else if (volStreamSpec)
- volStreamSpec->SetMTime(&ft);;
- }
- }
-
- if (callback)
- {
- UInt64 size = 0;
- if (outStreamSpec)
- outStreamSpec->GetSize(&size);
- else if (stdOutFileStreamSpec)
- size = stdOutFileStreamSpec->GetSize();
- else
- size = volStreamSpec->GetSize();
-
- st.OutArcFileSize = size;
- }
-
- if (outStreamSpec)
- result = outStreamSpec->Close();
- else if (volStreamSpec)
- result = volStreamSpec->Close();
- return result;
-}
-
-bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include);
-
-static bool Censor_CheckPath(const NWildcard::CCensor &censor, const CReadArcItem &item)
-{
- bool finded = false;
- FOR_VECTOR (i, censor.Pairs)
- {
- bool include;
- if (CensorNode_CheckPath2(censor.Pairs[i].Head, item, include))
- {
- if (!include)
- return false;
- finded = true;
- }
- }
- return finded;
-}
-
-static HRESULT EnumerateInArchiveItems(
- // bool storeStreamsMode,
- const NWildcard::CCensor &censor,
- const CArc &arc,
- CObjectVector<CArcItem> &arcItems)
-{
- arcItems.Clear();
- UInt32 numItems;
- IInArchive *archive = arc.Archive;
- RINOK(archive->GetNumberOfItems(&numItems));
- arcItems.ClearAndReserve(numItems);
-
- CReadArcItem item;
-
- for (UInt32 i = 0; i < numItems; i++)
- {
- CArcItem ai;
-
- RINOK(arc.GetItem(i, item));
- ai.Name = item.Path;
- ai.IsDir = item.IsDir;
- ai.IsAltStream =
- #ifdef SUPPORT_ALT_STREAMS
- item.IsAltStream;
- #else
- false;
- #endif
-
- /*
- if (!storeStreamsMode && ai.IsAltStream)
- continue;
- */
- ai.Censored = Censor_CheckPath(censor, item);
-
- RINOK(arc.GetItemMTime(i, ai.MTime, ai.MTimeDefined));
- RINOK(arc.GetItemSize(i, ai.Size, ai.SizeDefined));
-
- {
- CPropVariant prop;
- RINOK(archive->GetProperty(i, kpidTimeType, &prop));
- if (prop.vt == VT_UI4)
- {
- ai.TimeType = (int)(NFileTimeType::EEnum)prop.ulVal;
- switch (ai.TimeType)
- {
- case NFileTimeType::kWindows:
- case NFileTimeType::kUnix:
- case NFileTimeType::kDOS:
- break;
- default:
- return E_FAIL;
- }
- }
- }
-
- ai.IndexInServer = i;
- arcItems.AddInReserved(ai);
- }
- return S_OK;
-}
-
-#if defined(_WIN32) && !defined(UNDER_CE)
-
-#include <mapi.h>
-
-#endif
-
-HRESULT UpdateArchive(
- CCodecs *codecs,
- const CObjectVector<COpenType> &types,
- const UString &cmdArcPath2,
- NWildcard::CCensor &censor,
- CUpdateOptions &options,
- CUpdateErrorInfo &errorInfo,
- IOpenCallbackUI *openCallback,
- IUpdateCallbackUI2 *callback,
- bool needSetPath)
-{
- if (options.StdOutMode && options.EMailMode)
- return E_FAIL;
-
- if (types.Size() > 1)
- return E_NOTIMPL;
-
- bool renameMode = !options.RenamePairs.IsEmpty();
- if (renameMode)
- {
- if (options.Commands.Size() != 1)
- return E_FAIL;
- }
-
- if (options.DeleteAfterCompressing)
- {
- if (options.Commands.Size() != 1)
- return E_NOTIMPL;
- const CActionSet &as = options.Commands[0].ActionSet;
- for (int i = 2; i < NPairState::kNumValues; i++)
- if (as.StateActions[i] != NPairAction::kCompress)
- return E_NOTIMPL;
- }
-
- censor.AddPathsToCensor(options.PathMode);
- #ifdef _WIN32
- ConvertToLongNames(censor);
- #endif
- censor.ExtendExclude();
-
-
- if (options.VolumesSizes.Size() > 0 && (options.EMailMode /* || options.SfxMode */))
- return E_NOTIMPL;
-
- if (options.SfxMode)
- {
- CProperty property;
- property.Name = "rsfx";
- options.MethodMode.Properties.Add(property);
- if (options.SfxModule.IsEmpty())
- {
- errorInfo.Message = "SFX file is not specified";
- return E_FAIL;
- }
- bool found = false;
- if (options.SfxModule.Find(FCHAR_PATH_SEPARATOR) < 0)
- {
- const FString fullName = NDLL::GetModuleDirPrefix() + options.SfxModule;
- if (NFind::DoesFileExist(fullName))
- {
- options.SfxModule = fullName;
- found = true;
- }
- }
- if (!found)
- {
- if (!NFind::DoesFileExist(options.SfxModule))
- return errorInfo.SetFromLastError("cannot find specified SFX module", options.SfxModule);
- }
- }
-
- CArchiveLink arcLink;
-
-
- if (needSetPath)
- {
- if (!options.InitFormatIndex(codecs, types, cmdArcPath2) ||
- !options.SetArcPath(codecs, cmdArcPath2))
- return E_NOTIMPL;
- }
-
- UString arcPath = options.ArchivePath.GetFinalPath();
-
- if (!options.VolumesSizes.IsEmpty())
- {
- arcPath = options.ArchivePath.GetFinalVolPath();
- arcPath += '.';
- arcPath += "001";
- }
-
- if (cmdArcPath2.IsEmpty())
- {
- if (options.MethodMode.Type.FormatIndex < 0)
- throw "type of archive is not specified";
- }
- else
- {
- NFind::CFileInfo fi;
- if (!fi.Find(us2fs(arcPath)))
- {
- if (renameMode)
- throw "can't find archive";;
- if (options.MethodMode.Type.FormatIndex < 0)
- {
- if (!options.SetArcPath(codecs, cmdArcPath2))
- return E_NOTIMPL;
- }
- }
- else
- {
- if (fi.IsDir())
- throw "there is no such archive";
- if (fi.IsDevice)
- return E_NOTIMPL;
-
- if (!options.StdOutMode && options.UpdateArchiveItself)
- if (fi.IsReadOnly())
- {
- errorInfo.SystemError = ERROR_ACCESS_DENIED;
- errorInfo.Message = "The file is read-only";
- errorInfo.FileNames.Add(us2fs(arcPath));
- return errorInfo.Get_HRESULT_Error();
- }
-
- if (options.VolumesSizes.Size() > 0)
- {
- errorInfo.FileNames.Add(us2fs(arcPath));
- errorInfo.SystemError = (DWORD)E_NOTIMPL;
- errorInfo.Message = kUpdateIsNotSupoorted_MultiVol;
- return E_NOTIMPL;
- }
- CObjectVector<COpenType> types2;
- // change it.
- if (options.MethodMode.Type_Defined)
- types2.Add(options.MethodMode.Type);
- // We need to set Properties to open archive only in some cases (WIM archives).
-
- CIntVector excl;
- COpenOptions op;
- #ifndef _SFX
- op.props = &options.MethodMode.Properties;
- #endif
- op.codecs = codecs;
- op.types = &types2;
- op.excludedFormats = &excl;
- op.stdInMode = false;
- op.stream = NULL;
- op.filePath = arcPath;
-
- RINOK(callback->StartOpenArchive(arcPath));
-
- HRESULT result = arcLink.Open_Strict(op, openCallback);
-
- if (result == E_ABORT)
- return result;
-
- HRESULT res2 = callback->OpenResult(codecs, arcLink, arcPath, result);
- /*
- if (result == S_FALSE)
- return E_FAIL;
- */
- RINOK(res2);
- RINOK(result);
-
- if (arcLink.VolumePaths.Size() > 1)
- {
- errorInfo.SystemError = (DWORD)E_NOTIMPL;
- errorInfo.Message = kUpdateIsNotSupoorted_MultiVol;
- return E_NOTIMPL;
- }
-
- CArc &arc = arcLink.Arcs.Back();
- arc.MTimeDefined = !fi.IsDevice;
- arc.MTime = fi.MTime;
-
- if (arc.ErrorInfo.ThereIsTail)
- {
- errorInfo.SystemError = (DWORD)E_NOTIMPL;
- errorInfo.Message = "There is some data block after the end of the archive";
- return E_NOTIMPL;
- }
- if (options.MethodMode.Type.FormatIndex < 0)
- {
- options.MethodMode.Type.FormatIndex = arcLink.GetArc()->FormatIndex;
- if (!options.SetArcPath(codecs, cmdArcPath2))
- return E_NOTIMPL;
- }
- }
- }
-
- if (options.MethodMode.Type.FormatIndex < 0)
- {
- options.MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveType((UString)kDefaultArcType);
- if (options.MethodMode.Type.FormatIndex < 0)
- return E_NOTIMPL;
- }
-
- bool thereIsInArchive = arcLink.IsOpen;
- if (!thereIsInArchive && renameMode)
- return E_FAIL;
-
- CDirItems dirItems;
- dirItems.Callback = callback;
-
- CDirItem parentDirItem;
- CDirItem *parentDirItem_Ptr = NULL;
-
- /*
- FStringVector requestedPaths;
- FStringVector *requestedPaths_Ptr = NULL;
- if (options.DeleteAfterCompressing)
- requestedPaths_Ptr = &requestedPaths;
- */
-
- if (options.StdInMode)
- {
- CDirItem di;
- di.Name = options.StdInFileName;
- di.Size = (UInt64)(Int64)-1;
- di.Attrib = 0;
- NTime::GetCurUtcFileTime(di.MTime);
- di.CTime = di.ATime = di.MTime;
- dirItems.Items.Add(di);
- }
- else
- {
- bool needScanning = false;
-
- if (!renameMode)
- FOR_VECTOR (i, options.Commands)
- if (options.Commands[i].ActionSet.NeedScanning())
- needScanning = true;
-
- if (needScanning)
- {
- RINOK(callback->StartScanning());
-
- dirItems.SymLinks = options.SymLinks.Val;
-
- #if defined(_WIN32) && !defined(UNDER_CE)
- dirItems.ReadSecure = options.NtSecurity.Val;
- #endif
-
- dirItems.ScanAltStreams = options.AltStreams.Val;
-
- HRESULT res = EnumerateItems(censor,
- options.PathMode,
- options.AddPathPrefix,
- dirItems);
-
- if (res != S_OK)
- {
- if (res != E_ABORT)
- errorInfo.Message = "Scanning error";
- return res;
- }
-
- RINOK(callback->FinishScanning(dirItems.Stat));
-
- if (censor.Pairs.Size() == 1)
- {
- NFind::CFileInfo fi;
- FString prefix = us2fs(censor.Pairs[0].Prefix);
- prefix += '.';
- // UString prefix = censor.Pairs[0].Prefix;
- /*
- if (prefix.Back() == WCHAR_PATH_SEPARATOR)
- {
- prefix.DeleteBack();
- }
- */
- if (fi.Find(prefix))
- if (fi.IsDir())
- {
- parentDirItem.Size = fi.Size;
- parentDirItem.CTime = fi.CTime;
- parentDirItem.ATime = fi.ATime;
- parentDirItem.MTime = fi.MTime;
- parentDirItem.Attrib = fi.Attrib;
- parentDirItem_Ptr = &parentDirItem;
-
- int secureIndex = -1;
- #if defined(_WIN32) && !defined(UNDER_CE)
- if (options.NtSecurity.Val)
- dirItems.AddSecurityItem(prefix, secureIndex);
- #endif
- parentDirItem.SecureIndex = secureIndex;
-
- parentDirItem_Ptr = &parentDirItem;
- }
- }
- }
- }
-
- FString tempDirPrefix;
- bool usesTempDir = false;
-
- #ifdef _WIN32
- CTempDir tempDirectory;
- if (options.EMailMode && options.EMailRemoveAfter)
- {
- tempDirectory.Create(kTempFolderPrefix);
- tempDirPrefix = tempDirectory.GetPath();
- NormalizeDirPathPrefix(tempDirPrefix);
- usesTempDir = true;
- }
- #endif
-
- CTempFiles tempFiles;
-
- bool createTempFile = false;
-
- if (!options.StdOutMode && options.UpdateArchiveItself)
- {
- CArchivePath &ap = options.Commands[0].ArchivePath;
- ap = options.ArchivePath;
- // if ((archive != 0 && !usesTempDir) || !options.WorkingDir.IsEmpty())
- if ((thereIsInArchive || !options.WorkingDir.IsEmpty()) && !usesTempDir && options.VolumesSizes.Size() == 0)
- {
- createTempFile = true;
- ap.Temp = true;
- if (!options.WorkingDir.IsEmpty())
- ap.TempPrefix = options.WorkingDir;
- else
- ap.TempPrefix = us2fs(ap.Prefix);
- NormalizeDirPathPrefix(ap.TempPrefix);
- }
- }
-
- unsigned ci;
-
-
- // self including protection
- if (options.DeleteAfterCompressing)
- {
- for (ci = 0; ci < options.Commands.Size(); ci++)
- {
- CArchivePath &ap = options.Commands[ci].ArchivePath;
- const FString path = us2fs(ap.GetFinalPath());
- // maybe we must compare absolute paths path here
- FOR_VECTOR (i, dirItems.Items)
- {
- const FString phyPath = dirItems.GetPhyPath(i);
- if (phyPath == path)
- {
- UString s;
- s = "It is not allowed to include archive to itself";
- s.Add_LF();
- s += path;
- throw s;
- }
- }
- }
- }
-
-
- for (ci = 0; ci < options.Commands.Size(); ci++)
- {
- CArchivePath &ap = options.Commands[ci].ArchivePath;
- if (usesTempDir)
- {
- // Check it
- ap.Prefix = fs2us(tempDirPrefix);
- // ap.Temp = true;
- // ap.TempPrefix = tempDirPrefix;
- }
- if (!options.StdOutMode &&
- (ci > 0 || !createTempFile))
- {
- const FString path = us2fs(ap.GetFinalPath());
- if (NFind::DoesFileOrDirExist(path))
- {
- errorInfo.SystemError = ERROR_FILE_EXISTS;
- errorInfo.Message = "The file already exists";
- errorInfo.FileNames.Add(path);
- return errorInfo.Get_HRESULT_Error();
- }
- }
- }
-
- CObjectVector<CArcItem> arcItems;
- if (thereIsInArchive)
- {
- RINOK(EnumerateInArchiveItems(
- // options.StoreAltStreams,
- censor, arcLink.Arcs.Back(), arcItems));
- }
-
- /*
- FStringVector processedFilePaths;
- FStringVector *processedFilePaths_Ptr = NULL;
- if (options.DeleteAfterCompressing)
- processedFilePaths_Ptr = &processedFilePaths;
- */
-
- CByteBuffer processedItems;
- if (options.DeleteAfterCompressing)
- {
- unsigned num = dirItems.Items.Size();
- processedItems.Alloc(num);
- for (unsigned i = 0; i < num; i++)
- processedItems[i] = 0;
- }
-
- /*
- #ifndef _NO_CRYPTO
- if (arcLink.PasswordWasAsked)
- {
- // We set password, if open have requested password
- RINOK(callback->SetPassword(arcLink.Password));
- }
- #endif
- */
-
- for (ci = 0; ci < options.Commands.Size(); ci++)
- {
- const CArc *arc = thereIsInArchive ? arcLink.GetArc() : NULL;
- CUpdateArchiveCommand &command = options.Commands[ci];
- UString name;
- bool isUpdating;
-
- if (options.StdOutMode)
- {
- name = "stdout";
- isUpdating = thereIsInArchive;
- }
- else
- {
- name = command.ArchivePath.GetFinalPath();
- isUpdating = (ci == 0 && options.UpdateArchiveItself && thereIsInArchive);
- }
-
- RINOK(callback->StartArchive(name, isUpdating))
-
- CFinishArchiveStat st;
-
- RINOK(Compress(options,
- isUpdating,
- codecs,
- command.ActionSet,
- arc,
- command.ArchivePath,
- arcItems,
- options.DeleteAfterCompressing ? (Byte *)processedItems : NULL,
-
- dirItems,
- parentDirItem_Ptr,
-
- tempFiles,
- errorInfo, callback, st));
-
- RINOK(callback->FinishArchive(st));
- }
-
-
- if (thereIsInArchive)
- {
- RINOK(arcLink.Close());
- arcLink.Release();
- }
-
- tempFiles.Paths.Clear();
- if (createTempFile)
- {
- try
- {
- CArchivePath &ap = options.Commands[0].ArchivePath;
- const FString &tempPath = ap.GetTempPath();
-
- // DWORD attrib = 0;
- if (thereIsInArchive)
- {
- // attrib = NFind::GetFileAttrib(us2fs(arcPath));
- if (!DeleteFileAlways(us2fs(arcPath)))
- return errorInfo.SetFromLastError("cannot delete the file", us2fs(arcPath));
- }
-
- if (!MyMoveFile(tempPath, us2fs(arcPath)))
- {
- errorInfo.SetFromLastError("cannot move the file", tempPath);
- errorInfo.FileNames.Add(us2fs(arcPath));
- return errorInfo.Get_HRESULT_Error();
- }
-
- /*
- if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY))
- {
- DWORD attrib2 = NFind::GetFileAttrib(us2fs(arcPath));
- if (attrib2 != INVALID_FILE_ATTRIBUTES)
- NDir::SetFileAttrib(us2fs(arcPath), attrib2 | FILE_ATTRIBUTE_READONLY);
- }
- */
- }
- catch(...)
- {
- throw;
- }
- }
-
-
- #if defined(_WIN32) && !defined(UNDER_CE)
-
- if (options.EMailMode)
- {
- NDLL::CLibrary mapiLib;
- if (!mapiLib.Load(FTEXT("Mapi32.dll")))
- {
- errorInfo.SetFromLastError("cannot load Mapi32.dll");
- return errorInfo.Get_HRESULT_Error();
- }
-
- /*
- LPMAPISENDDOCUMENTS fnSend = (LPMAPISENDDOCUMENTS)mapiLib.GetProc("MAPISendDocuments");
- if (fnSend == 0)
- {
- errorInfo.SetFromLastError)("7-Zip cannot find MAPISendDocuments function");
- return errorInfo.Get_HRESULT_Error();
- }
- */
-
- LPMAPISENDMAIL sendMail = (LPMAPISENDMAIL)mapiLib.GetProc("MAPISendMail");
- if (sendMail == 0)
- {
- errorInfo.SetFromLastError("7-Zip cannot find MAPISendMail function");
- return errorInfo.Get_HRESULT_Error();;
- }
-
- FStringVector fullPaths;
- unsigned i;
-
- for (i = 0; i < options.Commands.Size(); i++)
- {
- CArchivePath &ap = options.Commands[i].ArchivePath;
- FString finalPath = us2fs(ap.GetFinalPath());
- FString arcPath2;
- if (!MyGetFullPathName(finalPath, arcPath2))
- return errorInfo.SetFromLastError("GetFullPathName error", finalPath);
- fullPaths.Add(arcPath2);
- }
-
- CCurrentDirRestorer curDirRestorer;
-
- AStringVector paths;
- AStringVector names;
-
- for (i = 0; i < fullPaths.Size(); i++)
- {
- const UString arcPath2 = fs2us(fullPaths[i]);
- const UString fileName = ExtractFileNameFromPath(arcPath2);
- paths.Add(GetAnsiString(arcPath2));
- names.Add(GetAnsiString(fileName));
- // const AString path (GetAnsiString(arcPath2));
- // const AString name (GetAnsiString(fileName));
- // Warning!!! MAPISendDocuments function changes Current directory
- // fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0);
- }
-
- CRecordVector<MapiFileDesc> files;
- files.ClearAndSetSize(paths.Size());
-
- for (i = 0; i < paths.Size(); i++)
- {
- MapiFileDesc &f = files[i];
- memset(&f, 0, sizeof(f));
- f.nPosition = 0xFFFFFFFF;
- f.lpszPathName = (char *)(const char *)paths[i];
- f.lpszFileName = (char *)(const char *)names[i];
- }
-
- {
- MapiMessage m;
- memset(&m, 0, sizeof(m));
- m.nFileCount = files.Size();
- m.lpFiles = &files.Front();
-
- const AString addr (GetAnsiString(options.EMailAddress));
- MapiRecipDesc rec;
- if (!addr.IsEmpty())
- {
- memset(&rec, 0, sizeof(rec));
- rec.ulRecipClass = MAPI_TO;
- rec.lpszAddress = (char *)(const char *)addr;
- m.nRecipCount = 1;
- m.lpRecips = &rec;
- }
-
- sendMail((LHANDLE)0, 0, &m, MAPI_DIALOG, 0);
- }
- }
-
- #endif
-
- if (options.DeleteAfterCompressing)
- {
- CRecordVector<CDirPathSortPair> pairs;
- FStringVector foldersNames;
-
- unsigned i;
-
- for (i = 0; i < dirItems.Items.Size(); i++)
- {
- const CDirItem &dirItem = dirItems.Items[i];
- const FString phyPath = dirItems.GetPhyPath(i);
- if (dirItem.IsDir())
- {
- CDirPathSortPair pair;
- pair.Index = i;
- pair.SetNumSlashes(phyPath);
- pairs.Add(pair);
- }
- else
- {
- if (processedItems[i] != 0 || dirItem.Size == 0)
- {
- NFind::CFileInfo fileInfo;
- if (fileInfo.Find(phyPath))
- {
- // maybe we must exclude also files with archive name: "a a.7z * -sdel"
- if (fileInfo.Size == dirItem.Size
- && CompareFileTime(&fileInfo.MTime, &dirItem.MTime) == 0
- && CompareFileTime(&fileInfo.CTime, &dirItem.CTime) == 0)
- {
- RINOK(callback->DeletingAfterArchiving(phyPath, false));
- DeleteFileAlways(phyPath);
- }
- }
- }
- else
- {
- // file was skipped
- /*
- errorInfo.SystemError = 0;
- errorInfo.Message = "file was not processed";
- errorInfo.FileName = phyPath;
- return E_FAIL;
- */
- }
- }
- }
-
- pairs.Sort2();
-
- for (i = 0; i < pairs.Size(); i++)
- {
- const FString phyPath = dirItems.GetPhyPath(pairs[i].Index);
- if (NFind::DoesDirExist(phyPath))
- {
- RINOK(callback->DeletingAfterArchiving(phyPath, true));
- RemoveDir(phyPath);
- }
- }
-
- RINOK(callback->FinishDeletingAfterArchiving());
- }
-
- return S_OK;
-}
+// Update.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "Update.h"
+
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/PropVariantConv.h"
+#include "../../../Windows/TimeUtils.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Common/LimitedStreams.h"
+#include "../../Common/MultiOutStream.h"
+#include "../../Common/StreamUtils.h"
+
+#include "../../Compress/CopyCoder.h"
+
+#include "../Common/DirItem.h"
+#include "../Common/EnumDirItems.h"
+#include "../Common/OpenArchive.h"
+#include "../Common/UpdateProduce.h"
+
+#include "EnumDirItems.h"
+#include "SetProperties.h"
+#include "TempFiles.h"
+#include "UpdateCallback.h"
+
+static const char * const kUpdateIsNotSupoorted =
+ "update operations are not supported for this archive";
+
+static const char * const kUpdateIsNotSupported_MultiVol =
+ "Updating for multivolume archives is not implemented";
+
+using namespace NWindows;
+using namespace NCOM;
+using namespace NFile;
+using namespace NDir;
+using namespace NName;
+
+#ifdef _WIN32
+static CFSTR const kTempFolderPrefix = FTEXT("7zE");
+#endif
+
+void CUpdateErrorInfo::SetFromLastError(const char *message)
+{
+ SystemError = ::GetLastError();
+ Message = message;
+}
+
+HRESULT CUpdateErrorInfo::SetFromLastError(const char *message, const FString &fileName)
+{
+ SetFromLastError(message);
+ FileNames.Add(fileName);
+ return Get_HRESULT_Error();
+}
+
+HRESULT CUpdateErrorInfo::SetFromError_DWORD(const char *message, const FString &fileName, DWORD error)
+{
+ Message = message;
+ FileNames.Add(fileName);
+ SystemError = error;
+ return Get_HRESULT_Error();
+}
+
+
+using namespace NUpdateArchive;
+
+struct CMultiOutStream_Rec
+{
+ CMultiOutStream *Spec;
+ CMyComPtr<IOutStream> Ref;
+};
+
+struct CMultiOutStream_Bunch
+{
+ CObjectVector<CMultiOutStream_Rec> Items;
+
+ HRESULT Destruct()
+ {
+ HRESULT hres = S_OK;
+ FOR_VECTOR (i, Items)
+ {
+ CMultiOutStream_Rec &rec = Items[i];
+ if (rec.Ref)
+ {
+ const HRESULT hres2 = rec.Spec->Destruct();
+ if (hres == S_OK)
+ hres = hres2;
+ }
+ }
+ Items.Clear();
+ return hres;
+ }
+
+ void DisableDeletion()
+ {
+ FOR_VECTOR (i, Items)
+ {
+ CMultiOutStream_Rec &rec = Items[i];
+ if (rec.Ref)
+ rec.Spec->NeedDelete = false;
+ }
+ }
+};
+
+
+void CArchivePath::ParseFromPath(const UString &path, EArcNameMode mode)
+{
+ OriginalPath = path;
+
+ SplitPathToParts_2(path, Prefix, Name);
+
+ if (mode == k_ArcNameMode_Add)
+ return;
+
+ if (mode != k_ArcNameMode_Exact)
+ {
+ int dotPos = Name.ReverseFind_Dot();
+ if (dotPos < 0)
+ return;
+ if ((unsigned)dotPos == Name.Len() - 1)
+ Name.DeleteBack();
+ else
+ {
+ const UString ext = Name.Ptr((unsigned)(dotPos + 1));
+ if (BaseExtension.IsEqualTo_NoCase(ext))
+ {
+ BaseExtension = ext;
+ Name.DeleteFrom((unsigned)dotPos);
+ return;
+ }
+ }
+ }
+
+ BaseExtension.Empty();
+}
+
+UString CArchivePath::GetFinalPath() const
+{
+ UString path = GetPathWithoutExt();
+ if (!BaseExtension.IsEmpty())
+ {
+ path.Add_Dot();
+ path += BaseExtension;
+ }
+ return path;
+}
+
+UString CArchivePath::GetFinalVolPath() const
+{
+ UString path = GetPathWithoutExt();
+ // if BaseExtension is empty, we must ignore VolExtension also.
+ if (!BaseExtension.IsEmpty())
+ {
+ path.Add_Dot();
+ path += VolExtension;
+ }
+ return path;
+}
+
+FString CArchivePath::GetTempPath() const
+{
+ FString path = TempPrefix;
+ path += us2fs(Name);
+ if (!BaseExtension.IsEmpty())
+ {
+ path.Add_Dot();
+ path += us2fs(BaseExtension);
+ }
+ path += ".tmp";
+ path += TempPostfix;
+ return path;
+}
+
+static const char * const kDefaultArcType = "7z";
+static const char * const kDefaultArcExt = "7z";
+static const char * const kSFXExtension =
+ #ifdef _WIN32
+ "exe";
+ #else
+ "";
+ #endif
+
+bool CUpdateOptions::InitFormatIndex(const CCodecs *codecs,
+ const CObjectVector<COpenType> &types, const UString &arcPath)
+{
+ if (types.Size() > 1)
+ return false;
+ // int arcTypeIndex = -1;
+ if (types.Size() != 0)
+ {
+ MethodMode.Type = types[0];
+ MethodMode.Type_Defined = true;
+ }
+ if (MethodMode.Type.FormatIndex < 0)
+ {
+ // MethodMode.Type = -1;
+ MethodMode.Type = COpenType();
+ if (ArcNameMode != k_ArcNameMode_Add)
+ {
+ MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveName(arcPath);
+ if (MethodMode.Type.FormatIndex >= 0)
+ MethodMode.Type_Defined = true;
+ }
+ }
+ return true;
+}
+
+bool CUpdateOptions::SetArcPath(const CCodecs *codecs, const UString &arcPath)
+{
+ UString typeExt;
+ int formatIndex = MethodMode.Type.FormatIndex;
+ if (formatIndex < 0)
+ {
+ typeExt = kDefaultArcExt;
+ }
+ else
+ {
+ const CArcInfoEx &arcInfo = codecs->Formats[(unsigned)formatIndex];
+ if (!arcInfo.UpdateEnabled)
+ return false;
+ typeExt = arcInfo.GetMainExt();
+ }
+ UString ext = typeExt;
+ if (SfxMode)
+ ext = kSFXExtension;
+ ArchivePath.BaseExtension = ext;
+ ArchivePath.VolExtension = typeExt;
+ ArchivePath.ParseFromPath(arcPath, ArcNameMode);
+ FOR_VECTOR (i, Commands)
+ {
+ CUpdateArchiveCommand &uc = Commands[i];
+ uc.ArchivePath.BaseExtension = ext;
+ uc.ArchivePath.VolExtension = typeExt;
+ uc.ArchivePath.ParseFromPath(uc.UserArchivePath, ArcNameMode);
+ }
+ return true;
+}
+
+
+struct CUpdateProduceCallbackImp Z7_final: public IUpdateProduceCallback
+{
+ const CObjectVector<CArcItem> *_arcItems;
+ CDirItemsStat *_stat;
+ IUpdateCallbackUI *_callback;
+
+ CUpdateProduceCallbackImp(
+ const CObjectVector<CArcItem> *a,
+ CDirItemsStat *stat,
+ IUpdateCallbackUI *callback):
+ _arcItems(a),
+ _stat(stat),
+ _callback(callback) {}
+
+ virtual HRESULT ShowDeleteFile(unsigned arcIndex) Z7_override;
+};
+
+
+HRESULT CUpdateProduceCallbackImp::ShowDeleteFile(unsigned arcIndex)
+{
+ const CArcItem &ai = (*_arcItems)[arcIndex];
+ {
+ CDirItemsStat &stat = *_stat;
+ if (ai.IsDir)
+ stat.NumDirs++;
+ else if (ai.IsAltStream)
+ {
+ stat.NumAltStreams++;
+ stat.AltStreamsSize += ai.Size;
+ }
+ else
+ {
+ stat.NumFiles++;
+ stat.FilesSize += ai.Size;
+ }
+ }
+ return _callback->ShowDeleteFile(ai.Name, ai.IsDir);
+}
+
+bool CRenamePair::Prepare()
+{
+ if (RecursedType != NRecursedType::kNonRecursed)
+ return false;
+ if (!WildcardParsing)
+ return true;
+ return !DoesNameContainWildcard(OldName);
+}
+
+extern bool g_CaseSensitive;
+
+static unsigned CompareTwoNames(const wchar_t *s1, const wchar_t *s2)
+{
+ for (unsigned i = 0;; i++)
+ {
+ wchar_t c1 = s1[i];
+ wchar_t c2 = s2[i];
+ if (c1 == 0 || c2 == 0)
+ return i;
+ if (c1 == c2)
+ continue;
+ if (!g_CaseSensitive && (MyCharUpper(c1) == MyCharUpper(c2)))
+ continue;
+ if (IsPathSepar(c1) && IsPathSepar(c2))
+ continue;
+ return i;
+ }
+}
+
+bool CRenamePair::GetNewPath(bool isFolder, const UString &src, UString &dest) const
+{
+ unsigned num = CompareTwoNames(OldName, src);
+ if (OldName[num] == 0)
+ {
+ if (src[num] != 0 && !IsPathSepar(src[num]) && num != 0 && !IsPathSepar(src[num - 1]))
+ return false;
+ }
+ else
+ {
+ // OldName[num] != 0
+ // OldName = "1\1a.txt"
+ // src = "1"
+
+ if (!isFolder
+ || src[num] != 0
+ || !IsPathSepar(OldName[num])
+ || OldName[num + 1] != 0)
+ return false;
+ }
+ dest = NewName + src.Ptr(num);
+ return true;
+}
+
+#ifdef SUPPORT_ALT_STREAMS
+int FindAltStreamColon_in_Path(const wchar_t *path);
+#endif
+
+
+
+static HRESULT Compress(
+ const CUpdateOptions &options,
+ bool isUpdatingItself,
+ CCodecs *codecs,
+ const CActionSet &actionSet,
+ const CArc *arc,
+ CArchivePath &archivePath,
+ const CObjectVector<CArcItem> &arcItems,
+ Byte *processedItemsStatuses,
+ const CDirItems &dirItems,
+ const CDirItem *parentDirItem,
+ CTempFiles &tempFiles,
+ CMultiOutStream_Bunch &multiStreams,
+ CUpdateErrorInfo &errorInfo,
+ IUpdateCallbackUI *callback,
+ CFinishArchiveStat &st)
+{
+ CMyComPtr<IOutArchive> outArchive;
+ int formatIndex = options.MethodMode.Type.FormatIndex;
+
+ if (arc)
+ {
+ formatIndex = arc->FormatIndex;
+ if (formatIndex < 0)
+ return E_NOTIMPL;
+ CMyComPtr<IInArchive> archive2 = arc->Archive;
+ HRESULT result = archive2.QueryInterface(IID_IOutArchive, &outArchive);
+ if (result != S_OK)
+ throw kUpdateIsNotSupoorted;
+ }
+ else
+ {
+ RINOK(codecs->CreateOutArchive((unsigned)formatIndex, outArchive))
+
+ #ifdef Z7_EXTERNAL_CODECS
+ {
+ CMyComPtr<ISetCompressCodecsInfo> setCompressCodecsInfo;
+ outArchive.QueryInterface(IID_ISetCompressCodecsInfo, (void **)&setCompressCodecsInfo);
+ if (setCompressCodecsInfo)
+ {
+ RINOK(setCompressCodecsInfo->SetCompressCodecsInfo(codecs))
+ }
+ }
+ #endif
+ }
+
+ if (!outArchive)
+ throw kUpdateIsNotSupoorted;
+
+ // we need to set properties to get fileTimeType.
+ RINOK(SetProperties(outArchive, options.MethodMode.Properties))
+
+ NFileTimeType::EEnum fileTimeType;
+ {
+ /*
+ how we compare file_in_archive::MTime with dirItem.MTime
+ for GetUpdatePairInfoList():
+
+ if (kpidMTime is not defined), external MTime of archive is used.
+
+ before 22.00:
+ if (kpidTimeType is defined)
+ {
+ kpidTimeType is used as precision.
+ (kpidTimeType > kDOS) is not allowed.
+ }
+ else GetFileTimeType() value is used as precision.
+
+ 22.00:
+ if (kpidMTime is defined)
+ {
+ if (kpidMTime::precision != 0), then kpidMTime::precision is used as precision.
+ else
+ {
+ if (kpidTimeType is defined), kpidTimeType is used as precision.
+ else GetFileTimeType() value is used as precision.
+ }
+ }
+ else external MTime of archive is used as precision.
+ */
+
+ UInt32 value;
+ RINOK(outArchive->GetFileTimeType(&value))
+
+ // we support any future fileType here.
+ fileTimeType = (NFileTimeType::EEnum)value;
+
+ /*
+ old 21.07 code:
+ switch (value)
+ {
+ case NFileTimeType::kWindows:
+ case NFileTimeType::kUnix:
+ case NFileTimeType::kDOS:
+ fileTimeType = (NFileTimeType::EEnum)value;
+ break;
+ default:
+ return E_FAIL;
+ }
+ */
+ }
+
+ // bool noTimestampExpected = false;
+ {
+ const CArcInfoEx &arcInfo = codecs->Formats[(unsigned)formatIndex];
+
+ // if (arcInfo.Flags_KeepName()) noTimestampExpected = true;
+ if (arcInfo.Is_Xz() ||
+ arcInfo.Is_BZip2())
+ {
+ /* 7-zip before 22.00 returns NFileTimeType::kUnix for xz and bzip2,
+ but we want to set timestamp without reduction to unix. */
+ // noTimestampExpected = true;
+ fileTimeType = NFileTimeType::kNotDefined; // it means not defined
+ }
+
+ if (options.AltStreams.Val && !arcInfo.Flags_AltStreams())
+ return E_NOTIMPL;
+ if (options.NtSecurity.Val && !arcInfo.Flags_NtSecurity())
+ return E_NOTIMPL;
+ if (options.DeleteAfterCompressing && arcInfo.Flags_HashHandler())
+ return E_NOTIMPL;
+ }
+
+ CRecordVector<CUpdatePair2> updatePairs2;
+
+ UStringVector newNames;
+
+ CArcToDoStat stat2;
+
+ if (options.RenamePairs.Size() != 0)
+ {
+ FOR_VECTOR (i, arcItems)
+ {
+ const CArcItem &ai = arcItems[i];
+ bool needRename = false;
+ UString dest;
+
+ if (ai.Censored)
+ {
+ FOR_VECTOR (j, options.RenamePairs)
+ {
+ const CRenamePair &rp = options.RenamePairs[j];
+ if (rp.GetNewPath(ai.IsDir, ai.Name, dest))
+ {
+ needRename = true;
+ break;
+ }
+
+ #ifdef SUPPORT_ALT_STREAMS
+ if (ai.IsAltStream)
+ {
+ int colonPos = FindAltStreamColon_in_Path(ai.Name);
+ if (colonPos >= 0)
+ {
+ UString mainName = ai.Name.Left((unsigned)colonPos);
+ /*
+ actually we must improve that code to support cases
+ with folder renaming like: rn arc dir1\ dir2\
+ */
+ if (rp.GetNewPath(false, mainName, dest))
+ {
+ needRename = true;
+ dest += ':';
+ dest += ai.Name.Ptr((unsigned)(colonPos + 1));
+ break;
+ }
+ }
+ }
+ #endif
+ }
+ }
+
+ CUpdatePair2 up2;
+ up2.SetAs_NoChangeArcItem(ai.IndexInServer);
+ if (needRename)
+ {
+ up2.NewProps = true;
+ RINOK(arc->IsItem_Anti(i, up2.IsAnti))
+ up2.NewNameIndex = (int)newNames.Add(dest);
+ }
+ updatePairs2.Add(up2);
+ }
+ }
+ else
+ {
+ CRecordVector<CUpdatePair> updatePairs;
+ GetUpdatePairInfoList(dirItems, arcItems, fileTimeType, updatePairs); // must be done only once!!!
+ CUpdateProduceCallbackImp upCallback(&arcItems, &stat2.DeleteData, callback);
+
+ UpdateProduce(updatePairs, actionSet, updatePairs2, isUpdatingItself ? &upCallback : NULL);
+ }
+
+ {
+ FOR_VECTOR (i, updatePairs2)
+ {
+ const CUpdatePair2 &up = updatePairs2[i];
+
+ // 17.01: anti-item is (up.NewData && (p.UseArcProps in most cases))
+
+ if (up.NewData && !up.UseArcProps)
+ {
+ if (up.ExistOnDisk())
+ {
+ CDirItemsStat2 &stat = stat2.NewData;
+ const CDirItem &di = dirItems.Items[(unsigned)up.DirIndex];
+ if (di.IsDir())
+ {
+ if (up.IsAnti)
+ stat.Anti_NumDirs++;
+ else
+ stat.NumDirs++;
+ }
+ #ifdef _WIN32
+ else if (di.IsAltStream)
+ {
+ if (up.IsAnti)
+ stat.Anti_NumAltStreams++;
+ else
+ {
+ stat.NumAltStreams++;
+ stat.AltStreamsSize += di.Size;
+ }
+ }
+ #endif
+ else
+ {
+ if (up.IsAnti)
+ stat.Anti_NumFiles++;
+ else
+ {
+ stat.NumFiles++;
+ stat.FilesSize += di.Size;
+ }
+ }
+ }
+ }
+ else if (up.ArcIndex >= 0)
+ {
+ CDirItemsStat2 &stat = *(up.NewData ? &stat2.NewData : &stat2.OldData);
+ const CArcItem &ai = arcItems[(unsigned)up.ArcIndex];
+ if (ai.IsDir)
+ {
+ if (up.IsAnti)
+ stat.Anti_NumDirs++;
+ else
+ stat.NumDirs++;
+ }
+ else if (ai.IsAltStream)
+ {
+ if (up.IsAnti)
+ stat.Anti_NumAltStreams++;
+ else
+ {
+ stat.NumAltStreams++;
+ stat.AltStreamsSize += ai.Size;
+ }
+ }
+ else
+ {
+ if (up.IsAnti)
+ stat.Anti_NumFiles++;
+ else
+ {
+ stat.NumFiles++;
+ stat.FilesSize += ai.Size;
+ }
+ }
+ }
+ }
+ RINOK(callback->SetNumItems(stat2))
+ }
+
+ CArchiveUpdateCallback *updateCallbackSpec = new CArchiveUpdateCallback;
+ CMyComPtr<IArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+
+ updateCallbackSpec->PreserveATime = options.PreserveATime;
+ updateCallbackSpec->ShareForWrite = options.OpenShareForWrite;
+ updateCallbackSpec->StopAfterOpenError = options.StopAfterOpenError;
+ updateCallbackSpec->StdInMode = options.StdInMode;
+ updateCallbackSpec->Callback = callback;
+
+ if (arc)
+ {
+ // we set Archive to allow to transfer GetProperty requests back to DLL.
+ updateCallbackSpec->Archive = arc->Archive;
+ }
+
+ updateCallbackSpec->DirItems = &dirItems;
+ updateCallbackSpec->ParentDirItem = parentDirItem;
+
+ updateCallbackSpec->StoreNtSecurity = options.NtSecurity.Val;
+ updateCallbackSpec->StoreHardLinks = options.HardLinks.Val;
+ updateCallbackSpec->StoreSymLinks = options.SymLinks.Val;
+ updateCallbackSpec->StoreOwnerName = options.StoreOwnerName.Val;
+ updateCallbackSpec->StoreOwnerId = options.StoreOwnerId.Val;
+
+ updateCallbackSpec->Arc = arc;
+ updateCallbackSpec->ArcItems = &arcItems;
+ updateCallbackSpec->UpdatePairs = &updatePairs2;
+
+ updateCallbackSpec->ProcessedItemsStatuses = processedItemsStatuses;
+
+ {
+ const UString arcPath = archivePath.GetFinalPath();
+ updateCallbackSpec->ArcFileName = ExtractFileNameFromPath(arcPath);
+ }
+
+ if (options.RenamePairs.Size() != 0)
+ updateCallbackSpec->NewNames = &newNames;
+
+ if (options.SetArcMTime)
+ {
+ // updateCallbackSpec->Need_ArcMTime_Report = true;
+ updateCallbackSpec->Need_LatestMTime = true;
+ }
+
+ CMyComPtr<IOutStream> outSeekStream;
+ CMyComPtr<ISequentialOutStream> outStream;
+
+ if (!options.StdOutMode)
+ {
+ FString dirPrefix;
+ if (!GetOnlyDirPrefix(us2fs(archivePath.GetFinalPath()), dirPrefix))
+ throw 1417161;
+ CreateComplexDir(dirPrefix);
+ }
+
+ COutFileStream *outStreamSpec = NULL;
+ CStdOutFileStream *stdOutFileStreamSpec = NULL;
+ CMultiOutStream *volStreamSpec = NULL;
+
+ if (options.VolumesSizes.Size() == 0)
+ {
+ if (options.StdOutMode)
+ {
+ stdOutFileStreamSpec = new CStdOutFileStream;
+ outStream = stdOutFileStreamSpec;
+ }
+ else
+ {
+ outStreamSpec = new COutFileStream;
+ outSeekStream = outStreamSpec;
+ outStream = outSeekStream;
+ bool isOK = false;
+ FString realPath;
+
+ for (unsigned i = 0; i < (1 << 16); i++)
+ {
+ if (archivePath.Temp)
+ {
+ if (i > 0)
+ {
+ archivePath.TempPostfix.Empty();
+ archivePath.TempPostfix.Add_UInt32(i);
+ }
+ realPath = archivePath.GetTempPath();
+ }
+ else
+ realPath = us2fs(archivePath.GetFinalPath());
+ if (outStreamSpec->Create(realPath, false))
+ {
+ tempFiles.Paths.Add(realPath);
+ isOK = true;
+ break;
+ }
+ if (::GetLastError() != ERROR_FILE_EXISTS)
+ break;
+ if (!archivePath.Temp)
+ break;
+ }
+
+ if (!isOK)
+ return errorInfo.SetFromLastError("cannot open file", realPath);
+ }
+ }
+ else
+ {
+ if (options.StdOutMode)
+ return E_FAIL;
+ if (arc && arc->GetGlobalOffset() > 0)
+ return E_NOTIMPL;
+
+ volStreamSpec = new CMultiOutStream();
+ outSeekStream = volStreamSpec;
+ outStream = outSeekStream;
+ volStreamSpec->Prefix = us2fs(archivePath.GetFinalVolPath());
+ volStreamSpec->Prefix.Add_Dot();
+ volStreamSpec->Init(options.VolumesSizes);
+ {
+ CMultiOutStream_Rec &rec = multiStreams.Items.AddNew();
+ rec.Spec = volStreamSpec;
+ rec.Ref = rec.Spec;
+ }
+
+ /*
+ updateCallbackSpec->VolumesSizes = volumesSizes;
+ updateCallbackSpec->VolName = archivePath.Prefix + archivePath.Name;
+ if (!archivePath.VolExtension.IsEmpty())
+ updateCallbackSpec->VolExt = UString('.') + archivePath.VolExtension;
+ */
+ }
+
+ if (options.SfxMode)
+ {
+ CInFileStream *sfxStreamSpec = new CInFileStream;
+ CMyComPtr<IInStream> sfxStream(sfxStreamSpec);
+ if (!sfxStreamSpec->Open(options.SfxModule))
+ return errorInfo.SetFromLastError("cannot open SFX module", options.SfxModule);
+
+ CMyComPtr<ISequentialOutStream> sfxOutStream;
+ COutFileStream *outStreamSpec2 = NULL;
+ if (options.VolumesSizes.Size() == 0)
+ sfxOutStream = outStream;
+ else
+ {
+ outStreamSpec2 = new COutFileStream;
+ sfxOutStream = outStreamSpec2;
+ const FString realPath = us2fs(archivePath.GetFinalPath());
+ if (!outStreamSpec2->Create(realPath, false))
+ return errorInfo.SetFromLastError("cannot open file", realPath);
+ }
+
+ {
+ UInt64 sfxSize;
+ RINOK(sfxStreamSpec->GetSize(&sfxSize))
+ RINOK(callback->WriteSfx(fs2us(options.SfxModule), sfxSize))
+ }
+
+ RINOK(NCompress::CopyStream(sfxStream, sfxOutStream, NULL))
+
+ if (outStreamSpec2)
+ {
+ RINOK(outStreamSpec2->Close())
+ }
+ }
+
+ CMyComPtr<ISequentialOutStream> tailStream;
+
+ if (options.SfxMode || !arc || arc->ArcStreamOffset == 0)
+ tailStream = outStream;
+ else
+ {
+ // Int64 globalOffset = arc->GetGlobalOffset();
+ RINOK(InStream_SeekToBegin(arc->InStream))
+ RINOK(NCompress::CopyStream_ExactSize(arc->InStream, outStream, arc->ArcStreamOffset, NULL))
+ if (options.StdOutMode)
+ tailStream = outStream;
+ else
+ {
+ CTailOutStream *tailStreamSpec = new CTailOutStream;
+ tailStream = tailStreamSpec;
+ tailStreamSpec->Stream = outSeekStream;
+ tailStreamSpec->Offset = arc->ArcStreamOffset;
+ tailStreamSpec->Init();
+ }
+ }
+
+ CFiTime ft;
+ FiTime_Clear(ft);
+ bool ft_Defined = false;
+ {
+ FOR_VECTOR (i, updatePairs2)
+ {
+ const CUpdatePair2 &pair2 = updatePairs2[i];
+ CFiTime ft2;
+ FiTime_Clear(ft2);
+ bool ft2_Defined = false;
+ /* we use full precision of dirItem, if dirItem is defined
+ and (dirItem will be used or dirItem is sameTime in dir and arc */
+ if (pair2.DirIndex >= 0 &&
+ (pair2.NewProps || pair2.IsSameTime))
+ {
+ ft2 = dirItems.Items[(unsigned)pair2.DirIndex].MTime;
+ ft2_Defined = true;
+ }
+ else if (pair2.UseArcProps && pair2.ArcIndex >= 0)
+ {
+ const CArcItem &arcItem = arcItems[(unsigned)pair2.ArcIndex];
+ if (arcItem.MTime.Def)
+ {
+ arcItem.MTime.Write_To_FiTime(ft2);
+ ft2_Defined = true;
+ }
+ }
+ if (ft2_Defined)
+ {
+ if (!ft_Defined || Compare_FiTime(&ft, &ft2) < 0)
+ {
+ ft = ft2;
+ ft_Defined = true;
+ }
+ }
+ }
+ /*
+ if (fileTimeType != NFileTimeType::kNotDefined)
+ FiTime_Normalize_With_Prec(ft, fileTimeType);
+ */
+ }
+
+ if (volStreamSpec && options.SetArcMTime && ft_Defined)
+ {
+ volStreamSpec->MTime = ft;
+ volStreamSpec->MTime_Defined = true;
+ }
+
+ HRESULT result = outArchive->UpdateItems(tailStream, updatePairs2.Size(), updateCallback);
+ // callback->Finalize();
+ RINOK(result)
+
+ if (!updateCallbackSpec->AreAllFilesClosed())
+ {
+ errorInfo.Message = "There are unclosed input file:";
+ errorInfo.FileNames = updateCallbackSpec->_openFiles_Paths;
+ return E_FAIL;
+ }
+
+ if (options.SetArcMTime)
+ {
+ // bool needNormalizeAfterStream;
+ // needParse;
+ /*
+ if (updateCallbackSpec->ArcMTime_WasReported)
+ {
+ isDefined = updateCallbackSpec->Reported_ArcMTime.Def;
+ if (isDefined)
+ updateCallbackSpec->Reported_ArcMTime.Write_To_FiTime(ft);
+ else
+ fileTimeType = NFileTimeType::kNotDefined;
+ }
+ if (!isDefined)
+ */
+ {
+ if (updateCallbackSpec->LatestMTime_Defined)
+ {
+ // CArcTime at = StreamCallback_ArcMTime;
+ // updateCallbackSpec->StreamCallback_ArcMTime.Write_To_FiTime(ft);
+ // we must normalize with precision from archive;
+ if (!ft_Defined || Compare_FiTime(&ft, &updateCallbackSpec->LatestMTime) < 0)
+ ft = updateCallbackSpec->LatestMTime;
+ ft_Defined = true;
+ }
+ /*
+ if (fileTimeType != NFileTimeType::kNotDefined)
+ FiTime_Normalize_With_Prec(ft, fileTimeType);
+ */
+ }
+ // if (ft.dwLowDateTime != 0 || ft.dwHighDateTime != 0)
+ if (ft_Defined)
+ {
+ // we ignore set time errors here.
+ // note that user could move some finished volumes to another folder.
+ if (outStreamSpec)
+ outStreamSpec->SetMTime(&ft);
+ else if (volStreamSpec)
+ volStreamSpec->SetMTime_Final(ft);
+ }
+ }
+
+ if (callback)
+ {
+ UInt64 size = 0;
+ if (outStreamSpec)
+ outStreamSpec->GetSize(&size);
+ else if (stdOutFileStreamSpec)
+ size = stdOutFileStreamSpec->GetSize();
+ else
+ size = volStreamSpec->GetSize();
+
+ st.OutArcFileSize = size;
+ }
+
+ if (outStreamSpec)
+ result = outStreamSpec->Close();
+ else if (volStreamSpec)
+ {
+ result = volStreamSpec->FinalFlush_and_CloseFiles(st.NumVolumes);
+ st.IsMultiVolMode = true;
+ }
+
+ RINOK(result)
+
+ if (processedItemsStatuses)
+ {
+ FOR_VECTOR (i, updatePairs2)
+ {
+ const CUpdatePair2 &up = updatePairs2[i];
+ if (up.NewData && up.DirIndex >= 0)
+ {
+ const CDirItem &di = dirItems.Items[(unsigned)up.DirIndex];
+ if (di.AreReparseData() || (!di.IsDir() && di.Size == 0))
+ processedItemsStatuses[(unsigned)up.DirIndex] = 1;
+ }
+ }
+ }
+
+ return result;
+}
+
+
+
+static bool Censor_AreAllAllowed(const NWildcard::CCensor &censor)
+{
+ if (censor.Pairs.Size() != 1)
+ return false;
+ const NWildcard::CPair &pair = censor.Pairs[0];
+ /* Censor_CheckPath() ignores (CPair::Prefix).
+ So we also ignore (CPair::Prefix) here */
+ // if (!pair.Prefix.IsEmpty()) return false;
+ return pair.Head.AreAllAllowed();
+}
+
+bool CensorNode_CheckPath2(const NWildcard::CCensorNode &node, const CReadArcItem &item, bool &include);
+
+static bool Censor_CheckPath(const NWildcard::CCensor &censor, const CReadArcItem &item)
+{
+ bool finded = false;
+ FOR_VECTOR (i, censor.Pairs)
+ {
+ /* (CPair::Prefix) in not used for matching items in archive.
+ So we ignore (CPair::Prefix) here */
+ bool include;
+ if (CensorNode_CheckPath2(censor.Pairs[i].Head, item, include))
+ {
+ // Check it and FIXME !!!!
+ // here we can exclude item via some Pair, that is still allowed by another Pair
+ if (!include)
+ return false;
+ finded = true;
+ }
+ }
+ return finded;
+}
+
+static HRESULT EnumerateInArchiveItems(
+ // bool storeStreamsMode,
+ const NWildcard::CCensor &censor,
+ const CArc &arc,
+ CObjectVector<CArcItem> &arcItems)
+{
+ arcItems.Clear();
+ UInt32 numItems;
+ IInArchive *archive = arc.Archive;
+ RINOK(archive->GetNumberOfItems(&numItems))
+ arcItems.ClearAndReserve(numItems);
+
+ CReadArcItem item;
+
+ const bool allFilesAreAllowed = Censor_AreAllAllowed(censor);
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ CArcItem ai;
+
+ RINOK(arc.GetItem(i, item))
+ ai.Name = item.Path;
+ ai.IsDir = item.IsDir;
+ ai.IsAltStream =
+ #ifdef SUPPORT_ALT_STREAMS
+ item.IsAltStream;
+ #else
+ false;
+ #endif
+
+ /*
+ if (!storeStreamsMode && ai.IsAltStream)
+ continue;
+ */
+ if (allFilesAreAllowed)
+ ai.Censored = true;
+ else
+ ai.Censored = Censor_CheckPath(censor, item);
+
+ // ai.MTime will be set to archive MTime, if not present in archive item
+ RINOK(arc.GetItem_MTime(i, ai.MTime))
+ RINOK(arc.GetItem_Size(i, ai.Size, ai.Size_Defined))
+
+ ai.IndexInServer = i;
+ arcItems.AddInReserved(ai);
+ }
+ return S_OK;
+}
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <mapi.h>
+#else
+#include <MAPI.h>
+#endif
+
+extern "C" {
+
+#ifdef MAPI_FORCE_UNICODE
+
+#define Z7_WIN_LPMAPISENDMAILW LPMAPISENDMAILW
+#define Z7_WIN_MapiFileDescW MapiFileDescW
+#define Z7_WIN_MapiMessageW MapiMessageW
+#define Z7_WIN_MapiRecipDescW MapiRecipDescW
+
+#else
+
+typedef struct
+{
+ ULONG ulReserved;
+ ULONG ulRecipClass;
+ PWSTR lpszName;
+ PWSTR lpszAddress;
+ ULONG ulEIDSize;
+ PVOID lpEntryID;
+} Z7_WIN_MapiRecipDescW, *Z7_WIN_lpMapiRecipDescW;
+
+typedef struct
+{
+ ULONG ulReserved;
+ ULONG flFlags;
+ ULONG nPosition;
+ PWSTR lpszPathName;
+ PWSTR lpszFileName;
+ PVOID lpFileType;
+} Z7_WIN_MapiFileDescW, *Z7_WIN_lpMapiFileDescW;
+
+typedef struct
+{
+ ULONG ulReserved;
+ PWSTR lpszSubject;
+ PWSTR lpszNoteText;
+ PWSTR lpszMessageType;
+ PWSTR lpszDateReceived;
+ PWSTR lpszConversationID;
+ FLAGS flFlags;
+ Z7_WIN_lpMapiRecipDescW lpOriginator;
+ ULONG nRecipCount;
+ Z7_WIN_lpMapiRecipDescW lpRecips;
+ ULONG nFileCount;
+ Z7_WIN_lpMapiFileDescW lpFiles;
+} Z7_WIN_MapiMessageW, *Z7_WIN_lpMapiMessageW;
+
+typedef ULONG (FAR PASCAL Z7_WIN_MAPISENDMAILW)(
+ LHANDLE lhSession,
+ ULONG_PTR ulUIParam,
+ Z7_WIN_lpMapiMessageW lpMessage,
+ FLAGS flFlags,
+ ULONG ulReserved
+);
+typedef Z7_WIN_MAPISENDMAILW FAR *Z7_WIN_LPMAPISENDMAILW;
+
+#endif // MAPI_FORCE_UNICODE
+}
+#endif // _WIN32
+
+
+HRESULT UpdateArchive(
+ CCodecs *codecs,
+ const CObjectVector<COpenType> &types,
+ const UString &cmdArcPath2,
+ NWildcard::CCensor &censor,
+ CUpdateOptions &options,
+ CUpdateErrorInfo &errorInfo,
+ IOpenCallbackUI *openCallback,
+ IUpdateCallbackUI2 *callback,
+ bool needSetPath)
+{
+ if (options.StdOutMode && options.EMailMode)
+ return E_FAIL;
+
+ if (types.Size() > 1)
+ return E_NOTIMPL;
+
+ bool renameMode = !options.RenamePairs.IsEmpty();
+ if (renameMode)
+ {
+ if (options.Commands.Size() != 1)
+ return E_FAIL;
+ }
+
+ if (options.DeleteAfterCompressing)
+ {
+ if (options.Commands.Size() != 1)
+ return E_NOTIMPL;
+ const CActionSet &as = options.Commands[0].ActionSet;
+ for (unsigned i = 2; i < NPairState::kNumValues; i++)
+ if (as.StateActions[i] != NPairAction::kCompress)
+ return E_NOTIMPL;
+ }
+
+ censor.AddPathsToCensor(options.PathMode);
+ #ifdef _WIN32
+ ConvertToLongNames(censor);
+ #endif
+ censor.ExtendExclude();
+
+
+ if (options.VolumesSizes.Size() > 0 && (options.EMailMode /* || options.SfxMode */))
+ return E_NOTIMPL;
+
+ if (options.SfxMode)
+ {
+ CProperty property;
+ property.Name = "rsfx";
+ options.MethodMode.Properties.Add(property);
+ if (options.SfxModule.IsEmpty())
+ {
+ errorInfo.Message = "SFX file is not specified";
+ return E_FAIL;
+ }
+ bool found = false;
+ if (options.SfxModule.Find(FCHAR_PATH_SEPARATOR) < 0)
+ {
+ const FString fullName = NDLL::GetModuleDirPrefix() + options.SfxModule;
+ if (NFind::DoesFileExist_FollowLink(fullName))
+ {
+ options.SfxModule = fullName;
+ found = true;
+ }
+ }
+ if (!found)
+ {
+ if (!NFind::DoesFileExist_FollowLink(options.SfxModule))
+ return errorInfo.SetFromLastError("cannot find specified SFX module", options.SfxModule);
+ }
+ }
+
+ CArchiveLink arcLink;
+
+
+ if (needSetPath)
+ {
+ if (!options.InitFormatIndex(codecs, types, cmdArcPath2) ||
+ !options.SetArcPath(codecs, cmdArcPath2))
+ return E_NOTIMPL;
+ }
+
+ UString arcPath = options.ArchivePath.GetFinalPath();
+
+ if (!options.VolumesSizes.IsEmpty())
+ {
+ arcPath = options.ArchivePath.GetFinalVolPath();
+ arcPath += ".001";
+ }
+
+ if (cmdArcPath2.IsEmpty())
+ {
+ if (options.MethodMode.Type.FormatIndex < 0)
+ throw "type of archive is not specified";
+ }
+ else
+ {
+ NFind::CFileInfo fi;
+ if (!fi.Find_FollowLink(us2fs(arcPath)))
+ {
+ if (renameMode)
+ throw "can't find archive";
+ if (options.MethodMode.Type.FormatIndex < 0)
+ {
+ if (!options.SetArcPath(codecs, cmdArcPath2))
+ return E_NOTIMPL;
+ }
+ }
+ else
+ {
+ if (fi.IsDir())
+ return errorInfo.SetFromError_DWORD("There is a folder with the name of archive",
+ us2fs(arcPath),
+ #ifdef _WIN32
+ ERROR_ACCESS_DENIED
+ #else
+ EISDIR
+ #endif
+ );
+ #ifdef _WIN32
+ if (fi.IsDevice)
+ return E_NOTIMPL;
+ #endif
+
+ if (!options.StdOutMode && options.UpdateArchiveItself)
+ if (fi.IsReadOnly())
+ {
+ return errorInfo.SetFromError_DWORD("The file is read-only",
+ us2fs(arcPath),
+ #ifdef _WIN32
+ ERROR_ACCESS_DENIED
+ #else
+ EACCES
+ #endif
+ );
+ }
+
+ if (options.VolumesSizes.Size() > 0)
+ {
+ errorInfo.FileNames.Add(us2fs(arcPath));
+ // errorInfo.SystemError = (DWORD)E_NOTIMPL;
+ errorInfo.Message = kUpdateIsNotSupported_MultiVol;
+ return E_NOTIMPL;
+ }
+ CObjectVector<COpenType> types2;
+ // change it.
+ if (options.MethodMode.Type_Defined)
+ types2.Add(options.MethodMode.Type);
+ // We need to set Properties to open archive only in some cases (WIM archives).
+
+ CIntVector excl;
+ COpenOptions op;
+ #ifndef Z7_SFX
+ op.props = &options.MethodMode.Properties;
+ #endif
+ op.codecs = codecs;
+ op.types = &types2;
+ op.excludedFormats = &excl;
+ op.stdInMode = false;
+ op.stream = NULL;
+ op.filePath = arcPath;
+
+ RINOK(callback->StartOpenArchive(arcPath))
+
+ HRESULT result = arcLink.Open_Strict(op, openCallback);
+
+ if (result == E_ABORT)
+ return result;
+
+ HRESULT res2 = callback->OpenResult(codecs, arcLink, arcPath, result);
+ /*
+ if (result == S_FALSE)
+ return E_FAIL;
+ */
+ RINOK(res2)
+ RINOK(result)
+
+ if (arcLink.VolumePaths.Size() > 1)
+ {
+ // errorInfo.SystemError = (DWORD)E_NOTIMPL;
+ errorInfo.Message = kUpdateIsNotSupported_MultiVol;
+ return E_NOTIMPL;
+ }
+
+ CArc &arc = arcLink.Arcs.Back();
+ arc.MTime.Def =
+ #ifdef _WIN32
+ !fi.IsDevice;
+ #else
+ true;
+ #endif
+ if (arc.MTime.Def)
+ arc.MTime.Set_From_FiTime(fi.MTime);
+
+ if (arc.ErrorInfo.ThereIsTail)
+ {
+ // errorInfo.SystemError = (DWORD)E_NOTIMPL;
+ errorInfo.Message = "There is some data block after the end of the archive";
+ return E_NOTIMPL;
+ }
+ if (options.MethodMode.Type.FormatIndex < 0)
+ {
+ options.MethodMode.Type.FormatIndex = arcLink.GetArc()->FormatIndex;
+ if (!options.SetArcPath(codecs, cmdArcPath2))
+ return E_NOTIMPL;
+ }
+ }
+ }
+
+ if (options.MethodMode.Type.FormatIndex < 0)
+ {
+ options.MethodMode.Type.FormatIndex = codecs->FindFormatForArchiveType((UString)kDefaultArcType);
+ if (options.MethodMode.Type.FormatIndex < 0)
+ return E_NOTIMPL;
+ }
+
+ bool thereIsInArchive = arcLink.IsOpen;
+ if (!thereIsInArchive && renameMode)
+ return E_FAIL;
+
+ CDirItems dirItems;
+ dirItems.Callback = callback;
+
+ CDirItem parentDirItem;
+ CDirItem *parentDirItem_Ptr = NULL;
+
+ /*
+ FStringVector requestedPaths;
+ FStringVector *requestedPaths_Ptr = NULL;
+ if (options.DeleteAfterCompressing)
+ requestedPaths_Ptr = &requestedPaths;
+ */
+
+ if (options.StdInMode)
+ {
+ CDirItem di;
+ di.ClearBase();
+ di.Name = options.StdInFileName;
+ di.Size = (UInt64)(Int64)-1;
+ di.SetAsFile();
+ NTime::GetCurUtc_FiTime(di.MTime);
+ di.CTime = di.ATime = di.MTime;
+ dirItems.Items.Add(di);
+ }
+ else
+ {
+ bool needScanning = false;
+
+ if (!renameMode)
+ FOR_VECTOR (i, options.Commands)
+ if (options.Commands[i].ActionSet.NeedScanning())
+ needScanning = true;
+
+ if (needScanning)
+ {
+ RINOK(callback->StartScanning())
+
+ dirItems.SymLinks = options.SymLinks.Val;
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ dirItems.ReadSecure = options.NtSecurity.Val;
+ #endif
+
+ dirItems.ScanAltStreams = options.AltStreams.Val;
+ dirItems.ExcludeDirItems = censor.ExcludeDirItems;
+ dirItems.ExcludeFileItems = censor.ExcludeFileItems;
+
+ dirItems.ShareForWrite = options.OpenShareForWrite;
+
+ #ifndef _WIN32
+ dirItems.StoreOwnerName = options.StoreOwnerName.Val;
+ #endif
+
+ const HRESULT res = EnumerateItems(censor,
+ options.PathMode,
+ UString(), // options.AddPathPrefix,
+ dirItems);
+
+ if (res != S_OK)
+ {
+ if (res != E_ABORT)
+ errorInfo.Message = "Scanning error";
+ return res;
+ }
+
+ RINOK(callback->FinishScanning(dirItems.Stat))
+
+ // 22.00: we don't need parent folder, if absolute path mode
+ if (options.PathMode != NWildcard::k_AbsPath)
+ if (censor.Pairs.Size() == 1)
+ {
+ NFind::CFileInfo fi;
+ FString prefix = us2fs(censor.Pairs[0].Prefix);
+ prefix.Add_Dot();
+ // UString prefix = censor.Pairs[0].Prefix;
+ /*
+ if (prefix.Back() == WCHAR_PATH_SEPARATOR)
+ {
+ prefix.DeleteBack();
+ }
+ */
+ if (fi.Find(prefix))
+ if (fi.IsDir())
+ {
+ parentDirItem.Copy_From_FileInfoBase(fi);
+ parentDirItem_Ptr = &parentDirItem;
+
+ int secureIndex = -1;
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (options.NtSecurity.Val)
+ dirItems.AddSecurityItem(prefix, secureIndex);
+ #endif
+ parentDirItem.SecureIndex = secureIndex;
+ }
+ }
+ }
+ }
+
+ FString tempDirPrefix;
+ bool usesTempDir = false;
+
+ #ifdef _WIN32
+ CTempDir tempDirectory;
+ if (options.EMailMode && options.EMailRemoveAfter)
+ {
+ tempDirectory.Create(kTempFolderPrefix);
+ tempDirPrefix = tempDirectory.GetPath();
+ NormalizeDirPathPrefix(tempDirPrefix);
+ usesTempDir = true;
+ }
+ #endif
+
+ CTempFiles tempFiles;
+
+ bool createTempFile = false;
+
+ if (!options.StdOutMode && options.UpdateArchiveItself)
+ {
+ CArchivePath &ap = options.Commands[0].ArchivePath;
+ ap = options.ArchivePath;
+ // if ((archive != 0 && !usesTempDir) || !options.WorkingDir.IsEmpty())
+ if ((thereIsInArchive || !options.WorkingDir.IsEmpty()) && !usesTempDir && options.VolumesSizes.Size() == 0)
+ {
+ createTempFile = true;
+ ap.Temp = true;
+ if (!options.WorkingDir.IsEmpty())
+ ap.TempPrefix = options.WorkingDir;
+ else
+ ap.TempPrefix = us2fs(ap.Prefix);
+ NormalizeDirPathPrefix(ap.TempPrefix);
+ }
+ }
+
+ unsigned ci;
+
+
+ // self including protection
+ if (options.DeleteAfterCompressing)
+ {
+ for (ci = 0; ci < options.Commands.Size(); ci++)
+ {
+ CArchivePath &ap = options.Commands[ci].ArchivePath;
+ const FString path = us2fs(ap.GetFinalPath());
+ // maybe we must compare absolute paths path here
+ FOR_VECTOR (i, dirItems.Items)
+ {
+ const FString phyPath = dirItems.GetPhyPath(i);
+ if (phyPath == path)
+ {
+ UString s;
+ s = "It is not allowed to include archive to itself";
+ s.Add_LF();
+ s += fs2us(path);
+ throw s;
+ }
+ }
+ }
+ }
+
+
+ for (ci = 0; ci < options.Commands.Size(); ci++)
+ {
+ CArchivePath &ap = options.Commands[ci].ArchivePath;
+ if (usesTempDir)
+ {
+ // Check it
+ ap.Prefix = fs2us(tempDirPrefix);
+ // ap.Temp = true;
+ // ap.TempPrefix = tempDirPrefix;
+ }
+ if (!options.StdOutMode &&
+ (ci > 0 || !createTempFile))
+ {
+ const FString path = us2fs(ap.GetFinalPath());
+ if (NFind::DoesFileOrDirExist(path))
+ {
+ errorInfo.SystemError = ERROR_FILE_EXISTS;
+ errorInfo.Message = "The file already exists";
+ errorInfo.FileNames.Add(path);
+ return errorInfo.Get_HRESULT_Error();
+ }
+ }
+ }
+
+ CObjectVector<CArcItem> arcItems;
+ if (thereIsInArchive)
+ {
+ RINOK(EnumerateInArchiveItems(
+ // options.StoreAltStreams,
+ censor, arcLink.Arcs.Back(), arcItems))
+ }
+
+ /*
+ FStringVector processedFilePaths;
+ FStringVector *processedFilePaths_Ptr = NULL;
+ if (options.DeleteAfterCompressing)
+ processedFilePaths_Ptr = &processedFilePaths;
+ */
+
+ CByteBuffer processedItems;
+ if (options.DeleteAfterCompressing)
+ {
+ const unsigned num = dirItems.Items.Size();
+ processedItems.Alloc(num);
+ for (unsigned i = 0; i < num; i++)
+ processedItems[i] = 0;
+ }
+
+ CMultiOutStream_Bunch multiStreams;
+
+ /*
+ #ifndef Z7_NO_CRYPTO
+ if (arcLink.PasswordWasAsked)
+ {
+ // We set password, if open have requested password
+ RINOK(callback->SetPassword(arcLink.Password));
+ }
+ #endif
+ */
+
+ for (ci = 0; ci < options.Commands.Size(); ci++)
+ {
+ const CArc *arc = thereIsInArchive ? arcLink.GetArc() : NULL;
+ CUpdateArchiveCommand &command = options.Commands[ci];
+ UString name;
+ bool isUpdating;
+
+ if (options.StdOutMode)
+ {
+ name = "stdout";
+ isUpdating = thereIsInArchive;
+ }
+ else
+ {
+ name = command.ArchivePath.GetFinalPath();
+ isUpdating = (ci == 0 && options.UpdateArchiveItself && thereIsInArchive);
+ }
+
+ RINOK(callback->StartArchive(name, isUpdating))
+
+ CFinishArchiveStat st;
+
+ RINOK(Compress(options,
+ isUpdating,
+ codecs,
+ command.ActionSet,
+ arc,
+ command.ArchivePath,
+ arcItems,
+ options.DeleteAfterCompressing ? (Byte *)processedItems : NULL,
+
+ dirItems,
+ parentDirItem_Ptr,
+
+ tempFiles,
+ multiStreams,
+ errorInfo, callback, st))
+
+ RINOK(callback->FinishArchive(st))
+ }
+
+
+ if (thereIsInArchive)
+ {
+ RINOK(arcLink.Close())
+ arcLink.Release();
+ }
+
+ multiStreams.DisableDeletion();
+ RINOK(multiStreams.Destruct())
+
+ tempFiles.Paths.Clear();
+ if (createTempFile)
+ {
+ try
+ {
+ CArchivePath &ap = options.Commands[0].ArchivePath;
+ const FString &tempPath = ap.GetTempPath();
+
+ // DWORD attrib = 0;
+ if (thereIsInArchive)
+ {
+ // attrib = NFind::GetFileAttrib(us2fs(arcPath));
+ if (!DeleteFileAlways(us2fs(arcPath)))
+ return errorInfo.SetFromLastError("cannot delete the file", us2fs(arcPath));
+ }
+
+ if (!MyMoveFile(tempPath, us2fs(arcPath)))
+ {
+ errorInfo.SetFromLastError("cannot move the file", tempPath);
+ errorInfo.FileNames.Add(us2fs(arcPath));
+ return errorInfo.Get_HRESULT_Error();
+ }
+
+ /*
+ if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY))
+ {
+ DWORD attrib2 = NFind::GetFileAttrib(us2fs(arcPath));
+ if (attrib2 != INVALID_FILE_ATTRIBUTES)
+ NDir::SetFileAttrib(us2fs(arcPath), attrib2 | FILE_ATTRIBUTE_READONLY);
+ }
+ */
+ }
+ catch(...)
+ {
+ throw;
+ }
+ }
+
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+
+ if (options.EMailMode)
+ {
+ NDLL::CLibrary mapiLib;
+ if (!mapiLib.Load(FTEXT("Mapi32.dll")))
+ {
+ errorInfo.SetFromLastError("cannot load Mapi32.dll");
+ return errorInfo.Get_HRESULT_Error();
+ }
+
+ FStringVector fullPaths;
+ unsigned i;
+
+ for (i = 0; i < options.Commands.Size(); i++)
+ {
+ CArchivePath &ap = options.Commands[i].ArchivePath;
+ const FString finalPath = us2fs(ap.GetFinalPath());
+ FString arcPath2;
+ if (!MyGetFullPathName(finalPath, arcPath2))
+ return errorInfo.SetFromLastError("GetFullPathName error", finalPath);
+ fullPaths.Add(arcPath2);
+ }
+
+ /*
+ LPMAPISENDDOCUMENTS fnSend = (LPMAPISENDDOCUMENTS)mapiLib.GetProc("MAPISendDocuments");
+ if (fnSend == 0)
+ {
+ errorInfo.SetFromLastError)("7-Zip cannot find MAPISendDocuments function");
+ return errorInfo.Get_HRESULT_Error();
+ }
+ */
+ const
+ Z7_WIN_LPMAPISENDMAILW sendMailW = Z7_GET_PROC_ADDRESS(
+ Z7_WIN_LPMAPISENDMAILW, mapiLib.Get_HMODULE(),
+ "MAPISendMailW");
+ if (sendMailW)
+ {
+
+ CCurrentDirRestorer curDirRestorer;
+
+ UStringVector paths;
+ UStringVector names;
+
+ for (i = 0; i < fullPaths.Size(); i++)
+ {
+ const UString arcPath2 = fs2us(fullPaths[i]);
+ const UString fileName = ExtractFileNameFromPath(arcPath2);
+ paths.Add(arcPath2);
+ names.Add(fileName);
+ // Warning!!! MAPISendDocuments function changes Current directory
+ // fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0);
+ }
+
+ CRecordVector<Z7_WIN_MapiFileDescW> files;
+ files.ClearAndSetSize(paths.Size());
+
+ for (i = 0; i < paths.Size(); i++)
+ {
+ Z7_WIN_MapiFileDescW &f = files[i];
+ memset(&f, 0, sizeof(f));
+ f.nPosition = 0xFFFFFFFF;
+ f.lpszPathName = paths[i].Ptr_non_const();
+ f.lpszFileName = names[i].Ptr_non_const();
+ }
+
+ {
+ Z7_WIN_MapiMessageW m;
+ memset(&m, 0, sizeof(m));
+ m.nFileCount = files.Size();
+ m.lpFiles = &files.Front();
+
+ const UString addr (options.EMailAddress);
+ Z7_WIN_MapiRecipDescW rec;
+ if (!addr.IsEmpty())
+ {
+ memset(&rec, 0, sizeof(rec));
+ rec.ulRecipClass = MAPI_TO;
+ rec.lpszAddress = addr.Ptr_non_const();
+ m.nRecipCount = 1;
+ m.lpRecips = &rec;
+ }
+
+ sendMailW((LHANDLE)0, 0, &m, MAPI_DIALOG, 0);
+ }
+ }
+ else
+ {
+ const
+ LPMAPISENDMAIL sendMail = Z7_GET_PROC_ADDRESS(
+ LPMAPISENDMAIL, mapiLib.Get_HMODULE(),
+ "MAPISendMail");
+ if (!sendMail)
+ {
+ errorInfo.SetFromLastError("7-Zip cannot find MAPISendMail function");
+ return errorInfo.Get_HRESULT_Error();
+ }
+
+ CCurrentDirRestorer curDirRestorer;
+
+ AStringVector paths;
+ AStringVector names;
+
+ for (i = 0; i < fullPaths.Size(); i++)
+ {
+ const UString arcPath2 = fs2us(fullPaths[i]);
+ const UString fileName = ExtractFileNameFromPath(arcPath2);
+ paths.Add(GetAnsiString(arcPath2));
+ names.Add(GetAnsiString(fileName));
+ // const AString path (GetAnsiString(arcPath2));
+ // const AString name (GetAnsiString(fileName));
+ // Warning!!! MAPISendDocuments function changes Current directory
+ // fnSend(0, ";", (LPSTR)(LPCSTR)path, (LPSTR)(LPCSTR)name, 0);
+ }
+
+ CRecordVector<MapiFileDesc> files;
+ files.ClearAndSetSize(paths.Size());
+
+ for (i = 0; i < paths.Size(); i++)
+ {
+ MapiFileDesc &f = files[i];
+ memset(&f, 0, sizeof(f));
+ f.nPosition = 0xFFFFFFFF;
+ f.lpszPathName = paths[i].Ptr_non_const();
+ f.lpszFileName = names[i].Ptr_non_const();
+ }
+
+ {
+ MapiMessage m;
+ memset(&m, 0, sizeof(m));
+ m.nFileCount = files.Size();
+ m.lpFiles = &files.Front();
+
+ const AString addr (GetAnsiString(options.EMailAddress));
+ MapiRecipDesc rec;
+ if (!addr.IsEmpty())
+ {
+ memset(&rec, 0, sizeof(rec));
+ rec.ulRecipClass = MAPI_TO;
+ rec.lpszAddress = addr.Ptr_non_const();
+ m.nRecipCount = 1;
+ m.lpRecips = &rec;
+ }
+
+ sendMail((LHANDLE)0, 0, &m, MAPI_DIALOG, 0);
+ }
+ }
+ }
+
+ #endif
+
+ if (options.DeleteAfterCompressing)
+ {
+ CRecordVector<CDirPathSortPair> pairs;
+ FStringVector foldersNames;
+
+ unsigned i;
+
+ for (i = 0; i < dirItems.Items.Size(); i++)
+ {
+ const CDirItem &dirItem = dirItems.Items[i];
+ const FString phyPath = dirItems.GetPhyPath(i);
+ if (dirItem.IsDir())
+ {
+ CDirPathSortPair pair;
+ pair.Index = i;
+ pair.SetNumSlashes(phyPath);
+ pairs.Add(pair);
+ }
+ else
+ {
+ // 21.04: we have set processedItems[*] before for all required items
+ if (processedItems[i] != 0
+ // || dirItem.Size == 0
+ // || dirItem.AreReparseData()
+ )
+ {
+ NFind::CFileInfo fileInfo;
+ /* if (!SymLinks), we follow link here, similar to (dirItem) filling */
+ if (fileInfo.Find(phyPath, !options.SymLinks.Val))
+ {
+ bool is_SameSize = false;
+ if (options.SymLinks.Val && dirItem.AreReparseData())
+ {
+ /* (dirItem.Size = dirItem.ReparseData.Size()) was set before.
+ So we don't compare sizes for that case here */
+ is_SameSize = fileInfo.IsOsSymLink();
+ }
+ else
+ is_SameSize = (fileInfo.Size == dirItem.Size);
+
+ if (is_SameSize
+ && Compare_FiTime(&fileInfo.MTime, &dirItem.MTime) == 0
+ && Compare_FiTime(&fileInfo.CTime, &dirItem.CTime) == 0)
+ {
+ RINOK(callback->DeletingAfterArchiving(phyPath, false))
+ DeleteFileAlways(phyPath);
+ }
+ }
+ }
+ else
+ {
+ // file was skipped by some reason. We can throw error for debug:
+ /*
+ errorInfo.SystemError = 0;
+ errorInfo.Message = "file was not processed";
+ errorInfo.FileNames.Add(phyPath);
+ return E_FAIL;
+ */
+ }
+ }
+ }
+
+ pairs.Sort2();
+
+ for (i = 0; i < pairs.Size(); i++)
+ {
+ const FString phyPath = dirItems.GetPhyPath(pairs[i].Index);
+ if (NFind::DoesDirExist(phyPath))
+ {
+ RINOK(callback->DeletingAfterArchiving(phyPath, true))
+ RemoveDir(phyPath);
+ }
+ }
+
+ RINOK(callback->FinishDeletingAfterArchiving())
+ }
+
+ return S_OK;
+}
diff --git a/CPP/7zip/UI/Common/Update.h b/CPP/7zip/UI/Common/Update.h
index 45b02d7..a9459ff 100644
--- a/CPP/7zip/UI/Common/Update.h
+++ b/CPP/7zip/UI/Common/Update.h
@@ -1,200 +1,218 @@
-// Update.h
-
-#ifndef __COMMON_UPDATE_H
-#define __COMMON_UPDATE_H
-
-#include "../../../Common/Wildcard.h"
-
-#include "ArchiveOpenCallback.h"
-#include "LoadCodecs.h"
-#include "OpenArchive.h"
-#include "Property.h"
-#include "UpdateAction.h"
-#include "UpdateCallback.h"
-
-#include "DirItem.h"
-
-enum EArcNameMode
-{
- k_ArcNameMode_Smart,
- k_ArcNameMode_Exact,
- k_ArcNameMode_Add,
-};
-
-struct CArchivePath
-{
- UString OriginalPath;
-
- UString Prefix; // path(folder) prefix including slash
- UString Name; // base name
- UString BaseExtension; // archive type extension or "exe" extension
- UString VolExtension; // archive type extension for volumes
-
- bool Temp;
- FString TempPrefix; // path(folder) for temp location
- FString TempPostfix;
-
- CArchivePath(): Temp(false) {};
-
- void ParseFromPath(const UString &path, EArcNameMode mode);
- UString GetPathWithoutExt() const { return Prefix + Name; }
- UString GetFinalPath() const;
- UString GetFinalVolPath() const;
- FString GetTempPath() const;
-};
-
-struct CUpdateArchiveCommand
-{
- UString UserArchivePath;
- CArchivePath ArchivePath;
- NUpdateArchive::CActionSet ActionSet;
-};
-
-struct CCompressionMethodMode
-{
- bool Type_Defined;
- COpenType Type;
- CObjectVector<CProperty> Properties;
-
- CCompressionMethodMode(): Type_Defined(false) {}
-};
-
-namespace NRecursedType { enum EEnum
-{
- kRecursed,
- kWildcardOnlyRecursed,
- kNonRecursed
-};}
-
-struct CRenamePair
-{
- UString OldName;
- UString NewName;
- bool WildcardParsing;
- NRecursedType::EEnum RecursedType;
-
- CRenamePair(): WildcardParsing(true), RecursedType(NRecursedType::kNonRecursed) {}
-
- bool Prepare();
- bool GetNewPath(bool isFolder, const UString &src, UString &dest) const;
-};
-
-struct CUpdateOptions
-{
- CCompressionMethodMode MethodMode;
-
- CObjectVector<CUpdateArchiveCommand> Commands;
- bool UpdateArchiveItself;
- CArchivePath ArchivePath;
- EArcNameMode ArcNameMode;
-
- bool SfxMode;
- FString SfxModule;
-
- bool OpenShareForWrite;
- bool StopAfterOpenError;
-
- bool StdInMode;
- UString StdInFileName;
- bool StdOutMode;
-
- bool EMailMode;
- bool EMailRemoveAfter;
- UString EMailAddress;
-
- FString WorkingDir;
- NWildcard::ECensorPathMode PathMode;
- UString AddPathPrefix;
-
- CBoolPair NtSecurity;
- CBoolPair AltStreams;
- CBoolPair HardLinks;
- CBoolPair SymLinks;
-
- bool DeleteAfterCompressing;
-
- bool SetArcMTime;
-
- CObjectVector<CRenamePair> RenamePairs;
-
- bool InitFormatIndex(const CCodecs *codecs, const CObjectVector<COpenType> &types, const UString &arcPath);
- bool SetArcPath(const CCodecs *codecs, const UString &arcPath);
-
- CUpdateOptions():
- UpdateArchiveItself(true),
- SfxMode(false),
- StdInMode(false),
- StdOutMode(false),
- EMailMode(false),
- EMailRemoveAfter(false),
- OpenShareForWrite(false),
- StopAfterOpenError(false),
- ArcNameMode(k_ArcNameMode_Smart),
- PathMode(NWildcard::k_RelatPath),
-
- DeleteAfterCompressing(false),
- SetArcMTime(false)
-
- {};
-
- void SetActionCommand_Add()
- {
- Commands.Clear();
- CUpdateArchiveCommand c;
- c.ActionSet = NUpdateArchive::k_ActionSet_Add;
- Commands.Add(c);
- }
-
- CRecordVector<UInt64> VolumesSizes;
-};
-
-struct CUpdateErrorInfo
-{
- DWORD SystemError;
- AString Message;
- FStringVector FileNames;
-
- bool ThereIsError() const { return SystemError != 0 || !Message.IsEmpty() || !FileNames.IsEmpty(); }
- HRESULT Get_HRESULT_Error() const { return SystemError == 0 ? E_FAIL : HRESULT_FROM_WIN32(SystemError); }
- void SetFromLastError(const char *message);
- HRESULT SetFromLastError(const char *message, const FString &fileName);
-
- CUpdateErrorInfo(): SystemError(0) {};
-};
-
-struct CFinishArchiveStat
-{
- UInt64 OutArcFileSize;
-
- CFinishArchiveStat(): OutArcFileSize(0) {}
-};
-
-#define INTERFACE_IUpdateCallbackUI2(x) \
- INTERFACE_IUpdateCallbackUI(x) \
- INTERFACE_IDirItemsCallback(x) \
- virtual HRESULT OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) x; \
- virtual HRESULT StartScanning() x; \
- virtual HRESULT FinishScanning(const CDirItemsStat &st) x; \
- virtual HRESULT StartOpenArchive(const wchar_t *name) x; \
- virtual HRESULT StartArchive(const wchar_t *name, bool updating) x; \
- virtual HRESULT FinishArchive(const CFinishArchiveStat &st) x; \
- virtual HRESULT DeletingAfterArchiving(const FString &path, bool isDir) x; \
- virtual HRESULT FinishDeletingAfterArchiving() x; \
-
-struct IUpdateCallbackUI2: public IUpdateCallbackUI, public IDirItemsCallback
-{
- INTERFACE_IUpdateCallbackUI2(=0)
-};
-
-HRESULT UpdateArchive(
- CCodecs *codecs,
- const CObjectVector<COpenType> &types,
- const UString &cmdArcPath2,
- NWildcard::CCensor &censor,
- CUpdateOptions &options,
- CUpdateErrorInfo &errorInfo,
- IOpenCallbackUI *openCallback,
- IUpdateCallbackUI2 *callback,
- bool needSetPath);
-
-#endif
+// Update.h
+
+#ifndef ZIP7_INC_COMMON_UPDATE_H
+#define ZIP7_INC_COMMON_UPDATE_H
+
+#include "../../../Common/Wildcard.h"
+
+#include "ArchiveOpenCallback.h"
+#include "LoadCodecs.h"
+#include "OpenArchive.h"
+#include "Property.h"
+#include "UpdateAction.h"
+#include "UpdateCallback.h"
+
+#include "DirItem.h"
+
+enum EArcNameMode
+{
+ k_ArcNameMode_Smart,
+ k_ArcNameMode_Exact,
+ k_ArcNameMode_Add
+};
+
+struct CArchivePath
+{
+ UString OriginalPath;
+
+ UString Prefix; // path(folder) prefix including slash
+ UString Name; // base name
+ UString BaseExtension; // archive type extension or "exe" extension
+ UString VolExtension; // archive type extension for volumes
+
+ bool Temp;
+ FString TempPrefix; // path(folder) for temp location
+ FString TempPostfix;
+
+ CArchivePath(): Temp(false) {}
+
+ void ParseFromPath(const UString &path, EArcNameMode mode);
+ UString GetPathWithoutExt() const { return Prefix + Name; }
+ UString GetFinalPath() const;
+ UString GetFinalVolPath() const;
+ FString GetTempPath() const;
+};
+
+struct CUpdateArchiveCommand
+{
+ UString UserArchivePath;
+ CArchivePath ArchivePath;
+ NUpdateArchive::CActionSet ActionSet;
+};
+
+struct CCompressionMethodMode
+{
+ bool Type_Defined;
+ COpenType Type;
+ CObjectVector<CProperty> Properties;
+
+ CCompressionMethodMode(): Type_Defined(false) {}
+};
+
+namespace NRecursedType { enum EEnum
+{
+ kRecursed,
+ kWildcardOnlyRecursed,
+ kNonRecursed
+};}
+
+struct CRenamePair
+{
+ UString OldName;
+ UString NewName;
+ bool WildcardParsing;
+ NRecursedType::EEnum RecursedType;
+
+ CRenamePair(): WildcardParsing(true), RecursedType(NRecursedType::kNonRecursed) {}
+
+ bool Prepare();
+ bool GetNewPath(bool isFolder, const UString &src, UString &dest) const;
+};
+
+struct CUpdateOptions
+{
+ bool UpdateArchiveItself;
+ bool SfxMode;
+
+ bool PreserveATime;
+ bool OpenShareForWrite;
+ bool StopAfterOpenError;
+
+ bool StdInMode;
+ bool StdOutMode;
+
+ bool EMailMode;
+ bool EMailRemoveAfter;
+
+ bool DeleteAfterCompressing;
+ bool SetArcMTime;
+
+ CBoolPair NtSecurity;
+ CBoolPair AltStreams;
+ CBoolPair HardLinks;
+ CBoolPair SymLinks;
+
+ CBoolPair StoreOwnerId;
+ CBoolPair StoreOwnerName;
+
+ EArcNameMode ArcNameMode;
+ NWildcard::ECensorPathMode PathMode;
+
+ CCompressionMethodMode MethodMode;
+
+ CObjectVector<CUpdateArchiveCommand> Commands;
+ CArchivePath ArchivePath;
+
+ FString SfxModule;
+ UString StdInFileName;
+ UString EMailAddress;
+ FString WorkingDir;
+ // UString AddPathPrefix;
+
+ CObjectVector<CRenamePair> RenamePairs;
+ CRecordVector<UInt64> VolumesSizes;
+
+ bool InitFormatIndex(const CCodecs *codecs, const CObjectVector<COpenType> &types, const UString &arcPath);
+ bool SetArcPath(const CCodecs *codecs, const UString &arcPath);
+
+ CUpdateOptions():
+ UpdateArchiveItself(true),
+ SfxMode(false),
+
+ PreserveATime(false),
+ OpenShareForWrite(false),
+ StopAfterOpenError(false),
+
+ StdInMode(false),
+ StdOutMode(false),
+
+ EMailMode(false),
+ EMailRemoveAfter(false),
+
+ DeleteAfterCompressing(false),
+ SetArcMTime(false),
+
+ ArcNameMode(k_ArcNameMode_Smart),
+ PathMode(NWildcard::k_RelatPath)
+
+ {}
+
+ void SetActionCommand_Add()
+ {
+ Commands.Clear();
+ CUpdateArchiveCommand c;
+ c.ActionSet = NUpdateArchive::k_ActionSet_Add;
+ Commands.Add(c);
+ }
+};
+
+
+struct CUpdateErrorInfo
+{
+ DWORD SystemError; // it's DWORD (WRes) only;
+ AString Message;
+ FStringVector FileNames;
+
+ bool ThereIsError() const { return SystemError != 0 || !Message.IsEmpty() || !FileNames.IsEmpty(); }
+ HRESULT Get_HRESULT_Error() const { return SystemError == 0 ? E_FAIL : HRESULT_FROM_WIN32(SystemError); }
+ void SetFromLastError(const char *message);
+ HRESULT SetFromLastError(const char *message, const FString &fileName);
+ HRESULT SetFromError_DWORD(const char *message, const FString &fileName, DWORD error);
+
+ CUpdateErrorInfo(): SystemError(0) {}
+};
+
+struct CFinishArchiveStat
+{
+ UInt64 OutArcFileSize;
+ unsigned NumVolumes;
+ bool IsMultiVolMode;
+
+ CFinishArchiveStat(): OutArcFileSize(0), NumVolumes(0), IsMultiVolMode(false) {}
+};
+
+Z7_PURE_INTERFACES_BEGIN
+
+// INTERFACE_IUpdateCallbackUI(x)
+// INTERFACE_IDirItemsCallback(x)
+
+#define Z7_IFACEN_IUpdateCallbackUI2(x) \
+ virtual HRESULT OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result) x \
+ virtual HRESULT StartScanning() x \
+ virtual HRESULT FinishScanning(const CDirItemsStat &st) x \
+ virtual HRESULT StartOpenArchive(const wchar_t *name) x \
+ virtual HRESULT StartArchive(const wchar_t *name, bool updating) x \
+ virtual HRESULT FinishArchive(const CFinishArchiveStat &st) x \
+ virtual HRESULT DeletingAfterArchiving(const FString &path, bool isDir) x \
+ virtual HRESULT FinishDeletingAfterArchiving() x \
+
+DECLARE_INTERFACE(IUpdateCallbackUI2):
+ public IUpdateCallbackUI,
+ public IDirItemsCallback
+{
+ Z7_IFACE_PURE(IUpdateCallbackUI2)
+};
+Z7_PURE_INTERFACES_END
+
+HRESULT UpdateArchive(
+ CCodecs *codecs,
+ const CObjectVector<COpenType> &types,
+ const UString &cmdArcPath2,
+ NWildcard::CCensor &censor,
+ CUpdateOptions &options,
+ CUpdateErrorInfo &errorInfo,
+ IOpenCallbackUI *openCallback,
+ IUpdateCallbackUI2 *callback,
+ bool needSetPath);
+
+#endif
diff --git a/CPP/7zip/UI/Common/UpdateAction.cpp b/CPP/7zip/UI/Common/UpdateAction.cpp
index ba138d2..a80db72 100644
--- a/CPP/7zip/UI/Common/UpdateAction.cpp
+++ b/CPP/7zip/UI/Common/UpdateAction.cpp
@@ -1,64 +1,64 @@
-// UpdateAction.cpp
-
-#include "StdAfx.h"
-
-#include "UpdateAction.h"
-
-namespace NUpdateArchive {
-
-const CActionSet k_ActionSet_Add =
-{{
- NPairAction::kCopy,
- NPairAction::kCopy,
- NPairAction::kCompress,
- NPairAction::kCompress,
- NPairAction::kCompress,
- NPairAction::kCompress,
- NPairAction::kCompress
-}};
-
-const CActionSet k_ActionSet_Update =
-{{
- NPairAction::kCopy,
- NPairAction::kCopy,
- NPairAction::kCompress,
- NPairAction::kCopy,
- NPairAction::kCompress,
- NPairAction::kCopy,
- NPairAction::kCompress
-}};
-
-const CActionSet k_ActionSet_Fresh =
-{{
- NPairAction::kCopy,
- NPairAction::kCopy,
- NPairAction::kIgnore,
- NPairAction::kCopy,
- NPairAction::kCompress,
- NPairAction::kCopy,
- NPairAction::kCompress
-}};
-
-const CActionSet k_ActionSet_Sync =
-{{
- NPairAction::kCopy,
- NPairAction::kIgnore,
- NPairAction::kCompress,
- NPairAction::kCopy,
- NPairAction::kCompress,
- NPairAction::kCopy,
- NPairAction::kCompress,
-}};
-
-const CActionSet k_ActionSet_Delete =
-{{
- NPairAction::kCopy,
- NPairAction::kIgnore,
- NPairAction::kIgnore,
- NPairAction::kIgnore,
- NPairAction::kIgnore,
- NPairAction::kIgnore,
- NPairAction::kIgnore
-}};
-
-}
+// UpdateAction.cpp
+
+#include "StdAfx.h"
+
+#include "UpdateAction.h"
+
+namespace NUpdateArchive {
+
+const CActionSet k_ActionSet_Add =
+{{
+ NPairAction::kCopy,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCompress,
+ NPairAction::kCompress,
+ NPairAction::kCompress,
+ NPairAction::kCompress
+}};
+
+const CActionSet k_ActionSet_Update =
+{{
+ NPairAction::kCopy,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress
+}};
+
+const CActionSet k_ActionSet_Fresh =
+{{
+ NPairAction::kCopy,
+ NPairAction::kCopy,
+ NPairAction::kIgnore,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress
+}};
+
+const CActionSet k_ActionSet_Sync =
+{{
+ NPairAction::kCopy,
+ NPairAction::kIgnore,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+ NPairAction::kCopy,
+ NPairAction::kCompress,
+}};
+
+const CActionSet k_ActionSet_Delete =
+{{
+ NPairAction::kCopy,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore,
+ NPairAction::kIgnore
+}};
+
+}
diff --git a/CPP/7zip/UI/Common/UpdateAction.h b/CPP/7zip/UI/Common/UpdateAction.h
index 8d6002f..6a3565e 100644
--- a/CPP/7zip/UI/Common/UpdateAction.h
+++ b/CPP/7zip/UI/Common/UpdateAction.h
@@ -1,66 +1,66 @@
-// UpdateAction.h
-
-#ifndef __UPDATE_ACTION_H
-#define __UPDATE_ACTION_H
-
-namespace NUpdateArchive {
-
- namespace NPairState
- {
- const unsigned kNumValues = 7;
- enum EEnum
- {
- kNotMasked = 0,
- kOnlyInArchive,
- kOnlyOnDisk,
- kNewInArchive,
- kOldInArchive,
- kSameFiles,
- kUnknowNewerFiles
- };
- }
-
- namespace NPairAction
- {
- enum EEnum
- {
- kIgnore = 0,
- kCopy,
- kCompress,
- kCompressAsAnti
- };
- }
-
- struct CActionSet
- {
- NPairAction::EEnum StateActions[NPairState::kNumValues];
-
- bool IsEqualTo(const CActionSet &a) const
- {
- for (unsigned i = 0; i < NPairState::kNumValues; i++)
- if (StateActions[i] != a.StateActions[i])
- return false;
- return true;
- }
-
- bool NeedScanning() const
- {
- unsigned i;
- for (i = 0; i < NPairState::kNumValues; i++)
- if (StateActions[i] == NPairAction::kCompress)
- return true;
- for (i = 1; i < NPairState::kNumValues; i++)
- if (StateActions[i] != NPairAction::kIgnore)
- return true;
- return false;
- }
- };
-
- extern const CActionSet k_ActionSet_Add;
- extern const CActionSet k_ActionSet_Update;
- extern const CActionSet k_ActionSet_Fresh;
- extern const CActionSet k_ActionSet_Sync;
- extern const CActionSet k_ActionSet_Delete;
-}
-
-#endif
+// UpdateAction.h
+
+#ifndef ZIP7_INC_UPDATE_ACTION_H
+#define ZIP7_INC_UPDATE_ACTION_H
+
+namespace NUpdateArchive {
+
+ namespace NPairState
+ {
+ const unsigned kNumValues = 7;
+ enum EEnum
+ {
+ kNotMasked = 0,
+ kOnlyInArchive,
+ kOnlyOnDisk,
+ kNewInArchive,
+ kOldInArchive,
+ kSameFiles,
+ kUnknowNewerFiles
+ };
+ }
+
+ namespace NPairAction
+ {
+ enum EEnum
+ {
+ kIgnore = 0,
+ kCopy,
+ kCompress,
+ kCompressAsAnti
+ };
+ }
+
+ struct CActionSet
+ {
+ NPairAction::EEnum StateActions[NPairState::kNumValues];
+
+ bool IsEqualTo(const CActionSet &a) const
+ {
+ for (unsigned i = 0; i < NPairState::kNumValues; i++)
+ if (StateActions[i] != a.StateActions[i])
+ return false;
+ return true;
+ }
+
+ bool NeedScanning() const
+ {
+ unsigned i;
+ for (i = 0; i < NPairState::kNumValues; i++)
+ if (StateActions[i] == NPairAction::kCompress)
+ return true;
+ for (i = 1; i < NPairState::kNumValues; i++)
+ if (StateActions[i] != NPairAction::kIgnore)
+ return true;
+ return false;
+ }
+ };
+
+ extern const CActionSet k_ActionSet_Add;
+ extern const CActionSet k_ActionSet_Update;
+ extern const CActionSet k_ActionSet_Fresh;
+ extern const CActionSet k_ActionSet_Sync;
+ extern const CActionSet k_ActionSet_Delete;
+}
+
+#endif
diff --git a/CPP/7zip/UI/Common/UpdateCallback.cpp b/CPP/7zip/UI/Common/UpdateCallback.cpp
index 9c165fe..5e2860d 100644
--- a/CPP/7zip/UI/Common/UpdateCallback.cpp
+++ b/CPP/7zip/UI/Common/UpdateCallback.cpp
@@ -1,771 +1,1026 @@
-// UpdateCallback.cpp
-
-#include "StdAfx.h"
-
-#ifndef _7ZIP_ST
-#include "../../../Windows/Synchronization.h"
-#endif
-
-#include "../../../Common/ComTry.h"
-#include "../../../Common/IntToString.h"
-#include "../../../Common/StringConvert.h"
-#include "../../../Common/Wildcard.h"
-
-#include "../../../Windows/FileDir.h"
-#include "../../../Windows/FileName.h"
-#include "../../../Windows/PropVariant.h"
-
-#include "../../Common/StreamObjects.h"
-
-#include "UpdateCallback.h"
-
-#if defined(_WIN32) && !defined(UNDER_CE)
-#define _USE_SECURITY_CODE
-#include "../../../Windows/SecurityUtils.h"
-#endif
-
-using namespace NWindows;
-using namespace NFile;
-
-#ifndef _7ZIP_ST
-static NSynchronization::CCriticalSection g_CriticalSection;
-#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
-#else
-#define MT_LOCK
-#endif
-
-
-#ifdef _USE_SECURITY_CODE
-bool InitLocalPrivileges();
-#endif
-
-CArchiveUpdateCallback::CArchiveUpdateCallback():
- _hardIndex_From((UInt32)(Int32)-1),
-
- Callback(NULL),
-
- DirItems(NULL),
- ParentDirItem(NULL),
-
- Arc(NULL),
- ArcItems(NULL),
- UpdatePairs(NULL),
- NewNames(NULL),
- CommentIndex(-1),
- Comment(NULL),
-
- ShareForWrite(false),
- StopAfterOpenError(false),
- StdInMode(false),
-
- KeepOriginalItemNames(false),
- StoreNtSecurity(false),
- StoreHardLinks(false),
- StoreSymLinks(false),
-
- ProcessedItemsStatuses(NULL)
-{
- #ifdef _USE_SECURITY_CODE
- _saclEnabled = InitLocalPrivileges();
- #endif
-}
-
-
-STDMETHODIMP CArchiveUpdateCallback::SetTotal(UInt64 size)
-{
- COM_TRY_BEGIN
- return Callback->SetTotal(size);
- COM_TRY_END
-}
-
-STDMETHODIMP CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue)
-{
- COM_TRY_BEGIN
- return Callback->SetCompleted(completeValue);
- COM_TRY_END
-}
-
-STDMETHODIMP CArchiveUpdateCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
-{
- COM_TRY_BEGIN
- return Callback->SetRatioInfo(inSize, outSize);
- COM_TRY_END
-}
-
-
-/*
-static const CStatProp kProps[] =
-{
- { NULL, kpidPath, VT_BSTR},
- { NULL, kpidIsDir, VT_BOOL},
- { NULL, kpidSize, VT_UI8},
- { NULL, kpidCTime, VT_FILETIME},
- { NULL, kpidATime, VT_FILETIME},
- { NULL, kpidMTime, VT_FILETIME},
- { NULL, kpidAttrib, VT_UI4},
- { NULL, kpidIsAnti, VT_BOOL}
-};
-
-STDMETHODIMP CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **)
-{
- return CStatPropEnumerator::CreateEnumerator(kProps, ARRAY_SIZE(kProps), enumerator);
-}
-*/
-
-STDMETHODIMP CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index,
- Int32 *newData, Int32 *newProps, UInt32 *indexInArchive)
-{
- COM_TRY_BEGIN
- RINOK(Callback->CheckBreak());
- const CUpdatePair2 &up = (*UpdatePairs)[index];
- if (newData) *newData = BoolToInt(up.NewData);
- if (newProps) *newProps = BoolToInt(up.NewProps);
- if (indexInArchive)
- {
- *indexInArchive = (UInt32)(Int32)-1;
- if (up.ExistInArchive())
- *indexInArchive = (ArcItems == 0) ? up.ArcIndex : (*ArcItems)[up.ArcIndex].IndexInServer;
- }
- return S_OK;
- COM_TRY_END
-}
-
-STDMETHODIMP CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *value)
-{
- NCOM::CPropVariant prop;
- switch (propID)
- {
- case kpidIsDir: prop = true; break;
- case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->Attrib; break;
- case kpidCTime: if (ParentDirItem) prop = ParentDirItem->CTime; break;
- case kpidATime: if (ParentDirItem) prop = ParentDirItem->ATime; break;
- case kpidMTime: if (ParentDirItem) prop = ParentDirItem->MTime; break;
- }
- prop.Detach(value);
- return S_OK;
-}
-
-STDMETHODIMP CArchiveUpdateCallback::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType)
-{
- *parentType = NParentType::kDir;
- *parent = (UInt32)(Int32)-1;
- return S_OK;
-}
-
-STDMETHODIMP CArchiveUpdateCallback::GetNumRawProps(UInt32 *numProps)
-{
- *numProps = 0;
- if (StoreNtSecurity)
- *numProps = 1;
- return S_OK;
-}
-
-STDMETHODIMP CArchiveUpdateCallback::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID)
-{
- *name = NULL;
- *propID = kpidNtSecure;
- return S_OK;
-}
-
-STDMETHODIMP CArchiveUpdateCallback::GetRootRawProp(PROPID
- #ifdef _USE_SECURITY_CODE
- propID
- #endif
- , const void **data, UInt32 *dataSize, UInt32 *propType)
-{
- *data = 0;
- *dataSize = 0;
- *propType = 0;
- if (!StoreNtSecurity)
- return S_OK;
- #ifdef _USE_SECURITY_CODE
- if (propID == kpidNtSecure)
- {
- if (StdInMode)
- return S_OK;
-
- if (ParentDirItem)
- {
- if (ParentDirItem->SecureIndex < 0)
- return S_OK;
- const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[ParentDirItem->SecureIndex];
- *data = buf;
- *dataSize = (UInt32)buf.Size();
- *propType = NPropDataType::kRaw;
- return S_OK;
- }
-
- if (Arc && Arc->GetRootProps)
- return Arc->GetRootProps->GetRootRawProp(propID, data, dataSize, propType);
- }
- #endif
- return S_OK;
-}
-
-// #ifdef _USE_SECURITY_CODE
-// #endif
-
-STDMETHODIMP CArchiveUpdateCallback::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType)
-{
- *data = 0;
- *dataSize = 0;
- *propType = 0;
-
- if (propID == kpidNtSecure ||
- propID == kpidNtReparse)
- {
- if (StdInMode)
- return S_OK;
-
- const CUpdatePair2 &up = (*UpdatePairs)[index];
- if (up.UseArcProps && up.ExistInArchive() && Arc->GetRawProps)
- return Arc->GetRawProps->GetRawProp(
- ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex,
- propID, data, dataSize, propType);
- {
- /*
- if (!up.NewData)
- return E_FAIL;
- */
- if (up.IsAnti)
- return S_OK;
-
- #ifndef UNDER_CE
- const CDirItem &di = DirItems->Items[up.DirIndex];
- #endif
-
- #ifdef _USE_SECURITY_CODE
- if (propID == kpidNtSecure)
- {
- if (!StoreNtSecurity)
- return S_OK;
- if (di.SecureIndex < 0)
- return S_OK;
- const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[di.SecureIndex];
- *data = buf;
- *dataSize = (UInt32)buf.Size();
- *propType = NPropDataType::kRaw;
- }
- else
- #endif
- {
- // propID == kpidNtReparse
- if (!StoreSymLinks)
- return S_OK;
- #ifndef UNDER_CE
- const CByteBuffer *buf = &di.ReparseData2;
- if (buf->Size() == 0)
- buf = &di.ReparseData;
- if (buf->Size() != 0)
- {
- *data = *buf;
- *dataSize = (UInt32)buf->Size();
- *propType = NPropDataType::kRaw;
- }
- #endif
- }
-
- return S_OK;
- }
- }
-
- return S_OK;
-}
-
-#ifndef UNDER_CE
-
-static UString GetRelativePath(const UString &to, const UString &from)
-{
- UStringVector partsTo, partsFrom;
- SplitPathToParts(to, partsTo);
- SplitPathToParts(from, partsFrom);
-
- unsigned i;
- for (i = 0;; i++)
- {
- if (i + 1 >= partsFrom.Size() ||
- i + 1 >= partsTo.Size())
- break;
- if (CompareFileNames(partsFrom[i], partsTo[i]) != 0)
- break;
- }
-
- if (i == 0)
- {
- #ifdef _WIN32
- if (NName::IsDrivePath(to) ||
- NName::IsDrivePath(from))
- return to;
- #endif
- }
-
- UString s;
- unsigned k;
-
- for (k = i + 1; k < partsFrom.Size(); k++)
- s += ".." STRING_PATH_SEPARATOR;
-
- for (k = i; k < partsTo.Size(); k++)
- {
- if (k != i)
- s.Add_PathSepar();
- s += partsTo[k];
- }
-
- return s;
-}
-
-#endif
-
-STDMETHODIMP CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value)
-{
- COM_TRY_BEGIN
- const CUpdatePair2 &up = (*UpdatePairs)[index];
- NCOM::CPropVariant prop;
-
- if (up.NewData)
- {
- /*
- if (propID == kpidIsHardLink)
- {
- prop = _isHardLink;
- prop.Detach(value);
- return S_OK;
- }
- */
- if (propID == kpidSymLink)
- {
- if (index == _hardIndex_From)
- {
- prop.Detach(value);
- return S_OK;
- }
- if (up.DirIndex >= 0)
- {
- #ifndef UNDER_CE
- const CDirItem &di = DirItems->Items[up.DirIndex];
- // if (di.IsDir())
- {
- CReparseAttr attr;
- DWORD errorCode = 0;
- if (attr.Parse(di.ReparseData, di.ReparseData.Size(), errorCode))
- {
- UString simpleName = attr.GetPath();
- if (attr.IsRelative())
- prop = simpleName;
- else
- {
- const FString phyPath = DirItems->GetPhyPath(up.DirIndex);
- FString fullPath;
- if (NDir::MyGetFullPathName(phyPath, fullPath))
- {
- prop = GetRelativePath(simpleName, fs2us(fullPath));
- }
- }
- prop.Detach(value);
- return S_OK;
- }
- }
- #endif
- }
- }
- else if (propID == kpidHardLink)
- {
- if (index == _hardIndex_From)
- {
- const CKeyKeyValPair &pair = _map[_hardIndex_To];
- const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value];
- prop = DirItems->GetLogPath(up2.DirIndex);
- prop.Detach(value);
- return S_OK;
- }
- if (up.DirIndex >= 0)
- {
- prop.Detach(value);
- return S_OK;
- }
- }
- }
-
- if (up.IsAnti
- && propID != kpidIsDir
- && propID != kpidPath
- && propID != kpidIsAltStream)
- {
- switch (propID)
- {
- case kpidSize: prop = (UInt64)0; break;
- case kpidIsAnti: prop = true; break;
- }
- }
- else if (propID == kpidPath && up.NewNameIndex >= 0)
- prop = (*NewNames)[up.NewNameIndex];
- else if (propID == kpidComment
- && CommentIndex >= 0
- && (unsigned)CommentIndex == index
- && Comment)
- prop = *Comment;
- else if (propID == kpidShortName && up.NewNameIndex >= 0 && up.IsMainRenameItem)
- {
- // we can generate new ShortName here;
- }
- else if ((up.UseArcProps || (KeepOriginalItemNames && (propID == kpidPath || propID == kpidIsAltStream)))
- && up.ExistInArchive() && Archive)
- return Archive->GetProperty(ArcItems ? (*ArcItems)[up.ArcIndex].IndexInServer : up.ArcIndex, propID, value);
- else if (up.ExistOnDisk())
- {
- const CDirItem &di = DirItems->Items[up.DirIndex];
- switch (propID)
- {
- case kpidPath: prop = DirItems->GetLogPath(up.DirIndex); break;
- case kpidIsDir: prop = di.IsDir(); break;
- case kpidSize: prop = di.IsDir() ? (UInt64)0 : di.Size; break;
- case kpidAttrib: prop = di.Attrib; break;
- case kpidCTime: prop = di.CTime; break;
- case kpidATime: prop = di.ATime; break;
- case kpidMTime: prop = di.MTime; break;
- case kpidIsAltStream: prop = di.IsAltStream; break;
- #if defined(_WIN32) && !defined(UNDER_CE)
- // case kpidShortName: prop = di.ShortName; break;
- #endif
- }
- }
- prop.Detach(value);
- return S_OK;
- COM_TRY_END
-}
-
-#ifndef _7ZIP_ST
-static NSynchronization::CCriticalSection CS;
-#endif
-
-STDMETHODIMP CArchiveUpdateCallback::GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 mode)
-{
- COM_TRY_BEGIN
- *inStream = NULL;
- const CUpdatePair2 &up = (*UpdatePairs)[index];
- if (!up.NewData)
- return E_FAIL;
-
- RINOK(Callback->CheckBreak());
- // RINOK(Callback->Finalize());
-
- bool isDir = IsDir(up);
-
- if (up.IsAnti)
- {
- UString name;
- if (up.ArcIndex >= 0)
- name = (*ArcItems)[up.ArcIndex].Name;
- else if (up.DirIndex >= 0)
- name = DirItems->GetLogPath(up.DirIndex);
- RINOK(Callback->GetStream(name, isDir, true, mode));
-
- /* 9.33: fixed. Handlers expect real stream object for files, even for anti-file.
- so we return empty stream */
-
- if (!isDir)
- {
- CBufInStream *inStreamSpec = new CBufInStream();
- CMyComPtr<ISequentialInStream> inStreamLoc = inStreamSpec;
- inStreamSpec->Init(NULL, 0);
- *inStream = inStreamLoc.Detach();
- }
- return S_OK;
- }
-
- RINOK(Callback->GetStream(DirItems->GetLogPath(up.DirIndex), isDir, false, mode));
-
- if (isDir)
- return S_OK;
-
- if (StdInMode)
- {
- if (mode != NUpdateNotifyOp::kAdd &&
- mode != NUpdateNotifyOp::kUpdate)
- return S_OK;
-
- CStdInFileStream *inStreamSpec = new CStdInFileStream;
- CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
- *inStream = inStreamLoc.Detach();
- }
- else
- {
- CInFileStream *inStreamSpec = new CInFileStream;
- CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
-
- inStreamSpec->SupportHardLinks = StoreHardLinks;
- inStreamSpec->Callback = this;
- inStreamSpec->CallbackRef = index;
-
- const FString path = DirItems->GetPhyPath(up.DirIndex);
- _openFiles_Indexes.Add(index);
- _openFiles_Paths.Add(path);
-
- #if defined(_WIN32) && !defined(UNDER_CE)
- if (DirItems->Items[up.DirIndex].AreReparseData())
- {
- if (!inStreamSpec->File.OpenReparse(path))
- {
- return Callback->OpenFileError(path, ::GetLastError());
- }
- }
- else
- #endif
- if (!inStreamSpec->OpenShared(path, ShareForWrite))
- {
- DWORD error = ::GetLastError();
- HRESULT hres = Callback->OpenFileError(path, error);
- if (StopAfterOpenError)
- if (hres == S_OK || hres == S_FALSE)
- return HRESULT_FROM_WIN32(error);
- return hres;
- }
-
- if (StoreHardLinks)
- {
- CStreamFileProps props;
- if (inStreamSpec->GetProps2(&props) == S_OK)
- {
- if (props.NumLinks > 1)
- {
- CKeyKeyValPair pair;
- pair.Key1 = props.VolID;
- pair.Key2 = props.FileID_Low;
- pair.Value = index;
- unsigned numItems = _map.Size();
- unsigned pairIndex = _map.AddToUniqueSorted2(pair);
- if (numItems == _map.Size())
- {
- // const CKeyKeyValPair &pair2 = _map.Pairs[pairIndex];
- _hardIndex_From = index;
- _hardIndex_To = pairIndex;
- // we could return NULL as stream, but it's better to return real stream
- // return S_OK;
- }
- }
- }
- }
-
- if (ProcessedItemsStatuses)
- {
- #ifndef _7ZIP_ST
- NSynchronization::CCriticalSectionLock lock(CS);
- #endif
- ProcessedItemsStatuses[(unsigned)up.DirIndex] = 1;
- }
- *inStream = inStreamLoc.Detach();
- }
-
- return S_OK;
- COM_TRY_END
-}
-
-STDMETHODIMP CArchiveUpdateCallback::SetOperationResult(Int32 opRes)
-{
- COM_TRY_BEGIN
- return Callback->SetOperationResult(opRes);
- COM_TRY_END
-}
-
-STDMETHODIMP CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream)
-{
- COM_TRY_BEGIN
- return GetStream2(index, inStream,
- (*UpdatePairs)[index].ArcIndex < 0 ?
- NUpdateNotifyOp::kAdd :
- NUpdateNotifyOp::kUpdate);
- COM_TRY_END
-}
-
-STDMETHODIMP CArchiveUpdateCallback::ReportOperation(UInt32 indexType, UInt32 index, UInt32 op)
-{
- COM_TRY_BEGIN
-
- bool isDir = false;
-
- if (indexType == NArchive::NEventIndexType::kOutArcIndex)
- {
- UString name;
- if (index != (UInt32)(Int32)-1)
- {
- const CUpdatePair2 &up = (*UpdatePairs)[index];
- if (up.ExistOnDisk())
- {
- name = DirItems->GetLogPath(up.DirIndex);
- isDir = DirItems->Items[up.DirIndex].IsDir();
- }
- }
- return Callback->ReportUpdateOpeartion(op, name.IsEmpty() ? NULL : name.Ptr(), isDir);
- }
-
- wchar_t temp[16];
- UString s2;
- const wchar_t *s = NULL;
-
- if (indexType == NArchive::NEventIndexType::kInArcIndex)
- {
- if (index != (UInt32)(Int32)-1)
- {
- if (ArcItems)
- {
- const CArcItem &ai = (*ArcItems)[index];
- s = ai.Name;
- isDir = ai.IsDir;
- }
- else if (Arc)
- {
- RINOK(Arc->GetItemPath(index, s2));
- s = s2;
- RINOK(Archive_IsItem_Dir(Arc->Archive, index, isDir));
- }
- }
- }
- else if (indexType == NArchive::NEventIndexType::kBlockIndex)
- {
- temp[0] = '#';
- ConvertUInt32ToString(index, temp + 1);
- s = temp;
- }
-
- if (!s)
- s = L"";
-
- return Callback->ReportUpdateOpeartion(op, s, isDir);
-
- COM_TRY_END
-}
-
-STDMETHODIMP CArchiveUpdateCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes)
-{
- COM_TRY_BEGIN
-
- bool isEncrypted = false;
- wchar_t temp[16];
- UString s2;
- const wchar_t *s = NULL;
-
- if (indexType == NArchive::NEventIndexType::kOutArcIndex)
- {
- /*
- UString name;
- if (index != (UInt32)(Int32)-1)
- {
- const CUpdatePair2 &up = (*UpdatePairs)[index];
- if (up.ExistOnDisk())
- {
- s2 = DirItems->GetLogPath(up.DirIndex);
- s = s2;
- }
- }
- */
- return E_FAIL;
- }
-
- if (indexType == NArchive::NEventIndexType::kInArcIndex)
- {
- if (index != (UInt32)(Int32)-1)
- {
- if (ArcItems)
- s = (*ArcItems)[index].Name;
- else if (Arc)
- {
- RINOK(Arc->GetItemPath(index, s2));
- s = s2;
- }
- if (Archive)
- {
- RINOK(Archive_GetItemBoolProp(Archive, index, kpidEncrypted, isEncrypted));
- }
- }
- }
- else if (indexType == NArchive::NEventIndexType::kBlockIndex)
- {
- temp[0] = '#';
- ConvertUInt32ToString(index, temp + 1);
- s = temp;
- }
-
- return Callback->ReportExtractResult(opRes, BoolToInt(isEncrypted), s);
-
- COM_TRY_END
-}
-
-STDMETHODIMP CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size)
-{
- if (VolumesSizes.Size() == 0)
- return S_FALSE;
- if (index >= (UInt32)VolumesSizes.Size())
- index = VolumesSizes.Size() - 1;
- *size = VolumesSizes[index];
- return S_OK;
-}
-
-STDMETHODIMP CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream)
-{
- COM_TRY_BEGIN
- char temp[16];
- ConvertUInt32ToString(index + 1, temp);
- FString res (temp);
- while (res.Len() < 2)
- res.InsertAtFront(FTEXT('0'));
- FString fileName = VolName;
- fileName += '.';
- fileName += res;
- fileName += VolExt;
- COutFileStream *streamSpec = new COutFileStream;
- CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
- if (!streamSpec->Create(fileName, false))
- return ::GetLastError();
- *volumeStream = streamLoc.Detach();
- return S_OK;
- COM_TRY_END
-}
-
-STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
-{
- COM_TRY_BEGIN
- return Callback->CryptoGetTextPassword2(passwordIsDefined, password);
- COM_TRY_END
-}
-
-STDMETHODIMP CArchiveUpdateCallback::CryptoGetTextPassword(BSTR *password)
-{
- COM_TRY_BEGIN
- return Callback->CryptoGetTextPassword(password);
- COM_TRY_END
-}
-
-HRESULT CArchiveUpdateCallback::InFileStream_On_Error(UINT_PTR val, DWORD error)
-{
- if (error == ERROR_LOCK_VIOLATION)
- {
- MT_LOCK
- UInt32 index = (UInt32)val;
- FOR_VECTOR(i, _openFiles_Indexes)
- {
- if (_openFiles_Indexes[i] == index)
- {
- RINOK(Callback->ReadingFileError(_openFiles_Paths[i], error));
- break;
- }
- }
- }
- return HRESULT_FROM_WIN32(error);
-}
-
-void CArchiveUpdateCallback::InFileStream_On_Destroy(UINT_PTR val)
-{
- MT_LOCK
- UInt32 index = (UInt32)val;
- FOR_VECTOR(i, _openFiles_Indexes)
- {
- if (_openFiles_Indexes[i] == index)
- {
- _openFiles_Indexes.Delete(i);
- _openFiles_Paths.Delete(i);
- return;
- }
- }
- throw 20141125;
-}
+// UpdateCallback.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#ifndef _WIN32
+// #include <grp.h>
+// #include <pwd.h>
+/*
+inclusion of <sys/sysmacros.h> by <sys/types.h> is deprecated since glibc 2.25.
+Since glibc 2.3.3, macros have been aliases for three GNU-specific
+functions: gnu_dev_makedev(), gnu_dev_major(), and gnu_dev_minor()
+*/
+// for major()/minor():
+#include <sys/types.h>
+#if defined(__FreeBSD__) || defined(BSD) || defined(__APPLE__)
+#else
+#ifndef major
+#include <sys/sysmacros.h>
+#endif
+#endif
+
+#endif // _WIN32
+
+#ifndef Z7_ST
+#include "../../../Windows/Synchronization.h"
+#endif
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/Wildcard.h"
+#include "../../../Common/UTFConvert.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/PropVariant.h"
+
+#include "../../Common/StreamObjects.h"
+
+#include "UpdateCallback.h"
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+#define Z7_USE_SECURITY_CODE
+#include "../../../Windows/SecurityUtils.h"
+#endif
+
+using namespace NWindows;
+using namespace NFile;
+
+#ifndef Z7_ST
+static NSynchronization::CCriticalSection g_CriticalSection;
+#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
+#else
+#define MT_LOCK
+#endif
+
+
+#ifdef Z7_USE_SECURITY_CODE
+bool InitLocalPrivileges();
+#endif
+
+CArchiveUpdateCallback::CArchiveUpdateCallback():
+ PreserveATime(false),
+ ShareForWrite(false),
+ StopAfterOpenError(false),
+ StdInMode(false),
+
+ KeepOriginalItemNames(false),
+ StoreNtSecurity(false),
+ StoreHardLinks(false),
+ StoreSymLinks(false),
+
+ #ifndef _WIN32
+ StoreOwnerId(false),
+ StoreOwnerName(false),
+ #endif
+
+ /*
+ , Need_ArcMTime_Report(false),
+ , ArcMTime_WasReported(false),
+ */
+ Need_LatestMTime(false),
+ LatestMTime_Defined(false),
+
+ Callback(NULL),
+
+ DirItems(NULL),
+ ParentDirItem(NULL),
+
+ Arc(NULL),
+ ArcItems(NULL),
+ UpdatePairs(NULL),
+ NewNames(NULL),
+ Comment(NULL),
+ CommentIndex(-1),
+
+ ProcessedItemsStatuses(NULL),
+ _hardIndex_From((UInt32)(Int32)-1)
+{
+ #ifdef Z7_USE_SECURITY_CODE
+ _saclEnabled = InitLocalPrivileges();
+ #endif
+}
+
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::SetTotal(UInt64 size))
+{
+ COM_TRY_BEGIN
+ return Callback->SetTotal(size);
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::SetCompleted(const UInt64 *completeValue))
+{
+ COM_TRY_BEGIN
+ return Callback->SetCompleted(completeValue);
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
+{
+ COM_TRY_BEGIN
+ return Callback->SetRatioInfo(inSize, outSize);
+ COM_TRY_END
+}
+
+
+/*
+static const CStatProp kProps[] =
+{
+ { NULL, kpidPath, VT_BSTR},
+ { NULL, kpidIsDir, VT_BOOL},
+ { NULL, kpidSize, VT_UI8},
+ { NULL, kpidCTime, VT_FILETIME},
+ { NULL, kpidATime, VT_FILETIME},
+ { NULL, kpidMTime, VT_FILETIME},
+ { NULL, kpidAttrib, VT_UI4},
+ { NULL, kpidIsAnti, VT_BOOL}
+};
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::EnumProperties(IEnumSTATPROPSTG **)
+{
+ return CStatPropEnumerator::CreateEnumerator(kProps, Z7_ARRAY_SIZE(kProps), enumerator);
+}
+*/
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::GetUpdateItemInfo(UInt32 index,
+ Int32 *newData, Int32 *newProps, UInt32 *indexInArchive))
+{
+ COM_TRY_BEGIN
+ RINOK(Callback->CheckBreak())
+ const CUpdatePair2 &up = (*UpdatePairs)[index];
+ if (newData) *newData = BoolToInt(up.NewData);
+ if (newProps) *newProps = BoolToInt(up.NewProps);
+ if (indexInArchive)
+ {
+ *indexInArchive = (UInt32)(Int32)-1;
+ if (up.ExistInArchive())
+ *indexInArchive = ArcItems ? (*ArcItems)[(unsigned)up.ArcIndex].IndexInServer : (UInt32)(Int32)up.ArcIndex;
+ }
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::GetRootProp(PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidIsDir: prop = true; break;
+ case kpidAttrib: if (ParentDirItem) prop = ParentDirItem->GetWinAttrib(); break;
+ case kpidCTime: if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->CTime); break;
+ case kpidATime: if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->ATime); break;
+ case kpidMTime: if (ParentDirItem) PropVariant_SetFrom_FiTime(prop, ParentDirItem->MTime); break;
+ case kpidArcFileName: if (!ArcFileName.IsEmpty()) prop = ArcFileName; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::GetParent(UInt32 /* index */, UInt32 *parent, UInt32 *parentType))
+{
+ *parentType = NParentType::kDir;
+ *parent = (UInt32)(Int32)-1;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::GetNumRawProps(UInt32 *numProps))
+{
+ *numProps = 0;
+ if (StoreNtSecurity)
+ *numProps = 1;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID))
+{
+ *name = NULL;
+ *propID = kpidNtSecure;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::GetRootRawProp(PROPID
+ propID
+ , const void **data, UInt32 *dataSize, UInt32 *propType))
+{
+ #ifndef Z7_USE_SECURITY_CODE
+ UNUSED_VAR(propID)
+ #endif
+
+ *data = NULL;
+ *dataSize = 0;
+ *propType = 0;
+ if (!StoreNtSecurity)
+ return S_OK;
+ #ifdef Z7_USE_SECURITY_CODE
+ if (propID == kpidNtSecure)
+ {
+ if (StdInMode)
+ return S_OK;
+
+ if (ParentDirItem)
+ {
+ if (ParentDirItem->SecureIndex < 0)
+ return S_OK;
+ const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[(unsigned)ParentDirItem->SecureIndex];
+ *data = buf;
+ *dataSize = (UInt32)buf.Size();
+ *propType = NPropDataType::kRaw;
+ return S_OK;
+ }
+
+ if (Arc && Arc->GetRootProps)
+ return Arc->GetRootProps->GetRootRawProp(propID, data, dataSize, propType);
+ }
+ #endif
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::GetRawProp(UInt32 index, PROPID propID, const void **data, UInt32 *dataSize, UInt32 *propType))
+{
+ *data = NULL;
+ *dataSize = 0;
+ *propType = 0;
+
+ if (propID == kpidNtSecure ||
+ propID == kpidNtReparse)
+ {
+ if (StdInMode)
+ return S_OK;
+
+ const CUpdatePair2 &up = (*UpdatePairs)[index];
+ if (up.UseArcProps && up.ExistInArchive() && Arc->GetRawProps)
+ return Arc->GetRawProps->GetRawProp(
+ ArcItems ? (*ArcItems)[(unsigned)up.ArcIndex].IndexInServer : (UInt32)(Int32)up.ArcIndex,
+ propID, data, dataSize, propType);
+ {
+ /*
+ if (!up.NewData)
+ return E_FAIL;
+ */
+ if (up.IsAnti)
+ return S_OK;
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex];
+ #endif
+
+ #ifdef Z7_USE_SECURITY_CODE
+ if (propID == kpidNtSecure)
+ {
+ if (!StoreNtSecurity)
+ return S_OK;
+ if (di.SecureIndex < 0)
+ return S_OK;
+ const CByteBuffer &buf = DirItems->SecureBlocks.Bufs[(unsigned)di.SecureIndex];
+ *data = buf;
+ *dataSize = (UInt32)buf.Size();
+ *propType = NPropDataType::kRaw;
+ }
+ else
+ #endif
+ if (propID == kpidNtReparse)
+ {
+ if (!StoreSymLinks)
+ return S_OK;
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ // we use ReparseData2 instead of ReparseData for WIM format
+ const CByteBuffer *buf = &di.ReparseData2;
+ if (buf->Size() == 0)
+ buf = &di.ReparseData;
+ if (buf->Size() != 0)
+ {
+ *data = *buf;
+ *dataSize = (UInt32)buf->Size();
+ *propType = NPropDataType::kRaw;
+ }
+ #endif
+ }
+
+ return S_OK;
+ }
+ }
+
+ return S_OK;
+}
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+
+static UString GetRelativePath(const UString &to, const UString &from)
+{
+ UStringVector partsTo, partsFrom;
+ SplitPathToParts(to, partsTo);
+ SplitPathToParts(from, partsFrom);
+
+ unsigned i;
+ for (i = 0;; i++)
+ {
+ if (i + 1 >= partsFrom.Size() ||
+ i + 1 >= partsTo.Size())
+ break;
+ if (CompareFileNames(partsFrom[i], partsTo[i]) != 0)
+ break;
+ }
+
+ if (i == 0)
+ {
+ #ifdef _WIN32
+ if (NName::IsDrivePath(to) ||
+ NName::IsDrivePath(from))
+ return to;
+ #endif
+ }
+
+ UString s;
+ unsigned k;
+
+ for (k = i + 1; k < partsFrom.Size(); k++)
+ s += ".." STRING_PATH_SEPARATOR;
+
+ for (k = i; k < partsTo.Size(); k++)
+ {
+ if (k != i)
+ s.Add_PathSepar();
+ s += partsTo[k];
+ }
+
+ return s;
+}
+
+#endif
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ const CUpdatePair2 &up = (*UpdatePairs)[index];
+ NCOM::CPropVariant prop;
+
+ if (up.NewData)
+ {
+ /*
+ if (propID == kpidIsHardLink)
+ {
+ prop = _isHardLink;
+ prop.Detach(value);
+ return S_OK;
+ }
+ */
+ if (propID == kpidSymLink)
+ {
+ if (index == _hardIndex_From)
+ {
+ prop.Detach(value);
+ return S_OK;
+ }
+
+ #if !defined(UNDER_CE)
+
+ if (up.DirIndex >= 0)
+ {
+ const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex];
+
+ #ifdef _WIN32
+ // if (di.IsDir())
+ {
+ CReparseAttr attr;
+ if (attr.Parse(di.ReparseData, di.ReparseData.Size()))
+ {
+ const UString simpleName = attr.GetPath();
+ if (!attr.IsSymLink_WSL() && attr.IsRelative_Win())
+ prop = simpleName;
+ else
+ {
+ const FString phyPath = DirItems->GetPhyPath((unsigned)up.DirIndex);
+ FString fullPath;
+ if (NDir::MyGetFullPathName(phyPath, fullPath))
+ {
+ prop = GetRelativePath(simpleName, fs2us(fullPath));
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ }
+ }
+
+ #else // _WIN32
+
+ if (di.ReparseData.Size() != 0)
+ {
+ AString utf;
+ utf.SetFrom_CalcLen((const char *)(const Byte *)di.ReparseData, (unsigned)di.ReparseData.Size());
+
+ UString us;
+ if (ConvertUTF8ToUnicode(utf, us))
+ {
+ prop = us;
+ prop.Detach(value);
+ return S_OK;
+ }
+ }
+
+ #endif // _WIN32
+ }
+ #endif // !defined(UNDER_CE)
+ }
+ else if (propID == kpidHardLink)
+ {
+ if (index == _hardIndex_From)
+ {
+ const CKeyKeyValPair &pair = _map[_hardIndex_To];
+ const CUpdatePair2 &up2 = (*UpdatePairs)[pair.Value];
+ prop = DirItems->GetLogPath((unsigned)up2.DirIndex);
+ prop.Detach(value);
+ return S_OK;
+ }
+ if (up.DirIndex >= 0)
+ {
+ prop.Detach(value);
+ return S_OK;
+ }
+ }
+ }
+
+ if (up.IsAnti
+ && propID != kpidIsDir
+ && propID != kpidPath
+ && propID != kpidIsAltStream)
+ {
+ switch (propID)
+ {
+ case kpidSize: prop = (UInt64)0; break;
+ case kpidIsAnti: prop = true; break;
+ }
+ }
+ else if (propID == kpidPath && up.NewNameIndex >= 0)
+ prop = (*NewNames)[(unsigned)up.NewNameIndex];
+ else if (propID == kpidComment
+ && CommentIndex >= 0
+ && (unsigned)CommentIndex == index
+ && Comment)
+ prop = *Comment;
+ else if (propID == kpidShortName && up.NewNameIndex >= 0 && up.IsMainRenameItem)
+ {
+ // we can generate new ShortName here;
+ }
+ else if ((up.UseArcProps || (KeepOriginalItemNames && (propID == kpidPath || propID == kpidIsAltStream)))
+ && up.ExistInArchive() && Archive)
+ return Archive->GetProperty(ArcItems ? (*ArcItems)[(unsigned)up.ArcIndex].IndexInServer : (UInt32)(Int32)up.ArcIndex, propID, value);
+ else if (up.ExistOnDisk())
+ {
+ const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex];
+ switch (propID)
+ {
+ case kpidPath: prop = DirItems->GetLogPath((unsigned)up.DirIndex); break;
+ case kpidIsDir: prop = di.IsDir(); break;
+ case kpidSize: prop = (UInt64)(di.IsDir() ? (UInt64)0 : di.Size); break;
+ case kpidCTime: PropVariant_SetFrom_FiTime(prop, di.CTime); break;
+ case kpidATime: PropVariant_SetFrom_FiTime(prop, di.ATime); break;
+ case kpidMTime: PropVariant_SetFrom_FiTime(prop, di.MTime); break;
+ case kpidAttrib: prop = (UInt32)di.GetWinAttrib(); break;
+ case kpidPosixAttrib: prop = (UInt32)di.GetPosixAttrib(); break;
+
+ #if defined(_WIN32)
+ case kpidIsAltStream: prop = di.IsAltStream; break;
+ // case kpidShortName: prop = di.ShortName; break;
+ #else
+
+ #if defined(__APPLE__)
+ #pragma GCC diagnostic push
+ #pragma GCC diagnostic ignored "-Wsign-conversion"
+ #endif
+
+ case kpidDeviceMajor:
+ /*
+ printf("\ndi.mode = %o\n", di.mode);
+ printf("\nst.st_rdev major = %d\n", (unsigned)major(di.rdev));
+ printf("\nst.st_rdev minor = %d\n", (unsigned)minor(di.rdev));
+ */
+ if (S_ISCHR(di.mode) || S_ISBLK(di.mode))
+ prop = (UInt32)major(di.rdev);
+ break;
+
+ case kpidDeviceMinor:
+ if (S_ISCHR(di.mode) || S_ISBLK(di.mode))
+ prop = (UInt32)minor(di.rdev);
+ break;
+
+ #if defined(__APPLE__)
+ #pragma GCC diagnostic pop
+ #endif
+
+ // case kpidDevice: if (S_ISCHR(di.mode) || S_ISBLK(di.mode)) prop = (UInt64)(di.rdev); break;
+
+ case kpidUserId: if (StoreOwnerId) prop = (UInt32)di.uid; break;
+ case kpidGroupId: if (StoreOwnerId) prop = (UInt32)di.gid; break;
+ case kpidUser:
+ if (di.OwnerNameIndex >= 0)
+ prop = DirItems->OwnerNameMap.Strings[(unsigned)di.OwnerNameIndex];
+ break;
+ case kpidGroup:
+ if (di.OwnerGroupIndex >= 0)
+ prop = DirItems->OwnerGroupMap.Strings[(unsigned)di.OwnerGroupIndex];
+ break;
+ #endif
+ }
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+#ifndef Z7_ST
+static NSynchronization::CCriticalSection g_CS;
+#endif
+
+void CArchiveUpdateCallback::UpdateProcessedItemStatus(unsigned dirIndex)
+{
+ if (ProcessedItemsStatuses)
+ {
+ #ifndef Z7_ST
+ NSynchronization::CCriticalSectionLock lock(g_CS);
+ #endif
+ ProcessedItemsStatuses[dirIndex] = 1;
+ }
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream2(UInt32 index, ISequentialInStream **inStream, UInt32 mode))
+{
+ COM_TRY_BEGIN
+ *inStream = NULL;
+ const CUpdatePair2 &up = (*UpdatePairs)[index];
+ if (!up.NewData)
+ return E_FAIL;
+
+ RINOK(Callback->CheckBreak())
+ // RINOK(Callback->Finalize());
+
+ bool isDir = IsDir(up);
+
+ if (up.IsAnti)
+ {
+ UString name;
+ if (up.ArcIndex >= 0)
+ name = (*ArcItems)[(unsigned)up.ArcIndex].Name;
+ else if (up.DirIndex >= 0)
+ name = DirItems->GetLogPath((unsigned)up.DirIndex);
+ RINOK(Callback->GetStream(name, isDir, true, mode))
+
+ /* 9.33: fixed. Handlers expect real stream object for files, even for anti-file.
+ so we return empty stream */
+
+ if (!isDir)
+ {
+ CBufInStream *inStreamSpec = new CBufInStream();
+ CMyComPtr<ISequentialInStream> inStreamLoc = inStreamSpec;
+ inStreamSpec->Init(NULL, 0);
+ *inStream = inStreamLoc.Detach();
+ }
+ return S_OK;
+ }
+
+ RINOK(Callback->GetStream(DirItems->GetLogPath((unsigned)up.DirIndex), isDir, false, mode))
+
+ if (isDir)
+ return S_OK;
+
+ if (StdInMode)
+ {
+ if (mode != NUpdateNotifyOp::kAdd &&
+ mode != NUpdateNotifyOp::kUpdate)
+ return S_OK;
+
+ CStdInFileStream *inStreamSpec = new CStdInFileStream;
+ CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
+ *inStream = inStreamLoc.Detach();
+ }
+ else
+ {
+ #if !defined(UNDER_CE)
+ const CDirItem &di = DirItems->Items[(unsigned)up.DirIndex];
+ if (di.AreReparseData())
+ {
+ /*
+ // we still need DeviceIoControlOut() instead of Read
+ if (!inStreamSpec->File.OpenReparse(path))
+ {
+ return Callback->OpenFileError(path, ::GetLastError());
+ }
+ */
+ // 20.03: we use Reparse Data instead of real data
+
+ CBufInStream *inStreamSpec = new CBufInStream();
+ CMyComPtr<ISequentialInStream> inStreamLoc = inStreamSpec;
+ inStreamSpec->Init(di.ReparseData, di.ReparseData.Size());
+ *inStream = inStreamLoc.Detach();
+
+ UpdateProcessedItemStatus((unsigned)up.DirIndex);
+ return S_OK;
+ }
+ #endif // !defined(UNDER_CE)
+
+ CInFileStream *inStreamSpec = new CInFileStream;
+ CMyComPtr<ISequentialInStream> inStreamLoc(inStreamSpec);
+
+ /*
+ // for debug:
+ #ifdef _WIN32
+ inStreamSpec->StoreOwnerName = true;
+ inStreamSpec->OwnerName = "user_name";
+ inStreamSpec->OwnerName += di.Name;
+ inStreamSpec->OwnerName += "11111111112222222222222333333333333";
+ inStreamSpec->OwnerGroup = "gname_";
+ inStreamSpec->OwnerGroup += inStreamSpec->OwnerName;
+ #endif
+ */
+
+ #ifndef _WIN32
+ inStreamSpec->StoreOwnerId = StoreOwnerId;
+ inStreamSpec->StoreOwnerName = StoreOwnerName;
+
+ // if (StoreOwner)
+ {
+ inStreamSpec->_uid = di.uid;
+ inStreamSpec->_gid = di.gid;
+ if (di.OwnerNameIndex >= 0)
+ inStreamSpec->OwnerName = DirItems->OwnerNameMap.Strings[(unsigned)di.OwnerNameIndex];
+ if (di.OwnerGroupIndex >= 0)
+ inStreamSpec->OwnerGroup = DirItems->OwnerGroupMap.Strings[(unsigned)di.OwnerGroupIndex];
+ }
+ #endif
+
+ inStreamSpec->SupportHardLinks = StoreHardLinks;
+ const bool preserveATime = (PreserveATime
+ || mode == NUpdateNotifyOp::kAnalyze); // 22.00 : we don't change access time in Analyze pass.
+ inStreamSpec->Set_PreserveATime(preserveATime);
+
+ const FString path = DirItems->GetPhyPath((unsigned)up.DirIndex);
+ _openFiles_Indexes.Add(index);
+ _openFiles_Paths.Add(path);
+ // _openFiles_Streams.Add(inStreamSpec);
+
+ /* 21.02 : we set Callback/CallbackRef after _openFiles_Indexes adding
+ for correct working if exception was raised in GetPhyPath */
+ inStreamSpec->Callback = this;
+ inStreamSpec->CallbackRef = index;
+
+ if (!inStreamSpec->OpenShared(path, ShareForWrite))
+ {
+ bool isOpen = false;
+ if (preserveATime)
+ {
+ inStreamSpec->Set_PreserveATime(false);
+ isOpen = inStreamSpec->OpenShared(path, ShareForWrite);
+ }
+ if (!isOpen)
+ {
+ const DWORD error = ::GetLastError();
+ const HRESULT hres = Callback->OpenFileError(path, error);
+ if (hres == S_OK || hres == S_FALSE)
+ if (StopAfterOpenError ||
+ // v23: we check also for some critical errors:
+ #ifdef _WIN32
+ error == ERROR_NO_SYSTEM_RESOURCES
+ #else
+ error == EMFILE
+ #endif
+ )
+ {
+ if (error == 0)
+ return E_FAIL;
+ return HRESULT_FROM_WIN32(error);
+ }
+ return hres;
+ }
+ }
+
+ /*
+ {
+ // for debug:
+ Byte b = 0;
+ UInt32 processedSize = 0;
+ if (inStreamSpec->Read(&b, 1, &processedSize) != S_OK ||
+ processedSize != 1)
+ return E_FAIL;
+ }
+ */
+
+ if (Need_LatestMTime)
+ {
+ inStreamSpec->ReloadProps();
+ }
+
+ // #if defined(Z7_FILE_STREAMS_USE_WIN_FILE) || !defined(_WIN32)
+ if (StoreHardLinks)
+ {
+ CStreamFileProps props;
+ if (inStreamSpec->GetProps2(&props) == S_OK)
+ {
+ if (props.NumLinks > 1)
+ {
+ CKeyKeyValPair pair;
+ pair.Key1 = props.VolID;
+ pair.Key2 = props.FileID_Low;
+ pair.Value = index;
+ const unsigned numItems = _map.Size();
+ const unsigned pairIndex = _map.AddToUniqueSorted2(pair);
+ if (numItems == _map.Size())
+ {
+ // const CKeyKeyValPair &pair2 = _map.Pairs[pairIndex];
+ _hardIndex_From = index;
+ _hardIndex_To = pairIndex;
+ // we could return NULL as stream, but it's better to return real stream
+ // return S_OK;
+ }
+ }
+ }
+ }
+ // #endif
+
+ UpdateProcessedItemStatus((unsigned)up.DirIndex);
+ *inStream = inStreamLoc.Detach();
+ }
+
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::SetOperationResult(Int32 opRes))
+{
+ COM_TRY_BEGIN
+ return Callback->SetOperationResult(opRes);
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::GetStream(UInt32 index, ISequentialInStream **inStream))
+{
+ COM_TRY_BEGIN
+ return GetStream2(index, inStream,
+ (*UpdatePairs)[index].ArcIndex < 0 ?
+ NUpdateNotifyOp::kAdd :
+ NUpdateNotifyOp::kUpdate);
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::ReportOperation(UInt32 indexType, UInt32 index, UInt32 op))
+{
+ COM_TRY_BEGIN
+
+ // if (op == NUpdateNotifyOp::kOpFinished) return Callback->ReportFinished(indexType, index);
+
+ bool isDir = false;
+
+ if (indexType == NArchive::NEventIndexType::kOutArcIndex)
+ {
+ UString name;
+ if (index != (UInt32)(Int32)-1)
+ {
+ const CUpdatePair2 &up = (*UpdatePairs)[index];
+ if (up.ExistOnDisk())
+ {
+ name = DirItems->GetLogPath((unsigned)up.DirIndex);
+ isDir = DirItems->Items[(unsigned)up.DirIndex].IsDir();
+ }
+ }
+ return Callback->ReportUpdateOperation(op, name.IsEmpty() ? NULL : name.Ptr(), isDir);
+ }
+
+ wchar_t temp[16];
+ UString s2;
+ const wchar_t *s = NULL;
+
+ if (indexType == NArchive::NEventIndexType::kInArcIndex)
+ {
+ if (index != (UInt32)(Int32)-1)
+ {
+ if (ArcItems)
+ {
+ const CArcItem &ai = (*ArcItems)[index];
+ s = ai.Name;
+ isDir = ai.IsDir;
+ }
+ else if (Arc)
+ {
+ RINOK(Arc->GetItem_Path(index, s2))
+ s = s2;
+ RINOK(Archive_IsItem_Dir(Arc->Archive, index, isDir))
+ }
+ }
+ }
+ else if (indexType == NArchive::NEventIndexType::kBlockIndex)
+ {
+ temp[0] = '#';
+ ConvertUInt32ToString(index, temp + 1);
+ s = temp;
+ }
+
+ if (!s)
+ s = L"";
+
+ return Callback->ReportUpdateOperation(op, s, isDir);
+
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::ReportExtractResult(UInt32 indexType, UInt32 index, Int32 opRes))
+{
+ COM_TRY_BEGIN
+
+ bool isEncrypted = false;
+ wchar_t temp[16];
+ UString s2;
+ const wchar_t *s = NULL;
+
+ if (indexType == NArchive::NEventIndexType::kOutArcIndex)
+ {
+ /*
+ UString name;
+ if (index != (UInt32)(Int32)-1)
+ {
+ const CUpdatePair2 &up = (*UpdatePairs)[index];
+ if (up.ExistOnDisk())
+ {
+ s2 = DirItems->GetLogPath(up.DirIndex);
+ s = s2;
+ }
+ }
+ */
+ return E_FAIL;
+ }
+
+ if (indexType == NArchive::NEventIndexType::kInArcIndex)
+ {
+ if (index != (UInt32)(Int32)-1)
+ {
+ if (ArcItems)
+ s = (*ArcItems)[index].Name;
+ else if (Arc)
+ {
+ RINOK(Arc->GetItem_Path(index, s2))
+ s = s2;
+ }
+ if (Archive)
+ {
+ RINOK(Archive_GetItemBoolProp(Archive, index, kpidEncrypted, isEncrypted))
+ }
+ }
+ }
+ else if (indexType == NArchive::NEventIndexType::kBlockIndex)
+ {
+ temp[0] = '#';
+ ConvertUInt32ToString(index, temp + 1);
+ s = temp;
+ }
+
+ return Callback->ReportExtractResult(opRes, BoolToInt(isEncrypted), s);
+
+ COM_TRY_END
+}
+
+
+/*
+Z7_COM7F_IMF(CArchiveUpdateCallback::DoNeedArcProp(PROPID propID, Int32 *answer))
+{
+ *answer = 0;
+ if (Need_ArcMTime_Report && propID == kpidComboMTime)
+ *answer = 1;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value))
+{
+ if (indexType == NArchive::NEventIndexType::kArcProp)
+ {
+ if (propID == kpidComboMTime)
+ {
+ ArcMTime_WasReported = true;
+ if (value->vt == VT_FILETIME)
+ {
+ Reported_ArcMTime.Set_From_Prop(*value);
+ Reported_ArcMTime.Def = true;
+ }
+ else
+ {
+ Reported_ArcMTime.Clear();
+ if (value->vt != VT_EMPTY)
+ return E_FAIL; // for debug
+ }
+ }
+ }
+ return Callback->ReportProp(indexType, index, propID, value);
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::ReportRawProp(UInt32 indexType, UInt32 index,
+ PROPID propID, const void *data, UInt32 dataSize, UInt32 propType))
+{
+ return Callback->ReportRawProp(indexType, index, propID, data, dataSize, propType);
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes))
+{
+ return Callback->ReportFinished(indexType, index, opRes);
+}
+*/
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeSize(UInt32 index, UInt64 *size))
+{
+ if (VolumesSizes.Size() == 0)
+ return S_FALSE;
+ if (index >= (UInt32)VolumesSizes.Size())
+ index = VolumesSizes.Size() - 1;
+ *size = VolumesSizes[index];
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::GetVolumeStream(UInt32 index, ISequentialOutStream **volumeStream))
+{
+ COM_TRY_BEGIN
+ char temp[16];
+ ConvertUInt32ToString(index + 1, temp);
+ FString res (temp);
+ while (res.Len() < 2)
+ res.InsertAtFront(FTEXT('0'));
+ FString fileName = VolName;
+ fileName.Add_Dot();
+ fileName += res;
+ fileName += VolExt;
+ COutFileStream *streamSpec = new COutFileStream;
+ CMyComPtr<ISequentialOutStream> streamLoc(streamSpec);
+ if (!streamSpec->Create(fileName, false))
+ return GetLastError_noZero_HRESULT();
+ *volumeStream = streamLoc.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password))
+{
+ COM_TRY_BEGIN
+ return Callback->CryptoGetTextPassword2(passwordIsDefined, password);
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CArchiveUpdateCallback::CryptoGetTextPassword(BSTR *password))
+{
+ COM_TRY_BEGIN
+ return Callback->CryptoGetTextPassword(password);
+ COM_TRY_END
+}
+
+HRESULT CArchiveUpdateCallback::InFileStream_On_Error(UINT_PTR val, DWORD error)
+{
+ #ifdef _WIN32 // FIX IT !!!
+ // why did we check only for ERROR_LOCK_VIOLATION ?
+ // if (error == ERROR_LOCK_VIOLATION)
+ #endif
+ {
+ MT_LOCK
+ const UInt32 index = (UInt32)val;
+ FOR_VECTOR(i, _openFiles_Indexes)
+ {
+ if (_openFiles_Indexes[i] == index)
+ {
+ RINOK(Callback->ReadingFileError(_openFiles_Paths[i], error))
+ break;
+ }
+ }
+ }
+ return HRESULT_FROM_WIN32(error);
+}
+
+void CArchiveUpdateCallback::InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val)
+{
+ MT_LOCK
+ if (Need_LatestMTime)
+ {
+ if (stream->_info_WasLoaded)
+ {
+ const CFiTime &ft = ST_MTIME(stream->_info);
+ if (!LatestMTime_Defined
+ || Compare_FiTime(&LatestMTime, &ft) < 0)
+ LatestMTime = ft;
+ LatestMTime_Defined = true;
+ }
+ }
+ const UInt32 index = (UInt32)val;
+ FOR_VECTOR(i, _openFiles_Indexes)
+ {
+ if (_openFiles_Indexes[i] == index)
+ {
+ _openFiles_Indexes.Delete(i);
+ _openFiles_Paths.Delete(i);
+ // _openFiles_Streams.Delete(i);
+ return;
+ }
+ }
+ /* 21.02 : this function can be called in destructor.
+ And destructor can be called after some exception.
+ If we don't want to throw exception in desctructors or after another exceptions,
+ we must disable the code below that raises new exception.
+ */
+ // throw 20141125;
+}
diff --git a/CPP/7zip/UI/Common/UpdateCallback.h b/CPP/7zip/UI/Common/UpdateCallback.h
index 1b5d1ee..379b814 100644
--- a/CPP/7zip/UI/Common/UpdateCallback.h
+++ b/CPP/7zip/UI/Common/UpdateCallback.h
@@ -1,162 +1,197 @@
-// UpdateCallback.h
-
-#ifndef __UPDATE_CALLBACK_H
-#define __UPDATE_CALLBACK_H
-
-#include "../../../Common/MyCom.h"
-
-#include "../../Common/FileStreams.h"
-
-#include "../../IPassword.h"
-#include "../../ICoder.h"
-
-#include "../Common/UpdatePair.h"
-#include "../Common/UpdateProduce.h"
-
-#include "OpenArchive.h"
-
-struct CArcToDoStat
-{
- CDirItemsStat2 NewData;
- CDirItemsStat2 OldData;
- CDirItemsStat2 DeleteData;
-
- UInt64 Get_NumDataItems_Total() const
- {
- return NewData.Get_NumDataItems2() + OldData.Get_NumDataItems2();
- }
-};
-
-#define INTERFACE_IUpdateCallbackUI(x) \
- virtual HRESULT WriteSfx(const wchar_t *name, UInt64 size) x; \
- virtual HRESULT SetTotal(UInt64 size) x; \
- virtual HRESULT SetCompleted(const UInt64 *completeValue) x; \
- virtual HRESULT SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) x; \
- virtual HRESULT CheckBreak() x; \
- /* virtual HRESULT Finalize() x; */ \
- virtual HRESULT SetNumItems(const CArcToDoStat &stat) x; \
- virtual HRESULT GetStream(const wchar_t *name, bool isDir, bool isAnti, UInt32 mode) x; \
- virtual HRESULT OpenFileError(const FString &path, DWORD systemError) x; \
- virtual HRESULT ReadingFileError(const FString &path, DWORD systemError) x; \
- virtual HRESULT SetOperationResult(Int32 opRes) x; \
- virtual HRESULT ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name) x; \
- virtual HRESULT ReportUpdateOpeartion(UInt32 op, const wchar_t *name, bool isDir) x; \
- /* virtual HRESULT SetPassword(const UString &password) x; */ \
- virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) x; \
- virtual HRESULT CryptoGetTextPassword(BSTR *password) x; \
- virtual HRESULT ShowDeleteFile(const wchar_t *name, bool isDir) x; \
- /* virtual HRESULT CloseProgress() { return S_OK; } */
-
-struct IUpdateCallbackUI
-{
- INTERFACE_IUpdateCallbackUI(=0)
-};
-
-struct CKeyKeyValPair
-{
- UInt64 Key1;
- UInt64 Key2;
- unsigned Value;
-
- int Compare(const CKeyKeyValPair &a) const
- {
- if (Key1 < a.Key1) return -1;
- if (Key1 > a.Key1) return 1;
- return MyCompare(Key2, a.Key2);
- }
-};
-
-
-class CArchiveUpdateCallback:
- public IArchiveUpdateCallback2,
- public IArchiveUpdateCallbackFile,
- public IArchiveExtractCallbackMessage,
- public IArchiveGetRawProps,
- public IArchiveGetRootProps,
- public ICryptoGetTextPassword2,
- public ICryptoGetTextPassword,
- public ICompressProgressInfo,
- public IInFileStream_Callback,
- public CMyUnknownImp
-{
- #if defined(_WIN32) && !defined(UNDER_CE)
- bool _saclEnabled;
- #endif
- CRecordVector<CKeyKeyValPair> _map;
-
- UInt32 _hardIndex_From;
- UInt32 _hardIndex_To;
-
-public:
- MY_QUERYINTERFACE_BEGIN2(IArchiveUpdateCallback2)
- MY_QUERYINTERFACE_ENTRY(IArchiveUpdateCallbackFile)
- MY_QUERYINTERFACE_ENTRY(IArchiveExtractCallbackMessage)
- MY_QUERYINTERFACE_ENTRY(IArchiveGetRawProps)
- MY_QUERYINTERFACE_ENTRY(IArchiveGetRootProps)
- MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword2)
- MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword)
- MY_QUERYINTERFACE_ENTRY(ICompressProgressInfo)
- MY_QUERYINTERFACE_END
- MY_ADDREF_RELEASE
-
-
- STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
-
- INTERFACE_IArchiveUpdateCallback2(;)
- INTERFACE_IArchiveUpdateCallbackFile(;)
- INTERFACE_IArchiveExtractCallbackMessage(;)
- INTERFACE_IArchiveGetRawProps(;)
- INTERFACE_IArchiveGetRootProps(;)
-
- STDMETHOD(CryptoGetTextPassword2)(Int32 *passwordIsDefined, BSTR *password);
- STDMETHOD(CryptoGetTextPassword)(BSTR *password);
-
- CRecordVector<UInt32> _openFiles_Indexes;
- FStringVector _openFiles_Paths;
-
- bool AreAllFilesClosed() const { return _openFiles_Indexes.IsEmpty(); }
- virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error);
- virtual void InFileStream_On_Destroy(UINT_PTR val);
-
- CRecordVector<UInt64> VolumesSizes;
- FString VolName;
- FString VolExt;
-
- IUpdateCallbackUI *Callback;
-
- const CDirItems *DirItems;
- const CDirItem *ParentDirItem;
-
- const CArc *Arc;
- CMyComPtr<IInArchive> Archive;
- const CObjectVector<CArcItem> *ArcItems;
- const CRecordVector<CUpdatePair2> *UpdatePairs;
- const UStringVector *NewNames;
- int CommentIndex;
- const UString *Comment;
-
- bool ShareForWrite;
- bool StopAfterOpenError;
- bool StdInMode;
-
- bool KeepOriginalItemNames;
- bool StoreNtSecurity;
- bool StoreHardLinks;
- bool StoreSymLinks;
-
- Byte *ProcessedItemsStatuses;
-
-
- CArchiveUpdateCallback();
-
- bool IsDir(const CUpdatePair2 &up) const
- {
- if (up.DirIndex >= 0)
- return DirItems->Items[up.DirIndex].IsDir();
- else if (up.ArcIndex >= 0)
- return (*ArcItems)[up.ArcIndex].IsDir;
- return false;
- }
-};
-
-#endif
+// UpdateCallback.h
+
+#ifndef ZIP7_INC_UPDATE_CALLBACK_H
+#define ZIP7_INC_UPDATE_CALLBACK_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../Common/FileStreams.h"
+
+#include "../../IPassword.h"
+#include "../../ICoder.h"
+
+#include "../Common/UpdatePair.h"
+#include "../Common/UpdateProduce.h"
+
+#include "OpenArchive.h"
+
+struct CArcToDoStat
+{
+ CDirItemsStat2 NewData;
+ CDirItemsStat2 OldData;
+ CDirItemsStat2 DeleteData;
+
+ UInt64 Get_NumDataItems_Total() const
+ {
+ return NewData.Get_NumDataItems2() + OldData.Get_NumDataItems2();
+ }
+};
+
+
+Z7_PURE_INTERFACES_BEGIN
+
+#define Z7_IFACEN_IUpdateCallbackUI(x) \
+ virtual HRESULT WriteSfx(const wchar_t *name, UInt64 size) x \
+ virtual HRESULT SetTotal(UInt64 size) x \
+ virtual HRESULT SetCompleted(const UInt64 *completeValue) x \
+ virtual HRESULT SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize) x \
+ virtual HRESULT CheckBreak() x \
+ /* virtual HRESULT Finalize() x */ \
+ virtual HRESULT SetNumItems(const CArcToDoStat &stat) x \
+ virtual HRESULT GetStream(const wchar_t *name, bool isDir, bool isAnti, UInt32 mode) x \
+ virtual HRESULT OpenFileError(const FString &path, DWORD systemError) x \
+ virtual HRESULT ReadingFileError(const FString &path, DWORD systemError) x \
+ virtual HRESULT SetOperationResult(Int32 opRes) x \
+ virtual HRESULT ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name) x \
+ virtual HRESULT ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir) x \
+ /* virtual HRESULT SetPassword(const UString &password) x */ \
+ virtual HRESULT CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password) x \
+ virtual HRESULT CryptoGetTextPassword(BSTR *password) x \
+ virtual HRESULT ShowDeleteFile(const wchar_t *name, bool isDir) x \
+
+ /*
+ virtual HRESULT ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value) x \
+ virtual HRESULT ReportRawProp(UInt32 indexType, UInt32 index, PROPID propID, const void *data, UInt32 dataSize, UInt32 propType) x \
+ virtual HRESULT ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes) x \
+ */
+
+ /* virtual HRESULT CloseProgress() { return S_OK; } */
+
+Z7_IFACE_DECL_PURE(IUpdateCallbackUI)
+Z7_PURE_INTERFACES_END
+
+struct CKeyKeyValPair
+{
+ UInt64 Key1;
+ UInt64 Key2;
+ unsigned Value;
+
+ int Compare(const CKeyKeyValPair &a) const
+ {
+ if (Key1 < a.Key1) return -1;
+ if (Key1 > a.Key1) return 1;
+ return MyCompare(Key2, a.Key2);
+ }
+};
+
+
+class CArchiveUpdateCallback Z7_final:
+ public IArchiveUpdateCallback2,
+ public IArchiveUpdateCallbackFile,
+ // public IArchiveUpdateCallbackArcProp,
+ public IArchiveExtractCallbackMessage2,
+ public IArchiveGetRawProps,
+ public IArchiveGetRootProps,
+ public ICryptoGetTextPassword2,
+ public ICryptoGetTextPassword,
+ public ICompressProgressInfo,
+ public IInFileStream_Callback,
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(IArchiveUpdateCallback2)
+ Z7_COM_QI_ENTRY(IArchiveUpdateCallbackFile)
+ // Z7_COM_QI_ENTRY(IArchiveUpdateCallbackArcProp)
+ Z7_COM_QI_ENTRY(IArchiveExtractCallbackMessage2)
+ Z7_COM_QI_ENTRY(IArchiveGetRawProps)
+ Z7_COM_QI_ENTRY(IArchiveGetRootProps)
+ Z7_COM_QI_ENTRY(ICryptoGetTextPassword2)
+ Z7_COM_QI_ENTRY(ICryptoGetTextPassword)
+ Z7_COM_QI_ENTRY(ICompressProgressInfo)
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(ICompressProgressInfo)
+
+ Z7_IFACE_COM7_IMP(IProgress)
+ Z7_IFACE_COM7_IMP(IArchiveUpdateCallback)
+ Z7_IFACE_COM7_IMP(IArchiveUpdateCallback2)
+ Z7_IFACE_COM7_IMP(IArchiveUpdateCallbackFile)
+ // Z7_IFACE_COM7_IMP(IArchiveUpdateCallbackArcProp)
+ Z7_IFACE_COM7_IMP(IArchiveExtractCallbackMessage2)
+ Z7_IFACE_COM7_IMP(IArchiveGetRawProps)
+ Z7_IFACE_COM7_IMP(IArchiveGetRootProps)
+ Z7_IFACE_COM7_IMP(ICryptoGetTextPassword2)
+ Z7_IFACE_COM7_IMP(ICryptoGetTextPassword)
+
+
+ void UpdateProcessedItemStatus(unsigned dirIndex);
+
+public:
+ bool PreserveATime;
+ bool ShareForWrite;
+ bool StopAfterOpenError;
+ bool StdInMode;
+
+ bool KeepOriginalItemNames;
+ bool StoreNtSecurity;
+ bool StoreHardLinks;
+ bool StoreSymLinks;
+
+ bool StoreOwnerId;
+ bool StoreOwnerName;
+
+ bool Need_LatestMTime;
+ bool LatestMTime_Defined;
+
+ /*
+ bool Need_ArcMTime_Report;
+ bool ArcMTime_WasReported;
+ */
+
+ CRecordVector<UInt32> _openFiles_Indexes;
+ FStringVector _openFiles_Paths;
+ // CRecordVector< CInFileStream* > _openFiles_Streams;
+
+ bool AreAllFilesClosed() const { return _openFiles_Indexes.IsEmpty(); }
+ virtual HRESULT InFileStream_On_Error(UINT_PTR val, DWORD error) Z7_override;
+ virtual void InFileStream_On_Destroy(CInFileStream *stream, UINT_PTR val) Z7_override;
+
+ IUpdateCallbackUI *Callback;
+
+ const CDirItems *DirItems;
+ const CDirItem *ParentDirItem;
+
+ const CArc *Arc;
+ CMyComPtr<IInArchive> Archive;
+ const CObjectVector<CArcItem> *ArcItems;
+ const CRecordVector<CUpdatePair2> *UpdatePairs;
+
+ CRecordVector<UInt64> VolumesSizes;
+ FString VolName;
+ FString VolExt;
+ UString ArcFileName; // without path prefix
+
+ const UStringVector *NewNames;
+ const UString *Comment;
+ int CommentIndex;
+
+ /*
+ CArcTime Reported_ArcMTime;
+ */
+ CFiTime LatestMTime;
+
+ Byte *ProcessedItemsStatuses;
+
+
+ CArchiveUpdateCallback();
+
+ bool IsDir(const CUpdatePair2 &up) const
+ {
+ if (up.DirIndex >= 0)
+ return DirItems->Items[(unsigned)up.DirIndex].IsDir();
+ else if (up.ArcIndex >= 0)
+ return (*ArcItems)[(unsigned)up.ArcIndex].IsDir;
+ return false;
+ }
+
+private:
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ bool _saclEnabled;
+ #endif
+ CRecordVector<CKeyKeyValPair> _map;
+
+ UInt32 _hardIndex_From;
+ UInt32 _hardIndex_To;
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/UpdatePair.cpp b/CPP/7zip/UI/Common/UpdatePair.cpp
index 5153671..99b0aaf 100644
--- a/CPP/7zip/UI/Common/UpdatePair.cpp
+++ b/CPP/7zip/UI/Common/UpdatePair.cpp
@@ -1,233 +1,302 @@
-// UpdatePair.cpp
-
-#include "StdAfx.h"
-
-#include <time.h>
-
-#include "../../../Common/Wildcard.h"
-
-#include "../../../Windows/TimeUtils.h"
-
-#include "SortUtils.h"
-#include "UpdatePair.h"
-
-using namespace NWindows;
-using namespace NTime;
-
-static int MyCompareTime(NFileTimeType::EEnum fileTimeType, const FILETIME &time1, const FILETIME &time2)
-{
- switch (fileTimeType)
- {
- case NFileTimeType::kWindows:
- return ::CompareFileTime(&time1, &time2);
- case NFileTimeType::kUnix:
- {
- UInt32 unixTime1, unixTime2;
- FileTimeToUnixTime(time1, unixTime1);
- FileTimeToUnixTime(time2, unixTime2);
- return MyCompare(unixTime1, unixTime2);
- }
- case NFileTimeType::kDOS:
- {
- UInt32 dosTime1, dosTime2;
- FileTimeToDosTime(time1, dosTime1);
- FileTimeToDosTime(time2, dosTime2);
- return MyCompare(dosTime1, dosTime2);
- }
- }
- throw 4191618;
-}
-
-static const char * const k_Duplicate_inArc_Message = "Duplicate filename in archive:";
-static const char * const k_Duplicate_inDir_Message = "Duplicate filename on disk:";
-static const char * const k_NotCensoredCollision_Message = "Internal file name collision (file on disk, file in archive):";
-
-static void ThrowError(const char *message, const UString &s1, const UString &s2)
-{
- UString m (message);
- m.Add_LF(); m += s1;
- m.Add_LF(); m += s2;
- throw m;
-}
-
-static int CompareArcItemsBase(const CArcItem &ai1, const CArcItem &ai2)
-{
- int res = CompareFileNames(ai1.Name, ai2.Name);
- if (res != 0)
- return res;
- if (ai1.IsDir != ai2.IsDir)
- return ai1.IsDir ? -1 : 1;
- return 0;
-}
-
-static int CompareArcItems(const unsigned *p1, const unsigned *p2, void *param)
-{
- unsigned i1 = *p1;
- unsigned i2 = *p2;
- const CObjectVector<CArcItem> &arcItems = *(const CObjectVector<CArcItem> *)param;
- int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]);
- if (res != 0)
- return res;
- return MyCompare(i1, i2);
-}
-
-void GetUpdatePairInfoList(
- const CDirItems &dirItems,
- const CObjectVector<CArcItem> &arcItems,
- NFileTimeType::EEnum fileTimeType,
- CRecordVector<CUpdatePair> &updatePairs)
-{
- CUIntVector dirIndices, arcIndices;
-
- unsigned numDirItems = dirItems.Items.Size();
- unsigned numArcItems = arcItems.Size();
-
- CIntArr duplicatedArcItem(numArcItems);
- {
- int *vals = &duplicatedArcItem[0];
- for (unsigned i = 0; i < numArcItems; i++)
- vals[i] = 0;
- }
-
- {
- arcIndices.ClearAndSetSize(numArcItems);
- if (numArcItems != 0)
- {
- unsigned *vals = &arcIndices[0];
- for (unsigned i = 0; i < numArcItems; i++)
- vals[i] = i;
- }
- arcIndices.Sort(CompareArcItems, (void *)&arcItems);
- for (unsigned i = 0; i + 1 < numArcItems; i++)
- if (CompareArcItemsBase(
- arcItems[arcIndices[i]],
- arcItems[arcIndices[i + 1]]) == 0)
- {
- duplicatedArcItem[i] = 1;
- duplicatedArcItem[i + 1] = -1;
- }
- }
-
- UStringVector dirNames;
- {
- dirNames.ClearAndReserve(numDirItems);
- unsigned i;
- for (i = 0; i < numDirItems; i++)
- dirNames.AddInReserved(dirItems.GetLogPath(i));
- SortFileNames(dirNames, dirIndices);
- for (i = 0; i + 1 < numDirItems; i++)
- {
- const UString &s1 = dirNames[dirIndices[i]];
- const UString &s2 = dirNames[dirIndices[i + 1]];
- if (CompareFileNames(s1, s2) == 0)
- ThrowError(k_Duplicate_inDir_Message, s1, s2);
- }
- }
-
- unsigned dirIndex = 0;
- unsigned arcIndex = 0;
-
- int prevHostFile = -1;
- const UString *prevHostName = NULL;
-
- while (dirIndex < numDirItems || arcIndex < numArcItems)
- {
- CUpdatePair pair;
-
- int dirIndex2 = -1;
- int arcIndex2 = -1;
- const CDirItem *di = NULL;
- const CArcItem *ai = NULL;
-
- int compareResult = -1;
- const UString *name = NULL;
-
- if (dirIndex < numDirItems)
- {
- dirIndex2 = dirIndices[dirIndex];
- di = &dirItems.Items[dirIndex2];
- }
-
- if (arcIndex < numArcItems)
- {
- arcIndex2 = arcIndices[arcIndex];
- ai = &arcItems[arcIndex2];
- compareResult = 1;
- if (dirIndex < numDirItems)
- {
- compareResult = CompareFileNames(dirNames[dirIndex2], ai->Name);
- if (compareResult == 0)
- {
- if (di->IsDir() != ai->IsDir)
- compareResult = (ai->IsDir ? 1 : -1);
- }
- }
- }
-
- if (compareResult < 0)
- {
- name = &dirNames[dirIndex2];
- pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
- pair.DirIndex = dirIndex2;
- dirIndex++;
- }
- else if (compareResult > 0)
- {
- name = &ai->Name;
- pair.State = ai->Censored ?
- NUpdateArchive::NPairState::kOnlyInArchive:
- NUpdateArchive::NPairState::kNotMasked;
- pair.ArcIndex = arcIndex2;
- arcIndex++;
- }
- else
- {
- int dupl = duplicatedArcItem[arcIndex];
- if (dupl != 0)
- ThrowError(k_Duplicate_inArc_Message, ai->Name, arcItems[arcIndices[arcIndex + dupl]].Name);
-
- name = &dirNames[dirIndex2];
- if (!ai->Censored)
- ThrowError(k_NotCensoredCollision_Message, *name, ai->Name);
-
- pair.DirIndex = dirIndex2;
- pair.ArcIndex = arcIndex2;
-
- switch (ai->MTimeDefined ? MyCompareTime(
- ai->TimeType != - 1 ? (NFileTimeType::EEnum)ai->TimeType : fileTimeType,
- di->MTime, ai->MTime): 0)
- {
- case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break;
- case 1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break;
- default:
- pair.State = (ai->SizeDefined && di->Size == ai->Size) ?
- NUpdateArchive::NPairState::kSameFiles :
- NUpdateArchive::NPairState::kUnknowNewerFiles;
- }
-
- dirIndex++;
- arcIndex++;
- }
-
- if ((di && di->IsAltStream) ||
- (ai && ai->IsAltStream))
- {
- if (prevHostName)
- {
- unsigned hostLen = prevHostName->Len();
- if (name->Len() > hostLen)
- if ((*name)[hostLen] == ':' && CompareFileNames(*prevHostName, name->Left(hostLen)) == 0)
- pair.HostIndex = prevHostFile;
- }
- }
- else
- {
- prevHostFile = updatePairs.Size();
- prevHostName = name;
- }
-
- updatePairs.Add(pair);
- }
-
- updatePairs.ReserveDown();
-}
+// UpdatePair.cpp
+
+#include "StdAfx.h"
+
+#include <time.h>
+// #include <stdio.h>
+
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/TimeUtils.h"
+
+#include "SortUtils.h"
+#include "UpdatePair.h"
+
+using namespace NWindows;
+using namespace NTime;
+
+
+/*
+ a2.Prec =
+ {
+ 0 (k_PropVar_TimePrec_0):
+ if GetProperty(kpidMTime) returned 0 and
+ GetProperty(kpidTimeType) did not returned VT_UI4.
+ 7z, wim, tar in 7-Zip before v21)
+ in that case we use
+ (prec) that is set by IOutArchive::GetFileTimeType()
+ }
+*/
+
+static int MyCompareTime(unsigned prec, const CFiTime &f1, const CArcTime &a2)
+{
+ // except of precision, we also have limitation, when timestamp is out of range
+
+ /* if (Prec) in archive item is defined, then use global (prec) */
+ if (a2.Prec != k_PropVar_TimePrec_0)
+ prec = a2.Prec;
+
+ CArcTime a1;
+ a1.Set_From_FiTime(f1);
+ /* Set_From_FiTime() must set full form precision:
+ k_PropVar_TimePrec_Base + numDigits
+ windows: 7 digits, non-windows: 9 digits */
+
+ if (prec == k_PropVar_TimePrec_DOS)
+ {
+ const UInt32 dosTime1 = a1.Get_DosTime();
+ const UInt32 dosTime2 = a2.Get_DosTime();
+ return MyCompare(dosTime1, dosTime2);
+ }
+
+ if (prec == k_PropVar_TimePrec_Unix)
+ {
+ const Int64 u2 = FileTime_To_UnixTime64(a2.FT);
+ if (u2 == 0 || u2 == (UInt32)0xFFFFFFFF)
+ {
+ // timestamp probably was saturated in archive to 32-bit
+ // so we use saturated 32-bit value for disk file too.
+ UInt32 u1;
+ FileTime_To_UnixTime(a1.FT, u1);
+ const UInt32 u2_32 = (UInt32)u2;
+ return MyCompare(u1, u2_32);
+ }
+
+ const Int64 u1 = FileTime_To_UnixTime64(a1.FT);
+ return MyCompare(u1, u2);
+ // prec = k_PropVar_TimePrec_Base; // for debug
+ }
+
+ if (prec == k_PropVar_TimePrec_0)
+ prec = k_PropVar_TimePrec_Base + 7;
+ else if (prec == k_PropVar_TimePrec_HighPrec)
+ prec = k_PropVar_TimePrec_Base + 9;
+ else if (prec < k_PropVar_TimePrec_Base)
+ prec = k_PropVar_TimePrec_Base;
+ else if (prec > k_PropVar_TimePrec_Base + 9)
+ prec = k_PropVar_TimePrec_Base + 7;
+
+ // prec now is full form: k_PropVar_TimePrec_Base + numDigits;
+ if (prec > a1.Prec && a1.Prec >= k_PropVar_TimePrec_Base)
+ prec = a1.Prec;
+
+ const unsigned numDigits = prec - k_PropVar_TimePrec_Base;
+ if (numDigits >= 7)
+ {
+ const int comp = CompareFileTime(&a1.FT, &a2.FT);
+ if (comp != 0 || numDigits == 7)
+ return comp;
+ return MyCompare(a1.Ns100, a2.Ns100);
+ }
+ UInt32 d = 1;
+ for (unsigned k = numDigits; k < 7; k++)
+ d *= 10;
+ const UInt64 v1 = a1.Get_FILETIME_as_UInt64() / d * d;
+ const UInt64 v2 = a2.Get_FILETIME_as_UInt64() / d * d;
+ // printf("\ndelta=%d numDigits=%d\n", (unsigned)(v1- v2), numDigits);
+ return MyCompare(v1, v2);
+}
+
+
+
+static const char * const k_Duplicate_inArc_Message = "Duplicate filename in archive:";
+static const char * const k_Duplicate_inDir_Message = "Duplicate filename on disk:";
+static const char * const k_NotCensoredCollision_Message = "Internal file name collision (file on disk, file in archive):";
+
+Z7_ATTR_NORETURN
+static
+void ThrowError(const char *message, const UString &s1, const UString &s2)
+{
+ UString m (message);
+ m.Add_LF(); m += s1;
+ m.Add_LF(); m += s2;
+ throw m;
+}
+
+static int CompareArcItemsBase(const CArcItem &ai1, const CArcItem &ai2)
+{
+ const int res = CompareFileNames(ai1.Name, ai2.Name);
+ if (res != 0)
+ return res;
+ if (ai1.IsDir != ai2.IsDir)
+ return ai1.IsDir ? -1 : 1;
+ return 0;
+}
+
+static int CompareArcItems(const unsigned *p1, const unsigned *p2, void *param)
+{
+ const unsigned i1 = *p1;
+ const unsigned i2 = *p2;
+ const CObjectVector<CArcItem> &arcItems = *(const CObjectVector<CArcItem> *)param;
+ const int res = CompareArcItemsBase(arcItems[i1], arcItems[i2]);
+ if (res != 0)
+ return res;
+ return MyCompare(i1, i2);
+}
+
+void GetUpdatePairInfoList(
+ const CDirItems &dirItems,
+ const CObjectVector<CArcItem> &arcItems,
+ NFileTimeType::EEnum fileTimeType,
+ CRecordVector<CUpdatePair> &updatePairs)
+{
+ CUIntVector dirIndices, arcIndices;
+
+ const unsigned numDirItems = dirItems.Items.Size();
+ const unsigned numArcItems = arcItems.Size();
+
+ CIntArr duplicatedArcItem(numArcItems);
+ {
+ int *vals = &duplicatedArcItem[0];
+ for (unsigned i = 0; i < numArcItems; i++)
+ vals[i] = 0;
+ }
+
+ {
+ arcIndices.ClearAndSetSize(numArcItems);
+ if (numArcItems != 0)
+ {
+ unsigned *vals = &arcIndices[0];
+ for (unsigned i = 0; i < numArcItems; i++)
+ vals[i] = i;
+ }
+ arcIndices.Sort(CompareArcItems, (void *)&arcItems);
+ for (unsigned i = 0; i + 1 < numArcItems; i++)
+ if (CompareArcItemsBase(
+ arcItems[arcIndices[i]],
+ arcItems[arcIndices[i + 1]]) == 0)
+ {
+ duplicatedArcItem[i] = 1;
+ duplicatedArcItem[i + 1] = -1;
+ }
+ }
+
+ UStringVector dirNames;
+ {
+ dirNames.ClearAndReserve(numDirItems);
+ unsigned i;
+ for (i = 0; i < numDirItems; i++)
+ dirNames.AddInReserved(dirItems.GetLogPath(i));
+ SortFileNames(dirNames, dirIndices);
+ for (i = 0; i + 1 < numDirItems; i++)
+ {
+ const UString &s1 = dirNames[dirIndices[i]];
+ const UString &s2 = dirNames[dirIndices[i + 1]];
+ if (CompareFileNames(s1, s2) == 0)
+ ThrowError(k_Duplicate_inDir_Message, s1, s2);
+ }
+ }
+
+ unsigned dirIndex = 0;
+ unsigned arcIndex = 0;
+
+ int prevHostFile = -1;
+ const UString *prevHostName = NULL;
+
+ while (dirIndex < numDirItems || arcIndex < numArcItems)
+ {
+ CUpdatePair pair;
+
+ int dirIndex2 = -1;
+ int arcIndex2 = -1;
+ const CDirItem *di = NULL;
+ const CArcItem *ai = NULL;
+
+ int compareResult = -1;
+ const UString *name = NULL;
+
+ if (dirIndex < numDirItems)
+ {
+ dirIndex2 = (int)dirIndices[dirIndex];
+ di = &dirItems.Items[(unsigned)dirIndex2];
+ }
+
+ if (arcIndex < numArcItems)
+ {
+ arcIndex2 = (int)arcIndices[arcIndex];
+ ai = &arcItems[(unsigned)arcIndex2];
+ compareResult = 1;
+ if (dirIndex < numDirItems)
+ {
+ compareResult = CompareFileNames(dirNames[(unsigned)dirIndex2], ai->Name);
+ if (compareResult == 0)
+ {
+ if (di->IsDir() != ai->IsDir)
+ compareResult = (ai->IsDir ? 1 : -1);
+ }
+ }
+ }
+
+ if (compareResult < 0)
+ {
+ name = &dirNames[(unsigned)dirIndex2];
+ pair.State = NUpdateArchive::NPairState::kOnlyOnDisk;
+ pair.DirIndex = dirIndex2;
+ dirIndex++;
+ }
+ else if (compareResult > 0)
+ {
+ name = &ai->Name;
+ pair.State = ai->Censored ?
+ NUpdateArchive::NPairState::kOnlyInArchive:
+ NUpdateArchive::NPairState::kNotMasked;
+ pair.ArcIndex = arcIndex2;
+ arcIndex++;
+ }
+ else
+ {
+ const int dupl = duplicatedArcItem[arcIndex];
+ if (dupl != 0)
+ ThrowError(k_Duplicate_inArc_Message, ai->Name, arcItems[arcIndices[(unsigned)((int)arcIndex + dupl)]].Name);
+
+ name = &dirNames[(unsigned)dirIndex2];
+ if (!ai->Censored)
+ ThrowError(k_NotCensoredCollision_Message, *name, ai->Name);
+
+ pair.DirIndex = dirIndex2;
+ pair.ArcIndex = arcIndex2;
+
+ int compResult = 0;
+ if (ai->MTime.Def)
+ {
+ compResult = MyCompareTime((unsigned)fileTimeType, di->MTime, ai->MTime);
+ }
+ switch (compResult)
+ {
+ case -1: pair.State = NUpdateArchive::NPairState::kNewInArchive; break;
+ case 1: pair.State = NUpdateArchive::NPairState::kOldInArchive; break;
+ default:
+ pair.State = (ai->Size_Defined && di->Size == ai->Size) ?
+ NUpdateArchive::NPairState::kSameFiles :
+ NUpdateArchive::NPairState::kUnknowNewerFiles;
+ }
+
+ dirIndex++;
+ arcIndex++;
+ }
+
+ if (
+ #ifdef _WIN32
+ (di && di->IsAltStream) ||
+ #endif
+ (ai && ai->IsAltStream))
+ {
+ if (prevHostName)
+ {
+ const unsigned hostLen = prevHostName->Len();
+ if (name->Len() > hostLen)
+ if ((*name)[hostLen] == ':' && CompareFileNames(*prevHostName, name->Left(hostLen)) == 0)
+ pair.HostIndex = prevHostFile;
+ }
+ }
+ else
+ {
+ prevHostFile = (int)updatePairs.Size();
+ prevHostName = name;
+ }
+
+ updatePairs.Add(pair);
+ }
+
+ updatePairs.ReserveDown();
+}
diff --git a/CPP/7zip/UI/Common/UpdatePair.h b/CPP/7zip/UI/Common/UpdatePair.h
index 36da243..13228b0 100644
--- a/CPP/7zip/UI/Common/UpdatePair.h
+++ b/CPP/7zip/UI/Common/UpdatePair.h
@@ -1,27 +1,27 @@
-// UpdatePair.h
-
-#ifndef __UPDATE_PAIR_H
-#define __UPDATE_PAIR_H
-
-#include "DirItem.h"
-#include "UpdateAction.h"
-
-#include "../../Archive/IArchive.h"
-
-struct CUpdatePair
-{
- NUpdateArchive::NPairState::EEnum State;
- int ArcIndex;
- int DirIndex;
- int HostIndex; // >= 0 for alt streams only, contains index of host pair
-
- CUpdatePair(): ArcIndex(-1), DirIndex(-1), HostIndex(-1) {}
-};
-
-void GetUpdatePairInfoList(
- const CDirItems &dirItems,
- const CObjectVector<CArcItem> &arcItems,
- NFileTimeType::EEnum fileTimeType,
- CRecordVector<CUpdatePair> &updatePairs);
-
-#endif
+// UpdatePair.h
+
+#ifndef ZIP7_INC_UPDATE_PAIR_H
+#define ZIP7_INC_UPDATE_PAIR_H
+
+#include "DirItem.h"
+#include "UpdateAction.h"
+
+#include "../../Archive/IArchive.h"
+
+struct CUpdatePair
+{
+ NUpdateArchive::NPairState::EEnum State;
+ int ArcIndex;
+ int DirIndex;
+ int HostIndex; // >= 0 for alt streams only, contains index of host pair
+
+ CUpdatePair(): ArcIndex(-1), DirIndex(-1), HostIndex(-1) {}
+};
+
+void GetUpdatePairInfoList(
+ const CDirItems &dirItems,
+ const CObjectVector<CArcItem> &arcItems,
+ NFileTimeType::EEnum fileTimeType,
+ CRecordVector<CUpdatePair> &updatePairs);
+
+#endif
diff --git a/CPP/7zip/UI/Common/UpdateProduce.cpp b/CPP/7zip/UI/Common/UpdateProduce.cpp
index c025ac4..e921dc3 100644
--- a/CPP/7zip/UI/Common/UpdateProduce.cpp
+++ b/CPP/7zip/UI/Common/UpdateProduce.cpp
@@ -1,70 +1,72 @@
-// UpdateProduce.cpp
-
-#include "StdAfx.h"
-
-#include "UpdateProduce.h"
-
-using namespace NUpdateArchive;
-
-static const char * const kUpdateActionSetCollision = "Internal collision in update action set";
-
-void UpdateProduce(
- const CRecordVector<CUpdatePair> &updatePairs,
- const CActionSet &actionSet,
- CRecordVector<CUpdatePair2> &operationChain,
- IUpdateProduceCallback *callback)
-{
- FOR_VECTOR (i, updatePairs)
- {
- const CUpdatePair &pair = updatePairs[i];
-
- CUpdatePair2 up2;
- up2.DirIndex = pair.DirIndex;
- up2.ArcIndex = pair.ArcIndex;
- up2.NewData = up2.NewProps = true;
- up2.UseArcProps = false;
-
- switch (actionSet.StateActions[(unsigned)pair.State])
- {
- case NPairAction::kIgnore:
- if (pair.ArcIndex >= 0 && callback)
- callback->ShowDeleteFile(pair.ArcIndex);
- continue;
-
- case NPairAction::kCopy:
- if (pair.State == NPairState::kOnlyOnDisk)
- throw kUpdateActionSetCollision;
- if (pair.State == NPairState::kOnlyInArchive)
- {
- if (pair.HostIndex >= 0)
- {
- /*
- ignore alt stream if
- 1) no such alt stream in Disk
- 2) there is Host file in disk
- */
- if (updatePairs[pair.HostIndex].DirIndex >= 0)
- continue;
- }
- }
- up2.NewData = up2.NewProps = false;
- up2.UseArcProps = true;
- break;
-
- case NPairAction::kCompress:
- if (pair.State == NPairState::kOnlyInArchive ||
- pair.State == NPairState::kNotMasked)
- throw kUpdateActionSetCollision;
- break;
-
- case NPairAction::kCompressAsAnti:
- up2.IsAnti = true;
- up2.UseArcProps = (pair.ArcIndex >= 0);
- break;
- }
-
- operationChain.Add(up2);
- }
-
- operationChain.ReserveDown();
-}
+// UpdateProduce.cpp
+
+#include "StdAfx.h"
+
+#include "UpdateProduce.h"
+
+using namespace NUpdateArchive;
+
+static const char * const kUpdateActionSetCollision = "Internal collision in update action set";
+
+void UpdateProduce(
+ const CRecordVector<CUpdatePair> &updatePairs,
+ const CActionSet &actionSet,
+ CRecordVector<CUpdatePair2> &operationChain,
+ IUpdateProduceCallback *callback)
+{
+ FOR_VECTOR (i, updatePairs)
+ {
+ const CUpdatePair &pair = updatePairs[i];
+
+ CUpdatePair2 up2;
+ up2.DirIndex = pair.DirIndex;
+ up2.ArcIndex = pair.ArcIndex;
+ up2.NewData = up2.NewProps = true;
+ up2.UseArcProps = false;
+
+ switch (actionSet.StateActions[(unsigned)pair.State])
+ {
+ case NPairAction::kIgnore:
+ if (pair.ArcIndex >= 0 && callback)
+ callback->ShowDeleteFile((unsigned)pair.ArcIndex);
+ continue;
+
+ case NPairAction::kCopy:
+ if (pair.State == NPairState::kOnlyOnDisk)
+ throw kUpdateActionSetCollision;
+ if (pair.State == NPairState::kOnlyInArchive)
+ {
+ if (pair.HostIndex >= 0)
+ {
+ /*
+ ignore alt stream if
+ 1) no such alt stream in Disk
+ 2) there is Host file in disk
+ */
+ if (updatePairs[(unsigned)pair.HostIndex].DirIndex >= 0)
+ continue;
+ }
+ }
+ up2.NewData = up2.NewProps = false;
+ up2.UseArcProps = true;
+ break;
+
+ case NPairAction::kCompress:
+ if (pair.State == NPairState::kOnlyInArchive ||
+ pair.State == NPairState::kNotMasked)
+ throw kUpdateActionSetCollision;
+ break;
+
+ case NPairAction::kCompressAsAnti:
+ up2.IsAnti = true;
+ up2.UseArcProps = (pair.ArcIndex >= 0);
+ break;
+ }
+
+ up2.IsSameTime = ((unsigned)pair.State == NUpdateArchive::NPairState::kSameFiles);
+
+ operationChain.Add(up2);
+ }
+
+ operationChain.ReserveDown();
+}
diff --git a/CPP/7zip/UI/Common/UpdateProduce.h b/CPP/7zip/UI/Common/UpdateProduce.h
index 8467543..9db6c1e 100644
--- a/CPP/7zip/UI/Common/UpdateProduce.h
+++ b/CPP/7zip/UI/Common/UpdateProduce.h
@@ -1,55 +1,60 @@
-// UpdateProduce.h
-
-#ifndef __UPDATE_PRODUCE_H
-#define __UPDATE_PRODUCE_H
-
-#include "UpdatePair.h"
-
-struct CUpdatePair2
-{
- bool NewData;
- bool NewProps;
- bool UseArcProps; // if (UseArcProps && NewProps), we want to change only some properties.
- bool IsAnti; // if (!IsAnti) we use other ways to detect Anti status
-
- int DirIndex;
- int ArcIndex;
- int NewNameIndex;
-
- bool IsMainRenameItem;
-
- void SetAs_NoChangeArcItem(int arcIndex)
- {
- NewData = NewProps = false;
- UseArcProps = true;
- IsAnti = false;
- ArcIndex = arcIndex;
- }
-
- bool ExistOnDisk() const { return DirIndex != -1; }
- bool ExistInArchive() const { return ArcIndex != -1; }
-
- CUpdatePair2():
- NewData(false),
- NewProps(false),
- UseArcProps(false),
- IsAnti(false),
- DirIndex(-1),
- ArcIndex(-1),
- NewNameIndex(-1),
- IsMainRenameItem(false)
- {}
-};
-
-struct IUpdateProduceCallback
-{
- virtual HRESULT ShowDeleteFile(unsigned arcIndex) = 0;
-};
-
-void UpdateProduce(
- const CRecordVector<CUpdatePair> &updatePairs,
- const NUpdateArchive::CActionSet &actionSet,
- CRecordVector<CUpdatePair2> &operationChain,
- IUpdateProduceCallback *callback);
-
-#endif
+// UpdateProduce.h
+
+#ifndef ZIP7_INC_UPDATE_PRODUCE_H
+#define ZIP7_INC_UPDATE_PRODUCE_H
+
+#include "UpdatePair.h"
+
+struct CUpdatePair2
+{
+ bool NewData;
+ bool NewProps;
+ bool UseArcProps; // if (UseArcProps && NewProps), we want to change only some properties.
+ bool IsAnti; // if (!IsAnti) we use other ways to detect Anti status
+
+ int DirIndex;
+ int ArcIndex;
+ int NewNameIndex;
+
+ bool IsMainRenameItem;
+ bool IsSameTime;
+
+ void SetAs_NoChangeArcItem(unsigned arcIndex) // int
+ {
+ NewData = NewProps = false;
+ UseArcProps = true;
+ IsAnti = false;
+ ArcIndex = (int)arcIndex;
+ }
+
+ bool ExistOnDisk() const { return DirIndex != -1; }
+ bool ExistInArchive() const { return ArcIndex != -1; }
+
+ CUpdatePair2():
+ NewData(false),
+ NewProps(false),
+ UseArcProps(false),
+ IsAnti(false),
+ DirIndex(-1),
+ ArcIndex(-1),
+ NewNameIndex(-1),
+ IsMainRenameItem(false),
+ IsSameTime(false)
+ {}
+};
+
+Z7_PURE_INTERFACES_BEGIN
+
+DECLARE_INTERFACE(IUpdateProduceCallback)
+{
+ virtual HRESULT ShowDeleteFile(unsigned arcIndex) = 0;
+};
+Z7_PURE_INTERFACES_END
+
+void UpdateProduce(
+ const CRecordVector<CUpdatePair> &updatePairs,
+ const NUpdateArchive::CActionSet &actionSet,
+ CRecordVector<CUpdatePair2> &operationChain,
+ IUpdateProduceCallback *callback);
+
+#endif
diff --git a/CPP/7zip/UI/Common/WorkDir.cpp b/CPP/7zip/UI/Common/WorkDir.cpp
index 03d6eed..cfec635 100644
--- a/CPP/7zip/UI/Common/WorkDir.cpp
+++ b/CPP/7zip/UI/Common/WorkDir.cpp
@@ -1,94 +1,86 @@
-// WorkDir.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/StringConvert.h"
-#include "../../../Common/Wildcard.h"
-
-#include "../../../Windows/FileName.h"
-
-#include "WorkDir.h"
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NDir;
-
-FString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const FString &path, FString &fileName)
-{
- NWorkDir::NMode::EEnum mode = workDirInfo.Mode;
-
- #if defined(_WIN32) && !defined(UNDER_CE)
- if (workDirInfo.ForRemovableOnly)
- {
- mode = NWorkDir::NMode::kCurrent;
- FString prefix = path.Left(3);
- if (prefix[1] == FTEXT(':') && prefix[2] == FTEXT('\\'))
- {
- UINT driveType = GetDriveType(GetSystemString(prefix, ::AreFileApisANSI() ? CP_ACP : CP_OEMCP));
- if (driveType == DRIVE_CDROM || driveType == DRIVE_REMOVABLE)
- mode = workDirInfo.Mode;
- }
- /*
- CParsedPath parsedPath;
- parsedPath.ParsePath(archiveName);
- UINT driveType = GetDriveType(parsedPath.Prefix);
- if ((driveType != DRIVE_CDROM) && (driveType != DRIVE_REMOVABLE))
- mode = NZipSettings::NWorkDir::NMode::kCurrent;
- */
- }
- #endif
-
- int pos = path.ReverseFind_PathSepar() + 1;
- fileName = path.Ptr(pos);
-
- switch (mode)
- {
- case NWorkDir::NMode::kCurrent:
- {
- return path.Left(pos);
- }
- case NWorkDir::NMode::kSpecified:
- {
- FString tempDir = workDirInfo.Path;
- NName::NormalizeDirPathPrefix(tempDir);
- return tempDir;
- }
- default:
- {
- FString tempDir;
- if (!MyGetTempPath(tempDir))
- throw 141717;
- return tempDir;
- }
- }
-}
-
-HRESULT CWorkDirTempFile::CreateTempFile(const FString &originalPath)
-{
- NWorkDir::CInfo workDirInfo;
- workDirInfo.Load();
- FString namePart;
- FString workDir = GetWorkDir(workDirInfo, originalPath, namePart);
- CreateComplexDir(workDir);
- CTempFile tempFile;
- _outStreamSpec = new COutFileStream;
- OutStream = _outStreamSpec;
- if (!_tempFile.Create(workDir + namePart, &_outStreamSpec->File))
- {
- DWORD error = GetLastError();
- return error ? error : E_FAIL;
- }
- _originalPath = originalPath;
- return S_OK;
-}
-
-HRESULT CWorkDirTempFile::MoveToOriginal(bool deleteOriginal)
-{
- OutStream.Release();
- if (!_tempFile.MoveTo(_originalPath, deleteOriginal))
- {
- DWORD error = GetLastError();
- return error ? error : E_FAIL;
- }
- return S_OK;
-}
+// WorkDir.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/FileSystem.h"
+
+#include "WorkDir.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+FString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const FString &path, FString &fileName)
+{
+ NWorkDir::NMode::EEnum mode = workDirInfo.Mode;
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (workDirInfo.ForRemovableOnly)
+ {
+ mode = NWorkDir::NMode::kCurrent;
+ const FString prefix = path.Left(3);
+ if (NName::IsDrivePath(prefix))
+ {
+ const UINT driveType = NSystem::MyGetDriveType(prefix);
+ if (driveType == DRIVE_CDROM || driveType == DRIVE_REMOVABLE)
+ mode = workDirInfo.Mode;
+ }
+ /*
+ CParsedPath parsedPath;
+ parsedPath.ParsePath(archiveName);
+ UINT driveType = GetDriveType(parsedPath.Prefix);
+ if ((driveType != DRIVE_CDROM) && (driveType != DRIVE_REMOVABLE))
+ mode = NZipSettings::NWorkDir::NMode::kCurrent;
+ */
+ }
+ #endif
+
+ const int pos = path.ReverseFind_PathSepar() + 1;
+ fileName = path.Ptr((unsigned)pos);
+
+ FString tempDir;
+ switch ((int)mode)
+ {
+ case NWorkDir::NMode::kCurrent:
+ tempDir = path.Left((unsigned)pos);
+ break;
+ case NWorkDir::NMode::kSpecified:
+ tempDir = workDirInfo.Path;
+ break;
+ // case NWorkDir::NMode::kSystem:
+ default:
+ if (!MyGetTempPath(tempDir))
+ throw 141717;
+ break;
+ }
+ NName::NormalizeDirPathPrefix(tempDir);
+ return tempDir;
+}
+
+HRESULT CWorkDirTempFile::CreateTempFile(const FString &originalPath)
+{
+ NWorkDir::CInfo workDirInfo;
+ workDirInfo.Load();
+ FString namePart;
+ const FString workDir = GetWorkDir(workDirInfo, originalPath, namePart);
+ CreateComplexDir(workDir);
+ _outStreamSpec = new COutFileStream;
+ OutStream = _outStreamSpec;
+ if (!_tempFile.Create(workDir + namePart, &_outStreamSpec->File))
+ {
+ return GetLastError_noZero_HRESULT();
+ }
+ _originalPath = originalPath;
+ return S_OK;
+}
+
+HRESULT CWorkDirTempFile::MoveToOriginal(bool deleteOriginal)
+{
+ OutStream.Release();
+ if (!_tempFile.MoveTo(_originalPath, deleteOriginal))
+ {
+ return GetLastError_noZero_HRESULT();
+ }
+ return S_OK;
+}
diff --git a/CPP/7zip/UI/Common/WorkDir.h b/CPP/7zip/UI/Common/WorkDir.h
index 13d4ed9..d32ab9d 100644
--- a/CPP/7zip/UI/Common/WorkDir.h
+++ b/CPP/7zip/UI/Common/WorkDir.h
@@ -1,26 +1,26 @@
-// WorkDir.h
-
-#ifndef __WORK_DIR_H
-#define __WORK_DIR_H
-
-#include "../../../Windows/FileDir.h"
-
-#include "../../Common/FileStreams.h"
-
-#include "ZipRegistry.h"
-
-FString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const FString &path, FString &fileName);
-
-class CWorkDirTempFile
-{
- FString _originalPath;
- NWindows::NFile::NDir::CTempFile _tempFile;
- COutFileStream *_outStreamSpec;
-public:
- CMyComPtr<IOutStream> OutStream;
-
- HRESULT CreateTempFile(const FString &originalPath);
- HRESULT MoveToOriginal(bool deleteOriginal);
-};
-
-#endif
+// WorkDir.h
+
+#ifndef ZIP7_INC_WORK_DIR_H
+#define ZIP7_INC_WORK_DIR_H
+
+#include "../../../Windows/FileDir.h"
+
+#include "../../Common/FileStreams.h"
+
+#include "ZipRegistry.h"
+
+FString GetWorkDir(const NWorkDir::CInfo &workDirInfo, const FString &path, FString &fileName);
+
+class CWorkDirTempFile
+{
+ FString _originalPath;
+ NWindows::NFile::NDir::CTempFile _tempFile;
+ COutFileStream *_outStreamSpec;
+public:
+ CMyComPtr<IOutStream> OutStream;
+
+ HRESULT CreateTempFile(const FString &originalPath);
+ HRESULT MoveToOriginal(bool deleteOriginal);
+};
+
+#endif
diff --git a/CPP/7zip/UI/Common/ZipRegistry.cpp b/CPP/7zip/UI/Common/ZipRegistry.cpp
new file mode 100644
index 0000000..6c1b9c8
--- /dev/null
+++ b/CPP/7zip/UI/Common/ZipRegistry.cpp
@@ -0,0 +1,580 @@
+// ZipRegistry.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/Registry.h"
+#include "../../../Windows/Synchronization.h"
+
+// #include "../Explorer/ContextMenuFlags.h"
+#include "ZipRegistry.h"
+
+using namespace NWindows;
+using namespace NRegistry;
+
+static NSynchronization::CCriticalSection g_CS;
+#define CS_LOCK NSynchronization::CCriticalSectionLock lock(g_CS);
+
+static LPCTSTR const kCuPrefix = TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-Zip") TEXT(STRING_PATH_SEPARATOR);
+
+static CSysString GetKeyPath(LPCTSTR path) { return kCuPrefix + (CSysString)path; }
+
+static LONG OpenMainKey(CKey &key, LPCTSTR keyName)
+{
+ return key.Open(HKEY_CURRENT_USER, GetKeyPath(keyName), KEY_READ);
+}
+
+static LONG CreateMainKey(CKey &key, LPCTSTR keyName)
+{
+ return key.Create(HKEY_CURRENT_USER, GetKeyPath(keyName));
+}
+
+static void Key_Set_UInt32(CKey &key, LPCTSTR name, UInt32 value)
+{
+ if (value == (UInt32)(Int32)-1)
+ key.DeleteValue(name);
+ else
+ key.SetValue(name, value);
+}
+
+
+static void Key_Get_UInt32(CKey &key, LPCTSTR name, UInt32 &value)
+{
+ if (key.QueryValue(name, value) != ERROR_SUCCESS)
+ value = (UInt32)(Int32)-1;
+}
+
+
+static void Key_Set_BoolPair(CKey &key, LPCTSTR name, const CBoolPair &b)
+{
+ if (b.Def)
+ key.SetValue(name, b.Val);
+}
+
+static void Key_Set_bool_if_Changed(CKey &key, LPCTSTR name, bool val)
+{
+ bool oldVal = false;
+ if (key.GetValue_IfOk(name, oldVal) == ERROR_SUCCESS)
+ if (val == oldVal)
+ return;
+ key.SetValue(name, val);
+}
+
+static void Key_Set_BoolPair_Delete_IfNotDef(CKey &key, LPCTSTR name, const CBoolPair &b)
+{
+ if (b.Def)
+ Key_Set_bool_if_Changed(key, name, b.Val);
+ else
+ key.DeleteValue(name);
+}
+
+static void Key_Get_BoolPair(CKey &key, LPCTSTR name, CBoolPair &b)
+{
+ b.Val = false;
+ b.Def = (key.GetValue_IfOk(name, b.Val) == ERROR_SUCCESS);
+}
+
+static void Key_Get_BoolPair_true(CKey &key, LPCTSTR name, CBoolPair &b)
+{
+ b.Val = true;
+ b.Def = (key.GetValue_IfOk(name, b.Val) == ERROR_SUCCESS);
+}
+
+namespace NExtract
+{
+
+static LPCTSTR const kKeyName = TEXT("Extraction");
+
+static LPCTSTR const kExtractMode = TEXT("ExtractMode");
+static LPCTSTR const kOverwriteMode = TEXT("OverwriteMode");
+static LPCTSTR const kShowPassword = TEXT("ShowPassword");
+static LPCTSTR const kPathHistory = TEXT("PathHistory");
+static LPCTSTR const kSplitDest = TEXT("SplitDest");
+static LPCTSTR const kElimDup = TEXT("ElimDup");
+// static LPCTSTR const kAltStreams = TEXT("AltStreams");
+static LPCTSTR const kNtSecur = TEXT("Security");
+
+void CInfo::Save() const
+{
+ CS_LOCK
+ CKey key;
+ CreateMainKey(key, kKeyName);
+
+ if (PathMode_Force)
+ key.SetValue(kExtractMode, (UInt32)PathMode);
+ if (OverwriteMode_Force)
+ key.SetValue(kOverwriteMode, (UInt32)OverwriteMode);
+
+ Key_Set_BoolPair(key, kSplitDest, SplitDest);
+ Key_Set_BoolPair(key, kElimDup, ElimDup);
+ // Key_Set_BoolPair(key, kAltStreams, AltStreams);
+ Key_Set_BoolPair(key, kNtSecur, NtSecurity);
+ Key_Set_BoolPair(key, kShowPassword, ShowPassword);
+
+ key.RecurseDeleteKey(kPathHistory);
+ key.SetValue_Strings(kPathHistory, Paths);
+}
+
+void Save_ShowPassword(bool showPassword)
+{
+ CS_LOCK
+ CKey key;
+ CreateMainKey(key, kKeyName);
+ key.SetValue(kShowPassword, showPassword);
+}
+
+void CInfo::Load()
+{
+ PathMode = NPathMode::kCurPaths;
+ PathMode_Force = false;
+ OverwriteMode = NOverwriteMode::kAsk;
+ OverwriteMode_Force = false;
+
+ SplitDest.Val = true;
+
+ Paths.Clear();
+
+ CS_LOCK
+ CKey key;
+ if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS)
+ return;
+
+ key.GetValue_Strings(kPathHistory, Paths);
+ UInt32 v;
+ if (key.QueryValue(kExtractMode, v) == ERROR_SUCCESS && v <= NPathMode::kAbsPaths)
+ {
+ PathMode = (NPathMode::EEnum)v;
+ PathMode_Force = true;
+ }
+ if (key.QueryValue(kOverwriteMode, v) == ERROR_SUCCESS && v <= NOverwriteMode::kRenameExisting)
+ {
+ OverwriteMode = (NOverwriteMode::EEnum)v;
+ OverwriteMode_Force = true;
+ }
+
+ Key_Get_BoolPair_true(key, kSplitDest, SplitDest);
+
+ Key_Get_BoolPair(key, kElimDup, ElimDup);
+ // Key_Get_BoolPair(key, kAltStreams, AltStreams);
+ Key_Get_BoolPair(key, kNtSecur, NtSecurity);
+ Key_Get_BoolPair(key, kShowPassword, ShowPassword);
+}
+
+bool Read_ShowPassword()
+{
+ CS_LOCK
+ CKey key;
+ bool showPassword = false;
+ if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS)
+ return showPassword;
+ key.GetValue_IfOk(kShowPassword, showPassword);
+ return showPassword;
+}
+
+}
+
+namespace NCompression
+{
+
+static LPCTSTR const kKeyName = TEXT("Compression");
+
+static LPCTSTR const kArcHistory = TEXT("ArcHistory");
+static LPCWSTR const kArchiver = L"Archiver";
+static LPCTSTR const kShowPassword = TEXT("ShowPassword");
+static LPCTSTR const kEncryptHeaders = TEXT("EncryptHeaders");
+
+static LPCTSTR const kOptionsKeyName = TEXT("Options");
+
+static LPCTSTR const kLevel = TEXT("Level");
+static LPCTSTR const kDictionary = TEXT("Dictionary");
+// static LPCTSTR const kDictionaryChain = TEXT("DictionaryChain");
+static LPCTSTR const kOrder = TEXT("Order");
+static LPCTSTR const kBlockSize = TEXT("BlockSize");
+static LPCTSTR const kNumThreads = TEXT("NumThreads");
+static LPCWSTR const kMethod = L"Method";
+static LPCWSTR const kOptions = L"Options";
+static LPCWSTR const kEncryptionMethod = L"EncryptionMethod";
+
+static LPCTSTR const kNtSecur = TEXT("Security");
+static LPCTSTR const kAltStreams = TEXT("AltStreams");
+static LPCTSTR const kHardLinks = TEXT("HardLinks");
+static LPCTSTR const kSymLinks = TEXT("SymLinks");
+static LPCTSTR const kPreserveATime = TEXT("PreserveATime");
+
+static LPCTSTR const kTimePrec = TEXT("TimePrec");
+static LPCTSTR const kMTime = TEXT("MTime");
+static LPCTSTR const kATime = TEXT("ATime");
+static LPCTSTR const kCTime = TEXT("CTime");
+static LPCTSTR const kSetArcMTime = TEXT("SetArcMTime");
+
+static void SetRegString(CKey &key, LPCWSTR name, const UString &value)
+{
+ if (value.IsEmpty())
+ key.DeleteValue(name);
+ else
+ key.SetValue(name, value);
+}
+
+static void GetRegString(CKey &key, LPCWSTR name, UString &value)
+{
+ if (key.QueryValue(name, value) != ERROR_SUCCESS)
+ value.Empty();
+}
+
+static LPCWSTR const kMemUse = L"MemUse"
+ #if defined(MY_CPU_SIZEOF_POINTER) && (MY_CPU_SIZEOF_POINTER == 4)
+ L"32";
+ #else
+ L"64";
+ #endif
+
+void CInfo::Save() const
+{
+ CS_LOCK
+
+ CKey key;
+ CreateMainKey(key, kKeyName);
+
+ Key_Set_BoolPair_Delete_IfNotDef (key, kNtSecur, NtSecurity);
+ Key_Set_BoolPair_Delete_IfNotDef (key, kAltStreams, AltStreams);
+ Key_Set_BoolPair_Delete_IfNotDef (key, kHardLinks, HardLinks);
+ Key_Set_BoolPair_Delete_IfNotDef (key, kSymLinks, SymLinks);
+ Key_Set_BoolPair_Delete_IfNotDef (key, kPreserveATime, PreserveATime);
+
+ key.SetValue(kShowPassword, ShowPassword);
+ key.SetValue(kLevel, (UInt32)Level);
+ key.SetValue(kArchiver, ArcType);
+ key.SetValue(kShowPassword, ShowPassword);
+ key.SetValue(kEncryptHeaders, EncryptHeaders);
+ key.RecurseDeleteKey(kArcHistory);
+ key.SetValue_Strings(kArcHistory, ArcPaths);
+
+ key.RecurseDeleteKey(kOptionsKeyName);
+ {
+ CKey optionsKey;
+ optionsKey.Create(key, kOptionsKeyName);
+ FOR_VECTOR (i, Formats)
+ {
+ const CFormatOptions &fo = Formats[i];
+ CKey fk;
+ fk.Create(optionsKey, fo.FormatID);
+
+ SetRegString(fk, kMethod, fo.Method);
+ SetRegString(fk, kOptions, fo.Options);
+ SetRegString(fk, kEncryptionMethod, fo.EncryptionMethod);
+ SetRegString(fk, kMemUse, fo.MemUse);
+
+ Key_Set_UInt32(fk, kLevel, fo.Level);
+ Key_Set_UInt32(fk, kDictionary, fo.Dictionary);
+ // Key_Set_UInt32(fk, kDictionaryChain, fo.DictionaryChain);
+ Key_Set_UInt32(fk, kOrder, fo.Order);
+ Key_Set_UInt32(fk, kBlockSize, fo.BlockLogSize);
+ Key_Set_UInt32(fk, kNumThreads, fo.NumThreads);
+
+ Key_Set_UInt32(fk, kTimePrec, fo.TimePrec);
+ Key_Set_BoolPair_Delete_IfNotDef (fk, kMTime, fo.MTime);
+ Key_Set_BoolPair_Delete_IfNotDef (fk, kATime, fo.ATime);
+ Key_Set_BoolPair_Delete_IfNotDef (fk, kCTime, fo.CTime);
+ Key_Set_BoolPair_Delete_IfNotDef (fk, kSetArcMTime, fo.SetArcMTime);
+ }
+ }
+}
+
+void CInfo::Load()
+{
+ ArcPaths.Clear();
+ Formats.Clear();
+
+ Level = 5;
+ ArcType = L"7z";
+ ShowPassword = false;
+ EncryptHeaders = false;
+
+ CS_LOCK
+ CKey key;
+
+ if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS)
+ return;
+
+ Key_Get_BoolPair(key, kNtSecur, NtSecurity);
+ Key_Get_BoolPair(key, kAltStreams, AltStreams);
+ Key_Get_BoolPair(key, kHardLinks, HardLinks);
+ Key_Get_BoolPair(key, kSymLinks, SymLinks);
+ Key_Get_BoolPair(key, kPreserveATime, PreserveATime);
+
+ key.GetValue_Strings(kArcHistory, ArcPaths);
+
+ {
+ CKey optionsKey;
+ if (optionsKey.Open(key, kOptionsKeyName, KEY_READ) == ERROR_SUCCESS)
+ {
+ CSysStringVector formatIDs;
+ optionsKey.EnumKeys(formatIDs);
+ FOR_VECTOR (i, formatIDs)
+ {
+ CKey fk;
+ CFormatOptions fo;
+ fo.FormatID = formatIDs[i];
+ if (fk.Open(optionsKey, fo.FormatID, KEY_READ) == ERROR_SUCCESS)
+ {
+ GetRegString(fk, kMethod, fo.Method);
+ GetRegString(fk, kOptions, fo.Options);
+ GetRegString(fk, kEncryptionMethod, fo.EncryptionMethod);
+ GetRegString(fk, kMemUse, fo.MemUse);
+
+ Key_Get_UInt32(fk, kLevel, fo.Level);
+ Key_Get_UInt32(fk, kDictionary, fo.Dictionary);
+ // Key_Get_UInt32(fk, kDictionaryChain, fo.DictionaryChain);
+ Key_Get_UInt32(fk, kOrder, fo.Order);
+ Key_Get_UInt32(fk, kBlockSize, fo.BlockLogSize);
+ Key_Get_UInt32(fk, kNumThreads, fo.NumThreads);
+
+ Key_Get_UInt32(fk, kTimePrec, fo.TimePrec);
+ Key_Get_BoolPair(fk, kMTime, fo.MTime);
+ Key_Get_BoolPair(fk, kATime, fo.ATime);
+ Key_Get_BoolPair(fk, kCTime, fo.CTime);
+ Key_Get_BoolPair(fk, kSetArcMTime, fo.SetArcMTime);
+
+ Formats.Add(fo);
+ }
+ }
+ }
+ }
+
+ UString a;
+ if (key.QueryValue(kArchiver, a) == ERROR_SUCCESS)
+ ArcType = a;
+ key.GetValue_IfOk(kLevel, Level);
+ key.GetValue_IfOk(kShowPassword, ShowPassword);
+ key.GetValue_IfOk(kEncryptHeaders, EncryptHeaders);
+}
+
+
+static bool ParseMemUse(const wchar_t *s, CMemUse &mu)
+{
+ mu.Clear();
+
+ bool percentMode = false;
+ {
+ const wchar_t c = *s;
+ if (MyCharLower_Ascii(c) == 'p')
+ {
+ percentMode = true;
+ s++;
+ }
+ }
+ const wchar_t *end;
+ UInt64 number = ConvertStringToUInt64(s, &end);
+ if (end == s)
+ return false;
+
+ wchar_t c = *end;
+
+ if (percentMode)
+ {
+ if (c != 0)
+ return false;
+ mu.IsPercent = true;
+ mu.Val = number;
+ return true;
+ }
+
+ if (c == 0)
+ {
+ mu.Val = number;
+ return true;
+ }
+
+ c = MyCharLower_Ascii(c);
+
+ const wchar_t c1 = end[1];
+
+ if (c == '%')
+ {
+ if (c1 != 0)
+ return false;
+ mu.IsPercent = true;
+ mu.Val = number;
+ return true;
+ }
+
+ if (c == 'b')
+ {
+ if (c1 != 0)
+ return false;
+ mu.Val = number;
+ return true;
+ }
+
+ if (c1 != 0)
+ if (MyCharLower_Ascii(c1) != 'b' || end[2] != 0)
+ return false;
+
+ unsigned numBits;
+ switch (c)
+ {
+ case 'k': numBits = 10; break;
+ case 'm': numBits = 20; break;
+ case 'g': numBits = 30; break;
+ case 't': numBits = 40; break;
+ default: return false;
+ }
+ if (number >= ((UInt64)1 << (64 - numBits)))
+ return false;
+ mu.Val = number << numBits;
+ return true;
+}
+
+
+void CMemUse::Parse(const UString &s)
+{
+ IsDefined = ParseMemUse(s, *this);
+}
+
+/*
+void MemLimit_Save(const UString &s)
+{
+ CS_LOCK
+ CKey key;
+ CreateMainKey(key, kKeyName);
+ SetRegString(key, kMemUse, s);
+}
+
+bool MemLimit_Load(NCompression::CMemUse &mu)
+{
+ mu.Clear();
+ UString a;
+ {
+ CS_LOCK
+ CKey key;
+ if (OpenMainKey(key, kKeyName) != ERROR_SUCCESS)
+ return false;
+ if (key.QueryValue(kMemUse, a) != ERROR_SUCCESS)
+ return false;
+ }
+ if (a.IsEmpty())
+ return false;
+ mu.Parse(a);
+ return mu.IsDefined;
+}
+*/
+
+}
+
+static LPCTSTR const kOptionsInfoKeyName = TEXT("Options");
+
+namespace NWorkDir
+{
+static LPCTSTR const kWorkDirType = TEXT("WorkDirType");
+static LPCWSTR const kWorkDirPath = L"WorkDirPath";
+static LPCTSTR const kTempRemovableOnly = TEXT("TempRemovableOnly");
+
+
+void CInfo::Save()const
+{
+ CS_LOCK
+ CKey key;
+ CreateMainKey(key, kOptionsInfoKeyName);
+ key.SetValue(kWorkDirType, (UInt32)Mode);
+ key.SetValue(kWorkDirPath, fs2us(Path));
+ key.SetValue(kTempRemovableOnly, ForRemovableOnly);
+}
+
+void CInfo::Load()
+{
+ SetDefault();
+
+ CS_LOCK
+ CKey key;
+ if (OpenMainKey(key, kOptionsInfoKeyName) != ERROR_SUCCESS)
+ return;
+
+ UInt32 dirType;
+ if (key.QueryValue(kWorkDirType, dirType) != ERROR_SUCCESS)
+ return;
+ switch (dirType)
+ {
+ case NMode::kSystem:
+ case NMode::kCurrent:
+ case NMode::kSpecified:
+ Mode = (NMode::EEnum)dirType;
+ }
+ UString pathU;
+ if (key.QueryValue(kWorkDirPath, pathU) == ERROR_SUCCESS)
+ Path = us2fs(pathU);
+ else
+ {
+ Path.Empty();
+ if (Mode == NMode::kSpecified)
+ Mode = NMode::kSystem;
+ }
+ key.GetValue_IfOk(kTempRemovableOnly, ForRemovableOnly);
+}
+
+}
+
+static LPCTSTR const kCascadedMenu = TEXT("CascadedMenu");
+static LPCTSTR const kContextMenu = TEXT("ContextMenu");
+static LPCTSTR const kMenuIcons = TEXT("MenuIcons");
+static LPCTSTR const kElimDup = TEXT("ElimDupExtract");
+static LPCTSTR const kWriteZoneId = TEXT("WriteZoneIdExtract");
+
+void CContextMenuInfo::Save() const
+{
+ CS_LOCK
+ CKey key;
+ CreateMainKey(key, kOptionsInfoKeyName);
+
+ Key_Set_BoolPair(key, kCascadedMenu, Cascaded);
+ Key_Set_BoolPair(key, kMenuIcons, MenuIcons);
+ Key_Set_BoolPair(key, kElimDup, ElimDup);
+
+ Key_Set_UInt32(key, kWriteZoneId, WriteZone);
+
+ if (Flags_Def)
+ key.SetValue(kContextMenu, Flags);
+}
+
+void CContextMenuInfo::Load()
+{
+ Cascaded.Val = true;
+ Cascaded.Def = false;
+
+ MenuIcons.Val = false;
+ MenuIcons.Def = false;
+
+ ElimDup.Val = true;
+ ElimDup.Def = false;
+
+ WriteZone = (UInt32)(Int32)-1;
+
+ /* we can disable email items by default,
+ because email code doesn't work in some systems */
+ Flags = (UInt32)(Int32)-1
+ /*
+ & ~NContextMenuFlags::kCompressEmail
+ & ~NContextMenuFlags::kCompressTo7zEmail
+ & ~NContextMenuFlags::kCompressToZipEmail
+ */
+ ;
+ Flags_Def = false;
+
+ CS_LOCK
+
+ CKey key;
+ if (OpenMainKey(key, kOptionsInfoKeyName) != ERROR_SUCCESS)
+ return;
+
+ Key_Get_BoolPair_true(key, kCascadedMenu, Cascaded);
+ Key_Get_BoolPair_true(key, kElimDup, ElimDup);
+ Key_Get_BoolPair(key, kMenuIcons, MenuIcons);
+
+ Key_Get_UInt32(key, kWriteZoneId, WriteZone);
+
+ Flags_Def = (key.GetValue_IfOk(kContextMenu, Flags) == ERROR_SUCCESS);
+}
diff --git a/CPP/7zip/UI/Common/ZipRegistry.h b/CPP/7zip/UI/Common/ZipRegistry.h
index 4c16b61..6bc6977 100644
--- a/CPP/7zip/UI/Common/ZipRegistry.h
+++ b/CPP/7zip/UI/Common/ZipRegistry.h
@@ -1,130 +1,209 @@
-// ZipRegistry.h
-
-#ifndef __ZIP_REGISTRY_H
-#define __ZIP_REGISTRY_H
-
-#include "../../../Common/MyTypes.h"
-#include "../../../Common/MyString.h"
-
-#include "ExtractMode.h"
-
-namespace NExtract
-{
- struct CInfo
- {
- NPathMode::EEnum PathMode;
- NOverwriteMode::EEnum OverwriteMode;
- bool PathMode_Force;
- bool OverwriteMode_Force;
-
- CBoolPair SplitDest;
- CBoolPair ElimDup;
- // CBoolPair AltStreams;
- CBoolPair NtSecurity;
- CBoolPair ShowPassword;
-
- UStringVector Paths;
-
- void Save() const;
- void Load();
- };
-
- void Save_ShowPassword(bool showPassword);
- bool Read_ShowPassword();
-}
-
-namespace NCompression
-{
- struct CFormatOptions
- {
- UInt32 Level;
- UInt32 Dictionary;
- UInt32 Order;
- UInt32 BlockLogSize;
- UInt32 NumThreads;
-
- CSysString FormatID;
- UString Method;
- UString Options;
- UString EncryptionMethod;
-
- void Reset_BlockLogSize()
- {
- BlockLogSize = (UInt32)(Int32)-1;
- }
-
- void ResetForLevelChange()
- {
- BlockLogSize = NumThreads = Level = Dictionary = Order = (UInt32)(Int32)-1;
- Method.Empty();
- // Options.Empty();
- // EncryptionMethod.Empty();
- }
- CFormatOptions() { ResetForLevelChange(); }
- };
-
- struct CInfo
- {
- UInt32 Level;
- bool ShowPassword;
- bool EncryptHeaders;
- UString ArcType;
- UStringVector ArcPaths;
-
- CObjectVector<CFormatOptions> Formats;
-
- CBoolPair NtSecurity;
- CBoolPair AltStreams;
- CBoolPair HardLinks;
- CBoolPair SymLinks;
-
- void Save() const;
- void Load();
- };
-}
-
-namespace NWorkDir
-{
- namespace NMode
- {
- enum EEnum
- {
- kSystem,
- kCurrent,
- kSpecified
- };
- }
- struct CInfo
- {
- NMode::EEnum Mode;
- FString Path;
- bool ForRemovableOnly;
-
- void SetForRemovableOnlyDefault() { ForRemovableOnly = true; }
- void SetDefault()
- {
- Mode = NMode::kSystem;
- Path.Empty();
- SetForRemovableOnlyDefault();
- }
-
- void Save() const;
- void Load();
- };
-}
-
-
-struct CContextMenuInfo
-{
- CBoolPair Cascaded;
- CBoolPair MenuIcons;
- CBoolPair ElimDup;
-
- bool Flags_Def;
- UInt32 Flags;
-
- void Save() const;
- void Load();
-};
-
-#endif
+// ZipRegistry.h
+
+#ifndef ZIP7_INC_ZIP_REGISTRY_H
+#define ZIP7_INC_ZIP_REGISTRY_H
+
+#include "../../../Common/MyTypes.h"
+#include "../../../Common/MyString.h"
+
+#include "../../Common/MethodProps.h"
+
+#include "ExtractMode.h"
+
+/*
+CBoolPair::Def in writing functions means:
+ if ( CBoolPair::Def ), we write CBoolPair::Val
+ if ( !CBoolPair::Def )
+ {
+ in NCompression functions we delete registry value
+ in another functions we do nothing
+ }
+*/
+
+namespace NExtract
+{
+ struct CInfo
+ {
+ NPathMode::EEnum PathMode;
+ NOverwriteMode::EEnum OverwriteMode;
+ bool PathMode_Force;
+ bool OverwriteMode_Force;
+
+ CBoolPair SplitDest;
+ CBoolPair ElimDup;
+ // CBoolPair AltStreams;
+ CBoolPair NtSecurity;
+ CBoolPair ShowPassword;
+
+ UStringVector Paths;
+
+ void Save() const;
+ void Load();
+ };
+
+ void Save_ShowPassword(bool showPassword);
+ bool Read_ShowPassword();
+}
+
+namespace NCompression
+{
+ struct CMemUse
+ {
+ // UString Str;
+ bool IsDefined;
+ bool IsPercent;
+ UInt64 Val;
+
+ CMemUse():
+ IsDefined(false),
+ IsPercent(false),
+ Val(0)
+ {}
+
+ void Clear()
+ {
+ // Str.Empty();
+ IsDefined = false;
+ IsPercent = false;
+ Val = 0;
+ }
+
+ UInt64 GetBytes(UInt64 ramSize) const
+ {
+ if (!IsPercent)
+ return Val;
+ return Calc_From_Val_Percents(ramSize, Val);
+ }
+ void Parse(const UString &s);
+ };
+
+ struct CFormatOptions
+ {
+ UInt32 Level;
+ UInt32 Dictionary;
+ // UInt32 DictionaryChain;
+ UInt32 Order;
+ UInt32 BlockLogSize;
+ UInt32 NumThreads;
+
+ UInt32 TimePrec;
+ CBoolPair MTime;
+ CBoolPair ATime;
+ CBoolPair CTime;
+ CBoolPair SetArcMTime;
+
+ CSysString FormatID;
+ UString Method;
+ UString Options;
+ UString EncryptionMethod;
+ UString MemUse;
+
+ void Reset_TimePrec()
+ {
+ TimePrec = (UInt32)(Int32)-1;
+ }
+
+ bool IsSet_TimePrec() const
+ {
+ return TimePrec != (UInt32)(Int32)-1;
+ }
+
+
+ void Reset_BlockLogSize()
+ {
+ BlockLogSize = (UInt32)(Int32)-1;
+ }
+
+ void ResetForLevelChange()
+ {
+ BlockLogSize = NumThreads = Level = Dictionary = Order = (UInt32)(Int32)-1;
+ // DictionaryChain = (UInt32)(Int32)-1;
+ Method.Empty();
+ // Options.Empty();
+ // EncryptionMethod.Empty();
+ }
+ CFormatOptions()
+ {
+ // TimePrec = 0;
+ Reset_TimePrec();
+ ResetForLevelChange();
+ }
+ };
+
+ struct CInfo
+ {
+ UInt32 Level;
+ bool ShowPassword;
+ bool EncryptHeaders;
+
+ CBoolPair NtSecurity;
+ CBoolPair AltStreams;
+ CBoolPair HardLinks;
+ CBoolPair SymLinks;
+
+ CBoolPair PreserveATime;
+
+ UString ArcType;
+ UStringVector ArcPaths;
+
+ CObjectVector<CFormatOptions> Formats;
+
+ void Save() const;
+ void Load();
+ };
+}
+
+namespace NWorkDir
+{
+ namespace NMode
+ {
+ enum EEnum
+ {
+ kSystem,
+ kCurrent,
+ kSpecified
+ };
+ }
+ struct CInfo
+ {
+ NMode::EEnum Mode;
+ bool ForRemovableOnly;
+ FString Path;
+
+ void SetForRemovableOnlyDefault() { ForRemovableOnly = true; }
+ void SetDefault()
+ {
+ Mode = NMode::kSystem;
+ Path.Empty();
+ SetForRemovableOnlyDefault();
+ }
+
+ void Save() const;
+ void Load();
+ };
+}
+
+
+struct CContextMenuInfo
+{
+ CBoolPair Cascaded;
+ CBoolPair MenuIcons;
+ CBoolPair ElimDup;
+
+ bool Flags_Def;
+ UInt32 Flags;
+ UInt32 WriteZone;
+
+ /*
+ CContextMenuInfo():
+ Flags_Def(0),
+ WriteZone((UInt32)(Int32)-1),
+ Flags((UInt32)(Int32)-1)
+ {}
+ */
+
+ void Save() const;
+ void Load();
+};
+
+#endif
diff --git a/CPP/7zip/UI/Console/BenchCon.cpp b/CPP/7zip/UI/Console/BenchCon.cpp
index 9cf8dd6..113f584 100644
--- a/CPP/7zip/UI/Console/BenchCon.cpp
+++ b/CPP/7zip/UI/Console/BenchCon.cpp
@@ -1,41 +1,41 @@
-// BenchCon.cpp
-
-#include "StdAfx.h"
-
-#include "../Common/Bench.h"
-
-#include "BenchCon.h"
-#include "ConsoleClose.h"
-
-struct CPrintBenchCallback: public IBenchPrintCallback
-{
- FILE *_file;
-
- void Print(const char *s);
- void NewLine();
- HRESULT CheckBreak();
-};
-
-void CPrintBenchCallback::Print(const char *s)
-{
- fputs(s, _file);
-}
-
-void CPrintBenchCallback::NewLine()
-{
- fputc('\n', _file);
-}
-
-HRESULT CPrintBenchCallback::CheckBreak()
-{
- return NConsoleClose::TestBreakSignal() ? E_ABORT: S_OK;
-}
-
-HRESULT BenchCon(DECL_EXTERNAL_CODECS_LOC_VARS
- const CObjectVector<CProperty> &props, UInt32 numIterations, FILE *f)
-{
- CPrintBenchCallback callback;
- callback._file = f;
- return Bench(EXTERNAL_CODECS_LOC_VARS
- &callback, NULL, props, numIterations, true);
-}
+// BenchCon.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/Bench.h"
+
+#include "BenchCon.h"
+#include "ConsoleClose.h"
+
+struct CPrintBenchCallback Z7_final: public IBenchPrintCallback
+{
+ FILE *_file;
+
+ void Print(const char *s) Z7_override;
+ void NewLine() Z7_override;
+ HRESULT CheckBreak() Z7_override;
+};
+
+void CPrintBenchCallback::Print(const char *s)
+{
+ fputs(s, _file);
+}
+
+void CPrintBenchCallback::NewLine()
+{
+ fputc('\n', _file);
+}
+
+HRESULT CPrintBenchCallback::CheckBreak()
+{
+ return NConsoleClose::TestBreakSignal() ? E_ABORT: S_OK;
+}
+
+HRESULT BenchCon(DECL_EXTERNAL_CODECS_LOC_VARS
+ const CObjectVector<CProperty> &props, UInt32 numIterations, FILE *f)
+{
+ CPrintBenchCallback callback;
+ callback._file = f;
+ return Bench(EXTERNAL_CODECS_LOC_VARS
+ &callback, NULL, props, numIterations, true);
+}
diff --git a/CPP/7zip/UI/Console/BenchCon.h b/CPP/7zip/UI/Console/BenchCon.h
index ef235ee..844cc2a 100644
--- a/CPP/7zip/UI/Console/BenchCon.h
+++ b/CPP/7zip/UI/Console/BenchCon.h
@@ -1,14 +1,14 @@
-// BenchCon.h
-
-#ifndef __BENCH_CON_H
-#define __BENCH_CON_H
-
-#include <stdio.h>
-
-#include "../../Common/CreateCoder.h"
-#include "../../UI/Common/Property.h"
-
-HRESULT BenchCon(DECL_EXTERNAL_CODECS_LOC_VARS
- const CObjectVector<CProperty> &props, UInt32 numIterations, FILE *f);
-
-#endif
+// BenchCon.h
+
+#ifndef ZIP7_INC_BENCH_CON_H
+#define ZIP7_INC_BENCH_CON_H
+
+#include <stdio.h>
+
+#include "../../Common/CreateCoder.h"
+#include "../../UI/Common/Property.h"
+
+HRESULT BenchCon(DECL_EXTERNAL_CODECS_LOC_VARS
+ const CObjectVector<CProperty> &props, UInt32 numIterations, FILE *f);
+
+#endif
diff --git a/CPP/7zip/UI/Console/Console.dsp b/CPP/7zip/UI/Console/Console.dsp
new file mode 100644
index 0000000..26e8c7f
--- /dev/null
+++ b/CPP/7zip/UI/Console/Console.dsp
@@ -0,0 +1,1040 @@
+# Microsoft Developer Studio Project File - Name="Console" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Console Application" 0x0103
+
+CFG=Console - Win32 DebugU
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "Console.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "Console.mak" CFG="Console - Win32 DebugU"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Console - Win32 Release" (based on "Win32 (x86) Console Application")
+!MESSAGE "Console - Win32 Debug" (based on "Win32 (x86) Console Application")
+!MESSAGE "Console - Win32 ReleaseU" (based on "Win32 (x86) Console Application")
+!MESSAGE "Console - Win32 DebugU" (based on "Win32 (x86) Console Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "Console - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /FAcs /Yu"StdAfx.h" /FD /GF /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"C:\UTIL\7z.exe" /OPT:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "Console - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /Gr /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /FAcs /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"C:\UTIL\7z.exe" /pdbtype:sept /ignore:4033
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "Console - Win32 ReleaseU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Console___Win32_ReleaseU"
+# PROP BASE Intermediate_Dir "Console___Win32_ReleaseU"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "ReleaseU"
+# PROP Intermediate_Dir "ReleaseU"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /Gz /MD /W3 /GX /O1 /I "../../../" /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"StdAfx.h" /FD /c
+# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /c
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"C:\UTIL\7z.exe"
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /machine:I386 /out:"C:\UTIL\7zn.exe" /OPT:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "Console - Win32 DebugU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Console___Win32_DebugU"
+# PROP BASE Intermediate_Dir "Console___Win32_DebugU"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "DebugU"
+# PROP Intermediate_Dir "DebugU"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /Gz /W3 /Gm /GX /ZI /Od /I "../../../" /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c
+# ADD CPP /nologo /Gr /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_CONSOLE" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_LARGE_PAGES" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"C:\UTIL\7z.exe" /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:console /debug /machine:I386 /out:"C:\UTIL\7z.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "Console - Win32 Release"
+# Name "Console - Win32 Debug"
+# Name "Console - Win32 ReleaseU"
+# Name "Console - Win32 DebugU"
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"StdAfx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "Console"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\BenchCon.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\BenchCon.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ConsoleClose.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ConsoleClose.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ExtractCallbackConsole.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ExtractCallbackConsole.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\HashCon.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\HashCon.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\List.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\List.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Main.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\MainAr.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\OpenCallbackConsole.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\OpenCallbackConsole.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\PercentPrinter.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\PercentPrinter.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\UpdateCallbackConsole.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\UpdateCallbackConsole.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\UserInputUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\UserInputUtils.h
+# End Source File
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileLink.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileMapping.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileSystem.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileSystem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryLock.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryLock.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\NtCheck.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Registry.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Registry.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\SecurityUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\SystemInfo.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\SystemInfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Thread.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\TimeUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\TimeUtils.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Common.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ComTry.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynLimBuf.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynLimBuf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ListFileUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ListFileUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyBuffer2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyCom.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyGuidDef.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyInitGuid.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdInStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdInStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StdOutStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.h
+# End Source File
+# End Group
+# Begin Group "UI Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\Common\ArchiveCommandLine.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveCommandLine.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveExtractCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveOpenCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveOpenCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\Bench.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\Bench.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\DefaultName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\DefaultName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\DirItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\EnumDirItems.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\EnumDirItems.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ExitCode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\Extract.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\Extract.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ExtractingFilePath.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ExtractingFilePath.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ExtractMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\HashCalc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\HashCalc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\IFileExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\LoadCodecs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\LoadCodecs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\OpenArchive.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\OpenArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\Property.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\PropIDUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\PropIDUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\SetProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\SetProperties.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\SortUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\SortUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\TempFiles.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\TempFiles.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\Update.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\Update.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateAction.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateAction.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdatePair.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdatePair.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateProduce.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateProduce.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ZipRegistry.h
+# End Source File
+# End Group
+# Begin Group "7-zip Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MultiOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MultiOutStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\PropId.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\RegisterArc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\UniqBlocks.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\UniqBlocks.h
+# End Source File
+# End Group
+# Begin Group "Compress"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.h
+# End Source File
+# End Group
+# Begin Group "C"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.c
+
+!IF "$(CFG)" == "Console - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Console - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Console - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "Console - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\DllSecur.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\DllSecur.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sort.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sort.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.h
+# End Source File
+# End Group
+# Begin Group "ArchiveCommon"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.h
+# End Source File
+# End Group
+# Begin Group "Asm"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\Asm\x86\7zAsm.asm
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\Asm\x86\7zCrcOpt.asm
+
+!IF "$(CFG)" == "Console - Win32 Release"
+
+# Begin Custom Build
+OutDir=.\Release
+InputPath=..\..\..\..\Asm\x86\7zCrcOpt.asm
+InputName=7zCrcOpt
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml.exe -c -Fo$(OutDir)\$(InputName).obj $(InputPath)
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "Console - Win32 Debug"
+
+# Begin Custom Build
+OutDir=.\Debug
+InputPath=..\..\..\..\Asm\x86\7zCrcOpt.asm
+InputName=7zCrcOpt
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml.exe -c -omf -Fo$(OutDir)\$(InputName).obj $(InputPath)
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "Console - Win32 ReleaseU"
+
+# Begin Custom Build
+OutDir=.\ReleaseU
+InputPath=..\..\..\..\Asm\x86\7zCrcOpt.asm
+InputName=7zCrcOpt
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml.exe -c -Fo$(OutDir)\$(InputName).obj $(InputPath)
+
+# End Custom Build
+
+!ELSEIF "$(CFG)" == "Console - Win32 DebugU"
+
+# Begin Custom Build
+OutDir=.\DebugU
+InputPath=..\..\..\..\Asm\x86\7zCrcOpt.asm
+InputName=7zCrcOpt
+
+"$(OutDir)\$(InputName).obj" : $(SOURCE) "$(INTDIR)" "$(OUTDIR)"
+ ml.exe -c -omf -Fo$(OutDir)\$(InputName).obj $(InputPath)
+
+# End Custom Build
+
+!ENDIF
+
+# End Source File
+# End Group
+# Begin Group "Interface"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\IArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ICoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IDecl.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IPassword.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IProgress.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\PropID.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/CPP/7zip/UI/Console/Console.dsw b/CPP/7zip/UI/Console/Console.dsw
new file mode 100644
index 0000000..0d93da2
--- /dev/null
+++ b/CPP/7zip/UI/Console/Console.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "Console"=".\Console.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/UI/Console/Console.mak b/CPP/7zip/UI/Console/Console.mak
index d4268c5..1a47bfa 100644
--- a/CPP/7zip/UI/Console/Console.mak
+++ b/CPP/7zip/UI/Console/Console.mak
@@ -1,43 +1,45 @@
-MY_CONSOLE = 1
-
-!IFNDEF UNDER_CE
-CFLAGS = $(CFLAGS) -DWIN_LONG_PATH -D_7ZIP_LARGE_PAGES -DSUPPORT_DEVICE_FILE
-!ENDIF
-
-CONSOLE_OBJS = \
- $O\BenchCon.obj \
- $O\ConsoleClose.obj \
- $O\ExtractCallbackConsole.obj \
- $O\HashCon.obj \
- $O\List.obj \
- $O\Main.obj \
- $O\MainAr.obj \
- $O\OpenCallbackConsole.obj \
- $O\PercentPrinter.obj \
- $O\UpdateCallbackConsole.obj \
- $O\UserInputUtils.obj \
-
-UI_COMMON_OBJS = \
- $O\ArchiveCommandLine.obj \
- $O\ArchiveExtractCallback.obj \
- $O\ArchiveOpenCallback.obj \
- $O\Bench.obj \
- $O\DefaultName.obj \
- $O\EnumDirItems.obj \
- $O\Extract.obj \
- $O\ExtractingFilePath.obj \
- $O\HashCalc.obj \
- $O\LoadCodecs.obj \
- $O\OpenArchive.obj \
- $O\PropIDUtils.obj \
- $O\SetProperties.obj \
- $O\SortUtils.obj \
- $O\TempFiles.obj \
- $O\Update.obj \
- $O\UpdateAction.obj \
- $O\UpdateCallback.obj \
- $O\UpdatePair.obj \
- $O\UpdateProduce.obj \
-
-C_OBJS = $(C_OBJS) \
- $O\DllSecur.obj \
+MY_CONSOLE = 1
+
+!IFNDEF UNDER_CE
+CFLAGS = $(CFLAGS) -DZ7_LONG_PATH -DZ7_LARGE_PAGES -DZ7_DEVICE_FILE
+!ENDIF
+
+CONSOLE_OBJS = \
+ $O\BenchCon.obj \
+ $O\ConsoleClose.obj \
+ $O\ExtractCallbackConsole.obj \
+ $O\HashCon.obj \
+ $O\List.obj \
+ $O\Main.obj \
+ $O\MainAr.obj \
+ $O\OpenCallbackConsole.obj \
+ $O\PercentPrinter.obj \
+ $O\UpdateCallbackConsole.obj \
+ $O\UserInputUtils.obj \
+
+UI_COMMON_OBJS = \
+ $O\ArchiveCommandLine.obj \
+ $O\ArchiveExtractCallback.obj \
+ $O\ArchiveOpenCallback.obj \
+ $O\Bench.obj \
+ $O\DefaultName.obj \
+ $O\EnumDirItems.obj \
+ $O\Extract.obj \
+ $O\ExtractingFilePath.obj \
+ $O\HashCalc.obj \
+ $O\LoadCodecs.obj \
+ $O\OpenArchive.obj \
+ $O\PropIDUtils.obj \
+ $O\SetProperties.obj \
+ $O\SortUtils.obj \
+ $O\TempFiles.obj \
+ $O\Update.obj \
+ $O\UpdateAction.obj \
+ $O\UpdateCallback.obj \
+ $O\UpdatePair.obj \
+ $O\UpdateProduce.obj \
+
+C_OBJS = $(C_OBJS) \
+ $O\DllSecur.obj \
+
+# we need empty line after last line above
diff --git a/CPP/7zip/UI/Console/Console.manifest b/CPP/7zip/UI/Console/Console.manifest
index 77ecaad..c932b28 100644
--- a/CPP/7zip/UI/Console/Console.manifest
+++ b/CPP/7zip/UI/Console/Console.manifest
@@ -1,13 +1,16 @@
-<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
-<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="7z" type="win32"></assemblyIdentity>
-<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
-<security><requestedPrivileges><requestedExecutionLevel level="asInvoker" uiAccess="false">
-</requestedExecutionLevel></requestedPrivileges></security></trustInfo>
-<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application>
-<!-- Vista --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
-<!-- Win 7 --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
-<!-- Win 8 --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
-<!-- Win 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
-<!-- Win 10 --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
-</application></compatibility>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+<assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="7z" type="win32"></assemblyIdentity>
+<trustInfo xmlns="urn:schemas-microsoft-com:asm.v2">
+<security><requestedPrivileges><requestedExecutionLevel level="asInvoker" uiAccess="false">
+</requestedExecutionLevel></requestedPrivileges></security></trustInfo>
+<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application>
+<!-- Vista --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+<!-- Win 7 --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+<!-- Win 8 --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+<!-- Win 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+<!-- Win 10 --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+</application></compatibility>
+<application xmlns="urn:schemas-microsoft-com:asm.v3">
+<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
+<ws2:longPathAware>true</ws2:longPathAware></windowsSettings></application>
</assembly> \ No newline at end of file
diff --git a/CPP/7zip/UI/Console/ConsoleClose.cpp b/CPP/7zip/UI/Console/ConsoleClose.cpp
index a6f17af..9e4c040 100644
--- a/CPP/7zip/UI/Console/ConsoleClose.cpp
+++ b/CPP/7zip/UI/Console/ConsoleClose.cpp
@@ -1,69 +1,100 @@
-// ConsoleClose.cpp
-
-#include "StdAfx.h"
-
-#include "ConsoleClose.h"
-
-#if !defined(UNDER_CE) && defined(_WIN32)
-#include "../../../Common/MyWindows.h"
-#endif
-
-namespace NConsoleClose {
-
-unsigned g_BreakCounter = 0;
-static const unsigned kBreakAbortThreshold = 2;
-
-#if !defined(UNDER_CE) && defined(_WIN32)
-static BOOL WINAPI HandlerRoutine(DWORD ctrlType)
-{
- if (ctrlType == CTRL_LOGOFF_EVENT)
- {
- // printf("\nCTRL_LOGOFF_EVENT\n");
- return TRUE;
- }
-
- g_BreakCounter++;
- if (g_BreakCounter < kBreakAbortThreshold)
- return TRUE;
- return FALSE;
- /*
- switch (ctrlType)
- {
- case CTRL_C_EVENT:
- case CTRL_BREAK_EVENT:
- if (g_BreakCounter < kBreakAbortThreshold)
- return TRUE;
- }
- return FALSE;
- */
-}
-#endif
-
-/*
-void CheckCtrlBreak()
-{
- if (TestBreakSignal())
- throw CCtrlBreakException();
-}
-*/
-
-CCtrlHandlerSetter::CCtrlHandlerSetter()
-{
- #if !defined(UNDER_CE) && defined(_WIN32)
- if (!SetConsoleCtrlHandler(HandlerRoutine, TRUE))
- throw "SetConsoleCtrlHandler fails";
- #endif
-}
-
-CCtrlHandlerSetter::~CCtrlHandlerSetter()
-{
- #if !defined(UNDER_CE) && defined(_WIN32)
- if (!SetConsoleCtrlHandler(HandlerRoutine, FALSE))
- {
- // warning for throw in destructor.
- // throw "SetConsoleCtrlHandler fails";
- }
- #endif
-}
-
-}
+// ConsoleClose.cpp
+
+#include "StdAfx.h"
+
+#include "ConsoleClose.h"
+
+#ifndef UNDER_CE
+
+#ifdef _WIN32
+#include "../../../Common/MyWindows.h"
+#else
+#include <stdlib.h>
+#include <signal.h>
+#endif
+
+namespace NConsoleClose {
+
+unsigned g_BreakCounter = 0;
+static const unsigned kBreakAbortThreshold = 2;
+
+#ifdef _WIN32
+
+static BOOL WINAPI HandlerRoutine(DWORD ctrlType)
+{
+ if (ctrlType == CTRL_LOGOFF_EVENT)
+ {
+ // printf("\nCTRL_LOGOFF_EVENT\n");
+ return TRUE;
+ }
+
+ g_BreakCounter++;
+ if (g_BreakCounter < kBreakAbortThreshold)
+ return TRUE;
+ return FALSE;
+ /*
+ switch (ctrlType)
+ {
+ case CTRL_C_EVENT:
+ case CTRL_BREAK_EVENT:
+ if (g_BreakCounter < kBreakAbortThreshold)
+ return TRUE;
+ }
+ return FALSE;
+ */
+}
+
+CCtrlHandlerSetter::CCtrlHandlerSetter()
+{
+ if (!SetConsoleCtrlHandler(HandlerRoutine, TRUE))
+ throw "SetConsoleCtrlHandler fails";
+}
+
+CCtrlHandlerSetter::~CCtrlHandlerSetter()
+{
+ if (!SetConsoleCtrlHandler(HandlerRoutine, FALSE))
+ {
+ // warning for throw in destructor.
+ // throw "SetConsoleCtrlHandler fails";
+ }
+}
+
+#else // _WIN32
+
+static void HandlerRoutine(int)
+{
+ g_BreakCounter++;
+ if (g_BreakCounter < kBreakAbortThreshold)
+ return;
+ exit(EXIT_FAILURE);
+}
+
+CCtrlHandlerSetter::CCtrlHandlerSetter()
+{
+ memo_sig_int = signal(SIGINT, HandlerRoutine); // CTRL-C
+ if (memo_sig_int == SIG_ERR)
+ throw "SetConsoleCtrlHandler fails (SIGINT)";
+ memo_sig_term = signal(SIGTERM, HandlerRoutine); // for kill -15 (before "kill -9")
+ if (memo_sig_term == SIG_ERR)
+ throw "SetConsoleCtrlHandler fails (SIGTERM)";
+}
+
+CCtrlHandlerSetter::~CCtrlHandlerSetter()
+{
+ signal(SIGINT, memo_sig_int); // CTRL-C
+ signal(SIGTERM, memo_sig_term); // kill {pid}
+}
+
+#endif // _WIN32
+
+/*
+void CheckCtrlBreak()
+{
+ if (TestBreakSignal())
+ throw CCtrlBreakException();
+}
+*/
+
+}
+
+#endif
diff --git a/CPP/7zip/UI/Console/ConsoleClose.h b/CPP/7zip/UI/Console/ConsoleClose.h
index 0a0bbf0..25c5d0c 100644
--- a/CPP/7zip/UI/Console/ConsoleClose.h
+++ b/CPP/7zip/UI/Console/ConsoleClose.h
@@ -1,33 +1,39 @@
-// ConsoleClose.h
-
-#ifndef __CONSOLE_CLOSE_H
-#define __CONSOLE_CLOSE_H
-
-namespace NConsoleClose {
-
-extern unsigned g_BreakCounter;
-
-inline bool TestBreakSignal()
-{
- #ifdef UNDER_CE
- return false;
- #else
- return (g_BreakCounter != 0);
- #endif
-}
-
-class CCtrlHandlerSetter
-{
-public:
- CCtrlHandlerSetter();
- virtual ~CCtrlHandlerSetter();
-};
-
-class CCtrlBreakException
-{};
-
-// void CheckCtrlBreak();
-
-}
-
-#endif
+// ConsoleClose.h
+
+#ifndef ZIP7_INC_CONSOLE_CLOSE_H
+#define ZIP7_INC_CONSOLE_CLOSE_H
+
+namespace NConsoleClose {
+
+class CCtrlBreakException {};
+
+#ifdef UNDER_CE
+
+inline bool TestBreakSignal() { return false; }
+struct CCtrlHandlerSetter {};
+
+#else
+
+extern unsigned g_BreakCounter;
+
+inline bool TestBreakSignal()
+{
+ return (g_BreakCounter != 0);
+}
+
+class CCtrlHandlerSetter Z7_final
+{
+ #ifndef _WIN32
+ void (*memo_sig_int)(int);
+ void (*memo_sig_term)(int);
+ #endif
+public:
+ CCtrlHandlerSetter();
+ ~CCtrlHandlerSetter();
+};
+
+#endif
+
+}
+
+#endif
diff --git a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp b/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
index bdf9549..dd7a214 100644
--- a/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
+++ b/CPP/7zip/UI/Console/ExtractCallbackConsole.cpp
@@ -1,825 +1,849 @@
-// ExtractCallbackConsole.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/IntToString.h"
-#include "../../../Common/Wildcard.h"
-
-#include "../../../Windows/FileDir.h"
-#include "../../../Windows/FileFind.h"
-#include "../../../Windows/TimeUtils.h"
-#include "../../../Windows/ErrorMsg.h"
-#include "../../../Windows/PropVariantConv.h"
-
-#ifndef _7ZIP_ST
-#include "../../../Windows/Synchronization.h"
-#endif
-
-#include "../../Common/FilePathAutoRename.h"
-
-#include "../Common/ExtractingFilePath.h"
-
-#include "ConsoleClose.h"
-#include "ExtractCallbackConsole.h"
-#include "UserInputUtils.h"
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NDir;
-
-static HRESULT CheckBreak2()
-{
- return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
-}
-
-static const char * const kError = "ERROR: ";
-
-
-void CExtractScanConsole::StartScanning()
-{
- if (NeedPercents())
- _percent.Command = "Scan";
-}
-
-HRESULT CExtractScanConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */)
-{
- if (NeedPercents())
- {
- _percent.Files = st.NumDirs + st.NumFiles;
- _percent.Completed = st.GetTotalBytes();
- _percent.FileName = fs2us(path);
- _percent.Print();
- }
-
- return CheckBreak2();
-}
-
-HRESULT CExtractScanConsole::ScanError(const FString &path, DWORD systemError)
-{
- ClosePercentsAndFlush();
-
- if (_se)
- {
- *_se << endl << kError << NError::MyFormatMessage(systemError) << endl;
- _se->NormalizePrint_UString(fs2us(path));
- *_se << endl << endl;
- _se->Flush();
- }
- return HRESULT_FROM_WIN32(systemError);
-}
-
-
-void Print_UInt64_and_String(AString &s, UInt64 val, const char *name)
-{
- char temp[32];
- ConvertUInt64ToString(val, temp);
- s += temp;
- s.Add_Space();
- s += name;
-}
-
-void PrintSize_bytes_Smart(AString &s, UInt64 val)
-{
- Print_UInt64_and_String(s, val, "bytes");
-
- if (val == 0)
- return;
-
- unsigned numBits = 10;
- char c = 'K';
- char temp[4] = { 'K', 'i', 'B', 0 };
- if (val >= ((UInt64)10 << 30)) { numBits = 30; c = 'G'; }
- else if (val >= ((UInt64)10 << 20)) { numBits = 20; c = 'M'; }
- temp[0] = c;
- s += " (";
- Print_UInt64_and_String(s, ((val + ((UInt64)1 << numBits) - 1) >> numBits), temp);
- s += ')';
-}
-
-void PrintSize_bytes_Smart_comma(AString &s, UInt64 val)
-{
- if (val == (UInt64)(Int64)-1)
- return;
- s += ", ";
- PrintSize_bytes_Smart(s, val);
-}
-
-
-
-void Print_DirItemsStat(AString &s, const CDirItemsStat &st)
-{
- if (st.NumDirs != 0)
- {
- Print_UInt64_and_String(s, st.NumDirs, st.NumDirs == 1 ? "folder" : "folders");
- s += ", ";
- }
- Print_UInt64_and_String(s, st.NumFiles, st.NumFiles == 1 ? "file" : "files");
- PrintSize_bytes_Smart_comma(s, st.FilesSize);
- if (st.NumAltStreams != 0)
- {
- s.Add_LF();
- Print_UInt64_and_String(s, st.NumAltStreams, "alternate streams");
- PrintSize_bytes_Smart_comma(s, st.AltStreamsSize);
- }
-}
-
-
-void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st)
-{
- Print_DirItemsStat(s, (CDirItemsStat &)st);
- bool needLF = true;
- if (st.Anti_NumDirs != 0)
- {
- if (needLF)
- s.Add_LF();
- needLF = false;
- Print_UInt64_and_String(s, st.Anti_NumDirs, st.Anti_NumDirs == 1 ? "anti-folder" : "anti-folders");
- }
- if (st.Anti_NumFiles != 0)
- {
- if (needLF)
- s.Add_LF();
- else
- s += ", ";
- needLF = false;
- Print_UInt64_and_String(s, st.Anti_NumFiles, st.Anti_NumFiles == 1 ? "anti-file" : "anti-files");
- }
- if (st.Anti_NumAltStreams != 0)
- {
- if (needLF)
- s.Add_LF();
- else
- s += ", ";
- needLF = false;
- Print_UInt64_and_String(s, st.Anti_NumAltStreams, "anti-alternate-streams");
- }
-}
-
-
-void CExtractScanConsole::PrintStat(const CDirItemsStat &st)
-{
- if (_so)
- {
- AString s;
- Print_DirItemsStat(s, st);
- *_so << s << endl;
- }
-}
-
-
-
-
-
-
-
-#ifndef _7ZIP_ST
-static NSynchronization::CCriticalSection g_CriticalSection;
-#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
-#else
-#define MT_LOCK
-#endif
-
-
-static const char * const kTestString = "T";
-static const char * const kExtractString = "-";
-static const char * const kSkipString = ".";
-
-// static const char * const kCantAutoRename = "can not create file with auto name\n";
-// static const char * const kCantRenameFile = "can not rename existing file\n";
-// static const char * const kCantDeleteOutputFile = "can not delete output file ";
-
-static const char * const kMemoryExceptionMessage = "Can't allocate required memory!";
-
-static const char * const kExtracting = "Extracting archive: ";
-static const char * const kTesting = "Testing archive: ";
-
-static const char * const kEverythingIsOk = "Everything is Ok";
-static const char * const kNoFiles = "No files to process";
-
-static const char * const kUnsupportedMethod = "Unsupported Method";
-static const char * const kCrcFailed = "CRC Failed";
-static const char * const kCrcFailedEncrypted = "CRC Failed in encrypted file. Wrong password?";
-static const char * const kDataError = "Data Error";
-static const char * const kDataErrorEncrypted = "Data Error in encrypted file. Wrong password?";
-static const char * const kUnavailableData = "Unavailable data";
-static const char * const kUnexpectedEnd = "Unexpected end of data";
-static const char * const kDataAfterEnd = "There are some data after the end of the payload data";
-static const char * const kIsNotArc = "Is not archive";
-static const char * const kHeadersError = "Headers Error";
-static const char * const kWrongPassword = "Wrong password";
-
-static const char * const k_ErrorFlagsMessages[] =
-{
- "Is not archive"
- , "Headers Error"
- , "Headers Error in encrypted archive. Wrong password?"
- , "Unavailable start of archive"
- , "Unconfirmed start of archive"
- , "Unexpected end of archive"
- , "There are data after the end of archive"
- , "Unsupported method"
- , "Unsupported feature"
- , "Data Error"
- , "CRC Error"
-};
-
-STDMETHODIMP CExtractCallbackConsole::SetTotal(UInt64 size)
-{
- MT_LOCK
-
- if (NeedPercents())
- {
- _percent.Total = size;
- _percent.Print();
- }
- return CheckBreak2();
-}
-
-STDMETHODIMP CExtractCallbackConsole::SetCompleted(const UInt64 *completeValue)
-{
- MT_LOCK
-
- if (NeedPercents())
- {
- if (completeValue)
- _percent.Completed = *completeValue;
- _percent.Print();
- }
- return CheckBreak2();
-}
-
-static const char * const kTab = " ";
-
-static void PrintFileInfo(CStdOutStream *_so, const wchar_t *path, const FILETIME *ft, const UInt64 *size)
-{
- *_so << kTab << "Path: ";
- _so->NormalizePrint_wstr(path);
- *_so << endl;
- if (size && *size != (UInt64)(Int64)-1)
- {
- AString s;
- PrintSize_bytes_Smart(s, *size);
- *_so << kTab << "Size: " << s << endl;
- }
- if (ft)
- {
- char temp[64];
- if (ConvertUtcFileTimeToString(*ft, temp, kTimestampPrintLevel_SEC))
- *_so << kTab << "Modified: " << temp << endl;
- }
-}
-
-STDMETHODIMP CExtractCallbackConsole::AskOverwrite(
- const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
- const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
- Int32 *answer)
-{
- MT_LOCK
-
- RINOK(CheckBreak2());
-
- ClosePercentsAndFlush();
-
- if (_so)
- {
- *_so << endl << "Would you like to replace the existing file:\n";
- PrintFileInfo(_so, existName, existTime, existSize);
- *_so << "with the file from archive:\n";
- PrintFileInfo(_so, newName, newTime, newSize);
- }
-
- NUserAnswerMode::EEnum overwriteAnswer = ScanUserYesNoAllQuit(_so);
-
- switch (overwriteAnswer)
- {
- case NUserAnswerMode::kQuit: return E_ABORT;
- case NUserAnswerMode::kNo: *answer = NOverwriteAnswer::kNo; break;
- case NUserAnswerMode::kNoAll: *answer = NOverwriteAnswer::kNoToAll; break;
- case NUserAnswerMode::kYesAll: *answer = NOverwriteAnswer::kYesToAll; break;
- case NUserAnswerMode::kYes: *answer = NOverwriteAnswer::kYes; break;
- case NUserAnswerMode::kAutoRenameAll: *answer = NOverwriteAnswer::kAutoRename; break;
- case NUserAnswerMode::kEof: return E_ABORT;
- case NUserAnswerMode::kError: return E_FAIL;
- default: return E_FAIL;
- }
-
- if (_so)
- {
- *_so << endl;
- if (NeedFlush)
- _so->Flush();
- }
-
- return CheckBreak2();
-}
-
-STDMETHODIMP CExtractCallbackConsole::PrepareOperation(const wchar_t *name, Int32 /* isFolder */, Int32 askExtractMode, const UInt64 *position)
-{
- MT_LOCK
-
- _currentName = name;
-
- const char *s;
- unsigned requiredLevel = 1;
-
- switch (askExtractMode)
- {
- case NArchive::NExtract::NAskMode::kExtract: s = kExtractString; break;
- case NArchive::NExtract::NAskMode::kTest: s = kTestString; break;
- case NArchive::NExtract::NAskMode::kSkip: s = kSkipString; requiredLevel = 2; break;
- default: s = "???"; requiredLevel = 2;
- };
-
- bool show2 = (LogLevel >= requiredLevel && _so);
-
- if (show2)
- {
- ClosePercents_for_so();
-
- _tempA = s;
- if (name)
- _tempA.Add_Space();
- *_so << _tempA;
-
- _tempU.Empty();
- if (name)
- {
- _tempU = name;
- _so->Normalize_UString(_tempU);
- }
- _so->PrintUString(_tempU, _tempA);
- if (position)
- *_so << " <" << *position << ">";
- *_so << endl;
-
- if (NeedFlush)
- _so->Flush();
- }
-
- if (NeedPercents())
- {
- if (PercentsNameLevel >= 1)
- {
- _percent.FileName.Empty();
- _percent.Command.Empty();
- if (PercentsNameLevel > 1 || !show2)
- {
- _percent.Command = s;
- if (name)
- _percent.FileName = name;
- }
- }
- _percent.Print();
- }
-
- return CheckBreak2();
-}
-
-STDMETHODIMP CExtractCallbackConsole::MessageError(const wchar_t *message)
-{
- MT_LOCK
-
- RINOK(CheckBreak2());
-
- NumFileErrors_in_Current++;
- NumFileErrors++;
-
- ClosePercentsAndFlush();
- if (_se)
- {
- *_se << kError << message << endl;
- _se->Flush();
- }
-
- return CheckBreak2();
-}
-
-void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest)
-{
- dest.Empty();
- const char *s = NULL;
-
- switch (opRes)
- {
- case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
- s = kUnsupportedMethod;
- break;
- case NArchive::NExtract::NOperationResult::kCRCError:
- s = (encrypted ? kCrcFailedEncrypted : kCrcFailed);
- break;
- case NArchive::NExtract::NOperationResult::kDataError:
- s = (encrypted ? kDataErrorEncrypted : kDataError);
- break;
- case NArchive::NExtract::NOperationResult::kUnavailable:
- s = kUnavailableData;
- break;
- case NArchive::NExtract::NOperationResult::kUnexpectedEnd:
- s = kUnexpectedEnd;
- break;
- case NArchive::NExtract::NOperationResult::kDataAfterEnd:
- s = kDataAfterEnd;
- break;
- case NArchive::NExtract::NOperationResult::kIsNotArc:
- s = kIsNotArc;
- break;
- case NArchive::NExtract::NOperationResult::kHeadersError:
- s = kHeadersError;
- break;
- case NArchive::NExtract::NOperationResult::kWrongPassword:
- s = kWrongPassword;
- break;
- }
-
- dest += kError;
- if (s)
- dest += s;
- else
- {
- dest += "Error #";
- dest.Add_UInt32(opRes);
- }
-}
-
-STDMETHODIMP CExtractCallbackConsole::SetOperationResult(Int32 opRes, Int32 encrypted)
-{
- MT_LOCK
-
- if (opRes == NArchive::NExtract::NOperationResult::kOK)
- {
- if (NeedPercents())
- {
- _percent.Command.Empty();
- _percent.FileName.Empty();
- _percent.Files++;
- }
- }
- else
- {
- NumFileErrors_in_Current++;
- NumFileErrors++;
-
- if (_se)
- {
- ClosePercentsAndFlush();
-
- AString s;
- SetExtractErrorMessage(opRes, encrypted, s);
-
- *_se << s;
- if (!_currentName.IsEmpty())
- {
- *_se << " : ";
- _se->NormalizePrint_UString(_currentName);
- }
- *_se << endl;
- _se->Flush();
- }
- }
-
- return CheckBreak2();
-}
-
-STDMETHODIMP CExtractCallbackConsole::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)
-{
- if (opRes != NArchive::NExtract::NOperationResult::kOK)
- {
- _currentName = name;
- return SetOperationResult(opRes, encrypted);
- }
-
- return CheckBreak2();
-}
-
-
-
-#ifndef _NO_CRYPTO
-
-HRESULT CExtractCallbackConsole::SetPassword(const UString &password)
-{
- PasswordIsDefined = true;
- Password = password;
- return S_OK;
-}
-
-STDMETHODIMP CExtractCallbackConsole::CryptoGetTextPassword(BSTR *password)
-{
- COM_TRY_BEGIN
- MT_LOCK
- return Open_CryptoGetTextPassword(password);
- COM_TRY_END
-}
-
-#endif
-
-HRESULT CExtractCallbackConsole::BeforeOpen(const wchar_t *name, bool testMode)
-{
- RINOK(CheckBreak2());
-
- NumTryArcs++;
- ThereIsError_in_Current = false;
- ThereIsWarning_in_Current = false;
- NumFileErrors_in_Current = 0;
-
- ClosePercents_for_so();
- if (_so)
- {
- *_so << endl << (testMode ? kTesting : kExtracting);
- _so->NormalizePrint_wstr(name);
- *_so << endl;
- }
-
- if (NeedPercents())
- _percent.Command = "Open";
- return S_OK;
-}
-
-HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
-HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
-
-static AString GetOpenArcErrorMessage(UInt32 errorFlags)
-{
- AString s;
-
- for (unsigned i = 0; i < ARRAY_SIZE(k_ErrorFlagsMessages); i++)
- {
- UInt32 f = (1 << i);
- if ((errorFlags & f) == 0)
- continue;
- const char *m = k_ErrorFlagsMessages[i];
- if (!s.IsEmpty())
- s.Add_LF();
- s += m;
- errorFlags &= ~f;
- }
-
- if (errorFlags != 0)
- {
- char sz[16];
- sz[0] = '0';
- sz[1] = 'x';
- ConvertUInt32ToHex(errorFlags, sz + 2);
- if (!s.IsEmpty())
- s.Add_LF();
- s += sz;
- }
-
- return s;
-}
-
-void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags)
-{
- if (errorFlags == 0)
- return;
- so << s << endl << GetOpenArcErrorMessage(errorFlags) << endl;
-}
-
-void Add_Messsage_Pre_ArcType(UString &s, const char *pre, const wchar_t *arcType)
-{
- s.Add_LF();
- s += pre;
- s += " as [";
- s += arcType;
- s += "] archive";
-}
-
-void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc)
-{
- const CArcErrorInfo &er = arc.ErrorInfo;
-
- *_so << "WARNING:\n";
- _so->NormalizePrint_UString(arc.Path);
- UString s;
- if (arc.FormatIndex == er.ErrorFormatIndex)
- {
- s.Add_LF();
- s += "The archive is open with offset";
- }
- else
- {
- Add_Messsage_Pre_ArcType(s, "Can not open the file", codecs->GetFormatNamePtr(er.ErrorFormatIndex));
- Add_Messsage_Pre_ArcType(s, "The file is open", codecs->GetFormatNamePtr(arc.FormatIndex));
- }
-
- *_so << s << endl << endl;
-}
-
-
-HRESULT CExtractCallbackConsole::OpenResult(
- const CCodecs *codecs, const CArchiveLink &arcLink,
- const wchar_t *name, HRESULT result)
-{
- ClosePercents();
-
- if (NeedPercents())
- {
- _percent.Files = 0;
- _percent.Command.Empty();
- _percent.FileName.Empty();
- }
-
-
- ClosePercentsAndFlush();
-
- FOR_VECTOR (level, arcLink.Arcs)
- {
- const CArc &arc = arcLink.Arcs[level];
- const CArcErrorInfo &er = arc.ErrorInfo;
-
- UInt32 errorFlags = er.GetErrorFlags();
-
- if (errorFlags != 0 || !er.ErrorMessage.IsEmpty())
- {
- if (_se)
- {
- *_se << endl;
- if (level != 0)
- {
- _se->NormalizePrint_UString(arc.Path);
- *_se << endl;
- }
- }
-
- if (errorFlags != 0)
- {
- if (_se)
- PrintErrorFlags(*_se, "ERRORS:", errorFlags);
- NumOpenArcErrors++;
- ThereIsError_in_Current = true;
- }
-
- if (!er.ErrorMessage.IsEmpty())
- {
- if (_se)
- *_se << "ERRORS:" << endl << er.ErrorMessage << endl;
- NumOpenArcErrors++;
- ThereIsError_in_Current = true;
- }
-
- if (_se)
- {
- *_se << endl;
- _se->Flush();
- }
- }
-
- UInt32 warningFlags = er.GetWarningFlags();
-
- if (warningFlags != 0 || !er.WarningMessage.IsEmpty())
- {
- if (_so)
- {
- *_so << endl;
- if (level != 0)
- {
- _so->NormalizePrint_UString(arc.Path);
- *_so << endl;
- }
- }
-
- if (warningFlags != 0)
- {
- if (_so)
- PrintErrorFlags(*_so, "WARNINGS:", warningFlags);
- NumOpenArcWarnings++;
- ThereIsWarning_in_Current = true;
- }
-
- if (!er.WarningMessage.IsEmpty())
- {
- if (_so)
- *_so << "WARNINGS:" << endl << er.WarningMessage << endl;
- NumOpenArcWarnings++;
- ThereIsWarning_in_Current = true;
- }
-
- if (_so)
- {
- *_so << endl;
- if (NeedFlush)
- _so->Flush();
- }
- }
-
-
- if (er.ErrorFormatIndex >= 0)
- {
- if (_so)
- {
- Print_ErrorFormatIndex_Warning(_so, codecs, arc);
- if (NeedFlush)
- _so->Flush();
- }
- ThereIsWarning_in_Current = true;
- }
- }
-
- if (result == S_OK)
- {
- if (_so)
- {
- RINOK(Print_OpenArchive_Props(*_so, codecs, arcLink));
- *_so << endl;
- }
- }
- else
- {
- NumCantOpenArcs++;
- if (_so)
- _so->Flush();
- if (_se)
- {
- *_se << kError;
- _se->NormalizePrint_wstr(name);
- *_se << endl;
- HRESULT res = Print_OpenArchive_Error(*_se, codecs, arcLink);
- RINOK(res);
- if (result == S_FALSE)
- {
- }
- else
- {
- if (result == E_OUTOFMEMORY)
- *_se << "Can't allocate required memory";
- else
- *_se << NError::MyFormatMessage(result);
- *_se << endl;
- }
- _se->Flush();
- }
- }
-
-
- return CheckBreak2();
-}
-
-HRESULT CExtractCallbackConsole::ThereAreNoFiles()
-{
- ClosePercents_for_so();
-
- if (_so)
- {
- *_so << endl << kNoFiles << endl;
- if (NeedFlush)
- _so->Flush();
- }
- return CheckBreak2();
-}
-
-HRESULT CExtractCallbackConsole::ExtractResult(HRESULT result)
-{
- MT_LOCK
-
- if (NeedPercents())
- {
- _percent.ClosePrint(true);
- _percent.Command.Empty();
- _percent.FileName.Empty();
- }
-
- if (_so)
- _so->Flush();
-
- if (result == S_OK)
- {
- if (NumFileErrors_in_Current == 0 && !ThereIsError_in_Current)
- {
- if (ThereIsWarning_in_Current)
- NumArcsWithWarnings++;
- else
- NumOkArcs++;
- if (_so)
- *_so << kEverythingIsOk << endl;
- }
- else
- {
- NumArcsWithError++;
- if (_so)
- {
- *_so << endl;
- if (NumFileErrors_in_Current != 0)
- *_so << "Sub items Errors: " << NumFileErrors_in_Current << endl;
- }
- }
- if (_so && NeedFlush)
- _so->Flush();
- }
- else
- {
- NumArcsWithError++;
- if (result == E_ABORT || result == ERROR_DISK_FULL)
- return result;
-
- if (_se)
- {
- *_se << endl << kError;
- if (result == E_OUTOFMEMORY)
- *_se << kMemoryExceptionMessage;
- else
- *_se << NError::MyFormatMessage(result);
- *_se << endl;
- _se->Flush();
- }
- }
-
- return CheckBreak2();
-}
+// ExtractCallbackConsole.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/TimeUtils.h"
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/PropVariantConv.h"
+
+#ifndef Z7_ST
+#include "../../../Windows/Synchronization.h"
+#endif
+
+#include "../../Common/FilePathAutoRename.h"
+
+#include "../Common/ExtractingFilePath.h"
+
+#include "ConsoleClose.h"
+#include "ExtractCallbackConsole.h"
+#include "UserInputUtils.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+static HRESULT CheckBreak2()
+{
+ return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
+}
+
+static const char * const kError = "ERROR: ";
+
+
+void CExtractScanConsole::StartScanning()
+{
+ if (NeedPercents())
+ _percent.Command = "Scan";
+}
+
+HRESULT CExtractScanConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */)
+{
+ if (NeedPercents())
+ {
+ _percent.Files = st.NumDirs + st.NumFiles;
+ _percent.Completed = st.GetTotalBytes();
+ _percent.FileName = fs2us(path);
+ _percent.Print();
+ }
+
+ return CheckBreak2();
+}
+
+HRESULT CExtractScanConsole::ScanError(const FString &path, DWORD systemError)
+{
+ // 22.00:
+ // ScanErrors.AddError(path, systemError);
+
+ ClosePercentsAndFlush();
+
+ if (_se)
+ {
+ *_se << endl << kError << NError::MyFormatMessage(systemError) << endl;
+ _se->NormalizePrint_UString(fs2us(path));
+ *_se << endl << endl;
+ _se->Flush();
+ }
+ return HRESULT_FROM_WIN32(systemError);
+
+ // 22.00: commented
+ // CommonError(path, systemError, true);
+ // return S_OK;
+}
+
+
+void Print_UInt64_and_String(AString &s, UInt64 val, const char *name);
+void Print_UInt64_and_String(AString &s, UInt64 val, const char *name)
+{
+ char temp[32];
+ ConvertUInt64ToString(val, temp);
+ s += temp;
+ s.Add_Space();
+ s += name;
+}
+
+void PrintSize_bytes_Smart(AString &s, UInt64 val);
+void PrintSize_bytes_Smart(AString &s, UInt64 val)
+{
+ Print_UInt64_and_String(s, val, "bytes");
+
+ if (val == 0)
+ return;
+
+ unsigned numBits = 10;
+ char c = 'K';
+ char temp[4] = { 'K', 'i', 'B', 0 };
+ if (val >= ((UInt64)10 << 30)) { numBits = 30; c = 'G'; }
+ else if (val >= ((UInt64)10 << 20)) { numBits = 20; c = 'M'; }
+ temp[0] = c;
+ s += " (";
+ Print_UInt64_and_String(s, ((val + ((UInt64)1 << numBits) - 1) >> numBits), temp);
+ s += ')';
+}
+
+static void PrintSize_bytes_Smart_comma(AString &s, UInt64 val)
+{
+ if (val == (UInt64)(Int64)-1)
+ return;
+ s += ", ";
+ PrintSize_bytes_Smart(s, val);
+}
+
+
+
+void Print_DirItemsStat(AString &s, const CDirItemsStat &st);
+void Print_DirItemsStat(AString &s, const CDirItemsStat &st)
+{
+ if (st.NumDirs != 0)
+ {
+ Print_UInt64_and_String(s, st.NumDirs, st.NumDirs == 1 ? "folder" : "folders");
+ s += ", ";
+ }
+ Print_UInt64_and_String(s, st.NumFiles, st.NumFiles == 1 ? "file" : "files");
+ PrintSize_bytes_Smart_comma(s, st.FilesSize);
+ if (st.NumAltStreams != 0)
+ {
+ s.Add_LF();
+ Print_UInt64_and_String(s, st.NumAltStreams, "alternate streams");
+ PrintSize_bytes_Smart_comma(s, st.AltStreamsSize);
+ }
+}
+
+
+void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st);
+void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st)
+{
+ Print_DirItemsStat(s, (CDirItemsStat &)st);
+ bool needLF = true;
+ if (st.Anti_NumDirs != 0)
+ {
+ if (needLF)
+ s.Add_LF();
+ needLF = false;
+ Print_UInt64_and_String(s, st.Anti_NumDirs, st.Anti_NumDirs == 1 ? "anti-folder" : "anti-folders");
+ }
+ if (st.Anti_NumFiles != 0)
+ {
+ if (needLF)
+ s.Add_LF();
+ else
+ s += ", ";
+ needLF = false;
+ Print_UInt64_and_String(s, st.Anti_NumFiles, st.Anti_NumFiles == 1 ? "anti-file" : "anti-files");
+ }
+ if (st.Anti_NumAltStreams != 0)
+ {
+ if (needLF)
+ s.Add_LF();
+ else
+ s += ", ";
+ needLF = false;
+ Print_UInt64_and_String(s, st.Anti_NumAltStreams, "anti-alternate-streams");
+ }
+}
+
+
+void CExtractScanConsole::PrintStat(const CDirItemsStat &st)
+{
+ if (_so)
+ {
+ AString s;
+ Print_DirItemsStat(s, st);
+ *_so << s << endl;
+ }
+}
+
+
+
+
+
+
+
+#ifndef Z7_ST
+static NSynchronization::CCriticalSection g_CriticalSection;
+#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
+#else
+#define MT_LOCK
+#endif
+
+
+static const char * const kTestString = "T";
+static const char * const kExtractString = "-";
+static const char * const kSkipString = ".";
+static const char * const kReadString = "H";
+
+// static const char * const kCantAutoRename = "cannot create file with auto name\n";
+// static const char * const kCantRenameFile = "cannot rename existing file\n";
+// static const char * const kCantDeleteOutputFile = "cannot delete output file ";
+
+static const char * const kMemoryExceptionMessage = "Can't allocate required memory!";
+
+static const char * const kExtracting = "Extracting archive: ";
+static const char * const kTesting = "Testing archive: ";
+
+static const char * const kEverythingIsOk = "Everything is Ok";
+static const char * const kNoFiles = "No files to process";
+
+static const char * const kUnsupportedMethod = "Unsupported Method";
+static const char * const kCrcFailed = "CRC Failed";
+static const char * const kCrcFailedEncrypted = "CRC Failed in encrypted file. Wrong password?";
+static const char * const kDataError = "Data Error";
+static const char * const kDataErrorEncrypted = "Data Error in encrypted file. Wrong password?";
+static const char * const kUnavailableData = "Unavailable data";
+static const char * const kUnexpectedEnd = "Unexpected end of data";
+static const char * const kDataAfterEnd = "There are some data after the end of the payload data";
+static const char * const kIsNotArc = "Is not archive";
+static const char * const kHeadersError = "Headers Error";
+static const char * const kWrongPassword = "Wrong password";
+
+static const char * const k_ErrorFlagsMessages[] =
+{
+ "Is not archive"
+ , "Headers Error"
+ , "Headers Error in encrypted archive. Wrong password?"
+ , "Unavailable start of archive"
+ , "Unconfirmed start of archive"
+ , "Unexpected end of archive"
+ , "There are data after the end of archive"
+ , "Unsupported method"
+ , "Unsupported feature"
+ , "Data Error"
+ , "CRC Error"
+};
+
+Z7_COM7F_IMF(CExtractCallbackConsole::SetTotal(UInt64 size))
+{
+ MT_LOCK
+
+ if (NeedPercents())
+ {
+ _percent.Total = size;
+ _percent.Print();
+ }
+ return CheckBreak2();
+}
+
+Z7_COM7F_IMF(CExtractCallbackConsole::SetCompleted(const UInt64 *completeValue))
+{
+ MT_LOCK
+
+ if (NeedPercents())
+ {
+ if (completeValue)
+ _percent.Completed = *completeValue;
+ _percent.Print();
+ }
+ return CheckBreak2();
+}
+
+static const char * const kTab = " ";
+
+static void PrintFileInfo(CStdOutStream *_so, const wchar_t *path, const FILETIME *ft, const UInt64 *size)
+{
+ *_so << kTab << "Path: ";
+ _so->NormalizePrint_wstr(path);
+ *_so << endl;
+ if (size && *size != (UInt64)(Int64)-1)
+ {
+ AString s;
+ PrintSize_bytes_Smart(s, *size);
+ *_so << kTab << "Size: " << s << endl;
+ }
+ if (ft)
+ {
+ char temp[64];
+ if (ConvertUtcFileTimeToString(*ft, temp, kTimestampPrintLevel_SEC))
+ *_so << kTab << "Modified: " << temp << endl;
+ }
+}
+
+Z7_COM7F_IMF(CExtractCallbackConsole::AskOverwrite(
+ const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
+ const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
+ Int32 *answer))
+{
+ MT_LOCK
+
+ RINOK(CheckBreak2())
+
+ ClosePercentsAndFlush();
+
+ if (_so)
+ {
+ *_so << endl << "Would you like to replace the existing file:\n";
+ PrintFileInfo(_so, existName, existTime, existSize);
+ *_so << "with the file from archive:\n";
+ PrintFileInfo(_so, newName, newTime, newSize);
+ }
+
+ NUserAnswerMode::EEnum overwriteAnswer = ScanUserYesNoAllQuit(_so);
+
+ switch ((int)overwriteAnswer)
+ {
+ case NUserAnswerMode::kQuit: return E_ABORT;
+ case NUserAnswerMode::kNo: *answer = NOverwriteAnswer::kNo; break;
+ case NUserAnswerMode::kNoAll: *answer = NOverwriteAnswer::kNoToAll; break;
+ case NUserAnswerMode::kYesAll: *answer = NOverwriteAnswer::kYesToAll; break;
+ case NUserAnswerMode::kYes: *answer = NOverwriteAnswer::kYes; break;
+ case NUserAnswerMode::kAutoRenameAll: *answer = NOverwriteAnswer::kAutoRename; break;
+ case NUserAnswerMode::kEof: return E_ABORT;
+ case NUserAnswerMode::kError: return E_FAIL;
+ default: return E_FAIL;
+ }
+
+ if (_so)
+ {
+ *_so << endl;
+ if (NeedFlush)
+ _so->Flush();
+ }
+
+ return CheckBreak2();
+}
+
+Z7_COM7F_IMF(CExtractCallbackConsole::PrepareOperation(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 *position))
+{
+ MT_LOCK
+
+ _currentName = name;
+
+ const char *s;
+ unsigned requiredLevel = 1;
+
+ switch (askExtractMode)
+ {
+ case NArchive::NExtract::NAskMode::kExtract: s = kExtractString; break;
+ case NArchive::NExtract::NAskMode::kTest: s = kTestString; break;
+ case NArchive::NExtract::NAskMode::kSkip: s = kSkipString; requiredLevel = 2; break;
+ case NArchive::NExtract::NAskMode::kReadExternal: s = kReadString; requiredLevel = 0; break;
+ default: s = "???"; requiredLevel = 2;
+ }
+
+ bool show2 = (LogLevel >= requiredLevel && _so);
+
+ if (show2)
+ {
+ ClosePercents_for_so();
+
+ _tempA = s;
+ if (name)
+ _tempA.Add_Space();
+ *_so << _tempA;
+
+ _tempU.Empty();
+ if (name)
+ {
+ _tempU = name;
+ _so->Normalize_UString(_tempU);
+ // 21.04
+ if (isFolder)
+ {
+ if (!_tempU.IsEmpty() && _tempU.Back() != WCHAR_PATH_SEPARATOR)
+ _tempU.Add_PathSepar();
+ }
+ }
+ _so->PrintUString(_tempU, _tempA);
+ if (position)
+ *_so << " <" << *position << ">";
+ *_so << endl;
+
+ if (NeedFlush)
+ _so->Flush();
+ }
+
+ if (NeedPercents())
+ {
+ if (PercentsNameLevel >= 1)
+ {
+ _percent.FileName.Empty();
+ _percent.Command.Empty();
+ if (PercentsNameLevel > 1 || !show2)
+ {
+ _percent.Command = s;
+ if (name)
+ _percent.FileName = name;
+ }
+ }
+ _percent.Print();
+ }
+
+ return CheckBreak2();
+}
+
+Z7_COM7F_IMF(CExtractCallbackConsole::MessageError(const wchar_t *message))
+{
+ MT_LOCK
+
+ RINOK(CheckBreak2())
+
+ NumFileErrors_in_Current++;
+ NumFileErrors++;
+
+ ClosePercentsAndFlush();
+ if (_se)
+ {
+ *_se << kError << message << endl;
+ _se->Flush();
+ }
+
+ return CheckBreak2();
+}
+
+void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest);
+void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest)
+{
+ dest.Empty();
+ const char *s = NULL;
+
+ switch (opRes)
+ {
+ case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
+ s = kUnsupportedMethod;
+ break;
+ case NArchive::NExtract::NOperationResult::kCRCError:
+ s = (encrypted ? kCrcFailedEncrypted : kCrcFailed);
+ break;
+ case NArchive::NExtract::NOperationResult::kDataError:
+ s = (encrypted ? kDataErrorEncrypted : kDataError);
+ break;
+ case NArchive::NExtract::NOperationResult::kUnavailable:
+ s = kUnavailableData;
+ break;
+ case NArchive::NExtract::NOperationResult::kUnexpectedEnd:
+ s = kUnexpectedEnd;
+ break;
+ case NArchive::NExtract::NOperationResult::kDataAfterEnd:
+ s = kDataAfterEnd;
+ break;
+ case NArchive::NExtract::NOperationResult::kIsNotArc:
+ s = kIsNotArc;
+ break;
+ case NArchive::NExtract::NOperationResult::kHeadersError:
+ s = kHeadersError;
+ break;
+ case NArchive::NExtract::NOperationResult::kWrongPassword:
+ s = kWrongPassword;
+ break;
+ }
+
+ dest += kError;
+ if (s)
+ dest += s;
+ else
+ {
+ dest += "Error #";
+ dest.Add_UInt32((UInt32)opRes);
+ }
+}
+
+Z7_COM7F_IMF(CExtractCallbackConsole::SetOperationResult(Int32 opRes, Int32 encrypted))
+{
+ MT_LOCK
+
+ if (opRes == NArchive::NExtract::NOperationResult::kOK)
+ {
+ if (NeedPercents())
+ {
+ _percent.Command.Empty();
+ _percent.FileName.Empty();
+ _percent.Files++;
+ }
+ }
+ else
+ {
+ NumFileErrors_in_Current++;
+ NumFileErrors++;
+
+ if (_se)
+ {
+ ClosePercentsAndFlush();
+
+ AString s;
+ SetExtractErrorMessage(opRes, encrypted, s);
+
+ *_se << s;
+ if (!_currentName.IsEmpty())
+ {
+ *_se << " : ";
+ _se->NormalizePrint_UString(_currentName);
+ }
+ *_se << endl;
+ _se->Flush();
+ }
+ }
+
+ return CheckBreak2();
+}
+
+Z7_COM7F_IMF(CExtractCallbackConsole::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name))
+{
+ if (opRes != NArchive::NExtract::NOperationResult::kOK)
+ {
+ _currentName = name;
+ return SetOperationResult(opRes, encrypted);
+ }
+
+ return CheckBreak2();
+}
+
+
+
+#ifndef Z7_NO_CRYPTO
+
+HRESULT CExtractCallbackConsole::SetPassword(const UString &password)
+{
+ PasswordIsDefined = true;
+ Password = password;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CExtractCallbackConsole::CryptoGetTextPassword(BSTR *password))
+{
+ COM_TRY_BEGIN
+ MT_LOCK
+ return Open_CryptoGetTextPassword(password);
+ COM_TRY_END
+}
+
+#endif
+
+HRESULT CExtractCallbackConsole::BeforeOpen(const wchar_t *name, bool testMode)
+{
+ RINOK(CheckBreak2())
+
+ NumTryArcs++;
+ ThereIsError_in_Current = false;
+ ThereIsWarning_in_Current = false;
+ NumFileErrors_in_Current = 0;
+
+ ClosePercents_for_so();
+ if (_so)
+ {
+ *_so << endl << (testMode ? kTesting : kExtracting);
+ _so->NormalizePrint_wstr(name);
+ *_so << endl;
+ }
+
+ if (NeedPercents())
+ _percent.Command = "Open";
+ return S_OK;
+}
+
+HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
+HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
+
+static AString GetOpenArcErrorMessage(UInt32 errorFlags)
+{
+ AString s;
+
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_ErrorFlagsMessages); i++)
+ {
+ UInt32 f = (1 << i);
+ if ((errorFlags & f) == 0)
+ continue;
+ const char *m = k_ErrorFlagsMessages[i];
+ if (!s.IsEmpty())
+ s.Add_LF();
+ s += m;
+ errorFlags &= ~f;
+ }
+
+ if (errorFlags != 0)
+ {
+ char sz[16];
+ sz[0] = '0';
+ sz[1] = 'x';
+ ConvertUInt32ToHex(errorFlags, sz + 2);
+ if (!s.IsEmpty())
+ s.Add_LF();
+ s += sz;
+ }
+
+ return s;
+}
+
+void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags);
+void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags)
+{
+ if (errorFlags == 0)
+ return;
+ so << s << endl << GetOpenArcErrorMessage(errorFlags) << endl;
+}
+
+static void Add_Messsage_Pre_ArcType(UString &s, const char *pre, const wchar_t *arcType)
+{
+ s.Add_LF();
+ s += pre;
+ s += " as [";
+ s += arcType;
+ s += "] archive";
+}
+
+void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc);
+void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc)
+{
+ const CArcErrorInfo &er = arc.ErrorInfo;
+
+ *_so << "WARNING:\n";
+ _so->NormalizePrint_UString(arc.Path);
+ UString s;
+ if (arc.FormatIndex == er.ErrorFormatIndex)
+ {
+ s.Add_LF();
+ s += "The archive is open with offset";
+ }
+ else
+ {
+ Add_Messsage_Pre_ArcType(s, "Cannot open the file", codecs->GetFormatNamePtr(er.ErrorFormatIndex));
+ Add_Messsage_Pre_ArcType(s, "The file is open", codecs->GetFormatNamePtr(arc.FormatIndex));
+ }
+
+ *_so << s << endl << endl;
+}
+
+
+HRESULT CExtractCallbackConsole::OpenResult(
+ const CCodecs *codecs, const CArchiveLink &arcLink,
+ const wchar_t *name, HRESULT result)
+{
+ ClosePercents();
+
+ if (NeedPercents())
+ {
+ _percent.Files = 0;
+ _percent.Command.Empty();
+ _percent.FileName.Empty();
+ }
+
+
+ ClosePercentsAndFlush();
+
+ FOR_VECTOR (level, arcLink.Arcs)
+ {
+ const CArc &arc = arcLink.Arcs[level];
+ const CArcErrorInfo &er = arc.ErrorInfo;
+
+ UInt32 errorFlags = er.GetErrorFlags();
+
+ if (errorFlags != 0 || !er.ErrorMessage.IsEmpty())
+ {
+ if (_se)
+ {
+ *_se << endl;
+ if (level != 0)
+ {
+ _se->NormalizePrint_UString(arc.Path);
+ *_se << endl;
+ }
+ }
+
+ if (errorFlags != 0)
+ {
+ if (_se)
+ PrintErrorFlags(*_se, "ERRORS:", errorFlags);
+ NumOpenArcErrors++;
+ ThereIsError_in_Current = true;
+ }
+
+ if (!er.ErrorMessage.IsEmpty())
+ {
+ if (_se)
+ *_se << "ERRORS:" << endl << er.ErrorMessage << endl;
+ NumOpenArcErrors++;
+ ThereIsError_in_Current = true;
+ }
+
+ if (_se)
+ {
+ *_se << endl;
+ _se->Flush();
+ }
+ }
+
+ UInt32 warningFlags = er.GetWarningFlags();
+
+ if (warningFlags != 0 || !er.WarningMessage.IsEmpty())
+ {
+ if (_so)
+ {
+ *_so << endl;
+ if (level != 0)
+ {
+ _so->NormalizePrint_UString(arc.Path);
+ *_so << endl;
+ }
+ }
+
+ if (warningFlags != 0)
+ {
+ if (_so)
+ PrintErrorFlags(*_so, "WARNINGS:", warningFlags);
+ NumOpenArcWarnings++;
+ ThereIsWarning_in_Current = true;
+ }
+
+ if (!er.WarningMessage.IsEmpty())
+ {
+ if (_so)
+ *_so << "WARNINGS:" << endl << er.WarningMessage << endl;
+ NumOpenArcWarnings++;
+ ThereIsWarning_in_Current = true;
+ }
+
+ if (_so)
+ {
+ *_so << endl;
+ if (NeedFlush)
+ _so->Flush();
+ }
+ }
+
+
+ if (er.ErrorFormatIndex >= 0)
+ {
+ if (_so)
+ {
+ Print_ErrorFormatIndex_Warning(_so, codecs, arc);
+ if (NeedFlush)
+ _so->Flush();
+ }
+ ThereIsWarning_in_Current = true;
+ }
+ }
+
+ if (result == S_OK)
+ {
+ if (_so)
+ {
+ RINOK(Print_OpenArchive_Props(*_so, codecs, arcLink))
+ *_so << endl;
+ }
+ }
+ else
+ {
+ NumCantOpenArcs++;
+ if (_so)
+ _so->Flush();
+ if (_se)
+ {
+ *_se << kError;
+ _se->NormalizePrint_wstr(name);
+ *_se << endl;
+ const HRESULT res = Print_OpenArchive_Error(*_se, codecs, arcLink);
+ RINOK(res)
+ if (result == S_FALSE)
+ {
+ }
+ else
+ {
+ if (result == E_OUTOFMEMORY)
+ *_se << "Can't allocate required memory";
+ else
+ *_se << NError::MyFormatMessage(result);
+ *_se << endl;
+ }
+ _se->Flush();
+ }
+ }
+
+
+ return CheckBreak2();
+}
+
+HRESULT CExtractCallbackConsole::ThereAreNoFiles()
+{
+ ClosePercents_for_so();
+
+ if (_so)
+ {
+ *_so << endl << kNoFiles << endl;
+ if (NeedFlush)
+ _so->Flush();
+ }
+ return CheckBreak2();
+}
+
+HRESULT CExtractCallbackConsole::ExtractResult(HRESULT result)
+{
+ MT_LOCK
+
+ if (NeedPercents())
+ {
+ _percent.ClosePrint(true);
+ _percent.Command.Empty();
+ _percent.FileName.Empty();
+ }
+
+ if (_so)
+ _so->Flush();
+
+ if (result == S_OK)
+ {
+ if (NumFileErrors_in_Current == 0 && !ThereIsError_in_Current)
+ {
+ if (ThereIsWarning_in_Current)
+ NumArcsWithWarnings++;
+ else
+ NumOkArcs++;
+ if (_so)
+ *_so << kEverythingIsOk << endl;
+ }
+ else
+ {
+ NumArcsWithError++;
+ if (_so)
+ {
+ *_so << endl;
+ if (NumFileErrors_in_Current != 0)
+ *_so << "Sub items Errors: " << NumFileErrors_in_Current << endl;
+ }
+ }
+ if (_so && NeedFlush)
+ _so->Flush();
+ }
+ else
+ {
+ NumArcsWithError++;
+ if (result == E_ABORT
+ || result == HRESULT_FROM_WIN32(ERROR_DISK_FULL)
+ )
+ return result;
+
+ if (_se)
+ {
+ *_se << endl << kError;
+ if (result == E_OUTOFMEMORY)
+ *_se << kMemoryExceptionMessage;
+ else
+ *_se << NError::MyFormatMessage(result);
+ *_se << endl;
+ _se->Flush();
+ }
+ }
+
+ return CheckBreak2();
+}
diff --git a/CPP/7zip/UI/Console/ExtractCallbackConsole.h b/CPP/7zip/UI/Console/ExtractCallbackConsole.h
index 5de6c5b..478b293 100644
--- a/CPP/7zip/UI/Console/ExtractCallbackConsole.h
+++ b/CPP/7zip/UI/Console/ExtractCallbackConsole.h
@@ -1,164 +1,181 @@
-// ExtractCallbackConsole.h
-
-#ifndef __EXTRACT_CALLBACK_CONSOLE_H
-#define __EXTRACT_CALLBACK_CONSOLE_H
-
-#include "../../../Common/StdOutStream.h"
-
-#include "../../IPassword.h"
-
-#include "../../Archive/IArchive.h"
-
-#include "../Common/ArchiveExtractCallback.h"
-
-#include "PercentPrinter.h"
-
-#include "OpenCallbackConsole.h"
-
-class CExtractScanConsole: public IDirItemsCallback
-{
- CStdOutStream *_so;
- CStdOutStream *_se;
- CPercentPrinter _percent;
-
- bool NeedPercents() const { return _percent._so != NULL; }
-
- void ClosePercentsAndFlush()
- {
- if (NeedPercents())
- _percent.ClosePrint(true);
- if (_so)
- _so->Flush();
- }
-
-public:
- void Init(CStdOutStream *outStream, CStdOutStream *errorStream, CStdOutStream *percentStream)
- {
- _so = outStream;
- _se = errorStream;
- _percent._so = percentStream;
- }
-
- void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; }
-
- void StartScanning();
-
- INTERFACE_IDirItemsCallback(;)
-
- void CloseScanning()
- {
- if (NeedPercents())
- _percent.ClosePrint(true);
- }
-
- void PrintStat(const CDirItemsStat &st);
-};
-
-
-
-
-class CExtractCallbackConsole:
- public IExtractCallbackUI,
- // public IArchiveExtractCallbackMessage,
- public IFolderArchiveExtractCallback2,
- #ifndef _NO_CRYPTO
- public ICryptoGetTextPassword,
- #endif
- public COpenCallbackConsole,
- public CMyUnknownImp
-{
- AString _tempA;
- UString _tempU;
-
- UString _currentName;
-
- void ClosePercents_for_so()
- {
- if (NeedPercents() && _so == _percent._so)
- _percent.ClosePrint(false);
- }
-
- void ClosePercentsAndFlush()
- {
- if (NeedPercents())
- _percent.ClosePrint(true);
- if (_so)
- _so->Flush();
- }
-
-public:
- MY_QUERYINTERFACE_BEGIN2(IFolderArchiveExtractCallback)
- // MY_QUERYINTERFACE_ENTRY(IArchiveExtractCallbackMessage)
- MY_QUERYINTERFACE_ENTRY(IFolderArchiveExtractCallback2)
- #ifndef _NO_CRYPTO
- MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword)
- #endif
- MY_QUERYINTERFACE_END
- MY_ADDREF_RELEASE
-
- STDMETHOD(SetTotal)(UInt64 total);
- STDMETHOD(SetCompleted)(const UInt64 *completeValue);
-
- INTERFACE_IFolderArchiveExtractCallback(;)
-
- INTERFACE_IExtractCallbackUI(;)
- // INTERFACE_IArchiveExtractCallbackMessage(;)
- INTERFACE_IFolderArchiveExtractCallback2(;)
-
- #ifndef _NO_CRYPTO
-
- STDMETHOD(CryptoGetTextPassword)(BSTR *password);
-
- #endif
-
- UInt64 NumTryArcs;
-
- bool ThereIsError_in_Current;
- bool ThereIsWarning_in_Current;
-
- UInt64 NumOkArcs;
- UInt64 NumCantOpenArcs;
- UInt64 NumArcsWithError;
- UInt64 NumArcsWithWarnings;
-
- UInt64 NumOpenArcErrors;
- UInt64 NumOpenArcWarnings;
-
- UInt64 NumFileErrors;
- UInt64 NumFileErrors_in_Current;
-
- bool NeedFlush;
- unsigned PercentsNameLevel;
- unsigned LogLevel;
-
- CExtractCallbackConsole():
- NeedFlush(false),
- PercentsNameLevel(1),
- LogLevel(0)
- {}
-
- void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; }
-
- void Init(CStdOutStream *outStream, CStdOutStream *errorStream, CStdOutStream *percentStream)
- {
- COpenCallbackConsole::Init(outStream, errorStream, percentStream);
-
- NumTryArcs = 0;
-
- ThereIsError_in_Current = false;
- ThereIsWarning_in_Current = false;
-
- NumOkArcs = 0;
- NumCantOpenArcs = 0;
- NumArcsWithError = 0;
- NumArcsWithWarnings = 0;
-
- NumOpenArcErrors = 0;
- NumOpenArcWarnings = 0;
-
- NumFileErrors = 0;
- NumFileErrors_in_Current = 0;
- }
-};
-
-#endif
+// ExtractCallbackConsole.h
+
+#ifndef ZIP7_INC_EXTRACT_CALLBACK_CONSOLE_H
+#define ZIP7_INC_EXTRACT_CALLBACK_CONSOLE_H
+
+#include "../../../Common/StdOutStream.h"
+
+#include "../../IPassword.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "../Common/ArchiveExtractCallback.h"
+
+#include "PercentPrinter.h"
+
+#include "OpenCallbackConsole.h"
+
+/*
+struct CErrorPathCodes2
+{
+ FStringVector Paths;
+ CRecordVector<DWORD> Codes;
+
+ void AddError(const FString &path, DWORD systemError)
+ {
+ Paths.Add(path);
+ Codes.Add(systemError);
+ }
+ void Clear()
+ {
+ Paths.Clear();
+ Codes.Clear();
+ }
+};
+*/
+
+class CExtractScanConsole Z7_final: public IDirItemsCallback
+{
+ Z7_IFACE_IMP(IDirItemsCallback)
+
+ CStdOutStream *_so;
+ CStdOutStream *_se;
+ CPercentPrinter _percent;
+
+ // CErrorPathCodes2 ScanErrors;
+
+ bool NeedPercents() const { return _percent._so != NULL; }
+
+ void ClosePercentsAndFlush()
+ {
+ if (NeedPercents())
+ _percent.ClosePrint(true);
+ if (_so)
+ _so->Flush();
+ }
+
+public:
+
+ void Init(CStdOutStream *outStream, CStdOutStream *errorStream, CStdOutStream *percentStream)
+ {
+ _so = outStream;
+ _se = errorStream;
+ _percent._so = percentStream;
+ }
+
+ void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; }
+
+ void StartScanning();
+
+ void CloseScanning()
+ {
+ if (NeedPercents())
+ _percent.ClosePrint(true);
+ }
+
+ void PrintStat(const CDirItemsStat &st);
+};
+
+
+
+
+class CExtractCallbackConsole Z7_final:
+ public IFolderArchiveExtractCallback,
+ public IExtractCallbackUI,
+ // public IArchiveExtractCallbackMessage,
+ public IFolderArchiveExtractCallback2,
+ #ifndef Z7_NO_CRYPTO
+ public ICryptoGetTextPassword,
+ #endif
+ public COpenCallbackConsole,
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(IFolderArchiveExtractCallback)
+ // Z7_COM_QI_ENTRY(IArchiveExtractCallbackMessage)
+ Z7_COM_QI_ENTRY(IFolderArchiveExtractCallback2)
+ #ifndef Z7_NO_CRYPTO
+ Z7_COM_QI_ENTRY(ICryptoGetTextPassword)
+ #endif
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(IProgress)
+ Z7_IFACE_COM7_IMP(IFolderArchiveExtractCallback)
+ Z7_IFACE_IMP(IExtractCallbackUI)
+ // Z7_IFACE_COM7_IMP(IArchiveExtractCallbackMessage)
+ Z7_IFACE_COM7_IMP(IFolderArchiveExtractCallback2)
+ #ifndef Z7_NO_CRYPTO
+ Z7_IFACE_COM7_IMP(ICryptoGetTextPassword)
+ #endif
+
+
+ AString _tempA;
+ UString _tempU;
+
+ UString _currentName;
+
+ void ClosePercents_for_so()
+ {
+ if (NeedPercents() && _so == _percent._so)
+ _percent.ClosePrint(false);
+ }
+
+ void ClosePercentsAndFlush()
+ {
+ if (NeedPercents())
+ _percent.ClosePrint(true);
+ if (_so)
+ _so->Flush();
+ }
+public:
+ UInt64 NumTryArcs;
+
+ bool ThereIsError_in_Current;
+ bool ThereIsWarning_in_Current;
+
+ UInt64 NumOkArcs;
+ UInt64 NumCantOpenArcs;
+ UInt64 NumArcsWithError;
+ UInt64 NumArcsWithWarnings;
+
+ UInt64 NumOpenArcErrors;
+ UInt64 NumOpenArcWarnings;
+
+ UInt64 NumFileErrors;
+ UInt64 NumFileErrors_in_Current;
+
+ bool NeedFlush;
+ unsigned PercentsNameLevel;
+ unsigned LogLevel;
+
+ CExtractCallbackConsole():
+ NeedFlush(false),
+ PercentsNameLevel(1),
+ LogLevel(0)
+ {}
+
+ void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; }
+
+ void Init(CStdOutStream *outStream, CStdOutStream *errorStream, CStdOutStream *percentStream)
+ {
+ COpenCallbackConsole::Init(outStream, errorStream, percentStream);
+
+ NumTryArcs = 0;
+
+ ThereIsError_in_Current = false;
+ ThereIsWarning_in_Current = false;
+
+ NumOkArcs = 0;
+ NumCantOpenArcs = 0;
+ NumArcsWithError = 0;
+ NumArcsWithWarnings = 0;
+
+ NumOpenArcErrors = 0;
+ NumOpenArcWarnings = 0;
+
+ NumFileErrors = 0;
+ NumFileErrors_in_Current = 0;
+ }
+};
+
+#endif
diff --git a/CPP/7zip/UI/Console/HashCon.cpp b/CPP/7zip/UI/Console/HashCon.cpp
index 3ade0fd..c0e69e2 100644
--- a/CPP/7zip/UI/Console/HashCon.cpp
+++ b/CPP/7zip/UI/Console/HashCon.cpp
@@ -1,367 +1,426 @@
-// HashCon.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/IntToString.h"
-
-#include "ConsoleClose.h"
-#include "HashCon.h"
-
-static const char * const kEmptyFileAlias = "[Content]";
-
-static const char * const kScanningMessage = "Scanning";
-
-static HRESULT CheckBreak2()
-{
- return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
-}
-
-HRESULT CHashCallbackConsole::CheckBreak()
-{
- return CheckBreak2();
-}
-
-HRESULT CHashCallbackConsole::StartScanning()
-{
- if (PrintHeaders && _so)
- *_so << kScanningMessage << endl;
- if (NeedPercents())
- {
- _percent.ClearCurState();
- _percent.Command = "Scan";
- }
- return CheckBreak2();
-}
-
-HRESULT CHashCallbackConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */)
-{
- if (NeedPercents())
- {
- _percent.Files = st.NumDirs + st.NumFiles + st.NumAltStreams;
- _percent.Completed = st.GetTotalBytes();
- _percent.FileName = fs2us(path);
- _percent.Print();
- }
- return CheckBreak2();
-}
-
-HRESULT CHashCallbackConsole::ScanError(const FString &path, DWORD systemError)
-{
- return ScanError_Base(path, systemError);
-}
-
-void Print_DirItemsStat(AString &s, const CDirItemsStat &st);
-
-HRESULT CHashCallbackConsole::FinishScanning(const CDirItemsStat &st)
-{
- if (NeedPercents())
- {
- _percent.ClosePrint(true);
- _percent.ClearCurState();
- }
- if (PrintHeaders && _so)
- {
- Print_DirItemsStat(_s, st);
- *_so << _s << endl << endl;
- }
- return CheckBreak2();
-}
-
-HRESULT CHashCallbackConsole::SetNumFiles(UInt64 /* numFiles */)
-{
- return CheckBreak2();
-}
-
-HRESULT CHashCallbackConsole::SetTotal(UInt64 size)
-{
- if (NeedPercents())
- {
- _percent.Total = size;
- _percent.Print();
- }
- return CheckBreak2();
-}
-
-HRESULT CHashCallbackConsole::SetCompleted(const UInt64 *completeValue)
-{
- if (completeValue && NeedPercents())
- {
- _percent.Completed = *completeValue;
- _percent.Print();
- }
- return CheckBreak2();
-}
-
-static void AddMinuses(AString &s, unsigned num)
-{
- for (unsigned i = 0; i < num; i++)
- s += '-';
-}
-
-static void AddSpaces_if_Positive(AString &s, int num)
-{
- for (int i = 0; i < num; i++)
- s.Add_Space();
-}
-
-static void SetSpacesAndNul(char *s, unsigned num)
-{
- for (unsigned i = 0; i < num; i++)
- s[i] = ' ';
- s[num] = 0;
-}
-
-static const unsigned kSizeField_Len = 13;
-static const unsigned kNameField_Len = 12;
-
-static const unsigned kHashColumnWidth_Min = 4 * 2;
-
-static unsigned GetColumnWidth(unsigned digestSize)
-{
- unsigned width = digestSize * 2;
- return width < kHashColumnWidth_Min ? kHashColumnWidth_Min: width;
-}
-
-void CHashCallbackConsole::PrintSeparatorLine(const CObjectVector<CHasherState> &hashers)
-{
- _s.Empty();
-
- for (unsigned i = 0; i < hashers.Size(); i++)
- {
- if (i != 0)
- _s.Add_Space();
- const CHasherState &h = hashers[i];
- AddMinuses(_s, GetColumnWidth(h.DigestSize));
- }
-
- if (PrintSize)
- {
- _s.Add_Space();
- AddMinuses(_s, kSizeField_Len);
- }
-
- if (PrintName)
- {
- AddSpacesBeforeName();
- AddMinuses(_s, kNameField_Len);
- }
-
- *_so << _s << endl;
-}
-
-HRESULT CHashCallbackConsole::BeforeFirstFile(const CHashBundle &hb)
-{
- if (PrintHeaders && _so)
- {
- _s.Empty();
- ClosePercents_for_so();
-
- FOR_VECTOR (i, hb.Hashers)
- {
- if (i != 0)
- _s.Add_Space();
- const CHasherState &h = hb.Hashers[i];
- _s += h.Name;
- AddSpaces_if_Positive(_s, (int)GetColumnWidth(h.DigestSize) - (int)h.Name.Len());
- }
-
- if (PrintSize)
- {
- _s.Add_Space();
- const AString s2 ("Size");
- AddSpaces_if_Positive(_s, (int)kSizeField_Len - (int)s2.Len());
- _s += s2;
- }
-
- if (PrintName)
- {
- AddSpacesBeforeName();
- _s += "Name";
- }
-
- *_so << _s << endl;
- PrintSeparatorLine(hb.Hashers);
- }
-
- return CheckBreak2();
-}
-
-HRESULT CHashCallbackConsole::OpenFileError(const FString &path, DWORD systemError)
-{
- return OpenFileError_Base(path, systemError);
-}
-
-HRESULT CHashCallbackConsole::GetStream(const wchar_t *name, bool /* isFolder */)
-{
- _fileName = name;
-
- if (NeedPercents())
- {
- if (PrintNameInPercents)
- {
- _percent.FileName.Empty();
- if (name)
- _percent.FileName = name;
- }
- _percent.Print();
- }
- return CheckBreak2();
-}
-
-void CHashCallbackConsole::PrintResultLine(UInt64 fileSize,
- const CObjectVector<CHasherState> &hashers, unsigned digestIndex, bool showHash)
-{
- ClosePercents_for_so();
-
- _s.Empty();
-
- FOR_VECTOR (i, hashers)
- {
- const CHasherState &h = hashers[i];
- char s[k_HashCalc_DigestSize_Max * 2 + 64];
- s[0] = 0;
- if (showHash)
- AddHashHexToString(s, h.Digests[digestIndex], h.DigestSize);
- SetSpacesAndNul(s + strlen(s), (int)GetColumnWidth(h.DigestSize) - (int)strlen(s));
- if (i != 0)
- _s.Add_Space();
- _s += s;
- }
-
- if (PrintSize)
- {
- _s.Add_Space();
-
- char s[kSizeField_Len + 32];
- char *p = s;
-
- if (showHash)
- {
- p = s + kSizeField_Len;
- ConvertUInt64ToString(fileSize, p);
- int numSpaces = kSizeField_Len - (int)strlen(p);
- if (numSpaces > 0)
- {
- p -= (unsigned)numSpaces;
- for (unsigned i = 0; i < (unsigned)numSpaces; i++)
- p[i] = ' ';
- }
- }
- else
- SetSpacesAndNul(s, kSizeField_Len);
-
- _s += p;
- }
-
- if (PrintName)
- AddSpacesBeforeName();
-
- *_so << _s;
-}
-
-HRESULT CHashCallbackConsole::SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash)
-{
- if (_so)
- {
- PrintResultLine(fileSize, hb.Hashers, k_HashCalc_Index_Current, showHash);
- if (PrintName)
- {
- if (_fileName.IsEmpty())
- *_so << kEmptyFileAlias;
- else
- _so->NormalizePrint_UString(_fileName);
- }
- *_so << endl;
- }
-
- if (NeedPercents())
- {
- _percent.Files++;
- _percent.Print();
- }
-
- return CheckBreak2();
-}
-
-static const char * const k_DigestTitles[] =
-{
- " : "
- , " for data: "
- , " for data and names: "
- , " for streams and names: "
-};
-
-static void PrintSum(CStdOutStream &so, const CHasherState &h, unsigned digestIndex)
-{
- so << h.Name;
-
- {
- AString temp;
- AddSpaces_if_Positive(temp, 6 - (int)h.Name.Len());
- so << temp;
- }
-
- so << k_DigestTitles[digestIndex];
-
- char s[k_HashCalc_DigestSize_Max * 2 + 64];
- s[0] = 0;
- AddHashHexToString(s, h.Digests[digestIndex], h.DigestSize);
- so << s << endl;
-}
-
-void PrintHashStat(CStdOutStream &so, const CHashBundle &hb)
-{
- FOR_VECTOR (i, hb.Hashers)
- {
- const CHasherState &h = hb.Hashers[i];
- PrintSum(so, h, k_HashCalc_Index_DataSum);
- if (hb.NumFiles != 1 || hb.NumDirs != 0)
- PrintSum(so, h, k_HashCalc_Index_NamesSum);
- if (hb.NumAltStreams != 0)
- PrintSum(so, h, k_HashCalc_Index_StreamsSum);
- so << endl;
- }
-}
-
-void CHashCallbackConsole::PrintProperty(const char *name, UInt64 value)
-{
- char s[32];
- s[0] = ':';
- s[1] = ' ';
- ConvertUInt64ToString(value, s + 2);
- *_so << name << s << endl;
-}
-
-HRESULT CHashCallbackConsole::AfterLastFile(CHashBundle &hb)
-{
- ClosePercents2();
-
- if (PrintHeaders && _so)
- {
- PrintSeparatorLine(hb.Hashers);
-
- PrintResultLine(hb.FilesSize, hb.Hashers, k_HashCalc_Index_DataSum, true);
-
- *_so << endl << endl;
-
- if (hb.NumFiles != 1 || hb.NumDirs != 0)
- {
- if (hb.NumDirs != 0)
- PrintProperty("Folders", hb.NumDirs);
- PrintProperty("Files", hb.NumFiles);
- }
-
- PrintProperty("Size", hb.FilesSize);
-
- if (hb.NumAltStreams != 0)
- {
- PrintProperty("Alternate streams", hb.NumAltStreams);
- PrintProperty("Alternate streams size", hb.AltStreamsSize);
- }
-
- *_so << endl;
- PrintHashStat(*_so, hb);
- }
-
- return S_OK;
-}
+// HashCon.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+
+#include "../../../Windows/FileName.h"
+
+#include "ConsoleClose.h"
+#include "HashCon.h"
+
+static const char * const kEmptyFileAlias = "[Content]";
+
+static const char * const kScanningMessage = "Scanning";
+
+static HRESULT CheckBreak2()
+{
+ return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
+}
+
+HRESULT CHashCallbackConsole::CheckBreak()
+{
+ return CheckBreak2();
+}
+
+HRESULT CHashCallbackConsole::StartScanning()
+{
+ if (PrintHeaders && _so)
+ *_so << kScanningMessage << endl;
+ if (NeedPercents())
+ {
+ _percent.ClearCurState();
+ _percent.Command = "Scan";
+ }
+ return CheckBreak2();
+}
+
+HRESULT CHashCallbackConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir)
+{
+ if (NeedPercents())
+ {
+ _percent.Files = st.NumDirs + st.NumFiles + st.NumAltStreams;
+ _percent.Completed = st.GetTotalBytes();
+ _percent.FileName = fs2us(path);
+ if (isDir)
+ NWindows::NFile::NName::NormalizeDirPathPrefix(_percent.FileName);
+ _percent.Print();
+ }
+ return CheckBreak2();
+}
+
+HRESULT CHashCallbackConsole::ScanError(const FString &path, DWORD systemError)
+{
+ return ScanError_Base(path, systemError);
+}
+
+void Print_DirItemsStat(AString &s, const CDirItemsStat &st);
+
+HRESULT CHashCallbackConsole::FinishScanning(const CDirItemsStat &st)
+{
+ if (NeedPercents())
+ {
+ _percent.ClosePrint(true);
+ _percent.ClearCurState();
+ }
+ if (PrintHeaders && _so)
+ {
+ Print_DirItemsStat(_s, st);
+ *_so << _s << endl << endl;
+ }
+ return CheckBreak2();
+}
+
+HRESULT CHashCallbackConsole::SetNumFiles(UInt64 /* numFiles */)
+{
+ return CheckBreak2();
+}
+
+HRESULT CHashCallbackConsole::SetTotal(UInt64 size)
+{
+ if (NeedPercents())
+ {
+ _percent.Total = size;
+ _percent.Print();
+ }
+ return CheckBreak2();
+}
+
+HRESULT CHashCallbackConsole::SetCompleted(const UInt64 *completeValue)
+{
+ if (completeValue && NeedPercents())
+ {
+ _percent.Completed = *completeValue;
+ _percent.Print();
+ }
+ return CheckBreak2();
+}
+
+static void AddMinuses(AString &s, unsigned num)
+{
+ for (unsigned i = 0; i < num; i++)
+ s.Add_Minus();
+}
+
+static void AddSpaces_if_Positive(AString &s, int num)
+{
+ for (int i = 0; i < num; i++)
+ s.Add_Space();
+}
+
+static void SetSpacesAndNul(char *s, unsigned num)
+{
+ for (unsigned i = 0; i < num; i++)
+ s[i] = ' ';
+ s[num] = 0;
+}
+
+static void SetSpacesAndNul_if_Positive(char *s, int num)
+{
+ if (num < 0)
+ return;
+ for (int i = 0; i < num; i++)
+ s[i] = ' ';
+ s[num] = 0;
+}
+
+static const unsigned kSizeField_Len = 13;
+static const unsigned kNameField_Len = 12;
+
+static const unsigned kHashColumnWidth_Min = 4 * 2;
+
+static unsigned GetColumnWidth(unsigned digestSize)
+{
+ unsigned width = digestSize * 2;
+ return width < kHashColumnWidth_Min ? kHashColumnWidth_Min: width;
+}
+
+
+AString CHashCallbackConsole::GetFields() const
+{
+ AString s (PrintFields);
+ if (s.IsEmpty())
+ s = "hsn";
+ s.MakeLower_Ascii();
+ return s;
+}
+
+
+void CHashCallbackConsole::PrintSeparatorLine(const CObjectVector<CHasherState> &hashers)
+{
+ _s.Empty();
+ const AString fields = GetFields();
+ for (unsigned pos = 0; pos < fields.Len(); pos++)
+ {
+ const char c = fields[pos];
+ if (c == 'h')
+ {
+ for (unsigned i = 0; i < hashers.Size(); i++)
+ {
+ AddSpace();
+ const CHasherState &h = hashers[i];
+ AddMinuses(_s, GetColumnWidth(h.DigestSize));
+ }
+ }
+ else if (c == 's')
+ {
+ AddSpace();
+ AddMinuses(_s, kSizeField_Len);
+ }
+ else if (c == 'n')
+ {
+ AddSpacesBeforeName();
+ AddMinuses(_s, kNameField_Len);
+ }
+ }
+
+ *_so << _s << endl;
+}
+
+
+HRESULT CHashCallbackConsole::BeforeFirstFile(const CHashBundle &hb)
+{
+ if (PrintHeaders && _so)
+ {
+ _s.Empty();
+ ClosePercents_for_so();
+
+ const AString fields = GetFields();
+ for (unsigned pos = 0; pos < fields.Len(); pos++)
+ {
+ const char c = fields[pos];
+ if (c == 'h')
+ {
+ FOR_VECTOR (i, hb.Hashers)
+ {
+ AddSpace();
+ const CHasherState &h = hb.Hashers[i];
+ _s += h.Name;
+ AddSpaces_if_Positive(_s, (int)GetColumnWidth(h.DigestSize) - (int)h.Name.Len());
+ }
+ }
+
+ else if (c == 's')
+ {
+ AddSpace();
+ const AString s2 ("Size");
+ AddSpaces_if_Positive(_s, (int)kSizeField_Len - (int)s2.Len());
+ _s += s2;
+ }
+ else if (c == 'n')
+ {
+ AddSpacesBeforeName();
+ _s += "Name";
+ }
+ }
+
+ *_so << _s << endl;
+ PrintSeparatorLine(hb.Hashers);
+ }
+
+ return CheckBreak2();
+}
+
+HRESULT CHashCallbackConsole::OpenFileError(const FString &path, DWORD systemError)
+{
+ return OpenFileError_Base(path, systemError);
+}
+
+HRESULT CHashCallbackConsole::GetStream(const wchar_t *name, bool isDir)
+{
+ _fileName = name;
+ if (isDir)
+ NWindows::NFile::NName::NormalizeDirPathPrefix(_fileName);
+
+ if (NeedPercents())
+ {
+ if (PrintNameInPercents)
+ {
+ _percent.FileName.Empty();
+ if (name)
+ _percent.FileName = name;
+ }
+ _percent.Print();
+ }
+ return CheckBreak2();
+}
+
+
+static const unsigned k_DigestStringSize = k_HashCalc_DigestSize_Max * 2 + k_HashCalc_ExtraSize * 2 + 16;
+
+
+
+void CHashCallbackConsole::PrintResultLine(UInt64 fileSize,
+ const CObjectVector<CHasherState> &hashers, unsigned digestIndex, bool showHash,
+ const AString &path)
+{
+ ClosePercents_for_so();
+
+ _s.Empty();
+ const AString fields = GetFields();
+
+ for (unsigned pos = 0; pos < fields.Len(); pos++)
+ {
+ const char c = fields[pos];
+ if (c == 'h')
+ {
+ FOR_VECTOR (i, hashers)
+ {
+ AddSpace();
+ const CHasherState &h = hashers[i];
+ char s[k_DigestStringSize];
+ s[0] = 0;
+ if (showHash)
+ h.WriteToString(digestIndex, s);
+ const unsigned len = (unsigned)strlen(s);
+ SetSpacesAndNul_if_Positive(s + len, (int)GetColumnWidth(h.DigestSize) - (int)len);
+ _s += s;
+ }
+ }
+ else if (c == 's')
+ {
+ AddSpace();
+ char s[kSizeField_Len + 32];
+ char *p = s;
+ SetSpacesAndNul(s, kSizeField_Len);
+ if (showHash)
+ {
+ p = s + kSizeField_Len;
+ ConvertUInt64ToString(fileSize, p);
+ const int numSpaces = (int)kSizeField_Len - (int)strlen(p);
+ if (numSpaces > 0)
+ p -= (unsigned)numSpaces;
+ }
+ _s += p;
+ }
+ else if (c == 'n')
+ {
+ AddSpacesBeforeName();
+ _s += path;
+ }
+ }
+
+ *_so << _s;
+}
+
+
+HRESULT CHashCallbackConsole::SetOperationResult(UInt64 fileSize, const CHashBundle &hb, bool showHash)
+{
+ if (_so)
+ {
+ AString s;
+ if (_fileName.IsEmpty())
+ s = kEmptyFileAlias;
+ else
+ {
+ UString temp (_fileName);
+ _so->Normalize_UString(temp);
+ _so->Convert_UString_to_AString(temp, s);
+ }
+ PrintResultLine(fileSize, hb.Hashers, k_HashCalc_Index_Current, showHash, s);
+
+ /*
+ PrintResultLine(fileSize, hb.Hashers, k_HashCalc_Index_Current, showHash);
+ if (PrintName)
+ {
+ if (_fileName.IsEmpty())
+ *_so << kEmptyFileAlias;
+ else
+ _so->NormalizePrint_UString(_fileName);
+ }
+ */
+ // if (PrintNewLine)
+ *_so << endl;
+ }
+
+ if (NeedPercents())
+ {
+ _percent.Files++;
+ _percent.Print();
+ }
+
+ return CheckBreak2();
+}
+
+static const char * const k_DigestTitles[] =
+{
+ " : "
+ , " for data: "
+ , " for data and names: "
+ , " for streams and names: "
+};
+
+static void PrintSum(CStdOutStream &so, const CHasherState &h, unsigned digestIndex)
+{
+ so << h.Name;
+
+ {
+ AString temp;
+ AddSpaces_if_Positive(temp, 6 - (int)h.Name.Len());
+ so << temp;
+ }
+
+ so << k_DigestTitles[digestIndex];
+
+ char s[k_DigestStringSize];
+ // s[0] = 0;
+ h.WriteToString(digestIndex, s);
+ so << s << endl;
+}
+
+void PrintHashStat(CStdOutStream &so, const CHashBundle &hb)
+{
+ FOR_VECTOR (i, hb.Hashers)
+ {
+ const CHasherState &h = hb.Hashers[i];
+ PrintSum(so, h, k_HashCalc_Index_DataSum);
+ if (hb.NumFiles != 1 || hb.NumDirs != 0)
+ PrintSum(so, h, k_HashCalc_Index_NamesSum);
+ if (hb.NumAltStreams != 0)
+ PrintSum(so, h, k_HashCalc_Index_StreamsSum);
+ so << endl;
+ }
+}
+
+void CHashCallbackConsole::PrintProperty(const char *name, UInt64 value)
+{
+ char s[32];
+ s[0] = ':';
+ s[1] = ' ';
+ ConvertUInt64ToString(value, s + 2);
+ *_so << name << s << endl;
+}
+
+HRESULT CHashCallbackConsole::AfterLastFile(CHashBundle &hb)
+{
+ ClosePercents2();
+
+ if (PrintHeaders && _so)
+ {
+ PrintSeparatorLine(hb.Hashers);
+
+ PrintResultLine(hb.FilesSize, hb.Hashers, k_HashCalc_Index_DataSum, true, AString());
+
+ *_so << endl << endl;
+
+ if (hb.NumFiles != 1 || hb.NumDirs != 0)
+ {
+ if (hb.NumDirs != 0)
+ PrintProperty("Folders", hb.NumDirs);
+ PrintProperty("Files", hb.NumFiles);
+ }
+
+ PrintProperty("Size", hb.FilesSize);
+
+ if (hb.NumAltStreams != 0)
+ {
+ PrintProperty("Alternate streams", hb.NumAltStreams);
+ PrintProperty("Alternate streams size", hb.AltStreamsSize);
+ }
+
+ *_so << endl;
+ PrintHashStat(*_so, hb);
+ }
+
+ return S_OK;
+}
diff --git a/CPP/7zip/UI/Console/HashCon.h b/CPP/7zip/UI/Console/HashCon.h
index 9c12869..ebccb6f 100644
--- a/CPP/7zip/UI/Console/HashCon.h
+++ b/CPP/7zip/UI/Console/HashCon.h
@@ -1,48 +1,58 @@
-// HashCon.h
-
-#ifndef __HASH_CON_H
-#define __HASH_CON_H
-
-#include "../Common/HashCalc.h"
-
-#include "UpdateCallbackConsole.h"
-
-class CHashCallbackConsole: public IHashCallbackUI, public CCallbackConsoleBase
-{
- UString _fileName;
- AString _s;
-
- void AddSpacesBeforeName()
- {
- _s.Add_Space();
- _s.Add_Space();
- }
-
- void PrintSeparatorLine(const CObjectVector<CHasherState> &hashers);
- void PrintResultLine(UInt64 fileSize,
- const CObjectVector<CHasherState> &hashers, unsigned digestIndex, bool showHash);
- void PrintProperty(const char *name, UInt64 value);
-
-public:
- bool PrintNameInPercents;
-
- bool PrintHeaders;
-
- bool PrintSize;
- bool PrintName;
-
- CHashCallbackConsole():
- PrintNameInPercents(true),
- PrintHeaders(false),
- PrintSize(true),
- PrintName(true)
- {}
-
- ~CHashCallbackConsole() { }
-
- INTERFACE_IHashCallbackUI(;)
-};
-
-void PrintHashStat(CStdOutStream &so, const CHashBundle &hb);
-
-#endif
+// HashCon.h
+
+#ifndef ZIP7_INC_HASH_CON_H
+#define ZIP7_INC_HASH_CON_H
+
+#include "../Common/HashCalc.h"
+
+#include "UpdateCallbackConsole.h"
+
+class CHashCallbackConsole Z7_final:
+ public IHashCallbackUI,
+ public CCallbackConsoleBase
+{
+ Z7_IFACE_IMP(IDirItemsCallback)
+ Z7_IFACE_IMP(IHashCallbackUI)
+
+ UString _fileName;
+ AString _s;
+
+ void AddSpace()
+ {
+ _s.Add_Space_if_NotEmpty();
+ }
+
+ void AddSpacesBeforeName()
+ {
+ if (!_s.IsEmpty())
+ {
+ _s.Add_Space();
+ _s.Add_Space();
+ }
+ }
+
+ void PrintSeparatorLine(const CObjectVector<CHasherState> &hashers);
+ void PrintResultLine(UInt64 fileSize,
+ const CObjectVector<CHasherState> &hashers, unsigned digestIndex, bool showHash, const AString &path);
+ void PrintProperty(const char *name, UInt64 value);
+
+public:
+ bool PrintNameInPercents;
+ bool PrintHeaders;
+ // bool PrintSize;
+ // bool PrintNewLine; // set it too (false), if you need only hash for single file without LF char.
+ AString PrintFields;
+
+ AString GetFields() const;
+
+ CHashCallbackConsole():
+ PrintNameInPercents(true),
+ PrintHeaders(false)
+ // , PrintSize(true),
+ // , PrintNewLine(true)
+ {}
+};
+
+void PrintHashStat(CStdOutStream &so, const CHashBundle &hb);
+
+#endif
diff --git a/CPP/7zip/UI/Console/List.cpp b/CPP/7zip/UI/Console/List.cpp
index c56e2e2..46819f1 100644
--- a/CPP/7zip/UI/Console/List.cpp
+++ b/CPP/7zip/UI/Console/List.cpp
@@ -1,1359 +1,1390 @@
-// List.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/IntToString.h"
-#include "../../../Common/MyCom.h"
-#include "../../../Common/StdOutStream.h"
-#include "../../../Common/StringConvert.h"
-#include "../../../Common/UTFConvert.h"
-
-#include "../../../Windows/ErrorMsg.h"
-#include "../../../Windows/FileDir.h"
-#include "../../../Windows/PropVariant.h"
-#include "../../../Windows/PropVariantConv.h"
-
-#include "../Common/OpenArchive.h"
-#include "../Common/PropIDUtils.h"
-
-#include "ConsoleClose.h"
-#include "List.h"
-#include "OpenCallbackConsole.h"
-
-using namespace NWindows;
-using namespace NCOM;
-
-extern CStdOutStream *g_StdStream;
-extern CStdOutStream *g_ErrStream;
-
-static const char * const kPropIdToName[] =
-{
- "0"
- , "1"
- , "2"
- , "Path"
- , "Name"
- , "Extension"
- , "Folder"
- , "Size"
- , "Packed Size"
- , "Attributes"
- , "Created"
- , "Accessed"
- , "Modified"
- , "Solid"
- , "Commented"
- , "Encrypted"
- , "Split Before"
- , "Split After"
- , "Dictionary Size"
- , "CRC"
- , "Type"
- , "Anti"
- , "Method"
- , "Host OS"
- , "File System"
- , "User"
- , "Group"
- , "Block"
- , "Comment"
- , "Position"
- , "Path Prefix"
- , "Folders"
- , "Files"
- , "Version"
- , "Volume"
- , "Multivolume"
- , "Offset"
- , "Links"
- , "Blocks"
- , "Volumes"
- , "Time Type"
- , "64-bit"
- , "Big-endian"
- , "CPU"
- , "Physical Size"
- , "Headers Size"
- , "Checksum"
- , "Characteristics"
- , "Virtual Address"
- , "ID"
- , "Short Name"
- , "Creator Application"
- , "Sector Size"
- , "Mode"
- , "Symbolic Link"
- , "Error"
- , "Total Size"
- , "Free Space"
- , "Cluster Size"
- , "Label"
- , "Local Name"
- , "Provider"
- , "NT Security"
- , "Alternate Stream"
- , "Aux"
- , "Deleted"
- , "Tree"
- , "SHA-1"
- , "SHA-256"
- , "Error Type"
- , "Errors"
- , "Errors"
- , "Warnings"
- , "Warning"
- , "Streams"
- , "Alternate Streams"
- , "Alternate Streams Size"
- , "Virtual Size"
- , "Unpack Size"
- , "Total Physical Size"
- , "Volume Index"
- , "SubType"
- , "Short Comment"
- , "Code Page"
- , "Is not archive type"
- , "Physical Size can't be detected"
- , "Zeros Tail Is Allowed"
- , "Tail Size"
- , "Embedded Stub Size"
- , "Link"
- , "Hard Link"
- , "iNode"
- , "Stream ID"
- , "Read-only"
- , "Out Name"
- , "Copy Link"
-};
-
-static const char kEmptyAttribChar = '.';
-
-static const char * const kListing = "Listing archive: ";
-
-static const char * const kString_Files = "files";
-static const char * const kString_Dirs = "folders";
-static const char * const kString_AltStreams = "alternate streams";
-static const char * const kString_Streams = "streams";
-
-static const char * const kError = "ERROR: ";
-
-static void GetAttribString(UInt32 wa, bool isDir, bool allAttribs, char *s)
-{
- if (isDir)
- wa |= FILE_ATTRIBUTE_DIRECTORY;
- if (allAttribs)
- {
- ConvertWinAttribToString(s, wa);
- return;
- }
- s[0] = ((wa & FILE_ATTRIBUTE_DIRECTORY) != 0) ? 'D': kEmptyAttribChar;
- s[1] = ((wa & FILE_ATTRIBUTE_READONLY) != 0) ? 'R': kEmptyAttribChar;
- s[2] = ((wa & FILE_ATTRIBUTE_HIDDEN) != 0) ? 'H': kEmptyAttribChar;
- s[3] = ((wa & FILE_ATTRIBUTE_SYSTEM) != 0) ? 'S': kEmptyAttribChar;
- s[4] = ((wa & FILE_ATTRIBUTE_ARCHIVE) != 0) ? 'A': kEmptyAttribChar;
- s[5] = 0;
-}
-
-enum EAdjustment
-{
- kLeft,
- kCenter,
- kRight
-};
-
-struct CFieldInfo
-{
- PROPID PropID;
- bool IsRawProp;
- UString NameU;
- AString NameA;
- EAdjustment TitleAdjustment;
- EAdjustment TextAdjustment;
- unsigned PrefixSpacesWidth;
- unsigned Width;
-};
-
-struct CFieldInfoInit
-{
- PROPID PropID;
- const char *Name;
- EAdjustment TitleAdjustment;
- EAdjustment TextAdjustment;
- unsigned PrefixSpacesWidth;
- unsigned Width;
-};
-
-static const CFieldInfoInit kStandardFieldTable[] =
-{
- { kpidMTime, " Date Time", kLeft, kLeft, 0, 19 },
- { kpidAttrib, "Attr", kRight, kCenter, 1, 5 },
- { kpidSize, "Size", kRight, kRight, 1, 12 },
- { kpidPackSize, "Compressed", kRight, kRight, 1, 12 },
- { kpidPath, "Name", kLeft, kLeft, 2, 24 }
-};
-
-const unsigned kNumSpacesMax = 32; // it must be larger than max CFieldInfoInit.Width
-static const char *g_Spaces =
-" " ;
-
-static void PrintSpaces(unsigned numSpaces)
-{
- if (numSpaces > 0 && numSpaces <= kNumSpacesMax)
- g_StdOut << g_Spaces + (kNumSpacesMax - numSpaces);
-}
-
-static void PrintSpacesToString(char *dest, unsigned numSpaces)
-{
- unsigned i;
- for (i = 0; i < numSpaces; i++)
- dest[i] = ' ';
- dest[i] = 0;
-}
-
-// extern int g_CodePage;
-
-static void PrintUString(EAdjustment adj, unsigned width, const UString &s, AString &temp)
-{
- /*
- // we don't need multibyte align.
- int codePage = g_CodePage;
- if (codePage == -1)
- codePage = CP_OEMCP;
- if (codePage == CP_UTF8)
- ConvertUnicodeToUTF8(s, temp);
- else
- UnicodeStringToMultiByte2(temp, s, (UINT)codePage);
- */
-
- unsigned numSpaces = 0;
-
- if (width > s.Len())
- {
- numSpaces = width - s.Len();
- unsigned numLeftSpaces = 0;
- switch (adj)
- {
- case kLeft: numLeftSpaces = 0; break;
- case kCenter: numLeftSpaces = numSpaces / 2; break;
- case kRight: numLeftSpaces = numSpaces; break;
- }
- PrintSpaces(numLeftSpaces);
- numSpaces -= numLeftSpaces;
- }
-
- g_StdOut.PrintUString(s, temp);
- PrintSpaces(numSpaces);
-}
-
-static void PrintString(EAdjustment adj, unsigned width, const char *s)
-{
- unsigned numSpaces = 0;
- unsigned len = (unsigned)strlen(s);
-
- if (width > len)
- {
- numSpaces = width - len;
- unsigned numLeftSpaces = 0;
- switch (adj)
- {
- case kLeft: numLeftSpaces = 0; break;
- case kCenter: numLeftSpaces = numSpaces / 2; break;
- case kRight: numLeftSpaces = numSpaces; break;
- }
- PrintSpaces(numLeftSpaces);
- numSpaces -= numLeftSpaces;
- }
-
- g_StdOut << s;
- PrintSpaces(numSpaces);
-}
-
-static void PrintStringToString(char *dest, EAdjustment adj, unsigned width, const char *textString)
-{
- unsigned numSpaces = 0;
- unsigned len = (unsigned)strlen(textString);
-
- if (width > len)
- {
- numSpaces = width - len;
- unsigned numLeftSpaces = 0;
- switch (adj)
- {
- case kLeft: numLeftSpaces = 0; break;
- case kCenter: numLeftSpaces = numSpaces / 2; break;
- case kRight: numLeftSpaces = numSpaces; break;
- }
- PrintSpacesToString(dest, numLeftSpaces);
- dest += numLeftSpaces;
- numSpaces -= numLeftSpaces;
- }
-
- memcpy(dest, textString, len);
- dest += len;
- PrintSpacesToString(dest, numSpaces);
-}
-
-struct CListUInt64Def
-{
- UInt64 Val;
- bool Def;
-
- CListUInt64Def(): Val(0), Def(false) {}
- void Add(UInt64 v) { Val += v; Def = true; }
- void Add(const CListUInt64Def &v) { if (v.Def) Add(v.Val); }
-};
-
-struct CListFileTimeDef
-{
- FILETIME Val;
- bool Def;
-
- CListFileTimeDef(): Def(false) { Val.dwLowDateTime = 0; Val.dwHighDateTime = 0; }
- void Update(const CListFileTimeDef &t)
- {
- if (t.Def && (!Def || CompareFileTime(&Val, &t.Val) < 0))
- {
- Val = t.Val;
- Def = true;
- }
- }
-};
-
-struct CListStat
-{
- CListUInt64Def Size;
- CListUInt64Def PackSize;
- CListFileTimeDef MTime;
- UInt64 NumFiles;
-
- CListStat(): NumFiles(0) {}
- void Update(const CListStat &st)
- {
- Size.Add(st.Size);
- PackSize.Add(st.PackSize);
- MTime.Update(st.MTime);
- NumFiles += st.NumFiles;
- }
- void SetSizeDefIfNoFiles() { if (NumFiles == 0) Size.Def = true; }
-};
-
-struct CListStat2
-{
- CListStat MainFiles;
- CListStat AltStreams;
- UInt64 NumDirs;
-
- CListStat2(): NumDirs(0) {}
-
- void Update(const CListStat2 &st)
- {
- MainFiles.Update(st.MainFiles);
- AltStreams.Update(st.AltStreams);
- NumDirs += st.NumDirs;
- }
- const UInt64 GetNumStreams() const { return MainFiles.NumFiles + AltStreams.NumFiles; }
- CListStat &GetStat(bool altStreamsMode) { return altStreamsMode ? AltStreams : MainFiles; }
-};
-
-class CFieldPrinter
-{
- CObjectVector<CFieldInfo> _fields;
-
- void AddProp(const wchar_t *name, PROPID propID, bool isRawProp);
-public:
- const CArc *Arc;
- bool TechMode;
- UString FilePath;
- AString TempAString;
- UString TempWString;
- bool IsDir;
-
- AString LinesString;
-
- void Clear() { _fields.Clear(); LinesString.Empty(); }
- void Init(const CFieldInfoInit *standardFieldTable, unsigned numItems);
-
- HRESULT AddMainProps(IInArchive *archive);
- HRESULT AddRawProps(IArchiveGetRawProps *getRawProps);
-
- void PrintTitle();
- void PrintTitleLines();
- HRESULT PrintItemInfo(UInt32 index, const CListStat &st);
- void PrintSum(const CListStat &st, UInt64 numDirs, const char *str);
- void PrintSum(const CListStat2 &stat2);
-};
-
-void CFieldPrinter::Init(const CFieldInfoInit *standardFieldTable, unsigned numItems)
-{
- Clear();
- for (unsigned i = 0; i < numItems; i++)
- {
- CFieldInfo &f = _fields.AddNew();
- const CFieldInfoInit &fii = standardFieldTable[i];
- f.PropID = fii.PropID;
- f.IsRawProp = false;
- f.NameA = fii.Name;
- f.TitleAdjustment = fii.TitleAdjustment;
- f.TextAdjustment = fii.TextAdjustment;
- f.PrefixSpacesWidth = fii.PrefixSpacesWidth;
- f.Width = fii.Width;
-
- unsigned k;
- for (k = 0; k < fii.PrefixSpacesWidth; k++)
- LinesString.Add_Space();
- for (k = 0; k < fii.Width; k++)
- LinesString += '-';
- }
-}
-
-static void GetPropName(PROPID propID, const wchar_t *name, AString &nameA, UString &nameU)
-{
- if (propID < ARRAY_SIZE(kPropIdToName))
- {
- nameA = kPropIdToName[propID];
- return;
- }
- if (name)
- nameU = name;
- else
- {
- nameA.Empty();
- nameA.Add_UInt32(propID);
- }
-}
-
-void CFieldPrinter::AddProp(const wchar_t *name, PROPID propID, bool isRawProp)
-{
- CFieldInfo f;
- f.PropID = propID;
- f.IsRawProp = isRawProp;
- GetPropName(propID, name, f.NameA, f.NameU);
- f.NameU += " = ";
- if (!f.NameA.IsEmpty())
- f.NameA += " = ";
- else
- {
- const UString &s = f.NameU;
- AString sA;
- unsigned i;
- for (i = 0; i < s.Len(); i++)
- {
- wchar_t c = s[i];
- if (c >= 0x80)
- break;
- sA += (char)c;
- }
- if (i == s.Len())
- f.NameA = sA;
- }
- _fields.Add(f);
-}
-
-HRESULT CFieldPrinter::AddMainProps(IInArchive *archive)
-{
- UInt32 numProps;
- RINOK(archive->GetNumberOfProperties(&numProps));
- for (UInt32 i = 0; i < numProps; i++)
- {
- CMyComBSTR name;
- PROPID propID;
- VARTYPE vt;
- RINOK(archive->GetPropertyInfo(i, &name, &propID, &vt));
- AddProp(name, propID, false);
- }
- return S_OK;
-}
-
-HRESULT CFieldPrinter::AddRawProps(IArchiveGetRawProps *getRawProps)
-{
- UInt32 numProps;
- RINOK(getRawProps->GetNumRawProps(&numProps));
- for (UInt32 i = 0; i < numProps; i++)
- {
- CMyComBSTR name;
- PROPID propID;
- RINOK(getRawProps->GetRawPropInfo(i, &name, &propID));
- AddProp(name, propID, true);
- }
- return S_OK;
-}
-
-void CFieldPrinter::PrintTitle()
-{
- FOR_VECTOR (i, _fields)
- {
- const CFieldInfo &f = _fields[i];
- PrintSpaces(f.PrefixSpacesWidth);
- PrintString(f.TitleAdjustment, ((f.PropID == kpidPath) ? 0: f.Width), f.NameA);
- }
-}
-
-void CFieldPrinter::PrintTitleLines()
-{
- g_StdOut << LinesString;
-}
-
-static void PrintTime(char *dest, const FILETIME *ft)
-{
- *dest = 0;
- if (ft->dwLowDateTime == 0 && ft->dwHighDateTime == 0)
- return;
- ConvertUtcFileTimeToString(*ft, dest, kTimestampPrintLevel_SEC);
-}
-
-#ifndef _SFX
-
-static inline char GetHex(Byte value)
-{
- return (char)((value < 10) ? ('0' + value) : ('A' + (value - 10)));
-}
-
-static void HexToString(char *dest, const Byte *data, UInt32 size)
-{
- for (UInt32 i = 0; i < size; i++)
- {
- Byte b = data[i];
- dest[0] = GetHex((Byte)((b >> 4) & 0xF));
- dest[1] = GetHex((Byte)(b & 0xF));
- dest += 2;
- }
- *dest = 0;
-}
-
-#endif
-
-#define MY_ENDL endl
-
-HRESULT CFieldPrinter::PrintItemInfo(UInt32 index, const CListStat &st)
-{
- char temp[128];
- size_t tempPos = 0;
-
- bool techMode = this->TechMode;
- /*
- if (techMode)
- {
- g_StdOut << "Index = ";
- g_StdOut << (UInt64)index;
- g_StdOut << endl;
- }
- */
- FOR_VECTOR (i, _fields)
- {
- const CFieldInfo &f = _fields[i];
-
- if (!techMode)
- {
- PrintSpacesToString(temp + tempPos, f.PrefixSpacesWidth);
- tempPos += f.PrefixSpacesWidth;
- }
-
- if (techMode)
- {
- if (!f.NameA.IsEmpty())
- g_StdOut << f.NameA;
- else
- g_StdOut << f.NameU;
- }
-
- if (f.PropID == kpidPath)
- {
- if (!techMode)
- g_StdOut << temp;
- g_StdOut.NormalizePrint_UString(FilePath, TempWString, TempAString);
- if (techMode)
- g_StdOut << MY_ENDL;
- continue;
- }
-
- const unsigned width = f.Width;
-
- if (f.IsRawProp)
- {
- #ifndef _SFX
-
- const void *data;
- UInt32 dataSize;
- UInt32 propType;
- RINOK(Arc->GetRawProps->GetRawProp(index, f.PropID, &data, &dataSize, &propType));
-
- if (dataSize != 0)
- {
- bool needPrint = true;
-
- if (f.PropID == kpidNtSecure)
- {
- if (propType != NPropDataType::kRaw)
- return E_FAIL;
- #ifndef _SFX
- ConvertNtSecureToString((const Byte *)data, dataSize, TempAString);
- g_StdOut << TempAString;
- needPrint = false;
- #endif
- }
- else if (f.PropID == kpidNtReparse)
- {
- UString s;
- if (ConvertNtReparseToString((const Byte *)data, dataSize, s))
- {
- needPrint = false;
- g_StdOut.PrintUString(s, TempAString);
- }
- }
-
- if (needPrint)
- {
- if (propType != NPropDataType::kRaw)
- return E_FAIL;
-
- const UInt32 kMaxDataSize = 64;
-
- if (dataSize > kMaxDataSize)
- {
- g_StdOut << "data:";
- g_StdOut << dataSize;
- }
- else
- {
- char hexStr[kMaxDataSize * 2 + 4];
- HexToString(hexStr, (const Byte *)data, dataSize);
- g_StdOut << hexStr;
- }
- }
- }
-
- #endif
- }
- else
- {
- CPropVariant prop;
- switch (f.PropID)
- {
- case kpidSize: if (st.Size.Def) prop = st.Size.Val; break;
- case kpidPackSize: if (st.PackSize.Def) prop = st.PackSize.Val; break;
- case kpidMTime: if (st.MTime.Def) prop = st.MTime.Val; break;
- default:
- RINOK(Arc->Archive->GetProperty(index, f.PropID, &prop));
- }
- if (f.PropID == kpidAttrib && (prop.vt == VT_EMPTY || prop.vt == VT_UI4))
- {
- GetAttribString((prop.vt == VT_EMPTY) ? 0 : prop.ulVal, IsDir, techMode, temp + tempPos);
- if (techMode)
- g_StdOut << temp + tempPos;
- else
- tempPos += strlen(temp + tempPos);
- }
- else if (prop.vt == VT_EMPTY)
- {
- if (!techMode)
- {
- PrintSpacesToString(temp + tempPos, width);
- tempPos += width;
- }
- }
- else if (prop.vt == VT_FILETIME)
- {
- PrintTime(temp + tempPos, &prop.filetime);
- if (techMode)
- g_StdOut << temp + tempPos;
- else
- {
- size_t len = strlen(temp + tempPos);
- tempPos += len;
- if (len < (unsigned)f.Width)
- {
- len = f.Width - len;
- PrintSpacesToString(temp + tempPos, (unsigned)len);
- tempPos += len;
- }
- }
- }
- else if (prop.vt == VT_BSTR)
- {
- TempWString.SetFromBstr(prop.bstrVal);
- // do we need multi-line support here ?
- g_StdOut.Normalize_UString(TempWString);
- if (techMode)
- {
- g_StdOut.PrintUString(TempWString, TempAString);
- }
- else
- PrintUString(f.TextAdjustment, width, TempWString, TempAString);
- }
- else
- {
- char s[64];
- ConvertPropertyToShortString2(s, prop, f.PropID);
- if (techMode)
- g_StdOut << s;
- else
- {
- PrintStringToString(temp + tempPos, f.TextAdjustment, width, s);
- tempPos += strlen(temp + tempPos);
- }
- }
- }
- if (techMode)
- g_StdOut << MY_ENDL;
- }
- g_StdOut << MY_ENDL;
- return S_OK;
-}
-
-static void PrintNumber(EAdjustment adj, unsigned width, const CListUInt64Def &value)
-{
- char s[32];
- s[0] = 0;
- if (value.Def)
- ConvertUInt64ToString(value.Val, s);
- PrintString(adj, width, s);
-}
-
-void Print_UInt64_and_String(AString &s, UInt64 val, const char *name);
-
-void CFieldPrinter::PrintSum(const CListStat &st, UInt64 numDirs, const char *str)
-{
- FOR_VECTOR (i, _fields)
- {
- const CFieldInfo &f = _fields[i];
- PrintSpaces(f.PrefixSpacesWidth);
- if (f.PropID == kpidSize)
- PrintNumber(f.TextAdjustment, f.Width, st.Size);
- else if (f.PropID == kpidPackSize)
- PrintNumber(f.TextAdjustment, f.Width, st.PackSize);
- else if (f.PropID == kpidMTime)
- {
- char s[64];
- s[0] = 0;
- if (st.MTime.Def)
- PrintTime(s, &st.MTime.Val);
- PrintString(f.TextAdjustment, f.Width, s);
- }
- else if (f.PropID == kpidPath)
- {
- AString s;
- Print_UInt64_and_String(s, st.NumFiles, str);
- if (numDirs != 0)
- {
- s += ", ";
- Print_UInt64_and_String(s, numDirs, kString_Dirs);
- }
- PrintString(f.TextAdjustment, 0, s);
- }
- else
- PrintString(f.TextAdjustment, f.Width, "");
- }
- g_StdOut << endl;
-}
-
-void CFieldPrinter::PrintSum(const CListStat2 &stat2)
-{
- PrintSum(stat2.MainFiles, stat2.NumDirs, kString_Files);
- if (stat2.AltStreams.NumFiles != 0)
- {
- PrintSum(stat2.AltStreams, 0, kString_AltStreams);;
- CListStat st = stat2.MainFiles;
- st.Update(stat2.AltStreams);
- PrintSum(st, 0, kString_Streams);
- }
-}
-
-static HRESULT GetUInt64Value(IInArchive *archive, UInt32 index, PROPID propID, CListUInt64Def &value)
-{
- value.Val = 0;
- value.Def = false;
- CPropVariant prop;
- RINOK(archive->GetProperty(index, propID, &prop));
- value.Def = ConvertPropVariantToUInt64(prop, value.Val);
- return S_OK;
-}
-
-static HRESULT GetItemMTime(IInArchive *archive, UInt32 index, CListFileTimeDef &t)
-{
- t.Val.dwLowDateTime = 0;
- t.Val.dwHighDateTime = 0;
- t.Def = false;
- CPropVariant prop;
- RINOK(archive->GetProperty(index, kpidMTime, &prop));
- if (prop.vt == VT_FILETIME)
- {
- t.Val = prop.filetime;
- t.Def = true;
- }
- else if (prop.vt != VT_EMPTY)
- return E_FAIL;
- return S_OK;
-}
-
-static void PrintPropNameAndNumber(CStdOutStream &so, const char *name, UInt64 val)
-{
- so << name << ": " << val << endl;
-}
-
-static void PrintPropName_and_Eq(CStdOutStream &so, PROPID propID)
-{
- const char *s;
- char temp[16];
- if (propID < ARRAY_SIZE(kPropIdToName))
- s = kPropIdToName[propID];
- else
- {
- ConvertUInt32ToString(propID, temp);
- s = temp;
- }
- so << s << " = ";
-}
-
-static void PrintPropNameAndNumber(CStdOutStream &so, PROPID propID, UInt64 val)
-{
- PrintPropName_and_Eq(so, propID);
- so << val << endl;
-}
-
-static void PrintPropNameAndNumber_Signed(CStdOutStream &so, PROPID propID, Int64 val)
-{
- PrintPropName_and_Eq(so, propID);
- so << val << endl;
-}
-
-
-static void UString_Replace_CRLF_to_LF(UString &s)
-{
- // s.Replace(L"\r\n", L"\n");
- wchar_t *src = s.GetBuf();
- wchar_t *dest = src;
- for (;;)
- {
- wchar_t c = *src++;
- if (c == 0)
- break;
- if (c == '\r' && *src == '\n')
- {
- src++;
- c = '\n';
- }
- *dest++ = c;
- }
- s.ReleaseBuf_SetEnd((unsigned)(dest - s.GetBuf()));
-}
-
-
-static void PrintPropVal_MultiLine(CStdOutStream &so, const wchar_t *val)
-{
- UString s = val;
- if (s.Find(L'\n') >= 0)
- {
- so << endl;
- so << "{";
- so << endl;
- UString_Replace_CRLF_to_LF(s);
- so.Normalize_UString__LF_Allowed(s);
- so << s;
- so << endl;
- so << "}";
- }
- else
- {
- so.Normalize_UString(s);
- so << s;
- }
- so << endl;
-}
-
-
-static void PrintPropPair(CStdOutStream &so, const char *name, const wchar_t *val, bool multiLine)
-{
- so << name << " = ";
- if (multiLine)
- {
- PrintPropVal_MultiLine(so, val);
- return;
- }
- UString s = val;
- so.Normalize_UString(s);
- so << s;
- so << endl;
-}
-
-
-static void PrintPropertyPair2(CStdOutStream &so, PROPID propID, const wchar_t *name, const CPropVariant &prop)
-{
- UString s;
- ConvertPropertyToString2(s, prop, propID);
- if (!s.IsEmpty())
- {
- AString nameA;
- UString nameU;
- GetPropName(propID, name, nameA, nameU);
- if (!nameA.IsEmpty())
- so << nameA;
- else
- so << nameU;
- so << " = ";
- PrintPropVal_MultiLine(so, s);
- }
-}
-
-static HRESULT PrintArcProp(CStdOutStream &so, IInArchive *archive, PROPID propID, const wchar_t *name)
-{
- CPropVariant prop;
- RINOK(archive->GetArchiveProperty(propID, &prop));
- PrintPropertyPair2(so, propID, name, prop);
- return S_OK;
-}
-
-static void PrintArcTypeError(CStdOutStream &so, const UString &type, bool isWarning)
-{
- so << "Open " << (isWarning ? "WARNING" : "ERROR")
- << ": Can not open the file as ["
- << type
- << "] archive"
- << endl;
-}
-
-int Find_FileName_InSortedVector(const UStringVector &fileName, const UString& name);
-
-void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags);
-
-static void ErrorInfo_Print(CStdOutStream &so, const CArcErrorInfo &er)
-{
- PrintErrorFlags(so, "ERRORS:", er.GetErrorFlags());
- if (!er.ErrorMessage.IsEmpty())
- PrintPropPair(so, "ERROR", er.ErrorMessage, true);
-
- PrintErrorFlags(so, "WARNINGS:", er.GetWarningFlags());
- if (!er.WarningMessage.IsEmpty())
- PrintPropPair(so, "WARNING", er.WarningMessage, true);
-}
-
-HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink)
-{
- FOR_VECTOR (r, arcLink.Arcs)
- {
- const CArc &arc = arcLink.Arcs[r];
- const CArcErrorInfo &er = arc.ErrorInfo;
-
- so << "--\n";
- PrintPropPair(so, "Path", arc.Path, false);
- if (er.ErrorFormatIndex >= 0)
- {
- if (er.ErrorFormatIndex == arc.FormatIndex)
- so << "Warning: The archive is open with offset" << endl;
- else
- PrintArcTypeError(so, codecs->GetFormatNamePtr(er.ErrorFormatIndex), true);
- }
- PrintPropPair(so, "Type", codecs->GetFormatNamePtr(arc.FormatIndex), false);
-
- ErrorInfo_Print(so, er);
-
- Int64 offset = arc.GetGlobalOffset();
- if (offset != 0)
- PrintPropNameAndNumber_Signed(so, kpidOffset, offset);
- IInArchive *archive = arc.Archive;
- RINOK(PrintArcProp(so, archive, kpidPhySize, NULL));
- if (er.TailSize != 0)
- PrintPropNameAndNumber(so, kpidTailSize, er.TailSize);
- {
- UInt32 numProps;
- RINOK(archive->GetNumberOfArchiveProperties(&numProps));
-
- for (UInt32 j = 0; j < numProps; j++)
- {
- CMyComBSTR name;
- PROPID propID;
- VARTYPE vt;
- RINOK(archive->GetArchivePropertyInfo(j, &name, &propID, &vt));
- RINOK(PrintArcProp(so, archive, propID, name));
- }
- }
-
- if (r != arcLink.Arcs.Size() - 1)
- {
- UInt32 numProps;
- so << "----\n";
- if (archive->GetNumberOfProperties(&numProps) == S_OK)
- {
- UInt32 mainIndex = arcLink.Arcs[r + 1].SubfileIndex;
- for (UInt32 j = 0; j < numProps; j++)
- {
- CMyComBSTR name;
- PROPID propID;
- VARTYPE vt;
- RINOK(archive->GetPropertyInfo(j, &name, &propID, &vt));
- CPropVariant prop;
- RINOK(archive->GetProperty(mainIndex, propID, &prop));
- PrintPropertyPair2(so, propID, name, prop);
- }
- }
- }
- }
- return S_OK;
-}
-
-HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink)
-{
- #ifndef _NO_CRYPTO
- if (arcLink.PasswordWasAsked)
- so << "Can not open encrypted archive. Wrong password?";
- else
- #endif
- {
- if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
- {
- so.NormalizePrint_UString(arcLink.NonOpen_ArcPath);
- so << endl;
- PrintArcTypeError(so, codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false);
- }
- else
- so << "Can not open the file as archive";
- }
-
- so << endl;
- so << endl;
- ErrorInfo_Print(so, arcLink.NonOpen_ErrorInfo);
-
- return S_OK;
-}
-
-bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item);
-
-HRESULT ListArchives(CCodecs *codecs,
- const CObjectVector<COpenType> &types,
- const CIntVector &excludedFormats,
- bool stdInMode,
- UStringVector &arcPaths, UStringVector &arcPathsFull,
- bool processAltStreams, bool showAltStreams,
- const NWildcard::CCensorNode &wildcardCensor,
- bool enableHeaders, bool techMode,
- #ifndef _NO_CRYPTO
- bool &passwordEnabled, UString &password,
- #endif
- #ifndef _SFX
- const CObjectVector<CProperty> *props,
- #endif
- UInt64 &numErrors,
- UInt64 &numWarnings)
-{
- bool allFilesAreAllowed = wildcardCensor.AreAllAllowed();
-
- numErrors = 0;
- numWarnings = 0;
-
- CFieldPrinter fp;
- if (!techMode)
- fp.Init(kStandardFieldTable, ARRAY_SIZE(kStandardFieldTable));
-
- CListStat2 stat2total;
-
- CBoolArr skipArcs(arcPaths.Size());
- unsigned arcIndex;
- for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++)
- skipArcs[arcIndex] = false;
- UInt64 numVolumes = 0;
- UInt64 numArcs = 0;
- UInt64 totalArcSizes = 0;
-
- HRESULT lastError = 0;
-
- for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++)
- {
- if (skipArcs[arcIndex])
- continue;
- const UString &arcPath = arcPaths[arcIndex];
- UInt64 arcPackSize = 0;
-
- if (!stdInMode)
- {
- NFile::NFind::CFileInfo fi;
- if (!fi.Find(us2fs(arcPath)))
- {
- DWORD errorCode = GetLastError();
- if (errorCode == 0)
- errorCode = ERROR_FILE_NOT_FOUND;
- lastError = HRESULT_FROM_WIN32(lastError);;
- g_StdOut.Flush();
- if (g_ErrStream)
- {
- *g_ErrStream << endl << kError << NError::MyFormatMessage(errorCode) << endl;
- g_ErrStream->NormalizePrint_UString(arcPath);
- *g_ErrStream << endl << endl;
- }
- numErrors++;
- continue;
- }
- if (fi.IsDir())
- {
- g_StdOut.Flush();
- if (g_ErrStream)
- {
- *g_ErrStream << endl << kError;
- g_ErrStream->NormalizePrint_UString(arcPath);
- *g_ErrStream << " is not a file" << endl << endl;
- }
- numErrors++;
- continue;
- }
- arcPackSize = fi.Size;
- totalArcSizes += arcPackSize;
- }
-
- CArchiveLink arcLink;
-
- COpenCallbackConsole openCallback;
- openCallback.Init(&g_StdOut, g_ErrStream, NULL);
-
- #ifndef _NO_CRYPTO
-
- openCallback.PasswordIsDefined = passwordEnabled;
- openCallback.Password = password;
-
- #endif
-
- /*
- CObjectVector<COptionalOpenProperties> optPropsVector;
- COptionalOpenProperties &optProps = optPropsVector.AddNew();
- optProps.Props = *props;
- */
-
- COpenOptions options;
- #ifndef _SFX
- options.props = props;
- #endif
- options.codecs = codecs;
- options.types = &types;
- options.excludedFormats = &excludedFormats;
- options.stdInMode = stdInMode;
- options.stream = NULL;
- options.filePath = arcPath;
-
- if (enableHeaders)
- {
- g_StdOut << endl << kListing;
- g_StdOut.NormalizePrint_UString(arcPath);
- g_StdOut << endl << endl;
- }
-
- HRESULT result = arcLink.Open_Strict(options, &openCallback);
-
- if (result != S_OK)
- {
- if (result == E_ABORT)
- return result;
- if (result != S_FALSE)
- lastError = result;
- g_StdOut.Flush();
- if (g_ErrStream)
- {
- *g_ErrStream << endl << kError;
- g_ErrStream->NormalizePrint_UString(arcPath);
- *g_ErrStream << " : ";
- if (result == S_FALSE)
- {
- Print_OpenArchive_Error(*g_ErrStream, codecs, arcLink);
- }
- else
- {
- *g_ErrStream << "opening : ";
- if (result == E_OUTOFMEMORY)
- *g_ErrStream << "Can't allocate required memory";
- else
- *g_ErrStream << NError::MyFormatMessage(result);
- }
- *g_ErrStream << endl;
- }
- numErrors++;
- continue;
- }
-
- {
- FOR_VECTOR (r, arcLink.Arcs)
- {
- const CArcErrorInfo &arc = arcLink.Arcs[r].ErrorInfo;
- if (!arc.WarningMessage.IsEmpty())
- numWarnings++;
- if (arc.AreThereWarnings())
- numWarnings++;
- if (arc.ErrorFormatIndex >= 0)
- numWarnings++;
- if (arc.AreThereErrors())
- {
- numErrors++;
- // break;
- }
- if (!arc.ErrorMessage.IsEmpty())
- numErrors++;
- }
- }
-
- numArcs++;
- numVolumes++;
-
- if (!stdInMode)
- {
- numVolumes += arcLink.VolumePaths.Size();
- totalArcSizes += arcLink.VolumesSize;
- FOR_VECTOR (v, arcLink.VolumePaths)
- {
- int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]);
- if (index >= 0 && (unsigned)index > arcIndex)
- skipArcs[(unsigned)index] = true;
- }
- }
-
-
- if (enableHeaders)
- {
- RINOK(Print_OpenArchive_Props(g_StdOut, codecs, arcLink));
-
- g_StdOut << endl;
- if (techMode)
- g_StdOut << "----------\n";
- }
-
- if (enableHeaders && !techMode)
- {
- fp.PrintTitle();
- g_StdOut << endl;
- fp.PrintTitleLines();
- g_StdOut << endl;
- }
-
- const CArc &arc = arcLink.Arcs.Back();
- fp.Arc = &arc;
- fp.TechMode = techMode;
- IInArchive *archive = arc.Archive;
- if (techMode)
- {
- fp.Clear();
- RINOK(fp.AddMainProps(archive));
- if (arc.GetRawProps)
- {
- RINOK(fp.AddRawProps(arc.GetRawProps));
- }
- }
-
- CListStat2 stat2;
-
- UInt32 numItems;
- RINOK(archive->GetNumberOfItems(&numItems));
-
- CReadArcItem item;
- UStringVector pathParts;
-
- for (UInt32 i = 0; i < numItems; i++)
- {
- if (NConsoleClose::TestBreakSignal())
- return E_ABORT;
-
- HRESULT res = arc.GetItemPath2(i, fp.FilePath);
-
- if (stdInMode && res == E_INVALIDARG)
- break;
- RINOK(res);
-
- if (arc.Ask_Aux)
- {
- bool isAux;
- RINOK(Archive_IsItem_Aux(archive, i, isAux));
- if (isAux)
- continue;
- }
-
- bool isAltStream = false;
- if (arc.Ask_AltStream)
- {
- RINOK(Archive_IsItem_AltStream(archive, i, isAltStream));
- if (isAltStream && !processAltStreams)
- continue;
- }
-
- RINOK(Archive_IsItem_Dir(archive, i, fp.IsDir));
-
- if (!allFilesAreAllowed)
- {
- if (isAltStream)
- {
- RINOK(arc.GetItem(i, item));
- if (!CensorNode_CheckPath(wildcardCensor, item))
- continue;
- }
- else
- {
- SplitPathToParts(fp.FilePath, pathParts);;
- bool include;
- if (!wildcardCensor.CheckPathVect(pathParts, !fp.IsDir, include))
- continue;
- if (!include)
- continue;
- }
- }
-
- CListStat st;
-
- RINOK(GetUInt64Value(archive, i, kpidSize, st.Size));
- RINOK(GetUInt64Value(archive, i, kpidPackSize, st.PackSize));
- RINOK(GetItemMTime(archive, i, st.MTime));
-
- if (fp.IsDir)
- stat2.NumDirs++;
- else
- st.NumFiles = 1;
- stat2.GetStat(isAltStream).Update(st);
-
- if (isAltStream && !showAltStreams)
- continue;
- RINOK(fp.PrintItemInfo(i, st));
- }
-
- UInt64 numStreams = stat2.GetNumStreams();
- if (!stdInMode
- && !stat2.MainFiles.PackSize.Def
- && !stat2.AltStreams.PackSize.Def)
- {
- if (arcLink.VolumePaths.Size() != 0)
- arcPackSize += arcLink.VolumesSize;
- stat2.MainFiles.PackSize.Add((numStreams == 0) ? 0 : arcPackSize);
- }
-
- stat2.MainFiles.SetSizeDefIfNoFiles();
- stat2.AltStreams.SetSizeDefIfNoFiles();
-
- if (enableHeaders && !techMode)
- {
- fp.PrintTitleLines();
- g_StdOut << endl;
- fp.PrintSum(stat2);
- }
-
- if (enableHeaders)
- {
- if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
- {
- g_StdOut << "----------\n";
- PrintPropPair(g_StdOut, "Path", arcLink.NonOpen_ArcPath, false);
- PrintArcTypeError(g_StdOut, codecs->Formats[arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false);
- }
- }
-
- stat2total.Update(stat2);
-
- g_StdOut.Flush();
- }
-
- if (enableHeaders && !techMode && (arcPaths.Size() > 1 || numVolumes > 1))
- {
- g_StdOut << endl;
- fp.PrintTitleLines();
- g_StdOut << endl;
- fp.PrintSum(stat2total);
- g_StdOut << endl;
- PrintPropNameAndNumber(g_StdOut, "Archives", numArcs);
- PrintPropNameAndNumber(g_StdOut, "Volumes", numVolumes);
- PrintPropNameAndNumber(g_StdOut, "Total archives size", totalArcSizes);
- }
-
- if (numErrors == 1 && lastError != 0)
- return lastError;
-
- return S_OK;
-}
+// List.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/MyCom.h"
+#include "../../../Common/StdOutStream.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/UTFConvert.h"
+
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/PropVariantConv.h"
+
+#include "../Common/OpenArchive.h"
+#include "../Common/PropIDUtils.h"
+
+#include "ConsoleClose.h"
+#include "List.h"
+#include "OpenCallbackConsole.h"
+
+using namespace NWindows;
+using namespace NCOM;
+
+extern CStdOutStream *g_StdStream;
+extern CStdOutStream *g_ErrStream;
+
+static const char * const kPropIdToName[] =
+{
+ "0"
+ , "1"
+ , "2"
+ , "Path"
+ , "Name"
+ , "Extension"
+ , "Folder"
+ , "Size"
+ , "Packed Size"
+ , "Attributes"
+ , "Created"
+ , "Accessed"
+ , "Modified"
+ , "Solid"
+ , "Commented"
+ , "Encrypted"
+ , "Split Before"
+ , "Split After"
+ , "Dictionary Size"
+ , "CRC"
+ , "Type"
+ , "Anti"
+ , "Method"
+ , "Host OS"
+ , "File System"
+ , "User"
+ , "Group"
+ , "Block"
+ , "Comment"
+ , "Position"
+ , "Path Prefix"
+ , "Folders"
+ , "Files"
+ , "Version"
+ , "Volume"
+ , "Multivolume"
+ , "Offset"
+ , "Links"
+ , "Blocks"
+ , "Volumes"
+ , "Time Type"
+ , "64-bit"
+ , "Big-endian"
+ , "CPU"
+ , "Physical Size"
+ , "Headers Size"
+ , "Checksum"
+ , "Characteristics"
+ , "Virtual Address"
+ , "ID"
+ , "Short Name"
+ , "Creator Application"
+ , "Sector Size"
+ , "Mode"
+ , "Symbolic Link"
+ , "Error"
+ , "Total Size"
+ , "Free Space"
+ , "Cluster Size"
+ , "Label"
+ , "Local Name"
+ , "Provider"
+ , "NT Security"
+ , "Alternate Stream"
+ , "Aux"
+ , "Deleted"
+ , "Tree"
+ , "SHA-1"
+ , "SHA-256"
+ , "Error Type"
+ , "Errors"
+ , "Errors"
+ , "Warnings"
+ , "Warning"
+ , "Streams"
+ , "Alternate Streams"
+ , "Alternate Streams Size"
+ , "Virtual Size"
+ , "Unpack Size"
+ , "Total Physical Size"
+ , "Volume Index"
+ , "SubType"
+ , "Short Comment"
+ , "Code Page"
+ , "Is not archive type"
+ , "Physical Size can't be detected"
+ , "Zeros Tail Is Allowed"
+ , "Tail Size"
+ , "Embedded Stub Size"
+ , "Link"
+ , "Hard Link"
+ , "iNode"
+ , "Stream ID"
+ , "Read-only"
+ , "Out Name"
+ , "Copy Link"
+ , "ArcFileName"
+ , "IsHash"
+ , "Metadata Changed"
+ , "User ID"
+ , "Group ID"
+ , "Device Major"
+ , "Device Minor"
+ , "Dev Major"
+ , "Dev Minor"
+};
+
+static const char kEmptyAttribChar = '.';
+
+static const char * const kListing = "Listing archive: ";
+
+static const char * const kString_Files = "files";
+static const char * const kString_Dirs = "folders";
+static const char * const kString_AltStreams = "alternate streams";
+static const char * const kString_Streams = "streams";
+
+static const char * const kError = "ERROR: ";
+
+static void GetAttribString(UInt32 wa, bool isDir, bool allAttribs, char *s)
+{
+ if (isDir)
+ wa |= FILE_ATTRIBUTE_DIRECTORY;
+ if (allAttribs)
+ {
+ ConvertWinAttribToString(s, wa);
+ return;
+ }
+ s[0] = ((wa & FILE_ATTRIBUTE_DIRECTORY) != 0) ? 'D': kEmptyAttribChar;
+ s[1] = ((wa & FILE_ATTRIBUTE_READONLY) != 0) ? 'R': kEmptyAttribChar;
+ s[2] = ((wa & FILE_ATTRIBUTE_HIDDEN) != 0) ? 'H': kEmptyAttribChar;
+ s[3] = ((wa & FILE_ATTRIBUTE_SYSTEM) != 0) ? 'S': kEmptyAttribChar;
+ s[4] = ((wa & FILE_ATTRIBUTE_ARCHIVE) != 0) ? 'A': kEmptyAttribChar;
+ s[5] = 0;
+}
+
+enum EAdjustment
+{
+ kLeft,
+ kCenter,
+ kRight
+};
+
+struct CFieldInfo
+{
+ PROPID PropID;
+ bool IsRawProp;
+ UString NameU;
+ AString NameA;
+ EAdjustment TitleAdjustment;
+ EAdjustment TextAdjustment;
+ unsigned PrefixSpacesWidth;
+ unsigned Width;
+};
+
+struct CFieldInfoInit
+{
+ PROPID PropID;
+ const char *Name;
+ EAdjustment TitleAdjustment;
+ EAdjustment TextAdjustment;
+ unsigned PrefixSpacesWidth;
+ unsigned Width;
+};
+
+static const CFieldInfoInit kStandardFieldTable[] =
+{
+ { kpidMTime, " Date Time", kLeft, kLeft, 0, 19 },
+ { kpidAttrib, "Attr", kRight, kCenter, 1, 5 },
+ { kpidSize, "Size", kRight, kRight, 1, 12 },
+ { kpidPackSize, "Compressed", kRight, kRight, 1, 12 },
+ { kpidPath, "Name", kLeft, kLeft, 2, 24 }
+};
+
+const unsigned kNumSpacesMax = 32; // it must be larger than max CFieldInfoInit.Width
+static const char *g_Spaces =
+" " ;
+
+static void PrintSpaces(unsigned numSpaces)
+{
+ if (numSpaces > 0 && numSpaces <= kNumSpacesMax)
+ g_StdOut << g_Spaces + (kNumSpacesMax - numSpaces);
+}
+
+static void PrintSpacesToString(char *dest, unsigned numSpaces)
+{
+ unsigned i;
+ for (i = 0; i < numSpaces; i++)
+ dest[i] = ' ';
+ dest[i] = 0;
+}
+
+// extern int g_CodePage;
+
+static void PrintUString(EAdjustment adj, unsigned width, const UString &s, AString &temp)
+{
+ /*
+ // we don't need multibyte align.
+ int codePage = g_CodePage;
+ if (codePage == -1)
+ codePage = CP_OEMCP;
+ if (codePage == CP_UTF8)
+ ConvertUnicodeToUTF8(s, temp);
+ else
+ UnicodeStringToMultiByte2(temp, s, (UINT)codePage);
+ */
+
+ unsigned numSpaces = 0;
+
+ if (width > s.Len())
+ {
+ numSpaces = width - s.Len();
+ unsigned numLeftSpaces = 0;
+ switch (adj)
+ {
+ case kLeft: numLeftSpaces = 0; break;
+ case kCenter: numLeftSpaces = numSpaces / 2; break;
+ case kRight: numLeftSpaces = numSpaces; break;
+ }
+ PrintSpaces(numLeftSpaces);
+ numSpaces -= numLeftSpaces;
+ }
+
+ g_StdOut.PrintUString(s, temp);
+ PrintSpaces(numSpaces);
+}
+
+static void PrintString(EAdjustment adj, unsigned width, const char *s)
+{
+ unsigned numSpaces = 0;
+ unsigned len = (unsigned)strlen(s);
+
+ if (width > len)
+ {
+ numSpaces = width - len;
+ unsigned numLeftSpaces = 0;
+ switch (adj)
+ {
+ case kLeft: numLeftSpaces = 0; break;
+ case kCenter: numLeftSpaces = numSpaces / 2; break;
+ case kRight: numLeftSpaces = numSpaces; break;
+ }
+ PrintSpaces(numLeftSpaces);
+ numSpaces -= numLeftSpaces;
+ }
+
+ g_StdOut << s;
+ PrintSpaces(numSpaces);
+}
+
+static void PrintStringToString(char *dest, EAdjustment adj, unsigned width, const char *textString)
+{
+ unsigned numSpaces = 0;
+ unsigned len = (unsigned)strlen(textString);
+
+ if (width > len)
+ {
+ numSpaces = width - len;
+ unsigned numLeftSpaces = 0;
+ switch (adj)
+ {
+ case kLeft: numLeftSpaces = 0; break;
+ case kCenter: numLeftSpaces = numSpaces / 2; break;
+ case kRight: numLeftSpaces = numSpaces; break;
+ }
+ PrintSpacesToString(dest, numLeftSpaces);
+ dest += numLeftSpaces;
+ numSpaces -= numLeftSpaces;
+ }
+
+ memcpy(dest, textString, len);
+ dest += len;
+ PrintSpacesToString(dest, numSpaces);
+}
+
+struct CListUInt64Def
+{
+ UInt64 Val;
+ bool Def;
+
+ CListUInt64Def(): Val(0), Def(false) {}
+ void Add(UInt64 v) { Val += v; Def = true; }
+ void Add(const CListUInt64Def &v) { if (v.Def) Add(v.Val); }
+};
+
+
+struct CListFileTimeDef: public CArcTime
+{
+ void Update(const CListFileTimeDef &t)
+ {
+ if (t.Def && (!Def || CompareWith(t) < 0))
+ (*this) = t;
+ }
+};
+
+
+
+struct CListStat
+{
+ CListUInt64Def Size;
+ CListUInt64Def PackSize;
+ CListFileTimeDef MTime;
+ UInt64 NumFiles;
+
+ CListStat(): NumFiles(0) {}
+ void Update(const CListStat &st)
+ {
+ Size.Add(st.Size);
+ PackSize.Add(st.PackSize);
+ MTime.Update(st.MTime);
+ NumFiles += st.NumFiles;
+ }
+ void SetSizeDefIfNoFiles() { if (NumFiles == 0) Size.Def = true; }
+};
+
+struct CListStat2
+{
+ CListStat MainFiles;
+ CListStat AltStreams;
+ UInt64 NumDirs;
+
+ CListStat2(): NumDirs(0) {}
+
+ void Update(const CListStat2 &st)
+ {
+ MainFiles.Update(st.MainFiles);
+ AltStreams.Update(st.AltStreams);
+ NumDirs += st.NumDirs;
+ }
+ UInt64 GetNumStreams() const { return MainFiles.NumFiles + AltStreams.NumFiles; }
+ CListStat &GetStat(bool altStreamsMode) { return altStreamsMode ? AltStreams : MainFiles; }
+};
+
+class CFieldPrinter
+{
+ CObjectVector<CFieldInfo> _fields;
+
+ void AddProp(const wchar_t *name, PROPID propID, bool isRawProp);
+public:
+ const CArc *Arc;
+ bool TechMode;
+ UString FilePath;
+ AString TempAString;
+ UString TempWString;
+ bool IsDir;
+
+ AString LinesString;
+
+ void Clear() { _fields.Clear(); LinesString.Empty(); }
+ void Init(const CFieldInfoInit *standardFieldTable, unsigned numItems);
+
+ HRESULT AddMainProps(IInArchive *archive);
+ HRESULT AddRawProps(IArchiveGetRawProps *getRawProps);
+
+ void PrintTitle();
+ void PrintTitleLines();
+ HRESULT PrintItemInfo(UInt32 index, const CListStat &st);
+ void PrintSum(const CListStat &st, UInt64 numDirs, const char *str);
+ void PrintSum(const CListStat2 &stat2);
+};
+
+void CFieldPrinter::Init(const CFieldInfoInit *standardFieldTable, unsigned numItems)
+{
+ Clear();
+ for (unsigned i = 0; i < numItems; i++)
+ {
+ CFieldInfo &f = _fields.AddNew();
+ const CFieldInfoInit &fii = standardFieldTable[i];
+ f.PropID = fii.PropID;
+ f.IsRawProp = false;
+ f.NameA = fii.Name;
+ f.TitleAdjustment = fii.TitleAdjustment;
+ f.TextAdjustment = fii.TextAdjustment;
+ f.PrefixSpacesWidth = fii.PrefixSpacesWidth;
+ f.Width = fii.Width;
+
+ unsigned k;
+ for (k = 0; k < fii.PrefixSpacesWidth; k++)
+ LinesString.Add_Space();
+ for (k = 0; k < fii.Width; k++)
+ LinesString.Add_Minus();
+ }
+}
+
+static void GetPropName(PROPID propID, const wchar_t *name, AString &nameA, UString &nameU)
+{
+ if (propID < Z7_ARRAY_SIZE(kPropIdToName))
+ {
+ nameA = kPropIdToName[propID];
+ return;
+ }
+ if (name)
+ nameU = name;
+ else
+ {
+ nameA.Empty();
+ nameA.Add_UInt32(propID);
+ }
+}
+
+void CFieldPrinter::AddProp(const wchar_t *name, PROPID propID, bool isRawProp)
+{
+ CFieldInfo f;
+ f.PropID = propID;
+ f.IsRawProp = isRawProp;
+ GetPropName(propID, name, f.NameA, f.NameU);
+ f.NameU += " = ";
+ if (!f.NameA.IsEmpty())
+ f.NameA += " = ";
+ else
+ {
+ const UString &s = f.NameU;
+ AString sA;
+ unsigned i;
+ for (i = 0; i < s.Len(); i++)
+ {
+ wchar_t c = s[i];
+ if (c >= 0x80)
+ break;
+ sA += (char)c;
+ }
+ if (i == s.Len())
+ f.NameA = sA;
+ }
+ _fields.Add(f);
+}
+
+HRESULT CFieldPrinter::AddMainProps(IInArchive *archive)
+{
+ UInt32 numProps;
+ RINOK(archive->GetNumberOfProperties(&numProps))
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE vt;
+ RINOK(archive->GetPropertyInfo(i, &name, &propID, &vt))
+ AddProp(name, propID, false);
+ }
+ return S_OK;
+}
+
+HRESULT CFieldPrinter::AddRawProps(IArchiveGetRawProps *getRawProps)
+{
+ UInt32 numProps;
+ RINOK(getRawProps->GetNumRawProps(&numProps))
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ RINOK(getRawProps->GetRawPropInfo(i, &name, &propID))
+ AddProp(name, propID, true);
+ }
+ return S_OK;
+}
+
+void CFieldPrinter::PrintTitle()
+{
+ FOR_VECTOR (i, _fields)
+ {
+ const CFieldInfo &f = _fields[i];
+ PrintSpaces(f.PrefixSpacesWidth);
+ PrintString(f.TitleAdjustment, ((f.PropID == kpidPath) ? 0: f.Width), f.NameA);
+ }
+}
+
+void CFieldPrinter::PrintTitleLines()
+{
+ g_StdOut << LinesString;
+}
+
+static void PrintTime(char *dest, const CListFileTimeDef &t, bool showNS)
+{
+ *dest = 0;
+ if (t.IsZero())
+ return;
+ int prec = kTimestampPrintLevel_SEC;
+ if (showNS)
+ {
+ prec = kTimestampPrintLevel_NTFS;
+ if (t.Prec != 0)
+ {
+ prec = t.GetNumDigits();
+ if (prec < kTimestampPrintLevel_DAY)
+ prec = kTimestampPrintLevel_NTFS;
+ }
+ }
+
+ ConvertUtcFileTimeToString2(t.FT, t.Ns100, dest, prec);
+}
+
+#ifndef Z7_SFX
+
+static inline char GetHex(Byte value)
+{
+ return (char)((value < 10) ? ('0' + value) : ('a' + (value - 10)));
+}
+
+static void HexToString(char *dest, const Byte *data, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ {
+ Byte b = data[i];
+ dest[0] = GetHex((Byte)((b >> 4) & 0xF));
+ dest[1] = GetHex((Byte)(b & 0xF));
+ dest += 2;
+ }
+ *dest = 0;
+}
+
+#endif
+
+#define MY_ENDL endl
+
+HRESULT CFieldPrinter::PrintItemInfo(UInt32 index, const CListStat &st)
+{
+ char temp[128];
+ size_t tempPos = 0;
+
+ bool techMode = this->TechMode;
+ /*
+ if (techMode)
+ {
+ g_StdOut << "Index = ";
+ g_StdOut << (UInt64)index;
+ g_StdOut << endl;
+ }
+ */
+ FOR_VECTOR (i, _fields)
+ {
+ const CFieldInfo &f = _fields[i];
+
+ if (!techMode)
+ {
+ PrintSpacesToString(temp + tempPos, f.PrefixSpacesWidth);
+ tempPos += f.PrefixSpacesWidth;
+ }
+
+ if (techMode)
+ {
+ if (!f.NameA.IsEmpty())
+ g_StdOut << f.NameA;
+ else
+ g_StdOut << f.NameU;
+ }
+
+ if (f.PropID == kpidPath)
+ {
+ if (!techMode)
+ g_StdOut << temp;
+ g_StdOut.NormalizePrint_UString(FilePath, TempWString, TempAString);
+ if (techMode)
+ g_StdOut << MY_ENDL;
+ continue;
+ }
+
+ const unsigned width = f.Width;
+
+ if (f.IsRawProp)
+ {
+ #ifndef Z7_SFX
+
+ const void *data;
+ UInt32 dataSize;
+ UInt32 propType;
+ RINOK(Arc->GetRawProps->GetRawProp(index, f.PropID, &data, &dataSize, &propType))
+
+ if (dataSize != 0)
+ {
+ bool needPrint = true;
+
+ if (f.PropID == kpidNtSecure)
+ {
+ if (propType != NPropDataType::kRaw)
+ return E_FAIL;
+ #ifndef Z7_SFX
+ ConvertNtSecureToString((const Byte *)data, dataSize, TempAString);
+ g_StdOut << TempAString;
+ needPrint = false;
+ #endif
+ }
+ else if (f.PropID == kpidNtReparse)
+ {
+ UString s;
+ if (ConvertNtReparseToString((const Byte *)data, dataSize, s))
+ {
+ needPrint = false;
+ g_StdOut.PrintUString(s, TempAString);
+ }
+ }
+
+ if (needPrint)
+ {
+ if (propType != NPropDataType::kRaw)
+ return E_FAIL;
+
+ const UInt32 kMaxDataSize = 64;
+
+ if (dataSize > kMaxDataSize)
+ {
+ g_StdOut << "data:";
+ g_StdOut << dataSize;
+ }
+ else
+ {
+ char hexStr[kMaxDataSize * 2 + 4];
+ HexToString(hexStr, (const Byte *)data, dataSize);
+ g_StdOut << hexStr;
+ }
+ }
+ }
+
+ #endif
+ }
+ else
+ {
+ CPropVariant prop;
+ switch (f.PropID)
+ {
+ case kpidSize: if (st.Size.Def) prop = st.Size.Val; break;
+ case kpidPackSize: if (st.PackSize.Def) prop = st.PackSize.Val; break;
+ case kpidMTime:
+ {
+ const CListFileTimeDef &mtime = st.MTime;
+ if (mtime.Def)
+ prop.SetAsTimeFrom_FT_Prec_Ns100(mtime.FT, mtime.Prec, mtime.Ns100);
+ break;
+ }
+ default:
+ RINOK(Arc->Archive->GetProperty(index, f.PropID, &prop))
+ }
+ if (f.PropID == kpidAttrib && (prop.vt == VT_EMPTY || prop.vt == VT_UI4))
+ {
+ GetAttribString((prop.vt == VT_EMPTY) ? 0 : prop.ulVal, IsDir, techMode, temp + tempPos);
+ if (techMode)
+ g_StdOut << temp + tempPos;
+ else
+ tempPos += strlen(temp + tempPos);
+ }
+ else if (prop.vt == VT_EMPTY)
+ {
+ if (!techMode)
+ {
+ PrintSpacesToString(temp + tempPos, width);
+ tempPos += width;
+ }
+ }
+ else if (prop.vt == VT_FILETIME)
+ {
+ CListFileTimeDef t;
+ t.Set_From_Prop(prop);
+ PrintTime(temp + tempPos, t, techMode);
+ if (techMode)
+ g_StdOut << temp + tempPos;
+ else
+ {
+ size_t len = strlen(temp + tempPos);
+ tempPos += len;
+ if (len < (unsigned)f.Width)
+ {
+ len = f.Width - len;
+ PrintSpacesToString(temp + tempPos, (unsigned)len);
+ tempPos += len;
+ }
+ }
+ }
+ else if (prop.vt == VT_BSTR)
+ {
+ TempWString.SetFromBstr(prop.bstrVal);
+ // do we need multi-line support here ?
+ g_StdOut.Normalize_UString(TempWString);
+ if (techMode)
+ {
+ g_StdOut.PrintUString(TempWString, TempAString);
+ }
+ else
+ PrintUString(f.TextAdjustment, width, TempWString, TempAString);
+ }
+ else
+ {
+ char s[64];
+ ConvertPropertyToShortString2(s, prop, f.PropID);
+ if (techMode)
+ g_StdOut << s;
+ else
+ {
+ PrintStringToString(temp + tempPos, f.TextAdjustment, width, s);
+ tempPos += strlen(temp + tempPos);
+ }
+ }
+ }
+ if (techMode)
+ g_StdOut << MY_ENDL;
+ }
+ g_StdOut << MY_ENDL;
+ return S_OK;
+}
+
+static void PrintNumber(EAdjustment adj, unsigned width, const CListUInt64Def &value)
+{
+ char s[32];
+ s[0] = 0;
+ if (value.Def)
+ ConvertUInt64ToString(value.Val, s);
+ PrintString(adj, width, s);
+}
+
+void Print_UInt64_and_String(AString &s, UInt64 val, const char *name);
+
+void CFieldPrinter::PrintSum(const CListStat &st, UInt64 numDirs, const char *str)
+{
+ FOR_VECTOR (i, _fields)
+ {
+ const CFieldInfo &f = _fields[i];
+ PrintSpaces(f.PrefixSpacesWidth);
+ if (f.PropID == kpidSize)
+ PrintNumber(f.TextAdjustment, f.Width, st.Size);
+ else if (f.PropID == kpidPackSize)
+ PrintNumber(f.TextAdjustment, f.Width, st.PackSize);
+ else if (f.PropID == kpidMTime)
+ {
+ char s[64];
+ s[0] = 0;
+ if (st.MTime.Def)
+ PrintTime(s, st.MTime, false); // showNS
+ PrintString(f.TextAdjustment, f.Width, s);
+ }
+ else if (f.PropID == kpidPath)
+ {
+ AString s;
+ Print_UInt64_and_String(s, st.NumFiles, str);
+ if (numDirs != 0)
+ {
+ s += ", ";
+ Print_UInt64_and_String(s, numDirs, kString_Dirs);
+ }
+ PrintString(f.TextAdjustment, 0, s);
+ }
+ else
+ PrintString(f.TextAdjustment, f.Width, "");
+ }
+ g_StdOut << endl;
+}
+
+void CFieldPrinter::PrintSum(const CListStat2 &stat2)
+{
+ PrintSum(stat2.MainFiles, stat2.NumDirs, kString_Files);
+ if (stat2.AltStreams.NumFiles != 0)
+ {
+ PrintSum(stat2.AltStreams, 0, kString_AltStreams);
+ CListStat st = stat2.MainFiles;
+ st.Update(stat2.AltStreams);
+ PrintSum(st, 0, kString_Streams);
+ }
+}
+
+static HRESULT GetUInt64Value(IInArchive *archive, UInt32 index, PROPID propID, CListUInt64Def &value)
+{
+ value.Val = 0;
+ value.Def = false;
+ CPropVariant prop;
+ RINOK(archive->GetProperty(index, propID, &prop))
+ value.Def = ConvertPropVariantToUInt64(prop, value.Val);
+ return S_OK;
+}
+
+static HRESULT GetItemMTime(IInArchive *archive, UInt32 index, CListFileTimeDef &t)
+{
+ /* maybe we could call CArc::GetItemMTime(UInt32 index, CArcTime &ft, bool &defined) here
+ that can set default timestamp, if not defined */
+ t.Clear();
+ // t.Def = false;
+ CPropVariant prop;
+ RINOK(archive->GetProperty(index, kpidMTime, &prop))
+ if (prop.vt == VT_FILETIME)
+ t.Set_From_Prop(prop);
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+static void PrintPropNameAndNumber(CStdOutStream &so, const char *name, UInt64 val)
+{
+ so << name << ": " << val << endl;
+}
+
+static void PrintPropName_and_Eq(CStdOutStream &so, PROPID propID)
+{
+ const char *s;
+ char temp[16];
+ if (propID < Z7_ARRAY_SIZE(kPropIdToName))
+ s = kPropIdToName[propID];
+ else
+ {
+ ConvertUInt32ToString(propID, temp);
+ s = temp;
+ }
+ so << s << " = ";
+}
+
+static void PrintPropNameAndNumber(CStdOutStream &so, PROPID propID, UInt64 val)
+{
+ PrintPropName_and_Eq(so, propID);
+ so << val << endl;
+}
+
+static void PrintPropNameAndNumber_Signed(CStdOutStream &so, PROPID propID, Int64 val)
+{
+ PrintPropName_and_Eq(so, propID);
+ so << val << endl;
+}
+
+
+static void UString_Replace_CRLF_to_LF(UString &s)
+{
+ // s.Replace(L"\r\n", L"\n");
+ wchar_t *src = s.GetBuf();
+ wchar_t *dest = src;
+ for (;;)
+ {
+ wchar_t c = *src++;
+ if (c == 0)
+ break;
+ if (c == '\r' && *src == '\n')
+ {
+ src++;
+ c = '\n';
+ }
+ *dest++ = c;
+ }
+ s.ReleaseBuf_SetEnd((unsigned)(dest - s.GetBuf()));
+}
+
+
+static void PrintPropVal_MultiLine(CStdOutStream &so, const wchar_t *val)
+{
+ UString s (val);
+ if (s.Find(L'\n') >= 0)
+ {
+ so << endl;
+ so << "{";
+ so << endl;
+ UString_Replace_CRLF_to_LF(s);
+ so.Normalize_UString_LF_Allowed(s);
+ so << s;
+ so << endl;
+ so << "}";
+ }
+ else
+ {
+ so.Normalize_UString(s);
+ so << s;
+ }
+ so << endl;
+}
+
+
+static void PrintPropPair(CStdOutStream &so, const char *name, const wchar_t *val, bool multiLine)
+{
+ so << name << " = ";
+ if (multiLine)
+ {
+ PrintPropVal_MultiLine(so, val);
+ return;
+ }
+ UString s (val);
+ so.Normalize_UString(s);
+ so << s;
+ so << endl;
+}
+
+
+static void PrintPropertyPair2(CStdOutStream &so, PROPID propID, const wchar_t *name, const CPropVariant &prop)
+{
+ UString s;
+ const int levelTopLimit = 9; // 1ns level
+ ConvertPropertyToString2(s, prop, propID, levelTopLimit);
+ if (!s.IsEmpty())
+ {
+ AString nameA;
+ UString nameU;
+ GetPropName(propID, name, nameA, nameU);
+ if (!nameA.IsEmpty())
+ so << nameA;
+ else
+ so << nameU;
+ so << " = ";
+ PrintPropVal_MultiLine(so, s);
+ }
+}
+
+static HRESULT PrintArcProp(CStdOutStream &so, IInArchive *archive, PROPID propID, const wchar_t *name)
+{
+ CPropVariant prop;
+ RINOK(archive->GetArchiveProperty(propID, &prop))
+ PrintPropertyPair2(so, propID, name, prop);
+ return S_OK;
+}
+
+static void PrintArcTypeError(CStdOutStream &so, const UString &type, bool isWarning)
+{
+ so << "Open " << (isWarning ? "WARNING" : "ERROR")
+ << ": Cannot open the file as ["
+ << type
+ << "] archive"
+ << endl;
+}
+
+int Find_FileName_InSortedVector(const UStringVector &fileName, const UString& name);
+
+void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags);
+
+static void ErrorInfo_Print(CStdOutStream &so, const CArcErrorInfo &er)
+{
+ PrintErrorFlags(so, "ERRORS:", er.GetErrorFlags());
+ if (!er.ErrorMessage.IsEmpty())
+ PrintPropPair(so, "ERROR", er.ErrorMessage, true);
+
+ PrintErrorFlags(so, "WARNINGS:", er.GetWarningFlags());
+ if (!er.WarningMessage.IsEmpty())
+ PrintPropPair(so, "WARNING", er.WarningMessage, true);
+}
+
+HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
+HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink)
+{
+ FOR_VECTOR (r, arcLink.Arcs)
+ {
+ const CArc &arc = arcLink.Arcs[r];
+ const CArcErrorInfo &er = arc.ErrorInfo;
+
+ so << "--\n";
+ PrintPropPair(so, "Path", arc.Path, false);
+ if (er.ErrorFormatIndex >= 0)
+ {
+ if (er.ErrorFormatIndex == arc.FormatIndex)
+ so << "Warning: The archive is open with offset" << endl;
+ else
+ PrintArcTypeError(so, codecs->GetFormatNamePtr(er.ErrorFormatIndex), true);
+ }
+ PrintPropPair(so, "Type", codecs->GetFormatNamePtr(arc.FormatIndex), false);
+
+ ErrorInfo_Print(so, er);
+
+ Int64 offset = arc.GetGlobalOffset();
+ if (offset != 0)
+ PrintPropNameAndNumber_Signed(so, kpidOffset, offset);
+ IInArchive *archive = arc.Archive;
+ RINOK(PrintArcProp(so, archive, kpidPhySize, NULL))
+ if (er.TailSize != 0)
+ PrintPropNameAndNumber(so, kpidTailSize, er.TailSize);
+ {
+ UInt32 numProps;
+ RINOK(archive->GetNumberOfArchiveProperties(&numProps))
+
+ for (UInt32 j = 0; j < numProps; j++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE vt;
+ RINOK(archive->GetArchivePropertyInfo(j, &name, &propID, &vt))
+ RINOK(PrintArcProp(so, archive, propID, name))
+ }
+ }
+
+ if (r != arcLink.Arcs.Size() - 1)
+ {
+ UInt32 numProps;
+ so << "----\n";
+ if (archive->GetNumberOfProperties(&numProps) == S_OK)
+ {
+ UInt32 mainIndex = arcLink.Arcs[r + 1].SubfileIndex;
+ for (UInt32 j = 0; j < numProps; j++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE vt;
+ RINOK(archive->GetPropertyInfo(j, &name, &propID, &vt))
+ CPropVariant prop;
+ RINOK(archive->GetProperty(mainIndex, propID, &prop))
+ PrintPropertyPair2(so, propID, name, prop);
+ }
+ }
+ }
+ }
+ return S_OK;
+}
+
+HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
+HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink)
+{
+ #ifndef Z7_NO_CRYPTO
+ if (arcLink.PasswordWasAsked)
+ so << "Cannot open encrypted archive. Wrong password?";
+ else
+ #endif
+ {
+ if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
+ {
+ so.NormalizePrint_UString(arcLink.NonOpen_ArcPath);
+ so << endl;
+ PrintArcTypeError(so, codecs->Formats[(unsigned)arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false);
+ }
+ else
+ so << "Cannot open the file as archive";
+ }
+
+ so << endl;
+ so << endl;
+ ErrorInfo_Print(so, arcLink.NonOpen_ErrorInfo);
+
+ return S_OK;
+}
+
+bool CensorNode_CheckPath(const NWildcard::CCensorNode &node, const CReadArcItem &item);
+
+HRESULT ListArchives(
+ const CListOptions &listOptions,
+ CCodecs *codecs,
+ const CObjectVector<COpenType> &types,
+ const CIntVector &excludedFormats,
+ bool stdInMode,
+ UStringVector &arcPaths, UStringVector &arcPathsFull,
+ bool processAltStreams, bool showAltStreams,
+ const NWildcard::CCensorNode &wildcardCensor,
+ bool enableHeaders, bool techMode,
+ #ifndef Z7_NO_CRYPTO
+ bool &passwordEnabled, UString &password,
+ #endif
+ #ifndef Z7_SFX
+ const CObjectVector<CProperty> *props,
+ #endif
+ UInt64 &numErrors,
+ UInt64 &numWarnings)
+{
+ bool allFilesAreAllowed = wildcardCensor.AreAllAllowed();
+
+ numErrors = 0;
+ numWarnings = 0;
+
+ CFieldPrinter fp;
+ if (!techMode)
+ fp.Init(kStandardFieldTable, Z7_ARRAY_SIZE(kStandardFieldTable));
+
+ CListStat2 stat2total;
+
+ CBoolArr skipArcs(arcPaths.Size());
+ unsigned arcIndex;
+ for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++)
+ skipArcs[arcIndex] = false;
+ UInt64 numVolumes = 0;
+ UInt64 numArcs = 0;
+ UInt64 totalArcSizes = 0;
+
+ HRESULT lastError = 0;
+
+ for (arcIndex = 0; arcIndex < arcPaths.Size(); arcIndex++)
+ {
+ if (skipArcs[arcIndex])
+ continue;
+ const UString &arcPath = arcPaths[arcIndex];
+ UInt64 arcPackSize = 0;
+
+ if (!stdInMode)
+ {
+ NFile::NFind::CFileInfo fi;
+ if (!fi.Find_FollowLink(us2fs(arcPath)))
+ {
+ DWORD errorCode = GetLastError();
+ if (errorCode == 0)
+ errorCode = ERROR_FILE_NOT_FOUND;
+ lastError = HRESULT_FROM_WIN32(errorCode);
+ g_StdOut.Flush();
+ if (g_ErrStream)
+ {
+ *g_ErrStream << endl << kError << NError::MyFormatMessage(errorCode) << endl;
+ g_ErrStream->NormalizePrint_UString(arcPath);
+ *g_ErrStream << endl << endl;
+ }
+ numErrors++;
+ continue;
+ }
+ if (fi.IsDir())
+ {
+ g_StdOut.Flush();
+ if (g_ErrStream)
+ {
+ *g_ErrStream << endl << kError;
+ g_ErrStream->NormalizePrint_UString(arcPath);
+ *g_ErrStream << " is not a file" << endl << endl;
+ }
+ numErrors++;
+ continue;
+ }
+ arcPackSize = fi.Size;
+ totalArcSizes += arcPackSize;
+ }
+
+ CArchiveLink arcLink;
+
+ COpenCallbackConsole openCallback;
+ openCallback.Init(&g_StdOut, g_ErrStream, NULL);
+
+ #ifndef Z7_NO_CRYPTO
+
+ openCallback.PasswordIsDefined = passwordEnabled;
+ openCallback.Password = password;
+
+ #endif
+
+ /*
+ CObjectVector<COptionalOpenProperties> optPropsVector;
+ COptionalOpenProperties &optProps = optPropsVector.AddNew();
+ optProps.Props = *props;
+ */
+
+ COpenOptions options;
+ #ifndef Z7_SFX
+ options.props = props;
+ #endif
+ options.codecs = codecs;
+ options.types = &types;
+ options.excludedFormats = &excludedFormats;
+ options.stdInMode = stdInMode;
+ options.stream = NULL;
+ options.filePath = arcPath;
+
+ if (enableHeaders)
+ {
+ g_StdOut << endl << kListing;
+ g_StdOut.NormalizePrint_UString(arcPath);
+ g_StdOut << endl << endl;
+ }
+
+ HRESULT result = arcLink.Open_Strict(options, &openCallback);
+
+ if (result != S_OK)
+ {
+ if (result == E_ABORT)
+ return result;
+ if (result != S_FALSE)
+ lastError = result;
+ g_StdOut.Flush();
+ if (g_ErrStream)
+ {
+ *g_ErrStream << endl << kError;
+ g_ErrStream->NormalizePrint_UString(arcPath);
+ *g_ErrStream << " : ";
+ if (result == S_FALSE)
+ {
+ Print_OpenArchive_Error(*g_ErrStream, codecs, arcLink);
+ }
+ else
+ {
+ *g_ErrStream << "opening : ";
+ if (result == E_OUTOFMEMORY)
+ *g_ErrStream << "Can't allocate required memory";
+ else
+ *g_ErrStream << NError::MyFormatMessage(result);
+ }
+ *g_ErrStream << endl;
+ }
+ numErrors++;
+ continue;
+ }
+
+ {
+ FOR_VECTOR (r, arcLink.Arcs)
+ {
+ const CArcErrorInfo &arc = arcLink.Arcs[r].ErrorInfo;
+ if (!arc.WarningMessage.IsEmpty())
+ numWarnings++;
+ if (arc.AreThereWarnings())
+ numWarnings++;
+ if (arc.ErrorFormatIndex >= 0)
+ numWarnings++;
+ if (arc.AreThereErrors())
+ {
+ numErrors++;
+ // break;
+ }
+ if (!arc.ErrorMessage.IsEmpty())
+ numErrors++;
+ }
+ }
+
+ numArcs++;
+ numVolumes++;
+
+ if (!stdInMode)
+ {
+ numVolumes += arcLink.VolumePaths.Size();
+ totalArcSizes += arcLink.VolumesSize;
+ FOR_VECTOR (v, arcLink.VolumePaths)
+ {
+ int index = Find_FileName_InSortedVector(arcPathsFull, arcLink.VolumePaths[v]);
+ if (index >= 0 && (unsigned)index > arcIndex)
+ skipArcs[(unsigned)index] = true;
+ }
+ }
+
+
+ if (enableHeaders)
+ {
+ RINOK(Print_OpenArchive_Props(g_StdOut, codecs, arcLink))
+
+ g_StdOut << endl;
+ if (techMode)
+ g_StdOut << "----------\n";
+ }
+
+ if (enableHeaders && !techMode)
+ {
+ fp.PrintTitle();
+ g_StdOut << endl;
+ fp.PrintTitleLines();
+ g_StdOut << endl;
+ }
+
+ const CArc &arc = arcLink.Arcs.Back();
+ fp.Arc = &arc;
+ fp.TechMode = techMode;
+ IInArchive *archive = arc.Archive;
+ if (techMode)
+ {
+ fp.Clear();
+ RINOK(fp.AddMainProps(archive))
+ if (arc.GetRawProps)
+ {
+ RINOK(fp.AddRawProps(arc.GetRawProps))
+ }
+ }
+
+ CListStat2 stat2;
+
+ UInt32 numItems;
+ RINOK(archive->GetNumberOfItems(&numItems))
+
+ CReadArcItem item;
+ UStringVector pathParts;
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ if (NConsoleClose::TestBreakSignal())
+ return E_ABORT;
+
+ HRESULT res = arc.GetItem_Path2(i, fp.FilePath);
+
+ if (stdInMode && res == E_INVALIDARG)
+ break;
+ RINOK(res)
+
+ if (arc.Ask_Aux)
+ {
+ bool isAux;
+ RINOK(Archive_IsItem_Aux(archive, i, isAux))
+ if (isAux)
+ continue;
+ }
+
+ bool isAltStream = false;
+ if (arc.Ask_AltStream)
+ {
+ RINOK(Archive_IsItem_AltStream(archive, i, isAltStream))
+ if (isAltStream && !processAltStreams)
+ continue;
+ }
+
+ RINOK(Archive_IsItem_Dir(archive, i, fp.IsDir))
+
+ if (fp.IsDir ? listOptions.ExcludeDirItems : listOptions.ExcludeFileItems)
+ continue;
+
+ if (!allFilesAreAllowed)
+ {
+ if (isAltStream)
+ {
+ RINOK(arc.GetItem(i, item))
+ if (!CensorNode_CheckPath(wildcardCensor, item))
+ continue;
+ }
+ else
+ {
+ SplitPathToParts(fp.FilePath, pathParts);
+ bool include;
+ if (!wildcardCensor.CheckPathVect(pathParts, !fp.IsDir, include))
+ continue;
+ if (!include)
+ continue;
+ }
+ }
+
+ CListStat st;
+
+ RINOK(GetUInt64Value(archive, i, kpidSize, st.Size))
+ RINOK(GetUInt64Value(archive, i, kpidPackSize, st.PackSize))
+ RINOK(GetItemMTime(archive, i, st.MTime))
+
+ if (fp.IsDir)
+ stat2.NumDirs++;
+ else
+ st.NumFiles = 1;
+ stat2.GetStat(isAltStream).Update(st);
+
+ if (isAltStream && !showAltStreams)
+ continue;
+ RINOK(fp.PrintItemInfo(i, st))
+ }
+
+ UInt64 numStreams = stat2.GetNumStreams();
+ if (!stdInMode
+ && !stat2.MainFiles.PackSize.Def
+ && !stat2.AltStreams.PackSize.Def)
+ {
+ if (arcLink.VolumePaths.Size() != 0)
+ arcPackSize += arcLink.VolumesSize;
+ stat2.MainFiles.PackSize.Add((numStreams == 0) ? 0 : arcPackSize);
+ }
+
+ stat2.MainFiles.SetSizeDefIfNoFiles();
+ stat2.AltStreams.SetSizeDefIfNoFiles();
+
+ if (enableHeaders && !techMode)
+ {
+ fp.PrintTitleLines();
+ g_StdOut << endl;
+ fp.PrintSum(stat2);
+ }
+
+ if (enableHeaders)
+ {
+ if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
+ {
+ g_StdOut << "----------\n";
+ PrintPropPair(g_StdOut, "Path", arcLink.NonOpen_ArcPath, false);
+ PrintArcTypeError(g_StdOut, codecs->Formats[(unsigned)arcLink.NonOpen_ErrorInfo.ErrorFormatIndex].Name, false);
+ }
+ }
+
+ stat2total.Update(stat2);
+
+ g_StdOut.Flush();
+ }
+
+ if (enableHeaders && !techMode && (arcPaths.Size() > 1 || numVolumes > 1))
+ {
+ g_StdOut << endl;
+ fp.PrintTitleLines();
+ g_StdOut << endl;
+ fp.PrintSum(stat2total);
+ g_StdOut << endl;
+ PrintPropNameAndNumber(g_StdOut, "Archives", numArcs);
+ PrintPropNameAndNumber(g_StdOut, "Volumes", numVolumes);
+ PrintPropNameAndNumber(g_StdOut, "Total archives size", totalArcSizes);
+ }
+
+ if (numErrors == 1 && lastError != 0)
+ return lastError;
+
+ return S_OK;
+}
diff --git a/CPP/7zip/UI/Console/List.h b/CPP/7zip/UI/Console/List.h
index dabbc2a..4969c3e 100644
--- a/CPP/7zip/UI/Console/List.h
+++ b/CPP/7zip/UI/Console/List.h
@@ -1,27 +1,40 @@
-// List.h
-
-#ifndef __LIST_H
-#define __LIST_H
-
-#include "../../../Common/Wildcard.h"
-
-#include "../Common/LoadCodecs.h"
-
-HRESULT ListArchives(CCodecs *codecs,
- const CObjectVector<COpenType> &types,
- const CIntVector &excludedFormats,
- bool stdInMode,
- UStringVector &archivePaths, UStringVector &archivePathsFull,
- bool processAltStreams, bool showAltStreams,
- const NWildcard::CCensorNode &wildcardCensor,
- bool enableHeaders, bool techMode,
- #ifndef _NO_CRYPTO
- bool &passwordEnabled, UString &password,
- #endif
- #ifndef _SFX
- const CObjectVector<CProperty> *props,
- #endif
- UInt64 &errors,
- UInt64 &numWarnings);
-
-#endif
+// List.h
+
+#ifndef ZIP7_INC_LIST_H
+#define ZIP7_INC_LIST_H
+
+#include "../../../Common/Wildcard.h"
+
+#include "../Common/LoadCodecs.h"
+
+struct CListOptions
+{
+ bool ExcludeDirItems;
+ bool ExcludeFileItems;
+
+ CListOptions():
+ ExcludeDirItems(false),
+ ExcludeFileItems(false)
+ {}
+};
+
+HRESULT ListArchives(
+ const CListOptions &listOptions,
+ CCodecs *codecs,
+ const CObjectVector<COpenType> &types,
+ const CIntVector &excludedFormats,
+ bool stdInMode,
+ UStringVector &archivePaths, UStringVector &archivePathsFull,
+ bool processAltStreams, bool showAltStreams,
+ const NWildcard::CCensorNode &wildcardCensor,
+ bool enableHeaders, bool techMode,
+ #ifndef Z7_NO_CRYPTO
+ bool &passwordEnabled, UString &password,
+ #endif
+ #ifndef Z7_SFX
+ const CObjectVector<CProperty> *props,
+ #endif
+ UInt64 &errors,
+ UInt64 &numWarnings);
+
+#endif
diff --git a/CPP/7zip/UI/Console/Main.cpp b/CPP/7zip/UI/Console/Main.cpp
index 4d7aac9..eb9e2a8 100644
--- a/CPP/7zip/UI/Console/Main.cpp
+++ b/CPP/7zip/UI/Console/Main.cpp
@@ -1,1154 +1,1576 @@
-// Main.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/MyWindows.h"
-
-#ifdef _WIN32
-#include <Psapi.h>
-#endif
-
-#include "../../../../C/CpuArch.h"
-
-#include "../../../Common/MyInitGuid.h"
-
-#include "../../../Common/CommandLineParser.h"
-#include "../../../Common/IntToString.h"
-#include "../../../Common/MyException.h"
-#include "../../../Common/StringConvert.h"
-#include "../../../Common/StringToInt.h"
-#include "../../../Common/UTFConvert.h"
-
-#include "../../../Windows/ErrorMsg.h"
-
-#include "../../../Windows/TimeUtils.h"
-
-#include "../Common/ArchiveCommandLine.h"
-#include "../Common/Bench.h"
-#include "../Common/ExitCode.h"
-#include "../Common/Extract.h"
-
-#ifdef EXTERNAL_CODECS
-#include "../Common/LoadCodecs.h"
-#endif
-
-#include "../../Common/RegisterCodec.h"
-
-#include "BenchCon.h"
-#include "ConsoleClose.h"
-#include "ExtractCallbackConsole.h"
-#include "List.h"
-#include "OpenCallbackConsole.h"
-#include "UpdateCallbackConsole.h"
-
-#include "HashCon.h"
-
-#ifdef PROG_VARIANT_R
-#include "../../../../C/7zVersion.h"
-#else
-#include "../../MyVersion.h"
-#endif
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NCommandLineParser;
-
-#ifdef _WIN32
-HINSTANCE g_hInstance = 0;
-#endif
-
-extern CStdOutStream *g_StdStream;
-extern CStdOutStream *g_ErrStream;
-
-extern unsigned g_NumCodecs;
-extern const CCodecInfo *g_Codecs[];
-
-extern unsigned g_NumHashers;
-extern const CHasherInfo *g_Hashers[];
-
-static const char * const kCopyrightString = "\n7-Zip"
- #ifndef EXTERNAL_CODECS
- #ifdef PROG_VARIANT_R
- " (r)"
- #else
- " (a)"
- #endif
- #endif
-
- " " MY_VERSION_CPU
- " : " MY_COPYRIGHT_DATE "\n\n";
-
-static const char * const kHelpString =
- "Usage: 7z"
-#ifndef EXTERNAL_CODECS
-#ifdef PROG_VARIANT_R
- "r"
-#else
- "a"
-#endif
-#endif
- " <command> [<switches>...] <archive_name> [<file_names>...] [@listfile]\n"
- "\n"
- "<Commands>\n"
- " a : Add files to archive\n"
- " b : Benchmark\n"
- " d : Delete files from archive\n"
- " e : Extract files from archive (without using directory names)\n"
- " h : Calculate hash values for files\n"
- " i : Show information about supported formats\n"
- " l : List contents of archive\n"
- " rn : Rename files in archive\n"
- " t : Test integrity of archive\n"
- " u : Update files to archive\n"
- " x : eXtract files with full paths\n"
- "\n"
- "<Switches>\n"
- " -- : Stop switches and @listfile parsing\n"
- " -ai[r[-|0]]{@listfile|!wildcard} : Include archives\n"
- " -ax[r[-|0]]{@listfile|!wildcard} : eXclude archives\n"
- " -ao{a|s|t|u} : set Overwrite mode\n"
- " -an : disable archive_name field\n"
- " -bb[0-3] : set output log level\n"
- " -bd : disable progress indicator\n"
- " -bs{o|e|p}{0|1|2} : set output stream for output/error/progress line\n"
- " -bt : show execution time statistics\n"
- " -i[r[-|0]]{@listfile|!wildcard} : Include filenames\n"
- " -m{Parameters} : set compression Method\n"
- " -mmt[N] : set number of CPU threads\n"
- " -mx[N] : set compression level: -mx1 (fastest) ... -mx9 (ultra)\n"
- " -o{Directory} : set Output directory\n"
- #ifndef _NO_CRYPTO
- " -p{Password} : set Password\n"
- #endif
- " -r[-|0] : Recurse subdirectories\n"
- " -sa{a|e|s} : set Archive name mode\n"
- " -scc{UTF-8|WIN|DOS} : set charset for for console input/output\n"
- " -scs{UTF-8|UTF-16LE|UTF-16BE|WIN|DOS|{id}} : set charset for list files\n"
- " -scrc[CRC32|CRC64|SHA1|SHA256|*] : set hash function for x, e, h commands\n"
- " -sdel : delete files after compression\n"
- " -seml[.] : send archive by email\n"
- " -sfx[{name}] : Create SFX archive\n"
- " -si[{name}] : read data from stdin\n"
- " -slp : set Large Pages mode\n"
- " -slt : show technical information for l (List) command\n"
- " -snh : store hard links as links\n"
- " -snl : store symbolic links as links\n"
- " -sni : store NT security information\n"
- " -sns[-] : store NTFS alternate streams\n"
- " -so : write data to stdout\n"
- " -spd : disable wildcard matching for file names\n"
- " -spe : eliminate duplication of root folder for extract command\n"
- " -spf : use fully qualified file paths\n"
- " -ssc[-] : set sensitive case mode\n"
- " -sse : stop archive creating, if it can't open some input file\n"
- " -ssw : compress shared files\n"
- " -stl : set archive timestamp from the most recently modified file\n"
- " -stm{HexMask} : set CPU thread affinity mask (hexadecimal number)\n"
- " -stx{Type} : exclude archive type\n"
- " -t{Type} : Set type of archive\n"
- " -u[-][p#][q#][r#][x#][y#][z#][!newArchiveName] : Update options\n"
- " -v{Size}[b|k|m|g] : Create volumes\n"
- " -w[{path}] : assign Work directory. Empty path means a temporary directory\n"
- " -x[r[-|0]]{@listfile|!wildcard} : eXclude filenames\n"
- " -y : assume Yes on all queries\n";
-
-// ---------------------------
-// exception messages
-
-static const char * const kEverythingIsOk = "Everything is Ok";
-static const char * const kUserErrorMessage = "Incorrect command line";
-static const char * const kNoFormats = "7-Zip cannot find the code that works with archives.";
-static const char * const kUnsupportedArcTypeMessage = "Unsupported archive type";
-// static const char * const kUnsupportedUpdateArcType = "Can't create archive for that type";
-
-#define kDefaultSfxModule "7zCon.sfx"
-
-static void ShowMessageAndThrowException(LPCSTR message, NExitCode::EEnum code)
-{
- if (g_ErrStream)
- *g_ErrStream << endl << "ERROR: " << message << endl;
- throw code;
-}
-
-#ifndef _WIN32
-static void GetArguments(int numArgs, const char *args[], UStringVector &parts)
-{
- parts.Clear();
- for (int i = 0; i < numArgs; i++)
- {
- UString s = MultiByteToUnicodeString(args[i]);
- parts.Add(s);
- }
-}
-#endif
-
-static void ShowCopyrightAndHelp(CStdOutStream *so, bool needHelp)
-{
- if (!so)
- return;
- *so << kCopyrightString;
- // *so << "# CPUs: " << (UInt64)NWindows::NSystem::GetNumberOfProcessors() << endl;
- if (needHelp)
- *so << kHelpString;
-}
-
-
-static void PrintStringRight(CStdOutStream &so, const char *s, unsigned size)
-{
- unsigned len = MyStringLen(s);
- for (unsigned i = len; i < size; i++)
- so << ' ';
- so << s;
-}
-
-static void PrintUInt32(CStdOutStream &so, UInt32 val, unsigned size)
-{
- char s[16];
- ConvertUInt32ToString(val, s);
- PrintStringRight(so, s, size);
-}
-
-static void PrintLibIndex(CStdOutStream &so, int libIndex)
-{
- if (libIndex >= 0)
- PrintUInt32(so, libIndex, 2);
- else
- so << " ";
- so << ' ';
-}
-
-static void PrintString(CStdOutStream &so, const UString &s, unsigned size)
-{
- unsigned len = s.Len();
- so << s;
- for (unsigned i = len; i < size; i++)
- so << ' ';
-}
-
-static inline char GetHex(unsigned val)
-{
- return (char)((val < 10) ? ('0' + val) : ('A' + (val - 10)));
-}
-
-static void PrintWarningsPaths(const CErrorPathCodes &pc, CStdOutStream &so)
-{
- FOR_VECTOR(i, pc.Paths)
- {
- so.NormalizePrint_UString(fs2us(pc.Paths[i]));
- so << " : ";
- so << NError::MyFormatMessage(pc.Codes[i]) << endl;
- }
- so << "----------------" << endl;
-}
-
-static int WarningsCheck(HRESULT result, const CCallbackConsoleBase &callback,
- const CUpdateErrorInfo &errorInfo,
- CStdOutStream *so,
- CStdOutStream *se,
- bool showHeaders)
-{
- int exitCode = NExitCode::kSuccess;
-
- if (callback.ScanErrors.Paths.Size() != 0)
- {
- if (se)
- {
- *se << endl;
- *se << "Scan WARNINGS for files and folders:" << endl << endl;
- PrintWarningsPaths(callback.ScanErrors, *se);
- *se << "Scan WARNINGS: " << callback.ScanErrors.Paths.Size();
- *se << endl;
- }
- exitCode = NExitCode::kWarning;
- }
-
- if (result != S_OK || errorInfo.ThereIsError())
- {
- if (se)
- {
- UString message;
- if (!errorInfo.Message.IsEmpty())
- {
- message += errorInfo.Message.Ptr();
- message.Add_LF();
- }
- {
- FOR_VECTOR(i, errorInfo.FileNames)
- {
- message += fs2us(errorInfo.FileNames[i]);
- message.Add_LF();
- }
- }
- if (errorInfo.SystemError != 0)
- {
- message += NError::MyFormatMessage(errorInfo.SystemError);
- message.Add_LF();
- }
- if (!message.IsEmpty())
- *se << L"\nError:\n" << message;
- }
-
- // we will work with (result) later
- // throw CSystemException(result);
- return NExitCode::kFatalError;
- }
-
- unsigned numErrors = callback.FailedFiles.Paths.Size();
- if (numErrors == 0)
- {
- if (showHeaders)
- if (callback.ScanErrors.Paths.Size() == 0)
- if (so)
- {
- if (se)
- se->Flush();
- *so << kEverythingIsOk << endl;
- }
- }
- else
- {
- if (se)
- {
- *se << endl;
- *se << "WARNINGS for files:" << endl << endl;
- PrintWarningsPaths(callback.FailedFiles, *se);
- *se << "WARNING: Cannot open " << numErrors << " file";
- if (numErrors > 1)
- *se << 's';
- *se << endl;
- }
- exitCode = NExitCode::kWarning;
- }
-
- return exitCode;
-}
-
-static void ThrowException_if_Error(HRESULT res)
-{
- if (res != S_OK)
- throw CSystemException(res);
-}
-
-
-static void PrintNum(UInt64 val, unsigned numDigits, char c = ' ')
-{
- char temp[64];
- char *p = temp + 32;
- ConvertUInt64ToString(val, p);
- unsigned len = MyStringLen(p);
- for (; len < numDigits; len++)
- *--p = c;
- *g_StdStream << p;
-}
-
-static void PrintTime(const char *s, UInt64 val, UInt64 total)
-{
- *g_StdStream << endl << s << " Time =";
- const UInt32 kFreq = 10000000;
- UInt64 sec = val / kFreq;
- PrintNum(sec, 6);
- *g_StdStream << '.';
- UInt32 ms = (UInt32)(val - (sec * kFreq)) / (kFreq / 1000);
- PrintNum(ms, 3, '0');
-
- while (val > ((UInt64)1 << 56))
- {
- val >>= 1;
- total >>= 1;
- }
-
- UInt64 percent = 0;
- if (total != 0)
- percent = val * 100 / total;
- *g_StdStream << " =";
- PrintNum(percent, 5);
- *g_StdStream << '%';
-}
-
-#ifndef UNDER_CE
-
-#define SHIFT_SIZE_VALUE(x, num) (((x) + (1 << (num)) - 1) >> (num))
-
-static void PrintMemUsage(const char *s, UInt64 val)
-{
- *g_StdStream << " " << s << " Memory =";
- PrintNum(SHIFT_SIZE_VALUE(val, 20), 7);
- *g_StdStream << " MB";
-
- #ifdef _7ZIP_LARGE_PAGES
- AString lp;
- Add_LargePages_String(lp);
- if (!lp.IsEmpty())
- *g_StdStream << lp;
- #endif
-}
-
-EXTERN_C_BEGIN
-typedef BOOL (WINAPI *Func_GetProcessMemoryInfo)(HANDLE Process,
- PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb);
-typedef BOOL (WINAPI *Func_QueryProcessCycleTime)(HANDLE Process, PULONG64 CycleTime);
-EXTERN_C_END
-
-#endif
-
-static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }
-
-static void PrintStat()
-{
- FILETIME creationTimeFT, exitTimeFT, kernelTimeFT, userTimeFT;
- if (!
- #ifdef UNDER_CE
- ::GetThreadTimes(::GetCurrentThread()
- #else
- // NT 3.5
- ::GetProcessTimes(::GetCurrentProcess()
- #endif
- , &creationTimeFT, &exitTimeFT, &kernelTimeFT, &userTimeFT))
- return;
- FILETIME curTimeFT;
- NTime::GetCurUtcFileTime(curTimeFT);
-
- #ifndef UNDER_CE
-
- PROCESS_MEMORY_COUNTERS m;
- memset(&m, 0, sizeof(m));
- BOOL memDefined = FALSE;
- BOOL cycleDefined = FALSE;
- ULONG64 cycleTime = 0;
- {
- /* NT 4.0: GetProcessMemoryInfo() in Psapi.dll
- Win7: new function K32GetProcessMemoryInfo() in kernel32.dll
- It's faster to call kernel32.dll code than Psapi.dll code
- GetProcessMemoryInfo() requires Psapi.lib
- Psapi.lib in SDK7+ can link to K32GetProcessMemoryInfo in kernel32.dll
- The program with K32GetProcessMemoryInfo will not work on systems before Win7
- // memDefined = GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m));
- */
-
- HMODULE kern = ::GetModuleHandleW(L"kernel32.dll");
- Func_GetProcessMemoryInfo my_GetProcessMemoryInfo = (Func_GetProcessMemoryInfo)
- ::GetProcAddress(kern, "K32GetProcessMemoryInfo");
- if (!my_GetProcessMemoryInfo)
- {
- HMODULE lib = LoadLibraryW(L"Psapi.dll");
- if (lib)
- my_GetProcessMemoryInfo = (Func_GetProcessMemoryInfo)::GetProcAddress(lib, "GetProcessMemoryInfo");
- }
- if (my_GetProcessMemoryInfo)
- memDefined = my_GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m));
- // FreeLibrary(lib);
-
- Func_QueryProcessCycleTime my_QueryProcessCycleTime = (Func_QueryProcessCycleTime)
- ::GetProcAddress(kern, "QueryProcessCycleTime");
- if (my_QueryProcessCycleTime)
- cycleDefined = my_QueryProcessCycleTime(GetCurrentProcess(), &cycleTime);
- }
-
- #endif
-
- UInt64 curTime = GetTime64(curTimeFT);
- UInt64 creationTime = GetTime64(creationTimeFT);
- UInt64 kernelTime = GetTime64(kernelTimeFT);
- UInt64 userTime = GetTime64(userTimeFT);
-
- UInt64 totalTime = curTime - creationTime;
-
- PrintTime("Kernel ", kernelTime, totalTime);
-
- #ifndef UNDER_CE
- if (cycleDefined)
- {
- *g_StdStream << " ";
- PrintNum(cycleTime / 1000000, 22);
- *g_StdStream << " MCycles";
- }
- #endif
-
- PrintTime("User ", userTime, totalTime);
-
- PrintTime("Process", kernelTime + userTime, totalTime);
- #ifndef UNDER_CE
- if (memDefined) PrintMemUsage("Virtual ", m.PeakPagefileUsage);
- #endif
-
- PrintTime("Global ", totalTime, totalTime);
- #ifndef UNDER_CE
- if (memDefined) PrintMemUsage("Physical", m.PeakWorkingSetSize);
- #endif
-
- *g_StdStream << endl;
-}
-
-static void PrintHexId(CStdOutStream &so, UInt64 id)
-{
- char s[32];
- ConvertUInt64ToHex(id, s);
- PrintStringRight(so, s, 8);
-}
-
-
-int Main2(
- #ifndef _WIN32
- int numArgs, char *args[]
- #endif
-)
-{
- #if defined(_WIN32) && !defined(UNDER_CE)
- SetFileApisToOEM();
- #endif
-
- UStringVector commandStrings;
-
- #ifdef _WIN32
- NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);
- #else
- GetArguments(numArgs, args, commandStrings);
- #endif
-
- #ifndef UNDER_CE
- if (commandStrings.Size() > 0)
- commandStrings.Delete(0);
- #endif
-
- if (commandStrings.Size() == 0)
- {
- ShowCopyrightAndHelp(g_StdStream, true);
- return 0;
- }
-
- CArcCmdLineOptions options;
-
- CArcCmdLineParser parser;
-
- parser.Parse1(commandStrings, options);
-
- g_StdOut.IsTerminalMode = options.IsStdOutTerminal;
- g_StdErr.IsTerminalMode = options.IsStdErrTerminal;
-
- if (options.Number_for_Out != k_OutStream_stdout)
- g_StdStream = (options.Number_for_Out == k_OutStream_stderr ? &g_StdErr : NULL);
-
- if (options.Number_for_Errors != k_OutStream_stderr)
- g_ErrStream = (options.Number_for_Errors == k_OutStream_stdout ? &g_StdOut : NULL);
-
- CStdOutStream *percentsStream = NULL;
- if (options.Number_for_Percents != k_OutStream_disabled)
- percentsStream = (options.Number_for_Percents == k_OutStream_stderr) ? &g_StdErr : &g_StdOut;;
-
- if (options.HelpMode)
- {
- ShowCopyrightAndHelp(g_StdStream, true);
- return 0;
- }
-
- if (options.EnableHeaders)
- ShowCopyrightAndHelp(g_StdStream, false);
-
- parser.Parse2(options);
-
- unsigned percentsNameLevel = 1;
- if (options.LogLevel == 0 || options.Number_for_Percents != options.Number_for_Out)
- percentsNameLevel = 2;
-
- unsigned consoleWidth = 80;
-
- if (percentsStream)
- {
- #ifdef _WIN32
-
- #if !defined(UNDER_CE)
- CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
- if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consoleInfo))
- consoleWidth = consoleInfo.dwSize.X;
- #endif
-
- #else
-
- struct winsize w;
- if (ioctl(0, TIOCGWINSZ, &w) == )
- consoleWidth = w.ws_col;
-
- #endif
- }
-
- CREATE_CODECS_OBJECT
-
- codecs->CaseSensitiveChange = options.CaseSensitiveChange;
- codecs->CaseSensitive = options.CaseSensitive;
- ThrowException_if_Error(codecs->Load());
-
- bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
-
- if (codecs->Formats.Size() == 0 &&
- (isExtractGroupCommand
- || options.Command.CommandType == NCommandType::kList
- || options.Command.IsFromUpdateGroup()))
- {
- #ifdef EXTERNAL_CODECS
- if (!codecs->MainDll_ErrorPath.IsEmpty())
- {
- UString s ("Can't load module: ");
- s += fs2us(codecs->MainDll_ErrorPath);
- throw s;
- }
- #endif
-
- throw kNoFormats;
- }
-
- CObjectVector<COpenType> types;
- if (!ParseOpenTypes(*codecs, options.ArcType, types))
- throw kUnsupportedArcTypeMessage;
-
- CIntVector excludedFormats;
- FOR_VECTOR (k, options.ExcludedArcTypes)
- {
- CIntVector tempIndices;
- if (!codecs->FindFormatForArchiveType(options.ExcludedArcTypes[k], tempIndices)
- || tempIndices.Size() != 1)
- throw kUnsupportedArcTypeMessage;
- excludedFormats.AddToUniqueSorted(tempIndices[0]);
- // excludedFormats.Sort();
- }
-
-
- #ifdef EXTERNAL_CODECS
- if (isExtractGroupCommand
- || options.Command.CommandType == NCommandType::kHash
- || options.Command.CommandType == NCommandType::kBenchmark)
- ThrowException_if_Error(__externalCodecs.Load());
- #endif
-
- int retCode = NExitCode::kSuccess;
- HRESULT hresultMain = S_OK;
-
- // bool showStat = options.ShowTime;
-
- /*
- if (!options.EnableHeaders ||
- options.TechMode)
- showStat = false;
- */
-
-
- if (options.Command.CommandType == NCommandType::kInfo)
- {
- CStdOutStream &so = (g_StdStream ? *g_StdStream : g_StdOut);
- unsigned i;
-
- #ifdef EXTERNAL_CODECS
- so << endl << "Libs:" << endl;
- for (i = 0; i < codecs->Libs.Size(); i++)
- {
- PrintLibIndex(so, i);
- so << ' ' << codecs->Libs[i].Path << endl;
- }
- #endif
-
- so << endl << "Formats:" << endl;
-
- const char * const kArcFlags = "KSNFMGOPBELH";
- const unsigned kNumArcFlags = (unsigned)strlen(kArcFlags);
-
- for (i = 0; i < codecs->Formats.Size(); i++)
- {
- const CArcInfoEx &arc = codecs->Formats[i];
-
- #ifdef EXTERNAL_CODECS
- PrintLibIndex(so, arc.LibIndex);
- #else
- so << " ";
- #endif
-
- so << (char)(arc.UpdateEnabled ? 'C' : ' ');
-
- for (unsigned b = 0; b < kNumArcFlags; b++)
- {
- so << (char)
- ((arc.Flags & ((UInt32)1 << b)) != 0 ? kArcFlags[b] : ' ');
- }
-
- so << ' ';
- PrintString(so, arc.Name, 8);
- so << ' ';
- UString s;
-
- FOR_VECTOR (t, arc.Exts)
- {
- if (t != 0)
- s.Add_Space();
- const CArcExtInfo &ext = arc.Exts[t];
- s += ext.Ext;
- if (!ext.AddExt.IsEmpty())
- {
- s += " (";
- s += ext.AddExt;
- s += ')';
- }
- }
-
- PrintString(so, s, 13);
- so << ' ';
-
- if (arc.SignatureOffset != 0)
- so << "offset=" << arc.SignatureOffset << ' ';
-
- FOR_VECTOR(si, arc.Signatures)
- {
- if (si != 0)
- so << " || ";
-
- const CByteBuffer &sig = arc.Signatures[si];
-
- for (size_t j = 0; j < sig.Size(); j++)
- {
- if (j != 0)
- so << ' ';
- Byte b = sig[j];
- if (b > 0x20 && b < 0x80)
- {
- so << (char)b;
- }
- else
- {
- so << GetHex((b >> 4) & 0xF);
- so << GetHex(b & 0xF);
- }
- }
- }
- so << endl;
- }
-
- so << endl << "Codecs:" << endl; // << "Lib ID Name" << endl;
-
- for (i = 0; i < g_NumCodecs; i++)
- {
- const CCodecInfo &cod = *g_Codecs[i];
-
- PrintLibIndex(so, -1);
-
- if (cod.NumStreams == 1)
- so << ' ';
- else
- so << cod.NumStreams;
-
- so << (char)(cod.CreateEncoder ? 'E' : ' ');
- so << (char)(cod.CreateDecoder ? 'D' : ' ');
-
- so << ' ';
- PrintHexId(so, cod.Id);
- so << ' ' << cod.Name << endl;
- }
-
-
- #ifdef EXTERNAL_CODECS
-
- UInt32 numMethods;
- if (codecs->GetNumMethods(&numMethods) == S_OK)
- for (UInt32 j = 0; j < numMethods; j++)
- {
- PrintLibIndex(so, codecs->GetCodec_LibIndex(j));
-
- UInt32 numStreams = codecs->GetCodec_NumStreams(j);
- if (numStreams == 1)
- so << ' ';
- else
- so << numStreams;
-
- so << (char)(codecs->GetCodec_EncoderIsAssigned(j) ? 'E' : ' ');
- so << (char)(codecs->GetCodec_DecoderIsAssigned(j) ? 'D' : ' ');
-
- so << ' ';
- UInt64 id;
- HRESULT res = codecs->GetCodec_Id(j, id);
- if (res != S_OK)
- id = (UInt64)(Int64)-1;
- PrintHexId(so, id);
- so << ' ' << codecs->GetCodec_Name(j) << endl;
- }
-
- #endif
-
-
- so << endl << "Hashers:" << endl; // << " L Size ID Name" << endl;
-
- for (i = 0; i < g_NumHashers; i++)
- {
- const CHasherInfo &codec = *g_Hashers[i];
- PrintLibIndex(so, -1);
- PrintUInt32(so, codec.DigestSize, 4);
- so << ' ';
- PrintHexId(so, codec.Id);
- so << ' ' << codec.Name << endl;
- }
-
- #ifdef EXTERNAL_CODECS
-
- numMethods = codecs->GetNumHashers();
- for (UInt32 j = 0; j < numMethods; j++)
- {
- PrintLibIndex(so, codecs->GetHasherLibIndex(j));
- PrintUInt32(so, codecs->GetHasherDigestSize(j), 4);
- so << ' ';
- PrintHexId(so, codecs->GetHasherId(j));
- so << ' ' << codecs->GetHasherName(j) << endl;
- }
-
- #endif
-
- }
- else if (options.Command.CommandType == NCommandType::kBenchmark)
- {
- CStdOutStream &so = (g_StdStream ? *g_StdStream : g_StdOut);
- hresultMain = BenchCon(EXTERNAL_CODECS_VARS_L
- options.Properties, options.NumIterations, (FILE *)so);
- if (hresultMain == S_FALSE)
- {
- if (g_ErrStream)
- *g_ErrStream << "\nDecoding ERROR\n";
- retCode = NExitCode::kFatalError;
- hresultMain = S_OK;
- }
- }
- else if (isExtractGroupCommand || options.Command.CommandType == NCommandType::kList)
- {
- UStringVector ArchivePathsSorted;
- UStringVector ArchivePathsFullSorted;
-
- if (options.StdInMode)
- {
- ArchivePathsSorted.Add(options.ArcName_for_StdInMode);
- ArchivePathsFullSorted.Add(options.ArcName_for_StdInMode);
- }
- else
- {
- CExtractScanConsole scan;
-
- scan.Init(options.EnableHeaders ? g_StdStream : NULL, g_ErrStream, percentsStream);
- scan.SetWindowWidth(consoleWidth);
-
- if (g_StdStream && options.EnableHeaders)
- *g_StdStream << "Scanning the drive for archives:" << endl;
-
- CDirItemsStat st;
-
- scan.StartScanning();
-
- hresultMain = EnumerateDirItemsAndSort(
- options.arcCensor,
- NWildcard::k_RelatPath,
- UString(), // addPathPrefix
- ArchivePathsSorted,
- ArchivePathsFullSorted,
- st,
- &scan);
-
- scan.CloseScanning();
-
- if (hresultMain == S_OK)
- {
- if (options.EnableHeaders)
- scan.PrintStat(st);
- }
- else
- {
- /*
- if (res != E_ABORT)
- {
- throw CSystemException(res);
- // errorInfo.Message = "Scanning error";
- }
- return res;
- */
- }
- }
-
- if (hresultMain == S_OK)
- if (isExtractGroupCommand)
- {
- CExtractCallbackConsole *ecs = new CExtractCallbackConsole;
- CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
-
- #ifndef _NO_CRYPTO
- ecs->PasswordIsDefined = options.PasswordEnabled;
- ecs->Password = options.Password;
- #endif
-
- ecs->Init(g_StdStream, g_ErrStream, percentsStream);
- ecs->MultiArcMode = (ArchivePathsSorted.Size() > 1);
-
- ecs->LogLevel = options.LogLevel;
- ecs->PercentsNameLevel = percentsNameLevel;
-
- if (percentsStream)
- ecs->SetWindowWidth(consoleWidth);
-
- /*
- COpenCallbackConsole openCallback;
- openCallback.Init(g_StdStream, g_ErrStream);
-
- #ifndef _NO_CRYPTO
- openCallback.PasswordIsDefined = options.PasswordEnabled;
- openCallback.Password = options.Password;
- #endif
- */
-
- CExtractOptions eo;
- (CExtractOptionsBase &)eo = options.ExtractOptions;
-
- eo.StdInMode = options.StdInMode;
- eo.StdOutMode = options.StdOutMode;
- eo.YesToAll = options.YesToAll;
- eo.TestMode = options.Command.IsTestCommand();
-
- #ifndef _SFX
- eo.Properties = options.Properties;
- #endif
-
- UString errorMessage;
- CDecompressStat stat;
- CHashBundle hb;
- IHashCalc *hashCalc = NULL;
-
- if (!options.HashMethods.IsEmpty())
- {
- hashCalc = &hb;
- ThrowException_if_Error(hb.SetMethods(EXTERNAL_CODECS_VARS_L options.HashMethods));
- // hb.Init();
- }
-
- hresultMain = Extract(
- codecs,
- types,
- excludedFormats,
- ArchivePathsSorted,
- ArchivePathsFullSorted,
- options.Censor.Pairs.Front().Head,
- eo, ecs, ecs, hashCalc, errorMessage, stat);
-
- ecs->ClosePercents();
-
- if (!errorMessage.IsEmpty())
- {
- if (g_ErrStream)
- *g_ErrStream << endl << "ERROR:" << endl << errorMessage << endl;
- if (hresultMain == S_OK)
- hresultMain = E_FAIL;
- }
-
- CStdOutStream *so = g_StdStream;
-
- bool isError = false;
-
- if (so)
- {
- *so << endl;
-
- if (ecs->NumTryArcs > 1)
- {
- *so << "Archives: " << ecs->NumTryArcs << endl;
- *so << "OK archives: " << ecs->NumOkArcs << endl;
- }
- }
-
- if (ecs->NumCantOpenArcs != 0)
- {
- isError = true;
- if (so)
- *so << "Can't open as archive: " << ecs->NumCantOpenArcs << endl;
- }
-
- if (ecs->NumArcsWithError != 0)
- {
- isError = true;
- if (so)
- *so << "Archives with Errors: " << ecs->NumArcsWithError << endl;
- }
-
- if (so)
- {
- if (ecs->NumArcsWithWarnings != 0)
- *so << "Archives with Warnings: " << ecs->NumArcsWithWarnings << endl;
-
- if (ecs->NumOpenArcWarnings != 0)
- {
- *so << endl;
- if (ecs->NumOpenArcWarnings != 0)
- *so << "Warnings: " << ecs->NumOpenArcWarnings << endl;
- }
- }
-
- if (ecs->NumOpenArcErrors != 0)
- {
- isError = true;
- if (so)
- {
- *so << endl;
- if (ecs->NumOpenArcErrors != 0)
- *so << "Open Errors: " << ecs->NumOpenArcErrors << endl;
- }
- }
-
- if (isError)
- retCode = NExitCode::kFatalError;
-
- if (so)
- if (ecs->NumArcsWithError != 0 || ecs->NumFileErrors != 0)
- {
- // if (ecs->NumArchives > 1)
- {
- *so << endl;
- if (ecs->NumFileErrors != 0)
- *so << "Sub items Errors: " << ecs->NumFileErrors << endl;
- }
- }
- else if (hresultMain == S_OK)
- {
- if (stat.NumFolders != 0)
- *so << "Folders: " << stat.NumFolders << endl;
- if (stat.NumFiles != 1 || stat.NumFolders != 0 || stat.NumAltStreams != 0)
- *so << "Files: " << stat.NumFiles << endl;
- if (stat.NumAltStreams != 0)
- {
- *so << "Alternate Streams: " << stat.NumAltStreams << endl;
- *so << "Alternate Streams Size: " << stat.AltStreams_UnpackSize << endl;
- }
-
- *so
- << "Size: " << stat.UnpackSize << endl
- << "Compressed: " << stat.PackSize << endl;
- if (hashCalc)
- {
- *so << endl;
- PrintHashStat(*so, hb);
- }
- }
- }
- else
- {
- UInt64 numErrors = 0;
- UInt64 numWarnings = 0;
-
- // options.ExtractNtOptions.StoreAltStreams = true, if -sns[-] is not definmed
-
- hresultMain = ListArchives(
- codecs,
- types,
- excludedFormats,
- options.StdInMode,
- ArchivePathsSorted,
- ArchivePathsFullSorted,
- options.ExtractOptions.NtOptions.AltStreams.Val,
- options.AltStreams.Val, // we don't want to show AltStreams by default
- options.Censor.Pairs.Front().Head,
- options.EnableHeaders,
- options.TechMode,
- #ifndef _NO_CRYPTO
- options.PasswordEnabled,
- options.Password,
- #endif
- &options.Properties,
- numErrors, numWarnings);
-
- if (options.EnableHeaders)
- if (numWarnings > 0)
- g_StdOut << endl << "Warnings: " << numWarnings << endl;
-
- if (numErrors > 0)
- {
- if (options.EnableHeaders)
- g_StdOut << endl << "Errors: " << numErrors << endl;
- retCode = NExitCode::kFatalError;
- }
- }
- }
- else if (options.Command.IsFromUpdateGroup())
- {
- CUpdateOptions &uo = options.UpdateOptions;
- if (uo.SfxMode && uo.SfxModule.IsEmpty())
- uo.SfxModule = kDefaultSfxModule;
-
- COpenCallbackConsole openCallback;
- openCallback.Init(g_StdStream, g_ErrStream, percentsStream);
-
- #ifndef _NO_CRYPTO
- bool passwordIsDefined =
- (options.PasswordEnabled && !options.Password.IsEmpty());
- openCallback.PasswordIsDefined = passwordIsDefined;
- openCallback.Password = options.Password;
- #endif
-
- CUpdateCallbackConsole callback;
- callback.LogLevel = options.LogLevel;
- callback.PercentsNameLevel = percentsNameLevel;
-
- if (percentsStream)
- callback.SetWindowWidth(consoleWidth);
-
- #ifndef _NO_CRYPTO
- callback.PasswordIsDefined = passwordIsDefined;
- callback.AskPassword = (options.PasswordEnabled && options.Password.IsEmpty());
- callback.Password = options.Password;
- #endif
-
- callback.StdOutMode = uo.StdOutMode;
- callback.Init(
- // NULL,
- g_StdStream, g_ErrStream, percentsStream);
-
- CUpdateErrorInfo errorInfo;
-
- /*
- if (!uo.Init(codecs, types, options.ArchiveName))
- throw kUnsupportedUpdateArcType;
- */
- hresultMain = UpdateArchive(codecs,
- types,
- options.ArchiveName,
- options.Censor,
- uo,
- errorInfo, &openCallback, &callback, true);
-
- callback.ClosePercents2();
-
- CStdOutStream *se = g_StdStream;
- if (!se)
- se = g_ErrStream;
-
- retCode = WarningsCheck(hresultMain, callback, errorInfo,
- g_StdStream, se,
- true // options.EnableHeaders
- );
- }
- else if (options.Command.CommandType == NCommandType::kHash)
- {
- const CHashOptions &uo = options.HashOptions;
-
- CHashCallbackConsole callback;
- if (percentsStream)
- callback.SetWindowWidth(consoleWidth);
-
- callback.Init(g_StdStream, g_ErrStream, percentsStream);
- callback.PrintHeaders = options.EnableHeaders;
-
- AString errorInfoString;
- hresultMain = HashCalc(EXTERNAL_CODECS_VARS_L
- options.Censor, uo,
- errorInfoString, &callback);
- CUpdateErrorInfo errorInfo;
- errorInfo.Message = errorInfoString;
- CStdOutStream *se = g_StdStream;
- if (!se)
- se = g_ErrStream;
- retCode = WarningsCheck(hresultMain, callback, errorInfo, g_StdStream, se, options.EnableHeaders);
- }
- else
- ShowMessageAndThrowException(kUserErrorMessage, NExitCode::kUserError);
-
- if (options.ShowTime && g_StdStream)
- PrintStat();
-
- ThrowException_if_Error(hresultMain);
-
- return retCode;
-}
+// Main.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+
+#ifdef _WIN32
+
+#ifndef Z7_OLD_WIN_SDK
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <psapi.h>
+#else
+#include <Psapi.h>
+#endif
+
+#else // Z7_OLD_WIN_SDK
+
+typedef struct _PROCESS_MEMORY_COUNTERS {
+ DWORD cb;
+ DWORD PageFaultCount;
+ SIZE_T PeakWorkingSetSize;
+ SIZE_T WorkingSetSize;
+ SIZE_T QuotaPeakPagedPoolUsage;
+ SIZE_T QuotaPagedPoolUsage;
+ SIZE_T QuotaPeakNonPagedPoolUsage;
+ SIZE_T QuotaNonPagedPoolUsage;
+ SIZE_T PagefileUsage;
+ SIZE_T PeakPagefileUsage;
+} PROCESS_MEMORY_COUNTERS;
+typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS;
+
+#endif // Z7_OLD_WIN_SDK
+
+#else // _WIN32
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/time.h>
+#include <sys/times.h>
+#endif // _WIN32
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/MyInitGuid.h"
+
+#include "../../../Common/CommandLineParser.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/MyException.h"
+#include "../../../Common/StdInStream.h"
+#include "../../../Common/StdOutStream.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/StringToInt.h"
+#include "../../../Common/UTFConvert.h"
+
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/TimeUtils.h"
+#include "../../../Windows/FileDir.h"
+
+#include "../Common/ArchiveCommandLine.h"
+#include "../Common/Bench.h"
+#include "../Common/ExitCode.h"
+#include "../Common/Extract.h"
+
+#ifdef Z7_EXTERNAL_CODECS
+#include "../Common/LoadCodecs.h"
+#endif
+
+#include "../../Common/RegisterCodec.h"
+
+#include "BenchCon.h"
+#include "ConsoleClose.h"
+#include "ExtractCallbackConsole.h"
+#include "HashCon.h"
+#include "List.h"
+#include "OpenCallbackConsole.h"
+#include "UpdateCallbackConsole.h"
+
+#ifdef Z7_PROG_VARIANT_R
+#include "../../../../C/7zVersion.h"
+#else
+#include "../../MyVersion.h"
+#endif
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NCommandLineParser;
+
+#ifdef _WIN32
+extern
+HINSTANCE g_hInstance;
+HINSTANCE g_hInstance = NULL;
+#endif
+
+extern CStdOutStream *g_StdStream;
+extern CStdOutStream *g_ErrStream;
+
+extern unsigned g_NumCodecs;
+extern const CCodecInfo *g_Codecs[];
+
+extern unsigned g_NumHashers;
+extern const CHasherInfo *g_Hashers[];
+
+#ifdef Z7_EXTERNAL_CODECS
+extern
+const CExternalCodecs *g_ExternalCodecs_Ptr;
+const CExternalCodecs *g_ExternalCodecs_Ptr;
+#endif
+
+DECLARE_AND_SET_CLIENT_VERSION_VAR
+
+#if defined(Z7_PROG_VARIANT_Z)
+ #define PROG_POSTFIX "z"
+ #define PROG_POSTFIX_2 " (z)"
+#elif defined(Z7_PROG_VARIANT_R)
+ #define PROG_POSTFIX "r"
+ #define PROG_POSTFIX_2 " (r)"
+#elif !defined(Z7_EXTERNAL_CODECS)
+ #define PROG_POSTFIX "a"
+ #define PROG_POSTFIX_2 " (a)"
+#else
+ #define PROG_POSTFIX ""
+ #define PROG_POSTFIX_2 ""
+#endif
+
+
+static const char * const kCopyrightString = "\n7-Zip"
+ PROG_POSTFIX_2
+ " " MY_VERSION_CPU
+ " : " MY_COPYRIGHT_DATE "\n";
+
+static const char * const kHelpString =
+ "Usage: 7z"
+ PROG_POSTFIX
+ " <command> [<switches>...] <archive_name> [<file_names>...] [@listfile]\n"
+ "\n"
+ "<Commands>\n"
+ " a : Add files to archive\n"
+ " b : Benchmark\n"
+ " d : Delete files from archive\n"
+ " e : Extract files from archive (without using directory names)\n"
+ " h : Calculate hash values for files\n"
+ " i : Show information about supported formats\n"
+ " l : List contents of archive\n"
+ " rn : Rename files in archive\n"
+ " t : Test integrity of archive\n"
+ " u : Update files to archive\n"
+ " x : eXtract files with full paths\n"
+ "\n"
+ "<Switches>\n"
+ " -- : Stop switches and @listfile parsing\n"
+ " -ai[r[-|0]]{@listfile|!wildcard} : Include archives\n"
+ " -ax[r[-|0]]{@listfile|!wildcard} : eXclude archives\n"
+ " -ao{a|s|t|u} : set Overwrite mode\n"
+ " -an : disable archive_name field\n"
+ " -bb[0-3] : set output log level\n"
+ " -bd : disable progress indicator\n"
+ " -bs{o|e|p}{0|1|2} : set output stream for output/error/progress line\n"
+ " -bt : show execution time statistics\n"
+ " -i[r[-|0]]{@listfile|!wildcard} : Include filenames\n"
+ " -m{Parameters} : set compression Method\n"
+ " -mmt[N] : set number of CPU threads\n"
+ " -mx[N] : set compression level: -mx1 (fastest) ... -mx9 (ultra)\n"
+ " -o{Directory} : set Output directory\n"
+ #ifndef Z7_NO_CRYPTO
+ " -p{Password} : set Password\n"
+ #endif
+ " -r[-|0] : Recurse subdirectories for name search\n"
+ " -sa{a|e|s} : set Archive name mode\n"
+ " -scc{UTF-8|WIN|DOS} : set charset for console input/output\n"
+ " -scs{UTF-8|UTF-16LE|UTF-16BE|WIN|DOS|{id}} : set charset for list files\n"
+ " -scrc[CRC32|CRC64|SHA1|SHA256|*] : set hash function for x, e, h commands\n"
+ " -sdel : delete files after compression\n"
+ " -seml[.] : send archive by email\n"
+ " -sfx[{name}] : Create SFX archive\n"
+ " -si[{name}] : read data from stdin\n"
+ " -slp : set Large Pages mode\n"
+ " -slt : show technical information for l (List) command\n"
+ " -snh : store hard links as links\n"
+ " -snl : store symbolic links as links\n"
+ " -sni : store NT security information\n"
+ " -sns[-] : store NTFS alternate streams\n"
+ " -so : write data to stdout\n"
+ " -spd : disable wildcard matching for file names\n"
+ " -spe : eliminate duplication of root folder for extract command\n"
+ " -spf[2] : use fully qualified file paths\n"
+ " -ssc[-] : set sensitive case mode\n"
+ " -sse : stop archive creating, if it can't open some input file\n"
+ " -ssp : do not change Last Access Time of source files while archiving\n"
+ " -ssw : compress shared files\n"
+ " -stl : set archive timestamp from the most recently modified file\n"
+ " -stm{HexMask} : set CPU thread affinity mask (hexadecimal number)\n"
+ " -stx{Type} : exclude archive type\n"
+ " -t{Type} : Set type of archive\n"
+ " -u[-][p#][q#][r#][x#][y#][z#][!newArchiveName] : Update options\n"
+ " -v{Size}[b|k|m|g] : Create volumes\n"
+ " -w[{path}] : assign Work directory. Empty path means a temporary directory\n"
+ " -x[r[-|0]]{@listfile|!wildcard} : eXclude filenames\n"
+ " -y : assume Yes on all queries\n";
+
+// ---------------------------
+// exception messages
+
+static const char * const kEverythingIsOk = "Everything is Ok";
+static const char * const kUserErrorMessage = "Incorrect command line";
+static const char * const kNoFormats = "7-Zip cannot find the code that works with archives.";
+static const char * const kUnsupportedArcTypeMessage = "Unsupported archive type";
+// static const char * const kUnsupportedUpdateArcType = "Can't create archive for that type";
+
+#define kDefaultSfxModule "7zCon.sfx"
+
+Z7_ATTR_NORETURN
+static void ShowMessageAndThrowException(LPCSTR message, NExitCode::EEnum code)
+{
+ if (g_ErrStream)
+ *g_ErrStream << endl << "ERROR: " << message << endl;
+ throw code;
+}
+
+
+#ifdef _WIN32
+#define ShowProgInfo(so)
+#else
+static void ShowProgInfo(CStdOutStream *so)
+{
+ if (!so)
+ return;
+
+ *so
+
+ /*
+ #ifdef __DATE__
+ << " " << __DATE__
+ #endif
+ #ifdef __TIME__
+ << " " << __TIME__
+ #endif
+ */
+
+ << " " << (unsigned)(sizeof(void *)) * 8 << "-bit"
+
+ #ifdef __ILP32__
+ << " ILP32"
+ #endif
+
+ #ifdef __ARM_ARCH
+ << " arm_v:" << __ARM_ARCH
+ #ifdef __ARM_ARCH_ISA_THUMB
+ << " thumb:" << __ARM_ARCH_ISA_THUMB
+ #endif
+ #endif
+ ;
+
+
+
+ #ifdef ENV_HAVE_LOCALE
+ *so << " locale=" << GetLocale();
+ #endif
+ #ifndef _WIN32
+ {
+ const bool is_IsNativeUTF8 = IsNativeUTF8();
+ if (!is_IsNativeUTF8)
+ *so << " UTF8=" << (is_IsNativeUTF8 ? "+" : "-");
+ }
+ if (!g_ForceToUTF8)
+ *so << " use-UTF8=" << (g_ForceToUTF8 ? "+" : "-");
+ {
+ const unsigned wchar_t_size = (unsigned)sizeof(wchar_t);
+ if (wchar_t_size != 4)
+ *so << " wchar_t=" << wchar_t_size * 8 << "-bit";
+ }
+ {
+ const unsigned off_t_size = (unsigned)sizeof(off_t);
+ if (off_t_size != 8)
+ *so << " Files=" << off_t_size * 8 << "-bit";
+ }
+ #endif
+
+ {
+ const UInt32 numCpus = NWindows::NSystem::GetNumberOfProcessors();
+ *so << " Threads:" << numCpus;
+ const UInt64 openMAX= NWindows::NSystem::Get_File_OPEN_MAX();
+ *so << " OPEN_MAX:" << openMAX;
+ {
+ FString temp;
+ NDir::MyGetTempPath(temp);
+ if (!temp.IsEqualTo(STRING_PATH_SEPARATOR "tmp" STRING_PATH_SEPARATOR))
+ *so << " temp_path:" << temp;
+ }
+ }
+
+ #ifdef Z7_7ZIP_ASM
+ *so << ", ASM";
+ #endif
+
+ /*
+ {
+ AString s;
+ GetCpuName(s);
+ s.Trim();
+ *so << ", " << s;
+ }
+
+ #ifdef __ARM_FEATURE_CRC32
+ << " CRC32"
+ #endif
+
+
+ #if (defined MY_CPU_X86_OR_AMD64 || defined(MY_CPU_ARM_OR_ARM64))
+ if (CPU_IsSupported_AES()) *so << ",AES";
+ #endif
+
+ #ifdef MY_CPU_ARM_OR_ARM64
+ if (CPU_IsSupported_CRC32()) *so << ",CRC32";
+ #if defined(_WIN32)
+ if (CPU_IsSupported_CRYPTO()) *so << ",CRYPTO";
+ #else
+ if (CPU_IsSupported_SHA1()) *so << ",SHA1";
+ if (CPU_IsSupported_SHA2()) *so << ",SHA2";
+ #endif
+ #endif
+ */
+
+ *so << endl;
+}
+#endif
+
+static void ShowCopyrightAndHelp(CStdOutStream *so, bool needHelp)
+{
+ if (!so)
+ return;
+ *so << kCopyrightString;
+ // *so << "# CPUs: " << (UInt64)NWindows::NSystem::GetNumberOfProcessors() << endl;
+ ShowProgInfo(so);
+ *so << endl;
+ if (needHelp)
+ *so << kHelpString;
+}
+
+
+static void PrintStringRight(CStdOutStream &so, const char *s, unsigned size)
+{
+ unsigned len = MyStringLen(s);
+ for (unsigned i = len; i < size; i++)
+ so << ' ';
+ so << s;
+}
+
+static void PrintUInt32(CStdOutStream &so, UInt32 val, unsigned size)
+{
+ char s[16];
+ ConvertUInt32ToString(val, s);
+ PrintStringRight(so, s, size);
+}
+
+#ifdef Z7_EXTERNAL_CODECS
+static void PrintNumber(CStdOutStream &so, UInt32 val, unsigned numDigits)
+{
+ AString s;
+ s.Add_UInt32(val);
+ while (s.Len() < numDigits)
+ s.InsertAtFront('0');
+ so << s;
+}
+#endif
+
+static void PrintLibIndex(CStdOutStream &so, int libIndex)
+{
+ if (libIndex >= 0)
+ PrintUInt32(so, (UInt32)libIndex, 2);
+ else
+ so << " ";
+ so << ' ';
+}
+
+static void PrintString(CStdOutStream &so, const UString &s, unsigned size)
+{
+ unsigned len = s.Len();
+ so << s;
+ for (unsigned i = len; i < size; i++)
+ so << ' ';
+}
+
+static inline char GetHex(unsigned val)
+{
+ return (char)((val < 10) ? ('0' + val) : ('A' + (val - 10)));
+}
+
+static void PrintWarningsPaths(const CErrorPathCodes &pc, CStdOutStream &so)
+{
+ FOR_VECTOR(i, pc.Paths)
+ {
+ so.NormalizePrint_UString(fs2us(pc.Paths[i]));
+ so << " : ";
+ so << NError::MyFormatMessage(pc.Codes[i]) << endl;
+ }
+ so << "----------------" << endl;
+}
+
+static int WarningsCheck(HRESULT result, const CCallbackConsoleBase &callback,
+ const CUpdateErrorInfo &errorInfo,
+ CStdOutStream *so,
+ CStdOutStream *se,
+ bool showHeaders)
+{
+ int exitCode = NExitCode::kSuccess;
+
+ if (callback.ScanErrors.Paths.Size() != 0)
+ {
+ if (se)
+ {
+ *se << endl;
+ *se << "Scan WARNINGS for files and folders:" << endl << endl;
+ PrintWarningsPaths(callback.ScanErrors, *se);
+ *se << "Scan WARNINGS: " << callback.ScanErrors.Paths.Size();
+ *se << endl;
+ }
+ exitCode = NExitCode::kWarning;
+ }
+
+ if (result != S_OK || errorInfo.ThereIsError())
+ {
+ if (se)
+ {
+ UString message;
+ if (!errorInfo.Message.IsEmpty())
+ {
+ message += errorInfo.Message.Ptr();
+ message.Add_LF();
+ }
+ {
+ FOR_VECTOR(i, errorInfo.FileNames)
+ {
+ message += fs2us(errorInfo.FileNames[i]);
+ message.Add_LF();
+ }
+ }
+ if (errorInfo.SystemError != 0)
+ {
+ message += NError::MyFormatMessage(errorInfo.SystemError);
+ message.Add_LF();
+ }
+ if (!message.IsEmpty())
+ *se << L"\nError:\n" << message;
+ }
+
+ // we will work with (result) later
+ // throw CSystemException(result);
+ return NExitCode::kFatalError;
+ }
+
+ unsigned numErrors = callback.FailedFiles.Paths.Size();
+ if (numErrors == 0)
+ {
+ if (showHeaders)
+ if (callback.ScanErrors.Paths.Size() == 0)
+ if (so)
+ {
+ if (se)
+ se->Flush();
+ *so << kEverythingIsOk << endl;
+ }
+ }
+ else
+ {
+ if (se)
+ {
+ *se << endl;
+ *se << "WARNINGS for files:" << endl << endl;
+ PrintWarningsPaths(callback.FailedFiles, *se);
+ *se << "WARNING: Cannot open " << numErrors << " file";
+ if (numErrors > 1)
+ *se << 's';
+ *se << endl;
+ }
+ exitCode = NExitCode::kWarning;
+ }
+
+ return exitCode;
+}
+
+static void ThrowException_if_Error(HRESULT res)
+{
+ if (res != S_OK)
+ throw CSystemException(res);
+}
+
+static void PrintNum(UInt64 val, unsigned numDigits, char c = ' ')
+{
+ char temp[64];
+ char *p = temp + 32;
+ ConvertUInt64ToString(val, p);
+ unsigned len = MyStringLen(p);
+ for (; len < numDigits; len++)
+ *--p = c;
+ *g_StdStream << p;
+}
+
+#ifdef _WIN32
+
+static void PrintTime(const char *s, UInt64 val, UInt64 total)
+{
+ *g_StdStream << endl << s << " Time =";
+ const UInt32 kFreq = 10000000;
+ UInt64 sec = val / kFreq;
+ PrintNum(sec, 6);
+ *g_StdStream << '.';
+ UInt32 ms = (UInt32)(val - (sec * kFreq)) / (kFreq / 1000);
+ PrintNum(ms, 3, '0');
+
+ while (val > ((UInt64)1 << 56))
+ {
+ val >>= 1;
+ total >>= 1;
+ }
+
+ UInt64 percent = 0;
+ if (total != 0)
+ percent = val * 100 / total;
+ *g_StdStream << " =";
+ PrintNum(percent, 5);
+ *g_StdStream << '%';
+}
+
+#ifndef UNDER_CE
+
+#define SHIFT_SIZE_VALUE(x, num) (((x) + (1 << (num)) - 1) >> (num))
+
+static void PrintMemUsage(const char *s, UInt64 val)
+{
+ *g_StdStream << " " << s << " Memory =";
+ PrintNum(SHIFT_SIZE_VALUE(val, 20), 7);
+ *g_StdStream << " MB";
+ /*
+ *g_StdStream << " =";
+ PrintNum(SHIFT_SIZE_VALUE(val, 10), 9);
+ *g_StdStream << " KB";
+ */
+ #ifdef Z7_LARGE_PAGES
+ AString lp;
+ Add_LargePages_String(lp);
+ if (!lp.IsEmpty())
+ *g_StdStream << lp;
+ #endif
+}
+
+EXTERN_C_BEGIN
+typedef BOOL (WINAPI *Func_GetProcessMemoryInfo)(HANDLE Process,
+ PPROCESS_MEMORY_COUNTERS ppsmemCounters, DWORD cb);
+typedef BOOL (WINAPI *Func_QueryProcessCycleTime)(HANDLE Process, PULONG64 CycleTime);
+EXTERN_C_END
+
+#endif
+
+static inline UInt64 GetTime64(const FILETIME &t) { return ((UInt64)t.dwHighDateTime << 32) | t.dwLowDateTime; }
+
+static void PrintStat()
+{
+ FILETIME creationTimeFT, exitTimeFT, kernelTimeFT, userTimeFT;
+ if (!
+ #ifdef UNDER_CE
+ ::GetThreadTimes(::GetCurrentThread()
+ #else
+ // NT 3.5
+ ::GetProcessTimes(::GetCurrentProcess()
+ #endif
+ , &creationTimeFT, &exitTimeFT, &kernelTimeFT, &userTimeFT))
+ return;
+ FILETIME curTimeFT;
+ NTime::GetCurUtc_FiTime(curTimeFT);
+
+ #ifndef UNDER_CE
+
+ PROCESS_MEMORY_COUNTERS m;
+ memset(&m, 0, sizeof(m));
+ BOOL memDefined = FALSE;
+ BOOL cycleDefined = FALSE;
+ ULONG64 cycleTime = 0;
+ {
+ /* NT 4.0: GetProcessMemoryInfo() in Psapi.dll
+ Win7: new function K32GetProcessMemoryInfo() in kernel32.dll
+ It's faster to call kernel32.dll code than Psapi.dll code
+ GetProcessMemoryInfo() requires Psapi.lib
+ Psapi.lib in SDK7+ can link to K32GetProcessMemoryInfo in kernel32.dll
+ The program with K32GetProcessMemoryInfo will not work on systems before Win7
+ // memDefined = GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m));
+ */
+ const HMODULE kern = ::GetModuleHandleW(L"kernel32.dll");
+ Func_GetProcessMemoryInfo
+ my_GetProcessMemoryInfo = Z7_GET_PROC_ADDRESS(
+ Func_GetProcessMemoryInfo, kern,
+ "K32GetProcessMemoryInfo");
+ if (!my_GetProcessMemoryInfo)
+ {
+ const HMODULE lib = LoadLibraryW(L"Psapi.dll");
+ if (lib)
+ my_GetProcessMemoryInfo = Z7_GET_PROC_ADDRESS(
+ Func_GetProcessMemoryInfo, lib,
+ "GetProcessMemoryInfo");
+ }
+ if (my_GetProcessMemoryInfo)
+ memDefined = my_GetProcessMemoryInfo(GetCurrentProcess(), &m, sizeof(m));
+ // FreeLibrary(lib);
+ const
+ Func_QueryProcessCycleTime
+ my_QueryProcessCycleTime = Z7_GET_PROC_ADDRESS(
+ Func_QueryProcessCycleTime, kern,
+ "QueryProcessCycleTime");
+ if (my_QueryProcessCycleTime)
+ cycleDefined = my_QueryProcessCycleTime(GetCurrentProcess(), &cycleTime);
+ }
+
+ #endif
+
+ UInt64 curTime = GetTime64(curTimeFT);
+ UInt64 creationTime = GetTime64(creationTimeFT);
+ UInt64 kernelTime = GetTime64(kernelTimeFT);
+ UInt64 userTime = GetTime64(userTimeFT);
+
+ UInt64 totalTime = curTime - creationTime;
+
+ PrintTime("Kernel ", kernelTime, totalTime);
+
+ const UInt64 processTime = kernelTime + userTime;
+
+ #ifndef UNDER_CE
+ if (cycleDefined)
+ {
+ *g_StdStream << " Cnt:";
+ PrintNum(cycleTime / 1000000, 15);
+ *g_StdStream << " MCycles";
+ }
+ #endif
+
+ PrintTime("User ", userTime, totalTime);
+
+ #ifndef UNDER_CE
+ if (cycleDefined)
+ {
+ *g_StdStream << " Freq (cnt/ptime):";
+ UInt64 us = processTime / 10;
+ if (us == 0)
+ us = 1;
+ PrintNum(cycleTime / us, 6);
+ *g_StdStream << " MHz";
+ }
+ #endif
+
+ PrintTime("Process", processTime, totalTime);
+ #ifndef UNDER_CE
+ if (memDefined) PrintMemUsage("Virtual ", m.PeakPagefileUsage);
+ #endif
+
+ PrintTime("Global ", totalTime, totalTime);
+ #ifndef UNDER_CE
+ if (memDefined) PrintMemUsage("Physical", m.PeakWorkingSetSize);
+ #endif
+ *g_StdStream << endl;
+}
+
+
+#else // ! _WIN32
+
+static UInt64 Get_timeofday_us()
+{
+ struct timeval now;
+ if (gettimeofday(&now, NULL) == 0)
+ return (UInt64)now.tv_sec * 1000000 + (UInt64)now.tv_usec;
+ return 0;
+}
+
+static void PrintTime(const char *s, UInt64 val, UInt64 total_us, UInt64 kFreq)
+{
+ *g_StdStream << endl << s << " Time =";
+
+ {
+ UInt64 sec, ms;
+
+ if (kFreq == 0)
+ {
+ sec = val / 1000000;
+ ms = val % 1000000 / 1000;
+ }
+ else
+ {
+ sec = val / kFreq;
+ ms = (UInt32)((val - (sec * kFreq)) * 1000 / kFreq);
+ }
+
+ PrintNum(sec, 6);
+ *g_StdStream << '.';
+ PrintNum(ms, 3, '0');
+ }
+
+ if (total_us == 0)
+ return;
+
+ UInt64 percent = 0;
+ if (kFreq == 0)
+ percent = val * 100 / total_us;
+ else
+ {
+ const UInt64 kMaxVal = (UInt64)(Int64)-1;
+ UInt32 m = 100000000;
+ for (;;)
+ {
+ if (m == 0 || kFreq == 0)
+ break;
+ if (kMaxVal / m > val &&
+ kMaxVal / kFreq > total_us)
+ break;
+ if (val > m)
+ val >>= 1;
+ else
+ m >>= 1;
+ if (kFreq > total_us)
+ kFreq >>= 1;
+ else
+ total_us >>= 1;
+ }
+ const UInt64 total = kFreq * total_us;
+ if (total != 0)
+ percent = val * m / total;
+ }
+ *g_StdStream << " =";
+ PrintNum(percent, 5);
+ *g_StdStream << '%';
+}
+
+static void PrintStat(const UInt64 startTime)
+{
+ tms t;
+ /* clock_t res = */ times(&t);
+ const UInt64 totalTime = Get_timeofday_us() - startTime;
+ const UInt64 kFreq = (UInt64)sysconf(_SC_CLK_TCK);
+ PrintTime("Kernel ", (UInt64)t.tms_stime, totalTime, kFreq);
+ PrintTime("User ", (UInt64)t.tms_utime, totalTime, kFreq);
+ PrintTime("Process", (UInt64)t.tms_utime + (UInt64)t.tms_stime, totalTime, kFreq);
+ PrintTime("Global ", totalTime, totalTime, 0);
+ *g_StdStream << endl;
+}
+
+#endif // ! _WIN32
+
+
+
+
+
+static void PrintHexId(CStdOutStream &so, UInt64 id)
+{
+ char s[32];
+ ConvertUInt64ToHex(id, s);
+ PrintStringRight(so, s, 8);
+}
+
+#ifndef _WIN32
+void Set_ModuleDirPrefix_From_ProgArg0(const char *s);
+#endif
+
+int Main2(
+ #ifndef _WIN32
+ int numArgs, char *args[]
+ #endif
+);
+int Main2(
+ #ifndef _WIN32
+ int numArgs, char *args[]
+ #endif
+)
+{
+ #if defined(MY_CPU_SIZEOF_POINTER)
+ { unsigned k = sizeof(void *); if (k != MY_CPU_SIZEOF_POINTER) throw "incorrect MY_CPU_PTR_SIZE"; }
+ #endif
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ SetFileApisToOEM();
+ #endif
+
+ #ifdef ENV_HAVE_LOCALE
+ // printf("\nBefore SetLocale() : %s\n", IsNativeUtf8() ? "NATIVE UTF-8" : "IS NOT NATIVE UTF-8");
+ MY_SetLocale();
+ // printf("\nAfter SetLocale() : %s\n", IsNativeUtf8() ? "NATIVE UTF-8" : "IS NOT NATIVE UTF-8");
+ #endif
+
+ #ifndef _WIN32
+ const UInt64 startTime = Get_timeofday_us();
+ #endif
+
+ /*
+ {
+ g_StdOut << "DWORD:" << (unsigned)sizeof(DWORD);
+ g_StdOut << " LONG:" << (unsigned)sizeof(LONG);
+ g_StdOut << " long:" << (unsigned)sizeof(long);
+ #ifdef _WIN64
+ // g_StdOut << " long long:" << (unsigned)sizeof(long long);
+ #endif
+ g_StdOut << " int:" << (unsigned)sizeof(int);
+ g_StdOut << " void*:" << (unsigned)sizeof(void *);
+ g_StdOut << endl;
+ }
+ */
+
+ UStringVector commandStrings;
+
+ #ifdef _WIN32
+ NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);
+ #else
+ {
+ if (numArgs > 0)
+ Set_ModuleDirPrefix_From_ProgArg0(args[0]);
+
+ for (int i = 0; i < numArgs; i++)
+ {
+ AString a (args[i]);
+ /*
+ printf("\n%d %s :", i, a.Ptr());
+ for (unsigned k = 0; k < a.Len(); k++)
+ printf(" %2x", (unsigned)(Byte)a[k]);
+ */
+ const UString s = MultiByteToUnicodeString(a);
+ commandStrings.Add(s);
+ }
+ // printf("\n");
+ }
+
+ #endif
+
+ #ifndef UNDER_CE
+ if (commandStrings.Size() > 0)
+ commandStrings.Delete(0);
+ #endif
+
+ if (commandStrings.Size() == 0)
+ {
+ ShowCopyrightAndHelp(g_StdStream, true);
+ return 0;
+ }
+
+ CArcCmdLineOptions options;
+
+ CArcCmdLineParser parser;
+
+ parser.Parse1(commandStrings, options);
+
+ g_StdOut.IsTerminalMode = options.IsStdOutTerminal;
+ g_StdErr.IsTerminalMode = options.IsStdErrTerminal;
+
+ if (options.Number_for_Out != k_OutStream_stdout)
+ g_StdStream = (options.Number_for_Out == k_OutStream_stderr ? &g_StdErr : NULL);
+
+ if (options.Number_for_Errors != k_OutStream_stderr)
+ g_ErrStream = (options.Number_for_Errors == k_OutStream_stdout ? &g_StdOut : NULL);
+
+ CStdOutStream *percentsStream = NULL;
+ if (options.Number_for_Percents != k_OutStream_disabled)
+ percentsStream = (options.Number_for_Percents == k_OutStream_stderr) ? &g_StdErr : &g_StdOut;
+
+ if (options.HelpMode)
+ {
+ ShowCopyrightAndHelp(g_StdStream, true);
+ return 0;
+ }
+
+ if (options.EnableHeaders)
+ {
+ ShowCopyrightAndHelp(g_StdStream, false);
+ if (!parser.Parse1Log.IsEmpty())
+ *g_StdStream << parser.Parse1Log;
+ }
+
+ parser.Parse2(options);
+
+ {
+ int cp = options.ConsoleCodePage;
+
+ int stdout_cp = cp;
+ int stderr_cp = cp;
+ int stdin_cp = cp;
+
+ /*
+ // these cases are complicated.
+ // maybe we must use CRT functions instead of console WIN32.
+ // different Windows/CRT versions also can work different ways.
+ // so the following code was not enabled:
+ if (cp == -1)
+ {
+ // we set CodePage only if stream is attached to terminal
+ // maybe we should set CodePage even if is not terminal?
+ #ifdef _WIN32
+ {
+ UINT ccp = GetConsoleOutputCP();
+ if (ccp != 0)
+ {
+ if (options.IsStdOutTerminal) stdout_cp = ccp;
+ if (options.IsStdErrTerminal) stderr_cp = ccp;
+ }
+ }
+ if (options.IsInTerminal)
+ {
+ UINT ccp = GetConsoleCP();
+ if (ccp != 0) stdin_cp = ccp;
+ }
+ #endif
+ }
+ */
+
+ if (stdout_cp != -1) g_StdOut.CodePage = stdout_cp;
+ if (stderr_cp != -1) g_StdErr.CodePage = stderr_cp;
+ if (stdin_cp != -1) g_StdIn.CodePage = stdin_cp;
+ }
+
+ unsigned percentsNameLevel = 1;
+ if (options.LogLevel == 0 || options.Number_for_Percents != options.Number_for_Out)
+ percentsNameLevel = 2;
+
+ unsigned consoleWidth = 80;
+
+ if (percentsStream)
+ {
+ #ifdef _WIN32
+
+ #if !defined(UNDER_CE)
+ CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
+ if (GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &consoleInfo))
+ consoleWidth = (unsigned)(unsigned short)consoleInfo.dwSize.X;
+ #endif
+
+ #else
+
+ struct winsize w;
+ if (ioctl(0, TIOCGWINSZ, &w) == 0)
+ consoleWidth = w.ws_col;
+
+ #endif
+ }
+
+ CREATE_CODECS_OBJECT
+
+ codecs->CaseSensitive_Change = options.CaseSensitive_Change;
+ codecs->CaseSensitive = options.CaseSensitive;
+ ThrowException_if_Error(codecs->Load());
+ Codecs_AddHashArcHandler(codecs);
+
+ #ifdef Z7_EXTERNAL_CODECS
+ {
+ g_ExternalCodecs_Ptr = &_externalCodecs;
+ UString s;
+ codecs->GetCodecsErrorMessage(s);
+ if (!s.IsEmpty())
+ {
+ CStdOutStream &so = (g_StdStream ? *g_StdStream : g_StdOut);
+ so << endl << s << endl;
+ }
+ }
+ #endif
+
+ const bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
+
+ if (codecs->Formats.Size() == 0 &&
+ (isExtractGroupCommand
+ || options.Command.CommandType == NCommandType::kList
+ || options.Command.IsFromUpdateGroup()))
+ {
+ #ifdef Z7_EXTERNAL_CODECS
+ if (!codecs->MainDll_ErrorPath.IsEmpty())
+ {
+ UString s ("Can't load module: ");
+ s += fs2us(codecs->MainDll_ErrorPath);
+ throw s;
+ }
+ #endif
+ throw kNoFormats;
+ }
+
+ CObjectVector<COpenType> types;
+ if (!ParseOpenTypes(*codecs, options.ArcType, types))
+ {
+ throw kUnsupportedArcTypeMessage;
+ }
+
+
+ CIntVector excludedFormats;
+ FOR_VECTOR (k, options.ExcludedArcTypes)
+ {
+ CIntVector tempIndices;
+ if (!codecs->FindFormatForArchiveType(options.ExcludedArcTypes[k], tempIndices)
+ || tempIndices.Size() != 1)
+ throw kUnsupportedArcTypeMessage;
+
+
+
+ excludedFormats.AddToUniqueSorted(tempIndices[0]);
+ // excludedFormats.Sort();
+ }
+
+ #ifdef Z7_EXTERNAL_CODECS
+ if (isExtractGroupCommand
+ || options.Command.IsFromUpdateGroup()
+ || options.Command.CommandType == NCommandType::kHash
+ || options.Command.CommandType == NCommandType::kBenchmark)
+ ThrowException_if_Error(_externalCodecs.Load());
+ #endif
+
+ int retCode = NExitCode::kSuccess;
+ HRESULT hresultMain = S_OK;
+
+ // bool showStat = options.ShowTime;
+
+ /*
+ if (!options.EnableHeaders ||
+ options.TechMode)
+ showStat = false;
+ */
+
+
+ if (options.Command.CommandType == NCommandType::kInfo)
+ {
+ CStdOutStream &so = (g_StdStream ? *g_StdStream : g_StdOut);
+ unsigned i;
+
+ #ifdef Z7_EXTERNAL_CODECS
+ so << endl << "Libs:" << endl;
+ for (i = 0; i < codecs->Libs.Size(); i++)
+ {
+ PrintLibIndex(so, (int)i);
+ const CCodecLib &lib = codecs->Libs[i];
+ // if (lib.Version != 0)
+ so << ": " << (lib.Version >> 16) << ".";
+ PrintNumber(so, lib.Version & 0xffff, 2);
+ so << " : " << lib.Path << endl;
+ }
+ #endif
+
+ so << endl << "Formats:" << endl;
+
+ const char * const kArcFlags = "KSNFMGOPBELHXCc+a+m+r+";
+ const char * const kArcTimeFlags = "wudn";
+ const unsigned kNumArcFlags = (unsigned)strlen(kArcFlags);
+ const unsigned kNumArcTimeFlags = (unsigned)strlen(kArcTimeFlags);
+
+ for (i = 0; i < codecs->Formats.Size(); i++)
+ {
+ const CArcInfoEx &arc = codecs->Formats[i];
+
+ #ifdef Z7_EXTERNAL_CODECS
+ PrintLibIndex(so, arc.LibIndex);
+ #else
+ so << " ";
+ #endif
+
+ so << (char)(arc.UpdateEnabled ? 'C' : ' ');
+
+ {
+ unsigned b;
+ for (b = 0; b < kNumArcFlags; b++)
+ so << (char)((arc.Flags & ((UInt32)1 << b)) != 0 ? kArcFlags[b] : '.');
+ so << ' ';
+ }
+
+ if (arc.TimeFlags != 0)
+ {
+ unsigned b;
+ for (b = 0; b < kNumArcTimeFlags; b++)
+ so << (char)((arc.TimeFlags & ((UInt32)1 << b)) != 0 ? kArcTimeFlags[b] : '.');
+ so << arc.Get_DefaultTimePrec();
+ so << ' ';
+ }
+
+ so << ' ';
+ PrintString(so, arc.Name, 8);
+ so << ' ';
+ UString s;
+
+ FOR_VECTOR (t, arc.Exts)
+ {
+ if (t != 0)
+ s.Add_Space();
+ const CArcExtInfo &ext = arc.Exts[t];
+ s += ext.Ext;
+ if (!ext.AddExt.IsEmpty())
+ {
+ s += " (";
+ s += ext.AddExt;
+ s += ')';
+ }
+ }
+
+ PrintString(so, s, 13);
+ so << ' ';
+
+ if (arc.SignatureOffset != 0)
+ so << "offset=" << arc.SignatureOffset << ' ';
+
+ // so << "numSignatures = " << arc.Signatures.Size() << " ";
+
+ FOR_VECTOR(si, arc.Signatures)
+ {
+ if (si != 0)
+ so << " || ";
+
+ const CByteBuffer &sig = arc.Signatures[si];
+
+ for (size_t j = 0; j < sig.Size(); j++)
+ {
+ if (j != 0)
+ so << ' ';
+ Byte b = sig[j];
+ if (b > 0x20 && b < 0x80)
+ {
+ so << (char)b;
+ }
+ else
+ {
+ so << GetHex((b >> 4) & 0xF);
+ so << GetHex(b & 0xF);
+ }
+ }
+ }
+ so << endl;
+ }
+
+ so << endl << "Codecs:" << endl; // << "Lib ID Name" << endl;
+
+ for (i = 0; i < g_NumCodecs; i++)
+ {
+ const CCodecInfo &cod = *g_Codecs[i];
+
+ PrintLibIndex(so, -1);
+
+ if (cod.NumStreams == 1)
+ so << ' ';
+ else
+ so << cod.NumStreams;
+
+ so << (char)(cod.CreateEncoder ? 'E' : ' ');
+ so << (char)(cod.CreateDecoder ? 'D' : ' ');
+ so << (char)(cod.IsFilter ? 'F' : ' ');
+
+ so << ' ';
+ PrintHexId(so, cod.Id);
+ so << ' ' << cod.Name << endl;
+ }
+
+
+ #ifdef Z7_EXTERNAL_CODECS
+
+ UInt32 numMethods;
+ if (_externalCodecs.GetCodecs->GetNumMethods(&numMethods) == S_OK)
+ for (UInt32 j = 0; j < numMethods; j++)
+ {
+ PrintLibIndex(so, codecs->GetCodec_LibIndex(j));
+
+ UInt32 numStreams = codecs->GetCodec_NumStreams(j);
+ if (numStreams == 1)
+ so << ' ';
+ else
+ so << numStreams;
+
+ so << (char)(codecs->GetCodec_EncoderIsAssigned(j) ? 'E' : ' ');
+ so << (char)(codecs->GetCodec_DecoderIsAssigned(j) ? 'D' : ' ');
+ {
+ bool isFilter_Assigned;
+ const bool isFilter = codecs->GetCodec_IsFilter(j, isFilter_Assigned);
+ so << (char)(isFilter ? 'F' : isFilter_Assigned ? ' ' : '*');
+ }
+
+
+ so << ' ';
+ UInt64 id;
+ HRESULT res = codecs->GetCodec_Id(j, id);
+ if (res != S_OK)
+ id = (UInt64)(Int64)-1;
+ PrintHexId(so, id);
+ so << ' ' << codecs->GetCodec_Name(j) << endl;
+ }
+
+ #endif
+
+
+ so << endl << "Hashers:" << endl; // << " L Size ID Name" << endl;
+
+ for (i = 0; i < g_NumHashers; i++)
+ {
+ const CHasherInfo &codec = *g_Hashers[i];
+ PrintLibIndex(so, -1);
+ PrintUInt32(so, codec.DigestSize, 4);
+ so << ' ';
+ PrintHexId(so, codec.Id);
+ so << ' ' << codec.Name << endl;
+ }
+
+ #ifdef Z7_EXTERNAL_CODECS
+
+ numMethods = _externalCodecs.GetHashers->GetNumHashers();
+ for (UInt32 j = 0; j < numMethods; j++)
+ {
+ PrintLibIndex(so, codecs->GetHasherLibIndex(j));
+ PrintUInt32(so, codecs->GetHasherDigestSize(j), 4);
+ so << ' ';
+ PrintHexId(so, codecs->GetHasherId(j));
+ so << ' ' << codecs->GetHasherName(j) << endl;
+ }
+
+ #endif
+
+ }
+ else if (options.Command.CommandType == NCommandType::kBenchmark)
+ {
+ CStdOutStream &so = (g_StdStream ? *g_StdStream : g_StdOut);
+ hresultMain = BenchCon(EXTERNAL_CODECS_VARS_L
+ options.Properties, options.NumIterations, (FILE *)so);
+ if (hresultMain == S_FALSE)
+ {
+ so << endl;
+ if (g_ErrStream)
+ *g_ErrStream << "\nDecoding ERROR\n";
+ retCode = NExitCode::kFatalError;
+ hresultMain = S_OK;
+ }
+ }
+ else if (isExtractGroupCommand || options.Command.CommandType == NCommandType::kList)
+ {
+ UStringVector ArchivePathsSorted;
+ UStringVector ArchivePathsFullSorted;
+
+ if (options.StdInMode)
+ {
+ ArchivePathsSorted.Add(options.ArcName_for_StdInMode);
+ ArchivePathsFullSorted.Add(options.ArcName_for_StdInMode);
+ }
+ else
+ {
+ CExtractScanConsole scan;
+
+ scan.Init(options.EnableHeaders ? g_StdStream : NULL, g_ErrStream, percentsStream);
+ scan.SetWindowWidth(consoleWidth);
+
+ if (g_StdStream && options.EnableHeaders)
+ *g_StdStream << "Scanning the drive for archives:" << endl;
+
+ CDirItemsStat st;
+
+ scan.StartScanning();
+
+ hresultMain = EnumerateDirItemsAndSort(
+ options.arcCensor,
+ NWildcard::k_RelatPath,
+ UString(), // addPathPrefix
+ ArchivePathsSorted,
+ ArchivePathsFullSorted,
+ st,
+ &scan);
+
+ scan.CloseScanning();
+
+ if (hresultMain == S_OK)
+ {
+ if (options.EnableHeaders)
+ scan.PrintStat(st);
+ }
+ else
+ {
+ /*
+ if (res != E_ABORT)
+ {
+ throw CSystemException(res);
+ // errorInfo.Message = "Scanning error";
+ }
+ return res;
+ */
+ }
+ }
+
+ if (hresultMain == S_OK) {
+ if (isExtractGroupCommand)
+ {
+ CExtractCallbackConsole *ecs = new CExtractCallbackConsole;
+ CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
+
+ #ifndef Z7_NO_CRYPTO
+ ecs->PasswordIsDefined = options.PasswordEnabled;
+ ecs->Password = options.Password;
+ #endif
+
+ ecs->Init(g_StdStream, g_ErrStream, percentsStream);
+ ecs->MultiArcMode = (ArchivePathsSorted.Size() > 1);
+
+ ecs->LogLevel = options.LogLevel;
+ ecs->PercentsNameLevel = percentsNameLevel;
+
+ if (percentsStream)
+ ecs->SetWindowWidth(consoleWidth);
+
+ /*
+ COpenCallbackConsole openCallback;
+ openCallback.Init(g_StdStream, g_ErrStream);
+
+ #ifndef Z7_NO_CRYPTO
+ openCallback.PasswordIsDefined = options.PasswordEnabled;
+ openCallback.Password = options.Password;
+ #endif
+ */
+
+ CExtractOptions eo;
+ (CExtractOptionsBase &)eo = options.ExtractOptions;
+
+ eo.StdInMode = options.StdInMode;
+ eo.StdOutMode = options.StdOutMode;
+ eo.YesToAll = options.YesToAll;
+ eo.TestMode = options.Command.IsTestCommand();
+
+ #ifndef Z7_SFX
+ eo.Properties = options.Properties;
+ #endif
+
+ UString errorMessage;
+ CDecompressStat stat;
+ CHashBundle hb;
+ IHashCalc *hashCalc = NULL;
+
+ if (!options.HashMethods.IsEmpty())
+ {
+ hashCalc = &hb;
+ ThrowException_if_Error(hb.SetMethods(EXTERNAL_CODECS_VARS_L options.HashMethods));
+ // hb.Init();
+ }
+
+ hresultMain = Extract(
+ // EXTERNAL_CODECS_VARS_L
+ codecs,
+ types,
+ excludedFormats,
+ ArchivePathsSorted,
+ ArchivePathsFullSorted,
+ options.Censor.Pairs.Front().Head,
+ eo,
+ ecs, ecs, ecs,
+ hashCalc, errorMessage, stat);
+
+ ecs->ClosePercents();
+
+ if (!errorMessage.IsEmpty())
+ {
+ if (g_ErrStream)
+ *g_ErrStream << endl << "ERROR:" << endl << errorMessage << endl;
+ if (hresultMain == S_OK)
+ hresultMain = E_FAIL;
+ }
+
+ CStdOutStream *so = g_StdStream;
+
+ bool isError = false;
+
+ if (so)
+ {
+ *so << endl;
+
+ if (ecs->NumTryArcs > 1)
+ {
+ *so << "Archives: " << ecs->NumTryArcs << endl;
+ *so << "OK archives: " << ecs->NumOkArcs << endl;
+ }
+ }
+
+ if (ecs->NumCantOpenArcs != 0)
+ {
+ isError = true;
+ if (so)
+ *so << "Can't open as archive: " << ecs->NumCantOpenArcs << endl;
+ }
+
+ if (ecs->NumArcsWithError != 0)
+ {
+ isError = true;
+ if (so)
+ *so << "Archives with Errors: " << ecs->NumArcsWithError << endl;
+ }
+
+ if (so)
+ {
+ if (ecs->NumArcsWithWarnings != 0)
+ *so << "Archives with Warnings: " << ecs->NumArcsWithWarnings << endl;
+
+ if (ecs->NumOpenArcWarnings != 0)
+ {
+ *so << endl;
+ if (ecs->NumOpenArcWarnings != 0)
+ *so << "Warnings: " << ecs->NumOpenArcWarnings << endl;
+ }
+ }
+
+ if (ecs->NumOpenArcErrors != 0)
+ {
+ isError = true;
+ if (so)
+ {
+ *so << endl;
+ if (ecs->NumOpenArcErrors != 0)
+ *so << "Open Errors: " << ecs->NumOpenArcErrors << endl;
+ }
+ }
+
+ if (isError)
+ retCode = NExitCode::kFatalError;
+
+ if (so) {
+ if (ecs->NumArcsWithError != 0 || ecs->NumFileErrors != 0)
+ {
+ // if (ecs->NumArchives > 1)
+ {
+ *so << endl;
+ if (ecs->NumFileErrors != 0)
+ *so << "Sub items Errors: " << ecs->NumFileErrors << endl;
+ }
+ }
+ else if (hresultMain == S_OK)
+ {
+ if (stat.NumFolders != 0)
+ *so << "Folders: " << stat.NumFolders << endl;
+ if (stat.NumFiles != 1 || stat.NumFolders != 0 || stat.NumAltStreams != 0)
+ *so << "Files: " << stat.NumFiles << endl;
+ if (stat.NumAltStreams != 0)
+ {
+ *so << "Alternate Streams: " << stat.NumAltStreams << endl;
+ *so << "Alternate Streams Size: " << stat.AltStreams_UnpackSize << endl;
+ }
+
+ *so
+ << "Size: " << stat.UnpackSize << endl
+ << "Compressed: " << stat.PackSize << endl;
+ if (hashCalc)
+ {
+ *so << endl;
+ PrintHashStat(*so, hb);
+ }
+ }
+ } // if (so)
+ }
+ else // if_(!isExtractGroupCommand)
+ {
+ UInt64 numErrors = 0;
+ UInt64 numWarnings = 0;
+
+ // options.ExtractNtOptions.StoreAltStreams = true, if -sns[-] is not definmed
+
+ CListOptions lo;
+ lo.ExcludeDirItems = options.Censor.ExcludeDirItems;
+ lo.ExcludeFileItems = options.Censor.ExcludeFileItems;
+
+ hresultMain = ListArchives(
+ lo,
+ codecs,
+ types,
+ excludedFormats,
+ options.StdInMode,
+ ArchivePathsSorted,
+ ArchivePathsFullSorted,
+ options.ExtractOptions.NtOptions.AltStreams.Val,
+ options.AltStreams.Val, // we don't want to show AltStreams by default
+ options.Censor.Pairs.Front().Head,
+ options.EnableHeaders,
+ options.TechMode,
+ #ifndef Z7_NO_CRYPTO
+ options.PasswordEnabled,
+ options.Password,
+ #endif
+ &options.Properties,
+ numErrors, numWarnings);
+
+ if (options.EnableHeaders)
+ if (numWarnings > 0)
+ g_StdOut << endl << "Warnings: " << numWarnings << endl;
+
+ if (numErrors > 0)
+ {
+ if (options.EnableHeaders)
+ g_StdOut << endl << "Errors: " << numErrors << endl;
+ retCode = NExitCode::kFatalError;
+ }
+ } // if_(isExtractGroupCommand)
+ } // if_(hresultMain == S_OK)
+ }
+ else if (options.Command.IsFromUpdateGroup())
+ {
+ CUpdateOptions &uo = options.UpdateOptions;
+ if (uo.SfxMode && uo.SfxModule.IsEmpty())
+ uo.SfxModule = kDefaultSfxModule;
+
+ COpenCallbackConsole openCallback;
+ openCallback.Init(g_StdStream, g_ErrStream, percentsStream);
+
+ #ifndef Z7_NO_CRYPTO
+ bool passwordIsDefined =
+ (options.PasswordEnabled && !options.Password.IsEmpty());
+ openCallback.PasswordIsDefined = passwordIsDefined;
+ openCallback.Password = options.Password;
+ #endif
+
+ CUpdateCallbackConsole callback;
+ callback.LogLevel = options.LogLevel;
+ callback.PercentsNameLevel = percentsNameLevel;
+
+ if (percentsStream)
+ callback.SetWindowWidth(consoleWidth);
+
+ #ifndef Z7_NO_CRYPTO
+ callback.PasswordIsDefined = passwordIsDefined;
+ callback.AskPassword = (options.PasswordEnabled && options.Password.IsEmpty());
+ callback.Password = options.Password;
+ #endif
+
+ callback.StdOutMode = uo.StdOutMode;
+ callback.Init(
+ // NULL,
+ g_StdStream, g_ErrStream, percentsStream);
+
+ CUpdateErrorInfo errorInfo;
+
+ /*
+ if (!uo.Init(codecs, types, options.ArchiveName))
+ throw kUnsupportedUpdateArcType;
+ */
+ hresultMain = UpdateArchive(codecs,
+ types,
+ options.ArchiveName,
+ options.Censor,
+ uo,
+ errorInfo, &openCallback, &callback, true);
+
+ callback.ClosePercents2();
+
+ CStdOutStream *se = g_StdStream;
+ if (!se)
+ se = g_ErrStream;
+
+ retCode = WarningsCheck(hresultMain, callback, errorInfo,
+ g_StdStream, se,
+ true // options.EnableHeaders
+ );
+ }
+ else if (options.Command.CommandType == NCommandType::kHash)
+ {
+ const CHashOptions &uo = options.HashOptions;
+
+ CHashCallbackConsole callback;
+ if (percentsStream)
+ callback.SetWindowWidth(consoleWidth);
+
+ callback.Init(g_StdStream, g_ErrStream, percentsStream);
+ callback.PrintHeaders = options.EnableHeaders;
+ callback.PrintFields = options.ListFields;
+
+ AString errorInfoString;
+ hresultMain = HashCalc(EXTERNAL_CODECS_VARS_L
+ options.Censor, uo,
+ errorInfoString, &callback);
+ CUpdateErrorInfo errorInfo;
+ errorInfo.Message = errorInfoString;
+ CStdOutStream *se = g_StdStream;
+ if (!se)
+ se = g_ErrStream;
+ retCode = WarningsCheck(hresultMain, callback, errorInfo, g_StdStream, se, options.EnableHeaders);
+ }
+ else
+ ShowMessageAndThrowException(kUserErrorMessage, NExitCode::kUserError);
+
+ if (options.ShowTime && g_StdStream)
+ PrintStat(
+ #ifndef _WIN32
+ startTime
+ #endif
+ );
+
+ ThrowException_if_Error(hresultMain);
+
+ return retCode;
+}
diff --git a/CPP/7zip/UI/Console/MainAr.cpp b/CPP/7zip/UI/Console/MainAr.cpp
index 1d6c5a4..80f84f5 100644
--- a/CPP/7zip/UI/Console/MainAr.cpp
+++ b/CPP/7zip/UI/Console/MainAr.cpp
@@ -1,175 +1,227 @@
-// MainAr.cpp
-
-#include "StdAfx.h"
-
-#ifdef _WIN32
-#include "../../../../C/DllSecur.h"
-#endif
-
-#include "../../../Common/MyException.h"
-#include "../../../Common/StdOutStream.h"
-
-#include "../../../Windows/ErrorMsg.h"
-#include "../../../Windows/NtCheck.h"
-
-#include "../Common/ArchiveCommandLine.h"
-#include "../Common/ExitCode.h"
-
-#include "ConsoleClose.h"
-
-using namespace NWindows;
-
-CStdOutStream *g_StdStream = NULL;
-CStdOutStream *g_ErrStream = NULL;
-
-extern int Main2(
- #ifndef _WIN32
- int numArgs, char *args[]
- #endif
-);
-
-static const char * const kException_CmdLine_Error_Message = "Command Line Error:";
-static const char * const kExceptionErrorMessage = "ERROR:";
-static const char * const kUserBreakMessage = "Break signaled";
-static const char * const kMemoryExceptionMessage = "ERROR: Can't allocate required memory!";
-static const char * const kUnknownExceptionMessage = "Unknown Error";
-static const char * const kInternalExceptionMessage = "\n\nInternal Error #";
-
-static void FlushStreams()
-{
- if (g_StdStream)
- g_StdStream->Flush();
-}
-
-static void PrintError(const char *message)
-{
- FlushStreams();
- if (g_ErrStream)
- *g_ErrStream << "\n\n" << message << endl;
-}
-
-#define NT_CHECK_FAIL_ACTION *g_StdStream << "Unsupported Windows version"; return NExitCode::kFatalError;
-
-int MY_CDECL main
-(
- #ifndef _WIN32
- int numArgs, char *args[]
- #endif
-)
-{
- g_ErrStream = &g_StdErr;
- g_StdStream = &g_StdOut;
-
- NT_CHECK
-
- NConsoleClose::CCtrlHandlerSetter ctrlHandlerSetter;
- int res = 0;
-
- try
- {
- #ifdef _WIN32
- My_SetDefaultDllDirectories();
- #endif
-
- res = Main2(
- #ifndef _WIN32
- numArgs, args
- #endif
- );
- }
- catch(const CNewException &)
- {
- PrintError(kMemoryExceptionMessage);
- return (NExitCode::kMemoryError);
- }
- catch(const NConsoleClose::CCtrlBreakException &)
- {
- PrintError(kUserBreakMessage);
- return (NExitCode::kUserBreak);
- }
- catch(const CMessagePathException &e)
- {
- PrintError(kException_CmdLine_Error_Message);
- if (g_ErrStream)
- *g_ErrStream << e << endl;
- return (NExitCode::kUserError);
- }
- catch(const CSystemException &systemError)
- {
- if (systemError.ErrorCode == E_OUTOFMEMORY)
- {
- PrintError(kMemoryExceptionMessage);
- return (NExitCode::kMemoryError);
- }
- if (systemError.ErrorCode == E_ABORT)
- {
- PrintError(kUserBreakMessage);
- return (NExitCode::kUserBreak);
- }
- if (g_ErrStream)
- {
- PrintError("System ERROR:");
- *g_ErrStream << NError::MyFormatMessage(systemError.ErrorCode) << endl;
- }
- return (NExitCode::kFatalError);
- }
- catch(NExitCode::EEnum &exitCode)
- {
- FlushStreams();
- if (g_ErrStream)
- *g_ErrStream << kInternalExceptionMessage << exitCode << endl;
- return (exitCode);
- }
- catch(const UString &s)
- {
- if (g_ErrStream)
- {
- PrintError(kExceptionErrorMessage);
- *g_ErrStream << s << endl;
- }
- return (NExitCode::kFatalError);
- }
- catch(const AString &s)
- {
- if (g_ErrStream)
- {
- PrintError(kExceptionErrorMessage);
- *g_ErrStream << s << endl;
- }
- return (NExitCode::kFatalError);
- }
- catch(const char *s)
- {
- if (g_ErrStream)
- {
- PrintError(kExceptionErrorMessage);
- *g_ErrStream << s << endl;
- }
- return (NExitCode::kFatalError);
- }
- catch(const wchar_t *s)
- {
- if (g_ErrStream)
- {
- PrintError(kExceptionErrorMessage);
- *g_ErrStream << s << endl;
- }
- return (NExitCode::kFatalError);
- }
- catch(int t)
- {
- if (g_ErrStream)
- {
- FlushStreams();
- *g_ErrStream << kInternalExceptionMessage << t << endl;
- return (NExitCode::kFatalError);
- }
- }
- catch(...)
- {
- PrintError(kUnknownExceptionMessage);
- return (NExitCode::kFatalError);
- }
-
- return res;
-}
+// MainAr.cpp
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#include "../../../../C/DllSecur.h"
+#endif
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/MyException.h"
+#include "../../../Common/StdOutStream.h"
+
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/NtCheck.h"
+
+#include "../Common/ArchiveCommandLine.h"
+#include "../Common/ExitCode.h"
+
+#include "ConsoleClose.h"
+
+using namespace NWindows;
+
+extern
+CStdOutStream *g_StdStream;
+CStdOutStream *g_StdStream = NULL;
+extern
+CStdOutStream *g_ErrStream;
+CStdOutStream *g_ErrStream = NULL;
+
+extern int Main2(
+ #ifndef _WIN32
+ int numArgs, char *args[]
+ #endif
+);
+
+static const char * const kException_CmdLine_Error_Message = "Command Line Error:";
+static const char * const kExceptionErrorMessage = "ERROR:";
+static const char * const kUserBreakMessage = "Break signaled";
+static const char * const kMemoryExceptionMessage = "ERROR: Can't allocate required memory!";
+static const char * const kUnknownExceptionMessage = "Unknown Error";
+static const char * const kInternalExceptionMessage = "\n\nInternal Error #";
+
+static void FlushStreams()
+{
+ if (g_StdStream)
+ g_StdStream->Flush();
+}
+
+static void PrintError(const char *message)
+{
+ FlushStreams();
+ if (g_ErrStream)
+ *g_ErrStream << "\n\n" << message << endl;
+}
+
+#if defined(_WIN32) && defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE)
+#define NT_CHECK_FAIL_ACTION *g_StdStream << "Unsupported Windows version"; return NExitCode::kFatalError;
+#endif
+
+static inline bool CheckIsa()
+{
+ // __try
+ {
+ #if defined(__AVX2__)
+ if (!CPU_IsSupported_AVX2())
+ return false;
+ #elif defined(__AVX__)
+ if (!CPU_IsSupported_AVX())
+ return false;
+ #elif defined(__SSE2__) && !defined(MY_CPU_AMD64) || defined(_M_IX86_FP) && (_M_IX86_FP >= 2)
+ if (!CPU_IsSupported_SSE2())
+ return false;
+ #elif defined(__SSE__) && !defined(MY_CPU_AMD64) || defined(_M_IX86_FP) && (_M_IX86_FP >= 1)
+ if (!CPU_IsSupported_SSE() ||
+ !CPU_IsSupported_CMOV())
+ return false;
+ #endif
+ /*
+ __asm
+ {
+ _emit 0fH
+ _emit 038H
+ _emit 0cbH
+ _emit (0c0H + 0 * 8 + 0)
+ }
+ */
+ return true;
+ }
+ /*
+ __except (EXCEPTION_EXECUTE_HANDLER)
+ {
+ return false;
+ }
+ */
+}
+
+int Z7_CDECL main
+(
+ #ifndef _WIN32
+ int numArgs, char *args[]
+ #endif
+)
+{
+ g_ErrStream = &g_StdErr;
+ g_StdStream = &g_StdOut;
+
+ // #if (defined(_MSC_VER) && defined(_M_IX86))
+ if (!CheckIsa())
+ {
+ PrintError("ERROR: processor doesn't support required ISA extension");
+ return NExitCode::kFatalError;
+ }
+ // #endif
+
+ NT_CHECK
+
+ NConsoleClose::CCtrlHandlerSetter ctrlHandlerSetter;
+ int res = 0;
+
+ try
+ {
+ #ifdef _WIN32
+ My_SetDefaultDllDirectories();
+ #endif
+
+ res = Main2(
+ #ifndef _WIN32
+ numArgs, args
+ #endif
+ );
+ }
+ catch(const CNewException &)
+ {
+ PrintError(kMemoryExceptionMessage);
+ return (NExitCode::kMemoryError);
+ }
+ catch(const NConsoleClose::CCtrlBreakException &)
+ {
+ PrintError(kUserBreakMessage);
+ return (NExitCode::kUserBreak);
+ }
+ catch(const CMessagePathException &e)
+ {
+ PrintError(kException_CmdLine_Error_Message);
+ if (g_ErrStream)
+ *g_ErrStream << e << endl;
+ return (NExitCode::kUserError);
+ }
+ catch(const CSystemException &systemError)
+ {
+ if (systemError.ErrorCode == E_OUTOFMEMORY)
+ {
+ PrintError(kMemoryExceptionMessage);
+ return (NExitCode::kMemoryError);
+ }
+ if (systemError.ErrorCode == E_ABORT)
+ {
+ PrintError(kUserBreakMessage);
+ return (NExitCode::kUserBreak);
+ }
+ if (g_ErrStream)
+ {
+ PrintError("System ERROR:");
+ *g_ErrStream << NError::MyFormatMessage(systemError.ErrorCode) << endl;
+ }
+ return (NExitCode::kFatalError);
+ }
+ catch(NExitCode::EEnum exitCode)
+ {
+ FlushStreams();
+ if (g_ErrStream)
+ *g_ErrStream << kInternalExceptionMessage << exitCode << endl;
+ return (exitCode);
+ }
+ catch(const UString &s)
+ {
+ if (g_ErrStream)
+ {
+ PrintError(kExceptionErrorMessage);
+ *g_ErrStream << s << endl;
+ }
+ return (NExitCode::kFatalError);
+ }
+ catch(const AString &s)
+ {
+ if (g_ErrStream)
+ {
+ PrintError(kExceptionErrorMessage);
+ *g_ErrStream << s << endl;
+ }
+ return (NExitCode::kFatalError);
+ }
+ catch(const char *s)
+ {
+ if (g_ErrStream)
+ {
+ PrintError(kExceptionErrorMessage);
+ *g_ErrStream << s << endl;
+ }
+ return (NExitCode::kFatalError);
+ }
+ catch(const wchar_t *s)
+ {
+ if (g_ErrStream)
+ {
+ PrintError(kExceptionErrorMessage);
+ *g_ErrStream << s << endl;
+ }
+ return (NExitCode::kFatalError);
+ }
+ catch(int t)
+ {
+ if (g_ErrStream)
+ {
+ FlushStreams();
+ *g_ErrStream << kInternalExceptionMessage << t << endl;
+ return (NExitCode::kFatalError);
+ }
+ }
+ catch(...)
+ {
+ PrintError(kUnknownExceptionMessage);
+ return (NExitCode::kFatalError);
+ }
+
+ return res;
+}
diff --git a/CPP/7zip/UI/Console/OpenCallbackConsole.cpp b/CPP/7zip/UI/Console/OpenCallbackConsole.cpp
index 6e58c1f..1e7adf5 100644
--- a/CPP/7zip/UI/Console/OpenCallbackConsole.cpp
+++ b/CPP/7zip/UI/Console/OpenCallbackConsole.cpp
@@ -1,115 +1,115 @@
-// OpenCallbackConsole.cpp
-
-#include "StdAfx.h"
-
-#include "OpenCallbackConsole.h"
-
-#include "ConsoleClose.h"
-#include "UserInputUtils.h"
-
-static HRESULT CheckBreak2()
-{
- return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
-}
-
-HRESULT COpenCallbackConsole::Open_CheckBreak()
-{
- return CheckBreak2();
-}
-
-HRESULT COpenCallbackConsole::Open_SetTotal(const UInt64 *files, const UInt64 *bytes)
-{
- if (!MultiArcMode && NeedPercents())
- {
- if (files)
- {
- _totalFilesDefined = true;
- // _totalFiles = *files;
- _percent.Total = *files;
- }
- else
- _totalFilesDefined = false;
-
- if (bytes)
- {
- // _totalBytesDefined = true;
- _totalBytes = *bytes;
- if (!files)
- _percent.Total = *bytes;
- }
- else
- {
- // _totalBytesDefined = false;
- if (!files)
- _percent.Total = _totalBytes;
- }
- }
-
- return CheckBreak2();
-}
-
-HRESULT COpenCallbackConsole::Open_SetCompleted(const UInt64 *files, const UInt64 *bytes)
-{
- if (!MultiArcMode && NeedPercents())
- {
- if (files)
- {
- _percent.Files = *files;
- if (_totalFilesDefined)
- _percent.Completed = *files;
- }
-
- if (bytes)
- {
- if (!_totalFilesDefined)
- _percent.Completed = *bytes;
- }
- _percent.Print();
- }
-
- return CheckBreak2();
-}
-
-HRESULT COpenCallbackConsole::Open_Finished()
-{
- ClosePercents();
- return S_OK;
-}
-
-
-#ifndef _NO_CRYPTO
-
-HRESULT COpenCallbackConsole::Open_CryptoGetTextPassword(BSTR *password)
-{
- *password = NULL;
- RINOK(CheckBreak2());
-
- if (!PasswordIsDefined)
- {
- ClosePercents();
- RINOK(GetPassword_HRESULT(_so, Password));
- PasswordIsDefined = true;
- }
- return StringToBstr(Password, password);
-}
-
-/*
-HRESULT COpenCallbackConsole::Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password)
-{
- passwordIsDefined = PasswordIsDefined;
- password = Password;
- return S_OK;
-}
-
-bool COpenCallbackConsole::Open_WasPasswordAsked()
-{
- return PasswordWasAsked;
-}
-
-void COpenCallbackConsole::Open_Clear_PasswordWasAsked_Flag ()
-{
- PasswordWasAsked = false;
-}
-*/
-
-#endif
+// OpenCallbackConsole.cpp
+
+#include "StdAfx.h"
+
+#include "OpenCallbackConsole.h"
+
+#include "ConsoleClose.h"
+#include "UserInputUtils.h"
+
+static HRESULT CheckBreak2()
+{
+ return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
+}
+
+HRESULT COpenCallbackConsole::Open_CheckBreak()
+{
+ return CheckBreak2();
+}
+
+HRESULT COpenCallbackConsole::Open_SetTotal(const UInt64 *files, const UInt64 *bytes)
+{
+ if (!MultiArcMode && NeedPercents())
+ {
+ if (files)
+ {
+ _totalFilesDefined = true;
+ // _totalFiles = *files;
+ _percent.Total = *files;
+ }
+ else
+ _totalFilesDefined = false;
+
+ if (bytes)
+ {
+ // _totalBytesDefined = true;
+ _totalBytes = *bytes;
+ if (!files)
+ _percent.Total = *bytes;
+ }
+ else
+ {
+ // _totalBytesDefined = false;
+ if (!files)
+ _percent.Total = _totalBytes;
+ }
+ }
+
+ return CheckBreak2();
+}
+
+HRESULT COpenCallbackConsole::Open_SetCompleted(const UInt64 *files, const UInt64 *bytes)
+{
+ if (!MultiArcMode && NeedPercents())
+ {
+ if (files)
+ {
+ _percent.Files = *files;
+ if (_totalFilesDefined)
+ _percent.Completed = *files;
+ }
+
+ if (bytes)
+ {
+ if (!_totalFilesDefined)
+ _percent.Completed = *bytes;
+ }
+ _percent.Print();
+ }
+
+ return CheckBreak2();
+}
+
+HRESULT COpenCallbackConsole::Open_Finished()
+{
+ ClosePercents();
+ return S_OK;
+}
+
+
+#ifndef Z7_NO_CRYPTO
+
+HRESULT COpenCallbackConsole::Open_CryptoGetTextPassword(BSTR *password)
+{
+ *password = NULL;
+ RINOK(CheckBreak2())
+
+ if (!PasswordIsDefined)
+ {
+ ClosePercents();
+ RINOK(GetPassword_HRESULT(_so, Password))
+ PasswordIsDefined = true;
+ }
+ return StringToBstr(Password, password);
+}
+
+/*
+HRESULT COpenCallbackConsole::Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password)
+{
+ passwordIsDefined = PasswordIsDefined;
+ password = Password;
+ return S_OK;
+}
+
+bool COpenCallbackConsole::Open_WasPasswordAsked()
+{
+ return PasswordWasAsked;
+}
+
+void COpenCallbackConsole::Open_Clear_PasswordWasAsked_Flag ()
+{
+ PasswordWasAsked = false;
+}
+*/
+
+#endif
diff --git a/CPP/7zip/UI/Console/OpenCallbackConsole.h b/CPP/7zip/UI/Console/OpenCallbackConsole.h
index b9270f8..c5b4b45 100644
--- a/CPP/7zip/UI/Console/OpenCallbackConsole.h
+++ b/CPP/7zip/UI/Console/OpenCallbackConsole.h
@@ -1,66 +1,68 @@
-// OpenCallbackConsole.h
-
-#ifndef __OPEN_CALLBACK_CONSOLE_H
-#define __OPEN_CALLBACK_CONSOLE_H
-
-#include "../../../Common/StdOutStream.h"
-
-#include "../Common/ArchiveOpenCallback.h"
-
-#include "PercentPrinter.h"
-
-class COpenCallbackConsole: public IOpenCallbackUI
-{
-protected:
- CPercentPrinter _percent;
-
- CStdOutStream *_so;
- CStdOutStream *_se;
-
- bool _totalFilesDefined;
- // bool _totalBytesDefined;
- // UInt64 _totalFiles;
- UInt64 _totalBytes;
-
- bool NeedPercents() const { return _percent._so != NULL; }
-
-public:
-
- bool MultiArcMode;
-
- void ClosePercents()
- {
- if (NeedPercents())
- _percent.ClosePrint(true);
- }
-
- COpenCallbackConsole():
- _totalFilesDefined(false),
- // _totalBytesDefined(false),
- _totalBytes(0),
- MultiArcMode(false)
-
- #ifndef _NO_CRYPTO
- , PasswordIsDefined(false)
- // , PasswordWasAsked(false)
- #endif
-
- {}
-
- void Init(CStdOutStream *outStream, CStdOutStream *errorStream, CStdOutStream *percentStream)
- {
- _so = outStream;
- _se = errorStream;
- _percent._so = percentStream;
- }
-
- INTERFACE_IOpenCallbackUI(;)
-
- #ifndef _NO_CRYPTO
- bool PasswordIsDefined;
- // bool PasswordWasAsked;
- UString Password;
- #endif
-};
-
-#endif
+// OpenCallbackConsole.h
+
+#ifndef ZIP7_INC_OPEN_CALLBACK_CONSOLE_H
+#define ZIP7_INC_OPEN_CALLBACK_CONSOLE_H
+
+#include "../../../Common/StdOutStream.h"
+
+#include "../Common/ArchiveOpenCallback.h"
+
+#include "PercentPrinter.h"
+
+class COpenCallbackConsole: public IOpenCallbackUI
+{
+protected:
+ CPercentPrinter _percent;
+
+ CStdOutStream *_so;
+ CStdOutStream *_se;
+
+ // UInt64 _totalFiles;
+ UInt64 _totalBytes;
+ bool _totalFilesDefined;
+ // bool _totalBytesDefined;
+
+ bool NeedPercents() const { return _percent._so != NULL; }
+
+public:
+
+ bool MultiArcMode;
+
+ void ClosePercents()
+ {
+ if (NeedPercents())
+ _percent.ClosePrint(true);
+ }
+
+ COpenCallbackConsole():
+ _totalBytes(0),
+ _totalFilesDefined(false),
+ // _totalBytesDefined(false),
+ MultiArcMode(false)
+
+ #ifndef Z7_NO_CRYPTO
+ , PasswordIsDefined(false)
+ // , PasswordWasAsked(false)
+ #endif
+
+ {}
+
+ virtual ~COpenCallbackConsole() {}
+
+ void Init(CStdOutStream *outStream, CStdOutStream *errorStream, CStdOutStream *percentStream)
+ {
+ _so = outStream;
+ _se = errorStream;
+ _percent._so = percentStream;
+ }
+
+ Z7_IFACE_IMP(IOpenCallbackUI)
+
+ #ifndef Z7_NO_CRYPTO
+ bool PasswordIsDefined;
+ // bool PasswordWasAsked;
+ UString Password;
+ #endif
+};
+
+#endif
diff --git a/CPP/7zip/UI/Console/PercentPrinter.cpp b/CPP/7zip/UI/Console/PercentPrinter.cpp
index 20249ed..9d392ab 100644
--- a/CPP/7zip/UI/Console/PercentPrinter.cpp
+++ b/CPP/7zip/UI/Console/PercentPrinter.cpp
@@ -1,183 +1,184 @@
-// PercentPrinter.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/IntToString.h"
-
-#include "PercentPrinter.h"
-
-static const unsigned kPercentsSize = 4;
-
-CPercentPrinter::~CPercentPrinter()
-{
- ClosePrint(false);
-}
-
-void CPercentPrinterState::ClearCurState()
-{
- Completed = 0;
- Total = ((UInt64)(Int64)-1);
- Files = 0;
- Command.Empty();
- FileName.Empty();
-}
-
-void CPercentPrinter::ClosePrint(bool needFlush)
-{
- unsigned num = _printedString.Len();
- if (num != 0)
- {
-
- unsigned i;
-
- /* '\r' in old MAC OS means "new line".
- So we can't use '\r' in some systems */
-
- #ifdef _WIN32
- char *start = _temp.GetBuf(num + 2);
- char *p = start;
- *p++ = '\r';
- for (i = 0; i < num; i++) *p++ = ' ';
- *p++ = '\r';
- #else
- char *start = _temp.GetBuf(num * 3);
- char *p = start;
- for (i = 0; i < num; i++) *p++ = '\b';
- for (i = 0; i < num; i++) *p++ = ' ';
- for (i = 0; i < num; i++) *p++ = '\b';
- #endif
-
- *p = 0;
- _temp.ReleaseBuf_SetLen((unsigned)(p - start));
- *_so << _temp;
- }
- if (needFlush)
- _so->Flush();
- _printedString.Empty();
-}
-
-void CPercentPrinter::GetPercents()
-{
- char s[32];
- unsigned size;
- {
- char c = '%';
- UInt64 val = 0;
- if (Total == (UInt64)(Int64)-1)
- {
- val = Completed >> 20;
- c = 'M';
- }
- else if (Total != 0)
- val = Completed * 100 / Total;
- ConvertUInt64ToString(val, s);
- size = (unsigned)strlen(s);
- s[size++] = c;
- s[size] = 0;
- }
-
- while (size < kPercentsSize)
- {
- _s += ' ';
- size++;
- }
-
- _s += s;
-}
-
-void CPercentPrinter::Print()
-{
- DWORD tick = 0;
- if (_tickStep != 0)
- tick = GetTickCount();
-
- bool onlyPercentsChanged = false;
-
- if (!_printedString.IsEmpty())
- {
- if (_tickStep != 0 && (UInt32)(tick - _prevTick) < _tickStep)
- return;
-
- CPercentPrinterState &st = *this;
- if (_printedState.Command == st.Command
- && _printedState.FileName == st.FileName
- && _printedState.Files == st.Files)
- {
- if (_printedState.Total == st.Total
- && _printedState.Completed == st.Completed)
- return;
- onlyPercentsChanged = true;
- }
- }
-
- _s.Empty();
-
- GetPercents();
-
- if (onlyPercentsChanged && _s == _printedPercents)
- return;
-
- _printedPercents = _s;
-
- if (Files != 0)
- {
- char s[32];
- ConvertUInt64ToString(Files, s);
- // unsigned size = (unsigned)strlen(s);
- // for (; size < 3; size++) _s += ' ';
- _s += ' ';
- _s += s;
- // _s += "f";
- }
-
-
- if (!Command.IsEmpty())
- {
- _s += ' ';
- _s += Command;
- }
-
- if (!FileName.IsEmpty() && _s.Len() < MaxLen)
- {
- _s += ' ';
-
- _tempU = FileName;
- _so->Normalize_UString(_tempU);
- StdOut_Convert_UString_to_AString(_tempU, _temp);
- if (_s.Len() + _temp.Len() > MaxLen)
- {
- unsigned len = FileName.Len();
- for (; len != 0;)
- {
- unsigned delta = len / 8;
- if (delta == 0)
- delta = 1;
- len -= delta;
- _tempU = FileName;
- _tempU.Delete(len / 2, _tempU.Len() - len);
- _tempU.Insert(len / 2, L" . ");
- _so->Normalize_UString(_tempU);
- StdOut_Convert_UString_to_AString(_tempU, _temp);
- if (_s.Len() + _temp.Len() <= MaxLen)
- break;
- }
- if (len == 0)
- _temp.Empty();
- }
- _s += _temp;
- }
-
- if (_printedString != _s)
- {
- ClosePrint(false);
- *_so << _s;
- if (NeedFlush)
- _so->Flush();
- _printedString = _s;
- }
-
- _printedState = *this;
-
- if (_tickStep != 0)
- _prevTick = tick;
-}
+// PercentPrinter.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+
+#include "PercentPrinter.h"
+
+static const unsigned kPercentsSize = 4;
+
+CPercentPrinter::~CPercentPrinter()
+{
+ ClosePrint(false);
+}
+
+void CPercentPrinterState::ClearCurState()
+{
+ Completed = 0;
+ Total = ((UInt64)(Int64)-1);
+ Files = 0;
+ Command.Empty();
+ FileName.Empty();
+}
+
+void CPercentPrinter::ClosePrint(bool needFlush)
+{
+ unsigned num = _printedString.Len();
+ if (num != 0)
+ {
+
+ unsigned i;
+
+ /* '\r' in old MAC OS means "new line".
+ So we can't use '\r' in some systems */
+
+ #ifdef _WIN32
+ char *start = _temp.GetBuf(num + 2);
+ char *p = start;
+ *p++ = '\r';
+ for (i = 0; i < num; i++) *p++ = ' ';
+ *p++ = '\r';
+ #else
+ char *start = _temp.GetBuf(num * 3);
+ char *p = start;
+ for (i = 0; i < num; i++) *p++ = '\b';
+ for (i = 0; i < num; i++) *p++ = ' ';
+ for (i = 0; i < num; i++) *p++ = '\b';
+ #endif
+
+ *p = 0;
+ _temp.ReleaseBuf_SetLen((unsigned)(p - start));
+ *_so << _temp;
+ }
+ if (needFlush)
+ _so->Flush();
+ _printedString.Empty();
+}
+
+void CPercentPrinter::GetPercents()
+{
+ char s[32];
+ unsigned size;
+ {
+ char c = '%';
+ UInt64 val = 0;
+ if (Total == (UInt64)(Int64)-1 ||
+ (Total == 0 && Completed != 0))
+ {
+ val = Completed >> 20;
+ c = 'M';
+ }
+ else if (Total != 0)
+ val = Completed * 100 / Total;
+ ConvertUInt64ToString(val, s);
+ size = (unsigned)strlen(s);
+ s[size++] = c;
+ s[size] = 0;
+ }
+
+ while (size < kPercentsSize)
+ {
+ _s.Add_Space();
+ size++;
+ }
+
+ _s += s;
+}
+
+void CPercentPrinter::Print()
+{
+ DWORD tick = 0;
+ if (_tickStep != 0)
+ tick = GetTickCount();
+
+ bool onlyPercentsChanged = false;
+
+ if (!_printedString.IsEmpty())
+ {
+ if (_tickStep != 0 && (UInt32)(tick - _prevTick) < _tickStep)
+ return;
+
+ CPercentPrinterState &st = *this;
+ if (_printedState.Command == st.Command
+ && _printedState.FileName == st.FileName
+ && _printedState.Files == st.Files)
+ {
+ if (_printedState.Total == st.Total
+ && _printedState.Completed == st.Completed)
+ return;
+ onlyPercentsChanged = true;
+ }
+ }
+
+ _s.Empty();
+
+ GetPercents();
+
+ if (onlyPercentsChanged && _s == _printedPercents)
+ return;
+
+ _printedPercents = _s;
+
+ if (Files != 0)
+ {
+ char s[32];
+ ConvertUInt64ToString(Files, s);
+ // unsigned size = (unsigned)strlen(s);
+ // for (; size < 3; size++) _s.Add_Space();
+ _s.Add_Space();
+ _s += s;
+ // _s += "f";
+ }
+
+
+ if (!Command.IsEmpty())
+ {
+ _s.Add_Space();
+ _s += Command;
+ }
+
+ if (!FileName.IsEmpty() && _s.Len() < MaxLen)
+ {
+ _s.Add_Space();
+
+ _tempU = FileName;
+ _so->Normalize_UString(_tempU);
+ _so->Convert_UString_to_AString(_tempU, _temp);
+ if (_s.Len() + _temp.Len() > MaxLen)
+ {
+ unsigned len = FileName.Len();
+ for (; len != 0;)
+ {
+ unsigned delta = len / 8;
+ if (delta == 0)
+ delta = 1;
+ len -= delta;
+ _tempU = FileName;
+ _tempU.Delete(len / 2, _tempU.Len() - len);
+ _tempU.Insert(len / 2, L" . ");
+ _so->Normalize_UString(_tempU);
+ _so->Convert_UString_to_AString(_tempU, _temp);
+ if (_s.Len() + _temp.Len() <= MaxLen)
+ break;
+ }
+ if (len == 0)
+ _temp.Empty();
+ }
+ _s += _temp;
+ }
+
+ if (_printedString != _s)
+ {
+ ClosePrint(false);
+ *_so << _s;
+ if (NeedFlush)
+ _so->Flush();
+ _printedString = _s;
+ }
+
+ _printedState = *this;
+
+ if (_tickStep != 0)
+ _prevTick = tick;
+}
diff --git a/CPP/7zip/UI/Console/PercentPrinter.h b/CPP/7zip/UI/Console/PercentPrinter.h
index 90b4083..4debb3b 100644
--- a/CPP/7zip/UI/Console/PercentPrinter.h
+++ b/CPP/7zip/UI/Console/PercentPrinter.h
@@ -1,62 +1,62 @@
-// PercentPrinter.h
-
-#ifndef __PERCENT_PRINTER_H
-#define __PERCENT_PRINTER_H
-
-#include "../../../Common/StdOutStream.h"
-
-struct CPercentPrinterState
-{
- UInt64 Completed;
- UInt64 Total;
-
- UInt64 Files;
-
- AString Command;
- UString FileName;
-
- void ClearCurState();
-
- CPercentPrinterState():
- Completed(0),
- Total((UInt64)(Int64)-1),
- Files(0)
- {}
-};
-
-class CPercentPrinter: public CPercentPrinterState
-{
- UInt32 _tickStep;
- DWORD _prevTick;
-
- AString _s;
-
- AString _printedString;
- AString _temp;
- UString _tempU;
-
- CPercentPrinterState _printedState;
- AString _printedPercents;
-
- void GetPercents();
-
-public:
- CStdOutStream *_so;
-
- bool NeedFlush;
- unsigned MaxLen;
-
- CPercentPrinter(UInt32 tickStep = 200):
- _tickStep(tickStep),
- _prevTick(0),
- NeedFlush(true),
- MaxLen(80 - 1)
- {}
-
- ~CPercentPrinter();
-
- void ClosePrint(bool needFlush);
- void Print();
-};
-
-#endif
+// PercentPrinter.h
+
+#ifndef ZIP7_INC_PERCENT_PRINTER_H
+#define ZIP7_INC_PERCENT_PRINTER_H
+
+#include "../../../Common/StdOutStream.h"
+
+struct CPercentPrinterState
+{
+ UInt64 Completed;
+ UInt64 Total;
+
+ UInt64 Files;
+
+ AString Command;
+ UString FileName;
+
+ void ClearCurState();
+
+ CPercentPrinterState():
+ Completed(0),
+ Total((UInt64)(Int64)-1),
+ Files(0)
+ {}
+};
+
+class CPercentPrinter: public CPercentPrinterState
+{
+ UInt32 _tickStep;
+ DWORD _prevTick;
+
+ AString _s;
+
+ AString _printedString;
+ AString _temp;
+ UString _tempU;
+
+ CPercentPrinterState _printedState;
+ AString _printedPercents;
+
+ void GetPercents();
+
+public:
+ CStdOutStream *_so;
+
+ bool NeedFlush;
+ unsigned MaxLen;
+
+ CPercentPrinter(UInt32 tickStep = 200):
+ _tickStep(tickStep),
+ _prevTick(0),
+ NeedFlush(true),
+ MaxLen(80 - 1)
+ {}
+
+ ~CPercentPrinter();
+
+ void ClosePrint(bool needFlush);
+ void Print();
+};
+
+#endif
diff --git a/CPP/7zip/UI/Console/StdAfx.cpp b/CPP/7zip/UI/Console/StdAfx.cpp
index c6d3b1f..d0feea8 100644
--- a/CPP/7zip/UI/Console/StdAfx.cpp
+++ b/CPP/7zip/UI/Console/StdAfx.cpp
@@ -1,3 +1,3 @@
-// StdAfx.cpp
-
-#include "StdAfx.h"
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/UI/Console/StdAfx.h b/CPP/7zip/UI/Console/StdAfx.h
index 59d9ac1..035267c 100644
--- a/CPP/7zip/UI/Console/StdAfx.h
+++ b/CPP/7zip/UI/Console/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "../../../Common/Common.h"
-
-#endif
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp b/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
index 46ffaba..85496f5 100644
--- a/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
+++ b/CPP/7zip/UI/Console/UpdateCallbackConsole.cpp
@@ -1,702 +1,885 @@
-// UpdateCallbackConsole.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/IntToString.h"
-
-#include "../../../Windows/ErrorMsg.h"
-
-#ifndef _7ZIP_ST
-#include "../../../Windows/Synchronization.h"
-#endif
-
-#include "ConsoleClose.h"
-#include "UserInputUtils.h"
-#include "UpdateCallbackConsole.h"
-
-using namespace NWindows;
-
-#ifndef _7ZIP_ST
-static NSynchronization::CCriticalSection g_CriticalSection;
-#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
-#else
-#define MT_LOCK
-#endif
-
-static const wchar_t * const kEmptyFileAlias = L"[Content]";
-
-static const char * const kOpenArchiveMessage = "Open archive: ";
-static const char * const kCreatingArchiveMessage = "Creating archive: ";
-static const char * const kUpdatingArchiveMessage = "Updating archive: ";
-static const char * const kScanningMessage = "Scanning the drive:";
-
-static const char * const kError = "ERROR: ";
-static const char * const kWarning = "WARNING: ";
-
-static HRESULT CheckBreak2()
-{
- return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
-}
-
-HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
-HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
-
-void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags);
-
-void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc);
-
-HRESULT CUpdateCallbackConsole::OpenResult(
- const CCodecs *codecs, const CArchiveLink &arcLink,
- const wchar_t *name, HRESULT result)
-{
- ClosePercents2();
-
- FOR_VECTOR (level, arcLink.Arcs)
- {
- const CArc &arc = arcLink.Arcs[level];
- const CArcErrorInfo &er = arc.ErrorInfo;
-
- UInt32 errorFlags = er.GetErrorFlags();
-
- if (errorFlags != 0 || !er.ErrorMessage.IsEmpty())
- {
- if (_se)
- {
- *_se << endl;
- if (level != 0)
- *_se << arc.Path << endl;
- }
-
- if (errorFlags != 0)
- {
- if (_se)
- PrintErrorFlags(*_se, "ERRORS:", errorFlags);
- }
-
- if (!er.ErrorMessage.IsEmpty())
- {
- if (_se)
- *_se << "ERRORS:" << endl << er.ErrorMessage << endl;
- }
-
- if (_se)
- {
- *_se << endl;
- _se->Flush();
- }
- }
-
- UInt32 warningFlags = er.GetWarningFlags();
-
- if (warningFlags != 0 || !er.WarningMessage.IsEmpty())
- {
- if (_so)
- {
- *_so << endl;
- if (level != 0)
- *_so << arc.Path << endl;
- }
-
- if (warningFlags != 0)
- {
- if (_so)
- PrintErrorFlags(*_so, "WARNINGS:", warningFlags);
- }
-
- if (!er.WarningMessage.IsEmpty())
- {
- if (_so)
- *_so << "WARNINGS:" << endl << er.WarningMessage << endl;
- }
-
- if (_so)
- {
- *_so << endl;
- if (NeedFlush)
- _so->Flush();
- }
- }
-
-
- if (er.ErrorFormatIndex >= 0)
- {
- if (_so)
- {
- Print_ErrorFormatIndex_Warning(_so, codecs, arc);
- if (NeedFlush)
- _so->Flush();
- }
- }
- }
-
- if (result == S_OK)
- {
- if (_so)
- {
- RINOK(Print_OpenArchive_Props(*_so, codecs, arcLink));
- *_so << endl;
- }
- }
- else
- {
- if (_so)
- _so->Flush();
- if (_se)
- {
- *_se << kError;
- _se->NormalizePrint_wstr(name);
- *_se << endl;
- HRESULT res = Print_OpenArchive_Error(*_se, codecs, arcLink);
- RINOK(res);
- _se->Flush();
- }
- }
-
- return S_OK;
-}
-
-HRESULT CUpdateCallbackConsole::StartScanning()
-{
- if (_so)
- *_so << kScanningMessage << endl;
- _percent.Command = "Scan ";
- return S_OK;
-}
-
-HRESULT CUpdateCallbackConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */)
-{
- if (NeedPercents())
- {
- _percent.Files = st.NumDirs + st.NumFiles + st.NumAltStreams;
- _percent.Completed = st.GetTotalBytes();
- _percent.FileName = fs2us(path);
- _percent.Print();
- }
-
- return CheckBreak();
-}
-
-void CCallbackConsoleBase::CommonError(const FString &path, DWORD systemError, bool isWarning)
-{
- ClosePercents2();
-
- if (_se)
- {
- if (_so)
- _so->Flush();
-
- *_se << endl << (isWarning ? kWarning : kError)
- << NError::MyFormatMessage(systemError)
- << endl;
- _se->NormalizePrint_UString(fs2us(path));
- *_se << endl << endl;
- _se->Flush();
- }
-}
-
-
-HRESULT CCallbackConsoleBase::ScanError_Base(const FString &path, DWORD systemError)
-{
- MT_LOCK
-
- ScanErrors.AddError(path, systemError);
- CommonError(path, systemError, true);
-
- return S_OK;
-}
-
-HRESULT CCallbackConsoleBase::OpenFileError_Base(const FString &path, DWORD systemError)
-{
- MT_LOCK
- FailedFiles.AddError(path, systemError);
- /*
- if (systemError == ERROR_SHARING_VIOLATION)
- {
- */
- CommonError(path, systemError, true);
- return S_FALSE;
- /*
- }
- return systemError;
- */
-}
-
-HRESULT CCallbackConsoleBase::ReadingFileError_Base(const FString &path, DWORD systemError)
-{
- MT_LOCK
- CommonError(path, systemError, false);
- return HRESULT_FROM_WIN32(systemError);
-}
-
-HRESULT CUpdateCallbackConsole::ScanError(const FString &path, DWORD systemError)
-{
- return ScanError_Base(path, systemError);
-}
-
-
-static void PrintPropPair(AString &s, const char *name, UInt64 val)
-{
- char temp[32];
- ConvertUInt64ToString(val, temp);
- s += name;
- s += ": ";
- s += temp;
-}
-
-void PrintSize_bytes_Smart(AString &s, UInt64 val);
-void Print_DirItemsStat(AString &s, const CDirItemsStat &st);
-void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st);
-
-HRESULT CUpdateCallbackConsole::FinishScanning(const CDirItemsStat &st)
-{
- if (NeedPercents())
- {
- _percent.ClosePrint(true);
- _percent.ClearCurState();
- }
-
- if (_so)
- {
- AString s;
- Print_DirItemsStat(s, st);
- *_so << s << endl << endl;
- }
- return S_OK;
-}
-
-static const char * const k_StdOut_ArcName = "StdOut";
-
-HRESULT CUpdateCallbackConsole::StartOpenArchive(const wchar_t *name)
-{
- if (_so)
- {
- *_so << kOpenArchiveMessage;
- if (name)
- *_so << name;
- else
- *_so << k_StdOut_ArcName;
- *_so << endl;
- }
- return S_OK;
-}
-
-HRESULT CUpdateCallbackConsole::StartArchive(const wchar_t *name, bool updating)
-{
- if (_so)
- {
- *_so << (updating ? kUpdatingArchiveMessage : kCreatingArchiveMessage);
- if (name)
- _so->NormalizePrint_wstr(name);
- else
- *_so << k_StdOut_ArcName;
- *_so << endl << endl;
- }
- return S_OK;
-}
-
-HRESULT CUpdateCallbackConsole::FinishArchive(const CFinishArchiveStat &st)
-{
- ClosePercents2();
-
- if (_so)
- {
- AString s;
- // Print_UInt64_and_String(s, _percent.Files == 1 ? "file" : "files", _percent.Files);
- PrintPropPair(s, "Files read from disk", _percent.Files);
- s.Add_LF();
- s += "Archive size: ";
- PrintSize_bytes_Smart(s, st.OutArcFileSize);
- s.Add_LF();
- *_so << endl;
- *_so << s;
- // *_so << endl;
- }
-
- return S_OK;
-}
-
-HRESULT CUpdateCallbackConsole::WriteSfx(const wchar_t *name, UInt64 size)
-{
- if (_so)
- {
- *_so << "Write SFX: ";
- *_so << name;
- AString s (" : ");
- PrintSize_bytes_Smart(s, size);
- *_so << s << endl;
- }
- return S_OK;
-}
-
-
-HRESULT CUpdateCallbackConsole::DeletingAfterArchiving(const FString &path, bool /* isDir */)
-{
- if (LogLevel > 0 && _so)
- {
- ClosePercents_for_so();
-
- if (!DeleteMessageWasShown)
- {
- if (_so)
- *_so << endl << ": Removing files after including to archive" << endl;
- }
-
- {
- {
- _tempA = "Removing";
- _tempA.Add_Space();
- *_so << _tempA;
- _tempU = fs2us(path);
- _so->Normalize_UString(_tempU);
- _so->PrintUString(_tempU, _tempA);
- *_so << endl;
- if (NeedFlush)
- _so->Flush();
- }
- }
- }
-
- if (!DeleteMessageWasShown)
- {
- if (NeedPercents())
- {
- _percent.ClearCurState();
- }
- DeleteMessageWasShown = true;
- }
- else
- {
- _percent.Files++;
- }
-
- if (NeedPercents())
- {
- // if (!FullLog)
- {
- _percent.Command = "Removing";
- _percent.FileName = fs2us(path);
- }
- _percent.Print();
- }
-
- return S_OK;
-}
-
-
-HRESULT CUpdateCallbackConsole::FinishDeletingAfterArchiving()
-{
- ClosePercents2();
- if (_so && DeleteMessageWasShown)
- *_so << endl;
- return S_OK;
-}
-
-HRESULT CUpdateCallbackConsole::CheckBreak()
-{
- return CheckBreak2();
-}
-
-/*
-HRESULT CUpdateCallbackConsole::Finalize()
-{
- // MT_LOCK
- return S_OK;
-}
-*/
-
-
-void static PrintToDoStat(CStdOutStream *_so, const CDirItemsStat2 &stat, const char *name)
-{
- AString s;
- Print_DirItemsStat2(s, stat);
- *_so << name << ": " << s << endl;
-}
-
-HRESULT CUpdateCallbackConsole::SetNumItems(const CArcToDoStat &stat)
-{
- if (_so)
- {
- ClosePercents_for_so();
- if (!stat.DeleteData.IsEmpty())
- {
- *_so << endl;
- PrintToDoStat(_so, stat.DeleteData, "Delete data from archive");
- }
- if (!stat.OldData.IsEmpty())
- PrintToDoStat(_so, stat.OldData, "Keep old data in archive");
- // if (!stat.NewData.IsEmpty())
- {
- PrintToDoStat(_so, stat.NewData, "Add new data to archive");
- }
- *_so << endl;
- }
- return S_OK;
-}
-
-HRESULT CUpdateCallbackConsole::SetTotal(UInt64 size)
-{
- MT_LOCK
- if (NeedPercents())
- {
- _percent.Total = size;
- _percent.Print();
- }
- return S_OK;
-}
-
-HRESULT CUpdateCallbackConsole::SetCompleted(const UInt64 *completeValue)
-{
- MT_LOCK
- if (completeValue)
- {
- if (NeedPercents())
- {
- _percent.Completed = *completeValue;
- _percent.Print();
- }
- }
- return CheckBreak2();
-}
-
-HRESULT CUpdateCallbackConsole::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 * /* outSize */)
-{
- return CheckBreak2();
-}
-
-HRESULT CCallbackConsoleBase::PrintProgress(const wchar_t *name, const char *command, bool showInLog)
-{
- MT_LOCK
-
- bool show2 = (showInLog && _so);
-
- if (show2)
- {
- ClosePercents_for_so();
-
- _tempA = command;
- if (name)
- _tempA.Add_Space();
- *_so << _tempA;
-
- _tempU.Empty();
- if (name)
- {
- _tempU = name;
- _so->Normalize_UString(_tempU);
- }
- _so->PrintUString(_tempU, _tempA);
- *_so << endl;
- if (NeedFlush)
- _so->Flush();
- }
-
- if (NeedPercents())
- {
- if (PercentsNameLevel >= 1)
- {
- _percent.FileName.Empty();
- _percent.Command.Empty();
- if (PercentsNameLevel > 1 || !show2)
- {
- _percent.Command = command;
- if (name)
- _percent.FileName = name;
- }
- }
- _percent.Print();
- }
-
- return CheckBreak2();
-}
-
-HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool /* isDir */, bool isAnti, UInt32 mode)
-{
- if (StdOutMode)
- return S_OK;
-
- if (!name || name[0] == 0)
- name = kEmptyFileAlias;
-
- unsigned requiredLevel = 1;
-
- const char *s;
- if (mode == NUpdateNotifyOp::kAdd ||
- mode == NUpdateNotifyOp::kUpdate)
- {
- if (isAnti)
- s = "Anti";
- else if (mode == NUpdateNotifyOp::kAdd)
- s = "+";
- else
- s = "U";
- }
- else
- {
- requiredLevel = 3;
- if (mode == NUpdateNotifyOp::kAnalyze)
- s = "A";
- else
- s = "Reading";
- }
-
- return PrintProgress(name, s, LogLevel >= requiredLevel);
-}
-
-HRESULT CUpdateCallbackConsole::OpenFileError(const FString &path, DWORD systemError)
-{
- return OpenFileError_Base(path, systemError);
-}
-
-HRESULT CUpdateCallbackConsole::ReadingFileError(const FString &path, DWORD systemError)
-{
- return ReadingFileError_Base(path, systemError);
-}
-
-HRESULT CUpdateCallbackConsole::SetOperationResult(Int32)
-{
- MT_LOCK
- _percent.Files++;
- return S_OK;
-}
-
-void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest);
-
-HRESULT CUpdateCallbackConsole::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name)
-{
- // if (StdOutMode) return S_OK;
-
- if (opRes != NArchive::NExtract::NOperationResult::kOK)
- {
- ClosePercents2();
-
- if (_se)
- {
- if (_so)
- _so->Flush();
-
- AString s;
- SetExtractErrorMessage(opRes, isEncrypted, s);
- *_se << s << " : " << endl;
- _se->NormalizePrint_wstr(name);
- *_se << endl << endl;
- _se->Flush();
- }
- return S_OK;
- }
- return S_OK;
-}
-
-
-HRESULT CUpdateCallbackConsole::ReportUpdateOpeartion(UInt32 op, const wchar_t *name, bool /* isDir */)
-{
- // if (StdOutMode) return S_OK;
-
- char temp[16];
- const char *s;
-
- unsigned requiredLevel = 1;
-
- switch (op)
- {
- case NUpdateNotifyOp::kAdd: s = "+"; break;
- case NUpdateNotifyOp::kUpdate: s = "U"; break;
- case NUpdateNotifyOp::kAnalyze: s = "A"; requiredLevel = 3; break;
- case NUpdateNotifyOp::kReplicate: s = "="; requiredLevel = 3; break;
- case NUpdateNotifyOp::kRepack: s = "R"; requiredLevel = 2; break;
- case NUpdateNotifyOp::kSkip: s = "."; requiredLevel = 2; break;
- case NUpdateNotifyOp::kDelete: s = "D"; requiredLevel = 3; break;
- case NUpdateNotifyOp::kHeader: s = "Header creation"; requiredLevel = 100; break;
- default:
- {
- temp[0] = 'o';
- temp[1] = 'p';
- ConvertUInt64ToString(op, temp + 2);
- s = temp;
- }
- }
-
- return PrintProgress(name, s, LogLevel >= requiredLevel);
-}
-
-/*
-HRESULT CUpdateCallbackConsole::SetPassword(const UString &
- #ifndef _NO_CRYPTO
- password
- #endif
- )
-{
- #ifndef _NO_CRYPTO
- PasswordIsDefined = true;
- Password = password;
- #endif
- return S_OK;
-}
-*/
-
-HRESULT CUpdateCallbackConsole::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
-{
- COM_TRY_BEGIN
-
- *password = NULL;
-
- #ifdef _NO_CRYPTO
-
- *passwordIsDefined = false;
- return S_OK;
-
- #else
-
- if (!PasswordIsDefined)
- {
- if (AskPassword)
- {
- RINOK(GetPassword_HRESULT(_so, Password));
- PasswordIsDefined = true;
- }
- }
- *passwordIsDefined = BoolToInt(PasswordIsDefined);
- return StringToBstr(Password, password);
-
- #endif
-
- COM_TRY_END
-}
-
-HRESULT CUpdateCallbackConsole::CryptoGetTextPassword(BSTR *password)
-{
- COM_TRY_BEGIN
-
- *password = NULL;
-
- #ifdef _NO_CRYPTO
-
- return E_NOTIMPL;
-
- #else
-
- if (!PasswordIsDefined)
- {
- {
- RINOK(GetPassword_HRESULT(_so, Password))
- PasswordIsDefined = true;
- }
- }
- return StringToBstr(Password, password);
-
- #endif
- COM_TRY_END
-}
-
-HRESULT CUpdateCallbackConsole::ShowDeleteFile(const wchar_t *name, bool /* isDir */)
-{
- if (StdOutMode)
- return S_OK;
-
- if (LogLevel > 7)
- {
- if (!name || name[0] == 0)
- name = kEmptyFileAlias;
- return PrintProgress(name, "D", true);
- }
- return S_OK;
-}
+// UpdateCallbackConsole.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/FileName.h"
+
+#ifndef Z7_ST
+#include "../../../Windows/Synchronization.h"
+#endif
+
+// #include "../Common/PropIDUtils.h"
+
+#include "ConsoleClose.h"
+#include "UserInputUtils.h"
+#include "UpdateCallbackConsole.h"
+
+using namespace NWindows;
+
+#ifndef Z7_ST
+static NSynchronization::CCriticalSection g_CriticalSection;
+#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
+#else
+#define MT_LOCK
+#endif
+
+static const wchar_t * const kEmptyFileAlias = L"[Content]";
+
+static const char * const kOpenArchiveMessage = "Open archive: ";
+static const char * const kCreatingArchiveMessage = "Creating archive: ";
+static const char * const kUpdatingArchiveMessage = "Updating archive: ";
+static const char * const kScanningMessage = "Scanning the drive:";
+
+static const char * const kError = "ERROR: ";
+static const char * const kWarning = "WARNING: ";
+
+static HRESULT CheckBreak2()
+{
+ return NConsoleClose::TestBreakSignal() ? E_ABORT : S_OK;
+}
+
+HRESULT Print_OpenArchive_Props(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
+HRESULT Print_OpenArchive_Error(CStdOutStream &so, const CCodecs *codecs, const CArchiveLink &arcLink);
+
+void PrintErrorFlags(CStdOutStream &so, const char *s, UInt32 errorFlags);
+
+void Print_ErrorFormatIndex_Warning(CStdOutStream *_so, const CCodecs *codecs, const CArc &arc);
+
+HRESULT CUpdateCallbackConsole::OpenResult(
+ const CCodecs *codecs, const CArchiveLink &arcLink,
+ const wchar_t *name, HRESULT result)
+{
+ ClosePercents2();
+
+ FOR_VECTOR (level, arcLink.Arcs)
+ {
+ const CArc &arc = arcLink.Arcs[level];
+ const CArcErrorInfo &er = arc.ErrorInfo;
+
+ UInt32 errorFlags = er.GetErrorFlags();
+
+ if (errorFlags != 0 || !er.ErrorMessage.IsEmpty())
+ {
+ if (_se)
+ {
+ *_se << endl;
+ if (level != 0)
+ *_se << arc.Path << endl;
+ }
+
+ if (errorFlags != 0)
+ {
+ if (_se)
+ PrintErrorFlags(*_se, "ERRORS:", errorFlags);
+ }
+
+ if (!er.ErrorMessage.IsEmpty())
+ {
+ if (_se)
+ *_se << "ERRORS:" << endl << er.ErrorMessage << endl;
+ }
+
+ if (_se)
+ {
+ *_se << endl;
+ _se->Flush();
+ }
+ }
+
+ UInt32 warningFlags = er.GetWarningFlags();
+
+ if (warningFlags != 0 || !er.WarningMessage.IsEmpty())
+ {
+ if (_so)
+ {
+ *_so << endl;
+ if (level != 0)
+ *_so << arc.Path << endl;
+ }
+
+ if (warningFlags != 0)
+ {
+ if (_so)
+ PrintErrorFlags(*_so, "WARNINGS:", warningFlags);
+ }
+
+ if (!er.WarningMessage.IsEmpty())
+ {
+ if (_so)
+ *_so << "WARNINGS:" << endl << er.WarningMessage << endl;
+ }
+
+ if (_so)
+ {
+ *_so << endl;
+ if (NeedFlush)
+ _so->Flush();
+ }
+ }
+
+
+ if (er.ErrorFormatIndex >= 0)
+ {
+ if (_so)
+ {
+ Print_ErrorFormatIndex_Warning(_so, codecs, arc);
+ if (NeedFlush)
+ _so->Flush();
+ }
+ }
+ }
+
+ if (result == S_OK)
+ {
+ if (_so)
+ {
+ RINOK(Print_OpenArchive_Props(*_so, codecs, arcLink))
+ *_so << endl;
+ }
+ }
+ else
+ {
+ if (_so)
+ _so->Flush();
+ if (_se)
+ {
+ *_se << kError;
+ _se->NormalizePrint_wstr(name);
+ *_se << endl;
+ HRESULT res = Print_OpenArchive_Error(*_se, codecs, arcLink);
+ RINOK(res)
+ _se->Flush();
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::StartScanning()
+{
+ if (_so)
+ *_so << kScanningMessage << endl;
+ _percent.Command = "Scan ";
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::ScanProgress(const CDirItemsStat &st, const FString &path, bool /* isDir */)
+{
+ if (NeedPercents())
+ {
+ _percent.Files = st.NumDirs + st.NumFiles + st.NumAltStreams;
+ _percent.Completed = st.GetTotalBytes();
+ _percent.FileName = fs2us(path);
+ _percent.Print();
+ }
+
+ return CheckBreak();
+}
+
+void CCallbackConsoleBase::CommonError(const FString &path, DWORD systemError, bool isWarning)
+{
+ ClosePercents2();
+
+ if (_se)
+ {
+ if (_so)
+ _so->Flush();
+
+ *_se << endl << (isWarning ? kWarning : kError)
+ << NError::MyFormatMessage(systemError)
+ << endl;
+ _se->NormalizePrint_UString(fs2us(path));
+ *_se << endl << endl;
+ _se->Flush();
+ }
+}
+
+/*
+void CCallbackConsoleBase::CommonError(const char *message)
+{
+ ClosePercents2();
+
+ if (_se)
+ {
+ if (_so)
+ _so->Flush();
+
+ *_se << endl << kError << message << endl;
+ _se->Flush();
+ }
+}
+*/
+
+
+HRESULT CCallbackConsoleBase::ScanError_Base(const FString &path, DWORD systemError)
+{
+ MT_LOCK
+
+ ScanErrors.AddError(path, systemError);
+ CommonError(path, systemError, true);
+
+ return S_OK;
+}
+
+HRESULT CCallbackConsoleBase::OpenFileError_Base(const FString &path, DWORD systemError)
+{
+ MT_LOCK
+ FailedFiles.AddError(path, systemError);
+ NumNonOpenFiles++;
+ /*
+ if (systemError == ERROR_SHARING_VIOLATION)
+ {
+ */
+ CommonError(path, systemError, true);
+ return S_FALSE;
+ /*
+ }
+ return systemError;
+ */
+}
+
+HRESULT CCallbackConsoleBase::ReadingFileError_Base(const FString &path, DWORD systemError)
+{
+ MT_LOCK
+ CommonError(path, systemError, false);
+ return HRESULT_FROM_WIN32(systemError);
+}
+
+HRESULT CUpdateCallbackConsole::ScanError(const FString &path, DWORD systemError)
+{
+ return ScanError_Base(path, systemError);
+}
+
+
+static void PrintPropPair(AString &s, const char *name, UInt64 val)
+{
+ char temp[32];
+ ConvertUInt64ToString(val, temp);
+ s += name;
+ s += ": ";
+ s += temp;
+}
+
+void PrintSize_bytes_Smart(AString &s, UInt64 val);
+void Print_DirItemsStat(AString &s, const CDirItemsStat &st);
+void Print_DirItemsStat2(AString &s, const CDirItemsStat2 &st);
+
+HRESULT CUpdateCallbackConsole::FinishScanning(const CDirItemsStat &st)
+{
+ if (NeedPercents())
+ {
+ _percent.ClosePrint(true);
+ _percent.ClearCurState();
+ }
+
+ if (_so)
+ {
+ AString s;
+ Print_DirItemsStat(s, st);
+ *_so << s << endl << endl;
+ }
+ return S_OK;
+}
+
+static const char * const k_StdOut_ArcName = "StdOut";
+
+HRESULT CUpdateCallbackConsole::StartOpenArchive(const wchar_t *name)
+{
+ if (_so)
+ {
+ *_so << kOpenArchiveMessage;
+ if (name)
+ *_so << name;
+ else
+ *_so << k_StdOut_ArcName;
+ *_so << endl;
+ }
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::StartArchive(const wchar_t *name, bool updating)
+{
+ if (NeedPercents())
+ _percent.ClosePrint(true);
+
+ _percent.ClearCurState();
+ NumNonOpenFiles = 0;
+
+ if (_so)
+ {
+ *_so << (updating ? kUpdatingArchiveMessage : kCreatingArchiveMessage);
+ if (name)
+ _so->NormalizePrint_wstr(name);
+ else
+ *_so << k_StdOut_ArcName;
+ *_so << endl << endl;
+ }
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::FinishArchive(const CFinishArchiveStat &st)
+{
+ ClosePercents2();
+
+ if (_so)
+ {
+ AString s;
+ // Print_UInt64_and_String(s, _percent.Files == 1 ? "file" : "files", _percent.Files);
+ PrintPropPair(s, "Files read from disk", _percent.Files - NumNonOpenFiles);
+ s.Add_LF();
+ s += "Archive size: ";
+ PrintSize_bytes_Smart(s, st.OutArcFileSize);
+ s.Add_LF();
+ if (st.IsMultiVolMode)
+ {
+ s += "Volumes: ";
+ s.Add_UInt32(st.NumVolumes);
+ s.Add_LF();
+ }
+ *_so << endl;
+ *_so << s;
+ // *_so << endl;
+ }
+
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::WriteSfx(const wchar_t *name, UInt64 size)
+{
+ if (_so)
+ {
+ *_so << "Write SFX: ";
+ *_so << name;
+ AString s (" : ");
+ PrintSize_bytes_Smart(s, size);
+ *_so << s << endl;
+ }
+ return S_OK;
+}
+
+
+HRESULT CUpdateCallbackConsole::DeletingAfterArchiving(const FString &path, bool /* isDir */)
+{
+ if (LogLevel > 0 && _so)
+ {
+ ClosePercents_for_so();
+
+ if (!DeleteMessageWasShown)
+ {
+ if (_so)
+ *_so << endl << ": Removing files after including to archive" << endl;
+ }
+
+ {
+ {
+ _tempA = "Removing";
+ _tempA.Add_Space();
+ *_so << _tempA;
+ _tempU = fs2us(path);
+ _so->Normalize_UString(_tempU);
+ _so->PrintUString(_tempU, _tempA);
+ *_so << endl;
+ if (NeedFlush)
+ _so->Flush();
+ }
+ }
+ }
+
+ if (!DeleteMessageWasShown)
+ {
+ if (NeedPercents())
+ {
+ _percent.ClearCurState();
+ }
+ DeleteMessageWasShown = true;
+ }
+ else
+ {
+ _percent.Files++;
+ }
+
+ if (NeedPercents())
+ {
+ // if (!FullLog)
+ {
+ _percent.Command = "Removing";
+ _percent.FileName = fs2us(path);
+ }
+ _percent.Print();
+ }
+
+ return S_OK;
+}
+
+
+HRESULT CUpdateCallbackConsole::FinishDeletingAfterArchiving()
+{
+ ClosePercents2();
+ if (_so && DeleteMessageWasShown)
+ *_so << endl;
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::CheckBreak()
+{
+ return CheckBreak2();
+}
+
+/*
+HRESULT CUpdateCallbackConsole::Finalize()
+{
+ // MT_LOCK
+ return S_OK;
+}
+*/
+
+
+void static PrintToDoStat(CStdOutStream *_so, const CDirItemsStat2 &stat, const char *name)
+{
+ AString s;
+ Print_DirItemsStat2(s, stat);
+ *_so << name << ": " << s << endl;
+}
+
+HRESULT CUpdateCallbackConsole::SetNumItems(const CArcToDoStat &stat)
+{
+ if (_so)
+ {
+ ClosePercents_for_so();
+ if (!stat.DeleteData.IsEmpty())
+ {
+ *_so << endl;
+ PrintToDoStat(_so, stat.DeleteData, "Delete data from archive");
+ }
+ if (!stat.OldData.IsEmpty())
+ PrintToDoStat(_so, stat.OldData, "Keep old data in archive");
+ // if (!stat.NewData.IsEmpty())
+ {
+ PrintToDoStat(_so, stat.NewData, "Add new data to archive");
+ }
+ *_so << endl;
+ }
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::SetTotal(UInt64 size)
+{
+ MT_LOCK
+ if (NeedPercents())
+ {
+ _percent.Total = size;
+ _percent.Print();
+ }
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::SetCompleted(const UInt64 *completeValue)
+{
+ MT_LOCK
+ if (completeValue)
+ {
+ if (NeedPercents())
+ {
+ _percent.Completed = *completeValue;
+ _percent.Print();
+ }
+ }
+ return CheckBreak2();
+}
+
+HRESULT CUpdateCallbackConsole::SetRatioInfo(const UInt64 * /* inSize */, const UInt64 * /* outSize */)
+{
+ return CheckBreak2();
+}
+
+HRESULT CCallbackConsoleBase::PrintProgress(const wchar_t *name, bool isDir, const char *command, bool showInLog)
+{
+ MT_LOCK
+
+ bool show2 = (showInLog && _so);
+
+ if (show2)
+ {
+ ClosePercents_for_so();
+
+ _tempA = command;
+ if (name)
+ _tempA.Add_Space();
+ *_so << _tempA;
+
+ _tempU.Empty();
+ if (name)
+ {
+ _tempU = name;
+ if (isDir)
+ NWindows::NFile::NName::NormalizeDirPathPrefix(_tempU);
+ _so->Normalize_UString(_tempU);
+ }
+ _so->PrintUString(_tempU, _tempA);
+ *_so << endl;
+ if (NeedFlush)
+ _so->Flush();
+ }
+
+ if (NeedPercents())
+ {
+ if (PercentsNameLevel >= 1)
+ {
+ _percent.FileName.Empty();
+ _percent.Command.Empty();
+ if (PercentsNameLevel > 1 || !show2)
+ {
+ _percent.Command = command;
+ if (name)
+ _percent.FileName = name;
+ }
+ }
+ _percent.Print();
+ }
+
+ return CheckBreak2();
+}
+
+
+/*
+void CCallbackConsoleBase::PrintInfoLine(const UString &s)
+{
+ if (LogLevel < 1000)
+ return;
+
+ MT_LOCK
+
+ const bool show2 = (_so != NULL);
+
+ if (show2)
+ {
+ ClosePercents_for_so();
+ _so->PrintUString(s, _tempA);
+ *_so << endl;
+ if (NeedFlush)
+ _so->Flush();
+ }
+}
+*/
+
+HRESULT CUpdateCallbackConsole::GetStream(const wchar_t *name, bool isDir, bool isAnti, UInt32 mode)
+{
+ if (StdOutMode)
+ return S_OK;
+
+ if (!name || name[0] == 0)
+ name = kEmptyFileAlias;
+
+ unsigned requiredLevel = 1;
+
+ const char *s;
+ if (mode == NUpdateNotifyOp::kAdd ||
+ mode == NUpdateNotifyOp::kUpdate)
+ {
+ if (isAnti)
+ s = "Anti";
+ else if (mode == NUpdateNotifyOp::kAdd)
+ s = "+";
+ else
+ s = "U";
+ }
+ else
+ {
+ requiredLevel = 3;
+ if (mode == NUpdateNotifyOp::kAnalyze)
+ s = "A";
+ else
+ s = "Reading";
+ }
+
+ return PrintProgress(name, isDir, s, LogLevel >= requiredLevel);
+}
+
+HRESULT CUpdateCallbackConsole::OpenFileError(const FString &path, DWORD systemError)
+{
+ return OpenFileError_Base(path, systemError);
+}
+
+HRESULT CUpdateCallbackConsole::ReadingFileError(const FString &path, DWORD systemError)
+{
+ return ReadingFileError_Base(path, systemError);
+}
+
+HRESULT CUpdateCallbackConsole::SetOperationResult(Int32 /* opRes */)
+{
+ MT_LOCK
+ _percent.Files++;
+ /*
+ if (opRes != NArchive::NUpdate::NOperationResult::kOK)
+ {
+ if (opRes == NArchive::NUpdate::NOperationResult::kError_FileChanged)
+ {
+ CommonError("Input file changed");
+ }
+ }
+ */
+ return S_OK;
+}
+
+void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &dest);
+
+HRESULT CUpdateCallbackConsole::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name)
+{
+ // if (StdOutMode) return S_OK;
+
+ if (opRes != NArchive::NExtract::NOperationResult::kOK)
+ {
+ ClosePercents2();
+
+ if (_se)
+ {
+ if (_so)
+ _so->Flush();
+
+ AString s;
+ SetExtractErrorMessage(opRes, isEncrypted, s);
+ *_se << s << " : " << endl;
+ _se->NormalizePrint_wstr(name);
+ *_se << endl << endl;
+ _se->Flush();
+ }
+ return S_OK;
+ }
+ return S_OK;
+}
+
+
+HRESULT CUpdateCallbackConsole::ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir)
+{
+ // if (StdOutMode) return S_OK;
+
+ char temp[16];
+ const char *s;
+
+ unsigned requiredLevel = 1;
+
+ switch (op)
+ {
+ case NUpdateNotifyOp::kAdd: s = "+"; break;
+ case NUpdateNotifyOp::kUpdate: s = "U"; break;
+ case NUpdateNotifyOp::kAnalyze: s = "A"; requiredLevel = 3; break;
+ case NUpdateNotifyOp::kReplicate: s = "="; requiredLevel = 3; break;
+ case NUpdateNotifyOp::kRepack: s = "R"; requiredLevel = 2; break;
+ case NUpdateNotifyOp::kSkip: s = "."; requiredLevel = 2; break;
+ case NUpdateNotifyOp::kDelete: s = "D"; requiredLevel = 3; break;
+ case NUpdateNotifyOp::kHeader: s = "Header creation"; requiredLevel = 100; break;
+ case NUpdateNotifyOp::kInFileChanged: s = "Size of input file was changed:"; requiredLevel = 10; break;
+ // case NUpdateNotifyOp::kOpFinished: s = "Finished"; requiredLevel = 100; break;
+ default:
+ {
+ temp[0] = 'o';
+ temp[1] = 'p';
+ ConvertUInt64ToString(op, temp + 2);
+ s = temp;
+ }
+ }
+
+ return PrintProgress(name, isDir, s, LogLevel >= requiredLevel);
+}
+
+/*
+HRESULT CUpdateCallbackConsole::SetPassword(const UString &
+ #ifndef Z7_NO_CRYPTO
+ password
+ #endif
+ )
+{
+ #ifndef Z7_NO_CRYPTO
+ PasswordIsDefined = true;
+ Password = password;
+ #endif
+ return S_OK;
+}
+*/
+
+HRESULT CUpdateCallbackConsole::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
+{
+ COM_TRY_BEGIN
+
+ *password = NULL;
+
+ #ifdef Z7_NO_CRYPTO
+
+ *passwordIsDefined = false;
+ return S_OK;
+
+ #else
+
+ if (!PasswordIsDefined)
+ {
+ if (AskPassword)
+ {
+ RINOK(GetPassword_HRESULT(_so, Password))
+ PasswordIsDefined = true;
+ }
+ }
+ *passwordIsDefined = BoolToInt(PasswordIsDefined);
+ return StringToBstr(Password, password);
+
+ #endif
+
+ COM_TRY_END
+}
+
+HRESULT CUpdateCallbackConsole::CryptoGetTextPassword(BSTR *password)
+{
+ COM_TRY_BEGIN
+
+ *password = NULL;
+
+ #ifdef Z7_NO_CRYPTO
+
+ return E_NOTIMPL;
+
+ #else
+
+ if (!PasswordIsDefined)
+ {
+ {
+ RINOK(GetPassword_HRESULT(_so, Password))
+ PasswordIsDefined = true;
+ }
+ }
+ return StringToBstr(Password, password);
+
+ #endif
+ COM_TRY_END
+}
+
+HRESULT CUpdateCallbackConsole::ShowDeleteFile(const wchar_t *name, bool isDir)
+{
+ if (StdOutMode)
+ return S_OK;
+
+ if (LogLevel > 7)
+ {
+ if (!name || name[0] == 0)
+ name = kEmptyFileAlias;
+ return PrintProgress(name, isDir, "D", true);
+ }
+ return S_OK;
+}
+
+/*
+void GetPropName(PROPID propID, const wchar_t *name, AString &nameA, UString &nameU);
+
+static void GetPropName(PROPID propID, UString &nameU)
+{
+ AString nameA;
+ GetPropName(propID, NULL, nameA, nameU);
+ // if (!nameA.IsEmpty())
+ nameU = nameA;
+}
+
+
+static void AddPropNamePrefix(UString &s, PROPID propID)
+{
+ UString name;
+ GetPropName(propID, name);
+ s += name;
+ s += " = ";
+}
+
+void CCallbackConsoleBase::PrintPropInfo(UString &s, PROPID propID, const PROPVARIANT *value)
+{
+ AddPropNamePrefix(s, propID);
+ {
+ UString dest;
+ const int level = 9; // we show up to ns precision level
+ ConvertPropertyToString2(dest, *value, propID, level);
+ s += dest;
+ }
+ PrintInfoLine(s);
+}
+
+static void Add_IndexType_Index(UString &s, UInt32 indexType, UInt32 index)
+{
+ if (indexType == NArchive::NEventIndexType::kArcProp)
+ {
+ }
+ else
+ {
+ if (indexType == NArchive::NEventIndexType::kBlockIndex)
+ {
+ s += "#";
+ }
+ else if (indexType == NArchive::NEventIndexType::kOutArcIndex)
+ {
+ }
+ else
+ {
+ s += "indexType_";
+ s.Add_UInt32(indexType);
+ s.Add_Space();
+ }
+ s.Add_UInt32(index);
+ }
+ s += ": ";
+}
+
+HRESULT CUpdateCallbackConsole::ReportProp(UInt32 indexType, UInt32 index, PROPID propID, const PROPVARIANT *value)
+{
+ UString s;
+ Add_IndexType_Index(s, indexType, index);
+ PrintPropInfo(s, propID, value);
+ return S_OK;
+}
+
+static inline char GetHex(Byte value)
+{
+ return (char)((value < 10) ? ('0' + value) : ('a' + (value - 10)));
+}
+
+static void AddHexToString(UString &dest, const Byte *data, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ {
+ Byte b = data[i];
+ dest += GetHex((Byte)((b >> 4) & 0xF));
+ dest += GetHex((Byte)(b & 0xF));
+ }
+}
+
+void HashHexToString(char *dest, const Byte *data, UInt32 size);
+
+HRESULT CUpdateCallbackConsole::ReportRawProp(UInt32 indexType, UInt32 index,
+ PROPID propID, const void *data, UInt32 dataSize, UInt32 propType)
+{
+ UString s;
+ propType = propType;
+ Add_IndexType_Index(s, indexType, index);
+ AddPropNamePrefix(s, propID);
+ if (propID == kpidChecksum)
+ {
+ char temp[k_HashCalc_DigestSize_Max + 8];
+ HashHexToString(temp, (const Byte *)data, dataSize);
+ s += temp;
+ }
+ else
+ AddHexToString(s, (const Byte *)data, dataSize);
+ PrintInfoLine(s);
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackConsole::ReportFinished(UInt32 indexType, UInt32 index, Int32 opRes)
+{
+ UString s;
+ Add_IndexType_Index(s, indexType, index);
+ s += "finished";
+ if (opRes != NArchive::NUpdate::NOperationResult::kOK)
+ {
+ s += ": ";
+ s.Add_UInt32(opRes);
+ }
+ PrintInfoLine(s);
+ return S_OK;
+}
+*/
diff --git a/CPP/7zip/UI/Console/UpdateCallbackConsole.h b/CPP/7zip/UI/Console/UpdateCallbackConsole.h
index 6765db6..b6c1be4 100644
--- a/CPP/7zip/UI/Console/UpdateCallbackConsole.h
+++ b/CPP/7zip/UI/Console/UpdateCallbackConsole.h
@@ -1,124 +1,133 @@
-// UpdateCallbackConsole.h
-
-#ifndef __UPDATE_CALLBACK_CONSOLE_H
-#define __UPDATE_CALLBACK_CONSOLE_H
-
-#include "../../../Common/StdOutStream.h"
-
-#include "../Common/Update.h"
-
-#include "PercentPrinter.h"
-
-struct CErrorPathCodes
-{
- FStringVector Paths;
- CRecordVector<DWORD> Codes;
-
- void AddError(const FString &path, DWORD systemError)
- {
- Paths.Add(path);
- Codes.Add(systemError);
- }
- void Clear()
- {
- Paths.Clear();
- Codes.Clear();
- }
-};
-
-class CCallbackConsoleBase
-{
-protected:
- CPercentPrinter _percent;
-
- CStdOutStream *_so;
- CStdOutStream *_se;
-
- void CommonError(const FString &path, DWORD systemError, bool isWarning);
-
- HRESULT ScanError_Base(const FString &path, DWORD systemError);
- HRESULT OpenFileError_Base(const FString &name, DWORD systemError);
- HRESULT ReadingFileError_Base(const FString &name, DWORD systemError);
-
-public:
- bool NeedPercents() const { return _percent._so != NULL; };
-
- bool StdOutMode;
-
- bool NeedFlush;
- unsigned PercentsNameLevel;
- unsigned LogLevel;
-
- AString _tempA;
- UString _tempU;
-
- CCallbackConsoleBase():
- StdOutMode(false),
- NeedFlush(false),
- PercentsNameLevel(1),
- LogLevel(0)
- {}
-
- void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; }
-
- void Init(CStdOutStream *outStream, CStdOutStream *errorStream, CStdOutStream *percentStream)
- {
- FailedFiles.Clear();
-
- _so = outStream;
- _se = errorStream;
- _percent._so = percentStream;
- }
-
- void ClosePercents2()
- {
- if (NeedPercents())
- _percent.ClosePrint(true);
- }
-
- void ClosePercents_for_so()
- {
- if (NeedPercents() && _so == _percent._so)
- _percent.ClosePrint(false);
- }
-
-
- CErrorPathCodes FailedFiles;
- CErrorPathCodes ScanErrors;
-
- HRESULT PrintProgress(const wchar_t *name, const char *command, bool showInLog);
-
-};
-
-class CUpdateCallbackConsole: public IUpdateCallbackUI2, public CCallbackConsoleBase
-{
- // void PrintPropPair(const char *name, const wchar_t *val);
-
-public:
- #ifndef _NO_CRYPTO
- bool PasswordIsDefined;
- UString Password;
- bool AskPassword;
- #endif
-
- bool DeleteMessageWasShown;
-
- CUpdateCallbackConsole()
- : DeleteMessageWasShown(false)
- #ifndef _NO_CRYPTO
- , PasswordIsDefined(false)
- , AskPassword(false)
- #endif
- {}
-
- /*
- void Init(CStdOutStream *outStream)
- {
- CCallbackConsoleBase::Init(outStream);
- }
- */
- // ~CUpdateCallbackConsole() { if (NeedPercents()) _percent.ClosePrint(); }
- INTERFACE_IUpdateCallbackUI2(;)
-};
-
-#endif
+// UpdateCallbackConsole.h
+
+#ifndef ZIP7_INC_UPDATE_CALLBACK_CONSOLE_H
+#define ZIP7_INC_UPDATE_CALLBACK_CONSOLE_H
+
+#include "../../../Common/StdOutStream.h"
+
+#include "../Common/Update.h"
+
+#include "PercentPrinter.h"
+
+struct CErrorPathCodes
+{
+ FStringVector Paths;
+ CRecordVector<DWORD> Codes;
+
+ void AddError(const FString &path, DWORD systemError)
+ {
+ Paths.Add(path);
+ Codes.Add(systemError);
+ }
+ void Clear()
+ {
+ Paths.Clear();
+ Codes.Clear();
+ }
+};
+
+
+class CCallbackConsoleBase
+{
+protected:
+ CPercentPrinter _percent;
+
+ CStdOutStream *_so;
+ CStdOutStream *_se;
+
+ void CommonError(const FString &path, DWORD systemError, bool isWarning);
+ // void CommonError(const char *message);
+
+ HRESULT ScanError_Base(const FString &path, DWORD systemError);
+ HRESULT OpenFileError_Base(const FString &name, DWORD systemError);
+ HRESULT ReadingFileError_Base(const FString &name, DWORD systemError);
+
+public:
+ bool NeedPercents() const { return _percent._so != NULL; }
+
+ bool StdOutMode;
+
+ bool NeedFlush;
+ unsigned PercentsNameLevel;
+ unsigned LogLevel;
+
+ AString _tempA;
+ UString _tempU;
+
+ CCallbackConsoleBase():
+ StdOutMode(false),
+ NeedFlush(false),
+ PercentsNameLevel(1),
+ LogLevel(0),
+ NumNonOpenFiles(0)
+ {}
+
+ void SetWindowWidth(unsigned width) { _percent.MaxLen = width - 1; }
+
+ void Init(CStdOutStream *outStream, CStdOutStream *errorStream, CStdOutStream *percentStream)
+ {
+ FailedFiles.Clear();
+
+ _so = outStream;
+ _se = errorStream;
+ _percent._so = percentStream;
+ }
+
+ void ClosePercents2()
+ {
+ if (NeedPercents())
+ _percent.ClosePrint(true);
+ }
+
+ void ClosePercents_for_so()
+ {
+ if (NeedPercents() && _so == _percent._so)
+ _percent.ClosePrint(false);
+ }
+
+ CErrorPathCodes FailedFiles;
+ CErrorPathCodes ScanErrors;
+ UInt64 NumNonOpenFiles;
+
+ HRESULT PrintProgress(const wchar_t *name, bool isDir, const char *command, bool showInLog);
+
+ // void PrintInfoLine(const UString &s);
+ // void PrintPropInfo(UString &s, PROPID propID, const PROPVARIANT *value);
+};
+
+
+class CUpdateCallbackConsole Z7_final:
+ public IUpdateCallbackUI2,
+ public CCallbackConsoleBase
+{
+ // void PrintPropPair(const char *name, const wchar_t *val);
+ Z7_IFACE_IMP(IUpdateCallbackUI)
+ Z7_IFACE_IMP(IDirItemsCallback)
+ Z7_IFACE_IMP(IUpdateCallbackUI2)
+public:
+ bool DeleteMessageWasShown;
+
+ #ifndef Z7_NO_CRYPTO
+ bool PasswordIsDefined;
+ bool AskPassword;
+ UString Password;
+ #endif
+
+ CUpdateCallbackConsole():
+ DeleteMessageWasShown(false)
+ #ifndef Z7_NO_CRYPTO
+ , PasswordIsDefined(false)
+ , AskPassword(false)
+ #endif
+ {}
+
+ /*
+ void Init(CStdOutStream *outStream)
+ {
+ CCallbackConsoleBase::Init(outStream);
+ }
+ */
+ // ~CUpdateCallbackConsole() { if (NeedPercents()) _percent.ClosePrint(); }
+};
+
+#endif
diff --git a/CPP/7zip/UI/Console/UserInputUtils.cpp b/CPP/7zip/UI/Console/UserInputUtils.cpp
index 7bdafda..04d675e 100644
--- a/CPP/7zip/UI/Console/UserInputUtils.cpp
+++ b/CPP/7zip/UI/Console/UserInputUtils.cpp
@@ -1,110 +1,117 @@
-// UserInputUtils.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/StdInStream.h"
-#include "../../../Common/StringConvert.h"
-
-#include "UserInputUtils.h"
-
-static const char kYes = 'y';
-static const char kNo = 'n';
-static const char kYesAll = 'a';
-static const char kNoAll = 's';
-static const char kAutoRenameAll = 'u';
-static const char kQuit = 'q';
-
-static const char * const kFirstQuestionMessage = "? ";
-static const char * const kHelpQuestionMessage =
- "(Y)es / (N)o / (A)lways / (S)kip all / A(u)to rename all / (Q)uit? ";
-
-// return true if pressed Quite;
-
-NUserAnswerMode::EEnum ScanUserYesNoAllQuit(CStdOutStream *outStream)
-{
- if (outStream)
- *outStream << kFirstQuestionMessage;
- for (;;)
- {
- if (outStream)
- {
- *outStream << kHelpQuestionMessage;
- outStream->Flush();
- }
- AString scannedString;
- if (!g_StdIn.ScanAStringUntilNewLine(scannedString))
- return NUserAnswerMode::kError;
- if (g_StdIn.Error())
- return NUserAnswerMode::kError;
- scannedString.Trim();
- if (scannedString.IsEmpty() && g_StdIn.Eof())
- return NUserAnswerMode::kEof;
-
- if (scannedString.Len() == 1)
- switch (::MyCharLower_Ascii(scannedString[0]))
- {
- case kYes: return NUserAnswerMode::kYes;
- case kNo: return NUserAnswerMode::kNo;
- case kYesAll: return NUserAnswerMode::kYesAll;
- case kNoAll: return NUserAnswerMode::kNoAll;
- case kAutoRenameAll: return NUserAnswerMode::kAutoRenameAll;
- case kQuit: return NUserAnswerMode::kQuit;
- }
- }
-}
-
-#ifdef _WIN32
-#ifndef UNDER_CE
-#define MY_DISABLE_ECHO
-#endif
-#endif
-
-static bool GetPassword(CStdOutStream *outStream, UString &psw)
-{
- if (outStream)
- {
- *outStream << "\nEnter password"
- #ifdef MY_DISABLE_ECHO
- " (will not be echoed)"
- #endif
- ":";
- outStream->Flush();
- }
-
- #ifdef MY_DISABLE_ECHO
-
- HANDLE console = GetStdHandle(STD_INPUT_HANDLE);
- bool wasChanged = false;
- DWORD mode = 0;
- if (console != INVALID_HANDLE_VALUE && console != 0)
- if (GetConsoleMode(console, &mode))
- wasChanged = (SetConsoleMode(console, mode & ~ENABLE_ECHO_INPUT) != 0);
- bool res = g_StdIn.ScanUStringUntilNewLine(psw);
- if (wasChanged)
- SetConsoleMode(console, mode);
-
- #else
-
- bool res = g_StdIn.ScanUStringUntilNewLine(psw);
-
- #endif
-
- if (outStream)
- {
- *outStream << endl;
- outStream->Flush();
- }
-
- return res;
-}
-
-HRESULT GetPassword_HRESULT(CStdOutStream *outStream, UString &psw)
-{
- if (!GetPassword(outStream, psw))
- return E_INVALIDARG;
- if (g_StdIn.Error())
- return E_FAIL;
- if (g_StdIn.Eof() && psw.IsEmpty())
- return E_ABORT;
- return S_OK;
-}
+// UserInputUtils.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/StdInStream.h"
+#include "../../../Common/StringConvert.h"
+
+#include "UserInputUtils.h"
+
+static const char kYes = 'y';
+static const char kNo = 'n';
+static const char kYesAll = 'a';
+static const char kNoAll = 's';
+static const char kAutoRenameAll = 'u';
+static const char kQuit = 'q';
+
+static const char * const kFirstQuestionMessage = "? ";
+static const char * const kHelpQuestionMessage =
+ "(Y)es / (N)o / (A)lways / (S)kip all / A(u)to rename all / (Q)uit? ";
+
+// return true if pressed Quite;
+
+NUserAnswerMode::EEnum ScanUserYesNoAllQuit(CStdOutStream *outStream)
+{
+ if (outStream)
+ *outStream << kFirstQuestionMessage;
+ for (;;)
+ {
+ if (outStream)
+ {
+ *outStream << kHelpQuestionMessage;
+ outStream->Flush();
+ }
+ AString scannedString;
+ if (!g_StdIn.ScanAStringUntilNewLine(scannedString))
+ return NUserAnswerMode::kError;
+ if (g_StdIn.Error())
+ return NUserAnswerMode::kError;
+ scannedString.Trim();
+ if (scannedString.IsEmpty() && g_StdIn.Eof())
+ return NUserAnswerMode::kEof;
+
+ if (scannedString.Len() == 1)
+ switch (::MyCharLower_Ascii(scannedString[0]))
+ {
+ case kYes: return NUserAnswerMode::kYes;
+ case kNo: return NUserAnswerMode::kNo;
+ case kYesAll: return NUserAnswerMode::kYesAll;
+ case kNoAll: return NUserAnswerMode::kNoAll;
+ case kAutoRenameAll: return NUserAnswerMode::kAutoRenameAll;
+ case kQuit: return NUserAnswerMode::kQuit;
+ }
+ }
+}
+
+#ifdef _WIN32
+#ifndef UNDER_CE
+#define MY_DISABLE_ECHO
+#endif
+#endif
+
+static bool GetPassword(CStdOutStream *outStream, UString &psw)
+{
+ if (outStream)
+ {
+ *outStream << "\nEnter password"
+ #ifdef MY_DISABLE_ECHO
+ " (will not be echoed)"
+ #endif
+ ":";
+ outStream->Flush();
+ }
+
+ #ifdef MY_DISABLE_ECHO
+
+ const HANDLE console = GetStdHandle(STD_INPUT_HANDLE);
+
+ /*
+ GetStdHandle() returns
+ INVALID_HANDLE_VALUE: If the function fails.
+ NULL : If an application does not have associated standard handles,
+ such as a service running on an interactive desktop,
+ and has not redirected them. */
+ bool wasChanged = false;
+ DWORD mode = 0;
+ if (console != INVALID_HANDLE_VALUE && console != NULL)
+ if (GetConsoleMode(console, &mode))
+ wasChanged = (SetConsoleMode(console, mode & ~(DWORD)ENABLE_ECHO_INPUT) != 0);
+ const bool res = g_StdIn.ScanUStringUntilNewLine(psw);
+ if (wasChanged)
+ SetConsoleMode(console, mode);
+
+ #else
+
+ const bool res = g_StdIn.ScanUStringUntilNewLine(psw);
+
+ #endif
+
+ if (outStream)
+ {
+ *outStream << endl;
+ outStream->Flush();
+ }
+
+ return res;
+}
+
+HRESULT GetPassword_HRESULT(CStdOutStream *outStream, UString &psw)
+{
+ if (!GetPassword(outStream, psw))
+ return E_INVALIDARG;
+ if (g_StdIn.Error())
+ return E_FAIL;
+ if (g_StdIn.Eof() && psw.IsEmpty())
+ return E_ABORT;
+ return S_OK;
+}
diff --git a/CPP/7zip/UI/Console/UserInputUtils.h b/CPP/7zip/UI/Console/UserInputUtils.h
index ebe09c1..695a3e6 100644
--- a/CPP/7zip/UI/Console/UserInputUtils.h
+++ b/CPP/7zip/UI/Console/UserInputUtils.h
@@ -1,27 +1,27 @@
-// UserInputUtils.h
-
-#ifndef __USER_INPUT_UTILS_H
-#define __USER_INPUT_UTILS_H
-
-#include "../../../Common/StdOutStream.h"
-
-namespace NUserAnswerMode {
-
-enum EEnum
-{
- kYes,
- kNo,
- kYesAll,
- kNoAll,
- kAutoRenameAll,
- kQuit,
- kEof,
- kError
-};
-}
-
-NUserAnswerMode::EEnum ScanUserYesNoAllQuit(CStdOutStream *outStream);
-// bool GetPassword(CStdOutStream *outStream, UString &psw);
-HRESULT GetPassword_HRESULT(CStdOutStream *outStream, UString &psw);
-
-#endif
+// UserInputUtils.h
+
+#ifndef ZIP7_INC_USER_INPUT_UTILS_H
+#define ZIP7_INC_USER_INPUT_UTILS_H
+
+#include "../../../Common/StdOutStream.h"
+
+namespace NUserAnswerMode {
+
+enum EEnum
+{
+ kYes,
+ kNo,
+ kYesAll,
+ kNoAll,
+ kAutoRenameAll,
+ kQuit,
+ kEof,
+ kError
+};
+}
+
+NUserAnswerMode::EEnum ScanUserYesNoAllQuit(CStdOutStream *outStream);
+// bool GetPassword(CStdOutStream *outStream, UString &psw);
+HRESULT GetPassword_HRESULT(CStdOutStream *outStream, UString &psw);
+
+#endif
diff --git a/CPP/7zip/UI/Console/makefile b/CPP/7zip/UI/Console/makefile
index 2210e0b..a20b0cc 100644
--- a/CPP/7zip/UI/Console/makefile
+++ b/CPP/7zip/UI/Console/makefile
@@ -1,64 +1,68 @@
-PROG = 7z.exe
-CFLAGS = $(CFLAGS) \
- -DEXTERNAL_CODECS \
-
-COMMON_OBJS = \
- $O\CommandLineParser.obj \
- $O\CRC.obj \
- $O\IntToString.obj \
- $O\ListFileUtils.obj \
- $O\NewHandler.obj \
- $O\StdInStream.obj \
- $O\StdOutStream.obj \
- $O\MyString.obj \
- $O\StringConvert.obj \
- $O\StringToInt.obj \
- $O\UTFConvert.obj \
- $O\MyVector.obj \
- $O\Wildcard.obj \
-
-WIN_OBJS = \
- $O\DLL.obj \
- $O\ErrorMsg.obj \
- $O\FileDir.obj \
- $O\FileFind.obj \
- $O\FileIO.obj \
- $O\FileLink.obj \
- $O\FileName.obj \
- $O\FileSystem.obj \
- $O\MemoryLock.obj \
- $O\PropVariant.obj \
- $O\PropVariantConv.obj \
- $O\Registry.obj \
- $O\System.obj \
- $O\TimeUtils.obj \
-
-7ZIP_COMMON_OBJS = \
- $O\CreateCoder.obj \
- $O\FilePathAutoRename.obj \
- $O\FileStreams.obj \
- $O\FilterCoder.obj \
- $O\LimitedStreams.obj \
- $O\MethodProps.obj \
- $O\ProgressUtils.obj \
- $O\PropId.obj \
- $O\StreamObjects.obj \
- $O\StreamUtils.obj \
- $O\UniqBlocks.obj \
-
-AR_COMMON_OBJS = \
- $O\OutStreamWithCRC.obj \
-
-COMPRESS_OBJS = \
- $O\CopyCoder.obj \
-
-C_OBJS = $(C_OBJS) \
- $O\Alloc.obj \
- $O\CpuArch.obj \
- $O\Sort.obj \
- $O\Threads.obj \
-
-!include "../../Crc.mak"
-!include "Console.mak"
-
-!include "../../7zip.mak"
+PROG = 7z.exe
+CFLAGS = $(CFLAGS) \
+ -DZ7_EXTERNAL_CODECS \
+
+COMMON_OBJS = \
+ $O\CommandLineParser.obj \
+ $O\CRC.obj \
+ $O\DynLimBuf.obj \
+ $O\IntToString.obj \
+ $O\ListFileUtils.obj \
+ $O\NewHandler.obj \
+ $O\StdInStream.obj \
+ $O\StdOutStream.obj \
+ $O\MyString.obj \
+ $O\StringConvert.obj \
+ $O\StringToInt.obj \
+ $O\UTFConvert.obj \
+ $O\MyVector.obj \
+ $O\Wildcard.obj \
+
+WIN_OBJS = \
+ $O\DLL.obj \
+ $O\ErrorMsg.obj \
+ $O\FileDir.obj \
+ $O\FileFind.obj \
+ $O\FileIO.obj \
+ $O\FileLink.obj \
+ $O\FileName.obj \
+ $O\FileSystem.obj \
+ $O\MemoryLock.obj \
+ $O\PropVariant.obj \
+ $O\PropVariantConv.obj \
+ $O\Registry.obj \
+ $O\System.obj \
+ $O\SystemInfo.obj \
+ $O\TimeUtils.obj \
+
+7ZIP_COMMON_OBJS = \
+ $O\CreateCoder.obj \
+ $O\FilePathAutoRename.obj \
+ $O\FileStreams.obj \
+ $O\FilterCoder.obj \
+ $O\LimitedStreams.obj \
+ $O\MethodProps.obj \
+ $O\MultiOutStream.obj \
+ $O\ProgressUtils.obj \
+ $O\PropId.obj \
+ $O\StreamObjects.obj \
+ $O\StreamUtils.obj \
+ $O\UniqBlocks.obj \
+
+AR_COMMON_OBJS = \
+ $O\ItemNameUtils.obj \
+ $O\OutStreamWithCRC.obj \
+
+COMPRESS_OBJS = \
+ $O\CopyCoder.obj \
+
+C_OBJS = $(C_OBJS) \
+ $O\Alloc.obj \
+ $O\CpuArch.obj \
+ $O\Sort.obj \
+ $O\Threads.obj \
+
+!include "../../Crc.mak"
+!include "Console.mak"
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/UI/Console/makefile.gcc b/CPP/7zip/UI/Console/makefile.gcc
new file mode 100644
index 0000000..8a293d8
--- /dev/null
+++ b/CPP/7zip/UI/Console/makefile.gcc
@@ -0,0 +1,186 @@
+PROG = 7z
+IS_NOT_STANDALONE = 1
+
+# IS_X64 = 1
+# USE_ASM = 1
+# ST_MODE = 1
+
+
+LOCAL_FLAGS_ST =
+MT_OBJS =
+
+ifdef SystemDrive
+IS_MINGW = 1
+else
+ifdef SYSTEMDRIVE
+# ifdef OS
+IS_MINGW = 1
+endif
+endif
+
+ifdef ST_MODE
+
+LOCAL_FLAGS_ST = -DZ7_ST
+
+ifdef IS_MINGW
+MT_OBJS = \
+ $O/Threads.o \
+
+endif
+
+else
+
+MT_OBJS = \
+ $O/Synchronization.o \
+ $O/Threads.o \
+
+endif
+
+
+
+LOCAL_FLAGS_WIN=
+
+ifdef IS_MINGW
+
+LOCAL_FLAGS_WIN = \
+ -DZ7_LARGE_PAGES \
+ -DZ7_LONG_PATH \
+ -DZ7_DEVICE_FILE \
+
+SYS_OBJS = \
+ $O/FileSystem.o \
+ $O/Registry.o \
+ $O/MemoryLock.o \
+ $O/DllSecur.o \
+ $O/resource.o \
+
+else
+
+SYS_OBJS = \
+ $O/MyWindows.o \
+
+endif
+
+
+
+LOCAL_FLAGS = \
+ $(LOCAL_FLAGS_WIN) \
+ $(LOCAL_FLAGS_ST) \
+ -DZ7_EXTERNAL_CODECS \
+
+
+
+CONSOLE_OBJS = \
+ $O/BenchCon.o \
+ $O/ConsoleClose.o \
+ $O/ExtractCallbackConsole.o \
+ $O/HashCon.o \
+ $O/List.o \
+ $O/Main.o \
+ $O/MainAr.o \
+ $O/OpenCallbackConsole.o \
+ $O/PercentPrinter.o \
+ $O/UpdateCallbackConsole.o \
+ $O/UserInputUtils.o \
+
+UI_COMMON_OBJS = \
+ $O/ArchiveCommandLine.o \
+ $O/ArchiveExtractCallback.o \
+ $O/ArchiveOpenCallback.o \
+ $O/Bench.o \
+ $O/DefaultName.o \
+ $O/EnumDirItems.o \
+ $O/Extract.o \
+ $O/ExtractingFilePath.o \
+ $O/HashCalc.o \
+ $O/LoadCodecs.o \
+ $O/OpenArchive.o \
+ $O/PropIDUtils.o \
+ $O/SetProperties.o \
+ $O/SortUtils.o \
+ $O/TempFiles.o \
+ $O/Update.o \
+ $O/UpdateAction.o \
+ $O/UpdateCallback.o \
+ $O/UpdatePair.o \
+ $O/UpdateProduce.o \
+
+COMMON_OBJS = \
+ $O/CommandLineParser.o \
+ $O/CRC.o \
+ $O/CrcReg.o \
+ $O/DynLimBuf.o \
+ $O/IntToString.o \
+ $O/ListFileUtils.o \
+ $O/NewHandler.o \
+ $O/StdInStream.o \
+ $O/StdOutStream.o \
+ $O/MyString.o \
+ $O/StringConvert.o \
+ $O/StringToInt.o \
+ $O/UTFConvert.o \
+ $O/MyVector.o \
+ $O/Wildcard.o \
+
+WIN_OBJS = \
+ $O/DLL.o \
+ $O/ErrorMsg.o \
+ $O/FileDir.o \
+ $O/FileFind.o \
+ $O/FileIO.o \
+ $O/FileLink.o \
+ $O/FileName.o \
+ $O/PropVariant.o \
+ $O/PropVariantConv.o \
+ $O/System.o \
+ $O/SystemInfo.o \
+ $O/TimeUtils.o \
+
+7ZIP_COMMON_OBJS = \
+ $O/CreateCoder.o \
+ $O/CWrappers.o \
+ $O/FilePathAutoRename.o \
+ $O/FileStreams.o \
+ $O/InBuffer.o \
+ $O/InOutTempBuffer.o \
+ $O/FilterCoder.o \
+ $O/LimitedStreams.o \
+ $O/MethodId.o \
+ $O/MethodProps.o \
+ $O/MultiOutStream.o \
+ $O/OffsetStream.o \
+ $O/OutBuffer.o \
+ $O/ProgressUtils.o \
+ $O/PropId.o \
+ $O/StreamObjects.o \
+ $O/StreamUtils.o \
+ $O/UniqBlocks.o \
+
+COMPRESS_OBJS = \
+ $O/CopyCoder.o \
+
+AR_COMMON_OBJS = \
+ $O/ItemNameUtils.o \
+
+C_OBJS = \
+ $O/Alloc.o \
+ $O/CpuArch.o \
+ $O/Sort.o \
+ $O/7zCrc.o \
+ $O/7zCrcOpt.o \
+
+
+OBJS = \
+ $(C_OBJS) \
+ $(MT_OBJS) \
+ $(COMMON_OBJS) \
+ $(WIN_OBJS) \
+ $(SYS_OBJS) \
+ $(COMPRESS_OBJS) \
+ $(AR_COMMON_OBJS) \
+ $(7ZIP_COMMON_OBJS) \
+ $(UI_COMMON_OBJS) \
+ $(CONSOLE_OBJS) \
+
+
+include ../../7zip_gcc.mak
diff --git a/CPP/7zip/UI/Console/resource.rc b/CPP/7zip/UI/Console/resource.rc
index 8d721f5..414427f 100644
--- a/CPP/7zip/UI/Console/resource.rc
+++ b/CPP/7zip/UI/Console/resource.rc
@@ -1,7 +1,7 @@
-#include "../../MyVersionInfo.rc"
-
-MY_VERSION_INFO_APP("7-Zip Console" , "7z")
-
-#ifndef UNDER_CE
-1 24 MOVEABLE PURE "Console.manifest"
-#endif
+#include "../../MyVersionInfo.rc"
+
+MY_VERSION_INFO_APP("7-Zip Console" , "7z")
+
+#ifndef UNDER_CE
+1 24 MOVEABLE PURE "Console.manifest"
+#endif
diff --git a/CPP/7zip/UI/Explorer/7-zip.dll.manifest b/CPP/7zip/UI/Explorer/7-zip.dll.manifest
new file mode 100644
index 0000000..cba1c5d
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/7-zip.dll.manifest
@@ -0,0 +1 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?><assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0"><assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="7-Zip.7-Zip.7-zip" type="win32"/><description>7-Zip Extension.</description><dependency> <dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/></dependentAssembly></dependency></assembly>
diff --git a/CPP/7zip/UI/Explorer/ContextMenu.cpp b/CPP/7zip/UI/Explorer/ContextMenu.cpp
new file mode 100644
index 0000000..7815e13
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/ContextMenu.cpp
@@ -0,0 +1,1822 @@
+// ContextMenu.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/COM.h"
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/Menu.h"
+#include "../../../Windows/ProcessUtils.h"
+
+// for IS_INTRESOURCE():
+#include "../../../Windows/Window.h"
+
+#include "../../PropID.h"
+
+#include "../Common/ArchiveName.h"
+#include "../Common/CompressCall.h"
+#include "../Common/ExtractingFilePath.h"
+#include "../Common/ZipRegistry.h"
+
+#include "../FileManager/FormatUtils.h"
+#include "../FileManager/LangUtils.h"
+#include "../FileManager/PropertyName.h"
+
+#include "ContextMenu.h"
+#include "ContextMenuFlags.h"
+#include "MyMessages.h"
+
+#include "resource.h"
+
+
+// #define SHOW_DEBUG_CTX_MENU
+
+#ifdef SHOW_DEBUG_CTX_MENU
+#include <stdio.h>
+#endif
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+#ifndef UNDER_CE
+#define EMAIL_SUPPORT 1
+#endif
+
+extern LONG g_DllRefCount;
+
+#ifdef _WIN32
+extern HINSTANCE g_hInstance;
+#endif
+
+#ifdef UNDER_CE
+ #define MY_IS_INTRESOURCE(_r) ((((ULONG_PTR)(_r)) >> 16) == 0)
+#else
+ #define MY_IS_INTRESOURCE(_r) IS_INTRESOURCE(_r)
+#endif
+
+
+#ifdef SHOW_DEBUG_CTX_MENU
+
+static void PrintStringA(const char *name, LPCSTR ptr)
+{
+ AString m;
+ m += name;
+ m += ": ";
+ char s[32];
+ sprintf(s, "%p", (const void *)ptr);
+ m += s;
+ if (!MY_IS_INTRESOURCE(ptr))
+ {
+ m += ": \"";
+ m += ptr;
+ m += "\"";
+ }
+ OutputDebugStringA(m);
+}
+
+#if !defined(UNDER_CE)
+static void PrintStringW(const char *name, LPCWSTR ptr)
+{
+ UString m;
+ m += name;
+ m += ": ";
+ char s[32];
+ sprintf(s, "%p", (const void *)ptr);
+ m += s;
+ if (!MY_IS_INTRESOURCE(ptr))
+ {
+ m += ": \"";
+ m += ptr;
+ m += "\"";
+ }
+ OutputDebugStringW(m);
+}
+#endif
+
+static void Print_Ptr(const void *p, const char *s)
+{
+ char temp[32];
+ sprintf(temp, "%p", (const void *)p);
+ AString m;
+ m += temp;
+ m.Add_Space();
+ m += s;
+ OutputDebugStringA(m);
+}
+
+static void Print_Number(UInt32 number, const char *s)
+{
+ AString m;
+ m.Add_UInt32(number);
+ m.Add_Space();
+ m += s;
+ OutputDebugStringA(m);
+}
+
+#define ODS(sz) { Print_Ptr(this, sz); }
+#define ODS_U(s) { OutputDebugStringW(s); }
+#define ODS_(op) { op; }
+#define ODS_SPRF_s(x) { char s[256]; x; OutputDebugStringA(s); }
+
+#else
+
+#define ODS(sz)
+#define ODS_U(s)
+#define ODS_(op)
+#define ODS_SPRF_s(x)
+
+#endif
+
+
+/*
+DOCs: In Windows 7 and later, the number of items passed to
+ a verb is limited to 16 when a shortcut menu is queried.
+ The verb is then re-created and re-initialized with the full
+ selection when that verb is invoked.
+win10 tests:
+ if (the number of selected file/dir objects > 16)
+ {
+ Explorer does the following actions:
+ - it creates ctx_menu_1 IContextMenu object
+ - it calls ctx_menu_1->Initialize() with list of only up to 16 items
+ - it calls ctx_menu_1->QueryContextMenu(menu_1)
+ - if (some menu command is pressed)
+ {
+ - it gets shown string from selected menu item : shown_menu_1_string
+ - it creates another ctx_menu_2 IContextMenu object
+ - it calls ctx_menu_2->Initialize() with list of all items
+ - it calls ctx_menu_2->QueryContextMenu(menu_2)
+ - if there is menu item with shown_menu_1_string string in menu_2,
+ Explorer calls ctx_menu_2->InvokeCommand() for that item.
+ Explorer probably doesn't use VERB from first object ctx_menu_1.
+ So we must provide same shown menu strings for both objects:
+ ctx_menu_1 and ctx_menu_2.
+ }
+ }
+*/
+
+
+CZipContextMenu::CZipContextMenu():
+ _isMenuForFM(true),
+ _fileNames_WereReduced(true),
+ _dropMode(false),
+ _bitmap(NULL),
+ _writeZone((UInt32)(Int32)-1),
+ IsSeparator(false),
+ IsRoot(true),
+ CurrentSubCommand(0)
+{
+ ODS("== CZipContextMenu()");
+ InterlockedIncrement(&g_DllRefCount);
+}
+
+CZipContextMenu::~CZipContextMenu()
+{
+ ODS("== ~CZipContextMenu");
+ if (_bitmap)
+ DeleteObject(_bitmap);
+ InterlockedDecrement(&g_DllRefCount);
+}
+
+// IShellExtInit
+
+/*
+IShellExtInit::Initialize()
+ pidlFolder:
+ - for property sheet extension:
+ NULL
+ - for shortcut menu extensions:
+ pidl of folder that contains the item whose shortcut menu is being displayed:
+ - for nondefault drag-and-drop menu extensions:
+ pidl of target folder: for nondefault drag-and-drop menu extensions
+ pidlFolder == NULL in (win10): for context menu
+*/
+
+Z7_COMWF_B CZipContextMenu::Initialize(LPCITEMIDLIST pidlFolder, LPDATAOBJECT dataObject, HKEY /* hkeyProgID */)
+{
+ COM_TRY_BEGIN
+ ODS("==== CZipContextMenu::Initialize START")
+ _isMenuForFM = false;
+ _fileNames_WereReduced = true;
+ _dropMode = false;
+ _attribs.Clear();
+ _fileNames.Clear();
+ _dropPath.Empty();
+
+ if (pidlFolder)
+ {
+ ODS("==== CZipContextMenu::Initialize (pidlFolder != 0)")
+ #ifndef UNDER_CE
+ if (NShell::GetPathFromIDList(pidlFolder, _dropPath))
+ {
+ ODS("==== CZipContextMenu::Initialize path from (pidl):")
+ ODS_U(_dropPath);
+ /* win10 : path with "\\\\?\\\" prefix is returned by GetPathFromIDList, if path is long
+ we can remove super prefix here. But probably prefix
+ is not problem for following 7-zip code.
+ so we don't remove super prefix */
+ NFile::NName::If_IsSuperPath_RemoveSuperPrefix(_dropPath);
+ NName::NormalizeDirPathPrefix(_dropPath);
+ _dropMode = !_dropPath.IsEmpty();
+ }
+ else
+ #endif
+ _dropPath.Empty();
+ }
+
+ if (!dataObject)
+ return E_INVALIDARG;
+
+ #ifndef UNDER_CE
+
+ RINOK(NShell::DataObject_GetData_HDROP_or_IDLIST_Names(dataObject, _fileNames))
+ // for (unsigned y = 0; y < 10000; y++)
+ if (NShell::DataObject_GetData_FILE_ATTRS(dataObject, _attribs) != S_OK)
+ _attribs.Clear();
+
+ #endif
+
+ ODS_SPRF_s(sprintf(s, "==== CZipContextMenu::Initialize END _files=%d",
+ _fileNames.Size()))
+
+ return S_OK;
+ COM_TRY_END
+}
+
+
+/////////////////////////////
+// IContextMenu
+
+static LPCSTR const kMainVerb = "SevenZip";
+static LPCSTR const kOpenCascadedVerb = "SevenZip.OpenWithType.";
+static LPCSTR const kCheckSumCascadedVerb = "SevenZip.Checksum";
+
+
+struct CContextMenuCommand
+{
+ UInt32 flag;
+ CZipContextMenu::enum_CommandInternalID CommandInternalID;
+ LPCSTR Verb;
+ UINT ResourceID;
+};
+
+#define CMD_REC(cns, verb, ids) { NContextMenuFlags::cns, CZipContextMenu::cns, verb, ids }
+
+static const CContextMenuCommand g_Commands[] =
+{
+ CMD_REC( kOpen, "Open", IDS_CONTEXT_OPEN),
+ CMD_REC( kExtract, "Extract", IDS_CONTEXT_EXTRACT),
+ CMD_REC( kExtractHere, "ExtractHere", IDS_CONTEXT_EXTRACT_HERE),
+ CMD_REC( kExtractTo, "ExtractTo", IDS_CONTEXT_EXTRACT_TO),
+ CMD_REC( kTest, "Test", IDS_CONTEXT_TEST),
+ CMD_REC( kCompress, "Compress", IDS_CONTEXT_COMPRESS),
+ CMD_REC( kCompressEmail, "CompressEmail", IDS_CONTEXT_COMPRESS_EMAIL),
+ CMD_REC( kCompressTo7z, "CompressTo7z", IDS_CONTEXT_COMPRESS_TO),
+ CMD_REC( kCompressTo7zEmail, "CompressTo7zEmail", IDS_CONTEXT_COMPRESS_TO_EMAIL),
+ CMD_REC( kCompressToZip, "CompressToZip", IDS_CONTEXT_COMPRESS_TO),
+ CMD_REC( kCompressToZipEmail, "CompressToZipEmail", IDS_CONTEXT_COMPRESS_TO_EMAIL)
+};
+
+
+struct CHashCommand
+{
+ CZipContextMenu::enum_CommandInternalID CommandInternalID;
+ LPCSTR UserName;
+ LPCSTR MethodName;
+};
+
+static const CHashCommand g_HashCommands[] =
+{
+ { CZipContextMenu::kHash_CRC32, "CRC-32", "CRC32" },
+ { CZipContextMenu::kHash_CRC64, "CRC-64", "CRC64" },
+ { CZipContextMenu::kHash_SHA1, "SHA-1", "SHA1" },
+ { CZipContextMenu::kHash_SHA256, "SHA-256", "SHA256" },
+ { CZipContextMenu::kHash_All, "*", "*" },
+ { CZipContextMenu::kHash_Generate_SHA256, "SHA-256 -> file.sha256", "SHA256" },
+ { CZipContextMenu::kHash_TestArc, "Checksum : Test", "Hash" }
+};
+
+
+static int FindCommand(CZipContextMenu::enum_CommandInternalID &id)
+{
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Commands); i++)
+ if (g_Commands[i].CommandInternalID == id)
+ return (int)i;
+ return -1;
+}
+
+
+void CZipContextMenu::FillCommand(enum_CommandInternalID id, UString &mainString, CCommandMapItem &cmi) const
+{
+ mainString.Empty();
+ const int i = FindCommand(id);
+ if (i < 0)
+ throw 201908;
+ const CContextMenuCommand &command = g_Commands[(unsigned)i];
+ cmi.CommandInternalID = command.CommandInternalID;
+ cmi.Verb = kMainVerb;
+ cmi.Verb += command.Verb;
+ // cmi.HelpString = cmi.Verb;
+ LangString(command.ResourceID, mainString);
+ cmi.UserString = mainString;
+}
+
+
+static UString LangStringAlt(UInt32 id, const char *altString)
+{
+ UString s = LangString(id);
+ if (s.IsEmpty())
+ s = altString;
+ return s;
+}
+
+
+void CZipContextMenu::AddCommand(enum_CommandInternalID id, UString &mainString, CCommandMapItem &cmi)
+{
+ FillCommand(id, mainString, cmi);
+ _commandMap.Add(cmi);
+}
+
+
+
+/*
+note: old msdn article:
+Duplicate Menu Items In the File Menu For a Shell Context Menu Extension (214477)
+----------
+ On systems with Shell32.dll version 4.71 or higher, a context menu extension
+ for a file folder that inserts one or more pop-up menus results in duplicates
+ of these menu items.
+ This occurs when the file menu is activated more than once for the selected object.
+
+CAUSE
+ In a context menu extension, if pop-up menus are inserted using InsertMenu
+ or AppendMenu, then the ID for the pop-up menu item cannot be specified.
+ Instead, this field should take in the HMENU of the pop-up menu.
+ Because the ID is not specified for the pop-up menu item, the Shell does
+ not keep track of the menu item if the file menu is pulled down multiple times.
+ As a result, the pop-up menu items are added multiple times in the context menu.
+
+ This problem occurs only when the file menu is pulled down, and does not happen
+ when the context menu is invoked by using the right button or the context menu key.
+RESOLUTION
+ To work around this problem, use InsertMenuItem and specify the ID of the
+ pop-up menu item in the wID member of the MENUITEMINFO structure.
+*/
+
+static void MyInsertMenu(CMenu &menu, unsigned pos, UINT id, const UString &s, HBITMAP bitmap)
+{
+ if (!menu)
+ return;
+ CMenuItem mi;
+ mi.fType = MFT_STRING;
+ mi.fMask = MIIM_TYPE | MIIM_ID;
+ if (bitmap)
+ mi.fMask |= MIIM_CHECKMARKS;
+ mi.wID = id;
+ mi.StringValue = s;
+ mi.hbmpUnchecked = bitmap;
+ // mi.hbmpChecked = bitmap; // do we need hbmpChecked ???
+ if (!menu.InsertItem(pos, true, mi))
+ throw 20190816;
+
+ // SetMenuItemBitmaps also works
+ // ::SetMenuItemBitmaps(menu, pos, MF_BYPOSITION, bitmap, NULL);
+}
+
+
+static void MyAddSubMenu(
+ CObjectVector<CZipContextMenu::CCommandMapItem> &_commandMap,
+ const char *verb,
+ CMenu &menu, unsigned pos, UINT id, const UString &s, HMENU hSubMenu, HBITMAP bitmap)
+{
+ CZipContextMenu::CCommandMapItem cmi;
+ cmi.CommandInternalID = CZipContextMenu::kCommandNULL;
+ cmi.Verb = verb;
+ cmi.IsPopup = true;
+ // cmi.HelpString = verb;
+ cmi.UserString = s;
+ _commandMap.Add(cmi);
+
+ if (!menu)
+ return;
+
+ CMenuItem mi;
+ mi.fType = MFT_STRING;
+ mi.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID;
+ if (bitmap)
+ mi.fMask |= MIIM_CHECKMARKS;
+ mi.wID = id;
+ mi.hSubMenu = hSubMenu;
+ mi.hbmpUnchecked = bitmap;
+
+ mi.StringValue = s;
+ if (!menu.InsertItem(pos, true, mi))
+ throw 20190817;
+}
+
+
+static const char * const kArcExts[] =
+{
+ "7z"
+ , "bz2"
+ , "gz"
+ , "rar"
+ , "zip"
+};
+
+static bool IsItArcExt(const UString &ext)
+{
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(kArcExts); i++)
+ if (ext.IsEqualTo_Ascii_NoCase(kArcExts[i]))
+ return true;
+ return false;
+}
+
+UString GetSubFolderNameForExtract(const UString &arcName);
+UString GetSubFolderNameForExtract(const UString &arcName)
+{
+ int dotPos = arcName.ReverseFind_Dot();
+ if (dotPos < 0)
+ return Get_Correct_FsFile_Name(arcName) + L'~';
+
+ const UString ext = arcName.Ptr(dotPos + 1);
+ UString res = arcName.Left(dotPos);
+ res.TrimRight();
+ dotPos = res.ReverseFind_Dot();
+ if (dotPos > 0)
+ {
+ const UString ext2 = res.Ptr(dotPos + 1);
+ if ((ext.IsEqualTo_Ascii_NoCase("001") && IsItArcExt(ext2))
+ || (ext.IsEqualTo_Ascii_NoCase("rar") &&
+ ( ext2.IsEqualTo_Ascii_NoCase("part001")
+ || ext2.IsEqualTo_Ascii_NoCase("part01")
+ || ext2.IsEqualTo_Ascii_NoCase("part1"))))
+ res.DeleteFrom(dotPos);
+ res.TrimRight();
+ }
+ return Get_Correct_FsFile_Name(res);
+}
+
+static void ReduceString(UString &s)
+{
+ const unsigned kMaxSize = 64;
+ if (s.Len() <= kMaxSize)
+ return;
+ s.Delete(kMaxSize / 2, s.Len() - kMaxSize);
+ s.Insert(kMaxSize / 2, L" ... ");
+}
+
+static UString GetQuotedReducedString(const UString &s)
+{
+ UString s2 = s;
+ ReduceString(s2);
+ s2.Replace(L"&", L"&&");
+ return GetQuotedString(s2);
+}
+
+static void MyFormatNew_ReducedName(UString &s, const UString &name)
+{
+ s = MyFormatNew(s, GetQuotedReducedString(name));
+}
+
+static const char * const kExtractExcludeExtensions =
+ " 3gp"
+ " aac ans ape asc asm asp aspx avi awk"
+ " bas bat bmp"
+ " c cs cls clw cmd cpp csproj css ctl cxx"
+ " def dep dlg dsp dsw"
+ " eps"
+ " f f77 f90 f95 fla flac frm"
+ " gif"
+ " h hpp hta htm html hxx"
+ " ico idl inc ini inl"
+ " java jpeg jpg js"
+ " la lnk log"
+ " mak manifest wmv mov mp3 mp4 mpe mpeg mpg m4a"
+ " ofr ogg"
+ " pac pas pdf php php3 php4 php5 phptml pl pm png ps py pyo"
+ " ra rb rc reg rka rm rtf"
+ " sed sh shn shtml sln sql srt swa"
+ " tcl tex tiff tta txt"
+ " vb vcproj vbs"
+ " wav wma wv"
+ " xml xsd xsl xslt"
+ " ";
+
+/*
+static const char * const kNoOpenAsExtensions =
+ " 7z arj bz2 cab chm cpio flv gz lha lzh lzma rar swm tar tbz2 tgz wim xar xz z zip ";
+*/
+
+static const char * const kOpenTypes[] =
+{
+ ""
+ , "*"
+ , "#"
+ , "#:e"
+ // , "#:a"
+ , "7z"
+ , "zip"
+ , "cab"
+ , "rar"
+};
+
+
+bool FindExt(const char *p, const UString &name, CStringFinder &finder);
+bool FindExt(const char *p, const UString &name, CStringFinder &finder)
+{
+ const int dotPos = name.ReverseFind_Dot();
+ if (dotPos < 0 || dotPos == (int)name.Len() - 1)
+ return false;
+ return finder.FindWord_In_LowCaseAsciiList_NoCase(p, name.Ptr(dotPos + 1));
+}
+
+/* returns false, if extraction of that file extension is not expected */
+static bool DoNeedExtract(const UString &name, CStringFinder &finder)
+{
+ // for (int y = 0; y < 1000; y++) FindExt(kExtractExcludeExtensions, name);
+ return !FindExt(kExtractExcludeExtensions, name, finder);
+}
+
+// we must use diferent Verbs for Popup subMenu.
+void CZipContextMenu::AddMapItem_ForSubMenu(const char *verb)
+{
+ CCommandMapItem cmi;
+ cmi.CommandInternalID = kCommandNULL;
+ cmi.Verb = verb;
+ // cmi.HelpString = verb;
+ _commandMap.Add(cmi);
+}
+
+
+static HRESULT RETURN_WIN32_LastError_AS_HRESULT()
+{
+ DWORD lastError = ::GetLastError();
+ if (lastError == 0)
+ return E_FAIL;
+ return HRESULT_FROM_WIN32(lastError);
+}
+
+
+/*
+ we add CCommandMapItem to _commandMap for each new Menu ID.
+ so then we use _commandMap[offset].
+ That way we can execute commands that have menu item.
+ Another non-implemented way:
+ We can return the number off all possible commands in QueryContextMenu().
+ so the caller could call InvokeCommand() via string verb even
+ without using menu items.
+*/
+
+
+Z7_COMWF_B CZipContextMenu::QueryContextMenu(HMENU hMenu, UINT indexMenu,
+ UINT commandIDFirst, UINT commandIDLast, UINT flags)
+{
+ ODS("+ QueryContextMenu()")
+ COM_TRY_BEGIN
+ try {
+
+ _commandMap.Clear();
+
+ ODS_SPRF_s(sprintf(s, "QueryContextMenu: index=%u first=%u last=%u flags=%x _files=%u",
+ indexMenu, commandIDFirst, commandIDLast, flags, _fileNames.Size()))
+ /*
+ for (UInt32 i = 0; i < _fileNames.Size(); i++)
+ {
+ ODS_U(_fileNames[i])
+ }
+ */
+
+ if (_fileNames.Size() == 0)
+ {
+ return MAKE_HRESULT(SEVERITY_SUCCESS, 0, 0);
+ // return E_INVALIDARG;
+ }
+
+ if (commandIDFirst > commandIDLast)
+ return E_INVALIDARG;
+
+ UINT currentCommandID = commandIDFirst;
+
+ if ((flags & 0x000F) != CMF_NORMAL
+ && (flags & CMF_VERBSONLY) == 0
+ && (flags & CMF_EXPLORE) == 0)
+ return MAKE_HRESULT(SEVERITY_SUCCESS, 0, currentCommandID - commandIDFirst);
+ // return MAKE_HRESULT(SEVERITY_SUCCESS, 0, currentCommandID);
+ // 19.01 : we changed from (currentCommandID) to (currentCommandID - commandIDFirst)
+ // why it was so before?
+
+#ifdef Z7_LANG
+ LoadLangOneTime();
+#endif
+
+ CMenu popupMenu;
+ CMenuDestroyer menuDestroyer;
+
+ ODS("### 40")
+ CContextMenuInfo ci;
+ ci.Load();
+ ODS("### 44")
+
+ _elimDup = ci.ElimDup;
+ _writeZone = ci.WriteZone;
+
+ HBITMAP bitmap = NULL;
+ if (ci.MenuIcons.Val)
+ {
+ ODS("### 45")
+ if (!_bitmap)
+ _bitmap = ::LoadBitmap(g_hInstance, MAKEINTRESOURCE(IDB_MENU_LOGO));
+ bitmap = _bitmap;
+ }
+
+ UINT subIndex = indexMenu;
+
+ ODS("### 50")
+
+ if (ci.Cascaded.Val)
+ {
+ if (hMenu)
+ if (!popupMenu.CreatePopup())
+ return RETURN_WIN32_LastError_AS_HRESULT();
+ menuDestroyer.Attach(popupMenu);
+
+ /* 9.31: we commented the following code. Probably we don't need.
+ Check more systems. Maybe it was for old Windows? */
+ /*
+ AddMapItem_ForSubMenu();
+ currentCommandID++;
+ */
+ subIndex = 0;
+ }
+ else
+ {
+ popupMenu.Attach(hMenu);
+ CMenuItem mi;
+ mi.fType = MFT_SEPARATOR;
+ mi.fMask = MIIM_TYPE;
+ if (hMenu)
+ popupMenu.InsertItem(subIndex++, true, mi);
+ }
+
+ const UInt32 contextMenuFlags = ci.Flags;
+
+ NFind::CFileInfo fi0;
+ FString folderPrefix;
+
+ if (_fileNames.Size() > 0)
+ {
+ const UString &fileName = _fileNames.Front();
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (NName::IsDevicePath(us2fs(fileName)))
+ {
+ // CFileInfo::Find can be slow for device files. So we don't call it.
+ // we need only name here.
+ fi0.Name = us2fs(fileName.Ptr(NName::kDevicePathPrefixSize));
+ folderPrefix =
+ #ifdef UNDER_CE
+ "\\";
+ #else
+ "C:\\";
+ #endif
+ }
+ else
+ #endif
+ {
+ if (!fi0.Find(us2fs(fileName)))
+ {
+ throw 20190820;
+ // return RETURN_WIN32_LastError_AS_HRESULT();
+ }
+ GetOnlyDirPrefix(us2fs(fileName), folderPrefix);
+ }
+ }
+
+ ODS("### 100")
+
+ UString mainString;
+ CStringFinder finder;
+ UStringVector fileNames_Reduced;
+ const unsigned k_Explorer_NumReducedItems = 16;
+ const bool needReduce = !_isMenuForFM && (_fileNames.Size() >= k_Explorer_NumReducedItems);
+ _fileNames_WereReduced = needReduce;
+ // _fileNames_WereReduced = true; // for debug;
+ const UStringVector *fileNames = &_fileNames;
+ if (needReduce)
+ {
+ for (unsigned i = 0; i < k_Explorer_NumReducedItems
+ && i < _fileNames.Size(); i++)
+ fileNames_Reduced.Add(_fileNames[i]);
+ fileNames = &fileNames_Reduced;
+ }
+
+ /*
+ if (_fileNames.Size() == k_Explorer_NumReducedItems) // for debug
+ {
+ for (int i = 0; i < 10; i++)
+ {
+ CCommandMapItem cmi;
+ AddCommand(kCompressToZipEmail, mainString, cmi);
+ MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap);
+ }
+ }
+ */
+
+ if (_fileNames.Size() == 1 && currentCommandID + 14 <= commandIDLast)
+ {
+ if (!fi0.IsDir() && DoNeedExtract(fs2us(fi0.Name), finder))
+ {
+ // Open
+ const bool thereIsMainOpenItem = ((contextMenuFlags & NContextMenuFlags::kOpen) != 0);
+ if (thereIsMainOpenItem)
+ {
+ CCommandMapItem cmi;
+ AddCommand(kOpen, mainString, cmi);
+ MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap);
+ }
+ if ((contextMenuFlags & NContextMenuFlags::kOpenAs) != 0
+ // && (!thereIsMainOpenItem || !FindExt(kNoOpenAsExtensions, fi0.Name))
+ && hMenu // we want to reduce number of menu items below 16
+ )
+ {
+ CMenu subMenu;
+ if (!hMenu || subMenu.CreatePopup())
+ {
+ MyAddSubMenu(_commandMap, kOpenCascadedVerb, popupMenu, subIndex++, currentCommandID++, LangString(IDS_CONTEXT_OPEN), subMenu, bitmap);
+ _commandMap.Back().CtxCommandType = CtxCommandType_OpenRoot;
+
+ UINT subIndex2 = 0;
+ for (unsigned i = (thereIsMainOpenItem ? 1 : 0); i < Z7_ARRAY_SIZE(kOpenTypes); i++)
+ {
+ CCommandMapItem cmi;
+ if (i == 0)
+ FillCommand(kOpen, mainString, cmi);
+ else
+ {
+ mainString = kOpenTypes[i];
+ cmi.CommandInternalID = kOpen;
+ cmi.Verb = kMainVerb;
+ cmi.Verb += ".Open.";
+ cmi.Verb += mainString;
+ // cmi.HelpString = cmi.Verb;
+ cmi.ArcType = mainString;
+ cmi.CtxCommandType = CtxCommandType_OpenChild;
+ }
+ _commandMap.Add(cmi);
+ Set_UserString_in_LastCommand(mainString);
+ MyInsertMenu(subMenu, subIndex2++, currentCommandID++, mainString, bitmap);
+ }
+
+ subMenu.Detach();
+ }
+ }
+ }
+ }
+
+ ODS("### 150")
+
+ if (_fileNames.Size() > 0 && currentCommandID + 10 <= commandIDLast)
+ {
+ ODS("### needExtract list START")
+ const bool needExtendedVerbs = ((flags & Z7_WIN_CMF_EXTENDEDVERBS) != 0);
+ // || _isMenuForFM;
+ bool needExtract = true;
+ bool areDirs = fi0.IsDir() || (unsigned)_attribs.FirstDirIndex < k_Explorer_NumReducedItems;
+ if (!needReduce)
+ areDirs = areDirs || (_attribs.FirstDirIndex != -1);
+ if (areDirs)
+ needExtract = false;
+
+ if (!needExtendedVerbs)
+ if (needExtract)
+ {
+ UString name;
+ const unsigned numItemsCheck = fileNames->Size();
+ for (unsigned i = 0; i < numItemsCheck; i++)
+ {
+ const UString &a = (*fileNames)[i];
+ const int slash = a.ReverseFind_PathSepar();
+ name = a.Ptr(slash + 1);
+ // for (int y = 0; y < 600; y++) // for debug
+ const bool needExtr2 = DoNeedExtract(name, finder);
+ if (!needExtr2)
+ {
+ needExtract = needExtr2;
+ break;
+ }
+ }
+ }
+ ODS("### needExtract list END")
+
+ if (needExtract)
+ {
+ {
+ UString baseFolder = fs2us(folderPrefix);
+ if (_dropMode)
+ baseFolder = _dropPath;
+
+ UString specFolder ('*');
+ if (_fileNames.Size() == 1)
+ specFolder = GetSubFolderNameForExtract(fs2us(fi0.Name));
+ specFolder.Add_PathSepar();
+
+ if ((contextMenuFlags & NContextMenuFlags::kExtract) != 0)
+ {
+ // Extract
+ CCommandMapItem cmi;
+ cmi.Folder = baseFolder + specFolder;
+ AddCommand(kExtract, mainString, cmi);
+ MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap);
+ }
+
+ if ((contextMenuFlags & NContextMenuFlags::kExtractHere) != 0)
+ {
+ // Extract Here
+ CCommandMapItem cmi;
+ cmi.Folder = baseFolder;
+ AddCommand(kExtractHere, mainString, cmi);
+ MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap);
+ }
+
+ if ((contextMenuFlags & NContextMenuFlags::kExtractTo) != 0)
+ {
+ // Extract To
+ CCommandMapItem cmi;
+ UString s;
+ cmi.Folder = baseFolder + specFolder;
+ AddCommand(kExtractTo, s, cmi);
+ MyFormatNew_ReducedName(s, specFolder);
+ Set_UserString_in_LastCommand(s);
+ MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap);
+ }
+ }
+
+ if ((contextMenuFlags & NContextMenuFlags::kTest) != 0)
+ {
+ // Test
+ CCommandMapItem cmi;
+ AddCommand(kTest, mainString, cmi);
+ // if (_fileNames.Size() == 16) mainString += "_[16]"; // for debug
+ MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap);
+ }
+ }
+
+ ODS("### CreateArchiveName START")
+ UString arcName_base;
+ const UString arcName = CreateArchiveName(
+ *fileNames,
+ false, // isHash
+ fileNames->Size() == 1 ? &fi0 : NULL,
+ arcName_base);
+ ODS("### CreateArchiveName END")
+ UString arcName_Show = arcName;
+ if (needReduce)
+ {
+ /* we need same arcName_Show for two calls from Explorer:
+ 1) reduced call (only first 16 items)
+ 2) full call with all items (can be >= 16 items)
+ (fileNames) array was reduced to 16 items.
+ So we will have same (arcName) in both reduced and full calls.
+ If caller (Explorer) uses (reduce_to_first_16_items) scheme,
+ we can use (arcName) here instead of (arcName_base).
+ (arcName_base) has no number in name.
+ */
+ arcName_Show = arcName_base; // we can comment that line
+ /* we use "_" in archive name as sign to user
+ that shows that final archive name can be changed. */
+ arcName_Show += "_";
+ }
+
+ UString arcName_7z = arcName;
+ arcName_7z += ".7z";
+ UString arcName_7z_Show = arcName_Show;
+ arcName_7z_Show += ".7z";
+ UString arcName_zip = arcName;
+ arcName_zip += ".zip";
+ UString arcName_zip_Show = arcName_Show;
+ arcName_zip_Show += ".zip";
+
+
+ // Compress
+ if ((contextMenuFlags & NContextMenuFlags::kCompress) != 0)
+ {
+ CCommandMapItem cmi;
+ if (_dropMode)
+ cmi.Folder = _dropPath;
+ else
+ cmi.Folder = fs2us(folderPrefix);
+ cmi.ArcName = arcName;
+ AddCommand(kCompress, mainString, cmi);
+ MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap);
+ }
+
+ #ifdef EMAIL_SUPPORT
+ // CompressEmail
+ if ((contextMenuFlags & NContextMenuFlags::kCompressEmail) != 0 && !_dropMode)
+ {
+ CCommandMapItem cmi;
+ cmi.ArcName = arcName;
+ AddCommand(kCompressEmail, mainString, cmi);
+ MyInsertMenu(popupMenu, subIndex++, currentCommandID++, mainString, bitmap);
+ }
+ #endif
+
+ // CompressTo7z
+ if (contextMenuFlags & NContextMenuFlags::kCompressTo7z &&
+ !arcName_7z.IsEqualTo_NoCase(fs2us(fi0.Name)))
+ {
+ CCommandMapItem cmi;
+ UString s;
+ if (_dropMode)
+ cmi.Folder = _dropPath;
+ else
+ cmi.Folder = fs2us(folderPrefix);
+ cmi.ArcName = arcName_7z;
+ cmi.ArcType = "7z";
+ AddCommand(kCompressTo7z, s, cmi);
+ MyFormatNew_ReducedName(s, arcName_7z_Show);
+ Set_UserString_in_LastCommand(s);
+ MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap);
+ }
+
+ #ifdef EMAIL_SUPPORT
+ // CompressTo7zEmail
+ if ((contextMenuFlags & NContextMenuFlags::kCompressTo7zEmail) != 0 && !_dropMode)
+ {
+ CCommandMapItem cmi;
+ UString s;
+ cmi.ArcName = arcName_7z;
+ cmi.ArcType = "7z";
+ AddCommand(kCompressTo7zEmail, s, cmi);
+ MyFormatNew_ReducedName(s, arcName_7z_Show);
+ Set_UserString_in_LastCommand(s);
+ MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap);
+ }
+ #endif
+
+ // CompressToZip
+ if (contextMenuFlags & NContextMenuFlags::kCompressToZip &&
+ !arcName_zip.IsEqualTo_NoCase(fs2us(fi0.Name)))
+ {
+ CCommandMapItem cmi;
+ UString s;
+ if (_dropMode)
+ cmi.Folder = _dropPath;
+ else
+ cmi.Folder = fs2us(folderPrefix);
+ cmi.ArcName = arcName_zip;
+ cmi.ArcType = "zip";
+ AddCommand(kCompressToZip, s, cmi);
+ MyFormatNew_ReducedName(s, arcName_zip_Show);
+ Set_UserString_in_LastCommand(s);
+ MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap);
+ }
+
+ #ifdef EMAIL_SUPPORT
+ // CompressToZipEmail
+ if ((contextMenuFlags & NContextMenuFlags::kCompressToZipEmail) != 0 && !_dropMode)
+ {
+ CCommandMapItem cmi;
+ UString s;
+ cmi.ArcName = arcName_zip;
+ cmi.ArcType = "zip";
+ AddCommand(kCompressToZipEmail, s, cmi);
+ MyFormatNew_ReducedName(s, arcName_zip_Show);
+ Set_UserString_in_LastCommand(s);
+ MyInsertMenu(popupMenu, subIndex++, currentCommandID++, s, bitmap);
+ }
+ #endif
+ }
+
+ ODS("### 300")
+
+ // don't use InsertMenu: See MSDN:
+ // PRB: Duplicate Menu Items In the File Menu For a Shell Context Menu Extension
+ // ID: Q214477
+
+ if (ci.Cascaded.Val)
+ {
+ CMenu menu;
+ menu.Attach(hMenu);
+ menuDestroyer.Disable();
+ MyAddSubMenu(_commandMap, kMainVerb, menu, indexMenu++, currentCommandID++, (UString)"7-Zip",
+ popupMenu, // popupMenu.Detach(),
+ bitmap);
+ }
+ else
+ {
+ // popupMenu.Detach();
+ indexMenu = subIndex;
+ }
+
+ ODS("### 350")
+
+ const bool needCrc = ((contextMenuFlags &
+ (NContextMenuFlags::kCRC |
+ NContextMenuFlags::kCRC_Cascaded)) != 0);
+
+ if (
+ // !_isMenuForFM && // 21.04: we don't hide CRC SHA menu in 7-Zip FM
+ needCrc
+ && currentCommandID + 1 < commandIDLast)
+ {
+ CMenu subMenu;
+ // CMenuDestroyer menuDestroyer_CRC;
+
+ UINT subIndex_CRC = 0;
+
+ if (!hMenu || subMenu.CreatePopup())
+ {
+ // menuDestroyer_CRC.Attach(subMenu);
+ const bool insertHashMenuTo7zipMenu = (ci.Cascaded.Val
+ && (contextMenuFlags & NContextMenuFlags::kCRC_Cascaded) != 0);
+
+ CMenu menu;
+ {
+ unsigned indexInParent;
+ if (insertHashMenuTo7zipMenu)
+ {
+ indexInParent = subIndex;
+ menu.Attach(popupMenu);
+ }
+ else
+ {
+ indexInParent = indexMenu;
+ menu.Attach(hMenu);
+ // menuDestroyer_CRC.Disable();
+ }
+ MyAddSubMenu(_commandMap, kCheckSumCascadedVerb, menu, indexInParent++, currentCommandID++, (UString)"CRC SHA", subMenu,
+ /* insertHashMenuTo7zipMenu ? NULL : */ bitmap);
+ _commandMap.Back().CtxCommandType = CtxCommandType_CrcRoot;
+ if (!insertHashMenuTo7zipMenu)
+ indexMenu = indexInParent;
+ }
+
+ ODS("### HashCommands")
+
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_HashCommands); i++)
+ {
+ if (currentCommandID >= commandIDLast)
+ break;
+ const CHashCommand &hc = g_HashCommands[i];
+ CCommandMapItem cmi;
+ cmi.CommandInternalID = hc.CommandInternalID;
+ cmi.Verb = kCheckSumCascadedVerb;
+ cmi.Verb.Add_Dot();
+ UString s;
+ s += hc.UserName;
+
+ if (hc.CommandInternalID == kHash_Generate_SHA256)
+ {
+ cmi.Verb += "Generate";
+ {
+ popupMenu.Attach(hMenu);
+ CMenuItem mi;
+ mi.fType = MFT_SEPARATOR;
+ mi.fMask = MIIM_TYPE;
+ subMenu.InsertItem(subIndex_CRC++, true, mi);
+ }
+
+ UString name;
+ UString showName;
+ ODS("### Hash CreateArchiveName Start")
+ // for (int y = 0; y < 10000; y++) // for debug
+ // if (fileNames->Size() == 1) name = fs2us(fi0.Name); else
+ name = CreateArchiveName(
+ *fileNames,
+ true, // isHash
+ fileNames->Size() == 1 ? &fi0 : NULL,
+ showName);
+ if (needReduce)
+ showName += "_";
+ else
+ showName = name;
+
+ ODS("### Hash CreateArchiveName END")
+ name += ".sha256";
+ showName += ".sha256";
+ cmi.Folder = fs2us(folderPrefix);
+ cmi.ArcName = name;
+ s = "SHA-256 -> ";
+ s += showName;
+ }
+ else if (hc.CommandInternalID == kHash_TestArc)
+ {
+ cmi.Verb += "Test";
+ s = LangStringAlt(IDS_CONTEXT_TEST, "Test archive");
+ s += " : ";
+ s += GetNameOfProperty(kpidChecksum, UString("Checksum"));
+ }
+ else
+ cmi.Verb += "Calc";
+
+ cmi.Verb.Add_Dot();
+ cmi.Verb += hc.MethodName;
+
+ // cmi.HelpString = cmi.Verb;
+ cmi.UserString = s;
+ cmi.CtxCommandType = CtxCommandType_CrcChild;
+ _commandMap.Add(cmi);
+ MyInsertMenu(subMenu, subIndex_CRC++, currentCommandID++, s, bitmap);
+ ODS("### 380")
+ }
+
+ subMenu.Detach();
+ }
+ }
+
+ popupMenu.Detach();
+ /*
+ if (!ci.Cascaded.Val)
+ indexMenu = subIndex;
+ */
+ const unsigned numCommands = currentCommandID - commandIDFirst;
+ ODS("+ QueryContextMenu() END")
+ ODS_SPRF_s(sprintf(s, "Commands=%u currentCommandID - commandIDFirst = %u",
+ _commandMap.Size(), numCommands))
+ if (_commandMap.Size() != numCommands)
+ throw 20190818;
+ /*
+ FOR_VECTOR (k, _commandMap)
+ {
+ ODS_U(_commandMap[k].Verb);
+ }
+ */
+ }
+ catch(...)
+ {
+ ODS_SPRF_s(sprintf(s, "catch() exception: Commands=%u", _commandMap.Size()))
+ if (_commandMap.Size() == 0)
+ throw;
+ }
+ /* we added some menu items already : num_added_menu_items,
+ So we MUST return (number_of_defined_ids), where (number_of_defined_ids >= num_added_menu_items)
+ This will prevent incorrect menu working, when same IDs can be
+ assigned in multiple menu items from different subhandlers.
+ And we must add items to _commandMap before adding to menu.
+ */
+ return MAKE_HRESULT(SEVERITY_SUCCESS, 0, _commandMap.Size());
+ COM_TRY_END
+}
+
+
+int CZipContextMenu::FindVerb(const UString &verb) const
+{
+ FOR_VECTOR (i, _commandMap)
+ if (_commandMap[i].Verb == verb)
+ return (int)i;
+ return -1;
+}
+
+static UString Get7zFmPath()
+{
+ return fs2us(NWindows::NDLL::GetModuleDirPrefix()) + L"7zFM.exe";
+}
+
+
+Z7_COMWF_B CZipContextMenu::InvokeCommand(LPCMINVOKECOMMANDINFO commandInfo)
+{
+ COM_TRY_BEGIN
+
+ ODS("==== CZipContextMenu::InvokeCommand()")
+
+ #ifdef SHOW_DEBUG_CTX_MENU
+
+ ODS_SPRF_s(sprintf(s, ": InvokeCommand: cbSize=%u flags=%x ",
+ (unsigned)commandInfo->cbSize, (unsigned)commandInfo->fMask))
+
+ PrintStringA("Verb", commandInfo->lpVerb);
+ PrintStringA("Parameters", commandInfo->lpParameters);
+ PrintStringA("Directory", commandInfo->lpDirectory);
+ #endif
+
+ int commandOffset = -1;
+
+ // xp64 / Win10 : explorer.exe sends 0 in lpVerbW
+ // MSDN: if (IS_INTRESOURCE(lpVerbW)), we must use LOWORD(lpVerb) as command offset
+
+ // FIXME: old MINGW doesn't define CMINVOKECOMMANDINFOEX / CMIC_MASK_UNICODE
+ #if !defined(UNDER_CE) && defined(CMIC_MASK_UNICODE)
+ bool unicodeVerb = false;
+ if (commandInfo->cbSize == sizeof(CMINVOKECOMMANDINFOEX) &&
+ (commandInfo->fMask & CMIC_MASK_UNICODE) != 0)
+ {
+ LPCMINVOKECOMMANDINFOEX commandInfoEx = (LPCMINVOKECOMMANDINFOEX)commandInfo;
+ if (!MY_IS_INTRESOURCE(commandInfoEx->lpVerbW))
+ {
+ unicodeVerb = true;
+ commandOffset = FindVerb(commandInfoEx->lpVerbW);
+ }
+
+ #ifdef SHOW_DEBUG_CTX_MENU
+ PrintStringW("VerbW", commandInfoEx->lpVerbW);
+ PrintStringW("ParametersW", commandInfoEx->lpParametersW);
+ PrintStringW("DirectoryW", commandInfoEx->lpDirectoryW);
+ PrintStringW("TitleW", commandInfoEx->lpTitleW);
+ PrintStringA("Title", commandInfoEx->lpTitle);
+ #endif
+ }
+ if (!unicodeVerb)
+ #endif
+ {
+ ODS("use non-UNICODE verb")
+ // if (HIWORD(commandInfo->lpVerb) == 0)
+ if (MY_IS_INTRESOURCE(commandInfo->lpVerb))
+ commandOffset = LOWORD(commandInfo->lpVerb);
+ else
+ commandOffset = FindVerb(GetUnicodeString(commandInfo->lpVerb));
+ }
+
+ ODS_SPRF_s(sprintf(s, "commandOffset=%d", commandOffset))
+
+ if (/* commandOffset < 0 || */ (unsigned)commandOffset >= _commandMap.Size())
+ return E_INVALIDARG;
+ const CCommandMapItem &cmi = _commandMap[(unsigned)commandOffset];
+ return InvokeCommandCommon(cmi);
+ COM_TRY_END
+}
+
+
+HRESULT CZipContextMenu::InvokeCommandCommon(const CCommandMapItem &cmi)
+{
+ const enum_CommandInternalID cmdID = cmi.CommandInternalID;
+
+ try
+ {
+ switch (cmdID)
+ {
+ case kOpen:
+ {
+ UString params;
+ params = GetQuotedString(_fileNames[0]);
+ if (!cmi.ArcType.IsEmpty())
+ {
+ params += " -t";
+ params += cmi.ArcType;
+ }
+ MyCreateProcess(Get7zFmPath(), params);
+ break;
+ }
+ case kExtract:
+ case kExtractHere:
+ case kExtractTo:
+ {
+ if (_attribs.FirstDirIndex != -1)
+ {
+ ShowErrorMessageRes(IDS_SELECT_FILES);
+ break;
+ }
+ ExtractArchives(_fileNames, cmi.Folder,
+ (cmdID == kExtract), // showDialog
+ (cmdID == kExtractTo) && _elimDup.Val, // elimDup
+ _writeZone
+ );
+ break;
+ }
+ case kTest:
+ {
+ TestArchives(_fileNames);
+ break;
+ }
+ case kCompress:
+ case kCompressEmail:
+ case kCompressTo7z:
+ case kCompressTo7zEmail:
+ case kCompressToZip:
+ case kCompressToZipEmail:
+ {
+ UString arcName = cmi.ArcName;
+ if (_fileNames_WereReduced)
+ {
+ UString arcName_base;
+ arcName = CreateArchiveName(
+ _fileNames,
+ false, // isHash
+ NULL, // fi0
+ arcName_base);
+ const char *postfix = NULL;
+ if (cmdID == kCompressTo7z ||
+ cmdID == kCompressTo7zEmail)
+ postfix = ".7z";
+ else if (
+ cmdID == kCompressToZip ||
+ cmdID == kCompressToZipEmail)
+ postfix = ".zip";
+ if (postfix)
+ arcName += postfix;
+ }
+
+ const bool email =
+ cmdID == kCompressEmail ||
+ cmdID == kCompressTo7zEmail ||
+ cmdID == kCompressToZipEmail;
+ const bool showDialog =
+ cmdID == kCompress ||
+ cmdID == kCompressEmail;
+ const bool addExtension = showDialog;
+ CompressFiles(cmi.Folder,
+ arcName, cmi.ArcType,
+ addExtension,
+ _fileNames, email, showDialog,
+ false // waitFinish
+ );
+ break;
+ }
+
+ case kHash_CRC32:
+ case kHash_CRC64:
+ case kHash_SHA1:
+ case kHash_SHA256:
+ case kHash_All:
+ case kHash_Generate_SHA256:
+ case kHash_TestArc:
+ {
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_HashCommands); i++)
+ {
+ const CHashCommand &hc = g_HashCommands[i];
+ if (hc.CommandInternalID == cmdID)
+ {
+ if (cmdID == kHash_TestArc)
+ {
+ TestArchives(_fileNames, true); // hashMode
+ break;
+ }
+ UString generateName;
+ if (cmdID == kHash_Generate_SHA256)
+ {
+ generateName = cmi.ArcName;
+ if (_fileNames_WereReduced)
+ {
+ UString arcName_base;
+ generateName = CreateArchiveName(_fileNames,
+ true, // isHash
+ NULL, // fi0
+ arcName_base);
+ generateName += ".sha256";
+ }
+ }
+ CalcChecksum(_fileNames, (UString)hc.MethodName,
+ cmi.Folder, generateName);
+ break;
+ }
+ }
+ break;
+ }
+ case kCommandNULL:
+ break;
+ }
+ }
+ catch(...)
+ {
+ ShowErrorMessage(NULL, L"Error");
+ }
+ return S_OK;
+}
+
+
+
+static void MyCopyString_isUnicode(void *dest, UINT size, const UString &src, bool writeInUnicode)
+{
+ if (size != 0)
+ size--;
+ if (writeInUnicode)
+ {
+ UString s = src;
+ s.DeleteFrom(size);
+ MyStringCopy((wchar_t *)dest, s);
+ ODS_U(s)
+ }
+ else
+ {
+ AString s = GetAnsiString(src);
+ s.DeleteFrom(size);
+ MyStringCopy((char *)dest, s);
+ }
+}
+
+
+Z7_COMWF_B CZipContextMenu::GetCommandString(
+ #ifdef Z7_OLD_WIN_SDK
+ UINT
+ #else
+ UINT_PTR
+ #endif
+ commandOffset,
+ UINT uType,
+ UINT * /* pwReserved */ , LPSTR pszName, UINT cchMax)
+{
+ COM_TRY_BEGIN
+
+ ODS("GetCommandString")
+
+ const int cmdOffset = (int)commandOffset;
+
+ ODS_SPRF_s(sprintf(s, "GetCommandString: cmdOffset=%d uType=%d cchMax = %d",
+ cmdOffset, uType, cchMax))
+
+ if ((uType | GCS_UNICODE) == GCS_VALIDATEW)
+ {
+ if (/* cmdOffset < 0 || */ (unsigned)cmdOffset >= _commandMap.Size())
+ return S_FALSE;
+ return S_OK;
+ }
+
+ if (/* cmdOffset < 0 || */ (unsigned)cmdOffset >= _commandMap.Size())
+ {
+ ODS("------ cmdOffset: E_INVALIDARG")
+ return E_INVALIDARG;
+ }
+
+ // we use Verb as HelpString
+ if (cchMax != 0)
+ if ((uType | GCS_UNICODE) == GCS_VERBW ||
+ (uType | GCS_UNICODE) == GCS_HELPTEXTW)
+ {
+ const CCommandMapItem &cmi = _commandMap[(unsigned)cmdOffset];
+ MyCopyString_isUnicode(pszName, cchMax, cmi.Verb, (uType & GCS_UNICODE) != 0);
+ return S_OK;
+ }
+
+ return E_INVALIDARG;
+
+ COM_TRY_END
+}
+
+
+
+// ---------- IExplorerCommand ----------
+
+static HRESULT WINAPI My_SHStrDupW(LPCWSTR src, LPWSTR *dest)
+{
+ if (src)
+ {
+ const SIZE_T size = (wcslen(src) + 1) * sizeof(WCHAR);
+ WCHAR *p = (WCHAR *)CoTaskMemAlloc(size);
+ if (p)
+ {
+ memcpy(p, src, size);
+ *dest = p;
+ return S_OK;
+ }
+ }
+ *dest = NULL;
+ return E_OUTOFMEMORY;
+}
+
+
+#define CZipExplorerCommand CZipContextMenu
+
+class CCoTaskWSTR
+{
+ LPWSTR m_str;
+ Z7_CLASS_NO_COPY(CCoTaskWSTR)
+public:
+ CCoTaskWSTR(): m_str(NULL) {}
+ ~CCoTaskWSTR() { ::CoTaskMemFree(m_str); }
+ LPWSTR* operator&() { return &m_str; }
+ operator LPCWSTR () const { return m_str; }
+ // operator LPCOLESTR() const { return m_str; }
+ operator bool() const { return m_str != NULL; }
+ // bool operator!() const { return m_str == NULL; }
+
+ /*
+ void Wipe_and_Free()
+ {
+ if (m_str)
+ {
+ memset(m_str, 0, ::SysStringLen(m_str) * sizeof(*m_str));
+ Empty();
+ }
+ }
+ */
+
+private:
+ /*
+ CCoTaskWSTR(LPCOLESTR src) { m_str = ::CoTaskMemAlloc(src); }
+
+ CCoTaskWSTR& operator=(LPCOLESTR src)
+ {
+ ::CoTaskMemFree(m_str);
+ m_str = ::SysAllocString(src);
+ return *this;
+ }
+
+
+ void Empty()
+ {
+ ::CoTaskMemFree(m_str);
+ m_str = NULL;
+ }
+ */
+};
+
+static HRESULT LoadPaths(IShellItemArray *psiItemArray, UStringVector &paths)
+{
+ if (psiItemArray)
+ {
+ DWORD numItems = 0;
+ RINOK(psiItemArray->GetCount(&numItems))
+ {
+ ODS_(Print_Number(numItems, " ==== LoadPaths START === "))
+ for (DWORD i = 0; i < numItems; i++)
+ {
+ CMyComPtr<IShellItem> item;
+ RINOK(psiItemArray->GetItemAt(i, &item))
+ if (item)
+ {
+ CCoTaskWSTR displayName;
+ if (item->GetDisplayName(SIGDN_FILESYSPATH, &displayName) == S_OK
+ && (bool)displayName)
+ {
+ ODS_U(displayName)
+ paths.Add((LPCWSTR)displayName);
+ }
+ }
+ }
+ ODS_(Print_Number(numItems, " ==== LoadPaths END === "))
+ }
+ }
+ return S_OK;
+}
+
+
+void CZipExplorerCommand::LoadItems(IShellItemArray *psiItemArray)
+{
+ SubCommands.Clear();
+ _fileNames.Clear();
+ {
+ UStringVector paths;
+ if (LoadPaths(psiItemArray, paths) != S_OK)
+ return;
+ _fileNames = paths;
+ }
+ const HRESULT res = QueryContextMenu(
+ NULL, // hMenu,
+ 0, // indexMenu,
+ 0, // commandIDFirst,
+ 0 + 999, // commandIDLast,
+ CMF_NORMAL);
+
+ if (FAILED(res))
+ return /* res */;
+
+ CZipExplorerCommand *crcHandler = NULL;
+ CZipExplorerCommand *openHandler = NULL;
+
+ bool useCascadedCrc = true; // false;
+ bool useCascadedOpen = true; // false;
+
+ for (unsigned i = 0; i < _commandMap.Size(); i++)
+ {
+ const CCommandMapItem &cmi = _commandMap[i];
+
+ if (cmi.IsPopup)
+ if (!cmi.IsSubMenu())
+ continue;
+
+ // if (cmi.IsSubMenu()) continue // for debug
+
+ CZipContextMenu *shellExt = new CZipContextMenu();
+ shellExt->IsRoot = false;
+
+ if (cmi.CtxCommandType == CtxCommandType_CrcRoot && !useCascadedCrc)
+ shellExt->IsSeparator = true;
+
+ {
+ CZipExplorerCommand *handler = this;
+ if (cmi.CtxCommandType == CtxCommandType_CrcChild && crcHandler)
+ handler = crcHandler;
+ else if (cmi.CtxCommandType == CtxCommandType_OpenChild && openHandler)
+ handler = openHandler;
+ handler->SubCommands.AddNew() = shellExt;
+ }
+
+ shellExt->_commandMap_Cur.Add(cmi);
+
+ ODS_U(cmi.UserString)
+
+ if (cmi.CtxCommandType == CtxCommandType_CrcRoot && useCascadedCrc)
+ crcHandler = shellExt;
+ if (cmi.CtxCommandType == CtxCommandType_OpenRoot && useCascadedOpen)
+ {
+ // ODS("cmi.CtxCommandType == CtxCommandType_OpenRoot");
+ openHandler = shellExt;
+ }
+ }
+}
+
+
+Z7_COMWF_B CZipExplorerCommand::GetTitle(IShellItemArray *psiItemArray, LPWSTR *ppszName)
+{
+ ODS("- GetTitle()")
+ // COM_TRY_BEGIN
+ if (IsSeparator)
+ {
+ *ppszName = NULL;
+ return S_FALSE;
+ }
+
+ UString name;
+ if (IsRoot)
+ {
+ LoadItems(psiItemArray);
+ name = "7-Zip"; // "New"
+ }
+ else
+ name = "7-Zip item";
+
+ if (!_commandMap_Cur.IsEmpty())
+ {
+ const CCommandMapItem &mi = _commandMap_Cur[0];
+ // s += mi.Verb;
+ // s += " : ";
+ name = mi.UserString;
+ }
+
+ return My_SHStrDupW(name, ppszName);
+ // return S_OK;
+ // COM_TRY_END
+}
+
+
+Z7_COMWF_B CZipExplorerCommand::GetIcon(IShellItemArray * /* psiItemArray */, LPWSTR *ppszIcon)
+{
+ ODS("- GetIcon()")
+ // COM_TRY_BEGIN
+ *ppszIcon = NULL;
+ // return E_NOTIMPL;
+ UString imageName = fs2us(NWindows::NDLL::GetModuleDirPrefix());
+ // imageName += "7zG.exe";
+ imageName += "7-zip.dll";
+ // imageName += ",190";
+ return My_SHStrDupW(imageName, ppszIcon);
+ // COM_TRY_END
+}
+
+
+Z7_COMWF_B CZipExplorerCommand::GetToolTip (IShellItemArray * /* psiItemArray */, LPWSTR *ppszInfotip)
+{
+ // COM_TRY_BEGIN
+ ODS("- GetToolTip()")
+ *ppszInfotip = NULL;
+ return E_NOTIMPL;
+ // COM_TRY_END
+}
+
+
+Z7_COMWF_B CZipExplorerCommand::GetCanonicalName(GUID *pguidCommandName)
+{
+ // COM_TRY_BEGIN
+ ODS("- GetCanonicalName()")
+ *pguidCommandName = GUID_NULL;
+ return E_NOTIMPL;
+ // COM_TRY_END
+}
+
+
+Z7_COMWF_B CZipExplorerCommand::GetState(IShellItemArray * /* psiItemArray */, BOOL /* fOkToBeSlow */, EXPCMDSTATE *pCmdState)
+{
+ // COM_TRY_BEGIN
+ ODS("- GetState()")
+ *pCmdState = ECS_ENABLED;
+ return S_OK;
+ // COM_TRY_END
+}
+
+
+
+
+Z7_COMWF_B CZipExplorerCommand::Invoke(IShellItemArray *psiItemArray, IBindCtx * /* pbc */)
+{
+ COM_TRY_BEGIN
+
+ if (_commandMap_Cur.IsEmpty())
+ return E_INVALIDARG;
+
+ ODS("- Invoke()")
+ _fileNames.Clear();
+ UStringVector paths;
+ RINOK(LoadPaths(psiItemArray, paths))
+ _fileNames = paths;
+ return InvokeCommandCommon(_commandMap_Cur[0]);
+
+ COM_TRY_END
+}
+
+
+Z7_COMWF_B CZipExplorerCommand::GetFlags(EXPCMDFLAGS *pFlags)
+{
+ ODS("- GetFlags()")
+ // COM_TRY_BEGIN
+ EXPCMDFLAGS f = ECF_DEFAULT;
+ if (IsSeparator)
+ f = ECF_ISSEPARATOR;
+ else if (IsRoot)
+ f = ECF_HASSUBCOMMANDS;
+ else
+ {
+ if (!_commandMap_Cur.IsEmpty())
+ {
+ // const CCommandMapItem &cmi = ;
+ if (_commandMap_Cur[0].IsSubMenu())
+ {
+ // ODS("ECF_HASSUBCOMMANDS")
+ f = ECF_HASSUBCOMMANDS;
+ }
+ }
+ }
+ *pFlags = f;
+ return S_OK;
+ // COM_TRY_END
+}
+
+
+Z7_COMWF_B CZipExplorerCommand::EnumSubCommands(IEnumExplorerCommand **ppEnum)
+{
+ ODS("- EnumSubCommands()")
+ // COM_TRY_BEGIN
+ *ppEnum = NULL;
+
+ if (!_commandMap_Cur.IsEmpty() && _commandMap_Cur[0].IsSubMenu())
+ {
+ }
+ else
+ {
+ if (!IsRoot)
+ return E_NOTIMPL;
+ if (SubCommands.IsEmpty())
+ {
+ return E_NOTIMPL;
+ }
+ }
+
+ // shellExt->
+ return QueryInterface(IID_IEnumExplorerCommand, (void **)ppEnum);
+
+ // return S_OK;
+ // COM_TRY_END
+}
+
+
+Z7_COMWF_B CZipContextMenu::Next(ULONG celt, IExplorerCommand **pUICommand, ULONG *pceltFetched)
+{
+ ODS("CZipContextMenu::Next()")
+ ODS_(Print_Number(celt, "celt"))
+ ODS_(Print_Number(CurrentSubCommand, "CurrentSubCommand"))
+ ODS_(Print_Number(SubCommands.Size(), "SubCommands.Size()"))
+
+ COM_TRY_BEGIN
+ ULONG fetched = 0;
+
+ ULONG i;
+ for (i = 0; i < celt; i++)
+ {
+ pUICommand[i] = NULL;
+ }
+
+ for (i = 0; i < celt && CurrentSubCommand < SubCommands.Size(); i++)
+ {
+ pUICommand[i] = SubCommands[CurrentSubCommand++];
+ pUICommand[i]->AddRef();
+ fetched++;
+ }
+
+ if (pceltFetched)
+ *pceltFetched = fetched;
+
+ ODS(fetched == celt ? " === OK === " : "=== ERROR ===")
+
+ // we return S_FALSE for (fetched == 0)
+ return (fetched == celt) ? S_OK : S_FALSE;
+ COM_TRY_END
+}
+
+
+Z7_COMWF_B CZipContextMenu::Skip(ULONG /* celt */)
+{
+ ODS("CZipContextMenu::Skip()")
+ return E_NOTIMPL;
+}
+
+
+Z7_COMWF_B CZipContextMenu::Reset(void)
+{
+ ODS("CZipContextMenu::Reset()")
+ CurrentSubCommand = 0;
+ return S_OK;
+}
+
+
+Z7_COMWF_B CZipContextMenu::Clone(IEnumExplorerCommand **ppenum)
+{
+ ODS("CZipContextMenu::Clone()")
+ *ppenum = NULL;
+ return E_NOTIMPL;
+}
diff --git a/CPP/7zip/UI/Explorer/ContextMenu.h b/CPP/7zip/UI/Explorer/ContextMenu.h
new file mode 100644
index 0000000..3f25f6a
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/ContextMenu.h
@@ -0,0 +1,167 @@
+// ContextMenu.h
+
+#ifndef ZIP7_INC_CONTEXT_MENU_H
+#define ZIP7_INC_CONTEXT_MENU_H
+
+#include "../../../Windows/Shell.h"
+
+#include "MyExplorerCommand.h"
+
+#include "../FileManager/MyCom2.h"
+
+#ifdef CMF_EXTENDEDVERBS
+#define Z7_WIN_CMF_EXTENDEDVERBS CMF_EXTENDEDVERBS
+#else
+#define Z7_WIN_CMF_EXTENDEDVERBS 0x00000100
+#endif
+
+enum enum_CtxCommandType
+{
+ CtxCommandType_Normal,
+ CtxCommandType_OpenRoot,
+ CtxCommandType_OpenChild,
+ CtxCommandType_CrcRoot,
+ CtxCommandType_CrcChild
+};
+
+
+class CZipContextMenu Z7_final:
+ public IContextMenu,
+ public IShellExtInit,
+ public IExplorerCommand,
+ public IEnumExplorerCommand,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_4_MT(
+ IContextMenu,
+ IShellExtInit,
+ IExplorerCommand,
+ IEnumExplorerCommand
+ )
+
+ // IShellExtInit
+ STDMETHOD(Initialize)(LPCITEMIDLIST pidlFolder, LPDATAOBJECT dataObject, HKEY hkeyProgID) Z7_override;
+
+ // IContextMenu
+ STDMETHOD(QueryContextMenu)(HMENU hmenu, UINT indexMenu, UINT idCmdFirst, UINT idCmdLast, UINT uFlags) Z7_override;
+ STDMETHOD(InvokeCommand)(LPCMINVOKECOMMANDINFO lpici) Z7_override;
+ STDMETHOD(GetCommandString)(
+ #ifdef Z7_OLD_WIN_SDK
+ UINT
+ #else
+ UINT_PTR
+ #endif
+ idCmd, UINT uType, UINT *pwReserved, LPSTR pszName, UINT cchMax) Z7_override;
+
+ // IExplorerCommand
+ STDMETHOD (GetTitle) (IShellItemArray *psiItemArray, LPWSTR *ppszName) Z7_override;
+ STDMETHOD (GetIcon) (IShellItemArray *psiItemArray, LPWSTR *ppszIcon) Z7_override;
+ STDMETHOD (GetToolTip) (IShellItemArray *psiItemArray, LPWSTR *ppszInfotip) Z7_override;
+ STDMETHOD (GetCanonicalName) (GUID *pguidCommandName) Z7_override;
+ STDMETHOD (GetState) (IShellItemArray *psiItemArray, BOOL fOkToBeSlow, EXPCMDSTATE *pCmdState) Z7_override;
+ STDMETHOD (Invoke) (IShellItemArray *psiItemArray, IBindCtx *pbc) Z7_override;
+ STDMETHOD (GetFlags) (EXPCMDFLAGS *pFlags) Z7_override;
+ STDMETHOD (EnumSubCommands) (IEnumExplorerCommand **ppEnum) Z7_override;
+
+ // IEnumExplorerCommand
+ STDMETHOD (Next) (ULONG celt, IExplorerCommand **pUICommand, ULONG *pceltFetched) Z7_override;
+ STDMETHOD (Skip) (ULONG celt) Z7_override;
+ STDMETHOD (Reset) (void) Z7_override;
+ STDMETHOD (Clone) (IEnumExplorerCommand **ppenum) Z7_override;
+
+public:
+
+ enum enum_CommandInternalID
+ {
+ kCommandNULL,
+ kOpen,
+ kExtract,
+ kExtractHere,
+ kExtractTo,
+ kTest,
+ kCompress,
+ kCompressEmail,
+ kCompressTo7z,
+ kCompressTo7zEmail,
+ kCompressToZip,
+ kCompressToZipEmail,
+ kHash_CRC32,
+ kHash_CRC64,
+ kHash_SHA1,
+ kHash_SHA256,
+ kHash_All,
+ kHash_Generate_SHA256,
+ kHash_TestArc
+ };
+
+public:
+ void Init_For_7zFM()
+ {
+ // _isMenuForFM = true;
+ // _fileNames_WereReduced = false;
+ }
+
+ void LoadItems(IShellItemArray *psiItemArray);
+
+ CZipContextMenu();
+ ~CZipContextMenu();
+
+ struct CCommandMapItem
+ {
+ enum_CommandInternalID CommandInternalID;
+ UString Verb;
+ UString UserString;
+ // UString HelpString;
+ UString Folder;
+ UString ArcName;
+ UString ArcType;
+ bool IsPopup;
+ enum_CtxCommandType CtxCommandType;
+
+ CCommandMapItem():
+ IsPopup(false),
+ CtxCommandType(CtxCommandType_Normal)
+ {}
+
+ bool IsSubMenu() const
+ {
+ return
+ CtxCommandType == CtxCommandType_CrcRoot ||
+ CtxCommandType == CtxCommandType_OpenRoot;
+ }
+ };
+
+ UStringVector _fileNames;
+ NWindows::NShell::CFileAttribs _attribs;
+
+private:
+ bool _isMenuForFM;
+ bool _fileNames_WereReduced; // = true, if only first 16 items were used in QueryContextMenu()
+ bool _dropMode;
+ UString _dropPath;
+ CObjectVector<CCommandMapItem> _commandMap;
+ CObjectVector<CCommandMapItem> _commandMap_Cur;
+
+ HBITMAP _bitmap;
+ UInt32 _writeZone;
+ CBoolPair _elimDup;
+
+ bool IsSeparator;
+ bool IsRoot;
+ CObjectVector< CMyComPtr<IExplorerCommand> > SubCommands;
+ unsigned CurrentSubCommand;
+
+ void Set_UserString_in_LastCommand(const UString &s)
+ {
+ _commandMap.Back().UserString = s;
+ }
+
+ int FindVerb(const UString &verb) const;
+ void FillCommand(enum_CommandInternalID id, UString &mainString, CCommandMapItem &cmi) const;
+ void AddCommand(enum_CommandInternalID id, UString &mainString, CCommandMapItem &cmi);
+ void AddMapItem_ForSubMenu(const char *ver);
+
+ HRESULT InvokeCommandCommon(const CCommandMapItem &cmi);
+};
+
+#endif
diff --git a/CPP/7zip/UI/Explorer/ContextMenuFlags.h b/CPP/7zip/UI/Explorer/ContextMenuFlags.h
new file mode 100644
index 0000000..50c177e
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/ContextMenuFlags.h
@@ -0,0 +1,27 @@
+// ContextMenuFlags.h
+
+#ifndef ZIP7_INC_CONTEXT_MENU_FLAGS_H
+#define ZIP7_INC_CONTEXT_MENU_FLAGS_H
+
+namespace NContextMenuFlags
+{
+ const UInt32 kExtract = 1 << 0;
+ const UInt32 kExtractHere = 1 << 1;
+ const UInt32 kExtractTo = 1 << 2;
+
+ const UInt32 kTest = 1 << 4;
+ const UInt32 kOpen = 1 << 5;
+ const UInt32 kOpenAs = 1 << 6;
+
+ const UInt32 kCompress = 1 << 8;
+ const UInt32 kCompressTo7z = 1 << 9;
+ const UInt32 kCompressEmail = 1 << 10;
+ const UInt32 kCompressTo7zEmail = 1 << 11;
+ const UInt32 kCompressToZip = 1 << 12;
+ const UInt32 kCompressToZipEmail = 1 << 13;
+
+ const UInt32 kCRC_Cascaded = (UInt32)1 << 30;
+ const UInt32 kCRC = (UInt32)1 << 31;
+}
+
+#endif
diff --git a/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp b/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp
new file mode 100644
index 0000000..7307b07
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/DllExportsExplorer.cpp
@@ -0,0 +1,264 @@
+// DLLExportsExplorer.cpp
+//
+// Notes:
+// Win2000:
+// If I register at HKCR\Folder\ShellEx then DLL is locked.
+// otherwise it unloads after explorer closing.
+// but if I call menu for desktop items it's locked all the time
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+
+#if defined(__clang__) && __clang_major__ >= 4
+#pragma GCC diagnostic ignored "-Wnonportable-system-include-path"
+#endif
+// <olectl.h> : in new Windows Kit 10.0.2**** (NTDDI_WIN10_MN is defined)
+// <OleCtl.h> : in another Windows Kit versions
+#if defined(NTDDI_WIN10_MN) || defined(__MINGW32__) || defined(__MINGW64__)
+#include <olectl.h>
+#else
+#include <OleCtl.h>
+#endif
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <shlguid.h>
+#else
+#include <ShlGuid.h>
+#endif
+
+#include "../../../Common/MyInitGuid.h"
+
+#include "../../../Common/ComTry.h"
+
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/NtCheck.h"
+#include "../../../Windows/Registry.h"
+
+#include "../FileManager/IFolder.h"
+
+#include "ContextMenu.h"
+
+static LPCTSTR const k_ShellExtName = TEXT("7-Zip Shell Extension");
+static LPCTSTR const k_Approved = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved");
+
+// {23170F69-40C1-278A-1000-000100020000}
+static LPCTSTR const k_Clsid = TEXT("{23170F69-40C1-278A-1000-000100020000}");
+
+Z7_DEFINE_GUID(CLSID_CZipContextMenu,
+ k_7zip_GUID_Data1,
+ k_7zip_GUID_Data2,
+ k_7zip_GUID_Data3_Common,
+ 0x10, 0x00, 0x00, 0x01, 0x00, 0x02, 0x00, 0x00);
+
+using namespace NWindows;
+
+extern
+HINSTANCE g_hInstance;
+HINSTANCE g_hInstance = NULL;
+
+extern
+HWND g_HWND;
+HWND g_HWND = NULL;
+
+extern
+LONG g_DllRefCount;
+LONG g_DllRefCount = 0; // Reference count of this DLL.
+
+
+// #define ODS(sz) OutputDebugStringW(L#sz)
+#define ODS(sz)
+
+class CShellExtClassFactory Z7_final:
+ public IClassFactory,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_1_MT(IClassFactory)
+
+ STDMETHOD(CreateInstance)(LPUNKNOWN, REFIID, void**) Z7_override Z7_final;
+ STDMETHOD(LockServer)(BOOL) Z7_override Z7_final;
+public:
+ CShellExtClassFactory() { InterlockedIncrement(&g_DllRefCount); }
+ ~CShellExtClassFactory() { InterlockedDecrement(&g_DllRefCount); }
+};
+
+Z7_COMWF_B CShellExtClassFactory::CreateInstance(LPUNKNOWN pUnkOuter,
+ REFIID riid, void **ppvObj)
+{
+ ODS("CShellExtClassFactory::CreateInstance()\r\n");
+ /*
+ char s[64];
+ ConvertUInt32ToHex(riid.Data1, s);
+ OutputDebugStringA(s);
+ */
+ *ppvObj = NULL;
+ if (pUnkOuter)
+ return CLASS_E_NOAGGREGATION;
+
+ CZipContextMenu *shellExt;
+ try
+ {
+ shellExt = new CZipContextMenu();
+ }
+ catch(...) { return E_OUTOFMEMORY; }
+ if (!shellExt)
+ return E_OUTOFMEMORY;
+
+ IContextMenu *ctxm = shellExt;
+ const HRESULT res = ctxm->QueryInterface(riid, ppvObj);
+ if (res != S_OK)
+ delete shellExt;
+ return res;
+}
+
+
+Z7_COMWF_B CShellExtClassFactory::LockServer(BOOL /* fLock */)
+{
+ return S_OK; // Check it
+}
+
+
+#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE)
+#define NT_CHECK_FAIL_ACTION return FALSE;
+#endif
+
+extern "C"
+BOOL WINAPI DllMain(
+ #ifdef UNDER_CE
+ HANDLE hInstance
+ #else
+ HINSTANCE hInstance
+ #endif
+ , DWORD dwReason, LPVOID);
+
+extern "C"
+BOOL WINAPI DllMain(
+ #ifdef UNDER_CE
+ HANDLE hInstance
+ #else
+ HINSTANCE hInstance
+ #endif
+ , DWORD dwReason, LPVOID)
+{
+ if (dwReason == DLL_PROCESS_ATTACH)
+ {
+ g_hInstance = (HINSTANCE)hInstance;
+ ODS("In DLLMain, DLL_PROCESS_ATTACH\r\n");
+ NT_CHECK
+ }
+ else if (dwReason == DLL_PROCESS_DETACH)
+ {
+ ODS("In DLLMain, DLL_PROCESS_DETACH\r\n");
+ }
+ return TRUE;
+}
+
+
+// Used to determine whether the DLL can be unloaded by OLE
+
+STDAPI DllCanUnloadNow(void)
+{
+ ODS("In DLLCanUnloadNow\r\n");
+ /*
+ if (g_DllRefCount == 0)
+ ODS( "g_DllRefCount == 0");
+ else
+ ODS( "g_DllRefCount != 0");
+ */
+ return (g_DllRefCount == 0 ? S_OK : S_FALSE);
+}
+
+STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv)
+{
+ ODS("In DllGetClassObject\r\n");
+ *ppv = NULL;
+ if (IsEqualIID(rclsid, CLSID_CZipContextMenu))
+ {
+ CShellExtClassFactory *cf;
+ try
+ {
+ cf = new CShellExtClassFactory;
+ }
+ catch(...) { return E_OUTOFMEMORY; }
+ if (!cf)
+ return E_OUTOFMEMORY;
+ IClassFactory *cf2 = cf;
+ const HRESULT res = cf2->QueryInterface(riid, ppv);
+ if (res != S_OK)
+ delete cf;
+ return res;
+ }
+ return CLASS_E_CLASSNOTAVAILABLE;
+ // return _Module.GetClassObject(rclsid, riid, ppv);
+}
+
+
+static BOOL RegisterServer()
+{
+ ODS("RegisterServer\r\n");
+ FString modulePath;
+ if (!NDLL::MyGetModuleFileName(modulePath))
+ return FALSE;
+ const UString modulePathU = fs2us(modulePath);
+
+ CSysString s ("CLSID\\");
+ s += k_Clsid;
+
+ {
+ NRegistry::CKey key;
+ if (key.Create(HKEY_CLASSES_ROOT, s, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE) != NOERROR)
+ return FALSE;
+ key.SetValue(NULL, k_ShellExtName);
+ NRegistry::CKey keyInproc;
+ if (keyInproc.Create(key, TEXT("InprocServer32"), NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE) != NOERROR)
+ return FALSE;
+ keyInproc.SetValue(NULL, modulePathU);
+ keyInproc.SetValue(TEXT("ThreadingModel"), TEXT("Apartment"));
+ }
+
+ #if !defined(_WIN64) && !defined(UNDER_CE)
+ if (IsItWindowsNT())
+ #endif
+ {
+ NRegistry::CKey key;
+ if (key.Create(HKEY_LOCAL_MACHINE, k_Approved, NULL, REG_OPTION_NON_VOLATILE, KEY_WRITE) == NOERROR)
+ key.SetValue(k_Clsid, k_ShellExtName);
+ }
+
+ ODS("RegisterServer :: return TRUE");
+ return TRUE;
+}
+
+STDAPI DllRegisterServer(void)
+{
+ return RegisterServer() ? S_OK: SELFREG_E_CLASS;
+}
+
+static BOOL UnregisterServer()
+{
+ CSysString s ("CLSID\\");
+ s += k_Clsid;
+
+ RegDeleteKey(HKEY_CLASSES_ROOT, s + TEXT("\\InprocServer32"));
+ RegDeleteKey(HKEY_CLASSES_ROOT, s);
+
+ #if !defined(_WIN64) && !defined(UNDER_CE)
+ if (IsItWindowsNT())
+ #endif
+ {
+ HKEY hKey;
+ if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, k_Approved, 0, KEY_SET_VALUE, &hKey) == NOERROR)
+ {
+ RegDeleteValue(hKey, k_Clsid);
+ RegCloseKey(hKey);
+ }
+ }
+
+ return TRUE;
+}
+
+STDAPI DllUnregisterServer(void)
+{
+ return UnregisterServer() ? S_OK: SELFREG_E_CLASS;
+}
diff --git a/CPP/7zip/UI/Explorer/Explorer.def b/CPP/7zip/UI/Explorer/Explorer.def
new file mode 100644
index 0000000..034a269
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/Explorer.def
@@ -0,0 +1,9 @@
+; 7-zip.def
+
+LIBRARY "7-zip"
+
+EXPORTS
+ DllCanUnloadNow PRIVATE
+ DllGetClassObject PRIVATE
+ DllRegisterServer PRIVATE
+ DllUnregisterServer PRIVATE
diff --git a/CPP/7zip/UI/Explorer/Explorer.dsp b/CPP/7zip/UI/Explorer/Explorer.dsp
new file mode 100644
index 0000000..ff8503b
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/Explorer.dsp
@@ -0,0 +1,612 @@
+# Microsoft Developer Studio Project File - Name="Explorer" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=Explorer - Win32 DebugU
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "Explorer.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "Explorer.mak" CFG="Explorer - Win32 DebugU"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Explorer - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "Explorer - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "Explorer - Win32 ReleaseU" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "Explorer - Win32 DebugU" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "Explorer - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /D "Z7_LANG" /D "Z7_LONG_PATH" /FAcs /Yu"StdAfx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /machine:I386 /out:"C:\Util\7-Zip.dll" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "Explorer - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /D "Z7_LANG" /D "Z7_LONG_PATH" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\7-Zip.dll" /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "Explorer - Win32 ReleaseU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ReleaseU"
+# PROP BASE Intermediate_Dir "ReleaseU"
+# PROP BASE Ignore_Export_Lib 1
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "ReleaseU"
+# PROP Intermediate_Dir "ReleaseU"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /D "Z7_LANG" /D "_MBCS" /Yu"StdAfx.h" /FD /c
+# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /D "Z7_LANG" /D "Z7_LONG_PATH" /Yu"StdAfx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /machine:I386 /out:"C:\Program Files\7-ZIP\7-Zip.dll" /opt:NOWIN98
+# SUBTRACT BASE LINK32 /pdb:none
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /machine:I386 /out:"C:\Util\7-Zip.dll" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "Explorer - Win32 DebugU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "DebugU"
+# PROP BASE Intermediate_Dir "DebugU"
+# PROP BASE Ignore_Export_Lib 1
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "DebugU"
+# PROP Intermediate_Dir "DebugU"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /D "Z7_LANG" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c
+# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_WINDOWS" /D "_USRDLL" /D "EXPLORER_EXPORTS" /D "Z7_LANG" /D "Z7_LONG_PATH" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /debug /machine:I386 /out:"C:\Program Files\7-ZIP\7-Zip.dll" /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /dll /debug /machine:I386 /out:"C:\Util\7-Zip.dll" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "Explorer - Win32 Release"
+# Name "Explorer - Win32 Debug"
+# Name "Explorer - Win32 ReleaseU"
+# Name "Explorer - Win32 DebugU"
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\DllExportsExplorer.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Explorer.def
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"StdAfx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "UI Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\Common\ArchiveName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\CompressCall.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\CompressCall.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ExtractingFilePath.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ExtractingFilePath.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ZipRegistry.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ZipRegistry.h
+# End Source File
+# End Group
+# Begin Group "Engine"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\ContextMenu.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ContextMenu.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\MyExplorerCommand.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\MyMessages.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\MyMessages.h
+# End Source File
+# End Group
+# Begin Group "FileManager"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\FileManager\FormatUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\FormatUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\HelpUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\HelpUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\IFolder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\LangUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\LangUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\MyCom2.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\ProgramLocation.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\ProgramLocation.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\PropertyName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\PropertyName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\RegistryUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\RegistryUtils.h
+# End Source File
+# End Group
+# Begin Group "C"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sort.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sort.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\Common.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Lang.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Lang.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyCom.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Random.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Random.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Types.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.h
+# End Source File
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Group "Control"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Dialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Dialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ListView.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ListView.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\PropertyPage.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\PropertyPage.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\..\Windows\COM.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileMapping.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryGlobal.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryGlobal.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryLock.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryLock.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Menu.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Menu.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ProcessUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ProcessUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Registry.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Registry.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ResourceString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ResourceString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Shell.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Shell.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Window.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Window.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=".\7-zip.dll.manifest"
+# End Source File
+# Begin Source File
+
+SOURCE=.\ContextMenuFlags.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\FM.ico
+# End Source File
+# End Target
+# End Project
diff --git a/CPP/7zip/UI/Explorer/Explorer.dsw b/CPP/7zip/UI/Explorer/Explorer.dsw
new file mode 100644
index 0000000..beb8df7
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/Explorer.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "Explorer"=".\Explorer.dsp" - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/UI/Explorer/MenuLogo.bmp b/CPP/7zip/UI/Explorer/MenuLogo.bmp
new file mode 100644
index 0000000..906a6c5
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/MenuLogo.bmp
Binary files differ
diff --git a/CPP/7zip/UI/Explorer/MyExplorerCommand.h b/CPP/7zip/UI/Explorer/MyExplorerCommand.h
new file mode 100644
index 0000000..11ac247
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/MyExplorerCommand.h
@@ -0,0 +1,217 @@
+// MyExplorerCommand.h
+
+#ifndef ZIP7_INC_MY_EXPLORER_COMMAND_H
+#define ZIP7_INC_MY_EXPLORER_COMMAND_H
+
+#if _MSC_VER >= 1910
+#define USE_SYS_shobjidl_core
+#endif
+
+#ifdef USE_SYS_shobjidl_core
+
+// #include <shobjidl_core.h>
+
+#else
+
+/* IShellItem is defined:
+ ShObjIdl.h : old Windows SDK
+ ShObjIdl_core.h : new Windows 10 SDK */
+
+#ifndef Z7_OLD_WIN_SDK
+#include <ShObjIdl.h>
+#endif
+
+#ifndef __IShellItem_INTERFACE_DEFINED__
+#define __IShellItem_INTERFACE_DEFINED__
+
+// For MINGW we define IShellItem
+
+// #error Stop_Compiling__NOT_DEFINED__IShellItem_INTERFACE_DEFINED__
+
+typedef
+enum
+{ SIGDN_NORMALDISPLAY = 0,
+ SIGDN_PARENTRELATIVEPARSING = 0x80018001,
+ SIGDN_PARENTRELATIVEFORADDRESSBAR = 0x8001c001,
+ SIGDN_DESKTOPABSOLUTEPARSING = 0x80028000,
+ SIGDN_PARENTRELATIVEEDITING = 0x80031001,
+ SIGDN_DESKTOPABSOLUTEEDITING = 0x8004c000,
+ SIGDN_FILESYSPATH = 0x80058000,
+ SIGDN_URL = 0x80068000
+} SIGDN;
+
+
+typedef DWORD SICHINTF;
+typedef ULONG SFGAOF;
+
+struct IShellItem : public IUnknown
+{
+ virtual HRESULT STDMETHODCALLTYPE BindToHandler(IBindCtx *pbc, REFGUID rbhid, REFIID riid, void **ppvOut) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetParent(IShellItem **ppsi) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetDisplayName(SIGDN sigdnName, LPOLESTR *ppszName) = 0;
+ virtual HRESULT STDMETHODCALLTYPE GetAttributes(SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs) = 0;
+ virtual HRESULT STDMETHODCALLTYPE Compare(IShellItem *psi, SICHINTF hint, int *piOrder) = 0;
+};
+
+#endif // __IShellItem_INTERFACE_DEFINED__
+
+
+
+#ifndef __IShellItemArray_INTERFACE_DEFINED__
+#define __IShellItemArray_INTERFACE_DEFINED__
+
+// propsys.h
+
+typedef /* [v1_enum] */
+enum GETPROPERTYSTOREFLAGS
+{
+ GPS_DEFAULT = 0,
+ GPS_HANDLERPROPERTIESONLY = 0x1,
+ GPS_READWRITE = 0x2,
+ GPS_TEMPORARY = 0x4,
+ GPS_FASTPROPERTIESONLY = 0x8,
+ GPS_OPENSLOWITEM = 0x10,
+ GPS_DELAYCREATION = 0x20,
+ GPS_BESTEFFORT = 0x40,
+ GPS_NO_OPLOCK = 0x80,
+ GPS_PREFERQUERYPROPERTIES = 0x100,
+ GPS_EXTRINSICPROPERTIES = 0x200,
+ GPS_EXTRINSICPROPERTIESONLY = 0x400,
+ GPS_VOLATILEPROPERTIES = 0x800,
+ GPS_VOLATILEPROPERTIESONLY = 0x1000,
+ GPS_MASK_VALID = 0x1fff
+} GETPROPERTYSTOREFLAGS;
+
+// DEFINE_ENUM_FLAG_OPERATORS(GETPROPERTYSTOREFLAGS)
+
+
+#ifndef PROPERTYKEY_DEFINED
+#define PROPERTYKEY_DEFINED
+
+typedef
+struct _tagpropertykey
+{
+ GUID fmtid;
+ DWORD pid;
+} PROPERTYKEY;
+
+#endif // PROPERTYKEY_DEFINED
+
+// propkeydef.h
+#define REFPROPERTYKEY const PROPERTYKEY &
+
+#ifdef INITGUID
+#define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) EXTERN_C const PROPERTYKEY DECLSPEC_SELECTANY name = { { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }, pid }
+#else
+#define DEFINE_PROPERTYKEY(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8, pid) EXTERN_C const PROPERTYKEY name
+#endif // INITGUID
+
+
+// <shobjidl_core.h>
+typedef /* [v1_enum] */
+enum SIATTRIBFLAGS
+{
+ SIATTRIBFLAGS_AND = 0x1,
+ SIATTRIBFLAGS_OR = 0x2,
+ SIATTRIBFLAGS_APPCOMPAT = 0x3,
+ SIATTRIBFLAGS_MASK = 0x3,
+ SIATTRIBFLAGS_ALLITEMS = 0x4000
+} SIATTRIBFLAGS;
+
+// DEFINE_ENUM_FLAG_OPERATORS(SIATTRIBFLAGS)
+
+
+// MIDL_INTERFACE("70629033-e363-4a28-a567-0db78006e6d7")
+DEFINE_GUID(IID_IEnumShellItems, 0x70629033, 0xe363, 0xe363, 0xa5, 0x67, 0x0d, 0xb7, 0x80, 0x06, 0xe6, 0xd7);
+
+struct IEnumShellItems : public IUnknown
+{
+ STDMETHOD (Next) (ULONG celt, IShellItem **rgelt, ULONG *pceltFetched) = 0;
+ STDMETHOD (Skip) (ULONG celt) = 0;
+ STDMETHOD (Reset) (void) = 0;
+ STDMETHOD (Clone) (IEnumShellItems **ppenum) = 0;
+};
+
+
+// MIDL_INTERFACE("b63ea76d-1f85-456f-a19c-48159efa858b")
+DEFINE_GUID(IID_IShellItemArray, 0xb63ea76d, 0x1f85, 0x456f, 0xa1, 0x9c, 0x48, 0x15, 0x9e, 0xfa, 0x85, 0x8b);
+
+struct IShellItemArray : public IUnknown
+{
+ STDMETHOD (BindToHandler) (IBindCtx *pbc, REFGUID bhid, REFIID riid, void **ppvOut) = 0;
+ STDMETHOD (GetPropertyStore) (GETPROPERTYSTOREFLAGS flags, REFIID riid, void **ppv) = 0;
+ STDMETHOD (GetPropertyDescriptionList) (REFPROPERTYKEY keyType, REFIID riid, void **ppv) = 0;
+ STDMETHOD (GetAttributes) ( SIATTRIBFLAGS AttribFlags, SFGAOF sfgaoMask, SFGAOF *psfgaoAttribs) = 0;
+ STDMETHOD (GetCount) (DWORD *pdwNumItems) = 0;
+ STDMETHOD (GetItemAt) (DWORD dwIndex, IShellItem **ppsi) = 0;
+ STDMETHOD (EnumItems) (IEnumShellItems **ppenumShellItems) = 0;
+};
+
+
+#ifndef __IEnumExplorerCommand_INTERFACE_DEFINED__
+#define __IEnumExplorerCommand_INTERFACE_DEFINED__
+
+struct IExplorerCommand;
+
+// MIDL_INTERFACE("a88826f8-186f-4987-aade-ea0cef8fbfe8")
+DEFINE_GUID(IID_IEnumExplorerCommand , 0xa88826f8, 0x186f, 0x4987, 0xaa, 0xde, 0xea, 0x0c, 0xef, 0x8f, 0xbf, 0xe8);
+
+struct IEnumExplorerCommand : public IUnknown
+{
+ STDMETHOD (Next) (ULONG celt, IExplorerCommand **pUICommand, ULONG *pceltFetched) = 0;
+ STDMETHOD (Skip) (ULONG celt) = 0;
+ STDMETHOD (Reset) (void) = 0;
+ STDMETHOD (Clone) (IEnumExplorerCommand **ppenum) = 0;
+};
+
+
+enum _EXPCMDSTATE
+{
+ ECS_ENABLED = 0,
+ ECS_DISABLED = 0x1,
+ ECS_HIDDEN = 0x2,
+ ECS_CHECKBOX = 0x4,
+ ECS_CHECKED = 0x8,
+ ECS_RADIOCHECK = 0x10
+};
+
+typedef DWORD EXPCMDSTATE;
+
+/* [v1_enum] */
+enum _EXPCMDFLAGS
+{
+ ECF_DEFAULT = 0,
+ ECF_HASSUBCOMMANDS = 0x1,
+ ECF_HASSPLITBUTTON = 0x2,
+ ECF_HIDELABEL = 0x4,
+ ECF_ISSEPARATOR = 0x8,
+ ECF_HASLUASHIELD = 0x10,
+ ECF_SEPARATORBEFORE = 0x20,
+ ECF_SEPARATORAFTER = 0x40,
+ ECF_ISDROPDOWN = 0x80,
+ ECF_TOGGLEABLE = 0x100,
+ ECF_AUTOMENUICONS = 0x200
+};
+typedef DWORD EXPCMDFLAGS;
+
+
+// MIDL_INTERFACE("a08ce4d0-fa25-44ab-b57c-c7b1c323e0b9")
+DEFINE_GUID(IID_IExplorerCommand, 0xa08ce4d0, 0xfa25, 0x44ab, 0xb5, 0x7c, 0xc7, 0xb1, 0xc3, 0x23, 0xe0, 0xb9);
+
+struct IExplorerCommand : public IUnknown
+{
+ STDMETHOD (GetTitle) (IShellItemArray *psiItemArray, LPWSTR *ppszName) = 0;
+ STDMETHOD (GetIcon) (IShellItemArray *psiItemArray, LPWSTR *ppszIcon) = 0;
+ STDMETHOD (GetToolTip) (IShellItemArray *psiItemArray, LPWSTR *ppszInfotip) = 0;
+ STDMETHOD (GetCanonicalName) (GUID *pguidCommandName) = 0;
+ STDMETHOD (GetState) (IShellItemArray *psiItemArray, BOOL fOkToBeSlow, EXPCMDSTATE *pCmdState) = 0;
+ STDMETHOD (Invoke) (IShellItemArray *psiItemArray, IBindCtx *pbc) = 0;
+ STDMETHOD (GetFlags) (EXPCMDFLAGS *pFlags) = 0;
+ STDMETHOD (EnumSubCommands) (IEnumExplorerCommand **ppEnum) = 0;
+};
+
+#endif // IShellItemArray
+#endif // __IEnumExplorerCommand_INTERFACE_DEFINED__
+#endif // USE_SYS_shobjidl_core
+
+#endif // __MY_EXPLORER_COMMAND_H
diff --git a/CPP/7zip/UI/Explorer/MyMessages.cpp b/CPP/7zip/UI/Explorer/MyMessages.cpp
index 1ef0d9c..daff7de 100644
--- a/CPP/7zip/UI/Explorer/MyMessages.cpp
+++ b/CPP/7zip/UI/Explorer/MyMessages.cpp
@@ -1,37 +1,40 @@
-// MyMessages.cpp
-
-#include "StdAfx.h"
-
-#include "MyMessages.h"
-
-#include "../../../Windows/ErrorMsg.h"
-#include "../../../Windows/ResourceString.h"
-
-#include "../FileManager/LangUtils.h"
-
-using namespace NWindows;
-
-void ShowErrorMessage(HWND window, LPCWSTR message)
-{
- ::MessageBoxW(window, message, L"7-Zip", MB_OK | MB_ICONSTOP);
-}
-
-void ShowErrorMessageHwndRes(HWND window, UINT resID)
-{
- ShowErrorMessage(window, LangString(resID));
-}
-
-void ShowErrorMessageRes(UINT resID)
-{
- ShowErrorMessageHwndRes(0, resID);
-}
-
-void ShowErrorMessageDWORD(HWND window, DWORD errorCode)
-{
- ShowErrorMessage(window, NError::MyFormatMessage(errorCode));
-}
-
-void ShowLastErrorMessage(HWND window)
-{
- ShowErrorMessageDWORD(window, ::GetLastError());
-}
+// MyMessages.cpp
+
+#include "StdAfx.h"
+
+#include "MyMessages.h"
+
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/ResourceString.h"
+
+#include "../FileManager/LangUtils.h"
+
+using namespace NWindows;
+
+void ShowErrorMessage(HWND window, LPCWSTR message)
+{
+ ::MessageBoxW(window, message, L"7-Zip", MB_OK | MB_ICONSTOP);
+}
+
+void ShowErrorMessageHwndRes(HWND window, UINT resID)
+{
+ UString s = LangString(resID);
+ if (s.IsEmpty())
+ s.Add_UInt32(resID);
+ ShowErrorMessage(window, s);
+}
+
+void ShowErrorMessageRes(UINT resID)
+{
+ ShowErrorMessageHwndRes(NULL, resID);
+}
+
+static void ShowErrorMessageDWORD(HWND window, DWORD errorCode)
+{
+ ShowErrorMessage(window, NError::MyFormatMessage(errorCode));
+}
+
+void ShowLastErrorMessage(HWND window)
+{
+ ShowErrorMessageDWORD(window, ::GetLastError());
+}
diff --git a/CPP/7zip/UI/Explorer/MyMessages.h b/CPP/7zip/UI/Explorer/MyMessages.h
index c175e8a..47d10db 100644
--- a/CPP/7zip/UI/Explorer/MyMessages.h
+++ b/CPP/7zip/UI/Explorer/MyMessages.h
@@ -1,16 +1,16 @@
-// MyMessages.h
-
-#ifndef __MY_MESSAGES_H
-#define __MY_MESSAGES_H
-
-#include "../../../Common/MyString.h"
-
-void ShowErrorMessage(HWND window, LPCWSTR message);
-inline void ShowErrorMessage(LPCWSTR message) { ShowErrorMessage(0, message); }
-
-void ShowErrorMessageHwndRes(HWND window, UInt32 langID);
-void ShowErrorMessageRes(UInt32 langID);
-
-void ShowLastErrorMessage(HWND window = 0);
-
-#endif
+// MyMessages.h
+
+#ifndef ZIP7_INC_MY_MESSAGES_H
+#define ZIP7_INC_MY_MESSAGES_H
+
+#include "../../../Common/MyString.h"
+
+void ShowErrorMessage(HWND window, LPCWSTR message);
+inline void ShowErrorMessage(LPCWSTR message) { ShowErrorMessage(NULL, message); }
+
+void ShowErrorMessageHwndRes(HWND window, UInt32 langID);
+void ShowErrorMessageRes(UInt32 langID);
+
+void ShowLastErrorMessage(HWND window = NULL);
+
+#endif
diff --git a/CPP/7zip/UI/Explorer/RegistryContextMenu.cpp b/CPP/7zip/UI/Explorer/RegistryContextMenu.cpp
new file mode 100644
index 0000000..bc03d6a
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/RegistryContextMenu.cpp
@@ -0,0 +1,227 @@
+// RegistryContextMenu.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/Registry.h"
+
+#include "RegistryContextMenu.h"
+
+using namespace NWindows;
+using namespace NRegistry;
+
+#ifndef UNDER_CE
+
+// does extension can work, if Approved is removed ?
+// CLISID (and Approved ?) items are separated for 32-bit and 64-bit code.
+// shellex items shared by 32-bit and 64-bit code?
+
+#define k_Clsid_A "{23170F69-40C1-278A-1000-000100020000}"
+
+static LPCTSTR const k_Clsid = TEXT(k_Clsid_A);
+static LPCTSTR const k_ShellExtName = TEXT("7-Zip Shell Extension");
+
+static LPCTSTR const k_Approved = TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Shell Extensions\\Approved");
+static LPCTSTR const k_Inproc = TEXT("InprocServer32");
+
+static LPCSTR const k_KeyPostfix_ContextMenu = "\\shellex\\ContextMenuHandlers\\7-Zip";
+static LPCSTR const k_KeyPostfix_DragDrop = "\\shellex\\DragDropHandlers\\7-Zip";
+
+static LPCSTR const k_KeyName_File = "*";
+static LPCSTR const k_KeyName_Folder = "Folder";
+static LPCSTR const k_KeyName_Directory = "Directory";
+static LPCSTR const k_KeyName_Drive = "Drive";
+
+static LPCSTR const k_shellex_Prefixes[] =
+{
+ k_KeyName_File,
+ k_KeyName_Folder,
+ k_KeyName_Directory,
+ k_KeyName_Drive
+};
+
+static const bool k_shellex_Statuses[2][4] =
+{
+ { true, true, true, false },
+ { false, false, true, true }
+};
+
+
+// can we use static RegDeleteKeyExW in _WIN64 mode?
+// is it supported by Windows 2003 x64?
+
+/*
+#ifdef _WIN64
+
+#define INIT_REG_WOW
+
+#else
+*/
+
+typedef
+// WINADVAPI
+LONG (APIENTRY *Func_RegDeleteKeyExW)(HKEY hKey, LPCWSTR lpSubKey, REGSAM samDesired, DWORD Reserved);
+static Func_RegDeleteKeyExW func_RegDeleteKeyExW;
+
+static void Init_RegDeleteKeyExW()
+{
+ if (!func_RegDeleteKeyExW)
+ func_RegDeleteKeyExW = Z7_GET_PROC_ADDRESS(
+ Func_RegDeleteKeyExW, GetModuleHandleW(L"advapi32.dll"),
+ "RegDeleteKeyExW");
+}
+
+#define INIT_REG_WOW if (wow != 0) Init_RegDeleteKeyExW();
+
+// #endif
+
+static LONG MyRegistry_DeleteKey(HKEY parentKey, LPCTSTR name, UInt32 wow)
+{
+ if (wow == 0)
+ return RegDeleteKey(parentKey, name);
+
+ /*
+ #ifdef _WIN64
+ return RegDeleteKeyExW
+ #else
+ */
+ if (!func_RegDeleteKeyExW)
+ return E_NOTIMPL;
+ return func_RegDeleteKeyExW
+ // #endif
+ (parentKey, GetUnicodeString(name), wow, 0);
+}
+
+static LONG MyRegistry_DeleteKey_HKCR(LPCTSTR name, UInt32 wow)
+{
+ return MyRegistry_DeleteKey(HKEY_CLASSES_ROOT, name, wow);
+}
+
+// static NSynchronization::CCriticalSection g_CS;
+
+static AString Get_ContextMenuHandler_KeyName(LPCSTR keyName)
+ { return (AString)keyName + k_KeyPostfix_ContextMenu; }
+
+/*
+static CSysString Get_DragDropHandler_KeyName(LPCTSTR keyName)
+ { return (AString)keyName + k_KeyPostfix_DragDrop); }
+*/
+
+static bool CheckHandlerCommon(const AString &keyName, UInt32 wow)
+{
+ CKey key;
+ if (key.Open(HKEY_CLASSES_ROOT, (CSysString)keyName, KEY_READ | wow) != ERROR_SUCCESS)
+ return false;
+ CSysString value;
+ if (key.QueryValue(NULL, value) != ERROR_SUCCESS)
+ return false;
+ return StringsAreEqualNoCase_Ascii(value, k_Clsid_A);
+}
+
+bool CheckContextMenuHandler(const UString &path, UInt32 wow)
+{
+ // NSynchronization::CCriticalSectionLock lock(g_CS);
+
+ CSysString s ("CLSID\\");
+ s += k_Clsid_A;
+ s += "\\InprocServer32";
+
+ {
+ NRegistry::CKey key;
+ if (key.Open(HKEY_CLASSES_ROOT, s, KEY_READ | wow) != ERROR_SUCCESS)
+ return false;
+ UString regPath;
+ if (key.QueryValue(NULL, regPath) != ERROR_SUCCESS)
+ return false;
+ if (!path.IsEqualTo_NoCase(regPath))
+ return false;
+ }
+
+ return
+ CheckHandlerCommon(Get_ContextMenuHandler_KeyName(k_KeyName_File), wow);
+ /*
+ && CheckHandlerCommon(Get_ContextMenuHandler_KeyName(k_KeyName_Directory), wow)
+ // && CheckHandlerCommon(Get_ContextMenuHandler_KeyName(k_KeyName_Folder))
+
+ && CheckHandlerCommon(Get_DragDropHandler_KeyName(k_KeyName_Directory), wow)
+ && CheckHandlerCommon(Get_DragDropHandler_KeyName(k_KeyName_Drive), wow);
+ */
+}
+
+
+static LONG MyCreateKey(CKey &key, HKEY parentKey, LPCTSTR keyName, UInt32 wow)
+{
+ return key.Create(parentKey, keyName, REG_NONE,
+ REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS | wow);
+}
+
+LONG SetContextMenuHandler(bool setMode, const UString &path, UInt32 wow)
+{
+ // NSynchronization::CCriticalSectionLock lock(g_CS);
+
+ INIT_REG_WOW
+
+ LONG res;
+
+ {
+ CSysString s ("CLSID\\");
+ s += k_Clsid_A;
+
+ if (setMode)
+ {
+ {
+ CKey key;
+ res = MyCreateKey(key, HKEY_CLASSES_ROOT, s, wow);
+ if (res == ERROR_SUCCESS)
+ {
+ key.SetValue(NULL, k_ShellExtName);
+ CKey keyInproc;
+ res = MyCreateKey(keyInproc, key, k_Inproc, wow);
+ if (res == ERROR_SUCCESS)
+ {
+ res = keyInproc.SetValue(NULL, path);
+ keyInproc.SetValue(TEXT("ThreadingModel"), TEXT("Apartment"));
+ }
+ }
+ }
+
+ {
+ CKey key;
+ if (MyCreateKey(key, HKEY_LOCAL_MACHINE, k_Approved, wow) == ERROR_SUCCESS)
+ key.SetValue(k_Clsid, k_ShellExtName);
+ }
+ }
+ else
+ {
+ CSysString s2 (s);
+ s2 += "\\InprocServer32";
+
+ MyRegistry_DeleteKey_HKCR(s2, wow);
+ res = MyRegistry_DeleteKey_HKCR(s, wow);
+ }
+ }
+
+ // shellex items probably are shared beween 32-bit and 64-bit apps. So we don't delete items for delete operation.
+ if (setMode)
+ for (unsigned i = 0; i < 2; i++)
+ {
+ for (unsigned k = 0; k < Z7_ARRAY_SIZE(k_shellex_Prefixes); k++)
+ {
+ CSysString s (k_shellex_Prefixes[k]);
+ s += (i == 0 ? k_KeyPostfix_ContextMenu : k_KeyPostfix_DragDrop);
+ if (k_shellex_Statuses[i][k])
+ {
+ CKey key;
+ MyCreateKey(key, HKEY_CLASSES_ROOT, s, wow);
+ key.SetValue(NULL, k_Clsid);
+ }
+ else
+ MyRegistry_DeleteKey_HKCR(s, wow);
+ }
+ }
+
+ return res;
+}
+
+#endif
diff --git a/CPP/7zip/UI/Explorer/RegistryContextMenu.h b/CPP/7zip/UI/Explorer/RegistryContextMenu.h
new file mode 100644
index 0000000..bf3bb5b
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/RegistryContextMenu.h
@@ -0,0 +1,13 @@
+// RegistryContextMenu.h
+
+#ifndef ZIP7_INC_REGISTRY_CONTEXT_MENU_H
+#define ZIP7_INC_REGISTRY_CONTEXT_MENU_H
+
+#ifndef UNDER_CE
+
+bool CheckContextMenuHandler(const UString &path, UInt32 wow = 0);
+LONG SetContextMenuHandler(bool setMode, const UString &path, UInt32 wow = 0);
+
+#endif
+
+#endif
diff --git a/CPP/7zip/UI/Explorer/StdAfx.cpp b/CPP/7zip/UI/Explorer/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/UI/Explorer/StdAfx.h b/CPP/7zip/UI/Explorer/StdAfx.h
new file mode 100644
index 0000000..130db8a
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/StdAfx.h
@@ -0,0 +1,6 @@
+// StdAfx.h
+
+#if _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../FileManager/StdAfx.h"
diff --git a/CPP/7zip/UI/Explorer/makefile b/CPP/7zip/UI/Explorer/makefile
new file mode 100644
index 0000000..da63a5c
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/makefile
@@ -0,0 +1,76 @@
+PROG = 7-zip.dll
+DEF_FILE = Explorer.def
+CFLAGS = $(CFLAGS) \
+ -DZ7_LANG \
+
+!IFDEF UNDER_CE
+LIBS = $(LIBS) Commctrl.lib
+!ELSE
+LIBS = $(LIBS) htmlhelp.lib comdlg32.lib Mpr.lib Gdi32.lib
+CFLAGS = $(CFLAGS) -DZ7_LONG_PATH
+!ENDIF
+
+EXPLORER_OBJS = \
+ $O\DllExportsExplorer.obj \
+ $O\ContextMenu.obj \
+ $O\MyMessages.obj \
+
+COMMON_OBJS = \
+ $O\IntToString.obj \
+ $O\Lang.obj \
+ $O\MyString.obj \
+ $O\MyVector.obj \
+ $O\NewHandler.obj \
+ $O\Random.obj \
+ $O\StringConvert.obj \
+ $O\StringToInt.obj \
+ $O\UTFConvert.obj \
+ $O\Wildcard.obj \
+
+WIN_OBJS = \
+ $O\DLL.obj \
+ $O\ErrorMsg.obj \
+ $O\FileDir.obj \
+ $O\FileFind.obj \
+ $O\FileIO.obj \
+ $O\FileName.obj \
+ $O\MemoryLock.obj \
+ $O\Menu.obj \
+ $O\ProcessUtils.obj \
+ $O\Registry.obj \
+ $O\ResourceString.obj \
+ $O\Shell.obj \
+ $O\Synchronization.obj \
+ $O\Window.obj \
+
+!IFDEF UNDER_CE
+
+WIN_OBJS = $(WIN_OBJS) \
+ $O\CommonDialog.obj \
+
+!ENDIF
+
+WIN_CTRL_OBJS = \
+ $O\Dialog.obj \
+ $O\ListView.obj \
+
+UI_COMMON_OBJS = \
+ $O\ArchiveName.obj \
+ $O\CompressCall.obj \
+ $O\ExtractingFilePath.obj \
+ $O\ZipRegistry.obj \
+
+FM_OBJS = \
+ $O\FormatUtils.obj \
+ $O\HelpUtils.obj \
+ $O\LangUtils.obj \
+ $O\ProgramLocation.obj \
+ $O\PropertyName.obj \
+ $O\RegistryUtils.obj \
+
+C_OBJS = \
+ $O\CpuArch.obj \
+ $O\Sort.obj \
+ $O\Threads.obj \
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/UI/Explorer/resource.h b/CPP/7zip/UI/Explorer/resource.h
new file mode 100644
index 0000000..bbb28b1
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/resource.h
@@ -0,0 +1,15 @@
+#define IDS_CONTEXT_FOLDER 2320
+#define IDS_CONTEXT_ARCHIVE 2321
+#define IDS_CONTEXT_OPEN 2322
+#define IDS_CONTEXT_EXTRACT 2323
+#define IDS_CONTEXT_COMPRESS 2324
+#define IDS_CONTEXT_TEST 2325
+#define IDS_CONTEXT_EXTRACT_HERE 2326
+#define IDS_CONTEXT_EXTRACT_TO 2327
+#define IDS_CONTEXT_COMPRESS_TO 2328
+#define IDS_CONTEXT_COMPRESS_EMAIL 2329
+#define IDS_CONTEXT_COMPRESS_TO_EMAIL 2330
+
+#define IDS_SELECT_FILES 3015
+
+#define IDB_MENU_LOGO 190
diff --git a/CPP/7zip/UI/Explorer/resource.rc b/CPP/7zip/UI/Explorer/resource.rc
new file mode 100644
index 0000000..acfa6e5
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/resource.rc
@@ -0,0 +1,10 @@
+#include "../../MyVersionInfo.rc"
+#include "resource2.rc"
+
+MY_VERSION_INFO_DLL("7-Zip Shell Extension", "7-zip")
+
+#ifndef UNDER_CE
+1 24 MOVEABLE PURE "7-zip.dll.manifest"
+#endif
+
+IDI_ICON ICON "../FileManager/FM.ico"
diff --git a/CPP/7zip/UI/Explorer/resource2.rc b/CPP/7zip/UI/Explorer/resource2.rc
new file mode 100644
index 0000000..de34824
--- /dev/null
+++ b/CPP/7zip/UI/Explorer/resource2.rc
@@ -0,0 +1,19 @@
+#include "resource.h"
+
+STRINGTABLE
+BEGIN
+ IDS_CONTEXT_FOLDER "<Folder>"
+ IDS_CONTEXT_ARCHIVE "<Archive>"
+ IDS_CONTEXT_OPEN "Open archive"
+ IDS_CONTEXT_EXTRACT "Extract files..."
+ IDS_CONTEXT_COMPRESS "Add to archive..."
+ IDS_CONTEXT_TEST "Test archive"
+ IDS_CONTEXT_EXTRACT_HERE "Extract Here"
+ IDS_CONTEXT_EXTRACT_TO "Extract to {0}"
+ IDS_CONTEXT_COMPRESS_TO "Add to {0}"
+ IDS_CONTEXT_COMPRESS_EMAIL "Compress and email..."
+ IDS_CONTEXT_COMPRESS_TO_EMAIL "Compress to {0} and email"
+ IDS_SELECT_FILES "You must select one or more files"
+END
+
+IDB_MENU_LOGO BITMAP "../../UI/Explorer/MenuLogo.bmp"
diff --git a/CPP/7zip/UI/Far/ExtractEngine.cpp b/CPP/7zip/UI/Far/ExtractEngine.cpp
new file mode 100644
index 0000000..05e9208
--- /dev/null
+++ b/CPP/7zip/UI/Far/ExtractEngine.cpp
@@ -0,0 +1,274 @@
+// ExtractEngine.h
+
+#include "StdAfx.h"
+
+#ifndef Z7_ST
+#include "../../../Windows/Synchronization.h"
+#endif
+
+#include "../../../Common/StringConvert.h"
+
+#include "ExtractEngine.h"
+#include "FarUtils.h"
+#include "Messages.h"
+#include "OverwriteDialogFar.h"
+
+using namespace NWindows;
+using namespace NFar;
+
+#ifndef Z7_ST
+static NSynchronization::CCriticalSection g_CriticalSection;
+#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
+#else
+#define MT_LOCK
+#endif
+
+
+static HRESULT CheckBreak2()
+{
+ return WasEscPressed() ? E_ABORT : S_OK;
+}
+
+extern void PrintMessage(const char *message);
+
+void CExtractCallbackImp::Init(
+ UINT codePage,
+ CProgressBox *progressBox,
+ bool passwordIsDefined,
+ const UString &password)
+{
+ m_PasswordIsDefined = passwordIsDefined;
+ m_Password = password;
+ m_CodePage = codePage;
+ _percent = progressBox;
+}
+
+Z7_COM7F_IMF(CExtractCallbackImp::SetTotal(UInt64 size))
+{
+ MT_LOCK
+
+ if (_percent)
+ {
+ _percent->Total = size;
+ _percent->Print();
+ }
+ return CheckBreak2();
+}
+
+Z7_COM7F_IMF(CExtractCallbackImp::SetCompleted(const UInt64 *completeValue))
+{
+ MT_LOCK
+
+ if (_percent)
+ {
+ if (completeValue)
+ _percent->Completed = *completeValue;
+ _percent->Print();
+ }
+ return CheckBreak2();
+}
+
+Z7_COM7F_IMF(CExtractCallbackImp::AskOverwrite(
+ const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
+ const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
+ Int32 *answer))
+{
+ MT_LOCK
+
+ NOverwriteDialog::CFileInfo oldFileInfo, newFileInfo;
+ oldFileInfo.TimeIsDefined = (existTime != NULL);
+ if (oldFileInfo.TimeIsDefined)
+ oldFileInfo.Time = *existTime;
+ oldFileInfo.SizeIsDefined = (existSize != NULL);
+ if (oldFileInfo.SizeIsDefined)
+ oldFileInfo.Size = *existSize;
+ oldFileInfo.Name = existName;
+
+ newFileInfo.TimeIsDefined = (newTime != NULL);
+ if (newFileInfo.TimeIsDefined)
+ newFileInfo.Time = *newTime;
+ newFileInfo.SizeIsDefined = (newSize != NULL);
+ if (newFileInfo.SizeIsDefined)
+ newFileInfo.Size = *newSize;
+ newFileInfo.Name = newName;
+
+ NOverwriteDialog::NResult::EEnum result =
+ NOverwriteDialog::Execute(oldFileInfo, newFileInfo);
+
+ switch ((int)result)
+ {
+ case NOverwriteDialog::NResult::kCancel:
+ // *answer = NOverwriteAnswer::kCancel;
+ // break;
+ return E_ABORT;
+ case NOverwriteDialog::NResult::kNo:
+ *answer = NOverwriteAnswer::kNo;
+ break;
+ case NOverwriteDialog::NResult::kNoToAll:
+ *answer = NOverwriteAnswer::kNoToAll;
+ break;
+ case NOverwriteDialog::NResult::kYesToAll:
+ *answer = NOverwriteAnswer::kYesToAll;
+ break;
+ case NOverwriteDialog::NResult::kYes:
+ *answer = NOverwriteAnswer::kYes;
+ break;
+ case NOverwriteDialog::NResult::kAutoRename:
+ *answer = NOverwriteAnswer::kAutoRename;
+ break;
+ default:
+ return E_FAIL;
+ }
+
+ return CheckBreak2();
+}
+
+static const char * const kTestString = "Testing";
+static const char * const kExtractString = "Extracting";
+static const char * const kSkipString = "Skipping";
+static const char * const kReadString = "Reading";
+
+Z7_COM7F_IMF(CExtractCallbackImp::PrepareOperation(const wchar_t *name, Int32 /* isFolder */, Int32 askExtractMode, const UInt64 * /* position */))
+{
+ MT_LOCK
+
+ m_CurrentFilePath = name;
+ const char *s;
+
+ switch (askExtractMode)
+ {
+ case NArchive::NExtract::NAskMode::kExtract: s = kExtractString; break;
+ case NArchive::NExtract::NAskMode::kTest: s = kTestString; break;
+ case NArchive::NExtract::NAskMode::kSkip: s = kSkipString; break;
+ case NArchive::NExtract::NAskMode::kReadExternal: s = kReadString; break;
+ default: s = "???"; // return E_FAIL;
+ }
+
+ if (_percent)
+ {
+ _percent->Command = s;
+ _percent->FileName = name;
+ _percent->Print();
+ }
+
+ return CheckBreak2();
+}
+
+Z7_COM7F_IMF(CExtractCallbackImp::MessageError(const wchar_t *message))
+{
+ MT_LOCK
+
+ AString s (UnicodeStringToMultiByte(message, CP_OEMCP));
+ if (g_StartupInfo.ShowErrorMessage((const char *)s) == -1)
+ return E_ABORT;
+
+ return CheckBreak2();
+}
+
+void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &s);
+void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &s)
+{
+ s.Empty();
+
+ switch (opRes)
+ {
+ case NArchive::NExtract::NOperationResult::kOK:
+ return;
+ default:
+ {
+ UINT messageID = 0;
+ switch (opRes)
+ {
+ case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
+ messageID = NMessageID::kExtractUnsupportedMethod;
+ break;
+ case NArchive::NExtract::NOperationResult::kCRCError:
+ messageID = encrypted ?
+ NMessageID::kExtractCRCFailedEncrypted :
+ NMessageID::kExtractCRCFailed;
+ break;
+ case NArchive::NExtract::NOperationResult::kDataError:
+ messageID = encrypted ?
+ NMessageID::kExtractDataErrorEncrypted :
+ NMessageID::kExtractDataError;
+ break;
+ }
+ if (messageID != 0)
+ {
+ s = g_StartupInfo.GetMsgString((int)messageID);
+ s.Replace((AString)" '%s'", AString());
+ }
+ else if (opRes == NArchive::NExtract::NOperationResult::kUnavailable)
+ s = "Unavailable data";
+ else if (opRes == NArchive::NExtract::NOperationResult::kUnexpectedEnd)
+ s = "Unexpected end of data";
+ else if (opRes == NArchive::NExtract::NOperationResult::kDataAfterEnd)
+ s = "There are some data after the end of the payload data";
+ else if (opRes == NArchive::NExtract::NOperationResult::kIsNotArc)
+ s = "Is not archive";
+ else if (opRes == NArchive::NExtract::NOperationResult::kHeadersError)
+ s = "kHeaders Error";
+ else if (opRes == NArchive::NExtract::NOperationResult::kWrongPassword)
+ s = "Wrong Password";
+ else
+ {
+ s = "Error #";
+ s.Add_UInt32((UInt32)opRes);
+ }
+ }
+ }
+}
+
+Z7_COM7F_IMF(CExtractCallbackImp::SetOperationResult(Int32 opRes, Int32 encrypted))
+{
+ MT_LOCK
+
+ if (opRes == NArchive::NExtract::NOperationResult::kOK)
+ {
+ if (_percent)
+ {
+ _percent->Command.Empty();
+ _percent->FileName.Empty();
+ _percent->Files++;
+ }
+ }
+ else
+ {
+ AString s;
+ SetExtractErrorMessage(opRes, encrypted, s);
+ if (PrintErrorMessage(s, m_CurrentFilePath) == -1)
+ return E_ABORT;
+ }
+
+ return CheckBreak2();
+}
+
+
+Z7_COM7F_IMF(CExtractCallbackImp::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name))
+{
+ MT_LOCK
+
+ if (opRes != NArchive::NExtract::NOperationResult::kOK)
+ {
+ AString s;
+ SetExtractErrorMessage(opRes, encrypted, s);
+ if (PrintErrorMessage(s, name) == -1)
+ return E_ABORT;
+ }
+
+ return CheckBreak2();
+}
+
+extern HRESULT GetPassword(UString &password);
+
+Z7_COM7F_IMF(CExtractCallbackImp::CryptoGetTextPassword(BSTR *password))
+{
+ MT_LOCK
+
+ if (!m_PasswordIsDefined)
+ {
+ RINOK(GetPassword(m_Password))
+ m_PasswordIsDefined = true;
+ }
+ return StringToBstr(m_Password, password);
+}
diff --git a/CPP/7zip/UI/Far/ExtractEngine.h b/CPP/7zip/UI/Far/ExtractEngine.h
new file mode 100644
index 0000000..2bee2ee
--- /dev/null
+++ b/CPP/7zip/UI/Far/ExtractEngine.h
@@ -0,0 +1,43 @@
+// ExtractEngine.h
+
+#ifndef ZIP7_INC_EXTRACT_ENGINE_H
+#define ZIP7_INC_EXTRACT_ENGINE_H
+
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyString.h"
+
+#include "../../IPassword.h"
+#include "../Agent/IFolderArchive.h"
+
+#include "ProgressBox.h"
+
+Z7_CLASS_IMP_COM_3(
+ CExtractCallbackImp
+ , IFolderArchiveExtractCallback
+ , IFolderArchiveExtractCallback2
+ , ICryptoGetTextPassword
+)
+ Z7_IFACE_COM7_IMP(IProgress)
+
+ UString m_CurrentFilePath;
+
+ CProgressBox *_percent;
+ UINT m_CodePage;
+
+ bool m_PasswordIsDefined;
+ UString m_Password;
+
+ void CreateComplexDirectory(const UStringVector &dirPathParts);
+ /*
+ void GetPropertyValue(LPITEMIDLIST anItemIDList, PROPID aPropId,
+ PROPVARIANT *aValue);
+ bool IsEncrypted(LPITEMIDLIST anItemIDList);
+ */
+ void AddErrorMessage(LPCTSTR message);
+public:
+ void Init(UINT codePage,
+ CProgressBox *progressBox,
+ bool passwordIsDefined, const UString &password);
+};
+
+#endif
diff --git a/CPP/7zip/UI/Far/Far.cpp b/CPP/7zip/UI/Far/Far.cpp
new file mode 100644
index 0000000..74d5e60
--- /dev/null
+++ b/CPP/7zip/UI/Far/Far.cpp
@@ -0,0 +1,587 @@
+// Far.cpp
+// Test Align for updating !!!!!!!!!!!!!!!!!!
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+#include "../../../Common/MyInitGuid.h"
+
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/NtCheck.h"
+
+#include "../../Common/FileStreams.h"
+
+#include "Messages.h"
+#include "Plugin.h"
+#include "ProgressBox.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+using namespace NFar;
+
+static const DWORD kShowProgressTime_ms = 100;
+
+static const char * const kCommandPrefix = "7-zip";
+static const char * const kRegisrtryMainKeyName = NULL; // ""
+static LPCTSTR const kRegisrtryValueNameEnabled = TEXT("UsedByDefault3");
+static const char * const kHelpTopicConfig = "Config";
+static bool kPluginEnabledDefault = true;
+
+extern
+HINSTANCE g_hInstance;
+HINSTANCE g_hInstance;
+
+namespace NFar {
+
+extern
+const char *g_PluginName_for_Error;
+const char *g_PluginName_for_Error = "7-Zip";
+
+}
+
+#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE)
+#define NT_CHECK_FAIL_ACTION return FALSE;
+#endif
+
+BOOL WINAPI DllMain(
+ #ifdef UNDER_CE
+ HANDLE
+ #else
+ HINSTANCE
+ #endif
+ hInstance, DWORD dwReason, LPVOID);
+BOOL WINAPI DllMain(
+ #ifdef UNDER_CE
+ HANDLE
+ #else
+ HINSTANCE
+ #endif
+ hInstance, DWORD dwReason, LPVOID)
+{
+ if (dwReason == DLL_PROCESS_ATTACH)
+ {
+ // OutputDebugStringA("7-Zip FAR DLL_PROCESS_ATTACH");
+ g_hInstance = (HINSTANCE)hInstance;
+ NT_CHECK
+ }
+ if (dwReason == DLL_PROCESS_DETACH)
+ {
+ // OutputDebugStringA("7-Zip FAR DLL_PROCESS_DETACH");
+ }
+ return TRUE;
+}
+
+static struct COptions
+{
+ bool Enabled;
+} g_Options;
+
+static const char * const kPliginNameForRegistry = "7-ZIP";
+
+EXTERN_C void WINAPI ExitFAR()
+{
+ /* WIN32:
+ it's not allowed to call FreeLibrary() from FreeLibrary().
+ So we try to free all DLLs before destructors */
+ // OutputDebugStringA("-- ExitFAR --- START");
+
+ FreeGlobalCodecs();
+
+ // OutputDebugStringA("-- ExitFAR --- END");
+}
+
+EXTERN_C void WINAPI SetStartupInfo(const PluginStartupInfo *info)
+{
+ MY_TRY_BEGIN
+ g_StartupInfo.Init(*info, kPliginNameForRegistry);
+ g_Options.Enabled = g_StartupInfo.QueryRegKeyValue(
+ HKEY_CURRENT_USER, kRegisrtryMainKeyName,
+ kRegisrtryValueNameEnabled, kPluginEnabledDefault);
+
+ // OutputDebugStringA("SetStartupInfo");
+ // LoadGlobalCodecs();
+
+ MY_TRY_END1("SetStartupInfo")
+}
+
+Z7_CLASS_IMP_COM_3(
+ COpenArchiveCallback
+ , IArchiveOpenCallback
+ , IProgress
+ , ICryptoGetTextPassword
+)
+ // DWORD m_StartTickValue;
+ bool m_MessageBoxIsShown;
+
+ CProgressBox _progressBox;
+
+ bool _numFilesTotalDefined;
+ bool _numBytesTotalDefined;
+
+public:
+ bool PasswordIsDefined;
+ UString Password;
+
+ COpenArchiveCallback()
+ {}
+
+ void Init()
+ {
+ PasswordIsDefined = false;
+
+ _numFilesTotalDefined = false;
+ _numBytesTotalDefined = false;
+
+ m_MessageBoxIsShown = false;
+
+ _progressBox.Init(
+ // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle),
+ g_StartupInfo.GetMsgString(NMessageID::kReading));
+ }
+ void ShowMessage();
+};
+
+static HRESULT CheckBreak2()
+{
+ return WasEscPressed() ? E_ABORT : S_OK;
+}
+
+void COpenArchiveCallback::ShowMessage()
+{
+ if (!m_MessageBoxIsShown)
+ {
+ DWORD currentTime = GetTickCount();
+ if (currentTime - _progressBox.StartTick < kShowProgressTime_ms)
+ return;
+ m_MessageBoxIsShown = true;
+ }
+
+ _progressBox.UseBytesForPercents = !_numFilesTotalDefined;
+ _progressBox.Print();
+}
+
+Z7_COM7F_IMF(COpenArchiveCallback::SetTotal(const UInt64 *numFiles, const UInt64 *numBytes))
+{
+ _numFilesTotalDefined = (numFiles != NULL);
+ if (_numFilesTotalDefined)
+ _progressBox.FilesTotal = *numFiles;
+
+ _numBytesTotalDefined = (numBytes != NULL);
+ if (_numBytesTotalDefined)
+ _progressBox.Total = *numBytes;
+
+ return CheckBreak2();
+}
+
+Z7_COM7F_IMF(COpenArchiveCallback::SetCompleted(const UInt64 *numFiles, const UInt64 *numBytes))
+{
+ if (numFiles)
+ _progressBox.Files = *numFiles;
+
+ if (numBytes)
+ _progressBox.Completed = *numBytes;
+
+ ShowMessage();
+ return CheckBreak2();
+}
+
+
+Z7_COM7F_IMF(COpenArchiveCallback::SetTotal(const UInt64 /* total */))
+{
+ return CheckBreak2();
+}
+
+Z7_COM7F_IMF(COpenArchiveCallback::SetCompleted(const UInt64 * /* completed */))
+{
+ ShowMessage();
+ return CheckBreak2();
+}
+
+HRESULT GetPassword(UString &password);
+HRESULT GetPassword(UString &password)
+{
+ if (WasEscPressed())
+ return E_ABORT;
+ password.Empty();
+ CInitDialogItem initItems[]=
+ {
+ { DI_DOUBLEBOX, 3, 1, 72, 4, false, false, 0, false, NMessageID::kGetPasswordTitle, NULL, NULL },
+ { DI_TEXT, 5, 2, 0, 0, false, false, DIF_SHOWAMPERSAND, false, NMessageID::kEnterPasswordForFile, NULL, NULL },
+ { DI_PSWEDIT, 5, 3, 70, 3, true, false, 0, true, -1, "", NULL }
+ };
+
+ const int kNumItems = Z7_ARRAY_SIZE(initItems);
+ FarDialogItem dialogItems[kNumItems];
+ g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumItems);
+
+ // sprintf(DialogItems[1].Data,GetMsg(MGetPasswordForFile),FileName);
+ if (g_StartupInfo.ShowDialog(76, 6, NULL, dialogItems, kNumItems) < 0)
+ return E_ABORT;
+
+ password = MultiByteToUnicodeString(dialogItems[2].Data, CP_OEMCP);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(COpenArchiveCallback::CryptoGetTextPassword(BSTR *password))
+{
+ if (!PasswordIsDefined)
+ {
+ RINOK(GetPassword(Password))
+ PasswordIsDefined = true;
+ }
+ return StringToBstr(Password, password);
+}
+
+/*
+HRESULT OpenArchive(const CSysString &fileName,
+ IInFolderArchive **archiveHandlerResult,
+ CArchiverInfo &archiverInfoResult,
+ UString &defaultName,
+ IArchiveOpenCallback *openArchiveCallback)
+{
+ HRESULT OpenArchive(const CSysString &fileName,
+ IInArchive **archive,
+ CArchiverInfo &archiverInfoResult,
+ IArchiveOpenCallback *openArchiveCallback);
+}
+*/
+
+static HANDLE MyOpenFilePluginW(const wchar_t *name, bool isAbortCodeSupported)
+{
+ FString normalizedName = us2fs(name);
+ normalizedName.Trim();
+ FString fullName;
+ MyGetFullPathName(normalizedName, fullName);
+ NFind::CFileInfo fileInfo;
+ if (!fileInfo.Find(fullName))
+ return INVALID_HANDLE_VALUE;
+ if (fileInfo.IsDir())
+ return INVALID_HANDLE_VALUE;
+
+
+ CMyComPtr<IInFolderArchive> archiveHandler;
+
+ // CArchiverInfo archiverInfoResult;
+ // ::OutputDebugStringA("before OpenArchive\n");
+
+ CScreenRestorer screenRestorer;
+ {
+ screenRestorer.Save();
+ }
+
+ COpenArchiveCallback *openArchiveCallbackSpec = new COpenArchiveCallback;
+ CMyComPtr<IArchiveOpenCallback> uiCallback = openArchiveCallbackSpec;
+
+ /* COpenCallbackImp object will exist after Open stage for multivolume archioves */
+ COpenCallbackImp *impSpec = new COpenCallbackImp;
+ CMyComPtr<IArchiveOpenCallback> impCallback = impSpec;
+ impSpec->ReOpenCallback = openArchiveCallbackSpec; // we set pointer without reference counter
+
+ // if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0)
+ openArchiveCallbackSpec->Init();
+ {
+ FString dirPrefix, fileName;
+ GetFullPathAndSplit(fullName, dirPrefix, fileName);
+ impSpec->Init2(dirPrefix, fileName);
+ }
+
+ // ::OutputDebugStringA("before OpenArchive\n");
+
+ CAgent *agent = new CAgent;
+ archiveHandler = agent;
+ CMyComBSTR archiveType;
+ HRESULT result = archiveHandler->Open(NULL,
+ GetUnicodeString(fullName, CP_OEMCP), UString(), &archiveType, impCallback);
+ /*
+ HRESULT result = ::OpenArchive(fullName, &archiveHandler,
+ archiverInfoResult, defaultName, openArchiveCallback);
+ */
+ if (result == E_ABORT)
+ {
+ // fixed 18.06:
+ // OpenFilePlugin() is allowed to return (HANDLE)-2 as abort code
+ // OpenPlugin() is not allowed to return (HANDLE)-2.
+ return isAbortCodeSupported ? (HANDLE)-2 : INVALID_HANDLE_VALUE;
+ }
+
+ UString errorMessage = agent->GetErrorMessage();
+ if (!errorMessage.IsEmpty())
+ g_StartupInfo.ShowErrorMessage(UnicodeStringToMultiByte(errorMessage, CP_OEMCP));
+
+ if (result != S_OK)
+ {
+ if (result == S_FALSE)
+ return INVALID_HANDLE_VALUE;
+ ShowSysErrorMessage(result);
+ return INVALID_HANDLE_VALUE;
+ }
+
+ // ::OutputDebugStringA("after OpenArchive\n");
+
+ CPlugin *plugin = new CPlugin(
+ fullName,
+ // defaultName,
+ agent,
+ (const wchar_t *)archiveType
+ );
+
+ plugin->PasswordIsDefined = openArchiveCallbackSpec->PasswordIsDefined;
+ plugin->Password = openArchiveCallbackSpec->Password;
+
+ // OutputDebugStringA("--- OpenFilePlugin ---- END");
+ return (HANDLE)(plugin);
+}
+
+static HANDLE MyOpenFilePlugin(const char *name, bool isAbortCodeSupported)
+{
+ UINT codePage =
+ #ifdef UNDER_CE
+ CP_OEMCP;
+ #else
+ ::AreFileApisANSI() ? CP_ACP : CP_OEMCP;
+ #endif
+ return MyOpenFilePluginW(GetUnicodeString(name, codePage), isAbortCodeSupported);
+}
+
+EXTERN_C HANDLE WINAPI OpenFilePlugin(char *name, const unsigned char * /* data */, int /* dataSize */)
+{
+ MY_TRY_BEGIN
+ // OutputDebugStringA("--- OpenFilePlugin");
+ if (name == NULL || (!g_Options.Enabled))
+ {
+ // if (!Opt.ProcessShiftF1)
+ return(INVALID_HANDLE_VALUE);
+ }
+ return MyOpenFilePlugin(name, true); // isAbortCodeSupported
+ MY_TRY_END2("OpenFilePlugin", INVALID_HANDLE_VALUE)
+}
+
+/*
+EXTERN_C HANDLE WINAPI OpenFilePluginW(const wchar_t *name,const unsigned char *Data,int DataSize,int OpMode)
+{
+ MY_TRY_BEGIN
+ if (name == NULL || (!g_Options.Enabled))
+ {
+ // if (!Opt.ProcessShiftF1)
+ return(INVALID_HANDLE_VALUE);
+ }
+ return MyOpenFilePluginW(name);
+ ::OutputDebugStringA("OpenFilePluginW\n");
+ MY_TRY_END2("OpenFilePluginW", INVALID_HANDLE_VALUE);
+}
+*/
+
+EXTERN_C HANDLE WINAPI OpenPlugin(int openFrom, INT_PTR item)
+{
+ MY_TRY_BEGIN
+
+ if (openFrom == OPEN_COMMANDLINE)
+ {
+ AString fileName ((const char *)item);
+ if (fileName.IsEmpty())
+ return INVALID_HANDLE_VALUE;
+ if (fileName.Len() >= 2
+ && fileName[0] == '\"'
+ && fileName.Back() == '\"')
+ {
+ fileName.DeleteBack();
+ fileName.DeleteFrontal(1);
+ }
+ return MyOpenFilePlugin(fileName, false); // isAbortCodeSupported
+ }
+
+ if (openFrom == OPEN_PLUGINSMENU)
+ {
+ switch (item)
+ {
+ case 0:
+ {
+ PluginPanelItem pluginPanelItem;
+ if (!g_StartupInfo.ControlGetActivePanelCurrentItemInfo(pluginPanelItem))
+ throw 142134;
+ return MyOpenFilePlugin(pluginPanelItem.FindData.cFileName, false); // isAbortCodeSupported
+ }
+
+ case 1:
+ {
+ CObjectVector<PluginPanelItem> pluginPanelItem;
+ if (!g_StartupInfo.ControlGetActivePanelSelectedOrCurrentItems(pluginPanelItem))
+ throw 142134;
+ HRESULT res = CompressFiles(pluginPanelItem);
+ if (res != S_OK && res != E_ABORT)
+ {
+ ShowSysErrorMessage(res);
+ }
+ // if (res == S_OK)
+ {
+ /* int t = */ g_StartupInfo.ControlClearPanelSelection();
+ g_StartupInfo.ControlRequestActivePanel(FCTL_UPDATEPANEL, NULL);
+ g_StartupInfo.ControlRequestActivePanel(FCTL_REDRAWPANEL, NULL);
+ g_StartupInfo.ControlRequestActivePanel(FCTL_UPDATEANOTHERPANEL, NULL);
+ g_StartupInfo.ControlRequestActivePanel(FCTL_REDRAWANOTHERPANEL, NULL);
+ }
+ return INVALID_HANDLE_VALUE;
+ }
+
+ default:
+ throw 4282215;
+ }
+ }
+
+ return INVALID_HANDLE_VALUE;
+ MY_TRY_END2("OpenPlugin", INVALID_HANDLE_VALUE)
+}
+
+EXTERN_C void WINAPI ClosePlugin(HANDLE plugin)
+{
+ // OutputDebugStringA("-- ClosePlugin --- START");
+ // MY_TRY_BEGIN
+ delete (CPlugin *)plugin;
+ // OutputDebugStringA("-- ClosePlugin --- END");
+ // MY_TRY_END1("ClosePlugin");
+}
+
+EXTERN_C int WINAPI GetFindData(HANDLE plugin, struct PluginPanelItem **panelItems, int *itemsNumber, int opMode)
+{
+ MY_TRY_BEGIN
+ return(((CPlugin *)plugin)->GetFindData(panelItems, itemsNumber, opMode));
+ MY_TRY_END2("GetFindData", FALSE)
+}
+
+EXTERN_C void WINAPI FreeFindData(HANDLE plugin, struct PluginPanelItem *panelItems, int itemsNumber)
+{
+ // MY_TRY_BEGIN
+ ((CPlugin *)plugin)->FreeFindData(panelItems, itemsNumber);
+ // MY_TRY_END1("FreeFindData");
+}
+
+EXTERN_C int WINAPI GetFiles(HANDLE plugin, struct PluginPanelItem *panelItems,
+ int itemsNumber, int move, char *destPath, int opMode)
+{
+ MY_TRY_BEGIN
+ return(((CPlugin *)plugin)->GetFiles(panelItems, (unsigned)itemsNumber, move, destPath, opMode));
+ MY_TRY_END2("GetFiles", NFileOperationReturnCode::kError)
+}
+
+EXTERN_C int WINAPI SetDirectory(HANDLE plugin, const char *dir, int opMode)
+{
+ MY_TRY_BEGIN
+ return(((CPlugin *)plugin)->SetDirectory(dir, opMode));
+ MY_TRY_END2("SetDirectory", FALSE)
+}
+
+EXTERN_C void WINAPI GetPluginInfo(struct PluginInfo *info)
+{
+ MY_TRY_BEGIN
+
+ info->StructSize = sizeof(*info);
+ info->Flags = 0;
+ info->DiskMenuStrings = NULL;
+ info->DiskMenuNumbers = NULL;
+ info->DiskMenuStringsNumber = 0;
+ static char *pluginMenuStrings[2];
+ pluginMenuStrings[0] = const_cast<char *>(g_StartupInfo.GetMsgString(NMessageID::kOpenArchiveMenuString));
+ pluginMenuStrings[1] = const_cast<char *>(g_StartupInfo.GetMsgString(NMessageID::kCreateArchiveMenuString));
+ info->PluginMenuStrings = (char **)pluginMenuStrings;
+ info->PluginMenuStringsNumber = 2;
+ static char *pluginCfgStrings[1];
+ pluginCfgStrings[0] = const_cast<char *>(g_StartupInfo.GetMsgString(NMessageID::kOpenArchiveMenuString));
+ info->PluginConfigStrings = (char **)pluginCfgStrings;
+ info->PluginConfigStringsNumber = Z7_ARRAY_SIZE(pluginCfgStrings);
+ info->CommandPrefix = const_cast<char *>(kCommandPrefix);
+ MY_TRY_END1("GetPluginInfo")
+}
+
+EXTERN_C int WINAPI Configure(int /* itemNumber */)
+{
+ MY_TRY_BEGIN
+
+ const int kEnabledCheckBoxIndex = 1;
+
+ const int kYSize = 7;
+
+ struct CInitDialogItem initItems[]=
+ {
+ { DI_DOUBLEBOX, 3, 1, 72, kYSize - 2, false, false, 0, false, NMessageID::kConfigTitle, NULL, NULL },
+ { DI_CHECKBOX, 5, 2, 0, 0, true, g_Options.Enabled, 0, false, NMessageID::kConfigPluginEnabled, NULL, NULL },
+ { DI_TEXT, 5, 3, 0, 0, false, false, DIF_BOXCOLOR | DIF_SEPARATOR, false, -1, "", NULL },
+ { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kOk, NULL, NULL },
+ { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kCancel, NULL, NULL },
+ };
+
+ const int kNumDialogItems = Z7_ARRAY_SIZE(initItems);
+ const int kOkButtonIndex = kNumDialogItems - 2;
+
+ FarDialogItem dialogItems[kNumDialogItems];
+ g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems);
+
+ int askCode = g_StartupInfo.ShowDialog(76, kYSize,
+ kHelpTopicConfig, dialogItems, kNumDialogItems);
+
+ if (askCode != kOkButtonIndex)
+ return (FALSE);
+
+ g_Options.Enabled = BOOLToBool(dialogItems[kEnabledCheckBoxIndex].Selected);
+
+ g_StartupInfo.SetRegKeyValue(HKEY_CURRENT_USER, kRegisrtryMainKeyName,
+ kRegisrtryValueNameEnabled, g_Options.Enabled);
+ return(TRUE);
+ MY_TRY_END2("Configure", FALSE)
+}
+
+EXTERN_C void WINAPI GetOpenPluginInfo(HANDLE plugin,struct OpenPluginInfo *info)
+{
+ MY_TRY_BEGIN
+ ((CPlugin *)plugin)->GetOpenPluginInfo(info);
+ MY_TRY_END1("GetOpenPluginInfo")
+}
+
+EXTERN_C int WINAPI PutFiles(HANDLE plugin, struct PluginPanelItem *panelItems, int itemsNumber, int move, int opMode)
+{
+ MY_TRY_BEGIN
+ return (((CPlugin *)plugin)->PutFiles(panelItems, (unsigned)itemsNumber, move, opMode));
+ MY_TRY_END2("PutFiles", NFileOperationReturnCode::kError)
+}
+
+EXTERN_C int WINAPI DeleteFiles(HANDLE plugin, PluginPanelItem *panelItems, int itemsNumber, int opMode)
+{
+ MY_TRY_BEGIN
+ return (((CPlugin *)plugin)->DeleteFiles(panelItems, (unsigned)itemsNumber, opMode));
+ MY_TRY_END2("DeleteFiles", FALSE)
+}
+
+EXTERN_C int WINAPI ProcessKey(HANDLE plugin, int key, unsigned int controlState)
+{
+ MY_TRY_BEGIN
+ /* FIXME: after folder creation with F7, it doesn't reload new file list
+ We need some to reload it */
+ return (((CPlugin *)plugin)->ProcessKey(key, controlState));
+ MY_TRY_END2("ProcessKey", FALSE)
+}
+
+/*
+struct MakeDirectoryInfo
+{
+ size_t StructSize;
+ HANDLE hPanel;
+ const wchar_t *Name;
+ OPERATION_MODES OpMode;
+ void* Instance;
+};
+
+typedef INT_PTR MY_intptr_t;
+
+MY_intptr_t WINAPI MakeDirectoryW(struct MakeDirectoryInfo *Info)
+{
+ MY_TRY_BEGIN
+ if (Info->StructSize < sizeof(MakeDirectoryInfo))
+ {
+ return 0;
+ }
+ return 0;
+ MY_TRY_END2("MakeDirectoryW", FALSE);
+}
+*/
diff --git a/CPP/7zip/UI/Far/Far.def b/CPP/7zip/UI/Far/Far.def
new file mode 100644
index 0000000..1de9acd
--- /dev/null
+++ b/CPP/7zip/UI/Far/Far.def
@@ -0,0 +1,35 @@
+; 7-ZipFar.def : Declares the module parameters for the DLL.
+
+LIBRARY "7-ZipFar"
+
+EXPORTS
+ ExitFAR
+ SetStartupInfo
+ OpenPlugin
+ OpenFilePlugin
+ ClosePlugin
+ GetFindData
+ FreeFindData
+ SetDirectory
+ GetPluginInfo
+ Configure
+ GetOpenPluginInfo
+ GetFiles
+ PutFiles
+ DeleteFiles
+ ProcessKey
+
+ ;SetStartupInfoW
+ ;OpenPluginW
+ ;OpenFilePluginW
+ ;ClosePluginW
+ ;GetFindDataW
+ ;FreeFindDataW
+ ;SetDirectoryW
+ ;GetPluginInfoW
+ ;ConfigureW
+ ;GetOpenPluginInfoW
+ ;GetFilesW
+ ;PutFilesW
+ ;DeleteFilesW
+ ;ProcessKeyW
diff --git a/CPP/7zip/UI/Far/Far.dsp b/CPP/7zip/UI/Far/Far.dsp
new file mode 100644
index 0000000..823c728
--- /dev/null
+++ b/CPP/7zip/UI/Far/Far.dsp
@@ -0,0 +1,831 @@
+# Microsoft Developer Studio Project File - Name="Far" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=Far - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "Far.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "Far.mak" CFG="Far - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "Far - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "Far - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "Far - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FAR_EXPORTS" /YX /FD /c
+# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FAR_EXPORTS" /D "Z7_EXTERNAL_CODECS" /Yu"StdAfx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386 /out:"C:\Progs\Far\Plugins\7-Zip\7-ZipFar.dll" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "Far - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 1
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FAR_EXPORTS" /YX /FD /GZ /c
+# ADD CPP /nologo /Gz /MTd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "FAR_EXPORTS" /D "Z7_EXTERNAL_CODECS" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /out:"C:\Progs\Far\Plugins\7-Zip\7-ZipFar.dll" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "Far - Win32 Release"
+# Name "Far - Win32 Debug"
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\Far.def
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"StdAfx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\Common.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynLimBuf.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynLimBuf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyCom.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.h
+# End Source File
+# End Group
+# Begin Group "Plugin"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\ExtractEngine.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ExtractEngine.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Far.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Messages.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\OverwriteDialogFar.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\OverwriteDialogFar.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Plugin.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Plugin.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\PluginDelete.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\PluginRead.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\PluginWrite.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\UpdateCallbackFar.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\UpdateCallbackFar.h
+# End Source File
+# End Group
+# Begin Group "Far"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\FarPlugin.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FarUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\FarUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ProgressBox.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ProgressBox.h
+# End Source File
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileLink.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileSystem.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileSystem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Registry.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Registry.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ResourceString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ResourceString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\TimeUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\TimeUtils.h
+# End Source File
+# End Group
+# Begin Group "UI Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\Common\ArchiveExtractCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveOpenCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveOpenCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\DefaultName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\DefaultName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\DirItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\EnumDirItems.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\EnumDirItems.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ExtractingFilePath.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ExtractingFilePath.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ExtractMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\HandlerLoader.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\HashCalc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\HashCalc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\LoadCodecs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\LoadCodecs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\OpenArchive.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\OpenArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\PropIDUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\PropIDUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\SetProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\SetProperties.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\SortUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\SortUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateAction.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateAction.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdatePair.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdatePair.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateProduce.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateProduce.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\WorkDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\WorkDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ZipRegistry.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ZipRegistry.h
+# End Source File
+# End Group
+# Begin Group "Agent"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\Agent\Agent.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\Agent.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\AgentOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\AgentProxy.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\AgentProxy.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\ArchiveFolder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\ArchiveFolderOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\IFolderArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\UpdateCallbackAgent.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\UpdateCallbackAgent.h
+# End Source File
+# End Group
+# Begin Group "Compress"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.h
+# End Source File
+# End Group
+# Begin Group "7-zip Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\PropId.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\UniqBlocks.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\UniqBlocks.h
+# End Source File
+# End Group
+# Begin Group "C"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrcOpt.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sort.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sort.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.h
+# End Source File
+# End Group
+# Begin Group "Arc Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.h
+# End Source File
+# End Group
+# Begin Group "Interface"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\IArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ICoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IDecl.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\IFileExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\IFolder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IPassword.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IProgress.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\PropID.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/CPP/7zip/UI/Far/Far.dsw b/CPP/7zip/UI/Far/Far.dsw
new file mode 100644
index 0000000..f4ef080
--- /dev/null
+++ b/CPP/7zip/UI/Far/Far.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "Far"=.\Far.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/UI/Far/FarPlugin.h b/CPP/7zip/UI/Far/FarPlugin.h
new file mode 100644
index 0000000..ad3ed38
--- /dev/null
+++ b/CPP/7zip/UI/Far/FarPlugin.h
@@ -0,0 +1,560 @@
+// FarPlugin.h
+
+// #include "plugin.hpp"
+
+const int kInfoPanelLineSize = 80;
+
+// #define __FAR_PLUGIN_H
+
+#ifdef UNDER_CE
+typedef struct _CHAR_INFO {
+ union {
+ WCHAR UnicodeChar;
+ CHAR AsciiChar;
+ } Char;
+ WORD Attributes;
+} CHAR_INFO, *PCHAR_INFO;
+#endif
+
+#ifndef ZIP7_INC_FAR_PLUGIN_H
+#define ZIP7_INC_FAR_PLUGIN_H
+
+#ifndef _WIN64
+#if defined(__BORLANDC__) && (__BORLANDC <= 0x520)
+ #pragma option -a1
+#elif defined(__GNUC__) || (defined(__WATCOMC__) && (__WATCOMC__ < 1100))
+ #pragma pack(1)
+#else
+ #pragma pack(push,1)
+#endif
+#endif
+
+ #if _MSC_VER
+ #define _export
+ #endif
+
+#define NM 260
+
+struct FarFindData
+{
+ DWORD dwFileAttributes;
+ FILETIME ftCreationTime;
+ FILETIME ftLastAccessTime;
+ FILETIME ftLastWriteTime;
+ DWORD nFileSizeHigh;
+ DWORD nFileSizeLow;
+ DWORD dwReserved0;
+ DWORD dwReserved1;
+ char cFileName[ MAX_PATH ];
+ char cAlternateFileName[ 14 ];
+};
+
+struct PluginPanelItem
+{
+ FarFindData FindData;
+ DWORD PackSizeHigh;
+ DWORD PackSize;
+ DWORD Flags;
+ DWORD NumberOfLinks;
+ char *Description;
+ char *Owner;
+ char **CustomColumnData;
+ int CustomColumnNumber;
+ DWORD_PTR UserData;
+ DWORD CRC32;
+ DWORD_PTR Reserved[2];
+};
+
+#define PPIF_PROCESSDESCR 0x80000000
+#define PPIF_SELECTED 0x40000000
+#define PPIF_USERDATA 0x20000000
+
+enum {
+ FMENU_SHOWAMPERSAND=1,
+ FMENU_WRAPMODE=2,
+ FMENU_AUTOHIGHLIGHT=4,
+ FMENU_REVERSEAUTOHIGHLIGHT=8
+};
+
+
+typedef int (WINAPI *FARAPIMENU)(
+ INT_PTR PluginNumber,
+ int X,
+ int Y,
+ int MaxHeight,
+ unsigned int Flags,
+ char *Title,
+ char *Bottom,
+ char *HelpTopic,
+ int *BreakKeys,
+ int *BreakCode,
+ struct FarMenuItem *Item,
+ int ItemsNumber
+);
+
+typedef int (WINAPI *FARAPIDIALOG)(
+ INT_PTR PluginNumber,
+ int X1,
+ int Y1,
+ int X2,
+ int Y2,
+ char *HelpTopic,
+ struct FarDialogItem *Item,
+ int ItemsNumber
+);
+
+enum {
+ FMSG_WARNING = 0x00000001,
+ FMSG_ERRORTYPE = 0x00000002,
+ FMSG_KEEPBACKGROUND = 0x00000004,
+ FMSG_DOWN = 0x00000008,
+ FMSG_LEFTALIGN = 0x00000010,
+
+ FMSG_ALLINONE = 0x00000020,
+
+ FMSG_MB_OK = 0x00010000,
+ FMSG_MB_OKCANCEL = 0x00020000,
+ FMSG_MB_ABORTRETRYIGNORE = 0x00030000,
+ FMSG_MB_YESNO = 0x00040000,
+ FMSG_MB_YESNOCANCEL = 0x00050000,
+ FMSG_MB_RETRYCANCEL = 0x00060000
+};
+
+typedef int (WINAPI *FARAPIMESSAGE)(
+ INT_PTR PluginNumber,
+ unsigned int Flags,
+ const char *HelpTopic,
+ const char * const *Items,
+ int ItemsNumber,
+ int ButtonsNumber
+);
+
+typedef char* (WINAPI *FARAPIGETMSG)(
+ INT_PTR PluginNumber,
+ int MsgId
+);
+
+
+enum DialogItemTypes {
+ DI_TEXT,
+ DI_VTEXT,
+ DI_SINGLEBOX,
+ DI_DOUBLEBOX,
+ DI_EDIT,
+ DI_PSWEDIT,
+ DI_FIXEDIT,
+ DI_BUTTON,
+ DI_CHECKBOX,
+ DI_RADIOBUTTON
+};
+
+enum FarDialogItemFlags {
+ DIF_COLORMASK = 0xff,
+ DIF_SETCOLOR = 0x100,
+ DIF_BOXCOLOR = 0x200,
+ DIF_GROUP = 0x400,
+ DIF_LEFTTEXT = 0x800,
+ DIF_MOVESELECT = 0x1000,
+ DIF_SHOWAMPERSAND = 0x2000,
+ DIF_CENTERGROUP = 0x4000,
+ DIF_NOBRACKETS = 0x8000,
+ DIF_SEPARATOR = 0x10000,
+ DIF_EDITOR = 0x20000,
+ DIF_HISTORY = 0x40000
+};
+
+struct FarDialogItem
+{
+ int Type;
+ int X1,Y1,X2,Y2;
+ int Focus;
+ union
+ {
+ int Selected;
+ const char *History;
+ const char *Mask;
+ struct FarList *ListItems;
+ int ListPos;
+ CHAR_INFO *VBuf;
+ };
+ unsigned int Flags;
+ int DefaultButton;
+ char Data[512];
+};
+
+
+struct FarMenuItem
+{
+ char Text[128];
+ int Selected;
+ int Checked;
+ int Separator;
+};
+
+
+enum {FCTL_CLOSEPLUGIN,FCTL_GETPANELINFO,FCTL_GETANOTHERPANELINFO,
+ FCTL_UPDATEPANEL,FCTL_UPDATEANOTHERPANEL,
+ FCTL_REDRAWPANEL,FCTL_REDRAWANOTHERPANEL,
+ FCTL_SETANOTHERPANELDIR,FCTL_GETCMDLINE,FCTL_SETCMDLINE,
+ FCTL_SETSELECTION,FCTL_SETANOTHERSELECTION,
+ FCTL_SETVIEWMODE,FCTL_SETANOTHERVIEWMODE,FCTL_INSERTCMDLINE,
+ FCTL_SETUSERSCREEN,FCTL_SETPANELDIR,FCTL_SETCMDLINEPOS,
+ FCTL_GETCMDLINEPOS
+};
+
+enum {PTYPE_FILEPANEL,PTYPE_TREEPANEL,PTYPE_QVIEWPANEL,PTYPE_INFOPANEL};
+
+struct PanelInfo
+{
+ int PanelType;
+ int Plugin;
+ RECT PanelRect;
+ struct PluginPanelItem *PanelItems;
+ int ItemsNumber;
+ struct PluginPanelItem *SelectedItems;
+ int SelectedItemsNumber;
+ int CurrentItem;
+ int TopPanelItem;
+ int Visible;
+ int Focus;
+ int ViewMode;
+ char ColumnTypes[80];
+ char ColumnWidths[80];
+ char CurDir[NM];
+ int ShortNames;
+ int SortMode;
+ DWORD Flags;
+ DWORD Reserved;
+};
+
+
+struct PanelRedrawInfo
+{
+ int CurrentItem;
+ int TopPanelItem;
+};
+
+
+typedef int (WINAPI *FARAPICONTROL)(
+ HANDLE hPlugin,
+ int Command,
+ void *Param
+);
+
+typedef HANDLE (WINAPI *FARAPISAVESCREEN)(int X1,int Y1,int X2,int Y2);
+
+typedef void (WINAPI *FARAPIRESTORESCREEN)(HANDLE hScreen);
+
+typedef int (WINAPI *FARAPIGETDIRLIST)(
+ char *Dir,
+ struct PluginPanelItem **pPanelItem,
+ int *pItemsNumber
+);
+
+typedef int (WINAPI *FARAPIGETPLUGINDIRLIST)(
+ INT_PTR PluginNumber,
+ HANDLE hPlugin,
+ char *Dir,
+ struct PluginPanelItem **pPanelItem,
+ int *pItemsNumber
+);
+
+typedef void (WINAPI *FARAPIFREEDIRLIST)(struct PluginPanelItem *PanelItem);
+
+enum VIEWER_FLAGS {
+ VF_NONMODAL=1,VF_DELETEONCLOSE=2
+};
+
+typedef int (WINAPI *FARAPIVIEWER)(
+ char *FileName,
+ char *Title,
+ int X1,
+ int Y1,
+ int X2,
+ int Y2,
+ DWORD Flags
+);
+
+typedef int (WINAPI *FARAPIEDITOR)(
+ char *FileName,
+ char *Title,
+ int X1,
+ int Y1,
+ int X2,
+ int Y2,
+ DWORD Flags,
+ int StartLine,
+ int StartChar
+);
+
+typedef int (WINAPI *FARAPICMPNAME)(
+ char *Pattern,
+ char *String,
+ int SkipPath
+);
+
+
+#define FCT_DETECT 0x40000000
+
+struct CharTableSet
+{
+ char DecodeTable[256];
+ char EncodeTable[256];
+ char UpperTable[256];
+ char LowerTable[256];
+ char TableName[128];
+};
+
+typedef int (WINAPI *FARAPICHARTABLE)(
+ int Command,
+ char *Buffer,
+ int BufferSize
+);
+
+typedef void (WINAPI *FARAPITEXT)(
+ int X,
+ int Y,
+ int Color,
+ char *Str
+);
+
+
+typedef int (WINAPI *FARAPIEDITORCONTROL)(
+ int Command,
+ void *Param
+);
+
+struct PluginStartupInfo
+{
+ int StructSize;
+ char ModuleName[NM];
+ INT_PTR ModuleNumber;
+ char *RootKey;
+ FARAPIMENU Menu;
+ FARAPIDIALOG Dialog;
+ FARAPIMESSAGE Message;
+ FARAPIGETMSG GetMsg;
+ FARAPICONTROL Control;
+ FARAPISAVESCREEN SaveScreen;
+ FARAPIRESTORESCREEN RestoreScreen;
+ FARAPIGETDIRLIST GetDirList;
+ FARAPIGETPLUGINDIRLIST GetPluginDirList;
+ FARAPIFREEDIRLIST FreeDirList;
+ FARAPIVIEWER Viewer;
+ FARAPIEDITOR Editor;
+ FARAPICMPNAME CmpName;
+ FARAPICHARTABLE CharTable;
+ FARAPITEXT Text;
+ FARAPIEDITORCONTROL EditorControl;
+};
+
+
+enum PLUGIN_FLAGS {
+ PF_PRELOAD = 0x0001,
+ PF_DISABLEPANELS = 0x0002,
+ PF_EDITOR = 0x0004,
+ PF_VIEWER = 0x0008
+};
+
+
+struct PluginInfo
+{
+ int StructSize;
+ DWORD Flags;
+ char **DiskMenuStrings;
+ int *DiskMenuNumbers;
+ int DiskMenuStringsNumber;
+ char **PluginMenuStrings;
+ int PluginMenuStringsNumber;
+ char **PluginConfigStrings;
+ int PluginConfigStringsNumber;
+ char *CommandPrefix;
+};
+
+struct InfoPanelLine
+{
+ char Text[kInfoPanelLineSize];
+ char Data[kInfoPanelLineSize];
+ int Separator;
+};
+
+
+struct PanelMode
+{
+ char *ColumnTypes;
+ char *ColumnWidths;
+ char **ColumnTitles;
+ int FullScreen;
+ int DetailedStatus;
+ int AlignExtensions;
+ int CaseConversion;
+ char *StatusColumnTypes;
+ char *StatusColumnWidths;
+ DWORD Reserved[2];
+};
+
+
+enum OPENPLUGININFO_FLAGS {
+ OPIF_USEFILTER = 0x0001,
+ OPIF_USESORTGROUPS = 0x0002,
+ OPIF_USEHIGHLIGHTING = 0x0004,
+ OPIF_ADDDOTS = 0x0008,
+ OPIF_RAWSELECTION = 0x0010,
+ OPIF_REALNAMES = 0x0020,
+ OPIF_SHOWNAMESONLY = 0x0040,
+ OPIF_SHOWRIGHTALIGNNAMES = 0x0080,
+ OPIF_SHOWPRESERVECASE = 0x0100,
+ OPIF_FINDFOLDERS = 0x0200,
+ OPIF_COMPAREFATTIME = 0x0400,
+ OPIF_EXTERNALGET = 0x0800,
+ OPIF_EXTERNALPUT = 0x1000,
+ OPIF_EXTERNALDELETE = 0x2000,
+ OPIF_EXTERNALMKDIR = 0x4000,
+ OPIF_USEATTRHIGHLIGHTING = 0x8000
+};
+
+
+enum OPENPLUGININFO_SORTMODES {
+ SM_DEFAULT,SM_UNSORTED,SM_NAME,SM_EXT,SM_MTIME,SM_CTIME,
+ SM_ATIME,SM_SIZE,SM_DESCR,SM_OWNER,SM_COMPRESSEDSIZE,SM_NUMLINKS
+};
+
+
+struct KeyBarTitles
+{
+ char *Titles[12];
+ char *CtrlTitles[12];
+ char *AltTitles[12];
+ char *ShiftTitles[12];
+};
+
+
+struct OpenPluginInfo
+{
+ int StructSize;
+ DWORD Flags;
+ const char *HostFile;
+ const char *CurDir;
+ const char *Format;
+ const char *PanelTitle;
+ const struct InfoPanelLine *InfoLines;
+ int InfoLinesNumber;
+ const char * const *DescrFiles;
+ int DescrFilesNumber;
+ const struct PanelMode *PanelModesArray;
+ int PanelModesNumber;
+ int StartPanelMode;
+ int StartSortMode;
+ int StartSortOrder;
+ const struct KeyBarTitles *KeyBar;
+ const char *ShortcutData;
+ // long Reserverd;
+};
+
+enum {
+ OPEN_DISKMENU,
+ OPEN_PLUGINSMENU,
+ OPEN_FINDLIST,
+ OPEN_SHORTCUT,
+ OPEN_COMMANDLINE,
+ OPEN_EDITOR,
+ OPEN_VIEWER
+};
+
+enum {PKF_CONTROL=1,PKF_ALT=2,PKF_SHIFT=4};
+
+enum FAR_EVENTS {
+ FE_CHANGEVIEWMODE,
+ FE_REDRAW,
+ FE_IDLE,
+ FE_CLOSE,
+ FE_BREAK,
+ FE_COMMAND
+};
+
+enum OPERATION_MODES {
+ OPM_SILENT=1,
+ OPM_FIND=2,
+ OPM_VIEW=4,
+ OPM_EDIT=8,
+ OPM_TOPLEVEL=16,
+ OPM_DESCR=32
+};
+
+#ifndef _WIN64
+#if defined(__BORLANDC__) && (__BORLANDC <= 0x520)
+ #pragma option -a.
+#elif defined(__GNUC__) || (defined(__WATCOMC__) && (__WATCOMC__ < 1100))
+ #pragma pack()
+#else
+ #pragma pack(pop)
+#endif
+#endif
+
+/*
+EXTERN_C_BEGIN
+
+ void WINAPI _export ClosePluginW(HANDLE hPlugin);
+ int WINAPI _export CompareW(HANDLE hPlugin,const struct PluginPanelItem *Item1,const struct PluginPanelItem *Item2,unsigned int Mode);
+ int WINAPI _export ConfigureW(int ItemNumber);
+ int WINAPI _export DeleteFilesW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int OpMode);
+ void WINAPI _export ExitFARW(void);
+ void WINAPI _export FreeFindDataW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber);
+ void WINAPI _export FreeVirtualFindDataW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber);
+ int WINAPI _export GetFilesW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int Move,const wchar_t **DestPath,int OpMode);
+ int WINAPI _export GetFindDataW(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber,int OpMode);
+ int WINAPI _export GetMinFarVersionW(void);
+ void WINAPI _export GetOpenPluginInfoW(HANDLE hPlugin,struct OpenPluginInfo *Info);
+ void WINAPI _export GetPluginInfoW(struct PluginInfo *Info);
+ int WINAPI _export GetVirtualFindDataW(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber,const wchar_t *Path);
+ int WINAPI _export MakeDirectoryW(HANDLE hPlugin,const wchar_t **Name,int OpMode);
+ HANDLE WINAPI _export OpenFilePluginW(const wchar_t *Name,const unsigned char *Data,int DataSize,int OpMode);
+ HANDLE WINAPI _export OpenPluginW(int OpenFrom,INT_PTR Item);
+ int WINAPI _export ProcessDialogEventW(int Event,void *Param);
+ int WINAPI _export ProcessEditorEventW(int Event,void *Param);
+ int WINAPI _export ProcessEditorInputW(const INPUT_RECORD *Rec);
+ int WINAPI _export ProcessEventW(HANDLE hPlugin,int Event,void *Param);
+ int WINAPI _export ProcessHostFileW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int OpMode);
+ int WINAPI _export ProcessKeyW(HANDLE hPlugin,int Key,unsigned int ControlState);
+ int WINAPI _export ProcessSynchroEventW(int Event,void *Param);
+ int WINAPI _export ProcessViewerEventW(int Event,void *Param);
+ int WINAPI _export PutFilesW(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int Move,const wchar_t *SrcPath,int OpMode);
+ int WINAPI _export SetDirectoryW(HANDLE hPlugin,const wchar_t *Dir,int OpMode);
+ int WINAPI _export SetFindListW(HANDLE hPlugin,const struct PluginPanelItem *PanelItem,int ItemsNumber);
+ void WINAPI _export SetStartupInfoW(const struct PluginStartupInfo *Info);
+
+EXTERN_C_END
+*/
+EXTERN_C_BEGIN
+
+ void WINAPI _export ClosePlugin(HANDLE hPlugin);
+ int WINAPI _export Compare(HANDLE hPlugin,const struct PluginPanelItem *Item1,const struct PluginPanelItem *Item2,unsigned int Mode);
+ int WINAPI _export Configure(int ItemNumber);
+ int WINAPI _export DeleteFiles(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int OpMode);
+ void WINAPI _export ExitFAR(void);
+ void WINAPI _export FreeFindData(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber);
+ void WINAPI _export FreeVirtualFindData(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber);
+ int WINAPI _export GetFiles(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int Move,char *DestPath,int OpMode);
+ int WINAPI _export GetFindData(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber,int OpMode);
+ int WINAPI _export GetMinFarVersion(void);
+ void WINAPI _export GetOpenPluginInfo(HANDLE hPlugin,struct OpenPluginInfo *Info);
+ void WINAPI _export GetPluginInfo(struct PluginInfo *Info);
+ int WINAPI _export GetVirtualFindData(HANDLE hPlugin,struct PluginPanelItem **pPanelItem,int *pItemsNumber,const char *Path);
+ int WINAPI _export MakeDirectory(HANDLE hPlugin,char *Name,int OpMode);
+ HANDLE WINAPI _export OpenFilePlugin(char *Name,const unsigned char *Data,int DataSize);
+ HANDLE WINAPI _export OpenPlugin(int OpenFrom,INT_PTR Item);
+ int WINAPI _export ProcessDialogEvent(int Event,void *Param);
+ int WINAPI _export ProcessEditorEvent(int Event,void *Param);
+ int WINAPI _export ProcessEditorInput(const INPUT_RECORD *Rec);
+ int WINAPI _export ProcessEvent(HANDLE hPlugin,int Event,void *Param);
+ int WINAPI _export ProcessHostFile(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int OpMode);
+ int WINAPI _export ProcessKey(HANDLE hPlugin,int Key,unsigned int ControlState);
+ int WINAPI _export ProcessViewerEvent(int Event,void *Param);
+ int WINAPI _export PutFiles(HANDLE hPlugin,struct PluginPanelItem *PanelItem,int ItemsNumber,int Move,int OpMode);
+ int WINAPI _export SetDirectory(HANDLE hPlugin,const char *Dir,int OpMode);
+ int WINAPI _export SetFindList(HANDLE hPlugin,const struct PluginPanelItem *PanelItem,int ItemsNumber);
+ void WINAPI _export SetStartupInfo(const struct PluginStartupInfo *Info);
+
+EXTERN_C_END
+
+#endif
diff --git a/CPP/7zip/UI/Far/FarUtils.cpp b/CPP/7zip/UI/Far/FarUtils.cpp
new file mode 100644
index 0000000..9fddbc1
--- /dev/null
+++ b/CPP/7zip/UI/Far/FarUtils.cpp
@@ -0,0 +1,524 @@
+// FarUtils.cpp
+
+#include "StdAfx.h"
+
+// #include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+
+#ifndef UNDER_CE
+#include "../../../Windows/Console.h"
+#endif
+#include "../../../Windows/Defs.h"
+#include "../../../Windows/ErrorMsg.h"
+
+#include "FarUtils.h"
+
+using namespace NWindows;
+
+namespace NFar {
+
+CStartupInfo g_StartupInfo;
+
+const char kRegistryKeyDelimiter = '\\';
+
+void CStartupInfo::Init(const PluginStartupInfo &pluginStartupInfo,
+ const char *pluginNameForRegistry)
+{
+ m_Data = pluginStartupInfo;
+ m_RegistryPath = pluginStartupInfo.RootKey;
+ m_RegistryPath += kRegistryKeyDelimiter;
+ m_RegistryPath += pluginNameForRegistry;
+}
+
+const char *CStartupInfo::GetMsgString(int messageId)
+{
+ return (const char*)m_Data.GetMsg(m_Data.ModuleNumber, messageId);
+}
+
+int CStartupInfo::ShowMessage(unsigned int flags,
+ const char *helpTopic, const char **items, unsigned numItems, int numButtons)
+{
+ return m_Data.Message(m_Data.ModuleNumber, flags, helpTopic,
+ items, (int)numItems, numButtons);
+}
+
+namespace NMessageID
+{
+ enum
+ {
+ kOk,
+ kCancel,
+ kWarning,
+ kError
+ };
+}
+
+int CStartupInfo::ShowWarningWithOk(const char **items, unsigned numItems)
+{
+ return ShowMessage(FMSG_WARNING | FMSG_MB_OK, NULL, items, numItems, 0);
+}
+
+extern const char *g_PluginName_for_Error;
+
+void CStartupInfo::SetErrorTitle(AString &s)
+{
+ if (g_PluginName_for_Error)
+ {
+ s += g_PluginName_for_Error;
+ s += ": ";
+ }
+ s += GetMsgString(NMessageID::kError);
+}
+
+/*
+int CStartupInfo::ShowErrorMessage(const char *message)
+{
+ AString s;
+ SetErrorTitle(s);
+ const char *items[]= { s, message };
+ return ShowWarningWithOk(items, Z7_ARRAY_SIZE(items));
+}
+*/
+
+int CStartupInfo::ShowErrorMessage2(const char *m1, const char *m2)
+{
+ AString s;
+ SetErrorTitle(s);
+ const char *items[]= { s, m1, m2 };
+ return ShowWarningWithOk(items, Z7_ARRAY_SIZE(items));
+}
+
+static void SplitString(const AString &src, AStringVector &destStrings)
+{
+ destStrings.Clear();
+ AString s;
+ unsigned len = src.Len();
+ if (len == 0)
+ return;
+ for (unsigned i = 0; i < len; i++)
+ {
+ char c = src[i];
+ if (c == '\n')
+ {
+ if (!s.IsEmpty())
+ {
+ destStrings.Add(s);
+ s.Empty();
+ }
+ }
+ else
+ s += c;
+ }
+ if (!s.IsEmpty())
+ destStrings.Add(s);
+}
+
+int CStartupInfo::ShowErrorMessage(const char *message)
+{
+ AStringVector strings;
+ SplitString((AString)message, strings);
+ const unsigned kNumStringsMax = 20;
+ const char *items[kNumStringsMax + 1];
+ unsigned pos = 0;
+ items[pos++] = GetMsgString(NMessageID::kError);
+ for (unsigned i = 0; i < strings.Size() && pos < kNumStringsMax; i++)
+ items[pos++] = strings[i];
+ items[pos++] = GetMsgString(NMessageID::kOk);
+
+ return ShowMessage(FMSG_WARNING, NULL, items, pos, 1);
+}
+
+/*
+int CStartupInfo::ShowMessageLines(const char *message)
+{
+ AString s = GetMsgString(NMessageID::kError);
+ s.Add_LF();
+ s += message;
+ return ShowMessage(FMSG_WARNING | FMSG_MB_OK | FMSG_ALLINONE, NULL,
+ (const char **)(const char *)s, 1, 0);
+}
+*/
+
+int CStartupInfo::ShowMessage(int messageId)
+{
+ return ShowErrorMessage(GetMsgString(messageId));
+}
+
+int CStartupInfo::ShowDialog(int X1, int Y1, int X2, int Y2,
+ const char *helpTopic, struct FarDialogItem *items, unsigned numItems)
+{
+ return m_Data.Dialog(m_Data.ModuleNumber, X1, Y1, X2, Y2, const_cast<char *>(helpTopic),
+ items, (int)numItems);
+}
+
+int CStartupInfo::ShowDialog(int sizeX, int sizeY,
+ const char *helpTopic, struct FarDialogItem *items, unsigned numItems)
+{
+ return ShowDialog(-1, -1, sizeX, sizeY, helpTopic, items, numItems);
+}
+
+inline static BOOL GetBOOLValue(bool v) { return (v? TRUE: FALSE); }
+
+void CStartupInfo::InitDialogItems(const CInitDialogItem *srcItems,
+ FarDialogItem *destItems, unsigned numItems)
+{
+ for (unsigned i = 0; i < numItems; i++)
+ {
+ const CInitDialogItem &srcItem = srcItems[i];
+ FarDialogItem &destItem = destItems[i];
+
+ destItem.Type = srcItem.Type;
+ destItem.X1 = srcItem.X1;
+ destItem.Y1 = srcItem.Y1;
+ destItem.X2 = srcItem.X2;
+ destItem.Y2 = srcItem.Y2;
+ destItem.Focus = GetBOOLValue(srcItem.Focus);
+ if (srcItem.HistoryName != NULL)
+ destItem.History = srcItem.HistoryName;
+ else
+ destItem.Selected = GetBOOLValue(srcItem.Selected);
+ destItem.Flags = srcItem.Flags;
+ destItem.DefaultButton = GetBOOLValue(srcItem.DefaultButton);
+
+ if (srcItem.DataMessageId < 0)
+ MyStringCopy(destItem.Data, srcItem.DataString);
+ else
+ MyStringCopy(destItem.Data, GetMsgString(srcItem.DataMessageId));
+
+ /*
+ if ((unsigned int)Init[i].Data < 0xFFF)
+ MyStringCopy(destItem.Data, GetMsg((unsigned int)srcItem.Data));
+ else
+ MyStringCopy(destItem.Data,srcItem.Data);
+ */
+ }
+}
+
+// --------------------------------------------
+
+HANDLE CStartupInfo::SaveScreen(int X1, int Y1, int X2, int Y2)
+{
+ return m_Data.SaveScreen(X1, Y1, X2, Y2);
+}
+
+HANDLE CStartupInfo::SaveScreen()
+{
+ return SaveScreen(0, 0, -1, -1);
+}
+
+void CStartupInfo::RestoreScreen(HANDLE handle)
+{
+ m_Data.RestoreScreen(handle);
+}
+
+CSysString CStartupInfo::GetFullKeyName(const char *keyName) const
+{
+ AString s (m_RegistryPath);
+ if (keyName && *keyName)
+ {
+ s += kRegistryKeyDelimiter;
+ s += keyName;
+ }
+ return (CSysString)s;
+}
+
+
+LONG CStartupInfo::CreateRegKey(HKEY parentKey,
+ const char *keyName, NRegistry::CKey &destKey) const
+{
+ return destKey.Create(parentKey, GetFullKeyName(keyName));
+}
+
+LONG CStartupInfo::OpenRegKey(HKEY parentKey,
+ const char *keyName, NRegistry::CKey &destKey) const
+{
+ return destKey.Open(parentKey, GetFullKeyName(keyName));
+}
+
+void CStartupInfo::SetRegKeyValue(HKEY parentKey, const char *keyName,
+ LPCTSTR valueName, LPCTSTR value) const
+{
+ NRegistry::CKey regKey;
+ CreateRegKey(parentKey, keyName, regKey);
+ regKey.SetValue(valueName, value);
+}
+
+void CStartupInfo::SetRegKeyValue(HKEY parentKey, const char *keyName,
+ LPCTSTR valueName, UInt32 value) const
+{
+ NRegistry::CKey regKey;
+ CreateRegKey(parentKey, keyName, regKey);
+ regKey.SetValue(valueName, value);
+}
+
+void CStartupInfo::SetRegKeyValue(HKEY parentKey, const char *keyName,
+ LPCTSTR valueName, bool value) const
+{
+ NRegistry::CKey regKey;
+ CreateRegKey(parentKey, keyName, regKey);
+ regKey.SetValue(valueName, value);
+}
+
+CSysString CStartupInfo::QueryRegKeyValue(HKEY parentKey, const char *keyName,
+ LPCTSTR valueName, const CSysString &valueDefault) const
+{
+ NRegistry::CKey regKey;
+ if (OpenRegKey(parentKey, keyName, regKey) != ERROR_SUCCESS)
+ return valueDefault;
+
+ CSysString value;
+ if (regKey.QueryValue(valueName, value) != ERROR_SUCCESS)
+ return valueDefault;
+
+ return value;
+}
+
+UInt32 CStartupInfo::QueryRegKeyValue(HKEY parentKey, const char *keyName,
+ LPCTSTR valueName, UInt32 valueDefault) const
+{
+ NRegistry::CKey regKey;
+ if (OpenRegKey(parentKey, keyName, regKey) != ERROR_SUCCESS)
+ return valueDefault;
+
+ UInt32 value;
+ if (regKey.QueryValue(valueName, value) != ERROR_SUCCESS)
+ return valueDefault;
+
+ return value;
+}
+
+bool CStartupInfo::QueryRegKeyValue(HKEY parentKey, const char *keyName,
+ LPCTSTR valueName, bool valueDefault) const
+{
+ NRegistry::CKey regKey;
+ if (OpenRegKey(parentKey, keyName, regKey) != ERROR_SUCCESS)
+ return valueDefault;
+
+ bool value;
+ if (regKey.QueryValue(valueName, value) != ERROR_SUCCESS)
+ return valueDefault;
+
+ return value;
+}
+
+bool CStartupInfo::Control(HANDLE pluginHandle, int command, void *param)
+{
+ return BOOLToBool(m_Data.Control(pluginHandle, command, param));
+}
+
+bool CStartupInfo::ControlRequestActivePanel(int command, void *param)
+{
+ return Control(INVALID_HANDLE_VALUE, command, param);
+}
+
+bool CStartupInfo::ControlGetActivePanelInfo(PanelInfo &panelInfo)
+{
+ return ControlRequestActivePanel(FCTL_GETPANELINFO, &panelInfo);
+}
+
+bool CStartupInfo::ControlSetSelection(const PanelInfo &panelInfo)
+{
+ return ControlRequestActivePanel(FCTL_SETSELECTION, (void *)&panelInfo);
+}
+
+bool CStartupInfo::ControlGetActivePanelCurrentItemInfo(
+ PluginPanelItem &pluginPanelItem)
+{
+ PanelInfo panelInfo;
+ if (!ControlGetActivePanelInfo(panelInfo))
+ return false;
+ if (panelInfo.ItemsNumber <= 0)
+ throw "There are no items";
+ pluginPanelItem = panelInfo.PanelItems[panelInfo.CurrentItem];
+ return true;
+}
+
+bool CStartupInfo::ControlGetActivePanelSelectedOrCurrentItems(
+ CObjectVector<PluginPanelItem> &pluginPanelItems)
+{
+ pluginPanelItems.Clear();
+ PanelInfo panelInfo;
+ if (!ControlGetActivePanelInfo(panelInfo))
+ return false;
+ if (panelInfo.ItemsNumber <= 0)
+ throw "There are no items";
+ if (panelInfo.SelectedItemsNumber == 0)
+ pluginPanelItems.Add(panelInfo.PanelItems[panelInfo.CurrentItem]);
+ else
+ for (int i = 0; i < panelInfo.SelectedItemsNumber; i++)
+ pluginPanelItems.Add(panelInfo.SelectedItems[i]);
+ return true;
+}
+
+bool CStartupInfo::ControlClearPanelSelection()
+{
+ PanelInfo panelInfo;
+ if (!ControlGetActivePanelInfo(panelInfo))
+ return false;
+ for (int i = 0; i < panelInfo.ItemsNumber; i++)
+ panelInfo.PanelItems[i].Flags &= ~(DWORD)PPIF_SELECTED;
+ return ControlSetSelection(panelInfo);
+}
+
+////////////////////////////////////////////////
+// menu function
+
+int CStartupInfo::Menu(
+ int x,
+ int y,
+ int maxHeight,
+ unsigned int flags,
+ const char *title,
+ const char *aBottom,
+ const char *helpTopic,
+ int *breakKeys,
+ int *breakCode,
+ struct FarMenuItem *items,
+ unsigned numItems)
+{
+ return m_Data.Menu(m_Data.ModuleNumber, x, y, maxHeight, flags,
+ const_cast<char *>(title),
+ const_cast<char *>(aBottom),
+ const_cast<char *>(helpTopic),
+ breakKeys, breakCode, items, (int)numItems);
+}
+
+int CStartupInfo::Menu(
+ unsigned int flags,
+ const char *title,
+ const char *helpTopic,
+ struct FarMenuItem *items,
+ unsigned numItems)
+{
+ return Menu(-1, -1, 0, flags, title, NULL, helpTopic, NULL,
+ NULL, items, numItems);
+}
+
+int CStartupInfo::Menu(
+ unsigned int flags,
+ const char *title,
+ const char *helpTopic,
+ const AStringVector &items,
+ int selectedItem)
+{
+ CRecordVector<FarMenuItem> farMenuItems;
+ FOR_VECTOR (i, items)
+ {
+ FarMenuItem item;
+ item.Checked = 0;
+ item.Separator = 0;
+ item.Selected = ((int)i == selectedItem);
+ const AString reducedString (items[i].Left(Z7_ARRAY_SIZE(item.Text) - 1));
+ MyStringCopy(item.Text, reducedString);
+ farMenuItems.Add(item);
+ }
+ return Menu(flags, title, helpTopic, &farMenuItems.Front(), farMenuItems.Size());
+}
+
+
+//////////////////////////////////
+// CScreenRestorer
+
+CScreenRestorer::~CScreenRestorer()
+{
+ Restore();
+}
+void CScreenRestorer::Save()
+{
+ if (m_Saved)
+ return;
+ m_HANDLE = g_StartupInfo.SaveScreen();
+ m_Saved = true;
+}
+
+void CScreenRestorer::Restore()
+{
+ if (m_Saved)
+ {
+ g_StartupInfo.RestoreScreen(m_HANDLE);
+ m_Saved = false;
+ }
+}
+
+int PrintErrorMessage(const char *message, unsigned code)
+{
+ AString s (message);
+ s += " #";
+ s.Add_UInt32((UInt32)code);
+ return g_StartupInfo.ShowErrorMessage(s);
+}
+
+int PrintErrorMessage(const char *message, const char *text)
+{
+ return g_StartupInfo.ShowErrorMessage2(message, text);
+}
+
+
+void ReduceString(UString &s, unsigned size)
+{
+ if (s.Len() > size)
+ {
+ if (size > 5)
+ size -= 5;
+ s.Delete(size / 2, s.Len() - size);
+ s.Insert(size / 2, L" ... ");
+ }
+}
+
+int PrintErrorMessage(const char *message, const wchar_t *name, unsigned maxLen)
+{
+ UString s = name;
+ ReduceString(s, maxLen);
+ return PrintErrorMessage(message, UnicodeStringToMultiByte(s, CP_OEMCP));
+}
+
+int ShowSysErrorMessage(DWORD errorCode)
+{
+ const UString message = NError::MyFormatMessage(errorCode);
+ return g_StartupInfo.ShowErrorMessage(UnicodeStringToMultiByte(message, CP_OEMCP));
+}
+
+int ShowLastErrorMessage()
+{
+ return ShowSysErrorMessage(::GetLastError());
+}
+
+int ShowSysErrorMessage(DWORD errorCode, const wchar_t *name)
+{
+ const UString s = NError::MyFormatMessage(errorCode);
+ return g_StartupInfo.ShowErrorMessage2(
+ UnicodeStringToMultiByte(s, CP_OEMCP),
+ UnicodeStringToMultiByte(name, CP_OEMCP));
+}
+
+
+bool WasEscPressed()
+{
+ #ifdef UNDER_CE
+ return false;
+ #else
+ NConsole::CIn inConsole;
+ HANDLE handle = ::GetStdHandle(STD_INPUT_HANDLE);
+ if (handle == INVALID_HANDLE_VALUE)
+ return true;
+ inConsole.Attach(handle);
+ for (;;)
+ {
+ DWORD numEvents;
+ if (!inConsole.GetNumberOfEvents(numEvents))
+ return true;
+ if (numEvents == 0)
+ return false;
+
+ INPUT_RECORD event;
+ if (!inConsole.ReadEvent(event, numEvents))
+ return true;
+ if (event.EventType == KEY_EVENT &&
+ event.Event.KeyEvent.bKeyDown &&
+ event.Event.KeyEvent.wVirtualKeyCode == VK_ESCAPE)
+ return true;
+ }
+ #endif
+}
+
+}
diff --git a/CPP/7zip/UI/Far/FarUtils.h b/CPP/7zip/UI/Far/FarUtils.h
new file mode 100644
index 0000000..6e6ff3c
--- /dev/null
+++ b/CPP/7zip/UI/Far/FarUtils.h
@@ -0,0 +1,203 @@
+// FarUtils.h
+
+#ifndef ZIP7_INC_FAR_UTILS_H
+#define ZIP7_INC_FAR_UTILS_H
+
+#include "FarPlugin.h"
+
+#include "../../../Windows/Registry.h"
+
+namespace NFar {
+
+namespace NFileOperationReturnCode
+{
+ enum EEnum
+ {
+ kInterruptedByUser = -1,
+ kError = 0,
+ kSuccess = 1
+ };
+}
+
+namespace NEditorReturnCode
+{
+ enum EEnum
+ {
+ kOpenError = 0,
+ kFileWasChanged = 1,
+ kFileWasNotChanged = 2,
+ kInterruptedByUser = 3
+ };
+}
+
+struct CInitDialogItem
+{
+ DialogItemTypes Type;
+ int X1,Y1,X2,Y2;
+ bool Focus;
+ bool Selected;
+ unsigned int Flags; //FarDialogItemFlags Flags;
+ bool DefaultButton;
+ int DataMessageId;
+ const char *DataString;
+ const char *HistoryName;
+ // void InitToFarDialogItem(struct FarDialogItem &anItemDest);
+};
+
+class CStartupInfo
+{
+ PluginStartupInfo m_Data;
+ AString m_RegistryPath;
+
+ CSysString GetFullKeyName(const char *keyName) const;
+ LONG CreateRegKey(HKEY parentKey,
+ const char *keyName, NWindows::NRegistry::CKey &destKey) const;
+ LONG OpenRegKey(HKEY parentKey,
+ const char *keyName, NWindows::NRegistry::CKey &destKey) const;
+
+public:
+ void Init(const PluginStartupInfo &pluginStartupInfo,
+ const char *pluginNameForRegistry);
+ const char *GetMsgString(int messageId);
+
+ int ShowMessage(unsigned int flags, const char *helpTopic,
+ const char **items, unsigned numItems, int numButtons);
+ int ShowWarningWithOk(const char **items, unsigned numItems);
+
+ void SetErrorTitle(AString &s);
+ int ShowErrorMessage(const char *message);
+ int ShowErrorMessage2(const char *m1, const char *m2);
+ // int ShowMessageLines(const char *messageLines);
+ int ShowMessage(int messageId);
+
+ int ShowDialog(int X1, int Y1, int X2, int Y2,
+ const char *helpTopic, struct FarDialogItem *items, unsigned numItems);
+ int ShowDialog(int sizeX, int sizeY,
+ const char *helpTopic, struct FarDialogItem *items, unsigned numItems);
+
+ void InitDialogItems(const CInitDialogItem *srcItems,
+ FarDialogItem *destItems, unsigned numItems);
+
+ HANDLE SaveScreen(int X1, int Y1, int X2, int Y2);
+ HANDLE SaveScreen();
+ void RestoreScreen(HANDLE handle);
+
+ void SetRegKeyValue(HKEY parentKey, const char *keyName,
+ const LPCTSTR valueName, LPCTSTR value) const;
+ void SetRegKeyValue(HKEY hRoot, const char *keyName,
+ const LPCTSTR valueName, UInt32 value) const;
+ void SetRegKeyValue(HKEY hRoot, const char *keyName,
+ const LPCTSTR valueName, bool value) const;
+
+ CSysString QueryRegKeyValue(HKEY parentKey, const char *keyName,
+ LPCTSTR valueName, const CSysString &valueDefault) const;
+
+ UInt32 QueryRegKeyValue(HKEY parentKey, const char *keyName,
+ LPCTSTR valueName, UInt32 valueDefault) const;
+
+ bool QueryRegKeyValue(HKEY parentKey, const char *keyName,
+ LPCTSTR valueName, bool valueDefault) const;
+
+ bool Control(HANDLE plugin, int command, void *param);
+ bool ControlRequestActivePanel(int command, void *param);
+ bool ControlGetActivePanelInfo(PanelInfo &panelInfo);
+ bool ControlSetSelection(const PanelInfo &panelInfo);
+ bool ControlGetActivePanelCurrentItemInfo(PluginPanelItem &pluginPanelItem);
+ bool ControlGetActivePanelSelectedOrCurrentItems(
+ CObjectVector<PluginPanelItem> &pluginPanelItems);
+
+ bool ControlClearPanelSelection();
+
+ int Menu(
+ int x,
+ int y,
+ int maxHeight,
+ unsigned int flags,
+ const char *title,
+ const char *aBottom,
+ const char *helpTopic,
+ int *breakKeys,
+ int *breakCode,
+ FarMenuItem *items,
+ unsigned numItems);
+ int Menu(
+ unsigned int flags,
+ const char *title,
+ const char *helpTopic,
+ FarMenuItem *items,
+ unsigned numItems);
+
+ int Menu(
+ unsigned int flags,
+ const char *title,
+ const char *helpTopic,
+ const AStringVector &items,
+ int selectedItem);
+
+ int Editor(const char *fileName, const char *title,
+ int X1, int Y1, int X2, int Y2, DWORD flags, int startLine, int startChar)
+ { return m_Data.Editor(const_cast<char *>(fileName), const_cast<char *>(title), X1, Y1, X2, Y2,
+ flags, startLine, startChar); }
+ int Editor(const char *fileName)
+ { return Editor(fileName, NULL, 0, 0, -1, -1, 0, -1, -1); }
+
+ int Viewer(const char *fileName, const char *title,
+ int X1, int Y1, int X2, int Y2, DWORD flags)
+ { return m_Data.Viewer(const_cast<char *>(fileName), const_cast<char *>(title), X1, Y1, X2, Y2, flags); }
+ int Viewer(const char *fileName)
+ { return Viewer(fileName, NULL, 0, 0, -1, -1, VF_NONMODAL); }
+
+};
+
+class CScreenRestorer
+{
+ bool m_Saved;
+ HANDLE m_HANDLE;
+public:
+ CScreenRestorer(): m_Saved(false) {}
+ ~CScreenRestorer();
+ void Save();
+ void Restore();
+};
+
+
+extern CStartupInfo g_StartupInfo;
+
+
+int PrintErrorMessage(const char *message, unsigned code);
+int PrintErrorMessage(const char *message, const char *text);
+int PrintErrorMessage(const char *message, const wchar_t *name, unsigned maxLen = 70);
+
+#define MY_TRY_BEGIN try {
+
+#define MY_TRY_END1(x) }\
+ catch(unsigned n) { PrintErrorMessage(x, n); return; }\
+ catch(const CSysString &s) { PrintErrorMessage(x, s); return; }\
+ catch(const char *s) { PrintErrorMessage(x, s); return; }\
+ catch(...) { g_StartupInfo.ShowErrorMessage(x); return; }
+
+#define MY_TRY_END2(x, y) }\
+ catch(unsigned n) { PrintErrorMessage(x, n); return y; }\
+ catch(const AString &s) { PrintErrorMessage(x, s); return y; }\
+ catch(const char *s) { PrintErrorMessage(x, s); return y; }\
+ catch(const UString &s) { PrintErrorMessage(x, s); return y; }\
+ catch(const wchar_t *s) { PrintErrorMessage(x, s); return y; }\
+ catch(...) { g_StartupInfo.ShowErrorMessage(x); return y; }
+
+
+int ShowSysErrorMessage(DWORD errorCode);
+int ShowSysErrorMessage(DWORD errorCode, const wchar_t *name);
+int ShowLastErrorMessage();
+
+inline int ShowSysErrorMessage(HRESULT errorCode)
+ { return ShowSysErrorMessage((DWORD)errorCode); }
+inline int ShowSysErrorMessage(HRESULT errorCode, const wchar_t *name)
+ { return ShowSysErrorMessage((DWORD)errorCode, name); }
+
+bool WasEscPressed();
+
+void ReduceString(UString &s, unsigned size);
+
+}
+
+#endif
diff --git a/CPP/7zip/UI/Far/Messages.h b/CPP/7zip/UI/Far/Messages.h
new file mode 100644
index 0000000..f6b20a3
--- /dev/null
+++ b/CPP/7zip/UI/Far/Messages.h
@@ -0,0 +1,136 @@
+// Far/Messages.h
+
+#ifndef ZIP7_INC_FAR_MESSAGES_H
+#define ZIP7_INC_FAR_MESSAGES_H
+
+#include "../../PropID.h"
+
+namespace NMessageID {
+
+const unsigned k_Last_PropId_supported_by_plugin = kpidDevMinor;
+
+enum EEnum
+{
+ kOk,
+ kCancel,
+
+ kWarning,
+ kError,
+
+ kArchiveType,
+
+ kProperties,
+
+ kYes,
+ kNo,
+
+ kGetPasswordTitle,
+ kEnterPasswordForFile,
+
+ kExtractTitle,
+ kExtractTo,
+
+ kExtractPathMode,
+ kExtractPathFull,
+ kExtractPathCurrent,
+ kExtractPathNo,
+
+ kExtractOwerwriteMode,
+ kExtractOwerwriteAsk,
+ kExtractOwerwritePrompt,
+ kExtractOwerwriteSkip,
+ kExtractOwerwriteAutoRename,
+ kExtractOwerwriteAutoRenameExisting,
+
+ kExtractFilesMode,
+ kExtractFilesSelected,
+ kExtractFilesAll,
+
+ kExtractPassword,
+
+ kExtractExtract,
+ kExtractCancel,
+
+ kExtractCanNotOpenOutputFile,
+
+ kExtractUnsupportedMethod,
+ kExtractCRCFailed,
+ kExtractDataError,
+ kExtractCRCFailedEncrypted,
+ kExtractDataErrorEncrypted,
+
+ kOverwriteTitle,
+ kOverwriteMessage1,
+ kOverwriteMessageWouldYouLike,
+ kOverwriteMessageWithtTisOne,
+
+ kOverwriteBytes,
+ kOverwriteModifiedOn,
+
+ kOverwriteYes,
+ kOverwriteYesToAll,
+ kOverwriteNo,
+ kOverwriteNoToAll,
+ kOverwriteAutoRename,
+ kOverwriteCancel,
+
+ kUpdateNotSupportedForThisArchive,
+
+ kDeleteTitle,
+ kDeleteFile,
+ kDeleteFiles,
+ kDeleteNumberOfFiles,
+ kDeleteDelete,
+ kDeleteCancel,
+
+ kUpdateTitle,
+ kUpdateAddToArchive,
+
+ kUpdateMethod,
+ kUpdateMethod_Store,
+ kUpdateMethod_Fastest,
+ kUpdateMethod_Fast,
+ kUpdateMethod_Normal,
+ kUpdateMethod_Maximum,
+ kUpdateMethod_Ultra,
+
+ kUpdateMode,
+ kUpdateMode_Add,
+ kUpdateMode_Update,
+ kUpdateMode_Fresh,
+ kUpdateMode_Sync,
+
+ kUpdateAdd,
+ kUpdateSelectArchiver,
+
+ kUpdateSelectArchiverMenuTitle,
+
+ // kArcReadFiles,
+
+ kWaitTitle,
+
+ kReading,
+ kExtracting,
+ kDeleting,
+ kUpdating,
+
+ // kReadingList,
+
+ kMoveIsNotSupported,
+
+ kOpenArchiveMenuString,
+ kCreateArchiveMenuString,
+
+ kConfigTitle,
+
+ kConfigPluginEnabled,
+
+ // ---------- IDs for Properies (kpid*) ----------
+ kNoProperty,
+ k_Last_MessageID_for_Property = kNoProperty + k_Last_PropId_supported_by_plugin
+ // ----------
+};
+
+}
+
+#endif
diff --git a/CPP/7zip/UI/Far/OverwriteDialogFar.cpp b/CPP/7zip/UI/Far/OverwriteDialogFar.cpp
new file mode 100644
index 0000000..a45d2b2
--- /dev/null
+++ b/CPP/7zip/UI/Far/OverwriteDialogFar.cpp
@@ -0,0 +1,145 @@
+// OverwriteDialogFar.cpp
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/IntToString.h"
+
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/PropVariantConv.h"
+
+#include "FarUtils.h"
+#include "Messages.h"
+
+#include "OverwriteDialogFar.h"
+
+using namespace NWindows;
+using namespace NFar;
+
+namespace NOverwriteDialog {
+
+struct CFileInfoStrings
+{
+ AString Size;
+ AString Time;
+};
+
+static void SetFileInfoStrings(const CFileInfo &fileInfo,
+ CFileInfoStrings &fileInfoStrings)
+{
+ char buffer[256];
+
+ if (fileInfo.SizeIsDefined)
+ {
+ ConvertUInt64ToString(fileInfo.Size, buffer);
+ fileInfoStrings.Size = buffer;
+ fileInfoStrings.Size.Add_Space();
+ fileInfoStrings.Size += g_StartupInfo.GetMsgString(NMessageID::kOverwriteBytes);
+ }
+ else
+ {
+ fileInfoStrings.Size = "";
+ }
+
+ fileInfoStrings.Time.Empty();
+ if (fileInfo.TimeIsDefined)
+ {
+ char timeString[32];
+ ConvertUtcFileTimeToString(fileInfo.Time, timeString);
+ fileInfoStrings.Time = g_StartupInfo.GetMsgString(NMessageID::kOverwriteModifiedOn);
+ fileInfoStrings.Time.Add_Space();
+ fileInfoStrings.Time += timeString;
+ }
+}
+
+static void ReduceString2(UString &s, unsigned size)
+{
+ if (!s.IsEmpty() && s.Back() == ' ')
+ {
+ // s += (wchar_t)(0x2423);
+ s.InsertAtFront(L'\"');
+ s += L'\"';
+ }
+ ReduceString(s, size);
+}
+
+NResult::EEnum Execute(const CFileInfo &oldFileInfo, const CFileInfo &newFileInfo)
+{
+ const int kYSize = 22;
+ const int kXSize = 76;
+
+ CFileInfoStrings oldFileInfoStrings;
+ CFileInfoStrings newFileInfoStrings;
+
+ SetFileInfoStrings(oldFileInfo, oldFileInfoStrings);
+ SetFileInfoStrings(newFileInfo, newFileInfoStrings);
+
+ const UString &oldName2 = oldFileInfo.Name;
+ const UString &newName2 = newFileInfo.Name;
+
+ int slashPos = oldName2.ReverseFind_PathSepar();
+ UString pref1 = oldName2.Left(slashPos + 1);
+ UString name1 = oldName2.Ptr(slashPos + 1);
+
+ slashPos = newName2.ReverseFind_PathSepar();
+ UString pref2 = newName2.Left(slashPos + 1);
+ UString name2 = newName2.Ptr(slashPos + 1);
+
+ const unsigned kNameOffset = 2;
+ {
+ const unsigned maxNameLen = kXSize - 9 - 2;
+ ReduceString(pref1, maxNameLen);
+ ReduceString(pref2, maxNameLen);
+ ReduceString2(name1, maxNameLen - kNameOffset);
+ ReduceString2(name2, maxNameLen - kNameOffset);
+ }
+
+ const AString pref1A (UnicodeStringToMultiByte(pref1, CP_OEMCP));
+ const AString pref2A (UnicodeStringToMultiByte(pref2, CP_OEMCP));
+ const AString name1A (UnicodeStringToMultiByte(name1, CP_OEMCP));
+ const AString name2A (UnicodeStringToMultiByte(name2, CP_OEMCP));
+
+ const struct CInitDialogItem initItems[]={
+ { DI_DOUBLEBOX, 3, 1, kXSize - 4, kYSize - 2, false, false, 0, false, NMessageID::kOverwriteTitle, NULL, NULL },
+ { DI_TEXT, 5, 2, 0, 0, false, false, 0, false, NMessageID::kOverwriteMessage1, NULL, NULL },
+
+ { DI_TEXT, 3, 3, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL },
+
+ { DI_TEXT, 5, 4, 0, 0, false, false, 0, false, NMessageID::kOverwriteMessageWouldYouLike, NULL, NULL },
+
+ { DI_TEXT, 7, 6, 0, 0, false, false, 0, false, -1, pref1A, NULL },
+ { DI_TEXT, 7 + kNameOffset, 7, 0, 0, false, false, 0, false, -1, name1A, NULL },
+ { DI_TEXT, 7, 8, 0, 0, false, false, 0, false, -1, oldFileInfoStrings.Size, NULL },
+ { DI_TEXT, 7, 9, 0, 0, false, false, 0, false, -1, oldFileInfoStrings.Time, NULL },
+
+ { DI_TEXT, 5, 11, 0, 0, false, false, 0, false, NMessageID::kOverwriteMessageWithtTisOne, NULL, NULL },
+
+ { DI_TEXT, 7, 13, 0, 0, false, false, 0, false, -1, pref2A, NULL },
+ { DI_TEXT, 7 + kNameOffset, 14, 0, 0, false, false, 0, false, -1, name2A, NULL },
+ { DI_TEXT, 7, 15, 0, 0, false, false, 0, false, -1, newFileInfoStrings.Size, NULL },
+ { DI_TEXT, 7, 16, 0, 0, false, false, 0, false, -1, newFileInfoStrings.Time, NULL },
+
+ { DI_TEXT, 3, kYSize - 5, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL },
+
+ { DI_BUTTON, 0, kYSize - 4, 0, 0, true, false, DIF_CENTERGROUP, true, NMessageID::kOverwriteYes, NULL, NULL },
+ { DI_BUTTON, 0, kYSize - 4, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kOverwriteYesToAll, NULL, NULL },
+ { DI_BUTTON, 0, kYSize - 4, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kOverwriteNo, NULL, NULL },
+ { DI_BUTTON, 0, kYSize - 4, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kOverwriteNoToAll, NULL, NULL },
+ { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kOverwriteAutoRename, NULL, NULL },
+ { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kOverwriteCancel, NULL, NULL }
+ };
+
+ const int kNumDialogItems = Z7_ARRAY_SIZE(initItems);
+ FarDialogItem aDialogItems[kNumDialogItems];
+ g_StartupInfo.InitDialogItems(initItems, aDialogItems, kNumDialogItems);
+ const int anAskCode = g_StartupInfo.ShowDialog(kXSize, kYSize,
+ NULL, aDialogItems, kNumDialogItems);
+ const int kButtonStartPos = kNumDialogItems - 6;
+ if (anAskCode >= kButtonStartPos && anAskCode < kNumDialogItems)
+ return NResult::EEnum(anAskCode - kButtonStartPos);
+ return NResult::kCancel;
+}
+
+}
diff --git a/CPP/7zip/UI/Far/OverwriteDialogFar.h b/CPP/7zip/UI/Far/OverwriteDialogFar.h
new file mode 100644
index 0000000..bc6e92b
--- /dev/null
+++ b/CPP/7zip/UI/Far/OverwriteDialogFar.h
@@ -0,0 +1,37 @@
+// OverwriteDialogFar.h
+
+#ifndef ZIP7_INC_OVERWRITE_DIALOG_FAR_H
+#define ZIP7_INC_OVERWRITE_DIALOG_FAR_H
+
+#include "../../../Common/MyString.h"
+#include "../../../Common/MyTypes.h"
+
+namespace NOverwriteDialog {
+
+struct CFileInfo
+{
+ bool SizeIsDefined;
+ bool TimeIsDefined;
+ UInt64 Size;
+ FILETIME Time;
+ UString Name;
+};
+
+namespace NResult
+{
+ enum EEnum
+ {
+ kYes,
+ kYesToAll,
+ kNo,
+ kNoToAll,
+ kAutoRename,
+ kCancel
+ };
+}
+
+NResult::EEnum Execute(const CFileInfo &oldFileInfo, const CFileInfo &newFileInfo);
+
+}
+
+#endif
diff --git a/CPP/7zip/UI/Far/Plugin.cpp b/CPP/7zip/UI/Far/Plugin.cpp
new file mode 100644
index 0000000..fe6fcce
--- /dev/null
+++ b/CPP/7zip/UI/Far/Plugin.cpp
@@ -0,0 +1,939 @@
+// Plugin.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/PropVariantConv.h"
+
+#include "../Common/PropIDUtils.h"
+
+#include "FarUtils.h"
+#include "Messages.h"
+#include "Plugin.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+using namespace NFar;
+
+// This function is used by CAgentFolder
+int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2);
+int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2)
+{
+ return MyStringCompareNoCase(s1, s2);
+}
+
+CPlugin::CPlugin(const FString &fileName, CAgent *agent, UString archiveTypeName):
+ _agent(agent),
+ m_FileName(fileName),
+ _archiveTypeName(archiveTypeName),
+ PasswordIsDefined(false)
+{
+ m_ArchiveHandler = agent;
+ if (!m_FileInfo.Find(m_FileName))
+ throw "error";
+ m_ArchiveHandler->BindToRootFolder(&_folder);
+}
+
+CPlugin::~CPlugin() {}
+
+static void MyGetFileTime(IFolderFolder *folder, UInt32 itemIndex,
+ PROPID propID, FILETIME &fileTime)
+{
+ NCOM::CPropVariant prop;
+ if (folder->GetProperty(itemIndex, propID, &prop) != S_OK)
+ throw 271932;
+ if (prop.vt == VT_EMPTY)
+ {
+ fileTime.dwHighDateTime = 0;
+ fileTime.dwLowDateTime = 0;
+ }
+ else
+ {
+ if (prop.vt != VT_FILETIME)
+ throw 4191730;
+ fileTime = prop.filetime;
+ }
+}
+
+#define kDotsReplaceString "[[..]]"
+#define kDotsReplaceStringU L"[[..]]"
+
+static void CopyStrLimited(char *dest, const AString &src, unsigned len)
+{
+ len--;
+ if (src.Len() < len)
+ len = src.Len();
+ memcpy(dest, src, sizeof(dest[0]) * len);
+ dest[len] = 0;
+}
+
+#define COPY_STR_LIMITED(dest, src) CopyStrLimited(dest, src, Z7_ARRAY_SIZE(dest))
+
+void CPlugin::ReadPluginPanelItem(PluginPanelItem &panelItem, UInt32 itemIndex)
+{
+ NCOM::CPropVariant prop;
+ if (_folder->GetProperty(itemIndex, kpidName, &prop) != S_OK)
+ throw 271932;
+
+ if (prop.vt != VT_BSTR)
+ throw 272340;
+
+ AString oemString (UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP));
+ if (oemString == "..")
+ oemString = kDotsReplaceString;
+
+ COPY_STR_LIMITED(panelItem.FindData.cFileName, oemString);
+ panelItem.FindData.cAlternateFileName[0] = 0;
+
+ if (_folder->GetProperty(itemIndex, kpidAttrib, &prop) != S_OK)
+ throw 271932;
+ if (prop.vt == VT_UI4)
+ panelItem.FindData.dwFileAttributes = prop.ulVal;
+ else if (prop.vt == VT_EMPTY)
+ panelItem.FindData.dwFileAttributes = m_FileInfo.Attrib;
+ else
+ throw 21631;
+
+ if (_folder->GetProperty(itemIndex, kpidIsDir, &prop) != S_OK)
+ throw 271932;
+ if (prop.vt == VT_BOOL)
+ {
+ if (VARIANT_BOOLToBool(prop.boolVal))
+ panelItem.FindData.dwFileAttributes |= FILE_ATTRIBUTE_DIRECTORY;
+ }
+ else if (prop.vt != VT_EMPTY)
+ throw 21632;
+
+ if (_folder->GetProperty(itemIndex, kpidSize, &prop) != S_OK)
+ throw 271932;
+ UInt64 length = 0;
+ ConvertPropVariantToUInt64(prop, length);
+ panelItem.FindData.nFileSizeLow = (UInt32)length;
+ panelItem.FindData.nFileSizeHigh = (UInt32)(length >> 32);
+
+ MyGetFileTime(_folder, itemIndex, kpidCTime, panelItem.FindData.ftCreationTime);
+ MyGetFileTime(_folder, itemIndex, kpidATime, panelItem.FindData.ftLastAccessTime);
+ MyGetFileTime(_folder, itemIndex, kpidMTime, panelItem.FindData.ftLastWriteTime);
+
+ if (panelItem.FindData.ftLastWriteTime.dwHighDateTime == 0 &&
+ panelItem.FindData.ftLastWriteTime.dwLowDateTime == 0)
+ panelItem.FindData.ftLastWriteTime = m_FileInfo.MTime;
+
+ if (_folder->GetProperty(itemIndex, kpidPackSize, &prop) != S_OK)
+ throw 271932;
+ length = 0;
+ ConvertPropVariantToUInt64(prop, length);
+ panelItem.PackSize = UInt32(length);
+ panelItem.PackSizeHigh = UInt32(length >> 32);
+
+ panelItem.Flags = 0;
+ panelItem.NumberOfLinks = 0;
+
+ panelItem.Description = NULL;
+ panelItem.Owner = NULL;
+ panelItem.CustomColumnData = NULL;
+ panelItem.CustomColumnNumber = 0;
+
+ panelItem.CRC32 = 0;
+ panelItem.Reserved[0] = 0;
+ panelItem.Reserved[1] = 0;
+}
+
+int CPlugin::GetFindData(PluginPanelItem **panelItems, int *itemsNumber, int opMode)
+{
+ // CScreenRestorer screenRestorer;
+ if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0)
+ {
+ /*
+ screenRestorer.Save();
+ const char *msgItems[]=
+ {
+ g_StartupInfo.GetMsgString(NMessageID::kWaitTitle),
+ g_StartupInfo.GetMsgString(NMessageID::kReadingList)
+ };
+ g_StartupInfo.ShowMessage(0, NULL, msgItems, Z7_ARRAY_SIZE(msgItems), 0);
+ */
+ }
+
+ UInt32 numItems;
+ _folder->GetNumberOfItems(&numItems);
+ *panelItems = new PluginPanelItem[numItems];
+ try
+ {
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ PluginPanelItem &panelItem = (*panelItems)[i];
+ ReadPluginPanelItem(panelItem, i);
+ panelItem.UserData = i;
+ }
+ }
+ catch(...)
+ {
+ delete [](*panelItems);
+ throw;
+ }
+ *itemsNumber = (int)numItems;
+ return(TRUE);
+}
+
+void CPlugin::FreeFindData(struct PluginPanelItem *panelItems, int itemsNumber)
+{
+ for (int i = 0; i < itemsNumber; i++)
+ if (panelItems[i].Description != NULL)
+ delete []panelItems[i].Description;
+ delete []panelItems;
+}
+
+void CPlugin::EnterToDirectory(const UString &dirName)
+{
+ CMyComPtr<IFolderFolder> newFolder;
+ UString s = dirName;
+ if (dirName == kDotsReplaceStringU)
+ s = "..";
+ _folder->BindToFolder(s, &newFolder);
+ if (!newFolder)
+ {
+ if (dirName.IsEmpty())
+ return;
+ else
+ throw 40325;
+ }
+ _folder = newFolder;
+}
+
+int CPlugin::SetDirectory(const char *aszDir, int /* opMode */)
+{
+ UString path = MultiByteToUnicodeString(aszDir, CP_OEMCP);
+ if (path == WSTRING_PATH_SEPARATOR)
+ {
+ _folder.Release();
+ m_ArchiveHandler->BindToRootFolder(&_folder);
+ }
+ else if (path == L"..")
+ {
+ CMyComPtr<IFolderFolder> newFolder;
+ _folder->BindToParentFolder(&newFolder);
+ if (!newFolder)
+ throw 40312;
+ _folder = newFolder;
+ }
+ else if (path.IsEmpty())
+ EnterToDirectory(path);
+ else
+ {
+ if (path[0] == WCHAR_PATH_SEPARATOR)
+ {
+ _folder.Release();
+ m_ArchiveHandler->BindToRootFolder(&_folder);
+ path.DeleteFrontal(1);
+ }
+ UStringVector pathParts;
+ SplitPathToParts(path, pathParts);
+ FOR_VECTOR (i, pathParts)
+ EnterToDirectory(pathParts[i]);
+ }
+ SetCurrentDirVar();
+ return TRUE;
+}
+
+void CPlugin::GetPathParts(UStringVector &pathParts)
+{
+ pathParts.Clear();
+ CMyComPtr<IFolderFolder> folderItem = _folder;
+ for (;;)
+ {
+ CMyComPtr<IFolderFolder> newFolder;
+ folderItem->BindToParentFolder(&newFolder);
+ if (!newFolder)
+ break;
+ NCOM::CPropVariant prop;
+ if (folderItem->GetFolderProperty(kpidName, &prop) == S_OK)
+ if (prop.vt == VT_BSTR)
+ pathParts.Insert(0, (const wchar_t *)prop.bstrVal);
+ folderItem = newFolder;
+ }
+}
+
+void CPlugin::SetCurrentDirVar()
+{
+ m_CurrentDir.Empty();
+
+ /*
+ // kpidPath path has tail slash, but we don't need it for compatibility with default FAR style
+ NCOM::CPropVariant prop;
+ if (_folder->GetFolderProperty(kpidPath, &prop) == S_OK)
+ if (prop.vt == VT_BSTR)
+ {
+ m_CurrentDir = (wchar_t *)prop.bstrVal;
+ // if (!m_CurrentDir.IsEmpty())
+ }
+ m_CurrentDir.InsertAtFront(WCHAR_PATH_SEPARATOR);
+ */
+
+ UStringVector pathParts;
+ GetPathParts(pathParts);
+ FOR_VECTOR (i, pathParts)
+ {
+ m_CurrentDir.Add_PathSepar();
+ m_CurrentDir += pathParts[i];
+ }
+}
+
+static const char * const kPluginFormatName = "7-ZIP";
+
+
+static int FindPropNameID(PROPID propID)
+{
+ if (propID > NMessageID::k_Last_PropId_supported_by_plugin)
+ return -1;
+ return NMessageID::kNoProperty + (int)propID;
+}
+
+/*
+struct CPropertyIDInfo
+{
+ PROPID PropID;
+ const char *FarID;
+ int Width;
+ // char CharID;
+};
+
+static CPropertyIDInfo kPropertyIDInfos[] =
+{
+ { kpidName, "N", 0},
+ { kpidSize, "S", 8},
+ { kpidPackSize, "P", 8},
+ { kpidAttrib, "A", 0},
+ { kpidCTime, "DC", 14},
+ { kpidATime, "DA", 14},
+ { kpidMTime, "DM", 14},
+
+ { kpidSolid, NULL, 0, 'S'},
+ { kpidEncrypted, NULL, 0, 'P'},
+
+ { kpidDictionarySize, IDS_PROPERTY_DICTIONARY_SIZE },
+ { kpidSplitBefore, NULL, 'B'},
+ { kpidSplitAfter, NULL, 'A'},
+ { kpidComment, NULL, 'C'},
+ { kpidCRC, IDS_PROPERTY_CRC }
+ // { kpidType, L"Type" }
+};
+
+static const int kNumPropertyIDInfos = Z7_ARRAY_SIZE(kPropertyIDInfos);
+
+static int FindPropertyInfo(PROPID propID)
+{
+ for (int i = 0; i < kNumPropertyIDInfos; i++)
+ if (kPropertyIDInfos[i].PropID == propID)
+ return i;
+ return -1;
+}
+*/
+
+// char *g_Titles[] = { "a", "f", "v" };
+/*
+static void SmartAddToString(AString &destString, const char *srcString)
+{
+ if (!destString.IsEmpty())
+ destString += ',';
+ destString += srcString;
+}
+*/
+
+/*
+void CPlugin::AddColumn(PROPID propID)
+{
+ int index = FindPropertyInfo(propID);
+ if (index >= 0)
+ {
+ for (int i = 0; i < m_ProxyHandler->m_InternalProperties.Size(); i++)
+ {
+ const CArchiveItemProperty &aHandlerProperty = m_ProxyHandler->m_InternalProperties[i];
+ if (aHandlerProperty.ID == propID)
+ break;
+ }
+ if (i == m_ProxyHandler->m_InternalProperties.Size())
+ return;
+
+ const CPropertyIDInfo &propertyIDInfo = kPropertyIDInfos[index];
+ SmartAddToString(PanelModeColumnTypes, propertyIDInfo.FarID);
+ char tmp[32];
+ itoa(propertyIDInfo.Width, tmp, 10);
+ SmartAddToString(PanelModeColumnWidths, tmp);
+ return;
+ }
+}
+*/
+
+static AString GetNameOfProp(PROPID propID, const wchar_t *name)
+{
+ int farID = FindPropNameID(propID);
+ if (farID >= 0)
+ return (AString)g_StartupInfo.GetMsgString(farID);
+ if (name)
+ return UnicodeStringToMultiByte(name, CP_OEMCP);
+ char s[16];
+ ConvertUInt32ToString(propID, s);
+ return (AString)s;
+}
+
+static AString GetNameOfProp2(PROPID propID, const wchar_t *name)
+{
+ AString s (GetNameOfProp(propID, name));
+ if (s.Len() > (kInfoPanelLineSize - 1))
+ s.DeleteFrom(kInfoPanelLineSize - 1);
+ return s;
+}
+
+static AString ConvertSizeToString(UInt64 value)
+{
+ char s[32];
+ ConvertUInt64ToString(value, s);
+ unsigned i = MyStringLen(s);
+ unsigned pos = Z7_ARRAY_SIZE(s);
+ s[--pos] = 0;
+ while (i > 3)
+ {
+ s[--pos] = s[--i];
+ s[--pos] = s[--i];
+ s[--pos] = s[--i];
+ s[--pos] = ' ';
+ }
+ while (i > 0)
+ s[--pos] = s[--i];
+ return (AString)(s + pos);
+}
+
+static AString PropToString(const NCOM::CPropVariant &prop, PROPID propID)
+{
+ if (prop.vt == VT_BSTR)
+ {
+ AString s (UnicodeStringToMultiByte(prop.bstrVal, CP_OEMCP));
+ s.Replace((char)0xA, ' ');
+ s.Replace((char)0xD, ' ');
+ return s;
+ }
+ if (prop.vt == VT_BOOL)
+ {
+ int messageID = VARIANT_BOOLToBool(prop.boolVal) ?
+ NMessageID::kYes : NMessageID::kNo;
+ return (AString)g_StartupInfo.GetMsgString(messageID);
+ }
+ if (prop.vt != VT_EMPTY)
+ {
+ if ((prop.vt == VT_UI8 || prop.vt == VT_UI4) && (
+ propID == kpidSize ||
+ propID == kpidPackSize ||
+ propID == kpidNumSubDirs ||
+ propID == kpidNumSubFiles ||
+ propID == kpidNumBlocks ||
+ propID == kpidPhySize ||
+ propID == kpidHeadersSize ||
+ propID == kpidClusterSize ||
+ propID == kpidUnpackSize
+ ))
+ {
+ UInt64 v = 0;
+ ConvertPropVariantToUInt64(prop, v);
+ return ConvertSizeToString(v);
+ }
+ {
+ char sz[64];
+ ConvertPropertyToShortString2(sz, prop, propID);
+ return (AString)sz;
+ }
+ }
+ return AString();
+}
+
+static AString PropToString2(const NCOM::CPropVariant &prop, PROPID propID)
+{
+ AString s (PropToString(prop, propID));
+ if (s.Len() > (kInfoPanelLineSize - 1))
+ s.DeleteFrom(kInfoPanelLineSize - 1);
+ return s;
+}
+
+static void AddPropertyString(InfoPanelLine *lines, unsigned &numItems, PROPID propID, const wchar_t *name,
+ const NCOM::CPropVariant &prop)
+{
+ if (prop.vt != VT_EMPTY)
+ {
+ AString val (PropToString2(prop, propID));
+ if (!val.IsEmpty())
+ {
+ InfoPanelLine &item = lines[numItems++];
+ COPY_STR_LIMITED(item.Text, GetNameOfProp2(propID, name));
+ COPY_STR_LIMITED(item.Data, val);
+ }
+ }
+}
+
+static void InsertSeparator(InfoPanelLine *lines, unsigned &numItems)
+{
+ if (numItems < kNumInfoLinesMax)
+ {
+ InfoPanelLine &item = lines[numItems++];
+ *item.Text = 0;
+ *item.Data = 0;
+ item.Separator = TRUE;
+ }
+}
+
+void CPlugin::GetOpenPluginInfo(struct OpenPluginInfo *info)
+{
+ info->StructSize = sizeof(*info);
+ info->Flags = OPIF_USEFILTER | OPIF_USESORTGROUPS | OPIF_USEHIGHLIGHTING |
+ OPIF_ADDDOTS | OPIF_COMPAREFATTIME;
+
+ COPY_STR_LIMITED(m_FileNameBuffer, UnicodeStringToMultiByte(fs2us(m_FileName), CP_OEMCP));
+ info->HostFile = m_FileNameBuffer; // test it it is not static
+
+ COPY_STR_LIMITED(m_CurrentDirBuffer, UnicodeStringToMultiByte(m_CurrentDir, CP_OEMCP));
+ info->CurDir = m_CurrentDirBuffer;
+
+ info->Format = kPluginFormatName;
+
+ {
+ UString name;
+ {
+ FString dirPrefix, fileName;
+ GetFullPathAndSplit(m_FileName, dirPrefix, fileName);
+ name = fs2us(fileName);
+ }
+
+ m_PannelTitle = ' ';
+ m_PannelTitle += _archiveTypeName;
+ m_PannelTitle += ':';
+ m_PannelTitle += name;
+ m_PannelTitle.Add_Space();
+ if (!m_CurrentDir.IsEmpty())
+ {
+ // m_PannelTitle += '\\';
+ m_PannelTitle += m_CurrentDir;
+ }
+
+ COPY_STR_LIMITED(m_PannelTitleBuffer, UnicodeStringToMultiByte(m_PannelTitle, CP_OEMCP));
+ info->PanelTitle = m_PannelTitleBuffer;
+
+ }
+
+ memset(m_InfoLines, 0, sizeof(m_InfoLines));
+ m_InfoLines[0].Text[0] = 0;
+ m_InfoLines[0].Separator = TRUE;
+
+ MyStringCopy(m_InfoLines[1].Text, g_StartupInfo.GetMsgString(NMessageID::kArchiveType));
+ MyStringCopy(m_InfoLines[1].Data, (const char *)UnicodeStringToMultiByte(_archiveTypeName, CP_OEMCP));
+
+ unsigned numItems = 2;
+
+ {
+ CMyComPtr<IFolderProperties> folderProperties;
+ _folder.QueryInterface(IID_IFolderProperties, &folderProperties);
+ if (folderProperties)
+ {
+ UInt32 numProps;
+ if (folderProperties->GetNumberOfFolderProperties(&numProps) == S_OK)
+ {
+ for (UInt32 i = 0; i < numProps && numItems < kNumInfoLinesMax; i++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE vt;
+ if (folderProperties->GetFolderPropertyInfo(i, &name, &propID, &vt) != S_OK)
+ continue;
+ NCOM::CPropVariant prop;
+ if (_folder->GetFolderProperty(propID, &prop) != S_OK || prop.vt == VT_EMPTY)
+ continue;
+
+ InfoPanelLine &item = m_InfoLines[numItems++];
+ COPY_STR_LIMITED(item.Text, GetNameOfProp2(propID, name));
+ COPY_STR_LIMITED(item.Data, PropToString2(prop, propID));
+ }
+ }
+ }
+ }
+
+ /*
+ if (numItems < kNumInfoLinesMax)
+ {
+ InsertSeparator(m_InfoLines, numItems);
+ }
+ */
+
+ {
+ CMyComPtr<IGetFolderArcProps> getFolderArcProps;
+ _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps);
+ if (getFolderArcProps)
+ {
+ CMyComPtr<IFolderArcProps> getProps;
+ getFolderArcProps->GetFolderArcProps(&getProps);
+ if (getProps)
+ {
+ UInt32 numLevels;
+ if (getProps->GetArcNumLevels(&numLevels) != S_OK)
+ numLevels = 0;
+ for (UInt32 level2 = 0; level2 < numLevels; level2++)
+ {
+ {
+ UInt32 level = numLevels - 1 - level2;
+ UInt32 numProps;
+ if (getProps->GetArcNumProps(level, &numProps) == S_OK)
+ {
+ InsertSeparator(m_InfoLines, numItems);
+ for (Int32 i = -3; i < (Int32)numProps && numItems < kNumInfoLinesMax; i++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE vt;
+ switch (i)
+ {
+ case -3: propID = kpidPath; break;
+ case -2: propID = kpidType; break;
+ case -1: propID = kpidError; break;
+ default:
+ if (getProps->GetArcPropInfo(level, (UInt32)i, &name, &propID, &vt) != S_OK)
+ continue;
+ }
+ NCOM::CPropVariant prop;
+ if (getProps->GetArcProp(level, propID, &prop) != S_OK)
+ continue;
+ AddPropertyString(m_InfoLines, numItems, propID, name, prop);
+ }
+ }
+ }
+ if (level2 != numLevels - 1)
+ {
+ UInt32 level = numLevels - 1 - level2;
+ UInt32 numProps;
+ if (getProps->GetArcNumProps2(level, &numProps) == S_OK)
+ {
+ InsertSeparator(m_InfoLines, numItems);
+ for (Int32 i = 0; i < (Int32)numProps && numItems < kNumInfoLinesMax; i++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE vt;
+ if (getProps->GetArcPropInfo2(level, (UInt32)i, &name, &propID, &vt) != S_OK)
+ continue;
+ NCOM::CPropVariant prop;
+ if (getProps->GetArcProp2(level, propID, &prop) != S_OK)
+ continue;
+ AddPropertyString(m_InfoLines, numItems, propID, name, prop);
+ }
+ }
+ }
+ }
+ }
+ }
+ }
+
+ //m_InfoLines[1].Separator = 0;
+
+ info->InfoLines = m_InfoLines;
+ info->InfoLinesNumber = (int)numItems;
+
+
+ info->DescrFiles = NULL;
+ info->DescrFilesNumber = 0;
+
+ PanelModeColumnTypes.Empty();
+ PanelModeColumnWidths.Empty();
+
+ /*
+ AddColumn(kpidName);
+ AddColumn(kpidSize);
+ AddColumn(kpidPackSize);
+ AddColumn(kpidMTime);
+ AddColumn(kpidCTime);
+ AddColumn(kpidATime);
+ AddColumn(kpidAttrib);
+
+ _panelMode.ColumnTypes = (char *)(const char *)PanelModeColumnTypes;
+ _panelMode.ColumnWidths = (char *)(const char *)PanelModeColumnWidths;
+ _panelMode.ColumnTitles = NULL;
+ _panelMode.FullScreen = TRUE;
+ _panelMode.DetailedStatus = FALSE;
+ _panelMode.AlignExtensions = FALSE;
+ _panelMode.CaseConversion = FALSE;
+ _panelMode.StatusColumnTypes = "N";
+ _panelMode.StatusColumnWidths = "0";
+ _panelMode.Reserved[0] = 0;
+ _panelMode.Reserved[1] = 0;
+
+ info->PanelModesArray = &_panelMode;
+ info->PanelModesNumber = 1;
+ */
+
+ info->PanelModesArray = NULL;
+ info->PanelModesNumber = 0;
+
+ info->StartPanelMode = 0;
+ info->StartSortMode = 0;
+ info->KeyBar = NULL;
+ info->ShortcutData = NULL;
+}
+
+struct CArchiveItemProperty
+{
+ AString Name;
+ PROPID ID;
+ VARTYPE Type;
+};
+
+static inline char GetHex_Upper(unsigned v)
+{
+ return (char)((v < 10) ? ('0' + v) : ('A' + (v - 10)));
+}
+
+static inline char GetHex_Lower(unsigned v)
+{
+ return (char)((v < 10) ? ('0' + v) : ('a' + (v - 10)));
+}
+
+HRESULT CPlugin::ShowAttributesWindow()
+{
+ PluginPanelItem pluginPanelItem;
+ if (!g_StartupInfo.ControlGetActivePanelCurrentItemInfo(pluginPanelItem))
+ return S_FALSE;
+ if (strcmp(pluginPanelItem.FindData.cFileName, "..") == 0 &&
+ NFind::NAttributes::IsDir(pluginPanelItem.FindData.dwFileAttributes))
+ return S_FALSE;
+ const UInt32 itemIndex = (UInt32)pluginPanelItem.UserData;
+
+ CObjectVector<CArchiveItemProperty> properties;
+ UInt32 numProps;
+ RINOK(_folder->GetNumberOfProperties(&numProps))
+ unsigned i;
+ for (i = 0; i < numProps; i++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE vt;
+ RINOK(_folder->GetPropertyInfo(i, &name, &propID, &vt))
+ CArchiveItemProperty prop;
+ prop.Type = vt;
+ prop.ID = propID;
+ if (prop.ID == kpidPath)
+ prop.ID = kpidName;
+ prop.Name = GetNameOfProp(propID, name);
+ properties.Add(prop);
+ }
+
+ int size = 2;
+ CRecordVector<CInitDialogItem> initDialogItems;
+
+ int xSize = 70;
+ {
+ const CInitDialogItem idi =
+ { DI_DOUBLEBOX, 3, 1, xSize - 4, size - 2, false, false, 0, false, NMessageID::kProperties, NULL, NULL };
+ initDialogItems.Add(idi);
+ }
+
+ AStringVector values;
+
+ const int kStartY = 3;
+
+ for (i = 0; i < properties.Size(); i++)
+ {
+ const CArchiveItemProperty &property = properties[i];
+
+ const int startY = kStartY + (int)values.Size();
+
+ {
+ CInitDialogItem idi =
+ { DI_TEXT, 5, startY, 0, 0, false, false, 0, false, 0, NULL, NULL };
+ idi.DataMessageId = FindPropNameID(property.ID);
+ if (idi.DataMessageId < 0)
+ idi.DataString = property.Name;
+ initDialogItems.Add(idi);
+ }
+
+ NCOM::CPropVariant prop;
+ RINOK(_folder->GetProperty(itemIndex, property.ID, &prop))
+ values.Add(PropToString(prop, property.ID));
+
+ {
+ const CInitDialogItem idi =
+ { DI_TEXT, 30, startY, 0, 0, false, false, 0, false, -1, NULL, NULL };
+ initDialogItems.Add(idi);
+ }
+ }
+
+ CMyComPtr<IArchiveGetRawProps> _folderRawProps;
+ _folder.QueryInterface(IID_IArchiveGetRawProps, &_folderRawProps);
+
+ CObjectVector<CArchiveItemProperty> properties2;
+
+ if (_folderRawProps)
+ {
+ _folderRawProps->GetNumRawProps(&numProps);
+
+ for (i = 0; i < numProps; i++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ if (_folderRawProps->GetRawPropInfo(i, &name, &propID) != S_OK)
+ continue;
+ CArchiveItemProperty prop;
+ prop.Type = VT_EMPTY;
+ prop.ID = propID;
+ if (prop.ID == kpidPath)
+ prop.ID = kpidName;
+ prop.Name = GetNameOfProp(propID, name);
+ properties2.Add(prop);
+ }
+
+ for (i = 0; i < properties2.Size(); i++)
+ {
+ const CArchiveItemProperty &property = properties2[i];
+ CMyComBSTR name;
+
+ const void *data;
+ UInt32 dataSize;
+ UInt32 propType;
+ if (_folderRawProps->GetRawProp(itemIndex, property.ID, &data, &dataSize, &propType) != S_OK)
+ continue;
+
+ if (dataSize != 0)
+ {
+ AString s;
+ if (property.ID == kpidNtSecure)
+ ConvertNtSecureToString((const Byte *)data, dataSize, s);
+ else
+ {
+ const UInt32 kMaxDataSize = 64;
+ if (dataSize > kMaxDataSize)
+ {
+ s += "data:";
+ s.Add_UInt32(dataSize);
+ }
+ else
+ {
+ const bool needUpper = (dataSize <= 8)
+ && (property.ID == kpidCRC || property.ID == kpidChecksum);
+ for (UInt32 k = 0; k < dataSize; k++)
+ {
+ unsigned b = ((const Byte *)data)[k];
+ if (needUpper)
+ {
+ s += GetHex_Upper((b >> 4) & 0xF);
+ s += GetHex_Upper(b & 0xF);
+ }
+ else
+ {
+ s += GetHex_Lower((b >> 4) & 0xF);
+ s += GetHex_Lower(b & 0xF);
+ }
+ }
+ }
+ }
+
+ const int startY = kStartY + (int)values.Size();
+
+ {
+ CInitDialogItem idi =
+ { DI_TEXT, 5, startY, 0, 0, false, false, 0, false, 0, NULL, NULL };
+ idi.DataMessageId = FindPropNameID(property.ID);
+ if (idi.DataMessageId < 0)
+ idi.DataString = property.Name;
+ initDialogItems.Add(idi);
+ }
+
+ values.Add(s);
+
+ {
+ const CInitDialogItem idi =
+ { DI_TEXT, 30, startY, 0, 0, false, false, 0, false, -1, NULL, NULL };
+ initDialogItems.Add(idi);
+ }
+ }
+ }
+ }
+
+ const unsigned numLines = values.Size();
+ for (i = 0; i < numLines; i++)
+ {
+ CInitDialogItem &idi = initDialogItems[1 + i * 2 + 1];
+ idi.DataString = values[i];
+ }
+
+ const unsigned numDialogItems = initDialogItems.Size();
+
+ CObjArray<FarDialogItem> dialogItems(numDialogItems);
+ g_StartupInfo.InitDialogItems(&initDialogItems.Front(), dialogItems, numDialogItems);
+
+ unsigned maxLen = 0;
+
+ for (i = 0; i < numLines; i++)
+ {
+ FarDialogItem &dialogItem = dialogItems[1 + i * 2];
+ unsigned len = (unsigned)strlen(dialogItem.Data);
+ if (len > maxLen)
+ maxLen = len;
+ }
+
+ unsigned maxLen2 = 0;
+ const unsigned kSpace = 10;
+
+ for (i = 0; i < numLines; i++)
+ {
+ FarDialogItem &dialogItem = dialogItems[1 + i * 2 + 1];
+ const unsigned len = (unsigned)strlen(dialogItem.Data);
+ if (len > maxLen2)
+ maxLen2 = len;
+ dialogItem.X1 = (int)(maxLen + kSpace);
+ }
+
+ size = (int)numLines + 6;
+ xSize = (int)(maxLen + kSpace + maxLen2 + 5);
+ FarDialogItem &firstDialogItem = dialogItems[0];
+ firstDialogItem.Y2 = size - 2;
+ firstDialogItem.X2 = xSize - 4;
+
+ /* int askCode = */ g_StartupInfo.ShowDialog(xSize, size, NULL, dialogItems, numDialogItems);
+ return S_OK;
+}
+
+int CPlugin::ProcessKey(int key, unsigned int controlState)
+{
+ if (key == VK_F7 && controlState == 0)
+ {
+ CreateFolder();
+ return TRUE;
+ }
+
+ if (controlState == PKF_CONTROL && key == 'A')
+ {
+ HRESULT result = ShowAttributesWindow();
+ if (result == S_OK)
+ return TRUE;
+ if (result == S_FALSE)
+ return FALSE;
+ throw "Error";
+ }
+
+ if ((controlState & PKF_ALT) != 0 && key == VK_F6)
+ {
+ FString folderPath;
+ if (!GetOnlyDirPrefix(m_FileName, folderPath))
+ return FALSE;
+ PanelInfo panelInfo;
+ g_StartupInfo.ControlGetActivePanelInfo(panelInfo);
+ GetFilesReal(panelInfo.SelectedItems,
+ (unsigned)panelInfo.SelectedItemsNumber, FALSE,
+ UnicodeStringToMultiByte(fs2us(folderPath), CP_OEMCP), OPM_SILENT, true);
+ g_StartupInfo.Control(this, FCTL_UPDATEPANEL, NULL);
+ g_StartupInfo.Control(this, FCTL_REDRAWPANEL, NULL);
+ g_StartupInfo.Control(this, FCTL_UPDATEANOTHERPANEL, NULL);
+ g_StartupInfo.Control(this, FCTL_REDRAWANOTHERPANEL, NULL);
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/CPP/7zip/UI/Far/Plugin.h b/CPP/7zip/UI/Far/Plugin.h
new file mode 100644
index 0000000..00ccc81
--- /dev/null
+++ b/CPP/7zip/UI/Far/Plugin.h
@@ -0,0 +1,94 @@
+// 7zip/Far/Plugin.h
+
+#ifndef ZIP7_INC_7ZIP_FAR_PLUGIN_H
+#define ZIP7_INC_7ZIP_FAR_PLUGIN_H
+
+#include "../../../Common/MyCom.h"
+
+// #include "../../../Windows/COM.h"
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/PropVariant.h"
+
+#include "../Common/WorkDir.h"
+
+#include "../Agent/Agent.h"
+
+#include "FarUtils.h"
+
+const UInt32 kNumInfoLinesMax = 64;
+
+class CPlugin
+{
+ CAgent *_agent;
+ CMyComPtr<IInFolderArchive> m_ArchiveHandler;
+ CMyComPtr<IFolderFolder> _folder;
+
+ // NWindows::NCOM::CComInitializer m_ComInitializer;
+ UString m_CurrentDir;
+
+ UString m_PannelTitle;
+ FString m_FileName;
+ NWindows::NFile::NFind::CFileInfo m_FileInfo;
+
+ UString _archiveTypeName;
+
+ InfoPanelLine m_InfoLines[kNumInfoLinesMax];
+
+ char m_FileNameBuffer[1024];
+ char m_CurrentDirBuffer[1024];
+ char m_PannelTitleBuffer[1024];
+
+ AString PanelModeColumnTypes;
+ AString PanelModeColumnWidths;
+ // PanelMode _panelMode;
+ void AddColumn(PROPID aPropID);
+
+ void EnterToDirectory(const UString &dirName);
+ void GetPathParts(UStringVector &pathParts);
+ void SetCurrentDirVar();
+ // HRESULT AfterUpdate(CWorkDirTempFile &tempFile, const UStringVector &pathVector);
+
+public:
+
+ bool PasswordIsDefined;
+ UString Password;
+
+ CPlugin(const FString &fileName, CAgent *agent, UString archiveTypeName);
+ ~CPlugin();
+
+ void ReadPluginPanelItem(PluginPanelItem &panelItem, UInt32 itemIndex);
+
+ int GetFindData(PluginPanelItem **panelItems,int *itemsNumber,int opMode);
+ void FreeFindData(PluginPanelItem *panelItem,int ItemsNumber);
+ int SetDirectory(const char *aszDir, int opMode);
+ void GetOpenPluginInfo(struct OpenPluginInfo *info);
+ int DeleteFiles(PluginPanelItem *panelItems, unsigned itemsNumber, int opMode);
+
+ HRESULT ExtractFiles(
+ bool decompressAllItems,
+ const UInt32 *indices,
+ UInt32 numIndices,
+ bool silent,
+ NExtract::NPathMode::EEnum pathMode,
+ NExtract::NOverwriteMode::EEnum overwriteMode,
+ const UString &destPath,
+ bool passwordIsDefined, const UString &password);
+
+ NFar::NFileOperationReturnCode::EEnum GetFiles(struct PluginPanelItem *panelItem, unsigned itemsNumber,
+ int move, char *destPath, int opMode);
+
+ NFar::NFileOperationReturnCode::EEnum GetFilesReal(struct PluginPanelItem *panelItems,
+ unsigned itemsNumber, int move, const char *_aDestPath, int opMode, bool showBox);
+
+ NFar::NFileOperationReturnCode::EEnum PutFiles(struct PluginPanelItem *panelItems, unsigned itemsNumber,
+ int move, int opMode);
+ HRESULT CreateFolder();
+
+ HRESULT ShowAttributesWindow();
+
+ int ProcessKey(int key, unsigned int controlState);
+};
+
+HRESULT CompressFiles(const CObjectVector<PluginPanelItem> &pluginPanelItems);
+
+#endif
diff --git a/CPP/7zip/UI/Far/PluginCommon.cpp b/CPP/7zip/UI/Far/PluginCommon.cpp
new file mode 100644
index 0000000..e1d4458
--- /dev/null
+++ b/CPP/7zip/UI/Far/PluginCommon.cpp
@@ -0,0 +1,50 @@
+// SevenZip/Plugin.cpp
+
+#include "StdAfx.h"
+
+#include "Plugin.h"
+
+/*
+void CPlugin::AddRealIndexOfFile(const CArchiveFolderItem &aFolder,
+ int anIndexInVector, vector<int> &aRealIndexes)
+{
+ const CArchiveFolderFileItem &anItem = aFolder.m_FileSubItems[anIndexInVector];
+ int aHandlerItemIndex = m_ProxyHandler->GetHandlerItemIndex(anItem.m_Properties);
+ if (aHandlerItemIndex < 0)
+ throw "error";
+ aRealIndexes.push_back(aHandlerItemIndex);
+}
+
+void CPlugin::AddRealIndexes(const CArchiveFolderItem &anItem,
+ vector<int> &aRealIndexes)
+{
+ int aHandlerItemIndex = m_ProxyHandler->GetHandlerItemIndex(anItem.m_Properties);
+ if (aHandlerItemIndex >= 0) // test -1 value
+ aRealIndexes.push_back(aHandlerItemIndex);
+ for (int i = 0; i < anItem.m_DirSubItems.Size(); i++)
+ AddRealIndexes(anItem.m_DirSubItems[i], aRealIndexes);
+ for (i = 0; i < anItem.m_FileSubItems.Size(); i++)
+ AddRealIndexOfFile(anItem, i , aRealIndexes);
+}
+
+
+void CPlugin::GetRealIndexes(PluginPanelItem *aPanelItems, int anItemsNumber,
+ vector<int> &aRealIndexes)
+{
+ aRealIndexes.clear();
+ for (int i = 0; i < anItemsNumber; i++)
+ {
+ int anIndex = aPanelItems[i].UserData;
+ if (anIndex < m_FolderItem->m_DirSubItems.Size())
+ {
+ const CArchiveFolderItem &anItem = m_FolderItem->m_DirSubItems[anIndex];
+ AddRealIndexes(anItem, aRealIndexes);
+ }
+ else
+ AddRealIndexOfFile(*m_FolderItem, anIndex - m_FolderItem->m_DirSubItems.Size(),
+ aRealIndexes);
+ }
+ sort(aRealIndexes.begin(), aRealIndexes.end());
+}
+
+*/
diff --git a/CPP/7zip/UI/Far/PluginDelete.cpp b/CPP/7zip/UI/Far/PluginDelete.cpp
new file mode 100644
index 0000000..fdade1a
--- /dev/null
+++ b/CPP/7zip/UI/Far/PluginDelete.cpp
@@ -0,0 +1,144 @@
+// PluginDelete.cpp
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+
+#include "../../../Common/StringConvert.h"
+#include "FarUtils.h"
+
+#include "Messages.h"
+#include "Plugin.h"
+#include "UpdateCallbackFar.h"
+
+using namespace NFar;
+
+int CPlugin::DeleteFiles(PluginPanelItem *panelItems, unsigned numItems, int opMode)
+{
+ if (numItems == 0)
+ return FALSE;
+ if (_agent->IsThere_ReadOnlyArc())
+ {
+ g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive);
+ return FALSE;
+ }
+ if ((opMode & OPM_SILENT) == 0)
+ {
+ const char *msgItems[]=
+ {
+ g_StartupInfo.GetMsgString(NMessageID::kDeleteTitle),
+ g_StartupInfo.GetMsgString(NMessageID::kDeleteFiles),
+ g_StartupInfo.GetMsgString(NMessageID::kDeleteDelete),
+ g_StartupInfo.GetMsgString(NMessageID::kDeleteCancel)
+ };
+
+ // char msg[1024];
+ AString str1;
+
+ if (numItems == 1)
+ {
+ str1 = g_StartupInfo.GetMsgString(NMessageID::kDeleteFile);
+ AString name (panelItems[0].FindData.cFileName);
+ const unsigned kSizeLimit = 48;
+ if (name.Len() > kSizeLimit)
+ {
+ UString s = MultiByteToUnicodeString(name, CP_OEMCP);
+ ReduceString(s, kSizeLimit);
+ name = UnicodeStringToMultiByte(s, CP_OEMCP);
+ }
+ str1.Replace(AString ("%.40s"), name);
+ msgItems[1] = str1;
+ // sprintf(msg, g_StartupInfo.GetMsgString(NMessageID::kDeleteFile), panelItems[0].FindData.cFileName);
+ // msgItems[2] = msg;
+ }
+ else if (numItems > 1)
+ {
+ str1 = g_StartupInfo.GetMsgString(NMessageID::kDeleteNumberOfFiles);
+ {
+ AString n;
+ n.Add_UInt32(numItems);
+ str1.Replace(AString ("%d"), n);
+ }
+ msgItems[1] = str1;
+ // sprintf(msg, g_StartupInfo.GetMsgString(NMessageID::kDeleteNumberOfFiles), numItems);
+ // msgItems[1] = msg;
+ }
+ if (g_StartupInfo.ShowMessage(FMSG_WARNING, NULL, msgItems, Z7_ARRAY_SIZE(msgItems), 2) != 0)
+ return (FALSE);
+ }
+
+ CScreenRestorer screenRestorer;
+ CProgressBox progressBox;
+ CProgressBox *progressBoxPointer = NULL;
+ if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0)
+ {
+ screenRestorer.Save();
+
+ progressBoxPointer = &progressBox;
+ progressBox.Init(
+ // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle),
+ g_StartupInfo.GetMsgString(NMessageID::kDeleting));
+ }
+
+ /*
+ CWorkDirTempFile tempFile;
+ if (tempFile.CreateTempFile(m_FileName) != S_OK)
+ return FALSE;
+ */
+
+ CObjArray<UInt32> indices(numItems);
+ unsigned i;
+ for (i = 0; i < numItems; i++)
+ indices[i] = (UInt32)panelItems[i].UserData;
+
+ /*
+ UStringVector pathVector;
+ GetPathParts(pathVector);
+
+ CMyComPtr<IOutFolderArchive> outArchive;
+ HRESULT result = m_ArchiveHandler.QueryInterface(IID_IOutFolderArchive, &outArchive);
+ if (result != S_OK)
+ {
+ g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive);
+ return FALSE;
+ }
+ */
+
+ CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp;
+ CMyComPtr<IFolderArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+
+ updateCallbackSpec->Init(/* m_ArchiveHandler, */ progressBoxPointer);
+ updateCallbackSpec->PasswordIsDefined = PasswordIsDefined;
+ updateCallbackSpec->Password = Password;
+
+ /*
+ outArchive->SetFolder(_folder);
+ result = outArchive->DeleteItems(tempFile.OutStream, indices, numItems, updateCallback);
+ updateCallback.Release();
+ outArchive.Release();
+
+ if (result == S_OK)
+ {
+ result = AfterUpdate(tempFile, pathVector);
+ }
+ */
+
+ HRESULT result;
+ {
+ CMyComPtr<IFolderOperations> folderOperations;
+ result = _folder.QueryInterface(IID_IFolderOperations, &folderOperations);
+ if (folderOperations)
+ result = folderOperations->Delete(indices, numItems, updateCallback);
+ else if (result != S_OK)
+ result = E_FAIL;
+ }
+
+ if (result != S_OK)
+ {
+ ShowSysErrorMessage(result);
+ return FALSE;
+ }
+
+ SetCurrentDirVar();
+ return TRUE;
+}
diff --git a/CPP/7zip/UI/Far/PluginRead.cpp b/CPP/7zip/UI/Far/PluginRead.cpp
new file mode 100644
index 0000000..7e81ddd
--- /dev/null
+++ b/CPP/7zip/UI/Far/PluginRead.cpp
@@ -0,0 +1,301 @@
+// PluginRead.cpp
+
+#include "StdAfx.h"
+
+#include "Plugin.h"
+
+#include "Messages.h"
+
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/FileDir.h"
+
+#include "../Common/ZipRegistry.h"
+
+#include "ExtractEngine.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+using namespace NFar;
+
+static const char * const kHelpTopicExtrFromSevenZip = "Extract";
+
+static const char kDirDelimiter = CHAR_PATH_SEPARATOR;
+
+static const char * const kExractPathHistoryName = "7-ZipExtractPath";
+
+HRESULT CPlugin::ExtractFiles(
+ bool decompressAllItems,
+ const UInt32 *indices,
+ UInt32 numIndices,
+ bool silent,
+ NExtract::NPathMode::EEnum pathMode,
+ NExtract::NOverwriteMode::EEnum overwriteMode,
+ const UString &destPath,
+ bool passwordIsDefined, const UString &password)
+{
+ if (_agent->_isHashHandler)
+ {
+ g_StartupInfo.ShowMessage(NMessageID::kMoveIsNotSupported);
+ return NFileOperationReturnCode::kError;
+ }
+
+ CScreenRestorer screenRestorer;
+ CProgressBox progressBox;
+ CProgressBox *progressBoxPointer = NULL;
+ if (!silent)
+ {
+ screenRestorer.Save();
+
+ progressBoxPointer = &progressBox;
+ progressBox.Init(
+ // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle),
+ g_StartupInfo.GetMsgString(NMessageID::kExtracting));
+ }
+
+
+ CExtractCallbackImp *extractCallbackSpec = new CExtractCallbackImp;
+ CMyComPtr<IFolderArchiveExtractCallback> extractCallback(extractCallbackSpec);
+
+ extractCallbackSpec->Init(
+ CP_OEMCP,
+ progressBoxPointer,
+ /*
+ GetDefaultName(m_FileName, m_ArchiverInfo.Extension),
+ m_FileInfo.MTime, m_FileInfo.Attributes,
+ */
+ passwordIsDefined, password);
+
+ if (decompressAllItems)
+ return m_ArchiveHandler->Extract(pathMode, overwriteMode,
+ destPath, BoolToInt(false), extractCallback);
+ else
+ {
+ CMyComPtr<IArchiveFolder> archiveFolder;
+ _folder.QueryInterface(IID_IArchiveFolder, &archiveFolder);
+
+ return archiveFolder->Extract(indices, numIndices,
+ BoolToInt(true), // includeAltStreams
+ BoolToInt(false), // replaceAltStreamChars
+ pathMode, overwriteMode,
+ destPath, BoolToInt(false), extractCallback);
+ }
+}
+
+NFileOperationReturnCode::EEnum CPlugin::GetFiles(struct PluginPanelItem *panelItems,
+ unsigned itemsNumber, int move, char *destPath, int opMode)
+{
+ return GetFilesReal(panelItems, itemsNumber, move,
+ destPath, opMode, (opMode & OPM_SILENT) == 0);
+}
+
+NFileOperationReturnCode::EEnum CPlugin::GetFilesReal(struct PluginPanelItem *panelItems,
+ unsigned itemsNumber, int move, const char *destPathLoc, int opMode, bool showBox)
+{
+ if (move != 0)
+ {
+ g_StartupInfo.ShowMessage(NMessageID::kMoveIsNotSupported);
+ return NFileOperationReturnCode::kError;
+ }
+
+ AString destPath (destPathLoc);
+ UString destPathU = GetUnicodeString(destPath, CP_OEMCP);
+ NName::NormalizeDirPathPrefix(destPathU);
+ destPath = UnicodeStringToMultiByte(destPathU, CP_OEMCP);
+
+ // bool extractSelectedFiles = true;
+
+ NExtract::CInfo extractionInfo;
+ extractionInfo.PathMode = NExtract::NPathMode::kCurPaths;
+ extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite;
+
+ const bool silent = (opMode & OPM_SILENT) != 0;
+ bool decompressAllItems = false;
+ UString password = Password;
+ bool passwordIsDefined = PasswordIsDefined;
+
+ if (!silent)
+ {
+ const int kPathIndex = 2;
+
+ extractionInfo.Load();
+
+ const int kPathModeRadioIndex = 4;
+ const int kOverwriteModeRadioIndex = kPathModeRadioIndex + 4;
+ const int kNumOverwriteOptions = 6;
+ const int kFilesModeIndex = kOverwriteModeRadioIndex + kNumOverwriteOptions;
+ const int kXSize = 76;
+ const int kYSize = 19;
+ const int kPasswordYPos = 12;
+
+ const int kXMid = kXSize / 2;
+
+ AString oemPassword (UnicodeStringToMultiByte(password, CP_OEMCP));
+
+ struct CInitDialogItem initItems[]={
+ { DI_DOUBLEBOX, 3, 1, kXSize - 4, kYSize - 2, false, false, 0, false, NMessageID::kExtractTitle, NULL, NULL },
+ { DI_TEXT, 5, 2, 0, 0, false, false, 0, false, NMessageID::kExtractTo, NULL, NULL },
+
+ { DI_EDIT, 5, 3, kXSize - 6, 3, true, false, DIF_HISTORY, false, -1, destPath, kExractPathHistoryName},
+ // { DI_EDIT, 5, 3, kXSize - 6, 3, true, false, 0, false, -1, destPath, NULL},
+
+ { DI_SINGLEBOX, 4, 5, kXMid - 2, 5 + 4, false, false, 0, false, NMessageID::kExtractPathMode, NULL, NULL },
+ { DI_RADIOBUTTON, 6, 6, 0, 0, false,
+ extractionInfo.PathMode == NExtract::NPathMode::kFullPaths,
+ DIF_GROUP, false, NMessageID::kExtractPathFull, NULL, NULL },
+ { DI_RADIOBUTTON, 6, 7, 0, 0, false,
+ extractionInfo.PathMode == NExtract::NPathMode::kCurPaths,
+ 0, false, NMessageID::kExtractPathCurrent, NULL, NULL },
+ { DI_RADIOBUTTON, 6, 8, 0, 0, false,
+ extractionInfo.PathMode == NExtract::NPathMode::kNoPaths,
+ false, 0, NMessageID::kExtractPathNo, NULL, NULL },
+
+ { DI_SINGLEBOX, kXMid, 5, kXSize - 6, 5 + kNumOverwriteOptions, false, false, 0, false, NMessageID::kExtractOwerwriteMode, NULL, NULL },
+ { DI_RADIOBUTTON, kXMid + 2, 6, 0, 0, false,
+ extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kAsk,
+ DIF_GROUP, false, NMessageID::kExtractOwerwriteAsk, NULL, NULL },
+ { DI_RADIOBUTTON, kXMid + 2, 7, 0, 0, false,
+ extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kOverwrite,
+ 0, false, NMessageID::kExtractOwerwritePrompt, NULL, NULL },
+ { DI_RADIOBUTTON, kXMid + 2, 8, 0, 0, false,
+ extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kSkip,
+ 0, false, NMessageID::kExtractOwerwriteSkip, NULL, NULL },
+ { DI_RADIOBUTTON, kXMid + 2, 9, 0, 0, false,
+ extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kRename,
+ 0, false, NMessageID::kExtractOwerwriteAutoRename, NULL, NULL },
+ { DI_RADIOBUTTON, kXMid + 2, 10, 0, 0, false,
+ extractionInfo.OverwriteMode == NExtract::NOverwriteMode::kRenameExisting,
+ 0, false, NMessageID::kExtractOwerwriteAutoRenameExisting, NULL, NULL },
+
+ { DI_SINGLEBOX, 4, 10, kXMid- 2, 10 + 3, false, false, 0, false, NMessageID::kExtractFilesMode, NULL, NULL },
+ { DI_RADIOBUTTON, 6, 11, 0, 0, false, true, DIF_GROUP, false, NMessageID::kExtractFilesSelected, NULL, NULL },
+ { DI_RADIOBUTTON, 6, 12, 0, 0, false, false, 0, false, NMessageID::kExtractFilesAll, NULL, NULL },
+
+ { DI_SINGLEBOX, kXMid, kPasswordYPos, kXSize - 6, kPasswordYPos + 2, false, false, 0, false, NMessageID::kExtractPassword, NULL, NULL },
+ { DI_PSWEDIT, kXMid + 2, kPasswordYPos + 1, kXSize - 8, 12, false, false, 0, false, -1, oemPassword, NULL},
+
+ { DI_TEXT, 3, kYSize - 4, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL },
+
+
+ { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kExtractExtract, NULL, NULL },
+ { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kExtractCancel, NULL, NULL }
+ };
+
+ const unsigned kNumDialogItems = Z7_ARRAY_SIZE(initItems);
+ const unsigned kOkButtonIndex = kNumDialogItems - 2;
+ const unsigned kPasswordIndex = kNumDialogItems - 4;
+
+ FarDialogItem dialogItems[kNumDialogItems];
+ g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems);
+ for (;;)
+ {
+ int askCode = g_StartupInfo.ShowDialog(kXSize, kYSize,
+ kHelpTopicExtrFromSevenZip, dialogItems, kNumDialogItems);
+ if (askCode != kOkButtonIndex)
+ return NFileOperationReturnCode::kInterruptedByUser;
+ destPath = dialogItems[kPathIndex].Data;
+ destPathU = GetUnicodeString(destPath, CP_OEMCP);
+ destPathU.Trim();
+ if (destPathU.IsEmpty())
+ {
+ #ifdef UNDER_CE
+ destPathU = "\\";
+ #else
+ FString destPathF = us2fs(destPathU);
+ if (!GetCurrentDir(destPathF))
+ throw 318016;
+ NName::NormalizeDirPathPrefix(destPathF);
+ destPathU = fs2us(destPathF);
+ #endif
+ break;
+ }
+ else
+ {
+ if (destPathU.Back() == kDirDelimiter)
+ break;
+ }
+ g_StartupInfo.ShowErrorMessage("You must specify directory path");
+ }
+
+ if (dialogItems[kPathModeRadioIndex].Selected)
+ extractionInfo.PathMode = NExtract::NPathMode::kFullPaths;
+ else if (dialogItems[kPathModeRadioIndex + 1].Selected)
+ extractionInfo.PathMode = NExtract::NPathMode::kCurPaths;
+ else if (dialogItems[kPathModeRadioIndex + 2].Selected)
+ extractionInfo.PathMode = NExtract::NPathMode::kNoPaths;
+ else
+ throw 31806;
+
+ if (dialogItems[kOverwriteModeRadioIndex].Selected)
+ extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kAsk;
+ else if (dialogItems[kOverwriteModeRadioIndex + 1].Selected)
+ extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kOverwrite;
+ else if (dialogItems[kOverwriteModeRadioIndex + 2].Selected)
+ extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kSkip;
+ else if (dialogItems[kOverwriteModeRadioIndex + 3].Selected)
+ extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kRename;
+ else if (dialogItems[kOverwriteModeRadioIndex + 4].Selected)
+ extractionInfo.OverwriteMode = NExtract::NOverwriteMode::kRenameExisting;
+ else
+ throw 31806;
+
+ if (dialogItems[kFilesModeIndex].Selected)
+ decompressAllItems = false;
+ else if (dialogItems[kFilesModeIndex + 1].Selected)
+ decompressAllItems = true;
+ else
+ throw 31806;
+
+ extractionInfo.Save();
+
+ if (dialogItems[kFilesModeIndex].Selected)
+ {
+ // extractSelectedFiles = true;
+ }
+ else if (dialogItems[kFilesModeIndex + 1].Selected)
+ {
+ // extractSelectedFiles = false;
+ }
+ else
+ throw 31806;
+
+ oemPassword = dialogItems[kPasswordIndex].Data;
+ password = MultiByteToUnicodeString(oemPassword, CP_OEMCP);
+ passwordIsDefined = !password.IsEmpty();
+ }
+
+ CreateComplexDir(us2fs(destPathU));
+
+ /*
+ vector<int> realIndices;
+ if (!decompressAllItems)
+ GetRealIndexes(panelItems, itemsNumber, realIndices);
+ */
+ CObjArray<UInt32> indices(itemsNumber);
+ for (unsigned i = 0; i < itemsNumber; i++)
+ indices[i] = (UInt32)panelItems[i].UserData;
+
+ const HRESULT result = ExtractFiles(decompressAllItems, indices, itemsNumber,
+ !showBox, extractionInfo.PathMode, extractionInfo.OverwriteMode,
+ destPathU,
+ passwordIsDefined, password);
+ // HRESULT result = ExtractFiles(decompressAllItems, realIndices, !showBox,
+ // extractionInfo, destPath, passwordIsDefined, password);
+ if (result != S_OK)
+ {
+ if (result == E_ABORT)
+ return NFileOperationReturnCode::kInterruptedByUser;
+ ShowSysErrorMessage(result);
+ return NFileOperationReturnCode::kError;
+ }
+
+ // if (move != 0)
+ // {
+ // if (DeleteFiles(panelItems, itemsNumber, opMode) == FALSE)
+ // return NFileOperationReturnCode::kError;
+ // }
+ return NFileOperationReturnCode::kSuccess;
+}
diff --git a/CPP/7zip/UI/Far/PluginWrite.cpp b/CPP/7zip/UI/Far/PluginWrite.cpp
new file mode 100644
index 0000000..3f1fba8
--- /dev/null
+++ b/CPP/7zip/UI/Far/PluginWrite.cpp
@@ -0,0 +1,839 @@
+// PluginWrite.cpp
+
+#include "StdAfx.h"
+
+#include <stdio.h>
+
+#include "Plugin.h"
+
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/FileFind.h"
+
+#include "../Common/ZipRegistry.h"
+
+#include "../Agent/Agent.h"
+
+#include "ProgressBox.h"
+#include "Messages.h"
+#include "UpdateCallbackFar.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+using namespace NFar;
+
+using namespace NUpdateArchive;
+
+static const char * const kHelpTopic = "Update";
+
+static const char * const kArchiveHistoryKeyName = "7-ZipArcName";
+
+static const UInt32 g_MethodMap[] = { 0, 1, 3, 5, 7, 9 };
+
+static HRESULT SetOutProperties(IOutFolderArchive *outArchive, UInt32 method)
+{
+ CMyComPtr<ISetProperties> setProperties;
+ if (outArchive->QueryInterface(IID_ISetProperties, (void **)&setProperties) == S_OK)
+ {
+ /*
+ UStringVector realNames;
+ realNames.Add(UString("x"));
+ NCOM::CPropVariant value = (UInt32)method;
+ CRecordVector<const wchar_t *> names;
+ FOR_VECTOR (i, realNames)
+ names.Add(realNames[i]);
+ RINOK(setProperties->SetProperties(&names.Front(), &value, names.Size()));
+ */
+ NCOM::CPropVariant value = (UInt32)method;
+ const wchar_t *name = L"x";
+ RINOK(setProperties->SetProperties(&name, &value, 1))
+ }
+ return S_OK;
+}
+
+/*
+HRESULT CPlugin::AfterUpdate(CWorkDirTempFile &tempFile, const UStringVector &pathVector)
+{
+ _folder.Release();
+ m_ArchiveHandler->Close();
+
+ RINOK(tempFile.MoveToOriginal(true));
+
+ RINOK(m_ArchiveHandler->ReOpen(NULL)); // check it
+
+ m_ArchiveHandler->BindToRootFolder(&_folder);
+ FOR_VECTOR (i, pathVector)
+ {
+ CMyComPtr<IFolderFolder> newFolder;
+ _folder->BindToFolder(pathVector[i], &newFolder);
+ if (!newFolder)
+ break;
+ _folder = newFolder;
+ }
+ return S_OK;
+}
+*/
+
+NFileOperationReturnCode::EEnum CPlugin::PutFiles(
+ struct PluginPanelItem *panelItems, unsigned numItems,
+ int moveMode, int opMode)
+{
+ if (moveMode != 0
+ && _agent->_isHashHandler)
+ {
+ g_StartupInfo.ShowMessage(NMessageID::kMoveIsNotSupported);
+ return NFileOperationReturnCode::kError;
+ }
+
+ if (numItems <= 0)
+ return NFileOperationReturnCode::kError;
+
+ if (_agent->IsThere_ReadOnlyArc())
+ {
+ g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive);
+ return NFileOperationReturnCode::kError;
+ }
+
+ const int kYSize = 14;
+ const int kXMid = 38;
+
+ NCompression::CInfo compressionInfo;
+ compressionInfo.Load();
+
+ unsigned methodIndex = 0;
+
+ unsigned i;
+ for (i = Z7_ARRAY_SIZE(g_MethodMap); i != 0;)
+ {
+ i--;
+ if (compressionInfo.Level >= g_MethodMap[i])
+ {
+ methodIndex = i;
+ break;
+ }
+ }
+
+ const int kMethodRadioIndex = 2;
+ const int kModeRadioIndex = kMethodRadioIndex + 7;
+
+ struct CInitDialogItem initItems[]={
+ { DI_DOUBLEBOX, 3, 1, 72, kYSize - 2, false, false, 0, false, NMessageID::kUpdateTitle, NULL, NULL },
+
+ { DI_SINGLEBOX, 4, 2, kXMid - 2, 2 + 7, false, false, 0, false, NMessageID::kUpdateMethod, NULL, NULL },
+
+ { DI_RADIOBUTTON, 6, 3, 0, 0, methodIndex == 0, methodIndex == 0, DIF_GROUP, false, NMessageID::kUpdateMethod_Store, NULL, NULL },
+ { DI_RADIOBUTTON, 6, 4, 0, 0, methodIndex == 1, methodIndex == 1, 0, false, NMessageID::kUpdateMethod_Fastest, NULL, NULL },
+ { DI_RADIOBUTTON, 6, 5, 0, 0, methodIndex == 2, methodIndex == 2, 0, false, NMessageID::kUpdateMethod_Fast, NULL, NULL },
+ { DI_RADIOBUTTON, 6, 6, 0, 0, methodIndex == 3, methodIndex == 3, 0, false, NMessageID::kUpdateMethod_Normal, NULL, NULL },
+ { DI_RADIOBUTTON, 6, 7, 0, 0, methodIndex == 4, methodIndex == 4, 0, false, NMessageID::kUpdateMethod_Maximum, NULL, NULL },
+ { DI_RADIOBUTTON, 6, 8, 0, 0, methodIndex == 5, methodIndex == 5, 0, false, NMessageID::kUpdateMethod_Ultra, NULL, NULL },
+
+ { DI_SINGLEBOX, kXMid, 2, 70, 2 + 5, false, false, 0, false, NMessageID::kUpdateMode, NULL, NULL },
+
+ { DI_RADIOBUTTON, kXMid + 2, 3, 0, 0, false, true, DIF_GROUP, false, NMessageID::kUpdateMode_Add, NULL, NULL },
+ { DI_RADIOBUTTON, kXMid + 2, 4, 0, 0, false, false, 0, false, NMessageID::kUpdateMode_Update, NULL, NULL },
+ { DI_RADIOBUTTON, kXMid + 2, 5, 0, 0, false, false, 0, false, NMessageID::kUpdateMode_Fresh, NULL, NULL },
+ { DI_RADIOBUTTON, kXMid + 2, 6, 0, 0, false, false, 0, false, NMessageID::kUpdateMode_Sync, NULL, NULL },
+
+ { DI_TEXT, 3, kYSize - 4, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL },
+
+ { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kUpdateAdd, NULL, NULL },
+ { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kCancel, NULL, NULL }
+ };
+
+ const int kNumDialogItems = Z7_ARRAY_SIZE(initItems);
+ const int kOkButtonIndex = kNumDialogItems - 2;
+ FarDialogItem dialogItems[kNumDialogItems];
+ g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems);
+ const int askCode = g_StartupInfo.ShowDialog(76, kYSize,
+ kHelpTopic, dialogItems, kNumDialogItems);
+ if (askCode != kOkButtonIndex)
+ return NFileOperationReturnCode::kInterruptedByUser;
+
+ compressionInfo.Level = g_MethodMap[0];
+ for (i = 0; i < Z7_ARRAY_SIZE(g_MethodMap); i++)
+ if (dialogItems[kMethodRadioIndex + i].Selected)
+ compressionInfo.Level = g_MethodMap[i];
+
+ const CActionSet *actionSet;
+
+ if (dialogItems[kModeRadioIndex ].Selected) actionSet = &k_ActionSet_Add;
+ else if (dialogItems[kModeRadioIndex + 1].Selected) actionSet = &k_ActionSet_Update;
+ else if (dialogItems[kModeRadioIndex + 2].Selected) actionSet = &k_ActionSet_Fresh;
+ else if (dialogItems[kModeRadioIndex + 3].Selected) actionSet = &k_ActionSet_Sync;
+ else throw 51751;
+
+ compressionInfo.Save();
+
+ CWorkDirTempFile tempFile;
+ if (tempFile.CreateTempFile(m_FileName) != S_OK)
+ return NFileOperationReturnCode::kError;
+
+
+ /*
+ CSysStringVector fileNames;
+ for (int i = 0; i < numItems; i++)
+ {
+ const PluginPanelItem &panelItem = panelItems[i];
+ CSysString fullName;
+ if (!MyGetFullPathName(panelItem.FindData.cFileName, fullName))
+ return NFileOperationReturnCode::kError;
+ fileNames.Add(fullName);
+ }
+ */
+
+ CScreenRestorer screenRestorer;
+ CProgressBox progressBox;
+ CProgressBox *progressBoxPointer = NULL;
+ if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0)
+ {
+ screenRestorer.Save();
+
+ progressBoxPointer = &progressBox;
+ progressBox.Init(
+ // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle),
+ g_StartupInfo.GetMsgString(NMessageID::kUpdating));
+ }
+
+ UStringVector pathVector;
+ GetPathParts(pathVector);
+
+ UStringVector fileNames;
+ fileNames.ClearAndReserve(numItems);
+ for (i = 0; i < (unsigned)numItems; i++)
+ fileNames.AddInReserved(MultiByteToUnicodeString(panelItems[i].FindData.cFileName, CP_OEMCP));
+ CObjArray<const wchar_t *> fileNamePointers(numItems);
+ for (i = 0; i < (unsigned)numItems; i++)
+ fileNamePointers[i] = fileNames[i];
+
+ CMyComPtr<IOutFolderArchive> outArchive;
+ HRESULT result = m_ArchiveHandler.QueryInterface(IID_IOutFolderArchive, &outArchive);
+ if (result != S_OK)
+ {
+ g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive);
+ return NFileOperationReturnCode::kError;
+ }
+
+ /*
+ BYTE actionSetByte[NUpdateArchive::NPairState::kNumValues];
+ for (i = 0; i < NUpdateArchive::NPairState::kNumValues; i++)
+ actionSetByte[i] = (BYTE)actionSet->StateActions[i];
+ */
+
+ CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp;
+ CMyComPtr<IFolderArchiveUpdateCallback> updateCallback(updateCallbackSpec );
+
+ updateCallbackSpec->Init(/* m_ArchiveHandler, */ progressBoxPointer);
+ updateCallbackSpec->PasswordIsDefined = PasswordIsDefined;
+ updateCallbackSpec->Password = Password;
+
+ if (!_agent->_isHashHandler)
+ {
+ if (SetOutProperties(outArchive, compressionInfo.Level) != S_OK)
+ return NFileOperationReturnCode::kError;
+ }
+
+ /*
+ outArchive->SetFolder(_folder);
+ outArchive->SetFiles(L"", fileNamePointers, numItems);
+ // FStringVector requestedPaths;
+ // FStringVector processedPaths;
+ result = outArchive->DoOperation2(
+ // &requestedPaths, &processedPaths,
+ NULL, NULL,
+ tempFile.OutStream, actionSetByte, NULL, updateCallback);
+ updateCallback.Release();
+ outArchive.Release();
+
+ if (result == S_OK)
+ {
+ result = AfterUpdate(tempFile, pathVector);
+ }
+ */
+
+ {
+ result = _agent->SetFiles(L"", fileNamePointers, numItems);
+ if (result == S_OK)
+ {
+ CAgentFolder *agentFolder = NULL;
+ {
+ CMyComPtr<IArchiveFolderInternal> afi;
+ _folder.QueryInterface(IID_IArchiveFolderInternal, &afi);
+ if (afi)
+ afi->GetAgentFolder(&agentFolder);
+ }
+ if (agentFolder)
+ result = agentFolder->CommonUpdateOperation(AGENT_OP_Uni,
+ (moveMode != 0), NULL, actionSet, NULL, 0, updateCallback);
+ else
+ result = E_FAIL;
+ }
+ }
+
+ if (result != S_OK)
+ {
+ ShowSysErrorMessage(result);
+ return NFileOperationReturnCode::kError;
+ }
+
+ return NFileOperationReturnCode::kSuccess;
+}
+
+namespace NPathType
+{
+ enum EEnum
+ {
+ kLocal,
+ kUNC
+ };
+ EEnum GetPathType(const UString &path);
+}
+
+struct CParsedPath
+{
+ UString Prefix; // Disk or UNC with slash
+ UStringVector PathParts;
+ void ParsePath(const UString &path);
+ UString MergePath() const;
+};
+
+static const char kDirDelimiter = CHAR_PATH_SEPARATOR;
+static const wchar_t kDiskDelimiter = L':';
+
+namespace NPathType
+{
+ EEnum GetPathType(const UString &path)
+ {
+ if (path.Len() <= 2)
+ return kLocal;
+ if (path[0] == kDirDelimiter && path[1] == kDirDelimiter)
+ return kUNC;
+ return kLocal;
+ }
+}
+
+void CParsedPath::ParsePath(const UString &path)
+{
+ int curPos = 0;
+ switch (NPathType::GetPathType(path))
+ {
+ case NPathType::kLocal:
+ {
+ int posDiskDelimiter = path.Find(kDiskDelimiter);
+ if (posDiskDelimiter >= 0)
+ {
+ curPos = posDiskDelimiter + 1;
+ if ((int)path.Len() > curPos)
+ if (path[curPos] == kDirDelimiter)
+ curPos++;
+ }
+ break;
+ }
+ case NPathType::kUNC:
+ {
+ // the bug was fixed:
+ curPos = path.Find((wchar_t)kDirDelimiter, 2);
+ if (curPos < 0)
+ curPos = (int)path.Len();
+ else
+ curPos++;
+ }
+ }
+ Prefix = path.Left(curPos);
+ SplitPathToParts(path.Ptr(curPos), PathParts);
+}
+
+UString CParsedPath::MergePath() const
+{
+ UString result = Prefix;
+ FOR_VECTOR (i, PathParts)
+ {
+ if (i != 0)
+ result += kDirDelimiter;
+ result += PathParts[i];
+ }
+ return result;
+}
+
+
+static void SetArcName(UString &arcName, const CArcInfoEx &arcInfo)
+{
+ if (!arcInfo.Flags_KeepName())
+ {
+ int dotPos = arcName.ReverseFind_Dot();
+ int slashPos = arcName.ReverseFind_PathSepar();
+ if (dotPos > slashPos + 1)
+ arcName.DeleteFrom(dotPos);
+ }
+ arcName.Add_Dot();
+ arcName += arcInfo.GetMainExt();
+}
+
+HRESULT CompressFiles(const CObjectVector<PluginPanelItem> &pluginPanelItems)
+{
+ if (pluginPanelItems.Size() == 0)
+ return E_FAIL;
+
+ UStringVector fileNames;
+ {
+ FOR_VECTOR (i, pluginPanelItems)
+ {
+ const PluginPanelItem &panelItem = pluginPanelItems[i];
+ if (strcmp(panelItem.FindData.cFileName, "..") == 0 &&
+ NFind::NAttributes::IsDir(panelItem.FindData.dwFileAttributes))
+ return E_FAIL;
+ if (strcmp(panelItem.FindData.cFileName, ".") == 0 &&
+ NFind::NAttributes::IsDir(panelItem.FindData.dwFileAttributes))
+ return E_FAIL;
+ FString fullPath;
+ FString fileNameUnicode = us2fs(MultiByteToUnicodeString(panelItem.FindData.cFileName, CP_OEMCP));
+ if (!MyGetFullPathName(fileNameUnicode, fullPath))
+ return E_FAIL;
+ fileNames.Add(fs2us(fullPath));
+ }
+ }
+
+ NCompression::CInfo compressionInfo;
+ compressionInfo.Load();
+
+ int archiverIndex = -1;
+
+ /*
+ CCodecs *codecs = new CCodecs;
+ CMyComPtr<ICompressCodecsInfo> compressCodecsInfo = codecs;
+ if (codecs->Load() != S_OK)
+ throw "Can't load 7-Zip codecs";
+ */
+
+ if (LoadGlobalCodecs() != S_OK)
+ throw "Can't load 7-Zip codecs";
+
+ CCodecs *codecs = g_CodecsObj;
+
+ {
+ FOR_VECTOR (i, codecs->Formats)
+ {
+ const CArcInfoEx &arcInfo = codecs->Formats[i];
+ if (arcInfo.UpdateEnabled)
+ {
+ if (archiverIndex == -1)
+ archiverIndex = (int)i;
+ if (MyStringCompareNoCase(arcInfo.Name, compressionInfo.ArcType) == 0)
+ archiverIndex = (int)i;
+ }
+ }
+ }
+
+ if (archiverIndex < 0)
+ throw "there is no output handler";
+
+ UString resultPath;
+ {
+ CParsedPath parsedPath;
+ parsedPath.ParsePath(fileNames.Front());
+ if (parsedPath.PathParts.Size() == 0)
+ return E_FAIL;
+ if (fileNames.Size() == 1 || parsedPath.PathParts.Size() == 1)
+ {
+ // CSysString pureName, dot, extension;
+ resultPath = parsedPath.PathParts.Back();
+ }
+ else
+ {
+ parsedPath.PathParts.DeleteBack();
+ resultPath = parsedPath.PathParts.Back();
+ }
+ }
+ UString archiveNameSrc = resultPath;
+ UString arcName = archiveNameSrc;
+
+ int prevFormat = archiverIndex;
+ SetArcName(arcName, codecs->Formats[archiverIndex]);
+
+ const CActionSet *actionSet = &k_ActionSet_Add;
+
+ for (;;)
+ {
+ AString archiveNameA (UnicodeStringToMultiByte(arcName, CP_OEMCP));
+ const int kYSize = 16;
+ const int kXMid = 38;
+
+ const int kArchiveNameIndex = 2;
+ const int kMethodRadioIndex = kArchiveNameIndex + 2;
+ const int kModeRadioIndex = kMethodRadioIndex + 7;
+
+ // char updateAddToArchiveString[512];
+ AString str1;
+ {
+ const CArcInfoEx &arcInfo = codecs->Formats[archiverIndex];
+ const AString s (UnicodeStringToMultiByte(arcInfo.Name, CP_OEMCP));
+ str1 = g_StartupInfo.GetMsgString(NMessageID::kUpdateAddToArchive);
+ str1.Replace(AString ("%s"), s);
+ /*
+ sprintf(updateAddToArchiveString,
+ g_StartupInfo.GetMsgString(NMessageID::kUpdateAddToArchive), (const char *)s);
+ */
+ }
+
+ unsigned methodIndex = 0;
+ unsigned i;
+ for (i = Z7_ARRAY_SIZE(g_MethodMap); i != 0;)
+ {
+ i--;
+ if (compressionInfo.Level >= g_MethodMap[i])
+ {
+ methodIndex = i;
+ break;
+ }
+ }
+
+ const struct CInitDialogItem initItems[]=
+ {
+ { DI_DOUBLEBOX, 3, 1, 72, kYSize - 2, false, false, 0, false, NMessageID::kUpdateTitle, NULL, NULL },
+
+ { DI_TEXT, 5, 2, 0, 0, false, false, 0, false, -1, str1, NULL },
+
+ { DI_EDIT, 5, 3, 70, 3, true, false, DIF_HISTORY, false, -1, archiveNameA, kArchiveHistoryKeyName},
+ // { DI_EDIT, 5, 3, 70, 3, true, false, 0, false, -1, arcName, NULL},
+
+ { DI_SINGLEBOX, 4, 4, kXMid - 2, 4 + 7, false, false, 0, false, NMessageID::kUpdateMethod, NULL, NULL },
+
+ { DI_RADIOBUTTON, 6, 5, 0, 0, false, methodIndex == 0, DIF_GROUP, false, NMessageID::kUpdateMethod_Store, NULL, NULL },
+ { DI_RADIOBUTTON, 6, 6, 0, 0, false, methodIndex == 1, 0, false, NMessageID::kUpdateMethod_Fastest, NULL, NULL },
+ { DI_RADIOBUTTON, 6, 7, 0, 0, false, methodIndex == 2, 0, false, NMessageID::kUpdateMethod_Fast, NULL, NULL },
+ { DI_RADIOBUTTON, 6, 8, 0, 0, false, methodIndex == 3, 0, false, NMessageID::kUpdateMethod_Normal, NULL, NULL },
+ { DI_RADIOBUTTON, 6, 9, 0, 0, false, methodIndex == 4, 0, false, NMessageID::kUpdateMethod_Maximum, NULL, NULL },
+ { DI_RADIOBUTTON, 6,10, 0, 0, false, methodIndex == 5, 0, false, NMessageID::kUpdateMethod_Ultra, NULL, NULL },
+
+ { DI_SINGLEBOX, kXMid, 4, 70, 4 + 5, false, false, 0, false, NMessageID::kUpdateMode, NULL, NULL },
+
+ { DI_RADIOBUTTON, kXMid + 2, 5, 0, 0, false, actionSet == &k_ActionSet_Add, DIF_GROUP, false, NMessageID::kUpdateMode_Add, NULL, NULL },
+ { DI_RADIOBUTTON, kXMid + 2, 6, 0, 0, false, actionSet == &k_ActionSet_Update, 0, false, NMessageID::kUpdateMode_Update, NULL, NULL },
+ { DI_RADIOBUTTON, kXMid + 2, 7, 0, 0, false, actionSet == &k_ActionSet_Fresh, 0, false, NMessageID::kUpdateMode_Fresh, NULL, NULL },
+ { DI_RADIOBUTTON, kXMid + 2, 8, 0, 0, false, actionSet == &k_ActionSet_Sync, 0, false, NMessageID::kUpdateMode_Sync, NULL, NULL },
+
+ { DI_TEXT, 3, kYSize - 4, 0, 0, false, false, DIF_BOXCOLOR|DIF_SEPARATOR, false, -1, "", NULL },
+
+ { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kUpdateAdd, NULL, NULL },
+ { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kUpdateSelectArchiver, NULL, NULL },
+ { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kCancel, NULL, NULL }
+ };
+
+ const int kNumDialogItems = Z7_ARRAY_SIZE(initItems);
+
+ const int kOkButtonIndex = kNumDialogItems - 3;
+ const int kSelectarchiverButtonIndex = kNumDialogItems - 2;
+
+ FarDialogItem dialogItems[kNumDialogItems];
+ g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems);
+ int askCode = g_StartupInfo.ShowDialog(76, kYSize,
+ kHelpTopic, dialogItems, kNumDialogItems);
+
+ archiveNameA = dialogItems[kArchiveNameIndex].Data;
+ archiveNameA.Trim();
+ MultiByteToUnicodeString2(arcName, archiveNameA, CP_OEMCP);
+
+ compressionInfo.Level = g_MethodMap[0];
+ for (i = 0; i < Z7_ARRAY_SIZE(g_MethodMap); i++)
+ if (dialogItems[kMethodRadioIndex + i].Selected)
+ compressionInfo.Level = g_MethodMap[i];
+
+ if (dialogItems[kModeRadioIndex ].Selected) actionSet = &k_ActionSet_Add;
+ else if (dialogItems[kModeRadioIndex + 1].Selected) actionSet = &k_ActionSet_Update;
+ else if (dialogItems[kModeRadioIndex + 2].Selected) actionSet = &k_ActionSet_Fresh;
+ else if (dialogItems[kModeRadioIndex + 3].Selected) actionSet = &k_ActionSet_Sync;
+ else throw 51751;
+
+ if (askCode == kSelectarchiverButtonIndex)
+ {
+ CUIntVector indices;
+ AStringVector archiverNames;
+ FOR_VECTOR (k, codecs->Formats)
+ {
+ const CArcInfoEx &arc = codecs->Formats[k];
+ if (arc.UpdateEnabled)
+ {
+ indices.Add(k);
+ archiverNames.Add(GetOemString(arc.Name));
+ }
+ }
+
+ const int index = g_StartupInfo.Menu(FMENU_AUTOHIGHLIGHT,
+ g_StartupInfo.GetMsgString(NMessageID::kUpdateSelectArchiverMenuTitle),
+ NULL, archiverNames, archiverIndex);
+ if (index >= 0)
+ {
+ const CArcInfoEx &prevArchiverInfo = codecs->Formats[prevFormat];
+ if (prevArchiverInfo.Flags_KeepName())
+ {
+ const UString &prevExtension = prevArchiverInfo.GetMainExt();
+ const unsigned prevExtensionLen = prevExtension.Len();
+ if (arcName.Len() >= prevExtensionLen &&
+ MyStringCompareNoCase(arcName.RightPtr(prevExtensionLen), prevExtension) == 0)
+ {
+ const unsigned pos = arcName.Len() - prevExtensionLen;
+ if (pos > 2)
+ {
+ if (arcName[pos - 1] == '.')
+ arcName.DeleteFrom(pos - 1);
+ }
+ }
+ }
+
+ archiverIndex = (int)indices[index];
+ const CArcInfoEx &arcInfo = codecs->Formats[archiverIndex];
+ prevFormat = archiverIndex;
+
+ if (arcInfo.Flags_KeepName())
+ arcName = archiveNameSrc;
+ SetArcName(arcName, arcInfo);
+ }
+ continue;
+ }
+
+ if (askCode != kOkButtonIndex)
+ return E_ABORT;
+
+ break;
+ }
+
+ const CArcInfoEx &archiverInfoFinal = codecs->Formats[archiverIndex];
+ compressionInfo.ArcType = archiverInfoFinal.Name;
+ compressionInfo.Save();
+
+ NWorkDir::CInfo workDirInfo;
+ workDirInfo.Load();
+
+ FString fullArcName;
+ if (!MyGetFullPathName(us2fs(arcName), fullArcName))
+ return E_FAIL;
+
+ CWorkDirTempFile tempFile;
+ RINOK(tempFile.CreateTempFile(fullArcName))
+ CScreenRestorer screenRestorer;
+ CProgressBox progressBox;
+ CProgressBox *progressBoxPointer = NULL;
+
+ screenRestorer.Save();
+
+ progressBoxPointer = &progressBox;
+ progressBox.Init(
+ // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle),
+ g_StartupInfo.GetMsgString(NMessageID::kUpdating));
+
+
+ NFind::CFileInfo fileInfo;
+
+ CMyComPtr<IOutFolderArchive> outArchive;
+
+ CMyComPtr<IInFolderArchive> archiveHandler;
+ if (fileInfo.Find(fullArcName))
+ {
+ if (fileInfo.IsDir())
+ throw "There is Directory with such name";
+
+ CAgent *agentSpec = new CAgent;
+ archiveHandler = agentSpec;
+ // CLSID realClassID;
+ CMyComBSTR archiveType;
+ RINOK(archiveHandler->Open(NULL,
+ GetUnicodeString(fullArcName, CP_OEMCP), UString(),
+ // &realClassID,
+ &archiveType,
+ NULL))
+
+ if (MyStringCompareNoCase(archiverInfoFinal.Name, (const wchar_t *)archiveType) != 0)
+ throw "Type of existing archive differs from specified type";
+ const HRESULT result = archiveHandler.QueryInterface(
+ IID_IOutFolderArchive, &outArchive);
+ if (result != S_OK)
+ {
+ g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive);
+ return E_FAIL;
+ }
+ }
+ else
+ {
+ // HRESULT result = outArchive.CoCreateInstance(classID);
+ CAgent *agentSpec = new CAgent;
+ outArchive = agentSpec;
+
+ /*
+ HRESULT result = outArchive.CoCreateInstance(CLSID_CAgentArchiveHandler);
+ if (result != S_OK)
+ {
+ g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive);
+ return E_FAIL;
+ }
+ */
+ }
+
+ CObjArray<const wchar_t *> fileNamePointers(fileNames.Size());
+
+ unsigned i;
+ for (i = 0; i < fileNames.Size(); i++)
+ fileNamePointers[i] = fileNames[i];
+
+ outArchive->SetFolder(NULL);
+ outArchive->SetFiles(L"", fileNamePointers, fileNames.Size());
+ BYTE actionSetByte[NUpdateArchive::NPairState::kNumValues];
+ for (i = 0; i < NUpdateArchive::NPairState::kNumValues; i++)
+ actionSetByte[i] = (BYTE)actionSet->StateActions[i];
+
+ CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp;
+ CMyComPtr<IFolderArchiveUpdateCallback> updateCallback(updateCallbackSpec );
+
+ updateCallbackSpec->Init(/* archiveHandler, */ progressBoxPointer);
+
+
+ RINOK(SetOutProperties(outArchive, compressionInfo.Level))
+
+ // FStringVector requestedPaths;
+ // FStringVector processedPaths;
+ HRESULT result = outArchive->DoOperation(
+ // &requestedPaths, &processedPaths,
+ NULL, NULL,
+ codecs, archiverIndex,
+ tempFile.OutStream, actionSetByte,
+ NULL, updateCallback);
+ updateCallback.Release();
+ outArchive.Release();
+
+ if (result != S_OK)
+ {
+ ShowSysErrorMessage(result);
+ return result;
+ }
+
+ if (archiveHandler)
+ {
+ archiveHandler->Close();
+ }
+
+ result = tempFile.MoveToOriginal(archiveHandler != NULL);
+ if (result != S_OK)
+ {
+ ShowSysErrorMessage(result);
+ return result;
+ }
+ return S_OK;
+}
+
+
+static const char * const k_CreateFolder_History = "NewFolder"; // we use default FAR folder name
+
+HRESULT CPlugin::CreateFolder()
+{
+ if (_agent->IsThere_ReadOnlyArc())
+ {
+ g_StartupInfo.ShowMessage(NMessageID::kUpdateNotSupportedForThisArchive);
+ return TRUE;
+ }
+
+ UString destPathU;
+ {
+ const int kXSize = 60;
+ const int kYSize = 8;
+ const int kPathIndex = 2;
+
+ AString destPath ("New Folder");
+
+ const struct CInitDialogItem initItems[]={
+ { DI_DOUBLEBOX, 3, 1, kXSize - 4, kYSize - 2, false, false, 0, false,
+ -1, "Create Folder", NULL },
+
+ { DI_TEXT, 5, 2, 0, 0, false, false, 0, false, -1, "Folder name:", NULL },
+
+ { DI_EDIT, 5, 3, kXSize - 6, 3, true, false, DIF_HISTORY, false, -1, destPath, k_CreateFolder_History },
+
+ { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, true, NMessageID::kOk, NULL, NULL },
+ { DI_BUTTON, 0, kYSize - 3, 0, 0, false, false, DIF_CENTERGROUP, false, NMessageID::kCancel, NULL, NULL }
+ };
+
+ const int kNumDialogItems = Z7_ARRAY_SIZE(initItems);
+ const int kOkButtonIndex = kNumDialogItems - 2;
+
+ FarDialogItem dialogItems[kNumDialogItems];
+ g_StartupInfo.InitDialogItems(initItems, dialogItems, kNumDialogItems);
+ for (;;)
+ {
+ int askCode = g_StartupInfo.ShowDialog(kXSize, kYSize,
+ NULL, // kHelpTopic
+ dialogItems, kNumDialogItems);
+ if (askCode != kOkButtonIndex)
+ return E_ABORT;
+ destPath = dialogItems[kPathIndex].Data;
+ destPathU = GetUnicodeString(destPath, CP_OEMCP);
+ destPathU.Trim();
+ if (!destPathU.IsEmpty())
+ break;
+ g_StartupInfo.ShowErrorMessage("You must specify folder name");
+ }
+
+ }
+
+ CScreenRestorer screenRestorer;
+ CProgressBox progressBox;
+ CProgressBox *progressBoxPointer = NULL;
+ // if ((opMode & OPM_SILENT) == 0 && (opMode & OPM_FIND ) == 0)
+ {
+ screenRestorer.Save();
+
+ progressBoxPointer = &progressBox;
+ progressBox.Init(
+ // g_StartupInfo.GetMsgString(NMessageID::kWaitTitle),
+ g_StartupInfo.GetMsgString(NMessageID::kDeleting));
+ }
+
+ CUpdateCallback100Imp *updateCallbackSpec = new CUpdateCallback100Imp;
+ CMyComPtr<IFolderArchiveUpdateCallback> updateCallback(updateCallbackSpec);
+
+ updateCallbackSpec->Init(/* m_ArchiveHandler, */ progressBoxPointer);
+ updateCallbackSpec->PasswordIsDefined = PasswordIsDefined;
+ updateCallbackSpec->Password = Password;
+
+ HRESULT result;
+ {
+ CMyComPtr<IFolderOperations> folderOperations;
+ result = _folder.QueryInterface(IID_IFolderOperations, &folderOperations);
+ if (folderOperations)
+ result = folderOperations->CreateFolder(destPathU, updateCallback);
+ else if (result != S_OK)
+ result = E_FAIL;
+ }
+
+ if (result != S_OK)
+ {
+ ShowSysErrorMessage(result);
+ return result;
+ }
+
+ g_StartupInfo.Control(this, FCTL_UPDATEPANEL, (void *)1);
+ g_StartupInfo.Control(this, FCTL_REDRAWPANEL, NULL);
+
+ PanelInfo panelInfo;
+
+ if (g_StartupInfo.ControlGetActivePanelInfo(panelInfo))
+ {
+ const AString destPath (GetOemString(destPathU));
+
+ for (int i = 0; i < panelInfo.ItemsNumber; i++)
+ {
+ const PluginPanelItem &pi = panelInfo.PanelItems[i];
+ if (strcmp(destPath, pi.FindData.cFileName) == 0)
+ {
+ PanelRedrawInfo panelRedrawInfo;
+ panelRedrawInfo.CurrentItem = i;
+ panelRedrawInfo.TopPanelItem = 0;
+ g_StartupInfo.Control(this, FCTL_REDRAWPANEL, &panelRedrawInfo);
+ break;
+ }
+ }
+ }
+
+ SetCurrentDirVar();
+ return S_OK;
+}
diff --git a/CPP/7zip/UI/Far/ProgressBox.cpp b/CPP/7zip/UI/Far/ProgressBox.cpp
new file mode 100644
index 0000000..ab25a10
--- /dev/null
+++ b/CPP/7zip/UI/Far/ProgressBox.cpp
@@ -0,0 +1,305 @@
+// ProgressBox.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+
+#include "FarUtils.h"
+#include "ProgressBox.h"
+
+void CPercentPrinterState::ClearCurState()
+{
+ Completed = 0;
+ Total = ((UInt64)(Int64)-1);
+ Files = 0;
+ FilesTotal = 0;
+ Command.Empty();
+ FileName.Empty();
+}
+
+void CProgressBox::Init(const char *title)
+{
+ _title = title;
+ _wasPrinted = false;
+ StartTick = GetTickCount();
+ _prevTick = StartTick;
+ _prevElapsedSec = 0;
+}
+
+static unsigned GetPower32(UInt32 val)
+{
+ const unsigned kStart = 32;
+ UInt32 mask = ((UInt32)1 << (kStart - 1));
+ for (unsigned i = kStart;; i--)
+ {
+ if (i == 0 || (val & mask) != 0)
+ return i;
+ mask >>= 1;
+ }
+}
+
+static unsigned GetPower64(UInt64 val)
+{
+ UInt32 high = (UInt32)(val >> 32);
+ if (high == 0)
+ return GetPower32((UInt32)val);
+ return GetPower32(high) + 32;
+}
+
+static UInt64 MyMultAndDiv(UInt64 mult1, UInt64 mult2, UInt64 divider)
+{
+ unsigned pow1 = GetPower64(mult1);
+ unsigned pow2 = GetPower64(mult2);
+ while (pow1 + pow2 > 64)
+ {
+ if (pow1 > pow2) { pow1--; mult1 >>= 1; }
+ else { pow2--; mult2 >>= 1; }
+ divider >>= 1;
+ }
+ UInt64 res = mult1 * mult2;
+ if (divider != 0)
+ res /= divider;
+ return res;
+}
+
+#define UINT_TO_STR_2(val) { s[0] = (char)('0' + (val) / 10); s[1] = (char)('0' + (val) % 10); s += 2; }
+
+static void GetTimeString(UInt64 timeValue, char *s)
+{
+ const UInt64 hours = timeValue / 3600;
+ UInt32 seconds = (UInt32)(timeValue - hours * 3600);
+ const UInt32 minutes = seconds / 60;
+ seconds %= 60;
+ if (hours > 99)
+ {
+ ConvertUInt64ToString(hours, s);
+ for (; *s != 0; s++);
+ }
+ else
+ {
+ const UInt32 hours32 = (UInt32)hours;
+ UINT_TO_STR_2(hours32)
+ }
+ *s++ = ':'; UINT_TO_STR_2(minutes)
+ *s++ = ':'; UINT_TO_STR_2(seconds)
+ *s = 0;
+}
+
+void CProgressBox::ReduceString(const UString &src, AString &dest)
+{
+ UnicodeStringToMultiByte2(dest, src, CP_OEMCP);
+
+ if (dest.Len() <= MaxLen)
+ return;
+ unsigned len = FileName.Len();
+ for (; len != 0;)
+ {
+ unsigned delta = len / 8;
+ if (delta == 0)
+ delta = 1;
+ len -= delta;
+ _tempU = FileName;
+ _tempU.Delete(len / 2, FileName.Len() - len);
+ _tempU.Insert(len / 2, L" . ");
+ UnicodeStringToMultiByte2(dest, _tempU, CP_OEMCP);
+ if (dest.Len() <= MaxLen)
+ return;
+ }
+ dest.Empty();
+}
+
+static void Print_UInt64_and_String(AString &s, UInt64 val, const char *name)
+{
+ char temp[32];
+ ConvertUInt64ToString(val, temp);
+ s += temp;
+ s.Add_Space();
+ s += name;
+}
+
+
+static void PrintSize_bytes_Smart(AString &s, UInt64 val)
+{
+ // Print_UInt64_and_String(s, val, "bytes");
+ {
+ char temp[32];
+ ConvertUInt64ToString(val, temp);
+ s += temp;
+ }
+
+ if (val == 0)
+ return;
+
+ unsigned numBits = 10;
+ char c = 'K';
+ char temp[4] = { 'K', 'i', 'B', 0 };
+ if (val >= ((UInt64)10 << 30)) { numBits = 30; c = 'G'; }
+ else if (val >= ((UInt64)10 << 20)) { numBits = 20; c = 'M'; }
+ temp[0] = c;
+ s += " (";
+ Print_UInt64_and_String(s, ((val + ((UInt64)1 << numBits) - 1) >> numBits), temp);
+ s += ')';
+}
+
+
+static const unsigned kPercentsSize = 4;
+
+void CProgressBox::Print()
+{
+ DWORD tick = GetTickCount();
+ DWORD elapsedTicks = tick - StartTick;
+ DWORD elapsedSec = elapsedTicks / 1000;
+
+ if (_wasPrinted)
+ {
+ if (elapsedSec == _prevElapsedSec)
+ {
+ if ((UInt32)(tick - _prevTick) < _tickStep)
+ return;
+ if (_printedState.IsEqualTo((const CPercentPrinterState &)*this))
+ return;
+ }
+ }
+
+ UInt64 cur = Completed;
+ UInt64 total = Total;
+
+ if (!UseBytesForPercents)
+ {
+ cur = Files;
+ total = FilesTotal;
+ }
+
+ {
+ _timeStr.Empty();
+ _timeStr = "Elapsed time: ";
+ char s[40];
+ GetTimeString(elapsedSec, s);
+ _timeStr += s;
+
+ if (cur != 0)
+ {
+ UInt64 remainingTime = 0;
+ if (cur < total)
+ remainingTime = MyMultAndDiv(elapsedTicks, total - cur, cur);
+ UInt64 remainingSec = remainingTime / 1000;
+ _timeStr += " Remaining time: ";
+
+ GetTimeString(remainingSec, s);
+ _timeStr += s;
+ }
+ }
+
+
+ {
+ _perc.Empty();
+ char s[32];
+ unsigned size;
+ {
+ UInt64 val = 0;
+ if (total != (UInt64)(Int64)-1 && total != 0)
+ val = cur * 100 / Total;
+
+ ConvertUInt64ToString(val, s);
+ size = (unsigned)strlen(s);
+ s[size++] = '%';
+ s[size] = 0;
+ }
+
+ unsigned len = size;
+ while (len < kPercentsSize)
+ len = kPercentsSize;
+ len++;
+
+ if (len < MaxLen)
+ {
+ unsigned numChars = MaxLen - len;
+ unsigned filled = 0;
+ if (total != (UInt64)(Int64)-1 && total != 0)
+ filled = (unsigned)(cur * numChars / total);
+ if (filled > numChars)
+ filled = numChars;
+ unsigned i = 0;
+ for (i = 0; i < filled; i++)
+ _perc += (char)(Byte)0xDB; // '=';
+ for (; i < numChars; i++)
+ _perc += (char)(Byte)0xB0; // '.';
+ }
+
+ _perc.Add_Space();
+ while (size < kPercentsSize)
+ {
+ _perc.Add_Space();
+ size++;
+ }
+ _perc += s;
+ }
+
+ _files.Empty();
+ if (Files != 0 || FilesTotal != 0)
+ {
+ _files += "Files: ";
+ char s[32];
+ // if (Files != 0)
+ {
+ ConvertUInt64ToString(Files, s);
+ _files += s;
+ }
+ if (FilesTotal != 0)
+ {
+ _files += " / ";
+ ConvertUInt64ToString(FilesTotal, s);
+ _files += s;
+ }
+ }
+
+ _sizesStr.Empty();
+ if (Total != 0)
+ {
+ _sizesStr += "Size: ";
+ PrintSize_bytes_Smart(_sizesStr, Completed);
+ if (Total != 0 && Total != (UInt64)(Int64)-1)
+ {
+ _sizesStr += " / ";
+ PrintSize_bytes_Smart(_sizesStr, Total);
+ }
+ }
+
+ _name1.Empty();
+ _name2.Empty();
+
+ if (!FileName.IsEmpty())
+ {
+ _name1U.Empty();
+ _name2U.Empty();
+
+ /*
+ if (_isDir)
+ s1 = _filePath;
+ else
+ */
+ {
+ const int slashPos = FileName.ReverseFind_PathSepar();
+ if (slashPos >= 0)
+ {
+ _name1U.SetFrom(FileName, (unsigned)(slashPos + 1));
+ _name2U = FileName.Ptr(slashPos + 1);
+ }
+ else
+ _name2U = FileName;
+ }
+ ReduceString(_name1U, _name1);
+ ReduceString(_name2U, _name2);
+ }
+
+ {
+ const char *strings[] = { _title, _timeStr, _files, _sizesStr, Command, _name1, _name2, _perc };
+ NFar::g_StartupInfo.ShowMessage(FMSG_LEFTALIGN, NULL, strings, Z7_ARRAY_SIZE(strings), 0);
+ }
+
+ _wasPrinted = true;
+ _printedState = *this;
+ _prevTick = tick;
+ _prevElapsedSec = elapsedSec;
+}
diff --git a/CPP/7zip/UI/Far/ProgressBox.h b/CPP/7zip/UI/Far/ProgressBox.h
new file mode 100644
index 0000000..6e8b487
--- /dev/null
+++ b/CPP/7zip/UI/Far/ProgressBox.h
@@ -0,0 +1,83 @@
+// ProgressBox.h
+
+#ifndef ZIP7_INC_PROGRESS_BOX_H
+#define ZIP7_INC_PROGRESS_BOX_H
+
+#include "../../../Common/MyString.h"
+#include "../../../Common/MyTypes.h"
+
+struct CPercentPrinterState
+{
+ UInt64 Completed;
+ UInt64 Total;
+
+ UInt64 Files;
+ UInt64 FilesTotal;
+
+ AString Command;
+ UString FileName;
+
+ void ClearCurState();
+
+ bool IsEqualTo(const CPercentPrinterState &s) const
+ {
+ return
+ Completed == s.Completed
+ && Total == s.Total
+ && Files == s.Files
+ && FilesTotal == s.FilesTotal
+ && Command == s.Command
+ && FileName == s.FileName;
+ }
+
+ CPercentPrinterState():
+ Completed(0),
+ Total((UInt64)(Int64)-1),
+ Files(0),
+ FilesTotal(0)
+ {}
+};
+
+class CProgressBox: public CPercentPrinterState
+{
+ UInt32 _tickStep;
+ DWORD _prevTick;
+ DWORD _prevElapsedSec;
+
+ bool _wasPrinted;
+
+ UString _tempU;
+ UString _name1U;
+ UString _name2U;
+
+ CPercentPrinterState _printedState;
+
+ AString _title;
+
+ AString _timeStr;
+ AString _files;
+ AString _sizesStr;
+ AString _name1;
+ AString _name2;
+ AString _perc;
+
+ void ReduceString(const UString &src, AString &dest);
+
+public:
+ DWORD StartTick;
+ bool UseBytesForPercents;
+ unsigned MaxLen;
+
+ CProgressBox(UInt32 tickStep = 200):
+ _tickStep(tickStep),
+ _prevTick(0),
+ StartTick(0),
+ UseBytesForPercents(true),
+ MaxLen(60)
+ {}
+
+ void Init(const char *title);
+ void Print();
+};
+
+#endif
diff --git a/CPP/7zip/UI/Far/StdAfx.cpp b/CPP/7zip/UI/Far/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/UI/Far/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/UI/Far/StdAfx.h b/CPP/7zip/UI/Far/StdAfx.h
new file mode 100644
index 0000000..035267c
--- /dev/null
+++ b/CPP/7zip/UI/Far/StdAfx.h
@@ -0,0 +1,11 @@
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../../Common/Common.h"
+
+#endif
diff --git a/CPP/7zip/UI/Far/UpdateCallbackFar.cpp b/CPP/7zip/UI/Far/UpdateCallbackFar.cpp
new file mode 100644
index 0000000..94f0a47
--- /dev/null
+++ b/CPP/7zip/UI/Far/UpdateCallbackFar.cpp
@@ -0,0 +1,237 @@
+// UpdateCallbackFar.cpp
+
+#include "StdAfx.h"
+
+#ifndef Z7_ST
+#include "../../../Windows/Synchronization.h"
+#endif
+
+#include "../../../Common/StringConvert.h"
+
+#include "FarUtils.h"
+#include "UpdateCallbackFar.h"
+
+using namespace NWindows;
+using namespace NFar;
+
+#ifndef Z7_ST
+static NSynchronization::CCriticalSection g_CriticalSection;
+#define MT_LOCK NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
+#else
+#define MT_LOCK
+#endif
+
+static HRESULT CheckBreak2()
+{
+ return WasEscPressed() ? E_ABORT : S_OK;
+}
+
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::ScanProgress(UInt64 numFolders, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, Int32 /* isDir */))
+{
+ MT_LOCK
+
+ if (_percent)
+ {
+ _percent->FilesTotal = numFolders + numFiles;
+ _percent->Total = totalSize;
+ _percent->Command = "Scanning";
+ _percent->FileName = path;
+ _percent->Print();
+ _percent->Print();
+ }
+ return CheckBreak2();
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::ScanError(const wchar_t *path, HRESULT errorCode))
+{
+ if (ShowSysErrorMessage(errorCode, path) == -1)
+ return E_ABORT;
+ return CheckBreak2();
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::SetNumFiles(UInt64 numFiles))
+{
+ MT_LOCK
+
+ if (_percent)
+ {
+ _percent->FilesTotal = numFiles;
+ _percent->Print();
+ }
+ return CheckBreak2();
+}
+
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */))
+{
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */))
+{
+ MT_LOCK
+ return CheckBreak2();
+}
+
+
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::SetTotal(UInt64 size))
+{
+ MT_LOCK
+
+ if (_percent)
+ {
+ _percent->Total = size;
+ _percent->Print();
+ }
+ return CheckBreak2();
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::SetCompleted(const UInt64 *completeValue))
+{
+ MT_LOCK
+
+ if (_percent)
+ {
+ if (completeValue)
+ _percent->Completed = *completeValue;
+ _percent->Print();
+ }
+ return CheckBreak2();
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::CompressOperation(const wchar_t *name))
+{
+ MT_LOCK
+
+ if (_percent)
+ {
+ _percent->Command = "Adding";
+ _percent->FileName = name;
+ _percent->Print();
+ }
+ return CheckBreak2();
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::DeleteOperation(const wchar_t *name))
+{
+ MT_LOCK
+
+ if (_percent)
+ {
+ _percent->Command = "Deleting";
+ _percent->FileName = name;
+ _percent->Print();
+ }
+ return CheckBreak2();
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::OperationResult(Int32 /* opRes */))
+{
+ MT_LOCK
+
+ if (_percent)
+ {
+ _percent->Files++;
+ }
+ return CheckBreak2();
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::UpdateErrorMessage(const wchar_t *message))
+{
+ MT_LOCK
+
+ if (g_StartupInfo.ShowErrorMessage(UnicodeStringToMultiByte(message, CP_OEMCP)) == -1)
+ return E_ABORT;
+ return CheckBreak2();
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::OpenFileError(const wchar_t *path, HRESULT errorCode))
+{
+ if (ShowSysErrorMessage(errorCode, path) == -1)
+ return E_ABORT;
+ return CheckBreak2();
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::ReadingFileError(const wchar_t *path, HRESULT errorCode))
+{
+ if (ShowSysErrorMessage(errorCode, path) == -1)
+ return E_ABORT;
+ return CheckBreak2();
+}
+
+void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, AString &s);
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name))
+{
+ MT_LOCK
+
+ if (opRes != NArchive::NExtract::NOperationResult::kOK)
+ {
+ AString s;
+ SetExtractErrorMessage(opRes, isEncrypted, s);
+ if (PrintErrorMessage(s, name) == -1)
+ return E_ABORT;
+ }
+
+ return CheckBreak2();
+}
+
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::ReportUpdateOperation(UInt32 op, const wchar_t *name, Int32 /* isDir */))
+{
+ const char *s;
+ switch (op)
+ {
+ case NUpdateNotifyOp::kAdd: s = "Adding"; break;
+ case NUpdateNotifyOp::kUpdate: s = "Updating"; break;
+ case NUpdateNotifyOp::kAnalyze: s = "Analyzing"; break;
+ case NUpdateNotifyOp::kReplicate: s = "Replicating"; break;
+ case NUpdateNotifyOp::kRepack: s = "Repacking"; break;
+ case NUpdateNotifyOp::kSkip: s = "Skipping"; break;
+ case NUpdateNotifyOp::kHeader: s = "Header creating"; break;
+ case NUpdateNotifyOp::kDelete: s = "Deleting"; break;
+ default: s = "Unknown operation";
+ }
+
+ MT_LOCK
+
+ if (_percent)
+ {
+ _percent->Command = s;
+ _percent->FileName.Empty();
+ if (name)
+ _percent->FileName = name;
+ _percent->Print();
+ }
+
+ return CheckBreak2();
+}
+
+
+extern HRESULT GetPassword(UString &password);
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::CryptoGetTextPassword(BSTR *password))
+{
+ MT_LOCK
+
+ *password = NULL;
+ if (!PasswordIsDefined)
+ {
+ RINOK(GetPassword(Password))
+ PasswordIsDefined = true;
+ }
+ return StringToBstr(Password, password);
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password))
+{
+ MT_LOCK
+
+ *password = NULL;
+ *passwordIsDefined = BoolToInt(PasswordIsDefined);
+ if (!PasswordIsDefined)
+ return S_OK;
+ return StringToBstr(Password, password);
+}
diff --git a/CPP/7zip/UI/Far/UpdateCallbackFar.h b/CPP/7zip/UI/Far/UpdateCallbackFar.h
new file mode 100644
index 0000000..4ec5eed
--- /dev/null
+++ b/CPP/7zip/UI/Far/UpdateCallbackFar.h
@@ -0,0 +1,44 @@
+// UpdateCallbackFar.h
+
+#ifndef ZIP7_INC_UPDATE_CALLBACK_FAR_H
+#define ZIP7_INC_UPDATE_CALLBACK_FAR_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../IPassword.h"
+
+#include "../Agent/IFolderArchive.h"
+
+#include "ProgressBox.h"
+
+Z7_CLASS_IMP_COM_6(
+ CUpdateCallback100Imp
+ , IFolderArchiveUpdateCallback
+ , IFolderArchiveUpdateCallback2
+ , IFolderScanProgress
+ , ICryptoGetTextPassword2
+ , ICryptoGetTextPassword
+ , IArchiveOpenCallback
+)
+ Z7_IFACE_COM7_IMP(IProgress)
+
+ // CMyComPtr<IInFolderArchive> _archiveHandler;
+ CProgressBox *_percent;
+ // UInt64 _total;
+public:
+ bool PasswordIsDefined;
+ UString Password;
+
+ CUpdateCallback100Imp()
+ // : _total(0)
+ {}
+ void Init(/* IInFolderArchive *archiveHandler, */ CProgressBox *progressBox)
+ {
+ // _archiveHandler = archiveHandler;
+ _percent = progressBox;
+ PasswordIsDefined = false;
+ Password.Empty();
+ }
+};
+
+#endif
diff --git a/CPP/7zip/UI/Far/makefile b/CPP/7zip/UI/Far/makefile
new file mode 100644
index 0000000..f3809a8
--- /dev/null
+++ b/CPP/7zip/UI/Far/makefile
@@ -0,0 +1,106 @@
+PROG = 7-ZipFar.dll
+DEF_FILE = Far.def
+CFLAGS = $(CFLAGS) \
+ -DZ7_EXTERNAL_CODECS \
+
+!IFNDEF UNDER_CE
+CFLAGS = $(CFLAGS) -DZ7_LONG_PATH
+!ENDIF
+
+CURRENT_OBJS = \
+ $O\ExtractEngine.obj \
+ $O\FarUtils.obj \
+ $O\Far.obj \
+ $O\OverwriteDialogFar.obj \
+ $O\Plugin.obj \
+ $O\PluginCommon.obj \
+ $O\PluginDelete.obj \
+ $O\PluginRead.obj \
+ $O\PluginWrite.obj \
+ $O\ProgressBox.obj \
+ $O\UpdateCallbackFar.obj \
+
+COMMON_OBJS = \
+ $O\DynLimBuf.obj \
+ $O\IntToString.obj \
+ $O\NewHandler.obj \
+ $O\MyString.obj \
+ $O\StringConvert.obj \
+ $O\StringToInt.obj \
+ $O\MyVector.obj \
+ $O\UTFConvert.obj \
+ $O\Wildcard.obj \
+
+WIN_OBJS = \
+ $O\DLL.obj \
+ $O\ErrorMsg.obj \
+ $O\FileDir.obj \
+ $O\FileFind.obj \
+ $O\FileIO.obj \
+ $O\FileLink.obj \
+ $O\FileName.obj \
+ $O\FileSystem.obj \
+ $O\PropVariant.obj \
+ $O\PropVariantConv.obj \
+ $O\Registry.obj \
+ $O\ResourceString.obj \
+ $O\Synchronization.obj \
+ $O\System.obj \
+ $O\TimeUtils.obj \
+
+7ZIP_COMMON_OBJS = \
+ $O\CreateCoder.obj \
+ $O\FilePathAutoRename.obj \
+ $O\FileStreams.obj \
+ $O\FilterCoder.obj \
+ $O\LimitedStreams.obj \
+ $O\MethodProps.obj \
+ $O\ProgressUtils.obj \
+ $O\PropId.obj \
+ $O\StreamObjects.obj \
+ $O\StreamUtils.obj \
+ $O\UniqBlocks.obj \
+
+UI_COMMON_OBJS = \
+ $O\ArchiveExtractCallback.obj \
+ $O\ArchiveOpenCallback.obj \
+ $O\DefaultName.obj \
+ $O\EnumDirItems.obj \
+ $O\ExtractingFilePath.obj \
+ $O\HashCalc.obj \
+ $O\LoadCodecs.obj \
+ $O\OpenArchive.obj \
+ $O\PropIDUtils.obj \
+ $O\SetProperties.obj \
+ $O\SortUtils.obj \
+ $O\UpdateAction.obj \
+ $O\UpdateCallback.obj \
+ $O\UpdatePair.obj \
+ $O\UpdateProduce.obj \
+ $O\WorkDir.obj \
+ $O\ZipRegistry.obj \
+
+AR_COMMON_OBJS = \
+ $O\ItemNameUtils.obj \
+ $O\OutStreamWithCRC.obj \
+
+AGENT_OBJS = \
+ $O\Agent.obj \
+ $O\AgentOut.obj \
+ $O\AgentProxy.obj \
+ $O\ArchiveFolder.obj \
+ $O\ArchiveFolderOut.obj \
+ $O\UpdateCallbackAgent.obj \
+
+COMPRESS_OBJS = \
+ $O\CopyCoder.obj \
+
+C_OBJS = \
+ $O\Alloc.obj \
+ $O\CpuArch.obj \
+ $O\Sort.obj \
+ $O\Threads.obj \
+
+!include "../../Crc.mak"
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/UI/Far/resource.rc b/CPP/7zip/UI/Far/resource.rc
new file mode 100644
index 0000000..a5c2e2f
--- /dev/null
+++ b/CPP/7zip/UI/Far/resource.rc
@@ -0,0 +1,3 @@
+#include "../../MyVersionInfo.rc"
+
+MY_VERSION_INFO_DLL("7-Zip Plugin for FAR Manager", "7-ZipFar")
diff --git a/CPP/7zip/UI/FileManager/7zFM.exe.manifest b/CPP/7zip/UI/FileManager/7zFM.exe.manifest
new file mode 100644
index 0000000..69c7f0b
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/7zFM.exe.manifest
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+ <assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="7-Zip.7-Zip.7zFM" type="win32"/>
+ <description>7-Zip File Manager.</description>
+ <dependency>
+ <dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/></dependentAssembly>
+ </dependency>
+<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application>
+<!-- Vista --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+<!-- Win 7 --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+<!-- Win 8 --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+<!-- Win 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+<!-- Win 10 --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+</application></compatibility>
+ <asmv3:application>
+ <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+ <dpiAware>true</dpiAware>
+ </asmv3:windowsSettings>
+ </asmv3:application>
+<application xmlns="urn:schemas-microsoft-com:asm.v3">
+<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
+<ws2:longPathAware>true</ws2:longPathAware></windowsSettings></application>
+</assembly>
diff --git a/CPP/7zip/UI/FileManager/7zipLogo.ico b/CPP/7zip/UI/FileManager/7zipLogo.ico
new file mode 100644
index 0000000..973241c
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/7zipLogo.ico
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/AboutDialog.cpp b/CPP/7zip/UI/FileManager/AboutDialog.cpp
new file mode 100644
index 0000000..efc74cc
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/AboutDialog.cpp
@@ -0,0 +1,81 @@
+// AboutDialog.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../MyVersion.h"
+
+#include "../Common/LoadCodecs.h"
+
+#include "AboutDialog.h"
+#include "PropertyNameRes.h"
+
+#include "HelpUtils.h"
+#include "LangUtils.h"
+
+#ifdef Z7_LANG
+static const UInt32 kLangIDs[] =
+{
+ IDT_ABOUT_INFO
+};
+#endif
+
+#define kHomePageURL TEXT("https://www.7-zip.org/")
+#define kHelpTopic "start.htm"
+
+#define LLL_(quote) L##quote
+#define LLL(quote) LLL_(quote)
+
+extern CCodecs *g_CodecsObj;
+
+bool CAboutDialog::OnInit()
+{
+ #ifdef Z7_EXTERNAL_CODECS
+ if (g_CodecsObj)
+ {
+ UString s;
+ g_CodecsObj->GetCodecsErrorMessage(s);
+ if (!s.IsEmpty())
+ MessageBoxW(GetParent(), s, L"7-Zip", MB_ICONERROR);
+ }
+ #endif
+
+ #ifdef Z7_LANG
+ LangSetWindowText(*this, IDD_ABOUT);
+ LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
+ #endif
+ SetItemText(IDT_ABOUT_VERSION, UString("7-Zip " MY_VERSION_CPU));
+ SetItemText(IDT_ABOUT_DATE, LLL(MY_DATE));
+
+ NormalizePosition();
+ return CModalDialog::OnInit();
+}
+
+void CAboutDialog::OnHelp()
+{
+ ShowHelpWindow(kHelpTopic);
+}
+
+bool CAboutDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ LPCTSTR url;
+ switch (buttonID)
+ {
+ case IDB_ABOUT_HOMEPAGE: url = kHomePageURL; break;
+ default:
+ return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
+ }
+
+ #ifdef UNDER_CE
+ SHELLEXECUTEINFO s;
+ memset(&s, 0, sizeof(s));
+ s.cbSize = sizeof(s);
+ s.lpFile = url;
+ ::ShellExecuteEx(&s);
+ #else
+ ::ShellExecute(NULL, NULL, url, NULL, NULL, SW_SHOWNORMAL);
+ #endif
+
+ return true;
+}
diff --git a/CPP/7zip/UI/FileManager/AboutDialog.h b/CPP/7zip/UI/FileManager/AboutDialog.h
new file mode 100644
index 0000000..1d11d74
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/AboutDialog.h
@@ -0,0 +1,19 @@
+// AboutDialog.h
+
+#ifndef ZIP7_INC_ABOUT_DIALOG_H
+#define ZIP7_INC_ABOUT_DIALOG_H
+
+#include "../../../Windows/Control/Dialog.h"
+
+#include "AboutDialogRes.h"
+
+class CAboutDialog: public NWindows::NControl::CModalDialog
+{
+public:
+ virtual bool OnInit() Z7_override;
+ virtual void OnHelp() Z7_override;
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+ INT_PTR Create(HWND wndParent = NULL) { return CModalDialog::Create(IDD_ABOUT, wndParent); }
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/AboutDialog.rc b/CPP/7zip/UI/FileManager/AboutDialog.rc
new file mode 100644
index 0000000..b235df0
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/AboutDialog.rc
@@ -0,0 +1,26 @@
+#include "AboutDialogRes.h"
+#include "../../GuiCommon.rc"
+#include "../../MyVersion.h"
+
+#define xc 144
+#define yc 144
+
+#define y 93
+
+IDI_LOGO ICON "../../UI/FileManager/7zipLogo.ico"
+
+#ifndef SS_REALSIZEIMAGE
+#define SS_REALSIZEIMAGE 0x800
+#endif
+
+IDD_ABOUT DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
+CAPTION "About 7-Zip"
+{
+ DEFPUSHBUTTON "OK", IDOK, bx1, by, bxs, bys
+ PUSHBUTTON "www.7-zip.org", IDB_ABOUT_HOMEPAGE, bx2, by, bxs, bys
+ ICON IDI_LOGO, -1, m, m, 32, 32, SS_REALSIZEIMAGE
+ LTEXT "", IDT_ABOUT_VERSION, m, 54, xc, 8
+ LTEXT "", IDT_ABOUT_DATE, m, 67, xc, 8
+ LTEXT MY_COPYRIGHT, -1, m, 80, xc, 8
+ LTEXT "7-Zip is free software", IDT_ABOUT_INFO, m, y, xc, (by - y - 1)
+}
diff --git a/CPP/7zip/UI/FileManager/AboutDialogRes.h b/CPP/7zip/UI/FileManager/AboutDialogRes.h
new file mode 100644
index 0000000..b416558
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/AboutDialogRes.h
@@ -0,0 +1,8 @@
+#define IDD_ABOUT 2900
+
+#define IDT_ABOUT_INFO 2901
+
+#define IDI_LOGO 100
+#define IDT_ABOUT_VERSION 101
+#define IDT_ABOUT_DATE 102
+#define IDB_ABOUT_HOMEPAGE 110
diff --git a/CPP/7zip/UI/FileManager/Add.bmp b/CPP/7zip/UI/FileManager/Add.bmp
new file mode 100644
index 0000000..a8577fc
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Add.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/Add2.bmp b/CPP/7zip/UI/FileManager/Add2.bmp
new file mode 100644
index 0000000..252fc25
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Add2.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp b/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp
new file mode 100644
index 0000000..b3d354d
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/AltStreamsFolder.cpp
@@ -0,0 +1,952 @@
+// AltStreamsFolder.cpp
+
+#include "StdAfx.h"
+
+#ifdef __MINGW32_VERSION
+// #if !defined(_MSC_VER) && (__GNUC__) && (__GNUC__ < 10)
+// for old mingw
+#include <ddk/ntddk.h>
+#else
+#ifndef Z7_OLD_WIN_SDK
+ #if !defined(_M_IA64)
+ #include <winternl.h>
+ #endif
+#else
+typedef LONG NTSTATUS;
+typedef struct _IO_STATUS_BLOCK {
+ union {
+ NTSTATUS Status;
+ PVOID Pointer;
+ };
+ ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+#endif
+#endif
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileIO.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/PropVariant.h"
+
+#include "../Common/ExtractingFilePath.h"
+
+#include "../Agent/IFolderArchive.h"
+
+#include "AltStreamsFolder.h"
+#include "FSDrives.h"
+#include "FSFolder.h"
+
+#include "SysIconUtils.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NFind;
+using namespace NDir;
+using namespace NName;
+
+#ifndef USE_UNICODE_FSTRING
+int CompareFileNames_ForFolderList(const FChar *s1, const FChar *s2);
+#endif
+
+#ifndef UNDER_CE
+
+namespace NFsFolder
+{
+bool MyGetCompressedFileSizeW(CFSTR path, UInt64 &size);
+}
+
+#endif
+
+namespace NAltStreamsFolder {
+
+static const Byte kProps[] =
+{
+ kpidName,
+ kpidSize,
+ kpidPackSize
+};
+
+static unsigned GetFsParentPrefixSize(const FString &path)
+{
+ if (IsNetworkShareRootPath(path))
+ return 0;
+ const unsigned prefixSize = GetRootPrefixSize(path);
+ if (prefixSize == 0 || prefixSize >= path.Len())
+ return 0;
+ FString parentPath = path;
+ int pos = parentPath.ReverseFind_PathSepar();
+ if (pos < 0)
+ return 0;
+ if (pos == (int)parentPath.Len() - 1)
+ {
+ parentPath.DeleteBack();
+ pos = parentPath.ReverseFind_PathSepar();
+ if (pos < 0)
+ return 0;
+ }
+ if ((unsigned)pos + 1 < prefixSize)
+ return 0;
+ return (unsigned)pos + 1;
+}
+
+HRESULT CAltStreamsFolder::Init(const FString &path /* , IFolderFolder *parentFolder */)
+{
+ // _parentFolder = parentFolder;
+ if (path.Back() != ':')
+ return E_FAIL;
+
+ _pathPrefix = path;
+ _pathBaseFile = path;
+ _pathBaseFile.DeleteBack();
+
+ {
+ CFileInfo fi;
+ if (!fi.Find(_pathBaseFile))
+ return GetLastError_noZero_HRESULT();
+ }
+
+ unsigned prefixSize = GetFsParentPrefixSize(_pathBaseFile);
+ if (prefixSize == 0)
+ return S_OK;
+ FString parentPath = _pathBaseFile;
+ parentPath.DeleteFrom(prefixSize);
+
+ _findChangeNotification.FindFirst(parentPath, false,
+ FILE_NOTIFY_CHANGE_FILE_NAME
+ | FILE_NOTIFY_CHANGE_DIR_NAME
+ | FILE_NOTIFY_CHANGE_ATTRIBUTES
+ | FILE_NOTIFY_CHANGE_SIZE
+ | FILE_NOTIFY_CHANGE_LAST_WRITE
+ /*
+ | FILE_NOTIFY_CHANGE_LAST_ACCESS
+ | FILE_NOTIFY_CHANGE_CREATION
+ | FILE_NOTIFY_CHANGE_SECURITY
+ */
+ );
+ /*
+ if (_findChangeNotification.IsHandleAllocated())
+ return S_OK;
+ return GetLastError();
+ */
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CAltStreamsFolder::LoadItems())
+{
+ Int32 dummy;
+ WasChanged(&dummy);
+ Clear();
+
+ CStreamEnumerator enumerator(_pathBaseFile);
+
+ CStreamInfo si;
+ for (;;)
+ {
+ bool found;
+ if (!enumerator.Next(si, found))
+ {
+ // if (GetLastError() == ERROR_ACCESS_DENIED)
+ // break;
+ // return E_FAIL;
+ break;
+ }
+ if (!found)
+ break;
+ if (si.IsMainStream())
+ continue;
+ CAltStream ss;
+ ss.Name = si.GetReducedName();
+ if (!ss.Name.IsEmpty() && ss.Name[0] == ':')
+ ss.Name.Delete(0);
+
+ ss.Size = si.Size;
+ ss.PackSize_Defined = false;
+ ss.PackSize = si.Size;
+ Streams.Add(ss);
+ }
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CAltStreamsFolder::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = Streams.Size();
+ return S_OK;
+}
+
+#ifdef USE_UNICODE_FSTRING
+
+Z7_COM7F_IMF(CAltStreamsFolder::GetItemPrefix(UInt32 /* index */, const wchar_t **name, unsigned *len))
+{
+ *name = NULL;
+ *len = 0;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CAltStreamsFolder::GetItemName(UInt32 index, const wchar_t **name, unsigned *len))
+{
+ *name = NULL;
+ *len = 0;
+ {
+ const CAltStream &ss = Streams[index];
+ *name = ss.Name;
+ *len = ss.Name.Len();
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF2(UInt64, CAltStreamsFolder::GetItemSize(UInt32 index))
+{
+ return Streams[index].Size;
+}
+
+#endif
+
+
+Z7_COM7F_IMF(CAltStreamsFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+ {
+ CAltStream &ss = Streams[index];
+ switch (propID)
+ {
+ case kpidIsDir: prop = false; break;
+ case kpidIsAltStream: prop = true; break;
+ case kpidName: prop = ss.Name; break;
+ case kpidSize: prop = ss.Size; break;
+ case kpidPackSize:
+ #ifdef UNDER_CE
+ prop = ss.Size;
+ #else
+ if (!ss.PackSize_Defined)
+ {
+ ss.PackSize_Defined = true;
+ if (!NFsFolder::MyGetCompressedFileSizeW(_pathPrefix + us2fs(ss.Name), ss.PackSize))
+ ss.PackSize = ss.Size;
+ }
+ prop = ss.PackSize;
+ #endif
+ break;
+ }
+ }
+
+ prop.Detach(value);
+ return S_OK;
+}
+
+
+// returns Position of extension including '.'
+
+static inline const wchar_t *GetExtensionPtr(const UString &name)
+{
+ const int dotPos = name.ReverseFind_Dot();
+ return name.Ptr(dotPos < 0 ? name.Len() : (unsigned)dotPos);
+}
+
+Z7_COM7F_IMF2(Int32, CAltStreamsFolder::CompareItems(UInt32 index1, UInt32 index2, PROPID propID, Int32 /* propIsRaw */))
+{
+ const CAltStream &ss1 = Streams[index1];
+ const CAltStream &ss2 = Streams[index2];
+
+ switch (propID)
+ {
+ case kpidName:
+ {
+ return CompareFileNames_ForFolderList(ss1.Name, ss2.Name);
+ // return MyStringCompareNoCase(ss1.Name, ss2.Name);
+ }
+ case kpidSize:
+ return MyCompare(ss1.Size, ss2.Size);
+ case kpidPackSize:
+ {
+ #ifdef UNDER_CE
+ return MyCompare(ss1.Size, ss2.Size);
+ #else
+ // PackSize can be undefined here
+ return MyCompare(
+ ss1.PackSize,
+ ss2.PackSize);
+ #endif
+ }
+
+ case kpidExtension:
+ return CompareFileNames_ForFolderList(
+ GetExtensionPtr(ss1.Name),
+ GetExtensionPtr(ss2.Name));
+ }
+
+ return 0;
+}
+
+Z7_COM7F_IMF(CAltStreamsFolder::BindToFolder(UInt32 /* index */, IFolderFolder **resultFolder))
+{
+ *resultFolder = NULL;
+ return E_INVALIDARG;
+}
+
+Z7_COM7F_IMF(CAltStreamsFolder::BindToFolder(const wchar_t * /* name */, IFolderFolder **resultFolder))
+{
+ *resultFolder = NULL;
+ return E_INVALIDARG;
+}
+
+// static CFSTR const kSuperPrefix = FTEXT("\\\\?\\");
+
+Z7_COM7F_IMF(CAltStreamsFolder::BindToParentFolder(IFolderFolder **resultFolder))
+{
+ *resultFolder = NULL;
+ /*
+ if (_parentFolder)
+ {
+ CMyComPtr<IFolderFolder> parentFolder = _parentFolder;
+ *resultFolder = parentFolder.Detach();
+ return S_OK;
+ }
+ */
+
+ if (IsDriveRootPath_SuperAllowed(_pathBaseFile))
+ {
+ CFSDrives *drivesFolderSpec = new CFSDrives;
+ CMyComPtr<IFolderFolder> drivesFolder = drivesFolderSpec;
+ drivesFolderSpec->Init();
+ *resultFolder = drivesFolder.Detach();
+ return S_OK;
+ }
+
+ /*
+ parentPath.DeleteFrom(pos + 1);
+
+ if (parentPath == kSuperPrefix)
+ {
+ #ifdef UNDER_CE
+ *resultFolder = 0;
+ #else
+ CFSDrives *drivesFolderSpec = new CFSDrives;
+ CMyComPtr<IFolderFolder> drivesFolder = drivesFolderSpec;
+ drivesFolderSpec->Init(false, true);
+ *resultFolder = drivesFolder.Detach();
+ #endif
+ return S_OK;
+ }
+
+ FString parentPathReduced = parentPath.Left(pos);
+
+ #ifndef UNDER_CE
+ pos = parentPathReduced.ReverseFind_PathSepar();
+ if (pos == 1)
+ {
+ if (!IS_PATH_SEPAR_CHAR(parentPath[0]))
+ return E_FAIL;
+ CNetFolder *netFolderSpec = new CNetFolder;
+ CMyComPtr<IFolderFolder> netFolder = netFolderSpec;
+ netFolderSpec->Init(fs2us(parentPath));
+ *resultFolder = netFolder.Detach();
+ return S_OK;
+ }
+ #endif
+
+ CFSFolder *parentFolderSpec = new CFSFolder;
+ CMyComPtr<IFolderFolder> parentFolder = parentFolderSpec;
+ RINOK(parentFolderSpec->Init(parentPath, 0));
+ *resultFolder = parentFolder.Detach();
+ */
+
+ return S_OK;
+}
+
+IMP_IFolderFolder_Props(CAltStreamsFolder)
+
+Z7_COM7F_IMF(CAltStreamsFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidType: prop = "AltStreamsFolder"; break;
+ case kpidPath: prop = fs2us(_pathPrefix); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CAltStreamsFolder::WasChanged(Int32 *wasChanged))
+{
+ bool wasChangedMain = false;
+ for (;;)
+ {
+ if (!_findChangeNotification.IsHandleAllocated())
+ {
+ *wasChanged = BoolToInt(false);
+ return S_OK;
+ }
+
+ DWORD waitResult = ::WaitForSingleObject(_findChangeNotification, 0);
+ bool wasChangedLoc = (waitResult == WAIT_OBJECT_0);
+ if (wasChangedLoc)
+ {
+ _findChangeNotification.FindNext();
+ wasChangedMain = true;
+ }
+ else
+ break;
+ }
+ *wasChanged = BoolToInt(wasChangedMain);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CAltStreamsFolder::Clone(IFolderFolder **resultFolder))
+{
+ CAltStreamsFolder *folderSpec = new CAltStreamsFolder;
+ CMyComPtr<IFolderFolder> folderNew = folderSpec;
+ folderSpec->Init(_pathPrefix);
+ *resultFolder = folderNew.Detach();
+ return S_OK;
+}
+
+void CAltStreamsFolder::GetAbsPath(const wchar_t *name, FString &absPath)
+{
+ absPath.Empty();
+ if (!IsAbsolutePath(name))
+ absPath += _pathPrefix;
+ absPath += us2fs(name);
+}
+
+
+
+static HRESULT SendMessageError(IFolderOperationsExtractCallback *callback,
+ const wchar_t *message, const FString &fileName)
+{
+ UString s = message;
+ s += " : ";
+ s += fs2us(fileName);
+ return callback->ShowMessage(s);
+}
+
+static HRESULT SendMessageError(IFolderArchiveUpdateCallback *callback,
+ const wchar_t *message, const FString &fileName)
+{
+ UString s = message;
+ s += " : ";
+ s += fs2us(fileName);
+ return callback->UpdateErrorMessage(s);
+}
+
+static HRESULT SendMessageError(IFolderOperationsExtractCallback *callback,
+ const char *message, const FString &fileName)
+{
+ return SendMessageError(callback, MultiByteToUnicodeString(message), fileName);
+}
+
+/*
+static HRESULT SendMessageError(IFolderArchiveUpdateCallback *callback,
+ const char *message, const FString &fileName)
+{
+ return SendMessageError(callback, MultiByteToUnicodeString(message), fileName);
+}
+*/
+
+Z7_COM7F_IMF(CAltStreamsFolder::CreateFolder(const wchar_t * /* name */, IProgress * /* progress */))
+{
+ return E_NOTIMPL;
+}
+
+Z7_COM7F_IMF(CAltStreamsFolder::CreateFile(const wchar_t *name, IProgress * /* progress */))
+{
+ FString absPath;
+ GetAbsPath(name, absPath);
+ NIO::COutFile outFile;
+ if (!outFile.Create(absPath, false))
+ return GetLastError_noZero_HRESULT();
+ return S_OK;
+}
+
+static UString GetLastErrorMessage()
+{
+ return NError::MyFormatMessage(GetLastError_noZero_HRESULT());
+}
+
+static HRESULT UpdateFile(NFsFolder::CCopyStateIO &state, CFSTR inPath, CFSTR outPath, IFolderArchiveUpdateCallback *callback)
+{
+ if (NFind::DoesFileOrDirExist(outPath))
+ {
+ RINOK(SendMessageError(callback, NError::MyFormatMessage(ERROR_ALREADY_EXISTS), FString(outPath)))
+ CFileInfo fi;
+ if (fi.Find(inPath))
+ {
+ if (state.TotalSize >= fi.Size)
+ state.TotalSize -= fi.Size;
+ }
+ return S_OK;
+ }
+
+ {
+ if (callback)
+ RINOK(callback->CompressOperation(fs2us(inPath)))
+ RINOK(state.MyCopyFile(inPath, outPath))
+ if (state.ErrorFileIndex >= 0)
+ {
+ if (state.ErrorMessage.IsEmpty())
+ state.ErrorMessage = GetLastErrorMessage();
+ FString errorName;
+ if (state.ErrorFileIndex == 0)
+ errorName = inPath;
+ else
+ errorName = outPath;
+ if (callback)
+ RINOK(SendMessageError(callback, state.ErrorMessage, errorName))
+ }
+ if (callback)
+ RINOK(callback->OperationResult(0))
+ }
+
+ return S_OK;
+}
+
+EXTERN_C_BEGIN
+
+typedef enum
+{
+ Z7_WIN_FileRenameInformation = 10
+}
+Z7_WIN_FILE_INFORMATION_CLASS;
+
+
+typedef struct
+{
+ // #if (_WIN32_WINNT >= _WIN32_WINNT_WIN10_RS1)
+ union
+ {
+ BOOLEAN ReplaceIfExists; // FileRenameInformation
+ ULONG Flags; // FileRenameInformationEx
+ } DUMMYUNIONNAME;
+ // #else
+ // BOOLEAN ReplaceIfExists;
+ // #endif
+ HANDLE RootDirectory;
+ ULONG FileNameLength;
+ WCHAR FileName[1];
+} Z7_WIN_FILE_RENAME_INFORMATION;
+
+#if (_WIN32_WINNT >= 0x0500) && !defined(_M_IA64)
+#define Z7_WIN_NTSTATUS NTSTATUS
+#define Z7_WIN_IO_STATUS_BLOCK IO_STATUS_BLOCK
+#else
+typedef LONG Z7_WIN_NTSTATUS;
+typedef struct
+{
+ union
+ {
+ Z7_WIN_NTSTATUS Status;
+ PVOID Pointer;
+ } DUMMYUNIONNAME;
+ ULONG_PTR Information;
+} Z7_WIN_IO_STATUS_BLOCK;
+#endif
+
+typedef Z7_WIN_NTSTATUS (WINAPI *Func_NtSetInformationFile)(
+ HANDLE FileHandle,
+ Z7_WIN_IO_STATUS_BLOCK *IoStatusBlock,
+ PVOID FileInformation,
+ ULONG Length,
+ Z7_WIN_FILE_INFORMATION_CLASS FileInformationClass);
+
+// NTAPI
+typedef ULONG (WINAPI *Func_RtlNtStatusToDosError)(Z7_WIN_NTSTATUS Status);
+
+#define MY_STATUS_SUCCESS 0
+
+EXTERN_C_END
+
+// static Func_NtSetInformationFile f_NtSetInformationFile;
+// static bool g_NtSetInformationFile_WasRequested = false;
+
+
+Z7_COM7F_IMF(CAltStreamsFolder::Rename(UInt32 index, const wchar_t *newName, IProgress *progress))
+{
+ const CAltStream &ss = Streams[index];
+ const FString srcPath = _pathPrefix + us2fs(ss.Name);
+
+ const HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll");
+ // if (!g_NtSetInformationFile_WasRequested) {
+ // g_NtSetInformationFile_WasRequested = true;
+ const
+ Func_NtSetInformationFile
+ f_NtSetInformationFile = Z7_GET_PROC_ADDRESS(
+ Func_NtSetInformationFile, ntdll,
+ "NtSetInformationFile");
+ if (f_NtSetInformationFile)
+ {
+ NIO::CInFile inFile;
+ if (inFile.Open_for_FileRenameInformation(srcPath))
+ {
+ UString destPath (':');
+ destPath += newName;
+ const ULONG len = (ULONG)sizeof(wchar_t) * destPath.Len();
+ CByteBuffer buffer(sizeof(Z7_WIN_FILE_RENAME_INFORMATION) + len);
+ // buffer is 4 bytes larger than required.
+ Z7_WIN_FILE_RENAME_INFORMATION *fri = (Z7_WIN_FILE_RENAME_INFORMATION *)(void *)(Byte *)buffer;
+ memset(fri, 0, sizeof(Z7_WIN_FILE_RENAME_INFORMATION));
+ /* DOCS: If ReplaceIfExists is set to TRUE, the rename operation will succeed only
+ if a stream with the same name does not exist or is a zero-length data stream. */
+ fri->ReplaceIfExists = FALSE;
+ fri->RootDirectory = NULL;
+ fri->FileNameLength = len;
+ memcpy(fri->FileName, destPath.Ptr(), len);
+ Z7_WIN_IO_STATUS_BLOCK iosb;
+ const Z7_WIN_NTSTATUS status = f_NtSetInformationFile (inFile.GetHandle(),
+ &iosb, fri, (ULONG)buffer.Size(), Z7_WIN_FileRenameInformation);
+ if (status != MY_STATUS_SUCCESS)
+ {
+ const
+ Func_RtlNtStatusToDosError
+ f_RtlNtStatusToDosError = Z7_GET_PROC_ADDRESS(
+ Func_RtlNtStatusToDosError, ntdll,
+ "RtlNtStatusToDosError");
+ if (f_RtlNtStatusToDosError)
+ {
+ const ULONG res = f_RtlNtStatusToDosError(status);
+ if (res != ERROR_MR_MID_NOT_FOUND)
+ return HRESULT_FROM_WIN32(res);
+ }
+ }
+ return status;
+ }
+ }
+
+ CMyComPtr<IFolderArchiveUpdateCallback> callback;
+ if (progress)
+ {
+ RINOK(progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&callback))
+ }
+
+ if (callback)
+ {
+ RINOK(callback->SetNumFiles(1))
+ RINOK(callback->SetTotal(ss.Size))
+ }
+
+ NFsFolder::CCopyStateIO state;
+ state.Progress = progress;
+ state.TotalSize = 0;
+ state.DeleteSrcFile = true;
+
+ const FString destPath = _pathPrefix + us2fs(newName);
+ return UpdateFile(state, srcPath, destPath, callback);
+}
+
+Z7_COM7F_IMF(CAltStreamsFolder::Delete(const UInt32 *indices, UInt32 numItems,IProgress *progress))
+{
+ RINOK(progress->SetTotal(numItems))
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ const CAltStream &ss = Streams[indices[i]];
+ const FString fullPath = _pathPrefix + us2fs(ss.Name);
+ const bool result = DeleteFileAlways(fullPath);
+ if (!result)
+ return GetLastError_noZero_HRESULT();
+ const UInt64 completed = i;
+ RINOK(progress->SetCompleted(&completed))
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CAltStreamsFolder::SetProperty(UInt32 /* index */, PROPID /* propID */,
+ const PROPVARIANT * /* value */, IProgress * /* progress */))
+{
+ return E_NOTIMPL;
+}
+
+Z7_COM7F_IMF(CAltStreamsFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex))
+{
+ const CAltStream &ss = Streams[index];
+ *iconIndex = 0;
+ int iconIndexTemp;
+ if (GetRealIconIndex(_pathPrefix + us2fs(ss.Name),
+ 0 // fi.Attrib
+ , iconIndexTemp) != 0)
+ {
+ *iconIndex = iconIndexTemp;
+ return S_OK;
+ }
+ return GetLastError_noZero_HRESULT();
+}
+
+/*
+Z7_CLASS_IMP_COM_1(
+ CGetProp
+ , IGetProp
+)
+public:
+ // const CArc *Arc;
+ // UInt32 IndexInArc;
+ UString Name; // relative path
+ UInt64 Size;
+};
+
+Z7_COM7F_IMF(CGetProp::GetProp(PROPID propID, PROPVARIANT *value))
+{
+ if (propID == kpidName)
+ {
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ prop = Name;
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+ }
+ if (propID == kpidSize)
+ {
+ NCOM::CPropVariant prop = Size;
+ prop.Detach(value);
+ return S_OK;
+ }
+ NCOM::CPropVariant prop;
+ prop.Detach(value);
+ return S_OK;
+}
+*/
+
+static HRESULT CopyStream(
+ NFsFolder::CCopyStateIO &state,
+ const FString &srcPath,
+ const CFileInfo &srcFileInfo,
+ const CAltStream &srcAltStream,
+ const FString &destPathSpec,
+ IFolderOperationsExtractCallback *callback)
+{
+ FString destPath = destPathSpec;
+ if (CompareFileNames(destPath, srcPath) == 0)
+ {
+ RINOK(SendMessageError(callback, "Cannot copy file onto itself", destPath))
+ return E_ABORT;
+ }
+
+ Int32 writeAskResult;
+ CMyComBSTR destPathResult;
+ RINOK(callback->AskWrite(
+ fs2us(srcPath),
+ BoolToInt(false),
+ &srcFileInfo.MTime, &srcAltStream.Size,
+ fs2us(destPath),
+ &destPathResult,
+ &writeAskResult))
+
+ if (IntToBool(writeAskResult))
+ {
+ RINOK(callback->SetCurrentFilePath(fs2us(srcPath)))
+ FString destPathNew (us2fs((LPCOLESTR)destPathResult));
+ RINOK(state.MyCopyFile(srcPath, destPathNew))
+ if (state.ErrorFileIndex >= 0)
+ {
+ if (state.ErrorMessage.IsEmpty())
+ state.ErrorMessage = GetLastErrorMessage();
+ FString errorName;
+ if (state.ErrorFileIndex == 0)
+ errorName = srcPath;
+ else
+ errorName = destPathNew;
+ RINOK(SendMessageError(callback, state.ErrorMessage, errorName))
+ return E_ABORT;
+ }
+ state.StartPos += state.CurrentSize;
+ }
+ else
+ {
+ if (state.TotalSize >= srcAltStream.Size)
+ {
+ state.TotalSize -= srcAltStream.Size;
+ RINOK(state.Progress->SetTotal(state.TotalSize))
+ }
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CAltStreamsFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems,
+ Int32 /* includeAltStreams */, Int32 /* replaceAltStreamColon */,
+ const wchar_t *path, IFolderOperationsExtractCallback *callback))
+{
+ if (numItems == 0)
+ return S_OK;
+
+ /*
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IFolderExtractToStreamCallback,
+ ExtractToStreamCallback, callback)
+ if (ExtractToStreamCallback)
+ {
+ Int32 useStreams = 0;
+ if (ExtractToStreamCallback->UseExtractToStream(&useStreams) != S_OK)
+ useStreams = 0;
+ if (useStreams == 0)
+ ExtractToStreamCallback.Release();
+ }
+ */
+
+ UInt64 totalSize = 0;
+ {
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ totalSize += Streams[indices[i]].Size;
+ }
+ RINOK(callback->SetTotal(totalSize))
+ RINOK(callback->SetNumFiles(numItems))
+ }
+
+ /*
+ if (ExtractToStreamCallback)
+ {
+ CGetProp *GetProp_Spec = new CGetProp;
+ CMyComPtr<IGetProp> GetProp= GetProp_Spec;
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ UInt32 index = indices[i];
+ const CAltStream &ss = Streams[index];
+ GetProp_Spec->Name = ss.Name;
+ GetProp_Spec->Size = ss.Size;
+ CMyComPtr<ISequentialOutStream> outStream;
+ RINOK(ExtractToStreamCallback->GetStream7(GetProp_Spec->Name, BoolToInt(false), &outStream,
+ NArchive::NExtract::NAskMode::kExtract, GetProp)); // isDir
+ FString srcPath;
+ GetFullPath(ss, srcPath);
+ RINOK(ExtractToStreamCallback->PrepareOperation7(NArchive::NExtract::NAskMode::kExtract));
+ RINOK(ExtractToStreamCallback->SetOperationResult7(NArchive::NExtract::NOperationResult::kOK, BoolToInt(false))); // _encrypted
+ // RINOK(CopyStream(state, srcPath, fi, ss, destPath2, callback, completedSize));
+ }
+ return S_OK;
+ }
+ */
+
+ FString destPath (us2fs(path));
+ if (destPath.IsEmpty() /* && !ExtractToStreamCallback */)
+ return E_INVALIDARG;
+
+ const bool isAltDest = NName::IsAltPathPrefix(destPath);
+ const bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back()));
+
+ if (isDirectPath)
+ {
+ if (numItems > 1)
+ return E_INVALIDARG;
+ }
+
+ CFileInfo fi;
+ if (!fi.Find(_pathBaseFile))
+ return GetLastError_noZero_HRESULT();
+
+ NFsFolder::CCopyStateIO state;
+ state.Progress = callback;
+ state.DeleteSrcFile = IntToBool(moveMode);
+ state.TotalSize = totalSize;
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ const UInt32 index = indices[i];
+ const CAltStream &ss = Streams[index];
+ FString destPath2 = destPath;
+ if (!isDirectPath)
+ destPath2 += us2fs(Get_Correct_FsFile_Name(ss.Name));
+ FString srcPath;
+ GetFullPath(ss, srcPath);
+ RINOK(CopyStream(state, srcPath, fi, ss, destPath2, callback))
+ }
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CAltStreamsFolder::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */,
+ const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */))
+{
+ /*
+ if (numItems == 0)
+ return S_OK;
+
+ CMyComPtr<IFolderArchiveUpdateCallback> callback;
+ if (progress)
+ {
+ RINOK(progress->QueryInterface(IID_IFolderArchiveUpdateCallback, (void **)&callback));
+ }
+
+ if (CompareFileNames(fromFolderPath, fs2us(_pathPrefix)) == 0)
+ {
+ RINOK(SendMessageError(callback, "Cannot copy file onto itself", _pathPrefix));
+ return E_ABORT;
+ }
+
+ if (callback)
+ RINOK(callback->SetNumFiles(numItems));
+
+ UInt64 totalSize = 0;
+
+ UInt32 i;
+
+ FString path;
+ for (i = 0; i < numItems; i++)
+ {
+ path = us2fs(fromFolderPath);
+ path += us2fs(itemsPaths[i]);
+
+ CFileInfo fi;
+ if (!fi.Find(path))
+ return ::GetLastError();
+ if (fi.IsDir())
+ return E_NOTIMPL;
+ totalSize += fi.Size;
+ }
+
+ RINOK(progress->SetTotal(totalSize));
+
+ // UInt64 completedSize = 0;
+
+ NFsFolder::CCopyStateIO state;
+ state.Progress = progress;
+ state.DeleteSrcFile = IntToBool(moveMode);
+ state.TotalSize = totalSize;
+
+ // we need to clear READ-ONLY of parent before creating alt stream
+ {
+ DWORD attrib = GetFileAttrib(_pathBaseFile);
+ if (attrib != INVALID_FILE_ATTRIBUTES
+ && (attrib & FILE_ATTRIBUTE_READONLY) != 0)
+ {
+ if (!SetFileAttrib(_pathBaseFile, attrib & ~FILE_ATTRIBUTE_READONLY))
+ {
+ if (callback)
+ {
+ RINOK(SendMessageError(callback, GetLastErrorMessage(), _pathBaseFile));
+ return S_OK;
+ }
+ return Return_LastError_or_FAIL();
+ }
+ }
+ }
+
+ for (i = 0; i < numItems; i++)
+ {
+ path = us2fs(fromFolderPath);
+ path += us2fs(itemsPaths[i]);
+
+ FString destPath = _pathPrefix + us2fs(itemsPaths[i]);
+
+ RINOK(UpdateFile(state, path, destPath, callback));
+ }
+
+ return S_OK;
+ */
+ return E_NOTIMPL;
+}
+
+Z7_COM7F_IMF(CAltStreamsFolder::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */))
+{
+ return E_NOTIMPL;
+}
+
+}
diff --git a/CPP/7zip/UI/FileManager/AltStreamsFolder.h b/CPP/7zip/UI/FileManager/AltStreamsFolder.h
new file mode 100644
index 0000000..ccb6d6f
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/AltStreamsFolder.h
@@ -0,0 +1,92 @@
+// AltStreamsFolder.h
+
+#ifndef ZIP7_INC_ALT_STREAMS_FOLDER_H
+#define ZIP7_INC_ALT_STREAMS_FOLDER_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../../Windows/FileFind.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "IFolder.h"
+
+namespace NAltStreamsFolder {
+
+class CAltStreamsFolder;
+
+struct CAltStream
+{
+ UInt64 Size;
+ UInt64 PackSize;
+ bool PackSize_Defined;
+ UString Name;
+};
+
+
+class CAltStreamsFolder Z7_final:
+ public IFolderFolder,
+ public IFolderCompare,
+ #ifdef USE_UNICODE_FSTRING
+ public IFolderGetItemName,
+ #endif
+ public IFolderWasChanged,
+ public IFolderOperations,
+ // public IFolderOperationsDeleteToRecycleBin,
+ public IFolderClone,
+ public IFolderGetSystemIconIndex,
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(IFolderFolder)
+ Z7_COM_QI_ENTRY(IFolderCompare)
+ #ifdef USE_UNICODE_FSTRING
+ Z7_COM_QI_ENTRY(IFolderGetItemName)
+ #endif
+ Z7_COM_QI_ENTRY(IFolderWasChanged)
+ // Z7_COM_QI_ENTRY(IFolderOperationsDeleteToRecycleBin)
+ Z7_COM_QI_ENTRY(IFolderOperations)
+ Z7_COM_QI_ENTRY(IFolderClone)
+ Z7_COM_QI_ENTRY(IFolderGetSystemIconIndex)
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(IFolderFolder)
+ Z7_IFACE_COM7_IMP(IFolderCompare)
+ #ifdef USE_UNICODE_FSTRING
+ Z7_IFACE_COM7_IMP(IFolderGetItemName)
+ #endif
+ Z7_IFACE_COM7_IMP(IFolderWasChanged)
+ Z7_IFACE_COM7_IMP(IFolderOperations)
+ Z7_IFACE_COM7_IMP(IFolderClone)
+ Z7_IFACE_COM7_IMP(IFolderGetSystemIconIndex)
+
+ FString _pathBaseFile; // folder
+ FString _pathPrefix; // folder:
+
+ CObjectVector<CAltStream> Streams;
+ // CMyComPtr<IFolderFolder> _parentFolder;
+
+ NWindows::NFile::NFind::CFindChangeNotification _findChangeNotification;
+
+ HRESULT GetItemFullSize(unsigned index, UInt64 &size, IProgress *progress);
+ void GetAbsPath(const wchar_t *name, FString &absPath);
+
+public:
+ // path must be with ':' at tail
+ HRESULT Init(const FString &path /* , IFolderFolder *parentFolder */);
+
+ void GetFullPath(const CAltStream &item, FString &path) const
+ {
+ path = _pathPrefix;
+ path += us2fs(item.Name);
+ }
+
+ void Clear()
+ {
+ Streams.Clear();
+ }
+};
+
+}
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/App.cpp b/CPP/7zip/UI/FileManager/App.cpp
new file mode 100644
index 0000000..3461c92
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/App.cpp
@@ -0,0 +1,998 @@
+// App.cpp
+
+#include "StdAfx.h"
+
+#include "resource.h"
+#include "OverwriteDialogRes.h"
+
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/PropVariantConv.h"
+
+/*
+#include "Windows/COM.h"
+#include "Windows/Error.h"
+#include "Windows/FileDir.h"
+
+#include "Windows/PropVariant.h"
+#include "Windows/Thread.h"
+*/
+
+#include "App.h"
+#include "CopyDialog.h"
+#include "ExtractCallback.h"
+#include "FormatUtils.h"
+#include "IFolder.h"
+#include "LangUtils.h"
+#include "MyLoadMenu.h"
+#include "RegistryUtils.h"
+#include "ViewSettings.h"
+
+#include "PropertyNameRes.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+using namespace NFind;
+using namespace NName;
+
+extern DWORD g_ComCtl32Version;
+extern HINSTANCE g_hInstance;
+
+#define kTempDirPrefix FTEXT("7zE")
+
+void CPanelCallbackImp::OnTab()
+{
+ if (g_App.NumPanels != 1)
+ _app->Panels[1 - _index].SetFocusToList();
+ _app->RefreshTitle();
+}
+
+void CPanelCallbackImp::SetFocusToPath(unsigned index)
+{
+ unsigned newPanelIndex = index;
+ if (g_App.NumPanels == 1)
+ newPanelIndex = g_App.LastFocusedPanel;
+ _app->RefreshTitle();
+ _app->Panels[newPanelIndex]._headerComboBox.SetFocus();
+ _app->Panels[newPanelIndex]._headerComboBox.ShowDropDown();
+}
+
+
+void CPanelCallbackImp::OnCopy(bool move, bool copyToSame) { _app->OnCopy(move, copyToSame, _index); }
+void CPanelCallbackImp::OnSetSameFolder() { _app->OnSetSameFolder(_index); }
+void CPanelCallbackImp::OnSetSubFolder() { _app->OnSetSubFolder(_index); }
+void CPanelCallbackImp::PanelWasFocused() { _app->SetFocusedPanel(_index); _app->RefreshTitlePanel(_index); }
+void CPanelCallbackImp::DragBegin() { _app->DragBegin(_index); }
+void CPanelCallbackImp::DragEnd() { _app->DragEnd(); }
+void CPanelCallbackImp::RefreshTitle(bool always) { _app->RefreshTitlePanel(_index, always); }
+
+void CApp::ReloadLangItems()
+{
+ LangString(IDS_N_SELECTED_ITEMS, LangString_N_SELECTED_ITEMS);
+}
+
+void CApp::SetListSettings()
+{
+ CFmSettings st;
+ st.Load();
+
+ ShowSystemMenu = st.ShowSystemMenu;
+
+ DWORD extendedStyle = LVS_EX_HEADERDRAGDROP;
+ if (st.FullRow)
+ extendedStyle |= LVS_EX_FULLROWSELECT;
+ if (st.ShowGrid)
+ extendedStyle |= LVS_EX_GRIDLINES;
+
+ if (st.SingleClick)
+ {
+ extendedStyle |= LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT;
+ /*
+ if (ReadUnderline())
+ extendedStyle |= LVS_EX_UNDERLINEHOT;
+ */
+ }
+
+ for (unsigned i = 0; i < kNumPanelsMax; i++)
+ {
+ CPanel &panel = Panels[i];
+ panel._mySelectMode = st.AlternativeSelection;
+ panel._showDots = st.ShowDots;
+ panel._showRealFileIcons = st.ShowRealFileIcons;
+ panel._exStyle = extendedStyle;
+
+ LONG_PTR style = panel._listView.GetStyle();
+ if (st.AlternativeSelection)
+ style |= LVS_SINGLESEL;
+ else
+ style &= ~(LONG_PTR)(DWORD)LVS_SINGLESEL;
+ panel._listView.SetStyle(style);
+ panel.SetExtendedStyle();
+ }
+}
+
+#ifndef ILC_COLOR32
+#define ILC_COLOR32 0x0020
+#endif
+
+HRESULT CApp::CreateOnePanel(unsigned panelIndex, const UString &mainPath, const UString &arcFormat,
+ bool needOpenArc,
+ COpenResult &openRes)
+{
+ if (Panels[panelIndex].PanelCreated)
+ return S_OK;
+
+ m_PanelCallbackImp[panelIndex].Init(this, panelIndex);
+
+ UString path;
+ if (mainPath.IsEmpty())
+ {
+ if (!::ReadPanelPath(panelIndex, path))
+ path.Empty();
+ }
+ else
+ path = mainPath;
+
+ const unsigned id = 1000 + 100 * panelIndex; // check it
+
+ return Panels[panelIndex].Create(_window, _window,
+ id, path, arcFormat, &m_PanelCallbackImp[panelIndex], &AppState,
+ needOpenArc,
+ openRes);
+}
+
+
+static void CreateToolbar(HWND parent,
+ NControl::CImageList &imageList,
+ NControl::CToolBar &toolBar,
+ bool largeButtons)
+{
+ toolBar.Attach(::CreateWindowEx(0, TOOLBARCLASSNAME, NULL, 0
+ | WS_CHILD
+ | WS_VISIBLE
+ | TBSTYLE_FLAT
+ | TBSTYLE_TOOLTIPS
+ | TBSTYLE_WRAPABLE
+ // | TBSTYLE_AUTOSIZE
+ // | CCS_NORESIZE
+ #ifdef UNDER_CE
+ | CCS_NODIVIDER
+ | CCS_NOPARENTALIGN
+ #endif
+ ,0,0,0,0, parent, NULL, g_hInstance, NULL));
+
+ // TB_BUTTONSTRUCTSIZE message, which is required for
+ // backward compatibility.
+ toolBar.ButtonStructSize();
+
+ imageList.Create(
+ largeButtons ? 48: 24,
+ largeButtons ? 36: 24,
+ ILC_MASK | ILC_COLOR32, 0, 0);
+ toolBar.SetImageList(0, imageList);
+}
+
+
+struct CButtonInfo
+{
+ int CommandID;
+ UINT BitmapResID;
+ UINT Bitmap2ResID;
+ UINT StringResID;
+
+ UString GetText() const { return LangString(StringResID); }
+};
+
+static const CButtonInfo g_StandardButtons[] =
+{
+ { IDM_COPY_TO, IDB_COPY, IDB_COPY2, IDS_BUTTON_COPY },
+ { IDM_MOVE_TO, IDB_MOVE, IDB_MOVE2, IDS_BUTTON_MOVE },
+ { IDM_DELETE, IDB_DELETE, IDB_DELETE2, IDS_BUTTON_DELETE } ,
+ { IDM_PROPERTIES, IDB_INFO, IDB_INFO2, IDS_BUTTON_INFO }
+};
+
+static const CButtonInfo g_ArchiveButtons[] =
+{
+ { kMenuCmdID_Toolbar_Add, IDB_ADD, IDB_ADD2, IDS_ADD },
+ { kMenuCmdID_Toolbar_Extract, IDB_EXTRACT, IDB_EXTRACT2, IDS_EXTRACT },
+ { kMenuCmdID_Toolbar_Test, IDB_TEST, IDB_TEST2, IDS_TEST }
+};
+
+static bool SetButtonText(int commandID, const CButtonInfo *buttons, unsigned numButtons, UString &s)
+{
+ for (unsigned i = 0; i < numButtons; i++)
+ {
+ const CButtonInfo &b = buttons[i];
+ if (b.CommandID == commandID)
+ {
+ s = b.GetText();
+ return true;
+ }
+ }
+ return false;
+}
+
+static void SetButtonText(int commandID, UString &s)
+{
+ if (SetButtonText(commandID, g_StandardButtons, Z7_ARRAY_SIZE(g_StandardButtons), s))
+ return;
+ SetButtonText(commandID, g_ArchiveButtons, Z7_ARRAY_SIZE(g_ArchiveButtons), s);
+}
+
+static void AddButton(
+ NControl::CImageList &imageList,
+ NControl::CToolBar &toolBar,
+ const CButtonInfo &butInfo, bool showText, bool large)
+{
+ TBBUTTON but;
+ but.iBitmap = 0;
+ but.idCommand = butInfo.CommandID;
+ but.fsState = TBSTATE_ENABLED;
+ but.fsStyle = TBSTYLE_BUTTON;
+ but.dwData = 0;
+
+ UString s = butInfo.GetText();
+ but.iString = 0;
+ if (showText)
+ but.iString = (INT_PTR)(LPCWSTR)s;
+
+ but.iBitmap = imageList.GetImageCount();
+ HBITMAP b = ::LoadBitmap(g_hInstance,
+ large ?
+ MAKEINTRESOURCE(butInfo.BitmapResID):
+ MAKEINTRESOURCE(butInfo.Bitmap2ResID));
+ if (b)
+ {
+ imageList.AddMasked(b, RGB(255, 0, 255));
+ ::DeleteObject(b);
+ }
+ #ifdef _UNICODE
+ toolBar.AddButton(1, &but);
+ #else
+ toolBar.AddButtonW(1, &but);
+ #endif
+}
+
+void CApp::ReloadToolbars()
+{
+ _buttonsImageList.Destroy();
+ _toolBar.Destroy();
+
+
+ if (ShowArchiveToolbar || ShowStandardToolbar)
+ {
+ CreateToolbar(_window, _buttonsImageList, _toolBar, LargeButtons);
+ unsigned i;
+ if (ShowArchiveToolbar)
+ for (i = 0; i < Z7_ARRAY_SIZE(g_ArchiveButtons); i++)
+ AddButton(_buttonsImageList, _toolBar, g_ArchiveButtons[i], ShowButtonsLables, LargeButtons);
+ if (ShowStandardToolbar)
+ for (i = 0; i < Z7_ARRAY_SIZE(g_StandardButtons); i++)
+ AddButton(_buttonsImageList, _toolBar, g_StandardButtons[i], ShowButtonsLables, LargeButtons);
+
+ _toolBar.AutoSize();
+ }
+}
+
+void CApp::SaveToolbarChanges()
+{
+ SaveToolbar();
+ ReloadToolbars();
+ MoveSubWindows();
+}
+
+
+HRESULT CApp::Create(HWND hwnd, const UString &mainPath, const UString &arcFormat, int xSizes[2], bool needOpenArc, COpenResult &openRes)
+{
+ _window.Attach(hwnd);
+
+ #ifdef UNDER_CE
+ _commandBar.Create(g_hInstance, hwnd, 1);
+ #endif
+
+ MyLoadMenu(false); // needResetMenu
+
+ #ifdef UNDER_CE
+ _commandBar.AutoSize();
+ #endif
+
+ ReadToolbar();
+ ReloadToolbars();
+
+ unsigned i;
+ for (i = 0; i < kNumPanelsMax; i++)
+ Panels[i].PanelCreated = false;
+
+ AppState.Read();
+
+ SetListSettings();
+
+ if (LastFocusedPanel >= kNumPanelsMax)
+ LastFocusedPanel = 0;
+ // ShowDeletedFiles = Read_ShowDeleted();
+
+ CListMode listMode;
+ listMode.Read();
+
+ for (i = 0; i < kNumPanelsMax; i++)
+ {
+ CPanel &panel = Panels[i];
+ panel._listViewMode = listMode.Panels[i];
+ panel._xSize = xSizes[i];
+ panel._flatModeForArc = ReadFlatView(i);
+ }
+
+ for (i = 0; i < kNumPanelsMax; i++)
+ {
+ unsigned panelIndex = i;
+ if (needOpenArc && LastFocusedPanel == 1)
+ panelIndex = 1 - i;
+
+ bool isMainPanel = (panelIndex == LastFocusedPanel);
+
+ if (NumPanels > 1 || isMainPanel)
+ {
+ if (NumPanels == 1)
+ Panels[panelIndex]._xSize = xSizes[0] + xSizes[1];
+
+ COpenResult openRes2;
+ UString path;
+ if (isMainPanel)
+ path = mainPath;
+
+ RINOK(CreateOnePanel(panelIndex, path, arcFormat,
+ isMainPanel && needOpenArc,
+ *(isMainPanel ? &openRes : &openRes2)))
+
+ if (isMainPanel)
+ {
+ if (needOpenArc && !openRes.ArchiveIsOpened)
+ return S_OK;
+ }
+ }
+ }
+
+ SetFocusedPanel(LastFocusedPanel);
+ Panels[LastFocusedPanel].SetFocusToList();
+ return S_OK;
+}
+
+
+HRESULT CApp::SwitchOnOffOnePanel()
+{
+ if (NumPanels == 1)
+ {
+ NumPanels++;
+ COpenResult openRes;
+ RINOK(CreateOnePanel(1 - LastFocusedPanel, UString(), UString(),
+ false, // needOpenArc
+ openRes))
+ Panels[1 - LastFocusedPanel].Enable(true);
+ Panels[1 - LastFocusedPanel].Show(SW_SHOWNORMAL);
+ }
+ else
+ {
+ NumPanels--;
+ Panels[1 - LastFocusedPanel].Enable(false);
+ Panels[1 - LastFocusedPanel].Show(SW_HIDE);
+ }
+ MoveSubWindows();
+ return S_OK;
+}
+
+void CApp::Save()
+{
+ AppState.Save();
+ CListMode listMode;
+
+ for (unsigned i = 0; i < kNumPanelsMax; i++)
+ {
+ const CPanel &panel = Panels[i];
+ UString path;
+ if (panel._parentFolders.IsEmpty())
+ path = panel._currentFolderPrefix;
+ else
+ path = panel._parentFolders[0].ParentFolderPath;
+ // GetFolderPath(panel._parentFolders[0].ParentFolder);
+ SavePanelPath(i, path);
+ listMode.Panels[i] = panel.GetListViewMode();
+ SaveFlatView(i, panel._flatModeForArc);
+ }
+
+ listMode.Save();
+ // Save_ShowDeleted(ShowDeletedFiles);
+}
+
+void CApp::Release()
+{
+ // It's for unloading COM dll's: don't change it.
+ for (unsigned i = 0; i < kNumPanelsMax; i++)
+ Panels[i].Release();
+}
+
+// reduces path to part that exists on disk (or root prefix of path)
+// output path is normalized (with WCHAR_PATH_SEPARATOR)
+static void Reduce_Path_To_RealFileSystemPath(UString &path)
+{
+ unsigned prefixSize = GetRootPrefixSize(path);
+
+ while (!path.IsEmpty())
+ {
+ if (NFind::DoesDirExist_FollowLink(us2fs(path)))
+ {
+ NName::NormalizeDirPathPrefix(path);
+ break;
+ }
+ int pos = path.ReverseFind_PathSepar();
+ if (pos < 0)
+ {
+ path.Empty();
+ break;
+ }
+ path.DeleteFrom((unsigned)(pos + 1));
+ if ((unsigned)pos + 1 == prefixSize)
+ break;
+ path.DeleteFrom((unsigned)pos);
+ }
+}
+
+// returns: true, if such dir exists or is root
+/*
+static bool CheckFolderPath(const UString &path)
+{
+ UString pathReduced = path;
+ Reduce_Path_To_RealFileSystemPath(pathReduced);
+ return (pathReduced == path);
+}
+*/
+
+extern UString ConvertSizeToString(UInt64 value);
+
+static void AddSizeValue(UString &s, UInt64 size)
+{
+ s += MyFormatNew(IDS_FILE_SIZE, ConvertSizeToString(size));
+}
+
+static void AddValuePair1(UString &s, UINT resourceID, UInt64 size)
+{
+ AddLangString(s, resourceID);
+ s += ": ";
+ AddSizeValue(s, size);
+ s.Add_LF();
+}
+
+void AddValuePair2(UString &s, UINT resourceID, UInt64 num, UInt64 size);
+void AddValuePair2(UString &s, UINT resourceID, UInt64 num, UInt64 size)
+{
+ if (num == 0)
+ return;
+ AddLangString(s, resourceID);
+ s += ": ";
+ s += ConvertSizeToString(num);
+
+ if (size != (UInt64)(Int64)-1)
+ {
+ s += " ( ";
+ AddSizeValue(s, size);
+ s += " )";
+ }
+ s.Add_LF();
+}
+
+static void AddPropValueToSum(IFolderFolder *folder, UInt32 index, PROPID propID, UInt64 &sum)
+{
+ if (sum == (UInt64)(Int64)-1)
+ return;
+ NCOM::CPropVariant prop;
+ folder->GetProperty(index, propID, &prop);
+ UInt64 val = 0;
+ if (ConvertPropVariantToUInt64(prop, val))
+ sum += val;
+ else
+ sum = (UInt64)(Int64)-1;
+}
+
+UString CPanel::GetItemsInfoString(const CRecordVector<UInt32> &indices)
+{
+ UString info;
+ UInt64 numDirs, numFiles, filesSize, foldersSize;
+ numDirs = numFiles = filesSize = foldersSize = 0;
+
+ unsigned i;
+ for (i = 0; i < indices.Size(); i++)
+ {
+ const UInt32 index = indices[i];
+ if (IsItem_Folder(index))
+ {
+ AddPropValueToSum(_folder, index, kpidSize, foldersSize);
+ numDirs++;
+ }
+ else
+ {
+ AddPropValueToSum(_folder, index, kpidSize, filesSize);
+ numFiles++;
+ }
+ }
+
+ AddValuePair2(info, IDS_PROP_FOLDERS, numDirs, foldersSize);
+ AddValuePair2(info, IDS_PROP_FILES, numFiles, filesSize);
+ int numDefined = ((foldersSize != (UInt64)(Int64)-1) && foldersSize != 0) ? 1: 0;
+ numDefined += ((filesSize != (UInt64)(Int64)-1) && filesSize != 0) ? 1: 0;
+ if (numDefined == 2)
+ AddValuePair1(info, IDS_PROP_SIZE, filesSize + foldersSize);
+
+ info.Add_LF();
+ info += _currentFolderPrefix;
+
+ for (i = 0; i < indices.Size() && (int)i < (int)kCopyDialog_NumInfoLines - 6; i++)
+ {
+ info.Add_LF();
+ info += " ";
+ const UInt32 index = indices[i];
+ info += GetItemRelPath(index);
+ if (IsItem_Folder(index))
+ info.Add_PathSepar();
+ }
+ if (i != indices.Size())
+ {
+ info.Add_LF();
+ info += " ...";
+ }
+ return info;
+}
+
+bool IsCorrectFsName(const UString &name);
+
+
+
+/* Returns true, if path is path that can be used as path for File System functions
+*/
+
+/*
+static bool IsFsPath(const FString &path)
+{
+ if (!IsAbsolutePath(path))
+ return false;
+ unsigned prefixSize = GetRootPrefixSize(path);
+}
+*/
+
+void CApp::OnCopy(bool move, bool copyToSame, unsigned srcPanelIndex)
+{
+ const unsigned destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex);
+ CPanel &srcPanel = Panels[srcPanelIndex];
+ CPanel &destPanel = Panels[destPanelIndex];
+
+ CPanel::CDisableTimerProcessing disableTimerProcessing1(destPanel);
+ CPanel::CDisableTimerProcessing disableTimerProcessing2(srcPanel);
+
+ if (move)
+ {
+ if (!srcPanel.CheckBeforeUpdate(IDS_MOVE))
+ return;
+ }
+ else if (!srcPanel.DoesItSupportOperations())
+ {
+ srcPanel.MessageBox_Error_UnsupportOperation();
+ return;
+ }
+
+ CRecordVector<UInt32> indices;
+ UString destPath;
+ bool useDestPanel = false;
+
+ {
+ if (copyToSame)
+ {
+ const int focusedItem = srcPanel._listView.GetFocusedItem();
+ if (focusedItem < 0)
+ return;
+ const unsigned realIndex = srcPanel.GetRealItemIndex(focusedItem);
+ if (realIndex == kParentIndex)
+ return;
+ indices.Add(realIndex);
+ destPath = srcPanel.GetItemName(realIndex);
+ }
+ else
+ {
+ srcPanel.Get_ItemIndices_OperSmart(indices);
+ if (indices.Size() == 0)
+ return;
+ destPath = destPanel.GetFsPath();
+ if (NumPanels == 1)
+ Reduce_Path_To_RealFileSystemPath(destPath);
+ }
+ }
+
+ UStringVector copyFolders;
+ ReadCopyHistory(copyFolders);
+
+ const bool useFullItemPaths = srcPanel.Is_IO_FS_Folder(); // maybe we need flat also here ??
+
+ {
+ CCopyDialog copyDialog;
+
+ copyDialog.Strings = copyFolders;
+ copyDialog.Value = destPath;
+ LangString(move ? IDS_MOVE : IDS_COPY, copyDialog.Title);
+ LangString(move ? IDS_MOVE_TO : IDS_COPY_TO, copyDialog.Static);
+ copyDialog.Info = srcPanel.GetItemsInfoString(indices);
+
+ if (copyDialog.Create(srcPanel.GetParent()) != IDOK)
+ return;
+
+ destPath = copyDialog.Value;
+ }
+
+ {
+ if (destPath.IsEmpty())
+ {
+ srcPanel.MessageBox_Error_UnsupportOperation();
+ return;
+ }
+
+ UString correctName;
+ if (!srcPanel.CorrectFsPath(destPath, correctName))
+ {
+ srcPanel.MessageBox_Error_HRESULT(E_INVALIDARG);
+ return;
+ }
+
+ if (IsAbsolutePath(destPath))
+ destPath.Empty();
+ else
+ destPath = srcPanel.GetFsPath();
+ destPath += correctName;
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (destPath.Len() > 0 && destPath[0] == '\\')
+ if (destPath.Len() == 1 || destPath[1] != '\\')
+ {
+ srcPanel.MessageBox_Error_UnsupportOperation();
+ return;
+ }
+ #endif
+
+ bool possibleToUseDestPanel = false;
+
+ if (CompareFileNames(destPath, destPanel.GetFsPath()) == 0)
+ {
+ if (NumPanels == 1 || CompareFileNames(destPath, srcPanel.GetFsPath()) == 0)
+ {
+ srcPanel.MessageBox_Error(L"Cannot copy files onto itself");
+ return;
+ }
+
+ if (destPanel.DoesItSupportOperations())
+ possibleToUseDestPanel = true;
+ }
+
+ bool destIsFsPath = false;
+
+ if (possibleToUseDestPanel)
+ {
+ if (destPanel.IsFSFolder() || destPanel.IsAltStreamsFolder())
+ destIsFsPath = true;
+ else if (destPanel.IsFSDrivesFolder() || destPanel.IsRootFolder())
+ {
+ srcPanel.MessageBox_Error_UnsupportOperation();
+ return;
+ }
+ }
+ else
+ {
+ if (IsAltPathPrefix(us2fs(destPath)))
+ {
+ // we allow alt streams dest only to alt stream folder in second panel
+ srcPanel.MessageBox_Error_UnsupportOperation();
+ return;
+ /*
+ FString basePath = us2fs(destPath);
+ basePath.DeleteBack();
+ if (!DoesFileOrDirExist(basePath))
+ {
+ srcPanel.MessageBoxError2Lines(basePath, ERROR_FILE_NOT_FOUND); // GetLastError()
+ return;
+ }
+ destIsFsPath = true;
+ */
+ }
+ else
+ {
+ if (indices.Size() == 1 &&
+ !destPath.IsEmpty() && !IS_PATH_SEPAR(destPath.Back()))
+ {
+ int pos = destPath.ReverseFind_PathSepar();
+ if (pos < 0)
+ {
+ srcPanel.MessageBox_Error_UnsupportOperation();
+ return;
+ }
+ {
+ /*
+ #ifdef _WIN32
+ UString name = destPath.Ptr(pos + 1);
+ if (name.Find(L':') >= 0)
+ {
+ srcPanel.MessageBox_Error_UnsupportOperation();
+ return;
+ }
+ #endif
+ */
+ UString prefix = destPath.Left(pos + 1);
+ if (!CreateComplexDir(us2fs(prefix)))
+ {
+ const HRESULT lastError = GetLastError_noZero_HRESULT();
+ srcPanel.MessageBox_Error_2Lines_Message_HRESULT(prefix, lastError);
+ return;
+ }
+ }
+ // bool isFolder = srcPanael.IsItem_Folder(indices[0]);
+ }
+ else
+ {
+ NName::NormalizeDirPathPrefix(destPath);
+ if (!CreateComplexDir(us2fs(destPath)))
+ {
+ const HRESULT lastError = GetLastError_noZero_HRESULT();
+ srcPanel.MessageBox_Error_2Lines_Message_HRESULT(destPath, lastError);
+ return;
+ }
+ }
+ destIsFsPath = true;
+ }
+ }
+
+ if (!destIsFsPath)
+ useDestPanel = true;
+
+ AddUniqueStringToHeadOfList(copyFolders, destPath);
+ while (copyFolders.Size() > 20)
+ copyFolders.DeleteBack();
+ SaveCopyHistory(copyFolders);
+ }
+
+ bool useSrcPanel = !useDestPanel || !srcPanel.Is_IO_FS_Folder();
+
+ bool useTemp = useSrcPanel && useDestPanel;
+ if (useTemp && NumPanels == 1)
+ {
+ srcPanel.MessageBox_Error_UnsupportOperation();
+ return;
+ }
+
+ CTempDir tempDirectory;
+ FString tempDirPrefix;
+ if (useTemp)
+ {
+ tempDirectory.Create(kTempDirPrefix);
+ tempDirPrefix = tempDirectory.GetPath();
+ NFile::NName::NormalizeDirPathPrefix(tempDirPrefix);
+ }
+
+ CSelectedState srcSelState;
+ CSelectedState destSelState;
+ srcPanel.SaveSelectedState(srcSelState);
+ destPanel.SaveSelectedState(destSelState);
+
+ CPanel::CDisableNotify disableNotify1(destPanel);
+ CPanel::CDisableNotify disableNotify2(srcPanel);
+
+ HRESULT result = S_OK;
+
+ if (useSrcPanel)
+ {
+ CCopyToOptions options;
+ options.folder = useTemp ? fs2us(tempDirPrefix) : destPath;
+ options.moveMode = move;
+ options.includeAltStreams = true;
+ options.replaceAltStreamChars = false;
+ options.showErrorMessages = true;
+
+ result = srcPanel.CopyTo(options, indices, NULL);
+ }
+
+ if (result == S_OK && useDestPanel)
+ {
+ UStringVector filePaths;
+ UString folderPrefix;
+
+ if (useTemp)
+ folderPrefix = fs2us(tempDirPrefix);
+ else
+ folderPrefix = srcPanel.GetFsPath();
+
+ filePaths.ClearAndReserve(indices.Size());
+
+ FOR_VECTOR (i, indices)
+ {
+ UInt32 index = indices[i];
+ UString s;
+ if (useFullItemPaths)
+ s = srcPanel.GetItemRelPath2(index);
+ else
+ s = srcPanel.GetItemName_for_Copy(index);
+ filePaths.AddInReserved(s);
+ }
+
+ result = destPanel.CopyFrom(move, folderPrefix, filePaths, true, NULL);
+ }
+
+ if (result != S_OK)
+ {
+ // disableNotify1.Restore();
+ // disableNotify2.Restore();
+ // For Password:
+ // srcPanel.SetFocusToList();
+ // srcPanel.InvalidateList(NULL, true);
+
+ if (result != E_ABORT)
+ srcPanel.MessageBox_Error_HRESULT(result);
+ // return;
+ }
+
+ RefreshTitleAlways();
+
+ if (copyToSame || move)
+ {
+ srcPanel.RefreshListCtrl(srcSelState);
+ }
+
+ if (!copyToSame)
+ {
+ destPanel.RefreshListCtrl(destSelState);
+ srcPanel.KillSelection();
+ }
+
+ disableNotify1.Restore();
+ disableNotify2.Restore();
+ srcPanel.SetFocusToList();
+}
+
+void CApp::OnSetSameFolder(unsigned srcPanelIndex)
+{
+ if (NumPanels <= 1)
+ return;
+ const CPanel &srcPanel = Panels[srcPanelIndex];
+ CPanel &destPanel = Panels[1 - srcPanelIndex];
+ destPanel.BindToPathAndRefresh(srcPanel._currentFolderPrefix);
+}
+
+void CApp::OnSetSubFolder(unsigned srcPanelIndex)
+{
+ if (NumPanels <= 1)
+ return;
+ const CPanel &srcPanel = Panels[srcPanelIndex];
+ CPanel &destPanel = Panels[1 - srcPanelIndex];
+
+ const int focusedItem = srcPanel._listView.GetFocusedItem();
+ if (focusedItem < 0)
+ return;
+ const unsigned realIndex = srcPanel.GetRealItemIndex(focusedItem);
+ if (!srcPanel.IsItem_Folder(realIndex))
+ return;
+
+ // destPanel.BindToFolder(srcPanel._currentFolderPrefix + srcPanel.GetItemName(realIndex) + WCHAR_PATH_SEPARATOR);
+
+ CMyComPtr<IFolderFolder> newFolder;
+ if (realIndex == kParentIndex)
+ {
+ if (srcPanel._folder->BindToParentFolder(&newFolder) != S_OK)
+ return;
+ if (!newFolder)
+ {
+ {
+ const UString parentPrefix = srcPanel.GetParentDirPrefix();
+ COpenResult openRes;
+ destPanel.BindToPath(parentPrefix, UString(), openRes);
+ }
+ destPanel.RefreshListCtrl();
+ return;
+ }
+ }
+ else
+ {
+ if (srcPanel._folder->BindToFolder(realIndex, &newFolder) != S_OK)
+ return;
+ }
+
+ if (!newFolder)
+ return;
+
+ destPanel.CloseOpenFolders();
+ destPanel.SetNewFolder(newFolder);
+ destPanel.RefreshListCtrl();
+}
+
+/*
+int CApp::GetFocusedPanelIndex() const
+{
+ return LastFocusedPanel;
+ HWND hwnd = ::GetFocus();
+ for (;;)
+ {
+ if (hwnd == 0)
+ return 0;
+ for (unsigned i = 0; i < kNumPanelsMax; i++)
+ {
+ if (PanelsCreated[i] &&
+ ((HWND)Panels[i] == hwnd || Panels[i]._listView == hwnd))
+ return i;
+ }
+ hwnd = GetParent(hwnd);
+ }
+}
+*/
+
+static UString g_ToolTipBuffer;
+static CSysString g_ToolTipBufferSys;
+
+void CApp::OnNotify(int /* ctrlID */, LPNMHDR pnmh)
+{
+ {
+ if (pnmh->code == TTN_GETDISPINFO)
+ {
+ LPNMTTDISPINFO info = (LPNMTTDISPINFO)pnmh;
+ info->hinst = NULL;
+ g_ToolTipBuffer.Empty();
+ SetButtonText((int)info->hdr.idFrom, g_ToolTipBuffer);
+ g_ToolTipBufferSys = GetSystemString(g_ToolTipBuffer);
+ info->lpszText = g_ToolTipBufferSys.Ptr_non_const();
+ return;
+ }
+ #ifndef _UNICODE
+ if (pnmh->code == TTN_GETDISPINFOW)
+ {
+ LPNMTTDISPINFOW info = (LPNMTTDISPINFOW)pnmh;
+ info->hinst = NULL;
+ g_ToolTipBuffer.Empty();
+ SetButtonText((int)info->hdr.idFrom, g_ToolTipBuffer);
+ info->lpszText = g_ToolTipBuffer.Ptr_non_const();
+ return;
+ }
+ #endif
+ }
+}
+
+void CApp::RefreshTitle(bool always)
+{
+ UString path = GetFocusedPanel()._currentFolderPrefix;
+ if (path.IsEmpty())
+ path = "7-Zip"; // LangString(IDS_APP_TITLE);
+ if (!always && path == PrevTitle)
+ return;
+ PrevTitle = path;
+ NWindows::MySetWindowText(_window, path);
+}
+
+void CApp::RefreshTitlePanel(unsigned panelIndex, bool always)
+{
+ if (panelIndex != GetFocusedPanelIndex())
+ return;
+ RefreshTitle(always);
+}
+
+static void AddUniqueStringToHead(UStringVector &list, const UString &s)
+{
+ for (unsigned i = 0; i < list.Size();)
+ if (s.IsEqualTo_NoCase(list[i]))
+ list.Delete(i);
+ else
+ i++;
+ list.Insert(0, s);
+}
+
+
+void CFolderHistory::Normalize()
+{
+ const unsigned kMaxSize = 100;
+ if (Strings.Size() > kMaxSize)
+ Strings.DeleteFrom(kMaxSize);
+}
+
+void CFolderHistory::AddString(const UString &s)
+{
+ NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ AddUniqueStringToHead(Strings, s);
+ Normalize();
+}
diff --git a/CPP/7zip/UI/FileManager/App.h b/CPP/7zip/UI/FileManager/App.h
new file mode 100644
index 0000000..fc54501
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/App.h
@@ -0,0 +1,306 @@
+// App.h
+
+#ifndef ZIP7_INC_APP_H
+#define ZIP7_INC_APP_H
+
+#include "../../../Windows/Control/CommandBar.h"
+#include "../../../Windows/Control/ImageList.h"
+
+#include "AppState.h"
+#include "Panel.h"
+
+class CApp;
+
+extern CApp g_App;
+extern HWND g_HWND;
+
+const unsigned kNumPanelsMax = 2;
+
+extern bool g_IsSmallScreen;
+
+// must be larger than context menu IDs
+const int kMenuCmdID_Toolbar_Start = 1070;
+const int kMenuCmdID_Plugin_Start = 1100;
+
+enum
+{
+ kMenuCmdID_Toolbar_Add = kMenuCmdID_Toolbar_Start,
+ kMenuCmdID_Toolbar_Extract,
+ kMenuCmdID_Toolbar_Test,
+ kMenuCmdID_Toolbar_End
+};
+
+class CPanelCallbackImp Z7_final: public CPanelCallback
+{
+ CApp *_app;
+ unsigned _index;
+public:
+ void Init(CApp *app, unsigned index)
+ {
+ _app = app;
+ _index = index;
+ }
+ virtual void OnTab() Z7_override;
+ virtual void SetFocusToPath(unsigned index) Z7_override;
+ virtual void OnCopy(bool move, bool copyToSame) Z7_override;
+ virtual void OnSetSameFolder() Z7_override;
+ virtual void OnSetSubFolder() Z7_override;
+ virtual void PanelWasFocused() Z7_override;
+ virtual void DragBegin() Z7_override;
+ virtual void DragEnd() Z7_override;
+ virtual void RefreshTitle(bool always) Z7_override;
+};
+
+
+class CDropTarget;
+
+class CApp
+{
+public:
+ NWindows::CWindow _window;
+ bool ShowSystemMenu;
+ bool AutoRefresh_Mode;
+ // bool ShowDeletedFiles;
+ unsigned NumPanels;
+ unsigned LastFocusedPanel;
+
+ bool ShowStandardToolbar;
+ bool ShowArchiveToolbar;
+ bool ShowButtonsLables;
+ bool LargeButtons;
+
+ CAppState AppState;
+ CPanelCallbackImp m_PanelCallbackImp[kNumPanelsMax];
+ CPanel Panels[kNumPanelsMax];
+
+ NWindows::NControl::CImageList _buttonsImageList;
+
+ #ifdef UNDER_CE
+ NWindows::NControl::CCommandBar _commandBar;
+ #endif
+ NWindows::NControl::CToolBar _toolBar;
+
+ CDropTarget *_dropTargetSpec;
+ CMyComPtr<IDropTarget> _dropTarget;
+
+ UString LangString_N_SELECTED_ITEMS;
+
+ void ReloadLangItems();
+
+ CApp():
+ _window(NULL),
+ AutoRefresh_Mode(true),
+ NumPanels(2),
+ LastFocusedPanel(0)
+ {
+ SetPanels_AutoRefresh_Mode();
+ }
+
+ void CreateDragTarget();
+ void SetFocusedPanel(unsigned index);
+ void DragBegin(unsigned panelIndex);
+ void DragEnd();
+
+ void OnCopy(bool move, bool copyToSame, unsigned srcPanelIndex);
+ void OnSetSameFolder(unsigned srcPanelIndex);
+ void OnSetSubFolder(unsigned srcPanelIndex);
+
+ HRESULT CreateOnePanel(unsigned panelIndex, const UString &mainPath, const UString &arcFormat, bool needOpenArc, COpenResult &openRes);
+ HRESULT Create(HWND hwnd, const UString &mainPath, const UString &arcFormat, int xSizes[2], bool needOpenArc, COpenResult &openRes);
+ void Read();
+ void Save();
+ void Release();
+
+ // void SetFocus(int panelIndex) { Panels[panelIndex].SetFocusToList(); }
+ void SetFocusToLastItem() { Panels[LastFocusedPanel].SetFocusToLastRememberedItem(); }
+ unsigned GetFocusedPanelIndex() const { return LastFocusedPanel; }
+ bool IsPanelVisible(unsigned index) const { return (NumPanels > 1 || index == LastFocusedPanel); }
+ CPanel &GetFocusedPanel() { return Panels[GetFocusedPanelIndex()]; }
+
+ // File Menu
+ void OpenItem() { GetFocusedPanel().OpenSelectedItems(true); }
+ void OpenItemInside(const wchar_t *type) { GetFocusedPanel().OpenFocusedItemAsInternal(type); }
+ void OpenItemOutside() { GetFocusedPanel().OpenSelectedItems(false); }
+ void EditItem(bool useEditor) { GetFocusedPanel().EditItem(useEditor); }
+ void Rename() { GetFocusedPanel().RenameFile(); }
+ void CopyTo() { OnCopy(false, false, GetFocusedPanelIndex()); }
+ void MoveTo() { OnCopy(true, false, GetFocusedPanelIndex()); }
+ void Delete(bool toRecycleBin) { GetFocusedPanel().DeleteItems(toRecycleBin); }
+ HRESULT CalculateCrc2(const UString &methodName);
+ void CalculateCrc(const char *methodName);
+
+ void DiffFiles(const UString &path1, const UString &path2);
+ void DiffFiles();
+
+ void VerCtrl(unsigned id);
+
+ void Split();
+ void Combine();
+ void Properties() { GetFocusedPanel().Properties(); }
+ void Comment() { GetFocusedPanel().ChangeComment(); }
+
+ #ifndef UNDER_CE
+ void Link();
+ void OpenAltStreams() { GetFocusedPanel().OpenAltStreams(); }
+ #endif
+
+ void CreateFolder() { GetFocusedPanel().CreateFolder(); }
+ void CreateFile() { GetFocusedPanel().CreateFile(); }
+
+ // Edit
+ void EditCut() { GetFocusedPanel().EditCut(); }
+ void EditCopy() { GetFocusedPanel().EditCopy(); }
+ void EditPaste() { GetFocusedPanel().EditPaste(); }
+
+ void SelectAll(bool selectMode) { GetFocusedPanel().SelectAll(selectMode); }
+ void InvertSelection() { GetFocusedPanel().InvertSelection(); }
+ void SelectSpec(bool selectMode) { GetFocusedPanel().SelectSpec(selectMode); }
+ void SelectByType(bool selectMode) { GetFocusedPanel().SelectByType(selectMode); }
+
+ void Refresh_StatusBar() { GetFocusedPanel().Refresh_StatusBar(); }
+
+ void SetListViewMode(UInt32 index) { GetFocusedPanel().SetListViewMode(index); }
+ UInt32 GetListViewMode() { return GetFocusedPanel().GetListViewMode(); }
+ PROPID GetSortID() { return GetFocusedPanel().GetSortID(); }
+
+ void SortItemsWithPropID(PROPID propID) { GetFocusedPanel().SortItemsWithPropID(propID); }
+
+ void OpenRootFolder() { GetFocusedPanel().OpenDrivesFolder(); }
+ void OpenParentFolder() { GetFocusedPanel().OpenParentFolder(); }
+ void FoldersHistory() { GetFocusedPanel().FoldersHistory(); }
+ void RefreshView() { GetFocusedPanel().OnReload(); }
+ void RefreshAllPanels()
+ {
+ for (unsigned i = 0; i < NumPanels; i++)
+ {
+ unsigned index = i;
+ if (NumPanels == 1)
+ index = LastFocusedPanel;
+ Panels[index].OnReload();
+ }
+ }
+
+ /*
+ void SysIconsWereChanged()
+ {
+ for (unsigned i = 0; i < NumPanels; i++)
+ {
+ unsigned index = i;
+ if (NumPanels == 1)
+ index = LastFocusedPanel;
+ Panels[index].SysIconsWereChanged();
+ }
+ }
+ */
+
+ void SetListSettings();
+ HRESULT SwitchOnOffOnePanel();
+
+ CIntVector _timestampLevels;
+
+ bool GetFlatMode() { return Panels[LastFocusedPanel].GetFlatMode(); }
+
+ int GetTimestampLevel() const { return Panels[LastFocusedPanel]._timestampLevel; }
+ void SetTimestampLevel(int level)
+ {
+ unsigned i;
+ for (i = 0; i < kNumPanelsMax; i++)
+ {
+ CPanel &panel = Panels[i];
+ panel._timestampLevel = level;
+ if (panel.PanelCreated)
+ panel.RedrawListItems();
+ }
+ }
+
+ // bool Get_ShowNtfsStrems_Mode() { return Panels[LastFocusedPanel].Get_ShowNtfsStrems_Mode(); }
+
+ void ChangeFlatMode() { Panels[LastFocusedPanel].ChangeFlatMode(); }
+ // void Change_ShowNtfsStrems_Mode() { Panels[LastFocusedPanel].Change_ShowNtfsStrems_Mode(); }
+ // void Change_ShowDeleted() { ShowDeletedFiles = !ShowDeletedFiles; }
+
+ bool Get_AutoRefresh_Mode()
+ {
+ // return Panels[LastFocusedPanel].Get_ShowNtfsStrems_Mode();
+ return AutoRefresh_Mode;
+ }
+ void Change_AutoRefresh_Mode()
+ {
+ AutoRefresh_Mode = !AutoRefresh_Mode;
+ SetPanels_AutoRefresh_Mode();
+ }
+ void SetPanels_AutoRefresh_Mode()
+ {
+ for (unsigned i = 0; i < kNumPanelsMax; i++)
+ Panels[i].Set_AutoRefresh_Mode(AutoRefresh_Mode);
+ }
+
+ void OpenBookmark(unsigned index) { GetFocusedPanel().OpenBookmark(index); }
+ void SetBookmark(unsigned index) { GetFocusedPanel().SetBookmark(index); }
+
+ void ReloadToolbars();
+ void ReadToolbar()
+ {
+ const UInt32 mask = ReadToolbarsMask();
+ if (mask & ((UInt32)1 << 31))
+ {
+ ShowButtonsLables = !g_IsSmallScreen;
+ LargeButtons = false;
+ ShowStandardToolbar = ShowArchiveToolbar = true;
+ }
+ else
+ {
+ ShowButtonsLables = ((mask & 1) != 0);
+ LargeButtons = ((mask & 2) != 0);
+ ShowStandardToolbar = ((mask & 4) != 0);
+ ShowArchiveToolbar = ((mask & 8) != 0);
+ }
+ }
+ void SaveToolbar()
+ {
+ UInt32 mask = 0;
+ if (ShowButtonsLables) mask |= 1;
+ if (LargeButtons) mask |= 2;
+ if (ShowStandardToolbar) mask |= 4;
+ if (ShowArchiveToolbar) mask |= 8;
+ SaveToolbarsMask(mask);
+ }
+
+ void SaveToolbarChanges();
+
+ void SwitchStandardToolbar()
+ {
+ ShowStandardToolbar = !ShowStandardToolbar;
+ SaveToolbarChanges();
+ }
+ void SwitchArchiveToolbar()
+ {
+ ShowArchiveToolbar = !ShowArchiveToolbar;
+ SaveToolbarChanges();
+ }
+ void SwitchButtonsLables()
+ {
+ ShowButtonsLables = !ShowButtonsLables;
+ SaveToolbarChanges();
+ }
+ void SwitchLargeButtons()
+ {
+ LargeButtons = !LargeButtons;
+ SaveToolbarChanges();
+ }
+
+ void AddToArchive() { GetFocusedPanel().AddToArchive(); }
+ void ExtractArchives() { GetFocusedPanel().ExtractArchives(); }
+ void TestArchives() { GetFocusedPanel().TestArchives(); }
+
+ void OnNotify(int ctrlID, LPNMHDR pnmh);
+
+ UString PrevTitle;
+ void RefreshTitle(bool always = false);
+ void RefreshTitleAlways() { RefreshTitle(true); }
+ void RefreshTitlePanel(unsigned panelIndex, bool always = false);
+
+ void MoveSubWindows();
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/AppState.h b/CPP/7zip/UI/FileManager/AppState.h
new file mode 100644
index 0000000..6630b96
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/AppState.h
@@ -0,0 +1,95 @@
+// AppState.h
+
+#ifndef ZIP7_INC_APP_STATE_H
+#define ZIP7_INC_APP_STATE_H
+
+#include "../../../Windows/Synchronization.h"
+
+#include "ViewSettings.h"
+
+class CFastFolders
+{
+ NWindows::NSynchronization::CCriticalSection _criticalSection;
+public:
+ UStringVector Strings;
+ void SetString(unsigned index, const UString &s)
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ while (Strings.Size() <= index)
+ Strings.AddNew();
+ Strings[index] = s;
+ }
+ UString GetString(unsigned index)
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ if (index >= Strings.Size())
+ return UString();
+ return Strings[index];
+ }
+ void Save()
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ SaveFastFolders(Strings);
+ }
+ void Read()
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ ReadFastFolders(Strings);
+ }
+};
+
+class CFolderHistory
+{
+ NWindows::NSynchronization::CCriticalSection _criticalSection;
+ UStringVector Strings;
+
+ void Normalize();
+
+public:
+
+ void GetList(UStringVector &foldersHistory)
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ foldersHistory = Strings;
+ }
+
+ void AddString(const UString &s);
+
+ void RemoveAll()
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ Strings.Clear();
+ }
+
+ void Save()
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ SaveFolderHistory(Strings);
+ }
+
+ void Read()
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ ReadFolderHistory(Strings);
+ Normalize();
+ }
+};
+
+struct CAppState
+{
+ CFastFolders FastFolders;
+ CFolderHistory FolderHistory;
+
+ void Save()
+ {
+ FastFolders.Save();
+ FolderHistory.Save();
+ }
+ void Read()
+ {
+ FastFolders.Read();
+ FolderHistory.Read();
+ }
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/BrowseDialog.cpp b/CPP/7zip/UI/FileManager/BrowseDialog.cpp
index d5c981c..5170302 100644
--- a/CPP/7zip/UI/FileManager/BrowseDialog.cpp
+++ b/CPP/7zip/UI/FileManager/BrowseDialog.cpp
@@ -1,1025 +1,1088 @@
-// BrowseDialog.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/MyWindows.h"
-
-#include <commctrl.h>
-
-#ifndef UNDER_CE
-#include "../../../Windows/CommonDialog.h"
-#include "../../../Windows/Shell.h"
-#endif
-
-#include "../../../Windows/FileName.h"
-#include "../../../Windows/FileFind.h"
-
-#ifdef UNDER_CE
-#include <commdlg.h>
-#endif
-
-#include "BrowseDialog.h"
-
-#define USE_MY_BROWSE_DIALOG
-
-#ifdef USE_MY_BROWSE_DIALOG
-
-#include "../../../Common/Defs.h"
-#include "../../../Common/IntToString.h"
-#include "../../../Common/Wildcard.h"
-
-#include "../../../Windows/FileDir.h"
-#include "../../../Windows/PropVariantConv.h"
-
-#include "../../../Windows/Control/ComboBox.h"
-#include "../../../Windows/Control/Dialog.h"
-#include "../../../Windows/Control/Edit.h"
-#include "../../../Windows/Control/ListView.h"
-
-#include "BrowseDialogRes.h"
-#include "PropertyNameRes.h"
-#include "SysIconUtils.h"
-
-#ifndef _SFX
-#include "RegistryUtils.h"
-#endif
-
-#endif
-
-#include "ComboDialog.h"
-#include "LangUtils.h"
-
-#include "resource.h"
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NName;
-using namespace NFind;
-
-#ifdef USE_MY_BROWSE_DIALOG
-
-extern bool g_LVN_ITEMACTIVATE_Support;
-
-static const int kParentIndex = -1;
-static const UINT k_Message_RefreshPathEdit = WM_APP + 1;
-
-static HRESULT GetNormalizedError()
-{
- DWORD errorCode = GetLastError();
- return errorCode == 0 ? E_FAIL : errorCode;
-}
-
-extern UString HResultToMessage(HRESULT errorCode);
-
-static void MessageBox_Error_Global(HWND wnd, const wchar_t *message)
-{
- ::MessageBoxW(wnd, message, L"7-Zip", MB_ICONERROR);
-}
-
-static void MessageBox_HResError(HWND wnd, HRESULT errorCode, const wchar_t *name)
-{
- UString s = HResultToMessage(errorCode);
- if (name)
- {
- s.Add_LF();
- s += name;
- }
- MessageBox_Error_Global(wnd, s);
-}
-
-class CBrowseDialog: public NControl::CModalDialog
-{
- NControl::CListView _list;
- NControl::CEdit _pathEdit;
- NControl::CComboBox _filterCombo;
-
- CObjectVector<CFileInfo> _files;
-
- CExtToIconMap _extToIconMap;
- int _sortIndex;
- bool _ascending;
- bool _showDots;
- UString _topDirPrefix; // we don't open parent of that folder
- UString DirPrefix;
-
- virtual bool OnInit();
- virtual bool OnSize(WPARAM wParam, int xSize, int ySize);
- virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
- virtual bool OnNotify(UINT controlID, LPNMHDR header);
- virtual bool OnKeyDown(LPNMLVKEYDOWN keyDownInfo);
- virtual bool OnButtonClicked(int buttonID, HWND buttonHWND);
- virtual void OnOK();
-
- void Post_RefreshPathEdit() { PostMsg(k_Message_RefreshPathEdit); }
-
- bool GetParentPath(const UString &path, UString &parentPrefix, UString &name);
- // Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter
- HRESULT Reload(const UString &pathPrefix, const UString &selectedName);
- HRESULT Reload();
-
- void OpenParentFolder();
- void SetPathEditText();
- void OnCreateDir();
- void OnItemEnter();
- void FinishOnOK();
-
- int GetRealItemIndex(int indexInListView) const
- {
- LPARAM param;
- if (!_list.GetItemParam(indexInListView, param))
- return (int)-1;
- return (int)param;
- }
-
-public:
- bool FolderMode;
- UString Title;
- UString FilePath; // input/ result path
- bool ShowAllFiles;
- UStringVector Filters;
- UString FilterDescription;
-
- CBrowseDialog(): FolderMode(false), _showDots(false), ShowAllFiles(true) {}
- void SetFilter(const UString &s);
- INT_PTR Create(HWND parent = 0) { return CModalDialog::Create(IDD_BROWSE, parent); }
- int CompareItems(LPARAM lParam1, LPARAM lParam2);
-};
-
-void CBrowseDialog::SetFilter(const UString &s)
-{
- Filters.Clear();
- UString mask;
- unsigned i;
- for (i = 0; i < s.Len(); i++)
- {
- wchar_t c = s[i];
- if (c == ';')
- {
- if (!mask.IsEmpty())
- Filters.Add(mask);
- mask.Empty();
- }
- else
- mask += c;
- }
- if (!mask.IsEmpty())
- Filters.Add(mask);
- ShowAllFiles = Filters.IsEmpty();
- for (i = 0; i < Filters.Size(); i++)
- {
- const UString &f = Filters[i];
- if (f == L"*.*" || f == L"*")
- {
- ShowAllFiles = true;
- break;
- }
- }
-}
-
-bool CBrowseDialog::OnInit()
-{
- #ifdef LANG
- LangSetDlgItems(*this, NULL, 0);
- #endif
- if (!Title.IsEmpty())
- SetText(Title);
- _list.Attach(GetItem(IDL_BROWSE));
- _filterCombo.Attach(GetItem(IDC_BROWSE_FILTER));
- _pathEdit.Attach(GetItem(IDE_BROWSE_PATH));
-
- if (FolderMode)
- HideItem(IDC_BROWSE_FILTER);
- else
- EnableItem(IDC_BROWSE_FILTER, false);
-
- #ifndef UNDER_CE
- _list.SetUnicodeFormat();
- #endif
-
- #ifndef _SFX
- CFmSettings st;
- st.Load();
- if (st.SingleClick)
- _list.SetExtendedListViewStyle(LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT);
- _showDots = st.ShowDots;
- #endif
-
- {
- UString s;
- if (!FilterDescription.IsEmpty())
- s = FilterDescription;
- else if (ShowAllFiles)
- s = "*.*";
- else
- {
- FOR_VECTOR (i, Filters)
- {
- if (i != 0)
- s.Add_Space();
- s += Filters[i];
- }
- }
- _filterCombo.AddString(s);
- _filterCombo.SetCurSel(0);
- }
-
- _list.SetImageList(GetSysImageList(true), LVSIL_SMALL);
- _list.SetImageList(GetSysImageList(false), LVSIL_NORMAL);
-
- _list.InsertColumn(0, LangString(IDS_PROP_NAME), 100);
- _list.InsertColumn(1, LangString(IDS_PROP_MTIME), 100);
- {
- LV_COLUMNW column;
- column.iSubItem = 2;
- column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
- column.fmt = LVCFMT_RIGHT;
- column.cx = 100;
- const UString s = LangString(IDS_PROP_SIZE);
- column.pszText = (wchar_t *)(const wchar_t *)s;
- _list.InsertColumn(2, &column);
- }
-
- _list.InsertItem(0, L"12345678901234567"
- #ifndef UNDER_CE
- L"1234567890"
- #endif
- );
- _list.SetSubItem(0, 1, L"2009-09-09"
- #ifndef UNDER_CE
- L" 09:09"
- #endif
- );
- _list.SetSubItem(0, 2, L"9999 MB");
- for (int i = 0; i < 3; i++)
- _list.SetColumnWidthAuto(i);
- _list.DeleteAllItems();
-
- _ascending = true;
- _sortIndex = 0;
-
- NormalizeSize();
-
- _topDirPrefix.Empty();
- {
- int rootSize = GetRootPrefixSize(FilePath);
- #if defined(_WIN32) && !defined(UNDER_CE)
- // We can go up from root folder to drives list
- if (IsDrivePath(FilePath))
- rootSize = 0;
- else if (IsSuperPath(FilePath))
- {
- if (IsDrivePath(FilePath.Ptr(kSuperPathPrefixSize)))
- rootSize = kSuperPathPrefixSize;
- }
- #endif
- _topDirPrefix.SetFrom(FilePath, rootSize);
- }
-
- UString name;
- if (!GetParentPath(FilePath, DirPrefix, name))
- DirPrefix = _topDirPrefix;
-
- for (;;)
- {
- UString baseFolder = DirPrefix;
- if (Reload(baseFolder, name) == S_OK)
- break;
- name.Empty();
- if (DirPrefix.IsEmpty())
- break;
- UString parent, name2;
- GetParentPath(DirPrefix, parent, name2);
- DirPrefix = parent;
- }
-
- if (name.IsEmpty())
- name = FilePath;
- if (FolderMode)
- NormalizeDirPathPrefix(name);
- _pathEdit.SetText(name);
-
- #ifndef UNDER_CE
- /* If we clear UISF_HIDEFOCUS, the focus rectangle in ListView will be visible,
- even if we use mouse for pressing the button to open this dialog. */
- PostMsg(MY__WM_UPDATEUISTATE, MAKEWPARAM(MY__UIS_CLEAR, MY__UISF_HIDEFOCUS));
- #endif
-
- return CModalDialog::OnInit();
-}
-
-bool CBrowseDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
-{
- int mx, my;
- {
- RECT r;
- GetClientRectOfItem(IDB_BROWSE_PARENT, r);
- mx = r.left;
- my = r.top;
- }
- InvalidateRect(NULL);
-
- int xLim = xSize - mx;
- {
- RECT r;
- GetClientRectOfItem(IDT_BROWSE_FOLDER, r);
- MoveItem(IDT_BROWSE_FOLDER, r.left, r.top, xLim - r.left, RECT_SIZE_Y(r));
- }
-
- int bx1, bx2, by;
- GetItemSizes(IDCANCEL, bx1, by);
- GetItemSizes(IDOK, bx2, by);
- int y = ySize - my - by;
- int x = xLim - bx1;
- MoveItem(IDCANCEL, x, y, bx1, by);
- MoveItem(IDOK, x - mx - bx2, y, bx2, by);
-
- // Y_Size of ComboBox is tricky. So we use Y_Size of _pathEdit instead
-
- int yPathSize;
- {
- RECT r;
- GetClientRectOfItem(IDE_BROWSE_PATH, r);
- yPathSize = RECT_SIZE_Y(r);
- _pathEdit.Move(r.left, y - my - yPathSize - my - yPathSize, xLim - r.left, yPathSize);
- }
-
- {
- RECT r;
- GetClientRectOfItem(IDC_BROWSE_FILTER, r);
- _filterCombo.Move(r.left, y - my - yPathSize, xLim - r.left, RECT_SIZE_Y(r));
- }
-
- {
- RECT r;
- GetClientRectOfItem(IDL_BROWSE, r);
- _list.Move(r.left, r.top, xLim - r.left, y - my - yPathSize - my - yPathSize - my - r.top);
- }
-
- return false;
-}
-
-bool CBrowseDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
-{
- if (message == k_Message_RefreshPathEdit)
- {
- SetPathEditText();
- return true;
- }
- return CModalDialog::OnMessage(message, wParam, lParam);
-}
-
-bool CBrowseDialog::OnNotify(UINT /* controlID */, LPNMHDR header)
-{
- if (header->hwndFrom != _list)
- return false;
- switch (header->code)
- {
- case LVN_ITEMACTIVATE:
- if (g_LVN_ITEMACTIVATE_Support)
- OnItemEnter();
- break;
- case NM_DBLCLK:
- case NM_RETURN: // probabably it's unused
- if (!g_LVN_ITEMACTIVATE_Support)
- OnItemEnter();
- break;
- case LVN_COLUMNCLICK:
- {
- int index = LPNMLISTVIEW(header)->iSubItem;
- if (index == _sortIndex)
- _ascending = !_ascending;
- else
- {
- _ascending = (index == 0);
- _sortIndex = index;
- }
- Reload();
- return false;
- }
- case LVN_KEYDOWN:
- {
- bool boolResult = OnKeyDown(LPNMLVKEYDOWN(header));
- Post_RefreshPathEdit();
- return boolResult;
- }
- case NM_RCLICK:
- case NM_CLICK:
- case LVN_BEGINDRAG:
- Post_RefreshPathEdit();
- break;
- }
- return false;
-}
-
-bool CBrowseDialog::OnKeyDown(LPNMLVKEYDOWN keyDownInfo)
-{
- bool ctrl = IsKeyDown(VK_CONTROL);
-
- switch (keyDownInfo->wVKey)
- {
- case VK_BACK:
- OpenParentFolder();
- return true;
- case 'R':
- if (ctrl)
- {
- Reload();
- return true;
- }
- return false;
- case VK_F7:
- OnCreateDir();
- return true;
- }
- return false;
-}
-
-bool CBrowseDialog::OnButtonClicked(int buttonID, HWND buttonHWND)
-{
- switch (buttonID)
- {
- case IDB_BROWSE_PARENT: OpenParentFolder(); break;
- case IDB_BROWSE_CREATE_DIR: OnCreateDir(); break;
- default: return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
- }
- _list.SetFocus();
- return true;
-}
-
-void CBrowseDialog::OnOK()
-{
- /* When we press "Enter" in listview, Windows sends message to first Button.
- We check that message was from ListView; */
- if (GetFocus() == _list)
- {
- OnItemEnter();
- return;
- }
- FinishOnOK();
-}
-
-
-bool CBrowseDialog::GetParentPath(const UString &path, UString &parentPrefix, UString &name)
-{
- parentPrefix.Empty();
- name.Empty();
- if (path.IsEmpty())
- return false;
- if (_topDirPrefix == path)
- return false;
- UString s = path;
- if (IS_PATH_SEPAR(s.Back()))
- s.DeleteBack();
- if (s.IsEmpty())
- return false;
- if (IS_PATH_SEPAR(s.Back()))
- return false;
- int pos = s.ReverseFind_PathSepar();
- parentPrefix.SetFrom(s, pos + 1);
- name = s.Ptr(pos + 1);
- return true;
-}
-
-int CBrowseDialog::CompareItems(LPARAM lParam1, LPARAM lParam2)
-{
- if (lParam1 == kParentIndex) return -1;
- if (lParam2 == kParentIndex) return 1;
- const CFileInfo &f1 = _files[(int)lParam1];
- const CFileInfo &f2 = _files[(int)lParam2];
-
- bool isDir1 = f1.IsDir();
- bool isDir2 = f2.IsDir();
- if (isDir1 && !isDir2) return -1;
- if (isDir2 && !isDir1) return 1;
-
- int res = 0;
- switch (_sortIndex)
- {
- case 0: res = CompareFileNames(fs2us(f1.Name), fs2us(f2.Name)); break;
- case 1: res = CompareFileTime(&f1.MTime, &f2.MTime); break;
- case 2: res = MyCompare(f1.Size, f2.Size); break;
- }
- return _ascending ? res: -res;
-}
-
-static int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData)
-{
- return ((CBrowseDialog *)lpData)->CompareItems(lParam1, lParam2);
-}
-
-static void ConvertSizeToString(UInt64 v, wchar_t *s)
-{
- Byte c = 0;
- if (v >= ((UInt64)10000 << 20)) { v >>= 30; c = 'G'; }
- else if (v >= ((UInt64)10000 << 10)) { v >>= 20; c = 'M'; }
- else if (v >= ((UInt64)10000 << 0)) { v >>= 10; c = 'K'; }
- ConvertUInt64ToString(v, s);
- if (c != 0)
- {
- s += MyStringLen(s);
- *s++ = ' ';
- *s++ = c;
- *s++ = 0;
- }
-}
-
-// Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter
-
-HRESULT CBrowseDialog::Reload(const UString &pathPrefix, const UString &selectedName)
-{
- CObjectVector<CFileInfo> files;
-
- #ifndef UNDER_CE
- bool isDrive = false;
- if (pathPrefix.IsEmpty() || pathPrefix.IsEqualTo(kSuperPathPrefix))
- {
- isDrive = true;
- FStringVector drives;
- if (!MyGetLogicalDriveStrings(drives))
- return GetNormalizedError();
- FOR_VECTOR (i, drives)
- {
- FString d = drives[i];
- if (d.Len() < 3 || d.Back() != '\\')
- return E_FAIL;
- d.DeleteBack();
- CFileInfo &fi = files.AddNew();
- fi.SetAsDir();
- fi.Name = d;
- }
- }
- else
- #endif
- {
- CEnumerator enumerator;
- enumerator.SetDirPrefix(us2fs(pathPrefix));
- for (;;)
- {
- bool found;
- CFileInfo fi;
- if (!enumerator.Next(fi, found))
- return GetNormalizedError();
- if (!found)
- break;
- if (!fi.IsDir())
- {
- if (FolderMode)
- continue;
- if (!ShowAllFiles)
- {
- unsigned i;
- for (i = 0; i < Filters.Size(); i++)
- if (DoesWildcardMatchName(Filters[i], fs2us(fi.Name)))
- break;
- if (i == Filters.Size())
- continue;
- }
- }
- files.Add(fi);
- }
- }
-
- DirPrefix = pathPrefix;
-
- _files = files;
-
- SetItemText(IDT_BROWSE_FOLDER, DirPrefix);
-
- _list.SetRedraw(false);
- _list.DeleteAllItems();
-
- LVITEMW item;
-
- int index = 0;
- int cursorIndex = -1;
-
- #ifndef _SFX
- if (_showDots && _topDirPrefix != DirPrefix)
- {
- item.iItem = index;
- const UString itemName ("..");
- if (selectedName.IsEmpty())
- cursorIndex = index;
- item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
- int subItem = 0;
- item.iSubItem = subItem++;
- item.lParam = kParentIndex;
- item.pszText = (wchar_t *)(const wchar_t *)itemName;
- item.iImage = _extToIconMap.GetIconIndex(FILE_ATTRIBUTE_DIRECTORY, DirPrefix);
- if (item.iImage < 0)
- item.iImage = 0;
- _list.InsertItem(&item);
- _list.SetSubItem(index, subItem++, L"");
- _list.SetSubItem(index, subItem++, L"");
- index++;
- }
- #endif
-
- for (unsigned i = 0; i < _files.Size(); i++, index++)
- {
- item.iItem = index;
- const CFileInfo &fi = _files[i];
- const UString name = fs2us(fi.Name);
- if (!selectedName.IsEmpty() && CompareFileNames(name, selectedName) == 0)
- cursorIndex = index;
- item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
- int subItem = 0;
- item.iSubItem = subItem++;
- item.lParam = i;
- item.pszText = (wchar_t *)(const wchar_t *)name;
-
- const UString fullPath = DirPrefix + name;
- #ifndef UNDER_CE
- if (isDrive)
- {
- if (GetRealIconIndex(fi.Name + FCHAR_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY, item.iImage) == 0)
- item.iImage = 0;
- }
- else
- #endif
- item.iImage = _extToIconMap.GetIconIndex(fi.Attrib, fullPath);
- if (item.iImage < 0)
- item.iImage = 0;
- _list.InsertItem(&item);
- wchar_t s[32];
- {
- s[0] = 0;
- ConvertUtcFileTimeToString(fi.MTime, s,
- #ifndef UNDER_CE
- kTimestampPrintLevel_MIN
- #else
- kTimestampPrintLevel_DAY
- #endif
- );
- _list.SetSubItem(index, subItem++, s);
- }
- {
- s[0] = 0;
- if (!fi.IsDir())
- ConvertSizeToString(fi.Size, s);
- _list.SetSubItem(index, subItem++, s);
- }
- }
-
- if (_list.GetItemCount() > 0 && cursorIndex >= 0)
- _list.SetItemState_FocusedSelected(cursorIndex);
- _list.SortItems(CompareItems2, (LPARAM)this);
- if (_list.GetItemCount() > 0 && cursorIndex < 0)
- _list.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED);
- _list.EnsureVisible(_list.GetFocusedItem(), false);
- _list.SetRedraw(true);
- _list.InvalidateRect(NULL, true);
- return S_OK;
-}
-
-HRESULT CBrowseDialog::Reload()
-{
- UString selected;
- int index = _list.GetNextSelectedItem(-1);
- if (index >= 0)
- {
- int fileIndex = GetRealItemIndex(index);
- if (fileIndex != kParentIndex)
- selected = fs2us(_files[fileIndex].Name);
- }
- UString dirPathTemp = DirPrefix;
- return Reload(dirPathTemp, selected);
-}
-
-void CBrowseDialog::OpenParentFolder()
-{
- UString parent, selected;
- if (GetParentPath(DirPrefix, parent, selected))
- {
- Reload(parent, selected);
- SetPathEditText();
- }
-}
-
-void CBrowseDialog::SetPathEditText()
-{
- int index = _list.GetNextSelectedItem(-1);
- if (index < 0)
- {
- if (FolderMode)
- _pathEdit.SetText(DirPrefix);
- return;
- }
- int fileIndex = GetRealItemIndex(index);
- if (fileIndex == kParentIndex)
- {
- if (FolderMode)
- _pathEdit.SetText(L".." WSTRING_PATH_SEPARATOR);
- return;
- }
- const CFileInfo &file = _files[fileIndex];
- if (file.IsDir())
- {
- if (!FolderMode)
- return;
- _pathEdit.SetText(fs2us(file.Name) + WCHAR_PATH_SEPARATOR);
- }
- else
- _pathEdit.SetText(fs2us(file.Name));
-}
-
-void CBrowseDialog::OnCreateDir()
-{
- UString name;
- {
- UString enteredName;
- Dlg_CreateFolder((HWND)*this, enteredName);
- if (enteredName.IsEmpty())
- return;
- if (!CorrectFsPath(DirPrefix, enteredName, name))
- {
- MessageBox_HResError((HWND)*this, ERROR_INVALID_NAME, name);
- return;
- }
- }
- if (name.IsEmpty())
- return;
-
- FString destPath;
- if (GetFullPath(us2fs(DirPrefix), us2fs(name), destPath))
- {
- if (!NDir::CreateComplexDir(destPath))
- {
- MessageBox_HResError((HWND)*this, GetNormalizedError(), fs2us(destPath));
- }
- else
- {
- UString tempPath = DirPrefix;
- Reload(tempPath, name);
- SetPathEditText();
- }
- _list.SetFocus();
- }
-}
-
-void CBrowseDialog::OnItemEnter()
-{
- int index = _list.GetNextSelectedItem(-1);
- if (index < 0)
- return;
- int fileIndex = GetRealItemIndex(index);
- if (fileIndex == kParentIndex)
- OpenParentFolder();
- else
- {
- const CFileInfo &file = _files[fileIndex];
- if (!file.IsDir())
- {
- if (!FolderMode)
- FinishOnOK();
- /*
- MessageBox_Error_Global(*this, FolderMode ?
- L"You must select some folder":
- L"You must select some file");
- */
- return;
- }
- UString s = DirPrefix;
- s += fs2us(file.Name);
- s.Add_PathSepar();
- HRESULT res = Reload(s, UString());
- if (res != S_OK)
- MessageBox_HResError(*this, res, s);
- SetPathEditText();
- }
-}
-
-void CBrowseDialog::FinishOnOK()
-{
- UString s;
- _pathEdit.GetText(s);
- FString destPath;
- if (!GetFullPath(us2fs(DirPrefix), us2fs(s), destPath))
- {
- MessageBox_HResError((HWND)*this, ERROR_INVALID_NAME, s);
- return;
- }
- FilePath = fs2us(destPath);
- if (FolderMode)
- NormalizeDirPathPrefix(FilePath);
- End(IDOK);
-}
-
-#endif
-
-bool MyBrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR path, UString &resultPath)
-{
- resultPath.Empty();
-
- #ifndef UNDER_CE
-
- #ifdef USE_MY_BROWSE_DIALOG
- if (!IsSuperOrDevicePath(path))
- #endif
- return NShell::BrowseForFolder(owner, title, path, resultPath);
-
- #endif
-
- #ifdef USE_MY_BROWSE_DIALOG
-
- CBrowseDialog dialog;
- dialog.FolderMode = true;
- if (title)
- dialog.Title = title;
- if (path)
- dialog.FilePath = path;
- if (dialog.Create(owner) != IDOK)
- return false;
- resultPath = dialog.FilePath;
- #endif
-
- return true;
-}
-
-bool MyBrowseForFile(HWND owner, LPCWSTR title, LPCWSTR path,
- LPCWSTR filterDescription, LPCWSTR filter, UString &resultPath)
-{
- resultPath.Empty();
-
- #ifndef UNDER_CE
-
- #ifdef USE_MY_BROWSE_DIALOG
- if (!IsSuperOrDevicePath(path))
- #endif
- {
- if (MyGetOpenFileName(owner, title, NULL, path, filterDescription, filter, resultPath))
- return true;
- #ifdef UNDER_CE
- return false;
- #else
- // maybe we must use GetLastError in WinCE.
- DWORD errorCode = CommDlgExtendedError();
- const char *errorMessage = NULL;
- switch (errorCode)
- {
- case 0: return false; // cancel or close obn dialog
- case FNERR_INVALIDFILENAME: errorMessage = "Invalid File Name"; break;
- default: errorMessage = "Open Dialog Error";
- }
- if (!errorMessage)
- return false;
- {
- UString s (errorMessage);
- s.Add_LF();
- s += path;
- MessageBox_Error_Global(owner, s);
- }
- #endif
- }
-
- #endif
-
- #ifdef USE_MY_BROWSE_DIALOG
- CBrowseDialog dialog;
- if (title)
- dialog.Title = title;
- if (path)
- dialog.FilePath = path;
- dialog.FolderMode = false;
- if (filter)
- dialog.SetFilter(filter);
- if (filterDescription)
- dialog.FilterDescription = filterDescription;
- if (dialog.Create(owner) != IDOK)
- return false;
- resultPath = dialog.FilePath;
- #endif
-
- return true;
-}
-
-
-#ifdef _WIN32
-
-static void RemoveDotsAndSpaces(UString &path)
-{
- while (!path.IsEmpty())
- {
- wchar_t c = path.Back();
- if (c != ' ' && c != '.')
- return;
- path.DeleteBack();
- }
-}
-
-
-bool CorrectFsPath(const UString &relBase, const UString &path2, UString &result)
-{
- result.Empty();
-
- UString path = path2;
- path.Replace(L'/', WCHAR_PATH_SEPARATOR);
- unsigned start = 0;
- UString base;
-
- if (IsAbsolutePath(path))
- {
- #if defined(_WIN32) && !defined(UNDER_CE)
- if (IsSuperOrDevicePath(path))
- {
- result = path;
- return true;
- }
- #endif
- int pos = GetRootPrefixSize(path);
- if (pos > 0)
- start = pos;
- }
- else
- {
- #if defined(_WIN32) && !defined(UNDER_CE)
- if (IsSuperOrDevicePath(relBase))
- {
- result = path;
- return true;
- }
- #endif
- base = relBase;
- }
-
- /* We can't use backward, since we must change only disk paths */
- /*
- for (;;)
- {
- if (path.Len() <= start)
- break;
- if (DoesFileOrDirExist(us2fs(path)))
- break;
- if (path.Back() == WCHAR_PATH_SEPARATOR)
- {
- path.DeleteBack();
- result.Insert(0, WCHAR_PATH_SEPARATOR);;
- }
- int pos = path.ReverseFind(WCHAR_PATH_SEPARATOR) + 1;
- UString cur = path.Ptr(pos);
- RemoveDotsAndSpaces(cur);
- result.Insert(0, cur);
- path.DeleteFrom(pos);
- }
- result.Insert(0, path);
- return true;
- */
-
- result += path.Left(start);
- bool checkExist = true;
- UString cur;
-
- for (;;)
- {
- if (start == path.Len())
- break;
- int slashPos = path.Find(WCHAR_PATH_SEPARATOR, start);
- cur.SetFrom(path.Ptr(start), (slashPos < 0 ? path.Len() : slashPos) - start);
- if (checkExist)
- {
- CFileInfo fi;
- if (fi.Find(us2fs(base + result + cur)))
- {
- if (!fi.IsDir())
- {
- result = path;
- break;
- }
- }
- else
- checkExist = false;
- }
- if (!checkExist)
- RemoveDotsAndSpaces(cur);
- result += cur;
- if (slashPos < 0)
- break;
- result.Add_PathSepar();
- start = slashPos + 1;
- }
-
- return true;
-}
-
-#else
-
-bool CorrectFsPath(const UString & /* relBase */, const UString &path, UString &result)
-{
- result = path;
- return true;
-}
-
-#endif
-
-bool Dlg_CreateFolder(HWND wnd, UString &destName)
-{
- destName.Empty();
- CComboDialog dlg;
- LangString(IDS_CREATE_FOLDER, dlg.Title);
- LangString(IDS_CREATE_FOLDER_NAME, dlg.Static);
- LangString(IDS_CREATE_FOLDER_DEFAULT_NAME, dlg.Value);
- if (dlg.Create(wnd) != IDOK)
- return false;
- destName = dlg.Value;
- return true;
-}
+// BrowseDialog.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+
+#include "../../../Common/IntToString.h"
+
+#ifndef UNDER_CE
+#include "../../../Windows/CommonDialog.h"
+#include "../../../Windows/Shell.h"
+#endif
+
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/FileFind.h"
+
+#ifdef UNDER_CE
+#include <commdlg.h>
+#endif
+
+#include "BrowseDialog.h"
+
+#define USE_MY_BROWSE_DIALOG
+
+#ifdef USE_MY_BROWSE_DIALOG
+
+#include "../../../Common/Defs.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/PropVariantConv.h"
+
+#include "../../../Windows/Control/ComboBox.h"
+#include "../../../Windows/Control/Dialog.h"
+#include "../../../Windows/Control/Edit.h"
+#include "../../../Windows/Control/ListView.h"
+
+#include "BrowseDialogRes.h"
+#include "PropertyNameRes.h"
+#include "SysIconUtils.h"
+
+#ifndef Z7_SFX
+#include "RegistryUtils.h"
+#endif
+
+#endif // USE_MY_BROWSE_DIALOG
+
+#include "ComboDialog.h"
+#include "LangUtils.h"
+
+#include "resource.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NName;
+using namespace NFind;
+
+static void MessageBox_Error_Global(HWND wnd, const wchar_t *message)
+{
+ ::MessageBoxW(wnd, message, L"7-Zip", MB_ICONERROR);
+}
+
+#ifdef USE_MY_BROWSE_DIALOG
+
+extern bool g_LVN_ITEMACTIVATE_Support;
+
+static const int kParentIndex = -1;
+static const UINT k_Message_RefreshPathEdit = WM_APP + 1;
+
+extern UString HResultToMessage(HRESULT errorCode);
+
+static void MessageBox_HResError(HWND wnd, HRESULT errorCode, const wchar_t *name)
+{
+ UString s = HResultToMessage(errorCode);
+ if (name)
+ {
+ s.Add_LF();
+ s += name;
+ }
+ MessageBox_Error_Global(wnd, s);
+}
+
+class CBrowseDialog: public NControl::CModalDialog
+{
+ NControl::CListView _list;
+ NControl::CEdit _pathEdit;
+ NControl::CComboBox _filterCombo;
+
+ CObjectVector<CFileInfo> _files;
+
+ CExtToIconMap _extToIconMap;
+ int _sortIndex;
+ bool _ascending;
+ #ifndef Z7_SFX
+ bool _showDots;
+ #endif
+ UString _topDirPrefix; // we don't open parent of that folder
+ UString DirPrefix;
+
+ virtual bool OnInit() Z7_override;
+ virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override;
+ virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override;
+ virtual bool OnNotify(UINT controlID, LPNMHDR header) Z7_override;
+ virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override;
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+ virtual void OnOK() Z7_override;
+
+ bool OnKeyDown(LPNMLVKEYDOWN keyDownInfo);
+
+ void Post_RefreshPathEdit() { PostMsg(k_Message_RefreshPathEdit); }
+
+ bool GetParentPath(const UString &path, UString &parentPrefix, UString &name);
+ // Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter
+ HRESULT Reload(const UString &pathPrefix, const UString &selectedName);
+ HRESULT Reload();
+
+ void OpenParentFolder();
+ void SetPathEditText();
+ void OnCreateDir();
+ void OnItemEnter();
+ void FinishOnOK();
+
+ int GetRealItemIndex(int indexInListView) const
+ {
+ LPARAM param;
+ if (!_list.GetItemParam((unsigned)indexInListView, param))
+ return (int)-1;
+ return (int)param;
+ }
+
+public:
+
+ bool SaveMode;
+ bool FolderMode;
+ int FilterIndex; // [in / out]
+ CObjectVector<CBrowseFilterInfo> Filters;
+
+ UString FilePath; // [in / out]
+ UString Title;
+
+ CBrowseDialog():
+ #ifndef Z7_SFX
+ _showDots(false),
+ #endif
+ SaveMode(false)
+ , FolderMode(false)
+ , FilterIndex(-1)
+ {}
+ INT_PTR Create(HWND parent = NULL) { return CModalDialog::Create(IDD_BROWSE, parent); }
+ int CompareItems(LPARAM lParam1, LPARAM lParam2) const;
+};
+
+
+bool CBrowseDialog::OnInit()
+{
+ #ifdef Z7_LANG
+ LangSetDlgItems(*this, NULL, 0);
+ #endif
+ if (!Title.IsEmpty())
+ SetText(Title);
+ _list.Attach(GetItem(IDL_BROWSE));
+ _filterCombo.Attach(GetItem(IDC_BROWSE_FILTER));
+ _pathEdit.Attach(GetItem(IDE_BROWSE_PATH));
+
+ #ifndef UNDER_CE
+ _list.SetUnicodeFormat();
+ #endif
+
+ #ifndef Z7_SFX
+ CFmSettings st;
+ st.Load();
+ if (st.SingleClick)
+ _list.SetExtendedListViewStyle(LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT);
+ _showDots = st.ShowDots;
+ #endif
+
+ {
+ /*
+ Filters.Clear(); // for debug
+ if (Filters.IsEmpty() && !FolderMode)
+ {
+ CBrowseFilterInfo &f = Filters.AddNew();
+ const UString mask("*.*");
+ f.Masks.Add(mask);
+ // f.Description = "(";
+ f.Description += mask;
+ // f.Description += ")";
+ }
+ */
+
+ FOR_VECTOR (i, Filters)
+ {
+ _filterCombo.AddString(Filters[i].Description);
+ }
+
+ if (Filters.Size() <= 1)
+ {
+ if (FolderMode)
+ HideItem(IDC_BROWSE_FILTER);
+ else
+ EnableItem(IDC_BROWSE_FILTER, false);
+ }
+
+ if (/* FilterIndex >= 0 && */ (unsigned)FilterIndex < Filters.Size())
+ _filterCombo.SetCurSel(FilterIndex);
+ }
+
+ _list.SetImageList(GetSysImageList(true), LVSIL_SMALL);
+ _list.SetImageList(GetSysImageList(false), LVSIL_NORMAL);
+
+ _list.InsertColumn(0, LangString(IDS_PROP_NAME), 100);
+ _list.InsertColumn(1, LangString(IDS_PROP_MTIME), 100);
+ {
+ LV_COLUMNW column;
+ column.iSubItem = 2;
+ column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
+ column.fmt = LVCFMT_RIGHT;
+ column.cx = 100;
+ const UString s = LangString(IDS_PROP_SIZE);
+ column.pszText = s.Ptr_non_const();
+ _list.InsertColumn(2, &column);
+ }
+
+ _list.InsertItem(0, L"12345678901234567"
+ #ifndef UNDER_CE
+ L"1234567890"
+ #endif
+ );
+ _list.SetSubItem(0, 1, L"2009-09-09"
+ #ifndef UNDER_CE
+ L" 09:09"
+ #endif
+ );
+ _list.SetSubItem(0, 2, L"9999 MB");
+ for (int i = 0; i < 3; i++)
+ _list.SetColumnWidthAuto(i);
+ _list.DeleteAllItems();
+
+ _ascending = true;
+ _sortIndex = 0;
+
+ NormalizeSize();
+
+ _topDirPrefix.Empty();
+ {
+ unsigned rootSize = GetRootPrefixSize(FilePath);
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ // We can go up from root folder to drives list
+ if (IsDrivePath(FilePath))
+ rootSize = 0;
+ else if (IsSuperPath(FilePath))
+ {
+ if (IsDrivePath(FilePath.Ptr(kSuperPathPrefixSize)))
+ rootSize = kSuperPathPrefixSize;
+ }
+ #endif
+ _topDirPrefix.SetFrom(FilePath, rootSize);
+ }
+
+ UString name;
+ if (!GetParentPath(FilePath, DirPrefix, name))
+ DirPrefix = _topDirPrefix;
+
+ for (;;)
+ {
+ UString baseFolder = DirPrefix;
+ if (Reload(baseFolder, name) == S_OK)
+ break;
+ name.Empty();
+ if (DirPrefix.IsEmpty())
+ break;
+ UString parent, name2;
+ GetParentPath(DirPrefix, parent, name2);
+ DirPrefix = parent;
+ }
+
+ if (name.IsEmpty())
+ name = FilePath;
+ if (FolderMode)
+ NormalizeDirPathPrefix(name);
+ _pathEdit.SetText(name);
+
+ #ifndef UNDER_CE
+ /* If we clear UISF_HIDEFOCUS, the focus rectangle in ListView will be visible,
+ even if we use mouse for pressing the button to open this dialog. */
+ PostMsg(Z7_WIN_WM_UPDATEUISTATE, MAKEWPARAM(Z7_WIN_UIS_CLEAR, Z7_WIN_UISF_HIDEFOCUS));
+ #endif
+
+ return CModalDialog::OnInit();
+}
+
+bool CBrowseDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
+{
+ int mx, my;
+ {
+ RECT r;
+ GetClientRectOfItem(IDB_BROWSE_PARENT, r);
+ mx = r.left;
+ my = r.top;
+ }
+ InvalidateRect(NULL);
+
+ int xLim = xSize - mx;
+ {
+ RECT r;
+ GetClientRectOfItem(IDT_BROWSE_FOLDER, r);
+ MoveItem(IDT_BROWSE_FOLDER, r.left, r.top, xLim - r.left, RECT_SIZE_Y(r));
+ }
+
+ int bx1, bx2, by;
+ GetItemSizes(IDCANCEL, bx1, by);
+ GetItemSizes(IDOK, bx2, by);
+ int y = ySize - my - by;
+ int x = xLim - bx1;
+ MoveItem(IDCANCEL, x, y, bx1, by);
+ MoveItem(IDOK, x - mx - bx2, y, bx2, by);
+
+ // Y_Size of ComboBox is tricky. So we use Y_Size of _pathEdit instead
+
+ int yPathSize;
+ {
+ RECT r;
+ GetClientRectOfItem(IDE_BROWSE_PATH, r);
+ yPathSize = RECT_SIZE_Y(r);
+ _pathEdit.Move(r.left, y - my - yPathSize - my - yPathSize, xLim - r.left, yPathSize);
+ }
+
+ {
+ RECT r;
+ GetClientRectOfItem(IDC_BROWSE_FILTER, r);
+ _filterCombo.Move(r.left, y - my - yPathSize, xLim - r.left, RECT_SIZE_Y(r));
+ }
+
+ {
+ RECT r;
+ GetClientRectOfItem(IDL_BROWSE, r);
+ _list.Move(r.left, r.top, xLim - r.left, y - my - yPathSize - my - yPathSize - my - r.top);
+ }
+
+ return false;
+}
+
+bool CBrowseDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ if (message == k_Message_RefreshPathEdit)
+ {
+ SetPathEditText();
+ return true;
+ }
+ return CModalDialog::OnMessage(message, wParam, lParam);
+}
+
+
+bool CBrowseDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam)
+{
+ if (code == CBN_SELCHANGE)
+ {
+ switch (itemID)
+ {
+ case IDC_BROWSE_FILTER:
+ {
+ Reload();
+ return true;
+ }
+ }
+ }
+ return CModalDialog::OnCommand(code, itemID, lParam);
+}
+
+
+bool CBrowseDialog::OnNotify(UINT /* controlID */, LPNMHDR header)
+{
+ if (header->hwndFrom != _list)
+ return false;
+ switch (header->code)
+ {
+ case LVN_ITEMACTIVATE:
+ if (g_LVN_ITEMACTIVATE_Support)
+ OnItemEnter();
+ break;
+ case NM_DBLCLK:
+ case NM_RETURN: // probabably it's unused
+ if (!g_LVN_ITEMACTIVATE_Support)
+ OnItemEnter();
+ break;
+ case LVN_COLUMNCLICK:
+ {
+ const int index = LPNMLISTVIEW(header)->iSubItem;
+ if (index == _sortIndex)
+ _ascending = !_ascending;
+ else
+ {
+ _ascending = (index == 0);
+ _sortIndex = index;
+ }
+ Reload();
+ return false;
+ }
+ case LVN_KEYDOWN:
+ {
+ bool boolResult = OnKeyDown(LPNMLVKEYDOWN(header));
+ Post_RefreshPathEdit();
+ return boolResult;
+ }
+ case NM_RCLICK:
+ case NM_CLICK:
+ case LVN_BEGINDRAG:
+ Post_RefreshPathEdit();
+ break;
+ }
+ return false;
+}
+
+bool CBrowseDialog::OnKeyDown(LPNMLVKEYDOWN keyDownInfo)
+{
+ const bool ctrl = IsKeyDown(VK_CONTROL);
+
+ switch (keyDownInfo->wVKey)
+ {
+ case VK_BACK:
+ OpenParentFolder();
+ return true;
+ case 'R':
+ if (ctrl)
+ {
+ Reload();
+ return true;
+ }
+ return false;
+ case VK_F7:
+ OnCreateDir();
+ return true;
+ }
+ return false;
+}
+
+
+bool CBrowseDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ switch (buttonID)
+ {
+ case IDB_BROWSE_PARENT: OpenParentFolder(); break;
+ case IDB_BROWSE_CREATE_DIR: OnCreateDir(); break;
+ default: return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
+ }
+ _list.SetFocus();
+ return true;
+}
+
+void CBrowseDialog::OnOK()
+{
+ /* When we press "Enter" in listview, Windows sends message to first Button.
+ We check that message was from ListView; */
+ if (GetFocus() == _list)
+ {
+ OnItemEnter();
+ return;
+ }
+ FinishOnOK();
+}
+
+
+bool CBrowseDialog::GetParentPath(const UString &path, UString &parentPrefix, UString &name)
+{
+ parentPrefix.Empty();
+ name.Empty();
+ if (path.IsEmpty())
+ return false;
+ if (_topDirPrefix == path)
+ return false;
+ UString s = path;
+ if (IS_PATH_SEPAR(s.Back()))
+ s.DeleteBack();
+ if (s.IsEmpty())
+ return false;
+ if (IS_PATH_SEPAR(s.Back()))
+ return false;
+ const unsigned pos1 = (unsigned)(s.ReverseFind_PathSepar() + 1);
+ parentPrefix.SetFrom(s, pos1);
+ name = s.Ptr(pos1);
+ return true;
+}
+
+int CBrowseDialog::CompareItems(LPARAM lParam1, LPARAM lParam2) const
+{
+ if (lParam1 == kParentIndex) return -1;
+ if (lParam2 == kParentIndex) return 1;
+ const CFileInfo &f1 = _files[(int)lParam1];
+ const CFileInfo &f2 = _files[(int)lParam2];
+
+ const bool isDir1 = f1.IsDir();
+ const bool isDir2 = f2.IsDir();
+ if (isDir1 && !isDir2) return -1;
+ if (isDir2 && !isDir1) return 1;
+
+ int res = 0;
+ switch (_sortIndex)
+ {
+ case 0: res = CompareFileNames(fs2us(f1.Name), fs2us(f2.Name)); break;
+ case 1: res = CompareFileTime(&f1.MTime, &f2.MTime); break;
+ case 2: res = MyCompare(f1.Size, f2.Size); break;
+ }
+ return _ascending ? res: -res;
+}
+
+static int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData)
+{
+ return ((CBrowseDialog *)lpData)->CompareItems(lParam1, lParam2);
+}
+
+static void ConvertSizeToString(UInt64 v, wchar_t *s)
+{
+ char c = 0;
+ if (v >= ((UInt64)10000 << 20)) { v >>= 30; c = 'G'; }
+ else if (v >= ((UInt64)10000 << 10)) { v >>= 20; c = 'M'; }
+ else if (v >= ((UInt64)10000 << 0)) { v >>= 10; c = 'K'; }
+ s = ConvertUInt64ToString(v, s);
+ if (c != 0)
+ {
+ *s++ = ' ';
+ *s++ = (wchar_t)c;
+ *s++ = 'B';
+ *s++ = 0;
+ }
+}
+
+// Reload changes DirPrefix. Don't send DirPrefix in pathPrefix parameter
+
+HRESULT CBrowseDialog::Reload(const UString &pathPrefix, const UString &selectedName)
+{
+ CObjectVector<CFileInfo> files;
+
+ #ifndef UNDER_CE
+ bool isDrive = false;
+ if (pathPrefix.IsEmpty() || pathPrefix.IsEqualTo(kSuperPathPrefix))
+ {
+ isDrive = true;
+ FStringVector drives;
+ if (!MyGetLogicalDriveStrings(drives))
+ return GetLastError_noZero_HRESULT();
+ FOR_VECTOR (i, drives)
+ {
+ const FString &d = drives[i];
+ if (d.Len() < 2 || d.Back() != '\\')
+ return E_FAIL;
+ CFileInfo &fi = files.AddNew();
+ fi.SetAsDir();
+ fi.Name = d;
+ fi.Name.DeleteBack();
+ }
+ }
+ else
+ #endif
+ {
+ const UStringVector *masks = NULL;
+ if (!Filters.IsEmpty() && _filterCombo.GetCount() > 0)
+ {
+ const int selected = _filterCombo.GetCurSel();
+ // GetItemData_of_CurSel(); // we don't use data field
+ if (/* selected >= 0 && */ (unsigned)selected < Filters.Size())
+ {
+ const UStringVector &m = Filters[selected].Masks;
+ if (m.Size() > 1 || (m.Size() == 1
+ && !m[0].IsEqualTo("*.*")
+ && !m[0].IsEqualTo("*")))
+ masks = &m;
+ }
+ }
+ CEnumerator enumerator;
+ enumerator.SetDirPrefix(us2fs(pathPrefix));
+ CFileInfo fi;
+ for (;;)
+ {
+ bool found;
+ if (!enumerator.Next(fi, found))
+ return GetLastError_noZero_HRESULT();
+ if (!found)
+ break;
+ if (!fi.IsDir())
+ {
+ if (FolderMode)
+ continue;
+ if (masks)
+ {
+ unsigned i;
+ const unsigned numMasks = masks->Size();
+ for (i = 0; i < numMasks; i++)
+ if (DoesWildcardMatchName((*masks)[i], fs2us(fi.Name)))
+ break;
+ if (i == numMasks)
+ continue;
+ }
+ }
+ files.Add(fi);
+ }
+ }
+
+ DirPrefix = pathPrefix;
+
+ _files = files;
+
+ SetItemText(IDT_BROWSE_FOLDER, DirPrefix);
+
+ _list.SetRedraw(false);
+ _list.DeleteAllItems();
+
+ LVITEMW item;
+
+ unsigned index = 0;
+ int cursorIndex = -1;
+
+ #ifndef Z7_SFX
+ if (_showDots && _topDirPrefix != DirPrefix)
+ {
+ item.iItem = (int)index;
+ const UString itemName ("..");
+ if (selectedName.IsEmpty())
+ cursorIndex = (int)index;
+ item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
+ unsigned subItem = 0;
+ item.iSubItem = (int)(subItem++);
+ item.lParam = kParentIndex;
+ item.pszText = itemName.Ptr_non_const();
+ item.iImage = _extToIconMap.GetIconIndex(FILE_ATTRIBUTE_DIRECTORY, DirPrefix);
+ if (item.iImage < 0)
+ item.iImage = 0;
+ _list.InsertItem(&item);
+ _list.SetSubItem(index, subItem++, L"");
+ _list.SetSubItem(index, subItem++, L"");
+ index++;
+ }
+ #endif
+
+ for (unsigned i = 0; i < _files.Size(); i++, index++)
+ {
+ item.iItem = (int)index;
+ const CFileInfo &fi = _files[i];
+ const UString name = fs2us(fi.Name);
+ if (!selectedName.IsEmpty() && CompareFileNames(name, selectedName) == 0)
+ cursorIndex = (int)index;
+ item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
+ unsigned subItem = 0;
+ item.iSubItem = (int)(subItem++);
+ item.lParam = (LPARAM)i;
+ item.pszText = name.Ptr_non_const();
+
+ const UString fullPath = DirPrefix + name;
+ #ifndef UNDER_CE
+ if (isDrive)
+ {
+ if (GetRealIconIndex(fi.Name + FCHAR_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY, item.iImage) == 0)
+ item.iImage = 0;
+ }
+ else
+ #endif
+ item.iImage = _extToIconMap.GetIconIndex(fi.Attrib, fullPath);
+ if (item.iImage < 0)
+ item.iImage = 0;
+ _list.InsertItem(&item);
+ wchar_t s[32];
+ {
+ s[0] = 0;
+ ConvertUtcFileTimeToString(fi.MTime, s,
+ #ifndef UNDER_CE
+ kTimestampPrintLevel_MIN
+ #else
+ kTimestampPrintLevel_DAY
+ #endif
+ );
+ _list.SetSubItem(index, subItem++, s);
+ }
+ {
+ s[0] = 0;
+ if (!fi.IsDir())
+ ConvertSizeToString(fi.Size, s);
+ _list.SetSubItem(index, subItem++, s);
+ }
+ }
+
+ if (_list.GetItemCount() > 0 && cursorIndex >= 0)
+ _list.SetItemState_FocusedSelected(cursorIndex);
+ _list.SortItems(CompareItems2, (LPARAM)this);
+ if (_list.GetItemCount() > 0 && cursorIndex < 0)
+ _list.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED);
+ _list.EnsureVisible(_list.GetFocusedItem(), false);
+ _list.SetRedraw(true);
+ _list.InvalidateRect(NULL, true);
+ return S_OK;
+}
+
+HRESULT CBrowseDialog::Reload()
+{
+ UString selected;
+ const int index = _list.GetNextSelectedItem(-1);
+ if (index >= 0)
+ {
+ const int fileIndex = GetRealItemIndex(index);
+ if (fileIndex != kParentIndex)
+ selected = fs2us(_files[fileIndex].Name);
+ }
+ const UString dirPathTemp = DirPrefix;
+ return Reload(dirPathTemp, selected);
+}
+
+void CBrowseDialog::OpenParentFolder()
+{
+ UString parent, selected;
+ if (GetParentPath(DirPrefix, parent, selected))
+ {
+ Reload(parent, selected);
+ SetPathEditText();
+ }
+}
+
+void CBrowseDialog::SetPathEditText()
+{
+ const int index = _list.GetNextSelectedItem(-1);
+ if (index < 0)
+ {
+ if (FolderMode)
+ _pathEdit.SetText(DirPrefix);
+ return;
+ }
+ const int fileIndex = GetRealItemIndex(index);
+ if (fileIndex == kParentIndex)
+ {
+ if (FolderMode)
+ _pathEdit.SetText(L".." WSTRING_PATH_SEPARATOR);
+ return;
+ }
+ const CFileInfo &file = _files[fileIndex];
+ if (file.IsDir())
+ {
+ if (!FolderMode)
+ return;
+ _pathEdit.SetText(fs2us(file.Name) + WCHAR_PATH_SEPARATOR);
+ }
+ else
+ _pathEdit.SetText(fs2us(file.Name));
+}
+
+void CBrowseDialog::OnCreateDir()
+{
+ UString name;
+ {
+ UString enteredName;
+ Dlg_CreateFolder((HWND)*this, enteredName);
+ if (enteredName.IsEmpty())
+ return;
+ if (!CorrectFsPath(DirPrefix, enteredName, name))
+ {
+ MessageBox_HResError((HWND)*this, ERROR_INVALID_NAME, name);
+ return;
+ }
+ }
+ if (name.IsEmpty())
+ return;
+
+ FString destPath;
+ if (GetFullPath(us2fs(DirPrefix), us2fs(name), destPath))
+ {
+ if (!NDir::CreateComplexDir(destPath))
+ {
+ MessageBox_HResError((HWND)*this, GetLastError_noZero_HRESULT(), fs2us(destPath));
+ }
+ else
+ {
+ UString tempPath = DirPrefix;
+ Reload(tempPath, name);
+ SetPathEditText();
+ }
+ _list.SetFocus();
+ }
+}
+
+void CBrowseDialog::OnItemEnter()
+{
+ const int index = _list.GetNextSelectedItem(-1);
+ if (index < 0)
+ return;
+ const int fileIndex = GetRealItemIndex(index);
+ if (fileIndex == kParentIndex)
+ OpenParentFolder();
+ else
+ {
+ const CFileInfo &file = _files[fileIndex];
+ if (!file.IsDir())
+ {
+ if (!FolderMode)
+ FinishOnOK();
+ /*
+ MessageBox_Error_Global(*this, FolderMode ?
+ L"You must select some folder":
+ L"You must select some file");
+ */
+ return;
+ }
+ UString s = DirPrefix;
+ s += fs2us(file.Name);
+ s.Add_PathSepar();
+ const HRESULT res = Reload(s, UString());
+ if (res != S_OK)
+ MessageBox_HResError(*this, res, s);
+ SetPathEditText();
+ }
+}
+
+void CBrowseDialog::FinishOnOK()
+{
+ UString s;
+ _pathEdit.GetText(s);
+ FString destPath;
+ if (!GetFullPath(us2fs(DirPrefix), us2fs(s), destPath))
+ {
+ MessageBox_HResError((HWND)*this, ERROR_INVALID_NAME, s);
+ return;
+ }
+ FilePath = fs2us(destPath);
+ if (FolderMode)
+ NormalizeDirPathPrefix(FilePath);
+ FilterIndex = _filterCombo.GetCurSel();
+ End(IDOK);
+}
+
+#endif // USE_MY_BROWSE_DIALOG
+
+
+
+bool MyBrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR path, UString &resultPath)
+{
+ resultPath.Empty();
+
+ #ifndef UNDER_CE
+
+#ifdef USE_MY_BROWSE_DIALOG
+ if (!IsSuperOrDevicePath(path))
+ if (MyStringLen(path) < MAX_PATH)
+#endif
+ return NShell::BrowseForFolder(owner, title, path, resultPath);
+
+ #endif // UNDER_CE
+
+ #ifdef USE_MY_BROWSE_DIALOG
+
+ CBrowseDialog dialog;
+ dialog.FolderMode = true;
+ if (title)
+ dialog.Title = title;
+ if (path)
+ dialog.FilePath = path;
+ if (dialog.Create(owner) != IDOK)
+ return false;
+ resultPath = dialog.FilePath;
+ return true;
+
+ #endif
+}
+
+
+// LPCWSTR filterDescription, LPCWSTR filter,
+
+bool CBrowseInfo::BrowseForFile(const CObjectVector<CBrowseFilterInfo> &filters)
+{
+#ifndef UNDER_CE
+#ifdef USE_MY_BROWSE_DIALOG
+ /* win10:
+ GetOpenFileName() for FilePath doesn't support super prefix "\\\\?\\"
+ GetOpenFileName() for FilePath doesn't support long path
+ */
+ if (!IsSuperOrDevicePath(FilePath))
+ // if (filters.Size() > 100) // for debug
+#endif
+ {
+ const UString filePath_Store = FilePath;
+ UString dirPrefix;
+ {
+ FString prefix, name;
+ if (NDir::GetFullPathAndSplit(us2fs(FilePath), prefix, name))
+ {
+ dirPrefix = fs2us(prefix);
+ FilePath = fs2us(name);
+ }
+ }
+ UStringVector filters2;
+ FOR_VECTOR (i, filters)
+ {
+ const CBrowseFilterInfo &fi = filters[i];
+ filters2.Add(fi.Description);
+ UString s;
+ FOR_VECTOR (k, fi.Masks)
+ {
+ if (k != 0)
+ s += ";";
+ s += fi.Masks[k];
+ }
+ filters2.Add(s);
+ }
+ if (CommonDlg_BrowseForFile(!dirPrefix.IsEmpty() ? dirPrefix.Ptr(): NULL, filters2))
+ return true;
+ FilePath = filePath_Store;
+
+ #ifdef UNDER_CE
+ return false;
+ #else
+ // maybe we must use GetLastError in WinCE.
+ const DWORD errorCode = CommDlgExtendedError();
+ #ifdef USE_MY_BROWSE_DIALOG
+ // FNERR_INVALIDFILENAME is expected error, if long path was used
+ if (errorCode != FNERR_INVALIDFILENAME
+ || FilePath.Len() < MAX_PATH)
+ #endif
+ {
+ if (errorCode == 0) // cancel or close on dialog
+ return false;
+ const char *message = NULL;
+ if (errorCode == FNERR_INVALIDFILENAME)
+ message = "Invalid file name";
+ UString s ("Open Dialog Error:");
+ s.Add_LF();
+ if (message)
+ s += message;
+ else
+ {
+ char temp[16];
+ ConvertUInt32ToHex8Digits(errorCode, temp);
+ s += "Error #";
+ s += temp;
+ }
+ s.Add_LF();
+ s += FilePath;
+ MessageBox_Error_Global(hwndOwner, s);
+ }
+ #endif // UNDER_CE
+ }
+
+#endif // UNDER_CE
+
+#ifdef USE_MY_BROWSE_DIALOG
+
+ CBrowseDialog dialog;
+
+ dialog.FolderMode = false;
+ dialog.SaveMode = SaveMode;
+ dialog.FilterIndex = FilterIndex;
+ dialog.Filters = filters;
+
+ if (lpstrTitle)
+ dialog.Title = lpstrTitle;
+ dialog.FilePath = FilePath;
+ if (dialog.Create(hwndOwner) != IDOK)
+ return false;
+ FilePath = dialog.FilePath;
+ FilterIndex = dialog.FilterIndex;
+#endif
+
+ return true;
+}
+
+
+#ifdef _WIN32
+
+static void RemoveDotsAndSpaces(UString &path)
+{
+ while (!path.IsEmpty())
+ {
+ wchar_t c = path.Back();
+ if (c != ' ' && c != '.')
+ return;
+ path.DeleteBack();
+ }
+}
+
+
+bool CorrectFsPath(const UString &relBase, const UString &path2, UString &result)
+{
+ result.Empty();
+
+ UString path = path2;
+ #ifdef _WIN32
+ path.Replace(L'/', WCHAR_PATH_SEPARATOR);
+ #endif
+ unsigned start = 0;
+ UString base;
+
+ if (IsAbsolutePath(path))
+ {
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (IsSuperOrDevicePath(path))
+ {
+ result = path;
+ return true;
+ }
+ #endif
+ start = GetRootPrefixSize(path);
+ }
+ else
+ {
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (IsSuperOrDevicePath(relBase))
+ {
+ result = path;
+ return true;
+ }
+ #endif
+ base = relBase;
+ }
+
+ /* We can't use backward, since we must change only disk paths */
+ /*
+ for (;;)
+ {
+ if (path.Len() <= start)
+ break;
+ if (DoesFileOrDirExist(us2fs(path)))
+ break;
+ if (path.Back() == WCHAR_PATH_SEPARATOR)
+ {
+ path.DeleteBack();
+ result.Insert(0, WCHAR_PATH_SEPARATOR);
+ }
+ int pos = path.ReverseFind(WCHAR_PATH_SEPARATOR) + 1;
+ UString cur = path.Ptr(pos);
+ RemoveDotsAndSpaces(cur);
+ result.Insert(0, cur);
+ path.DeleteFrom(pos);
+ }
+ result.Insert(0, path);
+ return true;
+ */
+
+ result += path.Left(start);
+ bool checkExist = true;
+ UString cur;
+
+ for (;;)
+ {
+ if (start == path.Len())
+ break;
+ const int slashPos = path.Find(WCHAR_PATH_SEPARATOR, start);
+ cur.SetFrom(path.Ptr(start), (slashPos < 0 ? path.Len() : (unsigned)slashPos) - start);
+ if (checkExist)
+ {
+ CFileInfo fi;
+ if (fi.Find(us2fs(base + result + cur)))
+ {
+ if (!fi.IsDir())
+ {
+ result = path;
+ break;
+ }
+ }
+ else
+ checkExist = false;
+ }
+ if (!checkExist)
+ RemoveDotsAndSpaces(cur);
+ result += cur;
+ if (slashPos < 0)
+ break;
+ start = (unsigned)(slashPos + 1);
+ result.Add_PathSepar();
+ }
+
+ return true;
+}
+
+#else
+
+bool CorrectFsPath(const UString & /* relBase */, const UString &path, UString &result)
+{
+ result = path;
+ return true;
+}
+
+#endif
+
+bool Dlg_CreateFolder(HWND wnd, UString &destName)
+{
+ destName.Empty();
+ CComboDialog dlg;
+ LangString(IDS_CREATE_FOLDER, dlg.Title);
+ LangString(IDS_CREATE_FOLDER_NAME, dlg.Static);
+ LangString(IDS_CREATE_FOLDER_DEFAULT_NAME, dlg.Value);
+ if (dlg.Create(wnd) != IDOK)
+ return false;
+ destName = dlg.Value;
+ return true;
+}
diff --git a/CPP/7zip/UI/FileManager/BrowseDialog.h b/CPP/7zip/UI/FileManager/BrowseDialog.h
index be51085..2ad8d54 100644
--- a/CPP/7zip/UI/FileManager/BrowseDialog.h
+++ b/CPP/7zip/UI/FileManager/BrowseDialog.h
@@ -1,21 +1,32 @@
-// BrowseDialog.h
-
-#ifndef __BROWSE_DIALOG_H
-#define __BROWSE_DIALOG_H
-
-#include "../../../Common/MyString.h"
-
-bool MyBrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR path, UString &resultPath);
-bool MyBrowseForFile(HWND owner, LPCWSTR title, LPCWSTR path, LPCWSTR filterDescription, LPCWSTR filter, UString &resultPath);
-
-/* CorrectFsPath removes undesirable characters in names (dots and spaces at the end of file)
- But it doesn't change "bad" name in any of the following cases:
- - path is Super Path (with \\?\ prefix)
- - path is relative and relBase is Super Path
- - there is file or dir in filesystem with specified "bad" name */
-
-bool CorrectFsPath(const UString &relBase, const UString &path, UString &result);
-
-bool Dlg_CreateFolder(HWND wnd, UString &destName);
-
-#endif
+// BrowseDialog.h
+
+#ifndef ZIP7_INC_BROWSE_DIALOG_H
+#define ZIP7_INC_BROWSE_DIALOG_H
+
+#include "../../../Windows/CommonDialog.h"
+
+bool MyBrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR path, UString &resultPath);
+
+struct CBrowseFilterInfo
+{
+ UStringVector Masks;
+ UString Description;
+};
+
+struct CBrowseInfo: public NWindows::CCommonDialogInfo
+{
+ bool BrowseForFile(const CObjectVector<CBrowseFilterInfo> &filters);
+};
+
+
+/* CorrectFsPath removes undesirable characters in names (dots and spaces at the end of file)
+ But it doesn't change "bad" name in any of the following cases:
+ - path is Super Path (with \\?\ prefix)
+ - path is relative and relBase is Super Path
+ - there is file or dir in filesystem with specified "bad" name */
+
+bool CorrectFsPath(const UString &relBase, const UString &path, UString &result);
+
+bool Dlg_CreateFolder(HWND wnd, UString &destName);
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/BrowseDialog.rc b/CPP/7zip/UI/FileManager/BrowseDialog.rc
new file mode 100644
index 0000000..04a6ad6
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/BrowseDialog.rc
@@ -0,0 +1,25 @@
+#include "BrowseDialogRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 256
+#define yc 320
+
+#define k_BROWSE_y_CtrlSize 14
+
+#define k_BROWSE_y_List 24
+
+IDD_BROWSE DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT
+CAPTION "7-Zip: Browse"
+{
+ EDITTEXT IDE_BROWSE_PATH, m, by - m - k_BROWSE_y_CtrlSize - k_BROWSE_y_CtrlSize - m, xc, k_BROWSE_y_CtrlSize, ES_AUTOHSCROLL
+ COMBOBOX IDC_BROWSE_FILTER, m, by - m - k_BROWSE_y_CtrlSize, xc, 30, MY_COMBO
+
+ PUSHBUTTON "OK", IDOK, bx2, by, bxs, bys
+ PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys
+ PUSHBUTTON "<--", IDB_BROWSE_PARENT, m, m, 24, bys
+ PUSHBUTTON "+", IDB_BROWSE_CREATE_DIR, m + 32, m, 24, bys
+ LTEXT "", IDT_BROWSE_FOLDER, m + 64, m + 3, xc - 20, 8
+ CONTROL "List1", IDL_BROWSE, "SysListView32",
+ LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | LVS_SINGLESEL | WS_BORDER | WS_TABSTOP,
+ m, m + k_BROWSE_y_List, xc, yc - bys - m - k_BROWSE_y_List - k_BROWSE_y_CtrlSize - m - k_BROWSE_y_CtrlSize - m
+}
diff --git a/CPP/7zip/UI/FileManager/BrowseDialogRes.h b/CPP/7zip/UI/FileManager/BrowseDialogRes.h
index f211b73..aff84ec 100644
--- a/CPP/7zip/UI/FileManager/BrowseDialogRes.h
+++ b/CPP/7zip/UI/FileManager/BrowseDialogRes.h
@@ -1,9 +1,9 @@
-#define IDD_BROWSE 95
-
-#define IDL_BROWSE 100
-#define IDT_BROWSE_FOLDER 101
-#define IDE_BROWSE_PATH 102
-#define IDC_BROWSE_FILTER 103
-
-#define IDB_BROWSE_PARENT 110
-#define IDB_BROWSE_CREATE_DIR 112
+#define IDD_BROWSE 95
+
+#define IDL_BROWSE 100
+#define IDT_BROWSE_FOLDER 101
+#define IDE_BROWSE_PATH 102
+#define IDC_BROWSE_FILTER 103
+
+#define IDB_BROWSE_PARENT 110
+#define IDB_BROWSE_CREATE_DIR 112
diff --git a/CPP/7zip/UI/FileManager/ClassDefs.cpp b/CPP/7zip/UI/FileManager/ClassDefs.cpp
new file mode 100644
index 0000000..5c26904
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ClassDefs.cpp
@@ -0,0 +1,12 @@
+// ClassDefs.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+
+#include "../../../Common/MyInitGuid.h"
+
+#include "../Agent/Agent.h"
+
+#include "MyWindowsNew.h"
+#include "../Explorer/MyExplorerCommand.h"
diff --git a/CPP/7zip/UI/FileManager/ComboDialog.cpp b/CPP/7zip/UI/FileManager/ComboDialog.cpp
index e846c56..921972e 100644
--- a/CPP/7zip/UI/FileManager/ComboDialog.cpp
+++ b/CPP/7zip/UI/FileManager/ComboDialog.cpp
@@ -1,64 +1,64 @@
-// ComboDialog.cpp
-
-#include "StdAfx.h"
-#include "ComboDialog.h"
-
-#include "../../../Windows/Control/Static.h"
-
-#ifdef LANG
-#include "LangUtils.h"
-#endif
-
-using namespace NWindows;
-
-bool CComboDialog::OnInit()
-{
- #ifdef LANG
- LangSetDlgItems(*this, NULL, 0);
- #endif
- _comboBox.Attach(GetItem(IDC_COMBO));
-
- /*
- // why it doesn't work ?
- DWORD style = _comboBox.GetStyle();
- if (Sorted)
- style |= CBS_SORT;
- else
- style &= ~CBS_SORT;
- _comboBox.SetStyle(style);
- */
- SetText(Title);
-
- NControl::CStatic staticContol;
- staticContol.Attach(GetItem(IDT_COMBO));
- staticContol.SetText(Static);
- _comboBox.SetText(Value);
- FOR_VECTOR (i, Strings)
- _comboBox.AddString(Strings[i]);
- NormalizeSize();
- return CModalDialog::OnInit();
-}
-
-bool CComboDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
-{
- int mx, my;
- GetMargins(8, mx, my);
- int bx1, bx2, by;
- GetItemSizes(IDCANCEL, bx1, by);
- GetItemSizes(IDOK, bx2, by);
- int y = ySize - my - by;
- int x = xSize - mx - bx1;
-
- InvalidateRect(NULL);
-
- MoveItem(IDCANCEL, x, y, bx1, by);
- MoveItem(IDOK, x - mx - bx2, y, bx2, by);
- ChangeSubWindowSizeX(_comboBox, xSize - mx * 2);
- return false;
-}
-
-void CComboDialog::OnOK()
-{
- _comboBox.GetText(Value);
- CModalDialog::OnOK();
-}
+// ComboDialog.cpp
+
+#include "StdAfx.h"
+#include "ComboDialog.h"
+
+#include "../../../Windows/Control/Static.h"
+
+#ifdef Z7_LANG
+#include "LangUtils.h"
+#endif
+
+using namespace NWindows;
+
+bool CComboDialog::OnInit()
+{
+ #ifdef Z7_LANG
+ LangSetDlgItems(*this, NULL, 0);
+ #endif
+ _comboBox.Attach(GetItem(IDC_COMBO));
+
+ /*
+ // why it doesn't work ?
+ DWORD style = _comboBox.GetStyle();
+ if (Sorted)
+ style |= CBS_SORT;
+ else
+ style &= ~CBS_SORT;
+ _comboBox.SetStyle(style);
+ */
+ SetText(Title);
+
+ NControl::CStatic staticContol;
+ staticContol.Attach(GetItem(IDT_COMBO));
+ staticContol.SetText(Static);
+ _comboBox.SetText(Value);
+ FOR_VECTOR (i, Strings)
+ _comboBox.AddString(Strings[i]);
+ NormalizeSize();
+ return CModalDialog::OnInit();
+}
+
+bool CComboDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
+{
+ int mx, my;
+ GetMargins(8, mx, my);
+ int bx1, bx2, by;
+ GetItemSizes(IDCANCEL, bx1, by);
+ GetItemSizes(IDOK, bx2, by);
+ int y = ySize - my - by;
+ int x = xSize - mx - bx1;
+
+ InvalidateRect(NULL);
+
+ MoveItem(IDCANCEL, x, y, bx1, by);
+ MoveItem(IDOK, x - mx - bx2, y, bx2, by);
+ ChangeSubWindowSizeX(_comboBox, xSize - mx * 2);
+ return false;
+}
+
+void CComboDialog::OnOK()
+{
+ _comboBox.GetText(Value);
+ CModalDialog::OnOK();
+}
diff --git a/CPP/7zip/UI/FileManager/ComboDialog.h b/CPP/7zip/UI/FileManager/ComboDialog.h
index 6869cff..bb0fda8 100644
--- a/CPP/7zip/UI/FileManager/ComboDialog.h
+++ b/CPP/7zip/UI/FileManager/ComboDialog.h
@@ -1,28 +1,28 @@
-// ComboDialog.h
-
-#ifndef __COMBO_DIALOG_H
-#define __COMBO_DIALOG_H
-
-#include "../../../Windows/Control/ComboBox.h"
-#include "../../../Windows/Control/Dialog.h"
-
-#include "ComboDialogRes.h"
-
-class CComboDialog: public NWindows::NControl::CModalDialog
-{
- NWindows::NControl::CComboBox _comboBox;
- virtual void OnOK();
- virtual bool OnInit();
- virtual bool OnSize(WPARAM wParam, int xSize, int ySize);
-public:
- // bool Sorted;
- UString Title;
- UString Static;
- UString Value;
- UStringVector Strings;
-
- // CComboDialog(): Sorted(false) {};
- INT_PTR Create(HWND parentWindow = 0) { return CModalDialog::Create(IDD_COMBO, parentWindow); }
-};
-
-#endif
+// ComboDialog.h
+
+#ifndef ZIP7_INC_COMBO_DIALOG_H
+#define ZIP7_INC_COMBO_DIALOG_H
+
+#include "../../../Windows/Control/ComboBox.h"
+#include "../../../Windows/Control/Dialog.h"
+
+#include "ComboDialogRes.h"
+
+class CComboDialog: public NWindows::NControl::CModalDialog
+{
+ NWindows::NControl::CComboBox _comboBox;
+ virtual void OnOK() Z7_override;
+ virtual bool OnInit() Z7_override;
+ virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override;
+public:
+ // bool Sorted;
+ UString Title;
+ UString Static;
+ UString Value;
+ UStringVector Strings;
+
+ // CComboDialog(): Sorted(false) {};
+ INT_PTR Create(HWND parentWindow = NULL) { return CModalDialog::Create(IDD_COMBO, parentWindow); }
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/ComboDialog.rc b/CPP/7zip/UI/FileManager/ComboDialog.rc
new file mode 100644
index 0000000..fddb748
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ComboDialog.rc
@@ -0,0 +1,16 @@
+#include "ComboDialogRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 240
+#define yc 64
+
+IDD_COMBO DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT
+CAPTION "Combo"
+{
+ LTEXT "", IDT_COMBO, m, m, xc, 8
+ COMBOBOX IDC_COMBO, m, 20, xc, 65, MY_COMBO_WITH_EDIT
+ OK_CANCEL
+}
+
+#undef xc
+#undef yc
diff --git a/CPP/7zip/UI/FileManager/ComboDialogRes.h b/CPP/7zip/UI/FileManager/ComboDialogRes.h
index 98938b6..a044797 100644
--- a/CPP/7zip/UI/FileManager/ComboDialogRes.h
+++ b/CPP/7zip/UI/FileManager/ComboDialogRes.h
@@ -1,4 +1,4 @@
-#define IDD_COMBO 98
-
-#define IDT_COMBO 100
-#define IDC_COMBO 101
+#define IDD_COMBO 98
+
+#define IDT_COMBO 100
+#define IDC_COMBO 101
diff --git a/CPP/7zip/UI/FileManager/Copy.bmp b/CPP/7zip/UI/FileManager/Copy.bmp
new file mode 100644
index 0000000..0f28a32
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Copy.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/Copy2.bmp b/CPP/7zip/UI/FileManager/Copy2.bmp
new file mode 100644
index 0000000..ba88ded
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Copy2.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/CopyDialog.cpp b/CPP/7zip/UI/FileManager/CopyDialog.cpp
new file mode 100644
index 0000000..9bc01d0
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/CopyDialog.cpp
@@ -0,0 +1,103 @@
+// CopyDialog.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Windows/FileName.h"
+
+#include "../../../Windows/Control/Static.h"
+
+#include "BrowseDialog.h"
+#include "CopyDialog.h"
+#include "LangUtils.h"
+
+using namespace NWindows;
+
+bool CCopyDialog::OnInit()
+{
+ #ifdef Z7_LANG
+ LangSetDlgItems(*this, NULL, 0);
+ #endif
+ _path.Attach(GetItem(IDC_COPY));
+ SetText(Title);
+
+ NControl::CStatic staticContol;
+ staticContol.Attach(GetItem(IDT_COPY));
+ staticContol.SetText(Static);
+ #ifdef UNDER_CE
+ // we do it, since WinCE selects Value\something instead of Value !!!!
+ _path.AddString(Value);
+ #endif
+ FOR_VECTOR (i, Strings)
+ _path.AddString(Strings[i]);
+ _path.SetText(Value);
+ SetItemText(IDT_COPY_INFO, Info);
+ NormalizeSize(true);
+ return CModalDialog::OnInit();
+}
+
+bool CCopyDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
+{
+ int mx, my;
+ GetMargins(8, mx, my);
+ int bx1, bx2, by;
+ GetItemSizes(IDCANCEL, bx1, by);
+ GetItemSizes(IDOK, bx2, by);
+ const int y = ySize - my - by;
+ const int x = xSize - mx - bx1;
+
+ InvalidateRect(NULL);
+
+ {
+ RECT r;
+ GetClientRectOfItem(IDB_COPY_SET_PATH, r);
+ const int bx = RECT_SIZE_X(r);
+ MoveItem(IDB_COPY_SET_PATH, xSize - mx - bx, r.top, bx, RECT_SIZE_Y(r));
+ ChangeSubWindowSizeX(_path, xSize - mx - mx - bx - mx);
+ }
+
+ {
+ RECT r;
+ GetClientRectOfItem(IDT_COPY_INFO, r);
+ NControl::CStatic staticContol;
+ staticContol.Attach(GetItem(IDT_COPY_INFO));
+ const int yPos = r.top;
+ staticContol.Move(mx, yPos, xSize - mx * 2, y - 2 - yPos);
+ }
+
+ MoveItem(IDCANCEL, x, y, bx1, by);
+ MoveItem(IDOK, x - mx - bx2, y, bx2, by);
+
+ return false;
+}
+
+bool CCopyDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ switch (buttonID)
+ {
+ case IDB_COPY_SET_PATH:
+ OnButtonSetPath();
+ return true;
+ }
+ return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
+}
+
+void CCopyDialog::OnButtonSetPath()
+{
+ UString currentPath;
+ _path.GetText(currentPath);
+
+ const UString title = LangString(IDS_SET_FOLDER);
+
+ UString resultPath;
+ if (!MyBrowseForFolder(*this, title, currentPath, resultPath))
+ return;
+ NFile::NName::NormalizeDirPathPrefix(resultPath);
+ _path.SetCurSel(-1);
+ _path.SetText(resultPath);
+}
+
+void CCopyDialog::OnOK()
+{
+ _path.GetText(Value);
+ CModalDialog::OnOK();
+}
diff --git a/CPP/7zip/UI/FileManager/CopyDialog.h b/CPP/7zip/UI/FileManager/CopyDialog.h
new file mode 100644
index 0000000..3782420
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/CopyDialog.h
@@ -0,0 +1,31 @@
+// CopyDialog.h
+
+#ifndef ZIP7_INC_COPY_DIALOG_H
+#define ZIP7_INC_COPY_DIALOG_H
+
+#include "../../../Windows/Control/ComboBox.h"
+#include "../../../Windows/Control/Dialog.h"
+
+#include "CopyDialogRes.h"
+
+const int kCopyDialog_NumInfoLines = 11;
+
+class CCopyDialog: public NWindows::NControl::CModalDialog
+{
+ NWindows::NControl::CComboBox _path;
+ virtual void OnOK() Z7_override;
+ virtual bool OnInit() Z7_override;
+ virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override;
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+ void OnButtonSetPath();
+public:
+ UString Title;
+ UString Static;
+ UString Value;
+ UString Info;
+ UStringVector Strings;
+
+ INT_PTR Create(HWND parentWindow = NULL) { return CModalDialog::Create(IDD_COPY, parentWindow); }
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/CopyDialog.rc b/CPP/7zip/UI/FileManager/CopyDialog.rc
new file mode 100644
index 0000000..73d3ea8
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/CopyDialog.rc
@@ -0,0 +1,20 @@
+#include "CopyDialogRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 320
+#define yc 144
+
+#define y 40
+
+IDD_COPY DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT
+CAPTION "Copy"
+{
+ LTEXT "", IDT_COPY, m, m, xc, 8
+ COMBOBOX IDC_COPY, m, 20, xc - bxsDots - m, 65, MY_COMBO_WITH_EDIT
+ PUSHBUTTON "...", IDB_COPY_SET_PATH, xs - m - bxsDots, 18, bxsDots, bys, WS_GROUP
+ LTEXT "", IDT_COPY_INFO, m, y, xc, by - y - 1, SS_NOPREFIX | SS_LEFTNOWORDWRAP
+ OK_CANCEL
+}
+
+#undef xc
+#undef yc
diff --git a/CPP/7zip/UI/FileManager/CopyDialogRes.h b/CPP/7zip/UI/FileManager/CopyDialogRes.h
new file mode 100644
index 0000000..85f5a39
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/CopyDialogRes.h
@@ -0,0 +1,8 @@
+#define IDD_COPY 96
+
+#define IDT_COPY 100
+#define IDC_COPY 101
+#define IDB_COPY_SET_PATH 102
+#define IDT_COPY_INFO 103
+
+#define IDS_SET_FOLDER 6007
diff --git a/CPP/7zip/UI/FileManager/Delete.bmp b/CPP/7zip/UI/FileManager/Delete.bmp
new file mode 100644
index 0000000..d1004d8
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Delete.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/Delete2.bmp b/CPP/7zip/UI/FileManager/Delete2.bmp
new file mode 100644
index 0000000..60e08c6
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Delete2.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/DialogSize.h b/CPP/7zip/UI/FileManager/DialogSize.h
index bbce159..9f2270b 100644
--- a/CPP/7zip/UI/FileManager/DialogSize.h
+++ b/CPP/7zip/UI/FileManager/DialogSize.h
@@ -1,16 +1,16 @@
-// DialogSize.h
-
-#ifndef __DIALOG_SIZE_H
-#define __DIALOG_SIZE_H
-
-#include "../../../Windows/Control/Dialog.h"
-
-#ifdef UNDER_CE
-#define BIG_DIALOG_SIZE(x, y) bool isBig = NWindows::NControl::IsDialogSizeOK(x, y);
-#define SIZED_DIALOG(big) (isBig ? big : big ## _2)
-#else
-#define BIG_DIALOG_SIZE(x, y)
-#define SIZED_DIALOG(big) big
-#endif
-
-#endif
+// DialogSize.h
+
+#ifndef ZIP7_INC_DIALOG_SIZE_H
+#define ZIP7_INC_DIALOG_SIZE_H
+
+#include "../../../Windows/Control/Dialog.h"
+
+#ifdef UNDER_CE
+#define BIG_DIALOG_SIZE(x, y) bool isBig = NWindows::NControl::IsDialogSizeOK(x, y);
+#define SIZED_DIALOG(big) (isBig ? big : big ## _2)
+#else
+#define BIG_DIALOG_SIZE(x, y)
+#define SIZED_DIALOG(big) big
+#endif
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/EditDialog.cpp b/CPP/7zip/UI/FileManager/EditDialog.cpp
new file mode 100644
index 0000000..e97d9ea
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EditDialog.cpp
@@ -0,0 +1,57 @@
+// EditDialog.cpp
+
+#include "StdAfx.h"
+
+#include "EditDialog.h"
+
+#ifdef Z7_LANG
+#include "LangUtils.h"
+#endif
+
+bool CEditDialog::OnInit()
+{
+ #ifdef Z7_LANG
+ LangSetDlgItems(*this, NULL, 0);
+ #endif
+ _edit.Attach(GetItem(IDE_EDIT));
+
+ SetText(Title);
+ _edit.SetText(Text);
+
+ NormalizeSize();
+ return CModalDialog::OnInit();
+}
+
+// #define MY_CLOSE_BUTTON_ID IDCANCEL
+#define MY_CLOSE_BUTTON_ID IDCLOSE
+
+bool CEditDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
+{
+ int mx, my;
+ GetMargins(8, mx, my);
+ int bx1, by;
+ GetItemSizes(MY_CLOSE_BUTTON_ID, bx1, by);
+
+ // int bx2;
+ // GetItemSizes(IDOK, bx2, by);
+
+ const int y = ySize - my - by;
+ const int x = xSize - mx - bx1;
+
+ /*
+ RECT rect;
+ GetClientRect(&rect);
+ rect.top = y - my;
+ InvalidateRect(&rect);
+ */
+ InvalidateRect(NULL);
+
+ MoveItem(MY_CLOSE_BUTTON_ID, x, y, bx1, by);
+ // MoveItem(IDOK, x - mx - bx2, y, bx2, by);
+ /*
+ if (wParam == SIZE_MAXSHOW || wParam == SIZE_MAXIMIZED || wParam == SIZE_MAXHIDE)
+ mx = 0;
+ */
+ _edit.Move(mx, my, xSize - mx * 2, y - my * 2);
+ return false;
+}
diff --git a/CPP/7zip/UI/FileManager/EditDialog.h b/CPP/7zip/UI/FileManager/EditDialog.h
new file mode 100644
index 0000000..6970b14
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EditDialog.h
@@ -0,0 +1,25 @@
+// EditDialog.h
+
+#ifndef ZIP7_INC_EDIT_DIALOG_H
+#define ZIP7_INC_EDIT_DIALOG_H
+
+#include "../../../Windows/Control/Dialog.h"
+#include "../../../Windows/Control/Edit.h"
+
+#include "EditDialogRes.h"
+
+class CEditDialog: public NWindows::NControl::CModalDialog
+{
+ NWindows::NControl::CEdit _edit;
+ virtual bool OnInit() Z7_override;
+ virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override;
+public:
+ UString Title;
+ UString Text;
+
+ INT_PTR Create(HWND wndParent = NULL) { return CModalDialog::Create(IDD_EDIT_DLG, wndParent); }
+
+ CEditDialog() {}
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/EditDialog.rc b/CPP/7zip/UI/FileManager/EditDialog.rc
new file mode 100644
index 0000000..cdb0b44
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EditDialog.rc
@@ -0,0 +1,15 @@
+#include "EditDialogRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 320
+#define yc 240
+
+IDD_EDIT_DLG DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT
+CAPTION "Edit"
+{
+ // OK_CANCEL
+ MY_BUTTON__CLOSE
+
+ EDITTEXT IDE_EDIT, m, m, xc, yc - bys - m,
+ ES_MULTILINE | ES_READONLY | WS_VSCROLL | WS_HSCROLL | ES_WANTRETURN
+}
diff --git a/CPP/7zip/UI/FileManager/EditDialogRes.h b/CPP/7zip/UI/FileManager/EditDialogRes.h
new file mode 100644
index 0000000..58c5ca9
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EditDialogRes.h
@@ -0,0 +1,2 @@
+#define IDD_EDIT_DLG 94
+#define IDE_EDIT 100
diff --git a/CPP/7zip/UI/FileManager/EditPage.cpp b/CPP/7zip/UI/FileManager/EditPage.cpp
new file mode 100644
index 0000000..a2a0321
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EditPage.cpp
@@ -0,0 +1,159 @@
+// EditPage.cpp
+
+#include "StdAfx.h"
+
+#include "EditPage.h"
+#include "EditPageRes.h"
+
+#include "BrowseDialog.h"
+#include "HelpUtils.h"
+#include "LangUtils.h"
+#include "RegistryUtils.h"
+
+using namespace NWindows;
+
+#ifdef Z7_LANG
+static const UInt32 kLangIDs[] =
+{
+ IDT_EDIT_EDITOR,
+ IDT_EDIT_DIFF
+};
+
+static const UInt32 kLangIDs_Colon[] =
+{
+ IDT_EDIT_VIEWER
+};
+#endif
+
+#define kEditTopic "FM/options.htm#editor"
+
+bool CEditPage::OnInit()
+{
+ _initMode = true;
+
+ #ifdef Z7_LANG
+ LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
+ LangSetDlgItems_Colon(*this, kLangIDs_Colon, Z7_ARRAY_SIZE(kLangIDs_Colon));
+ #endif
+
+ _ctrls[0].Ctrl = IDE_EDIT_VIEWER; _ctrls[0].Button = IDB_EDIT_VIEWER;
+ _ctrls[1].Ctrl = IDE_EDIT_EDITOR; _ctrls[1].Button = IDB_EDIT_EDITOR;
+ _ctrls[2].Ctrl = IDE_EDIT_DIFF; _ctrls[2].Button = IDB_EDIT_DIFF;
+
+ for (unsigned i = 0; i < 3; i++)
+ {
+ CEditPageCtrl &c = _ctrls[i];
+ c.WasChanged = false;
+ c.Edit.Attach(GetItem(c.Ctrl));
+ UString path;
+ if (i < 2)
+ ReadRegEditor(i > 0, path);
+ else
+ ReadRegDiff(path);
+ c.Edit.SetText(path);
+ }
+
+ _initMode = false;
+
+ return CPropertyPage::OnInit();
+}
+
+LONG CEditPage::OnApply()
+{
+ for (unsigned i = 0; i < 3; i++)
+ {
+ CEditPageCtrl &c = _ctrls[i];
+ if (c.WasChanged)
+ {
+ UString path;
+ c.Edit.GetText(path);
+ if (i < 2)
+ SaveRegEditor(i > 0, path);
+ else
+ SaveRegDiff(path);
+ c.WasChanged = false;
+ }
+ }
+
+ return PSNRET_NOERROR;
+}
+
+void CEditPage::OnNotifyHelp()
+{
+ ShowHelpWindow(kEditTopic);
+}
+
+void SplitCmdLineSmart(const UString &cmd, UString &prg, UString &params);
+
+static void Edit_BrowseForFile(NWindows::NControl::CEdit &edit, HWND hwnd)
+{
+ UString cmd;
+ edit.GetText(cmd);
+
+ UString param;
+ UString prg;
+
+ SplitCmdLineSmart(cmd, prg, param);
+
+ CObjectVector<CBrowseFilterInfo> filters;
+ CBrowseFilterInfo &bfi = filters.AddNew();
+ bfi.Description = "*.exe";
+ bfi.Masks.Add(UString("*.exe"));
+
+ CBrowseInfo bi;
+ bi.FilterIndex = 0;
+ bi.FilePath = prg;
+ bi.hwndOwner = hwnd;
+
+ if (bi.BrowseForFile(filters))
+ {
+ cmd = bi.FilePath;
+ cmd.Trim();
+ /*
+ if (!param.IsEmpty() && !resPath.IsEmpty())
+ {
+ cmd.InsertAtFront(L'\"');
+ cmd += L'\"';
+ cmd.Add_Space();
+ cmd += param;
+ }
+ */
+
+ edit.SetText(cmd);
+ // Changed();
+ }
+}
+
+bool CEditPage::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ for (unsigned i = 0; i < 3; i++)
+ {
+ CEditPageCtrl &c = _ctrls[i];
+ if (buttonID == c.Button)
+ {
+ Edit_BrowseForFile(c.Edit, *this);
+ return true;
+ }
+ }
+
+ return CPropertyPage::OnButtonClicked(buttonID, buttonHWND);
+}
+
+bool CEditPage::OnCommand(unsigned code, unsigned itemID, LPARAM param)
+{
+ if (!_initMode && code == EN_CHANGE)
+ {
+ for (unsigned i = 0; i < 3; i++)
+ {
+ CEditPageCtrl &c = _ctrls[i];
+ if (itemID == c.Ctrl)
+ {
+ c.WasChanged = true;
+ Changed();
+ return true;
+ }
+ }
+ }
+
+ return CPropertyPage::OnCommand(code, itemID, param);
+}
diff --git a/CPP/7zip/UI/FileManager/EditPage.h b/CPP/7zip/UI/FileManager/EditPage.h
new file mode 100644
index 0000000..a70fad7
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EditPage.h
@@ -0,0 +1,30 @@
+// EditPage.h
+
+#ifndef ZIP7_INC_EDIT_PAGE_H
+#define ZIP7_INC_EDIT_PAGE_H
+
+#include "../../../Windows/Control/PropertyPage.h"
+#include "../../../Windows/Control/Edit.h"
+
+struct CEditPageCtrl
+{
+ NWindows::NControl::CEdit Edit;
+ bool WasChanged;
+ unsigned Ctrl;
+ unsigned Button;
+};
+
+class CEditPage: public NWindows::NControl::CPropertyPage
+{
+ CEditPageCtrl _ctrls[3];
+
+ bool _initMode;
+public:
+ virtual bool OnInit() Z7_override;
+ virtual void OnNotifyHelp() Z7_override;
+ virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM param) Z7_override;
+ virtual LONG OnApply() Z7_override;
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/EditPage.rc b/CPP/7zip/UI/FileManager/EditPage.rc
new file mode 100644
index 0000000..38f74ea
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EditPage.rc
@@ -0,0 +1,19 @@
+#include "EditPageRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 240
+#define yc 80
+
+IDD_EDIT MY_PAGE
+#include "EditPage2.rc"
+
+#ifdef UNDER_CE
+
+#undef xc
+
+#define xc SMALL_PAGE_SIZE_X
+
+IDD_EDIT_2 MY_PAGE
+#include "EditPage2.rc"
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/EditPage2.rc b/CPP/7zip/UI/FileManager/EditPage2.rc
new file mode 100644
index 0000000..2d6554f
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EditPage2.rc
@@ -0,0 +1,14 @@
+CAPTION "Editor"
+{
+ LTEXT "&View:", IDT_EDIT_VIEWER, m, m, xc, 8
+ EDITTEXT IDE_EDIT_VIEWER, m, m + 12, xc - m - bxsDots, 14, ES_AUTOHSCROLL
+ PUSHBUTTON "...", IDB_EDIT_VIEWER, xs - m - bxsDots, m + 11, bxsDots, bys
+
+ LTEXT "&Editor:", IDT_EDIT_EDITOR, m, m + 32, xc, 8
+ EDITTEXT IDE_EDIT_EDITOR, m, m + 44, xc - m - bxsDots, 14, ES_AUTOHSCROLL
+ PUSHBUTTON "...", IDB_EDIT_EDITOR, xs - m - bxsDots, m + 43, bxsDots, bys
+
+ LTEXT "&Diff:", IDT_EDIT_DIFF, m, m + 64, xc, 8
+ EDITTEXT IDE_EDIT_DIFF, m, m + 76, xc - m - bxsDots, 14, ES_AUTOHSCROLL
+ PUSHBUTTON "...", IDB_EDIT_DIFF, xs - m - bxsDots, m + 75, bxsDots, bys
+}
diff --git a/CPP/7zip/UI/FileManager/EditPageRes.h b/CPP/7zip/UI/FileManager/EditPageRes.h
new file mode 100644
index 0000000..017d702
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EditPageRes.h
@@ -0,0 +1,15 @@
+#define IDD_EDIT 2103
+#define IDD_EDIT_2 12103
+
+#define IDT_EDIT_VIEWER 543
+#define IDT_EDIT_EDITOR 2104
+#define IDT_EDIT_DIFF 2105
+
+#define IDE_EDIT_VIEWER 100
+#define IDB_EDIT_VIEWER 101
+
+#define IDE_EDIT_EDITOR 102
+#define IDB_EDIT_EDITOR 103
+
+#define IDE_EDIT_DIFF 104
+#define IDB_EDIT_DIFF 105
diff --git a/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp b/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp
new file mode 100644
index 0000000..fc2fd6c
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EnumFormatEtc.cpp
@@ -0,0 +1,107 @@
+// EnumFormatEtc.cpp
+
+#include "StdAfx.h"
+
+#include "EnumFormatEtc.h"
+#include "../../IDecl.h"
+#include "MyCom2.h"
+
+class CEnumFormatEtc Z7_final:
+ public IEnumFORMATETC,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_1_MT(IEnumFORMATETC)
+
+ STDMETHOD(Next)(ULONG celt, FORMATETC *rgelt, ULONG *pceltFetched) Z7_override;
+ STDMETHOD(Skip)(ULONG celt) Z7_override;
+ STDMETHOD(Reset)(void) Z7_override;
+ STDMETHOD(Clone)(IEnumFORMATETC **ppEnumFormatEtc) Z7_override;
+
+ LONG m_RefCount;
+ ULONG m_NumFormats;
+ FORMATETC *m_Formats;
+ ULONG m_Index;
+public:
+ CEnumFormatEtc(const FORMATETC *pFormatEtc, ULONG numFormats);
+ ~CEnumFormatEtc();
+};
+
+static void DeepCopyFormatEtc(FORMATETC *dest, const FORMATETC *src)
+{
+ *dest = *src;
+ if (src->ptd)
+ {
+ dest->ptd = (DVTARGETDEVICE*)CoTaskMemAlloc(sizeof(DVTARGETDEVICE));
+ *(dest->ptd) = *(src->ptd);
+ }
+}
+
+CEnumFormatEtc::CEnumFormatEtc(const FORMATETC *pFormatEtc, ULONG numFormats)
+{
+ m_RefCount = 1;
+ m_Index = 0;
+ m_NumFormats = 0;
+ m_Formats = new FORMATETC[numFormats];
+ // if (m_Formats)
+ {
+ m_NumFormats = numFormats;
+ for (ULONG i = 0; i < numFormats; i++)
+ DeepCopyFormatEtc(&m_Formats[i], &pFormatEtc[i]);
+ }
+}
+
+CEnumFormatEtc::~CEnumFormatEtc()
+{
+ if (m_Formats)
+ {
+ for (ULONG i = 0; i < m_NumFormats; i++)
+ if (m_Formats[i].ptd)
+ CoTaskMemFree(m_Formats[i].ptd);
+ delete []m_Formats;
+ }
+}
+
+Z7_COMWF_B CEnumFormatEtc::Next(ULONG celt, FORMATETC *pFormatEtc, ULONG *pceltFetched)
+{
+ ULONG copied = 0;
+ if (celt == 0 || !pFormatEtc)
+ return E_INVALIDARG;
+ while (m_Index < m_NumFormats && copied < celt)
+ {
+ DeepCopyFormatEtc(&pFormatEtc[copied], &m_Formats[m_Index]);
+ copied++;
+ m_Index++;
+ }
+ if (pceltFetched)
+ *pceltFetched = copied;
+ return (copied == celt) ? S_OK : S_FALSE;
+}
+
+Z7_COMWF_B CEnumFormatEtc::Skip(ULONG celt)
+{
+ m_Index += celt;
+ return (m_Index <= m_NumFormats) ? S_OK : S_FALSE;
+}
+
+Z7_COMWF_B CEnumFormatEtc::Reset(void)
+{
+ m_Index = 0;
+ return S_OK;
+}
+
+Z7_COMWF_B CEnumFormatEtc::Clone(IEnumFORMATETC ** ppEnumFormatEtc)
+{
+ HRESULT hResult = CreateEnumFormatEtc(m_NumFormats, m_Formats, ppEnumFormatEtc);
+ if (hResult == S_OK)
+ ((CEnumFormatEtc *)*ppEnumFormatEtc)->m_Index = m_Index;
+ return hResult;
+}
+
+// replacement for SHCreateStdEnumFmtEtc
+HRESULT CreateEnumFormatEtc(UINT numFormats, const FORMATETC *formats, IEnumFORMATETC **enumFormat)
+{
+ if (numFormats == 0 || !formats || !enumFormat)
+ return E_INVALIDARG;
+ *enumFormat = new CEnumFormatEtc(formats, numFormats);
+ return (*enumFormat) ? S_OK : E_OUTOFMEMORY;
+}
diff --git a/CPP/7zip/UI/FileManager/EnumFormatEtc.h b/CPP/7zip/UI/FileManager/EnumFormatEtc.h
new file mode 100644
index 0000000..12df225
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/EnumFormatEtc.h
@@ -0,0 +1,10 @@
+// EnumFormatEtc.h
+
+#ifndef ZIP7_INC_ENUMFORMATETC_H
+#define ZIP7_INC_ENUMFORMATETC_H
+
+#include "../../../Common/MyWindows.h"
+
+HRESULT CreateEnumFormatEtc(UINT numFormats, const FORMATETC *formats, IEnumFORMATETC **enumFormat);
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/Extract.bmp b/CPP/7zip/UI/FileManager/Extract.bmp
new file mode 100644
index 0000000..0aeba92
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Extract.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/Extract2.bmp b/CPP/7zip/UI/FileManager/Extract2.bmp
new file mode 100644
index 0000000..a7e5775
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Extract2.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/ExtractCallback.cpp b/CPP/7zip/UI/FileManager/ExtractCallback.cpp
index f230594..f674044 100644
--- a/CPP/7zip/UI/FileManager/ExtractCallback.cpp
+++ b/CPP/7zip/UI/FileManager/ExtractCallback.cpp
@@ -1,1037 +1,1056 @@
-// ExtractCallback.cpp
-
-#include "StdAfx.h"
-
-
-#include "../../../Common/ComTry.h"
-#include "../../../Common/IntToString.h"
-#include "../../../Common/Lang.h"
-#include "../../../Common/StringConvert.h"
-
-#include "../../../Windows/ErrorMsg.h"
-#include "../../../Windows/FileDir.h"
-#include "../../../Windows/FileFind.h"
-#include "../../../Windows/PropVariantConv.h"
-
-#include "../../Common/FilePathAutoRename.h"
-#include "../../Common/StreamUtils.h"
-#include "../Common/ExtractingFilePath.h"
-
-#ifndef _SFX
-#include "../Common/ZipRegistry.h"
-#endif
-
-#include "../GUI/ExtractRes.h"
-#include "resourceGui.h"
-
-#include "ExtractCallback.h"
-#include "FormatUtils.h"
-#include "LangUtils.h"
-#include "OverwriteDialog.h"
-#ifndef _NO_CRYPTO
-#include "PasswordDialog.h"
-#endif
-#include "PropertyName.h"
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NFind;
-
-CExtractCallbackImp::~CExtractCallbackImp() {}
-
-void CExtractCallbackImp::Init()
-{
- _lang_Extracting = LangString(IDS_PROGRESS_EXTRACTING);
- _lang_Testing = LangString(IDS_PROGRESS_TESTING);
- _lang_Skipping = LangString(IDS_PROGRESS_SKIPPING);
-
- NumArchiveErrors = 0;
- ThereAreMessageErrors = false;
- #ifndef _SFX
- NumFolders = NumFiles = 0;
- NeedAddFile = false;
- #endif
-}
-
-void CExtractCallbackImp::AddError_Message(LPCWSTR s)
-{
- ThereAreMessageErrors = true;
- ProgressDialog->Sync.AddError_Message(s);
-}
-
-#ifndef _SFX
-
-STDMETHODIMP CExtractCallbackImp::SetNumFiles(UInt64
- #ifndef _SFX
- numFiles
- #endif
- )
-{
- #ifndef _SFX
- ProgressDialog->Sync.Set_NumFilesTotal(numFiles);
- #endif
- return S_OK;
-}
-
-#endif
-
-STDMETHODIMP CExtractCallbackImp::SetTotal(UInt64 total)
-{
- ProgressDialog->Sync.Set_NumBytesTotal(total);
- return S_OK;
-}
-
-STDMETHODIMP CExtractCallbackImp::SetCompleted(const UInt64 *value)
-{
- return ProgressDialog->Sync.Set_NumBytesCur(value);
-}
-
-HRESULT CExtractCallbackImp::Open_CheckBreak()
-{
- return ProgressDialog->Sync.CheckStop();
-}
-
-HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 *files, const UInt64 *bytes)
-{
- HRESULT res = S_OK;
- if (!MultiArcMode)
- {
- if (files)
- {
- _totalFilesDefined = true;
- // res = ProgressDialog->Sync.Set_NumFilesTotal(*files);
- }
- else
- _totalFilesDefined = false;
-
- if (bytes)
- {
- _totalBytesDefined = true;
- ProgressDialog->Sync.Set_NumBytesTotal(*bytes);
- }
- else
- _totalBytesDefined = false;
- }
-
- return res;
-}
-
-HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 *files, const UInt64 *bytes)
-{
- if (!MultiArcMode)
- {
- if (files)
- {
- ProgressDialog->Sync.Set_NumFilesCur(*files);
- }
-
- if (bytes)
- {
- }
- }
-
- return ProgressDialog->Sync.CheckStop();
-}
-
-HRESULT CExtractCallbackImp::Open_Finished()
-{
- return ProgressDialog->Sync.CheckStop();
-}
-
-#ifndef _NO_CRYPTO
-
-HRESULT CExtractCallbackImp::Open_CryptoGetTextPassword(BSTR *password)
-{
- return CryptoGetTextPassword(password);
-}
-
-/*
-HRESULT CExtractCallbackImp::Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password)
-{
- passwordIsDefined = PasswordIsDefined;
- password = Password;
- return S_OK;
-}
-
-bool CExtractCallbackImp::Open_WasPasswordAsked()
-{
- return PasswordWasAsked;
-}
-
-void CExtractCallbackImp::Open_Clear_PasswordWasAsked_Flag()
-{
- PasswordWasAsked = false;
-}
-*/
-
-#endif
-
-
-#ifndef _SFX
-STDMETHODIMP CExtractCallbackImp::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
-{
- ProgressDialog->Sync.Set_Ratio(inSize, outSize);
- return S_OK;
-}
-#endif
-
-/*
-STDMETHODIMP CExtractCallbackImp::SetTotalFiles(UInt64 total)
-{
- ProgressDialog->Sync.SetNumFilesTotal(total);
- return S_OK;
-}
-
-STDMETHODIMP CExtractCallbackImp::SetCompletedFiles(const UInt64 *value)
-{
- if (value != NULL)
- ProgressDialog->Sync.SetNumFilesCur(*value);
- return S_OK;
-}
-*/
-
-STDMETHODIMP CExtractCallbackImp::AskOverwrite(
- const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
- const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
- Int32 *answer)
-{
- COverwriteDialog dialog;
-
- dialog.OldFileInfo.SetTime(existTime);
- dialog.OldFileInfo.SetSize(existSize);
- dialog.OldFileInfo.Name = existName;
-
- dialog.NewFileInfo.SetTime(newTime);
- dialog.NewFileInfo.SetSize(newSize);
- dialog.NewFileInfo.Name = newName;
-
- ProgressDialog->WaitCreating();
- INT_PTR writeAnswer = dialog.Create(*ProgressDialog);
-
- switch (writeAnswer)
- {
- case IDCANCEL: *answer = NOverwriteAnswer::kCancel; return E_ABORT;
- case IDYES: *answer = NOverwriteAnswer::kYes; break;
- case IDNO: *answer = NOverwriteAnswer::kNo; break;
- case IDB_YES_TO_ALL: *answer = NOverwriteAnswer::kYesToAll; break;
- case IDB_NO_TO_ALL: *answer = NOverwriteAnswer::kNoToAll; break;
- case IDB_AUTO_RENAME: *answer = NOverwriteAnswer::kAutoRename; break;
- default: return E_FAIL;
- }
- return S_OK;
-}
-
-
-STDMETHODIMP CExtractCallbackImp::PrepareOperation(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 * /* position */)
-{
- _isFolder = IntToBool(isFolder);
- _currentFilePath = name;
-
- const UString *msg = &_lang_Empty;
- switch (askExtractMode)
- {
- case NArchive::NExtract::NAskMode::kExtract: msg = &_lang_Extracting; break;
- case NArchive::NExtract::NAskMode::kTest: msg = &_lang_Testing; break;
- case NArchive::NExtract::NAskMode::kSkip: msg = &_lang_Skipping; break;
- // default: s = "Unknown operation";
- }
-
- return ProgressDialog->Sync.Set_Status2(*msg, name, IntToBool(isFolder));
-}
-
-STDMETHODIMP CExtractCallbackImp::MessageError(const wchar_t *s)
-{
- AddError_Message(s);
- return S_OK;
-}
-
-HRESULT CExtractCallbackImp::MessageError(const char *message, const FString &path)
-{
- ThereAreMessageErrors = true;
- ProgressDialog->Sync.AddError_Message_Name(GetUnicodeString(message), fs2us(path));
- return S_OK;
-}
-
-#ifndef _SFX
-
-STDMETHODIMP CExtractCallbackImp::ShowMessage(const wchar_t *s)
-{
- AddError_Message(s);
- return S_OK;
-}
-
-#endif
-
-void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s)
-{
- s.Empty();
-
- if (opRes == NArchive::NExtract::NOperationResult::kOK)
- return;
-
- UINT messageID = 0;
- UINT id = 0;
-
- switch (opRes)
- {
- case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
- messageID = IDS_EXTRACT_MESSAGE_UNSUPPORTED_METHOD;
- id = IDS_EXTRACT_MSG_UNSUPPORTED_METHOD;
- break;
- case NArchive::NExtract::NOperationResult::kDataError:
- messageID = encrypted ?
- IDS_EXTRACT_MESSAGE_DATA_ERROR_ENCRYPTED:
- IDS_EXTRACT_MESSAGE_DATA_ERROR;
- id = IDS_EXTRACT_MSG_DATA_ERROR;
- break;
- case NArchive::NExtract::NOperationResult::kCRCError:
- messageID = encrypted ?
- IDS_EXTRACT_MESSAGE_CRC_ERROR_ENCRYPTED:
- IDS_EXTRACT_MESSAGE_CRC_ERROR;
- id = IDS_EXTRACT_MSG_CRC_ERROR;
- break;
- case NArchive::NExtract::NOperationResult::kUnavailable:
- id = IDS_EXTRACT_MSG_UNAVAILABLE_DATA;
- break;
- case NArchive::NExtract::NOperationResult::kUnexpectedEnd:
- id = IDS_EXTRACT_MSG_UEXPECTED_END;
- break;
- case NArchive::NExtract::NOperationResult::kDataAfterEnd:
- id = IDS_EXTRACT_MSG_DATA_AFTER_END;
- break;
- case NArchive::NExtract::NOperationResult::kIsNotArc:
- id = IDS_EXTRACT_MSG_IS_NOT_ARC;
- break;
- case NArchive::NExtract::NOperationResult::kHeadersError:
- id = IDS_EXTRACT_MSG_HEADERS_ERROR;
- break;
- case NArchive::NExtract::NOperationResult::kWrongPassword:
- id = IDS_EXTRACT_MSG_WRONG_PSW_CLAIM;
- break;
- /*
- default:
- messageID = IDS_EXTRACT_MESSAGE_UNKNOWN_ERROR;
- break;
- */
- }
-
- UString msg;
- UString msgOld;
-
- #ifndef _SFX
- if (id != 0)
- LangString_OnlyFromLangFile(id, msg);
- if (messageID != 0 && msg.IsEmpty())
- LangString_OnlyFromLangFile(messageID, msgOld);
- #endif
-
- if (msg.IsEmpty() && !msgOld.IsEmpty())
- s = MyFormatNew(msgOld, fileName);
- else
- {
- if (msg.IsEmpty() && id != 0)
- LangString(id, msg);
- if (!msg.IsEmpty())
- s += msg;
- else
- {
- s += "Error #";
- s.Add_UInt32(opRes);
- }
-
- if (encrypted && opRes != NArchive::NExtract::NOperationResult::kWrongPassword)
- {
- // s += " : ";
- // AddLangString(s, IDS_EXTRACT_MSG_ENCRYPTED);
- s += " : ";
- AddLangString(s, IDS_EXTRACT_MSG_WRONG_PSW_GUESS);
- }
- s += " : ";
- s += fileName;
- }
-}
-
-STDMETHODIMP CExtractCallbackImp::SetOperationResult(Int32 opRes, Int32 encrypted)
-{
- switch (opRes)
- {
- case NArchive::NExtract::NOperationResult::kOK:
- break;
- default:
- {
- UString s;
- SetExtractErrorMessage(opRes, encrypted, _currentFilePath, s);
- Add_ArchiveName_Error();
- AddError_Message(s);
- }
- }
-
- #ifndef _SFX
- if (_isFolder)
- NumFolders++;
- else
- NumFiles++;
- ProgressDialog->Sync.Set_NumFilesCur(NumFiles);
- #endif
-
- return S_OK;
-}
-
-STDMETHODIMP CExtractCallbackImp::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name)
-{
- if (opRes != NArchive::NExtract::NOperationResult::kOK)
- {
- UString s;
- SetExtractErrorMessage(opRes, encrypted, name, s);
- Add_ArchiveName_Error();
- AddError_Message(s);
- }
- return S_OK;
-}
-
-////////////////////////////////////////
-// IExtractCallbackUI
-
-HRESULT CExtractCallbackImp::BeforeOpen(const wchar_t *name, bool /* testMode */)
-{
- #ifndef _SFX
- RINOK(ProgressDialog->Sync.CheckStop());
- ProgressDialog->Sync.Set_TitleFileName(name);
- #endif
- _currentArchivePath = name;
- return S_OK;
-}
-
-HRESULT CExtractCallbackImp::SetCurrentFilePath2(const wchar_t *path)
-{
- _currentFilePath = path;
- #ifndef _SFX
- ProgressDialog->Sync.Set_FilePath(path);
- #endif
- return S_OK;
-}
-
-#ifndef _SFX
-
-HRESULT CExtractCallbackImp::SetCurrentFilePath(const wchar_t *path)
-{
- #ifndef _SFX
- if (NeedAddFile)
- NumFiles++;
- NeedAddFile = true;
- ProgressDialog->Sync.Set_NumFilesCur(NumFiles);
- #endif
- return SetCurrentFilePath2(path);
-}
-
-#endif
-
-UString HResultToMessage(HRESULT errorCode);
-
-static const UInt32 k_ErrorFlagsIds[] =
-{
- IDS_EXTRACT_MSG_IS_NOT_ARC,
- IDS_EXTRACT_MSG_HEADERS_ERROR,
- IDS_EXTRACT_MSG_HEADERS_ERROR,
- IDS_OPEN_MSG_UNAVAILABLE_START,
- IDS_OPEN_MSG_UNCONFIRMED_START,
- IDS_EXTRACT_MSG_UEXPECTED_END,
- IDS_EXTRACT_MSG_DATA_AFTER_END,
- IDS_EXTRACT_MSG_UNSUPPORTED_METHOD,
- IDS_OPEN_MSG_UNSUPPORTED_FEATURE,
- IDS_EXTRACT_MSG_DATA_ERROR,
- IDS_EXTRACT_MSG_CRC_ERROR
-};
-
-static void AddNewLineString(UString &s, const UString &m)
-{
- s += m;
- s.Add_LF();
-}
-
-UString GetOpenArcErrorMessage(UInt32 errorFlags)
-{
- UString s;
-
- for (unsigned i = 0; i < ARRAY_SIZE(k_ErrorFlagsIds); i++)
- {
- UInt32 f = ((UInt32)1 << i);
- if ((errorFlags & f) == 0)
- continue;
- UInt32 id = k_ErrorFlagsIds[i];
- UString m = LangString(id);
- if (m.IsEmpty())
- continue;
- if (f == kpv_ErrorFlags_EncryptedHeadersError)
- {
- m += " : ";
- AddLangString(m, IDS_EXTRACT_MSG_WRONG_PSW_GUESS);
- }
- if (!s.IsEmpty())
- s.Add_LF();
- s += m;
- errorFlags &= ~f;
- }
-
- if (errorFlags != 0)
- {
- char sz[16];
- sz[0] = '0';
- sz[1] = 'x';
- ConvertUInt32ToHex(errorFlags, sz + 2);
- if (!s.IsEmpty())
- s.Add_LF();
- s += sz;
- }
-
- return s;
-}
-
-static void ErrorInfo_Print(UString &s, const CArcErrorInfo &er)
-{
- UInt32 errorFlags = er.GetErrorFlags();
- UInt32 warningFlags = er.GetWarningFlags();
-
- if (errorFlags != 0)
- AddNewLineString(s, GetOpenArcErrorMessage(errorFlags));
-
- if (!er.ErrorMessage.IsEmpty())
- AddNewLineString(s, er.ErrorMessage);
-
- if (warningFlags != 0)
- {
- s += GetNameOfProperty(kpidWarningFlags, L"Warnings");
- s += ":";
- s.Add_LF();
- AddNewLineString(s, GetOpenArcErrorMessage(warningFlags));
- }
-
- if (!er.WarningMessage.IsEmpty())
- {
- s += GetNameOfProperty(kpidWarning, L"Warning");
- s += ": ";
- s += er.WarningMessage;
- s.Add_LF();
- }
-}
-
-static UString GetBracedType(const wchar_t *type)
-{
- UString s ('[');
- s += type;
- s += ']';
- return s;
-}
-
-void OpenResult_GUI(UString &s, const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result)
-{
- FOR_VECTOR (level, arcLink.Arcs)
- {
- const CArc &arc = arcLink.Arcs[level];
- const CArcErrorInfo &er = arc.ErrorInfo;
-
- if (!er.IsThereErrorOrWarning() && er.ErrorFormatIndex < 0)
- continue;
-
- if (s.IsEmpty())
- {
- s += name;
- s.Add_LF();
- }
-
- if (level != 0)
- {
- AddNewLineString(s, arc.Path);
- }
-
- ErrorInfo_Print(s, er);
-
- if (er.ErrorFormatIndex >= 0)
- {
- AddNewLineString(s, GetNameOfProperty(kpidWarning, L"Warning"));
- if (arc.FormatIndex == er.ErrorFormatIndex)
- {
- AddNewLineString(s, LangString(IDS_IS_OPEN_WITH_OFFSET));
- }
- else
- {
- AddNewLineString(s, MyFormatNew(IDS_CANT_OPEN_AS_TYPE, GetBracedType(codecs->GetFormatNamePtr(er.ErrorFormatIndex))));
- AddNewLineString(s, MyFormatNew(IDS_IS_OPEN_AS_TYPE, GetBracedType(codecs->GetFormatNamePtr(arc.FormatIndex))));
- }
- }
- }
-
- if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0 || result != S_OK)
- {
- s += name;
- s.Add_LF();
- if (!arcLink.Arcs.IsEmpty())
- AddNewLineString(s, arcLink.NonOpen_ArcPath);
-
- if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0 || result == S_FALSE)
- {
- UINT id = IDS_CANT_OPEN_ARCHIVE;
- UString param;
- if (arcLink.PasswordWasAsked)
- id = IDS_CANT_OPEN_ENCRYPTED_ARCHIVE;
- else if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
- {
- id = IDS_CANT_OPEN_AS_TYPE;
- param = GetBracedType(codecs->GetFormatNamePtr(arcLink.NonOpen_ErrorInfo.ErrorFormatIndex));
- }
- UString s2 = MyFormatNew(id, param);
- s2.Replace(L" ''", L"");
- s2.Replace(L"''", L"");
- s += s2;
- }
- else
- s += HResultToMessage(result);
-
- s.Add_LF();
- ErrorInfo_Print(s, arcLink.NonOpen_ErrorInfo);
- }
-
- if (!s.IsEmpty() && s.Back() == '\n')
- s.DeleteBack();
-}
-
-HRESULT CExtractCallbackImp::OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result)
-{
- _currentArchivePath = name;
- _needWriteArchivePath = true;
-
- UString s;
- OpenResult_GUI(s, codecs, arcLink, name, result);
- if (!s.IsEmpty())
- {
- NumArchiveErrors++;
- AddError_Message(s);
- _needWriteArchivePath = false;
- }
-
- return S_OK;
-}
-
-HRESULT CExtractCallbackImp::ThereAreNoFiles()
-{
- return S_OK;
-}
-
-void CExtractCallbackImp::Add_ArchiveName_Error()
-{
- if (_needWriteArchivePath)
- {
- if (!_currentArchivePath.IsEmpty())
- AddError_Message(_currentArchivePath);
- _needWriteArchivePath = false;
- }
-}
-
-HRESULT CExtractCallbackImp::ExtractResult(HRESULT result)
-{
- if (result == S_OK)
- return result;
- NumArchiveErrors++;
- if (result == E_ABORT || result == ERROR_DISK_FULL)
- return result;
-
- Add_ArchiveName_Error();
- if (!_currentFilePath.IsEmpty())
- MessageError(_currentFilePath);
- MessageError(NError::MyFormatMessage(result));
- return S_OK;
-}
-
-#ifndef _NO_CRYPTO
-
-HRESULT CExtractCallbackImp::SetPassword(const UString &password)
-{
- PasswordIsDefined = true;
- Password = password;
- return S_OK;
-}
-
-STDMETHODIMP CExtractCallbackImp::CryptoGetTextPassword(BSTR *password)
-{
- PasswordWasAsked = true;
- if (!PasswordIsDefined)
- {
- CPasswordDialog dialog;
- #ifndef _SFX
- bool showPassword = NExtract::Read_ShowPassword();
- dialog.ShowPassword = showPassword;
- #endif
- ProgressDialog->WaitCreating();
- if (dialog.Create(*ProgressDialog) != IDOK)
- return E_ABORT;
- Password = dialog.Password;
- PasswordIsDefined = true;
- #ifndef _SFX
- if (dialog.ShowPassword != showPassword)
- NExtract::Save_ShowPassword(dialog.ShowPassword);
- #endif
- }
- return StringToBstr(Password, password);
-}
-
-#endif
-
-#ifndef _SFX
-
-STDMETHODIMP CExtractCallbackImp::AskWrite(
- const wchar_t *srcPath, Int32 srcIsFolder,
- const FILETIME *srcTime, const UInt64 *srcSize,
- const wchar_t *destPath,
- BSTR *destPathResult,
- Int32 *writeAnswer)
-{
- UString destPathResultTemp = destPath;
-
- // RINOK(StringToBstr(destPath, destPathResult));
-
- *destPathResult = 0;
- *writeAnswer = BoolToInt(false);
-
- FString destPathSys = us2fs(destPath);
- bool srcIsFolderSpec = IntToBool(srcIsFolder);
- CFileInfo destFileInfo;
-
- if (destFileInfo.Find(destPathSys))
- {
- if (srcIsFolderSpec)
- {
- if (!destFileInfo.IsDir())
- {
- RINOK(MessageError("can not replace file with folder with same name", destPathSys));
- return E_ABORT;
- }
- *writeAnswer = BoolToInt(false);
- return S_OK;
- }
-
- if (destFileInfo.IsDir())
- {
- RINOK(MessageError("can not replace folder with file with same name", destPathSys));
- *writeAnswer = BoolToInt(false);
- return S_OK;
- }
-
- switch (OverwriteMode)
- {
- case NExtract::NOverwriteMode::kSkip:
- return S_OK;
- case NExtract::NOverwriteMode::kAsk:
- {
- Int32 overwriteResult;
- UString destPathSpec = destPath;
- int slashPos = destPathSpec.ReverseFind_PathSepar();
- destPathSpec.DeleteFrom(slashPos + 1);
- destPathSpec += fs2us(destFileInfo.Name);
-
- RINOK(AskOverwrite(
- destPathSpec,
- &destFileInfo.MTime, &destFileInfo.Size,
- srcPath,
- srcTime, srcSize,
- &overwriteResult));
-
- switch (overwriteResult)
- {
- case NOverwriteAnswer::kCancel: return E_ABORT;
- case NOverwriteAnswer::kNo: return S_OK;
- case NOverwriteAnswer::kNoToAll: OverwriteMode = NExtract::NOverwriteMode::kSkip; return S_OK;
- case NOverwriteAnswer::kYes: break;
- case NOverwriteAnswer::kYesToAll: OverwriteMode = NExtract::NOverwriteMode::kOverwrite; break;
- case NOverwriteAnswer::kAutoRename: OverwriteMode = NExtract::NOverwriteMode::kRename; break;
- default:
- return E_FAIL;
- }
- }
- }
-
- if (OverwriteMode == NExtract::NOverwriteMode::kRename)
- {
- if (!AutoRenamePath(destPathSys))
- {
- RINOK(MessageError("can not create name for file", destPathSys));
- return E_ABORT;
- }
- destPathResultTemp = fs2us(destPathSys);
- }
- else
- {
- if (NFind::DoesFileExist(destPathSys))
- if (!NDir::DeleteFileAlways(destPathSys))
- if (GetLastError() != ERROR_FILE_NOT_FOUND)
- {
- RINOK(MessageError("can not delete output file", destPathSys));
- return E_ABORT;
- }
- }
- }
- *writeAnswer = BoolToInt(true);
- return StringToBstr(destPathResultTemp, destPathResult);
-}
-
-
-STDMETHODIMP CExtractCallbackImp::UseExtractToStream(Int32 *res)
-{
- *res = BoolToInt(StreamMode);
- return S_OK;
-}
-
-static HRESULT GetTime(IGetProp *getProp, PROPID propID, FILETIME &ft, bool &ftDefined)
-{
- ftDefined = false;
- NCOM::CPropVariant prop;
- RINOK(getProp->GetProp(propID, &prop));
- if (prop.vt == VT_FILETIME)
- {
- ft = prop.filetime;
- ftDefined = (ft.dwHighDateTime != 0 || ft.dwLowDateTime != 0);
- }
- else if (prop.vt != VT_EMPTY)
- return E_FAIL;
- return S_OK;
-}
-
-
-static HRESULT GetItemBoolProp(IGetProp *getProp, PROPID propID, bool &result)
-{
- NCOM::CPropVariant prop;
- result = false;
- RINOK(getProp->GetProp(propID, &prop));
- if (prop.vt == VT_BOOL)
- result = VARIANT_BOOLToBool(prop.boolVal);
- else if (prop.vt != VT_EMPTY)
- return E_FAIL;
- return S_OK;
-}
-
-
-STDMETHODIMP CExtractCallbackImp::GetStream7(const wchar_t *name,
- Int32 isDir,
- ISequentialOutStream **outStream, Int32 askExtractMode,
- IGetProp *getProp)
-{
- COM_TRY_BEGIN
- *outStream = 0;
- _newVirtFileWasAdded = false;
- _hashStreamWasUsed = false;
- _needUpdateStat = false;
-
- if (_hashStream)
- _hashStreamSpec->ReleaseStream();
-
- GetItemBoolProp(getProp, kpidIsAltStream, _isAltStream);
-
- if (!ProcessAltStreams && _isAltStream)
- return S_OK;
-
- _filePath = name;
- _isFolder = IntToBool(isDir);
- _curSize = 0;
- _curSizeDefined = false;
-
- UInt64 size = 0;
- bool sizeDefined;
- {
- NCOM::CPropVariant prop;
- RINOK(getProp->GetProp(kpidSize, &prop));
- sizeDefined = ConvertPropVariantToUInt64(prop, size);
- }
-
- if (sizeDefined)
- {
- _curSize = size;
- _curSizeDefined = true;
- }
-
- if (askExtractMode != NArchive::NExtract::NAskMode::kExtract &&
- askExtractMode != NArchive::NExtract::NAskMode::kTest)
- return S_OK;
-
- _needUpdateStat = true;
-
- CMyComPtr<ISequentialOutStream> outStreamLoc;
-
- if (VirtFileSystem && askExtractMode == NArchive::NExtract::NAskMode::kExtract)
- {
- CVirtFile &file = VirtFileSystemSpec->AddNewFile();
- _newVirtFileWasAdded = true;
- file.Name = name;
- file.IsDir = IntToBool(isDir);
- file.IsAltStream = _isAltStream;
- file.Size = 0;
-
- RINOK(GetTime(getProp, kpidCTime, file.CTime, file.CTimeDefined));
- RINOK(GetTime(getProp, kpidATime, file.ATime, file.ATimeDefined));
- RINOK(GetTime(getProp, kpidMTime, file.MTime, file.MTimeDefined));
-
- NCOM::CPropVariant prop;
- RINOK(getProp->GetProp(kpidAttrib, &prop));
- if (prop.vt == VT_UI4)
- {
- file.Attrib = prop.ulVal;
- file.AttribDefined = true;
- }
- // else if (isDir) file.Attrib = FILE_ATTRIBUTE_DIRECTORY;
-
- file.ExpectedSize = 0;
- if (sizeDefined)
- file.ExpectedSize = size;
- outStreamLoc = VirtFileSystem;
- }
-
- if (_hashStream)
- {
- {
- _hashStreamSpec->SetStream(outStreamLoc);
- outStreamLoc = _hashStream;
- _hashStreamSpec->Init(true);
- _hashStreamWasUsed = true;
- }
- }
-
- if (outStreamLoc)
- *outStream = outStreamLoc.Detach();
- return S_OK;
- COM_TRY_END
-}
-
-STDMETHODIMP CExtractCallbackImp::PrepareOperation7(Int32 askExtractMode)
-{
- COM_TRY_BEGIN
- _needUpdateStat = (
- askExtractMode == NArchive::NExtract::NAskMode::kExtract ||
- askExtractMode == NArchive::NExtract::NAskMode::kTest);
-
- /*
- _extractMode = false;
- switch (askExtractMode)
- {
- case NArchive::NExtract::NAskMode::kExtract:
- if (_testMode)
- askExtractMode = NArchive::NExtract::NAskMode::kTest;
- else
- _extractMode = true;
- break;
- };
- */
- return SetCurrentFilePath2(_filePath);
- COM_TRY_END
-}
-
-STDMETHODIMP CExtractCallbackImp::SetOperationResult7(Int32 opRes, Int32 encrypted)
-{
- COM_TRY_BEGIN
- if (VirtFileSystem && _newVirtFileWasAdded)
- {
- // FIXME: probably we must request file size from VirtFileSystem
- // _curSize = VirtFileSystem->GetLastFileSize()
- // _curSizeDefined = true;
- RINOK(VirtFileSystemSpec->CloseMemFile());
- }
- if (_hashStream && _hashStreamWasUsed)
- {
- _hashStreamSpec->_hash->Final(_isFolder, _isAltStream, _filePath);
- _curSize = _hashStreamSpec->GetSize();
- _curSizeDefined = true;
- _hashStreamSpec->ReleaseStream();
- _hashStreamWasUsed = false;
- }
- else if (_hashCalc && _needUpdateStat)
- {
- _hashCalc->SetSize(_curSize);
- _hashCalc->Final(_isFolder, _isAltStream, _filePath);
- }
- return SetOperationResult(opRes, encrypted);
- COM_TRY_END
-}
-
-
-static const size_t k_SizeT_MAX = (size_t)((size_t)0 - 1);
-
-static const UInt32 kBlockSize = ((UInt32)1 << 31);
-
-STDMETHODIMP CVirtFileSystem::Write(const void *data, UInt32 size, UInt32 *processedSize)
-{
- if (processedSize)
- *processedSize = 0;
- if (size == 0)
- return S_OK;
- if (!_fileMode)
- {
- CVirtFile &file = Files.Back();
- size_t rem = file.Data.Size() - (size_t)file.Size;
- bool useMem = true;
- if (rem < size)
- {
- UInt64 b = 0;
- if (file.Data.Size() == 0)
- b = file.ExpectedSize;
- UInt64 a = file.Size + size;
- if (b < a)
- b = a;
- a = (UInt64)file.Data.Size() * 2;
- if (b < a)
- b = a;
- useMem = false;
- if (b <= k_SizeT_MAX && b <= MaxTotalAllocSize)
- useMem = file.Data.ReAlloc_KeepData((size_t)b, (size_t)file.Size);
- }
- if (useMem)
- {
- memcpy(file.Data + file.Size, data, size);
- file.Size += size;
- if (processedSize)
- *processedSize = (UInt32)size;
- return S_OK;
- }
- _fileMode = true;
- }
- RINOK(FlushToDisk(false));
- return _outFileStream->Write(data, size, processedSize);
-}
-
-HRESULT CVirtFileSystem::FlushToDisk(bool closeLast)
-{
- if (!_outFileStream)
- {
- _outFileStreamSpec = new COutFileStream;
- _outFileStream = _outFileStreamSpec;
- }
- while (_numFlushed < Files.Size())
- {
- const CVirtFile &file = Files[_numFlushed];
- const FString path = DirPrefix + us2fs(Get_Correct_FsFile_Name(file.Name));
- if (!_fileIsOpen)
- {
- if (!_outFileStreamSpec->Create(path, false))
- {
- _outFileStream.Release();
- return E_FAIL;
- // MessageBoxMyError(UString("Can't create file ") + fs2us(tempFilePath));
- }
- _fileIsOpen = true;
- RINOK(WriteStream(_outFileStream, file.Data, (size_t)file.Size));
- }
- if (_numFlushed == Files.Size() - 1 && !closeLast)
- break;
- if (file.CTimeDefined ||
- file.ATimeDefined ||
- file.MTimeDefined)
- _outFileStreamSpec->SetTime(
- file.CTimeDefined ? &file.CTime : NULL,
- file.ATimeDefined ? &file.ATime : NULL,
- file.MTimeDefined ? &file.MTime : NULL);
- _outFileStreamSpec->Close();
- _numFlushed++;
- _fileIsOpen = false;
- if (file.AttribDefined)
- NDir::SetFileAttrib_PosixHighDetect(path, file.Attrib);
- }
- return S_OK;
-}
-
-#endif
+// ExtractCallback.cpp
+
+#include "StdAfx.h"
+
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/Lang.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/PropVariantConv.h"
+
+#include "../../Common/FilePathAutoRename.h"
+#include "../../Common/StreamUtils.h"
+#include "../Common/ExtractingFilePath.h"
+
+#ifndef Z7_SFX
+#include "../Common/ZipRegistry.h"
+#endif
+
+#include "../GUI/ExtractRes.h"
+#include "resourceGui.h"
+
+#include "ExtractCallback.h"
+#include "FormatUtils.h"
+#include "LangUtils.h"
+#include "OverwriteDialog.h"
+#ifndef Z7_NO_CRYPTO
+#include "PasswordDialog.h"
+#endif
+#include "PropertyName.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NFind;
+
+CExtractCallbackImp::~CExtractCallbackImp() {}
+
+void CExtractCallbackImp::Init()
+{
+ _lang_Extracting = LangString(IDS_PROGRESS_EXTRACTING);
+ _lang_Testing = LangString(IDS_PROGRESS_TESTING);
+ _lang_Skipping = LangString(IDS_PROGRESS_SKIPPING);
+ _lang_Reading = "Reading";
+
+ NumArchiveErrors = 0;
+ ThereAreMessageErrors = false;
+ #ifndef Z7_SFX
+ NumFolders = NumFiles = 0;
+ NeedAddFile = false;
+ #endif
+}
+
+void CExtractCallbackImp::AddError_Message(LPCWSTR s)
+{
+ ThereAreMessageErrors = true;
+ ProgressDialog->Sync.AddError_Message(s);
+}
+
+#ifndef Z7_SFX
+
+Z7_COM7F_IMF(CExtractCallbackImp::SetNumFiles(UInt64 numFiles))
+{
+ #ifdef Z7_SFX
+ UNUSED_VAR(numFiles)
+ #else
+ ProgressDialog->Sync.Set_NumFilesTotal(numFiles);
+ #endif
+ return S_OK;
+}
+
+#endif
+
+Z7_COM7F_IMF(CExtractCallbackImp::SetTotal(UInt64 total))
+{
+ ProgressDialog->Sync.Set_NumBytesTotal(total);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CExtractCallbackImp::SetCompleted(const UInt64 *value))
+{
+ return ProgressDialog->Sync.Set_NumBytesCur(value);
+}
+
+HRESULT CExtractCallbackImp::Open_CheckBreak()
+{
+ return ProgressDialog->Sync.CheckStop();
+}
+
+HRESULT CExtractCallbackImp::Open_SetTotal(const UInt64 *files, const UInt64 *bytes)
+{
+ HRESULT res = S_OK;
+ if (!MultiArcMode)
+ {
+ if (files)
+ {
+ _totalFilesDefined = true;
+ // res = ProgressDialog->Sync.Set_NumFilesTotal(*files);
+ }
+ else
+ _totalFilesDefined = false;
+
+ if (bytes)
+ {
+ _totalBytesDefined = true;
+ ProgressDialog->Sync.Set_NumBytesTotal(*bytes);
+ }
+ else
+ _totalBytesDefined = false;
+ }
+
+ return res;
+}
+
+HRESULT CExtractCallbackImp::Open_SetCompleted(const UInt64 *files, const UInt64 *bytes)
+{
+ if (!MultiArcMode)
+ {
+ if (files)
+ {
+ ProgressDialog->Sync.Set_NumFilesCur(*files);
+ }
+
+ if (bytes)
+ {
+ }
+ }
+
+ return ProgressDialog->Sync.CheckStop();
+}
+
+HRESULT CExtractCallbackImp::Open_Finished()
+{
+ return ProgressDialog->Sync.CheckStop();
+}
+
+#ifndef Z7_NO_CRYPTO
+
+HRESULT CExtractCallbackImp::Open_CryptoGetTextPassword(BSTR *password)
+{
+ return CryptoGetTextPassword(password);
+}
+
+/*
+HRESULT CExtractCallbackImp::Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password)
+{
+ passwordIsDefined = PasswordIsDefined;
+ password = Password;
+ return S_OK;
+}
+
+bool CExtractCallbackImp::Open_WasPasswordAsked()
+{
+ return PasswordWasAsked;
+}
+
+void CExtractCallbackImp::Open_Clear_PasswordWasAsked_Flag()
+{
+ PasswordWasAsked = false;
+}
+*/
+
+#endif
+
+
+#ifndef Z7_SFX
+Z7_COM7F_IMF(CExtractCallbackImp::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
+{
+ ProgressDialog->Sync.Set_Ratio(inSize, outSize);
+ return S_OK;
+}
+#endif
+
+/*
+Z7_COM7F_IMF(CExtractCallbackImp::SetTotalFiles(UInt64 total)
+{
+ ProgressDialog->Sync.SetNumFilesTotal(total);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CExtractCallbackImp::SetCompletedFiles(const UInt64 *value)
+{
+ if (value != NULL)
+ ProgressDialog->Sync.SetNumFilesCur(*value);
+ return S_OK;
+}
+*/
+
+Z7_COM7F_IMF(CExtractCallbackImp::AskOverwrite(
+ const wchar_t *existName, const FILETIME *existTime, const UInt64 *existSize,
+ const wchar_t *newName, const FILETIME *newTime, const UInt64 *newSize,
+ Int32 *answer))
+{
+ COverwriteDialog dialog;
+
+ dialog.OldFileInfo.SetTime(existTime);
+ dialog.OldFileInfo.SetSize(existSize);
+ dialog.OldFileInfo.Name = existName;
+
+ dialog.NewFileInfo.SetTime(newTime);
+ dialog.NewFileInfo.SetSize(newSize);
+ dialog.NewFileInfo.Name = newName;
+
+ ProgressDialog->WaitCreating();
+ INT_PTR writeAnswer = dialog.Create(*ProgressDialog);
+
+ switch (writeAnswer)
+ {
+ case IDCANCEL: *answer = NOverwriteAnswer::kCancel; return E_ABORT;
+ case IDYES: *answer = NOverwriteAnswer::kYes; break;
+ case IDNO: *answer = NOverwriteAnswer::kNo; break;
+ case IDB_YES_TO_ALL: *answer = NOverwriteAnswer::kYesToAll; break;
+ case IDB_NO_TO_ALL: *answer = NOverwriteAnswer::kNoToAll; break;
+ case IDB_AUTO_RENAME: *answer = NOverwriteAnswer::kAutoRename; break;
+ default: return E_FAIL;
+ }
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CExtractCallbackImp::PrepareOperation(const wchar_t *name, Int32 isFolder, Int32 askExtractMode, const UInt64 * /* position */))
+{
+ _isFolder = IntToBool(isFolder);
+ _currentFilePath = name;
+
+ const UString *msg = &_lang_Empty;
+ switch (askExtractMode)
+ {
+ case NArchive::NExtract::NAskMode::kExtract: msg = &_lang_Extracting; break;
+ case NArchive::NExtract::NAskMode::kTest: msg = &_lang_Testing; break;
+ case NArchive::NExtract::NAskMode::kSkip: msg = &_lang_Skipping; break;
+ case NArchive::NExtract::NAskMode::kReadExternal: msg = &_lang_Reading; break;
+ // default: s = "Unknown operation";
+ }
+
+ return ProgressDialog->Sync.Set_Status2(*msg, name, IntToBool(isFolder));
+}
+
+Z7_COM7F_IMF(CExtractCallbackImp::MessageError(const wchar_t *s))
+{
+ AddError_Message(s);
+ return S_OK;
+}
+
+HRESULT CExtractCallbackImp::MessageError(const char *message, const FString &path)
+{
+ ThereAreMessageErrors = true;
+ ProgressDialog->Sync.AddError_Message_Name(GetUnicodeString(message), fs2us(path));
+ return S_OK;
+}
+
+#ifndef Z7_SFX
+
+Z7_COM7F_IMF(CExtractCallbackImp::ShowMessage(const wchar_t *s))
+{
+ AddError_Message(s);
+ return S_OK;
+}
+
+#endif
+
+void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s);
+void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s)
+{
+ s.Empty();
+
+ if (opRes == NArchive::NExtract::NOperationResult::kOK)
+ return;
+
+ #ifndef Z7_SFX
+ UINT messageID = 0;
+ #endif
+ UINT id = 0;
+
+ switch (opRes)
+ {
+ case NArchive::NExtract::NOperationResult::kUnsupportedMethod:
+ #ifndef Z7_SFX
+ messageID = IDS_EXTRACT_MESSAGE_UNSUPPORTED_METHOD;
+ #endif
+ id = IDS_EXTRACT_MSG_UNSUPPORTED_METHOD;
+ break;
+ case NArchive::NExtract::NOperationResult::kDataError:
+ #ifndef Z7_SFX
+ messageID = encrypted ?
+ IDS_EXTRACT_MESSAGE_DATA_ERROR_ENCRYPTED:
+ IDS_EXTRACT_MESSAGE_DATA_ERROR;
+ #endif
+ id = IDS_EXTRACT_MSG_DATA_ERROR;
+ break;
+ case NArchive::NExtract::NOperationResult::kCRCError:
+ #ifndef Z7_SFX
+ messageID = encrypted ?
+ IDS_EXTRACT_MESSAGE_CRC_ERROR_ENCRYPTED:
+ IDS_EXTRACT_MESSAGE_CRC_ERROR;
+ #endif
+ id = IDS_EXTRACT_MSG_CRC_ERROR;
+ break;
+ case NArchive::NExtract::NOperationResult::kUnavailable:
+ id = IDS_EXTRACT_MSG_UNAVAILABLE_DATA;
+ break;
+ case NArchive::NExtract::NOperationResult::kUnexpectedEnd:
+ id = IDS_EXTRACT_MSG_UEXPECTED_END;
+ break;
+ case NArchive::NExtract::NOperationResult::kDataAfterEnd:
+ id = IDS_EXTRACT_MSG_DATA_AFTER_END;
+ break;
+ case NArchive::NExtract::NOperationResult::kIsNotArc:
+ id = IDS_EXTRACT_MSG_IS_NOT_ARC;
+ break;
+ case NArchive::NExtract::NOperationResult::kHeadersError:
+ id = IDS_EXTRACT_MSG_HEADERS_ERROR;
+ break;
+ case NArchive::NExtract::NOperationResult::kWrongPassword:
+ id = IDS_EXTRACT_MSG_WRONG_PSW_CLAIM;
+ break;
+ /*
+ default:
+ messageID = IDS_EXTRACT_MESSAGE_UNKNOWN_ERROR;
+ break;
+ */
+ }
+
+ UString msg;
+
+ #ifndef Z7_SFX
+ UString msgOld;
+ #ifdef Z7_LANG
+ if (id != 0)
+ LangString_OnlyFromLangFile(id, msg);
+ if (messageID != 0 && msg.IsEmpty())
+ LangString_OnlyFromLangFile(messageID, msgOld);
+ #endif
+ if (msg.IsEmpty() && !msgOld.IsEmpty())
+ s = MyFormatNew(msgOld, fileName);
+ else
+ #endif
+ {
+ if (msg.IsEmpty() && id != 0)
+ LangString(id, msg);
+ if (!msg.IsEmpty())
+ s += msg;
+ else
+ {
+ s += "Error #";
+ s.Add_UInt32((UInt32)opRes);
+ }
+
+ if (encrypted && opRes != NArchive::NExtract::NOperationResult::kWrongPassword)
+ {
+ // s += " : ";
+ // AddLangString(s, IDS_EXTRACT_MSG_ENCRYPTED);
+ s += " : ";
+ AddLangString(s, IDS_EXTRACT_MSG_WRONG_PSW_GUESS);
+ }
+ s += " : ";
+ s += fileName;
+ }
+}
+
+Z7_COM7F_IMF(CExtractCallbackImp::SetOperationResult(Int32 opRes, Int32 encrypted))
+{
+ switch (opRes)
+ {
+ case NArchive::NExtract::NOperationResult::kOK:
+ break;
+ default:
+ {
+ UString s;
+ SetExtractErrorMessage(opRes, encrypted, _currentFilePath, s);
+ Add_ArchiveName_Error();
+ AddError_Message(s);
+ }
+ }
+
+ #ifndef Z7_SFX
+ if (_isFolder)
+ NumFolders++;
+ else
+ NumFiles++;
+ ProgressDialog->Sync.Set_NumFilesCur(NumFiles);
+ #endif
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CExtractCallbackImp::ReportExtractResult(Int32 opRes, Int32 encrypted, const wchar_t *name))
+{
+ if (opRes != NArchive::NExtract::NOperationResult::kOK)
+ {
+ UString s;
+ SetExtractErrorMessage(opRes, encrypted, name, s);
+ Add_ArchiveName_Error();
+ AddError_Message(s);
+ }
+ return S_OK;
+}
+
+////////////////////////////////////////
+// IExtractCallbackUI
+
+HRESULT CExtractCallbackImp::BeforeOpen(const wchar_t *name, bool /* testMode */)
+{
+ #ifndef Z7_SFX
+ RINOK(ProgressDialog->Sync.CheckStop())
+ ProgressDialog->Sync.Set_TitleFileName(name);
+ #endif
+ _currentArchivePath = name;
+ return S_OK;
+}
+
+HRESULT CExtractCallbackImp::SetCurrentFilePath2(const wchar_t *path)
+{
+ _currentFilePath = path;
+ #ifndef Z7_SFX
+ ProgressDialog->Sync.Set_FilePath(path);
+ #endif
+ return S_OK;
+}
+
+#ifndef Z7_SFX
+
+Z7_COM7F_IMF(CExtractCallbackImp::SetCurrentFilePath(const wchar_t *path))
+{
+ #ifndef Z7_SFX
+ if (NeedAddFile)
+ NumFiles++;
+ NeedAddFile = true;
+ ProgressDialog->Sync.Set_NumFilesCur(NumFiles);
+ #endif
+ return SetCurrentFilePath2(path);
+}
+
+#endif
+
+UString HResultToMessage(HRESULT errorCode);
+
+static const UInt32 k_ErrorFlagsIds[] =
+{
+ IDS_EXTRACT_MSG_IS_NOT_ARC,
+ IDS_EXTRACT_MSG_HEADERS_ERROR,
+ IDS_EXTRACT_MSG_HEADERS_ERROR,
+ IDS_OPEN_MSG_UNAVAILABLE_START,
+ IDS_OPEN_MSG_UNCONFIRMED_START,
+ IDS_EXTRACT_MSG_UEXPECTED_END,
+ IDS_EXTRACT_MSG_DATA_AFTER_END,
+ IDS_EXTRACT_MSG_UNSUPPORTED_METHOD,
+ IDS_OPEN_MSG_UNSUPPORTED_FEATURE,
+ IDS_EXTRACT_MSG_DATA_ERROR,
+ IDS_EXTRACT_MSG_CRC_ERROR
+};
+
+static void AddNewLineString(UString &s, const UString &m)
+{
+ s += m;
+ s.Add_LF();
+}
+
+UString GetOpenArcErrorMessage(UInt32 errorFlags);
+UString GetOpenArcErrorMessage(UInt32 errorFlags)
+{
+ UString s;
+
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_ErrorFlagsIds); i++)
+ {
+ UInt32 f = ((UInt32)1 << i);
+ if ((errorFlags & f) == 0)
+ continue;
+ UInt32 id = k_ErrorFlagsIds[i];
+ UString m = LangString(id);
+ if (m.IsEmpty())
+ continue;
+ if (f == kpv_ErrorFlags_EncryptedHeadersError)
+ {
+ m += " : ";
+ AddLangString(m, IDS_EXTRACT_MSG_WRONG_PSW_GUESS);
+ }
+ if (!s.IsEmpty())
+ s.Add_LF();
+ s += m;
+ errorFlags &= ~f;
+ }
+
+ if (errorFlags != 0)
+ {
+ char sz[16];
+ sz[0] = '0';
+ sz[1] = 'x';
+ ConvertUInt32ToHex(errorFlags, sz + 2);
+ if (!s.IsEmpty())
+ s.Add_LF();
+ s += sz;
+ }
+
+ return s;
+}
+
+static void ErrorInfo_Print(UString &s, const CArcErrorInfo &er)
+{
+ UInt32 errorFlags = er.GetErrorFlags();
+ UInt32 warningFlags = er.GetWarningFlags();
+
+ if (errorFlags != 0)
+ AddNewLineString(s, GetOpenArcErrorMessage(errorFlags));
+
+ if (!er.ErrorMessage.IsEmpty())
+ AddNewLineString(s, er.ErrorMessage);
+
+ if (warningFlags != 0)
+ {
+ s += GetNameOfProperty(kpidWarningFlags, L"Warnings");
+ s += ":";
+ s.Add_LF();
+ AddNewLineString(s, GetOpenArcErrorMessage(warningFlags));
+ }
+
+ if (!er.WarningMessage.IsEmpty())
+ {
+ s += GetNameOfProperty(kpidWarning, L"Warning");
+ s += ": ";
+ s += er.WarningMessage;
+ s.Add_LF();
+ }
+}
+
+static UString GetBracedType(const wchar_t *type)
+{
+ UString s ('[');
+ s += type;
+ s += ']';
+ return s;
+}
+
+void OpenResult_GUI(UString &s, const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result);
+void OpenResult_GUI(UString &s, const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result)
+{
+ FOR_VECTOR (level, arcLink.Arcs)
+ {
+ const CArc &arc = arcLink.Arcs[level];
+ const CArcErrorInfo &er = arc.ErrorInfo;
+
+ if (!er.IsThereErrorOrWarning() && er.ErrorFormatIndex < 0)
+ continue;
+
+ if (s.IsEmpty())
+ {
+ s += name;
+ s.Add_LF();
+ }
+
+ if (level != 0)
+ {
+ AddNewLineString(s, arc.Path);
+ }
+
+ ErrorInfo_Print(s, er);
+
+ if (er.ErrorFormatIndex >= 0)
+ {
+ AddNewLineString(s, GetNameOfProperty(kpidWarning, L"Warning"));
+ if (arc.FormatIndex == er.ErrorFormatIndex)
+ {
+ AddNewLineString(s, LangString(IDS_IS_OPEN_WITH_OFFSET));
+ }
+ else
+ {
+ AddNewLineString(s, MyFormatNew(IDS_CANT_OPEN_AS_TYPE, GetBracedType(codecs->GetFormatNamePtr(er.ErrorFormatIndex))));
+ AddNewLineString(s, MyFormatNew(IDS_IS_OPEN_AS_TYPE, GetBracedType(codecs->GetFormatNamePtr(arc.FormatIndex))));
+ }
+ }
+ }
+
+ if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0 || result != S_OK)
+ {
+ s += name;
+ s.Add_LF();
+ if (!arcLink.Arcs.IsEmpty())
+ AddNewLineString(s, arcLink.NonOpen_ArcPath);
+
+ if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0 || result == S_FALSE)
+ {
+ UINT id = IDS_CANT_OPEN_ARCHIVE;
+ UString param;
+ if (arcLink.PasswordWasAsked)
+ id = IDS_CANT_OPEN_ENCRYPTED_ARCHIVE;
+ else if (arcLink.NonOpen_ErrorInfo.ErrorFormatIndex >= 0)
+ {
+ id = IDS_CANT_OPEN_AS_TYPE;
+ param = GetBracedType(codecs->GetFormatNamePtr(arcLink.NonOpen_ErrorInfo.ErrorFormatIndex));
+ }
+ UString s2 = MyFormatNew(id, param);
+ s2.Replace(L" ''", L"");
+ s2.Replace(L"''", L"");
+ s += s2;
+ }
+ else
+ s += HResultToMessage(result);
+
+ s.Add_LF();
+ ErrorInfo_Print(s, arcLink.NonOpen_ErrorInfo);
+ }
+
+ if (!s.IsEmpty() && s.Back() == '\n')
+ s.DeleteBack();
+}
+
+HRESULT CExtractCallbackImp::OpenResult(const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result)
+{
+ _currentArchivePath = name;
+ _needWriteArchivePath = true;
+
+ UString s;
+ OpenResult_GUI(s, codecs, arcLink, name, result);
+ if (!s.IsEmpty())
+ {
+ NumArchiveErrors++;
+ AddError_Message(s);
+ _needWriteArchivePath = false;
+ }
+
+ return S_OK;
+}
+
+HRESULT CExtractCallbackImp::ThereAreNoFiles()
+{
+ return S_OK;
+}
+
+void CExtractCallbackImp::Add_ArchiveName_Error()
+{
+ if (_needWriteArchivePath)
+ {
+ if (!_currentArchivePath.IsEmpty())
+ AddError_Message(_currentArchivePath);
+ _needWriteArchivePath = false;
+ }
+}
+
+HRESULT CExtractCallbackImp::ExtractResult(HRESULT result)
+{
+ if (result == S_OK)
+ return result;
+ NumArchiveErrors++;
+ if (result == E_ABORT
+ || result == HRESULT_FROM_WIN32(ERROR_DISK_FULL)
+ )
+ return result;
+
+ Add_ArchiveName_Error();
+ if (!_currentFilePath.IsEmpty())
+ MessageError(_currentFilePath);
+ MessageError(NError::MyFormatMessage(result));
+ return S_OK;
+}
+
+#ifndef Z7_NO_CRYPTO
+
+HRESULT CExtractCallbackImp::SetPassword(const UString &password)
+{
+ PasswordIsDefined = true;
+ Password = password;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CExtractCallbackImp::CryptoGetTextPassword(BSTR *password))
+{
+ PasswordWasAsked = true;
+ if (!PasswordIsDefined)
+ {
+ CPasswordDialog dialog;
+ #ifndef Z7_SFX
+ const bool showPassword = NExtract::Read_ShowPassword();
+ dialog.ShowPassword = showPassword;
+ #endif
+ ProgressDialog->WaitCreating();
+ if (dialog.Create(*ProgressDialog) != IDOK)
+ return E_ABORT;
+ Password = dialog.Password;
+ PasswordIsDefined = true;
+ #ifndef Z7_SFX
+ if (dialog.ShowPassword != showPassword)
+ NExtract::Save_ShowPassword(dialog.ShowPassword);
+ #endif
+ }
+ return StringToBstr(Password, password);
+}
+
+#endif
+
+#ifndef Z7_SFX
+
+Z7_COM7F_IMF(CExtractCallbackImp::AskWrite(
+ const wchar_t *srcPath, Int32 srcIsFolder,
+ const FILETIME *srcTime, const UInt64 *srcSize,
+ const wchar_t *destPath,
+ BSTR *destPathResult,
+ Int32 *writeAnswer))
+{
+ UString destPathResultTemp = destPath;
+
+ // RINOK(StringToBstr(destPath, destPathResult));
+
+ *destPathResult = NULL;
+ *writeAnswer = BoolToInt(false);
+
+ FString destPathSys = us2fs(destPath);
+ const bool srcIsFolderSpec = IntToBool(srcIsFolder);
+ CFileInfo destFileInfo;
+
+ if (destFileInfo.Find(destPathSys))
+ {
+ if (srcIsFolderSpec)
+ {
+ if (!destFileInfo.IsDir())
+ {
+ RINOK(MessageError("Cannot replace file with folder with same name", destPathSys))
+ return E_ABORT;
+ }
+ *writeAnswer = BoolToInt(false);
+ return S_OK;
+ }
+
+ if (destFileInfo.IsDir())
+ {
+ RINOK(MessageError("Cannot replace folder with file with same name", destPathSys))
+ *writeAnswer = BoolToInt(false);
+ return S_OK;
+ }
+
+ switch ((int)OverwriteMode)
+ {
+ case NExtract::NOverwriteMode::kSkip:
+ return S_OK;
+ case NExtract::NOverwriteMode::kAsk:
+ {
+ Int32 overwriteResult;
+ UString destPathSpec = destPath;
+ const int slashPos = destPathSpec.ReverseFind_PathSepar();
+ destPathSpec.DeleteFrom((unsigned)(slashPos + 1));
+ destPathSpec += fs2us(destFileInfo.Name);
+
+ RINOK(AskOverwrite(
+ destPathSpec,
+ &destFileInfo.MTime, &destFileInfo.Size,
+ srcPath,
+ srcTime, srcSize,
+ &overwriteResult))
+
+ switch (overwriteResult)
+ {
+ case NOverwriteAnswer::kCancel: return E_ABORT;
+ case NOverwriteAnswer::kNo: return S_OK;
+ case NOverwriteAnswer::kNoToAll: OverwriteMode = NExtract::NOverwriteMode::kSkip; return S_OK;
+ case NOverwriteAnswer::kYes: break;
+ case NOverwriteAnswer::kYesToAll: OverwriteMode = NExtract::NOverwriteMode::kOverwrite; break;
+ case NOverwriteAnswer::kAutoRename: OverwriteMode = NExtract::NOverwriteMode::kRename; break;
+ default:
+ return E_FAIL;
+ }
+ break;
+ }
+ default:
+ break;
+ }
+
+ if (OverwriteMode == NExtract::NOverwriteMode::kRename)
+ {
+ if (!AutoRenamePath(destPathSys))
+ {
+ RINOK(MessageError("Cannot create name for file", destPathSys))
+ return E_ABORT;
+ }
+ destPathResultTemp = fs2us(destPathSys);
+ }
+ else
+ {
+ if (NFind::DoesFileExist_Raw(destPathSys))
+ if (!NDir::DeleteFileAlways(destPathSys))
+ if (GetLastError() != ERROR_FILE_NOT_FOUND)
+ {
+ RINOK(MessageError("Cannot delete output file", destPathSys))
+ return E_ABORT;
+ }
+ }
+ }
+ *writeAnswer = BoolToInt(true);
+ return StringToBstr(destPathResultTemp, destPathResult);
+}
+
+
+Z7_COM7F_IMF(CExtractCallbackImp::UseExtractToStream(Int32 *res))
+{
+ *res = BoolToInt(StreamMode);
+ return S_OK;
+}
+
+static HRESULT GetTime(IGetProp *getProp, PROPID propID, FILETIME &ft, bool &ftDefined)
+{
+ ftDefined = false;
+ NCOM::CPropVariant prop;
+ RINOK(getProp->GetProp(propID, &prop))
+ if (prop.vt == VT_FILETIME)
+ {
+ ft = prop.filetime;
+ ftDefined = (ft.dwHighDateTime != 0 || ft.dwLowDateTime != 0);
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+
+static HRESULT GetItemBoolProp(IGetProp *getProp, PROPID propID, bool &result)
+{
+ NCOM::CPropVariant prop;
+ result = false;
+ RINOK(getProp->GetProp(propID, &prop))
+ if (prop.vt == VT_BOOL)
+ result = VARIANT_BOOLToBool(prop.boolVal);
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CExtractCallbackImp::GetStream7(const wchar_t *name,
+ Int32 isDir,
+ ISequentialOutStream **outStream, Int32 askExtractMode,
+ IGetProp *getProp))
+{
+ COM_TRY_BEGIN
+ *outStream = NULL;
+ _newVirtFileWasAdded = false;
+ _hashStreamWasUsed = false;
+ _needUpdateStat = false;
+
+ if (_hashStream)
+ _hashStreamSpec->ReleaseStream();
+
+ GetItemBoolProp(getProp, kpidIsAltStream, _isAltStream);
+
+ if (!ProcessAltStreams && _isAltStream)
+ return S_OK;
+
+ _filePath = name;
+ _isFolder = IntToBool(isDir);
+ _curSize = 0;
+ _curSize_Defined = false;
+
+ UInt64 size = 0;
+ bool sizeDefined;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(getProp->GetProp(kpidSize, &prop))
+ sizeDefined = ConvertPropVariantToUInt64(prop, size);
+ }
+
+ if (sizeDefined)
+ {
+ _curSize = size;
+ _curSize_Defined = true;
+ }
+
+ if (askExtractMode != NArchive::NExtract::NAskMode::kExtract &&
+ askExtractMode != NArchive::NExtract::NAskMode::kTest)
+ return S_OK;
+
+ _needUpdateStat = true;
+
+ CMyComPtr<ISequentialOutStream> outStreamLoc;
+
+ if (VirtFileSystem && askExtractMode == NArchive::NExtract::NAskMode::kExtract)
+ {
+ CVirtFile &file = VirtFileSystemSpec->AddNewFile();
+ _newVirtFileWasAdded = true;
+ file.Name = name;
+ file.IsDir = IntToBool(isDir);
+ file.IsAltStream = _isAltStream;
+ file.Size = 0;
+
+ RINOK(GetTime(getProp, kpidCTime, file.CTime, file.CTimeDefined))
+ RINOK(GetTime(getProp, kpidATime, file.ATime, file.ATimeDefined))
+ RINOK(GetTime(getProp, kpidMTime, file.MTime, file.MTimeDefined))
+
+ NCOM::CPropVariant prop;
+ RINOK(getProp->GetProp(kpidAttrib, &prop))
+ if (prop.vt == VT_UI4)
+ {
+ file.Attrib = prop.ulVal;
+ file.AttribDefined = true;
+ }
+ // else if (isDir) file.Attrib = FILE_ATTRIBUTE_DIRECTORY;
+
+ file.ExpectedSize = 0;
+ if (sizeDefined)
+ file.ExpectedSize = size;
+ outStreamLoc = VirtFileSystem;
+ }
+
+ if (_hashStream)
+ {
+ {
+ _hashStreamSpec->SetStream(outStreamLoc);
+ outStreamLoc = _hashStream;
+ _hashStreamSpec->Init(true);
+ _hashStreamWasUsed = true;
+ }
+ }
+
+ if (outStreamLoc)
+ *outStream = outStreamLoc.Detach();
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CExtractCallbackImp::PrepareOperation7(Int32 askExtractMode))
+{
+ COM_TRY_BEGIN
+ _needUpdateStat = (
+ askExtractMode == NArchive::NExtract::NAskMode::kExtract
+ || askExtractMode == NArchive::NExtract::NAskMode::kTest
+ || askExtractMode == NArchive::NExtract::NAskMode::kReadExternal
+ );
+
+ /*
+ _extractMode = false;
+ switch (askExtractMode)
+ {
+ case NArchive::NExtract::NAskMode::kExtract:
+ if (_testMode)
+ askExtractMode = NArchive::NExtract::NAskMode::kTest;
+ else
+ _extractMode = true;
+ break;
+ };
+ */
+ return SetCurrentFilePath2(_filePath);
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CExtractCallbackImp::SetOperationResult8(Int32 opRes, Int32 encrypted, UInt64 size))
+{
+ COM_TRY_BEGIN
+ if (VirtFileSystem && _newVirtFileWasAdded)
+ {
+ // FIXME: probably we must request file size from VirtFileSystem
+ // _curSize = VirtFileSystem->GetLastFileSize()
+ // _curSize_Defined = true;
+ RINOK(VirtFileSystemSpec->CloseMemFile())
+ }
+ if (_hashStream && _hashStreamWasUsed)
+ {
+ _hashStreamSpec->_hash->Final(_isFolder, _isAltStream, _filePath);
+ _curSize = _hashStreamSpec->GetSize();
+ _curSize_Defined = true;
+ _hashStreamSpec->ReleaseStream();
+ _hashStreamWasUsed = false;
+ }
+ else if (_hashCalc && _needUpdateStat)
+ {
+ _hashCalc->SetSize(size); // (_curSize) before 21.04
+ _hashCalc->Final(_isFolder, _isAltStream, _filePath);
+ }
+ return SetOperationResult(opRes, encrypted);
+ COM_TRY_END
+}
+
+
+
+// static const UInt32 kBlockSize = ((UInt32)1 << 31);
+
+Z7_COM7F_IMF(CVirtFileSystem::Write(const void *data, UInt32 size, UInt32 *processedSize))
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (size == 0)
+ return S_OK;
+ if (!_fileMode)
+ {
+ CVirtFile &file = Files.Back();
+ size_t rem = file.Data.Size() - (size_t)file.Size;
+ bool useMem = true;
+ if (rem < size)
+ {
+ UInt64 b = 0;
+ if (file.Data.Size() == 0)
+ b = file.ExpectedSize;
+ UInt64 a = file.Size + size;
+ if (b < a)
+ b = a;
+ a = (UInt64)file.Data.Size() * 2;
+ if (b < a)
+ b = a;
+ useMem = false;
+ const size_t b_sizet = (size_t)b;
+ if (b == b_sizet && b <= MaxTotalAllocSize)
+ useMem = file.Data.ReAlloc_KeepData(b_sizet, (size_t)file.Size);
+ }
+ if (useMem)
+ {
+ memcpy(file.Data + file.Size, data, size);
+ file.Size += size;
+ if (processedSize)
+ *processedSize = (UInt32)size;
+ return S_OK;
+ }
+ _fileMode = true;
+ }
+ RINOK(FlushToDisk(false))
+ return _outFileStream->Write(data, size, processedSize);
+}
+
+HRESULT CVirtFileSystem::FlushToDisk(bool closeLast)
+{
+ if (!_outFileStream)
+ {
+ _outFileStreamSpec = new COutFileStream;
+ _outFileStream = _outFileStreamSpec;
+ }
+ while (_numFlushed < Files.Size())
+ {
+ const CVirtFile &file = Files[_numFlushed];
+ const FString path = DirPrefix + us2fs(Get_Correct_FsFile_Name(file.Name));
+ if (!_fileIsOpen)
+ {
+ if (!_outFileStreamSpec->Create(path, false))
+ {
+ _outFileStream.Release();
+ return E_FAIL;
+ // MessageBoxMyError(UString("Can't create file ") + fs2us(tempFilePath));
+ }
+ _fileIsOpen = true;
+ RINOK(WriteStream(_outFileStream, file.Data, (size_t)file.Size))
+ }
+ if (_numFlushed == Files.Size() - 1 && !closeLast)
+ break;
+ if (file.CTimeDefined ||
+ file.ATimeDefined ||
+ file.MTimeDefined)
+ _outFileStreamSpec->SetTime(
+ file.CTimeDefined ? &file.CTime : NULL,
+ file.ATimeDefined ? &file.ATime : NULL,
+ file.MTimeDefined ? &file.MTime : NULL);
+ _outFileStreamSpec->Close();
+ _numFlushed++;
+ _fileIsOpen = false;
+ if (file.AttribDefined)
+ NDir::SetFileAttrib_PosixHighDetect(path, file.Attrib);
+ }
+ return S_OK;
+}
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/ExtractCallback.h b/CPP/7zip/UI/FileManager/ExtractCallback.h
index a6d5ae3..c2aa470 100644
--- a/CPP/7zip/UI/FileManager/ExtractCallback.h
+++ b/CPP/7zip/UI/FileManager/ExtractCallback.h
@@ -1,328 +1,310 @@
-// ExtractCallback.h
-
-#ifndef __EXTRACT_CALLBACK_H
-#define __EXTRACT_CALLBACK_H
-
-#include "../../../../C/Alloc.h"
-
-#include "../../../Common/MyCom.h"
-#include "../../../Common/StringConvert.h"
-
-#ifndef _SFX
-#include "../Agent/IFolderArchive.h"
-#endif
-
-#include "../Common/ArchiveExtractCallback.h"
-#include "../Common/ArchiveOpenCallback.h"
-
-#ifndef _NO_CRYPTO
-#include "../../IPassword.h"
-#endif
-
-#ifndef _SFX
-#include "IFolder.h"
-#endif
-
-#include "ProgressDialog2.h"
-
-#ifdef LANG
-#include "LangUtils.h"
-#endif
-
-#ifndef _SFX
-
-class CGrowBuf
-{
- Byte *_items;
- size_t _size;
-
- CLASS_NO_COPY(CGrowBuf);
-
-public:
- bool ReAlloc_KeepData(size_t newSize, size_t keepSize)
- {
- void *buf = MyAlloc(newSize);
- if (!buf)
- return false;
- if (keepSize != 0)
- memcpy(buf, _items, keepSize);
- MyFree(_items);
- _items = (Byte *)buf;
- _size = newSize;
- return true;
- }
-
- CGrowBuf(): _items(0), _size(0) {}
- ~CGrowBuf() { MyFree(_items); }
-
- operator Byte *() { return _items; }
- operator const Byte *() const { return _items; }
- size_t Size() const { return _size; }
-};
-
-struct CVirtFile
-{
- CGrowBuf Data;
-
- UInt64 Size; // real size
- UInt64 ExpectedSize; // the size from props request. 0 if unknown
-
- UString Name;
-
- bool CTimeDefined;
- bool ATimeDefined;
- bool MTimeDefined;
- bool AttribDefined;
-
- bool IsDir;
- bool IsAltStream;
-
- DWORD Attrib;
-
- FILETIME CTime;
- FILETIME ATime;
- FILETIME MTime;
-
- CVirtFile():
- CTimeDefined(false),
- ATimeDefined(false),
- MTimeDefined(false),
- AttribDefined(false),
- IsDir(false),
- IsAltStream(false) {}
-};
-
-class CVirtFileSystem:
- public ISequentialOutStream,
- public CMyUnknownImp
-{
- UInt64 _totalAllocSize;
-
- size_t _pos;
- unsigned _numFlushed;
- bool _fileIsOpen;
- bool _fileMode;
- COutFileStream *_outFileStreamSpec;
- CMyComPtr<ISequentialOutStream> _outFileStream;
-public:
- CObjectVector<CVirtFile> Files;
- UInt64 MaxTotalAllocSize;
- FString DirPrefix;
-
- CVirtFile &AddNewFile()
- {
- if (!Files.IsEmpty())
- {
- MaxTotalAllocSize -= Files.Back().Data.Size();
- }
- return Files.AddNew();
- }
- HRESULT CloseMemFile()
- {
- if (_fileMode)
- {
- return FlushToDisk(true);
- }
- CVirtFile &file = Files.Back();
- if (file.Data.Size() != file.Size)
- {
- file.Data.ReAlloc_KeepData((size_t)file.Size, (size_t)file.Size);
- }
- return S_OK;
- }
-
- bool IsStreamInMem() const
- {
- if (_fileMode)
- return false;
- if (Files.Size() < 1 || /* Files[0].IsAltStream || */ Files[0].IsDir)
- return false;
- return true;
- }
-
- size_t GetMemStreamWrittenSize() const { return _pos; }
-
- CVirtFileSystem(): _outFileStreamSpec(NULL), MaxTotalAllocSize((UInt64)0 - 1) {}
-
- void Init()
- {
- _totalAllocSize = 0;
- _fileMode = false;
- _pos = 0;
- _numFlushed = 0;
- _fileIsOpen = false;
- }
-
- HRESULT CloseFile(const FString &path);
- HRESULT FlushToDisk(bool closeLast);
- size_t GetPos() const { return _pos; }
-
- MY_UNKNOWN_IMP
- STDMETHOD(Write)(const void *data, UInt32 size, UInt32 *processedSize);
-};
-
-#endif
-
-class CExtractCallbackImp:
- public IExtractCallbackUI, // it includes IFolderArchiveExtractCallback
- public IOpenCallbackUI,
- public IFolderArchiveExtractCallback2,
- #ifndef _SFX
- public IFolderOperationsExtractCallback,
- public IFolderExtractToStreamCallback,
- public ICompressProgressInfo,
- #endif
- #ifndef _NO_CRYPTO
- public ICryptoGetTextPassword,
- #endif
- public CMyUnknownImp
-{
- HRESULT MessageError(const char *message, const FString &path);
- void Add_ArchiveName_Error();
-public:
- MY_QUERYINTERFACE_BEGIN2(IFolderArchiveExtractCallback)
- MY_QUERYINTERFACE_ENTRY(IFolderArchiveExtractCallback2)
- #ifndef _SFX
- MY_QUERYINTERFACE_ENTRY(IFolderOperationsExtractCallback)
- MY_QUERYINTERFACE_ENTRY(IFolderExtractToStreamCallback)
- MY_QUERYINTERFACE_ENTRY(ICompressProgressInfo)
- #endif
- #ifndef _NO_CRYPTO
- MY_QUERYINTERFACE_ENTRY(ICryptoGetTextPassword)
- #endif
- MY_QUERYINTERFACE_END
- MY_ADDREF_RELEASE
-
- INTERFACE_IProgress(;)
- INTERFACE_IOpenCallbackUI(;)
- INTERFACE_IFolderArchiveExtractCallback(;)
- INTERFACE_IFolderArchiveExtractCallback2(;)
- // STDMETHOD(SetTotalFiles)(UInt64 total);
- // STDMETHOD(SetCompletedFiles)(const UInt64 *value);
-
- INTERFACE_IExtractCallbackUI(;)
-
- #ifndef _SFX
- // IFolderOperationsExtractCallback
- STDMETHOD(AskWrite)(
- const wchar_t *srcPath,
- Int32 srcIsFolder,
- const FILETIME *srcTime,
- const UInt64 *srcSize,
- const wchar_t *destPathRequest,
- BSTR *destPathResult,
- Int32 *writeAnswer);
- STDMETHOD(ShowMessage)(const wchar_t *message);
- STDMETHOD(SetCurrentFilePath)(const wchar_t *filePath);
- STDMETHOD(SetNumFiles)(UInt64 numFiles);
- INTERFACE_IFolderExtractToStreamCallback(;)
- STDMETHOD(SetRatioInfo)(const UInt64 *inSize, const UInt64 *outSize);
- #endif
-
- // ICryptoGetTextPassword
- #ifndef _NO_CRYPTO
- STDMETHOD(CryptoGetTextPassword)(BSTR *password);
- #endif
-
-private:
- UString _currentArchivePath;
- bool _needWriteArchivePath;
-
- UString _currentFilePath;
- bool _isFolder;
-
- bool _isAltStream;
- UInt64 _curSize;
- bool _curSizeDefined;
- UString _filePath;
- // bool _extractMode;
- // bool _testMode;
- bool _newVirtFileWasAdded;
- bool _needUpdateStat;
-
-
- HRESULT SetCurrentFilePath2(const wchar_t *filePath);
- void AddError_Message(LPCWSTR message);
-
- #ifndef _SFX
- bool _hashStreamWasUsed;
- COutStreamWithHash *_hashStreamSpec;
- CMyComPtr<ISequentialOutStream> _hashStream;
- IHashCalc *_hashCalc; // it's for stat in Test operation
- #endif
-
-public:
-
- #ifndef _SFX
- CVirtFileSystem *VirtFileSystemSpec;
- CMyComPtr<ISequentialOutStream> VirtFileSystem;
- #endif
-
- bool ProcessAltStreams;
-
- bool StreamMode;
-
- CProgressDialog *ProgressDialog;
- #ifndef _SFX
- UInt64 NumFolders;
- UInt64 NumFiles;
- bool NeedAddFile;
- #endif
- UInt32 NumArchiveErrors;
- bool ThereAreMessageErrors;
- NExtract::NOverwriteMode::EEnum OverwriteMode;
-
- #ifndef _NO_CRYPTO
- bool PasswordIsDefined;
- bool PasswordWasAsked;
- UString Password;
- #endif
-
-
- UString _lang_Extracting;
- UString _lang_Testing;
- UString _lang_Skipping;
- UString _lang_Empty;
-
- bool _totalFilesDefined;
- bool _totalBytesDefined;
- bool MultiArcMode;
-
- CExtractCallbackImp():
- #ifndef _NO_CRYPTO
- PasswordIsDefined(false),
- PasswordWasAsked(false),
- #endif
- OverwriteMode(NExtract::NOverwriteMode::kAsk),
- StreamMode(false),
- ProcessAltStreams(true),
-
- _totalFilesDefined(false),
- _totalBytesDefined(false),
- MultiArcMode(false)
-
- #ifndef _SFX
- , _hashCalc(NULL)
- #endif
- {}
-
- ~CExtractCallbackImp();
- void Init();
-
- #ifndef _SFX
- void SetHashCalc(IHashCalc *hashCalc) { _hashCalc = hashCalc; }
-
- void SetHashMethods(IHashCalc *hash)
- {
- if (!hash)
- return;
- _hashStreamSpec = new COutStreamWithHash;
- _hashStream = _hashStreamSpec;
- _hashStreamSpec->_hash = hash;
- }
- #endif
-
- bool IsOK() const { return NumArchiveErrors == 0 && !ThereAreMessageErrors; }
-};
-
-#endif
+// ExtractCallback.h
+
+#ifndef ZIP7_INC_EXTRACT_CALLBACK_H
+#define ZIP7_INC_EXTRACT_CALLBACK_H
+
+#include "../../../../C/Alloc.h"
+
+#include "../../../Common/MyCom.h"
+#include "../../../Common/StringConvert.h"
+
+#ifndef Z7_SFX
+#include "../Agent/IFolderArchive.h"
+#endif
+
+#include "../Common/ArchiveExtractCallback.h"
+#include "../Common/ArchiveOpenCallback.h"
+
+#ifndef Z7_NO_CRYPTO
+#include "../../IPassword.h"
+#endif
+
+#ifndef Z7_SFX
+#include "IFolder.h"
+#endif
+
+#include "ProgressDialog2.h"
+
+#ifdef Z7_LANG
+// #include "LangUtils.h"
+#endif
+
+#ifndef Z7_SFX
+
+class CGrowBuf
+{
+ Byte *_items;
+ size_t _size;
+
+ Z7_CLASS_NO_COPY(CGrowBuf)
+
+public:
+ bool ReAlloc_KeepData(size_t newSize, size_t keepSize)
+ {
+ void *buf = MyAlloc(newSize);
+ if (!buf)
+ return false;
+ if (keepSize != 0)
+ memcpy(buf, _items, keepSize);
+ MyFree(_items);
+ _items = (Byte *)buf;
+ _size = newSize;
+ return true;
+ }
+
+ CGrowBuf(): _items(NULL), _size(0) {}
+ ~CGrowBuf() { MyFree(_items); }
+
+ operator Byte *() { return _items; }
+ operator const Byte *() const { return _items; }
+ size_t Size() const { return _size; }
+};
+
+struct CVirtFile
+{
+ CGrowBuf Data;
+
+ UInt64 Size; // real size
+ UInt64 ExpectedSize; // the size from props request. 0 if unknown
+
+ UString Name;
+
+ bool CTimeDefined;
+ bool ATimeDefined;
+ bool MTimeDefined;
+ bool AttribDefined;
+
+ bool IsDir;
+ bool IsAltStream;
+
+ DWORD Attrib;
+
+ FILETIME CTime;
+ FILETIME ATime;
+ FILETIME MTime;
+
+ CVirtFile():
+ CTimeDefined(false),
+ ATimeDefined(false),
+ MTimeDefined(false),
+ AttribDefined(false),
+ IsDir(false),
+ IsAltStream(false) {}
+};
+
+
+Z7_CLASS_IMP_NOQIB_1(
+ CVirtFileSystem,
+ ISequentialOutStream
+)
+ UInt64 _totalAllocSize;
+
+ size_t _pos;
+ unsigned _numFlushed;
+ bool _fileIsOpen;
+ bool _fileMode;
+ COutFileStream *_outFileStreamSpec;
+ CMyComPtr<ISequentialOutStream> _outFileStream;
+public:
+ CObjectVector<CVirtFile> Files;
+ UInt64 MaxTotalAllocSize;
+ FString DirPrefix;
+
+ CVirtFile &AddNewFile()
+ {
+ if (!Files.IsEmpty())
+ {
+ MaxTotalAllocSize -= Files.Back().Data.Size();
+ }
+ return Files.AddNew();
+ }
+ HRESULT CloseMemFile()
+ {
+ if (_fileMode)
+ {
+ return FlushToDisk(true);
+ }
+ CVirtFile &file = Files.Back();
+ if (file.Data.Size() != file.Size)
+ {
+ file.Data.ReAlloc_KeepData((size_t)file.Size, (size_t)file.Size);
+ }
+ return S_OK;
+ }
+
+ bool IsStreamInMem() const
+ {
+ if (_fileMode)
+ return false;
+ if (Files.Size() < 1 || /* Files[0].IsAltStream || */ Files[0].IsDir)
+ return false;
+ return true;
+ }
+
+ size_t GetMemStreamWrittenSize() const { return _pos; }
+
+ CVirtFileSystem(): _outFileStreamSpec(NULL), MaxTotalAllocSize((UInt64)0 - 1) {}
+
+ void Init()
+ {
+ _totalAllocSize = 0;
+ _fileMode = false;
+ _pos = 0;
+ _numFlushed = 0;
+ _fileIsOpen = false;
+ }
+
+ HRESULT CloseFile(const FString &path);
+ HRESULT FlushToDisk(bool closeLast);
+ size_t GetPos() const { return _pos; }
+};
+
+#endif
+
+class CExtractCallbackImp Z7_final:
+ public IFolderArchiveExtractCallback,
+ /* IExtractCallbackUI:
+ before v23.00 : it included IFolderArchiveExtractCallback
+ since v23.00 : it doesn't include IFolderArchiveExtractCallback
+ */
+ public IExtractCallbackUI, // NON-COM interface since 23.00
+ public IOpenCallbackUI, // NON-COM interface
+ public IFolderArchiveExtractCallback2,
+ #ifndef Z7_SFX
+ public IFolderOperationsExtractCallback,
+ public IFolderExtractToStreamCallback,
+ public ICompressProgressInfo,
+ #endif
+ #ifndef Z7_NO_CRYPTO
+ public ICryptoGetTextPassword,
+ #endif
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(IFolderArchiveExtractCallback)
+ Z7_COM_QI_ENTRY(IFolderArchiveExtractCallback2)
+ #ifndef Z7_SFX
+ Z7_COM_QI_ENTRY(IFolderOperationsExtractCallback)
+ Z7_COM_QI_ENTRY(IFolderExtractToStreamCallback)
+ Z7_COM_QI_ENTRY(ICompressProgressInfo)
+ #endif
+ #ifndef Z7_NO_CRYPTO
+ Z7_COM_QI_ENTRY(ICryptoGetTextPassword)
+ #endif
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_IMP(IExtractCallbackUI)
+ Z7_IFACE_IMP(IOpenCallbackUI)
+ Z7_IFACE_COM7_IMP(IProgress)
+ Z7_IFACE_COM7_IMP(IFolderArchiveExtractCallback)
+ Z7_IFACE_COM7_IMP(IFolderArchiveExtractCallback2)
+ #ifndef Z7_SFX
+ Z7_IFACE_COM7_IMP(IFolderOperationsExtractCallback)
+ Z7_IFACE_COM7_IMP(IFolderExtractToStreamCallback)
+ Z7_IFACE_COM7_IMP(ICompressProgressInfo)
+ #endif
+ #ifndef Z7_NO_CRYPTO
+ Z7_IFACE_COM7_IMP(ICryptoGetTextPassword)
+ #endif
+
+
+ UString _currentArchivePath;
+ bool _needWriteArchivePath;
+
+ bool _isFolder;
+ UString _currentFilePath;
+ UString _filePath;
+
+ #ifndef Z7_SFX
+ bool _needUpdateStat;
+ bool _newVirtFileWasAdded;
+ bool _isAltStream;
+ bool _curSize_Defined;
+ UInt64 _curSize;
+ // bool _extractMode;
+ // bool _testMode;
+ bool _hashStreamWasUsed;
+ COutStreamWithHash *_hashStreamSpec;
+ CMyComPtr<ISequentialOutStream> _hashStream;
+ IHashCalc *_hashCalc; // it's for stat in Test operation
+ #endif
+
+ HRESULT SetCurrentFilePath2(const wchar_t *filePath);
+ void AddError_Message(LPCWSTR message);
+ HRESULT MessageError(const char *message, const FString &path);
+ void Add_ArchiveName_Error();
+
+public:
+
+ #ifndef Z7_SFX
+ CVirtFileSystem *VirtFileSystemSpec;
+ CMyComPtr<ISequentialOutStream> VirtFileSystem;
+ #endif
+
+ bool ProcessAltStreams;
+
+ bool StreamMode;
+
+ CProgressDialog *ProgressDialog;
+ #ifndef Z7_SFX
+ UInt64 NumFolders;
+ UInt64 NumFiles;
+ bool NeedAddFile;
+ #endif
+ UInt32 NumArchiveErrors;
+ bool ThereAreMessageErrors;
+ NExtract::NOverwriteMode::EEnum OverwriteMode;
+
+ #ifndef Z7_NO_CRYPTO
+ bool PasswordIsDefined;
+ bool PasswordWasAsked;
+ UString Password;
+ #endif
+
+
+ UString _lang_Extracting;
+ UString _lang_Testing;
+ UString _lang_Skipping;
+ UString _lang_Reading;
+ UString _lang_Empty;
+
+ bool _totalFilesDefined;
+ bool _totalBytesDefined;
+ bool MultiArcMode;
+
+ CExtractCallbackImp():
+ #ifndef Z7_SFX
+ _hashCalc(NULL),
+ #endif
+ ProcessAltStreams(true),
+ StreamMode(false),
+ OverwriteMode(NExtract::NOverwriteMode::kAsk),
+ #ifndef Z7_NO_CRYPTO
+ PasswordIsDefined(false),
+ PasswordWasAsked(false),
+ #endif
+ _totalFilesDefined(false),
+ _totalBytesDefined(false),
+ MultiArcMode(false)
+ {}
+
+ ~CExtractCallbackImp();
+ void Init();
+
+ #ifndef Z7_SFX
+ void SetHashCalc(IHashCalc *hashCalc) { _hashCalc = hashCalc; }
+
+ void SetHashMethods(IHashCalc *hash)
+ {
+ if (!hash)
+ return;
+ _hashStreamSpec = new COutStreamWithHash;
+ _hashStream = _hashStreamSpec;
+ _hashStreamSpec->_hash = hash;
+ }
+ #endif
+
+ bool IsOK() const { return NumArchiveErrors == 0 && !ThereAreMessageErrors; }
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/FM.cpp b/CPP/7zip/UI/FileManager/FM.cpp
new file mode 100644
index 0000000..13189a7
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FM.cpp
@@ -0,0 +1,1116 @@
+// FM.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <shlwapi.h>
+#else
+#include <Shlwapi.h>
+#endif
+
+#include "../../../../C/Compiler.h"
+#include "../../../../C/Alloc.h"
+#ifdef _WIN32
+#include "../../../../C/DllSecur.h"
+#endif
+
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/MemoryLock.h"
+#include "../../../Windows/NtCheck.h"
+#include "../../../Windows/System.h"
+
+#ifndef UNDER_CE
+#include "../../../Windows/SecurityUtils.h"
+#endif
+
+#include "../GUI/ExtractRes.h"
+
+#include "resource.h"
+
+#include "App.h"
+#include "FormatUtils.h"
+#include "LangUtils.h"
+#include "MyLoadMenu.h"
+#include "Panel.h"
+#include "RegistryUtils.h"
+#include "StringUtils.h"
+#include "ViewSettings.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NFind;
+
+// #define MAX_LOADSTRING 100
+
+extern
+bool g_RAM_Size_Defined;
+bool g_RAM_Size_Defined;
+
+extern
+bool g_LargePagesMode;
+bool g_LargePagesMode = false;
+// static bool g_OpenArchive = false;
+
+static bool g_Maximized = false;
+
+extern
+UInt64 g_RAM_Size;
+UInt64 g_RAM_Size;
+
+#ifdef _WIN32
+extern
+HINSTANCE g_hInstance;
+HINSTANCE g_hInstance;
+#endif
+
+HWND g_HWND;
+
+static UString g_MainPath;
+static UString g_ArcFormat;
+
+// HRESULT LoadGlobalCodecs();
+void FreeGlobalCodecs();
+
+#ifndef UNDER_CE
+
+extern
+DWORD g_ComCtl32Version;
+DWORD g_ComCtl32Version;
+
+static DWORD GetDllVersion(LPCTSTR dllName)
+{
+ DWORD dwVersion = 0;
+ const HMODULE hmodule = LoadLibrary(dllName);
+ if (hmodule)
+ {
+ const
+ DLLGETVERSIONPROC f_DllGetVersion = Z7_GET_PROC_ADDRESS(
+ DLLGETVERSIONPROC, hmodule,
+ "DllGetVersion");
+ if (f_DllGetVersion)
+ {
+ DLLVERSIONINFO dvi;
+ ZeroMemory(&dvi, sizeof(dvi));
+ dvi.cbSize = sizeof(dvi);
+ const HRESULT hr = f_DllGetVersion(&dvi);
+ if (SUCCEEDED(hr))
+ dwVersion = (DWORD)MAKELONG(dvi.dwMinorVersion, dvi.dwMajorVersion);
+ }
+ FreeLibrary(hmodule);
+ }
+ return dwVersion;
+}
+
+#endif
+
+bool g_IsSmallScreen = false;
+
+extern
+bool g_LVN_ITEMACTIVATE_Support;
+bool g_LVN_ITEMACTIVATE_Support = true;
+// LVN_ITEMACTIVATE replaces both NM_DBLCLK & NM_RETURN
+// Windows 2000
+// NT/98 + IE 3 (g_ComCtl32Version >= 4.70)
+
+
+static const int kNumDefaultPanels = 1;
+static const int kSplitterWidth = 4;
+static const int kSplitterRateMax = 1 << 16;
+static const int kPanelSizeMin = 120;
+
+
+class CSplitterPos
+{
+ int _ratio; // 10000 is max
+ int _pos;
+ int _fullWidth;
+ void SetRatioFromPos(HWND hWnd)
+ { _ratio = (_pos + kSplitterWidth / 2) * kSplitterRateMax /
+ MyMax(GetWidth(hWnd), 1); }
+public:
+ int GetPos() const
+ { return _pos; }
+ int GetWidth(HWND hWnd) const
+ {
+ RECT rect;
+ ::GetClientRect(hWnd, &rect);
+ return rect.right;
+ }
+ void SetRatio(HWND hWnd, int aRatio)
+ {
+ _ratio = aRatio;
+ SetPosFromRatio(hWnd);
+ }
+ void SetPosPure(HWND hWnd, int pos)
+ {
+ int posMax = GetWidth(hWnd) - kSplitterWidth;
+ if (posMax < kPanelSizeMin * 2)
+ pos = posMax / 2;
+ else
+ {
+ if (pos > posMax - kPanelSizeMin)
+ pos = posMax - kPanelSizeMin;
+ else if (pos < kPanelSizeMin)
+ pos = kPanelSizeMin;
+ }
+ _pos = pos;
+ }
+ void SetPos(HWND hWnd, int pos)
+ {
+ _fullWidth = GetWidth(hWnd);
+ SetPosPure(hWnd, pos);
+ SetRatioFromPos(hWnd);
+ }
+ void SetPosFromRatio(HWND hWnd)
+ {
+ int fullWidth = GetWidth(hWnd);
+ if (_fullWidth != fullWidth && fullWidth != 0)
+ {
+ _fullWidth = fullWidth;
+ SetPosPure(hWnd, GetWidth(hWnd) * _ratio / kSplitterRateMax - kSplitterWidth / 2);
+ }
+ }
+};
+
+static bool g_CanChangeSplitter = false;
+static UInt32 g_SplitterPos = 0;
+static CSplitterPos g_Splitter;
+static bool g_PanelsInfoDefined = false;
+static bool g_WindowWasCreated = false;
+
+static int g_StartCaptureMousePos;
+static int g_StartCaptureSplitterPos;
+
+CApp g_App;
+
+LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+static const wchar_t * const kWindowClass = L"7-Zip::FM";
+
+#ifdef UNDER_CE
+#define WS_OVERLAPPEDWINDOW ( \
+ WS_OVERLAPPED | \
+ WS_CAPTION | \
+ WS_SYSMENU | \
+ WS_THICKFRAME | \
+ WS_MINIMIZEBOX | \
+ WS_MAXIMIZEBOX)
+#endif
+
+// FUNCTION: InitInstance(HANDLE, int)
+static BOOL InitInstance(int nCmdShow)
+{
+ CWindow wnd;
+
+ // LoadString(hInstance, IDS_CLASS, windowClass, MAX_LOADSTRING);
+
+ UString title ("7-Zip"); // LangString(IDS_APP_TITLE, 0x03000000);
+
+ /*
+ //If it is already running, then focus on the window
+ hWnd = FindWindow(windowClass, title);
+ if (hWnd)
+ {
+ SetForegroundWindow ((HWND) (((DWORD)hWnd) | 0x01));
+ return 0;
+ }
+ */
+
+ WNDCLASSW wc;
+
+ // wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.style = 0;
+ wc.lpfnWndProc = (WNDPROC) WndProc;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = g_hInstance;
+ wc.hIcon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ICON));
+
+ // wc.hCursor = LoadCursor (NULL, IDC_ARROW);
+ wc.hCursor = ::LoadCursor(NULL, IDC_SIZEWE);
+ // wc.hbrBackground = (HBRUSH) GetStockObject(WHITE_BRUSH);
+ wc.hbrBackground = (HBRUSH) (COLOR_BTNFACE + 1);
+
+ wc.lpszMenuName =
+ #ifdef UNDER_CE
+ 0
+ #else
+ MAKEINTRESOURCEW(IDM_MENU)
+ #endif
+ ;
+
+ wc.lpszClassName = kWindowClass;
+
+ if (MyRegisterClass(&wc) == 0)
+ return FALSE;
+
+ // RECT rect;
+ // GetClientRect(hWnd, &rect);
+
+ DWORD style = WS_OVERLAPPEDWINDOW;
+ // DWORD style = 0;
+
+ CWindowInfo info;
+ info.maximized = false;
+ int x, y, xSize, ySize;
+ x = y = xSize = ySize = CW_USEDEFAULT;
+ bool windowPosIsRead;
+ info.Read(windowPosIsRead, g_PanelsInfoDefined);
+
+ if (windowPosIsRead)
+ {
+ x = info.rect.left;
+ y = info.rect.top;
+
+ xSize = RECT_SIZE_X(info.rect);
+ ySize = RECT_SIZE_Y(info.rect);
+ }
+
+
+ if (g_PanelsInfoDefined)
+ {
+ g_SplitterPos = info.splitterPos;
+ if (info.numPanels < 1 || info.numPanels > 2)
+ info.numPanels = kNumDefaultPanels;
+ if (info.currentPanel >= 2)
+ info.currentPanel = 0;
+ }
+ else
+ {
+ info.numPanels = kNumDefaultPanels;
+ info.currentPanel = 0;
+ }
+
+ g_App.NumPanels = info.numPanels;
+ g_App.LastFocusedPanel = info.currentPanel;
+
+ if (!wnd.Create(kWindowClass, title, style,
+ x, y, xSize, ySize, NULL, NULL, g_hInstance, NULL))
+ return FALSE;
+
+ if (nCmdShow == SW_SHOWNORMAL ||
+ nCmdShow == SW_SHOW
+ #ifndef UNDER_CE
+ || nCmdShow == SW_SHOWDEFAULT
+ #endif
+ )
+ {
+ if (info.maximized)
+ nCmdShow = SW_SHOWMAXIMIZED;
+ else
+ nCmdShow = SW_SHOWNORMAL;
+ }
+
+ if (nCmdShow == SW_SHOWMAXIMIZED)
+ g_Maximized = true;
+
+ #ifndef UNDER_CE
+ WINDOWPLACEMENT placement;
+ placement.length = sizeof(placement);
+ if (wnd.GetPlacement(&placement))
+ {
+ if (windowPosIsRead)
+ placement.rcNormalPosition = info.rect;
+ placement.showCmd = (UINT)nCmdShow;
+ wnd.SetPlacement(&placement);
+ }
+ else
+ #endif
+ wnd.Show(nCmdShow);
+
+ return TRUE;
+}
+
+/*
+static void GetCommands(const UString &aCommandLine, UString &aCommands)
+{
+ UString aProgramName;
+ aCommands.Empty();
+ bool aQuoteMode = false;
+ for (int i = 0; i < aCommandLine.Length(); i++)
+ {
+ wchar_t aChar = aCommandLine[i];
+ if (aChar == L'\"')
+ aQuoteMode = !aQuoteMode;
+ else if (aChar == L' ' && !aQuoteMode)
+ {
+ if (!aQuoteMode)
+ {
+ i++;
+ break;
+ }
+ }
+ else
+ aProgramName += aChar;
+ }
+ aCommands = aCommandLine.Ptr(i);
+}
+*/
+
+#if defined(_WIN32) && !defined(_WIN64) && !defined(UNDER_CE)
+
+extern
+bool g_Is_Wow64;
+bool g_Is_Wow64;
+
+typedef BOOL (WINAPI *Func_IsWow64Process)(HANDLE, PBOOL);
+
+static void Set_Wow64()
+{
+ g_Is_Wow64 = false;
+ const
+ Func_IsWow64Process fn = Z7_GET_PROC_ADDRESS(
+ Func_IsWow64Process, GetModuleHandleA("kernel32.dll"),
+ "IsWow64Process");
+ if (fn)
+ {
+ BOOL isWow;
+ if (fn(GetCurrentProcess(), &isWow))
+ g_Is_Wow64 = (isWow != FALSE);
+ }
+}
+
+#endif
+
+#if _MSC_VER > 1400 /* && _MSC_VER <= 1900 */
+ // GetVersion was declared deprecated
+ #pragma warning(disable : 4996)
+#endif
+#ifdef __clang__
+ #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+#endif
+
+bool IsLargePageSupported();
+bool IsLargePageSupported()
+{
+ #ifdef _WIN64
+ return true;
+ #else
+
+ DWORD v = GetVersion();
+ // low byte is major version:
+ // next byte is minor version:
+ v = ((v & 0xff) << 8) | ((v >> 8) & 0xFF);
+ return (v > 0x501);
+ // if ((Byte)v < 5) return false;
+ // if ((Byte)v > 5) return true;
+ // return ((Byte)(v >> 8) > 1);
+ /* large pages work in 5.1 (XP-32bit) if it's (g_Is_Wow64) mode;
+ but here we don't enable them in (XP-32bit). */
+ #endif
+}
+
+#ifndef UNDER_CE
+
+static void SetMemoryLock()
+{
+ if (!IsLargePageSupported())
+ return;
+ // if (ReadLockMemoryAdd())
+ NSecurity::AddLockMemoryPrivilege();
+
+ if (ReadLockMemoryEnable())
+ if (NSecurity::Get_LargePages_RiskLevel() == 0)
+ {
+ // note: child processes can inherit that Privilege
+ g_LargePagesMode = NSecurity::EnablePrivilege_LockMemory();
+ }
+}
+
+extern
+bool g_SymLink_Supported;
+bool g_SymLink_Supported = false;
+
+static void Set_SymLink_Supported()
+{
+ // g_SymLink_Supported = false;
+ const DWORD v = GetVersion();
+ // low byte is major version:
+ if ((Byte)v < 6)
+ return;
+ g_SymLink_Supported = true;
+ // if (g_SymLink_Supported)
+ {
+ NSecurity::EnablePrivilege_SymLink();
+ }
+}
+
+#endif
+
+/*
+static const int kNumSwitches = 1;
+
+namespace NKey {
+enum Enum
+{
+ kOpenArachive = 0
+};
+
+}
+
+static const CSwitchForm kSwitchForms[kNumSwitches] =
+ {
+ { L"SOA", NSwitchType::kSimple, false },
+ };
+*/
+
+// int APIENTRY WinMain2(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */, LPSTR /* lpCmdLine */, int /* nCmdShow */);
+
+static void ErrorMessage(const wchar_t *s)
+{
+ MessageBoxW(NULL, s, L"7-Zip", MB_ICONERROR);
+}
+
+static void ErrorMessage(const char *s)
+{
+ ErrorMessage(GetUnicodeString(s));
+}
+
+
+#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE)
+#define NT_CHECK_FAIL_ACTION ErrorMessage("Unsupported Windows version"); return 1;
+#endif
+
+static int WINAPI WinMain2(int nCmdShow)
+{
+ g_RAM_Size_Defined = NSystem::GetRamSize(g_RAM_Size);
+
+ #ifdef _WIN32
+
+ /*
+ #ifndef _WIN64
+ #ifndef UNDER_CE
+ {
+ HMODULE hMod = GetModuleHandle("Kernel32.dll");
+ if (hMod)
+ {
+ typedef BOOL (WINAPI *PSETDEP)(DWORD);
+ #define MY_PROCESS_DEP_ENABLE 1
+ PSETDEP procSet = (PSETDEP)GetProcAddress(hMod,"SetProcessDEPPolicy");
+ if (procSet)
+ procSet(MY_PROCESS_DEP_ENABLE);
+
+ typedef BOOL (WINAPI *HSI)(HANDLE, HEAP_INFORMATION_CLASS ,PVOID, SIZE_T);
+ HSI hsi = (HSI)GetProcAddress(hMod, "HeapSetInformation");
+ #define MY_HeapEnableTerminationOnCorruption ((HEAP_INFORMATION_CLASS)1)
+ if (hsi)
+ hsi(NULL, MY_HeapEnableTerminationOnCorruption, NULL, 0);
+ }
+ }
+ #endif
+ #endif
+ */
+
+ NT_CHECK
+ #ifdef Z7_LARGE_PAGES
+ SetLargePageSize();
+ #endif
+
+ #endif
+
+ #ifdef Z7_LANG
+ LoadLangOneTime();
+ #endif
+
+ InitCommonControls();
+
+ #ifndef UNDER_CE
+ g_ComCtl32Version = ::GetDllVersion(TEXT("comctl32.dll"));
+ g_LVN_ITEMACTIVATE_Support = (g_ComCtl32Version >= MAKELONG(71, 4));
+ #endif
+
+ #if defined(_WIN32) && !defined(_WIN64) && !defined(UNDER_CE)
+ Set_Wow64();
+ #endif
+
+
+ g_IsSmallScreen = !NWindows::NControl::IsDialogSizeOK(200, 200);
+
+ // OleInitialize is required for drag and drop.
+ #ifndef UNDER_CE
+ OleInitialize(NULL);
+ #endif
+ // Maybe needs CoInitializeEx also ?
+ // NCOM::CComInitializer comInitializer;
+
+ UString commandsString;
+ // MessageBoxW(NULL, GetCommandLineW(), L"", 0);
+
+ #ifdef UNDER_CE
+ commandsString = GetCommandLineW();
+ #else
+ UString programString;
+ SplitStringToTwoStrings(GetCommandLineW(), programString, commandsString);
+ #endif
+
+ commandsString.Trim();
+ UString paramString, tailString;
+ SplitStringToTwoStrings(commandsString, paramString, tailString);
+ paramString.Trim();
+ tailString.Trim();
+ if (tailString.IsPrefixedBy(L"-t"))
+ g_ArcFormat = tailString.Ptr(2);
+
+ /*
+ UStringVector switches;
+ for (;;)
+ {
+ if (tailString.IsEmpty())
+ break;
+ UString s1, s2;
+ SplitStringToTwoStrings(tailString, s1, s2);
+ if (s2.IsEmpty())
+ {
+ tailString.Trim();
+ switches.Add(tailString);
+ break;
+ }
+ s1.Trim();
+ switches.Add(s1);
+ tailString = s2;
+ }
+
+ FOR_VECTOR(i, switches)
+ {
+ const UString &sw = switches[i];
+ if (sw.IsPrefixedBy(L"-t"))
+ g_ArcFormat = sw.Ptr(2);
+ //
+ else if (sw.IsPrefixedBy(L"-stp"))
+ {
+ const wchar_t *end;
+ UInt32 val = ConvertStringToUInt32(sw.Ptr(4), &end);
+ if (*end != 0)
+ throw 111;
+ g_TypeParseLevel = val;
+ }
+ else
+ //
+ throw 112;
+ }
+ */
+
+ if (!paramString.IsEmpty())
+ {
+ g_MainPath = paramString;
+ // return WinMain2(hInstance, hPrevInstance, lpCmdLine, nCmdShow);
+
+ // MessageBoxW(NULL, paramString, L"", 0);
+ }
+ /*
+ UStringVector commandStrings;
+ NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);
+ NCommandLineParser::CParser parser(kNumSwitches);
+ try
+ {
+ parser.ParseStrings(kSwitchForms, commandStrings);
+ const UStringVector &nonSwitchStrings = parser.NonSwitchStrings;
+ if (nonSwitchStrings.Size() > 1)
+ {
+ g_MainPath = nonSwitchStrings[1];
+ // g_OpenArchive = parser[NKey::kOpenArachive].ThereIs;
+ CFileInfoW fileInfo;
+ if (FindFile(g_MainPath, fileInfo))
+ {
+ if (!fileInfo.IsDir())
+ g_OpenArchive = true;
+ }
+ }
+ }
+ catch(...) { }
+ */
+
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ SetMemoryLock();
+ Set_SymLink_Supported();
+ #endif
+
+ g_App.ReloadLangItems();
+
+ MSG msg;
+ if (!InitInstance (nCmdShow))
+ return FALSE;
+
+ // we will load Global_Codecs at first use instead.
+ /*
+ OutputDebugStringW(L"Before LoadGlobalCodecs");
+ LoadGlobalCodecs();
+ OutputDebugStringW(L"After LoadGlobalCodecs");
+ */
+
+ #ifndef _UNICODE
+ if (g_IsNT)
+ {
+ HACCEL hAccels = LoadAcceleratorsW(g_hInstance, MAKEINTRESOURCEW(IDR_ACCELERATOR1));
+ while (GetMessageW(&msg, NULL, 0, 0))
+ {
+ if (TranslateAcceleratorW(g_HWND, hAccels, &msg) == 0)
+ {
+ TranslateMessage(&msg);
+ DispatchMessageW(&msg);
+ }
+ }
+ }
+ else
+ #endif
+ {
+ HACCEL hAccels = LoadAccelerators(g_hInstance, MAKEINTRESOURCE(IDR_ACCELERATOR1));
+ while (GetMessage(&msg, NULL, 0, 0))
+ {
+ if (TranslateAccelerator(g_HWND, hAccels, &msg) == 0)
+ {
+ // if (g_Hwnd != NULL || !IsDialogMessage(g_Hwnd, &msg))
+ // if (!IsDialogMessage(g_Hwnd, &msg))
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ }
+
+ // Destructor of g_CodecsReleaser can release DLLs.
+ // But we suppose that it's better to release DLLs here (before destructor).
+ FreeGlobalCodecs();
+
+ g_HWND = NULL;
+ #ifndef UNDER_CE
+ OleUninitialize();
+ #endif
+ return (int)msg.wParam;
+}
+
+int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */,
+ #ifdef UNDER_CE
+ LPWSTR
+ #else
+ LPSTR
+ #endif
+ /* lpCmdLine */, int nCmdShow)
+{
+ g_hInstance = hInstance;
+
+ try
+ {
+ try
+ {
+ #ifdef _WIN32
+ My_SetDefaultDllDirectories();
+ #endif
+ return WinMain2(nCmdShow);
+ }
+ catch (...)
+ {
+ g_ExitEventLauncher.Exit(true);
+ throw;
+ }
+ }
+ catch(const CNewException &)
+ {
+ ErrorMessage(LangString(IDS_MEM_ERROR));
+ return 1;
+ }
+ catch(const UString &s)
+ {
+ ErrorMessage(s);
+ return 1;
+ }
+ catch(const AString &s)
+ {
+ ErrorMessage(s.Ptr());
+ return 1;
+ }
+ catch(const wchar_t *s)
+ {
+ ErrorMessage(s);
+ return 1;
+ }
+ catch(const char *s)
+ {
+ ErrorMessage(s);
+ return 1;
+ }
+ catch(int v)
+ {
+ AString e ("Error: ");
+ e.Add_UInt32((unsigned)v);
+ ErrorMessage(e);
+ return 1;
+ }
+ catch(...)
+ {
+ ErrorMessage("Unknown error");
+ return 1;
+ }
+}
+
+static void SaveWindowInfo(HWND aWnd)
+{
+ CWindowInfo info;
+
+ #ifdef UNDER_CE
+
+ if (!::GetWindowRect(aWnd, &info.rect))
+ return;
+ info.maximized = g_Maximized;
+
+ #else
+
+ WINDOWPLACEMENT placement;
+ placement.length = sizeof(placement);
+ if (!::GetWindowPlacement(aWnd, &placement))
+ return;
+ info.rect = placement.rcNormalPosition;
+ info.maximized = BOOLToBool(::IsZoomed(aWnd));
+
+ #endif
+
+ info.numPanels = g_App.NumPanels;
+ info.currentPanel = g_App.LastFocusedPanel;
+ info.splitterPos = (unsigned)g_Splitter.GetPos();
+
+ info.Save();
+}
+
+static void ExecuteCommand(UINT commandID)
+{
+ CPanel::CDisableTimerProcessing disableTimerProcessing1(g_App.Panels[0]);
+ CPanel::CDisableTimerProcessing disableTimerProcessing2(g_App.Panels[1]);
+
+ switch (commandID)
+ {
+ case kMenuCmdID_Toolbar_Add: g_App.AddToArchive(); break;
+ case kMenuCmdID_Toolbar_Extract: g_App.ExtractArchives(); break;
+ case kMenuCmdID_Toolbar_Test: g_App.TestArchives(); break;
+ }
+}
+
+LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_COMMAND:
+ {
+ unsigned wmId = LOWORD(wParam);
+ unsigned wmEvent = HIWORD(wParam);
+ if ((HWND) lParam != NULL && wmEvent != 0)
+ break;
+ if (wmId >= kMenuCmdID_Toolbar_Start && wmId < kMenuCmdID_Toolbar_End)
+ {
+ ExecuteCommand(wmId);
+ return 0;
+ }
+ if (OnMenuCommand(hWnd, wmId))
+ return 0;
+ break;
+ }
+ case WM_INITMENUPOPUP:
+ OnMenuActivating(hWnd, HMENU(wParam), LOWORD(lParam));
+ break;
+
+ /*
+ It doesn't help
+ case WM_EXITMENULOOP:
+ {
+ OnMenuUnActivating(hWnd);
+ break;
+ }
+ case WM_UNINITMENUPOPUP:
+ OnMenuUnActivating(hWnd, HMENU(wParam), lParam);
+ break;
+ */
+
+ case WM_CREATE:
+ {
+ g_HWND = hWnd;
+ /*
+ INITCOMMONCONTROLSEX icex;
+ icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ icex.dwICC = ICC_BAR_CLASSES;
+ InitCommonControlsEx(&icex);
+
+ // Toolbar buttons used to create the first 4 buttons.
+ TBBUTTON tbb [ ] =
+ {
+ // {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0},
+ // {VIEW_PARENTFOLDER, kParentFolderID, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0},
+ // {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0},
+ {VIEW_NEWFOLDER, ID_FILE_CREATEFOLDER, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0},
+ };
+
+ int baseID = 100;
+ NWindows::NControl::CToolBar aToolBar;
+ aToolBar.Attach(::CreateToolbarEx (hWnd,
+ WS_CHILD | WS_BORDER | WS_VISIBLE | TBSTYLE_TOOLTIPS, // | TBSTYLE_FLAT
+ baseID + 2, 11,
+ (HINSTANCE)HINST_COMMCTRL, IDB_VIEW_SMALL_COLOR,
+ (LPCTBBUTTON)&tbb, Z7_ARRAY_SIZE(tbb),
+ 0, 0, 100, 30, sizeof (TBBUTTON)));
+ */
+ // HCURSOR cursor = ::LoadCursor(0, IDC_SIZEWE);
+ // ::SetCursor(cursor);
+
+ if (g_PanelsInfoDefined)
+ g_Splitter.SetPos(hWnd, (int)g_SplitterPos);
+ else
+ {
+ g_Splitter.SetRatio(hWnd, kSplitterRateMax / 2);
+ g_SplitterPos = (unsigned)g_Splitter.GetPos();
+ }
+
+ RECT rect;
+ ::GetClientRect(hWnd, &rect);
+ const int xSize = rect.right;
+ int xSizes[2];
+ xSizes[0] = g_Splitter.GetPos();
+ xSizes[1] = xSize - kSplitterWidth - xSizes[0];
+ if (xSizes[1] < 0)
+ xSizes[1] = 0;
+
+ g_App.CreateDragTarget();
+
+ COpenResult openRes;
+ bool needOpenArc = false;
+
+ UString fullPath = g_MainPath;
+ if (!fullPath.IsEmpty() /* && g_OpenArchive */)
+ {
+ if (!NFile::NName::IsAbsolutePath(fullPath))
+ {
+ FString fullPathF;
+ if (NFile::NName::GetFullPath(us2fs(fullPath), fullPathF))
+ fullPath = fs2us(fullPathF);
+ }
+ if (NFile::NFind::DoesFileExist_FollowLink(us2fs(fullPath)))
+ needOpenArc = true;
+ }
+
+ HRESULT res = g_App.Create(hWnd, fullPath, g_ArcFormat, xSizes,
+ needOpenArc,
+ openRes);
+
+ if (res == E_ABORT)
+ return -1;
+
+ if ((needOpenArc && !openRes.ArchiveIsOpened) || res != S_OK)
+ {
+ UString m ("Error");
+ if (res == S_FALSE || res == S_OK)
+ {
+ m = MyFormatNew(openRes.Encrypted ?
+ IDS_CANT_OPEN_ENCRYPTED_ARCHIVE :
+ IDS_CANT_OPEN_ARCHIVE,
+ fullPath);
+ }
+ else if (res != S_OK)
+ m = HResultToMessage(res);
+ if (!openRes.ErrorMessage.IsEmpty())
+ {
+ m.Add_LF();
+ m += openRes.ErrorMessage;
+ }
+ ErrorMessage(m);
+ return -1;
+ }
+
+ g_WindowWasCreated = true;
+
+ // g_SplitterPos = 0;
+
+ // ::DragAcceptFiles(hWnd, TRUE);
+ RegisterDragDrop(hWnd, g_App._dropTarget);
+
+ break;
+ }
+
+ case WM_DESTROY:
+ {
+ // ::DragAcceptFiles(hWnd, FALSE);
+ RevokeDragDrop(hWnd);
+ g_App._dropTarget.Release();
+
+ if (g_WindowWasCreated)
+ g_App.Save();
+
+ g_App.Release();
+
+ if (g_WindowWasCreated)
+ SaveWindowInfo(hWnd);
+
+ g_ExitEventLauncher.Exit(true);
+ PostQuitMessage(0);
+ break;
+ }
+
+ // case WM_MOVE: break;
+
+ case WM_LBUTTONDOWN:
+ g_StartCaptureMousePos = LOWORD(lParam);
+ g_StartCaptureSplitterPos = g_Splitter.GetPos();
+ ::SetCapture(hWnd);
+ break;
+
+ case WM_LBUTTONUP:
+ {
+ ::ReleaseCapture();
+ break;
+ }
+
+ case WM_MOUSEMOVE:
+ {
+ if ((wParam & MK_LBUTTON) != 0 && ::GetCapture() == hWnd)
+ {
+ g_Splitter.SetPos(hWnd, g_StartCaptureSplitterPos +
+ (short)LOWORD(lParam) - g_StartCaptureMousePos);
+ g_App.MoveSubWindows();
+ }
+ break;
+ }
+
+ case WM_SIZE:
+ {
+ if (g_CanChangeSplitter)
+ g_Splitter.SetPosFromRatio(hWnd);
+ else
+ {
+ g_Splitter.SetPos(hWnd, (int)g_SplitterPos );
+ g_CanChangeSplitter = true;
+ }
+
+ g_Maximized = (wParam == SIZE_MAXIMIZED) || (wParam == SIZE_MAXSHOW);
+
+ g_App.MoveSubWindows();
+ /*
+ int xSize = LOWORD(lParam);
+ int ySize = HIWORD(lParam);
+ // int xSplitter = 2;
+ int xWidth = g_SplitPos;
+ // int xSplitPos = xWidth;
+ g_Panel[0]._listView.MoveWindow(0, 0, xWidth, ySize);
+ g_Panel[1]._listView.MoveWindow(xSize - xWidth, 0, xWidth, ySize);
+ */
+ return 0;
+ // break;
+ }
+
+ case WM_SETFOCUS:
+ // g_App.SetFocus(g_App.LastFocusedPanel);
+ g_App.SetFocusToLastItem();
+ break;
+
+ /*
+ case WM_ACTIVATE:
+ {
+ int fActive = LOWORD(wParam);
+ switch (fActive)
+ {
+ case WA_INACTIVE:
+ {
+ // g_FocusIndex = g_App.LastFocusedPanel;
+ // g_App.LastFocusedPanel = g_App.GetFocusedPanelIndex();
+ // return 0;
+ }
+ }
+ break;
+ }
+ */
+
+ /*
+ case kLangWasChangedMessage:
+ MyLoadMenu();
+ return 0;
+ */
+
+ /*
+ case WM_SETTINGCHANGE:
+ break;
+ */
+
+ case WM_NOTIFY:
+ {
+ g_App.OnNotify((int)wParam, (LPNMHDR)lParam);
+ break;
+ }
+
+ /*
+ case WM_DROPFILES:
+ {
+ g_App.GetFocusedPanel().CompressDropFiles((HDROP)wParam);
+ return 0 ;
+ }
+ */
+ }
+ #ifndef _UNICODE
+ if (g_IsNT)
+ return DefWindowProcW(hWnd, message, wParam, lParam);
+ else
+ #endif
+ return DefWindowProc(hWnd, message, wParam, lParam);
+
+}
+
+static int Window_GetRealHeight(NWindows::CWindow &w)
+{
+ RECT rect;
+ w.GetWindowRect(&rect);
+ int res = RECT_SIZE_Y(rect);
+ #ifndef UNDER_CE
+ WINDOWPLACEMENT placement;
+ if (w.GetPlacement(&placement))
+ res += placement.rcNormalPosition.top;
+ #endif
+ return res;
+}
+
+void CApp::MoveSubWindows()
+{
+ HWND hWnd = _window;
+ RECT rect;
+ if (!hWnd)
+ return;
+ ::GetClientRect(hWnd, &rect);
+ int xSize = rect.right;
+ if (xSize == 0)
+ return;
+ int headerSize = 0;
+
+ #ifdef UNDER_CE
+ _commandBar.AutoSize();
+ {
+ _commandBar.Show(true); // maybe we need it for
+ headerSize += _commandBar.Height();
+ }
+ #endif
+
+ if (_toolBar)
+ {
+ _toolBar.AutoSize();
+ #ifdef UNDER_CE
+ int h2 = Window_GetRealHeight(_toolBar);
+ _toolBar.Move(0, headerSize, xSize, h2);
+ #endif
+ headerSize += Window_GetRealHeight(_toolBar);
+ }
+
+ int ySize = MyMax((int)(rect.bottom - headerSize), 0);
+
+ if (NumPanels > 1)
+ {
+ Panels[0].Move(0, headerSize, g_Splitter.GetPos(), ySize);
+ int xWidth1 = g_Splitter.GetPos() + kSplitterWidth;
+ Panels[1].Move(xWidth1, headerSize, xSize - xWidth1, ySize);
+ }
+ else
+ {
+ /*
+ int otherPanel = 1 - LastFocusedPanel;
+ if (PanelsCreated[otherPanel])
+ Panels[otherPanel].Move(0, headerSize, 0, ySize);
+ */
+ Panels[LastFocusedPanel].Move(0, headerSize, xSize, ySize);
+ }
+}
diff --git a/CPP/7zip/UI/FileManager/FM.dsp b/CPP/7zip/UI/FileManager/FM.dsp
new file mode 100644
index 0000000..1ae054d
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FM.dsp
@@ -0,0 +1,1667 @@
+# Microsoft Developer Studio Project File - Name="FM" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=FM - Win32 DebugU
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "FM.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "FM.mak" CFG="FM - Win32 DebugU"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "FM - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "FM - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE "FM - Win32 ReleaseU" (based on "Win32 (x86) Application")
+!MESSAGE "FM - Win32 DebugU" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "FM - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c
+# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /FAcs /Yu"StdAfx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zFM.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "FM - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /GZ /c
+# ADD CPP /nologo /Gz /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zFM.exe" /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "FM - Win32 ReleaseU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ReleaseU"
+# PROP BASE Intermediate_Dir "ReleaseU"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "ReleaseU"
+# PROP Intermediate_Dir "ReleaseU"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"StdAfx.h" /FD /c
+# ADD CPP /nologo /Gz /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zFM.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "FM - Win32 DebugU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "DebugU"
+# PROP BASE Intermediate_Dir "DebugU"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "DebugU"
+# PROP Intermediate_Dir "DebugU"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"StdAfx.h" /FD /GZ /c
+# ADD CPP /nologo /Gz /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /Yu"StdAfx.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib Mpr.lib htmlhelp.lib Urlmon.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zFM.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "FM - Win32 Release"
+# Name "FM - Win32 Debug"
+# Name "FM - Win32 ReleaseU"
+# Name "FM - Win32 DebugU"
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\7zipLogo.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\add.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ClassDefs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Copy.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Delete.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Extract.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\FM.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\Move.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\MyWindowsNew.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Parent.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Properties.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.rc
+# ADD BASE RSC /l 0x419
+# ADD RSC /l 0x409
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"StdAfx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Test.bmp
+# End Source File
+# End Group
+# Begin Group "Folders"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\AltStreamsFolder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\AltStreamsFolder.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FSDrives.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\FSDrives.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FSFolder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\FSFolder.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FSFolderCopy.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\IFolder.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\NetFolder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\NetFolder.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\RootFolder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\RootFolder.h
+# End Source File
+# End Group
+# Begin Group "Registry"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\RegistryAssociations.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\RegistryAssociations.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\RegistryPlugins.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\RegistryPlugins.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\RegistryUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\RegistryUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ViewSettings.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ViewSettings.h
+# End Source File
+# End Group
+# Begin Group "Panel"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\App.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\App.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\AppState.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\EnumFormatEtc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\EnumFormatEtc.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FileFolderPluginOpen.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\FileFolderPluginOpen.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Panel.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Panel.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\PanelCopy.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\PanelCrc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\PanelDrag.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\PanelFolderChange.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\PanelItemOpen.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\PanelItems.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\PanelKey.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\PanelListNotify.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\PanelMenu.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\PanelOperations.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\PanelSelect.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\PanelSort.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\PanelSplitFile.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\VerCtrl.cpp
+# End Source File
+# End Group
+# Begin Group "Dialog"
+
+# PROP Default_Filter ""
+# Begin Group "Options"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\EditPage.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\EditPage.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FoldersPage.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\FoldersPage.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\LangPage.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\LangPage.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\MenuPage.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\MenuPage.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\OptionsDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\SettingsPage.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\SettingsPage.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SystemPage.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\SystemPage.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\AboutDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\AboutDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\BrowseDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\BrowseDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ComboDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ComboDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=CopyDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=CopyDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\DialogSize.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\EditDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\EditDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\LinkDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\LinkDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ListViewDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ListViewDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=MessagesDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=MessagesDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=OverwriteDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=OverwriteDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\PasswordDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\PasswordDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ProgressDialog2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ProgressDialog2.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SplitDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\SplitDialog.h
+# End Source File
+# End Group
+# Begin Group "FM Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\ExtractCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FormatUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\FormatUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\HelpUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\HelpUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\LangUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\LangUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ProgramLocation.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ProgramLocation.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\UpdateCallback100.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\UpdateCallback100.h
+# End Source File
+# End Group
+# Begin Group "7-Zip Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\PropId.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\UniqBlocks.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\UniqBlocks.h
+# End Source File
+# End Group
+# Begin Group "C"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\DllSecur.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\DllSecur.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sort.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sort.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.h
+# End Source File
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Group "Control"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ComboBox.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ComboBox.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\CommandBar.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Dialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Dialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Edit.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ImageList.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ListView.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ListView.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ProgressBar.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\PropertyPage.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\PropertyPage.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ReBar.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Static.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\StatusBar.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ToolBar.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Window2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Window2.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Clipboard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Clipboard.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\COM.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\CommonDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\CommonDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Device.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileLink.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileMapping.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileSystem.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileSystem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Handle.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryGlobal.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryGlobal.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryLock.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryLock.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Menu.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Menu.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Net.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Net.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\NtCheck.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ProcessUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ProcessUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Registry.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Registry.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ResourceString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ResourceString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\SecurityUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\SecurityUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Shell.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Shell.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Thread.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\TimeUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\TimeUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Window.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Window.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\Common.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ComTry.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Defs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynamicBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynLimBuf.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynLimBuf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Exception.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Lang.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Lang.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyCom.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyInitGuid.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Random.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Random.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.h
+# End Source File
+# End Group
+# Begin Group "UI"
+
+# PROP Default_Filter ""
+# Begin Group "UI Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\Common\ArchiveExtractCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveOpenCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveOpenCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\CompressCall.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\CompressCall.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\DefaultName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\DefaultName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\DirItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\EnumDirItems.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\EnumDirItems.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ExitCode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ExtractingFilePath.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ExtractingFilePath.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ExtractMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\HashCalc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\HashCalc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\IFileExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\LoadCodecs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\LoadCodecs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\OpenArchive.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\OpenArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\Property.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\PropIDUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\PropIDUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\SetProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\SetProperties.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\SortUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\SortUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\StdAfx.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateAction.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateAction.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdatePair.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdatePair.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateProduce.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateProduce.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\WorkDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\WorkDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ZipRegistry.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ZipRegistry.h
+# End Source File
+# End Group
+# Begin Group "Agent"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\Agent\Agent.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\Agent.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\AgentOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\AgentProxy.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\AgentProxy.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\ArchiveFolder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\ArchiveFolderOpen.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\ArchiveFolderOut.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\IFolderArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\UpdateCallbackAgent.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Agent\UpdateCallbackAgent.h
+# End Source File
+# End Group
+# Begin Group "Explorer"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\Explorer\ContextMenu.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Explorer\ContextMenu.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Explorer\ContextMenuFlags.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Explorer\MyExplorerCommand.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Explorer\MyMessages.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Explorer\MyMessages.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Explorer\RegistryContextMenu.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Explorer\RegistryContextMenu.h
+# End Source File
+# End Group
+# Begin Group "GUI"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\GUI\HashGUI.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\GUI\HashGUI.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\GUI\UpdateCallbackGUI2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\GUI\UpdateCallbackGUI2.h
+# End Source File
+# End Group
+# End Group
+# Begin Group "Compress"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.h
+# End Source File
+# End Group
+# Begin Group "Interface"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\IArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ICoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IDecl.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IPassword.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IProgress.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\PropID.h
+# End Source File
+# End Group
+# Begin Group "ArchiveCommon"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\7zFM.exe.manifest
+# End Source File
+# Begin Source File
+
+SOURCE=.\7zipLogo.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\Add2.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Copy2.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Delete2.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Extract2.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\FilePlugins.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\FilePlugins.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FM.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Info.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Info2.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\Move2.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\MyCom2.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\MyLoadMenu.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\MyLoadMenu.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\OpenCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\OpenCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\PluginInterface.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\PluginLoader.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\PropertyName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\PropertyName.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SplitUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\SplitUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\StringUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\StringUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\SysIconUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\SysIconUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\Test2.bmp
+# End Source File
+# Begin Source File
+
+SOURCE=.\TextPairs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\TextPairs.h
+# End Source File
+# End Target
+# End Project
diff --git a/CPP/7zip/UI/FileManager/FM.dsw b/CPP/7zip/UI/FileManager/FM.dsw
new file mode 100644
index 0000000..1c955d9
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FM.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "FM"=.\FM.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/UI/FileManager/FM.ico b/CPP/7zip/UI/FileManager/FM.ico
new file mode 100644
index 0000000..3a0a34d
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FM.ico
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/FM.mak b/CPP/7zip/UI/FileManager/FM.mak
new file mode 100644
index 0000000..8331285
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FM.mak
@@ -0,0 +1,100 @@
+CFLAGS = $(CFLAGS) \
+ -DZ7_LANG \
+
+!IFDEF UNDER_CE
+LIBS = $(LIBS) ceshell.lib Commctrl.lib
+!ELSE
+LIBS = $(LIBS) comctl32.lib htmlhelp.lib comdlg32.lib Mpr.lib Gdi32.lib
+CFLAGS = $(CFLAGS) -DZ7_LONG_PATH -DZ7_DEVICE_FILE
+LFLAGS = $(LFLAGS) /DELAYLOAD:mpr.dll
+LIBS = $(LIBS) delayimp.lib
+!ENDIF
+
+FM_OBJS = \
+ $O\App.obj \
+ $O\BrowseDialog.obj \
+ $O\ClassDefs.obj \
+ $O\EnumFormatEtc.obj \
+ $O\ExtractCallback.obj \
+ $O\FileFolderPluginOpen.obj \
+ $O\FilePlugins.obj \
+ $O\FM.obj \
+ $O\FoldersPage.obj \
+ $O\FormatUtils.obj \
+ $O\FSFolder.obj \
+ $O\FSFolderCopy.obj \
+ $O\HelpUtils.obj \
+ $O\LangUtils.obj \
+ $O\MenuPage.obj \
+ $O\MyLoadMenu.obj \
+ $O\OpenCallback.obj \
+ $O\OptionsDialog.obj \
+ $O\Panel.obj \
+ $O\PanelCopy.obj \
+ $O\PanelCrc.obj \
+ $O\PanelDrag.obj \
+ $O\PanelFolderChange.obj \
+ $O\PanelItemOpen.obj \
+ $O\PanelItems.obj \
+ $O\PanelKey.obj \
+ $O\PanelListNotify.obj \
+ $O\PanelMenu.obj \
+ $O\PanelOperations.obj \
+ $O\PanelSelect.obj \
+ $O\PanelSort.obj \
+ $O\PanelSplitFile.obj \
+ $O\ProgramLocation.obj \
+ $O\PropertyName.obj \
+ $O\RegistryAssociations.obj \
+ $O\RegistryUtils.obj \
+ $O\RootFolder.obj \
+ $O\SplitUtils.obj \
+ $O\StringUtils.obj \
+ $O\SysIconUtils.obj \
+ $O\TextPairs.obj \
+ $O\UpdateCallback100.obj \
+ $O\ViewSettings.obj \
+ $O\AboutDialog.obj \
+ $O\ComboDialog.obj \
+ $O\CopyDialog.obj \
+ $O\EditDialog.obj \
+ $O\EditPage.obj \
+ $O\LangPage.obj \
+ $O\ListViewDialog.obj \
+ $O\MessagesDialog.obj \
+ $O\OverwriteDialog.obj \
+ $O\PasswordDialog.obj \
+ $O\ProgressDialog2.obj \
+ $O\SettingsPage.obj \
+ $O\SplitDialog.obj \
+ $O\SystemPage.obj \
+ $O\VerCtrl.obj \
+
+!IFNDEF UNDER_CE
+
+FM_OBJS = $(FM_OBJS) \
+ $O\AltStreamsFolder.obj \
+ $O\FSDrives.obj \
+ $O\LinkDialog.obj \
+ $O\NetFolder.obj \
+
+WIN_OBJS = $(WIN_OBJS) \
+ $O\FileSystem.obj \
+ $O\Net.obj \
+ $O\SecurityUtils.obj \
+
+!ENDIF
+
+C_OBJS = $(C_OBJS) \
+ $O\DllSecur.obj \
+
+AGENT_OBJS = \
+ $O\Agent.obj \
+ $O\AgentOut.obj \
+ $O\AgentProxy.obj \
+ $O\ArchiveFolder.obj \
+ $O\ArchiveFolderOpen.obj \
+ $O\ArchiveFolderOut.obj \
+ $O\UpdateCallbackAgent.obj \
+
+# we need empty line after last line above
diff --git a/CPP/7zip/UI/FileManager/FSDrives.cpp b/CPP/7zip/UI/FileManager/FSDrives.cpp
new file mode 100644
index 0000000..985d7c4
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FSDrives.cpp
@@ -0,0 +1,518 @@
+// FSDrives.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Alloc.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/Defs.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileIO.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/FileSystem.h"
+#include "../../../Windows/PropVariant.h"
+
+#include "../../PropID.h"
+
+#include "FSDrives.h"
+#include "FSFolder.h"
+#include "LangUtils.h"
+#include "SysIconUtils.h"
+
+#include "resource.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NFind;
+
+static const char * const kVolPrefix = "\\\\.\\";
+static const char * const kSuperPrefix = "\\\\?\\";
+
+FString CDriveInfo::GetDeviceFileIoName() const
+{
+ FString f (kVolPrefix);
+ f += Name;
+ return f;
+}
+
+struct CPhysTempBuffer
+{
+ void *buffer;
+ CPhysTempBuffer(): buffer(NULL) {}
+ ~CPhysTempBuffer() { MidFree(buffer); }
+};
+
+static HRESULT CopyFileSpec(CFSTR fromPath, CFSTR toPath, bool writeToDisk, UInt64 fileSize,
+ UInt32 bufferSize, UInt64 progressStart, IProgress *progress)
+{
+ NIO::CInFile inFile;
+ if (!inFile.Open(fromPath))
+ return GetLastError_noZero_HRESULT();
+ if (fileSize == (UInt64)(Int64)-1)
+ {
+ if (!inFile.GetLength(fileSize))
+ return GetLastError_noZero_HRESULT();
+ }
+
+ NIO::COutFile outFile;
+ if (writeToDisk)
+ {
+ if (!outFile.Open(toPath, FILE_SHARE_WRITE, OPEN_EXISTING, 0))
+ return GetLastError_noZero_HRESULT();
+ }
+ else
+ if (!outFile.Create(toPath, true))
+ return GetLastError_noZero_HRESULT();
+
+ CPhysTempBuffer tempBuffer;
+ tempBuffer.buffer = MidAlloc(bufferSize);
+ if (!tempBuffer.buffer)
+ return E_OUTOFMEMORY;
+
+ for (UInt64 pos = 0; pos < fileSize;)
+ {
+ UInt64 progressCur = progressStart + pos;
+ RINOK(progress->SetCompleted(&progressCur))
+ UInt64 rem = fileSize - pos;
+ UInt32 curSize = (UInt32)MyMin(rem, (UInt64)bufferSize);
+ UInt32 processedSize;
+ if (!inFile.Read(tempBuffer.buffer, curSize, processedSize))
+ return GetLastError_noZero_HRESULT();
+ if (processedSize == 0)
+ break;
+ curSize = processedSize;
+ if (writeToDisk)
+ {
+ const UInt32 kMask = 0x1FF;
+ curSize = (curSize + kMask) & ~kMask;
+ if (curSize > bufferSize)
+ return E_FAIL;
+ }
+
+ if (!outFile.Write(tempBuffer.buffer, curSize, processedSize))
+ return GetLastError_noZero_HRESULT();
+ if (curSize != processedSize)
+ return E_FAIL;
+ pos += curSize;
+ }
+
+ return S_OK;
+}
+
+static const Byte kProps[] =
+{
+ kpidName,
+ // kpidOutName,
+ kpidTotalSize,
+ kpidFreeSpace,
+ kpidType,
+ kpidVolumeName,
+ kpidFileSystem,
+ kpidClusterSize
+};
+
+static const char * const kDriveTypes[] =
+{
+ "Unknown"
+ , "No Root Dir"
+ , "Removable"
+ , "Fixed"
+ , "Remote"
+ , "CD-ROM"
+ , "RAM disk"
+};
+
+Z7_COM7F_IMF(CFSDrives::LoadItems())
+{
+ _drives.Clear();
+
+ FStringVector driveStrings;
+ MyGetLogicalDriveStrings(driveStrings);
+
+ FOR_VECTOR (i, driveStrings)
+ {
+ CDriveInfo di;
+
+ const FString &driveName = driveStrings[i];
+
+ di.FullSystemName = driveName;
+ if (!driveName.IsEmpty())
+ di.Name.SetFrom(driveName, driveName.Len() - 1);
+ di.ClusterSize = 0;
+ di.DriveSize = 0;
+ di.FreeSpace = 0;
+ di.DriveType = NSystem::MyGetDriveType(driveName);
+ bool needRead = true;
+
+ if (di.DriveType == DRIVE_CDROM || di.DriveType == DRIVE_REMOVABLE)
+ {
+ /*
+ DWORD dwSerialNumber;`
+ if (!::GetVolumeInformation(di.FullSystemName,
+ NULL, 0, &dwSerialNumber, NULL, NULL, NULL, 0))
+ */
+ {
+ needRead = false;
+ }
+ }
+
+ if (needRead)
+ {
+ DWORD volumeSerialNumber, maximumComponentLength, fileSystemFlags;
+ NSystem::MyGetVolumeInformation(driveName,
+ di.VolumeName,
+ &volumeSerialNumber, &maximumComponentLength, &fileSystemFlags,
+ di.FileSystemName);
+
+ NSystem::MyGetDiskFreeSpace(driveName,
+ di.ClusterSize, di.DriveSize, di.FreeSpace);
+ di.KnownSizes = true;
+ di.KnownSize = true;
+ }
+
+ _drives.Add(di);
+ }
+
+ if (_volumeMode)
+ {
+ // we must use IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS
+ for (unsigned n = 0; n < 16; n++) // why 16 ?
+ {
+ FString name ("PhysicalDrive");
+ name.Add_UInt32(n);
+
+ FString fullPath (kVolPrefix);
+ fullPath += name;
+
+ CFileInfo fi;
+ if (!fi.Find(fullPath))
+ continue;
+
+ CDriveInfo di;
+ di.Name = name;
+ di.FullSystemName = fullPath;
+ di.ClusterSize = 0;
+ di.DriveSize = fi.Size;
+ di.FreeSpace = 0;
+ di.DriveType = 0;
+
+ di.IsPhysicalDrive = true;
+ di.KnownSize = true;
+
+ _drives.Add(di);
+ }
+ }
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFSDrives::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _drives.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFSDrives::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value))
+{
+ if (itemIndex >= (UInt32)_drives.Size())
+ return E_INVALIDARG;
+ NCOM::CPropVariant prop;
+ const CDriveInfo &di = _drives[itemIndex];
+ switch (propID)
+ {
+ case kpidIsDir: prop = !_volumeMode; break;
+ case kpidName: prop = fs2us(di.Name); break;
+ case kpidOutName:
+ if (!di.Name.IsEmpty() && di.Name.Back() == ':')
+ {
+ FString s = di.Name;
+ s.DeleteBack();
+ AddExt(s, itemIndex);
+ prop = fs2us(s);
+ }
+ break;
+
+ case kpidTotalSize: if (di.KnownSize) prop = di.DriveSize; break;
+ case kpidFreeSpace: if (di.KnownSizes) prop = di.FreeSpace; break;
+ case kpidClusterSize: if (di.KnownSizes) prop = di.ClusterSize; break;
+ case kpidType:
+ if (di.DriveType < Z7_ARRAY_SIZE(kDriveTypes))
+ prop = kDriveTypes[di.DriveType];
+ break;
+ case kpidVolumeName: prop = di.VolumeName; break;
+ case kpidFileSystem: prop = di.FileSystemName; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+HRESULT CFSDrives::BindToFolderSpec(CFSTR name, IFolderFolder **resultFolder)
+{
+ *resultFolder = NULL;
+ if (_volumeMode)
+ return S_OK;
+ NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder;
+ CMyComPtr<IFolderFolder> subFolder = fsFolderSpec;
+ FString path;
+ if (_superMode)
+ path = kSuperPrefix;
+ path += name;
+ RINOK(fsFolderSpec->Init(path))
+ *resultFolder = subFolder.Detach();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFSDrives::BindToFolder(UInt32 index, IFolderFolder **resultFolder))
+{
+ *resultFolder = NULL;
+ if (index >= (UInt32)_drives.Size())
+ return E_INVALIDARG;
+ const CDriveInfo &di = _drives[index];
+ /*
+ if (_volumeMode)
+ {
+ *resultFolder = 0;
+ CPhysDriveFolder *folderSpec = new CPhysDriveFolder;
+ CMyComPtr<IFolderFolder> subFolder = folderSpec;
+ RINOK(folderSpec->Init(di.Name));
+ *resultFolder = subFolder.Detach();
+ return S_OK;
+ }
+ */
+ return BindToFolderSpec(di.FullSystemName, resultFolder);
+}
+
+Z7_COM7F_IMF(CFSDrives::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder))
+{
+ return BindToFolderSpec(us2fs(name), resultFolder);
+}
+
+Z7_COM7F_IMF(CFSDrives::BindToParentFolder(IFolderFolder **resultFolder))
+{
+ *resultFolder = NULL;
+ return S_OK;
+}
+
+IMP_IFolderFolder_Props(CFSDrives)
+
+Z7_COM7F_IMF(CFSDrives::GetFolderProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidType: prop = "FSDrives"; break;
+ case kpidPath:
+ if (_volumeMode)
+ prop = kVolPrefix;
+ else if (_superMode)
+ prop = kSuperPrefix;
+ else
+ prop = (UString)LangString(IDS_COMPUTER) + WCHAR_PATH_SEPARATOR;
+ break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+
+Z7_COM7F_IMF(CFSDrives::GetSystemIconIndex(UInt32 index, Int32 *iconIndex))
+{
+ *iconIndex = 0;
+ const CDriveInfo &di = _drives[index];
+ if (di.IsPhysicalDrive)
+ return S_OK;
+ int iconIndexTemp;
+ if (GetRealIconIndex(di.FullSystemName, 0, iconIndexTemp) != 0)
+ {
+ *iconIndex = iconIndexTemp;
+ return S_OK;
+ }
+ return GetLastError_noZero_HRESULT();
+}
+
+void CFSDrives::AddExt(FString &s, unsigned index) const
+{
+ s.Add_Dot();
+ const CDriveInfo &di = _drives[index];
+ UString n = di.FileSystemName;
+ n.MakeLower_Ascii();
+ const char *ext;
+ if (di.DriveType == DRIVE_CDROM)
+ ext = "iso";
+ else
+ {
+ unsigned i;
+ for (i = 0; i < n.Len(); i++)
+ {
+ const wchar_t c = n[i];
+ if (c < 'a' || c > 'z')
+ break;
+ }
+ if (i != 0)
+ {
+ n.DeleteFrom(i);
+ s += us2fs(n);
+ return;
+ }
+ ext = "img";
+ }
+ /*
+ if (n.IsPrefixedBy_Ascii_NoCase("NTFS")) ext = "ntfs";
+ else if (n.IsPrefixedBy_Ascii_NoCase("UDF")) ext = "udf";
+ else if (n.IsPrefixedBy_Ascii_NoCase("exFAT")) ext = "exfat";
+ */
+ s += ext;
+}
+
+HRESULT CFSDrives::GetFileSize(unsigned index, UInt64& fileSize) const
+{
+#ifdef Z7_DEVICE_FILE
+ NIO::CInFile inFile;
+ if (!inFile.Open(_drives[index].GetDeviceFileIoName()))
+ return GetLastError_noZero_HRESULT();
+ if (inFile.SizeDefined)
+ {
+ fileSize = inFile.Size;
+ return S_OK;
+ }
+#else
+ UNUSED_VAR(index)
+#endif
+ fileSize = 0;
+ return E_FAIL;
+}
+
+Z7_COM7F_IMF(CFSDrives::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems,
+ Int32 /* includeAltStreams */, Int32 /* replaceAltStreamColon */,
+ const wchar_t *path, IFolderOperationsExtractCallback *callback))
+{
+ if (numItems == 0)
+ return S_OK;
+
+ if (moveMode)
+ return E_NOTIMPL;
+
+ if (!_volumeMode)
+ return E_NOTIMPL;
+
+ UInt64 totalSize = 0;
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const CDriveInfo &di = _drives[indices[i]];
+ if (di.KnownSize)
+ totalSize += di.DriveSize;
+ }
+ RINOK(callback->SetTotal(totalSize))
+ RINOK(callback->SetNumFiles(numItems))
+
+ FString destPath = us2fs(path);
+ if (destPath.IsEmpty())
+ return E_INVALIDARG;
+
+ bool isAltDest = NName::IsAltPathPrefix(destPath);
+ bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back()));
+
+ if (isDirectPath)
+ {
+ if (numItems > 1)
+ return E_INVALIDARG;
+ }
+
+ UInt64 completedSize = 0;
+ RINOK(callback->SetCompleted(&completedSize))
+ for (i = 0; i < numItems; i++)
+ {
+ unsigned index = indices[i];
+ const CDriveInfo &di = _drives[index];
+ FString destPath2 = destPath;
+
+ if (!isDirectPath)
+ {
+ FString destName = di.Name;
+ if (!destName.IsEmpty() && destName.Back() == ':')
+ {
+ destName.DeleteBack();
+ AddExt(destName, index);
+ }
+ destPath2 += destName;
+ }
+
+ FString srcPath = di.GetDeviceFileIoName();
+
+ UInt64 fileSize = 0;
+ if (GetFileSize(index, fileSize) != S_OK)
+ {
+ return E_FAIL;
+ }
+ if (!di.KnownSize)
+ {
+ totalSize += fileSize;
+ RINOK(callback->SetTotal(totalSize))
+ }
+
+ Int32 writeAskResult;
+ CMyComBSTR destPathResult;
+ RINOK(callback->AskWrite(fs2us(srcPath), BoolToInt(false), NULL, &fileSize,
+ fs2us(destPath2), &destPathResult, &writeAskResult))
+
+ if (!IntToBool(writeAskResult))
+ {
+ if (totalSize >= fileSize)
+ totalSize -= fileSize;
+ RINOK(callback->SetTotal(totalSize))
+ continue;
+ }
+
+ RINOK(callback->SetCurrentFilePath(fs2us(srcPath)))
+
+ const UInt32 kBufferSize = (4 << 20);
+ const UInt32 bufferSize = (di.DriveType == DRIVE_REMOVABLE) ? (18 << 10) * 4 : kBufferSize;
+ RINOK(CopyFileSpec(srcPath, us2fs(destPathResult), false, fileSize, bufferSize, completedSize, callback))
+ completedSize += fileSize;
+ }
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFSDrives::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */,
+ const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */))
+{
+ return E_NOTIMPL;
+}
+
+Z7_COM7F_IMF(CFSDrives::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */))
+{
+ return E_NOTIMPL;
+}
+
+Z7_COM7F_IMF(CFSDrives::CreateFolder(const wchar_t * /* name */, IProgress * /* progress */))
+{
+ return E_NOTIMPL;
+}
+
+Z7_COM7F_IMF(CFSDrives::CreateFile(const wchar_t * /* name */, IProgress * /* progress */))
+{
+ return E_NOTIMPL;
+}
+
+Z7_COM7F_IMF(CFSDrives::Rename(UInt32 /* index */, const wchar_t * /* newName */, IProgress * /* progress */))
+{
+ return E_NOTIMPL;
+}
+
+Z7_COM7F_IMF(CFSDrives::Delete(const UInt32 * /* indices */, UInt32 /* numItems */, IProgress * /* progress */))
+{
+ return E_NOTIMPL;
+}
+
+Z7_COM7F_IMF(CFSDrives::SetProperty(UInt32 /* index */, PROPID /* propID */,
+ const PROPVARIANT * /* value */, IProgress * /* progress */))
+{
+ return E_NOTIMPL;
+}
diff --git a/CPP/7zip/UI/FileManager/FSDrives.h b/CPP/7zip/UI/FileManager/FSDrives.h
new file mode 100644
index 0000000..8ae831c
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FSDrives.h
@@ -0,0 +1,52 @@
+// FSDrives.h
+
+#ifndef ZIP7_INC_FS_DRIVES_H
+#define ZIP7_INC_FS_DRIVES_H
+
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyString.h"
+
+#include "IFolder.h"
+
+struct CDriveInfo
+{
+ FString Name;
+ FString FullSystemName;
+ UInt64 DriveSize;
+ UInt64 FreeSpace;
+ UInt64 ClusterSize;
+ // UString Type;
+ UString VolumeName;
+ UString FileSystemName;
+ UINT DriveType;
+
+ bool KnownSize;
+ bool KnownSizes;
+ bool IsPhysicalDrive;
+
+ FString GetDeviceFileIoName() const;
+ CDriveInfo(): KnownSize(false), KnownSizes(false), IsPhysicalDrive(false) {}
+};
+
+Z7_CLASS_IMP_NOQIB_3(
+ CFSDrives
+ , IFolderFolder
+ , IFolderOperations
+ , IFolderGetSystemIconIndex
+)
+ CObjectVector<CDriveInfo> _drives;
+ bool _volumeMode;
+ bool _superMode;
+
+ HRESULT BindToFolderSpec(CFSTR name, IFolderFolder **resultFolder);
+ void AddExt(FString &s, unsigned index) const;
+ HRESULT GetFileSize(unsigned index, UInt64 &fileSize) const;
+public:
+ void Init(bool volMode = false, bool superMode = false)
+ {
+ _volumeMode = volMode;
+ _superMode = superMode;
+ }
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/FSFolder.cpp b/CPP/7zip/UI/FileManager/FSFolder.cpp
new file mode 100644
index 0000000..06c572d
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FSFolder.cpp
@@ -0,0 +1,1200 @@
+// FSFolder.cpp
+
+#include "StdAfx.h"
+
+#ifdef __MINGW32_VERSION
+// #if !defined(_MSC_VER) && (__GNUC__) && (__GNUC__ < 10)
+// for old mingw
+#include <ddk/ntddk.h>
+#else
+#ifndef Z7_OLD_WIN_SDK
+ #if !defined(_M_IA64)
+ #include <winternl.h>
+ #endif
+#else
+typedef LONG NTSTATUS;
+typedef struct _IO_STATUS_BLOCK {
+ union {
+ NTSTATUS Status;
+ PVOID Pointer;
+ };
+ ULONG_PTR Information;
+} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
+#endif
+#endif
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/Defs.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/UTFConvert.h"
+
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileIO.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/PropVariant.h"
+
+#include "../../PropID.h"
+
+#include "FSDrives.h"
+#include "FSFolder.h"
+
+#ifndef UNDER_CE
+#include "NetFolder.h"
+#endif
+
+#include "SysIconUtils.h"
+
+#if _WIN32_WINNT < 0x0501
+#ifdef _APISETFILE_
+// Windows SDK 8.1 defines in fileapi.h the function GetCompressedFileSizeW only if _WIN32_WINNT >= 0x0501
+// But real support version for that function is NT 3.1 (probably)
+// So we must define GetCompressedFileSizeW
+EXTERN_C_BEGIN
+WINBASEAPI DWORD WINAPI GetCompressedFileSizeW(LPCWSTR lpFileName, LPDWORD lpFileSizeHigh);
+EXTERN_C_END
+#endif
+#endif
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NFind;
+using namespace NDir;
+using namespace NName;
+
+#ifndef USE_UNICODE_FSTRING
+int CompareFileNames_ForFolderList(const FChar *s1, const FChar *s2)
+{
+ return CompareFileNames_ForFolderList(fs2us(s1), fs2us(s2));
+}
+#endif
+
+namespace NFsFolder {
+
+static const Byte kProps[] =
+{
+ kpidName,
+ kpidSize,
+ kpidMTime,
+ kpidCTime,
+ kpidATime,
+ #ifdef FS_SHOW_LINKS_INFO
+ kpidChangeTime,
+ #endif
+ kpidAttrib,
+ kpidPackSize,
+ #ifdef FS_SHOW_LINKS_INFO
+ kpidINode,
+ kpidLinks,
+ #endif
+ kpidComment,
+ kpidNumSubDirs,
+ kpidNumSubFiles,
+ kpidPrefix
+};
+
+HRESULT CFSFolder::Init(const FString &path /* , IFolderFolder *parentFolder */)
+{
+ // _parentFolder = parentFolder;
+ _path = path;
+
+ #ifdef _WIN32
+
+ _findChangeNotification.FindFirst(_path, false,
+ FILE_NOTIFY_CHANGE_FILE_NAME
+ | FILE_NOTIFY_CHANGE_DIR_NAME
+ | FILE_NOTIFY_CHANGE_ATTRIBUTES
+ | FILE_NOTIFY_CHANGE_SIZE
+ | FILE_NOTIFY_CHANGE_LAST_WRITE
+ /*
+ | FILE_NOTIFY_CHANGE_LAST_ACCESS
+ | FILE_NOTIFY_CHANGE_CREATION
+ | FILE_NOTIFY_CHANGE_SECURITY
+ */
+ );
+
+ if (!_findChangeNotification.IsHandleAllocated())
+ {
+ const HRESULT lastError = GetLastError_noZero_HRESULT();
+ CFindFile findFile;
+ CFileInfo fi;
+ FString path2 = _path;
+ path2 += '*'; // CHAR_ANY_MASK;
+ if (!findFile.FindFirst(path2, fi))
+ return lastError;
+ }
+
+ #endif
+
+ return S_OK;
+}
+
+
+HRESULT CFsFolderStat::Enumerate()
+{
+ if (Progress)
+ {
+ RINOK(Progress->SetCompleted(NULL))
+ }
+ Path.Add_PathSepar();
+ const unsigned len = Path.Len();
+ CEnumerator enumerator;
+ enumerator.SetDirPrefix(Path);
+ CDirEntry fi;
+ while (enumerator.Next(fi))
+ {
+ if (fi.IsDir())
+ {
+ NumFolders++;
+ Path.DeleteFrom(len);
+ Path += fi.Name;
+ RINOK(Enumerate())
+ }
+ else
+ {
+ NumFiles++;
+ Size += fi.Size;
+ }
+ }
+ return S_OK;
+}
+
+#ifndef UNDER_CE
+
+bool MyGetCompressedFileSizeW(CFSTR path, UInt64 &size);
+bool MyGetCompressedFileSizeW(CFSTR path, UInt64 &size)
+{
+ DWORD highPart;
+ DWORD lowPart = INVALID_FILE_SIZE;
+ IF_USE_MAIN_PATH
+ {
+ lowPart = ::GetCompressedFileSizeW(fs2us(path), &highPart);
+ if (lowPart != INVALID_FILE_SIZE || ::GetLastError() == NO_ERROR)
+ {
+ size = ((UInt64)highPart << 32) | lowPart;
+ return true;
+ }
+ }
+ #ifdef Z7_LONG_PATH
+ if (USE_SUPER_PATH)
+ {
+ UString superPath;
+ if (GetSuperPath(path, superPath, USE_MAIN_PATH))
+ {
+ lowPart = ::GetCompressedFileSizeW(superPath, &highPart);
+ if (lowPart != INVALID_FILE_SIZE || ::GetLastError() == NO_ERROR)
+ {
+ size = ((UInt64)highPart << 32) | lowPart;
+ return true;
+ }
+ }
+ }
+ #endif
+ return false;
+}
+
+#endif
+
+HRESULT CFSFolder::LoadSubItems(int dirItem, const FString &relPrefix)
+{
+ const unsigned startIndex = Folders.Size();
+ {
+ CEnumerator enumerator;
+ enumerator.SetDirPrefix(_path + relPrefix);
+ CDirItem fi;
+ fi.FolderStat_Defined = false;
+ fi.NumFolders = 0;
+ fi.NumFiles = 0;
+ fi.Parent = dirItem;
+
+ while (enumerator.Next(fi))
+ {
+ if (fi.IsDir())
+ {
+ fi.Size = 0;
+ if (_flatMode)
+ Folders.Add(relPrefix + fi.Name + FCHAR_PATH_SEPARATOR);
+ }
+ else
+ {
+ /*
+ fi.PackSize_Defined = true;
+ if (!MyGetCompressedFileSizeW(_path + relPrefix + fi.Name, fi.PackSize))
+ fi.PackSize = fi.Size;
+ */
+ }
+
+ #ifndef UNDER_CE
+
+ fi.Reparse.Free();
+ fi.PackSize_Defined = false;
+
+ #ifdef FS_SHOW_LINKS_INFO
+ fi.FileInfo_Defined = false;
+ fi.FileInfo_WasRequested = false;
+ fi.FileIndex = 0;
+ fi.NumLinks = 0;
+ fi.ChangeTime_Defined = false;
+ fi.ChangeTime_WasRequested = false;
+ #endif
+
+ fi.PackSize = fi.Size;
+
+ #ifdef FS_SHOW_LINKS_INFO
+ if (fi.HasReparsePoint())
+ {
+ fi.FileInfo_WasRequested = true;
+ BY_HANDLE_FILE_INFORMATION info;
+ NIO::GetReparseData(_path + relPrefix + fi.Name, fi.Reparse, &info);
+ fi.NumLinks = info.nNumberOfLinks;
+ fi.FileIndex = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow;
+ fi.FileInfo_Defined = true;
+ }
+ #endif
+
+ #endif // UNDER_CE
+
+ /* unsigned fileIndex = */ Files.Add(fi);
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ /*
+ if (_scanAltStreams)
+ {
+ CStreamEnumerator enumerator(_path + relPrefix + fi.Name);
+ CStreamInfo si;
+ for (;;)
+ {
+ bool found;
+ if (!enumerator.Next(si, found))
+ {
+ // if (GetLastError() == ERROR_ACCESS_DENIED)
+ // break;
+ // return E_FAIL;
+ break;
+ }
+ if (!found)
+ break;
+ if (si.IsMainStream())
+ continue;
+ CAltStream ss;
+ ss.Parent = fileIndex;
+ ss.Name = si.GetReducedName();
+ ss.Size = si.Size;
+ ss.PackSize_Defined = false;
+ ss.PackSize = si.Size;
+ Streams.Add(ss);
+ }
+ }
+ */
+ #endif
+ }
+ }
+ if (!_flatMode)
+ return S_OK;
+
+ const unsigned endIndex = Folders.Size();
+ for (unsigned i = startIndex; i < endIndex; i++)
+ LoadSubItems((int)i, Folders[i]);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFSFolder::LoadItems())
+{
+ Int32 dummy;
+ WasChanged(&dummy);
+ Clear();
+ RINOK(LoadSubItems(-1, FString()))
+ _commentsAreLoaded = false;
+ return S_OK;
+}
+
+static CFSTR const kDescriptionFileName = FTEXT("descript.ion");
+
+bool CFSFolder::LoadComments()
+{
+ _comments.Clear();
+ _commentsAreLoaded = true;
+ NIO::CInFile file;
+ if (!file.Open(_path + kDescriptionFileName))
+ return false;
+ UInt64 len;
+ if (!file.GetLength(len))
+ return false;
+ if (len >= (1 << 28))
+ return false;
+ AString s;
+ char *p = s.GetBuf((unsigned)(size_t)len);
+ size_t processedSize;
+ if (!file.ReadFull(p, (unsigned)(size_t)len, processedSize))
+ return false;
+ s.ReleaseBuf_CalcLen((unsigned)(size_t)len);
+ if (processedSize != len)
+ return false;
+ file.Close();
+ UString unicodeString;
+ if (!ConvertUTF8ToUnicode(s, unicodeString))
+ return false;
+ return _comments.ReadFromString(unicodeString);
+}
+
+bool CFSFolder::SaveComments()
+{
+ AString utf;
+ {
+ UString unicode;
+ _comments.SaveToString(unicode);
+ ConvertUnicodeToUTF8(unicode, utf);
+ }
+ if (!utf.IsAscii())
+ utf.Insert(0, "\xEF\xBB\xBF" "\r\n");
+
+ FString path = _path + kDescriptionFileName;
+ // We must set same attrib. COutFile::CreateAlways can fail, if file has another attrib.
+ DWORD attrib = FILE_ATTRIBUTE_NORMAL;
+ {
+ CFileInfo fi;
+ if (fi.Find(path))
+ attrib = fi.Attrib;
+ }
+ NIO::COutFile file;
+ if (!file.CreateAlways(path, attrib))
+ return false;
+ UInt32 processed;
+ file.Write(utf, utf.Len(), processed);
+ _commentsAreLoaded = false;
+ return true;
+}
+
+Z7_COM7F_IMF(CFSFolder::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = Files.Size() /* + Streams.Size() */;
+ return S_OK;
+}
+
+#ifdef USE_UNICODE_FSTRING
+
+Z7_COM7F_IMF(CFSFolder::GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len))
+{
+ *name = NULL;
+ *len = 0;
+ /*
+ if (index >= Files.Size())
+ index = Streams[index - Files.Size()].Parent;
+ */
+ CDirItem &fi = Files[index];
+ if (fi.Parent >= 0)
+ {
+ const FString &fo = Folders[fi.Parent];
+ USE_UNICODE_FSTRING
+ *name = fo;
+ *len = fo.Len();
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFSFolder::GetItemName(UInt32 index, const wchar_t **name, unsigned *len))
+{
+ *name = NULL;
+ *len = 0;
+ if (index < Files.Size())
+ {
+ CDirItem &fi = Files[index];
+ *name = fi.Name;
+ *len = fi.Name.Len();
+ return S_OK;
+ }
+ else
+ {
+ // const CAltStream &ss = Streams[index - Files.Size()];
+ // *name = ss.Name;
+ // *len = ss.Name.Len();
+ //
+ // change it;
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF2(UInt64, CFSFolder::GetItemSize(UInt32 index))
+{
+ /*
+ if (index >= Files.Size())
+ return Streams[index - Files.Size()].Size;
+ */
+ CDirItem &fi = Files[index];
+ return fi.IsDir() ? 0 : fi.Size;
+}
+
+#endif
+
+
+#ifdef FS_SHOW_LINKS_INFO
+
+bool CFSFolder::ReadFileInfo(CDirItem &di)
+{
+ di.FileInfo_WasRequested = true;
+ BY_HANDLE_FILE_INFORMATION info;
+ memset(&info, 0, sizeof(info)); // for vc6-O2
+ if (!NIO::CFileBase::GetFileInformation(_path + GetRelPath(di), &info))
+ return false;
+ di.NumLinks = info.nNumberOfLinks;
+ di.FileIndex = (((UInt64)info.nFileIndexHigh) << 32) + info.nFileIndexLow;
+ di.FileInfo_Defined = true;
+ return true;
+}
+
+
+EXTERN_C_BEGIN
+
+typedef struct
+{
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ ULONG FileAttributes;
+ UInt32 Reserved; // it's expected for alignment
+}
+Z7_WIN_FILE_BASIC_INFORMATION;
+
+
+typedef enum
+{
+ Z7_WIN_FileDirectoryInformation = 1,
+ Z7_WIN_FileFullDirectoryInformation,
+ Z7_WIN_FileBothDirectoryInformation,
+ Z7_WIN_FileBasicInformation
+}
+Z7_WIN_FILE_INFORMATION_CLASS;
+
+
+#if (_WIN32_WINNT >= 0x0500) && !defined(_M_IA64)
+#define Z7_WIN_NTSTATUS NTSTATUS
+#define Z7_WIN_IO_STATUS_BLOCK IO_STATUS_BLOCK
+#else
+typedef LONG Z7_WIN_NTSTATUS;
+typedef struct
+{
+ union
+ {
+ Z7_WIN_NTSTATUS Status;
+ PVOID Pointer;
+ } DUMMYUNIONNAME;
+ ULONG_PTR Information;
+} Z7_WIN_IO_STATUS_BLOCK;
+#endif
+
+
+typedef Z7_WIN_NTSTATUS (WINAPI * Func_NtQueryInformationFile)(
+ HANDLE handle, Z7_WIN_IO_STATUS_BLOCK *io,
+ void *ptr, LONG len, Z7_WIN_FILE_INFORMATION_CLASS cls);
+
+#define MY_STATUS_SUCCESS 0
+
+EXTERN_C_END
+
+static Func_NtQueryInformationFile f_NtQueryInformationFile;
+static bool g_NtQueryInformationFile_WasRequested = false;
+
+
+void CFSFolder::ReadChangeTime(CDirItem &di)
+{
+ di.ChangeTime_WasRequested = true;
+
+ if (!g_NtQueryInformationFile_WasRequested)
+ {
+ g_NtQueryInformationFile_WasRequested = true;
+ f_NtQueryInformationFile = Z7_GET_PROC_ADDRESS(
+ Func_NtQueryInformationFile, ::GetModuleHandleW(L"ntdll.dll"),
+ "NtQueryInformationFile");
+ }
+ if (!f_NtQueryInformationFile)
+ return;
+
+ NIO::CInFile file;
+ if (!file.Open_for_ReadAttributes(_path + GetRelPath(di)))
+ return;
+ Z7_WIN_FILE_BASIC_INFORMATION fbi;
+ Z7_WIN_IO_STATUS_BLOCK IoStatusBlock;
+ const Z7_WIN_NTSTATUS status = f_NtQueryInformationFile(file.GetHandle(), &IoStatusBlock,
+ &fbi, sizeof(fbi), Z7_WIN_FileBasicInformation);
+ if (status != MY_STATUS_SUCCESS)
+ return;
+ if (IoStatusBlock.Information != sizeof(fbi))
+ return;
+ di.ChangeTime.dwLowDateTime = fbi.ChangeTime.u.LowPart;
+ di.ChangeTime.dwHighDateTime = (DWORD)fbi.ChangeTime.u.HighPart;
+ di.ChangeTime_Defined = true;
+}
+
+#endif // FS_SHOW_LINKS_INFO
+
+
+Z7_COM7F_IMF(CFSFolder::GetProperty(UInt32 index, PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+ /*
+ if (index >= (UInt32)Files.Size())
+ {
+ CAltStream &ss = Streams[index - Files.Size()];
+ CDirItem &fi = Files[ss.Parent];
+ switch (propID)
+ {
+ case kpidIsDir: prop = false; break;
+ case kpidIsAltStream: prop = true; break;
+ case kpidName: prop = fs2us(fi.Name) + ss.Name; break;
+ case kpidSize: prop = ss.Size; break;
+ case kpidPackSize:
+ #ifdef UNDER_CE
+ prop = ss.Size;
+ #else
+ if (!ss.PackSize_Defined)
+ {
+ ss.PackSize_Defined = true;
+ if (!MyGetCompressedFileSizeW(_path + GetRelPath(fi) + us2fs(ss.Name), ss.PackSize))
+ ss.PackSize = ss.Size;
+ }
+ prop = ss.PackSize;
+ #endif
+ break;
+ case kpidComment: break;
+ default: index = ss.Parent;
+ }
+ if (index >= (UInt32)Files.Size())
+ {
+ prop.Detach(value);
+ return S_OK;
+ }
+ }
+ */
+ CDirItem &fi = Files[index];
+ switch (propID)
+ {
+ case kpidIsDir: prop = fi.IsDir(); break;
+ case kpidIsAltStream: prop = false; break;
+ case kpidName: prop = fs2us(fi.Name); break;
+ case kpidSize: if (!fi.IsDir() || fi.FolderStat_Defined) prop = fi.Size; break;
+ case kpidPackSize:
+ #ifdef UNDER_CE
+ prop = fi.Size;
+ #else
+ if (!fi.PackSize_Defined)
+ {
+ fi.PackSize_Defined = true;
+ if (fi.IsDir () || !MyGetCompressedFileSizeW(_path + GetRelPath(fi), fi.PackSize))
+ fi.PackSize = fi.Size;
+ }
+ prop = fi.PackSize;
+ #endif
+ break;
+
+ #ifdef FS_SHOW_LINKS_INFO
+
+ case kpidLinks:
+ #ifdef UNDER_CE
+ // prop = fi.NumLinks;
+ #else
+ if (!fi.FileInfo_WasRequested)
+ ReadFileInfo(fi);
+ if (fi.FileInfo_Defined)
+ prop = fi.NumLinks;
+ #endif
+ break;
+
+ case kpidINode:
+ #ifdef UNDER_CE
+ // prop = fi.FileIndex;
+ #else
+ if (!fi.FileInfo_WasRequested)
+ ReadFileInfo(fi);
+ if (fi.FileInfo_Defined)
+ prop = fi.FileIndex;
+ #endif
+ break;
+
+ case kpidChangeTime:
+ if (!fi.ChangeTime_WasRequested)
+ ReadChangeTime(fi);
+ if (fi.ChangeTime_Defined)
+ prop = fi.ChangeTime;
+ break;
+
+ #endif
+
+ case kpidAttrib: prop = (UInt32)fi.Attrib; break;
+ case kpidCTime: prop = fi.CTime; break;
+ case kpidATime: prop = fi.ATime; break;
+ case kpidMTime: prop = fi.MTime; break;
+ case kpidComment:
+ {
+ if (!_commentsAreLoaded)
+ LoadComments();
+ UString comment;
+ if (_comments.GetValue(fs2us(GetRelPath(fi)), comment))
+ {
+ int pos = comment.Find((wchar_t)4);
+ if (pos >= 0)
+ comment.DeleteFrom((unsigned)pos);
+ prop = comment;
+ }
+ break;
+ }
+ case kpidPrefix:
+ if (fi.Parent >= 0)
+ prop = fs2us(Folders[fi.Parent]);
+ break;
+ case kpidNumSubDirs: if (fi.IsDir() && fi.FolderStat_Defined) prop = fi.NumFolders; break;
+ case kpidNumSubFiles: if (fi.IsDir() && fi.FolderStat_Defined) prop = fi.NumFiles; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+
+// ---------- IArchiveGetRawProps ----------
+
+
+Z7_COM7F_IMF(CFSFolder::GetNumRawProps(UInt32 *numProps))
+{
+ *numProps = 1;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFSFolder::GetRawPropInfo(UInt32 /* index */, BSTR *name, PROPID *propID))
+{
+ *name = NULL;
+ *propID = kpidNtReparse;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFSFolder::GetParent(UInt32 /* index */, UInt32 * /* parent */, UInt32 * /* parentType */))
+{
+ return E_FAIL;
+}
+
+Z7_COM7F_IMF(CFSFolder::GetRawProp(UInt32 index, PROPID propID,
+ const void **data, UInt32 *dataSize, UInt32 *propType))
+{
+ #ifdef UNDER_CE
+ UNUSED(index)
+ UNUSED(propID)
+ #endif
+
+ *data = NULL;
+ *dataSize = 0;
+ *propType = 0;
+
+ #ifndef UNDER_CE
+ if (propID == kpidNtReparse)
+ {
+ const CDirItem &fi = Files[index];
+ const CByteBuffer &buf = fi.Reparse;
+ if (buf.Size() == 0)
+ return S_OK;
+ *data = buf;
+ *dataSize = (UInt32)buf.Size();
+ *propType = NPropDataType::kRaw;
+ return S_OK;
+ }
+ #endif
+
+ return S_OK;
+}
+
+
+// returns Position of extension including '.'
+
+static inline CFSTR GetExtensionPtr(const FString &name)
+{
+ const int dotPos = name.ReverseFind_Dot();
+ return name.Ptr((dotPos < 0) ? name.Len() : (unsigned)dotPos);
+}
+
+Z7_COM7F_IMF2(Int32, CFSFolder::CompareItems(UInt32 index1, UInt32 index2, PROPID propID, Int32 /* propIsRaw */))
+{
+ /*
+ const CAltStream *ss1 = NULL;
+ const CAltStream *ss2 = NULL;
+ if (index1 >= (UInt32)Files.Size()) { ss1 = &Streams[index1 - Files.Size()]; index1 = ss1->Parent; }
+ if (index2 >= (UInt32)Files.Size()) { ss2 = &Streams[index2 - Files.Size()]; index2 = ss2->Parent; }
+ */
+ CDirItem &fi1 = Files[index1];
+ CDirItem &fi2 = Files[index2];
+
+ switch (propID)
+ {
+ case kpidName:
+ {
+ const int comp = CompareFileNames_ForFolderList(fi1.Name, fi2.Name);
+ /*
+ if (comp != 0)
+ return comp;
+ if (!ss1)
+ return ss2 ? -1 : 0;
+ if (!ss2)
+ return 1;
+ return MyStringCompareNoCase(ss1->Name, ss2->Name);
+ */
+ return comp;
+ }
+ case kpidSize:
+ return MyCompare(
+ /* ss1 ? ss1->Size : */ fi1.Size,
+ /* ss2 ? ss2->Size : */ fi2.Size);
+ case kpidAttrib: return MyCompare(fi1.Attrib, fi2.Attrib);
+ case kpidCTime: return CompareFileTime(&fi1.CTime, &fi2.CTime);
+ case kpidATime: return CompareFileTime(&fi1.ATime, &fi2.ATime);
+ case kpidMTime: return CompareFileTime(&fi1.MTime, &fi2.MTime);
+ case kpidIsDir:
+ {
+ bool isDir1 = /* ss1 ? false : */ fi1.IsDir();
+ bool isDir2 = /* ss2 ? false : */ fi2.IsDir();
+ if (isDir1 == isDir2)
+ return 0;
+ return isDir1 ? -1 : 1;
+ }
+ case kpidPackSize:
+ {
+ #ifdef UNDER_CE
+ return MyCompare(fi1.Size, fi2.Size);
+ #else
+ // PackSize can be undefined here
+ return MyCompare(
+ /* ss1 ? ss1->PackSize : */ fi1.PackSize,
+ /* ss2 ? ss2->PackSize : */ fi2.PackSize);
+ #endif
+ }
+
+ #ifdef FS_SHOW_LINKS_INFO
+ case kpidINode:
+ {
+ #ifndef UNDER_CE
+ if (!fi1.FileInfo_WasRequested) ReadFileInfo(fi1);
+ if (!fi2.FileInfo_WasRequested) ReadFileInfo(fi2);
+ return MyCompare(
+ fi1.FileIndex,
+ fi2.FileIndex);
+ #endif
+ }
+ case kpidLinks:
+ {
+ #ifndef UNDER_CE
+ if (!fi1.FileInfo_WasRequested) ReadFileInfo(fi1);
+ if (!fi2.FileInfo_WasRequested) ReadFileInfo(fi2);
+ return MyCompare(
+ fi1.NumLinks,
+ fi2.NumLinks);
+ #endif
+ }
+ #endif
+
+ case kpidComment:
+ {
+ // change it !
+ UString comment1, comment2;
+ _comments.GetValue(fs2us(GetRelPath(fi1)), comment1);
+ _comments.GetValue(fs2us(GetRelPath(fi2)), comment2);
+ return MyStringCompareNoCase(comment1, comment2);
+ }
+ case kpidPrefix:
+ if (fi1.Parent < 0) return (fi2.Parent < 0) ? 0 : -1;
+ if (fi2.Parent < 0) return 1;
+ return CompareFileNames_ForFolderList(
+ Folders[fi1.Parent],
+ Folders[fi2.Parent]);
+ case kpidExtension:
+ return CompareFileNames_ForFolderList(
+ GetExtensionPtr(fi1.Name),
+ GetExtensionPtr(fi2.Name));
+ }
+
+ return 0;
+}
+
+HRESULT CFSFolder::BindToFolderSpec(CFSTR name, IFolderFolder **resultFolder)
+{
+ *resultFolder = NULL;
+ CFSFolder *folderSpec = new CFSFolder;
+ CMyComPtr<IFolderFolder> subFolder = folderSpec;
+ RINOK(folderSpec->Init(_path + name + FCHAR_PATH_SEPARATOR))
+ *resultFolder = subFolder.Detach();
+ return S_OK;
+}
+
+/*
+void CFSFolder::GetPrefix(const CDirItem &item, FString &prefix) const
+{
+ if (item.Parent >= 0)
+ prefix = Folders[item.Parent];
+ else
+ prefix.Empty();
+}
+*/
+
+/*
+void CFSFolder::GetPrefix(const CDirItem &item, FString &prefix) const
+{
+ int parent = item.Parent;
+
+ unsigned len = 0;
+
+ while (parent >= 0)
+ {
+ const CDirItem &cur = Files[parent];
+ len += cur.Name.Len() + 1;
+ parent = cur.Parent;
+ }
+
+ wchar_t *p = prefix.GetBuf_SetEnd(len) + len;
+ parent = item.Parent;
+
+ while (parent >= 0)
+ {
+ const CDirItem &cur = Files[parent];
+ *(--p) = FCHAR_PATH_SEPARATOR;
+ p -= cur.Name.Len();
+ wmemcpy(p, cur.Name, cur.Name.Len());
+ parent = cur.Parent;
+ }
+}
+*/
+
+FString CFSFolder::GetRelPath(const CDirItem &item) const
+{
+ if (item.Parent < 0)
+ return item.Name;
+ return Folders[item.Parent] + item.Name;
+}
+
+Z7_COM7F_IMF(CFSFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder))
+{
+ *resultFolder = NULL;
+ const CDirItem &fi = Files[index];
+ if (!fi.IsDir())
+ return E_INVALIDARG;
+ return BindToFolderSpec(GetRelPath(fi), resultFolder);
+}
+
+Z7_COM7F_IMF(CFSFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder))
+{
+ return BindToFolderSpec(us2fs(name), resultFolder);
+}
+
+Z7_COM7F_IMF(CFSFolder::BindToParentFolder(IFolderFolder **resultFolder))
+{
+ *resultFolder = NULL;
+ /*
+ if (_parentFolder)
+ {
+ CMyComPtr<IFolderFolder> parentFolder = _parentFolder;
+ *resultFolder = parentFolder.Detach();
+ return S_OK;
+ }
+ */
+ if (_path.IsEmpty())
+ return E_INVALIDARG;
+
+ #ifndef UNDER_CE
+
+ if (IsDriveRootPath_SuperAllowed(_path))
+ {
+ CFSDrives *drivesFolderSpec = new CFSDrives;
+ CMyComPtr<IFolderFolder> drivesFolder = drivesFolderSpec;
+ drivesFolderSpec->Init(false, IsSuperPath(_path));
+ *resultFolder = drivesFolder.Detach();
+ return S_OK;
+ }
+
+ int pos = _path.ReverseFind_PathSepar();
+ if (pos < 0 || pos != (int)_path.Len() - 1)
+ return E_FAIL;
+ FString parentPath = _path.Left(pos);
+ pos = parentPath.ReverseFind_PathSepar();
+ parentPath.DeleteFrom((unsigned)(pos + 1));
+
+ if (NName::IsDrivePath_SuperAllowed(parentPath))
+ {
+ CFSFolder *parentFolderSpec = new CFSFolder;
+ CMyComPtr<IFolderFolder> parentFolder = parentFolderSpec;
+ if (parentFolderSpec->Init(parentPath) == S_OK)
+ {
+ *resultFolder = parentFolder.Detach();
+ return S_OK;
+ }
+ }
+
+ /*
+ FString parentPathReduced = parentPath.Left(pos);
+
+ pos = parentPathReduced.ReverseFind_PathSepar();
+ if (pos == 1)
+ {
+ if (!IS_PATH_SEPAR_CHAR(parentPath[0]))
+ return E_FAIL;
+ CNetFolder *netFolderSpec = new CNetFolder;
+ CMyComPtr<IFolderFolder> netFolder = netFolderSpec;
+ netFolderSpec->Init(fs2us(parentPath));
+ *resultFolder = netFolder.Detach();
+ return S_OK;
+ }
+ */
+
+ #endif
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFSFolder::GetNumberOfProperties(UInt32 *numProperties))
+{
+ *numProperties = Z7_ARRAY_SIZE(kProps);
+ if (!_flatMode)
+ (*numProperties)--;
+ return S_OK;
+}
+
+IMP_IFolderFolder_GetProp(CFSFolder::GetPropertyInfo, kProps)
+
+Z7_COM7F_IMF(CFSFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value))
+{
+ COM_TRY_BEGIN
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidType: prop = "FSFolder"; break;
+ case kpidPath: prop = fs2us(_path); break;
+ }
+ prop.Detach(value);
+ return S_OK;
+ COM_TRY_END
+}
+
+Z7_COM7F_IMF(CFSFolder::WasChanged(Int32 *wasChanged))
+{
+ bool wasChangedMain = false;
+
+ #ifdef _WIN32
+
+ for (;;)
+ {
+ if (!_findChangeNotification.IsHandleAllocated())
+ break;
+ DWORD waitResult = ::WaitForSingleObject(_findChangeNotification, 0);
+ if (waitResult != WAIT_OBJECT_0)
+ break;
+ _findChangeNotification.FindNext();
+ wasChangedMain = true;
+ }
+
+ #endif
+
+ *wasChanged = BoolToInt(wasChangedMain);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFSFolder::Clone(IFolderFolder **resultFolder))
+{
+ CFSFolder *fsFolderSpec = new CFSFolder;
+ CMyComPtr<IFolderFolder> folderNew = fsFolderSpec;
+ fsFolderSpec->Init(_path);
+ *resultFolder = folderNew.Detach();
+ return S_OK;
+}
+
+
+/*
+HRESULT CFSFolder::GetItemFullSize(unsigned index, UInt64 &size, IProgress *progress)
+{
+ if (index >= Files.Size())
+ {
+ size = Streams[index - Files.Size()].Size;
+ return S_OK;
+ }
+ const CDirItem &fi = Files[index];
+ if (fi.IsDir())
+ {
+ UInt64 numFolders = 0, numFiles = 0;
+ size = 0;
+ return GetFolderSize(_path + GetRelPath(fi), numFolders, numFiles, size, progress);
+ }
+ size = fi.Size;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFSFolder::GetItemFullSize(UInt32 index, PROPVARIANT *value, IProgress *progress)
+{
+ NCOM::CPropVariant prop;
+ UInt64 size = 0;
+ HRESULT result = GetItemFullSize(index, size, progress);
+ prop = size;
+ prop.Detach(value);
+ return result;
+}
+*/
+
+Z7_COM7F_IMF(CFSFolder::CalcItemFullSize(UInt32 index, IProgress *progress))
+{
+ if (index >= (UInt32)Files.Size())
+ return S_OK;
+ CDirItem &fi = Files[index];
+ if (!fi.IsDir())
+ return S_OK;
+ CFsFolderStat stat(_path + GetRelPath(fi), progress);
+ RINOK(stat.Enumerate())
+ fi.Size = stat.Size;
+ fi.NumFolders = stat.NumFolders;
+ fi.NumFiles = stat.NumFiles;
+ fi.FolderStat_Defined = true;
+ return S_OK;
+}
+
+void CFSFolder::GetAbsPath(const wchar_t *name, FString &absPath)
+{
+ absPath.Empty();
+ if (!IsAbsolutePath(name))
+ absPath += _path;
+ absPath += us2fs(name);
+}
+
+Z7_COM7F_IMF(CFSFolder::CreateFolder(const wchar_t *name, IProgress * /* progress */))
+{
+ FString absPath;
+ GetAbsPath(name, absPath);
+ if (CreateDir(absPath))
+ return S_OK;
+ if (::GetLastError() != ERROR_ALREADY_EXISTS)
+ if (CreateComplexDir(absPath))
+ return S_OK;
+ return GetLastError_noZero_HRESULT();
+}
+
+Z7_COM7F_IMF(CFSFolder::CreateFile(const wchar_t *name, IProgress * /* progress */))
+{
+ FString absPath;
+ GetAbsPath(name, absPath);
+ NIO::COutFile outFile;
+ if (!outFile.Create(absPath, false))
+ return GetLastError_noZero_HRESULT();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFSFolder::Rename(UInt32 index, const wchar_t *newName, IProgress * /* progress */))
+{
+ if (index >= (UInt32)Files.Size())
+ return E_NOTIMPL;
+ const CDirItem &fi = Files[index];
+ // FString prefix;
+ // GetPrefix(fi, prefix);
+ FString fullPrefix = _path;
+ if (fi.Parent >= 0)
+ fullPrefix += Folders[fi.Parent];
+ if (!MyMoveFile(fullPrefix + fi.Name, fullPrefix + us2fs(newName)))
+ return GetLastError_noZero_HRESULT();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFSFolder::Delete(const UInt32 *indices, UInt32 numItems,IProgress *progress))
+{
+ RINOK(progress->SetTotal(numItems))
+ // int prevDeletedFileIndex = -1;
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ // Sleep(200);
+ UInt32 index = indices[i];
+ bool result = true;
+ /*
+ if (index >= (UInt32)Files.Size())
+ {
+ const CAltStream &ss = Streams[index - (UInt32)Files.Size()];
+ if (prevDeletedFileIndex != ss.Parent)
+ {
+ const CDirItem &fi = Files[ss.Parent];
+ result = DeleteFileAlways(_path + GetRelPath(fi) + us2fs(ss.Name));
+ }
+ }
+ else
+ */
+ {
+ const CDirItem &fi = Files[index];
+ const FString fullPath = _path + GetRelPath(fi);
+ // prevDeletedFileIndex = index;
+ if (fi.IsDir())
+ result = RemoveDirWithSubItems(fullPath);
+ else
+ result = DeleteFileAlways(fullPath);
+ }
+ if (!result)
+ return GetLastError_noZero_HRESULT();
+ const UInt64 completed = i;
+ RINOK(progress->SetCompleted(&completed))
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFSFolder::SetProperty(UInt32 index, PROPID propID,
+ const PROPVARIANT *value, IProgress * /* progress */))
+{
+ if (index >= (UInt32)Files.Size())
+ return E_INVALIDARG;
+ CDirItem &fi = Files[index];
+ if (fi.Parent >= 0)
+ return E_NOTIMPL;
+ switch (propID)
+ {
+ case kpidComment:
+ {
+ UString filename = fs2us(fi.Name);
+ filename.Trim();
+ if (value->vt == VT_EMPTY)
+ _comments.DeletePair(filename);
+ else if (value->vt == VT_BSTR)
+ {
+ CTextPair pair;
+ pair.ID = filename;
+ pair.ID.Trim();
+ pair.Value.SetFromBstr(value->bstrVal);
+ pair.Value.Trim();
+ if (pair.Value.IsEmpty())
+ _comments.DeletePair(filename);
+ else
+ _comments.AddPair(pair);
+ }
+ else
+ return E_INVALIDARG;
+ SaveComments();
+ break;
+ }
+ default:
+ return E_NOTIMPL;
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFSFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex))
+{
+ if (index >= (UInt32)Files.Size())
+ return E_INVALIDARG;
+ const CDirItem &fi = Files[index];
+ *iconIndex = 0;
+ int iconIndexTemp;
+ if (GetRealIconIndex(_path + GetRelPath(fi), fi.Attrib, iconIndexTemp) != 0)
+ {
+ *iconIndex = iconIndexTemp;
+ return S_OK;
+ }
+ return GetLastError_noZero_HRESULT();
+}
+
+Z7_COM7F_IMF(CFSFolder::SetFlatMode(Int32 flatMode))
+{
+ _flatMode = IntToBool(flatMode);
+ return S_OK;
+}
+
+/*
+Z7_COM7F_IMF(CFSFolder::SetShowNtfsStreamsMode(Int32 showStreamsMode)
+{
+ _scanAltStreams = IntToBool(showStreamsMode);
+ return S_OK;
+}
+*/
+
+}
diff --git a/CPP/7zip/UI/FileManager/FSFolder.h b/CPP/7zip/UI/FileManager/FSFolder.h
new file mode 100644
index 0000000..fe8538a
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FSFolder.h
@@ -0,0 +1,221 @@
+// FSFolder.h
+
+#ifndef ZIP7_INC_FS_FOLDER_H
+#define ZIP7_INC_FS_FOLDER_H
+
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyBuffer.h"
+
+#include "../../../Windows/FileFind.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "IFolder.h"
+#include "TextPairs.h"
+
+namespace NFsFolder {
+
+class CFSFolder;
+
+#define FS_SHOW_LINKS_INFO
+// #define FS_SHOW_CHANGE_TIME
+
+struct CDirItem: public NWindows::NFile::NFind::CFileInfo
+{
+ #ifndef UNDER_CE
+ UInt64 PackSize;
+ #endif
+
+ #ifdef FS_SHOW_LINKS_INFO
+ FILETIME ChangeTime;
+ UInt64 FileIndex;
+ UInt32 NumLinks;
+ bool FileInfo_Defined;
+ bool FileInfo_WasRequested;
+ bool ChangeTime_Defined;
+ bool ChangeTime_WasRequested;
+ #endif
+
+ #ifndef UNDER_CE
+ bool PackSize_Defined;
+ #endif
+
+ bool FolderStat_Defined;
+
+ #ifndef UNDER_CE
+ CByteBuffer Reparse;
+ #endif
+
+ UInt64 NumFolders;
+ UInt64 NumFiles;
+
+ int Parent;
+};
+
+/*
+struct CAltStream
+{
+ UInt64 Size;
+ UInt64 PackSize;
+ bool PackSize_Defined;
+ int Parent;
+ UString Name;
+};
+*/
+
+struct CFsFolderStat
+{
+ UInt64 NumFolders;
+ UInt64 NumFiles;
+ UInt64 Size;
+ IProgress *Progress;
+ FString Path;
+
+ CFsFolderStat(): NumFolders(0), NumFiles(0), Size(0), Progress(NULL) {}
+ CFsFolderStat(const FString &path, IProgress *progress = NULL):
+ NumFolders(0), NumFiles(0), Size(0), Progress(progress), Path(path) {}
+
+ HRESULT Enumerate();
+};
+
+class CFSFolder Z7_final:
+ public IFolderFolder,
+ public IArchiveGetRawProps,
+ public IFolderCompare,
+ #ifdef USE_UNICODE_FSTRING
+ public IFolderGetItemName,
+ #endif
+ public IFolderWasChanged,
+ public IFolderOperations,
+ // public IFolderOperationsDeleteToRecycleBin,
+ public IFolderCalcItemFullSize,
+ public IFolderClone,
+ public IFolderGetSystemIconIndex,
+ public IFolderSetFlatMode,
+ // public IFolderSetShowNtfsStreamsMode,
+ public CMyUnknownImp
+{
+ Z7_COM_QI_BEGIN2(IFolderFolder)
+ Z7_COM_QI_ENTRY(IArchiveGetRawProps)
+ Z7_COM_QI_ENTRY(IFolderCompare)
+ #ifdef USE_UNICODE_FSTRING
+ Z7_COM_QI_ENTRY(IFolderGetItemName)
+ #endif
+ Z7_COM_QI_ENTRY(IFolderWasChanged)
+ // Z7_COM_QI_ENTRY(IFolderOperationsDeleteToRecycleBin)
+ Z7_COM_QI_ENTRY(IFolderOperations)
+ Z7_COM_QI_ENTRY(IFolderCalcItemFullSize)
+ Z7_COM_QI_ENTRY(IFolderClone)
+ Z7_COM_QI_ENTRY(IFolderGetSystemIconIndex)
+ Z7_COM_QI_ENTRY(IFolderSetFlatMode)
+ // Z7_COM_QI_ENTRY(IFolderSetShowNtfsStreamsMode)
+ Z7_COM_QI_END
+ Z7_COM_ADDREF_RELEASE
+
+ Z7_IFACE_COM7_IMP(IFolderFolder)
+ Z7_IFACE_COM7_IMP(IArchiveGetRawProps)
+ Z7_IFACE_COM7_IMP(IFolderCompare)
+ #ifdef USE_UNICODE_FSTRING
+ Z7_IFACE_COM7_IMP(IFolderGetItemName)
+ #endif
+ Z7_IFACE_COM7_IMP(IFolderWasChanged)
+ Z7_IFACE_COM7_IMP(IFolderOperations)
+ Z7_IFACE_COM7_IMP(IFolderCalcItemFullSize)
+ Z7_IFACE_COM7_IMP(IFolderClone)
+ Z7_IFACE_COM7_IMP(IFolderGetSystemIconIndex)
+ Z7_IFACE_COM7_IMP(IFolderSetFlatMode)
+ // Z7_IFACE_COM7_IMP(IFolderSetShowNtfsStreamsMode)
+
+private:
+ FString _path;
+
+ CObjectVector<CDirItem> Files;
+ FStringVector Folders;
+ // CObjectVector<CAltStream> Streams;
+ // CMyComPtr<IFolderFolder> _parentFolder;
+
+ bool _commentsAreLoaded;
+ CPairsStorage _comments;
+
+ // bool _scanAltStreams;
+ bool _flatMode;
+
+ #ifdef _WIN32
+ NWindows::NFile::NFind::CFindChangeNotification _findChangeNotification;
+ #endif
+
+ // HRESULT GetItemFullSize(unsigned index, UInt64 &size, IProgress *progress);
+ void GetAbsPath(const wchar_t *name, FString &absPath);
+ HRESULT BindToFolderSpec(CFSTR name, IFolderFolder **resultFolder);
+
+ bool LoadComments();
+ bool SaveComments();
+ HRESULT LoadSubItems(int dirItem, const FString &path);
+
+ #ifdef FS_SHOW_LINKS_INFO
+ bool ReadFileInfo(CDirItem &di);
+ void ReadChangeTime(CDirItem &di);
+ #endif
+
+public:
+ HRESULT Init(const FString &path /* , IFolderFolder *parentFolder */);
+ #if !defined(_WIN32) || defined(UNDER_CE)
+ HRESULT InitToRoot() { return Init((FString) FSTRING_PATH_SEPARATOR /* , NULL */); }
+ #endif
+
+ CFSFolder() : _flatMode(false)
+ // , _scanAltStreams(false)
+ {}
+
+ void GetFullPath(const CDirItem &item, FString &path) const
+ {
+ // FString prefix;
+ // GetPrefix(item, prefix);
+ path = _path;
+ if (item.Parent >= 0)
+ path += Folders[item.Parent];
+ path += item.Name;
+ }
+
+ // void GetPrefix(const CDirItem &item, FString &prefix) const;
+
+ FString GetRelPath(const CDirItem &item) const;
+
+ void Clear()
+ {
+ Files.Clear();
+ Folders.Clear();
+ // Streams.Clear();
+ }
+};
+
+struct CCopyStateIO
+{
+ IProgress *Progress;
+ UInt64 TotalSize;
+ UInt64 StartPos;
+ UInt64 CurrentSize;
+ bool DeleteSrcFile;
+
+ int ErrorFileIndex;
+ UString ErrorMessage;
+
+ CCopyStateIO(): TotalSize(0), StartPos(0), DeleteSrcFile(false) {}
+
+ HRESULT MyCopyFile(CFSTR inPath, CFSTR outPath, DWORD attrib = INVALID_FILE_ATTRIBUTES);
+};
+
+HRESULT SendLastErrorMessage(IFolderOperationsExtractCallback *callback, const FString &fileName);
+
+/* destDirPrefix is allowed to be:
+ "full_path\" or "full_path:" for alt streams */
+
+HRESULT CopyFileSystemItems(
+ const UStringVector &itemsPaths,
+ const FString &destDirPrefix,
+ bool moveMode,
+ IFolderOperationsExtractCallback *callback);
+
+}
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/FSFolderCopy.cpp b/CPP/7zip/UI/FileManager/FSFolderCopy.cpp
new file mode 100644
index 0000000..db4ae0a
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FSFolderCopy.cpp
@@ -0,0 +1,810 @@
+// FSFolderCopy.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+
+#include "../../../Common/Defs.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileName.h"
+
+#include "../../Common/FilePathAutoRename.h"
+
+#include "FSFolder.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+using namespace NName;
+using namespace NFind;
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NFsFolder {
+
+static const char * const k_CannotCopyDirToAltStream = "Cannot copy folder as alternate stream";
+
+
+HRESULT CCopyStateIO::MyCopyFile(CFSTR inPath, CFSTR outPath, DWORD attrib)
+{
+ ErrorFileIndex = -1;
+ ErrorMessage.Empty();
+ CurrentSize = 0;
+
+ {
+ const size_t kBufSize = 1 << 16;
+ CByteArr buf(kBufSize);
+
+ NIO::CInFile inFile;
+ NIO::COutFile outFile;
+
+ if (!inFile.Open(inPath))
+ {
+ ErrorFileIndex = 0;
+ return S_OK;
+ }
+
+ if (!outFile.Create(outPath, true))
+ {
+ ErrorFileIndex = 1;
+ return S_OK;
+ }
+
+ for (;;)
+ {
+ UInt32 num;
+ if (!inFile.Read(buf, kBufSize, num))
+ {
+ ErrorFileIndex = 0;
+ return S_OK;
+ }
+ if (num == 0)
+ break;
+
+ UInt32 written = 0;
+ if (!outFile.Write(buf, num, written))
+ {
+ ErrorFileIndex = 1;
+ return S_OK;
+ }
+ if (written != num)
+ {
+ ErrorMessage = "Write error";
+ return S_OK;
+ }
+ CurrentSize += num;
+ if (Progress)
+ {
+ UInt64 completed = StartPos + CurrentSize;
+ RINOK(Progress->SetCompleted(&completed))
+ }
+ }
+ }
+
+ /* SetFileAttrib("path:alt_stream_name") sets attributes for main file "path".
+ But we don't want to change attributes of main file, when we write alt stream.
+ So we need INVALID_FILE_ATTRIBUTES for alt stream here */
+
+ if (attrib != INVALID_FILE_ATTRIBUTES)
+ SetFileAttrib(outPath, attrib);
+
+ if (DeleteSrcFile)
+ {
+ if (!DeleteFileAlways(inPath))
+ {
+ ErrorFileIndex = 0;
+ return S_OK;
+ }
+ }
+
+ return S_OK;
+}
+
+
+/*
+static bool IsItWindows2000orHigher()
+{
+ OSVERSIONINFO versionInfo;
+ versionInfo.dwOSVersionInfoSize = sizeof(versionInfo);
+ if (!::GetVersionEx(&versionInfo))
+ return false;
+ return (versionInfo.dwPlatformId == VER_PLATFORM_WIN32_NT) &&
+ (versionInfo.dwMajorVersion >= 5);
+}
+*/
+
+struct CProgressInfo
+{
+ UInt64 TotalSize;
+ UInt64 StartPos;
+ UInt64 FileSize;
+ IProgress *Progress;
+ HRESULT ProgressResult;
+
+ void Init() { ProgressResult = S_OK; }
+};
+
+#ifndef PROGRESS_CONTINUE
+
+#define PROGRESS_CONTINUE 0
+#define PROGRESS_CANCEL 1
+
+#define COPY_FILE_FAIL_IF_EXISTS 0x00000001
+
+typedef
+DWORD
+(WINAPI* LPPROGRESS_ROUTINE)(
+ LARGE_INTEGER TotalFileSize,
+ LARGE_INTEGER TotalBytesTransferred,
+ LARGE_INTEGER StreamSize,
+ LARGE_INTEGER StreamBytesTransferred,
+ DWORD dwStreamNumber,
+ DWORD dwCallbackReason,
+ HANDLE hSourceFile,
+ HANDLE hDestinationFile,
+ LPVOID lpData
+ );
+
+#endif
+
+static DWORD CALLBACK CopyProgressRoutine(
+ LARGE_INTEGER TotalFileSize, // file size
+ LARGE_INTEGER TotalBytesTransferred, // bytes transferred
+ LARGE_INTEGER /* StreamSize */, // bytes in stream
+ LARGE_INTEGER /* StreamBytesTransferred */, // bytes transferred for stream
+ DWORD /* dwStreamNumber */, // current stream
+ DWORD /* dwCallbackReason */, // callback reason
+ HANDLE /* hSourceFile */, // handle to source file
+ HANDLE /* hDestinationFile */, // handle to destination file
+ LPVOID lpData // from CopyFileEx
+)
+{
+ // StreamSize = StreamSize;
+ // StreamBytesTransferred = StreamBytesTransferred;
+ // dwStreamNumber = dwStreamNumber;
+ // dwCallbackReason = dwCallbackReason;
+
+ CProgressInfo &pi = *(CProgressInfo *)lpData;
+
+ if ((UInt64)TotalFileSize.QuadPart > pi.FileSize)
+ {
+ pi.TotalSize += (UInt64)TotalFileSize.QuadPart - pi.FileSize;
+ pi.FileSize = (UInt64)TotalFileSize.QuadPart;
+ pi.ProgressResult = pi.Progress->SetTotal(pi.TotalSize);
+ }
+ const UInt64 completed = pi.StartPos + (UInt64)TotalBytesTransferred.QuadPart;
+ pi.ProgressResult = pi.Progress->SetCompleted(&completed);
+ return (pi.ProgressResult == S_OK ? PROGRESS_CONTINUE : PROGRESS_CANCEL);
+}
+
+typedef BOOL (WINAPI * Func_CopyFileExA)(
+ IN LPCSTR lpExistingFileName,
+ IN LPCSTR lpNewFileName,
+ IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL,
+ IN LPVOID lpData OPTIONAL,
+ IN LPBOOL pbCancel OPTIONAL,
+ IN DWORD dwCopyFlags
+ );
+
+typedef BOOL (WINAPI * Func_CopyFileExW)(
+ IN LPCWSTR lpExistingFileName,
+ IN LPCWSTR lpNewFileName,
+ IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL,
+ IN LPVOID lpData OPTIONAL,
+ IN LPBOOL pbCancel OPTIONAL,
+ IN DWORD dwCopyFlags
+ );
+
+typedef BOOL (WINAPI * Func_MoveFileWithProgressW)(
+ IN LPCWSTR lpExistingFileName,
+ IN LPCWSTR lpNewFileName,
+ IN LPPROGRESS_ROUTINE lpProgressRoutine OPTIONAL,
+ IN LPVOID lpData OPTIONAL,
+ IN DWORD dwFlags
+ );
+
+struct CCopyState
+{
+ CProgressInfo ProgressInfo;
+ IFolderOperationsExtractCallback *Callback;
+ bool MoveMode;
+ bool UseReadWriteMode;
+ bool IsAltStreamsDest;
+
+ Func_CopyFileExW my_CopyFileExW;
+ #ifndef UNDER_CE
+ Func_MoveFileWithProgressW my_MoveFileWithProgressW;
+ #endif
+ #ifndef _UNICODE
+ Func_CopyFileExA my_CopyFileExA;
+ #endif
+
+ void Prepare();
+ bool CopyFile_NT(const wchar_t *oldFile, const wchar_t *newFile);
+ bool CopyFile_Sys(CFSTR oldFile, CFSTR newFile);
+ bool MoveFile_Sys(CFSTR oldFile, CFSTR newFile);
+
+ HRESULT CallProgress();
+
+ bool IsCallbackProgressError() { return ProgressInfo.ProgressResult != S_OK; }
+};
+
+HRESULT CCopyState::CallProgress()
+{
+ return ProgressInfo.Progress->SetCompleted(&ProgressInfo.StartPos);
+}
+
+void CCopyState::Prepare()
+{
+ my_CopyFileExW = NULL;
+ #ifndef UNDER_CE
+ my_MoveFileWithProgressW = NULL;
+ #endif
+ #ifndef _UNICODE
+ my_CopyFileExA = NULL;
+ if (!g_IsNT)
+ {
+ my_CopyFileExA = Z7_GET_PROC_ADDRESS(
+ Func_CopyFileExA, ::GetModuleHandleA("kernel32.dll"),
+ "CopyFileExA");
+ }
+ else
+ #endif
+ {
+ const HMODULE module = ::GetModuleHandleW(
+ #ifdef UNDER_CE
+ L"coredll.dll"
+ #else
+ L"kernel32.dll"
+ #endif
+ );
+ my_CopyFileExW = Z7_GET_PROC_ADDRESS(
+ Func_CopyFileExW, module,
+ "CopyFileExW");
+ #ifndef UNDER_CE
+ my_MoveFileWithProgressW = Z7_GET_PROC_ADDRESS(
+ Func_MoveFileWithProgressW, module,
+ "MoveFileWithProgressW");
+ #endif
+ }
+}
+
+/* WinXP-64:
+ CopyFileW(fromFile, toFile:altStream)
+ OK - there are NO alt streams in fromFile
+ ERROR_INVALID_PARAMETER - there are alt streams in fromFile
+*/
+
+bool CCopyState::CopyFile_NT(const wchar_t *oldFile, const wchar_t *newFile)
+{
+ BOOL cancelFlag = FALSE;
+ if (my_CopyFileExW)
+ return BOOLToBool(my_CopyFileExW(oldFile, newFile, CopyProgressRoutine,
+ &ProgressInfo, &cancelFlag, COPY_FILE_FAIL_IF_EXISTS));
+ return BOOLToBool(::CopyFileW(oldFile, newFile, TRUE));
+}
+
+bool CCopyState::CopyFile_Sys(CFSTR oldFile, CFSTR newFile)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ if (my_CopyFileExA)
+ {
+ BOOL cancelFlag = FALSE;
+ if (my_CopyFileExA(fs2fas(oldFile), fs2fas(newFile),
+ CopyProgressRoutine, &ProgressInfo, &cancelFlag, COPY_FILE_FAIL_IF_EXISTS))
+ return true;
+ if (::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return false;
+ }
+ return BOOLToBool(::CopyFile(fs2fas(oldFile), fs2fas(newFile), TRUE));
+ }
+ else
+ #endif
+ {
+ IF_USE_MAIN_PATH_2(oldFile, newFile)
+ {
+ if (CopyFile_NT(fs2us(oldFile), fs2us(newFile)))
+ return true;
+ }
+ #ifdef Z7_LONG_PATH
+ if (USE_SUPER_PATH_2)
+ {
+ if (IsCallbackProgressError())
+ return false;
+ UString superPathOld, superPathNew;
+ if (!GetSuperPaths(oldFile, newFile, superPathOld, superPathNew, USE_MAIN_PATH_2))
+ return false;
+ if (CopyFile_NT(superPathOld, superPathNew))
+ return true;
+ }
+ #endif
+ return false;
+ }
+}
+
+bool CCopyState::MoveFile_Sys(CFSTR oldFile, CFSTR newFile)
+{
+ #ifndef UNDER_CE
+ // if (IsItWindows2000orHigher())
+ // {
+ if (my_MoveFileWithProgressW)
+ {
+ IF_USE_MAIN_PATH_2(oldFile, newFile)
+ {
+ if (my_MoveFileWithProgressW(fs2us(oldFile), fs2us(newFile), CopyProgressRoutine,
+ &ProgressInfo, MOVEFILE_COPY_ALLOWED))
+ return true;
+ }
+ #ifdef Z7_LONG_PATH
+ if ((!(USE_MAIN_PATH_2) || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED) && USE_SUPER_PATH_2)
+ {
+ if (IsCallbackProgressError())
+ return false;
+ UString superPathOld, superPathNew;
+ if (!GetSuperPaths(oldFile, newFile, superPathOld, superPathNew, USE_MAIN_PATH_2))
+ return false;
+ if (my_MoveFileWithProgressW(superPathOld, superPathNew, CopyProgressRoutine,
+ &ProgressInfo, MOVEFILE_COPY_ALLOWED))
+ return true;
+ }
+ #endif
+ if (::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return false;
+ }
+ // }
+ // else
+ #endif
+ return MyMoveFile(oldFile, newFile);
+}
+
+static HRESULT SendMessageError(IFolderOperationsExtractCallback *callback,
+ const wchar_t *message, const FString &fileName)
+{
+ UString s = message;
+ s += " : ";
+ s += fs2us(fileName);
+ return callback->ShowMessage(s);
+}
+
+static HRESULT SendMessageError(IFolderOperationsExtractCallback *callback,
+ const char *message, const FString &fileName)
+{
+ return SendMessageError(callback, MultiByteToUnicodeString(message), fileName);
+}
+
+static DWORD Return_LastError_or_FAIL()
+{
+ DWORD errorCode = GetLastError();
+ if (errorCode == 0)
+ errorCode = (DWORD)E_FAIL;
+ return errorCode;
+}
+
+static UString GetLastErrorMessage()
+{
+ return NError::MyFormatMessage(Return_LastError_or_FAIL());
+}
+
+HRESULT SendLastErrorMessage(IFolderOperationsExtractCallback *callback, const FString &fileName)
+{
+ return SendMessageError(callback, GetLastErrorMessage(), fileName);
+}
+
+static HRESULT CopyFile_Ask(
+ CCopyState &state,
+ const FString &srcPath,
+ const CFileInfo &srcFileInfo,
+ const FString &destPath)
+{
+ if (CompareFileNames(destPath, srcPath) == 0)
+ {
+ RINOK(SendMessageError(state.Callback,
+ state.MoveMode ?
+ "Cannot move file onto itself" :
+ "Cannot copy file onto itself"
+ , destPath))
+ return E_ABORT;
+ }
+
+ Int32 writeAskResult;
+ CMyComBSTR destPathResult;
+ RINOK(state.Callback->AskWrite(
+ fs2us(srcPath),
+ BoolToInt(false),
+ &srcFileInfo.MTime, &srcFileInfo.Size,
+ fs2us(destPath),
+ &destPathResult,
+ &writeAskResult))
+
+ if (IntToBool(writeAskResult))
+ {
+ FString destPathNew = us2fs((LPCOLESTR)destPathResult);
+ RINOK(state.Callback->SetCurrentFilePath(fs2us(srcPath)))
+
+ if (state.UseReadWriteMode)
+ {
+ NFsFolder::CCopyStateIO state2;
+ state2.Progress = state.Callback;
+ state2.DeleteSrcFile = state.MoveMode;
+ state2.TotalSize = state.ProgressInfo.TotalSize;
+ state2.StartPos = state.ProgressInfo.StartPos;
+
+ RINOK(state2.MyCopyFile(srcPath, destPathNew,
+ state.IsAltStreamsDest ? INVALID_FILE_ATTRIBUTES: srcFileInfo.Attrib))
+
+ if (state2.ErrorFileIndex >= 0)
+ {
+ if (state2.ErrorMessage.IsEmpty())
+ state2.ErrorMessage = GetLastErrorMessage();
+ FString errorName;
+ if (state2.ErrorFileIndex == 0)
+ errorName = srcPath;
+ else
+ errorName = destPathNew;
+ RINOK(SendMessageError(state.Callback, state2.ErrorMessage, errorName))
+ return E_ABORT;
+ }
+ state.ProgressInfo.StartPos += state2.CurrentSize;
+ }
+ else
+ {
+ state.ProgressInfo.FileSize = srcFileInfo.Size;
+ bool res;
+ if (state.MoveMode)
+ res = state.MoveFile_Sys(srcPath, destPathNew);
+ else
+ res = state.CopyFile_Sys(srcPath, destPathNew);
+ RINOK(state.ProgressInfo.ProgressResult)
+ if (!res)
+ {
+ // GetLastError() is ERROR_REQUEST_ABORTED in case of PROGRESS_CANCEL.
+ RINOK(SendMessageError(state.Callback, GetLastErrorMessage(), destPathNew))
+ return E_ABORT;
+ }
+ state.ProgressInfo.StartPos += state.ProgressInfo.FileSize;
+ }
+ }
+ else
+ {
+ if (state.ProgressInfo.TotalSize >= srcFileInfo.Size)
+ {
+ state.ProgressInfo.TotalSize -= srcFileInfo.Size;
+ RINOK(state.ProgressInfo.Progress->SetTotal(state.ProgressInfo.TotalSize))
+ }
+ }
+ return state.CallProgress();
+}
+
+static FString CombinePath(const FString &folderPath, const FString &fileName)
+{
+ FString s (folderPath);
+ s.Add_PathSepar(); // FCHAR_PATH_SEPARATOR
+ s += fileName;
+ return s;
+}
+
+static bool IsDestChild(const FString &src, const FString &dest)
+{
+ unsigned len = src.Len();
+ if (dest.Len() < len)
+ return false;
+ if (dest.Len() != len && dest[len] != FCHAR_PATH_SEPARATOR)
+ return false;
+ return CompareFileNames(dest.Left(len), src) == 0;
+}
+
+static HRESULT CopyFolder(
+ CCopyState &state,
+ const FString &srcPath, // without TAIL separator
+ const FString &destPath) // without TAIL separator
+{
+ RINOK(state.CallProgress())
+
+ if (IsDestChild(srcPath, destPath))
+ {
+ RINOK(SendMessageError(state.Callback,
+ state.MoveMode ?
+ "Cannot copy folder onto itself" :
+ "Cannot move folder onto itself"
+ , destPath))
+ return E_ABORT;
+ }
+
+ if (state.MoveMode)
+ {
+ if (state.MoveFile_Sys(srcPath, destPath))
+ return S_OK;
+
+ // MSDN: MoveFile() fails for dirs on different volumes.
+ }
+
+ if (!CreateComplexDir(destPath))
+ {
+ RINOK(SendMessageError(state.Callback, "Cannot create folder", destPath))
+ return E_ABORT;
+ }
+
+ CEnumerator enumerator;
+ enumerator.SetDirPrefix(CombinePath(srcPath, FString()));
+
+ for (;;)
+ {
+ NFind::CFileInfo fi;
+ bool found;
+ if (!enumerator.Next(fi, found))
+ {
+ SendLastErrorMessage(state.Callback, srcPath);
+ return S_OK;
+ }
+ if (!found)
+ break;
+ const FString srcPath2 = CombinePath(srcPath, fi.Name);
+ const FString destPath2 = CombinePath(destPath, fi.Name);
+ if (fi.IsDir())
+ {
+ RINOK(CopyFolder(state, srcPath2, destPath2))
+ }
+ else
+ {
+ RINOK(CopyFile_Ask(state, srcPath2, fi, destPath2))
+ }
+ }
+
+ if (state.MoveMode)
+ {
+ if (!RemoveDir(srcPath))
+ {
+ RINOK(SendMessageError(state.Callback, "Cannot remove folder", srcPath))
+ return E_ABORT;
+ }
+ }
+
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CFSFolder::CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems,
+ Int32 /* includeAltStreams */, Int32 /* replaceAltStreamColon */,
+ const wchar_t *path, IFolderOperationsExtractCallback *callback))
+{
+ if (numItems == 0)
+ return S_OK;
+
+ const FString destPath = us2fs(path);
+ if (destPath.IsEmpty())
+ return E_INVALIDARG;
+
+ const bool isAltDest = NName::IsAltPathPrefix(destPath);
+ const bool isDirectPath = (!isAltDest && !IsPathSepar(destPath.Back()));
+
+ if (isDirectPath)
+ if (numItems > 1)
+ return E_INVALIDARG;
+
+ CFsFolderStat stat;
+ stat.Progress = callback;
+
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ const UInt32 index = indices[i];
+ /*
+ if (index >= Files.Size())
+ {
+ size += Streams[index - Files.Size()].Size;
+ // numFiles++;
+ continue;
+ }
+ */
+ const CDirItem &fi = Files[index];
+ if (fi.IsDir())
+ {
+ if (!isAltDest)
+ {
+ stat.Path = _path;
+ stat.Path += GetRelPath(fi);
+ RINOK(stat.Enumerate())
+ }
+ stat.NumFolders++;
+ }
+ else
+ {
+ stat.NumFiles++;
+ stat.Size += fi.Size;
+ }
+ }
+
+ /*
+ if (stat.NumFolders != 0 && isAltDest)
+ return E_NOTIMPL;
+ */
+
+ RINOK(callback->SetTotal(stat.Size))
+ RINOK(callback->SetNumFiles(stat.NumFiles))
+
+ UInt64 completedSize = 0;
+ RINOK(callback->SetCompleted(&completedSize))
+
+ CCopyState state;
+ state.ProgressInfo.TotalSize = stat.Size;
+ state.ProgressInfo.StartPos = 0;
+ state.ProgressInfo.Progress = callback;
+ state.ProgressInfo.Init();
+ state.Callback = callback;
+ state.MoveMode = IntToBool(moveMode);
+ state.IsAltStreamsDest = isAltDest;
+ /* CopyFileW(fromFile, toFile:altStream) returns ERROR_INVALID_PARAMETER,
+ if there are alt streams in fromFile.
+ So we don't use CopyFileW() for alt Streams. */
+ state.UseReadWriteMode = isAltDest;
+ state.Prepare();
+
+ for (i = 0; i < numItems; i++)
+ {
+ const UInt32 index = indices[i];
+ if (index >= (UInt32)Files.Size())
+ continue;
+ const CDirItem &fi = Files[index];
+ FString destPath2 = destPath;
+ if (!isDirectPath)
+ destPath2 += fi.Name;
+ FString srcPath;
+ GetFullPath(fi, srcPath);
+
+ if (fi.IsDir())
+ {
+ if (isAltDest)
+ {
+ RINOK(SendMessageError(callback, k_CannotCopyDirToAltStream, srcPath))
+ }
+ else
+ {
+ RINOK(CopyFolder(state, srcPath, destPath2))
+ }
+ }
+ else
+ {
+ RINOK(CopyFile_Ask(state, srcPath, fi, destPath2))
+ }
+ }
+ return S_OK;
+}
+
+
+
+/* we can call CopyFileSystemItems() from CDropTarget::Drop() */
+
+HRESULT CopyFileSystemItems(
+ const UStringVector &itemsPaths,
+ const FString &destDirPrefix,
+ bool moveMode,
+ IFolderOperationsExtractCallback *callback)
+{
+ if (itemsPaths.IsEmpty())
+ return S_OK;
+
+ if (destDirPrefix.IsEmpty())
+ return E_INVALIDARG;
+
+ const bool isAltDest = NName::IsAltPathPrefix(destDirPrefix);
+
+ CFsFolderStat stat;
+ stat.Progress = callback;
+
+ {
+ FOR_VECTOR (i, itemsPaths)
+ {
+ const UString &path = itemsPaths[i];
+ CFileInfo fi;
+ if (!fi.Find(us2fs(path)))
+ continue;
+ if (fi.IsDir())
+ {
+ if (!isAltDest)
+ {
+ stat.Path = us2fs(path);
+ RINOK(stat.Enumerate())
+ }
+ stat.NumFolders++;
+ }
+ else
+ {
+ stat.NumFiles++;
+ stat.Size += fi.Size;
+ }
+ }
+ }
+
+ /*
+ if (stat.NumFolders != 0 && isAltDest)
+ return E_NOTIMPL;
+ */
+
+ RINOK(callback->SetTotal(stat.Size))
+ // RINOK(progress->SetNumFiles(stat.NumFiles));
+
+ UInt64 completedSize = 0;
+ RINOK(callback->SetCompleted(&completedSize))
+
+ CCopyState state;
+ state.ProgressInfo.TotalSize = stat.Size;
+ state.ProgressInfo.StartPos = 0;
+ state.ProgressInfo.Progress = callback;
+ state.ProgressInfo.Init();
+ state.Callback = callback;
+ state.MoveMode = moveMode;
+ state.IsAltStreamsDest = isAltDest;
+ /* CopyFileW(fromFile, toFile:altStream) returns ERROR_INVALID_PARAMETER,
+ if there are alt streams in fromFile.
+ So we don't use CopyFileW() for alt Streams. */
+ state.UseReadWriteMode = isAltDest;
+ state.Prepare();
+
+ FOR_VECTOR (i, itemsPaths)
+ {
+ const UString path = itemsPaths[i];
+ CFileInfo fi;
+
+ if (!fi.Find(us2fs(path)))
+ {
+ RINOK(SendMessageError(callback, "Cannot find the file", us2fs(path)))
+ continue;
+ }
+
+ FString destPath = destDirPrefix;
+ destPath += fi.Name;
+
+ if (fi.IsDir())
+ {
+ if (isAltDest)
+ {
+ RINOK(SendMessageError(callback, k_CannotCopyDirToAltStream, us2fs(path)))
+ }
+ else
+ {
+ RINOK(CopyFolder(state, us2fs(path), destPath))
+ }
+ }
+ else
+ {
+ RINOK(CopyFile_Ask(state, us2fs(path), fi, destPath))
+ }
+ }
+ return S_OK;
+}
+
+
+/* we don't use CFSFolder::CopyFrom() because the caller of CopyFrom()
+ is optimized for IFolderArchiveUpdateCallback interface,
+ but we want to use IFolderOperationsExtractCallback interface instead */
+
+Z7_COM7F_IMF(CFSFolder::CopyFrom(Int32 /* moveMode */, const wchar_t * /* fromFolderPath */,
+ const wchar_t * const * /* itemsPaths */, UInt32 /* numItems */, IProgress * /* progress */))
+{
+ /*
+ Z7_DECL_CMyComPtr_QI_FROM(
+ IFolderOperationsExtractCallback,
+ callback, progress)
+ if (!callback)
+ return E_NOTIMPL;
+ return CopyFileSystemItems(_path,
+ moveMode, fromDirPrefix,
+ itemsPaths, numItems, callback);
+ */
+ return E_NOTIMPL;
+}
+
+Z7_COM7F_IMF(CFSFolder::CopyFromFile(UInt32 /* index */, const wchar_t * /* fullFilePath */, IProgress * /* progress */))
+{
+ return E_NOTIMPL;
+}
+
+}
diff --git a/CPP/7zip/UI/FileManager/FileFolderPluginOpen.cpp b/CPP/7zip/UI/FileManager/FileFolderPluginOpen.cpp
new file mode 100644
index 0000000..e4e9997
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FileFolderPluginOpen.cpp
@@ -0,0 +1,394 @@
+// FileFolderPluginOpen.cpp
+
+#include "StdAfx.h"
+
+#include "resource.h"
+
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/Thread.h"
+
+#include "../Agent/Agent.h"
+#include "../GUI/ExtractRes.h"
+
+#include "FileFolderPluginOpen.h"
+#include "FormatUtils.h"
+#include "LangUtils.h"
+#include "OpenCallback.h"
+#include "PluginLoader.h"
+#include "PropertyName.h"
+#include "RegistryPlugins.h"
+
+using namespace NWindows;
+
+struct CThreadArchiveOpen
+{
+ UString Path;
+ UString ArcFormat;
+ CMyComPtr<IInStream> InStream;
+ CMyComPtr<IFolderManager> FolderManager;
+ CMyComPtr<IProgress> OpenCallbackProgress;
+
+ COpenArchiveCallback *OpenCallbackSpec;
+ /*
+ CMyComPtr<IUnknown>
+ // CMyComPtr<IProgress>
+ // CMyComPtr<IArchiveOpenCallback>
+ OpenCallbackSpec_Ref;
+ */
+
+ CMyComPtr<IFolderFolder> Folder;
+ HRESULT Result;
+
+ void Process()
+ {
+ try
+ {
+ CProgressCloser closer(OpenCallbackSpec->ProgressDialog);
+ Result = FolderManager->OpenFolderFile(InStream, Path, ArcFormat, &Folder, OpenCallbackProgress);
+ }
+ catch(...) { Result = E_FAIL; }
+ }
+
+ static THREAD_FUNC_DECL MyThreadFunction(void *param)
+ {
+ ((CThreadArchiveOpen *)param)->Process();
+ return 0;
+ }
+};
+
+/*
+static int FindPlugin(const CObjectVector<CPluginInfo> &plugins, const UString &pluginName)
+{
+ for (int i = 0; i < plugins.Size(); i++)
+ if (plugins[i].Name.CompareNoCase(pluginName) == 0)
+ return i;
+ return -1;
+}
+*/
+
+static void SplitNameToPureNameAndExtension(const FString &fullName,
+ FString &pureName, FString &extensionDelimiter, FString &extension)
+{
+ const int index = fullName.ReverseFind_Dot();
+ if (index < 0)
+ {
+ pureName = fullName;
+ extensionDelimiter.Empty();
+ extension.Empty();
+ }
+ else
+ {
+ pureName.SetFrom(fullName, (unsigned)index);
+ extensionDelimiter = '.';
+ extension = fullName.Ptr((unsigned)index + 1);
+ }
+}
+
+
+struct CArcLevelInfo
+{
+ UString Error;
+ UString Path;
+ UString Type;
+ UString ErrorType;
+ UString ErrorFlags;
+};
+
+
+struct CArcLevelsInfo
+{
+ CObjectVector<CArcLevelInfo> Levels; // LastLevel Is NON-OPEN
+};
+
+
+UString GetOpenArcErrorMessage(UInt32 errorFlags);
+
+
+static void GetFolderLevels(CMyComPtr<IFolderFolder> &folder, CArcLevelsInfo &levels)
+{
+ levels.Levels.Clear();
+
+ CMyComPtr<IGetFolderArcProps> getFolderArcProps;
+ folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps);
+
+ if (!getFolderArcProps)
+ return;
+ CMyComPtr<IFolderArcProps> arcProps;
+ getFolderArcProps->GetFolderArcProps(&arcProps);
+ if (!arcProps)
+ return;
+
+ UInt32 numLevels;
+ if (arcProps->GetArcNumLevels(&numLevels) != S_OK)
+ numLevels = 0;
+
+ for (UInt32 level = 0; level <= numLevels; level++)
+ {
+ const PROPID propIDs[] = { kpidError, kpidPath, kpidType, kpidErrorType };
+
+ CArcLevelInfo lev;
+
+ for (Int32 i = 0; i < 4; i++)
+ {
+ CMyComBSTR name;
+ NCOM::CPropVariant prop;
+ if (arcProps->GetArcProp(level, propIDs[i], &prop) != S_OK)
+ continue;
+ if (prop.vt != VT_EMPTY)
+ {
+ UString *s = NULL;
+ switch (propIDs[i])
+ {
+ case kpidError: s = &lev.Error; break;
+ case kpidPath: s = &lev.Path; break;
+ case kpidType: s = &lev.Type; break;
+ case kpidErrorType: s = &lev.ErrorType; break;
+ }
+ *s = (prop.vt == VT_BSTR) ? prop.bstrVal : L"?";
+ }
+ }
+
+ {
+ NCOM::CPropVariant prop;
+ if (arcProps->GetArcProp(level, kpidErrorFlags, &prop) == S_OK)
+ {
+ UInt32 flags = GetOpenArcErrorFlags(prop);
+ if (flags != 0)
+ lev.ErrorFlags = GetOpenArcErrorMessage(flags);
+ }
+ }
+
+ levels.Levels.Add(lev);
+ }
+}
+
+static UString GetBracedType(const wchar_t *type)
+{
+ UString s ('[');
+ s += type;
+ s += ']';
+ return s;
+}
+
+static void GetFolderError(CMyComPtr<IFolderFolder> &folder, UString &open_Errors, UString &nonOpen_Errors)
+{
+ CArcLevelsInfo levs;
+ GetFolderLevels(folder, levs);
+ open_Errors.Empty();
+ nonOpen_Errors.Empty();
+
+ FOR_VECTOR (i, levs.Levels)
+ {
+ bool isNonOpenLevel = (i == 0);
+ const CArcLevelInfo &lev = levs.Levels[levs.Levels.Size() - 1 - i];
+
+ UString m;
+
+ if (!lev.ErrorType.IsEmpty())
+ {
+ m = MyFormatNew(IDS_CANT_OPEN_AS_TYPE, GetBracedType(lev.ErrorType));
+ if (!isNonOpenLevel)
+ {
+ m.Add_LF();
+ m += MyFormatNew(IDS_IS_OPEN_AS_TYPE, GetBracedType(lev.Type));
+ }
+ }
+
+ if (!lev.Error.IsEmpty())
+ {
+ if (!m.IsEmpty())
+ m.Add_LF();
+ m += GetBracedType(lev.Type);
+ m += " : ";
+ m += GetNameOfProperty(kpidError, L"Error");
+ m += " : ";
+ m += lev.Error;
+ }
+
+ if (!lev.ErrorFlags.IsEmpty())
+ {
+ if (!m.IsEmpty())
+ m.Add_LF();
+ m += GetNameOfProperty(kpidErrorFlags, L"Errors");
+ m += ": ";
+ m += lev.ErrorFlags;
+ }
+
+ if (!m.IsEmpty())
+ {
+ if (isNonOpenLevel)
+ {
+ UString &s = nonOpen_Errors;
+ s += lev.Path;
+ s.Add_LF();
+ s += m;
+ }
+ else
+ {
+ UString &s = open_Errors;
+ if (!s.IsEmpty())
+ s += "--------------------\n";
+ s += lev.Path;
+ s.Add_LF();
+ s += m;
+ }
+ }
+ }
+}
+
+#ifdef _MSC_VER
+#pragma warning(error : 4702) // unreachable code
+#endif
+
+HRESULT CFfpOpen::OpenFileFolderPlugin(IInStream *inStream,
+ const FString &path, const UString &arcFormat, HWND parentWindow)
+{
+ /*
+ CObjectVector<CPluginInfo> plugins;
+ ReadFileFolderPluginInfoList(plugins);
+ */
+
+ FString extension, name, pureName, dot;
+
+ const int slashPos = path.ReverseFind_PathSepar();
+ FString dirPrefix;
+ FString fileName;
+ if (slashPos >= 0)
+ {
+ dirPrefix.SetFrom(path, (unsigned)(slashPos + 1));
+ fileName = path.Ptr((unsigned)(slashPos + 1));
+ }
+ else
+ fileName = path;
+
+ SplitNameToPureNameAndExtension(fileName, pureName, dot, extension);
+
+ /*
+ if (!extension.IsEmpty())
+ {
+ CExtInfo extInfo;
+ if (ReadInternalAssociation(extension, extInfo))
+ {
+ for (int i = extInfo.Plugins.Size() - 1; i >= 0; i--)
+ {
+ int pluginIndex = FindPlugin(plugins, extInfo.Plugins[i]);
+ if (pluginIndex >= 0)
+ {
+ const CPluginInfo plugin = plugins[pluginIndex];
+ plugins.Delete(pluginIndex);
+ plugins.Insert(0, plugin);
+ }
+ }
+ }
+ }
+ */
+
+ ErrorMessage.Empty();
+
+ // FOR_VECTOR (i, plugins)
+ // {
+ /*
+ const CPluginInfo &plugin = plugins[i];
+ if (!plugin.ClassID_Defined && !plugin.FilePath.IsEmpty())
+ continue;
+ */
+ CPluginLibrary library;
+
+ CThreadArchiveOpen t;
+
+ // if (plugin.FilePath.IsEmpty())
+ t.FolderManager = new CArchiveFolderManager;
+ /*
+ else if (library.LoadAndCreateManager(plugin.FilePath, plugin.ClassID, &t.FolderManager) != S_OK)
+ continue;
+ */
+
+ COpenArchiveCallback OpenCallbackSpec_loc;
+ t.OpenCallbackSpec = &OpenCallbackSpec_loc;
+ /*
+ t.OpenCallbackSpec = new COpenArchiveCallback;
+ t.OpenCallbackSpec_Ref = t.OpenCallbackSpec;
+ */
+ t.OpenCallbackSpec->PasswordIsDefined = Encrypted;
+ t.OpenCallbackSpec->Password = Password;
+ t.OpenCallbackSpec->ParentWindow = parentWindow;
+
+ /* COpenCallbackImp object will exist after Open stage for multivolume archives */
+ COpenCallbackImp *openCallbackSpec = new COpenCallbackImp;
+ t.OpenCallbackProgress = openCallbackSpec;
+ // openCallbackSpec->Callback_Ref = t.OpenCallbackSpec;
+ // we set pointer without reference counter:
+ openCallbackSpec->Callback =
+ // openCallbackSpec->ReOpenCallback =
+ t.OpenCallbackSpec;
+
+ if (inStream)
+ openCallbackSpec->SetSubArchiveName(fs2us(fileName));
+ else
+ {
+ RINOK(openCallbackSpec->Init2(dirPrefix, fileName))
+ }
+
+ t.InStream = inStream;
+ t.Path = fs2us(path);
+ t.ArcFormat = arcFormat;
+
+ const UString progressTitle = LangString(IDS_OPENNING);
+ {
+ CProgressDialog &pd = t.OpenCallbackSpec->ProgressDialog;
+ pd.MainWindow = parentWindow;
+ pd.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE);
+ pd.MainAddTitle = progressTitle + L' ';
+ pd.WaitMode = true;
+ }
+
+ {
+ NWindows::CThread thread;
+ const WRes wres = thread.Create(CThreadArchiveOpen::MyThreadFunction, &t);
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ t.OpenCallbackSpec->StartProgressDialog(progressTitle, thread);
+ }
+
+ /*
+ if archive is multivolume:
+ COpenCallbackImp object will exist after Open stage.
+ COpenCallbackImp object will be deleted when last reference
+ from each volume object (CInFileStreamVol) will be closed (when archive will be closed).
+ */
+ t.OpenCallbackProgress.Release();
+
+ if (t.Result != S_FALSE && t.Result != S_OK)
+ return t.Result;
+
+ if (t.Folder)
+ {
+ UString open_Errors, nonOpen_Errors;
+ GetFolderError(t.Folder, open_Errors, nonOpen_Errors);
+ if (!nonOpen_Errors.IsEmpty())
+ {
+ ErrorMessage = nonOpen_Errors;
+ // if (t.Result != S_OK) return t.Result;
+ /* if there are good open leves, and non0open level,
+ we could force error as critical error and return error here
+ but it's better to allow to open such rachives */
+ // return S_FALSE;
+ }
+ }
+
+ // if (openCallbackSpec->PasswordWasAsked)
+ {
+ Encrypted = t.OpenCallbackSpec->PasswordIsDefined;
+ Password = t.OpenCallbackSpec->Password;
+ }
+
+ if (t.Result == S_OK)
+ {
+ Library.Attach(library.Detach());
+ // Folder.Attach(t.Folder.Detach());
+ Folder = t.Folder;
+ }
+
+ return t.Result;
+ // }
+}
diff --git a/CPP/7zip/UI/FileManager/FileFolderPluginOpen.h b/CPP/7zip/UI/FileManager/FileFolderPluginOpen.h
new file mode 100644
index 0000000..8802765
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FileFolderPluginOpen.h
@@ -0,0 +1,27 @@
+// FileFolderPluginOpen.h
+
+#ifndef ZIP7_INC_FILE_FOLDER_PLUGIN_OPEN_H
+#define ZIP7_INC_FILE_FOLDER_PLUGIN_OPEN_H
+
+#include "../../../Windows/DLL.h"
+
+struct CFfpOpen
+{
+ Z7_CLASS_NO_COPY(CFfpOpen)
+public:
+ // out:
+ bool Encrypted;
+ UString Password;
+
+ NWindows::NDLL::CLibrary Library;
+ CMyComPtr<IFolderFolder> Folder;
+ UString ErrorMessage;
+
+ CFfpOpen(): Encrypted (false) {}
+
+ HRESULT OpenFileFolderPlugin(IInStream *inStream,
+ const FString &path, const UString &arcFormat, HWND parentWindow);
+};
+
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/FilePlugins.cpp b/CPP/7zip/UI/FileManager/FilePlugins.cpp
new file mode 100644
index 0000000..cf20970
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FilePlugins.cpp
@@ -0,0 +1,78 @@
+// FilePlugins.cpp
+
+#include "StdAfx.h"
+
+#include "../Agent/Agent.h"
+
+#include "FilePlugins.h"
+#include "PluginLoader.h"
+#include "StringUtils.h"
+
+int CExtDatabase::FindExt(const UString &ext) const
+{
+ FOR_VECTOR (i, Exts)
+ if (Exts[i].Ext.IsEqualTo_NoCase(ext))
+ return (int)i;
+ return -1;
+}
+
+void CExtDatabase::Read()
+{
+ /*
+ ReadFileFolderPluginInfoList(Plugins);
+ FOR_VECTOR (pluginIndex, Plugins)
+ */
+ {
+ // const CPluginInfo &plugin = Plugins[pluginIndex];
+
+ CPluginLibrary pluginLib;
+ CMyComPtr<IFolderManager> folderManager;
+
+ // if (plugin.FilePath.IsEmpty())
+ folderManager = new CArchiveFolderManager;
+ /*
+ else
+ {
+ if (!plugin.ClassID_Defined)
+ continue;
+ if (pluginLib.LoadAndCreateManager(plugin.FilePath, plugin.ClassID, &folderManager) != S_OK)
+ continue;
+ }
+ */
+ CMyComBSTR extBSTR;
+ if (folderManager->GetExtensions(&extBSTR) != S_OK)
+ return;
+ UStringVector exts;
+ SplitString((const wchar_t *)extBSTR, exts);
+ FOR_VECTOR (i, exts)
+ {
+ const UString &ext = exts[i];
+ #ifdef UNDER_CE
+ if (ext == L"cab")
+ continue;
+ #endif
+
+ Int32 iconIndex;
+ CMyComBSTR iconPath;
+ CPluginToIcon plugPair;
+ // plugPair.PluginIndex = pluginIndex;
+ if (folderManager->GetIconPath(ext, &iconPath, &iconIndex) == S_OK)
+ if (iconPath)
+ {
+ plugPair.IconPath = (const wchar_t *)iconPath;
+ plugPair.IconIndex = iconIndex;
+ }
+
+ const int index = FindExt(ext);
+ if (index >= 0)
+ Exts[index].Plugins.Add(plugPair);
+ else
+ {
+ CExtPlugins extInfo;
+ extInfo.Plugins.Add(plugPair);
+ extInfo.Ext = ext;
+ Exts.Add(extInfo);
+ }
+ }
+ }
+}
diff --git a/CPP/7zip/UI/FileManager/FilePlugins.h b/CPP/7zip/UI/FileManager/FilePlugins.h
new file mode 100644
index 0000000..db8ec39
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FilePlugins.h
@@ -0,0 +1,33 @@
+// FilePlugins.h
+
+#ifndef ZIP7_INC_FILE_PLUGINS_H
+#define ZIP7_INC_FILE_PLUGINS_H
+
+#include "RegistryPlugins.h"
+
+struct CPluginToIcon
+{
+ // unsigned PluginIndex;
+ int IconIndex;
+ UString IconPath;
+
+ CPluginToIcon(): IconIndex(-1) {}
+};
+
+struct CExtPlugins
+{
+ UString Ext;
+ CObjectVector<CPluginToIcon> Plugins;
+};
+
+class CExtDatabase
+{
+ int FindExt(const UString &ext) const;
+public:
+ CObjectVector<CExtPlugins> Exts;
+ // CObjectVector<CPluginInfo> Plugins;
+
+ void Read();
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/FoldersPage.cpp b/CPP/7zip/UI/FileManager/FoldersPage.cpp
new file mode 100644
index 0000000..7e74635
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FoldersPage.cpp
@@ -0,0 +1,172 @@
+// FoldersPage.cpp
+
+#include "StdAfx.h"
+
+#include "FoldersPageRes.h"
+#include "FoldersPage.h"
+
+#include "../FileManager/BrowseDialog.h"
+#include "../FileManager/HelpUtils.h"
+#include "../FileManager/LangUtils.h"
+
+using namespace NWindows;
+
+#ifdef Z7_LANG
+static const UInt32 kLangIDs[] =
+{
+ IDT_FOLDERS_WORKING_FOLDER,
+ IDR_FOLDERS_WORK_SYSTEM,
+ IDR_FOLDERS_WORK_CURRENT,
+ IDR_FOLDERS_WORK_SPECIFIED,
+ IDX_FOLDERS_WORK_FOR_REMOVABLE
+};
+#endif
+
+static const unsigned kWorkModeButtons[] =
+{
+ IDR_FOLDERS_WORK_SYSTEM,
+ IDR_FOLDERS_WORK_CURRENT,
+ IDR_FOLDERS_WORK_SPECIFIED
+};
+
+#define kFoldersTopic "fm/options.htm#folders"
+
+static const unsigned kNumWorkModeButtons = Z7_ARRAY_SIZE(kWorkModeButtons);
+
+bool CFoldersPage::OnInit()
+{
+ _initMode = true;
+ _needSave = false;
+
+ #ifdef Z7_LANG
+ LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
+ #endif
+ m_WorkDirInfo.Load();
+
+ CheckButton(IDX_FOLDERS_WORK_FOR_REMOVABLE, m_WorkDirInfo.ForRemovableOnly);
+
+ CheckRadioButton(
+ kWorkModeButtons[0],
+ kWorkModeButtons[kNumWorkModeButtons - 1],
+ kWorkModeButtons[m_WorkDirInfo.Mode]);
+
+ m_WorkPath.Init(*this, IDE_FOLDERS_WORK_PATH);
+
+ m_WorkPath.SetText(fs2us(m_WorkDirInfo.Path));
+
+ MyEnableControls();
+
+ _initMode = false;
+ return CPropertyPage::OnInit();
+}
+
+int CFoldersPage::GetWorkMode() const
+{
+ for (unsigned i = 0; i < kNumWorkModeButtons; i++)
+ if (IsButtonCheckedBool(kWorkModeButtons[i]))
+ return (int)i;
+ throw 0;
+}
+
+void CFoldersPage::MyEnableControls()
+{
+ bool enablePath = (GetWorkMode() == NWorkDir::NMode::kSpecified);
+ m_WorkPath.Enable(enablePath);
+ EnableItem(IDB_FOLDERS_WORK_PATH, enablePath);
+}
+
+void CFoldersPage::GetWorkDir(NWorkDir::CInfo &workDirInfo)
+{
+ UString s;
+ m_WorkPath.GetText(s);
+ workDirInfo.Path = us2fs(s);
+ workDirInfo.ForRemovableOnly = IsButtonCheckedBool(IDX_FOLDERS_WORK_FOR_REMOVABLE);
+ workDirInfo.Mode = NWorkDir::NMode::EEnum(GetWorkMode());
+}
+
+/*
+bool CFoldersPage::WasChanged()
+{
+ NWorkDir::CInfo workDirInfo;
+ GetWorkDir(workDirInfo);
+ return (workDirInfo.Mode != m_WorkDirInfo.Mode ||
+ workDirInfo.ForRemovableOnly != m_WorkDirInfo.ForRemovableOnly ||
+ workDirInfo.Path.Compare(m_WorkDirInfo.Path) != 0);
+}
+*/
+
+void CFoldersPage::ModifiedEvent()
+{
+ if (!_initMode)
+ {
+ _needSave = true;
+ Changed();
+ }
+ /*
+ if (WasChanged())
+ Changed();
+ else
+ UnChanged();
+ */
+}
+
+bool CFoldersPage::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ for (unsigned i = 0; i < kNumWorkModeButtons; i++)
+ if (buttonID == kWorkModeButtons[i])
+ {
+ MyEnableControls();
+ ModifiedEvent();
+ return true;
+ }
+
+ switch (buttonID)
+ {
+ case IDB_FOLDERS_WORK_PATH:
+ OnFoldersWorkButtonPath();
+ return true;
+ case IDX_FOLDERS_WORK_FOR_REMOVABLE:
+ break;
+ default:
+ return CPropertyPage::OnButtonClicked(buttonID, buttonHWND);
+ }
+
+ ModifiedEvent();
+ return true;
+}
+
+bool CFoldersPage::OnCommand(unsigned code, unsigned itemID, LPARAM lParam)
+{
+ if (code == EN_CHANGE && itemID == IDE_FOLDERS_WORK_PATH)
+ {
+ ModifiedEvent();
+ return true;
+ }
+ return CPropertyPage::OnCommand(code, itemID, lParam);
+}
+
+void CFoldersPage::OnFoldersWorkButtonPath()
+{
+ UString currentPath;
+ m_WorkPath.GetText(currentPath);
+ UString title = LangString(IDS_FOLDERS_SET_WORK_PATH_TITLE);
+ UString resultPath;
+ if (MyBrowseForFolder(*this, title, currentPath, resultPath))
+ m_WorkPath.SetText(resultPath);
+}
+
+LONG CFoldersPage::OnApply()
+{
+ if (_needSave)
+ {
+ GetWorkDir(m_WorkDirInfo);
+ m_WorkDirInfo.Save();
+ _needSave = false;
+ }
+ return PSNRET_NOERROR;
+}
+
+void CFoldersPage::OnNotifyHelp()
+{
+ ShowHelpWindow(kFoldersTopic);
+}
diff --git a/CPP/7zip/UI/FileManager/FoldersPage.h b/CPP/7zip/UI/FileManager/FoldersPage.h
new file mode 100644
index 0000000..09b6cdd
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FoldersPage.h
@@ -0,0 +1,32 @@
+// FoldersPage.h
+
+#ifndef ZIP7_INC_FOLDERS_PAGE_H
+#define ZIP7_INC_FOLDERS_PAGE_H
+
+#include "../../../Windows/Control/PropertyPage.h"
+
+#include "../Common/ZipRegistry.h"
+
+class CFoldersPage : public NWindows::NControl::CPropertyPage
+{
+ NWorkDir::CInfo m_WorkDirInfo;
+ NWindows::NControl::CDialogChildControl m_WorkPath;
+
+ bool _needSave;
+ bool _initMode;
+
+ void MyEnableControls();
+ void ModifiedEvent();
+
+ void OnFoldersWorkButtonPath();
+ int GetWorkMode() const;
+ void GetWorkDir(NWorkDir::CInfo &workDirInfo);
+ // bool WasChanged();
+ virtual bool OnInit() Z7_override;
+ virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override;
+ virtual void OnNotifyHelp() Z7_override;
+ virtual LONG OnApply() Z7_override;
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/FoldersPage.rc b/CPP/7zip/UI/FileManager/FoldersPage.rc
new file mode 100644
index 0000000..cb345ea
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FoldersPage.rc
@@ -0,0 +1,23 @@
+#include "FoldersPageRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 240
+#define yc 100
+
+IDD_FOLDERS MY_PAGE
+#include "FoldersPage2.rc"
+
+#ifdef UNDER_CE
+
+#undef xc
+#define xc SMALL_PAGE_SIZE_X
+
+IDD_FOLDERS_2 MY_PAGE
+#include "FoldersPage2.rc"
+
+#endif
+
+STRINGTABLE
+BEGIN
+ IDS_FOLDERS_SET_WORK_PATH_TITLE "Specify a location for temporary archive files."
+END
diff --git a/CPP/7zip/UI/FileManager/FoldersPage2.rc b/CPP/7zip/UI/FileManager/FoldersPage2.rc
new file mode 100644
index 0000000..9b9276e
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FoldersPage2.rc
@@ -0,0 +1,16 @@
+CAPTION "Folders"
+BEGIN
+ // GROUPBOX "&Working folder", IDT_FOLDERS_WORKING_FOLDER, m, m, xc, 98
+
+ LTEXT "&Working folder", IDT_FOLDERS_WORKING_FOLDER, m, m, xc, 8
+ CONTROL "&System temp folder", IDR_FOLDERS_WORK_SYSTEM, "Button", BS_AUTORADIOBUTTON | WS_GROUP,
+ m, 20, xc, 10
+ CONTROL "&Current", IDR_FOLDERS_WORK_CURRENT, "Button", BS_AUTORADIOBUTTON,
+ m, 34, xc, 10
+ CONTROL "Specified:", IDR_FOLDERS_WORK_SPECIFIED, "Button", BS_AUTORADIOBUTTON,
+ m, 48, xc, 10
+ EDITTEXT IDE_FOLDERS_WORK_PATH, m + m, 62, xc - m - m - bxsDots, 14, ES_AUTOHSCROLL
+ PUSHBUTTON "...", IDB_FOLDERS_WORK_PATH, xs - m - bxsDots, 61, bxsDots, bys
+ CONTROL "Use for removable drives only", IDX_FOLDERS_WORK_FOR_REMOVABLE, MY_CHECKBOX,
+ m, 86, xc, 10
+END
diff --git a/CPP/7zip/UI/FileManager/FoldersPageRes.h b/CPP/7zip/UI/FileManager/FoldersPageRes.h
new file mode 100644
index 0000000..ba9ab73
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/FoldersPageRes.h
@@ -0,0 +1,12 @@
+#define IDD_FOLDERS 2400
+#define IDD_FOLDERS_2 12400
+
+#define IDT_FOLDERS_WORKING_FOLDER 2401
+#define IDR_FOLDERS_WORK_SYSTEM 2402
+#define IDR_FOLDERS_WORK_CURRENT 2403
+#define IDR_FOLDERS_WORK_SPECIFIED 2404
+#define IDX_FOLDERS_WORK_FOR_REMOVABLE 2405
+#define IDS_FOLDERS_SET_WORK_PATH_TITLE 2406
+
+#define IDE_FOLDERS_WORK_PATH 100
+#define IDB_FOLDERS_WORK_PATH 101
diff --git a/CPP/7zip/UI/FileManager/FormatUtils.cpp b/CPP/7zip/UI/FileManager/FormatUtils.cpp
index 4f7ef74..2143c3f 100644
--- a/CPP/7zip/UI/FileManager/FormatUtils.cpp
+++ b/CPP/7zip/UI/FileManager/FormatUtils.cpp
@@ -1,28 +1,28 @@
-// FormatUtils.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/IntToString.h"
-
-#include "FormatUtils.h"
-
-#include "LangUtils.h"
-
-UString NumberToString(UInt64 number)
-{
- wchar_t numberString[32];
- ConvertUInt64ToString(number, numberString);
- return numberString;
-}
-
-UString MyFormatNew(const UString &format, const UString &argument)
-{
- UString result = format;
- result.Replace(L"{0}", argument);
- return result;
-}
-
-UString MyFormatNew(UINT resourceID, const UString &argument)
-{
- return MyFormatNew(LangString(resourceID), argument);
-}
+// FormatUtils.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+
+#include "FormatUtils.h"
+
+#include "LangUtils.h"
+
+UString NumberToString(UInt64 number)
+{
+ wchar_t numberString[32];
+ ConvertUInt64ToString(number, numberString);
+ return numberString;
+}
+
+UString MyFormatNew(const UString &format, const UString &argument)
+{
+ UString result = format;
+ result.Replace(L"{0}", argument);
+ return result;
+}
+
+UString MyFormatNew(UINT resourceID, const UString &argument)
+{
+ return MyFormatNew(LangString(resourceID), argument);
+}
diff --git a/CPP/7zip/UI/FileManager/FormatUtils.h b/CPP/7zip/UI/FileManager/FormatUtils.h
index f221cd2..1db08ef 100644
--- a/CPP/7zip/UI/FileManager/FormatUtils.h
+++ b/CPP/7zip/UI/FileManager/FormatUtils.h
@@ -1,14 +1,14 @@
-// FormatUtils.h
-
-#ifndef __FORMAT_UTILS_H
-#define __FORMAT_UTILS_H
-
-#include "../../../Common/MyTypes.h"
-#include "../../../Common/MyString.h"
-
-UString NumberToString(UInt64 number);
-
-UString MyFormatNew(const UString &format, const UString &argument);
-UString MyFormatNew(UINT resourceID, const UString &argument);
-
-#endif
+// FormatUtils.h
+
+#ifndef ZIP7_INC_FORMAT_UTILS_H
+#define ZIP7_INC_FORMAT_UTILS_H
+
+#include "../../../Common/MyTypes.h"
+#include "../../../Common/MyString.h"
+
+UString NumberToString(UInt64 number);
+
+UString MyFormatNew(const UString &format, const UString &argument);
+UString MyFormatNew(UINT resourceID, const UString &argument);
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/HelpUtils.cpp b/CPP/7zip/UI/FileManager/HelpUtils.cpp
new file mode 100644
index 0000000..d5b6a58
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/HelpUtils.cpp
@@ -0,0 +1,78 @@
+// HelpUtils.cpp
+
+#include "StdAfx.h"
+
+#include "HelpUtils.h"
+
+#if defined(UNDER_CE) || defined(__MINGW32_VERSION)
+
+void ShowHelpWindow(LPCSTR)
+{
+}
+
+#else
+
+/* USE_EXTERNAL_HELP creates new help process window for each HtmlHelp() call.
+ HtmlHelp() call uses one window. */
+
+#if defined(__MINGW32_VERSION) /* || defined(Z7_OLD_WIN_SDK) */
+#define USE_EXTERNAL_HELP
+#endif
+
+// #define USE_EXTERNAL_HELP
+
+#ifdef USE_EXTERNAL_HELP
+
+#include "../../../Windows/ProcessUtils.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileName.h"
+
+#else
+#include <HtmlHelp.h>
+#endif
+
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/DLL.h"
+
+#define kHelpFileName "7-zip.chm::/"
+
+void ShowHelpWindow(LPCSTR topicFile)
+{
+ FString path = NWindows::NDLL::GetModuleDirPrefix();
+ path += kHelpFileName;
+ path += topicFile;
+ #ifdef USE_EXTERNAL_HELP
+ FString prog;
+
+ #ifdef UNDER_CE
+ prog = "\\Windows\\";
+ #else
+ if (!NWindows::NFile::NDir::GetWindowsDir(prog))
+ return;
+ NWindows::NFile::NName::NormalizeDirPathPrefix(prog);
+ #endif
+ prog += "hh.exe";
+
+ UString params;
+ params += '"';
+ params += fs2us(path);
+ params += '"';
+
+ NWindows::CProcess process;
+ const WRes wres = process.Create(fs2us(prog), params, NULL); // curDir);
+ if (wres != 0)
+ {
+ /*
+ HRESULT hres = HRESULT_FROM_WIN32(wres);
+ ErrorMessageHRESULT(hres, imageName);
+ return hres;
+ */
+ }
+ #else
+ // HWND hwnd = NULL;
+ HtmlHelp(NULL, GetSystemString(fs2us(path)), HH_DISPLAY_TOPIC, 0);
+ #endif
+}
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/HelpUtils.h b/CPP/7zip/UI/FileManager/HelpUtils.h
new file mode 100644
index 0000000..d7bdf45
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/HelpUtils.h
@@ -0,0 +1,10 @@
+// HelpUtils.h
+
+#ifndef ZIP7_INC_HELP_UTILS_H
+#define ZIP7_INC_HELP_UTILS_H
+
+#include "../../../Common/MyString.h"
+
+void ShowHelpWindow(LPCSTR topicFile);
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/IFolder.h b/CPP/7zip/UI/FileManager/IFolder.h
new file mode 100644
index 0000000..1ebdf7e
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/IFolder.h
@@ -0,0 +1,187 @@
+// IFolder.h
+
+#ifndef ZIP7_INC_IFOLDER_H
+#define ZIP7_INC_IFOLDER_H
+
+#include "../../IProgress.h"
+#include "../../IStream.h"
+
+Z7_PURE_INTERFACES_BEGIN
+
+#define Z7_IFACE_CONSTR_FOLDER_SUB(i, base, n) \
+ Z7_DECL_IFACE_7ZIP_SUB(i, base, 8, n) \
+ { Z7_IFACE_COM7_PURE(i) };
+
+#define Z7_IFACE_CONSTR_FOLDER(i, n) \
+ Z7_IFACE_CONSTR_FOLDER_SUB(i, IUnknown, n)
+
+namespace NPlugin
+{
+ enum
+ {
+ kName = 0,
+ kType,
+ kClassID,
+ kOptionsClassID
+ };
+}
+
+#define Z7_IFACEM_IFolderFolder(x) \
+ x(LoadItems()) \
+ x(GetNumberOfItems(UInt32 *numItems)) \
+ x(GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value)) \
+ x(BindToFolder(UInt32 index, IFolderFolder **resultFolder)) \
+ x(BindToFolder(const wchar_t *name, IFolderFolder **resultFolder)) \
+ x(BindToParentFolder(IFolderFolder **resultFolder)) \
+ x(GetNumberOfProperties(UInt32 *numProperties)) \
+ x(GetPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \
+ x(GetFolderProperty(PROPID propID, PROPVARIANT *value)) \
+
+Z7_IFACE_CONSTR_FOLDER(IFolderFolder, 0x00)
+
+/*
+ IFolderAltStreams::
+ BindToAltStreams((UInt32)(Int32)-1, ... ) means alt streams of that folder
+*/
+
+#define Z7_IFACEM_IFolderAltStreams(x) \
+ x(BindToAltStreams(UInt32 index, IFolderFolder **resultFolder)) \
+ x(BindToAltStreams(const wchar_t *name, IFolderFolder **resultFolder)) \
+ x(AreAltStreamsSupported(UInt32 index, Int32 *isSupported)) \
+
+Z7_IFACE_CONSTR_FOLDER(IFolderAltStreams, 0x17)
+
+#define Z7_IFACEM_IFolderWasChanged(x) \
+ x(WasChanged(Int32 *wasChanged))
+Z7_IFACE_CONSTR_FOLDER(IFolderWasChanged, 0x04)
+
+ /* x(SetTotalFiles(UInt64 total)) */ \
+ /* x(SetCompletedFiles(const UInt64 *completedValue)) */ \
+#define Z7_IFACEM_IFolderOperationsExtractCallback(x) \
+ x(AskWrite( \
+ const wchar_t *srcPath, \
+ Int32 srcIsFolder, \
+ const FILETIME *srcTime, \
+ const UInt64 *srcSize, \
+ const wchar_t *destPathRequest, \
+ BSTR *destPathResult, \
+ Int32 *writeAnswer)) \
+ x(ShowMessage(const wchar_t *message)) \
+ x(SetCurrentFilePath(const wchar_t *filePath)) \
+ x(SetNumFiles(UInt64 numFiles)) \
+
+Z7_IFACE_CONSTR_FOLDER_SUB(IFolderOperationsExtractCallback, IProgress, 0x0B)
+
+
+#define Z7_IFACEM_IFolderOperations(x) \
+ x(CreateFolder(const wchar_t *name, IProgress *progress)) \
+ x(CreateFile(const wchar_t *name, IProgress *progress)) \
+ x(Rename(UInt32 index, const wchar_t *newName, IProgress *progress)) \
+ x(Delete(const UInt32 *indices, UInt32 numItems, IProgress *progress)) \
+ x(CopyTo(Int32 moveMode, const UInt32 *indices, UInt32 numItems, \
+ Int32 includeAltStreams, Int32 replaceAltStreamCharsMode, \
+ const wchar_t *path, IFolderOperationsExtractCallback *callback)) \
+ x(CopyFrom(Int32 moveMode, const wchar_t *fromFolderPath, \
+ const wchar_t * const *itemsPaths, UInt32 numItems, IProgress *progress)) \
+ x(SetProperty(UInt32 index, PROPID propID, const PROPVARIANT *value, IProgress *progress)) \
+ x(CopyFromFile(UInt32 index, const wchar_t *fullFilePath, IProgress *progress)) \
+
+Z7_IFACE_CONSTR_FOLDER(IFolderOperations, 0x13)
+
+/*
+FOLDER_INTERFACE2(IFolderOperationsDeleteToRecycleBin, 0x06, 0x03)
+{
+ x(DeleteToRecycleBin(const UInt32 *indices, UInt32 numItems, IProgress *progress)) \
+};
+*/
+
+#define Z7_IFACEM_IFolderGetSystemIconIndex(x) \
+ x(GetSystemIconIndex(UInt32 index, Int32 *iconIndex))
+Z7_IFACE_CONSTR_FOLDER(IFolderGetSystemIconIndex, 0x07)
+
+#define Z7_IFACEM_IFolderGetItemFullSize(x) \
+ x(GetItemFullSize(UInt32 index, PROPVARIANT *value, IProgress *progress))
+Z7_IFACE_CONSTR_FOLDER(IFolderGetItemFullSize, 0x08)
+
+#define Z7_IFACEM_IFolderCalcItemFullSize(x) \
+ x(CalcItemFullSize(UInt32 index, IProgress *progress))
+Z7_IFACE_CONSTR_FOLDER(IFolderCalcItemFullSize, 0x14)
+
+#define Z7_IFACEM_IFolderClone(x) \
+ x(Clone(IFolderFolder **resultFolder))
+Z7_IFACE_CONSTR_FOLDER(IFolderClone, 0x09)
+
+#define Z7_IFACEM_IFolderSetFlatMode(x) \
+ x(SetFlatMode(Int32 flatMode))
+Z7_IFACE_CONSTR_FOLDER(IFolderSetFlatMode, 0x0A)
+
+/*
+#define Z7_IFACEM_IFolderSetShowNtfsStreamsMode(x) \
+ x(SetShowNtfsStreamsMode(Int32 showStreamsMode))
+Z7_IFACE_CONSTR_FOLDER(IFolderSetShowNtfsStreamsMode, 0xFA)
+*/
+
+#define Z7_IFACEM_IFolderProperties(x) \
+ x(GetNumberOfFolderProperties(UInt32 *numProperties)) \
+ x(GetFolderPropertyInfo(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \
+
+Z7_IFACE_CONSTR_FOLDER(IFolderProperties, 0x0E)
+
+#define Z7_IFACEM_IFolderArcProps(x) \
+ x(GetArcNumLevels(UInt32 *numLevels)) \
+ x(GetArcProp(UInt32 level, PROPID propID, PROPVARIANT *value)) \
+ x(GetArcNumProps(UInt32 level, UInt32 *numProps)) \
+ x(GetArcPropInfo(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \
+ x(GetArcProp2(UInt32 level, PROPID propID, PROPVARIANT *value)) \
+ x(GetArcNumProps2(UInt32 level, UInt32 *numProps)) \
+ x(GetArcPropInfo2(UInt32 level, UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \
+
+Z7_IFACE_CONSTR_FOLDER(IFolderArcProps, 0x10)
+
+#define Z7_IFACEM_IGetFolderArcProps(x) \
+ x(GetFolderArcProps(IFolderArcProps **object))
+Z7_IFACE_CONSTR_FOLDER(IGetFolderArcProps, 0x11)
+
+#define Z7_IFACEM_IFolderCompare(x) \
+ x##2(Int32, CompareItems(UInt32 index1, UInt32 index2, PROPID propID, Int32 propIsRaw))
+Z7_IFACE_CONSTR_FOLDER(IFolderCompare, 0x15)
+
+#define Z7_IFACEM_IFolderGetItemName(x) \
+ x(GetItemName(UInt32 index, const wchar_t **name, unsigned *len)) \
+ x(GetItemPrefix(UInt32 index, const wchar_t **name, unsigned *len)) \
+ x##2(UInt64, GetItemSize(UInt32 index)) \
+
+Z7_IFACE_CONSTR_FOLDER(IFolderGetItemName, 0x16)
+
+
+#define Z7_IFACEM_IFolderManager(x) \
+ x(OpenFolderFile(IInStream *inStream, const wchar_t *filePath, const wchar_t *arcFormat, IFolderFolder **resultFolder, IProgress *progress)) \
+ x(GetExtensions(BSTR *extensions)) \
+ x(GetIconPath(const wchar_t *ext, BSTR *iconPath, Int32 *iconIndex)) \
+
+ // x(GetTypes(BSTR *types))
+ // x(CreateFolderFile(const wchar_t *type, const wchar_t *filePath, IProgress *progress))
+
+Z7_DECL_IFACE_7ZIP(IFolderManager, 9, 5)
+ { Z7_IFACE_COM7_PURE(IFolderManager) };
+
+/*
+ const CMy_STATPROPSTG_2 &srcItem = k[index]; \
+ *propID = srcItem.propid; *varType = srcItem.vt; *name = 0; return S_OK; } \
+*/
+#define IMP_IFolderFolder_GetProp(fn, k) \
+ Z7_COM7F_IMF(fn(UInt32 index, BSTR *name, PROPID *propID, VARTYPE *varType)) \
+ { if (index >= Z7_ARRAY_SIZE(k)) return E_INVALIDARG; \
+ *propID = k[index]; *varType = k7z_PROPID_To_VARTYPE[(unsigned)*propID]; *name = NULL; return S_OK; } \
+
+#define IMP_IFolderFolder_Props(c) \
+ Z7_COM7F_IMF(c::GetNumberOfProperties(UInt32 *numProperties)) \
+ { *numProperties = Z7_ARRAY_SIZE(kProps); return S_OK; } \
+ IMP_IFolderFolder_GetProp(c::GetPropertyInfo, kProps)
+
+
+int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2);
+// int CompareFileNames_ForFolderList(const FChar *s1, const FChar *s2);
+
+Z7_PURE_INTERFACES_END
+#endif
diff --git a/CPP/7zip/UI/FileManager/Info.bmp b/CPP/7zip/UI/FileManager/Info.bmp
new file mode 100644
index 0000000..d769a66
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Info.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/Info2.bmp b/CPP/7zip/UI/FileManager/Info2.bmp
new file mode 100644
index 0000000..af724d2
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Info2.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/LangPage.cpp b/CPP/7zip/UI/FileManager/LangPage.cpp
new file mode 100644
index 0000000..ec1dd2e
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LangPage.cpp
@@ -0,0 +1,361 @@
+// LangPage.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/Lang.h"
+
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/ResourceString.h"
+
+#include "HelpUtils.h"
+#include "LangPage.h"
+#include "LangPageRes.h"
+#include "LangUtils.h"
+#include "RegistryUtils.h"
+
+using namespace NWindows;
+
+
+static const unsigned k_NumLangLines_EN = 429;
+
+#ifdef Z7_LANG
+static const UInt32 kLangIDs[] =
+{
+ IDT_LANG_LANG
+};
+#endif
+
+#define kLangTopic "fm/options.htm#language"
+
+
+struct CLangListRecord
+{
+ int Order;
+ unsigned LangInfoIndex;
+ bool IsSelected;
+ UString Mark;
+ UString Name;
+
+ CLangListRecord(): Order (10), IsSelected(false) {}
+ int Compare(const CLangListRecord &a) const
+ {
+ if (Order < a.Order) return -1;
+ if (Order > a.Order) return 1;
+ return MyStringCompareNoCase(Name, a.Name);
+ }
+};
+
+
+static void NativeLangString(UString &dest, const wchar_t *s)
+{
+ dest += " (";
+ dest += s;
+ dest += ')';
+}
+
+bool LangOpen(CLang &lang, CFSTR fileName);
+
+bool CLangPage::OnInit()
+{
+#ifdef Z7_LANG
+ LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
+#endif
+ _langCombo.Attach(GetItem(IDC_LANG_LANG));
+
+
+ unsigned listRecords_SelectedIndex = 0;
+
+ CObjectVector<CLangListRecord> listRecords;
+ {
+ CLangListRecord listRecord;
+ listRecord.Order = 0;
+ listRecord.Mark = "---";
+ listRecord.Name = MyLoadString(IDS_LANG_ENGLISH);
+ NativeLangString(listRecord.Name, MyLoadString(IDS_LANG_NATIVE));
+ listRecord.LangInfoIndex = _langs.Size();
+ listRecords.Add(listRecord);
+ }
+
+ AStringVector names;
+ unsigned subLangIndex = 0;
+ Lang_GetShortNames_for_DefaultLang(names, subLangIndex);
+
+ const FString dirPrefix = GetLangDirPrefix();
+ NFile::NFind::CEnumerator enumerator;
+ enumerator.SetDirPrefix(dirPrefix);
+ NFile::NFind::CFileInfo fi;
+
+ CLang lang_en;
+ {
+ CLangInfo &langInfo = _langs.AddNew();
+ langInfo.Name = "-";
+ if (LangOpen(lang_en, dirPrefix + FTEXT("en.ttt")))
+ {
+ langInfo.NumLines = lang_en._ids.Size();
+ // langInfo.Comments = lang_en.Comments;
+ }
+ else
+ langInfo.NumLines = k_NumLangLines_EN;
+ NumLangLines_EN = langInfo.NumLines;
+ }
+
+ CLang lang;
+ UString error;
+ UString n;
+
+ while (enumerator.Next(fi))
+ {
+ if (fi.IsDir())
+ continue;
+ const unsigned kExtSize = 4;
+ if (fi.Name.Len() < kExtSize)
+ continue;
+ const unsigned pos = fi.Name.Len() - kExtSize;
+ if (!StringsAreEqualNoCase_Ascii(fi.Name.Ptr(pos), ".txt"))
+ {
+ // if (!StringsAreEqualNoCase_Ascii(fi.Name.Ptr(pos), ".ttt"))
+ continue;
+ }
+
+ if (!LangOpen(lang, dirPrefix + fi.Name))
+ {
+ error.Add_Space_if_NotEmpty();
+ error += fs2us(fi.Name);
+ continue;
+ }
+
+ const UString shortName = fs2us(fi.Name.Left(pos));
+
+ CLangListRecord listRecord;
+ if (!names.IsEmpty())
+ {
+ for (unsigned i = 0; i < names.Size(); i++)
+ if (shortName.IsEqualTo_Ascii_NoCase(names[i]))
+ {
+ if (subLangIndex == i || names.Size() == 1)
+ {
+ listRecord.Mark = "***";
+ // listRecord.Order = 1;
+ }
+ else
+ {
+ listRecord.Mark = "+++";
+ // listRecord.Order = 2;
+ }
+ break;
+ }
+ if (listRecord.Mark.IsEmpty())
+ {
+ const int minusPos = shortName.Find(L'-');
+ if (minusPos >= 0)
+ {
+ const UString shortName2 = shortName.Left(minusPos);
+ if (shortName2.IsEqualTo_Ascii_NoCase(names[0]))
+ {
+ listRecord.Mark = "+++";
+ // listRecord.Order = 3;
+ }
+ }
+ }
+ }
+ UString s = shortName;
+ const wchar_t *eng = lang.Get(IDS_LANG_ENGLISH);
+ if (eng)
+ s = eng;
+ const wchar_t *native = lang.Get(IDS_LANG_NATIVE);
+ if (native)
+ NativeLangString(s, native);
+
+ listRecord.Name = s;
+ listRecord.LangInfoIndex = _langs.Size();
+ listRecords.Add(listRecord);
+ if (g_LangID.IsEqualTo_NoCase(shortName))
+ listRecords_SelectedIndex = listRecords.Size() - 1;
+
+ CLangInfo &langInfo = _langs.AddNew();
+ langInfo.Comments = lang.Comments;
+ langInfo.Name = shortName;
+ unsigned numLines = lang._ids.Size();
+ if (!lang_en.IsEmpty())
+ {
+ numLines = 0;
+ unsigned i1 = 0;
+ unsigned i2 = 0;
+ for (;;)
+ {
+ UInt32 id1 = (UInt32)0 - 1;
+ UInt32 id2 = (UInt32)0 - 1;
+ bool id1_defined = false;
+ bool id2_defined = false;
+ if (i1 < lang_en._ids.Size())
+ {
+ id1 = lang_en._ids[i1];
+ id1_defined = true;
+ }
+ if (i2 < lang._ids.Size())
+ {
+ id2 = lang._ids[i2];
+ id2_defined = true;
+ }
+
+ bool id1_is_smaller = true;
+ if (id1_defined)
+ {
+ if (id2_defined)
+ {
+ if (id1 == id2)
+ {
+ i1++;
+ i2++;
+ numLines++;
+ continue;
+ }
+ if (id1 > id2)
+ id1_is_smaller = false;
+ }
+ }
+ else if (!id2_defined)
+ break;
+ else
+ id1_is_smaller = false;
+
+ n.Empty();
+ if (id1_is_smaller)
+ {
+ n.Add_UInt32(id1);
+ n += " : ";
+ n += lang_en.Get_by_index(i1);
+ langInfo.MissingLines.Add(n);
+ i1++;
+ }
+ else
+ {
+ n.Add_UInt32(id2);
+ n += " : ";
+ n += lang.Get_by_index(i2);
+ langInfo.ExtraLines.Add(n);
+ i2++;
+ }
+ }
+ }
+ langInfo.NumLines = numLines + langInfo.ExtraLines.Size();
+ }
+
+ listRecords[listRecords_SelectedIndex].IsSelected = true;
+
+ listRecords.Sort();
+ FOR_VECTOR (i, listRecords)
+ {
+ const CLangListRecord &rec= listRecords[i];
+ UString temp = rec.Name;
+ if (!rec.Mark.IsEmpty())
+ {
+ temp += " ";
+ temp += rec.Mark;
+ }
+ const int index = (int)_langCombo.AddString(temp);
+ _langCombo.SetItemData(index, (LPARAM)rec.LangInfoIndex);
+ if (rec.IsSelected)
+ _langCombo.SetCurSel(index);
+ }
+
+ ShowLangInfo();
+
+ if (!error.IsEmpty())
+ MessageBoxW(NULL, error, L"Error in Lang file", MB_ICONERROR);
+ return CPropertyPage::OnInit();
+}
+
+LONG CLangPage::OnApply()
+{
+ if (_needSave)
+ {
+ const int pathIndex = (int)_langCombo.GetItemData_of_CurSel();
+ if ((unsigned)pathIndex < _langs.Size())
+ SaveRegLang(_langs[pathIndex].Name);
+ }
+ _needSave = false;
+ #ifdef Z7_LANG
+ ReloadLang();
+ #endif
+ LangWasChanged = true;
+ return PSNRET_NOERROR;
+}
+
+void CLangPage::OnNotifyHelp()
+{
+ ShowHelpWindow(kLangTopic);
+}
+
+bool CLangPage::OnCommand(unsigned code, unsigned itemID, LPARAM param)
+{
+ if (code == CBN_SELCHANGE && itemID == IDC_LANG_LANG)
+ {
+ _needSave = true;
+ Changed();
+ ShowLangInfo();
+ return true;
+ }
+ return CPropertyPage::OnCommand(code, itemID, param);
+}
+
+static void AddVectorToString(UString &s, const UStringVector &v)
+{
+ UString a;
+ FOR_VECTOR (i, v)
+ {
+ if (i >= 50)
+ break;
+ a = v[i];
+ if (a.Len() > 1500)
+ continue;
+ if (a[0] == ';')
+ {
+ a.DeleteFrontal(1);
+ a.Trim();
+ }
+ s += a;
+ s.Add_LF();
+ }
+}
+
+static void AddVectorToString2(UString &s, const char *name, const UStringVector &v)
+{
+ if (v.IsEmpty())
+ return;
+ s.Add_LF();
+ s += "------ ";
+ s += name;
+ s += ": ";
+ s.Add_UInt32(v.Size());
+ s += " :";
+ s.Add_LF();
+ AddVectorToString(s, v);
+}
+
+void CLangPage::ShowLangInfo()
+{
+ UString s;
+ const int pathIndex = (int)_langCombo.GetItemData_of_CurSel();
+ if ((unsigned)pathIndex < _langs.Size())
+ {
+ const CLangInfo &langInfo = _langs[pathIndex];
+ const unsigned numLines = langInfo.NumLines;
+ s += langInfo.Name;
+ s += " : ";
+ s.Add_UInt32(numLines);
+ if (NumLangLines_EN != 0)
+ {
+ s += " / ";
+ s.Add_UInt32(NumLangLines_EN);
+ s += " = ";
+ s.Add_UInt32(numLines * 100 / NumLangLines_EN);
+ s += "%";
+ }
+ s.Add_LF();
+ AddVectorToString(s, langInfo.Comments);
+ AddVectorToString2(s, "Missing lines", langInfo.MissingLines);
+ AddVectorToString2(s, "Extra lines", langInfo.ExtraLines);
+ }
+ SetItemText(IDT_LANG_INFO, s);
+}
diff --git a/CPP/7zip/UI/FileManager/LangPage.h b/CPP/7zip/UI/FileManager/LangPage.h
new file mode 100644
index 0000000..e37ba05
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LangPage.h
@@ -0,0 +1,36 @@
+// LangPage.h
+
+#ifndef ZIP7_INC_LANG_PAGE_H
+#define ZIP7_INC_LANG_PAGE_H
+
+#include "../../../Windows/Control/PropertyPage.h"
+#include "../../../Windows/Control/ComboBox.h"
+
+struct CLangInfo
+{
+ unsigned NumLines;
+ UString Name;
+ UStringVector Comments;
+ UStringVector MissingLines;
+ UStringVector ExtraLines;
+};
+
+class CLangPage: public NWindows::NControl::CPropertyPage
+{
+ NWindows::NControl::CComboBox _langCombo;
+ CObjectVector<CLangInfo> _langs;
+ unsigned NumLangLines_EN;
+ bool _needSave;
+
+ void ShowLangInfo();
+public:
+ bool LangWasChanged;
+
+ CLangPage(): _needSave(false), LangWasChanged(false) {}
+ virtual bool OnInit() Z7_override;
+ virtual void OnNotifyHelp() Z7_override;
+ virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM param) Z7_override;
+ virtual LONG OnApply() Z7_override;
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/LangPage.rc b/CPP/7zip/UI/FileManager/LangPage.rc
new file mode 100644
index 0000000..506f102
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LangPage.rc
@@ -0,0 +1,40 @@
+#include "LangPageRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 240
+#define yc 252
+
+#define y 32
+
+IDD_LANG DIALOG 0, 0, xs, ys MY_PAGE_STYLE MY_FONT
+CAPTION "Language"
+{
+ LTEXT "Language:", IDT_LANG_LANG, m, m, xc, 8
+ COMBOBOX IDC_LANG_LANG, m, 20, 160, yc - 20, MY_COMBO // MY_COMBO_SORTED
+ LTEXT "", IDT_LANG_INFO, m, m + y, xc, yc - y, SS_NOPREFIX
+}
+
+
+#ifdef UNDER_CE
+
+#undef m
+#undef xc
+
+#define m 4
+#define xc (SMALL_PAGE_SIZE_X + 8)
+
+IDD_LANG_2 MY_PAGE
+CAPTION "Language"
+{
+ LTEXT "Language:", IDT_LANG_LANG, m, m, xc, 8
+ COMBOBOX IDC_LANG_LANG, m, 20, xc, yc - 20, MY_COMBO // MY_COMBO_SORTED
+}
+
+#endif
+
+
+STRINGTABLE
+BEGIN
+ IDS_LANG_ENGLISH "English"
+ IDS_LANG_NATIVE "English"
+END
diff --git a/CPP/7zip/UI/FileManager/LangPageRes.h b/CPP/7zip/UI/FileManager/LangPageRes.h
new file mode 100644
index 0000000..a1ad30f
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LangPageRes.h
@@ -0,0 +1,9 @@
+#define IDD_LANG 2101
+#define IDD_LANG_2 12101
+
+#define IDS_LANG_ENGLISH 1
+#define IDS_LANG_NATIVE 2
+
+#define IDT_LANG_LANG 2102
+#define IDC_LANG_LANG 100
+#define IDT_LANG_INFO 101
diff --git a/CPP/7zip/UI/FileManager/LangUtils.cpp b/CPP/7zip/UI/FileManager/LangUtils.cpp
new file mode 100644
index 0000000..4c9d16f
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LangUtils.cpp
@@ -0,0 +1,326 @@
+// LangUtils.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/Lang.h"
+
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/Synchronization.h"
+#include "../../../Windows/Window.h"
+
+#include "LangUtils.h"
+#include "RegistryUtils.h"
+
+using namespace NWindows;
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+UString g_LangID;
+
+// static
+CLang g_Lang;
+static bool g_Loaded = false;
+static NSynchronization::CCriticalSection g_CriticalSection;
+
+bool LangOpen(CLang &lang, CFSTR fileName);
+bool LangOpen(CLang &lang, CFSTR fileName)
+{
+ return lang.Open(fileName, "7-Zip");
+}
+
+FString GetLangDirPrefix()
+{
+ return NDLL::GetModuleDirPrefix() + FTEXT("Lang") FSTRING_PATH_SEPARATOR;
+}
+
+#ifdef Z7_LANG
+
+void LoadLangOneTime()
+{
+ NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
+ if (g_Loaded)
+ return;
+ g_Loaded = true;
+ ReloadLang();
+}
+
+void LangSetDlgItemText(HWND dialog, UInt32 controlID, UInt32 langID)
+{
+ const wchar_t *s = g_Lang.Get(langID);
+ if (s)
+ {
+ CWindow window(GetDlgItem(dialog, (int)controlID));
+ window.SetText(s);
+ }
+}
+
+static const CIDLangPair kLangPairs[] =
+{
+ { IDOK, 401 },
+ { IDCANCEL, 402 },
+ { IDYES, 406 },
+ { IDNO, 407 },
+ { IDCLOSE, 408 },
+ { IDHELP, 409 }
+};
+
+
+void LangSetDlgItems(HWND dialog, const UInt32 *ids, unsigned numItems)
+{
+ unsigned i;
+ for (i = 0; i < Z7_ARRAY_SIZE(kLangPairs); i++)
+ {
+ const CIDLangPair &pair = kLangPairs[i];
+ CWindow window(GetDlgItem(dialog, (int)pair.ControlID));
+ if (window)
+ {
+ const wchar_t *s = g_Lang.Get(pair.LangID);
+ if (s)
+ window.SetText(s);
+ }
+ }
+
+ for (i = 0; i < numItems; i++)
+ {
+ const UInt32 id = ids[i];
+ LangSetDlgItemText(dialog, id, id);
+ }
+}
+
+void LangSetDlgItems_Colon(HWND dialog, const UInt32 *ids, unsigned numItems)
+{
+ for (unsigned i = 0; i < numItems; i++)
+ {
+ const UInt32 id = ids[i];
+ const wchar_t *s = g_Lang.Get(id);
+ if (s)
+ {
+ CWindow window(GetDlgItem(dialog, (int)id));
+ UString s2 = s;
+ s2 += ':';
+ window.SetText(s2);
+ }
+ }
+}
+
+void LangSetDlgItems_RemoveColon(HWND dialog, const UInt32 *ids, unsigned numItems)
+{
+ for (unsigned i = 0; i < numItems; i++)
+ {
+ const UInt32 id = ids[i];
+ const wchar_t *s = g_Lang.Get(id);
+ if (s)
+ {
+ CWindow window(GetDlgItem(dialog, (int)id));
+ UString s2 = s;
+ if (!s2.IsEmpty() && s2.Back() == ':')
+ s2.DeleteBack();
+ window.SetText(s2);
+ }
+ }
+}
+
+void LangSetWindowText(HWND window, UInt32 langID)
+{
+ const wchar_t *s = g_Lang.Get(langID);
+ if (s)
+ MySetWindowText(window, s);
+}
+
+UString LangString(UInt32 langID)
+{
+ const wchar_t *s = g_Lang.Get(langID);
+ if (s)
+ return s;
+ return MyLoadString(langID);
+}
+
+void AddLangString(UString &s, UInt32 langID)
+{
+ s += LangString(langID);
+}
+
+void LangString(UInt32 langID, UString &dest)
+{
+ const wchar_t *s = g_Lang.Get(langID);
+ if (s)
+ {
+ dest = s;
+ return;
+ }
+ MyLoadString(langID, dest);
+}
+
+void LangString_OnlyFromLangFile(UInt32 langID, UString &dest)
+{
+ dest.Empty();
+ const wchar_t *s = g_Lang.Get(langID);
+ if (s)
+ dest = s;
+}
+
+static const char * const kLangs =
+ "ar.bg.ca.zh.-tw.-cn.cs.da.de.el.en.es.fi.fr.he.hu.is."
+ "it.ja.ko.nl.no.=nb.=nn.pl.pt.-br.rm.ro.ru.sr.=hr.-spl.-spc.sk.sq.sv.th.tr."
+ "ur.id.uk.be.sl.et.lv.lt.tg.fa.vi.hy.az.eu.hsb.mk."
+ "st.ts.tn.ve.xh.zu.af.ka.fo.hi.mt.se.ga.yi.ms.kk."
+ "ky.sw.tk.uz.-latn.-cyrl.tt.bn.pa.-in.gu.or.ta.te.kn.ml.as.mr.sa."
+ "mn.=mn.=mng.bo.cy.kh.lo.my.gl.kok..sd.syr.si..iu.am.tzm."
+ "ks.ne.fy.ps.tl.dv..ff.ha..yo.qu.st.ba.lb.kl."
+ "ig.kr.om.ti.gn..la.so.ii..arn..moh..br.."
+ "ug.mi.oc.co."
+ // "gsw.sah.qut.rw.wo....prs...."
+ // ".gd."
+ ;
+
+static void FindShortNames(UInt32 primeLang, AStringVector &names)
+{
+ UInt32 index = 0;
+ for (const char *p = kLangs; *p != 0;)
+ {
+ const char *p2 = p;
+ for (; *p2 != '.'; p2++);
+ bool isSub = (p[0] == '-' || p[0] == '=');
+ if (!isSub)
+ index++;
+ if (index >= primeLang)
+ {
+ if (index > primeLang)
+ break;
+ AString s;
+ if (isSub)
+ {
+ if (p[0] == '-')
+ s = names[0];
+ else
+ p++;
+ }
+ while (p != p2)
+ s += (char)(Byte)*p++;
+ names.Add(s);
+ }
+ p = p2 + 1;
+ }
+}
+
+/*
+#include "../../../Common/IntToString.h"
+
+static struct CC1Lang
+{
+ CC1Lang()
+ {
+ for (int i = 1; i < 150; i++)
+ {
+ UString s;
+ char ttt[32];
+ ConvertUInt32ToHex(i, ttt);
+ s += ttt;
+ UStringVector names;
+ FindShortNames(i, names);
+
+ FOR_VECTOR (k, names)
+ {
+ s.Add_Space();
+ s += names[k];
+ }
+ OutputDebugStringW(s);
+ }
+ }
+} g_cc1;
+*/
+
+// typedef LANGID (WINAPI *GetUserDefaultUILanguageP)();
+
+void Lang_GetShortNames_for_DefaultLang(AStringVector &names, unsigned &subLang)
+{
+ names.Clear();
+ subLang = 0;
+ const LANGID sysLang = GetSystemDefaultLangID(); // "Language for non-Unicode programs" in XP64
+ const LANGID userLang = GetUserDefaultLangID(); // "Standards and formats" language in XP64
+
+ if (sysLang != userLang)
+ return;
+ const LANGID langID = userLang;
+
+ // const LANGID langID = MAKELANGID(0x1a, 1); // for debug
+
+ /*
+ LANGID sysUILang; // english in XP64
+ LANGID userUILang; // english in XP64
+
+ GetUserDefaultUILanguageP fn = (GetUserDefaultUILanguageP)GetProcAddress(
+ GetModuleHandle("kernel32"), "GetUserDefaultUILanguage");
+ if (fn)
+ userUILang = fn();
+ fn = (GetUserDefaultUILanguageP)GetProcAddress(
+ GetModuleHandle("kernel32"), "GetSystemDefaultUILanguage");
+ if (fn)
+ sysUILang = fn();
+ */
+
+ const WORD primLang = (WORD)(PRIMARYLANGID(langID));
+ subLang = SUBLANGID(langID);
+ FindShortNames(primLang, names);
+}
+
+
+static void OpenDefaultLang()
+{
+ AStringVector names;
+ unsigned subLang;
+ Lang_GetShortNames_for_DefaultLang(names, subLang);
+ {
+ const FString dirPrefix (GetLangDirPrefix());
+ for (unsigned i = 0; i < 2; i++)
+ {
+ const unsigned index = (i == 0 ? subLang : 0);
+ if (index < names.Size())
+ {
+ const AString &name = names[index];
+ if (!name.IsEmpty())
+ {
+ FString path (dirPrefix);
+ path += name;
+ path += ".txt";
+ if (LangOpen(g_Lang, path))
+ {
+ g_LangID = name;
+ return;
+ }
+ }
+ }
+ }
+ }
+}
+
+void ReloadLang()
+{
+ g_Lang.Clear();
+ ReadRegLang(g_LangID);
+ #ifndef _UNICODE
+ if (g_IsNT)
+ #endif
+ {
+ if (g_LangID.IsEmpty())
+ {
+ OpenDefaultLang();
+ return;
+ }
+ }
+ if (g_LangID.Len() > 1 || g_LangID[0] != L'-')
+ {
+ FString s = us2fs(g_LangID);
+ if (s.ReverseFind_PathSepar() < 0)
+ {
+ if (s.ReverseFind_Dot() < 0)
+ s += ".txt";
+ s.Insert(0, GetLangDirPrefix());
+ LangOpen(g_Lang, s);
+ }
+ }
+}
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/LangUtils.h b/CPP/7zip/UI/FileManager/LangUtils.h
index c694423..d53d270 100644
--- a/CPP/7zip/UI/FileManager/LangUtils.h
+++ b/CPP/7zip/UI/FileManager/LangUtils.h
@@ -1,40 +1,48 @@
-// LangUtils.h
-
-#ifndef __LANG_UTILS_H
-#define __LANG_UTILS_H
-
-#include "../../../Windows/ResourceString.h"
-
-#ifdef LANG
-
-extern UString g_LangID;
-
-struct CIDLangPair
-{
- UInt32 ControlID;
- UInt32 LangID;
-};
-
-void ReloadLang();
-void LoadLangOneTime();
-FString GetLangDirPrefix();
-
-void LangSetDlgItemText(HWND dialog, UInt32 controlID, UInt32 langID);
-void LangSetDlgItems(HWND dialog, const UInt32 *ids, unsigned numItems);
-void LangSetDlgItems_Colon(HWND dialog, const UInt32 *ids, unsigned numItems);
-void LangSetWindowText(HWND window, UInt32 langID);
-
-UString LangString(UInt32 langID);
-void AddLangString(UString &s, UInt32 langID);
-void LangString(UInt32 langID, UString &dest);
-void LangString_OnlyFromLangFile(UInt32 langID, UString &dest);
-
-#else
-
-inline UString LangString(UInt32 langID) { return NWindows::MyLoadString(langID); }
-inline void LangString(UInt32 langID, UString &dest) { NWindows::MyLoadString(langID, dest); }
-inline void AddLangString(UString &s, UInt32 langID) { s += NWindows::MyLoadString(langID); }
-
-#endif
-
-#endif
+// LangUtils.h
+
+#ifndef ZIP7_INC_LANG_UTILS_H
+#define ZIP7_INC_LANG_UTILS_H
+
+#include "../../../Common/Lang.h"
+
+#include "../../../Windows/ResourceString.h"
+
+extern UString g_LangID;
+extern CLang g_Lang;
+
+#ifdef Z7_LANG
+
+struct CIDLangPair
+{
+ UInt32 ControlID;
+ UInt32 LangID;
+};
+
+void ReloadLang();
+void LoadLangOneTime();
+
+void LangSetDlgItemText(HWND dialog, UInt32 controlID, UInt32 langID);
+void LangSetDlgItems(HWND dialog, const UInt32 *ids, unsigned numItems);
+void LangSetDlgItems_Colon(HWND dialog, const UInt32 *ids, unsigned numItems);
+void LangSetDlgItems_RemoveColon(HWND dialog, const UInt32 *ids, unsigned numItems);
+void LangSetWindowText(HWND window, UInt32 langID);
+
+UString LangString(UInt32 langID);
+void AddLangString(UString &s, UInt32 langID);
+void LangString(UInt32 langID, UString &dest);
+void LangString_OnlyFromLangFile(UInt32 langID, UString &dest);
+
+#else
+
+inline UString LangString(UInt32 langID) { return NWindows::MyLoadString(langID); }
+inline void LangString(UInt32 langID, UString &dest) { NWindows::MyLoadString(langID, dest); }
+inline void AddLangString(UString &s, UInt32 langID) { s += NWindows::MyLoadString(langID); }
+
+#endif
+
+FString GetLangDirPrefix();
+// bool LangOpen(CLang &lang, CFSTR fileName);
+
+void Lang_GetShortNames_for_DefaultLang(AStringVector &names, unsigned &subLang);
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/LinkDialog.cpp b/CPP/7zip/UI/FileManager/LinkDialog.cpp
new file mode 100644
index 0000000..0f24761
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LinkDialog.cpp
@@ -0,0 +1,400 @@
+// LinkDialog.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/FileIO.h"
+#include "../../../Windows/FileName.h"
+
+#include "LangUtils.h"
+
+#include "BrowseDialog.h"
+#include "CopyDialogRes.h"
+#include "LinkDialog.h"
+#include "resourceGui.h"
+
+#include "App.h"
+
+#include "resource.h"
+
+extern bool g_SymLink_Supported;
+
+using namespace NWindows;
+using namespace NFile;
+
+#ifdef Z7_LANG
+static const UInt32 kLangIDs[] =
+{
+ IDB_LINK_LINK,
+ IDT_LINK_PATH_FROM,
+ IDT_LINK_PATH_TO,
+ IDG_LINK_TYPE,
+ IDR_LINK_TYPE_HARD,
+ IDR_LINK_TYPE_SYM_FILE,
+ IDR_LINK_TYPE_SYM_DIR,
+ IDR_LINK_TYPE_JUNCTION,
+ IDR_LINK_TYPE_WSL
+};
+#endif
+
+
+static bool GetSymLink(CFSTR path, CReparseAttr &attr, UString &errorMessage)
+{
+ CByteBuffer buf;
+ if (!NIO::GetReparseData(path, buf, NULL))
+ return false;
+
+ if (!attr.Parse(buf, buf.Size()))
+ {
+ SetLastError(attr.ErrorCode);
+ return false;
+ }
+
+ CByteBuffer data2;
+ if (!FillLinkData(data2, attr.GetPath(),
+ !attr.IsMountPoint(), attr.IsSymLink_WSL()))
+ {
+ errorMessage = "Cannot reproduce reparse point";
+ return false;
+ }
+
+ if (data2.Size() != buf.Size() ||
+ memcmp(data2, buf, buf.Size()) != 0)
+ {
+ errorMessage = "mismatch for reproduced reparse point";
+ return false;
+ }
+
+ return true;
+}
+
+
+static const unsigned k_LinkType_Buttons[] =
+{
+ IDR_LINK_TYPE_HARD,
+ IDR_LINK_TYPE_SYM_FILE,
+ IDR_LINK_TYPE_SYM_DIR,
+ IDR_LINK_TYPE_JUNCTION,
+ IDR_LINK_TYPE_WSL
+};
+
+void CLinkDialog::Set_LinkType_Radio(unsigned idb)
+{
+ CheckRadioButton(
+ k_LinkType_Buttons[0],
+ k_LinkType_Buttons[Z7_ARRAY_SIZE(k_LinkType_Buttons) - 1],
+ idb);
+}
+
+bool CLinkDialog::OnInit()
+{
+ #ifdef Z7_LANG
+ LangSetWindowText(*this, IDD_LINK);
+ LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
+ #endif
+
+ _pathFromCombo.Attach(GetItem(IDC_LINK_PATH_FROM));
+ _pathToCombo.Attach(GetItem(IDC_LINK_PATH_TO));
+
+ if (!FilePath.IsEmpty())
+ {
+ NFind::CFileInfo fi;
+ unsigned linkType = 0;
+ if (!fi.Find(us2fs(FilePath)))
+ linkType = IDR_LINK_TYPE_SYM_FILE;
+ else
+ {
+ if (fi.HasReparsePoint())
+ {
+ CReparseAttr attr;
+ UString error;
+ const bool res = GetSymLink(us2fs(FilePath), attr, error);
+ if (!res && error.IsEmpty())
+ {
+ DWORD lastError = GetLastError();
+ if (lastError != 0)
+ error = NError::MyFormatMessage(lastError);
+ }
+
+ UString s = attr.GetPath();
+ if (!attr.IsSymLink_WSL())
+ if (!attr.IsOkNamePair())
+ {
+ s += " : ";
+ s += attr.PrintName;
+ }
+
+ if (!res)
+ {
+ s.Insert(0, L"ERROR: ");
+ if (!error.IsEmpty())
+ {
+ s += " : ";
+ s += error;
+ }
+ }
+
+
+ SetItemText(IDT_LINK_PATH_TO_CUR, s);
+
+ const UString destPath = attr.GetPath();
+ _pathFromCombo.SetText(FilePath);
+ _pathToCombo.SetText(destPath);
+
+ // if (res)
+ {
+ if (attr.IsMountPoint())
+ linkType = IDR_LINK_TYPE_JUNCTION;
+ else if (attr.IsSymLink_WSL())
+ linkType = IDR_LINK_TYPE_WSL;
+ else if (attr.IsSymLink_Win())
+ {
+ linkType =
+ fi.IsDir() ?
+ IDR_LINK_TYPE_SYM_DIR :
+ IDR_LINK_TYPE_SYM_FILE;
+ // if (attr.IsRelative()) linkType = IDR_LINK_TYPE_SYM_RELATIVE;
+ }
+
+ if (linkType != 0)
+ Set_LinkType_Radio(linkType);
+ }
+ }
+ else
+ {
+ // no ReparsePoint
+ _pathFromCombo.SetText(AnotherPath);
+ _pathToCombo.SetText(FilePath);
+ if (fi.IsDir())
+ linkType = g_SymLink_Supported ?
+ IDR_LINK_TYPE_SYM_DIR :
+ IDR_LINK_TYPE_JUNCTION;
+ else
+ linkType = IDR_LINK_TYPE_HARD;
+ }
+ }
+ if (linkType != 0)
+ Set_LinkType_Radio(linkType);
+ }
+
+ NormalizeSize();
+ return CModalDialog::OnInit();
+}
+
+bool CLinkDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
+{
+ int mx, my;
+ GetMargins(8, mx, my);
+ int bx1, bx2, by;
+ GetItemSizes(IDCANCEL, bx1, by);
+ GetItemSizes(IDB_LINK_LINK, bx2, by);
+ int yPos = ySize - my - by;
+ int xPos = xSize - mx - bx1;
+
+ InvalidateRect(NULL);
+
+ {
+ RECT r, r2;
+ GetClientRectOfItem(IDB_LINK_PATH_FROM, r);
+ GetClientRectOfItem(IDB_LINK_PATH_TO, r2);
+ int bx = RECT_SIZE_X(r);
+ int newButtonXpos = xSize - mx - bx;
+
+ MoveItem(IDB_LINK_PATH_FROM, newButtonXpos, r.top, bx, RECT_SIZE_Y(r));
+ MoveItem(IDB_LINK_PATH_TO, newButtonXpos, r2.top, bx, RECT_SIZE_Y(r2));
+
+ int newComboXsize = newButtonXpos - mx - mx;
+ ChangeSubWindowSizeX(_pathFromCombo, newComboXsize);
+ ChangeSubWindowSizeX(_pathToCombo, newComboXsize);
+ }
+
+ MoveItem(IDCANCEL, xPos, yPos, bx1, by);
+ MoveItem(IDB_LINK_LINK, xPos - mx - bx2, yPos, bx2, by);
+
+ return false;
+}
+
+bool CLinkDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ switch (buttonID)
+ {
+ case IDB_LINK_PATH_FROM:
+ OnButton_SetPath(false);
+ return true;
+ case IDB_LINK_PATH_TO:
+ OnButton_SetPath(true);
+ return true;
+ case IDB_LINK_LINK:
+ OnButton_Link();
+ return true;
+ }
+ return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
+}
+
+void CLinkDialog::OnButton_SetPath(bool to)
+{
+ UString currentPath;
+ NWindows::NControl::CComboBox &combo = to ?
+ _pathToCombo :
+ _pathFromCombo;
+ combo.GetText(currentPath);
+ // UString title = "Specify a location for output folder";
+ const UString title = LangString(IDS_SET_FOLDER);
+
+ UString resultPath;
+ if (!MyBrowseForFolder(*this, title, currentPath, resultPath))
+ return;
+ NName::NormalizeDirPathPrefix(resultPath);
+ combo.SetCurSel(-1);
+ combo.SetText(resultPath);
+}
+
+void CLinkDialog::ShowError(const wchar_t *s)
+{
+ ::MessageBoxW(*this, s, L"7-Zip", MB_ICONERROR);
+}
+
+void CLinkDialog::ShowLastErrorMessage()
+{
+ ShowError(NError::MyFormatMessage(GetLastError()));
+}
+
+void CLinkDialog::OnButton_Link()
+{
+ UString from, to;
+ _pathFromCombo.GetText(from);
+ _pathToCombo.GetText(to);
+
+ if (from.IsEmpty())
+ return;
+ if (!NName::IsAbsolutePath(from))
+ from.Insert(0, CurDirPrefix);
+
+ unsigned idb = 0;
+ for (unsigned i = 0;; i++)
+ {
+ if (i >= Z7_ARRAY_SIZE(k_LinkType_Buttons))
+ return;
+ idb = k_LinkType_Buttons[i];
+ if (IsButtonCheckedBool(idb))
+ break;
+ }
+
+ NFind::CFileInfo info1, info2;
+ const bool finded1 = info1.Find(us2fs(from));
+ const bool finded2 = info2.Find(us2fs(to));
+
+ const bool isDirLink = (
+ idb == IDR_LINK_TYPE_SYM_DIR ||
+ idb == IDR_LINK_TYPE_JUNCTION);
+
+ const bool isWSL = (idb == IDR_LINK_TYPE_WSL);
+
+ if (!isWSL)
+ if ((finded1 && info1.IsDir() != isDirLink) ||
+ (finded2 && info2.IsDir() != isDirLink))
+ {
+ ShowError(L"Incorrect link type");
+ return;
+ }
+
+ if (idb == IDR_LINK_TYPE_HARD)
+ {
+ if (!NDir::MyCreateHardLink(us2fs(from), us2fs(to)))
+ {
+ ShowLastErrorMessage();
+ return;
+ }
+ }
+ else
+ {
+ if (finded1 && !info1.IsDir() && !info1.HasReparsePoint() && info1.Size != 0)
+ {
+ UString s ("WARNING: reparse point will hide the data of existing file");
+ s.Add_LF();
+ s += from;
+ ShowError(s);
+ return;
+ }
+
+ const bool isSymLink = (idb != IDR_LINK_TYPE_JUNCTION);
+
+ CByteBuffer data;
+ if (!FillLinkData(data, to, isSymLink, isWSL))
+ {
+ ShowError(L"Incorrect link");
+ return;
+ }
+
+ CReparseAttr attr;
+ if (!attr.Parse(data, data.Size()))
+ {
+ ShowError(L"Internal conversion error");
+ return;
+ }
+
+ bool res;
+ if (to.IsEmpty())
+ {
+ // res = NIO::SetReparseData(us2fs(from), isDirLink, NULL, 0);
+ res = NIO::DeleteReparseData(us2fs(from));
+ }
+ else
+ res = NIO::SetReparseData(us2fs(from), isDirLink, data, (DWORD)data.Size());
+
+ if (!res)
+ {
+ ShowLastErrorMessage();
+ return;
+ }
+ }
+
+ End(IDOK);
+}
+
+void CApp::Link()
+{
+ const unsigned srcPanelIndex = GetFocusedPanelIndex();
+ CPanel &srcPanel = Panels[srcPanelIndex];
+ if (!srcPanel.IsFSFolder())
+ {
+ srcPanel.MessageBox_Error_UnsupportOperation();
+ return;
+ }
+ CRecordVector<UInt32> indices;
+ srcPanel.Get_ItemIndices_Operated(indices);
+ if (indices.IsEmpty())
+ return;
+ if (indices.Size() != 1)
+ {
+ srcPanel.MessageBox_Error_LangID(IDS_SELECT_ONE_FILE);
+ return;
+ }
+ const UInt32 index = indices[0];
+ const UString itemName = srcPanel.GetItemName(index);
+
+ const UString fsPrefix = srcPanel.GetFsPath();
+ const UString srcPath = fsPrefix + srcPanel.GetItemPrefix(index);
+ UString path = srcPath;
+ {
+ const unsigned destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex);
+ CPanel &destPanel = Panels[destPanelIndex];
+ if (NumPanels > 1)
+ if (destPanel.IsFSFolder())
+ path = destPanel.GetFsPath();
+ }
+
+ CLinkDialog dlg;
+ dlg.CurDirPrefix = fsPrefix;
+ dlg.FilePath = srcPath + itemName;
+ dlg.AnotherPath = path;
+
+ if (dlg.Create(srcPanel.GetParent()) != IDOK)
+ return;
+
+ // fix it: we should refresh panel with changed link
+
+ RefreshTitleAlways();
+}
diff --git a/CPP/7zip/UI/FileManager/LinkDialog.h b/CPP/7zip/UI/FileManager/LinkDialog.h
new file mode 100644
index 0000000..dd768f7
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LinkDialog.h
@@ -0,0 +1,34 @@
+// LinkDialog.h
+
+#ifndef ZIP7_INC_LINK_DIALOG_H
+#define ZIP7_INC_LINK_DIALOG_H
+
+#include "../../../Windows/Control/Dialog.h"
+#include "../../../Windows/Control/ComboBox.h"
+
+#include "LinkDialogRes.h"
+
+class CLinkDialog: public NWindows::NControl::CModalDialog
+{
+ NWindows::NControl::CComboBox _pathFromCombo;
+ NWindows::NControl::CComboBox _pathToCombo;
+
+ virtual bool OnInit() Z7_override;
+ virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override;
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+ void OnButton_SetPath(bool to);
+ void OnButton_Link();
+
+ void ShowLastErrorMessage();
+ void ShowError(const wchar_t *s);
+ void Set_LinkType_Radio(unsigned idb);
+public:
+ UString CurDirPrefix;
+ UString FilePath;
+ UString AnotherPath;
+
+ INT_PTR Create(HWND parentWindow = NULL)
+ { return CModalDialog::Create(IDD_LINK, parentWindow); }
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/LinkDialog.rc b/CPP/7zip/UI/FileManager/LinkDialog.rc
new file mode 100644
index 0000000..a9e220b
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LinkDialog.rc
@@ -0,0 +1,38 @@
+#include "LinkDialogRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 288
+#define yc 214
+
+#undef xRadioSize
+#define xRadioSize xc - m - 2
+
+IDD_LINK DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT
+CAPTION "Link"
+BEGIN
+ LTEXT "Link from:", IDT_LINK_PATH_FROM, m, m, xc, 8
+ COMBOBOX IDC_LINK_PATH_FROM, m, 20, xc - bxsDots - m, 64, MY_COMBO_WITH_EDIT
+ PUSHBUTTON "...", IDB_LINK_PATH_FROM, xs - m - bxsDots, 18, bxsDots, bys, WS_GROUP
+
+ LTEXT "Link to:", IDT_LINK_PATH_TO, m, 48, xc, 8
+ COMBOBOX IDC_LINK_PATH_TO, m, 60, xc - bxsDots - m, 64, MY_COMBO_WITH_EDIT
+ PUSHBUTTON "...", IDB_LINK_PATH_TO, xs - m - bxsDots, 58, bxsDots, bys, WS_GROUP
+
+ LTEXT "", IDT_LINK_PATH_TO_CUR, m, 78, xc, 8
+
+ GROUPBOX "Link Type", IDG_LINK_TYPE, m, 104, xc, 90
+
+ CONTROL "Hard Link", IDR_LINK_TYPE_HARD, "Button", BS_AUTORADIOBUTTON | WS_GROUP,
+ m + m, 120, xRadioSize, 10
+ CONTROL "File Symbolic Link", IDR_LINK_TYPE_SYM_FILE, "Button", BS_AUTORADIOBUTTON,
+ m + m, 134, xRadioSize, 10
+ CONTROL "Directory Symbolic Link", IDR_LINK_TYPE_SYM_DIR, "Button", BS_AUTORADIOBUTTON,
+ m + m, 148, xRadioSize, 10
+ CONTROL "Directory Junction", IDR_LINK_TYPE_JUNCTION, "Button", BS_AUTORADIOBUTTON,
+ m + m, 162, xRadioSize, 10
+ CONTROL "WSL", IDR_LINK_TYPE_WSL, "Button", BS_AUTORADIOBUTTON,
+ m + m, 176, xRadioSize, 10
+
+ DEFPUSHBUTTON "Link", IDB_LINK_LINK, bx2, by, bxs, bys
+ PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys
+END
diff --git a/CPP/7zip/UI/FileManager/LinkDialogRes.h b/CPP/7zip/UI/FileManager/LinkDialogRes.h
new file mode 100644
index 0000000..3f7b3f2
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/LinkDialogRes.h
@@ -0,0 +1,22 @@
+#define IDD_LINK 7700
+
+#define IDB_LINK_LINK 7701
+
+#define IDT_LINK_PATH_FROM 7702
+#define IDT_LINK_PATH_TO 7703
+
+#define IDG_LINK_TYPE 7710
+#define IDR_LINK_TYPE_HARD 7711
+#define IDR_LINK_TYPE_SYM_FILE 7712
+#define IDR_LINK_TYPE_SYM_DIR 7713
+#define IDR_LINK_TYPE_JUNCTION 7714
+#define IDR_LINK_TYPE_WSL 7715
+
+
+#define IDC_LINK_PATH_FROM 100
+#define IDC_LINK_PATH_TO 101
+
+#define IDT_LINK_PATH_TO_CUR 102
+
+#define IDB_LINK_PATH_FROM 103
+#define IDB_LINK_PATH_TO 104
diff --git a/CPP/7zip/UI/FileManager/ListViewDialog.cpp b/CPP/7zip/UI/FileManager/ListViewDialog.cpp
new file mode 100644
index 0000000..6767e4c
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ListViewDialog.cpp
@@ -0,0 +1,321 @@
+// ListViewDialog.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Windows/Clipboard.h"
+
+#include "EditDialog.h"
+#include "ListViewDialog.h"
+#include "RegistryUtils.h"
+
+#ifdef Z7_LANG
+#include "LangUtils.h"
+#endif
+
+using namespace NWindows;
+
+static const unsigned kOneStringMaxSize = 1024;
+
+
+static void ListView_GetSelected(NControl::CListView &listView, CUIntVector &vector)
+{
+ vector.Clear();
+ int index = -1;
+ for (;;)
+ {
+ index = listView.GetNextSelectedItem(index);
+ if (index < 0)
+ break;
+ vector.Add((unsigned)index);
+ }
+}
+
+
+bool CListViewDialog::OnInit()
+{
+ #ifdef Z7_LANG
+ LangSetDlgItems(*this, NULL, 0);
+ #endif
+ _listView.Attach(GetItem(IDL_LISTVIEW));
+
+ if (NumColumns > 1)
+ {
+ LONG_PTR style = _listView.GetStyle();
+ style &= ~(LONG_PTR)LVS_NOCOLUMNHEADER;
+ _listView.SetStyle(style);
+ }
+
+ CFmSettings st;
+ st.Load();
+
+ DWORD exStyle = 0;
+
+ if (st.SingleClick)
+ exStyle |= LVS_EX_ONECLICKACTIVATE | LVS_EX_TRACKSELECT;
+
+ exStyle |= LVS_EX_FULLROWSELECT;
+ if (exStyle != 0)
+ _listView.SetExtendedListViewStyle(exStyle);
+
+
+ SetText(Title);
+
+ const int kWidth = 400;
+
+ LVCOLUMN columnInfo;
+ columnInfo.mask = LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM;
+ columnInfo.fmt = LVCFMT_LEFT;
+ columnInfo.iSubItem = 0;
+ columnInfo.cx = kWidth;
+ columnInfo.pszText = NULL; // (TCHAR *)(const TCHAR *)""; // "Property"
+
+ if (NumColumns > 1)
+ {
+ columnInfo.cx = 100;
+ /*
+ // Windows always uses LVCFMT_LEFT for first column.
+ // if we need LVCFMT_RIGHT, we can create dummy column and then remove it
+
+ // columnInfo.mask |= LVCF_TEXT;
+ _listView.InsertColumn(0, &columnInfo);
+
+ columnInfo.iSubItem = 1;
+ columnInfo.fmt = LVCFMT_RIGHT;
+ _listView.InsertColumn(1, &columnInfo);
+ _listView.DeleteColumn(0);
+ */
+ }
+ // else
+ _listView.InsertColumn(0, &columnInfo);
+
+ if (NumColumns > 1)
+ {
+ // columnInfo.fmt = LVCFMT_LEFT;
+ columnInfo.cx = kWidth - columnInfo.cx;
+ columnInfo.iSubItem = 1;
+ // columnInfo.pszText = NULL; // (TCHAR *)(const TCHAR *)""; // "Value"
+ _listView.InsertColumn(1, &columnInfo);
+ }
+
+
+ UString s;
+
+ FOR_VECTOR (i, Strings)
+ {
+ _listView.InsertItem(i, Strings[i]);
+
+ if (NumColumns > 1 && i < Values.Size())
+ {
+ s = Values[i];
+ if (s.Len() > kOneStringMaxSize)
+ {
+ s.DeleteFrom(kOneStringMaxSize);
+ s += " ...";
+ }
+ s.Replace(L"\r\n", L" ");
+ s.Replace(L"\n", L" ");
+ _listView.SetSubItem(i, 1, s);
+ }
+ }
+
+ if (SelectFirst && Strings.Size() > 0)
+ _listView.SetItemState_FocusedSelected(0);
+
+ _listView.SetColumnWidthAuto(0);
+ if (NumColumns > 1)
+ _listView.SetColumnWidthAuto(1);
+ StringsWereChanged = false;
+
+ NormalizeSize();
+ return CModalDialog::OnInit();
+}
+
+bool CListViewDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
+{
+ int mx, my;
+ GetMargins(8, mx, my);
+ int bx1, bx2, by;
+ GetItemSizes(IDCANCEL, bx1, by);
+ GetItemSizes(IDOK, bx2, by);
+ int y = ySize - my - by;
+ int x = xSize - mx - bx1;
+
+ /*
+ RECT rect;
+ GetClientRect(&rect);
+ rect.top = y - my;
+ InvalidateRect(&rect);
+ */
+ InvalidateRect(NULL);
+
+ MoveItem(IDCANCEL, x, y, bx1, by);
+ MoveItem(IDOK, x - mx - bx2, y, bx2, by);
+ /*
+ if (wParam == SIZE_MAXSHOW || wParam == SIZE_MAXIMIZED || wParam == SIZE_MAXHIDE)
+ mx = 0;
+ */
+ _listView.Move(mx, my, xSize - mx * 2, y - my * 2);
+ return false;
+}
+
+
+extern bool g_LVN_ITEMACTIVATE_Support;
+
+void CListViewDialog::CopyToClipboard()
+{
+ CUIntVector indexes;
+ ListView_GetSelected(_listView, indexes);
+ UString s;
+
+ FOR_VECTOR (i, indexes)
+ {
+ unsigned index = indexes[i];
+ s += Strings[index];
+ if (NumColumns > 1 && index < Values.Size())
+ {
+ const UString &v = Values[index];
+ // if (!v.IsEmpty())
+ {
+ s += ": ";
+ s += v;
+ }
+ }
+ // if (indexes.Size() > 1)
+ {
+ s +=
+ #ifdef _WIN32
+ "\r\n"
+ #else
+ "\n"
+ #endif
+ ;
+ }
+ }
+
+ ClipboardSetText(*this, s);
+}
+
+
+void CListViewDialog::ShowItemInfo()
+{
+ CUIntVector indexes;
+ ListView_GetSelected(_listView, indexes);
+ if (indexes.Size() != 1)
+ return;
+ unsigned index = indexes[0];
+
+ CEditDialog dlg;
+ if (NumColumns == 1)
+ dlg.Text = Strings[index];
+ else
+ {
+ dlg.Title = Strings[index];
+ if (index < Values.Size())
+ dlg.Text = Values[index];
+ }
+
+ #ifdef _WIN32
+ if (dlg.Text.Find(L'\r') < 0)
+ dlg.Text.Replace(L"\n", L"\r\n");
+ #endif
+
+ dlg.Create(*this);
+}
+
+
+void CListViewDialog::DeleteItems()
+{
+ for (;;)
+ {
+ const int index = _listView.GetNextSelectedItem(-1);
+ if (index < 0)
+ break;
+ StringsWereChanged = true;
+ _listView.DeleteItem((unsigned)index);
+ if ((unsigned)index < Strings.Size())
+ Strings.Delete((unsigned)index);
+ if ((unsigned)index < Values.Size())
+ Values.Delete((unsigned)index);
+ }
+ const int focusedIndex = _listView.GetFocusedItem();
+ if (focusedIndex >= 0)
+ _listView.SetItemState_FocusedSelected(focusedIndex);
+ _listView.SetColumnWidthAuto(0);
+}
+
+
+void CListViewDialog::OnEnter()
+{
+ if (IsKeyDown(VK_MENU)
+ || NumColumns > 1)
+ {
+ ShowItemInfo();
+ return;
+ }
+ OnOK();
+}
+
+bool CListViewDialog::OnNotify(UINT /* controlID */, LPNMHDR header)
+{
+ if (header->hwndFrom != _listView)
+ return false;
+ switch (header->code)
+ {
+ case LVN_ITEMACTIVATE:
+ if (g_LVN_ITEMACTIVATE_Support)
+ {
+ OnEnter();
+ return true;
+ }
+ break;
+ case NM_DBLCLK:
+ case NM_RETURN: // probabably it's unused
+ if (!g_LVN_ITEMACTIVATE_Support)
+ {
+ OnEnter();
+ return true;
+ }
+ break;
+
+ case LVN_KEYDOWN:
+ {
+ LPNMLVKEYDOWN keyDownInfo = LPNMLVKEYDOWN(header);
+ switch (keyDownInfo->wVKey)
+ {
+ case VK_DELETE:
+ {
+ if (!DeleteIsAllowed)
+ return false;
+ DeleteItems();
+ return true;
+ }
+ case 'A':
+ {
+ if (IsKeyDown(VK_CONTROL))
+ {
+ _listView.SelectAll();
+ return true;
+ }
+ break;
+ }
+ case VK_INSERT:
+ case 'C':
+ {
+ if (IsKeyDown(VK_CONTROL))
+ {
+ CopyToClipboard();
+ return true;
+ }
+ break;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+void CListViewDialog::OnOK()
+{
+ FocusedItemIndex = _listView.GetFocusedItem();
+ CModalDialog::OnOK();
+}
diff --git a/CPP/7zip/UI/FileManager/ListViewDialog.h b/CPP/7zip/UI/FileManager/ListViewDialog.h
new file mode 100644
index 0000000..5f0b66d
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ListViewDialog.h
@@ -0,0 +1,46 @@
+// ListViewDialog.h
+
+#ifndef ZIP7_INC_LISTVIEW_DIALOG_H
+#define ZIP7_INC_LISTVIEW_DIALOG_H
+
+#include "../../../Windows/Control/Dialog.h"
+#include "../../../Windows/Control/ListView.h"
+
+#include "ListViewDialogRes.h"
+
+class CListViewDialog: public NWindows::NControl::CModalDialog
+{
+ NWindows::NControl::CListView _listView;
+ virtual void OnOK() Z7_override;
+ virtual bool OnInit() Z7_override;
+ virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override;
+ virtual bool OnNotify(UINT controlID, LPNMHDR header) Z7_override;
+ void CopyToClipboard();
+ void DeleteItems();
+ void ShowItemInfo();
+ void OnEnter();
+public:
+ UString Title;
+
+ bool SelectFirst;
+ bool DeleteIsAllowed;
+ bool StringsWereChanged;
+
+ UStringVector Strings;
+ UStringVector Values;
+
+ int FocusedItemIndex;
+ unsigned NumColumns;
+
+ INT_PTR Create(HWND wndParent = NULL) { return CModalDialog::Create(IDD_LISTVIEW, wndParent); }
+
+ CListViewDialog():
+ SelectFirst(false),
+ DeleteIsAllowed(false),
+ StringsWereChanged(false),
+ FocusedItemIndex(-1),
+ NumColumns(1)
+ {}
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/ListViewDialog.rc b/CPP/7zip/UI/FileManager/ListViewDialog.rc
new file mode 100644
index 0000000..4343b75
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ListViewDialog.rc
@@ -0,0 +1,14 @@
+#include "ListViewDialogRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 480
+#define yc 320
+
+IDD_LISTVIEW DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT
+CAPTION "ListView"
+{
+ CONTROL "List1", IDL_LISTVIEW, "SysListView32", LVS_REPORT | LVS_SHOWSELALWAYS |
+ LVS_AUTOARRANGE | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,
+ m, m, xc, yc - bys - m
+ OK_CANCEL
+}
diff --git a/CPP/7zip/UI/FileManager/ListViewDialogRes.h b/CPP/7zip/UI/FileManager/ListViewDialogRes.h
new file mode 100644
index 0000000..9abdb9d
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ListViewDialogRes.h
@@ -0,0 +1,2 @@
+#define IDD_LISTVIEW 99
+#define IDL_LISTVIEW 100
diff --git a/CPP/7zip/UI/FileManager/MenuPage.cpp b/CPP/7zip/UI/FileManager/MenuPage.cpp
new file mode 100644
index 0000000..2da7f3a
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MenuPage.cpp
@@ -0,0 +1,440 @@
+// MenuPage.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/ZipRegistry.h"
+
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/FileFind.h"
+
+#include "../Explorer/ContextMenuFlags.h"
+#include "../Explorer/RegistryContextMenu.h"
+#include "../Explorer/resource.h"
+
+#include "../FileManager/PropertyNameRes.h"
+
+#include "../GUI/ExtractDialogRes.h"
+
+#include "FormatUtils.h"
+#include "HelpUtils.h"
+#include "LangUtils.h"
+#include "MenuPage.h"
+#include "MenuPageRes.h"
+
+
+using namespace NWindows;
+using namespace NContextMenuFlags;
+
+#ifdef Z7_LANG
+static const UInt32 kLangIDs[] =
+{
+ IDX_SYSTEM_INTEGRATE_TO_MENU,
+ IDX_SYSTEM_CASCADED_MENU,
+ IDX_SYSTEM_ICON_IN_MENU,
+ IDX_EXTRACT_ELIM_DUP,
+ IDT_SYSTEM_ZONE,
+ IDT_SYSTEM_CONTEXT_MENU_ITEMS
+};
+#endif
+
+#define kMenuTopic "fm/options.htm#sevenZip"
+
+struct CContextMenuItem
+{
+ unsigned ControlID;
+ UInt32 Flag;
+};
+
+static const CContextMenuItem kMenuItems[] =
+{
+ { IDS_CONTEXT_OPEN, kOpen },
+ { IDS_CONTEXT_OPEN, kOpenAs },
+ { IDS_CONTEXT_EXTRACT, kExtract },
+ { IDS_CONTEXT_EXTRACT_HERE, kExtractHere },
+ { IDS_CONTEXT_EXTRACT_TO, kExtractTo },
+
+ { IDS_CONTEXT_TEST, kTest },
+
+ { IDS_CONTEXT_COMPRESS, kCompress },
+ { IDS_CONTEXT_COMPRESS_TO, kCompressTo7z },
+ { IDS_CONTEXT_COMPRESS_TO, kCompressToZip },
+
+ #ifndef UNDER_CE
+ { IDS_CONTEXT_COMPRESS_EMAIL, kCompressEmail },
+ { IDS_CONTEXT_COMPRESS_TO_EMAIL, kCompressTo7zEmail },
+ { IDS_CONTEXT_COMPRESS_TO_EMAIL, kCompressToZipEmail },
+ #endif
+
+ { IDS_PROP_CHECKSUM, kCRC },
+ { IDS_PROP_CHECKSUM, kCRC_Cascaded },
+};
+
+
+#if !defined(_WIN64)
+extern bool g_Is_Wow64;
+#endif
+
+#ifndef KEY_WOW64_64KEY
+ #define KEY_WOW64_64KEY (0x0100)
+#endif
+
+#ifndef KEY_WOW64_32KEY
+ #define KEY_WOW64_32KEY (0x0200)
+#endif
+
+
+static void LoadLang_Spec(UString &s, UInt32 id, const char *eng)
+{
+ LangString(id, s);
+ if (s.IsEmpty())
+ s = eng;
+ s.RemoveChar(L'&');
+}
+
+
+bool CMenuPage::OnInit()
+{
+ _initMode = true;
+
+ Clear_MenuChanged();
+
+#ifdef Z7_LANG
+ LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
+#endif
+
+ #ifdef UNDER_CE
+
+ HideItem(IDX_SYSTEM_INTEGRATE_TO_MENU);
+ HideItem(IDX_SYSTEM_INTEGRATE_TO_MENU_2);
+
+ #else
+
+ {
+ UString s;
+ {
+ CWindow window(GetItem(IDX_SYSTEM_INTEGRATE_TO_MENU));
+ window.GetText(s);
+ }
+ UString bit64 = LangString(IDS_PROP_BIT64);
+ if (bit64.IsEmpty())
+ bit64 = "64-bit";
+ #ifdef _WIN64
+ bit64.Replace(L"64", L"32");
+ #endif
+ s.Add_Space();
+ s += '(';
+ s += bit64;
+ s += ')';
+ SetItemText(IDX_SYSTEM_INTEGRATE_TO_MENU_2, s);
+ }
+
+ const FString prefix = NDLL::GetModuleDirPrefix();
+
+ _dlls[0].ctrl = IDX_SYSTEM_INTEGRATE_TO_MENU;
+ _dlls[1].ctrl = IDX_SYSTEM_INTEGRATE_TO_MENU_2;
+
+ _dlls[0].wow = 0;
+ _dlls[1].wow =
+ #ifdef _WIN64
+ KEY_WOW64_32KEY
+ #else
+ KEY_WOW64_64KEY
+ #endif
+ ;
+
+ for (unsigned d = 0; d < 2; d++)
+ {
+ CShellDll &dll = _dlls[d];
+
+ dll.wasChanged = false;
+
+ #ifndef _WIN64
+ if (d != 0 && !g_Is_Wow64)
+ {
+ HideItem(dll.ctrl);
+ continue;
+ }
+ #endif
+
+ FString &path = dll.Path;
+ path = prefix;
+ path += (d == 0 ? "7-zip.dll" :
+ #ifdef _WIN64
+ "7-zip32.dll"
+ #else
+ "7-zip64.dll"
+ #endif
+ );
+
+
+ if (!NFile::NFind::DoesFileExist_Raw(path))
+ {
+ path.Empty();
+ EnableItem(dll.ctrl, false);
+ }
+ else
+ {
+ dll.prevValue = CheckContextMenuHandler(fs2us(path), dll.wow);
+ CheckButton(dll.ctrl, dll.prevValue);
+ }
+ }
+
+ #endif
+
+
+ CContextMenuInfo ci;
+ ci.Load();
+
+ CheckButton(IDX_SYSTEM_CASCADED_MENU, ci.Cascaded.Val);
+ CheckButton(IDX_SYSTEM_ICON_IN_MENU, ci.MenuIcons.Val);
+ CheckButton(IDX_EXTRACT_ELIM_DUP, ci.ElimDup.Val);
+
+ _listView.Attach(GetItem(IDL_SYSTEM_OPTIONS));
+ _zoneCombo.Attach(GetItem(IDC_SYSTEM_ZONE));
+
+ {
+ unsigned wz = ci.WriteZone;
+ if (wz == (UInt32)(Int32)-1)
+ wz = 0;
+ for (unsigned i = 0; i <= 3; i++)
+ {
+ unsigned val = i;
+ UString s;
+ if (i == 3)
+ {
+ if (wz < 3)
+ break;
+ val = wz;
+ }
+ else
+ {
+ #define MY_IDYES 406
+ #define MY_IDNO 407
+ if (i == 0)
+ LoadLang_Spec(s, MY_IDNO, "No");
+ else if (i == 1)
+ LoadLang_Spec(s, MY_IDYES, "Yes");
+ else
+ LangString(IDT_ZONE_FOR_OFFICE, s);
+ }
+ if (s.IsEmpty())
+ s.Add_UInt32(val);
+ if (i == 0)
+ s.Insert(0, L"* ");
+ const int index = (int)_zoneCombo.AddString(s);
+ _zoneCombo.SetItemData(index, (LPARAM)val);
+ if (val == wz)
+ _zoneCombo.SetCurSel(index);
+ }
+ }
+
+
+ const UInt32 newFlags = LVS_EX_CHECKBOXES | LVS_EX_FULLROWSELECT;
+ _listView.SetExtendedListViewStyle(newFlags, newFlags);
+
+ _listView.InsertColumn(0, L"", 200);
+
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(kMenuItems); i++)
+ {
+ const CContextMenuItem &menuItem = kMenuItems[i];
+
+ UString s = LangString(menuItem.ControlID);
+ if (menuItem.Flag == kCRC)
+ s = "CRC SHA";
+ else if (menuItem.Flag == kCRC_Cascaded)
+ s = "7-Zip > CRC SHA";
+ if (menuItem.Flag == kOpenAs
+ || menuItem.Flag == kCRC
+ || menuItem.Flag == kCRC_Cascaded)
+ s += " >";
+
+ switch (menuItem.ControlID)
+ {
+ case IDS_CONTEXT_EXTRACT_TO:
+ {
+ s = MyFormatNew(s, LangString(IDS_CONTEXT_FOLDER));
+ break;
+ }
+ case IDS_CONTEXT_COMPRESS_TO:
+ case IDS_CONTEXT_COMPRESS_TO_EMAIL:
+ {
+ UString s2 = LangString(IDS_CONTEXT_ARCHIVE);
+ switch (menuItem.Flag)
+ {
+ case kCompressTo7z:
+ case kCompressTo7zEmail:
+ s2 += (".7z");
+ break;
+ case kCompressToZip:
+ case kCompressToZipEmail:
+ s2 += (".zip");
+ break;
+ }
+ s = MyFormatNew(s, s2);
+ break;
+ }
+ }
+
+ const int itemIndex = _listView.InsertItem(i, s);
+ _listView.SetCheckState((unsigned)itemIndex, ((ci.Flags & menuItem.Flag) != 0));
+ }
+
+ _listView.SetColumnWidthAuto(0);
+ _initMode = false;
+
+ return CPropertyPage::OnInit();
+}
+
+
+#ifndef UNDER_CE
+
+static void ShowMenuErrorMessage(const wchar_t *m, HWND hwnd)
+{
+ MessageBoxW(hwnd, m, L"7-Zip", MB_ICONERROR);
+}
+
+#endif
+
+
+LONG CMenuPage::OnApply()
+{
+ #ifndef UNDER_CE
+
+ for (unsigned d = 2; d != 0;)
+ {
+ d--;
+ CShellDll &dll = _dlls[d];
+ if (dll.wasChanged && !dll.Path.IsEmpty())
+ {
+ const bool newVal = IsButtonCheckedBool(dll.ctrl);
+ const LONG res = SetContextMenuHandler(newVal, fs2us(dll.Path), dll.wow);
+ if (res != ERROR_SUCCESS && (dll.prevValue != newVal || newVal))
+ ShowMenuErrorMessage(NError::MyFormatMessage(res), *this);
+ dll.prevValue = CheckContextMenuHandler(fs2us(dll.Path), dll.wow);
+ CheckButton(dll.ctrl, dll.prevValue);
+ dll.wasChanged = false;
+ }
+ }
+
+ #endif
+
+ if (_cascaded_Changed
+ || _menuIcons_Changed
+ || _elimDup_Changed
+ || _writeZone_Changed
+ || _flags_Changed)
+ {
+ CContextMenuInfo ci;
+ ci.Cascaded.Val = IsButtonCheckedBool(IDX_SYSTEM_CASCADED_MENU);
+ ci.Cascaded.Def = _cascaded_Changed;
+
+ ci.MenuIcons.Val = IsButtonCheckedBool(IDX_SYSTEM_ICON_IN_MENU);
+ ci.MenuIcons.Def = _menuIcons_Changed;
+
+ ci.ElimDup.Val = IsButtonCheckedBool(IDX_EXTRACT_ELIM_DUP);
+ ci.ElimDup.Def = _elimDup_Changed;
+
+ {
+ int zoneIndex = (int)_zoneCombo.GetItemData_of_CurSel();
+ if (zoneIndex <= 0)
+ zoneIndex = -1;
+ ci.WriteZone = (UInt32)(Int32)zoneIndex;
+ }
+
+ ci.Flags = 0;
+
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(kMenuItems); i++)
+ if (_listView.GetCheckState(i))
+ ci.Flags |= kMenuItems[i].Flag;
+
+ ci.Flags_Def = _flags_Changed;
+ ci.Save();
+
+ Clear_MenuChanged();
+ }
+
+ // UnChanged();
+
+ return PSNRET_NOERROR;
+}
+
+void CMenuPage::OnNotifyHelp()
+{
+ ShowHelpWindow(kMenuTopic);
+}
+
+bool CMenuPage::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ switch (buttonID)
+ {
+ #ifndef UNDER_CE
+ case IDX_SYSTEM_INTEGRATE_TO_MENU:
+ case IDX_SYSTEM_INTEGRATE_TO_MENU_2:
+ {
+ for (unsigned d = 0; d < 2; d++)
+ {
+ CShellDll &dll = _dlls[d];
+ if (buttonID == dll.ctrl && !dll.Path.IsEmpty())
+ dll.wasChanged = true;
+ }
+ break;
+ }
+ #endif
+
+ case IDX_SYSTEM_CASCADED_MENU: _cascaded_Changed = true; break;
+ case IDX_SYSTEM_ICON_IN_MENU: _menuIcons_Changed = true; break;
+ case IDX_EXTRACT_ELIM_DUP: _elimDup_Changed = true; break;
+ // case IDX_EXTRACT_WRITE_ZONE: _writeZone_Changed = true; break;
+
+ default:
+ return CPropertyPage::OnButtonClicked(buttonID, buttonHWND);
+ }
+
+ Changed();
+ return true;
+}
+
+
+bool CMenuPage::OnCommand(unsigned code, unsigned itemID, LPARAM param)
+{
+ if (code == CBN_SELCHANGE && itemID == IDC_SYSTEM_ZONE)
+ {
+ _writeZone_Changed = true;
+ Changed();
+ return true;
+ }
+ return CPropertyPage::OnCommand(code, itemID, param);
+}
+
+
+bool CMenuPage::OnNotify(UINT controlID, LPNMHDR lParam)
+{
+ if (lParam->hwndFrom == HWND(_listView))
+ {
+ switch (lParam->code)
+ {
+ case (LVN_ITEMCHANGED):
+ return OnItemChanged((const NMLISTVIEW *)lParam);
+ }
+ }
+ return CPropertyPage::OnNotify(controlID, lParam);
+}
+
+
+bool CMenuPage::OnItemChanged(const NMLISTVIEW *info)
+{
+ if (_initMode)
+ return true;
+ if ((info->uChanged & LVIF_STATE) != 0)
+ {
+ UINT oldState = info->uOldState & LVIS_STATEIMAGEMASK;
+ UINT newState = info->uNewState & LVIS_STATEIMAGEMASK;
+ if (oldState != newState)
+ {
+ _flags_Changed = true;
+ Changed();
+ }
+ }
+ return true;
+}
diff --git a/CPP/7zip/UI/FileManager/MenuPage.h b/CPP/7zip/UI/FileManager/MenuPage.h
new file mode 100644
index 0000000..3b62a8b
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MenuPage.h
@@ -0,0 +1,57 @@
+// MenuPage.h
+
+#ifndef ZIP7_INC_MENU_PAGE_H
+#define ZIP7_INC_MENU_PAGE_H
+
+#include "../../../Windows/Control/PropertyPage.h"
+#include "../../../Windows/Control/ComboBox.h"
+#include "../../../Windows/Control/ListView.h"
+
+struct CShellDll
+{
+ FString Path;
+ bool wasChanged;
+ bool prevValue;
+ unsigned ctrl;
+ UInt32 wow;
+
+ CShellDll(): wasChanged (false), prevValue(false), ctrl(0), wow(0) {}
+};
+
+class CMenuPage: public NWindows::NControl::CPropertyPage
+{
+ bool _initMode;
+
+ bool _cascaded_Changed;
+ bool _menuIcons_Changed;
+ bool _elimDup_Changed;
+ bool _writeZone_Changed;
+ bool _flags_Changed;
+
+ void Clear_MenuChanged()
+ {
+ _cascaded_Changed = false;
+ _menuIcons_Changed = false;
+ _elimDup_Changed = false;
+ _writeZone_Changed = false;
+ _flags_Changed = false;
+ }
+
+ #ifndef UNDER_CE
+ CShellDll _dlls[2];
+ #endif
+
+ NWindows::NControl::CListView _listView;
+ NWindows::NControl::CComboBox _zoneCombo;
+
+ virtual bool OnInit() Z7_override;
+ virtual void OnNotifyHelp() Z7_override;
+ virtual bool OnNotify(UINT controlID, LPNMHDR lParam) Z7_override;
+ virtual LONG OnApply() Z7_override;
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+ virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM param) Z7_override;
+
+ bool OnItemChanged(const NMLISTVIEW* info);
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/MenuPage.rc b/CPP/7zip/UI/FileManager/MenuPage.rc
new file mode 100644
index 0000000..fc21107
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MenuPage.rc
@@ -0,0 +1,24 @@
+#include "MenuPageRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 240
+#define yc 252
+
+IDD_MENU MY_PAGE
+#include "MenuPage2.rc"
+
+#ifdef UNDER_CE
+
+#undef m
+#undef xc
+#undef yc
+
+#define m 4
+#define xc (SMALL_PAGE_SIZE_X + 8)
+
+#define yc 112
+
+IDD_MENU_2 MY_PAGE
+#include "MenuPage2.rc"
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/MenuPage2.rc b/CPP/7zip/UI/FileManager/MenuPage2.rc
new file mode 100644
index 0000000..4d1ba21
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MenuPage2.rc
@@ -0,0 +1,28 @@
+#include "../GUI/ExtractDialogRes.h"
+
+#define y 96
+
+#define zoneX 90
+
+CAPTION "7-Zip"
+BEGIN
+ CONTROL "Integrate 7-Zip to shell context menu", IDX_SYSTEM_INTEGRATE_TO_MENU, MY_CHECKBOX, m, m, xc, 10
+ CONTROL "(32-bit)", IDX_SYSTEM_INTEGRATE_TO_MENU_2, MY_CHECKBOX, m, m + 14, xc, 10
+ CONTROL "Cascaded context menu", IDX_SYSTEM_CASCADED_MENU, MY_CHECKBOX, m, m + 28, xc, 10
+ CONTROL "Icons in context menu", IDX_SYSTEM_ICON_IN_MENU, MY_CHECKBOX, m, m + 42, xc, 10
+ CONTROL "Eliminate duplication of root folder", IDX_EXTRACT_ELIM_DUP, MY_CHECKBOX, m, m + 56, xc, 10
+
+ LTEXT "Propagate Zone.Id stream:", IDT_SYSTEM_ZONE, m, m + 70, xc - zoneX, 8
+ COMBOBOX IDC_SYSTEM_ZONE, m + xc - zoneX, m + 70 - 2, zoneX, 50, MY_COMBO
+
+ LTEXT "Context menu items:", IDT_SYSTEM_CONTEXT_MENU_ITEMS, m, m + 84, xc, 8
+ CONTROL "List", IDL_SYSTEM_OPTIONS, "SysListView32",
+ LVS_REPORT | LVS_SINGLESEL | LVS_NOCOLUMNHEADER | WS_BORDER | WS_TABSTOP,
+ m, m + y, xc, yc - y
+END
+
+
+STRINGTABLE
+BEGIN
+ IDT_ZONE_FOR_OFFICE "For Office files"
+END
diff --git a/CPP/7zip/UI/FileManager/MenuPageRes.h b/CPP/7zip/UI/FileManager/MenuPageRes.h
new file mode 100644
index 0000000..e2cf798
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MenuPageRes.h
@@ -0,0 +1,15 @@
+#define IDD_MENU 2300
+#define IDD_MENU_2 12300
+
+#define IDX_SYSTEM_INTEGRATE_TO_MENU 2301
+#define IDX_SYSTEM_CASCADED_MENU 2302
+#define IDT_SYSTEM_CONTEXT_MENU_ITEMS 2303
+#define IDX_SYSTEM_ICON_IN_MENU 2304
+
+#define IDX_SYSTEM_INTEGRATE_TO_MENU_2 2310
+
+#define IDT_SYSTEM_ZONE 3440
+#define IDT_ZONE_FOR_OFFICE 3441
+
+#define IDL_SYSTEM_OPTIONS 100
+#define IDC_SYSTEM_ZONE 101
diff --git a/CPP/7zip/UI/FileManager/MessagesDialog.cpp b/CPP/7zip/UI/FileManager/MessagesDialog.cpp
new file mode 100644
index 0000000..57e56bc
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MessagesDialog.cpp
@@ -0,0 +1,76 @@
+// MessagesDialog.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+
+#include "../../../Windows/ResourceString.h"
+
+#include "MessagesDialog.h"
+
+#include "LangUtils.h"
+
+#include "ProgressDialog2Res.h"
+
+using namespace NWindows;
+
+void CMessagesDialog::AddMessageDirect(LPCWSTR message)
+{
+ const unsigned i = (unsigned)_messageList.GetItemCount();
+ wchar_t sz[16];
+ ConvertUInt32ToString(i, sz);
+ _messageList.InsertItem(i, sz);
+ _messageList.SetSubItem(i, 1, message);
+}
+
+void CMessagesDialog::AddMessage(LPCWSTR message)
+{
+ UString s = message;
+ while (!s.IsEmpty())
+ {
+ const int pos = s.Find(L'\n');
+ if (pos < 0)
+ break;
+ AddMessageDirect(s.Left(pos));
+ s.DeleteFrontal((unsigned)pos + 1);
+ }
+ AddMessageDirect(s);
+}
+
+bool CMessagesDialog::OnInit()
+{
+ #ifdef Z7_LANG
+ LangSetWindowText(*this, IDD_MESSAGES);
+ LangSetDlgItems(*this, NULL, 0);
+ SetItemText(IDOK, LangString(IDS_CLOSE));
+ #endif
+ _messageList.Attach(GetItem(IDL_MESSAGE));
+ _messageList.SetUnicodeFormat();
+
+ _messageList.InsertColumn(0, L"", 30);
+ _messageList.InsertColumn(1, LangString(IDS_MESSAGE), 600);
+
+ FOR_VECTOR (i, *Messages)
+ AddMessage((*Messages)[i]);
+
+ _messageList.SetColumnWidthAuto(0);
+ _messageList.SetColumnWidthAuto(1);
+ NormalizeSize();
+ return CModalDialog::OnInit();
+}
+
+bool CMessagesDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
+{
+ int mx, my;
+ GetMargins(8, mx, my);
+ int bx, by;
+ GetItemSizes(IDOK, bx, by);
+ int y = ySize - my - by;
+ int x = xSize - mx - bx;
+
+ InvalidateRect(NULL);
+
+ MoveItem(IDOK, x, y, bx, by);
+ _messageList.Move(mx, my, xSize - mx * 2, y - my * 2);
+ return false;
+}
diff --git a/CPP/7zip/UI/FileManager/MessagesDialog.h b/CPP/7zip/UI/FileManager/MessagesDialog.h
new file mode 100644
index 0000000..40b0379
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MessagesDialog.h
@@ -0,0 +1,25 @@
+// MessagesDialog.h
+
+#ifndef ZIP7_INC_MESSAGES_DIALOG_H
+#define ZIP7_INC_MESSAGES_DIALOG_H
+
+#include "../../../Windows/Control/Dialog.h"
+#include "../../../Windows/Control/ListView.h"
+
+#include "MessagesDialogRes.h"
+
+class CMessagesDialog: public NWindows::NControl::CModalDialog
+{
+ NWindows::NControl::CListView _messageList;
+
+ void AddMessageDirect(LPCWSTR message);
+ void AddMessage(LPCWSTR message);
+ virtual bool OnInit() Z7_override;
+ virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override;
+public:
+ const UStringVector *Messages;
+
+ INT_PTR Create(HWND parent = NULL) { return CModalDialog::Create(IDD_MESSAGES, parent); }
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/MessagesDialog.rc b/CPP/7zip/UI/FileManager/MessagesDialog.rc
new file mode 100644
index 0000000..49b73e8
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MessagesDialog.rc
@@ -0,0 +1,14 @@
+#include "MessagesDialogRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 440
+#define yc 160
+
+IDD_MESSAGES DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT
+CAPTION "7-Zip: Diagnostic messages"
+{
+ DEFPUSHBUTTON "&Close", IDOK, bx, by, bxs, bys
+ CONTROL "List1", IDL_MESSAGE, "SysListView32",
+ LVS_REPORT | LVS_SHOWSELALWAYS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,
+ m, m, xc, yc - bys - m
+}
diff --git a/CPP/7zip/UI/FileManager/MessagesDialogRes.h b/CPP/7zip/UI/FileManager/MessagesDialogRes.h
new file mode 100644
index 0000000..c8fffff
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MessagesDialogRes.h
@@ -0,0 +1,3 @@
+#define IDD_MESSAGES 6602
+#define IDS_MESSAGE 6603
+#define IDL_MESSAGE 100
diff --git a/CPP/7zip/UI/FileManager/Move.bmp b/CPP/7zip/UI/FileManager/Move.bmp
new file mode 100644
index 0000000..eb5f20f
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Move.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/Move2.bmp b/CPP/7zip/UI/FileManager/Move2.bmp
new file mode 100644
index 0000000..58679ef
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Move2.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/MyCom2.h b/CPP/7zip/UI/FileManager/MyCom2.h
new file mode 100644
index 0000000..d3b49fe
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MyCom2.h
@@ -0,0 +1,55 @@
+// MyCom2.h
+
+#ifndef ZIP7_INC_MYCOM2_H
+#define ZIP7_INC_MYCOM2_H
+
+#include "../../../Common/MyCom.h"
+
+#define Z7_COM_ADDREF_RELEASE_MT \
+ private: \
+ STDMETHOD_(ULONG, AddRef)() Z7_override Z7_final \
+ { return (ULONG)InterlockedIncrement((LONG *)&_m_RefCount); } \
+ STDMETHOD_(ULONG, Release)() Z7_override Z7_final \
+ { const LONG v = InterlockedDecrement((LONG *)&_m_RefCount); \
+ if (v != 0) return (ULONG)v; \
+ delete this; return 0; }
+
+#define Z7_COM_UNKNOWN_IMP_SPEC_MT2(i1, i) \
+ Z7_COM_QI_BEGIN \
+ Z7_COM_QI_ENTRY_UNKNOWN(i1) \
+ i \
+ Z7_COM_QI_END \
+ Z7_COM_ADDREF_RELEASE_MT
+
+
+#define Z7_COM_UNKNOWN_IMP_1_MT(i) \
+ Z7_COM_UNKNOWN_IMP_SPEC_MT2( \
+ i, \
+ Z7_COM_QI_ENTRY(i) \
+ )
+
+#define Z7_COM_UNKNOWN_IMP_2_MT(i1, i2) \
+ Z7_COM_UNKNOWN_IMP_SPEC_MT2( \
+ i1, \
+ Z7_COM_QI_ENTRY(i1) \
+ Z7_COM_QI_ENTRY(i2) \
+ )
+
+#define Z7_COM_UNKNOWN_IMP_3_MT(i1, i2, i3) \
+ Z7_COM_UNKNOWN_IMP_SPEC_MT2( \
+ i1, \
+ Z7_COM_QI_ENTRY(i1) \
+ Z7_COM_QI_ENTRY(i2) \
+ Z7_COM_QI_ENTRY(i3) \
+ )
+
+#define Z7_COM_UNKNOWN_IMP_4_MT(i1, i2, i3, i4) \
+ Z7_COM_UNKNOWN_IMP_SPEC_MT2( \
+ i1, \
+ Z7_COM_QI_ENTRY(i1) \
+ Z7_COM_QI_ENTRY(i2) \
+ Z7_COM_QI_ENTRY(i3) \
+ Z7_COM_QI_ENTRY(i4) \
+ )
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/MyLoadMenu.cpp b/CPP/7zip/UI/FileManager/MyLoadMenu.cpp
new file mode 100644
index 0000000..9453536
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MyLoadMenu.cpp
@@ -0,0 +1,918 @@
+// MyLoadMenu.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Windows/Menu.h"
+#include "../../../Windows/TimeUtils.h"
+#include "../../../Windows/Control/Dialog.h"
+
+#include "../../PropID.h"
+
+#include "../Common/CompressCall.h"
+
+#include "AboutDialog.h"
+#include "App.h"
+#include "HelpUtils.h"
+#include "LangUtils.h"
+#include "MyLoadMenu.h"
+#include "RegistryUtils.h"
+
+#include "PropertyNameRes.h"
+#include "resource.h"
+
+using namespace NWindows;
+
+static const UINT k_MenuID_OpenBookmark = 830;
+static const UINT k_MenuID_SetBookmark = 810;
+static const UINT k_MenuID_TimePopup = IDM_VIEW_TIME_POPUP;
+static const UINT k_MenuID_Time = IDM_VIEW_TIME;
+
+extern HINSTANCE g_hInstance;
+
+#define kFMHelpTopic "FM/index.htm"
+
+extern void OptionsDialog(HWND hwndOwner, HINSTANCE hInstance);
+
+enum
+{
+ k_MenuIndex_File = 0,
+ k_MenuIndex_Edit,
+ k_MenuIndex_View,
+ k_MenuIndex_Bookmarks
+};
+
+#ifdef Z7_LANG
+static const UInt32 k_LangID_TopMenuItems[] =
+{
+ IDM_FILE,
+ IDM_EDIT,
+ IDM_VIEW,
+ IDM_FAVORITES,
+ IDM_TOOLS,
+ IDM_HELP
+};
+
+static const UInt32 k_LangID_Toolbars = IDM_VIEW_TOOLBARS;
+static const UInt32 k_LangID_AddToFavorites = IDM_ADD_TO_FAVORITES;
+
+static const CIDLangPair kIDLangPairs[] =
+{
+ { IDCLOSE, 557 }, // IDM_EXIT
+ { IDM_VIEW_ARANGE_BY_NAME, IDS_PROP_NAME },
+ { IDM_VIEW_ARANGE_BY_TYPE, IDS_PROP_FILE_TYPE },
+ { IDM_VIEW_ARANGE_BY_DATE, IDS_PROP_MTIME },
+ { IDM_VIEW_ARANGE_BY_SIZE, IDS_PROP_SIZE }
+};
+
+static int FindLangItem(unsigned controlID)
+{
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(kIDLangPairs); i++)
+ if (kIDLangPairs[i].ControlID == controlID)
+ return (int)i;
+ return -1;
+}
+#endif
+
+static unsigned GetSortControlID(PROPID propID)
+{
+ switch (propID)
+ {
+ case kpidName: return IDM_VIEW_ARANGE_BY_NAME;
+ case kpidExtension: return IDM_VIEW_ARANGE_BY_TYPE;
+ case kpidMTime: return IDM_VIEW_ARANGE_BY_DATE;
+ case kpidSize: return IDM_VIEW_ARANGE_BY_SIZE;
+ case kpidNoProperty: return IDM_VIEW_ARANGE_NO_SORT;
+ }
+ return IDM_VIEW_ARANGE_BY_NAME;
+ // IDM_VIEW_ARANGE_NO_SORT;
+ // return -1;
+}
+
+/*
+#if _MSC_VER > 1400
+// GetVersion was declared deprecated
+#pragma warning(disable : 4996)
+#endif
+
+static bool g_IsNew_fMask = false;
+static class CInit_fMask
+{
+public:
+ CInit_fMask()
+ {
+ DWORD v = GetVersion();
+ v = ((v & 0xff) << 8) | ((v >> 8) & 0xFF);
+ g_IsNew_fMask = (v > 0x400); // (win98/win2000) or newer
+ }
+} g_Init_fMask;
+static UINT Get_fMask_for_String()
+ { return g_IsNew_fMask ? MIIM_STRING : MIIM_TYPE; }
+static UINT Get_fMask_for_FType_and_String()
+ { return g_IsNew_fMask ? (MIIM_STRING | MIIM_FTYPE) : MIIM_TYPE; }
+*/
+
+/*
+We can use new MIIM_STRING / MIIM_FTYPE flags in the following conditions:
+ 1) we run at new Windows (win98/win2000) or newer
+ 2) also we probably must set MENUITEMINFO::cbSize as sizeof of full
+ (MENUITEMINFO) that was compiled with (WINVER >= 0x0500)
+But it's simpler to use old MIIM_TYPE without these complex checks.
+*/
+
+// /*
+static inline UINT Get_fMask_for_String() { return MIIM_TYPE; }
+static inline UINT Get_fMask_for_FType_and_String() { return MIIM_TYPE; }
+// */
+
+static bool Is_MenuItem_TimePopup(const CMenuItem &item)
+{
+ return item.wID == k_MenuID_TimePopup ||
+ item.StringValue.IsPrefixedBy_Ascii_NoCase("20");
+}
+
+#ifdef Z7_LANG
+static void MyChangeMenu(HMENU menuLoc, unsigned menuID, unsigned level, unsigned menuIndex)
+{
+ CMenu menu;
+ menu.Attach(menuLoc);
+
+ for (unsigned i = 0;; i++)
+ {
+ CMenuItem item;
+ /* here we can use
+ Get_fMask_for_String() or
+ Get_fMask_for_FType_and_String()
+ We want to change only String of menu item.
+ It's not required to change (fType) of menu item.
+ We can look (fType) to check for SEPARATOR item.
+ But String of separator is empty and (wID == 0).
+ So we can check for SEPARATOR without (fType) requesting.
+ So it's enough to use Get_fMask_for_String() here */
+ item.fMask =
+ Get_fMask_for_String()
+ // Get_fMask_for_FType_and_String()
+ | MIIM_SUBMENU | MIIM_ID;
+ if (!menu.GetItem(i, true, item))
+ break;
+ {
+ UString newString;
+ if (item.hSubMenu)
+ {
+ /* in win10:
+ MENU+POPUP:
+ (wID == item.hSubMenu)
+ MENUEX+POPUP where ID is not set:
+ (wID == 0)
+ MENU+SEPARATOR
+ (wID == 0)
+ */
+ UInt32 langID = item.wID;
+ if (langID >= (1 << 16))
+ {
+ // here we try to exclude the case (wID == item.hSubMenu) if (MENU+POPUP)
+ continue;
+ }
+ if (langID == 0)
+ {
+ if (level == 0)
+ {
+ if (i < Z7_ARRAY_SIZE(k_LangID_TopMenuItems))
+ langID = k_LangID_TopMenuItems[i];
+ }
+ else if (level == 1)
+ {
+ if (menuID == IDM_FAVORITES || (menuID == 0 && menuIndex == k_MenuIndex_Bookmarks))
+ langID = k_LangID_AddToFavorites;
+ else if (menuID == IDM_VIEW || (menuID == 0 && menuIndex == k_MenuIndex_View))
+ {
+ if (Is_MenuItem_TimePopup(item))
+ langID = k_MenuID_TimePopup;
+ else
+ langID = k_LangID_Toolbars;
+ }
+ }
+ }
+ if (langID == k_MenuID_TimePopup)
+ continue;
+ if (langID != k_LangID_AddToFavorites)
+ MyChangeMenu(item.hSubMenu, langID, level + 1, i);
+ if (langID == 0)
+ continue;
+ LangString_OnlyFromLangFile(langID, newString);
+ if (newString.IsEmpty())
+ continue;
+ }
+ else
+ {
+ if (item.fMask & (MIIM_TYPE | MIIM_FTYPE))
+ if (item.IsSeparator())
+ continue;
+ if (item.StringValue.IsEmpty())
+ continue;
+ const int langPos = FindLangItem(item.wID);
+ // we don't need lang change for CRC items!!!
+ const UInt32 langID = langPos >= 0 ? kIDLangPairs[langPos].LangID : item.wID;
+ if (langID == 0)
+ continue;
+
+ if (langID == IDM_OPEN_INSIDE_ONE ||
+ langID == IDM_OPEN_INSIDE_PARSER)
+ {
+ LangString_OnlyFromLangFile(IDM_OPEN_INSIDE, newString);
+ if (newString.IsEmpty())
+ continue;
+ newString.Replace(L"&", L"");
+ const int tabPos = newString.Find(L"\t");
+ if (tabPos >= 0)
+ newString.DeleteFrom(tabPos);
+ newString += (langID == IDM_OPEN_INSIDE_ONE ? " *" : " #");
+ }
+ else if (langID == IDM_BENCHMARK2)
+ {
+ LangString_OnlyFromLangFile(IDM_BENCHMARK, newString);
+ if (newString.IsEmpty())
+ continue;
+ newString.Replace(L"&", L"");
+ const int tabPos = newString.Find(L"\t");
+ if (tabPos >= 0)
+ newString.DeleteFrom(tabPos);
+ newString += " 2";
+ }
+ else
+ {
+ LangString_OnlyFromLangFile(langID, newString);
+ }
+
+ if (newString.IsEmpty())
+ continue;
+
+ const int tabPos = item.StringValue.ReverseFind(L'\t');
+ if (tabPos >= 0)
+ newString += item.StringValue.Ptr(tabPos);
+ }
+
+ {
+ item.StringValue = newString;
+ // we want to change only String
+ item.fMask = Get_fMask_for_String();
+ menu.SetItem(i, true, item);
+ }
+ }
+ }
+}
+#endif
+
+static CMenu g_FileMenu;
+
+static struct CFileMenuDestroyer
+{
+ ~CFileMenuDestroyer() { if ((HMENU)g_FileMenu) g_FileMenu.Destroy(); }
+} g_FileMenuDestroyer;
+
+
+static void CopyMenu(HMENU srcMenuSpec, HMENU destMenuSpec);
+
+static void CopyPopMenu_IfRequired(CMenuItem &item)
+{
+ /* if (item.hSubMenu) is defined
+ {
+ - it creates new (popup) menu
+ - it copies menu items from old item.hSubMenu menu to new (popup) menu
+ - it sets item.hSubMenu to handle of created (popup) menu
+ } */
+ if (item.hSubMenu)
+ {
+ CMenu popup;
+ popup.CreatePopup();
+ CopyMenu(item.hSubMenu, popup);
+ item.hSubMenu = popup;
+ }
+}
+
+/* destMenuSpec must be non-NULL handle to created empty popup menu */
+static void CopyMenu(HMENU srcMenuSpec, HMENU destMenuSpec)
+{
+ CMenu srcMenu;
+ srcMenu.Attach(srcMenuSpec);
+ CMenu destMenu;
+ destMenu.Attach(destMenuSpec);
+ unsigned startPos = 0;
+ for (unsigned i = 0;; i++)
+ {
+ CMenuItem item;
+ item.fMask = MIIM_SUBMENU | MIIM_STATE | MIIM_ID | Get_fMask_for_FType_and_String();
+ if (!srcMenu.GetItem(i, true, item))
+ break;
+ CopyPopMenu_IfRequired(item);
+ if (destMenu.InsertItem(startPos, true, item))
+ startPos++;
+ }
+}
+
+
+/* use for (needResetMenu):
+ false : for call from program window creation code
+ true : for another calls : (from Options language change)
+*/
+void MyLoadMenu(bool needResetMenu)
+{
+ #ifdef UNDER_CE
+
+ const HMENU oldMenu = g_App._commandBar.GetMenu(0);
+ if (oldMenu)
+ ::DestroyMenu(oldMenu);
+ /* BOOL b = */ g_App._commandBar.InsertMenubar(g_hInstance, IDM_MENU, 0);
+ const HMENU baseMenu = g_App._commandBar.GetMenu(0);
+ // if (startInit)
+ // SetIdsForSubMenus(baseMenu, 0, 0);
+ if (!g_LangID.IsEmpty())
+ MyChangeMenu(baseMenu, 0, 0);
+ g_App._commandBar.DrawMenuBar(0);
+
+ #else // UNDER_CE
+
+ const HWND hWnd = g_HWND;
+ bool menuWasChanged = false;
+ /*
+ We must reload to english default menu for at least two cases:
+ - if some submenu was changed (File or another submenu can be changed after menu activating).
+ - for change from non-english lang to another partial non-english lang,
+ where we still need some english strings.
+ But we reload menu to default menu everytime except of program starting stage.
+ That scheme is simpler than complex checks for exact conditions for menu reload.
+ */
+ if (needResetMenu)
+ {
+ const HMENU oldMenu = ::GetMenu(hWnd);
+ const HMENU newMenu = ::LoadMenu(g_hInstance, MAKEINTRESOURCE(IDM_MENU));
+ // docs for SetMenu(): the window is redrawn to reflect the menu change.
+ if (newMenu && ::SetMenu(hWnd, newMenu))
+ ::DestroyMenu(oldMenu);
+ menuWasChanged = true;
+ }
+ const HMENU baseMenu = ::GetMenu(hWnd);
+ // if (startInit)
+ // SetIdsForSubMenus(baseMenu, 0, 0);
+ #ifdef Z7_LANG
+ if (!g_Lang.IsEmpty()) // !g_LangID.IsEmpty() &&
+ {
+ MyChangeMenu(baseMenu, 0, 0, 0);
+ menuWasChanged = true;
+ }
+ #endif
+
+ if (menuWasChanged)
+ ::DrawMenuBar(hWnd);
+
+ #endif // UNDER_CE
+
+ // menuWasChanged = false; // for debug
+ if (menuWasChanged || !(HMENU)g_FileMenu)
+ {
+ if ((HMENU)g_FileMenu)
+ g_FileMenu.Destroy();
+ g_FileMenu.CreatePopup();
+ CopyMenu(::GetSubMenu(baseMenu, k_MenuIndex_File), g_FileMenu);
+ }
+}
+
+void OnMenuActivating(HWND /* hWnd */, HMENU hMenu, int position)
+{
+ HMENU mainMenu =
+ #ifdef UNDER_CE
+ g_App._commandBar.GetMenu(0);
+ #else
+ ::GetMenu(g_HWND)
+ #endif
+ ;
+
+ if (::GetSubMenu(mainMenu, position) != hMenu)
+ return;
+
+ if (position == k_MenuIndex_File)
+ {
+ CMenu menu;
+ menu.Attach(hMenu);
+ menu.RemoveAllItems();
+ g_App.GetFocusedPanel().CreateFileMenu(hMenu);
+ }
+ else if (position == k_MenuIndex_Edit)
+ {
+ /*
+ CMenu menu;
+ menu.Attach(hMenu);
+ menu.EnableItem(IDM_EDIT_CUT, MF_ENABLED);
+ menu.EnableItem(IDM_EDIT_COPY, MF_ENABLED);
+ menu.EnableItem(IDM_EDIT_PASTE, IsClipboardFormatAvailableHDROP() ? MF_ENABLED : MF_GRAYED);
+ */
+ }
+ else if (position == k_MenuIndex_View)
+ {
+ // View;
+ CMenu menu;
+ menu.Attach(hMenu);
+ menu.CheckRadioItem(
+ IDM_VIEW_LARGE_ICONS, IDM_VIEW_DETAILS,
+ IDM_VIEW_LARGE_ICONS + g_App.GetListViewMode(), MF_BYCOMMAND);
+
+ menu.CheckRadioItem(
+ IDM_VIEW_ARANGE_BY_NAME,
+ IDM_VIEW_ARANGE_NO_SORT,
+ GetSortControlID(g_App.GetSortID()),
+ MF_BYCOMMAND);
+
+ menu.CheckItemByID(IDM_VIEW_TWO_PANELS, g_App.NumPanels == 2);
+ menu.CheckItemByID(IDM_VIEW_FLAT_VIEW, g_App.GetFlatMode());
+ menu.CheckItemByID(IDM_VIEW_ARCHIVE_TOOLBAR, g_App.ShowArchiveToolbar);
+ menu.CheckItemByID(IDM_VIEW_STANDARD_TOOLBAR, g_App.ShowStandardToolbar);
+ menu.CheckItemByID(IDM_VIEW_TOOLBARS_LARGE_BUTTONS, g_App.LargeButtons);
+ menu.CheckItemByID(IDM_VIEW_TOOLBARS_SHOW_BUTTONS_TEXT, g_App.ShowButtonsLables);
+ menu.CheckItemByID(IDM_VIEW_AUTO_REFRESH, g_App.Get_AutoRefresh_Mode());
+ // menu.CheckItemByID(IDM_VIEW_SHOW_STREAMS, g_App.Get_ShowNtfsStrems_Mode());
+ // menu.CheckItemByID(IDM_VIEW_SHOW_DELETED, g_App.ShowDeletedFiles);
+
+ for (unsigned i = 0;; i++)
+ {
+ CMenuItem item;
+ item.fMask = Get_fMask_for_String() | MIIM_SUBMENU | MIIM_ID;
+ item.fType = MFT_STRING;
+ if (!menu.GetItem(i, true, item))
+ break;
+ if (item.hSubMenu && Is_MenuItem_TimePopup(item))
+ {
+ FILETIME ft;
+ NTime::GetCurUtcFileTime(ft);
+
+ {
+ wchar_t s[64];
+ s[0] = 0;
+ if (ConvertUtcFileTimeToString(ft, s, kTimestampPrintLevel_DAY))
+ item.StringValue = s;
+ }
+
+ item.fMask = Get_fMask_for_String() | MIIM_ID;
+ item.fType = MFT_STRING;
+ item.wID = k_MenuID_TimePopup;
+ menu.SetItem(i, true, item);
+
+ CMenu subMenu;
+ subMenu.Attach(menu.GetSubMenu((int)i));
+ subMenu.RemoveAllItems();
+
+ const int k_TimeLevels[] =
+ {
+ kTimestampPrintLevel_DAY,
+ kTimestampPrintLevel_MIN,
+ kTimestampPrintLevel_SEC,
+ // 1,2,3,4,5,6,
+ kTimestampPrintLevel_NTFS,
+ kTimestampPrintLevel_NS
+ };
+
+ unsigned last = k_MenuID_Time;
+ unsigned selectedCommand = 0;
+ g_App._timestampLevels.Clear();
+ unsigned id = k_MenuID_Time;
+
+ for (unsigned k = 0; k < Z7_ARRAY_SIZE(k_TimeLevels); k++)
+ {
+ wchar_t s[64];
+ s[0] = 0;
+ const int timestampLevel = k_TimeLevels[k];
+ if (ConvertUtcFileTimeToString(ft, s, timestampLevel))
+ {
+ if (subMenu.AppendItem(MF_STRING, id, s))
+ {
+ last = id;
+ g_App._timestampLevels.Add(timestampLevel);
+ if (g_App.GetTimestampLevel() == timestampLevel)
+ selectedCommand = id;
+ id++;
+ }
+ }
+ }
+ if (selectedCommand != 0)
+ menu.CheckRadioItem(k_MenuID_Time, last, selectedCommand, MF_BYCOMMAND);
+ }
+ }
+ }
+ else if (position == k_MenuIndex_Bookmarks)
+ {
+ CMenu menu;
+ menu.Attach(hMenu);
+
+ CMenu subMenu;
+ subMenu.Attach(menu.GetSubMenu(0));
+ subMenu.RemoveAllItems();
+ unsigned i;
+
+ for (i = 0; i < 10; i++)
+ {
+ UString s = LangString(IDS_BOOKMARK);
+ s.Add_Space();
+ const char c = (char)(L'0' + i);
+ s += c;
+ s += "\tAlt+Shift+";
+ s += c;
+ subMenu.AppendItem(MF_STRING, k_MenuID_SetBookmark + i, s);
+ }
+
+ menu.RemoveAllItemsFrom(2);
+
+ for (i = 0; i < 10; i++)
+ {
+ UString s = g_App.AppState.FastFolders.GetString(i);
+ const int kMaxSize = 100;
+ const int kFirstPartSize = kMaxSize / 2;
+ if (s.Len() > kMaxSize)
+ {
+ s.Delete(kFirstPartSize, s.Len() - kMaxSize);
+ s.Insert(kFirstPartSize, L" ... ");
+ }
+ if (s.IsEmpty())
+ s = '-';
+ s += "\tAlt+";
+ s += (char)('0' + i);
+ menu.AppendItem(MF_STRING, k_MenuID_OpenBookmark + i, s);
+ }
+ }
+}
+
+/*
+It doesn't help
+void OnMenuUnActivating(HWND hWnd, HMENU hMenu, int id)
+{
+ if (::GetSubMenu(::GetMenu(g_HWND), 0) != hMenu)
+ return;
+}
+*/
+
+static const unsigned g_Zvc_IDs[] =
+{
+ IDM_VER_EDIT,
+ IDM_VER_COMMIT,
+ IDM_VER_REVERT,
+ IDM_VER_DIFF
+};
+
+static const char * const g_Zvc_Strings[] =
+{
+ "Ver Edit (&1)"
+ , "Ver Commit"
+ , "Ver Revert"
+ , "Ver Diff (&0)"
+};
+
+void CFileMenu::Load(HMENU hMenu, unsigned startPos)
+{
+ CMenu destMenu;
+ destMenu.Attach(hMenu);
+
+ UString diffPath;
+ ReadRegDiff(diffPath);
+
+ unsigned numRealItems = startPos;
+
+ const bool isBigScreen = NControl::IsDialogSizeOK(40, 200, g_HWND);
+
+ for (unsigned i = 0;; i++)
+ {
+ CMenuItem item;
+
+ item.fMask = MIIM_SUBMENU | MIIM_STATE | MIIM_ID | Get_fMask_for_FType_and_String();
+ item.fType = MFT_STRING;
+
+ if (!g_FileMenu.GetItem(i, true, item))
+ break;
+
+ {
+ if (!programMenu && item.wID == IDCLOSE)
+ continue;
+
+ if (item.wID == IDM_DIFF && diffPath.IsEmpty())
+ continue;
+
+ if (item.wID == IDM_OPEN_INSIDE_ONE || item.wID == IDM_OPEN_INSIDE_PARSER)
+ {
+ // We use diff as "super mode" marker for additional commands.
+ /*
+ if (diffPath.IsEmpty())
+ continue;
+ */
+ }
+
+ if (item.wID == IDM_BENCHMARK2)
+ {
+ // We use diff as "super mode" marker for additional commands.
+ if (diffPath.IsEmpty())
+ continue;
+ }
+
+ bool isOneFsFile = (isFsFolder && numItems == 1 && allAreFiles);
+ bool disable = (!isOneFsFile && (item.wID == IDM_SPLIT || item.wID == IDM_COMBINE));
+
+ if (readOnly)
+ {
+ switch (item.wID)
+ {
+ case IDM_RENAME:
+ case IDM_MOVE_TO:
+ case IDM_DELETE:
+ case IDM_COMMENT:
+ case IDM_CREATE_FOLDER:
+ case IDM_CREATE_FILE:
+ disable = true;
+ }
+ }
+
+ if (isHashFolder)
+ {
+ switch (item.wID)
+ {
+ case IDM_OPEN:
+ case IDM_OPEN_INSIDE:
+ case IDM_OPEN_INSIDE_ONE:
+ case IDM_OPEN_INSIDE_PARSER:
+ case IDM_OPEN_OUTSIDE:
+ case IDM_FILE_VIEW:
+ case IDM_FILE_EDIT:
+ // case IDM_RENAME:
+ case IDM_COPY_TO:
+ case IDM_MOVE_TO:
+ // case IDM_DELETE:
+ case IDM_COMMENT:
+ case IDM_CREATE_FOLDER:
+ case IDM_CREATE_FILE:
+ case IDM_LINK:
+ case IDM_DIFF:
+ disable = true;
+ }
+ }
+
+
+ if (item.wID == IDM_LINK && numItems != 1)
+ disable = true;
+
+ if (item.wID == IDM_ALT_STREAMS)
+ disable = !isAltStreamsSupported;
+
+ if (!isBigScreen && (disable || item.IsSeparator()))
+ continue;
+
+ CopyPopMenu_IfRequired(item);
+ if (destMenu.InsertItem(startPos, true, item))
+ {
+ if (disable)
+ destMenu.EnableItem(startPos, MF_BYPOSITION | MF_GRAYED);
+ startPos++;
+ }
+
+ if (!item.IsSeparator())
+ numRealItems = startPos;
+ }
+ }
+
+ UString vercPath;
+ if (!diffPath.IsEmpty() && isFsFolder && allAreFiles && numItems == 1)
+ ReadReg_VerCtrlPath(vercPath);
+
+ if (!vercPath.IsEmpty())
+ {
+ NFile::NFind::CFileInfo fi;
+ if (fi.Find(FilePath) && fi.Size < ((UInt32)1 << 31) && !fi.IsDir())
+ {
+ for (unsigned k = 0; k < Z7_ARRAY_SIZE(g_Zvc_IDs); k++)
+ {
+ const unsigned id = g_Zvc_IDs[k];
+ if (fi.IsReadOnly())
+ {
+ if (id == IDM_VER_COMMIT ||
+ id == IDM_VER_REVERT ||
+ id == IDM_VER_DIFF)
+ continue;
+ }
+ else
+ {
+ if (id == IDM_VER_EDIT)
+ continue;
+ }
+
+ CMenuItem item;
+ UString s (g_Zvc_Strings[k]);
+ if (destMenu.AppendItem(MF_STRING, id, s))
+ {
+ startPos++;
+ numRealItems = startPos;
+ }
+ }
+ }
+ }
+
+ destMenu.RemoveAllItemsFrom(numRealItems);
+}
+
+bool ExecuteFileCommand(unsigned id)
+{
+ if (id >= kMenuCmdID_Plugin_Start)
+ {
+ g_App.GetFocusedPanel().InvokePluginCommand(id);
+ g_App.GetFocusedPanel()._sevenZipContextMenu.Release();
+ g_App.GetFocusedPanel()._systemContextMenu.Release();
+ return true;
+ }
+
+ switch (id)
+ {
+ // File
+ case IDM_OPEN: g_App.OpenItem(); break;
+
+ case IDM_OPEN_INSIDE: g_App.OpenItemInside(NULL); break;
+ case IDM_OPEN_INSIDE_ONE: g_App.OpenItemInside(L"*"); break;
+ case IDM_OPEN_INSIDE_PARSER: g_App.OpenItemInside(L"#"); break;
+
+ case IDM_OPEN_OUTSIDE: g_App.OpenItemOutside(); break;
+ case IDM_FILE_VIEW: g_App.EditItem(false); break;
+ case IDM_FILE_EDIT: g_App.EditItem(true); break;
+ case IDM_RENAME: g_App.Rename(); break;
+ case IDM_COPY_TO: g_App.CopyTo(); break;
+ case IDM_MOVE_TO: g_App.MoveTo(); break;
+ case IDM_DELETE: g_App.Delete(!IsKeyDown(VK_SHIFT)); break;
+
+ case IDM_HASH_ALL: g_App.CalculateCrc("*"); break;
+ case IDM_CRC32: g_App.CalculateCrc("CRC32"); break;
+ case IDM_CRC64: g_App.CalculateCrc("CRC64"); break;
+ case IDM_SHA1: g_App.CalculateCrc("SHA1"); break;
+ case IDM_SHA256: g_App.CalculateCrc("SHA256"); break;
+
+ case IDM_DIFF: g_App.DiffFiles(); break;
+
+ case IDM_VER_EDIT:
+ case IDM_VER_COMMIT:
+ case IDM_VER_REVERT:
+ case IDM_VER_DIFF:
+ g_App.VerCtrl(id); break;
+
+ case IDM_SPLIT: g_App.Split(); break;
+ case IDM_COMBINE: g_App.Combine(); break;
+ case IDM_PROPERTIES: g_App.Properties(); break;
+ case IDM_COMMENT: g_App.Comment(); break;
+ case IDM_CREATE_FOLDER: g_App.CreateFolder(); break;
+ case IDM_CREATE_FILE: g_App.CreateFile(); break;
+ #ifndef UNDER_CE
+ case IDM_LINK: g_App.Link(); break;
+ case IDM_ALT_STREAMS: g_App.OpenAltStreams(); break;
+ #endif
+ default: return false;
+ }
+ return true;
+}
+
+static void MyBenchmark(bool totalMode)
+{
+ CPanel::CDisableTimerProcessing disableTimerProcessing1(g_App.Panels[0]);
+ CPanel::CDisableTimerProcessing disableTimerProcessing2(g_App.Panels[1]);
+ Benchmark(totalMode);
+}
+
+bool OnMenuCommand(HWND hWnd, unsigned id)
+{
+ if (ExecuteFileCommand(id))
+ return true;
+
+ switch (id)
+ {
+ // File
+ case IDCLOSE:
+ SendMessage(hWnd, WM_ACTIVATE, MAKEWPARAM(WA_INACTIVE, 0), (LPARAM)hWnd);
+ g_ExitEventLauncher.Exit(false);
+ SendMessage(hWnd, WM_CLOSE, 0, 0);
+ break;
+
+ // Edit
+ /*
+ case IDM_EDIT_CUT:
+ g_App.EditCut();
+ break;
+ case IDM_EDIT_COPY:
+ g_App.EditCopy();
+ break;
+ case IDM_EDIT_PASTE:
+ g_App.EditPaste();
+ break;
+ */
+ case IDM_SELECT_ALL:
+ g_App.SelectAll(true);
+ g_App.Refresh_StatusBar();
+ break;
+ case IDM_DESELECT_ALL:
+ g_App.SelectAll(false);
+ g_App.Refresh_StatusBar();
+ break;
+ case IDM_INVERT_SELECTION:
+ g_App.InvertSelection();
+ g_App.Refresh_StatusBar();
+ break;
+ case IDM_SELECT:
+ g_App.SelectSpec(true);
+ g_App.Refresh_StatusBar();
+ break;
+ case IDM_DESELECT:
+ g_App.SelectSpec(false);
+ g_App.Refresh_StatusBar();
+ break;
+ case IDM_SELECT_BY_TYPE:
+ g_App.SelectByType(true);
+ g_App.Refresh_StatusBar();
+ break;
+ case IDM_DESELECT_BY_TYPE:
+ g_App.SelectByType(false);
+ g_App.Refresh_StatusBar();
+ break;
+
+ //View
+ case IDM_VIEW_LARGE_ICONS:
+ case IDM_VIEW_SMALL_ICONS:
+ case IDM_VIEW_LIST:
+ case IDM_VIEW_DETAILS:
+ {
+ UINT index = id - IDM_VIEW_LARGE_ICONS;
+ if (index < 4)
+ {
+ g_App.SetListViewMode(index);
+ /*
+ CMenu menu;
+ menu.Attach(::GetSubMenu(::GetMenu(hWnd), k_MenuIndex_View));
+ menu.CheckRadioItem(IDM_VIEW_LARGE_ICONS, IDM_VIEW_DETAILS,
+ id, MF_BYCOMMAND);
+ */
+ }
+ break;
+ }
+ case IDM_VIEW_ARANGE_BY_NAME: g_App.SortItemsWithPropID(kpidName); break;
+ case IDM_VIEW_ARANGE_BY_TYPE: g_App.SortItemsWithPropID(kpidExtension); break;
+ case IDM_VIEW_ARANGE_BY_DATE: g_App.SortItemsWithPropID(kpidMTime); break;
+ case IDM_VIEW_ARANGE_BY_SIZE: g_App.SortItemsWithPropID(kpidSize); break;
+ case IDM_VIEW_ARANGE_NO_SORT: g_App.SortItemsWithPropID(kpidNoProperty); break;
+
+ case IDM_OPEN_ROOT_FOLDER: g_App.OpenRootFolder(); break;
+ case IDM_OPEN_PARENT_FOLDER: g_App.OpenParentFolder(); break;
+ case IDM_FOLDERS_HISTORY: g_App.FoldersHistory(); break;
+ case IDM_VIEW_FLAT_VIEW: g_App.ChangeFlatMode(); break;
+ case IDM_VIEW_REFRESH: g_App.RefreshView(); break;
+ case IDM_VIEW_AUTO_REFRESH: g_App.Change_AutoRefresh_Mode(); break;
+
+ // case IDM_VIEW_SHOW_STREAMS: g_App.Change_ShowNtfsStrems_Mode(); break;
+ /*
+ case IDM_VIEW_SHOW_DELETED:
+ {
+ g_App.Change_ShowDeleted();
+ bool isChecked = g_App.ShowDeletedFiles;
+ Save_ShowDeleted(isChecked);
+ }
+ */
+
+ case IDM_VIEW_TWO_PANELS: g_App.SwitchOnOffOnePanel(); break;
+ case IDM_VIEW_STANDARD_TOOLBAR: g_App.SwitchStandardToolbar(); break;
+ case IDM_VIEW_ARCHIVE_TOOLBAR: g_App.SwitchArchiveToolbar(); break;
+
+ case IDM_VIEW_TOOLBARS_SHOW_BUTTONS_TEXT: g_App.SwitchButtonsLables(); break;
+ case IDM_VIEW_TOOLBARS_LARGE_BUTTONS: g_App.SwitchLargeButtons(); break;
+
+ // Tools
+ case IDM_OPTIONS: OptionsDialog(hWnd, g_hInstance); break;
+
+ case IDM_BENCHMARK: MyBenchmark(false); break;
+ case IDM_BENCHMARK2: MyBenchmark(true); break;
+
+ // Help
+ case IDM_HELP_CONTENTS:
+ ShowHelpWindow(kFMHelpTopic);
+ break;
+ case IDM_ABOUT:
+ {
+ CAboutDialog dialog;
+ dialog.Create(hWnd);
+ break;
+ }
+ default:
+ {
+ if (id >= k_MenuID_OpenBookmark && id <= k_MenuID_OpenBookmark + 9)
+ {
+ g_App.OpenBookmark(id - k_MenuID_OpenBookmark);
+ return true;
+ }
+ else if (id >= k_MenuID_SetBookmark && id <= k_MenuID_SetBookmark + 9)
+ {
+ g_App.SetBookmark(id - k_MenuID_SetBookmark);
+ return true;
+ }
+ else if (id >= k_MenuID_Time && (unsigned)id < k_MenuID_Time + g_App._timestampLevels.Size())
+ {
+ g_App.SetTimestampLevel(g_App._timestampLevels[id - k_MenuID_Time]);
+ return true;
+ }
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/CPP/7zip/UI/FileManager/MyLoadMenu.h b/CPP/7zip/UI/FileManager/MyLoadMenu.h
new file mode 100644
index 0000000..e71dbbf
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/MyLoadMenu.h
@@ -0,0 +1,40 @@
+// MyLoadMenu.h
+
+#ifndef ZIP7_INC_MY_LOAD_MENU_H
+#define ZIP7_INC_MY_LOAD_MENU_H
+
+void OnMenuActivating(HWND hWnd, HMENU hMenu, int position);
+// void OnMenuUnActivating(HWND hWnd, HMENU hMenu, int id);
+// void OnMenuUnActivating(HWND hWnd);
+
+bool OnMenuCommand(HWND hWnd, unsigned id);
+void MyLoadMenu(bool needResetMenu);
+
+struct CFileMenu
+{
+ bool programMenu;
+ bool readOnly;
+ bool isHashFolder;
+ bool isFsFolder;
+ bool allAreFiles;
+ bool isAltStreamsSupported;
+ unsigned numItems;
+
+ FString FilePath;
+
+ CFileMenu():
+ programMenu(false),
+ readOnly(false),
+ isHashFolder(false),
+ isFsFolder(false),
+ allAreFiles(false),
+ isAltStreamsSupported(true),
+ numItems(0)
+ {}
+
+ void Load(HMENU hMenu, unsigned startPos);
+};
+
+bool ExecuteFileCommand(unsigned id);
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/MyWindowsNew.h b/CPP/7zip/UI/FileManager/MyWindowsNew.h
index c0fe843..325babc 100644
--- a/CPP/7zip/UI/FileManager/MyWindowsNew.h
+++ b/CPP/7zip/UI/FileManager/MyWindowsNew.h
@@ -1,76 +1,119 @@
-// MyWindowsNew.h
-
-#ifndef __MY_WINDOWS_NEW_H
-#define __MY_WINDOWS_NEW_H
-
-#ifdef _MSC_VER
-
-#include <ShObjIdl.h>
-
-#ifndef __ITaskbarList3_INTERFACE_DEFINED__
-#define __ITaskbarList3_INTERFACE_DEFINED__
-
-typedef enum THUMBBUTTONFLAGS
-{
- THBF_ENABLED = 0,
- THBF_DISABLED = 0x1,
- THBF_DISMISSONCLICK = 0x2,
- THBF_NOBACKGROUND = 0x4,
- THBF_HIDDEN = 0x8,
- THBF_NONINTERACTIVE = 0x10
-} THUMBBUTTONFLAGS;
-
-typedef enum THUMBBUTTONMASK
-{
- THB_BITMAP = 0x1,
- THB_ICON = 0x2,
- THB_TOOLTIP = 0x4,
- THB_FLAGS = 0x8
-} THUMBBUTTONMASK;
-
-// #include <pshpack8.h>
-
-typedef struct THUMBBUTTON
-{
- THUMBBUTTONMASK dwMask;
- UINT iId;
- UINT iBitmap;
- HICON hIcon;
- WCHAR szTip[260];
- THUMBBUTTONFLAGS dwFlags;
-} THUMBBUTTON;
-
-typedef struct THUMBBUTTON *LPTHUMBBUTTON;
-
-typedef enum TBPFLAG
-{
- TBPF_NOPROGRESS = 0,
- TBPF_INDETERMINATE = 0x1,
- TBPF_NORMAL = 0x2,
- TBPF_ERROR = 0x4,
- TBPF_PAUSED = 0x8
-} TBPFLAG;
-
-DEFINE_GUID(IID_ITaskbarList3, 0xEA1AFB91, 0x9E28, 0x4B86, 0x90, 0xE9, 0x9E, 0x9F, 0x8A, 0x5E, 0xEF, 0xAF);
-
-struct ITaskbarList3: public ITaskbarList2
-{
- STDMETHOD(SetProgressValue)(HWND hwnd, ULONGLONG ullCompleted, ULONGLONG ullTotal) = 0;
- STDMETHOD(SetProgressState)(HWND hwnd, TBPFLAG tbpFlags) = 0;
- STDMETHOD(RegisterTab)(HWND hwndTab, HWND hwndMDI) = 0;
- STDMETHOD(UnregisterTab)(HWND hwndTab) = 0;
- STDMETHOD(SetTabOrder)(HWND hwndTab, HWND hwndInsertBefore) = 0;
- STDMETHOD(SetTabActive)(HWND hwndTab, HWND hwndMDI, DWORD dwReserved) = 0;
- STDMETHOD(ThumbBarAddButtons)(HWND hwnd, UINT cButtons, LPTHUMBBUTTON pButton) = 0;
- STDMETHOD(ThumbBarUpdateButtons)(HWND hwnd, UINT cButtons, LPTHUMBBUTTON pButton) = 0;
- STDMETHOD(ThumbBarSetImageList)(HWND hwnd, HIMAGELIST himl) = 0;
- STDMETHOD(SetOverlayIcon)(HWND hwnd, HICON hIcon, LPCWSTR pszDescription) = 0;
- STDMETHOD(SetThumbnailTooltip)(HWND hwnd, LPCWSTR pszTip) = 0;
- STDMETHOD(SetThumbnailClip)(HWND hwnd, RECT *prcClip) = 0;
-};
-
-#endif
-
-#endif
-
-#endif
+// MyWindowsNew.h
+
+#ifndef ZIP7_INC_MY_WINDOWS_NEW_H
+#define ZIP7_INC_MY_WINDOWS_NEW_H
+
+#if defined(__MINGW32__) || defined(__MINGW64__) || defined(__MINGW32_VERSION)
+#include <shobjidl.h>
+
+#if defined(__MINGW32_VERSION) && !defined(__ITaskbarList3_INTERFACE_DEFINED__)
+// for old mingw
+extern "C" {
+DEFINE_GUID(IID_ITaskbarList3, 0xEA1AFB91, 0x9E28, 0x4B86, 0x90, 0xE9, 0x9E, 0x9F, 0x8A, 0x5E, 0xEF, 0xAF);
+DEFINE_GUID(CLSID_TaskbarList, 0x56fdf344, 0xfd6d, 0x11d0, 0x95,0x8a, 0x00,0x60,0x97,0xc9,0xa0,0x90);
+}
+#endif
+
+#else // is not __MINGW*
+
+#ifndef Z7_OLD_WIN_SDK
+#include <ShObjIdl.h>
+#else
+
+#ifndef HIMAGELIST
+struct _IMAGELIST;
+typedef struct _IMAGELIST* HIMAGELIST;
+#endif
+
+#ifndef __ITaskbarList_INTERFACE_DEFINED__
+#define __ITaskbarList_INTERFACE_DEFINED__
+DEFINE_GUID(IID_ITaskbarList, 0x56FDF342, 0xFD6D, 0x11d0, 0x95, 0x8A, 0x00, 0x60, 0x97, 0xC9, 0xA0, 0x90);
+struct ITaskbarList: public IUnknown
+{
+ STDMETHOD(HrInit)(void) = 0;
+ STDMETHOD(AddTab)(HWND hwnd) = 0;
+ STDMETHOD(DeleteTab)(HWND hwnd) = 0;
+ STDMETHOD(ActivateTab)(HWND hwnd) = 0;
+ STDMETHOD(SetActiveAlt)(HWND hwnd) = 0;
+};
+#endif // __ITaskbarList_INTERFACE_DEFINED__
+
+#ifndef __ITaskbarList2_INTERFACE_DEFINED__
+#define __ITaskbarList2_INTERFACE_DEFINED__
+DEFINE_GUID(IID_ITaskbarList2, 0x602D4995, 0xB13A, 0x429b, 0xA6, 0x6E, 0x19, 0x35, 0xE4, 0x4F, 0x43, 0x17);
+struct ITaskbarList2: public ITaskbarList
+{
+ STDMETHOD(MarkFullscreenWindow)(HWND hwnd, BOOL fFullscreen) = 0;
+};
+#endif // __ITaskbarList2_INTERFACE_DEFINED__
+
+#endif // Z7_OLD_WIN_SDK
+
+
+#ifndef __ITaskbarList3_INTERFACE_DEFINED__
+#define __ITaskbarList3_INTERFACE_DEFINED__
+
+typedef enum THUMBBUTTONFLAGS
+{
+ THBF_ENABLED = 0,
+ THBF_DISABLED = 0x1,
+ THBF_DISMISSONCLICK = 0x2,
+ THBF_NOBACKGROUND = 0x4,
+ THBF_HIDDEN = 0x8,
+ THBF_NONINTERACTIVE = 0x10
+} THUMBBUTTONFLAGS;
+
+typedef enum THUMBBUTTONMASK
+{
+ THB_BITMAP = 0x1,
+ THB_ICON = 0x2,
+ THB_TOOLTIP = 0x4,
+ THB_FLAGS = 0x8
+} THUMBBUTTONMASK;
+
+// #include <pshpack8.h>
+
+typedef struct THUMBBUTTON
+{
+ THUMBBUTTONMASK dwMask;
+ UINT iId;
+ UINT iBitmap;
+ HICON hIcon;
+ WCHAR szTip[260];
+ THUMBBUTTONFLAGS dwFlags;
+} THUMBBUTTON;
+
+typedef struct THUMBBUTTON *LPTHUMBBUTTON;
+
+typedef enum TBPFLAG
+{
+ TBPF_NOPROGRESS = 0,
+ TBPF_INDETERMINATE = 0x1,
+ TBPF_NORMAL = 0x2,
+ TBPF_ERROR = 0x4,
+ TBPF_PAUSED = 0x8
+} TBPFLAG;
+
+DEFINE_GUID(IID_ITaskbarList3, 0xEA1AFB91, 0x9E28, 0x4B86, 0x90, 0xE9, 0x9E, 0x9F, 0x8A, 0x5E, 0xEF, 0xAF);
+
+struct ITaskbarList3: public ITaskbarList2
+{
+ STDMETHOD(SetProgressValue)(HWND hwnd, ULONGLONG ullCompleted, ULONGLONG ullTotal) = 0;
+ STDMETHOD(SetProgressState)(HWND hwnd, TBPFLAG tbpFlags) = 0;
+ STDMETHOD(RegisterTab)(HWND hwndTab, HWND hwndMDI) = 0;
+ STDMETHOD(UnregisterTab)(HWND hwndTab) = 0;
+ STDMETHOD(SetTabOrder)(HWND hwndTab, HWND hwndInsertBefore) = 0;
+ STDMETHOD(SetTabActive)(HWND hwndTab, HWND hwndMDI, DWORD dwReserved) = 0;
+ STDMETHOD(ThumbBarAddButtons)(HWND hwnd, UINT cButtons, LPTHUMBBUTTON pButton) = 0;
+ STDMETHOD(ThumbBarUpdateButtons)(HWND hwnd, UINT cButtons, LPTHUMBBUTTON pButton) = 0;
+ STDMETHOD(ThumbBarSetImageList)(HWND hwnd, HIMAGELIST himl) = 0;
+ STDMETHOD(SetOverlayIcon)(HWND hwnd, HICON hIcon, LPCWSTR pszDescription) = 0;
+ STDMETHOD(SetThumbnailTooltip)(HWND hwnd, LPCWSTR pszTip) = 0;
+ STDMETHOD(SetThumbnailClip)(HWND hwnd, RECT *prcClip) = 0;
+};
+
+#endif // __ITaskbarList3_INTERFACE_DEFINED__
+
+#endif // __MINGW*
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/NetFolder.cpp b/CPP/7zip/UI/FileManager/NetFolder.cpp
new file mode 100644
index 0000000..879f1db
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/NetFolder.cpp
@@ -0,0 +1,281 @@
+// NetFolder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#include "../../PropID.h"
+
+#include "FSFolder.h"
+#include "NetFolder.h"
+#include "SysIconUtils.h"
+
+using namespace NWindows;
+using namespace NNet;
+
+static const Byte kProps[] =
+{
+ kpidName,
+ kpidLocalName,
+ kpidComment,
+ kpidProvider
+};
+
+void CNetFolder::Init(const UString &path)
+{
+ /*
+ if (path.Len() > 2)
+ {
+ if (path[0] == L'\\' && path[1] == L'\\')
+ {
+ CResource netResource;
+ netResource.RemoteName = GetSystemString(path.Left(path.Len() - 1));
+ netResource.Scope = RESOURCE_GLOBALNET;
+ netResource.Type = RESOURCETYPE_DISK;
+ netResource.DisplayType = RESOURCEDISPLAYTYPE_SERVER;
+ netResource.Usage = RESOURCEUSAGE_CONTAINER;
+ Init(&netResource, 0, path);
+ return;
+ }
+ }
+ Init(0, 0 , L"");
+ */
+ CResourceW resource;
+ resource.RemoteNameIsDefined = true;
+ if (!path.IsEmpty())
+ resource.RemoteName.SetFrom(path, path.Len() - 1);
+ resource.ProviderIsDefined = false;
+ resource.LocalNameIsDefined = false;
+ resource.CommentIsDefined = false;
+ resource.Type = RESOURCETYPE_DISK;
+ resource.Scope = RESOURCE_GLOBALNET;
+ resource.Usage = 0;
+ resource.DisplayType = 0;
+ CResourceW destResource;
+ UString systemPathPart;
+ DWORD result = GetResourceInformation(resource, destResource, systemPathPart);
+ if (result == NO_ERROR)
+ Init(&destResource, NULL, path);
+ else
+ Init(NULL, NULL , L"");
+ return;
+}
+
+void CNetFolder::Init(const NWindows::NNet::CResourceW *netResource,
+ IFolderFolder *parentFolder, const UString &path)
+{
+ _path = path;
+ if (!netResource)
+ _netResourcePointer = NULL;
+ else
+ {
+ _netResource = *netResource;
+ _netResourcePointer = &_netResource;
+
+ // if (_netResource.DisplayType == RESOURCEDISPLAYTYPE_SERVER)
+ _path = _netResource.RemoteName;
+
+ /* WinXP-64: When we move UP from Network share without _parentFolder chain,
+ we can get empty _netResource.RemoteName. Do we need to use Provider there ? */
+ if (_path.IsEmpty())
+ _path = _netResource.Provider;
+
+ if (!_path.IsEmpty())
+ _path.Add_PathSepar();
+ }
+ _parentFolder = parentFolder;
+}
+
+Z7_COM7F_IMF(CNetFolder::LoadItems())
+{
+ _items.Clear();
+ CEnum enumerator;
+
+ for (;;)
+ {
+ DWORD result = enumerator.Open(
+ RESOURCE_GLOBALNET,
+ RESOURCETYPE_DISK,
+ 0, // enumerate all resources
+ _netResourcePointer
+ );
+ if (result == NO_ERROR)
+ break;
+ if (result != ERROR_ACCESS_DENIED)
+ return HRESULT_FROM_WIN32(result);
+ if (_netResourcePointer)
+ result = AddConnection2(_netResource,
+ NULL, NULL, CONNECT_INTERACTIVE);
+ if (result != NO_ERROR)
+ return HRESULT_FROM_WIN32(result);
+ }
+
+ for (;;)
+ {
+ CResourceEx resource;
+ const DWORD result = enumerator.Next(resource);
+ if (result == NO_ERROR)
+ {
+ if (!resource.RemoteNameIsDefined) // For Win 98, I don't know what's wrong
+ resource.RemoteName = resource.Comment;
+ resource.Name = resource.RemoteName;
+ const int pos = resource.Name.ReverseFind_PathSepar();
+ if (pos >= 0)
+ {
+ // _path = resource.Name.Left(pos + 1);
+ resource.Name.DeleteFrontal((unsigned)pos + 1);
+ }
+ _items.Add(resource);
+ }
+ else if (result == ERROR_NO_MORE_ITEMS)
+ break;
+ else
+ return HRESULT_FROM_WIN32(result);
+ }
+
+ /*
+ It's too slow for some systems.
+ if (_netResourcePointer && _netResource.DisplayType == RESOURCEDISPLAYTYPE_SERVER)
+ {
+ for (char c = 'a'; c <= 'z'; c++)
+ {
+ CResourceEx resource;
+ resource.Name = UString(wchar_t(c)) + L'$';
+ resource.RemoteNameIsDefined = true;
+ resource.RemoteName = _path + resource.Name;
+
+ NFile::NFind::CFindFile findFile;
+ NFile::NFind::CFileInfo fileInfo;
+ if (!findFile.FindFirst(us2fs(resource.RemoteName) + FString(FCHAR_PATH_SEPARATOR) + FCHAR_ANY_MASK, fileInfo))
+ continue;
+ resource.Usage = RESOURCEUSAGE_CONNECTABLE;
+ resource.LocalNameIsDefined = false;
+ resource.CommentIsDefined = false;
+ resource.ProviderIsDefined = false;
+ _items.Add(resource);
+ }
+ }
+ */
+ return S_OK;
+}
+
+
+Z7_COM7F_IMF(CNetFolder::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = _items.Size();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CNetFolder::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+ const CResourceEx &item = _items[itemIndex];
+ switch (propID)
+ {
+ case kpidIsDir: prop = true; break;
+ case kpidName:
+ // if (item.RemoteNameIsDefined)
+ prop = item.Name;
+ break;
+ case kpidLocalName: if (item.LocalNameIsDefined) prop = item.LocalName; break;
+ case kpidComment: if (item.CommentIsDefined) prop = item.Comment; break;
+ case kpidProvider: if (item.ProviderIsDefined) prop = item.Provider; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CNetFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder))
+{
+ *resultFolder = NULL;
+ const CResourceEx &resource = _items[index];
+ if (resource.Usage == RESOURCEUSAGE_CONNECTABLE ||
+ resource.DisplayType == RESOURCEDISPLAYTYPE_SHARE)
+ {
+ NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder;
+ CMyComPtr<IFolderFolder> subFolder = fsFolderSpec;
+ RINOK(fsFolderSpec->Init(us2fs(resource.RemoteName + WCHAR_PATH_SEPARATOR))) // , this
+ *resultFolder = subFolder.Detach();
+ }
+ else
+ {
+ CNetFolder *netFolder = new CNetFolder;
+ CMyComPtr<IFolderFolder> subFolder = netFolder;
+ netFolder->Init(&resource, this, resource.Name + WCHAR_PATH_SEPARATOR);
+ *resultFolder = subFolder.Detach();
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CNetFolder::BindToFolder(const wchar_t * /* name */, IFolderFolder ** /* resultFolder */))
+{
+ return E_NOTIMPL;
+}
+
+Z7_COM7F_IMF(CNetFolder::BindToParentFolder(IFolderFolder **resultFolder))
+{
+ *resultFolder = NULL;
+ if (_parentFolder)
+ {
+ CMyComPtr<IFolderFolder> parentFolder = _parentFolder;
+ *resultFolder = parentFolder.Detach();
+ return S_OK;
+ }
+ if (_netResourcePointer)
+ {
+ CResourceW resourceParent;
+ const DWORD result = GetResourceParent(_netResource, resourceParent);
+ if (result != NO_ERROR)
+ return HRESULT_FROM_WIN32(result);
+ if (!_netResource.RemoteNameIsDefined)
+ return S_OK;
+
+ CNetFolder *netFolder = new CNetFolder;
+ CMyComPtr<IFolderFolder> subFolder = netFolder;
+ netFolder->Init(&resourceParent, NULL, WSTRING_PATH_SEPARATOR);
+ *resultFolder = subFolder.Detach();
+ }
+ return S_OK;
+}
+
+IMP_IFolderFolder_Props(CNetFolder)
+
+Z7_COM7F_IMF(CNetFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value))
+{
+ NWindows::NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidType: prop = "NetFolder"; break;
+ case kpidPath: prop = _path; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CNetFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex))
+{
+ if (index >= (UInt32)_items.Size())
+ return E_INVALIDARG;
+ *iconIndex = 0;
+ const CResourceW &resource = _items[index];
+ int iconIndexTemp;
+ if (resource.DisplayType == RESOURCEDISPLAYTYPE_SERVER ||
+ resource.Usage == RESOURCEUSAGE_CONNECTABLE)
+ {
+ if (GetRealIconIndex(us2fs(resource.RemoteName), 0, iconIndexTemp))
+ {
+ *iconIndex = iconIndexTemp;
+ return S_OK;
+ }
+ }
+ else
+ {
+ if (GetRealIconIndex(FTEXT(""), FILE_ATTRIBUTE_DIRECTORY, iconIndexTemp))
+ {
+ *iconIndex = iconIndexTemp;
+ return S_OK;
+ }
+ // *anIconIndex = GetRealIconIndex(0, L"\\\\HOME");
+ }
+ return GetLastError_noZero_HRESULT();
+}
diff --git a/CPP/7zip/UI/FileManager/NetFolder.h b/CPP/7zip/UI/FileManager/NetFolder.h
new file mode 100644
index 0000000..352f5bd
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/NetFolder.h
@@ -0,0 +1,36 @@
+// NetFolder.h
+
+#ifndef ZIP7_INC_NET_FOLDER_H
+#define ZIP7_INC_NET_FOLDER_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../../Windows/Net.h"
+
+#include "IFolder.h"
+
+struct CResourceEx: public NWindows::NNet::CResourceW
+{
+ UString Name;
+};
+
+Z7_CLASS_IMP_NOQIB_2(
+ CNetFolder
+ , IFolderFolder
+ , IFolderGetSystemIconIndex
+)
+ NWindows::NNet::CResourceW _netResource;
+ NWindows::NNet::CResourceW *_netResourcePointer;
+
+ CObjectVector<CResourceEx> _items;
+
+ CMyComPtr<IFolderFolder> _parentFolder;
+ UString _path;
+public:
+ CNetFolder(): _netResourcePointer(NULL) {}
+ void Init(const UString &path);
+ void Init(const NWindows::NNet::CResourceW *netResource,
+ IFolderFolder *parentFolder, const UString &path);
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/OpenCallback.cpp b/CPP/7zip/UI/FileManager/OpenCallback.cpp
new file mode 100644
index 0000000..5b6df50
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/OpenCallback.cpp
@@ -0,0 +1,86 @@
+// OpenCallback.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/ComTry.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/PropVariant.h"
+
+#include "../../Common/FileStreams.h"
+
+#include "../Common/ZipRegistry.h"
+
+#include "OpenCallback.h"
+#include "PasswordDialog.h"
+
+using namespace NWindows;
+
+HRESULT COpenArchiveCallback::Open_SetTotal(const UInt64 *numFiles, const UInt64 *numBytes)
+// Z7_COM7F_IMF(COpenArchiveCallback::SetTotal(const UInt64 *numFiles, const UInt64 *numBytes))
+{
+ // COM_TRY_BEGIN
+ RINOK(ProgressDialog.Sync.CheckStop())
+ {
+ // NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ ProgressDialog.Sync.Set_NumFilesTotal(numFiles ? *numFiles : (UInt64)(Int64)-1);
+ // if (numFiles)
+ {
+ ProgressDialog.Sync.Set_BytesProgressMode(numFiles == NULL);
+ }
+ if (numBytes)
+ ProgressDialog.Sync.Set_NumBytesTotal(*numBytes);
+ }
+ return S_OK;
+ // COM_TRY_END
+}
+
+HRESULT COpenArchiveCallback::Open_SetCompleted(const UInt64 *numFiles, const UInt64 *numBytes)
+// Z7_COM7F_IMF(COpenArchiveCallback::SetCompleted(const UInt64 *numFiles, const UInt64 *numBytes))
+{
+ // COM_TRY_BEGIN
+ // NSynchronization::CCriticalSectionLock lock(_criticalSection);
+ if (numFiles)
+ ProgressDialog.Sync.Set_NumFilesCur(*numFiles);
+ if (numBytes)
+ ProgressDialog.Sync.Set_NumBytesCur(*numBytes);
+ return ProgressDialog.Sync.CheckStop();
+ // COM_TRY_END
+}
+
+HRESULT COpenArchiveCallback::Open_CheckBreak()
+{
+ return ProgressDialog.Sync.CheckStop();
+}
+
+HRESULT COpenArchiveCallback::Open_Finished()
+{
+ return ProgressDialog.Sync.CheckStop();
+}
+
+#ifndef Z7_NO_CRYPTO
+HRESULT COpenArchiveCallback::Open_CryptoGetTextPassword(BSTR *password)
+// Z7_COM7F_IMF(COpenArchiveCallback::CryptoGetTextPassword(BSTR *password))
+{
+ // COM_TRY_BEGIN
+ PasswordWasAsked = true;
+ if (!PasswordIsDefined)
+ {
+ CPasswordDialog dialog;
+ bool showPassword = NExtract::Read_ShowPassword();
+ dialog.ShowPassword = showPassword;
+
+ ProgressDialog.WaitCreating();
+ if (dialog.Create(ProgressDialog) != IDOK)
+ return E_ABORT;
+
+ Password = dialog.Password;
+ PasswordIsDefined = true;
+ if (dialog.ShowPassword != showPassword)
+ NExtract::Save_ShowPassword(dialog.ShowPassword);
+ }
+ return StringToBstr(Password, password);
+ // COM_TRY_END
+}
+#endif
diff --git a/CPP/7zip/UI/FileManager/OpenCallback.h b/CPP/7zip/UI/FileManager/OpenCallback.h
new file mode 100644
index 0000000..8f4638c
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/OpenCallback.h
@@ -0,0 +1,69 @@
+// OpenCallback.h
+
+#ifndef ZIP7_INC_OPEN_CALLBACK_H
+#define ZIP7_INC_OPEN_CALLBACK_H
+
+#include "../Common/ArchiveOpenCallback.h"
+
+#ifdef Z7_SFX
+#include "ProgressDialog.h"
+#else
+#include "ProgressDialog2.h"
+#endif
+
+/* we can use IArchiveOpenCallback or IOpenCallbackUI here */
+
+class COpenArchiveCallback Z7_final:
+ /*
+ public IArchiveOpenCallback,
+ public IProgress,
+ public ICryptoGetTextPassword,
+ public CMyUnknownImp
+ */
+ public IOpenCallbackUI
+{
+ // NWindows::NSynchronization::CCriticalSection _criticalSection;
+public:
+ bool PasswordIsDefined;
+ bool PasswordWasAsked;
+ UString Password;
+ HWND ParentWindow;
+ CProgressDialog ProgressDialog;
+
+ /*
+ Z7_COM_UNKNOWN_IMP_3(
+ IArchiveOpenVolumeCallback,
+ IProgress
+ ICryptoGetTextPassword
+ )
+
+ Z7_IFACE_COM7_IMP(IProgress)
+ Z7_IFACE_COM7_IMP(IArchiveOpenCallback)
+ // ICryptoGetTextPassword
+ Z7_COM7F_IMP(CryptoGetTextPassword(BSTR *password))
+ */
+
+ Z7_IFACE_IMP(IOpenCallbackUI)
+
+ COpenArchiveCallback():
+ ParentWindow(NULL)
+ {
+ // _subArchiveMode = false;
+ PasswordIsDefined = false;
+ PasswordWasAsked = false;
+ }
+ /*
+ void Init()
+ {
+ PasswordIsDefined = false;
+ _subArchiveMode = false;
+ }
+ */
+
+ INT_PTR StartProgressDialog(const UString &title, NWindows::CThread &thread)
+ {
+ return ProgressDialog.Create(title, thread, ParentWindow);
+ }
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/OptionsDialog.cpp b/CPP/7zip/UI/FileManager/OptionsDialog.cpp
new file mode 100644
index 0000000..b71c323
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/OptionsDialog.cpp
@@ -0,0 +1,89 @@
+// OptionsDialog.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Windows/Control/Dialog.h"
+#include "../../../Windows/Control/PropertyPage.h"
+
+#include "DialogSize.h"
+
+#include "EditPage.h"
+#include "EditPageRes.h"
+#include "FoldersPage.h"
+#include "FoldersPageRes.h"
+#include "LangPage.h"
+#include "LangPageRes.h"
+#include "MenuPage.h"
+#include "MenuPageRes.h"
+#include "SettingsPage.h"
+#include "SettingsPageRes.h"
+#include "SystemPage.h"
+#include "SystemPageRes.h"
+
+#include "App.h"
+#include "LangUtils.h"
+#include "MyLoadMenu.h"
+
+#include "resource.h"
+
+using namespace NWindows;
+
+void OptionsDialog(HWND hwndOwner, HINSTANCE hInstance);
+void OptionsDialog(HWND hwndOwner, HINSTANCE /* hInstance */)
+{
+ CSystemPage systemPage;
+ CMenuPage menuPage;
+ CFoldersPage foldersPage;
+ CEditPage editPage;
+ CSettingsPage settingsPage;
+ CLangPage langPage;
+
+ CObjectVector<NControl::CPageInfo> pages;
+ BIG_DIALOG_SIZE(200, 200);
+
+ const UINT pageIDs[] = {
+ SIZED_DIALOG(IDD_SYSTEM),
+ SIZED_DIALOG(IDD_MENU),
+ SIZED_DIALOG(IDD_FOLDERS),
+ SIZED_DIALOG(IDD_EDIT),
+ SIZED_DIALOG(IDD_SETTINGS),
+ SIZED_DIALOG(IDD_LANG) };
+
+ NControl::CPropertyPage *pagePointers[] = { &systemPage, &menuPage, &foldersPage, &editPage, &settingsPage, &langPage };
+
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(pageIDs); i++)
+ {
+ NControl::CPageInfo &page = pages.AddNew();
+ page.ID = pageIDs[i];
+ #ifdef Z7_LANG
+ LangString_OnlyFromLangFile(page.ID, page.Title);
+ #endif
+ page.Page = pagePointers[i];
+ }
+
+ const INT_PTR res = NControl::MyPropertySheet(pages, hwndOwner, LangString(IDS_OPTIONS));
+
+ if (res != -1 && res != 0)
+ {
+ if (langPage.LangWasChanged)
+ {
+ // g_App._window.SetText(LangString(IDS_APP_TITLE, 0x03000000));
+ MyLoadMenu(true); // needResetMenu
+ g_App.ReloadToolbars();
+ g_App.MoveSubWindows(); // we need it to change list window aafter _toolBar.AutoSize();
+ g_App.ReloadLangItems();
+ }
+
+ /*
+ if (systemPage.WasChanged)
+ {
+ // probably it doesn't work, since image list is locked?
+ g_App.SysIconsWereChanged();
+ }
+ */
+
+ g_App.SetListSettings();
+ g_App.RefreshAllPanels();
+ // ::PostMessage(hwndOwner, kLangWasChangedMessage, 0 , 0);
+ }
+}
diff --git a/CPP/7zip/UI/FileManager/OverwriteDialog.cpp b/CPP/7zip/UI/FileManager/OverwriteDialog.cpp
index 3f0180d..096527c 100644
--- a/CPP/7zip/UI/FileManager/OverwriteDialog.cpp
+++ b/CPP/7zip/UI/FileManager/OverwriteDialog.cpp
@@ -1,122 +1,138 @@
-// OverwriteDialog.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/StringConvert.h"
-
-#include "../../../Windows/PropVariantConv.h"
-#include "../../../Windows/ResourceString.h"
-
-#include "../../../Windows/Control/Static.h"
-
-#include "FormatUtils.h"
-#include "LangUtils.h"
-#include "OverwriteDialog.h"
-
-#include "PropertyNameRes.h"
-
-using namespace NWindows;
-
-#ifdef LANG
-static const UInt32 kLangIDs[] =
-{
- IDT_OVERWRITE_HEADER,
- IDT_OVERWRITE_QUESTION_BEGIN,
- IDT_OVERWRITE_QUESTION_END,
- IDB_YES_TO_ALL,
- IDB_NO_TO_ALL,
- IDB_AUTO_RENAME
-};
-#endif
-
-static const unsigned kCurrentFileNameSizeLimit = 82;
-static const unsigned kCurrentFileNameSizeLimit2 = 30;
-
-void COverwriteDialog::ReduceString(UString &s)
-{
- unsigned size = _isBig ? kCurrentFileNameSizeLimit : kCurrentFileNameSizeLimit2;
- if (s.Len() > size)
- {
- s.Delete(size / 2, s.Len() - size);
- s.Insert(size / 2, L" ... ");
- }
- if (!s.IsEmpty() && s.Back() == ' ')
- {
- // s += (wchar_t)(0x2423);
- s.InsertAtFront(L'\"');
- s += L'\"';
- }
-}
-
-void COverwriteDialog::SetFileInfoControl(int textID, int iconID,
- const NOverwriteDialog::CFileInfo &fileInfo)
-{
- UString sizeString;
- if (fileInfo.SizeIsDefined)
- sizeString = MyFormatNew(IDS_FILE_SIZE, NumberToString(fileInfo.Size));
-
- const UString &fileName = fileInfo.Name;
- int slashPos = fileName.ReverseFind_PathSepar();
- UString s1 = fileName.Left(slashPos + 1);
- UString s2 = fileName.Ptr(slashPos + 1);
-
- ReduceString(s1);
- ReduceString(s2);
-
- UString s = s1;
- s.Add_LF();
- s += s2;
- s.Add_LF();
- s += sizeString;
- s.Add_LF();
-
- if (fileInfo.TimeIsDefined)
- {
- AddLangString(s, IDS_PROP_MTIME);
- s += ": ";
- char t[32];
- ConvertUtcFileTimeToString(fileInfo.Time, t);
- s += t;
- }
-
- NControl::CDialogChildControl control;
- control.Init(*this, textID);
- control.SetText(s);
-
- SHFILEINFO shellFileInfo;
- if (::SHGetFileInfo(
- GetSystemString(fileInfo.Name), FILE_ATTRIBUTE_NORMAL, &shellFileInfo,
- sizeof(shellFileInfo), SHGFI_ICON | SHGFI_USEFILEATTRIBUTES | SHGFI_LARGEICON))
- {
- NControl::CStatic staticContol;
- staticContol.Attach(GetItem(iconID));
- staticContol.SetIcon(shellFileInfo.hIcon);
- }
-}
-
-bool COverwriteDialog::OnInit()
-{
- #ifdef LANG
- LangSetWindowText(*this, IDD_OVERWRITE);
- LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs));
- #endif
- SetFileInfoControl(IDT_OVERWRITE_OLD_FILE_SIZE_TIME, IDI_OVERWRITE_OLD_FILE, OldFileInfo);
- SetFileInfoControl(IDT_OVERWRITE_NEW_FILE_SIZE_TIME, IDI_OVERWRITE_NEW_FILE, NewFileInfo);
- NormalizePosition();
- return CModalDialog::OnInit();
-}
-
-bool COverwriteDialog::OnButtonClicked(int buttonID, HWND buttonHWND)
-{
- switch (buttonID)
- {
- case IDYES:
- case IDNO:
- case IDB_YES_TO_ALL:
- case IDB_NO_TO_ALL:
- case IDB_AUTO_RENAME:
- End(buttonID);
- return true;
- }
- return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
-}
+// OverwriteDialog.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/PropVariantConv.h"
+#include "../../../Windows/ResourceString.h"
+
+#include "../../../Windows/Control/Static.h"
+
+#include "FormatUtils.h"
+#include "LangUtils.h"
+#include "OverwriteDialog.h"
+
+#include "PropertyNameRes.h"
+
+using namespace NWindows;
+
+#ifdef Z7_LANG
+static const UInt32 kLangIDs[] =
+{
+ IDT_OVERWRITE_HEADER,
+ IDT_OVERWRITE_QUESTION_BEGIN,
+ IDT_OVERWRITE_QUESTION_END,
+ IDB_YES_TO_ALL,
+ IDB_NO_TO_ALL,
+ IDB_AUTO_RENAME
+};
+#endif
+
+static const unsigned kCurrentFileNameSizeLimit = 82;
+static const unsigned kCurrentFileNameSizeLimit2 = 30;
+
+void COverwriteDialog::ReduceString(UString &s)
+{
+ unsigned size = _isBig ? kCurrentFileNameSizeLimit : kCurrentFileNameSizeLimit2;
+ if (s.Len() > size)
+ {
+ s.Delete(size / 2, s.Len() - size);
+ s.Insert(size / 2, L" ... ");
+ }
+ if (!s.IsEmpty() && s.Back() == ' ')
+ {
+ // s += (wchar_t)(0x2423);
+ s.InsertAtFront(L'\"');
+ s += L'\"';
+ }
+}
+
+void COverwriteDialog::SetFileInfoControl(unsigned textID, unsigned iconID,
+ const NOverwriteDialog::CFileInfo &fileInfo)
+{
+ UString sizeString;
+ if (fileInfo.SizeIsDefined)
+ sizeString = MyFormatNew(IDS_FILE_SIZE, NumberToString(fileInfo.Size));
+
+ const UString &fileName = fileInfo.Name;
+ int slashPos = fileName.ReverseFind_PathSepar();
+ UString s1 = fileName.Left((unsigned)(slashPos + 1));
+ UString s2 = fileName.Ptr((unsigned)(slashPos + 1));
+
+ ReduceString(s1);
+ ReduceString(s2);
+
+ UString s = s1;
+ s.Add_LF();
+ s += s2;
+ s.Add_LF();
+ s += sizeString;
+ s.Add_LF();
+
+ if (fileInfo.TimeIsDefined)
+ {
+ AddLangString(s, IDS_PROP_MTIME);
+ s += ": ";
+ char t[32];
+ ConvertUtcFileTimeToString(fileInfo.Time, t);
+ s += t;
+ }
+
+ NControl::CDialogChildControl control;
+ control.Init(*this, textID);
+ control.SetText(s);
+
+ SHFILEINFO shellFileInfo;
+ if (::SHGetFileInfo(
+ GetSystemString(fileInfo.Name), FILE_ATTRIBUTE_NORMAL, &shellFileInfo,
+ sizeof(shellFileInfo), SHGFI_ICON | SHGFI_USEFILEATTRIBUTES | SHGFI_LARGEICON))
+ {
+ NControl::CStatic staticContol;
+ staticContol.Attach(GetItem(iconID));
+ staticContol.SetIcon(shellFileInfo.hIcon);
+ }
+}
+
+bool COverwriteDialog::OnInit()
+{
+ #ifdef Z7_LANG
+ LangSetWindowText(*this, IDD_OVERWRITE);
+ LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
+ #endif
+ SetFileInfoControl(IDT_OVERWRITE_OLD_FILE_SIZE_TIME, IDI_OVERWRITE_OLD_FILE, OldFileInfo);
+ SetFileInfoControl(IDT_OVERWRITE_NEW_FILE_SIZE_TIME, IDI_OVERWRITE_NEW_FILE, NewFileInfo);
+ NormalizePosition();
+
+ if (!ShowExtraButtons)
+ {
+ HideItem(IDB_YES_TO_ALL);
+ HideItem(IDB_NO_TO_ALL);
+ HideItem(IDB_AUTO_RENAME);
+ }
+
+ if (DefaultButton_is_NO)
+ {
+ PostMsg(DM_SETDEFID, IDNO);
+ HWND h = GetItem(IDNO);
+ PostMsg(WM_NEXTDLGCTL, (WPARAM)h, TRUE);
+ // ::SetFocus(h);
+ }
+
+ return CModalDialog::OnInit();
+}
+
+bool COverwriteDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ switch (buttonID)
+ {
+ case IDYES:
+ case IDNO:
+ case IDB_YES_TO_ALL:
+ case IDB_NO_TO_ALL:
+ case IDB_AUTO_RENAME:
+ End((INT_PTR)buttonID);
+ return true;
+ }
+ return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
+}
diff --git a/CPP/7zip/UI/FileManager/OverwriteDialog.h b/CPP/7zip/UI/FileManager/OverwriteDialog.h
index 4564a47..a9ca991 100644
--- a/CPP/7zip/UI/FileManager/OverwriteDialog.h
+++ b/CPP/7zip/UI/FileManager/OverwriteDialog.h
@@ -1,69 +1,79 @@
-// OverwriteDialog.h
-
-#ifndef __OVERWRITE_DIALOG_H
-#define __OVERWRITE_DIALOG_H
-
-#include "../../../Windows/Control/Dialog.h"
-
-#include "DialogSize.h"
-#include "OverwriteDialogRes.h"
-
-namespace NOverwriteDialog
-{
- struct CFileInfo
- {
- bool SizeIsDefined;
- bool TimeIsDefined;
- UInt64 Size;
- FILETIME Time;
- UString Name;
-
- void SetTime(const FILETIME *t)
- {
- if (t == 0)
- TimeIsDefined = false;
- else
- {
- TimeIsDefined = true;
- Time = *t;
- }
- }
- void SetSize(const UInt64 *size)
- {
- if (size == 0)
- SizeIsDefined = false;
- else
- {
- SizeIsDefined = true;
- Size = *size;
- }
- }
- };
-}
-
-class COverwriteDialog: public NWindows::NControl::CModalDialog
-{
- bool _isBig;
-
- void SetFileInfoControl(int textID, int iconID, const NOverwriteDialog::CFileInfo &fileInfo);
- virtual bool OnInit();
- bool OnButtonClicked(int buttonID, HWND buttonHWND);
- void ReduceString(UString &s);
-
-public:
- INT_PTR Create(HWND parent = 0)
- {
- BIG_DIALOG_SIZE(280, 200);
- #ifdef UNDER_CE
- _isBig = isBig;
- #else
- _isBig = true;
- #endif
- return CModalDialog::Create(SIZED_DIALOG(IDD_OVERWRITE), parent);
- }
-
- NOverwriteDialog::CFileInfo OldFileInfo;
- NOverwriteDialog::CFileInfo NewFileInfo;
-};
-
-#endif
+// OverwriteDialog.h
+
+#ifndef ZIP7_INC_OVERWRITE_DIALOG_H
+#define ZIP7_INC_OVERWRITE_DIALOG_H
+
+#include "../../../Windows/Control/Dialog.h"
+
+#include "DialogSize.h"
+#include "OverwriteDialogRes.h"
+
+namespace NOverwriteDialog
+{
+ struct CFileInfo
+ {
+ bool SizeIsDefined;
+ bool TimeIsDefined;
+ UInt64 Size;
+ FILETIME Time;
+ UString Name;
+
+ void SetTime(const FILETIME *t)
+ {
+ if (!t)
+ TimeIsDefined = false;
+ else
+ {
+ TimeIsDefined = true;
+ Time = *t;
+ }
+ }
+
+ void SetSize(UInt64 size)
+ {
+ SizeIsDefined = true;
+ Size = size;
+ }
+
+ void SetSize(const UInt64 *size)
+ {
+ if (!size)
+ SizeIsDefined = false;
+ else
+ SetSize(*size);
+ }
+ };
+}
+
+class COverwriteDialog: public NWindows::NControl::CModalDialog
+{
+ bool _isBig;
+
+ void SetFileInfoControl(unsigned textID, unsigned iconID, const NOverwriteDialog::CFileInfo &fileInfo);
+ virtual bool OnInit() Z7_override;
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+ void ReduceString(UString &s);
+
+public:
+ bool ShowExtraButtons;
+ bool DefaultButton_is_NO;
+
+
+ COverwriteDialog(): ShowExtraButtons(true), DefaultButton_is_NO(false) {}
+
+ INT_PTR Create(HWND parent = NULL)
+ {
+ BIG_DIALOG_SIZE(280, 200);
+ #ifdef UNDER_CE
+ _isBig = isBig;
+ #else
+ _isBig = true;
+ #endif
+ return CModalDialog::Create(SIZED_DIALOG(IDD_OVERWRITE), parent);
+ }
+
+ NOverwriteDialog::CFileInfo OldFileInfo;
+ NOverwriteDialog::CFileInfo NewFileInfo;
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/OverwriteDialog.rc b/CPP/7zip/UI/FileManager/OverwriteDialog.rc
index 80f48b0..29f9912 100644
--- a/CPP/7zip/UI/FileManager/OverwriteDialog.rc
+++ b/CPP/7zip/UI/FileManager/OverwriteDialog.rc
@@ -1,91 +1,91 @@
-#include "OverwriteDialogRes.h"
-#include "../../GuiCommon.rc"
-
-#define xc 280
-#define yc 200
-
-#undef iconSize
-#define iconSize 24
-
-#undef x
-#undef fx
-#undef fy
-#define x (m + iconSize + m)
-#define fx (xc - iconSize - m)
-#define fy 50
-
-#define bSizeBig 104
-#undef bx1
-#define bx1 (xs - m - bSizeBig)
-
-IDD_OVERWRITE DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
-CAPTION "Confirm File Replace"
-BEGIN
- LTEXT "Destination folder already contains processed file.", IDT_OVERWRITE_HEADER, m, 7, xc, 8
- LTEXT "Would you like to replace the existing file", IDT_OVERWRITE_QUESTION_BEGIN, m, 28, xc, 8
-
- ICON "", IDI_OVERWRITE_OLD_FILE, m, 44, iconSize, iconSize
- LTEXT "", IDT_OVERWRITE_OLD_FILE_SIZE_TIME, x, 44, fx, fy, SS_NOPREFIX
-
- LTEXT "with this one?", IDT_OVERWRITE_QUESTION_END, m, 98, xc, 8
-
- ICON "", IDI_OVERWRITE_NEW_FILE, m, 114, iconSize, iconSize
- LTEXT "", IDT_OVERWRITE_NEW_FILE_SIZE_TIME, x, 114, fx, fy, SS_NOPREFIX
-
- PUSHBUTTON "&Yes", IDYES, bx3, by2, bxs, bys
- PUSHBUTTON "Yes to &All", IDB_YES_TO_ALL, bx2, by2, bxs, bys
- PUSHBUTTON "A&uto Rename", IDB_AUTO_RENAME, bx1, by2, bSizeBig, bys
- PUSHBUTTON "&No", IDNO, bx3, by1, bxs, bys
- PUSHBUTTON "No to A&ll", IDB_NO_TO_ALL, bx2, by1, bxs, bys
- PUSHBUTTON "&Cancel", IDCANCEL, xs - m - bxs, by1, bxs, bys
-END
-
-
-#ifdef UNDER_CE
-
-#undef m
-#undef xc
-#undef yc
-
-#define m 4
-#define xc 152
-#define yc 144
-
-#undef fy
-#define fy 40
-
-#undef bxs
-#define bxs 48
-
-#undef bx1
-
-#define bx1 (xs - m - bxs)
-
-IDD_OVERWRITE_2 DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
-CAPTION "Confirm File Replace"
-BEGIN
- LTEXT "Would you like to replace the existing file", IDT_OVERWRITE_QUESTION_BEGIN, m, m, xc, 8
-
- ICON "", IDI_OVERWRITE_OLD_FILE, m, 20, iconSize, iconSize
- LTEXT "", IDT_OVERWRITE_OLD_FILE_SIZE_TIME, x, 20, fx, fy, SS_NOPREFIX
-
- LTEXT "with this one?", IDT_OVERWRITE_QUESTION_END, m, 60, xc, 8
-
- ICON "", IDI_OVERWRITE_NEW_FILE, m, 72, iconSize, iconSize
- LTEXT "", IDT_OVERWRITE_NEW_FILE_SIZE_TIME, x, 72, fx, fy, SS_NOPREFIX
-
- PUSHBUTTON "&Yes", IDYES, bx3, by2, bxs, bys
- PUSHBUTTON "Yes to &All", IDB_YES_TO_ALL, bx2, by2, bxs, bys
- PUSHBUTTON "A&uto Rename", IDB_AUTO_RENAME, bx1, by2, bxs, bys
- PUSHBUTTON "&No", IDNO, bx3, by1, bxs, bys
- PUSHBUTTON "No to A&ll", IDB_NO_TO_ALL, bx2, by1, bxs, bys
- PUSHBUTTON "&Cancel", IDCANCEL, bx1, by1, bxs, bys
-END
-
-#endif
-
-
-STRINGTABLE
-BEGIN
- IDS_FILE_SIZE "{0} bytes"
-END
+#include "OverwriteDialogRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 280
+#define yc 200
+
+#undef iconSize
+#define iconSize 24
+
+#undef x
+#undef fx
+#undef fy
+#define x (m + iconSize + m)
+#define fx (xc - iconSize - m)
+#define fy 50
+
+#define bSizeBig 104
+#undef bx1
+#define bx1 (xs - m - bSizeBig)
+
+IDD_OVERWRITE DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
+CAPTION "Confirm File Replace"
+BEGIN
+ LTEXT "Destination folder already contains processed file.", IDT_OVERWRITE_HEADER, m, 7, xc, 8
+ LTEXT "Would you like to replace the existing file", IDT_OVERWRITE_QUESTION_BEGIN, m, 28, xc, 8
+
+ ICON "", IDI_OVERWRITE_OLD_FILE, m, 44, iconSize, iconSize
+ LTEXT "", IDT_OVERWRITE_OLD_FILE_SIZE_TIME, x, 44, fx, fy, SS_NOPREFIX
+
+ LTEXT "with this one?", IDT_OVERWRITE_QUESTION_END, m, 98, xc, 8
+
+ ICON "", IDI_OVERWRITE_NEW_FILE, m, 114, iconSize, iconSize
+ LTEXT "", IDT_OVERWRITE_NEW_FILE_SIZE_TIME, x, 114, fx, fy, SS_NOPREFIX
+
+ PUSHBUTTON "&Yes", IDYES, bx3, by2, bxs, bys
+ PUSHBUTTON "Yes to &All", IDB_YES_TO_ALL, bx2, by2, bxs, bys
+ PUSHBUTTON "A&uto Rename", IDB_AUTO_RENAME, bx1, by2, bSizeBig, bys
+ PUSHBUTTON "&No", IDNO, bx3, by1, bxs, bys
+ PUSHBUTTON "No to A&ll", IDB_NO_TO_ALL, bx2, by1, bxs, bys
+ PUSHBUTTON "&Cancel", IDCANCEL, xs - m - bxs, by1, bxs, bys
+END
+
+
+#ifdef UNDER_CE
+
+#undef m
+#undef xc
+#undef yc
+
+#define m 4
+#define xc 152
+#define yc 144
+
+#undef fy
+#define fy 40
+
+#undef bxs
+#define bxs 48
+
+#undef bx1
+
+#define bx1 (xs - m - bxs)
+
+IDD_OVERWRITE_2 DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
+CAPTION "Confirm File Replace"
+BEGIN
+ LTEXT "Would you like to replace the existing file", IDT_OVERWRITE_QUESTION_BEGIN, m, m, xc, 8
+
+ ICON "", IDI_OVERWRITE_OLD_FILE, m, 20, iconSize, iconSize
+ LTEXT "", IDT_OVERWRITE_OLD_FILE_SIZE_TIME, x, 20, fx, fy, SS_NOPREFIX
+
+ LTEXT "with this one?", IDT_OVERWRITE_QUESTION_END, m, 60, xc, 8
+
+ ICON "", IDI_OVERWRITE_NEW_FILE, m, 72, iconSize, iconSize
+ LTEXT "", IDT_OVERWRITE_NEW_FILE_SIZE_TIME, x, 72, fx, fy, SS_NOPREFIX
+
+ PUSHBUTTON "&Yes", IDYES, bx3, by2, bxs, bys
+ PUSHBUTTON "Yes to &All", IDB_YES_TO_ALL, bx2, by2, bxs, bys
+ PUSHBUTTON "A&uto Rename", IDB_AUTO_RENAME, bx1, by2, bxs, bys
+ PUSHBUTTON "&No", IDNO, bx3, by1, bxs, bys
+ PUSHBUTTON "No to A&ll", IDB_NO_TO_ALL, bx2, by1, bxs, bys
+ PUSHBUTTON "&Cancel", IDCANCEL, bx1, by1, bxs, bys
+END
+
+#endif
+
+
+STRINGTABLE
+BEGIN
+ IDS_FILE_SIZE "{0} bytes"
+END
diff --git a/CPP/7zip/UI/FileManager/OverwriteDialogRes.h b/CPP/7zip/UI/FileManager/OverwriteDialogRes.h
index 28bc0d0..b480ba1 100644
--- a/CPP/7zip/UI/FileManager/OverwriteDialogRes.h
+++ b/CPP/7zip/UI/FileManager/OverwriteDialogRes.h
@@ -1,17 +1,17 @@
-#define IDD_OVERWRITE 3500
-#define IDD_OVERWRITE_2 13500
-
-#define IDT_OVERWRITE_HEADER 3501
-#define IDT_OVERWRITE_QUESTION_BEGIN 3502
-#define IDT_OVERWRITE_QUESTION_END 3503
-#define IDS_FILE_SIZE 3504
-
-#define IDB_AUTO_RENAME 3505
-#define IDB_YES_TO_ALL 440
-#define IDB_NO_TO_ALL 441
-
-#define IDI_OVERWRITE_OLD_FILE 100
-#define IDI_OVERWRITE_NEW_FILE 101
-
-#define IDT_OVERWRITE_OLD_FILE_SIZE_TIME 102
-#define IDT_OVERWRITE_NEW_FILE_SIZE_TIME 103
+#define IDD_OVERWRITE 3500
+#define IDD_OVERWRITE_2 13500
+
+#define IDT_OVERWRITE_HEADER 3501
+#define IDT_OVERWRITE_QUESTION_BEGIN 3502
+#define IDT_OVERWRITE_QUESTION_END 3503
+#define IDS_FILE_SIZE 3504
+
+#define IDB_AUTO_RENAME 3505
+#define IDB_YES_TO_ALL 440
+#define IDB_NO_TO_ALL 441
+
+#define IDI_OVERWRITE_OLD_FILE 100
+#define IDI_OVERWRITE_NEW_FILE 101
+
+#define IDT_OVERWRITE_OLD_FILE_SIZE_TIME 102
+#define IDT_OVERWRITE_NEW_FILE_SIZE_TIME 103
diff --git a/CPP/7zip/UI/FileManager/Panel.cpp b/CPP/7zip/UI/FileManager/Panel.cpp
new file mode 100644
index 0000000..72b72c6
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Panel.cpp
@@ -0,0 +1,1182 @@
+// Panel.cpp
+
+#include "StdAfx.h"
+
+#include <windowsx.h>
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/Thread.h"
+
+#include "../../PropID.h"
+
+#include "resource.h"
+#include "../GUI/ExtractRes.h"
+
+#include "../Common/ArchiveName.h"
+#include "../Common/CompressCall.h"
+#include "../Common/ZipRegistry.h"
+
+#include "../Agent/IFolderArchive.h"
+
+#include "App.h"
+#include "ExtractCallback.h"
+#include "FSFolder.h"
+#include "FormatUtils.h"
+#include "LangUtils.h"
+#include "Panel.h"
+#include "RootFolder.h"
+
+#include "PropertyNameRes.h"
+
+using namespace NWindows;
+using namespace NControl;
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+static const UINT_PTR kTimerID = 1;
+static const UINT kTimerElapse = 1000;
+
+static DWORD kStyles[4] = { LVS_ICON, LVS_SMALLICON, LVS_LIST, LVS_REPORT };
+
+// static const int kCreateFolderID = 101;
+
+extern HINSTANCE g_hInstance;
+extern DWORD g_ComCtl32Version;
+
+void CPanel::Release()
+{
+ // It's for unloading COM dll's: don't change it.
+ CloseOpenFolders();
+ _sevenZipContextMenu.Release();
+ _systemContextMenu.Release();
+}
+
+CPanel::~CPanel()
+{
+ CloseOpenFolders();
+}
+
+HWND CPanel::GetParent() const
+{
+ const HWND h = CWindow2::GetParent();
+ return h ? h : _mainWindow;
+}
+
+#define kClassName L"7-Zip::Panel"
+
+
+HRESULT CPanel::Create(HWND mainWindow, HWND parentWindow, UINT id,
+ const UString &currentFolderPrefix,
+ const UString &arcFormat,
+ CPanelCallback *panelCallback, CAppState *appState,
+ bool needOpenArc,
+ COpenResult &openRes)
+{
+ _mainWindow = mainWindow;
+ _processTimer = true;
+ _processNotify = true;
+ _processStatusBar = true;
+
+ _panelCallback = panelCallback;
+ _appState = appState;
+ // _index = index;
+ _baseID = id;
+ _comboBoxID = _baseID + 3;
+ _statusBarID = _comboBoxID + 1;
+
+ UString cfp = currentFolderPrefix;
+
+ if (!currentFolderPrefix.IsEmpty())
+ if (currentFolderPrefix[0] == L'.')
+ {
+ FString cfpF;
+ if (NFile::NDir::MyGetFullPathName(us2fs(currentFolderPrefix), cfpF))
+ cfp = fs2us(cfpF);
+ }
+
+ RINOK(BindToPath(cfp, arcFormat, openRes))
+
+ if (needOpenArc && !openRes.ArchiveIsOpened)
+ return S_OK;
+
+ if (!CreateEx(0, kClassName, NULL, WS_CHILD | WS_VISIBLE,
+ 0, 0, _xSize, 260,
+ parentWindow, (HMENU)(UINT_PTR)id, g_hInstance))
+ return E_FAIL;
+ PanelCreated = true;
+
+ return S_OK;
+}
+
+// extern UInt32 g_NumMessages;
+
+LRESULT CPanel::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ // g_NumMessages++;
+ switch (message)
+ {
+ case kShiftSelectMessage:
+ OnShiftSelectMessage();
+ return 0;
+ case kReLoadMessage:
+ RefreshListCtrl(_selectedState);
+ return 0;
+ case kSetFocusToListView:
+ _listView.SetFocus();
+ return 0;
+ case kOpenItemChanged:
+ return OnOpenItemChanged(lParam);
+ case kRefresh_StatusBar:
+ if (_processStatusBar)
+ Refresh_StatusBar();
+ return 0;
+ #ifdef UNDER_CE
+ case kRefresh_HeaderComboBox:
+ LoadFullPathAndShow();
+ return 0;
+ #endif
+ case WM_TIMER:
+ OnTimer();
+ return 0;
+ case WM_CONTEXTMENU:
+ if (OnContextMenu(HANDLE(wParam), GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)))
+ return 0;
+ break;
+ /*
+ case WM_DROPFILES:
+ CompressDropFiles(HDROP(wParam));
+ return 0;
+ */
+ }
+ return CWindow2::OnMessage(message, wParam, lParam);
+}
+
+LRESULT CMyListView::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ if (message == WM_CHAR)
+ {
+ UINT scanCode = (UINT)((lParam >> 16) & 0xFF);
+ bool extended = ((lParam & 0x1000000) != 0);
+ UINT virtualKey = MapVirtualKey(scanCode, 1);
+ if (virtualKey == VK_MULTIPLY || virtualKey == VK_ADD ||
+ virtualKey == VK_SUBTRACT)
+ return 0;
+ if ((wParam == '/' && extended)
+ || wParam == '\\' || wParam == '/')
+ {
+ _panel->OpenDrivesFolder();
+ return 0;
+ }
+ }
+ else if (message == WM_SYSCHAR)
+ {
+ // For Alt+Enter Beep disabling
+ UINT scanCode = (UINT)(lParam >> 16) & 0xFF;
+ UINT virtualKey = MapVirtualKey(scanCode, 1);
+ if (virtualKey == VK_RETURN || virtualKey == VK_MULTIPLY ||
+ virtualKey == VK_ADD || virtualKey == VK_SUBTRACT)
+ return 0;
+ }
+ /*
+ else if (message == WM_SYSKEYDOWN)
+ {
+ // return 0;
+ }
+ */
+ else if (message == WM_KEYDOWN)
+ {
+ bool alt = IsKeyDown(VK_MENU);
+ bool ctrl = IsKeyDown(VK_CONTROL);
+ bool shift = IsKeyDown(VK_SHIFT);
+ switch (wParam)
+ {
+ /*
+ case VK_RETURN:
+ {
+ if (shift && !alt && !ctrl)
+ {
+ _panel->OpenSelectedItems(false);
+ return 0;
+ }
+ break;
+ }
+ */
+ case VK_NEXT:
+ {
+ if (ctrl && !alt && !shift)
+ {
+ _panel->OpenFocusedItemAsInternal();
+ return 0;
+ }
+ break;
+ }
+ case VK_PRIOR:
+ if (ctrl && !alt && !shift)
+ {
+ _panel->OpenParentFolder();
+ return 0;
+ }
+ }
+ }
+ #ifdef UNDER_CE
+ else if (message == WM_KEYUP)
+ {
+ if (wParam == VK_F2) // it's VK_TSOFT2
+ {
+ // Activate Menu
+ ::PostMessage(g_HWND, WM_SYSCOMMAND, SC_KEYMENU, 0);
+ return 0;
+ }
+ }
+ #endif
+ else if (message == WM_SETFOCUS)
+ {
+ _panel->_lastFocusedIsList = true;
+ _panel->_panelCallback->PanelWasFocused();
+ }
+ return CListView2::OnMessage(message, wParam, lParam);
+}
+
+/*
+static LRESULT APIENTRY ComboBoxSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ CWindow tempDialog(hwnd);
+ CMyComboBox *w = (CMyComboBox *)(tempDialog.GetUserDataLongPtr());
+ if (w == NULL)
+ return 0;
+ return w->OnMessage(message, wParam, lParam);
+}
+
+LRESULT CMyComboBox::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ return CallWindowProc(_origWindowProc, *this, message, wParam, lParam);
+}
+*/
+
+#ifndef UNDER_CE
+
+static LRESULT APIENTRY ComboBoxEditSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ CWindow tempDialog(hwnd);
+ CMyComboBoxEdit *w = (CMyComboBoxEdit *)(tempDialog.GetUserDataLongPtr());
+ if (w == NULL)
+ return 0;
+ return w->OnMessage(message, wParam, lParam);
+}
+
+#endif
+
+LRESULT CMyComboBoxEdit::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ // See MSDN / Subclassing a Combo Box / Creating a Combo-box Toolbar
+ switch (message)
+ {
+ case WM_SYSKEYDOWN:
+ switch (wParam)
+ {
+ case VK_F1:
+ case VK_F2:
+ {
+ // check ALT
+ if ((lParam & (1<<29)) == 0)
+ break;
+ bool alt = IsKeyDown(VK_MENU);
+ bool ctrl = IsKeyDown(VK_CONTROL);
+ bool shift = IsKeyDown(VK_SHIFT);
+ if (alt && !ctrl && !shift)
+ {
+ _panel->_panelCallback->SetFocusToPath(wParam == VK_F1 ? 0 : 1);
+ return 0;
+ }
+ break;
+ }
+ }
+ break;
+ case WM_KEYDOWN:
+ switch (wParam)
+ {
+ case VK_TAB:
+ // SendMessage(hwndMain, WM_ENTER, 0, 0);
+ _panel->SetFocusToList();
+ return 0;
+ case VK_F9:
+ {
+ bool alt = IsKeyDown(VK_MENU);
+ bool ctrl = IsKeyDown(VK_CONTROL);
+ bool shift = IsKeyDown(VK_SHIFT);
+ if (!alt && !ctrl && !shift)
+ {
+ g_App.SwitchOnOffOnePanel();
+ return 0;
+ }
+ break;
+ }
+ case 'W':
+ {
+ bool ctrl = IsKeyDown(VK_CONTROL);
+ if (ctrl)
+ {
+ PostMessage(g_HWND, WM_COMMAND, IDCLOSE, 0);
+ return 0;
+ }
+ break;
+ }
+ }
+ break;
+ case WM_CHAR:
+ switch (wParam)
+ {
+ case VK_TAB:
+ case VK_ESCAPE:
+ return 0;
+ }
+ }
+ #ifndef _UNICODE
+ if (g_IsNT)
+ return CallWindowProcW(_origWindowProc, *this, message, wParam, lParam);
+ else
+ #endif
+ return CallWindowProc(_origWindowProc, *this, message, wParam, lParam);
+}
+
+
+/*
+ REBARBANDINFO in vista (_WIN32_WINNT >= 0x0600) has additional fields
+ we want 2000/xp compatibility.
+ so we must use reduced structure, if we compile with (_WIN32_WINNT >= 0x0600)
+ Also there are additional fields, if (_WIN32_IE >= 0x0400).
+ but (_WIN32_IE >= 0x0400) is expected.
+ note:
+ in x64 (64-bit):
+ {
+ (108 == REBARBANDINFO_V6_SIZE)
+ (112 == sizeof(REBARBANDINFO) // for (_WIN32_WINNT < 0x0600)
+ (128 == sizeof(REBARBANDINFO) // for (_WIN32_WINNT >= 0x0600)
+ there is difference in sizes, because REBARBANDINFO size was
+ not aligned for 8-bytes in (_WIN32_WINNT < 0x0600).
+ We hope that WinVista+ support support both (108 and 112) sizes.
+ But does WinXP-x64 support (108 == REBARBANDINFO_V6_SIZE)?
+ {
+ 96 LPARAM lParam;
+ 104 UINT cxHeader;
+ #if (_WIN32_WINNT >= 0x0600)
+ 108 RECT rcChevronLocation;
+ 124 UINT uChevronState;
+ #endif
+ }
+*/
+
+#if defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0600) && defined(REBARBANDINFOA_V6_SIZE)
+ #define my_compatib_REBARBANDINFO_size REBARBANDINFO_V6_SIZE
+#else
+ #define my_compatib_REBARBANDINFO_size sizeof(REBARBANDINFO)
+#endif
+
+
+bool CPanel::OnCreate(CREATESTRUCT * /* createStruct */)
+{
+ // _virtualMode = false;
+ // _sortIndex = 0;
+ _sortID = kpidName;
+ _ascending = true;
+ _lastFocusedIsList = true;
+
+ DWORD style = WS_CHILD | WS_VISIBLE; // | WS_BORDER ; // | LVS_SHAREIMAGELISTS; // | LVS_SHOWSELALWAYS;
+
+ style |= LVS_SHAREIMAGELISTS;
+ // style |= LVS_AUTOARRANGE;
+ style |= WS_CLIPCHILDREN;
+ style |= WS_CLIPSIBLINGS;
+
+ const UInt32 kNumListModes = Z7_ARRAY_SIZE(kStyles);
+ if (_listViewMode >= kNumListModes)
+ _listViewMode = kNumListModes - 1;
+
+ style |= kStyles[_listViewMode]
+ | WS_TABSTOP
+ | LVS_EDITLABELS;
+ if (_mySelectMode)
+ style |= LVS_SINGLESEL;
+
+ /*
+ if (_virtualMode)
+ style |= LVS_OWNERDATA;
+ */
+
+ DWORD exStyle;
+ exStyle = WS_EX_CLIENTEDGE;
+
+ if (!_listView.CreateEx(exStyle, style, 0, 0, 116, 260,
+ *this, (HMENU)(UINT_PTR)(_baseID + 1), g_hInstance, NULL))
+ return false;
+
+ _listView.SetUnicodeFormat();
+ _listView._panel = this;
+ _listView.SetWindowProc();
+
+ _listView.SetImageList(GetSysImageList(true), LVSIL_SMALL);
+ _listView.SetImageList(GetSysImageList(false), LVSIL_NORMAL);
+
+ // _exStyle |= LVS_EX_HEADERDRAGDROP;
+ // DWORD extendedStyle = _listView.GetExtendedListViewStyle();
+ // extendedStyle |= _exStyle;
+ // _listView.SetExtendedListViewStyle(extendedStyle);
+ SetExtendedStyle();
+
+ _listView.Show(SW_SHOW);
+ _listView.InvalidateRect(NULL, true);
+ _listView.Update();
+
+ // Ensure that the common control DLL is loaded.
+ INITCOMMONCONTROLSEX icex;
+
+ icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ icex.dwICC = ICC_BAR_CLASSES;
+ InitCommonControlsEx(&icex);
+
+ const TBBUTTON tbb[] =
+ {
+ // {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0},
+ {VIEW_PARENTFOLDER, kParentFolderID, TBSTATE_ENABLED, BTNS_BUTTON, { 0, 0 }, 0, 0 },
+ // {0, 0, TBSTATE_ENABLED, BTNS_SEP, 0L, 0},
+ // {VIEW_NEWFOLDER, kCreateFolderID, TBSTATE_ENABLED, BTNS_BUTTON, 0L, 0},
+ };
+
+ #ifndef UNDER_CE
+ if (g_ComCtl32Version >= MAKELONG(71, 4))
+ #endif
+ {
+ icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ icex.dwICC = ICC_COOL_CLASSES | ICC_BAR_CLASSES;
+ InitCommonControlsEx(&icex);
+
+ // if there is no CCS_NOPARENTALIGN, there is space of some pixels after rebar (Incorrect GetWindowRect ?)
+
+ _headerReBar.Attach(::CreateWindowEx(WS_EX_TOOLWINDOW,
+ REBARCLASSNAME,
+ NULL, WS_VISIBLE | WS_BORDER | WS_CHILD |
+ WS_CLIPCHILDREN | WS_CLIPSIBLINGS
+ | CCS_NODIVIDER
+ | CCS_NOPARENTALIGN
+ | CCS_TOP
+ | RBS_VARHEIGHT
+ | RBS_BANDBORDERS
+ ,0,0,0,0, *this, NULL, g_hInstance, NULL));
+ }
+
+ DWORD toolbarStyle = WS_CHILD | WS_VISIBLE ;
+ if (_headerReBar)
+ {
+ toolbarStyle |= 0
+ // | WS_CLIPCHILDREN
+ // | WS_CLIPSIBLINGS
+
+ | TBSTYLE_TOOLTIPS
+ | CCS_NODIVIDER
+ | CCS_NORESIZE
+ | TBSTYLE_FLAT
+ ;
+ }
+
+ _headerToolBar.Attach(::CreateToolbarEx ((*this), toolbarStyle,
+ _baseID + 2, 11,
+ (HINSTANCE)HINST_COMMCTRL,
+ IDB_VIEW_SMALL_COLOR,
+ (LPCTBBUTTON)&tbb, Z7_ARRAY_SIZE(tbb),
+ 0, 0, 0, 0, sizeof (TBBUTTON)));
+
+ #ifndef UNDER_CE
+ // Load ComboBoxEx class
+ icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
+ icex.dwICC = ICC_USEREX_CLASSES;
+ InitCommonControlsEx(&icex);
+ #endif
+
+ _headerComboBox.CreateEx(0,
+ #ifdef UNDER_CE
+ WC_COMBOBOXW
+ #else
+ WC_COMBOBOXEXW
+ #endif
+ , NULL,
+ WS_BORDER | WS_VISIBLE |WS_CHILD | CBS_DROPDOWN | CBS_AUTOHSCROLL,
+ 0, 0, 100, 520,
+ (_headerReBar ? _headerToolBar : (HWND)*this),
+ (HMENU)(UINT_PTR)(_comboBoxID),
+ g_hInstance, NULL);
+ #ifndef UNDER_CE
+ _headerComboBox.SetUnicodeFormat(true);
+
+ _headerComboBox.SetImageList(GetSysImageList(true));
+
+ _headerComboBox.SetExtendedStyle(CBES_EX_PATHWORDBREAKPROC, CBES_EX_PATHWORDBREAKPROC);
+
+ /*
+ _headerComboBox.SetUserDataLongPtr(LONG_PTR(&_headerComboBox));
+ _headerComboBox._panel = this;
+ _headerComboBox._origWindowProc =
+ (WNDPROC)_headerComboBox.SetLongPtr(GWLP_WNDPROC,
+ LONG_PTR(ComboBoxSubclassProc));
+ */
+ _comboBoxEdit.Attach(_headerComboBox.GetEditControl());
+
+ // _comboBoxEdit.SendMessage(CCM_SETUNICODEFORMAT, (WPARAM)(BOOL)TRUE, 0);
+
+ _comboBoxEdit.SetUserDataLongPtr(LONG_PTR(&_comboBoxEdit));
+ _comboBoxEdit._panel = this;
+ #ifndef _UNICODE
+ if (g_IsNT)
+ _comboBoxEdit._origWindowProc =
+ (WNDPROC)_comboBoxEdit.SetLongPtrW(GWLP_WNDPROC, LONG_PTR(ComboBoxEditSubclassProc));
+ else
+ #endif
+ _comboBoxEdit._origWindowProc =
+ (WNDPROC)_comboBoxEdit.SetLongPtr(GWLP_WNDPROC, LONG_PTR(ComboBoxEditSubclassProc));
+
+ #endif
+
+ if (_headerReBar)
+ {
+ REBARINFO rbi;
+ rbi.cbSize = sizeof(REBARINFO); // Required when using this struct.
+ rbi.fMask = 0;
+ rbi.himl = (HIMAGELIST)NULL;
+ _headerReBar.SetBarInfo(&rbi);
+
+ // Send the TB_BUTTONSTRUCTSIZE message, which is required for
+ // backward compatibility.
+ // _headerToolBar.SendMessage(TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);
+ SIZE size;
+ _headerToolBar.GetMaxSize(&size);
+
+ REBARBANDINFO rbBand;
+ memset(&rbBand, 0, sizeof(rbBand));
+ // rbBand.cbSize = sizeof(rbBand); // for debug
+ // rbBand.cbSize = REBARBANDINFO_V3_SIZE; // for debug
+ rbBand.cbSize = my_compatib_REBARBANDINFO_size;
+ rbBand.fMask = RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | RBBIM_SIZE;
+ rbBand.fStyle = RBBS_NOGRIPPER;
+ rbBand.cxMinChild = (UINT)size.cx;
+ rbBand.cyMinChild = (UINT)size.cy;
+ rbBand.cyChild = (UINT)size.cy;
+ rbBand.cx = (UINT)size.cx;
+ rbBand.hwndChild = _headerToolBar;
+ _headerReBar.InsertBand(-1, &rbBand);
+
+ RECT rc;
+ ::GetWindowRect(_headerComboBox, &rc);
+ rbBand.cxMinChild = 30;
+ rbBand.cyMinChild = (UINT)(rc.bottom - rc.top);
+ rbBand.cx = 1000;
+ rbBand.hwndChild = _headerComboBox;
+ _headerReBar.InsertBand(-1, &rbBand);
+ // _headerReBar.MaximizeBand(1, false);
+ }
+
+ _statusBar.Create(WS_CHILD | WS_VISIBLE, L"Status", (*this), _statusBarID);
+ // _statusBar2.Create(WS_CHILD | WS_VISIBLE, L"Status", (*this), _statusBarID + 1);
+
+ const int sizes[] = {220, 320, 420, -1};
+ _statusBar.SetParts(4, sizes);
+ // _statusBar2.SetParts(5, sizes);
+
+ /*
+ RECT rect;
+ GetClientRect(&rect);
+ OnSize(0, RECT_SIZE_X(rect), RECT_SIZE_Y(rect));
+ */
+
+ SetTimer(kTimerID, kTimerElapse);
+
+ // InitListCtrl();
+ RefreshListCtrl();
+
+ return true;
+}
+
+void CPanel::OnDestroy()
+{
+ SaveListViewInfo();
+ CWindow2::OnDestroy();
+}
+
+void CPanel::ChangeWindowSize(int xSize, int ySize)
+{
+ if (!(HWND)*this)
+ return;
+ int kHeaderSize;
+ int kStatusBarSize;
+ // int kStatusBar2Size;
+ RECT rect;
+ if (_headerReBar)
+ _headerReBar.GetWindowRect(&rect);
+ else
+ _headerToolBar.GetWindowRect(&rect);
+
+ kHeaderSize = RECT_SIZE_Y(rect);
+
+ _statusBar.GetWindowRect(&rect);
+ kStatusBarSize = RECT_SIZE_Y(rect);
+
+ // _statusBar2.GetWindowRect(&rect);
+ // kStatusBar2Size = RECT_SIZE_Y(rect);
+
+ int yListViewSize = MyMax(ySize - kHeaderSize - kStatusBarSize, 0);
+ const int kStartXPos = 32;
+ if (_headerReBar)
+ {
+ }
+ else
+ {
+ _headerToolBar.Move(0, 0, xSize, 0);
+ _headerComboBox.Move(kStartXPos, 2,
+ MyMax(xSize - kStartXPos - 10, kStartXPos), 0);
+ }
+ _listView.Move(0, kHeaderSize, xSize, yListViewSize);
+ _statusBar.Move(0, kHeaderSize + yListViewSize, xSize, kStatusBarSize);
+ // _statusBar2.MoveWindow(0, kHeaderSize + yListViewSize + kStatusBarSize, xSize, kStatusBar2Size);
+ // _statusBar.MoveWindow(0, 100, xSize, kStatusBarSize);
+ // _statusBar2.MoveWindow(0, 200, xSize, kStatusBar2Size);
+}
+
+bool CPanel::OnSize(WPARAM /* wParam */, int xSize, int ySize)
+{
+ if (!(HWND)*this)
+ return true;
+ if (_headerReBar)
+ _headerReBar.Move(0, 0, xSize, 0);
+ ChangeWindowSize(xSize, ySize);
+ return true;
+}
+
+bool CPanel::OnNotifyReBar(LPNMHDR header, LRESULT & /* result */)
+{
+ switch (header->code)
+ {
+ case RBN_HEIGHTCHANGE:
+ {
+ RECT rect;
+ GetWindowRect(&rect);
+ ChangeWindowSize(RECT_SIZE_X(rect), RECT_SIZE_Y(rect));
+ return false;
+ }
+ }
+ return false;
+}
+
+/*
+UInt32 g_OnNotify = 0;
+UInt32 g_LVIF_TEXT = 0;
+UInt32 g_Time = 0;
+
+void Print_OnNotify(const char *name)
+{
+ char s[256];
+ DWORD tim = GetTickCount();
+ sprintf(s,
+ "Time = %7u ms, Notify = %9u, TEXT = %9u, %s",
+ tim - g_Time,
+ g_OnNotify,
+ g_LVIF_TEXT,
+ name);
+ g_Time = tim;
+ OutputDebugStringA(s);
+ g_OnNotify = 0;
+ g_LVIF_TEXT = 0;
+}
+*/
+
+bool CPanel::OnNotify(UINT /* controlID */, LPNMHDR header, LRESULT &result)
+{
+ /*
+ g_OnNotify++;
+
+ if (header->hwndFrom == _listView)
+ {
+ if (header->code == LVN_GETDISPINFOW)
+ {
+ LV_DISPINFOW *dispInfo = (LV_DISPINFOW *)header;
+ if ((dispInfo->item.mask & LVIF_TEXT))
+ g_LVIF_TEXT++;
+ }
+ }
+ */
+
+ if (!_processNotify)
+ return false;
+
+ if (header->hwndFrom == _headerComboBox)
+ return OnNotifyComboBox(header, result);
+ else if (header->hwndFrom == _headerReBar)
+ return OnNotifyReBar(header, result);
+ else if (header->hwndFrom == _listView)
+ return OnNotifyList(header, result);
+ else if (::GetParent(header->hwndFrom) == _listView)
+ {
+ // NMHDR:code is UINT
+ // NM_RCLICK is unsigned in windows sdk
+ // NM_RCLICK is int in MinGW
+ if (header->code == (UINT)NM_RCLICK)
+ return OnRightClick((MY_NMLISTVIEW_NMITEMACTIVATE *)header, result);
+ }
+ return false;
+}
+
+bool CPanel::OnCommand(unsigned code, unsigned itemID, LPARAM lParam, LRESULT &result)
+{
+ if (itemID == kParentFolderID)
+ {
+ OpenParentFolder();
+ result = 0;
+ return true;
+ }
+ /*
+ if (itemID == kCreateFolderID)
+ {
+ CreateFolder();
+ result = 0;
+ return true;
+ }
+ */
+ if (itemID == _comboBoxID)
+ {
+ if (OnComboBoxCommand(code, lParam, result))
+ return true;
+ }
+ return CWindow2::OnCommand(code, itemID, lParam, result);
+}
+
+
+
+/*
+void CPanel::MessageBox_Info(LPCWSTR message, LPCWSTR caption) const
+ { ::MessageBoxW((HWND)*this, message, caption, MB_OK); }
+void CPanel::MessageBox_Warning(LPCWSTR message) const
+ { ::MessageBoxW((HWND)*this, message, L"7-Zip", MB_OK | MB_ICONWARNING); }
+*/
+
+void CPanel::MessageBox_Error_Caption(LPCWSTR message, LPCWSTR caption) const
+ { ::MessageBoxW((HWND)*this, message, caption, MB_OK | MB_ICONSTOP); }
+
+void CPanel::MessageBox_Error(LPCWSTR message) const
+ { MessageBox_Error_Caption(message, L"7-Zip"); }
+
+static UString ErrorHResult_To_Message(HRESULT errorCode)
+{
+ if (errorCode == 0)
+ errorCode = E_FAIL;
+ return HResultToMessage(errorCode);
+}
+
+void CPanel::MessageBox_Error_HRESULT_Caption(HRESULT errorCode, LPCWSTR caption) const
+{
+ MessageBox_Error_Caption(ErrorHResult_To_Message(errorCode), caption);
+}
+
+void CPanel::MessageBox_Error_HRESULT(HRESULT errorCode) const
+ { MessageBox_Error_HRESULT_Caption(errorCode, L"7-Zip"); }
+
+void CPanel::MessageBox_Error_2Lines_Message_HRESULT(LPCWSTR message, HRESULT errorCode) const
+{
+ UString m = message;
+ m.Add_LF();
+ m += ErrorHResult_To_Message(errorCode);
+ MessageBox_Error(m);
+}
+
+void CPanel::MessageBox_LastError(LPCWSTR caption) const
+ { MessageBox_Error_HRESULT_Caption(GetLastError_noZero_HRESULT(), caption); }
+
+void CPanel::MessageBox_LastError() const
+ { MessageBox_LastError(L"7-Zip"); }
+
+void CPanel::MessageBox_Error_LangID(UINT resourceID) const
+ { MessageBox_Error(LangString(resourceID)); }
+
+void CPanel::MessageBox_Error_UnsupportOperation() const
+ { MessageBox_Error_LangID(IDS_OPERATION_IS_NOT_SUPPORTED); }
+
+
+
+
+void CPanel::SetFocusToList()
+{
+ _listView.SetFocus();
+ // SetCurrentPathText();
+}
+
+void CPanel::SetFocusToLastRememberedItem()
+{
+ if (_lastFocusedIsList)
+ SetFocusToList();
+ else
+ _headerComboBox.SetFocus();
+}
+
+UString CPanel::GetFolderTypeID() const
+{
+ {
+ NCOM::CPropVariant prop;
+ if (_folder->GetFolderProperty(kpidType, &prop) == S_OK)
+ if (prop.vt == VT_BSTR)
+ return (const wchar_t *)prop.bstrVal;
+ }
+ return UString();
+}
+
+bool CPanel::IsFolderTypeEqTo(const char *s) const
+{
+ return StringsAreEqual_Ascii(GetFolderTypeID(), s);
+}
+
+bool CPanel::IsRootFolder() const { return IsFolderTypeEqTo("RootFolder"); }
+bool CPanel::IsFSFolder() const { return IsFolderTypeEqTo("FSFolder"); }
+bool CPanel::IsFSDrivesFolder() const { return IsFolderTypeEqTo("FSDrives"); }
+bool CPanel::IsAltStreamsFolder() const { return IsFolderTypeEqTo("AltStreamsFolder"); }
+bool CPanel::IsArcFolder() const
+{
+ return GetFolderTypeID().IsPrefixedBy_Ascii_NoCase("7-Zip");
+}
+
+bool CPanel::IsHashFolder() const
+{
+ if (_folder)
+ {
+ NCOM::CPropVariant prop;
+ if (_folder->GetFolderProperty(kpidIsHash, &prop) == S_OK)
+ if (prop.vt == VT_BOOL)
+ return VARIANT_BOOLToBool(prop.boolVal);
+ }
+ return false;
+}
+
+UString CPanel::GetFsPath() const
+{
+ if (IsFSDrivesFolder() && !IsDeviceDrivesPrefix() && !IsSuperDrivesPrefix())
+ return UString();
+ return _currentFolderPrefix;
+}
+
+UString CPanel::GetDriveOrNetworkPrefix() const
+{
+ if (!IsFSFolder())
+ return UString();
+ UString drive = GetFsPath();
+ drive.DeleteFrom(NFile::NName::GetRootPrefixSize(drive));
+ return drive;
+}
+
+void CPanel::SetListViewMode(UInt32 index)
+{
+ if (index >= 4)
+ return;
+ _listViewMode = index;
+ const LONG_PTR oldStyle = _listView.GetStyle();
+ const DWORD newStyle = kStyles[index];
+
+ // DWORD tickCount1 = GetTickCount();
+ if ((oldStyle & LVS_TYPEMASK) != (LONG_PTR)newStyle)
+ _listView.SetStyle((oldStyle & ~(LONG_PTR)(DWORD)LVS_TYPEMASK) | (LONG_PTR)newStyle);
+ // RefreshListCtrlSaveFocused();
+ /*
+ DWORD tickCount2 = GetTickCount();
+ char s[256];
+ sprintf(s, "SetStyle = %5d",
+ tickCount2 - tickCount1
+ );
+ OutputDebugStringA(s);
+ */
+
+}
+
+void CPanel::ChangeFlatMode()
+{
+ _flatMode = !_flatMode;
+ if (_parentFolders.Size() > 0)
+ _flatModeForArc = _flatMode;
+ else
+ _flatModeForDisk = _flatMode;
+ RefreshListCtrl_SaveFocused();
+}
+
+/*
+void CPanel::Change_ShowNtfsStrems_Mode()
+{
+ _showNtfsStrems_Mode = !_showNtfsStrems_Mode;
+ if (_parentFolders.Size() > 0)
+ _showNtfsStrems_ModeForArc = _showNtfsStrems_Mode;
+ else
+ _showNtfsStrems_ModeForDisk = _showNtfsStrems_Mode;
+ RefreshListCtrlSaveFocused();
+}
+*/
+
+void CPanel::Post_Refresh_StatusBar()
+{
+ if (_processStatusBar)
+ PostMsg(kRefresh_StatusBar);
+}
+
+void CPanel::AddToArchive()
+{
+ if (!Is_IO_FS_Folder())
+ {
+ MessageBox_Error_UnsupportOperation();
+ return;
+ }
+ CRecordVector<UInt32> indices;
+ Get_ItemIndices_Operated(indices);
+ if (indices.Size() == 0)
+ {
+ MessageBox_Error_LangID(IDS_SELECT_FILES);
+ return;
+ }
+ UString destCurDirPrefix = GetFsPath();
+ if (IsFSDrivesFolder())
+ destCurDirPrefix = ROOT_FS_FOLDER;
+ UStringVector names;
+ GetFilePaths(indices, names);
+ UString baseName;
+ const UString arcName = CreateArchiveName(names,
+ false, // isHash
+ NULL, // CFileInfo *fi
+ baseName);
+ const HRESULT res = CompressFiles(destCurDirPrefix, arcName, L"",
+ true, // addExtension
+ names,
+ false, // email
+ true, // showDialog
+ false); // waitFinish
+ if (res != S_OK)
+ {
+ if (destCurDirPrefix.Len() >= MAX_PATH)
+ MessageBox_Error_LangID(IDS_MESSAGE_UNSUPPORTED_OPERATION_FOR_LONG_PATH_FOLDER);
+ }
+ // KillSelection();
+}
+
+// function from ContextMenu.cpp
+UString GetSubFolderNameForExtract(const UString &arcPath);
+
+static UString GetSubFolderNameForExtract2(const UString &arcPath)
+{
+ int slashPos = arcPath.ReverseFind_PathSepar();
+ UString s;
+ UString name = arcPath;
+ if (slashPos >= 0)
+ {
+ s = arcPath.Left((unsigned)(slashPos + 1));
+ name = arcPath.Ptr((unsigned)(slashPos + 1));
+ }
+ s += GetSubFolderNameForExtract(name);
+ return s;
+}
+
+
+int CPanel::FindDir_InOperatedList(const CRecordVector<UInt32> &operatedIndices) const
+{
+ const bool *isDirVector = &_isDirVector.Front();
+ const UInt32 *indices = &operatedIndices.Front();
+ const unsigned numItems = operatedIndices.Size();
+ for (unsigned i = 0; i < numItems; i++)
+ if (isDirVector[indices[i]])
+ return (int)i;
+ return -1;
+}
+
+
+void CPanel::GetFilePaths(const CRecordVector<UInt32> &operatedIndices, UStringVector &paths) const
+{
+ paths.ClearAndReserve(operatedIndices.Size());
+ UString path = GetFsPath();
+ const unsigned prefixLen = path.Len();
+ const UInt32 *indices = &operatedIndices.Front();
+ const unsigned numItems = operatedIndices.Size();
+ // for (unsigned y = 0; y < 10000; y++, paths.Clear())
+ for (unsigned i = 0; i < numItems; i++)
+ {
+ path.DeleteFrom(prefixLen);
+ Add_ItemRelPath2_To_String(indices[i], path);
+ // ODS_U(path)
+ paths.AddInReserved(path);
+ }
+}
+
+
+void CPanel::ExtractArchives()
+{
+ if (_parentFolders.Size() > 0)
+ {
+ _panelCallback->OnCopy(false, false);
+ return;
+ }
+ CRecordVector<UInt32> indices;
+ Get_ItemIndices_Operated(indices);
+ if (indices.IsEmpty() || FindDir_InOperatedList(indices) != -1)
+ {
+ MessageBox_Error_LangID(IDS_SELECT_FILES);
+ return;
+ }
+ UStringVector paths;
+ GetFilePaths(indices, paths);
+ UString outFolder = GetFsPath();
+ if (indices.Size() == 1)
+ outFolder += GetSubFolderNameForExtract2(GetItemRelPath(indices[0]));
+ else
+ outFolder += '*';
+ outFolder.Add_PathSepar();
+
+ CContextMenuInfo ci;
+ ci.Load();
+
+ ::ExtractArchives(paths, outFolder
+ , true // showDialog
+ , false // elimDup
+ , ci.WriteZone
+ );
+}
+
+/*
+static void AddValuePair(UINT resourceID, UInt64 value, UString &s)
+{
+ AddLangString(s, resourceID);
+ char sz[32];
+ s += ": ";
+ ConvertUInt64ToString(value, sz);
+ s += sz;
+ s.Add_LF();
+}
+
+// now we don't need CThreadTest, since now we call CopyTo for "test command
+
+class CThreadTest: public CProgressThreadVirt
+{
+ HRESULT ProcessVirt();
+public:
+ CRecordVector<UInt32> Indices;
+ CExtractCallbackImp *ExtractCallbackSpec;
+ CMyComPtr<IFolderArchiveExtractCallback> ExtractCallback;
+ CMyComPtr<IArchiveFolder> ArchiveFolder;
+};
+
+HRESULT CThreadTest::ProcessVirt()
+{
+ RINOK(ArchiveFolder->Extract(&Indices[0], Indices.Size(),
+ true, // includeAltStreams
+ false, // replaceAltStreamColon
+ NExtract::NPathMode::kFullPathnames,
+ NExtract::NOverwriteMode::kAskBefore,
+ NULL, // path
+ BoolToInt(true), // testMode
+ ExtractCallback));
+ if (ExtractCallbackSpec->IsOK())
+ {
+ UString s;
+ AddValuePair(IDS_PROP_FOLDERS, ExtractCallbackSpec->NumFolders, s);
+ AddValuePair(IDS_PROP_FILES, ExtractCallbackSpec->NumFiles, s);
+ // AddValuePair(IDS_PROP_SIZE, ExtractCallbackSpec->UnpackSize, s);
+ // AddSizePair(IDS_COMPRESSED_COLON, Stat.PackSize, s);
+ s.Add_LF();
+ AddLangString(s, IDS_MESSAGE_NO_ERRORS);
+ FinalMessage.OkMessage.Message = s;
+ }
+ return S_OK;
+}
+
+static void AddSizePair(UInt32 langID, UInt64 value, UString &s)
+{
+ char sz[32];
+ AddLangString(s, langID);
+ s += L' ';
+ ConvertUInt64ToString(value, sz);
+ s += sz;
+ ConvertUInt64ToString(value >> 20, sz);
+ s += " (";
+ s += sz;
+ s += " MB)";
+ s.Add_LF();
+}
+*/
+
+void CPanel::TestArchives()
+{
+ CRecordVector<UInt32> indices;
+ Get_ItemIndices_OperSmart(indices);
+ CMyComPtr<IArchiveFolder> archiveFolder;
+ _folder.QueryInterface(IID_IArchiveFolder, &archiveFolder);
+ if (archiveFolder)
+ {
+ CCopyToOptions options;
+ options.streamMode = true;
+ options.showErrorMessages = true;
+ options.testMode = true;
+
+ UStringVector messages;
+ HRESULT res = CopyTo(options, indices, &messages);
+ if (res != S_OK)
+ {
+ if (res != E_ABORT)
+ MessageBox_Error_HRESULT(res);
+ }
+ return;
+
+ /*
+ {
+ CThreadTest extracter;
+
+ extracter.ArchiveFolder = archiveFolder;
+ extracter.ExtractCallbackSpec = new CExtractCallbackImp;
+ extracter.ExtractCallback = extracter.ExtractCallbackSpec;
+ extracter.ExtractCallbackSpec->ProgressDialog = &extracter.ProgressDialog;
+ if (!_parentFolders.IsEmpty())
+ {
+ const CFolderLink &fl = _parentFolders.Back();
+ extracter.ExtractCallbackSpec->PasswordIsDefined = fl.UsePassword;
+ extracter.ExtractCallbackSpec->Password = fl.Password;
+ }
+
+ if (indices.IsEmpty())
+ return;
+
+ extracter.Indices = indices;
+
+ const UString title = LangString(IDS_PROGRESS_TESTING);
+
+ extracter.ProgressDialog.CompressingMode = false;
+ extracter.ProgressDialog.MainWindow = GetParent();
+ extracter.ProgressDialog.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE);
+ extracter.ProgressDialog.MainAddTitle = title + L' ';
+
+ extracter.ExtractCallbackSpec->OverwriteMode = NExtract::NOverwriteMode::kAskBefore;
+ extracter.ExtractCallbackSpec->Init();
+
+ if (extracter.Create(title, GetParent()) != S_OK)
+ return;
+
+ }
+ RefreshTitleAlways();
+ return;
+ */
+ }
+
+ if (!IsFSFolder())
+ {
+ MessageBox_Error_UnsupportOperation();
+ return;
+ }
+ UStringVector paths;
+ GetFilePaths(indices, paths);
+ if (paths.IsEmpty())
+ {
+ MessageBox_Error_LangID(IDS_SELECT_FILES);
+ return;
+ }
+ ::TestArchives(paths);
+}
diff --git a/CPP/7zip/UI/FileManager/Panel.h b/CPP/7zip/UI/FileManager/Panel.h
new file mode 100644
index 0000000..e512cad
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Panel.h
@@ -0,0 +1,1016 @@
+// Panel.h
+
+#ifndef ZIP7_INC_PANEL_H
+#define ZIP7_INC_PANEL_H
+
+#include "../../../Common/MyWindows.h"
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <shlobj.h>
+#else
+#include <ShlObj.h>
+#endif
+
+#include "../../../../C/Alloc.h"
+
+#include "../../../Common/Defs.h"
+#include "../../../Common/MyCom.h"
+
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/Handle.h"
+#include "../../../Windows/PropVariantConv.h"
+#include "../../../Windows/Synchronization.h"
+
+#include "../../../Windows/Control/ComboBox.h"
+#include "../../../Windows/Control/Edit.h"
+#include "../../../Windows/Control/ListView.h"
+#include "../../../Windows/Control/ReBar.h"
+#include "../../../Windows/Control/Static.h"
+#include "../../../Windows/Control/StatusBar.h"
+#include "../../../Windows/Control/ToolBar.h"
+#include "../../../Windows/Control/Window2.h"
+
+#include "../../Archive/IArchive.h"
+
+#include "ExtractCallback.h"
+
+#include "AppState.h"
+#include "IFolder.h"
+#include "MyCom2.h"
+#include "ProgressDialog2.h"
+#include "SysIconUtils.h"
+
+#ifdef UNDER_CE
+#define NON_CE_VAR(_v_)
+#else
+#define NON_CE_VAR(_v_) _v_
+#endif
+
+const int kParentFolderID = 100;
+
+const unsigned kParentIndex = (unsigned)(int)-1;
+const UInt32 kParentIndex_UInt32 = (UInt32)(Int32)kParentIndex;
+
+#if !defined(_WIN32) || defined(UNDER_CE)
+#define ROOT_FS_FOLDER L"\\"
+#else
+#define ROOT_FS_FOLDER L"C:\\"
+#endif
+
+Z7_PURE_INTERFACES_BEGIN
+
+DECLARE_INTERFACE(CPanelCallback)
+{
+ virtual void OnTab() = 0;
+ virtual void SetFocusToPath(unsigned index) = 0;
+ virtual void OnCopy(bool move, bool copyToSame) = 0;
+ virtual void OnSetSameFolder() = 0;
+ virtual void OnSetSubFolder() = 0;
+ virtual void PanelWasFocused() = 0;
+ virtual void DragBegin() = 0;
+ virtual void DragEnd() = 0;
+ virtual void RefreshTitle(bool always) = 0;
+};
+Z7_PURE_INTERFACES_END
+
+void PanelCopyItems();
+
+
+struct CPropColumn
+{
+ int Order;
+ PROPID ID;
+ VARTYPE Type;
+ bool IsVisible;
+ bool IsRawProp;
+ UInt32 Width;
+ UString Name;
+
+ bool IsEqualTo(const CPropColumn &a) const
+ {
+ return Order == a.Order
+ && ID == a.ID
+ && Type == a.Type
+ && IsVisible == a.IsVisible
+ && IsRawProp == a.IsRawProp
+ && Width == a.Width
+ && Name == a.Name;
+ }
+
+ int Compare(const CPropColumn &a) const { return MyCompare(Order, a.Order); }
+
+ int Compare_NameFirst(const CPropColumn &a) const
+ {
+ if (ID == kpidName)
+ {
+ if (a.ID != kpidName)
+ return -1;
+ }
+ else if (a.ID == kpidName)
+ return 1;
+ return MyCompare(Order, a.Order);
+ }
+};
+
+
+class CPropColumns: public CObjectVector<CPropColumn>
+{
+public:
+ int FindItem_for_PropID(PROPID id) const
+ {
+ FOR_VECTOR (i, (*this))
+ if ((*this)[i].ID == id)
+ return (int)i;
+ return -1;
+ }
+
+ bool IsEqualTo(const CPropColumns &props) const
+ {
+ if (Size() != props.Size())
+ return false;
+ FOR_VECTOR (i, (*this))
+ if (!(*this)[i].IsEqualTo(props[i]))
+ return false;
+ return true;
+ }
+};
+
+
+struct CTempFileInfo
+{
+ UInt32 FileIndex; // index of file in folder
+ UString RelPath; // Relative path of file from Folder
+ FString FolderPath;
+ FString FilePath;
+ NWindows::NFile::NFind::CFileInfo FileInfo;
+ bool NeedDelete;
+
+ CTempFileInfo(): FileIndex((UInt32)(Int32)-1), NeedDelete(false) {}
+ void DeleteDirAndFile() const
+ {
+ if (NeedDelete)
+ {
+ NWindows::NFile::NDir::DeleteFileAlways(FilePath);
+ NWindows::NFile::NDir::RemoveDir(FolderPath);
+ }
+ }
+ bool WasChanged(const NWindows::NFile::NFind::CFileInfo &newFileInfo) const
+ {
+ return newFileInfo.Size != FileInfo.Size ||
+ CompareFileTime(&newFileInfo.MTime, &FileInfo.MTime) != 0;
+ }
+};
+
+struct CFolderLink: public CTempFileInfo
+{
+ NWindows::NDLL::CLibrary Library;
+ CMyComPtr<IFolderFolder> ParentFolder; // can be NULL, if parent is FS folder (in _parentFolders[0])
+ UString ParentFolderPath; // including tail slash (doesn't include paths parts of parent in next level)
+ bool UsePassword;
+ UString Password;
+ bool IsVirtual;
+
+ UString VirtualPath; // without tail slash
+ CFolderLink(): UsePassword(false), IsVirtual(false) {}
+
+ bool WasChanged(const NWindows::NFile::NFind::CFileInfo &newFileInfo) const
+ {
+ return IsVirtual || CTempFileInfo::WasChanged(newFileInfo);
+ }
+
+};
+
+enum MyMessages
+{
+ // we can use WM_USER, since we have defined new window class.
+ // so we don't need WM_APP.
+ kShiftSelectMessage = WM_USER + 1,
+ kReLoadMessage,
+ kSetFocusToListView,
+ kOpenItemChanged,
+ kRefresh_StatusBar
+ #ifdef UNDER_CE
+ , kRefresh_HeaderComboBox
+ #endif
+};
+
+UString GetFolderPath(IFolderFolder *folder);
+
+class CPanel;
+
+class CMyListView Z7_final: public NWindows::NControl::CListView2
+{
+ // ~CMyListView() ZIP7_eq_delete;
+ // CMyListView() ZIP7_eq_delete;
+public:
+ // CMyListView() {}
+ // ~CMyListView() Z7_DESTRUCTOR_override {} // change it
+ CPanel *_panel;
+ LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override;
+};
+
+/*
+class CMyComboBox: public NWindows::NControl::CComboBoxEx
+{
+public:
+ WNDPROC _origWindowProc;
+ CPanel *_panel;
+ LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
+};
+*/
+class CMyComboBoxEdit: public NWindows::NControl::CEdit
+{
+public:
+ WNDPROC _origWindowProc;
+ CPanel *_panel;
+ LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
+};
+
+struct CSelectedState
+{
+ int FocusedItem;
+ bool SelectFocused;
+ bool FocusedName_Defined;
+ bool CalledFromTimer;
+ UString FocusedName;
+ UStringVector SelectedNames;
+
+ CSelectedState():
+ FocusedItem(-1),
+ SelectFocused(true),
+ FocusedName_Defined(false),
+ CalledFromTimer(false)
+ {}
+};
+
+#ifdef UNDER_CE
+#define MY_NMLISTVIEW_NMITEMACTIVATE NMLISTVIEW
+#else
+#define MY_NMLISTVIEW_NMITEMACTIVATE NMITEMACTIVATE
+#endif
+
+struct CCopyToOptions
+{
+ bool streamMode;
+ bool moveMode;
+ bool testMode;
+ bool includeAltStreams;
+ bool replaceAltStreamChars;
+ bool showErrorMessages;
+
+ bool NeedRegistryZone;
+ NExtract::NZoneIdMode::EEnum ZoneIdMode;
+
+ UString folder;
+
+ UStringVector hashMethods;
+
+ CVirtFileSystem *VirtFileSystemSpec;
+ ISequentialOutStream *VirtFileSystem;
+
+ CCopyToOptions():
+ streamMode(false),
+ moveMode(false),
+ testMode(false),
+ includeAltStreams(true),
+ replaceAltStreamChars(false),
+ showErrorMessages(false),
+ NeedRegistryZone(true),
+ ZoneIdMode(NExtract::NZoneIdMode::kNone),
+ VirtFileSystemSpec(NULL),
+ VirtFileSystem(NULL)
+ {}
+};
+
+
+
+struct COpenResult
+{
+ // bool needOpenArc;
+ // out:
+ bool ArchiveIsOpened;
+ bool Encrypted;
+ UString ErrorMessage;
+
+ COpenResult():
+ // needOpenArc(false),
+ ArchiveIsOpened(false), Encrypted(false) {}
+};
+
+
+
+
+class CPanel Z7_final: public NWindows::NControl::CWindow2
+{
+ CExtToIconMap _extToIconMap;
+ UINT _baseID;
+ unsigned _comboBoxID;
+ UINT _statusBarID;
+
+ CAppState *_appState;
+
+ virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam, LRESULT &result) Z7_override;
+ virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override;
+ virtual bool OnCreate(CREATESTRUCT *createStruct) Z7_override;
+ virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override;
+ virtual void OnDestroy() Z7_override;
+ virtual bool OnNotify(UINT controlID, LPNMHDR lParam, LRESULT &result) Z7_override;
+
+ void AddComboBoxItem(const UString &name, int iconIndex, int indent, bool addToList);
+
+ bool OnComboBoxCommand(UINT code, LPARAM param, LRESULT &result);
+
+ #ifndef UNDER_CE
+
+ LRESULT OnNotifyComboBoxEnter(const UString &s);
+ bool OnNotifyComboBoxEndEdit(PNMCBEENDEDITW info, LRESULT &result);
+ #ifndef _UNICODE
+ bool OnNotifyComboBoxEndEdit(PNMCBEENDEDIT info, LRESULT &result);
+ #endif
+
+ #endif
+
+ bool OnNotifyReBar(LPNMHDR lParam, LRESULT &result);
+ bool OnNotifyComboBox(LPNMHDR lParam, LRESULT &result);
+ void OnItemChanged(NMLISTVIEW *item);
+ void OnNotifyActivateItems();
+ bool OnNotifyList(LPNMHDR lParam, LRESULT &result);
+ void OnDrag(LPNMLISTVIEW nmListView, bool isRightButton = false);
+ bool OnKeyDown(LPNMLVKEYDOWN keyDownInfo, LRESULT &result);
+ BOOL OnBeginLabelEdit(LV_DISPINFOW * lpnmh);
+ BOOL OnEndLabelEdit(LV_DISPINFOW * lpnmh);
+ void OnColumnClick(LPNMLISTVIEW info);
+ bool OnCustomDraw(LPNMLVCUSTOMDRAW lplvcd, LRESULT &result);
+
+
+public:
+ HWND _mainWindow;
+ CPanelCallback *_panelCallback;
+
+ void SysIconsWereChanged() { _extToIconMap.Clear(); }
+
+ void DeleteItems(bool toRecycleBin);
+ void CreateFolder();
+ void CreateFile();
+ bool CorrectFsPath(const UString &path, UString &result);
+ // bool IsPathForPlugin(const UString &path);
+
+private:
+
+ void ChangeWindowSize(int xSize, int ySize);
+
+ HRESULT InitColumns();
+ void DeleteColumn(unsigned index);
+ void AddColumn(const CPropColumn &prop);
+
+ void SetFocusedSelectedItem(int index, bool select);
+
+ void OnShiftSelectMessage();
+ void OnArrowWithShift();
+
+ void OnInsert();
+ // void OnUpWithShift();
+ // void OnDownWithShift();
+public:
+ void UpdateSelection();
+ void SelectSpec(bool selectMode);
+ void SelectByType(bool selectMode);
+ void SelectAll(bool selectMode);
+ void InvertSelection();
+private:
+
+ // UString GetFileType(UInt32 index);
+ LRESULT SetItemText(LVITEMW &item);
+
+ // CRecordVector<PROPID> m_ColumnsPropIDs;
+
+public:
+ NWindows::NControl::CReBar _headerReBar;
+ NWindows::NControl::CToolBar _headerToolBar;
+ NWindows::NControl::
+ #ifdef UNDER_CE
+ CComboBox
+ #else
+ CComboBoxEx
+ #endif
+ _headerComboBox;
+ UStringVector ComboBoxPaths;
+ // CMyComboBox _headerComboBox;
+ CMyComboBoxEdit _comboBoxEdit;
+ CMyListView _listView;
+ bool _thereAre_ListView_Items;
+ NWindows::NControl::CStatusBar _statusBar;
+ bool _lastFocusedIsList;
+ // NWindows::NControl::CStatusBar _statusBar2;
+
+ DWORD _exStyle;
+ bool _showDots;
+ bool _showRealFileIcons;
+ // bool _virtualMode;
+ // CUIntVector _realIndices;
+ bool _enableItemChangeNotify;
+ bool _mySelectMode;
+
+ int _timestampLevel;
+
+
+ void RedrawListItems()
+ {
+ _listView.RedrawAllItems();
+ }
+
+
+ CBoolVector _selectedStatusVector;
+
+ CSelectedState _selectedState;
+ bool _thereAreDeletedItems;
+ bool _markDeletedItems;
+
+ bool PanelCreated;
+
+ void DeleteListItems()
+ {
+ if (_thereAre_ListView_Items)
+ {
+ bool b = _enableItemChangeNotify;
+ _enableItemChangeNotify = false;
+ _listView.DeleteAllItems();
+ _thereAre_ListView_Items = false;
+ _enableItemChangeNotify = b;
+ }
+ }
+
+ HWND GetParent() const;
+
+ UInt32 GetRealIndex(const LVITEMW &item) const
+ {
+ /*
+ if (_virtualMode)
+ return _realIndices[item.iItem];
+ */
+ return (UInt32)item.lParam;
+ }
+
+ unsigned GetRealItemIndex(int indexInListView) const
+ {
+ /*
+ if (_virtualMode)
+ return indexInListView;
+ */
+ LPARAM param;
+ if (!_listView.GetItemParam((unsigned)indexInListView, param))
+ throw 1;
+ return (unsigned)param;
+ }
+
+ UInt32 _listViewMode;
+ int _xSize;
+
+ bool _flatMode;
+ bool _flatModeForDisk;
+ bool _flatModeForArc;
+
+ // bool _showNtfsStrems_Mode;
+ // bool _showNtfsStrems_ModeForDisk;
+ // bool _showNtfsStrems_ModeForArc;
+
+ bool _dontShowMode;
+
+
+ UString _currentFolderPrefix;
+
+ CObjectVector<CFolderLink> _parentFolders;
+ NWindows::NDLL::CLibrary _library;
+
+ CMyComPtr<IFolderFolder> _folder;
+ CBoolVector _isDirVector;
+ CMyComPtr<IFolderCompare> _folderCompare;
+ CMyComPtr<IFolderGetItemName> _folderGetItemName;
+ CMyComPtr<IArchiveGetRawProps> _folderRawProps;
+ CMyComPtr<IFolderAltStreams> _folderAltStreams;
+ CMyComPtr<IFolderOperations> _folderOperations;
+
+
+ // for drag and drop highliting
+ int m_DropHighlighted_SelectionIndex;
+ // int m_SubFolderIndex; // realIndex of item in m_Panel list (if drop cursor to that item)
+ UString m_DropHighlighted_SubFolderName; // name of folder in m_Panel list (if drop cursor to that folder)
+
+ void ReleaseFolder();
+ void SetNewFolder(IFolderFolder *newFolder);
+
+ // CMyComPtr<IFolderGetSystemIconIndex> _folderGetSystemIconIndex;
+
+ UStringVector _fastFolders;
+
+ void GetSelectedNames(UStringVector &selectedNames);
+ void SaveSelectedState(CSelectedState &s);
+ HRESULT RefreshListCtrl(const CSelectedState &s);
+ HRESULT RefreshListCtrl_SaveFocused(bool onTimer = false);
+
+ // UInt32 GetItem_Attrib(UInt32 itemIndex) const;
+
+ bool GetItem_BoolProp(UInt32 itemIndex, PROPID propID) const;
+
+ bool IsItem_Deleted(unsigned itemIndex) const;
+ bool IsItem_Folder(unsigned itemIndex) const;
+ bool IsItem_AltStream(unsigned itemIndex) const;
+
+ UString GetItemName(unsigned itemIndex) const;
+ UString GetItemName_for_Copy(unsigned itemIndex) const;
+ void GetItemName(unsigned itemIndex, UString &s) const;
+ UString GetItemPrefix(unsigned itemIndex) const;
+ UString GetItemRelPath(unsigned itemIndex) const;
+ UString GetItemRelPath2(unsigned itemIndex) const;
+
+ void Add_ItemRelPath2_To_String(unsigned itemIndex, UString &s) const;
+
+ UString GetItemFullPath(unsigned itemIndex) const;
+ UInt64 GetItem_UInt64Prop(unsigned itemIndex, PROPID propID) const;
+ UInt64 GetItemSize(unsigned itemIndex) const;
+
+ ////////////////////////
+ // PanelFolderChange.cpp
+
+ void SetToRootFolder();
+ HRESULT BindToPath(const UString &fullPath, const UString &arcFormat, COpenResult &openRes); // can be prefix
+ HRESULT BindToPathAndRefresh(const UString &path);
+ void OpenDrivesFolder();
+
+ void SetBookmark(unsigned index);
+ void OpenBookmark(unsigned index);
+
+ void LoadFullPath();
+ void LoadFullPathAndShow();
+ void FoldersHistory();
+ void OpenParentFolder();
+ void CloseOneLevel();
+ void CloseOpenFolders();
+ void OpenRootFolder();
+
+ UString GetParentDirPrefix() const;
+
+ HRESULT Create(HWND mainWindow, HWND parentWindow,
+ UINT id,
+ const UString &currentFolderPrefix,
+ const UString &arcFormat,
+ CPanelCallback *panelCallback,
+ CAppState *appState,
+ bool needOpenArc,
+ COpenResult &openRes);
+
+ void SetFocusToList();
+ void SetFocusToLastRememberedItem();
+
+
+ void SaveListViewInfo();
+
+ CPanel() :
+ _thereAre_ListView_Items(false),
+ _exStyle(0),
+ _showDots(false),
+ _showRealFileIcons(false),
+ // _virtualMode(flase),
+ _enableItemChangeNotify(true),
+ _mySelectMode(false),
+ _timestampLevel(kTimestampPrintLevel_MIN),
+
+ _thereAreDeletedItems(false),
+ _markDeletedItems(true),
+ PanelCreated(false),
+
+ _listViewMode(3),
+ _xSize(300),
+
+ _flatMode(false),
+ _flatModeForDisk(false),
+ _flatModeForArc(false),
+
+ // _showNtfsStrems_Mode(false),
+ // _showNtfsStrems_ModeForDisk(false),
+ // _showNtfsStrems_ModeForArc(false),
+
+ _dontShowMode(false),
+
+ m_DropHighlighted_SelectionIndex(-1),
+
+ _needSaveInfo(false),
+ _startGroupSelect(0),
+ _selectionIsDefined(false)
+ {}
+
+ void SetExtendedStyle()
+ {
+ if (_listView)
+ _listView.SetExtendedListViewStyle(_exStyle);
+ }
+
+
+ bool _needSaveInfo;
+ UString _typeIDString;
+ CListViewInfo _listViewInfo;
+
+ CPropColumns _columns;
+ CPropColumns _visibleColumns;
+
+ PROPID _sortID;
+ // int _sortIndex;
+ bool _ascending;
+ Int32 _isRawSortProp;
+
+ void SetSortRawStatus();
+
+ void Release();
+ ~CPanel() Z7_DESTRUCTOR_override;
+ void OnLeftClick(MY_NMLISTVIEW_NMITEMACTIVATE *itemActivate);
+ bool OnRightClick(MY_NMLISTVIEW_NMITEMACTIVATE *itemActivate, LRESULT &result);
+ void ShowColumnsContextMenu(int x, int y);
+
+ void OnTimer();
+ void OnReload(bool onTimer = false);
+ bool OnContextMenu(HANDLE windowHandle, int xPos, int yPos);
+
+ CMyComPtr<IContextMenu> _sevenZipContextMenu;
+ CMyComPtr<IContextMenu> _systemContextMenu;
+
+ HRESULT CreateShellContextMenu(
+ const CRecordVector<UInt32> &operatedIndices,
+ CMyComPtr<IContextMenu> &systemContextMenu);
+
+ void CreateSystemMenu(HMENU menu,
+ bool showExtendedVerbs,
+ const CRecordVector<UInt32> &operatedIndices,
+ CMyComPtr<IContextMenu> &systemContextMenu);
+
+ void CreateSevenZipMenu(HMENU menu,
+ bool showExtendedVerbs,
+ const CRecordVector<UInt32> &operatedIndices,
+ int firstDirIndex,
+ CMyComPtr<IContextMenu> &sevenZipContextMenu);
+
+ void CreateFileMenu(HMENU menu,
+ CMyComPtr<IContextMenu> &sevenZipContextMenu,
+ CMyComPtr<IContextMenu> &systemContextMenu,
+ bool programMenu);
+
+ void CreateFileMenu(HMENU menu);
+ bool InvokePluginCommand(unsigned id);
+ bool InvokePluginCommand(unsigned id, IContextMenu *sevenZipContextMenu,
+ IContextMenu *systemContextMenu);
+
+ void InvokeSystemCommand(const char *command);
+ void Properties();
+ void EditCut();
+ void EditCopy();
+ void EditPaste();
+
+ int _startGroupSelect;
+
+ bool _selectionIsDefined;
+ bool _selectMark;
+ int _prevFocusedItem;
+
+
+ // void SortItems(int index);
+ void SortItemsWithPropID(PROPID propID);
+
+ void Get_ItemIndices_Selected(CRecordVector<UInt32> &indices) const;
+ void Get_ItemIndices_Operated(CRecordVector<UInt32> &indices) const;
+ void Get_ItemIndices_All(CRecordVector<UInt32> &indices) const;
+ void Get_ItemIndices_OperSmart(CRecordVector<UInt32> &indices) const;
+ // void GetOperatedListViewIndices(CRecordVector<UInt32> &indices) const;
+ void KillSelection();
+
+ UString GetFolderTypeID() const;
+
+ bool IsFolderTypeEqTo(const char *s) const;
+ bool IsRootFolder() const;
+ bool IsFSFolder() const;
+ bool IsFSDrivesFolder() const;
+ bool IsAltStreamsFolder() const;
+ bool IsArcFolder() const;
+ bool IsHashFolder() const;
+
+ /*
+ c:\Dir
+ Computer\
+ \\?\
+ \\.\
+ */
+ bool Is_IO_FS_Folder() const
+ {
+ return IsFSFolder() || IsFSDrivesFolder() || IsAltStreamsFolder();
+ }
+
+ bool Is_Slow_Icon_Folder() const
+ {
+ return IsFSFolder() || IsAltStreamsFolder();
+ }
+
+ // bool IsFsOrDrivesFolder() const { return IsFSFolder() || IsFSDrivesFolder(); }
+ bool IsDeviceDrivesPrefix() const { return _currentFolderPrefix == L"\\\\.\\"; }
+ bool IsSuperDrivesPrefix() const { return _currentFolderPrefix == L"\\\\?\\"; }
+
+ /*
+ c:\Dir
+ Computer\
+ \\?\
+ */
+ bool IsFsOrPureDrivesFolder() const { return IsFSFolder() || (IsFSDrivesFolder() && !IsDeviceDrivesPrefix()); }
+
+ /*
+ c:\Dir
+ Computer\
+ \\?\
+ \\SERVER\
+ */
+ bool IsFolder_with_FsItems() const
+ {
+ if (IsFsOrPureDrivesFolder())
+ return true;
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ FString prefix = us2fs(GetFsPath());
+ return (prefix.Len() == NWindows::NFile::NName::GetNetworkServerPrefixSize(prefix));
+ #else
+ return false;
+ #endif
+ }
+
+ UString GetFsPath() const;
+ UString GetDriveOrNetworkPrefix() const;
+
+ bool DoesItSupportOperations() const { return _folderOperations != NULL; }
+ bool IsThereReadOnlyFolder() const;
+ bool CheckBeforeUpdate(UINT resourceID);
+
+ bool _processTimer;
+ bool _processNotify;
+ bool _processStatusBar;
+
+ class CDisableTimerProcessing
+ {
+ Z7_CLASS_NO_COPY(CDisableTimerProcessing)
+
+ bool _processTimer;
+ CPanel &_panel;
+
+ public:
+
+ CDisableTimerProcessing(CPanel &panel): _panel(panel) { Disable(); }
+ ~CDisableTimerProcessing() { Restore(); }
+ void Disable()
+ {
+ _processTimer = _panel._processTimer;
+ _panel._processTimer = false;
+ }
+ void Restore()
+ {
+ _panel._processTimer = _processTimer;
+ }
+ };
+
+ class CDisableTimerProcessing2
+ {
+ Z7_CLASS_NO_COPY(CDisableTimerProcessing2)
+
+ bool _processTimer;
+ CPanel *_panel;
+
+ public:
+
+ CDisableTimerProcessing2(CPanel *panel): _processTimer(true), _panel(panel) { Disable(); }
+ ~CDisableTimerProcessing2() { Restore(); }
+ void Disable()
+ {
+ if (_panel)
+ {
+ _processTimer = _panel->_processTimer;
+ _panel->_processTimer = false;
+ }
+ }
+ void Restore()
+ {
+ if (_panel)
+ {
+ _panel->_processTimer = _processTimer;
+ _panel = NULL;
+ }
+ }
+ };
+
+ class CDisableNotify
+ {
+ Z7_CLASS_NO_COPY(CDisableNotify)
+
+ bool _processNotify;
+ bool _processStatusBar;
+
+ CPanel &_panel;
+
+ public:
+
+ CDisableNotify(CPanel &panel): _panel(panel) { Disable(); }
+ ~CDisableNotify() { Restore(); }
+ void Disable()
+ {
+ _processNotify = _panel._processNotify;
+ _processStatusBar = _panel._processStatusBar;
+ _panel._processNotify = false;
+ _panel._processStatusBar = false;
+ }
+ void SetMemMode_Enable()
+ {
+ _processNotify = true;
+ _processStatusBar = true;
+ }
+ void Restore()
+ {
+ _panel._processNotify = _processNotify;
+ _panel._processStatusBar = _processStatusBar;
+ }
+ };
+
+ void InvalidateList() { _listView.InvalidateRect(NULL, true); }
+
+ HRESULT RefreshListCtrl();
+
+
+ // void MessageBox_Info(LPCWSTR message, LPCWSTR caption) const;
+ // void MessageBox_Warning(LPCWSTR message) const;
+ void MessageBox_Error_Caption(LPCWSTR message, LPCWSTR caption) const;
+ void MessageBox_Error(LPCWSTR message) const;
+ void MessageBox_Error_HRESULT_Caption(HRESULT errorCode, LPCWSTR caption) const;
+ void MessageBox_Error_HRESULT(HRESULT errorCode) const;
+ void MessageBox_Error_2Lines_Message_HRESULT(LPCWSTR message, HRESULT errorCode) const;
+ void MessageBox_LastError(LPCWSTR caption) const;
+ void MessageBox_LastError() const;
+ void MessageBox_Error_LangID(UINT resourceID) const;
+ void MessageBox_Error_UnsupportOperation() const;
+ // void MessageBoxErrorForUpdate(HRESULT errorCode, UINT resourceID);
+
+
+ void OpenAltStreams();
+
+ void OpenFocusedItemAsInternal(const wchar_t *type = NULL);
+ void OpenSelectedItems(bool internal);
+
+ void OpenFolderExternal(unsigned index);
+
+ void OpenFolder(unsigned index);
+ HRESULT OpenParentArchiveFolder();
+
+ HRESULT OpenAsArc(IInStream *inStream,
+ const CTempFileInfo &tempFileInfo,
+ const UString &virtualFilePath,
+ const UString &arcFormat,
+ COpenResult &openRes);
+
+ HRESULT OpenAsArc_Msg(IInStream *inStream,
+ const CTempFileInfo &tempFileInfo,
+ const UString &virtualFilePath,
+ const UString &arcFormat
+ // , bool showErrorMessage
+ );
+
+ HRESULT OpenAsArc_Name(const UString &relPath, const UString &arcFormat
+ // , bool showErrorMessage
+ );
+ HRESULT OpenAsArc_Index(unsigned index, const wchar_t *type /* = NULL */
+ // , bool showErrorMessage
+ );
+
+ void OpenItemInArchive(unsigned index, bool tryInternal, bool tryExternal,
+ bool editMode, bool useEditor, const wchar_t *type = NULL);
+
+ HRESULT OnOpenItemChanged(UInt32 index, const wchar_t *fullFilePath, bool usePassword, const UString &password);
+ LRESULT OnOpenItemChanged(LPARAM lParam);
+
+ bool IsVirus_Message(const UString &name);
+ void OpenItem(unsigned index, bool tryInternal, bool tryExternal, const wchar_t *type = NULL);
+ void EditItem(bool useEditor);
+ void EditItem(unsigned index, bool useEditor);
+
+ void RenameFile();
+ void ChangeComment();
+
+ void SetListViewMode(UInt32 index);
+ UInt32 GetListViewMode() const { return _listViewMode; }
+ PROPID GetSortID() const { return _sortID; }
+
+ void ChangeFlatMode();
+ void Change_ShowNtfsStrems_Mode();
+ bool GetFlatMode() const { return _flatMode; }
+ // bool Get_ShowNtfsStrems_Mode() const { return _showNtfsStrems_Mode; }
+
+ bool AutoRefresh_Mode;
+ void Set_AutoRefresh_Mode(bool mode)
+ {
+ AutoRefresh_Mode = mode;
+ }
+
+ void Post_Refresh_StatusBar();
+ void Refresh_StatusBar();
+
+ void AddToArchive();
+
+ int FindDir_InOperatedList(const CRecordVector<UInt32> &indices) const;
+ void GetFilePaths(const CRecordVector<UInt32> &indices, UStringVector &paths) const;
+ void ExtractArchives();
+ void TestArchives();
+
+
+ HRESULT CopyTo(CCopyToOptions &options,
+ const CRecordVector<UInt32> &indices,
+ UStringVector *messages,
+ bool &usePassword, UString &password,
+ const UStringVector *filePaths = NULL);
+
+ HRESULT CopyTo(CCopyToOptions &options,
+ const CRecordVector<UInt32> &indices,
+ UStringVector *messages)
+ {
+ bool usePassword = false;
+ UString password;
+ if (_parentFolders.Size() > 0)
+ {
+ const CFolderLink &fl = _parentFolders.Back();
+ usePassword = fl.UsePassword;
+ password = fl.Password;
+ }
+ return CopyTo(options, indices, messages, usePassword, password);
+ }
+
+ HRESULT CopyFsItems(CCopyToOptions &options,
+ const UStringVector &filePaths,
+ UStringVector *messages)
+ {
+ bool usePassword = false;
+ UString password;
+ CRecordVector<UInt32> indices;
+ return CopyTo(options, indices, messages, usePassword, password, &filePaths);
+ }
+
+
+ HRESULT CopyFrom(bool moveMode, const UString &folderPrefix, const UStringVector &filePaths,
+ bool showErrorMessages, UStringVector *messages);
+
+ void CopyFromNoAsk(bool moveMode, const UStringVector &filePaths);
+
+ void CompressDropFiles(
+ const UStringVector &filePaths,
+ const UString &folderPath,
+ bool createNewArchive,
+ bool moveMode,
+ UInt32 sourceFlags,
+ UInt32 &targetFlags);
+
+ void RefreshTitle(bool always = false) { _panelCallback->RefreshTitle(always); }
+ void RefreshTitleAlways() { RefreshTitle(true); }
+
+ UString GetItemsInfoString(const CRecordVector<UInt32> &indices);
+};
+
+class CMyBuffer
+{
+ void *_data;
+public:
+ CMyBuffer(): _data(NULL) {}
+ operator void *() { return _data; }
+ bool Allocate(size_t size)
+ {
+ if (_data)
+ return false;
+ _data = ::MidAlloc(size);
+ return _data != NULL;
+ }
+ ~CMyBuffer() { ::MidFree(_data); }
+};
+
+class CExitEventLauncher
+{
+public:
+ NWindows::NSynchronization::CManualResetEvent _exitEvent;
+ bool _needExit;
+ CRecordVector< ::CThread > _threads;
+ unsigned _numActiveThreads;
+
+ CExitEventLauncher()
+ {
+ _needExit = false;
+ if (_exitEvent.Create(false) != S_OK)
+ throw 9387173;
+ _needExit = true;
+ _numActiveThreads = 0;
+ }
+
+ ~CExitEventLauncher() { Exit(true); }
+
+ void Exit(bool hardExit);
+};
+
+extern CExitEventLauncher g_ExitEventLauncher;
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/PanelCopy.cpp b/CPP/7zip/UI/FileManager/PanelCopy.cpp
new file mode 100644
index 0000000..de3d764
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelCopy.cpp
@@ -0,0 +1,435 @@
+/// PanelCopy.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/ZipRegistry.h"
+
+#include "../GUI/HashGUI.h"
+
+#include "FSFolder.h"
+#include "ExtractCallback.h"
+#include "LangUtils.h"
+#include "Panel.h"
+#include "UpdateCallback100.h"
+
+#include "resource.h"
+
+
+class CPanelCopyThread: public CProgressThreadVirt
+{
+ bool ResultsWereShown;
+ bool NeedShowRes;
+
+ HRESULT ProcessVirt() Z7_override;
+ virtual void ProcessWasFinished_GuiVirt() Z7_override;
+public:
+ const CCopyToOptions *options;
+ const UStringVector *CopyFrom_Paths;
+ CMyComPtr<IFolderOperations> FolderOperations;
+ CRecordVector<UInt32> Indices;
+ CExtractCallbackImp *ExtractCallbackSpec;
+ CMyComPtr<IFolderOperationsExtractCallback> ExtractCallback;
+
+ CHashBundle Hash;
+ // UString FirstFilePath;
+
+ // HRESULT Result2;
+
+ void ShowFinalResults(HWND hwnd);
+
+ CPanelCopyThread():
+ ResultsWereShown(false),
+ NeedShowRes(false),
+ CopyFrom_Paths(NULL)
+ // , Result2(E_FAIL)
+ {}
+};
+
+void CPanelCopyThread::ShowFinalResults(HWND hwnd)
+{
+ if (NeedShowRes)
+ if (!ResultsWereShown)
+ {
+ ResultsWereShown = true;
+ ShowHashResults(Hash, hwnd);
+ }
+}
+
+void CPanelCopyThread::ProcessWasFinished_GuiVirt()
+{
+ ShowFinalResults(*this);
+}
+
+HRESULT CPanelCopyThread::ProcessVirt()
+{
+ /*
+ CMyComPtr<IFolderSetReplaceAltStreamCharsMode> iReplace;
+ FolderOperations.QueryInterface(IID_IFolderSetReplaceAltStreamCharsMode, &iReplace);
+ if (iReplace)
+ {
+ RINOK(iReplace->SetReplaceAltStreamCharsMode(ReplaceAltStreamChars ? 1 : 0));
+ }
+ */
+
+ HRESULT result2;
+
+ if (FolderOperations)
+ {
+ CMyComPtr<IFolderSetZoneIdMode> setZoneMode;
+ FolderOperations.QueryInterface(IID_IFolderSetZoneIdMode, &setZoneMode);
+ if (setZoneMode)
+ {
+ RINOK(setZoneMode->SetZoneIdMode(options->ZoneIdMode))
+ }
+ }
+
+ if (CopyFrom_Paths)
+ {
+ result2 = NFsFolder::CopyFileSystemItems(
+ *CopyFrom_Paths,
+ us2fs(options->folder),
+ options->moveMode,
+ (IFolderOperationsExtractCallback *)ExtractCallbackSpec);
+ }
+ else if (options->testMode)
+ {
+ CMyComPtr<IArchiveFolder> archiveFolder;
+ FolderOperations.QueryInterface(IID_IArchiveFolder, &archiveFolder);
+ if (!archiveFolder)
+ return E_NOTIMPL;
+ CMyComPtr<IFolderArchiveExtractCallback> extractCallback2;
+ RINOK(ExtractCallback.QueryInterface(IID_IFolderArchiveExtractCallback, &extractCallback2))
+ NExtract::NPathMode::EEnum pathMode =
+ NExtract::NPathMode::kCurPaths;
+ // NExtract::NPathMode::kFullPathnames;
+ result2 = archiveFolder->Extract(&Indices.Front(), Indices.Size(),
+ BoolToInt(options->includeAltStreams),
+ BoolToInt(options->replaceAltStreamChars),
+ pathMode, NExtract::NOverwriteMode::kAsk,
+ options->folder, BoolToInt(true), extractCallback2);
+ }
+ else
+ result2 = FolderOperations->CopyTo(
+ BoolToInt(options->moveMode),
+ &Indices.Front(), Indices.Size(),
+ BoolToInt(options->includeAltStreams),
+ BoolToInt(options->replaceAltStreamChars),
+ options->folder, ExtractCallback);
+
+ if (result2 == S_OK && !ExtractCallbackSpec->ThereAreMessageErrors)
+ {
+ if (!options->hashMethods.IsEmpty())
+ NeedShowRes = true;
+ else if (options->testMode)
+ {
+ CProgressMessageBoxPair &pair = GetMessagePair(false); // GetMessagePair(ExtractCallbackSpec->Hash.NumErrors != 0);
+ AddHashBundleRes(pair.Message, Hash);
+ }
+ }
+
+ return result2;
+}
+
+
+/*
+#ifdef Z7_EXTERNAL_CODECS
+
+static void ThrowException_if_Error(HRESULT res)
+{
+ if (res != S_OK)
+ throw CSystemException(res);
+}
+
+#endif
+*/
+
+HRESULT CPanel::CopyTo(CCopyToOptions &options,
+ const CRecordVector<UInt32> &indices,
+ UStringVector *messages,
+ bool &usePassword, UString &password,
+ const UStringVector *filePaths)
+{
+ if (options.NeedRegistryZone && !options.testMode)
+ {
+ CContextMenuInfo ci;
+ ci.Load();
+ if (ci.WriteZone != (UInt32)(Int32)-1)
+ options.ZoneIdMode = (NExtract::NZoneIdMode::EEnum)(int)(Int32)ci.WriteZone;
+ }
+
+ if (IsHashFolder())
+ {
+ if (!options.testMode)
+ return E_NOTIMPL;
+ }
+
+ if (!filePaths)
+ if (!_folderOperations)
+ {
+ const UString errorMessage = LangString(IDS_OPERATION_IS_NOT_SUPPORTED);
+ if (options.showErrorMessages)
+ MessageBox_Error(errorMessage);
+ else if (messages)
+ messages->Add(errorMessage);
+ return E_FAIL;
+ }
+
+ HRESULT res = S_OK;
+
+ {
+ /*
+ #ifdef Z7_EXTERNAL_CODECS
+ CExternalCodecs g_ExternalCodecs;
+ #endif
+ */
+ /* extracter.Hash uses g_ExternalCodecs
+ extracter must be declared after g_ExternalCodecs for correct destructor order !!! */
+
+ CPanelCopyThread extracter;
+
+ extracter.ExtractCallbackSpec = new CExtractCallbackImp;
+ extracter.ExtractCallback = extracter.ExtractCallbackSpec;
+
+ extracter.options = &options;
+ extracter.ExtractCallbackSpec->ProgressDialog = &extracter;
+ extracter.CompressingMode = false;
+
+ extracter.ExtractCallbackSpec->StreamMode = options.streamMode;
+
+
+ if (indices.Size() == 1)
+ {
+ extracter.Hash.FirstFileName = GetItemRelPath(indices[0]);
+ extracter.Hash.MainName = extracter.Hash.FirstFileName;
+ }
+
+ if (options.VirtFileSystem)
+ {
+ extracter.ExtractCallbackSpec->VirtFileSystem = options.VirtFileSystem;
+ extracter.ExtractCallbackSpec->VirtFileSystemSpec = options.VirtFileSystemSpec;
+ }
+ extracter.ExtractCallbackSpec->ProcessAltStreams = options.includeAltStreams;
+
+ if (!options.hashMethods.IsEmpty())
+ {
+ /* this code is used when we call CRC calculation for files in side archive
+ But new code uses global codecs so we don't need to call LoadGlobalCodecs again */
+
+ /*
+ #ifdef Z7_EXTERNAL_CODECS
+ ThrowException_if_Error(LoadGlobalCodecs());
+ #endif
+ */
+
+ extracter.Hash.SetMethods(EXTERNAL_CODECS_VARS_G options.hashMethods);
+ extracter.ExtractCallbackSpec->SetHashMethods(&extracter.Hash);
+ }
+ else if (options.testMode)
+ {
+ extracter.ExtractCallbackSpec->SetHashCalc(&extracter.Hash);
+ }
+
+ // extracter.Hash.Init();
+
+ UString title;
+ {
+ UInt32 titleID = IDS_COPYING;
+ if (options.moveMode)
+ titleID = IDS_MOVING;
+ else if (!options.hashMethods.IsEmpty() && options.streamMode)
+ {
+ titleID = IDS_CHECKSUM_CALCULATING;
+ if (options.hashMethods.Size() == 1)
+ {
+ const UString &s = options.hashMethods[0];
+ if (s != L"*")
+ title = s;
+ }
+ }
+ else if (options.testMode)
+ titleID = IDS_PROGRESS_TESTING;
+
+ if (title.IsEmpty())
+ title = LangString(titleID);
+ }
+
+ const UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE);
+
+ extracter.MainWindow = GetParent();
+ extracter.MainTitle = progressWindowTitle;
+ extracter.MainAddTitle = title + L' ';
+
+ extracter.ExtractCallbackSpec->OverwriteMode = NExtract::NOverwriteMode::kAsk;
+ extracter.ExtractCallbackSpec->Init();
+
+ extracter.CopyFrom_Paths = filePaths;
+ if (!filePaths)
+ {
+ extracter.Indices = indices;
+ extracter.FolderOperations = _folderOperations;
+ }
+
+ extracter.ExtractCallbackSpec->PasswordIsDefined = usePassword;
+ extracter.ExtractCallbackSpec->Password = password;
+
+ RINOK(extracter.Create(title, GetParent()))
+
+
+ if (messages)
+ *messages = extracter.Sync.Messages;
+
+ // res = extracter.Result2;
+ res = extracter.Result;
+
+ if (res == S_OK && extracter.ExtractCallbackSpec->IsOK())
+ {
+ usePassword = extracter.ExtractCallbackSpec->PasswordIsDefined;
+ password = extracter.ExtractCallbackSpec->Password;
+ }
+
+ extracter.ShowFinalResults(_window);
+
+ }
+
+ RefreshTitleAlways();
+ return res;
+}
+
+
+struct CThreadUpdate
+{
+ CMyComPtr<IFolderOperations> FolderOperations;
+ UString FolderPrefix;
+ UStringVector FileNames;
+ CRecordVector<const wchar_t *> FileNamePointers;
+ CProgressDialog ProgressDialog;
+ CMyComPtr<IFolderArchiveUpdateCallback> UpdateCallback;
+ CUpdateCallback100Imp *UpdateCallbackSpec;
+ HRESULT Result;
+ bool MoveMode;
+
+ void Process()
+ {
+ try
+ {
+ CProgressCloser closer(ProgressDialog);
+ Result = FolderOperations->CopyFrom(
+ MoveMode,
+ FolderPrefix,
+ &FileNamePointers.Front(),
+ FileNamePointers.Size(),
+ UpdateCallback);
+ }
+ catch(...) { Result = E_FAIL; }
+ }
+ static THREAD_FUNC_DECL MyThreadFunction(void *param)
+ {
+ ((CThreadUpdate *)param)->Process();
+ return 0;
+ }
+};
+
+
+HRESULT CPanel::CopyFrom(bool moveMode, const UString &folderPrefix, const UStringVector &filePaths,
+ bool showErrorMessages, UStringVector *messages)
+{
+ if (IsHashFolder())
+ {
+ if (moveMode)
+ return E_NOTIMPL;
+ }
+ // CDisableNotify disableNotify(*this);
+
+ HRESULT res;
+ if (!_folderOperations)
+ res = E_NOINTERFACE;
+ else
+ {
+ CThreadUpdate updater;
+ updater.MoveMode = moveMode;
+ updater.UpdateCallbackSpec = new CUpdateCallback100Imp;
+ updater.UpdateCallback = updater.UpdateCallbackSpec;
+ updater.UpdateCallbackSpec->Init();
+
+ updater.UpdateCallbackSpec->ProgressDialog = &updater.ProgressDialog;
+
+ const UString title = LangString(IDS_COPYING);
+ const UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE);
+
+ updater.ProgressDialog.MainWindow = GetParent();
+ updater.ProgressDialog.MainTitle = progressWindowTitle;
+ updater.ProgressDialog.MainAddTitle = title + L' ';
+
+ {
+ if (!_parentFolders.IsEmpty())
+ {
+ const CFolderLink &fl = _parentFolders.Back();
+ updater.UpdateCallbackSpec->PasswordIsDefined = fl.UsePassword;
+ updater.UpdateCallbackSpec->Password = fl.Password;
+ }
+ }
+
+ updater.FolderOperations = _folderOperations;
+ updater.FolderPrefix = folderPrefix;
+ updater.FileNames.ClearAndReserve(filePaths.Size());
+ unsigned i;
+ for (i = 0; i < filePaths.Size(); i++)
+ updater.FileNames.AddInReserved(filePaths[i]);
+ updater.FileNamePointers.ClearAndReserve(updater.FileNames.Size());
+ for (i = 0; i < updater.FileNames.Size(); i++)
+ updater.FileNamePointers.AddInReserved(updater.FileNames[i]);
+
+ {
+ NWindows::CThread thread;
+ const WRes wres = thread.Create(CThreadUpdate::MyThreadFunction, &updater);
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ updater.ProgressDialog.Create(title, thread, GetParent());
+ }
+
+ if (messages)
+ *messages = updater.ProgressDialog.Sync.Messages;
+
+ res = updater.Result;
+ }
+
+ if (res == E_NOINTERFACE)
+ {
+ const UString errorMessage = LangString(IDS_OPERATION_IS_NOT_SUPPORTED);
+ if (showErrorMessages)
+ MessageBox_Error(errorMessage);
+ else if (messages)
+ messages->Add(errorMessage);
+ return E_ABORT;
+ }
+
+ RefreshTitleAlways();
+ return res;
+}
+
+void CPanel::CopyFromNoAsk(bool moveMode, const UStringVector &filePaths)
+{
+ CDisableTimerProcessing disableTimerProcessing(*this);
+
+ CSelectedState srcSelState;
+ SaveSelectedState(srcSelState);
+
+ CDisableNotify disableNotify(*this);
+
+ const HRESULT result = CopyFrom(moveMode, L"", filePaths, true, NULL);
+
+ if (result != S_OK)
+ {
+ disableNotify.Restore();
+ // For Password:
+ SetFocusToList();
+ if (result != E_ABORT)
+ MessageBox_Error_HRESULT(result);
+ return;
+ }
+
+ RefreshListCtrl(srcSelState);
+
+ disableNotify.Restore();
+ SetFocusToList();
+}
diff --git a/CPP/7zip/UI/FileManager/PanelCrc.cpp b/CPP/7zip/UI/FileManager/PanelCrc.cpp
new file mode 100644
index 0000000..df0b733
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelCrc.cpp
@@ -0,0 +1,422 @@
+// PanelCrc.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyException.h"
+
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/FileIO.h"
+#include "../../../Windows/FileName.h"
+
+#include "../Common/LoadCodecs.h"
+
+#include "../GUI/HashGUI.h"
+
+#include "App.h"
+#include "LangUtils.h"
+
+#include "resource.h"
+
+using namespace NWindows;
+using namespace NFile;
+
+#ifdef Z7_EXTERNAL_CODECS
+extern CExternalCodecs g_ExternalCodecs;
+HRESULT LoadGlobalCodecs();
+#endif
+
+static const UInt32 kBufSize = (1 << 15);
+
+struct CDirEnumerator
+{
+ bool EnterToDirs;
+ FString BasePrefix;
+ FString BasePrefix_for_Open;
+ FStringVector FilePaths;
+
+ CObjectVector<NFind::CEnumerator> Enumerators;
+ FStringVector Prefixes;
+ unsigned Index;
+
+ CDirEnumerator(): EnterToDirs(false), Index(0) {}
+
+ void Init();
+ DWORD GetNextFile(NFind::CFileInfo &fi, bool &filled, FString &resPath);
+};
+
+void CDirEnumerator::Init()
+{
+ Enumerators.Clear();
+ Prefixes.Clear();
+ Index = 0;
+}
+
+static DWORD GetNormalizedError()
+{
+ const DWORD error = GetLastError();
+ return (error == 0) ? (DWORD)E_FAIL : error;
+}
+
+DWORD CDirEnumerator::GetNextFile(NFind::CFileInfo &fi, bool &filled, FString &resPath)
+{
+ filled = false;
+ resPath.Empty();
+
+ for (;;)
+ {
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ bool isRootPrefix = (BasePrefix.IsEmpty() || (NName::IsSuperPath(BasePrefix) && BasePrefix[NName::kSuperPathPrefixSize] == 0));
+ #endif
+
+ if (Enumerators.IsEmpty())
+ {
+ if (Index >= FilePaths.Size())
+ return S_OK;
+ const FString &path = FilePaths[Index++];
+ const int pos = path.ReverseFind_PathSepar();
+ if (pos >= 0)
+ resPath.SetFrom(path, (unsigned)pos + 1);
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (isRootPrefix && path.Len() == 2 && NName::IsDrivePath2(path))
+ {
+ // we use "c:" item as directory item
+ fi.ClearBase();
+ fi.Name = path;
+ fi.SetAsDir();
+ fi.Size = 0;
+ }
+ else
+ #endif
+ if (!fi.Find(BasePrefix + path))
+ {
+ const DWORD error = GetNormalizedError();
+ resPath = path;
+ return error;
+ }
+
+ break;
+ }
+
+ bool found;
+
+ if (Enumerators.Back().Next(fi, found))
+ {
+ if (found)
+ {
+ resPath = Prefixes.Back();
+ break;
+ }
+ }
+ else
+ {
+ const DWORD error = GetNormalizedError();
+ resPath = Prefixes.Back();
+ Enumerators.DeleteBack();
+ Prefixes.DeleteBack();
+ return error;
+ }
+
+ Enumerators.DeleteBack();
+ Prefixes.DeleteBack();
+ }
+
+ resPath += fi.Name;
+
+ if (EnterToDirs && fi.IsDir())
+ {
+ FString s = resPath;
+ s.Add_PathSepar();
+ Prefixes.Add(s);
+ Enumerators.AddNew().SetDirPrefix(BasePrefix + s);
+ }
+
+ filled = true;
+ return S_OK;
+}
+
+
+
+class CThreadCrc: public CProgressThreadVirt
+{
+ bool ResultsWereShown;
+ bool WasFinished;
+
+ HRESULT ProcessVirt() Z7_override;
+ virtual void ProcessWasFinished_GuiVirt() Z7_override;
+public:
+ CDirEnumerator Enumerator;
+ CHashBundle Hash;
+ // FString FirstFilePath;
+
+ void SetStatus(const UString &s);
+ void AddErrorMessage(DWORD systemError, const FChar *name);
+ void ShowFinalResults(HWND hwnd);
+
+ CThreadCrc():
+ ResultsWereShown(false),
+ WasFinished(false)
+ {}
+};
+
+void CThreadCrc::ShowFinalResults(HWND hwnd)
+{
+ if (WasFinished)
+ if (!ResultsWereShown)
+ {
+ ResultsWereShown = true;
+ ShowHashResults(Hash, hwnd);
+ }
+}
+
+void CThreadCrc::ProcessWasFinished_GuiVirt()
+{
+ ShowFinalResults(*this);
+}
+
+void CThreadCrc::AddErrorMessage(DWORD systemError, const FChar *name)
+{
+ Sync.AddError_Code_Name(HRESULT_FROM_WIN32(systemError), fs2us(Enumerator.BasePrefix + name));
+ Hash.NumErrors++;
+}
+
+void CThreadCrc::SetStatus(const UString &s2)
+{
+ UString s = s2;
+ if (!Enumerator.BasePrefix.IsEmpty())
+ {
+ s.Add_Space_if_NotEmpty();
+ s += fs2us(Enumerator.BasePrefix);
+ }
+ Sync.Set_Status(s);
+}
+
+HRESULT CThreadCrc::ProcessVirt()
+{
+ // Hash.Init();
+
+ CMyBuffer buf;
+ if (!buf.Allocate(kBufSize))
+ return E_OUTOFMEMORY;
+
+ CProgressSync &sync = Sync;
+
+ SetStatus(LangString(IDS_SCANNING));
+
+ Enumerator.Init();
+
+ FString path;
+ NFind::CFileInfo fi;
+ UInt64 numFiles = 0;
+ UInt64 numItems = 0, numItems_Prev = 0;
+ UInt64 totalSize = 0;
+
+ for (;;)
+ {
+ bool filled;
+ const DWORD error = Enumerator.GetNextFile(fi, filled, path);
+ if (error != 0)
+ {
+ AddErrorMessage(error, path);
+ continue;
+ }
+ if (!filled)
+ break;
+ if (!fi.IsDir())
+ {
+ totalSize += fi.Size;
+ numFiles++;
+ }
+ numItems++;
+ bool needPrint = false;
+ // if (fi.IsDir())
+ {
+ if (numItems - numItems_Prev >= 100)
+ {
+ needPrint = true;
+ numItems_Prev = numItems;
+ }
+ }
+ /*
+ else if (numFiles - numFiles_Prev >= 200)
+ {
+ needPrint = true;
+ numFiles_Prev = numFiles;
+ }
+ */
+ if (needPrint)
+ {
+ RINOK(sync.ScanProgress(numFiles, totalSize, path, fi.IsDir()))
+ }
+ }
+ RINOK(sync.ScanProgress(numFiles, totalSize, FString(), false))
+ // sync.SetNumFilesTotal(numFiles);
+ // sync.SetProgress(totalSize, 0);
+ // SetStatus(LangString(IDS_CHECKSUM_CALCULATING));
+ // sync.SetCurFilePath(L"");
+ SetStatus(L"");
+
+ Enumerator.Init();
+
+ FString tempPath;
+ bool isFirstFile = true;
+ UInt64 errorsFilesSize = 0;
+
+ for (;;)
+ {
+ bool filled;
+ DWORD error = Enumerator.GetNextFile(fi, filled, path);
+ if (error != 0)
+ {
+ AddErrorMessage(error, path);
+ continue;
+ }
+ if (!filled)
+ break;
+
+ error = 0;
+ Hash.InitForNewFile();
+ if (!fi.IsDir())
+ {
+ NIO::CInFile inFile;
+ tempPath = Enumerator.BasePrefix_for_Open;
+ tempPath += path;
+ if (!inFile.Open(tempPath))
+ {
+ error = GetNormalizedError();
+ AddErrorMessage(error, path);
+ continue;
+ }
+ if (isFirstFile)
+ {
+ Hash.FirstFileName = fs2us(path);
+ isFirstFile = false;
+ }
+ sync.Set_FilePath(fs2us(path));
+ sync.Set_NumFilesCur(Hash.NumFiles);
+ UInt64 progress_Prev = 0;
+ for (;;)
+ {
+ UInt32 size;
+ if (!inFile.Read(buf, kBufSize, size))
+ {
+ error = GetNormalizedError();
+ AddErrorMessage(error, path);
+ UInt64 errorSize = 0;
+ if (inFile.GetLength(errorSize))
+ errorsFilesSize += errorSize;
+ break;
+ }
+ if (size == 0)
+ break;
+ Hash.Update(buf, size);
+ if (Hash.CurSize - progress_Prev >= ((UInt32)1 << 21))
+ {
+ RINOK(sync.Set_NumBytesCur(errorsFilesSize + Hash.FilesSize + Hash.CurSize))
+ progress_Prev = Hash.CurSize;
+ }
+ }
+ }
+ if (error == 0)
+ Hash.Final(fi.IsDir(), false, fs2us(path));
+ RINOK(sync.Set_NumBytesCur(errorsFilesSize + Hash.FilesSize))
+ }
+ RINOK(sync.Set_NumBytesCur(errorsFilesSize + Hash.FilesSize))
+ sync.Set_NumFilesCur(Hash.NumFiles);
+ if (Hash.NumFiles != 1)
+ sync.Set_FilePath(L"");
+ SetStatus(L"");
+
+ CProgressMessageBoxPair &pair = GetMessagePair(Hash.NumErrors != 0);
+ WasFinished = true;
+ LangString(IDS_CHECKSUM_INFORMATION, pair.Title);
+ return S_OK;
+}
+
+
+
+HRESULT CApp::CalculateCrc2(const UString &methodName)
+{
+ unsigned srcPanelIndex = GetFocusedPanelIndex();
+ CPanel &srcPanel = Panels[srcPanelIndex];
+
+ CRecordVector<UInt32> indices;
+ srcPanel.Get_ItemIndices_OperSmart(indices);
+ if (indices.IsEmpty())
+ return S_OK;
+
+ if (!srcPanel.Is_IO_FS_Folder())
+ {
+ CCopyToOptions options;
+ options.streamMode = true;
+ options.showErrorMessages = true;
+ options.hashMethods.Add(methodName);
+ options.NeedRegistryZone = false;
+
+ UStringVector messages;
+ return srcPanel.CopyTo(options, indices, &messages);
+ }
+
+ #ifdef Z7_EXTERNAL_CODECS
+
+ LoadGlobalCodecs();
+
+ #endif
+
+ {
+ CThreadCrc t;
+
+ {
+ UStringVector methods;
+ methods.Add(methodName);
+ RINOK(t.Hash.SetMethods(EXTERNAL_CODECS_VARS_G methods))
+ }
+
+ FOR_VECTOR (i, indices)
+ t.Enumerator.FilePaths.Add(us2fs(srcPanel.GetItemRelPath(indices[i])));
+
+ if (t.Enumerator.FilePaths.Size() == 1)
+ t.Hash.MainName = fs2us(t.Enumerator.FilePaths[0]);
+
+ UString basePrefix = srcPanel.GetFsPath();
+ UString basePrefix2 = basePrefix;
+ if (basePrefix2.Back() == ':')
+ {
+ const int pos = basePrefix2.ReverseFind_PathSepar();
+ if (pos >= 0)
+ basePrefix2.DeleteFrom((unsigned)(pos + 1));
+ }
+
+ t.Enumerator.BasePrefix = us2fs(basePrefix);
+ t.Enumerator.BasePrefix_for_Open = us2fs(basePrefix2);
+
+ t.Enumerator.EnterToDirs = !GetFlatMode();
+
+ t.ShowCompressionInfo = false;
+
+ const UString title = LangString(IDS_CHECKSUM_CALCULATING);
+
+ t.MainWindow = _window;
+ t.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE);
+ t.MainAddTitle = title;
+ t.MainAddTitle.Add_Space();
+
+ RINOK(t.Create(title, _window))
+
+ t.ShowFinalResults(_window);
+ }
+
+ RefreshTitleAlways();
+ return S_OK;
+}
+
+void CApp::CalculateCrc(const char *methodName)
+{
+ HRESULT res = CalculateCrc2(UString(methodName));
+ if (res != S_OK && res != E_ABORT)
+ {
+ unsigned srcPanelIndex = GetFocusedPanelIndex();
+ CPanel &srcPanel = Panels[srcPanelIndex];
+ srcPanel.MessageBox_Error_HRESULT(res);
+ }
+}
diff --git a/CPP/7zip/UI/FileManager/PanelDrag.cpp b/CPP/7zip/UI/FileManager/PanelDrag.cpp
new file mode 100644
index 0000000..040444c
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelDrag.cpp
@@ -0,0 +1,3006 @@
+// PanelDrag.cpp
+
+#include "StdAfx.h"
+
+#ifdef UNDER_CE
+#include <winuserm.h>
+#endif
+
+#include "../../../../C/7zVersion.h"
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/COM.h"
+#include "../../../Windows/MemoryGlobal.h"
+#include "../../../Windows/Menu.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/Shell.h"
+
+#include "../Common/ArchiveName.h"
+#include "../Common/CompressCall.h"
+#include "../Common/ExtractingFilePath.h"
+
+#include "MessagesDialog.h"
+
+#include "App.h"
+#include "EnumFormatEtc.h"
+#include "FormatUtils.h"
+#include "LangUtils.h"
+
+#include "resource.h"
+#include "../Explorer/resource.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+#define PRF(x)
+#define PRF_W(x)
+// #define PRF2(x)
+#define PRF3(x)
+#define PRF3_W(x)
+#define PRF4(x)
+// #define PRF4(x) OutputDebugStringA(x)
+// #define PRF4_W(x) OutputDebugStringW(x)
+
+// #define SHOW_DEBUG_DRAG
+
+#ifdef SHOW_DEBUG_DRAG
+
+#define PRF_(x) { x; }
+
+static void Print_Point(const char *name, DWORD keyState, const POINTL &pt, DWORD effect)
+{
+ AString s (name);
+ s += " x="; s.Add_UInt32((unsigned)pt.x);
+ s += " y="; s.Add_UInt32((unsigned)pt.y);
+ s += " k="; s.Add_UInt32(keyState);
+ s += " e="; s.Add_UInt32(effect);
+ PRF4(s);
+}
+
+#else
+
+#define PRF_(x)
+
+#endif
+
+
+#define kTempDirPrefix FTEXT("7zE")
+
+// all versions: k_Format_7zip_SetTargetFolder format to transfer folder path from target to source
+static LPCTSTR const k_Format_7zip_SetTargetFolder = TEXT("7-Zip::SetTargetFolder");
+// new v23 formats:
+static LPCTSTR const k_Format_7zip_SetTransfer = TEXT("7-Zip::SetTransfer");
+static LPCTSTR const k_Format_7zip_GetTransfer = TEXT("7-Zip::GetTransfer");
+
+/*
+ Win10: clipboard formats.
+ There are about 16K free ids (formats) per system that can be
+ registered with RegisterClipboardFormat() with different names.
+ Probably that 16K ids space is common for ids registering for both
+ formats: RegisterClipboardFormat(), and registered window classes:
+ RegisterClass(). But ids for window classes will be deleted from
+ the list after process finishing. And registered clipboard
+ formats probably will be deleted from the list only after reboot.
+*/
+
+// static bool const g_CreateArchive_for_Drag_from_7zip = false;
+// static bool const g_CreateArchive_for_Drag_from_Explorer = true;
+ // = false; // for debug
+
+/*
+How DoDragDrop() works:
+{
+ IDropSource::QueryContinueDrag() (keyState & MK_LBUTTON) != 0
+ IDropTarget::Enter()
+ IDropSource::GiveFeedback()
+ IDropTarget::DragOver()
+ IDropSource::GiveFeedback()
+
+ for()
+ {
+ IDropSource::QueryContinueDrag() (keyState & MK_LBUTTON) != 0
+ IDropTarget::DragOver() (keyState & MK_LBUTTON) != 0
+ IDropSource::GiveFeedback()
+ }
+
+ {
+ // DoDragDrop() in Win10 before calling // QueryContinueDrag()
+ // with (*(keyState & MK_LBUTTON) == 0) probably calls:
+ // 1) IDropTarget::DragOver() with same point values (x,y), but (keyState & MK_LBUTTON) != 0)
+ // 2) IDropSource::GiveFeedback().
+ // so DropSource can know exact GiveFeedback(effect) mode just before LBUTTON releasing.
+
+ if (IDropSource::QueryContinueDrag() for (keyState & MK_LBUTTON) == 0
+ returns DRAGDROP_S_DROP), it will call
+ IDropTarget::Drop()
+ }
+ or
+ {
+ IDropSource::QueryContinueDrag()
+ IDropTarget::DragLeave()
+ IDropSource::GiveFeedback(0)
+ }
+ or
+ {
+ if (IDropSource::QueryContinueDrag()
+ returns DRAGDROP_S_CANCEL)
+ IDropTarget::DragLeave()
+ }
+}
+*/
+
+
+// ---------- CDropTarget ----------
+
+static const UInt32 k_Struct_Id_SetTranfer = 2; // it's our selected id
+static const UInt32 k_Struct_Id_GetTranfer = 3; // it's our selected id
+
+static const UInt64 k_Program_Id = 1; // "7-Zip"
+
+enum E_Program_ISA
+{
+ k_Program_ISA_x86 = 2,
+ k_Program_ISA_x64 = 3,
+ k_Program_ISA_armt = 4,
+ k_Program_ISA_arm64 = 5,
+ k_Program_ISA_arm32 = 6,
+ k_Program_ISA_ia64 = 9
+};
+
+#define k_Program_Ver ((MY_VER_MAJOR << 16) | MY_VER_MINOR)
+
+
+// k_SourceFlags_* are flags that are sent from Source to Target
+
+static const UInt32 k_SourceFlags_DoNotProcessInTarget = 1 << 1;
+/* Do not process in Target. Source will process operation instead of Target.
+ By default Target processes Drop opearation. */
+// static const UInt32 k_SourceFlags_ProcessInTarget = 1 << 2;
+
+static const UInt32 k_SourceFlags_DoNotWaitFinish = 1 << 3;
+static const UInt32 k_SourceFlags_WaitFinish = 1 << 4;
+/* usually Source needs WaitFinish, if temp files were created. */
+
+static const UInt32 k_SourceFlags_TempFiles = 1 << 6;
+static const UInt32 k_SourceFlags_NamesAreParent = 1 << 7;
+/* if returned path list for GetData(CF_HDROP) contains
+ path of parent temp folder instead of final paths of items
+ that will be extracted later from archive */
+
+static const UInt32 k_SourceFlags_SetTargetFolder = 1 << 8;
+/* SetData::("SetTargetFolder") was called (with empty or non-empty string) */
+
+static const UInt32 k_SourceFlags_SetTargetFolder_NonEmpty = 1 << 9;
+/* SetData::("SetTargetFolder") was called with non-empty string */
+
+static const UInt32 k_SourceFlags_NeedExtractOpToFs = 1 << 10;
+
+static const UInt32 k_SourceFlags_Copy_WasCalled = 1 << 11;
+
+static const UInt32 k_SourceFlags_LeftButton = 1 << 14;
+static const UInt32 k_SourceFlags_RightButton = 1 << 15;
+
+
+static const UInt32 k_TargetFlags_WasCanceled = 1 << 0;
+static const UInt32 k_TargetFlags_MustBeProcessedBySource = 1 << 1;
+static const UInt32 k_TargetFlags_WasProcessed = 1 << 2;
+static const UInt32 k_TargetFlags_DoNotWaitFinish = 1 << 3;
+static const UInt32 k_TargetFlags_WaitFinish = 1 << 4;
+static const UInt32 k_TargetFlags_MenuWasShown = 1 << 16;
+
+struct CDataObject_TransferBase
+{
+ UInt32 Struct_Id;
+ UInt32 Struct_Size;
+
+ UInt64 Program_Id;
+ UInt32 Program_Ver_Main;
+ UInt32 Program_Ver_Build;
+ UInt32 Program_ISA;
+ UInt32 Program_Flags;
+
+ UInt32 ProcessId;
+ UInt32 _reserved1[7];
+
+protected:
+ void Init_Program();
+};
+
+
+void CDataObject_TransferBase::Init_Program()
+{
+ Program_Id = k_Program_Id;
+ Program_ISA =
+ #if defined(MY_CPU_AMD64)
+ k_Program_ISA_x64
+ #elif defined(MY_CPU_X86)
+ k_Program_ISA_x86
+ #elif defined(MY_CPU_ARM64)
+ k_Program_ISA_arm64
+ #elif defined(MY_CPU_ARM32)
+ k_Program_ISA_arm32
+ #elif defined(MY_CPU_ARMT) || defined(MY_CPU_ARM)
+ k_Program_ISA_armt
+ #elif defined(MY_CPU_IA64)
+ k_Program_ISA_ia64
+ #else
+ 0
+ #endif
+ ;
+ Program_Flags = sizeof(size_t);
+ Program_Ver_Main = k_Program_Ver;
+ // Program_Ver_Build = 0;
+ ProcessId = GetCurrentProcessId();
+}
+
+
+#if defined(__GNUC__) && !defined(__clang__)
+/* 'void* memset(void*, int, size_t)' clearing an object
+ of non-trivial type 'struct CDataObject_SetTransfer' */
+#pragma GCC diagnostic ignored "-Wclass-memaccess"
+#endif
+
+
+struct CDataObject_GetTransfer:
+public CDataObject_TransferBase
+{
+ UInt32 Flags;
+
+ UInt32 _reserved2[11];
+
+ CDataObject_GetTransfer()
+ {
+ memset(this, 0, sizeof(*this));
+ Init_Program();
+ Struct_Id = k_Struct_Id_GetTranfer;
+ Struct_Size = sizeof(*this);
+ }
+
+ bool Check() const
+ {
+ return Struct_Size >= sizeof(*this) && Struct_Id == k_Struct_Id_GetTranfer;
+ }
+};
+
+
+enum Enum_FolderType
+{
+ k_FolderType_None,
+ k_FolderType_Unknown = 1,
+ k_FolderType_Fs = 2,
+ k_FolderType_AltStreams = 3,
+ k_FolderType_Archive = 4
+};
+
+struct CTargetTransferInfo
+{
+ UInt32 Flags;
+ UInt32 FuncType;
+
+ UInt32 KeyState;
+ UInt32 OkEffects;
+ POINTL Point;
+
+ UInt32 Cmd_Effect;
+ UInt32 Cmd_Type;
+ UInt32 FolderType;
+ UInt32 _reserved3[3];
+
+ CTargetTransferInfo()
+ {
+ memset(this, 0, sizeof(*this));
+ }
+};
+
+struct CDataObject_SetTransfer:
+public CDataObject_TransferBase
+{
+ CTargetTransferInfo Target;
+
+ void Init()
+ {
+ memset(this, 0, sizeof(*this));
+ Init_Program();
+ Struct_Id = k_Struct_Id_SetTranfer;
+ Struct_Size = sizeof(*this);
+ }
+
+ bool Check() const
+ {
+ return Struct_Size >= sizeof(*this) && Struct_Id == k_Struct_Id_SetTranfer;
+ }
+};
+
+
+
+
+
+enum Enum_DragTargetMode
+{
+ k_DragTargetMode_None = 0,
+ k_DragTargetMode_Leave = 1,
+ k_DragTargetMode_Enter = 2,
+ k_DragTargetMode_Over = 3,
+ k_DragTargetMode_Drop_Begin = 4,
+ k_DragTargetMode_Drop_End = 5
+};
+
+
+// ---- menu ----
+
+namespace NDragMenu {
+
+enum Enum_CmdId
+{
+ k_None = 0,
+ k_Cancel = 1,
+ k_Copy_Base = 2, // to fs
+ k_Copy_ToArc = 3,
+ k_AddToArc = 4
+ /*
+ k_OpenArc = 8,
+ k_TestArc = 9,
+ k_ExtractFiles = 10,
+ k_ExtractHere = 11
+ */
+};
+
+struct CCmdLangPair
+{
+ unsigned CmdId_and_Flags;
+ unsigned LangId;
+};
+
+static const UInt32 k_MenuFlags_CmdMask = (1 << 7) - 1;
+static const UInt32 k_MenuFlag_Copy = 1 << 14;
+static const UInt32 k_MenuFlag_Move = 1 << 15;
+// #define IDS_CANCEL (IDCANCEL + 400)
+#define IDS_CANCEL 402
+
+static const CCmdLangPair g_Pairs[] =
+{
+ { k_Copy_Base | k_MenuFlag_Copy, IDS_COPY },
+ { k_Copy_Base | k_MenuFlag_Move, IDS_MOVE },
+ { k_Copy_ToArc | k_MenuFlag_Copy, IDS_COPY_TO },
+ // { k_Copy_ToArc | k_MenuFlag_Move, IDS_MOVE_TO }, // IDS_CONTEXT_COMPRESS_TO
+ // { k_OpenArc, IDS_CONTEXT_OPEN },
+ // { k_ExtractFiles, IDS_CONTEXT_EXTRACT },
+ // { k_ExtractHere, IDS_CONTEXT_EXTRACT_HERE },
+ // { k_TestArc, IDS_CONTEXT_TEST },
+ { k_AddToArc | k_MenuFlag_Copy, IDS_CONTEXT_COMPRESS },
+ { k_Cancel, IDS_CANCEL }
+};
+
+}
+
+
+class CDropTarget Z7_final:
+ public IDropTarget,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_1_MT(IDropTarget)
+ STDMETHOD(DragEnter)(IDataObject *dataObject, DWORD keyState, POINTL pt, DWORD *effect) Z7_override;
+ STDMETHOD(DragOver)(DWORD keyState, POINTL pt, DWORD *effect) Z7_override;
+ STDMETHOD(DragLeave)() Z7_override;
+ STDMETHOD(Drop)(IDataObject *dataObject, DWORD keyState, POINTL pt, DWORD *effect) Z7_override;
+
+ bool m_IsRightButton;
+ bool m_GetTransfer_WasSuccess;
+ bool m_DropIsAllowed; // = true, if data IDataObject can return CF_HDROP (so we can get list of paths)
+ bool m_PanelDropIsAllowed; // = false, if current target_panel is source_panel.
+ // check it only if m_DropIsAllowed == true
+ // we use it to show icon effect that drop is not allowed here.
+
+ CMyComPtr<IDataObject> m_DataObject; // we set it in DragEnter()
+ UStringVector m_SourcePaths;
+
+ // int m_DropHighlighted_SelectionIndex;
+ // int m_SubFolderIndex; // realIndex of item in m_Panel list (if drop cursor to that item)
+ // UString m_DropHighlighted_SubFolderName; // name of folder in m_Panel list (if drop cursor to that folder)
+
+ CPanel *m_Panel;
+ bool m_IsAppTarget; // true, if we want to drop to app window (not to panel)
+
+ bool m_TargetPath_WasSent_ToDataObject; // true, if TargetPath was sent
+ bool m_TargetPath_NonEmpty_WasSent_ToDataObject; // true, if non-empty TargetPath was sent
+ bool m_Transfer_WasSent_ToDataObject; // true, if Transfer was sent
+ UINT m_Format_7zip_SetTargetFolder;
+ UINT m_Format_7zip_SetTransfer;
+ UINT m_Format_7zip_GetTransfer;
+
+ UInt32 m_ProcessId; // for sending
+
+ bool IsItSameDrive() const;
+
+ // void Try_QueryGetData(IDataObject *dataObject);
+ void LoadNames_From_DataObject(IDataObject *dataObject);
+
+ UInt32 GetFolderType() const;
+ bool IsFsFolderPath() const;
+ DWORD GetEffect(DWORD keyState, POINTL pt, DWORD allowedEffect) const;
+ void RemoveSelection();
+ void PositionCursor(const POINTL &ptl);
+ UString GetTargetPath() const;
+ bool SendToSource_TargetPath_enable(IDataObject *dataObject, bool enablePath);
+ bool SendToSource_UInt32(IDataObject *dataObject, UINT format, UInt32 value);
+ bool SendToSource_TransferInfo(IDataObject *dataObject,
+ const CTargetTransferInfo &info);
+ void SendToSource_auto(IDataObject *dataObject,
+ const CTargetTransferInfo &info);
+ void SendToSource_Drag(CTargetTransferInfo &info)
+ {
+ SendToSource_auto(m_DataObject, info);
+ }
+
+ void ClearState();
+
+public:
+ CDropTarget();
+
+ CApp *App;
+ int SrcPanelIndex; // index of D&D source_panel
+ int TargetPanelIndex; // what panel to use as target_panel of Application
+};
+
+
+
+
+// ---------- CDataObject ----------
+
+/*
+ Some programs (like Sticky Notes in Win10) do not like
+ virtual non-existing items (files/dirs) in CF_HDROP format.
+ So we use two versions of CF_HDROP data:
+ m_hGlobal_HDROP_Pre : the list contains only destination path of temp directory.
+ That directory later will be filled with extracted items.
+ m_hGlobal_HDROP_Final : the list contains paths of all root items that
+ will be created in temp directory by archive extraction operation,
+ or the list of existing fs items, if source is filesystem directory.
+
+ The DRAWBACK: some programs (like Edge in Win10) can use names from IDataObject::GetData()
+ call that was called before IDropSource::QueryContinueDrag() where we set (UseFinalGlobal = true)
+ So such programs will use non-relevant m_hGlobal_HDROP_Pre item,
+ instead of m_hGlobal_HDROP_Final items.
+*/
+
+class CDataObject Z7_final:
+ public IDataObject,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_1_MT(IDataObject)
+
+ Z7_COMWF_B GetData(LPFORMATETC pformatetcIn, LPSTGMEDIUM medium) Z7_override;
+ Z7_COMWF_B GetDataHere(LPFORMATETC pformatetc, LPSTGMEDIUM medium) Z7_override;
+ Z7_COMWF_B QueryGetData(LPFORMATETC pformatetc) Z7_override;
+
+ Z7_COMWF_B GetCanonicalFormatEtc(LPFORMATETC /* pformatetc */, LPFORMATETC pformatetcOut) Z7_override
+ {
+ if (!pformatetcOut)
+ return E_INVALIDARG;
+ pformatetcOut->ptd = NULL;
+ return E_NOTIMPL;
+ }
+
+ Z7_COMWF_B SetData(LPFORMATETC etc, STGMEDIUM *medium, BOOL release) Z7_override;
+ Z7_COMWF_B EnumFormatEtc(DWORD drection, LPENUMFORMATETC *enumFormatEtc) Z7_override;
+
+ Z7_COMWF_B DAdvise(FORMATETC * /* etc */, DWORD /* advf */, LPADVISESINK /* pAdvSink */, DWORD * /* pdwConnection */) Z7_override
+ { return OLE_E_ADVISENOTSUPPORTED; }
+ Z7_COMWF_B DUnadvise(DWORD /* dwConnection */) Z7_override
+ { return OLE_E_ADVISENOTSUPPORTED; }
+ Z7_COMWF_B EnumDAdvise(LPENUMSTATDATA *ppenumAdvise) Z7_override
+ {
+ if (ppenumAdvise)
+ *ppenumAdvise = NULL;
+ return OLE_E_ADVISENOTSUPPORTED;
+ }
+
+ bool m_PerformedDropEffect_WasSet;
+ bool m_LogicalPerformedDropEffect_WasSet;
+ bool m_DestDirPrefix_FromTarget_WasSet;
+public:
+ bool m_Transfer_WasSet;
+private:
+ // GetData formats (source to target):
+ FORMATETC m_Etc;
+ // UINT m_Format_FileOpFlags;
+ // UINT m_Format_PreferredDropEffect;
+
+ // SetData() formats (target to source):
+ // 7-Zip's format:
+ UINT m_Format_7zip_SetTargetFolder;
+ UINT m_Format_7zip_SetTransfer;
+ UINT m_Format_7zip_GetTransfer; // for GetData()
+
+ UINT m_Format_PerformedDropEffect;
+ UINT m_Format_LogicalPerformedDropEffect;
+ UINT m_Format_DisableDragText;
+ UINT m_Format_IsShowingLayered;
+ UINT m_Format_IsShowingText;
+ UINT m_Format_DropDescription;
+ UINT m_Format_TargetCLSID;
+
+ DWORD m_PerformedDropEffect;
+ DWORD m_LogicalPerformedDropEffect;
+
+ void CopyFromPanelTo_Folder();
+ HRESULT SetData2(const FORMATETC *formatetc, const STGMEDIUM *medium);
+
+public:
+ bool IsRightButton;
+ bool IsTempFiles;
+
+ bool UsePreGlobal;
+ bool DoNotProcessInTarget;
+
+ bool NeedCall_Copy;
+ bool Copy_WasCalled;
+
+ NMemory::CGlobal m_hGlobal_HDROP_Pre;
+ NMemory::CGlobal m_hGlobal_HDROP_Final;
+ // NMemory::CGlobal m_hGlobal_FileOpFlags;
+ // NMemory::CGlobal m_hGlobal_PreferredDropEffect;
+
+ CPanel *Panel;
+ CRecordVector<UInt32> Indices;
+
+ UString SrcDirPrefix_Temp; // FS directory with source files or Temp
+ UString DestDirPrefix_FromTarget;
+ /* destination Path that was sent by Target via SetData().
+ it can be altstreams prefix.
+ if (!DestDirPrefix_FromTarget.IsEmpty()) m_Panel->CompressDropFiles() was not called by Target.
+ So we must do drop actions in Source */
+ HRESULT Copy_HRESULT;
+ UStringVector Messages;
+
+ CDataObject();
+public:
+ CDataObject_SetTransfer m_Transfer;
+};
+
+
+// for old mingw:
+#ifndef CFSTR_LOGICALPERFORMEDDROPEFFECT
+#define CFSTR_LOGICALPERFORMEDDROPEFFECT TEXT("Logical Performed DropEffect")
+#endif
+#ifndef CFSTR_TARGETCLSID
+#define CFSTR_TARGETCLSID TEXT("TargetCLSID") // HGLOBAL with a CLSID of the drop target
+#endif
+
+
+
+CDataObject::CDataObject()
+{
+ // GetData formats (source to target):
+ // and we use CF_HDROP format to transfer file paths from source to target:
+ m_Etc.cfFormat = CF_HDROP;
+ m_Etc.ptd = NULL;
+ m_Etc.dwAspect = DVASPECT_CONTENT;
+ m_Etc.lindex = -1;
+ m_Etc.tymed = TYMED_HGLOBAL;
+
+ // m_Format_FileOpFlags = RegisterClipboardFormat(TEXT("FileOpFlags"));
+ // m_Format_PreferredDropEffect = RegisterClipboardFormat(CFSTR_PREFERREDDROPEFFECT); // "Preferred DropEffect"
+
+ // SetData() formats (target to source):
+ m_Format_7zip_SetTargetFolder = RegisterClipboardFormat(k_Format_7zip_SetTargetFolder);
+ m_Format_7zip_SetTransfer = RegisterClipboardFormat(k_Format_7zip_SetTransfer);
+ m_Format_7zip_GetTransfer = RegisterClipboardFormat(k_Format_7zip_GetTransfer);
+
+ m_Format_PerformedDropEffect = RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT); // "Performed DropEffect"
+ m_Format_LogicalPerformedDropEffect = RegisterClipboardFormat(CFSTR_LOGICALPERFORMEDDROPEFFECT); // "Logical Performed DropEffect"
+ m_Format_DisableDragText = RegisterClipboardFormat(TEXT("DisableDragText"));
+ m_Format_IsShowingLayered = RegisterClipboardFormat(TEXT("IsShowingLayered"));
+ m_Format_IsShowingText = RegisterClipboardFormat(TEXT("IsShowingText"));
+ m_Format_DropDescription = RegisterClipboardFormat(TEXT("DropDescription"));
+ m_Format_TargetCLSID = RegisterClipboardFormat(CFSTR_TARGETCLSID);
+
+ m_PerformedDropEffect = 0;
+ m_LogicalPerformedDropEffect = 0;
+
+ m_PerformedDropEffect_WasSet = false;
+ m_LogicalPerformedDropEffect_WasSet = false;
+
+ m_DestDirPrefix_FromTarget_WasSet = false;
+ m_Transfer_WasSet = false;
+
+ IsRightButton = false;
+ IsTempFiles = false;
+
+ UsePreGlobal = false;
+ DoNotProcessInTarget = false;
+
+ NeedCall_Copy = false;
+ Copy_WasCalled = false;
+
+ Copy_HRESULT = S_OK;
+}
+
+
+
+void CDataObject::CopyFromPanelTo_Folder()
+{
+ try
+ {
+ CCopyToOptions options;
+ options.folder = SrcDirPrefix_Temp;
+ /* 15.13: fixed problem with mouse cursor for password window.
+ DoDragDrop() probably calls SetCapture() to some hidden window.
+ But it's problem, if we show some modal window, like MessageBox.
+ So we return capture to our window.
+ If you know better way to solve the problem, please notify 7-Zip developer.
+ */
+ // MessageBoxW(*Panel, L"test", L"test", 0);
+ /* HWND oldHwnd = */ SetCapture(*Panel);
+ Copy_WasCalled = true;
+ Copy_HRESULT = E_FAIL;
+ Copy_HRESULT = Panel->CopyTo(options, Indices, &Messages);
+ // do we need to restore capture?
+ // ReleaseCapture();
+ // oldHwnd = SetCapture(oldHwnd);
+ }
+ catch(...)
+ {
+ Copy_HRESULT = E_FAIL;
+ }
+}
+
+
+#ifdef SHOW_DEBUG_DRAG
+
+static void PrintFormat2(AString &s, unsigned format)
+{
+ s += " ";
+ s += "= format=";
+ s.Add_UInt32(format);
+ s += " ";
+ const int k_len = 512;
+ CHAR temp[k_len];
+ if (GetClipboardFormatNameA(format, temp, k_len) && strlen(temp) != 0)
+ s += temp;
+}
+
+static void PrintFormat(const char *title, unsigned format)
+{
+ AString s (title);
+ PrintFormat2(s, format);
+ PRF4(s);
+}
+
+static void PrintFormat_AndData(const char *title, unsigned format, const void *data, size_t size)
+{
+ AString s (title);
+ PrintFormat2(s, format);
+ s += " size=";
+ s.Add_UInt32((UInt32)size);
+ for (size_t i = 0; i < size && i < 16; i++)
+ {
+ s += " ";
+ s.Add_UInt32(((const Byte *)data)[i]);
+ }
+ PRF4(s);
+}
+
+static void PrintFormat_GUIDToStringW(const void *p)
+{
+ const GUID *guid = (const GUID *)p;
+ UString s;
+ const unsigned kSize = 48;
+ StringFromGUID2(*guid, s.GetBuf(kSize), kSize);
+ s.ReleaseBuf_CalcLen(kSize);
+ PRF3_W(s);
+}
+
+// Vista
+typedef enum
+{
+ MY_DROPIMAGE_INVALID = -1, // no image preference (use default)
+ MY_DROPIMAGE_NONE = 0, // red "no" circle
+ MY_DROPIMAGE_COPY = DROPEFFECT_COPY, // plus for copy
+ MY_DROPIMAGE_MOVE = DROPEFFECT_MOVE, // movement arrow for move
+ MY_DROPIMAGE_LINK = DROPEFFECT_LINK, // link arrow for link
+ MY_DROPIMAGE_LABEL = 6, // tag icon to indicate metadata will be changed
+ MY_DROPIMAGE_WARNING = 7, // yellow exclamation, something is amiss with the operation
+ MY_DROPIMAGE_NOIMAGE = 8 // no image at all
+} MY_DROPIMAGETYPE;
+
+typedef struct {
+ MY_DROPIMAGETYPE type;
+ WCHAR szMessage[MAX_PATH];
+ WCHAR szInsert[MAX_PATH];
+} MY_DROPDESCRIPTION;
+
+#endif
+
+
+/*
+IDataObject::SetData(LPFORMATETC etc, STGMEDIUM *medium, BOOL release)
+======================================================================
+
+ Main purpose of CDataObject is to transfer data from source to target
+ of drag and drop operation.
+ But also CDataObject can be used to transfer data in backward direction
+ from target to source (even if target and source are different processes).
+ There are some predefined Explorer's formats to transfer some data from target to source.
+ And 7-Zip uses 7-Zip's format k_Format_7zip_SetTargetFolder to transfer
+ destination directory path from target to source.
+
+ Our CDataObject::SetData() function here is used only to transfer data from target to source.
+ Usual source_to_target data is filled to m_hGlobal_* objects directly without SetData() calling.
+
+The main problem of SetData() is ownership of medium for (release == TRUE) case.
+
+SetData(,, release = TRUE) from different processes (DropSource and DropTarget)
+===============================================================================
+{
+ MS DOCs about (STGMEDIUM *medium) ownership:
+ The data object called does not take ownership of the data
+ until it has successfully received it and no error code is returned.
+
+ Each of processes (Source and Target) has own copy of medium allocated.
+ Windows code creates proxy IDataObject object in Target process to transferr
+ SetData() call between Target and Source processes via special proxies:
+ DropTarget ->
+ proxy_DataObject_in_Target ->
+ proxy_in_Source ->
+ DataObject_in_Source
+ when Target calls SetData() with proxy_DataObject_in_Target,
+ the system and proxy_in_Source
+ - allocates proxy-medium-in-Source process
+ - copies medium data from Target to that proxy-medium-in-Source
+ - sends proxy-medium-in-Source to DataObject_in_Source->SetData().
+
+ after returning from SetData() to Target process:
+ Win10 proxy_DataObject_in_Target releases original medium in Target process,
+ only if SetData() in Source returns S_OK. It's consistent with DOCs above.
+
+ for unsupported cfFormat:
+ [DropSource is 7-Zip 22.01 (old) : (etc->cfFormat != m_Format_7zip_SetTargetFolder && release == TRUE)]
+ (DropSource is WinRAR case):
+ Source doesn't release medium and returns error (for example, E_NOTIMPL)
+ {
+ Then Win10 proxy_in_Source also doesn't release proxy-medium-in-Source.
+ So there is memory leak in Source process.
+ Probably Win10 proxy_in_Source tries to avoid possible double releasing
+ that can be more fatal than memory leak.
+
+ Then Win10 proxy_DataObject_in_Target also doesn't release
+ original medium, that was allocated by DropTarget.
+ So if DropTarget also doesn't release medium, there is memory leak in
+ DropTarget process too.
+ DropTarget is Win10-Explorer probably doesn't release medium in that case.
+ }
+
+ [DropSource is 7-Zip 22.01 (old) : (etc->cfFormat == m_Format_7zip_SetTargetFolder && release == TRUE)]
+ DropSource returns S_OK and doesn't release medium:
+ {
+ then there is memory leak in DropSource process only.
+ }
+
+ (DropSource is 7-Zip v23 (new)):
+ (DropSource is Win10-Explorer case)
+ {
+ Win10-Explorer-DropSource probably always releases medium,
+ and then it always returns S_OK.
+ So Win10 proxy_DataObject_in_Target also releases
+ original medium, that was allocated by DropTarget.
+ So there is no memory leak in Source and Target processes.
+ }
+
+ if (DropTarget is Win10-Explorer)
+ {
+ Explorer Target uses SetData(,, (release = TRUE)) and
+ Explorer Target probably doesn't free memory after SetData(),
+ even if SetData(,, (release = TRUE)) returns E_NOTIMPL;
+ }
+
+ if (DropSource is Win10-Explorer)
+ {
+ (release == FALSE) doesn't work, and SetData() returns E_NOTIMPL;
+ (release == TRUE) works, and SetData() returns S_OK, and
+ it returns S_OK even for formats unsupported by Explorer.
+ }
+
+ To be more compatible with DOCs and Win10-Explorer and to avoid memory leaks,
+ we use the following scheme for our IDataObject::SetData(,, release == TRUE)
+ in DropSource code:
+ if (release == TRUE) { our SetData() always releases medium
+ with ReleaseStgMedium() and returns S_OK; }
+ The DRAWBACK of that scheme:
+ The caller always receives S_OK,
+ so the caller doesn't know about any error in SetData() in that case.
+
+for 7zip-Target to 7zip-Source calls:
+ we use (release == FALSE)
+ So we avoid (release == TRUE) memory leak problems,
+ and we can get real return code from SetData().
+
+for 7zip-Target to Explorer-Source calls:
+ we use (release == TRUE).
+ beacuse Explorer-Source doesn't accept (release == FALSE).
+}
+*/
+
+/*
+https://github.com/MicrosoftDocs/win32/blob/docs/desktop-src/shell/datascenarios.md
+CFSTR_PERFORMEDDROPEFFECT:
+ is used by the target to inform the data object through its
+ IDataObject::SetData method of the outcome of a data transfer.
+CFSTR_PREFERREDDROPEFFECT:
+ is used by the source to specify whether its preferred method of data transfer is move or copy.
+*/
+
+Z7_COMWF_B CDataObject::SetData(LPFORMATETC etc, STGMEDIUM *medium, BOOL release)
+{
+ try {
+ const HRESULT hres = SetData2(etc, medium);
+ // PrintFormat(release ? "SetData RELEASE=TRUE" : "SetData RELEASE=FALSE" , etc->cfFormat);
+ if (release)
+ {
+ /*
+ const DWORD tymed = medium->tymed;
+ IUnknown *pUnkForRelease = medium->pUnkForRelease;
+ */
+ // medium->tymed = NULL; // for debug
+ // return E_NOTIMPL; // for debug
+ ReleaseStgMedium(medium);
+ /* ReleaseStgMedium() will change STGMEDIUM::tymed to (TYMED_NULL = 0).
+ but we also can clear (medium.hGlobal = NULL),
+ to prevent some incorrect releasing, if the caller will try to release the data */
+ /*
+ if (medium->tymed == TYMED_NULL && tymed == TYMED_HGLOBAL && !pUnkForRelease)
+ medium->hGlobal = NULL;
+ */
+ // do we need return S_OK; for (tymed != TYMED_HGLOBAL) cases ?
+ /* we return S_OK here to shows that we take ownership of the data in (medium),
+ so the caller will not try to release (medium) */
+ return S_OK; // to be more compatible with Win10-Explorer and DOCs.
+ }
+ return hres;
+ } catch(...) { return E_FAIL; }
+}
+
+
+
+HRESULT CDataObject::SetData2(const FORMATETC *etc, const STGMEDIUM *medium)
+{
+ // PRF3("== CDataObject::SetData()");
+
+ HRESULT hres = S_OK;
+
+ if (etc->cfFormat == 0)
+ return DV_E_FORMATETC;
+ if (etc->tymed != TYMED_HGLOBAL)
+ return E_NOTIMPL; // DV_E_TYMED;
+ if (etc->dwAspect != DVASPECT_CONTENT)
+ return E_NOTIMPL; // DV_E_DVASPECT;
+ if (medium->tymed != TYMED_HGLOBAL)
+ return E_NOTIMPL; // DV_E_TYMED;
+
+ if (!medium->hGlobal)
+ return S_OK;
+
+ if (etc->cfFormat == m_Format_7zip_SetTargetFolder)
+ {
+ DestDirPrefix_FromTarget.Empty();
+ m_DestDirPrefix_FromTarget_WasSet = true;
+ }
+ else if (etc->cfFormat == m_Format_7zip_SetTransfer)
+ m_Transfer_WasSet = false;
+
+ const size_t size = GlobalSize(medium->hGlobal);
+ // GlobalLock() can return NULL, if memory block has a zero size
+ if (size == 0)
+ return S_OK;
+ const void *src = (const Byte *)GlobalLock(medium->hGlobal);
+ if (!src)
+ return E_FAIL;
+
+ PRF_(PrintFormat_AndData("SetData", etc->cfFormat, src, size))
+
+ if (etc->cfFormat == m_Format_7zip_SetTargetFolder)
+ {
+ /* this is our registered k_Format_7zip_SetTargetFolder format.
+ so it's call from 7-zip's CDropTarget */
+ /* 7-zip's CDropTarget calls SetData() for m_Format_7zip_SetTargetFolder
+ with (release == FALSE) */
+ const size_t num = size / sizeof(wchar_t);
+ if (size != num * sizeof(wchar_t))
+ return E_FAIL;
+ // if (num == 0) return S_OK;
+ // GlobalLock() can return NULL, if memory block has a zero-byte size
+ const wchar_t *s = (const wchar_t *)src;
+ UString &dest = DestDirPrefix_FromTarget;
+ for (size_t i = 0; i < num; i++)
+ {
+ const wchar_t c = s[i];
+ if (c == 0)
+ break;
+ dest += c;
+ }
+ // PRF_(PrintFormat_AndData("SetData", etc->cfFormat, src, size))
+ PRF3_W(DestDirPrefix_FromTarget);
+ }
+ else if (etc->cfFormat == m_Format_7zip_SetTransfer)
+ {
+ /* 7-zip's CDropTarget calls SetData() for m_Format_7zip_SetTransfer
+ with (release == FALSE) */
+ if (size < sizeof(CDataObject_SetTransfer))
+ return E_FAIL;
+ const CDataObject_SetTransfer *t = (const CDataObject_SetTransfer *)src;
+ if (!t->Check())
+ return E_FAIL;
+ m_Transfer = *t;
+ if (t->Target.FuncType != k_DragTargetMode_Leave)
+ m_Transfer_WasSet = true;
+ bool needProcessBySource = !DestDirPrefix_FromTarget.IsEmpty();
+ if (t->Target.FuncType == k_DragTargetMode_Drop_Begin)
+ {
+ if (t->Target.Cmd_Type != NDragMenu::k_Copy_Base
+ // || t->Target.Cmd_Effect != DROPEFFECT_COPY
+ )
+ needProcessBySource = false;
+ }
+ if (t->Target.FuncType == k_DragTargetMode_Drop_End)
+ {
+ if (t->Target.Flags & k_TargetFlags_MustBeProcessedBySource)
+ needProcessBySource = true;
+ else if (t->Target.Flags & k_TargetFlags_WasProcessed)
+ needProcessBySource = false;
+ }
+ DoNotProcessInTarget = needProcessBySource;
+ }
+ else
+ {
+ // SetData() from Explorer Target:
+ if (etc->cfFormat == m_Format_PerformedDropEffect)
+ {
+ m_PerformedDropEffect_WasSet = false;
+ if (size == sizeof(DWORD))
+ {
+ m_PerformedDropEffect = *(const DWORD *)src;
+ m_PerformedDropEffect_WasSet = true;
+ }
+ }
+ else if (etc->cfFormat == m_Format_LogicalPerformedDropEffect)
+ {
+ m_LogicalPerformedDropEffect_WasSet = false;
+ if (size == sizeof(DWORD))
+ {
+ m_LogicalPerformedDropEffect = *(const DWORD *)src;
+ m_LogicalPerformedDropEffect_WasSet = true;
+ }
+ }
+ else if (etc->cfFormat == m_Format_DropDescription)
+ {
+ // drop description contains only name of dest folder without full path
+ #ifdef SHOW_DEBUG_DRAG
+ if (size == sizeof(MY_DROPDESCRIPTION))
+ {
+ // const MY_DROPDESCRIPTION *s = (const MY_DROPDESCRIPTION *)src;
+ // PRF3_W(s->szMessage);
+ // PRF3_W(s->szInsert);
+ }
+ #endif
+ }
+ else if (etc->cfFormat == m_Format_TargetCLSID)
+ {
+ // it's called after call QueryContinueDrag() (keyState & MK_LBUTTON) == 0
+ // Shell File System Folder (explorer) guid: F3364BA0-65B9-11CE-A9BA-00AA004AE837
+ #ifdef SHOW_DEBUG_DRAG
+ if (size == 16)
+ {
+ PrintFormat_GUIDToStringW((const Byte *)src);
+ }
+ #endif
+ }
+ else if (etc->cfFormat == m_Format_DisableDragText)
+ {
+ // (size == 4) (UInt32 value)
+ // value==0 : if drag to folder item or folder
+ // value==1 : if drag to file or non list_view */
+ }
+ else if (
+ etc->cfFormat == m_Format_IsShowingLayered ||
+ etc->cfFormat == m_Format_IsShowingText)
+ {
+ // (size == 4) (UInt32 value) value==0 :
+ }
+ else
+ hres = DV_E_FORMATETC;
+ // hres = E_NOTIMPL; // for debug
+ // hres = DV_E_FORMATETC; // for debug
+ }
+
+ GlobalUnlock(medium->hGlobal);
+ return hres;
+}
+
+
+
+static HGLOBAL DuplicateGlobalMem(HGLOBAL srcGlobal)
+{
+ /* GlobalSize() returns 0: If the specified handle
+ is not valid or if the object has been discarded */
+ const SIZE_T size = GlobalSize(srcGlobal);
+ if (size == 0)
+ return NULL;
+ // GlobalLock() can return NULL, if memory block has a zero-byte size
+ const void *src = GlobalLock(srcGlobal);
+ if (!src)
+ return NULL;
+ HGLOBAL destGlobal = GlobalAlloc(GHND | GMEM_SHARE, size);
+ if (destGlobal)
+ {
+ void *dest = GlobalLock(destGlobal);
+ if (!dest)
+ {
+ GlobalFree(destGlobal);
+ destGlobal = NULL;
+ }
+ else
+ {
+ memcpy(dest, src, size);
+ GlobalUnlock(destGlobal);
+ }
+ }
+ GlobalUnlock(srcGlobal);
+ return destGlobal;
+}
+
+
+static bool Medium_CopyFrom(LPSTGMEDIUM medium, const void *data, size_t size)
+{
+ medium->tymed = TYMED_NULL;
+ medium->pUnkForRelease = NULL;
+ medium->hGlobal = NULL;
+ const HGLOBAL global = GlobalAlloc(GHND | GMEM_SHARE, size);
+ if (!global)
+ return false;
+ void *dest = GlobalLock(global);
+ if (!dest)
+ {
+ GlobalFree(global);
+ return false;
+ }
+ memcpy(dest, data, size);
+ GlobalUnlock(global);
+ medium->hGlobal = global;
+ medium->tymed = TYMED_HGLOBAL;
+ return true;
+}
+
+
+Z7_COMWF_B CDataObject::GetData(LPFORMATETC etc, LPSTGMEDIUM medium)
+{
+ try {
+ PRF_(PrintFormat("-- GetData", etc->cfFormat))
+
+ medium->tymed = TYMED_NULL;
+ medium->pUnkForRelease = NULL;
+ medium->hGlobal = NULL;
+
+ if (NeedCall_Copy && !Copy_WasCalled)
+ CopyFromPanelTo_Folder();
+
+ // PRF3("+ CDataObject::GetData");
+ // PrintFormat(etc->cfFormat);
+ HGLOBAL global;
+ RINOK(QueryGetData(etc))
+
+ /*
+ if (etc->cfFormat == m_Format_FileOpFlags)
+ global = m_hGlobal_FileOpFlags;
+ else if (etc->cfFormat == m_Format_PreferredDropEffect)
+ {
+ // Explorer requests PreferredDropEffect only if Move/Copy selection is possible:
+ // Shift is not pressed and Ctrl is not pressed
+ PRF3("------ CDataObject::GetData() PreferredDropEffect");
+ global = m_hGlobal_PreferredDropEffect;
+ }
+ else
+ */
+ if (etc->cfFormat == m_Etc.cfFormat) // CF_HDROP
+ global = UsePreGlobal ? m_hGlobal_HDROP_Pre : m_hGlobal_HDROP_Final;
+ else if (etc->cfFormat == m_Format_7zip_GetTransfer)
+ {
+ CDataObject_GetTransfer transfer;
+ if (m_DestDirPrefix_FromTarget_WasSet)
+ {
+ transfer.Flags |= k_SourceFlags_SetTargetFolder;
+ }
+ if (!DestDirPrefix_FromTarget.IsEmpty())
+ {
+ transfer.Flags |= k_SourceFlags_SetTargetFolder_NonEmpty;
+ }
+ if (IsTempFiles)
+ {
+ transfer.Flags |= k_SourceFlags_TempFiles;
+ transfer.Flags |= k_SourceFlags_WaitFinish;
+ transfer.Flags |= k_SourceFlags_NeedExtractOpToFs;
+ if (UsePreGlobal)
+ transfer.Flags |= k_SourceFlags_NamesAreParent;
+ }
+ else
+ transfer.Flags |= k_SourceFlags_DoNotWaitFinish;
+
+ if (IsRightButton)
+ transfer.Flags |= k_SourceFlags_RightButton;
+ else
+ transfer.Flags |= k_SourceFlags_LeftButton;
+
+ if (DoNotProcessInTarget)
+ transfer.Flags |= k_SourceFlags_DoNotProcessInTarget;
+ if (Copy_WasCalled)
+ transfer.Flags |= k_SourceFlags_Copy_WasCalled;
+
+ if (Medium_CopyFrom(medium, &transfer, sizeof(transfer)))
+ return S_OK;
+ return E_OUTOFMEMORY;
+ }
+ else
+ return DV_E_FORMATETC;
+
+ if (!global)
+ return DV_E_FORMATETC;
+ medium->tymed = m_Etc.tymed;
+ medium->hGlobal = DuplicateGlobalMem(global);
+ if (!medium->hGlobal)
+ return E_OUTOFMEMORY;
+ return S_OK;
+ } catch(...) { return E_FAIL; }
+}
+
+Z7_COMWF_B CDataObject::GetDataHere(LPFORMATETC /* etc */, LPSTGMEDIUM /* medium */)
+{
+ PRF3("CDataObject::GetDataHere()");
+ // Seems Windows doesn't call it, so we will not implement it.
+ return E_UNEXPECTED;
+}
+
+
+/*
+ IDataObject::QueryGetData() Determines whether the data object is capable of
+ rendering the data as specified. Objects attempting a paste or drop
+ operation can call this method before calling IDataObject::GetData
+ to get an indication of whether the operation may be successful.
+
+ The client of a data object calls QueryGetData to determine whether
+ passing the specified FORMATETC structure to a subsequent call to
+ IDataObject::GetData is likely to be successful.
+
+ we check Try_QueryGetData with CF_HDROP
+*/
+
+Z7_COMWF_B CDataObject::QueryGetData(LPFORMATETC etc)
+{
+ PRF3("-- CDataObject::QueryGetData()");
+ if ( etc->cfFormat == m_Etc.cfFormat // CF_HDROP
+ || etc->cfFormat == m_Format_7zip_GetTransfer
+ // || (etc->cfFormat == m_Format_FileOpFlags && (HGLOBAL)m_hGlobal_FileOpFlags)
+ // || (etc->cfFormat == m_Format_PreferredDropEffect && (HGLOBAL)m_hGlobal_PreferredDropEffect)
+ )
+ {
+ }
+ else
+ return DV_E_FORMATETC;
+ if (etc->dwAspect != m_Etc.dwAspect)
+ return DV_E_DVASPECT;
+ /* GetData(): It is possible to specify more than one medium by using the Boolean OR
+ operator, allowing the method to choose the best medium among those specified. */
+ if ((etc->tymed & m_Etc.tymed) == 0)
+ return DV_E_TYMED;
+ return S_OK;
+}
+
+Z7_COMWF_B CDataObject::EnumFormatEtc(DWORD direction, LPENUMFORMATETC FAR* enumFormatEtc)
+{
+ // we don't enumerate for DATADIR_SET. Seems it can work without it.
+ if (direction != DATADIR_GET)
+ return E_NOTIMPL;
+ // we don't enumerate for m_Format_FileOpFlags also. Seems it can work without it.
+ return CreateEnumFormatEtc(1, &m_Etc, enumFormatEtc);
+}
+
+
+
+////////////////////////////////////////////////////////
+
+class CDropSource Z7_final:
+ public IDropSource,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_1_MT(IDropSource)
+ STDMETHOD(QueryContinueDrag)(BOOL escapePressed, DWORD keyState) Z7_override;
+ STDMETHOD(GiveFeedback)(DWORD effect) Z7_override;
+
+ DWORD m_Effect;
+public:
+ CDataObject *DataObjectSpec;
+ CMyComPtr<IDataObject> DataObject;
+
+ HRESULT DragProcessing_HRESULT;
+ bool DragProcessing_WasFinished;
+
+ CDropSource():
+ m_Effect(DROPEFFECT_NONE),
+ // Panel(NULL),
+ DragProcessing_HRESULT(S_OK),
+ DragProcessing_WasFinished(false)
+ {}
+};
+
+// static bool g_Debug = 0;
+
+
+Z7_COMWF_B CDropSource::QueryContinueDrag(BOOL escapePressed, DWORD keyState)
+{
+ // try {
+
+ /* Determines whether a drag-and-drop operation should be continued, canceled, or completed.
+ escapePressed : Indicates whether the Esc key has been pressed
+ since the previous call to QueryContinueDrag
+ or to DoDragDrop if this is the first call to QueryContinueDrag:
+ TRUE : the end user has pressed the escape key;
+ FALSE : it has not been pressed.
+ keyState : The current state of the keyboard modifier keys on the keyboard.
+ Possible values can be a combination of any of the flags:
+ MK_CONTROL, MK_SHIFT, MK_ALT, MK_BUTTON, MK_LBUTTON, MK_MBUTTON, and MK_RBUTTON.
+ */
+ #ifdef SHOW_DEBUG_DRAG
+ {
+ AString s ("CDropSource::QueryContinueDrag()");
+ s.Add_Space();
+ s += "keystate=";
+ s.Add_UInt32(keyState);
+ PRF4(s);
+ }
+ #endif
+
+ /*
+ if ((keyState & MK_LBUTTON) == 0)
+ {
+ // PRF4("CDropSource::QueryContinueDrag() (keyState & MK_LBUTTON) == 0");
+ g_Debug = true;
+ }
+ else
+ {
+ // PRF4("CDropSource::QueryContinueDrag() (keyState & MK_LBUTTON) != 0");
+ }
+ */
+
+ if (escapePressed)
+ {
+ // The drag operation should be canceled with no drop operation occurring.
+ DragProcessing_WasFinished = true;
+ DragProcessing_HRESULT = DRAGDROP_S_CANCEL;
+ return DRAGDROP_S_CANCEL;
+ }
+
+ if (DragProcessing_WasFinished)
+ return DragProcessing_HRESULT;
+
+ if ((keyState & MK_RBUTTON) != 0)
+ {
+ if (!DataObjectSpec->IsRightButton)
+ {
+ DragProcessing_WasFinished = true;
+ DragProcessing_HRESULT = DRAGDROP_S_CANCEL;
+ return DRAGDROP_S_CANCEL;
+ }
+ return S_OK;
+ }
+
+ if ((keyState & MK_LBUTTON) != 0)
+ {
+ if (DataObjectSpec->IsRightButton)
+ {
+ DragProcessing_WasFinished = true;
+ DragProcessing_HRESULT = DRAGDROP_S_CANCEL;
+ return DRAGDROP_S_CANCEL;
+ }
+ /* The drag operation should continue. This result occurs if no errors are detected,
+ the mouse button starting the drag-and-drop operation has not been released,
+ and the Esc key has not been detected. */
+ return S_OK;
+ }
+ {
+ // the mouse button starting the drag-and-drop operation has been released.
+
+ /* Win10 probably calls DragOver()/GiveFeedback() just before LBUTTON releasing.
+ so m_Effect is effect returned by DropTarget::DragOver()
+ just before LBUTTON releasing.
+ So here we can use Effect sent to last GiveFeedback() */
+
+ if (m_Effect == DROPEFFECT_NONE)
+ {
+ DragProcessing_WasFinished = true;
+ DragProcessing_HRESULT = DRAGDROP_S_CANCEL;
+ // Drop target cannot accept the data. So we cancel drag and drop
+ // maybe return DRAGDROP_S_DROP also OK here ?
+ // return DRAGDROP_S_DROP; // for debug
+ return DRAGDROP_S_CANCEL;
+ }
+
+ // we switch to real names for items that will be created in temp folder
+ DataObjectSpec->UsePreGlobal = false;
+ DataObjectSpec->Copy_HRESULT = S_OK;
+ // MoveMode = (((keyState & MK_SHIFT) != 0) && MoveIsAllowed);
+ /*
+ if (DataObjectSpec->IsRightButton)
+ return DRAGDROP_S_DROP;
+ */
+
+ if (DataObjectSpec->IsTempFiles)
+ {
+ if (!DataObjectSpec->DestDirPrefix_FromTarget.IsEmpty())
+ {
+ /* we know the destination Path.
+ So we can copy or extract items later in Source with simpler code. */
+ DataObjectSpec->DoNotProcessInTarget = true;
+ // return DRAGDROP_S_CANCEL;
+ }
+ else
+ {
+ DataObjectSpec->NeedCall_Copy = true;
+ /*
+ if (Copy_HRESULT != S_OK || !Messages.IsEmpty())
+ {
+ DragProcessing_WasFinished = true;
+ DragProcessing_HRESULT = DRAGDROP_S_CANCEL;
+ return DRAGDROP_S_CANCEL;
+ }
+ */
+ }
+ }
+ DragProcessing_HRESULT = DRAGDROP_S_DROP;
+ DragProcessing_WasFinished = true;
+ return DRAGDROP_S_DROP;
+ }
+ // } catch(...) { return E_FAIL; }
+}
+
+
+Z7_COMWF_B CDropSource::GiveFeedback(DWORD effect)
+{
+ // PRF3("CDropSource::GiveFeedback");
+ /* Enables a source application to give visual feedback to the end user
+ during a drag-and-drop operation by providing the DoDragDrop function
+ with an enumeration value specifying the visual effect.
+ in (effect):
+ The DROPEFFECT value returned by the most recent call to
+ IDropTarget::DragEnter,
+ IDropTarget::DragOver,
+ or DROPEFFECT_NONE after IDropTarget::DragLeave.
+ 0: DROPEFFECT_NONE
+ 1: DROPEFFECT_COPY
+ 2: DROPEFFECT_MOVE
+ 4: DROPEFFECT_LINK
+ 0x80000000: DROPEFFECT_SCROLL
+ The dwEffect parameter can include DROPEFFECT_SCROLL, indicating that the
+ source should put up the drag-scrolling variation of the appropriate pointer.
+ */
+ m_Effect = effect;
+
+ #ifdef SHOW_DEBUG_DRAG
+ AString w ("GiveFeedback effect=");
+ if (effect & DROPEFFECT_SCROLL)
+ w += " SCROLL ";
+ w.Add_UInt32(effect & ~DROPEFFECT_SCROLL);
+ // if (g_Debug)
+ PRF4(w);
+ #endif
+
+ /* S_OK : no special drag and drop cursors.
+ Maybe it's for case where we created custom custom cursors.
+ DRAGDROP_S_USEDEFAULTCURSORS: Indicates successful completion of the method,
+ and requests OLE to update the cursor using the OLE-provided default cursors. */
+ // return S_OK; // for debug
+ return DRAGDROP_S_USEDEFAULTCURSORS;
+}
+
+
+
+/*
+static bool Global_SetUInt32(NMemory::CGlobal &hg, const UInt32 v)
+{
+ if (!hg.Alloc(GHND | GMEM_SHARE, sizeof(v)))
+ return false;
+ NMemory::CGlobalLock dropLock(hg);
+ *(UInt32 *)dropLock.GetPointer() = v;
+ return true;
+}
+*/
+
+static bool CopyNamesToHGlobal(NMemory::CGlobal &hgDrop, const UStringVector &names)
+{
+ size_t totalLen = 1;
+
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ AStringVector namesA;
+ unsigned i;
+ for (i = 0; i < names.Size(); i++)
+ namesA.Add(GetSystemString(names[i]));
+ for (i = 0; i < namesA.Size(); i++)
+ totalLen += namesA[i].Len() + 1;
+
+ if (!hgDrop.Alloc(GHND | GMEM_SHARE, totalLen * sizeof(CHAR) + sizeof(DROPFILES)))
+ return false;
+
+ NMemory::CGlobalLock dropLock(hgDrop);
+ DROPFILES *dropFiles = (DROPFILES *)dropLock.GetPointer();
+ if (!dropFiles)
+ return false;
+ dropFiles->fNC = FALSE;
+ dropFiles->pt.x = 0;
+ dropFiles->pt.y = 0;
+ dropFiles->pFiles = sizeof(DROPFILES);
+ dropFiles->fWide = FALSE;
+ CHAR *p = (CHAR *) (void *) ((BYTE *)dropFiles + sizeof(DROPFILES));
+ for (i = 0; i < namesA.Size(); i++)
+ {
+ const AString &s = namesA[i];
+ const unsigned fullLen = s.Len() + 1;
+ MyStringCopy(p, (const char *)s);
+ p += fullLen;
+ totalLen -= fullLen;
+ }
+ *p = 0;
+ }
+ else
+ #endif
+ {
+ unsigned i;
+ for (i = 0; i < names.Size(); i++)
+ totalLen += names[i].Len() + 1;
+
+ if (!hgDrop.Alloc(GHND | GMEM_SHARE, totalLen * sizeof(WCHAR) + sizeof(DROPFILES)))
+ return false;
+
+ NMemory::CGlobalLock dropLock(hgDrop);
+ DROPFILES *dropFiles = (DROPFILES *)dropLock.GetPointer();
+ if (!dropFiles)
+ return false;
+ /* fNC:
+ TRUE : pt specifies the screen coordinates of a point in a window's nonclient area.
+ FALSE : pt specifies the client coordinates of a point in the client area.
+ */
+ dropFiles->fNC = FALSE;
+ dropFiles->pt.x = 0;
+ dropFiles->pt.y = 0;
+ dropFiles->pFiles = sizeof(DROPFILES);
+ dropFiles->fWide = TRUE;
+ WCHAR *p = (WCHAR *) (void *) ((BYTE *)dropFiles + sizeof(DROPFILES));
+ for (i = 0; i < names.Size(); i++)
+ {
+ const UString &s = names[i];
+ const unsigned fullLen = s.Len() + 1;
+ MyStringCopy(p, (const WCHAR *)s);
+ p += fullLen;
+ totalLen -= fullLen;
+ }
+ *p = 0;
+ }
+ // if (totalLen != 1) return false;
+ return true;
+}
+
+
+void CPanel::OnDrag(LPNMLISTVIEW /* nmListView */, bool isRightButton)
+{
+ PRF("CPanel::OnDrag");
+ if (!DoesItSupportOperations())
+ return;
+
+ CDisableTimerProcessing disableTimerProcessing2(*this);
+
+ CRecordVector<UInt32> indices;
+ Get_ItemIndices_Operated(indices);
+ if (indices.Size() == 0)
+ return;
+
+ // CSelectedState selState;
+ // SaveSelectedState(selState);
+
+ const bool isFSFolder = IsFSFolder();
+ // why we don't allow drag with rightButton from archive?
+ if (!isFSFolder && isRightButton)
+ return;
+
+ UString dirPrefix;
+ CTempDir tempDirectory;
+
+ CDataObject *dataObjectSpec = new CDataObject;
+ CMyComPtr<IDataObject> dataObject = dataObjectSpec;
+ dataObjectSpec->IsRightButton = isRightButton;
+
+ {
+ /* we can change confirmation mode and another options.
+ Explorer target requests that FILEOP_FLAGS value. */
+ /*
+ const FILEOP_FLAGS fopFlags =
+ FOF_NOCONFIRMATION
+ | FOF_NOCONFIRMMKDIR
+ | FOF_NOERRORUI
+ | FOF_SILENT;
+ // | FOF_SIMPLEPROGRESS; // it doesn't work as expected in Win10
+ Global_SetUInt32(dataObjectSpec->m_hGlobal_FileOpFlags, fopFlags);
+ // dataObjectSpec->m_hGlobal_FileOpFlags.Free(); // for debug : disable these options
+ */
+ }
+ {
+ /* we can change Preferred DropEffect.
+ Explorer target requests that FILEOP_FLAGS value. */
+ /*
+ const DWORD effect = DROPEFFECT_MOVE; // DROPEFFECT_COPY;
+ Global_SetUInt32(dataObjectSpec->m_hGlobal_PreferredDropEffect, effect);
+ */
+ }
+ if (isFSFolder)
+ {
+ dirPrefix = GetFsPath(); // why this in 22.01 ?
+ dataObjectSpec->UsePreGlobal = false;
+ // dataObjectSpec->IsTempFiles = false;
+ }
+ else
+ {
+ if (!tempDirectory.Create(kTempDirPrefix))
+ {
+ MessageBox_Error(L"Can't create temp folder");
+ return;
+ }
+ dirPrefix = fs2us(tempDirectory.GetPath());
+ {
+ UStringVector names;
+ names.Add(dirPrefix);
+ dataObjectSpec->IsTempFiles = true;
+ dataObjectSpec->UsePreGlobal = true;
+ if (!CopyNamesToHGlobal(dataObjectSpec->m_hGlobal_HDROP_Pre, names))
+ return;
+ }
+ NFile::NName::NormalizeDirPathPrefix(dirPrefix);
+ /*
+ {
+ FString path2 = dirPrefix;
+ path2 += "1.txt";
+ CopyFileW(L"C:\\1\\1.txt", path2, FALSE);
+ }
+ */
+ }
+
+ {
+ UStringVector names;
+ // names variable is USED for drag and drop from 7-zip to Explorer or to 7-zip archive folder.
+ // names variable is NOT USED for drag and drop from 7-zip to 7-zip File System folder.
+ FOR_VECTOR (i, indices)
+ {
+ const UInt32 index = indices[i];
+ UString s;
+ if (isFSFolder)
+ s = GetItemRelPath(index);
+ else
+ {
+ s = GetItemName(index);
+ /*
+ // We use (keepAndReplaceEmptyPrefixes = true) in CAgentFolder::Extract
+ // So the following code is not required.
+ // Maybe we also can change IFolder interface and send some flag also.
+ if (s.IsEmpty())
+ {
+ // Correct_FsFile_Name("") returns "_".
+ // If extracting code removes empty folder prefixes from path (as it was in old version),
+ // Explorer can't find "_" folder in temp folder.
+ // We can ask Explorer to copy parent temp folder "7zE" instead.
+ names.Clear();
+ names.Add(dirPrefix2);
+ break;
+ }
+ */
+ s = Get_Correct_FsFile_Name(s);
+ }
+ names.Add(dirPrefix + s);
+ }
+ if (!CopyNamesToHGlobal(dataObjectSpec->m_hGlobal_HDROP_Final, names))
+ return;
+ }
+
+ CDropSource *dropSourceSpec = new CDropSource;
+ CMyComPtr<IDropSource> dropSource = dropSourceSpec;
+ dataObjectSpec->Panel = this;
+ dataObjectSpec->Indices = indices;
+ dataObjectSpec->SrcDirPrefix_Temp = dirPrefix;
+
+ dropSourceSpec->DataObjectSpec = dataObjectSpec;
+ dropSourceSpec->DataObject = dataObjectSpec;
+
+
+ /*
+ CTime - file creation timestamp.
+ There are two operations in Windows with Drag and Drop:
+ COPY_OPERATION : icon with Plus sign : CTime will be set as current_time.
+ MOVE_OPERATION : icon without Plus sign : CTime will be preserved.
+
+ Note: if we call DoDragDrop() with (effectsOK = DROPEFFECT_MOVE), then
+ it will use MOVE_OPERATION and CTime will be preserved.
+ But MoveFile() function doesn't preserve CTime, if different volumes are used.
+ Why it's so?
+ Does DoDragDrop() use some another function (not MoveFile())?
+
+ if (effectsOK == DROPEFFECT_COPY) it works as COPY_OPERATION
+
+ if (effectsOK == DROPEFFECT_MOVE) drag works as MOVE_OPERATION
+
+ if (effectsOK == (DROPEFFECT_COPY | DROPEFFECT_MOVE))
+ {
+ if we drag file to same volume, then Windows suggests:
+ CTRL - COPY_OPERATION
+ [default] - MOVE_OPERATION
+
+ if we drag file to another volume, then Windows suggests
+ [default] - COPY_OPERATION
+ SHIFT - MOVE_OPERATION
+ }
+
+ We want to use MOVE_OPERATION for extracting from archive (open in 7-Zip) to Explorer:
+ It has the following advantages:
+ 1) it uses fast MOVE_OPERATION instead of slow COPY_OPERATION and DELETE, if same volume.
+ 2) it preserves CTime
+
+ Some another programs support only COPY_OPERATION.
+ So we can use (DROPEFFECT_COPY | DROPEFFECT_MOVE)
+
+ Also another program can return from DoDragDrop() before
+ files using. But we delete temp folder after DoDragDrop(),
+ and another program can't open input files in that case.
+
+ We create objects:
+ IDropSource *dropSource
+ IDataObject *dataObject
+ if DropTarget is 7-Zip window, then 7-Zip's
+ IDropTarget::DragOver() sets DestDirPrefix_FromTarget in IDataObject.
+ and
+ IDropSource::QueryContinueDrag() sets DoNotProcessInTarget, if DestDirPrefix_FromTarget is not empty.
+ So we can detect destination path after DoDragDrop().
+ Now we don't know any good way to detect destination path for D&D to Explorer.
+ */
+
+ /*
+ DWORD effectsOK = DROPEFFECT_COPY;
+ if (moveIsAllowed)
+ effectsOK |= DROPEFFECT_MOVE;
+ */
+ const bool moveIsAllowed = isFSFolder;
+ _panelCallback->DragBegin();
+ PRF("=== DoDragDrop()");
+ DWORD effect = 0;
+ // 18.04: was changed
+ const DWORD effectsOK = DROPEFFECT_MOVE | DROPEFFECT_COPY;
+ // effectsOK |= (1 << 8); // for debug
+ HRESULT res = ::DoDragDrop(dataObject, dropSource, effectsOK, &effect);
+ PRF("=== After DoDragDrop()");
+ _panelCallback->DragEnd();
+
+ /*
+ Win10 drag and drop to Explorer:
+ DoDragDrop() output variables:
+ for MOVE operation:
+ {
+ effect == DROPEFFECT_NONE;
+ dropSourceSpec->m_PerformedDropEffect == DROPEFFECT_MOVE;
+ }
+ for COPY operation:
+ {
+ effect == DROPEFFECT_COPY;
+ dropSourceSpec->m_PerformedDropEffect == DROPEFFECT_COPY;
+ }
+ DOCs: The source inspects the two values that can be returned by the target.
+ If both are set to DROPEFFECT_MOVE, it completes the unoptimized move
+ by deleting the original data. Otherwise, the target did an optimized
+ move and the original data has been deleted.
+
+ We didn't see "unoptimized move" case (two values of DROPEFFECT_MOVE),
+ where we still need to delete source files.
+ So we don't delete files after DoDragDrop().
+
+ Also DOCs say for "optimized move":
+ The target also calls the data object's IDataObject::SetData method and passes
+ it a CFSTR_PERFORMEDDROPEFFECT format identifier set to DROPEFFECT_NONE.
+ but actually in Win10 we always have
+ (dropSourceSpec->m_PerformedDropEffect == DROPEFFECT_MOVE)
+ for any MOVE operation.
+ */
+
+ const bool canceled = (res == DRAGDROP_S_CANCEL);
+
+ CDisableNotify disableNotify(*this);
+
+ if (res == DRAGDROP_S_DROP)
+ {
+ /* DRAGDROP_S_DROP is returned. It means that
+ - IDropTarget::Drop() was called,
+ - IDropTarget::Drop() returned (ret_code >= 0)
+ */
+ res = dataObjectSpec->Copy_HRESULT;
+ bool need_Process = dataObjectSpec->DoNotProcessInTarget;
+ if (dataObjectSpec->m_Transfer_WasSet)
+ {
+ if (dataObjectSpec->m_Transfer.Target.FuncType == k_DragTargetMode_Drop_End)
+ {
+ if (dataObjectSpec->m_Transfer.Target.Flags & k_TargetFlags_MustBeProcessedBySource)
+ need_Process = true;
+ }
+ }
+
+ if (need_Process)
+ if (!dataObjectSpec->DestDirPrefix_FromTarget.IsEmpty())
+ {
+ if (!NFile::NName::IsAltStreamPrefixWithColon(dataObjectSpec->DestDirPrefix_FromTarget))
+ NFile::NName::NormalizeDirPathPrefix(dataObjectSpec->DestDirPrefix_FromTarget);
+ CCopyToOptions options;
+ options.folder = dataObjectSpec->DestDirPrefix_FromTarget;
+ // if MOVE is not allowed, we just use COPY operation
+ /* it was 7-zip's Target that set non-empty dataObjectSpec->DestDirPrefix_FromTarget.
+ it means that target didn't completed operation,
+ and we can use (effect) value returned by target via DoDragDrop().
+ as indicator of type of operation
+ */
+ // options.moveMode = (moveIsAllowed && effect == DROPEFFECT_MOVE) // before v23.00:
+ options.moveMode = moveIsAllowed;
+ if (moveIsAllowed)
+ {
+ if (dataObjectSpec->m_Transfer_WasSet)
+ options.moveMode = (
+ dataObjectSpec->m_Transfer.Target.Cmd_Effect == DROPEFFECT_MOVE);
+ else
+ options.moveMode = (effect == DROPEFFECT_MOVE);
+ // we expect (DROPEFFECT_MOVE) as indicator of move operation for Drag&Drop MOVE ver 22.01.
+ }
+ res = CopyTo(options, indices, &dataObjectSpec->Messages);
+ }
+ /*
+ if (effect & DROPEFFECT_MOVE)
+ RefreshListCtrl(selState);
+ */
+ }
+ else
+ {
+ // we ignore E_UNEXPECTED that is returned if we drag file to printer
+ if (res != DRAGDROP_S_CANCEL
+ && res != S_OK
+ && res != E_UNEXPECTED)
+ MessageBox_Error_HRESULT(res);
+ res = dataObjectSpec->Copy_HRESULT;
+ }
+
+ if (!dataObjectSpec->Messages.IsEmpty())
+ {
+ CMessagesDialog messagesDialog;
+ messagesDialog.Messages = &dataObjectSpec->Messages;
+ messagesDialog.Create((*this));
+ }
+
+ if (res != S_OK && res != E_ABORT)
+ {
+ // we restore Notify before MessageBox_Error_HRESULT. So we will see files selection
+ disableNotify.Restore();
+ // SetFocusToList();
+ MessageBox_Error_HRESULT(res);
+ }
+ if (res == S_OK && dataObjectSpec->Messages.IsEmpty() && !canceled)
+ KillSelection();
+}
+
+
+
+
+
+CDropTarget::CDropTarget():
+ m_IsRightButton(false),
+ m_GetTransfer_WasSuccess(false),
+ m_DropIsAllowed(false),
+ m_PanelDropIsAllowed(false),
+ // m_DropHighlighted_SelectionIndex(-1),
+ // m_SubFolderIndex(-1),
+ m_Panel(NULL),
+ m_IsAppTarget(false),
+ m_TargetPath_WasSent_ToDataObject(false),
+ m_TargetPath_NonEmpty_WasSent_ToDataObject(false),
+ m_Transfer_WasSent_ToDataObject(false),
+ App(NULL),
+ SrcPanelIndex(-1),
+ TargetPanelIndex(-1)
+{
+ m_Format_7zip_SetTargetFolder = RegisterClipboardFormat(k_Format_7zip_SetTargetFolder);
+ m_Format_7zip_SetTransfer = RegisterClipboardFormat(k_Format_7zip_SetTransfer);
+ m_Format_7zip_GetTransfer = RegisterClipboardFormat(k_Format_7zip_GetTransfer);
+
+ m_ProcessId = GetCurrentProcessId();
+ // m_TransactionId = ((UInt64)m_ProcessId << 32) + 1;
+ // ClearState();
+}
+
+// clear internal state
+void CDropTarget::ClearState()
+{
+ m_DataObject.Release();
+ m_SourcePaths.Clear();
+
+ m_IsRightButton = false;
+
+ m_GetTransfer_WasSuccess = false;
+ m_DropIsAllowed = false;
+
+ m_PanelDropIsAllowed = false;
+ // m_SubFolderIndex = -1;
+ // m_DropHighlighted_SubFolderName.Empty();
+ m_Panel = NULL;
+ m_IsAppTarget = false;
+ m_TargetPath_WasSent_ToDataObject = false;
+ m_TargetPath_NonEmpty_WasSent_ToDataObject = false;
+ m_Transfer_WasSent_ToDataObject = false;
+}
+
+/*
+ IDataObject::QueryGetData() Determines whether the data object is capable of
+ rendering the data as specified. Objects attempting a paste or drop
+ operation can call this method before calling IDataObject::GetData
+ to get an indication of whether the operation may be successful.
+
+ The client of a data object calls QueryGetData to determine whether
+ passing the specified FORMATETC structure to a subsequent call to
+ IDataObject::GetData is likely to be successful.
+
+ We check Try_QueryGetData with CF_HDROP
+*/
+/*
+void CDropTarget::Try_QueryGetData(IDataObject *dataObject)
+{
+ FORMATETC etc = { CF_HDROP, 0, DVASPECT_CONTENT, -1, TYMED_HGLOBAL };
+ m_DropIsAllowed = (dataObject->QueryGetData(&etc) == S_OK);
+}
+*/
+
+static void ListView_SetItemState_DropHighlighted(
+ NControl::CListView &listView, int index, bool highlighted)
+{
+ // LVIS_DROPHILITED : The item is highlighted as a drag-and-drop target
+ /*
+ LVITEM item;
+ item.mask = LVIF_STATE;
+ item.iItem = index;
+ item.iSubItem = 0;
+ item.state = enable ? LVIS_DROPHILITED : 0;
+ item.stateMask = LVIS_DROPHILITED;
+ item.pszText = NULL;
+ listView.SetItem(&item);
+ */
+ listView.SetItemState(index, highlighted ? LVIS_DROPHILITED : 0, LVIS_DROPHILITED);
+}
+
+// Removes DropHighlighted state in ListView item, if it was set before
+void CDropTarget::RemoveSelection()
+{
+ if (m_Panel)
+ {
+ m_Panel->m_DropHighlighted_SubFolderName.Empty();
+ if (m_Panel->m_DropHighlighted_SelectionIndex >= 0)
+ {
+ ListView_SetItemState_DropHighlighted(m_Panel->_listView,
+ m_Panel->m_DropHighlighted_SelectionIndex, false);
+ m_Panel->m_DropHighlighted_SelectionIndex = -1;
+ }
+ }
+}
+
+#ifdef UNDER_CE
+#define ChildWindowFromPointEx(hwndParent, pt, uFlags) ChildWindowFromPoint(hwndParent, pt)
+#endif
+
+
+/*
+ PositionCursor() function sets m_Panel under cursor drop, and
+ m_SubFolderIndex/m_DropHighlighted_SubFolderName, if drop to some folder in Panel list.
+*/
+/*
+PositionCursor() uses as input variables:
+ m_DropIsAllowed must be set before PositionCursor()
+ if (m_DropHighlighted_SelectionIndex >= 0 && m_Panel) it uses m_Panel and removes previous selection
+PositionCursor() sets
+ m_PanelDropIsAllowed
+ m_Panel
+ m_IsAppTarget
+ m_SubFolderIndex
+ m_DropHighlighted_SubFolderName
+ m_DropHighlighted_SelectionIndex
+*/
+void CDropTarget::PositionCursor(const POINTL &ptl)
+{
+ RemoveSelection();
+
+ // m_SubFolderIndex = -1;
+ // m_DropHighlighted_SubFolderName.Empty();
+ m_IsAppTarget = true;
+ m_Panel = NULL;
+ m_PanelDropIsAllowed = false;
+
+ if (!m_DropIsAllowed)
+ return;
+
+ POINT pt;
+ pt.x = ptl.x;
+ pt.y = ptl.y;
+ {
+ POINT pt2 = pt;
+ if (App->_window.ScreenToClient(&pt2))
+ for (unsigned i = 0; i < kNumPanelsMax; i++)
+ if (App->IsPanelVisible(i))
+ {
+ CPanel *panel = &App->Panels[i];
+ if (panel->IsEnabled())
+ if (::ChildWindowFromPointEx(App->_window, pt2,
+ CWP_SKIPINVISIBLE | CWP_SKIPDISABLED) == (HWND)*panel)
+ {
+ m_Panel = panel;
+ m_IsAppTarget = false;
+ if ((int)i == SrcPanelIndex)
+ return; // we don't allow to drop to source panel
+ break;
+ }
+ }
+ }
+
+ m_PanelDropIsAllowed = true;
+
+ if (!m_Panel)
+ {
+ if (TargetPanelIndex >= 0)
+ m_Panel = &App->Panels[TargetPanelIndex];
+ // we don't need to find item in panel
+ return;
+ }
+
+ // we will try to find and highlight drop folder item in listView under cursor
+ /*
+ m_PanelDropIsAllowed = m_Panel->DoesItSupportOperations();
+ if (!m_PanelDropIsAllowed)
+ return;
+ */
+ /* now we don't allow drop to subfolder under cursor, if dest panel is archive.
+ Another code must be fixed for that case, where we must use m_SubFolderIndex/m_DropHighlighted_SubFolderName */
+ if (!m_Panel->IsFsOrPureDrivesFolder())
+ return;
+
+ if (::WindowFromPoint(pt) != (HWND)m_Panel->_listView)
+ return;
+
+ LVHITTESTINFO info;
+ m_Panel->_listView.ScreenToClient(&pt);
+ info.pt = pt;
+ const int index = ListView_HitTest(m_Panel->_listView, &info);
+ if (index < 0)
+ return;
+ const unsigned realIndex = m_Panel->GetRealItemIndex(index);
+ if (realIndex == kParentIndex)
+ return;
+ if (!m_Panel->IsItem_Folder(realIndex))
+ return;
+ // m_SubFolderIndex = (int)realIndex;
+ m_Panel->m_DropHighlighted_SubFolderName = m_Panel->GetItemName(realIndex);
+ ListView_SetItemState_DropHighlighted(m_Panel->_listView, index, true);
+ m_Panel->m_DropHighlighted_SelectionIndex = index;
+}
+
+
+/* returns true, if !m_IsAppTarget
+ and target is FS folder or altStream folder
+*/
+
+UInt32 CDropTarget::GetFolderType() const
+{
+ if (m_IsAppTarget || !m_Panel)
+ return k_FolderType_None;
+ if (m_Panel->IsFSFolder() ||
+ (m_Panel->IsFSDrivesFolder()
+ && m_Panel->m_DropHighlighted_SelectionIndex >= 0))
+ return k_FolderType_Fs;
+ if (m_Panel->IsAltStreamsFolder())
+ return k_FolderType_AltStreams;
+ if (m_Panel->IsArcFolder())
+ return k_FolderType_Archive;
+ return k_FolderType_Unknown;
+}
+
+bool CDropTarget::IsFsFolderPath() const
+{
+ if (m_IsAppTarget || !m_Panel)
+ return false;
+ if (m_Panel->IsFSFolder())
+ return true;
+ if (m_Panel->IsAltStreamsFolder())
+ return true;
+ return m_Panel->IsFSDrivesFolder() &&
+ m_Panel->m_DropHighlighted_SelectionIndex >= 0;
+}
+
+
+#define INIT_FORMATETC_HGLOBAL(type) { (type), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }
+
+static bool DataObject_GetData_GetTransfer(IDataObject *dataObject,
+ UINT a_Format_7zip_GetTransfer, CDataObject_GetTransfer &transfer)
+{
+ FORMATETC etc = INIT_FORMATETC_HGLOBAL((CLIPFORMAT)a_Format_7zip_GetTransfer);
+ NCOM::CStgMedium medium;
+ const HRESULT res = dataObject->GetData(&etc, &medium);
+ if (res != S_OK)
+ return false;
+ if (medium.tymed != TYMED_HGLOBAL)
+ return false;
+ const size_t size = GlobalSize(medium.hGlobal);
+ if (size < sizeof(transfer))
+ return false;
+ NMemory::CGlobalLock dropLock(medium.hGlobal);
+ const CDataObject_GetTransfer *t = (const CDataObject_GetTransfer *)dropLock.GetPointer();
+ if (!t)
+ return false;
+ if (!t->Check()) // isSetData
+ return false;
+ transfer = *t;
+ return true;
+}
+
+/*
+ returns true, if all m_SourcePaths[] items are same drive
+ as destination drop path in m_Panel
+*/
+bool CDropTarget::IsItSameDrive() const
+{
+ if (!m_Panel)
+ return false;
+ if (!IsFsFolderPath())
+ return false;
+
+ UString drive;
+
+ if (m_Panel->IsFSFolder())
+ {
+ drive = m_Panel->GetDriveOrNetworkPrefix();
+ if (drive.IsEmpty())
+ return false;
+ }
+ else if (m_Panel->IsFSDrivesFolder()
+ && m_Panel->m_DropHighlighted_SelectionIndex >= 0)
+ {
+ drive = m_Panel->m_DropHighlighted_SubFolderName;
+ drive.Add_PathSepar();
+ }
+ else
+ return false;
+
+ if (m_SourcePaths.Size() == 0)
+ return false;
+
+ FOR_VECTOR (i, m_SourcePaths)
+ {
+ if (!m_SourcePaths[i].IsPrefixedBy_NoCase(drive))
+ return false;
+ }
+ return true;
+}
+
+
+/*
+ There are 2 different actions, when we drag to 7-Zip:
+ 1) if target panel is "7-Zip" FS and any of the 2 cases:
+ - Drag from any non "7-Zip" program;
+ or
+ - Drag from "7-Zip" to non-panel area of "7-Zip".
+ We want to create new archive for that operation with "Add to Archive" window.
+ 2) all another operations work as usual file COPY/MOVE
+ - Drag from "7-Zip" FS to "7-Zip" FS.
+ COPY/MOVE are supported.
+ - Drag to open archive in 7-Zip.
+ We want to update archive.
+ We replace COPY to MOVE.
+ - Drag from "7-Zip" archive to "7-Zip" FS.
+ We replace COPY to MOVE.
+*/
+
+// we try to repeat Explorer's effects.
+// out: 0 - means that use default effect
+static DWORD GetEffect_ForKeys(DWORD keyState)
+{
+ if (keyState & MK_CONTROL)
+ {
+ if (keyState & MK_ALT)
+ return 0;
+ if (keyState & MK_SHIFT)
+ return DROPEFFECT_LINK; // CONTROL + SHIFT
+ return DROPEFFECT_COPY; // CONTROL
+ }
+ // no CONTROL
+ if (keyState & MK_SHIFT)
+ {
+ if (keyState & MK_ALT)
+ return 0;
+ return DROPEFFECT_MOVE; // SHIFT
+ }
+ // no CONTROL, no SHIFT
+ if (keyState & MK_ALT)
+ return DROPEFFECT_LINK; // ALT
+ return 0;
+}
+
+
+/* GetEffect() uses m_TargetPath_WasSentToDataObject
+ to disale MOVE operation, if Source is not 7-Zip
+*/
+DWORD CDropTarget::GetEffect(DWORD keyState, POINTL /* pt */, DWORD allowedEffect) const
+{
+ // (DROPEFFECT_NONE == 0)
+ if (!m_DropIsAllowed || !m_PanelDropIsAllowed)
+ return 0;
+ if (!IsFsFolderPath() || !m_TargetPath_WasSent_ToDataObject)
+ {
+ // we don't allow MOVE, if Target is archive or Source is not 7-Zip
+ // disabled for debug:
+ // allowedEffect &= ~DROPEFFECT_MOVE;
+ }
+ DWORD effect;
+ {
+ effect = GetEffect_ForKeys(keyState);
+ if (effect == DROPEFFECT_LINK)
+ return 0;
+ effect &= allowedEffect;
+ }
+ if (effect == 0)
+ {
+ if (allowedEffect & DROPEFFECT_COPY)
+ effect = DROPEFFECT_COPY;
+ if (allowedEffect & DROPEFFECT_MOVE)
+ {
+ /* MOVE operation can be optimized. So MOVE is preferred way
+ for default action, if Source and Target are at same drive */
+ if (IsItSameDrive())
+ effect = DROPEFFECT_MOVE;
+ }
+ }
+ return effect;
+}
+
+
+/* returns:
+ - target folder path prefix, if target is FS folder
+ - empty string, if target is not FS folder
+*/
+UString CDropTarget::GetTargetPath() const
+{
+ if (!IsFsFolderPath())
+ return UString();
+ UString path = m_Panel->GetFsPath();
+ if (/* m_SubFolderIndex >= 0 && */
+ !m_Panel->m_DropHighlighted_SubFolderName.IsEmpty())
+ {
+ path += m_Panel->m_DropHighlighted_SubFolderName;
+ path.Add_PathSepar();
+ }
+ return path;
+}
+
+
+/*
+if IDropSource is Win10-Explorer
+--------------------------------
+ As in MS DOCs:
+ The source inspects the two (effect) values that can be returned by the target:
+ 1) SetData(CFSTR_PERFORMEDDROPEFFECT)
+ 2) returned value (*effect) by
+ CDropTarget::Drop(IDataObject *dataObject, DWORD keyState,
+ POINTL pt, DWORD *effect)
+ If both are set to DROPEFFECT_MOVE, Explorer completes the unoptimized move by deleting
+ the original data.
+ // Otherwise, the target did an optimized move and the original data has been deleted.
+*/
+
+
+/*
+ Send targetPath from target to dataObject (to Source)
+ input: set (enablePath = false) to send empty path
+ returns true, if SetData() returns S_OK : (source is 7-zip)
+ returns false, if SetData() doesn't return S_OK : (source is Explorer)
+*/
+bool CDropTarget::SendToSource_TargetPath_enable(IDataObject *dataObject, bool enablePath)
+{
+ m_TargetPath_NonEmpty_WasSent_ToDataObject = false;
+ UString path;
+ if (enablePath)
+ path = GetTargetPath();
+ PRF("CDropTarget::SetPath");
+ PRF_W(path);
+ if (!dataObject || m_Format_7zip_SetTargetFolder == 0)
+ return false;
+ FORMATETC etc = INIT_FORMATETC_HGLOBAL((CLIPFORMAT)m_Format_7zip_SetTargetFolder);
+ STGMEDIUM medium;
+ medium.tymed = etc.tymed;
+ medium.pUnkForRelease = NULL;
+ const size_t num = path.Len() + 1; // + (1 << 19) // for debug
+ medium.hGlobal = GlobalAlloc(GHND | GMEM_SHARE, num * sizeof(wchar_t));
+ if (!medium.hGlobal)
+ return false;
+ // Sleep(1000);
+ wchar_t *dest = (wchar_t *)GlobalLock(medium.hGlobal);
+ // Sleep(1000);
+ bool res = false;
+ if (dest)
+ {
+ MyStringCopy(dest, (const wchar_t *)path);
+ GlobalUnlock(medium.hGlobal);
+ // OutputDebugString("m_DataObject->SetData");
+ const BOOL release = FALSE; // that way is more simple for correct releasing.
+ // TRUE; // for debug : is not good for some cases.
+ /* If DropSource is Win10-Explorer, dataObject->SetData() returns E_NOTIMPL; */
+ const HRESULT hres = dataObject->SetData(&etc, &medium, release);
+ // Sleep(1000);
+ res = (hres == S_OK);
+ }
+
+ ReleaseStgMedium(&medium);
+ if (res && !path.IsEmpty())
+ m_TargetPath_NonEmpty_WasSent_ToDataObject = true;
+ // Sleep(1000);
+ return res;
+}
+
+
+void CDropTarget::SendToSource_auto(IDataObject *dataObject,
+ const CTargetTransferInfo &info)
+{
+ /* we try to send target path to Source.
+ If Source is 7-Zip, then it will accept k_Format_7zip_SetTargetFolder.
+ That sent path will be non-Empty, if this target is FS folder and drop is allowed */
+ bool need_Send = false;
+ if ( info.FuncType == k_DragTargetMode_Enter
+ || info.FuncType == k_DragTargetMode_Over
+ || (info.FuncType == k_DragTargetMode_Drop_Begin
+ // && targetOp_Cmd != NDragMenu::k_None
+ && info.Cmd_Type != NDragMenu::k_Cancel))
+ // if (!g_CreateArchive_for_Drag_from_7zip)
+ need_Send = m_DropIsAllowed && m_PanelDropIsAllowed && IsFsFolderPath();
+ m_TargetPath_WasSent_ToDataObject = SendToSource_TargetPath_enable(dataObject, need_Send);
+ SendToSource_TransferInfo(dataObject, info);
+}
+
+
+bool CDropTarget::SendToSource_TransferInfo(IDataObject *dataObject,
+ const CTargetTransferInfo &info)
+{
+ m_Transfer_WasSent_ToDataObject = false;
+ PRF("CDropTarget::SendToSource_TransferInfo");
+
+ if (!dataObject || m_Format_7zip_SetTransfer == 0)
+ return false;
+ FORMATETC etc = INIT_FORMATETC_HGLOBAL((CLIPFORMAT)m_Format_7zip_SetTransfer);
+ STGMEDIUM medium;
+ medium.tymed = etc.tymed;
+ medium.pUnkForRelease = NULL;
+ CDataObject_SetTransfer transfer;
+ const size_t size = sizeof(transfer); // + (1 << 19) // for debug
+ // OutputDebugString("GlobalAlloc");
+ medium.hGlobal = GlobalAlloc(GHND | GMEM_SHARE, size);
+ // Sleep(1000);
+ if (!medium.hGlobal)
+ return false;
+ // OutputDebugString("GlobalLock");
+ void *dest = (wchar_t *)GlobalLock(medium.hGlobal);
+ // Sleep(1000);
+ bool res = false;
+ if (dest)
+ {
+ transfer.Init();
+ transfer.Target = info;
+
+ memcpy(dest, &transfer, sizeof(transfer));
+ GlobalUnlock(medium.hGlobal);
+ // OutputDebugString("m_DataObject->SetData");
+ const BOOL release = FALSE; // that way is more simple for correct releasing.
+ // TRUE; // for debug : is not good for some cases
+ const HRESULT hres = dataObject->SetData(&etc, &medium, release);
+ res = (hres == S_OK);
+ }
+
+ ReleaseStgMedium(&medium);
+ if (res)
+ m_Transfer_WasSent_ToDataObject = true;
+ return res;
+}
+
+
+bool CDropTarget::SendToSource_UInt32(IDataObject *dataObject, UINT format, UInt32 value)
+{
+ PRF("CDropTarget::Send_UInt32 (Performed)");
+
+ if (!dataObject || format == 0)
+ return false;
+ FORMATETC etc = INIT_FORMATETC_HGLOBAL((CLIPFORMAT)format);
+ STGMEDIUM medium;
+ medium.tymed = etc.tymed;
+ medium.pUnkForRelease = NULL;
+ const size_t size = 4;
+ medium.hGlobal = GlobalAlloc(GHND | GMEM_SHARE, size);
+ if (!medium.hGlobal)
+ return false;
+ void *dest = GlobalLock(medium.hGlobal);
+ bool res = false;
+ if (dest)
+ {
+ *(UInt32 *)dest = value;
+ GlobalUnlock(medium.hGlobal);
+ // OutputDebugString("m_DataObject->SetData");
+ const BOOL release = TRUE;
+ // FALSE; // for debug
+ /* If DropSource is Win10-Explorer, then (release == FALSE) doesn't work
+ and dataObject->SetData() returns E_NOTIMPL;
+ So we use release = TRUE; here */
+ const HRESULT hres = dataObject->SetData(&etc, &medium, release);
+ // we return here without calling ReleaseStgMedium().
+ return (hres == S_OK);
+ // Sleep(1000);
+ /*
+ if (we use release = TRUE), we expect that
+ - SetData() will release medium, and
+ - SetData() will set STGMEDIUM::tymed to (TYMED_NULL = 0).
+ but some "incorrect" SetData() implementations can keep STGMEDIUM::tymed unchanged.
+ And it's not safe to call ReleaseStgMedium() here for that case,
+ because DropSource also could release medium.
+ We can reset (medium.tymed = TYMED_NULL) manually here to disable
+ unsafe medium releasing in ReleaseStgMedium().
+ */
+ /*
+ if (release)
+ {
+ medium.tymed = TYMED_NULL;
+ medium.pUnkForRelease = NULL;
+ medium.hGlobal = NULL;
+ }
+ res = (hres == S_OK);
+ */
+ }
+ ReleaseStgMedium(&medium);
+ return res;
+}
+
+
+void CDropTarget::LoadNames_From_DataObject(IDataObject *dataObject)
+{
+ // "\\\\.\\" prefix is possible for long names
+ m_DropIsAllowed = NShell::DataObject_GetData_HDROP_or_IDLIST_Names(dataObject, m_SourcePaths) == S_OK;
+}
+
+
+Z7_COMWF_B CDropTarget::DragEnter(IDataObject *dataObject, DWORD keyState, POINTL pt, DWORD *effect)
+{
+ /* *(effect):
+ - on input : value of the dwOKEffects parameter of the DoDragDrop() function.
+ - on return : must contain one of the DROPEFFECT flags, which indicates
+ what the result of the drop operation would be.
+ (pt): the current cursor coordinates in screen coordinates.
+ */
+ PRF_(Print_Point("CDropTarget::DragEnter", keyState, pt, *effect))
+ try {
+
+ if ((keyState & (MK_RBUTTON | MK_MBUTTON)) != 0)
+ m_IsRightButton = true;
+
+ LoadNames_From_DataObject(dataObject);
+ // Try_QueryGetData(dataObject);
+ // we will use (m_DataObject) later in DragOver() and DragLeave().
+ m_DataObject = dataObject;
+ // return DragOver(keyState, pt, effect);
+ PositionCursor(pt);
+ CTargetTransferInfo target;
+ target.FuncType = k_DragTargetMode_Enter;
+ target.KeyState = keyState;
+ target.Point = pt;
+ target.OkEffects = *effect;
+ SendToSource_Drag(target);
+
+ CDataObject_GetTransfer transfer;
+ m_GetTransfer_WasSuccess = DataObject_GetData_GetTransfer(
+ dataObject, m_Format_7zip_GetTransfer, transfer);
+ if (m_GetTransfer_WasSuccess)
+ {
+ if (transfer.Flags & k_SourceFlags_LeftButton)
+ m_IsRightButton = false;
+ else if (transfer.Flags & k_SourceFlags_RightButton)
+ m_IsRightButton = true;
+ }
+
+ *effect = GetEffect(keyState, pt, *effect);
+ return S_OK;
+ } catch(...) { return E_FAIL; }
+}
+
+
+Z7_COMWF_B CDropTarget::DragOver(DWORD keyState, POINTL pt, DWORD *effect)
+{
+ PRF_(Print_Point("CDropTarget::DragOver", keyState, pt, *effect))
+ /*
+ For efficiency reasons, a data object is not passed in IDropTarget::DragOver.
+ The data object passed in the most recent call to IDropTarget::DragEnter
+ is available and can be used.
+
+ When IDropTarget::DragOver has completed its operation, the DoDragDrop
+ function calls IDropSource::GiveFeedback so the source application can display
+ the appropriate visual feedback to the user.
+ */
+ /*
+ we suppose that it's unexpected that (keyState) shows that mouse
+ button is not pressed, because such cases will be processed by
+ IDropSource::QueryContinueDrag() that returns DRAGDROP_S_DROP or DRAGDROP_S_CANCEL.
+ So DragOver() will not be called.
+ */
+
+ if ((keyState & MK_LBUTTON) == 0)
+ {
+ PRF4("CDropTarget::DragOver() (keyState & MK_LBUTTON) == 0");
+ // g_Debug = true;
+ }
+
+ try {
+ /* we suppose that source names were not changed after DragEnter()
+ so we don't request GetNames_From_DataObject() for each call of DragOver() */
+ PositionCursor(pt);
+ CTargetTransferInfo target;
+ target.FuncType = k_DragTargetMode_Over;
+ target.KeyState = keyState;
+ target.Point = pt;
+ target.OkEffects = *effect;
+ SendToSource_Drag(target);
+ *effect = GetEffect(keyState, pt, *effect);
+ // *effect = 1 << 8; // for debug
+ return S_OK;
+ } catch(...) { return E_FAIL; }
+}
+
+
+Z7_COMWF_B CDropTarget::DragLeave()
+{
+ PRF4("CDropTarget::DragLeave");
+ try {
+ RemoveSelection();
+ // we send empty TargetPath to 7-Zip Source to clear value of TargetPath that was sent before
+
+ CTargetTransferInfo target;
+ target.FuncType = k_DragTargetMode_Leave;
+ /*
+ target.KeyState = 0;
+ target.Point = pt;
+ pt.x = 0; // -1
+ pt.y = 0; // -1
+ target.Effect = 0;
+ */
+ SendToSource_Drag(target);
+ ClearState();
+ return S_OK;
+ } catch(...) { return E_FAIL; }
+}
+
+
+static unsigned Drag_OnContextMenu(int xPos, int yPos, UInt32 cmdFlags);
+
+/*
+ We suppose that there was DragEnter/DragOver for same (POINTL pt) before Drop().
+ But we can work without DragEnter/DragOver too.
+*/
+Z7_COMWF_B CDropTarget::Drop(IDataObject *dataObject, DWORD keyState,
+ POINTL pt, DWORD *effect)
+{
+ PRF_(Print_Point("CDropTarget::Drop", keyState, pt, *effect))
+ /* Drop() is called after SourceDrop::QueryContinueDrag() returned DRAGDROP_S_DROP.
+ So it's possible that Source have done some operations already.
+ */
+ HRESULT hres = S_OK;
+ bool needDrop_by_Source = false;
+ DWORD opEffect = DROPEFFECT_NONE;
+
+ try {
+ // we don't need m_DataObject reference anymore, because we use local (dataObject)
+ m_DataObject.Release();
+
+ /* in normal case : we called LoadNames_From_DataObject() in DragEnter() already.
+ But if by some reason DragEnter() was not called,
+ we need to call LoadNames_From_DataObject() before PositionCursor().
+ */
+ if (!m_DropIsAllowed) LoadNames_From_DataObject(dataObject);
+ PositionCursor(pt);
+
+ CPanel::CDisableTimerProcessing2 disableTimerProcessing(m_Panel);
+ // CDisableNotify disableNotify2(m_Panel);
+
+ UInt32 cmd = NDragMenu::k_None;
+ UInt32 cmdEffect = DROPEFFECT_NONE;
+ bool menu_WasShown = false;
+ if (m_IsRightButton && m_Panel)
+ {
+ UInt32 flagsMask;
+ if (m_Panel->IsArcFolder())
+ flagsMask = (UInt32)1 << NDragMenu::k_Copy_ToArc;
+ else
+ {
+ flagsMask = (UInt32)1 << NDragMenu::k_AddToArc;
+ if (IsFsFolderPath())
+ flagsMask |= (UInt32)1 << NDragMenu::k_Copy_Base;
+ }
+ // flagsMask |= (UInt32)1 << NDragMenu::k_Cancel;
+ const UInt32 cmd32 = Drag_OnContextMenu(pt.x, pt.y, flagsMask);
+ cmd = cmd32 & NDragMenu::k_MenuFlags_CmdMask;
+ if (cmd32 & NDragMenu::k_MenuFlag_Copy)
+ cmdEffect = DROPEFFECT_COPY;
+ else if (cmd32 & NDragMenu::k_MenuFlag_Move)
+ cmdEffect = DROPEFFECT_MOVE;
+ opEffect = cmdEffect;
+ menu_WasShown = true;
+ }
+ else
+ {
+ opEffect = GetEffect(keyState, pt, *effect);
+ if (m_IsAppTarget)
+ cmd = NDragMenu::k_AddToArc;
+ else if (m_Panel)
+ {
+ if (IsFsFolderPath())
+ {
+ const bool is7zip = m_TargetPath_WasSent_ToDataObject;
+ bool createNewArchive = false;
+ if (is7zip)
+ createNewArchive = false; // g_CreateArchive_for_Drag_from_7zip;
+ else
+ createNewArchive = true; // g_CreateArchive_for_Drag_from_Explorer;
+
+ if (createNewArchive)
+ cmd = NDragMenu::k_AddToArc;
+ else
+ {
+ if (opEffect != 0)
+ cmd = NDragMenu::k_Copy_Base;
+ cmdEffect = opEffect;
+ }
+ }
+ else
+ {
+ /* if we are inside open archive:
+ if archive support operations -> we will call operations
+ if archive doesn't support operations -> we will create new archove
+ */
+ if (m_Panel->IsArcFolder()
+ || m_Panel->DoesItSupportOperations())
+ {
+ cmd = NDragMenu::k_Copy_ToArc;
+ // we don't want move to archive operation here.
+ // so we force to DROPEFFECT_COPY.
+ if (opEffect != DROPEFFECT_NONE)
+ opEffect = DROPEFFECT_COPY;
+ cmdEffect = opEffect;
+ }
+ else
+ cmd = NDragMenu::k_AddToArc;
+ }
+ }
+ }
+
+ if (cmd == 0)
+ cmd = NDragMenu::k_AddToArc;
+
+ if (cmd == NDragMenu::k_AddToArc)
+ {
+ opEffect = DROPEFFECT_COPY;
+ cmdEffect = DROPEFFECT_COPY;
+ }
+
+ if (m_Panel)
+ if (cmd == NDragMenu::k_Copy_ToArc)
+ {
+ const UString title = LangString(IDS_CONFIRM_FILE_COPY);
+ UString s = LangString(cmdEffect == DROPEFFECT_MOVE ?
+ IDS_MOVE_TO : IDS_COPY_TO);
+ s.Add_LF();
+ s += "\'";
+ s += m_Panel->_currentFolderPrefix;
+ s += "\'";
+ s.Add_LF();
+ s += LangString(IDS_WANT_TO_COPY_FILES);
+ s += " ?";
+ const int res = ::MessageBoxW(*m_Panel, s, title, MB_YESNOCANCEL | MB_ICONQUESTION);
+ if (res != IDYES)
+ cmd = NDragMenu::k_Cancel;
+ }
+
+ CTargetTransferInfo target;
+ target.FuncType = k_DragTargetMode_Drop_Begin;
+ target.KeyState = keyState;
+ target.Point = pt;
+ target.OkEffects = *effect;
+ target.Flags = 0;
+
+ target.Cmd_Effect = cmdEffect;
+ target.Cmd_Type = cmd;
+ target.FolderType = GetFolderType();
+
+ if (cmd == NDragMenu::k_Cancel)
+ target.Flags |= k_TargetFlags_WasCanceled;
+ if (menu_WasShown)
+ target.Flags |= k_TargetFlags_MenuWasShown;
+
+ SendToSource_auto(dataObject, target);
+
+ CDataObject_GetTransfer transfer;
+ m_GetTransfer_WasSuccess = DataObject_GetData_GetTransfer(
+ dataObject, m_Format_7zip_GetTransfer, transfer);
+
+ /* The Source (for example, 7-zip) could change file names when drop was confirmed.
+ So we must reload source file paths here */
+ if (cmd != NDragMenu::k_Cancel)
+ LoadNames_From_DataObject(dataObject);
+
+ if (cmd == NDragMenu::k_Cancel)
+ {
+ opEffect = DROPEFFECT_NONE;
+ cmdEffect = DROPEFFECT_NONE;
+ }
+ else
+ {
+ if (m_GetTransfer_WasSuccess)
+ needDrop_by_Source = ((transfer.Flags & k_SourceFlags_DoNotProcessInTarget) != 0);
+ if (!needDrop_by_Source)
+ {
+ bool moveMode = (cmdEffect == DROPEFFECT_MOVE);
+ bool needDrop = false;
+ if (m_IsRightButton && m_Panel)
+ needDrop = true;
+ if (m_DropIsAllowed && m_PanelDropIsAllowed)
+ {
+ /* if non-empty TargetPath was sent successfully to DataObject,
+ then the Source is 7-Zip, and that 7zip-Source can copy to FS operation.
+ So we can disable Drop operation here for such case.
+ */
+ needDrop_by_Source = (cmd != NDragMenu::k_AddToArc
+ && m_TargetPath_WasSent_ToDataObject
+ && m_TargetPath_NonEmpty_WasSent_ToDataObject);
+ needDrop = !(needDrop_by_Source);
+ }
+ if (needDrop)
+ {
+ UString path = GetTargetPath();
+ if (m_IsAppTarget && m_Panel)
+ if (m_Panel->IsFSFolder())
+ path = m_Panel->GetFsPath();
+
+ UInt32 sourceFlags = 0;
+ if (m_GetTransfer_WasSuccess)
+ sourceFlags = transfer.Flags;
+
+ if (menu_WasShown)
+ target.Flags |= k_TargetFlags_MenuWasShown;
+
+ target.Flags |= k_TargetFlags_WasProcessed;
+
+ RemoveSelection();
+ // disableTimerProcessing.Restore();
+ m_Panel->CompressDropFiles(m_SourcePaths, path,
+ (cmd == NDragMenu::k_AddToArc), // createNewArchive,
+ moveMode, sourceFlags,
+ target.Flags
+ );
+ }
+ }
+ } // end of if (cmd != NDragMenu::k_Cancel)
+ {
+ /* note that, if (we send CFSTR_PERFORMEDDROPEFFECT as DROPEFFECT_MOVE
+ and Drop() returns (*effect == DROPEFFECT_MOVE), then
+ Win10-Explorer-Source will try to remove files just after Drop() exit.
+ But our CompressFiles() could be run without waiting finishing.
+ DOCs say, that we must send CFSTR_PERFORMEDDROPEFFECT
+ - DROPEFFECT_NONE : for optimized move
+ - DROPEFFECT_MOVE : for unoptimized move.
+ But actually Win10-Explorer-Target sends (DROPEFFECT_MOVE) for move operation.
+ And it still works as in optimized mode, because "unoptimized" deleting by Source will be performed
+ if both conditions are met:
+ 1) DROPEFFECT_MOVE is sent to (CFSTR_PERFORMEDDROPEFFECT) and
+ 2) (*effect == DROPEFFECT_MOVE) is returend by Drop().
+ We don't want to send DROPEFFECT_MOVE here to protect from
+ deleting file by Win10-Explorer.
+ We are not sure that allfile fieree processed by move.
+ */
+
+ // for debug: we test the case when source tries to delete original files
+ // bool res;
+ // only CFSTR_PERFORMEDDROPEFFECT affects file removing in Win10-Explorer.
+ // res = SendToSource_UInt32(dataObject, RegisterClipboardFormat(CFSTR_LOGICALPERFORMEDDROPEFFECT), DROPEFFECT_MOVE); // for debug
+ /* res = */ SendToSource_UInt32(dataObject,
+ RegisterClipboardFormat(CFSTR_PERFORMEDDROPEFFECT),
+ cmd == NDragMenu::k_Cancel ? DROPEFFECT_NONE : DROPEFFECT_COPY);
+ // res = res;
+ }
+ RemoveSelection();
+
+ target.FuncType = k_DragTargetMode_Drop_End;
+ target.Cmd_Type = cmd;
+ if (needDrop_by_Source)
+ target.Flags |= k_TargetFlags_MustBeProcessedBySource;
+
+ SendToSource_TransferInfo(dataObject, target);
+ } catch(...) { hres = E_FAIL; }
+
+ ClearState();
+ // *effect |= (1 << 10); // for debug
+ // *effect = DROPEFFECT_COPY; // for debug
+
+ /*
+ if we return (*effect == DROPEFFECT_MOVE) here,
+ Explorer-Source at some conditions can treat it as (unoptimized move) mode,
+ and Explorer-Source will remove source files after DoDragDrop()
+ in that (unoptimized move) mode.
+ We want to avoid such (unoptimized move) cases.
+ So we don't return (*effect == DROPEFFECT_MOVE), here if Source is not 7-Zip.
+ If source is 7-Zip that will do acual opeartion, then we can return DROPEFFECT_MOVE.
+ */
+ if (hres != S_OK || (opEffect == DROPEFFECT_MOVE && !needDrop_by_Source))
+ {
+ // opEffect = opEffect;
+ // opEffect = DROPEFFECT_NONE; // for debug disabled
+ }
+
+ *effect = opEffect;
+ /* if (hres < 0), DoDragDrop() also will return (hres).
+ if (hres >= 0), DoDragDrop() will return DRAGDROP_S_DROP;
+ */
+ return hres;
+}
+
+
+
+// ---------- CPanel ----------
+
+
+static bool Is_Path1_Prefixed_by_Path2(const UString &path, const UString &prefix)
+{
+ const unsigned len = prefix.Len();
+ if (path.Len() < len)
+ return false;
+ return CompareFileNames(path.Left(len), prefix) == 0;
+}
+
+static bool IsFolderInTemp(const UString &path)
+{
+ FString tempPathF;
+ if (!MyGetTempPath(tempPathF))
+ return false;
+ const UString tempPath = fs2us(tempPathF);
+ if (tempPath.IsEmpty())
+ return false;
+ return Is_Path1_Prefixed_by_Path2(path, tempPath);
+}
+
+static bool AreThereNamesFromTemp(const UStringVector &filePaths)
+{
+ FString tempPathF;
+ if (!MyGetTempPath(tempPathF))
+ return false;
+ const UString tempPath = fs2us(tempPathF);
+ if (tempPath.IsEmpty())
+ return false;
+ FOR_VECTOR (i, filePaths)
+ if (Is_Path1_Prefixed_by_Path2(filePaths[i], tempPath))
+ return true;
+ return false;
+}
+
+
+/*
+ empty folderPath means create new Archive to path of first fileName.
+ createNewArchive == true : show "Add to archive ..." dialog with external program
+ folderPath.IsEmpty() : create archive in folder of filePaths[0].
+ createNewArchive == false :
+ folderPath.IsEmpty() : copy to archive folder that is open in panel
+ !folderPath.IsEmpty() : CopyFsItems() to folderPath.
+*/
+void CPanel::CompressDropFiles(
+ const UStringVector &filePaths,
+ const UString &folderPath,
+ bool createNewArchive,
+ bool moveMode,
+ UInt32 sourceFlags,
+ UInt32 &targetFlags
+ )
+{
+ if (filePaths.Size() == 0)
+ return;
+ // createNewArchive = false; // for debug
+
+ if (createNewArchive)
+ {
+ UString folderPath2 = folderPath;
+ // folderPath2.Empty(); // for debug
+ if (folderPath2.IsEmpty())
+ {
+ {
+ FString folderPath2F;
+ GetOnlyDirPrefix(us2fs(filePaths.Front()), folderPath2F);
+ folderPath2 = fs2us(folderPath2F);
+ }
+ if (IsFolderInTemp(folderPath2))
+ {
+ /* we don't want archive to be created in temp directory.
+ so we change the path to root folder (non-temp) */
+ folderPath2 = ROOT_FS_FOLDER;
+ }
+ }
+
+ UString arcName_base;
+ const UString arcName = CreateArchiveName(filePaths,
+ false, // isHash
+ NULL, // CFileInfo *fi
+ arcName_base);
+
+ bool needWait;
+ if (sourceFlags & k_SourceFlags_WaitFinish)
+ needWait = true;
+ else if (sourceFlags & k_SourceFlags_DoNotWaitFinish)
+ needWait = false;
+ else if (sourceFlags & k_SourceFlags_TempFiles)
+ needWait = true;
+ else
+ needWait = AreThereNamesFromTemp(filePaths);
+
+ targetFlags |= (needWait ?
+ k_TargetFlags_WaitFinish :
+ k_TargetFlags_DoNotWaitFinish);
+
+ CompressFiles(folderPath2, arcName,
+ L"", // arcType
+ true, // addExtension
+ filePaths,
+ false, // email
+ true, // showDialog
+ needWait);
+ }
+ else
+ {
+ targetFlags |= k_TargetFlags_WaitFinish;
+ if (!folderPath.IsEmpty())
+ {
+ CCopyToOptions options;
+ options.moveMode = moveMode;
+ options.folder = folderPath;
+ options.showErrorMessages = true; // showErrorMessages is not used for this operation
+ options.NeedRegistryZone = false;
+ options.ZoneIdMode = NExtract::NZoneIdMode::kNone;
+ // maybe we need more options here: FIXME
+ /* HRESULT hres = */ CopyFsItems(options,
+ filePaths,
+ NULL // UStringVector *messages
+ );
+ // hres = hres;
+ }
+ else
+ {
+ CopyFromNoAsk(moveMode, filePaths);
+ }
+ }
+}
+
+
+
+static unsigned Drag_OnContextMenu(int xPos, int yPos, UInt32 cmdFlags)
+{
+ CMenu menu;
+ CMenuDestroyer menuDestroyer(menu);
+ /*
+ Esc key in shown menu doesn't work if we call Drag_OnContextMenu from ::Drop().
+ We call SetFocus() tp solve that problem.
+ But the focus will be changed to Target Window after Drag and Drop.
+ Is it OK to use SetFocus() here ?
+ Is there another way to enable Esc key ?
+ */
+ // _listView.SetFocus(); // for debug
+ ::SetFocus(g_HWND);
+ menu.CreatePopup();
+ /*
+ int defaultCmd; // = NDragMenu::k_Move;
+ defaultCmd = NDragMenu::k_None;
+ */
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(NDragMenu::g_Pairs); i++)
+ {
+ const NDragMenu::CCmdLangPair &pair = NDragMenu::g_Pairs[i];
+ const UInt32 cmdAndFlags = pair.CmdId_and_Flags;
+ const UInt32 cmdId = cmdAndFlags & NDragMenu::k_MenuFlags_CmdMask;
+ if (cmdId != NDragMenu::k_Cancel)
+ if ((cmdFlags & ((UInt32)1 << cmdId)) == 0)
+ continue;
+ const UINT flags = MF_STRING;
+ /*
+ if (prop.IsVisible)
+ flags |= MF_CHECKED;
+ if (i == 0)
+ flags |= MF_GRAYED;
+ */
+ // MF_DEFAULT doesn't work
+ // if (i == 2) flags |= MF_DEFAULT;
+ // if (i == 4) flags |= MF_HILITE;
+ // if (cmd == defaultCmd) flags |= MF_HILITE;
+ UString name = LangString(pair.LangId);
+ if (name.IsEmpty())
+ {
+ if (cmdId == NDragMenu::k_Cancel)
+ name = "Cancel";
+ else
+ name.Add_UInt32(pair.LangId);
+ }
+ if (cmdId == NDragMenu::k_Copy_ToArc)
+ {
+ // UString destPath = _currentFolderPrefix;
+ /*
+ UString destPath = LangString(IDS_CONTEXT_ARCHIVE);
+ name = MyFormatNew(name, destPath);
+ */
+ name.Add_Space();
+ name += LangString(IDS_CONTEXT_ARCHIVE);
+ }
+ if (cmdId == NDragMenu::k_Cancel)
+ menu.AppendItem(MF_SEPARATOR, 0, (LPCTSTR)NULL);
+ menu.AppendItem(flags, cmdAndFlags, name);
+ }
+ /*
+ if (defaultCmd != 0)
+ SetMenuDefaultItem(menu, (unsigned)defaultCmd,
+ FALSE); // byPos
+ */
+ int menuResult = menu.Track(
+ TPM_LEFTALIGN | TPM_RETURNCMD | TPM_NONOTIFY,
+ xPos, yPos,
+ g_HWND
+ // _listView // for debug
+ );
+ /* menu.Track() return value is zero, if the user cancels
+ the menu without making a selection, or if an error occurs */
+ if (menuResult <= 0)
+ menuResult = NDragMenu::k_Cancel;
+ return (unsigned)menuResult;
+}
+
+
+
+void CApp::CreateDragTarget()
+{
+ _dropTargetSpec = new CDropTarget();
+ _dropTarget = _dropTargetSpec;
+ _dropTargetSpec->App = (this);
+}
+
+void CApp::SetFocusedPanel(unsigned index)
+{
+ LastFocusedPanel = index;
+ _dropTargetSpec->TargetPanelIndex = (int)LastFocusedPanel;
+}
+
+void CApp::DragBegin(unsigned panelIndex)
+{
+ _dropTargetSpec->TargetPanelIndex = (int)(NumPanels > 1 ? 1 - panelIndex : panelIndex);
+ _dropTargetSpec->SrcPanelIndex = (int)panelIndex;
+}
+
+void CApp::DragEnd()
+{
+ _dropTargetSpec->TargetPanelIndex = (int)LastFocusedPanel;
+ _dropTargetSpec->SrcPanelIndex = -1;
+}
diff --git a/CPP/7zip/UI/FileManager/PanelFolderChange.cpp b/CPP/7zip/UI/FileManager/PanelFolderChange.cpp
new file mode 100644
index 0000000..a13b88d
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelFolderChange.cpp
@@ -0,0 +1,913 @@
+// PanelFolderChange.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/PropVariant.h"
+
+#include "../../PropID.h"
+
+#ifdef UNDER_CE
+#include "FSFolder.h"
+#else
+#include "FSDrives.h"
+#endif
+#include "LangUtils.h"
+#include "ListViewDialog.h"
+#include "Panel.h"
+#include "RootFolder.h"
+#include "ViewSettings.h"
+
+#include "resource.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NFind;
+
+void CPanel::ReleaseFolder()
+{
+ DeleteListItems();
+
+ _folder.Release();
+
+ _folderCompare.Release();
+ _folderGetItemName.Release();
+ _folderRawProps.Release();
+ _folderAltStreams.Release();
+ _folderOperations.Release();
+
+ _thereAreDeletedItems = false;
+}
+
+void CPanel::SetNewFolder(IFolderFolder *newFolder)
+{
+ ReleaseFolder();
+ _folder = newFolder;
+ if (_folder)
+ {
+ _folder.QueryInterface(IID_IFolderCompare, &_folderCompare);
+ _folder.QueryInterface(IID_IFolderGetItemName, &_folderGetItemName);
+ _folder.QueryInterface(IID_IArchiveGetRawProps, &_folderRawProps);
+ _folder.QueryInterface(IID_IFolderAltStreams, &_folderAltStreams);
+ _folder.QueryInterface(IID_IFolderOperations, &_folderOperations);
+ }
+}
+
+void CPanel::SetToRootFolder()
+{
+ ReleaseFolder();
+ _library.Free();
+
+ CRootFolder *rootFolderSpec = new CRootFolder;
+ SetNewFolder(rootFolderSpec);
+ rootFolderSpec->Init();
+}
+
+
+static bool DoesNameContainWildcard_SkipRoot(const UString &path)
+{
+ return DoesNameContainWildcard(path.Ptr(NName::GetRootPrefixSize(path)));
+}
+
+HRESULT CPanel::BindToPath(const UString &fullPath, const UString &arcFormat, COpenResult &openRes)
+{
+ UString path = fullPath;
+ #ifdef _WIN32
+ path.Replace(L'/', WCHAR_PATH_SEPARATOR);
+ #endif
+
+ openRes.ArchiveIsOpened = false;
+ openRes.Encrypted = false;
+
+ CDisableTimerProcessing disableTimerProcessing(*this);
+ CDisableNotify disableNotify(*this);
+
+ for (; !_parentFolders.IsEmpty(); CloseOneLevel())
+ {
+ // ---------- we try to use open archive ----------
+
+ const CFolderLink &link = _parentFolders.Back();
+ const UString &virtPath = link.VirtualPath;
+ if (!path.IsPrefixedBy(virtPath))
+ continue;
+ UString relatPath = path.Ptr(virtPath.Len());
+ if (!relatPath.IsEmpty())
+ {
+ if (!IS_PATH_SEPAR(relatPath[0]))
+ continue;
+ else
+ relatPath.Delete(0);
+ }
+
+ UString relatPath2 = relatPath;
+ if (!relatPath2.IsEmpty() && !IS_PATH_SEPAR(relatPath2.Back()))
+ relatPath2.Add_PathSepar();
+
+ for (;;)
+ {
+ const UString foldPath = GetFolderPath(_folder);
+ if (relatPath2 == foldPath)
+ break;
+ if (relatPath.IsPrefixedBy(foldPath))
+ {
+ path = relatPath.Ptr(foldPath.Len());
+ break;
+ }
+ CMyComPtr<IFolderFolder> newFolder;
+ if (_folder->BindToParentFolder(&newFolder) != S_OK)
+ throw 20140918;
+ if (!newFolder) // we exit from loop above if (relatPath.IsPrefixedBy(empty path for root folder)
+ throw 20140918;
+ SetNewFolder(newFolder);
+ }
+ break;
+ }
+
+ if (_parentFolders.IsEmpty())
+ {
+ // ---------- we open file or folder from file system ----------
+
+ CloseOpenFolders();
+ UString sysPath = path;
+ /* we will Empty() sysPath variable, if we need to BindToFolder()
+ directly with (path) variable */
+ const unsigned prefixSize = NName::GetRootPrefixSize(sysPath);
+ if (prefixSize == 0 || sysPath[prefixSize] == 0)
+ sysPath.Empty();
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (!sysPath.IsEmpty() && sysPath.Back() == ':' &&
+ (sysPath.Len() != 2 || !NName::IsDrivePath2(sysPath)))
+ {
+ // if base item for alt streams prefix "base:" exists, we will use it
+ UString baseFile = sysPath;
+ baseFile.DeleteBack();
+ if (NFind::DoesFileOrDirExist(us2fs(baseFile)))
+ sysPath.Empty();
+ }
+ #endif
+
+ CFileInfo fileInfo;
+
+ while (!sysPath.IsEmpty())
+ {
+ if (sysPath.Len() <= prefixSize)
+ {
+ path.DeleteFrom(prefixSize);
+ sysPath.Empty();
+ break;
+ }
+
+ fileInfo.ClearBase();
+ if (IsPathSepar(sysPath.Back()))
+ {
+ /* Windows 10 by default doesn't allow look "Local Settings" that is junction to "AppData\Local",
+ but it does allow look "Local Settings\Temp\*"
+ 22.02: at first we try to use paths with slashes "path\" */
+ CFileInfo fi;
+ // CFindFile findFile;
+ // FString path2 = us2fs(sysPath);
+ // path2 += '*'; // CHAR_ANY_MASK;
+ // if (findFile.FindFirst(path2, fi))
+ CEnumerator enumerator;
+ enumerator.SetDirPrefix(us2fs(sysPath));
+ bool found = false;
+ if (enumerator.Next(fi, found))
+ {
+ // sysPath.DeleteBack();
+ fileInfo.SetAsDir();
+ fileInfo.Size = 0;
+ fileInfo.Name.Empty();
+ break;
+ }
+ sysPath.DeleteBack();
+ continue;
+ }
+
+ if (fileInfo.Find(us2fs(sysPath)))
+ break;
+ int pos = sysPath.ReverseFind_PathSepar();
+ if (pos < 0)
+ {
+ sysPath.Empty();
+ break;
+ }
+ {
+ if ((unsigned)pos != sysPath.Len() - 1)
+ pos++;
+ sysPath.DeleteFrom((unsigned)pos);
+ }
+ }
+
+ SetToRootFolder();
+
+ CMyComPtr<IFolderFolder> newFolder;
+
+ if (sysPath.IsEmpty())
+ {
+ _folder->BindToFolder(path, &newFolder);
+ }
+ else if (fileInfo.IsDir())
+ {
+ #ifdef _WIN32
+ if (DoesNameContainWildcard_SkipRoot(sysPath))
+ {
+ FString dirPrefix, fileName;
+ NDir::GetFullPathAndSplit(us2fs(sysPath), dirPrefix, fileName);
+ if (DoesNameContainWildcard_SkipRoot(fs2us(dirPrefix)))
+ return E_INVALIDARG;
+ sysPath = fs2us(dirPrefix + fileInfo.Name);
+ }
+ #endif
+
+ NName::NormalizeDirPathPrefix(sysPath);
+ _folder->BindToFolder(sysPath, &newFolder);
+ }
+ else
+ {
+ FString dirPrefix, fileName;
+
+ NDir::GetFullPathAndSplit(us2fs(sysPath), dirPrefix, fileName);
+
+ HRESULT res = S_OK;
+
+ #ifdef _WIN32
+ if (DoesNameContainWildcard_SkipRoot(fs2us(dirPrefix)))
+ return E_INVALIDARG;
+
+ if (DoesNameContainWildcard(fs2us(fileName)))
+ res = S_FALSE;
+ else
+ #endif
+ {
+ CTempFileInfo tfi;
+ tfi.RelPath = fs2us(fileName);
+ tfi.FolderPath = dirPrefix;
+ tfi.FilePath = us2fs(sysPath);
+ res = OpenAsArc(NULL, tfi, sysPath, arcFormat, openRes);
+ }
+
+ if (res == S_FALSE)
+ _folder->BindToFolder(fs2us(dirPrefix), &newFolder);
+ else
+ {
+ RINOK(res)
+ openRes.ArchiveIsOpened = true;
+ _parentFolders.Back().ParentFolderPath = fs2us(dirPrefix);
+ path.DeleteFrontal(sysPath.Len());
+ if (!path.IsEmpty() && IS_PATH_SEPAR(path[0]))
+ path.Delete(0);
+ }
+ }
+
+ if (newFolder)
+ {
+ SetNewFolder(newFolder);
+ // LoadFullPath();
+ return S_OK;
+ }
+ }
+
+ {
+ // ---------- we open folder remPath in archive and sub archives ----------
+
+ for (unsigned curPos = 0; curPos != path.Len();)
+ {
+ UString s = path.Ptr(curPos);
+ const int slashPos = NName::FindSepar(s);
+ unsigned skipLen = s.Len();
+ if (slashPos >= 0)
+ {
+ s.DeleteFrom((unsigned)slashPos);
+ skipLen = (unsigned)slashPos + 1;
+ }
+
+ CMyComPtr<IFolderFolder> newFolder;
+ _folder->BindToFolder(s, &newFolder);
+ if (newFolder)
+ curPos += skipLen;
+ else if (_folderAltStreams)
+ {
+ const int pos = s.Find(L':');
+ if (pos >= 0)
+ {
+ UString baseName = s;
+ baseName.DeleteFrom((unsigned)pos);
+ if (_folderAltStreams->BindToAltStreams(baseName, &newFolder) == S_OK && newFolder)
+ curPos += (unsigned)pos + 1;
+ }
+ }
+
+ if (!newFolder)
+ break;
+
+ SetNewFolder(newFolder);
+ }
+ }
+
+ return S_OK;
+}
+
+HRESULT CPanel::BindToPathAndRefresh(const UString &path)
+{
+ CDisableTimerProcessing disableTimerProcessing(*this);
+ CDisableNotify disableNotify(*this);
+ COpenResult openRes;
+ UString s = path;
+
+ #ifdef _WIN32
+ if (!s.IsEmpty() && s[0] == '\"' && s.Back() == '\"')
+ {
+ s.DeleteBack();
+ s.Delete(0);
+ }
+ #endif
+
+ HRESULT res = BindToPath(s, UString(), openRes);
+ RefreshListCtrl();
+ return res;
+}
+
+void CPanel::SetBookmark(unsigned index)
+{
+ _appState->FastFolders.SetString(index, _currentFolderPrefix);
+}
+
+void CPanel::OpenBookmark(unsigned index)
+{
+ BindToPathAndRefresh(_appState->FastFolders.GetString(index));
+}
+
+UString GetFolderPath(IFolderFolder *folder)
+{
+ {
+ NCOM::CPropVariant prop;
+ if (folder->GetFolderProperty(kpidPath, &prop) == S_OK)
+ if (prop.vt == VT_BSTR)
+ return (wchar_t *)prop.bstrVal;
+ }
+ return UString();
+}
+
+void CPanel::LoadFullPath()
+{
+ _currentFolderPrefix.Empty();
+ FOR_VECTOR (i, _parentFolders)
+ {
+ const CFolderLink &folderLink = _parentFolders[i];
+ _currentFolderPrefix += folderLink.ParentFolderPath;
+ // GetFolderPath(folderLink.ParentFolder);
+ _currentFolderPrefix += folderLink.RelPath;
+ _currentFolderPrefix.Add_PathSepar();
+ }
+ if (_folder)
+ _currentFolderPrefix += GetFolderPath(_folder);
+}
+
+static int GetRealIconIndex(CFSTR path, DWORD attributes)
+{
+ int index = -1;
+ if (GetRealIconIndex(path, attributes, index) != 0)
+ return index;
+ return -1;
+}
+
+void CPanel::LoadFullPathAndShow()
+{
+ LoadFullPath();
+ _appState->FolderHistory.AddString(_currentFolderPrefix);
+
+ _headerComboBox.SetText(_currentFolderPrefix);
+
+ #ifndef UNDER_CE
+
+ COMBOBOXEXITEM item;
+ item.mask = 0;
+
+ UString path = _currentFolderPrefix;
+ if (path.Len() >
+ #ifdef _WIN32
+ 3
+ #else
+ 1
+ #endif
+ && IS_PATH_SEPAR(path.Back()))
+ path.DeleteBack();
+
+ DWORD attrib = FILE_ATTRIBUTE_DIRECTORY;
+
+ // GetRealIconIndex is slow for direct DVD/UDF path. So we use dummy path
+ if (path.IsPrefixedBy(L"\\\\.\\"))
+ path = "_TestFolder_";
+ else
+ {
+ CFileInfo fi;
+ if (fi.Find(us2fs(path)))
+ attrib = fi.Attrib;
+ }
+ item.iImage = GetRealIconIndex(us2fs(path), attrib);
+
+ if (item.iImage >= 0)
+ {
+ item.iSelectedImage = item.iImage;
+ item.mask |= (CBEIF_IMAGE | CBEIF_SELECTEDIMAGE);
+ }
+ item.iItem = -1;
+ _headerComboBox.SetItem(&item);
+
+ #endif
+
+ RefreshTitle();
+}
+
+#ifndef UNDER_CE
+LRESULT CPanel::OnNotifyComboBoxEnter(const UString &s)
+{
+ if (BindToPathAndRefresh(GetUnicodeString(s)) == S_OK)
+ {
+ PostMsg(kSetFocusToListView);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+bool CPanel::OnNotifyComboBoxEndEdit(PNMCBEENDEDITW info, LRESULT &result)
+{
+ if (info->iWhy == CBENF_ESCAPE)
+ {
+ _headerComboBox.SetText(_currentFolderPrefix);
+ PostMsg(kSetFocusToListView);
+ result = FALSE;
+ return true;
+ }
+
+ /*
+ if (info->iWhy == CBENF_DROPDOWN)
+ {
+ result = FALSE;
+ return true;
+ }
+ */
+
+ if (info->iWhy == CBENF_RETURN)
+ {
+ // When we use Edit control and press Enter.
+ UString s;
+ _headerComboBox.GetText(s);
+ result = OnNotifyComboBoxEnter(s);
+ return true;
+ }
+ return false;
+}
+#endif
+
+#ifndef _UNICODE
+bool CPanel::OnNotifyComboBoxEndEdit(PNMCBEENDEDIT info, LRESULT &result)
+{
+ if (info->iWhy == CBENF_ESCAPE)
+ {
+ _headerComboBox.SetText(_currentFolderPrefix);
+ PostMsg(kSetFocusToListView);
+ result = FALSE;
+ return true;
+ }
+ /*
+ if (info->iWhy == CBENF_DROPDOWN)
+ {
+ result = FALSE;
+ return true;
+ }
+ */
+
+ if (info->iWhy == CBENF_RETURN)
+ {
+ UString s;
+ _headerComboBox.GetText(s);
+ // GetUnicodeString(info->szText)
+ result = OnNotifyComboBoxEnter(s);
+ return true;
+ }
+ return false;
+}
+#endif
+
+void CPanel::AddComboBoxItem(const UString &name, int iconIndex, int indent, bool addToList)
+{
+ #ifdef UNDER_CE
+
+ UString s;
+ iconIndex = iconIndex;
+ for (int i = 0; i < indent; i++)
+ s += " ";
+ _headerComboBox.AddString(s + name);
+
+ #else
+
+ COMBOBOXEXITEMW item;
+ item.mask = CBEIF_TEXT | CBEIF_INDENT;
+ item.iSelectedImage = item.iImage = iconIndex;
+ if (iconIndex >= 0)
+ item.mask |= (CBEIF_IMAGE | CBEIF_SELECTEDIMAGE);
+ item.iItem = -1;
+ item.iIndent = indent;
+ item.pszText = name.Ptr_non_const();
+ _headerComboBox.InsertItem(&item);
+
+ #endif
+
+ if (addToList)
+ ComboBoxPaths.Add(name);
+}
+
+extern UString RootFolder_GetName_Computer(int &iconIndex);
+extern UString RootFolder_GetName_Network(int &iconIndex);
+extern UString RootFolder_GetName_Documents(int &iconIndex);
+
+bool CPanel::OnComboBoxCommand(UINT code, LPARAM /* param */, LRESULT &result)
+{
+ result = FALSE;
+ switch (code)
+ {
+ case CBN_DROPDOWN:
+ {
+ ComboBoxPaths.Clear();
+ _headerComboBox.ResetContent();
+
+ unsigned i;
+ UStringVector pathParts;
+
+ SplitPathToParts(_currentFolderPrefix, pathParts);
+ UString sumPass;
+ if (!pathParts.IsEmpty())
+ pathParts.DeleteBack();
+ for (i = 0; i < pathParts.Size(); i++)
+ {
+ const UString name = pathParts[i];
+ sumPass += name;
+ sumPass.Add_PathSepar();
+ CFileInfo info;
+ DWORD attrib = FILE_ATTRIBUTE_DIRECTORY;
+ if (info.Find(us2fs(sumPass)))
+ attrib = info.Attrib;
+ AddComboBoxItem(
+ name.IsEmpty() ? L"\\" : name,
+ GetRealIconIndex(us2fs(sumPass), attrib),
+ (int)i, // iIndent
+ false); // addToList
+ ComboBoxPaths.Add(sumPass);
+ }
+
+ #ifndef UNDER_CE
+
+ int iconIndex;
+ UString name;
+ name = RootFolder_GetName_Documents(iconIndex);
+ AddComboBoxItem(name, iconIndex, 0, true);
+
+ name = RootFolder_GetName_Computer(iconIndex);
+ AddComboBoxItem(name, iconIndex, 0, true);
+
+ FStringVector driveStrings;
+ MyGetLogicalDriveStrings(driveStrings);
+ for (i = 0; i < driveStrings.Size(); i++)
+ {
+ FString s = driveStrings[i];
+ ComboBoxPaths.Add(fs2us(s));
+ int iconIndex2 = GetRealIconIndex(s, 0);
+ if (s.Len() > 0 && s.Back() == FCHAR_PATH_SEPARATOR)
+ s.DeleteBack();
+ AddComboBoxItem(fs2us(s), iconIndex2, 1, false);
+ }
+
+ name = RootFolder_GetName_Network(iconIndex);
+ AddComboBoxItem(name, iconIndex, 0, true);
+
+ #endif
+
+ return false;
+ }
+
+ case CBN_SELENDOK:
+ {
+ int index = _headerComboBox.GetCurSel();
+ if (index >= 0)
+ {
+ UString pass = ComboBoxPaths[index];
+ _headerComboBox.SetCurSel(-1);
+ // _headerComboBox.SetText(pass); // it's fix for seclecting by mouse.
+ if (BindToPathAndRefresh(pass) == S_OK)
+ {
+ PostMsg(kSetFocusToListView);
+ #ifdef UNDER_CE
+ PostMsg(kRefresh_HeaderComboBox);
+ #endif
+ return true;
+ }
+ }
+ return false;
+ }
+ /*
+ case CBN_CLOSEUP:
+ {
+ LoadFullPathAndShow();
+ true;
+
+ }
+ case CBN_SELCHANGE:
+ {
+ // LoadFullPathAndShow();
+ return true;
+ }
+ */
+ }
+ return false;
+}
+
+bool CPanel::OnNotifyComboBox(LPNMHDR NON_CE_VAR(header), LRESULT & NON_CE_VAR(result))
+{
+ #ifndef UNDER_CE
+ switch (header->code)
+ {
+ case CBEN_BEGINEDIT:
+ {
+ _lastFocusedIsList = false;
+ _panelCallback->PanelWasFocused();
+ break;
+ }
+ #ifndef _UNICODE
+ case CBEN_ENDEDIT:
+ {
+ return OnNotifyComboBoxEndEdit((PNMCBEENDEDIT)header, result);
+ }
+ #endif
+ case CBEN_ENDEDITW:
+ {
+ return OnNotifyComboBoxEndEdit((PNMCBEENDEDITW)header, result);
+ }
+ }
+ #endif
+ return false;
+}
+
+
+void CPanel::FoldersHistory()
+{
+ CListViewDialog listViewDialog;
+ listViewDialog.DeleteIsAllowed = true;
+ listViewDialog.SelectFirst = true;
+ LangString(IDS_FOLDERS_HISTORY, listViewDialog.Title);
+ _appState->FolderHistory.GetList(listViewDialog.Strings);
+ if (listViewDialog.Create(GetParent()) != IDOK)
+ return;
+ UString selectString;
+ if (listViewDialog.StringsWereChanged)
+ {
+ _appState->FolderHistory.RemoveAll();
+ for (int i = (int)listViewDialog.Strings.Size() - 1; i >= 0; i--)
+ _appState->FolderHistory.AddString(listViewDialog.Strings[i]);
+ if (listViewDialog.FocusedItemIndex >= 0)
+ selectString = listViewDialog.Strings[listViewDialog.FocusedItemIndex];
+ }
+ else
+ {
+ if (listViewDialog.FocusedItemIndex >= 0)
+ selectString = listViewDialog.Strings[listViewDialog.FocusedItemIndex];
+ }
+ if (listViewDialog.FocusedItemIndex >= 0)
+ BindToPathAndRefresh(selectString);
+}
+
+
+UString CPanel::GetParentDirPrefix() const
+{
+ UString s;
+ if (!_currentFolderPrefix.IsEmpty())
+ {
+ wchar_t c = _currentFolderPrefix.Back();
+ if (IS_PATH_SEPAR(c) || c == ':')
+ {
+ s = _currentFolderPrefix;
+ s.DeleteBack();
+ if (s != L"\\\\." &&
+ s != L"\\\\?")
+ {
+ int pos = s.ReverseFind_PathSepar();
+ if (pos >= 0)
+ s.DeleteFrom((unsigned)(pos + 1));
+ }
+ }
+ }
+ return s;
+}
+
+
+void CPanel::OpenParentFolder()
+{
+ LoadFullPath(); // Maybe we don't need it ??
+
+ UString parentFolderPrefix;
+ UString focusedName;
+
+ if (!_currentFolderPrefix.IsEmpty())
+ {
+ wchar_t c = _currentFolderPrefix.Back();
+ if (IS_PATH_SEPAR(c) || c == ':')
+ {
+ focusedName = _currentFolderPrefix;
+ focusedName.DeleteBack();
+ /*
+ if (c == ':' && !focusedName.IsEmpty() && IS_PATH_SEPAR(focusedName.Back()))
+ {
+ focusedName.DeleteBack();
+ }
+ else
+ */
+ if (focusedName != L"\\\\." &&
+ focusedName != L"\\\\?")
+ {
+ const int pos = focusedName.ReverseFind_PathSepar();
+ if (pos >= 0)
+ {
+ parentFolderPrefix = focusedName;
+ parentFolderPrefix.DeleteFrom((unsigned)(pos + 1));
+ focusedName.DeleteFrontal((unsigned)(pos + 1));
+ }
+ }
+ }
+ }
+
+ CDisableTimerProcessing disableTimerProcessing(*this);
+ CDisableNotify disableNotify(*this);
+
+ CMyComPtr<IFolderFolder> newFolder;
+ _folder->BindToParentFolder(&newFolder);
+
+ // newFolder.Release(); // for test
+
+ if (newFolder)
+ SetNewFolder(newFolder);
+ else
+ {
+ bool needSetFolder = true;
+ if (!_parentFolders.IsEmpty())
+ {
+ {
+ const CFolderLink &link = _parentFolders.Back();
+ parentFolderPrefix = link.ParentFolderPath;
+ focusedName = link.RelPath;
+ }
+ CloseOneLevel();
+ needSetFolder = (!_folder);
+ }
+
+ if (needSetFolder)
+ {
+ {
+ COpenResult openRes;
+ BindToPath(parentFolderPrefix, UString(), openRes);
+ }
+ }
+ }
+
+ CSelectedState state;
+ state.FocusedName = focusedName;
+ state.FocusedName_Defined = true;
+ /*
+ if (!focusedName.IsEmpty())
+ state.SelectedNames.Add(focusedName);
+ */
+ LoadFullPath();
+ // ::SetCurrentDirectory(::_currentFolderPrefix);
+ RefreshListCtrl(state);
+ // _listView.EnsureVisible(_listView.GetFocusedItem(), false);
+}
+
+
+void CPanel::CloseOneLevel()
+{
+ ReleaseFolder();
+ _library.Free();
+ {
+ CFolderLink &link = _parentFolders.Back();
+ if (link.ParentFolder)
+ SetNewFolder(link.ParentFolder);
+ _library.Attach(link.Library.Detach());
+ }
+ if (_parentFolders.Size() > 1)
+ OpenParentArchiveFolder();
+ _parentFolders.DeleteBack();
+ if (_parentFolders.IsEmpty())
+ _flatMode = _flatModeForDisk;
+}
+
+void CPanel::CloseOpenFolders()
+{
+ while (!_parentFolders.IsEmpty())
+ CloseOneLevel();
+ _flatMode = _flatModeForDisk;
+ ReleaseFolder();
+ _library.Free();
+}
+
+void CPanel::OpenRootFolder()
+{
+ CDisableTimerProcessing disableTimerProcessing(*this);
+ CDisableNotify disableNotify(*this);
+ _parentFolders.Clear();
+ SetToRootFolder();
+ RefreshListCtrl();
+ // ::SetCurrentDirectory(::_currentFolderPrefix);
+ /*
+ BeforeChangeFolder();
+ _currentFolderPrefix.Empty();
+ AfterChangeFolder();
+ SetCurrentPathText();
+ RefreshListCtrl(UString(), 0, UStringVector());
+ _listView.EnsureVisible(_listView.GetFocusedItem(), false);
+ */
+}
+
+void CPanel::OpenDrivesFolder()
+{
+ CloseOpenFolders();
+ #ifdef UNDER_CE
+ NFsFolder::CFSFolder *folderSpec = new NFsFolder::CFSFolder;
+ SetNewFolder(folderSpec);
+ folderSpec->InitToRoot();
+ #else
+ CFSDrives *folderSpec = new CFSDrives;
+ SetNewFolder(folderSpec);
+ folderSpec->Init();
+ #endif
+ RefreshListCtrl();
+}
+
+void CPanel::OpenFolder(unsigned index)
+{
+ if (index == kParentIndex)
+ {
+ OpenParentFolder();
+ return;
+ }
+ CMyComPtr<IFolderFolder> newFolder;
+ const HRESULT res = _folder->BindToFolder((unsigned)index, &newFolder);
+ if (res != 0)
+ {
+ MessageBox_Error_HRESULT(res);
+ return;
+ }
+ if (!newFolder)
+ return;
+ SetNewFolder(newFolder);
+ LoadFullPath();
+ RefreshListCtrl();
+ // 17.02: fixed : now we don't select first item
+ // _listView.SetItemState_Selected(_listView.GetFocusedItem());
+ _listView.EnsureVisible(_listView.GetFocusedItem(), false);
+}
+
+void CPanel::OpenAltStreams()
+{
+ CRecordVector<UInt32> indices;
+ Get_ItemIndices_Operated(indices);
+ Int32 realIndex = -1;
+ if (indices.Size() > 1)
+ return;
+ if (indices.Size() == 1)
+ realIndex = (Int32)indices[0];
+
+ if (_folderAltStreams)
+ {
+ CMyComPtr<IFolderFolder> newFolder;
+ _folderAltStreams->BindToAltStreams((UInt32)realIndex, &newFolder);
+ if (newFolder)
+ {
+ CDisableTimerProcessing disableTimerProcessing(*this);
+ CDisableNotify disableNotify(*this);
+ SetNewFolder(newFolder);
+ RefreshListCtrl();
+ return;
+ }
+ return;
+ }
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ UString path;
+ if (realIndex >= 0)
+ path = GetItemFullPath((UInt32)realIndex);
+ else
+ {
+ path = GetFsPath();
+ if (!NName::IsDriveRootPath_SuperAllowed(us2fs(path)))
+ if (!path.IsEmpty() && IS_PATH_SEPAR(path.Back()))
+ path.DeleteBack();
+ }
+
+ path += ':';
+ BindToPathAndRefresh(path);
+ #endif
+}
diff --git a/CPP/7zip/UI/FileManager/PanelItemOpen.cpp b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp
new file mode 100644
index 0000000..bd65aef
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelItemOpen.cpp
@@ -0,0 +1,1869 @@
+// PanelItemOpen.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+
+#include <TlHelp32.h>
+
+#include "../../../Common/IntToString.h"
+
+#include "../../../Common/AutoPtr.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/ProcessUtils.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/PropVariantConv.h"
+
+#include "../../Common/FileStreams.h"
+#include "../../Common/StreamObjects.h"
+
+#include "../Common/ExtractingFilePath.h"
+
+#include "App.h"
+
+#include "FileFolderPluginOpen.h"
+#include "FormatUtils.h"
+#include "LangUtils.h"
+#include "PropertyNameRes.h"
+#include "RegistryUtils.h"
+#include "UpdateCallback100.h"
+
+#include "../GUI/ExtractRes.h"
+
+#include "resource.h"
+
+using namespace NWindows;
+using namespace NSynchronization;
+using namespace NFile;
+using namespace NDir;
+
+extern bool g_RAM_Size_Defined;
+extern UInt64 g_RAM_Size;
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+#define kTempDirPrefix FTEXT("7zO")
+
+// #define SHOW_DEBUG_INFO
+
+#ifdef SHOW_DEBUG_INFO
+ #define DEBUG_PRINT(s) OutputDebugStringA(s);
+ #define DEBUG_PRINT_W(s) OutputDebugStringW(s);
+ #define DEBUG_PRINT_NUM(s, num) { char ttt[32]; ConvertUInt32ToString(num, ttt); OutputDebugStringA(s); OutputDebugStringA(ttt); }
+#else
+ #define DEBUG_PRINT(s)
+ #define DEBUG_PRINT_W(s)
+ #define DEBUG_PRINT_NUM(s, num)
+#endif
+
+
+
+#ifndef UNDER_CE
+
+class CProcessSnapshot
+{
+ HANDLE _handle;
+public:
+ CProcessSnapshot(): _handle(INVALID_HANDLE_VALUE) {}
+ ~CProcessSnapshot() { Close(); }
+
+ bool Close()
+ {
+ if (_handle == INVALID_HANDLE_VALUE)
+ return true;
+ if (!::CloseHandle(_handle))
+ return false;
+ _handle = INVALID_HANDLE_VALUE;
+ return true;
+ }
+
+ bool Create()
+ {
+ _handle = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ return (_handle != INVALID_HANDLE_VALUE);
+ }
+
+ bool GetFirstProcess(PROCESSENTRY32 *pe) { return BOOLToBool(Process32First(_handle, pe)); }
+ bool GetNextProcess(PROCESSENTRY32 *pe) { return BOOLToBool(Process32Next(_handle, pe)); }
+};
+
+#endif
+
+
+/*
+struct COpenExtProg
+{
+ const char *Ext;
+ const char *Prog;
+};
+
+static const COpenExtProg g_Progs[] =
+{
+ { "jpeg jpg png bmp gif", "Microsoft.Photos.exe" },
+ { "html htm pdf", "MicrosoftEdge.exe" },
+ // , { "rrr", "notepad.exe" }
+};
+
+static bool FindExtProg(const char *exts, const char *ext)
+{
+ unsigned len = (unsigned)strlen(ext);
+ for (;;)
+ {
+ const char *p = exts;
+ for (;; p++)
+ {
+ const char c = *p;
+ if (c == 0 || c == ' ')
+ break;
+ }
+ if (len == (unsigned)(p - exts) && IsString1PrefixedByString2(exts, ext))
+ return true;
+ if (*p == 0)
+ return false;
+ exts = p + 1;
+ }
+}
+
+class CPossibleProgs
+{
+public:
+ AStringVector ProgNames;
+
+ void SetFromExtension(const char *ext) // ext must be low case
+ {
+ ProgNames.Clear();
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Progs); i++)
+ if (FindExtProg(g_Progs[i].Ext, ext))
+ {
+ ProgNames.Add(g_Progs[i].Prog);
+ }
+ }
+
+ bool IsFromList(const UString &progName) const
+ {
+ FOR_VECTOR (i, ProgNames)
+ if (progName.IsEqualTo_Ascii_NoCase(ProgNames[i]))
+ return true;
+ return false;
+ }
+};
+*/
+
+
+#ifndef UNDER_CE
+
+EXTERN_C_BEGIN
+
+/*
+GetProcessImageFileName
+ returns the path in device form, rather than drive letters:
+ \Device\HarddiskVolume1\WINDOWS\SysWOW64\notepad.exe
+
+GetModuleFileNameEx works only after Sleep(something). Why?
+ returns the path
+ C:\WINDOWS\system32\NOTEPAD.EXE
+*/
+
+/* Kernel32.dll: Win7, Win2008R2;
+ Psapi.dll: (if PSAPI_VERSION=1) on Win7 and Win2008R2;
+ Psapi.dll: XP, Win2003, Vista, 2008;
+*/
+
+typedef DWORD (WINAPI *Func_GetProcessImageFileNameW)(
+ HANDLE hProcess, LPWSTR lpFilename, DWORD nSize);
+
+typedef DWORD (WINAPI *Func_GetModuleFileNameExW)(
+ HANDLE hProcess, HMODULE hModule, LPWSTR lpFilename, DWORD nSize);
+
+typedef DWORD (WINAPI *Func_GetProcessId)(HANDLE process);
+
+EXTERN_C_END
+
+
+static HMODULE g_Psapi_dll_module;
+
+/*
+static void My_GetProcessFileName_2(HANDLE hProcess, UString &path)
+{
+ path.Empty();
+ const unsigned maxPath = 1024;
+ WCHAR temp[maxPath + 1];
+
+ const char *func_name = "GetModuleFileNameExW";
+ Func_GetModuleFileNameExW my_func = (Func_GetModuleFileNameExW)
+ ::GetProcAddress(::GetModuleHandleA("kernel32.dll"), func_name);
+ if (!my_func)
+ {
+ if (!g_Psapi_dll_module)
+ g_Psapi_dll_module = LoadLibraryW(L"Psapi.dll");
+ if (g_Psapi_dll_module)
+ my_func = (Func_GetModuleFileNameExW)::GetProcAddress(g_Psapi_dll_module, func_name);
+ }
+ if (my_func)
+ {
+ // DWORD num = GetModuleFileNameEx(hProcess, NULL, temp, maxPath);
+ DWORD num = my_func(hProcess, NULL, temp, maxPath);
+ if (num != 0)
+ path = temp;
+ }
+ // FreeLibrary(lib);
+}
+*/
+
+static void My_GetProcessFileName(HANDLE hProcess, UString &path)
+{
+ path.Empty();
+ const unsigned maxPath = 1024;
+ WCHAR temp[maxPath + 1];
+
+ const char *func_name =
+ "GetProcessImageFileNameW";
+ Func_GetProcessImageFileNameW my_func = Z7_GET_PROC_ADDRESS(
+ Func_GetProcessImageFileNameW, ::GetModuleHandleA("kernel32.dll"), func_name);
+
+ if (!my_func)
+ {
+ if (!g_Psapi_dll_module)
+ g_Psapi_dll_module = LoadLibraryW(L"Psapi.dll");
+ if (g_Psapi_dll_module)
+ my_func = Z7_GET_PROC_ADDRESS(
+ Func_GetProcessImageFileNameW, g_Psapi_dll_module, func_name);
+ }
+
+ if (my_func)
+ {
+ const DWORD num =
+ // GetProcessImageFileNameW(hProcess, temp, maxPath);
+ my_func(hProcess, temp, maxPath);
+ if (num != 0)
+ path = temp;
+ }
+ // FreeLibrary(lib);
+}
+
+struct CSnapshotProcess
+{
+ DWORD Id;
+ DWORD ParentId;
+ UString Name;
+};
+
+static void GetSnapshot(CObjectVector<CSnapshotProcess> &items)
+{
+ items.Clear();
+
+ CProcessSnapshot snapshot;
+ if (!snapshot.Create())
+ return;
+
+ DEBUG_PRINT("snapshot.Create() OK");
+ PROCESSENTRY32 pe;
+ CSnapshotProcess item;
+ memset(&pe, 0, sizeof(pe));
+ pe.dwSize = sizeof(pe);
+ BOOL res = snapshot.GetFirstProcess(&pe);
+ while (res)
+ {
+ item.Id = pe.th32ProcessID;
+ item.ParentId = pe.th32ParentProcessID;
+ item.Name = GetUnicodeString(pe.szExeFile);
+ items.Add(item);
+ res = snapshot.GetNextProcess(&pe);
+ }
+}
+
+#endif
+
+
+class CChildProcesses
+{
+ #ifndef UNDER_CE
+ CRecordVector<DWORD> _ids;
+ #endif
+
+public:
+ // bool ProgsWereUsed;
+ CRecordVector<HANDLE> Handles;
+ CRecordVector<bool> NeedWait;
+ // UStringVector Names;
+
+ #ifndef UNDER_CE
+ UString Path;
+ #endif
+
+ // CChildProcesses(): ProgsWereUsed(false) {}
+ ~CChildProcesses() { CloseAll(); }
+ void DisableWait(unsigned index) { NeedWait[index] = false; }
+
+ void CloseAll()
+ {
+ FOR_VECTOR (i, Handles)
+ {
+ HANDLE h = Handles[i];
+ if (h != NULL)
+ CloseHandle(h);
+ }
+
+ Handles.Clear();
+ NeedWait.Clear();
+ // Names.Clear();
+
+ #ifndef UNDER_CE
+ // Path.Empty();
+ _ids.Clear();
+ #endif
+ }
+
+ void SetMainProcess(HANDLE h)
+ {
+ #ifndef UNDER_CE
+ const
+ Func_GetProcessId func = Z7_GET_PROC_ADDRESS(
+ Func_GetProcessId, ::GetModuleHandleA("kernel32.dll"),
+ "GetProcessId");
+ if (func)
+ {
+ const DWORD id = func(h);
+ if (id != 0)
+ _ids.AddToUniqueSorted(id);
+ }
+
+ My_GetProcessFileName(h, Path);
+ DEBUG_PRINT_W(Path);
+
+ #endif
+
+ Handles.Add(h);
+ NeedWait.Add(true);
+ }
+
+ #ifndef UNDER_CE
+
+ void Update(bool needFindProcessByPath /* , const CPossibleProgs &progs */)
+ {
+ /*
+ if (_ids.IsEmpty())
+ return;
+ */
+
+ CObjectVector<CSnapshotProcess> sps;
+ GetSnapshot(sps);
+
+ const int separ = Path.ReverseFind_PathSepar();
+ const UString mainName = Path.Ptr((unsigned)(separ + 1));
+ if (mainName.IsEmpty())
+ needFindProcessByPath = false;
+
+ const DWORD currentProcessId = GetCurrentProcessId();
+
+ for (;;)
+ {
+ bool wasAdded = false;
+
+ FOR_VECTOR (i, sps)
+ {
+ const CSnapshotProcess &sp = sps[i];
+ const DWORD id = sp.Id;
+
+ if (id == currentProcessId)
+ continue;
+ if (_ids.FindInSorted(id) >= 0)
+ continue;
+
+ bool isSameName = false;
+ const UString &name = sp.Name;
+
+ if (needFindProcessByPath)
+ isSameName = mainName.IsEqualTo_NoCase(name);
+
+ bool needAdd = false;
+ // bool isFromProgs = false;
+
+ if (isSameName || _ids.FindInSorted(sp.ParentId) >= 0)
+ needAdd = true;
+ /*
+ else if (progs.IsFromList(name))
+ {
+ needAdd = true;
+ isFromProgs = true;
+ }
+ */
+
+ if (needAdd)
+ {
+ DEBUG_PRINT("----- OpenProcess -----");
+ DEBUG_PRINT_W(name);
+ HANDLE hProcess = OpenProcess(SYNCHRONIZE, FALSE, id);
+ if (hProcess)
+ {
+ DEBUG_PRINT("----- OpenProcess OK -----");
+ // if (!isFromProgs)
+ _ids.AddToUniqueSorted(id);
+ Handles.Add(hProcess);
+ NeedWait.Add(true);
+ // Names.Add(name);
+ wasAdded = true;
+ // ProgsWereUsed = isFromProgs;
+ }
+ }
+ }
+
+ if (!wasAdded)
+ break;
+ }
+ }
+
+ #endif
+};
+
+
+struct CTmpProcessInfo: public CTempFileInfo
+{
+ CChildProcesses Processes;
+ HWND Window;
+ UString FullPathFolderPrefix;
+ bool UsePassword;
+ UString Password;
+
+ bool ReadOnly;
+
+ CTmpProcessInfo(): UsePassword(false), ReadOnly(false) {}
+};
+
+
+class CTmpProcessInfoRelease
+{
+ CTmpProcessInfo *_tmpProcessInfo;
+public:
+ bool _needDelete;
+ CTmpProcessInfoRelease(CTmpProcessInfo &tpi):
+ _tmpProcessInfo(&tpi), _needDelete(true) {}
+ ~CTmpProcessInfoRelease()
+ {
+ if (_needDelete)
+ _tmpProcessInfo->DeleteDirAndFile();
+ }
+};
+
+void GetFolderError(CMyComPtr<IFolderFolder> &folder, UString &s);
+
+
+HRESULT CPanel::OpenAsArc(IInStream *inStream,
+ const CTempFileInfo &tempFileInfo,
+ const UString &virtualFilePath,
+ const UString &arcFormat,
+ COpenResult &openRes)
+{
+ openRes.Encrypted = false;
+ CFolderLink folderLink;
+ (CTempFileInfo &)folderLink = tempFileInfo;
+
+ if (inStream)
+ folderLink.IsVirtual = true;
+ else
+ {
+ if (!folderLink.FileInfo.Find(folderLink.FilePath))
+ return GetLastError_noZero_HRESULT();
+ if (folderLink.FileInfo.IsDir())
+ return S_FALSE;
+ folderLink.IsVirtual = false;
+ }
+
+ folderLink.VirtualPath = virtualFilePath;
+
+ CFfpOpen ffp;
+ const HRESULT res = ffp.OpenFileFolderPlugin(inStream,
+ folderLink.FilePath.IsEmpty() ? us2fs(virtualFilePath) : folderLink.FilePath,
+ arcFormat, GetParent());
+
+ openRes.Encrypted = ffp.Encrypted;
+ openRes.ErrorMessage = ffp.ErrorMessage;
+
+ RINOK(res)
+
+ folderLink.Password = ffp.Password;
+ folderLink.UsePassword = ffp.Encrypted;
+
+ if (_folder)
+ folderLink.ParentFolderPath = GetFolderPath(_folder);
+ else
+ folderLink.ParentFolderPath = _currentFolderPrefix;
+
+ if (!_parentFolders.IsEmpty())
+ folderLink.ParentFolder = _folder;
+
+ _parentFolders.Add(folderLink);
+ _parentFolders.Back().Library.Attach(_library.Detach());
+
+ ReleaseFolder();
+ _library.Free();
+ SetNewFolder(ffp.Folder);
+ _library.Attach(ffp.Library.Detach());
+
+ _flatMode = _flatModeForArc;
+
+ _thereAreDeletedItems = false;
+
+ if (!openRes.ErrorMessage.IsEmpty())
+ MessageBox_Error(openRes.ErrorMessage);
+ /*
+ UString s;
+ GetFolderError(_folder, s);
+ if (!s.IsEmpty())
+ MessageBox_Error(s);
+ */
+ // we don't show error here by some reasons:
+ // after MessageBox_Warning it throws exception in nested archives in Debug Mode. why ?.
+ // MessageBox_Warning(L"test error");
+
+ return S_OK;
+}
+
+
+HRESULT CPanel::OpenAsArc_Msg(IInStream *inStream,
+ const CTempFileInfo &tempFileInfo,
+ const UString &virtualFilePath,
+ const UString &arcFormat
+ // , bool &encrypted
+ // , bool showErrorMessage
+ )
+{
+ COpenResult opRes;
+
+ HRESULT res = OpenAsArc(inStream, tempFileInfo, virtualFilePath, arcFormat, opRes);
+
+ if (res == S_OK)
+ return res;
+ if (res == E_ABORT)
+ return res;
+
+ // if (showErrorMessage)
+ if (opRes.Encrypted || res != S_FALSE) // 17.01 : we show message also for (res != S_FALSE)
+ {
+ UString message;
+ if (res == S_FALSE)
+ {
+ message = MyFormatNew(
+ opRes.Encrypted ?
+ IDS_CANT_OPEN_ENCRYPTED_ARCHIVE :
+ IDS_CANT_OPEN_ARCHIVE,
+ virtualFilePath);
+ }
+ else
+ message = HResultToMessage(res);
+ MessageBox_Error(message);
+ }
+
+ return res;
+}
+
+
+HRESULT CPanel::OpenAsArc_Name(const UString &relPath, const UString &arcFormat
+ // , bool &encrypted,
+ // , bool showErrorMessage
+ )
+{
+ CTempFileInfo tfi;
+ tfi.RelPath = relPath;
+ tfi.FolderPath = us2fs(GetFsPath());
+ const UString fullPath = GetFsPath() + relPath;
+ tfi.FilePath = us2fs(fullPath);
+ return OpenAsArc_Msg(NULL, tfi, fullPath, arcFormat /* , encrypted, showErrorMessage */);
+}
+
+
+HRESULT CPanel::OpenAsArc_Index(unsigned index, const wchar_t *type
+ // , bool showErrorMessage
+ )
+{
+ CDisableTimerProcessing disableTimerProcessing1(*this);
+ CDisableNotify disableNotify(*this);
+
+ HRESULT res = OpenAsArc_Name(GetItemRelPath2(index), type ? type : L"" /* , encrypted, showErrorMessage */);
+ if (res != S_OK)
+ {
+ RefreshTitle(true); // in case of error we must refresh changed title of 7zFM
+ return res;
+ }
+ RefreshListCtrl();
+ return S_OK;
+}
+
+
+HRESULT CPanel::OpenParentArchiveFolder()
+{
+ CDisableTimerProcessing disableTimerProcessing(*this);
+ CDisableNotify disableNotify(*this);
+ if (_parentFolders.Size() < 2)
+ return S_OK;
+ const CFolderLink &folderLinkPrev = _parentFolders[_parentFolders.Size() - 2];
+ const CFolderLink &folderLink = _parentFolders.Back();
+ NFind::CFileInfo newFileInfo;
+ if (newFileInfo.Find(folderLink.FilePath))
+ {
+ if (folderLink.WasChanged(newFileInfo))
+ {
+ UString message = MyFormatNew(IDS_WANT_UPDATE_MODIFIED_FILE, folderLink.RelPath);
+ if (::MessageBoxW((HWND)*this, message, L"7-Zip", MB_OKCANCEL | MB_ICONQUESTION) == IDOK)
+ {
+ if (OnOpenItemChanged(folderLink.FileIndex, fs2us(folderLink.FilePath),
+ folderLinkPrev.UsePassword, folderLinkPrev.Password) != S_OK)
+ {
+ ::MessageBoxW((HWND)*this, MyFormatNew(IDS_CANNOT_UPDATE_FILE,
+ fs2us(folderLink.FilePath)), L"7-Zip", MB_OK | MB_ICONSTOP);
+ return S_OK;
+ }
+ }
+ }
+ }
+ folderLink.DeleteDirAndFile();
+ return S_OK;
+}
+
+
+static const char * const kExeExtensions =
+ " exe bat ps1 com"
+ " ";
+
+static const char * const kStartExtensions =
+ #ifdef UNDER_CE
+ " cab"
+ #endif
+ " exe bat ps1 com"
+ " chm"
+ " msi doc dot xls ppt pps wps wpt wks xlr wdb vsd pub"
+
+ " docx docm dotx dotm xlsx xlsm xltx xltm xlsb xps"
+ " xlam pptx pptm potx potm ppam ppsx ppsm vsdx xsn"
+ " mpp"
+ " msg"
+ " dwf"
+
+ " flv swf"
+
+ " epub"
+ " odt ods"
+ " wb3"
+ " pdf"
+ " ps"
+ " txt"
+ " xml xsd xsl xslt hxk hxc htm html xhtml xht mht mhtml htw asp aspx css cgi jsp shtml"
+ " h hpp hxx c cpp cxx m mm go swift"
+ " awk sed hta js json php php3 php4 php5 phptml pl pm py pyo rb tcl ts vbs"
+ " asm"
+ " mak clw csproj vcproj sln dsp dsw"
+ " ";
+
+// bool FindExt(const char *p, const UString &name, AString &s);
+bool FindExt(const char *p, const UString &name, CStringFinder &finder);
+
+static bool DoItemAlwaysStart(const UString &name)
+{
+ CStringFinder finder;
+ return FindExt(kStartExtensions, name, finder);
+}
+
+UString GetQuotedString(const UString &s);
+
+
+void SplitCmdLineSmart(const UString &cmd, UString &prg, UString &params);
+void SplitCmdLineSmart(const UString &cmd, UString &prg, UString &params)
+{
+ params.Empty();
+ prg = cmd;
+ prg.Trim();
+ if (prg.Len() >= 2 && prg[0] == L'"')
+ {
+ int pos = prg.Find(L'"', 1);
+ if (pos >= 0)
+ {
+ if ((unsigned)(pos + 1) == prg.Len() || prg[pos + 1] == ' ')
+ {
+ params = prg.Ptr((unsigned)(pos + 1));
+ params.Trim();
+ prg.DeleteFrom((unsigned)pos);
+ prg.DeleteFrontal(1);
+ }
+ }
+ }
+}
+
+
+static WRes StartAppWithParams(const UString &cmd, const UStringVector &paramVector, CProcess &process)
+{
+ UString param;
+ UString prg;
+
+ SplitCmdLineSmart(cmd, prg, param);
+
+ param.Trim();
+
+ // int pos = params.Find(L"%1");
+
+ FOR_VECTOR (i, paramVector)
+ {
+ if (!param.IsEmpty() && param.Back() != ' ')
+ param.Add_Space();
+ param += GetQuotedString(paramVector[i]);
+ }
+
+ return process.Create(prg, param, NULL);
+}
+
+
+static HRESULT StartEditApplication(const UString &path, bool useEditor, HWND window, CProcess &process)
+{
+ UString command;
+ ReadRegEditor(useEditor, command);
+ if (command.IsEmpty())
+ {
+ #ifdef UNDER_CE
+ command = "\\Windows\\";
+ #else
+ FString winDir;
+ if (!GetWindowsDir(winDir))
+ return 0;
+ NName::NormalizeDirPathPrefix(winDir);
+ command = fs2us(winDir);
+ #endif
+ command += "notepad.exe";
+ }
+
+ UStringVector params;
+ params.Add(path);
+
+ const WRes res = StartAppWithParams(command, params, process);
+ if (res != 0)
+ ::MessageBoxW(window, LangString(IDS_CANNOT_START_EDITOR), L"7-Zip", MB_OK | MB_ICONSTOP);
+ return HRESULT_FROM_WIN32(res);
+}
+
+
+void CApp::DiffFiles()
+{
+ const CPanel &panel = GetFocusedPanel();
+
+ if (!panel.Is_IO_FS_Folder())
+ {
+ panel.MessageBox_Error_UnsupportOperation();
+ return;
+ }
+
+ CRecordVector<UInt32> indices;
+ panel.Get_ItemIndices_Selected(indices);
+
+ UString path1, path2;
+ if (indices.Size() == 2)
+ {
+ path1 = panel.GetItemFullPath(indices[0]);
+ path2 = panel.GetItemFullPath(indices[1]);
+ }
+ else if (indices.Size() == 1 && NumPanels >= 2)
+ {
+ const CPanel &destPanel = Panels[1 - LastFocusedPanel];
+
+ if (!destPanel.Is_IO_FS_Folder())
+ {
+ panel.MessageBox_Error_UnsupportOperation();
+ return;
+ }
+
+ path1 = panel.GetItemFullPath(indices[0]);
+ CRecordVector<UInt32> indices2;
+ destPanel.Get_ItemIndices_Selected(indices2);
+ if (indices2.Size() == 1)
+ path2 = destPanel.GetItemFullPath(indices2[0]);
+ else
+ {
+ UString relPath = panel.GetItemRelPath2(indices[0]);
+ if (panel._flatMode && !destPanel._flatMode)
+ relPath = panel.GetItemName(indices[0]);
+ path2 = destPanel._currentFolderPrefix + relPath;
+ }
+ }
+ else
+ return;
+
+ DiffFiles(path1, path2);
+}
+
+void CApp::DiffFiles(const UString &path1, const UString &path2)
+{
+ UString command;
+ ReadRegDiff(command);
+ if (command.IsEmpty())
+ return;
+
+ UStringVector params;
+ params.Add(path1);
+ params.Add(path2);
+
+ WRes res;
+ {
+ CProcess process;
+ res = StartAppWithParams(command, params, process);
+ }
+ if (res == 0)
+ return;
+ ::MessageBoxW(_window, LangString(IDS_CANNOT_START_EDITOR), L"7-Zip", MB_OK | MB_ICONSTOP);
+}
+
+
+#ifndef _UNICODE
+typedef BOOL (WINAPI * Func_ShellExecuteExW)(LPSHELLEXECUTEINFOW lpExecInfo);
+#endif
+
+static HRESULT StartApplication(const UString &dir, const UString &path, HWND window, CProcess &process)
+{
+ UString path2 = path;
+
+ #ifdef _WIN32
+ {
+ int dot = path2.ReverseFind_Dot();
+ int separ = path2.ReverseFind_PathSepar();
+ if (dot < 0 || dot < separ)
+ path2.Add_Dot();
+ }
+ #endif
+
+ UINT32 result;
+
+ #ifndef _UNICODE
+ if (g_IsNT)
+ {
+ SHELLEXECUTEINFOW execInfo;
+ execInfo.cbSize = sizeof(execInfo);
+ execInfo.fMask = SEE_MASK_NOCLOSEPROCESS | SEE_MASK_FLAG_DDEWAIT;
+ execInfo.hwnd = NULL;
+ execInfo.lpVerb = NULL;
+ execInfo.lpFile = path2;
+ execInfo.lpParameters = NULL;
+ execInfo.lpDirectory = dir.IsEmpty() ? NULL : (LPCWSTR)dir;
+ execInfo.nShow = SW_SHOWNORMAL;
+ execInfo.hProcess = NULL;
+ const
+ Func_ShellExecuteExW
+ f_ShellExecuteExW = Z7_GET_PROC_ADDRESS(
+ Func_ShellExecuteExW, ::GetModuleHandleW(L"shell32.dll"),
+ "ShellExecuteExW");
+ if (!f_ShellExecuteExW)
+ return 0;
+ f_ShellExecuteExW(&execInfo);
+ result = (UINT32)(UINT_PTR)execInfo.hInstApp;
+ process.Attach(execInfo.hProcess);
+ }
+ else
+ #endif
+ {
+ SHELLEXECUTEINFO execInfo;
+ execInfo.cbSize = sizeof(execInfo);
+ execInfo.fMask = SEE_MASK_NOCLOSEPROCESS
+ #ifndef UNDER_CE
+ | SEE_MASK_FLAG_DDEWAIT
+ #endif
+ ;
+ execInfo.hwnd = NULL;
+ execInfo.lpVerb = NULL;
+ const CSysString sysPath (GetSystemString(path2));
+ const CSysString sysDir (GetSystemString(dir));
+ execInfo.lpFile = sysPath;
+ execInfo.lpParameters = NULL;
+ execInfo.lpDirectory =
+ #ifdef UNDER_CE
+ NULL
+ #else
+ sysDir.IsEmpty() ? NULL : (LPCTSTR)sysDir
+ #endif
+ ;
+ execInfo.nShow = SW_SHOWNORMAL;
+ execInfo.hProcess = NULL;
+ ::ShellExecuteEx(&execInfo);
+ result = (UINT32)(UINT_PTR)execInfo.hInstApp;
+ process.Attach(execInfo.hProcess);
+ }
+
+
+ DEBUG_PRINT_NUM("-- ShellExecuteEx -- execInfo.hInstApp = ", result)
+
+ if (result <= 32)
+ {
+ switch (result)
+ {
+ case SE_ERR_NOASSOC:
+ ::MessageBoxW(window,
+ NError::MyFormatMessage(::GetLastError()),
+ // L"There is no application associated with the given file name extension",
+ L"7-Zip", MB_OK | MB_ICONSTOP);
+ }
+
+ return E_FAIL; // fixed in 15.13. Can we use it for any Windows version?
+ }
+
+ return S_OK;
+}
+
+static void StartApplicationDontWait(const UString &dir, const UString &path, HWND window)
+{
+ CProcess process;
+ StartApplication(dir, path, window, process);
+}
+
+void CPanel::EditItem(unsigned index, bool useEditor)
+{
+ if (!_parentFolders.IsEmpty())
+ {
+ OpenItemInArchive(index, false, true, true, useEditor);
+ return;
+ }
+ CProcess process;
+ StartEditApplication(GetItemFullPath(index), useEditor, (HWND)*this, process);
+}
+
+
+void CPanel::OpenFolderExternal(unsigned index)
+{
+ UString prefix = GetFsPath();
+ UString path = prefix;
+
+ if (index == kParentIndex)
+ {
+ if (prefix.IsEmpty())
+ return;
+ const wchar_t c = prefix.Back();
+ if (!IS_PATH_SEPAR(c) && c != ':')
+ return;
+ prefix.DeleteBack();
+ int pos = prefix.ReverseFind_PathSepar();
+ if (pos < 0)
+ return;
+ prefix.DeleteFrom((unsigned)(pos + 1));
+ path = prefix;
+ }
+ else
+ {
+ path += GetItemRelPath(index);
+ path.Add_PathSepar();
+ }
+
+ StartApplicationDontWait(prefix, path, (HWND)*this);
+}
+
+
+bool CPanel::IsVirus_Message(const UString &name)
+{
+ UString name2;
+
+ const wchar_t cRLO = (wchar_t)0x202E;
+ bool isVirus = false;
+ bool isSpaceError = false;
+ name2 = name;
+
+ if (name2.Find(cRLO) >= 0)
+ {
+ const UString badString(cRLO);
+ name2.Replace(badString, L"[RLO]");
+ isVirus = true;
+ }
+ {
+ const wchar_t * const kVirusSpaces = L" ";
+ // const unsigned kNumSpaces = strlen(kVirusSpaces);
+ for (;;)
+ {
+ int pos = name2.Find(kVirusSpaces);
+ if (pos < 0)
+ break;
+ isVirus = true;
+ isSpaceError = true;
+ name2.Replace(kVirusSpaces, L" ");
+ }
+ }
+
+ #ifdef _WIN32
+ {
+ unsigned i;
+ for (i = name2.Len(); i != 0;)
+ {
+ wchar_t c = name2[i - 1];
+ if (c != '.' && c != ' ')
+ break;
+ i--;
+ name2.ReplaceOneCharAtPos(i, '_');
+ }
+ if (i != name2.Len())
+ {
+ CStringFinder finder;
+ UString name3 = name2;
+ name3.DeleteFrom(i);
+ if (FindExt(kExeExtensions, name3, finder))
+ isVirus = true;
+ }
+ }
+ #endif
+
+ if (!isVirus)
+ return false;
+
+ UString s = LangString(IDS_VIRUS);
+
+ if (!isSpaceError)
+ {
+ const int pos1 = s.Find(L'(');
+ if (pos1 >= 0)
+ {
+ const int pos2 = s.Find(L')', (unsigned)pos1 + 1);
+ if (pos2 >= 0)
+ {
+ s.Delete((unsigned)pos1, (unsigned)pos2 + 1 - (unsigned)pos1);
+ if (pos1 > 0 && s[pos1 - 1] == ' ' && s[pos1] == '.')
+ s.Delete(pos1 - 1);
+ }
+ }
+ }
+
+ UString name3 = name;
+ name3.Replace(L'\n', L'_');
+ name2.Replace(L'\n', L'_');
+
+ s.Add_LF(); s += name2;
+ s.Add_LF(); s += name3;
+
+ MessageBox_Error(s);
+ return true;
+}
+
+
+void CPanel::OpenItem(unsigned index, bool tryInternal, bool tryExternal, const wchar_t *type)
+{
+ CDisableTimerProcessing disableTimerProcessing(*this);
+ const UString name = GetItemRelPath2(index);
+
+ if (tryExternal)
+ if (IsVirus_Message(name))
+ return;
+
+ if (!_parentFolders.IsEmpty())
+ {
+ OpenItemInArchive(index, tryInternal, tryExternal, false, false, type);
+ return;
+ }
+
+ CDisableNotify disableNotify(*this);
+ UString prefix = GetFsPath();
+ UString fullPath = prefix + name;
+
+ if (tryInternal)
+ if (!tryExternal || !DoItemAlwaysStart(name))
+ {
+ HRESULT res = OpenAsArc_Index(index, type
+ // , true
+ );
+ disableNotify.Restore(); // we must restore to allow text notification update
+ InvalidateList();
+ if (res == S_OK || res == E_ABORT)
+ return;
+ if (res != S_FALSE)
+ {
+ MessageBox_Error_HRESULT(res);
+ return;
+ }
+ }
+
+ if (tryExternal)
+ {
+ // SetCurrentDirectory opens HANDLE to folder!!!
+ // NDirectory::MySetCurrentDirectory(prefix);
+ StartApplicationDontWait(prefix, fullPath, (HWND)*this);
+ }
+}
+
+class CThreadCopyFrom: public CProgressThreadVirt
+{
+ HRESULT ProcessVirt() Z7_override;
+public:
+ UString FullPath;
+ UInt32 ItemIndex;
+
+ CMyComPtr<IFolderOperations> FolderOperations;
+ CMyComPtr<IProgress> UpdateCallback;
+ CUpdateCallback100Imp *UpdateCallbackSpec;
+};
+
+HRESULT CThreadCopyFrom::ProcessVirt()
+{
+ return FolderOperations->CopyFromFile(ItemIndex, FullPath, UpdateCallback);
+}
+
+HRESULT CPanel::OnOpenItemChanged(UInt32 index, const wchar_t *fullFilePath,
+ bool usePassword, const UString &password)
+{
+ if (!_folderOperations)
+ {
+ MessageBox_Error_UnsupportOperation();
+ return E_FAIL;
+ }
+
+ CThreadCopyFrom t;
+ t.UpdateCallbackSpec = new CUpdateCallback100Imp;
+ t.UpdateCallback = t.UpdateCallbackSpec;
+ t.UpdateCallbackSpec->ProgressDialog = &t;
+ t.ItemIndex = index;
+ t.FullPath = fullFilePath;
+ t.FolderOperations = _folderOperations;
+
+ t.UpdateCallbackSpec->Init();
+ t.UpdateCallbackSpec->PasswordIsDefined = usePassword;
+ t.UpdateCallbackSpec->Password = password;
+
+
+ RINOK(t.Create(GetItemName(index), (HWND)*this))
+ return t.Result;
+}
+
+LRESULT CPanel::OnOpenItemChanged(LPARAM lParam)
+{
+ // DEBUG_PRINT_NUM("OnOpenItemChanged", GetCurrentThreadId());
+
+ CTmpProcessInfo &tpi = *(CTmpProcessInfo *)lParam;
+ if (tpi.FullPathFolderPrefix != _currentFolderPrefix)
+ return 0;
+ UInt32 fileIndex = tpi.FileIndex;
+ UInt32 numItems;
+ _folder->GetNumberOfItems(&numItems);
+
+ // This code is not 100% OK for cases when there are several files with
+ // tpi.RelPath name and there are changes in archive before update.
+ // So tpi.FileIndex can point to another file.
+
+ if (fileIndex >= numItems || GetItemRelPath(fileIndex) != tpi.RelPath)
+ {
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ if (GetItemRelPath(i) == tpi.RelPath)
+ break;
+ if (i == numItems)
+ return 0;
+ fileIndex = i;
+ }
+
+ CSelectedState state;
+ SaveSelectedState(state);
+
+ CDisableNotify disableNotify(*this); // do we need it??
+
+ HRESULT result = OnOpenItemChanged(fileIndex, fs2us(tpi.FilePath), tpi.UsePassword, tpi.Password);
+ RefreshListCtrl(state);
+ if (result != S_OK)
+ return 0;
+ return 1;
+}
+
+
+CExitEventLauncher g_ExitEventLauncher;
+
+void CExitEventLauncher::Exit(bool hardExit)
+{
+ if (_needExit)
+ {
+ _exitEvent.Set();
+ _needExit = false;
+ }
+
+ if (_numActiveThreads == 0)
+ return;
+
+ FOR_VECTOR (i, _threads)
+ {
+ ::CThread &th = _threads[i];
+ DWORD wait = (hardExit ? 100 : INFINITE);
+ if (Thread_WasCreated(&th))
+ {
+ DWORD waitResult = WaitForSingleObject(th, wait);
+ // Thread_Wait(&th);
+ if (waitResult == WAIT_TIMEOUT)
+ wait = 1;
+ if (!hardExit && waitResult != WAIT_OBJECT_0)
+ continue;
+ Thread_Close(&th);
+ _numActiveThreads--;
+ }
+ }
+}
+
+
+
+static THREAD_FUNC_DECL MyThreadFunction(void *param)
+{
+ DEBUG_PRINT("==== MyThreadFunction ====");
+
+ CMyAutoPtr<CTmpProcessInfo> tmpProcessInfoPtr((CTmpProcessInfo *)param);
+ CTmpProcessInfo *tpi = tmpProcessInfoPtr.get();
+ CChildProcesses &processes = tpi->Processes;
+
+ bool mainProcessWasSet = !processes.Handles.IsEmpty();
+
+ bool isComplexMode = true;
+
+ if (!processes.Handles.IsEmpty())
+ {
+
+ const DWORD startTime = GetTickCount();
+
+ /*
+ CPossibleProgs progs;
+ {
+ const UString &name = tpi->RelPath;
+ int slashPos = name.ReverseFind_PathSepar();
+ int dotPos = name.ReverseFind_Dot();
+ if (dotPos > slashPos)
+ {
+ const UString ext = name.Ptr(dotPos + 1);
+ AString extA = UnicodeStringToMultiByte(ext);
+ extA.MakeLower_Ascii();
+ progs.SetFromExtension(extA);
+ }
+ }
+ */
+
+ bool firstPass = true;
+
+ for (;;)
+ {
+ CRecordVector<HANDLE> handles;
+ CUIntVector indices;
+
+ FOR_VECTOR (i, processes.Handles)
+ {
+ if (handles.Size() > 60)
+ break;
+ if (processes.NeedWait[i])
+ {
+ handles.Add(processes.Handles[i]);
+ indices.Add(i);
+ }
+ }
+
+ bool needFindProcessByPath = false;
+
+ if (handles.IsEmpty())
+ {
+ if (!firstPass)
+ break;
+ }
+ else
+ {
+ handles.Add(g_ExitEventLauncher._exitEvent);
+
+ DWORD waitResult = WaitForMultiObj_Any_Infinite(handles.Size(), &handles.Front());
+
+ waitResult -= WAIT_OBJECT_0;
+
+ if (waitResult >= handles.Size() - 1)
+ {
+ processes.CloseAll();
+ /*
+ if (waitResult == handles.Size() - 1)
+ {
+ // exit event
+ // we want to delete temp files, if progs were used
+ if (processes.ProgsWereUsed)
+ break;
+ }
+ */
+ return waitResult >= (DWORD)handles.Size() ? 1 : 0;
+ }
+
+ if (firstPass && indices.Size() == 1)
+ {
+ const DWORD curTime = GetTickCount() - startTime;
+
+ /*
+ if (curTime > 5 * 1000)
+ progs.ProgNames.Clear();
+ */
+
+ needFindProcessByPath = (curTime < 2 * 1000);
+
+ if (needFindProcessByPath)
+ {
+ NFind::CFileInfo newFileInfo;
+ if (newFileInfo.Find(tpi->FilePath))
+ if (tpi->WasChanged(newFileInfo))
+ needFindProcessByPath = false;
+ }
+
+ DEBUG_PRINT_NUM(" -- firstPass -- time = ", curTime)
+ }
+
+ processes.DisableWait(indices[(unsigned)waitResult]);
+ }
+
+ firstPass = false;
+
+ // Sleep(300);
+ #ifndef UNDER_CE
+ processes.Update(needFindProcessByPath /* , progs */);
+ #endif
+ }
+
+
+ const DWORD curTime = GetTickCount() - startTime;
+
+ DEBUG_PRINT_NUM("after time = ", curTime)
+
+ processes.CloseAll();
+
+ isComplexMode = (curTime < 2 * 1000);
+
+ }
+
+ bool needCheckTimestamp = true;
+
+ for (;;)
+ {
+ NFind::CFileInfo newFileInfo;
+
+ if (!newFileInfo.Find(tpi->FilePath))
+ break;
+
+ if (mainProcessWasSet)
+ {
+ if (tpi->WasChanged(newFileInfo))
+ {
+ UString m = MyFormatNew(IDS_CANNOT_UPDATE_FILE, fs2us(tpi->FilePath));
+ if (tpi->ReadOnly)
+ {
+ m.Add_LF();
+ AddLangString(m, IDS_PROP_READ_ONLY);
+ m.Add_LF();
+ m += tpi->FullPathFolderPrefix;
+ ::MessageBoxW(g_HWND, m, L"7-Zip", MB_OK | MB_ICONSTOP);
+ return 0;
+ }
+ {
+ const UString message = MyFormatNew(IDS_WANT_UPDATE_MODIFIED_FILE, tpi->RelPath);
+ if (::MessageBoxW(g_HWND, message, L"7-Zip", MB_OKCANCEL | MB_ICONQUESTION) == IDOK)
+ {
+ // DEBUG_PRINT_NUM("SendMessage", GetCurrentThreadId());
+ if (SendMessage(tpi->Window, kOpenItemChanged, 0, (LONG_PTR)tpi) != 1)
+ {
+ ::MessageBoxW(g_HWND, m, L"7-Zip", MB_OK | MB_ICONSTOP);
+ return 0;
+ }
+ }
+ needCheckTimestamp = false;
+ break;
+ }
+ }
+
+ if (!isComplexMode)
+ break;
+ }
+
+ // DEBUG_PRINT("WaitForSingleObject");
+ DWORD waitResult = ::WaitForSingleObject(g_ExitEventLauncher._exitEvent, INFINITE);
+ // DEBUG_PRINT("---");
+
+ if (waitResult == WAIT_OBJECT_0)
+ break;
+
+ return 1;
+ }
+
+ {
+ NFind::CFileInfo newFileInfo;
+
+ bool finded = newFileInfo.Find(tpi->FilePath);
+
+ if (!needCheckTimestamp || !finded || !tpi->WasChanged(newFileInfo))
+ {
+ DEBUG_PRINT("Delete Temp file");
+ tpi->DeleteDirAndFile();
+ }
+ }
+
+ return 0;
+}
+
+
+/*
+#if defined(_WIN32) && !defined(UNDER_CE)
+static const FChar * const k_ZoneId_StreamName = FTEXT(":Zone.Identifier");
+#endif
+
+
+#ifndef UNDER_CE
+
+static void ReadZoneFile(CFSTR fileName, CByteBuffer &buf)
+{
+ buf.Free();
+ NIO::CInFile file;
+ if (!file.Open(fileName))
+ return;
+ UInt64 fileSize;
+ if (!file.GetLength(fileSize))
+ return;
+ if (fileSize == 0 || fileSize >= ((UInt32)1 << 20))
+ return;
+ buf.Alloc((size_t)fileSize);
+ size_t processed;
+ if (file.ReadFull(buf, (size_t)fileSize, processed) && processed == fileSize)
+ return;
+ buf.Free();
+}
+
+static bool WriteZoneFile(CFSTR fileName, const CByteBuffer &buf)
+{
+ NIO::COutFile file;
+ if (!file.Create(fileName, true))
+ return false;
+ UInt32 processed;
+ if (!file.Write(buf, (UInt32)buf.Size(), processed))
+ return false;
+ return processed == buf.Size();
+}
+
+#endif
+*/
+
+/*
+Z7_CLASS_IMP_COM_1(
+ CBufSeqOutStream_WithFile
+ , ISequentialOutStream
+)
+ Byte *_buffer;
+ size_t _size;
+ size_t _pos;
+
+ size_t _fileWritePos;
+ bool fileMode;
+public:
+
+ bool IsStreamInMem() const { return !fileMode; }
+ size_t GetMemStreamWrittenSize() const { return _pos; }
+
+ // ISequentialOutStream *FileStream;
+ FString FilePath;
+ COutFileStream *outFileStreamSpec;
+ CMyComPtr<ISequentialOutStream> outFileStream;
+
+ CBufSeqOutStream_WithFile(): outFileStreamSpec(NULL) {}
+
+ void Init(Byte *buffer, size_t size)
+ {
+ fileMode = false;
+ _buffer = buffer;
+ _pos = 0;
+ _size = size;
+ _fileWritePos = 0;
+ }
+
+ HRESULT FlushToFile();
+ size_t GetPos() const { return _pos; }
+};
+
+static const UInt32 kBlockSize = ((UInt32)1 << 31);
+
+STDMETHODIMP CBufSeqOutStream_WithFile::Write(const void *data, UInt32 size, UInt32 *processedSize)
+{
+ if (processedSize)
+ *processedSize = 0;
+ if (!fileMode)
+ {
+ if (_size - _pos >= size)
+ {
+ if (size != 0)
+ {
+ memcpy(_buffer + _pos, data, size);
+ _pos += size;
+ }
+ if (processedSize)
+ *processedSize = (UInt32)size;
+ return S_OK;
+ }
+
+ fileMode = true;
+ }
+ RINOK(FlushToFile());
+ return outFileStream->Write(data, size, processedSize);
+}
+
+HRESULT CBufSeqOutStream_WithFile::FlushToFile()
+{
+ if (!outFileStream)
+ {
+ outFileStreamSpec = new COutFileStream;
+ outFileStream = outFileStreamSpec;
+ if (!outFileStreamSpec->Create(FilePath, false))
+ {
+ outFileStream.Release();
+ return E_FAIL;
+ // MessageBoxMyError(UString("Can't create file ") + fs2us(tempFilePath));
+ }
+ }
+ while (_fileWritePos != _pos)
+ {
+ size_t cur = _pos - _fileWritePos;
+ UInt32 curSize = (cur < kBlockSize) ? (UInt32)cur : kBlockSize;
+ UInt32 processedSizeLoc = 0;
+ HRESULT res = outFileStream->Write(_buffer + _fileWritePos, curSize, &processedSizeLoc);
+ _fileWritePos += processedSizeLoc;
+ RINOK(res);
+ if (processedSizeLoc == 0)
+ return E_FAIL;
+ }
+ return S_OK;
+}
+*/
+
+/*
+static HRESULT GetTime(IFolderFolder *folder, UInt32 index, PROPID propID, FILETIME &filetime, bool &filetimeIsDefined)
+{
+ filetimeIsDefined = false;
+ NCOM::CPropVariant prop;
+ RINOK(folder->GetProperty(index, propID, &prop));
+ if (prop.vt == VT_FILETIME)
+ {
+ filetime = prop.filetime;
+ filetimeIsDefined = (filetime.dwHighDateTime != 0 || filetime.dwLowDateTime != 0);
+ }
+ else if (prop.vt != VT_EMPTY)
+ return E_FAIL;
+ return S_OK;
+}
+*/
+
+
+/*
+tryInternal tryExternal
+ false false : unused
+ false true : external
+ true false : internal
+ true true : smart based on file extension:
+ !alwaysStart(name) : both
+ alwaysStart(name) : external
+*/
+
+void CPanel::OpenItemInArchive(unsigned index, bool tryInternal, bool tryExternal, bool editMode, bool useEditor, const wchar_t *type)
+{
+ // we don't want to change hash data here
+ if (IsHashFolder())
+ return;
+
+ const UString name = GetItemName(index);
+ const UString relPath = GetItemRelPath(index);
+
+ if (tryExternal)
+ if (IsVirus_Message(name))
+ return;
+
+ if (!_folderOperations)
+ {
+ MessageBox_Error_UnsupportOperation();
+ return;
+ }
+
+ bool tryAsArchive = tryInternal && (!tryExternal || !DoItemAlwaysStart(name));
+
+ const UString fullVirtPath = _currentFolderPrefix + relPath;
+
+ CTempDir tempDirectory;
+ if (!tempDirectory.Create(kTempDirPrefix))
+ {
+ MessageBox_LastError();
+ return;
+ }
+
+ FString tempDir = tempDirectory.GetPath();
+ FString tempDirNorm = tempDir;
+ NName::NormalizeDirPathPrefix(tempDirNorm);
+ const FString tempFilePath = tempDirNorm + us2fs(Get_Correct_FsFile_Name(name));
+
+ CTempFileInfo tempFileInfo;
+ tempFileInfo.FileIndex = index;
+ tempFileInfo.RelPath = relPath;
+ tempFileInfo.FolderPath = tempDir;
+ tempFileInfo.FilePath = tempFilePath;
+ tempFileInfo.NeedDelete = true;
+
+ if (tryAsArchive)
+ {
+ CMyComPtr<IInArchiveGetStream> getStream;
+ _folder.QueryInterface(IID_IInArchiveGetStream, &getStream);
+ if (getStream)
+ {
+ CMyComPtr<ISequentialInStream> subSeqStream;
+ getStream->GetStream(index, &subSeqStream);
+ if (subSeqStream)
+ {
+ CMyComPtr<IInStream> subStream;
+ subSeqStream.QueryInterface(IID_IInStream, &subStream);
+ if (subStream)
+ {
+ HRESULT res = OpenAsArc_Msg(subStream, tempFileInfo, fullVirtPath, type ? type : L""
+ // , true // showErrorMessage
+ );
+ if (res == S_OK)
+ {
+ tempDirectory.DisableDeleting();
+ RefreshListCtrl();
+ return;
+ }
+ if (res == E_ABORT || res != S_FALSE)
+ return;
+ if (!tryExternal)
+ return;
+ tryAsArchive = false;
+ }
+ }
+ }
+ }
+
+
+ CRecordVector<UInt32> indices;
+ indices.Add(index);
+
+ UStringVector messages;
+
+ bool usePassword = false;
+ UString password;
+ if (_parentFolders.Size() > 0)
+ {
+ const CFolderLink &fl = _parentFolders.Back();
+ usePassword = fl.UsePassword;
+ password = fl.Password;
+ }
+
+ /*
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ CByteBuffer zoneBuf;
+ #ifndef _UNICODE
+ if (g_IsNT)
+ #endif
+ if (_parentFolders.Size() > 0)
+ {
+ const CFolderLink &fl = _parentFolders.Front();
+ if (!fl.IsVirtual && !fl.FilePath.IsEmpty())
+ ReadZoneFile(fl.FilePath + k_ZoneId_StreamName, zoneBuf);
+ }
+ #endif
+ */
+
+
+ CVirtFileSystem *virtFileSystemSpec = NULL;
+ CMyComPtr<ISequentialOutStream> virtFileSystem;
+
+ const bool isAltStream = IsItem_AltStream(index);
+
+ CCopyToOptions options;
+ options.includeAltStreams = true;
+ options.replaceAltStreamChars = isAltStream;
+ {
+ // CContextMenuInfo ci;
+ // ci.Load();
+ // if (ci.WriteZone != (UInt32)(Int32)-1)
+ // we use kAll when we unpack just one file.
+ options.ZoneIdMode = NExtract::NZoneIdMode::kAll;
+ options.NeedRegistryZone = false;
+ }
+
+ if (tryAsArchive)
+ {
+ NCOM::CPropVariant prop;
+ _folder->GetProperty(index, kpidSize, &prop);
+ UInt64 fileLimit = 1 << 22;
+ if (g_RAM_Size_Defined)
+ fileLimit = g_RAM_Size / 4;
+
+ UInt64 fileSize = 0;
+ if (!ConvertPropVariantToUInt64(prop, fileSize))
+ fileSize = fileLimit;
+ if (fileSize <= fileLimit && fileSize > 0)
+ {
+ options.streamMode = true;
+ virtFileSystemSpec = new CVirtFileSystem;
+ virtFileSystem = virtFileSystemSpec;
+ // we allow additional total size for small alt streams;
+ virtFileSystemSpec->MaxTotalAllocSize = fileSize + (1 << 10);
+
+ virtFileSystemSpec->DirPrefix = tempDirNorm;
+ virtFileSystemSpec->Init();
+ options.VirtFileSystem = virtFileSystem;
+ options.VirtFileSystemSpec = virtFileSystemSpec;
+ }
+ }
+
+ options.folder = fs2us(tempDirNorm);
+ options.showErrorMessages = true;
+
+ const HRESULT result = CopyTo(options, indices, &messages, usePassword, password);
+
+ if (_parentFolders.Size() > 0)
+ {
+ CFolderLink &fl = _parentFolders.Back();
+ fl.UsePassword = usePassword;
+ fl.Password = password;
+ }
+
+ if (!messages.IsEmpty())
+ return;
+ if (result != S_OK)
+ {
+ if (result != E_ABORT)
+ MessageBox_Error_HRESULT(result);
+ return;
+ }
+
+ if (options.VirtFileSystem)
+ {
+ if (virtFileSystemSpec->IsStreamInMem())
+ {
+ const CVirtFile &file = virtFileSystemSpec->Files[0];
+
+ size_t streamSize = (size_t)file.Size;
+ CBufInStream *bufInStreamSpec = new CBufInStream;
+ CMyComPtr<IInStream> bufInStream = bufInStreamSpec;
+ bufInStreamSpec->Init(file.Data, streamSize, virtFileSystem);
+
+ HRESULT res = OpenAsArc_Msg(bufInStream, tempFileInfo, fullVirtPath, type ? type : L""
+ // , encrypted
+ // , true // showErrorMessage
+ );
+
+ if (res == S_OK)
+ {
+ tempDirectory.DisableDeleting();
+ RefreshListCtrl();
+ return;
+ }
+
+ if (res == E_ABORT || res != S_FALSE)
+ return;
+ if (!tryExternal)
+ return;
+
+ tryAsArchive = false;
+ if (virtFileSystemSpec->FlushToDisk(true) != S_OK)
+ return;
+ }
+ }
+
+
+ /*
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (zoneBuf.Size() != 0)
+ {
+ if (NFind::DoesFileExist_Raw(tempFilePath))
+ {
+ WriteZoneFile(tempFilePath + k_ZoneId_StreamName, zoneBuf);
+ }
+ }
+ #endif
+ */
+
+
+ if (tryAsArchive)
+ {
+ HRESULT res = OpenAsArc_Msg(NULL, tempFileInfo, fullVirtPath, type ? type : L""
+ // , encrypted
+ // , true // showErrorMessage
+ );
+ if (res == S_OK)
+ {
+ tempDirectory.DisableDeleting();
+ RefreshListCtrl();
+ return;
+ }
+ if (res == E_ABORT || res != S_FALSE)
+ return;
+ }
+
+ if (!tryExternal)
+ return;
+
+ CMyAutoPtr<CTmpProcessInfo> tmpProcessInfoPtr(new CTmpProcessInfo());
+ CTmpProcessInfo *tpi = tmpProcessInfoPtr.get();
+ tpi->FolderPath = tempDir;
+ tpi->FilePath = tempFilePath;
+ tpi->NeedDelete = true;
+ tpi->UsePassword = usePassword;
+ tpi->Password = password;
+ tpi->ReadOnly = IsThereReadOnlyFolder();
+ if (IsHashFolder())
+ tpi->ReadOnly = true;
+
+ if (!tpi->FileInfo.Find(tempFilePath))
+ return;
+
+ CTmpProcessInfoRelease tmpProcessInfoRelease(*tpi);
+
+ CProcess process;
+ HRESULT res;
+ if (editMode)
+ res = StartEditApplication(fs2us(tempFilePath), useEditor, (HWND)*this, process);
+ else
+ res = StartApplication(fs2us(tempDirNorm), fs2us(tempFilePath), (HWND)*this, process);
+
+ if ((HANDLE)process == NULL)
+ {
+ // win7 / win10 work so for some extensions (pdf, html ..);
+ DEBUG_PRINT("#### (HANDLE)process == 0");
+ // return;
+ if (res != S_OK)
+ return;
+ }
+
+ tpi->Window = (HWND)(*this);
+ tpi->FullPathFolderPrefix = _currentFolderPrefix;
+ tpi->FileIndex = index;
+ tpi->RelPath = relPath;
+
+ if ((HANDLE)process)
+ tpi->Processes.SetMainProcess(process.Detach());
+
+ ::CThread th;
+ if (Thread_Create(&th, MyThreadFunction, tpi) != 0)
+ throw 271824;
+ g_ExitEventLauncher._threads.Add(th);
+ g_ExitEventLauncher._numActiveThreads++;
+
+ tempDirectory.DisableDeleting();
+ tmpProcessInfoPtr.release();
+ tmpProcessInfoRelease._needDelete = false;
+}
+
+
+/*
+static const UINT64 kTimeLimit = UINT64(10000000) * 3600 * 24;
+
+static bool CheckDeleteItem(UINT64 currentFileTime, UINT64 folderFileTime)
+{
+ return (currentFileTime - folderFileTime > kTimeLimit &&
+ folderFileTime - currentFileTime > kTimeLimit);
+}
+
+void DeleteOldTempFiles()
+{
+ UString tempPath;
+ if (!MyGetTempPath(tempPath))
+ throw 1;
+
+ UINT64 currentFileTime;
+ NTime::GetCurUtcFileTime(currentFileTime);
+ UString searchWildCard = tempPath + kTempDirPrefix + L"*.tmp";
+ searchWildCard += WCHAR(NName::kAnyStringWildcard);
+ NFind::CEnumeratorW enumerator(searchWildCard);
+ NFind::CFileInfo fileInfo;
+ while (enumerator.Next(fileInfo))
+ {
+ if (!fileInfo.IsDir())
+ continue;
+ const UINT64 &cTime = *(const UINT64 *)(&fileInfo.CTime);
+ if (CheckDeleteItem(cTime, currentFileTime))
+ RemoveDirectoryWithSubItems(tempPath + fileInfo.Name);
+ }
+}
+*/
diff --git a/CPP/7zip/UI/FileManager/PanelItems.cpp b/CPP/7zip/UI/FileManager/PanelItems.cpp
new file mode 100644
index 0000000..0cb33d8
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelItems.cpp
@@ -0,0 +1,1391 @@
+// PanelItems.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/Sort.h"
+
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/Menu.h"
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/PropVariantConv.h"
+
+#include "../../PropID.h"
+
+#include "../Common/ExtractingFilePath.h"
+
+#include "resource.h"
+
+#include "LangUtils.h"
+#include "Panel.h"
+#include "PropertyName.h"
+#include "RootFolder.h"
+
+using namespace NWindows;
+
+static bool GetColumnVisible(PROPID propID, bool isFsFolder)
+{
+ if (isFsFolder)
+ {
+ switch (propID)
+ {
+ case kpidATime:
+ case kpidChangeTime:
+ case kpidAttrib:
+ case kpidPackSize:
+ case kpidINode:
+ case kpidLinks:
+ case kpidNtReparse:
+ return false;
+ }
+ }
+ return true;
+}
+
+static unsigned GetColumnWidth(PROPID propID, VARTYPE /* varType */)
+{
+ switch (propID)
+ {
+ case kpidName: return 160;
+ }
+ return 100;
+}
+
+static int GetColumnAlign(PROPID propID, VARTYPE varType)
+{
+ switch (propID)
+ {
+ case kpidCTime:
+ case kpidATime:
+ case kpidMTime:
+ case kpidChangeTime:
+ return LVCFMT_LEFT;
+ }
+
+ switch (varType)
+ {
+ case VT_UI1:
+ case VT_I2:
+ case VT_UI2:
+ case VT_I4:
+ case VT_INT:
+ case VT_UI4:
+ case VT_UINT:
+ case VT_I8:
+ case VT_UI8:
+ case VT_BOOL:
+ return LVCFMT_RIGHT;
+
+ case VT_EMPTY:
+ case VT_I1:
+ case VT_FILETIME:
+ case VT_BSTR:
+ return LVCFMT_LEFT;
+
+ default:
+ return LVCFMT_CENTER;
+ }
+}
+
+
+static int ItemProperty_Compare_NameFirst(void *const *a1, void *const *a2, void * /* param */)
+{
+ return (*(*((const CPropColumn *const *)a1))).Compare_NameFirst(*(*((const CPropColumn *const *)a2)));
+}
+
+HRESULT CPanel::InitColumns()
+{
+ SaveListViewInfo();
+
+ // DeleteListItems();
+ _selectedStatusVector.Clear();
+
+ {
+ // ReadListViewInfo();
+ const UString oldType = _typeIDString;
+ _typeIDString = GetFolderTypeID();
+ // an empty _typeIDString is allowed.
+
+ // we read registry only for new FolderTypeID
+ if (!_needSaveInfo || _typeIDString != oldType)
+ _listViewInfo.Read(_typeIDString);
+
+ // folders with same FolderTypeID can have different columns
+ // so we still read columns for that case.
+ // if (_needSaveInfo && _typeIDString == oldType) return S_OK;
+ }
+
+ // PROPID sortID;
+ /*
+ if (_listViewInfo.SortIndex >= 0)
+ sortID = _listViewInfo.Columns[_listViewInfo.SortIndex].PropID;
+ */
+ // sortID = _listViewInfo.SortID;
+
+ _ascending = _listViewInfo.Ascending;
+
+ _columns.Clear();
+
+ bool isFsFolder = IsFSFolder() || IsAltStreamsFolder();
+
+ {
+ UInt32 numProps;
+ _folder->GetNumberOfProperties(&numProps);
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE varType;
+ HRESULT res = _folder->GetPropertyInfo(i, &name, &propID, &varType);
+
+ if (res != S_OK)
+ {
+ /* We can return ERROR, but in that case, other code will not be called,
+ and user can see empty window without error message. So we just ignore that field */
+ continue;
+ }
+ if (propID == kpidIsDir)
+ continue;
+ CPropColumn prop;
+ prop.Type = varType;
+ prop.ID = propID;
+ prop.Name = GetNameOfProperty(propID, name);
+ prop.Order = -1;
+ prop.IsVisible = GetColumnVisible(propID, isFsFolder);
+ prop.Width = GetColumnWidth(propID, varType);
+ prop.IsRawProp = false;
+ _columns.Add(prop);
+ }
+
+ /*
+ {
+ // debug column
+ CPropColumn prop;
+ prop.Type = VT_BSTR;
+ prop.ID = 2000;
+ prop.Name = "Debug";
+ prop.Order = -1;
+ prop.IsVisible = true;
+ prop.Width = 300;
+ prop.IsRawProp = false;
+ _columns.Add(prop);
+ }
+ */
+ }
+
+ if (_folderRawProps)
+ {
+ UInt32 numProps;
+ _folderRawProps->GetNumRawProps(&numProps);
+
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ HRESULT res = _folderRawProps->GetRawPropInfo(i, &name, &propID);
+ if (res != S_OK)
+ continue;
+ CPropColumn prop;
+ prop.Type = VT_EMPTY;
+ prop.ID = propID;
+ prop.Name = GetNameOfProperty(propID, name);
+ prop.Order = -1;
+ prop.IsVisible = GetColumnVisible(propID, isFsFolder);
+ prop.Width = GetColumnWidth(propID, VT_BSTR);
+ prop.IsRawProp = true;
+ _columns.Add(prop);
+ }
+ }
+
+ unsigned order = 0;
+ unsigned i;
+
+ for (i = 0; i < _listViewInfo.Columns.Size(); i++)
+ {
+ const CColumnInfo &columnInfo = _listViewInfo.Columns[i];
+ const int index = _columns.FindItem_for_PropID(columnInfo.PropID);
+ if (index >= 0)
+ {
+ CPropColumn &item = _columns[index];
+ if (item.Order >= 0)
+ continue; // we ignore duplicated items
+ bool isVisible = columnInfo.IsVisible;
+ // we enable kpidName, if it was disabled by some incorrect code
+ if (columnInfo.PropID == kpidName)
+ isVisible = true;
+ item.IsVisible = isVisible;
+ item.Width = columnInfo.Width;
+ if (isVisible)
+ item.Order = (int)(order++);
+ continue;
+ }
+ }
+
+ for (i = 0; i < _columns.Size(); i++)
+ {
+ CPropColumn &item = _columns[i];
+ if (item.IsVisible && item.Order < 0)
+ item.Order = (int)(order++);
+ }
+
+ for (i = 0; i < _columns.Size(); i++)
+ {
+ CPropColumn &item = _columns[i];
+ if (item.Order < 0)
+ item.Order = (int)(order++);
+ }
+
+ CPropColumns newColumns;
+
+ for (i = 0; i < _columns.Size(); i++)
+ {
+ const CPropColumn &prop = _columns[i];
+ if (prop.IsVisible)
+ newColumns.Add(prop);
+ }
+
+
+ /*
+ _sortIndex = 0;
+ if (_listViewInfo.SortIndex >= 0)
+ {
+ int sortIndex = _columns.FindItem_for_PropID(sortID);
+ if (sortIndex >= 0)
+ _sortIndex = sortIndex;
+ }
+ */
+
+ if (_listViewInfo.IsLoaded)
+ _sortID = _listViewInfo.SortID;
+ else
+ {
+ _sortID = 0;
+ if (IsFSFolder() || IsAltStreamsFolder() || IsArcFolder())
+ _sortID = kpidName;
+ }
+
+ /* There are restrictions in ListView control:
+ 1) main column (kpidName) must have (LV_COLUMNW::iSubItem = 0)
+ So we need special sorting for columns.
+ 2) when we add new column, LV_COLUMNW::iOrder cannot be larger than already inserted columns)
+ So we set column order after all columns are added.
+ */
+ newColumns.Sort(ItemProperty_Compare_NameFirst, NULL);
+
+ if (newColumns.IsEqualTo(_visibleColumns))
+ return S_OK;
+
+ CIntArr columns(newColumns.Size());
+ for (i = 0; i < newColumns.Size(); i++)
+ columns[i] = -1;
+
+ bool orderError = false;
+
+ for (i = 0; i < newColumns.Size(); i++)
+ {
+ const CPropColumn &prop = newColumns[i];
+ if (prop.Order < (int)newColumns.Size() && columns[prop.Order] == -1)
+ columns[prop.Order] = (int)i;
+ else
+ orderError = true;
+ }
+
+ for (;;)
+ {
+ const unsigned numColumns = _visibleColumns.Size();
+ if (numColumns == 0)
+ break;
+ DeleteColumn(numColumns - 1);
+ }
+
+ for (i = 0; i < newColumns.Size(); i++)
+ AddColumn(newColumns[i]);
+
+ // columns[0], columns[1], .... should be displayed from left to right:
+ if (!orderError)
+ _listView.SetColumnOrderArray(_visibleColumns.Size(), columns);
+
+ _needSaveInfo = true;
+
+ return S_OK;
+}
+
+
+void CPanel::DeleteColumn(unsigned index)
+{
+ _visibleColumns.Delete(index);
+ _listView.DeleteColumn(index);
+}
+
+void CPanel::AddColumn(const CPropColumn &prop)
+{
+ const unsigned index = _visibleColumns.Size();
+
+ LV_COLUMNW column;
+ column.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM | LVCF_ORDER;
+ column.cx = (int)prop.Width;
+ column.fmt = GetColumnAlign(prop.ID, prop.Type);
+ column.iOrder = (int)index; // must be <= _listView.ItemCount
+ column.iSubItem = (int)index; // must be <= _listView.ItemCount
+ column.pszText = const_cast<wchar_t *>((const wchar_t *)prop.Name);
+
+ _visibleColumns.Add(prop);
+ _listView.InsertColumn(index, &column);
+}
+
+
+HRESULT CPanel::RefreshListCtrl()
+{
+ CSelectedState state;
+ return RefreshListCtrl(state);
+}
+
+int CALLBACK CompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData);
+
+
+void CPanel::GetSelectedNames(UStringVector &selectedNames)
+{
+ CRecordVector<UInt32> indices;
+ Get_ItemIndices_Selected(indices);
+ selectedNames.ClearAndReserve(indices.Size());
+ FOR_VECTOR (i, indices)
+ selectedNames.AddInReserved(GetItemRelPath(indices[i]));
+
+ /*
+ for (int i = 0; i < _listView.GetItemCount(); i++)
+ {
+ const int kSize = 1024;
+ WCHAR name[kSize + 1];
+ LVITEMW item;
+ item.iItem = i;
+ item.pszText = name;
+ item.cchTextMax = kSize;
+ item.iSubItem = 0;
+ item.mask = LVIF_TEXT | LVIF_PARAM;
+ if (!_listView.GetItem(&item))
+ continue;
+ const unsigned realIndex = GetRealIndex(item);
+ if (realIndex == kParentIndex)
+ continue;
+ if (_selectedStatusVector[realIndex])
+ selectedNames.Add(item.pszText);
+ }
+ */
+ selectedNames.Sort();
+}
+
+void CPanel::SaveSelectedState(CSelectedState &s)
+{
+ s.FocusedName_Defined = false;
+ s.FocusedName.Empty();
+ s.SelectFocused = true; // false;
+ s.SelectedNames.Clear();
+ s.FocusedItem = _listView.GetFocusedItem();
+ {
+ if (s.FocusedItem >= 0)
+ {
+ const unsigned realIndex = GetRealItemIndex(s.FocusedItem);
+ if (realIndex != kParentIndex)
+ {
+ s.FocusedName = GetItemRelPath(realIndex);
+ s.FocusedName_Defined = true;
+
+ s.SelectFocused = _listView.IsItemSelected(s.FocusedItem);
+
+ /*
+ const int kSize = 1024;
+ WCHAR name[kSize + 1];
+ LVITEMW item;
+ item.iItem = focusedItem;
+ item.pszText = name;
+ item.cchTextMax = kSize;
+ item.iSubItem = 0;
+ item.mask = LVIF_TEXT;
+ if (_listView.GetItem(&item))
+ focusedName = item.pszText;
+ */
+ }
+ }
+ }
+ GetSelectedNames(s.SelectedNames);
+}
+
+/*
+HRESULT CPanel::RefreshListCtrl(const CSelectedState &s)
+{
+ bool selectFocused = s.SelectFocused;
+ if (_mySelectMode)
+ selectFocused = true;
+ return RefreshListCtrl2(
+ s.FocusedItem >= 0, // allowEmptyFocusedName
+ s.FocusedName, s.FocusedItem, selectFocused, s.SelectedNames);
+}
+*/
+
+HRESULT CPanel::RefreshListCtrl_SaveFocused(bool onTimer)
+{
+ CSelectedState state;
+ SaveSelectedState(state);
+ state.CalledFromTimer = onTimer;
+ return RefreshListCtrl(state);
+}
+
+void CPanel::SetFocusedSelectedItem(int index, bool select)
+{
+ UINT state = LVIS_FOCUSED;
+ if (select)
+ state |= LVIS_SELECTED;
+ _listView.SetItemState(index, state, state);
+ if (!_mySelectMode && select)
+ {
+ const unsigned realIndex = GetRealItemIndex(index);
+ if (realIndex != kParentIndex)
+ _selectedStatusVector[realIndex] = true;
+ }
+}
+
+// #define PRINT_STAT
+
+#ifdef PRINT_STAT
+ void Print_OnNotify(const char *name);
+#else
+ #define Print_OnNotify(x)
+#endif
+
+
+
+/*
+
+extern UInt32 g_NumGroups;
+extern DWORD g_start_tick;
+extern DWORD g_prev_tick;
+extern DWORD g_Num_SetItemText;
+extern UInt32 g_NumMessages;
+*/
+
+HRESULT CPanel::RefreshListCtrl(const CSelectedState &state)
+{
+ m_DropHighlighted_SelectionIndex = -1;
+ m_DropHighlighted_SubFolderName.Empty();
+
+ if (!_folder)
+ return S_OK;
+
+ /*
+ g_start_tick = GetTickCount();
+ g_Num_SetItemText = 0;
+ g_NumMessages = 0;
+ */
+
+ _dontShowMode = false;
+ if (!state.CalledFromTimer)
+ LoadFullPathAndShow();
+ // OutputDebugStringA("=======\n");
+ // OutputDebugStringA("s1 \n");
+ CDisableTimerProcessing timerProcessing(*this);
+ CDisableNotify disableNotify(*this);
+
+ int focusedPos = state.FocusedItem;
+ if (focusedPos < 0)
+ focusedPos = 0;
+
+ _listView.SetRedraw(false);
+ // m_RedrawEnabled = false;
+
+ LVITEMW item;
+ ZeroMemory(&item, sizeof(item));
+
+ // DWORD tickCount0 = GetTickCount();
+
+ // _enableItemChangeNotify = false;
+ DeleteListItems();
+ _enableItemChangeNotify = true;
+
+ int listViewItemCount = 0;
+
+ _selectedStatusVector.Clear();
+ // _realIndices.Clear();
+ _startGroupSelect = 0;
+
+ _selectionIsDefined = false;
+
+ // m_Files.Clear();
+
+ /*
+ if (!_folder)
+ {
+ // throw 1;
+ SetToRootFolder();
+ }
+ */
+
+ _headerToolBar.EnableButton(kParentFolderID, !IsRootFolder());
+
+ {
+ CMyComPtr<IFolderSetFlatMode> folderSetFlatMode;
+ _folder.QueryInterface(IID_IFolderSetFlatMode, &folderSetFlatMode);
+ if (folderSetFlatMode)
+ folderSetFlatMode->SetFlatMode(BoolToInt(_flatMode));
+ }
+
+ /*
+ {
+ CMyComPtr<IFolderSetShowNtfsStreamsMode> setShow;
+ _folder.QueryInterface(IID_IFolderSetShowNtfsStreamsMode, &setShow);
+ if (setShow)
+ setShow->SetShowNtfsStreamsMode(BoolToInt(_showNtfsStrems_Mode));
+ }
+ */
+
+ _isDirVector.Clear();
+ // DWORD tickCount1 = GetTickCount();
+ IFolderFolder *folder = _folder;
+ RINOK(_folder->LoadItems())
+ // DWORD tickCount2 = GetTickCount();
+ // OutputDebugString(TEXT("Start Dir\n"));
+ RINOK(InitColumns())
+
+ UInt32 numItems;
+ _folder->GetNumberOfItems(&numItems);
+ {
+ NCOM::CPropVariant prop;
+ _isDirVector.ClearAndSetSize(numItems);
+ bool *vec = (bool *)&_isDirVector.Front();
+ HRESULT hres = S_OK;
+ unsigned i;
+ for (i = 0; i < numItems; i++)
+ {
+ hres = folder->GetProperty(i, kpidIsDir, &prop);
+ if (hres != S_OK)
+ break;
+ bool v = false;
+ if (prop.vt == VT_BOOL)
+ v = VARIANT_BOOLToBool(prop.boolVal);
+ else if (prop.vt != VT_EMPTY)
+ break;
+ vec[i] = v;
+ }
+ if (i != numItems)
+ {
+ _isDirVector.Clear();
+ if (hres == S_OK)
+ hres = E_FAIL;
+ }
+ RINOK(hres)
+ }
+
+ const bool showDots = _showDots && !IsRootFolder();
+
+ _listView.SetItemCount(numItems + (showDots ? 1 : 0));
+
+ _selectedStatusVector.ClearAndReserve(numItems);
+ int cursorIndex = -1;
+
+ CMyComPtr<IFolderGetSystemIconIndex> folderGetSystemIconIndex;
+ if (!Is_Slow_Icon_Folder() || _showRealFileIcons)
+ _folder.QueryInterface(IID_IFolderGetSystemIconIndex, &folderGetSystemIconIndex);
+
+ if (!IsFSFolder())
+ {
+ CMyComPtr<IGetFolderArcProps> getFolderArcProps;
+ _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps);
+ _thereAreDeletedItems = false;
+ if (getFolderArcProps)
+ {
+ CMyComPtr<IFolderArcProps> arcProps;
+ getFolderArcProps->GetFolderArcProps(&arcProps);
+ if (arcProps)
+ {
+ UInt32 numLevels;
+ if (arcProps->GetArcNumLevels(&numLevels) != S_OK)
+ numLevels = 0;
+ NCOM::CPropVariant prop;
+ if (arcProps->GetArcProp(numLevels - 1, kpidIsDeleted, &prop) == S_OK)
+ if (prop.vt == VT_BOOL && VARIANT_BOOLToBool(prop.boolVal))
+ _thereAreDeletedItems = true;
+ }
+ }
+ }
+
+ _thereAre_ListView_Items = true;
+
+ // OutputDebugStringA("\n\n");
+
+ Print_OnNotify("===== Before Load");
+
+ // #define USE_EMBED_ITEM
+
+ if (showDots)
+ {
+ const UString itemName ("..");
+ item.iItem = listViewItemCount;
+ if (itemName == state.FocusedName)
+ cursorIndex = listViewItemCount;
+ item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
+ int subItem = 0;
+ item.iSubItem = subItem++;
+ item.lParam = (LPARAM)(int)kParentIndex;
+ #ifdef USE_EMBED_ITEM
+ item.pszText = const_cast<wchar_t *>((const wchar_t *)itemName);
+ #else
+ item.pszText = LPSTR_TEXTCALLBACKW;
+ #endif
+ const UInt32 attrib = FILE_ATTRIBUTE_DIRECTORY;
+ item.iImage = _extToIconMap.GetIconIndex(attrib, itemName);
+ if (item.iImage < 0)
+ item.iImage = 0;
+ if (_listView.InsertItem(&item) == -1)
+ return E_FAIL;
+ listViewItemCount++;
+ }
+
+ // OutputDebugStringA("S1\n");
+
+ UString correctedName;
+ UString itemName;
+ UString relPath;
+
+ for (UInt32 i = 0; i < numItems; i++)
+ {
+ const wchar_t *name = NULL;
+ unsigned nameLen = 0;
+
+ if (_folderGetItemName)
+ _folderGetItemName->GetItemName(i, &name, &nameLen);
+ if (!name)
+ {
+ GetItemName(i, itemName);
+ name = itemName;
+ nameLen = itemName.Len();
+ }
+
+ bool selected = false;
+
+ if (state.FocusedName_Defined || !state.SelectedNames.IsEmpty())
+ {
+ relPath.Empty();
+ // relPath += GetItemPrefix(i);
+ if (_flatMode)
+ {
+ const wchar_t *prefix = NULL;
+ if (_folderGetItemName)
+ {
+ unsigned prefixLen = 0;
+ _folderGetItemName->GetItemPrefix(i, &prefix, &prefixLen);
+ if (prefix)
+ relPath = prefix;
+ }
+ if (!prefix)
+ {
+ NCOM::CPropVariant prop;
+ if (_folder->GetProperty(i, kpidPrefix, &prop) != S_OK)
+ throw 2723400;
+ if (prop.vt == VT_BSTR)
+ relPath.SetFromBstr(prop.bstrVal);
+ }
+ }
+ relPath += name;
+ if (relPath == state.FocusedName)
+ cursorIndex = listViewItemCount;
+ if (state.SelectedNames.FindInSorted(relPath) != -1)
+ selected = true;
+ }
+
+ _selectedStatusVector.AddInReserved(selected);
+
+ item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
+
+ if (!_mySelectMode)
+ if (selected)
+ {
+ item.mask |= LVIF_STATE;
+ item.state = LVIS_SELECTED;
+ }
+
+ int subItem = 0;
+ item.iItem = listViewItemCount;
+
+ item.iSubItem = subItem++;
+ item.lParam = (LPARAM)i;
+
+ /*
+ int finish = nameLen - 4;
+ int j;
+ for (j = 0; j < finish; j++)
+ {
+ if (name[j ] == ' ' &&
+ name[j + 1] == ' ' &&
+ name[j + 2] == ' ' &&
+ name[j + 3] == ' ' &&
+ name[j + 4] == ' ')
+ break;
+ }
+ if (j < finish)
+ {
+ correctedName.Empty();
+ correctedName = "virus";
+ int pos = 0;
+ for (;;)
+ {
+ int posNew = itemName.Find(L" ", pos);
+ if (posNew < 0)
+ {
+ correctedName += itemName.Ptr(pos);
+ break;
+ }
+ correctedName += itemName.Mid(pos, posNew - pos);
+ correctedName += " ... ";
+ pos = posNew;
+ while (itemName[++pos] == ' ');
+ }
+ item.pszText = const_cast<wchar_t *>((const wchar_t *)correctedName);
+ }
+ else
+ */
+ {
+ #ifdef USE_EMBED_ITEM
+ item.pszText = const_cast<wchar_t *>((const wchar_t *)name);
+ #else
+ item.pszText = LPSTR_TEXTCALLBACKW;
+ #endif
+ /* LPSTR_TEXTCALLBACKW works, but in some cases there are problems,
+ since we block notify handler.
+ LPSTR_TEXTCALLBACKW can be 2-3 times faster for loading in this loop. */
+ }
+
+ bool defined = false;
+
+ if (folderGetSystemIconIndex)
+ {
+ folderGetSystemIconIndex->GetSystemIconIndex(i, &item.iImage);
+ defined = (item.iImage > 0);
+ }
+
+ if (!defined)
+ {
+ UInt32 attrib = 0;
+ {
+ NCOM::CPropVariant prop;
+ RINOK(_folder->GetProperty(i, kpidAttrib, &prop))
+ if (prop.vt == VT_UI4)
+ attrib = prop.ulVal;
+ }
+ if (IsItem_Folder(i))
+ attrib |= FILE_ATTRIBUTE_DIRECTORY;
+
+ if (_currentFolderPrefix.IsEmpty())
+ {
+ int iconIndexTemp;
+ GetRealIconIndex(us2fs((UString)name) + FCHAR_PATH_SEPARATOR, attrib, iconIndexTemp);
+ item.iImage = iconIndexTemp;
+ }
+ else
+ {
+ item.iImage = _extToIconMap.GetIconIndex(attrib, name);
+ }
+ }
+
+ if (item.iImage < 0)
+ item.iImage = 0;
+
+ if (_listView.InsertItem(&item) == -1)
+ return E_FAIL;
+ listViewItemCount++;
+ }
+
+ /*
+ xp-64: there is different order when Windows calls CPanel::OnNotify for _listView modes:
+ Details : after whole code
+ List : 2 times:
+ 1) - ListView.SotRedraw()
+ 2) - after whole code
+ Small Icons :
+ Large icons : 2 times:
+ 1) - ListView.Sort()
+ 2) - after whole code (calls with reverse order of items)
+
+ So we need to allow Notify(), when windows requests names during the following code.
+ */
+
+ Print_OnNotify("after Load");
+
+ disableNotify.SetMemMode_Enable();
+ disableNotify.Restore();
+
+ if (_listView.GetItemCount() > 0 && cursorIndex >= 0)
+ SetFocusedSelectedItem(cursorIndex, state.SelectFocused);
+
+ Print_OnNotify("after SetFocusedSelectedItem");
+
+ SetSortRawStatus();
+ _listView.SortItems(CompareItems, (LPARAM)this);
+
+ Print_OnNotify("after Sort");
+
+ if (cursorIndex < 0 && _listView.GetItemCount() > 0)
+ {
+ if (focusedPos >= _listView.GetItemCount())
+ focusedPos = _listView.GetItemCount() - 1;
+ // we select item only in showDots mode.
+ SetFocusedSelectedItem(focusedPos, showDots && (focusedPos == 0));
+ }
+
+ // m_RedrawEnabled = true;
+
+ Print_OnNotify("after SetFocusedSelectedItem2");
+
+ _listView.EnsureVisible(_listView.GetFocusedItem(), false);
+
+ // disableNotify.SetMemMode_Enable();
+ // disableNotify.Restore();
+
+ Print_OnNotify("after EnsureVisible");
+
+ _listView.SetRedraw(true);
+
+ Print_OnNotify("after SetRedraw");
+
+ _listView.InvalidateRect(NULL, true);
+
+ Print_OnNotify("after InvalidateRect");
+ /*
+ _listView.UpdateWindow();
+ */
+ Refresh_StatusBar();
+ /*
+ char s[256];
+ sprintf(s,
+ // "attribMap = %5d, extMap = %5d, "
+ "delete = %5d, load = %5d, list = %5d, sort = %5d, end = %5d",
+ // _extToIconMap._attribMap.Size(),
+ // _extToIconMap._extMap.Size(),
+ tickCount1 - tickCount0,
+ tickCount2 - tickCount1,
+ tickCount3 - tickCount2,
+ tickCount4 - tickCount3,
+ tickCount5 - tickCount4
+ );
+ sprintf(s,
+ "5 = %5d, 6 = %5d, 7 = %5d, 8 = %5d, 9 = %5d",
+ tickCount5 - tickCount4,
+ tickCount6 - tickCount5,
+ tickCount7 - tickCount6,
+ tickCount8 - tickCount7,
+ tickCount9 - tickCount8
+ );
+ OutputDebugStringA(s);
+ */
+ return S_OK;
+}
+
+
+void CPanel::Get_ItemIndices_Selected(CRecordVector<UInt32> &indices) const
+{
+ indices.Clear();
+ /*
+ int itemIndex = -1;
+ while ((itemIndex = _listView.GetNextSelectedItem(itemIndex)) != -1)
+ {
+ LPARAM param;
+ if (_listView.GetItemParam(itemIndex, param))
+ indices.Add(param);
+ }
+ HeapSort(&indices.Front(), indices.Size());
+ */
+ const bool *v = &_selectedStatusVector.Front();
+ const unsigned size = _selectedStatusVector.Size();
+ for (unsigned i = 0; i < size; i++)
+ if (v[i])
+ indices.Add(i);
+}
+
+
+void CPanel::Get_ItemIndices_Operated(CRecordVector<UInt32> &indices) const
+{
+ Get_ItemIndices_Selected(indices);
+ if (!indices.IsEmpty())
+ return;
+ if (_listView.GetSelectedCount() == 0)
+ return;
+ const int focusedItem = _listView.GetFocusedItem();
+ if (focusedItem >= 0)
+ {
+ if (_listView.IsItemSelected(focusedItem))
+ {
+ const unsigned realIndex = GetRealItemIndex(focusedItem);
+ if (realIndex != kParentIndex)
+ indices.Add(realIndex);
+ }
+ }
+}
+
+void CPanel::Get_ItemIndices_All(CRecordVector<UInt32> &indices) const
+{
+ indices.Clear();
+ UInt32 numItems;
+ if (_folder->GetNumberOfItems(&numItems) != S_OK)
+ return;
+ indices.ClearAndSetSize(numItems);
+ UInt32 *vec = (UInt32 *)&indices.Front();
+ for (UInt32 i = 0; i < numItems; i++)
+ vec[i] = i;
+}
+
+void CPanel::Get_ItemIndices_OperSmart(CRecordVector<UInt32> &indices) const
+{
+ Get_ItemIndices_Operated(indices);
+ if (indices.IsEmpty() || (indices.Size() == 1 && indices[0] == (UInt32)(Int32)-1))
+ Get_ItemIndices_All(indices);
+}
+
+/*
+void CPanel::GetOperatedListViewIndices(CRecordVector<UInt32> &indices) const
+{
+ indices.Clear();
+ int numItems = _listView.GetItemCount();
+ for (int i = 0; i < numItems; i++)
+ {
+ const unsigned realIndex = GetRealItemIndex(i);
+ if (realIndex >= 0)
+ if (_selectedStatusVector[realIndex])
+ indices.Add(i);
+ }
+ if (indices.IsEmpty())
+ {
+ const int focusedItem = _listView.GetFocusedItem();
+ if (focusedItem >= 0)
+ indices.Add(focusedItem);
+ }
+}
+*/
+
+void CPanel::EditItem(bool useEditor)
+{
+ if (!useEditor)
+ {
+ CMyComPtr<IFolderCalcItemFullSize> calcItemFullSize;
+ _folder.QueryInterface(IID_IFolderCalcItemFullSize, &calcItemFullSize);
+ if (calcItemFullSize)
+ {
+ bool needRefresh = false;
+ CRecordVector<UInt32> indices;
+ Get_ItemIndices_Operated(indices);
+ FOR_VECTOR (i, indices)
+ {
+ UInt32 index = indices[i];
+ if (IsItem_Folder(index))
+ {
+ calcItemFullSize->CalcItemFullSize(index, NULL);
+ needRefresh = true;
+ }
+ }
+ if (needRefresh)
+ {
+ // _listView.RedrawItem(0);
+ // _listView.RedrawAllItems();
+ InvalidateList();
+ return;
+ }
+ }
+ }
+
+
+ const int focusedItem = _listView.GetFocusedItem();
+ if (focusedItem < 0)
+ return;
+ const unsigned realIndex = GetRealItemIndex(focusedItem);
+ if (realIndex == kParentIndex)
+ return;
+ if (!IsItem_Folder(realIndex))
+ EditItem(realIndex, useEditor);
+}
+
+void CPanel::OpenFocusedItemAsInternal(const wchar_t *type)
+{
+ const int focusedItem = _listView.GetFocusedItem();
+ if (focusedItem < 0)
+ return;
+ const unsigned realIndex = GetRealItemIndex(focusedItem);
+ if (IsItem_Folder(realIndex))
+ OpenFolder(realIndex);
+ else
+ OpenItem(realIndex, true, false, type);
+}
+
+void CPanel::OpenSelectedItems(bool tryInternal)
+{
+ CRecordVector<UInt32> indices;
+ Get_ItemIndices_Operated(indices);
+ if (indices.Size() > 20)
+ {
+ MessageBox_Error_LangID(IDS_TOO_MANY_ITEMS);
+ return;
+ }
+
+ const int focusedItem = _listView.GetFocusedItem();
+ if (focusedItem >= 0)
+ {
+ const unsigned realIndex = GetRealItemIndex(focusedItem);
+ if (realIndex == kParentIndex && (tryInternal || indices.Size() == 0) && _listView.IsItemSelected(focusedItem))
+ indices.Insert(0, realIndex);
+ }
+
+ bool dirIsStarted = false;
+ FOR_VECTOR (i, indices)
+ {
+ UInt32 index = indices[i];
+ // CFileInfo &aFile = m_Files[index];
+ if (IsItem_Folder(index))
+ {
+ if (!dirIsStarted)
+ {
+ if (tryInternal)
+ {
+ OpenFolder(index);
+ dirIsStarted = true;
+ break;
+ }
+ else
+ OpenFolderExternal(index);
+ }
+ }
+ else
+ OpenItem(index, (tryInternal && indices.Size() == 1), true);
+ }
+}
+
+UString CPanel::GetItemName(unsigned itemIndex) const
+{
+ if (itemIndex == kParentIndex)
+ return L"..";
+ NCOM::CPropVariant prop;
+ if (_folder->GetProperty(itemIndex, kpidName, &prop) != S_OK)
+ throw 2723400;
+ if (prop.vt != VT_BSTR)
+ throw 2723401;
+ return prop.bstrVal;
+}
+
+UString CPanel::GetItemName_for_Copy(unsigned itemIndex) const
+{
+ if (itemIndex == kParentIndex)
+ return L"..";
+ UString s;
+ {
+ NCOM::CPropVariant prop;
+ if (_folder->GetProperty(itemIndex, kpidOutName, &prop) == S_OK)
+ {
+ if (prop.vt == VT_BSTR)
+ s = prop.bstrVal;
+ else if (prop.vt != VT_EMPTY)
+ throw 2723401;
+ }
+ if (s.IsEmpty())
+ s = GetItemName(itemIndex);
+ }
+ return Get_Correct_FsFile_Name(s);
+}
+
+void CPanel::GetItemName(unsigned itemIndex, UString &s) const
+{
+ if (itemIndex == kParentIndex)
+ {
+ s = "..";
+ return;
+ }
+ NCOM::CPropVariant prop;
+ if (_folder->GetProperty(itemIndex, kpidName, &prop) != S_OK)
+ throw 2723400;
+ if (prop.vt != VT_BSTR)
+ throw 2723401;
+ s.SetFromBstr(prop.bstrVal);
+}
+
+UString CPanel::GetItemPrefix(unsigned itemIndex) const
+{
+ if (itemIndex == kParentIndex)
+ return UString();
+ NCOM::CPropVariant prop;
+ if (_folder->GetProperty(itemIndex, kpidPrefix, &prop) != S_OK)
+ throw 2723400;
+ UString prefix;
+ if (prop.vt == VT_BSTR)
+ prefix.SetFromBstr(prop.bstrVal);
+ return prefix;
+}
+
+UString CPanel::GetItemRelPath(unsigned itemIndex) const
+{
+ return GetItemPrefix(itemIndex) + GetItemName(itemIndex);
+}
+
+UString CPanel::GetItemRelPath2(unsigned itemIndex) const
+{
+ UString s = GetItemRelPath(itemIndex);
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (s.Len() == 2 && NFile::NName::IsDrivePath2(s))
+ {
+ if (IsFSDrivesFolder() && !IsDeviceDrivesPrefix())
+ s.Add_PathSepar();
+ }
+ #endif
+ return s;
+}
+
+
+void CPanel::Add_ItemRelPath2_To_String(unsigned itemIndex, UString &s) const
+{
+ if (itemIndex == kParentIndex)
+ {
+ s += "..";
+ return;
+ }
+
+ const unsigned start = s.Len();
+ NCOM::CPropVariant prop;
+ if (_folder->GetProperty(itemIndex, kpidPrefix, &prop) != S_OK)
+ throw 2723400;
+ if (prop.vt == VT_BSTR)
+ s += prop.bstrVal;
+
+ const wchar_t *name = NULL;
+ unsigned nameLen = 0;
+
+ if (_folderGetItemName)
+ _folderGetItemName->GetItemName(itemIndex, &name, &nameLen);
+ if (name)
+ s += name;
+ else
+ {
+ prop.Clear();
+ if (_folder->GetProperty(itemIndex, kpidName, &prop) != S_OK)
+ throw 2723400;
+ if (prop.vt != VT_BSTR)
+ throw 2723401;
+ s += prop.bstrVal;
+ }
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (s.Len() - start == 2 && NFile::NName::IsDrivePath2(s.Ptr(start)))
+ {
+ if (IsFSDrivesFolder() && !IsDeviceDrivesPrefix())
+ s.Add_PathSepar();
+ }
+ #endif
+}
+
+
+UString CPanel::GetItemFullPath(unsigned itemIndex) const
+{
+ return GetFsPath() + GetItemRelPath2(itemIndex);
+}
+
+bool CPanel::GetItem_BoolProp(UInt32 itemIndex, PROPID propID) const
+{
+ NCOM::CPropVariant prop;
+ if (_folder->GetProperty(itemIndex, propID, &prop) != S_OK)
+ throw 2723400;
+ if (prop.vt == VT_BOOL)
+ return VARIANT_BOOLToBool(prop.boolVal);
+ if (prop.vt == VT_EMPTY)
+ return false;
+ throw 2723401;
+}
+
+bool CPanel::IsItem_Deleted(unsigned itemIndex) const
+{
+ if (itemIndex == kParentIndex)
+ return false;
+ return GetItem_BoolProp(itemIndex, kpidIsDeleted);
+}
+
+bool CPanel::IsItem_Folder(unsigned itemIndex) const
+{
+ if (itemIndex == kParentIndex)
+ return true;
+ if (itemIndex < _isDirVector.Size())
+ return _isDirVector[itemIndex];
+ return GetItem_BoolProp(itemIndex, kpidIsDir);
+}
+
+bool CPanel::IsItem_AltStream(unsigned itemIndex) const
+{
+ if (itemIndex == kParentIndex)
+ return false;
+ return GetItem_BoolProp(itemIndex, kpidIsAltStream);
+}
+
+UInt64 CPanel::GetItem_UInt64Prop(unsigned itemIndex, PROPID propID) const
+{
+ if (itemIndex == kParentIndex)
+ return 0;
+ NCOM::CPropVariant prop;
+ if (_folder->GetProperty(itemIndex, propID, &prop) != S_OK)
+ throw 2723400;
+ UInt64 val = 0;
+ if (ConvertPropVariantToUInt64(prop, val))
+ return val;
+ return 0;
+}
+
+UInt64 CPanel::GetItemSize(unsigned itemIndex) const
+{
+ if (itemIndex == kParentIndex)
+ return 0;
+ if (_folderGetItemName)
+ return _folderGetItemName->GetItemSize(itemIndex);
+ return GetItem_UInt64Prop(itemIndex, kpidSize);
+}
+
+void CPanel::SaveListViewInfo()
+{
+ if (!_needSaveInfo)
+ return;
+
+ unsigned i;
+
+ for (i = 0; i < _visibleColumns.Size(); i++)
+ {
+ CPropColumn &prop = _visibleColumns[i];
+ LVCOLUMN winColumnInfo;
+ winColumnInfo.mask = LVCF_ORDER | LVCF_WIDTH;
+ if (!_listView.GetColumn(i, &winColumnInfo))
+ throw 1;
+ prop.Order = winColumnInfo.iOrder;
+ prop.Width = (UInt32)(Int32)winColumnInfo.cx;
+ }
+
+ CListViewInfo viewInfo;
+
+ // PROPID sortPropID = _columns[_sortIndex].ID;
+ PROPID sortPropID = _sortID;
+
+ // we save columns as "sorted by order" to registry
+
+ CPropColumns sortedProperties = _visibleColumns;
+
+ sortedProperties.Sort();
+
+ for (i = 0; i < sortedProperties.Size(); i++)
+ {
+ const CPropColumn &prop = sortedProperties[i];
+ CColumnInfo columnInfo;
+ columnInfo.IsVisible = prop.IsVisible;
+ columnInfo.PropID = prop.ID;
+ columnInfo.Width = prop.Width;
+ viewInfo.Columns.Add(columnInfo);
+ }
+
+ for (i = 0; i < _columns.Size(); i++)
+ {
+ const CPropColumn &prop = _columns[i];
+ if (sortedProperties.FindItem_for_PropID(prop.ID) < 0)
+ {
+ CColumnInfo columnInfo;
+ columnInfo.IsVisible = false;
+ columnInfo.PropID = prop.ID;
+ columnInfo.Width = prop.Width;
+ viewInfo.Columns.Add(columnInfo);
+ }
+ }
+
+ viewInfo.SortID = sortPropID;
+ viewInfo.Ascending = _ascending;
+ viewInfo.IsLoaded = true;
+ if (!_listViewInfo.IsEqual(viewInfo))
+ {
+ viewInfo.Save(_typeIDString);
+ _listViewInfo = viewInfo;
+ }
+}
+
+
+bool CPanel::OnRightClick(MY_NMLISTVIEW_NMITEMACTIVATE *itemActiveate, LRESULT &result)
+{
+ if (itemActiveate->hdr.hwndFrom == HWND(_listView))
+ return false;
+ POINT point;
+ ::GetCursorPos(&point);
+ ShowColumnsContextMenu(point.x, point.y);
+ result = TRUE;
+ return true;
+}
+
+void CPanel::ShowColumnsContextMenu(int x, int y)
+{
+ CMenu menu;
+ CMenuDestroyer menuDestroyer(menu);
+
+ menu.CreatePopup();
+
+ const int kCommandStart = 100;
+ FOR_VECTOR (i, _columns)
+ {
+ const CPropColumn &prop = _columns[i];
+ UINT flags = MF_STRING;
+ if (prop.IsVisible)
+ flags |= MF_CHECKED;
+ if (i == 0)
+ flags |= MF_GRAYED;
+ menu.AppendItem(flags, kCommandStart + i, prop.Name);
+ }
+
+ const int menuResult = menu.Track(TPM_LEFTALIGN | TPM_RETURNCMD | TPM_NONOTIFY, x, y, _listView);
+
+ if (menuResult >= kCommandStart && menuResult <= kCommandStart + (int)_columns.Size())
+ {
+ const unsigned index = (unsigned)(menuResult - kCommandStart);
+ CPropColumn &prop = _columns[index];
+ prop.IsVisible = !prop.IsVisible;
+
+ if (prop.IsVisible)
+ {
+ prop.Order = (int)_visibleColumns.Size();
+ AddColumn(prop);
+ }
+ else
+ {
+ const int visibleIndex = _visibleColumns.FindItem_for_PropID(prop.ID);
+ if (visibleIndex >= 0)
+ {
+ /*
+ if (_sortIndex == index)
+ {
+ _sortIndex = 0;
+ _ascending = true;
+ }
+ */
+ if (_sortID == prop.ID)
+ {
+ _sortID = kpidName;
+ _ascending = true;
+ }
+ DeleteColumn((unsigned)visibleIndex);
+ }
+ }
+ }
+}
+
+void CPanel::OnReload(bool onTimer)
+{
+ const HRESULT res = RefreshListCtrl_SaveFocused(onTimer);
+ if (res != S_OK)
+ MessageBox_Error_HRESULT(res);
+}
+
+void CPanel::OnTimer()
+{
+ if (!_processTimer)
+ return;
+ if (!AutoRefresh_Mode)
+ return;
+ CMyComPtr<IFolderWasChanged> folderWasChanged;
+ if (_folder.QueryInterface(IID_IFolderWasChanged, &folderWasChanged) != S_OK)
+ return;
+ Int32 wasChanged;
+ if (folderWasChanged->WasChanged(&wasChanged) != S_OK)
+ return;
+ if (wasChanged == 0)
+ return;
+ OnReload(true); // onTimer
+}
diff --git a/CPP/7zip/UI/FileManager/PanelKey.cpp b/CPP/7zip/UI/FileManager/PanelKey.cpp
new file mode 100644
index 0000000..a4ea489
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelKey.cpp
@@ -0,0 +1,357 @@
+// PanelKey.cpp
+
+#include "StdAfx.h"
+
+#include "Panel.h"
+#include "HelpUtils.h"
+
+#include "../../PropID.h"
+#include "App.h"
+
+using namespace NWindows;
+
+// #define kHelpTopic "FM/index.htm"
+
+struct CVKeyPropIDPair
+{
+ WORD VKey;
+ PROPID PropID;
+};
+
+static const CVKeyPropIDPair g_VKeyPropIDPairs[] =
+{
+ { VK_F3, kpidName },
+ { VK_F4, kpidExtension },
+ { VK_F5, kpidMTime },
+ { VK_F6, kpidSize },
+ { VK_F7, kpidNoProperty }
+};
+
+static int FindVKeyPropIDPair(WORD vKey)
+{
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_VKeyPropIDPairs); i++)
+ if (g_VKeyPropIDPairs[i].VKey == vKey)
+ return (int)i;
+ return -1;
+}
+
+
+bool CPanel::OnKeyDown(LPNMLVKEYDOWN keyDownInfo, LRESULT &result)
+{
+ if (keyDownInfo->wVKey == VK_TAB && keyDownInfo->hdr.hwndFrom == _listView)
+ {
+ _panelCallback->OnTab();
+ return false;
+ }
+ const bool alt = IsKeyDown(VK_MENU);
+ const bool ctrl = IsKeyDown(VK_CONTROL);
+ // const bool leftCtrl = IsKeyDown(VK_LCONTROL);
+ const bool rightCtrl = IsKeyDown(VK_RCONTROL);
+ const bool shift = IsKeyDown(VK_SHIFT);
+ result = 0;
+
+ if (keyDownInfo->wVKey >= '0' &&
+ keyDownInfo->wVKey <= '9' &&
+ (rightCtrl || alt))
+ {
+ const unsigned index = (unsigned)(keyDownInfo->wVKey - '0');
+ if (shift)
+ {
+ SetBookmark(index);
+ return true;
+ }
+ else
+ {
+ OpenBookmark(index);
+ return true;
+ }
+ }
+
+ if ((keyDownInfo->wVKey == VK_F2 ||
+ keyDownInfo->wVKey == VK_F1)
+ && alt && !ctrl && !shift)
+ {
+ _panelCallback->SetFocusToPath(keyDownInfo->wVKey == VK_F1 ? 0 : 1);
+ return true;
+ }
+
+ if ((keyDownInfo->wVKey == VK_F9) && !alt && !ctrl && !shift)
+ {
+ g_App.SwitchOnOffOnePanel();
+ }
+
+ if (keyDownInfo->wVKey >= VK_F3 && keyDownInfo->wVKey <= VK_F12 && ctrl)
+ {
+ const int index = FindVKeyPropIDPair(keyDownInfo->wVKey);
+ if (index >= 0)
+ SortItemsWithPropID(g_VKeyPropIDPairs[index].PropID);
+ }
+
+ switch (keyDownInfo->wVKey)
+ {
+ case VK_SHIFT:
+ {
+ _selectionIsDefined = false;
+ _prevFocusedItem = _listView.GetFocusedItem();
+ break;
+ }
+ /*
+ case VK_F1:
+ {
+ // ShowHelpWindow(NULL, kHelpTopic);
+ break;
+ }
+ */
+ case VK_F2:
+ {
+ if (!alt && !ctrl &&!shift)
+ {
+ RenameFile();
+ return true;
+ }
+ break;
+ }
+ case VK_F3:
+ {
+ if (!alt && !ctrl && !shift)
+ {
+ EditItem(false);
+ return true;
+ }
+ break;
+ }
+ case VK_F4:
+ {
+ if (!alt && !ctrl && !shift)
+ {
+ EditItem(true);
+ return true;
+ }
+ if (!alt && !ctrl && shift)
+ {
+ CreateFile();
+ return true;
+ }
+ break;
+ }
+ case VK_F5:
+ {
+ if (!alt && !ctrl)
+ {
+ _panelCallback->OnCopy(false, shift);
+ return true;
+ }
+ break;
+ }
+ case VK_F6:
+ {
+ if (!alt && !ctrl)
+ {
+ _panelCallback->OnCopy(true, shift);
+ return true;
+ }
+ break;
+ }
+ case VK_F7:
+ {
+ if (!alt && !ctrl && !shift)
+ {
+ /* we can process F7 via menu ACCELERATOR.
+ But menu loading can be slow in case of UNC paths and system menu.
+ So we use don't use ACCELERATOR */
+ CreateFolder();
+ return true;
+ }
+ break;
+ }
+ case VK_DELETE:
+ {
+ DeleteItems(!shift);
+ return true;
+ }
+ case VK_INSERT:
+ {
+ if (!alt)
+ {
+ if (ctrl && !shift)
+ {
+ EditCopy();
+ return true;
+ }
+ if (shift && !ctrl)
+ {
+ EditPaste();
+ return true;
+ }
+ if (!shift && !ctrl && _mySelectMode)
+ {
+ OnInsert();
+ return true;
+ }
+ }
+ return false;
+ }
+ case VK_DOWN:
+ {
+ if (shift)
+ OnArrowWithShift();
+ return false;
+ }
+ case VK_UP:
+ {
+ if (alt)
+ _panelCallback->OnSetSameFolder();
+ else if (shift)
+ OnArrowWithShift();
+ return false;
+ }
+ case VK_RIGHT:
+ {
+ if (alt)
+ _panelCallback->OnSetSubFolder();
+ else if (shift)
+ OnArrowWithShift();
+ return false;
+ }
+ case VK_LEFT:
+ {
+ if (alt)
+ _panelCallback->OnSetSubFolder();
+ else if (shift)
+ OnArrowWithShift();
+ return false;
+ }
+ case VK_NEXT:
+ {
+ if (ctrl && !alt && !shift)
+ {
+ // EnterToFocused();
+ return true;
+ }
+ break;
+ }
+ case VK_ADD:
+ {
+ if (alt)
+ SelectByType(true);
+ else if (shift)
+ SelectAll(true);
+ else if (!ctrl)
+ SelectSpec(true);
+ return true;
+ }
+ case VK_SUBTRACT:
+ {
+ if (alt)
+ SelectByType(false);
+ else if (shift)
+ SelectAll(false);
+ else
+ SelectSpec(false);
+ return true;
+ }
+ /*
+ case VK_DELETE:
+ CommandDelete();
+ return 0;
+ case VK_F1:
+ CommandHelp();
+ return 0;
+ */
+ case VK_BACK:
+ OpenParentFolder();
+ return true;
+ /*
+ case VK_DIVIDE:
+ case '\\':
+ case '/':
+ case VK_OEM_5:
+ {
+ // OpenRootFolder();
+ OpenDrivesFolder();
+
+ return true;
+ }
+ */
+ case 'A':
+ if (ctrl)
+ {
+ SelectAll(true);
+ return true;
+ }
+ return false;
+ case 'X':
+ if (ctrl)
+ {
+ EditCut();
+ return true;
+ }
+ return false;
+ case 'C':
+ if (ctrl)
+ {
+ EditCopy();
+ return true;
+ }
+ return false;
+ case 'V':
+ if (ctrl)
+ {
+ EditPaste();
+ return true;
+ }
+ return false;
+ case 'N':
+ if (ctrl)
+ {
+ CreateFile();
+ return true;
+ }
+ return false;
+ case 'R':
+ if (ctrl)
+ {
+ OnReload();
+ return true;
+ }
+ return false;
+ case 'W':
+ if (ctrl)
+ {
+ // SendMessage();
+ PostMessage(g_HWND, WM_COMMAND, IDCLOSE, 0);
+ return true;
+ }
+ return false;
+ case 'Z':
+ if (ctrl)
+ {
+ ChangeComment();
+ return true;
+ }
+ return false;
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ if (ctrl)
+ {
+ const unsigned styleIndex = (unsigned)(keyDownInfo->wVKey - '1');
+ SetListViewMode(styleIndex);
+ return true;
+ }
+ return false;
+ case VK_MULTIPLY:
+ {
+ InvertSelection();
+ return true;
+ }
+ case VK_F12:
+ if (alt && !ctrl && !shift)
+ {
+ FoldersHistory();
+ return true;
+ }
+ }
+ return false;
+}
diff --git a/CPP/7zip/UI/FileManager/PanelListNotify.cpp b/CPP/7zip/UI/FileManager/PanelListNotify.cpp
new file mode 100644
index 0000000..2fb0e87
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelListNotify.cpp
@@ -0,0 +1,870 @@
+// PanelListNotify.cpp
+
+#include "StdAfx.h"
+
+#include "resource.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/PropVariantConv.h"
+
+#include "../Common/PropIDUtils.h"
+#include "../../PropID.h"
+
+#include "App.h"
+#include "Panel.h"
+#include "FormatUtils.h"
+
+using namespace NWindows;
+
+/* Unicode characters for space:
+0x009C STRING TERMINATOR
+0x00B7 Middle dot
+0x237D Shouldered open box
+0x2420 Symbol for space
+0x2422 Blank symbol
+0x2423 Open box
+*/
+
+#define SPACE_REPLACE_CHAR (wchar_t)(0x2423)
+#define SPACE_TERMINATOR_CHAR (wchar_t)(0x9C)
+
+#define INT_TO_STR_SPEC(v) \
+ while (v >= 10) { temp[i++] = (unsigned char)('0' + (unsigned)(v % 10)); v /= 10; } \
+ *s++ = (unsigned char)('0' + (unsigned)v);
+
+static void ConvertSizeToString(UInt64 val, wchar_t *s) throw()
+{
+ unsigned char temp[32];
+ unsigned i = 0;
+
+ if (val <= (UInt32)0xFFFFFFFF)
+ {
+ UInt32 val32 = (UInt32)val;
+ INT_TO_STR_SPEC(val32)
+ }
+ else
+ {
+ INT_TO_STR_SPEC(val)
+ }
+
+ if (i < 3)
+ {
+ if (i != 0)
+ {
+ *s++ = temp[(size_t)i - 1];
+ if (i == 2)
+ *s++ = temp[0];
+ }
+ *s = 0;
+ return;
+ }
+
+ unsigned r = i % 3;
+ if (r != 0)
+ {
+ s[0] = temp[--i];
+ if (r == 2)
+ s[1] = temp[--i];
+ s += r;
+ }
+
+ do
+ {
+ s[0] = ' ';
+ s[1] = temp[(size_t)i - 1];
+ s[2] = temp[(size_t)i - 2];
+ s[3] = temp[(size_t)i - 3];
+ s += 4;
+ }
+ while (i -= 3);
+
+ *s = 0;
+}
+
+UString ConvertSizeToString(UInt64 value);
+UString ConvertSizeToString(UInt64 value)
+{
+ wchar_t s[32];
+ ConvertSizeToString(value, s);
+ return s;
+}
+
+static inline unsigned GetHex_Upper(unsigned v)
+{
+ return (v < 10) ? ('0' + v) : ('A' + (v - 10));
+}
+
+static inline unsigned GetHex_Lower(unsigned v)
+{
+ return (v < 10) ? ('0' + v) : ('a' + (v - 10));
+}
+
+/*
+static void HexToString(char *dest, const Byte *data, UInt32 size)
+{
+ for (UInt32 i = 0; i < size; i++)
+ {
+ unsigned b = data[i];
+ dest[0] = GetHex((b >> 4) & 0xF);
+ dest[1] = GetHex(b & 0xF);
+ dest += 2;
+ }
+ *dest = 0;
+}
+*/
+
+bool IsSizeProp(UINT propID) throw();
+bool IsSizeProp(UINT propID) throw()
+{
+ switch (propID)
+ {
+ case kpidSize:
+ case kpidPackSize:
+ case kpidNumSubDirs:
+ case kpidNumSubFiles:
+ case kpidOffset:
+ case kpidLinks:
+ case kpidNumBlocks:
+ case kpidNumVolumes:
+ case kpidPhySize:
+ case kpidHeadersSize:
+ case kpidTotalSize:
+ case kpidFreeSpace:
+ case kpidClusterSize:
+ case kpidNumErrors:
+ case kpidNumStreams:
+ case kpidNumAltStreams:
+ case kpidAltStreamsSize:
+ case kpidVirtualSize:
+ case kpidUnpackSize:
+ case kpidTotalPhySize:
+ case kpidTailSize:
+ case kpidEmbeddedStubSize:
+ return true;
+ }
+ return false;
+}
+
+
+
+/*
+#include <stdio.h>
+
+UInt64 GetCpuTicks()
+{
+ #ifdef _WIN64
+ return __rdtsc();
+ #else
+ UInt32 lowVal, highVal;
+ __asm RDTSC;
+ __asm mov lowVal, EAX;
+ __asm mov highVal, EDX;
+ return ((UInt64)highVal << 32) | lowVal;
+ #endif
+}
+
+UInt32 g_NumGroups;
+UInt64 g_start_tick;
+UInt64 g_prev_tick;
+DWORD g_Num_SetItemText;
+UInt32 g_NumMessages;
+*/
+
+LRESULT CPanel::SetItemText(LVITEMW &item)
+{
+ if (_dontShowMode)
+ return 0;
+ UInt32 realIndex = GetRealIndex(item);
+
+ // g_Num_SetItemText++;
+
+ /*
+ if ((item.mask & LVIF_IMAGE) != 0)
+ {
+ bool defined = false;
+ CComPtr<IFolderGetSystemIconIndex> folderGetSystemIconIndex;
+ _folder.QueryInterface(&folderGetSystemIconIndex);
+ if (folderGetSystemIconIndex)
+ {
+ folderGetSystemIconIndex->GetSystemIconIndex(index, &item.iImage);
+ defined = (item.iImage > 0);
+ }
+ if (!defined)
+ {
+ NCOM::CPropVariant prop;
+ _folder->GetProperty(index, kpidAttrib, &prop);
+ UINT32 attrib = 0;
+ if (prop.vt == VT_UI4)
+ attrib = prop.ulVal;
+ else if (IsItemFolder(index))
+ attrib |= FILE_ATTRIBUTE_DIRECTORY;
+ if (_currentFolderPrefix.IsEmpty())
+ throw 1;
+ else
+ item.iImage = _extToIconMap.GetIconIndex(attrib, GetSystemString(GetItemName(index)));
+ }
+ // item.iImage = 1;
+ }
+ */
+
+ if ((item.mask & LVIF_TEXT) == 0)
+ return 0;
+
+ LPWSTR text = item.pszText;
+
+ if (item.cchTextMax > 0)
+ text[0] = 0;
+
+ if (item.cchTextMax <= 1)
+ return 0;
+
+ const CPropColumn &property = _visibleColumns[item.iSubItem];
+ PROPID propID = property.ID;
+
+ if (realIndex == kParentIndex_UInt32)
+ {
+ if (propID == kpidName)
+ {
+ if (item.cchTextMax > 2)
+ {
+ text[0] = '.';
+ text[1] = '.';
+ text[2] = 0;
+ }
+ }
+ return 0;
+ }
+
+ /*
+ // List-view in report-view in Windows 10 is slow (50+ ms) for page change.
+ // that code shows the time of page reload for items
+ // if you know how to improve the speed of list view refresh, notify 7-Zip developer
+
+ // if (propID == 2000)
+ // if (propID == kpidName)
+ {
+ // debug column;
+ // DWORD dw = GetCpuTicks();
+ UInt64 dw = GetCpuTicks();
+ UInt64 deltaLast = dw - g_prev_tick;
+ #define conv_ticks(t) ((unsigned)((t) / 100000))
+ if (deltaLast > 1000u * 1000 * 1000)
+ {
+ UInt64 deltaFull = g_prev_tick - g_start_tick;
+ char s[128];
+ sprintf(s, "%d", conv_ticks(deltaFull));
+ OutputDebugStringA(s);
+ g_start_tick = dw;
+ g_NumGroups++;
+ }
+ g_prev_tick = dw;
+ UString u;
+ char s[128];
+ UInt64 deltaFull = dw - g_start_tick;
+ // for (int i = 0; i < 100000; i++)
+ sprintf(s, "%d %d %d-%d ", g_NumMessages, g_Num_SetItemText, g_NumGroups, conv_ticks(deltaFull));
+ // sprintf(s, "%d-%d ", g_NumGroups, conv_ticks(deltaFull));
+ u = s;
+ lstrcpyW(text, u.Ptr());
+ text += u.Len();
+
+ // dw = GetCpuTicks();
+ // deltaFull = dw - g_prev_tick;
+ // sprintf(s, "-%d ", conv_ticks(deltaFull));
+ // u = s;
+ // lstrcpyW(text, u.Ptr());
+ // text += u.Len();
+
+ if (propID != kpidName)
+ return 0;
+ }
+ */
+
+
+ if (property.IsRawProp)
+ {
+ const void *data;
+ UInt32 dataSize;
+ UInt32 propType;
+ RINOK(_folderRawProps->GetRawProp(realIndex, propID, &data, &dataSize, &propType))
+ const unsigned limit = (unsigned)item.cchTextMax - 1;
+ if (dataSize == 0)
+ {
+ text[0] = 0;
+ return 0;
+ }
+
+ if (propID == kpidNtReparse)
+ {
+ UString s;
+ ConvertNtReparseToString((const Byte *)data, dataSize, s);
+ if (!s.IsEmpty())
+ {
+ unsigned i;
+ for (i = 0; i < limit; i++)
+ {
+ wchar_t c = s[i];
+ if (c == 0)
+ break;
+ text[i] = c;
+ }
+ text[i] = 0;
+ return 0;
+ }
+ }
+ else if (propID == kpidNtSecure)
+ {
+ AString s;
+ ConvertNtSecureToString((const Byte *)data, dataSize, s);
+ if (!s.IsEmpty())
+ {
+ unsigned i;
+ for (i = 0; i < limit; i++)
+ {
+ wchar_t c = (Byte)s[i];
+ if (c == 0)
+ break;
+ text[i] = c;
+ }
+ text[i] = 0;
+ return 0;
+ }
+ }
+ {
+ const unsigned kMaxDataSize = 64;
+ if (dataSize > kMaxDataSize)
+ {
+ char temp[32];
+ MyStringCopy(temp, "data:");
+ ConvertUInt32ToString(dataSize, temp + 5);
+ unsigned i;
+ for (i = 0; i < limit; i++)
+ {
+ wchar_t c = (Byte)temp[i];
+ if (c == 0)
+ break;
+ text[i] = c;
+ }
+ text[i] = 0;
+ }
+ else
+ {
+ if (dataSize > limit)
+ dataSize = limit;
+ WCHAR *dest = text;
+ const bool needUpper = (dataSize <= 8)
+ && (propID == kpidCRC || propID == kpidChecksum);
+ for (UInt32 i = 0; i < dataSize; i++)
+ {
+ unsigned b = ((const Byte *)data)[i];
+ if (needUpper)
+ {
+ dest[0] = (WCHAR)GetHex_Upper((b >> 4) & 0xF);
+ dest[1] = (WCHAR)GetHex_Upper(b & 0xF);
+ }
+ else
+ {
+ dest[0] = (WCHAR)GetHex_Lower((b >> 4) & 0xF);
+ dest[1] = (WCHAR)GetHex_Lower(b & 0xF);
+ }
+ dest += 2;
+ }
+ *dest = 0;
+ }
+ }
+ return 0;
+ }
+ /*
+ {
+ NCOM::CPropVariant prop;
+ if (propID == kpidType)
+ string = GetFileType(index);
+ else
+ {
+ HRESULT result = m_ArchiveFolder->GetProperty(index, propID, &prop);
+ if (result != S_OK)
+ {
+ // PrintMessage("GetPropertyValue error");
+ return 0;
+ }
+ string = ConvertPropertyToString(prop, propID, false);
+ }
+ }
+ */
+ // const NFind::CFileInfo &aFileInfo = m_Files[index];
+
+ NCOM::CPropVariant prop;
+ /*
+ bool needRead = true;
+ if (propID == kpidSize)
+ {
+ CComPtr<IFolderGetItemFullSize> getItemFullSize;
+ if (_folder.QueryInterface(&getItemFullSize) == S_OK)
+ {
+ if (getItemFullSize->GetItemFullSize(index, &prop) == S_OK)
+ needRead = false;
+ }
+ }
+ if (needRead)
+ */
+
+ if (item.cchTextMax < 32)
+ return 0;
+
+ if (propID == kpidName)
+ {
+ if (_folderGetItemName)
+ {
+ const wchar_t *name = NULL;
+ unsigned nameLen = 0;
+ _folderGetItemName->GetItemName(realIndex, &name, &nameLen);
+
+ if (name)
+ {
+ unsigned dest = 0;
+ const unsigned limit = (unsigned)item.cchTextMax - 1;
+
+ for (unsigned i = 0; dest < limit;)
+ {
+ const wchar_t c = name[i++];
+ if (c == 0)
+ break;
+ text[dest++] = c;
+
+ if (c != ' ')
+ {
+ if (c != 0x202E) // RLO
+ continue;
+ text[(size_t)dest - 1] = '_';
+ continue;
+ }
+
+ if (name[i] != ' ')
+ continue;
+
+ unsigned t = 1;
+ for (; name[i + t] == ' '; t++);
+
+ if (t >= 4 && dest + 4 < limit)
+ {
+ text[dest++] = '.';
+ text[dest++] = '.';
+ text[dest++] = '.';
+ text[dest++] = ' ';
+ i += t;
+ }
+ }
+
+ if (dest == 0)
+ text[dest++]= '_';
+
+ #ifdef _WIN32
+ else if (text[(size_t)dest - 1] == ' ')
+ {
+ if (dest < limit)
+ text[dest++] = SPACE_TERMINATOR_CHAR;
+ else
+ text[dest - 1] = SPACE_REPLACE_CHAR;
+ }
+ #endif
+
+ text[dest] = 0;
+ // OutputDebugStringW(text);
+ return 0;
+ }
+ }
+ }
+
+ if (propID == kpidPrefix)
+ {
+ if (_folderGetItemName)
+ {
+ const wchar_t *name = NULL;
+ unsigned nameLen = 0;
+ _folderGetItemName->GetItemPrefix(realIndex, &name, &nameLen);
+ if (name)
+ {
+ unsigned dest = 0;
+ const unsigned limit = (unsigned)item.cchTextMax - 1;
+ for (unsigned i = 0; dest < limit;)
+ {
+ const wchar_t c = name[i++];
+ if (c == 0)
+ break;
+ text[dest++] = c;
+ }
+ text[dest] = 0;
+ return 0;
+ }
+ }
+ }
+
+ const HRESULT res = _folder->GetProperty(realIndex, propID, &prop);
+
+ if (res != S_OK)
+ {
+ MyStringCopy(text, L"Error: ");
+ // s = UString("Error: ") + HResultToMessage(res);
+ }
+ else if ((prop.vt == VT_UI8 || prop.vt == VT_UI4 || prop.vt == VT_UI2) && IsSizeProp(propID))
+ {
+ UInt64 v = 0;
+ ConvertPropVariantToUInt64(prop, v);
+ ConvertSizeToString(v, text);
+ }
+ else if (prop.vt == VT_BSTR)
+ {
+ const unsigned limit = (unsigned)item.cchTextMax - 1;
+ const wchar_t *src = prop.bstrVal;
+ unsigned i;
+ for (i = 0; i < limit; i++)
+ {
+ wchar_t c = src[i];
+ if (c == 0) break;
+ if (c == 0xA) c = ' ';
+ if (c == 0xD) c = ' ';
+ text[i] = c;
+ }
+ text[i] = 0;
+ }
+ else
+ {
+ char temp[64];
+ ConvertPropertyToShortString2(temp, prop, propID, _timestampLevel);
+ unsigned i;
+ const unsigned limit = (unsigned)item.cchTextMax - 1;
+ for (i = 0; i < limit; i++)
+ {
+ const wchar_t c = (Byte)temp[i];
+ if (c == 0)
+ break;
+ text[i] = c;
+ }
+ text[i] = 0;
+ }
+
+ return 0;
+}
+
+#ifndef UNDER_CE
+extern DWORD g_ComCtl32Version;
+#endif
+
+void CPanel::OnItemChanged(NMLISTVIEW *item)
+{
+ const unsigned index = (unsigned)item->lParam;
+ if (index == kParentIndex)
+ return;
+ const bool oldSelected = (item->uOldState & LVIS_SELECTED) != 0;
+ const bool newSelected = (item->uNewState & LVIS_SELECTED) != 0;
+ // Don't change this code. It works only with such check
+ if (oldSelected != newSelected)
+ _selectedStatusVector[index] = newSelected;
+}
+
+extern bool g_LVN_ITEMACTIVATE_Support;
+
+void CPanel::OnNotifyActivateItems()
+{
+ bool alt = IsKeyDown(VK_MENU);
+ bool ctrl = IsKeyDown(VK_CONTROL);
+ bool shift = IsKeyDown(VK_SHIFT);
+ if (!shift && alt && !ctrl)
+ Properties();
+ else
+ OpenSelectedItems(!shift || alt || ctrl);
+}
+
+bool CPanel::OnNotifyList(LPNMHDR header, LRESULT &result)
+{
+ switch (header->code)
+ {
+ case LVN_ITEMCHANGED:
+ {
+ if (_enableItemChangeNotify)
+ {
+ if (!_mySelectMode)
+ OnItemChanged((LPNMLISTVIEW)header);
+
+ // Post_Refresh_StatusBar();
+ /* 9.26: we don't call Post_Refresh_StatusBar.
+ it was very slow if we select big number of files
+ and then clead slection by selecting just new file.
+ probably it called slow Refresh_StatusBar for each item deselection.
+ I hope Refresh_StatusBar still will be called for each key / mouse action.
+ */
+ }
+ return false;
+ }
+ /*
+
+ case LVN_ODSTATECHANGED:
+ {
+ break;
+ }
+ */
+
+ case LVN_GETDISPINFOW:
+ {
+ LV_DISPINFOW *dispInfo = (LV_DISPINFOW *)header;
+
+ //is the sub-item information being requested?
+
+ if ((dispInfo->item.mask & LVIF_TEXT) != 0 ||
+ (dispInfo->item.mask & LVIF_IMAGE) != 0)
+ SetItemText(dispInfo->item);
+ {
+ // 20.03:
+ result = 0;
+ return true;
+ // old 7-Zip:
+ // return false;
+ }
+ }
+ case LVN_KEYDOWN:
+ {
+ LPNMLVKEYDOWN keyDownInfo = LPNMLVKEYDOWN(header);
+ bool boolResult = OnKeyDown(keyDownInfo, result);
+ switch (keyDownInfo->wVKey)
+ {
+ case VK_CONTROL:
+ case VK_SHIFT:
+ case VK_MENU:
+ break;
+ default:
+ Post_Refresh_StatusBar();
+ }
+ return boolResult;
+ }
+
+ case LVN_COLUMNCLICK:
+ OnColumnClick(LPNMLISTVIEW(header));
+ return false;
+
+ case LVN_ITEMACTIVATE:
+ if (g_LVN_ITEMACTIVATE_Support)
+ {
+ OnNotifyActivateItems();
+ return false;
+ }
+ break;
+ case NM_DBLCLK:
+ case NM_RETURN:
+ if (!g_LVN_ITEMACTIVATE_Support)
+ {
+ OnNotifyActivateItems();
+ return false;
+ }
+ break;
+
+ case NM_RCLICK:
+ Post_Refresh_StatusBar();
+ break;
+
+ /*
+ return OnRightClick((LPNMITEMACTIVATE)header, result);
+ */
+ /*
+ case NM_CLICK:
+ SendRefreshStatusBarMessage();
+ return 0;
+
+ // TODO : Handler default action...
+ return 0;
+ case LVN_ITEMCHANGED:
+ {
+ NMLISTVIEW *pNMLV = (NMLISTVIEW *) lpnmh;
+ SelChange(pNMLV);
+ return TRUE;
+ }
+ case NM_SETFOCUS:
+ return onSetFocus(NULL);
+ case NM_KILLFOCUS:
+ return onKillFocus(NULL);
+ */
+ case NM_CLICK:
+ {
+ // we need SetFocusToList, if we drag-select items from other panel.
+ SetFocusToList();
+ Post_Refresh_StatusBar();
+ if (_mySelectMode)
+ #ifndef UNDER_CE
+ if (g_ComCtl32Version >= MAKELONG(71, 4))
+ #endif
+ OnLeftClick((MY_NMLISTVIEW_NMITEMACTIVATE *)header);
+ return false;
+ }
+ case LVN_BEGINLABELEDITW:
+ result = OnBeginLabelEdit((LV_DISPINFOW *)header);
+ return true;
+ case LVN_ENDLABELEDITW:
+ result = OnEndLabelEdit((LV_DISPINFOW *)header);
+ return true;
+
+ case NM_CUSTOMDRAW:
+ {
+ if (_mySelectMode || (_markDeletedItems && _thereAreDeletedItems))
+ return OnCustomDraw((LPNMLVCUSTOMDRAW)header, result);
+ break;
+ }
+ case LVN_BEGINDRAG:
+ {
+ OnDrag((LPNMLISTVIEW)header, false);
+ Post_Refresh_StatusBar();
+ break;
+ }
+ case LVN_BEGINRDRAG:
+ {
+ OnDrag((LPNMLISTVIEW)header, true);
+ Post_Refresh_StatusBar();
+ break;
+ }
+ // case LVN_BEGINRDRAG:
+ }
+ return false;
+}
+
+bool CPanel::OnCustomDraw(LPNMLVCUSTOMDRAW lplvcd, LRESULT &result)
+{
+ switch (lplvcd->nmcd.dwDrawStage)
+ {
+ case CDDS_PREPAINT :
+ result = CDRF_NOTIFYITEMDRAW;
+ return true;
+
+ case CDDS_ITEMPREPAINT:
+ /*
+ SelectObject(lplvcd->nmcd.hdc,
+ GetFontForItem(lplvcd->nmcd.dwItemSpec,
+ lplvcd->nmcd.lItemlParam) );
+ lplvcd->clrText = GetColorForItem(lplvcd->nmcd.dwItemSpec,
+ lplvcd->nmcd.lItemlParam);
+ lplvcd->clrTextBk = GetBkColorForItem(lplvcd->nmcd.dwItemSpec,
+ lplvcd->nmcd.lItemlParam);
+ */
+ const unsigned realIndex = (unsigned)lplvcd->nmcd.lItemlParam;
+ lplvcd->clrTextBk = _listView.GetBkColor();
+ if (_mySelectMode)
+ {
+ if (realIndex != kParentIndex && _selectedStatusVector[realIndex])
+ lplvcd->clrTextBk = RGB(255, 192, 192);
+ }
+
+ if (_markDeletedItems && _thereAreDeletedItems)
+ {
+ if (IsItem_Deleted(realIndex))
+ lplvcd->clrText = RGB(255, 0, 0);
+ }
+ // lplvcd->clrText = RGB(0, 0, 0);
+ // result = CDRF_NEWFONT;
+ result = CDRF_NOTIFYITEMDRAW;
+ return true;
+
+ // return false;
+ // return true;
+ /*
+ case CDDS_SUBITEM | CDDS_ITEMPREPAINT:
+ if (lplvcd->iSubItem == 0)
+ {
+ // lplvcd->clrText = RGB(255, 0, 0);
+ lplvcd->clrTextBk = RGB(192, 192, 192);
+ }
+ else
+ {
+ lplvcd->clrText = RGB(0, 0, 0);
+ lplvcd->clrTextBk = RGB(255, 255, 255);
+ }
+ return true;
+ */
+
+ /* At this point, you can change the background colors for the item
+ and any subitems and return CDRF_NEWFONT. If the list-view control
+ is in report mode, you can simply return CDRF_NOTIFYSUBITEMREDRAW
+ to customize the item's subitems individually */
+ }
+ return false;
+}
+
+void CPanel::Refresh_StatusBar()
+{
+ /*
+ g_name_cnt++;
+ char s[256];
+ sprintf(s, "g_name_cnt = %8d", g_name_cnt);
+ OutputDebugStringA(s);
+ */
+ // DWORD dw = GetTickCount();
+
+ CRecordVector<UInt32> indices;
+ Get_ItemIndices_Operated(indices);
+
+ {
+ UString s;
+ s.Add_UInt32(indices.Size());
+ s += " / ";
+ s.Add_UInt32(_selectedStatusVector.Size());
+
+ // UString s1 = MyFormatNew(g_App.LangString_N_SELECTED_ITEMS, NumberToString(indices.Size()));
+ // UString s1 = MyFormatNew(IDS_N_SELECTED_ITEMS, NumberToString(indices.Size()));
+ _statusBar.SetText(0, MyFormatNew(g_App.LangString_N_SELECTED_ITEMS, s));
+ // _statusBar.SetText(0, MyFormatNew(IDS_N_SELECTED_ITEMS, NumberToString(indices.Size())));
+ }
+
+ {
+ wchar_t selectSizeString[32];
+ selectSizeString[0] = 0;
+
+ if (indices.Size() > 0)
+ {
+ // for (unsigned ttt = 0; ttt < 1000; ttt++) {
+ UInt64 totalSize = 0;
+ FOR_VECTOR (i, indices)
+ totalSize += GetItemSize(indices[i]);
+ ConvertSizeToString(totalSize, selectSizeString);
+ // }
+ }
+ _statusBar.SetText(1, selectSizeString);
+ }
+
+ const int focusedItem = _listView.GetFocusedItem();
+ wchar_t sizeString[32];
+ sizeString[0] = 0;
+ wchar_t dateString[32];
+ dateString[0] = 0;
+ if (focusedItem >= 0 && _listView.GetSelectedCount() > 0)
+ {
+ const unsigned realIndex = GetRealItemIndex(focusedItem);
+ if (realIndex != kParentIndex)
+ {
+ ConvertSizeToString(GetItemSize(realIndex), sizeString);
+ NCOM::CPropVariant prop;
+ if (_folder->GetProperty(realIndex, kpidMTime, &prop) == S_OK)
+ {
+ char dateString2[32];
+ dateString2[0] = 0;
+ ConvertPropertyToShortString2(dateString2, prop, kpidMTime);
+ for (unsigned i = 0;; i++)
+ {
+ char c = dateString2[i];
+ dateString[i] = (Byte)c;
+ if (c == 0)
+ break;
+ }
+ }
+ }
+ }
+ _statusBar.SetText(2, sizeString);
+ _statusBar.SetText(3, dateString);
+
+ // _statusBar.SetText(4, nameString);
+ // _statusBar2.SetText(1, MyFormatNew(L"{0} bytes", NumberToStringW(totalSize)));
+ // }
+ /*
+ dw = GetTickCount() - dw;
+ sprintf(s, "status = %8d ms", dw);
+ OutputDebugStringA(s);
+ */
+}
diff --git a/CPP/7zip/UI/FileManager/PanelMenu.cpp b/CPP/7zip/UI/FileManager/PanelMenu.cpp
new file mode 100644
index 0000000..f0afe15
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelMenu.cpp
@@ -0,0 +1,1176 @@
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/COM.h"
+#include "../../../Windows/Clipboard.h"
+#include "../../../Windows/Menu.h"
+#include "../../../Windows/PropVariant.h"
+#include "../../../Windows/PropVariantConv.h"
+
+#include "../../PropID.h"
+#include "../Common/PropIDUtils.h"
+#include "../Explorer/ContextMenu.h"
+
+#include "App.h"
+#include "FormatUtils.h"
+#include "LangUtils.h"
+#include "ListViewDialog.h"
+#include "MyLoadMenu.h"
+#include "PropertyName.h"
+
+#include "PropertyNameRes.h"
+#include "resource.h"
+
+// #define SHOW_DEBUG_PANEL_MENU
+
+using namespace NWindows;
+
+extern
+LONG g_DllRefCount;
+LONG g_DllRefCount = 0;
+
+static const UINT kSevenZipStartMenuID = kMenuCmdID_Plugin_Start;
+static const UINT kSystemStartMenuID = kMenuCmdID_Plugin_Start + 400;
+
+
+#ifdef SHOW_DEBUG_PANEL_MENU
+static void Print_Ptr(void *p, const char *s)
+{
+ char temp[32];
+ ConvertUInt64ToHex((UInt64)(void *)p, temp);
+ AString m;
+ m += temp;
+ m.Add_Space();
+ m += s;
+ OutputDebugStringA(m);
+}
+#define ODS(sz) { Print_Ptr(this, sz); }
+#define ODS_U(s) { OutputDebugStringW(s); }
+#else
+#define ODS(sz)
+#define ODS_U(s)
+#endif
+
+
+void CPanel::InvokeSystemCommand(const char *command)
+{
+ NCOM::CComInitializer comInitializer;
+ if (!IsFsOrPureDrivesFolder())
+ return;
+ CRecordVector<UInt32> operatedIndices;
+ Get_ItemIndices_Operated(operatedIndices);
+ if (operatedIndices.IsEmpty())
+ return;
+ CMyComPtr<IContextMenu> contextMenu;
+ if (CreateShellContextMenu(operatedIndices, contextMenu) != S_OK)
+ return;
+
+ CMINVOKECOMMANDINFO ci;
+ ZeroMemory(&ci, sizeof(ci));
+ ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
+ ci.hwnd = GetParent();
+ ci.lpVerb = command;
+ contextMenu->InvokeCommand(&ci);
+}
+
+static const char * const kSeparator = "------------------------";
+static const char * const kSeparatorSmall = "----------------";
+
+extern UString ConvertSizeToString(UInt64 value) throw();
+bool IsSizeProp(UINT propID) throw();
+
+UString GetOpenArcErrorMessage(UInt32 errorFlags);
+
+
+static void AddListAscii(CListViewDialog &dialog, const char *s)
+{
+ dialog.Strings.Add((UString)s);
+ dialog.Values.AddNew();
+}
+
+static void AddSeparator(CListViewDialog &dialog)
+{
+ AddListAscii(dialog, kSeparator);
+}
+
+static void AddSeparatorSmall(CListViewDialog &dialog)
+{
+ AddListAscii(dialog, kSeparatorSmall);
+}
+
+static void AddPropertyPair(const UString &name, const UString &val, CListViewDialog &dialog)
+{
+ dialog.Strings.Add(name);
+ dialog.Values.Add(val);
+}
+
+
+static void AddPropertyString(PROPID propID, const wchar_t *nameBSTR,
+ const NCOM::CPropVariant &prop, CListViewDialog &dialog)
+{
+ if (prop.vt != VT_EMPTY)
+ {
+ UString val;
+
+ if (propID == kpidErrorFlags ||
+ propID == kpidWarningFlags)
+ {
+ UInt32 flags = GetOpenArcErrorFlags(prop);
+ if (flags == 0)
+ return;
+ if (flags != 0)
+ val = GetOpenArcErrorMessage(flags);
+ }
+
+ if (val.IsEmpty())
+ {
+ if ((prop.vt == VT_UI8 || prop.vt == VT_UI4 || prop.vt == VT_UI2) && IsSizeProp(propID))
+ {
+ UInt64 v = 0;
+ ConvertPropVariantToUInt64(prop, v);
+ val = ConvertSizeToString(v);
+ }
+ else
+ ConvertPropertyToString2(val, prop, propID, 9); // we send 9 - is ns precision
+ }
+
+ if (!val.IsEmpty())
+ {
+ if (propID == kpidErrorType)
+ {
+ AddPropertyPair(L"Open WARNING:", L"Cannot open the file as expected archive type", dialog);
+ }
+ AddPropertyPair(GetNameOfProperty(propID, nameBSTR), val, dialog);
+ }
+ }
+}
+
+
+static void AddPropertyString(PROPID propID, UInt64 val, CListViewDialog &dialog)
+{
+ NCOM::CPropVariant prop = val;
+ AddPropertyString(propID, NULL, prop, dialog);
+}
+
+
+static inline unsigned GetHex_Upper(unsigned v)
+{
+ return (v < 10) ? ('0' + v) : ('A' + (v - 10));
+}
+
+static inline unsigned GetHex_Lower(unsigned v)
+{
+ return (v < 10) ? ('0' + v) : ('a' + (v - 10));
+}
+
+static const Byte kSpecProps[] =
+{
+ kpidPath,
+ kpidType,
+ kpidErrorType,
+ kpidError,
+ kpidErrorFlags,
+ kpidWarning,
+ kpidWarningFlags,
+ kpidOffset,
+ kpidPhySize,
+ kpidTailSize
+};
+
+void CPanel::Properties()
+{
+ CMyComPtr<IGetFolderArcProps> getFolderArcProps;
+ _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps);
+ if (!getFolderArcProps)
+ {
+ InvokeSystemCommand("properties");
+ return;
+ }
+
+ {
+ CListViewDialog message;
+ // message.DeleteIsAllowed = false;
+ // message.SelectFirst = false;
+
+ CRecordVector<UInt32> operatedIndices;
+ Get_ItemIndices_Operated(operatedIndices);
+
+ if (operatedIndices.Size() == 1)
+ {
+ UInt32 index = operatedIndices[0];
+ // message += "Item:\n");
+ UInt32 numProps;
+ if (_folder->GetNumberOfProperties(&numProps) == S_OK)
+ {
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE varType;
+
+ if (_folder->GetPropertyInfo(i, &name, &propID, &varType) != S_OK)
+ continue;
+
+ NCOM::CPropVariant prop;
+ if (_folder->GetProperty(index, propID, &prop) != S_OK)
+ continue;
+ AddPropertyString(propID, name, prop, message);
+ }
+ }
+
+
+ if (_folderRawProps)
+ {
+ _folderRawProps->GetNumRawProps(&numProps);
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ if (_folderRawProps->GetRawPropInfo(i, &name, &propID) != S_OK)
+ continue;
+
+ const void *data;
+ UInt32 dataSize;
+ UInt32 propType;
+ if (_folderRawProps->GetRawProp(index, propID, &data, &dataSize, &propType) != S_OK)
+ continue;
+
+ if (dataSize != 0)
+ {
+ AString s;
+ if (propID == kpidNtSecure)
+ ConvertNtSecureToString((const Byte *)data, dataSize, s);
+ else
+ {
+ const UInt32 kMaxDataSize = 64;
+ if (dataSize > kMaxDataSize)
+ {
+ s += "data:";
+ s.Add_UInt32(dataSize);
+ }
+ else
+ {
+ const bool needUpper = (dataSize <= 8)
+ && (propID == kpidCRC || propID == kpidChecksum);
+ for (UInt32 k = 0; k < dataSize; k++)
+ {
+ const Byte b = ((const Byte *)data)[k];
+ if (needUpper)
+ {
+ s += (char)GetHex_Upper((b >> 4) & 0xF);
+ s += (char)GetHex_Upper(b & 0xF);
+ }
+ else
+ {
+ s += (char)GetHex_Lower((b >> 4) & 0xF);
+ s += (char)GetHex_Lower(b & 0xF);
+ }
+ }
+ }
+ }
+ AddPropertyPair(GetNameOfProperty(propID, name), (UString)s.Ptr(), message);
+ }
+ }
+ }
+
+ AddSeparator(message);
+ }
+ else if (operatedIndices.Size() >= 1)
+ {
+ UInt64 packSize = 0;
+ UInt64 unpackSize = 0;
+ UInt64 numFiles = 0;
+ UInt64 numDirs = 0;
+
+ FOR_VECTOR (i, operatedIndices)
+ {
+ const UInt32 index = operatedIndices[i];
+ unpackSize += GetItemSize(index);
+ packSize += GetItem_UInt64Prop(index, kpidPackSize);
+ if (IsItem_Folder(index))
+ {
+ numDirs++;
+ numDirs += GetItem_UInt64Prop(index, kpidNumSubDirs);
+ numFiles += GetItem_UInt64Prop(index, kpidNumSubFiles);
+ }
+ else
+ numFiles++;
+ }
+ {
+ wchar_t temp[32];
+ ConvertUInt32ToString(operatedIndices.Size(), temp);
+ AddPropertyPair(L"", MyFormatNew(g_App.LangString_N_SELECTED_ITEMS, temp), message);
+ }
+
+ if (numDirs != 0)
+ AddPropertyString(kpidNumSubDirs, numDirs, message);
+ if (numFiles != 0)
+ AddPropertyString(kpidNumSubFiles, numFiles, message);
+ AddPropertyString(kpidSize, unpackSize, message);
+ AddPropertyString(kpidPackSize, packSize, message);
+
+ AddSeparator(message);
+ }
+
+
+ /*
+ AddLangString(message, IDS_PROP_FILE_TYPE);
+ message += kPropValueSeparator;
+ message += GetFolderTypeID();
+ message.Add_LF();
+ */
+
+ {
+ NCOM::CPropVariant prop;
+ if (_folder->GetFolderProperty(kpidPath, &prop) == S_OK)
+ {
+ AddPropertyString(kpidName, L"Path", prop, message);
+ }
+ }
+
+ CMyComPtr<IFolderProperties> folderProperties;
+ _folder.QueryInterface(IID_IFolderProperties, &folderProperties);
+ if (folderProperties)
+ {
+ UInt32 numProps;
+ if (folderProperties->GetNumberOfFolderProperties(&numProps) == S_OK)
+ {
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE vt;
+ if (folderProperties->GetFolderPropertyInfo(i, &name, &propID, &vt) != S_OK)
+ continue;
+ NCOM::CPropVariant prop;
+ if (_folder->GetFolderProperty(propID, &prop) != S_OK)
+ continue;
+ AddPropertyString(propID, name, prop, message);
+ }
+ }
+ }
+
+ if (getFolderArcProps)
+ {
+ CMyComPtr<IFolderArcProps> getProps;
+ getFolderArcProps->GetFolderArcProps(&getProps);
+ if (getProps)
+ {
+ UInt32 numLevels;
+ if (getProps->GetArcNumLevels(&numLevels) != S_OK)
+ numLevels = 0;
+ for (UInt32 level2 = 0; level2 < numLevels; level2++)
+ {
+ {
+ UInt32 level = numLevels - 1 - level2;
+ UInt32 numProps;
+ if (getProps->GetArcNumProps(level, &numProps) == S_OK)
+ {
+ const int kNumSpecProps = Z7_ARRAY_SIZE(kSpecProps);
+
+ AddSeparator(message);
+
+ for (Int32 i = -(int)kNumSpecProps; i < (Int32)numProps; i++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE vt;
+ if (i < 0)
+ propID = kSpecProps[i + kNumSpecProps];
+ else if (getProps->GetArcPropInfo(level, (UInt32)i, &name, &propID, &vt) != S_OK)
+ continue;
+ NCOM::CPropVariant prop;
+ if (getProps->GetArcProp(level, propID, &prop) != S_OK)
+ continue;
+ AddPropertyString(propID, name, prop, message);
+ }
+ }
+ }
+
+ if (level2 < numLevels - 1)
+ {
+ const UInt32 level = numLevels - 1 - level2;
+ UInt32 numProps;
+ if (getProps->GetArcNumProps2(level, &numProps) == S_OK)
+ {
+ AddSeparatorSmall(message);
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ CMyComBSTR name;
+ PROPID propID;
+ VARTYPE vt;
+ if (getProps->GetArcPropInfo2(level, i, &name, &propID, &vt) != S_OK)
+ continue;
+ NCOM::CPropVariant prop;
+ if (getProps->GetArcProp2(level, propID, &prop) != S_OK)
+ continue;
+ AddPropertyString(propID, name, prop, message);
+ }
+ }
+ }
+ }
+
+ {
+ // we ERROR message for NonOpen level
+ bool needSep = true;
+ const int kNumSpecProps = Z7_ARRAY_SIZE(kSpecProps);
+ for (Int32 i = -(int)kNumSpecProps; i < 0; i++)
+ {
+ CMyComBSTR name;
+ const PROPID propID = kSpecProps[i + kNumSpecProps];
+ NCOM::CPropVariant prop;
+ if (getProps->GetArcProp(numLevels, propID, &prop) != S_OK)
+ continue;
+ if (needSep)
+ {
+ AddSeparator(message);
+ AddSeparator(message);
+ needSep = false;
+ }
+ AddPropertyString(propID, name, prop, message);
+ }
+ }
+
+ }
+ }
+
+ message.Title = LangString(IDS_PROPERTIES);
+ message.NumColumns = 2;
+ message.Create(GetParent());
+ }
+}
+
+
+
+void CPanel::EditCut()
+{
+ // InvokeSystemCommand("cut");
+}
+
+void CPanel::EditCopy()
+{
+ /*
+ CMyComPtr<IGetFolderArcProps> getFolderArcProps;
+ _folder.QueryInterface(IID_IGetFolderArcProps, &getFolderArcProps);
+ if (!getFolderArcProps)
+ {
+ InvokeSystemCommand("copy");
+ return;
+ }
+ */
+ UString s;
+ CRecordVector<UInt32> indices;
+ Get_ItemIndices_Selected(indices);
+ FOR_VECTOR (i, indices)
+ {
+ if (i != 0)
+ s += "\xD\n";
+ s += GetItemName(indices[i]);
+ }
+ ClipboardSetText(_mainWindow, s);
+}
+
+void CPanel::EditPaste()
+{
+ /*
+ UStringVector names;
+ ClipboardGetFileNames(names);
+ CopyFromNoAsk(names);
+ UString s;
+ for (int i = 0; i < names.Size(); i++)
+ {
+ s += L' ';
+ s += names[i];
+ }
+
+ MessageBoxW(0, s, L"", 0);
+ */
+
+ // InvokeSystemCommand("paste");
+}
+
+
+
+struct CFolderPidls
+{
+ LPITEMIDLIST parent;
+ CRecordVector<LPITEMIDLIST> items;
+
+ CFolderPidls(): parent(NULL) {}
+ ~CFolderPidls()
+ {
+ FOR_VECTOR (i, items)
+ CoTaskMemFree(items[i]);
+ CoTaskMemFree(parent);
+ }
+};
+
+
+static HRESULT ShellFolder_ParseDisplayName(IShellFolder *shellFolder,
+ HWND hwnd, const UString &path, LPITEMIDLIST *ppidl)
+{
+ ULONG eaten = 0;
+ return shellFolder->ParseDisplayName(hwnd, NULL,
+ path.Ptr_non_const(), &eaten, ppidl, NULL);
+}
+
+
+HRESULT CPanel::CreateShellContextMenu(
+ const CRecordVector<UInt32> &operatedIndices,
+ CMyComPtr<IContextMenu> &systemContextMenu)
+{
+ ODS("==== CPanel::CreateShellContextMenu");
+ systemContextMenu.Release();
+ UString folderPath = GetFsPath();
+
+ CMyComPtr<IShellFolder> desktopFolder;
+ RINOK(::SHGetDesktopFolder(&desktopFolder))
+ if (!desktopFolder)
+ {
+ // ShowMessage("Failed to get Desktop folder");
+ return E_FAIL;
+ }
+
+ CFolderPidls pidls;
+ // NULL is allowed for parentHWND in ParseDisplayName()
+ const HWND parentHWND_for_ParseDisplayName = GetParent();
+ // if (folderPath.IsEmpty()), then ParseDisplayName returns pidls of "My Computer"
+ /* win10: ParseDisplayName() supports folder path with tail slash
+ ParseDisplayName() returns {
+ E_INVALIDARG : path with super path prefix "\\\\?\\"
+ ERROR_FILE_NOT_FOUND : path for network share (\\server\path1\long path2") larger than MAX_PATH
+ } */
+ const HRESULT res = ShellFolder_ParseDisplayName(desktopFolder,
+ parentHWND_for_ParseDisplayName,
+ folderPath, &pidls.parent);
+ if (res != S_OK)
+ {
+ ODS_U(folderPath);
+ if (res != E_INVALIDARG)
+ return res;
+ if (!NFile::NName::If_IsSuperPath_RemoveSuperPrefix(folderPath))
+ return res;
+ RINOK(ShellFolder_ParseDisplayName(desktopFolder,
+ parentHWND_for_ParseDisplayName,
+ folderPath, &pidls.parent))
+ }
+ if (!pidls.parent)
+ return E_FAIL;
+
+ /*
+ UString path2;
+ NShell::GetPathFromIDList(pidls.parent, path2);
+ ODS_U(path2);
+ */
+
+ if (operatedIndices.IsEmpty())
+ {
+ // how to get IContextMenu, if there are no selected files?
+ return E_FAIL;
+
+ /*
+ xp64 :
+ 1) we can't use GetUIObjectOf() with (numItems == 0), it throws exception
+ 2) we can't use desktopFolder->GetUIObjectOf() with absolute pidls of folder
+ context menu items are different in that case:
+ "Open / Explorer" for folder
+ "Delete" for "My Computer" icon
+ "Preperties" for "System"
+ */
+ /*
+ parentFolder = desktopFolder;
+ pidls.items.AddInReserved(pidls.parent);
+ pidls.parent = NULL;
+ */
+
+ // CreateViewObject() doesn't show all context menu items
+ /*
+ HRESULT res = parentFolder->CreateViewObject(
+ GetParent(), IID_IContextMenu, (void**)&systemContextMenu);
+ */
+ }
+
+ CMyComPtr<IShellFolder> parentFolder;
+ RINOK(desktopFolder->BindToObject(pidls.parent,
+ NULL, IID_IShellFolder, (void**)&parentFolder))
+ if (!parentFolder)
+ return E_FAIL;
+
+ ODS("==== CPanel::CreateShellContextMenu pidls START");
+
+ pidls.items.ClearAndReserve(operatedIndices.Size());
+ UString fileName;
+ FOR_VECTOR (i, operatedIndices)
+ {
+ fileName.Empty();
+ Add_ItemRelPath2_To_String(operatedIndices[i], fileName);
+ /* ParseDisplayName() in win10 returns:
+ E_INVALIDARG : if empty name, or path with dots only: "." , ".."
+ HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND) : if there is no such file
+ */
+ LPITEMIDLIST pidl = NULL;
+ RINOK(ShellFolder_ParseDisplayName(parentFolder,
+ parentHWND_for_ParseDisplayName,
+ fileName, &pidl))
+ if (!pidl)
+ return E_FAIL;
+ pidls.items.AddInReserved(pidl);
+ }
+
+ ODS("==== CPanel::CreateShellContextMenu pidls END");
+ // Get IContextMenu for items
+ RINOK(parentFolder->GetUIObjectOf(GetParent(),
+ pidls.items.Size(), (LPCITEMIDLIST *)(void *)&pidls.items.Front(),
+ IID_IContextMenu, NULL, (void**)&systemContextMenu))
+ ODS("==== CPanel::CreateShellContextMenu GetUIObjectOf finished");
+ if (!systemContextMenu)
+ {
+ // ShowMessage("Unable to get context menu interface");
+ return E_FAIL;
+ }
+ return S_OK;
+}
+
+
+// #define SHOW_DEBUG_FM_CTX_MENU
+
+#ifdef SHOW_DEBUG_FM_CTX_MENU
+
+static void PrintHex(UString &s, UInt32 v)
+{
+ char sz[32];
+ ConvertUInt32ToHex(v, sz);
+ s += sz;
+}
+
+static void PrintContextStr(UString &s, IContextMenu *ctxm, unsigned i, unsigned id, const char *name)
+{
+ s += " | ";
+ s += name;
+ s += ": ";
+ UString s1;
+ {
+ char buf[256];
+ buf[0] = 0;
+ const HRESULT res = ctxm->GetCommandString(i, id,
+ NULL, buf, Z7_ARRAY_SIZE(buf) - 1);
+ if (res != S_OK)
+ {
+ PrintHex(s1, res);
+ s1.Add_Space();
+ }
+ s1 += GetUnicodeString(buf);
+ }
+ UString s2;
+ {
+ wchar_t buf2[256];
+ buf2[0] = 0;
+ const HRESULT res = ctxm->GetCommandString(i, id | GCS_UNICODE,
+ NULL, (char *)buf2, Z7_ARRAY_SIZE(buf2) - sizeof(wchar_t));
+ if (res != S_OK)
+ {
+ PrintHex(s2, res);
+ s2.Add_Space();
+ }
+ s2 += buf2;
+ }
+ s += s1;
+ if (s2.Compare(s1) != 0)
+ {
+ s += " Unicode: ";
+ s += s2;
+ }
+}
+
+static void PrintAllContextItems(IContextMenu *ctxm, unsigned num)
+{
+ for (unsigned i = 0; i < num; i++)
+ {
+ UString s;
+ s.Add_UInt32(i);
+ s += ": ";
+ PrintContextStr(s, ctxm, i, GCS_VALIDATEA, "valid");
+ PrintContextStr(s, ctxm, i, GCS_VERBA, "verb");
+ PrintContextStr(s, ctxm, i, GCS_HELPTEXTA, "helptext");
+ OutputDebugStringW(s);
+ }
+}
+
+#endif
+
+
+void CPanel::CreateSystemMenu(HMENU menuSpec,
+ bool showExtendedVerbs,
+ const CRecordVector<UInt32> &operatedIndices,
+ CMyComPtr<IContextMenu> &systemContextMenu)
+{
+ systemContextMenu.Release();
+
+ CreateShellContextMenu(operatedIndices, systemContextMenu);
+
+ if (!systemContextMenu)
+ return;
+
+ /*
+ // Set up a CMINVOKECOMMANDINFO structure.
+ CMINVOKECOMMANDINFO ci;
+ ZeroMemory(&ci, sizeof(ci));
+ ci.cbSize = sizeof(CMINVOKECOMMANDINFO);
+ ci.hwnd = GetParent();
+ */
+
+ /*
+ if (Sender == GoBtn)
+ {
+ // Verbs that can be used are cut, paste,
+ // properties, delete, and so on.
+ String action;
+ if (CutRb->Checked)
+ action = "cut";
+ else if (CopyRb->Checked)
+ action = "copy";
+ else if (DeleteRb->Checked)
+ action = "delete";
+ else if (PropertiesRb->Checked)
+ action = "properties";
+
+ ci.lpVerb = action.c_str();
+ result = cm->InvokeCommand(&ci);
+ if (result)
+ ShowMessage(
+ "Error copying file to clipboard.");
+
+ }
+ else
+ */
+ {
+ // HMENU hMenu = CreatePopupMenu();
+ CMenu popupMenu;
+ CMenuDestroyer menuDestroyer(popupMenu);
+ if (!popupMenu.CreatePopup())
+ throw 210503;
+ const HMENU hMenu = popupMenu;
+ DWORD flags = CMF_EXPLORE;
+ if (showExtendedVerbs)
+ flags |= Z7_WIN_CMF_EXTENDEDVERBS;
+ ODS("=== systemContextMenu->QueryContextMenu START");
+ const HRESULT res = systemContextMenu->QueryContextMenu(hMenu, 0, kSystemStartMenuID, 0x7FFF, flags);
+ ODS("=== systemContextMenu->QueryContextMenu END");
+ if (SUCCEEDED(res))
+ {
+ #ifdef SHOW_DEBUG_FM_CTX_MENU
+ PrintAllContextItems(systemContextMenu, (unsigned)res);
+ #endif
+
+ CMenu menu;
+ menu.Attach(menuSpec);
+ CMenuItem menuItem;
+ menuItem.fMask = MIIM_SUBMENU | MIIM_TYPE | MIIM_ID;
+ menuItem.fType = MFT_STRING;
+ menuItem.hSubMenu = popupMenu.Detach();
+ menuDestroyer.Disable();
+ LangString(IDS_SYSTEM, menuItem.StringValue);
+ menu.InsertItem(0, true, menuItem);
+ }
+ /*
+ if (Cmd < 100 && Cmd != 0)
+ {
+ ci.lpVerb = MAKEINTRESOURCE(Cmd - 1);
+ ci.lpParameters = "";
+ ci.lpDirectory = "";
+ ci.nShow = SW_SHOWNORMAL;
+ cm->InvokeCommand(&ci);
+ }
+ // If Cmd is > 100 then it's one of our
+ // inserted menu items.
+ else
+ // Find the menu item.
+ for (int i = 0; i < popupMenu1->Items->Count; i++)
+ {
+ TMenuItem* menu = popupMenu1->Items->Items[i];
+ // Call its OnClick handler.
+ if (menu->Command == Cmd - 100)
+ menu->OnClick(this);
+ }
+ // Release the memory allocated for the menu.
+ DestroyMenu(hMenu);
+ */
+ }
+}
+
+void CPanel::CreateFileMenu(HMENU menuSpec)
+{
+ CreateFileMenu(menuSpec, _sevenZipContextMenu, _systemContextMenu, true); // programMenu
+}
+
+void CPanel::CreateSevenZipMenu(HMENU menuSpec,
+ bool showExtendedVerbs,
+ const CRecordVector<UInt32> &operatedIndices,
+ int firstDirIndex,
+ CMyComPtr<IContextMenu> &sevenZipContextMenu)
+{
+ sevenZipContextMenu.Release();
+
+ CMenu menu;
+ menu.Attach(menuSpec);
+ // CMenuDestroyer menuDestroyer(menu);
+ // menu.CreatePopup();
+
+ CZipContextMenu *contextMenuSpec = new CZipContextMenu;
+ CMyComPtr<IContextMenu> contextMenu = contextMenuSpec;
+ // if (contextMenu.CoCreateInstance(CLSID_CZipContextMenu, IID_IContextMenu) == S_OK)
+ {
+ /*
+ CMyComPtr<IInitContextMenu> initContextMenu;
+ if (contextMenu.QueryInterface(IID_IInitContextMenu, &initContextMenu) != S_OK)
+ return;
+ */
+ ODS("=== FileName List Add START")
+ // for (unsigned y = 0; y < 10000; y++, contextMenuSpec->_fileNames.Clear())
+ GetFilePaths(operatedIndices, contextMenuSpec->_fileNames);
+ ODS("=== FileName List Add END")
+ contextMenuSpec->Init_For_7zFM();
+ contextMenuSpec->_attribs.FirstDirIndex = firstDirIndex;
+ {
+ DWORD flags = CMF_EXPLORE;
+ if (showExtendedVerbs)
+ flags |= Z7_WIN_CMF_EXTENDEDVERBS;
+ const HRESULT res = contextMenu->QueryContextMenu(menu,
+ 0, // indexMenu
+ kSevenZipStartMenuID, // first
+ kSystemStartMenuID - 1, // last
+ flags);
+ ODS("=== contextMenu->QueryContextMenu END")
+ const bool sevenZipMenuCreated = SUCCEEDED(res);
+ if (sevenZipMenuCreated)
+ {
+ // if (res != 0)
+ {
+ // some "non-good" implementation of QueryContextMenu() could add some items to menu, but it return 0.
+ // so we still allow these items
+ sevenZipContextMenu = contextMenu;
+ #ifdef SHOW_DEBUG_FM_CTX_MENU
+ PrintAllContextItems(contextMenu, (unsigned)res);
+ #endif
+ }
+ }
+ else
+ {
+ // MessageBox_Error_HRESULT_Caption(res, L"QueryContextMenu");
+ }
+ // int code = HRESULT_CODE(res);
+ // int nextItemID = code;
+ }
+ }
+}
+
+static bool IsReadOnlyFolder(IFolderFolder *folder)
+{
+ if (!folder)
+ return false;
+
+ bool res = false;
+ {
+ NCOM::CPropVariant prop;
+ if (folder->GetFolderProperty(kpidReadOnly, &prop) == S_OK)
+ if (prop.vt == VT_BOOL)
+ res = VARIANT_BOOLToBool(prop.boolVal);
+ }
+ return res;
+}
+
+bool CPanel::IsThereReadOnlyFolder() const
+{
+ if (!_folderOperations)
+ return true;
+ if (IsReadOnlyFolder(_folder))
+ return true;
+ FOR_VECTOR (i, _parentFolders)
+ {
+ if (IsReadOnlyFolder(_parentFolders[i].ParentFolder))
+ return true;
+ }
+ return false;
+}
+
+bool CPanel::CheckBeforeUpdate(UINT resourceID)
+{
+ if (!_folderOperations)
+ {
+ MessageBox_Error_UnsupportOperation();
+ // resourceID = resourceID;
+ // MessageBoxErrorForUpdate(E_NOINTERFACE, resourceID);
+ return false;
+ }
+
+ for (int i = (int)_parentFolders.Size(); i >= 0; i--)
+ {
+ IFolderFolder *folder;
+ if (i == (int)_parentFolders.Size())
+ folder = _folder;
+ else
+ folder = _parentFolders[i].ParentFolder;
+
+ if (!IsReadOnlyFolder(folder))
+ continue;
+
+ UString s;
+ AddLangString(s, resourceID);
+ s.Add_LF();
+ AddLangString(s, IDS_OPERATION_IS_NOT_SUPPORTED);
+ s.Add_LF();
+ if (i == 0)
+ s += GetFolderPath(folder);
+ else
+ s += _parentFolders[i - 1].VirtualPath;
+ s.Add_LF();
+ AddLangString(s, IDS_PROP_READ_ONLY);
+ MessageBox_Error(s);
+ return false;
+ }
+
+ return true;
+}
+
+void CPanel::CreateFileMenu(HMENU menuSpec,
+ CMyComPtr<IContextMenu> &sevenZipContextMenu,
+ CMyComPtr<IContextMenu> &systemContextMenu,
+ bool programMenu)
+{
+ sevenZipContextMenu.Release();
+ systemContextMenu.Release();
+
+ const bool showExtendedVerbs = IsKeyDown(VK_SHIFT);
+
+ CRecordVector<UInt32> operatedIndices;
+ Get_ItemIndices_Operated(operatedIndices);
+ const int firstDirIndex = FindDir_InOperatedList(operatedIndices);
+
+ CMenu menu;
+ menu.Attach(menuSpec);
+
+ if (!IsArcFolder())
+ {
+ CreateSevenZipMenu(menu, showExtendedVerbs, operatedIndices, firstDirIndex, sevenZipContextMenu);
+ // CreateSystemMenu is very slow if you call it inside ZIP archive with big number of files
+ // Windows probably can parse items inside ZIP archive.
+ if (g_App.ShowSystemMenu)
+ CreateSystemMenu(menu, showExtendedVerbs, operatedIndices, systemContextMenu);
+ }
+
+ /*
+ if (menu.GetItemCount() > 0)
+ menu.AppendItem(MF_SEPARATOR, 0, (LPCTSTR)0);
+ */
+
+ CFileMenu fm;
+
+ fm.readOnly = IsThereReadOnlyFolder();
+ fm.isHashFolder = IsHashFolder();
+ fm.isFsFolder = Is_IO_FS_Folder();
+ fm.programMenu = programMenu;
+ fm.allAreFiles = (firstDirIndex == -1);
+ fm.numItems = operatedIndices.Size();
+
+ fm.isAltStreamsSupported = false;
+
+ if (fm.numItems == 1)
+ fm.FilePath = us2fs(GetItemFullPath(operatedIndices[0]));
+
+ if (_folderAltStreams)
+ {
+ if (operatedIndices.Size() <= 1)
+ {
+ UInt32 realIndex = (UInt32)(Int32)-1;
+ if (operatedIndices.Size() == 1)
+ realIndex = operatedIndices[0];
+ Int32 val = 0;
+ if (_folderAltStreams->AreAltStreamsSupported(realIndex, &val) == S_OK)
+ fm.isAltStreamsSupported = IntToBool(val);
+ }
+ }
+ else
+ {
+ if (fm.numItems == 0)
+ fm.isAltStreamsSupported = IsFSFolder();
+ else
+ fm.isAltStreamsSupported = IsFolder_with_FsItems();
+ }
+
+ fm.Load(menu, (unsigned)menu.GetItemCount());
+}
+
+bool CPanel::InvokePluginCommand(unsigned id)
+{
+ return InvokePluginCommand(id, _sevenZipContextMenu, _systemContextMenu);
+}
+
+#if defined(_MSC_VER) && !defined(UNDER_CE)
+#define use_CMINVOKECOMMANDINFOEX
+/* CMINVOKECOMMANDINFOEX depends from (_WIN32_IE >= 0x0400) */
+#endif
+
+bool CPanel::InvokePluginCommand(unsigned id,
+ IContextMenu *sevenZipContextMenu, IContextMenu *systemContextMenu)
+{
+ UInt32 offset;
+ const bool isSystemMenu = (id >= kSystemStartMenuID);
+ if (isSystemMenu)
+ {
+ if (!systemContextMenu)
+ return false;
+ offset = id - kSystemStartMenuID;
+ }
+ else
+ {
+ if (!sevenZipContextMenu)
+ return false;
+ offset = id - kSevenZipStartMenuID;
+ }
+
+ #ifdef use_CMINVOKECOMMANDINFOEX
+ CMINVOKECOMMANDINFOEX
+ #else
+ CMINVOKECOMMANDINFO
+ #endif
+ commandInfo;
+
+ memset(&commandInfo, 0, sizeof(commandInfo));
+ commandInfo.cbSize = sizeof(commandInfo);
+
+ commandInfo.fMask = 0
+ #ifdef use_CMINVOKECOMMANDINFOEX
+ | CMIC_MASK_UNICODE
+ #endif
+ ;
+
+ commandInfo.hwnd = GetParent();
+ commandInfo.lpVerb = (LPCSTR)(MAKEINTRESOURCE(offset));
+ commandInfo.lpParameters = NULL;
+ // 19.01: fixed CSysString to AString
+ // MSDN suggest to send NULL: lpDirectory: This member is always NULL for menu items inserted by a Shell extension.
+ const AString currentFolderA (GetAnsiString(_currentFolderPrefix));
+ commandInfo.lpDirectory = (LPCSTR)(currentFolderA);
+ commandInfo.nShow = SW_SHOW;
+
+ #ifdef use_CMINVOKECOMMANDINFOEX
+
+ commandInfo.lpParametersW = NULL;
+ commandInfo.lpTitle = "";
+
+ /*
+ system ContextMenu handler supports ContextMenu subhandlers.
+ so InvokeCommand() converts (command_offset) from global number to subhandler number.
+ XP-64 / win10:
+ system ContextMenu converts (command_offset) in lpVerb only,
+ and it keeps lpVerbW unchanged.
+ also explorer.exe sends 0 in lpVerbW.
+ We try to keep compatibility with Windows Explorer here.
+ */
+ commandInfo.lpVerbW = NULL;
+
+ const UString currentFolderUnicode = _currentFolderPrefix;
+ commandInfo.lpDirectoryW = currentFolderUnicode;
+ commandInfo.lpTitleW = L"";
+ // commandInfo.ptInvoke.x = xPos;
+ // commandInfo.ptInvoke.y = yPos;
+ commandInfo.ptInvoke.x = 0;
+ commandInfo.ptInvoke.y = 0;
+
+ #endif
+
+ HRESULT result;
+ if (isSystemMenu)
+ result = systemContextMenu->InvokeCommand(LPCMINVOKECOMMANDINFO(&commandInfo));
+ else
+ result = sevenZipContextMenu->InvokeCommand(LPCMINVOKECOMMANDINFO(&commandInfo));
+ if (result == NOERROR)
+ {
+ KillSelection();
+ return true;
+ }
+ else
+ MessageBox_Error_HRESULT_Caption(result, L"InvokeCommand");
+ return false;
+}
+
+bool CPanel::OnContextMenu(HANDLE windowHandle, int xPos, int yPos)
+{
+ if (::GetParent((HWND)windowHandle) == _listView)
+ {
+ ShowColumnsContextMenu(xPos, yPos);
+ return true;
+ }
+
+ if (windowHandle != _listView)
+ return false;
+ /*
+ POINT point;
+ point.x = xPos;
+ point.y = yPos;
+ if (!_listView.ScreenToClient(&point))
+ return false;
+
+ LVHITTESTINFO info;
+ info.pt = point;
+ int index = _listView.HitTest(&info);
+ */
+
+ CRecordVector<UInt32> operatedIndices;
+ Get_ItemIndices_Operated(operatedIndices);
+
+ // negative x,y are possible for multi-screen modes.
+ // x=-1 && y=-1 for keyboard call (SHIFT+F10 and others).
+ if (xPos == -1 && yPos == -1)
+ {
+ if (operatedIndices.Size() == 0)
+ {
+ xPos = 0;
+ yPos = 0;
+ }
+ else
+ {
+ int itemIndex = _listView.GetNextItem(-1, LVNI_FOCUSED);
+ if (itemIndex == -1)
+ return false;
+ RECT rect;
+ if (!_listView.GetItemRect(itemIndex, &rect, LVIR_ICON))
+ return false;
+ xPos = (rect.left + rect.right) / 2;
+ yPos = (rect.top + rect.bottom) / 2;
+ }
+ POINT point = {xPos, yPos};
+ _listView.ClientToScreen(&point);
+ xPos = point.x;
+ yPos = point.y;
+ }
+
+ CMenu menu;
+ CMenuDestroyer menuDestroyer(menu);
+ menu.CreatePopup();
+
+ CMyComPtr<IContextMenu> sevenZipContextMenu;
+ CMyComPtr<IContextMenu> systemContextMenu;
+ CreateFileMenu(menu, sevenZipContextMenu, systemContextMenu, false); // programMenu
+
+ const unsigned id = (unsigned)menu.Track(TPM_LEFTALIGN
+ #ifndef UNDER_CE
+ | TPM_RIGHTBUTTON
+ #endif
+ | TPM_RETURNCMD | TPM_NONOTIFY,
+ xPos, yPos, _listView);
+
+ if (id == 0)
+ return true;
+
+ if (id >= kMenuCmdID_Plugin_Start)
+ {
+ InvokePluginCommand(id, sevenZipContextMenu, systemContextMenu);
+ return true;
+ }
+ if (ExecuteFileCommand(id))
+ return true;
+ return true;
+}
diff --git a/CPP/7zip/UI/FileManager/PanelOperations.cpp b/CPP/7zip/UI/FileManager/PanelOperations.cpp
new file mode 100644
index 0000000..b61f4e9
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelOperations.cpp
@@ -0,0 +1,528 @@
+// PanelOperations.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/DynamicBuffer.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/COM.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/PropVariant.h"
+
+#include "ComboDialog.h"
+
+#include "FSFolder.h"
+#include "FormatUtils.h"
+#include "LangUtils.h"
+#include "Panel.h"
+#include "UpdateCallback100.h"
+
+#include "resource.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NName;
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+enum EFolderOpType
+{
+ FOLDER_TYPE_CREATE_FOLDER = 0,
+ FOLDER_TYPE_DELETE = 1,
+ FOLDER_TYPE_RENAME = 2
+};
+
+class CThreadFolderOperations: public CProgressThreadVirt
+{
+ HRESULT ProcessVirt() Z7_override;
+public:
+ EFolderOpType OpType;
+ UString Name;
+ UInt32 Index;
+ CRecordVector<UInt32> Indices;
+
+ CMyComPtr<IFolderOperations> FolderOperations;
+ CMyComPtr<IProgress> UpdateCallback;
+ CUpdateCallback100Imp *UpdateCallbackSpec;
+
+ CThreadFolderOperations(EFolderOpType opType): OpType(opType) {}
+ HRESULT DoOperation(CPanel &panel, const UString &progressTitle, const UString &titleError);
+};
+
+HRESULT CThreadFolderOperations::ProcessVirt()
+{
+ NCOM::CComInitializer comInitializer;
+ switch ((int)OpType)
+ {
+ case FOLDER_TYPE_CREATE_FOLDER:
+ return FolderOperations->CreateFolder(Name, UpdateCallback);
+ case FOLDER_TYPE_DELETE:
+ return FolderOperations->Delete(&Indices.Front(), Indices.Size(), UpdateCallback);
+ case FOLDER_TYPE_RENAME:
+ return FolderOperations->Rename(Index, Name, UpdateCallback);
+ default:
+ return E_FAIL;
+ }
+}
+
+
+HRESULT CThreadFolderOperations::DoOperation(CPanel &panel, const UString &progressTitle, const UString &titleError)
+{
+ UpdateCallbackSpec = new CUpdateCallback100Imp;
+ UpdateCallback = UpdateCallbackSpec;
+ UpdateCallbackSpec->ProgressDialog = this;
+
+ WaitMode = true;
+ Sync.FinalMessage.ErrorMessage.Title = titleError;
+
+ UpdateCallbackSpec->Init();
+
+ if (panel._parentFolders.Size() > 0)
+ {
+ const CFolderLink &fl = panel._parentFolders.Back();
+ UpdateCallbackSpec->PasswordIsDefined = fl.UsePassword;
+ UpdateCallbackSpec->Password = fl.Password;
+ }
+
+ MainWindow = panel._mainWindow; // panel.GetParent()
+ MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE);
+ MainAddTitle = progressTitle + L' ';
+
+ RINOK(Create(progressTitle, MainWindow))
+ return Result;
+}
+
+#ifndef _UNICODE
+typedef int (WINAPI * Func_SHFileOperationW)(LPSHFILEOPSTRUCTW lpFileOp);
+#endif
+
+/*
+void CPanel::MessageBoxErrorForUpdate(HRESULT errorCode, UINT resourceID)
+{
+ if (errorCode == E_NOINTERFACE)
+ MessageBox_Error_UnsupportOperation();
+ else
+ MessageBox_Error_HRESULT_Caption(errorCode, LangString(resourceID));
+}
+*/
+
+void CPanel::DeleteItems(bool NON_CE_VAR(toRecycleBin))
+{
+ CDisableTimerProcessing disableTimerProcessing(*this);
+ CRecordVector<UInt32> indices;
+ Get_ItemIndices_Operated(indices);
+ if (indices.IsEmpty())
+ return;
+ CSelectedState state;
+ SaveSelectedState(state);
+
+ #ifndef UNDER_CE
+ // WM6 / SHFileOperationW doesn't ask user! So we use internal delete
+ if (IsFSFolder() && toRecycleBin)
+ {
+ bool useInternalDelete = false;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ CDynamicBuffer<CHAR> buffer;
+ FOR_VECTOR (i, indices)
+ {
+ const AString path (GetSystemString(GetItemFullPath(indices[i])));
+ buffer.AddData(path, path.Len() + 1);
+ }
+ *buffer.GetCurPtrAndGrow(1) = 0;
+ SHFILEOPSTRUCTA fo;
+ fo.hwnd = GetParent();
+ fo.wFunc = FO_DELETE;
+ fo.pFrom = (const CHAR *)buffer;
+ fo.pTo = NULL;
+ fo.fFlags = 0;
+ if (toRecycleBin)
+ fo.fFlags |= FOF_ALLOWUNDO;
+ // fo.fFlags |= FOF_NOCONFIRMATION;
+ // fo.fFlags |= FOF_NOERRORUI;
+ // fo.fFlags |= FOF_SILENT;
+ // fo.fFlags |= FOF_WANTNUKEWARNING;
+ fo.fAnyOperationsAborted = FALSE;
+ fo.hNameMappings = NULL;
+ fo.lpszProgressTitle = NULL;
+ /* int res = */ ::SHFileOperationA(&fo);
+ }
+ else
+ #endif
+ {
+ CDynamicBuffer<WCHAR> buffer;
+ unsigned maxLen = 0;
+ const UString prefix = GetFsPath();
+ FOR_VECTOR (i, indices)
+ {
+ // L"\\\\?\\") doesn't work here.
+ const UString path = prefix + GetItemRelPath2(indices[i]);
+ if (path.Len() > maxLen)
+ maxLen = path.Len();
+ buffer.AddData(path, path.Len() + 1);
+ }
+ *buffer.GetCurPtrAndGrow(1) = 0;
+ if (maxLen >= MAX_PATH)
+ {
+ if (toRecycleBin)
+ {
+ MessageBox_Error_LangID(IDS_ERROR_LONG_PATH_TO_RECYCLE);
+ return;
+ }
+ useInternalDelete = true;
+ }
+ else
+ {
+ SHFILEOPSTRUCTW fo;
+ fo.hwnd = GetParent();
+ fo.wFunc = FO_DELETE;
+ fo.pFrom = (const WCHAR *)buffer;
+ fo.pTo = NULL;
+ fo.fFlags = 0;
+ if (toRecycleBin)
+ fo.fFlags |= FOF_ALLOWUNDO;
+ fo.fAnyOperationsAborted = FALSE;
+ fo.hNameMappings = NULL;
+ fo.lpszProgressTitle = NULL;
+ // int res;
+ #ifdef _UNICODE
+ /* res = */ ::SHFileOperationW(&fo);
+ #else
+ Func_SHFileOperationW
+ f_SHFileOperationW = Z7_GET_PROC_ADDRESS(
+ Func_SHFileOperationW, ::GetModuleHandleW(L"shell32.dll"),
+ "SHFileOperationW");
+ if (!f_SHFileOperationW)
+ return;
+ /* res = */ f_SHFileOperationW(&fo);
+ #endif
+ }
+ }
+ /*
+ if (fo.fAnyOperationsAborted)
+ MessageBox_Error_HRESULT_Caption(result, LangString(IDS_ERROR_DELETING));
+ */
+ if (!useInternalDelete)
+ {
+ RefreshListCtrl(state);
+ return;
+ }
+ }
+ #endif
+
+ // DeleteItemsInternal
+
+ if (!CheckBeforeUpdate(IDS_ERROR_DELETING))
+ return;
+
+ UInt32 titleID, messageID;
+ UString messageParam;
+ if (indices.Size() == 1)
+ {
+ const unsigned index = indices[0];
+ messageParam = GetItemRelPath2(index);
+ if (IsItem_Folder(index))
+ {
+ titleID = IDS_CONFIRM_FOLDER_DELETE;
+ messageID = IDS_WANT_TO_DELETE_FOLDER;
+ }
+ else
+ {
+ titleID = IDS_CONFIRM_FILE_DELETE;
+ messageID = IDS_WANT_TO_DELETE_FILE;
+ }
+ }
+ else
+ {
+ titleID = IDS_CONFIRM_ITEMS_DELETE;
+ messageID = IDS_WANT_TO_DELETE_ITEMS;
+ messageParam = NumberToString(indices.Size());
+ }
+ if (::MessageBoxW(GetParent(), MyFormatNew(messageID, messageParam), LangString(titleID), MB_OKCANCEL | MB_ICONQUESTION) != IDOK)
+ return;
+
+ CDisableNotify disableNotify(*this);
+ {
+ CThreadFolderOperations op(FOLDER_TYPE_DELETE);
+ op.FolderOperations = _folderOperations;
+ op.Indices = indices;
+ op.DoOperation(*this,
+ LangString(IDS_DELETING),
+ LangString(IDS_ERROR_DELETING));
+ }
+ RefreshTitleAlways();
+ RefreshListCtrl(state);
+}
+
+BOOL CPanel::OnBeginLabelEdit(LV_DISPINFOW * lpnmh)
+{
+ const unsigned realIndex = GetRealIndex(lpnmh->item);
+ if (realIndex == kParentIndex)
+ return TRUE;
+ if (IsThereReadOnlyFolder())
+ return TRUE;
+ return FALSE;
+}
+
+static bool IsCorrectFsName(const UString &name)
+{
+ const UString lastPart = name.Ptr((unsigned)(name.ReverseFind_PathSepar() + 1));
+ return
+ lastPart != L"." &&
+ lastPart != L"..";
+}
+
+bool CorrectFsPath(const UString &relBase, const UString &path, UString &result);
+
+bool CPanel::CorrectFsPath(const UString &path2, UString &result)
+{
+ return ::CorrectFsPath(GetFsPath(), path2, result);
+}
+
+BOOL CPanel::OnEndLabelEdit(LV_DISPINFOW * lpnmh)
+{
+ if (lpnmh->item.pszText == NULL)
+ return FALSE;
+ CDisableTimerProcessing disableTimerProcessing2(*this);
+
+ if (!CheckBeforeUpdate(IDS_ERROR_RENAMING))
+ return FALSE;
+
+ UString newName = lpnmh->item.pszText;
+ if (!IsCorrectFsName(newName))
+ {
+ MessageBox_Error_HRESULT(E_INVALIDARG);
+ return FALSE;
+ }
+
+ if (IsFSFolder())
+ {
+ UString correctName;
+ if (!CorrectFsPath(newName, correctName))
+ {
+ MessageBox_Error_HRESULT(E_INVALIDARG);
+ return FALSE;
+ }
+ newName = correctName;
+ }
+
+ SaveSelectedState(_selectedState);
+
+ const unsigned realIndex = GetRealIndex(lpnmh->item);
+ if (realIndex == kParentIndex)
+ return FALSE;
+ const UString prefix = GetItemPrefix(realIndex);
+
+
+ CDisableNotify disableNotify(*this);
+ {
+ CThreadFolderOperations op(FOLDER_TYPE_RENAME);
+ op.FolderOperations = _folderOperations;
+ op.Index = realIndex;
+ op.Name = newName;
+ /* HRESULTres = */ op.DoOperation(*this,
+ LangString(IDS_RENAMING),
+ LangString(IDS_ERROR_RENAMING));
+ // fixed in 9.26: we refresh list even after errors
+ // (it's more safe, since error can be at different stages, so list can be incorrect).
+ /*
+ if (res != S_OK)
+ return FALSE;
+ */
+ }
+
+ // Can't use RefreshListCtrl here.
+ // RefreshListCtrlSaveFocused();
+ _selectedState.FocusedName = prefix + newName;
+ _selectedState.FocusedName_Defined = true;
+ _selectedState.SelectFocused = true;
+
+ // We need clear all items to disable GetText before Reload:
+ // number of items can change.
+ // DeleteListItems();
+ // But seems it can still call GetText (maybe for current item)
+ // so we can't delete items.
+
+ _dontShowMode = true;
+
+ PostMsg(kReLoadMessage);
+ return TRUE;
+}
+
+bool Dlg_CreateFolder(HWND wnd, UString &destName);
+
+void CPanel::CreateFolder()
+{
+ if (IsHashFolder())
+ return;
+
+ if (!CheckBeforeUpdate(IDS_CREATE_FOLDER_ERROR))
+ return;
+
+ CDisableTimerProcessing disableTimerProcessing2(*this);
+ CSelectedState state;
+ SaveSelectedState(state);
+
+ UString newName;
+ if (!Dlg_CreateFolder(GetParent(), newName))
+ return;
+
+ if (!IsCorrectFsName(newName))
+ {
+ MessageBox_Error_HRESULT(E_INVALIDARG);
+ return;
+ }
+
+ if (IsFSFolder())
+ {
+ UString correctName;
+ if (!CorrectFsPath(newName, correctName))
+ {
+ MessageBox_Error_HRESULT(E_INVALIDARG);
+ return;
+ }
+ newName = correctName;
+ }
+
+ HRESULT res;
+ CDisableNotify disableNotify(*this);
+ {
+ CThreadFolderOperations op(FOLDER_TYPE_CREATE_FOLDER);
+ op.FolderOperations = _folderOperations;
+ op.Name = newName;
+ res = op.DoOperation(*this,
+ LangString(IDS_CREATE_FOLDER),
+ LangString(IDS_CREATE_FOLDER_ERROR));
+ /*
+ // fixed for 9.26: we must refresh always
+ if (res != S_OK)
+ return;
+ */
+ }
+ if (res == S_OK)
+ {
+ int pos = newName.Find(WCHAR_PATH_SEPARATOR);
+ if (pos >= 0)
+ newName.DeleteFrom((unsigned)(pos));
+ if (!_mySelectMode)
+ state.SelectedNames.Clear();
+ state.FocusedName = newName;
+ state.FocusedName_Defined = true;
+ state.SelectFocused = true;
+ }
+ RefreshTitleAlways();
+ RefreshListCtrl(state);
+}
+
+void CPanel::CreateFile()
+{
+ if (IsHashFolder())
+ return;
+
+ if (!CheckBeforeUpdate(IDS_CREATE_FILE_ERROR))
+ return;
+
+ CDisableTimerProcessing disableTimerProcessing2(*this);
+ CSelectedState state;
+ SaveSelectedState(state);
+ CComboDialog dlg;
+ LangString(IDS_CREATE_FILE, dlg.Title);
+ LangString(IDS_CREATE_FILE_NAME, dlg.Static);
+ LangString(IDS_CREATE_FILE_DEFAULT_NAME, dlg.Value);
+
+ if (dlg.Create(GetParent()) != IDOK)
+ return;
+
+ CDisableNotify disableNotify(*this);
+
+ UString newName = dlg.Value;
+
+ if (IsFSFolder())
+ {
+ UString correctName;
+ if (!CorrectFsPath(newName, correctName))
+ {
+ MessageBox_Error_HRESULT(E_INVALIDARG);
+ return;
+ }
+ newName = correctName;
+ }
+
+ const HRESULT result = _folderOperations->CreateFile(newName, NULL);
+ if (result != S_OK)
+ {
+ MessageBox_Error_HRESULT_Caption(result, LangString(IDS_CREATE_FILE_ERROR));
+ // MessageBoxErrorForUpdate(result, IDS_CREATE_FILE_ERROR);
+ return;
+ }
+ const int pos = newName.Find(WCHAR_PATH_SEPARATOR);
+ if (pos >= 0)
+ newName.DeleteFrom((unsigned)pos);
+ if (!_mySelectMode)
+ state.SelectedNames.Clear();
+ state.FocusedName = newName;
+ state.FocusedName_Defined = true;
+ state.SelectFocused = true;
+ RefreshListCtrl(state);
+}
+
+void CPanel::RenameFile()
+{
+ if (!CheckBeforeUpdate(IDS_ERROR_RENAMING))
+ return;
+ int index = _listView.GetFocusedItem();
+ if (index >= 0)
+ _listView.EditLabel(index);
+}
+
+void CPanel::ChangeComment()
+{
+ if (IsHashFolder())
+ return;
+ if (!CheckBeforeUpdate(IDS_COMMENT))
+ return;
+ CDisableTimerProcessing disableTimerProcessing2(*this);
+ const int index = _listView.GetFocusedItem();
+ if (index < 0)
+ return;
+ const unsigned realIndex = GetRealItemIndex(index);
+ if (realIndex == kParentIndex)
+ return;
+ CSelectedState state;
+ SaveSelectedState(state);
+ UString comment;
+ {
+ NCOM::CPropVariant propVariant;
+ if (_folder->GetProperty(realIndex, kpidComment, &propVariant) != S_OK)
+ return;
+ if (propVariant.vt == VT_BSTR)
+ comment = propVariant.bstrVal;
+ else if (propVariant.vt != VT_EMPTY)
+ return;
+ }
+ const UString name = GetItemRelPath2(realIndex);
+ CComboDialog dlg;
+ dlg.Title = name;
+ dlg.Title += " : ";
+ AddLangString(dlg.Title, IDS_COMMENT);
+ dlg.Value = comment;
+ LangString(IDS_COMMENT2, dlg.Static);
+ if (dlg.Create(GetParent()) != IDOK)
+ return;
+ NCOM::CPropVariant propVariant (dlg.Value);
+
+ CDisableNotify disableNotify(*this);
+ const HRESULT result = _folderOperations->SetProperty(realIndex, kpidComment, &propVariant, NULL);
+ if (result != S_OK)
+ {
+ if (result == E_NOINTERFACE)
+ MessageBox_Error_UnsupportOperation();
+ else
+ MessageBox_Error_HRESULT_Caption(result, L"Set Comment Error");
+ }
+ RefreshListCtrl(state);
+}
diff --git a/CPP/7zip/UI/FileManager/PanelSelect.cpp b/CPP/7zip/UI/FileManager/PanelSelect.cpp
new file mode 100644
index 0000000..f7a16dd
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelSelect.cpp
@@ -0,0 +1,317 @@
+// PanelSelect.cpp
+
+#include "StdAfx.h"
+
+#include "resource.h"
+
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/Wildcard.h"
+
+#include "ComboDialog.h"
+#include "LangUtils.h"
+#include "Panel.h"
+
+void CPanel::OnShiftSelectMessage()
+{
+ if (!_mySelectMode)
+ return;
+ const int focusedItem = _listView.GetFocusedItem();
+ if (focusedItem < 0)
+ return;
+ if (!_selectionIsDefined)
+ return;
+ int startItem = MyMin(focusedItem, _prevFocusedItem);
+ int finishItem = MyMax(focusedItem, _prevFocusedItem);
+
+ int numItems = _listView.GetItemCount();
+ for (int i = 0; i < numItems; i++)
+ {
+ const unsigned realIndex = GetRealItemIndex(i);
+ if (realIndex == kParentIndex)
+ continue;
+ if (i >= startItem && i <= finishItem)
+ if (_selectedStatusVector[realIndex] != _selectMark)
+ {
+ _selectedStatusVector[realIndex] = _selectMark;
+ _listView.RedrawItem(i);
+ }
+ }
+
+ _prevFocusedItem = focusedItem;
+}
+
+void CPanel::OnArrowWithShift()
+{
+ if (!_mySelectMode)
+ return;
+ const int focusedItem = _listView.GetFocusedItem();
+ if (focusedItem < 0)
+ return;
+ const unsigned realIndex = GetRealItemIndex(focusedItem);
+
+ if (_selectionIsDefined)
+ {
+ if (realIndex != kParentIndex)
+ _selectedStatusVector[realIndex] = _selectMark;
+ }
+ else
+ {
+ if (realIndex == kParentIndex)
+ {
+ _selectionIsDefined = true;
+ _selectMark = true;
+ }
+ else
+ {
+ _selectionIsDefined = true;
+ _selectMark = !_selectedStatusVector[realIndex];
+ _selectedStatusVector[realIndex] = _selectMark;
+ }
+ }
+
+ _prevFocusedItem = focusedItem;
+ PostMsg(kShiftSelectMessage);
+ _listView.RedrawItem(focusedItem);
+}
+
+void CPanel::OnInsert()
+{
+ /*
+ const int kState = CDIS_MARKED; // LVIS_DROPHILITED;
+ UINT state = (_listView.GetItemState(focusedItem, LVIS_CUT) == 0) ?
+ LVIS_CUT : 0;
+ _listView.SetItemState(focusedItem, state, LVIS_CUT);
+ // _listView.SetItemState_Selected(focusedItem);
+ */
+
+ const int focusedItem = _listView.GetFocusedItem();
+ if (focusedItem < 0)
+ return;
+
+ const unsigned realIndex = GetRealItemIndex(focusedItem);
+ if (realIndex != kParentIndex)
+ {
+ bool isSelected = !_selectedStatusVector[realIndex];
+ _selectedStatusVector[realIndex] = isSelected;
+ if (!_mySelectMode)
+ _listView.SetItemState_Selected(focusedItem, isSelected);
+ _listView.RedrawItem(focusedItem);
+ }
+
+ int nextIndex = focusedItem + 1;
+ if (nextIndex < _listView.GetItemCount())
+ {
+ _listView.SetItemState_FocusedSelected(nextIndex);
+ _listView.EnsureVisible(nextIndex, false);
+ }
+}
+
+/*
+void CPanel::OnUpWithShift()
+{
+ const int focusedItem = _listView.GetFocusedItem();
+ if (focusedItem < 0)
+ return;
+ const int index = GetRealItemIndex(focusedItem);
+ if (index == kParentIndex)
+ return;
+ _selectedStatusVector[index] = !_selectedStatusVector[index];
+ _listView.RedrawItem(index);
+}
+
+void CPanel::OnDownWithShift()
+{
+ const int focusedItem = _listView.GetFocusedItem();
+ if (focusedItem < 0)
+ return;
+ const int index = GetRealItemIndex(focusedItem);
+ if (index == kParentIndex)
+ return;
+ _selectedStatusVector[index] = !_selectedStatusVector[index];
+ _listView.RedrawItem(index);
+}
+*/
+
+void CPanel::UpdateSelection()
+{
+ if (!_mySelectMode)
+ {
+ bool enableTemp = _enableItemChangeNotify;
+ _enableItemChangeNotify = false;
+ int numItems = _listView.GetItemCount();
+ for (int i = 0; i < numItems; i++)
+ {
+ const unsigned realIndex = GetRealItemIndex(i);
+ if (realIndex != kParentIndex)
+ _listView.SetItemState_Selected(i, _selectedStatusVector[realIndex]);
+ }
+ _enableItemChangeNotify = enableTemp;
+ }
+ _listView.RedrawAllItems();
+}
+
+
+void CPanel::SelectSpec(bool selectMode)
+{
+ CComboDialog dlg;
+ LangString(selectMode ? IDS_SELECT : IDS_DESELECT, dlg.Title );
+ LangString(IDS_SELECT_MASK, dlg.Static);
+ dlg.Value = '*';
+ if (dlg.Create(GetParent()) != IDOK)
+ return;
+ const UString &mask = dlg.Value;
+ FOR_VECTOR (i, _selectedStatusVector)
+ if (DoesWildcardMatchName(mask, GetItemName(i)))
+ _selectedStatusVector[i] = selectMode;
+ UpdateSelection();
+}
+
+void CPanel::SelectByType(bool selectMode)
+{
+ const int focusedItem = _listView.GetFocusedItem();
+ if (focusedItem < 0)
+ return;
+ const unsigned realIndex = GetRealItemIndex(focusedItem);
+ UString name = GetItemName(realIndex);
+ bool isItemFolder = IsItem_Folder(realIndex);
+
+ if (isItemFolder)
+ {
+ FOR_VECTOR (i, _selectedStatusVector)
+ if (IsItem_Folder(i) == isItemFolder)
+ _selectedStatusVector[i] = selectMode;
+ }
+ else
+ {
+ int pos = name.ReverseFind_Dot();
+ if (pos < 0)
+ {
+ FOR_VECTOR (i, _selectedStatusVector)
+ if (IsItem_Folder(i) == isItemFolder && GetItemName(i).ReverseFind_Dot() < 0)
+ _selectedStatusVector[i] = selectMode;
+ }
+ else
+ {
+ UString mask ('*');
+ mask += name.Ptr((unsigned)pos);
+ FOR_VECTOR (i, _selectedStatusVector)
+ if (IsItem_Folder(i) == isItemFolder && DoesWildcardMatchName(mask, GetItemName(i)))
+ _selectedStatusVector[i] = selectMode;
+ }
+ }
+
+ UpdateSelection();
+}
+
+void CPanel::SelectAll(bool selectMode)
+{
+ FOR_VECTOR (i, _selectedStatusVector)
+ _selectedStatusVector[i] = selectMode;
+ UpdateSelection();
+}
+
+void CPanel::InvertSelection()
+{
+ if (!_mySelectMode)
+ {
+ /*
+ unsigned numSelected = 0;
+ FOR_VECTOR (i, _selectedStatusVector)
+ if (_selectedStatusVector[i])
+ numSelected++;
+ */
+ // 17.02: fixed : now we invert item even, if single item is selected
+ /*
+ if (numSelected == 1)
+ {
+ int focused = _listView.GetFocusedItem();
+ if (focused >= 0)
+ {
+ const unsigned realIndex = GetRealItemIndex(focused);
+ if (realIndex >= 0)
+ if (_selectedStatusVector[realIndex])
+ _selectedStatusVector[realIndex] = false;
+ }
+ }
+ */
+ }
+ FOR_VECTOR (i, _selectedStatusVector)
+ _selectedStatusVector[i] = !_selectedStatusVector[i];
+ UpdateSelection();
+}
+
+void CPanel::KillSelection()
+{
+ SelectAll(false);
+ // ver 20.01: now we don't like that focused will be selected item.
+ // So the following code was disabled:
+ /*
+ if (!_mySelectMode)
+ {
+ int focused = _listView.GetFocusedItem();
+ if (focused >= 0)
+ {
+ // CPanel::OnItemChanged notify for LVIS_SELECTED change doesn't work here. Why?
+ // so we change _selectedStatusVector[realIndex] here.
+ const unsigned realIndex = GetRealItemIndex(focused);
+ if (realIndex != kParentIndex)
+ _selectedStatusVector[realIndex] = true;
+ _listView.SetItemState_Selected(focused);
+ }
+ }
+ */
+}
+
+void CPanel::OnLeftClick(MY_NMLISTVIEW_NMITEMACTIVATE *itemActivate)
+{
+ if (itemActivate->hdr.hwndFrom != HWND(_listView))
+ return;
+ // It will work only for Version 4.71 (IE 4);
+ int indexInList = itemActivate->iItem;
+ if (indexInList < 0)
+ return;
+
+ #ifndef UNDER_CE
+ if ((itemActivate->uKeyFlags & LVKF_SHIFT) != 0)
+ {
+ // int focusedIndex = _listView.GetFocusedItem();
+ const int focusedIndex = _startGroupSelect;
+ if (focusedIndex < 0)
+ return;
+ const int startItem = MyMin(focusedIndex, indexInList);
+ const int finishItem = MyMax(focusedIndex, indexInList);
+
+ const int numItems = _listView.GetItemCount();
+ for (int i = 0; i < numItems; i++)
+ {
+ const unsigned realIndex = GetRealItemIndex(i);
+ if (realIndex == kParentIndex)
+ continue;
+ const bool selected = (i >= startItem && i <= finishItem);
+ if (_selectedStatusVector[realIndex] != selected)
+ {
+ _selectedStatusVector[realIndex] = selected;
+ _listView.RedrawItem(i);
+ }
+ }
+ }
+ else
+ #endif
+ {
+ _startGroupSelect = indexInList;
+
+ #ifndef UNDER_CE
+ if ((itemActivate->uKeyFlags & LVKF_CONTROL) != 0)
+ {
+ const unsigned realIndex = GetRealItemIndex(indexInList);
+ if (realIndex != kParentIndex)
+ {
+ _selectedStatusVector[realIndex] = !_selectedStatusVector[realIndex];
+ _listView.RedrawItem(indexInList);
+ }
+ }
+ #endif
+ }
+
+ return;
+}
diff --git a/CPP/7zip/UI/FileManager/PanelSort.cpp b/CPP/7zip/UI/FileManager/PanelSort.cpp
new file mode 100644
index 0000000..f95f8ee
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelSort.cpp
@@ -0,0 +1,269 @@
+// PanelSort.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+#include "../../../Windows/PropVariant.h"
+
+#include "../../PropID.h"
+
+#include "Panel.h"
+
+using namespace NWindows;
+
+int CompareFileNames_ForFolderList(const wchar_t *s1, const wchar_t *s2)
+{
+ for (;;)
+ {
+ wchar_t c1 = *s1;
+ wchar_t c2 = *s2;
+ if ((c1 >= '0' && c1 <= '9') &&
+ (c2 >= '0' && c2 <= '9'))
+ {
+ for (; *s1 == '0'; s1++);
+ for (; *s2 == '0'; s2++);
+ size_t len1 = 0;
+ size_t len2 = 0;
+ for (; (s1[len1] >= '0' && s1[len1] <= '9'); len1++);
+ for (; (s2[len2] >= '0' && s2[len2] <= '9'); len2++);
+ if (len1 < len2) return -1;
+ if (len1 > len2) return 1;
+ for (; len1 > 0; s1++, s2++, len1--)
+ {
+ if (*s1 == *s2) continue;
+ return (*s1 < *s2) ? -1 : 1;
+ }
+ c1 = *s1;
+ c2 = *s2;
+ }
+ s1++;
+ s2++;
+ if (c1 != c2)
+ {
+ // Probably we need to change the order for special characters like in Explorer.
+ wchar_t u1 = MyCharUpper(c1);
+ wchar_t u2 = MyCharUpper(c2);
+ if (u1 < u2) return -1;
+ if (u1 > u2) return 1;
+ }
+ if (c1 == 0) return 0;
+ }
+}
+
+static int CompareFileNames_Le16(const Byte *s1, unsigned size1, const Byte *s2, unsigned size2)
+{
+ size1 &= ~1u;
+ size2 &= ~1u;
+ for (unsigned i = 0;; i += 2)
+ {
+ if (i >= size1)
+ return (i >= size2) ? 0 : -1;
+ if (i >= size2)
+ return 1;
+ UInt16 c1 = GetUi16(s1 + i);
+ UInt16 c2 = GetUi16(s2 + i);
+ if (c1 == c2)
+ {
+ if (c1 == 0)
+ return 0;
+ continue;
+ }
+ if (c1 < c2)
+ return -1;
+ return 1;
+ }
+}
+
+static inline const wchar_t *GetExtensionPtr(const UString &name)
+{
+ const int dotPos = name.ReverseFind_Dot();
+ return name.Ptr(dotPos < 0 ? name.Len() : (unsigned)dotPos);
+}
+
+void CPanel::SetSortRawStatus()
+{
+ _isRawSortProp = false;
+ FOR_VECTOR (i, _columns)
+ {
+ const CPropColumn &prop = _columns[i];
+ if (prop.ID == _sortID)
+ {
+ _isRawSortProp = prop.IsRawProp ? 1 : 0;
+ return;
+ }
+ }
+}
+
+
+static int CALLBACK CompareItems2(LPARAM lParam1, LPARAM lParam2, LPARAM lpData)
+{
+ if (lpData == 0)
+ return 0;
+ CPanel *panel = (CPanel*)lpData;
+
+
+ PROPID propID = panel->_sortID;
+
+ if (propID == kpidNoProperty)
+ return MyCompare(lParam1, lParam2);
+
+ if (panel->_isRawSortProp)
+ {
+ // Sha1, NtSecurity, NtReparse
+ const void *data1;
+ const void *data2;
+ UInt32 dataSize1;
+ UInt32 dataSize2;
+ UInt32 propType1;
+ UInt32 propType2;
+ if (panel->_folderRawProps->GetRawProp((UInt32)lParam1, propID, &data1, &dataSize1, &propType1) != 0) return 0;
+ if (panel->_folderRawProps->GetRawProp((UInt32)lParam2, propID, &data2, &dataSize2, &propType2) != 0) return 0;
+ if (dataSize1 == 0)
+ return (dataSize2 == 0) ? 0 : -1;
+ if (dataSize2 == 0)
+ return 1;
+ if (propType1 != NPropDataType::kRaw) return 0;
+ if (propType2 != NPropDataType::kRaw) return 0;
+ if (propID == kpidNtReparse)
+ {
+ NFile::CReparseShortInfo r1; r1.Parse((const Byte *)data1, dataSize1);
+ NFile::CReparseShortInfo r2; r2.Parse((const Byte *)data2, dataSize2);
+ return CompareFileNames_Le16(
+ (const Byte *)data1 + r1.Offset, r1.Size,
+ (const Byte *)data2 + r2.Offset, r2.Size);
+ }
+ }
+
+ if (panel->_folderCompare)
+ return panel->_folderCompare->CompareItems((UInt32)lParam1, (UInt32)lParam2, propID, panel->_isRawSortProp);
+
+ switch (propID)
+ {
+ // if (panel->_sortIndex == 0)
+ case kpidName:
+ {
+ const UString name1 = panel->GetItemName((unsigned)lParam1);
+ const UString name2 = panel->GetItemName((unsigned)lParam2);
+ const int res = CompareFileNames_ForFolderList(name1, name2);
+ /*
+ if (res != 0 || !panel->_flatMode)
+ return res;
+ const UString prefix1 = panel->GetItemPrefix(lParam1);
+ const UString prefix2 = panel->GetItemPrefix(lParam2);
+ return res = CompareFileNames_ForFolderList(prefix1, prefix2);
+ */
+ return res;
+ }
+ case kpidExtension:
+ {
+ const UString name1 = panel->GetItemName((unsigned)lParam1);
+ const UString name2 = panel->GetItemName((unsigned)lParam2);
+ return CompareFileNames_ForFolderList(
+ GetExtensionPtr(name1),
+ GetExtensionPtr(name2));
+ }
+ }
+ /*
+ if (panel->_sortIndex == 1)
+ return MyCompare(file1.Size, file2.Size);
+ return ::CompareFileTime(&file1.MTime, &file2.MTime);
+ */
+
+ // PROPID propID = panel->_columns[panel->_sortIndex].ID;
+
+ NCOM::CPropVariant prop1, prop2;
+ // Name must be first property
+ panel->_folder->GetProperty((UInt32)lParam1, propID, &prop1);
+ panel->_folder->GetProperty((UInt32)lParam2, propID, &prop2);
+ if (prop1.vt != prop2.vt)
+ return MyCompare(prop1.vt, prop2.vt);
+ if (prop1.vt == VT_BSTR)
+ return MyStringCompareNoCase(prop1.bstrVal, prop2.bstrVal);
+ return prop1.Compare(prop2);
+}
+
+int CALLBACK CompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData);
+int CALLBACK CompareItems(LPARAM lParam1, LPARAM lParam2, LPARAM lpData)
+{
+ if (lpData == 0) return 0;
+ if (lParam1 == (int)kParentIndex) return -1;
+ if (lParam2 == (int)kParentIndex) return 1;
+
+ CPanel *panel = (CPanel*)lpData;
+
+ const bool isDir1 = panel->IsItem_Folder((unsigned)lParam1);
+ const bool isDir2 = panel->IsItem_Folder((unsigned)lParam2);
+
+ if (isDir1 && !isDir2) return -1;
+ if (isDir2 && !isDir1) return 1;
+
+ const int result = CompareItems2(lParam1, lParam2, lpData);
+ return panel->_ascending ? result: (-result);
+}
+
+
+/*
+void CPanel::SortItems(int index)
+{
+ if (index == _sortIndex)
+ _ascending = !_ascending;
+ else
+ {
+ _sortIndex = index;
+ _ascending = true;
+ switch (_columns[_sortIndex].ID)
+ {
+ case kpidSize:
+ case kpidPackedSize:
+ case kpidCTime:
+ case kpidATime:
+ case kpidMTime:
+ _ascending = false;
+ break;
+ }
+ }
+ _listView.SortItems(CompareItems, (LPARAM)this);
+ _listView.EnsureVisible(_listView.GetFocusedItem(), false);
+}
+
+void CPanel::SortItemsWithPropID(PROPID propID)
+{
+ int index = _columns.FindItem_for_PropID(propID);
+ if (index >= 0)
+ SortItems(index);
+}
+*/
+
+void CPanel::SortItemsWithPropID(PROPID propID)
+{
+ if (propID == _sortID)
+ _ascending = !_ascending;
+ else
+ {
+ _sortID = propID;
+ _ascending = true;
+ switch (propID)
+ {
+ case kpidSize:
+ case kpidPackSize:
+ case kpidCTime:
+ case kpidATime:
+ case kpidMTime:
+ _ascending = false;
+ break;
+ }
+ }
+ SetSortRawStatus();
+ _listView.SortItems(CompareItems, (LPARAM)this);
+ _listView.EnsureVisible(_listView.GetFocusedItem(), false);
+}
+
+
+void CPanel::OnColumnClick(LPNMLISTVIEW info)
+{
+ /*
+ int index = _columns.FindItem_for_PropID(_visibleColumns[info->iSubItem].ID);
+ SortItems(index);
+ */
+ SortItemsWithPropID(_visibleColumns[info->iSubItem].ID);
+}
diff --git a/CPP/7zip/UI/FileManager/PanelSplitFile.cpp b/CPP/7zip/UI/FileManager/PanelSplitFile.cpp
new file mode 100644
index 0000000..64aa039
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PanelSplitFile.cpp
@@ -0,0 +1,562 @@
+// PanelSplitFile.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/FileName.h"
+
+#include "../GUI/ExtractRes.h"
+
+#include "resource.h"
+
+#include "App.h"
+#include "CopyDialog.h"
+#include "FormatUtils.h"
+#include "LangUtils.h"
+#include "SplitDialog.h"
+#include "SplitUtils.h"
+
+#include "PropertyNameRes.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+static const char * const g_Message_FileWriteError = "File write error";
+
+struct CVolSeqName
+{
+ UString UnchangedPart;
+ UString ChangedPart;
+ CVolSeqName(): ChangedPart("000") {}
+
+ void SetNumDigits(UInt64 numVolumes)
+ {
+ ChangedPart = "000";
+ while (numVolumes > 999)
+ {
+ numVolumes /= 10;
+ ChangedPart += '0';
+ }
+ }
+
+ bool ParseName(const UString &name)
+ {
+ if (name.Len() < 2)
+ return false;
+ if (name.Back() != L'1' || name[name.Len() - 2] != L'0')
+ return false;
+
+ unsigned pos = name.Len() - 2;
+ for (; pos > 0 && name[pos - 1] == '0'; pos--);
+ UnchangedPart.SetFrom(name, pos);
+ ChangedPart = name.Ptr(pos);
+ return true;
+ }
+
+ UString GetNextName();
+};
+
+
+UString CVolSeqName::GetNextName()
+{
+ for (int i = (int)ChangedPart.Len() - 1; i >= 0; i--)
+ {
+ const wchar_t c = ChangedPart[i];
+ if (c != L'9')
+ {
+ ChangedPart.ReplaceOneCharAtPos((unsigned)i, (wchar_t)(c + 1));
+ break;
+ }
+ ChangedPart.ReplaceOneCharAtPos((unsigned)i, L'0');
+ if (i == 0)
+ ChangedPart.InsertAtFront(L'1');
+ }
+ return UnchangedPart + ChangedPart;
+}
+
+class CThreadSplit: public CProgressThreadVirt
+{
+ HRESULT ProcessVirt() Z7_override;
+public:
+ FString FilePath;
+ FString VolBasePath;
+ UInt64 NumVolumes;
+ CRecordVector<UInt64> VolumeSizes;
+};
+
+
+class CPreAllocOutFile
+{
+ UInt64 _preAllocSize;
+public:
+ NIO::COutFile File;
+ UInt64 Written;
+
+ CPreAllocOutFile(): _preAllocSize(0), Written(0) {}
+
+ ~CPreAllocOutFile()
+ {
+ SetCorrectFileLength();
+ }
+
+ void PreAlloc(UInt64 preAllocSize)
+ {
+ _preAllocSize = 0;
+ if (File.SetLength(preAllocSize))
+ _preAllocSize = preAllocSize;
+ File.SeekToBegin();
+ }
+
+ bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw()
+ {
+ bool res = File.Write(data, size, processedSize);
+ Written += processedSize;
+ return res;
+ }
+
+ void Close()
+ {
+ SetCorrectFileLength();
+ Written = 0;
+ _preAllocSize = 0;
+ File.Close();
+ }
+
+ void SetCorrectFileLength()
+ {
+ if (Written < _preAllocSize)
+ {
+ File.SetLength(Written);
+ _preAllocSize = 0;
+ }
+ }
+};
+
+
+static const UInt32 kBufSize = (1 << 20);
+
+HRESULT CThreadSplit::ProcessVirt()
+{
+ NIO::CInFile inFile;
+ if (!inFile.Open(FilePath))
+ return GetLastError_noZero_HRESULT();
+
+ CPreAllocOutFile outFile;
+
+ CMyBuffer buffer;
+ if (!buffer.Allocate(kBufSize))
+ return E_OUTOFMEMORY;
+
+ CVolSeqName seqName;
+ seqName.SetNumDigits(NumVolumes);
+
+ UInt64 length;
+ if (!inFile.GetLength(length))
+ return GetLastError_noZero_HRESULT();
+
+ CProgressSync &sync = Sync;
+ sync.Set_NumBytesTotal(length);
+
+ UInt64 pos = 0;
+ UInt64 prev = 0;
+ UInt64 numFiles = 0;
+ unsigned volIndex = 0;
+
+ for (;;)
+ {
+ UInt64 volSize;
+ if (volIndex < VolumeSizes.Size())
+ volSize = VolumeSizes[volIndex];
+ else
+ volSize = VolumeSizes.Back();
+
+ UInt32 needSize = kBufSize;
+ {
+ const UInt64 rem = volSize - outFile.Written;
+ if (needSize > rem)
+ needSize = (UInt32)rem;
+ }
+ UInt32 processedSize;
+ if (!inFile.Read(buffer, needSize, processedSize))
+ return GetLastError_noZero_HRESULT();
+ if (processedSize == 0)
+ return S_OK;
+ needSize = processedSize;
+
+ if (outFile.Written == 0)
+ {
+ FString name = VolBasePath;
+ name.Add_Dot();
+ name += us2fs(seqName.GetNextName());
+ sync.Set_FilePath(fs2us(name));
+ if (!outFile.File.Create(name, false))
+ {
+ const HRESULT res = GetLastError_noZero_HRESULT();
+ AddErrorPath(name);
+ return res;
+ }
+ UInt64 expectSize = volSize;
+ if (pos < length)
+ {
+ const UInt64 rem = length - pos;
+ if (expectSize > rem)
+ expectSize = rem;
+ }
+ outFile.PreAlloc(expectSize);
+ }
+
+ if (!outFile.Write(buffer, needSize, processedSize))
+ return GetLastError_noZero_HRESULT();
+ if (needSize != processedSize)
+ throw g_Message_FileWriteError;
+
+ pos += processedSize;
+
+ if (outFile.Written == volSize)
+ {
+ outFile.Close();
+ sync.Set_NumFilesCur(++numFiles);
+ if (volIndex < VolumeSizes.Size())
+ volIndex++;
+ }
+
+ if (pos - prev >= ((UInt32)1 << 22) || outFile.Written == 0)
+ {
+ RINOK(sync.Set_NumBytesCur(pos))
+ prev = pos;
+ }
+ }
+}
+
+
+void CApp::Split()
+{
+ const unsigned srcPanelIndex = GetFocusedPanelIndex();
+ CPanel &srcPanel = Panels[srcPanelIndex];
+ if (!srcPanel.Is_IO_FS_Folder())
+ {
+ srcPanel.MessageBox_Error_UnsupportOperation();
+ return;
+ }
+ CRecordVector<UInt32> indices;
+ srcPanel.Get_ItemIndices_Operated(indices);
+ if (indices.IsEmpty())
+ return;
+ if (indices.Size() != 1)
+ {
+ srcPanel.MessageBox_Error_LangID(IDS_SELECT_ONE_FILE);
+ return;
+ }
+ const unsigned index = indices[0];
+ if (srcPanel.IsItem_Folder(index))
+ {
+ srcPanel.MessageBox_Error_LangID(IDS_SELECT_ONE_FILE);
+ return;
+ }
+ const UString itemName = srcPanel.GetItemName(index);
+
+ const UString srcPath = srcPanel.GetFsPath() + srcPanel.GetItemPrefix(index);
+ UString path = srcPath;
+ unsigned destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex);
+ CPanel &destPanel = Panels[destPanelIndex];
+ if (NumPanels > 1)
+ if (destPanel.IsFSFolder())
+ path = destPanel.GetFsPath();
+ CSplitDialog splitDialog;
+ splitDialog.FilePath = srcPanel.GetItemRelPath(index);
+ splitDialog.Path = path;
+ if (splitDialog.Create(srcPanel.GetParent()) != IDOK)
+ return;
+
+ NFind::CFileInfo fileInfo;
+ if (!fileInfo.Find(us2fs(srcPath + itemName)))
+ {
+ srcPanel.MessageBox_Error(L"Cannot find file");
+ return;
+ }
+ if (fileInfo.Size <= splitDialog.VolumeSizes.Front())
+ {
+ srcPanel.MessageBox_Error_LangID(IDS_SPLIT_VOL_MUST_BE_SMALLER);
+ return;
+ }
+ const UInt64 numVolumes = GetNumberOfVolumes(fileInfo.Size, splitDialog.VolumeSizes);
+ if (numVolumes >= 100)
+ {
+ wchar_t s[32];
+ ConvertUInt64ToString(numVolumes, s);
+ if (::MessageBoxW(srcPanel, MyFormatNew(IDS_SPLIT_CONFIRM_MESSAGE, s),
+ LangString(IDS_SPLIT_CONFIRM_TITLE),
+ MB_YESNOCANCEL | MB_ICONQUESTION) != IDYES)
+ return;
+ }
+
+ path = splitDialog.Path;
+ NName::NormalizeDirPathPrefix(path);
+ if (!CreateComplexDir(us2fs(path)))
+ {
+ const HRESULT lastError = GetLastError_noZero_HRESULT();
+ srcPanel.MessageBox_Error_2Lines_Message_HRESULT(MyFormatNew(IDS_CANNOT_CREATE_FOLDER, path), lastError);
+ return;
+ }
+
+ {
+ CThreadSplit spliter;
+ spliter.NumVolumes = numVolumes;
+
+ CProgressDialog &progressDialog = spliter;
+
+ const UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE, 0x03000000);
+ const UString title = LangString(IDS_SPLITTING);
+
+ progressDialog.ShowCompressionInfo = false;
+
+ progressDialog.MainWindow = _window;
+ progressDialog.MainTitle = progressWindowTitle;
+ progressDialog.MainAddTitle = title;
+ progressDialog.MainAddTitle.Add_Space();
+ progressDialog.Sync.Set_TitleFileName(itemName);
+
+
+ spliter.FilePath = us2fs(srcPath + itemName);
+ spliter.VolBasePath = us2fs(path + srcPanel.GetItemName_for_Copy(index));
+ spliter.VolumeSizes = splitDialog.VolumeSizes;
+
+ // if (splitDialog.VolumeSizes.Size() == 0) return;
+
+ // CPanel::CDisableTimerProcessing disableTimerProcessing1(srcPanel);
+ // CPanel::CDisableTimerProcessing disableTimerProcessing2(destPanel);
+
+ if (spliter.Create(title, _window) != 0)
+ return;
+ }
+ RefreshTitleAlways();
+
+
+ // disableNotify.Restore();
+ // disableNotify.Restore();
+ // srcPanel.SetFocusToList();
+ // srcPanel.RefreshListCtrlSaveFocused();
+}
+
+
+class CThreadCombine: public CProgressThreadVirt
+{
+ HRESULT ProcessVirt() Z7_override;
+public:
+ FString InputDirPrefix;
+ FStringVector Names;
+ FString OutputPath;
+ UInt64 TotalSize;
+};
+
+HRESULT CThreadCombine::ProcessVirt()
+{
+ NIO::COutFile outFile;
+ if (!outFile.Create(OutputPath, false))
+ {
+ const HRESULT res = GetLastError_noZero_HRESULT();
+ AddErrorPath(OutputPath);
+ return res;
+ }
+
+ CProgressSync &sync = Sync;
+ sync.Set_NumBytesTotal(TotalSize);
+
+ CMyBuffer bufferObject;
+ if (!bufferObject.Allocate(kBufSize))
+ return E_OUTOFMEMORY;
+ Byte *buffer = (Byte *)(void *)bufferObject;
+ UInt64 pos = 0;
+ FOR_VECTOR (i, Names)
+ {
+ NIO::CInFile inFile;
+ const FString nextName = InputDirPrefix + Names[i];
+ if (!inFile.Open(nextName))
+ {
+ const HRESULT res = GetLastError_noZero_HRESULT();
+ AddErrorPath(nextName);
+ return res;
+ }
+ sync.Set_FilePath(fs2us(nextName));
+ for (;;)
+ {
+ UInt32 processedSize;
+ if (!inFile.Read(buffer, kBufSize, processedSize))
+ {
+ const HRESULT res = GetLastError_noZero_HRESULT();
+ AddErrorPath(nextName);
+ return res;
+ }
+ if (processedSize == 0)
+ break;
+ const UInt32 needSize = processedSize;
+ if (!outFile.Write(buffer, needSize, processedSize))
+ {
+ const HRESULT res = GetLastError_noZero_HRESULT();
+ AddErrorPath(OutputPath);
+ return res;
+ }
+ if (needSize != processedSize)
+ throw g_Message_FileWriteError;
+ pos += processedSize;
+ RINOK(sync.Set_NumBytesCur(pos))
+ }
+ }
+ return S_OK;
+}
+
+extern void AddValuePair2(UString &s, UINT resourceID, UInt64 num, UInt64 size);
+
+static void AddInfoFileName(UString &dest, const UString &name)
+{
+ dest += "\n ";
+ dest += name;
+}
+
+void CApp::Combine()
+{
+ const unsigned srcPanelIndex = GetFocusedPanelIndex();
+ CPanel &srcPanel = Panels[srcPanelIndex];
+ if (!srcPanel.IsFSFolder())
+ {
+ srcPanel.MessageBox_Error_LangID(IDS_OPERATION_IS_NOT_SUPPORTED);
+ return;
+ }
+ CRecordVector<UInt32> indices;
+ srcPanel.Get_ItemIndices_Operated(indices);
+ if (indices.IsEmpty())
+ return;
+ const unsigned index = indices[0];
+ if (indices.Size() != 1 || srcPanel.IsItem_Folder(index))
+ {
+ srcPanel.MessageBox_Error_LangID(IDS_COMBINE_SELECT_ONE_FILE);
+ return;
+ }
+ const UString itemName = srcPanel.GetItemName(index);
+
+ UString srcPath = srcPanel.GetFsPath() + srcPanel.GetItemPrefix(index);
+ UString path = srcPath;
+ unsigned destPanelIndex = (NumPanels <= 1) ? srcPanelIndex : (1 - srcPanelIndex);
+ CPanel &destPanel = Panels[destPanelIndex];
+ if (NumPanels > 1)
+ if (destPanel.IsFSFolder())
+ path = destPanel.GetFsPath();
+
+ CVolSeqName volSeqName;
+ if (!volSeqName.ParseName(itemName))
+ {
+ srcPanel.MessageBox_Error_LangID(IDS_COMBINE_CANT_DETECT_SPLIT_FILE);
+ return;
+ }
+
+ {
+ CThreadCombine combiner;
+
+ UString nextName = itemName;
+ combiner.TotalSize = 0;
+ for (;;)
+ {
+ NFind::CFileInfo fileInfo;
+ if (!fileInfo.Find(us2fs(srcPath + nextName)) || fileInfo.IsDir())
+ break;
+ combiner.Names.Add(us2fs(nextName));
+ combiner.TotalSize += fileInfo.Size;
+ nextName = volSeqName.GetNextName();
+ }
+ if (combiner.Names.Size() == 1)
+ {
+ srcPanel.MessageBox_Error_LangID(IDS_COMBINE_CANT_FIND_MORE_THAN_ONE_PART);
+ return;
+ }
+
+ if (combiner.TotalSize == 0)
+ {
+ srcPanel.MessageBox_Error(L"No data");
+ return;
+ }
+
+ UString info;
+ AddValuePair2(info, IDS_PROP_FILES, combiner.Names.Size(), combiner.TotalSize);
+
+ info.Add_LF();
+ info += srcPath;
+
+ unsigned i;
+ for (i = 0; i < combiner.Names.Size() && i < 2; i++)
+ AddInfoFileName(info, fs2us(combiner.Names[i]));
+ if (i != combiner.Names.Size())
+ {
+ if (i + 1 != combiner.Names.Size())
+ AddInfoFileName(info, L"...");
+ AddInfoFileName(info, fs2us(combiner.Names.Back()));
+ }
+
+ {
+ CCopyDialog copyDialog;
+ copyDialog.Value = path;
+ LangString(IDS_COMBINE, copyDialog.Title);
+ copyDialog.Title.Add_Space();
+ copyDialog.Title += srcPanel.GetItemRelPath(index);
+ LangString(IDS_COMBINE_TO, copyDialog.Static);
+ copyDialog.Info = info;
+ if (copyDialog.Create(srcPanel.GetParent()) != IDOK)
+ return;
+ path = copyDialog.Value;
+ }
+
+ NName::NormalizeDirPathPrefix(path);
+ if (!CreateComplexDir(us2fs(path)))
+ {
+ const HRESULT lastError = GetLastError_noZero_HRESULT();
+ srcPanel.MessageBox_Error_2Lines_Message_HRESULT(MyFormatNew(IDS_CANNOT_CREATE_FOLDER, path), lastError);
+ return;
+ }
+
+ UString outName = volSeqName.UnchangedPart;
+ while (!outName.IsEmpty())
+ {
+ if (outName.Back() != L'.')
+ break;
+ outName.DeleteBack();
+ }
+ if (outName.IsEmpty())
+ outName = "file";
+
+ NFind::CFileInfo fileInfo;
+ UString destFilePath = path + outName;
+ combiner.OutputPath = us2fs(destFilePath);
+ if (fileInfo.Find(combiner.OutputPath))
+ {
+ srcPanel.MessageBox_Error(MyFormatNew(IDS_FILE_EXIST, destFilePath));
+ return;
+ }
+
+ CProgressDialog &progressDialog = combiner;
+ progressDialog.ShowCompressionInfo = false;
+
+ const UString progressWindowTitle ("7-Zip"); // LangString(IDS_APP_TITLE, 0x03000000);
+ const UString title = LangString(IDS_COMBINING);
+
+ progressDialog.MainWindow = _window;
+ progressDialog.MainTitle = progressWindowTitle;
+ progressDialog.MainAddTitle = title;
+ progressDialog.MainAddTitle.Add_Space();
+
+ combiner.InputDirPrefix = us2fs(srcPath);
+
+ // CPanel::CDisableTimerProcessing disableTimerProcessing1(srcPanel);
+ // CPanel::CDisableTimerProcessing disableTimerProcessing2(destPanel);
+
+ if (combiner.Create(title, _window) != 0)
+ return;
+ }
+ RefreshTitleAlways();
+
+ // disableNotify.Restore();
+ // disableNotify.Restore();
+ // srcPanel.SetFocusToList();
+ // srcPanel.RefreshListCtrlSaveFocused();
+}
diff --git a/CPP/7zip/UI/FileManager/PasswordDialog.cpp b/CPP/7zip/UI/FileManager/PasswordDialog.cpp
index 95e83fe..bf99580 100644
--- a/CPP/7zip/UI/FileManager/PasswordDialog.cpp
+++ b/CPP/7zip/UI/FileManager/PasswordDialog.cpp
@@ -1,58 +1,58 @@
-// PasswordDialog.cpp
-
-#include "StdAfx.h"
-
-#include "PasswordDialog.h"
-
-#ifdef LANG
-#include "LangUtils.h"
-#endif
-
-#ifdef LANG
-static const UInt32 kLangIDs[] =
-{
- IDT_PASSWORD_ENTER,
- IDX_PASSWORD_SHOW
-};
-#endif
-
-void CPasswordDialog::ReadControls()
-{
- _passwordEdit.GetText(Password);
- ShowPassword = IsButtonCheckedBool(IDX_PASSWORD_SHOW);
-}
-
-void CPasswordDialog::SetTextSpec()
-{
- _passwordEdit.SetPasswordChar(ShowPassword ? 0: TEXT('*'));
- _passwordEdit.SetText(Password);
-}
-
-bool CPasswordDialog::OnInit()
-{
- #ifdef LANG
- LangSetWindowText(*this, IDD_PASSWORD);
- LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs));
- #endif
- _passwordEdit.Attach(GetItem(IDE_PASSWORD_PASSWORD));
- CheckButton(IDX_PASSWORD_SHOW, ShowPassword);
- SetTextSpec();
- return CModalDialog::OnInit();
-}
-
-bool CPasswordDialog::OnButtonClicked(int buttonID, HWND buttonHWND)
-{
- if (buttonID == IDX_PASSWORD_SHOW)
- {
- ReadControls();
- SetTextSpec();
- return true;
- }
- return CDialog::OnButtonClicked(buttonID, buttonHWND);
-}
-
-void CPasswordDialog::OnOK()
-{
- ReadControls();
- CModalDialog::OnOK();
-}
+// PasswordDialog.cpp
+
+#include "StdAfx.h"
+
+#include "PasswordDialog.h"
+
+#ifdef Z7_LANG
+#include "LangUtils.h"
+#endif
+
+#ifdef Z7_LANG
+static const UInt32 kLangIDs[] =
+{
+ IDT_PASSWORD_ENTER,
+ IDX_PASSWORD_SHOW
+};
+#endif
+
+void CPasswordDialog::ReadControls()
+{
+ _passwordEdit.GetText(Password);
+ ShowPassword = IsButtonCheckedBool(IDX_PASSWORD_SHOW);
+}
+
+void CPasswordDialog::SetTextSpec()
+{
+ _passwordEdit.SetPasswordChar(ShowPassword ? 0: TEXT('*'));
+ _passwordEdit.SetText(Password);
+}
+
+bool CPasswordDialog::OnInit()
+{
+ #ifdef Z7_LANG
+ LangSetWindowText(*this, IDD_PASSWORD);
+ LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
+ #endif
+ _passwordEdit.Attach(GetItem(IDE_PASSWORD_PASSWORD));
+ CheckButton(IDX_PASSWORD_SHOW, ShowPassword);
+ SetTextSpec();
+ return CModalDialog::OnInit();
+}
+
+bool CPasswordDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ if (buttonID == IDX_PASSWORD_SHOW)
+ {
+ ReadControls();
+ SetTextSpec();
+ return true;
+ }
+ return CDialog::OnButtonClicked(buttonID, buttonHWND);
+}
+
+void CPasswordDialog::OnOK()
+{
+ ReadControls();
+ CModalDialog::OnOK();
+}
diff --git a/CPP/7zip/UI/FileManager/PasswordDialog.h b/CPP/7zip/UI/FileManager/PasswordDialog.h
index b756a1c..e05c4ad 100644
--- a/CPP/7zip/UI/FileManager/PasswordDialog.h
+++ b/CPP/7zip/UI/FileManager/PasswordDialog.h
@@ -1,28 +1,28 @@
-// PasswordDialog.h
-
-#ifndef __PASSWORD_DIALOG_H
-#define __PASSWORD_DIALOG_H
-
-#include "../../../Windows/Control/Dialog.h"
-#include "../../../Windows/Control/Edit.h"
-
-#include "PasswordDialogRes.h"
-
-class CPasswordDialog: public NWindows::NControl::CModalDialog
-{
- NWindows::NControl::CEdit _passwordEdit;
-
- virtual void OnOK();
- virtual bool OnInit();
- virtual bool OnButtonClicked(int buttonID, HWND buttonHWND);
- void SetTextSpec();
- void ReadControls();
-public:
- UString Password;
- bool ShowPassword;
-
- CPasswordDialog(): ShowPassword(false) {}
- INT_PTR Create(HWND parentWindow = 0) { return CModalDialog::Create(IDD_PASSWORD, parentWindow); }
-};
-
-#endif
+// PasswordDialog.h
+
+#ifndef ZIP7_INC_PASSWORD_DIALOG_H
+#define ZIP7_INC_PASSWORD_DIALOG_H
+
+#include "../../../Windows/Control/Dialog.h"
+#include "../../../Windows/Control/Edit.h"
+
+#include "PasswordDialogRes.h"
+
+class CPasswordDialog: public NWindows::NControl::CModalDialog
+{
+ NWindows::NControl::CEdit _passwordEdit;
+
+ virtual void OnOK() Z7_override;
+ virtual bool OnInit() Z7_override;
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+ void SetTextSpec();
+ void ReadControls();
+public:
+ UString Password;
+ bool ShowPassword;
+
+ CPasswordDialog(): ShowPassword(false) {}
+ INT_PTR Create(HWND parentWindow = NULL) { return CModalDialog::Create(IDD_PASSWORD, parentWindow); }
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/PasswordDialog.rc b/CPP/7zip/UI/FileManager/PasswordDialog.rc
index 51dd5bc..90c57ef 100644
--- a/CPP/7zip/UI/FileManager/PasswordDialog.rc
+++ b/CPP/7zip/UI/FileManager/PasswordDialog.rc
@@ -1,14 +1,14 @@
-#include "PasswordDialogRes.h"
-#include "../../GuiCommon.rc"
-
-#define xc 140
-#define yc 72
-
-IDD_PASSWORD DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
-CAPTION "Enter password"
-BEGIN
- LTEXT "&Enter password:", IDT_PASSWORD_ENTER, m, m, xc, 8
- EDITTEXT IDE_PASSWORD_PASSWORD, m, 20, xc, 14, ES_PASSWORD | ES_AUTOHSCROLL
- CONTROL "&Show password", IDX_PASSWORD_SHOW, MY_CHECKBOX, m, 42, xc, 10
- OK_CANCEL
-END
+#include "PasswordDialogRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 140
+#define yc 72
+
+IDD_PASSWORD DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
+CAPTION "Enter password"
+BEGIN
+ LTEXT "&Enter password:", IDT_PASSWORD_ENTER, m, m, xc, 8
+ EDITTEXT IDE_PASSWORD_PASSWORD, m, 20, xc, 14, ES_PASSWORD | ES_AUTOHSCROLL
+ CONTROL "&Show password", IDX_PASSWORD_SHOW, MY_CHECKBOX, m, 42, xc, 10
+ OK_CANCEL
+END
diff --git a/CPP/7zip/UI/FileManager/PasswordDialogRes.h b/CPP/7zip/UI/FileManager/PasswordDialogRes.h
index f9300d6..1fe32e1 100644
--- a/CPP/7zip/UI/FileManager/PasswordDialogRes.h
+++ b/CPP/7zip/UI/FileManager/PasswordDialogRes.h
@@ -1,5 +1,5 @@
-#define IDD_PASSWORD 3800
-#define IDT_PASSWORD_ENTER 3801
-#define IDX_PASSWORD_SHOW 3803
-
-#define IDE_PASSWORD_PASSWORD 120
+#define IDD_PASSWORD 3800
+#define IDT_PASSWORD_ENTER 3801
+#define IDX_PASSWORD_SHOW 3803
+
+#define IDE_PASSWORD_PASSWORD 120
diff --git a/CPP/7zip/UI/FileManager/PluginInterface.h b/CPP/7zip/UI/FileManager/PluginInterface.h
new file mode 100644
index 0000000..dcb1b4b
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PluginInterface.h
@@ -0,0 +1,32 @@
+// PluginInterface.h
+
+#ifndef ZIP7_INC_PLUGIN_INTERFACE_H
+#define ZIP7_INC_PLUGIN_INTERFACE_H
+
+/*
+#include "../../../../C/7zTypes.h"
+#include "../../IDecl.h"
+
+#define Z7_IFACE_CONSTR_PLUGIN(i, n) \
+ Z7_DECL_IFACE_7ZIP(i, 0x0A, n) \
+ { Z7_IFACE_COM7_PURE(i) };
+
+#define Z7_IFACEM_IInitContextMenu(x) \
+ x(InitContextMenu(const wchar_t *folder, const wchar_t * const *names, UInt32 numFiles)) \
+
+Z7_IFACE_CONSTR_PLUGIN(IInitContextMenu, 0x00)
+
+#define Z7_IFACEM_IPluginOptionsCallback(x) \
+ x(GetProgramFolderPath(BSTR *value)) \
+ x(GetProgramPath(BSTR *value)) \
+ x(GetRegistryCUPath(BSTR *value)) \
+
+Z7_IFACE_CONSTR_PLUGIN(IPluginOptionsCallback, 0x01)
+
+#define Z7_IFACEM_IPluginOptions(x) \
+ x(PluginOptions(HWND hWnd, IPluginOptionsCallback *callback)) \
+ // x(GetFileExtensions(BSTR *extensions))
+
+Z7_IFACE_CONSTR_PLUGIN(IPluginOptions, 0x02)
+*/
+#endif
diff --git a/CPP/7zip/UI/FileManager/PluginLoader.h b/CPP/7zip/UI/FileManager/PluginLoader.h
new file mode 100644
index 0000000..d9309f2
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PluginLoader.h
@@ -0,0 +1,31 @@
+// PluginLoader.h
+
+#ifndef ZIP7_INC_PLUGIN_LOADER_H
+#define ZIP7_INC_PLUGIN_LOADER_H
+
+#include "../../../Windows/DLL.h"
+
+#include "IFolder.h"
+
+class CPluginLibrary: public NWindows::NDLL::CLibrary
+{
+public:
+ HRESULT CreateManager(REFGUID clsID, IFolderManager **manager)
+ {
+ const
+ Func_CreateObject createObject = Z7_GET_PROC_ADDRESS(
+ Func_CreateObject, Get_HMODULE(),
+ "CreateObject");
+ if (!createObject)
+ return GetLastError_noZero_HRESULT();
+ return createObject(&clsID, &IID_IFolderManager, (void **)manager);
+ }
+ HRESULT LoadAndCreateManager(CFSTR filePath, REFGUID clsID, IFolderManager **manager)
+ {
+ if (!Load(filePath))
+ return GetLastError_noZero_HRESULT();
+ return CreateManager(clsID, manager);
+ }
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/ProgramLocation.cpp b/CPP/7zip/UI/FileManager/ProgramLocation.cpp
new file mode 100644
index 0000000..50ca5ca
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ProgramLocation.cpp
@@ -0,0 +1,3 @@
+// ProgramLocation.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/UI/FileManager/ProgramLocation.h b/CPP/7zip/UI/FileManager/ProgramLocation.h
new file mode 100644
index 0000000..0cd9c74
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ProgramLocation.h
@@ -0,0 +1,6 @@
+// ProgramLocation.h
+
+#ifndef ZIP7_INC_PROGRAM_LOCATION_H
+#define ZIP7_INC_PROGRAM_LOCATION_H
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/ProgressDialog.cpp b/CPP/7zip/UI/FileManager/ProgressDialog.cpp
index 27d42b2..fc6f559 100644
--- a/CPP/7zip/UI/FileManager/ProgressDialog.cpp
+++ b/CPP/7zip/UI/FileManager/ProgressDialog.cpp
@@ -1,196 +1,201 @@
-// ProgressDialog.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/IntToString.h"
-
-#include "resource.h"
-
-#include "ProgressDialog.h"
-
-using namespace NWindows;
-
-extern HINSTANCE g_hInstance;
-
-static const UINT_PTR kTimerID = 3;
-static const UINT kTimerElapse = 100;
-
-#ifdef LANG
-#include "LangUtils.h"
-#endif
-
-HRESULT CProgressSync::ProcessStopAndPause()
-{
- for (;;)
- {
- if (GetStopped())
- return E_ABORT;
- if (!GetPaused())
- break;
- ::Sleep(100);
- }
- return S_OK;
-}
-
-#ifndef _SFX
-CProgressDialog::~CProgressDialog()
-{
- AddToTitle(L"");
-}
-void CProgressDialog::AddToTitle(LPCWSTR s)
-{
- if (MainWindow != 0)
- MySetWindowText(MainWindow, UString(s) + MainTitle);
-}
-#endif
-
-
-bool CProgressDialog::OnInit()
-{
- _range = (UInt64)(Int64)-1;
- _prevPercentValue = -1;
-
- _wasCreated = true;
- _dialogCreatedEvent.Set();
-
- #ifdef LANG
- LangSetDlgItems(*this, NULL, 0);
- #endif
-
- m_ProgressBar.Attach(GetItem(IDC_PROGRESS1));
-
- if (IconID >= 0)
- {
- HICON icon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IconID));
- SetIcon(ICON_BIG, icon);
- }
-
- _timer = SetTimer(kTimerID, kTimerElapse);
- SetText(_title);
- CheckNeedClose();
- return CModalDialog::OnInit();
-}
-
-void CProgressDialog::OnCancel() { Sync.SetStopped(true); }
-void CProgressDialog::OnOK() { }
-
-void CProgressDialog::SetRange(UInt64 range)
-{
- _range = range;
- _peviousPos = (UInt64)(Int64)-1;
- _converter.Init(range);
- m_ProgressBar.SetRange32(0 , _converter.Count(range)); // Test it for 100%
-}
-
-void CProgressDialog::SetPos(UInt64 pos)
-{
- bool redraw = true;
- if (pos < _range && pos > _peviousPos)
- {
- UInt64 posDelta = pos - _peviousPos;
- if (posDelta < (_range >> 10))
- redraw = false;
- }
- if (redraw)
- {
- m_ProgressBar.SetPos(_converter.Count(pos)); // Test it for 100%
- _peviousPos = pos;
- }
-}
-
-bool CProgressDialog::OnTimer(WPARAM /* timerID */, LPARAM /* callback */)
-{
- if (Sync.GetPaused())
- return true;
-
- CheckNeedClose();
-
- UInt64 total, completed;
- Sync.GetProgress(total, completed);
- if (total != _range)
- SetRange(total);
- SetPos(completed);
-
- if (total == 0)
- total = 1;
-
- int percentValue = (int)(completed * 100 / total);
- if (percentValue != _prevPercentValue)
- {
- wchar_t s[64];
- ConvertUInt64ToString(percentValue, s);
- UString title = s;
- title += "% ";
- SetText(title + _title);
- #ifndef _SFX
- AddToTitle(title + MainAddTitle);
- #endif
- _prevPercentValue = percentValue;
- }
- return true;
-}
-
-bool CProgressDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
-{
- switch (message)
- {
- case kCloseMessage:
- {
- KillTimer(_timer);
- _timer = 0;
- if (_inCancelMessageBox)
- {
- _externalCloseMessageWasReceived = true;
- break;
- }
- return OnExternalCloseMessage();
- }
- /*
- case WM_SETTEXT:
- {
- if (_timer == 0)
- return true;
- }
- */
- }
- return CModalDialog::OnMessage(message, wParam, lParam);
-}
-
-bool CProgressDialog::OnButtonClicked(int buttonID, HWND buttonHWND)
-{
- switch (buttonID)
- {
- case IDCANCEL:
- {
- bool paused = Sync.GetPaused();
- Sync.SetPaused(true);
- _inCancelMessageBox = true;
- int res = ::MessageBoxW(*this, L"Are you sure you want to cancel?", _title, MB_YESNOCANCEL);
- _inCancelMessageBox = false;
- Sync.SetPaused(paused);
- if (res == IDCANCEL || res == IDNO)
- {
- if (_externalCloseMessageWasReceived)
- OnExternalCloseMessage();
- return true;
- }
- break;
- }
- }
- return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
-}
-
-void CProgressDialog::CheckNeedClose()
-{
- if (_needClose)
- {
- PostMsg(kCloseMessage);
- _needClose = false;
- }
-}
-
-bool CProgressDialog::OnExternalCloseMessage()
-{
- End(0);
- return true;
-}
+// ProgressDialog.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+
+#include "resource.h"
+
+#include "ProgressDialog.h"
+
+using namespace NWindows;
+
+extern HINSTANCE g_hInstance;
+
+static const UINT_PTR kTimerID = 3;
+static const UINT kTimerElapse = 100;
+
+#ifdef Z7_LANG
+#include "LangUtils.h"
+#endif
+
+HRESULT CProgressSync::ProcessStopAndPause()
+{
+ for (;;)
+ {
+ if (GetStopped())
+ return E_ABORT;
+ if (!GetPaused())
+ break;
+ ::Sleep(100);
+ }
+ return S_OK;
+}
+
+#ifndef Z7_SFX
+CProgressDialog::~CProgressDialog()
+{
+ AddToTitle(L"");
+}
+void CProgressDialog::AddToTitle(LPCWSTR s)
+{
+ if (MainWindow != 0)
+ MySetWindowText(MainWindow, UString(s) + MainTitle);
+}
+#endif
+
+
+#define UNDEFINED_VAL ((UInt64)(Int64)-1)
+
+bool CProgressDialog::OnInit()
+{
+ _range = UNDEFINED_VAL;
+ _prevPercentValue = UNDEFINED_VAL;
+
+ _wasCreated = true;
+ _dialogCreatedEvent.Set();
+
+ #ifdef Z7_LANG
+ LangSetDlgItems(*this, NULL, 0);
+ #endif
+
+ m_ProgressBar.Attach(GetItem(IDC_PROGRESS1));
+
+ if (IconID >= 0)
+ {
+ HICON icon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IconID));
+ SetIcon(ICON_BIG, icon);
+ }
+
+ _timer = SetTimer(kTimerID, kTimerElapse);
+ SetText(_title);
+ CheckNeedClose();
+ return CModalDialog::OnInit();
+}
+
+void CProgressDialog::OnCancel() { Sync.SetStopped(true); }
+void CProgressDialog::OnOK() { }
+
+void CProgressDialog::SetRange(UInt64 range)
+{
+ _range = range;
+ _peviousPos = (UInt64)(Int64)-1;
+ _converter.Init(range);
+ m_ProgressBar.SetRange32(0 , _converter.Count(range)); // Test it for 100%
+}
+
+void CProgressDialog::SetPos(UInt64 pos)
+{
+ bool redraw = true;
+ if (pos < _range && pos > _peviousPos)
+ {
+ UInt64 posDelta = pos - _peviousPos;
+ if (posDelta < (_range >> 10))
+ redraw = false;
+ }
+ if (redraw)
+ {
+ m_ProgressBar.SetPos(_converter.Count(pos)); // Test it for 100%
+ _peviousPos = pos;
+ }
+}
+
+bool CProgressDialog::OnTimer(WPARAM /* timerID */, LPARAM /* callback */)
+{
+ if (Sync.GetPaused())
+ return true;
+
+ CheckNeedClose();
+
+ UInt64 total, completed;
+ Sync.GetProgress(total, completed);
+ if (total != _range)
+ SetRange(total);
+ SetPos(completed);
+
+ if (total == 0)
+ total = 1;
+
+ const UInt64 percentValue = completed * 100 / total;
+ if (percentValue != _prevPercentValue)
+ {
+ wchar_t s[64];
+ ConvertUInt64ToString(percentValue, s);
+ UString title = s;
+ title += "% ";
+ SetText(title + _title);
+ #ifndef Z7_SFX
+ AddToTitle(title + MainAddTitle);
+ #endif
+ _prevPercentValue = percentValue;
+ }
+ return true;
+}
+
+bool CProgressDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case kCloseMessage:
+ {
+ if (_timer)
+ {
+ KillTimer(kTimerID);
+ _timer = 0;
+ }
+ if (_inCancelMessageBox)
+ {
+ _externalCloseMessageWasReceived = true;
+ break;
+ }
+ return OnExternalCloseMessage();
+ }
+ /*
+ case WM_SETTEXT:
+ {
+ if (_timer == 0)
+ return true;
+ }
+ */
+ }
+ return CModalDialog::OnMessage(message, wParam, lParam);
+}
+
+bool CProgressDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ switch (buttonID)
+ {
+ case IDCANCEL:
+ {
+ bool paused = Sync.GetPaused();
+ Sync.SetPaused(true);
+ _inCancelMessageBox = true;
+ int res = ::MessageBoxW(*this, L"Are you sure you want to cancel?", _title, MB_YESNOCANCEL);
+ _inCancelMessageBox = false;
+ Sync.SetPaused(paused);
+ if (res == IDCANCEL || res == IDNO)
+ {
+ if (_externalCloseMessageWasReceived)
+ OnExternalCloseMessage();
+ return true;
+ }
+ break;
+ }
+ }
+ return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
+}
+
+void CProgressDialog::CheckNeedClose()
+{
+ if (_needClose)
+ {
+ PostMsg(kCloseMessage);
+ _needClose = false;
+ }
+}
+
+bool CProgressDialog::OnExternalCloseMessage()
+{
+ End(0);
+ return true;
+}
diff --git a/CPP/7zip/UI/FileManager/ProgressDialog.h b/CPP/7zip/UI/FileManager/ProgressDialog.h
index 2a9d26d..1fe9587 100644
--- a/CPP/7zip/UI/FileManager/ProgressDialog.h
+++ b/CPP/7zip/UI/FileManager/ProgressDialog.h
@@ -1,170 +1,171 @@
-// ProgressDialog.h
-
-#ifndef __PROGRESS_DIALOG_H
-#define __PROGRESS_DIALOG_H
-
-#include "../../../Windows/Synchronization.h"
-#include "../../../Windows/Thread.h"
-
-#include "../../../Windows/Control/Dialog.h"
-#include "../../../Windows/Control/ProgressBar.h"
-
-#include "ProgressDialogRes.h"
-
-class CProgressSync
-{
- NWindows::NSynchronization::CCriticalSection _cs;
- bool _stopped;
- bool _paused;
- UInt64 _total;
- UInt64 _completed;
-public:
- CProgressSync(): _stopped(false), _paused(false), _total(1), _completed(0) {}
-
- HRESULT ProcessStopAndPause();
- bool GetStopped()
- {
- NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
- return _stopped;
- }
- void SetStopped(bool value)
- {
- NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
- _stopped = value;
- }
- bool GetPaused()
- {
- NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
- return _paused;
- }
- void SetPaused(bool value)
- {
- NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
- _paused = value;
- }
- void SetProgress(UInt64 total, UInt64 completed)
- {
- NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
- _total = total;
- _completed = completed;
- }
- void SetPos(UInt64 completed)
- {
- NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
- _completed = completed;
- }
- void GetProgress(UInt64 &total, UInt64 &completed)
- {
- NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
- total = _total;
- completed = _completed;
- }
-};
-
-class CU64ToI32Converter
-{
- UInt64 _numShiftBits;
-public:
- void Init(UInt64 range)
- {
- // Windows CE doesn't like big number here.
- for (_numShiftBits = 0; range > (1 << 15); _numShiftBits++)
- range >>= 1;
- }
- int Count(UInt64 value) { return int(value >> _numShiftBits); }
-};
-
-class CProgressDialog: public NWindows::NControl::CModalDialog
-{
-private:
- UINT_PTR _timer;
-
- UString _title;
- CU64ToI32Converter _converter;
- UInt64 _peviousPos;
- UInt64 _range;
- NWindows::NControl::CProgressBar m_ProgressBar;
-
- int _prevPercentValue;
-
- bool _wasCreated;
- bool _needClose;
- bool _inCancelMessageBox;
- bool _externalCloseMessageWasReceived;
-
- bool OnTimer(WPARAM timerID, LPARAM callback);
- void SetRange(UInt64 range);
- void SetPos(UInt64 pos);
- virtual bool OnInit();
- virtual void OnCancel();
- virtual void OnOK();
- NWindows::NSynchronization::CManualResetEvent _dialogCreatedEvent;
- #ifndef _SFX
- void AddToTitle(LPCWSTR string);
- #endif
- bool OnButtonClicked(int buttonID, HWND buttonHWND);
-
- void WaitCreating() { _dialogCreatedEvent.Lock(); }
- void CheckNeedClose();
- bool OnExternalCloseMessage();
-public:
- CProgressSync Sync;
- int IconID;
-
- #ifndef _SFX
- HWND MainWindow;
- UString MainTitle;
- UString MainAddTitle;
- ~CProgressDialog();
- #endif
-
- CProgressDialog(): _timer(0)
- #ifndef _SFX
- ,MainWindow(0)
- #endif
- {
- IconID = -1;
- _wasCreated = false;
- _needClose = false;
- _inCancelMessageBox = false;
- _externalCloseMessageWasReceived = false;
-
- if (_dialogCreatedEvent.Create() != S_OK)
- throw 1334987;
- }
-
- INT_PTR Create(const UString &title, NWindows::CThread &thread, HWND wndParent = 0)
- {
- _title = title;
- INT_PTR res = CModalDialog::Create(IDD_PROGRESS, wndParent);
- thread.Wait();
- return res;
- }
-
- enum
- {
- kCloseMessage = WM_APP + 1
- };
-
- virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
-
- void ProcessWasFinished()
- {
- WaitCreating();
- if (_wasCreated)
- PostMsg(kCloseMessage);
- else
- _needClose = true;
- };
-};
-
-
-class CProgressCloser
-{
- CProgressDialog *_p;
-public:
- CProgressCloser(CProgressDialog &p) : _p(&p) {}
- ~CProgressCloser() { _p->ProcessWasFinished(); }
-};
-
-#endif
+// ProgressDialog.h
+
+#ifndef ZIP7_INC_PROGRESS_DIALOG_H
+#define ZIP7_INC_PROGRESS_DIALOG_H
+
+#include "../../../Windows/Synchronization.h"
+#include "../../../Windows/Thread.h"
+
+#include "../../../Windows/Control/Dialog.h"
+#include "../../../Windows/Control/ProgressBar.h"
+
+#include "ProgressDialogRes.h"
+
+class CProgressSync
+{
+ NWindows::NSynchronization::CCriticalSection _cs;
+ bool _stopped;
+ bool _paused;
+ UInt64 _total;
+ UInt64 _completed;
+public:
+ CProgressSync(): _stopped(false), _paused(false), _total(1), _completed(0) {}
+
+ HRESULT ProcessStopAndPause();
+ bool GetStopped()
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
+ return _stopped;
+ }
+ void SetStopped(bool value)
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
+ _stopped = value;
+ }
+ bool GetPaused()
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
+ return _paused;
+ }
+ void SetPaused(bool value)
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
+ _paused = value;
+ }
+ void SetProgress(UInt64 total, UInt64 completed)
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
+ _total = total;
+ _completed = completed;
+ }
+ void SetPos(UInt64 completed)
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
+ _completed = completed;
+ }
+ void GetProgress(UInt64 &total, UInt64 &completed)
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
+ total = _total;
+ completed = _completed;
+ }
+};
+
+class CU64ToI32Converter
+{
+ UInt64 _numShiftBits;
+public:
+ void Init(UInt64 range)
+ {
+ // Windows CE doesn't like big number here.
+ for (_numShiftBits = 0; range > (1 << 15); _numShiftBits++)
+ range >>= 1;
+ }
+ int Count(UInt64 value) { return int(value >> _numShiftBits); }
+};
+
+class CProgressDialog: public NWindows::NControl::CModalDialog
+{
+private:
+ UINT_PTR _timer;
+
+ UString _title;
+ CU64ToI32Converter _converter;
+ UInt64 _peviousPos;
+ UInt64 _range;
+ NWindows::NControl::CProgressBar m_ProgressBar;
+
+ UInt64 _prevPercentValue;
+
+ bool _wasCreated;
+ bool _needClose;
+ bool _inCancelMessageBox;
+ bool _externalCloseMessageWasReceived;
+
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+ virtual bool OnTimer(WPARAM timerID, LPARAM callback) Z7_override;
+ virtual bool OnInit() Z7_override;
+ virtual void OnCancel() Z7_override;
+ virtual void OnOK() Z7_override;
+ virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override;
+
+ void SetRange(UInt64 range);
+ void SetPos(UInt64 pos);
+
+ NWindows::NSynchronization::CManualResetEvent _dialogCreatedEvent;
+ #ifndef Z7_SFX
+ void AddToTitle(LPCWSTR string);
+ #endif
+
+ void WaitCreating() { _dialogCreatedEvent.Lock(); }
+ void CheckNeedClose();
+ bool OnExternalCloseMessage();
+public:
+ CProgressSync Sync;
+ int IconID;
+
+ #ifndef Z7_SFX
+ HWND MainWindow;
+ UString MainTitle;
+ UString MainAddTitle;
+ ~CProgressDialog();
+ #endif
+
+ CProgressDialog(): _timer(0)
+ #ifndef Z7_SFX
+ ,MainWindow(NULL)
+ #endif
+ {
+ IconID = -1;
+ _wasCreated = false;
+ _needClose = false;
+ _inCancelMessageBox = false;
+ _externalCloseMessageWasReceived = false;
+
+ if (_dialogCreatedEvent.Create() != S_OK)
+ throw 1334987;
+ }
+
+ INT_PTR Create(const UString &title, NWindows::CThread &thread, HWND wndParent = NULL)
+ {
+ _title = title;
+ INT_PTR res = CModalDialog::Create(IDD_PROGRESS, wndParent);
+ thread.Wait_Close();
+ return res;
+ }
+
+ enum
+ {
+ kCloseMessage = WM_APP + 1
+ };
+
+ void ProcessWasFinished()
+ {
+ WaitCreating();
+ if (_wasCreated)
+ PostMsg(kCloseMessage);
+ else
+ _needClose = true;
+ }
+};
+
+
+class CProgressCloser
+{
+ CProgressDialog *_p;
+public:
+ CProgressCloser(CProgressDialog &p) : _p(&p) {}
+ ~CProgressCloser() { _p->ProcessWasFinished(); }
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/ProgressDialog.rc b/CPP/7zip/UI/FileManager/ProgressDialog.rc
index 5af370f..55d9923 100644
--- a/CPP/7zip/UI/FileManager/ProgressDialog.rc
+++ b/CPP/7zip/UI/FileManager/ProgressDialog.rc
@@ -1,12 +1,12 @@
-#include "ProgressDialogRes.h"
-#include "../../GuiCommon.rc"
-
-#define xc 172
-#define yc 44
-
-IDD_PROGRESS DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
-CAPTION "Progress"
-BEGIN
- PUSHBUTTON "Cancel", IDCANCEL, bx, by, bxs, bys
- CONTROL "Progress1", IDC_PROGRESS1, "msctls_progress32", PBS_SMOOTH | WS_BORDER, m, m, xc, 14
-END
+#include "ProgressDialogRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 172
+#define yc 44
+
+IDD_PROGRESS DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
+CAPTION "Progress"
+BEGIN
+ PUSHBUTTON "Cancel", IDCANCEL, bx, by, bxs, bys
+ CONTROL "Progress1", IDC_PROGRESS1, "msctls_progress32", PBS_SMOOTH | WS_BORDER, m, m, xc, 14
+END
diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2.cpp b/CPP/7zip/UI/FileManager/ProgressDialog2.cpp
index bdb2be3..1521d83 100644
--- a/CPP/7zip/UI/FileManager/ProgressDialog2.cpp
+++ b/CPP/7zip/UI/FileManager/ProgressDialog2.cpp
@@ -1,1337 +1,1467 @@
-// ProgressDialog2.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/IntToString.h"
-#include "../../../Common/StringConvert.h"
-
-#include "../../../Windows/Control/Static.h"
-#include "../../../Windows/ErrorMsg.h"
-
-#include "../GUI/ExtractRes.h"
-
-#include "LangUtils.h"
-
-#include "DialogSize.h"
-#include "ProgressDialog2.h"
-#include "ProgressDialog2Res.h"
-
-using namespace NWindows;
-
-extern HINSTANCE g_hInstance;
-
-static const UINT_PTR kTimerID = 3;
-
-static const UINT kCloseMessage = WM_APP + 1;
-// we can't use WM_USER, since WM_USER can be used by standard Windows procedure for Dialog
-
-static const UINT kTimerElapse =
- #ifdef UNDER_CE
- 500
- #else
- 200
- #endif
- ;
-
-static const UINT kCreateDelay =
- #ifdef UNDER_CE
- 2500
- #else
- 500
- #endif
- ;
-
-static const DWORD kPauseSleepTime = 100;
-
-#ifdef LANG
-
-static const UInt32 kLangIDs[] =
-{
- IDT_PROGRESS_ELAPSED,
- IDT_PROGRESS_REMAINING,
- IDT_PROGRESS_TOTAL,
- IDT_PROGRESS_SPEED,
- IDT_PROGRESS_PROCESSED,
- IDT_PROGRESS_RATIO,
- IDT_PROGRESS_ERRORS,
- IDB_PROGRESS_BACKGROUND,
- IDB_PAUSE
-};
-
-static const UInt32 kLangIDs_Colon[] =
-{
- IDT_PROGRESS_PACKED,
- IDT_PROGRESS_FILES
-};
-
-#endif
-
-
-#define UNDEFINED_VAL ((UInt64)(Int64)-1)
-#define INIT_AS_UNDEFINED(v) v = UNDEFINED_VAL;
-#define IS_UNDEFINED_VAL(v) ((v) == UNDEFINED_VAL)
-#define IS_DEFINED_VAL(v) ((v) != UNDEFINED_VAL)
-
-CProgressSync::CProgressSync():
- _stopped(false), _paused(false),
- _bytesProgressMode(true),
- _totalBytes(UNDEFINED_VAL), _completedBytes(0),
- _totalFiles(UNDEFINED_VAL), _curFiles(0),
- _inSize(UNDEFINED_VAL),
- _outSize(UNDEFINED_VAL),
- _isDir(false)
- {}
-
-#define CHECK_STOP if (_stopped) return E_ABORT; if (!_paused) return S_OK;
-#define CRITICAL_LOCK NSynchronization::CCriticalSectionLock lock(_cs);
-
-bool CProgressSync::Get_Paused()
-{
- CRITICAL_LOCK
- return _paused;
-}
-
-HRESULT CProgressSync::CheckStop()
-{
- for (;;)
- {
- {
- CRITICAL_LOCK
- CHECK_STOP
- }
- ::Sleep(kPauseSleepTime);
- }
-}
-
-HRESULT CProgressSync::ScanProgress(UInt64 numFiles, UInt64 totalSize, const FString &fileName, bool isDir)
-{
- {
- CRITICAL_LOCK
- _totalFiles = numFiles;
- _totalBytes = totalSize;
- _filePath = fs2us(fileName);
- _isDir = isDir;
- // _completedBytes = 0;
- CHECK_STOP
- }
- return CheckStop();
-}
-
-HRESULT CProgressSync::Set_NumFilesTotal(UInt64 val)
-{
- {
- CRITICAL_LOCK
- _totalFiles = val;
- CHECK_STOP
- }
- return CheckStop();
-}
-
-void CProgressSync::Set_NumBytesTotal(UInt64 val)
-{
- CRITICAL_LOCK
- _totalBytes = val;
-}
-
-void CProgressSync::Set_NumFilesCur(UInt64 val)
-{
- CRITICAL_LOCK
- _curFiles = val;
-}
-
-HRESULT CProgressSync::Set_NumBytesCur(const UInt64 *val)
-{
- {
- CRITICAL_LOCK
- if (val)
- _completedBytes = *val;
- CHECK_STOP
- }
- return CheckStop();
-}
-
-HRESULT CProgressSync::Set_NumBytesCur(UInt64 val)
-{
- {
- CRITICAL_LOCK
- _completedBytes = val;
- CHECK_STOP
- }
- return CheckStop();
-}
-
-void CProgressSync::Set_Ratio(const UInt64 *inSize, const UInt64 *outSize)
-{
- CRITICAL_LOCK
- if (inSize)
- _inSize = *inSize;
- if (outSize)
- _outSize = *outSize;
-}
-
-void CProgressSync::Set_TitleFileName(const UString &fileName)
-{
- CRITICAL_LOCK
- _titleFileName = fileName;
-}
-
-void CProgressSync::Set_Status(const UString &s)
-{
- CRITICAL_LOCK
- _status = s;
-}
-
-HRESULT CProgressSync::Set_Status2(const UString &s, const wchar_t *path, bool isDir)
-{
- {
- CRITICAL_LOCK
- _status = s;
- if (path)
- _filePath = path;
- else
- _filePath.Empty();
- _isDir = isDir;
- }
- return CheckStop();
-}
-
-void CProgressSync::Set_FilePath(const wchar_t *path, bool isDir)
-{
- CRITICAL_LOCK
- if (path)
- _filePath = path;
- else
- _filePath.Empty();
- _isDir = isDir;
-}
-
-
-void CProgressSync::AddError_Message(const wchar_t *message)
-{
- CRITICAL_LOCK
- Messages.Add(message);
-}
-
-void CProgressSync::AddError_Message_Name(const wchar_t *message, const wchar_t *name)
-{
- UString s;
- if (name && *name != 0)
- s += name;
- if (message && *message != 0)
- {
- if (!s.IsEmpty())
- s.Add_LF();
- s += message;
- if (!s.IsEmpty() && s.Back() == L'\n')
- s.DeleteBack();
- }
- AddError_Message(s);
-}
-
-void CProgressSync::AddError_Code_Name(DWORD systemError, const wchar_t *name)
-{
- UString s = NError::MyFormatMessage(systemError);
- if (systemError == 0)
- s = "Error";
- AddError_Message_Name(s, name);
-}
-
-CProgressDialog::CProgressDialog():
- _timer(0),
- CompressingMode(true),
- MainWindow(0)
-{
- _isDir = false;
-
- _numMessages = 0;
- IconID = -1;
- MessagesDisplayed = false;
- _wasCreated = false;
- _needClose = false;
- _inCancelMessageBox = false;
- _externalCloseMessageWasReceived = false;
-
- _numPostedMessages = 0;
- _numAutoSizeMessages = 0;
- _errorsWereDisplayed = false;
- _waitCloseByCancelButton = false;
- _cancelWasPressed = false;
- ShowCompressionInfo = true;
- WaitMode = false;
- if (_dialogCreatedEvent.Create() != S_OK)
- throw 1334987;
- if (_createDialogEvent.Create() != S_OK)
- throw 1334987;
- #ifdef __ITaskbarList3_INTERFACE_DEFINED__
- CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void**)&_taskbarList);
- if (_taskbarList)
- _taskbarList->HrInit();
- #endif
-}
-
-#ifndef _SFX
-
-CProgressDialog::~CProgressDialog()
-{
- #ifdef __ITaskbarList3_INTERFACE_DEFINED__
- SetTaskbarProgressState(TBPF_NOPROGRESS);
- #endif
- AddToTitle(L"");
-}
-void CProgressDialog::AddToTitle(LPCWSTR s)
-{
- if (MainWindow != 0)
- {
- CWindow window(MainWindow);
- window.SetText((UString)s + MainTitle);
- }
-}
-
-#endif
-
-
-void CProgressDialog::SetTaskbarProgressState()
-{
- #ifdef __ITaskbarList3_INTERFACE_DEFINED__
- if (_taskbarList && _hwndForTaskbar)
- {
- TBPFLAG tbpFlags;
- if (Sync.Get_Paused())
- tbpFlags = TBPF_PAUSED;
- else
- tbpFlags = _errorsWereDisplayed ? TBPF_ERROR: TBPF_NORMAL;
- SetTaskbarProgressState(tbpFlags);
- }
- #endif
-}
-
-static const unsigned kTitleFileNameSizeLimit = 36;
-static const unsigned kCurrentFileNameSizeLimit = 82;
-
-static void ReduceString(UString &s, unsigned size)
-{
- if (s.Len() <= size)
- return;
- s.Delete(size / 2, s.Len() - size);
- s.Insert(size / 2, L" ... ");
-}
-
-void CProgressDialog::EnableErrorsControls(bool enable)
-{
- ShowItem_Bool(IDT_PROGRESS_ERRORS, enable);
- ShowItem_Bool(IDT_PROGRESS_ERRORS_VAL, enable);
- ShowItem_Bool(IDL_PROGRESS_MESSAGES, enable);
-}
-
-bool CProgressDialog::OnInit()
-{
- _hwndForTaskbar = MainWindow;
- if (!_hwndForTaskbar)
- _hwndForTaskbar = GetParent();
- if (!_hwndForTaskbar)
- _hwndForTaskbar = *this;
-
- INIT_AS_UNDEFINED(_progressBar_Range);
- INIT_AS_UNDEFINED(_progressBar_Pos);
-
- INIT_AS_UNDEFINED(_prevPercentValue);
- INIT_AS_UNDEFINED(_prevElapsedSec);
- INIT_AS_UNDEFINED(_prevRemainingSec);
-
- INIT_AS_UNDEFINED(_prevSpeed);
- _prevSpeed_MoveBits = 0;
-
- _prevTime = ::GetTickCount();
- _elapsedTime = 0;
-
- INIT_AS_UNDEFINED(_totalBytes_Prev);
- INIT_AS_UNDEFINED(_processed_Prev);
- INIT_AS_UNDEFINED(_packed_Prev);
- INIT_AS_UNDEFINED(_ratio_Prev);
- _filesStr_Prev.Empty();
-
- _foreground = true;
-
- m_ProgressBar.Attach(GetItem(IDC_PROGRESS1));
- _messageList.Attach(GetItem(IDL_PROGRESS_MESSAGES));
- _messageList.SetUnicodeFormat();
-
- _wasCreated = true;
- _dialogCreatedEvent.Set();
-
- #ifdef LANG
- LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs));
- LangSetDlgItems_Colon(*this, kLangIDs_Colon, ARRAY_SIZE(kLangIDs_Colon));
- #endif
-
- CWindow window(GetItem(IDB_PROGRESS_BACKGROUND));
- window.GetText(_background_String);
- _backgrounded_String = _background_String;
- _backgrounded_String.RemoveChar(L'&');
-
- window = GetItem(IDB_PAUSE);
- window.GetText(_pause_String);
-
- LangString(IDS_PROGRESS_FOREGROUND, _foreground_String);
- LangString(IDS_CONTINUE, _continue_String);
- LangString(IDS_PROGRESS_PAUSED, _paused_String);
-
- SetText(_title);
- SetPauseText();
- SetPriorityText();
-
- _messageList.InsertColumn(0, L"", 30);
- _messageList.InsertColumn(1, L"", 600);
-
- _messageList.SetColumnWidthAuto(0);
- _messageList.SetColumnWidthAuto(1);
-
- EnableErrorsControls(false);
-
- GetItemSizes(IDCANCEL, _buttonSizeX, _buttonSizeY);
- _numReduceSymbols = kCurrentFileNameSizeLimit;
- NormalizeSize(true);
-
- if (!ShowCompressionInfo)
- {
- HideItem(IDT_PROGRESS_PACKED);
- HideItem(IDT_PROGRESS_PACKED_VAL);
- HideItem(IDT_PROGRESS_RATIO);
- HideItem(IDT_PROGRESS_RATIO_VAL);
- }
-
- if (IconID >= 0)
- {
- HICON icon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IconID));
- // SetIcon(ICON_SMALL, icon);
- SetIcon(ICON_BIG, icon);
- }
- _timer = SetTimer(kTimerID, kTimerElapse);
- #ifdef UNDER_CE
- Foreground();
- #endif
-
- CheckNeedClose();
-
- SetTaskbarProgressState();
-
- return CModalDialog::OnInit();
-}
-
-static const UINT kIDs[] =
-{
- IDT_PROGRESS_ELAPSED, IDT_PROGRESS_ELAPSED_VAL,
- IDT_PROGRESS_REMAINING, IDT_PROGRESS_REMAINING_VAL,
- IDT_PROGRESS_FILES, IDT_PROGRESS_FILES_VAL,
- IDT_PROGRESS_RATIO, IDT_PROGRESS_RATIO_VAL,
- IDT_PROGRESS_ERRORS, IDT_PROGRESS_ERRORS_VAL,
-
- IDT_PROGRESS_TOTAL, IDT_PROGRESS_TOTAL_VAL,
- IDT_PROGRESS_SPEED, IDT_PROGRESS_SPEED_VAL,
- IDT_PROGRESS_PROCESSED, IDT_PROGRESS_PROCESSED_VAL,
- IDT_PROGRESS_PACKED, IDT_PROGRESS_PACKED_VAL
-};
-
-bool CProgressDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
-{
- int sY;
- int sStep;
- int mx, my;
- {
- RECT r;
- GetClientRectOfItem(IDT_PROGRESS_ELAPSED, r);
- mx = r.left;
- my = r.top;
- sY = RECT_SIZE_Y(r);
- GetClientRectOfItem(IDT_PROGRESS_REMAINING, r);
- sStep = r.top - my;
- }
-
- InvalidateRect(NULL);
-
- int xSizeClient = xSize - mx * 2;
-
- {
- int i;
- for (i = 800; i > 40; i = i * 9 / 10)
- if (Units_To_Pixels_X(i) <= xSizeClient)
- break;
- _numReduceSymbols = i / 4;
- }
-
- int yPos = ySize - my - _buttonSizeY;
-
- ChangeSubWindowSizeX(GetItem(IDT_PROGRESS_STATUS), xSize - mx * 2);
- ChangeSubWindowSizeX(GetItem(IDT_PROGRESS_FILE_NAME), xSize - mx * 2);
- ChangeSubWindowSizeX(GetItem(IDC_PROGRESS1), xSize - mx * 2);
-
- int bSizeX = _buttonSizeX;
- int mx2 = mx;
- for (;; mx2--)
- {
- int bSize2 = bSizeX * 3 + mx2 * 2;
- if (bSize2 <= xSizeClient)
- break;
- if (mx2 < 5)
- {
- bSizeX = (xSizeClient - mx2 * 2) / 3;
- break;
- }
- }
- if (bSizeX < 2)
- bSizeX = 2;
-
- {
- RECT r;
- GetClientRectOfItem(IDL_PROGRESS_MESSAGES, r);
- int y = r.top;
- int ySize2 = yPos - my - y;
- const int kMinYSize = _buttonSizeY + _buttonSizeY * 3 / 4;
- int xx = xSize - mx * 2;
- if (ySize2 < kMinYSize)
- {
- ySize2 = kMinYSize;
- if (xx > bSizeX * 2)
- xx -= bSizeX;
- }
-
- _messageList.Move(mx, y, xx, ySize2);
- }
-
- {
- int xPos = xSize - mx;
- xPos -= bSizeX;
- MoveItem(IDCANCEL, xPos, yPos, bSizeX, _buttonSizeY);
- xPos -= (mx2 + bSizeX);
- MoveItem(IDB_PAUSE, xPos, yPos, bSizeX, _buttonSizeY);
- xPos -= (mx2 + bSizeX);
- MoveItem(IDB_PROGRESS_BACKGROUND, xPos, yPos, bSizeX, _buttonSizeY);
- }
-
- int valueSize;
- int labelSize;
- int padSize;
-
- labelSize = Units_To_Pixels_X(MY_PROGRESS_LABEL_UNITS_MIN);
- valueSize = Units_To_Pixels_X(MY_PROGRESS_VAL_UNITS);
- padSize = Units_To_Pixels_X(MY_PROGRESS_PAD_UNITS);
- int requiredSize = (labelSize + valueSize) * 2 + padSize;
-
- int gSize;
- {
- if (requiredSize < xSizeClient)
- {
- int incr = (xSizeClient - requiredSize) / 3;
- labelSize += incr;
- }
- else
- labelSize = (xSizeClient - valueSize * 2 - padSize) / 2;
- if (labelSize < 0)
- labelSize = 0;
-
- gSize = labelSize + valueSize;
- padSize = xSizeClient - gSize * 2;
- }
-
- labelSize = gSize - valueSize;
-
- yPos = my;
- for (int i = 0; i < ARRAY_SIZE(kIDs); i += 2)
- {
- int x = mx;
- const int kNumColumn1Items = 5 * 2;
- if (i >= kNumColumn1Items)
- {
- if (i == kNumColumn1Items)
- yPos = my;
- x = mx + gSize + padSize;
- }
- MoveItem(kIDs[i], x, yPos, labelSize, sY);
- MoveItem(kIDs[i + 1], x + labelSize, yPos, valueSize, sY);
- yPos += sStep;
- }
- return false;
-}
-
-void CProgressDialog::OnCancel() { Sync.Set_Stopped(true); }
-void CProgressDialog::OnOK() { }
-
-void CProgressDialog::SetProgressRange(UInt64 range)
-{
- if (range == _progressBar_Range)
- return;
- _progressBar_Range = range;
- INIT_AS_UNDEFINED(_progressBar_Pos);
- _progressConv.Init(range);
- m_ProgressBar.SetRange32(0, _progressConv.Count(range));
-}
-
-void CProgressDialog::SetProgressPos(UInt64 pos)
-{
- if (pos >= _progressBar_Range ||
- pos <= _progressBar_Pos ||
- pos - _progressBar_Pos >= (_progressBar_Range >> 10))
- {
- m_ProgressBar.SetPos(_progressConv.Count(pos));
- #ifdef __ITaskbarList3_INTERFACE_DEFINED__
- if (_taskbarList && _hwndForTaskbar)
- _taskbarList->SetProgressValue(_hwndForTaskbar, pos, _progressBar_Range);
- #endif
- _progressBar_Pos = pos;
- }
-}
-
-#define UINT_TO_STR_2(val) { s[0] = (wchar_t)('0' + (val) / 10); s[1] = (wchar_t)('0' + (val) % 10); s += 2; }
-
-void GetTimeString(UInt64 timeValue, wchar_t *s)
-{
- UInt64 hours = timeValue / 3600;
- UInt32 seconds = (UInt32)(timeValue - hours * 3600);
- UInt32 minutes = seconds / 60;
- seconds %= 60;
- if (hours > 99)
- {
- ConvertUInt64ToString(hours, s);
- for (; *s != 0; s++);
- }
- else
- {
- UInt32 hours32 = (UInt32)hours;
- UINT_TO_STR_2(hours32);
- }
- *s++ = ':'; UINT_TO_STR_2(minutes);
- *s++ = ':'; UINT_TO_STR_2(seconds);
- *s = 0;
-}
-
-static void ConvertSizeToString(UInt64 v, wchar_t *s)
-{
- Byte c = 0;
- if (v >= ((UInt64)100000 << 20)) { v >>= 30; c = 'G'; }
- else if (v >= ((UInt64)100000 << 10)) { v >>= 20; c = 'M'; }
- else if (v >= ((UInt64)100000 << 0)) { v >>= 10; c = 'K'; }
- ConvertUInt64ToString(v, s);
- if (c != 0)
- {
- s += MyStringLen(s);
- *s++ = ' ';
- *s++ = c;
- *s++ = 0;
- }
-}
-
-void CProgressDialog::ShowSize(int id, UInt64 val, UInt64 &prev)
-{
- if (val == prev)
- return;
- prev = val;
- wchar_t s[40];
- s[0] = 0;
- if (IS_DEFINED_VAL(val))
- ConvertSizeToString(val, s);
- SetItemText(id, s);
-}
-
-static void GetChangedString(const UString &newStr, UString &prevStr, bool &hasChanged)
-{
- hasChanged = !(prevStr == newStr);
- if (hasChanged)
- prevStr = newStr;
-}
-
-static unsigned GetPower32(UInt32 val)
-{
- const unsigned kStart = 32;
- UInt32 mask = ((UInt32)1 << (kStart - 1));
- for (unsigned i = kStart;; i--)
- {
- if (i == 0 || (val & mask) != 0)
- return i;
- mask >>= 1;
- }
-}
-
-static unsigned GetPower64(UInt64 val)
-{
- UInt32 high = (UInt32)(val >> 32);
- if (high == 0)
- return GetPower32((UInt32)val);
- return GetPower32(high) + 32;
-}
-
-static UInt64 MyMultAndDiv(UInt64 mult1, UInt64 mult2, UInt64 divider)
-{
- unsigned pow1 = GetPower64(mult1);
- unsigned pow2 = GetPower64(mult2);
- while (pow1 + pow2 > 64)
- {
- if (pow1 > pow2) { pow1--; mult1 >>= 1; }
- else { pow2--; mult2 >>= 1; }
- divider >>= 1;
- }
- UInt64 res = mult1 * mult2;
- if (divider != 0)
- res /= divider;
- return res;
-}
-
-void CProgressDialog::UpdateStatInfo(bool showAll)
-{
- UInt64 total, completed, totalFiles, completedFiles, inSize, outSize;
- bool bytesProgressMode;
-
- bool titleFileName_Changed;
- bool curFilePath_Changed;
- bool status_Changed;
- unsigned numErrors;
- {
- NSynchronization::CCriticalSectionLock lock(Sync._cs);
- total = Sync._totalBytes;
- completed = Sync._completedBytes;
- totalFiles = Sync._totalFiles;
- completedFiles = Sync._curFiles;
- inSize = Sync._inSize;
- outSize = Sync._outSize;
- bytesProgressMode = Sync._bytesProgressMode;
-
- GetChangedString(Sync._titleFileName, _titleFileName, titleFileName_Changed);
- GetChangedString(Sync._filePath, _filePath, curFilePath_Changed);
- GetChangedString(Sync._status, _status, status_Changed);
- if (_isDir != Sync._isDir)
- {
- curFilePath_Changed = true;
- _isDir = Sync._isDir;
- }
- numErrors = Sync.Messages.Size();
- }
-
- UInt32 curTime = ::GetTickCount();
-
- const UInt64 progressTotal = bytesProgressMode ? total : totalFiles;
- const UInt64 progressCompleted = bytesProgressMode ? completed : completedFiles;
- {
- if (IS_UNDEFINED_VAL(progressTotal))
- {
- // SetPos(0);
- // SetRange(progressCompleted);
- }
- else
- {
- if (_progressBar_Pos != 0 || progressCompleted != 0 ||
- (_progressBar_Range == 0 && progressTotal != 0))
- {
- SetProgressRange(progressTotal);
- SetProgressPos(progressCompleted);
- }
- }
- }
-
- ShowSize(IDT_PROGRESS_TOTAL_VAL, total, _totalBytes_Prev);
-
- _elapsedTime += (curTime - _prevTime);
- _prevTime = curTime;
- UInt64 elapsedSec = _elapsedTime / 1000;
- bool elapsedChanged = false;
- if (elapsedSec != _prevElapsedSec)
- {
- _prevElapsedSec = elapsedSec;
- elapsedChanged = true;
- wchar_t s[40];
- GetTimeString(elapsedSec, s);
- SetItemText(IDT_PROGRESS_ELAPSED_VAL, s);
- }
-
- bool needSetTitle = false;
- if (elapsedChanged || showAll)
- {
- if (numErrors > _numPostedMessages)
- {
- UpdateMessagesDialog();
- wchar_t s[32];
- ConvertUInt64ToString(numErrors, s);
- SetItemText(IDT_PROGRESS_ERRORS_VAL, s);
- if (!_errorsWereDisplayed)
- {
- _errorsWereDisplayed = true;
- EnableErrorsControls(true);
- SetTaskbarProgressState();
- }
- }
-
- if (progressCompleted != 0)
- {
- if (IS_UNDEFINED_VAL(progressTotal))
- {
- if (IS_DEFINED_VAL(_prevRemainingSec))
- {
- INIT_AS_UNDEFINED(_prevRemainingSec);
- SetItemText(IDT_PROGRESS_REMAINING_VAL, L"");
- }
- }
- else
- {
- UInt64 remainingTime = 0;
- if (progressCompleted < progressTotal)
- remainingTime = MyMultAndDiv(_elapsedTime, progressTotal - progressCompleted, progressCompleted);
- UInt64 remainingSec = remainingTime / 1000;
- if (remainingSec != _prevRemainingSec)
- {
- _prevRemainingSec = remainingSec;
- wchar_t s[40];
- GetTimeString(remainingSec, s);
- SetItemText(IDT_PROGRESS_REMAINING_VAL, s);
- }
- }
- {
- UInt64 elapsedTime = (_elapsedTime == 0) ? 1 : _elapsedTime;
- UInt64 v = (progressCompleted * 1000) / elapsedTime;
- Byte c = 0;
- unsigned moveBits = 0;
- if (v >= ((UInt64)10000 << 10)) { moveBits = 20; c = 'M'; }
- else if (v >= ((UInt64)10000 << 0)) { moveBits = 10; c = 'K'; }
- v >>= moveBits;
- if (moveBits != _prevSpeed_MoveBits || v != _prevSpeed)
- {
- _prevSpeed_MoveBits = moveBits;
- _prevSpeed = v;
- wchar_t s[40];
- ConvertUInt64ToString(v, s);
- unsigned pos = MyStringLen(s);
- s[pos++] = ' ';
- if (moveBits != 0)
- s[pos++] = c;
- s[pos++] = 'B';
- s[pos++] = '/';
- s[pos++] = 's';
- s[pos++] = 0;
- SetItemText(IDT_PROGRESS_SPEED_VAL, s);
- }
- }
- }
-
- {
- UInt64 percent = 0;
- {
- if (IS_DEFINED_VAL(progressTotal))
- {
- percent = progressCompleted * 100;
- if (progressTotal != 0)
- percent /= progressTotal;
- }
- }
- if (percent != _prevPercentValue)
- {
- _prevPercentValue = percent;
- needSetTitle = true;
- }
- }
-
- {
- wchar_t s[64];
- ConvertUInt64ToString(completedFiles, s);
- if (IS_DEFINED_VAL(totalFiles))
- {
- MyStringCat(s, L" / ");
- ConvertUInt64ToString(totalFiles, s + MyStringLen(s));
- }
- if (_filesStr_Prev != s)
- {
- _filesStr_Prev = s;
- SetItemText(IDT_PROGRESS_FILES_VAL, s);
- }
- }
-
- const UInt64 packSize = CompressingMode ? outSize : inSize;
- const UInt64 unpackSize = CompressingMode ? inSize : outSize;
-
- if (IS_UNDEFINED_VAL(unpackSize) &&
- IS_UNDEFINED_VAL(packSize))
- {
- ShowSize(IDT_PROGRESS_PROCESSED_VAL, completed, _processed_Prev);
- ShowSize(IDT_PROGRESS_PACKED_VAL, UNDEFINED_VAL, _packed_Prev);
- }
- else
- {
- ShowSize(IDT_PROGRESS_PROCESSED_VAL, unpackSize, _processed_Prev);
- ShowSize(IDT_PROGRESS_PACKED_VAL, packSize, _packed_Prev);
-
- if (IS_DEFINED_VAL(packSize) &&
- IS_DEFINED_VAL(unpackSize) &&
- unpackSize != 0)
- {
- wchar_t s[32];
- UInt64 ratio = packSize * 100 / unpackSize;
- if (_ratio_Prev != ratio)
- {
- _ratio_Prev = ratio;
- ConvertUInt64ToString(ratio, s);
- MyStringCat(s, L"%");
- SetItemText(IDT_PROGRESS_RATIO_VAL, s);
- }
- }
- }
- }
-
- if (needSetTitle || titleFileName_Changed)
- SetTitleText();
-
- if (status_Changed)
- {
- UString s = _status;
- ReduceString(s, _numReduceSymbols);
- SetItemText(IDT_PROGRESS_STATUS, _status);
- }
-
- if (curFilePath_Changed)
- {
- UString s1, s2;
- if (_isDir)
- s1 = _filePath;
- else
- {
- int slashPos = _filePath.ReverseFind_PathSepar();
- if (slashPos >= 0)
- {
- s1.SetFrom(_filePath, slashPos + 1);
- s2 = _filePath.Ptr(slashPos + 1);
- }
- else
- s2 = _filePath;
- }
- ReduceString(s1, _numReduceSymbols);
- ReduceString(s2, _numReduceSymbols);
- s1.Add_LF();
- s1 += s2;
- SetItemText(IDT_PROGRESS_FILE_NAME, s1);
- }
-}
-
-bool CProgressDialog::OnTimer(WPARAM /* timerID */, LPARAM /* callback */)
-{
- if (Sync.Get_Paused())
- return true;
- CheckNeedClose();
- UpdateStatInfo(false);
- return true;
-}
-
-struct CWaitCursor
-{
- HCURSOR _waitCursor;
- HCURSOR _oldCursor;
- CWaitCursor()
- {
- _waitCursor = LoadCursor(NULL, IDC_WAIT);
- if (_waitCursor != NULL)
- _oldCursor = SetCursor(_waitCursor);
- }
- ~CWaitCursor()
- {
- if (_waitCursor != NULL)
- SetCursor(_oldCursor);
- }
-};
-
-INT_PTR CProgressDialog::Create(const UString &title, NWindows::CThread &thread, HWND wndParent)
-{
- INT_PTR res = 0;
- try
- {
- if (WaitMode)
- {
- CWaitCursor waitCursor;
- HANDLE h[] = { thread, _createDialogEvent };
-
- WRes res2 = WaitForMultipleObjects(ARRAY_SIZE(h), h, FALSE, kCreateDelay);
- if (res2 == WAIT_OBJECT_0 && !Sync.ThereIsMessage())
- return 0;
- }
- _title = title;
- BIG_DIALOG_SIZE(360, 192);
- res = CModalDialog::Create(SIZED_DIALOG(IDD_PROGRESS), wndParent);
- }
- catch(...)
- {
- _wasCreated = true;
- _dialogCreatedEvent.Set();
- res = res;
- }
- thread.Wait();
- if (!MessagesDisplayed)
- MessageBoxW(wndParent, L"Progress Error", L"7-Zip", MB_ICONERROR);
- return res;
-}
-
-bool CProgressDialog::OnExternalCloseMessage()
-{
- // it doesn't work if there is MessageBox.
- #ifdef __ITaskbarList3_INTERFACE_DEFINED__
- SetTaskbarProgressState(TBPF_NOPROGRESS);
- #endif
- // AddToTitle(L"Finished ");
- // SetText(L"Finished2 ");
-
- UpdateStatInfo(true);
-
- SetItemText(IDCANCEL, LangString(IDS_CLOSE));
- ::SendMessage(GetItem(IDCANCEL), BM_SETSTYLE, BS_DEFPUSHBUTTON, MAKELPARAM(TRUE, 0));
- HideItem(IDB_PROGRESS_BACKGROUND);
- HideItem(IDB_PAUSE);
-
- ProcessWasFinished_GuiVirt();
-
- bool thereAreMessages;
- CProgressFinalMessage fm;
- {
- NSynchronization::CCriticalSectionLock lock(Sync._cs);
- thereAreMessages = !Sync.Messages.IsEmpty();
- fm = Sync.FinalMessage;
- }
-
- if (!fm.ErrorMessage.Message.IsEmpty())
- {
- MessagesDisplayed = true;
- if (fm.ErrorMessage.Title.IsEmpty())
- fm.ErrorMessage.Title = "7-Zip";
- MessageBoxW(*this, fm.ErrorMessage.Message, fm.ErrorMessage.Title, MB_ICONERROR);
- }
- else if (!thereAreMessages)
- {
- MessagesDisplayed = true;
-
- if (!fm.OkMessage.Message.IsEmpty())
- {
- if (fm.OkMessage.Title.IsEmpty())
- fm.OkMessage.Title = "7-Zip";
- MessageBoxW(*this, fm.OkMessage.Message, fm.OkMessage.Title, MB_OK);
- }
- }
-
- if (thereAreMessages && !_cancelWasPressed)
- {
- _waitCloseByCancelButton = true;
- UpdateMessagesDialog();
- return true;
- }
-
- End(0);
- return true;
-}
-
-bool CProgressDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
-{
- switch (message)
- {
- case kCloseMessage:
- {
- KillTimer(_timer);
- _timer = 0;
- if (_inCancelMessageBox)
- {
- _externalCloseMessageWasReceived = true;
- break;
- }
- return OnExternalCloseMessage();
- }
- /*
- case WM_SETTEXT:
- {
- if (_timer == 0)
- return true;
- break;
- }
- */
- }
- return CModalDialog::OnMessage(message, wParam, lParam);
-}
-
-void CProgressDialog::SetTitleText()
-{
- UString s;
- if (Sync.Get_Paused())
- {
- s += _paused_String;
- s.Add_Space();
- }
- if (IS_DEFINED_VAL(_prevPercentValue))
- {
- char temp[32];
- ConvertUInt64ToString(_prevPercentValue, temp);
- s += temp;
- s += '%';
- }
- if (!_foreground)
- {
- s.Add_Space();
- s += _backgrounded_String;
- }
-
- s.Add_Space();
- #ifndef _SFX
- {
- unsigned len = s.Len();
- s += MainAddTitle;
- AddToTitle(s);
- s.DeleteFrom(len);
- }
- #endif
-
- s += _title;
- if (!_titleFileName.IsEmpty())
- {
- UString fileName = _titleFileName;
- ReduceString(fileName, kTitleFileNameSizeLimit);
- s.Add_Space();
- s += fileName;
- }
- SetText(s);
-}
-
-void CProgressDialog::SetPauseText()
-{
- SetItemText(IDB_PAUSE, Sync.Get_Paused() ? _continue_String : _pause_String);
- SetTitleText();
-}
-
-void CProgressDialog::OnPauseButton()
-{
- bool paused = !Sync.Get_Paused();
- Sync.Set_Paused(paused);
- UInt32 curTime = ::GetTickCount();
- if (paused)
- _elapsedTime += (curTime - _prevTime);
- SetTaskbarProgressState();
- _prevTime = curTime;
- SetPauseText();
-}
-
-void CProgressDialog::SetPriorityText()
-{
- SetItemText(IDB_PROGRESS_BACKGROUND, _foreground ?
- _background_String :
- _foreground_String);
- SetTitleText();
-}
-
-void CProgressDialog::OnPriorityButton()
-{
- _foreground = !_foreground;
- #ifndef UNDER_CE
- SetPriorityClass(GetCurrentProcess(), _foreground ? NORMAL_PRIORITY_CLASS: IDLE_PRIORITY_CLASS);
- #endif
- SetPriorityText();
-}
-
-void CProgressDialog::AddMessageDirect(LPCWSTR message, bool needNumber)
-{
- int itemIndex = _messageList.GetItemCount();
- wchar_t sz[16];
- sz[0] = 0;
- if (needNumber)
- ConvertUInt32ToString(_numMessages + 1, sz);
- _messageList.InsertItem(itemIndex, sz);
- _messageList.SetSubItem(itemIndex, 1, message);
-}
-
-void CProgressDialog::AddMessage(LPCWSTR message)
-{
- UString s = message;
- bool needNumber = true;
- while (!s.IsEmpty())
- {
- int pos = s.Find(L'\n');
- if (pos < 0)
- break;
- AddMessageDirect(s.Left(pos), needNumber);
- needNumber = false;
- s.DeleteFrontal(pos + 1);
- }
- AddMessageDirect(s, needNumber);
- _numMessages++;
-}
-
-static unsigned GetNumDigits(UInt32 val)
-{
- unsigned i;
- for (i = 0; val >= 10; i++)
- val /= 10;
- return i;
-}
-
-void CProgressDialog::UpdateMessagesDialog()
-{
- UStringVector messages;
- {
- NSynchronization::CCriticalSectionLock lock(Sync._cs);
- unsigned num = Sync.Messages.Size();
- if (num > _numPostedMessages)
- {
- messages.ClearAndReserve(num - _numPostedMessages);
- for (unsigned i = _numPostedMessages; i < num; i++)
- messages.AddInReserved(Sync.Messages[i]);
- _numPostedMessages = num;
- }
- }
- if (!messages.IsEmpty())
- {
- FOR_VECTOR (i, messages)
- AddMessage(messages[i]);
- if (_numAutoSizeMessages < 256 || GetNumDigits(_numPostedMessages) > GetNumDigits(_numAutoSizeMessages))
- {
- _messageList.SetColumnWidthAuto(0);
- _messageList.SetColumnWidthAuto(1);
- _numAutoSizeMessages = _numPostedMessages;
- }
- }
-}
-
-
-bool CProgressDialog::OnButtonClicked(int buttonID, HWND buttonHWND)
-{
- switch (buttonID)
- {
- // case IDOK: // if IDCANCEL is not DEFPUSHBUTTON
- case IDCANCEL:
- {
- if (_waitCloseByCancelButton)
- {
- MessagesDisplayed = true;
- End(IDCLOSE);
- break;
- }
-
- bool paused = Sync.Get_Paused();
- if (!paused)
- OnPauseButton();
- _inCancelMessageBox = true;
- int res = ::MessageBoxW(*this, LangString(IDS_PROGRESS_ASK_CANCEL), _title, MB_YESNOCANCEL);
- _inCancelMessageBox = false;
- if (!paused)
- OnPauseButton();
- if (res == IDCANCEL || res == IDNO)
- {
- if (_externalCloseMessageWasReceived)
- OnExternalCloseMessage();
- return true;
- }
-
- _cancelWasPressed = true;
- MessagesDisplayed = true;
- break;
- }
-
- case IDB_PAUSE:
- OnPauseButton();
- return true;
- case IDB_PROGRESS_BACKGROUND:
- OnPriorityButton();
- return true;
- }
- return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
-}
-
-void CProgressDialog::CheckNeedClose()
-{
- if (_needClose)
- {
- PostMsg(kCloseMessage);
- _needClose = false;
- }
-}
-
-void CProgressDialog::ProcessWasFinished()
-{
- // Set Window title here.
- if (!WaitMode)
- WaitCreating();
-
- if (_wasCreated)
- PostMsg(kCloseMessage);
- else
- _needClose = true;
-}
-
-
-static THREAD_FUNC_DECL MyThreadFunction(void *param)
-{
- CProgressThreadVirt *p = (CProgressThreadVirt *)param;
- try
- {
- p->Process();
- p->ThreadFinishedOK = true;
- }
- catch (...) { p->Result = E_FAIL; }
- return 0;
-}
-
-
-HRESULT CProgressThreadVirt::Create(const UString &title, HWND parentWindow)
-{
- NWindows::CThread thread;
- RINOK(thread.Create(MyThreadFunction, this));
- CProgressDialog::Create(title, thread, parentWindow);
- return S_OK;
-}
-
-static void AddMessageToString(UString &dest, const UString &src)
-{
- if (!src.IsEmpty())
- {
- if (!dest.IsEmpty())
- dest.Add_LF();
- dest += src;
- }
-}
-
-void CProgressThreadVirt::Process()
-{
- CProgressCloser closer(*this);
- UString m;
- try { Result = ProcessVirt(); }
- catch(const wchar_t *s) { m = s; }
- catch(const UString &s) { m = s; }
- catch(const char *s) { m = GetUnicodeString(s); }
- catch(int v)
- {
- m = "Error #";
- m.Add_UInt32(v);
- }
- catch(...) { m = "Error"; }
- if (Result != E_ABORT)
- {
- if (m.IsEmpty() && Result != S_OK)
- m = HResultToMessage(Result);
- }
- AddMessageToString(m, FinalMessage.ErrorMessage.Message);
-
- {
- FOR_VECTOR(i, ErrorPaths)
- {
- if (i >= 32)
- break;
- AddMessageToString(m, fs2us(ErrorPaths[i]));
- }
- }
-
- CProgressSync &sync = Sync;
- NSynchronization::CCriticalSectionLock lock(sync._cs);
- if (m.IsEmpty())
- {
- if (!FinalMessage.OkMessage.Message.IsEmpty())
- sync.FinalMessage.OkMessage = FinalMessage.OkMessage;
- }
- else
- {
- sync.FinalMessage.ErrorMessage.Message = m;
- if (Result == S_OK)
- Result = E_FAIL;
- }
-}
-
-UString HResultToMessage(HRESULT errorCode)
-{
- if (errorCode == E_OUTOFMEMORY)
- return LangString(IDS_MEM_ERROR);
- else
- return NError::MyFormatMessage(errorCode);
-}
+// ProgressDialog2.cpp
+
+#include "StdAfx.h"
+
+#ifdef Z7_OLD_WIN_SDK
+#include <ShlGuid.h>
+#endif
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/Clipboard.h"
+#include "../../../Windows/ErrorMsg.h"
+
+#include "../GUI/ExtractRes.h"
+
+#include "LangUtils.h"
+
+#include "DialogSize.h"
+#include "ProgressDialog2.h"
+#include "ProgressDialog2Res.h"
+
+using namespace NWindows;
+
+extern HINSTANCE g_hInstance;
+
+static const UINT_PTR kTimerID = 3;
+
+static const UINT kCloseMessage = WM_APP + 1;
+// we can't use WM_USER, since WM_USER can be used by standard Windows procedure for Dialog
+
+static const UINT kTimerElapse =
+ #ifdef UNDER_CE
+ 500
+ #else
+ 200
+ #endif
+ ;
+
+static const UINT kCreateDelay =
+ #ifdef UNDER_CE
+ 2500
+ #else
+ 500
+ #endif
+ ;
+
+static const DWORD kPauseSleepTime = 100;
+
+#ifdef Z7_LANG
+
+static const UInt32 kLangIDs[] =
+{
+ IDT_PROGRESS_ELAPSED,
+ IDT_PROGRESS_REMAINING,
+ IDT_PROGRESS_TOTAL,
+ IDT_PROGRESS_SPEED,
+ IDT_PROGRESS_PROCESSED,
+ IDT_PROGRESS_RATIO,
+ IDT_PROGRESS_ERRORS,
+ IDB_PROGRESS_BACKGROUND,
+ IDB_PAUSE
+};
+
+static const UInt32 kLangIDs_Colon[] =
+{
+ IDT_PROGRESS_PACKED,
+ IDT_PROGRESS_FILES
+};
+
+#endif
+
+
+#define UNDEFINED_VAL ((UInt64)(Int64)-1)
+#define INIT_AS_UNDEFINED(v) v = UNDEFINED_VAL;
+#define IS_UNDEFINED_VAL(v) ((v) == UNDEFINED_VAL)
+#define IS_DEFINED_VAL(v) ((v) != UNDEFINED_VAL)
+
+CProgressSync::CProgressSync():
+ _stopped(false), _paused(false),
+ _bytesProgressMode(true),
+ _isDir(false),
+ _totalBytes(UNDEFINED_VAL), _completedBytes(0),
+ _totalFiles(UNDEFINED_VAL), _curFiles(0),
+ _inSize(UNDEFINED_VAL),
+ _outSize(UNDEFINED_VAL)
+ {}
+
+#define CHECK_STOP if (_stopped) return E_ABORT; if (!_paused) return S_OK;
+#define CRITICAL_LOCK NSynchronization::CCriticalSectionLock lock(_cs);
+
+bool CProgressSync::Get_Paused()
+{
+ CRITICAL_LOCK
+ return _paused;
+}
+
+HRESULT CProgressSync::CheckStop()
+{
+ for (;;)
+ {
+ {
+ CRITICAL_LOCK
+ CHECK_STOP
+ }
+ ::Sleep(kPauseSleepTime);
+ }
+}
+
+HRESULT CProgressSync::ScanProgress(UInt64 numFiles, UInt64 totalSize, const FString &fileName, bool isDir)
+{
+ {
+ CRITICAL_LOCK
+ _totalFiles = numFiles;
+ _totalBytes = totalSize;
+ _filePath = fs2us(fileName);
+ _isDir = isDir;
+ // _completedBytes = 0;
+ CHECK_STOP
+ }
+ return CheckStop();
+}
+
+HRESULT CProgressSync::Set_NumFilesTotal(UInt64 val)
+{
+ {
+ CRITICAL_LOCK
+ _totalFiles = val;
+ CHECK_STOP
+ }
+ return CheckStop();
+}
+
+void CProgressSync::Set_NumBytesTotal(UInt64 val)
+{
+ CRITICAL_LOCK
+ _totalBytes = val;
+}
+
+void CProgressSync::Set_NumFilesCur(UInt64 val)
+{
+ CRITICAL_LOCK
+ _curFiles = val;
+}
+
+HRESULT CProgressSync::Set_NumBytesCur(const UInt64 *val)
+{
+ {
+ CRITICAL_LOCK
+ if (val)
+ _completedBytes = *val;
+ CHECK_STOP
+ }
+ return CheckStop();
+}
+
+HRESULT CProgressSync::Set_NumBytesCur(UInt64 val)
+{
+ {
+ CRITICAL_LOCK
+ _completedBytes = val;
+ CHECK_STOP
+ }
+ return CheckStop();
+}
+
+void CProgressSync::Set_Ratio(const UInt64 *inSize, const UInt64 *outSize)
+{
+ CRITICAL_LOCK
+ if (inSize)
+ _inSize = *inSize;
+ if (outSize)
+ _outSize = *outSize;
+}
+
+void CProgressSync::Set_TitleFileName(const UString &fileName)
+{
+ CRITICAL_LOCK
+ _titleFileName = fileName;
+}
+
+void CProgressSync::Set_Status(const UString &s)
+{
+ CRITICAL_LOCK
+ _status = s;
+}
+
+HRESULT CProgressSync::Set_Status2(const UString &s, const wchar_t *path, bool isDir)
+{
+ {
+ CRITICAL_LOCK
+ _status = s;
+ if (path)
+ _filePath = path;
+ else
+ _filePath.Empty();
+ _isDir = isDir;
+ }
+ return CheckStop();
+}
+
+void CProgressSync::Set_FilePath(const wchar_t *path, bool isDir)
+{
+ CRITICAL_LOCK
+ if (path)
+ _filePath = path;
+ else
+ _filePath.Empty();
+ _isDir = isDir;
+}
+
+
+void CProgressSync::AddError_Message(const wchar_t *message)
+{
+ CRITICAL_LOCK
+ Messages.Add(message);
+}
+
+void CProgressSync::AddError_Message_Name(const wchar_t *message, const wchar_t *name)
+{
+ UString s;
+ if (name && *name != 0)
+ s += name;
+ if (message && *message != 0)
+ {
+ if (!s.IsEmpty())
+ s.Add_LF();
+ s += message;
+ if (!s.IsEmpty() && s.Back() == L'\n')
+ s.DeleteBack();
+ }
+ AddError_Message(s);
+}
+
+void CProgressSync::AddError_Code_Name(HRESULT systemError, const wchar_t *name)
+{
+ UString s = NError::MyFormatMessage(systemError);
+ if (systemError == 0)
+ s = "Error";
+ AddError_Message_Name(s, name);
+}
+
+CProgressDialog::CProgressDialog():
+ _timer(0),
+ CompressingMode(true),
+ MainWindow(NULL)
+{
+ _isDir = false;
+
+ _numMessages = 0;
+ IconID = -1;
+ MessagesDisplayed = false;
+ _wasCreated = false;
+ _needClose = false;
+ _inCancelMessageBox = false;
+ _externalCloseMessageWasReceived = false;
+
+ _numPostedMessages = 0;
+ _numAutoSizeMessages = 0;
+ _errorsWereDisplayed = false;
+ _waitCloseByCancelButton = false;
+ _cancelWasPressed = false;
+ ShowCompressionInfo = true;
+ WaitMode = false;
+ if (_dialogCreatedEvent.Create() != S_OK)
+ throw 1334987;
+ if (_createDialogEvent.Create() != S_OK)
+ throw 1334987;
+ // #ifdef __ITaskbarList3_INTERFACE_DEFINED__
+ CoCreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER, IID_ITaskbarList3, (void**)&_taskbarList);
+ if (_taskbarList)
+ _taskbarList->HrInit();
+ // #endif
+}
+
+#ifndef Z7_SFX
+
+CProgressDialog::~CProgressDialog()
+{
+ // #ifdef __ITaskbarList3_INTERFACE_DEFINED__
+ SetTaskbarProgressState(TBPF_NOPROGRESS);
+ // #endif
+ AddToTitle(L"");
+}
+void CProgressDialog::AddToTitle(LPCWSTR s)
+{
+ if (MainWindow)
+ {
+ CWindow window(MainWindow);
+ window.SetText((UString)s + MainTitle);
+ }
+}
+
+#endif
+
+
+void CProgressDialog::SetTaskbarProgressState()
+{
+ // #ifdef __ITaskbarList3_INTERFACE_DEFINED__
+ if (_taskbarList && _hwndForTaskbar)
+ {
+ TBPFLAG tbpFlags;
+ if (Sync.Get_Paused())
+ tbpFlags = TBPF_PAUSED;
+ else
+ tbpFlags = _errorsWereDisplayed ? TBPF_ERROR: TBPF_NORMAL;
+ SetTaskbarProgressState(tbpFlags);
+ }
+ // #endif
+}
+
+static const unsigned kTitleFileNameSizeLimit = 36;
+static const unsigned kCurrentFileNameSizeLimit = 82;
+
+static void ReduceString(UString &s, unsigned size)
+{
+ if (s.Len() <= size)
+ return;
+ s.Delete(size / 2, s.Len() - size);
+ s.Insert(size / 2, L" ... ");
+}
+
+void CProgressDialog::EnableErrorsControls(bool enable)
+{
+ ShowItem_Bool(IDT_PROGRESS_ERRORS, enable);
+ ShowItem_Bool(IDT_PROGRESS_ERRORS_VAL, enable);
+ ShowItem_Bool(IDL_PROGRESS_MESSAGES, enable);
+}
+
+bool CProgressDialog::OnInit()
+{
+ _hwndForTaskbar = MainWindow;
+ if (!_hwndForTaskbar)
+ _hwndForTaskbar = GetParent();
+ if (!_hwndForTaskbar)
+ _hwndForTaskbar = *this;
+
+ INIT_AS_UNDEFINED(_progressBar_Range)
+ INIT_AS_UNDEFINED(_progressBar_Pos)
+
+ INIT_AS_UNDEFINED(_prevPercentValue)
+ INIT_AS_UNDEFINED(_prevElapsedSec)
+ INIT_AS_UNDEFINED(_prevRemainingSec)
+
+ INIT_AS_UNDEFINED(_prevSpeed)
+ _prevSpeed_MoveBits = 0;
+
+ _prevTime = ::GetTickCount();
+ _elapsedTime = 0;
+
+ INIT_AS_UNDEFINED(_totalBytes_Prev)
+ INIT_AS_UNDEFINED(_processed_Prev)
+ INIT_AS_UNDEFINED(_packed_Prev)
+ INIT_AS_UNDEFINED(_ratio_Prev)
+
+ _filesStr_Prev.Empty();
+ _filesTotStr_Prev.Empty();
+
+ _foreground = true;
+
+ m_ProgressBar.Attach(GetItem(IDC_PROGRESS1));
+ _messageList.Attach(GetItem(IDL_PROGRESS_MESSAGES));
+ _messageList.SetUnicodeFormat();
+ _messageList.SetExtendedListViewStyle(LVS_EX_FULLROWSELECT);
+
+ _wasCreated = true;
+ _dialogCreatedEvent.Set();
+
+ #ifdef Z7_LANG
+ LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
+ LangSetDlgItems_Colon(*this, kLangIDs_Colon, Z7_ARRAY_SIZE(kLangIDs_Colon));
+ #endif
+
+ CWindow window(GetItem(IDB_PROGRESS_BACKGROUND));
+ window.GetText(_background_String);
+ _backgrounded_String = _background_String;
+ _backgrounded_String.RemoveChar(L'&');
+
+ window = GetItem(IDB_PAUSE);
+ window.GetText(_pause_String);
+
+ LangString(IDS_PROGRESS_FOREGROUND, _foreground_String);
+ LangString(IDS_CONTINUE, _continue_String);
+ LangString(IDS_PROGRESS_PAUSED, _paused_String);
+
+ SetText(_title);
+ SetPauseText();
+ SetPriorityText();
+
+ _messageList.InsertColumn(0, L"", 30);
+ _messageList.InsertColumn(1, L"", 600);
+
+ _messageList.SetColumnWidthAuto(0);
+ _messageList.SetColumnWidthAuto(1);
+
+ EnableErrorsControls(false);
+
+ GetItemSizes(IDCANCEL, _buttonSizeX, _buttonSizeY);
+ _numReduceSymbols = kCurrentFileNameSizeLimit;
+ NormalizeSize(true);
+
+ if (!ShowCompressionInfo)
+ {
+ HideItem(IDT_PROGRESS_PACKED);
+ HideItem(IDT_PROGRESS_PACKED_VAL);
+ HideItem(IDT_PROGRESS_RATIO);
+ HideItem(IDT_PROGRESS_RATIO_VAL);
+ }
+
+ if (IconID >= 0)
+ {
+ HICON icon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IconID));
+ // SetIcon(ICON_SMALL, icon);
+ SetIcon(ICON_BIG, icon);
+ }
+ _timer = SetTimer(kTimerID, kTimerElapse);
+ #ifdef UNDER_CE
+ Foreground();
+ #endif
+
+ CheckNeedClose();
+
+ SetTaskbarProgressState();
+
+ return CModalDialog::OnInit();
+}
+
+static const UINT kIDs[] =
+{
+ IDT_PROGRESS_ELAPSED, IDT_PROGRESS_ELAPSED_VAL,
+ IDT_PROGRESS_REMAINING, IDT_PROGRESS_REMAINING_VAL,
+ IDT_PROGRESS_FILES, IDT_PROGRESS_FILES_VAL,
+ 0, IDT_PROGRESS_FILES_TOTAL,
+ IDT_PROGRESS_ERRORS, IDT_PROGRESS_ERRORS_VAL,
+
+ IDT_PROGRESS_TOTAL, IDT_PROGRESS_TOTAL_VAL,
+ IDT_PROGRESS_SPEED, IDT_PROGRESS_SPEED_VAL,
+ IDT_PROGRESS_PROCESSED, IDT_PROGRESS_PROCESSED_VAL,
+ IDT_PROGRESS_PACKED, IDT_PROGRESS_PACKED_VAL,
+ IDT_PROGRESS_RATIO, IDT_PROGRESS_RATIO_VAL
+};
+
+bool CProgressDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
+{
+ int sY;
+ int sStep;
+ int mx, my;
+ {
+ RECT r;
+ GetClientRectOfItem(IDT_PROGRESS_ELAPSED, r);
+ mx = r.left;
+ my = r.top;
+ sY = RECT_SIZE_Y(r);
+ GetClientRectOfItem(IDT_PROGRESS_REMAINING, r);
+ sStep = r.top - my;
+ }
+
+ InvalidateRect(NULL);
+
+ const int xSizeClient = xSize - mx * 2;
+
+ {
+ unsigned i;
+ for (i = 800; i > 40; i = i * 9 / 10)
+ if (Units_To_Pixels_X((int)i) <= xSizeClient)
+ break;
+ _numReduceSymbols = i / 4;
+ }
+
+ int yPos = ySize - my - _buttonSizeY;
+
+ ChangeSubWindowSizeX(GetItem(IDT_PROGRESS_STATUS), xSize - mx * 2);
+ ChangeSubWindowSizeX(GetItem(IDT_PROGRESS_FILE_NAME), xSize - mx * 2);
+ ChangeSubWindowSizeX(GetItem(IDC_PROGRESS1), xSize - mx * 2);
+
+ int bSizeX = _buttonSizeX;
+ int mx2 = mx;
+ for (;; mx2--)
+ {
+ const int bSize2 = bSizeX * 3 + mx2 * 2;
+ if (bSize2 <= xSizeClient)
+ break;
+ if (mx2 < 5)
+ {
+ bSizeX = (xSizeClient - mx2 * 2) / 3;
+ break;
+ }
+ }
+ if (bSizeX < 2)
+ bSizeX = 2;
+
+ {
+ RECT r;
+ GetClientRectOfItem(IDL_PROGRESS_MESSAGES, r);
+ const int y = r.top;
+ int ySize2 = yPos - my - y;
+ const int kMinYSize = _buttonSizeY + _buttonSizeY * 3 / 4;
+ int xx = xSize - mx * 2;
+ if (ySize2 < kMinYSize)
+ {
+ ySize2 = kMinYSize;
+ if (xx > bSizeX * 2)
+ xx -= bSizeX;
+ }
+
+ _messageList.Move(mx, y, xx, ySize2);
+ }
+
+ {
+ int xPos = xSize - mx;
+ xPos -= bSizeX;
+ MoveItem(IDCANCEL, xPos, yPos, bSizeX, _buttonSizeY);
+ xPos -= (mx2 + bSizeX);
+ MoveItem(IDB_PAUSE, xPos, yPos, bSizeX, _buttonSizeY);
+ xPos -= (mx2 + bSizeX);
+ MoveItem(IDB_PROGRESS_BACKGROUND, xPos, yPos, bSizeX, _buttonSizeY);
+ }
+
+ int valueSize;
+ int labelSize;
+ int padSize;
+
+ labelSize = Units_To_Pixels_X(MY_PROGRESS_LABEL_UNITS_MIN);
+ valueSize = Units_To_Pixels_X(MY_PROGRESS_VAL_UNITS);
+ padSize = Units_To_Pixels_X(MY_PROGRESS_PAD_UNITS);
+ const int requiredSize = (labelSize + valueSize) * 2 + padSize;
+
+ int gSize;
+ {
+ if (requiredSize < xSizeClient)
+ {
+ const int incr = (xSizeClient - requiredSize) / 3;
+ labelSize += incr;
+ }
+ else
+ labelSize = (xSizeClient - valueSize * 2 - padSize) / 2;
+ if (labelSize < 0)
+ labelSize = 0;
+
+ gSize = labelSize + valueSize;
+ padSize = xSizeClient - gSize * 2;
+ }
+
+ labelSize = gSize - valueSize;
+
+ yPos = my;
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(kIDs); i += 2)
+ {
+ int x = mx;
+ const unsigned kNumColumn1Items = 5 * 2;
+ if (i >= kNumColumn1Items)
+ {
+ if (i == kNumColumn1Items)
+ yPos = my;
+ x = mx + gSize + padSize;
+ }
+ if (kIDs[i] != 0)
+ MoveItem(kIDs[i], x, yPos, labelSize, sY);
+ MoveItem(kIDs[i + 1], x + labelSize, yPos, valueSize, sY);
+ yPos += sStep;
+ }
+ return false;
+}
+
+void CProgressDialog::OnCancel() { Sync.Set_Stopped(true); }
+void CProgressDialog::OnOK() { }
+
+void CProgressDialog::SetProgressRange(UInt64 range)
+{
+ if (range == _progressBar_Range)
+ return;
+ _progressBar_Range = range;
+ INIT_AS_UNDEFINED(_progressBar_Pos)
+ _progressConv.Init(range);
+ m_ProgressBar.SetRange32(0, _progressConv.Count(range));
+}
+
+void CProgressDialog::SetProgressPos(UInt64 pos)
+{
+ if (pos >= _progressBar_Range ||
+ pos <= _progressBar_Pos ||
+ pos - _progressBar_Pos >= (_progressBar_Range >> 10))
+ {
+ m_ProgressBar.SetPos(_progressConv.Count(pos));
+ // #ifdef __ITaskbarList3_INTERFACE_DEFINED__
+ if (_taskbarList && _hwndForTaskbar)
+ _taskbarList->SetProgressValue(_hwndForTaskbar, pos, _progressBar_Range);
+ // #endif
+ _progressBar_Pos = pos;
+ }
+}
+
+#define UINT_TO_STR_2(val) { s[0] = (wchar_t)('0' + (val) / 10); s[1] = (wchar_t)('0' + (val) % 10); s += 2; }
+
+void GetTimeString(UInt64 timeValue, wchar_t *s);
+void GetTimeString(UInt64 timeValue, wchar_t *s)
+{
+ UInt64 hours = timeValue / 3600;
+ UInt32 seconds = (UInt32)(timeValue - hours * 3600);
+ UInt32 minutes = seconds / 60;
+ seconds %= 60;
+ if (hours > 99)
+ {
+ ConvertUInt64ToString(hours, s);
+ for (; *s != 0; s++);
+ }
+ else
+ {
+ UInt32 hours32 = (UInt32)hours;
+ UINT_TO_STR_2(hours32)
+ }
+ *s++ = ':'; UINT_TO_STR_2(minutes)
+ *s++ = ':'; UINT_TO_STR_2(seconds)
+ *s = 0;
+}
+
+static void ConvertSizeToString(UInt64 v, wchar_t *s)
+{
+ Byte c = 0;
+ if (v >= ((UInt64)100000 << 20)) { v >>= 30; c = 'G'; }
+ else if (v >= ((UInt64)100000 << 10)) { v >>= 20; c = 'M'; }
+ else if (v >= ((UInt64)100000 << 0)) { v >>= 10; c = 'K'; }
+ ConvertUInt64ToString(v, s);
+ if (c != 0)
+ {
+ s += MyStringLen(s);
+ *s++ = ' ';
+ *s++ = c;
+ *s++ = 'B';
+ *s++ = 0;
+ }
+}
+
+void CProgressDialog::ShowSize(unsigned id, UInt64 val, UInt64 &prev)
+{
+ if (val == prev)
+ return;
+ prev = val;
+ wchar_t s[40];
+ s[0] = 0;
+ if (IS_DEFINED_VAL(val))
+ ConvertSizeToString(val, s);
+ SetItemText(id, s);
+}
+
+static void GetChangedString(const UString &newStr, UString &prevStr, bool &hasChanged)
+{
+ hasChanged = !(prevStr == newStr);
+ if (hasChanged)
+ prevStr = newStr;
+}
+
+static unsigned GetPower32(UInt32 val)
+{
+ const unsigned kStart = 32;
+ UInt32 mask = ((UInt32)1 << (kStart - 1));
+ for (unsigned i = kStart;; i--)
+ {
+ if (i == 0 || (val & mask) != 0)
+ return i;
+ mask >>= 1;
+ }
+}
+
+static unsigned GetPower64(UInt64 val)
+{
+ UInt32 high = (UInt32)(val >> 32);
+ if (high == 0)
+ return GetPower32((UInt32)val);
+ return GetPower32(high) + 32;
+}
+
+static UInt64 MyMultAndDiv(UInt64 mult1, UInt64 mult2, UInt64 divider)
+{
+ unsigned pow1 = GetPower64(mult1);
+ unsigned pow2 = GetPower64(mult2);
+ while (pow1 + pow2 > 64)
+ {
+ if (pow1 > pow2) { pow1--; mult1 >>= 1; }
+ else { pow2--; mult2 >>= 1; }
+ divider >>= 1;
+ }
+ UInt64 res = mult1 * mult2;
+ if (divider != 0)
+ res /= divider;
+ return res;
+}
+
+void CProgressDialog::UpdateStatInfo(bool showAll)
+{
+ UInt64 total, completed, totalFiles, completedFiles, inSize, outSize;
+ bool bytesProgressMode;
+
+ bool titleFileName_Changed;
+ bool curFilePath_Changed;
+ bool status_Changed;
+ unsigned numErrors;
+ {
+ NSynchronization::CCriticalSectionLock lock(Sync._cs);
+ total = Sync._totalBytes;
+ completed = Sync._completedBytes;
+ totalFiles = Sync._totalFiles;
+ completedFiles = Sync._curFiles;
+ inSize = Sync._inSize;
+ outSize = Sync._outSize;
+ bytesProgressMode = Sync._bytesProgressMode;
+
+ GetChangedString(Sync._titleFileName, _titleFileName, titleFileName_Changed);
+ GetChangedString(Sync._filePath, _filePath, curFilePath_Changed);
+ GetChangedString(Sync._status, _status, status_Changed);
+ if (_isDir != Sync._isDir)
+ {
+ curFilePath_Changed = true;
+ _isDir = Sync._isDir;
+ }
+ numErrors = Sync.Messages.Size();
+ }
+
+ UInt32 curTime = ::GetTickCount();
+
+ const UInt64 progressTotal = bytesProgressMode ? total : totalFiles;
+ const UInt64 progressCompleted = bytesProgressMode ? completed : completedFiles;
+ {
+ if (IS_UNDEFINED_VAL(progressTotal))
+ {
+ // SetPos(0);
+ // SetRange(progressCompleted);
+ }
+ else
+ {
+ if (_progressBar_Pos != 0 || progressCompleted != 0 ||
+ (_progressBar_Range == 0 && progressTotal != 0))
+ {
+ SetProgressRange(progressTotal);
+ SetProgressPos(progressCompleted);
+ }
+ }
+ }
+
+ ShowSize(IDT_PROGRESS_TOTAL_VAL, total, _totalBytes_Prev);
+
+ _elapsedTime += (curTime - _prevTime);
+ _prevTime = curTime;
+ UInt64 elapsedSec = _elapsedTime / 1000;
+ bool elapsedChanged = false;
+ if (elapsedSec != _prevElapsedSec)
+ {
+ _prevElapsedSec = elapsedSec;
+ elapsedChanged = true;
+ wchar_t s[40];
+ GetTimeString(elapsedSec, s);
+ SetItemText(IDT_PROGRESS_ELAPSED_VAL, s);
+ }
+
+ bool needSetTitle = false;
+ if (elapsedChanged || showAll)
+ {
+ if (numErrors > _numPostedMessages)
+ {
+ UpdateMessagesDialog();
+ wchar_t s[32];
+ ConvertUInt64ToString(numErrors, s);
+ SetItemText(IDT_PROGRESS_ERRORS_VAL, s);
+ if (!_errorsWereDisplayed)
+ {
+ _errorsWereDisplayed = true;
+ EnableErrorsControls(true);
+ SetTaskbarProgressState();
+ }
+ }
+
+ if (progressCompleted != 0)
+ {
+ if (IS_UNDEFINED_VAL(progressTotal))
+ {
+ if (IS_DEFINED_VAL(_prevRemainingSec))
+ {
+ INIT_AS_UNDEFINED(_prevRemainingSec)
+ SetItemText(IDT_PROGRESS_REMAINING_VAL, L"");
+ }
+ }
+ else
+ {
+ UInt64 remainingTime = 0;
+ if (progressCompleted < progressTotal)
+ remainingTime = MyMultAndDiv(_elapsedTime, progressTotal - progressCompleted, progressCompleted);
+ UInt64 remainingSec = remainingTime / 1000;
+ if (remainingSec != _prevRemainingSec)
+ {
+ _prevRemainingSec = remainingSec;
+ wchar_t s[40];
+ GetTimeString(remainingSec, s);
+ SetItemText(IDT_PROGRESS_REMAINING_VAL, s);
+ }
+ }
+ {
+ const UInt64 elapsedTime = (_elapsedTime == 0) ? 1 : _elapsedTime;
+ // 22.02: progressCompleted can be for number of files
+ UInt64 v = (completed * 1000) / elapsedTime;
+ Byte c = 0;
+ unsigned moveBits = 0;
+ if (v >= ((UInt64)10000 << 10)) { moveBits = 20; c = 'M'; }
+ else if (v >= ((UInt64)10000 << 0)) { moveBits = 10; c = 'K'; }
+ v >>= moveBits;
+ if (moveBits != _prevSpeed_MoveBits || v != _prevSpeed)
+ {
+ _prevSpeed_MoveBits = moveBits;
+ _prevSpeed = v;
+ wchar_t s[40];
+ ConvertUInt64ToString(v, s);
+ unsigned pos = MyStringLen(s);
+ s[pos++] = ' ';
+ if (moveBits != 0)
+ s[pos++] = c;
+ s[pos++] = 'B';
+ s[pos++] = '/';
+ s[pos++] = 's';
+ s[pos++] = 0;
+ SetItemText(IDT_PROGRESS_SPEED_VAL, s);
+ }
+ }
+ }
+
+ {
+ UInt64 percent = 0;
+ {
+ if (IS_DEFINED_VAL(progressTotal))
+ {
+ percent = progressCompleted * 100;
+ if (progressTotal != 0)
+ percent /= progressTotal;
+ }
+ }
+ if (percent != _prevPercentValue)
+ {
+ _prevPercentValue = percent;
+ needSetTitle = true;
+ }
+ }
+
+ {
+ wchar_t s[64];
+
+ ConvertUInt64ToString(completedFiles, s);
+ if (_filesStr_Prev != s)
+ {
+ _filesStr_Prev = s;
+ SetItemText(IDT_PROGRESS_FILES_VAL, s);
+ }
+
+ s[0] = 0;
+ if (IS_DEFINED_VAL(totalFiles))
+ {
+ MyStringCopy(s, L" / ");
+ ConvertUInt64ToString(totalFiles, s + MyStringLen(s));
+ }
+ if (_filesTotStr_Prev != s)
+ {
+ _filesTotStr_Prev = s;
+ SetItemText(IDT_PROGRESS_FILES_TOTAL, s);
+ }
+ }
+
+ const UInt64 packSize = CompressingMode ? outSize : inSize;
+ const UInt64 unpackSize = CompressingMode ? inSize : outSize;
+
+ if (IS_UNDEFINED_VAL(unpackSize) &&
+ IS_UNDEFINED_VAL(packSize))
+ {
+ ShowSize(IDT_PROGRESS_PROCESSED_VAL, completed, _processed_Prev);
+ ShowSize(IDT_PROGRESS_PACKED_VAL, UNDEFINED_VAL, _packed_Prev);
+ }
+ else
+ {
+ ShowSize(IDT_PROGRESS_PROCESSED_VAL, unpackSize, _processed_Prev);
+ ShowSize(IDT_PROGRESS_PACKED_VAL, packSize, _packed_Prev);
+
+ if (IS_DEFINED_VAL(packSize) &&
+ IS_DEFINED_VAL(unpackSize) &&
+ unpackSize != 0)
+ {
+ wchar_t s[32];
+ UInt64 ratio = packSize * 100 / unpackSize;
+ if (_ratio_Prev != ratio)
+ {
+ _ratio_Prev = ratio;
+ ConvertUInt64ToString(ratio, s);
+ MyStringCat(s, L"%");
+ SetItemText(IDT_PROGRESS_RATIO_VAL, s);
+ }
+ }
+ }
+ }
+
+ if (needSetTitle || titleFileName_Changed)
+ SetTitleText();
+
+ if (status_Changed)
+ {
+ UString s = _status;
+ ReduceString(s, _numReduceSymbols);
+ SetItemText(IDT_PROGRESS_STATUS, _status);
+ }
+
+ if (curFilePath_Changed)
+ {
+ UString s1, s2;
+ if (_isDir)
+ s1 = _filePath;
+ else
+ {
+ int slashPos = _filePath.ReverseFind_PathSepar();
+ if (slashPos >= 0)
+ {
+ s1.SetFrom(_filePath, (unsigned)(slashPos + 1));
+ s2 = _filePath.Ptr((unsigned)(slashPos + 1));
+ }
+ else
+ s2 = _filePath;
+ }
+ ReduceString(s1, _numReduceSymbols);
+ ReduceString(s2, _numReduceSymbols);
+ s1.Add_LF();
+ s1 += s2;
+ SetItemText(IDT_PROGRESS_FILE_NAME, s1);
+ }
+}
+
+bool CProgressDialog::OnTimer(WPARAM /* timerID */, LPARAM /* callback */)
+{
+ if (Sync.Get_Paused())
+ return true;
+ CheckNeedClose();
+ UpdateStatInfo(false);
+ return true;
+}
+
+struct CWaitCursor
+{
+ HCURSOR _waitCursor;
+ HCURSOR _oldCursor;
+ CWaitCursor()
+ {
+ _waitCursor = LoadCursor(NULL, IDC_WAIT);
+ if (_waitCursor != NULL)
+ _oldCursor = SetCursor(_waitCursor);
+ }
+ ~CWaitCursor()
+ {
+ if (_waitCursor != NULL)
+ SetCursor(_oldCursor);
+ }
+};
+
+INT_PTR CProgressDialog::Create(const UString &title, NWindows::CThread &thread, HWND wndParent)
+{
+ INT_PTR res = 0;
+ try
+ {
+ if (WaitMode)
+ {
+ CWaitCursor waitCursor;
+ HANDLE h[] = { thread, _createDialogEvent };
+
+ const DWORD res2 = WaitForMultipleObjects(Z7_ARRAY_SIZE(h), h, FALSE, kCreateDelay);
+ if (res2 == WAIT_OBJECT_0 && !Sync.ThereIsMessage())
+ return 0;
+ }
+ _title = title;
+ BIG_DIALOG_SIZE(360, 192);
+ res = CModalDialog::Create(SIZED_DIALOG(IDD_PROGRESS), wndParent);
+ }
+ catch(...)
+ {
+ _wasCreated = true;
+ _dialogCreatedEvent.Set();
+ }
+ thread.Wait_Close();
+ if (!MessagesDisplayed)
+ MessageBoxW(wndParent, L"Progress Error", L"7-Zip", MB_ICONERROR);
+ return res;
+}
+
+bool CProgressDialog::OnExternalCloseMessage()
+{
+ // it doesn't work if there is MessageBox.
+ // #ifdef __ITaskbarList3_INTERFACE_DEFINED__
+ SetTaskbarProgressState(TBPF_NOPROGRESS);
+ // #endif
+ // AddToTitle(L"Finished ");
+ // SetText(L"Finished2 ");
+
+ UpdateStatInfo(true);
+
+ SetItemText(IDCANCEL, LangString(IDS_CLOSE));
+ ::SendMessage(GetItem(IDCANCEL), BM_SETSTYLE, BS_DEFPUSHBUTTON, MAKELPARAM(TRUE, 0));
+ HideItem(IDB_PROGRESS_BACKGROUND);
+ HideItem(IDB_PAUSE);
+
+ ProcessWasFinished_GuiVirt();
+
+ bool thereAreMessages;
+ CProgressFinalMessage fm;
+ {
+ NSynchronization::CCriticalSectionLock lock(Sync._cs);
+ thereAreMessages = !Sync.Messages.IsEmpty();
+ fm = Sync.FinalMessage;
+ }
+
+ if (!fm.ErrorMessage.Message.IsEmpty())
+ {
+ MessagesDisplayed = true;
+ if (fm.ErrorMessage.Title.IsEmpty())
+ fm.ErrorMessage.Title = "7-Zip";
+ MessageBoxW(*this, fm.ErrorMessage.Message, fm.ErrorMessage.Title, MB_ICONERROR);
+ }
+ else if (!thereAreMessages)
+ {
+ MessagesDisplayed = true;
+
+ if (!fm.OkMessage.Message.IsEmpty())
+ {
+ if (fm.OkMessage.Title.IsEmpty())
+ fm.OkMessage.Title = "7-Zip";
+ MessageBoxW(*this, fm.OkMessage.Message, fm.OkMessage.Title, MB_OK);
+ }
+ }
+
+ if (thereAreMessages && !_cancelWasPressed)
+ {
+ _waitCloseByCancelButton = true;
+ UpdateMessagesDialog();
+ return true;
+ }
+
+ End(0);
+ return true;
+}
+
+bool CProgressDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case kCloseMessage:
+ {
+ if (_timer)
+ {
+ /* 21.03 : KillTimer(kTimerID) instead of KillTimer(_timer).
+ But (_timer == kTimerID) in Win10. So it worked too */
+ KillTimer(kTimerID);
+ _timer = 0;
+ }
+ if (_inCancelMessageBox)
+ {
+ /* if user is in MessageBox(), we will call OnExternalCloseMessage()
+ later, when MessageBox() will be closed */
+ _externalCloseMessageWasReceived = true;
+ break;
+ }
+ return OnExternalCloseMessage();
+ }
+ /*
+ case WM_SETTEXT:
+ {
+ if (_timer == 0)
+ return true;
+ break;
+ }
+ */
+ }
+ return CModalDialog::OnMessage(message, wParam, lParam);
+}
+
+void CProgressDialog::SetTitleText()
+{
+ UString s;
+ if (Sync.Get_Paused())
+ {
+ s += _paused_String;
+ s.Add_Space();
+ }
+ if (IS_DEFINED_VAL(_prevPercentValue))
+ {
+ char temp[32];
+ ConvertUInt64ToString(_prevPercentValue, temp);
+ s += temp;
+ s += '%';
+ }
+ if (!_foreground)
+ {
+ s.Add_Space();
+ s += _backgrounded_String;
+ }
+
+ s.Add_Space();
+ #ifndef Z7_SFX
+ {
+ unsigned len = s.Len();
+ s += MainAddTitle;
+ AddToTitle(s);
+ s.DeleteFrom(len);
+ }
+ #endif
+
+ s += _title;
+ if (!_titleFileName.IsEmpty())
+ {
+ UString fileName = _titleFileName;
+ ReduceString(fileName, kTitleFileNameSizeLimit);
+ s.Add_Space();
+ s += fileName;
+ }
+ SetText(s);
+}
+
+void CProgressDialog::SetPauseText()
+{
+ SetItemText(IDB_PAUSE, Sync.Get_Paused() ? _continue_String : _pause_String);
+ SetTitleText();
+}
+
+void CProgressDialog::OnPauseButton()
+{
+ bool paused = !Sync.Get_Paused();
+ Sync.Set_Paused(paused);
+ UInt32 curTime = ::GetTickCount();
+ if (paused)
+ _elapsedTime += (curTime - _prevTime);
+ SetTaskbarProgressState();
+ _prevTime = curTime;
+ SetPauseText();
+}
+
+void CProgressDialog::SetPriorityText()
+{
+ SetItemText(IDB_PROGRESS_BACKGROUND, _foreground ?
+ _background_String :
+ _foreground_String);
+ SetTitleText();
+}
+
+void CProgressDialog::OnPriorityButton()
+{
+ _foreground = !_foreground;
+ #ifndef UNDER_CE
+ SetPriorityClass(GetCurrentProcess(), _foreground ? NORMAL_PRIORITY_CLASS: IDLE_PRIORITY_CLASS);
+ #endif
+ SetPriorityText();
+}
+
+void CProgressDialog::AddMessageDirect(LPCWSTR message, bool needNumber)
+{
+ wchar_t sz[16];
+ sz[0] = 0;
+ if (needNumber)
+ ConvertUInt32ToString(_numMessages + 1, sz);
+ const unsigned itemIndex = _messageStrings.Size(); // _messageList.GetItemCount();
+ if (_messageList.InsertItem(itemIndex, sz) == (int)itemIndex)
+ {
+ _messageList.SetSubItem(itemIndex, 1, message);
+ _messageStrings.Add(message);
+ }
+}
+
+void CProgressDialog::AddMessage(LPCWSTR message)
+{
+ UString s = message;
+ bool needNumber = true;
+ while (!s.IsEmpty())
+ {
+ const int pos = s.Find(L'\n');
+ if (pos < 0)
+ break;
+ AddMessageDirect(s.Left((unsigned)pos), needNumber);
+ needNumber = false;
+ s.DeleteFrontal((unsigned)pos + 1);
+ }
+ AddMessageDirect(s, needNumber);
+ _numMessages++;
+}
+
+static unsigned GetNumDigits(UInt32 val)
+{
+ unsigned i;
+ for (i = 0; val >= 10; i++)
+ val /= 10;
+ return i;
+}
+
+void CProgressDialog::UpdateMessagesDialog()
+{
+ UStringVector messages;
+ {
+ NSynchronization::CCriticalSectionLock lock(Sync._cs);
+ unsigned num = Sync.Messages.Size();
+ if (num > _numPostedMessages)
+ {
+ messages.ClearAndReserve(num - _numPostedMessages);
+ for (unsigned i = _numPostedMessages; i < num; i++)
+ messages.AddInReserved(Sync.Messages[i]);
+ _numPostedMessages = num;
+ }
+ }
+ if (!messages.IsEmpty())
+ {
+ FOR_VECTOR (i, messages)
+ AddMessage(messages[i]);
+ if (_numAutoSizeMessages < 256 || GetNumDigits(_numPostedMessages) > GetNumDigits(_numAutoSizeMessages))
+ {
+ _messageList.SetColumnWidthAuto(0);
+ _messageList.SetColumnWidthAuto(1);
+ _numAutoSizeMessages = _numPostedMessages;
+ }
+ }
+}
+
+
+bool CProgressDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ switch (buttonID)
+ {
+ // case IDOK: // if IDCANCEL is not DEFPUSHBUTTON
+ case IDCANCEL:
+ {
+ if (_waitCloseByCancelButton)
+ {
+ MessagesDisplayed = true;
+ End(IDCLOSE);
+ break;
+ }
+
+ if (_cancelWasPressed)
+ return true;
+
+ const bool paused = Sync.Get_Paused();
+
+ if (!paused)
+ {
+ OnPauseButton();
+ }
+
+ _inCancelMessageBox = true;
+ const int res = ::MessageBoxW(*this, LangString(IDS_PROGRESS_ASK_CANCEL), _title, MB_YESNOCANCEL);
+ _inCancelMessageBox = false;
+ if (res == IDYES)
+ _cancelWasPressed = true;
+
+ if (!paused)
+ {
+ OnPauseButton();
+ }
+
+ if (_externalCloseMessageWasReceived)
+ {
+ /* we have received kCloseMessage while we were in MessageBoxW().
+ so we call OnExternalCloseMessage() here.
+ it can show MessageBox and it can close dialog */
+ OnExternalCloseMessage();
+ return true;
+ }
+
+ if (!_cancelWasPressed)
+ return true;
+
+ MessagesDisplayed = true;
+ // we will call Sync.Set_Stopped(true) in OnButtonClicked() : OnCancel()
+ break;
+ }
+
+ case IDB_PAUSE:
+ OnPauseButton();
+ return true;
+ case IDB_PROGRESS_BACKGROUND:
+ OnPriorityButton();
+ return true;
+ }
+ return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
+}
+
+void CProgressDialog::CheckNeedClose()
+{
+ if (_needClose)
+ {
+ PostMsg(kCloseMessage);
+ _needClose = false;
+ }
+}
+
+void CProgressDialog::ProcessWasFinished()
+{
+ // Set Window title here.
+ if (!WaitMode)
+ WaitCreating();
+
+ if (_wasCreated)
+ PostMsg(kCloseMessage);
+ else
+ _needClose = true;
+}
+
+
+bool CProgressDialog::OnNotify(UINT /* controlID */, LPNMHDR header)
+{
+ if (header->hwndFrom != _messageList)
+ return false;
+ switch (header->code)
+ {
+ case LVN_KEYDOWN:
+ {
+ LPNMLVKEYDOWN keyDownInfo = LPNMLVKEYDOWN(header);
+ switch (keyDownInfo->wVKey)
+ {
+ case 'A':
+ {
+ if (IsKeyDown(VK_CONTROL))
+ {
+ _messageList.SelectAll();
+ return true;
+ }
+ break;
+ }
+ case VK_INSERT:
+ case 'C':
+ {
+ if (IsKeyDown(VK_CONTROL))
+ {
+ CopyToClipboard();
+ return true;
+ }
+ break;
+ }
+ }
+ }
+ }
+ return false;
+}
+
+
+static void ListView_GetSelected(NControl::CListView &listView, CUIntVector &vector)
+{
+ vector.Clear();
+ int index = -1;
+ for (;;)
+ {
+ index = listView.GetNextSelectedItem(index);
+ if (index < 0)
+ break;
+ vector.Add((unsigned)index);
+ }
+}
+
+
+void CProgressDialog::CopyToClipboard()
+{
+ CUIntVector indexes;
+ ListView_GetSelected(_messageList, indexes);
+ UString s;
+ unsigned numIndexes = indexes.Size();
+ if (numIndexes == 0)
+ numIndexes = (unsigned)_messageList.GetItemCount();
+
+ for (unsigned i = 0; i < numIndexes; i++)
+ {
+ const unsigned index = (i < indexes.Size() ? indexes[i] : i);
+ // s.Add_UInt32(index);
+ // s += ": ";
+ s += _messageStrings[index];
+ {
+ s +=
+ #ifdef _WIN32
+ "\r\n"
+ #else
+ "\n"
+ #endif
+ ;
+ }
+ }
+
+ ClipboardSetText(*this, s);
+}
+
+
+static THREAD_FUNC_DECL MyThreadFunction(void *param)
+{
+ CProgressThreadVirt *p = (CProgressThreadVirt *)param;
+ try
+ {
+ p->Process();
+ p->ThreadFinishedOK = true;
+ }
+ catch (...) { p->Result = E_FAIL; }
+ return 0;
+}
+
+
+HRESULT CProgressThreadVirt::Create(const UString &title, HWND parentWindow)
+{
+ NWindows::CThread thread;
+ const WRes wres = thread.Create(MyThreadFunction, this);
+ if (wres != 0)
+ return HRESULT_FROM_WIN32(wres);
+ CProgressDialog::Create(title, thread, parentWindow);
+ return S_OK;
+}
+
+static void AddMessageToString(UString &dest, const UString &src)
+{
+ if (!src.IsEmpty())
+ {
+ if (!dest.IsEmpty())
+ dest.Add_LF();
+ dest += src;
+ }
+}
+
+void CProgressThreadVirt::Process()
+{
+ CProgressCloser closer(*this);
+ UString m;
+ try { Result = ProcessVirt(); }
+ catch(const wchar_t *s) { m = s; }
+ catch(const UString &s) { m = s; }
+ catch(const char *s) { m = GetUnicodeString(s); }
+ catch(int v)
+ {
+ m = "Error #";
+ m.Add_UInt32((unsigned)v);
+ }
+ catch(...) { m = "Error"; }
+ if (Result != E_ABORT)
+ {
+ if (m.IsEmpty() && Result != S_OK)
+ m = HResultToMessage(Result);
+ }
+ AddMessageToString(m, FinalMessage.ErrorMessage.Message);
+
+ {
+ FOR_VECTOR(i, ErrorPaths)
+ {
+ if (i >= 32)
+ break;
+ AddMessageToString(m, fs2us(ErrorPaths[i]));
+ }
+ }
+
+ CProgressSync &sync = Sync;
+ NSynchronization::CCriticalSectionLock lock(sync._cs);
+ if (m.IsEmpty())
+ {
+ if (!FinalMessage.OkMessage.Message.IsEmpty())
+ sync.FinalMessage.OkMessage = FinalMessage.OkMessage;
+ }
+ else
+ {
+ sync.FinalMessage.ErrorMessage.Message = m;
+ if (Result == S_OK)
+ Result = E_FAIL;
+ }
+}
+
+UString HResultToMessage(HRESULT errorCode)
+{
+ if (errorCode == E_OUTOFMEMORY)
+ return LangString(IDS_MEM_ERROR);
+ else
+ return NError::MyFormatMessage(errorCode);
+}
diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2.h b/CPP/7zip/UI/FileManager/ProgressDialog2.h
index 5e916e6..4ca9be7 100644
--- a/CPP/7zip/UI/FileManager/ProgressDialog2.h
+++ b/CPP/7zip/UI/FileManager/ProgressDialog2.h
@@ -1,351 +1,358 @@
-// ProgressDialog2.h
-
-#ifndef __PROGRESS_DIALOG_2_H
-#define __PROGRESS_DIALOG_2_H
-
-#include "../../../Common/MyCom.h"
-
-#include "../../../Windows/ErrorMsg.h"
-#include "../../../Windows/Synchronization.h"
-#include "../../../Windows/Thread.h"
-
-#include "../../../Windows/Control/Dialog.h"
-#include "../../../Windows/Control/ListView.h"
-#include "../../../Windows/Control/ProgressBar.h"
-
-#include "MyWindowsNew.h"
-
-struct CProgressMessageBoxPair
-{
- UString Title;
- UString Message;
-};
-
-struct CProgressFinalMessage
-{
- CProgressMessageBoxPair ErrorMessage;
- CProgressMessageBoxPair OkMessage;
-
- bool ThereIsMessage() const { return !ErrorMessage.Message.IsEmpty() || !OkMessage.Message.IsEmpty(); }
-};
-
-class CProgressSync
-{
- bool _stopped;
- bool _paused;
-
-public:
- bool _bytesProgressMode;
- UInt64 _totalBytes;
- UInt64 _completedBytes;
- UInt64 _totalFiles;
- UInt64 _curFiles;
- UInt64 _inSize;
- UInt64 _outSize;
-
- UString _titleFileName;
- UString _status;
- UString _filePath;
- bool _isDir;
-
- UStringVector Messages;
- CProgressFinalMessage FinalMessage;
-
- NWindows::NSynchronization::CCriticalSection _cs;
-
- CProgressSync();
-
- bool Get_Stopped()
- {
- NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
- return _stopped;
- }
- void Set_Stopped(bool val)
- {
- NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
- _stopped = val;
- }
-
- bool Get_Paused();
- void Set_Paused(bool val)
- {
- NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
- _paused = val;
- }
-
- void Set_BytesProgressMode(bool bytesProgressMode)
- {
- NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
- _bytesProgressMode = bytesProgressMode;
- }
-
- HRESULT CheckStop();
- HRESULT ScanProgress(UInt64 numFiles, UInt64 totalSize, const FString &fileName, bool isDir = false);
-
- HRESULT Set_NumFilesTotal(UInt64 val);
- void Set_NumBytesTotal(UInt64 val);
- void Set_NumFilesCur(UInt64 val);
- HRESULT Set_NumBytesCur(const UInt64 *val);
- HRESULT Set_NumBytesCur(UInt64 val);
- void Set_Ratio(const UInt64 *inSize, const UInt64 *outSize);
-
- void Set_TitleFileName(const UString &fileName);
- void Set_Status(const UString &s);
- HRESULT Set_Status2(const UString &s, const wchar_t *path, bool isDir = false);
- void Set_FilePath(const wchar_t *path, bool isDir = false);
-
- void AddError_Message(const wchar_t *message);
- void AddError_Message_Name(const wchar_t *message, const wchar_t *name);
- void AddError_Code_Name(DWORD systemError, const wchar_t *name);
-
- bool ThereIsMessage() const { return !Messages.IsEmpty() || FinalMessage.ThereIsMessage(); }
-};
-
-class CProgressDialog: public NWindows::NControl::CModalDialog
-{
- UString _titleFileName;
- UString _filePath;
- UString _status;
- bool _isDir;
-
- UString _background_String;
- UString _backgrounded_String;
- UString _foreground_String;
- UString _pause_String;
- UString _continue_String;
- UString _paused_String;
-
- int _buttonSizeX;
- int _buttonSizeY;
-
- UINT_PTR _timer;
-
- UString _title;
-
- class CU64ToI32Converter
- {
- unsigned _numShiftBits;
- UInt64 _range;
- public:
- CU64ToI32Converter(): _numShiftBits(0), _range(1) {}
- void Init(UInt64 range)
- {
- _range = range;
- // Windows CE doesn't like big number for ProgressBar.
- for (_numShiftBits = 0; range >= ((UInt32)1 << 15); _numShiftBits++)
- range >>= 1;
- }
- int Count(UInt64 val)
- {
- int res = (int)(val >> _numShiftBits);
- if (val == _range)
- res++;
- return res;
- }
- };
-
- CU64ToI32Converter _progressConv;
- UInt64 _progressBar_Pos;
- UInt64 _progressBar_Range;
-
- NWindows::NControl::CProgressBar m_ProgressBar;
- NWindows::NControl::CListView _messageList;
-
- int _numMessages;
-
- #ifdef __ITaskbarList3_INTERFACE_DEFINED__
- CMyComPtr<ITaskbarList3> _taskbarList;
- #endif
- HWND _hwndForTaskbar;
-
- UInt32 _prevTime;
- UInt64 _elapsedTime;
-
- UInt64 _prevPercentValue;
- UInt64 _prevElapsedSec;
- UInt64 _prevRemainingSec;
-
- UInt64 _totalBytes_Prev;
- UInt64 _processed_Prev;
- UInt64 _packed_Prev;
- UInt64 _ratio_Prev;
- UString _filesStr_Prev;
-
- unsigned _prevSpeed_MoveBits;
- UInt64 _prevSpeed;
-
- bool _foreground;
-
- unsigned _numReduceSymbols;
-
- bool _wasCreated;
- bool _needClose;
-
- unsigned _numPostedMessages;
- UInt32 _numAutoSizeMessages;
-
- bool _errorsWereDisplayed;
-
- bool _waitCloseByCancelButton;
- bool _cancelWasPressed;
-
- bool _inCancelMessageBox;
- bool _externalCloseMessageWasReceived;
-
-
- #ifdef __ITaskbarList3_INTERFACE_DEFINED__
- void SetTaskbarProgressState(TBPFLAG tbpFlags)
- {
- if (_taskbarList && _hwndForTaskbar)
- _taskbarList->SetProgressState(_hwndForTaskbar, tbpFlags);
- }
- #endif
- void SetTaskbarProgressState();
-
- void UpdateStatInfo(bool showAll);
- bool OnTimer(WPARAM timerID, LPARAM callback);
- void SetProgressRange(UInt64 range);
- void SetProgressPos(UInt64 pos);
- virtual bool OnInit();
- virtual bool OnSize(WPARAM wParam, int xSize, int ySize);
- virtual void OnCancel();
- virtual void OnOK();
- NWindows::NSynchronization::CManualResetEvent _createDialogEvent;
- NWindows::NSynchronization::CManualResetEvent _dialogCreatedEvent;
- #ifndef _SFX
- void AddToTitle(LPCWSTR string);
- #endif
-
- void SetPauseText();
- void SetPriorityText();
- void OnPauseButton();
- void OnPriorityButton();
- bool OnButtonClicked(int buttonID, HWND buttonHWND);
- bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
-
- void SetTitleText();
- void ShowSize(int id, UInt64 val, UInt64 &prev);
-
- void UpdateMessagesDialog();
-
- void AddMessageDirect(LPCWSTR message, bool needNumber);
- void AddMessage(LPCWSTR message);
-
- bool OnExternalCloseMessage();
- void EnableErrorsControls(bool enable);
-
- void ShowAfterMessages(HWND wndParent);
-
- void CheckNeedClose();
-public:
- CProgressSync Sync;
- bool CompressingMode;
- bool WaitMode;
- bool ShowCompressionInfo;
- bool MessagesDisplayed; // = true if user pressed OK on all messages or there are no messages.
- int IconID;
-
- HWND MainWindow;
- #ifndef _SFX
- UString MainTitle;
- UString MainAddTitle;
- ~CProgressDialog();
- #endif
-
- CProgressDialog();
- void WaitCreating()
- {
- _createDialogEvent.Set();
- _dialogCreatedEvent.Lock();
- }
-
- INT_PTR Create(const UString &title, NWindows::CThread &thread, HWND wndParent = 0);
-
-
- /* how it works:
- 1) the working thread calls ProcessWasFinished()
- that sends kCloseMessage message to CProgressDialog (GUI) thread
- 2) CProgressDialog (GUI) thread receives kCloseMessage message and
- calls ProcessWasFinished_GuiVirt();
- So we can implement ProcessWasFinished_GuiVirt() and show special
- results window in GUI thread with CProgressDialog as parent window
- */
-
- void ProcessWasFinished();
- virtual void ProcessWasFinished_GuiVirt() {}
-};
-
-
-class CProgressCloser
-{
- CProgressDialog *_p;
-public:
- CProgressCloser(CProgressDialog &p) : _p(&p) {}
- ~CProgressCloser() { _p->ProcessWasFinished(); }
-};
-
-
-class CProgressThreadVirt: public CProgressDialog
-{
-protected:
- FStringVector ErrorPaths;
- CProgressFinalMessage FinalMessage;
-
- // error if any of HRESULT, ErrorMessage, ErrorPath
- virtual HRESULT ProcessVirt() = 0;
-public:
- HRESULT Result;
- bool ThreadFinishedOK; // if there is no fatal exception
-
- void Process();
- void AddErrorPath(const FString &path) { ErrorPaths.Add(path); }
-
- HRESULT Create(const UString &title, HWND parentWindow = 0);
- CProgressThreadVirt(): Result(E_FAIL), ThreadFinishedOK(false) {}
-
- CProgressMessageBoxPair &GetMessagePair(bool isError) { return isError ? FinalMessage.ErrorMessage : FinalMessage.OkMessage; }
-};
-
-UString HResultToMessage(HRESULT errorCode);
-
-/*
-how it works:
-
-client code inherits CProgressThreadVirt and calls
-CProgressThreadVirt::Create()
-{
- it creates new thread that calls CProgressThreadVirt::Process();
- it creates modal progress dialog window with ProgressDialog.Create()
-}
-
-CProgressThreadVirt::Process()
-{
- {
- ProcessVirt(); // virtual function that must implement real work
- }
- if (exceptions) or FinalMessage.ErrorMessage.Message
- {
- set message to ProgressDialog.Sync.FinalMessage.ErrorMessage.Message
- }
- else if (FinalMessage.OkMessage.Message)
- {
- set message to ProgressDialog.Sync.FinalMessage.OkMessage
- }
-
- PostMsg(kCloseMessage);
-}
-
-
-CProgressDialog::OnExternalCloseMessage()
-{
- if (ProgressDialog.Sync.FinalMessage)
- {
- WorkWasFinishedVirt();
- Show (ProgressDialog.Sync.FinalMessage)
- MessagesDisplayed = true;
- }
-}
-
-*/
-
-#endif
+// ProgressDialog2.h
+
+#ifndef ZIP7_INC_PROGRESS_DIALOG_2_H
+#define ZIP7_INC_PROGRESS_DIALOG_2_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../../Windows/ErrorMsg.h"
+#include "../../../Windows/Synchronization.h"
+#include "../../../Windows/Thread.h"
+
+#include "../../../Windows/Control/Dialog.h"
+#include "../../../Windows/Control/ListView.h"
+#include "../../../Windows/Control/ProgressBar.h"
+
+#include "MyWindowsNew.h"
+
+struct CProgressMessageBoxPair
+{
+ UString Title;
+ UString Message;
+};
+
+struct CProgressFinalMessage
+{
+ CProgressMessageBoxPair ErrorMessage;
+ CProgressMessageBoxPair OkMessage;
+
+ bool ThereIsMessage() const { return !ErrorMessage.Message.IsEmpty() || !OkMessage.Message.IsEmpty(); }
+};
+
+class CProgressSync
+{
+ bool _stopped;
+ bool _paused;
+
+public:
+ bool _bytesProgressMode;
+ bool _isDir;
+ UInt64 _totalBytes;
+ UInt64 _completedBytes;
+ UInt64 _totalFiles;
+ UInt64 _curFiles;
+ UInt64 _inSize;
+ UInt64 _outSize;
+
+ UString _titleFileName;
+ UString _status;
+ UString _filePath;
+
+ UStringVector Messages;
+ CProgressFinalMessage FinalMessage;
+
+ NWindows::NSynchronization::CCriticalSection _cs;
+
+ CProgressSync();
+
+ bool Get_Stopped()
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
+ return _stopped;
+ }
+ void Set_Stopped(bool val)
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
+ _stopped = val;
+ }
+
+ bool Get_Paused();
+ void Set_Paused(bool val)
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
+ _paused = val;
+ }
+
+ void Set_BytesProgressMode(bool bytesProgressMode)
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(_cs);
+ _bytesProgressMode = bytesProgressMode;
+ }
+
+ HRESULT CheckStop();
+ HRESULT ScanProgress(UInt64 numFiles, UInt64 totalSize, const FString &fileName, bool isDir = false);
+
+ HRESULT Set_NumFilesTotal(UInt64 val);
+ void Set_NumBytesTotal(UInt64 val);
+ void Set_NumFilesCur(UInt64 val);
+ HRESULT Set_NumBytesCur(const UInt64 *val);
+ HRESULT Set_NumBytesCur(UInt64 val);
+ void Set_Ratio(const UInt64 *inSize, const UInt64 *outSize);
+
+ void Set_TitleFileName(const UString &fileName);
+ void Set_Status(const UString &s);
+ HRESULT Set_Status2(const UString &s, const wchar_t *path, bool isDir = false);
+ void Set_FilePath(const wchar_t *path, bool isDir = false);
+
+ void AddError_Message(const wchar_t *message);
+ void AddError_Message_Name(const wchar_t *message, const wchar_t *name);
+ // void AddError_Code_Name(DWORD systemError, const wchar_t *name);
+ void AddError_Code_Name(HRESULT systemError, const wchar_t *name);
+
+ bool ThereIsMessage() const { return !Messages.IsEmpty() || FinalMessage.ThereIsMessage(); }
+};
+
+class CProgressDialog: public NWindows::NControl::CModalDialog
+{
+ UString _titleFileName;
+ UString _filePath;
+ UString _status;
+ bool _isDir;
+
+ UString _background_String;
+ UString _backgrounded_String;
+ UString _foreground_String;
+ UString _pause_String;
+ UString _continue_String;
+ UString _paused_String;
+
+ int _buttonSizeX;
+ int _buttonSizeY;
+
+ UINT_PTR _timer;
+
+ UString _title;
+
+ class CU64ToI32Converter
+ {
+ unsigned _numShiftBits;
+ UInt64 _range;
+ public:
+ CU64ToI32Converter(): _numShiftBits(0), _range(1) {}
+ void Init(UInt64 range)
+ {
+ _range = range;
+ // Windows CE doesn't like big number for ProgressBar.
+ for (_numShiftBits = 0; range >= ((UInt32)1 << 15); _numShiftBits++)
+ range >>= 1;
+ }
+ int Count(UInt64 val)
+ {
+ int res = (int)(val >> _numShiftBits);
+ if (val == _range)
+ res++;
+ return res;
+ }
+ };
+
+ CU64ToI32Converter _progressConv;
+ UInt64 _progressBar_Pos;
+ UInt64 _progressBar_Range;
+
+ NWindows::NControl::CProgressBar m_ProgressBar;
+ NWindows::NControl::CListView _messageList;
+
+ unsigned _numMessages;
+ UStringVector _messageStrings;
+
+ // #ifdef __ITaskbarList3_INTERFACE_DEFINED__
+ CMyComPtr<ITaskbarList3> _taskbarList;
+ // #endif
+ HWND _hwndForTaskbar;
+
+ UInt32 _prevTime;
+ UInt64 _elapsedTime;
+
+ UInt64 _prevPercentValue;
+ UInt64 _prevElapsedSec;
+ UInt64 _prevRemainingSec;
+
+ UInt64 _totalBytes_Prev;
+ UInt64 _processed_Prev;
+ UInt64 _packed_Prev;
+ UInt64 _ratio_Prev;
+
+ UString _filesStr_Prev;
+ UString _filesTotStr_Prev;
+
+ unsigned _prevSpeed_MoveBits;
+ UInt64 _prevSpeed;
+
+ bool _foreground;
+
+ unsigned _numReduceSymbols;
+
+ bool _wasCreated;
+ bool _needClose;
+
+ unsigned _numPostedMessages;
+ UInt32 _numAutoSizeMessages;
+
+ bool _errorsWereDisplayed;
+
+ bool _waitCloseByCancelButton;
+ bool _cancelWasPressed;
+
+ bool _inCancelMessageBox;
+ bool _externalCloseMessageWasReceived;
+
+
+ // #ifdef __ITaskbarList3_INTERFACE_DEFINED__
+ void SetTaskbarProgressState(TBPFLAG tbpFlags)
+ {
+ if (_taskbarList && _hwndForTaskbar)
+ _taskbarList->SetProgressState(_hwndForTaskbar, tbpFlags);
+ }
+ // #endif
+ void SetTaskbarProgressState();
+
+ void UpdateStatInfo(bool showAll);
+ void SetProgressRange(UInt64 range);
+ void SetProgressPos(UInt64 pos);
+ virtual bool OnTimer(WPARAM timerID, LPARAM callback) Z7_override;
+ virtual bool OnInit() Z7_override;
+ virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override;
+ virtual void OnCancel() Z7_override;
+ virtual void OnOK() Z7_override;
+ virtual bool OnNotify(UINT /* controlID */, LPNMHDR header) Z7_override;
+ void CopyToClipboard();
+
+ NWindows::NSynchronization::CManualResetEvent _createDialogEvent;
+ NWindows::NSynchronization::CManualResetEvent _dialogCreatedEvent;
+ #ifndef Z7_SFX
+ void AddToTitle(LPCWSTR string);
+ #endif
+
+ void SetPauseText();
+ void SetPriorityText();
+ void OnPauseButton();
+ void OnPriorityButton();
+ bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+ bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override;
+
+ void SetTitleText();
+ void ShowSize(unsigned id, UInt64 val, UInt64 &prev);
+
+ void UpdateMessagesDialog();
+
+ void AddMessageDirect(LPCWSTR message, bool needNumber);
+ void AddMessage(LPCWSTR message);
+
+ bool OnExternalCloseMessage();
+ void EnableErrorsControls(bool enable);
+
+ void ShowAfterMessages(HWND wndParent);
+
+ void CheckNeedClose();
+public:
+ CProgressSync Sync;
+ bool CompressingMode;
+ bool WaitMode;
+ bool ShowCompressionInfo;
+ bool MessagesDisplayed; // = true if user pressed OK on all messages or there are no messages.
+ int IconID;
+
+ HWND MainWindow;
+ #ifndef Z7_SFX
+ UString MainTitle;
+ UString MainAddTitle;
+ ~CProgressDialog() Z7_DESTRUCTOR_override;
+ #endif
+
+ CProgressDialog();
+ void WaitCreating()
+ {
+ _createDialogEvent.Set();
+ _dialogCreatedEvent.Lock();
+ }
+
+ INT_PTR Create(const UString &title, NWindows::CThread &thread, HWND wndParent = NULL);
+
+
+ /* how it works:
+ 1) the working thread calls ProcessWasFinished()
+ that sends kCloseMessage message to CProgressDialog (GUI) thread
+ 2) CProgressDialog (GUI) thread receives kCloseMessage message and
+ calls ProcessWasFinished_GuiVirt();
+ So we can implement ProcessWasFinished_GuiVirt() and show special
+ results window in GUI thread with CProgressDialog as parent window
+ */
+
+ void ProcessWasFinished();
+ virtual void ProcessWasFinished_GuiVirt() {}
+};
+
+
+class CProgressCloser
+{
+ CProgressDialog *_p;
+public:
+ CProgressCloser(CProgressDialog &p) : _p(&p) {}
+ ~CProgressCloser() { _p->ProcessWasFinished(); }
+};
+
+
+class CProgressThreadVirt: public CProgressDialog
+{
+protected:
+ FStringVector ErrorPaths;
+ CProgressFinalMessage FinalMessage;
+
+ // error if any of HRESULT, ErrorMessage, ErrorPath
+ virtual HRESULT ProcessVirt() = 0;
+public:
+ HRESULT Result;
+ bool ThreadFinishedOK; // if there is no fatal exception
+
+ void Process();
+ void AddErrorPath(const FString &path) { ErrorPaths.Add(path); }
+
+ HRESULT Create(const UString &title, HWND parentWindow = NULL);
+ CProgressThreadVirt(): Result(E_FAIL), ThreadFinishedOK(false) {}
+
+ CProgressMessageBoxPair &GetMessagePair(bool isError) { return isError ? FinalMessage.ErrorMessage : FinalMessage.OkMessage; }
+};
+
+UString HResultToMessage(HRESULT errorCode);
+
+/*
+how it works:
+
+client code inherits CProgressThreadVirt and calls
+CProgressThreadVirt::Create()
+{
+ it creates new thread that calls CProgressThreadVirt::Process();
+ it creates modal progress dialog window with ProgressDialog.Create()
+}
+
+CProgressThreadVirt::Process()
+{
+ {
+ Result = ProcessVirt(); // virtual function that must implement real work
+ }
+ if (exceptions) or FinalMessage.ErrorMessage.Message
+ {
+ set message to ProgressDialog.Sync.FinalMessage.ErrorMessage.Message
+ }
+ else if (FinalMessage.OkMessage.Message)
+ {
+ set message to ProgressDialog.Sync.FinalMessage.OkMessage
+ }
+
+ PostMsg(kCloseMessage);
+}
+
+
+CProgressDialog::OnExternalCloseMessage()
+{
+ if (ProgressDialog.Sync.FinalMessage)
+ {
+ WorkWasFinishedVirt();
+ Show (ProgressDialog.Sync.FinalMessage)
+ MessagesDisplayed = true;
+ }
+}
+
+*/
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2.rc b/CPP/7zip/UI/FileManager/ProgressDialog2.rc
index 535a008..4d0e0c7 100644
--- a/CPP/7zip/UI/FileManager/ProgressDialog2.rc
+++ b/CPP/7zip/UI/FileManager/ProgressDialog2.rc
@@ -1,40 +1,40 @@
-#include "ProgressDialog2Res.h"
-#include "../../GuiCommon.rc"
-
-#undef DIALOG_ID
-#define DIALOG_ID IDD_PROGRESS
-#define xc 360
-#define k 11
-#define z1s 16
-
-#include "ProgressDialog2a.rc"
-
-#ifdef UNDER_CE
-
-#include "../../GuiCommon.rc"
-
-
-#undef DIALOG_ID
-#undef m
-#undef k
-#undef z1s
-
-#define DIALOG_ID IDD_PROGRESS_2
-#define m 4
-#define k 8
-#define z1s 12
-
-#define xc 280
-
-#include "ProgressDialog2a.rc"
-
-#endif
-
-STRINGTABLE DISCARDABLE
-{
- IDS_PROGRESS_PAUSED "Paused"
- IDS_PROGRESS_FOREGROUND "&Foreground"
- IDS_CONTINUE "&Continue"
- IDS_PROGRESS_ASK_CANCEL "Are you sure you want to cancel?"
- IDS_CLOSE "&Close"
-}
+#include "ProgressDialog2Res.h"
+#include "../../GuiCommon.rc"
+
+#undef DIALOG_ID
+#define DIALOG_ID IDD_PROGRESS
+#define xc 360
+#define k 11
+#define z1s 16
+
+#include "ProgressDialog2a.rc"
+
+#ifdef UNDER_CE
+
+#include "../../GuiCommon.rc"
+
+
+#undef DIALOG_ID
+#undef m
+#undef k
+#undef z1s
+
+#define DIALOG_ID IDD_PROGRESS_2
+#define m 4
+#define k 8
+#define z1s 12
+
+#define xc 280
+
+#include "ProgressDialog2a.rc"
+
+#endif
+
+STRINGTABLE DISCARDABLE
+{
+ IDS_PROGRESS_PAUSED "Paused"
+ IDS_PROGRESS_FOREGROUND "&Foreground"
+ IDS_CONTINUE "&Continue"
+ IDS_PROGRESS_ASK_CANCEL "Are you sure you want to cancel?"
+ IDS_CLOSE "&Close"
+}
diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2Res.h b/CPP/7zip/UI/FileManager/ProgressDialog2Res.h
index 54f02f0..736c717 100644
--- a/CPP/7zip/UI/FileManager/ProgressDialog2Res.h
+++ b/CPP/7zip/UI/FileManager/ProgressDialog2Res.h
@@ -1,48 +1,49 @@
-#define IDD_PROGRESS 97
-#define IDD_PROGRESS_2 10097
-
-#define IDS_CLOSE 408
-#define IDS_CONTINUE 411
-
-#define IDB_PROGRESS_BACKGROUND 444
-#define IDS_PROGRESS_FOREGROUND 445
-#define IDB_PAUSE 446
-#define IDS_PROGRESS_PAUSED 447
-#define IDS_PROGRESS_ASK_CANCEL 448
-
-#define IDT_PROGRESS_PACKED 1008
-#define IDT_PROGRESS_FILES 1032
-
-#define IDT_PROGRESS_ELAPSED 3900
-#define IDT_PROGRESS_REMAINING 3901
-#define IDT_PROGRESS_TOTAL 3902
-#define IDT_PROGRESS_SPEED 3903
-#define IDT_PROGRESS_PROCESSED 3904
-#define IDT_PROGRESS_RATIO 3905
-#define IDT_PROGRESS_ERRORS 3906
-
-#define IDC_PROGRESS1 100
-#define IDL_PROGRESS_MESSAGES 101
-#define IDT_PROGRESS_FILE_NAME 102
-#define IDT_PROGRESS_STATUS 103
-
-#define IDT_PROGRESS_PACKED_VAL 110
-#define IDT_PROGRESS_FILES_VAL 111
-
-#define IDT_PROGRESS_ELAPSED_VAL 120
-#define IDT_PROGRESS_REMAINING_VAL 121
-#define IDT_PROGRESS_TOTAL_VAL 122
-#define IDT_PROGRESS_SPEED_VAL 123
-#define IDT_PROGRESS_PROCESSED_VAL 124
-#define IDT_PROGRESS_RATIO_VAL 125
-#define IDT_PROGRESS_ERRORS_VAL 126
-
-
-#ifdef UNDER_CE
-#define MY_PROGRESS_VAL_UNITS 44
-#else
-#define MY_PROGRESS_VAL_UNITS 76
-#endif
-#define MY_PROGRESS_LABEL_UNITS_MIN 60
-#define MY_PROGRESS_LABEL_UNITS_START 90
-#define MY_PROGRESS_PAD_UNITS 4
+#define IDD_PROGRESS 97
+#define IDD_PROGRESS_2 10097
+
+#define IDS_CLOSE 408
+#define IDS_CONTINUE 411
+
+#define IDB_PROGRESS_BACKGROUND 444
+#define IDS_PROGRESS_FOREGROUND 445
+#define IDB_PAUSE 446
+#define IDS_PROGRESS_PAUSED 447
+#define IDS_PROGRESS_ASK_CANCEL 448
+
+#define IDT_PROGRESS_PACKED 1008
+#define IDT_PROGRESS_FILES 1032
+
+#define IDT_PROGRESS_ELAPSED 3900
+#define IDT_PROGRESS_REMAINING 3901
+#define IDT_PROGRESS_TOTAL 3902
+#define IDT_PROGRESS_SPEED 3903
+#define IDT_PROGRESS_PROCESSED 3904
+#define IDT_PROGRESS_RATIO 3905
+#define IDT_PROGRESS_ERRORS 3906
+
+#define IDC_PROGRESS1 100
+#define IDL_PROGRESS_MESSAGES 101
+#define IDT_PROGRESS_FILE_NAME 102
+#define IDT_PROGRESS_STATUS 103
+
+#define IDT_PROGRESS_PACKED_VAL 110
+#define IDT_PROGRESS_FILES_VAL 111
+#define IDT_PROGRESS_FILES_TOTAL 112
+
+#define IDT_PROGRESS_ELAPSED_VAL 120
+#define IDT_PROGRESS_REMAINING_VAL 121
+#define IDT_PROGRESS_TOTAL_VAL 122
+#define IDT_PROGRESS_SPEED_VAL 123
+#define IDT_PROGRESS_PROCESSED_VAL 124
+#define IDT_PROGRESS_RATIO_VAL 125
+#define IDT_PROGRESS_ERRORS_VAL 126
+
+
+#ifdef UNDER_CE
+#define MY_PROGRESS_VAL_UNITS 44
+#else
+#define MY_PROGRESS_VAL_UNITS 72
+#endif
+#define MY_PROGRESS_LABEL_UNITS_MIN 60
+#define MY_PROGRESS_LABEL_UNITS_START 90
+#define MY_PROGRESS_PAD_UNITS 4
diff --git a/CPP/7zip/UI/FileManager/ProgressDialog2a.rc b/CPP/7zip/UI/FileManager/ProgressDialog2a.rc
index f1daec7..dc7d797 100644
--- a/CPP/7zip/UI/FileManager/ProgressDialog2a.rc
+++ b/CPP/7zip/UI/FileManager/ProgressDialog2a.rc
@@ -1,80 +1,85 @@
-#undef bxs
-#define bxs 80
-
-#define x0s MY_PROGRESS_LABEL_UNITS_START
-#define x1s MY_PROGRESS_VAL_UNITS
-#define x2s MY_PROGRESS_LABEL_UNITS_START
-#define x3s MY_PROGRESS_VAL_UNITS
-
-#define x1 (m + x0s)
-#define x3 (xs - m - x3s)
-#define x2 (x3 - x2s)
-
-#undef y0
-#undef y1
-#undef y2
-#undef y3
-#undef y4
-
-#undef z0
-#undef z1
-#undef z2
-#undef z3
-
-#define y0 m
-#define y1 (y0 + k)
-#define y2 (y1 + k)
-#define y3 (y2 + k)
-#define y4 (y3 + k)
-
-#define z3 (y4 + k + 1)
-
-#define z2 (z3 + k + 1)
-#define z2s 24
-
-#define z1 (z2 + z2s)
-
-#define z0 (z1 + z1s + m)
-#define z0s 48
-
-#define yc (z0 + z0s + bys)
-
-
-DIALOG_ID DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT
-CAPTION "Progress"
-{
- DEFPUSHBUTTON "&Background", IDB_PROGRESS_BACKGROUND, bx3, by, bxs, bys
- PUSHBUTTON "&Pause", IDB_PAUSE bx2, by, bxs, bys
- PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys
-
- LTEXT "Elapsed time:", IDT_PROGRESS_ELAPSED, m, y0, x0s, 8
- LTEXT "Remaining time:", IDT_PROGRESS_REMAINING, m, y1, x0s, 8
- LTEXT "Files:", IDT_PROGRESS_FILES, m, y2, x0s, 8
- LTEXT "Compression ratio:", IDT_PROGRESS_RATIO, m, y3, x0s, 8
- LTEXT "Errors:", IDT_PROGRESS_ERRORS, m, y4, x0s, 8
-
- LTEXT "Total size:", IDT_PROGRESS_TOTAL, x2, y0, x2s, 8
- LTEXT "Speed:", IDT_PROGRESS_SPEED, x2, y1, x2s, 8
- LTEXT "Processed:", IDT_PROGRESS_PROCESSED,x2, y2, x2s, 8
- LTEXT "Compressed size:" , IDT_PROGRESS_PACKED, x2, y3, x2s, 8
-
- RTEXT "", IDT_PROGRESS_ELAPSED_VAL, x1, y0, x1s, MY_TEXT_NOPREFIX
- RTEXT "", IDT_PROGRESS_REMAINING_VAL, x1, y1, x1s, MY_TEXT_NOPREFIX
- RTEXT "", IDT_PROGRESS_FILES_VAL, x1, y2, x1s, MY_TEXT_NOPREFIX
- RTEXT "", IDT_PROGRESS_RATIO_VAL, x1, y3, x1s, MY_TEXT_NOPREFIX
- RTEXT "", IDT_PROGRESS_ERRORS_VAL, x1, y4, x1s, MY_TEXT_NOPREFIX
-
- RTEXT "", IDT_PROGRESS_TOTAL_VAL, x3, y0, x3s, MY_TEXT_NOPREFIX
- RTEXT "", IDT_PROGRESS_SPEED_VAL, x3, y1, x3s, MY_TEXT_NOPREFIX
- RTEXT "", IDT_PROGRESS_PROCESSED_VAL, x3, y2, x3s, MY_TEXT_NOPREFIX
- RTEXT "", IDT_PROGRESS_PACKED_VAL, x3, y3, x3s, MY_TEXT_NOPREFIX
-
- LTEXT "", IDT_PROGRESS_STATUS, m, z3, xc, MY_TEXT_NOPREFIX
- CONTROL "", IDT_PROGRESS_FILE_NAME, "Static", SS_NOPREFIX | SS_LEFTNOWORDWRAP, m, z2, xc, z2s
-
- CONTROL "Progress1", IDC_PROGRESS1, "msctls_progress32", PBS_SMOOTH | WS_BORDER, m, z1, xc, z1s
-
- CONTROL "List1", IDL_PROGRESS_MESSAGES, "SysListView32",
- LVS_REPORT | LVS_SHOWSELALWAYS | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,
- m, z0, xc, z0s
-}
+#undef bxs
+#define bxs 80
+
+#define x0s MY_PROGRESS_LABEL_UNITS_START
+#define x1s MY_PROGRESS_VAL_UNITS
+#define x2s MY_PROGRESS_LABEL_UNITS_START
+#define x3s MY_PROGRESS_VAL_UNITS
+
+#define x1 (m + x0s)
+#define x3 (xs - m - x3s)
+#define x2 (x3 - x2s)
+
+#undef y0
+#undef y1
+#undef y2
+#undef y3
+#undef y4
+
+#undef z0
+#undef z1
+#undef z2
+#undef z3
+
+#define y0 m
+#define y1 (y0 + k)
+#define y2 (y1 + k)
+#define y3 (y2 + k)
+#define y4 (y3 + k)
+
+#define z3 (y4 + k + 1)
+
+#define z2 (z3 + k + 1)
+#define z2s 24
+
+#define z1 (z2 + z2s)
+
+#define z0 (z1 + z1s + m)
+#define z0s 48
+
+#define yc (z0 + z0s + bys)
+
+
+DIALOG_ID DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT
+CAPTION "Progress"
+{
+ DEFPUSHBUTTON "&Background", IDB_PROGRESS_BACKGROUND, bx3, by, bxs, bys
+ PUSHBUTTON "&Pause", IDB_PAUSE, bx2, by, bxs, bys
+ PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys
+
+
+ LTEXT "Elapsed time:", IDT_PROGRESS_ELAPSED, m, y0, x0s, 8
+ LTEXT "Remaining time:", IDT_PROGRESS_REMAINING, m, y1, x0s, 8
+ LTEXT "Files:", IDT_PROGRESS_FILES, m, y2, x0s, 8
+
+ LTEXT "Errors:", IDT_PROGRESS_ERRORS, m, y4, x0s, 8
+
+
+ LTEXT "Total size:", IDT_PROGRESS_TOTAL, x2, y0, x2s, 8
+ LTEXT "Speed:", IDT_PROGRESS_SPEED, x2, y1, x2s, 8
+ LTEXT "Processed:", IDT_PROGRESS_PROCESSED,x2, y2, x2s, 8
+ LTEXT "Compressed size:" , IDT_PROGRESS_PACKED, x2, y3, x2s, 8
+ LTEXT "Compression ratio:", IDT_PROGRESS_RATIO, x2, y4, x2s, 8
+
+
+ RTEXT "", IDT_PROGRESS_ELAPSED_VAL, x1, y0, x1s, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_PROGRESS_REMAINING_VAL, x1, y1, x1s, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_PROGRESS_FILES_VAL, x1, y2, x1s, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_PROGRESS_FILES_TOTAL, x1, y3, x1s, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_PROGRESS_ERRORS_VAL, x1, y4, x1s, MY_TEXT_NOPREFIX
+
+ RTEXT "", IDT_PROGRESS_TOTAL_VAL, x3, y0, x3s, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_PROGRESS_SPEED_VAL, x3, y1, x3s, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_PROGRESS_PROCESSED_VAL, x3, y2, x3s, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_PROGRESS_PACKED_VAL, x3, y3, x3s, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_PROGRESS_RATIO_VAL, x3, y4, x3s, MY_TEXT_NOPREFIX
+
+ LTEXT "", IDT_PROGRESS_STATUS, m, z3, xc, MY_TEXT_NOPREFIX
+ CONTROL "", IDT_PROGRESS_FILE_NAME, "Static", SS_NOPREFIX | SS_LEFTNOWORDWRAP, m, z2, xc, z2s
+
+ CONTROL "Progress1", IDC_PROGRESS1, "msctls_progress32", PBS_SMOOTH | WS_BORDER, m, z1, xc, z1s
+
+ CONTROL "List1", IDL_PROGRESS_MESSAGES, "SysListView32",
+ LVS_REPORT | LVS_SHOWSELALWAYS | LVS_NOCOLUMNHEADER | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,
+ m, z0, xc, z0s
+}
diff --git a/CPP/7zip/UI/FileManager/ProgressDialogRes.h b/CPP/7zip/UI/FileManager/ProgressDialogRes.h
index a281418..cbf3beb 100644
--- a/CPP/7zip/UI/FileManager/ProgressDialogRes.h
+++ b/CPP/7zip/UI/FileManager/ProgressDialogRes.h
@@ -1,3 +1,3 @@
-#define IDD_PROGRESS 97
-
-#define IDC_PROGRESS1 100
+#define IDD_PROGRESS 97
+
+#define IDC_PROGRESS1 100
diff --git a/CPP/7zip/UI/FileManager/PropertyName.cpp b/CPP/7zip/UI/FileManager/PropertyName.cpp
index a955241..838b6e3 100644
--- a/CPP/7zip/UI/FileManager/PropertyName.cpp
+++ b/CPP/7zip/UI/FileManager/PropertyName.cpp
@@ -1,23 +1,23 @@
-// PropertyName.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/IntToString.h"
-
-#include "LangUtils.h"
-#include "PropertyName.h"
-
-UString GetNameOfProperty(PROPID propID, const wchar_t *name)
-{
- if (propID < 1000)
- {
- UString s = LangString(1000 + propID);
- if (!s.IsEmpty())
- return s;
- }
- if (name)
- return name;
- wchar_t temp[16];
- ConvertUInt32ToString(propID, temp);
- return temp;
-}
+// PropertyName.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+
+#include "LangUtils.h"
+#include "PropertyName.h"
+
+UString GetNameOfProperty(PROPID propID, const wchar_t *name)
+{
+ if (propID < 1000)
+ {
+ UString s = LangString(1000 + propID);
+ if (!s.IsEmpty())
+ return s;
+ }
+ if (name)
+ return name;
+ wchar_t temp[16];
+ ConvertUInt32ToString(propID, temp);
+ return temp;
+}
diff --git a/CPP/7zip/UI/FileManager/PropertyName.h b/CPP/7zip/UI/FileManager/PropertyName.h
index a1061b7..fa6e5c5 100644
--- a/CPP/7zip/UI/FileManager/PropertyName.h
+++ b/CPP/7zip/UI/FileManager/PropertyName.h
@@ -1,10 +1,10 @@
-// PropertyName.h
-
-#ifndef __PROPERTY_NAME_H
-#define __PROPERTY_NAME_H
-
-#include "../../../Common/MyString.h"
-
-UString GetNameOfProperty(PROPID propID, const wchar_t *name);
-
-#endif
+// PropertyName.h
+
+#ifndef ZIP7_INC_PROPERTY_NAME_H
+#define ZIP7_INC_PROPERTY_NAME_H
+
+#include "../../../Common/MyString.h"
+
+UString GetNameOfProperty(PROPID propID, const wchar_t *name);
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/PropertyName.rc b/CPP/7zip/UI/FileManager/PropertyName.rc
new file mode 100644
index 0000000..618875b
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/PropertyName.rc
@@ -0,0 +1,109 @@
+#include "PropertyNameRes.h"
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+STRINGTABLE
+BEGIN
+ IDS_PROP_PATH "Path"
+ IDS_PROP_NAME "Name"
+ IDS_PROP_EXTENSION "Extension"
+ IDS_PROP_IS_FOLDER "Folder"
+ IDS_PROP_SIZE "Size"
+ IDS_PROP_PACKED_SIZE "Packed Size"
+ IDS_PROP_ATTRIBUTES "Attributes"
+ IDS_PROP_CTIME "Created"
+ IDS_PROP_ATIME "Accessed"
+ IDS_PROP_MTIME "Modified"
+ IDS_PROP_SOLID "Solid"
+ IDS_PROP_C0MMENTED "Commented"
+ IDS_PROP_ENCRYPTED "Encrypted"
+ IDS_PROP_SPLIT_BEFORE "Split Before"
+ IDS_PROP_SPLIT_AFTER "Split After"
+ IDS_PROP_DICTIONARY_SIZE "Dictionary"
+ IDS_PROP_CRC "CRC"
+ IDS_PROP_FILE_TYPE "Type"
+ IDS_PROP_ANTI "Anti"
+ IDS_PROP_METHOD "Method"
+ IDS_PROP_HOST_OS "Host OS"
+ IDS_PROP_FILE_SYSTEM "File System"
+ IDS_PROP_USER "User"
+ IDS_PROP_GROUP "Group"
+ IDS_PROP_BLOCK "Block"
+ IDS_PROP_COMMENT "Comment"
+ IDS_PROP_POSITION "Position"
+ IDS_PROP_PREFIX "Path Prefix"
+ IDS_PROP_FOLDERS "Folders"
+ IDS_PROP_FILES "Files"
+ IDS_PROP_VERSION "Version"
+ IDS_PROP_VOLUME "Volume"
+ IDS_PROP_IS_VOLUME "Multivolume"
+ IDS_PROP_OFFSET "Offset"
+ IDS_PROP_LINKS "Links"
+ IDS_PROP_NUM_BLOCKS "Blocks"
+ IDS_PROP_NUM_VOLUMES "Volumes"
+
+ IDS_PROP_BIT64 "64-bit"
+ IDS_PROP_BIG_ENDIAN "Big-endian"
+ IDS_PROP_CPU "CPU"
+ IDS_PROP_PHY_SIZE "Physical Size"
+ IDS_PROP_HEADERS_SIZE "Headers Size"
+ IDS_PROP_CHECKSUM "Checksum"
+ IDS_PROP_CHARACTS "Characteristics"
+ IDS_PROP_VA "Virtual Address"
+ IDS_PROP_ID "ID"
+ IDS_PROP_SHORT_NAME "Short Name"
+ IDS_PROP_CREATOR_APP "Creator Application"
+ IDS_PROP_SECTOR_SIZE "Sector Size"
+ IDS_PROP_POSIX_ATTRIB "Mode"
+ IDS_PROP_SYM_LINK "Symbolic Link"
+ IDS_PROP_ERROR "Error"
+ IDS_PROP_TOTAL_SIZE "Total Size"
+ IDS_PROP_FREE_SPACE "Free Space"
+ IDS_PROP_CLUSTER_SIZE "Cluster Size"
+ IDS_PROP_VOLUME_NAME "Label"
+ IDS_PROP_LOCAL_NAME "Local Name"
+ IDS_PROP_PROVIDER "Provider"
+ IDS_PROP_NT_SECURITY "NT Security"
+ IDS_PROP_ALT_STREAM "Alternate Stream"
+ IDS_PROP_AUX "Aux"
+ IDS_PROP_DELETED "Deleted"
+ IDS_PROP_IS_TREE "Is Tree"
+ IDS_PROP_SHA1 "SHA-1"
+ IDS_PROP_SHA256 "SHA-256"
+ IDS_PROP_ERROR_TYPE "Error Type"
+ IDS_PROP_NUM_ERRORS "Errors"
+ IDS_PROP_ERROR_FLAGS "Errors"
+ IDS_PROP_WARNING_FLAGS "Warnings"
+ IDS_PROP_WARNING "Warning"
+ IDS_PROP_NUM_STREAMS "Streams"
+ IDS_PROP_NUM_ALT_STREAMS "Alternate Streams"
+ IDS_PROP_ALT_STREAMS_SIZE "Alternate Streams Size"
+ IDS_PROP_VIRTUAL_SIZE "Virtual Size"
+ IDS_PROP_UNPACK_SIZE "Unpack Size"
+ IDS_PROP_TOTAL_PHY_SIZE "Total Physical Size"
+ IDS_PROP_VOLUME_INDEX "Volume Index"
+ IDS_PROP_SUBTYPE "SubType"
+ IDS_PROP_SHORT_COMMENT "Short Comment"
+ IDS_PROP_CODE_PAGE "Code Page"
+ IDS_PROP_IS_NOT_ARC_TYPE "Is not archive type"
+ IDS_PROP_PHY_SIZE_CANT_BE_DETECTED "Physical Size can't be detected"
+ IDS_PROP_ZEROS_TAIL_IS_ALLOWED "Zeros Tail Is Allowed"
+ IDS_PROP_TAIL_SIZE "Tail Size"
+ IDS_PROP_EMB_STUB_SIZE "Embedded Stub Size"
+ IDS_PROP_NT_REPARSE "Link"
+ IDS_PROP_HARD_LINK "Hard Link"
+ IDS_PROP_INODE "iNode"
+ IDS_PROP_STREAM_ID "Stream ID"
+ IDS_PROP_READ_ONLY "Read-only"
+ IDS_PROP_OUT_NAME "Out Name"
+ IDS_PROP_COPY_LINK "Copy Link"
+ IDS_PROP_ARC_FILE_NAME "ArcFileName"
+ IDS_PROP_IS_HASH "IsHash"
+ IDS_PROP_CHANGE_TIME "Metadata Changed"
+ IDS_PROP_USER_ID "User ID"
+ IDS_PROP_GROUP_ID "Group ID"
+ IDS_PROP_DEVICE_MAJOR "Device Major"
+ IDS_PROP_DEVICE_MINOR "Device Minor"
+ IDS_PROP_DEV_MAJOR "Dev Major"
+ IDS_PROP_DEV_MINOR "Dev Minor"
+END
diff --git a/CPP/7zip/UI/FileManager/PropertyNameRes.h b/CPP/7zip/UI/FileManager/PropertyNameRes.h
index 1315b89..913887e 100644
--- a/CPP/7zip/UI/FileManager/PropertyNameRes.h
+++ b/CPP/7zip/UI/FileManager/PropertyNameRes.h
@@ -1,95 +1,104 @@
-
-
-#define IDS_PROP_PATH 1003
-#define IDS_PROP_NAME 1004
-#define IDS_PROP_EXTENSION 1005
-#define IDS_PROP_IS_FOLDER 1006
-#define IDS_PROP_SIZE 1007
-#define IDS_PROP_PACKED_SIZE 1008
-#define IDS_PROP_ATTRIBUTES 1009
-#define IDS_PROP_CTIME 1010
-#define IDS_PROP_ATIME 1011
-#define IDS_PROP_MTIME 1012
-#define IDS_PROP_SOLID 1013
-#define IDS_PROP_C0MMENTED 1014
-#define IDS_PROP_ENCRYPTED 1015
-#define IDS_PROP_SPLIT_BEFORE 1016
-#define IDS_PROP_SPLIT_AFTER 1017
-#define IDS_PROP_DICTIONARY_SIZE 1018
-#define IDS_PROP_CRC 1019
-#define IDS_PROP_FILE_TYPE 1020
-#define IDS_PROP_ANTI 1021
-#define IDS_PROP_METHOD 1022
-#define IDS_PROP_HOST_OS 1023
-#define IDS_PROP_FILE_SYSTEM 1024
-#define IDS_PROP_USER 1025
-#define IDS_PROP_GROUP 1026
-#define IDS_PROP_BLOCK 1027
-#define IDS_PROP_COMMENT 1028
-#define IDS_PROP_POSITION 1029
-#define IDS_PROP_PREFIX 1030
-#define IDS_PROP_FOLDERS 1031
-#define IDS_PROP_FILES 1032
-#define IDS_PROP_VERSION 1033
-#define IDS_PROP_VOLUME 1034
-#define IDS_PROP_IS_VOLUME 1035
-#define IDS_PROP_OFFSET 1036
-#define IDS_PROP_LINKS 1037
-#define IDS_PROP_NUM_BLOCKS 1038
-#define IDS_PROP_NUM_VOLUMES 1039
-
-#define IDS_PROP_BIT64 1041
-#define IDS_PROP_BIG_ENDIAN 1042
-#define IDS_PROP_CPU 1043
-#define IDS_PROP_PHY_SIZE 1044
-#define IDS_PROP_HEADERS_SIZE 1045
-#define IDS_PROP_CHECKSUM 1046
-#define IDS_PROP_CHARACTS 1047
-#define IDS_PROP_VA 1048
-#define IDS_PROP_ID 1049
-#define IDS_PROP_SHORT_NAME 1050
-#define IDS_PROP_CREATOR_APP 1051
-#define IDS_PROP_SECTOR_SIZE 1052
-#define IDS_PROP_POSIX_ATTRIB 1053
-#define IDS_PROP_SYM_LINK 1054
-#define IDS_PROP_ERROR 1055
-#define IDS_PROP_TOTAL_SIZE 1056
-#define IDS_PROP_FREE_SPACE 1057
-#define IDS_PROP_CLUSTER_SIZE 1058
-#define IDS_PROP_VOLUME_NAME 1059
-#define IDS_PROP_LOCAL_NAME 1060
-#define IDS_PROP_PROVIDER 1061
-#define IDS_PROP_NT_SECURITY 1062
-#define IDS_PROP_ALT_STREAM 1063
-#define IDS_PROP_AUX 1064
-#define IDS_PROP_DELETED 1065
-#define IDS_PROP_IS_TREE 1066
-#define IDS_PROP_SHA1 1067
-#define IDS_PROP_SHA256 1068
-#define IDS_PROP_ERROR_TYPE 1069
-#define IDS_PROP_NUM_ERRORS 1070
-#define IDS_PROP_ERROR_FLAGS 1071
-#define IDS_PROP_WARNING_FLAGS 1072
-#define IDS_PROP_WARNING 1073
-#define IDS_PROP_NUM_STREAMS 1074
-#define IDS_PROP_NUM_ALT_STREAMS 1075
-#define IDS_PROP_ALT_STREAMS_SIZE 1076
-#define IDS_PROP_VIRTUAL_SIZE 1077
-#define IDS_PROP_UNPACK_SIZE 1078
-#define IDS_PROP_TOTAL_PHY_SIZE 1079
-#define IDS_PROP_VOLUME_INDEX 1080
-#define IDS_PROP_SUBTYPE 1081
-#define IDS_PROP_SHORT_COMMENT 1082
-#define IDS_PROP_CODE_PAGE 1083
-#define IDS_PROP_IS_NOT_ARC_TYPE 1084
-#define IDS_PROP_PHY_SIZE_CANT_BE_DETECTED 1085
-#define IDS_PROP_ZEROS_TAIL_IS_ALLOWED 1086
-#define IDS_PROP_TAIL_SIZE 1087
-#define IDS_PROP_EMB_STUB_SIZE 1088
-#define IDS_PROP_NT_REPARSE 1089
-#define IDS_PROP_HARD_LINK 1090
-#define IDS_PROP_INODE 1091
-#define IDS_PROP_STREAM_ID 1092
-#define IDS_PROP_READ_ONLY 1093
-#define IDS_PROP_OUT_NAME 1094
-#define IDS_PROP_COPY_LINK 1095
+
+
+#define IDS_PROP_PATH 1003
+#define IDS_PROP_NAME 1004
+#define IDS_PROP_EXTENSION 1005
+#define IDS_PROP_IS_FOLDER 1006
+#define IDS_PROP_SIZE 1007
+#define IDS_PROP_PACKED_SIZE 1008
+#define IDS_PROP_ATTRIBUTES 1009
+#define IDS_PROP_CTIME 1010
+#define IDS_PROP_ATIME 1011
+#define IDS_PROP_MTIME 1012
+#define IDS_PROP_SOLID 1013
+#define IDS_PROP_C0MMENTED 1014
+#define IDS_PROP_ENCRYPTED 1015
+#define IDS_PROP_SPLIT_BEFORE 1016
+#define IDS_PROP_SPLIT_AFTER 1017
+#define IDS_PROP_DICTIONARY_SIZE 1018
+#define IDS_PROP_CRC 1019
+#define IDS_PROP_FILE_TYPE 1020
+#define IDS_PROP_ANTI 1021
+#define IDS_PROP_METHOD 1022
+#define IDS_PROP_HOST_OS 1023
+#define IDS_PROP_FILE_SYSTEM 1024
+#define IDS_PROP_USER 1025
+#define IDS_PROP_GROUP 1026
+#define IDS_PROP_BLOCK 1027
+#define IDS_PROP_COMMENT 1028
+#define IDS_PROP_POSITION 1029
+#define IDS_PROP_PREFIX 1030
+#define IDS_PROP_FOLDERS 1031
+#define IDS_PROP_FILES 1032
+#define IDS_PROP_VERSION 1033
+#define IDS_PROP_VOLUME 1034
+#define IDS_PROP_IS_VOLUME 1035
+#define IDS_PROP_OFFSET 1036
+#define IDS_PROP_LINKS 1037
+#define IDS_PROP_NUM_BLOCKS 1038
+#define IDS_PROP_NUM_VOLUMES 1039
+
+#define IDS_PROP_BIT64 1041
+#define IDS_PROP_BIG_ENDIAN 1042
+#define IDS_PROP_CPU 1043
+#define IDS_PROP_PHY_SIZE 1044
+#define IDS_PROP_HEADERS_SIZE 1045
+#define IDS_PROP_CHECKSUM 1046
+#define IDS_PROP_CHARACTS 1047
+#define IDS_PROP_VA 1048
+#define IDS_PROP_ID 1049
+#define IDS_PROP_SHORT_NAME 1050
+#define IDS_PROP_CREATOR_APP 1051
+#define IDS_PROP_SECTOR_SIZE 1052
+#define IDS_PROP_POSIX_ATTRIB 1053
+#define IDS_PROP_SYM_LINK 1054
+#define IDS_PROP_ERROR 1055
+#define IDS_PROP_TOTAL_SIZE 1056
+#define IDS_PROP_FREE_SPACE 1057
+#define IDS_PROP_CLUSTER_SIZE 1058
+#define IDS_PROP_VOLUME_NAME 1059
+#define IDS_PROP_LOCAL_NAME 1060
+#define IDS_PROP_PROVIDER 1061
+#define IDS_PROP_NT_SECURITY 1062
+#define IDS_PROP_ALT_STREAM 1063
+#define IDS_PROP_AUX 1064
+#define IDS_PROP_DELETED 1065
+#define IDS_PROP_IS_TREE 1066
+#define IDS_PROP_SHA1 1067
+#define IDS_PROP_SHA256 1068
+#define IDS_PROP_ERROR_TYPE 1069
+#define IDS_PROP_NUM_ERRORS 1070
+#define IDS_PROP_ERROR_FLAGS 1071
+#define IDS_PROP_WARNING_FLAGS 1072
+#define IDS_PROP_WARNING 1073
+#define IDS_PROP_NUM_STREAMS 1074
+#define IDS_PROP_NUM_ALT_STREAMS 1075
+#define IDS_PROP_ALT_STREAMS_SIZE 1076
+#define IDS_PROP_VIRTUAL_SIZE 1077
+#define IDS_PROP_UNPACK_SIZE 1078
+#define IDS_PROP_TOTAL_PHY_SIZE 1079
+#define IDS_PROP_VOLUME_INDEX 1080
+#define IDS_PROP_SUBTYPE 1081
+#define IDS_PROP_SHORT_COMMENT 1082
+#define IDS_PROP_CODE_PAGE 1083
+#define IDS_PROP_IS_NOT_ARC_TYPE 1084
+#define IDS_PROP_PHY_SIZE_CANT_BE_DETECTED 1085
+#define IDS_PROP_ZEROS_TAIL_IS_ALLOWED 1086
+#define IDS_PROP_TAIL_SIZE 1087
+#define IDS_PROP_EMB_STUB_SIZE 1088
+#define IDS_PROP_NT_REPARSE 1089
+#define IDS_PROP_HARD_LINK 1090
+#define IDS_PROP_INODE 1091
+#define IDS_PROP_STREAM_ID 1092
+#define IDS_PROP_READ_ONLY 1093
+#define IDS_PROP_OUT_NAME 1094
+#define IDS_PROP_COPY_LINK 1095
+#define IDS_PROP_ARC_FILE_NAME 1096
+#define IDS_PROP_IS_HASH 1097
+#define IDS_PROP_CHANGE_TIME 1098
+#define IDS_PROP_USER_ID 1099
+#define IDS_PROP_GROUP_ID 1100
+#define IDS_PROP_DEVICE_MAJOR 1101
+#define IDS_PROP_DEVICE_MINOR 1102
+#define IDS_PROP_DEV_MAJOR 1103
+#define IDS_PROP_DEV_MINOR 1104
diff --git a/CPP/7zip/UI/FileManager/RegistryAssociations.cpp b/CPP/7zip/UI/FileManager/RegistryAssociations.cpp
new file mode 100644
index 0000000..16e4675
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/RegistryAssociations.cpp
@@ -0,0 +1,167 @@
+// RegistryAssociations.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../../Windows/Registry.h"
+
+#include "RegistryAssociations.h"
+
+using namespace NWindows;
+using namespace NRegistry;
+
+namespace NRegistryAssoc {
+
+// static NSynchronization::CCriticalSection g_CriticalSection;
+
+static const TCHAR * const kClasses = TEXT("Software\\Classes\\");
+// static const TCHAR * const kShellNewKeyName = TEXT("ShellNew");
+// static const TCHAR * const kShellNewDataValueName = TEXT("Data");
+static const TCHAR * const kDefaultIconKeyName = TEXT("DefaultIcon");
+static const TCHAR * const kShellKeyName = TEXT("shell");
+static const TCHAR * const kOpenKeyName = TEXT("open");
+static const TCHAR * const kCommandKeyName = TEXT("command");
+static const char * const k7zipPrefix = "7-Zip.";
+
+static CSysString GetExtProgramKeyName(const CSysString &ext)
+{
+ return CSysString(k7zipPrefix) + ext;
+}
+
+static CSysString GetFullKeyPath(HKEY hkey, const CSysString &name)
+{
+ CSysString s;
+ if (hkey != HKEY_CLASSES_ROOT)
+ s = kClasses;
+ return s + name;
+}
+
+static CSysString GetExtKeyPath(HKEY hkey, const CSysString &ext)
+{
+ return GetFullKeyPath(hkey, (TEXT(".")) + ext);
+}
+
+bool CShellExtInfo::ReadFromRegistry(HKEY hkey, const CSysString &ext)
+{
+ ProgramKey.Empty();
+ IconPath.Empty();
+ IconIndex = -1;
+ // NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
+ {
+ CKey extKey;
+ if (extKey.Open(hkey, GetExtKeyPath(hkey, ext), KEY_READ) != ERROR_SUCCESS)
+ return false;
+ if (extKey.QueryValue(NULL, ProgramKey) != ERROR_SUCCESS)
+ return false;
+ }
+ {
+ CKey iconKey;
+
+ if (iconKey.Open(hkey, GetFullKeyPath(hkey, ProgramKey + CSysString(CHAR_PATH_SEPARATOR) + kDefaultIconKeyName), KEY_READ) == ERROR_SUCCESS)
+ {
+ UString value;
+ if (iconKey.QueryValue(NULL, value) == ERROR_SUCCESS)
+ {
+ const int pos = value.ReverseFind(L',');
+ IconPath = value;
+ if (pos >= 0)
+ {
+ const wchar_t *end;
+ const Int32 index = ConvertStringToInt32((const wchar_t *)value + pos + 1, &end);
+ if (*end == 0)
+ {
+ // 9.31: if there is no icon index, we use -1. Is it OK?
+ if (pos != (int)value.Len() - 1)
+ IconIndex = (int)index;
+ IconPath.SetFrom(value, (unsigned)pos);
+ }
+ }
+ }
+ }
+ }
+ return true;
+}
+
+bool CShellExtInfo::IsIt7Zip() const
+{
+ return ProgramKey.IsPrefixedBy_Ascii_NoCase(k7zipPrefix);
+}
+
+LONG DeleteShellExtensionInfo(HKEY hkey, const CSysString &ext)
+{
+ // NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
+ CKey rootKey;
+ rootKey.Attach(hkey);
+ LONG res = rootKey.RecurseDeleteKey(GetExtKeyPath(hkey, ext));
+ // then we delete only 7-Zip.* key.
+ rootKey.RecurseDeleteKey(GetFullKeyPath(hkey, GetExtProgramKeyName(ext)));
+ rootKey.Detach();
+ return res;
+}
+
+LONG AddShellExtensionInfo(HKEY hkey,
+ const CSysString &ext,
+ const UString &programTitle,
+ const UString &programOpenCommand,
+ const UString &iconPath, int iconIndex
+ // , const void *shellNewData, int shellNewDataSize
+ )
+{
+ LONG res = 0;
+ DeleteShellExtensionInfo(hkey, ext);
+ // NSynchronization::CCriticalSectionLock lock(g_CriticalSection);
+ CSysString programKeyName;
+ {
+ CSysString ext2 (ext);
+ if (iconIndex < 0)
+ ext2 = "*";
+ programKeyName = GetExtProgramKeyName(ext2);
+ }
+ {
+ CKey extKey;
+ res = extKey.Create(hkey, GetExtKeyPath(hkey, ext));
+ extKey.SetValue(NULL, programKeyName);
+ /*
+ if (shellNewData != NULL)
+ {
+ CKey shellNewKey;
+ shellNewKey.Create(extKey, kShellNewKeyName);
+ shellNewKey.SetValue(kShellNewDataValueName, shellNewData, shellNewDataSize);
+ }
+ */
+ }
+ CKey programKey;
+ programKey.Create(hkey, GetFullKeyPath(hkey, programKeyName));
+ programKey.SetValue(NULL, programTitle);
+ {
+ CKey iconKey;
+ UString iconPathFull = iconPath;
+ if (iconIndex < 0)
+ iconIndex = 0;
+ // if (iconIndex >= 0)
+ {
+ iconPathFull += ',';
+ iconPathFull.Add_UInt32((UInt32)iconIndex);
+ }
+ iconKey.Create(programKey, kDefaultIconKeyName);
+ iconKey.SetValue(NULL, iconPathFull);
+ }
+
+ CKey shellKey;
+ shellKey.Create(programKey, kShellKeyName);
+ shellKey.SetValue(NULL, TEXT(""));
+
+ CKey openKey;
+ openKey.Create(shellKey, kOpenKeyName);
+ openKey.SetValue(NULL, TEXT(""));
+
+ CKey commandKey;
+ commandKey.Create(openKey, kCommandKeyName);
+ commandKey.SetValue(NULL, programOpenCommand);
+ return res;
+}
+
+}
diff --git a/CPP/7zip/UI/FileManager/RegistryAssociations.h b/CPP/7zip/UI/FileManager/RegistryAssociations.h
new file mode 100644
index 0000000..3d7b63d
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/RegistryAssociations.h
@@ -0,0 +1,31 @@
+// RegistryAssociations.h
+
+#ifndef ZIP7_INC_REGISTRY_ASSOCIATIONS_H
+#define ZIP7_INC_REGISTRY_ASSOCIATIONS_H
+
+#include "../../../Common/MyString.h"
+
+namespace NRegistryAssoc {
+
+ struct CShellExtInfo
+ {
+ CSysString ProgramKey;
+ UString IconPath;
+ int IconIndex;
+
+ bool ReadFromRegistry(HKEY hkey, const CSysString &ext);
+ bool IsIt7Zip() const;
+ };
+
+ LONG DeleteShellExtensionInfo(HKEY hkey, const CSysString &ext);
+
+ LONG AddShellExtensionInfo(HKEY hkey,
+ const CSysString &ext,
+ const UString &programTitle,
+ const UString &programOpenCommand,
+ const UString &iconPath, int iconIndex
+ // , const void *shellNewData, int shellNewDataSize
+ );
+}
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/RegistryPlugins.cpp b/CPP/7zip/UI/FileManager/RegistryPlugins.cpp
new file mode 100644
index 0000000..87e5fa1
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/RegistryPlugins.cpp
@@ -0,0 +1,145 @@
+// RegistryPlugins.cpp
+
+#include "StdAfx.h"
+
+/*
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/PropVariant.h"
+
+#include "IFolder.h"
+*/
+#include "RegistryPlugins.h"
+
+// using namespace NWindows;
+// using namespace NFile;
+
+/*
+typedef UINT32 (WINAPI * Func_GetPluginProperty)(PROPID propID, PROPVARIANT *value);
+
+static bool ReadPluginInfo(CPluginInfo &plugin, bool needCheckDll)
+{
+ if (needCheckDll)
+ {
+ NDLL::CLibrary lib;
+ if (!lib.LoadEx(plugin.FilePath, LOAD_LIBRARY_AS_DATAFILE))
+ return false;
+ }
+ NDLL::CLibrary lib;
+ if (!lib.Load(plugin.FilePath))
+ return false;
+ const
+ Func_GetPluginProperty
+ f_GetPluginProperty = ZIP7_GET_PROC_ADDRESS(
+ Func_GetPluginProperty, lib.Get_HMODULE(),
+ "GetPluginProperty");
+ if (!f_GetPluginProperty)
+ return false;
+
+ NCOM::CPropVariant prop;
+ if (f_GetPluginProperty(NPlugin::kType, &prop) != S_OK)
+ return false;
+ if (prop.vt == VT_EMPTY)
+ plugin.Type = kPluginTypeFF;
+ else if (prop.vt == VT_UI4)
+ plugin.Type = (EPluginType)prop.ulVal;
+ else
+ return false;
+ prop.Clear();
+
+ if (f_GetPluginProperty(NPlugin::kName, &prop) != S_OK)
+ return false;
+ if (prop.vt != VT_BSTR)
+ return false;
+ plugin.Name = prop.bstrVal;
+ prop.Clear();
+
+ if (f_GetPluginProperty(NPlugin::kClassID, &prop) != S_OK)
+ return false;
+ if (prop.vt == VT_EMPTY)
+ plugin.ClassID_Defined = false;
+ else if (prop.vt != VT_BSTR)
+ return false;
+ else
+ {
+ plugin.ClassID_Defined = true;
+ plugin.ClassID = *(const GUID *)(const void *)prop.bstrVal;
+ }
+ prop.Clear();
+ return true;
+*/
+
+/*
+{
+ if (f_GetPluginProperty(NPlugin::kOptionsClassID, &prop) != S_OK)
+ return false;
+ if (prop.vt == VT_EMPTY)
+ plugin.OptionsClassID_Defined = false;
+ else if (prop.vt != VT_BSTR)
+ return false;
+ else
+ {
+ plugin.OptionsClassID_Defined = true;
+ plugin.OptionsClassID = *(const GUID *)(const void *)prop.bstrVal;
+ }
+}
+*/
+
+ /*
+ {
+ // very old 7-zip used agent plugin in "7-zip.dll"
+ // but then agent code was moved to 7zfm.
+ // so now we don't need to load "7-zip.dll" here
+ CPluginInfo plugin;
+ plugin.FilePath = baseFolderPrefix + FTEXT("7-zip.dll");
+ if (::ReadPluginInfo(plugin, false))
+ if (plugin.Type == kPluginTypeFF)
+ plugins.Add(plugin);
+ }
+ */
+ /*
+ FString folderPath = NDLL::GetModuleDirPrefix();
+ folderPath += "Plugins" STRING_PATH_SEPARATOR;
+ NFind::CEnumerator enumerator;
+ enumerator.SetDirPrefix(folderPath);
+ NFind::CFileInfo fi;
+ while (enumerator.Next(fi))
+ {
+ if (fi.IsDir())
+ continue;
+ CPluginInfo plugin;
+ plugin.FilePath = folderPath + fi.Name;
+ if (::ReadPluginInfo(plugin, true))
+ if (plugin.Type == kPluginTypeFF)
+ plugins.Add(plugin);
+ }
+ */
+
+ /*
+ ReadPluginInfoList(plugins);
+ for (unsigned i = 0; i < plugins.Size();)
+ if (plugins[i].Type != kPluginTypeFF)
+ plugins.Delete(i);
+ else
+ i++;
+ */
+
+/*
+void ReadFileFolderPluginInfoList(CObjectVector<CPluginInfo> &plugins)
+{
+ plugins.Clear();
+ {
+ }
+
+ {
+ CPluginInfo &plugin = plugins.AddNew();
+ // p.FilePath.Empty();
+ plugin.Type = kPluginTypeFF;
+ plugin.Name = "7-Zip";
+ // plugin.ClassID = CLSID_CAgentArchiveHandler;
+ // plugin.ClassID_Defined = true;
+ // plugin.ClassID_Defined = false;
+ // plugin.OptionsClassID_Defined = false;
+ }
+}
+*/
diff --git a/CPP/7zip/UI/FileManager/RegistryPlugins.h b/CPP/7zip/UI/FileManager/RegistryPlugins.h
new file mode 100644
index 0000000..1cb765a
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/RegistryPlugins.h
@@ -0,0 +1,29 @@
+// RegistryPlugins.h
+
+#ifndef ZIP7_INC_REGISTRY_PLUGINS_H
+#define ZIP7_INC_REGISTRY_PLUGINS_H
+
+#include "../../../Common/MyString.h"
+
+/*
+enum EPluginType
+{
+ kPluginTypeFF = 0
+};
+
+struct CPluginInfo
+{
+ EPluginType Type;
+ // bool ClassID_Defined;
+ // bool OptionsClassID_Defined;
+ // FString FilePath;
+ // UString Name;
+ // CLSID ClassID;
+ // CLSID OptionsClassID;
+};
+
+// void ReadPluginInfoList(CObjectVector<CPluginInfo> &plugins);
+// void ReadFileFolderPluginInfoList(CObjectVector<CPluginInfo> &plugins);
+*/
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/RegistryUtils.cpp b/CPP/7zip/UI/FileManager/RegistryUtils.cpp
new file mode 100644
index 0000000..7e61998
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/RegistryUtils.cpp
@@ -0,0 +1,196 @@
+// RegistryUtils.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+
+#include "../../../Windows/Registry.h"
+
+#include "RegistryUtils.h"
+
+using namespace NWindows;
+using namespace NRegistry;
+
+#define REG_PATH_7Z TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-Zip")
+
+static LPCTSTR const kCUBasePath = REG_PATH_7Z;
+static LPCTSTR const kCU_FMPath = REG_PATH_7Z TEXT(STRING_PATH_SEPARATOR) TEXT("FM");
+// static LPCTSTR const kLM_Path = REG_PATH_7Z TEXT(STRING_PATH_SEPARATOR) TEXT("FM");
+
+static LPCWSTR const kLangValueName = L"Lang";
+
+static LPCWSTR const kViewer = L"Viewer";
+static LPCWSTR const kEditor = L"Editor";
+static LPCWSTR const kDiff = L"Diff";
+static LPCWSTR const kVerCtrlPath = L"7vc";
+
+static LPCTSTR const kShowDots = TEXT("ShowDots");
+static LPCTSTR const kShowRealFileIcons = TEXT("ShowRealFileIcons");
+static LPCTSTR const kFullRow = TEXT("FullRow");
+static LPCTSTR const kShowGrid = TEXT("ShowGrid");
+static LPCTSTR const kSingleClick = TEXT("SingleClick");
+static LPCTSTR const kAlternativeSelection = TEXT("AlternativeSelection");
+// static LPCTSTR const kUnderline = TEXT("Underline");
+
+static LPCTSTR const kShowSystemMenu = TEXT("ShowSystemMenu");
+
+// static LPCTSTR const kLockMemoryAdd = TEXT("LockMemoryAdd");
+static LPCTSTR const kLargePages = TEXT("LargePages");
+
+static LPCTSTR const kFlatViewName = TEXT("FlatViewArc");
+// static LPCTSTR const kShowDeletedFiles = TEXT("ShowDeleted");
+
+static void SaveCuString(LPCTSTR keyPath, LPCWSTR valuePath, LPCWSTR value)
+{
+ CKey key;
+ key.Create(HKEY_CURRENT_USER, keyPath);
+ key.SetValue(valuePath, value);
+}
+
+static void ReadCuString(LPCTSTR keyPath, LPCWSTR valuePath, UString &res)
+{
+ res.Empty();
+ CKey key;
+ if (key.Open(HKEY_CURRENT_USER, keyPath, KEY_READ) == ERROR_SUCCESS)
+ key.QueryValue(valuePath, res);
+}
+
+void SaveRegLang(const UString &path) { SaveCuString(kCUBasePath, kLangValueName, path); }
+void ReadRegLang(UString &path) { ReadCuString(kCUBasePath, kLangValueName, path); }
+
+void SaveRegEditor(bool useEditor, const UString &path) { SaveCuString(kCU_FMPath, useEditor ? kEditor : kViewer, path); }
+void ReadRegEditor(bool useEditor, UString &path) { ReadCuString(kCU_FMPath, useEditor ? kEditor : kViewer, path); }
+
+void SaveRegDiff(const UString &path) { SaveCuString(kCU_FMPath, kDiff, path); }
+void ReadRegDiff(UString &path) { ReadCuString(kCU_FMPath, kDiff, path); }
+
+void ReadReg_VerCtrlPath(UString &path) { ReadCuString(kCU_FMPath, kVerCtrlPath, path); }
+
+static void Save7ZipOption(LPCTSTR value, bool enabled)
+{
+ CKey key;
+ key.Create(HKEY_CURRENT_USER, kCUBasePath);
+ key.SetValue(value, enabled);
+}
+
+static void SaveOption(LPCTSTR value, bool enabled)
+{
+ CKey key;
+ key.Create(HKEY_CURRENT_USER, kCU_FMPath);
+ key.SetValue(value, enabled);
+}
+
+static bool Read7ZipOption(LPCTSTR value, bool defaultValue)
+{
+ CKey key;
+ if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) == ERROR_SUCCESS)
+ {
+ bool enabled;
+ if (key.QueryValue(value, enabled) == ERROR_SUCCESS)
+ return enabled;
+ }
+ return defaultValue;
+}
+
+static void ReadOption(CKey &key, LPCTSTR value, bool &dest)
+{
+ bool enabled = false;
+ if (key.QueryValue(value, enabled) == ERROR_SUCCESS)
+ dest = enabled;
+}
+
+/*
+static void SaveLmOption(LPCTSTR value, bool enabled)
+{
+ CKey key;
+ key.Create(HKEY_LOCAL_MACHINE, kLM_Path);
+ key.SetValue(value, enabled);
+}
+
+static bool ReadLmOption(LPCTSTR value, bool defaultValue)
+{
+ CKey key;
+ if (key.Open(HKEY_LOCAL_MACHINE, kLM_Path, KEY_READ) == ERROR_SUCCESS)
+ {
+ bool enabled;
+ if (key.QueryValue(value, enabled) == ERROR_SUCCESS)
+ return enabled;
+ }
+ return defaultValue;
+}
+*/
+
+void CFmSettings::Save() const
+{
+ SaveOption(kShowDots, ShowDots);
+ SaveOption(kShowRealFileIcons, ShowRealFileIcons);
+ SaveOption(kFullRow, FullRow);
+ SaveOption(kShowGrid, ShowGrid);
+ SaveOption(kSingleClick, SingleClick);
+ SaveOption(kAlternativeSelection, AlternativeSelection);
+ // SaveOption(kUnderline, Underline);
+
+ SaveOption(kShowSystemMenu, ShowSystemMenu);
+}
+
+void CFmSettings::Load()
+{
+ ShowDots = false;
+ ShowRealFileIcons = false;
+ /* if (FullRow == false), we can use mouse click on another columns
+ to select group of files. We need to implement additional
+ way to select files in any column as in Explorer.
+ Then we can enable (FullRow == true) default mode. */
+ // FullRow = true;
+ FullRow = false;
+ ShowGrid = false;
+ SingleClick = false;
+ AlternativeSelection = false;
+ // Underline = false;
+
+ ShowSystemMenu = false;
+
+ CKey key;
+ if (key.Open(HKEY_CURRENT_USER, kCU_FMPath, KEY_READ) == ERROR_SUCCESS)
+ {
+ ReadOption(key, kShowDots, ShowDots);
+ ReadOption(key, kShowRealFileIcons, ShowRealFileIcons);
+ ReadOption(key, kFullRow, FullRow);
+ ReadOption(key, kShowGrid, ShowGrid);
+ ReadOption(key, kSingleClick, SingleClick);
+ ReadOption(key, kAlternativeSelection, AlternativeSelection);
+ // ReadOption(key, kUnderline, Underline);
+
+ ReadOption(key, kShowSystemMenu, ShowSystemMenu );
+ }
+}
+
+
+// void SaveLockMemoryAdd(bool enable) { SaveLmOption(kLockMemoryAdd, enable); }
+// bool ReadLockMemoryAdd() { return ReadLmOption(kLockMemoryAdd, true); }
+
+void SaveLockMemoryEnable(bool enable) { Save7ZipOption(kLargePages, enable); }
+bool ReadLockMemoryEnable() { return Read7ZipOption(kLargePages, false); }
+
+static CSysString GetFlatViewName(UInt32 panelIndex)
+{
+ TCHAR panelString[16];
+ ConvertUInt32ToString(panelIndex, panelString);
+ return (CSysString)kFlatViewName + panelString;
+}
+
+void SaveFlatView(UInt32 panelIndex, bool enable) { SaveOption(GetFlatViewName(panelIndex), enable); }
+
+bool ReadFlatView(UInt32 panelIndex)
+{
+ bool enabled = false;
+ CKey key;
+ if (key.Open(HKEY_CURRENT_USER, kCU_FMPath, KEY_READ) == ERROR_SUCCESS)
+ ReadOption(key, GetFlatViewName(panelIndex), enabled);
+ return enabled;
+}
+
+/*
+void Save_ShowDeleted(bool enable) { SaveOption(kShowDeletedFiles, enable); }
+bool Read_ShowDeleted() { return ReadOption(kShowDeletedFiles, false); }
+*/
diff --git a/CPP/7zip/UI/FileManager/RegistryUtils.h b/CPP/7zip/UI/FileManager/RegistryUtils.h
new file mode 100644
index 0000000..8b4cdf0
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/RegistryUtils.h
@@ -0,0 +1,50 @@
+// RegistryUtils.h
+
+#ifndef ZIP7_INC_REGISTRY_UTILS_H
+#define ZIP7_INC_REGISTRY_UTILS_H
+
+#include "../../../Common/MyTypes.h"
+#include "../../../Common/MyString.h"
+
+void SaveRegLang(const UString &path);
+void ReadRegLang(UString &path);
+
+void SaveRegEditor(bool useEditor, const UString &path);
+void ReadRegEditor(bool useEditor, UString &path);
+
+void SaveRegDiff(const UString &path);
+void ReadRegDiff(UString &path);
+
+void ReadReg_VerCtrlPath(UString &path);
+
+struct CFmSettings
+{
+ bool ShowDots;
+ bool ShowRealFileIcons;
+ bool FullRow;
+ bool ShowGrid;
+ bool SingleClick;
+ bool AlternativeSelection;
+ // bool Underline;
+
+ bool ShowSystemMenu;
+
+ void Save() const;
+ void Load();
+};
+
+// void SaveLockMemoryAdd(bool enable);
+// bool ReadLockMemoryAdd();
+
+bool ReadLockMemoryEnable();
+void SaveLockMemoryEnable(bool enable);
+
+void SaveFlatView(UInt32 panelIndex, bool enable);
+bool ReadFlatView(UInt32 panelIndex);
+
+/*
+void Save_ShowDeleted(bool enable);
+bool Read_ShowDeleted();
+*/
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/RootFolder.cpp b/CPP/7zip/UI/FileManager/RootFolder.cpp
new file mode 100644
index 0000000..34dd638
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/RootFolder.cpp
@@ -0,0 +1,326 @@
+// RootFolder.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <shlobj.h>
+#else
+#include <ShlObj.h>
+#endif
+
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/PropVariant.h"
+
+#include "../../PropID.h"
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+#define USE_WIN_PATHS
+#endif
+
+static const unsigned kNumRootFolderItems =
+ #ifdef USE_WIN_PATHS
+ 4
+ #else
+ 1
+ #endif
+ ;
+
+
+#include "FSFolder.h"
+#include "LangUtils.h"
+#ifdef USE_WIN_PATHS
+#include "NetFolder.h"
+#include "FSDrives.h"
+#include "AltStreamsFolder.h"
+#endif
+#include "RootFolder.h"
+#include "SysIconUtils.h"
+
+#include "resource.h"
+
+using namespace NWindows;
+
+static const Byte kProps[] =
+{
+ kpidName
+};
+
+UString RootFolder_GetName_Computer(int &iconIndex);
+UString RootFolder_GetName_Computer(int &iconIndex)
+{
+ #ifdef USE_WIN_PATHS
+ iconIndex = GetIconIndexForCSIDL(CSIDL_DRIVES);
+ #else
+ GetRealIconIndex(FSTRING_PATH_SEPARATOR, FILE_ATTRIBUTE_DIRECTORY, iconIndex);
+ #endif
+ return LangString(IDS_COMPUTER);
+}
+
+UString RootFolder_GetName_Network(int &iconIndex);
+UString RootFolder_GetName_Network(int &iconIndex)
+{
+ iconIndex = GetIconIndexForCSIDL(CSIDL_NETWORK);
+ return LangString(IDS_NETWORK);
+}
+
+UString RootFolder_GetName_Documents(int &iconIndex);
+UString RootFolder_GetName_Documents(int &iconIndex)
+{
+ iconIndex = GetIconIndexForCSIDL(CSIDL_PERSONAL);
+ return LangString(IDS_DOCUMENTS);
+}
+
+enum
+{
+ ROOT_INDEX_COMPUTER = 0
+ #ifdef USE_WIN_PATHS
+ , ROOT_INDEX_DOCUMENTS
+ , ROOT_INDEX_NETWORK
+ , ROOT_INDEX_VOLUMES
+ #endif
+};
+
+#ifdef USE_WIN_PATHS
+static const char * const kVolPrefix = "\\\\.";
+#endif
+
+void CRootFolder::Init()
+{
+ _names[ROOT_INDEX_COMPUTER] = RootFolder_GetName_Computer(_iconIndices[ROOT_INDEX_COMPUTER]);
+ #ifdef USE_WIN_PATHS
+ _names[ROOT_INDEX_DOCUMENTS] = RootFolder_GetName_Documents(_iconIndices[ROOT_INDEX_DOCUMENTS]);
+ _names[ROOT_INDEX_NETWORK] = RootFolder_GetName_Network(_iconIndices[ROOT_INDEX_NETWORK]);
+ _names[ROOT_INDEX_VOLUMES] = kVolPrefix;
+ _iconIndices[ROOT_INDEX_VOLUMES] = GetIconIndexForCSIDL(CSIDL_DRIVES);
+ #endif
+}
+
+Z7_COM7F_IMF(CRootFolder::LoadItems())
+{
+ Init();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CRootFolder::GetNumberOfItems(UInt32 *numItems))
+{
+ *numItems = kNumRootFolderItems;
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CRootFolder::GetProperty(UInt32 itemIndex, PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidIsDir: prop = true; break;
+ case kpidName: prop = _names[itemIndex]; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+typedef BOOL (WINAPI *Func_SHGetSpecialFolderPathW)(HWND hwnd, LPWSTR pszPath, int csidl, BOOL fCreate);
+typedef BOOL (WINAPI *Func_SHGetSpecialFolderPathA)(HWND hwnd, LPSTR pszPath, int csidl, BOOL fCreate);
+
+static UString GetMyDocsPath()
+{
+ UString us;
+ WCHAR s[MAX_PATH + 1];
+#ifdef UNDER_CE
+ #define shell_name TEXT("coredll.dll")
+#else
+ #define shell_name TEXT("shell32.dll")
+#endif
+ Func_SHGetSpecialFolderPathW getW = Z7_GET_PROC_ADDRESS(
+ Func_SHGetSpecialFolderPathW, GetModuleHandle(shell_name),
+ "SHGetSpecialFolderPathW");
+ if (getW && getW(NULL, s, CSIDL_PERSONAL, FALSE))
+ us = s;
+ #ifndef _UNICODE
+ else
+ {
+ Func_SHGetSpecialFolderPathA getA = Z7_GET_PROC_ADDRESS(
+ Func_SHGetSpecialFolderPathA, ::GetModuleHandleA("shell32.dll"),
+ "SHGetSpecialFolderPathA");
+ CHAR s2[MAX_PATH + 1];
+ if (getA && getA(NULL, s2, CSIDL_PERSONAL, FALSE))
+ us = GetUnicodeString(s2);
+ }
+ #endif
+ NFile::NName::NormalizeDirPathPrefix(us);
+ return us;
+}
+
+Z7_COM7F_IMF(CRootFolder::BindToFolder(UInt32 index, IFolderFolder **resultFolder))
+{
+ *resultFolder = NULL;
+ CMyComPtr<IFolderFolder> subFolder;
+
+ #ifdef USE_WIN_PATHS
+ if (index == ROOT_INDEX_COMPUTER || index == ROOT_INDEX_VOLUMES)
+ {
+ CFSDrives *fsDrivesSpec = new CFSDrives;
+ subFolder = fsDrivesSpec;
+ fsDrivesSpec->Init(index == ROOT_INDEX_VOLUMES);
+ }
+ else if (index == ROOT_INDEX_NETWORK)
+ {
+ CNetFolder *netFolderSpec = new CNetFolder;
+ subFolder = netFolderSpec;
+ netFolderSpec->Init(NULL, NULL, _names[ROOT_INDEX_NETWORK] + WCHAR_PATH_SEPARATOR);
+ }
+ else if (index == ROOT_INDEX_DOCUMENTS)
+ {
+ UString s = GetMyDocsPath();
+ if (!s.IsEmpty())
+ {
+ NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder;
+ subFolder = fsFolderSpec;
+ RINOK(fsFolderSpec->Init(us2fs(s)))
+ }
+ }
+ #else
+ if (index == ROOT_INDEX_COMPUTER)
+ {
+ NFsFolder::CFSFolder *fsFolder = new NFsFolder::CFSFolder;
+ subFolder = fsFolder;
+ fsFolder->InitToRoot();
+ }
+ #endif
+ else
+ return E_INVALIDARG;
+
+ *resultFolder = subFolder.Detach();
+ return S_OK;
+}
+
+static bool AreEqualNames(const UString &path, const wchar_t *name)
+{
+ unsigned len = MyStringLen(name);
+ if (len > path.Len() || len + 1 < path.Len())
+ return false;
+ if (len + 1 == path.Len() && !IS_PATH_SEPAR(path[len]))
+ return false;
+ return path.IsPrefixedBy(name);
+}
+
+Z7_COM7F_IMF(CRootFolder::BindToFolder(const wchar_t *name, IFolderFolder **resultFolder))
+{
+ *resultFolder = NULL;
+ UString name2 = name;
+ name2.Trim();
+
+ if (name2.IsEmpty())
+ {
+ CRootFolder *rootFolderSpec = new CRootFolder;
+ CMyComPtr<IFolderFolder> rootFolder = rootFolderSpec;
+ rootFolderSpec->Init();
+ *resultFolder = rootFolder.Detach();
+ return S_OK;
+ }
+
+ for (unsigned i = 0; i < kNumRootFolderItems; i++)
+ if (AreEqualNames(name2, _names[i]))
+ return BindToFolder((UInt32)i, resultFolder);
+
+ #ifdef USE_WIN_PATHS
+ if (AreEqualNames(name2, L"My Documents") ||
+ AreEqualNames(name2, L"Documents"))
+ return BindToFolder((UInt32)ROOT_INDEX_DOCUMENTS, resultFolder);
+ #else
+ if (name2 == WSTRING_PATH_SEPARATOR)
+ return BindToFolder((UInt32)ROOT_INDEX_COMPUTER, resultFolder);
+ #endif
+
+ if (AreEqualNames(name2, L"My Computer") ||
+ AreEqualNames(name2, L"Computer"))
+ return BindToFolder((UInt32)ROOT_INDEX_COMPUTER, resultFolder);
+
+ if (name2 == WSTRING_PATH_SEPARATOR)
+ {
+ CMyComPtr<IFolderFolder> subFolder = this;
+ *resultFolder = subFolder.Detach();
+ return S_OK;
+ }
+
+ if (name2.Len() < 2)
+ return E_INVALIDARG;
+
+ CMyComPtr<IFolderFolder> subFolder;
+
+ #ifdef USE_WIN_PATHS
+ if (name2.IsPrefixedBy_Ascii_NoCase(kVolPrefix))
+ {
+ CFSDrives *folderSpec = new CFSDrives;
+ subFolder = folderSpec;
+ folderSpec->Init(true);
+ }
+ else if (name2.IsEqualTo(NFile::NName::kSuperPathPrefix))
+ {
+ CFSDrives *folderSpec = new CFSDrives;
+ subFolder = folderSpec;
+ folderSpec->Init(false, true);
+ }
+ else if (name2.Back() == ':'
+ && (name2.Len() != 2 || !NFile::NName::IsDrivePath2(name2)))
+ {
+ NAltStreamsFolder::CAltStreamsFolder *folderSpec = new NAltStreamsFolder::CAltStreamsFolder;
+ subFolder = folderSpec;
+ if (folderSpec->Init(us2fs(name2)) != S_OK)
+ return E_INVALIDARG;
+ }
+ else
+ #endif
+ {
+ NFile::NName::NormalizeDirPathPrefix(name2);
+ NFsFolder::CFSFolder *fsFolderSpec = new NFsFolder::CFSFolder;
+ subFolder = fsFolderSpec;
+ if (fsFolderSpec->Init(us2fs(name2)) != S_OK)
+ {
+ #ifdef USE_WIN_PATHS
+ if (IS_PATH_SEPAR(name2[0]))
+ {
+ CNetFolder *netFolderSpec = new CNetFolder;
+ subFolder = netFolderSpec;
+ netFolderSpec->Init(name2);
+ }
+ else
+ #endif
+ return E_INVALIDARG;
+ }
+ }
+
+ *resultFolder = subFolder.Detach();
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CRootFolder::BindToParentFolder(IFolderFolder **resultFolder))
+{
+ *resultFolder = NULL;
+ return S_OK;
+}
+
+IMP_IFolderFolder_Props(CRootFolder)
+
+Z7_COM7F_IMF(CRootFolder::GetFolderProperty(PROPID propID, PROPVARIANT *value))
+{
+ NCOM::CPropVariant prop;
+ switch (propID)
+ {
+ case kpidType: prop = "RootFolder"; break;
+ case kpidPath: prop = ""; break;
+ }
+ prop.Detach(value);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CRootFolder::GetSystemIconIndex(UInt32 index, Int32 *iconIndex))
+{
+ *iconIndex = _iconIndices[index];
+ return S_OK;
+}
diff --git a/CPP/7zip/UI/FileManager/RootFolder.h b/CPP/7zip/UI/FileManager/RootFolder.h
new file mode 100644
index 0000000..3f0a31b
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/RootFolder.h
@@ -0,0 +1,24 @@
+// RootFolder.h
+
+#ifndef ZIP7_INC_ROOT_FOLDER_H
+#define ZIP7_INC_ROOT_FOLDER_H
+
+#include "../../../Common/MyCom.h"
+#include "../../../Common/MyString.h"
+
+#include "IFolder.h"
+
+const unsigned kNumRootFolderItems_Max = 4;
+
+Z7_CLASS_IMP_NOQIB_2(
+ CRootFolder
+ , IFolderFolder
+ , IFolderGetSystemIconIndex
+)
+ UString _names[kNumRootFolderItems_Max];
+ int _iconIndices[kNumRootFolderItems_Max];
+public:
+ void Init();
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/SettingsPage.cpp b/CPP/7zip/UI/FileManager/SettingsPage.cpp
new file mode 100644
index 0000000..784b8c7
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SettingsPage.cpp
@@ -0,0 +1,354 @@
+// SettingsPage.cpp
+
+#include "StdAfx.h"
+
+// #include "../../../Common/IntToString.h"
+// #include "../../../Common/StringConvert.h"
+
+#ifndef UNDER_CE
+#include "../../../Windows/MemoryLock.h"
+// #include "../../../Windows/System.h"
+#endif
+
+// #include "../Common/ZipRegistry.h"
+
+#include "HelpUtils.h"
+#include "LangUtils.h"
+#include "RegistryUtils.h"
+#include "SettingsPage.h"
+#include "SettingsPageRes.h"
+
+using namespace NWindows;
+
+#ifdef Z7_LANG
+static const UInt32 kLangIDs[] =
+{
+ IDX_SETTINGS_SHOW_DOTS,
+ IDX_SETTINGS_SHOW_REAL_FILE_ICONS,
+ IDX_SETTINGS_SHOW_SYSTEM_MENU,
+ IDX_SETTINGS_FULL_ROW,
+ IDX_SETTINGS_SHOW_GRID,
+ IDX_SETTINGS_SINGLE_CLICK,
+ IDX_SETTINGS_ALTERNATIVE_SELECTION,
+ IDX_SETTINGS_LARGE_PAGES
+ // , IDT_COMPRESS_MEMORY
+};
+#endif
+
+#define kSettingsTopic "FM/options.htm#settings"
+
+extern bool IsLargePageSupported();
+
+/*
+static void AddMemSize(UString &res, UInt64 size, bool needRound = false)
+{
+ char c;
+ unsigned moveBits = 0;
+ if (needRound)
+ {
+ UInt64 rn = 0;
+ if (size >= (1 << 31))
+ rn = (1 << 28) - 1;
+ UInt32 kRound = (1 << 20) - 1;
+ if (rn < kRound)
+ rn = kRound;
+ size += rn;
+ size &= ~rn;
+ }
+ if (size >= ((UInt64)1 << 31) && (size & 0x3FFFFFFF) == 0)
+ { moveBits = 30; c = 'G'; }
+ else
+ { moveBits = 20; c = 'M'; }
+ res.Add_UInt64(size >> moveBits);
+ res.Add_Space();
+ if (moveBits != 0)
+ res += c;
+ res += 'B';
+}
+
+
+int CSettingsPage::AddMemComboItem(UInt64 size, UInt64 percents, bool isDefault)
+{
+ UString sUser;
+ UString sRegistry;
+ if (size == 0)
+ {
+ UString s;
+ s.Add_UInt64(percents);
+ s += '%';
+ if (isDefault)
+ sUser = "* ";
+ else
+ sRegistry = s;
+ sUser += s;
+ }
+ else
+ {
+ AddMemSize(sUser, size);
+ sRegistry = sUser;
+ for (;;)
+ {
+ int pos = sRegistry.Find(L' ');
+ if (pos < 0)
+ break;
+ sRegistry.Delete(pos);
+ }
+ if (!sRegistry.IsEmpty())
+ if (sRegistry.Back() == 'B')
+ sRegistry.DeleteBack();
+ }
+ const int index = (int)_memCombo.AddString(sUser);
+ _memCombo.SetItemData(index, _memLimitStrings.Size());
+ _memLimitStrings.Add(sRegistry);
+ return index;
+}
+*/
+
+bool CSettingsPage::OnInit()
+{
+ _wasChanged = false;
+ _largePages_wasChanged = false;
+ /*
+ _wasChanged_MemLimit = false;
+ _memLimitStrings.Clear();
+ _memCombo.Attach(GetItem(IDC_SETTINGS_MEM));
+ */
+
+#ifdef Z7_LANG
+ LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
+#endif
+
+ CFmSettings st;
+ st.Load();
+
+ CheckButton(IDX_SETTINGS_SHOW_DOTS, st.ShowDots);
+ CheckButton(IDX_SETTINGS_SHOW_REAL_FILE_ICONS, st.ShowRealFileIcons);
+ CheckButton(IDX_SETTINGS_FULL_ROW, st.FullRow);
+ CheckButton(IDX_SETTINGS_SHOW_GRID, st.ShowGrid);
+ CheckButton(IDX_SETTINGS_SINGLE_CLICK, st.SingleClick);
+ CheckButton(IDX_SETTINGS_ALTERNATIVE_SELECTION, st.AlternativeSelection);
+ // CheckButton(IDX_SETTINGS_UNDERLINE, st.Underline);
+
+ CheckButton(IDX_SETTINGS_SHOW_SYSTEM_MENU, st.ShowSystemMenu);
+
+ if (IsLargePageSupported())
+ CheckButton(IDX_SETTINGS_LARGE_PAGES, ReadLockMemoryEnable());
+ else
+ EnableItem(IDX_SETTINGS_LARGE_PAGES, false);
+
+
+ /*
+ NCompression::CMemUse mu;
+ bool needSetCur = NCompression::MemLimit_Load(mu);
+ UInt64 curMemLimit;
+ {
+ AddMemComboItem(0, 90, true);
+ _memCombo.SetCurSel(0);
+ }
+ if (mu.IsPercent)
+ {
+ const int index = AddMemComboItem(0, mu.Val);
+ _memCombo.SetCurSel(index);
+ needSetCur = false;
+ }
+ {
+ _ramSize = (UInt64)(sizeof(size_t)) << 29;
+ _ramSize_Defined = NSystem::GetRamSize(_ramSize);
+ UString s;
+ if (_ramSize_Defined)
+ {
+ s += "/ ";
+ AddMemSize(s, _ramSize, true);
+ }
+ SetItemText(IDT_SETTINGS_MEM_RAM, s);
+
+ curMemLimit = mu.GetBytes(_ramSize);
+
+ // size = 100 << 20; // for debug only;
+ for (unsigned i = (27) * 2;; i++)
+ {
+ UInt64 size = (UInt64)(2 + (i & 1)) << (i / 2);
+ if (i > (20 + sizeof(size_t) * 3 * 1 - 1) * 2)
+ size = (UInt64)(Int64)-1;
+ if (needSetCur && (size >= curMemLimit))
+ {
+ const int index = AddMemComboItem(curMemLimit);
+ _memCombo.SetCurSel(index);
+ needSetCur = false;
+ if (size == curMemLimit)
+ continue;
+ }
+ if (size == (UInt64)(Int64)-1)
+ break;
+ AddMemComboItem(size);
+ }
+ }
+ */
+
+ // EnableSubItems();
+
+ return CPropertyPage::OnInit();
+}
+
+/*
+void CSettingsPage::EnableSubItems()
+{
+ EnableItem(IDX_SETTINGS_UNDERLINE, IsButtonCheckedBool(IDX_SETTINGS_SINGLE_CLICK));
+}
+*/
+
+/*
+static void AddSize_MB(UString &s, UInt64 size)
+{
+ s.Add_UInt64((size + (1 << 20) - 1) >> 20);
+ s += " MB";
+}
+*/
+
+LONG CSettingsPage::OnApply()
+{
+ if (_wasChanged)
+ {
+ CFmSettings st;
+ st.ShowDots = IsButtonCheckedBool(IDX_SETTINGS_SHOW_DOTS);
+ st.ShowRealFileIcons = IsButtonCheckedBool(IDX_SETTINGS_SHOW_REAL_FILE_ICONS);
+ st.FullRow = IsButtonCheckedBool(IDX_SETTINGS_FULL_ROW);
+ st.ShowGrid = IsButtonCheckedBool(IDX_SETTINGS_SHOW_GRID);
+ st.SingleClick = IsButtonCheckedBool(IDX_SETTINGS_SINGLE_CLICK);
+ st.AlternativeSelection = IsButtonCheckedBool(IDX_SETTINGS_ALTERNATIVE_SELECTION);
+ // st.Underline = IsButtonCheckedBool(IDX_SETTINGS_UNDERLINE);
+
+ st.ShowSystemMenu = IsButtonCheckedBool(IDX_SETTINGS_SHOW_SYSTEM_MENU);
+
+ st.Save();
+ _wasChanged = false;
+ }
+
+ #ifndef UNDER_CE
+ if (_largePages_wasChanged)
+ {
+ if (IsLargePageSupported())
+ {
+ const bool enable = IsButtonCheckedBool(IDX_SETTINGS_LARGE_PAGES);
+ NSecurity::EnablePrivilege_LockMemory(enable);
+ SaveLockMemoryEnable(enable);
+ }
+ _largePages_wasChanged = false;
+ }
+ #endif
+
+ /*
+ if (_wasChanged_MemLimit)
+ {
+ const unsigned index = (int)_memCombo.GetItemData_of_CurSel();
+ const UString str = _memLimitStrings[index];
+
+ bool needSave = true;
+
+ NCompression::CMemUse mu;
+
+ if (_ramSize_Defined)
+ mu.Parse(str);
+ if (mu.IsDefined)
+ {
+ const UInt64 usage64 = mu.GetBytes(_ramSize);
+ if (_ramSize <= usage64)
+ {
+ UString s2 = LangString(IDT_COMPRESS_MEMORY);
+ if (s2.IsEmpty())
+ GetItemText(IDT_COMPRESS_MEMORY, s2);
+ UString s;
+
+ s += "The selected value is not safe for system performance.";
+ s.Add_LF();
+ s += "The memory consumption for compression operation will exceed RAM size.";
+ s.Add_LF();
+ s.Add_LF();
+ AddSize_MB(s, usage64);
+
+ if (!s2.IsEmpty())
+ {
+ s += " : ";
+ s += s2;
+ }
+
+ s.Add_LF();
+ AddSize_MB(s, _ramSize);
+ s += " : RAM";
+
+ s.Add_LF();
+ s.Add_LF();
+ s += "Are you sure you want set that unsafe value for memory usage?";
+
+ int res = MessageBoxW(*this, s, L"7-Zip", MB_YESNOCANCEL | MB_ICONQUESTION);
+ if (res != IDYES)
+ needSave = false;
+ }
+ }
+
+ if (needSave)
+ {
+ NCompression::MemLimit_Save(str);
+ _wasChanged_MemLimit = false;
+ }
+ else
+ return PSNRET_INVALID_NOCHANGEPAGE;
+ }
+ */
+
+ return PSNRET_NOERROR;
+}
+
+void CSettingsPage::OnNotifyHelp()
+{
+ ShowHelpWindow(kSettingsTopic);
+}
+
+/*
+bool CSettingsPage::OnCommand(unsigned code, unsigned itemID, LPARAM param)
+{
+ if (code == CBN_SELCHANGE)
+ {
+ switch (itemID)
+ {
+ case IDC_SETTINGS_MEM:
+ {
+ _wasChanged_MemLimit = true;
+ Changed();
+ break;
+ }
+ }
+ }
+ return CPropertyPage::OnCommand(code, itemID, param);
+}
+*/
+
+bool CSettingsPage::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ switch (buttonID)
+ {
+ case IDX_SETTINGS_SINGLE_CLICK:
+ /*
+ EnableSubItems();
+ break;
+ */
+ case IDX_SETTINGS_SHOW_DOTS:
+ case IDX_SETTINGS_SHOW_SYSTEM_MENU:
+ case IDX_SETTINGS_SHOW_REAL_FILE_ICONS:
+ case IDX_SETTINGS_FULL_ROW:
+ case IDX_SETTINGS_SHOW_GRID:
+ case IDX_SETTINGS_ALTERNATIVE_SELECTION:
+ _wasChanged = true;
+ break;
+
+ case IDX_SETTINGS_LARGE_PAGES:
+ _largePages_wasChanged = true;
+ break;
+
+ default:
+ return CPropertyPage::OnButtonClicked(buttonID, buttonHWND);
+ }
+
+ Changed();
+ return true;
+}
diff --git a/CPP/7zip/UI/FileManager/SettingsPage.h b/CPP/7zip/UI/FileManager/SettingsPage.h
new file mode 100644
index 0000000..91b9828
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SettingsPage.h
@@ -0,0 +1,33 @@
+// SettingsPage.h
+
+#ifndef ZIP7_INC_SETTINGS_PAGE_H
+#define ZIP7_INC_SETTINGS_PAGE_H
+
+#include "../../../Windows/Control/PropertyPage.h"
+#include "../../../Windows/Control/ComboBox.h"
+#include "../../../Windows/Control/Edit.h"
+
+class CSettingsPage: public NWindows::NControl::CPropertyPage
+{
+ bool _wasChanged;
+ bool _largePages_wasChanged;
+ /*
+ bool _wasChanged_MemLimit;
+ NWindows::NControl::CComboBox _memCombo;
+ UStringVector _memLimitStrings;
+ UInt64 _ramSize;
+ UInt64 _ramSize_Defined;
+
+ int AddMemComboItem(UInt64 size, UInt64 percents = 0, bool isDefault = false);
+ */
+
+ // void EnableSubItems();
+ // bool OnCommand(unsigned code, unsigned itemID, LPARAM param) Z7_override;
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+ virtual bool OnInit() Z7_override;
+ virtual void OnNotifyHelp() Z7_override;
+ virtual LONG OnApply() Z7_override;
+public:
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/SettingsPage.rc b/CPP/7zip/UI/FileManager/SettingsPage.rc
new file mode 100644
index 0000000..baab484
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SettingsPage.rc
@@ -0,0 +1,22 @@
+#include "SettingsPageRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 240
+#define yc 250
+
+IDD_SETTINGS MY_PAGE
+#include "SettingsPage2.rc"
+
+
+#ifdef UNDER_CE
+
+#undef m
+#undef xc
+
+#define m 4
+#define xc (SMALL_PAGE_SIZE_X + 8)
+
+IDD_SETTINGS_2 MY_PAGE
+#include "SettingsPage2.rc"
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/SettingsPage2.rc b/CPP/7zip/UI/FileManager/SettingsPage2.rc
new file mode 100644
index 0000000..cf90742
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SettingsPage2.rc
@@ -0,0 +1,19 @@
+// #define g1xs 60
+
+CAPTION "Settings"
+BEGIN
+ CONTROL "Show "".."" item", IDX_SETTINGS_SHOW_DOTS, MY_CHECKBOX, m, 8, xc, 10
+ CONTROL "Show real file &icons", IDX_SETTINGS_SHOW_REAL_FILE_ICONS, MY_CHECKBOX, m, 22, xc, 10
+ CONTROL "&Full row select", IDX_SETTINGS_FULL_ROW, MY_CHECKBOX, m, 36, xc, 10
+ CONTROL "Show &grid lines", IDX_SETTINGS_SHOW_GRID, MY_CHECKBOX, m, 50, xc, 10
+ CONTROL "&Single-click to open an item", IDX_SETTINGS_SINGLE_CLICK, MY_CHECKBOX, m, 64, xc, 10
+ CONTROL "&Alternative selection mode", IDX_SETTINGS_ALTERNATIVE_SELECTION, MY_CHECKBOX, m, 78, xc, 10
+
+ CONTROL "Show system &menu", IDX_SETTINGS_SHOW_SYSTEM_MENU, MY_CHECKBOX, m, 100, xc, 10
+
+ CONTROL "Use &large memory pages", IDX_SETTINGS_LARGE_PAGES, MY_CHECKBOX, m, 122, xc, 10
+
+ // LTEXT "Memory usage for Compressing:", IDT_COMPRESS_MEMORY, m, 140, xc, 8
+ // COMBOBOX IDC_SETTINGS_MEM, m , 152, g1xs, yc - 152, MY_COMBO
+ // LTEXT "/ RAM", IDT_SETTINGS_MEM_RAM, m + g1xs + m, 154, xc - g1xs - m, MY_TEXT_NOPREFIX
+END
diff --git a/CPP/7zip/UI/FileManager/SettingsPageRes.h b/CPP/7zip/UI/FileManager/SettingsPageRes.h
new file mode 100644
index 0000000..e990bab
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SettingsPageRes.h
@@ -0,0 +1,17 @@
+#define IDD_SETTINGS 2500
+#define IDD_SETTINGS_2 12500
+
+#define IDX_SETTINGS_SHOW_DOTS 2501
+#define IDX_SETTINGS_SHOW_REAL_FILE_ICONS 2502
+#define IDX_SETTINGS_SHOW_SYSTEM_MENU 2503
+#define IDX_SETTINGS_FULL_ROW 2504
+#define IDX_SETTINGS_SHOW_GRID 2505
+#define IDX_SETTINGS_SINGLE_CLICK 2506
+#define IDX_SETTINGS_ALTERNATIVE_SELECTION 2507
+#define IDX_SETTINGS_LARGE_PAGES 2508
+
+
+// #define IDT_SETTINGS_MEM 100
+// #define IDC_SETTINGS_MEM 101
+// #define IDT_SETTINGS_MEM_RAM 102
+// #define IDT_COMPRESS_MEMORY 4017
diff --git a/CPP/7zip/UI/FileManager/SplitDialog.cpp b/CPP/7zip/UI/FileManager/SplitDialog.cpp
new file mode 100644
index 0000000..21d812c
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SplitDialog.cpp
@@ -0,0 +1,114 @@
+// SplitDialog.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Windows/FileName.h"
+
+#include "LangUtils.h"
+
+#include "BrowseDialog.h"
+#include "CopyDialogRes.h"
+#include "SplitDialog.h"
+#include "SplitUtils.h"
+#include "resourceGui.h"
+
+using namespace NWindows;
+
+#ifdef Z7_LANG
+static const UInt32 kLangIDs[] =
+{
+ IDT_SPLIT_PATH,
+ IDT_SPLIT_VOLUME
+};
+#endif
+
+
+bool CSplitDialog::OnInit()
+{
+ #ifdef Z7_LANG
+ LangSetWindowText(*this, IDD_SPLIT);
+ LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
+ #endif
+ _pathCombo.Attach(GetItem(IDC_SPLIT_PATH));
+ _volumeCombo.Attach(GetItem(IDC_SPLIT_VOLUME));
+
+ if (!FilePath.IsEmpty())
+ {
+ UString title;
+ GetText(title);
+ title.Add_Space();
+ title += FilePath;
+ SetText(title);
+ }
+ _pathCombo.SetText(Path);
+ AddVolumeItems(_volumeCombo);
+ _volumeCombo.SetCurSel(0);
+ NormalizeSize();
+ return CModalDialog::OnInit();
+}
+
+bool CSplitDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
+{
+ int mx, my;
+ GetMargins(8, mx, my);
+ int bx1, bx2, by;
+ GetItemSizes(IDCANCEL, bx1, by);
+ GetItemSizes(IDOK, bx2, by);
+ int yPos = ySize - my - by;
+ int xPos = xSize - mx - bx1;
+
+ InvalidateRect(NULL);
+
+ {
+ RECT r;
+ GetClientRectOfItem(IDB_SPLIT_PATH, r);
+ int bx = RECT_SIZE_X(r);
+ MoveItem(IDB_SPLIT_PATH, xSize - mx - bx, r.top, bx, RECT_SIZE_Y(r));
+ ChangeSubWindowSizeX(_pathCombo, xSize - mx - mx - bx - mx);
+ }
+
+ MoveItem(IDCANCEL, xPos, yPos, bx1, by);
+ MoveItem(IDOK, xPos - mx - bx2, yPos, bx2, by);
+
+ return false;
+}
+
+bool CSplitDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ switch (buttonID)
+ {
+ case IDB_SPLIT_PATH:
+ OnButtonSetPath();
+ return true;
+ }
+ return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
+}
+
+void CSplitDialog::OnButtonSetPath()
+{
+ UString currentPath;
+ _pathCombo.GetText(currentPath);
+ // UString title = "Specify a location for output folder";
+ const UString title = LangString(IDS_SET_FOLDER);
+
+ UString resultPath;
+ if (!MyBrowseForFolder(*this, title, currentPath, resultPath))
+ return;
+ NFile::NName::NormalizeDirPathPrefix(resultPath);
+ _pathCombo.SetCurSel(-1);
+ _pathCombo.SetText(resultPath);
+}
+
+void CSplitDialog::OnOK()
+{
+ _pathCombo.GetText(Path);
+ UString volumeString;
+ _volumeCombo.GetText(volumeString);
+ volumeString.Trim();
+ if (!ParseVolumeSizes(volumeString, VolumeSizes) || VolumeSizes.Size() == 0)
+ {
+ ::MessageBoxW(*this, LangString(IDS_INCORRECT_VOLUME_SIZE), L"7-Zip", MB_ICONERROR);
+ return;
+ }
+ CModalDialog::OnOK();
+}
diff --git a/CPP/7zip/UI/FileManager/SplitDialog.h b/CPP/7zip/UI/FileManager/SplitDialog.h
new file mode 100644
index 0000000..f897136
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SplitDialog.h
@@ -0,0 +1,28 @@
+// SplitDialog.h
+
+#ifndef ZIP7_INC_SPLIT_DIALOG_H
+#define ZIP7_INC_SPLIT_DIALOG_H
+
+#include "../../../Windows/Control/Dialog.h"
+#include "../../../Windows/Control/ComboBox.h"
+
+#include "SplitDialogRes.h"
+
+class CSplitDialog: public NWindows::NControl::CModalDialog
+{
+ NWindows::NControl::CComboBox _pathCombo;
+ NWindows::NControl::CComboBox _volumeCombo;
+ virtual void OnOK() Z7_override;
+ virtual bool OnInit() Z7_override;
+ virtual bool OnSize(WPARAM wParam, int xSize, int ySize) Z7_override;
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+ void OnButtonSetPath();
+public:
+ UString FilePath;
+ UString Path;
+ CRecordVector<UInt64> VolumeSizes;
+ INT_PTR Create(HWND parentWindow = NULL)
+ { return CModalDialog::Create(IDD_SPLIT, parentWindow); }
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/SplitDialog.rc b/CPP/7zip/UI/FileManager/SplitDialog.rc
new file mode 100644
index 0000000..5a026e8
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SplitDialog.rc
@@ -0,0 +1,16 @@
+#include "SplitDialogRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 288
+#define yc 96
+
+IDD_SPLIT DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT
+CAPTION "Split File"
+BEGIN
+ LTEXT "&Split to:", IDT_SPLIT_PATH, m, m, xc, 8
+ COMBOBOX IDC_SPLIT_PATH, m, 20, xc - bxsDots - m, 64, MY_COMBO_WITH_EDIT
+ PUSHBUTTON "...", IDB_SPLIT_PATH, xs - m - bxsDots, 18, bxsDots, bys, WS_GROUP
+ LTEXT "Split to &volumes, bytes:", IDT_SPLIT_VOLUME, m, 44, xc, 8
+ COMBOBOX IDC_SPLIT_VOLUME, m, 56, 96, 52, MY_COMBO_WITH_EDIT
+ OK_CANCEL
+END
diff --git a/CPP/7zip/UI/FileManager/SplitDialogRes.h b/CPP/7zip/UI/FileManager/SplitDialogRes.h
new file mode 100644
index 0000000..50584a1
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SplitDialogRes.h
@@ -0,0 +1,8 @@
+#define IDD_SPLIT 7300
+
+#define IDT_SPLIT_PATH 7301
+#define IDT_SPLIT_VOLUME 7302
+
+#define IDC_SPLIT_PATH 100
+#define IDB_SPLIT_PATH 101
+#define IDC_SPLIT_VOLUME 102
diff --git a/CPP/7zip/UI/FileManager/SplitUtils.cpp b/CPP/7zip/UI/FileManager/SplitUtils.cpp
new file mode 100644
index 0000000..1982afb
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SplitUtils.cpp
@@ -0,0 +1,96 @@
+// SplitUtils.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/StringToInt.h"
+
+#include "SplitUtils.h"
+
+bool ParseVolumeSizes(const UString &s, CRecordVector<UInt64> &values)
+{
+ values.Clear();
+ bool prevIsNumber = false;
+ for (unsigned i = 0; i < s.Len();)
+ {
+ wchar_t c = s[i++];
+ if (c == L' ')
+ continue;
+ if (c == L'-')
+ return true;
+ if (prevIsNumber)
+ {
+ prevIsNumber = false;
+ unsigned numBits = 0;
+ switch (MyCharLower_Ascii(c))
+ {
+ case 'b': continue;
+ case 'k': numBits = 10; break;
+ case 'm': numBits = 20; break;
+ case 'g': numBits = 30; break;
+ case 't': numBits = 40; break;
+ }
+ if (numBits != 0)
+ {
+ UInt64 &val = values.Back();
+ if (val >= ((UInt64)1 << (64 - numBits)))
+ return false;
+ val <<= numBits;
+
+ for (; i < s.Len(); i++)
+ if (s[i] == L' ')
+ break;
+ continue;
+ }
+ }
+ i--;
+ const wchar_t *start = s.Ptr(i);
+ const wchar_t *end;
+ UInt64 val = ConvertStringToUInt64(start, &end);
+ if (start == end)
+ return false;
+ if (val == 0)
+ return false;
+ values.Add(val);
+ prevIsNumber = true;
+ i += (unsigned)(end - start);
+ }
+ return true;
+}
+
+
+static const char * const k_Sizes[] =
+{
+ "10M"
+ , "100M"
+ , "1000M"
+ , "650M - CD"
+ , "700M - CD"
+ , "4092M - FAT"
+ , "4480M - DVD" // 4489 MiB limit
+ , "8128M - DVD DL" // 8147 MiB limit
+ , "23040M - BD" // 23866 MiB limit
+ // , "1457664 - 3.5\" floppy"
+};
+
+void AddVolumeItems(NWindows::NControl::CComboBox &combo)
+{
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_Sizes); i++)
+ combo.AddString(CSysString(k_Sizes[i]));
+}
+
+UInt64 GetNumberOfVolumes(UInt64 size, const CRecordVector<UInt64> &volSizes)
+{
+ if (size == 0 || volSizes.Size() == 0)
+ return 1;
+ FOR_VECTOR (i, volSizes)
+ {
+ UInt64 volSize = volSizes[i];
+ if (volSize >= size)
+ return i + 1;
+ size -= volSize;
+ }
+ UInt64 volSize = volSizes.Back();
+ if (volSize == 0)
+ return (UInt64)(Int64)-1;
+ return volSizes.Size() + (size - 1) / volSize + 1;
+}
diff --git a/CPP/7zip/UI/FileManager/SplitUtils.h b/CPP/7zip/UI/FileManager/SplitUtils.h
new file mode 100644
index 0000000..d1d44e4
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SplitUtils.h
@@ -0,0 +1,15 @@
+// SplitUtils.h
+
+#ifndef ZIP7_INC_SPLIT_UTILS_H
+#define ZIP7_INC_SPLIT_UTILS_H
+
+#include "../../../Common/MyTypes.h"
+#include "../../../Common/MyString.h"
+
+#include "../../../Windows/Control/ComboBox.h"
+
+bool ParseVolumeSizes(const UString &s, CRecordVector<UInt64> &values);
+void AddVolumeItems(NWindows::NControl::CComboBox &volumeCombo);
+UInt64 GetNumberOfVolumes(UInt64 size, const CRecordVector<UInt64> &volSizes);
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/StdAfx.cpp b/CPP/7zip/UI/FileManager/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/UI/FileManager/StdAfx.h b/CPP/7zip/UI/FileManager/StdAfx.h
new file mode 100644
index 0000000..789cc6e
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/StdAfx.h
@@ -0,0 +1,83 @@
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+
+#include "../../../../C/Compiler.h"
+
+Z7_DIAGNOSCTIC_IGNORE_BEGIN_RESERVED_MACRO_IDENTIFIER
+#ifndef _WIN32_WINNT
+// #define _WIN32_WINNT 0x0400
+#define _WIN32_WINNT 0x0500
+// #define _WIN32_WINNT 0x0600
+// #define _WIN32_WINNT 0x0A00
+#endif
+#ifndef WINVER
+#define WINVER _WIN32_WINNT
+#endif
+// #define _WIN32_IE 0x400 // for debug
+Z7_DIAGNOSCTIC_IGNORE_END_RESERVED_MACRO_IDENTIFIER
+
+#include "../../../Common/Common.h"
+#include "../../../Common/MyWindows.h"
+
+#endif
+
+/*
+WINVER and _WIN32_WINNT
+
+MSVC6 / 2003sdk:
+{
+ <windows.h> doesn't set _WIN32_WINNT
+ if WINVER is not set <windows.h> sets WINVER to value:
+ 0x0400 : MSVC6
+ 0x0501 : Windows Server 2003 PSDK / 2003 R2 PSDK
+}
+
+SDK for Win7 (and later)
+{
+ <windows.h> sets _WIN32_WINNT if it's not set.
+ <windows.h> sets WINVER if it's not set.
+<windows.h> includes <sdkddkver.h> that does:
+#if !defined(_WIN32_WINNT) && !defined(_CHICAGO_)
+ #define _WIN32_WINNT 0x0601 // in win7 sdk
+ #define _WIN32_WINNT 0x0A00 // in win10 sdk
+#endif
+#ifndef WINVER
+ #ifdef _WIN32_WINNT
+ #define WINVER _WIN32_WINNT
+ else
+ #define WINVER 0x0601 // in win7 sdk
+ #define WINVER 0x0A00 // in win10 sdk
+ endif
+#endif
+}
+
+Some GUI structures defined by windows will be larger,
+If (_WIN32_WINNT) value is larger.
+
+Also if we send sizeof(win_gui_struct) to some windows function,
+and we compile that code with big (_WIN32_WINNT) value,
+the window function in old Windows can fail, if that old Windows
+doesn't understand new big version of (win_gui_struct) compiled
+with big (_WIN32_WINNT) value.
+
+So it's better to define smallest (_WIN32_WINNT) value here.
+In 7-Zip FM we use some functions that require (_WIN32_WINNT == 0x0500).
+So it's simpler to define (_WIN32_WINNT == 0x0500) here.
+If we define (_WIN32_WINNT == 0x0400) here, we need some manual
+declarations for functions and macros that require (0x0500) functions.
+Also libs must contain these (0x0500+) functions.
+
+Some code in 7-zip FM uses also CommCtrl.h structures
+that depend from (_WIN32_IE) value. But default
+(_WIN32_IE) value from <windows.h> probably is OK for us.
+So we don't set _WIN32_IE here.
+default _WIN32_IE value set by <windows.h>:
+ 0x501 2003sdk
+ 0xa00 win10 sdk
+*/
diff --git a/CPP/7zip/UI/FileManager/StringUtils.cpp b/CPP/7zip/UI/FileManager/StringUtils.cpp
new file mode 100644
index 0000000..4641d15
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/StringUtils.cpp
@@ -0,0 +1,39 @@
+// StringUtils.cpp
+
+#include "StdAfx.h"
+
+#include "StringUtils.h"
+
+void SplitStringToTwoStrings(const UString &src, UString &dest1, UString &dest2)
+{
+ dest1.Empty();
+ dest2.Empty();
+ bool quoteMode = false;
+ for (unsigned i = 0; i < src.Len(); i++)
+ {
+ const wchar_t c = src[i];
+ if (c == '\"')
+ quoteMode = !quoteMode;
+ else if (c == ' ' && !quoteMode)
+ {
+ dest2 = src.Ptr(i + 1);
+ return;
+ }
+ else
+ dest1 += c;
+ }
+}
+
+/*
+UString JoinStrings(const UStringVector &srcStrings)
+{
+ UString s;
+ FOR_VECTOR (i, srcStrings)
+ {
+ if (i != 0)
+ s.Add_Space();
+ s += srcStrings[i];
+ }
+ return s;
+}
+*/
diff --git a/CPP/7zip/UI/FileManager/StringUtils.h b/CPP/7zip/UI/FileManager/StringUtils.h
new file mode 100644
index 0000000..37aad3a
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/StringUtils.h
@@ -0,0 +1,11 @@
+// StringUtils.h
+
+#ifndef ZIP7_INC_STRING_UTILS_H
+#define ZIP7_INC_STRING_UTILS_H
+
+#include "../../../Common/MyString.h"
+
+void SplitStringToTwoStrings(const UString &src, UString &dest1, UString &dest2);
+// UString JoinStrings(const UStringVector &srcStrings);
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/SysIconUtils.cpp b/CPP/7zip/UI/FileManager/SysIconUtils.cpp
index 2100e82..1c7cab0 100644
--- a/CPP/7zip/UI/FileManager/SysIconUtils.cpp
+++ b/CPP/7zip/UI/FileManager/SysIconUtils.cpp
@@ -1,255 +1,278 @@
-// SysIconUtils.cpp
-
-#include "StdAfx.h"
-
-#ifndef _UNICODE
-#include "../../../Common/StringConvert.h"
-#endif
-
-#include "../../../Windows/FileDir.h"
-
-#include "SysIconUtils.h"
-
-#include <ShlObj.h>
-
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-int GetIconIndexForCSIDL(int csidl)
-{
- LPITEMIDLIST pidl = 0;
- SHGetSpecialFolderLocation(NULL, csidl, &pidl);
- if (pidl)
- {
- SHFILEINFO shellInfo;
- SHGetFileInfo(LPCTSTR(pidl), FILE_ATTRIBUTE_NORMAL,
- &shellInfo, sizeof(shellInfo),
- SHGFI_PIDL | SHGFI_SYSICONINDEX);
- IMalloc *pMalloc;
- SHGetMalloc(&pMalloc);
- if (pMalloc)
- {
- pMalloc->Free(pidl);
- pMalloc->Release();
- }
- return shellInfo.iIcon;
- }
- return 0;
-}
-
-#ifndef _UNICODE
-typedef int (WINAPI * SHGetFileInfoWP)(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags);
-
-struct CSHGetFileInfoInit
-{
- SHGetFileInfoWP shGetFileInfoW;
- CSHGetFileInfoInit()
- {
- shGetFileInfoW = (SHGetFileInfoWP)
- ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetFileInfoW");
- }
-} g_SHGetFileInfoInit;
-#endif
-
-static DWORD_PTR MySHGetFileInfoW(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags)
-{
- #ifdef _UNICODE
- return SHGetFileInfo
- #else
- if (g_SHGetFileInfoInit.shGetFileInfoW == 0)
- return 0;
- return g_SHGetFileInfoInit.shGetFileInfoW
- #endif
- (pszPath, attrib, psfi, cbFileInfo, uFlags);
-}
-
-DWORD_PTR GetRealIconIndex(CFSTR path, DWORD attrib, int &iconIndex)
-{
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- SHFILEINFO shellInfo;
- DWORD_PTR res = ::SHGetFileInfo(fs2fas(path), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
- sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX);
- iconIndex = shellInfo.iIcon;
- return res;
- }
- else
- #endif
- {
- SHFILEINFOW shellInfo;
- DWORD_PTR res = ::MySHGetFileInfoW(fs2us(path), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
- sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX);
- iconIndex = shellInfo.iIcon;
- return res;
- }
-}
-
-/*
-DWORD_PTR GetRealIconIndex(const UString &fileName, DWORD attrib, int &iconIndex, UString *typeName)
-{
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- SHFILEINFO shellInfo;
- shellInfo.szTypeName[0] = 0;
- DWORD_PTR res = ::SHGetFileInfoA(GetSystemString(fileName), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
- sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
- if (typeName)
- *typeName = GetUnicodeString(shellInfo.szTypeName);
- iconIndex = shellInfo.iIcon;
- return res;
- }
- else
- #endif
- {
- SHFILEINFOW shellInfo;
- shellInfo.szTypeName[0] = 0;
- DWORD_PTR res = ::MySHGetFileInfoW(fileName, FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
- sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
- if (typeName)
- *typeName = shellInfo.szTypeName;
- iconIndex = shellInfo.iIcon;
- return res;
- }
-}
-*/
-
-static int FindInSorted_Attrib(const CRecordVector<CAttribIconPair> &vect, DWORD attrib, int &insertPos)
-{
- unsigned left = 0, right = vect.Size();
- while (left != right)
- {
- unsigned mid = (left + right) / 2;
- DWORD midAttrib = vect[mid].Attrib;
- if (attrib == midAttrib)
- return mid;
- if (attrib < midAttrib)
- right = mid;
- else
- left = mid + 1;
- }
- insertPos = left;
- return -1;
-}
-
-static int FindInSorted_Ext(const CObjectVector<CExtIconPair> &vect, const wchar_t *ext, int &insertPos)
-{
- unsigned left = 0, right = vect.Size();
- while (left != right)
- {
- unsigned mid = (left + right) / 2;
- int compare = MyStringCompareNoCase(ext, vect[mid].Ext);
- if (compare == 0)
- return mid;
- if (compare < 0)
- right = mid;
- else
- left = mid + 1;
- }
- insertPos = left;
- return -1;
-}
-
-int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UString *typeName */)
-{
- int dotPos = -1;
- unsigned i;
- for (i = 0;; i++)
- {
- wchar_t c = fileName[i];
- if (c == 0)
- break;
- if (c == '.')
- dotPos = i;
- }
-
- /*
- if (MyStringCompareNoCase(fileName, L"$Recycle.Bin") == 0)
- {
- char s[256];
- sprintf(s, "SPEC i = %3d, attr = %7x", _attribMap.Size(), attrib);
- OutputDebugStringA(s);
- OutputDebugStringW(fileName);
- }
- */
-
- if ((attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 || dotPos < 0)
- {
- int insertPos = 0;
- int index = FindInSorted_Attrib(_attribMap, attrib, insertPos);
- if (index >= 0)
- {
- // if (typeName) *typeName = _attribMap[index].TypeName;
- return _attribMap[index].IconIndex;
- }
- CAttribIconPair pair;
- GetRealIconIndex(
- #ifdef UNDER_CE
- FTEXT("\\")
- #endif
- FTEXT("__DIR__")
- , attrib, pair.IconIndex
- // , pair.TypeName
- );
-
- /*
- char s[256];
- sprintf(s, "i = %3d, attr = %7x", _attribMap.Size(), attrib);
- OutputDebugStringA(s);
- */
-
- pair.Attrib = attrib;
- _attribMap.Insert(insertPos, pair);
- // if (typeName) *typeName = pair.TypeName;
- return pair.IconIndex;
- }
-
- const wchar_t *ext = fileName + dotPos + 1;
- int insertPos = 0;
- int index = FindInSorted_Ext(_extMap, ext, insertPos);
- if (index >= 0)
- {
- const CExtIconPair &pa = _extMap[index];
- // if (typeName) *typeName = pa.TypeName;
- return pa.IconIndex;
- }
-
- for (i = 0;; i++)
- {
- wchar_t c = ext[i];
- if (c == 0)
- break;
- if (c < L'0' || c > L'9')
- break;
- }
- if (i != 0 && ext[i] == 0)
- {
- // GetRealIconIndex is too slow for big number of split extensions: .001, .002, .003
- if (!SplitIconIndex_Defined)
- {
- GetRealIconIndex(
- #ifdef UNDER_CE
- FTEXT("\\")
- #endif
- FTEXT("__FILE__.001"), 0, SplitIconIndex);
- SplitIconIndex_Defined = true;
- }
- return SplitIconIndex;
- }
-
- CExtIconPair pair;
- pair.Ext = ext;
- GetRealIconIndex(us2fs(fileName + dotPos), attrib, pair.IconIndex);
- _extMap.Insert(insertPos, pair);
- // if (typeName) *typeName = pair.TypeName;
- return pair.IconIndex;
-}
-
-/*
-int CExtToIconMap::GetIconIndex(DWORD attrib, const UString &fileName)
-{
- return GetIconIndex(attrib, fileName, NULL);
-}
-*/
+// SysIconUtils.cpp
+
+#include "StdAfx.h"
+
+#ifndef _UNICODE
+#include "../../../Common/StringConvert.h"
+#endif
+
+#include "../../../Windows/FileDir.h"
+
+#include "SysIconUtils.h"
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <shlobj.h>
+#else
+#include <ShlObj.h>
+#endif
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+int GetIconIndexForCSIDL(int csidl)
+{
+ LPITEMIDLIST pidl = NULL;
+ SHGetSpecialFolderLocation(NULL, csidl, &pidl);
+ if (pidl)
+ {
+ SHFILEINFO shellInfo;
+ shellInfo.iIcon = 0;
+ const DWORD_PTR res = SHGetFileInfo((LPCTSTR)(const void *)(pidl), FILE_ATTRIBUTE_NORMAL,
+ &shellInfo, sizeof(shellInfo),
+ SHGFI_PIDL | SHGFI_SYSICONINDEX);
+ /*
+ IMalloc *pMalloc;
+ SHGetMalloc(&pMalloc);
+ if (pMalloc)
+ {
+ pMalloc->Free(pidl);
+ pMalloc->Release();
+ }
+ */
+ // we use OLE2.dll function here
+ CoTaskMemFree(pidl);
+ if (res)
+ return shellInfo.iIcon;
+ }
+ return 0;
+}
+
+#ifndef _UNICODE
+typedef DWORD_PTR (WINAPI * Func_SHGetFileInfoW)(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags);
+
+static struct C_SHGetFileInfo_Init
+{
+ Func_SHGetFileInfoW f_SHGetFileInfoW;
+ C_SHGetFileInfo_Init()
+ {
+ f_SHGetFileInfoW = Z7_GET_PROC_ADDRESS(
+ Func_SHGetFileInfoW, ::GetModuleHandleW(L"shell32.dll"),
+ "SHGetFileInfoW");
+ }
+} g_SHGetFileInfo_Init;
+#endif
+
+static DWORD_PTR My_SHGetFileInfoW(LPCWSTR pszPath, DWORD attrib, SHFILEINFOW *psfi, UINT cbFileInfo, UINT uFlags)
+{
+ #ifdef _UNICODE
+ return SHGetFileInfo
+ #else
+ if (!g_SHGetFileInfo_Init.f_SHGetFileInfoW)
+ return 0;
+ return g_SHGetFileInfo_Init.f_SHGetFileInfoW
+ #endif
+ (pszPath, attrib, psfi, cbFileInfo, uFlags);
+}
+
+DWORD_PTR GetRealIconIndex(CFSTR path, DWORD attrib, int &iconIndex)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ SHFILEINFO shellInfo;
+ const DWORD_PTR res = ::SHGetFileInfo(fs2fas(path), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
+ sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX);
+ iconIndex = shellInfo.iIcon;
+ return res;
+ }
+ else
+ #endif
+ {
+ SHFILEINFOW shellInfo;
+ const DWORD_PTR res = ::My_SHGetFileInfoW(fs2us(path), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
+ sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX);
+ iconIndex = shellInfo.iIcon;
+ return res;
+ }
+}
+
+/*
+DWORD_PTR GetRealIconIndex(const UString &fileName, DWORD attrib, int &iconIndex, UString *typeName)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ SHFILEINFO shellInfo;
+ shellInfo.szTypeName[0] = 0;
+ DWORD_PTR res = ::SHGetFileInfoA(GetSystemString(fileName), FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
+ sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
+ if (typeName)
+ *typeName = GetUnicodeString(shellInfo.szTypeName);
+ iconIndex = shellInfo.iIcon;
+ return res;
+ }
+ else
+ #endif
+ {
+ SHFILEINFOW shellInfo;
+ shellInfo.szTypeName[0] = 0;
+ DWORD_PTR res = ::My_SHGetFileInfoW(fileName, FILE_ATTRIBUTE_NORMAL | attrib, &shellInfo,
+ sizeof(shellInfo), SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | SHGFI_TYPENAME);
+ if (typeName)
+ *typeName = shellInfo.szTypeName;
+ iconIndex = shellInfo.iIcon;
+ return res;
+ }
+}
+*/
+
+static int FindInSorted_Attrib(const CRecordVector<CAttribIconPair> &vect, DWORD attrib, unsigned &insertPos)
+{
+ unsigned left = 0, right = vect.Size();
+ while (left != right)
+ {
+ const unsigned mid = (left + right) / 2;
+ const DWORD midAttrib = vect[mid].Attrib;
+ if (attrib == midAttrib)
+ return (int)mid;
+ if (attrib < midAttrib)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ insertPos = left;
+ return -1;
+}
+
+static int FindInSorted_Ext(const CObjectVector<CExtIconPair> &vect, const wchar_t *ext, unsigned &insertPos)
+{
+ unsigned left = 0, right = vect.Size();
+ while (left != right)
+ {
+ const unsigned mid = (left + right) / 2;
+ const int compare = MyStringCompareNoCase(ext, vect[mid].Ext);
+ if (compare == 0)
+ return (int)mid;
+ if (compare < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ insertPos = left;
+ return -1;
+}
+
+int CExtToIconMap::GetIconIndex(DWORD attrib, const wchar_t *fileName /*, UString *typeName */)
+{
+ int dotPos = -1;
+ unsigned i;
+ for (i = 0;; i++)
+ {
+ const wchar_t c = fileName[i];
+ if (c == 0)
+ break;
+ if (c == '.')
+ dotPos = (int)i;
+ }
+
+ /*
+ if (MyStringCompareNoCase(fileName, L"$Recycle.Bin") == 0)
+ {
+ char s[256];
+ sprintf(s, "SPEC i = %3d, attr = %7x", _attribMap.Size(), attrib);
+ OutputDebugStringA(s);
+ OutputDebugStringW(fileName);
+ }
+ */
+
+ if ((attrib & FILE_ATTRIBUTE_DIRECTORY) != 0 || dotPos < 0)
+ {
+ unsigned insertPos = 0;
+ const int index = FindInSorted_Attrib(_attribMap, attrib, insertPos);
+ if (index >= 0)
+ {
+ // if (typeName) *typeName = _attribMap[index].TypeName;
+ return _attribMap[(unsigned)index].IconIndex;
+ }
+ CAttribIconPair pair;
+ GetRealIconIndex(
+ #ifdef UNDER_CE
+ FTEXT("\\")
+ #endif
+ FTEXT("__DIR__")
+ , attrib, pair.IconIndex
+ // , pair.TypeName
+ );
+
+ /*
+ char s[256];
+ sprintf(s, "i = %3d, attr = %7x", _attribMap.Size(), attrib);
+ OutputDebugStringA(s);
+ */
+
+ pair.Attrib = attrib;
+ _attribMap.Insert(insertPos, pair);
+ // if (typeName) *typeName = pair.TypeName;
+ return pair.IconIndex;
+ }
+
+ const wchar_t *ext = fileName + dotPos + 1;
+ unsigned insertPos = 0;
+ const int index = FindInSorted_Ext(_extMap, ext, insertPos);
+ if (index >= 0)
+ {
+ const CExtIconPair &pa = _extMap[index];
+ // if (typeName) *typeName = pa.TypeName;
+ return pa.IconIndex;
+ }
+
+ for (i = 0;; i++)
+ {
+ const wchar_t c = ext[i];
+ if (c == 0)
+ break;
+ if (c < L'0' || c > L'9')
+ break;
+ }
+ if (i != 0 && ext[i] == 0)
+ {
+ // GetRealIconIndex is too slow for big number of split extensions: .001, .002, .003
+ if (!SplitIconIndex_Defined)
+ {
+ GetRealIconIndex(
+ #ifdef UNDER_CE
+ FTEXT("\\")
+ #endif
+ FTEXT("__FILE__.001"), 0, SplitIconIndex);
+ SplitIconIndex_Defined = true;
+ }
+ return SplitIconIndex;
+ }
+
+ CExtIconPair pair;
+ pair.Ext = ext;
+ GetRealIconIndex(us2fs(fileName + dotPos), attrib, pair.IconIndex);
+ _extMap.Insert(insertPos, pair);
+ // if (typeName) *typeName = pair.TypeName;
+ return pair.IconIndex;
+}
+
+/*
+int CExtToIconMap::GetIconIndex(DWORD attrib, const UString &fileName)
+{
+ return GetIconIndex(attrib, fileName, NULL);
+}
+*/
+
+HIMAGELIST GetSysImageList(bool smallIcons)
+{
+ SHFILEINFO shellInfo;
+ return (HIMAGELIST)SHGetFileInfo(TEXT(""),
+ FILE_ATTRIBUTE_NORMAL |
+ FILE_ATTRIBUTE_DIRECTORY,
+ &shellInfo, sizeof(shellInfo),
+ SHGFI_USEFILEATTRIBUTES |
+ SHGFI_SYSICONINDEX |
+ (smallIcons ? SHGFI_SMALLICON : SHGFI_ICON));
+}
diff --git a/CPP/7zip/UI/FileManager/SysIconUtils.h b/CPP/7zip/UI/FileManager/SysIconUtils.h
index 2eedc4b..1d34ef6 100644
--- a/CPP/7zip/UI/FileManager/SysIconUtils.h
+++ b/CPP/7zip/UI/FileManager/SysIconUtils.h
@@ -1,62 +1,55 @@
-// SysIconUtils.h
-
-#ifndef __SYS_ICON_UTILS_H
-#define __SYS_ICON_UTILS_H
-
-#include "../../../Common/MyWindows.h"
-
-#include <commctrl.h>
-
-#include "../../../Common/MyString.h"
-
-struct CExtIconPair
-{
- UString Ext;
- int IconIndex;
- // UString TypeName;
-
- // int Compare(const CExtIconPair &a) const { return MyStringCompareNoCase(Ext, a.Ext); }
-};
-
-struct CAttribIconPair
-{
- DWORD Attrib;
- int IconIndex;
- // UString TypeName;
-
- // int Compare(const CAttribIconPair &a) const { return Ext.Compare(a.Ext); }
-};
-
-class CExtToIconMap
-{
-public:
- CRecordVector<CAttribIconPair> _attribMap;
- CObjectVector<CExtIconPair> _extMap;
- int SplitIconIndex;
- int SplitIconIndex_Defined;
-
- CExtToIconMap(): SplitIconIndex_Defined(false) {}
-
- void Clear()
- {
- SplitIconIndex_Defined = false;
- _extMap.Clear();
- _attribMap.Clear();
- }
- int GetIconIndex(DWORD attrib, const wchar_t *fileName /* , UString *typeName */);
- // int GetIconIndex(DWORD attrib, const UString &fileName);
-};
-
-DWORD_PTR GetRealIconIndex(CFSTR path, DWORD attrib, int &iconIndex);
-int GetIconIndexForCSIDL(int csidl);
-
-inline HIMAGELIST GetSysImageList(bool smallIcons)
-{
- SHFILEINFO shellInfo;
- return (HIMAGELIST)SHGetFileInfo(TEXT(""),
- FILE_ATTRIBUTE_NORMAL | FILE_ATTRIBUTE_DIRECTORY,
- &shellInfo, sizeof(shellInfo),
- SHGFI_USEFILEATTRIBUTES | SHGFI_SYSICONINDEX | (smallIcons ? SHGFI_SMALLICON : SHGFI_ICON));
-}
-
-#endif
+// SysIconUtils.h
+
+#ifndef ZIP7_INC_SYS_ICON_UTILS_H
+#define ZIP7_INC_SYS_ICON_UTILS_H
+
+#include "../../../Common/MyWindows.h"
+
+#include <CommCtrl.h>
+
+#include "../../../Common/MyString.h"
+
+struct CExtIconPair
+{
+ UString Ext;
+ int IconIndex;
+ // UString TypeName;
+
+ // int Compare(const CExtIconPair &a) const { return MyStringCompareNoCase(Ext, a.Ext); }
+};
+
+struct CAttribIconPair
+{
+ DWORD Attrib;
+ int IconIndex;
+ // UString TypeName;
+
+ // int Compare(const CAttribIconPair &a) const { return Ext.Compare(a.Ext); }
+};
+
+class CExtToIconMap
+{
+public:
+ CRecordVector<CAttribIconPair> _attribMap;
+ CObjectVector<CExtIconPair> _extMap;
+ int SplitIconIndex;
+ int SplitIconIndex_Defined;
+
+ CExtToIconMap(): SplitIconIndex_Defined(false) {}
+
+ void Clear()
+ {
+ SplitIconIndex_Defined = false;
+ _extMap.Clear();
+ _attribMap.Clear();
+ }
+ int GetIconIndex(DWORD attrib, const wchar_t *fileName /* , UString *typeName */);
+ // int GetIconIndex(DWORD attrib, const UString &fileName);
+};
+
+DWORD_PTR GetRealIconIndex(CFSTR path, DWORD attrib, int &iconIndex);
+int GetIconIndexForCSIDL(int csidl);
+
+HIMAGELIST GetSysImageList(bool smallIcons);
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/SystemPage.cpp b/CPP/7zip/UI/FileManager/SystemPage.cpp
new file mode 100644
index 0000000..09d8a72
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SystemPage.cpp
@@ -0,0 +1,472 @@
+// SystemPage.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/MyWindows.h"
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <shlobj.h>
+#else
+#include <ShlObj.h>
+#endif
+
+#include "../../../Common/Defs.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/ErrorMsg.h"
+
+#include "HelpUtils.h"
+#include "IFolder.h"
+#include "LangUtils.h"
+#include "PropertyNameRes.h"
+#include "SystemPage.h"
+#include "SystemPageRes.h"
+
+using namespace NWindows;
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+#ifdef Z7_LANG
+static const UInt32 kLangIDs[] =
+{
+ IDT_SYSTEM_ASSOCIATE
+};
+#endif
+
+#define kSystemTopic "FM/options.htm#system"
+
+CSysString CModifiedExtInfo::GetString() const
+{
+ const char *s;
+ if (State == kExtState_7Zip)
+ s = "7-Zip";
+ else if (State == kExtState_Clear)
+ s = "";
+ else if (Other7Zip)
+ s = "[7-Zip]";
+ else
+ return ProgramKey;
+ return CSysString (s);
+}
+
+
+int CSystemPage::AddIcon(const UString &iconPath, int iconIndex)
+{
+ if (iconPath.IsEmpty())
+ return -1;
+ if (iconIndex == -1)
+ iconIndex = 0;
+
+ HICON hicon;
+
+ #ifdef UNDER_CE
+ ExtractIconExW(iconPath, iconIndex, NULL, &hicon, 1);
+ if (!hicon)
+ #else
+ // we expand path from REG_EXPAND_SZ registry item.
+ UString path;
+ const DWORD size = MAX_PATH + 10;
+ const DWORD needLen = ::ExpandEnvironmentStringsW(iconPath, path.GetBuf(size + 2), size);
+ path.ReleaseBuf_CalcLen(size);
+ if (needLen == 0 || needLen >= size)
+ path = iconPath;
+ const UINT num = ExtractIconExW(path, iconIndex, NULL, &hicon, 1);
+ if (num != 1 || !hicon)
+ #endif
+ return -1;
+
+ _imageList.AddIcon(hicon);
+ DestroyIcon(hicon);
+ return (int)(_numIcons++);
+}
+
+
+void CSystemPage::RefreshListItem(unsigned group, unsigned listIndex)
+{
+ const CAssoc &assoc = _items[GetRealIndex(listIndex)];
+ _listView.SetSubItem(listIndex, group + 1, assoc.Pair[group].GetString());
+ LVITEMW newItem;
+ memset(&newItem, 0, sizeof(newItem));
+ newItem.iItem = (int)listIndex;
+ newItem.mask = LVIF_IMAGE;
+ newItem.iImage = assoc.GetIconIndex();
+ _listView.SetItem(&newItem);
+}
+
+
+void CSystemPage::ChangeState(unsigned group, const CUIntVector &indices)
+{
+ if (indices.IsEmpty())
+ return;
+
+ bool thereAreClearItems = false;
+ unsigned counters[3] = { 0, 0, 0 };
+
+ unsigned i;
+ for (i = 0; i < indices.Size(); i++)
+ {
+ const CModifiedExtInfo &mi = _items[GetRealIndex(indices[i])].Pair[group];
+ int state = kExtState_7Zip;
+ if (mi.State == kExtState_7Zip)
+ state = kExtState_Clear;
+ else if (mi.State == kExtState_Clear)
+ {
+ thereAreClearItems = true;
+ if (mi.Other)
+ state = kExtState_Other;
+ }
+ counters[state]++;
+ }
+
+ int state = kExtState_Clear;
+ if (counters[kExtState_Other] != 0)
+ state = kExtState_Other;
+ else if (counters[kExtState_7Zip] != 0)
+ state = kExtState_7Zip;
+
+ for (i = 0; i < indices.Size(); i++)
+ {
+ unsigned listIndex = indices[i];
+ CAssoc &assoc = _items[GetRealIndex(listIndex)];
+ CModifiedExtInfo &mi = assoc.Pair[group];
+ bool change = false;
+
+ switch (state)
+ {
+ case kExtState_Clear: change = true; break;
+ case kExtState_Other: change = mi.Other; break;
+ default: change = !(mi.Other && thereAreClearItems); break;
+ }
+
+ if (change)
+ {
+ mi.State = state;
+ RefreshListItem(group, listIndex);
+ }
+ }
+
+ _needSave = true;
+ Changed();
+}
+
+
+bool CSystemPage::OnInit()
+{
+ _needSave = false;
+
+#ifdef Z7_LANG
+ LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
+#endif
+
+ _listView.Attach(GetItem(IDL_SYSTEM_ASSOCIATE));
+ _listView.SetUnicodeFormat();
+ DWORD newFlags = LVS_EX_FULLROWSELECT;
+ _listView.SetExtendedListViewStyle(newFlags, newFlags);
+
+ _numIcons = 0;
+ _imageList.Create(16, 16, ILC_MASK | ILC_COLOR32, 0, 0);
+
+ _listView.SetImageList(_imageList, LVSIL_SMALL);
+
+ _listView.InsertColumn(0, LangString(IDS_PROP_FILE_TYPE), 72);
+
+ UString s;
+
+ #if NUM_EXT_GROUPS == 1
+ s = "Program";
+ #else
+ #ifndef UNDER_CE
+ const unsigned kSize = 256;
+ BOOL res;
+
+ DWORD size = kSize;
+
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ AString s2;
+ res = GetUserNameA(s2.GetBuf(size), &size);
+ s2.ReleaseBuf_CalcLen(MyMin((unsigned)size, kSize));
+ s = GetUnicodeString(s2);
+ }
+ else
+ #endif
+ {
+ res = GetUserNameW(s.GetBuf(size), &size);
+ s.ReleaseBuf_CalcLen(MyMin((unsigned)size, kSize));
+ }
+
+ if (!res)
+ #endif
+ s = "Current User";
+ #endif
+
+ LV_COLUMNW ci;
+ ci.mask = LVCF_TEXT | LVCF_FMT | LVCF_WIDTH | LVCF_SUBITEM;
+ ci.cx = 128;
+ ci.fmt = LVCFMT_CENTER;
+ ci.pszText = s.Ptr_non_const();
+ ci.iSubItem = 1;
+ _listView.InsertColumn(1, &ci);
+
+ #if NUM_EXT_GROUPS > 1
+ {
+ LangString(IDS_SYSTEM_ALL_USERS, s);
+ ci.pszText = s.Ptr_non_const();
+ ci.iSubItem = 2;
+ _listView.InsertColumn(2, &ci);
+ }
+ #endif
+
+ _extDB.Read();
+ _items.Clear();
+
+ FOR_VECTOR (i, _extDB.Exts)
+ {
+ const CExtPlugins &extInfo = _extDB.Exts[i];
+
+ LVITEMW item;
+ item.iItem = (int)i;
+ item.mask = LVIF_TEXT | LVIF_PARAM | LVIF_IMAGE;
+ item.lParam = (LPARAM)i;
+ item.iSubItem = 0;
+ // ListView always uses internal iImage that is 0 by default?
+ // so we always use LVIF_IMAGE.
+ item.iImage = -1;
+ item.pszText = extInfo.Ext.Ptr_non_const();
+
+ CAssoc assoc;
+ const CPluginToIcon &plug = extInfo.Plugins[0];
+ assoc.SevenZipImageIndex = AddIcon(plug.IconPath, plug.IconIndex);
+
+ CSysString texts[NUM_EXT_GROUPS];
+ unsigned g;
+ for (g = 0; g < NUM_EXT_GROUPS; g++)
+ {
+ CModifiedExtInfo &mi = assoc.Pair[g];
+ mi.ReadFromRegistry(GetHKey(g), GetSystemString(extInfo.Ext));
+ mi.SetState(plug.IconPath);
+ mi.ImageIndex = AddIcon(mi.IconPath, mi.IconIndex);
+ texts[g] = mi.GetString();
+ }
+ item.iImage = assoc.GetIconIndex();
+ const int itemIndex = _listView.InsertItem(&item);
+ for (g = 0; g < NUM_EXT_GROUPS; g++)
+ _listView.SetSubItem((unsigned)itemIndex, 1 + g, texts[g]);
+ _items.Add(assoc);
+ }
+
+ if (_listView.GetItemCount() > 0)
+ _listView.SetItemState(0, LVIS_FOCUSED, LVIS_FOCUSED);
+
+ return CPropertyPage::OnInit();
+}
+
+
+static UString GetProgramCommand()
+{
+ UString s ('\"');
+ s += fs2us(NDLL::GetModuleDirPrefix());
+ s += "7zFM.exe\" \"%1\"";
+ return s;
+}
+
+
+LONG CSystemPage::OnApply()
+{
+ if (!_needSave)
+ return PSNRET_NOERROR;
+
+ const UString command = GetProgramCommand();
+
+ LONG res = 0;
+
+ FOR_VECTOR (listIndex, _extDB.Exts)
+ {
+ unsigned realIndex = GetRealIndex(listIndex);
+ const CExtPlugins &extInfo = _extDB.Exts[realIndex];
+ CAssoc &assoc = _items[realIndex];
+
+ for (unsigned g = 0; g < NUM_EXT_GROUPS; g++)
+ {
+ CModifiedExtInfo &mi = assoc.Pair[g];
+ HKEY key = GetHKey(g);
+
+ if (mi.OldState != mi.State)
+ {
+ LONG res2 = 0;
+
+ if (mi.State == kExtState_7Zip)
+ {
+ UString title = extInfo.Ext;
+ title += " Archive";
+ const CPluginToIcon &plug = extInfo.Plugins[0];
+ res2 = NRegistryAssoc::AddShellExtensionInfo(key, GetSystemString(extInfo.Ext),
+ title, command, plug.IconPath, plug.IconIndex);
+ }
+ else if (mi.State == kExtState_Clear)
+ res2 = NRegistryAssoc::DeleteShellExtensionInfo(key, GetSystemString(extInfo.Ext));
+
+ if (res == 0)
+ res = res2;
+ if (res2 == 0)
+ mi.OldState = mi.State;
+
+ mi.State = mi.OldState;
+ RefreshListItem(g, listIndex);
+ }
+ }
+ }
+
+ #ifndef UNDER_CE
+ SHChangeNotify(SHCNE_ASSOCCHANGED, SHCNF_IDLIST, NULL, NULL);
+ #endif
+
+ WasChanged = true;
+
+ _needSave = false;
+
+ if (res != 0)
+ MessageBoxW(*this, NError::MyFormatMessage(res), L"7-Zip", MB_ICONERROR);
+
+ return PSNRET_NOERROR;
+}
+
+
+void CSystemPage::OnNotifyHelp()
+{
+ ShowHelpWindow(kSystemTopic);
+}
+
+
+bool CSystemPage::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ switch (buttonID)
+ {
+ /*
+ case IDC_SYSTEM_SELECT_ALL:
+ _listView.SelectAll();
+ return true;
+ */
+ case IDB_SYSTEM_CURRENT:
+ case IDB_SYSTEM_ALL:
+ ChangeState(buttonID == IDB_SYSTEM_CURRENT ? 0 : 1);
+ return true;
+ }
+ return CPropertyPage::OnButtonClicked(buttonID, buttonHWND);
+}
+
+
+bool CSystemPage::OnNotify(UINT controlID, LPNMHDR lParam)
+{
+ if (lParam->hwndFrom == HWND(_listView))
+ {
+ switch (lParam->code)
+ {
+ case NM_RETURN:
+ {
+ ChangeState(0);
+ return true;
+ }
+
+ case NM_CLICK:
+ {
+ #ifdef UNDER_CE
+ NMLISTVIEW *item = (NMLISTVIEW *)lParam;
+ #else
+ NMITEMACTIVATE *item = (NMITEMACTIVATE *)lParam;
+ if (item->uKeyFlags == 0)
+ #endif
+ {
+ if (item->iItem >= 0)
+ {
+ // unsigned realIndex = GetRealIndex(item->iItem);
+ if (item->iSubItem >= 1 && item->iSubItem <= 2)
+ {
+ CUIntVector indices;
+ indices.Add((unsigned)item->iItem);
+ ChangeState(item->iSubItem < 2 ? 0 : 1, indices);
+ }
+ }
+ }
+ break;
+ }
+
+ case LVN_KEYDOWN:
+ {
+ if (OnListKeyDown(LPNMLVKEYDOWN(lParam)))
+ return true;
+ break;
+ }
+
+ /*
+ case NM_RCLICK:
+ case NM_DBLCLK:
+ case LVN_BEGINRDRAG:
+ // PostMessage(kRefreshpluginsListMessage, 0);
+ PostMessage(kUpdateDatabase, 0);
+ break;
+ */
+ }
+ }
+ return CPropertyPage::OnNotify(controlID, lParam);
+}
+
+
+void CSystemPage::ChangeState(unsigned group)
+{
+ CUIntVector indices;
+
+ int itemIndex = -1;
+ while ((itemIndex = _listView.GetNextSelectedItem(itemIndex)) != -1)
+ indices.Add((unsigned)itemIndex);
+
+ if (indices.IsEmpty())
+ FOR_VECTOR (i, _items)
+ indices.Add(i);
+
+ ChangeState(group, indices);
+}
+
+
+bool CSystemPage::OnListKeyDown(LPNMLVKEYDOWN keyDownInfo)
+{
+ bool ctrl = IsKeyDown(VK_CONTROL);
+ bool alt = IsKeyDown(VK_MENU);
+
+ if (alt)
+ return false;
+
+ if ((ctrl && keyDownInfo->wVKey == 'A')
+ || (!ctrl && keyDownInfo->wVKey == VK_MULTIPLY))
+ {
+ _listView.SelectAll();
+ return true;
+ }
+
+ switch (keyDownInfo->wVKey)
+ {
+ case VK_SPACE:
+ case VK_ADD:
+ case VK_SUBTRACT:
+ case VK_SEPARATOR:
+ case VK_DIVIDE:
+
+ #ifndef UNDER_CE
+ case VK_OEM_PLUS:
+ case VK_OEM_MINUS:
+ #endif
+
+ if (!ctrl)
+ {
+ ChangeState(keyDownInfo->wVKey == VK_SPACE ? 0 : 1);
+ return true;
+ }
+ break;
+ }
+
+ return false;
+}
diff --git a/CPP/7zip/UI/FileManager/SystemPage.h b/CPP/7zip/UI/FileManager/SystemPage.h
new file mode 100644
index 0000000..6f2ed0c
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SystemPage.h
@@ -0,0 +1,126 @@
+// SystemPage.h
+
+#ifndef ZIP7_INC_SYSTEM_PAGE_H
+#define ZIP7_INC_SYSTEM_PAGE_H
+
+#include "../../../Windows/Control/ImageList.h"
+#include "../../../Windows/Control/ListView.h"
+#include "../../../Windows/Control/PropertyPage.h"
+
+#include "FilePlugins.h"
+#include "RegistryAssociations.h"
+
+enum EExtState
+{
+ kExtState_Clear = 0,
+ kExtState_Other,
+ kExtState_7Zip
+};
+
+struct CModifiedExtInfo: public NRegistryAssoc::CShellExtInfo
+{
+ int OldState;
+ int State;
+ int ImageIndex;
+ bool Other;
+ bool Other7Zip;
+
+ CModifiedExtInfo(): ImageIndex(-1) {}
+
+ CSysString GetString() const;
+
+ void SetState(const UString &iconPath)
+ {
+ State = kExtState_Clear;
+ Other = false;
+ Other7Zip = false;
+ if (!ProgramKey.IsEmpty())
+ {
+ State = kExtState_Other;
+ Other = true;
+ if (IsIt7Zip())
+ {
+ Other7Zip = !iconPath.IsEqualTo_NoCase(IconPath);
+ if (!Other7Zip)
+ {
+ State = kExtState_7Zip;
+ Other = false;
+ }
+ }
+ }
+ OldState = State;
+ }
+};
+
+struct CAssoc
+{
+ CModifiedExtInfo Pair[2];
+ int SevenZipImageIndex;
+
+ int GetIconIndex() const
+ {
+ for (unsigned i = 0; i < 2; i++)
+ {
+ const CModifiedExtInfo &pair = Pair[i];
+ if (pair.State == kExtState_Clear)
+ continue;
+ if (pair.State == kExtState_7Zip)
+ return SevenZipImageIndex;
+ if (pair.ImageIndex != -1)
+ return pair.ImageIndex;
+ }
+ return -1;
+ }
+};
+
+#ifdef UNDER_CE
+ #define NUM_EXT_GROUPS 1
+#else
+ #define NUM_EXT_GROUPS 2
+#endif
+
+class CSystemPage: public NWindows::NControl::CPropertyPage
+{
+ CExtDatabase _extDB;
+ CObjectVector<CAssoc> _items;
+
+ unsigned _numIcons;
+ NWindows::NControl::CImageList _imageList;
+ NWindows::NControl::CListView _listView;
+
+ bool _needSave;
+
+ HKEY GetHKey(unsigned
+ #if NUM_EXT_GROUPS != 1
+ group
+ #endif
+ ) const
+ {
+ #if NUM_EXT_GROUPS == 1
+ return HKEY_CLASSES_ROOT;
+ #else
+ return group == 0 ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE;
+ #endif
+ }
+
+ int AddIcon(const UString &path, int iconIndex);
+ unsigned GetRealIndex(unsigned listIndex) const { return listIndex; }
+ void RefreshListItem(unsigned group, unsigned listIndex);
+ void ChangeState(unsigned group, const CUIntVector &indices);
+ void ChangeState(unsigned group);
+
+ bool OnListKeyDown(LPNMLVKEYDOWN keyDownInfo);
+
+public:
+ bool WasChanged;
+
+ CSystemPage(): WasChanged(false) {}
+
+ virtual bool OnInit() Z7_override;
+ virtual void OnNotifyHelp() Z7_override;
+ virtual bool OnNotify(UINT controlID, LPNMHDR lParam) Z7_override;
+ virtual LONG OnApply() Z7_override;
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/SystemPage.rc b/CPP/7zip/UI/FileManager/SystemPage.rc
new file mode 100644
index 0000000..3bb143a
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SystemPage.rc
@@ -0,0 +1,43 @@
+#include "SystemPageRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 240
+#define yc 252
+
+IDD_SYSTEM DIALOG 0, 0, xs, ys MY_PAGE_STYLE MY_FONT
+CAPTION "System"
+BEGIN
+ LTEXT "Associate 7-Zip with:", IDT_SYSTEM_ASSOCIATE, m, m, xc, 8
+ PUSHBUTTON "+", IDB_SYSTEM_CURRENT, 80, m + 12, 40, bys
+ PUSHBUTTON "+", IDB_SYSTEM_ALL, 166, m + 12, 40, bys
+ CONTROL "List1", IDL_SYSTEM_ASSOCIATE, "SysListView32",
+ LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,
+ m, m + 32, xc, (yc - 32)
+END
+
+#ifdef UNDER_CE
+
+#undef m
+#undef xc
+#undef yc
+
+#define m 4
+#define xc (SMALL_PAGE_SIZE_X + 8)
+#define yc (128 + 8)
+
+IDD_SYSTEM_2 DIALOG 0, 0, xs, ys MY_PAGE_STYLE MY_FONT
+CAPTION "System"
+BEGIN
+ LTEXT "Associate 7-Zip with:", IDT_SYSTEM_ASSOCIATE, m, m, xc, 8
+ PUSHBUTTON "+", IDB_SYSTEM_CURRENT, 60, m + 12, 40, bys
+ CONTROL "List1", IDL_SYSTEM_ASSOCIATE, "SysListView32",
+ LVS_REPORT | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS | LVS_NOSORTHEADER | WS_BORDER | WS_TABSTOP,
+ m, m + 32, xc, (yc - 32)
+END
+
+#endif
+
+STRINGTABLE
+BEGIN
+ IDS_SYSTEM_ALL_USERS "All users"
+END
diff --git a/CPP/7zip/UI/FileManager/SystemPageRes.h b/CPP/7zip/UI/FileManager/SystemPageRes.h
new file mode 100644
index 0000000..c894448
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/SystemPageRes.h
@@ -0,0 +1,9 @@
+#define IDD_SYSTEM 2200
+#define IDD_SYSTEM_2 12200
+
+#define IDT_SYSTEM_ASSOCIATE 2201
+#define IDS_SYSTEM_ALL_USERS 2202
+
+#define IDL_SYSTEM_ASSOCIATE 100
+#define IDB_SYSTEM_CURRENT 101
+#define IDB_SYSTEM_ALL 102
diff --git a/CPP/7zip/UI/FileManager/Test.bmp b/CPP/7zip/UI/FileManager/Test.bmp
new file mode 100644
index 0000000..ef85ba2
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Test.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/Test2.bmp b/CPP/7zip/UI/FileManager/Test2.bmp
new file mode 100644
index 0000000..99b7dbf
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/Test2.bmp
Binary files differ
diff --git a/CPP/7zip/UI/FileManager/TextPairs.cpp b/CPP/7zip/UI/FileManager/TextPairs.cpp
new file mode 100644
index 0000000..1ac7098
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/TextPairs.cpp
@@ -0,0 +1,193 @@
+// TextPairs.cpp
+
+#include "StdAfx.h"
+
+#include "TextPairs.h"
+
+static const wchar_t kNewLineChar = '\n';
+static const wchar_t kQuoteChar = '\"';
+
+static const wchar_t kBOM = (wchar_t)0xFEFF;
+
+static bool IsSeparatorChar(wchar_t c)
+{
+ return (c == ' ' || c == '\t');
+}
+
+static void RemoveCr(UString &s)
+{
+ s.RemoveChar(L'\x0D');
+}
+
+static UString GetIDString(const wchar_t *srcString, unsigned &finishPos)
+{
+ UString result;
+ bool quotes = false;
+ for (finishPos = 0;;)
+ {
+ wchar_t c = srcString[finishPos];
+ if (c == 0)
+ break;
+ finishPos++;
+ bool isSeparatorChar = IsSeparatorChar(c);
+ if (c == kNewLineChar || (isSeparatorChar && !quotes)
+ || (c == kQuoteChar && quotes))
+ break;
+ else if (c == kQuoteChar)
+ quotes = true;
+ else
+ result += c;
+ }
+ result.Trim();
+ RemoveCr(result);
+ return result;
+}
+
+static UString GetValueString(const wchar_t *srcString, unsigned &finishPos)
+{
+ UString result;
+ for (finishPos = 0;;)
+ {
+ wchar_t c = srcString[finishPos];
+ if (c == 0)
+ break;
+ finishPos++;
+ if (c == kNewLineChar)
+ break;
+ result += c;
+ }
+ result.Trim();
+ RemoveCr(result);
+ return result;
+}
+
+static bool GetTextPairs(const UString &srcString, CObjectVector<CTextPair> &pairs)
+{
+ pairs.Clear();
+ unsigned pos = 0;
+
+ if (srcString.Len() > 0)
+ {
+ if (srcString[0] == kBOM)
+ pos++;
+ }
+ while (pos < srcString.Len())
+ {
+ unsigned finishPos;
+ UString id = GetIDString((const wchar_t *)srcString + pos, finishPos);
+ pos += finishPos;
+ if (id.IsEmpty())
+ continue;
+ UString value = GetValueString((const wchar_t *)srcString + pos, finishPos);
+ pos += finishPos;
+ if (!id.IsEmpty())
+ {
+ CTextPair pair;
+ pair.ID = id;
+ pair.Value = value;
+ pairs.Add(pair);
+ }
+ }
+ return true;
+}
+
+static int ComparePairIDs(const UString &s1, const UString &s2)
+ { return MyStringCompareNoCase(s1, s2); }
+
+static int ComparePairItems(const CTextPair &p1, const CTextPair &p2)
+ { return ComparePairIDs(p1.ID, p2.ID); }
+
+static int ComparePairItems(void *const *a1, void *const *a2, void * /* param */)
+ { return ComparePairItems(**(const CTextPair *const *)a1, **(const CTextPair *const *)a2); }
+
+void CPairsStorage::Sort() { Pairs.Sort(ComparePairItems, NULL); }
+
+int CPairsStorage::FindID(const UString &id, unsigned &insertPos) const
+{
+ unsigned left = 0, right = Pairs.Size();
+ while (left != right)
+ {
+ const unsigned mid = (left + right) / 2;
+ const int compResult = ComparePairIDs(id, Pairs[mid].ID);
+ if (compResult == 0)
+ {
+ insertPos = mid; // to disable GCC warning
+ return (int)mid;
+ }
+ if (compResult < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ insertPos = left;
+ return -1;
+}
+
+int CPairsStorage::FindID(const UString &id) const
+{
+ unsigned pos;
+ return FindID(id, pos);
+}
+
+void CPairsStorage::AddPair(const CTextPair &pair)
+{
+ unsigned insertPos;
+ const int pos = FindID(pair.ID, insertPos);
+ if (pos >= 0)
+ Pairs[pos] = pair;
+ else
+ Pairs.Insert(insertPos, pair);
+}
+
+void CPairsStorage::DeletePair(const UString &id)
+{
+ const int pos = FindID(id);
+ if (pos >= 0)
+ Pairs.Delete((unsigned)pos);
+}
+
+bool CPairsStorage::GetValue(const UString &id, UString &value) const
+{
+ value.Empty();
+ const int pos = FindID(id);
+ if (pos < 0)
+ return false;
+ value = Pairs[pos].Value;
+ return true;
+}
+
+UString CPairsStorage::GetValue(const UString &id) const
+{
+ const int pos = FindID(id);
+ if (pos < 0)
+ return UString();
+ return Pairs[pos].Value;
+}
+
+bool CPairsStorage::ReadFromString(const UString &text)
+{
+ bool result = ::GetTextPairs(text, Pairs);
+ if (result)
+ Sort();
+ else
+ Pairs.Clear();
+ return result;
+}
+
+void CPairsStorage::SaveToString(UString &text) const
+{
+ FOR_VECTOR (i, Pairs)
+ {
+ const CTextPair &pair = Pairs[i];
+ bool multiWord = (pair.ID.Find(L' ') >= 0);
+ if (multiWord)
+ text += '\"';
+ text += pair.ID;
+ if (multiWord)
+ text += '\"';
+ text.Add_Space();
+ text += pair.Value;
+ text += '\x0D';
+ text.Add_LF();
+ }
+}
diff --git a/CPP/7zip/UI/FileManager/TextPairs.h b/CPP/7zip/UI/FileManager/TextPairs.h
new file mode 100644
index 0000000..d18233d
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/TextPairs.h
@@ -0,0 +1,32 @@
+// TextPairs.h
+
+#ifndef ZIP7_INC_FM_TEXT_PAIRS_H
+#define ZIP7_INC_FM_TEXT_PAIRS_H
+
+#include "../../../Common/MyString.h"
+
+struct CTextPair
+{
+ UString ID;
+ UString Value;
+};
+
+class CPairsStorage
+{
+ CObjectVector<CTextPair> Pairs;
+
+ int FindID(const UString &id, unsigned &insertPos) const;
+ int FindID(const UString &id) const;
+ void Sort();
+public:
+ void Clear() { Pairs.Clear(); }
+ bool ReadFromString(const UString &text);
+ void SaveToString(UString &text) const;
+
+ bool GetValue(const UString &id, UString &value) const;
+ UString GetValue(const UString &id) const;
+ void AddPair(const CTextPair &pair);
+ void DeletePair(const UString &id);
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/UpdateCallback100.cpp b/CPP/7zip/UI/FileManager/UpdateCallback100.cpp
new file mode 100644
index 0000000..71ad710
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/UpdateCallback100.cpp
@@ -0,0 +1,124 @@
+// UpdateCallback100.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Windows/ErrorMsg.h"
+
+#include "../GUI/resource3.h"
+
+#include "LangUtils.h"
+#include "UpdateCallback100.h"
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::ScanProgress(UInt64 /* numFolders */, UInt64 numFiles, UInt64 totalSize, const wchar_t *path, Int32 /* isDir */))
+{
+ return ProgressDialog->Sync.ScanProgress(numFiles, totalSize, us2fs(path));
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::ScanError(const wchar_t *path, HRESULT errorCode))
+{
+ ProgressDialog->Sync.AddError_Code_Name(errorCode, path);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::SetNumFiles(UInt64 numFiles))
+{
+ return ProgressDialog->Sync.Set_NumFilesTotal(numFiles);
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::SetTotal(UInt64 size))
+{
+ ProgressDialog->Sync.Set_NumBytesTotal(size);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::SetCompleted(const UInt64 *completed))
+{
+ return ProgressDialog->Sync.Set_NumBytesCur(completed);
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize))
+{
+ ProgressDialog->Sync.Set_Ratio(inSize, outSize);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::CompressOperation(const wchar_t *name))
+{
+ return SetOperation_Base(NUpdateNotifyOp::kAdd, name, false);
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::DeleteOperation(const wchar_t *name))
+{
+ return SetOperation_Base(NUpdateNotifyOp::kDelete, name, false);
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::OperationResult(Int32 /* operationResult */))
+{
+ ProgressDialog->Sync.Set_NumFilesCur(++NumFiles);
+ return S_OK;
+}
+
+void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s);
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name))
+{
+ if (opRes != NArchive::NExtract::NOperationResult::kOK)
+ {
+ UString s;
+ SetExtractErrorMessage(opRes, isEncrypted, name, s);
+ ProgressDialog->Sync.AddError_Message(s);
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::ReportUpdateOperation(UInt32 notifyOp, const wchar_t *name, Int32 isDir))
+{
+ return SetOperation_Base(notifyOp, name, IntToBool(isDir));
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::UpdateErrorMessage(const wchar_t *message))
+{
+ ProgressDialog->Sync.AddError_Message(message);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::OpenFileError(const wchar_t *path, HRESULT errorCode))
+{
+ ProgressDialog->Sync.AddError_Code_Name(errorCode, path);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::ReadingFileError(const wchar_t *path, HRESULT errorCode))
+{
+ ProgressDialog->Sync.AddError_Code_Name(errorCode, path);
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password))
+{
+ *password = NULL;
+ *passwordIsDefined = BoolToInt(PasswordIsDefined);
+ if (!PasswordIsDefined)
+ return S_OK;
+ return StringToBstr(Password, password);
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::SetTotal(const UInt64 * /* files */, const UInt64 * /* bytes */))
+{
+ return S_OK;
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::SetCompleted(const UInt64 * /* files */, const UInt64 * /* bytes */))
+{
+ return ProgressDialog->Sync.CheckStop();
+}
+
+Z7_COM7F_IMF(CUpdateCallback100Imp::CryptoGetTextPassword(BSTR *password))
+{
+ *password = NULL;
+ if (!PasswordIsDefined)
+ {
+ RINOK(ShowAskPasswordDialog())
+ }
+ return StringToBstr(Password, password);
+}
diff --git a/CPP/7zip/UI/FileManager/UpdateCallback100.h b/CPP/7zip/UI/FileManager/UpdateCallback100.h
new file mode 100644
index 0000000..5d56dfb
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/UpdateCallback100.h
@@ -0,0 +1,46 @@
+// UpdateCallback100.h
+
+#ifndef ZIP7_INC_UPDATE_CALLBACK100_H
+#define ZIP7_INC_UPDATE_CALLBACK100_H
+
+#include "../../../Common/MyCom.h"
+
+#include "../../IPassword.h"
+
+#include "../Agent/IFolderArchive.h"
+
+#include "../GUI/UpdateCallbackGUI2.h"
+
+#include "ProgressDialog2.h"
+
+class CUpdateCallback100Imp Z7_final:
+ public IFolderArchiveUpdateCallback,
+ public IFolderArchiveUpdateCallback2,
+ public IFolderScanProgress,
+ public ICryptoGetTextPassword2,
+ public ICryptoGetTextPassword,
+ public IArchiveOpenCallback,
+ public ICompressProgressInfo,
+ public CUpdateCallbackGUI2,
+ public CMyUnknownImp
+{
+ Z7_COM_UNKNOWN_IMP_7(
+ IFolderArchiveUpdateCallback,
+ IFolderArchiveUpdateCallback2,
+ IFolderScanProgress,
+ ICryptoGetTextPassword2,
+ ICryptoGetTextPassword,
+ IArchiveOpenCallback,
+ ICompressProgressInfo)
+
+ Z7_IFACE_COM7_IMP(IProgress)
+ Z7_IFACE_COM7_IMP(IFolderArchiveUpdateCallback)
+ Z7_IFACE_COM7_IMP(IFolderArchiveUpdateCallback2)
+ Z7_IFACE_COM7_IMP(IFolderScanProgress)
+ Z7_IFACE_COM7_IMP(ICryptoGetTextPassword2)
+ Z7_IFACE_COM7_IMP(ICryptoGetTextPassword)
+ Z7_IFACE_COM7_IMP(IArchiveOpenCallback)
+ Z7_IFACE_COM7_IMP(ICompressProgressInfo)
+};
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/VerCtrl.cpp b/CPP/7zip/UI/FileManager/VerCtrl.cpp
new file mode 100644
index 0000000..0c894b8
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/VerCtrl.cpp
@@ -0,0 +1,428 @@
+// VerCtrl.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/StringToInt.h"
+
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/FileFind.h"
+
+#include "App.h"
+#include "RegistryUtils.h"
+#include "OverwriteDialog.h"
+
+#include "resource.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NFind;
+using namespace NDir;
+
+static FString ConvertPath_to_Ctrl(const FString &path)
+{
+ FString s = path;
+ s.Replace(FChar(':'), FChar('_'));
+ return s;
+}
+
+struct CFileDataInfo
+{
+ CByteBuffer Data;
+ BY_HANDLE_FILE_INFORMATION Info;
+ bool IsOpen;
+
+ CFileDataInfo(): IsOpen (false) {}
+ UInt64 GetSize() const { return (((UInt64)Info.nFileSizeHigh) << 32) + Info.nFileSizeLow; }
+ bool Read(const FString &path);
+};
+
+
+bool CFileDataInfo::Read(const FString &path)
+{
+ IsOpen = false;
+ NIO::CInFile file;
+ if (!file.Open(path))
+ return false;
+ if (!file.GetFileInformation(&Info))
+ return false;
+
+ const UInt64 size = GetSize();
+ const size_t size2 = (size_t)size;
+ if (size2 != size || size2 > (1 << 28))
+ {
+ SetLastError(1);
+ return false;
+ }
+
+ Data.Alloc(size2);
+
+ size_t processedSize;
+ if (!file.ReadFull(Data, size2, processedSize))
+ return false;
+ if (processedSize != size2)
+ {
+ SetLastError(1);
+ return false;
+ }
+ IsOpen = true;
+ return true;
+}
+
+
+static bool CreateComplexDir_for_File(const FString &path)
+{
+ FString resDirPrefix;
+ FString resFileName;
+ if (!GetFullPathAndSplit(path, resDirPrefix, resFileName))
+ return false;
+ return CreateComplexDir(resDirPrefix);
+}
+
+
+static bool ParseNumberString(const FString &s, UInt32 &number)
+{
+ const FChar *end;
+ UInt64 result = ConvertStringToUInt64(s, &end);
+ if (*end != 0 || s.IsEmpty() || result > (UInt32)0x7FFFFFFF)
+ return false;
+ number = (UInt32)result;
+ return true;
+}
+
+
+static void WriteFile(const FString &path, bool createAlways, const CFileDataInfo &fdi, const CPanel &panel)
+{
+ NIO::COutFile outFile;
+ if (!outFile.Create(path, createAlways)) // (createAlways = false) means CREATE_NEW
+ {
+ panel.MessageBox_LastError();
+ return;
+ }
+ UInt32 processedSize;
+ if (!outFile.Write(fdi.Data, (UInt32)fdi.Data.Size(), processedSize))
+ {
+ panel.MessageBox_LastError();
+ return;
+ }
+ if (processedSize != fdi.Data.Size())
+ {
+ panel.MessageBox_Error(L"Write error");
+ return;
+ }
+ if (!outFile.SetTime(
+ &fdi.Info.ftCreationTime,
+ &fdi.Info.ftLastAccessTime,
+ &fdi.Info.ftLastWriteTime))
+ {
+ panel.MessageBox_LastError();
+ return;
+ }
+
+ if (!SetFileAttrib(path, fdi.Info.dwFileAttributes))
+ {
+ panel.MessageBox_LastError();
+ return;
+ }
+}
+
+
+static UInt64 FILETIME_to_UInt64(const FILETIME &ft)
+{
+ return ft.dwLowDateTime | ((UInt64)ft.dwHighDateTime << 32);
+}
+
+static void UInt64_TO_FILETIME(UInt64 v, FILETIME &ft)
+{
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+}
+
+
+void CApp::VerCtrl(unsigned id)
+{
+ const CPanel &panel = GetFocusedPanel();
+
+ if (!panel.Is_IO_FS_Folder())
+ {
+ panel.MessageBox_Error_UnsupportOperation();
+ return;
+ }
+
+ CRecordVector<UInt32> indices;
+ panel.Get_ItemIndices_Selected(indices);
+
+ if (indices.Size() != 1)
+ {
+ // panel.MessageBox_Error_UnsupportOperation();
+ return;
+ }
+
+ const FString path = us2fs(panel.GetItemFullPath(indices[0]));
+
+ UString vercPath;
+ ReadReg_VerCtrlPath(vercPath);
+ if (vercPath.IsEmpty())
+ return;
+ NName::NormalizeDirPathPrefix(vercPath);
+
+ FString dirPrefix;
+ FString fileName;
+ if (!GetFullPathAndSplit(path, dirPrefix, fileName))
+ {
+ panel.MessageBox_LastError();
+ return;
+ }
+
+ const FString dirPrefix2 = us2fs(vercPath) + ConvertPath_to_Ctrl(dirPrefix);
+ const FString path2 = dirPrefix2 + fileName;
+
+ bool sameTime = false;
+ bool sameData = false;
+ bool areIdentical = false;
+
+ CFileDataInfo fdi, fdi2;
+ if (!fdi.Read(path))
+ {
+ panel.MessageBox_LastError();
+ return;
+ }
+
+ if (fdi2.Read(path2))
+ {
+ sameData = (fdi.Data == fdi2.Data);
+ sameTime = (CompareFileTime(&fdi.Info.ftLastWriteTime, &fdi2.Info.ftLastWriteTime) == 0);
+ areIdentical = (sameData && sameTime);
+ }
+
+ const bool isReadOnly = NAttributes::IsReadOnly(fdi.Info.dwFileAttributes);
+
+ if (id == IDM_VER_EDIT)
+ {
+ if (!isReadOnly)
+ {
+ panel.MessageBox_Error(L"File is not read-only");
+ return;
+ }
+
+ if (!areIdentical)
+ {
+ if (fdi2.IsOpen)
+ {
+ NFind::CEnumerator enumerator;
+ FString d2 = dirPrefix2;
+ d2 += "_7vc";
+ d2.Add_PathSepar();
+ d2 += fileName;
+ d2.Add_PathSepar();
+ enumerator.SetDirPrefix(d2);
+ NFind::CDirEntry fi;
+ Int32 maxVal = -1;
+ while (enumerator.Next(fi))
+ {
+ UInt32 val;
+ if (!ParseNumberString(fi.Name, val))
+ continue;
+ if ((Int32)val > maxVal)
+ maxVal = (Int32)val;
+ }
+
+ UInt32 next = (UInt32)maxVal + 1;
+ if (maxVal < 0)
+ {
+ next = 1;
+ if (!::CreateComplexDir_for_File(path2))
+ {
+ panel.MessageBox_LastError();
+ return;
+ }
+ }
+
+ // we rename old file2 to some name;
+ FString path_num = d2;
+ {
+ AString t;
+ t.Add_UInt32((UInt32)next);
+ while (t.Len() < 3)
+ t.InsertAtFront('0');
+ path_num += t;
+ }
+
+ if (maxVal < 0)
+ {
+ if (!::CreateComplexDir_for_File(path_num))
+ {
+ panel.MessageBox_LastError();
+ return;
+ }
+ }
+
+ if (!NDir::MyMoveFile(path2, path_num))
+ {
+ panel.MessageBox_LastError();
+ return;
+ }
+ }
+ else
+ {
+ if (!::CreateComplexDir_for_File(path2))
+ {
+ panel.MessageBox_LastError();
+ return;
+ }
+ }
+ /*
+ if (!::CopyFile(fs2fas(path), fs2fas(path2), TRUE))
+ {
+ panel.MessageBox_LastError();
+ return;
+ }
+ */
+ WriteFile(path2,
+ false, // (createAlways = false) means CREATE_NEW
+ fdi, panel);
+ }
+
+ if (!SetFileAttrib(path, fdi.Info.dwFileAttributes & ~(DWORD)FILE_ATTRIBUTE_READONLY))
+ {
+ panel.MessageBox_LastError();
+ return;
+ }
+
+ return;
+ }
+
+ if (isReadOnly)
+ {
+ panel.MessageBox_Error(L"File is read-only");
+ return;
+ }
+
+ if (id == IDM_VER_COMMIT)
+ {
+ if (sameData)
+ {
+ if (!sameTime)
+ {
+ panel.MessageBox_Error(
+ L"Same data, but different timestamps.\n"
+ L"Use `Revert` to recover timestamp.");
+ return;
+ }
+ }
+
+ const UInt64 timeStampOriginal = FILETIME_to_UInt64(fdi.Info.ftLastWriteTime);
+ UInt64 timeStamp2 = 0;
+ if (fdi2.IsOpen)
+ timeStamp2 = FILETIME_to_UInt64(fdi2.Info.ftLastWriteTime);
+
+ if (timeStampOriginal > timeStamp2)
+ {
+ const UInt64 k_Ntfs_prec = 10000000;
+ UInt64 timeStamp = timeStampOriginal;
+ const UInt32 k_precs[] = { 60 * 60, 60, 2, 1 };
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_precs); i++)
+ {
+ timeStamp = timeStampOriginal;
+ const UInt64 prec = k_Ntfs_prec * k_precs[i];
+ // timeStamp += prec - 1; // for rounding up
+ timeStamp /= prec;
+ timeStamp *= prec;
+ if (timeStamp > timeStamp2)
+ break;
+ }
+
+ if (timeStamp != timeStampOriginal
+ && timeStamp > timeStamp2)
+ {
+ FILETIME mTime;
+ UInt64_TO_FILETIME(timeStamp, mTime);
+ // NDir::SetFileAttrib(path, 0);
+ {
+ NIO::COutFile outFile;
+ if (!outFile.Open(path, OPEN_EXISTING))
+ {
+ panel.MessageBox_LastError();
+ return;
+ // if (::GetLastError() != ERROR_SUCCESS)
+ // throw "open error";
+ }
+ else
+ {
+ const UInt64 cTime = FILETIME_to_UInt64(fdi.Info.ftCreationTime);
+ if (cTime > timeStamp)
+ outFile.SetTime(&mTime, NULL, &mTime);
+ else
+ outFile.SetMTime(&mTime);
+ }
+ }
+ }
+ }
+
+ if (!SetFileAttrib(path, fdi.Info.dwFileAttributes | FILE_ATTRIBUTE_READONLY))
+ {
+ panel.MessageBox_LastError();
+ return;
+ }
+ return;
+ }
+
+ if (id == IDM_VER_REVERT)
+ {
+ if (!fdi2.IsOpen)
+ {
+ panel.MessageBox_Error(L"No file to revert");
+ return;
+ }
+ if (!sameData || !sameTime)
+ {
+ if (!sameData)
+ {
+ /*
+ UString m;
+ m = "Are you sure you want to revert file ?";
+ m.Add_LF();
+ m += path;
+ if (::MessageBoxW(panel.GetParent(), m, L"Version Control: File Revert", MB_OKCANCEL | MB_ICONQUESTION) != IDOK)
+ return;
+ */
+ COverwriteDialog dialog;
+
+ dialog.OldFileInfo.SetTime(&fdi.Info.ftLastWriteTime);
+ dialog.OldFileInfo.SetSize(fdi.GetSize());
+ dialog.OldFileInfo.Name = fs2us(path);
+
+ dialog.NewFileInfo.SetTime(&fdi2.Info.ftLastWriteTime);
+ dialog.NewFileInfo.SetSize(fdi2.GetSize());
+ dialog.NewFileInfo.Name = fs2us(path2);
+
+ dialog.ShowExtraButtons = false;
+ dialog.DefaultButton_is_NO = true;
+
+ INT_PTR writeAnswer = dialog.Create(panel.GetParent());
+
+ if (writeAnswer != IDYES)
+ return;
+ }
+
+ WriteFile(path,
+ true, // (createAlways = true) means CREATE_ALWAYS
+ fdi2, panel);
+ }
+ else
+ {
+ if (!SetFileAttrib(path, fdi2.Info.dwFileAttributes | FILE_ATTRIBUTE_READONLY))
+ {
+ panel.MessageBox_LastError();
+ return;
+ }
+ }
+ return;
+ }
+
+ // if (id == IDM_VER_DIFF)
+ {
+ if (!fdi2.IsOpen)
+ return;
+ DiffFiles(fs2us(path2), fs2us(path));
+ }
+}
diff --git a/CPP/7zip/UI/FileManager/ViewSettings.cpp b/CPP/7zip/UI/FileManager/ViewSettings.cpp
new file mode 100644
index 0000000..3d64602
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ViewSettings.cpp
@@ -0,0 +1,314 @@
+// ViewSettings.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/Registry.h"
+#include "../../../Windows/Synchronization.h"
+
+#include "ViewSettings.h"
+
+using namespace NWindows;
+using namespace NRegistry;
+
+#define REG_PATH_FM TEXT("Software") TEXT(STRING_PATH_SEPARATOR) TEXT("7-Zip") TEXT(STRING_PATH_SEPARATOR) TEXT("FM")
+
+static LPCTSTR const kCUBasePath = REG_PATH_FM;
+static LPCTSTR const kCulumnsKeyName = REG_PATH_FM TEXT(STRING_PATH_SEPARATOR) TEXT("Columns");
+
+static LPCTSTR const kPositionValueName = TEXT("Position");
+static LPCTSTR const kPanelsInfoValueName = TEXT("Panels");
+static LPCTSTR const kToolbars = TEXT("Toolbars");
+
+static LPCWSTR const kPanelPathValueName = L"PanelPath";
+
+static LPCTSTR const kListMode = TEXT("ListMode");
+static LPCTSTR const kFolderHistoryValueName = TEXT("FolderHistory");
+static LPCTSTR const kFastFoldersValueName = TEXT("FolderShortcuts");
+static LPCTSTR const kCopyHistoryValueName = TEXT("CopyHistory");
+
+static NSynchronization::CCriticalSection g_CS;
+
+#define Set32(p, v) SetUi32(((Byte *)p), v)
+#define SetBool(p, v) Set32(p, ((v) ? 1 : 0))
+
+#define Get32(p, dest) dest = GetUi32((const Byte *)p);
+#define Get32_LONG(p, dest) dest = (LONG)GetUi32((const Byte *)p);
+#define GetBool(p, dest) dest = (GetUi32(p) != 0);
+
+/*
+struct CColumnHeader
+{
+ UInt32 Version;
+ UInt32 SortID;
+ UInt32 Ascending; // bool
+};
+*/
+
+static const UInt32 kListViewHeaderSize = 3 * 4;
+static const UInt32 kColumnInfoSize = 3 * 4;
+static const UInt32 kListViewVersion = 1;
+
+void CListViewInfo::Save(const UString &id) const
+{
+ const UInt32 dataSize = kListViewHeaderSize + kColumnInfoSize * Columns.Size();
+ CByteArr buf(dataSize);
+
+ Set32(buf, kListViewVersion)
+ Set32(buf + 4, SortID)
+ SetBool(buf + 8, Ascending)
+ FOR_VECTOR (i, Columns)
+ {
+ const CColumnInfo &column = Columns[i];
+ Byte *p = buf + kListViewHeaderSize + i * kColumnInfoSize;
+ Set32(p, column.PropID)
+ SetBool(p + 4, column.IsVisible)
+ Set32(p + 8, column.Width)
+ }
+ {
+ NSynchronization::CCriticalSectionLock lock(g_CS);
+ CKey key;
+ key.Create(HKEY_CURRENT_USER, kCulumnsKeyName);
+ key.SetValue(GetSystemString(id), (const Byte *)buf, dataSize);
+ }
+}
+
+void CListViewInfo::Read(const UString &id)
+{
+ Clear();
+ CByteBuffer buf;
+ UInt32 size;
+ {
+ NSynchronization::CCriticalSectionLock lock(g_CS);
+ CKey key;
+ if (key.Open(HKEY_CURRENT_USER, kCulumnsKeyName, KEY_READ) != ERROR_SUCCESS)
+ return;
+ if (key.QueryValue(GetSystemString(id), buf, size) != ERROR_SUCCESS)
+ return;
+ }
+ if (size < kListViewHeaderSize)
+ return;
+ UInt32 version;
+ Get32(buf, version)
+ if (version != kListViewVersion)
+ return;
+ Get32(buf + 4, SortID)
+ GetBool(buf + 8, Ascending)
+
+ IsLoaded = true;
+
+ size -= kListViewHeaderSize;
+ if (size % kColumnInfoSize != 0)
+ return;
+ unsigned numItems = size / kColumnInfoSize;
+ Columns.ClearAndReserve(numItems);
+ for (unsigned i = 0; i < numItems; i++)
+ {
+ CColumnInfo column;
+ const Byte *p = buf + kListViewHeaderSize + i * kColumnInfoSize;
+ Get32(p, column.PropID)
+ GetBool(p + 4, column.IsVisible)
+ Get32(p + 8, column.Width)
+ Columns.AddInReserved(column);
+ }
+}
+
+
+/*
+struct CWindowPosition
+{
+ RECT Rect;
+ UInt32 Maximized; // bool
+};
+
+struct CPanelsInfo
+{
+ UInt32 NumPanels;
+ UInt32 CurrentPanel;
+ UInt32 SplitterPos;
+};
+*/
+
+static const UInt32 kWindowPositionHeaderSize = 5 * 4;
+static const UInt32 kPanelsInfoHeaderSize = 3 * 4;
+
+void CWindowInfo::Save() const
+{
+ NSynchronization::CCriticalSectionLock lock(g_CS);
+ CKey key;
+ key.Create(HKEY_CURRENT_USER, kCUBasePath);
+ {
+ Byte buf[kWindowPositionHeaderSize];
+ Set32(buf, (UInt32)rect.left)
+ Set32(buf + 4, (UInt32)rect.top)
+ Set32(buf + 8, (UInt32)rect.right)
+ Set32(buf + 12, (UInt32)rect.bottom)
+ SetBool(buf + 16, maximized)
+ key.SetValue(kPositionValueName, buf, kWindowPositionHeaderSize);
+ }
+ {
+ Byte buf[kPanelsInfoHeaderSize];
+ Set32(buf, numPanels)
+ Set32(buf + 4, currentPanel)
+ Set32(buf + 8, splitterPos)
+ key.SetValue(kPanelsInfoValueName, buf, kPanelsInfoHeaderSize);
+ }
+}
+
+static bool QueryBuf(CKey &key, LPCTSTR name, CByteBuffer &buf, UInt32 dataSize)
+{
+ UInt32 size;
+ return key.QueryValue(name, buf, size) == ERROR_SUCCESS && size == dataSize;
+}
+
+void CWindowInfo::Read(bool &windowPosDefined, bool &panelInfoDefined)
+{
+ windowPosDefined = false;
+ panelInfoDefined = false;
+ NSynchronization::CCriticalSectionLock lock(g_CS);
+ CKey key;
+ if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) != ERROR_SUCCESS)
+ return;
+ CByteBuffer buf;
+ if (QueryBuf(key, kPositionValueName, buf, kWindowPositionHeaderSize))
+ {
+ Get32_LONG(buf, rect.left)
+ Get32_LONG(buf + 4, rect.top)
+ Get32_LONG(buf + 8, rect.right)
+ Get32_LONG(buf + 12, rect.bottom)
+ GetBool(buf + 16, maximized)
+ windowPosDefined = true;
+ }
+ if (QueryBuf(key, kPanelsInfoValueName, buf, kPanelsInfoHeaderSize))
+ {
+ Get32(buf, numPanels)
+ Get32(buf + 4, currentPanel)
+ Get32(buf + 8, splitterPos)
+ panelInfoDefined = true;
+ }
+ return;
+}
+
+
+static void SaveUi32Val(const TCHAR *name, UInt32 value)
+{
+ CKey key;
+ key.Create(HKEY_CURRENT_USER, kCUBasePath);
+ key.SetValue(name, value);
+}
+
+static bool ReadUi32Val(const TCHAR *name, UInt32 &value)
+{
+ CKey key;
+ if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) != ERROR_SUCCESS)
+ return false;
+ return key.QueryValue(name, value) == ERROR_SUCCESS;
+}
+
+void SaveToolbarsMask(UInt32 toolbarMask)
+{
+ SaveUi32Val(kToolbars, toolbarMask);
+}
+
+static const UInt32 kDefaultToolbarMask = ((UInt32)1 << 31) | 8 | 4 | 1;
+
+UInt32 ReadToolbarsMask()
+{
+ UInt32 mask;
+ if (!ReadUi32Val(kToolbars, mask))
+ return kDefaultToolbarMask;
+ return mask;
+}
+
+
+void CListMode::Save() const
+{
+ UInt32 t = 0;
+ for (int i = 0; i < 2; i++)
+ t |= ((Panels[i]) & 0xFF) << (i * 8);
+ SaveUi32Val(kListMode, t);
+}
+
+void CListMode::Read()
+{
+ Init();
+ UInt32 t;
+ if (!ReadUi32Val(kListMode, t))
+ return;
+ for (int i = 0; i < 2; i++)
+ {
+ Panels[i] = (t & 0xFF);
+ t >>= 8;
+ }
+}
+
+static UString GetPanelPathName(UInt32 panelIndex)
+{
+ UString s (kPanelPathValueName);
+ s.Add_UInt32(panelIndex);
+ return s;
+}
+
+void SavePanelPath(UInt32 panel, const UString &path)
+{
+ NSynchronization::CCriticalSectionLock lock(g_CS);
+ CKey key;
+ key.Create(HKEY_CURRENT_USER, kCUBasePath);
+ key.SetValue(GetPanelPathName(panel), path);
+}
+
+bool ReadPanelPath(UInt32 panel, UString &path)
+{
+ NSynchronization::CCriticalSectionLock lock(g_CS);
+ CKey key;
+ if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) != ERROR_SUCCESS)
+ return false;
+ return (key.QueryValue(GetPanelPathName(panel), path) == ERROR_SUCCESS);
+}
+
+
+static void SaveStringList(LPCTSTR valueName, const UStringVector &folders)
+{
+ NSynchronization::CCriticalSectionLock lock(g_CS);
+ CKey key;
+ key.Create(HKEY_CURRENT_USER, kCUBasePath);
+ key.SetValue_Strings(valueName, folders);
+}
+
+static void ReadStringList(LPCTSTR valueName, UStringVector &folders)
+{
+ folders.Clear();
+ NSynchronization::CCriticalSectionLock lock(g_CS);
+ CKey key;
+ if (key.Open(HKEY_CURRENT_USER, kCUBasePath, KEY_READ) == ERROR_SUCCESS)
+ key.GetValue_Strings(valueName, folders);
+}
+
+void SaveFolderHistory(const UStringVector &folders)
+ { SaveStringList(kFolderHistoryValueName, folders); }
+void ReadFolderHistory(UStringVector &folders)
+ { ReadStringList(kFolderHistoryValueName, folders); }
+
+void SaveFastFolders(const UStringVector &folders)
+ { SaveStringList(kFastFoldersValueName, folders); }
+void ReadFastFolders(UStringVector &folders)
+ { ReadStringList(kFastFoldersValueName, folders); }
+
+void SaveCopyHistory(const UStringVector &folders)
+ { SaveStringList(kCopyHistoryValueName, folders); }
+void ReadCopyHistory(UStringVector &folders)
+ { ReadStringList(kCopyHistoryValueName, folders); }
+
+void AddUniqueStringToHeadOfList(UStringVector &list, const UString &s)
+{
+ for (unsigned i = 0; i < list.Size();)
+ if (s.IsEqualTo_NoCase(list[i]))
+ list.Delete(i);
+ else
+ i++;
+ list.Insert(0, s);
+}
diff --git a/CPP/7zip/UI/FileManager/ViewSettings.h b/CPP/7zip/UI/FileManager/ViewSettings.h
new file mode 100644
index 0000000..02af0a1
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/ViewSettings.h
@@ -0,0 +1,115 @@
+// ViewSettings.h
+
+#ifndef ZIP7_INC_VIEW_SETTINGS_H
+#define ZIP7_INC_VIEW_SETTINGS_H
+
+#include "../../../Common/MyTypes.h"
+#include "../../../Common/MyString.h"
+
+struct CColumnInfo
+{
+ PROPID PropID;
+ bool IsVisible;
+ UInt32 Width;
+
+ bool IsEqual(const CColumnInfo &a) const
+ {
+ return PropID == a.PropID && IsVisible == a.IsVisible && Width == a.Width;
+ }
+};
+
+struct CListViewInfo
+{
+ CRecordVector<CColumnInfo> Columns;
+ PROPID SortID;
+ bool Ascending;
+ bool IsLoaded;
+
+ void Clear()
+ {
+ SortID = 0;
+ Ascending = true;
+ IsLoaded = false;
+ Columns.Clear();
+ }
+
+ CListViewInfo():
+ SortID(0),
+ Ascending(true),
+ IsLoaded(false)
+ {}
+
+ /*
+ int FindColumnWithID(PROPID propID) const
+ {
+ FOR_VECTOR (i, Columns)
+ if (Columns[i].PropID == propID)
+ return i;
+ return -1;
+ }
+ */
+
+ bool IsEqual(const CListViewInfo &info) const
+ {
+ if (Columns.Size() != info.Columns.Size() ||
+ SortID != info.SortID ||
+ Ascending != info.Ascending)
+ return false;
+ FOR_VECTOR (i, Columns)
+ if (!Columns[i].IsEqual(info.Columns[i]))
+ return false;
+ return true;
+ }
+
+ void Save(const UString &id) const;
+ void Read(const UString &id);
+};
+
+
+struct CWindowInfo
+{
+ RECT rect;
+ bool maximized;
+
+ UInt32 numPanels;
+ UInt32 currentPanel;
+ UInt32 splitterPos;
+
+ void Save() const;
+ void Read(bool &windowPosDefined, bool &panelInfoDefined);
+};
+
+void SaveToolbarsMask(UInt32 toolbarMask);
+UInt32 ReadToolbarsMask();
+
+const UInt32 kListMode_Report = 3;
+
+struct CListMode
+{
+ UInt32 Panels[2];
+
+ void Init() { Panels[0] = Panels[1] = kListMode_Report; }
+ CListMode() { Init(); }
+
+ void Save() const ;
+ void Read();
+};
+
+
+
+void SavePanelPath(UInt32 panel, const UString &path);
+bool ReadPanelPath(UInt32 panel, UString &path);
+
+
+void SaveFolderHistory(const UStringVector &folders);
+void ReadFolderHistory(UStringVector &folders);
+
+void SaveFastFolders(const UStringVector &folders);
+void ReadFastFolders(UStringVector &folders);
+
+void SaveCopyHistory(const UStringVector &folders);
+void ReadCopyHistory(UStringVector &folders);
+
+void AddUniqueStringToHeadOfList(UStringVector &list, const UString &s);
+
+#endif
diff --git a/CPP/7zip/UI/FileManager/makefile b/CPP/7zip/UI/FileManager/makefile
new file mode 100644
index 0000000..df08c98
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/makefile
@@ -0,0 +1,108 @@
+PROG = 7zFM.exe
+CFLAGS = $(CFLAGS) \
+ -DZ7_EXTERNAL_CODECS \
+
+!include "FM.mak"
+
+COMMON_OBJS = \
+ $O\DynLimBuf.obj \
+ $O\IntToString.obj \
+ $O\Lang.obj \
+ $O\MyString.obj \
+ $O\MyVector.obj \
+ $O\NewHandler.obj \
+ $O\Random.obj \
+ $O\StringConvert.obj \
+ $O\StringToInt.obj \
+ $O\UTFConvert.obj \
+ $O\Wildcard.obj \
+
+WIN_OBJS = $(WIN_OBJS) \
+ $O\Clipboard.obj \
+ $O\CommonDialog.obj \
+ $O\DLL.obj \
+ $O\ErrorMsg.obj \
+ $O\FileDir.obj \
+ $O\FileFind.obj \
+ $O\FileIO.obj \
+ $O\FileLink.obj \
+ $O\FileName.obj \
+ $O\MemoryGlobal.obj \
+ $O\MemoryLock.obj \
+ $O\Menu.obj \
+ $O\ProcessUtils.obj \
+ $O\PropVariant.obj \
+ $O\PropVariantConv.obj \
+ $O\Registry.obj \
+ $O\ResourceString.obj \
+ $O\Shell.obj \
+ $O\Synchronization.obj \
+ $O\System.obj \
+ $O\TimeUtils.obj \
+ $O\Window.obj \
+
+
+WIN_CTRL_OBJS = \
+ $O\ComboBox.obj \
+ $O\Dialog.obj \
+ $O\ListView.obj \
+ $O\PropertyPage.obj \
+ $O\Window2.obj \
+
+7ZIP_COMMON_OBJS = \
+ $O\CreateCoder.obj \
+ $O\FilePathAutoRename.obj \
+ $O\FileStreams.obj \
+ $O\FilterCoder.obj \
+ $O\LimitedStreams.obj \
+ $O\MethodProps.obj \
+ $O\ProgressUtils.obj \
+ $O\PropId.obj \
+ $O\StreamObjects.obj \
+ $O\StreamUtils.obj \
+ $O\UniqBlocks.obj \
+
+UI_COMMON_OBJS = \
+ $O\ArchiveExtractCallback.obj \
+ $O\ArchiveName.obj \
+ $O\ArchiveOpenCallback.obj \
+ $O\CompressCall.obj \
+ $O\DefaultName.obj \
+ $O\EnumDirItems.obj \
+ $O\ExtractingFilePath.obj \
+ $O\HashCalc.obj \
+ $O\LoadCodecs.obj \
+ $O\OpenArchive.obj \
+ $O\PropIDUtils.obj \
+ $O\SetProperties.obj \
+ $O\SortUtils.obj \
+ $O\UpdateAction.obj \
+ $O\UpdateCallback.obj \
+ $O\UpdatePair.obj \
+ $O\UpdateProduce.obj \
+ $O\WorkDir.obj \
+ $O\ZipRegistry.obj \
+
+EXPLORER_OBJS = \
+ $O\ContextMenu.obj \
+ $O\MyMessages.obj \
+ $O\RegistryContextMenu.obj \
+
+GUI_OBJS = \
+ $O\HashGUI.obj \
+ $O\UpdateCallbackGUI2.obj \
+
+COMPRESS_OBJS = \
+ $O\CopyCoder.obj \
+
+AR_COMMON_OBJS = \
+ $O\ItemNameUtils.obj \
+
+
+C_OBJS = $(C_OBJS) \
+ $O\Alloc.obj \
+ $O\CpuArch.obj \
+ $O\Sort.obj \
+ $O\Threads.obj \
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/UI/FileManager/resource.h b/CPP/7zip/UI/FileManager/resource.h
index 4666269..9d605c6 100644
--- a/CPP/7zip/UI/FileManager/resource.h
+++ b/CPP/7zip/UI/FileManager/resource.h
@@ -1,177 +1,192 @@
-#include "resourceGui.h"
-
-#define IDR_MENUBAR1 70
-#define IDM_MENU 71
-#define IDR_ACCELERATOR1 72
-
-#define IDB_ADD 100
-#define IDB_EXTRACT 101
-#define IDB_TEST 102
-#define IDB_COPY 103
-#define IDB_MOVE 104
-#define IDB_DELETE 105
-#define IDB_INFO 106
-
-#define IDB_ADD2 150
-#define IDB_EXTRACT2 151
-#define IDB_TEST2 152
-#define IDB_COPY2 153
-#define IDB_MOVE2 154
-#define IDB_DELETE2 155
-#define IDB_INFO2 156
-
-#define IDM_HASH_ALL 101
-#define IDM_CRC32 102
-#define IDM_CRC64 103
-#define IDM_SHA1 104
-#define IDM_SHA256 105
-
-#define IDM_OPEN 540
-#define IDM_OPEN_INSIDE 541
-#define IDM_OPEN_OUTSIDE 542
-#define IDM_FILE_VIEW 543
-#define IDM_FILE_EDIT 544
-#define IDM_RENAME 545
-#define IDM_COPY_TO 546
-#define IDM_MOVE_TO 547
-#define IDM_DELETE 548
-#define IDM_SPLIT 549
-#define IDM_COMBINE 550
-#define IDM_PROPERTIES 551
-#define IDM_COMMENT 552
-#define IDM_CRC 553
-#define IDM_DIFF 554
-#define IDM_CREATE_FOLDER 555
-#define IDM_CREATE_FILE 556
-// #define IDM_EXIT 557
-#define IDM_LINK 558
-#define IDM_ALT_STREAMS 559
-
-#define IDM_OPEN_INSIDE_ONE 590
-#define IDM_OPEN_INSIDE_PARSER 591
-
-#define IDM_SELECT_ALL 600
-#define IDM_DESELECT_ALL 601
-#define IDM_INVERT_SELECTION 602
-#define IDM_SELECT 603
-#define IDM_DESELECT 604
-#define IDM_SELECT_BY_TYPE 605
-#define IDM_DESELECT_BY_TYPE 606
-
-#define IDM_VIEW_LARGE_ICONS 700
-#define IDM_VIEW_SMALL_ICONS 701
-#define IDM_VIEW_LIST 702
-#define IDM_VIEW_DETAILS 703
-
-#define IDM_VIEW_ARANGE_BY_NAME 710
-#define IDM_VIEW_ARANGE_BY_TYPE 711
-#define IDM_VIEW_ARANGE_BY_DATE 712
-#define IDM_VIEW_ARANGE_BY_SIZE 713
-
-#define IDM_VIEW_ARANGE_NO_SORT 730
-#define IDM_VIEW_FLAT_VIEW 731
-#define IDM_VIEW_TWO_PANELS 732
-#define IDM_VIEW_TOOLBARS 733
-#define IDM_OPEN_ROOT_FOLDER 734
-#define IDM_OPEN_PARENT_FOLDER 735
-#define IDM_FOLDERS_HISTORY 736
-#define IDM_VIEW_REFRESH 737
-#define IDM_VIEW_AUTO_REFRESH 738
-// #define IDM_VIEW_SHOW_DELETED 739
-// #define IDM_VIEW_SHOW_STREAMS 740
-
-#define IDM_VIEW_ARCHIVE_TOOLBAR 750
-#define IDM_VIEW_STANDARD_TOOLBAR 751
-#define IDM_VIEW_TOOLBARS_LARGE_BUTTONS 752
-#define IDM_VIEW_TOOLBARS_SHOW_BUTTONS_TEXT 753
-
-#define IDM_VIEW_TIME 761
-
-#define IDS_BOOKMARK 801
-
-#define IDM_OPTIONS 900
-#define IDM_BENCHMARK 901
-#define IDM_BENCHMARK2 902
-
-#define IDM_HELP_CONTENTS 960
-#define IDM_ABOUT 961
-
-#define IDS_OPTIONS 2100
-
-#define IDS_N_SELECTED_ITEMS 3002
-
-#define IDS_FILE_EXIST 3008
-#define IDS_WANT_UPDATE_MODIFIED_FILE 3009
-#define IDS_CANNOT_UPDATE_FILE 3010
-#define IDS_CANNOT_START_EDITOR 3011
-#define IDS_VIRUS 3012
-#define IDS_MESSAGE_UNSUPPORTED_OPERATION_FOR_LONG_PATH_FOLDER 3013
-#define IDS_SELECT_ONE_FILE 3014
-#define IDS_SELECT_FILES 3015
-#define IDS_TOO_MANY_ITEMS 3016
-
-#define IDS_COPY 6000
-#define IDS_MOVE 6001
-#define IDS_COPY_TO 6002
-#define IDS_MOVE_TO 6003
-#define IDS_COPYING 6004
-#define IDS_MOVING 6005
-#define IDS_RENAMING 6006
-
-#define IDS_OPERATION_IS_NOT_SUPPORTED 6008
-#define IDS_ERROR_RENAMING 6009
-#define IDS_CONFIRM_FILE_COPY 6010
-#define IDS_WANT_TO_COPY_FILES 6011
-
-#define IDS_CONFIRM_FILE_DELETE 6100
-#define IDS_CONFIRM_FOLDER_DELETE 6101
-#define IDS_CONFIRM_ITEMS_DELETE 6102
-#define IDS_WANT_TO_DELETE_FILE 6103
-#define IDS_WANT_TO_DELETE_FOLDER 6104
-#define IDS_WANT_TO_DELETE_ITEMS 6105
-#define IDS_DELETING 6106
-#define IDS_ERROR_DELETING 6107
-#define IDS_ERROR_LONG_PATH_TO_RECYCLE 6108
-
-#define IDS_CREATE_FOLDER 6300
-#define IDS_CREATE_FILE 6301
-#define IDS_CREATE_FOLDER_NAME 6302
-#define IDS_CREATE_FILE_NAME 6303
-#define IDS_CREATE_FOLDER_DEFAULT_NAME 6304
-#define IDS_CREATE_FILE_DEFAULT_NAME 6305
-#define IDS_CREATE_FOLDER_ERROR 6306
-#define IDS_CREATE_FILE_ERROR 6307
-
-#define IDS_COMMENT 6400
-#define IDS_COMMENT2 6401
-#define IDS_SELECT 6402
-#define IDS_DESELECT 6403
-#define IDS_SELECT_MASK 6404
-
-#define IDS_PROPERTIES 6600
-#define IDS_FOLDERS_HISTORY 6601
-
-#define IDS_COMPUTER 7100
-#define IDS_NETWORK 7101
-#define IDS_DOCUMENTS 7102
-#define IDS_SYSTEM 7103
-
-#define IDS_ADD 7200
-#define IDS_EXTRACT 7201
-#define IDS_TEST 7202
-#define IDS_BUTTON_COPY 7203
-#define IDS_BUTTON_MOVE 7204
-#define IDS_BUTTON_DELETE 7205
-#define IDS_BUTTON_INFO 7206
-
-#define IDS_SPLITTING 7303
-#define IDS_SPLIT_CONFIRM_TITLE 7304
-#define IDS_SPLIT_CONFIRM_MESSAGE 7305
-#define IDS_SPLIT_VOL_MUST_BE_SMALLER 7306
-
-#define IDS_COMBINE 7400
-#define IDS_COMBINE_TO 7401
-#define IDS_COMBINING 7402
-#define IDS_COMBINE_SELECT_ONE_FILE 7403
-#define IDS_COMBINE_CANT_DETECT_SPLIT_FILE 7404
-#define IDS_COMBINE_CANT_FIND_MORE_THAN_ONE_PART 7405
+#include "resourceGui.h"
+
+#define IDR_MENUBAR1 70
+#define IDM_MENU 71
+#define IDR_ACCELERATOR1 72
+
+#define IDB_ADD 100
+#define IDB_EXTRACT 101
+#define IDB_TEST 102
+#define IDB_COPY 103
+#define IDB_MOVE 104
+#define IDB_DELETE 105
+#define IDB_INFO 106
+
+#define IDB_ADD2 150
+#define IDB_EXTRACT2 151
+#define IDB_TEST2 152
+#define IDB_COPY2 153
+#define IDB_MOVE2 154
+#define IDB_DELETE2 155
+#define IDB_INFO2 156
+
+#define IDM_HASH_ALL 101
+#define IDM_CRC32 102
+#define IDM_CRC64 103
+#define IDM_SHA1 104
+#define IDM_SHA256 105
+
+
+#define IDM_FILE 500
+#define IDM_EDIT 501
+#define IDM_VIEW 502
+#define IDM_FAVORITES 503
+#define IDM_TOOLS 504
+#define IDM_HELP 505
+
+#define IDM_OPEN 540
+#define IDM_OPEN_INSIDE 541
+#define IDM_OPEN_OUTSIDE 542
+#define IDM_FILE_VIEW 543
+#define IDM_FILE_EDIT 544
+#define IDM_RENAME 545
+#define IDM_COPY_TO 546
+#define IDM_MOVE_TO 547
+#define IDM_DELETE 548
+#define IDM_SPLIT 549
+#define IDM_COMBINE 550
+#define IDM_PROPERTIES 551
+#define IDM_COMMENT 552
+#define IDM_CRC 553
+#define IDM_DIFF 554
+#define IDM_CREATE_FOLDER 555
+#define IDM_CREATE_FILE 556
+// #define IDM_EXIT 557
+#define IDM_LINK 558
+#define IDM_ALT_STREAMS 559
+
+#define IDM_VER_EDIT 580
+#define IDM_VER_COMMIT 581
+#define IDM_VER_REVERT 582
+#define IDM_VER_DIFF 583
+
+#define IDM_OPEN_INSIDE_ONE 590
+#define IDM_OPEN_INSIDE_PARSER 591
+
+#define IDM_SELECT_ALL 600
+#define IDM_DESELECT_ALL 601
+#define IDM_INVERT_SELECTION 602
+#define IDM_SELECT 603
+#define IDM_DESELECT 604
+#define IDM_SELECT_BY_TYPE 605
+#define IDM_DESELECT_BY_TYPE 606
+
+#define IDM_VIEW_LARGE_ICONS 700
+#define IDM_VIEW_SMALL_ICONS 701
+#define IDM_VIEW_LIST 702
+#define IDM_VIEW_DETAILS 703
+
+#define IDM_VIEW_ARANGE_BY_NAME 710
+#define IDM_VIEW_ARANGE_BY_TYPE 711
+#define IDM_VIEW_ARANGE_BY_DATE 712
+#define IDM_VIEW_ARANGE_BY_SIZE 713
+
+#define IDM_VIEW_ARANGE_NO_SORT 730
+#define IDM_VIEW_FLAT_VIEW 731
+#define IDM_VIEW_TWO_PANELS 732
+#define IDM_VIEW_TOOLBARS 733
+#define IDM_OPEN_ROOT_FOLDER 734
+#define IDM_OPEN_PARENT_FOLDER 735
+#define IDM_FOLDERS_HISTORY 736
+#define IDM_VIEW_REFRESH 737
+#define IDM_VIEW_AUTO_REFRESH 738
+// #define IDM_VIEW_SHOW_DELETED 739
+// #define IDM_VIEW_SHOW_STREAMS 740
+
+#define IDM_VIEW_ARCHIVE_TOOLBAR 750
+#define IDM_VIEW_STANDARD_TOOLBAR 751
+#define IDM_VIEW_TOOLBARS_LARGE_BUTTONS 752
+#define IDM_VIEW_TOOLBARS_SHOW_BUTTONS_TEXT 753
+
+#define IDM_VIEW_TIME_POPUP 760
+#define IDM_VIEW_TIME 761
+
+#define IDM_ADD_TO_FAVORITES 800
+#define IDS_BOOKMARK 801
+
+#define IDM_OPTIONS 900
+#define IDM_BENCHMARK 901
+#define IDM_BENCHMARK2 902
+
+#define IDM_HELP_CONTENTS 960
+#define IDM_ABOUT 961
+
+#define IDS_OPTIONS 2100
+
+#define IDS_N_SELECTED_ITEMS 3002
+
+#define IDS_FILE_EXIST 3008
+#define IDS_WANT_UPDATE_MODIFIED_FILE 3009
+#define IDS_CANNOT_UPDATE_FILE 3010
+#define IDS_CANNOT_START_EDITOR 3011
+#define IDS_VIRUS 3012
+#define IDS_MESSAGE_UNSUPPORTED_OPERATION_FOR_LONG_PATH_FOLDER 3013
+#define IDS_SELECT_ONE_FILE 3014
+#define IDS_SELECT_FILES 3015
+#define IDS_TOO_MANY_ITEMS 3016
+
+#define IDS_COPY 6000
+#define IDS_MOVE 6001
+#define IDS_COPY_TO 6002
+#define IDS_MOVE_TO 6003
+#define IDS_COPYING 6004
+#define IDS_MOVING 6005
+#define IDS_RENAMING 6006
+
+#define IDS_OPERATION_IS_NOT_SUPPORTED 6008
+#define IDS_ERROR_RENAMING 6009
+#define IDS_CONFIRM_FILE_COPY 6010
+#define IDS_WANT_TO_COPY_FILES 6011
+
+#define IDS_CONFIRM_FILE_DELETE 6100
+#define IDS_CONFIRM_FOLDER_DELETE 6101
+#define IDS_CONFIRM_ITEMS_DELETE 6102
+#define IDS_WANT_TO_DELETE_FILE 6103
+#define IDS_WANT_TO_DELETE_FOLDER 6104
+#define IDS_WANT_TO_DELETE_ITEMS 6105
+#define IDS_DELETING 6106
+#define IDS_ERROR_DELETING 6107
+#define IDS_ERROR_LONG_PATH_TO_RECYCLE 6108
+
+#define IDS_CREATE_FOLDER 6300
+#define IDS_CREATE_FILE 6301
+#define IDS_CREATE_FOLDER_NAME 6302
+#define IDS_CREATE_FILE_NAME 6303
+#define IDS_CREATE_FOLDER_DEFAULT_NAME 6304
+#define IDS_CREATE_FILE_DEFAULT_NAME 6305
+#define IDS_CREATE_FOLDER_ERROR 6306
+#define IDS_CREATE_FILE_ERROR 6307
+
+#define IDS_COMMENT 6400
+#define IDS_COMMENT2 6401
+#define IDS_SELECT 6402
+#define IDS_DESELECT 6403
+#define IDS_SELECT_MASK 6404
+
+#define IDS_PROPERTIES 6600
+#define IDS_FOLDERS_HISTORY 6601
+
+#define IDS_COMPUTER 7100
+#define IDS_NETWORK 7101
+#define IDS_DOCUMENTS 7102
+#define IDS_SYSTEM 7103
+
+#define IDS_ADD 7200
+#define IDS_EXTRACT 7201
+#define IDS_TEST 7202
+#define IDS_BUTTON_COPY 7203
+#define IDS_BUTTON_MOVE 7204
+#define IDS_BUTTON_DELETE 7205
+#define IDS_BUTTON_INFO 7206
+
+#define IDS_SPLITTING 7303
+#define IDS_SPLIT_CONFIRM_TITLE 7304
+#define IDS_SPLIT_CONFIRM_MESSAGE 7305
+#define IDS_SPLIT_VOL_MUST_BE_SMALLER 7306
+
+#define IDS_COMBINE 7400
+#define IDS_COMBINE_TO 7401
+#define IDS_COMBINING 7402
+#define IDS_COMBINE_SELECT_ONE_FILE 7403
+#define IDS_COMBINE_CANT_DETECT_SPLIT_FILE 7404
+#define IDS_COMBINE_CANT_FIND_MORE_THAN_ONE_PART 7405
diff --git a/CPP/7zip/UI/FileManager/resource.rc b/CPP/7zip/UI/FileManager/resource.rc
new file mode 100644
index 0000000..002265a
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/resource.rc
@@ -0,0 +1,286 @@
+#include "../../MyVersionInfo.rc"
+#include "../../GuiCommon.rc"
+#include "resource.h"
+
+MY_VERSION_INFO_APP("7-Zip File Manager", "7zFM")
+
+IDR_ACCELERATOR1 ACCELERATORS
+BEGIN
+// "N", IDM_CREATE_FILE, VIRTKEY, CONTROL, NOINVERT
+ VK_F1, IDM_HELP_CONTENTS, VIRTKEY, NOINVERT
+ VK_F12, IDM_FOLDERS_HISTORY, VIRTKEY, ALT, NOINVERT
+// VK_F7, IDM_CREATE_FOLDER, VIRTKEY, NOINVERT
+END
+
+// for MENUEX:
+// /*
+#define MY_MENUITEM_SEPARATOR MENUITEM "", 0, MFT_SEPARATOR
+#define MY_MFT_MENUBREAK MFT_MENUBREAK
+#define MY_MFT_MENUBARBREAK MFT_MENUBARBREAK
+#define MY_MFS_CHECKED MFT_STRING, MFS_CHECKED
+#define MY_MENUITEM_ID(x) , x
+// */
+
+// for MENU:
+/*
+#define MY_MENUITEM_SEPARATOR MENUITEM SEPARATOR
+#define MY_MFT_MENUBREAK MENUBREAK
+#define MY_MFT_MENUBARBREAK MENUBARBREAK
+#define MY_MFS_CHECKED CHECKED
+#define MY_MENUITEM_ID(x)
+*/
+
+IDM_MENU MENUEX
+BEGIN
+ POPUP "&File" MY_MENUITEM_ID(IDM_FILE)
+ BEGIN
+ MENUITEM "&Open\tEnter", IDM_OPEN
+ MENUITEM "Open &Inside\tCtrl+PgDn", IDM_OPEN_INSIDE
+ MENUITEM "Open Inside *", IDM_OPEN_INSIDE_ONE
+ MENUITEM "Open Inside #", IDM_OPEN_INSIDE_PARSER
+ MENUITEM "Open O&utside\tShift+Enter", IDM_OPEN_OUTSIDE
+ MENUITEM "&View\tF3", IDM_FILE_VIEW
+ MENUITEM "&Edit\tF4", IDM_FILE_EDIT
+ MY_MENUITEM_SEPARATOR
+ MENUITEM "Rena&me\tF2", IDM_RENAME
+ MENUITEM "&Copy To...\tF5", IDM_COPY_TO
+ MENUITEM "&Move To...\tF6", IDM_MOVE_TO
+ MENUITEM "&Delete\tDel", IDM_DELETE
+ MY_MENUITEM_SEPARATOR
+ MENUITEM "&Split file...", IDM_SPLIT
+ MENUITEM "Com&bine files...", IDM_COMBINE
+ MY_MENUITEM_SEPARATOR
+ MENUITEM "P&roperties\tAlt+Enter", IDM_PROPERTIES
+ MENUITEM "Comme&nt...\tCtrl+Z", IDM_COMMENT
+ // MENUITEM "Calculate checksum", IDM_CRC
+ POPUP "CRC" MY_MENUITEM_ID(0)
+ BEGIN
+ MENUITEM "CRC-32", IDM_CRC32
+ MENUITEM "CRC-64", IDM_CRC64
+ MENUITEM "SHA-1", IDM_SHA1
+ MENUITEM "SHA-256", IDM_SHA256
+ MENUITEM "*", IDM_HASH_ALL
+ END
+ MENUITEM "Di&ff", IDM_DIFF
+ MY_MENUITEM_SEPARATOR
+ MENUITEM "Create Folder\tF7", IDM_CREATE_FOLDER
+ MENUITEM "Create File\tCtrl+N", IDM_CREATE_FILE
+ MY_MENUITEM_SEPARATOR
+ MENUITEM "&Link...", IDM_LINK
+ MENUITEM "&Alternate streams", IDM_ALT_STREAMS
+ MY_MENUITEM_SEPARATOR
+ MENUITEM "E&xit\tAlt+F4", IDCLOSE
+ END
+ POPUP "&Edit" MY_MENUITEM_ID(IDM_EDIT)
+ BEGIN
+ // MENUITEM "Cu&t\tCtrl+X", IDM_EDIT_CUT, GRAYED
+ // MENUITEM "&Copy\tCtrl+C", IDM_EDIT_COPY, GRAYED
+ // MENUITEM "&Paste\tCtrl+V", IDM_EDIT_PASTE, GRAYED
+ // MY_MENUITEM_SEPARATOR
+ MENUITEM "Select &All\tShift+[Grey +]", IDM_SELECT_ALL
+ MENUITEM "Deselect All\tShift+[Grey -]", IDM_DESELECT_ALL
+ MENUITEM "&Invert Selection\tGrey *", IDM_INVERT_SELECTION
+ MENUITEM "Select...\tGrey +", IDM_SELECT
+ MENUITEM "Deselect...\tGrey -", IDM_DESELECT
+ MENUITEM "", 0, MY_MFT_MENUBARBREAK
+ MENUITEM "Select by Type\tAlt+[Grey+]", IDM_SELECT_BY_TYPE
+ MENUITEM "Deselect by Type\tAlt+[Grey -]", IDM_DESELECT_BY_TYPE
+ END
+ POPUP "&View" MY_MENUITEM_ID(IDM_VIEW)
+ BEGIN
+ MENUITEM "Lar&ge Icons\tCtrl+1", IDM_VIEW_LARGE_ICONS
+ MENUITEM "S&mall Icons\tCtrl+2", IDM_VIEW_SMALL_ICONS
+ MENUITEM "&List\tCtrl+3", IDM_VIEW_LIST
+ MENUITEM "&Details\tCtrl+4", IDM_VIEW_DETAILS, MY_MFS_CHECKED
+ MY_MENUITEM_SEPARATOR
+ MENUITEM "Name\tCtrl+F3", IDM_VIEW_ARANGE_BY_NAME
+ MENUITEM "Type\tCtrl+F4", IDM_VIEW_ARANGE_BY_TYPE
+ MENUITEM "Date\tCtrl+F5", IDM_VIEW_ARANGE_BY_DATE
+ MENUITEM "Size\tCtrl+F6", IDM_VIEW_ARANGE_BY_SIZE
+ MENUITEM "Unsorted\tCtrl+F7", IDM_VIEW_ARANGE_NO_SORT
+ MY_MENUITEM_SEPARATOR
+ MENUITEM "Flat View", IDM_VIEW_FLAT_VIEW
+ MENUITEM "&2 Panels\tF9", IDM_VIEW_TWO_PANELS
+
+ POPUP "2017" MY_MENUITEM_ID(IDM_VIEW_TIME_POPUP)
+ BEGIN
+ MENUITEM "Time", IDM_VIEW_TIME
+ END
+
+ POPUP "Toolbars" MY_MENUITEM_ID(IDM_VIEW_TOOLBARS)
+ BEGIN
+ MENUITEM "Archive Toolbar", IDM_VIEW_ARCHIVE_TOOLBAR
+ MENUITEM "Standard Toolbar", IDM_VIEW_STANDARD_TOOLBAR
+ MY_MENUITEM_SEPARATOR
+ MENUITEM "Large Buttons", IDM_VIEW_TOOLBARS_LARGE_BUTTONS
+ MENUITEM "Show Buttons Text", IDM_VIEW_TOOLBARS_SHOW_BUTTONS_TEXT
+ END
+ MENUITEM "Open Root Folder\t\\", IDM_OPEN_ROOT_FOLDER
+ MENUITEM "Up One Level\tBackspace", IDM_OPEN_PARENT_FOLDER
+ MENUITEM "Folders History...\tAlt+F12", IDM_FOLDERS_HISTORY
+ MENUITEM "&Refresh\tCtrl+R", IDM_VIEW_REFRESH
+ MENUITEM "Auto Refresh", IDM_VIEW_AUTO_REFRESH
+
+ // MENUITEM "Show NTFS streams", IDM_VIEW_SHOW_STREAMS
+ // MENUITEM "Show deleted files", IDM_VIEW_SHOW_DELETED
+
+ END
+ POPUP "F&avorites" MY_MENUITEM_ID(IDM_FAVORITES)
+ BEGIN
+ POPUP "&Add folder to Favorites as" MY_MENUITEM_ID(IDM_ADD_TO_FAVORITES)
+ BEGIN
+ MY_MENUITEM_SEPARATOR
+ END
+ MY_MENUITEM_SEPARATOR
+ END
+ POPUP "&Tools" MY_MENUITEM_ID(IDM_TOOLS)
+ BEGIN
+ MENUITEM "&Options...", IDM_OPTIONS
+ MY_MENUITEM_SEPARATOR
+ MENUITEM "&Benchmark", IDM_BENCHMARK
+ #ifdef UNDER_CE
+ MENUITEM "Benchmark 2", IDM_BENCHMARK2
+ #endif
+ #ifndef UNDER_CE
+ END
+ POPUP "&Help" MY_MENUITEM_ID(IDM_HELP)
+ BEGIN
+ MENUITEM "&Contents...\tF1", IDM_HELP_CONTENTS
+ #endif
+ MY_MENUITEM_SEPARATOR
+ MENUITEM "&About 7-Zip...", IDM_ABOUT
+ END
+END
+
+
+IDI_ICON ICON "../../UI/FileManager/FM.ico"
+
+#ifndef UNDER_CE
+1 24 MOVEABLE PURE "../../UI/FileManager/7zFM.exe.manifest"
+#endif
+
+IDB_ADD BITMAP "../../UI/FileManager/Add.bmp"
+IDB_EXTRACT BITMAP "../../UI/FileManager/Extract.bmp"
+IDB_TEST BITMAP "../../UI/FileManager/Test.bmp"
+IDB_COPY BITMAP "../../UI/FileManager/Copy.bmp"
+IDB_MOVE BITMAP "../../UI/FileManager/Move.bmp"
+IDB_DELETE BITMAP "../../UI/FileManager/Delete.bmp"
+IDB_INFO BITMAP "../../UI/FileManager/Info.bmp"
+IDB_ADD2 BITMAP "../../UI/FileManager/Add2.bmp"
+IDB_EXTRACT2 BITMAP "../../UI/FileManager/Extract2.bmp"
+IDB_TEST2 BITMAP "../../UI/FileManager/Test2.bmp"
+IDB_COPY2 BITMAP "../../UI/FileManager/Copy2.bmp"
+IDB_MOVE2 BITMAP "../../UI/FileManager/Move2.bmp"
+IDB_DELETE2 BITMAP "../../UI/FileManager/Delete2.bmp"
+IDB_INFO2 BITMAP "../../UI/FileManager/Info2.bmp"
+
+
+STRINGTABLE
+BEGIN
+ IDS_BOOKMARK "Bookmark"
+
+ IDS_OPTIONS "Options"
+
+ IDS_N_SELECTED_ITEMS "{0} object(s) selected"
+
+ IDS_FILE_EXIST "File {0} is already exist"
+ IDS_WANT_UPDATE_MODIFIED_FILE "File '{0}' was modified.\nDo you want to update it in the archive?"
+ IDS_CANNOT_UPDATE_FILE "Cannot update file\n'{0}'"
+ IDS_CANNOT_START_EDITOR "Cannot start editor."
+ IDS_VIRUS "The file looks like a virus (the file name contains long spaces in name)."
+ IDS_MESSAGE_UNSUPPORTED_OPERATION_FOR_LONG_PATH_FOLDER "The operation cannot be called from a folder that has a long path."
+ IDS_SELECT_ONE_FILE "You must select one file"
+ // IDS_SELECT_FILES "You must select one or more files"
+ IDS_TOO_MANY_ITEMS "Too many items"
+
+ IDS_COPY "Copy"
+ IDS_MOVE "Move"
+ IDS_COPY_TO "Copy to:"
+ IDS_MOVE_TO "Move to:"
+ IDS_COPYING "Copying..."
+ IDS_MOVING "Moving..."
+ IDS_RENAMING "Renaming..."
+
+ IDS_OPERATION_IS_NOT_SUPPORTED "Operation is not supported."
+ IDS_ERROR_RENAMING "Error Renaming File or Folder"
+ IDS_CONFIRM_FILE_COPY "Confirm File Copy"
+ IDS_WANT_TO_COPY_FILES "Are you sure you want to copy files to archive"
+
+ IDS_CONFIRM_FILE_DELETE "Confirm File Delete"
+ IDS_CONFIRM_FOLDER_DELETE "Confirm Folder Delete"
+ IDS_CONFIRM_ITEMS_DELETE "Confirm Multiple File Delete"
+ IDS_WANT_TO_DELETE_FILE "Are you sure you want to delete '{0}'?"
+ IDS_WANT_TO_DELETE_FOLDER "Are you sure you want to delete the folder '{0}' and all its contents?"
+ IDS_WANT_TO_DELETE_ITEMS "Are you sure you want to delete these {0} items?"
+ IDS_DELETING "Deleting..."
+ IDS_ERROR_DELETING "Error Deleting File or Folder"
+ IDS_ERROR_LONG_PATH_TO_RECYCLE "The system cannot move a file with long path to the Recycle Bin"
+
+ IDS_CREATE_FOLDER "Create Folder"
+ IDS_CREATE_FILE "Create File"
+ IDS_CREATE_FOLDER_NAME "Folder name:"
+ IDS_CREATE_FILE_NAME "File Name:"
+ IDS_CREATE_FOLDER_DEFAULT_NAME "New Folder"
+ IDS_CREATE_FILE_DEFAULT_NAME "New File"
+ IDS_CREATE_FOLDER_ERROR "Error Creating Folder"
+ IDS_CREATE_FILE_ERROR "Error Creating File"
+
+ IDS_COMMENT "Comment"
+ IDS_COMMENT2 "&Comment:"
+ IDS_SELECT "Select"
+ IDS_DESELECT "Deselect"
+ IDS_SELECT_MASK "Mask:"
+
+ IDS_PROPERTIES "Properties"
+ IDS_FOLDERS_HISTORY "Folders History"
+
+ IDS_COMPUTER "Computer"
+ IDS_NETWORK "Network"
+ IDS_DOCUMENTS "Documents"
+ IDS_SYSTEM "System"
+
+ IDS_ADD "Add"
+ IDS_EXTRACT "Extract"
+ IDS_TEST "Test"
+ IDS_BUTTON_COPY "Copy"
+ IDS_BUTTON_MOVE "Move"
+ IDS_BUTTON_DELETE "Delete"
+ IDS_BUTTON_INFO "Info"
+
+ IDS_SPLITTING "Splitting..."
+ IDS_SPLIT_CONFIRM_TITLE "Confirm Splitting"
+ IDS_SPLIT_CONFIRM_MESSAGE "Are you sure you want to split file into {0} volumes?"
+ IDS_SPLIT_VOL_MUST_BE_SMALLER "Volume size must be smaller than size of original file"
+
+ IDS_COMBINE "Combine Files"
+ IDS_COMBINE_TO "&Combine to:"
+ IDS_COMBINING "Combining..."
+ IDS_COMBINE_SELECT_ONE_FILE "Select only first part of split file"
+ IDS_COMBINE_CANT_DETECT_SPLIT_FILE "Cannot detect file as split file"
+ IDS_COMBINE_CANT_FIND_MORE_THAN_ONE_PART "Cannot find more than one part of split file"
+
+END
+
+#include "AboutDialog.rc"
+#include "BrowseDialog.rc"
+#include "ComboDialog.rc"
+#include "CopyDialog.rc"
+#include "EditDialog.rc"
+#include "EditPage.rc"
+#include "FoldersPage.rc"
+#include "LangPage.rc"
+#include "LinkDialog.rc"
+#include "ListViewDialog.rc"
+#include "MenuPage.rc"
+#include "MessagesDialog.rc"
+#include "OverwriteDialog.rc"
+#include "PasswordDialog.rc"
+#include "ProgressDialog2.rc"
+#include "PropertyName.rc"
+#include "SettingsPage.rc"
+#include "SplitDialog.rc"
+#include "SystemPage.rc"
+#include "../GUI/Extract.rc"
+#include "../GUI/resource3.rc"
+#include "../Explorer/resource2.rc"
+#include "resourceGui.rc"
diff --git a/CPP/7zip/UI/FileManager/resourceGui.h b/CPP/7zip/UI/FileManager/resourceGui.h
index 025f316..7c1b40e 100644
--- a/CPP/7zip/UI/FileManager/resourceGui.h
+++ b/CPP/7zip/UI/FileManager/resourceGui.h
@@ -1,15 +1,15 @@
-#define IDI_ICON 1
-
-#define IDS_MESSAGE_NO_ERRORS 3001
-
-#define IDS_PROGRESS_TESTING 3302
-#define IDS_OPENNING 3303
-#define IDS_SCANNING 3304
-
-#define IDS_CHECKSUM_CALCULATING 7500
-#define IDS_CHECKSUM_INFORMATION 7501
-#define IDS_CHECKSUM_CRC_DATA 7502
-#define IDS_CHECKSUM_CRC_DATA_NAMES 7503
-#define IDS_CHECKSUM_CRC_STREAMS_NAMES 7504
-
-#define IDS_INCORRECT_VOLUME_SIZE 7307
+#define IDI_ICON 1
+
+#define IDS_MESSAGE_NO_ERRORS 3001
+
+#define IDS_PROGRESS_TESTING 3302
+#define IDS_OPENNING 3303
+#define IDS_SCANNING 3304
+
+#define IDS_CHECKSUM_CALCULATING 7500
+#define IDS_CHECKSUM_INFORMATION 7501
+#define IDS_CHECKSUM_CRC_DATA 7502
+#define IDS_CHECKSUM_CRC_DATA_NAMES 7503
+#define IDS_CHECKSUM_CRC_STREAMS_NAMES 7504
+
+#define IDS_INCORRECT_VOLUME_SIZE 7307
diff --git a/CPP/7zip/UI/FileManager/resourceGui.rc b/CPP/7zip/UI/FileManager/resourceGui.rc
new file mode 100644
index 0000000..f748e0b
--- /dev/null
+++ b/CPP/7zip/UI/FileManager/resourceGui.rc
@@ -0,0 +1,19 @@
+#include "resourceGui.h"
+
+STRINGTABLE
+BEGIN
+ IDS_MESSAGE_NO_ERRORS "There are no errors"
+
+ IDS_PROGRESS_TESTING "Testing"
+
+ IDS_CHECKSUM_CALCULATING "Checksum calculating..."
+ IDS_CHECKSUM_INFORMATION "Checksum information"
+ IDS_CHECKSUM_CRC_DATA "CRC checksum for data:"
+ IDS_CHECKSUM_CRC_DATA_NAMES "CRC checksum for data and names:"
+ IDS_CHECKSUM_CRC_STREAMS_NAMES "CRC checksum for streams and names:"
+
+ IDS_INCORRECT_VOLUME_SIZE "Incorrect volume size"
+
+ IDS_OPENNING "Opening..."
+ IDS_SCANNING "Scanning..."
+END
diff --git a/CPP/7zip/UI/GUI/7zG.exe.manifest b/CPP/7zip/UI/GUI/7zG.exe.manifest
new file mode 100644
index 0000000..ae964d8
--- /dev/null
+++ b/CPP/7zip/UI/GUI/7zG.exe.manifest
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0" xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
+ <assemblyIdentity version="1.0.0.0" processorArchitecture="*" name="7-Zip.7-Zip.7zG" type="win32"/>
+ <description>7-Zip GUI.</description>
+ <dependency>
+ <dependentAssembly><assemblyIdentity type="win32" name="Microsoft.Windows.Common-Controls" version="6.0.0.0" processorArchitecture="*" publicKeyToken="6595b64144ccf1df" language="*"/></dependentAssembly>
+ </dependency>
+<compatibility xmlns="urn:schemas-microsoft-com:compatibility.v1"><application>
+<!-- Vista --> <supportedOS Id="{e2011457-1546-43c5-a5fe-008deee3d3f0}"/>
+<!-- Win 7 --> <supportedOS Id="{35138b9a-5d96-4fbd-8e2d-a2440225f93a}"/>
+<!-- Win 8 --> <supportedOS Id="{4a2f28e3-53b9-4441-ba9c-d69d4a4a6e38}"/>
+<!-- Win 8.1 --> <supportedOS Id="{1f676c76-80e1-4239-95bb-83d0f6d0da78}"/>
+<!-- Win 10 --> <supportedOS Id="{8e0f7a12-bfb3-4fe8-b9a5-48fd50a15a9a}"/>
+</application></compatibility>
+ <asmv3:application>
+ <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
+ <dpiAware>true</dpiAware>
+ </asmv3:windowsSettings>
+ </asmv3:application>
+<application xmlns="urn:schemas-microsoft-com:asm.v3">
+<windowsSettings xmlns:ws2="http://schemas.microsoft.com/SMI/2016/WindowsSettings">
+<ws2:longPathAware>true</ws2:longPathAware></windowsSettings></application>
+</assembly>
diff --git a/CPP/7zip/UI/GUI/BenchmarkDialog.cpp b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp
new file mode 100644
index 0000000..539d689
--- /dev/null
+++ b/CPP/7zip/UI/GUI/BenchmarkDialog.cpp
@@ -0,0 +1,1920 @@
+// BenchmarkDialog.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/Defs.h"
+#include "../../../Common/IntToString.h"
+#include "../../../Common/MyException.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../../Windows/Synchronization.h"
+#include "../../../Windows/System.h"
+#include "../../../Windows/Thread.h"
+#include "../../../Windows/SystemInfo.h"
+
+#include "../../../Windows/Control/ComboBox.h"
+#include "../../../Windows/Control/Edit.h"
+
+#include "../../Common/MethodProps.h"
+
+#include "../FileManager/DialogSize.h"
+#include "../FileManager/HelpUtils.h"
+#include "../FileManager/LangUtils.h"
+
+#include "../../MyVersion.h"
+
+#include "../Common/Bench.h"
+
+#include "BenchmarkDialogRes.h"
+#include "BenchmarkDialog.h"
+
+using namespace NWindows;
+
+#define kHelpTopic "fm/benchmark.htm"
+
+static const UINT_PTR kTimerID = 4;
+static const UINT kTimerElapse = 1000; // 1000
+
+// use PRINT_ITER_TIME to show time of each iteration in log box
+// #define PRINT_ITER_TIME
+
+static const unsigned kRatingVector_NumBundlesMax = 20;
+
+enum MyBenchMessages
+{
+ k_Message_Finished = WM_APP + 1
+};
+
+enum My_Message_WPARAM
+{
+ k_Msg_WPARM_Thread_Finished = 0,
+ k_Msg_WPARM_Iter_Finished,
+ k_Msg_WPARM_Enc1_Finished
+};
+
+
+struct CBenchPassResult
+{
+ CTotalBenchRes Enc;
+ CTotalBenchRes Dec;
+ #ifdef PRINT_ITER_TIME
+ DWORD Ticks;
+ #endif
+ // CBenchInfo EncInfo; // for debug
+ // CBenchPassResult() {};
+};
+
+
+struct CTotalBenchRes2: public CTotalBenchRes
+{
+ UInt64 UnpackSize;
+
+ void Init()
+ {
+ CTotalBenchRes::Init();
+ UnpackSize = 0;
+ }
+
+ void SetFrom_BenchInfo(const CBenchInfo &info)
+ {
+ NumIterations2 = 1;
+ Generate_From_BenchInfo(info);
+ UnpackSize = info.Get_UnpackSize_Full();
+ }
+
+ void Update_With_Res2(const CTotalBenchRes2 &r)
+ {
+ Update_With_Res(r);
+ UnpackSize += r.UnpackSize;
+ }
+};
+
+
+struct CSyncData
+{
+ UInt32 NumPasses_Finished;
+
+ // UInt64 NumEncProgress; // for debug
+ // UInt64 NumDecProgress; // for debug
+ // CBenchInfo EncInfo; // for debug
+
+ CTotalBenchRes2 Enc_BenchRes_1;
+ CTotalBenchRes2 Enc_BenchRes;
+
+ CTotalBenchRes2 Dec_BenchRes_1;
+ CTotalBenchRes2 Dec_BenchRes;
+
+ #ifdef PRINT_ITER_TIME
+ DWORD TotalTicks;
+ #endif
+
+ int RatingVector_DeletedIndex;
+ // UInt64 RatingVector_NumDeleted;
+
+ bool BenchWasFinished; // all passes were finished
+ bool NeedPrint_Freq;
+ bool NeedPrint_RatingVector;
+ bool NeedPrint_Enc_1;
+ bool NeedPrint_Enc;
+ bool NeedPrint_Dec_1;
+ bool NeedPrint_Dec;
+ bool NeedPrint_Tot; // intermediate Total was updated after current pass
+
+ void Init();
+};
+
+
+void CSyncData::Init()
+{
+ NumPasses_Finished = 0;
+
+ // NumEncProgress = 0;
+ // NumDecProgress = 0;
+
+ Enc_BenchRes.Init();
+ Enc_BenchRes_1.Init();
+ Dec_BenchRes.Init();
+ Dec_BenchRes_1.Init();
+
+ #ifdef PRINT_ITER_TIME
+ TotalTicks = 0;
+ #endif
+
+ RatingVector_DeletedIndex = -1;
+ // RatingVector_NumDeleted = 0;
+
+ BenchWasFinished =
+ NeedPrint_Freq =
+ NeedPrint_RatingVector =
+ NeedPrint_Enc_1 =
+ NeedPrint_Enc =
+ NeedPrint_Dec_1 =
+ NeedPrint_Dec =
+ NeedPrint_Tot = false;
+}
+
+
+struct CBenchProgressSync
+{
+ bool Exit; // GUI asks BenchThread to Exit, and BenchThread reads that variable
+ UInt32 NumThreads;
+ UInt64 DictSize;
+ UInt32 NumPasses_Limit;
+ int Level;
+
+ // must be written by benchmark thread, read by GUI thread */
+ CSyncData sd;
+ CRecordVector<CBenchPassResult> RatingVector;
+
+ NWindows::NSynchronization::CCriticalSection CS;
+
+ AString Text;
+ bool TextWasChanged;
+
+ /* BenchFinish_Task_HRESULT - for result from benchmark code
+ BenchFinish_Thread_HRESULT - for Exceptions and service errors
+ these arreos must be shown even if user escapes benchmark */
+
+ HRESULT BenchFinish_Task_HRESULT;
+ HRESULT BenchFinish_Thread_HRESULT;
+
+ UInt32 NumFreqThreadsPrev;
+ UString FreqString_Sync;
+ UString FreqString_GUI;
+
+ CBenchProgressSync()
+ {
+ NumPasses_Limit = 1;
+ }
+
+ void Init();
+
+ void SendExit()
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(CS);
+ Exit = true;
+ }
+};
+
+
+void CBenchProgressSync::Init()
+{
+ Exit = false;
+
+ BenchFinish_Task_HRESULT = S_OK;
+ BenchFinish_Thread_HRESULT = S_OK;
+
+ sd.Init();
+ RatingVector.Clear();
+
+ NumFreqThreadsPrev = 0;
+ FreqString_Sync.Empty();
+ FreqString_GUI.Empty();
+
+ Text.Empty();
+ TextWasChanged = true;
+}
+
+
+
+struct CMyFont
+{
+ HFONT _font;
+ CMyFont(): _font(NULL) {}
+ ~CMyFont()
+ {
+ if (_font)
+ DeleteObject(_font);
+ }
+ void Create(const LOGFONT *lplf)
+ {
+ _font = CreateFontIndirect(lplf);
+ }
+};
+
+
+class CBenchmarkDialog;
+
+struct CThreadBenchmark
+{
+ CBenchmarkDialog *BenchmarkDialog;
+ DECL_EXTERNAL_CODECS_LOC_VARS_DECL
+ // HRESULT Result;
+
+ HRESULT Process();
+ static THREAD_FUNC_DECL MyThreadFunction(void *param)
+ {
+ /* ((CThreadBenchmark *)param)->Result = */
+ ((CThreadBenchmark *)param)->Process();
+ return 0;
+ }
+};
+
+
+class CBenchmarkDialog:
+ public NWindows::NControl::CModalDialog
+{
+ NWindows::NControl::CComboBox m_Dictionary;
+ NWindows::NControl::CComboBox m_NumThreads;
+ NWindows::NControl::CComboBox m_NumPasses;
+ NWindows::NControl::CEdit _consoleEdit;
+ UINT_PTR _timer;
+
+ UInt32 _startTime;
+ UInt32 _finishTime;
+ bool _finishTime_WasSet;
+
+ bool WasStopped_in_GUI;
+ bool ExitWasAsked_in_GUI;
+ bool NeedRestart;
+
+ CMyFont _font;
+
+ UInt64 RamSize;
+ UInt64 RamSize_Limit;
+ bool RamSize_Defined;
+
+ UInt32 NumPasses_Finished_Prev;
+
+ UString ElapsedSec_Prev;
+
+ void InitSyncNew()
+ {
+ NumPasses_Finished_Prev = (UInt32)(Int32)-1;
+ ElapsedSec_Prev.Empty();
+ Sync.Init();
+ }
+
+ virtual bool OnInit() Z7_override;
+ virtual bool OnDestroy() Z7_override;
+ virtual bool OnSize(WPARAM /* wParam */, int xSize, int ySize) Z7_override;
+ virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override;
+ virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override;
+ virtual void OnHelp() Z7_override;
+ virtual void OnCancel() Z7_override;
+ virtual bool OnTimer(WPARAM timerID, LPARAM callback) Z7_override;
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+
+ void Disable_Stop_Button();
+ void OnStopButton();
+ void RestartBenchmark();
+ void StartBenchmark();
+
+ void UpdateGui();
+
+ void PrintTime();
+ void PrintRating(UInt64 rating, UINT controlID);
+ void PrintUsage(UInt64 usage, UINT controlID);
+ void PrintBenchRes(const CTotalBenchRes2 &info, const UINT ids[]);
+
+ UInt32 GetNumberOfThreads();
+ size_t OnChangeDictionary();
+
+ void SetItemText_Number(unsigned itemID, UInt64 val, LPCTSTR post = NULL);
+ void Print_MemUsage(UString &s, UInt64 memUsage) const;
+ bool IsMemoryUsageOK(UInt64 memUsage) const
+ { return memUsage + (1 << 20) <= RamSize_Limit; }
+
+ void MyKillTimer();
+
+ void SendExit_Status(const wchar_t *message)
+ {
+ SetItemText(IDT_BENCH_ERROR_MESSAGE, message);
+ Sync.SendExit();
+ }
+
+public:
+ CBenchProgressSync Sync;
+
+ bool TotalMode;
+ CObjectVector<CProperty> Props;
+
+ CSysString Bench2Text;
+
+ NWindows::CThread _thread;
+ CThreadBenchmark _threadBenchmark;
+
+ CBenchmarkDialog():
+ _timer(0),
+ WasStopped_in_GUI(false),
+ ExitWasAsked_in_GUI(false),
+ NeedRestart(false),
+ TotalMode(false)
+ {}
+
+ ~CBenchmarkDialog() Z7_DESTRUCTOR_override;
+
+ bool PostMsg_Finish(WPARAM wparam)
+ {
+ if ((HWND)*this)
+ return PostMsg(k_Message_Finished, wparam);
+ // the (HWND)*this is NULL only for some internal code failure
+ return true;
+ }
+
+ INT_PTR Create(HWND wndParent = NULL)
+ {
+ BIG_DIALOG_SIZE(332, 228);
+ return CModalDialog::Create(TotalMode ? IDD_BENCH_TOTAL : SIZED_DIALOG(IDD_BENCH), wndParent);
+ }
+ void MessageBoxError(LPCWSTR message)
+ {
+ MessageBoxW(*this, message, L"7-Zip", MB_ICONERROR);
+ }
+ void MessageBoxError_Status(LPCWSTR message)
+ {
+ UString s ("ERROR: ");
+ s += message;
+ MessageBoxError(s);
+ SetItemText(IDT_BENCH_ERROR_MESSAGE, s);
+ }
+};
+
+
+
+
+
+
+
+
+
+UString HResultToMessage(HRESULT errorCode);
+
+#ifdef Z7_LANG
+static const UInt32 kLangIDs[] =
+{
+ IDT_BENCH_DICTIONARY,
+ IDT_BENCH_MEMORY,
+ IDT_BENCH_NUM_THREADS,
+ IDT_BENCH_SIZE,
+ IDT_BENCH_RATING_LABEL,
+ IDT_BENCH_USAGE_LABEL,
+ IDT_BENCH_RPU_LABEL,
+ IDG_BENCH_COMPRESSING,
+ IDG_BENCH_DECOMPRESSING,
+ IDG_BENCH_TOTAL_RATING,
+ IDT_BENCH_CURRENT,
+ IDT_BENCH_RESULTING,
+ IDT_BENCH_ELAPSED,
+ IDT_BENCH_PASSES,
+ IDB_STOP,
+ IDB_RESTART
+};
+
+static const UInt32 kLangIDs_RemoveColon[] =
+{
+ IDT_BENCH_SPEED
+};
+
+#endif
+
+static LPCTSTR const kProcessingString = TEXT("...");
+static LPCTSTR const kGB = TEXT(" GB");
+static LPCTSTR const kMB = TEXT(" MB");
+static LPCTSTR const kKB = TEXT(" KB");
+// static LPCTSTR const kMIPS = TEXT(" MIPS");
+static LPCTSTR const kKBs = TEXT(" KB/s");
+
+static const unsigned kMinDicLogSize = 18;
+
+static const UInt32 kMinDicSize = (UInt32)1 << kMinDicLogSize;
+static const size_t kMaxDicSize = (size_t)1 << (22 + sizeof(size_t) / 4 * 5);
+// static const size_t kMaxDicSize = (size_t)1 << 16;
+ /*
+ #ifdef MY_CPU_64BIT
+ (UInt32)(Int32)-1; // we can use it, if we want 4 GB buffer
+ // (UInt32)15 << 28;
+ #else
+ (UInt32)1 << 27;
+ #endif
+ */
+
+
+static int ComboBox_Add_UInt32(NWindows::NControl::CComboBox &cb, UInt32 v)
+{
+ TCHAR s[16];
+ ConvertUInt32ToString(v, s);
+ const int index = (int)cb.AddString(s);
+ cb.SetItemData(index, (LPARAM)v);
+ return index;
+}
+
+
+bool CBenchmarkDialog::OnInit()
+{
+ #ifdef Z7_LANG
+ LangSetWindowText(*this, IDD_BENCH);
+ LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
+ LangSetDlgItems_RemoveColon(*this, kLangIDs_RemoveColon, Z7_ARRAY_SIZE(kLangIDs_RemoveColon));
+ LangSetDlgItemText(*this, IDT_BENCH_CURRENT2, IDT_BENCH_CURRENT);
+ LangSetDlgItemText(*this, IDT_BENCH_RESULTING2, IDT_BENCH_RESULTING);
+ #endif
+
+ InitSyncNew();
+
+ if (TotalMode)
+ {
+ _consoleEdit.Attach(GetItem(IDE_BENCH2_EDIT));
+ LOGFONT f;
+ memset(&f, 0, sizeof(f));
+ f.lfHeight = 14;
+ f.lfWidth = 0;
+ f.lfWeight = FW_DONTCARE;
+ f.lfCharSet = DEFAULT_CHARSET;
+ f.lfOutPrecision = OUT_DEFAULT_PRECIS;
+ f.lfClipPrecision = CLIP_DEFAULT_PRECIS;
+ f.lfQuality = DEFAULT_QUALITY;
+
+ f.lfPitchAndFamily = FIXED_PITCH;
+ // MyStringCopy(f.lfFaceName, TEXT(""));
+ // f.lfFaceName[0] = 0;
+ _font.Create(&f);
+ if (_font._font)
+ _consoleEdit.SendMsg(WM_SETFONT, (WPARAM)_font._font, TRUE);
+ }
+
+ UInt32 numCPUs = 1;
+
+ {
+ AString s ("/ ");
+
+ NSystem::CProcessAffinity threadsInfo;
+ threadsInfo.InitST();
+
+ #ifndef Z7_ST
+ if (threadsInfo.Get() && threadsInfo.processAffinityMask != 0)
+ numCPUs = threadsInfo.GetNumProcessThreads();
+ else
+ numCPUs = NSystem::GetNumberOfProcessors();
+ #endif
+
+ s.Add_UInt32(numCPUs);
+ s += GetProcessThreadsInfo(threadsInfo);
+ SetItemTextA(IDT_BENCH_HARDWARE_THREADS, s);
+
+ {
+ AString s2;
+ GetSysInfo(s, s2);
+ SetItemTextA(IDT_BENCH_SYS1, s);
+ if (s != s2 && !s2.IsEmpty())
+ SetItemTextA(IDT_BENCH_SYS2, s2);
+ }
+ {
+ GetCpuName_MultiLine(s);
+ SetItemTextA(IDT_BENCH_CPU, s);
+ }
+ {
+ GetOsInfoText(s);
+ s += " : ";
+ AddCpuFeatures(s);
+ SetItemTextA(IDT_BENCH_CPU_FEATURE, s);
+ }
+
+ s = "7-Zip " MY_VERSION_CPU;
+ SetItemTextA(IDT_BENCH_VER, s);
+ }
+
+
+ // ----- Num Threads ----------
+
+ if (numCPUs < 1)
+ numCPUs = 1;
+ numCPUs = MyMin(numCPUs, (UInt32)(1 << 6)); // it's WIN32 limit
+
+ UInt32 numThreads = Sync.NumThreads;
+
+ if (numThreads == (UInt32)(Int32)-1)
+ numThreads = numCPUs;
+ if (numThreads > 1)
+ numThreads &= ~(UInt32)1;
+ const UInt32 kNumThreadsMax = (1 << 12);
+ if (numThreads > kNumThreadsMax)
+ numThreads = kNumThreadsMax;
+
+ m_NumThreads.Attach(GetItem(IDC_BENCH_NUM_THREADS));
+ const UInt32 numTheads_Combo = numCPUs * 2;
+ UInt32 v = 1;
+ int cur = 0;
+ for (; v <= numTheads_Combo;)
+ {
+ int index = ComboBox_Add_UInt32(m_NumThreads, v);
+ const UInt32 vNext = v + (v < 2 ? 1 : 2);
+ if (v <= numThreads)
+ if (numThreads < vNext || vNext > numTheads_Combo)
+ {
+ if (v != numThreads)
+ index = ComboBox_Add_UInt32(m_NumThreads, numThreads);
+ cur = index;
+ }
+ v = vNext;
+ }
+ m_NumThreads.SetCurSel(cur);
+ Sync.NumThreads = GetNumberOfThreads();
+
+
+ // ----- Dictionary ----------
+
+ m_Dictionary.Attach(GetItem(IDC_BENCH_DICTIONARY));
+
+ RamSize = (UInt64)(sizeof(size_t)) << 29;
+ RamSize_Defined = NSystem::GetRamSize(RamSize);
+
+
+ #ifdef UNDER_CE
+ const UInt32 kNormalizedCeSize = (16 << 20);
+ if (RamSize > kNormalizedCeSize && RamSize < (33 << 20))
+ RamSize = kNormalizedCeSize;
+ #endif
+ RamSize_Limit = RamSize / 16 * 15;
+
+ if (Sync.DictSize == (UInt64)(Int64)-1)
+ {
+ unsigned dicSizeLog = 25;
+ #ifdef UNDER_CE
+ dicSizeLog = 20;
+ #endif
+ if (RamSize_Defined)
+ for (; dicSizeLog > kBenchMinDicLogSize; dicSizeLog--)
+ if (IsMemoryUsageOK(GetBenchMemoryUsage(
+ Sync.NumThreads, Sync.Level, (UInt64)1 << dicSizeLog, TotalMode)))
+ break;
+ Sync.DictSize = (UInt64)1 << dicSizeLog;
+ }
+
+ if (Sync.DictSize < kMinDicSize) Sync.DictSize = kMinDicSize;
+ if (Sync.DictSize > kMaxDicSize) Sync.DictSize = kMaxDicSize;
+
+ cur = 0;
+ for (unsigned i = (kMinDicLogSize - 1) * 2; i <= (32 - 1) * 2; i++)
+ {
+ const size_t dict = (size_t)(2 + (i & 1)) << (i / 2);
+ // if (i == (32 - 1) * 2) dict = kMaxDicSize;
+ TCHAR s[32];
+ const TCHAR *post;
+ UInt32 d;
+ if (dict >= ((UInt32)1 << 31)) { d = (UInt32)(dict >> 30); post = kGB; }
+ else if (dict >= ((UInt32)1 << 21)) { d = (UInt32)(dict >> 20); post = kMB; }
+ else { d = (UInt32)(dict >> 10); post = kKB; }
+ ConvertUInt32ToString(d, s);
+ lstrcat(s, post);
+ const int index = (int)m_Dictionary.AddString(s);
+ m_Dictionary.SetItemData(index, (LPARAM)dict);
+ if (dict <= Sync.DictSize)
+ cur = index;
+ if (dict >= kMaxDicSize)
+ break;
+ }
+ m_Dictionary.SetCurSel(cur);
+
+
+ // ----- Num Passes ----------
+
+ m_NumPasses.Attach(GetItem(IDC_BENCH_NUM_PASSES));
+ cur = 0;
+ v = 1;
+ for (;;)
+ {
+ int index = ComboBox_Add_UInt32(m_NumPasses, v);
+ const bool isLast = (v >= 10000000);
+ UInt32 vNext = v * 10;
+ if (v < 2) vNext = 2;
+ else if (v < 5) vNext = 5;
+ else if (v < 10) vNext = 10;
+
+ if (v <= Sync.NumPasses_Limit)
+ if (isLast || Sync.NumPasses_Limit < vNext)
+ {
+ if (v != Sync.NumPasses_Limit)
+ index = ComboBox_Add_UInt32(m_NumPasses, Sync.NumPasses_Limit);
+ cur = index;
+ }
+ v = vNext;
+ if (isLast)
+ break;
+ }
+ m_NumPasses.SetCurSel(cur);
+
+ if (TotalMode)
+ NormalizeSize(true);
+ else
+ NormalizePosition();
+
+ RestartBenchmark();
+
+ return CModalDialog::OnInit();
+}
+
+
+bool CBenchmarkDialog::OnSize(WPARAM /* wParam */, int xSize, int ySize)
+{
+ int mx, my;
+ GetMargins(8, mx, my);
+
+ if (!TotalMode)
+ {
+ RECT rect;
+ GetClientRectOfItem(IDT_BENCH_LOG, rect);
+ int x = xSize - rect.left - mx;
+ int y = ySize - rect.top - my;
+ if (x < 0) x = 0;
+ if (y < 0) y = 0;
+ MoveItem(IDT_BENCH_LOG, rect.left, rect.top, x, y, true);
+ return false;
+ }
+
+ int bx1, bx2, by;
+
+ GetItemSizes(IDCANCEL, bx1, by);
+ GetItemSizes(IDHELP, bx2, by);
+
+ {
+ int y = ySize - my - by;
+ int x = xSize - mx - bx1;
+
+ InvalidateRect(NULL);
+
+ MoveItem(IDCANCEL, x, y, bx1, by);
+ MoveItem(IDHELP, x - mx - bx2, y, bx2, by);
+ }
+
+ if (_consoleEdit)
+ {
+ int yPos = ySize - my - by;
+ RECT rect;
+ GetClientRectOfItem(IDE_BENCH2_EDIT, rect);
+ int y = rect.top;
+ int ySize2 = yPos - my - y;
+ const int kMinYSize = 20;
+ int xx = xSize - mx * 2;
+ if (ySize2 < kMinYSize)
+ {
+ ySize2 = kMinYSize;
+ }
+ _consoleEdit.Move(mx, y, xx, ySize2);
+ }
+ return false;
+}
+
+
+UInt32 CBenchmarkDialog::GetNumberOfThreads()
+{
+ return (UInt32)m_NumThreads.GetItemData_of_CurSel();
+}
+
+
+#define UINT_TO_STR_3(s, val) { \
+ s[0] = (wchar_t)('0' + (val) / 100); \
+ s[1] = (wchar_t)('0' + (val) % 100 / 10); \
+ s[2] = (wchar_t)('0' + (val) % 10); \
+ s += 3; s[0] = 0; }
+
+static WCHAR *NumberToDot3(UInt64 val, WCHAR *s)
+{
+ s = ConvertUInt64ToString(val / 1000, s);
+ const UInt32 rem = (UInt32)(val % 1000);
+ *s++ = '.';
+ UINT_TO_STR_3(s, rem)
+ return s;
+}
+
+void CBenchmarkDialog::SetItemText_Number(unsigned itemID, UInt64 val, LPCTSTR post)
+{
+ TCHAR s[64];
+ ConvertUInt64ToString(val, s);
+ if (post)
+ lstrcat(s, post);
+ SetItemText(itemID, s);
+}
+
+static void AddSize_MB(UString &s, UInt64 size)
+{
+ s.Add_UInt64((size + (1 << 20) - 1) >> 20);
+ s += kMB;
+}
+
+void CBenchmarkDialog::Print_MemUsage(UString &s, UInt64 memUsage) const
+{
+ AddSize_MB(s, memUsage);
+ if (RamSize_Defined)
+ {
+ s += " / ";
+ AddSize_MB(s, RamSize);
+ }
+}
+
+size_t CBenchmarkDialog::OnChangeDictionary()
+{
+ const size_t dict = (size_t)m_Dictionary.GetItemData_of_CurSel();
+ const UInt64 memUsage = GetBenchMemoryUsage(GetNumberOfThreads(),
+ Sync.Level,
+ dict,
+ false); // totalBench mode
+
+ UString s;
+ Print_MemUsage(s, memUsage);
+
+ #ifdef Z7_LARGE_PAGES
+ {
+ AString s2;
+ Add_LargePages_String(s2);
+ if (!s2.IsEmpty())
+ {
+ s.Add_Space();
+ s += s2;
+ }
+ }
+ #endif
+
+ SetItemText(IDT_BENCH_MEMORY_VAL, s);
+
+ return dict;
+}
+
+
+static const UInt32 g_IDs[] =
+{
+ IDT_BENCH_COMPRESS_SIZE1,
+ IDT_BENCH_COMPRESS_SIZE2,
+ IDT_BENCH_COMPRESS_USAGE1,
+ IDT_BENCH_COMPRESS_USAGE2,
+ IDT_BENCH_COMPRESS_SPEED1,
+ IDT_BENCH_COMPRESS_SPEED2,
+ IDT_BENCH_COMPRESS_RATING1,
+ IDT_BENCH_COMPRESS_RATING2,
+ IDT_BENCH_COMPRESS_RPU1,
+ IDT_BENCH_COMPRESS_RPU2,
+
+ IDT_BENCH_DECOMPR_SIZE1,
+ IDT_BENCH_DECOMPR_SIZE2,
+ IDT_BENCH_DECOMPR_SPEED1,
+ IDT_BENCH_DECOMPR_SPEED2,
+ IDT_BENCH_DECOMPR_RATING1,
+ IDT_BENCH_DECOMPR_RATING2,
+ IDT_BENCH_DECOMPR_USAGE1,
+ IDT_BENCH_DECOMPR_USAGE2,
+ IDT_BENCH_DECOMPR_RPU1,
+ IDT_BENCH_DECOMPR_RPU2,
+
+ IDT_BENCH_TOTAL_USAGE_VAL,
+ IDT_BENCH_TOTAL_RATING_VAL,
+ IDT_BENCH_TOTAL_RPU_VAL
+};
+
+
+static const unsigned k_Ids_Enc_1[] = {
+ IDT_BENCH_COMPRESS_USAGE1,
+ IDT_BENCH_COMPRESS_SPEED1,
+ IDT_BENCH_COMPRESS_RPU1,
+ IDT_BENCH_COMPRESS_RATING1,
+ IDT_BENCH_COMPRESS_SIZE1 };
+
+static const unsigned k_Ids_Enc[] = {
+ IDT_BENCH_COMPRESS_USAGE2,
+ IDT_BENCH_COMPRESS_SPEED2,
+ IDT_BENCH_COMPRESS_RPU2,
+ IDT_BENCH_COMPRESS_RATING2,
+ IDT_BENCH_COMPRESS_SIZE2 };
+
+static const unsigned k_Ids_Dec_1[] = {
+ IDT_BENCH_DECOMPR_USAGE1,
+ IDT_BENCH_DECOMPR_SPEED1,
+ IDT_BENCH_DECOMPR_RPU1,
+ IDT_BENCH_DECOMPR_RATING1,
+ IDT_BENCH_DECOMPR_SIZE1 };
+
+static const unsigned k_Ids_Dec[] = {
+ IDT_BENCH_DECOMPR_USAGE2,
+ IDT_BENCH_DECOMPR_SPEED2,
+ IDT_BENCH_DECOMPR_RPU2,
+ IDT_BENCH_DECOMPR_RATING2,
+ IDT_BENCH_DECOMPR_SIZE2 };
+
+static const unsigned k_Ids_Tot[] = {
+ IDT_BENCH_TOTAL_USAGE_VAL,
+ 0,
+ IDT_BENCH_TOTAL_RPU_VAL,
+ IDT_BENCH_TOTAL_RATING_VAL,
+ 0 };
+
+
+void CBenchmarkDialog::MyKillTimer()
+{
+ if (_timer != 0)
+ {
+ KillTimer(kTimerID);
+ _timer = 0;
+ }
+}
+
+
+bool CBenchmarkDialog::OnDestroy()
+{
+ /* actually timer was removed before.
+ also the timer must be removed by Windows, when window will be removed. */
+ MyKillTimer(); // it's optional code
+ return false; // we return (false) to perform default dialog operation
+}
+
+void SetErrorMessage_MemUsage(UString &s, UInt64 reqSize, UInt64 ramSize, UInt64 ramLimit, const UString &usageString);
+
+void CBenchmarkDialog::StartBenchmark()
+{
+ NeedRestart = false;
+ WasStopped_in_GUI = false;
+
+ SetItemText_Empty(IDT_BENCH_ERROR_MESSAGE);
+
+ MyKillTimer(); // optional code. timer was killed before
+
+ const size_t dict = OnChangeDictionary();
+ const UInt32 numThreads = GetNumberOfThreads();
+ const UInt32 numPasses = (UInt32)m_NumPasses.GetItemData_of_CurSel();
+
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_IDs); i++)
+ SetItemText(g_IDs[i], kProcessingString);
+
+ SetItemText_Empty(IDT_BENCH_LOG);
+ SetItemText_Empty(IDT_BENCH_ELAPSED_VAL);
+ SetItemText_Empty(IDT_BENCH_ERROR_MESSAGE);
+
+ const UInt64 memUsage = GetBenchMemoryUsage(numThreads, Sync.Level, dict,
+ false); // totalBench
+ if (!IsMemoryUsageOK(memUsage))
+ {
+ UString s2 = LangString(IDT_BENCH_MEMORY);
+ if (s2.IsEmpty())
+ GetItemText(IDT_BENCH_MEMORY, s2);
+ UString s;
+ SetErrorMessage_MemUsage(s, memUsage, RamSize, RamSize_Limit, s2);
+ MessageBoxError_Status(s);
+ return;
+ }
+
+ EnableItem(IDB_STOP, true);
+
+ _startTime = GetTickCount();
+ _finishTime = _startTime;
+ _finishTime_WasSet = false;
+
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS);
+ InitSyncNew();
+ Sync.DictSize = dict;
+ Sync.NumThreads = numThreads;
+ Sync.NumPasses_Limit = numPasses;
+ }
+
+ PrintTime();
+
+ _timer = SetTimer(kTimerID, kTimerElapse);
+ if (_thread.Create(CThreadBenchmark::MyThreadFunction, &_threadBenchmark) != 0)
+ {
+ MyKillTimer();
+ MessageBoxError_Status(L"Can't create thread");
+ }
+ return;
+}
+
+
+void CBenchmarkDialog::RestartBenchmark()
+{
+ if (ExitWasAsked_in_GUI)
+ return;
+
+ if (_thread.IsCreated())
+ {
+ NeedRestart = true;
+ SendExit_Status(L"Stop for restart ...");
+ }
+ else
+ StartBenchmark();
+}
+
+
+void CBenchmarkDialog::Disable_Stop_Button()
+{
+ // if we disable focused button, then focus will be lost
+ if (GetFocus() == GetItem(IDB_STOP))
+ {
+ // SendMsg_NextDlgCtl_Prev();
+ SendMsg_NextDlgCtl_CtlId(IDB_RESTART);
+ }
+ EnableItem(IDB_STOP, false);
+}
+
+
+void CBenchmarkDialog::OnStopButton()
+{
+ if (ExitWasAsked_in_GUI)
+ return;
+
+ Disable_Stop_Button();
+
+ WasStopped_in_GUI = true;
+ if (_thread.IsCreated())
+ {
+ SendExit_Status(L"Stop ...");
+ }
+}
+
+
+
+void CBenchmarkDialog::OnCancel()
+{
+ ExitWasAsked_in_GUI = true;
+
+ /*
+ SendMsg_NextDlgCtl_Prev();
+ EnableItem(IDCANCEL, false);
+ */
+
+ if (_thread.IsCreated())
+ SendExit_Status(L"Cancel ...");
+ else
+ CModalDialog::OnCancel();
+}
+
+
+void CBenchmarkDialog::OnHelp()
+{
+ ShowHelpWindow(kHelpTopic);
+}
+
+
+
+// void GetTimeString(UInt64 timeValue, wchar_t *s);
+
+void CBenchmarkDialog::PrintTime()
+{
+ const UInt32 curTime =
+ _finishTime_WasSet ?
+ _finishTime :
+ ::GetTickCount();
+
+ const UInt32 elapsedTime = (curTime - _startTime);
+
+ WCHAR s[64];
+
+ WCHAR *p = ConvertUInt32ToString(elapsedTime / 1000, s);
+
+ if (_finishTime_WasSet)
+ {
+ *p++ = '.';
+ UINT_TO_STR_3(p, elapsedTime % 1000)
+ }
+
+ // p = NumberToDot3((UInt64)elapsedTime, s);
+
+ MyStringCopy(p, L" s");
+
+ // if (WasStopped_in_GUI) wcscat(s, L" X"); // for debug
+
+ if (s == ElapsedSec_Prev)
+ return;
+
+ ElapsedSec_Prev = s;
+
+ // static cnt = 0; cnt++; wcscat(s, L" ");
+ // UString s2; s2.Add_UInt32(cnt); wcscat(s, s2.Ptr());
+
+ SetItemText(IDT_BENCH_ELAPSED_VAL, s);
+}
+
+
+static UInt64 GetMips(UInt64 ips)
+{
+ return (ips + 500000) / 1000000;
+}
+
+
+static UInt64 GetUsagePercents(UInt64 usage)
+{
+ return Benchmark_GetUsage_Percents(usage);
+}
+
+
+static UInt32 GetRating(const CTotalBenchRes &info)
+{
+ UInt64 numIter = info.NumIterations2;
+ if (numIter == 0)
+ numIter = 1000000;
+ const UInt64 rating64 = GetMips(info.Rating / numIter);
+ // return rating64;
+ UInt32 rating32 = (UInt32)rating64;
+ if (rating32 != rating64)
+ rating32 = (UInt32)(Int32)-1;
+ return rating32;
+}
+
+
+static void AddUsageString(UString &s, const CTotalBenchRes &info)
+{
+ UInt64 numIter = info.NumIterations2;
+ if (numIter == 0)
+ numIter = 1000000;
+ UInt64 usage = GetUsagePercents(info.Usage / numIter);
+
+ wchar_t w[64];
+ ConvertUInt64ToString(usage, w);
+ unsigned len = MyStringLen(w);
+ while (len < 5)
+ {
+ s.Add_Space();
+ len++;
+ }
+ s += w;
+ s += "%";
+}
+
+
+static void Add_Dot3String(UString &s, UInt64 val)
+{
+ WCHAR temp[32];
+ NumberToDot3(val, temp);
+ s += temp;
+}
+
+
+static void AddRatingString(UString &s, const CTotalBenchRes &info)
+{
+ // AddUsageString(s, info);
+ // s += " ";
+ // s.Add_UInt32(GetRating(info));
+ Add_Dot3String(s, GetRating(info));
+}
+
+
+static void AddRatingsLine(UString &s, const CTotalBenchRes &enc, const CTotalBenchRes &dec
+ #ifdef PRINT_ITER_TIME
+ , DWORD ticks
+ #endif
+ )
+{
+ // AddUsageString(s, enc); s += " ";
+
+ AddRatingString(s, enc);
+ s += " ";
+ AddRatingString(s, dec);
+
+ CTotalBenchRes tot_BenchRes;
+ tot_BenchRes.SetSum(enc, dec);
+
+ s += " ";
+ AddRatingString(s, tot_BenchRes);
+
+ s += " "; AddUsageString(s, tot_BenchRes);
+
+
+ #ifdef PRINT_ITER_TIME
+ s += " ";
+ {
+ Add_Dot3String(s, ticks;
+ s += " s";
+ // s.Add_UInt32(ticks); s += " ms";
+ }
+ #endif
+}
+
+
+void CBenchmarkDialog::PrintRating(UInt64 rating, UINT controlID)
+{
+ // SetItemText_Number(controlID, GetMips(rating), kMIPS);
+ WCHAR s[64];
+ MyStringCopy(NumberToDot3(GetMips(rating), s), L" GIPS");
+ SetItemText(controlID, s);
+}
+
+void CBenchmarkDialog::PrintUsage(UInt64 usage, UINT controlID)
+{
+ SetItemText_Number(controlID, GetUsagePercents(usage), TEXT("%"));
+}
+
+
+// void SetItemText_Number
+
+void CBenchmarkDialog::PrintBenchRes(
+ const CTotalBenchRes2 &info,
+ const UINT ids[])
+{
+ if (info.NumIterations2 == 0)
+ return;
+ if (ids[1] != 0)
+ SetItemText_Number(ids[1], (info.Speed >> 10) / info.NumIterations2, kKBs);
+ PrintRating(info.Rating / info.NumIterations2, ids[3]);
+ PrintRating(info.RPU / info.NumIterations2, ids[2]);
+ PrintUsage(info.Usage / info.NumIterations2, ids[0]);
+ if (ids[4] != 0)
+ {
+ UInt64 val = info.UnpackSize;
+ LPCTSTR kPostfix;
+ if (val >= ((UInt64)1 << 40))
+ {
+ kPostfix = kGB;
+ val >>= 30;
+ }
+ else
+ {
+ kPostfix = kMB;
+ val >>= 20;
+ }
+ SetItemText_Number(ids[4], val, kPostfix);
+ }
+}
+
+
+// static UInt32 k_Message_Finished_cnt = 0;
+// static UInt32 k_OnTimer_cnt = 0;
+
+bool CBenchmarkDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ if (message != k_Message_Finished)
+ return CModalDialog::OnMessage(message, wParam, lParam);
+
+ {
+ if (wParam == k_Msg_WPARM_Thread_Finished)
+ {
+ _finishTime = GetTickCount();
+ _finishTime_WasSet = true;
+ MyKillTimer();
+
+ if (_thread.Wait_Close() != 0)
+ {
+ MessageBoxError_Status(L"Thread Wait Error");
+ }
+
+ if (!WasStopped_in_GUI)
+ {
+ WasStopped_in_GUI = true;
+ Disable_Stop_Button();
+ }
+
+ HRESULT res = Sync.BenchFinish_Thread_HRESULT;
+ if (res != S_OK)
+ // if (!ExitWasAsked_in_GUI || res != E_ABORT)
+ MessageBoxError_Status(HResultToMessage(res));
+
+ if (ExitWasAsked_in_GUI)
+ {
+ // SetItemText(IDT_BENCH_ERROR_MESSAGE, "before CModalDialog::OnCancel()");
+ // Sleep (2000);
+ // MessageBoxError(L"test");
+ CModalDialog::OnCancel();
+ return true;
+ }
+
+ SetItemText_Empty(IDT_BENCH_ERROR_MESSAGE);
+
+ res = Sync.BenchFinish_Task_HRESULT;
+ if (res != S_OK)
+ {
+ if (!WasStopped_in_GUI || res != E_ABORT)
+ {
+ UString m;
+ if (res == S_FALSE)
+ m = "Decoding error";
+ else if (res == CLASS_E_CLASSNOTAVAILABLE)
+ m = "Can't find 7z.dll";
+ else
+ m = HResultToMessage(res);
+ MessageBoxError_Status(m);
+ }
+ }
+
+ if (NeedRestart)
+ {
+ StartBenchmark();
+ return true;
+ }
+ }
+ // k_Message_Finished_cnt++;
+ UpdateGui();
+ return true;
+ }
+}
+
+
+bool CBenchmarkDialog::OnTimer(WPARAM timerID, LPARAM /* callback */)
+{
+ // k_OnTimer_cnt++;
+ if (timerID == kTimerID)
+ UpdateGui();
+ return true;
+}
+
+
+void CBenchmarkDialog::UpdateGui()
+{
+ PrintTime();
+
+ if (TotalMode)
+ {
+ bool wasChanged = false;
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS);
+
+ if (Sync.TextWasChanged)
+ {
+ wasChanged = true;
+ Bench2Text += Sync.Text;
+ Sync.Text.Empty();
+ Sync.TextWasChanged = false;
+ }
+ }
+ if (wasChanged)
+ _consoleEdit.SetText(Bench2Text);
+ return;
+ }
+
+ CSyncData sd;
+ CRecordVector<CBenchPassResult> RatingVector;
+
+ {
+ NWindows::NSynchronization::CCriticalSectionLock lock(Sync.CS);
+ sd = Sync.sd;
+
+ if (sd.NeedPrint_RatingVector)
+ RatingVector = Sync.RatingVector;
+
+ if (sd.NeedPrint_Freq)
+ {
+ Sync.FreqString_GUI = Sync.FreqString_Sync;
+ sd.NeedPrint_RatingVector = true;
+ }
+
+ Sync.sd.NeedPrint_RatingVector = false;
+ Sync.sd.NeedPrint_Enc_1 = false;
+ Sync.sd.NeedPrint_Enc = false;
+ Sync.sd.NeedPrint_Dec_1 = false;
+ Sync.sd.NeedPrint_Dec = false;
+ Sync.sd.NeedPrint_Tot = false;
+ Sync.sd.NeedPrint_Freq = false;
+ }
+
+ if (sd.NumPasses_Finished != NumPasses_Finished_Prev)
+ {
+ SetItemText_Number(IDT_BENCH_PASSES_VAL, sd.NumPasses_Finished, TEXT(" /"));
+ NumPasses_Finished_Prev = sd.NumPasses_Finished;
+ }
+
+ if (sd.NeedPrint_Enc_1) PrintBenchRes(sd.Enc_BenchRes_1, k_Ids_Enc_1);
+ if (sd.NeedPrint_Enc) PrintBenchRes(sd.Enc_BenchRes, k_Ids_Enc);
+ if (sd.NeedPrint_Dec_1) PrintBenchRes(sd.Dec_BenchRes_1, k_Ids_Dec_1);
+ if (sd.NeedPrint_Dec) PrintBenchRes(sd.Dec_BenchRes, k_Ids_Dec);
+
+ if (sd.BenchWasFinished && sd.NeedPrint_Tot)
+ {
+ CTotalBenchRes2 tot_BenchRes = sd.Enc_BenchRes;
+ tot_BenchRes.Update_With_Res2(sd.Dec_BenchRes);
+ PrintBenchRes(tot_BenchRes, k_Ids_Tot);
+ }
+
+
+ if (sd.NeedPrint_RatingVector)
+ // for (unsigned k = 0; k < 1; k++)
+ {
+ UString s;
+ s += Sync.FreqString_GUI;
+ if (!RatingVector.IsEmpty())
+ {
+ if (!s.IsEmpty())
+ s.Add_LF();
+ s += "Compr Decompr Total CPU"
+ #ifdef PRINT_ITER_TIME
+ " Time"
+ #endif
+ ;
+ s.Add_LF();
+ }
+ // s += "GIPS GIPS GIPS % s"; s.Add_LF();
+ for (unsigned i = 0; i < RatingVector.Size(); i++)
+ {
+ if (i != 0)
+ s.Add_LF();
+ if ((int)i == sd.RatingVector_DeletedIndex)
+ {
+ s += "...";
+ s.Add_LF();
+ }
+ const CBenchPassResult &pair = RatingVector[i];
+ /*
+ s += "g:"; s.Add_UInt32((UInt32)pair.EncInfo.GlobalTime);
+ s += " u:"; s.Add_UInt32((UInt32)pair.EncInfo.UserTime);
+ s += " ";
+ */
+ AddRatingsLine(s, pair.Enc, pair.Dec
+ #ifdef PRINT_ITER_TIME
+ , pair.Ticks
+ #endif
+ );
+ /*
+ {
+ UInt64 v = i + 1;
+ if (sd.RatingVector_DeletedIndex >= 0 && i >= (unsigned)sd.RatingVector_DeletedIndex)
+ v += sd.RatingVector_NumDeleted;
+ char temp[64];
+ ConvertUInt64ToString(v, temp);
+ s += " : ";
+ s += temp;
+ }
+ */
+ }
+
+ if (sd.BenchWasFinished)
+ {
+ s.Add_LF();
+ s += "-------------";
+ s.Add_LF();
+ {
+ // average time is not correct because of freq detection in first iteration
+ AddRatingsLine(s, sd.Enc_BenchRes, sd.Dec_BenchRes
+ #ifdef PRINT_ITER_TIME
+ , (DWORD)(sd.TotalTicks / (sd.NumPasses_Finished ? sd.NumPasses_Finished : 1))
+ #endif
+ );
+ }
+ }
+ // s.Add_LF(); s += "OnTimer: "; s.Add_UInt32(k_OnTimer_cnt);
+ // s.Add_LF(); s += "finished Message: "; s.Add_UInt32(k_Message_Finished_cnt);
+ // static cnt = 0; cnt++; s.Add_LF(); s += "Print: "; s.Add_UInt32(cnt);
+ // s.Add_LF(); s += "NumEncProgress: "; s.Add_UInt32((UInt32)sd.NumEncProgress);
+ // s.Add_LF(); s += "NumDecProgress: "; s.Add_UInt32((UInt32)sd.NumDecProgress);
+ SetItemText(IDT_BENCH_LOG, s);
+ }
+}
+
+
+bool CBenchmarkDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam)
+{
+ if (code == CBN_SELCHANGE &&
+ (itemID == IDC_BENCH_DICTIONARY ||
+ itemID == IDC_BENCH_NUM_PASSES ||
+ itemID == IDC_BENCH_NUM_THREADS))
+ {
+ RestartBenchmark();
+ return true;
+ }
+ return CModalDialog::OnCommand(code, itemID, lParam);
+}
+
+
+bool CBenchmarkDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ switch (buttonID)
+ {
+ case IDB_RESTART:
+ RestartBenchmark();
+ return true;
+ case IDB_STOP:
+ OnStopButton();
+ return true;
+ }
+ return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
+}
+
+
+
+
+
+// ---------- Benchmark Thread ----------
+
+struct CBenchCallback Z7_final: public IBenchCallback
+{
+ UInt64 dictionarySize;
+ CBenchProgressSync *Sync;
+ CBenchmarkDialog *BenchmarkDialog;
+
+ HRESULT SetEncodeResult(const CBenchInfo &info, bool final) Z7_override;
+ HRESULT SetDecodeResult(const CBenchInfo &info, bool final) Z7_override;
+};
+
+HRESULT CBenchCallback::SetEncodeResult(const CBenchInfo &info, bool final)
+{
+ bool needPost = false;
+ {
+ NSynchronization::CCriticalSectionLock lock(Sync->CS);
+ if (Sync->Exit)
+ return E_ABORT;
+ CSyncData &sd = Sync->sd;
+ // sd.NumEncProgress++;
+ CTotalBenchRes2 &br = sd.Enc_BenchRes_1;
+ {
+ UInt64 dictSize = Sync->DictSize;
+ if (final)
+ {
+ // sd.EncInfo = info;
+ }
+ else
+ {
+ /* if (!final), then CBenchInfo::NumIterations means totalNumber of threads.
+ so we can reduce the dictionary */
+ if (dictSize > info.UnpackSize)
+ dictSize = info.UnpackSize;
+ }
+ br.Rating = info.GetRating_LzmaEnc(dictSize);
+ }
+ br.SetFrom_BenchInfo(info);
+ sd.NeedPrint_Enc_1 = true;
+ if (final)
+ {
+ sd.Enc_BenchRes.Update_With_Res2(br);
+ sd.NeedPrint_Enc = true;
+ needPost = true;
+ }
+ }
+
+ if (needPost)
+ BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished);
+
+ return S_OK;
+}
+
+
+HRESULT CBenchCallback::SetDecodeResult(const CBenchInfo &info, bool final)
+{
+ NSynchronization::CCriticalSectionLock lock(Sync->CS);
+ if (Sync->Exit)
+ return E_ABORT;
+ CSyncData &sd = Sync->sd;
+ // sd.NumDecProgress++;
+ CTotalBenchRes2 &br = sd.Dec_BenchRes_1;
+ br.Rating = info.GetRating_LzmaDec();
+ br.SetFrom_BenchInfo(info);
+ sd.NeedPrint_Dec_1 = true;
+ if (final)
+ sd.Dec_BenchRes.Update_With_Res2(br);
+ return S_OK;
+}
+
+
+struct CBenchCallback2 Z7_final: public IBenchPrintCallback
+{
+ CBenchProgressSync *Sync;
+ bool TotalMode;
+
+ void Print(const char *s) Z7_override;
+ void NewLine() Z7_override;
+ HRESULT CheckBreak() Z7_override;
+};
+
+void CBenchCallback2::Print(const char *s)
+{
+ if (TotalMode)
+ {
+ NSynchronization::CCriticalSectionLock lock(Sync->CS);
+ Sync->Text += s;
+ Sync->TextWasChanged = true;
+ }
+}
+
+void CBenchCallback2::NewLine()
+{
+ Print("\xD\n");
+}
+
+HRESULT CBenchCallback2::CheckBreak()
+{
+ if (Sync->Exit)
+ return E_ABORT;
+ return S_OK;
+}
+
+
+
+struct CFreqCallback Z7_final: public IBenchFreqCallback
+{
+ CBenchmarkDialog *BenchmarkDialog;
+
+ virtual HRESULT AddCpuFreq(unsigned numThreads, UInt64 freq, UInt64 usage) Z7_override;
+ virtual HRESULT FreqsFinished(unsigned numThreads) Z7_override;
+};
+
+HRESULT CFreqCallback::AddCpuFreq(unsigned numThreads, UInt64 freq, UInt64 usage)
+{
+ HRESULT res;
+ {
+ CBenchProgressSync &sync = BenchmarkDialog->Sync;
+ NSynchronization::CCriticalSectionLock lock(sync.CS);
+ UString &s = sync.FreqString_Sync;
+ if (sync.NumFreqThreadsPrev != numThreads)
+ {
+ sync.NumFreqThreadsPrev = numThreads;
+ if (!s.IsEmpty())
+ s.Add_LF();
+ s.Add_UInt32(numThreads);
+ s += "T Frequency (MHz):";
+ s.Add_LF();
+ }
+ s += " ";
+ if (numThreads != 1)
+ {
+ s.Add_UInt64(GetUsagePercents(usage));
+ s += '%';
+ s.Add_Space();
+ }
+ s.Add_UInt64(GetMips(freq));
+ // BenchmarkDialog->Sync.sd.NeedPrint_Freq = true;
+ res = sync.Exit ? E_ABORT : S_OK;
+ }
+ // BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished);
+ return res;
+}
+
+HRESULT CFreqCallback::FreqsFinished(unsigned /* numThreads */)
+{
+ HRESULT res;
+ {
+ CBenchProgressSync &sync = BenchmarkDialog->Sync;
+ NSynchronization::CCriticalSectionLock lock(sync.CS);
+ sync.sd.NeedPrint_Freq = true;
+ BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished);
+ res = sync.Exit ? E_ABORT : S_OK;
+ }
+ BenchmarkDialog->PostMsg(k_Message_Finished, k_Msg_WPARM_Enc1_Finished);
+ return res;
+}
+
+
+
+// define USE_DUMMY only for debug
+// #define USE_DUMMY
+#ifdef USE_DUMMY
+static unsigned dummy = 1;
+static unsigned Dummy(unsigned limit)
+{
+ unsigned sum = 0;
+ for (unsigned k = 0; k < limit; k++)
+ {
+ sum += dummy;
+ if (sum == 0)
+ break;
+ }
+ return sum;
+}
+#endif
+
+
+HRESULT CThreadBenchmark::Process()
+{
+ /* the first benchmark pass can be slow,
+ if we run benchmark while the window is being created,
+ and (no freq detecion loop) && (dictionary is small) (-mtic is small) */
+
+ // Sleep(300); // for debug
+ #ifdef USE_DUMMY
+ Dummy(1000 * 1000 * 1000); // for debug
+ #endif
+
+ CBenchProgressSync &sync = BenchmarkDialog->Sync;
+ HRESULT finishHRESULT = S_OK;
+
+ try
+ {
+ for (UInt32 passIndex = 0;; passIndex++)
+ {
+ // throw 1; // to debug
+ // throw CSystemException(E_INVALIDARG); // to debug
+
+ UInt64 dictionarySize;
+ UInt32 numThreads;
+ {
+ NSynchronization::CCriticalSectionLock lock(sync.CS);
+ if (sync.Exit)
+ break;
+ dictionarySize = sync.DictSize;
+ numThreads = sync.NumThreads;
+ }
+
+ #ifdef PRINT_ITER_TIME
+ const DWORD startTick = GetTickCount();
+ #endif
+
+ CBenchCallback callback;
+
+ callback.dictionarySize = dictionarySize;
+ callback.Sync = &sync;
+ callback.BenchmarkDialog = BenchmarkDialog;
+
+ CBenchCallback2 callback2;
+ callback2.TotalMode = BenchmarkDialog->TotalMode;
+ callback2.Sync = &sync;
+
+ CFreqCallback freqCallback;
+ freqCallback.BenchmarkDialog = BenchmarkDialog;
+
+ HRESULT result;
+
+ try
+ {
+ CObjectVector<CProperty> props;
+
+ props = BenchmarkDialog->Props;
+
+ if (BenchmarkDialog->TotalMode)
+ {
+ props = BenchmarkDialog->Props;
+ }
+ else
+ {
+ {
+ CProperty prop;
+ prop.Name = "mt";
+ prop.Value.Add_UInt32(numThreads);
+ props.Add(prop);
+ }
+ {
+ CProperty prop;
+ prop.Name = 'd';
+ prop.Name.Add_UInt32((UInt32)(dictionarySize >> 10));
+ prop.Name += 'k';
+ props.Add(prop);
+ }
+ }
+
+ result = Bench(EXTERNAL_CODECS_LOC_VARS
+ BenchmarkDialog->TotalMode ? &callback2 : NULL,
+ BenchmarkDialog->TotalMode ? NULL : &callback,
+ props, 1, false,
+ (!BenchmarkDialog->TotalMode) && passIndex == 0 ? &freqCallback: NULL);
+
+ // result = S_FALSE; // for debug;
+ // throw 1;
+ }
+ catch(...)
+ {
+ result = E_FAIL;
+ }
+
+ #ifdef PRINT_ITER_TIME
+ const DWORD numTicks = GetTickCount() - startTick;
+ #endif
+
+ bool finished = true;
+
+ NSynchronization::CCriticalSectionLock lock(sync.CS);
+
+ if (result != S_OK)
+ {
+ sync.BenchFinish_Task_HRESULT = result;
+ break;
+ }
+
+ {
+ CSyncData &sd = sync.sd;
+
+ sd.NumPasses_Finished++;
+ #ifdef PRINT_ITER_TIME
+ sd.TotalTicks += numTicks;
+ #endif
+
+ if (BenchmarkDialog->TotalMode)
+ break;
+
+ {
+ CTotalBenchRes tot_BenchRes = sd.Enc_BenchRes_1;
+ tot_BenchRes.Update_With_Res(sd.Dec_BenchRes_1);
+
+ sd.NeedPrint_RatingVector = true;
+ {
+ CBenchPassResult pair;
+ // pair.EncInfo = sd.EncInfo; // for debug
+ pair.Enc = sd.Enc_BenchRes_1;
+ pair.Dec = sd.Dec_BenchRes_1;
+ #ifdef PRINT_ITER_TIME
+ pair.Ticks = numTicks;
+ #endif
+ sync.RatingVector.Add(pair);
+ // pair.Dec_Defined = true;
+ }
+ }
+
+ sd.NeedPrint_Dec = true;
+ sd.NeedPrint_Tot = true;
+
+ if (sync.RatingVector.Size() > kRatingVector_NumBundlesMax)
+ {
+ // sd.RatingVector_NumDeleted++;
+ sd.RatingVector_DeletedIndex = (int)(kRatingVector_NumBundlesMax / 4);
+ sync.RatingVector.Delete((unsigned)(sd.RatingVector_DeletedIndex));
+ }
+
+ if (sync.sd.NumPasses_Finished < sync.NumPasses_Limit)
+ finished = false;
+ else
+ {
+ sync.sd.BenchWasFinished = true;
+ // BenchmarkDialog->_finishTime = GetTickCount();
+ // return 0;
+ }
+ }
+
+ if (BenchmarkDialog->TotalMode)
+ break;
+
+ /*
+ if (newTick - prevTick < 1000)
+ numSameTick++;
+ if (numSameTick > 5 || finished)
+ {
+ prevTick = newTick;
+ numSameTick = 0;
+ */
+ // for (unsigned i = 0; i < 1; i++)
+ {
+ // we suppose that PostMsg messages will be processed in order.
+ if (!BenchmarkDialog->PostMsg_Finish(k_Msg_WPARM_Iter_Finished))
+ {
+ finished = true;
+ finishHRESULT = E_FAIL;
+ // throw 1234567;
+ }
+ }
+ if (finished)
+ break;
+ }
+ // return S_OK;
+ }
+ catch(CSystemException &e)
+ {
+ finishHRESULT = e.ErrorCode;
+ // BenchmarkDialog->MessageBoxError(HResultToMessage(e.ErrorCode));
+ // return E_FAIL;
+ }
+ catch(...)
+ {
+ finishHRESULT = E_FAIL;
+ // BenchmarkDialog->MessageBoxError(HResultToMessage(E_FAIL));
+ // return E_FAIL;
+ }
+
+ if (finishHRESULT != S_OK)
+ {
+ NSynchronization::CCriticalSectionLock lock(sync.CS);
+ sync.BenchFinish_Thread_HRESULT = finishHRESULT;
+ }
+ if (!BenchmarkDialog->PostMsg_Finish(k_Msg_WPARM_Thread_Finished))
+ {
+ // sync.BenchFinish_Thread_HRESULT = E_FAIL;
+ }
+ return 0;
+}
+
+
+
+static void ParseNumberString(const UString &s, NCOM::CPropVariant &prop)
+{
+ const wchar_t *end;
+ UInt64 result = ConvertStringToUInt64(s, &end);
+ if (*end != 0 || s.IsEmpty())
+ prop = s;
+ else if (result <= (UInt32)0xFFFFFFFF)
+ prop = (UInt32)result;
+ else
+ prop = result;
+}
+
+
+HRESULT Benchmark(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const CObjectVector<CProperty> &props, UInt32 numIterations, HWND hwndParent)
+{
+ CBenchmarkDialog bd;
+
+ bd.TotalMode = false;
+ bd.Props = props;
+ if (numIterations == 0)
+ numIterations = 1;
+ bd.Sync.NumPasses_Limit = numIterations;
+ bd.Sync.DictSize = (UInt64)(Int64)-1;
+ bd.Sync.NumThreads = (UInt32)(Int32)-1;
+ bd.Sync.Level = -1;
+
+ COneMethodInfo method;
+
+ UInt32 numCPUs = 1;
+ #ifndef Z7_ST
+ numCPUs = NSystem::GetNumberOfProcessors();
+ #endif
+ UInt32 numThreads = numCPUs;
+
+ FOR_VECTOR (i, props)
+ {
+ const CProperty &prop = props[i];
+ UString name = prop.Name;
+ name.MakeLower_Ascii();
+ if (name.IsEqualTo_Ascii_NoCase("m") && prop.Value == L"*")
+ {
+ bd.TotalMode = true;
+ continue;
+ }
+
+ NCOM::CPropVariant propVariant;
+ if (!prop.Value.IsEmpty())
+ ParseNumberString(prop.Value, propVariant);
+ if (name.IsPrefixedBy(L"mt"))
+ {
+ #ifndef Z7_ST
+ RINOK(ParseMtProp(name.Ptr(2), propVariant, numCPUs, numThreads))
+ if (numThreads != numCPUs)
+ bd.Sync.NumThreads = numThreads;
+ #endif
+ continue;
+ }
+ /*
+ if (name.IsEqualTo("time"))
+ {
+ // UInt32 testTime = 4;
+ // RINOK(ParsePropToUInt32(L"", propVariant, testTime));
+ continue;
+ }
+ RINOK(method.ParseMethodFromPROPVARIANT(name, propVariant));
+ */
+ // here we need to parse DictSize property, and ignore unknown properties
+ method.ParseMethodFromPROPVARIANT(name, propVariant);
+ }
+
+ if (bd.TotalMode)
+ {
+ // bd.Bench2Text.Empty();
+ bd.Bench2Text = "7-Zip " MY_VERSION_CPU;
+ bd.Bench2Text += (char)0xD;
+ bd.Bench2Text.Add_LF();
+ }
+
+ {
+ UInt64 dict;
+ if (method.Get_DicSize(dict))
+ bd.Sync.DictSize = dict;
+ }
+ bd.Sync.Level = (int)method.GetLevel();
+
+ // Dummy(1000 * 1000 * 1);
+
+ {
+ CThreadBenchmark &benchmarker = bd._threadBenchmark;
+ #ifdef Z7_EXTERNAL_CODECS
+ benchmarker._externalCodecs = _externalCodecs;
+ #endif
+ benchmarker.BenchmarkDialog = &bd;
+ }
+
+ bd.Create(hwndParent);
+
+ return S_OK;
+}
+
+
+CBenchmarkDialog::~CBenchmarkDialog()
+{
+ if (_thread.IsCreated())
+ {
+ /* the following code will be not executed in normal code flow.
+ it can be called, if there is some internal failure in dialog code. */
+ Attach(NULL);
+ MessageBoxError(L"The flaw in benchmark thread code");
+ Sync.SendExit();
+ _thread.Wait_Close();
+ }
+}
diff --git a/CPP/7zip/UI/GUI/BenchmarkDialog.h b/CPP/7zip/UI/GUI/BenchmarkDialog.h
new file mode 100644
index 0000000..63c6ded
--- /dev/null
+++ b/CPP/7zip/UI/GUI/BenchmarkDialog.h
@@ -0,0 +1,15 @@
+// BenchmarkDialog.h
+
+#ifndef ZIP7_INC_BENCHMARK_DIALOG_H
+#define ZIP7_INC_BENCHMARK_DIALOG_H
+
+#include "../../Common/CreateCoder.h"
+#include "../../UI/Common/Property.h"
+
+const UInt32 k_NumBenchIterations_Default = 10;
+
+HRESULT Benchmark(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const CObjectVector<CProperty> &props, UInt32 numIterations, HWND hwndParent = NULL);
+
+#endif
diff --git a/CPP/7zip/UI/GUI/BenchmarkDialog.rc b/CPP/7zip/UI/GUI/BenchmarkDialog.rc
new file mode 100644
index 0000000..3e73e46
--- /dev/null
+++ b/CPP/7zip/UI/GUI/BenchmarkDialog.rc
@@ -0,0 +1,288 @@
+#include "BenchmarkDialogRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 332
+#define yc 248
+
+#undef g0xs
+#undef g1x
+#undef g1xs
+#undef g2xs
+#undef g3x
+#undef g3xs
+#undef g4x
+
+#define gs 160
+#define gSpace 24
+
+#define g0xs 90
+#define g1xs 48
+#define g1x (m + g0xs)
+#define gc2x (g1x + g1xs + m)
+#define gc2xs 80
+
+#define g4x (m + m)
+
+#define sRating 58
+#define sSpeed 60
+#define sUsage 46
+#define sRpu 58
+#define sSize 52
+// #define sFreq 34
+
+#define xRating (xs - m - m - sRating)
+#define xRpu (xRating - sRpu)
+#define xUsage (xRpu - sUsage)
+#define xSpeed (xUsage - sSpeed)
+#define xSize (xSpeed - sSize)
+
+// #define xFreq (xUsage - sFreq)
+
+#define sLabel (xSize - g4x)
+#define sTotalRating (sUsage + sRpu + sRating + m + m)
+#define xTotalRating (xs - m - sTotalRating)
+
+#define sPasses 60
+
+#define g2xs 60
+#define g3xs 64
+#define g3x (m + g2xs)
+
+#undef GROUP_Y_SIZE
+#undef GROUP_Y2_SIZE
+#ifdef UNDER_CE
+#define GROUP_Y_SIZE 8
+#define GROUP_Y2_SIZE 8
+#else
+#define GROUP_Y_SIZE 40
+#define GROUP_Y2_SIZE 32
+#endif
+
+#define g7xs bx1 - m - g0xs - g1xs - m
+
+#define sLog 140 + 0
+
+// MY_MODAL_DIALOG_STYLE
+IDD_BENCH DIALOG 0, 0, xs + sLog, ys MY_MODAL_RESIZE_DIALOG_STYLE | WS_MINIMIZEBOX
+CAPTION "Benchmark"
+MY_FONT
+BEGIN
+ PUSHBUTTON "&Restart", IDB_RESTART, bx1, m, bxs, bys
+ PUSHBUTTON "&Stop", IDB_STOP, bx1, m + bys + 6, bxs, bys
+
+ PUSHBUTTON "&Help", IDHELP, bx2, by, bxs, bys
+ PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys
+
+ LTEXT "&Dictionary size:", IDT_BENCH_DICTIONARY, m, m + 1, g0xs, 8
+ COMBOBOX IDC_BENCH_DICTIONARY, g1x, m, g1xs, 140, MY_COMBO
+
+ LTEXT "Memory usage:", IDT_BENCH_MEMORY, gc2x, m - 2, g7xs, 8
+ LTEXT "", IDT_BENCH_MEMORY_VAL, gc2x, m + 8, g7xs, MY_TEXT_NOPREFIX
+
+ LTEXT "&Number of CPU threads:", IDT_BENCH_NUM_THREADS, m, 30, g0xs, 8
+ COMBOBOX IDC_BENCH_NUM_THREADS, g1x, 29, g1xs, 140, MY_COMBO
+ LTEXT "", IDT_BENCH_HARDWARE_THREADS, gc2x, 30, g7xs, MY_TEXT_NOPREFIX
+
+ RTEXT "Size", IDT_BENCH_SIZE, xSize, 54, sSize, MY_TEXT_NOPREFIX
+ RTEXT "CPU Usage", IDT_BENCH_USAGE_LABEL, xUsage, 54, sUsage, MY_TEXT_NOPREFIX
+ RTEXT "Speed", IDT_BENCH_SPEED, xSpeed, 54, sSpeed, MY_TEXT_NOPREFIX
+ RTEXT "Rating / Usage", IDT_BENCH_RPU_LABEL, xRpu, 54, sRpu, MY_TEXT_NOPREFIX
+ RTEXT "Rating", IDT_BENCH_RATING_LABEL, xRating, 54, sRating, MY_TEXT_NOPREFIX
+
+ GROUPBOX "Compressing", IDG_BENCH_COMPRESSING, m, 64, xc, GROUP_Y_SIZE
+
+ LTEXT "Current", IDT_BENCH_CURRENT, g4x, 76, sLabel, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_COMPRESS_SIZE1, xSize, 76, sSize, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_COMPRESS_USAGE1, xUsage, 76, sUsage, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_COMPRESS_SPEED1, xSpeed, 76, sSpeed, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_COMPRESS_RPU1, xRpu, 76, sRpu, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_COMPRESS_RATING1, xRating, 76, sRating, MY_TEXT_NOPREFIX
+
+ LTEXT "Resulting", IDT_BENCH_RESULTING, g4x, 89, sLabel, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_COMPRESS_SIZE2, xSize, 89, sSize, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_COMPRESS_USAGE2, xUsage, 89, sUsage, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_COMPRESS_SPEED2, xSpeed, 89, sSpeed, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_COMPRESS_RPU2, xRpu, 89, sRpu, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_COMPRESS_RATING2, xRating, 89, sRating, MY_TEXT_NOPREFIX
+
+ GROUPBOX "Decompressing", IDG_BENCH_DECOMPRESSING, m, 111, xc, GROUP_Y_SIZE
+
+ LTEXT "Current", IDT_BENCH_CURRENT2, g4x, 123, sLabel, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_DECOMPR_SIZE1, xSize, 123, sSize, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_DECOMPR_USAGE1, xUsage, 123, sUsage, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_DECOMPR_SPEED1, xSpeed, 123, sSpeed, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_DECOMPR_RPU1, xRpu, 123, sRpu, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_DECOMPR_RATING1, xRating, 123, sRating, MY_TEXT_NOPREFIX
+
+ LTEXT "Resulting", IDT_BENCH_RESULTING2, g4x, 136, sLabel, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_DECOMPR_SIZE2, xSize, 136, sSize, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_DECOMPR_USAGE2, xUsage, 136, sUsage, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_DECOMPR_SPEED2, xSpeed, 136, sSpeed, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_DECOMPR_RPU2, xRpu, 136, sRpu, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_DECOMPR_RATING2, xRating, 136, sRating, MY_TEXT_NOPREFIX
+
+ RTEXT "", IDT_BENCH_ERROR_MESSAGE, m, 155, xc, MY_TEXT_NOPREFIX
+
+ GROUPBOX "Total Rating", IDG_BENCH_TOTAL_RATING, xTotalRating, 163, sTotalRating, GROUP_Y2_SIZE
+
+ RTEXT "", IDT_BENCH_TOTAL_USAGE_VAL, xUsage, 176, sUsage, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_TOTAL_RPU_VAL, xRpu, 176, sRpu, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_TOTAL_RATING_VAL, xRating, 176, sRating, MY_TEXT_NOPREFIX
+
+
+ // RTEXT "", IDT_BENCH_CPU, m + sPasses, 202, xc - sPasses, 16, SS_NOPREFIX
+ RTEXT "", IDT_BENCH_CPU, m + 0, 202, xc - 0, 16, SS_NOPREFIX
+ RTEXT "", IDT_BENCH_VER, m + xc - 100, 222, 100, MY_TEXT_NOPREFIX
+
+ LTEXT "", IDT_BENCH_CPU_FEATURE, m, 222, xc - 100, 16, SS_NOPREFIX // - 100
+ LTEXT "", IDT_BENCH_SYS1, m, 238, xc - 140, MY_TEXT_NOPREFIX
+ LTEXT "", IDT_BENCH_SYS2, m, 248, xc - 140, MY_TEXT_NOPREFIX
+
+ LTEXT "", IDT_BENCH_LOG, m + xc + m, m, sLog - m, yc, SS_LEFTNOWORDWRAP | SS_NOPREFIX
+
+
+ LTEXT "Elapsed time:", IDT_BENCH_ELAPSED, m, 163, g2xs, 8
+// LTEXT "Size:", IDT_BENCH_SIZE, m, 176, g2xs, 8
+ LTEXT "Passes:", IDT_BENCH_PASSES, m, 176, g2xs, 8
+ COMBOBOX IDC_BENCH_NUM_PASSES, m, 187, sPasses, 140, MY_COMBO
+
+ RTEXT "", IDT_BENCH_ELAPSED_VAL, g3x, 163, g3xs, MY_TEXT_NOPREFIX
+ // RTEXT "", IDT_BENCH_SIZE_VAL, g3x, 176, g3xs, MY_TEXT_NOPREFIX
+ RTEXT "", IDT_BENCH_PASSES_VAL, g3x, 176, g3xs, MY_TEXT_NOPREFIX
+
+END
+
+#ifdef UNDER_CE
+
+#undef m
+#define m 4
+
+#undef xc
+#undef yc
+
+#define xc 154
+#define yc 160
+
+#undef g0xs
+#undef g1x
+#undef g1xs
+#undef g2xs
+#undef g3x
+#undef g3xs
+
+#undef bxs
+#undef bys
+
+#define bxs 60
+#define bys 14
+
+#undef gs
+#undef gSpace
+
+#define gs 160
+#define gSpace 24
+
+#define g0xs (xc - bxs)
+#define g1xs 44
+
+#undef g4x
+#define g4x (m)
+
+#undef xRpu
+#undef xUsage
+#undef xRating
+#undef xTotalRating
+
+#undef sRpu
+#undef sRating
+#undef sUsage
+#undef sLabel
+#undef sTotalRating
+
+#define sRating 40
+#define sUsage 24
+#define sRpu 40
+
+#define xRating (xs - m - sRating)
+#define xRpu (xRating - sRpu)
+#define xUsage (xRpu - sUsage)
+
+#define sLabel (xUsage - g4x)
+#define sTotalRating (sRpu + sRating)
+#define xTotalRating (xs - m - sTotalRating)
+
+#define g3xs 32
+#define g3x (xRpu - g3xs)
+#define g2xs (g3x - m)
+
+
+IDD_BENCH_2 DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE | WS_MINIMIZEBOX
+CAPTION "Benchmark"
+MY_FONT
+BEGIN
+ PUSHBUTTON "&Restart", IDB_RESTART, bx1, m, bxs, bys
+ PUSHBUTTON "&Stop", IDB_STOP, bx1, m + bys + m, bxs, bys
+
+ PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys
+
+ LTEXT "&Dictionary size:", IDT_BENCH_DICTIONARY, m, m, g0xs, 8
+ COMBOBOX IDC_BENCH_DICTIONARY, m, m + 11, g1xs, 140, MY_COMBO
+
+ LTEXT "&Number of CPU threads:", IDT_BENCH_NUM_THREADS, m, 31, g0xs, 8
+ COMBOBOX IDC_BENCH_NUM_THREADS, m, 42, g1xs, 140, MY_COMBO
+
+ LTEXT "", IDT_BENCH_MEMORY_VAL, m + g1xs + 8, m + 13, xc - bxs - g1xs - 8, 8
+ LTEXT "", IDT_BENCH_HARDWARE_THREADS, m + g1xs + 8, 44, xc - bxs - g1xs - 8, 8
+
+ LTEXT "Current", IDT_BENCH_CURRENT, g4x, 70, sLabel, 8
+ RTEXT "", IDT_BENCH_COMPRESS_USAGE1, xUsage, 70, sUsage, 8
+ RTEXT "", IDT_BENCH_COMPRESS_RPU1, xRpu, 70, sRpu, 8
+ RTEXT "", IDT_BENCH_COMPRESS_RATING1, xRating, 70, sRating, 8
+
+ LTEXT "Resulting", IDT_BENCH_RESULTING, g4x, 80, sLabel, 8
+ RTEXT "", IDT_BENCH_COMPRESS_USAGE2, xUsage, 80, sUsage, 8
+ RTEXT "", IDT_BENCH_COMPRESS_RPU2, xRpu, 80, sRpu, 8
+ RTEXT "", IDT_BENCH_COMPRESS_RATING2, xRating, 80, sRating, 8
+
+ LTEXT "Compressing", IDG_BENCH_COMPRESSING, m, 60, xc - bxs, 8
+
+ LTEXT "Current", IDT_BENCH_CURRENT2, g4x, 104, sLabel, 8
+ RTEXT "", IDT_BENCH_DECOMPR_USAGE1, xUsage, 104, sUsage, 8
+ RTEXT "", IDT_BENCH_DECOMPR_RPU1, xRpu, 104, sRpu, 8
+ RTEXT "", IDT_BENCH_DECOMPR_RATING1, xRating, 104, sRating, 8
+
+ LTEXT "Resulting", IDT_BENCH_RESULTING2, g4x, 114, sLabel, 8
+ RTEXT "", IDT_BENCH_DECOMPR_USAGE2, xUsage, 114, sUsage, 8
+ RTEXT "", IDT_BENCH_DECOMPR_RPU2, xRpu, 114, sRpu, 8
+ RTEXT "", IDT_BENCH_DECOMPR_RATING2, xRating, 114, sRating, 8
+
+ LTEXT "Decompressing", IDG_BENCH_DECOMPRESSING, m, 94, xc, 8
+
+ RTEXT "", IDT_BENCH_TOTAL_RPU_VAL, xRpu, 140, sRpu, 8
+ RTEXT "", IDT_BENCH_TOTAL_RATING_VAL, xRating, 140, sRating, 8
+
+ LTEXT "Elapsed time:", IDT_BENCH_ELAPSED, m, 130, g2xs, 8
+ LTEXT "Size:", IDT_BENCH_SIZE, m, 140, g2xs, 8
+ LTEXT "Passes:", IDT_BENCH_PASSES, m, 150, g2xs, 8
+
+ RTEXT "", IDT_BENCH_ELAPSED_VAL, g3x, 130, g3xs, 8
+ RTEXT "", IDT_BENCH_SIZE_VAL, g3x, 140, g3xs, 8
+ RTEXT "", IDT_BENCH_PASSES_VAL, g3x, 150, g3xs, 8
+END
+
+#endif
+
+#include "../../GuiCommon.rc"
+
+#define xc 360
+#define yc 260
+
+IDD_BENCH_TOTAL DIALOG 0, 0, xs, ys MY_MODAL_RESIZE_DIALOG_STYLE MY_FONT
+CAPTION "Benchmark"
+{
+ LTEXT "Elapsed time:", IDT_BENCH_ELAPSED, m, m, 58, 8
+ RTEXT "", IDT_BENCH_ELAPSED_VAL, m + 58, m, 38, 8
+ EDITTEXT IDE_BENCH2_EDIT, m, m + 14, xc, yc - bys - m - 14, ES_MULTILINE | ES_READONLY | ES_AUTOVSCROLL | WS_VSCROLL | WS_HSCROLL
+ PUSHBUTTON "&Help", IDHELP, bx2, by, bxs, bys
+ PUSHBUTTON "Cancel", IDCANCEL, bx1, by, bxs, bys
+}
diff --git a/CPP/7zip/UI/GUI/BenchmarkDialogRes.h b/CPP/7zip/UI/GUI/BenchmarkDialogRes.h
new file mode 100644
index 0000000..b7d54b7
--- /dev/null
+++ b/CPP/7zip/UI/GUI/BenchmarkDialogRes.h
@@ -0,0 +1,79 @@
+#define IDD_BENCH 7600
+#define IDD_BENCH_2 17600
+#define IDD_BENCH_TOTAL 7699
+
+#define IDE_BENCH2_EDIT 100
+
+#define IDC_BENCH_DICTIONARY 101
+#define IDT_BENCH_MEMORY_VAL 102
+#define IDC_BENCH_NUM_THREADS 103
+#define IDT_BENCH_HARDWARE_THREADS 104
+
+#define IDT_BENCH_VER 105
+#define IDT_BENCH_CPU 106
+#define IDT_BENCH_SYS1 107
+#define IDT_BENCH_SYS2 108
+#define IDT_BENCH_CPU_FEATURE 109
+
+#define IDT_BENCH_COMPRESS_SPEED1 110
+#define IDT_BENCH_COMPRESS_SPEED2 111
+#define IDT_BENCH_COMPRESS_RATING1 112
+#define IDT_BENCH_COMPRESS_RATING2 113
+#define IDT_BENCH_COMPRESS_USAGE1 114
+#define IDT_BENCH_COMPRESS_USAGE2 115
+#define IDT_BENCH_COMPRESS_RPU1 116
+#define IDT_BENCH_COMPRESS_RPU2 117
+
+#define IDT_BENCH_DECOMPR_SPEED1 118
+#define IDT_BENCH_DECOMPR_SPEED2 119
+#define IDT_BENCH_DECOMPR_RATING1 120
+#define IDT_BENCH_DECOMPR_RATING2 121
+#define IDT_BENCH_DECOMPR_USAGE1 122
+#define IDT_BENCH_DECOMPR_USAGE2 123
+#define IDT_BENCH_DECOMPR_RPU1 124
+#define IDT_BENCH_DECOMPR_RPU2 125
+
+#define IDT_BENCH_TOTAL_RATING_VAL 130
+#define IDT_BENCH_TOTAL_RPU_VAL 131
+#define IDT_BENCH_TOTAL_USAGE_VAL 133
+
+#define IDT_BENCH_ELAPSED_VAL 140
+// #define IDT_BENCH_SIZE_VAL 141
+#define IDT_BENCH_PASSES_VAL 142
+#define IDC_BENCH_NUM_PASSES 143
+
+#define IDT_BENCH_LOG 160
+#define IDT_BENCH_ERROR_MESSAGE 161
+
+#define IDT_BENCH_COMPRESS_SIZE1 170
+#define IDT_BENCH_COMPRESS_SIZE2 171
+#define IDT_BENCH_DECOMPR_SIZE1 172
+#define IDT_BENCH_DECOMPR_SIZE2 173
+
+// #define IDT_BENCH_FREQ_CUR 150
+// #define IDT_BENCH_FREQ_RES 151
+
+#define IDB_STOP 442
+#define IDB_RESTART 443
+
+#define IDT_BENCH_DICTIONARY 4006
+#define IDT_BENCH_NUM_THREADS 4009
+
+#define IDT_BENCH_SIZE 1007
+#define IDT_BENCH_ELAPSED 3900
+#define IDT_BENCH_SPEED 3903
+
+#define IDT_BENCH_MEMORY 7601
+
+#define IDG_BENCH_COMPRESSING 7602
+#define IDG_BENCH_DECOMPRESSING 7603
+#define IDG_BENCH_TOTAL_RATING 7605
+
+#define IDT_BENCH_RATING_LABEL 7604
+#define IDT_BENCH_CURRENT 7606
+#define IDT_BENCH_RESULTING 7607
+#define IDT_BENCH_USAGE_LABEL 7608
+#define IDT_BENCH_RPU_LABEL 7609
+#define IDT_BENCH_PASSES 7610
+#define IDT_BENCH_CURRENT2 (7606+50)
+#define IDT_BENCH_RESULTING2 (7607+50)
diff --git a/CPP/7zip/UI/GUI/CompressDialog.cpp b/CPP/7zip/UI/GUI/CompressDialog.cpp
new file mode 100644
index 0000000..c2aee6c
--- /dev/null
+++ b/CPP/7zip/UI/GUI/CompressDialog.cpp
@@ -0,0 +1,3820 @@
+// CompressDialog.cpp
+
+#include "StdAfx.h"
+
+#include "../../../../C/CpuArch.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/System.h"
+
+#include "../../Common/MethodProps.h"
+
+#include "../FileManager/BrowseDialog.h"
+#include "../FileManager/FormatUtils.h"
+#include "../FileManager/HelpUtils.h"
+#include "../FileManager/PropertyName.h"
+#include "../FileManager/SplitUtils.h"
+
+#include "../Explorer/MyMessages.h"
+
+#include "../Common/ZipRegistry.h"
+
+#include "CompressDialog.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+#include "../FileManager/LangUtils.h"
+
+#include "CompressDialogRes.h"
+#include "ExtractRes.h"
+#include "resource2.h"
+
+// #define PRINT_PARAMS
+
+#ifdef Z7_LANG
+
+// #define IDS_OPTIONS 2100
+
+static const UInt32 kLangIDs[] =
+{
+ IDT_COMPRESS_ARCHIVE,
+ IDT_COMPRESS_UPDATE_MODE,
+ IDT_COMPRESS_FORMAT,
+ IDT_COMPRESS_LEVEL,
+ IDT_COMPRESS_METHOD,
+ IDT_COMPRESS_DICTIONARY,
+ IDT_COMPRESS_ORDER,
+ IDT_COMPRESS_SOLID,
+ IDT_COMPRESS_THREADS,
+ IDT_COMPRESS_PARAMETERS,
+
+ IDB_COMPRESS_OPTIONS, // IDS_OPTIONS
+
+ IDG_COMPRESS_OPTIONS,
+ IDX_COMPRESS_SFX,
+ IDX_COMPRESS_SHARED,
+ IDX_COMPRESS_DEL,
+
+ IDT_COMPRESS_MEMORY,
+ IDT_COMPRESS_MEMORY_DE,
+
+ IDG_COMPRESS_ENCRYPTION,
+ IDT_COMPRESS_ENCRYPTION_METHOD,
+ IDX_COMPRESS_ENCRYPT_FILE_NAMES,
+
+ IDT_PASSWORD_ENTER,
+ IDT_PASSWORD_REENTER,
+ IDX_PASSWORD_SHOW,
+
+ IDT_SPLIT_TO_VOLUMES,
+ IDT_COMPRESS_PATH_MODE,
+};
+#endif
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NName;
+using namespace NDir;
+
+static const unsigned kHistorySize = 20;
+
+static const UInt32 kSolidLog_NoSolid = 0;
+static const UInt32 kSolidLog_FullSolid = 64;
+
+static const UInt32 kLzmaMaxDictSize = (UInt32)15 << 28;
+
+static const UINT k_Message_ArcChanged = WM_APP + 1;
+
+/*
+static const UInt32 kZstd_MAX_DictSize = (UInt32)1 << MY_ZSTD_WINDOWLOG_MAX;
+*/
+
+/* The top value for windowLog_Chain:
+ (MY_ZSTD_CHAINLOG_MAX - 1): in BT mode
+ (MY_ZSTD_CHAINLOG_MAX) : in non-BT mode. But such big value is useless in most cases.
+ So we always reduce top value to (MY_ZSTD_CHAINLOG_MAX - 1) */
+/*
+static const unsigned kMaxDictChain = MY_ZSTD_CHAINLOG_MAX - 1;
+static const UInt32 kZstd_MAX_DictSize_Chain = (UInt32)1 << kMaxDictChain;
+*/
+
+static LPCSTR const kExeExt = ".exe";
+
+static const UInt32 g_Levels[] =
+{
+ IDS_METHOD_STORE,
+ IDS_METHOD_FASTEST,
+ 0,
+ IDS_METHOD_FAST,
+ 0,
+ IDS_METHOD_NORMAL,
+ 0,
+ IDS_METHOD_MAXIMUM,
+ 0,
+ IDS_METHOD_ULTRA
+};
+
+enum EMethodID
+{
+ kCopy,
+ kLZMA,
+ kLZMA2,
+ kPPMd,
+ kBZip2,
+ kDeflate,
+ kDeflate64,
+ kPPMdZip,
+ // kZSTD,
+ kSha256,
+ kSha1,
+ kCrc32,
+ kCrc64,
+ kGnu,
+ kPosix
+};
+
+static LPCSTR const kMethodsNames[] =
+{
+ "Copy"
+ , "LZMA"
+ , "LZMA2"
+ , "PPMd"
+ , "BZip2"
+ , "Deflate"
+ , "Deflate64"
+ , "PPMd"
+ // , "ZSTD"
+ , "SHA256"
+ , "SHA1"
+ , "CRC32"
+ , "CRC64"
+ , "GNU"
+ , "POSIX"
+};
+
+static const EMethodID g_7zMethods[] =
+{
+ kLZMA2,
+ kLZMA,
+ kPPMd,
+ kBZip2
+ , kDeflate
+ , kDeflate64
+ // , kZSTD
+ , kCopy
+};
+
+static const EMethodID g_7zSfxMethods[] =
+{
+ kCopy,
+ kLZMA,
+ kLZMA2,
+ kPPMd
+};
+
+static const EMethodID g_ZipMethods[] =
+{
+ kDeflate,
+ kDeflate64,
+ kBZip2,
+ kLZMA,
+ kPPMdZip
+ // , kZSTD
+};
+
+static const EMethodID g_GZipMethods[] =
+{
+ kDeflate
+};
+
+static const EMethodID g_BZip2Methods[] =
+{
+ kBZip2
+};
+
+static const EMethodID g_XzMethods[] =
+{
+ kLZMA2
+};
+
+/*
+static const EMethodID g_ZstdMethods[] =
+{
+ kZSTD
+};
+*/
+
+static const EMethodID g_SwfcMethods[] =
+{
+ kDeflate
+ // kLZMA
+};
+
+static const EMethodID g_TarMethods[] =
+{
+ kGnu,
+ kPosix
+};
+
+static const EMethodID g_HashMethods[] =
+{
+ kSha256
+ , kSha1
+ // , kCrc32
+ // , kCrc64
+};
+
+static const UInt32 kFF_Filter = 1 << 0;
+static const UInt32 kFF_Solid = 1 << 1;
+static const UInt32 kFF_MultiThread = 1 << 2;
+static const UInt32 kFF_Encrypt = 1 << 3;
+static const UInt32 kFF_EncryptFileNames = 1 << 4;
+static const UInt32 kFF_MemUse = 1 << 5;
+static const UInt32 kFF_SFX = 1 << 6;
+
+/*
+static const UInt32 kFF_Time_Win = 1 << 10;
+static const UInt32 kFF_Time_Unix = 1 << 11;
+static const UInt32 kFF_Time_DOS = 1 << 12;
+static const UInt32 kFF_Time_1ns = 1 << 13;
+*/
+
+struct CFormatInfo
+{
+ LPCSTR Name;
+ UInt32 LevelsMask;
+ unsigned NumMethods;
+ const EMethodID *MethodIDs;
+
+ UInt32 Flags;
+
+ bool Filter_() const { return (Flags & kFF_Filter) != 0; }
+ bool Solid_() const { return (Flags & kFF_Solid) != 0; }
+ bool MultiThread_() const { return (Flags & kFF_MultiThread) != 0; }
+ bool Encrypt_() const { return (Flags & kFF_Encrypt) != 0; }
+ bool EncryptFileNames_() const { return (Flags & kFF_EncryptFileNames) != 0; }
+ bool MemUse_() const { return (Flags & kFF_MemUse) != 0; }
+ bool SFX_() const { return (Flags & kFF_SFX) != 0; }
+};
+
+#define METHODS_PAIR(x) Z7_ARRAY_SIZE(x), x
+
+static const CFormatInfo g_Formats[] =
+{
+ {
+ "",
+ // (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
+ ((UInt32)1 << 10) - 1,
+ // (UInt32)(Int32)-1,
+ 0, NULL,
+ kFF_MultiThread | kFF_MemUse
+ },
+ {
+ "7z",
+ (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
+ METHODS_PAIR(g_7zMethods),
+ kFF_Filter | kFF_Solid | kFF_MultiThread | kFF_Encrypt |
+ kFF_EncryptFileNames | kFF_MemUse | kFF_SFX
+ // | kFF_Time_Win
+ },
+ {
+ "Zip",
+ (1 << 0) | (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
+ METHODS_PAIR(g_ZipMethods),
+ kFF_MultiThread | kFF_Encrypt | kFF_MemUse
+ // | kFF_Time_Win | kFF_Time_Unix | kFF_Time_DOS
+ },
+ {
+ "GZip",
+ (1 << 1) | (1 << 5) | (1 << 7) | (1 << 9),
+ METHODS_PAIR(g_GZipMethods),
+ kFF_MemUse
+ // | kFF_Time_Unix
+ },
+ {
+ "BZip2",
+ (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
+ METHODS_PAIR(g_BZip2Methods),
+ kFF_MultiThread | kFF_MemUse
+ },
+ {
+ "xz",
+ (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
+ METHODS_PAIR(g_XzMethods),
+ kFF_Solid | kFF_MultiThread | kFF_MemUse
+ },
+ /*
+ {
+ "zstd",
+ // (1 << (MY_ZSTD_LEVEL_MAX + 1)) - 1,
+ (1 << (9 + 1)) - 1,
+ METHODS_PAIR(g_ZstdMethods),
+ // kFF_Solid |
+ kFF_MultiThread
+ | kFF_MemUse
+ },
+ */
+ {
+ "Swfc",
+ (1 << 1) | (1 << 3) | (1 << 5) | (1 << 7) | (1 << 9),
+ METHODS_PAIR(g_SwfcMethods),
+ 0
+ },
+ {
+ "Tar",
+ (1 << 0),
+ METHODS_PAIR(g_TarMethods),
+ 0
+ // kFF_Time_Unix | kFF_Time_Win // | kFF_Time_1ns
+ },
+ {
+ "wim",
+ (1 << 0),
+ 0, NULL,
+ 0
+ // | kFF_Time_Win
+ },
+ {
+ "Hash",
+ (0 << 0),
+ METHODS_PAIR(g_HashMethods),
+ 0
+ }
+};
+
+static bool IsMethodSupportedBySfx(int methodID)
+{
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_7zSfxMethods); i++)
+ if (methodID == g_7zSfxMethods[i])
+ return true;
+ return false;
+}
+
+
+static const
+ // NCompressDialog::NUpdateMode::EEnum
+ int
+ k_UpdateMode_Vals[] =
+{
+ NCompressDialog::NUpdateMode::kAdd,
+ NCompressDialog::NUpdateMode::kUpdate,
+ NCompressDialog::NUpdateMode::kFresh,
+ NCompressDialog::NUpdateMode::kSync
+};
+
+static const UInt32 k_UpdateMode_IDs[] =
+{
+ IDS_COMPRESS_UPDATE_MODE_ADD,
+ IDS_COMPRESS_UPDATE_MODE_UPDATE,
+ IDS_COMPRESS_UPDATE_MODE_FRESH,
+ IDS_COMPRESS_UPDATE_MODE_SYNC
+};
+
+static const
+ // NWildcard::ECensorPathMode
+ int
+ k_PathMode_Vals[] =
+{
+ NWildcard::k_RelatPath,
+ NWildcard::k_FullPath,
+ NWildcard::k_AbsPath,
+};
+
+static const UInt32 k_PathMode_IDs[] =
+{
+ IDS_PATH_MODE_RELAT,
+ IDS_EXTRACT_PATHS_FULL,
+ IDS_EXTRACT_PATHS_ABS
+};
+
+void AddComboItems(NControl::CComboBox &combo, const UInt32 *langIDs, unsigned numItems, const int *values, int curVal);
+
+void CCompressDialog::SetMethods(const CObjectVector<CCodecInfoUser> &userCodecs)
+{
+ ExternalMethods.Clear();
+ {
+ FOR_VECTOR (i, userCodecs)
+ {
+ const CCodecInfoUser &c = userCodecs[i];
+ if (!c.EncoderIsAssigned
+ || !c.IsFilter_Assigned
+ || c.IsFilter
+ || c.NumStreams != 1)
+ continue;
+ unsigned k;
+ for (k = 0; k < Z7_ARRAY_SIZE(g_7zMethods); k++)
+ if (c.Name.IsEqualTo_Ascii_NoCase(kMethodsNames[g_7zMethods[k]]))
+ break;
+ if (k != Z7_ARRAY_SIZE(g_7zMethods))
+ continue;
+ ExternalMethods.Add(c.Name);
+ }
+ }
+}
+
+
+bool CCompressDialog::OnInit()
+{
+ #ifdef Z7_LANG
+ LangSetWindowText(*this, IDD_COMPRESS);
+ LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
+ // LangSetDlgItemText(*this, IDB_COMPRESS_OPTIONS, IDS_OPTIONS); // IDG_COMPRESS_OPTIONS
+ #endif
+
+ {
+ UInt64 size = (UInt64)(sizeof(size_t)) << 29;
+ _ramSize_Defined = NSystem::GetRamSize(size);
+ // size = (UInt64)3 << 62; // for debug only;
+ _ramSize = size;
+ const UInt64 kMinUseSize = (1 << 26);
+ if (size < kMinUseSize)
+ size = kMinUseSize;
+
+ unsigned bits = sizeof(size_t) * 8;
+ if (bits == 32)
+ {
+ const UInt32 limit2 = (UInt32)7 << 28;
+ if (size > limit2)
+ size = limit2;
+ }
+
+ _ramSize_Reduced = size;
+
+ // 80% - is auto usage limit in handlers
+ _ramUsage_Auto = Calc_From_Val_Percents(size, 80);
+ }
+
+ _password1Control.Attach(GetItem(IDE_COMPRESS_PASSWORD1));
+ _password2Control.Attach(GetItem(IDE_COMPRESS_PASSWORD2));
+ _password1Control.SetText(Info.Password);
+ _password2Control.SetText(Info.Password);
+ _encryptionMethod.Attach(GetItem(IDC_COMPRESS_ENCRYPTION_METHOD));
+ _default_encryptionMethod_Index = -1;
+
+ m_ArchivePath.Attach(GetItem(IDC_COMPRESS_ARCHIVE));
+ m_Format.Attach(GetItem(IDC_COMPRESS_FORMAT)); // that combo has CBS_SORT style in resources
+ m_Level.Attach(GetItem(IDC_COMPRESS_LEVEL));
+ m_Method.Attach(GetItem(IDC_COMPRESS_METHOD));
+ m_Dictionary.Attach(GetItem(IDC_COMPRESS_DICTIONARY));
+
+ /*
+ {
+ RECT r;
+ GetClientRectOfItem(IDC_COMPRESS_DICTIONARY, r);
+ _dictionaryCombo_left = r.left;
+ }
+ */
+ _dictionaryCombo_left = 0; // 230;
+
+ // m_Dictionary_Chain.Attach(GetItem(IDC_COMPRESS_DICTIONARY2));
+ m_Order.Attach(GetItem(IDC_COMPRESS_ORDER));
+ m_Solid.Attach(GetItem(IDC_COMPRESS_SOLID));
+ m_NumThreads.Attach(GetItem(IDC_COMPRESS_THREADS));
+ m_MemUse.Attach(GetItem(IDC_COMPRESS_MEM_USE));
+
+ m_UpdateMode.Attach(GetItem(IDC_COMPRESS_UPDATE_MODE));
+ m_PathMode.Attach(GetItem(IDC_COMPRESS_PATH_MODE));
+
+ m_Volume.Attach(GetItem(IDC_COMPRESS_VOLUME));
+ m_Params.Attach(GetItem(IDE_COMPRESS_PARAMETERS));
+
+ AddVolumeItems(m_Volume);
+
+ m_RegistryInfo.Load();
+ CheckButton(IDX_PASSWORD_SHOW, m_RegistryInfo.ShowPassword);
+ CheckButton(IDX_COMPRESS_ENCRYPT_FILE_NAMES, m_RegistryInfo.EncryptHeaders);
+
+ UpdatePasswordControl();
+
+ {
+ const bool needSetMain = (Info.FormatIndex < 0);
+ FOR_VECTOR(i, ArcIndices)
+ {
+ const unsigned arcIndex = ArcIndices[i];
+ const CArcInfoEx &ai = (*ArcFormats)[arcIndex];
+ const int index = (int)m_Format.AddString(ai.Name);
+ m_Format.SetItemData(index, (LPARAM)arcIndex);
+ if (!needSetMain)
+ {
+ if (Info.FormatIndex == (int)arcIndex)
+ m_Format.SetCurSel(index);
+ continue;
+ }
+ if (i == 0 || ai.Name.IsEqualTo_NoCase(m_RegistryInfo.ArcType))
+ {
+ m_Format.SetCurSel(index);
+ Info.FormatIndex = (int)arcIndex;
+ }
+ }
+ }
+
+ CheckButton(IDX_COMPRESS_SFX, Info.SFXMode);
+
+ {
+ UString fileName;
+ SetArcPathFields(Info.ArcPath, fileName, true);
+ StartDirPrefix = DirPrefix;
+ SetArchiveName(fileName);
+ }
+
+ for (unsigned i = 0; i < m_RegistryInfo.ArcPaths.Size() && i < kHistorySize; i++)
+ m_ArchivePath.AddString(m_RegistryInfo.ArcPaths[i]);
+
+ AddComboItems(m_UpdateMode, k_UpdateMode_IDs, Z7_ARRAY_SIZE(k_UpdateMode_IDs),
+ k_UpdateMode_Vals, Info.UpdateMode);
+
+ AddComboItems(m_PathMode, k_PathMode_IDs, Z7_ARRAY_SIZE(k_PathMode_IDs),
+ k_PathMode_Vals, Info.PathMode);
+
+
+ TCHAR s[32] = { TEXT('/'), TEXT(' '), 0 };
+ ConvertUInt32ToString(NSystem::GetNumberOfProcessors(), s + 2);
+ SetItemText(IDT_COMPRESS_HARDWARE_THREADS, s);
+
+ CheckButton(IDX_COMPRESS_SHARED, Info.OpenShareForWrite);
+ CheckButton(IDX_COMPRESS_DEL, Info.DeleteAfterCompressing);
+
+ FormatChanged(false); // isChanged
+
+ // OnButtonSFX();
+
+ NormalizePosition();
+
+ return CModalDialog::OnInit();
+}
+
+/*
+namespace NCompressDialog
+{
+ bool CInfo::GetFullPathName(UString &result) const
+ {
+ #ifndef UNDER_CE
+ // NDirectory::MySetCurrentDirectory(CurrentDirPrefix);
+ #endif
+ FString resultF;
+ bool res = MyGetFullPathName(us2fs(ArchiveName), resultF);
+ result = fs2us(resultF);
+ return res;
+ }
+}
+*/
+
+void CCompressDialog::UpdatePasswordControl()
+{
+ const bool showPassword = IsShowPasswordChecked();
+ const TCHAR c = showPassword ? (TCHAR)0: TEXT('*');
+ _password1Control.SetPasswordChar((WPARAM)c);
+ _password2Control.SetPasswordChar((WPARAM)c);
+ UString password;
+ _password1Control.GetText(password);
+ _password1Control.SetText(password);
+ _password2Control.GetText(password);
+ _password2Control.SetText(password);
+
+ ShowItem_Bool(IDT_PASSWORD_REENTER, !showPassword);
+ _password2Control.Show_Bool(!showPassword);
+}
+
+bool CCompressDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ switch (buttonID)
+ {
+ case IDB_COMPRESS_SET_ARCHIVE:
+ {
+ OnButtonSetArchive();
+ return true;
+ }
+ case IDX_COMPRESS_SFX:
+ {
+ SetMethod(GetMethodID());
+ OnButtonSFX();
+ SetMemoryUsage();
+ return true;
+ }
+ case IDX_PASSWORD_SHOW:
+ {
+ UpdatePasswordControl();
+ return true;
+ }
+ case IDB_COMPRESS_OPTIONS:
+ {
+ COptionsDialog dialog(this);
+ if (dialog.Create(*this) == IDOK)
+ ShowOptionsString();
+ return true;
+ }
+ }
+ return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
+}
+
+void CCompressDialog::CheckSFXControlsEnable()
+{
+ const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
+ bool enable = fi.SFX_();
+ if (enable)
+ {
+ const int methodID = GetMethodID();
+ enable = (methodID == -1 || IsMethodSupportedBySfx(methodID));
+ }
+ if (!enable)
+ CheckButton(IDX_COMPRESS_SFX, false);
+ EnableItem(IDX_COMPRESS_SFX, enable);
+}
+
+/*
+void CCompressDialog::CheckVolumeEnable()
+{
+ bool isSFX = IsSFX();
+ m_Volume.Enable(!isSFX);
+ if (isSFX)
+ m_Volume.SetText(TEXT(""));
+}
+*/
+
+void CCompressDialog::EnableMultiCombo(unsigned id)
+{
+ NWindows::NControl::CComboBox combo;
+ combo.Attach(GetItem(id));
+ const bool enable = (combo.GetCount() > 1);
+ EnableItem(id, enable);
+}
+
+static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s);
+
+static void Combine_Two_BoolPairs(const CBoolPair &b1, const CBoolPair &b2, CBool1 &res)
+{
+ if (!b1.Def && b2.Def)
+ res.Val = b2.Val;
+ else
+ res.Val = b1.Val;
+}
+
+#define SET_GUI_BOOL(name) \
+ Combine_Two_BoolPairs(Info. name, m_RegistryInfo. name, name)
+
+
+static void Set_Final_BoolPairs(
+ const CBool1 &gui,
+ CBoolPair &cmd,
+ CBoolPair &reg)
+{
+ if (!cmd.Def)
+ {
+ reg.Val = gui.Val;
+ reg.Def = gui.Val;
+ }
+ if (gui.Supported)
+ {
+ cmd.Val = gui.Val;
+ cmd.Def = gui.Val;
+ }
+ else
+ cmd.Init();
+}
+
+#define SET_FINAL_BOOL_PAIRS(name) \
+ Set_Final_BoolPairs(name, Info. name, m_RegistryInfo. name)
+
+void CCompressDialog::FormatChanged(bool isChanged)
+{
+ SetLevel();
+ SetSolidBlockSize();
+ SetParams();
+ SetMemUseCombo();
+ SetNumThreads();
+
+ const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
+ Info.SolidIsSpecified = fi.Solid_();
+ Info.EncryptHeadersIsAllowed = fi.EncryptFileNames_();
+
+ /*
+ const bool multiThreadEnable = fi.MultiThread;
+ Info.MultiThreadIsAllowed = multiThreadEnable;
+ EnableItem(IDC_COMPRESS_SOLID, fi.Solid);
+ EnableItem(IDC_COMPRESS_THREADS, multiThreadEnable);
+ const bool methodEnable = (fi.MethodIDs != NULL);
+ EnableItem(IDC_COMPRESS_METHOD, methodEnable);
+ EnableMultiCombo(IDC_COMPRESS_DICTIONARY, methodEnable);
+ EnableItem(IDC_COMPRESS_ORDER, methodEnable);
+ */
+
+ CheckSFXControlsEnable();
+
+ {
+ if (!isChanged)
+ {
+ SET_GUI_BOOL (SymLinks);
+ SET_GUI_BOOL (HardLinks);
+ SET_GUI_BOOL (AltStreams);
+ SET_GUI_BOOL (NtSecurity);
+ SET_GUI_BOOL (PreserveATime);
+ }
+
+ PreserveATime.Supported = true;
+
+ {
+ const CArcInfoEx &ai = Get_ArcInfoEx();
+ SymLinks.Supported = ai.Flags_SymLinks();
+ HardLinks.Supported = ai.Flags_HardLinks();
+ AltStreams.Supported = ai.Flags_AltStreams();
+ NtSecurity.Supported = ai.Flags_NtSecurity();
+ }
+
+ ShowOptionsString();
+ }
+ // CheckVolumeEnable();
+
+ const bool encrypt = fi.Encrypt_();
+ EnableItem(IDG_COMPRESS_ENCRYPTION, encrypt);
+
+ EnableItem(IDT_PASSWORD_ENTER, encrypt);
+ EnableItem(IDT_PASSWORD_REENTER, encrypt);
+ EnableItem(IDE_COMPRESS_PASSWORD1, encrypt);
+ EnableItem(IDE_COMPRESS_PASSWORD2, encrypt);
+ EnableItem(IDX_PASSWORD_SHOW, encrypt);
+
+ EnableItem(IDT_COMPRESS_ENCRYPTION_METHOD, encrypt);
+ EnableItem(IDC_COMPRESS_ENCRYPTION_METHOD, encrypt);
+ EnableItem(IDX_COMPRESS_ENCRYPT_FILE_NAMES, fi.EncryptFileNames_());
+
+ ShowItem_Bool(IDX_COMPRESS_ENCRYPT_FILE_NAMES, fi.EncryptFileNames_());
+
+ SetEncryptionMethod();
+ SetMemoryUsage();
+}
+
+
+bool CCompressDialog::IsSFX()
+{
+ return IsWindowEnabled(GetItem(IDX_COMPRESS_SFX))
+ && IsButtonCheckedBool(IDX_COMPRESS_SFX);
+}
+
+static int GetExtDotPos(const UString &s)
+{
+ const int dotPos = s.ReverseFind_Dot();
+ if (dotPos > s.ReverseFind_PathSepar() + 1)
+ return dotPos;
+ return -1;
+}
+
+void CCompressDialog::OnButtonSFX()
+{
+ UString fileName;
+ m_ArchivePath.GetText(fileName);
+ const int dotPos = GetExtDotPos(fileName);
+ if (IsSFX())
+ {
+ if (dotPos >= 0)
+ fileName.DeleteFrom(dotPos);
+ fileName += kExeExt;
+ m_ArchivePath.SetText(fileName);
+ }
+ else
+ {
+ if (dotPos >= 0)
+ {
+ const UString ext = fileName.Ptr(dotPos);
+ if (ext.IsEqualTo_Ascii_NoCase(kExeExt))
+ {
+ fileName.DeleteFrom(dotPos);
+ m_ArchivePath.SetText(fileName);
+ }
+ }
+ SetArchiveName2(false); // it's for OnInit
+ }
+
+ // CheckVolumeEnable();
+}
+
+
+bool CCompressDialog::GetFinalPath_Smart(UString &resPath) const
+{
+ resPath.Empty();
+ UString name;
+ m_ArchivePath.GetText(name);
+ name.Trim();
+ FString fullPath;
+ UString dirPrefx = DirPrefix;
+ if (dirPrefx.IsEmpty())
+ dirPrefx = StartDirPrefix;
+ const bool res = !dirPrefx.IsEmpty() ?
+ NName::GetFullPath(us2fs(dirPrefx), us2fs(name), fullPath):
+ NName::GetFullPath( us2fs(name), fullPath);
+ if (res)
+ resPath = fs2us(fullPath);
+ return res;
+}
+
+
+bool CCompressDialog::SetArcPathFields(const UString &path)
+{
+ UString name;
+ return SetArcPathFields(path, name, true); // always
+}
+
+
+bool CCompressDialog::SetArcPathFields(const UString &path, UString &name, bool always)
+{
+ FString resDirPrefix;
+ FString resFileName;
+ const bool res = GetFullPathAndSplit(us2fs(path), resDirPrefix, resFileName);
+ if (res)
+ {
+ DirPrefix = fs2us(resDirPrefix);
+ name = fs2us(resFileName);
+ }
+ else
+ {
+ if (!always)
+ return false;
+ DirPrefix.Empty();
+ name = path;
+ }
+ SetItemText(IDT_COMPRESS_ARCHIVE_FOLDER, DirPrefix);
+ m_ArchivePath.SetText(name);
+ return res;
+}
+
+
+static const wchar_t * const k_IncorrectPathMessage = L"Incorrect archive path";
+
+static void AddFilter(CObjectVector<CBrowseFilterInfo> &filters,
+ const UString &description, const UString &ext)
+{
+ CBrowseFilterInfo &f = filters.AddNew();
+ UString mask ("*.");
+ mask += ext;
+ f.Masks.Add(mask);
+ f.Description = description;
+ f.Description += " (";
+ f.Description += mask;
+ f.Description += ")";
+}
+
+
+static const char * const k_DontSave_Exts =
+ "xpi odt ods docx xlsx ";
+
+void CCompressDialog::OnButtonSetArchive()
+{
+ UString path;
+ if (!GetFinalPath_Smart(path))
+ {
+ ShowErrorMessage(*this, k_IncorrectPathMessage);
+ return;
+ }
+
+ int filterIndex;
+ CObjectVector<CBrowseFilterInfo> filters;
+ unsigned numFormats = 0;
+
+ const bool isSFX = IsSFX();
+ if (isSFX)
+ {
+ filterIndex = 0;
+ const UString ext ("exe");
+ AddFilter(filters, ext, ext);
+ }
+ else
+ {
+ filterIndex = m_Format.GetCurSel();
+ numFormats = (unsigned)m_Format.GetCount();
+
+ // filters [0, ... numFormats - 1] corresponds to items in m_Format combo
+ UString desc;
+ UStringVector masks;
+ CStringFinder finder;
+
+ for (unsigned i = 0; i < numFormats; i++)
+ {
+ const CArcInfoEx &ai = (*ArcFormats)[(unsigned)m_Format.GetItemData(i)];
+ CBrowseFilterInfo &f = filters.AddNew();
+ f.Description = ai.Name;
+ f.Description += " (";
+ bool needSpace_desc = false;
+
+ FOR_VECTOR (k, ai.Exts)
+ {
+ const UString &ext = ai.Exts[k].Ext;
+ UString mask ("*.");
+ mask += ext;
+
+ if (finder.FindWord_In_LowCaseAsciiList_NoCase(k_DontSave_Exts, ext))
+ continue;
+
+ f.Masks.Add(mask);
+ masks.Add(mask);
+ if (needSpace_desc)
+ f.Description.Add_Space();
+ needSpace_desc = true;
+ f.Description += ext;
+ }
+ f.Description += ")";
+ // we use only main ext in desc to reduce the size of list
+ if (i != 0)
+ desc.Add_Space();
+ desc += ai.GetMainExt();
+ }
+
+ CBrowseFilterInfo &f = filters.AddNew();
+ f.Description = LangString(IDT_COMPRESS_ARCHIVE); // IDS_ARCHIVES_COLON;
+ if (f.Description.IsEmpty())
+ GetItemText(IDT_COMPRESS_ARCHIVE, f.Description);
+ f.Description.RemoveChar(L'&');
+ // f.Description = "archive";
+ f.Description += " (";
+ f.Description += desc;
+ f.Description += ")";
+ f.Masks = masks;
+ }
+
+ AddFilter(filters, LangString(IDS_OPEN_TYPE_ALL_FILES), UString("*"));
+ if (filterIndex < 0)
+ filterIndex = (int)filters.Size() - 1;
+
+ const UString title = LangString(IDS_COMPRESS_SET_ARCHIVE_BROWSE);
+ CBrowseInfo bi;
+ bi.lpstrTitle = title;
+ bi.SaveMode = true;
+ bi.FilterIndex = filterIndex;
+ bi.hwndOwner = *this;
+ bi.FilePath = path;
+
+ if (!bi.BrowseForFile(filters))
+ return;
+
+ path = bi.FilePath;
+
+ if (isSFX)
+ {
+ const int dotPos = GetExtDotPos(path);
+ if (dotPos >= 0)
+ path.DeleteFrom(dotPos);
+ path += kExeExt;
+ }
+ else
+ // if (bi.FilterIndex >= 0)
+ // if (bi.FilterIndex != filterIndex)
+ if ((unsigned)bi.FilterIndex < numFormats)
+ {
+ // archive format was confirmed. So we try to set format extension
+ bool needAddExt = true;
+ const CArcInfoEx &ai = (*ArcFormats)[(unsigned)m_Format.GetItemData((unsigned)bi.FilterIndex)];
+ const int dotPos = GetExtDotPos(path);
+ if (dotPos >= 0)
+ {
+ const UString ext = path.Ptr(dotPos + 1);
+ if (ai.FindExtension(ext) >= 0)
+ needAddExt = false;
+ }
+ if (needAddExt)
+ {
+ if (path.IsEmpty() || path.Back() != '.')
+ path.Add_Dot();
+ path += ai.GetMainExt();
+ }
+ }
+
+ SetArcPathFields(path);
+
+ if (!isSFX)
+ if ((unsigned)bi.FilterIndex < numFormats)
+ if (bi.FilterIndex != m_Format.GetCurSel())
+ {
+ m_Format.SetCurSel(bi.FilterIndex);
+ SaveOptionsInMem();
+ FormatChanged(true); // isChanged
+ return;
+ }
+
+ ArcPath_WasChanged(path);
+}
+
+
+// in ExtractDialog.cpp
+extern void AddUniqueString(UStringVector &strings, const UString &srcString);
+
+static bool IsAsciiString(const UString &s)
+{
+ for (unsigned i = 0; i < s.Len(); i++)
+ {
+ const wchar_t c = s[i];
+ if (c < 0x20 || c > 0x7F)
+ return false;
+ }
+ return true;
+}
+
+
+static void AddSize_MB(UString &s, UInt64 size)
+{
+ const UInt64 v2 = size + ((UInt32)1 << 20) - 1;
+ if (size <= v2)
+ size = v2;
+ s.Add_UInt64(size >> 20);
+ s += " MB";
+}
+
+
+void SetErrorMessage_MemUsage(UString &s, UInt64 reqSize, UInt64 ramSize, UInt64 ramLimit, const UString &usageString);
+void SetErrorMessage_MemUsage(UString &s, UInt64 reqSize, UInt64 ramSize, UInt64 ramLimit, const UString &usageString)
+{
+ s += "The operation was blocked by 7-Zip";
+ s.Add_LF();
+ s += "The operation can require big amount of RAM (memory):";
+ s.Add_LF();
+ s.Add_LF();
+ AddSize_MB(s, reqSize);
+
+ if (!usageString.IsEmpty())
+ {
+ s += " : ";
+ s += usageString;
+ }
+
+ s.Add_LF();
+ AddSize_MB(s, ramSize);
+ s += " : RAM";
+
+ // if (ramLimit != 0)
+ {
+ s.Add_LF();
+ AddSize_MB(s, ramLimit);
+ s += " : 7-Zip limit";
+ }
+
+ s.Add_LF();
+ s.Add_LF();
+ AddLangString(s, IDS_MEM_ERROR);
+}
+
+
+void CCompressDialog::OnOK()
+{
+ _password1Control.GetText(Info.Password);
+ if (IsZipFormat())
+ {
+ if (!IsAsciiString(Info.Password))
+ {
+ ShowErrorMessageHwndRes(*this, IDS_PASSWORD_USE_ASCII);
+ return;
+ }
+ UString method = GetEncryptionMethodSpec();
+ if (method.IsPrefixedBy_Ascii_NoCase("aes"))
+ {
+ if (Info.Password.Len() > 99)
+ {
+ ShowErrorMessageHwndRes(*this, IDS_PASSWORD_TOO_LONG);
+ return;
+ }
+ }
+ }
+ if (!IsShowPasswordChecked())
+ {
+ UString password2;
+ _password2Control.GetText(password2);
+ if (password2 != Info.Password)
+ {
+ ShowErrorMessageHwndRes(*this, IDS_PASSWORD_NOT_MATCH);
+ return;
+ }
+ }
+
+ {
+ UInt64 decompressMem;
+ const UInt64 memUsage = GetMemoryUsage_DecompMem(decompressMem);
+ if (memUsage != (UInt64)(Int64)-1)
+ {
+ const UInt64 limit = Get_MemUse_Bytes();
+ if (memUsage > limit)
+ {
+ UString s;
+ UString s2 = LangString(IDT_COMPRESS_MEMORY);
+ if (s2.IsEmpty())
+ GetItemText(IDT_COMPRESS_MEMORY, s2);
+ SetErrorMessage_MemUsage(s, memUsage, _ramSize, limit, s2);
+ MessageBoxError(s);
+ return;
+ }
+ }
+ }
+
+ SaveOptionsInMem();
+
+ UStringVector arcPaths;
+ {
+ UString s;
+ if (!GetFinalPath_Smart(s))
+ {
+ ShowErrorMessage(*this, k_IncorrectPathMessage);
+ return;
+ }
+ Info.ArcPath = s;
+ AddUniqueString(arcPaths, s);
+ }
+
+ Info.UpdateMode = (NCompressDialog::NUpdateMode::EEnum)k_UpdateMode_Vals[m_UpdateMode.GetCurSel()];
+ Info.PathMode = (NWildcard::ECensorPathMode)k_PathMode_Vals[m_PathMode.GetCurSel()];
+
+ Info.Level = GetLevelSpec();
+ Info.Dict64 = GetDictSpec();
+ // Info.Dict64_Chain = GetDictChainSpec();
+ Info.Order = GetOrderSpec();
+ Info.OrderMode = GetOrderMode();
+ Info.NumThreads = GetNumThreadsSpec();
+
+ Info.MemUsage.Clear();
+ {
+ const UString mus = Get_MemUse_Spec();
+ if (!mus.IsEmpty())
+ {
+ NCompression::CMemUse mu;
+ mu.Parse(mus);
+ if (mu.IsDefined)
+ Info.MemUsage = mu;
+ }
+ }
+
+ {
+ // Info.SolidIsSpecified = g_Formats[GetStaticFormatIndex()].Solid;
+ const UInt32 solidLogSize = GetBlockSizeSpec();
+ Info.SolidBlockSize = 0;
+ if (solidLogSize == (UInt32)(Int32)-1)
+ Info.SolidIsSpecified = false;
+ else if (solidLogSize > 0)
+ Info.SolidBlockSize = (solidLogSize >= 64) ?
+ (UInt64)(Int64)-1 :
+ ((UInt64)1 << solidLogSize);
+ }
+
+ Info.Method = GetMethodSpec();
+ Info.EncryptionMethod = GetEncryptionMethodSpec();
+ Info.FormatIndex = (int)GetFormatIndex();
+ Info.SFXMode = IsSFX();
+ Info.OpenShareForWrite = IsButtonCheckedBool(IDX_COMPRESS_SHARED);
+ Info.DeleteAfterCompressing = IsButtonCheckedBool(IDX_COMPRESS_DEL);
+
+ m_RegistryInfo.EncryptHeaders =
+ Info.EncryptHeaders = IsButtonCheckedBool(IDX_COMPRESS_ENCRYPT_FILE_NAMES);
+
+
+ /* (Info) is for saving to registry:
+ (CBoolPair::Val) will be set as (false), if it was (false)
+ in registry at dialog creation, and user didn't click checkbox.
+ in another case (CBoolPair::Val) will be set as (true) */
+
+ {
+ /* Info properties could be for another archive types.
+ so we disable unsupported properties in Info */
+ // const CArcInfoEx &ai = Get_ArcInfoEx();
+
+ SET_FINAL_BOOL_PAIRS (SymLinks);
+ SET_FINAL_BOOL_PAIRS (HardLinks);
+ SET_FINAL_BOOL_PAIRS (AltStreams);
+ SET_FINAL_BOOL_PAIRS (NtSecurity);
+
+ SET_FINAL_BOOL_PAIRS (PreserveATime);
+ }
+
+ {
+ const NCompression::CFormatOptions &fo = Get_FormatOptions();
+
+ Info.TimePrec = fo.TimePrec;
+ Info.MTime = fo.MTime;
+ Info.CTime = fo.CTime;
+ Info.ATime = fo.ATime;
+ Info.SetArcMTime = fo.SetArcMTime;
+ }
+
+ m_Params.GetText(Info.Options);
+
+ UString volumeString;
+ m_Volume.GetText(volumeString);
+ volumeString.Trim();
+ Info.VolumeSizes.Clear();
+
+ if (!volumeString.IsEmpty())
+ {
+ if (!ParseVolumeSizes(volumeString, Info.VolumeSizes))
+ {
+ ShowErrorMessageHwndRes(*this, IDS_INCORRECT_VOLUME_SIZE);
+ return;
+ }
+ if (!Info.VolumeSizes.IsEmpty())
+ {
+ const UInt64 volumeSize = Info.VolumeSizes.Back();
+ if (volumeSize < (100 << 10))
+ {
+ wchar_t s[32];
+ ConvertUInt64ToString(volumeSize, s);
+ if (::MessageBoxW(*this, MyFormatNew(IDS_SPLIT_CONFIRM, s),
+ L"7-Zip", MB_YESNOCANCEL | MB_ICONQUESTION) != IDYES)
+ return;
+ }
+ }
+ }
+
+ if (Info.FormatIndex >= 0)
+ m_RegistryInfo.ArcType = (*ArcFormats)[Info.FormatIndex].Name;
+ m_RegistryInfo.ShowPassword = IsShowPasswordChecked();
+
+ FOR_VECTOR (i, m_RegistryInfo.ArcPaths)
+ {
+ if (arcPaths.Size() >= kHistorySize)
+ break;
+ AddUniqueString(arcPaths, m_RegistryInfo.ArcPaths[i]);
+ }
+ m_RegistryInfo.ArcPaths = arcPaths;
+
+ m_RegistryInfo.Save();
+
+ CModalDialog::OnOK();
+}
+
+#define kHelpTopic "fm/plugins/7-zip/add.htm"
+#define kHelpTopic_Options "fm/plugins/7-zip/add.htm#options"
+
+void CCompressDialog::OnHelp()
+{
+ ShowHelpWindow(kHelpTopic);
+}
+
+
+void CCompressDialog::ArcPath_WasChanged(const UString &path)
+{
+ const int dotPos = GetExtDotPos(path);
+ if (dotPos < 0)
+ return;
+ const UString ext = path.Ptr(dotPos + 1);
+ {
+ const CArcInfoEx &ai = Get_ArcInfoEx();
+ if (ai.FindExtension(ext) >= 0)
+ return;
+ }
+
+ const unsigned count = (unsigned)m_Format.GetCount();
+ for (unsigned i = 0; i < count; i++)
+ {
+ const CArcInfoEx &ai = (*ArcFormats)[(unsigned)m_Format.GetItemData(i)];
+ if (ai.FindExtension(ext) >= 0)
+ {
+ m_Format.SetCurSel(i);
+ SaveOptionsInMem();
+ FormatChanged(true); // isChanged
+ return;
+ }
+ }
+}
+
+
+bool CCompressDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case k_Message_ArcChanged:
+ {
+ // UString path;
+ // m_ArchivePath.GetText(path);
+ const int select = m_ArchivePath.GetCurSel();
+ if ((unsigned)select < m_RegistryInfo.ArcPaths.Size())
+ // if (path == m_RegistryInfo.ArcPaths[select])
+ {
+ const UString &path = m_RegistryInfo.ArcPaths[select];
+ SetArcPathFields(path);
+ // ArcPath_WasChanged(path);
+ }
+ return 0;
+ }
+ }
+ return CModalDialog::OnMessage(message, wParam, lParam);
+}
+
+
+bool CCompressDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam)
+{
+ if (code == CBN_SELCHANGE)
+ {
+ switch (itemID)
+ {
+ case IDC_COMPRESS_ARCHIVE:
+ {
+ /* CBN_SELCHANGE is called before actual value of combo text will be changed.
+ So GetText() here returns old value (before change) of combo text.
+ So here we can change all controls except of m_ArchivePath.
+ */
+ const int select = m_ArchivePath.GetCurSel();
+ if ((unsigned)select < m_RegistryInfo.ArcPaths.Size())
+ {
+ // DirPrefix.Empty();
+ // SetItemText(IDT_COMPRESS_ARCHIVE_FOLDER, DirPrefix);
+ const UString &path = m_RegistryInfo.ArcPaths[select];
+ // SetArcPathFields(path);
+ ArcPath_WasChanged(path);
+ // we use PostMessage(k_Message_ArcChanged) here that later will change m_ArchivePath control
+ PostMsg(k_Message_ArcChanged);
+ }
+ return true;
+ }
+
+ case IDC_COMPRESS_FORMAT:
+ {
+ const bool isSFX = IsSFX();
+ SaveOptionsInMem();
+ FormatChanged(true); // isChanged
+ SetArchiveName2(isSFX);
+ return true;
+ }
+
+ case IDC_COMPRESS_LEVEL:
+ {
+ Get_FormatOptions().ResetForLevelChange();
+
+ SetMethod(); // call it if level changes method
+
+ // call the following if level change keeps old method
+ /*
+ {
+ // try to keep old method
+ SetMethod(GetMethodID());
+ MethodChanged();
+ }
+ */
+
+ SetSolidBlockSize();
+ SetNumThreads();
+ CheckSFXNameChange();
+ SetMemoryUsage();
+ return true;
+ }
+
+ case IDC_COMPRESS_METHOD:
+ {
+ MethodChanged();
+ SetSolidBlockSize();
+ SetNumThreads();
+ CheckSFXNameChange();
+ SetMemoryUsage();
+ if (Get_ArcInfoEx().Flags_HashHandler())
+ SetArchiveName2(false);
+
+ return true;
+ }
+
+ case IDC_COMPRESS_DICTIONARY:
+ // case IDC_COMPRESS_DICTIONARY2:
+ {
+ /* we want to change the reported threads for Auto line
+ and keep selected NumThreads option
+ So we save selected NumThreads option in memory */
+ SaveOptionsInMem();
+ const UInt32 blockSizeLog = GetBlockSizeSpec();
+ if (// blockSizeLog != (UInt32)(Int32)-1 &&
+ blockSizeLog != kSolidLog_NoSolid
+ && blockSizeLog != kSolidLog_FullSolid)
+ {
+ Get_FormatOptions().Reset_BlockLogSize();
+ // SetSolidBlockSize(true);
+ }
+
+ SetDictionary2();
+ SetSolidBlockSize();
+ SetNumThreads(); // we want to change the reported threads for Auto line only
+ SetMemoryUsage();
+ return true;
+ }
+
+ case IDC_COMPRESS_ORDER:
+ {
+ #ifdef PRINT_PARAMS
+ Print_Params();
+ #endif
+ return true;
+ }
+
+ case IDC_COMPRESS_SOLID:
+ {
+ SetMemoryUsage();
+ return true;
+ }
+
+ case IDC_COMPRESS_THREADS:
+ {
+ SetMemoryUsage();
+ return true;
+ }
+
+ case IDC_COMPRESS_MEM_USE:
+ {
+ /* we want to change the reported threads for Auto line
+ and keep selected NumThreads option
+ So we save selected NumThreads option in memory */
+ SaveOptionsInMem();
+
+ SetNumThreads(); // we want to change the reported threads for Auto line only
+ SetMemoryUsage();
+ return true;
+ }
+ }
+ }
+ return CModalDialog::OnCommand(code, itemID, lParam);
+}
+
+void CCompressDialog::CheckSFXNameChange()
+{
+ const bool isSFX = IsSFX();
+ CheckSFXControlsEnable();
+ if (isSFX != IsSFX())
+ SetArchiveName2(isSFX);
+}
+
+void CCompressDialog::SetArchiveName2(bool prevWasSFX)
+{
+ UString fileName;
+ m_ArchivePath.GetText(fileName);
+ const CArcInfoEx &prevArchiverInfo = (*ArcFormats)[m_PrevFormat];
+ if (prevArchiverInfo.Flags_KeepName() || Info.KeepName)
+ {
+ UString prevExtension;
+ if (prevWasSFX)
+ prevExtension = kExeExt;
+ else
+ {
+ prevExtension.Add_Dot();
+ prevExtension += prevArchiverInfo.GetMainExt();
+ }
+ const unsigned prevExtensionLen = prevExtension.Len();
+ if (fileName.Len() >= prevExtensionLen)
+ if (StringsAreEqualNoCase(fileName.RightPtr(prevExtensionLen), prevExtension))
+ fileName.DeleteFrom(fileName.Len() - prevExtensionLen);
+ }
+ SetArchiveName(fileName);
+}
+
+// if type.KeepName then use OriginalFileName
+// else if !KeepName remove extension
+// add new extension
+
+void CCompressDialog::SetArchiveName(const UString &name)
+{
+ UString fileName = name;
+ Info.FormatIndex = (int)GetFormatIndex();
+ const CArcInfoEx &ai = (*ArcFormats)[Info.FormatIndex];
+ m_PrevFormat = Info.FormatIndex;
+ if (ai.Flags_KeepName())
+ {
+ fileName = OriginalFileName;
+ }
+ else
+ {
+ if (!Info.KeepName)
+ {
+ int dotPos = GetExtDotPos(fileName);
+ if (dotPos >= 0)
+ fileName.DeleteFrom(dotPos);
+ }
+ }
+
+ if (IsSFX())
+ fileName += kExeExt;
+ else
+ {
+ fileName.Add_Dot();
+ UString ext = ai.GetMainExt();
+ if (ai.Flags_HashHandler())
+ {
+ UString estimatedName;
+ GetMethodSpec(estimatedName);
+ if (!estimatedName.IsEmpty())
+ {
+ ext = estimatedName;
+ ext.MakeLower_Ascii();
+ }
+ }
+ fileName += ext;
+ }
+ m_ArchivePath.SetText(fileName);
+}
+
+
+int CCompressDialog::FindRegistryFormat(const UString &name)
+{
+ FOR_VECTOR (i, m_RegistryInfo.Formats)
+ {
+ const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[i];
+ if (name.IsEqualTo_NoCase(GetUnicodeString(fo.FormatID)))
+ return (int)i;
+ }
+ return -1;
+}
+
+
+unsigned CCompressDialog::FindRegistryFormat_Always(const UString &name)
+{
+ const int index = FindRegistryFormat(name);
+ if (index >= 0)
+ return (unsigned)index;
+ {
+ NCompression::CFormatOptions fo;
+ fo.FormatID = GetSystemString(name);
+ return m_RegistryInfo.Formats.Add(fo);
+ }
+}
+
+
+NCompression::CFormatOptions &CCompressDialog::Get_FormatOptions()
+{
+ const CArcInfoEx &ai = Get_ArcInfoEx();
+ return m_RegistryInfo.Formats[FindRegistryFormat_Always(ai.Name)];
+}
+
+
+unsigned CCompressDialog::GetStaticFormatIndex()
+{
+ const CArcInfoEx &ai = Get_ArcInfoEx();
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_Formats); i++)
+ if (ai.Name.IsEqualTo_Ascii_NoCase(g_Formats[i].Name))
+ return i;
+ return 0; // -1;
+}
+
+void CCompressDialog::SetNearestSelectComboBox(NControl::CComboBox &comboBox, UInt32 value)
+{
+ for (int i = comboBox.GetCount() - 1; i >= 0; i--)
+ if ((UInt32)comboBox.GetItemData(i) <= value)
+ {
+ comboBox.SetCurSel(i);
+ return;
+ }
+ if (comboBox.GetCount() > 0)
+ comboBox.SetCurSel(0);
+}
+
+void CCompressDialog::SetLevel2()
+{
+ m_Level.ResetContent();
+ const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
+ const CArcInfoEx &ai = Get_ArcInfoEx();
+ UInt32 level = 5;
+ {
+ int index = FindRegistryFormat(ai.Name);
+ if (index >= 0)
+ {
+ const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
+ if (fo.Level <= 9)
+ level = fo.Level;
+ else if (fo.Level == (UInt32)(Int32)-1)
+ level = 5;
+ else
+ level = 9;
+ }
+ }
+
+ const bool isZstd = ai.Is_Zstd();
+
+ for (unsigned i = 0; i < sizeof(UInt32) * 8; i++)
+ {
+ const UInt32 mask = (UInt32)1 << i;
+ if ((fi.LevelsMask & mask) != 0)
+ {
+ const UInt32 langID = g_Levels[i];
+ UString s;
+ s.Add_UInt32(i);
+ // if (fi.LevelsMask < (1 << (MY_ZSTD_LEVEL_MAX + 1)) - 1)
+ if (langID)
+ if (i != 0 || !isZstd)
+ {
+ s += " - ";
+ s += LangString(langID);
+ }
+ const int index = (int)m_Level.AddString(s);
+ m_Level.SetItemData(index, (LPARAM)i);
+ }
+ if (fi.LevelsMask <= mask)
+ break;
+ }
+ SetNearestSelectComboBox(m_Level, level);
+}
+
+
+static LRESULT ComboBox_AddStringAscii(NControl::CComboBox &cb, const char *s)
+{
+ return cb.AddString((CSysString)s);
+}
+
+static const char *k_Auto_Prefix = "* ";
+
+static void Modify_Auto(AString &s)
+{
+ s.Insert(0, k_Auto_Prefix);
+}
+
+void CCompressDialog::SetMethod2(int keepMethodId)
+{
+ m_Method.ResetContent();
+ _auto_MethodId = -1;
+ const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
+ const CArcInfoEx &ai = Get_ArcInfoEx();
+ if (GetLevel() == 0 && !ai.Flags_HashHandler())
+ {
+ if (!ai.Is_Tar() &&
+ !ai.Is_Zstd())
+ {
+ MethodChanged();
+ return;
+ }
+ }
+ UString defaultMethod;
+ {
+ const int index = FindRegistryFormat(ai.Name);
+ if (index >= 0)
+ {
+ const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
+ defaultMethod = fo.Method;
+ }
+ }
+ const bool isSfx = IsSFX();
+ bool weUseSameMethod = false;
+
+ const bool is7z = ai.Is_7z();
+
+ for (unsigned m = 0;; m++)
+ {
+ int methodID;
+ const char *method;
+ if (m < fi.NumMethods)
+ {
+ methodID = fi.MethodIDs[m];
+ method = kMethodsNames[methodID];
+ if (is7z)
+ if (methodID == kCopy
+ || methodID == kDeflate
+ || methodID == kDeflate64
+ )
+ continue;
+ }
+ else
+ {
+ if (!is7z)
+ break;
+ const unsigned extIndex = m - fi.NumMethods;
+ if (extIndex >= ExternalMethods.Size())
+ break;
+ methodID = (int)(Z7_ARRAY_SIZE(kMethodsNames) + extIndex);
+ method = ExternalMethods[extIndex].Ptr();
+ }
+ if (isSfx)
+ if (!IsMethodSupportedBySfx(methodID))
+ continue;
+
+ AString s (method);
+ int writtenMethodId = methodID;
+ if (m == 0)
+ {
+ _auto_MethodId = methodID;
+ writtenMethodId = -1;
+ Modify_Auto(s);
+ }
+ const int itemIndex = (int)ComboBox_AddStringAscii(m_Method, s);
+ m_Method.SetItemData(itemIndex, writtenMethodId);
+ if (keepMethodId == methodID)
+ {
+ m_Method.SetCurSel(itemIndex);
+ weUseSameMethod = true;
+ continue;
+ }
+ if ((defaultMethod.IsEqualTo_Ascii_NoCase(method) || m == 0) && !weUseSameMethod)
+ m_Method.SetCurSel(itemIndex);
+ }
+
+ if (!weUseSameMethod)
+ MethodChanged();
+}
+
+
+
+bool CCompressDialog::IsZipFormat()
+{
+ return Get_ArcInfoEx().Is_Zip();
+}
+
+bool CCompressDialog::IsXzFormat()
+{
+ return Get_ArcInfoEx().Is_Xz();
+}
+
+void CCompressDialog::SetEncryptionMethod()
+{
+ _encryptionMethod.ResetContent();
+ _default_encryptionMethod_Index = -1;
+ const CArcInfoEx &ai = Get_ArcInfoEx();
+ if (ai.Is_7z())
+ {
+ ComboBox_AddStringAscii(_encryptionMethod, "AES-256");
+ _encryptionMethod.SetCurSel(0);
+ _default_encryptionMethod_Index = 0;
+ }
+ else if (ai.Is_Zip())
+ {
+ int index = FindRegistryFormat(ai.Name);
+ UString encryptionMethod;
+ if (index >= 0)
+ {
+ const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
+ encryptionMethod = fo.EncryptionMethod;
+ }
+ int sel = 0;
+ // if (ZipCryptoIsAllowed)
+ {
+ ComboBox_AddStringAscii(_encryptionMethod, "ZipCrypto");
+ sel = (encryptionMethod.IsPrefixedBy_Ascii_NoCase("aes") ? 1 : 0);
+ _default_encryptionMethod_Index = 0;
+ }
+ ComboBox_AddStringAscii(_encryptionMethod, "AES-256");
+ _encryptionMethod.SetCurSel(sel);
+ }
+}
+
+
+int CCompressDialog::GetMethodID_RAW()
+{
+ if (m_Method.GetCount() <= 0)
+ return -1;
+ return (int)(Int32)(UInt32)m_Method.GetItemData_of_CurSel();
+}
+
+int CCompressDialog::GetMethodID()
+{
+ int raw = GetMethodID_RAW();
+ if (raw < 0)
+ return _auto_MethodId;
+ return raw;
+}
+
+
+UString CCompressDialog::GetMethodSpec(UString &estimatedName)
+{
+ estimatedName.Empty();
+ if (m_Method.GetCount() < 1)
+ return estimatedName;
+ const int methodIdRaw = GetMethodID_RAW();
+ int methodId = methodIdRaw;
+ if (methodIdRaw < 0)
+ methodId = _auto_MethodId;
+ UString s;
+ if (methodId >= 0)
+ {
+ if ((unsigned)methodId < Z7_ARRAY_SIZE(kMethodsNames))
+ estimatedName = kMethodsNames[methodId];
+ else
+ estimatedName = ExternalMethods[(unsigned)methodId - (unsigned)Z7_ARRAY_SIZE(kMethodsNames)];
+ if (methodIdRaw >= 0)
+ s = estimatedName;
+ }
+ return s;
+}
+
+
+UString CCompressDialog::GetMethodSpec()
+{
+ UString estimatedName;
+ UString s = GetMethodSpec(estimatedName);
+ return s;
+}
+
+bool CCompressDialog::IsMethodEqualTo(const UString &s)
+{
+ UString estimatedName;
+ const UString shortName = GetMethodSpec(estimatedName);
+ if (s.IsEmpty())
+ return shortName.IsEmpty();
+ return s.IsEqualTo_NoCase(estimatedName);
+}
+
+
+UString CCompressDialog::GetEncryptionMethodSpec()
+{
+ UString s;
+ if (_encryptionMethod.GetCount() > 0
+ && _encryptionMethod.GetCurSel() != _default_encryptionMethod_Index)
+ {
+ _encryptionMethod.GetText(s);
+ s.RemoveChar(L'-');
+ }
+ return s;
+}
+
+
+static const size_t k_Auto_Dict = (size_t)0 - 1;
+
+static int Combo_AddDict2(NWindows::NControl::CComboBox &cb, size_t sizeReal, size_t sizeShow)
+{
+ char c = 0;
+ unsigned moveBits = 0;
+ if ((sizeShow & 0xFFFFF) == 0) { moveBits = 20; c = 'M'; }
+ else if ((sizeShow & 0x3FF) == 0) { moveBits = 10; c = 'K'; }
+ AString s;
+ s.Add_UInt64(sizeShow >> moveBits);
+ s.Add_Space();
+ if (c != 0)
+ s += c;
+ s += 'B';
+ if (sizeReal == k_Auto_Dict)
+ Modify_Auto(s);
+ const int index = (int)ComboBox_AddStringAscii(cb, s);
+ cb.SetItemData(index, (LPARAM)sizeReal);
+ return index;
+}
+
+int CCompressDialog::AddDict2(size_t sizeReal, size_t sizeShow)
+{
+ return Combo_AddDict2(m_Dictionary, sizeReal, sizeShow);
+}
+
+int CCompressDialog::AddDict(size_t size)
+{
+ return AddDict2(size, size);
+}
+
+/*
+int CCompressDialog::AddDict_Chain(size_t size)
+{
+ return Combo_AddDict2(m_Dictionary_Chain, size, size);
+}
+*/
+
+void CCompressDialog::SetDictionary2()
+{
+ m_Dictionary.ResetContent();
+ // m_Dictionary_Chain.ResetContent();
+
+ // _auto_Dict = (UInt32)1 << 24; // we can use this dictSize to calculate _auto_Solid for unknown method for 7z
+ _auto_Dict = (UInt32)(Int32)-1; // for debug
+ // _auto_Dict_Chain = (UInt32)(Int32)-1; // for debug
+
+ const CArcInfoEx &ai = Get_ArcInfoEx();
+ UInt32 defaultDict = (UInt32)(Int32)-1;
+ // UInt32 defaultDict_Chain = (UInt32)(Int32)-1;
+ {
+ const int index = FindRegistryFormat(ai.Name);
+ if (index >= 0)
+ {
+ const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
+ if (IsMethodEqualTo(fo.Method))
+ {
+ defaultDict = fo.Dictionary;
+ // defaultDict_Chain = fo.DictionaryChain;
+ }
+ }
+ }
+
+ const int methodID = GetMethodID();
+ const UInt32 level = GetLevel2();
+
+ {
+ RECT r, rLabel;
+ GetClientRectOfItem(IDT_COMPRESS_DICTIONARY, rLabel);
+ GetClientRectOfItem(IDC_COMPRESS_DICTIONARY, r);
+ if (_dictionaryCombo_left == 0)
+ _dictionaryCombo_left = r.left;
+
+ // bool showDict2;
+ int newLableRight;
+ int newDictLeft;
+
+ /*
+ if (methodID == kZSTD)
+ {
+ showDict2 = true;
+ newDictLeft = _dictionaryCombo_left;
+ RECT r2;
+ GetClientRectOfItem(IDC_COMPRESS_DICTIONARY2, r2);
+ newLableRight = r2.left;
+ }
+ else
+ */
+ {
+ // showDict2 = false;
+ RECT rBig;
+ GetClientRectOfItem(IDC_COMPRESS_METHOD, rBig);
+ newDictLeft= rBig.left;
+ newLableRight = newDictLeft;
+ }
+
+ if (newLableRight != rLabel.right)
+ {
+ rLabel.right = newLableRight;
+ MoveItem_RECT(IDT_COMPRESS_DICTIONARY, rLabel);
+ InvalidateRect(&rLabel);
+ }
+ if (newDictLeft != r.left)
+ {
+ r.left = newDictLeft;
+ MoveItem_RECT(IDC_COMPRESS_DICTIONARY, r);
+ // InvalidateRect(&r);
+ }
+ // ShowItem_Bool(IDC_COMPRESS_DICTIONARY2, showDict2);
+ }
+
+ if (methodID < 0)
+ return;
+
+ switch (methodID)
+ {
+ case kLZMA:
+ case kLZMA2:
+ {
+ {
+ _auto_Dict =
+ ( level <= 3 ? ((UInt32)1 << (level * 2 + 16)) :
+ ( level <= 6 ? ((UInt32)1 << (level + 19)) :
+ ( level <= 7 ? ((UInt32)1 << 25) : ((UInt32)1 << 26)
+ )));
+ }
+
+ // we use threshold 3.75 GiB to switch to kLzmaMaxDictSize.
+ if (defaultDict != (UInt32)(Int32)-1
+ && defaultDict >= ((UInt32)15 << 28))
+ defaultDict = kLzmaMaxDictSize;
+
+ const size_t kLzmaMaxDictSize_Up = (size_t)1 << (20 + sizeof(size_t) / 4 * 6);
+
+ int curSel = AddDict2(k_Auto_Dict, _auto_Dict);
+
+ for (unsigned i = (16 - 1) * 2; i <= (32 - 1) * 2; i++)
+ {
+ if (i < (20 - 1) * 2
+ && i != (16 - 1) * 2
+ && i != (18 - 1) * 2)
+ continue;
+ if (i == (20 - 1) * 2 + 1)
+ continue;
+ const size_t dict_up = (size_t)(2 + (i & 1)) << (i / 2);
+ size_t dict = dict_up;
+ if (dict_up >= kLzmaMaxDictSize)
+ dict = kLzmaMaxDictSize; // we reduce dictionary
+
+ const int index = AddDict(dict);
+ // AddDict2(dict, dict_up); // for debug : we show 4 GB
+
+ // const UInt32 numThreads = 2;
+ // const UInt64 memUsage = GetMemoryUsageComp_Threads_Dict(numThreads, dict);
+ if (defaultDict != (UInt32)(Int32)-1)
+ if (dict <= defaultDict || curSel <= 0)
+ // if (!maxRamSize_Defined || memUsage <= maxRamSize)
+ curSel = index;
+ if (dict_up >= kLzmaMaxDictSize_Up)
+ break;
+ }
+
+ m_Dictionary.SetCurSel(curSel);
+ break;
+ }
+
+ /*
+ case kZSTD:
+ {
+ if (defaultDict != (UInt32)(Int32)-1 &&
+ defaultDict > kZstd_MAX_DictSize)
+ defaultDict = kZstd_MAX_DictSize;
+
+ if (defaultDict_Chain != (UInt32)(Int32)-1 &&
+ defaultDict_Chain > kZstd_MAX_DictSize_Chain)
+ defaultDict_Chain = kZstd_MAX_DictSize_Chain;
+
+ {
+ CZstdEncProps props;
+ ZstdEncProps_Init(&props);
+ // props.level_zstd = level;
+ props.level_7z = level;
+ ZstdEncProps_Set_WindowSize(&props, defaultDict != (UInt32)(Int32)-1 ? defaultDict: 0);
+ ZstdEncProps_NormalizeFull(&props);
+ _auto_Dict_Chain = (UInt32)1 << props.windowLog_Chain;
+ }
+ {
+ CZstdEncProps props;
+ ZstdEncProps_Init(&props);
+ // props.level_zstd = level;
+ props.level_7z = level;
+ ZstdEncProps_Set_WindowChainSize(&props, defaultDict_Chain != (UInt32)(Int32)-1 ? defaultDict_Chain: 0);
+ ZstdEncProps_NormalizeFull(&props);
+ _auto_Dict = (UInt32)1 << props.windowLog;
+ }
+
+ // if there is collision of two window sizes, we reduce dict_Chain
+ if (defaultDict != (UInt32)(Int32)-1 &&
+ defaultDict_Chain != (UInt32)(Int32)-1 &&
+ defaultDict < defaultDict_Chain)
+ defaultDict_Chain = defaultDict;
+
+ {
+ int curSel = AddDict2(k_Auto_Dict, _auto_Dict);
+
+ // defaultDict = 12 << 10; // for debug
+ const UInt32 kWinStart = 18;
+ if (defaultDict != 0 && defaultDict < ((UInt32)1 << kWinStart))
+ curSel = AddDict(defaultDict);
+
+ for (unsigned i = kWinStart; i <= MY_ZSTD_WINDOWLOG_MAX; i++)
+ {
+ const size_t dict = (size_t)1 << i;
+ const int index = AddDict(dict);
+ if (defaultDict != (UInt32)(Int32)-1)
+ if (dict <= defaultDict || curSel <= 0)
+ curSel = index;
+ }
+ m_Dictionary.SetCurSel(curSel);
+ }
+
+ {
+ int curSel = Combo_AddDict2(m_Dictionary_Chain, k_Auto_Dict, _auto_Dict_Chain);
+
+ // defaultDict_Chain = 10 << 10; // for debug
+ const UInt32 kWinChainStart = 15;
+ if (defaultDict_Chain != 0 && defaultDict_Chain < ((UInt32)1 << kWinChainStart))
+ curSel = AddDict_Chain(defaultDict_Chain);
+
+ for (unsigned i = kWinChainStart; i <= kMaxDictChain; i++)
+ {
+ const size_t dict = (size_t)1 << i;
+ if (defaultDict != (UInt32)(Int32)-1 && dict > defaultDict)
+ break;
+ const int index = AddDict_Chain(dict);
+ if (defaultDict_Chain != (UInt32)(Int32)-1)
+ if (dict <= defaultDict_Chain || curSel <= 0)
+ curSel = index;
+ }
+ m_Dictionary_Chain.SetCurSel(curSel);
+ }
+
+ break;
+ }
+ */
+
+ case kPPMd:
+ {
+ _auto_Dict = (UInt32)1 << (level + 19);
+
+ const UInt32 kPpmd_Default_4g = (UInt32)0 - ((UInt32)1 << 10);
+ const size_t kPpmd_MaxDictSize_Up = (size_t)1 << (29 + sizeof(size_t) / 8);
+
+ if (defaultDict != (UInt32)(Int32)-1
+ && defaultDict >= ((UInt32)15 << 28)) // threshold
+ defaultDict = kPpmd_Default_4g;
+
+ int curSel = AddDict2(k_Auto_Dict, _auto_Dict);
+
+ for (unsigned i = (20 - 1) * 2; i <= (32 - 1) * 2; i++)
+ {
+ if (i == (20 - 1) * 2 + 1)
+ continue;
+
+ const size_t dict_up = (size_t)(2 + (i & 1)) << (i / 2);
+ size_t dict = dict_up;
+ if (dict_up >= kPpmd_Default_4g)
+ dict = kPpmd_Default_4g;
+
+ const int index = AddDict2(dict, dict_up);
+ // AddDict2((UInt32)((UInt32)0 - 2), dict_up); // for debug
+ // AddDict(dict_up); // for debug
+ // const UInt64 memUsage = GetMemoryUsageComp_Threads_Dict(1, dict);
+ if (defaultDict != (UInt32)(Int32)-1)
+ if (dict <= defaultDict || curSel <= 0)
+ // if (!maxRamSize_Defined || memUsage <= maxRamSize)
+ curSel = index;
+ if (dict_up >= kPpmd_MaxDictSize_Up)
+ break;
+ }
+ m_Dictionary.SetCurSel(curSel);
+ break;
+ }
+
+ case kPPMdZip:
+ {
+ _auto_Dict = (UInt32)1 << (level + 19);
+
+ int curSel = AddDict2(k_Auto_Dict, _auto_Dict);
+
+ for (unsigned i = 20; i <= 28; i++)
+ {
+ const UInt32 dict = (UInt32)1 << i;
+ const int index = AddDict(dict);
+ // const UInt64 memUsage = GetMemoryUsageComp_Threads_Dict(1, dict);
+ if (defaultDict != (UInt32)(Int32)-1)
+ if (dict <= defaultDict || curSel <= 0)
+ // if (!maxRamSize_Defined || memUsage <= maxRamSize)
+ curSel = index;
+ }
+ m_Dictionary.SetCurSel(curSel);
+ break;
+ }
+
+ case kDeflate:
+ case kDeflate64:
+ {
+ const UInt32 dict = (methodID == kDeflate ? (UInt32)(1 << 15) : (UInt32)(1 << 16));
+ _auto_Dict = dict;
+ AddDict2(k_Auto_Dict, _auto_Dict);
+ m_Dictionary.SetCurSel(0);
+ // EnableItem(IDC_COMPRESS_DICTIONARY, false);
+ break;
+ }
+
+ case kBZip2:
+ {
+ {
+ if (level >= 5) _auto_Dict = (900 << 10);
+ else if (level >= 3) _auto_Dict = (500 << 10);
+ else _auto_Dict = (100 << 10);
+ }
+
+ int curSel = AddDict2(k_Auto_Dict, _auto_Dict);
+
+ for (unsigned i = 1; i <= 9; i++)
+ {
+ const UInt32 dict = ((UInt32)i * 100) << 10;
+ AddDict(dict);
+ // AddDict2(i * 100000, dict);
+ if (defaultDict != (UInt32)(Int32)-1)
+ if (i <= defaultDict / 100000 || curSel <= 0)
+ curSel = m_Dictionary.GetCount() - 1;
+ }
+ m_Dictionary.SetCurSel(curSel);
+ break;
+ }
+
+ case kCopy:
+ {
+ _auto_Dict = 0;
+ AddDict(0);
+ m_Dictionary.SetCurSel(0);
+ break;
+ }
+ }
+}
+
+
+UInt32 CCompressDialog::GetComboValue(NWindows::NControl::CComboBox &c, int defMax)
+{
+ if (c.GetCount() <= defMax)
+ return (UInt32)(Int32)-1;
+ return (UInt32)c.GetItemData_of_CurSel();
+}
+
+
+UInt64 CCompressDialog::GetComboValue_64(NWindows::NControl::CComboBox &c, int defMax)
+{
+ if (c.GetCount() <= defMax)
+ return (UInt64)(Int64)-1;
+ // LRESULT is signed. so we cast it to unsigned size_t at first:
+ LRESULT val = c.GetItemData_of_CurSel();
+ if (val == (LPARAM)(INT_PTR)(-1))
+ return (UInt64)(Int64)-1;
+ return (UInt64)(size_t)c.GetItemData_of_CurSel();
+}
+
+UInt32 CCompressDialog::GetLevel2()
+{
+ UInt32 level = GetLevel();
+ if (level == (UInt32)(Int32)-1)
+ level = 5;
+ return level;
+}
+
+
+int CCompressDialog::AddOrder(UInt32 size)
+{
+ char s[32];
+ ConvertUInt32ToString(size, s);
+ const int index = (int)ComboBox_AddStringAscii(m_Order, s);
+ m_Order.SetItemData(index, (LPARAM)size);
+ return index;
+}
+
+int CCompressDialog::AddOrder_Auto()
+{
+ AString s;
+ s.Add_UInt32(_auto_Order);
+ Modify_Auto(s);
+ int index = (int)ComboBox_AddStringAscii(m_Order, s);
+ m_Order.SetItemData(index, (LPARAM)(INT_PTR)(-1));
+ return index;
+}
+
+void CCompressDialog::SetOrder2()
+{
+ m_Order.ResetContent();
+
+ _auto_Order = 1;
+
+ const CArcInfoEx &ai = Get_ArcInfoEx();
+ UInt32 defaultOrder = (UInt32)(Int32)-1;
+
+ {
+ const int index = FindRegistryFormat(ai.Name);
+ if (index >= 0)
+ {
+ const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
+ if (IsMethodEqualTo(fo.Method))
+ defaultOrder = fo.Order;
+ }
+ }
+
+ const int methodID = GetMethodID();
+ const UInt32 level = GetLevel2();
+ if (methodID < 0)
+ return;
+
+ switch (methodID)
+ {
+ case kLZMA:
+ case kLZMA2:
+ {
+ _auto_Order = (level < 7 ? 32 : 64);
+ int curSel = AddOrder_Auto();
+ for (unsigned i = 2 * 2; i < 8 * 2; i++)
+ {
+ UInt32 order = ((UInt32)(2 + (i & 1)) << (i / 2));
+ if (order > 256)
+ order = 273;
+ const int index = AddOrder(order);
+ if (defaultOrder != (UInt32)(Int32)-1)
+ if (order <= defaultOrder || curSel <= 0)
+ curSel = index;
+ }
+ m_Order.SetCurSel(curSel);
+ break;
+ }
+
+ /*
+ case kZSTD:
+ {
+ {
+ CZstdEncProps props;
+ ZstdEncProps_Init(&props);
+ // props.level_zstd = level;
+ props.level_7z = level;
+ ZstdEncProps_NormalizeFull(&props);
+ _auto_Order = props.targetLength;
+ if (props.strategy < ZSTD_strategy_btopt)
+ {
+ // ZSTD_strategy_fast uses targetLength to change fast level.
+ // targetLength probably is used only in ZSTD_strategy_btopt and higher
+ break;
+ }
+ }
+ int curSel = AddOrder_Auto();
+
+ for (unsigned i = 6; i <= 9 * 2; i++)
+ {
+ UInt32 order = ((UInt32)(2 + (i & 1)) << (i / 2));
+ // if (order > 999) order = 999;
+ const int index = AddOrder(order);
+ if (defaultOrder != (UInt32)(Int32)-1)
+ if (order <= defaultOrder || curSel <= 0)
+ curSel = index;
+ }
+ m_Order.SetCurSel(curSel);
+ break;
+ }
+ */
+
+ case kDeflate:
+ case kDeflate64:
+ {
+ {
+ if (level >= 9) _auto_Order = 128;
+ else if (level >= 7) _auto_Order = 64;
+ else _auto_Order = 32;
+ }
+ int curSel = AddOrder_Auto();
+ for (unsigned i = 2 * 2; i < 8 * 2; i++)
+ {
+ UInt32 order = ((UInt32)(2 + (i & 1)) << (i / 2));
+ if (order > 256)
+ order = (methodID == kDeflate64 ? 257 : 258);
+ const int index = AddOrder(order);
+ if (defaultOrder != (UInt32)(Int32)-1)
+ if (order <= defaultOrder || curSel <= 0)
+ curSel = index;
+ }
+
+ m_Order.SetCurSel(curSel);
+ break;
+ }
+
+ case kPPMd:
+ {
+ {
+ if (level >= 9) _auto_Order = 32;
+ else if (level >= 7) _auto_Order = 16;
+ else if (level >= 5) _auto_Order = 6;
+ else _auto_Order = 4;
+ }
+
+ int curSel = AddOrder_Auto();
+
+ for (unsigned i = 0;; i++)
+ {
+ UInt32 order = i + 2;
+ if (i >= 2)
+ order = (4 + ((i - 2) & 3)) << ((i - 2) / 4);
+ const int index = AddOrder(order);
+ if (defaultOrder != (UInt32)(Int32)-1)
+ if (order <= defaultOrder || curSel <= 0)
+ curSel = index;
+ if (order >= 32)
+ break;
+ }
+ m_Order.SetCurSel(curSel);
+ break;
+ }
+
+ case kPPMdZip:
+ {
+ _auto_Order = level + 3;
+ int curSel = AddOrder_Auto();
+ for (unsigned i = 2; i <= 16; i++)
+ {
+ const int index = AddOrder(i);
+ if (defaultOrder != (UInt32)(Int32)-1)
+ if (i <= defaultOrder || curSel <= 0)
+ curSel = index;
+ }
+ m_Order.SetCurSel(curSel);
+ break;
+ }
+
+ // case kBZip2:
+ default:
+ break;
+ }
+}
+
+bool CCompressDialog::GetOrderMode()
+{
+ switch (GetMethodID())
+ {
+ case kPPMd:
+ case kPPMdZip:
+ return true;
+ }
+ return false;
+}
+
+
+static UInt64 Get_Lzma2_ChunkSize(UInt64 dict)
+{
+ // we use same default chunk sizes as defined in 7z encoder and lzma2 encoder
+ UInt64 cs = (UInt64)dict << 2;
+ const UInt32 kMinSize = (UInt32)1 << 20;
+ const UInt32 kMaxSize = (UInt32)1 << 28;
+ if (cs < kMinSize) cs = kMinSize;
+ if (cs > kMaxSize) cs = kMaxSize;
+ if (cs < dict) cs = dict;
+ cs += (kMinSize - 1);
+ cs &= ~(UInt64)(kMinSize - 1);
+ return cs;
+}
+
+
+static void Add_Size(AString &s, UInt64 val)
+{
+ unsigned moveBits = 0;
+ char c = 0;
+ if ((val & 0x3FFFFFFF) == 0) { moveBits = 30; c = 'G'; }
+ else if ((val & 0xFFFFF) == 0) { moveBits = 20; c = 'M'; }
+ else if ((val & 0x3FF) == 0) { moveBits = 10; c = 'K'; }
+ s.Add_UInt64(val >> moveBits);
+ s.Add_Space();
+ if (moveBits != 0)
+ s += c;
+ s += 'B';
+}
+
+
+void CCompressDialog::SetSolidBlockSize2()
+{
+ m_Solid.ResetContent();
+ _auto_Solid = 1 << 20;
+
+ const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
+ if (!fi.Solid_())
+ return;
+
+ const UInt32 level = GetLevel2();
+ if (level == 0)
+ return;
+
+ UInt64 dict = GetDict2();
+ if (dict == (UInt64)(Int64)-1)
+ {
+ dict = 1 << 25; // default dict for unknown methods
+ // return;
+ }
+
+
+ UInt32 defaultBlockSize = (UInt32)(Int32)-1;
+
+ const CArcInfoEx &ai = Get_ArcInfoEx();
+
+ /*
+ if (usePrevDictionary)
+ defaultBlockSize = GetBlockSizeSpec();
+ else
+ */
+ {
+ const int index = FindRegistryFormat(ai.Name);
+ if (index >= 0)
+ {
+ const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
+ if (IsMethodEqualTo(fo.Method))
+ defaultBlockSize = fo.BlockLogSize;
+ }
+ }
+
+ const bool is7z = ai.Is_7z();
+
+ const UInt64 cs = Get_Lzma2_ChunkSize(dict);
+
+ // Solid Block Size
+ UInt64 blockSize = cs; // for xz
+
+ if (is7z)
+ {
+ // we use same default block sizes as defined in 7z encoder
+ UInt64 kMaxSize = (UInt64)1 << 32;
+ const int methodId = GetMethodID();
+ if (methodId == kLZMA2)
+ {
+ blockSize = cs << 6;
+ kMaxSize = (UInt64)1 << 34;
+ }
+ else
+ {
+ UInt64 dict2 = dict;
+ if (methodId == kBZip2)
+ {
+ dict2 /= 100000;
+ if (dict2 < 1)
+ dict2 = 1;
+ dict2 *= 100000;
+ }
+ blockSize = dict2 << 7;
+ }
+
+ const UInt32 kMinSize = (UInt32)1 << 24;
+ if (blockSize < kMinSize) blockSize = kMinSize;
+ if (blockSize > kMaxSize) blockSize = kMaxSize;
+ }
+
+ _auto_Solid = blockSize;
+
+ int curSel;
+ {
+ AString s;
+ Add_Size(s, _auto_Solid);
+ Modify_Auto(s);
+ const int index = (int)ComboBox_AddStringAscii(m_Solid, s);
+ m_Solid.SetItemData(index, (LPARAM)(UInt32)(Int32)-1);
+ curSel = index;
+ }
+
+ if (is7z)
+ {
+ UString s ('-');
+ // kSolidLog_NoSolid = 0 for xz means default blockSize
+ if (is7z)
+ LangString(IDS_COMPRESS_NON_SOLID, s);
+ const int index = (int)m_Solid.AddString(s);
+ m_Solid.SetItemData(index, (LPARAM)(UInt32)kSolidLog_NoSolid);
+ if (defaultBlockSize == kSolidLog_NoSolid)
+ curSel = index;
+ }
+
+ for (unsigned i = 20; i <= 36; i++)
+ {
+ AString s;
+ Add_Size(s, (UInt64)1 << i);
+ const int index = (int)ComboBox_AddStringAscii(m_Solid, s);
+ m_Solid.SetItemData(index, (LPARAM)(UInt32)i);
+ if (defaultBlockSize != (UInt32)(Int32)-1)
+ if (i <= defaultBlockSize || index <= 1)
+ curSel = index;
+ }
+
+ {
+ const int index = (int)m_Solid.AddString(LangString(IDS_COMPRESS_SOLID));
+ m_Solid.SetItemData(index, (LPARAM)kSolidLog_FullSolid);
+ if (defaultBlockSize == kSolidLog_FullSolid)
+ curSel = index;
+ }
+
+ m_Solid.SetCurSel(curSel);
+}
+
+
+/*
+static void ZstdEncProps_SetDictProps_From_CompressDialog(CZstdEncProps *props, CCompressDialog &cd)
+{
+ {
+ const UInt64 d64 = cd.GetDictSpec();
+ UInt32 d32 = 0; // 0 is default for ZstdEncProps::windowLog
+ if (d64 != (UInt64)(Int64)-1)
+ {
+ d32 = (UInt32)d64;
+ if (d32 != d64)
+ d32 = (UInt32)(Int32)-2;
+ }
+ ZstdEncProps_Set_WindowSize(props, d32);
+ }
+ {
+ const UInt64 d64 = cd.GetDictChainSpec();
+ UInt32 d32 = 0; // 0 is default for ZstdEncProps::windowLog_Chain
+ if (d64 != (UInt64)(Int64)-1)
+ {
+ d32 = (UInt32)d64;
+ if (d32 != d64)
+ d32 = (UInt32)(Int32)-2;
+ }
+ ZstdEncProps_Set_WindowChainSize(props, d32);
+ }
+}
+
+static bool Is_Zstd_Mt_Supported()
+{
+ if (!GetProcAddress(GetModuleHandle(TEXT("kernel32.dll")), "InitializeConditionVariable"))
+ return false;
+ return true;
+}
+*/
+
+static const char *k_ST_Threads = " (ST)";
+
+void CCompressDialog::SetNumThreads2()
+{
+ _auto_NumThreads = 1;
+
+ m_NumThreads.ResetContent();
+ const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
+ if (!fi.MultiThread_())
+ return;
+
+ const UInt32 numHardwareThreads = NSystem::GetNumberOfProcessors();
+ // 64; // for debug:
+
+ UInt32 defaultValue = numHardwareThreads;
+ bool useAutoThreads = true;
+
+ {
+ const CArcInfoEx &ai = Get_ArcInfoEx();
+ int index = FindRegistryFormat(ai.Name);
+ if (index >= 0)
+ {
+ const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
+ if (IsMethodEqualTo(fo.Method) && fo.NumThreads != (UInt32)(Int32)-1)
+ {
+ defaultValue = fo.NumThreads;
+ useAutoThreads = false;
+ }
+ }
+ }
+
+ // const UInt32 num_ZSTD_threads_MAX = Is_Zstd_Mt_Supported() ? MY_ZSTDMT_NBWORKERS_MAX : 0;
+
+ UInt32 numAlgoThreadsMax = numHardwareThreads * 2;
+ const int methodID = GetMethodID();
+
+ switch (methodID)
+ {
+ case kLZMA: numAlgoThreadsMax = 2; break;
+ case kLZMA2: numAlgoThreadsMax = 256; break;
+ case kBZip2: numAlgoThreadsMax = 32; break;
+ // case kZSTD: numAlgoThreadsMax = num_ZSTD_threads_MAX; break;
+ case kCopy:
+ case kPPMd:
+ case kDeflate:
+ case kDeflate64:
+ case kPPMdZip:
+ numAlgoThreadsMax = 1;
+ }
+ const bool isZip = IsZipFormat();
+ if (isZip)
+ {
+ numAlgoThreadsMax =
+ #ifdef _WIN32
+ 64; // _WIN32 supports only 64 threads in one group. So no need for more threads here
+ #else
+ 128;
+ #endif
+ }
+
+ UInt32 autoThreads = numHardwareThreads;
+ if (autoThreads > numAlgoThreadsMax)
+ autoThreads = numAlgoThreadsMax;
+
+ const UInt64 memUse_Limit = Get_MemUse_Bytes();
+
+ if (_ramSize_Defined)
+ if (autoThreads > 1
+ // || (autoThreads == 0 && methodID == kZSTD)
+ )
+ {
+ if (isZip)
+ {
+ for (; autoThreads > 1; autoThreads--)
+ {
+ const UInt64 dict64 = GetDict2();
+ UInt64 decompressMemory;
+ const UInt64 usage = GetMemoryUsage_Threads_Dict_DecompMem(autoThreads, dict64, decompressMemory);
+ if (usage <= memUse_Limit)
+ break;
+ }
+ }
+ else if (methodID == kLZMA2)
+ {
+ const UInt64 dict64 = GetDict2();
+ const UInt32 numThreads1 = (GetLevel2() >= 5 ? 2 : 1);
+ UInt32 numBlockThreads = autoThreads / numThreads1;
+ for (; numBlockThreads > 1; numBlockThreads--)
+ {
+ autoThreads = numBlockThreads * numThreads1;
+ UInt64 decompressMemory;
+ const UInt64 usage = GetMemoryUsage_Threads_Dict_DecompMem(autoThreads, dict64, decompressMemory);
+ if (usage <= memUse_Limit)
+ break;
+ }
+ autoThreads = numBlockThreads * numThreads1;
+ }
+ /*
+ else if (methodID == kZSTD)
+ {
+ if (num_ZSTD_threads_MAX != 0)
+ {
+ CZstdEncProps props;
+ ZstdEncProps_Init(&props);
+ // props.level_zstd = level;
+ props.level_7z = GetLevel2();
+ ZstdEncProps_SetDictProps_From_CompressDialog(&props, *this);
+ autoThreads = ZstdEncProps_GetNumThreads_for_MemUsageLimit(&props, memUse_Limit, autoThreads);
+ }
+ }
+ */
+ }
+
+ _auto_NumThreads = autoThreads;
+
+ int curSel = -1;
+ {
+ AString s;
+ s.Add_UInt32(autoThreads);
+ if (autoThreads == 0) s += k_ST_Threads;
+ Modify_Auto(s);
+ const int index = (int)ComboBox_AddStringAscii(m_NumThreads, s);
+ m_NumThreads.SetItemData(index, (LPARAM)(INT_PTR)(-1));
+ // m_NumThreads.SetItemData(index, autoThreads);
+ if (useAutoThreads)
+ curSel = index;
+ }
+
+ if (numAlgoThreadsMax != autoThreads || autoThreads != 1)
+ for (UInt32 i =
+ // (methodID == kZSTD) ? 0 :
+ 1;
+ i <= numHardwareThreads * 2 && i <= numAlgoThreadsMax; i++)
+ {
+ AString s;
+ s.Add_UInt32(i);
+ if (i == 0) s += k_ST_Threads;
+ const int index = (int)ComboBox_AddStringAscii(m_NumThreads, s);
+ m_NumThreads.SetItemData(index, (LPARAM)(UInt32)i);
+ if (!useAutoThreads && i == defaultValue)
+ curSel = index;
+ }
+
+ m_NumThreads.SetCurSel(curSel);
+}
+
+
+static void AddMemSize(UString &res, UInt64 size)
+{
+ char c;
+ unsigned moveBits = 0;
+ if (size >= ((UInt64)1 << 31) && (size & 0x3FFFFFFF) == 0)
+ { moveBits = 30; c = 'G'; }
+ else // if (size >= ((UInt32)1 << 21) && (size & 0xFFFFF) == 0)
+ { moveBits = 20; c = 'M'; }
+ // else { moveBits = 10; c = 'K'; }
+ res.Add_UInt64(size >> moveBits);
+ res.Add_Space();
+ if (moveBits != 0)
+ res += c;
+ res += 'B';
+}
+
+
+int CCompressDialog::AddMemComboItem(UInt64 val, bool isPercent, bool isDefault)
+{
+ UString sUser;
+ UString sRegistry;
+ if (isPercent)
+ {
+ UString s;
+ s.Add_UInt64(val);
+ s += '%';
+ if (isDefault)
+ sUser = k_Auto_Prefix;
+ else
+ sRegistry = s;
+ sUser += s;
+ }
+ else
+ {
+ AddMemSize(sUser, val);
+ sRegistry = sUser;
+ for (;;)
+ {
+ const int pos = sRegistry.Find(L' ');
+ if (pos < 0)
+ break;
+ sRegistry.Delete(pos);
+ }
+ if (!sRegistry.IsEmpty())
+ if (sRegistry.Back() == 'B')
+ sRegistry.DeleteBack();
+ }
+ const unsigned dataIndex = _memUse_Strings.Add(sRegistry);
+ const int index = (int)m_MemUse.AddString(sUser);
+ m_MemUse.SetItemData(index, (LPARAM)dataIndex);
+ return index;
+}
+
+
+
+void CCompressDialog::SetMemUseCombo()
+{
+ _memUse_Strings.Clear();
+ m_MemUse.ResetContent();
+ const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
+
+ {
+ const bool enable = fi.MemUse_();
+ ShowItem_Bool(IDT_COMPRESS_MEMORY, enable);
+ ShowItem_Bool(IDT_COMPRESS_MEMORY_VALUE, enable);
+ ShowItem_Bool(IDT_COMPRESS_MEMORY_DE, enable);
+ ShowItem_Bool(IDT_COMPRESS_MEMORY_DE_VALUE, enable);
+ ShowItem_Bool(IDC_COMPRESS_MEM_USE, enable);
+ EnableItem(IDC_COMPRESS_MEM_USE, enable);
+ if (!enable)
+ return;
+ }
+
+ UInt64 curMem_Bytes = 0;
+ UInt64 curMem_Percents = 0;
+ bool needSetCur_Bytes = false;
+ bool needSetCur_Percents = false;
+ {
+ const NCompression::CFormatOptions &fo = Get_FormatOptions();
+ if (!fo.MemUse.IsEmpty())
+ {
+ NCompression::CMemUse mu;
+ mu.Parse(fo.MemUse);
+ if (mu.IsDefined)
+ {
+ if (mu.IsPercent)
+ {
+ curMem_Percents = mu.Val;
+ needSetCur_Percents = true;
+ }
+ else
+ {
+ curMem_Bytes = mu.GetBytes(_ramSize_Reduced);
+ needSetCur_Bytes = true;
+ }
+ }
+ }
+ }
+
+
+ // 80% - is auto usage limit in handlers
+ AddMemComboItem(80, true, true);
+ m_MemUse.SetCurSel(0);
+
+ {
+ for (unsigned i = 10;; i += 10)
+ {
+ UInt64 size = i;
+ if (i > 100)
+ size = (UInt64)(Int64)-1;
+ if (needSetCur_Percents && size >= curMem_Percents)
+ {
+ const int index = AddMemComboItem(curMem_Percents, true);
+ m_MemUse.SetCurSel(index);
+ needSetCur_Percents = false;
+ if (size == curMem_Percents)
+ continue;
+ }
+ if (size == (UInt64)(Int64)-1)
+ break;
+ AddMemComboItem(size, true);
+ }
+ }
+ {
+ for (unsigned i = (27) * 2;; i++)
+ {
+ UInt64 size = (UInt64)(2 + (i & 1)) << (i / 2);
+ if (i > (20 + sizeof(size_t) * 3 - 1) * 2)
+ size = (UInt64)(Int64)-1;
+ if (needSetCur_Bytes && size >= curMem_Bytes)
+ {
+ const int index = AddMemComboItem(curMem_Bytes);
+ m_MemUse.SetCurSel(index);
+ needSetCur_Bytes = false;
+ if (size == curMem_Bytes)
+ continue;
+ }
+ if (size == (UInt64)(Int64)-1)
+ break;
+ AddMemComboItem(size);
+ }
+ }
+}
+
+
+UString CCompressDialog::Get_MemUse_Spec()
+{
+ if (m_MemUse.GetCount() < 1)
+ return UString();
+ return _memUse_Strings[(unsigned)m_MemUse.GetItemData_of_CurSel()];
+}
+
+
+UInt64 CCompressDialog::Get_MemUse_Bytes()
+{
+ const UString mus = Get_MemUse_Spec();
+ NCompression::CMemUse mu;
+ if (!mus.IsEmpty())
+ {
+ mu.Parse(mus);
+ if (mu.IsDefined)
+ return mu.GetBytes(_ramSize_Reduced);
+ }
+ return _ramUsage_Auto; // _ramSize_Reduced; // _ramSize;;
+}
+
+
+
+UInt64 CCompressDialog::GetMemoryUsage_DecompMem(UInt64 &decompressMemory)
+{
+ return GetMemoryUsage_Dict_DecompMem(GetDict2(), decompressMemory);
+}
+
+
+/*
+we could use that function to reduce the dictionary if small RAM
+UInt64 CCompressDialog::GetMemoryUsageComp_Threads_Dict(UInt32 numThreads, UInt64 dict64)
+{
+ UInt64 decompressMemory;
+ return GetMemoryUsage_Threads_Dict_DecompMem(numThreads, dict64, decompressMemory);
+}
+*/
+
+
+UInt64 CCompressDialog::GetMemoryUsage_Dict_DecompMem(UInt64 dict64, UInt64 &decompressMemory)
+{
+ return GetMemoryUsage_Threads_Dict_DecompMem(GetNumThreads2(), dict64, decompressMemory);
+}
+
+UInt64 CCompressDialog::GetMemoryUsage_Threads_Dict_DecompMem(UInt32 numThreads, UInt64 dict64, UInt64 &decompressMemory)
+{
+ decompressMemory = (UInt64)(Int64)-1;
+
+ const UInt32 level = GetLevel2();
+ if (level == 0 && !Get_ArcInfoEx().Is_Zstd())
+ {
+ decompressMemory = (1 << 20);
+ return decompressMemory;
+ }
+ UInt64 size = 0;
+
+ const CFormatInfo &fi = g_Formats[GetStaticFormatIndex()];
+ if (fi.Filter_() && level >= 9)
+ size += (12 << 20) * 2 + (5 << 20);
+ // UInt32 numThreads = GetNumThreads2();
+
+ UInt32 numMainZipThreads = 1;
+
+ if (IsZipFormat())
+ {
+ UInt32 numSubThreads = 1;
+ if (GetMethodID() == kLZMA && numThreads > 1 && level >= 5)
+ numSubThreads = 2;
+ numMainZipThreads = numThreads / numSubThreads;
+ if (numMainZipThreads > 1)
+ size += (UInt64)numMainZipThreads * ((size_t)sizeof(size_t) << 23);
+ else
+ numMainZipThreads = 1;
+ }
+
+ const int methodId = GetMethodID();
+
+ if (dict64 == (UInt64)(Int64)-1
+ // && methodId != kZSTD
+ )
+ return (UInt64)(Int64)-1;
+
+
+ switch (methodId)
+ {
+ case kLZMA:
+ case kLZMA2:
+ {
+ const UInt32 dict = (dict64 >= kLzmaMaxDictSize ? kLzmaMaxDictSize : (UInt32)dict64);
+ UInt32 hs = dict - 1;
+ hs |= (hs >> 1);
+ hs |= (hs >> 2);
+ hs |= (hs >> 4);
+ hs |= (hs >> 8);
+ hs >>= 1;
+ if (hs >= (1 << 24))
+ hs >>= 1;
+ hs |= (1 << 16) - 1;
+ // if (numHashBytes >= 5)
+ if (level < 5)
+ hs |= (256 << 10) - 1;
+ hs++;
+ UInt64 size1 = (UInt64)hs * 4;
+ size1 += (UInt64)dict * 4;
+ if (level >= 5)
+ size1 += (UInt64)dict * 4;
+ size1 += (2 << 20);
+
+ UInt32 numThreads1 = 1;
+ if (numThreads > 1 && level >= 5)
+ {
+ size1 += (2 << 20) + (4 << 20);
+ numThreads1 = 2;
+ }
+
+ UInt32 numBlockThreads = numThreads / numThreads1;
+
+ UInt64 chunkSize = 0; // it's solid chunk
+
+ if (methodId != kLZMA && numBlockThreads != 1)
+ {
+ chunkSize = Get_Lzma2_ChunkSize(dict);
+
+ if (IsXzFormat())
+ {
+ UInt32 blockSizeLog = GetBlockSizeSpec();
+ if (blockSizeLog != (UInt32)(Int32)-1)
+ {
+ if (blockSizeLog == kSolidLog_FullSolid)
+ {
+ numBlockThreads = 1;
+ chunkSize = 0;
+ }
+ else if (blockSizeLog != kSolidLog_NoSolid)
+ chunkSize = (UInt64)1 << blockSizeLog;
+ }
+ }
+ }
+
+ if (chunkSize == 0)
+ {
+ const UInt32 kBlockSizeMax = (UInt32)0 - (UInt32)(1 << 16);
+ UInt64 blockSize = (UInt64)dict + (1 << 16)
+ + (numThreads1 > 1 ? (1 << 20) : 0);
+ blockSize += (blockSize >> (blockSize < ((UInt32)1 << 30) ? 1 : 2));
+ if (blockSize >= kBlockSizeMax)
+ blockSize = kBlockSizeMax;
+ size += numBlockThreads * (size1 + blockSize);
+ }
+ else
+ {
+ size += numBlockThreads * (size1 + chunkSize);
+ UInt32 numPackChunks = numBlockThreads + (numBlockThreads / 8) + 1;
+ if (chunkSize < ((UInt32)1 << 26)) numBlockThreads++;
+ if (chunkSize < ((UInt32)1 << 24)) numBlockThreads++;
+ if (chunkSize < ((UInt32)1 << 22)) numBlockThreads++;
+ size += numPackChunks * chunkSize;
+ }
+
+ decompressMemory = dict + (2 << 20);
+ return size;
+ }
+
+ /*
+ case kZSTD:
+ {
+ CZstdEncProps props;
+ ZstdEncProps_Init(&props);
+ // props.level_zstd = level;
+ props.level_7z = level;
+ props.nbWorkers = numThreads;
+ ZstdEncProps_SetDictProps_From_CompressDialog(&props, *this);
+ ZstdEncProps_NormalizeFull(&props);
+ size = ZstdEncProps_GetMemUsage(&props);
+ decompressMemory = (UInt64)1 << props.windowLog;
+ return size;
+ }
+ */
+
+ case kPPMd:
+ {
+ decompressMemory = dict64 + (2 << 20);
+ return size + decompressMemory;
+ }
+
+ case kDeflate:
+ case kDeflate64:
+ {
+ UInt64 size1 = 3 << 20;
+ // if (level >= 7)
+ size1 += (1 << 20);
+ size += size1 * numMainZipThreads;
+ decompressMemory = (2 << 20);
+ return size;
+ }
+
+ case kBZip2:
+ {
+ decompressMemory = (7 << 20);
+ UInt64 memForOneThread = (10 << 20);
+ return size + memForOneThread * numThreads;
+ }
+
+ case kPPMdZip:
+ {
+ decompressMemory = dict64 + (2 << 20);
+ return size + (UInt64)decompressMemory * numThreads;
+ }
+ }
+
+ return (UInt64)(Int64)-1;
+}
+
+
+
+static void AddMemUsage(UString &s, UInt64 v)
+{
+ const char *post;
+ if (v <= ((UInt64)16 << 30))
+ {
+ v = (v + (1 << 20) - 1) >> 20;
+ post = "MB";
+ }
+ else if (v <= ((UInt64)64 << 40))
+ {
+ v = (v + (1 << 30) - 1) >> 30;
+ post = "GB";
+ }
+ else
+ {
+ const UInt64 v2 = v + ((UInt64)1 << 40) - 1;
+ if (v <= v2)
+ v = v2;
+ v >>= 40;
+ post = "TB";
+ }
+ s.Add_UInt64(v);
+ s.Add_Space();
+ s += post;
+}
+
+
+void CCompressDialog::PrintMemUsage(UINT res, UInt64 value)
+{
+ if (value == (UInt64)(Int64)-1)
+ {
+ SetItemText(res, TEXT("?"));
+ return;
+ }
+ UString s;
+ AddMemUsage(s, value);
+ if (res == IDT_COMPRESS_MEMORY_VALUE)
+ {
+ const UString mus = Get_MemUse_Spec();
+ NCompression::CMemUse mu;
+ if (!mus.IsEmpty())
+ mu.Parse(mus);
+ if (mu.IsDefined)
+ {
+ s += " / ";
+ AddMemUsage(s, mu.GetBytes(_ramSize_Reduced));
+ }
+ else if (_ramSize_Defined)
+ {
+ s += " / ";
+ AddMemUsage(s, _ramUsage_Auto);
+ }
+
+ if (_ramSize_Defined)
+ {
+ s += " / ";
+ AddMemUsage(s, _ramSize);
+ }
+ }
+ SetItemText(res, s);
+}
+
+
+void CCompressDialog::SetMemoryUsage()
+{
+ UInt64 decompressMem;
+ const UInt64 memUsage = GetMemoryUsage_DecompMem(decompressMem);
+ PrintMemUsage(IDT_COMPRESS_MEMORY_VALUE, memUsage);
+ PrintMemUsage(IDT_COMPRESS_MEMORY_DE_VALUE, decompressMem);
+ #ifdef PRINT_PARAMS
+ Print_Params();
+ #endif
+}
+
+
+
+#ifdef PRINT_PARAMS
+
+static const char kPropDelimeter = ' '; // ':'
+
+static void AddPropName(AString &s, const char *name)
+{
+ if (!s.IsEmpty())
+ s += kPropDelimeter;
+ s += name;
+}
+
+static void AddProp(AString &s, const char *name, unsigned v)
+{
+ AddPropName(s, name);
+ s.Add_UInt32(v);
+}
+
+static void AddProp_switch(AString &s, const char *name, E_ZSTD_paramSwitch_e e)
+{
+ AddPropName(s, name);
+ s += e == k_ZSTD_ps_enable ? "" : "-";
+}
+
+static void PrintPropAsLog(AString &s, const char *name, size_t v)
+{
+ AddPropName(s, name);
+ for (unsigned i = 0; i < sizeof(size_t) * 8; i++)
+ {
+ if (((size_t)1 << i) == v)
+ {
+ s.Add_UInt32(i);
+ return;
+ }
+ }
+ char c = 'b';
+ if ((v & 0x3FFFFFFF) == 0) { v >>= 30; c = 'G'; }
+ else if ((v & 0xFFFFF) == 0) { v >>= 20; c = 'M'; }
+ else if ((v & 0x3FF) == 0) { v >>= 10; c = 'K'; }
+ s.Add_UInt64(v);
+ s += c;
+}
+
+static void ZstdEncProps_Print(CZstdEncProps *props, AString &s)
+{
+ if (props->level_zstd >= 0)
+ AddProp(s, "zx", props->level_zstd);
+ else
+ AddProp(s, "zf", -(props->level_zstd));
+ AddProp(s, "a", props->strategy);
+ AddProp(s, "d", props->windowLog);
+ AddProp(s, "zclog", props->chainLog);
+ AddProp(s, "zhb", props->hashLog);
+ AddProp(s, "mml", props->minMatch);
+ AddProp(s, "mcb", props->searchLog);
+ AddProp(s, "fb", props->targetLength);
+ AddProp(s, "mt", props->nbWorkers);
+ PrintPropAsLog(s, "c", props->jobSize);
+ AddProp(s, "zov", props->overlapLog);
+ PrintPropAsLog(s, "ztps", props->targetPrefixSize);
+ AddProp_switch(s, "zmfr", props->useRowMatchFinder);
+ if (props->ldmParams.enableLdm == k_ZSTD_ps_enable)
+ {
+ AddProp_switch(s, "zle", props->ldmParams.enableLdm);
+ AddProp(s, "zlhb", props->ldmParams.hashLog);
+ AddProp(s, "zlbb", props->ldmParams.bucketSizeLog);
+ AddProp(s, "zlmml", props->ldmParams.minMatchLength);
+ AddProp(s, "zlhrb", props->ldmParams.hashRateLog);
+ }
+}
+
+void CCompressDialog::Print_Params()
+{
+ {
+ CZstdEncProps props;
+ ZstdEncProps_Init(&props);
+ // props.level_zstd = level;
+ props.level_7z = GetLevel2();
+ ZstdEncProps_SetDictProps_From_CompressDialog(&props, *this);
+ {
+ UInt32 order = GetOrderSpec();
+ if (order != (UInt32)(Int32)-1)
+ props.targetLength = GetOrderSpec();
+ }
+ props.nbWorkers = GetNumThreads2();
+ // props.windowLog = 18; // for debug
+ ZstdEncProps_NormalizeFull(&props);
+ AString s;
+ ZstdEncProps_Print(&props, s);
+ SetItemTextA(IDT_COMPRESS_PARAMS_INFO, s);
+ }
+}
+
+#endif // PRINT_PARAMS
+
+
+
+void CCompressDialog::SetParams()
+{
+ const CArcInfoEx &ai = Get_ArcInfoEx();
+ m_Params.SetText(TEXT(""));
+ const int index = FindRegistryFormat(ai.Name);
+ if (index >= 0)
+ {
+ const NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
+ m_Params.SetText(fo.Options);
+ }
+}
+
+void CCompressDialog::SaveOptionsInMem()
+{
+ /* these options are for (Info.FormatIndex).
+ If it's called just after format changing,
+ then it's format that was selected before format changing
+ So we store previous format properties */
+
+ m_Params.GetText(Info.Options);
+ Info.Options.Trim();
+
+ const CArcInfoEx &ai = (*ArcFormats)[Info.FormatIndex];
+ const unsigned index = FindRegistryFormat_Always(ai.Name);
+ NCompression::CFormatOptions &fo = m_RegistryInfo.Formats[index];
+ fo.Options = Info.Options;
+ fo.Level = GetLevelSpec();
+ {
+ const UInt64 dict64 = GetDictSpec();
+ UInt32 dict32;
+ if (dict64 == (UInt64)(Int64)-1)
+ dict32 = (UInt32)(Int32)-1;
+ else
+ {
+ dict32 = (UInt32)dict64;
+ if (dict64 != dict32)
+ {
+ /* here we must write 32-bit value for registry that indicates big_value
+ (UInt32)(Int32)-1 : is used as marker for default size
+ (UInt32)(Int32)-2 : it can be used to indicate big value (4 GiB)
+ the value must be larger than threshold
+ */
+ dict32 = (UInt32)(Int32)-2;
+ // dict32 = kLzmaMaxDictSize; // it must be larger than threshold
+ }
+ }
+ fo.Dictionary = dict32;
+ }
+ /*
+ {
+ const UInt64 dict64 = GetDictChainSpec();
+ UInt32 dict32;
+ if (dict64 == (UInt64)(Int64)-1)
+ dict32 = (UInt32)(Int32)-1;
+ else
+ {
+ dict32 = (UInt32)dict64;
+ if (dict64 != dict32)
+ {
+ dict32 = (UInt32)(Int32)-2;
+ // dict32 = k_Zstd_MAX_DictSize; // it must be larger than threshold
+ }
+ }
+ fo.DictionaryChain = dict32;
+ }
+ */
+
+ fo.Order = GetOrderSpec();
+ fo.Method = GetMethodSpec();
+ fo.EncryptionMethod = GetEncryptionMethodSpec();
+ fo.NumThreads = GetNumThreadsSpec();
+ fo.BlockLogSize = GetBlockSizeSpec();
+ fo.MemUse = Get_MemUse_Spec();
+}
+
+
+unsigned CCompressDialog::GetFormatIndex()
+{
+ return (unsigned)m_Format.GetItemData_of_CurSel();
+}
+
+
+
+static void AddText_from_BoolPair(AString &s, const char *name, const CBoolPair &bp)
+{
+ if (bp.Def)
+ {
+ s.Add_OptSpaced(name);
+ if (!bp.Val)
+ s += "-";
+ }
+ /*
+ else if (bp.Val)
+ {
+ s.Add_OptSpaced("[");
+ s += name;
+ s += "]";
+ }
+ */
+}
+
+
+static void AddText_from_Bool1(AString &s, const char *name, const CBool1 &b)
+{
+ if (b.Supported && b.Val)
+ s.Add_OptSpaced(name);
+}
+
+
+void CCompressDialog::ShowOptionsString()
+{
+ NCompression::CFormatOptions &fo = Get_FormatOptions();
+
+ AString s;
+ if (fo.IsSet_TimePrec())
+ {
+ s.Add_OptSpaced("tp");
+ s.Add_UInt32(fo.TimePrec);
+ }
+ AddText_from_BoolPair(s, "tm", fo.MTime);
+ AddText_from_BoolPair(s, "tc", fo.CTime);
+ AddText_from_BoolPair(s, "ta", fo.ATime);
+ AddText_from_BoolPair(s, "-stl", fo.SetArcMTime);
+
+ // const CArcInfoEx &ai = Get_ArcInfoEx();
+ AddText_from_Bool1(s, "SL", SymLinks);
+ AddText_from_Bool1(s, "HL", HardLinks);
+ AddText_from_Bool1(s, "AS", AltStreams);
+ AddText_from_Bool1(s, "Sec", NtSecurity);
+
+ // AddText_from_Bool1(s, "Preserve", PreserveATime);
+
+ SetItemText(IDT_COMPRESS_OPTIONS, GetUnicodeString(s));
+}
+
+
+
+
+
+// ---------- OPTIONS ----------
+
+
+void COptionsDialog::CheckButton_Bool1(UINT id, const CBool1 &b1)
+{
+ CheckButton(id, b1.Val);
+}
+
+void COptionsDialog::GetButton_Bool1(UINT id, CBool1 &b1)
+{
+ b1.Val = IsButtonCheckedBool(id);
+}
+
+
+void COptionsDialog::CheckButton_BoolBox(
+ bool supported, const CBoolPair &b2, CBoolBox &bb)
+{
+ const bool isSet = b2.Def;
+ const bool val = isSet ? b2.Val : bb.DefaultVal;
+
+ bb.IsSupported = supported;
+
+ CheckButton (bb.Set_Id, isSet);
+ ShowItem_Bool (bb.Set_Id, supported);
+ CheckButton (bb.Id, val);
+ EnableItem (bb.Id, isSet);
+ ShowItem_Bool (bb.Id, supported);
+}
+
+void COptionsDialog::GetButton_BoolBox(CBoolBox &bb)
+{
+ // we save value for invisible buttons too
+ bb.BoolPair.Val = IsButtonCheckedBool (bb.Id);
+ bb.BoolPair.Def = IsButtonCheckedBool (bb.Set_Id);
+}
+
+
+void COptionsDialog::Store_TimeBoxes()
+{
+ TimePrec = GetPrecSpec();
+ GetButton_BoolBox (MTime);
+ GetButton_BoolBox (CTime);
+ GetButton_BoolBox (ATime);
+ GetButton_BoolBox (ZTime);
+}
+
+
+UInt32 COptionsDialog::GetComboValue(NWindows::NControl::CComboBox &c, int defMax)
+{
+ if (c.GetCount() <= defMax)
+ return (UInt32)(Int32)-1;
+ return (UInt32)c.GetItemData_of_CurSel();
+}
+
+static const unsigned kTimePrec_Win = 0;
+static const unsigned kTimePrec_Unix = 1;
+static const unsigned kTimePrec_DOS = 2;
+static const unsigned kTimePrec_1ns = 3;
+
+static void AddTimeOption(UString &s, UInt32 val, const UString &unit, const char *sys = NULL)
+{
+ // s += " : ";
+ {
+ AString s2;
+ s2.Add_UInt32(val);
+ s += s2;
+ }
+ s.Add_Space();
+ s += unit;
+ if (sys)
+ {
+ s += " : ";
+ s += sys;
+ }
+}
+
+int COptionsDialog::AddPrec(unsigned prec, bool isDefault)
+{
+ UString s;
+ UInt32 writePrec = prec;
+ if (isDefault)
+ {
+ // s += "* ";
+ // writePrec = (UInt32)(Int32)-1;
+ }
+ if (prec == kTimePrec_Win) AddTimeOption(s, 100, NsString, "Windows");
+ else if (prec == kTimePrec_Unix) AddTimeOption(s, 1, SecString, "Unix");
+ else if (prec == kTimePrec_DOS) AddTimeOption(s, 2, SecString, "DOS");
+ else if (prec == kTimePrec_1ns) AddTimeOption(s, 1, NsString, "Linux");
+ else if (prec == k_PropVar_TimePrec_Base) AddTimeOption(s, 1, SecString);
+ else if (prec >= k_PropVar_TimePrec_Base)
+ {
+ UInt32 d = 1;
+ for (unsigned i = prec; i < k_PropVar_TimePrec_Base + 9; i++)
+ d *= 10;
+ AddTimeOption(s, d, NsString);
+ }
+ else
+ s.Add_UInt32(prec);
+ const int index = (int)m_Prec.AddString(s);
+ m_Prec.SetItemData(index, (LPARAM)writePrec);
+ return index;
+}
+
+
+void COptionsDialog::SetPrec()
+{
+ // const CFormatInfo &fi = g_Formats[cd->GetStaticFormatIndex()];
+ const CArcInfoEx &ai = cd->Get_ArcInfoEx();
+
+ // UInt32 flags = fi.Flags;
+
+ UInt32 flags = ai.Get_TimePrecFlags();
+ UInt32 defaultPrec = ai.Get_DefaultTimePrec();
+ if (defaultPrec != 0)
+ flags |= ((UInt32)1 << defaultPrec);
+
+ // const NCompression::CFormatOptions &fo = cd->Get_FormatOptions();
+
+ // unsigned defaultPrec = kTimePrec_Win;
+
+ if (ai.Is_GZip())
+ defaultPrec = kTimePrec_Unix;
+
+ {
+ UString s;
+ s += GetNameOfProperty(kpidType, L"type");
+ s += ": ";
+ s += ai.Name;
+ if (ai.Is_Tar())
+ {
+ const int methodID = cd->GetMethodID();
+
+ // for debug
+ // defaultPrec = kTimePrec_Unix;
+ // flags = (UInt32)1 << kTimePrec_Unix;
+
+ s += ":";
+ if (methodID >= 0 && (unsigned)methodID < Z7_ARRAY_SIZE(kMethodsNames))
+ s += kMethodsNames[methodID];
+ if (methodID == kPosix)
+ {
+ // for debug
+ // flags |= (UInt32)1 << kTimePrec_Win;
+ // flags |= (UInt32)1 << kTimePrec_1ns;
+ }
+ }
+ else
+ {
+ // if (is_for_MethodChanging) return;
+ }
+
+ SetItemText(IDT_COMPRESS_TIME_INFO, s);
+ }
+
+ m_Prec.ResetContent();
+ _auto_Prec = defaultPrec;
+
+ unsigned selectedPrec = defaultPrec;
+ {
+ // if (TimePrec >= kTimePrec_Win && TimePrec <= kTimePrec_DOS)
+ if ((Int32)TimePrec >= 0)
+ selectedPrec = TimePrec;
+ }
+
+ int curSel = -1;
+ int defaultPrecIndex = -1;
+ for (unsigned prec = 0;
+ // prec <= k_PropVar_TimePrec_HighPrec;
+ prec <= k_PropVar_TimePrec_1ns;
+ prec++)
+ {
+ if (((flags >> prec) & 1) == 0)
+ continue;
+ const bool isDefault = (defaultPrec == prec);
+ const int index = AddPrec(prec, isDefault);
+ if (isDefault)
+ defaultPrecIndex = index;
+ if (selectedPrec == prec)
+ curSel = index;
+ }
+
+ if (curSel < 0 && selectedPrec > kTimePrec_DOS)
+ curSel = AddPrec(selectedPrec, false); // isDefault
+ if (curSel < 0)
+ curSel = defaultPrecIndex;
+ if (curSel >= 0)
+ m_Prec.SetCurSel(curSel);
+
+ {
+ const bool isSet = IsSet_TimePrec();
+ const int count = m_Prec.GetCount();
+ const bool showPrec = (count != 0);
+ ShowItem_Bool(IDC_COMPRESS_TIME_PREC, showPrec);
+ ShowItem_Bool(IDT_COMPRESS_TIME_PREC, showPrec);
+ EnableItem(IDC_COMPRESS_TIME_PREC, isSet && (count > 1));
+
+ CheckButton(IDX_COMPRESS_PREC_SET, isSet);
+ const bool setIsSupported = isSet || (count > 1);
+ EnableItem(IDX_COMPRESS_PREC_SET, setIsSupported);
+ ShowItem_Bool(IDX_COMPRESS_PREC_SET, setIsSupported);
+ }
+
+ SetTimeMAC();
+}
+
+
+void COptionsDialog::SetTimeMAC()
+{
+ const CArcInfoEx &ai = cd->Get_ArcInfoEx();
+
+ const
+ bool m_allow = ai.Flags_MTime();
+ bool c_allow = ai.Flags_CTime();
+ bool a_allow = ai.Flags_ATime();
+
+ if (ai.Is_Tar())
+ {
+ const int methodID = cd->GetMethodID();
+ c_allow = false;
+ a_allow = false;
+ if (methodID == kPosix)
+ {
+ // c_allow = true; // do we need it as change time ?
+ a_allow = true;
+ }
+ }
+
+ if (ai.Is_Zip())
+ {
+ // const int methodID = GetMethodID();
+ UInt32 prec = GetPrec();
+ if (prec == (UInt32)(Int32)-1)
+ prec = _auto_Prec;
+ if (prec != kTimePrec_Win)
+ {
+ c_allow = false;
+ a_allow = false;
+ }
+ }
+
+
+ /*
+ MTime.DefaultVal = true;
+ CTime.DefaultVal = false;
+ ATime.DefaultVal = false;
+ */
+
+ MTime.DefaultVal = ai.Flags_MTime_Default();
+ CTime.DefaultVal = ai.Flags_CTime_Default();
+ ATime.DefaultVal = ai.Flags_ATime_Default();
+
+ ZTime.DefaultVal = false;
+
+ const NCompression::CFormatOptions &fo = cd->Get_FormatOptions();
+
+ CheckButton_BoolBox (m_allow, fo.MTime, MTime );
+ CheckButton_BoolBox (c_allow, fo.CTime, CTime );
+ CheckButton_BoolBox (a_allow, fo.ATime, ATime );
+ CheckButton_BoolBox (true, fo.SetArcMTime, ZTime);
+
+ if (m_allow && !fo.MTime.Def)
+ {
+ const bool isSingleFile = ai.Flags_KeepName();
+ if (!isSingleFile)
+ {
+ // we can hide changing checkboxes for MTime here:
+ ShowItem_Bool (MTime.Set_Id, false);
+ EnableItem (MTime.Id, false);
+ }
+ }
+ // On_CheckBoxSet_Prec_Clicked();
+ // const bool isSingleFile = ai.Flags_KeepName();
+ // mtime for Gz can be
+}
+
+
+
+void COptionsDialog::On_CheckBoxSet_Prec_Clicked()
+{
+ const bool isSet = IsButtonCheckedBool(IDX_COMPRESS_PREC_SET);
+ if (!isSet)
+ {
+ // We save current MAC boxes to memory before SetPrec()
+ Store_TimeBoxes();
+ Reset_TimePrec();
+ SetPrec();
+ }
+ EnableItem(IDC_COMPRESS_TIME_PREC, isSet);
+}
+
+void COptionsDialog::On_CheckBoxSet_Clicked(const CBoolBox &bb)
+{
+ const bool isSet = IsButtonCheckedBool(bb.Set_Id);
+ if (!isSet)
+ CheckButton(bb.Id, bb.DefaultVal);
+ EnableItem(bb.Id, isSet);
+}
+
+
+
+
+#ifdef Z7_LANG
+static const UInt32 kLangIDs_Options[] =
+{
+ IDX_COMPRESS_NT_SYM_LINKS,
+ IDX_COMPRESS_NT_HARD_LINKS,
+ IDX_COMPRESS_NT_ALT_STREAMS,
+ IDX_COMPRESS_NT_SECUR,
+
+ IDG_COMPRESS_TIME,
+ IDT_COMPRESS_TIME_PREC,
+ IDX_COMPRESS_MTIME,
+ IDX_COMPRESS_CTIME,
+ IDX_COMPRESS_ATIME,
+ IDX_COMPRESS_ZTIME,
+ IDX_COMPRESS_PRESERVE_ATIME
+};
+#endif
+
+
+bool COptionsDialog::OnInit()
+{
+ #ifdef Z7_LANG
+ LangSetWindowText(*this, IDB_COMPRESS_OPTIONS); // IDS_OPTIONS
+ LangSetDlgItems(*this, kLangIDs_Options, Z7_ARRAY_SIZE(kLangIDs_Options));
+ // LangSetDlgItemText(*this, IDB_COMPRESS_TIME_DEFAULT, IDB_COMPRESS_TIME_DEFAULT);
+ // LangSetDlgItemText(*this, IDX_COMPRESS_TIME_DEFAULT, IDX_COMPRESS_TIME_DEFAULT);
+ #endif
+
+ LangString(IDS_COMPRESS_SEC, SecString);
+ if (SecString.IsEmpty())
+ SecString = "sec";
+ LangString(IDS_COMPRESS_NS, NsString);
+ if (NsString.IsEmpty())
+ NsString = "ns";
+
+ {
+ // const CArcInfoEx &ai = cd->Get_ArcInfoEx();
+
+ ShowItem_Bool ( IDX_COMPRESS_NT_SYM_LINKS, cd->SymLinks.Supported);
+ ShowItem_Bool ( IDX_COMPRESS_NT_HARD_LINKS, cd->HardLinks.Supported);
+ ShowItem_Bool ( IDX_COMPRESS_NT_ALT_STREAMS, cd->AltStreams.Supported);
+ ShowItem_Bool ( IDX_COMPRESS_NT_SECUR, cd->NtSecurity.Supported);
+
+ ShowItem_Bool ( IDG_COMPRESS_NTFS,
+ cd->SymLinks.Supported
+ || cd->HardLinks.Supported
+ || cd->AltStreams.Supported
+ || cd->NtSecurity.Supported);
+ }
+
+ /* we read property from two sources:
+ 1) command line : (Info)
+ 2) registry : (m_RegistryInfo)
+ (Info) has priority, if both are no defined */
+
+ CheckButton_Bool1 ( IDX_COMPRESS_NT_SYM_LINKS, cd->SymLinks);
+ CheckButton_Bool1 ( IDX_COMPRESS_NT_HARD_LINKS, cd->HardLinks);
+ CheckButton_Bool1 ( IDX_COMPRESS_NT_ALT_STREAMS, cd->AltStreams);
+ CheckButton_Bool1 ( IDX_COMPRESS_NT_SECUR, cd->NtSecurity);
+
+ CheckButton_Bool1 (IDX_COMPRESS_PRESERVE_ATIME, cd->PreserveATime);
+
+ m_Prec.Attach (GetItem(IDC_COMPRESS_TIME_PREC));
+
+ MTime.SetIDs ( IDX_COMPRESS_MTIME, IDX_COMPRESS_MTIME_SET);
+ CTime.SetIDs ( IDX_COMPRESS_CTIME, IDX_COMPRESS_CTIME_SET);
+ ATime.SetIDs ( IDX_COMPRESS_ATIME, IDX_COMPRESS_ATIME_SET);
+ ZTime.SetIDs ( IDX_COMPRESS_ZTIME, IDX_COMPRESS_ZTIME_SET);
+
+ {
+ const NCompression::CFormatOptions &fo = cd->Get_FormatOptions();
+ TimePrec = fo.TimePrec;
+ MTime.BoolPair = fo.MTime;
+ CTime.BoolPair = fo.CTime;
+ ATime.BoolPair = fo.ATime;
+ ZTime.BoolPair = fo.SetArcMTime;
+ }
+
+ SetPrec();
+
+ NormalizePosition();
+
+ return CModalDialog::OnInit();
+}
+
+
+bool COptionsDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam)
+{
+ if (code == CBN_SELCHANGE)
+ {
+ switch (itemID)
+ {
+ case IDC_COMPRESS_TIME_PREC:
+ {
+ Store_TimeBoxes();
+ SetTimeMAC(); // for zip/tar
+ return true;
+ }
+ }
+ }
+ return CModalDialog::OnCommand(code, itemID, lParam);
+}
+
+
+bool COptionsDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ switch (buttonID)
+ {
+ case IDX_COMPRESS_PREC_SET: { On_CheckBoxSet_Prec_Clicked(); return true; }
+ case IDX_COMPRESS_MTIME_SET: { On_CheckBoxSet_Clicked (MTime); return true; }
+ case IDX_COMPRESS_CTIME_SET: { On_CheckBoxSet_Clicked (CTime); return true; }
+ case IDX_COMPRESS_ATIME_SET: { On_CheckBoxSet_Clicked (ATime); return true; }
+ case IDX_COMPRESS_ZTIME_SET: { On_CheckBoxSet_Clicked (ZTime); return true; }
+ }
+ return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
+}
+
+
+void COptionsDialog::OnOK()
+{
+ GetButton_Bool1 (IDX_COMPRESS_NT_SYM_LINKS, cd->SymLinks);
+ GetButton_Bool1 (IDX_COMPRESS_NT_HARD_LINKS, cd->HardLinks);
+ GetButton_Bool1 (IDX_COMPRESS_NT_ALT_STREAMS, cd->AltStreams);
+ GetButton_Bool1 (IDX_COMPRESS_NT_SECUR, cd->NtSecurity);
+ GetButton_Bool1 (IDX_COMPRESS_PRESERVE_ATIME, cd->PreserveATime);
+
+ Store_TimeBoxes();
+ {
+ NCompression::CFormatOptions &fo = cd->Get_FormatOptions();
+ fo.TimePrec = TimePrec;
+ fo.MTime = MTime.BoolPair;
+ fo.CTime = CTime.BoolPair;
+ fo.ATime = ATime.BoolPair;
+ fo.SetArcMTime = ZTime.BoolPair;
+ }
+
+ CModalDialog::OnOK();
+}
+
+void COptionsDialog::OnHelp()
+{
+ ShowHelpWindow(kHelpTopic_Options);
+}
diff --git a/CPP/7zip/UI/GUI/CompressDialog.h b/CPP/7zip/UI/GUI/CompressDialog.h
new file mode 100644
index 0000000..c2d2699
--- /dev/null
+++ b/CPP/7zip/UI/GUI/CompressDialog.h
@@ -0,0 +1,481 @@
+// CompressDialog.h
+
+#ifndef ZIP7_INC_COMPRESS_DIALOG_H
+#define ZIP7_INC_COMPRESS_DIALOG_H
+
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/Control/ComboBox.h"
+#include "../../../Windows/Control/Edit.h"
+
+#include "../Common/LoadCodecs.h"
+#include "../Common/ZipRegistry.h"
+
+#include "../FileManager/DialogSize.h"
+
+#include "CompressDialogRes.h"
+
+namespace NCompressDialog
+{
+ namespace NUpdateMode
+ {
+ enum EEnum
+ {
+ kAdd,
+ kUpdate,
+ kFresh,
+ kSync
+ };
+ }
+
+ struct CInfo
+ {
+ NUpdateMode::EEnum UpdateMode;
+ NWildcard::ECensorPathMode PathMode;
+
+ bool SolidIsSpecified;
+ // bool MultiThreadIsAllowed;
+ UInt64 SolidBlockSize;
+ UInt32 NumThreads;
+
+ NCompression::CMemUse MemUsage;
+
+ CRecordVector<UInt64> VolumeSizes;
+
+ UInt32 Level;
+ UString Method;
+ UInt64 Dict64;
+ // UInt64 Dict64_Chain;
+ bool OrderMode;
+ UInt32 Order;
+ UString Options;
+
+ UString EncryptionMethod;
+
+ bool SFXMode;
+ bool OpenShareForWrite;
+ bool DeleteAfterCompressing;
+
+ CBoolPair SymLinks;
+ CBoolPair HardLinks;
+ CBoolPair AltStreams;
+ CBoolPair NtSecurity;
+
+ CBoolPair PreserveATime;
+
+ UInt32 TimePrec;
+ CBoolPair MTime;
+ CBoolPair CTime;
+ CBoolPair ATime;
+ CBoolPair SetArcMTime;
+
+ UString ArcPath; // in: Relative or abs ; out: Relative or abs
+
+ // FString CurrentDirPrefix;
+ bool KeepName;
+
+ bool GetFullPathName(UString &result) const;
+
+ int FormatIndex;
+
+ UString Password;
+ bool EncryptHeadersIsAllowed;
+ bool EncryptHeaders;
+
+ CInfo():
+ UpdateMode(NCompressDialog::NUpdateMode::kAdd),
+ PathMode(NWildcard::k_RelatPath),
+ SFXMode(false),
+ OpenShareForWrite(false),
+ DeleteAfterCompressing(false),
+ FormatIndex(-1)
+ {
+ Level = Order = (UInt32)(Int32)-1;
+ NumThreads = (UInt32)(Int32)-1;
+ SolidIsSpecified = false;
+ Dict64 = (UInt64)(Int64)(-1);
+ // Dict64_Chain = (UInt64)(Int64)(-1);
+ OrderMode = false;
+ Method.Empty();
+ Options.Empty();
+ EncryptionMethod.Empty();
+ TimePrec = (UInt32)(Int32)(-1);
+ }
+ };
+}
+
+
+struct CBool1
+{
+ bool Val;
+ bool Supported;
+
+ CBool1(): Val(false), Supported(false) {}
+
+ void Init()
+ {
+ Val = false;
+ Supported = false;
+ }
+
+ void SetTrueTrue()
+ {
+ Val = true;
+ Supported = true;
+ }
+
+ void SetVal_as_Supported(bool val)
+ {
+ Val = val;
+ Supported = true;
+ }
+
+ /*
+ bool IsVal_True_and_Defined() const
+ {
+ return Def && Val;
+ }
+ */
+};
+
+
+class CCompressDialog: public NWindows::NControl::CModalDialog
+{
+ NWindows::NControl::CComboBox m_ArchivePath;
+ NWindows::NControl::CComboBox m_Format;
+ NWindows::NControl::CComboBox m_Level;
+ NWindows::NControl::CComboBox m_Method;
+ NWindows::NControl::CComboBox m_Dictionary;
+ // NWindows::NControl::CComboBox m_Dictionary_Chain;
+ NWindows::NControl::CComboBox m_Order;
+ NWindows::NControl::CComboBox m_Solid;
+ NWindows::NControl::CComboBox m_NumThreads;
+ NWindows::NControl::CComboBox m_MemUse;
+ NWindows::NControl::CComboBox m_Volume;
+
+ int _dictionaryCombo_left;
+
+ UStringVector _memUse_Strings;
+
+ NWindows::NControl::CDialogChildControl m_Params;
+
+ NWindows::NControl::CComboBox m_UpdateMode;
+ NWindows::NControl::CComboBox m_PathMode;
+
+ NWindows::NControl::CEdit _password1Control;
+ NWindows::NControl::CEdit _password2Control;
+ NWindows::NControl::CComboBox _encryptionMethod;
+
+ int _auto_MethodId;
+ UInt32 _auto_Dict; // (UInt32)(Int32)-1 means unknown
+ UInt32 _auto_Dict_Chain; // (UInt32)(Int32)-1 means unknown
+ UInt32 _auto_Order;
+ UInt64 _auto_Solid;
+ UInt32 _auto_NumThreads;
+
+ int _default_encryptionMethod_Index;
+
+ int m_PrevFormat;
+ UString DirPrefix;
+ UString StartDirPrefix;
+
+ bool _ramSize_Defined;
+ UInt64 _ramSize; // full RAM size avail
+ UInt64 _ramSize_Reduced; // full for 64-bit and reduced for 32-bit
+ UInt64 _ramUsage_Auto;
+
+public:
+ NCompression::CInfo m_RegistryInfo;
+
+ CBool1 SymLinks;
+ CBool1 HardLinks;
+ CBool1 AltStreams;
+ CBool1 NtSecurity;
+ CBool1 PreserveATime;
+
+ void SetArchiveName(const UString &name);
+ int FindRegistryFormat(const UString &name);
+ unsigned FindRegistryFormat_Always(const UString &name);
+
+ const CArcInfoEx &Get_ArcInfoEx()
+ {
+ return (*ArcFormats)[GetFormatIndex()];
+ }
+
+ NCompression::CFormatOptions &Get_FormatOptions();
+
+ void CheckSFXNameChange();
+ void SetArchiveName2(bool prevWasSFX);
+
+ unsigned GetStaticFormatIndex();
+
+ void SetNearestSelectComboBox(NWindows::NControl::CComboBox &comboBox, UInt32 value);
+
+ void SetLevel2();
+ void SetLevel()
+ {
+ SetLevel2();
+ EnableMultiCombo(IDC_COMPRESS_LEVEL);
+ SetMethod();
+ }
+
+ void SetMethod2(int keepMethodId);
+ void SetMethod(int keepMethodId = -1)
+ {
+ SetMethod2(keepMethodId);
+ EnableMultiCombo(IDC_COMPRESS_METHOD);
+ }
+
+ void MethodChanged()
+ {
+ SetDictionary2();
+ EnableMultiCombo(IDC_COMPRESS_DICTIONARY);
+ // EnableMultiCombo(IDC_COMPRESS_DICTIONARY2);
+ SetOrder2();
+ EnableMultiCombo(IDC_COMPRESS_ORDER);
+ }
+
+ int GetMethodID_RAW();
+ int GetMethodID();
+
+ UString GetMethodSpec(UString &estimatedName);
+ UString GetMethodSpec();
+ bool IsMethodEqualTo(const UString &s);
+ UString GetEncryptionMethodSpec();
+
+ bool IsZipFormat();
+ bool IsXzFormat();
+
+ void SetEncryptionMethod();
+
+ int AddDict2(size_t sizeReal, size_t sizeShow);
+ int AddDict(size_t size);
+ // int AddDict_Chain(size_t size);
+
+ void SetDictionary2();
+
+ UInt32 GetComboValue(NWindows::NControl::CComboBox &c, int defMax = 0);
+ UInt64 GetComboValue_64(NWindows::NControl::CComboBox &c, int defMax = 0);
+
+ UInt32 GetLevel() { return GetComboValue(m_Level); }
+ UInt32 GetLevelSpec() { return GetComboValue(m_Level, 1); }
+ UInt32 GetLevel2();
+
+ UInt64 GetDictSpec() { return GetComboValue_64(m_Dictionary, 1); }
+ // UInt64 GetDictChainSpec() { return GetComboValue_64(m_Dictionary_Chain, 1); }
+
+ UInt64 GetDict2()
+ {
+ UInt64 num = GetDictSpec();
+ if (num == (UInt64)(Int64)-1)
+ {
+ if (_auto_Dict == (UInt32)(Int32)-1)
+ return (UInt64)(Int64)-1; // unknown
+ num = _auto_Dict;
+ }
+ return num;
+ }
+
+ // UInt32 GetOrder() { return GetComboValue(m_Order); }
+ UInt32 GetOrderSpec() { return GetComboValue(m_Order, 1); }
+ UInt32 GetNumThreadsSpec() { return GetComboValue(m_NumThreads, 1); }
+
+ UInt32 GetNumThreads2()
+ {
+ UInt32 num = GetNumThreadsSpec();
+ if (num == (UInt32)(Int32)-1)
+ num = _auto_NumThreads;
+ return num;
+ }
+
+ UInt32 GetBlockSizeSpec() { return GetComboValue(m_Solid, 1); }
+
+ /*
+ UInt32 GetPrecSpec() { return GetComboValue(m_Prec, 1); }
+ UInt32 GetPrec() { return GetComboValue(m_Prec, 0); }
+ */
+
+
+ int AddOrder(UInt32 size);
+ int AddOrder_Auto();
+
+ void SetOrder2();
+
+ bool GetOrderMode();
+
+ void SetSolidBlockSize2();
+ void SetSolidBlockSize(/* bool useDictionary = false */)
+ {
+ SetSolidBlockSize2();
+ EnableMultiCombo(IDC_COMPRESS_SOLID);
+ }
+
+ void SetNumThreads2();
+ void SetNumThreads()
+ {
+ SetNumThreads2();
+ EnableMultiCombo(IDC_COMPRESS_THREADS);
+ }
+
+ int AddMemComboItem(UInt64 val, bool isPercent = false, bool isDefault = false);
+ void SetMemUseCombo();
+ UString Get_MemUse_Spec();
+ UInt64 Get_MemUse_Bytes();
+
+ UInt64 GetMemoryUsage_Dict_DecompMem(UInt64 dict, UInt64 &decompressMemory);
+ UInt64 GetMemoryUsage_Threads_Dict_DecompMem(UInt32 numThreads, UInt64 dict, UInt64 &decompressMemory);
+ UInt64 GetMemoryUsage_DecompMem(UInt64 &decompressMemory);
+ UInt64 GetMemoryUsageComp_Threads_Dict(UInt32 numThreads, UInt64 dict64);
+
+ void PrintMemUsage(UINT res, UInt64 value);
+ void SetMemoryUsage();
+ void Print_Params();
+
+ void SetParams();
+
+ void SaveOptionsInMem();
+
+ void UpdatePasswordControl();
+ bool IsShowPasswordChecked() const { return IsButtonCheckedBool(IDX_PASSWORD_SHOW); }
+
+ unsigned GetFormatIndex();
+ bool SetArcPathFields(const UString &path, UString &name, bool always);
+ bool SetArcPathFields(const UString &path);
+ bool GetFinalPath_Smart(UString &resPath) const;
+ void ArcPath_WasChanged(const UString &newPath);
+
+ void CheckSFXControlsEnable();
+ // void CheckVolumeEnable();
+ void EnableMultiCombo(unsigned id);
+ void FormatChanged(bool isChanged);
+
+ void OnButtonSetArchive();
+ bool IsSFX();
+ void OnButtonSFX();
+
+ virtual bool OnInit() Z7_override;
+ virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam) Z7_override;
+ virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override;
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+ virtual void OnOK() Z7_override;
+ virtual void OnHelp() Z7_override;
+
+ void MessageBoxError(LPCWSTR message)
+ {
+ MessageBoxW(*this, message, L"7-Zip", MB_ICONERROR);
+ }
+
+ void ShowOptionsString();
+
+public:
+ const CObjectVector<CArcInfoEx> *ArcFormats;
+ CUIntVector ArcIndices; // can not be empty, must contain Info.FormatIndex, if Info.FormatIndex >= 0
+ AStringVector ExternalMethods;
+
+ void SetMethods(const CObjectVector<CCodecInfoUser> &userCodecs);
+
+ NCompressDialog::CInfo Info;
+ UString OriginalFileName; // for bzip2, gzip2
+
+ INT_PTR Create(HWND wndParent = NULL)
+ {
+ BIG_DIALOG_SIZE(400, 320);
+ return CModalDialog::Create(SIZED_DIALOG(IDD_COMPRESS), wndParent);
+ }
+
+ CCompressDialog() {}
+};
+
+
+
+
+class COptionsDialog: public NWindows::NControl::CModalDialog
+{
+ struct CBoolBox
+ {
+ bool IsSupported;
+ bool DefaultVal;
+ CBoolPair BoolPair;
+
+ unsigned Id;
+ unsigned Set_Id;
+
+ void SetIDs(unsigned id, unsigned set_Id)
+ {
+ Id = id;
+ Set_Id = set_Id;
+ }
+
+ CBoolBox():
+ IsSupported(false),
+ DefaultVal(false)
+ {}
+ };
+
+ CCompressDialog *cd;
+
+ NWindows::NControl::CComboBox m_Prec;
+
+ UInt32 _auto_Prec;
+ UInt32 TimePrec;
+
+ void Reset_TimePrec() { TimePrec = (UInt32)(Int32)-1; }
+ bool IsSet_TimePrec() const { return TimePrec != (UInt32)(Int32)-1; }
+
+ CBoolBox MTime;
+ CBoolBox CTime;
+ CBoolBox ATime;
+ CBoolBox ZTime;
+
+ UString SecString;
+ UString NsString;
+
+
+ void CheckButton_Bool1(UINT id, const CBool1 &b1);
+ void GetButton_Bool1(UINT id, CBool1 &b1);
+ void CheckButton_BoolBox(bool supported, const CBoolPair &b2, CBoolBox &bb);
+ void GetButton_BoolBox(CBoolBox &bb);
+
+ void Store_TimeBoxes();
+
+ UInt32 GetComboValue(NWindows::NControl::CComboBox &c, int defMax = 0);
+ UInt32 GetPrecSpec()
+ {
+ UInt32 prec = GetComboValue(m_Prec, 1);
+ if (prec == _auto_Prec)
+ prec = (UInt32)(Int32)-1;
+ return prec;
+ }
+ UInt32 GetPrec() { return GetComboValue(m_Prec, 0); }
+
+ // void OnButton_TimeDefault();
+ int AddPrec(unsigned prec, bool isDefault);
+ void SetPrec();
+ void SetTimeMAC();
+
+ void On_CheckBoxSet_Prec_Clicked();
+ void On_CheckBoxSet_Clicked(const CBoolBox &bb);
+
+ virtual bool OnInit() Z7_override;
+ virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam) Z7_override;
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+ virtual void OnOK() Z7_override;
+ virtual void OnHelp() Z7_override;
+
+public:
+
+ INT_PTR Create(HWND wndParent = NULL)
+ {
+ BIG_DIALOG_SIZE(240, 232);
+ return CModalDialog::Create(SIZED_DIALOG(IDD_COMPRESS_OPTIONS), wndParent);
+ }
+
+ COptionsDialog(CCompressDialog *cdLoc):
+ cd(cdLoc)
+ // , TimePrec(0)
+ {
+ Reset_TimePrec();
+ }
+};
+
+#endif
diff --git a/CPP/7zip/UI/GUI/CompressDialog.rc b/CPP/7zip/UI/GUI/CompressDialog.rc
new file mode 100644
index 0000000..f04329e
--- /dev/null
+++ b/CPP/7zip/UI/GUI/CompressDialog.rc
@@ -0,0 +1,231 @@
+#include "CompressDialogRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 400
+#define yc 320
+
+#undef gSize
+#undef gSpace
+#undef g0xs
+#undef g1x
+#undef g1xs
+#undef g2xs
+#undef g3x
+#undef g3xs
+#undef g4x
+#undef g4x2
+#undef g4xs
+#undef g4xs2
+
+#define gSize 192
+#define gSpace 24
+
+
+#define g1xs 88
+#define g0xs (gSize - g1xs)
+#define g1x (m + g0xs)
+
+#define g3xs 52
+#define g2xs (gSize - g3xs)
+#define g3x (m + g2xs)
+
+#define g4x (m + gSize + gSpace)
+#define g4x2 (g4x + m)
+#define g4xs (xc - gSize - gSpace)
+#define g4xs2 (g4xs - m - m)
+
+#define yOpt 80
+
+#define xArcFolderOffs 40
+
+#undef GROUP_Y_SIZE
+#undef GROUP_Y_SIZE_ENCRYPT
+#ifdef UNDER_CE
+#define GROUP_Y_SIZE 8
+#define GROUP_Y_SIZE_ENCRYPT 8
+#else
+#define GROUP_Y_SIZE 64
+#define GROUP_Y_SIZE_ENCRYPT 128
+#endif
+
+// #define DICT_SIZE_SPACE 8
+// #define DICT_SIZE 54
+// #define DICT_x (g1x + g1xs - DICT_SIZE)
+// #define DICT2_x (DICT_x - DICT_SIZE_SPACE - DICT_SIZE)
+
+#define yPsw (yOpt + GROUP_Y_SIZE + 8)
+
+IDD_COMPRESS DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
+CAPTION "Add to Archive"
+BEGIN
+ LTEXT "", IDT_COMPRESS_ARCHIVE_FOLDER, m + xArcFolderOffs, m, xc - xArcFolderOffs, 8
+ LTEXT "&Archive:", IDT_COMPRESS_ARCHIVE, m, 12, xArcFolderOffs, 8
+ COMBOBOX IDC_COMPRESS_ARCHIVE, m + xArcFolderOffs, 18, xc - bxsDots - 12 - xArcFolderOffs, 126, MY_COMBO_WITH_EDIT
+ PUSHBUTTON "...", IDB_COMPRESS_SET_ARCHIVE, xs - m - bxsDots, 16, bxsDots, bys, WS_GROUP
+
+ LTEXT "Archive &format:", IDT_COMPRESS_FORMAT, m, 41, g0xs, 8
+ COMBOBOX IDC_COMPRESS_FORMAT, g1x, 39, g1xs, 80, MY_COMBO | CBS_SORT
+
+ LTEXT "Compression &level:", IDT_COMPRESS_LEVEL, m, 62, g0xs, 8
+ COMBOBOX IDC_COMPRESS_LEVEL, g1x, 60, g1xs, 80, MY_COMBO
+
+ LTEXT "Compression &method:", IDT_COMPRESS_METHOD, m, 83, g0xs, 8
+ COMBOBOX IDC_COMPRESS_METHOD, g1x, 81, g1xs, 80, MY_COMBO
+
+ LTEXT "&Dictionary size:", IDT_COMPRESS_DICTIONARY, m, 104, g0xs, 8
+ COMBOBOX IDC_COMPRESS_DICTIONARY, g1x, 102, g1xs, 167, MY_COMBO
+ // LTEXT "&Dictionary size:", IDT_COMPRESS_DICTIONARY, m, 104, DICT_x - m, 16 // 8, SS_LEFTNOWORDWRAP
+ // LTEXT "", IDT_COMPRESS_PARAMS_INFO, m, 283, xs, MY_TEXT_NOPREFIX
+ // CTEXT "-", 0, DICT_x - DICT_SIZE_SPACE, 104, DICT_SIZE_SPACE, 8
+ // COMBOBOX IDC_COMPRESS_DICTIONARY2, DICT2_x, 102, DICT_SIZE, 140, MY_COMBO
+ // COMBOBOX IDC_COMPRESS_DICTIONARY, DICT_x, 102, DICT_SIZE, 140, MY_COMBO
+
+ LTEXT "&Word size:", IDT_COMPRESS_ORDER, m, 125, g0xs, 8
+ COMBOBOX IDC_COMPRESS_ORDER, g1x, 123, g1xs, 140, MY_COMBO
+
+ LTEXT "&Solid Block size:", IDT_COMPRESS_SOLID, m, 146, g0xs, 8
+ COMBOBOX IDC_COMPRESS_SOLID, g1x, 144, g1xs, 140, MY_COMBO
+
+ LTEXT "Number of CPU &threads:", IDT_COMPRESS_THREADS, m, 167, g0xs, 8
+ COMBOBOX IDC_COMPRESS_THREADS, g1x, 165, g1xs - 35, 140, MY_COMBO
+ RTEXT "", IDT_COMPRESS_HARDWARE_THREADS, g1x + g1xs - 35 + 10, 167, 25, MY_TEXT_NOPREFIX
+
+
+ LTEXT "Memory usage for Compressing:", IDT_COMPRESS_MEMORY, m, 184, g2xs, 8
+ COMBOBOX IDC_COMPRESS_MEM_USE, g3x, 188, g3xs, 140, MY_COMBO
+ LTEXT "", IDT_COMPRESS_MEMORY_VALUE, m, 194, g2xs, MY_TEXT_NOPREFIX
+
+ LTEXT "Memory usage for Decompressing:", IDT_COMPRESS_MEMORY_DE, m, 208, g2xs, 8
+ RTEXT "", IDT_COMPRESS_MEMORY_DE_VALUE, g3x, 208, g3xs, MY_TEXT_NOPREFIX
+
+
+ LTEXT "Split to &volumes, bytes:", IDT_SPLIT_TO_VOLUMES, m, 225, gSize, 8
+ COMBOBOX IDC_COMPRESS_VOLUME, m, 237, gSize, 73, MY_COMBO_WITH_EDIT
+
+ LTEXT "Parameters:", IDT_COMPRESS_PARAMETERS, m, 256, gSize, 8
+ EDITTEXT IDE_COMPRESS_PARAMETERS, m, 268, gSize, 14, ES_AUTOHSCROLL
+
+ PUSHBUTTON "Options", IDB_COMPRESS_OPTIONS, m, 292, bxs, bys
+ LTEXT "", IDT_COMPRESS_OPTIONS, m + bxs + m, 294, gSize - bxs - m, 16, SS_NOPREFIX
+
+
+ LTEXT "&Update mode:", IDT_COMPRESS_UPDATE_MODE, g4x, 41, 80, 8
+ COMBOBOX IDC_COMPRESS_UPDATE_MODE, g4x + 84, 39, g4xs - 84, 80, MY_COMBO
+
+ LTEXT "Path mode:", IDT_COMPRESS_PATH_MODE, g4x, 61, 80, 8
+ COMBOBOX IDC_COMPRESS_PATH_MODE, g4x + 84, 59, g4xs - 84, 80, MY_COMBO
+
+
+ GROUPBOX "Options", IDG_COMPRESS_OPTIONS, g4x, yOpt, g4xs, GROUP_Y_SIZE
+
+ CONTROL "Create SF&X archive", IDX_COMPRESS_SFX, MY_CHECKBOX,
+ g4x2, yOpt + 14, g4xs2, 10
+ CONTROL "Compress shared files", IDX_COMPRESS_SHARED, MY_CHECKBOX,
+ g4x2, yOpt + 30, g4xs2, 10
+ CONTROL "Delete files after compression", IDX_COMPRESS_DEL, MY_CHECKBOX,
+ g4x2, yOpt + 46, g4xs2, 10
+
+
+ GROUPBOX "Encryption", IDG_COMPRESS_ENCRYPTION, g4x, yPsw, g4xs, GROUP_Y_SIZE_ENCRYPT
+
+ LTEXT "Enter &password:", IDT_PASSWORD_ENTER, g4x2, yPsw + 14, g4xs2, 8
+ EDITTEXT IDE_COMPRESS_PASSWORD1, g4x2, yPsw + 26, g4xs2, 14, ES_PASSWORD | ES_AUTOHSCROLL
+ LTEXT "Reenter password:", IDT_PASSWORD_REENTER, g4x2, yPsw + 46, g4xs2, 8
+ EDITTEXT IDE_COMPRESS_PASSWORD2, g4x2, yPsw + 58, g4xs2, 14, ES_PASSWORD | ES_AUTOHSCROLL
+
+ CONTROL "Show Password", IDX_PASSWORD_SHOW, MY_CHECKBOX,
+ g4x2, yPsw + 79, g4xs2, 10
+
+ LTEXT "&Encryption method:", IDT_COMPRESS_ENCRYPTION_METHOD, g4x2, yPsw + 95, 100, 8
+ COMBOBOX IDC_COMPRESS_ENCRYPTION_METHOD, g4x2 + 100, yPsw + 93, g4xs2 - 100, 198, MY_COMBO
+
+ CONTROL "Encrypt file &names", IDX_COMPRESS_ENCRYPT_FILE_NAMES, MY_CHECKBOX,
+ g4x2, yPsw + 111, g4xs2, 10
+
+ DEFPUSHBUTTON "OK", IDOK, bx3, by, bxs, bys, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, bx2, by, bxs, bys
+ PUSHBUTTON "Help", IDHELP, bx1, by, bxs, bys
+END
+
+
+#ifdef UNDER_CE
+
+#undef m
+#undef xc
+#undef yc
+
+#define m 4
+#define xc 152
+#define yc 160
+
+
+IDD_COMPRESS_2 DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
+CAPTION "Add to Archive"
+MY_FONT
+BEGIN
+ COMBOBOX IDC_COMPRESS_ARCHIVE, m, m, xc - bxsDots - m, 126, MY_COMBO_WITH_EDIT
+ PUSHBUTTON "...", IDB_COMPRESS_SET_ARCHIVE, xs - m - bxsDots, m, bxsDots, 12, WS_GROUP
+
+ COMBOBOX IDC_COMPRESS_FORMAT, m , 22, 32, 80, MY_COMBO | CBS_SORT
+ COMBOBOX IDC_COMPRESS_LEVEL, m + 36, 22, 68, 80, MY_COMBO
+ COMBOBOX IDC_COMPRESS_METHOD, m + 108, 22, 44, 80, MY_COMBO
+
+ COMBOBOX IDC_COMPRESS_DICTIONARY, m, 40, 40, 80, MY_COMBO
+ COMBOBOX IDC_COMPRESS_ORDER, m + 44, 40, 32, 80, MY_COMBO
+ COMBOBOX IDC_COMPRESS_SOLID, m + 80, 40, 40, 80, MY_COMBO
+ COMBOBOX IDC_COMPRESS_THREADS, m + 124, 40, 28, 80, MY_COMBO
+
+ LTEXT "Split to &volumes, bytes:", IDT_SPLIT_TO_VOLUMES, m, 60, 32, 8
+ COMBOBOX IDC_COMPRESS_VOLUME, m + 32, 58, 44, 73, MY_COMBO_WITH_EDIT
+ LTEXT "Parameters:", IDT_COMPRESS_PARAMETERS, m + 80, 60, 48, 8
+ EDITTEXT IDE_COMPRESS_PARAMETERS, m + 128, 58, 24, 13, ES_AUTOHSCROLL
+
+ COMBOBOX IDC_COMPRESS_UPDATE_MODE, m, 76, 88, 80, MY_COMBO
+ CONTROL "SF&X", IDX_COMPRESS_SFX, MY_CHECKBOX, m + 92, 77, 60, 10
+
+ CONTROL "Compress shared files", IDX_COMPRESS_SHARED, MY_CHECKBOX, m, 94, xc, 10
+
+ LTEXT "Enter &password:", IDT_PASSWORD_ENTER, m, 112, 60, 8
+ EDITTEXT IDE_COMPRESS_PASSWORD1, m + 60, 110, 44, 13, ES_PASSWORD | ES_AUTOHSCROLL
+ CONTROL "Show Password", IDX_PASSWORD_SHOW, MY_CHECKBOX, m + 108, 112, 44, 10
+
+ COMBOBOX IDC_COMPRESS_ENCRYPTION_METHOD, m, 128, 48, 198, MY_COMBO
+ CONTROL "Encrypt file &names", IDX_COMPRESS_ENCRYPT_FILE_NAMES, MY_CHECKBOX, m + 52, 130, 100, 10
+
+ OK_CANCEL
+END
+
+#endif
+
+STRINGTABLE
+BEGIN
+ IDS_PASSWORD_NOT_MATCH "Passwords do not match"
+ IDS_PASSWORD_USE_ASCII "Use only English letters, numbers and special characters (!, #, $, ...) for password."
+ IDS_PASSWORD_TOO_LONG "Password is too long"
+
+ IDS_METHOD_STORE "Store"
+ IDS_METHOD_FASTEST "Fastest"
+ IDS_METHOD_FAST "Fast"
+ IDS_METHOD_NORMAL "Normal"
+ IDS_METHOD_MAXIMUM "Maximum"
+ IDS_METHOD_ULTRA "Ultra"
+
+ IDS_COMPRESS_UPDATE_MODE_ADD "Add and replace files"
+ IDS_COMPRESS_UPDATE_MODE_UPDATE "Update and add files"
+ IDS_COMPRESS_UPDATE_MODE_FRESH "Freshen existing files"
+ IDS_COMPRESS_UPDATE_MODE_SYNC "Synchronize files"
+
+ IDS_OPEN_TYPE_ALL_FILES "All Files"
+ IDS_COMPRESS_SET_ARCHIVE_BROWSE "Browse"
+
+ IDS_COMPRESS_NON_SOLID "Non-solid"
+ IDS_COMPRESS_SOLID "Solid"
+
+ IDS_SPLIT_CONFIRM "Specified volume size: {0} bytes.\nAre you sure you want to split archive into such volumes?"
+
+ IDS_COMPRESS_SEC "sec"
+ IDS_COMPRESS_NS "ns"
+END
+
+
+#include "CompressOptionsDialog.rc"
diff --git a/CPP/7zip/UI/GUI/CompressDialogRes.h b/CPP/7zip/UI/GUI/CompressDialogRes.h
new file mode 100644
index 0000000..aa25b89
--- /dev/null
+++ b/CPP/7zip/UI/GUI/CompressDialogRes.h
@@ -0,0 +1,123 @@
+#define IDD_COMPRESS 4000
+#define IDD_COMPRESS_2 14000
+#define IDD_COMPRESS_OPTIONS 14001
+
+#define IDC_COMPRESS_ARCHIVE 100
+#define IDB_COMPRESS_SET_ARCHIVE 101
+#define IDC_COMPRESS_LEVEL 102
+#define IDC_COMPRESS_UPDATE_MODE 103
+#define IDC_COMPRESS_FORMAT 104
+#define IDC_COMPRESS_VOLUME 105
+#define IDC_COMPRESS_METHOD 106
+#define IDC_COMPRESS_DICTIONARY 107
+#define IDC_COMPRESS_ORDER 108
+#define IDC_COMPRESS_SOLID 109
+#define IDC_COMPRESS_THREADS 110
+#define IDE_COMPRESS_PARAMETERS 111
+
+#define IDT_COMPRESS_HARDWARE_THREADS 112
+#define IDT_COMPRESS_MEMORY_VALUE 113
+#define IDT_COMPRESS_MEMORY_DE_VALUE 114
+
+#define IDG_COMPRESS_NTFS 115
+#define IDC_COMPRESS_PATH_MODE 116
+#define IDC_COMPRESS_MEM_USE 117
+// #define IDC_COMPRESS_DICTIONARY2 118
+
+#define IDE_COMPRESS_PASSWORD1 120
+#define IDE_COMPRESS_PASSWORD2 121
+#define IDC_COMPRESS_ENCRYPTION_METHOD 122
+
+#define IDT_COMPRESS_ARCHIVE_FOLDER 130
+
+// #define IDB_COMPRESS_OPTIONS 140
+#define IDB_COMPRESS_OPTIONS 2100
+#define IDT_COMPRESS_OPTIONS 141
+// #define IDT_COMPRESS_PARAMS_INFO 142
+
+#define IDT_COMPRESS_PATH_MODE 3410
+
+#define IDT_PASSWORD_ENTER 3801
+#define IDT_PASSWORD_REENTER 3802
+#define IDX_PASSWORD_SHOW 3803
+#define IDS_PASSWORD_NOT_MATCH 3804
+#define IDS_PASSWORD_USE_ASCII 3805
+#define IDS_PASSWORD_TOO_LONG 3806
+
+#define IDT_COMPRESS_ARCHIVE 4001
+#define IDT_COMPRESS_UPDATE_MODE 4002
+#define IDT_COMPRESS_FORMAT 4003
+#define IDT_COMPRESS_LEVEL 4004
+#define IDT_COMPRESS_METHOD 4005
+#define IDT_COMPRESS_DICTIONARY 4006
+#define IDT_COMPRESS_ORDER 4007
+#define IDT_COMPRESS_SOLID 4008
+#define IDT_COMPRESS_THREADS 4009
+#define IDT_COMPRESS_PARAMETERS 4010
+#define IDG_COMPRESS_OPTIONS 4011
+
+#define IDX_COMPRESS_SFX 4012
+#define IDX_COMPRESS_SHARED 4013
+
+#define IDG_COMPRESS_ENCRYPTION 4014
+#define IDT_COMPRESS_ENCRYPTION_METHOD 4015
+#define IDX_COMPRESS_ENCRYPT_FILE_NAMES 4016
+
+#define IDT_COMPRESS_MEMORY 4017
+#define IDT_COMPRESS_MEMORY_DE 4018
+
+#define IDX_COMPRESS_DEL 4019
+
+#define IDX_COMPRESS_NT_SYM_LINKS 4040
+#define IDX_COMPRESS_NT_HARD_LINKS 4041
+#define IDX_COMPRESS_NT_ALT_STREAMS 4042
+#define IDX_COMPRESS_NT_SECUR 4043
+
+#define IDS_METHOD_STORE 4050
+#define IDS_METHOD_FASTEST 4051
+#define IDS_METHOD_FAST 4052
+#define IDS_METHOD_NORMAL 4053
+#define IDS_METHOD_MAXIMUM 4054
+#define IDS_METHOD_ULTRA 4055
+
+#define IDS_COMPRESS_UPDATE_MODE_ADD 4060
+#define IDS_COMPRESS_UPDATE_MODE_UPDATE 4061
+#define IDS_COMPRESS_UPDATE_MODE_FRESH 4062
+#define IDS_COMPRESS_UPDATE_MODE_SYNC 4063
+
+#define IDS_COMPRESS_SET_ARCHIVE_BROWSE 4070
+#define IDS_OPEN_TYPE_ALL_FILES 4071
+#define IDS_COMPRESS_NON_SOLID 4072
+#define IDS_COMPRESS_SOLID 4073
+
+#define IDT_SPLIT_TO_VOLUMES 7302
+#define IDS_INCORRECT_VOLUME_SIZE 7307
+#define IDS_SPLIT_CONFIRM 7308
+
+
+// Options Dialog
+
+#define IDG_COMPRESS_TIME 4080
+#define IDT_COMPRESS_TIME_PREC 4081
+#define IDX_COMPRESS_MTIME 4082
+#define IDX_COMPRESS_CTIME 4083
+#define IDX_COMPRESS_ATIME 4084
+#define IDX_COMPRESS_ZTIME 4085
+#define IDX_COMPRESS_PRESERVE_ATIME 4086
+
+#define IDS_COMPRESS_SEC 4090
+#define IDS_COMPRESS_NS 4091
+
+#define IDC_COMPRESS_TIME_PREC 190
+#define IDT_COMPRESS_TIME_INFO 191
+
+#define IDX_COMPRESS_PREC_SET 201
+#define IDX_COMPRESS_MTIME_SET 202
+#define IDX_COMPRESS_CTIME_SET 203
+#define IDX_COMPRESS_ATIME_SET 204
+#define IDX_COMPRESS_ZTIME_SET 205
+
+// #define IDX_COMPRESS_NT_SYM_LINKS_SET 210
+// #define IDX_COMPRESS_NT_HARD_LINKS_SET 211
+// #define IDX_COMPRESS_NT_ALT_STREAMS_SET 212
+// #define IDX_COMPRESS_NT_SECUR_SET 213
diff --git a/CPP/7zip/UI/GUI/CompressOptionsDialog.rc b/CPP/7zip/UI/GUI/CompressOptionsDialog.rc
new file mode 100644
index 0000000..0578227
--- /dev/null
+++ b/CPP/7zip/UI/GUI/CompressOptionsDialog.rc
@@ -0,0 +1,76 @@
+#include "CompressDialogRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 240
+#define yc 232
+
+#define g5x m
+#define g5x2 (g5x + m)
+#define g5xs (xc)
+#define g5xs2 (g5xs - m - m)
+
+#define ntPosX g5x2
+#define ntPosY m
+#define ntSizeX g5xs2
+#define precSizeX 76
+
+#define ntSizeY 72
+#define timePosY (ntPosY + ntSizeY + 20)
+
+#define ceSize 18
+#define ceString ":"
+
+
+IDD_COMPRESS_OPTIONS DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
+CAPTION "Options"
+BEGIN
+ GROUPBOX "NTFS", IDG_COMPRESS_NTFS, g5x, ntPosY, g5xs, ntSizeY
+
+ CONTROL "Store symbolic links", IDX_COMPRESS_NT_SYM_LINKS, MY_CHECKBOX,
+ ntPosX, ntPosY + 12, ntSizeX, 10
+ CONTROL "Store hard links", IDX_COMPRESS_NT_HARD_LINKS, MY_CHECKBOX,
+ ntPosX, ntPosY + 26, ntSizeX, 10
+ CONTROL "Store alternate data streams", IDX_COMPRESS_NT_ALT_STREAMS, MY_CHECKBOX,
+ ntPosX, ntPosY + 40, ntSizeX, 10
+ CONTROL "Store file security", IDX_COMPRESS_NT_SECUR, MY_CHECKBOX,
+ ntPosX, ntPosY + 54, ntSizeX, 10
+
+ LTEXT "", IDT_COMPRESS_TIME_INFO, g5x, timePosY - 14, g5xs, 8
+
+
+ GROUPBOX "Time", IDG_COMPRESS_TIME, g5x, timePosY, g5xs, 112
+
+// CONTROL "Default", IDX_COMPRESS_TIME_DEFAULT, MY_CHECKBOX,
+// ntPosX, timePosY + 10, ntSizeX, 16
+
+ CONTROL ceString, IDX_COMPRESS_PREC_SET, MY_CHECKBOX, ntPosX, timePosY + 14, ceSize, 10
+ LTEXT "Timestamp precision:", IDT_COMPRESS_TIME_PREC,
+ ntPosX + ceSize, timePosY + 14, ntSizeX - precSizeX - ceSize, 8
+ COMBOBOX IDC_COMPRESS_TIME_PREC, ntPosX + ntSizeX - precSizeX, timePosY + 12, precSizeX, 70, MY_COMBO
+
+ // PUSHBUTTON "Default", IDB_COMPRESS_TIME_DEFAULT, ntPosX + ntSizeX - bxs, timePosY + 22, bxs, bys, WS_GROUP
+
+ CONTROL ceString, IDX_COMPRESS_MTIME_SET, MY_CHECKBOX, ntPosX, timePosY + 28, ceSize, 10
+ CONTROL "Store modification time", IDX_COMPRESS_MTIME, MY_CHECKBOX,
+ ntPosX + ceSize, timePosY + 28, ntSizeX - ceSize, 10
+
+ CONTROL ceString, IDX_COMPRESS_CTIME_SET, MY_CHECKBOX, ntPosX, timePosY + 42, ceSize, 10
+ CONTROL "Store creation time", IDX_COMPRESS_CTIME, MY_CHECKBOX,
+ ntPosX + ceSize, timePosY + 42, ntSizeX - ceSize, 10
+
+ CONTROL ceString, IDX_COMPRESS_ATIME_SET, MY_CHECKBOX, ntPosX, timePosY + 56, ceSize, 10
+ CONTROL "Store last access time", IDX_COMPRESS_ATIME, MY_CHECKBOX,
+ ntPosX + ceSize, timePosY + 56, ntSizeX - ceSize, 10
+
+ CONTROL ceString, IDX_COMPRESS_ZTIME_SET, MY_CHECKBOX | BS_MULTILINE, ntPosX, timePosY + 72, ceSize, 16
+ CONTROL "Set archive time to latest file time", IDX_COMPRESS_ZTIME, MY_CHECKBOX | BS_MULTILINE,
+ ntPosX + ceSize, timePosY + 72, ntSizeX - ceSize, 16
+
+ CONTROL "Do not change source files last access time", IDX_COMPRESS_PRESERVE_ATIME, MY_CHECKBOX | BS_MULTILINE,
+ ntPosX, timePosY + 92, ntSizeX, 16
+
+
+ DEFPUSHBUTTON "OK", IDOK, bx3, by, bxs, bys, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, bx2, by, bxs, bys
+ PUSHBUTTON "Help", IDHELP, bx1, by, bxs, bys
+END
diff --git a/CPP/7zip/UI/GUI/Extract.rc b/CPP/7zip/UI/GUI/Extract.rc
index 6bda89e..36bfb00 100644
--- a/CPP/7zip/UI/GUI/Extract.rc
+++ b/CPP/7zip/UI/GUI/Extract.rc
@@ -1,59 +1,59 @@
-#include "ExtractRes.h"
-
-LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
-
-STRINGTABLE DISCARDABLE
-BEGIN
- IDS_MEM_ERROR "The system cannot allocate the required amount of memory"
- IDS_CANNOT_CREATE_FOLDER "Cannot create folder '{0}'"
- IDS_UPDATE_NOT_SUPPORTED "Update operations are not supported for this archive."
- IDS_CANT_OPEN_ARCHIVE "Can not open file '{0}' as archive"
- IDS_CANT_OPEN_ENCRYPTED_ARCHIVE "Can not open encrypted archive '{0}'. Wrong password?"
- IDS_UNSUPPORTED_ARCHIVE_TYPE "Unsupported archive type"
-
- IDS_CANT_OPEN_AS_TYPE "Can not open the file as {0} archive"
- IDS_IS_OPEN_AS_TYPE "The file is open as {0} archive"
- IDS_IS_OPEN_WITH_OFFSET "The archive is open with offset"
-
- IDS_PROGRESS_EXTRACTING "Extracting"
-
- IDS_PROGRESS_SKIPPING "Skipping"
-
- IDS_EXTRACT_SET_FOLDER "Specify a location for extracted files."
-
- IDS_EXTRACT_PATHS_FULL "Full pathnames"
- IDS_EXTRACT_PATHS_NO "No pathnames"
- IDS_EXTRACT_PATHS_ABS "Absolute pathnames"
- IDS_PATH_MODE_RELAT "Relative pathnames"
-
- IDS_EXTRACT_OVERWRITE_ASK "Ask before overwrite"
- IDS_EXTRACT_OVERWRITE_WITHOUT_PROMPT "Overwrite without prompt"
- IDS_EXTRACT_OVERWRITE_SKIP_EXISTING "Skip existing files"
- IDS_EXTRACT_OVERWRITE_RENAME "Auto rename"
- IDS_EXTRACT_OVERWRITE_RENAME_EXISTING "Auto rename existing files"
-
- IDS_EXTRACT_MESSAGE_UNSUPPORTED_METHOD "Unsupported compression method for '{0}'."
- IDS_EXTRACT_MESSAGE_DATA_ERROR "Data error in '{0}'. File is broken"
- IDS_EXTRACT_MESSAGE_CRC_ERROR "CRC failed in '{0}'. File is broken."
- IDS_EXTRACT_MESSAGE_DATA_ERROR_ENCRYPTED "Data error in encrypted file '{0}'. Wrong password?"
- IDS_EXTRACT_MESSAGE_CRC_ERROR_ENCRYPTED "CRC failed in encrypted file '{0}'. Wrong password?"
-
- IDS_EXTRACT_MSG_WRONG_PSW_GUESS "Wrong password?"
- // IDS_EXTRACT_MSG_ENCRYPTED "Encrypted file"
-
- IDS_EXTRACT_MSG_UNSUPPORTED_METHOD "Unsupported compression method"
- IDS_EXTRACT_MSG_DATA_ERROR "Data error"
- IDS_EXTRACT_MSG_CRC_ERROR "CRC failed"
- IDS_EXTRACT_MSG_UNAVAILABLE_DATA "Unavailable data"
- IDS_EXTRACT_MSG_UEXPECTED_END "Unexpected end of data";
- IDS_EXTRACT_MSG_DATA_AFTER_END "There are some data after the end of the payload data"
- IDS_EXTRACT_MSG_IS_NOT_ARC "Is not archive"
- IDS_EXTRACT_MSG_HEADERS_ERROR "Headers Error"
- IDS_EXTRACT_MSG_WRONG_PSW_CLAIM "Wrong password"
-
- IDS_OPEN_MSG_UNAVAILABLE_START "Unavailable start of archive"
- IDS_OPEN_MSG_UNCONFIRMED_START "Unconfirmed start of archive"
- // IDS_OPEN_MSG_ERROR_FLAGS + 5 "Unexpected end of archive"
- // IDS_OPEN_MSG_ERROR_FLAGS + 6 "There are data after the end of archive"
- IDS_OPEN_MSG_UNSUPPORTED_FEATURE "Unsupported feature"
-END
+#include "ExtractRes.h"
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+STRINGTABLE DISCARDABLE
+BEGIN
+ IDS_MEM_ERROR "The system cannot allocate the required amount of memory"
+ IDS_CANNOT_CREATE_FOLDER "Cannot create folder '{0}'"
+ IDS_UPDATE_NOT_SUPPORTED "Update operations are not supported for this archive."
+ IDS_CANT_OPEN_ARCHIVE "Cannot open file '{0}' as archive"
+ IDS_CANT_OPEN_ENCRYPTED_ARCHIVE "Cannot open encrypted archive '{0}'. Wrong password?"
+ IDS_UNSUPPORTED_ARCHIVE_TYPE "Unsupported archive type"
+
+ IDS_CANT_OPEN_AS_TYPE "Cannot open the file as {0} archive"
+ IDS_IS_OPEN_AS_TYPE "The file is open as {0} archive"
+ IDS_IS_OPEN_WITH_OFFSET "The archive is open with offset"
+
+ IDS_PROGRESS_EXTRACTING "Extracting"
+
+ IDS_PROGRESS_SKIPPING "Skipping"
+
+ IDS_EXTRACT_SET_FOLDER "Specify a location for extracted files."
+
+ IDS_EXTRACT_PATHS_FULL "Full pathnames"
+ IDS_EXTRACT_PATHS_NO "No pathnames"
+ IDS_EXTRACT_PATHS_ABS "Absolute pathnames"
+ IDS_PATH_MODE_RELAT "Relative pathnames"
+
+ IDS_EXTRACT_OVERWRITE_ASK "Ask before overwrite"
+ IDS_EXTRACT_OVERWRITE_WITHOUT_PROMPT "Overwrite without prompt"
+ IDS_EXTRACT_OVERWRITE_SKIP_EXISTING "Skip existing files"
+ IDS_EXTRACT_OVERWRITE_RENAME "Auto rename"
+ IDS_EXTRACT_OVERWRITE_RENAME_EXISTING "Auto rename existing files"
+
+ IDS_EXTRACT_MESSAGE_UNSUPPORTED_METHOD "Unsupported compression method for '{0}'."
+ IDS_EXTRACT_MESSAGE_DATA_ERROR "Data error in '{0}'. File is broken"
+ IDS_EXTRACT_MESSAGE_CRC_ERROR "CRC failed in '{0}'. File is broken."
+ IDS_EXTRACT_MESSAGE_DATA_ERROR_ENCRYPTED "Data error in encrypted file '{0}'. Wrong password?"
+ IDS_EXTRACT_MESSAGE_CRC_ERROR_ENCRYPTED "CRC failed in encrypted file '{0}'. Wrong password?"
+
+ IDS_EXTRACT_MSG_WRONG_PSW_GUESS "Wrong password?"
+ // IDS_EXTRACT_MSG_ENCRYPTED "Encrypted file"
+
+ IDS_EXTRACT_MSG_UNSUPPORTED_METHOD "Unsupported compression method"
+ IDS_EXTRACT_MSG_DATA_ERROR "Data error"
+ IDS_EXTRACT_MSG_CRC_ERROR "CRC failed"
+ IDS_EXTRACT_MSG_UNAVAILABLE_DATA "Unavailable data"
+ IDS_EXTRACT_MSG_UEXPECTED_END "Unexpected end of data"
+ IDS_EXTRACT_MSG_DATA_AFTER_END "There are some data after the end of the payload data"
+ IDS_EXTRACT_MSG_IS_NOT_ARC "Is not archive"
+ IDS_EXTRACT_MSG_HEADERS_ERROR "Headers Error"
+ IDS_EXTRACT_MSG_WRONG_PSW_CLAIM "Wrong password"
+
+ IDS_OPEN_MSG_UNAVAILABLE_START "Unavailable start of archive"
+ IDS_OPEN_MSG_UNCONFIRMED_START "Unconfirmed start of archive"
+ // IDS_OPEN_MSG_ERROR_FLAGS + 5 "Unexpected end of archive"
+ // IDS_OPEN_MSG_ERROR_FLAGS + 6 "There are data after the end of archive"
+ IDS_OPEN_MSG_UNSUPPORTED_FEATURE "Unsupported feature"
+END
diff --git a/CPP/7zip/UI/GUI/ExtractDialog.cpp b/CPP/7zip/UI/GUI/ExtractDialog.cpp
index 71c2a3b..4628482 100644
--- a/CPP/7zip/UI/GUI/ExtractDialog.cpp
+++ b/CPP/7zip/UI/GUI/ExtractDialog.cpp
@@ -1,418 +1,421 @@
-// ExtractDialog.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/StringConvert.h"
-#include "../../../Common/Wildcard.h"
-
-#include "../../../Windows/FileName.h"
-#include "../../../Windows/FileDir.h"
-#include "../../../Windows/ResourceString.h"
-
-#ifndef NO_REGISTRY
-#include "../FileManager/HelpUtils.h"
-#endif
-
-
-#include "../FileManager/BrowseDialog.h"
-#include "../FileManager/LangUtils.h"
-#include "../FileManager/resourceGui.h"
-
-#include "ExtractDialog.h"
-#include "ExtractDialogRes.h"
-#include "ExtractRes.h"
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NName;
-
-extern HINSTANCE g_hInstance;
-
-static const UInt32 kPathMode_IDs[] =
-{
- IDS_EXTRACT_PATHS_FULL,
- IDS_EXTRACT_PATHS_NO,
- IDS_EXTRACT_PATHS_ABS
-};
-
-static const UInt32 kOverwriteMode_IDs[] =
-{
- IDS_EXTRACT_OVERWRITE_ASK,
- IDS_EXTRACT_OVERWRITE_WITHOUT_PROMPT,
- IDS_EXTRACT_OVERWRITE_SKIP_EXISTING,
- IDS_EXTRACT_OVERWRITE_RENAME,
- IDS_EXTRACT_OVERWRITE_RENAME_EXISTING
-};
-
-#ifndef _SFX
-
-static const
- // NExtract::NPathMode::EEnum
- int
- kPathModeButtonsVals[] =
-{
- NExtract::NPathMode::kFullPaths,
- NExtract::NPathMode::kNoPaths,
- NExtract::NPathMode::kAbsPaths
-};
-
-static const
- int
- // NExtract::NOverwriteMode::EEnum
- kOverwriteButtonsVals[] =
-{
- NExtract::NOverwriteMode::kAsk,
- NExtract::NOverwriteMode::kOverwrite,
- NExtract::NOverwriteMode::kSkip,
- NExtract::NOverwriteMode::kRename,
- NExtract::NOverwriteMode::kRenameExisting
-};
-
-#endif
-
-#ifdef LANG
-
-static const UInt32 kLangIDs[] =
-{
- IDT_EXTRACT_EXTRACT_TO,
- IDT_EXTRACT_PATH_MODE,
- IDT_EXTRACT_OVERWRITE_MODE,
- // IDX_EXTRACT_ALT_STREAMS,
- IDX_EXTRACT_NT_SECUR,
- IDX_EXTRACT_ELIM_DUP,
- IDG_PASSWORD,
- IDX_PASSWORD_SHOW
-};
-#endif
-
-// static const int kWildcardsButtonIndex = 2;
-
-#ifndef NO_REGISTRY
-static const unsigned kHistorySize = 16;
-#endif
-
-#ifndef _SFX
-
-// it's used in CompressDialog also
-void AddComboItems(NControl::CComboBox &combo, const UInt32 *langIDs, unsigned numItems, const int *values, int curVal)
-{
- int curSel = 0;
- for (unsigned i = 0; i < numItems; i++)
- {
- UString s = LangString(langIDs[i]);
- s.RemoveChar(L'&');
- int index = (int)combo.AddString(s);
- combo.SetItemData(index, i);
- if (values[i] == curVal)
- curSel = i;
- }
- combo.SetCurSel(curSel);
-}
-
-// it's used in CompressDialog also
-bool GetBoolsVal(const CBoolPair &b1, const CBoolPair &b2)
-{
- if (b1.Def) return b1.Val;
- if (b2.Def) return b2.Val;
- return b1.Val;
-}
-
-void CExtractDialog::CheckButton_TwoBools(UINT id, const CBoolPair &b1, const CBoolPair &b2)
-{
- CheckButton(id, GetBoolsVal(b1, b2));
-}
-
-void CExtractDialog::GetButton_Bools(UINT id, CBoolPair &b1, CBoolPair &b2)
-{
- bool val = IsButtonCheckedBool(id);
- bool oldVal = GetBoolsVal(b1, b2);
- if (val != oldVal)
- b1.Def = b2.Def = true;
- b1.Val = b2.Val = val;
-}
-
-#endif
-
-bool CExtractDialog::OnInit()
-{
- #ifdef LANG
- {
- UString s;
- LangString_OnlyFromLangFile(IDD_EXTRACT, s);
- if (s.IsEmpty())
- GetText(s);
- if (!ArcPath.IsEmpty())
- {
- s += " : ";
- s += ArcPath;
- }
- SetText(s);
- // LangSetWindowText(*this, IDD_EXTRACT);
- LangSetDlgItems(*this, kLangIDs, ARRAY_SIZE(kLangIDs));
- }
- #endif
-
- #ifndef _SFX
- _passwordControl.Attach(GetItem(IDE_EXTRACT_PASSWORD));
- _passwordControl.SetText(Password);
- _passwordControl.SetPasswordChar(TEXT('*'));
- _pathName.Attach(GetItem(IDE_EXTRACT_NAME));
- #endif
-
- #ifdef NO_REGISTRY
-
- PathMode = NExtract::NPathMode::kFullPaths;
- OverwriteMode = NExtract::NOverwriteMode::kAsk;
-
- #else
-
- _info.Load();
-
- if (_info.PathMode == NExtract::NPathMode::kCurPaths)
- _info.PathMode = NExtract::NPathMode::kFullPaths;
-
- if (!PathMode_Force && _info.PathMode_Force)
- PathMode = _info.PathMode;
- if (!OverwriteMode_Force && _info.OverwriteMode_Force)
- OverwriteMode = _info.OverwriteMode;
-
- // CheckButton_TwoBools(IDX_EXTRACT_ALT_STREAMS, AltStreams, _info.AltStreams);
- CheckButton_TwoBools(IDX_EXTRACT_NT_SECUR, NtSecurity, _info.NtSecurity);
- CheckButton_TwoBools(IDX_EXTRACT_ELIM_DUP, ElimDup, _info.ElimDup);
-
- CheckButton(IDX_PASSWORD_SHOW, _info.ShowPassword.Val);
- UpdatePasswordControl();
-
- #endif
-
- _path.Attach(GetItem(IDC_EXTRACT_PATH));
-
- UString pathPrefix = DirPath;
-
- #ifndef _SFX
-
- if (_info.SplitDest.Val)
- {
- CheckButton(IDX_EXTRACT_NAME_ENABLE, true);
- UString pathName;
- SplitPathToParts_Smart(DirPath, pathPrefix, pathName);
- if (pathPrefix.IsEmpty())
- pathPrefix = pathName;
- else
- _pathName.SetText(pathName);
- }
- else
- ShowItem_Bool(IDE_EXTRACT_NAME, false);
-
- #endif
-
- _path.SetText(pathPrefix);
-
- #ifndef NO_REGISTRY
- for (unsigned i = 0; i < _info.Paths.Size() && i < kHistorySize; i++)
- _path.AddString(_info.Paths[i]);
- #endif
-
- /*
- if (_info.Paths.Size() > 0)
- _path.SetCurSel(0);
- else
- _path.SetCurSel(-1);
- */
-
- #ifndef _SFX
-
- _pathMode.Attach(GetItem(IDC_EXTRACT_PATH_MODE));
- _overwriteMode.Attach(GetItem(IDC_EXTRACT_OVERWRITE_MODE));
-
- AddComboItems(_pathMode, kPathMode_IDs, ARRAY_SIZE(kPathMode_IDs), kPathModeButtonsVals, PathMode);
- AddComboItems(_overwriteMode, kOverwriteMode_IDs, ARRAY_SIZE(kOverwriteMode_IDs), kOverwriteButtonsVals, OverwriteMode);
-
- #endif
-
- HICON icon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ICON));
- SetIcon(ICON_BIG, icon);
-
- // CWindow filesWindow = GetItem(IDC_EXTRACT_RADIO_FILES);
- // filesWindow.Enable(_enableFilesButton);
-
- NormalizePosition();
-
- return CModalDialog::OnInit();
-}
-
-#ifndef _SFX
-void CExtractDialog::UpdatePasswordControl()
-{
- _passwordControl.SetPasswordChar(IsShowPasswordChecked() ? 0 : TEXT('*'));
- UString password;
- _passwordControl.GetText(password);
- _passwordControl.SetText(password);
-}
-#endif
-
-bool CExtractDialog::OnButtonClicked(int buttonID, HWND buttonHWND)
-{
- switch (buttonID)
- {
- case IDB_EXTRACT_SET_PATH:
- OnButtonSetPath();
- return true;
- #ifndef _SFX
- case IDX_EXTRACT_NAME_ENABLE:
- ShowItem_Bool(IDE_EXTRACT_NAME, IsButtonCheckedBool(IDX_EXTRACT_NAME_ENABLE));
- return true;
- case IDX_PASSWORD_SHOW:
- {
- UpdatePasswordControl();
- return true;
- }
- #endif
- }
- return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
-}
-
-void CExtractDialog::OnButtonSetPath()
-{
- UString currentPath;
- _path.GetText(currentPath);
- UString title = LangString(IDS_EXTRACT_SET_FOLDER);
- UString resultPath;
- if (!MyBrowseForFolder(*this, title, currentPath, resultPath))
- return;
- #ifndef NO_REGISTRY
- _path.SetCurSel(-1);
- #endif
- _path.SetText(resultPath);
-}
-
-void AddUniqueString(UStringVector &list, const UString &s)
-{
- FOR_VECTOR (i, list)
- if (s.IsEqualTo_NoCase(list[i]))
- return;
- list.Add(s);
-}
-
-void CExtractDialog::OnOK()
-{
- #ifndef _SFX
- int pathMode2 = kPathModeButtonsVals[_pathMode.GetCurSel()];
- if (PathMode != NExtract::NPathMode::kCurPaths ||
- pathMode2 != NExtract::NPathMode::kFullPaths)
- PathMode = (NExtract::NPathMode::EEnum)pathMode2;
-
- OverwriteMode = (NExtract::NOverwriteMode::EEnum)kOverwriteButtonsVals[_overwriteMode.GetCurSel()];
-
- // _filesMode = (NExtractionDialog::NFilesMode::EEnum)GetFilesMode();
-
- _passwordControl.GetText(Password);
-
- #endif
-
- #ifndef NO_REGISTRY
-
- // GetButton_Bools(IDX_EXTRACT_ALT_STREAMS, AltStreams, _info.AltStreams);
- GetButton_Bools(IDX_EXTRACT_NT_SECUR, NtSecurity, _info.NtSecurity);
- GetButton_Bools(IDX_EXTRACT_ELIM_DUP, ElimDup, _info.ElimDup);
-
- bool showPassword = IsShowPasswordChecked();
- if (showPassword != _info.ShowPassword.Val)
- {
- _info.ShowPassword.Def = true;
- _info.ShowPassword.Val = showPassword;
- }
-
- if (_info.PathMode != pathMode2)
- {
- _info.PathMode_Force = true;
- _info.PathMode = (NExtract::NPathMode::EEnum)pathMode2;
- /*
- // we allow kAbsPaths in registry.
- if (_info.PathMode == NExtract::NPathMode::kAbsPaths)
- _info.PathMode = NExtract::NPathMode::kFullPaths;
- */
- }
-
- if (!OverwriteMode_Force && _info.OverwriteMode != OverwriteMode)
- _info.OverwriteMode_Force = true;
- _info.OverwriteMode = OverwriteMode;
-
-
- #else
-
- ElimDup.Val = IsButtonCheckedBool(IDX_EXTRACT_ELIM_DUP);
-
- #endif
-
- UString s;
-
- #ifdef NO_REGISTRY
-
- _path.GetText(s);
-
- #else
-
- int currentItem = _path.GetCurSel();
- if (currentItem == CB_ERR)
- {
- _path.GetText(s);
- if (_path.GetCount() >= kHistorySize)
- currentItem = _path.GetCount() - 1;
- }
- else
- _path.GetLBText(currentItem, s);
-
- #endif
-
- s.Trim();
- NName::NormalizeDirPathPrefix(s);
-
- #ifndef _SFX
-
- bool splitDest = IsButtonCheckedBool(IDX_EXTRACT_NAME_ENABLE);
- if (splitDest)
- {
- UString pathName;
- _pathName.GetText(pathName);
- pathName.Trim();
- s += pathName;
- NName::NormalizeDirPathPrefix(s);
- }
- if (splitDest != _info.SplitDest.Val)
- {
- _info.SplitDest.Def = true;
- _info.SplitDest.Val = splitDest;
- }
-
- #endif
-
- DirPath = s;
-
- #ifndef NO_REGISTRY
- _info.Paths.Clear();
- #ifndef _SFX
- AddUniqueString(_info.Paths, s);
- #endif
- for (int i = 0; i < _path.GetCount(); i++)
- if (i != currentItem)
- {
- UString sTemp;
- _path.GetLBText(i, sTemp);
- sTemp.Trim();
- AddUniqueString(_info.Paths, sTemp);
- }
- _info.Save();
- #endif
-
- CModalDialog::OnOK();
-}
-
-#ifndef NO_REGISTRY
-#define kHelpTopic "fm/plugins/7-zip/extract.htm"
-void CExtractDialog::OnHelp()
-{
- ShowHelpWindow(kHelpTopic);
- CModalDialog::OnHelp();
-}
-#endif
+// ExtractDialog.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/Wildcard.h"
+
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/ResourceString.h"
+
+#ifndef Z7_NO_REGISTRY
+#include "../FileManager/HelpUtils.h"
+#endif
+
+
+#include "../FileManager/BrowseDialog.h"
+#include "../FileManager/LangUtils.h"
+#include "../FileManager/resourceGui.h"
+
+#include "ExtractDialog.h"
+#include "ExtractDialogRes.h"
+#include "ExtractRes.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NName;
+
+extern HINSTANCE g_hInstance;
+
+#ifndef Z7_SFX
+
+static const UInt32 kPathMode_IDs[] =
+{
+ IDS_EXTRACT_PATHS_FULL,
+ IDS_EXTRACT_PATHS_NO,
+ IDS_EXTRACT_PATHS_ABS
+};
+
+static const UInt32 kOverwriteMode_IDs[] =
+{
+ IDS_EXTRACT_OVERWRITE_ASK,
+ IDS_EXTRACT_OVERWRITE_WITHOUT_PROMPT,
+ IDS_EXTRACT_OVERWRITE_SKIP_EXISTING,
+ IDS_EXTRACT_OVERWRITE_RENAME,
+ IDS_EXTRACT_OVERWRITE_RENAME_EXISTING
+};
+
+static const
+ // NExtract::NPathMode::EEnum
+ int
+ kPathModeButtonsVals[] =
+{
+ NExtract::NPathMode::kFullPaths,
+ NExtract::NPathMode::kNoPaths,
+ NExtract::NPathMode::kAbsPaths
+};
+
+static const
+ int
+ // NExtract::NOverwriteMode::EEnum
+ kOverwriteButtonsVals[] =
+{
+ NExtract::NOverwriteMode::kAsk,
+ NExtract::NOverwriteMode::kOverwrite,
+ NExtract::NOverwriteMode::kSkip,
+ NExtract::NOverwriteMode::kRename,
+ NExtract::NOverwriteMode::kRenameExisting
+};
+
+#endif
+
+#ifdef Z7_LANG
+
+static const UInt32 kLangIDs[] =
+{
+ IDT_EXTRACT_EXTRACT_TO,
+ IDT_EXTRACT_PATH_MODE,
+ IDT_EXTRACT_OVERWRITE_MODE,
+ // IDX_EXTRACT_ALT_STREAMS,
+ IDX_EXTRACT_NT_SECUR,
+ IDX_EXTRACT_ELIM_DUP,
+ IDG_PASSWORD,
+ IDX_PASSWORD_SHOW
+};
+#endif
+
+// static const int kWildcardsButtonIndex = 2;
+
+#ifndef Z7_NO_REGISTRY
+static const unsigned kHistorySize = 16;
+#endif
+
+#ifndef Z7_SFX
+
+// it's used in CompressDialog also
+void AddComboItems(NControl::CComboBox &combo, const UInt32 *langIDs, unsigned numItems, const int *values, int curVal);
+void AddComboItems(NControl::CComboBox &combo, const UInt32 *langIDs, unsigned numItems, const int *values, int curVal)
+{
+ unsigned curSel = 0;
+ for (unsigned i = 0; i < numItems; i++)
+ {
+ UString s = LangString(langIDs[i]);
+ s.RemoveChar(L'&');
+ const int index = (int)combo.AddString(s);
+ combo.SetItemData(index, (LPARAM)i);
+ if (values[i] == curVal)
+ curSel = i;
+ }
+ combo.SetCurSel(curSel);
+}
+
+// it's used in CompressDialog also
+bool GetBoolsVal(const CBoolPair &b1, const CBoolPair &b2);
+bool GetBoolsVal(const CBoolPair &b1, const CBoolPair &b2)
+{
+ if (b1.Def) return b1.Val;
+ if (b2.Def) return b2.Val;
+ return b1.Val;
+}
+
+void CExtractDialog::CheckButton_TwoBools(UINT id, const CBoolPair &b1, const CBoolPair &b2)
+{
+ CheckButton(id, GetBoolsVal(b1, b2));
+}
+
+void CExtractDialog::GetButton_Bools(UINT id, CBoolPair &b1, CBoolPair &b2)
+{
+ const bool val = IsButtonCheckedBool(id);
+ const bool oldVal = GetBoolsVal(b1, b2);
+ if (val != oldVal)
+ b1.Def = b2.Def = true;
+ b1.Val = b2.Val = val;
+}
+
+#endif
+
+bool CExtractDialog::OnInit()
+{
+ #ifdef Z7_LANG
+ {
+ UString s;
+ LangString_OnlyFromLangFile(IDD_EXTRACT, s);
+ if (s.IsEmpty())
+ GetText(s);
+ if (!ArcPath.IsEmpty())
+ {
+ s += " : ";
+ s += ArcPath;
+ }
+ SetText(s);
+ // LangSetWindowText(*this, IDD_EXTRACT);
+ LangSetDlgItems(*this, kLangIDs, Z7_ARRAY_SIZE(kLangIDs));
+ }
+ #endif
+
+ #ifndef Z7_SFX
+ _passwordControl.Attach(GetItem(IDE_EXTRACT_PASSWORD));
+ _passwordControl.SetText(Password);
+ _passwordControl.SetPasswordChar(TEXT('*'));
+ _pathName.Attach(GetItem(IDE_EXTRACT_NAME));
+ #endif
+
+ #ifdef Z7_NO_REGISTRY
+
+ PathMode = NExtract::NPathMode::kFullPaths;
+ OverwriteMode = NExtract::NOverwriteMode::kAsk;
+
+ #else
+
+ _info.Load();
+
+ if (_info.PathMode == NExtract::NPathMode::kCurPaths)
+ _info.PathMode = NExtract::NPathMode::kFullPaths;
+
+ if (!PathMode_Force && _info.PathMode_Force)
+ PathMode = _info.PathMode;
+ if (!OverwriteMode_Force && _info.OverwriteMode_Force)
+ OverwriteMode = _info.OverwriteMode;
+
+ // CheckButton_TwoBools(IDX_EXTRACT_ALT_STREAMS, AltStreams, _info.AltStreams);
+ CheckButton_TwoBools(IDX_EXTRACT_NT_SECUR, NtSecurity, _info.NtSecurity);
+ CheckButton_TwoBools(IDX_EXTRACT_ELIM_DUP, ElimDup, _info.ElimDup);
+
+ CheckButton(IDX_PASSWORD_SHOW, _info.ShowPassword.Val);
+ UpdatePasswordControl();
+
+ #endif
+
+ _path.Attach(GetItem(IDC_EXTRACT_PATH));
+
+ UString pathPrefix = DirPath;
+
+ #ifndef Z7_SFX
+
+ if (_info.SplitDest.Val)
+ {
+ CheckButton(IDX_EXTRACT_NAME_ENABLE, true);
+ UString pathName;
+ SplitPathToParts_Smart(DirPath, pathPrefix, pathName);
+ if (pathPrefix.IsEmpty())
+ pathPrefix = pathName;
+ else
+ _pathName.SetText(pathName);
+ }
+ else
+ ShowItem_Bool(IDE_EXTRACT_NAME, false);
+
+ #endif
+
+ _path.SetText(pathPrefix);
+
+ #ifndef Z7_NO_REGISTRY
+ for (unsigned i = 0; i < _info.Paths.Size() && i < kHistorySize; i++)
+ _path.AddString(_info.Paths[i]);
+ #endif
+
+ /*
+ if (_info.Paths.Size() > 0)
+ _path.SetCurSel(0);
+ else
+ _path.SetCurSel(-1);
+ */
+
+ #ifndef Z7_SFX
+
+ _pathMode.Attach(GetItem(IDC_EXTRACT_PATH_MODE));
+ _overwriteMode.Attach(GetItem(IDC_EXTRACT_OVERWRITE_MODE));
+
+ AddComboItems(_pathMode, kPathMode_IDs, Z7_ARRAY_SIZE(kPathMode_IDs), kPathModeButtonsVals, PathMode);
+ AddComboItems(_overwriteMode, kOverwriteMode_IDs, Z7_ARRAY_SIZE(kOverwriteMode_IDs), kOverwriteButtonsVals, OverwriteMode);
+
+ #endif
+
+ HICON icon = LoadIcon(g_hInstance, MAKEINTRESOURCE(IDI_ICON));
+ SetIcon(ICON_BIG, icon);
+
+ // CWindow filesWindow = GetItem(IDC_EXTRACT_RADIO_FILES);
+ // filesWindow.Enable(_enableFilesButton);
+
+ NormalizePosition();
+
+ return CModalDialog::OnInit();
+}
+
+#ifndef Z7_SFX
+void CExtractDialog::UpdatePasswordControl()
+{
+ _passwordControl.SetPasswordChar(IsShowPasswordChecked() ? 0 : TEXT('*'));
+ UString password;
+ _passwordControl.GetText(password);
+ _passwordControl.SetText(password);
+}
+#endif
+
+bool CExtractDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ switch (buttonID)
+ {
+ case IDB_EXTRACT_SET_PATH:
+ OnButtonSetPath();
+ return true;
+ #ifndef Z7_SFX
+ case IDX_EXTRACT_NAME_ENABLE:
+ ShowItem_Bool(IDE_EXTRACT_NAME, IsButtonCheckedBool(IDX_EXTRACT_NAME_ENABLE));
+ return true;
+ case IDX_PASSWORD_SHOW:
+ {
+ UpdatePasswordControl();
+ return true;
+ }
+ #endif
+ }
+ return CModalDialog::OnButtonClicked(buttonID, buttonHWND);
+}
+
+void CExtractDialog::OnButtonSetPath()
+{
+ UString currentPath;
+ _path.GetText(currentPath);
+ UString title = LangString(IDS_EXTRACT_SET_FOLDER);
+ UString resultPath;
+ if (!MyBrowseForFolder(*this, title, currentPath, resultPath))
+ return;
+ #ifndef Z7_NO_REGISTRY
+ _path.SetCurSel(-1);
+ #endif
+ _path.SetText(resultPath);
+}
+
+void AddUniqueString(UStringVector &list, const UString &s);
+void AddUniqueString(UStringVector &list, const UString &s)
+{
+ FOR_VECTOR (i, list)
+ if (s.IsEqualTo_NoCase(list[i]))
+ return;
+ list.Add(s);
+}
+
+void CExtractDialog::OnOK()
+{
+ #ifndef Z7_SFX
+ int pathMode2 = kPathModeButtonsVals[_pathMode.GetCurSel()];
+ if (PathMode != NExtract::NPathMode::kCurPaths ||
+ pathMode2 != NExtract::NPathMode::kFullPaths)
+ PathMode = (NExtract::NPathMode::EEnum)pathMode2;
+
+ OverwriteMode = (NExtract::NOverwriteMode::EEnum)kOverwriteButtonsVals[_overwriteMode.GetCurSel()];
+
+ // _filesMode = (NExtractionDialog::NFilesMode::EEnum)GetFilesMode();
+
+ _passwordControl.GetText(Password);
+
+ #endif
+
+ #ifndef Z7_NO_REGISTRY
+
+ // GetButton_Bools(IDX_EXTRACT_ALT_STREAMS, AltStreams, _info.AltStreams);
+ GetButton_Bools(IDX_EXTRACT_NT_SECUR, NtSecurity, _info.NtSecurity);
+ GetButton_Bools(IDX_EXTRACT_ELIM_DUP, ElimDup, _info.ElimDup);
+
+ bool showPassword = IsShowPasswordChecked();
+ if (showPassword != _info.ShowPassword.Val)
+ {
+ _info.ShowPassword.Def = true;
+ _info.ShowPassword.Val = showPassword;
+ }
+
+ if (_info.PathMode != pathMode2)
+ {
+ _info.PathMode_Force = true;
+ _info.PathMode = (NExtract::NPathMode::EEnum)pathMode2;
+ /*
+ // we allow kAbsPaths in registry.
+ if (_info.PathMode == NExtract::NPathMode::kAbsPaths)
+ _info.PathMode = NExtract::NPathMode::kFullPaths;
+ */
+ }
+
+ if (!OverwriteMode_Force && _info.OverwriteMode != OverwriteMode)
+ _info.OverwriteMode_Force = true;
+ _info.OverwriteMode = OverwriteMode;
+
+
+ #else
+
+ ElimDup.Val = IsButtonCheckedBool(IDX_EXTRACT_ELIM_DUP);
+
+ #endif
+
+ UString s;
+
+ #ifdef Z7_NO_REGISTRY
+
+ _path.GetText(s);
+
+ #else
+
+ int currentItem = _path.GetCurSel();
+ if (currentItem == CB_ERR)
+ {
+ _path.GetText(s);
+ if (_path.GetCount() >= (int)kHistorySize)
+ currentItem = _path.GetCount() - 1;
+ }
+ else
+ _path.GetLBText(currentItem, s);
+
+ #endif
+
+ s.Trim();
+ NName::NormalizeDirPathPrefix(s);
+
+ #ifndef Z7_SFX
+
+ const bool splitDest = IsButtonCheckedBool(IDX_EXTRACT_NAME_ENABLE);
+ if (splitDest)
+ {
+ UString pathName;
+ _pathName.GetText(pathName);
+ pathName.Trim();
+ s += pathName;
+ NName::NormalizeDirPathPrefix(s);
+ }
+ if (splitDest != _info.SplitDest.Val)
+ {
+ _info.SplitDest.Def = true;
+ _info.SplitDest.Val = splitDest;
+ }
+
+ #endif
+
+ DirPath = s;
+
+ #ifndef Z7_NO_REGISTRY
+ _info.Paths.Clear();
+ #ifndef Z7_SFX
+ AddUniqueString(_info.Paths, s);
+ #endif
+ for (int i = 0; i < _path.GetCount(); i++)
+ if (i != currentItem)
+ {
+ UString sTemp;
+ _path.GetLBText(i, sTemp);
+ sTemp.Trim();
+ AddUniqueString(_info.Paths, sTemp);
+ }
+ _info.Save();
+ #endif
+
+ CModalDialog::OnOK();
+}
+
+#ifndef Z7_NO_REGISTRY
+#define kHelpTopic "fm/plugins/7-zip/extract.htm"
+void CExtractDialog::OnHelp()
+{
+ ShowHelpWindow(kHelpTopic);
+ CModalDialog::OnHelp();
+}
+#endif
diff --git a/CPP/7zip/UI/GUI/ExtractDialog.h b/CPP/7zip/UI/GUI/ExtractDialog.h
index 308c786..1565fb8 100644
--- a/CPP/7zip/UI/GUI/ExtractDialog.h
+++ b/CPP/7zip/UI/GUI/ExtractDialog.h
@@ -1,113 +1,113 @@
-// ExtractDialog.h
-
-#ifndef __EXTRACT_DIALOG_H
-#define __EXTRACT_DIALOG_H
-
-#include "ExtractDialogRes.h"
-
-#include "../../../Windows/Control/ComboBox.h"
-#include "../../../Windows/Control/Edit.h"
-
-#include "../Common/ExtractMode.h"
-
-#include "../FileManager/DialogSize.h"
-
-#ifndef NO_REGISTRY
-#include "../Common/ZipRegistry.h"
-#endif
-
-namespace NExtractionDialog
-{
- /*
- namespace NFilesMode
- {
- enum EEnum
- {
- kSelected,
- kAll,
- kSpecified
- };
- }
- */
-}
-
-class CExtractDialog: public NWindows::NControl::CModalDialog
-{
- #ifdef NO_REGISTRY
- NWindows::NControl::CDialogChildControl _path;
- #else
- NWindows::NControl::CComboBox _path;
- #endif
-
- #ifndef _SFX
- NWindows::NControl::CEdit _pathName;
- NWindows::NControl::CEdit _passwordControl;
- NWindows::NControl::CComboBox _pathMode;
- NWindows::NControl::CComboBox _overwriteMode;
- #endif
-
- #ifndef _SFX
- // int GetFilesMode() const;
- void UpdatePasswordControl();
- #endif
-
- void OnButtonSetPath();
-
- void CheckButton_TwoBools(UINT id, const CBoolPair &b1, const CBoolPair &b2);
- void GetButton_Bools(UINT id, CBoolPair &b1, CBoolPair &b2);
- virtual bool OnInit();
- virtual bool OnButtonClicked(int buttonID, HWND buttonHWND);
- virtual void OnOK();
-
- #ifndef NO_REGISTRY
-
- virtual void OnHelp();
-
- NExtract::CInfo _info;
-
- #endif
-
- bool IsShowPasswordChecked() const { return IsButtonCheckedBool(IDX_PASSWORD_SHOW); }
-public:
- // bool _enableSelectedFilesButton;
- // bool _enableFilesButton;
- // NExtractionDialog::NFilesMode::EEnum FilesMode;
-
- UString DirPath;
- UString ArcPath;
-
- #ifndef _SFX
- UString Password;
- #endif
- bool PathMode_Force;
- bool OverwriteMode_Force;
- NExtract::NPathMode::EEnum PathMode;
- NExtract::NOverwriteMode::EEnum OverwriteMode;
-
- #ifndef _SFX
- // CBoolPair AltStreams;
- CBoolPair NtSecurity;
- #endif
-
- CBoolPair ElimDup;
-
- INT_PTR Create(HWND aWndParent = 0)
- {
- #ifdef _SFX
- BIG_DIALOG_SIZE(240, 64);
- #else
- BIG_DIALOG_SIZE(300, 160);
- #endif
- return CModalDialog::Create(SIZED_DIALOG(IDD_EXTRACT), aWndParent);
- }
-
- CExtractDialog():
- PathMode_Force(false),
- OverwriteMode_Force(false)
- {
- ElimDup.Val = true;
- }
-
-};
-
-#endif
+// ExtractDialog.h
+
+#ifndef ZIP7_INC_EXTRACT_DIALOG_H
+#define ZIP7_INC_EXTRACT_DIALOG_H
+
+#include "ExtractDialogRes.h"
+
+#include "../../../Windows/Control/ComboBox.h"
+#include "../../../Windows/Control/Edit.h"
+
+#include "../Common/ExtractMode.h"
+
+#include "../FileManager/DialogSize.h"
+
+#ifndef Z7_NO_REGISTRY
+#include "../Common/ZipRegistry.h"
+#endif
+
+namespace NExtractionDialog
+{
+ /*
+ namespace NFilesMode
+ {
+ enum EEnum
+ {
+ kSelected,
+ kAll,
+ kSpecified
+ };
+ }
+ */
+}
+
+class CExtractDialog: public NWindows::NControl::CModalDialog
+{
+ #ifdef Z7_NO_REGISTRY
+ NWindows::NControl::CDialogChildControl _path;
+ #else
+ NWindows::NControl::CComboBox _path;
+ #endif
+
+ #ifndef Z7_SFX
+ NWindows::NControl::CEdit _pathName;
+ NWindows::NControl::CEdit _passwordControl;
+ NWindows::NControl::CComboBox _pathMode;
+ NWindows::NControl::CComboBox _overwriteMode;
+ #endif
+
+ #ifndef Z7_SFX
+ // int GetFilesMode() const;
+ void UpdatePasswordControl();
+ #endif
+
+ void OnButtonSetPath();
+
+ void CheckButton_TwoBools(UINT id, const CBoolPair &b1, const CBoolPair &b2);
+ void GetButton_Bools(UINT id, CBoolPair &b1, CBoolPair &b2);
+ virtual bool OnInit() Z7_override;
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND) Z7_override;
+ virtual void OnOK() Z7_override;
+
+ #ifndef Z7_NO_REGISTRY
+
+ virtual void OnHelp() Z7_override;
+
+ NExtract::CInfo _info;
+
+ #endif
+
+ bool IsShowPasswordChecked() const { return IsButtonCheckedBool(IDX_PASSWORD_SHOW); }
+public:
+ // bool _enableSelectedFilesButton;
+ // bool _enableFilesButton;
+ // NExtractionDialog::NFilesMode::EEnum FilesMode;
+
+ UString DirPath;
+ UString ArcPath;
+
+ #ifndef Z7_SFX
+ UString Password;
+ #endif
+ bool PathMode_Force;
+ bool OverwriteMode_Force;
+ NExtract::NPathMode::EEnum PathMode;
+ NExtract::NOverwriteMode::EEnum OverwriteMode;
+
+ #ifndef Z7_SFX
+ // CBoolPair AltStreams;
+ CBoolPair NtSecurity;
+ #endif
+
+ CBoolPair ElimDup;
+
+ INT_PTR Create(HWND aWndParent = NULL)
+ {
+ #ifdef Z7_SFX
+ BIG_DIALOG_SIZE(240, 64);
+ #else
+ BIG_DIALOG_SIZE(300, 160);
+ #endif
+ return CModalDialog::Create(SIZED_DIALOG(IDD_EXTRACT), aWndParent);
+ }
+
+ CExtractDialog():
+ PathMode_Force(false),
+ OverwriteMode_Force(false)
+ {
+ ElimDup.Val = true;
+ }
+
+};
+
+#endif
diff --git a/CPP/7zip/UI/GUI/ExtractDialog.rc b/CPP/7zip/UI/GUI/ExtractDialog.rc
index f5d6528..3728b96 100644
--- a/CPP/7zip/UI/GUI/ExtractDialog.rc
+++ b/CPP/7zip/UI/GUI/ExtractDialog.rc
@@ -1,98 +1,98 @@
-#include "ExtractDialogRes.h"
-#include "../../GuiCommon.rc"
-
-#define xc 336
-#define yc 168
-
-#undef g1xs
-#undef g2x
-#undef g2x2
-#undef g2xs
-#undef g2xs2
-
-#define g1xs 160
-
-#define gSpace 20
-#define g2x (m + g1xs + gSpace)
-#define g2x2 (g2x + m)
-#define g2xs (xc - g1xs - gSpace)
-#define g2xs2 (g2xs - m - m)
-
-#undef GROUP_Y_SIZE
-#ifdef UNDER_CE
-#define GROUP_Y_SIZE 8
-#else
-#define GROUP_Y_SIZE 56
-#endif
-
-IDD_EXTRACT DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
-CAPTION "Extract"
-BEGIN
- LTEXT "E&xtract to:", IDT_EXTRACT_EXTRACT_TO, m, m, xc, 8
- COMBOBOX IDC_EXTRACT_PATH, m, m + 12, xc - bxsDots - 12, 100, MY_COMBO_WITH_EDIT
- PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, m + 12 - 2, bxsDots, bys, WS_GROUP
-
- CONTROL "", IDX_EXTRACT_NAME_ENABLE, MY_CHECKBOX, m, m + 34, 12, 10
- EDITTEXT IDE_EXTRACT_NAME, m + 12 + 2, m + 32, g1xs - 12 - 2, 14, ES_AUTOHSCROLL
-
- LTEXT "Path mode:", IDT_EXTRACT_PATH_MODE, m, m + 52, g1xs, 8
- COMBOBOX IDC_EXTRACT_PATH_MODE, m, m + 64, g1xs, 140, MY_COMBO
-
- CONTROL "Eliminate duplication of root folder", IDX_EXTRACT_ELIM_DUP, MY_CHECKBOX,
- m, m + 84, g1xs, 10
-
- LTEXT "Overwrite mode:", IDT_EXTRACT_OVERWRITE_MODE, m, m + 104, g1xs, 8
- COMBOBOX IDC_EXTRACT_OVERWRITE_MODE, m, m + 116, g1xs, 140, MY_COMBO
-
-
- GROUPBOX "Password", IDG_PASSWORD, g2x, m + 36, g2xs, GROUP_Y_SIZE
- EDITTEXT IDE_EXTRACT_PASSWORD, g2x2, m + 50, g2xs2, 14, ES_PASSWORD | ES_AUTOHSCROLL
- CONTROL "Show Password", IDX_PASSWORD_SHOW, MY_CHECKBOX, g2x2, m + 72, g2xs2, 10
-
-// CONTROL "Restore alternate data streams", IDX_EXTRACT_ALT_STREAMS, MY_CHECKBOX,
-// g2x, m + 104, g2xs, 10
- CONTROL "Restore file security", IDX_EXTRACT_NT_SECUR, MY_CHECKBOX,
- g2x, m + 104, g2xs, 10
-
- DEFPUSHBUTTON "OK", IDOK, bx3, by, bxs, bys, WS_GROUP
- PUSHBUTTON "Cancel", IDCANCEL, bx2, by, bxs, bys
- PUSHBUTTON "Help", IDHELP, bx1, by, bxs, bys
-END
-
-
-#ifdef UNDER_CE
-
-#undef m
-#define m 4
-
-#undef xc
-#undef yc
-
-#define xc 152
-#define yc 128
-
-#undef g1xs
-
-#define g1xs 64
-
-IDD_EXTRACT_2 DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
-CAPTION "Extract"
-BEGIN
- LTEXT "E&xtract to:", IDT_EXTRACT_EXTRACT_TO, m, m, xc - bxsDots - 8, 8
- COMBOBOX IDC_EXTRACT_PATH, m, m + 12, xc - bxsDots - 8, 100, MY_COMBO_WITH_EDIT
- PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, m + 12 - 3, bxsDots, bys, WS_GROUP
-
- LTEXT "Path mode:", IDT_EXTRACT_PATH_MODE, m, m + 36, g1xs, 8
- COMBOBOX IDC_EXTRACT_PATH_MODE, m + g1xs, m + 36, xc - g1xs, 100, MY_COMBO
-
- LTEXT "Overwrite mode:", IDT_EXTRACT_OVERWRITE_MODE, m, m + 56, g1xs, 8
- COMBOBOX IDC_EXTRACT_OVERWRITE_MODE, m + g1xs, m + 56, xc - g1xs, 100, MY_COMBO
-
- LTEXT "Password", IDG_PASSWORD, m, m + 76, g1xs, 8
- EDITTEXT IDE_EXTRACT_PASSWORD, m + g1xs, m + 76, xc - g1xs, 14, ES_PASSWORD | ES_AUTOHSCROLL
- CONTROL "Show Password", IDX_PASSWORD_SHOW, MY_CHECKBOX, m, m + 92, xc, 10
-
- OK_CANCEL
-END
-
-#endif
+#include "ExtractDialogRes.h"
+#include "../../GuiCommon.rc"
+
+#define xc 336
+#define yc 168
+
+#undef g1xs
+#undef g2x
+#undef g2x2
+#undef g2xs
+#undef g2xs2
+
+#define g1xs 160
+
+#define gSpace 20
+#define g2x (m + g1xs + gSpace)
+#define g2x2 (g2x + m)
+#define g2xs (xc - g1xs - gSpace)
+#define g2xs2 (g2xs - m - m)
+
+#undef GROUP_Y_SIZE
+#ifdef UNDER_CE
+#define GROUP_Y_SIZE 8
+#else
+#define GROUP_Y_SIZE 56
+#endif
+
+IDD_EXTRACT DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
+CAPTION "Extract"
+BEGIN
+ LTEXT "E&xtract to:", IDT_EXTRACT_EXTRACT_TO, m, m, xc, 8
+ COMBOBOX IDC_EXTRACT_PATH, m, m + 12, xc - bxsDots - 12, 100, MY_COMBO_WITH_EDIT
+ PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, m + 12 - 2, bxsDots, bys, WS_GROUP
+
+ CONTROL "", IDX_EXTRACT_NAME_ENABLE, MY_CHECKBOX, m, m + 34, 12, 10
+ EDITTEXT IDE_EXTRACT_NAME, m + 12 + 2, m + 32, g1xs - 12 - 2, 14, ES_AUTOHSCROLL
+
+ LTEXT "Path mode:", IDT_EXTRACT_PATH_MODE, m, m + 52, g1xs, 8
+ COMBOBOX IDC_EXTRACT_PATH_MODE, m, m + 64, g1xs, 140, MY_COMBO
+
+ CONTROL "Eliminate duplication of root folder", IDX_EXTRACT_ELIM_DUP, MY_CHECKBOX,
+ m, m + 84, g1xs, 10
+
+ LTEXT "Overwrite mode:", IDT_EXTRACT_OVERWRITE_MODE, m, m + 104, g1xs, 8
+ COMBOBOX IDC_EXTRACT_OVERWRITE_MODE, m, m + 116, g1xs, 140, MY_COMBO
+
+
+ GROUPBOX "Password", IDG_PASSWORD, g2x, m + 36, g2xs, GROUP_Y_SIZE
+ EDITTEXT IDE_EXTRACT_PASSWORD, g2x2, m + 50, g2xs2, 14, ES_PASSWORD | ES_AUTOHSCROLL
+ CONTROL "Show Password", IDX_PASSWORD_SHOW, MY_CHECKBOX, g2x2, m + 72, g2xs2, 10
+
+// CONTROL "Restore alternate data streams", IDX_EXTRACT_ALT_STREAMS, MY_CHECKBOX,
+// g2x, m + 104, g2xs, 10
+ CONTROL "Restore file security", IDX_EXTRACT_NT_SECUR, MY_CHECKBOX,
+ g2x, m + 104, g2xs, 10
+
+ DEFPUSHBUTTON "OK", IDOK, bx3, by, bxs, bys, WS_GROUP
+ PUSHBUTTON "Cancel", IDCANCEL, bx2, by, bxs, bys
+ PUSHBUTTON "Help", IDHELP, bx1, by, bxs, bys
+END
+
+
+#ifdef UNDER_CE
+
+#undef m
+#define m 4
+
+#undef xc
+#undef yc
+
+#define xc 152
+#define yc 128
+
+#undef g1xs
+
+#define g1xs 64
+
+IDD_EXTRACT_2 DIALOG 0, 0, xs, ys MY_MODAL_DIALOG_STYLE MY_FONT
+CAPTION "Extract"
+BEGIN
+ LTEXT "E&xtract to:", IDT_EXTRACT_EXTRACT_TO, m, m, xc - bxsDots - 8, 8
+ COMBOBOX IDC_EXTRACT_PATH, m, m + 12, xc - bxsDots - 8, 100, MY_COMBO_WITH_EDIT
+ PUSHBUTTON "...", IDB_EXTRACT_SET_PATH, xs - m - bxsDots, m + 12 - 3, bxsDots, bys, WS_GROUP
+
+ LTEXT "Path mode:", IDT_EXTRACT_PATH_MODE, m, m + 36, g1xs, 8
+ COMBOBOX IDC_EXTRACT_PATH_MODE, m + g1xs, m + 36, xc - g1xs, 100, MY_COMBO
+
+ LTEXT "Overwrite mode:", IDT_EXTRACT_OVERWRITE_MODE, m, m + 56, g1xs, 8
+ COMBOBOX IDC_EXTRACT_OVERWRITE_MODE, m + g1xs, m + 56, xc - g1xs, 100, MY_COMBO
+
+ LTEXT "Password", IDG_PASSWORD, m, m + 76, g1xs, 8
+ EDITTEXT IDE_EXTRACT_PASSWORD, m + g1xs, m + 76, xc - g1xs, 14, ES_PASSWORD | ES_AUTOHSCROLL
+ CONTROL "Show Password", IDX_PASSWORD_SHOW, MY_CHECKBOX, m, m + 92, xc, 10
+
+ OK_CANCEL
+END
+
+#endif
diff --git a/CPP/7zip/UI/GUI/ExtractDialogRes.h b/CPP/7zip/UI/GUI/ExtractDialogRes.h
index e198796..ed12bfb 100644
--- a/CPP/7zip/UI/GUI/ExtractDialogRes.h
+++ b/CPP/7zip/UI/GUI/ExtractDialogRes.h
@@ -1,24 +1,24 @@
-#define IDD_EXTRACT 3400
-#define IDD_EXTRACT_2 13400
-
-#define IDC_EXTRACT_PATH 100
-#define IDB_EXTRACT_SET_PATH 101
-#define IDC_EXTRACT_PATH_MODE 102
-#define IDC_EXTRACT_OVERWRITE_MODE 103
-
-#define IDE_EXTRACT_PASSWORD 120
-
-#define IDE_EXTRACT_NAME 130
-#define IDX_EXTRACT_NAME_ENABLE 131
-
-
-#define IDT_EXTRACT_EXTRACT_TO 3401
-#define IDT_EXTRACT_PATH_MODE 3410
-#define IDT_EXTRACT_OVERWRITE_MODE 3420
-
-#define IDX_EXTRACT_ELIM_DUP 3430
-#define IDX_EXTRACT_NT_SECUR 3431
-// #define IDX_EXTRACT_ALT_STREAMS 3432
-
-#define IDX_PASSWORD_SHOW 3803
-#define IDG_PASSWORD 3807
+#define IDD_EXTRACT 3400
+#define IDD_EXTRACT_2 13400
+
+#define IDC_EXTRACT_PATH 100
+#define IDB_EXTRACT_SET_PATH 101
+#define IDC_EXTRACT_PATH_MODE 102
+#define IDC_EXTRACT_OVERWRITE_MODE 103
+
+#define IDE_EXTRACT_PASSWORD 120
+
+#define IDE_EXTRACT_NAME 130
+#define IDX_EXTRACT_NAME_ENABLE 131
+
+
+#define IDT_EXTRACT_EXTRACT_TO 3401
+#define IDT_EXTRACT_PATH_MODE 3410
+#define IDT_EXTRACT_OVERWRITE_MODE 3420
+
+#define IDX_EXTRACT_ELIM_DUP 3430
+#define IDX_EXTRACT_NT_SECUR 3431
+// #define IDX_EXTRACT_ALT_STREAMS 3432
+
+#define IDX_PASSWORD_SHOW 3803
+#define IDG_PASSWORD 3807
diff --git a/CPP/7zip/UI/GUI/ExtractGUI.cpp b/CPP/7zip/UI/GUI/ExtractGUI.cpp
index 99db743..fdf3cc7 100644
--- a/CPP/7zip/UI/GUI/ExtractGUI.cpp
+++ b/CPP/7zip/UI/GUI/ExtractGUI.cpp
@@ -1,280 +1,297 @@
-// ExtractGUI.cpp
-
-#include "StdAfx.h"
-
-#include "../../../Common/IntToString.h"
-#include "../../../Common/StringConvert.h"
-
-#include "../../../Windows/FileDir.h"
-#include "../../../Windows/FileFind.h"
-#include "../../../Windows/FileName.h"
-#include "../../../Windows/Thread.h"
-
-#include "../FileManager/ExtractCallback.h"
-#include "../FileManager/FormatUtils.h"
-#include "../FileManager/LangUtils.h"
-#include "../FileManager/resourceGui.h"
-#include "../FileManager/OverwriteDialogRes.h"
-
-#include "../Common/ArchiveExtractCallback.h"
-#include "../Common/PropIDUtils.h"
-
-#include "../Explorer/MyMessages.h"
-
-#include "resource2.h"
-#include "ExtractRes.h"
-
-#include "ExtractDialog.h"
-#include "ExtractGUI.h"
-#include "HashGUI.h"
-
-#include "../FileManager/PropertyNameRes.h"
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NDir;
-
-static const wchar_t * const kIncorrectOutDir = L"Incorrect output directory path";
-
-#ifndef _SFX
-
-static void AddValuePair(UString &s, UINT resourceID, UInt64 value, bool addColon = true)
-{
- AddLangString(s, resourceID);
- if (addColon)
- s += ':';
- s.Add_Space();
- char sz[32];
- ConvertUInt64ToString(value, sz);
- s += sz;
- s.Add_LF();
-}
-
-static void AddSizePair(UString &s, UINT resourceID, UInt64 value)
-{
- AddLangString(s, resourceID);
- s += ": ";
- AddSizeValue(s, value);
- s.Add_LF();
-}
-
-#endif
-
-class CThreadExtracting: public CProgressThreadVirt
-{
- HRESULT ProcessVirt();
-public:
- CCodecs *codecs;
- CExtractCallbackImp *ExtractCallbackSpec;
- const CObjectVector<COpenType> *FormatIndices;
- const CIntVector *ExcludedFormatIndices;
-
- UStringVector *ArchivePaths;
- UStringVector *ArchivePathsFull;
- const NWildcard::CCensorNode *WildcardCensor;
- const CExtractOptions *Options;
-
- #ifndef _SFX
- CHashBundle *HashBundle;
- virtual void ProcessWasFinished_GuiVirt();
- #endif
-
- CMyComPtr<IExtractCallbackUI> ExtractCallback;
- UString Title;
-
- CPropNameValPairs Pairs;
-};
-
-
-#ifndef _SFX
-void CThreadExtracting::ProcessWasFinished_GuiVirt()
-{
- if (HashBundle && !Pairs.IsEmpty())
- ShowHashResults(Pairs, *this);
-}
-#endif
-
-HRESULT CThreadExtracting::ProcessVirt()
-{
- CDecompressStat Stat;
-
- #ifndef _SFX
- /*
- if (HashBundle)
- HashBundle->Init();
- */
- #endif
-
- HRESULT res = Extract(codecs,
- *FormatIndices, *ExcludedFormatIndices,
- *ArchivePaths, *ArchivePathsFull,
- *WildcardCensor, *Options, ExtractCallbackSpec, ExtractCallback,
- #ifndef _SFX
- HashBundle,
- #endif
- FinalMessage.ErrorMessage.Message, Stat);
-
- #ifndef _SFX
- if (res == S_OK && ExtractCallbackSpec->IsOK())
- {
- if (HashBundle)
- {
- AddValuePair(Pairs, IDS_ARCHIVES_COLON, Stat.NumArchives);
- AddSizeValuePair(Pairs, IDS_PROP_PACKED_SIZE, Stat.PackSize);
- AddHashBundleRes(Pairs, *HashBundle);
- }
- else if (Options->TestMode)
- {
- UString s;
-
- AddValuePair(s, IDS_ARCHIVES_COLON, Stat.NumArchives, false);
- AddSizePair(s, IDS_PROP_PACKED_SIZE, Stat.PackSize);
-
- if (Stat.NumFolders != 0)
- AddValuePair(s, IDS_PROP_FOLDERS, Stat.NumFolders);
- AddValuePair(s, IDS_PROP_FILES, Stat.NumFiles);
- AddSizePair(s, IDS_PROP_SIZE, Stat.UnpackSize);
- if (Stat.NumAltStreams != 0)
- {
- s.Add_LF();
- AddValuePair(s, IDS_PROP_NUM_ALT_STREAMS, Stat.NumAltStreams);
- AddSizePair(s, IDS_PROP_ALT_STREAMS_SIZE, Stat.AltStreams_UnpackSize);
- }
- s.Add_LF();
- AddLangString(s, IDS_MESSAGE_NO_ERRORS);
- FinalMessage.OkMessage.Title = Title;
- FinalMessage.OkMessage.Message = s;
- }
- }
- #endif
-
- return res;
-}
-
-
-
-HRESULT ExtractGUI(
- CCodecs *codecs,
- const CObjectVector<COpenType> &formatIndices,
- const CIntVector &excludedFormatIndices,
- UStringVector &archivePaths,
- UStringVector &archivePathsFull,
- const NWildcard::CCensorNode &wildcardCensor,
- CExtractOptions &options,
- #ifndef _SFX
- CHashBundle *hb,
- #endif
- bool showDialog,
- bool &messageWasDisplayed,
- CExtractCallbackImp *extractCallback,
- HWND hwndParent)
-{
- messageWasDisplayed = false;
-
- CThreadExtracting extracter;
- extracter.codecs = codecs;
- extracter.FormatIndices = &formatIndices;
- extracter.ExcludedFormatIndices = &excludedFormatIndices;
-
- if (!options.TestMode)
- {
- FString outputDir = options.OutputDir;
- #ifndef UNDER_CE
- if (outputDir.IsEmpty())
- GetCurrentDir(outputDir);
- #endif
- if (showDialog)
- {
- CExtractDialog dialog;
- FString outputDirFull;
- if (!MyGetFullPathName(outputDir, outputDirFull))
- {
- ShowErrorMessage(kIncorrectOutDir);
- messageWasDisplayed = true;
- return E_FAIL;
- }
- NName::NormalizeDirPathPrefix(outputDirFull);
-
- dialog.DirPath = fs2us(outputDirFull);
-
- dialog.OverwriteMode = options.OverwriteMode;
- dialog.OverwriteMode_Force = options.OverwriteMode_Force;
- dialog.PathMode = options.PathMode;
- dialog.PathMode_Force = options.PathMode_Force;
- dialog.ElimDup = options.ElimDup;
-
- if (archivePathsFull.Size() == 1)
- dialog.ArcPath = archivePathsFull[0];
-
- #ifndef _SFX
- // dialog.AltStreams = options.NtOptions.AltStreams;
- dialog.NtSecurity = options.NtOptions.NtSecurity;
- if (extractCallback->PasswordIsDefined)
- dialog.Password = extractCallback->Password;
- #endif
-
- if (dialog.Create(hwndParent) != IDOK)
- return E_ABORT;
-
- outputDir = us2fs(dialog.DirPath);
-
- options.OverwriteMode = dialog.OverwriteMode;
- options.PathMode = dialog.PathMode;
- options.ElimDup = dialog.ElimDup;
-
- #ifndef _SFX
- // options.NtOptions.AltStreams = dialog.AltStreams;
- options.NtOptions.NtSecurity = dialog.NtSecurity;
- extractCallback->Password = dialog.Password;
- extractCallback->PasswordIsDefined = !dialog.Password.IsEmpty();
- #endif
- }
- if (!MyGetFullPathName(outputDir, options.OutputDir))
- {
- ShowErrorMessage(kIncorrectOutDir);
- messageWasDisplayed = true;
- return E_FAIL;
- }
- NName::NormalizeDirPathPrefix(options.OutputDir);
-
- /*
- if (!CreateComplexDirectory(options.OutputDir))
- {
- UString s = GetUnicodeString(NError::MyFormatMessage(GetLastError()));
- UString s2 = MyFormatNew(IDS_CANNOT_CREATE_FOLDER,
- #ifdef LANG
- 0x02000603,
- #endif
- options.OutputDir);
- s2.Add_LF();
- s2 += s;
- MyMessageBox(s2);
- return E_FAIL;
- }
- */
- }
-
- UString title = LangString(options.TestMode ? IDS_PROGRESS_TESTING : IDS_PROGRESS_EXTRACTING);
-
- extracter.Title = title;
- extracter.ExtractCallbackSpec = extractCallback;
- extracter.ExtractCallbackSpec->ProgressDialog = &extracter;
- extracter.ExtractCallback = extractCallback;
- extracter.ExtractCallbackSpec->Init();
-
- extracter.CompressingMode = false;
-
- extracter.ArchivePaths = &archivePaths;
- extracter.ArchivePathsFull = &archivePathsFull;
- extracter.WildcardCensor = &wildcardCensor;
- extracter.Options = &options;
- #ifndef _SFX
- extracter.HashBundle = hb;
- #endif
-
- extracter.IconID = IDI_ICON;
-
- RINOK(extracter.Create(title, hwndParent));
- messageWasDisplayed = extracter.ThreadFinishedOK && extracter.MessagesDisplayed;
- return extracter.Result;
-}
+// ExtractGUI.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileFind.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/Thread.h"
+
+#include "../FileManager/ExtractCallback.h"
+#include "../FileManager/FormatUtils.h"
+#include "../FileManager/LangUtils.h"
+#include "../FileManager/resourceGui.h"
+#include "../FileManager/OverwriteDialogRes.h"
+
+#include "../Common/ArchiveExtractCallback.h"
+#include "../Common/PropIDUtils.h"
+
+#include "../Explorer/MyMessages.h"
+
+#include "resource2.h"
+#include "ExtractRes.h"
+
+#include "ExtractDialog.h"
+#include "ExtractGUI.h"
+#include "HashGUI.h"
+
+#include "../FileManager/PropertyNameRes.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+static const wchar_t * const kIncorrectOutDir = L"Incorrect output directory path";
+
+#ifndef Z7_SFX
+
+static void AddValuePair(UString &s, UINT resourceID, UInt64 value, bool addColon = true)
+{
+ AddLangString(s, resourceID);
+ if (addColon)
+ s += ':';
+ s.Add_Space();
+ s.Add_UInt64(value);
+ s.Add_LF();
+}
+
+static void AddSizePair(UString &s, UINT resourceID, UInt64 value)
+{
+ AddLangString(s, resourceID);
+ s += ": ";
+ AddSizeValue(s, value);
+ s.Add_LF();
+}
+
+#endif
+
+class CThreadExtracting: public CProgressThreadVirt
+{
+ HRESULT ProcessVirt() Z7_override;
+public:
+ /*
+ #ifdef Z7_EXTERNAL_CODECS
+ const CExternalCodecs *externalCodecs;
+ #endif
+ */
+
+ CCodecs *codecs;
+ CExtractCallbackImp *ExtractCallbackSpec;
+ const CObjectVector<COpenType> *FormatIndices;
+ const CIntVector *ExcludedFormatIndices;
+
+ UStringVector *ArchivePaths;
+ UStringVector *ArchivePathsFull;
+ const NWildcard::CCensorNode *WildcardCensor;
+ const CExtractOptions *Options;
+
+ #ifndef Z7_SFX
+ CHashBundle *HashBundle;
+ virtual void ProcessWasFinished_GuiVirt() Z7_override;
+ #endif
+
+ CMyComPtr<IFolderArchiveExtractCallback> FolderArchiveExtractCallback;
+ UString Title;
+
+ CPropNameValPairs Pairs;
+};
+
+
+#ifndef Z7_SFX
+void CThreadExtracting::ProcessWasFinished_GuiVirt()
+{
+ if (HashBundle && !Pairs.IsEmpty())
+ ShowHashResults(Pairs, *this);
+}
+#endif
+
+HRESULT CThreadExtracting::ProcessVirt()
+{
+ CDecompressStat Stat;
+
+ #ifndef Z7_SFX
+ /*
+ if (HashBundle)
+ HashBundle->Init();
+ */
+ #endif
+
+ HRESULT res = Extract(
+ /*
+ #ifdef Z7_EXTERNAL_CODECS
+ externalCodecs,
+ #endif
+ */
+ codecs,
+ *FormatIndices, *ExcludedFormatIndices,
+ *ArchivePaths, *ArchivePathsFull,
+ *WildcardCensor, *Options,
+ ExtractCallbackSpec, ExtractCallbackSpec, FolderArchiveExtractCallback,
+ #ifndef Z7_SFX
+ HashBundle,
+ #endif
+ FinalMessage.ErrorMessage.Message, Stat);
+
+ #ifndef Z7_SFX
+ if (res == S_OK && ExtractCallbackSpec->IsOK())
+ {
+ if (HashBundle)
+ {
+ AddValuePair(Pairs, IDS_ARCHIVES_COLON, Stat.NumArchives);
+ AddSizeValuePair(Pairs, IDS_PROP_PACKED_SIZE, Stat.PackSize);
+ AddHashBundleRes(Pairs, *HashBundle);
+ }
+ else if (Options->TestMode)
+ {
+ UString s;
+
+ AddValuePair(s, IDS_ARCHIVES_COLON, Stat.NumArchives, false);
+ AddSizePair(s, IDS_PROP_PACKED_SIZE, Stat.PackSize);
+
+ if (Stat.NumFolders != 0)
+ AddValuePair(s, IDS_PROP_FOLDERS, Stat.NumFolders);
+ AddValuePair(s, IDS_PROP_FILES, Stat.NumFiles);
+ AddSizePair(s, IDS_PROP_SIZE, Stat.UnpackSize);
+ if (Stat.NumAltStreams != 0)
+ {
+ s.Add_LF();
+ AddValuePair(s, IDS_PROP_NUM_ALT_STREAMS, Stat.NumAltStreams);
+ AddSizePair(s, IDS_PROP_ALT_STREAMS_SIZE, Stat.AltStreams_UnpackSize);
+ }
+ s.Add_LF();
+ AddLangString(s, IDS_MESSAGE_NO_ERRORS);
+ FinalMessage.OkMessage.Title = Title;
+ FinalMessage.OkMessage.Message = s;
+ }
+ }
+ #endif
+
+ return res;
+}
+
+
+
+HRESULT ExtractGUI(
+ // DECL_EXTERNAL_CODECS_LOC_VARS
+ CCodecs *codecs,
+ const CObjectVector<COpenType> &formatIndices,
+ const CIntVector &excludedFormatIndices,
+ UStringVector &archivePaths,
+ UStringVector &archivePathsFull,
+ const NWildcard::CCensorNode &wildcardCensor,
+ CExtractOptions &options,
+ #ifndef Z7_SFX
+ CHashBundle *hb,
+ #endif
+ bool showDialog,
+ bool &messageWasDisplayed,
+ CExtractCallbackImp *extractCallback,
+ HWND hwndParent)
+{
+ messageWasDisplayed = false;
+
+ CThreadExtracting extracter;
+ /*
+ #ifdef Z7_EXTERNAL_CODECS
+ extracter.externalCodecs = _externalCodecs;
+ #endif
+ */
+ extracter.codecs = codecs;
+ extracter.FormatIndices = &formatIndices;
+ extracter.ExcludedFormatIndices = &excludedFormatIndices;
+
+ if (!options.TestMode)
+ {
+ FString outputDir = options.OutputDir;
+ #ifndef UNDER_CE
+ if (outputDir.IsEmpty())
+ GetCurrentDir(outputDir);
+ #endif
+ if (showDialog)
+ {
+ CExtractDialog dialog;
+ FString outputDirFull;
+ if (!MyGetFullPathName(outputDir, outputDirFull))
+ {
+ ShowErrorMessage(kIncorrectOutDir);
+ messageWasDisplayed = true;
+ return E_FAIL;
+ }
+ NName::NormalizeDirPathPrefix(outputDirFull);
+
+ dialog.DirPath = fs2us(outputDirFull);
+
+ dialog.OverwriteMode = options.OverwriteMode;
+ dialog.OverwriteMode_Force = options.OverwriteMode_Force;
+ dialog.PathMode = options.PathMode;
+ dialog.PathMode_Force = options.PathMode_Force;
+ dialog.ElimDup = options.ElimDup;
+
+ if (archivePathsFull.Size() == 1)
+ dialog.ArcPath = archivePathsFull[0];
+
+ #ifndef Z7_SFX
+ // dialog.AltStreams = options.NtOptions.AltStreams;
+ dialog.NtSecurity = options.NtOptions.NtSecurity;
+ if (extractCallback->PasswordIsDefined)
+ dialog.Password = extractCallback->Password;
+ #endif
+
+ if (dialog.Create(hwndParent) != IDOK)
+ return E_ABORT;
+
+ outputDir = us2fs(dialog.DirPath);
+
+ options.OverwriteMode = dialog.OverwriteMode;
+ options.PathMode = dialog.PathMode;
+ options.ElimDup = dialog.ElimDup;
+
+ #ifndef Z7_SFX
+ // options.NtOptions.AltStreams = dialog.AltStreams;
+ options.NtOptions.NtSecurity = dialog.NtSecurity;
+ extractCallback->Password = dialog.Password;
+ extractCallback->PasswordIsDefined = !dialog.Password.IsEmpty();
+ #endif
+ }
+ if (!MyGetFullPathName(outputDir, options.OutputDir))
+ {
+ ShowErrorMessage(kIncorrectOutDir);
+ messageWasDisplayed = true;
+ return E_FAIL;
+ }
+ NName::NormalizeDirPathPrefix(options.OutputDir);
+
+ /*
+ if (!CreateComplexDirectory(options.OutputDir))
+ {
+ UString s = GetUnicodeString(NError::MyFormatMessage(GetLastError()));
+ UString s2 = MyFormatNew(IDS_CANNOT_CREATE_FOLDER,
+ #ifdef Z7_LANG
+ 0x02000603,
+ #endif
+ options.OutputDir);
+ s2.Add_LF();
+ s2 += s;
+ MyMessageBox(s2);
+ return E_FAIL;
+ }
+ */
+ }
+
+ UString title = LangString(options.TestMode ? IDS_PROGRESS_TESTING : IDS_PROGRESS_EXTRACTING);
+
+ extracter.Title = title;
+ extracter.ExtractCallbackSpec = extractCallback;
+ extracter.ExtractCallbackSpec->ProgressDialog = &extracter;
+ extracter.FolderArchiveExtractCallback = extractCallback;
+ extracter.ExtractCallbackSpec->Init();
+
+ extracter.CompressingMode = false;
+
+ extracter.ArchivePaths = &archivePaths;
+ extracter.ArchivePathsFull = &archivePathsFull;
+ extracter.WildcardCensor = &wildcardCensor;
+ extracter.Options = &options;
+ #ifndef Z7_SFX
+ extracter.HashBundle = hb;
+ #endif
+
+ extracter.IconID = IDI_ICON;
+
+ RINOK(extracter.Create(title, hwndParent))
+ messageWasDisplayed = extracter.ThreadFinishedOK && extracter.MessagesDisplayed;
+ return extracter.Result;
+}
diff --git a/CPP/7zip/UI/GUI/ExtractGUI.h b/CPP/7zip/UI/GUI/ExtractGUI.h
index 466e524..13ca6ab 100644
--- a/CPP/7zip/UI/GUI/ExtractGUI.h
+++ b/CPP/7zip/UI/GUI/ExtractGUI.h
@@ -1,38 +1,39 @@
-// GUI/ExtractGUI.h
-
-#ifndef __EXTRACT_GUI_H
-#define __EXTRACT_GUI_H
-
-#include "../Common/Extract.h"
-
-#include "../FileManager/ExtractCallback.h"
-
-/*
- RESULT can be S_OK, even if there are errors!!!
- if RESULT == S_OK, check extractCallback->IsOK() after ExtractGUI().
-
- RESULT = E_ABORT - user break.
- RESULT != E_ABORT:
- {
- messageWasDisplayed = true - message was displayed already.
- messageWasDisplayed = false - there was some internal error, so you must show error message.
- }
-*/
-
-HRESULT ExtractGUI(
- CCodecs *codecs,
- const CObjectVector<COpenType> &formatIndices,
- const CIntVector &excludedFormatIndices,
- UStringVector &archivePaths,
- UStringVector &archivePathsFull,
- const NWildcard::CCensorNode &wildcardCensor,
- CExtractOptions &options,
- #ifndef _SFX
- CHashBundle *hb,
- #endif
- bool showDialog,
- bool &messageWasDisplayed,
- CExtractCallbackImp *extractCallback,
- HWND hwndParent = NULL);
-
-#endif
+// GUI/ExtractGUI.h
+
+#ifndef ZIP7_INC_EXTRACT_GUI_H
+#define ZIP7_INC_EXTRACT_GUI_H
+
+#include "../Common/Extract.h"
+
+#include "../FileManager/ExtractCallback.h"
+
+/*
+ RESULT can be S_OK, even if there are errors!!!
+ if RESULT == S_OK, check extractCallback->IsOK() after ExtractGUI().
+
+ RESULT = E_ABORT - user break.
+ RESULT != E_ABORT:
+ {
+ messageWasDisplayed = true - message was displayed already.
+ messageWasDisplayed = false - there was some internal error, so you must show error message.
+ }
+*/
+
+HRESULT ExtractGUI(
+ // DECL_EXTERNAL_CODECS_LOC_VARS
+ CCodecs *codecs,
+ const CObjectVector<COpenType> &formatIndices,
+ const CIntVector &excludedFormatIndices,
+ UStringVector &archivePaths,
+ UStringVector &archivePathsFull,
+ const NWildcard::CCensorNode &wildcardCensor,
+ CExtractOptions &options,
+ #ifndef Z7_SFX
+ CHashBundle *hb,
+ #endif
+ bool showDialog,
+ bool &messageWasDisplayed,
+ CExtractCallbackImp *extractCallback,
+ HWND hwndParent = NULL);
+
+#endif
diff --git a/CPP/7zip/UI/GUI/ExtractRes.h b/CPP/7zip/UI/GUI/ExtractRes.h
index 6437d95..634ba6b 100644
--- a/CPP/7zip/UI/GUI/ExtractRes.h
+++ b/CPP/7zip/UI/GUI/ExtractRes.h
@@ -1,51 +1,51 @@
-#define IDS_MEM_ERROR 3000
-
-#define IDS_CANNOT_CREATE_FOLDER 3003
-#define IDS_UPDATE_NOT_SUPPORTED 3004
-#define IDS_CANT_OPEN_ARCHIVE 3005
-#define IDS_CANT_OPEN_ENCRYPTED_ARCHIVE 3006
-#define IDS_UNSUPPORTED_ARCHIVE_TYPE 3007
-
-#define IDS_CANT_OPEN_AS_TYPE 3017
-#define IDS_IS_OPEN_AS_TYPE 3018
-#define IDS_IS_OPEN_WITH_OFFSET 3019
-
-#define IDS_PROGRESS_EXTRACTING 3300
-
-#define IDS_PROGRESS_SKIPPING 3325
-
-#define IDS_EXTRACT_SET_FOLDER 3402
-
-#define IDS_EXTRACT_PATHS_FULL 3411
-#define IDS_EXTRACT_PATHS_NO 3412
-#define IDS_EXTRACT_PATHS_ABS 3413
-#define IDS_PATH_MODE_RELAT 3414
-
-#define IDS_EXTRACT_OVERWRITE_ASK 3421
-#define IDS_EXTRACT_OVERWRITE_WITHOUT_PROMPT 3422
-#define IDS_EXTRACT_OVERWRITE_SKIP_EXISTING 3423
-#define IDS_EXTRACT_OVERWRITE_RENAME 3424
-#define IDS_EXTRACT_OVERWRITE_RENAME_EXISTING 3425
-
-#define IDS_EXTRACT_MESSAGE_UNSUPPORTED_METHOD 3700
-#define IDS_EXTRACT_MESSAGE_DATA_ERROR 3701
-#define IDS_EXTRACT_MESSAGE_CRC_ERROR 3702
-#define IDS_EXTRACT_MESSAGE_DATA_ERROR_ENCRYPTED 3703
-#define IDS_EXTRACT_MESSAGE_CRC_ERROR_ENCRYPTED 3704
-
-#define IDS_EXTRACT_MSG_WRONG_PSW_GUESS 3710
-// #define IDS_EXTRACT_MSG_ENCRYPTED 3711
-
-#define IDS_EXTRACT_MSG_UNSUPPORTED_METHOD 3721
-#define IDS_EXTRACT_MSG_DATA_ERROR 3722
-#define IDS_EXTRACT_MSG_CRC_ERROR 3723
-#define IDS_EXTRACT_MSG_UNAVAILABLE_DATA 3724
-#define IDS_EXTRACT_MSG_UEXPECTED_END 3725
-#define IDS_EXTRACT_MSG_DATA_AFTER_END 3726
-#define IDS_EXTRACT_MSG_IS_NOT_ARC 3727
-#define IDS_EXTRACT_MSG_HEADERS_ERROR 3728
-#define IDS_EXTRACT_MSG_WRONG_PSW_CLAIM 3729
-
-#define IDS_OPEN_MSG_UNAVAILABLE_START 3763
-#define IDS_OPEN_MSG_UNCONFIRMED_START 3764
-#define IDS_OPEN_MSG_UNSUPPORTED_FEATURE 3768
+#define IDS_MEM_ERROR 3000
+
+#define IDS_CANNOT_CREATE_FOLDER 3003
+#define IDS_UPDATE_NOT_SUPPORTED 3004
+#define IDS_CANT_OPEN_ARCHIVE 3005
+#define IDS_CANT_OPEN_ENCRYPTED_ARCHIVE 3006
+#define IDS_UNSUPPORTED_ARCHIVE_TYPE 3007
+
+#define IDS_CANT_OPEN_AS_TYPE 3017
+#define IDS_IS_OPEN_AS_TYPE 3018
+#define IDS_IS_OPEN_WITH_OFFSET 3019
+
+#define IDS_PROGRESS_EXTRACTING 3300
+
+#define IDS_PROGRESS_SKIPPING 3325
+
+#define IDS_EXTRACT_SET_FOLDER 3402
+
+#define IDS_EXTRACT_PATHS_FULL 3411
+#define IDS_EXTRACT_PATHS_NO 3412
+#define IDS_EXTRACT_PATHS_ABS 3413
+#define IDS_PATH_MODE_RELAT 3414
+
+#define IDS_EXTRACT_OVERWRITE_ASK 3421
+#define IDS_EXTRACT_OVERWRITE_WITHOUT_PROMPT 3422
+#define IDS_EXTRACT_OVERWRITE_SKIP_EXISTING 3423
+#define IDS_EXTRACT_OVERWRITE_RENAME 3424
+#define IDS_EXTRACT_OVERWRITE_RENAME_EXISTING 3425
+
+#define IDS_EXTRACT_MESSAGE_UNSUPPORTED_METHOD 3700
+#define IDS_EXTRACT_MESSAGE_DATA_ERROR 3701
+#define IDS_EXTRACT_MESSAGE_CRC_ERROR 3702
+#define IDS_EXTRACT_MESSAGE_DATA_ERROR_ENCRYPTED 3703
+#define IDS_EXTRACT_MESSAGE_CRC_ERROR_ENCRYPTED 3704
+
+#define IDS_EXTRACT_MSG_WRONG_PSW_GUESS 3710
+// #define IDS_EXTRACT_MSG_ENCRYPTED 3711
+
+#define IDS_EXTRACT_MSG_UNSUPPORTED_METHOD 3721
+#define IDS_EXTRACT_MSG_DATA_ERROR 3722
+#define IDS_EXTRACT_MSG_CRC_ERROR 3723
+#define IDS_EXTRACT_MSG_UNAVAILABLE_DATA 3724
+#define IDS_EXTRACT_MSG_UEXPECTED_END 3725
+#define IDS_EXTRACT_MSG_DATA_AFTER_END 3726
+#define IDS_EXTRACT_MSG_IS_NOT_ARC 3727
+#define IDS_EXTRACT_MSG_HEADERS_ERROR 3728
+#define IDS_EXTRACT_MSG_WRONG_PSW_CLAIM 3729
+
+#define IDS_OPEN_MSG_UNAVAILABLE_START 3763
+#define IDS_OPEN_MSG_UNCONFIRMED_START 3764
+#define IDS_OPEN_MSG_UNSUPPORTED_FEATURE 3768
diff --git a/CPP/7zip/UI/GUI/FM.ico b/CPP/7zip/UI/GUI/FM.ico
new file mode 100644
index 0000000..3a0a34d
--- /dev/null
+++ b/CPP/7zip/UI/GUI/FM.ico
Binary files differ
diff --git a/CPP/7zip/UI/GUI/GUI.cpp b/CPP/7zip/UI/GUI/GUI.cpp
new file mode 100644
index 0000000..37e637b
--- /dev/null
+++ b/CPP/7zip/UI/GUI/GUI.cpp
@@ -0,0 +1,478 @@
+// GUI.cpp
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#include "../../../../C/DllSecur.h"
+#endif
+
+#include "../../../Common/MyWindows.h"
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <shlwapi.h>
+#else
+#include <Shlwapi.h>
+#endif
+
+#include "../../../Common/MyInitGuid.h"
+
+#include "../../../Common/CommandLineParser.h"
+#include "../../../Common/MyException.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/NtCheck.h"
+
+#include "../Common/ArchiveCommandLine.h"
+#include "../Common/ExitCode.h"
+
+#include "../FileManager/StringUtils.h"
+#include "../FileManager/LangUtils.h"
+
+#include "BenchmarkDialog.h"
+#include "ExtractGUI.h"
+#include "HashGUI.h"
+#include "UpdateGUI.h"
+
+#include "ExtractRes.h"
+
+using namespace NWindows;
+
+#ifdef Z7_EXTERNAL_CODECS
+extern
+const CExternalCodecs *g_ExternalCodecs_Ptr;
+const CExternalCodecs *g_ExternalCodecs_Ptr;
+#endif
+
+extern
+HINSTANCE g_hInstance;
+HINSTANCE g_hInstance;
+
+#ifndef UNDER_CE
+
+extern
+DWORD g_ComCtl32Version;
+DWORD g_ComCtl32Version;
+
+static DWORD GetDllVersion(LPCTSTR dllName)
+{
+ DWORD dwVersion = 0;
+ const HMODULE hmodule = LoadLibrary(dllName);
+ if (hmodule)
+ {
+ const
+ DLLGETVERSIONPROC f_DllGetVersion = Z7_GET_PROC_ADDRESS(
+ DLLGETVERSIONPROC, hmodule,
+ "DllGetVersion");
+ if (f_DllGetVersion)
+ {
+ DLLVERSIONINFO dvi;
+ ZeroMemory(&dvi, sizeof(dvi));
+ dvi.cbSize = sizeof(dvi);
+ const HRESULT hr = (*f_DllGetVersion)(&dvi);
+ if (SUCCEEDED(hr))
+ dwVersion = (DWORD)MAKELONG(dvi.dwMinorVersion, dvi.dwMajorVersion);
+ }
+ FreeLibrary(hmodule);
+ }
+ return dwVersion;
+}
+
+#endif
+
+extern
+bool g_LVN_ITEMACTIVATE_Support;
+bool g_LVN_ITEMACTIVATE_Support = true;
+
+DECLARE_AND_SET_CLIENT_VERSION_VAR
+
+static void ErrorMessage(LPCWSTR message)
+{
+ MessageBoxW(NULL, message, L"7-Zip", MB_ICONERROR | MB_OK);
+}
+
+static void ErrorMessage(const char *s)
+{
+ ErrorMessage(GetUnicodeString(s));
+}
+
+static void ErrorLangMessage(UINT resourceID)
+{
+ ErrorMessage(LangString(resourceID));
+}
+
+static const char * const kNoFormats = "7-Zip cannot find the code that works with archives.";
+
+static int ShowMemErrorMessage()
+{
+ ErrorLangMessage(IDS_MEM_ERROR);
+ return NExitCode::kMemoryError;
+}
+
+static int ShowSysErrorMessage(HRESULT errorCode)
+{
+ if (errorCode == E_OUTOFMEMORY)
+ return ShowMemErrorMessage();
+ ErrorMessage(HResultToMessage(errorCode));
+ return NExitCode::kFatalError;
+}
+
+static void ThrowException_if_Error(HRESULT res)
+{
+ if (res != S_OK)
+ throw CSystemException(res);
+}
+
+static int Main2()
+{
+ UStringVector commandStrings;
+ NCommandLineParser::SplitCommandLine(GetCommandLineW(), commandStrings);
+
+ #ifndef UNDER_CE
+ if (commandStrings.Size() > 0)
+ commandStrings.Delete(0);
+ #endif
+ if (commandStrings.Size() == 0)
+ {
+ MessageBoxW(NULL, L"Specify command", L"7-Zip", 0);
+ return 0;
+ }
+
+ CArcCmdLineOptions options;
+ CArcCmdLineParser parser;
+
+ parser.Parse1(commandStrings, options);
+ parser.Parse2(options);
+
+ CREATE_CODECS_OBJECT
+
+ codecs->CaseSensitive_Change = options.CaseSensitive_Change;
+ codecs->CaseSensitive = options.CaseSensitive;
+ ThrowException_if_Error(codecs->Load());
+ Codecs_AddHashArcHandler(codecs);
+
+ #ifdef Z7_EXTERNAL_CODECS
+ {
+ g_ExternalCodecs_Ptr = &_externalCodecs;
+ UString s;
+ codecs->GetCodecsErrorMessage(s);
+ if (!s.IsEmpty())
+ {
+ MessageBoxW(NULL, s, L"7-Zip", MB_ICONERROR);
+ }
+
+ }
+ #endif
+
+ const bool isExtractGroupCommand = options.Command.IsFromExtractGroup();
+
+ if (codecs->Formats.Size() == 0 &&
+ (isExtractGroupCommand
+
+ || options.Command.IsFromUpdateGroup()))
+ {
+ #ifdef Z7_EXTERNAL_CODECS
+ if (!codecs->MainDll_ErrorPath.IsEmpty())
+ {
+ UString s ("7-Zip cannot load module: ");
+ s += fs2us(codecs->MainDll_ErrorPath);
+ throw s;
+ }
+ #endif
+ throw kNoFormats;
+ }
+
+ CObjectVector<COpenType> formatIndices;
+ if (!ParseOpenTypes(*codecs, options.ArcType, formatIndices))
+ {
+ ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE);
+ return NExitCode::kFatalError;
+ }
+
+ CIntVector excludedFormats;
+ FOR_VECTOR (k, options.ExcludedArcTypes)
+ {
+ CIntVector tempIndices;
+ if (!codecs->FindFormatForArchiveType(options.ExcludedArcTypes[k], tempIndices)
+ || tempIndices.Size() != 1)
+ {
+ ErrorLangMessage(IDS_UNSUPPORTED_ARCHIVE_TYPE);
+ return NExitCode::kFatalError;
+ }
+ excludedFormats.AddToUniqueSorted(tempIndices[0]);
+ // excludedFormats.Sort();
+ }
+
+ #ifdef Z7_EXTERNAL_CODECS
+ if (isExtractGroupCommand
+ || options.Command.IsFromUpdateGroup()
+ || options.Command.CommandType == NCommandType::kHash
+ || options.Command.CommandType == NCommandType::kBenchmark)
+ ThrowException_if_Error(_externalCodecs.Load());
+ #endif
+
+ if (options.Command.CommandType == NCommandType::kBenchmark)
+ {
+ HRESULT res = Benchmark(
+ EXTERNAL_CODECS_VARS_L
+ options.Properties,
+ options.NumIterations_Defined ?
+ options.NumIterations :
+ k_NumBenchIterations_Default);
+ /*
+ if (res == S_FALSE)
+ {
+ stdStream << "\nDecoding Error\n";
+ return NExitCode::kFatalError;
+ }
+ */
+ ThrowException_if_Error(res);
+ }
+ else if (isExtractGroupCommand)
+ {
+ UStringVector ArchivePathsSorted;
+ UStringVector ArchivePathsFullSorted;
+
+ CExtractCallbackImp *ecs = new CExtractCallbackImp;
+ CMyComPtr<IFolderArchiveExtractCallback> extractCallback = ecs;
+
+ #ifndef Z7_NO_CRYPTO
+ ecs->PasswordIsDefined = options.PasswordEnabled;
+ ecs->Password = options.Password;
+ #endif
+
+ ecs->Init();
+
+ CExtractOptions eo;
+ (CExtractOptionsBase &)eo = options.ExtractOptions;
+ eo.StdInMode = options.StdInMode;
+ eo.StdOutMode = options.StdOutMode;
+ eo.YesToAll = options.YesToAll;
+ eo.TestMode = options.Command.IsTestCommand();
+
+ #ifndef Z7_SFX
+ eo.Properties = options.Properties;
+ #endif
+
+ bool messageWasDisplayed = false;
+
+ #ifndef Z7_SFX
+ CHashBundle hb;
+ CHashBundle *hb_ptr = NULL;
+
+ if (!options.HashMethods.IsEmpty())
+ {
+ hb_ptr = &hb;
+ ThrowException_if_Error(hb.SetMethods(EXTERNAL_CODECS_VARS_L options.HashMethods));
+ }
+ #endif
+
+ {
+ CDirItemsStat st;
+ HRESULT hresultMain = EnumerateDirItemsAndSort(
+ options.arcCensor,
+ NWildcard::k_RelatPath,
+ UString(), // addPathPrefix
+ ArchivePathsSorted,
+ ArchivePathsFullSorted,
+ st,
+ NULL // &scan: change it!!!!
+ );
+ if (hresultMain != S_OK)
+ {
+ /*
+ if (hresultMain != E_ABORT && messageWasDisplayed)
+ return NExitCode::kFatalError;
+ */
+ throw CSystemException(hresultMain);
+ }
+ }
+
+ ecs->MultiArcMode = (ArchivePathsSorted.Size() > 1);
+
+ HRESULT result = ExtractGUI(
+ // EXTERNAL_CODECS_VARS_L
+ codecs,
+ formatIndices, excludedFormats,
+ ArchivePathsSorted,
+ ArchivePathsFullSorted,
+ options.Censor.Pairs.Front().Head,
+ eo,
+ #ifndef Z7_SFX
+ hb_ptr,
+ #endif
+ options.ShowDialog, messageWasDisplayed, ecs);
+ if (result != S_OK)
+ {
+ if (result != E_ABORT && messageWasDisplayed)
+ return NExitCode::kFatalError;
+ throw CSystemException(result);
+ }
+ if (!ecs->IsOK())
+ return NExitCode::kFatalError;
+ }
+ else if (options.Command.IsFromUpdateGroup())
+ {
+ #ifndef Z7_NO_CRYPTO
+ bool passwordIsDefined = options.PasswordEnabled && !options.Password.IsEmpty();
+ #endif
+
+ CUpdateCallbackGUI callback;
+ // callback.EnablePercents = options.EnablePercents;
+
+ #ifndef Z7_NO_CRYPTO
+ callback.PasswordIsDefined = passwordIsDefined;
+ callback.AskPassword = options.PasswordEnabled && options.Password.IsEmpty();
+ callback.Password = options.Password;
+ #endif
+
+ // callback.StdOutMode = options.UpdateOptions.StdOutMode;
+ callback.Init();
+
+ if (!options.UpdateOptions.InitFormatIndex(codecs, formatIndices, options.ArchiveName) ||
+ !options.UpdateOptions.SetArcPath(codecs, options.ArchiveName))
+ {
+ ErrorLangMessage(IDS_UPDATE_NOT_SUPPORTED);
+ return NExitCode::kFatalError;
+ }
+ bool messageWasDisplayed = false;
+ HRESULT result = UpdateGUI(
+ codecs, formatIndices,
+ options.ArchiveName,
+ options.Censor,
+ options.UpdateOptions,
+ options.ShowDialog,
+ messageWasDisplayed,
+ &callback);
+
+ if (result != S_OK)
+ {
+ if (result != E_ABORT && messageWasDisplayed)
+ return NExitCode::kFatalError;
+ throw CSystemException(result);
+ }
+ if (callback.FailedFiles.Size() > 0)
+ {
+ if (!messageWasDisplayed)
+ throw CSystemException(E_FAIL);
+ return NExitCode::kWarning;
+ }
+ }
+ else if (options.Command.CommandType == NCommandType::kHash)
+ {
+ bool messageWasDisplayed = false;
+ HRESULT result = HashCalcGUI(EXTERNAL_CODECS_VARS_L
+ options.Censor, options.HashOptions, messageWasDisplayed);
+
+ if (result != S_OK)
+ {
+ if (result != E_ABORT && messageWasDisplayed)
+ return NExitCode::kFatalError;
+ throw CSystemException(result);
+ }
+ /*
+ if (callback.FailedFiles.Size() > 0)
+ {
+ if (!messageWasDisplayed)
+ throw CSystemException(E_FAIL);
+ return NExitCode::kWarning;
+ }
+ */
+ }
+ else
+ {
+ throw "Unsupported command";
+ }
+ return 0;
+}
+
+#if defined(_UNICODE) && !defined(_WIN64) && !defined(UNDER_CE)
+#define NT_CHECK_FAIL_ACTION ErrorMessage("Unsupported Windows version"); return NExitCode::kFatalError;
+#endif
+
+int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE /* hPrevInstance */,
+ #ifdef UNDER_CE
+ LPWSTR
+ #else
+ LPSTR
+ #endif
+ /* lpCmdLine */, int /* nCmdShow */)
+{
+ g_hInstance = hInstance;
+
+ #ifdef _WIN32
+ NT_CHECK
+ #endif
+
+ InitCommonControls();
+
+ #ifndef UNDER_CE
+ g_ComCtl32Version = ::GetDllVersion(TEXT("comctl32.dll"));
+ g_LVN_ITEMACTIVATE_Support = (g_ComCtl32Version >= MAKELONG(71, 4));
+ #endif
+
+ // OleInitialize is required for ProgressBar in TaskBar.
+ #ifndef UNDER_CE
+ OleInitialize(NULL);
+ #endif
+
+ #ifdef Z7_LANG
+ LoadLangOneTime();
+ #endif
+
+ // setlocale(LC_COLLATE, ".ACP");
+ try
+ {
+ #ifdef _WIN32
+ My_SetDefaultDllDirectories();
+ #endif
+
+ return Main2();
+ }
+ catch(const CNewException &)
+ {
+ return ShowMemErrorMessage();
+ }
+ catch(const CMessagePathException &e)
+ {
+ ErrorMessage(e);
+ return NExitCode::kUserError;
+ }
+ catch(const CSystemException &systemError)
+ {
+ if (systemError.ErrorCode == E_ABORT)
+ return NExitCode::kUserBreak;
+ return ShowSysErrorMessage(systemError.ErrorCode);
+ }
+ catch(const UString &s)
+ {
+ ErrorMessage(s);
+ return NExitCode::kFatalError;
+ }
+ catch(const AString &s)
+ {
+ ErrorMessage(s);
+ return NExitCode::kFatalError;
+ }
+ catch(const wchar_t *s)
+ {
+ ErrorMessage(s);
+ return NExitCode::kFatalError;
+ }
+ catch(const char *s)
+ {
+ ErrorMessage(s);
+ return NExitCode::kFatalError;
+ }
+ catch(int v)
+ {
+ AString e ("Error: ");
+ e.Add_UInt32((unsigned)v);
+ ErrorMessage(e);
+ return NExitCode::kFatalError;
+ }
+ catch(...)
+ {
+ ErrorMessage("Unknown error");
+ return NExitCode::kFatalError;
+ }
+}
diff --git a/CPP/7zip/UI/GUI/GUI.dsp b/CPP/7zip/UI/GUI/GUI.dsp
new file mode 100644
index 0000000..3a6b60f
--- /dev/null
+++ b/CPP/7zip/UI/GUI/GUI.dsp
@@ -0,0 +1,1259 @@
+# Microsoft Developer Studio Project File - Name="GUI" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Application" 0x0101
+
+CFG=GUI - Win32 DebugU
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "GUI.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "GUI.mak" CFG="GUI - Win32 DebugU"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "GUI - Win32 Release" (based on "Win32 (x86) Application")
+!MESSAGE "GUI - Win32 Debug" (based on "Win32 (x86) Application")
+!MESSAGE "GUI - Win32 ReleaseU" (based on "Win32 (x86) Application")
+!MESSAGE "GUI - Win32 DebugU" (based on "Win32 (x86) Application")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "GUI - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c
+# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /D "Z7_LARGE_PAGES" /FAcs /Yu"stdafx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zg.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "GUI - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
+# ADD CPP /nologo /Gr /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_MBCS" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /D "Z7_LARGE_PAGES" /Yu"stdafx.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zg.exe" /pdbtype:sept
+
+!ELSEIF "$(CFG)" == "GUI - Win32 ReleaseU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "ReleaseU"
+# PROP BASE Intermediate_Dir "ReleaseU"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "ReleaseU"
+# PROP Intermediate_Dir "ReleaseU"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /c
+# ADD CPP /nologo /Gr /MD /W4 /WX /GX /O1 /D "NDEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /D "Z7_LARGE_PAGES" /Yu"stdafx.h" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "NDEBUG"
+# ADD RSC /l 0x419 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /machine:I386 /out:"C:\UTIL\7zg.exe"
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /subsystem:windows /machine:I386 /out:"C:\Util\7zg.exe" /opt:NOWIN98
+# SUBTRACT LINK32 /pdb:none
+
+!ELSEIF "$(CFG)" == "GUI - Win32 DebugU"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "DebugU"
+# PROP BASE Intermediate_Dir "DebugU"
+# PROP BASE Ignore_Export_Lib 0
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "DebugU"
+# PROP Intermediate_Dir "DebugU"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /Yu"stdafx.h" /FD /GZ /c
+# ADD CPP /nologo /Gr /MDd /W4 /WX /Gm /GX /ZI /Od /D "_DEBUG" /D "_UNICODE" /D "UNICODE" /D "WIN32" /D "_WINDOWS" /D "Z7_LANG" /D "Z7_LONG_PATH" /D "Z7_EXTERNAL_CODECS" /D "Z7_DEVICE_FILE" /D "Z7_LARGE_PAGES" /Yu"stdafx.h" /FD /GZ /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
+# ADD BASE RSC /l 0x419 /d "_DEBUG"
+# ADD RSC /l 0x419 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\UTIL\7zg.exe" /pdbtype:sept
+# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib comctl32.lib htmlhelp.lib /nologo /subsystem:windows /debug /machine:I386 /out:"C:\Util\7zg.exe" /pdbtype:sept
+
+!ENDIF
+
+# Begin Target
+
+# Name "GUI - Win32 Release"
+# Name "GUI - Win32 Debug"
+# Name "GUI - Win32 ReleaseU"
+# Name "GUI - Win32 DebugU"
+# Begin Group "Spec"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\7zG.exe.manifest
+# End Source File
+# Begin Source File
+
+SOURCE=.\ExtractRes.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\FM.ico
+# End Source File
+# Begin Source File
+
+SOURCE=.\resource.rc
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.cpp
+# ADD CPP /Yc"stdafx.h"
+# End Source File
+# Begin Source File
+
+SOURCE=.\StdAfx.h
+# End Source File
+# End Group
+# Begin Group "UI Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\Common\ArchiveCommandLine.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveCommandLine.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveExtractCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveOpenCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ArchiveOpenCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\Bench.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\Bench.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\DefaultName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\DefaultName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\DirItem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\EnumDirItems.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\EnumDirItems.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ExitCode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\Extract.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\Extract.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ExtractingFilePath.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ExtractingFilePath.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ExtractMode.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\HashCalc.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\HashCalc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\IFileExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\LoadCodecs.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\LoadCodecs.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\OpenArchive.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\OpenArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\Property.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\PropIDUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\PropIDUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\SetProperties.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\SetProperties.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\SortUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\SortUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\TempFiles.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\TempFiles.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\Update.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\Update.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateAction.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateAction.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdatePair.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdatePair.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateProduce.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\UpdateProduce.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\WorkDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\WorkDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ZipRegistry.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Common\ZipRegistry.h
+# End Source File
+# End Group
+# Begin Group "Explorer"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\Explorer\MyMessages.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\Explorer\MyMessages.h
+# End Source File
+# End Group
+# Begin Group "Dialogs"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\BenchmarkDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\BenchmarkDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\BrowseDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\BrowseDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\ComboDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\ComboDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\CompressDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\CompressDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\EditDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\EditDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\ExtractDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ExtractDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\ListViewDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\ListViewDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\OverwriteDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\OverwriteDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\PasswordDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\PasswordDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\ProgressDialog2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\ProgressDialog2.h
+# End Source File
+# End Group
+# Begin Group "FM Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\FileManager\ExtractCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\ExtractCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\FormatUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\FormatUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\HelpUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\HelpUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\LangUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\LangUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\OpenCallback.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\OpenCallback.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\ProgramLocation.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\ProgramLocation.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\PropertyName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\PropertyName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\RegistryUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\RegistryUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\SplitUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\SplitUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\StringUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\StringUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\SysIconUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\FileManager\SysIconUtils.h
+# End Source File
+# End Group
+# Begin Group "Engine"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\ExtractGUI.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\ExtractGUI.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\GUI.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\HashGUI.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\HashGUI.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\UpdateCallbackGUI.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\UpdateCallbackGUI.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\UpdateCallbackGUI2.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\UpdateCallbackGUI2.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\UpdateGUI.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=.\UpdateGUI.h
+# End Source File
+# End Group
+# Begin Group "7-zip Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\CreateCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilePathAutoRename.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FileStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\FilterCoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\LimitedStreams.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MethodProps.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MultiOutStream.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\MultiOutStream.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\ProgressUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\PropId.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamObjects.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\StreamUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\UniqBlocks.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Common\UniqBlocks.h
+# End Source File
+# End Group
+# Begin Group "Compress"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Compress\CopyCoder.h
+# End Source File
+# End Group
+# Begin Group "C"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.c
+
+!IF "$(CFG)" == "GUI - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "GUI - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "GUI - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "GUI - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zCrcOpt.c
+
+!IF "$(CFG)" == "GUI - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "GUI - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "GUI - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "GUI - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zTypes.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\7zWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Alloc.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.c
+
+!IF "$(CFG)" == "GUI - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "GUI - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "GUI - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "GUI - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\CpuArch.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\DllSecur.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\DllSecur.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sort.c
+
+!IF "$(CFG)" == "GUI - Win32 Release"
+
+# ADD CPP /O2
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "GUI - Win32 Debug"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "GUI - Win32 ReleaseU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ELSEIF "$(CFG)" == "GUI - Win32 DebugU"
+
+# SUBTRACT CPP /YX /Yc /Yu
+
+!ENDIF
+
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Sort.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.c
+# SUBTRACT CPP /YX /Yc /Yu
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Threads.h
+# End Source File
+# End Group
+# Begin Group "Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CommandLineParser.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Common.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\..\C\Compiler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\CRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynLimBuf.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\DynLimBuf.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\IntToString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Lang.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Lang.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ListFileUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\ListFileUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyBuffer.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyVector.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\MyWindows.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\NewHandler.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\StringToInt.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\UTFConvert.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Common\Wildcard.h
+# End Source File
+# End Group
+# Begin Group "Windows"
+
+# PROP Default_Filter ""
+# Begin Group "Control"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ComboBox.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ComboBox.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Dialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Dialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Edit.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ListView.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ListView.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\ProgressBar.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Control\Static.h
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Clipboard.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Clipboard.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\COM.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\CommonDialog.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\CommonDialog.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\DLL.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ErrorMsg.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileDir.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileFind.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileIO.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileLink.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileMapping.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileName.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileSystem.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\FileSystem.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryGlobal.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryGlobal.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryLock.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\MemoryLock.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariant.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\PropVariantConv.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Registry.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Registry.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ResourceString.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\ResourceString.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Shell.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Shell.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Synchronization.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\System.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\SystemInfo.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\SystemInfo.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Thread.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\TimeUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\TimeUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Window.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\..\Windows\Window.h
+# End Source File
+# End Group
+# Begin Group "Archive Common"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\ItemNameUtils.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.cpp
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\Archive\Common\OutStreamWithCRC.h
+# End Source File
+# End Group
+# Begin Group "7-Zip"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=..\..\Archive\IArchive.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\ICoder.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IDecl.h
+# End Source File
+# Begin Source File
+
+SOURCE=..\..\IStream.h
+# End Source File
+# End Group
+# End Target
+# End Project
diff --git a/CPP/7zip/UI/GUI/GUI.dsw b/CPP/7zip/UI/GUI/GUI.dsw
new file mode 100644
index 0000000..85d3348
--- /dev/null
+++ b/CPP/7zip/UI/GUI/GUI.dsw
@@ -0,0 +1,29 @@
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "GUI"=.\GUI.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
diff --git a/CPP/7zip/UI/GUI/HashGUI.cpp b/CPP/7zip/UI/GUI/HashGUI.cpp
new file mode 100644
index 0000000..b96e413
--- /dev/null
+++ b/CPP/7zip/UI/GUI/HashGUI.cpp
@@ -0,0 +1,363 @@
+// HashGUI.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/ErrorMsg.h"
+
+#include "../FileManager/FormatUtils.h"
+#include "../FileManager/LangUtils.h"
+#include "../FileManager/ListViewDialog.h"
+#include "../FileManager/OverwriteDialogRes.h"
+#include "../FileManager/ProgressDialog2.h"
+#include "../FileManager/ProgressDialog2Res.h"
+#include "../FileManager/PropertyNameRes.h"
+#include "../FileManager/resourceGui.h"
+
+#include "HashGUI.h"
+
+using namespace NWindows;
+
+
+
+class CHashCallbackGUI Z7_final: public CProgressThreadVirt, public IHashCallbackUI
+{
+ UInt64 NumFiles;
+ bool _curIsFolder;
+ UString FirstFileName;
+ // UString MainPath;
+
+ CPropNameValPairs PropNameValPairs;
+
+ HRESULT ProcessVirt() Z7_override;
+ virtual void ProcessWasFinished_GuiVirt() Z7_override;
+
+public:
+ const NWildcard::CCensor *censor;
+ const CHashOptions *options;
+
+ DECL_EXTERNAL_CODECS_LOC_VARS_DECL
+
+ Z7_IFACE_IMP(IDirItemsCallback)
+ Z7_IFACE_IMP(IHashCallbackUI)
+
+ /*
+ void AddErrorMessage(DWORD systemError, const wchar_t *name)
+ {
+ Sync.AddError_Code_Name(systemError, name);
+ }
+ */
+ void AddErrorMessage(HRESULT systemError, const wchar_t *name)
+ {
+ Sync.AddError_Code_Name(systemError, name);
+ }
+};
+
+
+void AddValuePair(CPropNameValPairs &pairs, UINT resourceID, UInt64 value)
+{
+ CProperty &pair = pairs.AddNew();
+ AddLangString(pair.Name, resourceID);
+ char sz[32];
+ ConvertUInt64ToString(value, sz);
+ pair.Value = sz;
+}
+
+
+void AddSizeValue(UString &s, UInt64 value)
+{
+ {
+ wchar_t sz[32];
+ ConvertUInt64ToString(value, sz);
+ s += MyFormatNew(IDS_FILE_SIZE, sz);
+ }
+ if (value >= (1 << 10))
+ {
+ char c;
+ if (value >= ((UInt64)10 << 30)) { value >>= 30; c = 'G'; }
+ else if (value >= (10 << 20)) { value >>= 20; c = 'M'; }
+ else { value >>= 10; c = 'K'; }
+
+ s += " (";
+ s.Add_UInt64(value);
+ s.Add_Space();
+ s += (wchar_t)c;
+ s += "iB)";
+ }
+}
+
+void AddSizeValuePair(CPropNameValPairs &pairs, UINT resourceID, UInt64 value)
+{
+ CProperty &pair = pairs.AddNew();
+ LangString(resourceID, pair.Name);
+ AddSizeValue(pair.Value, value);
+}
+
+
+HRESULT CHashCallbackGUI::StartScanning()
+{
+ CProgressSync &sync = Sync;
+ sync.Set_Status(LangString(IDS_SCANNING));
+ return CheckBreak();
+}
+
+HRESULT CHashCallbackGUI::ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir)
+{
+ return Sync.ScanProgress(st.NumFiles, st.GetTotalBytes(), path, isDir);
+}
+
+HRESULT CHashCallbackGUI::ScanError(const FString &path, DWORD systemError)
+{
+ AddErrorMessage(HRESULT_FROM_WIN32(systemError), fs2us(path));
+ return CheckBreak();
+}
+
+HRESULT CHashCallbackGUI::FinishScanning(const CDirItemsStat &st)
+{
+ return ScanProgress(st, FString(), false); // isDir
+}
+
+HRESULT CHashCallbackGUI::CheckBreak()
+{
+ return Sync.CheckStop();
+}
+
+HRESULT CHashCallbackGUI::SetNumFiles(UInt64 numFiles)
+{
+ CProgressSync &sync = Sync;
+ sync.Set_NumFilesTotal(numFiles);
+ return CheckBreak();
+}
+
+HRESULT CHashCallbackGUI::SetTotal(UInt64 size)
+{
+ CProgressSync &sync = Sync;
+ sync.Set_NumBytesTotal(size);
+ return CheckBreak();
+}
+
+HRESULT CHashCallbackGUI::SetCompleted(const UInt64 *completed)
+{
+ return Sync.Set_NumBytesCur(completed);
+}
+
+HRESULT CHashCallbackGUI::BeforeFirstFile(const CHashBundle & /* hb */)
+{
+ return S_OK;
+}
+
+HRESULT CHashCallbackGUI::GetStream(const wchar_t *name, bool isFolder)
+{
+ if (NumFiles == 0)
+ FirstFileName = name;
+ _curIsFolder = isFolder;
+ CProgressSync &sync = Sync;
+ sync.Set_FilePath(name, isFolder);
+ return CheckBreak();
+}
+
+HRESULT CHashCallbackGUI::OpenFileError(const FString &path, DWORD systemError)
+{
+ // if (systemError == ERROR_SHARING_VIOLATION)
+ {
+ AddErrorMessage(HRESULT_FROM_WIN32(systemError), fs2us(path));
+ return S_FALSE;
+ }
+ // return systemError;
+}
+
+HRESULT CHashCallbackGUI::SetOperationResult(UInt64 /* fileSize */, const CHashBundle & /* hb */, bool /* showHash */)
+{
+ CProgressSync &sync = Sync;
+ if (!_curIsFolder)
+ NumFiles++;
+ sync.Set_NumFilesCur(NumFiles);
+ return CheckBreak();
+}
+
+static const unsigned k_DigestStringSize = k_HashCalc_DigestSize_Max * 2 + k_HashCalc_ExtraSize * 2 + 16;
+
+static void AddHashString(CProperty &s, const CHasherState &h, unsigned digestIndex)
+{
+ char temp[k_DigestStringSize];
+ h.WriteToString(digestIndex, temp);
+ s.Value = temp;
+}
+
+static void AddHashResString(CPropNameValPairs &s, const CHasherState &h, unsigned digestIndex, UInt32 resID)
+{
+ CProperty &pair = s.AddNew();
+ UString &s2 = pair.Name;
+ LangString(resID, s2);
+ UString name (h.Name);
+ s2.Replace(L"CRC", name);
+ s2.Replace(L":", L"");
+ AddHashString(pair, h, digestIndex);
+}
+
+
+void AddHashBundleRes(CPropNameValPairs &s, const CHashBundle &hb)
+{
+ if (hb.NumErrors != 0)
+ AddValuePair(s, IDS_PROP_NUM_ERRORS, hb.NumErrors);
+
+ if (hb.NumFiles == 1 && hb.NumDirs == 0 && !hb.FirstFileName.IsEmpty())
+ {
+ CProperty &pair = s.AddNew();
+ LangString(IDS_PROP_NAME, pair.Name);
+ pair.Value = hb.FirstFileName;
+ }
+ else
+ {
+ if (!hb.MainName.IsEmpty())
+ {
+ CProperty &pair = s.AddNew();
+ LangString(IDS_PROP_NAME, pair.Name);
+ pair.Value = hb.MainName;
+ }
+ if (hb.NumDirs != 0)
+ AddValuePair(s, IDS_PROP_FOLDERS, hb.NumDirs);
+ AddValuePair(s, IDS_PROP_FILES, hb.NumFiles);
+ }
+
+ AddSizeValuePair(s, IDS_PROP_SIZE, hb.FilesSize);
+
+ if (hb.NumAltStreams != 0)
+ {
+ AddValuePair(s, IDS_PROP_NUM_ALT_STREAMS, hb.NumAltStreams);
+ AddSizeValuePair(s, IDS_PROP_ALT_STREAMS_SIZE, hb.AltStreamsSize);
+ }
+
+ FOR_VECTOR (i, hb.Hashers)
+ {
+ const CHasherState &h = hb.Hashers[i];
+ if (hb.NumFiles == 1 && hb.NumDirs == 0)
+ {
+ CProperty &pair = s.AddNew();
+ pair.Name += h.Name;
+ AddHashString(pair, h, k_HashCalc_Index_DataSum);
+ }
+ else
+ {
+ AddHashResString(s, h, k_HashCalc_Index_DataSum, IDS_CHECKSUM_CRC_DATA);
+ AddHashResString(s, h, k_HashCalc_Index_NamesSum, IDS_CHECKSUM_CRC_DATA_NAMES);
+ }
+ if (hb.NumAltStreams != 0)
+ {
+ AddHashResString(s, h, k_HashCalc_Index_StreamsSum, IDS_CHECKSUM_CRC_STREAMS_NAMES);
+ }
+ }
+}
+
+
+void AddHashBundleRes(UString &s, const CHashBundle &hb)
+{
+ CPropNameValPairs pairs;
+ AddHashBundleRes(pairs, hb);
+
+ FOR_VECTOR (i, pairs)
+ {
+ const CProperty &pair = pairs[i];
+ s += pair.Name;
+ s += ": ";
+ s += pair.Value;
+ s.Add_LF();
+ }
+
+ if (hb.NumErrors == 0 && hb.Hashers.IsEmpty())
+ {
+ s.Add_LF();
+ AddLangString(s, IDS_MESSAGE_NO_ERRORS);
+ s.Add_LF();
+ }
+}
+
+
+HRESULT CHashCallbackGUI::AfterLastFile(CHashBundle &hb)
+{
+ hb.FirstFileName = FirstFileName;
+ // MainPath
+ AddHashBundleRes(PropNameValPairs, hb);
+
+ CProgressSync &sync = Sync;
+ sync.Set_NumFilesCur(hb.NumFiles);
+
+ // CProgressMessageBoxPair &pair = GetMessagePair(hb.NumErrors != 0);
+ // pair.Message = s;
+ // LangString(IDS_CHECKSUM_INFORMATION, pair.Title);
+
+ return S_OK;
+}
+
+
+HRESULT CHashCallbackGUI::ProcessVirt()
+{
+ NumFiles = 0;
+ AString errorInfo;
+ HRESULT res = HashCalc(EXTERNAL_CODECS_LOC_VARS
+ *censor, *options, errorInfo, this);
+ return res;
+}
+
+
+HRESULT HashCalcGUI(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const NWildcard::CCensor &censor,
+ const CHashOptions &options,
+ bool &messageWasDisplayed)
+{
+ CHashCallbackGUI t;
+ #ifdef Z7_EXTERNAL_CODECS
+ t._externalCodecs = _externalCodecs;
+ #endif
+ t.censor = &censor;
+ t.options = &options;
+
+ t.ShowCompressionInfo = false;
+
+ const UString title = LangString(IDS_CHECKSUM_CALCULATING);
+
+ t.MainTitle = "7-Zip"; // LangString(IDS_APP_TITLE);
+ t.MainAddTitle = title;
+ t.MainAddTitle.Add_Space();
+
+ RINOK(t.Create(title))
+ messageWasDisplayed = t.ThreadFinishedOK && t.MessagesDisplayed;
+ return S_OK;
+}
+
+
+void ShowHashResults(const CPropNameValPairs &propPairs, HWND hwnd)
+{
+ CListViewDialog lv;
+
+ FOR_VECTOR (i, propPairs)
+ {
+ const CProperty &pair = propPairs[i];
+ lv.Strings.Add(pair.Name);
+ lv.Values.Add(pair.Value);
+ }
+
+ lv.Title = LangString(IDS_CHECKSUM_INFORMATION);
+ lv.DeleteIsAllowed = true;
+ lv.SelectFirst = false;
+ lv.NumColumns = 2;
+
+ lv.Create(hwnd);
+}
+
+
+void ShowHashResults(const CHashBundle &hb, HWND hwnd)
+{
+ CPropNameValPairs propPairs;
+ AddHashBundleRes(propPairs, hb);
+ ShowHashResults(propPairs, hwnd);
+}
+
+void CHashCallbackGUI::ProcessWasFinished_GuiVirt()
+{
+ if (Result != E_ABORT)
+ ShowHashResults(PropNameValPairs, *this);
+}
diff --git a/CPP/7zip/UI/GUI/HashGUI.h b/CPP/7zip/UI/GUI/HashGUI.h
index b626823..1ec9c47 100644
--- a/CPP/7zip/UI/GUI/HashGUI.h
+++ b/CPP/7zip/UI/GUI/HashGUI.h
@@ -1,27 +1,27 @@
-// HashGUI.h
-
-#ifndef __HASH_GUI_H
-#define __HASH_GUI_H
-
-#include "../Common/HashCalc.h"
-#include "../Common/Property.h"
-
-HRESULT HashCalcGUI(
- DECL_EXTERNAL_CODECS_LOC_VARS
- const NWildcard::CCensor &censor,
- const CHashOptions &options,
- bool &messageWasDisplayed);
-
-typedef CObjectVector<CProperty> CPropNameValPairs;
-
-void AddValuePair(CPropNameValPairs &pairs, UINT resourceID, UInt64 value);
-void AddSizeValue(UString &s, UInt64 value);
-void AddSizeValuePair(CPropNameValPairs &pairs, UINT resourceID, UInt64 value);
-
-void AddHashBundleRes(CPropNameValPairs &s, const CHashBundle &hb);
-void AddHashBundleRes(UString &s, const CHashBundle &hb);
-
-void ShowHashResults(const CPropNameValPairs &propPairs, HWND hwnd);
-void ShowHashResults(const CHashBundle &hb, HWND hwnd);
-
-#endif
+// HashGUI.h
+
+#ifndef ZIP7_INC_HASH_GUI_H
+#define ZIP7_INC_HASH_GUI_H
+
+#include "../Common/HashCalc.h"
+#include "../Common/Property.h"
+
+HRESULT HashCalcGUI(
+ DECL_EXTERNAL_CODECS_LOC_VARS
+ const NWildcard::CCensor &censor,
+ const CHashOptions &options,
+ bool &messageWasDisplayed);
+
+typedef CObjectVector<CProperty> CPropNameValPairs;
+
+void AddValuePair(CPropNameValPairs &pairs, UINT resourceID, UInt64 value);
+void AddSizeValue(UString &s, UInt64 value);
+void AddSizeValuePair(CPropNameValPairs &pairs, UINT resourceID, UInt64 value);
+
+void AddHashBundleRes(CPropNameValPairs &s, const CHashBundle &hb);
+void AddHashBundleRes(UString &s, const CHashBundle &hb);
+
+void ShowHashResults(const CPropNameValPairs &propPairs, HWND hwnd);
+void ShowHashResults(const CHashBundle &hb, HWND hwnd);
+
+#endif
diff --git a/CPP/7zip/UI/GUI/StdAfx.cpp b/CPP/7zip/UI/GUI/StdAfx.cpp
new file mode 100644
index 0000000..d0feea8
--- /dev/null
+++ b/CPP/7zip/UI/GUI/StdAfx.cpp
@@ -0,0 +1,3 @@
+// StdAfx.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/7zip/UI/GUI/StdAfx.h b/CPP/7zip/UI/GUI/StdAfx.h
new file mode 100644
index 0000000..130db8a
--- /dev/null
+++ b/CPP/7zip/UI/GUI/StdAfx.h
@@ -0,0 +1,6 @@
+// StdAfx.h
+
+#if _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../FileManager/StdAfx.h"
diff --git a/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp b/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp
new file mode 100644
index 0000000..26057a7
--- /dev/null
+++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI.cpp
@@ -0,0 +1,280 @@
+// UpdateCallbackGUI.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+
+#include "../../../Windows/PropVariant.h"
+
+#include "../FileManager/FormatUtils.h"
+#include "../FileManager/LangUtils.h"
+
+#include "../FileManager/resourceGui.h"
+
+#include "resource2.h"
+
+#include "UpdateCallbackGUI.h"
+
+using namespace NWindows;
+
+// CUpdateCallbackGUI::~CUpdateCallbackGUI() {}
+
+void CUpdateCallbackGUI::Init()
+{
+ CUpdateCallbackGUI2::Init();
+ FailedFiles.Clear();
+}
+
+void OpenResult_GUI(UString &s, const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result);
+
+HRESULT CUpdateCallbackGUI::OpenResult(
+ const CCodecs *codecs, const CArchiveLink &arcLink, const wchar_t *name, HRESULT result)
+{
+ UString s;
+ OpenResult_GUI(s, codecs, arcLink, name, result);
+ if (!s.IsEmpty())
+ {
+ ProgressDialog->Sync.AddError_Message(s);
+ }
+
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackGUI::StartScanning()
+{
+ CProgressSync &sync = ProgressDialog->Sync;
+ sync.Set_Status(LangString(IDS_SCANNING));
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackGUI::ScanError(const FString &path, DWORD systemError)
+{
+ FailedFiles.Add(path);
+ ProgressDialog->Sync.AddError_Code_Name(HRESULT_FROM_WIN32(systemError), fs2us(path));
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackGUI::FinishScanning(const CDirItemsStat &st)
+{
+ CProgressSync &sync = ProgressDialog->Sync;
+ RINOK(ProgressDialog->Sync.ScanProgress(st.NumFiles + st.NumAltStreams,
+ st.GetTotalBytes(), FString(), true))
+ sync.Set_Status(L"");
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackGUI::StartArchive(const wchar_t *name, bool /* updating */)
+{
+ CProgressSync &sync = ProgressDialog->Sync;
+ sync.Set_Status(LangString(IDS_PROGRESS_COMPRESSING));
+ sync.Set_TitleFileName(name);
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackGUI::FinishArchive(const CFinishArchiveStat & /* st */)
+{
+ CProgressSync &sync = ProgressDialog->Sync;
+ sync.Set_Status(L"");
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackGUI::CheckBreak()
+{
+ return ProgressDialog->Sync.CheckStop();
+}
+
+HRESULT CUpdateCallbackGUI::ScanProgress(const CDirItemsStat &st, const FString &path, bool isDir)
+{
+ return ProgressDialog->Sync.ScanProgress(st.NumFiles + st.NumAltStreams,
+ st.GetTotalBytes(), path, isDir);
+}
+
+/*
+HRESULT CUpdateCallbackGUI::Finalize()
+{
+ return S_OK;
+}
+*/
+
+HRESULT CUpdateCallbackGUI::SetNumItems(const CArcToDoStat &stat)
+{
+ ProgressDialog->Sync.Set_NumFilesTotal(stat.Get_NumDataItems_Total());
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackGUI::SetTotal(UInt64 total)
+{
+ ProgressDialog->Sync.Set_NumBytesTotal(total);
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackGUI::SetCompleted(const UInt64 *completed)
+{
+ return ProgressDialog->Sync.Set_NumBytesCur(completed);
+}
+
+HRESULT CUpdateCallbackGUI::SetRatioInfo(const UInt64 *inSize, const UInt64 *outSize)
+{
+ ProgressDialog->Sync.Set_Ratio(inSize, outSize);
+ return CheckBreak();
+}
+
+HRESULT CUpdateCallbackGUI::GetStream(const wchar_t *name, bool isDir, bool /* isAnti */, UInt32 mode)
+{
+ return SetOperation_Base(mode, name, isDir);
+}
+
+HRESULT CUpdateCallbackGUI::OpenFileError(const FString &path, DWORD systemError)
+{
+ FailedFiles.Add(path);
+ // if (systemError == ERROR_SHARING_VIOLATION)
+ {
+ ProgressDialog->Sync.AddError_Code_Name(HRESULT_FROM_WIN32(systemError), fs2us(path));
+ return S_FALSE;
+ }
+ // return systemError;
+}
+
+HRESULT CUpdateCallbackGUI::SetOperationResult(Int32 /* operationResult */)
+{
+ NumFiles++;
+ ProgressDialog->Sync.Set_NumFilesCur(NumFiles);
+ return S_OK;
+}
+
+void SetExtractErrorMessage(Int32 opRes, Int32 encrypted, const wchar_t *fileName, UString &s);
+
+HRESULT CUpdateCallbackGUI::ReportExtractResult(Int32 opRes, Int32 isEncrypted, const wchar_t *name)
+{
+ if (opRes != NArchive::NExtract::NOperationResult::kOK)
+ {
+ UString s;
+ SetExtractErrorMessage(opRes, isEncrypted, name, s);
+ ProgressDialog->Sync.AddError_Message(s);
+ }
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackGUI::ReportUpdateOperation(UInt32 op, const wchar_t *name, bool isDir)
+{
+ return SetOperation_Base(op, name, isDir);
+}
+
+HRESULT CUpdateCallbackGUI::CryptoGetTextPassword2(Int32 *passwordIsDefined, BSTR *password)
+{
+ *password = NULL;
+ if (passwordIsDefined)
+ *passwordIsDefined = BoolToInt(PasswordIsDefined);
+ if (!PasswordIsDefined)
+ {
+ if (AskPassword)
+ {
+ RINOK(ShowAskPasswordDialog())
+ }
+ }
+ if (passwordIsDefined)
+ *passwordIsDefined = BoolToInt(PasswordIsDefined);
+ return StringToBstr(Password, password);
+}
+
+HRESULT CUpdateCallbackGUI::CryptoGetTextPassword(BSTR *password)
+{
+ return CryptoGetTextPassword2(NULL, password);
+}
+
+/*
+It doesn't work, since main stream waits Dialog
+HRESULT CUpdateCallbackGUI::CloseProgress()
+{
+ ProgressDialog->MyClose();
+ return S_OK;
+}
+*/
+
+
+HRESULT CUpdateCallbackGUI::Open_CheckBreak()
+{
+ return ProgressDialog->Sync.CheckStop();
+}
+
+HRESULT CUpdateCallbackGUI::Open_SetTotal(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */)
+{
+ // if (numFiles != NULL) ProgressDialog->Sync.SetNumFilesTotal(*numFiles);
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackGUI::Open_SetCompleted(const UInt64 * /* numFiles */, const UInt64 * /* numBytes */)
+{
+ return ProgressDialog->Sync.CheckStop();
+}
+
+#ifndef Z7_NO_CRYPTO
+
+HRESULT CUpdateCallbackGUI::Open_CryptoGetTextPassword(BSTR *password)
+{
+ PasswordWasAsked = true;
+ return CryptoGetTextPassword2(NULL, password);
+}
+
+/*
+HRESULT CUpdateCallbackGUI::Open_GetPasswordIfAny(bool &passwordIsDefined, UString &password)
+{
+ passwordIsDefined = PasswordIsDefined;
+ password = Password;
+ return S_OK;
+}
+
+bool CUpdateCallbackGUI::Open_WasPasswordAsked()
+{
+ return PasswordWasAsked;
+}
+
+void CUpdateCallbackGUI::Open_Clear_PasswordWasAsked_Flag()
+{
+ PasswordWasAsked = false;
+}
+*/
+
+HRESULT CUpdateCallbackGUI::ShowDeleteFile(const wchar_t *name, bool isDir)
+{
+ return SetOperation_Base(NUpdateNotifyOp::kDelete, name, isDir);
+}
+
+HRESULT CUpdateCallbackGUI::FinishDeletingAfterArchiving()
+{
+ // ClosePercents2();
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackGUI::DeletingAfterArchiving(const FString &path, bool isDir)
+{
+ return ProgressDialog->Sync.Set_Status2(_lang_Removing, fs2us(path), isDir);
+}
+
+HRESULT CUpdateCallbackGUI::StartOpenArchive(const wchar_t * /* name */)
+{
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackGUI::ReadingFileError(const FString &path, DWORD systemError)
+{
+ FailedFiles.Add(path);
+ ProgressDialog->Sync.AddError_Code_Name(HRESULT_FROM_WIN32(systemError), fs2us(path));
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackGUI::WriteSfx(const wchar_t * /* name */, UInt64 /* size */)
+{
+ CProgressSync &sync = ProgressDialog->Sync;
+ sync.Set_Status(L"WriteSfx");
+ return S_OK;
+}
+
+HRESULT CUpdateCallbackGUI::Open_Finished()
+{
+ // ClosePercents();
+ return S_OK;
+}
+
+#endif
diff --git a/CPP/7zip/UI/GUI/UpdateCallbackGUI.h b/CPP/7zip/UI/GUI/UpdateCallbackGUI.h
new file mode 100644
index 0000000..998249a
--- /dev/null
+++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI.h
@@ -0,0 +1,31 @@
+// UpdateCallbackGUI.h
+
+#ifndef ZIP7_INC_UPDATE_CALLBACK_GUI_H
+#define ZIP7_INC_UPDATE_CALLBACK_GUI_H
+
+#include "../Common/Update.h"
+#include "../Common/ArchiveOpenCallback.h"
+
+#include "UpdateCallbackGUI2.h"
+
+class CUpdateCallbackGUI Z7_final:
+ public IOpenCallbackUI,
+ public IUpdateCallbackUI2,
+ public CUpdateCallbackGUI2
+{
+ Z7_IFACE_IMP(IOpenCallbackUI)
+ Z7_IFACE_IMP(IUpdateCallbackUI)
+ Z7_IFACE_IMP(IDirItemsCallback)
+ Z7_IFACE_IMP(IUpdateCallbackUI2)
+
+public:
+ bool AskPassword;
+ FStringVector FailedFiles;
+
+ CUpdateCallbackGUI():
+ AskPassword(false)
+ {}
+ void Init();
+};
+
+#endif
diff --git a/CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp
new file mode 100644
index 0000000..966f57e
--- /dev/null
+++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.cpp
@@ -0,0 +1,59 @@
+// UpdateCallbackGUI2.cpp
+
+#include "StdAfx.h"
+
+#include "../FileManager/LangUtils.h"
+#include "../FileManager/PasswordDialog.h"
+
+#include "resource2.h"
+#include "resource3.h"
+#include "ExtractRes.h"
+
+#include "UpdateCallbackGUI.h"
+
+using namespace NWindows;
+
+static const UINT k_UpdNotifyLangs[] =
+{
+ IDS_PROGRESS_ADD,
+ IDS_PROGRESS_UPDATE,
+ IDS_PROGRESS_ANALYZE,
+ IDS_PROGRESS_REPLICATE,
+ IDS_PROGRESS_REPACK,
+ IDS_PROGRESS_SKIPPING,
+ IDS_PROGRESS_DELETE,
+ IDS_PROGRESS_HEADER
+};
+
+void CUpdateCallbackGUI2::Init()
+{
+ NumFiles = 0;
+
+ _lang_Removing = LangString(IDS_PROGRESS_REMOVE);
+ _lang_Ops.Clear();
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(k_UpdNotifyLangs); i++)
+ _lang_Ops.Add(LangString(k_UpdNotifyLangs[i]));
+}
+
+HRESULT CUpdateCallbackGUI2::SetOperation_Base(UInt32 notifyOp, const wchar_t *name, bool isDir)
+{
+ const UString *s = NULL;
+ if (notifyOp < _lang_Ops.Size())
+ s = &(_lang_Ops[(unsigned)notifyOp]);
+ else
+ s = &_emptyString;
+
+ return ProgressDialog->Sync.Set_Status2(*s, name, isDir);
+}
+
+
+HRESULT CUpdateCallbackGUI2::ShowAskPasswordDialog()
+{
+ CPasswordDialog dialog;
+ ProgressDialog->WaitCreating();
+ if (dialog.Create(*ProgressDialog) != IDOK)
+ return E_ABORT;
+ Password = dialog.Password;
+ PasswordIsDefined = true;
+ return S_OK;
+}
diff --git a/CPP/7zip/UI/GUI/UpdateCallbackGUI2.h b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.h
new file mode 100644
index 0000000..e32b602
--- /dev/null
+++ b/CPP/7zip/UI/GUI/UpdateCallbackGUI2.h
@@ -0,0 +1,34 @@
+// UpdateCallbackGUI2.h
+
+#ifndef ZIP7_INC_UPDATE_CALLBACK_GUI2_H
+#define ZIP7_INC_UPDATE_CALLBACK_GUI2_H
+
+#include "../FileManager/ProgressDialog2.h"
+
+class CUpdateCallbackGUI2
+{
+ UStringVector _lang_Ops;
+ UString _emptyString;
+public:
+ UString Password;
+ bool PasswordIsDefined;
+ bool PasswordWasAsked;
+ UInt64 NumFiles;
+
+ UString _lang_Removing;
+
+ CUpdateCallbackGUI2():
+ PasswordIsDefined(false),
+ PasswordWasAsked(false),
+ NumFiles(0)
+ {}
+
+ void Init();
+
+ CProgressDialog *ProgressDialog;
+
+ HRESULT SetOperation_Base(UInt32 notifyOp, const wchar_t *name, bool isDir);
+ HRESULT ShowAskPasswordDialog();
+};
+
+#endif
diff --git a/CPP/7zip/UI/GUI/UpdateGUI.cpp b/CPP/7zip/UI/GUI/UpdateGUI.cpp
new file mode 100644
index 0000000..aaf7ebd
--- /dev/null
+++ b/CPP/7zip/UI/GUI/UpdateGUI.cpp
@@ -0,0 +1,605 @@
+// UpdateGUI.cpp
+
+#include "StdAfx.h"
+
+#include "../../../Common/IntToString.h"
+#include "../../../Common/StringConvert.h"
+#include "../../../Common/StringToInt.h"
+
+#include "../../../Windows/DLL.h"
+#include "../../../Windows/FileDir.h"
+#include "../../../Windows/FileName.h"
+#include "../../../Windows/Thread.h"
+
+#include "../Common/WorkDir.h"
+
+#include "../Explorer/MyMessages.h"
+
+#include "../FileManager/LangUtils.h"
+#include "../FileManager/StringUtils.h"
+#include "../FileManager/resourceGui.h"
+
+#include "CompressDialog.h"
+#include "UpdateGUI.h"
+
+#include "resource2.h"
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NDir;
+
+static const char * const kDefaultSfxModule = "7z.sfx";
+static const char * const kSFXExtension = "exe";
+
+extern void AddMessageToString(UString &dest, const UString &src);
+
+UString HResultToMessage(HRESULT errorCode);
+
+class CThreadUpdating: public CProgressThreadVirt
+{
+ HRESULT ProcessVirt() Z7_override;
+public:
+ CCodecs *codecs;
+ const CObjectVector<COpenType> *formatIndices;
+ const UString *cmdArcPath;
+ CUpdateCallbackGUI *UpdateCallbackGUI;
+ NWildcard::CCensor *WildcardCensor;
+ CUpdateOptions *Options;
+ bool needSetPath;
+};
+
+HRESULT CThreadUpdating::ProcessVirt()
+{
+ CUpdateErrorInfo ei;
+ HRESULT res = UpdateArchive(codecs, *formatIndices, *cmdArcPath,
+ *WildcardCensor, *Options,
+ ei, UpdateCallbackGUI, UpdateCallbackGUI, needSetPath);
+ FinalMessage.ErrorMessage.Message = ei.Message.Ptr();
+ ErrorPaths = ei.FileNames;
+ if (res != S_OK)
+ return res;
+ return HRESULT_FROM_WIN32(ei.SystemError);
+}
+
+
+// parse command line properties
+
+static bool ParseProp_Time_BoolPair(const CProperty &prop, const char *name, CBoolPair &bp)
+{
+ if (!prop.Name.IsPrefixedBy_Ascii_NoCase(name))
+ return false;
+ const UString rem = prop.Name.Ptr((unsigned)strlen(name));
+ UString val = prop.Value;
+ if (!rem.IsEmpty())
+ {
+ if (!val.IsEmpty())
+ return true;
+ val = rem;
+ }
+ bool res;
+ if (StringToBool(val, res))
+ {
+ bp.Val = res;
+ bp.Def = true;
+ }
+ return true;
+}
+
+static void ParseProp(
+ const CProperty &prop,
+ NCompressDialog::CInfo &di)
+{
+ if (ParseProp_Time_BoolPair(prop, "tm", di.MTime)) return;
+ if (ParseProp_Time_BoolPair(prop, "tc", di.CTime)) return;
+ if (ParseProp_Time_BoolPair(prop, "ta", di.ATime)) return;
+}
+
+static void ParseProperties(
+ const CObjectVector<CProperty> &properties,
+ NCompressDialog::CInfo &di)
+{
+ FOR_VECTOR (i, properties)
+ {
+ ParseProp(properties[i], di);
+ }
+}
+
+
+
+
+
+static void AddProp_UString(CObjectVector<CProperty> &properties, const char *name, const UString &value)
+{
+ CProperty prop;
+ prop.Name = name;
+ prop.Value = value;
+ properties.Add(prop);
+}
+
+static void AddProp_UInt32(CObjectVector<CProperty> &properties, const char *name, UInt32 value)
+{
+ UString s;
+ s.Add_UInt32(value);
+ AddProp_UString(properties, name, s);
+}
+
+static void AddProp_bool(CObjectVector<CProperty> &properties, const char *name, bool value)
+{
+ AddProp_UString(properties, name, UString(value ? "on": "off"));
+}
+
+
+static void AddProp_BoolPair(CObjectVector<CProperty> &properties,
+ const char *name, const CBoolPair &bp)
+{
+ if (bp.Def)
+ AddProp_bool(properties, name, bp.Val);
+}
+
+
+
+static void SplitOptionsToStrings(const UString &src, UStringVector &strings)
+{
+ SplitString(src, strings);
+ FOR_VECTOR (i, strings)
+ {
+ UString &s = strings[i];
+ if (s.Len() > 2
+ && s[0] == '-'
+ && MyCharLower_Ascii(s[1]) == 'm')
+ s.DeleteFrontal(2);
+ }
+}
+
+static bool IsThereMethodOverride(bool is7z, const UStringVector &strings)
+{
+ FOR_VECTOR (i, strings)
+ {
+ const UString &s = strings[i];
+ if (is7z)
+ {
+ const wchar_t *end;
+ UInt64 n = ConvertStringToUInt64(s, &end);
+ if (n == 0 && *end == L'=')
+ return true;
+ }
+ else
+ {
+ if (s.Len() > 0)
+ if (s[0] == L'm' && s[1] == L'=')
+ return true;
+ }
+ }
+ return false;
+}
+
+static void ParseAndAddPropertires(CObjectVector<CProperty> &properties,
+ const UStringVector &strings)
+{
+ FOR_VECTOR (i, strings)
+ {
+ const UString &s = strings[i];
+ CProperty property;
+ const int index = s.Find(L'=');
+ if (index < 0)
+ property.Name = s;
+ else
+ {
+ property.Name.SetFrom(s, (unsigned)index);
+ property.Value = s.Ptr(index + 1);
+ }
+ properties.Add(property);
+ }
+}
+
+
+static void AddProp_Size(CObjectVector<CProperty> &properties, const char *name, const UInt64 size)
+{
+ UString s;
+ s.Add_UInt64(size);
+ s += 'b';
+ AddProp_UString(properties, name, s);
+}
+
+
+static void SetOutProperties(
+ CObjectVector<CProperty> &properties,
+ const NCompressDialog::CInfo &di,
+ bool is7z,
+ bool setMethod)
+{
+ if (di.Level != (UInt32)(Int32)-1)
+ AddProp_UInt32(properties, "x", (UInt32)di.Level);
+ if (setMethod)
+ {
+ if (!di.Method.IsEmpty())
+ AddProp_UString(properties, is7z ? "0": "m", di.Method);
+ if (di.Dict64 != (UInt64)(Int64)-1)
+ {
+ AString name;
+ if (is7z)
+ name = "0";
+ name += (di.OrderMode ? "mem" : "d");
+ AddProp_Size(properties, name, di.Dict64);
+ }
+ /*
+ if (di.Dict64_Chain != (UInt64)(Int64)-1)
+ {
+ AString name;
+ if (is7z)
+ name = "0";
+ name += "dc";
+ AddProp_Size(properties, name, di.Dict64_Chain);
+ }
+ */
+ if (di.Order != (UInt32)(Int32)-1)
+ {
+ AString name;
+ if (is7z)
+ name = "0";
+ name += (di.OrderMode ? "o" : "fb");
+ AddProp_UInt32(properties, name, (UInt32)di.Order);
+ }
+ }
+
+ if (!di.EncryptionMethod.IsEmpty())
+ AddProp_UString(properties, "em", di.EncryptionMethod);
+
+ if (di.EncryptHeadersIsAllowed)
+ AddProp_bool(properties, "he", di.EncryptHeaders);
+
+ if (di.SolidIsSpecified)
+ AddProp_Size(properties, "s", di.SolidBlockSize);
+
+ if (
+ // di.MultiThreadIsAllowed &&
+ di.NumThreads != (UInt32)(Int32)-1)
+ AddProp_UInt32(properties, "mt", di.NumThreads);
+
+ const NCompression::CMemUse &memUse = di.MemUsage;
+ if (memUse.IsDefined)
+ {
+ const char *kMemUse = "memuse";
+ if (memUse.IsPercent)
+ {
+ UString s;
+ // s += 'p'; // for debug: alternate percent method
+ s.Add_UInt64(memUse.Val);
+ s += '%';
+ AddProp_UString(properties, kMemUse, s);
+ }
+ else
+ AddProp_Size(properties, kMemUse, memUse.Val);
+ }
+
+ AddProp_BoolPair(properties, "tm", di.MTime);
+ AddProp_BoolPair(properties, "tc", di.CTime);
+ AddProp_BoolPair(properties, "ta", di.ATime);
+
+ if (di.TimePrec != (UInt32)(Int32)-1)
+ AddProp_UInt32(properties, "tp", di.TimePrec);
+}
+
+
+struct C_UpdateMode_ToAction_Pair
+{
+ NCompressDialog::NUpdateMode::EEnum UpdateMode;
+ const NUpdateArchive::CActionSet *ActionSet;
+};
+
+static const C_UpdateMode_ToAction_Pair g_UpdateMode_Pairs[] =
+{
+ { NCompressDialog::NUpdateMode::kAdd, &NUpdateArchive::k_ActionSet_Add },
+ { NCompressDialog::NUpdateMode::kUpdate, &NUpdateArchive::k_ActionSet_Update },
+ { NCompressDialog::NUpdateMode::kFresh, &NUpdateArchive::k_ActionSet_Fresh },
+ { NCompressDialog::NUpdateMode::kSync, &NUpdateArchive::k_ActionSet_Sync }
+};
+
+static int FindActionSet(const NUpdateArchive::CActionSet &actionSet)
+{
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_UpdateMode_Pairs); i++)
+ if (actionSet.IsEqualTo(*g_UpdateMode_Pairs[i].ActionSet))
+ return (int)i;
+ return -1;
+}
+
+static int FindUpdateMode(NCompressDialog::NUpdateMode::EEnum mode)
+{
+ for (unsigned i = 0; i < Z7_ARRAY_SIZE(g_UpdateMode_Pairs); i++)
+ if (mode == g_UpdateMode_Pairs[i].UpdateMode)
+ return (int)i;
+ return -1;
+}
+
+
+static HRESULT ShowDialog(
+ CCodecs *codecs,
+ const CObjectVector<NWildcard::CCensorPath> &censor,
+ CUpdateOptions &options,
+ CUpdateCallbackGUI *callback, HWND hwndParent)
+{
+ if (options.Commands.Size() != 1)
+ throw "It must be one command";
+ /*
+ FString currentDirPrefix;
+ #ifndef UNDER_CE
+ {
+ if (!MyGetCurrentDirectory(currentDirPrefix))
+ return E_FAIL;
+ NName::NormalizeDirPathPrefix(currentDirPrefix);
+ }
+ #endif
+ */
+
+ bool oneFile = false;
+ NFind::CFileInfo fileInfo;
+ UString name;
+
+ /*
+ if (censor.Pairs.Size() > 0)
+ {
+ const NWildcard::CPair &pair = censor.Pairs[0];
+ if (pair.Head.IncludeItems.Size() > 0)
+ {
+ const NWildcard::CItem &item = pair.Head.IncludeItems[0];
+ if (item.ForFile)
+ {
+ name = pair.Prefix;
+ FOR_VECTOR (i, item.PathParts)
+ {
+ if (i > 0)
+ name.Add_PathSepar();
+ name += item.PathParts[i];
+ }
+ if (fileInfo.Find(us2fs(name)))
+ {
+ if (censor.Pairs.Size() == 1 && pair.Head.IncludeItems.Size() == 1)
+ oneFile = !fileInfo.IsDir();
+ }
+ }
+ }
+ }
+ */
+ if (censor.Size() > 0)
+ {
+ const NWildcard::CCensorPath &cp = censor[0];
+ if (cp.Include)
+ {
+ {
+ if (fileInfo.Find(us2fs(cp.Path)))
+ {
+ if (censor.Size() == 1)
+ oneFile = !fileInfo.IsDir();
+ }
+ }
+ }
+ }
+
+
+ /*
+ // v23: we restore current dir in dialog code
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ CCurrentDirRestorer curDirRestorer;
+ #endif
+ */
+
+ CCompressDialog dialog;
+ NCompressDialog::CInfo &di = dialog.Info;
+ dialog.ArcFormats = &codecs->Formats;
+ {
+ CObjectVector<CCodecInfoUser> userCodecs;
+ codecs->Get_CodecsInfoUser_Vector(userCodecs);
+ dialog.SetMethods(userCodecs);
+ }
+
+ if (options.MethodMode.Type_Defined)
+ di.FormatIndex = options.MethodMode.Type.FormatIndex;
+
+ FOR_VECTOR (i, codecs->Formats)
+ {
+ const CArcInfoEx &ai = codecs->Formats[i];
+ if (!ai.UpdateEnabled)
+ continue;
+ if (!oneFile && ai.Flags_KeepName())
+ continue;
+ if ((int)i != di.FormatIndex)
+ {
+ if (ai.Flags_HashHandler())
+ continue;
+ if (ai.Name.IsEqualTo_Ascii_NoCase("swfc"))
+ if (!oneFile || name.Len() < 4 || !StringsAreEqualNoCase_Ascii(name.RightPtr(4), ".swf"))
+ continue;
+ }
+ dialog.ArcIndices.Add(i);
+ }
+ if (dialog.ArcIndices.IsEmpty())
+ {
+ ShowErrorMessage(L"No Update Engines");
+ return E_FAIL;
+ }
+
+ // di.ArchiveName = options.ArchivePath.GetFinalPath();
+ di.ArcPath = options.ArchivePath.GetPathWithoutExt();
+ dialog.OriginalFileName = fs2us(fileInfo.Name);
+
+ di.PathMode = options.PathMode;
+
+ // di.CurrentDirPrefix = currentDirPrefix;
+ di.SFXMode = options.SfxMode;
+ di.OpenShareForWrite = options.OpenShareForWrite;
+ di.DeleteAfterCompressing = options.DeleteAfterCompressing;
+
+ di.SymLinks = options.SymLinks;
+ di.HardLinks = options.HardLinks;
+ di.AltStreams = options.AltStreams;
+ di.NtSecurity = options.NtSecurity;
+ if (options.SetArcMTime)
+ di.SetArcMTime.SetTrueTrue();
+ if (options.PreserveATime)
+ di.PreserveATime.SetTrueTrue();
+
+ if (callback->PasswordIsDefined)
+ di.Password = callback->Password;
+
+ di.KeepName = !oneFile;
+
+ NUpdateArchive::CActionSet &actionSet = options.Commands.Front().ActionSet;
+
+ {
+ int index = FindActionSet(actionSet);
+ if (index < 0)
+ return E_NOTIMPL;
+ di.UpdateMode = g_UpdateMode_Pairs[(unsigned)index].UpdateMode;
+ }
+
+ ParseProperties(options.MethodMode.Properties, di);
+
+ if (dialog.Create(hwndParent) != IDOK)
+ return E_ABORT;
+
+ options.DeleteAfterCompressing = di.DeleteAfterCompressing;
+
+ options.SymLinks = di.SymLinks;
+ options.HardLinks = di.HardLinks;
+ options.AltStreams = di.AltStreams;
+ options.NtSecurity = di.NtSecurity;
+ options.SetArcMTime = di.SetArcMTime.Val;
+ if (di.PreserveATime.Def)
+ options.PreserveATime = di.PreserveATime.Val;
+
+ /*
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ curDirRestorer.NeedRestore = dialog.CurrentDirWasChanged;
+ #endif
+ */
+
+ options.VolumesSizes = di.VolumeSizes;
+ /*
+ if (di.VolumeSizeIsDefined)
+ {
+ MyMessageBox(L"Splitting to volumes is not supported");
+ return E_FAIL;
+ }
+ */
+
+
+ {
+ int index = FindUpdateMode(di.UpdateMode);
+ if (index < 0)
+ return E_FAIL;
+ actionSet = *g_UpdateMode_Pairs[index].ActionSet;
+ }
+
+ options.PathMode = di.PathMode;
+
+ const CArcInfoEx &archiverInfo = codecs->Formats[di.FormatIndex];
+ callback->PasswordIsDefined = (!di.Password.IsEmpty());
+ if (callback->PasswordIsDefined)
+ callback->Password = di.Password;
+
+ // we clear command line options, and fill options form Dialog
+ options.MethodMode.Properties.Clear();
+
+ const bool is7z = archiverInfo.Is_7z();
+
+ UStringVector optionStrings;
+ SplitOptionsToStrings(di.Options, optionStrings);
+ const bool methodOverride = IsThereMethodOverride(is7z, optionStrings);
+
+ SetOutProperties(options.MethodMode.Properties, di,
+ is7z,
+ !methodOverride); // setMethod
+
+ options.OpenShareForWrite = di.OpenShareForWrite;
+ ParseAndAddPropertires(options.MethodMode.Properties, optionStrings);
+
+ if (di.SFXMode)
+ options.SfxMode = true;
+ options.MethodMode.Type = COpenType();
+ options.MethodMode.Type_Defined = true;
+ options.MethodMode.Type.FormatIndex = di.FormatIndex;
+
+ options.ArchivePath.VolExtension = archiverInfo.GetMainExt();
+ if (di.SFXMode)
+ options.ArchivePath.BaseExtension = kSFXExtension;
+ else
+ options.ArchivePath.BaseExtension = options.ArchivePath.VolExtension;
+ options.ArchivePath.ParseFromPath(di.ArcPath, k_ArcNameMode_Smart);
+
+ NWorkDir::CInfo workDirInfo;
+ workDirInfo.Load();
+ options.WorkingDir.Empty();
+ if (workDirInfo.Mode != NWorkDir::NMode::kCurrent)
+ {
+ FString fullPath;
+ MyGetFullPathName(us2fs(di.ArcPath), fullPath);
+ FString namePart;
+ options.WorkingDir = GetWorkDir(workDirInfo, fullPath, namePart);
+ CreateComplexDir(options.WorkingDir);
+ }
+ return S_OK;
+}
+
+HRESULT UpdateGUI(
+ CCodecs *codecs,
+ const CObjectVector<COpenType> &formatIndices,
+ const UString &cmdArcPath,
+ NWildcard::CCensor &censor,
+ CUpdateOptions &options,
+ bool showDialog,
+ bool &messageWasDisplayed,
+ CUpdateCallbackGUI *callback,
+ HWND hwndParent)
+{
+ messageWasDisplayed = false;
+ bool needSetPath = true;
+ if (showDialog)
+ {
+ RINOK(ShowDialog(codecs, censor.CensorPaths, options, callback, hwndParent))
+ needSetPath = false;
+ }
+ if (options.SfxMode && options.SfxModule.IsEmpty())
+ {
+ options.SfxModule = NWindows::NDLL::GetModuleDirPrefix();
+ options.SfxModule += kDefaultSfxModule;
+ }
+
+ CThreadUpdating tu;
+
+ tu.needSetPath = needSetPath;
+
+ tu.codecs = codecs;
+ tu.formatIndices = &formatIndices;
+ tu.cmdArcPath = &cmdArcPath;
+
+ tu.UpdateCallbackGUI = callback;
+ tu.UpdateCallbackGUI->ProgressDialog = &tu;
+ tu.UpdateCallbackGUI->Init();
+
+ UString title = LangString(IDS_PROGRESS_COMPRESSING);
+ if (!formatIndices.IsEmpty())
+ {
+ const int fin = formatIndices[0].FormatIndex;
+ if (fin >= 0)
+ if (codecs->Formats[fin].Flags_HashHandler())
+ title = LangString(IDS_CHECKSUM_CALCULATING);
+ }
+
+ /*
+ if (hwndParent != 0)
+ {
+ tu.ProgressDialog.MainWindow = hwndParent;
+ // tu.ProgressDialog.MainTitle = fileName;
+ tu.ProgressDialog.MainAddTitle = title + L' ';
+ }
+ */
+
+ tu.WildcardCensor = &censor;
+ tu.Options = &options;
+ tu.IconID = IDI_ICON;
+
+ RINOK(tu.Create(title, hwndParent))
+
+ messageWasDisplayed = tu.ThreadFinishedOK && tu.MessagesDisplayed;
+ return tu.Result;
+}
diff --git a/CPP/7zip/UI/GUI/UpdateGUI.h b/CPP/7zip/UI/GUI/UpdateGUI.h
new file mode 100644
index 0000000..0c43a01
--- /dev/null
+++ b/CPP/7zip/UI/GUI/UpdateGUI.h
@@ -0,0 +1,33 @@
+// GUI/UpdateGUI.h
+
+#ifndef ZIP7_INC_UPDATE_GUI_H
+#define ZIP7_INC_UPDATE_GUI_H
+
+#include "../Common/Update.h"
+
+#include "UpdateCallbackGUI.h"
+
+/*
+ callback->FailedFiles contains names of files for that there were problems.
+ RESULT can be S_OK, even if there are such warnings!!!
+
+ RESULT = E_ABORT - user break.
+ RESULT != E_ABORT:
+ {
+ messageWasDisplayed = true - message was displayed already.
+ messageWasDisplayed = false - there was some internal error, so you must show error message.
+ }
+*/
+
+HRESULT UpdateGUI(
+ CCodecs *codecs,
+ const CObjectVector<COpenType> &formatIndices,
+ const UString &cmdArcPath2,
+ NWildcard::CCensor &censor,
+ CUpdateOptions &options,
+ bool showDialog,
+ bool &messageWasDisplayed,
+ CUpdateCallbackGUI *callback,
+ HWND hwndParent = NULL);
+
+#endif
diff --git a/CPP/7zip/UI/GUI/makefile b/CPP/7zip/UI/GUI/makefile
new file mode 100644
index 0000000..9e2a9b4
--- /dev/null
+++ b/CPP/7zip/UI/GUI/makefile
@@ -0,0 +1,148 @@
+PROG = 7zG.exe
+CFLAGS = $(CFLAGS) \
+ -DZ7_LANG \
+ -DZ7_EXTERNAL_CODECS \
+
+!IFDEF UNDER_CE
+LIBS = $(LIBS) ceshell.lib Commctrl.lib
+!ELSE
+LIBS = $(LIBS) comctl32.lib htmlhelp.lib comdlg32.lib gdi32.lib
+CFLAGS = $(CFLAGS) -DZ7_LONG_PATH -DZ7_LARGE_PAGES -DZ7_DEVICE_FILE
+!ENDIF
+
+GUI_OBJS = \
+ $O\BenchmarkDialog.obj \
+ $O\CompressDialog.obj \
+ $O\ExtractDialog.obj \
+ $O\ExtractGUI.obj \
+ $O\GUI.obj \
+ $O\HashGUI.obj \
+ $O\UpdateCallbackGUI.obj \
+ $O\UpdateCallbackGUI2.obj \
+ $O\UpdateGUI.obj \
+
+COMMON_OBJS = \
+ $O\CommandLineParser.obj \
+ $O\CRC.obj \
+ $O\DynLimBuf.obj \
+ $O\IntToString.obj \
+ $O\Lang.obj \
+ $O\ListFileUtils.obj \
+ $O\MyString.obj \
+ $O\MyVector.obj \
+ $O\NewHandler.obj \
+ $O\StringConvert.obj \
+ $O\StringToInt.obj \
+ $O\UTFConvert.obj \
+ $O\Wildcard.obj \
+
+WIN_OBJS = \
+ $O\Clipboard.obj \
+ $O\CommonDialog.obj \
+ $O\DLL.obj \
+ $O\ErrorMsg.obj \
+ $O\FileDir.obj \
+ $O\FileFind.obj \
+ $O\FileIO.obj \
+ $O\FileLink.obj \
+ $O\FileName.obj \
+ $O\FileSystem.obj \
+ $O\MemoryGlobal.obj \
+ $O\MemoryLock.obj \
+ $O\PropVariant.obj \
+ $O\PropVariantConv.obj \
+ $O\Registry.obj \
+ $O\ResourceString.obj \
+ $O\Shell.obj \
+ $O\Synchronization.obj \
+ $O\System.obj \
+ $O\SystemInfo.obj \
+ $O\TimeUtils.obj \
+ $O\Window.obj \
+
+WIN_CTRL_OBJS = \
+ $O\ComboBox.obj \
+ $O\Dialog.obj \
+ $O\ListView.obj \
+
+7ZIP_COMMON_OBJS = \
+ $O\CreateCoder.obj \
+ $O\FilePathAutoRename.obj \
+ $O\FileStreams.obj \
+ $O\FilterCoder.obj \
+ $O\LimitedStreams.obj \
+ $O\MethodProps.obj \
+ $O\MultiOutStream.obj \
+ $O\ProgressUtils.obj \
+ $O\PropId.obj \
+ $O\StreamObjects.obj \
+ $O\StreamUtils.obj \
+ $O\UniqBlocks.obj \
+
+UI_COMMON_OBJS = \
+ $O\ArchiveCommandLine.obj \
+ $O\ArchiveExtractCallback.obj \
+ $O\ArchiveOpenCallback.obj \
+ $O\Bench.obj \
+ $O\DefaultName.obj \
+ $O\EnumDirItems.obj \
+ $O\Extract.obj \
+ $O\ExtractingFilePath.obj \
+ $O\HashCalc.obj \
+ $O\LoadCodecs.obj \
+ $O\OpenArchive.obj \
+ $O\PropIDUtils.obj \
+ $O\SetProperties.obj \
+ $O\SortUtils.obj \
+ $O\TempFiles.obj \
+ $O\Update.obj \
+ $O\UpdateAction.obj \
+ $O\UpdateCallback.obj \
+ $O\UpdatePair.obj \
+ $O\UpdateProduce.obj \
+ $O\WorkDir.obj \
+ $O\ZipRegistry.obj \
+
+AR_COMMON_OBJS = \
+ $O\ItemNameUtils.obj \
+ $O\OutStreamWithCRC.obj \
+
+FM_OBJS = \
+ $O\EditDialog.obj \
+ $O\ExtractCallback.obj \
+ $O\FormatUtils.obj \
+ $O\HelpUtils.obj \
+ $O\LangUtils.obj \
+ $O\ListViewDialog.obj \
+ $O\OpenCallback.obj \
+ $O\ProgramLocation.obj \
+ $O\PropertyName.obj \
+ $O\RegistryUtils.obj \
+ $O\SplitUtils.obj \
+ $O\StringUtils.obj \
+ $O\OverwriteDialog.obj \
+ $O\PasswordDialog.obj \
+ $O\ProgressDialog2.obj \
+
+FM_OBJS = $(FM_OBJS) \
+ $O\BrowseDialog.obj \
+ $O\ComboDialog.obj \
+ $O\SysIconUtils.obj \
+
+EXPLORER_OBJS = \
+ $O\MyMessages.obj \
+
+COMPRESS_OBJS = \
+ $O\CopyCoder.obj \
+
+C_OBJS = \
+ $O\Alloc.obj \
+ $O\CpuArch.obj \
+ $O\DllSecur.obj \
+ $O\Sort.obj \
+ $O\Threads.obj \
+
+!include "../../Crc.mak"
+
+
+!include "../../7zip.mak"
diff --git a/CPP/7zip/UI/GUI/resource.rc b/CPP/7zip/UI/GUI/resource.rc
new file mode 100644
index 0000000..04af815
--- /dev/null
+++ b/CPP/7zip/UI/GUI/resource.rc
@@ -0,0 +1,25 @@
+#include "../../MyVersionInfo.rc"
+// #include <winnt.h>
+
+#include "resource2.rc"
+#include "resource3.rc"
+
+#include "../FileManager/resourceGui.rc"
+
+MY_VERSION_INFO(MY_VFT_APP, "7-Zip GUI", "7zg", "7zg.exe")
+
+IDI_ICON ICON "FM.ico"
+
+#ifndef UNDER_CE
+1 24 MOVEABLE PURE "7zG.exe.manifest"
+#endif
+
+#include "../FileManager/PropertyName.rc"
+#include "../FileManager/OverwriteDialog.rc"
+#include "../FileManager/PasswordDialog.rc"
+#include "../FileManager/ProgressDialog2.rc"
+#include "Extract.rc"
+#include "../FileManager/BrowseDialog.rc"
+#include "../FileManager/ComboDialog.rc"
+#include "../FileManager/EditDialog.rc"
+#include "../FileManager/ListViewDialog.rc"
diff --git a/CPP/7zip/UI/GUI/resource2.h b/CPP/7zip/UI/GUI/resource2.h
index 152e71f..cd88292 100644
--- a/CPP/7zip/UI/GUI/resource2.h
+++ b/CPP/7zip/UI/GUI/resource2.h
@@ -1,2 +1,2 @@
-#define IDS_PROGRESS_COMPRESSING 3301
-#define IDS_ARCHIVES_COLON 3907
+#define IDS_PROGRESS_COMPRESSING 3301
+#define IDS_ARCHIVES_COLON 3907
diff --git a/CPP/7zip/UI/GUI/resource2.rc b/CPP/7zip/UI/GUI/resource2.rc
new file mode 100644
index 0000000..49534f5
--- /dev/null
+++ b/CPP/7zip/UI/GUI/resource2.rc
@@ -0,0 +1,10 @@
+#include "ExtractDialog.rc"
+#include "CompressDialog.rc"
+#include "BenchmarkDialog.rc"
+#include "resource2.h"
+
+STRINGTABLE
+BEGIN
+ IDS_PROGRESS_COMPRESSING "Compressing"
+ IDS_ARCHIVES_COLON "Archives:"
+END
diff --git a/CPP/7zip/UI/GUI/resource3.h b/CPP/7zip/UI/GUI/resource3.h
new file mode 100644
index 0000000..c25737f
--- /dev/null
+++ b/CPP/7zip/UI/GUI/resource3.h
@@ -0,0 +1,10 @@
+#define IDS_PROGRESS_REMOVE 3305
+
+#define IDS_PROGRESS_ADD 3320
+#define IDS_PROGRESS_UPDATE 3321
+#define IDS_PROGRESS_ANALYZE 3322
+#define IDS_PROGRESS_REPLICATE 3323
+#define IDS_PROGRESS_REPACK 3324
+
+#define IDS_PROGRESS_DELETE 3326
+#define IDS_PROGRESS_HEADER 3327
diff --git a/CPP/7zip/UI/GUI/resource3.rc b/CPP/7zip/UI/GUI/resource3.rc
new file mode 100644
index 0000000..cfc8bc3
--- /dev/null
+++ b/CPP/7zip/UI/GUI/resource3.rc
@@ -0,0 +1,15 @@
+#include "resource3.h"
+
+STRINGTABLE
+BEGIN
+ IDS_PROGRESS_REMOVE "Removing"
+
+ IDS_PROGRESS_ADD "Adding"
+ IDS_PROGRESS_UPDATE "Updating"
+ IDS_PROGRESS_ANALYZE "Analyzing"
+ IDS_PROGRESS_REPLICATE "Replicating"
+ IDS_PROGRESS_REPACK "Repacking"
+
+ IDS_PROGRESS_DELETE "Deleting"
+ IDS_PROGRESS_HEADER "Header creating"
+END
diff --git a/CPP/7zip/UI/makefile b/CPP/7zip/UI/makefile
new file mode 100644
index 0000000..1b0cdbe
--- /dev/null
+++ b/CPP/7zip/UI/makefile
@@ -0,0 +1,12 @@
+DIRS = \
+ Client7z\~ \
+ Console\~ \
+ Explorer\~ \
+ Far\~ \
+ FileManager\~ \
+ GUI\~ \
+
+all: $(DIRS)
+
+$(DIRS):
+!include "../SubBuild.mak"
diff --git a/CPP/7zip/cmpl_clang.mak b/CPP/7zip/cmpl_clang.mak
new file mode 100644
index 0000000..e62e1e6
--- /dev/null
+++ b/CPP/7zip/cmpl_clang.mak
@@ -0,0 +1,3 @@
+include ../../var_clang.mak
+include ../../warn_clang.mak
+include makefile.gcc
diff --git a/CPP/7zip/cmpl_clang_arm64.mak b/CPP/7zip/cmpl_clang_arm64.mak
new file mode 100644
index 0000000..3f6b02b
--- /dev/null
+++ b/CPP/7zip/cmpl_clang_arm64.mak
@@ -0,0 +1,3 @@
+include ../../var_clang_arm64.mak
+include ../../warn_clang.mak
+include makefile.gcc
diff --git a/CPP/7zip/cmpl_clang_x64.mak b/CPP/7zip/cmpl_clang_x64.mak
new file mode 100644
index 0000000..b61e2af
--- /dev/null
+++ b/CPP/7zip/cmpl_clang_x64.mak
@@ -0,0 +1,3 @@
+include ../../var_clang_x64.mak
+include ../../warn_clang.mak
+include makefile.gcc
diff --git a/CPP/7zip/cmpl_clang_x86.mak b/CPP/7zip/cmpl_clang_x86.mak
new file mode 100644
index 0000000..0e5cb76
--- /dev/null
+++ b/CPP/7zip/cmpl_clang_x86.mak
@@ -0,0 +1,3 @@
+include ../../var_clang_x86.mak
+include ../../warn_clang.mak
+include makefile.gcc
diff --git a/CPP/7zip/cmpl_gcc.mak b/CPP/7zip/cmpl_gcc.mak
new file mode 100644
index 0000000..7a1aef2
--- /dev/null
+++ b/CPP/7zip/cmpl_gcc.mak
@@ -0,0 +1,3 @@
+include ../../var_gcc.mak
+include ../../warn_gcc.mak
+include makefile.gcc
diff --git a/CPP/7zip/cmpl_gcc_arm64.mak b/CPP/7zip/cmpl_gcc_arm64.mak
new file mode 100644
index 0000000..53a8584
--- /dev/null
+++ b/CPP/7zip/cmpl_gcc_arm64.mak
@@ -0,0 +1,3 @@
+include ../../var_gcc_arm64.mak
+include ../../warn_gcc.mak
+include makefile.gcc
diff --git a/CPP/7zip/cmpl_gcc_x64.mak b/CPP/7zip/cmpl_gcc_x64.mak
new file mode 100644
index 0000000..500c30e
--- /dev/null
+++ b/CPP/7zip/cmpl_gcc_x64.mak
@@ -0,0 +1,3 @@
+include ../../var_gcc_x64.mak
+include ../../warn_gcc.mak
+include makefile.gcc
diff --git a/CPP/7zip/cmpl_gcc_x86.mak b/CPP/7zip/cmpl_gcc_x86.mak
new file mode 100644
index 0000000..e768707
--- /dev/null
+++ b/CPP/7zip/cmpl_gcc_x86.mak
@@ -0,0 +1,3 @@
+include ../../var_gcc_x86.mak
+include ../../warn_gcc.mak
+include makefile.gcc
diff --git a/CPP/7zip/cmpl_mac_arm64.mak b/CPP/7zip/cmpl_mac_arm64.mak
new file mode 100644
index 0000000..941028e
--- /dev/null
+++ b/CPP/7zip/cmpl_mac_arm64.mak
@@ -0,0 +1,3 @@
+include ../../var_mac_arm64.mak
+include ../../warn_clang_mac.mak
+include makefile.gcc
diff --git a/CPP/7zip/cmpl_mac_x64.mak b/CPP/7zip/cmpl_mac_x64.mak
new file mode 100644
index 0000000..d3aa039
--- /dev/null
+++ b/CPP/7zip/cmpl_mac_x64.mak
@@ -0,0 +1,3 @@
+include ../../var_mac_x64.mak
+include ../../warn_clang_mac.mak
+include makefile.gcc
diff --git a/CPP/7zip/makefile b/CPP/7zip/makefile
new file mode 100644
index 0000000..9d31e6b
--- /dev/null
+++ b/CPP/7zip/makefile
@@ -0,0 +1,10 @@
+DIRS = \
+ UI\~ \
+ Bundles\~ \
+
+all: $(DIRS)
+
+$(DIRS):
+ cd $(@D)
+ $(MAKE) -nologo
+ cd ..
diff --git a/CPP/7zip/var_clang.mak b/CPP/7zip/var_clang.mak
new file mode 100644
index 0000000..a6df26e
--- /dev/null
+++ b/CPP/7zip/var_clang.mak
@@ -0,0 +1,11 @@
+PLATFORM=
+O=b/c
+IS_X64=
+IS_X86=
+IS_ARM64=
+CROSS_COMPILE=
+MY_ARCH=
+USE_ASM=
+CC=$(CROSS_COMPILE)clang
+CXX=$(CROSS_COMPILE)clang++
+USE_CLANG=1
diff --git a/CPP/7zip/var_clang_arm64.mak b/CPP/7zip/var_clang_arm64.mak
new file mode 100644
index 0000000..4b35409
--- /dev/null
+++ b/CPP/7zip/var_clang_arm64.mak
@@ -0,0 +1,11 @@
+PLATFORM=arm64
+O=b/c_$(PLATFORM)
+IS_X64=
+IS_X86=
+IS_ARM64=1
+CROSS_COMPILE=
+MY_ARCH=
+USE_ASM=1
+CC=$(CROSS_COMPILE)clang
+CXX=$(CROSS_COMPILE)clang++
+USE_CLANG=1
diff --git a/CPP/7zip/var_clang_x64.mak b/CPP/7zip/var_clang_x64.mak
new file mode 100644
index 0000000..fefed51
--- /dev/null
+++ b/CPP/7zip/var_clang_x64.mak
@@ -0,0 +1,12 @@
+PLATFORM=x64
+O=b/c_$(PLATFORM)
+IS_X64=1
+IS_X86=
+IS_ARM64=
+CROSS_COMPILE=
+MY_ARCH=
+USE_ASM=1
+CC=$(CROSS_COMPILE)clang
+CXX=$(CROSS_COMPILE)clang++
+USE_CLANG=1
+
diff --git a/CPP/7zip/var_clang_x86.mak b/CPP/7zip/var_clang_x86.mak
new file mode 100644
index 0000000..5f3c2d9
--- /dev/null
+++ b/CPP/7zip/var_clang_x86.mak
@@ -0,0 +1,12 @@
+PLATFORM=x86
+O=b/c_$(PLATFORM)
+IS_X64=
+IS_X86=1
+IS_ARM64=
+CROSS_COMPILE=
+MY_ARCH=-m32
+USE_ASM=1
+CC=$(CROSS_COMPILE)clang
+CXX=$(CROSS_COMPILE)clang++
+USE_CLANG=1
+
diff --git a/CPP/7zip/var_gcc.mak b/CPP/7zip/var_gcc.mak
new file mode 100644
index 0000000..664491c
--- /dev/null
+++ b/CPP/7zip/var_gcc.mak
@@ -0,0 +1,12 @@
+PLATFORM=
+O=b/g
+IS_X64=
+IS_X86=
+IS_ARM64=
+CROSS_COMPILE=
+MY_ARCH=
+USE_ASM=
+CC=$(CROSS_COMPILE)gcc
+CXX=$(CROSS_COMPILE)g++
+
+# -march=armv8-a+crc+crypto
diff --git a/CPP/7zip/var_gcc_arm64.mak b/CPP/7zip/var_gcc_arm64.mak
new file mode 100644
index 0000000..4bbb687
--- /dev/null
+++ b/CPP/7zip/var_gcc_arm64.mak
@@ -0,0 +1,12 @@
+PLATFORM=arm64
+O=b/g_$(PLATFORM)
+IS_X64=
+IS_X86=
+IS_ARM64=1
+CROSS_COMPILE=
+MY_ARCH=-mtune=cortex-a53
+USE_ASM=1
+CC=$(CROSS_COMPILE)gcc
+CXX=$(CROSS_COMPILE)g++
+
+# -march=armv8-a+crc+crypto
diff --git a/CPP/7zip/var_gcc_x64.mak b/CPP/7zip/var_gcc_x64.mak
new file mode 100644
index 0000000..1acf604
--- /dev/null
+++ b/CPP/7zip/var_gcc_x64.mak
@@ -0,0 +1,10 @@
+PLATFORM=x64
+O=b/g_$(PLATFORM)
+IS_X64=1
+IS_X86=
+IS_ARM64=
+CROSS_COMPILE=
+MY_ARCH=
+USE_ASM=1
+CC=$(CROSS_COMPILE)gcc
+CXX=$(CROSS_COMPILE)g++
diff --git a/CPP/7zip/var_gcc_x86.mak b/CPP/7zip/var_gcc_x86.mak
new file mode 100644
index 0000000..288bf94
--- /dev/null
+++ b/CPP/7zip/var_gcc_x86.mak
@@ -0,0 +1,11 @@
+PLATFORM=x86
+O=b/g_$(PLATFORM)
+IS_X64=
+IS_X86=1
+IS_ARM64=
+CROSS_COMPILE=
+MY_ARCH=-m32
+USE_ASM=1
+CC=$(CROSS_COMPILE)gcc
+CXX=$(CROSS_COMPILE)g++
+
diff --git a/CPP/7zip/var_mac_arm64.mak b/CPP/7zip/var_mac_arm64.mak
new file mode 100644
index 0000000..adf5fa1
--- /dev/null
+++ b/CPP/7zip/var_mac_arm64.mak
@@ -0,0 +1,11 @@
+PLATFORM=arm64
+O=b/m_$(PLATFORM)
+IS_X64=
+IS_X86=
+IS_ARM64=1
+CROSS_COMPILE=
+MY_ARCH=-arch arm64
+USE_ASM=1
+CC=$(CROSS_COMPILE)clang
+CXX=$(CROSS_COMPILE)clang++
+USE_CLANG=1
diff --git a/CPP/7zip/var_mac_x64.mak b/CPP/7zip/var_mac_x64.mak
new file mode 100644
index 0000000..13d7aa7
--- /dev/null
+++ b/CPP/7zip/var_mac_x64.mak
@@ -0,0 +1,11 @@
+PLATFORM=x64
+O=b/m_$(PLATFORM)
+IS_X64=1
+IS_X86=
+IS_ARM64=
+CROSS_COMPILE=
+MY_ARCH=-arch x86_64
+USE_ASM=
+CC=$(CROSS_COMPILE)clang
+CXX=$(CROSS_COMPILE)clang++
+USE_CLANG=1
diff --git a/CPP/7zip/warn_clang.mak b/CPP/7zip/warn_clang.mak
new file mode 100644
index 0000000..0d00730
--- /dev/null
+++ b/CPP/7zip/warn_clang.mak
@@ -0,0 +1,3 @@
+CFLAGS_WARN = -Weverything -Wfatal-errors
+# CXX_STD_FLAGS = -std=c++11
+# CXX_STD_FLAGS =
diff --git a/CPP/7zip/warn_clang_mac.mak b/CPP/7zip/warn_clang_mac.mak
new file mode 100644
index 0000000..ed936c5
--- /dev/null
+++ b/CPP/7zip/warn_clang_mac.mak
@@ -0,0 +1,9 @@
+CFLAGS_WARN = -Weverything -Wfatal-errors -Wno-poison-system-directories
+CXX_STD_FLAGS = -std=c++98
+CXX_STD_FLAGS = -std=c++11
+CXX_STD_FLAGS = -std=c++14
+CXX_STD_FLAGS = -std=c++17
+CXX_STD_FLAGS = -std=c++20
+CXX_STD_FLAGS = -std=c++23
+
+CXX_STD_FLAGS = -std=c++11
diff --git a/CPP/7zip/warn_gcc.mak b/CPP/7zip/warn_gcc.mak
new file mode 100644
index 0000000..7eb1f57
--- /dev/null
+++ b/CPP/7zip/warn_gcc.mak
@@ -0,0 +1,45 @@
+CFLAGS_WARN_GCC_4_8 = \
+ -Waddress \
+ -Waggressive-loop-optimizations \
+ -Wattributes \
+ -Wcast-align \
+ -Wcomment \
+ -Wdiv-by-zero \
+ -Wformat-contains-nul \
+ -Winit-self \
+ -Wint-to-pointer-cast \
+ -Wunused \
+ -Wunused-macros \
+
+CFLAGS_WARN_GCC_6 = $(CFLAGS_WARN_GCC_4_8)\
+ -Wbool-compare \
+ -Wduplicated-cond \
+
+# -Wno-strict-aliasing
+
+CFLAGS_WARN_GCC_9 = $(CFLAGS_WARN_GCC_6)\
+ -Waddress-of-packed-member \
+ -Wbool-operation \
+ -Wcast-align=strict \
+ -Wconversion \
+ -Wdangling-else \
+ -Wduplicated-branches \
+ -Wimplicit-fallthrough=5 \
+ -Wint-in-bool-context \
+ -Wmaybe-uninitialized \
+ -Wmisleading-indentation \
+ -Wmissing-attributes
+
+# In C: -Wsign-conversion enabled also by -Wconversion
+# -Wno-sign-conversion \
+
+
+CFLAGS_WARN_GCC_PPMD_UNALIGNED = \
+ -Wno-strict-aliasing \
+
+
+# CFLAGS_WARN = $(CFLAGS_WARN_GCC_4_8)
+CFLAGS_WARN = $(CFLAGS_WARN_GCC_9)
+
+# CXX_STD_FLAGS = -std=c++11
+# CXX_STD_FLAGS =
diff --git a/CPP/Build.mak b/CPP/Build.mak
index 5752491..393fa2c 100644
--- a/CPP/Build.mak
+++ b/CPP/Build.mak
@@ -1,156 +1,229 @@
-LIBS = $(LIBS) oleaut32.lib ole32.lib
-
-!IFNDEF MY_NO_UNICODE
-CFLAGS = $(CFLAGS) -DUNICODE -D_UNICODE
-!ENDIF
-
-!IFNDEF O
-!IFDEF PLATFORM
-O=$(PLATFORM)
-!ELSE
-O=o
-!ENDIF
-!ENDIF
-
-# CFLAGS = $(CFLAGS) -FAsc -Fa$O/asm/
-
-
-!IF "$(PLATFORM)" == "x64"
-MY_ML = ml64 -Dx64 -WX
-!ELSEIF "$(PLATFORM)" == "arm"
-MY_ML = armasm -WX
-!ELSE
-MY_ML = ml -WX
-!ENDIF
-
-
-!IFDEF UNDER_CE
-RFLAGS = $(RFLAGS) -dUNDER_CE
-!IFDEF MY_CONSOLE
-LFLAGS = $(LFLAGS) /ENTRY:mainACRTStartup
-!ENDIF
-!ELSE
-!IFDEF OLD_COMPILER
-LFLAGS = $(LFLAGS) -OPT:NOWIN98
-!ENDIF
-!IF "$(PLATFORM)" != "arm" && "$(PLATFORM)" != "arm64"
-CFLAGS = $(CFLAGS) -Gr
-!ENDIF
-LIBS = $(LIBS) user32.lib advapi32.lib shell32.lib
-!ENDIF
-
-!IF "$(PLATFORM)" == "arm"
-COMPL_ASM = $(MY_ML) $** $O/$(*B).obj
-!ELSE
-COMPL_ASM = $(MY_ML) -c -Fo$O/ $**
-!ENDIF
-
-CFLAGS = $(CFLAGS) -nologo -c -Fo$O/ -W4 -WX -EHsc -Gy -GR- -GF
-
-!IFDEF MY_DYNAMIC_LINK
-CFLAGS = $(CFLAGS) -MD
-!ELSE
-!IFNDEF MY_SINGLE_THREAD
-CFLAGS = $(CFLAGS) -MT
-!ENDIF
-!ENDIF
-
-!IFNDEF OLD_COMPILER
-CFLAGS = $(CFLAGS) -GS- -Zc:forScope -Zc:wchar_t
-!IFNDEF UNDER_CE
-CFLAGS = $(CFLAGS) -MP2
-!IFNDEF PLATFORM
-# CFLAGS = $(CFLAGS) -arch:IA32
-!ENDIF
-!ENDIF
-!ELSE
-CFLAGS = $(CFLAGS)
-!ENDIF
-
-!IFDEF MY_CONSOLE
-CFLAGS = $(CFLAGS) -D_CONSOLE
-!ENDIF
-
-!IFNDEF UNDER_CE
-!IF "$(PLATFORM)" == "arm"
-CFLAGS = $(CFLAGS) -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE
-!ENDIF
-!ENDIF
-
-!IF "$(PLATFORM)" == "x64"
-CFLAGS_O1 = $(CFLAGS) -O1
-!ELSE
-CFLAGS_O1 = $(CFLAGS) -O1
-!ENDIF
-CFLAGS_O2 = $(CFLAGS) -O2
-
-LFLAGS = $(LFLAGS) -nologo -OPT:REF -OPT:ICF
-
-!IFNDEF UNDER_CE
-LFLAGS = $(LFLAGS) /LARGEADDRESSAWARE
-!ENDIF
-
-!IFDEF DEF_FILE
-LFLAGS = $(LFLAGS) -DLL -DEF:$(DEF_FILE)
-!ELSE
-!IF defined(MY_FIXED) && "$(PLATFORM)" != "arm" && "$(PLATFORM)" != "arm64"
-LFLAGS = $(LFLAGS) /FIXED
-!ELSE
-LFLAGS = $(LFLAGS) /FIXED:NO
-!ENDIF
-# /BASE:0x400000
-!ENDIF
-
-
-# !IF "$(PLATFORM)" == "x64"
-
-!IFDEF SUB_SYS_VER
-
-MY_SUB_SYS_VER=5.02
-
-!IFDEF MY_CONSOLE
-LFLAGS = $(LFLAGS) /SUBSYSTEM:console,$(MY_SUB_SYS_VER)
-!ELSE
-LFLAGS = $(LFLAGS) /SUBSYSTEM:windows,$(MY_SUB_SYS_VER)
-!ENDIF
-
-!ENDIF
-
-
-PROGPATH = $O\$(PROG)
-
-COMPL_O1 = $(CC) $(CFLAGS_O1) $**
-COMPL_O2 = $(CC) $(CFLAGS_O2) $**
-COMPL_PCH = $(CC) $(CFLAGS_O1) -Yc"StdAfx.h" -Fp$O/a.pch $**
-COMPL = $(CC) $(CFLAGS_O1) -Yu"StdAfx.h" -Fp$O/a.pch $**
-
-COMPLB = $(CC) $(CFLAGS_O1) -Yu"StdAfx.h" -Fp$O/a.pch $<
-# COMPLB_O2 = $(CC) $(CFLAGS_O2) -Yu"StdAfx.h" -Fp$O/a.pch $<
-COMPLB_O2 = $(CC) $(CFLAGS_O2) $<
-
-CFLAGS_C_ALL = $(CFLAGS_O2) $(CFLAGS_C_SPEC)
-CCOMPL_PCH = $(CC) $(CFLAGS_C_ALL) -Yc"Precomp.h" -Fp$O/a.pch $**
-CCOMPL_USE = $(CC) $(CFLAGS_C_ALL) -Yu"Precomp.h" -Fp$O/a.pch $**
-CCOMPL = $(CC) $(CFLAGS_C_ALL) $**
-CCOMPLB = $(CC) $(CFLAGS_C_ALL) $<
-
-
-all: $(PROGPATH)
-
-clean:
- -del /Q $(PROGPATH) $O\*.exe $O\*.dll $O\*.obj $O\*.lib $O\*.exp $O\*.res $O\*.pch $O\*.asm
-
-$O:
- if not exist "$O" mkdir "$O"
-$O/asm:
- if not exist "$O/asm" mkdir "$O/asm"
-
-$(PROGPATH): $O $O/asm $(OBJS) $(DEF_FILE)
- link $(LFLAGS) -out:$(PROGPATH) $(OBJS) $(LIBS)
-
-!IFNDEF NO_DEFAULT_RES
-$O\resource.res: $(*B).rc
- rc $(RFLAGS) -fo$@ $**
-!ENDIF
-$O\StdAfx.obj: $(*B).cpp
- $(COMPL_PCH)
+LIBS = $(LIBS) oleaut32.lib ole32.lib
+
+!IFNDEF MY_NO_UNICODE
+CFLAGS = $(CFLAGS) -DUNICODE -D_UNICODE
+!ENDIF
+
+!IF "$(CC)" != "clang-cl"
+# for link time code generation:
+# CFLAGS = $(CFLAGS) -GL
+!ENDIF
+
+!IFNDEF O
+!IFDEF PLATFORM
+O=$(PLATFORM)
+!ELSE
+O=o
+!ENDIF
+!ENDIF
+
+!IF "$(CC)" != "clang-cl"
+# CFLAGS = $(CFLAGS) -FAsc -Fa$O/asm/
+!ENDIF
+
+
+!IF "$(PLATFORM)" == "x64"
+MY_ML = ml64 -WX
+#-Dx64
+!ELSEIF "$(PLATFORM)" == "arm"
+MY_ML = armasm -WX
+!ELSE
+MY_ML = ml -WX
+# -DABI_CDECL
+!ENDIF
+
+# MY_ML = "$(MY_ML) -Fl$O\asm\
+
+
+!IFDEF UNDER_CE
+RFLAGS = $(RFLAGS) -dUNDER_CE
+!IFDEF MY_CONSOLE
+LFLAGS = $(LFLAGS) /ENTRY:mainACRTStartup
+!ENDIF
+!ELSE
+!IFDEF OLD_COMPILER
+LFLAGS = $(LFLAGS) -OPT:NOWIN98
+!ENDIF
+!IF "$(PLATFORM)" != "arm" && "$(PLATFORM)" != "arm64"
+CFLAGS = $(CFLAGS) -Gr
+!ENDIF
+LIBS = $(LIBS) user32.lib advapi32.lib shell32.lib
+!ENDIF
+
+!IF "$(PLATFORM)" == "arm"
+COMPL_ASM = $(MY_ML) $** $O/$(*B).obj
+!ELSE
+COMPL_ASM = $(MY_ML) -c -Fo$O/ $**
+!ENDIF
+
+!IFDEF OLD_COMPILER
+CFLAGS_WARN_LEVEL = -W4
+!ELSE
+CFLAGS_WARN_LEVEL = -Wall
+!ENDIF
+
+CFLAGS = $(CFLAGS) -nologo -c -Fo$O/ $(CFLAGS_WARN_LEVEL) -WX -EHsc -Gy -GR- -GF
+
+!IF "$(CC)" == "clang-cl"
+
+CFLAGS = $(CFLAGS) \
+ -Werror \
+ -Wall \
+ -Wextra \
+ -Weverything \
+ -Wfatal-errors \
+
+!ENDIF
+
+!IFDEF MY_DYNAMIC_LINK
+CFLAGS = $(CFLAGS) -MD
+!ELSE
+!IFNDEF MY_SINGLE_THREAD
+CFLAGS = $(CFLAGS) -MT
+!ENDIF
+!ENDIF
+
+
+CFLAGS = $(CFLAGS_COMMON) $(CFLAGS)
+
+
+!IFNDEF OLD_COMPILER
+
+CFLAGS = $(CFLAGS) -GS- -Zc:wchar_t
+!IFDEF VCTOOLSVERSION
+!IF "$(VCTOOLSVERSION)" >= "14.00"
+!IF "$(CC)" != "clang-cl"
+CFLAGS = $(CFLAGS) -Zc:throwingNew
+!ENDIF
+!ENDIF
+!ELSE
+# -Zc:forScope is default in VS2010. so we need it only for older versions
+CFLAGS = $(CFLAGS) -Zc:forScope
+!ENDIF
+
+!IFNDEF UNDER_CE
+!IF "$(CC)" != "clang-cl"
+CFLAGS = $(CFLAGS) -MP4
+!ENDIF
+!IFNDEF PLATFORM
+# CFLAGS = $(CFLAGS) -arch:IA32
+!ENDIF
+!ENDIF
+
+!ENDIF
+
+
+!IFDEF MY_CONSOLE
+CFLAGS = $(CFLAGS) -D_CONSOLE
+!ENDIF
+
+!IFNDEF UNDER_CE
+!IF "$(PLATFORM)" == "arm"
+CFLAGS = $(CFLAGS) -D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE
+!ENDIF
+!ENDIF
+
+!IF "$(PLATFORM)" == "x64"
+CFLAGS_O1 = $(CFLAGS) -O1
+!ELSE
+CFLAGS_O1 = $(CFLAGS) -O1
+!ENDIF
+CFLAGS_O2 = $(CFLAGS) -O2
+
+LFLAGS = $(LFLAGS) -nologo -OPT:REF -OPT:ICF -INCREMENTAL:NO
+
+!IFNDEF UNDER_CE
+LFLAGS = $(LFLAGS) /LARGEADDRESSAWARE
+!ENDIF
+
+!IFDEF DEF_FILE
+LFLAGS = $(LFLAGS) -DLL -DEF:$(DEF_FILE)
+!ELSE
+!IF defined(MY_FIXED) && "$(PLATFORM)" != "arm" && "$(PLATFORM)" != "arm64"
+LFLAGS = $(LFLAGS) /FIXED
+!ELSE
+LFLAGS = $(LFLAGS) /FIXED:NO
+!ENDIF
+# /BASE:0x400000
+!ENDIF
+
+!IF "$(PLATFORM)" == "arm64"
+# we can get better compression ratio with ARM64 filter if we change alignment to 4096
+# LFLAGS = $(LFLAGS) /FILEALIGN:4096
+!ENDIF
+
+
+
+# !IF "$(PLATFORM)" == "x64"
+
+!IFDEF SUB_SYS_VER
+
+MY_SUB_SYS_VER=5.02
+
+!IFDEF MY_CONSOLE
+LFLAGS = $(LFLAGS) /SUBSYSTEM:console,$(MY_SUB_SYS_VER)
+!ELSE
+LFLAGS = $(LFLAGS) /SUBSYSTEM:windows,$(MY_SUB_SYS_VER)
+!ENDIF
+
+!ENDIF
+
+
+PROGPATH = $O\$(PROG)
+
+COMPL_O1 = $(CC) $(CFLAGS_O1) $**
+COMPL_O2 = $(CC) $(CFLAGS_O2) $**
+COMPL_PCH = $(CC) $(CFLAGS_O1) -Yc"StdAfx.h" -Fp$O/a.pch $**
+COMPL = $(CC) $(CFLAGS_O1) -Yu"StdAfx.h" -Fp$O/a.pch $**
+COMPLB = $(CC) $(CFLAGS_O1) -Yu"StdAfx.h" -Fp$O/a.pch $<
+COMPLB_O2 = $(CC) $(CFLAGS_O2) $<
+# COMPLB_O2 = $(CC) $(CFLAGS_O2) -Yu"StdAfx.h" -Fp$O/a.pch $<
+
+CFLAGS_C_ALL = $(CFLAGS_O2) $(CFLAGS_C_SPEC)
+
+CCOMPL_PCH = $(CC) $(CFLAGS_C_ALL) -Yc"Precomp.h" -Fp$O/a.pch $**
+CCOMPL_USE = $(CC) $(CFLAGS_C_ALL) -Yu"Precomp.h" -Fp$O/a.pch $**
+CCOMPLB_USE = $(CC) $(CFLAGS_C_ALL) -Yu"Precomp.h" -Fp$O/a.pch $<
+CCOMPL = $(CC) $(CFLAGS_C_ALL) $**
+CCOMPLB = $(CC) $(CFLAGS_C_ALL) $<
+
+!IF "$(CC)" == "clang-cl"
+COMPL = $(COMPL) -FI StdAfx.h
+COMPLB = $(COMPLB) -FI StdAfx.h
+CCOMPL_USE = $(CCOMPL_USE) -FI Precomp.h
+CCOMPLB_USE = $(CCOMPLB_USE) -FI Precomp.h
+!ENDIF
+
+all: $(PROGPATH)
+
+clean:
+ -del /Q $(PROGPATH) $O\*.exe $O\*.dll $O\*.obj $O\*.lib $O\*.exp $O\*.res $O\*.pch $O\*.asm
+
+$O:
+ if not exist "$O" mkdir "$O"
+$O/asm:
+ if not exist "$O/asm" mkdir "$O/asm"
+
+!IF "$(CC)" != "clang-cl"
+# for link time code generation:
+# LFLAGS = $(LFLAGS) -LTCG
+!ENDIF
+
+$(PROGPATH): $O $O/asm $(OBJS) $(DEF_FILE)
+ link $(LFLAGS) -out:$(PROGPATH) $(OBJS) $(LIBS)
+
+!IFNDEF NO_DEFAULT_RES
+$O\resource.res: $(*B).rc
+ rc $(RFLAGS) -fo$@ $**
+!ENDIF
+$O\StdAfx.obj: $(*B).cpp
+ $(COMPL_PCH)
+
+predef: empty.c
+ $(CCOMPL) /EP /Zc:preprocessor /PD
+predef2: A.cpp
+ $(COMPL) -EP -Zc:preprocessor -PD
+predef3: A.cpp
+ $(COMPL) -E -dM
+predef4: A.cpp
+ $(COMPL_O2) -E
diff --git a/CPP/Common/AutoPtr.h b/CPP/Common/AutoPtr.h
index e53fb7f..0be8a7a 100644
--- a/CPP/Common/AutoPtr.h
+++ b/CPP/Common/AutoPtr.h
@@ -1,35 +1,35 @@
-// Common/AutoPtr.h
-
-#ifndef __COMMON_AUTOPTR_H
-#define __COMMON_AUTOPTR_H
-
-template<class T> class CMyAutoPtr
-{
- T *_p;
-public:
- CMyAutoPtr(T *p = 0) : _p(p) {}
- CMyAutoPtr(CMyAutoPtr<T>& p): _p(p.release()) {}
- CMyAutoPtr<T>& operator=(CMyAutoPtr<T>& p)
- {
- reset(p.release());
- return (*this);
- }
- ~CMyAutoPtr() { delete _p; }
- T& operator*() const { return *_p; }
- // T* operator->() const { return (&**this); }
- T* get() const { return _p; }
- T* release()
- {
- T *tmp = _p;
- _p = 0;
- return tmp;
- }
- void reset(T* p = 0)
- {
- if (p != _p)
- delete _p;
- _p = p;
- }
-};
-
-#endif
+// Common/AutoPtr.h
+
+#ifndef ZIP7_INC_COMMON_AUTOPTR_H
+#define ZIP7_INC_COMMON_AUTOPTR_H
+
+template<class T> class CMyAutoPtr
+{
+ T *_p;
+public:
+ CMyAutoPtr(T *p = NULL) : _p(p) {}
+ CMyAutoPtr(CMyAutoPtr<T>& p): _p(p.release()) {}
+ CMyAutoPtr<T>& operator=(CMyAutoPtr<T>& p)
+ {
+ reset(p.release());
+ return (*this);
+ }
+ ~CMyAutoPtr() { delete _p; }
+ T& operator*() const { return *_p; }
+ // T* operator->() const { return (&**this); }
+ T* get() const { return _p; }
+ T* release()
+ {
+ T *tmp = _p;
+ _p = NULL;
+ return tmp;
+ }
+ void reset(T* p = NULL)
+ {
+ if (p != _p)
+ delete _p;
+ _p = p;
+ }
+};
+
+#endif
diff --git a/CPP/Common/CRC.cpp b/CPP/Common/CRC.cpp
index 6ac52c4..c6b7d5e 100644
--- a/CPP/Common/CRC.cpp
+++ b/CPP/Common/CRC.cpp
@@ -1,7 +1,7 @@
-// Common/CRC.cpp
-
-#include "StdAfx.h"
-
-#include "../../C/7zCrc.h"
-
-struct CCRCTableInit { CCRCTableInit() { CrcGenerateTable(); } } g_CRCTableInit;
+// Common/CRC.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/7zCrc.h"
+
+static struct CCRCTableInit { CCRCTableInit() { CrcGenerateTable(); } } g_CRCTableInit;
diff --git a/CPP/Common/C_FileIO.cpp b/CPP/Common/C_FileIO.cpp
index d68a427..4bd3fad 100644
--- a/CPP/Common/C_FileIO.cpp
+++ b/CPP/Common/C_FileIO.cpp
@@ -1,92 +1,3 @@
-// Common/C_FileIO.cpp
-
-#include "C_FileIO.h"
-
-#include <fcntl.h>
-#ifdef _WIN32
-#include <io.h>
-#else
-#include <unistd.h>
-#endif
-
-namespace NC {
-namespace NFile {
-namespace NIO {
-
-bool CFileBase::OpenBinary(const char *name, int flags)
-{
- #ifdef O_BINARY
- flags |= O_BINARY;
- #endif
- Close();
- _handle = ::open(name, flags, 0666);
- return _handle != -1;
-}
-
-bool CFileBase::Close()
-{
- if (_handle == -1)
- return true;
- if (close(_handle) != 0)
- return false;
- _handle = -1;
- return true;
-}
-
-bool CFileBase::GetLength(UInt64 &length) const
-{
- off_t curPos = Seek(0, SEEK_CUR);
- off_t lengthTemp = Seek(0, SEEK_END);
- Seek(curPos, SEEK_SET);
- length = (UInt64)lengthTemp;
- return true;
-}
-
-off_t CFileBase::Seek(off_t distanceToMove, int moveMethod) const
-{
- return ::lseek(_handle, distanceToMove, moveMethod);
-}
-
-/////////////////////////
-// CInFile
-
-bool CInFile::Open(const char *name)
-{
- return CFileBase::OpenBinary(name, O_RDONLY);
-}
-
-bool CInFile::OpenShared(const char *name, bool)
-{
- return Open(name);
-}
-
-ssize_t CInFile::Read(void *data, size_t size)
-{
- return read(_handle, data, size);
-}
-
-/////////////////////////
-// COutFile
-
-bool COutFile::Create(const char *name, bool createAlways)
-{
- if (createAlways)
- {
- Close();
- _handle = ::creat(name, 0666);
- return _handle != -1;
- }
- return OpenBinary(name, O_CREAT | O_EXCL | O_WRONLY);
-}
-
-bool COutFile::Open(const char *name, DWORD creationDisposition)
-{
- return Create(name, false);
-}
-
-ssize_t COutFile::Write(const void *data, size_t size)
-{
- return write(_handle, data, size);
-}
-
-}}}
+// Common/C_FileIO.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/Common/C_FileIO.h b/CPP/Common/C_FileIO.h
index 4c400b4..12d9439 100644
--- a/CPP/Common/C_FileIO.h
+++ b/CPP/Common/C_FileIO.h
@@ -1,53 +1,6 @@
-// Common/C_FileIO.h
-
-#ifndef __COMMON_C_FILEIO_H
-#define __COMMON_C_FILEIO_H
-
-#include <stdio.h>
-#include <sys/types.h>
-
-#include "MyTypes.h"
-#include "MyWindows.h"
-
-#ifdef _WIN32
-#ifdef _MSC_VER
-typedef size_t ssize_t;
-#endif
-#endif
-
-namespace NC {
-namespace NFile {
-namespace NIO {
-
-class CFileBase
-{
-protected:
- int _handle;
- bool OpenBinary(const char *name, int flags);
-public:
- CFileBase(): _handle(-1) {};
- ~CFileBase() { Close(); }
- bool Close();
- bool GetLength(UInt64 &length) const;
- off_t Seek(off_t distanceToMove, int moveMethod) const;
-};
-
-class CInFile: public CFileBase
-{
-public:
- bool Open(const char *name);
- bool OpenShared(const char *name, bool shareForWrite);
- ssize_t Read(void *data, size_t size);
-};
-
-class COutFile: public CFileBase
-{
-public:
- bool Create(const char *name, bool createAlways);
- bool Open(const char *name, DWORD creationDisposition);
- ssize_t Write(const void *data, size_t size);
-};
-
-}}}
-
-#endif
+// Common/C_FileIO.h
+
+#ifndef ZIP7_INC_COMMON_C_FILEIO_H
+#define ZIP7_INC_COMMON_C_FILEIO_H
+
+#endif
diff --git a/CPP/Common/CksumReg.cpp b/CPP/Common/CksumReg.cpp
new file mode 100644
index 0000000..8c9c449
--- /dev/null
+++ b/CPP/Common/CksumReg.cpp
@@ -0,0 +1,55 @@
+// CksumReg.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/CpuArch.h"
+
+#include "../Common/MyCom.h"
+
+#include "../7zip/Common/RegisterCodec.h"
+#include "../7zip/Compress/BZip2Crc.h"
+
+Z7_CLASS_IMP_COM_1(
+ CCksumHasher
+ , IHasher
+)
+ CBZip2Crc _crc;
+ UInt64 _size;
+public:
+ // Byte _mtDummy[1 << 7];
+ CCksumHasher()
+ {
+ _crc.Init(0);
+ _size = 0;
+ }
+};
+
+Z7_COM7F_IMF2(void, CCksumHasher::Init())
+{
+ _crc.Init(0);
+ _size = 0;
+}
+
+Z7_COM7F_IMF2(void, CCksumHasher::Update(const void *data, UInt32 size))
+{
+ _size += size;
+ CBZip2Crc crc = _crc;
+ for (UInt32 i = 0; i < size; i++)
+ crc.UpdateByte(((const Byte *)data)[i]);
+ _crc = crc;
+}
+
+Z7_COM7F_IMF2(void, CCksumHasher::Final(Byte *digest))
+{
+ UInt64 size = _size;
+ CBZip2Crc crc = _crc;
+ while (size)
+ {
+ crc.UpdateByte((Byte)size);
+ size >>= 8;
+ }
+ const UInt32 val = crc.GetDigest();
+ SetUi32(digest, val)
+}
+
+REGISTER_HASHER(CCksumHasher, 0x203, "CKSUM", 4)
diff --git a/CPP/Common/ComTry.h b/CPP/Common/ComTry.h
index e6b514d..84746a7 100644
--- a/CPP/Common/ComTry.h
+++ b/CPP/Common/ComTry.h
@@ -1,21 +1,21 @@
-// ComTry.h
-
-#ifndef __COM_TRY_H
-#define __COM_TRY_H
-
-#include "MyWindows.h"
-// #include "Exception.h"
-// #include "NewHandler.h"
-
-#define COM_TRY_BEGIN try {
-#define COM_TRY_END } catch(...) { return E_OUTOFMEMORY; }
-
-/*
-#define COM_TRY_END } \
- catch(const CNewException &) { return E_OUTOFMEMORY; } \
- catch(...) { return HRESULT_FROM_WIN32(ERROR_NOACCESS); } \
-*/
- // catch(const CSystemException &e) { return e.ErrorCode; }
- // catch(...) { return E_FAIL; }
-
-#endif
+// ComTry.h
+
+#ifndef ZIP7_INC_COM_TRY_H
+#define ZIP7_INC_COM_TRY_H
+
+#include "MyWindows.h"
+// #include "Exception.h"
+// #include "NewHandler.h"
+
+#define COM_TRY_BEGIN try {
+#define COM_TRY_END } catch(...) { return E_OUTOFMEMORY; }
+
+/*
+#define COM_TRY_END } \
+ catch(const CNewException &) { return E_OUTOFMEMORY; } \
+ catch(...) { return HRESULT_FROM_WIN32(ERROR_NOACCESS); } \
+*/
+ // catch(const CSystemException &e) { return e.ErrorCode; }
+ // catch(...) { return E_FAIL; }
+
+#endif
diff --git a/CPP/Common/CommandLineParser.cpp b/CPP/Common/CommandLineParser.cpp
index 94aabce..465e0fd 100644
--- a/CPP/Common/CommandLineParser.cpp
+++ b/CPP/Common/CommandLineParser.cpp
@@ -1,197 +1,197 @@
-// CommandLineParser.cpp
-
-#include "StdAfx.h"
-
-#include "CommandLineParser.h"
-
-namespace NCommandLineParser {
-
-bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2)
-{
- dest1.Empty();
- dest2.Empty();
- bool quoteMode = false;
- unsigned i;
- for (i = 0; i < src.Len(); i++)
- {
- wchar_t c = src[i];
- if ((c == L' ' || c == L'\t') && !quoteMode)
- {
- dest2 = src.Ptr(i + 1);
- return i != 0;
- }
- if (c == L'\"')
- quoteMode = !quoteMode;
- else
- dest1 += c;
- }
- return i != 0;
-}
-
-void SplitCommandLine(const UString &s, UStringVector &parts)
-{
- UString sTemp (s);
- sTemp.Trim();
- parts.Clear();
- for (;;)
- {
- UString s1, s2;
- if (SplitCommandLine(sTemp, s1, s2))
- parts.Add(s1);
- if (s2.IsEmpty())
- break;
- sTemp = s2;
- }
-}
-
-
-static const char * const kStopSwitchParsing = "--";
-
-static bool inline IsItSwitchChar(wchar_t c)
-{
- return (c == '-');
-}
-
-CParser::CParser():
- _switches(NULL),
- StopSwitchIndex(-1)
-{
-}
-
-CParser::~CParser()
-{
- delete []_switches;
-}
-
-
-// if (s) contains switch then function updates switch structures
-// out: true, if (s) is a switch
-bool CParser::ParseString(const UString &s, const CSwitchForm *switchForms, unsigned numSwitches)
-{
- if (s.IsEmpty() || !IsItSwitchChar(s[0]))
- return false;
-
- unsigned pos = 1;
- unsigned switchIndex = 0;
- int maxLen = -1;
-
- for (unsigned i = 0; i < numSwitches; i++)
- {
- const char * const key = switchForms[i].Key;
- unsigned switchLen = MyStringLen(key);
- if ((int)switchLen <= maxLen || pos + switchLen > s.Len())
- continue;
- if (IsString1PrefixedByString2_NoCase_Ascii((const wchar_t *)s + pos, key))
- {
- switchIndex = i;
- maxLen = switchLen;
- }
- }
-
- if (maxLen < 0)
- {
- ErrorMessage = "Unknown switch:";
- return false;
- }
-
- pos += maxLen;
-
- CSwitchResult &sw = _switches[switchIndex];
- const CSwitchForm &form = switchForms[switchIndex];
-
- if (!form.Multi && sw.ThereIs)
- {
- ErrorMessage = "Multiple instances for switch:";
- return false;
- }
-
- sw.ThereIs = true;
-
- int rem = s.Len() - pos;
- if (rem < form.MinLen)
- {
- ErrorMessage = "Too short switch:";
- return false;
- }
-
- sw.WithMinus = false;
- sw.PostCharIndex = -1;
-
- switch (form.Type)
- {
- case NSwitchType::kMinus:
- if (rem == 1)
- {
- sw.WithMinus = (s[pos] == '-');
- if (sw.WithMinus)
- return true;
- ErrorMessage = "Incorrect switch postfix:";
- return false;
- }
- break;
-
- case NSwitchType::kChar:
- if (rem == 1)
- {
- wchar_t c = s[pos];
- if (c <= 0x7F)
- {
- sw.PostCharIndex = FindCharPosInString(form.PostCharSet, (char)c);
- if (sw.PostCharIndex >= 0)
- return true;
- }
- ErrorMessage = "Incorrect switch postfix:";
- return false;
- }
- break;
-
- case NSwitchType::kString:
- {
- sw.PostStrings.Add(s.Ptr(pos));
- return true;
- }
- }
-
- if (pos != s.Len())
- {
- ErrorMessage = "Too long switch:";
- return false;
- }
- return true;
-}
-
-
-bool CParser::ParseStrings(const CSwitchForm *switchForms, unsigned numSwitches, const UStringVector &commandStrings)
-{
- StopSwitchIndex = -1;
- ErrorMessage.Empty();
- ErrorLine.Empty();
- NonSwitchStrings.Clear();
- delete []_switches;
- _switches = NULL;
- _switches = new CSwitchResult[numSwitches];
-
- FOR_VECTOR (i, commandStrings)
- {
- const UString &s = commandStrings[i];
- if (StopSwitchIndex < 0)
- {
- if (s.IsEqualTo(kStopSwitchParsing))
- {
- StopSwitchIndex = NonSwitchStrings.Size();
- continue;
- }
- if (!s.IsEmpty() && IsItSwitchChar(s[0]))
- {
- if (ParseString(s, switchForms, numSwitches))
- continue;
- ErrorLine = s;
- return false;
- }
- }
- NonSwitchStrings.Add(s);
- }
- return true;
-}
-
-}
+// CommandLineParser.cpp
+
+#include "StdAfx.h"
+
+#include "CommandLineParser.h"
+
+namespace NCommandLineParser {
+
+bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2)
+{
+ dest1.Empty();
+ dest2.Empty();
+ bool quoteMode = false;
+ unsigned i;
+ for (i = 0; i < src.Len(); i++)
+ {
+ wchar_t c = src[i];
+ if ((c == L' ' || c == L'\t') && !quoteMode)
+ {
+ dest2 = src.Ptr(i + 1);
+ return i != 0;
+ }
+ if (c == L'\"')
+ quoteMode = !quoteMode;
+ else
+ dest1 += c;
+ }
+ return i != 0;
+}
+
+void SplitCommandLine(const UString &s, UStringVector &parts)
+{
+ UString sTemp (s);
+ sTemp.Trim();
+ parts.Clear();
+ for (;;)
+ {
+ UString s1, s2;
+ if (SplitCommandLine(sTemp, s1, s2))
+ parts.Add(s1);
+ if (s2.IsEmpty())
+ break;
+ sTemp = s2;
+ }
+}
+
+
+static const char * const kStopSwitchParsing = "--";
+
+static bool inline IsItSwitchChar(wchar_t c)
+{
+ return (c == '-');
+}
+
+CParser::CParser():
+ _switches(NULL),
+ StopSwitchIndex(-1)
+{
+}
+
+CParser::~CParser()
+{
+ delete []_switches;
+}
+
+
+// if (s) contains switch then function updates switch structures
+// out: true, if (s) is a switch
+bool CParser::ParseString(const UString &s, const CSwitchForm *switchForms, unsigned numSwitches)
+{
+ if (s.IsEmpty() || !IsItSwitchChar(s[0]))
+ return false;
+
+ unsigned pos = 1;
+ unsigned switchIndex = 0;
+ int maxLen = -1;
+
+ for (unsigned i = 0; i < numSwitches; i++)
+ {
+ const char * const key = switchForms[i].Key;
+ unsigned switchLen = MyStringLen(key);
+ if ((int)switchLen <= maxLen || pos + switchLen > s.Len())
+ continue;
+ if (IsString1PrefixedByString2_NoCase_Ascii((const wchar_t *)s + pos, key))
+ {
+ switchIndex = i;
+ maxLen = (int)switchLen;
+ }
+ }
+
+ if (maxLen < 0)
+ {
+ ErrorMessage = "Unknown switch:";
+ return false;
+ }
+
+ pos += (unsigned)maxLen;
+
+ CSwitchResult &sw = _switches[switchIndex];
+ const CSwitchForm &form = switchForms[switchIndex];
+
+ if (!form.Multi && sw.ThereIs)
+ {
+ ErrorMessage = "Multiple instances for switch:";
+ return false;
+ }
+
+ sw.ThereIs = true;
+
+ const unsigned rem = s.Len() - pos;
+ if (rem < form.MinLen)
+ {
+ ErrorMessage = "Too short switch:";
+ return false;
+ }
+
+ sw.WithMinus = false;
+ sw.PostCharIndex = -1;
+
+ switch (form.Type)
+ {
+ case NSwitchType::kMinus:
+ if (rem == 1)
+ {
+ sw.WithMinus = (s[pos] == '-');
+ if (sw.WithMinus)
+ return true;
+ ErrorMessage = "Incorrect switch postfix:";
+ return false;
+ }
+ break;
+
+ case NSwitchType::kChar:
+ if (rem == 1)
+ {
+ wchar_t c = s[pos];
+ if (c <= 0x7F)
+ {
+ sw.PostCharIndex = FindCharPosInString(form.PostCharSet, (char)c);
+ if (sw.PostCharIndex >= 0)
+ return true;
+ }
+ ErrorMessage = "Incorrect switch postfix:";
+ return false;
+ }
+ break;
+
+ case NSwitchType::kString:
+ {
+ sw.PostStrings.Add(s.Ptr(pos));
+ return true;
+ }
+ }
+
+ if (pos != s.Len())
+ {
+ ErrorMessage = "Too long switch:";
+ return false;
+ }
+ return true;
+}
+
+
+bool CParser::ParseStrings(const CSwitchForm *switchForms, unsigned numSwitches, const UStringVector &commandStrings)
+{
+ StopSwitchIndex = -1;
+ ErrorMessage.Empty();
+ ErrorLine.Empty();
+ NonSwitchStrings.Clear();
+ delete []_switches;
+ _switches = NULL;
+ _switches = new CSwitchResult[numSwitches];
+
+ FOR_VECTOR (i, commandStrings)
+ {
+ const UString &s = commandStrings[i];
+ if (StopSwitchIndex < 0)
+ {
+ if (s.IsEqualTo(kStopSwitchParsing))
+ {
+ StopSwitchIndex = (int)NonSwitchStrings.Size();
+ continue;
+ }
+ if (!s.IsEmpty() && IsItSwitchChar(s[0]))
+ {
+ if (ParseString(s, switchForms, numSwitches))
+ continue;
+ ErrorLine = s;
+ return false;
+ }
+ }
+ NonSwitchStrings.Add(s);
+ }
+ return true;
+}
+
+}
diff --git a/CPP/Common/CommandLineParser.h b/CPP/Common/CommandLineParser.h
index ec6336c..fc6f028 100644
--- a/CPP/Common/CommandLineParser.h
+++ b/CPP/Common/CommandLineParser.h
@@ -1,63 +1,63 @@
-// Common/CommandLineParser.h
-
-#ifndef __COMMON_COMMAND_LINE_PARSER_H
-#define __COMMON_COMMAND_LINE_PARSER_H
-
-#include "MyString.h"
-
-namespace NCommandLineParser {
-
-bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2);
-void SplitCommandLine(const UString &s, UStringVector &parts);
-
-namespace NSwitchType
-{
- enum EEnum
- {
- kSimple,
- kMinus,
- kString,
- kChar
- };
-}
-
-struct CSwitchForm
-{
- const char *Key;
- Byte Type;
- bool Multi;
- Byte MinLen;
- // int MaxLen;
- const char *PostCharSet;
-};
-
-struct CSwitchResult
-{
- bool ThereIs;
- bool WithMinus;
- int PostCharIndex;
- UStringVector PostStrings;
-
- CSwitchResult(): ThereIs(false) {};
-};
-
-class CParser
-{
- CSwitchResult *_switches;
-
- bool ParseString(const UString &s, const CSwitchForm *switchForms, unsigned numSwitches);
-public:
- UStringVector NonSwitchStrings;
- int StopSwitchIndex; // NonSwitchStrings[StopSwitchIndex+] are after "--"
- AString ErrorMessage;
- UString ErrorLine;
-
- CParser();
- ~CParser();
- bool ParseStrings(const CSwitchForm *switchForms, unsigned numSwitches, const UStringVector &commandStrings);
- const CSwitchResult& operator[](unsigned index) const { return _switches[index]; }
-};
-
-}
-
-#endif
+// Common/CommandLineParser.h
+
+#ifndef ZIP7_INC_COMMON_COMMAND_LINE_PARSER_H
+#define ZIP7_INC_COMMON_COMMAND_LINE_PARSER_H
+
+#include "MyString.h"
+
+namespace NCommandLineParser {
+
+bool SplitCommandLine(const UString &src, UString &dest1, UString &dest2);
+void SplitCommandLine(const UString &s, UStringVector &parts);
+
+namespace NSwitchType
+{
+ enum EEnum
+ {
+ kSimple,
+ kMinus,
+ kString,
+ kChar
+ };
+}
+
+struct CSwitchForm
+{
+ const char *Key;
+ Byte Type;
+ bool Multi;
+ Byte MinLen;
+ // int MaxLen;
+ const char *PostCharSet;
+};
+
+struct CSwitchResult
+{
+ bool ThereIs;
+ bool WithMinus;
+ int PostCharIndex;
+ UStringVector PostStrings;
+
+ CSwitchResult(): ThereIs(false) {}
+};
+
+class CParser
+{
+ CSwitchResult *_switches;
+
+ bool ParseString(const UString &s, const CSwitchForm *switchForms, unsigned numSwitches);
+public:
+ UStringVector NonSwitchStrings;
+ int StopSwitchIndex; // NonSwitchStrings[StopSwitchIndex+] are after "--"
+ AString ErrorMessage;
+ UString ErrorLine;
+
+ CParser();
+ ~CParser();
+ bool ParseStrings(const CSwitchForm *switchForms, unsigned numSwitches, const UStringVector &commandStrings);
+ const CSwitchResult& operator[](unsigned index) const { return _switches[index]; }
+};
+
+}
+
+#endif
diff --git a/CPP/Common/Common.h b/CPP/Common/Common.h
index c1ecc7e..0c77ab4 100644
--- a/CPP/Common/Common.h
+++ b/CPP/Common/Common.h
@@ -1,43 +1,313 @@
-// Common.h
-
-#ifndef __COMMON_COMMON_H
-#define __COMMON_COMMON_H
-
-/*
-This file is included to all cpp files in 7-Zip.
-Each folder contains StdAfx.h file that includes "Common.h".
-So 7-Zip includes "Common.h" in both modes:
- with precompiled StdAfx.h
-and
- without precompiled StdAfx.h
-
-If you use 7-Zip code, you must include "Common.h" before other h files of 7-zip.
-If you don't need some things that are used in 7-Zip,
-you can change this h file or h files included in this file.
-*/
-
-// compiler pragmas to disable some warnings
-#include "../../C/Compiler.h"
-
-// it's <windows.h> or code that defines windows things, if it's not _WIN32
-#include "MyWindows.h"
-
-// NewHandler.h and NewHandler.cpp redefine operator new() to throw exceptions, if compiled with old MSVC compilers
-#include "NewHandler.h"
-
-
-
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-
-
-/* There is BUG in MSVC 6.0 compiler for operator new[]:
- It doesn't check overflow, when it calculates size in bytes for allocated array.
- So we can use MY_ARRAY_NEW macro instead of new[] operator. */
-
-#if defined(_MSC_VER) && (_MSC_VER == 1200) && !defined(_WIN64)
- #define MY_ARRAY_NEW(p, T, size) p = new T[(size > (unsigned)0xFFFFFFFF / sizeof(T)) ? (unsigned)0xFFFFFFFF / sizeof(T) : size];
-#else
- #define MY_ARRAY_NEW(p, T, size) p = new T[size];
-#endif
-
-#endif
+// Common.h
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+
+#ifndef ZIP7_INC_COMMON_H
+#define ZIP7_INC_COMMON_H
+
+#include "../../C/Compiler.h"
+
+/*
+This file is included to all cpp files in 7-Zip.
+Each folder contains StdAfx.h file that includes "Common.h".
+So 7-Zip includes "Common.h" in both modes:
+ with precompiled StdAfx.h
+and
+ without precompiled StdAfx.h
+
+If you use 7-Zip code, you must include "Common.h" before other h files of 7-zip.
+If you don't need some things that are used in 7-Zip,
+you can change this h file or h files included in this file.
+*/
+
+#ifdef _MSC_VER
+ #pragma warning(disable : 4710) // function not inlined
+ // 'CUncopyable::CUncopyable':
+ #pragma warning(disable : 4514) // unreferenced inline function has been removed
+ #if _MSC_VER < 1300
+ #pragma warning(disable : 4702) // unreachable code
+ #pragma warning(disable : 4714) // function marked as __forceinline not inlined
+ #pragma warning(disable : 4786) // identifier was truncated to '255' characters in the debug information
+ #endif
+ #if _MSC_VER < 1400
+ #pragma warning(disable : 4511) // copy constructor could not be generated // #pragma warning(disable : 4512) // assignment operator could not be generated
+ #pragma warning(disable : 4512) // assignment operator could not be generated
+ #endif
+ #if _MSC_VER > 1400 && _MSC_VER <= 1900
+ // #pragma warning(disable : 4996)
+ // strcat: This function or variable may be unsafe
+ // GetVersion was declared deprecated
+ #endif
+
+#if _MSC_VER > 1200
+// -Wall warnings
+
+#if _MSC_VER <= 1600
+#pragma warning(disable : 4917) // 'OLE_HANDLE' : a GUID can only be associated with a class, interface or namespace
+#endif
+
+// #pragma warning(disable : 4061) // enumerator '' in switch of enum '' is not explicitly handled by a case label
+// #pragma warning(disable : 4266) // no override available for virtual member function from base ''; function is hidden
+#pragma warning(disable : 4625) // copy constructor was implicitly defined as deleted
+#pragma warning(disable : 4626) // assignment operator was implicitly defined as deleted
+#if _MSC_VER >= 1600 && _MSC_VER < 1920
+#pragma warning(disable : 4571) // Informational: catch(...) semantics changed since Visual C++ 7.1; structured exceptions (SEH) are no longer caught
+#endif
+#if _MSC_VER >= 1600
+#pragma warning(disable : 4365) // 'initializing' : conversion from 'int' to 'unsigned int', signed / unsigned mismatch
+#endif
+#if _MSC_VER < 1800
+// we disable the warning, if we don't use 'final' in class
+#pragma warning(disable : 4265) // class has virtual functions, but destructor is not virtual
+#endif
+
+#if _MSC_VER >= 1900
+#pragma warning(disable : 5026) // move constructor was implicitly defined as deleted
+#pragma warning(disable : 5027) // move assignment operator was implicitly defined as deleted
+#endif
+#if _MSC_VER >= 1912
+#pragma warning(disable : 5039) // pointer or reference to potentially throwing function passed to 'extern "C"' function under - EHc.Undefined behavior may occur if this function throws an exception.
+#endif
+#if _MSC_VER >= 1925
+// #pragma warning(disable : 5204) // 'ISequentialInStream' : class has virtual functions, but its trivial destructor is not virtual; instances of objects derived from this class may not be destructed correctly
+#endif
+#if _MSC_VER >= 1934
+// #pragma warning(disable : 5264) // const variable is not used
+#endif
+
+#endif // _MSC_VER > 1200
+#endif // _MSC_VER
+
+
+#if defined(_MSC_VER) // && !defined(__clang__)
+#define Z7_DECLSPEC_NOTHROW __declspec(nothrow)
+#elif defined(__clang__) || defined(__GNUC__)
+#define Z7_DECLSPEC_NOTHROW __attribute__((nothrow))
+#else
+#define Z7_DECLSPEC_NOTHROW
+#endif
+
+/*
+#if defined (_MSC_VER) && _MSC_VER >= 1900 \
+ || defined(__clang__) && __clang_major__ >= 6 \
+ || defined(__GNUC__) && __GNUC__ >= 6
+ #define Z7_noexcept noexcept
+#else
+ #define Z7_noexcept throw()
+#endif
+*/
+
+
+#if defined(__clang__)
+
+// noexcept, final, = delete
+#pragma GCC diagnostic ignored "-Wc++98-compat"
+#if __clang_major__ >= 4
+// throw() dynamic exception specifications are deprecated
+#pragma GCC diagnostic ignored "-Wdeprecated-dynamic-exception-spec"
+#endif
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#pragma GCC diagnostic ignored "-Wglobal-constructors"
+#pragma GCC diagnostic ignored "-Wexit-time-destructors"
+
+// #pragma GCC diagnostic ignored "-Wunused-private-field"
+// #pragma GCC diagnostic ignored "-Wnonportable-system-include-path"
+// #pragma GCC diagnostic ignored "-Wsuggest-override"
+// #pragma GCC diagnostic ignored "-Wsign-conversion"
+// #pragma GCC diagnostic ignored "-Winconsistent-missing-override"
+// #pragma GCC diagnostic ignored "-Wsuggest-destructor-override"
+// #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+// #pragma GCC diagnostic ignored "-Wdeprecated-copy-with-user-provided-dtor"
+// #pragma GCC diagnostic ignored "-Wdeprecated-copy-dtor"
+// #ifndef _WIN32
+// #pragma GCC diagnostic ignored "-Wweak-vtables"
+// #endif
+/*
+#if defined(Z7_GCC_VERSION) && (Z7_GCC_VERSION >= 40400) \
+ || defined(Z7_CLANG_VERSION) && (Z7_CLANG_VERSION >= 30000)
+// enumeration values not explicitly handled in switch
+#pragma GCC diagnostic ignored "-Wswitch-enum"
+#endif
+*/
+#endif // __clang__
+
+
+#ifdef __GNUC__
+// #pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
+#endif
+
+
+/* There is BUG in MSVC 6.0 compiler for operator new[]:
+ It doesn't check overflow, when it calculates size in bytes for allocated array.
+ So we can use Z7_ARRAY_NEW macro instead of new[] operator. */
+
+#if defined(_MSC_VER) && (_MSC_VER == 1200) && !defined(_WIN64)
+ #define Z7_ARRAY_NEW(p, T, size) p = new T[((size) > (unsigned)0xFFFFFFFF / sizeof(T)) ? (unsigned)0xFFFFFFFF / sizeof(T) : (size)];
+#else
+ #define Z7_ARRAY_NEW(p, T, size) p = new T[size];
+#endif
+
+#if (defined(__GNUC__) && (__GNUC__ >= 8))
+ #define Z7_ATTR_NORETURN __attribute__((noreturn))
+#elif (defined(__clang__) && (__clang_major__ >= 3))
+ #if __has_feature(cxx_attributes)
+ #define Z7_ATTR_NORETURN [[noreturn]]
+ #else
+ #define Z7_ATTR_NORETURN __attribute__((noreturn))
+ #endif
+#elif (defined(_MSC_VER) && (_MSC_VER >= 1900))
+ #define Z7_ATTR_NORETURN [[noreturn]]
+#else
+ #define Z7_ATTR_NORETURN
+#endif
+
+
+// final in "GCC 4.7.0"
+// In C++98 and C++03 code the alternative spelling __final can be used instead (this is a GCC extension.)
+
+#if defined (__cplusplus) && __cplusplus >= 201103L \
+ || defined(_MSC_VER) && _MSC_VER >= 1800 \
+ || defined(__clang__) && __clang_major__ >= 4 \
+ /* || defined(__GNUC__) && __GNUC__ >= 9 */
+ #define Z7_final final
+ #if defined(__clang__) && __cplusplus < 201103L
+ #pragma GCC diagnostic ignored "-Wc++11-extensions"
+ #endif
+#elif defined (__cplusplus) && __cplusplus >= 199711L \
+ && defined(__GNUC__) && __GNUC__ >= 4 && !defined(__clang__)
+ #define Z7_final __final
+#else
+ #define Z7_final
+ #if defined(__clang__) && __clang_major__ >= 4 \
+ || defined(__GNUC__) && __GNUC__ >= 4
+ #pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
+ #pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
+ #endif
+#endif
+
+#define Z7_class_final(c) class c Z7_final
+
+
+#if defined (__cplusplus) && __cplusplus >= 201103L \
+ || (defined(_MSC_VER) && _MSC_VER >= 1800)
+ #define Z7_CPP_IS_SUPPORTED_default
+ #define Z7_eq_delete = delete
+ // #define Z7_DECL_DEFAULT_COPY_CONSTRUCTOR_IF_SUPPORTED(c) c(const c& k) = default;
+#else
+ #define Z7_eq_delete
+ // #define Z7_DECL_DEFAULT_COPY_CONSTRUCTOR_IF_SUPPORTED(c)
+#endif
+
+
+#if defined(__cplusplus) && (__cplusplus >= 201103L) \
+ || defined(_MSC_VER) && (_MSC_VER >= 1400) /* && (_MSC_VER != 1600) */ \
+ || defined(__clang__) && __clang_major__ >= 4
+ #if defined(_MSC_VER) && (_MSC_VER == 1600) /* && (_MSC_VER != 1600) */
+ #pragma warning(disable : 4481) // nonstandard extension used: override specifier 'override'
+ #define Z7_DESTRUCTOR_override
+ #else
+ #define Z7_DESTRUCTOR_override override
+ #endif
+ #define Z7_override override
+#else
+ #define Z7_override
+ #define Z7_DESTRUCTOR_override
+#endif
+
+
+
+#define Z7_CLASS_NO_COPY(cls) \
+ private: \
+ cls(const cls &) Z7_eq_delete; \
+ cls &operator=(const cls &) Z7_eq_delete;
+
+class CUncopyable
+{
+protected:
+ CUncopyable() {} // allow constructor
+ // ~CUncopyable() {}
+ Z7_CLASS_NO_COPY(CUncopyable)
+};
+
+#define MY_UNCOPYABLE :private CUncopyable
+// #define MY_UNCOPYABLE
+
+
+typedef void (*Z7_void_Function)(void);
+
+#if defined(__clang__) || defined(__GNUC__)
+#define Z7_CAST_FUNC(t, e) reinterpret_cast<t>(reinterpret_cast<Z7_void_Function>(e))
+#else
+#define Z7_CAST_FUNC(t, e) reinterpret_cast<t>(reinterpret_cast<void*>(e))
+// #define Z7_CAST_FUNC(t, e) reinterpret_cast<t>(e)
+#endif
+
+#define Z7_GET_PROC_ADDRESS(func_type, hmodule, func_name) \
+ Z7_CAST_FUNC(func_type, GetProcAddress(hmodule, func_name))
+
+// || defined(__clang__)
+// || defined(__GNUC__)
+
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define Z7_DECLSPEC_NOVTABLE __declspec(novtable)
+#else
+#define Z7_DECLSPEC_NOVTABLE
+#endif
+
+#ifdef __clang__
+#define Z7_PURE_INTERFACES_BEGIN \
+_Pragma("GCC diagnostic push") \
+_Pragma("GCC diagnostic ignored \"-Wnon-virtual-dtor\"")
+_Pragma("GCC diagnostic ignored \"-Wweak-vtables\"")
+#define Z7_PURE_INTERFACES_END \
+_Pragma("GCC diagnostic pop")
+#else
+#define Z7_PURE_INTERFACES_BEGIN
+#define Z7_PURE_INTERFACES_END
+#endif
+
+// NewHandler.h and NewHandler.cpp redefine operator new() to throw exceptions, if compiled with old MSVC compilers
+#include "NewHandler.h"
+
+/*
+// #define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a) Z7_ARRAY_SIZE(a)
+#endif
+*/
+
+#endif // ZIP7_INC_COMMON_H
+
+
+
+// #define Z7_REDEFINE_NULL
+
+#if defined(Z7_REDEFINE_NULL) /* && (!defined(__clang__) || defined(_MSC_VER)) */
+
+// NULL is defined in <stddef.h>
+#include <stddef.h>
+#undef NULL
+
+#ifdef __cplusplus
+ #if defined (__cplusplus) && __cplusplus >= 201103L \
+ || (defined(_MSC_VER) && _MSC_VER >= 1800)
+ #define NULL nullptr
+ #else
+ #define NULL 0
+ #endif
+#else
+ #define NULL ((void *)0)
+#endif
+
+#else // Z7_REDEFINE_NULL
+
+#if defined(__clang__) && __clang_major__ >= 5
+#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant"
+#endif
+
+#endif // Z7_REDEFINE_NULL
+
+// for precompiler:
+#include "MyWindows.h"
diff --git a/CPP/Common/CrcReg.cpp b/CPP/Common/CrcReg.cpp
index 1d9d009..6cda892 100644
--- a/CPP/Common/CrcReg.cpp
+++ b/CPP/Common/CrcReg.cpp
@@ -1,98 +1,92 @@
-// CrcReg.cpp
-
-#include "StdAfx.h"
-
-#include "../../C/7zCrc.h"
-#include "../../C/CpuArch.h"
-
-#include "../Common/MyCom.h"
-
-#include "../7zip/Common/RegisterCodec.h"
-
-EXTERN_C_BEGIN
-
-typedef UInt32 (MY_FAST_CALL *CRC_FUNC)(UInt32 v, const void *data, size_t size, const UInt32 *table);
-
-UInt32 MY_FAST_CALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table);
-
-extern CRC_FUNC g_CrcUpdate;
-extern CRC_FUNC g_CrcUpdateT8;
-extern CRC_FUNC g_CrcUpdateT4;
-
-EXTERN_C_END
-
-class CCrcHasher:
- public IHasher,
- public ICompressSetCoderProperties,
- public CMyUnknownImp
-{
- UInt32 _crc;
- CRC_FUNC _updateFunc;
- Byte mtDummy[1 << 7];
-
- bool SetFunctions(UInt32 tSize);
-public:
- CCrcHasher(): _crc(CRC_INIT_VAL) { SetFunctions(0); }
-
- MY_UNKNOWN_IMP2(IHasher, ICompressSetCoderProperties)
- INTERFACE_IHasher(;)
- STDMETHOD(SetCoderProperties)(const PROPID *propIDs, const PROPVARIANT *props, UInt32 numProps);
-};
-
-bool CCrcHasher::SetFunctions(UInt32 tSize)
-{
- _updateFunc = g_CrcUpdate;
-
- if (tSize == 1)
- _updateFunc = CrcUpdateT1;
- else if (tSize == 4)
- {
- if (g_CrcUpdateT4)
- _updateFunc = g_CrcUpdateT4;
- else
- return false;
- }
- else if (tSize == 8)
- {
- if (g_CrcUpdateT8)
- _updateFunc = g_CrcUpdateT8;
- else
- return false;
- }
-
- return true;
-}
-
-STDMETHODIMP CCrcHasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps)
-{
- for (UInt32 i = 0; i < numProps; i++)
- {
- const PROPVARIANT &prop = coderProps[i];
- if (propIDs[i] == NCoderPropID::kDefaultProp)
- {
- if (prop.vt != VT_UI4)
- return E_INVALIDARG;
- if (!SetFunctions(prop.ulVal))
- return E_NOTIMPL;
- }
- }
- return S_OK;
-}
-
-STDMETHODIMP_(void) CCrcHasher::Init() throw()
-{
- _crc = CRC_INIT_VAL;
-}
-
-STDMETHODIMP_(void) CCrcHasher::Update(const void *data, UInt32 size) throw()
-{
- _crc = _updateFunc(_crc, data, size, g_CrcTable);
-}
-
-STDMETHODIMP_(void) CCrcHasher::Final(Byte *digest) throw()
-{
- UInt32 val = CRC_GET_DIGEST(_crc);
- SetUi32(digest, val);
-}
-
-REGISTER_HASHER(CCrcHasher, 0x1, "CRC32", 4)
+// CrcReg.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/7zCrc.h"
+#include "../../C/CpuArch.h"
+
+#include "../Common/MyCom.h"
+
+#include "../7zip/Common/RegisterCodec.h"
+
+EXTERN_C_BEGIN
+
+// UInt32 Z7_FASTCALL CrcUpdateT1(UInt32 v, const void *data, size_t size, const UInt32 *table);
+
+extern CRC_FUNC g_CrcUpdate;
+// extern CRC_FUNC g_CrcUpdateT4;
+extern CRC_FUNC g_CrcUpdateT8;
+extern CRC_FUNC g_CrcUpdateT0_32;
+extern CRC_FUNC g_CrcUpdateT0_64;
+
+EXTERN_C_END
+
+Z7_CLASS_IMP_COM_2(
+ CCrcHasher
+ , IHasher
+ , ICompressSetCoderProperties
+)
+ UInt32 _crc;
+ CRC_FUNC _updateFunc;
+
+ Z7_CLASS_NO_COPY(CCrcHasher)
+
+ bool SetFunctions(UInt32 tSize);
+public:
+ Byte _mtDummy[1 << 7]; // it's public to eliminate clang warning: unused private field
+
+ CCrcHasher(): _crc(CRC_INIT_VAL) { SetFunctions(0); }
+};
+
+bool CCrcHasher::SetFunctions(UInt32 tSize)
+{
+ CRC_FUNC f = NULL;
+ if (tSize == 0) f = g_CrcUpdate;
+ // else if (tSize == 1) f = CrcUpdateT1;
+ // else if (tSize == 4) f = g_CrcUpdateT4;
+ else if (tSize == 8) f = g_CrcUpdateT8;
+ else if (tSize == 32) f = g_CrcUpdateT0_32;
+ else if (tSize == 64) f = g_CrcUpdateT0_64;
+
+ if (!f)
+ {
+ _updateFunc = g_CrcUpdate;
+ return false;
+ }
+ _updateFunc = f;
+ return true;
+}
+
+Z7_COM7F_IMF(CCrcHasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps))
+{
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ if (propIDs[i] == NCoderPropID::kDefaultProp)
+ {
+ const PROPVARIANT &prop = coderProps[i];
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ if (!SetFunctions(prop.ulVal))
+ return E_NOTIMPL;
+ }
+ }
+ return S_OK;
+}
+
+Z7_COM7F_IMF2(void, CCrcHasher::Init())
+{
+ _crc = CRC_INIT_VAL;
+}
+
+Z7_COM7F_IMF2(void, CCrcHasher::Update(const void *data, UInt32 size))
+{
+ _crc = _updateFunc(_crc, data, size, g_CrcTable);
+}
+
+Z7_COM7F_IMF2(void, CCrcHasher::Final(Byte *digest))
+{
+ const UInt32 val = CRC_GET_DIGEST(_crc);
+ SetUi32(digest, val)
+}
+
+REGISTER_HASHER(CCrcHasher, 0x1, "CRC32", 4)
diff --git a/CPP/Common/Defs.h b/CPP/Common/Defs.h
index 9416098..e302f35 100644
--- a/CPP/Common/Defs.h
+++ b/CPP/Common/Defs.h
@@ -1,15 +1,16 @@
-// Common/Defs.h
-
-#ifndef __COMMON_DEFS_H
-#define __COMMON_DEFS_H
-
-template <class T> inline T MyMin(T a, T b) { return a < b ? a : b; }
-template <class T> inline T MyMax(T a, T b) { return a > b ? a : b; }
-
-template <class T> inline int MyCompare(T a, T b)
- { return a == b ? 0 : (a < b ? -1 : 1); }
-
-inline int BoolToInt(bool v) { return (v ? 1 : 0); }
-inline bool IntToBool(int v) { return (v != 0); }
-
-#endif
+// Common/Defs.h
+
+#ifndef ZIP7_INC_COMMON_DEFS_H
+#define ZIP7_INC_COMMON_DEFS_H
+
+template <class T> inline T MyMin(T a, T b) { return a < b ? a : b; }
+template <class T> inline T MyMax(T a, T b) { return a > b ? a : b; }
+
+template <class T> inline int MyCompare(T a, T b)
+ { return a == b ? 0 : (a < b ? -1 : 1); }
+
+inline int BoolToInt(bool v) { return (v ? 1 : 0); }
+inline unsigned BoolToUInt(bool v) { return (v ? 1u : 0u); }
+inline bool IntToBool(int v) { return (v != 0); }
+
+#endif
diff --git a/CPP/Common/DynLimBuf.cpp b/CPP/Common/DynLimBuf.cpp
new file mode 100644
index 0000000..1d92af3
--- /dev/null
+++ b/CPP/Common/DynLimBuf.cpp
@@ -0,0 +1,93 @@
+// Common/DynLimBuf.cpp
+
+#include "StdAfx.h"
+
+#include "DynLimBuf.h"
+#include "MyString.h"
+
+CDynLimBuf::CDynLimBuf(size_t limit) throw()
+{
+ _chars = NULL;
+ _pos = 0;
+ _size = 0;
+ _sizeLimit = limit;
+ _error = true;
+ unsigned size = 1 << 4;
+ if (size > limit)
+ size = (unsigned)limit;
+ _chars = (Byte *)MyAlloc(size);
+ if (_chars)
+ {
+ _size = size;
+ _error = false;
+ }
+}
+
+CDynLimBuf & CDynLimBuf::operator+=(char c) throw()
+{
+ if (_error)
+ return *this;
+ if (_size == _pos)
+ {
+ size_t n = _sizeLimit - _size;
+ if (n == 0)
+ {
+ _error = true;
+ return *this;
+ }
+ if (n > _size)
+ n = _size;
+
+ n += _pos;
+
+ Byte *newBuf = (Byte *)MyAlloc(n);
+ if (!newBuf)
+ {
+ _error = true;
+ return *this;
+ }
+ memcpy(newBuf, _chars, _pos);
+ MyFree(_chars);
+ _chars = newBuf;
+ _size = n;
+ }
+ _chars[_pos++] = (Byte)c;
+ return *this;
+}
+
+CDynLimBuf &CDynLimBuf::operator+=(const char *s) throw()
+{
+ if (_error)
+ return *this;
+ unsigned len = MyStringLen(s);
+ size_t rem = _sizeLimit - _pos;
+ if (rem < len)
+ {
+ len = (unsigned)rem;
+ _error = true;
+ }
+ if (_size - _pos < len)
+ {
+ size_t n = _pos + len;
+ if (n - _size < _size)
+ {
+ n = _sizeLimit;
+ if (n - _size > _size)
+ n = _size * 2;
+ }
+
+ Byte *newBuf = (Byte *)MyAlloc(n);
+ if (!newBuf)
+ {
+ _error = true;
+ return *this;
+ }
+ memcpy(newBuf, _chars, _pos);
+ MyFree(_chars);
+ _chars = newBuf;
+ _size = n;
+ }
+ memcpy(_chars + _pos, s, len);
+ _pos += len;
+ return *this;
+}
diff --git a/CPP/Common/DynLimBuf.h b/CPP/Common/DynLimBuf.h
new file mode 100644
index 0000000..af22f07
--- /dev/null
+++ b/CPP/Common/DynLimBuf.h
@@ -0,0 +1,41 @@
+// Common/DynLimBuf.h
+
+#ifndef ZIP7_INC_COMMON_DYN_LIM_BUF_H
+#define ZIP7_INC_COMMON_DYN_LIM_BUF_H
+
+#include <string.h>
+
+#include "../../C/Alloc.h"
+
+#include "MyString.h"
+
+class CDynLimBuf
+{
+ Byte *_chars;
+ size_t _pos;
+ size_t _size;
+ size_t _sizeLimit;
+ bool _error;
+
+ CDynLimBuf(const CDynLimBuf &s);
+
+ // ---------- forbidden functions ----------
+ CDynLimBuf &operator+=(wchar_t c);
+
+public:
+ CDynLimBuf(size_t limit) throw();
+ ~CDynLimBuf() { MyFree(_chars); }
+
+ size_t Len() const { return _pos; }
+ bool IsError() const { return _error; }
+ void Empty() { _pos = 0; _error = false; }
+
+ operator const Byte *() const { return _chars; }
+ // const char *Ptr() const { return _chars; }
+
+ CDynLimBuf &operator+=(char c) throw();
+ CDynLimBuf &operator+=(const char *s) throw();
+};
+
+
+#endif
diff --git a/CPP/Common/DynamicBuffer.h b/CPP/Common/DynamicBuffer.h
index 16c9250..714be4a 100644
--- a/CPP/Common/DynamicBuffer.h
+++ b/CPP/Common/DynamicBuffer.h
@@ -1,64 +1,68 @@
-// Common/DynamicBuffer.h
-
-#ifndef __COMMON_DYNAMIC_BUFFER_H
-#define __COMMON_DYNAMIC_BUFFER_H
-
-template <class T> class CDynamicBuffer
-{
- T *_items;
- size_t _size;
- size_t _pos;
-
- CDynamicBuffer(const CDynamicBuffer &buffer);
- void operator=(const CDynamicBuffer &buffer);
-
- void Grow(size_t size)
- {
- size_t delta = _size >= 64 ? _size : 64;
- if (delta < size)
- delta = size;
- size_t newCap = _size + delta;
- if (newCap < delta)
- {
- newCap = _size + size;
- if (newCap < size)
- throw 20120116;
- }
-
- T *newBuffer = new T[newCap];
- if (_pos != 0)
- memcpy(newBuffer, _items, _pos * sizeof(T));
- delete []_items;
- _items = newBuffer;
- _size = newCap;
- }
-
-public:
- CDynamicBuffer(): _items(0), _size(0), _pos(0) {}
- // operator T *() { return _items; }
- operator const T *() const { return _items; }
- ~CDynamicBuffer() { delete []_items; }
-
- T *GetCurPtrAndGrow(size_t addSize)
- {
- size_t rem = _size - _pos;
- if (rem < addSize)
- Grow(addSize - rem);
- T *res = _items + _pos;
- _pos += addSize;
- return res;
- }
-
- void AddData(const T *data, size_t size)
- {
- memcpy(GetCurPtrAndGrow(size), data, size * sizeof(T));
- }
-
- const size_t GetPos() const { return _pos; }
-
- // void Empty() { _pos = 0; }
-};
-
-typedef CDynamicBuffer<unsigned char> CByteDynamicBuffer;
-
-#endif
+// Common/DynamicBuffer.h
+
+#ifndef ZIP7_INC_COMMON_DYNAMIC_BUFFER_H
+#define ZIP7_INC_COMMON_DYNAMIC_BUFFER_H
+
+#include <string.h>
+
+#include "Common.h"
+
+template <class T> class CDynamicBuffer
+{
+ T *_items;
+ size_t _size;
+ size_t _pos;
+
+ CDynamicBuffer(const CDynamicBuffer &buffer);
+ void operator=(const CDynamicBuffer &buffer);
+
+ void Grow(size_t size)
+ {
+ size_t delta = _size >= 64 ? _size : 64;
+ if (delta < size)
+ delta = size;
+ size_t newCap = _size + delta;
+ if (newCap < delta)
+ {
+ newCap = _size + size;
+ if (newCap < size)
+ throw 20120116;
+ }
+
+ T *newBuffer = new T[newCap];
+ if (_pos != 0)
+ memcpy(newBuffer, _items, _pos * sizeof(T));
+ delete []_items;
+ _items = newBuffer;
+ _size = newCap;
+ }
+
+public:
+ CDynamicBuffer(): _items(NULL), _size(0), _pos(0) {}
+ // operator T *() { return _items; }
+ operator const T *() const { return _items; }
+ ~CDynamicBuffer() { delete []_items; }
+
+ T *GetCurPtrAndGrow(size_t addSize)
+ {
+ size_t rem = _size - _pos;
+ if (rem < addSize)
+ Grow(addSize - rem);
+ T *res = _items + _pos;
+ _pos += addSize;
+ return res;
+ }
+
+ void AddData(const T *data, size_t size)
+ {
+ memcpy(GetCurPtrAndGrow(size), data, size * sizeof(T));
+ }
+
+ size_t GetPos() const { return _pos; }
+
+ // void Empty() { _pos = 0; }
+};
+
+typedef CDynamicBuffer<unsigned char> CByteDynamicBuffer;
+
+#endif
diff --git a/CPP/Common/IntToString.cpp b/CPP/Common/IntToString.cpp
index da627ca..21b0680 100644
--- a/CPP/Common/IntToString.cpp
+++ b/CPP/Common/IntToString.cpp
@@ -1,193 +1,192 @@
-// Common/IntToString.cpp
-
-#include "StdAfx.h"
-
-#include "../../C/CpuArch.h"
-
-#include "IntToString.h"
-
-#define CONVERT_INT_TO_STR(charType, tempSize) \
- unsigned char temp[tempSize]; unsigned i = 0; \
- while (val >= 10) { temp[i++] = (unsigned char)('0' + (unsigned)(val % 10)); val /= 10; } \
- *s++ = (charType)('0' + (unsigned)val); \
- while (i != 0) { i--; *s++ = temp[i]; } \
- *s = 0;
-
-void ConvertUInt32ToString(UInt32 val, char *s) throw()
-{
- CONVERT_INT_TO_STR(char, 16);
-}
-
-void ConvertUInt64ToString(UInt64 val, char *s) throw()
-{
- if (val <= (UInt32)0xFFFFFFFF)
- {
- ConvertUInt32ToString((UInt32)val, s);
- return;
- }
- CONVERT_INT_TO_STR(char, 24);
-}
-
-void ConvertUInt64ToOct(UInt64 val, char *s) throw()
-{
- UInt64 v = val;
- unsigned i;
- for (i = 1;; i++)
- {
- v >>= 3;
- if (v == 0)
- break;
- }
- s[i] = 0;
- do
- {
- unsigned t = (unsigned)(val & 0x7);
- val >>= 3;
- s[--i] = (char)('0' + t);
- }
- while (i);
-}
-
-
-#define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))))
-
-static inline char GetHexChar(unsigned t) { return GET_HEX_CHAR(t); }
-
-
-void ConvertUInt32ToHex(UInt32 val, char *s) throw()
-{
- UInt32 v = val;
- unsigned i;
- for (i = 1;; i++)
- {
- v >>= 4;
- if (v == 0)
- break;
- }
- s[i] = 0;
- do
- {
- unsigned t = (unsigned)(val & 0xF);
- val >>= 4;
- s[--i] = GET_HEX_CHAR(t);
- }
- while (i);
-}
-
-
-void ConvertUInt64ToHex(UInt64 val, char *s) throw()
-{
- UInt64 v = val;
- unsigned i;
- for (i = 1;; i++)
- {
- v >>= 4;
- if (v == 0)
- break;
- }
- s[i] = 0;
- do
- {
- unsigned t = (unsigned)(val & 0xF);
- val >>= 4;
- s[--i] = GET_HEX_CHAR(t);
- }
- while (i);
-}
-
-void ConvertUInt32ToHex8Digits(UInt32 val, char *s) throw()
-{
- s[8] = 0;
- for (int i = 7; i >= 0; i--)
- {
- unsigned t = val & 0xF;
- val >>= 4;
- s[i] = GET_HEX_CHAR(t);;
- }
-}
-
-/*
-void ConvertUInt32ToHex8Digits(UInt32 val, wchar_t *s)
-{
- s[8] = 0;
- for (int i = 7; i >= 0; i--)
- {
- unsigned t = val & 0xF;
- val >>= 4;
- s[i] = (wchar_t)(((t < 10) ? ('0' + t) : ('A' + (t - 10))));
- }
-}
-*/
-
-void ConvertUInt32ToString(UInt32 val, wchar_t *s) throw()
-{
- CONVERT_INT_TO_STR(wchar_t, 16);
-}
-
-void ConvertUInt64ToString(UInt64 val, wchar_t *s) throw()
-{
- if (val <= (UInt32)0xFFFFFFFF)
- {
- ConvertUInt32ToString((UInt32)val, s);
- return;
- }
- CONVERT_INT_TO_STR(wchar_t, 24);
-}
-
-void ConvertInt64ToString(Int64 val, char *s) throw()
-{
- if (val < 0)
- {
- *s++ = '-';
- val = -val;
- }
- ConvertUInt64ToString(val, s);
-}
-
-void ConvertInt64ToString(Int64 val, wchar_t *s) throw()
-{
- if (val < 0)
- {
- *s++ = L'-';
- val = -val;
- }
- ConvertUInt64ToString(val, s);
-}
-
-
-static void ConvertByteToHex2Digits(unsigned v, char *s) throw()
-{
- s[0] = GetHexChar(v >> 4);
- s[1] = GetHexChar(v & 0xF);
-}
-
-static void ConvertUInt16ToHex4Digits(UInt32 val, char *s) throw()
-{
- ConvertByteToHex2Digits(val >> 8, s);
- ConvertByteToHex2Digits(val & 0xFF, s + 2);
-}
-
-char *RawLeGuidToString(const Byte *g, char *s) throw()
-{
- ConvertUInt32ToHex8Digits(GetUi32(g ), s); s += 8; *s++ = '-';
- ConvertUInt16ToHex4Digits(GetUi16(g + 4), s); s += 4; *s++ = '-';
- ConvertUInt16ToHex4Digits(GetUi16(g + 6), s); s += 4; *s++ = '-';
- for (unsigned i = 0; i < 8; i++)
- {
- if (i == 2)
- *s++ = '-';
- ConvertByteToHex2Digits(g[8 + i], s);
- s += 2;
- }
- *s = 0;
- return s;
-}
-
-char *RawLeGuidToString_Braced(const Byte *g, char *s) throw()
-{
- *s++ = '{';
- s = RawLeGuidToString(g, s);
- *s++ = '}';
- *s = 0;
- return s;
-}
+// Common/IntToString.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/CpuArch.h"
+
+#include "IntToString.h"
+
+#define CONVERT_INT_TO_STR(charType, tempSize) \
+ unsigned char temp[tempSize]; unsigned i = 0; \
+ while (val >= 10) { temp[i++] = (unsigned char)('0' + (unsigned)(val % 10)); val /= 10; } \
+ *s++ = (charType)('0' + (unsigned)val); \
+ while (i != 0) { i--; *s++ = (charType)temp[i]; } \
+ *s = 0; \
+ return s;
+
+char * ConvertUInt32ToString(UInt32 val, char *s) throw()
+{
+ CONVERT_INT_TO_STR(char, 16)
+}
+
+char * ConvertUInt64ToString(UInt64 val, char *s) throw()
+{
+ if (val <= (UInt32)0xFFFFFFFF)
+ {
+ return ConvertUInt32ToString((UInt32)val, s);
+ }
+ CONVERT_INT_TO_STR(char, 24)
+}
+
+void ConvertUInt64ToOct(UInt64 val, char *s) throw()
+{
+ UInt64 v = val;
+ unsigned i;
+ for (i = 1;; i++)
+ {
+ v >>= 3;
+ if (v == 0)
+ break;
+ }
+ s[i] = 0;
+ do
+ {
+ unsigned t = (unsigned)(val & 0x7);
+ val >>= 3;
+ s[--i] = (char)('0' + t);
+ }
+ while (i);
+}
+
+
+#define GET_HEX_CHAR(t) ((char)(((t < 10) ? ('0' + t) : ('A' + (t - 10)))))
+
+static inline char GetHexChar(unsigned t) { return GET_HEX_CHAR(t); }
+
+
+void ConvertUInt32ToHex(UInt32 val, char *s) throw()
+{
+ UInt32 v = val;
+ unsigned i;
+ for (i = 1;; i++)
+ {
+ v >>= 4;
+ if (v == 0)
+ break;
+ }
+ s[i] = 0;
+ do
+ {
+ unsigned t = (unsigned)(val & 0xF);
+ val >>= 4;
+ s[--i] = GET_HEX_CHAR(t);
+ }
+ while (i);
+}
+
+
+void ConvertUInt64ToHex(UInt64 val, char *s) throw()
+{
+ UInt64 v = val;
+ unsigned i;
+ for (i = 1;; i++)
+ {
+ v >>= 4;
+ if (v == 0)
+ break;
+ }
+ s[i] = 0;
+ do
+ {
+ unsigned t = (unsigned)(val & 0xF);
+ val >>= 4;
+ s[--i] = GET_HEX_CHAR(t);
+ }
+ while (i);
+}
+
+void ConvertUInt32ToHex8Digits(UInt32 val, char *s) throw()
+{
+ s[8] = 0;
+ for (int i = 7; i >= 0; i--)
+ {
+ unsigned t = val & 0xF;
+ val >>= 4;
+ s[i] = GET_HEX_CHAR(t);
+ }
+}
+
+/*
+void ConvertUInt32ToHex8Digits(UInt32 val, wchar_t *s)
+{
+ s[8] = 0;
+ for (int i = 7; i >= 0; i--)
+ {
+ unsigned t = val & 0xF;
+ val >>= 4;
+ s[i] = (wchar_t)(((t < 10) ? ('0' + t) : ('A' + (t - 10))));
+ }
+}
+*/
+
+wchar_t * ConvertUInt32ToString(UInt32 val, wchar_t *s) throw()
+{
+ CONVERT_INT_TO_STR(wchar_t, 16)
+}
+
+wchar_t * ConvertUInt64ToString(UInt64 val, wchar_t *s) throw()
+{
+ if (val <= (UInt32)0xFFFFFFFF)
+ {
+ return ConvertUInt32ToString((UInt32)val, s);
+ }
+ CONVERT_INT_TO_STR(wchar_t, 24)
+}
+
+void ConvertInt64ToString(Int64 val, char *s) throw()
+{
+ if (val < 0)
+ {
+ *s++ = '-';
+ val = -val;
+ }
+ ConvertUInt64ToString((UInt64)val, s);
+}
+
+void ConvertInt64ToString(Int64 val, wchar_t *s) throw()
+{
+ if (val < 0)
+ {
+ *s++ = L'-';
+ val = -val;
+ }
+ ConvertUInt64ToString((UInt64)val, s);
+}
+
+
+static void ConvertByteToHex2Digits(unsigned v, char *s) throw()
+{
+ s[0] = GetHexChar(v >> 4);
+ s[1] = GetHexChar(v & 0xF);
+}
+
+static void ConvertUInt16ToHex4Digits(UInt32 val, char *s) throw()
+{
+ ConvertByteToHex2Digits(val >> 8, s);
+ ConvertByteToHex2Digits(val & 0xFF, s + 2);
+}
+
+char *RawLeGuidToString(const Byte *g, char *s) throw()
+{
+ ConvertUInt32ToHex8Digits(GetUi32(g ), s); s += 8; *s++ = '-';
+ ConvertUInt16ToHex4Digits(GetUi16(g + 4), s); s += 4; *s++ = '-';
+ ConvertUInt16ToHex4Digits(GetUi16(g + 6), s); s += 4; *s++ = '-';
+ for (unsigned i = 0; i < 8; i++)
+ {
+ if (i == 2)
+ *s++ = '-';
+ ConvertByteToHex2Digits(g[8 + i], s);
+ s += 2;
+ }
+ *s = 0;
+ return s;
+}
+
+char *RawLeGuidToString_Braced(const Byte *g, char *s) throw()
+{
+ *s++ = '{';
+ s = RawLeGuidToString(g, s);
+ *s++ = '}';
+ *s = 0;
+ return s;
+}
diff --git a/CPP/Common/IntToString.h b/CPP/Common/IntToString.h
index 07b67c3..f4fc662 100644
--- a/CPP/Common/IntToString.h
+++ b/CPP/Common/IntToString.h
@@ -1,28 +1,30 @@
-// Common/IntToString.h
-
-#ifndef __COMMON_INT_TO_STRING_H
-#define __COMMON_INT_TO_STRING_H
-
-#include "MyTypes.h"
-
-void ConvertUInt32ToString(UInt32 value, char *s) throw();
-void ConvertUInt64ToString(UInt64 value, char *s) throw();
-
-void ConvertUInt32ToString(UInt32 value, wchar_t *s) throw();
-void ConvertUInt64ToString(UInt64 value, wchar_t *s) throw();
-
-void ConvertUInt64ToOct(UInt64 value, char *s) throw();
-
-void ConvertUInt32ToHex(UInt32 value, char *s) throw();
-void ConvertUInt64ToHex(UInt64 value, char *s) throw();
-void ConvertUInt32ToHex8Digits(UInt32 value, char *s) throw();
-// void ConvertUInt32ToHex8Digits(UInt32 value, wchar_t *s) throw();
-
-void ConvertInt64ToString(Int64 value, char *s) throw();
-void ConvertInt64ToString(Int64 value, wchar_t *s) throw();
-
-// use RawLeGuid only for RAW bytes that contain stored GUID as Little-endian.
-char *RawLeGuidToString(const Byte *guid, char *s) throw();
-char *RawLeGuidToString_Braced(const Byte *guid, char *s) throw();
-
-#endif
+// Common/IntToString.h
+
+#ifndef ZIP7_INC_COMMON_INT_TO_STRING_H
+#define ZIP7_INC_COMMON_INT_TO_STRING_H
+
+#include "MyTypes.h"
+
+// return: the pointer to the "terminating" null character after written characters
+
+char * ConvertUInt32ToString(UInt32 value, char *s) throw();
+char * ConvertUInt64ToString(UInt64 value, char *s) throw();
+
+wchar_t * ConvertUInt32ToString(UInt32 value, wchar_t *s) throw();
+wchar_t * ConvertUInt64ToString(UInt64 value, wchar_t *s) throw();
+
+void ConvertUInt64ToOct(UInt64 value, char *s) throw();
+
+void ConvertUInt32ToHex(UInt32 value, char *s) throw();
+void ConvertUInt64ToHex(UInt64 value, char *s) throw();
+void ConvertUInt32ToHex8Digits(UInt32 value, char *s) throw();
+// void ConvertUInt32ToHex8Digits(UInt32 value, wchar_t *s) throw();
+
+void ConvertInt64ToString(Int64 value, char *s) throw();
+void ConvertInt64ToString(Int64 value, wchar_t *s) throw();
+
+// use RawLeGuid only for RAW bytes that contain stored GUID as Little-endian.
+char *RawLeGuidToString(const Byte *guid, char *s) throw();
+char *RawLeGuidToString_Braced(const Byte *guid, char *s) throw();
+
+#endif
diff --git a/CPP/Common/Lang.cpp b/CPP/Common/Lang.cpp
new file mode 100644
index 0000000..b0b4342
--- /dev/null
+++ b/CPP/Common/Lang.cpp
@@ -0,0 +1,173 @@
+// Common/Lang.cpp
+
+#include "StdAfx.h"
+
+#include "Lang.h"
+#include "StringToInt.h"
+#include "UTFConvert.h"
+
+#include "../Windows/FileIO.h"
+
+void CLang::Clear() throw()
+{
+ _ids.Clear();
+ _offsets.Clear();
+ Comments.Clear();
+ delete []_text;
+ _text = NULL;
+}
+
+static const char * const kLangSignature = ";!@Lang2@!UTF-8!\n";
+
+bool CLang::OpenFromString(const AString &s2)
+{
+ UString su;
+ if (!ConvertUTF8ToUnicode(s2, su))
+ return false;
+ if (su.IsEmpty())
+ return false;
+ const wchar_t *s = su;
+ const wchar_t *sLim = s + su.Len();
+ if (*s == 0xFEFF)
+ s++;
+ for (const char *p = kLangSignature;; s++)
+ {
+ const Byte c = (Byte)(*p++);
+ if (c == 0)
+ break;
+ if (*s != c)
+ return false;
+ }
+
+ wchar_t *text = new wchar_t[(size_t)(sLim - s) + 1];
+ _text = text;
+
+ UString comment;
+ Int32 id = -1024;
+ unsigned pos = 0;
+
+ while (s != sLim)
+ {
+ const unsigned start = pos;
+ do
+ {
+ wchar_t c = *s++;
+ if (c == '\n')
+ break;
+ if (c == '\\')
+ {
+ if (s == sLim)
+ return false;
+ c = *s++;
+ switch (c)
+ {
+ case '\n': return false;
+ case 'n': c = '\n'; break;
+ case 't': c = '\t'; break;
+ case '\\': /* c = '\\'; */ break;
+ default: text[pos++] = L'\\'; break;
+ }
+ }
+ text[pos++] = c;
+ }
+ while (s != sLim);
+
+ {
+ unsigned j = start;
+ for (; j < pos; j++)
+ if (text[j] != ' ' && text[j] != '\t')
+ break;
+ if (j == pos)
+ {
+ id++;
+ pos = start;
+ continue;
+ }
+ }
+
+ // start != pos
+ text[pos++] = 0;
+
+ if (text[start] == ';')
+ {
+ comment = text + start;
+ comment.TrimRight();
+ if (comment.Len() != 1)
+ Comments.Add(comment);
+ id++;
+ pos = start;
+ continue;
+ }
+
+ const wchar_t *end;
+ const UInt32 id32 = ConvertStringToUInt32(text + start, &end);
+ if (*end == 0)
+ {
+ if (id32 > ((UInt32)1 << 30) || (Int32)id32 < id)
+ return false;
+ id = (Int32)id32;
+ pos = start;
+ continue;
+ }
+
+ if (id < 0)
+ return false;
+ _ids.Add((UInt32)id++);
+ _offsets.Add(start);
+ }
+
+ return true;
+}
+
+bool CLang::Open(CFSTR fileName, const char *id)
+{
+ Clear();
+ NWindows::NFile::NIO::CInFile file;
+ if (!file.Open(fileName))
+ return false;
+ UInt64 length;
+ if (!file.GetLength(length))
+ return false;
+ if (length > (1 << 20))
+ return false;
+
+ AString s;
+ const unsigned len = (unsigned)length;
+ char *p = s.GetBuf(len);
+ size_t processed;
+ if (!file.ReadFull(p, len, processed))
+ return false;
+ file.Close();
+ if (len != processed)
+ return false;
+
+ char *p2 = p;
+ for (unsigned i = 0; i < len; i++)
+ {
+ const char c = p[i];
+ if (c == 0)
+ break;
+ if (c != 0x0D)
+ *p2++ = c;
+ }
+ *p2 = 0;
+ s.ReleaseBuf_SetLen((unsigned)(p2 - p));
+
+ if (OpenFromString(s))
+ {
+ const wchar_t *name = Get(0);
+ if (name && StringsAreEqual_Ascii(name, id))
+ return true;
+ }
+
+ Clear();
+ return false;
+}
+
+const wchar_t *CLang::Get(UInt32 id) const throw()
+{
+ const int index = _ids.FindInSorted(id);
+ if (index < 0)
+ return NULL;
+ return _text + (size_t)_offsets[(unsigned)index];
+}
diff --git a/CPP/Common/Lang.h b/CPP/Common/Lang.h
index e95de68..76d5418 100644
--- a/CPP/Common/Lang.h
+++ b/CPP/Common/Lang.h
@@ -1,23 +1,30 @@
-// Common/Lang.h
-
-#ifndef __COMMON_LANG_H
-#define __COMMON_LANG_H
-
-#include "MyString.h"
-
-class CLang
-{
- wchar_t *_text;
- CRecordVector<UInt32> _ids;
- CRecordVector<UInt32> _offsets;
-
- bool OpenFromString(const AString &s);
-public:
- CLang(): _text(0) {}
- ~CLang() { Clear(); }
- bool Open(CFSTR fileName, const char *id);
- void Clear() throw();
- const wchar_t *Get(UInt32 id) const throw();
-};
-
-#endif
+// Common/Lang.h
+
+#ifndef ZIP7_INC_COMMON_LANG_H
+#define ZIP7_INC_COMMON_LANG_H
+
+#include "MyString.h"
+
+class CLang
+{
+ wchar_t *_text;
+
+ bool OpenFromString(const AString &s);
+public:
+ CRecordVector<UInt32> _ids;
+ CRecordVector<UInt32> _offsets;
+ UStringVector Comments;
+
+ CLang(): _text(NULL) {}
+ ~CLang() { Clear(); }
+ bool Open(CFSTR fileName, const char *id);
+ void Clear() throw();
+ bool IsEmpty() const { return _ids.IsEmpty(); }
+ const wchar_t *Get(UInt32 id) const throw();
+ const wchar_t *Get_by_index(unsigned index) const throw()
+ {
+ return _text + (size_t)_offsets[index];
+ }
+};
+
+#endif
diff --git a/CPP/Common/ListFileUtils.cpp b/CPP/Common/ListFileUtils.cpp
index 2fdde6d..e43dbc9 100644
--- a/CPP/Common/ListFileUtils.cpp
+++ b/CPP/Common/ListFileUtils.cpp
@@ -1,132 +1,150 @@
-// Common/ListFileUtils.cpp
-
-#include "StdAfx.h"
-
-#include "../../C/CpuArch.h"
-
-#include "../Windows/FileIO.h"
-
-#include "ListFileUtils.h"
-#include "MyBuffer.h"
-#include "StringConvert.h"
-#include "UTFConvert.h"
-
-static const char kQuoteChar = '\"';
-
-static void AddName(UStringVector &strings, UString &s)
-{
- s.Trim();
- if (s.Len() >= 2 && s[0] == kQuoteChar && s.Back() == kQuoteChar)
- {
- s.DeleteBack();
- s.Delete(0);
- }
- if (!s.IsEmpty())
- strings.Add(s);
-}
-
-bool ReadNamesFromListFile2(CFSTR fileName, UStringVector &strings, UINT codePage, DWORD &lastError)
-{
- lastError = 0;
- NWindows::NFile::NIO::CInFile file;
- if (!file.Open(fileName))
- {
- lastError = ::GetLastError();
- return false;
- }
- UInt64 fileSize;
- if (!file.GetLength(fileSize))
- {
- lastError = ::GetLastError();
- return false;
- }
- if (fileSize >= ((UInt32)1 << 31) - 32)
- return false;
- UString u;
- if (codePage == MY__CP_UTF16 || codePage == MY__CP_UTF16BE)
- {
- if ((fileSize & 1) != 0)
- return false;
- CByteArr buf((size_t)fileSize);
- UInt32 processed;
- if (!file.Read(buf, (UInt32)fileSize, processed))
- {
- lastError = ::GetLastError();
- return false;
- }
- if (processed != fileSize)
- return false;
- file.Close();
- unsigned num = (unsigned)fileSize / 2;
- wchar_t *p = u.GetBuf(num);
- if (codePage == MY__CP_UTF16)
- for (unsigned i = 0; i < num; i++)
- {
- wchar_t c = GetUi16(buf + (size_t)i * 2);
- if (c == 0)
- return false;
- p[i] = c;
- }
- else
- for (unsigned i = 0; i < num; i++)
- {
- wchar_t c = (wchar_t)GetBe16(buf + (size_t)i * 2);
- if (c == 0)
- return false;
- p[i] = c;
- }
- p[num] = 0;
- u.ReleaseBuf_SetLen(num);
- }
- else
- {
- AString s;
- char *p = s.GetBuf((unsigned)fileSize);
- UInt32 processed;
- if (!file.Read(p, (UInt32)fileSize, processed))
- {
- lastError = ::GetLastError();
- return false;
- }
- if (processed != fileSize)
- return false;
- file.Close();
- s.ReleaseBuf_CalcLen((unsigned)processed);
- if (s.Len() != processed)
- return false;
-
- // #ifdef CP_UTF8
- if (codePage == CP_UTF8)
- {
- if (!ConvertUTF8ToUnicode(s, u))
- return false;
- }
- else
- // #endif
- MultiByteToUnicodeString2(u, s, codePage);
- }
-
- const wchar_t kGoodBOM = 0xFEFF;
- // const wchar_t kBadBOM = 0xFFFE;
-
- UString s;
- unsigned i = 0;
- for (; i < u.Len() && u[i] == kGoodBOM; i++);
- for (; i < u.Len(); i++)
- {
- wchar_t c = u[i];
- /*
- if (c == kGoodBOM || c == kBadBOM)
- return false;
- */
- if (c == '\n' || c == 0xD)
- {
- AddName(strings, s);
- s.Empty();
- }
- else
- s += c;
- }
- AddName(strings, s);
- return true;
-}
+// Common/ListFileUtils.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/CpuArch.h"
+
+#include "ListFileUtils.h"
+#include "MyBuffer.h"
+#include "StringConvert.h"
+#include "UTFConvert.h"
+
+#include "../Windows/FileIO.h"
+
+#define CSysInFile NWindows::NFile::NIO::CInFile
+#define MY_GET_LAST_ERROR ::GetLastError()
+
+
+#define kQuoteChar '\"'
+
+
+static void AddName(UStringVector &strings, UString &s)
+{
+ s.Trim();
+ if (s.Len() >= 2 && s[0] == kQuoteChar && s.Back() == kQuoteChar)
+ {
+ s.DeleteBack();
+ s.Delete(0);
+ }
+ if (!s.IsEmpty())
+ strings.Add(s);
+}
+
+
+static bool My_File_Read(CSysInFile &file, void *data, size_t size, DWORD &lastError)
+{
+ size_t processed;
+ if (!file.ReadFull(data, size, processed))
+ {
+ lastError = MY_GET_LAST_ERROR;
+ return false;
+ }
+ if (processed != size)
+ {
+ lastError = 1; // error: size of listfile was changed
+ return false;
+ }
+ return true;
+}
+
+
+bool ReadNamesFromListFile2(CFSTR fileName, UStringVector &strings, UINT codePage, DWORD &lastError)
+{
+ lastError = 0;
+ CSysInFile file;
+ if (!file.Open(fileName))
+ {
+ lastError = MY_GET_LAST_ERROR;
+ return false;
+ }
+ UInt64 fileSize;
+ if (!file.GetLength(fileSize))
+ {
+ lastError = MY_GET_LAST_ERROR;
+ return false;
+ }
+ if (fileSize >= ((UInt32)1 << 31) - 32)
+ return false;
+ UString u;
+ if (codePage == Z7_WIN_CP_UTF16 || codePage == Z7_WIN_CP_UTF16BE)
+ {
+ if ((fileSize & 1) != 0)
+ return false;
+ CByteArr buf((size_t)fileSize);
+
+ if (!My_File_Read(file, buf, (size_t)fileSize, lastError))
+ return false;
+
+ file.Close();
+ const unsigned num = (unsigned)fileSize / 2;
+ wchar_t *p = u.GetBuf(num);
+ if (codePage == Z7_WIN_CP_UTF16)
+ for (unsigned i = 0; i < num; i++)
+ {
+ wchar_t c = GetUi16(buf + (size_t)i * 2);
+ if (c == 0)
+ return false;
+ p[i] = c;
+ }
+ else
+ for (unsigned i = 0; i < num; i++)
+ {
+ wchar_t c = (wchar_t)GetBe16(buf + (size_t)i * 2);
+ if (c == 0)
+ return false;
+ p[i] = c;
+ }
+ p[num] = 0;
+ u.ReleaseBuf_SetLen(num);
+ }
+ else
+ {
+ AString s;
+ char *p = s.GetBuf((unsigned)fileSize);
+
+ if (!My_File_Read(file, p, (size_t)fileSize, lastError))
+ return false;
+
+ file.Close();
+ s.ReleaseBuf_CalcLen((unsigned)fileSize);
+ if (s.Len() != fileSize)
+ return false;
+
+ // #ifdef CP_UTF8
+ if (codePage == CP_UTF8)
+ {
+ // we must check UTF8 here, if convert function doesn't check
+ if (!CheckUTF8_AString(s))
+ return false;
+ if (!ConvertUTF8ToUnicode(s, u))
+ return false;
+ }
+ else
+ // #endif
+ MultiByteToUnicodeString2(u, s, codePage);
+ }
+
+ const wchar_t kGoodBOM = 0xFEFF;
+ // const wchar_t kBadBOM = 0xFFFE;
+
+ UString s;
+ unsigned i = 0;
+ for (; i < u.Len() && u[i] == kGoodBOM; i++);
+ for (; i < u.Len(); i++)
+ {
+ wchar_t c = u[i];
+ /*
+ if (c == kGoodBOM || c == kBadBOM)
+ return false;
+ */
+ if (c == '\n' || c == 0xD)
+ {
+ AddName(strings, s);
+ s.Empty();
+ }
+ else
+ s += c;
+ }
+ AddName(strings, s);
+ return true;
+}
diff --git a/CPP/Common/ListFileUtils.h b/CPP/Common/ListFileUtils.h
index a4f0d16..d43cc37 100644
--- a/CPP/Common/ListFileUtils.h
+++ b/CPP/Common/ListFileUtils.h
@@ -1,18 +1,18 @@
-// Common/ListFileUtils.h
-
-#ifndef __COMMON_LIST_FILE_UTILS_H
-#define __COMMON_LIST_FILE_UTILS_H
-
-#include "MyString.h"
-#include "MyTypes.h"
-
-#define MY__CP_UTF16 1200
-#define MY__CP_UTF16BE 1201
-
-// bool ReadNamesFromListFile(CFSTR fileName, UStringVector &strings, UINT codePage = CP_OEMCP);
-
- // = CP_OEMCP
-bool ReadNamesFromListFile2(CFSTR fileName, UStringVector &strings, UINT codePage,
- DWORD &lastError);
-
-#endif
+// Common/ListFileUtils.h
+
+#ifndef ZIP7_INC_COMMON_LIST_FILE_UTILS_H
+#define ZIP7_INC_COMMON_LIST_FILE_UTILS_H
+
+#include "MyString.h"
+#include "MyTypes.h"
+
+#define Z7_WIN_CP_UTF16 1200
+#define Z7_WIN_CP_UTF16BE 1201
+
+// bool ReadNamesFromListFile(CFSTR fileName, UStringVector &strings, UINT codePage = CP_OEMCP);
+
+ // = CP_OEMCP
+bool ReadNamesFromListFile2(CFSTR fileName, UStringVector &strings, UINT codePage,
+ DWORD &lastError);
+
+#endif
diff --git a/CPP/Common/LzFindPrepare.cpp b/CPP/Common/LzFindPrepare.cpp
new file mode 100644
index 0000000..8845e4a
--- /dev/null
+++ b/CPP/Common/LzFindPrepare.cpp
@@ -0,0 +1,7 @@
+// Sha256Prepare.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/LzFind.h"
+
+static struct CLzFindPrepare { CLzFindPrepare() { LzFindPrepare(); } } g_CLzFindPrepare;
diff --git a/CPP/Common/MyBuffer.h b/CPP/Common/MyBuffer.h
index ae320ee..bc829f4 100644
--- a/CPP/Common/MyBuffer.h
+++ b/CPP/Common/MyBuffer.h
@@ -1,259 +1,286 @@
-// Common/MyBuffer.h
-
-#ifndef __COMMON_MY_BUFFER_H
-#define __COMMON_MY_BUFFER_H
-
-#include "Defs.h"
-
-/* 7-Zip now uses CBuffer only as CByteBuffer.
- So there is no need to use MY_ARRAY_NEW macro in CBuffer code. */
-
-template <class T> class CBuffer
-{
- T *_items;
- size_t _size;
-
-public:
- void Free()
- {
- if (_items)
- {
- delete []_items;
- _items = 0;
- }
- _size = 0;
- }
-
- CBuffer(): _items(0), _size(0) {};
- CBuffer(size_t size): _items(0), _size(0) { _items = new T[size]; _size = size; }
- CBuffer(const CBuffer &buffer): _items(0), _size(0)
- {
- size_t size = buffer._size;
- if (size != 0)
- {
- _items = new T[size];
- memcpy(_items, buffer._items, size * sizeof(T));
- _size = size;
- }
- }
-
- ~CBuffer() { delete []_items; }
-
- operator T *() { return _items; }
- operator const T *() const { return _items; }
- size_t Size() const { return _size; }
-
- void Alloc(size_t size)
- {
- if (size != _size)
- {
- Free();
- if (size != 0)
- {
- _items = new T[size];
- _size = size;
- }
- }
- }
-
- void AllocAtLeast(size_t size)
- {
- if (size > _size)
- {
- Free();
- _items = new T[size];
- _size = size;
- }
- }
-
- void CopyFrom(const T *data, size_t size)
- {
- Alloc(size);
- if (size != 0)
- memcpy(_items, data, size * sizeof(T));
- }
-
- void ChangeSize_KeepData(size_t newSize, size_t keepSize)
- {
- if (newSize == _size)
- return;
- T *newBuffer = NULL;
- if (newSize != 0)
- {
- newBuffer = new T[newSize];
- if (keepSize > _size)
- keepSize = _size;
- if (keepSize != 0)
- memcpy(newBuffer, _items, MyMin(keepSize, newSize) * sizeof(T));
- }
- delete []_items;
- _items = newBuffer;
- _size = newSize;
- }
-
- CBuffer& operator=(const CBuffer &buffer)
- {
- if (&buffer != this)
- CopyFrom(buffer, buffer._size);
- return *this;
- }
-};
-
-template <class T>
-bool operator==(const CBuffer<T>& b1, const CBuffer<T>& b2)
-{
- size_t size1 = b1.Size();
- if (size1 != b2.Size())
- return false;
- if (size1 == 0)
- return true;
- return memcmp(b1, b2, size1 * sizeof(T)) == 0;
-}
-
-template <class T>
-bool operator!=(const CBuffer<T>& b1, const CBuffer<T>& b2)
-{
- size_t size1 = b1.Size();
- if (size1 != b2.Size())
- return true;
- if (size1 == 0)
- return false;
- return memcmp(b1, b2, size1 * sizeof(T)) != 0;
-}
-
-
-// typedef CBuffer<char> CCharBuffer;
-// typedef CBuffer<wchar_t> CWCharBuffer;
-typedef CBuffer<unsigned char> CByteBuffer;
-
-
-template <class T> class CObjArray
-{
-protected:
- T *_items;
-private:
- // we disable copy
- CObjArray(const CObjArray &buffer);
- void operator=(const CObjArray &buffer);
-public:
- void Free()
- {
- delete []_items;
- _items = 0;
- }
- CObjArray(size_t size): _items(0)
- {
- if (size != 0)
- {
- MY_ARRAY_NEW(_items, T, size)
- // _items = new T[size];
- }
- }
- CObjArray(): _items(0) {};
- ~CObjArray() { delete []_items; }
-
- operator T *() { return _items; }
- operator const T *() const { return _items; }
-
- void Alloc(size_t newSize)
- {
- delete []_items;
- _items = 0;
- MY_ARRAY_NEW(_items, T, newSize)
- // _items = new T[newSize];
- }
-};
-
-typedef CObjArray<unsigned char> CByteArr;
-typedef CObjArray<bool> CBoolArr;
-typedef CObjArray<int> CIntArr;
-typedef CObjArray<unsigned> CUIntArr;
-
-
-template <class T> class CObjArray2
-{
- T *_items;
- unsigned _size;
-
- // we disable copy
- CObjArray2(const CObjArray2 &buffer);
- void operator=(const CObjArray2 &buffer);
-public:
-
- void Free()
- {
- delete []_items;
- _items = 0;
- _size = 0;
- }
- CObjArray2(): _items(0), _size(0) {};
- /*
- CObjArray2(const CObjArray2 &buffer): _items(0), _size(0)
- {
- size_t newSize = buffer._size;
- if (newSize != 0)
- {
- T *newBuffer = new T[newSize];;
- _items = newBuffer;
- _size = newSize;
- const T *src = buffer;
- for (size_t i = 0; i < newSize; i++)
- newBuffer[i] = src[i];
- }
- }
- */
- /*
- CObjArray2(size_t size): _items(0), _size(0)
- {
- if (size != 0)
- {
- _items = new T[size];
- _size = size;
- }
- }
- */
-
- ~CObjArray2() { delete []_items; }
-
- operator T *() { return _items; }
- operator const T *() const { return _items; }
-
- unsigned Size() const { return (unsigned)_size; }
- bool IsEmpty() const { return _size == 0; }
-
- // SetSize doesn't keep old items. It allocates new array if size is not equal
- void SetSize(unsigned size)
- {
- if (size == _size)
- return;
- T *newBuffer = NULL;
- if (size != 0)
- {
- MY_ARRAY_NEW(newBuffer, T, size)
- // newBuffer = new T[size];
- }
- delete []_items;
- _items = newBuffer;
- _size = size;
- }
-
- /*
- CObjArray2& operator=(const CObjArray2 &buffer)
- {
- Free();
- size_t newSize = buffer._size;
- if (newSize != 0)
- {
- T *newBuffer = new T[newSize];;
- _items = newBuffer;
- _size = newSize;
- const T *src = buffer;
- for (size_t i = 0; i < newSize; i++)
- newBuffer[i] = src[i];
- }
- return *this;
- }
- */
-};
-
-#endif
+// Common/MyBuffer.h
+
+#ifndef ZIP7_INC_COMMON_MY_BUFFER_H
+#define ZIP7_INC_COMMON_MY_BUFFER_H
+
+#include <string.h>
+
+#include "Defs.h"
+#include "MyTypes.h"
+
+/* 7-Zip now uses CBuffer only as CByteBuffer.
+ So there is no need to use Z7_ARRAY_NEW macro in CBuffer code. */
+
+template <class T> class CBuffer
+{
+ T *_items;
+ size_t _size;
+
+public:
+ void Free()
+ {
+ if (_items)
+ {
+ delete []_items;
+ _items = NULL;
+ }
+ _size = 0;
+ }
+
+ CBuffer(): _items(NULL), _size(0) {}
+ CBuffer(size_t size): _items(NULL), _size(0)
+ {
+ if (size != 0)
+ {
+ _items = new T[size];
+ _size = size;
+ }
+ }
+ CBuffer(const CBuffer &buffer): _items(NULL), _size(0)
+ {
+ const size_t size = buffer._size;
+ if (size != 0)
+ {
+ _items = new T[size];
+ memcpy(_items, buffer._items, size * sizeof(T));
+ _size = size;
+ }
+ }
+
+ ~CBuffer() { delete []_items; }
+
+ operator T *() { return _items; }
+ operator const T *() const { return _items; }
+ size_t Size() const { return _size; }
+
+ void Alloc(size_t size)
+ {
+ if (size != _size)
+ {
+ Free();
+ if (size != 0)
+ {
+ _items = new T[size];
+ _size = size;
+ }
+ }
+ }
+
+ void AllocAtLeast(size_t size)
+ {
+ if (size > _size)
+ {
+ Free();
+ _items = new T[size];
+ _size = size;
+ }
+ }
+
+ void CopyFrom(const T *data, size_t size)
+ {
+ Alloc(size);
+ if (size != 0)
+ memcpy(_items, data, size * sizeof(T));
+ }
+
+ void ChangeSize_KeepData(size_t newSize, size_t keepSize)
+ {
+ if (newSize == _size)
+ return;
+ T *newBuffer = NULL;
+ if (newSize != 0)
+ {
+ newBuffer = new T[newSize];
+ if (keepSize > _size)
+ keepSize = _size;
+ if (keepSize != 0)
+ memcpy(newBuffer, _items, MyMin(keepSize, newSize) * sizeof(T));
+ }
+ delete []_items;
+ _items = newBuffer;
+ _size = newSize;
+ }
+
+ void Wipe()
+ {
+ if (_size != 0)
+ memset(_items, 0, _size * sizeof(T));
+ }
+
+ CBuffer& operator=(const CBuffer &buffer)
+ {
+ if (&buffer != this)
+ CopyFrom(buffer, buffer._size);
+ return *this;
+ }
+};
+
+template <class T>
+bool operator==(const CBuffer<T>& b1, const CBuffer<T>& b2)
+{
+ size_t size1 = b1.Size();
+ if (size1 != b2.Size())
+ return false;
+ if (size1 == 0)
+ return true;
+ return memcmp(b1, b2, size1 * sizeof(T)) == 0;
+}
+
+template <class T>
+bool operator!=(const CBuffer<T>& b1, const CBuffer<T>& b2)
+{
+ size_t size1 = b1.Size();
+ if (size1 != b2.Size())
+ return true;
+ if (size1 == 0)
+ return false;
+ return memcmp(b1, b2, size1 * sizeof(T)) != 0;
+}
+
+
+// typedef CBuffer<char> CCharBuffer;
+// typedef CBuffer<wchar_t> CWCharBuffer;
+typedef CBuffer<unsigned char> CByteBuffer;
+
+
+class CByteBuffer_Wipe: public CByteBuffer
+{
+ Z7_CLASS_NO_COPY(CByteBuffer_Wipe)
+public:
+ // CByteBuffer_Wipe(): CBuffer<unsigned char>() {}
+ CByteBuffer_Wipe(size_t size): CBuffer<unsigned char>(size) {}
+ ~CByteBuffer_Wipe() { Wipe(); }
+};
+
+
+
+template <class T> class CObjArray
+{
+protected:
+ T *_items;
+private:
+ // we disable copy
+ CObjArray(const CObjArray &buffer);
+ void operator=(const CObjArray &buffer);
+public:
+ void Free()
+ {
+ delete []_items;
+ _items = NULL;
+ }
+ CObjArray(size_t size): _items(NULL)
+ {
+ if (size != 0)
+ {
+ Z7_ARRAY_NEW(_items, T, size)
+ // _items = new T[size];
+ }
+ }
+ CObjArray(): _items(NULL) {}
+ ~CObjArray() { delete []_items; }
+
+ operator T *() { return _items; }
+ operator const T *() const { return _items; }
+
+ void Alloc(size_t newSize)
+ {
+ delete []_items;
+ _items = NULL;
+ Z7_ARRAY_NEW(_items, T, newSize)
+ // _items = new T[newSize];
+ }
+};
+
+typedef CObjArray<unsigned char> CByteArr;
+typedef CObjArray<bool> CBoolArr;
+typedef CObjArray<int> CIntArr;
+typedef CObjArray<unsigned> CUIntArr;
+
+
+template <class T> class CObjArray2
+{
+ T *_items;
+ unsigned _size;
+
+ // we disable copy
+ CObjArray2(const CObjArray2 &buffer);
+ void operator=(const CObjArray2 &buffer);
+public:
+
+ void Free()
+ {
+ delete []_items;
+ _items = NULL;
+ _size = 0;
+ }
+ CObjArray2(): _items(NULL), _size(0) {}
+ /*
+ CObjArray2(const CObjArray2 &buffer): _items(NULL), _size(0)
+ {
+ size_t newSize = buffer._size;
+ if (newSize != 0)
+ {
+ T *newBuffer = new T[newSize];;
+ _items = newBuffer;
+ _size = newSize;
+ const T *src = buffer;
+ for (size_t i = 0; i < newSize; i++)
+ newBuffer[i] = src[i];
+ }
+ }
+ */
+ /*
+ CObjArray2(size_t size): _items(NULL), _size(0)
+ {
+ if (size != 0)
+ {
+ _items = new T[size];
+ _size = size;
+ }
+ }
+ */
+
+ ~CObjArray2() { delete []_items; }
+
+ operator T *() { return _items; }
+ operator const T *() const { return _items; }
+
+ unsigned Size() const { return (unsigned)_size; }
+ bool IsEmpty() const { return _size == 0; }
+
+ // SetSize doesn't keep old items. It allocates new array if size is not equal
+ void SetSize(unsigned size)
+ {
+ if (size == _size)
+ return;
+ T *newBuffer = NULL;
+ if (size != 0)
+ {
+ Z7_ARRAY_NEW(newBuffer, T, size)
+ // newBuffer = new T[size];
+ }
+ delete []_items;
+ _items = newBuffer;
+ _size = size;
+ }
+
+ /*
+ CObjArray2& operator=(const CObjArray2 &buffer)
+ {
+ Free();
+ size_t newSize = buffer._size;
+ if (newSize != 0)
+ {
+ T *newBuffer = new T[newSize];;
+ _items = newBuffer;
+ _size = newSize;
+ const T *src = buffer;
+ for (size_t i = 0; i < newSize; i++)
+ newBuffer[i] = src[i];
+ }
+ return *this;
+ }
+ */
+};
+
+#endif
diff --git a/CPP/Common/MyBuffer2.h b/CPP/Common/MyBuffer2.h
index 10edcb1..23394f8 100644
--- a/CPP/Common/MyBuffer2.h
+++ b/CPP/Common/MyBuffer2.h
@@ -1,100 +1,164 @@
-// Common/MyBuffer2.h
-
-#ifndef __COMMON_MY_BUFFER2_H
-#define __COMMON_MY_BUFFER2_H
-
-#include "../../C/Alloc.h"
-
-#include "MyTypes.h"
-
-class CMidBuffer
-{
- Byte *_data;
- size_t _size;
-
- CLASS_NO_COPY(CMidBuffer)
-
-public:
- CMidBuffer(): _data(NULL), _size(0) {}
- ~CMidBuffer() { ::MidFree(_data); }
-
- void Free() { ::MidFree(_data); _data = NULL; _size = 0; }
-
- bool IsAllocated() const { return _data != NULL; }
- operator Byte *() { return _data; }
- operator const Byte *() const { return _data; }
- size_t Size() const { return _size; }
-
- void AllocAtLeast(size_t size)
- {
- if (!_data || size > _size)
- {
- ::MidFree(_data);
- const size_t kMinSize = (size_t)1 << 16;
- if (size < kMinSize)
- size = kMinSize;
- _size = 0;
- _data = NULL;
- _data = (Byte *)::MidAlloc(size);
- if (_data)
- _size = size;
- }
- }
-};
-
-
-class CAlignedBuffer
-{
- Byte *_data;
- size_t _size;
-
- CLASS_NO_COPY(CAlignedBuffer)
-
-public:
- CAlignedBuffer(): _data(NULL), _size(0) {}
- ~CAlignedBuffer()
- {
- ISzAlloc_Free(&g_AlignedAlloc, _data);
- }
-
- void Free()
- {
- ISzAlloc_Free(&g_AlignedAlloc, _data);
- _data = NULL;
- _size = 0;
- }
-
- bool IsAllocated() const { return _data != NULL; }
- operator Byte *() { return _data; }
- operator const Byte *() const { return _data; }
- size_t Size() const { return _size; }
-
- void Alloc(size_t size)
- {
- if (!_data || size != _size)
- {
- ISzAlloc_Free(&g_AlignedAlloc, _data);
- _size = 0;
- _data = NULL;
- _data = (Byte *)ISzAlloc_Alloc(&g_AlignedAlloc, size);
- if (_data)
- _size = size;
- }
- }
-
- void AllocAtLeast(size_t size)
- {
- if (!_data || size > _size)
- {
- ISzAlloc_Free(&g_AlignedAlloc, _data);
- _size = 0;
- _data = NULL;
- _data = (Byte *)ISzAlloc_Alloc(&g_AlignedAlloc, size);
- if (_data)
- _size = size;
- }
- }
-};
-
-
-#endif
+// Common/MyBuffer2.h
+
+#ifndef ZIP7_INC_COMMON_MY_BUFFER2_H
+#define ZIP7_INC_COMMON_MY_BUFFER2_H
+
+#include "../../C/Alloc.h"
+
+#include "MyTypes.h"
+
+class CMidBuffer
+{
+ Byte *_data;
+ size_t _size;
+
+ Z7_CLASS_NO_COPY(CMidBuffer)
+
+public:
+ CMidBuffer(): _data(NULL), _size(0) {}
+ ~CMidBuffer() { ::MidFree(_data); }
+
+ void Free() { ::MidFree(_data); _data = NULL; _size = 0; }
+
+ bool IsAllocated() const { return _data != NULL; }
+ operator Byte *() { return _data; }
+ operator const Byte *() const { return _data; }
+ size_t Size() const { return _size; }
+
+ void Alloc(size_t size)
+ {
+ if (!_data || size != _size)
+ {
+ ::MidFree(_data);
+ _size = 0;
+ _data = NULL;
+ _data = (Byte *)::MidAlloc(size);
+ if (_data)
+ _size = size;
+ }
+ }
+
+ void AllocAtLeast(size_t size)
+ {
+ if (!_data || size > _size)
+ {
+ ::MidFree(_data);
+ const size_t kMinSize = (size_t)1 << 16;
+ if (size < kMinSize)
+ size = kMinSize;
+ _size = 0;
+ _data = NULL;
+ _data = (Byte *)::MidAlloc(size);
+ if (_data)
+ _size = size;
+ }
+ }
+};
+
+
+class CAlignedBuffer1
+{
+ Byte *_data;
+
+ Z7_CLASS_NO_COPY(CAlignedBuffer1)
+
+public:
+ ~CAlignedBuffer1()
+ {
+ ISzAlloc_Free(&g_AlignedAlloc, _data);
+ }
+
+ CAlignedBuffer1(size_t size)
+ {
+ _data = NULL;
+ _data = (Byte *)ISzAlloc_Alloc(&g_AlignedAlloc, size);
+ if (!_data)
+ throw 1;
+ }
+
+ operator Byte *() { return _data; }
+ operator const Byte *() const { return _data; }
+};
+
+
+class CAlignedBuffer
+{
+ Byte *_data;
+ size_t _size;
+
+ Z7_CLASS_NO_COPY(CAlignedBuffer)
+
+public:
+ CAlignedBuffer(): _data(NULL), _size(0) {}
+ ~CAlignedBuffer()
+ {
+ ISzAlloc_Free(&g_AlignedAlloc, _data);
+ }
+
+ CAlignedBuffer(size_t size): _size(0)
+ {
+ _data = NULL;
+ _data = (Byte *)ISzAlloc_Alloc(&g_AlignedAlloc, size);
+ if (!_data)
+ throw 1;
+ _size = size;
+ }
+
+ void Free()
+ {
+ ISzAlloc_Free(&g_AlignedAlloc, _data);
+ _data = NULL;
+ _size = 0;
+ }
+
+ bool IsAllocated() const { return _data != NULL; }
+ operator Byte *() { return _data; }
+ operator const Byte *() const { return _data; }
+ size_t Size() const { return _size; }
+
+ void Alloc(size_t size)
+ {
+ if (!_data || size != _size)
+ {
+ ISzAlloc_Free(&g_AlignedAlloc, _data);
+ _size = 0;
+ _data = NULL;
+ _data = (Byte *)ISzAlloc_Alloc(&g_AlignedAlloc, size);
+ if (_data)
+ _size = size;
+ }
+ }
+
+ void AllocAtLeast(size_t size)
+ {
+ if (!_data || size > _size)
+ {
+ ISzAlloc_Free(&g_AlignedAlloc, _data);
+ _size = 0;
+ _data = NULL;
+ _data = (Byte *)ISzAlloc_Alloc(&g_AlignedAlloc, size);
+ if (_data)
+ _size = size;
+ }
+ }
+};
+
+/*
+ CMidAlignedBuffer must return aligned pointer.
+ - in Windows it uses CMidBuffer(): MidAlloc() : VirtualAlloc()
+ VirtualAlloc(): Memory allocated is automatically initialized to zero.
+ MidAlloc(0) returns NULL
+ - in non-Windows systems it uses g_AlignedAlloc.
+ g_AlignedAlloc::Alloc(size = 0) can return non NULL.
+*/
+
+typedef
+#ifdef _WIN32
+ CMidBuffer
+#else
+ CAlignedBuffer
+#endif
+ CMidAlignedBuffer;
+
+
+#endif
diff --git a/CPP/Common/MyCom.h b/CPP/Common/MyCom.h
index ca49ead..65c4330 100644
--- a/CPP/Common/MyCom.h
+++ b/CPP/Common/MyCom.h
@@ -1,277 +1,509 @@
-// MyCom.h
-
-#ifndef __MY_COM_H
-#define __MY_COM_H
-
-#include "MyWindows.h"
-
-#ifndef RINOK
-#define RINOK(x) { HRESULT __result_ = (x); if (__result_ != S_OK) return __result_; }
-#endif
-
-template <class T>
-class CMyComPtr
-{
- T* _p;
-public:
- CMyComPtr(): _p(NULL) {}
- CMyComPtr(T* p) throw() { if ((_p = p) != NULL) p->AddRef(); }
- CMyComPtr(const CMyComPtr<T>& lp) throw() { if ((_p = lp._p) != NULL) _p->AddRef(); }
- ~CMyComPtr() { if (_p) _p->Release(); }
- void Release() { if (_p) { _p->Release(); _p = NULL; } }
- operator T*() const { return (T*)_p; }
- // T& operator*() const { return *_p; }
- T** operator&() { return &_p; }
- T* operator->() const { return _p; }
- T* operator=(T* p)
- {
- if (p)
- p->AddRef();
- if (_p)
- _p->Release();
- _p = p;
- return p;
- }
- T* operator=(const CMyComPtr<T>& lp) { return (*this = lp._p); }
- bool operator!() const { return (_p == NULL); }
- // bool operator==(T* pT) const { return _p == pT; }
- void Attach(T* p2)
- {
- Release();
- _p = p2;
- }
- T* Detach()
- {
- T* pt = _p;
- _p = NULL;
- return pt;
- }
- #ifdef _WIN32
- HRESULT CoCreateInstance(REFCLSID rclsid, REFIID iid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL)
- {
- return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, (void**)&_p);
- }
- #endif
- /*
- HRESULT CoCreateInstance(LPCOLESTR szProgID, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL)
- {
- CLSID clsid;
- HRESULT hr = CLSIDFromProgID(szProgID, &clsid);
- ATLASSERT(_p == NULL);
- if (SUCCEEDED(hr))
- hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&_p);
- return hr;
- }
- */
- template <class Q>
- HRESULT QueryInterface(REFGUID iid, Q** pp) const throw()
- {
- return _p->QueryInterface(iid, (void**)pp);
- }
-};
-
-//////////////////////////////////////////////////////////
-
-inline HRESULT StringToBstr(LPCOLESTR src, BSTR *bstr)
-{
- *bstr = ::SysAllocString(src);
- return (*bstr) ? S_OK : E_OUTOFMEMORY;
-}
-
-class CMyComBSTR
-{
- BSTR m_str;
-
-public:
- CMyComBSTR(): m_str(NULL) {}
- ~CMyComBSTR() { ::SysFreeString(m_str); }
- BSTR* operator&() { return &m_str; }
- operator LPCOLESTR() const { return m_str; }
- // operator bool() const { return m_str != NULL; }
- // bool operator!() const { return m_str == NULL; }
-private:
- // operator BSTR() const { return m_str; }
-
- CMyComBSTR(LPCOLESTR src) { m_str = ::SysAllocString(src); }
- // CMyComBSTR(int nSize) { m_str = ::SysAllocStringLen(NULL, nSize); }
- // CMyComBSTR(int nSize, LPCOLESTR sz) { m_str = ::SysAllocStringLen(sz, nSize); }
- CMyComBSTR(const CMyComBSTR& src) { m_str = src.MyCopy(); }
-
- /*
- CMyComBSTR(REFGUID src)
- {
- LPOLESTR szGuid;
- StringFromCLSID(src, &szGuid);
- m_str = ::SysAllocString(szGuid);
- CoTaskMemFree(szGuid);
- }
- */
-
- CMyComBSTR& operator=(const CMyComBSTR& src)
- {
- if (m_str != src.m_str)
- {
- if (m_str)
- ::SysFreeString(m_str);
- m_str = src.MyCopy();
- }
- return *this;
- }
-
- CMyComBSTR& operator=(LPCOLESTR src)
- {
- ::SysFreeString(m_str);
- m_str = ::SysAllocString(src);
- return *this;
- }
-
- unsigned Len() const { return ::SysStringLen(m_str); }
-
- BSTR MyCopy() const
- {
- // We don't support Byte BSTRs here
- return ::SysAllocStringLen(m_str, ::SysStringLen(m_str));
- /*
- UINT byteLen = ::SysStringByteLen(m_str);
- BSTR res = ::SysAllocStringByteLen(NULL, byteLen);
- if (res && byteLen != 0 && m_str)
- memcpy(res, m_str, byteLen);
- return res;
- */
- }
-
- /*
- void Attach(BSTR src) { m_str = src; }
- BSTR Detach()
- {
- BSTR s = m_str;
- m_str = NULL;
- return s;
- }
- */
-
- void Empty()
- {
- ::SysFreeString(m_str);
- m_str = NULL;
- }
-};
-
-
-
-/*
- If CMyUnknownImp doesn't use virtual destructor, the code size is smaller.
- But if some class_1 derived from CMyUnknownImp
- uses MY_ADDREF_RELEASE and IUnknown::Release()
- and some another class_2 is derived from class_1,
- then class_1 must use virtual destructor:
- virtual ~class_1();
- In that case, class_1::Release() calls correct destructor of class_2.
-
- Also you can use virtual ~CMyUnknownImp(), if you want to disable warning
- "class has virtual functions, but destructor is not virtual".
-*/
-
-class CMyUnknownImp
-{
-public:
- ULONG __m_RefCount;
- CMyUnknownImp(): __m_RefCount(0) {}
-
- // virtual
- ~CMyUnknownImp() {}
-};
-
-
-
-#define MY_QUERYINTERFACE_BEGIN STDMETHOD(QueryInterface) \
-(REFGUID iid, void **outObject) throw() { *outObject = NULL;
-
-#define MY_QUERYINTERFACE_ENTRY(i) else if (iid == IID_ ## i) \
- { *outObject = (void *)(i *)this; }
-
-#define MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) if (iid == IID_IUnknown) \
- { *outObject = (void *)(IUnknown *)(i *)this; }
-
-#define MY_QUERYINTERFACE_BEGIN2(i) MY_QUERYINTERFACE_BEGIN \
- MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) \
- MY_QUERYINTERFACE_ENTRY(i)
-
-#define MY_QUERYINTERFACE_END else return E_NOINTERFACE; ++__m_RefCount; /* AddRef(); */ return S_OK; }
-
-#define MY_ADDREF_RELEASE \
-STDMETHOD_(ULONG, AddRef)() throw() { return ++__m_RefCount; } \
-STDMETHOD_(ULONG, Release)() { if (--__m_RefCount != 0) \
- return __m_RefCount; delete this; return 0; }
-
-#define MY_UNKNOWN_IMP_SPEC(i) \
- MY_QUERYINTERFACE_BEGIN \
- i \
- MY_QUERYINTERFACE_END \
- MY_ADDREF_RELEASE
-
-
-#define MY_UNKNOWN_IMP MY_QUERYINTERFACE_BEGIN \
- MY_QUERYINTERFACE_ENTRY_UNKNOWN(IUnknown) \
- MY_QUERYINTERFACE_END \
- MY_ADDREF_RELEASE
-
-#define MY_UNKNOWN_IMP1(i) MY_UNKNOWN_IMP_SPEC( \
- MY_QUERYINTERFACE_ENTRY_UNKNOWN(i) \
- MY_QUERYINTERFACE_ENTRY(i) \
- )
-
-#define MY_UNKNOWN_IMP2(i1, i2) MY_UNKNOWN_IMP_SPEC( \
- MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \
- MY_QUERYINTERFACE_ENTRY(i1) \
- MY_QUERYINTERFACE_ENTRY(i2) \
- )
-
-#define MY_UNKNOWN_IMP3(i1, i2, i3) MY_UNKNOWN_IMP_SPEC( \
- MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \
- MY_QUERYINTERFACE_ENTRY(i1) \
- MY_QUERYINTERFACE_ENTRY(i2) \
- MY_QUERYINTERFACE_ENTRY(i3) \
- )
-
-#define MY_UNKNOWN_IMP4(i1, i2, i3, i4) MY_UNKNOWN_IMP_SPEC( \
- MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \
- MY_QUERYINTERFACE_ENTRY(i1) \
- MY_QUERYINTERFACE_ENTRY(i2) \
- MY_QUERYINTERFACE_ENTRY(i3) \
- MY_QUERYINTERFACE_ENTRY(i4) \
- )
-
-#define MY_UNKNOWN_IMP5(i1, i2, i3, i4, i5) MY_UNKNOWN_IMP_SPEC( \
- MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \
- MY_QUERYINTERFACE_ENTRY(i1) \
- MY_QUERYINTERFACE_ENTRY(i2) \
- MY_QUERYINTERFACE_ENTRY(i3) \
- MY_QUERYINTERFACE_ENTRY(i4) \
- MY_QUERYINTERFACE_ENTRY(i5) \
- )
-
-#define MY_UNKNOWN_IMP6(i1, i2, i3, i4, i5, i6) MY_UNKNOWN_IMP_SPEC( \
- MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \
- MY_QUERYINTERFACE_ENTRY(i1) \
- MY_QUERYINTERFACE_ENTRY(i2) \
- MY_QUERYINTERFACE_ENTRY(i3) \
- MY_QUERYINTERFACE_ENTRY(i4) \
- MY_QUERYINTERFACE_ENTRY(i5) \
- MY_QUERYINTERFACE_ENTRY(i6) \
- )
-
-#define MY_UNKNOWN_IMP7(i1, i2, i3, i4, i5, i6, i7) MY_UNKNOWN_IMP_SPEC( \
- MY_QUERYINTERFACE_ENTRY_UNKNOWN(i1) \
- MY_QUERYINTERFACE_ENTRY(i1) \
- MY_QUERYINTERFACE_ENTRY(i2) \
- MY_QUERYINTERFACE_ENTRY(i3) \
- MY_QUERYINTERFACE_ENTRY(i4) \
- MY_QUERYINTERFACE_ENTRY(i5) \
- MY_QUERYINTERFACE_ENTRY(i6) \
- MY_QUERYINTERFACE_ENTRY(i7) \
- )
-
-const HRESULT k_My_HRESULT_WritingWasCut = 0x20000010;
-
-#endif
+// MyCom.h
+
+#ifndef ZIP7_INC_MY_COM_H
+#define ZIP7_INC_MY_COM_H
+
+#include "MyWindows.h"
+#include "MyTypes.h"
+
+template <class T>
+class CMyComPtr
+{
+ T* _p;
+public:
+ CMyComPtr(): _p(NULL) {}
+ CMyComPtr(T* p) throw() { if ((_p = p) != NULL) p->AddRef(); }
+ CMyComPtr(const CMyComPtr<T>& lp) throw() { if ((_p = lp._p) != NULL) _p->AddRef(); }
+ ~CMyComPtr() { if (_p) _p->Release(); }
+ void Release() { if (_p) { _p->Release(); _p = NULL; } }
+ operator T*() const { return (T*)_p; }
+ // T& operator*() const { return *_p; }
+ T** operator&() { return &_p; }
+ T* operator->() const { return _p; }
+ T* operator=(T* p)
+ {
+ if (p)
+ p->AddRef();
+ if (_p)
+ _p->Release();
+ _p = p;
+ return p;
+ }
+ T* operator=(const CMyComPtr<T>& lp) { return (*this = lp._p); }
+ bool operator!() const { return (_p == NULL); }
+ // bool operator==(T* pT) const { return _p == pT; }
+ void Attach(T* p2)
+ {
+ Release();
+ _p = p2;
+ }
+ T* Detach()
+ {
+ T* pt = _p;
+ _p = NULL;
+ return pt;
+ }
+ #ifdef _WIN32
+ HRESULT CoCreateInstance(REFCLSID rclsid, REFIID iid, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL)
+ {
+ return ::CoCreateInstance(rclsid, pUnkOuter, dwClsContext, iid, (void**)&_p);
+ }
+ #endif
+ /*
+ HRESULT CoCreateInstance(LPCOLESTR szProgID, LPUNKNOWN pUnkOuter = NULL, DWORD dwClsContext = CLSCTX_ALL)
+ {
+ CLSID clsid;
+ HRESULT hr = CLSIDFromProgID(szProgID, &clsid);
+ ATLASSERT(_p == NULL);
+ if (SUCCEEDED(hr))
+ hr = ::CoCreateInstance(clsid, pUnkOuter, dwClsContext, __uuidof(T), (void**)&_p);
+ return hr;
+ }
+ */
+ template <class Q>
+ HRESULT QueryInterface(REFGUID iid, Q** pp) const throw()
+ {
+ // if (*pp) throw 20220216; // for debug
+ return _p->QueryInterface(iid, (void**)pp);
+ }
+};
+
+#define Z7_DECL_CMyComPtr_QI_FROM(i, v, unk) \
+ CMyComPtr<i> v; (unk)->QueryInterface(IID_ ## i, (void **)&v);
+
+
+//////////////////////////////////////////////////////////
+
+inline HRESULT StringToBstr(LPCOLESTR src, BSTR *bstr)
+{
+ *bstr = ::SysAllocString(src);
+ return (*bstr) ? S_OK : E_OUTOFMEMORY;
+}
+
+class CMyComBSTR
+{
+ BSTR m_str;
+ Z7_CLASS_NO_COPY(CMyComBSTR)
+public:
+ CMyComBSTR(): m_str(NULL) {}
+ ~CMyComBSTR() { ::SysFreeString(m_str); }
+ BSTR* operator&() { return &m_str; }
+ operator LPCOLESTR() const { return m_str; }
+ // operator bool() const { return m_str != NULL; }
+ // bool operator!() const { return m_str == NULL; }
+
+ void Wipe_and_Free()
+ {
+ if (m_str)
+ {
+ memset(m_str, 0, ::SysStringLen(m_str) * sizeof(*m_str));
+ Empty();
+ }
+ }
+
+private:
+ // operator BSTR() const { return m_str; }
+
+ CMyComBSTR(LPCOLESTR src) { m_str = ::SysAllocString(src); }
+ // CMyComBSTR(int nSize) { m_str = ::SysAllocStringLen(NULL, nSize); }
+ // CMyComBSTR(int nSize, LPCOLESTR sz) { m_str = ::SysAllocStringLen(sz, nSize); }
+ // CMyComBSTR(const CMyComBSTR& src) { m_str = src.MyCopy(); }
+
+ /*
+ CMyComBSTR(REFGUID src)
+ {
+ LPOLESTR szGuid;
+ StringFromCLSID(src, &szGuid);
+ m_str = ::SysAllocString(szGuid);
+ CoTaskMemFree(szGuid);
+ }
+ */
+
+ /*
+ CMyComBSTR& operator=(const CMyComBSTR& src)
+ {
+ if (m_str != src.m_str)
+ {
+ if (m_str)
+ ::SysFreeString(m_str);
+ m_str = src.MyCopy();
+ }
+ return *this;
+ }
+ */
+
+ CMyComBSTR& operator=(LPCOLESTR src)
+ {
+ ::SysFreeString(m_str);
+ m_str = ::SysAllocString(src);
+ return *this;
+ }
+
+ unsigned Len() const { return ::SysStringLen(m_str); }
+
+ BSTR MyCopy() const
+ {
+ // We don't support Byte BSTRs here
+ return ::SysAllocStringLen(m_str, ::SysStringLen(m_str));
+ /*
+ UINT byteLen = ::SysStringByteLen(m_str);
+ BSTR res = ::SysAllocStringByteLen(NULL, byteLen);
+ if (res && byteLen != 0 && m_str)
+ memcpy(res, m_str, byteLen);
+ return res;
+ */
+ }
+
+ /*
+ void Attach(BSTR src) { m_str = src; }
+ BSTR Detach()
+ {
+ BSTR s = m_str;
+ m_str = NULL;
+ return s;
+ }
+ */
+
+ void Empty()
+ {
+ ::SysFreeString(m_str);
+ m_str = NULL;
+ }
+};
+
+
+class CMyComBSTR_Wipe: public CMyComBSTR
+{
+ Z7_CLASS_NO_COPY(CMyComBSTR_Wipe)
+public:
+ CMyComBSTR_Wipe(): CMyComBSTR() {}
+ ~CMyComBSTR_Wipe() { Wipe_and_Free(); }
+};
+
+
+
+/*
+ If CMyUnknownImp doesn't use virtual destructor, the code size is smaller.
+ But if some class_1 derived from CMyUnknownImp
+ uses Z7_COM_ADDREF_RELEASE and IUnknown::Release()
+ and some another class_2 is derived from class_1,
+ then class_1 must use virtual destructor:
+ virtual ~class_1();
+ In that case, class_1::Release() calls correct destructor of class_2.
+ We can use virtual ~CMyUnknownImp() to disable warning
+ "class has virtual functions, but destructor is not virtual".
+ Also we can use virtual ~IUnknown() {} in MyWindows.h
+*/
+
+class CMyUnknownImp
+{
+ Z7_CLASS_NO_COPY(CMyUnknownImp)
+protected:
+ ULONG _m_RefCount;
+ CMyUnknownImp(): _m_RefCount(0) {}
+
+ #ifdef _WIN32
+ #if defined(__GNUC__) || defined(__clang__)
+ // virtual ~CMyUnknownImp() {} // to disable GCC/CLANG varnings
+ #endif
+ #endif
+};
+
+
+
+#define Z7_COM_QI_BEGIN \
+ private: STDMETHOD(QueryInterface) (REFGUID iid, void **outObject) throw() Z7_override Z7_final \
+ { *outObject = NULL;
+
+#define Z7_COM_QI_ENTRY(i) \
+ else if (iid == IID_ ## i) \
+ { i *ti = this; *outObject = ti; }
+// { *outObject = (void *)(i *)this; }
+
+#define Z7_COM_QI_ENTRY_UNKNOWN_0 \
+ if (iid == IID_IUnknown) \
+ { IUnknown *tu = this; *outObject = tu; }
+
+#define Z7_COM_QI_ENTRY_UNKNOWN(i) \
+ if (iid == IID_IUnknown) \
+ { i *ti = this; IUnknown *tu = ti; *outObject = tu; }
+// { *outObject = (void *)(IUnknown *)(i *)this; }
+
+#define Z7_COM_QI_BEGIN2(i) \
+ Z7_COM_QI_BEGIN \
+ Z7_COM_QI_ENTRY_UNKNOWN(i) \
+ Z7_COM_QI_ENTRY(i)
+
+#define Z7_COM_QI_END \
+ else return E_NOINTERFACE; \
+ ++_m_RefCount; /* AddRef(); */ return S_OK; }
+
+#define Z7_COM_ADDREF_RELEASE \
+ private: \
+ STDMETHOD_(ULONG, AddRef)() throw() Z7_override Z7_final \
+ { return ++_m_RefCount; } \
+ STDMETHOD_(ULONG, Release)() throw() Z7_override Z7_final \
+ { if (--_m_RefCount != 0) return _m_RefCount; delete this; return 0; } \
+
+#define Z7_COM_UNKNOWN_IMP_SPEC(i) \
+ Z7_COM_QI_BEGIN \
+ i \
+ Z7_COM_QI_END \
+ Z7_COM_ADDREF_RELEASE
+
+
+#define Z7_COM_UNKNOWN_IMP_0 \
+ Z7_COM_QI_BEGIN \
+ Z7_COM_QI_ENTRY_UNKNOWN_0 \
+ Z7_COM_QI_END \
+ Z7_COM_ADDREF_RELEASE
+
+#define Z7_COM_UNKNOWN_IMP_1(i) \
+ Z7_COM_UNKNOWN_IMP_SPEC( \
+ Z7_COM_QI_ENTRY_UNKNOWN(i) \
+ Z7_COM_QI_ENTRY(i) \
+ )
+
+#define Z7_COM_UNKNOWN_IMP_2(i1, i2) \
+ Z7_COM_UNKNOWN_IMP_SPEC( \
+ Z7_COM_QI_ENTRY_UNKNOWN(i1) \
+ Z7_COM_QI_ENTRY(i1) \
+ Z7_COM_QI_ENTRY(i2) \
+ )
+
+#define Z7_COM_UNKNOWN_IMP_3(i1, i2, i3) \
+ Z7_COM_UNKNOWN_IMP_SPEC( \
+ Z7_COM_QI_ENTRY_UNKNOWN(i1) \
+ Z7_COM_QI_ENTRY(i1) \
+ Z7_COM_QI_ENTRY(i2) \
+ Z7_COM_QI_ENTRY(i3) \
+ )
+
+#define Z7_COM_UNKNOWN_IMP_4(i1, i2, i3, i4) \
+ Z7_COM_UNKNOWN_IMP_SPEC( \
+ Z7_COM_QI_ENTRY_UNKNOWN(i1) \
+ Z7_COM_QI_ENTRY(i1) \
+ Z7_COM_QI_ENTRY(i2) \
+ Z7_COM_QI_ENTRY(i3) \
+ Z7_COM_QI_ENTRY(i4) \
+ )
+
+#define Z7_COM_UNKNOWN_IMP_5(i1, i2, i3, i4, i5) \
+ Z7_COM_UNKNOWN_IMP_SPEC( \
+ Z7_COM_QI_ENTRY_UNKNOWN(i1) \
+ Z7_COM_QI_ENTRY(i1) \
+ Z7_COM_QI_ENTRY(i2) \
+ Z7_COM_QI_ENTRY(i3) \
+ Z7_COM_QI_ENTRY(i4) \
+ Z7_COM_QI_ENTRY(i5) \
+ )
+
+#define Z7_COM_UNKNOWN_IMP_6(i1, i2, i3, i4, i5, i6) \
+ Z7_COM_UNKNOWN_IMP_SPEC( \
+ Z7_COM_QI_ENTRY_UNKNOWN(i1) \
+ Z7_COM_QI_ENTRY(i1) \
+ Z7_COM_QI_ENTRY(i2) \
+ Z7_COM_QI_ENTRY(i3) \
+ Z7_COM_QI_ENTRY(i4) \
+ Z7_COM_QI_ENTRY(i5) \
+ Z7_COM_QI_ENTRY(i6) \
+ )
+
+#define Z7_COM_UNKNOWN_IMP_7(i1, i2, i3, i4, i5, i6, i7) \
+ Z7_COM_UNKNOWN_IMP_SPEC( \
+ Z7_COM_QI_ENTRY_UNKNOWN(i1) \
+ Z7_COM_QI_ENTRY(i1) \
+ Z7_COM_QI_ENTRY(i2) \
+ Z7_COM_QI_ENTRY(i3) \
+ Z7_COM_QI_ENTRY(i4) \
+ Z7_COM_QI_ENTRY(i5) \
+ Z7_COM_QI_ENTRY(i6) \
+ Z7_COM_QI_ENTRY(i7) \
+ )
+
+
+#define Z7_IFACES_IMP_UNK_1(i1) \
+ Z7_COM_UNKNOWN_IMP_1(i1) \
+ Z7_IFACE_COM7_IMP(i1) \
+
+#define Z7_IFACES_IMP_UNK_2(i1, i2) \
+ Z7_COM_UNKNOWN_IMP_2(i1, i2) \
+ Z7_IFACE_COM7_IMP(i1) \
+ Z7_IFACE_COM7_IMP(i2) \
+
+#define Z7_IFACES_IMP_UNK_3(i1, i2, i3) \
+ Z7_COM_UNKNOWN_IMP_3(i1, i2, i3) \
+ Z7_IFACE_COM7_IMP(i1) \
+ Z7_IFACE_COM7_IMP(i2) \
+ Z7_IFACE_COM7_IMP(i3) \
+
+#define Z7_IFACES_IMP_UNK_4(i1, i2, i3, i4) \
+ Z7_COM_UNKNOWN_IMP_4(i1, i2, i3, i4) \
+ Z7_IFACE_COM7_IMP(i1) \
+ Z7_IFACE_COM7_IMP(i2) \
+ Z7_IFACE_COM7_IMP(i3) \
+ Z7_IFACE_COM7_IMP(i4) \
+
+#define Z7_IFACES_IMP_UNK_5(i1, i2, i3, i4, i5) \
+ Z7_COM_UNKNOWN_IMP_5(i1, i2, i3, i4, i5) \
+ Z7_IFACE_COM7_IMP(i1) \
+ Z7_IFACE_COM7_IMP(i2) \
+ Z7_IFACE_COM7_IMP(i3) \
+ Z7_IFACE_COM7_IMP(i4) \
+ Z7_IFACE_COM7_IMP(i5) \
+
+#define Z7_IFACES_IMP_UNK_6(i1, i2, i3, i4, i5, i6) \
+ Z7_COM_UNKNOWN_IMP_6(i1, i2, i3, i4, i5, i6) \
+ Z7_IFACE_COM7_IMP(i1) \
+ Z7_IFACE_COM7_IMP(i2) \
+ Z7_IFACE_COM7_IMP(i3) \
+ Z7_IFACE_COM7_IMP(i4) \
+ Z7_IFACE_COM7_IMP(i5) \
+ Z7_IFACE_COM7_IMP(i6) \
+
+
+#define Z7_CLASS_IMP_COM_0(c) \
+ Z7_class_final(c) : \
+ public IUnknown, \
+ public CMyUnknownImp { \
+ Z7_COM_UNKNOWN_IMP_0 \
+ private:
+
+#define Z7_CLASS_IMP_COM_1(c, i1) \
+ Z7_class_final(c) : \
+ public i1, \
+ public CMyUnknownImp { \
+ Z7_IFACES_IMP_UNK_1(i1) \
+ private:
+
+#define Z7_CLASS_IMP_COM_2(c, i1, i2) \
+ Z7_class_final(c) : \
+ public i1, \
+ public i2, \
+ public CMyUnknownImp { \
+ Z7_IFACES_IMP_UNK_2(i1, i2) \
+ private:
+
+#define Z7_CLASS_IMP_COM_3(c, i1, i2, i3) \
+ Z7_class_final(c) : \
+ public i1, \
+ public i2, \
+ public i3, \
+ public CMyUnknownImp { \
+ Z7_IFACES_IMP_UNK_3(i1, i2, i3) \
+ private:
+
+#define Z7_CLASS_IMP_COM_4(c, i1, i2, i3, i4) \
+ Z7_class_final(c) : \
+ public i1, \
+ public i2, \
+ public i3, \
+ public i4, \
+ public CMyUnknownImp { \
+ Z7_IFACES_IMP_UNK_4(i1, i2, i3, i4) \
+ private:
+
+#define Z7_CLASS_IMP_COM_5(c, i1, i2, i3, i4, i5) \
+ Z7_class_final(c) : \
+ public i1, \
+ public i2, \
+ public i3, \
+ public i4, \
+ public i5, \
+ public CMyUnknownImp { \
+ Z7_IFACES_IMP_UNK_5(i1, i2, i3, i4, i5) \
+ private:
+
+#define Z7_CLASS_IMP_COM_6(c, i1, i2, i3, i4, i5, i6) \
+ Z7_class_final(c) : \
+ public i1, \
+ public i2, \
+ public i3, \
+ public i4, \
+ public i5, \
+ public i6, \
+ public CMyUnknownImp { \
+ Z7_IFACES_IMP_UNK_6(i1, i2, i3, i4, i5, i6) \
+ private:
+
+
+/*
+#define Z7_CLASS_IMP_NOQIB_0(c) \
+ Z7_class_final(c) : \
+ public IUnknown, \
+ public CMyUnknownImp { \
+ Z7_COM_UNKNOWN_IMP_0 \
+ private:
+*/
+
+#define Z7_CLASS_IMP_NOQIB_1(c, i1) \
+ Z7_class_final(c) : \
+ public i1, \
+ public CMyUnknownImp { \
+ Z7_COM_UNKNOWN_IMP_0 \
+ Z7_IFACE_COM7_IMP(i1) \
+ private:
+
+#define Z7_CLASS_IMP_NOQIB_2(c, i1, i2) \
+ Z7_class_final(c) : \
+ public i1, \
+ public i2, \
+ public CMyUnknownImp { \
+ Z7_COM_UNKNOWN_IMP_1(i2) \
+ Z7_IFACE_COM7_IMP(i1) \
+ Z7_IFACE_COM7_IMP(i2) \
+ private:
+
+#define Z7_CLASS_IMP_NOQIB_3(c, i1, i2, i3) \
+ Z7_class_final(c) : \
+ public i1, \
+ public i2, \
+ public i3, \
+ public CMyUnknownImp { \
+ Z7_COM_UNKNOWN_IMP_2(i2, i3) \
+ Z7_IFACE_COM7_IMP(i1) \
+ Z7_IFACE_COM7_IMP(i2) \
+ Z7_IFACE_COM7_IMP(i3) \
+ private:
+
+#define Z7_CLASS_IMP_NOQIB_4(c, i1, i2, i3, i4) \
+ Z7_class_final(c) : \
+ public i1, \
+ public i2, \
+ public i3, \
+ public i4, \
+ public CMyUnknownImp { \
+ Z7_COM_UNKNOWN_IMP_3(i2, i3, i4) \
+ Z7_IFACE_COM7_IMP(i1) \
+ Z7_IFACE_COM7_IMP(i2) \
+ Z7_IFACE_COM7_IMP(i3) \
+ Z7_IFACE_COM7_IMP(i4) \
+
+/*
+#define Z7_CLASS_IMP_NOQIB_5(c, i1, i2, i3, i4, i5) \
+ Z7_class_final(c) : \
+ public i1, \
+ public i2, \
+ public i3, \
+ public i4, \
+ public i5, \
+ public CMyUnknownImp { \
+ Z7_COM_UNKNOWN_IMP_4(i2, i3, i4, i5) \
+ Z7_IFACE_COM7_IMP(i1) \
+ Z7_IFACE_COM7_IMP(i2) \
+ Z7_IFACE_COM7_IMP(i3) \
+ Z7_IFACE_COM7_IMP(i4) \
+ Z7_IFACE_COM7_IMP(i5) \
+*/
+
+
+#define Z7_CLASS_IMP_IInStream(c) \
+ class c Z7_final : \
+ public IInStream, \
+ public CMyUnknownImp { \
+ Z7_IFACES_IMP_UNK_2(ISequentialInStream, IInStream) \
+
+
+#define k_My_HRESULT_WritingWasCut 0x20000010
+
+#endif
diff --git a/CPP/Common/MyException.h b/CPP/Common/MyException.h
index cd9fe69..06fbdea 100644
--- a/CPP/Common/MyException.h
+++ b/CPP/Common/MyException.h
@@ -1,14 +1,14 @@
-// Common/Exception.h
-
-#ifndef __COMMON_EXCEPTION_H
-#define __COMMON_EXCEPTION_H
-
-#include "MyWindows.h"
-
-struct CSystemException
-{
- HRESULT ErrorCode;
- CSystemException(HRESULT errorCode): ErrorCode(errorCode) {}
-};
-
-#endif
+// Common/Exception.h
+
+#ifndef ZIP7_INC_COMMON_EXCEPTION_H
+#define ZIP7_INC_COMMON_EXCEPTION_H
+
+#include "MyWindows.h"
+
+struct CSystemException
+{
+ HRESULT ErrorCode;
+ CSystemException(HRESULT errorCode): ErrorCode(errorCode) {}
+};
+
+#endif
diff --git a/CPP/Common/MyGuidDef.h b/CPP/Common/MyGuidDef.h
index e0359e2..ab9993b 100644
--- a/CPP/Common/MyGuidDef.h
+++ b/CPP/Common/MyGuidDef.h
@@ -1,54 +1,63 @@
-// Common/MyGuidDef.h
-
-#ifndef GUID_DEFINED
-#define GUID_DEFINED
-
-#include "MyTypes.h"
-
-typedef struct {
- UInt32 Data1;
- UInt16 Data2;
- UInt16 Data3;
- unsigned char Data4[8];
-} GUID;
-
-#ifdef __cplusplus
-#define REFGUID const GUID &
-#else
-#define REFGUID const GUID *
-#endif
-
-#define REFCLSID REFGUID
-#define REFIID REFGUID
-
-#ifdef __cplusplus
-inline int operator==(REFGUID g1, REFGUID g2)
-{
- for (int i = 0; i < (int)sizeof(g1); i++)
- if (((unsigned char *)&g1)[i] != ((unsigned char *)&g2)[i])
- return 0;
- return 1;
-}
-inline int operator!=(REFGUID g1, REFGUID g2) { return !(g1 == g2); }
-#endif
-
-#ifdef __cplusplus
- #define MY_EXTERN_C extern "C"
-#else
- #define MY_EXTERN_C extern
-#endif
-
-#endif
-
-
-#ifdef DEFINE_GUID
-#undef DEFINE_GUID
-#endif
-
-#ifdef INITGUID
- #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
- MY_EXTERN_C const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
-#else
- #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
- MY_EXTERN_C const GUID name
-#endif
+// Common/MyGuidDef.h
+
+// #pragma message "Common/MyGuidDef.h"
+
+#ifndef GUID_DEFINED
+#define GUID_DEFINED
+
+// #pragma message "GUID_DEFINED"
+
+#include "MyTypes.h"
+
+typedef struct {
+ UInt32 Data1;
+ UInt16 Data2;
+ UInt16 Data3;
+ unsigned char Data4[8];
+} GUID;
+
+#ifdef __cplusplus
+#define REFGUID const GUID &
+#else
+#define REFGUID const GUID *
+#endif
+
+// typedef GUID IID;
+typedef GUID CLSID;
+
+#define REFCLSID REFGUID
+#define REFIID REFGUID
+
+#ifdef __cplusplus
+inline int operator==(REFGUID g1, REFGUID g2)
+{
+ for (unsigned i = 0; i < sizeof(g1); i++)
+ if (((const unsigned char *)&g1)[i] != ((const unsigned char *)&g2)[i])
+ return 0;
+ return 1;
+}
+inline int operator!=(REFGUID g1, REFGUID g2) { return !(g1 == g2); }
+#endif
+
+#endif // GUID_DEFINED
+
+#ifndef EXTERN_C
+#ifdef __cplusplus
+ #define EXTERN_C extern "C"
+#else
+ #define EXTERN_C extern
+#endif
+#endif
+
+#ifdef DEFINE_GUID
+#undef DEFINE_GUID
+#endif
+
+#ifdef INITGUID
+ #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ EXTERN_C const GUID name; \
+ EXTERN_C const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
+#else
+ #define DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ EXTERN_C const GUID name
+#endif
diff --git a/CPP/Common/MyInitGuid.h b/CPP/Common/MyInitGuid.h
index 79fea19..3745c79 100644
--- a/CPP/Common/MyInitGuid.h
+++ b/CPP/Common/MyInitGuid.h
@@ -1,45 +1,57 @@
-// Common/MyInitGuid.h
-
-#ifndef __COMMON_MY_INITGUID_H
-#define __COMMON_MY_INITGUID_H
-
-/*
-This file must be included only to one C++ file in project before
-declarations of COM interfaces with DEFINE_GUID macro.
-
-Each GUID must be initialized exactly once in project.
-There are two different versions of the DEFINE_GUID macro in guiddef.h (MyGuidDef.h):
- - if INITGUID is not defined: DEFINE_GUID declares an external reference to the symbol name.
- - if INITGUID is defined: DEFINE_GUID initializes the symbol name to the value of the GUID.
-
-Also we need IID_IUnknown that is initialized in some file for linking:
- MSVC: by default the linker uses some lib file that contains IID_IUnknown
- MinGW: add -luuid switch for linker
- WinCE: we define IID_IUnknown in this file
- Other: we define IID_IUnknown in this file
-*/
-
-#ifdef _WIN32
-
-#ifdef UNDER_CE
-#include <basetyps.h>
-#endif
-
-#include <initguid.h>
-
-#ifdef UNDER_CE
-DEFINE_GUID(IID_IUnknown,
-0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
-#endif
-
-#else
-
-#define INITGUID
-#include "MyGuidDef.h"
-DEFINE_GUID(IID_IUnknown,
-0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
-
-#endif
-
-
-#endif
+// Common/MyInitGuid.h
+
+#ifndef ZIP7_INC_COMMON_MY_INITGUID_H
+#define ZIP7_INC_COMMON_MY_INITGUID_H
+
+/*
+This file must be included only to one C++ file in project before
+declarations of COM interfaces with DEFINE_GUID macro.
+
+Each GUID must be initialized exactly once in project.
+There are two different versions of the DEFINE_GUID macro in guiddef.h (MyGuidDef.h):
+ - if INITGUID is not defined: DEFINE_GUID declares an external reference to the symbol name.
+ - if INITGUID is defined: DEFINE_GUID initializes the symbol name to the value of the GUID.
+
+Also we need IID_IUnknown that is initialized in some file for linking:
+ MSVC: by default the linker uses some lib file that contains IID_IUnknown
+ MinGW: add -luuid switch for linker
+ WinCE: we define IID_IUnknown in this file
+ Other: we define IID_IUnknown in this file
+*/
+
+// #include "Common.h"
+/* vc6 without sdk needs <objbase.h> before <initguid.h>,
+ but it doesn't work in new msvc.
+ So we include full "MyWindows.h" instead of <objbase.h> */
+// #include <objbase.h>
+#include "MyWindows.h"
+
+#ifdef _WIN32
+
+#ifdef __clang__
+ // #pragma GCC diagnostic ignored "-Wmissing-variable-declarations"
+#endif
+
+#ifdef UNDER_CE
+#include <basetyps.h>
+#endif
+
+// for vc6 without sdk we must define INITGUID here
+#define INITGUID
+#include <initguid.h>
+
+#ifdef UNDER_CE
+DEFINE_GUID(IID_IUnknown,
+0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+#endif
+
+#else // _WIN32
+
+#define INITGUID
+#include "MyGuidDef.h"
+DEFINE_GUID(IID_IUnknown,
+0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+
+#endif // _WIN32
+
+#endif
diff --git a/CPP/Common/MyLinux.h b/CPP/Common/MyLinux.h
index b4e7605..a8454d7 100644
--- a/CPP/Common/MyLinux.h
+++ b/CPP/Common/MyLinux.h
@@ -1,42 +1,75 @@
-// MyLinux.h
-
-#ifndef __MY_LIN_LINUX_H
-#define __MY_LIN_LINUX_H
-
-#define MY_LIN_S_IFMT 00170000
-#define MY_LIN_S_IFSOCK 0140000
-#define MY_LIN_S_IFLNK 0120000
-#define MY_LIN_S_IFREG 0100000
-#define MY_LIN_S_IFBLK 0060000
-#define MY_LIN_S_IFDIR 0040000
-#define MY_LIN_S_IFCHR 0020000
-#define MY_LIN_S_IFIFO 0010000
-
-#define MY_LIN_S_ISLNK(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFLNK)
-#define MY_LIN_S_ISREG(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFREG)
-#define MY_LIN_S_ISDIR(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFDIR)
-#define MY_LIN_S_ISCHR(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFCHR)
-#define MY_LIN_S_ISBLK(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFBLK)
-#define MY_LIN_S_ISFIFO(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFIFO)
-#define MY_LIN_S_ISSOCK(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFSOCK)
-
-#define MY_LIN_S_ISUID 0004000
-#define MY_LIN_S_ISGID 0002000
-#define MY_LIN_S_ISVTX 0001000
-
-#define MY_LIN_S_IRWXU 00700
-#define MY_LIN_S_IRUSR 00400
-#define MY_LIN_S_IWUSR 00200
-#define MY_LIN_S_IXUSR 00100
-
-#define MY_LIN_S_IRWXG 00070
-#define MY_LIN_S_IRGRP 00040
-#define MY_LIN_S_IWGRP 00020
-#define MY_LIN_S_IXGRP 00010
-
-#define MY_LIN_S_IRWXO 00007
-#define MY_LIN_S_IROTH 00004
-#define MY_LIN_S_IWOTH 00002
-#define MY_LIN_S_IXOTH 00001
-
-#endif
+// MyLinux.h
+
+#ifndef ZIP7_INC_COMMON_MY_LINUX_H
+#define ZIP7_INC_COMMON_MY_LINUX_H
+
+// #include "../../C/7zTypes.h"
+
+#define MY_LIN_DT_UNKNOWN 0
+#define MY_LIN_DT_FIFO 1
+#define MY_LIN_DT_CHR 2
+#define MY_LIN_DT_DIR 4
+#define MY_LIN_DT_BLK 6
+#define MY_LIN_DT_REG 8
+#define MY_LIN_DT_LNK 10
+#define MY_LIN_DT_SOCK 12
+#define MY_LIN_DT_WHT 14
+
+#define MY_LIN_S_IFMT 00170000
+#define MY_LIN_S_IFSOCK 0140000
+#define MY_LIN_S_IFLNK 0120000
+#define MY_LIN_S_IFREG 0100000
+#define MY_LIN_S_IFBLK 0060000
+#define MY_LIN_S_IFDIR 0040000
+#define MY_LIN_S_IFCHR 0020000
+#define MY_LIN_S_IFIFO 0010000
+
+#define MY_LIN_S_ISLNK(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFLNK)
+#define MY_LIN_S_ISREG(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFREG)
+#define MY_LIN_S_ISDIR(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFDIR)
+#define MY_LIN_S_ISCHR(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFCHR)
+#define MY_LIN_S_ISBLK(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFBLK)
+#define MY_LIN_S_ISFIFO(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFIFO)
+#define MY_LIN_S_ISSOCK(m) (((m) & MY_LIN_S_IFMT) == MY_LIN_S_IFSOCK)
+
+#define MY_LIN_S_ISUID 0004000
+#define MY_LIN_S_ISGID 0002000
+#define MY_LIN_S_ISVTX 0001000
+
+#define MY_LIN_S_IRWXU 00700
+#define MY_LIN_S_IRUSR 00400
+#define MY_LIN_S_IWUSR 00200
+#define MY_LIN_S_IXUSR 00100
+
+#define MY_LIN_S_IRWXG 00070
+#define MY_LIN_S_IRGRP 00040
+#define MY_LIN_S_IWGRP 00020
+#define MY_LIN_S_IXGRP 00010
+
+#define MY_LIN_S_IRWXO 00007
+#define MY_LIN_S_IROTH 00004
+#define MY_LIN_S_IWOTH 00002
+#define MY_LIN_S_IXOTH 00001
+
+/*
+// major/minor encoding for makedev(): MMMMMmmmmmmMMMmm:
+
+inline UInt32 MY_dev_major(UInt64 dev)
+{
+ return ((UInt32)(dev >> 8) & (UInt32)0xfff) | ((UInt32)(dev >> 32) & ~(UInt32)0xfff);
+}
+
+inline UInt32 MY_dev_minor(UInt64 dev)
+{
+ return ((UInt32)(dev) & 0xff) | ((UInt32)(dev >> 12) & ~0xff);
+}
+
+inline UInt64 MY_dev_makedev(UInt32 __major, UInt32 __minor)
+{
+ return (__minor & 0xff) | ((__major & 0xfff) << 8)
+ | ((UInt64) (__minor & ~0xff) << 12)
+ | ((UInt64) (__major & ~0xfff) << 32);
+}
+*/
+
+#endif
diff --git a/CPP/Common/MyMap.cpp b/CPP/Common/MyMap.cpp
new file mode 100644
index 0000000..0a200f0
--- /dev/null
+++ b/CPP/Common/MyMap.cpp
@@ -0,0 +1,140 @@
+// MyMap.cpp
+
+#include "StdAfx.h"
+
+#include "MyMap.h"
+
+static const unsigned kNumBitsMax = sizeof(UInt32) * 8;
+
+static UInt32 GetSubBits(UInt32 value, unsigned startPos, unsigned numBits) throw()
+{
+ if (startPos == sizeof(value) * 8)
+ return 0;
+ value >>= startPos;
+ if (numBits == sizeof(value) * 8)
+ return value;
+ return value & (((UInt32)1 << numBits) - 1);
+}
+
+static inline unsigned GetSubBit(UInt32 v, unsigned n) { return (unsigned)(v >> n) & 1; }
+
+bool CMap32::Find(UInt32 key, UInt32 &valueRes) const throw()
+{
+ valueRes = (UInt32)(Int32)-1;
+ if (Nodes.Size() == 0)
+ return false;
+ if (Nodes.Size() == 1)
+ {
+ const CNode &n = Nodes[0];
+ if (n.Len == kNumBitsMax)
+ {
+ valueRes = n.Values[0];
+ return (key == n.Key);
+ }
+ }
+
+ unsigned cur = 0;
+ unsigned bitPos = kNumBitsMax;
+ for (;;)
+ {
+ const CNode &n = Nodes[cur];
+ bitPos -= n.Len;
+ if (GetSubBits(key, bitPos, n.Len) != GetSubBits(n.Key, bitPos, n.Len))
+ return false;
+ unsigned bit = GetSubBit(key, --bitPos);
+ if (n.IsLeaf[bit])
+ {
+ valueRes = n.Values[bit];
+ return (key == n.Keys[bit]);
+ }
+ cur = (unsigned)n.Keys[bit];
+ }
+}
+
+bool CMap32::Set(UInt32 key, UInt32 value)
+{
+ if (Nodes.Size() == 0)
+ {
+ CNode n;
+ n.Key = n.Keys[0] = n.Keys[1] = key;
+ n.Values[0] = n.Values[1] = value;
+ n.IsLeaf[0] = n.IsLeaf[1] = 1;
+ n.Len = kNumBitsMax;
+ Nodes.Add(n);
+ return false;
+ }
+ if (Nodes.Size() == 1)
+ {
+ CNode &n = Nodes[0];
+ if (n.Len == kNumBitsMax)
+ {
+ if (key == n.Key)
+ {
+ n.Values[0] = n.Values[1] = value;
+ return true;
+ }
+ unsigned i = kNumBitsMax - 1;
+ for (; GetSubBit(key, i) == GetSubBit(n.Key, i); i--);
+ n.Len = (UInt16)(kNumBitsMax - (1 + i));
+ const unsigned newBit = GetSubBit(key, i);
+ n.Values[newBit] = value;
+ n.Keys[newBit] = key;
+ return false;
+ }
+ }
+
+ unsigned cur = 0;
+ unsigned bitPos = kNumBitsMax;
+ for (;;)
+ {
+ CNode &n = Nodes[cur];
+ bitPos -= n.Len;
+ if (GetSubBits(key, bitPos, n.Len) != GetSubBits(n.Key, bitPos, n.Len))
+ {
+ unsigned i = (unsigned)n.Len - 1;
+ for (; GetSubBit(key, bitPos + i) == GetSubBit(n.Key, bitPos + i); i--);
+
+ CNode e2(n);
+ e2.Len = (UInt16)i;
+
+ n.Len = (UInt16)(n.Len - (1 + i));
+ unsigned newBit = GetSubBit(key, bitPos + i);
+ n.Values[newBit] = value;
+ n.IsLeaf[newBit] = 1;
+ n.IsLeaf[1 - newBit] = 0;
+ n.Keys[newBit] = key;
+ n.Keys[1 - newBit] = Nodes.Size();
+ Nodes.Add(e2);
+ return false;
+ }
+ const unsigned bit = GetSubBit(key, --bitPos);
+
+ if (n.IsLeaf[bit])
+ {
+ if (key == n.Keys[bit])
+ {
+ n.Values[bit] = value;
+ return true;
+ }
+ unsigned i = bitPos - 1;
+ for (; GetSubBit(key, i) == GetSubBit(n.Keys[bit], i); i--);
+
+ CNode e2;
+
+ const unsigned newBit = GetSubBit(key, i);
+ e2.Values[newBit] = value;
+ e2.Values[1 - newBit] = n.Values[bit];
+ e2.IsLeaf[newBit] = e2.IsLeaf[1 - newBit] = 1;
+ e2.Keys[newBit] = key;
+ e2.Keys[1 - newBit] = e2.Key = n.Keys[bit];
+ e2.Len = (UInt16)(bitPos - (1 + i));
+
+ n.IsLeaf[bit] = 0;
+ n.Keys[bit] = Nodes.Size();
+
+ Nodes.Add(e2);
+ return false;
+ }
+ cur = (unsigned)n.Keys[bit];
+ }
+}
diff --git a/CPP/Common/MyMap.h b/CPP/Common/MyMap.h
new file mode 100644
index 0000000..9ca5566
--- /dev/null
+++ b/CPP/Common/MyMap.h
@@ -0,0 +1,28 @@
+// MyMap.h
+
+#ifndef ZIP7_INC_COMMON_MY_MAP_H
+#define ZIP7_INC_COMMON_MY_MAP_H
+
+#include "MyTypes.h"
+#include "MyVector.h"
+
+class CMap32
+{
+ struct CNode
+ {
+ UInt32 Key;
+ UInt32 Keys[2];
+ UInt32 Values[2];
+ UInt16 Len;
+ Byte IsLeaf[2];
+ };
+ CRecordVector<CNode> Nodes;
+
+public:
+
+ void Clear() { Nodes.Clear(); }
+ bool Find(UInt32 key, UInt32 &valueRes) const throw();
+ bool Set(UInt32 key, UInt32 value); // returns true, if there is such key already
+};
+
+#endif
diff --git a/CPP/Common/MyString.cpp b/CPP/Common/MyString.cpp
index bf62303..51c1c3b 100644
--- a/CPP/Common/MyString.cpp
+++ b/CPP/Common/MyString.cpp
@@ -1,1659 +1,1859 @@
-// Common/MyString.cpp
-
-#include "StdAfx.h"
-
-#ifdef _WIN32
-#include <wchar.h>
-#else
-#include <ctype.h>
-#endif
-
-#include "IntToString.h"
-
-#if !defined(_UNICODE) || !defined(USE_UNICODE_FSTRING)
-#include "StringConvert.h"
-#endif
-
-#include "MyString.h"
-
-#define MY_STRING_NEW(_T_, _size_) new _T_[_size_]
-// #define MY_STRING_NEW(_T_, _size_) ((_T_ *)my_new((size_t)(_size_) * sizeof(_T_)))
-
-/*
-inline const char* MyStringGetNextCharPointer(const char *p) throw()
-{
- #if defined(_WIN32) && !defined(UNDER_CE)
- return CharNextA(p);
- #else
- return p + 1;
- #endif
-}
-*/
-
-#define MY_STRING_NEW_char(_size_) MY_STRING_NEW(char, _size_)
-#define MY_STRING_NEW_wchar_t(_size_) MY_STRING_NEW(wchar_t, _size_)
-
-
-int FindCharPosInString(const char *s, char c) throw()
-{
- for (const char *p = s;; p++)
- {
- if (*p == c)
- return (int)(p - s);
- if (*p == 0)
- return -1;
- // MyStringGetNextCharPointer(p);
- }
-}
-
-int FindCharPosInString(const wchar_t *s, wchar_t c) throw()
-{
- for (const wchar_t *p = s;; p++)
- {
- if (*p == c)
- return (int)(p - s);
- if (*p == 0)
- return -1;
- }
-}
-
-/*
-void MyStringUpper_Ascii(char *s) throw()
-{
- for (;;)
- {
- char c = *s;
- if (c == 0)
- return;
- *s++ = MyCharUpper_Ascii(c);
- }
-}
-
-void MyStringUpper_Ascii(wchar_t *s) throw()
-{
- for (;;)
- {
- wchar_t c = *s;
- if (c == 0)
- return;
- *s++ = MyCharUpper_Ascii(c);
- }
-}
-*/
-
-void MyStringLower_Ascii(char *s) throw()
-{
- for (;;)
- {
- char c = *s;
- if (c == 0)
- return;
- *s++ = MyCharLower_Ascii(c);
- }
-}
-
-void MyStringLower_Ascii(wchar_t *s) throw()
-{
- for (;;)
- {
- wchar_t c = *s;
- if (c == 0)
- return;
- *s++ = MyCharLower_Ascii(c);
- }
-}
-
-#ifdef _WIN32
-
-#ifdef _UNICODE
-
-// wchar_t * MyStringUpper(wchar_t *s) { return CharUpperW(s); }
-// wchar_t * MyStringLower(wchar_t *s) { return CharLowerW(s); }
-// for WinCE - FString - char
-// const char *MyStringGetPrevCharPointer(const char * /* base */, const char *p) { return p - 1; }
-
-#else
-
-// const char * MyStringGetPrevCharPointer(const char *base, const char *p) throw() { return CharPrevA(base, p); }
-// char * MyStringUpper(char *s) { return CharUpperA(s); }
-// char * MyStringLower(char *s) { return CharLowerA(s); }
-
-wchar_t MyCharUpper_WIN(wchar_t c) throw()
-{
- wchar_t *res = CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c);
- if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
- return (wchar_t)(unsigned)(UINT_PTR)res;
- const int kBufSize = 4;
- char s[kBufSize + 1];
- int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0);
- if (numChars == 0 || numChars > kBufSize)
- return c;
- s[numChars] = 0;
- ::CharUpperA(s);
- ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1);
- return c;
-}
-
-/*
-wchar_t MyCharLower_WIN(wchar_t c)
-{
- wchar_t *res = CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c);
- if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
- return (wchar_t)(unsigned)(UINT_PTR)res;
- const int kBufSize = 4;
- char s[kBufSize + 1];
- int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0);
- if (numChars == 0 || numChars > kBufSize)
- return c;
- s[numChars] = 0;
- ::CharLowerA(s);
- ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1);
- return c;
-}
-*/
-
-/*
-wchar_t * MyStringUpper(wchar_t *s)
-{
- if (s == 0)
- return 0;
- wchar_t *res = CharUpperW(s);
- if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
- return res;
- AString a = UnicodeStringToMultiByte(s);
- a.MakeUpper();
- MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a));
- return s;
-}
-*/
-
-/*
-wchar_t * MyStringLower(wchar_t *s)
-{
- if (s == 0)
- return 0;
- wchar_t *res = CharLowerW(s);
- if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
- return res;
- AString a = UnicodeStringToMultiByte(s);
- a.MakeLower();
- MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a));
- return s;
-}
-*/
-
-#endif
-
-#endif
-
-bool IsString1PrefixedByString2(const char *s1, const char *s2) throw()
-{
- for (;;)
- {
- unsigned char c2 = (unsigned char)*s2++; if (c2 == 0) return true;
- unsigned char c1 = (unsigned char)*s1++; if (c1 != c2) return false;
- }
-}
-
-bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw()
-{
- for (;;)
- {
- wchar_t c1 = *s1++;
- wchar_t c2 = *s2++;
- if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) return false;
- if (c1 == 0) return true;
- }
-}
-
-// ---------- ASCII ----------
-
-bool AString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw()
-{
- const char *s1 = _chars;
- for (;;)
- {
- char c2 = *s++;
- if (c2 == 0)
- return true;
- char c1 = *s1++;
- if (MyCharLower_Ascii(c1) !=
- MyCharLower_Ascii(c2))
- return false;
- }
-}
-
-bool UString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw()
-{
- const wchar_t *s1 = _chars;
- for (;;)
- {
- char c2 = *s++;
- if (c2 == 0)
- return true;
- wchar_t c1 = *s1++;
- if (MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))
- return false;
- }
-}
-
-bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw()
-{
- for (;;)
- {
- unsigned char c = *a;
- if (c != *u)
- return false;
- if (c == 0)
- return true;
- a++;
- u++;
- }
-}
-
-bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw()
-{
- for (;;)
- {
- char c1 = *s1++;
- char c2 = *s2++;
- if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2))
- return false;
- if (c1 == 0)
- return true;
- }
-}
-
-bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw()
-{
- for (;;)
- {
- wchar_t c1 = *s1++;
- wchar_t c2 = *s2++;
- if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2))
- return false;
- if (c1 == 0)
- return true;
- }
-}
-
-bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw()
-{
- for (;;)
- {
- wchar_t c1 = *s1++;
- char c2 = *s2++;
- if (c1 != (unsigned char)c2 && (c1 > 0x7F || MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)))
- return false;
- if (c1 == 0)
- return true;
- }
-}
-
-bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw()
-{
- for (;;)
- {
- wchar_t c2 = *s2++; if (c2 == 0) return true;
- wchar_t c1 = *s1++; if (c1 != c2) return false;
- }
-}
-
-bool IsString1PrefixedByString2(const wchar_t *s1, const char *s2) throw()
-{
- for (;;)
- {
- unsigned char c2 = (unsigned char)(*s2++); if (c2 == 0) return true;
- wchar_t c1 = *s1++; if (c1 != c2) return false;
- }
-}
-
-bool IsString1PrefixedByString2_NoCase_Ascii(const wchar_t *s1, const char *s2) throw()
-{
- for (;;)
- {
- char c2 = *s2++; if (c2 == 0) return true;
- wchar_t c1 = *s1++;
- if (c1 != (unsigned char)c2 && MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))
- return false;
- }
-}
-
-bool IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2) throw()
-{
- for (;;)
- {
- wchar_t c2 = *s2++; if (c2 == 0) return true;
- wchar_t c1 = *s1++;
- if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2))
- return false;
- }
-}
-
-// NTFS order: uses upper case
-int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw()
-{
- for (;;)
- {
- wchar_t c1 = *s1++;
- wchar_t c2 = *s2++;
- if (c1 != c2)
- {
- wchar_t u1 = MyCharUpper(c1);
- wchar_t u2 = MyCharUpper(c2);
- if (u1 < u2) return -1;
- if (u1 > u2) return 1;
- }
- if (c1 == 0) return 0;
- }
-}
-
-/*
-int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num)
-{
- for (; num != 0; num--)
- {
- wchar_t c1 = *s1++;
- wchar_t c2 = *s2++;
- if (c1 != c2)
- {
- wchar_t u1 = MyCharUpper(c1);
- wchar_t u2 = MyCharUpper(c2);
- if (u1 < u2) return -1;
- if (u1 > u2) return 1;
- }
- if (c1 == 0) return 0;
- }
- return 0;
-}
-*/
-
-// ---------- AString ----------
-
-void AString::InsertSpace(unsigned &index, unsigned size)
-{
- Grow(size);
- MoveItems(index + size, index);
-}
-
-#define k_Alloc_Len_Limit 0x40000000
-
-void AString::ReAlloc(unsigned newLimit)
-{
- if (newLimit < _len || newLimit >= k_Alloc_Len_Limit) throw 20130220;
- // MY_STRING_REALLOC(_chars, char, newLimit + 1, _len + 1);
- char *newBuf = MY_STRING_NEW_char(newLimit + 1);
- memcpy(newBuf, _chars, (size_t)(_len + 1));
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- _limit = newLimit;
-}
-
-void AString::ReAlloc2(unsigned newLimit)
-{
- if (newLimit >= k_Alloc_Len_Limit) throw 20130220;
- // MY_STRING_REALLOC(_chars, char, newLimit + 1, 0);
- char *newBuf = MY_STRING_NEW_char(newLimit + 1);
- newBuf[0] = 0;
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- _limit = newLimit;
-}
-
-void AString::SetStartLen(unsigned len)
-{
- _chars = 0;
- _chars = MY_STRING_NEW_char(len + 1);
- _len = len;
- _limit = len;
-}
-
-void AString::Grow_1()
-{
- unsigned next = _len;
- next += next / 2;
- next += 16;
- next &= ~(unsigned)15;
- ReAlloc(next - 1);
-}
-
-void AString::Grow(unsigned n)
-{
- unsigned freeSize = _limit - _len;
- if (n <= freeSize)
- return;
-
- unsigned next = _len + n;
- next += next / 2;
- next += 16;
- next &= ~(unsigned)15;
- ReAlloc(next - 1);
-}
-
-AString::AString(unsigned num, const char *s)
-{
- unsigned len = MyStringLen(s);
- if (num > len)
- num = len;
- SetStartLen(num);
- memcpy(_chars, s, num);
- _chars[num] = 0;
-}
-
-AString::AString(unsigned num, const AString &s)
-{
- if (num > s._len)
- num = s._len;
- SetStartLen(num);
- memcpy(_chars, s._chars, num);
- _chars[num] = 0;
-}
-
-AString::AString(const AString &s, char c)
-{
- SetStartLen(s.Len() + 1);
- char *chars = _chars;
- unsigned len = s.Len();
- memcpy(chars, s, len);
- chars[len] = c;
- chars[(size_t)len + 1] = 0;
-}
-
-AString::AString(const char *s1, unsigned num1, const char *s2, unsigned num2)
-{
- SetStartLen(num1 + num2);
- char *chars = _chars;
- memcpy(chars, s1, num1);
- memcpy(chars + num1, s2, num2 + 1);
-}
-
-AString operator+(const AString &s1, const AString &s2) { return AString(s1, s1.Len(), s2, s2.Len()); }
-AString operator+(const AString &s1, const char *s2) { return AString(s1, s1.Len(), s2, MyStringLen(s2)); }
-AString operator+(const char *s1, const AString &s2) { return AString(s1, MyStringLen(s1), s2, s2.Len()); }
-
-static const unsigned kStartStringCapacity = 4;
-
-AString::AString()
-{
- _chars = 0;
- _chars = MY_STRING_NEW_char(kStartStringCapacity);
- _len = 0;
- _limit = kStartStringCapacity - 1;
- _chars[0] = 0;
-}
-
-AString::AString(char c)
-{
- SetStartLen(1);
- char *chars = _chars;
- chars[0] = c;
- chars[1] = 0;
-}
-
-AString::AString(const char *s)
-{
- SetStartLen(MyStringLen(s));
- MyStringCopy(_chars, s);
-}
-
-AString::AString(const AString &s)
-{
- SetStartLen(s._len);
- MyStringCopy(_chars, s._chars);
-}
-
-AString &AString::operator=(char c)
-{
- if (1 > _limit)
- {
- char *newBuf = MY_STRING_NEW_char(1 + 1);
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- _limit = 1;
- }
- _len = 1;
- char *chars = _chars;
- chars[0] = c;
- chars[1] = 0;
- return *this;
-}
-
-AString &AString::operator=(const char *s)
-{
- unsigned len = MyStringLen(s);
- if (len > _limit)
- {
- char *newBuf = MY_STRING_NEW_char(len + 1);
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- _limit = len;
- }
- _len = len;
- MyStringCopy(_chars, s);
- return *this;
-}
-
-AString &AString::operator=(const AString &s)
-{
- if (&s == this)
- return *this;
- unsigned len = s._len;
- if (len > _limit)
- {
- char *newBuf = MY_STRING_NEW_char(len + 1);
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- _limit = len;
- }
- _len = len;
- MyStringCopy(_chars, s._chars);
- return *this;
-}
-
-void AString::SetFromWStr_if_Ascii(const wchar_t *s)
-{
- unsigned len = 0;
- {
- for (;; len++)
- {
- wchar_t c = s[len];
- if (c == 0)
- break;
- if (c >= 0x80)
- return;
- }
- }
- if (len > _limit)
- {
- char *newBuf = MY_STRING_NEW_char(len + 1);
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- _limit = len;
- }
- _len = len;
- char *dest = _chars;
- unsigned i;
- for (i = 0; i < len; i++)
- dest[i] = (char)s[i];
- dest[i] = 0;
-}
-
-/*
-void AString::SetFromBstr_if_Ascii(BSTR s)
-{
- unsigned len = ::SysStringLen(s);
- {
- for (unsigned i = 0; i < len; i++)
- if (s[i] <= 0 || s[i] >= 0x80)
- return;
- }
- if (len > _limit)
- {
- char *newBuf = MY_STRING_NEW_char(len + 1);
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- _limit = len;
- }
- _len = len;
- char *dest = _chars;
- unsigned i;
- for (i = 0; i < len; i++)
- dest[i] = (char)s[i];
- dest[i] = 0;
-}
-*/
-
-void AString::Add_Space() { operator+=(' '); }
-void AString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); }
-void AString::Add_LF() { operator+=('\n'); }
-
-AString &AString::operator+=(const char *s)
-{
- unsigned len = MyStringLen(s);
- Grow(len);
- MyStringCopy(_chars + _len, s);
- _len += len;
- return *this;
-}
-
-void AString::Add_OptSpaced(const char *s)
-{
- Add_Space_if_NotEmpty();
- (*this) += s;
-}
-
-AString &AString::operator+=(const AString &s)
-{
- Grow(s._len);
- MyStringCopy(_chars + _len, s._chars);
- _len += s._len;
- return *this;
-}
-
-void AString::Add_UInt32(UInt32 v)
-{
- char sz[16];
- ConvertUInt32ToString(v, sz);
- (*this) += sz;
-}
-
-void AString::SetFrom(const char *s, unsigned len) // no check
-{
- if (len > _limit)
- {
- char *newBuf = MY_STRING_NEW_char(len + 1);
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- _limit = len;
- }
- if (len != 0)
- memcpy(_chars, s, len);
- _chars[len] = 0;
- _len = len;
-}
-
-void AString::SetFrom_CalcLen(const char *s, unsigned len) // no check
-{
- unsigned i;
- for (i = 0; i < len; i++)
- if (s[i] == 0)
- break;
- SetFrom(s, i);
-}
-
-int AString::Find(const char *s, unsigned startIndex) const throw()
-{
- const char *fs = strstr(_chars + startIndex, s);
- if (!fs)
- return -1;
- return (int)(fs - _chars);
-
- /*
- if (s[0] == 0)
- return startIndex;
- unsigned len = MyStringLen(s);
- const char *p = _chars + startIndex;
- for (;; p++)
- {
- const char c = *p;
- if (c != s[0])
- {
- if (c == 0)
- return -1;
- continue;
- }
- unsigned i;
- for (i = 1; i < len; i++)
- if (p[i] != s[i])
- break;
- if (i == len)
- return (int)(p - _chars);
- }
- */
-}
-
-int AString::ReverseFind(char c) const throw()
-{
- if (_len == 0)
- return -1;
- const char *p = _chars + _len - 1;
- for (;;)
- {
- if (*p == c)
- return (int)(p - _chars);
- if (p == _chars)
- return -1;
- p--; // p = GetPrevCharPointer(_chars, p);
- }
-}
-
-int AString::ReverseFind_PathSepar() const throw()
-{
- if (_len == 0)
- return -1;
- const char *p = _chars + _len - 1;
- for (;;)
- {
- char c = *p;
- if (IS_PATH_SEPAR(c))
- return (int)(p - _chars);
- if (p == _chars)
- return -1;
- p--;
- }
-}
-
-void AString::TrimLeft() throw()
-{
- const char *p = _chars;
- for (;; p++)
- {
- char c = *p;
- if (c != ' ' && c != '\n' && c != '\t')
- break;
- }
- unsigned pos = (unsigned)(p - _chars);
- if (pos != 0)
- {
- MoveItems(0, pos);
- _len -= pos;
- }
-}
-
-void AString::TrimRight() throw()
-{
- const char *p = _chars;
- unsigned i;
- for (i = _len; i != 0; i--)
- {
- char c = p[(size_t)i - 1];
- if (c != ' ' && c != '\n' && c != '\t')
- break;
- }
- if (i != _len)
- {
- _chars[i] = 0;
- _len = i;
- }
-}
-
-void AString::InsertAtFront(char c)
-{
- if (_limit == _len)
- Grow_1();
- MoveItems(1, 0);
- _chars[0] = c;
- _len++;
-}
-
-/*
-void AString::Insert(unsigned index, char c)
-{
- InsertSpace(index, 1);
- _chars[index] = c;
- _len++;
-}
-*/
-
-void AString::Insert(unsigned index, const char *s)
-{
- unsigned num = MyStringLen(s);
- if (num != 0)
- {
- InsertSpace(index, num);
- memcpy(_chars + index, s, num);
- _len += num;
- }
-}
-
-void AString::Insert(unsigned index, const AString &s)
-{
- unsigned num = s.Len();
- if (num != 0)
- {
- InsertSpace(index, num);
- memcpy(_chars + index, s, num);
- _len += num;
- }
-}
-
-void AString::RemoveChar(char ch) throw()
-{
- char *src = _chars;
-
- for (;;)
- {
- char c = *src++;
- if (c == 0)
- return;
- if (c == ch)
- break;
- }
-
- char *dest = src - 1;
-
- for (;;)
- {
- char c = *src++;
- if (c == 0)
- break;
- if (c != ch)
- *dest++ = c;
- }
-
- *dest = 0;
- _len = (unsigned)(dest - _chars);
-}
-
-// !!!!!!!!!!!!!!! test it if newChar = '\0'
-void AString::Replace(char oldChar, char newChar) throw()
-{
- if (oldChar == newChar)
- return; // 0;
- // unsigned number = 0;
- int pos = 0;
- char *chars = _chars;
- while ((unsigned)pos < _len)
- {
- pos = Find(oldChar, pos);
- if (pos < 0)
- break;
- chars[(unsigned)pos] = newChar;
- pos++;
- // number++;
- }
- return; // number;
-}
-
-void AString::Replace(const AString &oldString, const AString &newString)
-{
- if (oldString.IsEmpty())
- return; // 0;
- if (oldString == newString)
- return; // 0;
- unsigned oldLen = oldString.Len();
- unsigned newLen = newString.Len();
- // unsigned number = 0;
- int pos = 0;
- while ((unsigned)pos < _len)
- {
- pos = Find(oldString, pos);
- if (pos < 0)
- break;
- Delete(pos, oldLen);
- Insert(pos, newString);
- pos += newLen;
- // number++;
- }
- // return number;
-}
-
-void AString::Delete(unsigned index) throw()
-{
- MoveItems(index, index + 1);
- _len--;
-}
-
-void AString::Delete(unsigned index, unsigned count) throw()
-{
- if (index + count > _len)
- count = _len - index;
- if (count > 0)
- {
- MoveItems(index, index + count);
- _len -= count;
- }
-}
-
-void AString::DeleteFrontal(unsigned num) throw()
-{
- if (num != 0)
- {
- MoveItems(0, num);
- _len -= num;
- }
-}
-
-/*
-AString operator+(const AString &s1, const AString &s2)
-{
- AString result(s1);
- result += s2;
- return result;
-}
-
-AString operator+(const AString &s, const char *chars)
-{
- AString result(s);
- result += chars;
- return result;
-}
-
-AString operator+(const char *chars, const AString &s)
-{
- AString result(chars);
- result += s;
- return result;
-}
-
-AString operator+(const AString &s, char c)
-{
- AString result(s);
- result += c;
- return result;
-}
-*/
-
-/*
-AString operator+(char c, const AString &s)
-{
- AString result(c);
- result += s;
- return result;
-}
-*/
-
-
-
-
-// ---------- UString ----------
-
-void UString::InsertSpace(unsigned index, unsigned size)
-{
- Grow(size);
- MoveItems(index + size, index);
-}
-
-void UString::ReAlloc(unsigned newLimit)
-{
- if (newLimit < _len || newLimit >= k_Alloc_Len_Limit) throw 20130221;
- // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, _len + 1);
- wchar_t *newBuf = MY_STRING_NEW_wchar_t(newLimit + 1);
- wmemcpy(newBuf, _chars, _len + 1);
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- _limit = newLimit;
-}
-
-void UString::ReAlloc2(unsigned newLimit)
-{
- if (newLimit >= k_Alloc_Len_Limit) throw 20130221;
- // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0);
- wchar_t *newBuf = MY_STRING_NEW_wchar_t(newLimit + 1);
- newBuf[0] = 0;
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- _limit = newLimit;
-}
-
-void UString::SetStartLen(unsigned len)
-{
- _chars = 0;
- _chars = MY_STRING_NEW_wchar_t(len + 1);
- _len = len;
- _limit = len;
-}
-
-void UString::Grow_1()
-{
- unsigned next = _len;
- next += next / 2;
- next += 16;
- next &= ~(unsigned)15;
- ReAlloc(next - 1);
-}
-
-void UString::Grow(unsigned n)
-{
- unsigned freeSize = _limit - _len;
- if (n <= freeSize)
- return;
-
- unsigned next = _len + n;
- next += next / 2;
- next += 16;
- next &= ~(unsigned)15;
- ReAlloc(next - 1);
-}
-
-
-UString::UString(unsigned num, const wchar_t *s)
-{
- unsigned len = MyStringLen(s);
- if (num > len)
- num = len;
- SetStartLen(num);
- wmemcpy(_chars, s, num);
- _chars[num] = 0;
-}
-
-
-UString::UString(unsigned num, const UString &s)
-{
- if (num > s._len)
- num = s._len;
- SetStartLen(num);
- wmemcpy(_chars, s._chars, num);
- _chars[num] = 0;
-}
-
-UString::UString(const UString &s, wchar_t c)
-{
- SetStartLen(s.Len() + 1);
- wchar_t *chars = _chars;
- unsigned len = s.Len();
- wmemcpy(chars, s, len);
- chars[len] = c;
- chars[(size_t)len + 1] = 0;
-}
-
-UString::UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2)
-{
- SetStartLen(num1 + num2);
- wchar_t *chars = _chars;
- wmemcpy(chars, s1, num1);
- wmemcpy(chars + num1, s2, num2 + 1);
-}
-
-UString operator+(const UString &s1, const UString &s2) { return UString(s1, s1.Len(), s2, s2.Len()); }
-UString operator+(const UString &s1, const wchar_t *s2) { return UString(s1, s1.Len(), s2, MyStringLen(s2)); }
-UString operator+(const wchar_t *s1, const UString &s2) { return UString(s1, MyStringLen(s1), s2, s2.Len()); }
-
-UString::UString()
-{
- _chars = 0;
- _chars = MY_STRING_NEW_wchar_t(kStartStringCapacity);
- _len = 0;
- _limit = kStartStringCapacity - 1;
- _chars[0] = 0;
-}
-
-UString::UString(wchar_t c)
-{
- SetStartLen(1);
- wchar_t *chars = _chars;
- chars[0] = c;
- chars[1] = 0;
-}
-
-UString::UString(char c)
-{
- SetStartLen(1);
- wchar_t *chars = _chars;
- chars[0] = (unsigned char)c;
- chars[1] = 0;
-}
-
-UString::UString(const wchar_t *s)
-{
- unsigned len = MyStringLen(s);
- SetStartLen(len);
- wmemcpy(_chars, s, len + 1);
-}
-
-UString::UString(const char *s)
-{
- unsigned len = MyStringLen(s);
- SetStartLen(len);
- wchar_t *chars = _chars;
- for (unsigned i = 0; i < len; i++)
- chars[i] = (unsigned char)s[i];
- chars[len] = 0;
-}
-
-UString::UString(const UString &s)
-{
- SetStartLen(s._len);
- wmemcpy(_chars, s._chars, s._len + 1);
-}
-
-UString &UString::operator=(wchar_t c)
-{
- if (1 > _limit)
- {
- wchar_t *newBuf = MY_STRING_NEW_wchar_t(1 + 1);
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- _limit = 1;
- }
- _len = 1;
- wchar_t *chars = _chars;
- chars[0] = c;
- chars[1] = 0;
- return *this;
-}
-
-UString &UString::operator=(const wchar_t *s)
-{
- unsigned len = MyStringLen(s);
- if (len > _limit)
- {
- wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1);
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- _limit = len;
- }
- _len = len;
- wmemcpy(_chars, s, len + 1);
- return *this;
-}
-
-UString &UString::operator=(const UString &s)
-{
- if (&s == this)
- return *this;
- unsigned len = s._len;
- if (len > _limit)
- {
- wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1);
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- _limit = len;
- }
- _len = len;
- wmemcpy(_chars, s._chars, len + 1);
- return *this;
-}
-
-void UString::SetFrom(const wchar_t *s, unsigned len) // no check
-{
- if (len > _limit)
- {
- wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1);
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- _limit = len;
- }
- if (len != 0)
- wmemcpy(_chars, s, len);
- _chars[len] = 0;
- _len = len;
-}
-
-void UString::SetFromBstr(BSTR s)
-{
- unsigned len = ::SysStringLen(s);
- if (len > _limit)
- {
- wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1);
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- _limit = len;
- }
- _len = len;
- // if (s)
- wmemcpy(_chars, s, len + 1);
-}
-
-UString &UString::operator=(const char *s)
-{
- unsigned len = MyStringLen(s);
- if (len > _limit)
- {
- wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1);
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- _limit = len;
- }
- wchar_t *chars = _chars;
- for (unsigned i = 0; i < len; i++)
- chars[i] = (unsigned char)s[i];
- chars[len] = 0;
- _len = len;
- return *this;
-}
-
-void UString::Add_Space() { operator+=(L' '); }
-void UString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); }
-
-void UString::Add_LF()
-{
- if (_limit == _len)
- Grow_1();
- unsigned len = _len;
- wchar_t *chars = _chars;
- chars[len++] = L'\n';
- chars[len] = 0;
- _len = len;
-}
-
-UString &UString::operator+=(const wchar_t *s)
-{
- unsigned len = MyStringLen(s);
- Grow(len);
- wmemcpy(_chars + _len, s, len + 1);
- _len += len;
- return *this;
-}
-
-UString &UString::operator+=(const UString &s)
-{
- Grow(s._len);
- wmemcpy(_chars + _len, s._chars, s._len + 1);
- _len += s._len;
- return *this;
-}
-
-UString &UString::operator+=(const char *s)
-{
- unsigned len = MyStringLen(s);
- Grow(len);
- wchar_t *chars = _chars + _len;
- for (unsigned i = 0; i < len; i++)
- chars[i] = (unsigned char)s[i];
- chars[len] = 0;
- _len += len;
- return *this;
-}
-
-
-void UString::Add_UInt32(UInt32 v)
-{
- char sz[16];
- ConvertUInt32ToString(v, sz);
- (*this) += sz;
-}
-
-
-int UString::Find(const wchar_t *s, unsigned startIndex) const throw()
-{
- const wchar_t *fs = wcsstr(_chars + startIndex, s);
- if (!fs)
- return -1;
- return (int)(fs - _chars);
-
- /*
- if (s[0] == 0)
- return startIndex;
- unsigned len = MyStringLen(s);
- const wchar_t *p = _chars + startIndex;
- for (;; p++)
- {
- const wchar_t c = *p;
- if (c != s[0])
- {
- if (c == 0)
- return -1;
- continue;
- }
- unsigned i;
- for (i = 1; i < len; i++)
- if (p[i] != s[i])
- break;
- if (i == len)
- return (int)(p - _chars);
- }
- */
-}
-
-int UString::ReverseFind(wchar_t c) const throw()
-{
- if (_len == 0)
- return -1;
- const wchar_t *p = _chars + _len - 1;
- for (;;)
- {
- if (*p == c)
- return (int)(p - _chars);
- if (p == _chars)
- return -1;
- p--;
- }
-}
-
-int UString::ReverseFind_PathSepar() const throw()
-{
- if (_len == 0)
- return -1;
- const wchar_t *p = _chars + _len - 1;
- for (;;)
- {
- wchar_t c = *p;
- if (IS_PATH_SEPAR(c))
- return (int)(p - _chars);
- if (p == _chars)
- return -1;
- p--;
- }
-}
-
-void UString::TrimLeft() throw()
-{
- const wchar_t *p = _chars;
- for (;; p++)
- {
- wchar_t c = *p;
- if (c != ' ' && c != '\n' && c != '\t')
- break;
- }
- unsigned pos = (unsigned)(p - _chars);
- if (pos != 0)
- {
- MoveItems(0, pos);
- _len -= pos;
- }
-}
-
-void UString::TrimRight() throw()
-{
- const wchar_t *p = _chars;
- unsigned i;
- for (i = _len; i != 0; i--)
- {
- wchar_t c = p[(size_t)i - 1];
- if (c != ' ' && c != '\n' && c != '\t')
- break;
- }
- if (i != _len)
- {
- _chars[i] = 0;
- _len = i;
- }
-}
-
-void UString::InsertAtFront(wchar_t c)
-{
- if (_limit == _len)
- Grow_1();
- MoveItems(1, 0);
- _chars[0] = c;
- _len++;
-}
-
-/*
-void UString::Insert(unsigned index, wchar_t c)
-{
- InsertSpace(index, 1);
- _chars[index] = c;
- _len++;
-}
-*/
-
-void UString::Insert(unsigned index, const wchar_t *s)
-{
- unsigned num = MyStringLen(s);
- if (num != 0)
- {
- InsertSpace(index, num);
- wmemcpy(_chars + index, s, num);
- _len += num;
- }
-}
-
-void UString::Insert(unsigned index, const UString &s)
-{
- unsigned num = s.Len();
- if (num != 0)
- {
- InsertSpace(index, num);
- wmemcpy(_chars + index, s, num);
- _len += num;
- }
-}
-
-void UString::RemoveChar(wchar_t ch) throw()
-{
- wchar_t *src = _chars;
-
- for (;;)
- {
- wchar_t c = *src++;
- if (c == 0)
- return;
- if (c == ch)
- break;
- }
-
- wchar_t *dest = src - 1;
-
- for (;;)
- {
- wchar_t c = *src++;
- if (c == 0)
- break;
- if (c != ch)
- *dest++ = c;
- }
-
- *dest = 0;
- _len = (unsigned)(dest - _chars);
-}
-
-// !!!!!!!!!!!!!!! test it if newChar = '\0'
-void UString::Replace(wchar_t oldChar, wchar_t newChar) throw()
-{
- if (oldChar == newChar)
- return; // 0;
- // unsigned number = 0;
- int pos = 0;
- wchar_t *chars = _chars;
- while ((unsigned)pos < _len)
- {
- pos = Find(oldChar, pos);
- if (pos < 0)
- break;
- chars[(unsigned)pos] = newChar;
- pos++;
- // number++;
- }
- return; // number;
-}
-
-void UString::Replace(const UString &oldString, const UString &newString)
-{
- if (oldString.IsEmpty())
- return; // 0;
- if (oldString == newString)
- return; // 0;
- unsigned oldLen = oldString.Len();
- unsigned newLen = newString.Len();
- // unsigned number = 0;
- int pos = 0;
- while ((unsigned)pos < _len)
- {
- pos = Find(oldString, pos);
- if (pos < 0)
- break;
- Delete(pos, oldLen);
- Insert(pos, newString);
- pos += newLen;
- // number++;
- }
- // return number;
-}
-
-void UString::Delete(unsigned index) throw()
-{
- MoveItems(index, index + 1);
- _len--;
-}
-
-void UString::Delete(unsigned index, unsigned count) throw()
-{
- if (index + count > _len)
- count = _len - index;
- if (count > 0)
- {
- MoveItems(index, index + count);
- _len -= count;
- }
-}
-
-void UString::DeleteFrontal(unsigned num) throw()
-{
- if (num != 0)
- {
- MoveItems(0, num);
- _len -= num;
- }
-}
-
-
-// ---------- UString2 ----------
-
-void UString2::ReAlloc2(unsigned newLimit)
-{
- if (newLimit >= k_Alloc_Len_Limit) throw 20130221;
- // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0);
- _chars = MY_STRING_NEW_wchar_t(newLimit + 1);
-}
-
-void UString2::SetStartLen(unsigned len)
-{
- _chars = 0;
- _chars = MY_STRING_NEW_wchar_t(len + 1);
- _len = len;
-}
-
-
-/*
-UString2::UString2(wchar_t c)
-{
- SetStartLen(1);
- wchar_t *chars = _chars;
- chars[0] = c;
- chars[1] = 0;
-}
-*/
-
-UString2::UString2(const wchar_t *s)
-{
- unsigned len = MyStringLen(s);
- SetStartLen(len);
- wmemcpy(_chars, s, len + 1);
-}
-
-UString2::UString2(const UString2 &s): _chars(NULL), _len(0)
-{
- if (s._chars)
- {
- SetStartLen(s._len);
- wmemcpy(_chars, s._chars, s._len + 1);
- }
-}
-
-/*
-UString2 &UString2::operator=(wchar_t c)
-{
- if (1 > _len)
- {
- wchar_t *newBuf = MY_STRING_NEW_wchar_t(1 + 1);
- if (_chars)
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- }
- _len = 1;
- wchar_t *chars = _chars;
- chars[0] = c;
- chars[1] = 0;
- return *this;
-}
-*/
-
-UString2 &UString2::operator=(const wchar_t *s)
-{
- unsigned len = MyStringLen(s);
- if (len > _len)
- {
- wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1);
- if (_chars)
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- }
- _len = len;
- MyStringCopy(_chars, s);
- return *this;
-}
-
-void UString2::SetFromAscii(const char *s)
-{
- unsigned len = MyStringLen(s);
- if (len > _len)
- {
- wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1);
- if (_chars)
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- }
- wchar_t *chars = _chars;
- for (unsigned i = 0; i < len; i++)
- chars[i] = (unsigned char)s[i];
- chars[len] = 0;
- _len = len;
-}
-
-UString2 &UString2::operator=(const UString2 &s)
-{
- if (&s == this)
- return *this;
- unsigned len = s._len;
- if (len > _len)
- {
- wchar_t *newBuf = MY_STRING_NEW_wchar_t(len + 1);
- if (_chars)
- MY_STRING_DELETE(_chars);
- _chars = newBuf;
- }
- _len = len;
- MyStringCopy(_chars, s._chars);
- return *this;
-}
-
-bool operator==(const UString2 &s1, const UString2 &s2)
-{
- return s1.Len() == s2.Len() && (s1.IsEmpty() || wcscmp(s1.GetRawPtr(), s2.GetRawPtr()) == 0);
-}
-
-bool operator==(const UString2 &s1, const wchar_t *s2)
-{
- if (s1.IsEmpty())
- return (*s2 == 0);
- return wcscmp(s1.GetRawPtr(), s2) == 0;
-}
-
-bool operator==(const wchar_t *s1, const UString2 &s2)
-{
- if (s2.IsEmpty())
- return (*s1 == 0);
- return wcscmp(s1, s2.GetRawPtr()) == 0;
-}
-
-
-
-// ----------------------------------------
-
-/*
-int MyStringCompareNoCase(const char *s1, const char *s2)
-{
- return MyStringCompareNoCase(MultiByteToUnicodeString(s1), MultiByteToUnicodeString(s2));
-}
-*/
-
-static inline UINT GetCurrentCodePage()
-{
- #if defined(UNDER_CE) || !defined(_WIN32)
- return CP_ACP;
- #else
- return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP;
- #endif
-}
-
-#ifdef USE_UNICODE_FSTRING
-
-#ifndef _UNICODE
-
-AString fs2fas(CFSTR s)
-{
- return UnicodeStringToMultiByte(s, GetCurrentCodePage());
-}
-
-FString fas2fs(const char *s)
-{
- return MultiByteToUnicodeString(s, GetCurrentCodePage());
-}
-
-FString fas2fs(const AString &s)
-{
- return MultiByteToUnicodeString(s, GetCurrentCodePage());
-}
-
-#endif
-
-#else
-
-UString fs2us(const FChar *s)
-{
- return MultiByteToUnicodeString(s, GetCurrentCodePage());
-}
-
-UString fs2us(const FString &s)
-{
- return MultiByteToUnicodeString(s, GetCurrentCodePage());
-}
-
-FString us2fs(const wchar_t *s)
-{
- return UnicodeStringToMultiByte(s, GetCurrentCodePage());
-}
-
-#endif
+// Common/MyString.cpp
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#include <wchar.h>
+#else
+#include <ctype.h>
+#endif
+
+#include "IntToString.h"
+
+#if !defined(_UNICODE) || !defined(USE_UNICODE_FSTRING)
+#include "StringConvert.h"
+#endif
+
+#include "MyString.h"
+
+#define MY_STRING_NEW(_T_, _size_) new _T_[_size_]
+// #define MY_STRING_NEW(_T_, _size_) ((_T_ *)my_new((size_t)(_size_) * sizeof(_T_)))
+
+/*
+inline const char* MyStringGetNextCharPointer(const char *p) throw()
+{
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ return CharNextA(p);
+ #else
+ return p + 1;
+ #endif
+}
+*/
+
+#define MY_STRING_NEW_char(_size_) MY_STRING_NEW(char, (_size_))
+#define MY_STRING_NEW_wchar_t(_size_) MY_STRING_NEW(wchar_t, (_size_))
+
+
+int FindCharPosInString(const char *s, char c) throw()
+{
+ for (const char *p = s;; p++)
+ {
+ if (*p == c)
+ return (int)(p - s);
+ if (*p == 0)
+ return -1;
+ // MyStringGetNextCharPointer(p);
+ }
+}
+
+int FindCharPosInString(const wchar_t *s, wchar_t c) throw()
+{
+ for (const wchar_t *p = s;; p++)
+ {
+ if (*p == c)
+ return (int)(p - s);
+ if (*p == 0)
+ return -1;
+ }
+}
+
+/*
+void MyStringUpper_Ascii(char *s) throw()
+{
+ for (;;)
+ {
+ char c = *s;
+ if (c == 0)
+ return;
+ *s++ = MyCharUpper_Ascii(c);
+ }
+}
+
+void MyStringUpper_Ascii(wchar_t *s) throw()
+{
+ for (;;)
+ {
+ wchar_t c = *s;
+ if (c == 0)
+ return;
+ *s++ = MyCharUpper_Ascii(c);
+ }
+}
+*/
+
+void MyStringLower_Ascii(char *s) throw()
+{
+ for (;;)
+ {
+ char c = *s;
+ if (c == 0)
+ return;
+ *s++ = MyCharLower_Ascii(c);
+ }
+}
+
+void MyStringLower_Ascii(wchar_t *s) throw()
+{
+ for (;;)
+ {
+ wchar_t c = *s;
+ if (c == 0)
+ return;
+ *s++ = MyCharLower_Ascii(c);
+ }
+}
+
+#ifdef _WIN32
+
+#ifdef _UNICODE
+
+// wchar_t * MyStringUpper(wchar_t *s) { return CharUpperW(s); }
+// wchar_t * MyStringLower(wchar_t *s) { return CharLowerW(s); }
+// for WinCE - FString - char
+// const char *MyStringGetPrevCharPointer(const char * /* base */, const char *p) { return p - 1; }
+
+#else
+
+// const char * MyStringGetPrevCharPointer(const char *base, const char *p) throw() { return CharPrevA(base, p); }
+// char * MyStringUpper(char *s) { return CharUpperA(s); }
+// char * MyStringLower(char *s) { return CharLowerA(s); }
+
+wchar_t MyCharUpper_WIN(wchar_t c) throw()
+{
+ wchar_t *res = CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c);
+ if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return (wchar_t)(unsigned)(UINT_PTR)res;
+ const int kBufSize = 4;
+ char s[kBufSize + 1];
+ int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0);
+ if (numChars == 0 || numChars > kBufSize)
+ return c;
+ s[numChars] = 0;
+ ::CharUpperA(s);
+ ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1);
+ return c;
+}
+
+/*
+wchar_t MyCharLower_WIN(wchar_t c)
+{
+ wchar_t *res = CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c);
+ if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return (wchar_t)(unsigned)(UINT_PTR)res;
+ const int kBufSize = 4;
+ char s[kBufSize + 1];
+ int numChars = ::WideCharToMultiByte(CP_ACP, 0, &c, 1, s, kBufSize, 0, 0);
+ if (numChars == 0 || numChars > kBufSize)
+ return c;
+ s[numChars] = 0;
+ ::CharLowerA(s);
+ ::MultiByteToWideChar(CP_ACP, 0, s, numChars, &c, 1);
+ return c;
+}
+*/
+
+/*
+wchar_t * MyStringUpper(wchar_t *s)
+{
+ if (s == 0)
+ return 0;
+ wchar_t *res = CharUpperW(s);
+ if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return res;
+ AString a = UnicodeStringToMultiByte(s);
+ a.MakeUpper();
+ MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a));
+ return s;
+}
+*/
+
+/*
+wchar_t * MyStringLower(wchar_t *s)
+{
+ if (s == 0)
+ return 0;
+ wchar_t *res = CharLowerW(s);
+ if (res != 0 || ::GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+ return res;
+ AString a = UnicodeStringToMultiByte(s);
+ a.MakeLower();
+ MyStringCopy(s, (const wchar_t *)MultiByteToUnicodeString(a));
+ return s;
+}
+*/
+
+#endif
+
+#endif
+
+bool IsString1PrefixedByString2(const char *s1, const char *s2) throw()
+{
+ for (;;)
+ {
+ const unsigned char c2 = (unsigned char)*s2++; if (c2 == 0) return true;
+ const unsigned char c1 = (unsigned char)*s1++; if (c1 != c2) return false;
+ }
+}
+
+bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw()
+{
+ for (;;)
+ {
+ const wchar_t c1 = *s1++;
+ const wchar_t c2 = *s2++;
+ if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2)) return false;
+ if (c1 == 0) return true;
+ }
+}
+
+// ---------- ASCII ----------
+
+bool AString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw()
+{
+ const char *s1 = _chars;
+ for (;;)
+ {
+ const char c2 = *s++;
+ if (c2 == 0)
+ return true;
+ const char c1 = *s1++;
+ if (MyCharLower_Ascii(c1) !=
+ MyCharLower_Ascii(c2))
+ return false;
+ }
+}
+
+bool UString::IsPrefixedBy_Ascii_NoCase(const char *s) const throw()
+{
+ const wchar_t *s1 = _chars;
+ for (;;)
+ {
+ const char c2 = *s++;
+ if (c2 == 0)
+ return true;
+ const wchar_t c1 = *s1++;
+ if (MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))
+ return false;
+ }
+}
+
+bool StringsAreEqual_Ascii(const char *u, const char *a) throw()
+{
+ for (;;)
+ {
+ const char c = *a;
+ if (c != *u)
+ return false;
+ if (c == 0)
+ return true;
+ a++;
+ u++;
+ }
+}
+
+bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw()
+{
+ for (;;)
+ {
+ const unsigned char c = (unsigned char)*a;
+ if (c != *u)
+ return false;
+ if (c == 0)
+ return true;
+ a++;
+ u++;
+ }
+}
+
+bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw()
+{
+ for (;;)
+ {
+ const char c1 = *s1++;
+ const char c2 = *s2++;
+ if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2))
+ return false;
+ if (c1 == 0)
+ return true;
+ }
+}
+
+bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw()
+{
+ for (;;)
+ {
+ const wchar_t c1 = *s1++;
+ const wchar_t c2 = *s2++;
+ if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2))
+ return false;
+ if (c1 == 0)
+ return true;
+ }
+}
+
+bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw()
+{
+ for (;;)
+ {
+ const wchar_t c1 = *s1++;
+ const char c2 = *s2++;
+ if (c1 != (unsigned char)c2 && (c1 > 0x7F || MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2)))
+ return false;
+ if (c1 == 0)
+ return true;
+ }
+}
+
+bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw()
+{
+ for (;;)
+ {
+ const wchar_t c2 = *s2++; if (c2 == 0) return true;
+ const wchar_t c1 = *s1++; if (c1 != c2) return false;
+ }
+}
+
+bool IsString1PrefixedByString2(const wchar_t *s1, const char *s2) throw()
+{
+ for (;;)
+ {
+ const unsigned char c2 = (unsigned char)(*s2++); if (c2 == 0) return true;
+ const wchar_t c1 = *s1++; if (c1 != c2) return false;
+ }
+}
+
+bool IsString1PrefixedByString2_NoCase_Ascii(const char *s1, const char *s2) throw()
+{
+ for (;;)
+ {
+ const char c2 = *s2++; if (c2 == 0) return true;
+ const char c1 = *s1++;
+ if (c1 != c2 && MyCharLower_Ascii(c1) != MyCharLower_Ascii(c2))
+ return false;
+ }
+}
+
+bool IsString1PrefixedByString2_NoCase_Ascii(const wchar_t *s1, const char *s2) throw()
+{
+ for (;;)
+ {
+ const char c2 = *s2++; if (c2 == 0) return true;
+ const wchar_t c1 = *s1++;
+ if (c1 != (unsigned char)c2 && MyCharLower_Ascii(c1) != (unsigned char)MyCharLower_Ascii(c2))
+ return false;
+ }
+}
+
+bool IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2) throw()
+{
+ for (;;)
+ {
+ const wchar_t c2 = *s2++; if (c2 == 0) return true;
+ const wchar_t c1 = *s1++;
+ if (c1 != c2 && MyCharUpper(c1) != MyCharUpper(c2))
+ return false;
+ }
+}
+
+// NTFS order: uses upper case
+int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw()
+{
+ for (;;)
+ {
+ const wchar_t c1 = *s1++;
+ const wchar_t c2 = *s2++;
+ if (c1 != c2)
+ {
+ const wchar_t u1 = MyCharUpper(c1);
+ const wchar_t u2 = MyCharUpper(c2);
+ if (u1 < u2) return -1;
+ if (u1 > u2) return 1;
+ }
+ if (c1 == 0) return 0;
+ }
+}
+
+/*
+int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num)
+{
+ for (; num != 0; num--)
+ {
+ wchar_t c1 = *s1++;
+ wchar_t c2 = *s2++;
+ if (c1 != c2)
+ {
+ wchar_t u1 = MyCharUpper(c1);
+ wchar_t u2 = MyCharUpper(c2);
+ if (u1 < u2) return -1;
+ if (u1 > u2) return 1;
+ }
+ if (c1 == 0) return 0;
+ }
+ return 0;
+}
+*/
+
+// ---------- AString ----------
+
+void AString::InsertSpace(unsigned &index, unsigned size)
+{
+ Grow(size);
+ MoveItems(index + size, index);
+}
+
+#define k_Alloc_Len_Limit (0x40000000 - 2)
+
+void AString::ReAlloc(unsigned newLimit)
+{
+ // MY_STRING_REALLOC(_chars, char, (size_t)newLimit + 1, (size_t)_len + 1);
+ char *newBuf = MY_STRING_NEW_char((size_t)newLimit + 1);
+ memcpy(newBuf, _chars, (size_t)_len + 1);
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ _limit = newLimit;
+}
+
+void AString::ReAlloc2(unsigned newLimit)
+{
+ if (newLimit > k_Alloc_Len_Limit) throw 20130220;
+ // MY_STRING_REALLOC(_chars, char, (size_t)newLimit + 1, 0);
+ char *newBuf = MY_STRING_NEW_char((size_t)newLimit + 1);
+ newBuf[0] = 0;
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ _limit = newLimit;
+ _len = 0;
+}
+
+void AString::SetStartLen(unsigned len)
+{
+ _chars = NULL;
+ _chars = MY_STRING_NEW_char((size_t)len + 1);
+ _len = len;
+ _limit = len;
+}
+
+void AString::Grow_1()
+{
+ unsigned next = _len;
+ next += next / 2;
+ next += 16;
+ next &= ~(unsigned)15;
+ next--;
+ if (next < _len || next > k_Alloc_Len_Limit)
+ next = k_Alloc_Len_Limit;
+ if (next <= _len)
+ throw 20130220;
+ ReAlloc(next);
+ // Grow(1);
+}
+
+void AString::Grow(unsigned n)
+{
+ const unsigned freeSize = _limit - _len;
+ if (n <= freeSize)
+ return;
+ unsigned next = _len + n;
+ next += next / 2;
+ next += 16;
+ next &= ~(unsigned)15;
+ next--;
+ if (next < _len || next > k_Alloc_Len_Limit)
+ next = k_Alloc_Len_Limit;
+ if (next <= _len || next - _len < n)
+ throw 20130220;
+ ReAlloc(next);
+}
+
+AString::AString(unsigned num, const char *s)
+{
+ unsigned len = MyStringLen(s);
+ if (num > len)
+ num = len;
+ SetStartLen(num);
+ memcpy(_chars, s, num);
+ _chars[num] = 0;
+}
+
+AString::AString(unsigned num, const AString &s)
+{
+ if (num > s._len)
+ num = s._len;
+ SetStartLen(num);
+ memcpy(_chars, s._chars, num);
+ _chars[num] = 0;
+}
+
+AString::AString(const AString &s, char c)
+{
+ SetStartLen(s.Len() + 1);
+ char *chars = _chars;
+ unsigned len = s.Len();
+ memcpy(chars, s, len);
+ chars[len] = c;
+ chars[(size_t)len + 1] = 0;
+}
+
+AString::AString(const char *s1, unsigned num1, const char *s2, unsigned num2)
+{
+ SetStartLen(num1 + num2);
+ char *chars = _chars;
+ memcpy(chars, s1, num1);
+ memcpy(chars + num1, s2, num2 + 1);
+}
+
+AString operator+(const AString &s1, const AString &s2) { return AString(s1, s1.Len(), s2, s2.Len()); }
+AString operator+(const AString &s1, const char *s2) { return AString(s1, s1.Len(), s2, MyStringLen(s2)); }
+AString operator+(const char *s1, const AString &s2) { return AString(s1, MyStringLen(s1), s2, s2.Len()); }
+
+static const unsigned kStartStringCapacity = 4;
+
+AString::AString()
+{
+ _chars = NULL;
+ _chars = MY_STRING_NEW_char(kStartStringCapacity);
+ _len = 0;
+ _limit = kStartStringCapacity - 1;
+ _chars[0] = 0;
+}
+
+AString::AString(char c)
+{
+ SetStartLen(1);
+ char *chars = _chars;
+ chars[0] = c;
+ chars[1] = 0;
+}
+
+AString::AString(const char *s)
+{
+ SetStartLen(MyStringLen(s));
+ MyStringCopy(_chars, s);
+}
+
+AString::AString(const AString &s)
+{
+ SetStartLen(s._len);
+ MyStringCopy(_chars, s._chars);
+}
+
+AString &AString::operator=(char c)
+{
+ if (1 > _limit)
+ {
+ char *newBuf = MY_STRING_NEW_char(1 + 1);
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ _limit = 1;
+ }
+ _len = 1;
+ char *chars = _chars;
+ chars[0] = c;
+ chars[1] = 0;
+ return *this;
+}
+
+AString &AString::operator=(const char *s)
+{
+ unsigned len = MyStringLen(s);
+ if (len > _limit)
+ {
+ char *newBuf = MY_STRING_NEW_char((size_t)len + 1);
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ _limit = len;
+ }
+ _len = len;
+ MyStringCopy(_chars, s);
+ return *this;
+}
+
+AString &AString::operator=(const AString &s)
+{
+ if (&s == this)
+ return *this;
+ unsigned len = s._len;
+ if (len > _limit)
+ {
+ char *newBuf = MY_STRING_NEW_char((size_t)len + 1);
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ _limit = len;
+ }
+ _len = len;
+ MyStringCopy(_chars, s._chars);
+ return *this;
+}
+
+void AString::SetFromWStr_if_Ascii(const wchar_t *s)
+{
+ unsigned len = 0;
+ {
+ for (;; len++)
+ {
+ wchar_t c = s[len];
+ if (c == 0)
+ break;
+ if (c >= 0x80)
+ return;
+ }
+ }
+ if (len > _limit)
+ {
+ char *newBuf = MY_STRING_NEW_char((size_t)len + 1);
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ _limit = len;
+ }
+ _len = len;
+ char *dest = _chars;
+ unsigned i;
+ for (i = 0; i < len; i++)
+ dest[i] = (char)s[i];
+ dest[i] = 0;
+}
+
+/*
+void AString::SetFromBstr_if_Ascii(BSTR s)
+{
+ unsigned len = ::SysStringLen(s);
+ {
+ for (unsigned i = 0; i < len; i++)
+ if (s[i] <= 0 || s[i] >= 0x80)
+ return;
+ }
+ if (len > _limit)
+ {
+ char *newBuf = MY_STRING_NEW_char((size_t)len + 1);
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ _limit = len;
+ }
+ _len = len;
+ char *dest = _chars;
+ unsigned i;
+ for (i = 0; i < len; i++)
+ dest[i] = (char)s[i];
+ dest[i] = 0;
+}
+*/
+
+void AString::Add_Space() { operator+=(' '); }
+void AString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); }
+void AString::Add_LF() { operator+=('\n'); }
+void AString::Add_Slash() { operator+=('/'); }
+void AString::Add_Dot() { operator+=('.'); }
+void AString::Add_Minus() { operator+=('-'); }
+
+AString &AString::operator+=(const char *s)
+{
+ unsigned len = MyStringLen(s);
+ Grow(len);
+ MyStringCopy(_chars + _len, s);
+ _len += len;
+ return *this;
+}
+
+void AString::Add_OptSpaced(const char *s)
+{
+ Add_Space_if_NotEmpty();
+ (*this) += s;
+}
+
+AString &AString::operator+=(const AString &s)
+{
+ Grow(s._len);
+ MyStringCopy(_chars + _len, s._chars);
+ _len += s._len;
+ return *this;
+}
+
+void AString::Add_UInt32(UInt32 v)
+{
+ Grow(10);
+ _len = (unsigned)(ConvertUInt32ToString(v, _chars + _len) - _chars);
+}
+
+void UString::Add_UInt64(UInt64 v)
+{
+ Grow(20);
+ _len = (unsigned)(ConvertUInt64ToString(v, _chars + _len) - _chars);
+}
+
+void AString::AddFrom(const char *s, unsigned len) // no check
+{
+ if (len != 0)
+ {
+ Grow(len);
+ memcpy(_chars + _len, s, len);
+ len += _len;
+ _chars[len] = 0;
+ _len = len;
+ }
+}
+
+void AString::SetFrom(const char *s, unsigned len) // no check
+{
+ if (len > _limit)
+ {
+ char *newBuf = MY_STRING_NEW_char((size_t)len + 1);
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ _limit = len;
+ }
+ if (len != 0)
+ memcpy(_chars, s, len);
+ _chars[len] = 0;
+ _len = len;
+}
+
+void AString::SetFrom_CalcLen(const char *s, unsigned len) // no check
+{
+ unsigned i;
+ for (i = 0; i < len; i++)
+ if (s[i] == 0)
+ break;
+ SetFrom(s, i);
+}
+
+int AString::Find(const char *s, unsigned startIndex) const throw()
+{
+ const char *fs = strstr(_chars + startIndex, s);
+ if (!fs)
+ return -1;
+ return (int)(fs - _chars);
+
+ /*
+ if (s[0] == 0)
+ return startIndex;
+ unsigned len = MyStringLen(s);
+ const char *p = _chars + startIndex;
+ for (;; p++)
+ {
+ const char c = *p;
+ if (c != s[0])
+ {
+ if (c == 0)
+ return -1;
+ continue;
+ }
+ unsigned i;
+ for (i = 1; i < len; i++)
+ if (p[i] != s[i])
+ break;
+ if (i == len)
+ return (int)(p - _chars);
+ }
+ */
+}
+
+int AString::ReverseFind(char c) const throw()
+{
+ if (_len == 0)
+ return -1;
+ const char *p = _chars + _len - 1;
+ for (;;)
+ {
+ if (*p == c)
+ return (int)(p - _chars);
+ if (p == _chars)
+ return -1;
+ p--; // p = GetPrevCharPointer(_chars, p);
+ }
+}
+
+int AString::ReverseFind_PathSepar() const throw()
+{
+ if (_len == 0)
+ return -1;
+ const char *p = _chars + _len - 1;
+ for (;;)
+ {
+ const char c = *p;
+ if (IS_PATH_SEPAR(c))
+ return (int)(p - _chars);
+ if (p == _chars)
+ return -1;
+ p--;
+ }
+}
+
+void AString::TrimLeft() throw()
+{
+ const char *p = _chars;
+ for (;; p++)
+ {
+ char c = *p;
+ if (c != ' ' && c != '\n' && c != '\t')
+ break;
+ }
+ unsigned pos = (unsigned)(p - _chars);
+ if (pos != 0)
+ {
+ MoveItems(0, pos);
+ _len -= pos;
+ }
+}
+
+void AString::TrimRight() throw()
+{
+ const char *p = _chars;
+ unsigned i;
+ for (i = _len; i != 0; i--)
+ {
+ char c = p[(size_t)i - 1];
+ if (c != ' ' && c != '\n' && c != '\t')
+ break;
+ }
+ if (i != _len)
+ {
+ _chars[i] = 0;
+ _len = i;
+ }
+}
+
+void AString::InsertAtFront(char c)
+{
+ if (_limit == _len)
+ Grow_1();
+ MoveItems(1, 0);
+ _chars[0] = c;
+ _len++;
+}
+
+/*
+void AString::Insert(unsigned index, char c)
+{
+ InsertSpace(index, 1);
+ _chars[index] = c;
+ _len++;
+}
+*/
+
+void AString::Insert(unsigned index, const char *s)
+{
+ unsigned num = MyStringLen(s);
+ if (num != 0)
+ {
+ InsertSpace(index, num);
+ memcpy(_chars + index, s, num);
+ _len += num;
+ }
+}
+
+void AString::Insert(unsigned index, const AString &s)
+{
+ unsigned num = s.Len();
+ if (num != 0)
+ {
+ InsertSpace(index, num);
+ memcpy(_chars + index, s, num);
+ _len += num;
+ }
+}
+
+void AString::RemoveChar(char ch) throw()
+{
+ char *src = _chars;
+
+ for (;;)
+ {
+ char c = *src++;
+ if (c == 0)
+ return;
+ if (c == ch)
+ break;
+ }
+
+ char *dest = src - 1;
+
+ for (;;)
+ {
+ char c = *src++;
+ if (c == 0)
+ break;
+ if (c != ch)
+ *dest++ = c;
+ }
+
+ *dest = 0;
+ _len = (unsigned)(dest - _chars);
+}
+
+// !!!!!!!!!!!!!!! test it if newChar = '\0'
+void AString::Replace(char oldChar, char newChar) throw()
+{
+ if (oldChar == newChar)
+ return; // 0;
+ // unsigned number = 0;
+ int pos = 0;
+ char *chars = _chars;
+ while ((unsigned)pos < _len)
+ {
+ pos = Find(oldChar, (unsigned)pos);
+ if (pos < 0)
+ break;
+ chars[(unsigned)pos] = newChar;
+ pos++;
+ // number++;
+ }
+ return; // number;
+}
+
+void AString::Replace(const AString &oldString, const AString &newString)
+{
+ if (oldString.IsEmpty())
+ return; // 0;
+ if (oldString == newString)
+ return; // 0;
+ unsigned oldLen = oldString.Len();
+ unsigned newLen = newString.Len();
+ // unsigned number = 0;
+ int pos = 0;
+ while ((unsigned)pos < _len)
+ {
+ pos = Find(oldString, (unsigned)pos);
+ if (pos < 0)
+ break;
+ Delete((unsigned)pos, oldLen);
+ Insert((unsigned)pos, newString);
+ pos += newLen;
+ // number++;
+ }
+ // return number;
+}
+
+void AString::Delete(unsigned index) throw()
+{
+ MoveItems(index, index + 1);
+ _len--;
+}
+
+void AString::Delete(unsigned index, unsigned count) throw()
+{
+ if (index + count > _len)
+ count = _len - index;
+ if (count > 0)
+ {
+ MoveItems(index, index + count);
+ _len -= count;
+ }
+}
+
+void AString::DeleteFrontal(unsigned num) throw()
+{
+ if (num != 0)
+ {
+ MoveItems(0, num);
+ _len -= num;
+ }
+}
+
+/*
+AString operator+(const AString &s1, const AString &s2)
+{
+ AString result(s1);
+ result += s2;
+ return result;
+}
+
+AString operator+(const AString &s, const char *chars)
+{
+ AString result(s);
+ result += chars;
+ return result;
+}
+
+AString operator+(const char *chars, const AString &s)
+{
+ AString result(chars);
+ result += s;
+ return result;
+}
+
+AString operator+(const AString &s, char c)
+{
+ AString result(s);
+ result += c;
+ return result;
+}
+*/
+
+/*
+AString operator+(char c, const AString &s)
+{
+ AString result(c);
+ result += s;
+ return result;
+}
+*/
+
+
+
+
+// ---------- UString ----------
+
+void UString::InsertSpace(unsigned index, unsigned size)
+{
+ Grow(size);
+ MoveItems(index + size, index);
+}
+
+void UString::ReAlloc(unsigned newLimit)
+{
+ // MY_STRING_REALLOC(_chars, wchar_t, (size_t)newLimit + 1, (size_t)_len + 1);
+ wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)newLimit + 1);
+ wmemcpy(newBuf, _chars, _len + 1);
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ _limit = newLimit;
+}
+
+void UString::ReAlloc2(unsigned newLimit)
+{
+ if (newLimit > k_Alloc_Len_Limit) throw 20130221;
+ // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0);
+ wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)newLimit + 1);
+ newBuf[0] = 0;
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ _limit = newLimit;
+ _len = 0;
+}
+
+void UString::SetStartLen(unsigned len)
+{
+ _chars = NULL;
+ _chars = MY_STRING_NEW_wchar_t((size_t)len + 1);
+ _len = len;
+ _limit = len;
+}
+
+void UString::Grow_1()
+{
+ unsigned next = _len;
+ next += next / 2;
+ next += 16;
+ next &= ~(unsigned)15;
+ next--;
+ if (next < _len || next > k_Alloc_Len_Limit)
+ next = k_Alloc_Len_Limit;
+ if (next <= _len)
+ throw 20130220;
+ ReAlloc(next);
+}
+
+void UString::Grow(unsigned n)
+{
+ const unsigned freeSize = _limit - _len;
+ if (n <= freeSize)
+ return;
+ unsigned next = _len + n;
+ next += next / 2;
+ next += 16;
+ next &= ~(unsigned)15;
+ next--;
+ if (next < _len || next > k_Alloc_Len_Limit)
+ next = k_Alloc_Len_Limit;
+ if (next <= _len || next - _len < n)
+ throw 20130220;
+ ReAlloc(next - 1);
+}
+
+
+UString::UString(unsigned num, const wchar_t *s)
+{
+ unsigned len = MyStringLen(s);
+ if (num > len)
+ num = len;
+ SetStartLen(num);
+ wmemcpy(_chars, s, num);
+ _chars[num] = 0;
+}
+
+
+UString::UString(unsigned num, const UString &s)
+{
+ if (num > s._len)
+ num = s._len;
+ SetStartLen(num);
+ wmemcpy(_chars, s._chars, num);
+ _chars[num] = 0;
+}
+
+UString::UString(const UString &s, wchar_t c)
+{
+ SetStartLen(s.Len() + 1);
+ wchar_t *chars = _chars;
+ unsigned len = s.Len();
+ wmemcpy(chars, s, len);
+ chars[len] = c;
+ chars[(size_t)len + 1] = 0;
+}
+
+UString::UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2)
+{
+ SetStartLen(num1 + num2);
+ wchar_t *chars = _chars;
+ wmemcpy(chars, s1, num1);
+ wmemcpy(chars + num1, s2, num2 + 1);
+}
+
+UString operator+(const UString &s1, const UString &s2) { return UString(s1, s1.Len(), s2, s2.Len()); }
+UString operator+(const UString &s1, const wchar_t *s2) { return UString(s1, s1.Len(), s2, MyStringLen(s2)); }
+UString operator+(const wchar_t *s1, const UString &s2) { return UString(s1, MyStringLen(s1), s2, s2.Len()); }
+
+UString::UString()
+{
+ _chars = NULL;
+ _chars = MY_STRING_NEW_wchar_t(kStartStringCapacity);
+ _len = 0;
+ _limit = kStartStringCapacity - 1;
+ _chars[0] = 0;
+}
+
+UString::UString(wchar_t c)
+{
+ SetStartLen(1);
+ wchar_t *chars = _chars;
+ chars[0] = c;
+ chars[1] = 0;
+}
+
+UString::UString(char c)
+{
+ SetStartLen(1);
+ wchar_t *chars = _chars;
+ chars[0] = (unsigned char)c;
+ chars[1] = 0;
+}
+
+UString::UString(const wchar_t *s)
+{
+ const unsigned len = MyStringLen(s);
+ SetStartLen(len);
+ wmemcpy(_chars, s, len + 1);
+}
+
+UString::UString(const char *s)
+{
+ const unsigned len = MyStringLen(s);
+ SetStartLen(len);
+ wchar_t *chars = _chars;
+ for (unsigned i = 0; i < len; i++)
+ chars[i] = (unsigned char)s[i];
+ chars[len] = 0;
+}
+
+UString::UString(const AString &s)
+{
+ const unsigned len = s.Len();
+ SetStartLen(len);
+ wchar_t *chars = _chars;
+ const char *s2 = s.Ptr();
+ for (unsigned i = 0; i < len; i++)
+ chars[i] = (unsigned char)s2[i];
+ chars[len] = 0;
+}
+
+UString::UString(const UString &s)
+{
+ SetStartLen(s._len);
+ wmemcpy(_chars, s._chars, s._len + 1);
+}
+
+UString &UString::operator=(wchar_t c)
+{
+ if (1 > _limit)
+ {
+ wchar_t *newBuf = MY_STRING_NEW_wchar_t(1 + 1);
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ _limit = 1;
+ }
+ _len = 1;
+ wchar_t *chars = _chars;
+ chars[0] = c;
+ chars[1] = 0;
+ return *this;
+}
+
+UString &UString::operator=(const wchar_t *s)
+{
+ unsigned len = MyStringLen(s);
+ if (len > _limit)
+ {
+ wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1);
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ _limit = len;
+ }
+ _len = len;
+ wmemcpy(_chars, s, len + 1);
+ return *this;
+}
+
+UString &UString::operator=(const UString &s)
+{
+ if (&s == this)
+ return *this;
+ unsigned len = s._len;
+ if (len > _limit)
+ {
+ wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1);
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ _limit = len;
+ }
+ _len = len;
+ wmemcpy(_chars, s._chars, len + 1);
+ return *this;
+}
+
+void UString::SetFrom(const wchar_t *s, unsigned len) // no check
+{
+ if (len > _limit)
+ {
+ wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1);
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ _limit = len;
+ }
+ if (len != 0)
+ wmemcpy(_chars, s, len);
+ _chars[len] = 0;
+ _len = len;
+}
+
+void UString::SetFromBstr(LPCOLESTR s)
+{
+ unsigned len = ::SysStringLen((BSTR)(void *)(s));
+
+ /*
+ #if WCHAR_MAX > 0xffff
+ size_t num_wchars = 0;
+ for (size_t i = 0; i < len;)
+ {
+ wchar_t c = s[i++];
+ if (c >= 0xd800 && c < 0xdc00 && i + 1 != len)
+ {
+ wchar_t c2 = s[i];
+ if (c2 >= 0xdc00 && c2 < 0x10000)
+ {
+ c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff);
+ i++;
+ }
+ }
+ num_wchars++;
+ }
+ len = num_wchars;
+ #endif
+ */
+
+ if (len > _limit)
+ {
+ wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1);
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ _limit = len;
+ }
+ _len = len;
+
+ /*
+ #if WCHAR_MAX > 0xffff
+
+ wchar_t *chars = _chars;
+ for (size_t i = 0; i <= len; i++)
+ {
+ wchar_t c = *s++;
+ if (c >= 0xd800 && c < 0xdc00 && i + 1 != len)
+ {
+ wchar_t c2 = *s;
+ if (c2 >= 0xdc00 && c2 < 0x10000)
+ {
+ s++;
+ c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff);
+ }
+ }
+ chars[i] = c;
+ }
+
+ #else
+ */
+
+ // if (s)
+ wmemcpy(_chars, s, len + 1);
+
+ // #endif
+}
+
+UString &UString::operator=(const char *s)
+{
+ unsigned len = MyStringLen(s);
+ if (len > _limit)
+ {
+ wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1);
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ _limit = len;
+ }
+ wchar_t *chars = _chars;
+ for (unsigned i = 0; i < len; i++)
+ chars[i] = (unsigned char)s[i];
+ chars[len] = 0;
+ _len = len;
+ return *this;
+}
+
+void UString::Add_Dot() { operator+=(L'.'); }
+void UString::Add_Space() { operator+=(L' '); }
+void UString::Add_Space_if_NotEmpty() { if (!IsEmpty()) Add_Space(); }
+
+void UString::Add_LF()
+{
+ if (_limit == _len)
+ Grow_1();
+ unsigned len = _len;
+ wchar_t *chars = _chars;
+ chars[len++] = L'\n';
+ chars[len] = 0;
+ _len = len;
+}
+
+UString &UString::operator+=(const wchar_t *s)
+{
+ unsigned len = MyStringLen(s);
+ Grow(len);
+ wmemcpy(_chars + _len, s, len + 1);
+ _len += len;
+ return *this;
+}
+
+UString &UString::operator+=(const UString &s)
+{
+ Grow(s._len);
+ wmemcpy(_chars + _len, s._chars, s._len + 1);
+ _len += s._len;
+ return *this;
+}
+
+UString &UString::operator+=(const char *s)
+{
+ unsigned len = MyStringLen(s);
+ Grow(len);
+ wchar_t *chars = _chars + _len;
+ for (unsigned i = 0; i < len; i++)
+ chars[i] = (unsigned char)s[i];
+ chars[len] = 0;
+ _len += len;
+ return *this;
+}
+
+
+void UString::Add_UInt32(UInt32 v)
+{
+ Grow(10);
+ _len = (unsigned)(ConvertUInt32ToString(v, _chars + _len) - _chars);
+}
+
+void AString::Add_UInt64(UInt64 v)
+{
+ Grow(20);
+ _len = (unsigned)(ConvertUInt64ToString(v, _chars + _len) - _chars);
+}
+
+
+int UString::Find(const wchar_t *s, unsigned startIndex) const throw()
+{
+ const wchar_t *fs = wcsstr(_chars + startIndex, s);
+ if (!fs)
+ return -1;
+ return (int)(fs - _chars);
+
+ /*
+ if (s[0] == 0)
+ return startIndex;
+ unsigned len = MyStringLen(s);
+ const wchar_t *p = _chars + startIndex;
+ for (;; p++)
+ {
+ const wchar_t c = *p;
+ if (c != s[0])
+ {
+ if (c == 0)
+ return -1;
+ continue;
+ }
+ unsigned i;
+ for (i = 1; i < len; i++)
+ if (p[i] != s[i])
+ break;
+ if (i == len)
+ return (int)(p - _chars);
+ }
+ */
+}
+
+int UString::ReverseFind(wchar_t c) const throw()
+{
+ if (_len == 0)
+ return -1;
+ const wchar_t *p = _chars + _len;
+ do
+ {
+ if (*(--p) == c)
+ return (int)(p - _chars);
+ }
+ while (p != _chars);
+ return -1;
+}
+
+int UString::ReverseFind_PathSepar() const throw()
+{
+ const wchar_t *p = _chars + _len;
+ while (p != _chars)
+ {
+ const wchar_t c = *(--p);
+ if (IS_PATH_SEPAR(c))
+ return (int)(p - _chars);
+ }
+ return -1;
+}
+
+void UString::TrimLeft() throw()
+{
+ const wchar_t *p = _chars;
+ for (;; p++)
+ {
+ wchar_t c = *p;
+ if (c != ' ' && c != '\n' && c != '\t')
+ break;
+ }
+ unsigned pos = (unsigned)(p - _chars);
+ if (pos != 0)
+ {
+ MoveItems(0, pos);
+ _len -= pos;
+ }
+}
+
+void UString::TrimRight() throw()
+{
+ const wchar_t *p = _chars;
+ unsigned i;
+ for (i = _len; i != 0; i--)
+ {
+ wchar_t c = p[(size_t)i - 1];
+ if (c != ' ' && c != '\n' && c != '\t')
+ break;
+ }
+ if (i != _len)
+ {
+ _chars[i] = 0;
+ _len = i;
+ }
+}
+
+void UString::InsertAtFront(wchar_t c)
+{
+ if (_limit == _len)
+ Grow_1();
+ MoveItems(1, 0);
+ _chars[0] = c;
+ _len++;
+}
+
+/*
+void UString::Insert_wchar_t(unsigned index, wchar_t c)
+{
+ InsertSpace(index, 1);
+ _chars[index] = c;
+ _len++;
+}
+*/
+
+void UString::Insert(unsigned index, const wchar_t *s)
+{
+ unsigned num = MyStringLen(s);
+ if (num != 0)
+ {
+ InsertSpace(index, num);
+ wmemcpy(_chars + index, s, num);
+ _len += num;
+ }
+}
+
+void UString::Insert(unsigned index, const UString &s)
+{
+ unsigned num = s.Len();
+ if (num != 0)
+ {
+ InsertSpace(index, num);
+ wmemcpy(_chars + index, s, num);
+ _len += num;
+ }
+}
+
+void UString::RemoveChar(wchar_t ch) throw()
+{
+ wchar_t *src = _chars;
+
+ for (;;)
+ {
+ wchar_t c = *src++;
+ if (c == 0)
+ return;
+ if (c == ch)
+ break;
+ }
+
+ wchar_t *dest = src - 1;
+
+ for (;;)
+ {
+ wchar_t c = *src++;
+ if (c == 0)
+ break;
+ if (c != ch)
+ *dest++ = c;
+ }
+
+ *dest = 0;
+ _len = (unsigned)(dest - _chars);
+}
+
+// !!!!!!!!!!!!!!! test it if newChar = '\0'
+void UString::Replace(wchar_t oldChar, wchar_t newChar) throw()
+{
+ if (oldChar == newChar)
+ return; // 0;
+ // unsigned number = 0;
+ int pos = 0;
+ wchar_t *chars = _chars;
+ while ((unsigned)pos < _len)
+ {
+ pos = Find(oldChar, (unsigned)pos);
+ if (pos < 0)
+ break;
+ chars[(unsigned)pos] = newChar;
+ pos++;
+ // number++;
+ }
+ return; // number;
+}
+
+void UString::Replace(const UString &oldString, const UString &newString)
+{
+ if (oldString.IsEmpty())
+ return; // 0;
+ if (oldString == newString)
+ return; // 0;
+ unsigned oldLen = oldString.Len();
+ unsigned newLen = newString.Len();
+ // unsigned number = 0;
+ int pos = 0;
+ while ((unsigned)pos < _len)
+ {
+ pos = Find(oldString, (unsigned)pos);
+ if (pos < 0)
+ break;
+ Delete((unsigned)pos, oldLen);
+ Insert((unsigned)pos, newString);
+ pos += newLen;
+ // number++;
+ }
+ // return number;
+}
+
+void UString::Delete(unsigned index) throw()
+{
+ MoveItems(index, index + 1);
+ _len--;
+}
+
+void UString::Delete(unsigned index, unsigned count) throw()
+{
+ if (index + count > _len)
+ count = _len - index;
+ if (count > 0)
+ {
+ MoveItems(index, index + count);
+ _len -= count;
+ }
+}
+
+void UString::DeleteFrontal(unsigned num) throw()
+{
+ if (num != 0)
+ {
+ MoveItems(0, num);
+ _len -= num;
+ }
+}
+
+
+// ---------- UString2 ----------
+
+void UString2::ReAlloc2(unsigned newLimit)
+{
+ // wrong (_len) is allowed after this function
+ if (newLimit > k_Alloc_Len_Limit) throw 20130221;
+ // MY_STRING_REALLOC(_chars, wchar_t, newLimit + 1, 0);
+ if (_chars)
+ {
+ MY_STRING_DELETE(_chars)
+ _chars = NULL;
+ // _len = 0;
+ }
+ _chars = MY_STRING_NEW_wchar_t((size_t)newLimit + 1);
+ _chars[0] = 0;
+ // _len = newLimit;
+}
+
+void UString2::SetStartLen(unsigned len)
+{
+ _chars = NULL;
+ _chars = MY_STRING_NEW_wchar_t((size_t)len + 1);
+ _len = len;
+}
+
+
+/*
+UString2::UString2(wchar_t c)
+{
+ SetStartLen(1);
+ wchar_t *chars = _chars;
+ chars[0] = c;
+ chars[1] = 0;
+}
+*/
+
+UString2::UString2(const wchar_t *s)
+{
+ const unsigned len = MyStringLen(s);
+ SetStartLen(len);
+ wmemcpy(_chars, s, len + 1);
+}
+
+UString2::UString2(const UString2 &s): _chars(NULL), _len(0)
+{
+ if (s._chars)
+ {
+ SetStartLen(s._len);
+ wmemcpy(_chars, s._chars, s._len + 1);
+ }
+}
+
+/*
+UString2 &UString2::operator=(wchar_t c)
+{
+ if (1 > _len)
+ {
+ wchar_t *newBuf = MY_STRING_NEW_wchar_t(1 + 1);
+ if (_chars)
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ }
+ _len = 1;
+ wchar_t *chars = _chars;
+ chars[0] = c;
+ chars[1] = 0;
+ return *this;
+}
+*/
+
+UString2 &UString2::operator=(const wchar_t *s)
+{
+ unsigned len = MyStringLen(s);
+ if (len > _len)
+ {
+ wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1);
+ if (_chars)
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ }
+ _len = len;
+ MyStringCopy(_chars, s);
+ return *this;
+}
+
+void UString2::SetFromAscii(const char *s)
+{
+ unsigned len = MyStringLen(s);
+ if (len > _len)
+ {
+ wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1);
+ if (_chars)
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ }
+ wchar_t *chars = _chars;
+ for (unsigned i = 0; i < len; i++)
+ chars[i] = (unsigned char)s[i];
+ chars[len] = 0;
+ _len = len;
+}
+
+UString2 &UString2::operator=(const UString2 &s)
+{
+ if (&s == this)
+ return *this;
+ unsigned len = s._len;
+ if (len > _len)
+ {
+ wchar_t *newBuf = MY_STRING_NEW_wchar_t((size_t)len + 1);
+ if (_chars)
+ MY_STRING_DELETE(_chars)
+ _chars = newBuf;
+ }
+ _len = len;
+ MyStringCopy(_chars, s._chars);
+ return *this;
+}
+
+bool operator==(const UString2 &s1, const UString2 &s2)
+{
+ return s1.Len() == s2.Len() && (s1.IsEmpty() || wcscmp(s1.GetRawPtr(), s2.GetRawPtr()) == 0);
+}
+
+bool operator==(const UString2 &s1, const wchar_t *s2)
+{
+ if (s1.IsEmpty())
+ return (*s2 == 0);
+ return wcscmp(s1.GetRawPtr(), s2) == 0;
+}
+
+bool operator==(const wchar_t *s1, const UString2 &s2)
+{
+ if (s2.IsEmpty())
+ return (*s1 == 0);
+ return wcscmp(s1, s2.GetRawPtr()) == 0;
+}
+
+
+
+// ----------------------------------------
+
+/*
+int MyStringCompareNoCase(const char *s1, const char *s2)
+{
+ return MyStringCompareNoCase(MultiByteToUnicodeString(s1), MultiByteToUnicodeString(s2));
+}
+*/
+
+#if !defined(USE_UNICODE_FSTRING) || !defined(_UNICODE)
+
+static inline UINT GetCurrentCodePage()
+{
+ #if defined(UNDER_CE) || !defined(_WIN32)
+ return CP_ACP;
+ #else
+ return ::AreFileApisANSI() ? CP_ACP : CP_OEMCP;
+ #endif
+}
+
+#endif
+
+#ifdef USE_UNICODE_FSTRING
+
+#ifndef _UNICODE
+
+AString fs2fas(CFSTR s)
+{
+ return UnicodeStringToMultiByte(s, GetCurrentCodePage());
+}
+
+FString fas2fs(const char *s)
+{
+ return MultiByteToUnicodeString(s, GetCurrentCodePage());
+}
+
+FString fas2fs(const AString &s)
+{
+ return MultiByteToUnicodeString(s, GetCurrentCodePage());
+}
+
+#endif // _UNICODE
+
+#else // USE_UNICODE_FSTRING
+
+UString fs2us(const FChar *s)
+{
+ return MultiByteToUnicodeString(s, GetCurrentCodePage());
+}
+
+UString fs2us(const FString &s)
+{
+ return MultiByteToUnicodeString(s, GetCurrentCodePage());
+}
+
+FString us2fs(const wchar_t *s)
+{
+ return UnicodeStringToMultiByte(s, GetCurrentCodePage());
+}
+
+#endif // USE_UNICODE_FSTRING
+
+
+bool CStringFinder::FindWord_In_LowCaseAsciiList_NoCase(const char *p, const wchar_t *str)
+{
+ _temp.Empty();
+ for (;;)
+ {
+ const wchar_t c = *str++;
+ if (c == 0)
+ break;
+ if (c <= 0x20 || c > 0x7f)
+ return false;
+ _temp += (char)MyCharLower_Ascii((char)c);
+ }
+
+ while (*p != 0)
+ {
+ const char *s2 = _temp.Ptr();
+ char c, c2;
+ do
+ {
+ c = *p++;
+ c2 = *s2++;
+ }
+ while (c == c2);
+
+ if (c == ' ')
+ {
+ if (c2 == 0)
+ return true;
+ continue;
+ }
+
+ while (*p++ != ' ');
+ }
+
+ return false;
+}
+
+
+void SplitString(const UString &srcString, UStringVector &destStrings)
+{
+ destStrings.Clear();
+ unsigned len = srcString.Len();
+ if (len == 0)
+ return;
+ UString s;
+ for (unsigned i = 0; i < len; i++)
+ {
+ const wchar_t c = srcString[i];
+ if (c == ' ')
+ {
+ if (!s.IsEmpty())
+ {
+ destStrings.Add(s);
+ s.Empty();
+ }
+ }
+ else
+ s += c;
+ }
+ if (!s.IsEmpty())
+ destStrings.Add(s);
+}
diff --git a/CPP/Common/MyString.h b/CPP/Common/MyString.h
index 45cea98..e5ce18a 100644
--- a/CPP/Common/MyString.h
+++ b/CPP/Common/MyString.h
@@ -1,868 +1,1064 @@
-// Common/String.h
-
-#ifndef __COMMON_STRING_H
-#define __COMMON_STRING_H
-
-#include <string.h>
-
-#ifndef _WIN32
-#include <wctype.h>
-#include <wchar.h>
-#endif
-
-#include "MyWindows.h"
-#include "MyTypes.h"
-#include "MyVector.h"
-
-
-#ifdef _MSC_VER
- #ifdef _NATIVE_WCHAR_T_DEFINED
- #define MY_NATIVE_WCHAR_T_DEFINED
- #endif
-#else
- #define MY_NATIVE_WCHAR_T_DEFINED
-#endif
-
-/*
- native support for wchar_t:
- _MSC_VER == 1600 : /Zc:wchar_t is not supported
- _MSC_VER == 1310 (VS2003)
- ? _MSC_VER == 1400 (VS2005) : wchar_t <- unsigned short
- /Zc:wchar_t : wchar_t <- __wchar_t, _WCHAR_T_DEFINED and _NATIVE_WCHAR_T_DEFINED
- _MSC_VER > 1400 (VS2008+)
- /Zc:wchar_t[-]
- /Zc:wchar_t is on by default
-*/
-
-#ifdef _WIN32
-#define IS_PATH_SEPAR(c) ((c) == '\\' || (c) == '/')
-#else
-#define IS_PATH_SEPAR(c) ((c) == CHAR_PATH_SEPARATOR)
-#endif
-
-inline bool IsPathSepar(char c) { return IS_PATH_SEPAR(c); }
-inline bool IsPathSepar(wchar_t c) { return IS_PATH_SEPAR(c); }
-
-inline unsigned MyStringLen(const char *s)
-{
- unsigned i;
- for (i = 0; s[i] != 0; i++);
- return i;
-}
-
-inline void MyStringCopy(char *dest, const char *src)
-{
- while ((*dest++ = *src++) != 0);
-}
-
-inline char *MyStpCpy(char *dest, const char *src)
-{
- for (;;)
- {
- char c = *src;
- *dest = c;
- if (c == 0)
- return dest;
- src++;
- dest++;
- }
-}
-
-inline unsigned MyStringLen(const wchar_t *s)
-{
- unsigned i;
- for (i = 0; s[i] != 0; i++);
- return i;
-}
-
-inline void MyStringCopy(wchar_t *dest, const wchar_t *src)
-{
- while ((*dest++ = *src++) != 0);
-}
-
-inline void MyStringCat(wchar_t *dest, const wchar_t *src)
-{
- MyStringCopy(dest + MyStringLen(dest), src);
-}
-
-
-/*
-inline wchar_t *MyWcpCpy(wchar_t *dest, const wchar_t *src)
-{
- for (;;)
- {
- wchar_t c = *src;
- *dest = c;
- if (c == 0)
- return dest;
- src++;
- dest++;
- }
-}
-*/
-
-int FindCharPosInString(const char *s, char c) throw();
-int FindCharPosInString(const wchar_t *s, wchar_t c) throw();
-
-#ifdef _WIN32
- #ifndef _UNICODE
- #define STRING_UNICODE_THROW
- #endif
-#endif
-
-#ifndef STRING_UNICODE_THROW
- #define STRING_UNICODE_THROW throw()
-#endif
-
-
-inline char MyCharUpper_Ascii(char c)
-{
- if (c >= 'a' && c <= 'z')
- return (char)((unsigned char)c - 0x20);
- return c;
-}
-
-/*
-inline wchar_t MyCharUpper_Ascii(wchar_t c)
-{
- if (c >= 'a' && c <= 'z')
- return (wchar_t)(c - 0x20);
- return c;
-}
-*/
-
-inline char MyCharLower_Ascii(char c)
-{
- if (c >= 'A' && c <= 'Z')
- return (char)((unsigned char)c + 0x20);
- return c;
-}
-
-inline wchar_t MyCharLower_Ascii(wchar_t c)
-{
- if (c >= 'A' && c <= 'Z')
- return (wchar_t)(c + 0x20);
- return c;
-}
-
-wchar_t MyCharUpper_WIN(wchar_t c) throw();
-
-inline wchar_t MyCharUpper(wchar_t c) throw()
-{
- if (c < 'a') return c;
- if (c <= 'z') return (wchar_t)(c - 0x20);
- if (c <= 0x7F) return c;
- #ifdef _WIN32
- #ifdef _UNICODE
- return (wchar_t)(unsigned)(UINT_PTR)CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c);
- #else
- return (wchar_t)MyCharUpper_WIN(c);
- #endif
- #else
- return (wchar_t)towupper(c);
- #endif
-}
-
-/*
-wchar_t MyCharLower_WIN(wchar_t c) throw();
-
-inline wchar_t MyCharLower(wchar_t c) throw()
-{
- if (c < 'A') return c;
- if (c <= 'Z') return (wchar_t)(c + 0x20);
- if (c <= 0x7F) return c;
- #ifdef _WIN32
- #ifdef _UNICODE
- return (wchar_t)(unsigned)(UINT_PTR)CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c);
- #else
- return (wchar_t)MyCharLower_WIN(c);
- #endif
- #else
- return (wchar_t)tolower(c);
- #endif
-}
-*/
-
-// char *MyStringUpper(char *s) throw();
-// char *MyStringLower(char *s) throw();
-
-// void MyStringUpper_Ascii(char *s) throw();
-// void MyStringUpper_Ascii(wchar_t *s) throw();
-void MyStringLower_Ascii(char *s) throw();
-void MyStringLower_Ascii(wchar_t *s) throw();
-// wchar_t *MyStringUpper(wchar_t *s) STRING_UNICODE_THROW;
-// wchar_t *MyStringLower(wchar_t *s) STRING_UNICODE_THROW;
-
-bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw();
-
-bool IsString1PrefixedByString2(const char *s1, const char *s2) throw();
-bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw();
-bool IsString1PrefixedByString2(const wchar_t *s1, const char *s2) throw();
-bool IsString1PrefixedByString2_NoCase_Ascii(const wchar_t *u, const char *a) throw();
-bool IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2) throw();
-
-#define MyStringCompare(s1, s2) wcscmp(s1, s2)
-int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw();
-// int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num) throw();
-
-// ---------- ASCII ----------
-// char values in ASCII strings must be less then 128
-bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw();
-bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw();
-bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw();
-bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw();
-
-#define MY_STRING_DELETE(_p_) delete []_p_;
-// #define MY_STRING_DELETE(_p_) my_delete(_p_);
-
-
-#define FORBID_STRING_OPS_2(cls, t) \
- void Find(t) const; \
- void Find(t, unsigned startIndex) const; \
- void ReverseFind(t) const; \
- void InsertAtFront(t); \
- void RemoveChar(t); \
- void Replace(t, t); \
-
-#define FORBID_STRING_OPS(cls, t) \
- explicit cls(t); \
- explicit cls(const t *); \
- cls &operator=(t); \
- cls &operator=(const t *); \
- cls &operator+=(t); \
- cls &operator+=(const t *); \
- FORBID_STRING_OPS_2(cls, t); \
-
-/*
- cls &operator+(t); \
- cls &operator+(const t *); \
-*/
-
-#define FORBID_STRING_OPS_AString(t) FORBID_STRING_OPS(AString, t)
-#define FORBID_STRING_OPS_UString(t) FORBID_STRING_OPS(UString, t)
-#define FORBID_STRING_OPS_UString2(t) FORBID_STRING_OPS(UString2, t)
-
-class AString
-{
- char *_chars;
- unsigned _len;
- unsigned _limit;
-
- void MoveItems(unsigned dest, unsigned src)
- {
- memmove(_chars + dest, _chars + src, (size_t)(_len - src + 1) * sizeof(char));
- }
-
- void InsertSpace(unsigned &index, unsigned size);
-
- void ReAlloc(unsigned newLimit);
- void ReAlloc2(unsigned newLimit);
- void SetStartLen(unsigned len);
- void Grow_1();
- void Grow(unsigned n);
-
- AString(unsigned num, const char *s);
- AString(unsigned num, const AString &s);
- AString(const AString &s, char c); // it's for String + char
- AString(const char *s1, unsigned num1, const char *s2, unsigned num2);
-
- friend AString operator+(const AString &s, char c) { return AString(s, c); } ;
- // friend AString operator+(char c, const AString &s); // is not supported
-
- friend AString operator+(const AString &s1, const AString &s2);
- friend AString operator+(const AString &s1, const char *s2);
- friend AString operator+(const char *s1, const AString &s2);
-
- // ---------- forbidden functions ----------
-
- #ifdef MY_NATIVE_WCHAR_T_DEFINED
- FORBID_STRING_OPS_AString(wchar_t)
- #endif
-
- FORBID_STRING_OPS_AString(signed char)
- FORBID_STRING_OPS_AString(unsigned char)
- FORBID_STRING_OPS_AString(short)
- FORBID_STRING_OPS_AString(unsigned short)
- FORBID_STRING_OPS_AString(int)
- FORBID_STRING_OPS_AString(unsigned)
- FORBID_STRING_OPS_AString(long)
- FORBID_STRING_OPS_AString(unsigned long)
-
-public:
- explicit AString();
- explicit AString(char c);
- explicit AString(const char *s);
- AString(const AString &s);
- ~AString() { MY_STRING_DELETE(_chars); }
-
- unsigned Len() const { return _len; }
- bool IsEmpty() const { return _len == 0; }
- void Empty() { _len = 0; _chars[0] = 0; }
-
- operator const char *() const { return _chars; }
- const char *Ptr() const { return _chars; }
- const char *Ptr(unsigned pos) const { return _chars + pos; }
- const char *RightPtr(unsigned num) const { return _chars + _len - num; }
- char Back() const { return _chars[(size_t)_len - 1]; }
-
- void ReplaceOneCharAtPos(unsigned pos, char c) { _chars[pos] = c; }
-
- char *GetBuf() { return _chars; }
- /* GetBuf(minLen): provides the buffer that can store
- at least (minLen) characters and additional null terminator.
- 9.35: GetBuf doesn't preserve old characters and terminator */
- char *GetBuf(unsigned minLen)
- {
- if (minLen > _limit)
- ReAlloc2(minLen);
- return _chars;
- }
- char *GetBuf_SetEnd(unsigned minLen)
- {
- if (minLen > _limit)
- ReAlloc2(minLen);
- char *chars = _chars;
- chars[minLen] = 0;
- _len = minLen;
- return chars;
- }
-
- void ReleaseBuf_SetLen(unsigned newLen) { _len = newLen; }
- void ReleaseBuf_SetEnd(unsigned newLen) { _len = newLen; _chars[newLen] = 0; }
- void ReleaseBuf_CalcLen(unsigned maxLen)
- {
- char *chars = _chars;
- chars[maxLen] = 0;
- _len = MyStringLen(chars);
- }
-
- AString &operator=(char c);
- AString &operator=(const char *s);
- AString &operator=(const AString &s);
- void SetFromWStr_if_Ascii(const wchar_t *s);
- // void SetFromBstr_if_Ascii(BSTR s);
-
- AString &operator+=(char c)
- {
- if (_limit == _len)
- Grow_1();
- unsigned len = _len;
- char *chars = _chars;
- chars[len++] = c;
- chars[len] = 0;
- _len = len;
- return *this;
- }
-
- void Add_Space();
- void Add_Space_if_NotEmpty();
- void Add_OptSpaced(const char *s);
- void Add_LF();
- void Add_PathSepar() { operator+=(CHAR_PATH_SEPARATOR); }
-
- AString &operator+=(const char *s);
- AString &operator+=(const AString &s);
-
- void Add_UInt32(UInt32 v);
-
- void SetFrom(const char *s, unsigned len); // no check
- void SetFrom_CalcLen(const char *s, unsigned len);
-
- AString Mid(unsigned startIndex, unsigned count) const { return AString(count, _chars + startIndex); }
- AString Left(unsigned count) const { return AString(count, *this); }
-
- // void MakeUpper() { MyStringUpper(_chars); }
- // void MakeLower() { MyStringLower(_chars); }
- void MakeLower_Ascii() { MyStringLower_Ascii(_chars); }
-
-
- bool IsEqualTo(const char *s) const { return strcmp(_chars, s) == 0; }
- bool IsEqualTo_Ascii_NoCase(const char *s) const { return StringsAreEqualNoCase_Ascii(_chars, s); }
- // int Compare(const char *s) const { return MyStringCompare(_chars, s); }
- // int Compare(const AString &s) const { return MyStringCompare(_chars, s._chars); }
- // int CompareNoCase(const char *s) const { return MyStringCompareNoCase(_chars, s); }
- // int CompareNoCase(const AString &s) const { return MyStringCompareNoCase(_chars, s._chars); }
- bool IsPrefixedBy(const char *s) const { return IsString1PrefixedByString2(_chars, s); }
- bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw();
-
- bool IsAscii() const
- {
- unsigned len = Len();
- const char *s = _chars;
- for (unsigned i = 0; i < len; i++)
- if ((unsigned char)s[i] >= 0x80)
- return false;
- return true;
- }
- int Find(char c) const { return FindCharPosInString(_chars, c); }
- int Find(char c, unsigned startIndex) const
- {
- int pos = FindCharPosInString(_chars + startIndex, c);
- return pos < 0 ? -1 : (int)startIndex + pos;
- }
-
- int ReverseFind(char c) const throw();
- int ReverseFind_Dot() const throw() { return ReverseFind('.'); }
- int ReverseFind_PathSepar() const throw();
-
- int Find(const char *s) const { return Find(s, 0); }
- int Find(const char *s, unsigned startIndex) const throw();
-
- void TrimLeft() throw();
- void TrimRight() throw();
- void Trim()
- {
- TrimRight();
- TrimLeft();
- }
-
- void InsertAtFront(char c);
- // void Insert(unsigned index, char c);
- void Insert(unsigned index, const char *s);
- void Insert(unsigned index, const AString &s);
-
- void RemoveChar(char ch) throw();
-
- void Replace(char oldChar, char newChar) throw();
- void Replace(const AString &oldString, const AString &newString);
-
- void Delete(unsigned index) throw();
- void Delete(unsigned index, unsigned count) throw();
- void DeleteFrontal(unsigned num) throw();
- void DeleteBack() { _chars[--_len] = 0; }
- void DeleteFrom(unsigned index)
- {
- if (index < _len)
- {
- _len = index;
- _chars[index] = 0;
- }
- }
-};
-
-bool operator<(const AString &s1, const AString &s2);
-bool operator>(const AString &s1, const AString &s2);
-
-/*
-bool operator==(const AString &s1, const AString &s2);
-bool operator==(const AString &s1, const char *s2);
-bool operator==(const char *s1, const AString &s2);
-
-bool operator!=(const AString &s1, const AString &s2);
-bool operator!=(const AString &s1, const char *s2);
-bool operator!=(const char *s1, const AString &s2);
-*/
-
-inline bool operator==(const AString &s1, const AString &s2) { return s1.Len() == s2.Len() && strcmp(s1, s2) == 0; }
-inline bool operator==(const AString &s1, const char *s2) { return strcmp(s1, s2) == 0; }
-inline bool operator==(const char *s1, const AString &s2) { return strcmp(s1, s2) == 0; }
-
-inline bool operator!=(const AString &s1, const AString &s2) { return s1.Len() != s2.Len() || strcmp(s1, s2) != 0; }
-inline bool operator!=(const AString &s1, const char *s2) { return strcmp(s1, s2) != 0; }
-inline bool operator!=(const char *s1, const AString &s2) { return strcmp(s1, s2) != 0; }
-
-// ---------- forbidden functions ----------
-
-void operator==(char c1, const AString &s2);
-void operator==(const AString &s1, char c2);
-
-void operator+(char c, const AString &s); // this function can be OK, but we don't use it
-
-void operator+(const AString &s, int c);
-void operator+(const AString &s, unsigned c);
-void operator+(int c, const AString &s);
-void operator+(unsigned c, const AString &s);
-void operator-(const AString &s, int c);
-void operator-(const AString &s, unsigned c);
-
-
-class UString
-{
- wchar_t *_chars;
- unsigned _len;
- unsigned _limit;
-
- void MoveItems(unsigned dest, unsigned src)
- {
- memmove(_chars + dest, _chars + src, (size_t)(_len - src + 1) * sizeof(wchar_t));
- }
-
- void InsertSpace(unsigned index, unsigned size);
-
- void ReAlloc(unsigned newLimit);
- void ReAlloc2(unsigned newLimit);
- void SetStartLen(unsigned len);
- void Grow_1();
- void Grow(unsigned n);
-
- UString(unsigned num, const wchar_t *s); // for Mid
- UString(unsigned num, const UString &s); // for Left
- UString(const UString &s, wchar_t c); // it's for String + char
- UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2);
-
- friend UString operator+(const UString &s, wchar_t c) { return UString(s, c); } ;
- // friend UString operator+(wchar_t c, const UString &s); // is not supported
-
- friend UString operator+(const UString &s1, const UString &s2);
- friend UString operator+(const UString &s1, const wchar_t *s2);
- friend UString operator+(const wchar_t *s1, const UString &s2);
-
- // ---------- forbidden functions ----------
-
- FORBID_STRING_OPS_UString(signed char)
- FORBID_STRING_OPS_UString(unsigned char)
- FORBID_STRING_OPS_UString(short)
-
- #ifdef MY_NATIVE_WCHAR_T_DEFINED
- FORBID_STRING_OPS_UString(unsigned short)
- #endif
-
- FORBID_STRING_OPS_UString(int)
- FORBID_STRING_OPS_UString(unsigned)
- FORBID_STRING_OPS_UString(long)
- FORBID_STRING_OPS_UString(unsigned long)
-
- FORBID_STRING_OPS_2(UString, char)
-
-public:
- UString();
- explicit UString(wchar_t c);
- explicit UString(char c);
- explicit UString(const char *s);
- // UString(const AString &s);
- UString(const wchar_t *s);
- UString(const UString &s);
- ~UString() { MY_STRING_DELETE(_chars); }
-
- unsigned Len() const { return _len; }
- bool IsEmpty() const { return _len == 0; }
- void Empty() { _len = 0; _chars[0] = 0; }
-
- operator const wchar_t *() const { return _chars; }
- const wchar_t *Ptr() const { return _chars; }
- const wchar_t *Ptr(unsigned pos) const { return _chars + pos; }
- const wchar_t *RightPtr(unsigned num) const { return _chars + _len - num; }
- wchar_t Back() const { return _chars[(size_t)_len - 1]; }
-
- void ReplaceOneCharAtPos(unsigned pos, wchar_t c) { _chars[pos] = c; }
-
- wchar_t *GetBuf() { return _chars; }
-
- wchar_t *GetBuf(unsigned minLen)
- {
- if (minLen > _limit)
- ReAlloc2(minLen);
- return _chars;
- }
- wchar_t *GetBuf_SetEnd(unsigned minLen)
- {
- if (minLen > _limit)
- ReAlloc2(minLen);
- wchar_t *chars = _chars;
- chars[minLen] = 0;
- _len = minLen;
- return chars;
- }
-
- void ReleaseBuf_SetLen(unsigned newLen) { _len = newLen; }
- void ReleaseBuf_SetEnd(unsigned newLen) { _len = newLen; _chars[newLen] = 0; }
- void ReleaseBuf_CalcLen(unsigned maxLen)
- {
- wchar_t *chars = _chars;
- chars[maxLen] = 0;
- _len = MyStringLen(chars);
- }
-
- UString &operator=(wchar_t c);
- UString &operator=(char c) { return (*this)=((wchar_t)(unsigned char)c); }
- UString &operator=(const wchar_t *s);
- UString &operator=(const UString &s);
- void SetFrom(const wchar_t *s, unsigned len); // no check
- void SetFromBstr(BSTR s);
- UString &operator=(const char *s);
- UString &operator=(const AString &s) { return operator=(s.Ptr()); }
-
- UString &operator+=(wchar_t c)
- {
- if (_limit == _len)
- Grow_1();
- unsigned len = _len;
- wchar_t *chars = _chars;
- chars[len++] = c;
- chars[len] = 0;
- _len = len;
- return *this;
- }
-
- UString &operator+=(char c) { return (*this)+=((wchar_t)(unsigned char)c); }
-
- void Add_Space();
- void Add_Space_if_NotEmpty();
- void Add_LF();
- void Add_PathSepar() { operator+=(WCHAR_PATH_SEPARATOR); }
-
- UString &operator+=(const wchar_t *s);
- UString &operator+=(const UString &s);
- UString &operator+=(const char *s);
- UString &operator+=(const AString &s) { return operator+=(s.Ptr()); }
-
- void Add_UInt32(UInt32 v);
-
- UString Mid(unsigned startIndex, unsigned count) const { return UString(count, _chars + startIndex); }
- UString Left(unsigned count) const { return UString(count, *this); }
-
- // void MakeUpper() { MyStringUpper(_chars); }
- // void MakeUpper() { MyStringUpper_Ascii(_chars); }
- // void MakeUpper_Ascii() { MyStringUpper_Ascii(_chars); }
- void MakeLower_Ascii() { MyStringLower_Ascii(_chars); }
-
- bool IsEqualTo(const char *s) const { return StringsAreEqual_Ascii(_chars, s); }
- bool IsEqualTo_NoCase(const wchar_t *s) const { return StringsAreEqualNoCase(_chars, s); }
- bool IsEqualTo_Ascii_NoCase(const char *s) const { return StringsAreEqualNoCase_Ascii(_chars, s); }
- int Compare(const wchar_t *s) const { return wcscmp(_chars, s); }
- // int Compare(const UString &s) const { return MyStringCompare(_chars, s._chars); }
- // int CompareNoCase(const wchar_t *s) const { return MyStringCompareNoCase(_chars, s); }
- // int CompareNoCase(const UString &s) const { return MyStringCompareNoCase(_chars, s._chars); }
- bool IsPrefixedBy(const wchar_t *s) const { return IsString1PrefixedByString2(_chars, s); }
- bool IsPrefixedBy_NoCase(const wchar_t *s) const { return IsString1PrefixedByString2_NoCase(_chars, s); }
- bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw();
-
- bool IsAscii() const
- {
- unsigned len = Len();
- const wchar_t *s = _chars;
- for (unsigned i = 0; i < len; i++)
- if (s[i] >= 0x80)
- return false;
- return true;
- }
- int Find(wchar_t c) const { return FindCharPosInString(_chars, c); }
- int Find(wchar_t c, unsigned startIndex) const
- {
- int pos = FindCharPosInString(_chars + startIndex, c);
- return pos < 0 ? -1 : (int)startIndex + pos;
- }
-
- int ReverseFind(wchar_t c) const throw();
- int ReverseFind_Dot() const throw() { return ReverseFind(L'.'); }
- int ReverseFind_PathSepar() const throw();
-
- int Find(const wchar_t *s) const { return Find(s, 0); }
- int Find(const wchar_t *s, unsigned startIndex) const throw();
-
- void TrimLeft() throw();
- void TrimRight() throw();
- void Trim()
- {
- TrimRight();
- TrimLeft();
- }
-
- void InsertAtFront(wchar_t c);
- // void Insert(unsigned index, wchar_t c);
- void Insert(unsigned index, const wchar_t *s);
- void Insert(unsigned index, const UString &s);
-
- void RemoveChar(wchar_t ch) throw();
-
- void Replace(wchar_t oldChar, wchar_t newChar) throw();
- void Replace(const UString &oldString, const UString &newString);
-
- void Delete(unsigned index) throw();
- void Delete(unsigned index, unsigned count) throw();
- void DeleteFrontal(unsigned num) throw();
- void DeleteBack() { _chars[--_len] = 0; }
- void DeleteFrom(unsigned index)
- {
- if (index < _len)
- {
- _len = index;
- _chars[index] = 0;
- }
- }
-};
-
-bool operator<(const UString &s1, const UString &s2);
-bool operator>(const UString &s1, const UString &s2);
-
-inline bool operator==(const UString &s1, const UString &s2) { return s1.Len() == s2.Len() && wcscmp(s1, s2) == 0; }
-inline bool operator==(const UString &s1, const wchar_t *s2) { return wcscmp(s1, s2) == 0; }
-inline bool operator==(const wchar_t *s1, const UString &s2) { return wcscmp(s1, s2) == 0; }
-
-inline bool operator!=(const UString &s1, const UString &s2) { return s1.Len() != s2.Len() || wcscmp(s1, s2) != 0; }
-inline bool operator!=(const UString &s1, const wchar_t *s2) { return wcscmp(s1, s2) != 0; }
-inline bool operator!=(const wchar_t *s1, const UString &s2) { return wcscmp(s1, s2) != 0; }
-
-
-// ---------- forbidden functions ----------
-
-void operator==(wchar_t c1, const UString &s2);
-void operator==(const UString &s1, wchar_t c2);
-
-void operator+(wchar_t c, const UString &s); // this function can be OK, but we don't use it
-
-void operator+(const AString &s1, const UString &s2);
-void operator+(const UString &s1, const AString &s2);
-
-void operator+(const UString &s1, const char *s2);
-void operator+(const char *s1, const UString &s2);
-
-void operator+(const UString &s, char c);
-void operator+(const UString &s, unsigned char c);
-void operator+(char c, const UString &s);
-void operator+(unsigned char c, const UString &s);
-void operator-(const UString &s1, wchar_t c);
-
-#ifdef _WIN32
-// can we forbid these functions, if wchar_t is 32-bit ?
-void operator+(const UString &s, int c);
-void operator+(const UString &s, unsigned c);
-void operator+(int c, const UString &s);
-void operator+(unsigned c, const UString &s);
-void operator-(const UString &s1, int c);
-void operator-(const UString &s1, unsigned c);
-#endif
-
-
-
-
-
-
-
-class UString2
-{
- wchar_t *_chars;
- unsigned _len;
-
- void ReAlloc2(unsigned newLimit);
- void SetStartLen(unsigned len);
-
- // ---------- forbidden functions ----------
-
- FORBID_STRING_OPS_UString2(char)
- FORBID_STRING_OPS_UString2(signed char)
- FORBID_STRING_OPS_UString2(unsigned char)
- FORBID_STRING_OPS_UString2(short)
-
- UString2 &operator=(wchar_t c);
- UString2(wchar_t c);
-
-public:
- UString2(): _chars(NULL), _len(0) {}
- UString2(const wchar_t *s);
- UString2(const UString2 &s);
- ~UString2() { if (_chars) MY_STRING_DELETE(_chars); }
-
- unsigned Len() const { return _len; }
- bool IsEmpty() const { return _len == 0; }
- // void Empty() { _len = 0; _chars[0] = 0; }
-
- // operator const wchar_t *() const { return _chars; }
- const wchar_t *GetRawPtr() const { return _chars; }
-
- int Compare(const wchar_t *s) const { return wcscmp(_chars, s); }
-
- wchar_t *GetBuf(unsigned minLen)
- {
- if (!_chars || minLen > _len)
- ReAlloc2(minLen);
- return _chars;
- }
- void ReleaseBuf_SetLen(unsigned newLen) { _len = newLen; }
-
- UString2 &operator=(const wchar_t *s);
- UString2 &operator=(const UString2 &s);
- void SetFromAscii(const char *s);
-};
-
-bool operator==(const UString2 &s1, const UString2 &s2);
-bool operator==(const UString2 &s1, const wchar_t *s2);
-bool operator==(const wchar_t *s1, const UString2 &s2);
-
-inline bool operator!=(const UString2 &s1, const UString2 &s2) { return !(s1 == s2); }
-inline bool operator!=(const UString2 &s1, const wchar_t *s2) { return !(s1 == s2); }
-inline bool operator!=(const wchar_t *s1, const UString2 &s2) { return !(s1 == s2); }
-
-
-// ---------- forbidden functions ----------
-
-void operator==(wchar_t c1, const UString2 &s2);
-void operator==(const UString2 &s1, wchar_t c2);
-bool operator<(const UString2 &s1, const UString2 &s2);
-bool operator>(const UString2 &s1, const UString2 &s2);
-
-void operator+(const UString2 &s1, const UString2 &s2);
-void operator+(const UString2 &s1, const wchar_t *s2);
-void operator+(const wchar_t *s1, const UString2 &s2);
-void operator+(wchar_t c, const UString2 &s);
-void operator+(const UString2 &s, wchar_t c);
-void operator+(const UString2 &s, char c);
-void operator+(const UString2 &s, unsigned char c);
-void operator+(char c, const UString2 &s);
-void operator+(unsigned char c, const UString2 &s);
-void operator-(const UString2 &s1, wchar_t c);
-
-
-
-
-
-
-typedef CObjectVector<AString> AStringVector;
-typedef CObjectVector<UString> UStringVector;
-
-#ifdef _UNICODE
- typedef UString CSysString;
-#else
- typedef AString CSysString;
-#endif
-
-typedef CObjectVector<CSysString> CSysStringVector;
-
-
-// ---------- FString ----------
-
-#ifdef _WIN32
- #define USE_UNICODE_FSTRING
-#endif
-
-#ifdef USE_UNICODE_FSTRING
-
- #define __FTEXT(quote) L##quote
-
- typedef wchar_t FChar;
- typedef UString FString;
-
- #define fs2us(_x_) (_x_)
- #define us2fs(_x_) (_x_)
- FString fas2fs(const char *s);
- FString fas2fs(const AString &s);
- AString fs2fas(const FChar *s);
-
-#else
-
- #define __FTEXT(quote) quote
-
- typedef char FChar;
- typedef AString FString;
-
- UString fs2us(const FChar *s);
- UString fs2us(const FString &s);
- FString us2fs(const wchar_t *s);
- #define fas2fs(_x_) (_x_)
- #define fs2fas(_x_) (_x_)
-
-#endif
-
-#define FTEXT(quote) __FTEXT(quote)
-
-#define FCHAR_PATH_SEPARATOR FTEXT(CHAR_PATH_SEPARATOR)
-#define FSTRING_PATH_SEPARATOR FTEXT(STRING_PATH_SEPARATOR)
-
-// #define FCHAR_ANY_MASK FTEXT('*')
-// #define FSTRING_ANY_MASK FTEXT("*")
-
-typedef const FChar *CFSTR;
-
-typedef CObjectVector<FString> FStringVector;
-
-#endif
+// Common/MyString.h
+
+#ifndef ZIP7_INC_COMMON_MY_STRING_H
+#define ZIP7_INC_COMMON_MY_STRING_H
+
+#include <string.h>
+
+#ifndef _WIN32
+#include <wctype.h>
+#include <wchar.h>
+#endif
+
+#include "Common.h"
+#include "MyWindows.h"
+#include "MyTypes.h"
+#include "MyVector.h"
+
+
+/* if (DEBUG_FSTRING_INHERITS_ASTRING is defined), then
+ FString inherits from AString, so we can find bugs related to FString at compile time.
+ DON'T define DEBUG_FSTRING_INHERITS_ASTRING in release code */
+
+// #define DEBUG_FSTRING_INHERITS_ASTRING
+
+#ifdef DEBUG_FSTRING_INHERITS_ASTRING
+class FString;
+#endif
+
+
+#ifdef _MSC_VER
+ #ifdef _NATIVE_WCHAR_T_DEFINED
+ #define MY_NATIVE_WCHAR_T_DEFINED
+ #endif
+#else
+ #define MY_NATIVE_WCHAR_T_DEFINED
+#endif
+
+/*
+ native support for wchar_t:
+ _MSC_VER == 1600 : /Zc:wchar_t is not supported
+ _MSC_VER == 1310 (VS2003)
+ ? _MSC_VER == 1400 (VS2005) : wchar_t <- unsigned short
+ /Zc:wchar_t : wchar_t <- __wchar_t, _WCHAR_T_DEFINED and _NATIVE_WCHAR_T_DEFINED
+ _MSC_VER > 1400 (VS2008+)
+ /Zc:wchar_t[-]
+ /Zc:wchar_t is on by default
+*/
+
+#ifdef _WIN32
+#define IS_PATH_SEPAR(c) ((c) == '\\' || (c) == '/')
+#else
+#define IS_PATH_SEPAR(c) ((c) == CHAR_PATH_SEPARATOR)
+#endif
+
+inline bool IsPathSepar(char c) { return IS_PATH_SEPAR(c); }
+inline bool IsPathSepar(wchar_t c) { return IS_PATH_SEPAR(c); }
+
+inline unsigned MyStringLen(const char *s)
+{
+ unsigned i;
+ for (i = 0; s[i] != 0; i++);
+ return i;
+}
+
+inline void MyStringCopy(char *dest, const char *src)
+{
+ while ((*dest++ = *src++) != 0);
+}
+
+inline char *MyStpCpy(char *dest, const char *src)
+{
+ for (;;)
+ {
+ const char c = *src;
+ *dest = c;
+ if (c == 0)
+ return dest;
+ src++;
+ dest++;
+ }
+}
+
+inline void MyStringCat(char *dest, const char *src)
+{
+ for (; *dest != 0; dest++);
+ while ((*dest++ = *src++) != 0);
+ // MyStringCopy(dest + MyStringLen(dest), src);
+}
+
+inline unsigned MyStringLen(const wchar_t *s)
+{
+ unsigned i;
+ for (i = 0; s[i] != 0; i++);
+ return i;
+}
+
+inline void MyStringCopy(wchar_t *dest, const wchar_t *src)
+{
+ while ((*dest++ = *src++) != 0);
+}
+
+inline void MyStringCat(wchar_t *dest, const wchar_t *src)
+{
+ for (; *dest != 0; dest++);
+ while ((*dest++ = *src++) != 0);
+ // MyStringCopy(dest + MyStringLen(dest), src);
+}
+
+
+/*
+inline wchar_t *MyWcpCpy(wchar_t *dest, const wchar_t *src)
+{
+ for (;;)
+ {
+ const wchar_t c = *src;
+ *dest = c;
+ if (c == 0)
+ return dest;
+ src++;
+ dest++;
+ }
+}
+*/
+
+int FindCharPosInString(const char *s, char c) throw();
+int FindCharPosInString(const wchar_t *s, wchar_t c) throw();
+
+#ifdef _WIN32
+ #ifndef _UNICODE
+ #define STRING_UNICODE_THROW
+ #endif
+#endif
+
+#ifndef STRING_UNICODE_THROW
+ #define STRING_UNICODE_THROW throw()
+#endif
+
+
+inline char MyCharUpper_Ascii(char c)
+{
+ if (c >= 'a' && c <= 'z')
+ return (char)((unsigned char)c - 0x20);
+ return c;
+}
+
+/*
+inline wchar_t MyCharUpper_Ascii(wchar_t c)
+{
+ if (c >= 'a' && c <= 'z')
+ return (wchar_t)(c - 0x20);
+ return c;
+}
+*/
+
+inline char MyCharLower_Ascii(char c)
+{
+ if (c >= 'A' && c <= 'Z')
+ return (char)((unsigned char)c + 0x20);
+ return c;
+}
+
+inline wchar_t MyCharLower_Ascii(wchar_t c)
+{
+ if (c >= 'A' && c <= 'Z')
+ return (wchar_t)(c + 0x20);
+ return c;
+}
+
+wchar_t MyCharUpper_WIN(wchar_t c) throw();
+
+inline wchar_t MyCharUpper(wchar_t c) throw()
+{
+ if (c < 'a') return c;
+ if (c <= 'z') return (wchar_t)(c - 0x20);
+ if (c <= 0x7F) return c;
+ #ifdef _WIN32
+ #ifdef _UNICODE
+ return (wchar_t)(unsigned)(UINT_PTR)CharUpperW((LPWSTR)(UINT_PTR)(unsigned)c);
+ #else
+ return (wchar_t)MyCharUpper_WIN(c);
+ #endif
+ #else
+ return (wchar_t)towupper((wint_t)c);
+ #endif
+}
+
+/*
+wchar_t MyCharLower_WIN(wchar_t c) throw();
+
+inline wchar_t MyCharLower(wchar_t c) throw()
+{
+ if (c < 'A') return c;
+ if (c <= 'Z') return (wchar_t)(c + 0x20);
+ if (c <= 0x7F) return c;
+ #ifdef _WIN32
+ #ifdef _UNICODE
+ return (wchar_t)(unsigned)(UINT_PTR)CharLowerW((LPWSTR)(UINT_PTR)(unsigned)c);
+ #else
+ return (wchar_t)MyCharLower_WIN(c);
+ #endif
+ #else
+ return (wchar_t)tolower(c);
+ #endif
+}
+*/
+
+// char *MyStringUpper(char *s) throw();
+// char *MyStringLower(char *s) throw();
+
+// void MyStringUpper_Ascii(char *s) throw();
+// void MyStringUpper_Ascii(wchar_t *s) throw();
+void MyStringLower_Ascii(char *s) throw();
+void MyStringLower_Ascii(wchar_t *s) throw();
+// wchar_t *MyStringUpper(wchar_t *s) STRING_UNICODE_THROW;
+// wchar_t *MyStringLower(wchar_t *s) STRING_UNICODE_THROW;
+
+bool StringsAreEqualNoCase(const wchar_t *s1, const wchar_t *s2) throw();
+
+bool IsString1PrefixedByString2(const char *s1, const char *s2) throw();
+bool IsString1PrefixedByString2(const wchar_t *s1, const wchar_t *s2) throw();
+bool IsString1PrefixedByString2(const wchar_t *s1, const char *s2) throw();
+bool IsString1PrefixedByString2_NoCase_Ascii(const char *s1, const char *s2) throw();
+bool IsString1PrefixedByString2_NoCase_Ascii(const wchar_t *u, const char *a) throw();
+bool IsString1PrefixedByString2_NoCase(const wchar_t *s1, const wchar_t *s2) throw();
+
+#define MyStringCompare(s1, s2) wcscmp(s1, s2)
+int MyStringCompareNoCase(const wchar_t *s1, const wchar_t *s2) throw();
+// int MyStringCompareNoCase_N(const wchar_t *s1, const wchar_t *s2, unsigned num) throw();
+
+// ---------- ASCII ----------
+// char values in ASCII strings must be less then 128
+bool StringsAreEqual_Ascii(const char *u, const char *a) throw();
+bool StringsAreEqual_Ascii(const wchar_t *u, const char *a) throw();
+bool StringsAreEqualNoCase_Ascii(const char *s1, const char *s2) throw();
+bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const char *s2) throw();
+bool StringsAreEqualNoCase_Ascii(const wchar_t *s1, const wchar_t *s2) throw();
+
+#define MY_STRING_DELETE(_p_) { delete [](_p_); }
+// #define MY_STRING_DELETE(_p_) my_delete(_p_);
+
+
+#define FORBID_STRING_OPS_2(cls, t) \
+ void Find(t) const; \
+ void Find(t, unsigned startIndex) const; \
+ void ReverseFind(t) const; \
+ void InsertAtFront(t); \
+ void RemoveChar(t); \
+ void Replace(t, t); \
+
+#define FORBID_STRING_OPS(cls, t) \
+ explicit cls(t); \
+ explicit cls(const t *); \
+ cls &operator=(t); \
+ cls &operator=(const t *); \
+ cls &operator+=(t); \
+ cls &operator+=(const t *); \
+ FORBID_STRING_OPS_2(cls, t) \
+
+/*
+ cls &operator+(t); \
+ cls &operator+(const t *); \
+*/
+
+#define FORBID_STRING_OPS_AString(t) FORBID_STRING_OPS(AString, t)
+#define FORBID_STRING_OPS_UString(t) FORBID_STRING_OPS(UString, t)
+#define FORBID_STRING_OPS_UString2(t) FORBID_STRING_OPS(UString2, t)
+
+class AString
+{
+ char *_chars;
+ unsigned _len;
+ unsigned _limit;
+
+ void MoveItems(unsigned dest, unsigned src)
+ {
+ memmove(_chars + dest, _chars + src, (size_t)(_len - src + 1) * sizeof(char));
+ }
+
+ void InsertSpace(unsigned &index, unsigned size);
+
+ void ReAlloc(unsigned newLimit);
+ void ReAlloc2(unsigned newLimit);
+ void SetStartLen(unsigned len);
+ void Grow_1();
+ void Grow(unsigned n);
+
+ AString(unsigned num, const char *s);
+ AString(unsigned num, const AString &s);
+ AString(const AString &s, char c); // it's for String + char
+ AString(const char *s1, unsigned num1, const char *s2, unsigned num2);
+
+ friend AString operator+(const AString &s, char c) { return AString(s, c); }
+ // friend AString operator+(char c, const AString &s); // is not supported
+
+ friend AString operator+(const AString &s1, const AString &s2);
+ friend AString operator+(const AString &s1, const char *s2);
+ friend AString operator+(const char *s1, const AString &s2);
+
+ // ---------- forbidden functions ----------
+
+ #ifdef MY_NATIVE_WCHAR_T_DEFINED
+ FORBID_STRING_OPS_AString(wchar_t)
+ #endif
+
+ FORBID_STRING_OPS_AString(signed char)
+ FORBID_STRING_OPS_AString(unsigned char)
+ FORBID_STRING_OPS_AString(short)
+ FORBID_STRING_OPS_AString(unsigned short)
+ FORBID_STRING_OPS_AString(int)
+ FORBID_STRING_OPS_AString(unsigned)
+ FORBID_STRING_OPS_AString(long)
+ FORBID_STRING_OPS_AString(unsigned long)
+
+ #ifdef DEBUG_FSTRING_INHERITS_ASTRING
+ AString(const FString &s);
+ AString &operator=(const FString &s);
+ AString &operator+=(const FString &s);
+ #endif
+
+public:
+ explicit AString();
+ explicit AString(char c);
+ explicit AString(const char *s);
+ AString(const AString &s);
+ ~AString() { MY_STRING_DELETE(_chars) }
+
+ unsigned Len() const { return _len; }
+ bool IsEmpty() const { return _len == 0; }
+ void Empty() { _len = 0; _chars[0] = 0; }
+
+ operator const char *() const { return _chars; }
+ char *Ptr_non_const() const { return _chars; }
+ const char *Ptr() const { return _chars; }
+ const char *Ptr(unsigned pos) const { return _chars + pos; }
+ const char *Ptr(int pos) const { return _chars + (unsigned)pos; }
+ const char *RightPtr(unsigned num) const { return _chars + _len - num; }
+ char Back() const { return _chars[(size_t)_len - 1]; }
+
+ void ReplaceOneCharAtPos(unsigned pos, char c) { _chars[pos] = c; }
+
+ char *GetBuf() { return _chars; }
+ /* GetBuf(minLen): provides the buffer that can store
+ at least (minLen) characters and additional null terminator.
+ 9.35: GetBuf doesn't preserve old characters and terminator */
+ char *GetBuf(unsigned minLen)
+ {
+ if (minLen > _limit)
+ ReAlloc2(minLen);
+ return _chars;
+ }
+ char *GetBuf_SetEnd(unsigned minLen)
+ {
+ if (minLen > _limit)
+ ReAlloc2(minLen);
+ char *chars = _chars;
+ chars[minLen] = 0;
+ _len = minLen;
+ return chars;
+ }
+
+ void ReleaseBuf_SetLen(unsigned newLen) { _len = newLen; }
+ void ReleaseBuf_SetEnd(unsigned newLen) { _len = newLen; _chars[newLen] = 0; }
+ void ReleaseBuf_CalcLen(unsigned maxLen)
+ {
+ char *chars = _chars;
+ chars[maxLen] = 0;
+ _len = MyStringLen(chars);
+ }
+
+ AString &operator=(char c);
+ AString &operator=(const char *s);
+ AString &operator=(const AString &s);
+ void SetFromWStr_if_Ascii(const wchar_t *s);
+ // void SetFromBstr_if_Ascii(BSTR s);
+
+ AString &operator+=(char c)
+ {
+ if (_limit == _len)
+ Grow_1();
+ unsigned len = _len;
+ char *chars = _chars;
+ chars[len++] = c;
+ chars[len] = 0;
+ _len = len;
+ return *this;
+ }
+
+ void Add_Space();
+ void Add_Space_if_NotEmpty();
+ void Add_OptSpaced(const char *s);
+ void Add_LF();
+ void Add_Slash();
+ void Add_Dot();
+ void Add_Minus();
+ void Add_PathSepar() { operator+=(CHAR_PATH_SEPARATOR); }
+
+ AString &operator+=(const char *s);
+ AString &operator+=(const AString &s);
+
+ void Add_UInt32(UInt32 v);
+ void Add_UInt64(UInt64 v);
+
+ void AddFrom(const char *s, unsigned len); // no check
+ void SetFrom(const char *s, unsigned len); // no check
+ void SetFrom(const char* s, int len) // no check
+ {
+ SetFrom(s, (unsigned)len); // no check
+ }
+ void SetFrom_CalcLen(const char *s, unsigned len);
+
+ AString Mid(unsigned startIndex, unsigned count) const { return AString(count, _chars + startIndex); }
+ AString Left(unsigned count) const { return AString(count, *this); }
+ // void MakeUpper() { MyStringUpper(_chars); }
+ // void MakeLower() { MyStringLower(_chars); }
+ void MakeLower_Ascii() { MyStringLower_Ascii(_chars); }
+
+
+ bool IsEqualTo(const char *s) const { return strcmp(_chars, s) == 0; }
+ bool IsEqualTo_Ascii_NoCase(const char *s) const { return StringsAreEqualNoCase_Ascii(_chars, s); }
+ // int Compare(const char *s) const { return MyStringCompare(_chars, s); }
+ // int Compare(const AString &s) const { return MyStringCompare(_chars, s._chars); }
+ // int CompareNoCase(const char *s) const { return MyStringCompareNoCase(_chars, s); }
+ // int CompareNoCase(const AString &s) const { return MyStringCompareNoCase(_chars, s._chars); }
+ bool IsPrefixedBy(const char *s) const { return IsString1PrefixedByString2(_chars, s); }
+ bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw();
+
+ bool IsAscii() const
+ {
+ unsigned len = Len();
+ const char *s = _chars;
+ for (unsigned i = 0; i < len; i++)
+ if ((unsigned char)s[i] >= 0x80)
+ return false;
+ return true;
+ }
+ int Find(char c) const { return FindCharPosInString(_chars, c); }
+ int Find(char c, unsigned startIndex) const
+ {
+ const int pos = FindCharPosInString(_chars + startIndex, c);
+ return pos < 0 ? -1 : (int)startIndex + pos;
+ }
+ int Find(char c, int startIndex) const
+ {
+ return Find(c, (unsigned)startIndex);
+ }
+
+ int ReverseFind(char c) const throw();
+ int ReverseFind_Dot() const throw() { return ReverseFind('.'); }
+ int ReverseFind_PathSepar() const throw();
+
+ int Find(const char *s) const { return Find(s, 0); }
+ int Find(const char *s, unsigned startIndex) const throw();
+
+ void TrimLeft() throw();
+ void TrimRight() throw();
+ void Trim()
+ {
+ TrimRight();
+ TrimLeft();
+ }
+
+ void InsertAtFront(char c);
+ // void Insert(unsigned index, char c);
+ void Insert(unsigned index, const char *s);
+ void Insert(unsigned index, const AString &s);
+
+ void RemoveChar(char ch) throw();
+
+ void Replace(char oldChar, char newChar) throw();
+ void Replace(const AString &oldString, const AString &newString);
+
+ void Delete(unsigned index) throw();
+ void Delete(unsigned index, unsigned count) throw();
+ void DeleteFrontal(unsigned num) throw();
+ void DeleteBack() { _chars[--_len] = 0; }
+ void DeleteFrom(unsigned index)
+ {
+ if (index < _len)
+ {
+ _len = index;
+ _chars[index] = 0;
+ }
+ }
+ void DeleteFrom(int index)
+ {
+ DeleteFrom((unsigned)index);
+ }
+
+
+ void Wipe_and_Empty()
+ {
+ if (_chars)
+ {
+ memset(_chars, 0, (_limit + 1) * sizeof(*_chars));
+ _len = 0;
+ }
+ }
+};
+
+
+class AString_Wipe: public AString
+{
+ Z7_CLASS_NO_COPY(AString_Wipe)
+public:
+ AString_Wipe(): AString() {}
+ // AString_Wipe(const AString &s): AString(s) {}
+ // AString_Wipe &operator=(const AString &s) { AString::operator=(s); return *this; }
+ // AString_Wipe &operator=(const char *s) { AString::operator=(s); return *this; }
+ ~AString_Wipe() { Wipe_and_Empty(); }
+};
+
+
+bool operator<(const AString &s1, const AString &s2);
+bool operator>(const AString &s1, const AString &s2);
+
+/*
+bool operator==(const AString &s1, const AString &s2);
+bool operator==(const AString &s1, const char *s2);
+bool operator==(const char *s1, const AString &s2);
+
+bool operator!=(const AString &s1, const AString &s2);
+bool operator!=(const AString &s1, const char *s2);
+bool operator!=(const char *s1, const AString &s2);
+*/
+
+inline bool operator==(const AString &s1, const AString &s2) { return s1.Len() == s2.Len() && strcmp(s1, s2) == 0; }
+inline bool operator==(const AString &s1, const char *s2) { return strcmp(s1, s2) == 0; }
+inline bool operator==(const char *s1, const AString &s2) { return strcmp(s1, s2) == 0; }
+
+inline bool operator!=(const AString &s1, const AString &s2) { return s1.Len() != s2.Len() || strcmp(s1, s2) != 0; }
+inline bool operator!=(const AString &s1, const char *s2) { return strcmp(s1, s2) != 0; }
+inline bool operator!=(const char *s1, const AString &s2) { return strcmp(s1, s2) != 0; }
+
+// ---------- forbidden functions ----------
+
+void operator==(char c1, const AString &s2);
+void operator==(const AString &s1, char c2);
+
+void operator+(char c, const AString &s); // this function can be OK, but we don't use it
+
+void operator+(const AString &s, int c);
+void operator+(const AString &s, unsigned c);
+void operator+(int c, const AString &s);
+void operator+(unsigned c, const AString &s);
+void operator-(const AString &s, int c);
+void operator-(const AString &s, unsigned c);
+
+
+class UString
+{
+ wchar_t *_chars;
+ unsigned _len;
+ unsigned _limit;
+
+ void MoveItems(unsigned dest, unsigned src)
+ {
+ memmove(_chars + dest, _chars + src, (size_t)(_len - src + 1) * sizeof(wchar_t));
+ }
+
+ void InsertSpace(unsigned index, unsigned size);
+
+ void ReAlloc(unsigned newLimit);
+ void ReAlloc2(unsigned newLimit);
+ void SetStartLen(unsigned len);
+ void Grow_1();
+ void Grow(unsigned n);
+
+ UString(unsigned num, const wchar_t *s); // for Mid
+ UString(unsigned num, const UString &s); // for Left
+ UString(const UString &s, wchar_t c); // it's for String + char
+ UString(const wchar_t *s1, unsigned num1, const wchar_t *s2, unsigned num2);
+
+ friend UString operator+(const UString &s, wchar_t c) { return UString(s, c); }
+ // friend UString operator+(wchar_t c, const UString &s); // is not supported
+
+ friend UString operator+(const UString &s1, const UString &s2);
+ friend UString operator+(const UString &s1, const wchar_t *s2);
+ friend UString operator+(const wchar_t *s1, const UString &s2);
+
+ // ---------- forbidden functions ----------
+
+ FORBID_STRING_OPS_UString(signed char)
+ FORBID_STRING_OPS_UString(unsigned char)
+ FORBID_STRING_OPS_UString(short)
+
+ #ifdef MY_NATIVE_WCHAR_T_DEFINED
+ FORBID_STRING_OPS_UString(unsigned short)
+ #endif
+
+ FORBID_STRING_OPS_UString(int)
+ FORBID_STRING_OPS_UString(unsigned)
+ FORBID_STRING_OPS_UString(long)
+ FORBID_STRING_OPS_UString(unsigned long)
+
+ FORBID_STRING_OPS_2(UString, char)
+
+ #ifdef DEBUG_FSTRING_INHERITS_ASTRING
+ UString(const FString &s);
+ UString &operator=(const FString &s);
+ UString &operator+=(const FString &s);
+ #endif
+
+public:
+ UString();
+ explicit UString(wchar_t c);
+ explicit UString(char c);
+ explicit UString(const char *s);
+ explicit UString(const AString &s);
+ UString(const wchar_t *s);
+ UString(const UString &s);
+ ~UString() { MY_STRING_DELETE(_chars) }
+
+ unsigned Len() const { return _len; }
+ bool IsEmpty() const { return _len == 0; }
+ void Empty() { _len = 0; _chars[0] = 0; }
+
+ operator const wchar_t *() const { return _chars; }
+ wchar_t *Ptr_non_const() const { return _chars; }
+ const wchar_t *Ptr() const { return _chars; }
+ const wchar_t *Ptr(int pos) const { return _chars + (unsigned)pos; }
+ const wchar_t *Ptr(unsigned pos) const { return _chars + pos; }
+ const wchar_t *RightPtr(unsigned num) const { return _chars + _len - num; }
+ wchar_t Back() const { return _chars[(size_t)_len - 1]; }
+
+ void ReplaceOneCharAtPos(unsigned pos, wchar_t c) { _chars[pos] = c; }
+
+ wchar_t *GetBuf() { return _chars; }
+
+ /*
+ wchar_t *GetBuf_GetMaxAvail(unsigned &availBufLen)
+ {
+ availBufLen = _limit;
+ return _chars;
+ }
+ */
+
+ wchar_t *GetBuf(unsigned minLen)
+ {
+ if (minLen > _limit)
+ ReAlloc2(minLen);
+ return _chars;
+ }
+ wchar_t *GetBuf_SetEnd(unsigned minLen)
+ {
+ if (minLen > _limit)
+ ReAlloc2(minLen);
+ wchar_t *chars = _chars;
+ chars[minLen] = 0;
+ _len = minLen;
+ return chars;
+ }
+
+ void ReleaseBuf_SetLen(unsigned newLen) { _len = newLen; }
+ void ReleaseBuf_SetEnd(unsigned newLen) { _len = newLen; _chars[newLen] = 0; }
+ void ReleaseBuf_CalcLen(unsigned maxLen)
+ {
+ wchar_t *chars = _chars;
+ chars[maxLen] = 0;
+ _len = MyStringLen(chars);
+ }
+
+ UString &operator=(wchar_t c);
+ UString &operator=(char c) { return (*this)=((wchar_t)(unsigned char)c); }
+ UString &operator=(const wchar_t *s);
+ UString &operator=(const UString &s);
+ void SetFrom(const wchar_t *s, unsigned len); // no check
+ void SetFromBstr(LPCOLESTR s);
+ UString &operator=(const char *s);
+ UString &operator=(const AString &s) { return operator=(s.Ptr()); }
+
+ UString &operator+=(wchar_t c)
+ {
+ if (_limit == _len)
+ Grow_1();
+ unsigned len = _len;
+ wchar_t *chars = _chars;
+ chars[len++] = c;
+ chars[len] = 0;
+ _len = len;
+ return *this;
+ }
+
+ UString &operator+=(char c) { return (*this)+=((wchar_t)(unsigned char)c); }
+
+ void Add_Space();
+ void Add_Space_if_NotEmpty();
+ void Add_LF();
+ void Add_Dot();
+ void Add_PathSepar() { operator+=(WCHAR_PATH_SEPARATOR); }
+
+ UString &operator+=(const wchar_t *s);
+ UString &operator+=(const UString &s);
+ UString &operator+=(const char *s);
+ UString &operator+=(const AString &s) { return operator+=(s.Ptr()); }
+
+ void Add_UInt32(UInt32 v);
+ void Add_UInt64(UInt64 v);
+
+ UString Mid(unsigned startIndex, unsigned count) const { return UString(count, _chars + startIndex); }
+ UString Left(unsigned count) const { return UString(count, *this); }
+ UString Left(int count) const { return Left((unsigned)count); }
+
+ // void MakeUpper() { MyStringUpper(_chars); }
+ // void MakeUpper() { MyStringUpper_Ascii(_chars); }
+ // void MakeUpper_Ascii() { MyStringUpper_Ascii(_chars); }
+ void MakeLower_Ascii() { MyStringLower_Ascii(_chars); }
+
+ bool IsEqualTo(const char *s) const { return StringsAreEqual_Ascii(_chars, s); }
+ bool IsEqualTo_NoCase(const wchar_t *s) const { return StringsAreEqualNoCase(_chars, s); }
+ bool IsEqualTo_Ascii_NoCase(const char *s) const { return StringsAreEqualNoCase_Ascii(_chars, s); }
+ int Compare(const wchar_t *s) const { return wcscmp(_chars, s); }
+ // int Compare(const UString &s) const { return MyStringCompare(_chars, s._chars); }
+ // int CompareNoCase(const wchar_t *s) const { return MyStringCompareNoCase(_chars, s); }
+ // int CompareNoCase(const UString &s) const { return MyStringCompareNoCase(_chars, s._chars); }
+ bool IsPrefixedBy(const wchar_t *s) const { return IsString1PrefixedByString2(_chars, s); }
+ bool IsPrefixedBy_NoCase(const wchar_t *s) const { return IsString1PrefixedByString2_NoCase(_chars, s); }
+ bool IsPrefixedBy_Ascii_NoCase(const char *s) const throw();
+
+ bool IsAscii() const
+ {
+ unsigned len = Len();
+ const wchar_t *s = _chars;
+ for (unsigned i = 0; i < len; i++)
+ if (s[i] >= 0x80)
+ return false;
+ return true;
+ }
+ int Find(wchar_t c) const { return FindCharPosInString(_chars, c); }
+ int Find(wchar_t c, unsigned startIndex) const
+ {
+ int pos = FindCharPosInString(_chars + startIndex, c);
+ return pos < 0 ? -1 : (int)startIndex + pos;
+ }
+
+ int ReverseFind(wchar_t c) const throw();
+ int ReverseFind_Dot() const throw() { return ReverseFind(L'.'); }
+ int ReverseFind_PathSepar() const throw();
+
+ int Find(const wchar_t *s) const { return Find(s, 0); }
+ int Find(const wchar_t *s, unsigned startIndex) const throw();
+
+ void TrimLeft() throw();
+ void TrimRight() throw();
+ void Trim()
+ {
+ TrimRight();
+ TrimLeft();
+ }
+
+ void InsertAtFront(wchar_t c);
+ // void Insert_wchar_t(unsigned index, wchar_t c);
+ void Insert(unsigned index, const wchar_t *s);
+ void Insert(unsigned index, const UString &s);
+
+ void RemoveChar(wchar_t ch) throw();
+
+ void Replace(wchar_t oldChar, wchar_t newChar) throw();
+ void Replace(const UString &oldString, const UString &newString);
+
+ void Delete(int index) throw() { Delete((unsigned)index); }
+ void Delete(unsigned index) throw();
+ void Delete(unsigned index, unsigned count) throw();
+ void DeleteFrontal(unsigned num) throw();
+ void DeleteBack() { _chars[--_len] = 0; }
+ void DeleteFrom(int index) { DeleteFrom((unsigned)index); }
+ void DeleteFrom(unsigned index)
+ {
+ if (index < _len)
+ {
+ _len = index;
+ _chars[index] = 0;
+ }
+ }
+
+ void Wipe_and_Empty()
+ {
+ if (_chars)
+ {
+ memset(_chars, 0, (_limit + 1) * sizeof(*_chars));
+ _len = 0;
+ }
+ }
+};
+
+
+class UString_Wipe: public UString
+{
+ Z7_CLASS_NO_COPY(UString_Wipe)
+public:
+ UString_Wipe(): UString() {}
+ // UString_Wipe(const UString &s): UString(s) {}
+ // UString_Wipe &operator=(const UString &s) { UString::operator=(s); return *this; }
+ // UString_Wipe &operator=(const wchar_t *s) { UString::operator=(s); return *this; }
+ ~UString_Wipe() { Wipe_and_Empty(); }
+};
+
+
+bool operator<(const UString &s1, const UString &s2);
+bool operator>(const UString &s1, const UString &s2);
+
+inline bool operator==(const UString &s1, const UString &s2) { return s1.Len() == s2.Len() && wcscmp(s1, s2) == 0; }
+inline bool operator==(const UString &s1, const wchar_t *s2) { return wcscmp(s1, s2) == 0; }
+inline bool operator==(const wchar_t *s1, const UString &s2) { return wcscmp(s1, s2) == 0; }
+
+inline bool operator!=(const UString &s1, const UString &s2) { return s1.Len() != s2.Len() || wcscmp(s1, s2) != 0; }
+inline bool operator!=(const UString &s1, const wchar_t *s2) { return wcscmp(s1, s2) != 0; }
+inline bool operator!=(const wchar_t *s1, const UString &s2) { return wcscmp(s1, s2) != 0; }
+
+
+// ---------- forbidden functions ----------
+
+void operator==(wchar_t c1, const UString &s2);
+void operator==(const UString &s1, wchar_t c2);
+
+void operator+(wchar_t c, const UString &s); // this function can be OK, but we don't use it
+
+void operator+(const AString &s1, const UString &s2);
+void operator+(const UString &s1, const AString &s2);
+
+void operator+(const UString &s1, const char *s2);
+void operator+(const char *s1, const UString &s2);
+
+void operator+(const UString &s, char c);
+void operator+(const UString &s, unsigned char c);
+void operator+(char c, const UString &s);
+void operator+(unsigned char c, const UString &s);
+void operator-(const UString &s1, wchar_t c);
+
+#ifdef _WIN32
+// can we forbid these functions, if wchar_t is 32-bit ?
+void operator+(const UString &s, int c);
+void operator+(const UString &s, unsigned c);
+void operator+(int c, const UString &s);
+void operator+(unsigned c, const UString &s);
+void operator-(const UString &s1, int c);
+void operator-(const UString &s1, unsigned c);
+#endif
+
+
+
+
+
+
+
+class UString2
+{
+ wchar_t *_chars;
+ unsigned _len;
+
+ void ReAlloc2(unsigned newLimit);
+ void SetStartLen(unsigned len);
+
+ // ---------- forbidden functions ----------
+
+ FORBID_STRING_OPS_UString2(char)
+ FORBID_STRING_OPS_UString2(signed char)
+ FORBID_STRING_OPS_UString2(unsigned char)
+ FORBID_STRING_OPS_UString2(short)
+
+ UString2 &operator=(wchar_t c);
+
+ UString2(const AString &s);
+ UString2 &operator=(const AString &s);
+ UString2 &operator+=(const AString &s);
+
+ #ifdef DEBUG_FSTRING_INHERITS_ASTRING
+ UString2(const FString &s);
+ UString2 &operator=(const FString &s);
+ UString2 &operator+=(const FString &s);
+ #endif
+
+public:
+ UString2(): _chars(NULL), _len(0) {}
+ UString2(const wchar_t *s);
+ UString2(const UString2 &s);
+ ~UString2() { if (_chars) { MY_STRING_DELETE(_chars) } }
+
+ unsigned Len() const { return _len; }
+ bool IsEmpty() const { return _len == 0; }
+ // void Empty() { _len = 0; _chars[0] = 0; }
+
+ // operator const wchar_t *() const { return _chars; }
+ const wchar_t *GetRawPtr() const { return _chars; }
+
+ int Compare(const wchar_t *s) const { return wcscmp(_chars, s); }
+
+ wchar_t *GetBuf(unsigned minLen)
+ {
+ if (!_chars || minLen > _len)
+ ReAlloc2(minLen);
+ return _chars;
+ }
+ void ReleaseBuf_SetLen(unsigned newLen) { _len = newLen; }
+
+ UString2 &operator=(const wchar_t *s);
+ UString2 &operator=(const UString2 &s);
+ void SetFromAscii(const char *s);
+};
+
+bool operator==(const UString2 &s1, const UString2 &s2);
+bool operator==(const UString2 &s1, const wchar_t *s2);
+bool operator==(const wchar_t *s1, const UString2 &s2);
+
+inline bool operator!=(const UString2 &s1, const UString2 &s2) { return !(s1 == s2); }
+inline bool operator!=(const UString2 &s1, const wchar_t *s2) { return !(s1 == s2); }
+inline bool operator!=(const wchar_t *s1, const UString2 &s2) { return !(s1 == s2); }
+
+
+// ---------- forbidden functions ----------
+
+void operator==(wchar_t c1, const UString2 &s2);
+void operator==(const UString2 &s1, wchar_t c2);
+bool operator<(const UString2 &s1, const UString2 &s2);
+bool operator>(const UString2 &s1, const UString2 &s2);
+
+void operator+(const UString2 &s1, const UString2 &s2);
+void operator+(const UString2 &s1, const wchar_t *s2);
+void operator+(const wchar_t *s1, const UString2 &s2);
+void operator+(wchar_t c, const UString2 &s);
+void operator+(const UString2 &s, wchar_t c);
+void operator+(const UString2 &s, char c);
+void operator+(const UString2 &s, unsigned char c);
+void operator+(char c, const UString2 &s);
+void operator+(unsigned char c, const UString2 &s);
+void operator-(const UString2 &s1, wchar_t c);
+
+
+
+
+
+
+typedef CObjectVector<AString> AStringVector;
+typedef CObjectVector<UString> UStringVector;
+
+#ifdef _UNICODE
+ typedef UString CSysString;
+#else
+ typedef AString CSysString;
+#endif
+
+typedef CObjectVector<CSysString> CSysStringVector;
+
+
+// ---------- FString ----------
+
+#ifndef DEBUG_FSTRING_INHERITS_ASTRING
+#ifdef _WIN32
+ #define USE_UNICODE_FSTRING
+#endif
+#endif
+
+#ifdef USE_UNICODE_FSTRING
+
+ #define MY_FTEXT(quote) L##quote
+
+ typedef wchar_t FChar;
+ typedef UString FString;
+
+ #define fs2us(_x_) (_x_)
+ #define us2fs(_x_) (_x_)
+ FString fas2fs(const char *s);
+ FString fas2fs(const AString &s);
+ AString fs2fas(const FChar *s);
+
+#else // USE_UNICODE_FSTRING
+
+ #define MY_FTEXT(quote) quote
+
+ typedef char FChar;
+
+ #ifdef DEBUG_FSTRING_INHERITS_ASTRING
+
+ class FString: public AString
+ {
+ // FString &operator=(const char *s);
+ FString &operator=(const AString &s);
+ // FString &operator+=(const AString &s);
+ public:
+ FString(const AString &s): AString(s.Ptr()) {}
+ FString(const FString &s): AString(s.Ptr()) {}
+ FString(const char *s): AString(s) {}
+ FString() {}
+ FString &operator=(const FString &s) { AString::operator=((const AString &)s); return *this; }
+ FString &operator=(char c) { AString::operator=(c); return *this; }
+ FString &operator+=(char c) { AString::operator+=(c); return *this; }
+ FString &operator+=(const FString &s) { AString::operator+=((const AString &)s); return *this; }
+ FString Left(unsigned count) const { return FString(AString::Left(count)); }
+ };
+ void operator+(const AString &s1, const FString &s2);
+ void operator+(const FString &s1, const AString &s2);
+
+ inline FString operator+(const FString &s1, const FString &s2)
+ {
+ AString s =(const AString &)s1 + (const AString &)s2;
+ return FString(s.Ptr());
+ // return FString((const AString &)s1 + (const AString &)s2);
+ }
+ inline FString operator+(const FString &s1, const FChar *s2)
+ {
+ return s1 + (FString)s2;
+ }
+ /*
+ inline FString operator+(const FChar *s1, const FString &s2)
+ {
+ return (FString)s1 + s2;
+ }
+ */
+
+ inline FString fas2fs(const char *s) { return FString(s); }
+
+ #else // DEBUG_FSTRING_INHERITS_ASTRING
+ typedef AString FString;
+ #define fas2fs(_x_) (_x_)
+ #endif // DEBUG_FSTRING_INHERITS_ASTRING
+
+ UString fs2us(const FChar *s);
+ UString fs2us(const FString &s);
+ FString us2fs(const wchar_t *s);
+ #define fs2fas(_x_) (_x_)
+
+#endif // USE_UNICODE_FSTRING
+
+#define FTEXT(quote) MY_FTEXT(quote)
+
+#define FCHAR_PATH_SEPARATOR FTEXT(CHAR_PATH_SEPARATOR)
+#define FSTRING_PATH_SEPARATOR FTEXT(STRING_PATH_SEPARATOR)
+
+// #define FCHAR_ANY_MASK FTEXT('*')
+// #define FSTRING_ANY_MASK FTEXT("*")
+
+typedef const FChar *CFSTR;
+
+typedef CObjectVector<FString> FStringVector;
+
+
+class CStringFinder
+{
+ AString _temp;
+public:
+ // list - is list of low case Ascii strings separated by space " ".
+ // the function returns true, if it can find exact word (str) in (list).
+ bool FindWord_In_LowCaseAsciiList_NoCase(const char *list, const wchar_t *str);
+};
+
+void SplitString(const UString &srcString, UStringVector &destStrings);
+
+#endif
+
+
+
+#if defined(_WIN32)
+ // #include <wchar.h>
+ // WCHAR_MAX is defined as ((wchar_t)-1)
+ #define Z7_WCHART_IS_16BIT 1
+#elif (defined(WCHAR_MAX) && (WCHAR_MAX <= 0xffff)) \
+ || (defined(__SIZEOF_WCHAR_T__) && (__SIZEOF_WCHAR_T__ == 2))
+ #define Z7_WCHART_IS_16BIT 1
+#endif
+
+#if WCHAR_PATH_SEPARATOR == L'\\'
+// WSL scheme
+#define WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT ((wchar_t)((unsigned)(0xF000) + (unsigned)'\\'))
+// #define WCHAR_IN_FILE_NAME_BACKSLASH_REPLACEMENT '_'
+#endif
diff --git a/CPP/Common/MyTypes.h b/CPP/Common/MyTypes.h
index 6e73aca..8f44f67 100644
--- a/CPP/Common/MyTypes.h
+++ b/CPP/Common/MyTypes.h
@@ -1,35 +1,37 @@
-// Common/MyTypes.h
-
-#ifndef __COMMON_MY_TYPES_H
-#define __COMMON_MY_TYPES_H
-
-#include "../../C/7zTypes.h"
-
-typedef int HRes;
-
-struct CBoolPair
-{
- bool Val;
- bool Def;
-
- CBoolPair(): Val(false), Def(false) {}
-
- void Init()
- {
- Val = false;
- Def = false;
- }
-
- void SetTrueTrue()
- {
- Val = true;
- Def = true;
- }
-};
-
-#define CLASS_NO_COPY(cls) \
- private: \
- cls(const cls &); \
- cls &operator=(const cls &);
-
-#endif
+// Common/MyTypes.h
+
+#ifndef ZIP7_INC_COMMON_MY_TYPES_H
+#define ZIP7_INC_COMMON_MY_TYPES_H
+
+#include "../../C/7zTypes.h"
+#include "Common.h"
+
+typedef int HRes;
+
+struct CBoolPair
+{
+ bool Val;
+ bool Def;
+
+ CBoolPair(): Val(false), Def(false) {}
+
+ void Init()
+ {
+ Val = false;
+ Def = false;
+ }
+
+ void SetTrueTrue()
+ {
+ Val = true;
+ Def = true;
+ }
+
+ void SetVal_as_Defined(bool val)
+ {
+ Val = val;
+ Def = true;
+ }
+};
+
+#endif
diff --git a/CPP/Common/MyUnknown.h b/CPP/Common/MyUnknown.h
index b1d476f..75ee96f 100644
--- a/CPP/Common/MyUnknown.h
+++ b/CPP/Common/MyUnknown.h
@@ -1,17 +1,8 @@
-// MyUnknown.h
-
-#ifndef __MY_UNKNOWN_H
-#define __MY_UNKNOWN_H
-
-#include "MyWindows.h"
-
-/*
-#ifdef _WIN32
-#include <basetyps.h>
-#include <unknwn.h>
-#else
-#include "MyWindows.h"
-#endif
-*/
-
-#endif
+// MyUnknown.h
+
+#ifndef ZIP7_INC_MY_UNKNOWN_H
+#define ZIP7_INC_MY_UNKNOWN_H
+
+#include "MyWindows.h"
+
+#endif
diff --git a/CPP/Common/MyVector.cpp b/CPP/Common/MyVector.cpp
index 9a6d1d5..0b1baf4 100644
--- a/CPP/Common/MyVector.cpp
+++ b/CPP/Common/MyVector.cpp
@@ -1,3 +1,3 @@
-// Common/MyVector.cpp
-
-#include "StdAfx.h"
+// Common/MyVector.cpp
+
+#include "StdAfx.h"
diff --git a/CPP/Common/MyVector.h b/CPP/Common/MyVector.h
index 21125fa..9ee7105 100644
--- a/CPP/Common/MyVector.h
+++ b/CPP/Common/MyVector.h
@@ -1,634 +1,710 @@
-// Common/MyVector.h
-
-#ifndef __COMMON_MY_VECTOR_H
-#define __COMMON_MY_VECTOR_H
-
-#include <string.h>
-
-template <class T>
-class CRecordVector
-{
- T *_items;
- unsigned _size;
- unsigned _capacity;
-
- void MoveItems(unsigned destIndex, unsigned srcIndex)
- {
- memmove(_items + destIndex, _items + srcIndex, (size_t)(_size - srcIndex) * sizeof(T));
- }
-
- void ReserveOnePosition()
- {
- if (_size == _capacity)
- {
- unsigned newCapacity = _capacity + (_capacity >> 2) + 1;
- T *p;
- MY_ARRAY_NEW(p, T, newCapacity);
- // p = new T[newCapacity];
- if (_size != 0)
- memcpy(p, _items, (size_t)_size * sizeof(T));
- delete []_items;
- _items = p;
- _capacity = newCapacity;
- }
- }
-
-public:
-
- CRecordVector(): _items(0), _size(0), _capacity(0) {}
-
- CRecordVector(const CRecordVector &v): _items(0), _size(0), _capacity(0)
- {
- unsigned size = v.Size();
- if (size != 0)
- {
- _items = new T[size];
- _size = size;
- _capacity = size;
- memcpy(_items, v._items, (size_t)size * sizeof(T));
- }
- }
-
- unsigned Size() const { return _size; }
- bool IsEmpty() const { return _size == 0; }
-
- void ConstructReserve(unsigned size)
- {
- if (size != 0)
- {
- MY_ARRAY_NEW(_items, T, size)
- // _items = new T[size];
- _capacity = size;
- }
- }
-
- void Reserve(unsigned newCapacity)
- {
- if (newCapacity > _capacity)
- {
- T *p;
- MY_ARRAY_NEW(p, T, newCapacity);
- // p = new T[newCapacity];
- if (_size != 0)
- memcpy(p, _items, (size_t)_size * sizeof(T));
- delete []_items;
- _items = p;
- _capacity = newCapacity;
- }
- }
-
- void ClearAndReserve(unsigned newCapacity)
- {
- Clear();
- if (newCapacity > _capacity)
- {
- delete []_items;
- _items = NULL;
- _capacity = 0;
- MY_ARRAY_NEW(_items, T, newCapacity)
- // _items = new T[newCapacity];
- _capacity = newCapacity;
- }
- }
-
- void ClearAndSetSize(unsigned newSize)
- {
- ClearAndReserve(newSize);
- _size = newSize;
- }
-
- void ChangeSize_KeepData(unsigned newSize)
- {
- if (newSize > _capacity)
- {
- T *p;
- MY_ARRAY_NEW(p, T, newSize)
- // p = new T[newSize];
- if (_size != 0)
- memcpy(p, _items, (size_t)_size * sizeof(T));
- delete []_items;
- _items = p;
- _capacity = newSize;
- }
- _size = newSize;
- }
-
- void ReserveDown()
- {
- if (_size == _capacity)
- return;
- T *p = NULL;
- if (_size != 0)
- {
- p = new T[_size];
- memcpy(p, _items, (size_t)_size * sizeof(T));
- }
- delete []_items;
- _items = p;
- _capacity = _size;
- }
-
- ~CRecordVector() { delete []_items; }
-
- void ClearAndFree()
- {
- delete []_items;
- _items = NULL;
- _size = 0;
- _capacity = 0;
- }
-
- void Clear() { _size = 0; }
-
- void DeleteBack() { _size--; }
-
- void DeleteFrom(unsigned index)
- {
- // if (index <= _size)
- _size = index;
- }
-
- void DeleteFrontal(unsigned num)
- {
- if (num != 0)
- {
- MoveItems(0, num);
- _size -= num;
- }
- }
-
- void Delete(unsigned index)
- {
- MoveItems(index, index + 1);
- _size -= 1;
- }
-
- /*
- void Delete(unsigned index, unsigned num)
- {
- if (num > 0)
- {
- MoveItems(index, index + num);
- _size -= num;
- }
- }
- */
-
- CRecordVector& operator=(const CRecordVector &v)
- {
- if (&v == this)
- return *this;
- unsigned size = v.Size();
- if (size > _capacity)
- {
- delete []_items;
- _capacity = 0;
- _size = 0;
- _items = NULL;
- _items = new T[size];
- _capacity = size;
- }
- _size = size;
- if (size != 0)
- memcpy(_items, v._items, (size_t)size * sizeof(T));
- return *this;
- }
-
- CRecordVector& operator+=(const CRecordVector &v)
- {
- unsigned size = v.Size();
- Reserve(_size + size);
- if (size != 0)
- memcpy(_items + _size, v._items, (size_t)size * sizeof(T));
- _size += size;
- return *this;
- }
-
- unsigned Add(const T item)
- {
- ReserveOnePosition();
- _items[_size] = item;
- return _size++;
- }
-
- void AddInReserved(const T item)
- {
- _items[_size++] = item;
- }
-
- void Insert(unsigned index, const T item)
- {
- ReserveOnePosition();
- MoveItems(index + 1, index);
- _items[index] = item;
- _size++;
- }
-
- void MoveToFront(unsigned index)
- {
- if (index != 0)
- {
- T temp = _items[index];
- memmove(_items + 1, _items, (size_t)index * sizeof(T));
- _items[0] = temp;
- }
- }
-
- const T& operator[](unsigned index) const { return _items[index]; }
- T& operator[](unsigned index) { return _items[index]; }
- const T& Front() const { return _items[0]; }
- T& Front() { return _items[0]; }
- const T& Back() const { return _items[(size_t)_size - 1]; }
- T& Back() { return _items[(size_t)_size - 1]; }
-
- /*
- void Swap(unsigned i, unsigned j)
- {
- T temp = _items[i];
- _items[i] = _items[j];
- _items[j] = temp;
- }
- */
-
- int FindInSorted(const T item, unsigned left, unsigned right) const
- {
- while (left != right)
- {
- unsigned mid = (left + right) / 2;
- const T midVal = (*this)[mid];
- if (item == midVal)
- return mid;
- if (item < midVal)
- right = mid;
- else
- left = mid + 1;
- }
- return -1;
- }
-
- int FindInSorted2(const T &item, unsigned left, unsigned right) const
- {
- while (left != right)
- {
- unsigned mid = (left + right) / 2;
- const T& midVal = (*this)[mid];
- int comp = item.Compare(midVal);
- if (comp == 0)
- return mid;
- if (comp < 0)
- right = mid;
- else
- left = mid + 1;
- }
- return -1;
- }
-
- int FindInSorted(const T item) const
- {
- return FindInSorted(item, 0, _size);
- }
-
- int FindInSorted2(const T &item) const
- {
- return FindInSorted2(item, 0, _size);
- }
-
- unsigned AddToUniqueSorted(const T item)
- {
- unsigned left = 0, right = _size;
- while (left != right)
- {
- unsigned mid = (left + right) / 2;
- const T midVal = (*this)[mid];
- if (item == midVal)
- return mid;
- if (item < midVal)
- right = mid;
- else
- left = mid + 1;
- }
- Insert(right, item);
- return right;
- }
-
- unsigned AddToUniqueSorted2(const T &item)
- {
- unsigned left = 0, right = _size;
- while (left != right)
- {
- unsigned mid = (left + right) / 2;
- const T& midVal = (*this)[mid];
- int comp = item.Compare(midVal);
- if (comp == 0)
- return mid;
- if (comp < 0)
- right = mid;
- else
- left = mid + 1;
- }
- Insert(right, item);
- return right;
- }
-
- static void SortRefDown(T* p, unsigned k, unsigned size, int (*compare)(const T*, const T*, void *), void *param)
- {
- T temp = p[k];
- for (;;)
- {
- unsigned s = (k << 1);
- if (s > size)
- break;
- if (s < size && compare(p + s + 1, p + s, param) > 0)
- s++;
- if (compare(&temp, p + s, param) >= 0)
- break;
- p[k] = p[s];
- k = s;
- }
- p[k] = temp;
- }
-
- void Sort(int (*compare)(const T*, const T*, void *), void *param)
- {
- unsigned size = _size;
- if (size <= 1)
- return;
- T* p = (&Front()) - 1;
- {
- unsigned i = size >> 1;
- do
- SortRefDown(p, i, size, compare, param);
- while (--i != 0);
- }
- do
- {
- T temp = p[size];
- p[size--] = p[1];
- p[1] = temp;
- SortRefDown(p, 1, size, compare, param);
- }
- while (size > 1);
- }
-
- static void SortRefDown2(T* p, unsigned k, unsigned size)
- {
- T temp = p[k];
- for (;;)
- {
- unsigned s = (k << 1);
- if (s > size)
- break;
- if (s < size && p[(size_t)s + 1].Compare(p[s]) > 0)
- s++;
- if (temp.Compare(p[s]) >= 0)
- break;
- p[k] = p[s];
- k = s;
- }
- p[k] = temp;
- }
-
- void Sort2()
- {
- unsigned size = _size;
- if (size <= 1)
- return;
- T* p = (&Front()) - 1;
- {
- unsigned i = size >> 1;
- do
- SortRefDown2(p, i, size);
- while (--i != 0);
- }
- do
- {
- T temp = p[size];
- p[size--] = p[1];
- p[1] = temp;
- SortRefDown2(p, 1, size);
- }
- while (size > 1);
- }
-};
-
-typedef CRecordVector<int> CIntVector;
-typedef CRecordVector<unsigned int> CUIntVector;
-typedef CRecordVector<bool> CBoolVector;
-typedef CRecordVector<unsigned char> CByteVector;
-typedef CRecordVector<void *> CPointerVector;
-
-template <class T>
-class CObjectVector
-{
- CPointerVector _v;
-public:
- unsigned Size() const { return _v.Size(); }
- bool IsEmpty() const { return _v.IsEmpty(); }
- void ReserveDown() { _v.ReserveDown(); }
- // void Reserve(unsigned newCapacity) { _v.Reserve(newCapacity); }
- void ClearAndReserve(unsigned newCapacity) { Clear(); _v.ClearAndReserve(newCapacity); }
-
- CObjectVector() {};
- CObjectVector(const CObjectVector &v)
- {
- unsigned size = v.Size();
- _v.ConstructReserve(size);
- for (unsigned i = 0; i < size; i++)
- _v.AddInReserved(new T(v[i]));
- }
- CObjectVector& operator=(const CObjectVector &v)
- {
- if (&v == this)
- return *this;
- Clear();
- unsigned size = v.Size();
- _v.Reserve(size);
- for (unsigned i = 0; i < size; i++)
- _v.AddInReserved(new T(v[i]));
- return *this;
- }
-
- CObjectVector& operator+=(const CObjectVector &v)
- {
- unsigned size = v.Size();
- _v.Reserve(Size() + size);
- for (unsigned i = 0; i < size; i++)
- _v.AddInReserved(new T(v[i]));
- return *this;
- }
-
- const T& operator[](unsigned index) const { return *((T *)_v[index]); }
- T& operator[](unsigned index) { return *((T *)_v[index]); }
- const T& Front() const { return operator[](0); }
- T& Front() { return operator[](0); }
- const T& Back() const { return *(T *)_v.Back(); }
- T& Back() { return *(T *)_v.Back(); }
-
- void MoveToFront(unsigned index) { _v.MoveToFront(index); }
-
- unsigned Add(const T& item) { return _v.Add(new T(item)); }
-
- void AddInReserved(const T& item) { _v.AddInReserved(new T(item)); }
-
- T& AddNew()
- {
- T *p = new T;
- _v.Add(p);
- return *p;
- }
-
- T& AddNewInReserved()
- {
- T *p = new T;
- _v.AddInReserved(p);
- return *p;
- }
-
- void Insert(unsigned index, const T& item) { _v.Insert(index, new T(item)); }
-
- T& InsertNew(unsigned index)
- {
- T *p = new T;
- _v.Insert(index, p);
- return *p;
- }
-
- ~CObjectVector()
- {
- for (unsigned i = _v.Size(); i != 0;)
- delete (T *)_v[--i];
- }
-
- void ClearAndFree()
- {
- Clear();
- _v.ClearAndFree();
- }
-
- void Clear()
- {
- for (unsigned i = _v.Size(); i != 0;)
- delete (T *)_v[--i];
- _v.Clear();
- }
-
- void DeleteFrom(unsigned index)
- {
- unsigned size = _v.Size();
- for (unsigned i = index; i < size; i++)
- delete (T *)_v[i];
- _v.DeleteFrom(index);
- }
-
- void DeleteFrontal(unsigned num)
- {
- for (unsigned i = 0; i < num; i++)
- delete (T *)_v[i];
- _v.DeleteFrontal(num);
- }
-
- void DeleteBack()
- {
- delete (T *)_v.Back();
- _v.DeleteBack();
- }
-
- void Delete(unsigned index)
- {
- delete (T *)_v[index];
- _v.Delete(index);
- }
-
- /*
- void Delete(unsigned index, unsigned num)
- {
- for (unsigned i = 0; i < num; i++)
- delete (T *)_v[index + i];
- _v.Delete(index, num);
- }
- */
-
- /*
- int Find(const T& item) const
- {
- unsigned size = Size();
- for (unsigned i = 0; i < size; i++)
- if (item == (*this)[i])
- return i;
- return -1;
- }
- */
-
- int FindInSorted(const T& item) const
- {
- unsigned left = 0, right = Size();
- while (left != right)
- {
- unsigned mid = (left + right) / 2;
- const T& midVal = (*this)[mid];
- int comp = item.Compare(midVal);
- if (comp == 0)
- return mid;
- if (comp < 0)
- right = mid;
- else
- left = mid + 1;
- }
- return -1;
- }
-
- unsigned AddToUniqueSorted(const T& item)
- {
- unsigned left = 0, right = Size();
- while (left != right)
- {
- unsigned mid = (left + right) / 2;
- const T& midVal = (*this)[mid];
- int comp = item.Compare(midVal);
- if (comp == 0)
- return mid;
- if (comp < 0)
- right = mid;
- else
- left = mid + 1;
- }
- Insert(right, item);
- return right;
- }
-
- /*
- unsigned AddToSorted(const T& item)
- {
- unsigned left = 0, right = Size();
- while (left != right)
- {
- unsigned mid = (left + right) / 2;
- const T& midVal = (*this)[mid];
- int comp = item.Compare(midVal);
- if (comp == 0)
- {
- right = mid + 1;
- break;
- }
- if (comp < 0)
- right = mid;
- else
- left = mid + 1;
- }
- Insert(right, item);
- return right;
- }
- */
-
- void Sort(int (*compare)(void *const *, void *const *, void *), void *param)
- { _v.Sort(compare, param); }
-
- static int CompareObjectItems(void *const *a1, void *const *a2, void * /* param */)
- { return (*(*((const T **)a1))).Compare(*(*((const T **)a2))); }
-
- void Sort() { _v.Sort(CompareObjectItems, 0); }
-};
-
-#define FOR_VECTOR(_i_, _v_) for (unsigned _i_ = 0; _i_ < (_v_).Size(); _i_++)
-
-#endif
+// Common/MyVector.h
+
+#ifndef ZIP7_INC_COMMON_MY_VECTOR_H
+#define ZIP7_INC_COMMON_MY_VECTOR_H
+
+#include <string.h>
+
+#include "Common.h"
+
+const unsigned k_VectorSizeMax = ((unsigned)1 << 31) - 1;
+
+template <class T>
+class CRecordVector
+{
+ T *_items;
+ unsigned _size;
+ unsigned _capacity;
+
+ void MoveItems(unsigned destIndex, unsigned srcIndex)
+ {
+ memmove(_items + destIndex, _items + srcIndex, (size_t)(_size - srcIndex) * sizeof(T));
+ }
+
+ void ReAllocForNewCapacity(const unsigned newCapacity)
+ {
+ T *p;
+ Z7_ARRAY_NEW(p, T, newCapacity)
+ // p = new T[newCapacity];
+ if (_size != 0)
+ memcpy(p, _items, (size_t)_size * sizeof(T));
+ delete []_items;
+ _items = p;
+ _capacity = newCapacity;
+ }
+
+public:
+
+ void ReserveOnePosition()
+ {
+ if (_size != _capacity)
+ return;
+ if (_capacity >= k_VectorSizeMax)
+ throw 2021;
+ const unsigned rem = k_VectorSizeMax - _capacity;
+ unsigned add = (_capacity >> 2) + 1;
+ if (add > rem)
+ add = rem;
+ ReAllocForNewCapacity(_capacity + add);
+ }
+
+ CRecordVector(): _items(NULL), _size(0), _capacity(0) {}
+
+ CRecordVector(const CRecordVector &v): _items(NULL), _size(0), _capacity(0)
+ {
+ const unsigned size = v.Size();
+ if (size != 0)
+ {
+ // Z7_ARRAY_NEW(_items, T, size)
+ _items = new T[size];
+ _size = size;
+ _capacity = size;
+ memcpy(_items, v._items, (size_t)size * sizeof(T));
+ }
+ }
+
+ unsigned Size() const { return _size; }
+ bool IsEmpty() const { return _size == 0; }
+
+ void ConstructReserve(unsigned size)
+ {
+ if (size != 0)
+ {
+ Z7_ARRAY_NEW(_items, T, size)
+ // _items = new T[size];
+ _capacity = size;
+ }
+ }
+
+ void Reserve(unsigned newCapacity)
+ {
+ if (newCapacity > _capacity)
+ {
+ if (newCapacity > k_VectorSizeMax)
+ throw 2021;
+ ReAllocForNewCapacity(newCapacity);
+ }
+ }
+
+ void ChangeSize_KeepData(unsigned newSize)
+ {
+ Reserve(newSize);
+ _size = newSize;
+ }
+
+ void ClearAndReserve(unsigned newCapacity)
+ {
+ Clear();
+ if (newCapacity > _capacity)
+ {
+ if (newCapacity > k_VectorSizeMax)
+ throw 2021;
+ delete []_items;
+ _items = NULL;
+ _capacity = 0;
+ Z7_ARRAY_NEW(_items, T, newCapacity)
+ // _items = new T[newCapacity];
+ _capacity = newCapacity;
+ }
+ }
+
+ void ClearAndSetSize(unsigned newSize)
+ {
+ ClearAndReserve(newSize);
+ _size = newSize;
+ }
+
+ void ReserveDown()
+ {
+ if (_size == _capacity)
+ return;
+ T *p = NULL;
+ if (_size != 0)
+ {
+ // Z7_ARRAY_NEW(p, T, _size)
+ p = new T[_size];
+ memcpy(p, _items, (size_t)_size * sizeof(T));
+ }
+ delete []_items;
+ _items = p;
+ _capacity = _size;
+ }
+
+ ~CRecordVector() { delete []_items; }
+
+ void ClearAndFree()
+ {
+ delete []_items;
+ _items = NULL;
+ _size = 0;
+ _capacity = 0;
+ }
+
+ void Clear() { _size = 0; }
+
+ void DeleteBack() { _size--; }
+
+ void DeleteFrom(unsigned index)
+ {
+ // if (index <= _size)
+ _size = index;
+ }
+
+ void DeleteFrontal(unsigned num)
+ {
+ if (num != 0)
+ {
+ MoveItems(0, num);
+ _size -= num;
+ }
+ }
+
+ void Delete(unsigned index)
+ {
+ MoveItems(index, index + 1);
+ _size -= 1;
+ }
+
+ /*
+ void Delete(unsigned index, unsigned num)
+ {
+ if (num > 0)
+ {
+ MoveItems(index, index + num);
+ _size -= num;
+ }
+ }
+ */
+
+ CRecordVector& operator=(const CRecordVector &v)
+ {
+ if (&v == this)
+ return *this;
+ const unsigned size = v.Size();
+ if (size > _capacity)
+ {
+ delete []_items;
+ _capacity = 0;
+ _size = 0;
+ _items = NULL;
+ _items = new T[size];
+ _capacity = size;
+ }
+ _size = size;
+ if (size != 0)
+ memcpy(_items, v._items, (size_t)size * sizeof(T));
+ return *this;
+ }
+
+ CRecordVector& operator+=(const CRecordVector &v)
+ {
+ const unsigned size = v.Size();
+ if (size != 0)
+ {
+ if (_size >= k_VectorSizeMax || size > k_VectorSizeMax - _size)
+ throw 2021;
+ const unsigned newSize = _size + size;
+ Reserve(newSize);
+ memcpy(_items + _size, v._items, (size_t)size * sizeof(T));
+ _size = newSize;
+ }
+ return *this;
+ }
+
+ unsigned Add(const T item)
+ {
+ ReserveOnePosition();
+ const unsigned size = _size;
+ _size = size + 1;
+ _items[size] = item;
+ return size;
+ }
+
+ /*
+ unsigned Add2(const T &item)
+ {
+ ReserveOnePosition();
+ const unsigned size = _size;
+ _size = size + 1;
+ _items[size] = item;
+ return size;
+ }
+ */
+
+ unsigned AddInReserved(const T item)
+ {
+ const unsigned size = _size;
+ _size = size + 1;
+ _items[size] = item;
+ return size;
+ }
+
+ void Insert(unsigned index, const T item)
+ {
+ ReserveOnePosition();
+ MoveItems(index + 1, index);
+ _items[index] = item;
+ _size++;
+ }
+
+ void InsertInReserved(unsigned index, const T item)
+ {
+ MoveItems(index + 1, index);
+ _items[index] = item;
+ _size++;
+ }
+
+ void MoveToFront(unsigned index)
+ {
+ if (index != 0)
+ {
+ T temp = _items[index];
+ memmove(_items + 1, _items, (size_t)index * sizeof(T));
+ _items[0] = temp;
+ }
+ }
+
+ const T& operator[](unsigned index) const { return _items[index]; }
+ T& operator[](unsigned index) { return _items[index]; }
+ const T& operator[](int index) const { return _items[(unsigned)index]; }
+ T& operator[](int index) { return _items[(unsigned)index]; }
+ const T& Front() const { return _items[0]; }
+ T& Front() { return _items[0]; }
+ const T& Back() const { return _items[(size_t)_size - 1]; }
+ T& Back() { return _items[(size_t)_size - 1]; }
+
+ /*
+ void Swap(unsigned i, unsigned j)
+ {
+ T temp = _items[i];
+ _items[i] = _items[j];
+ _items[j] = temp;
+ }
+ */
+
+ int FindInSorted(const T item, unsigned left, unsigned right) const
+ {
+ while (left != right)
+ {
+ // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const unsigned mid = (left + right) / 2;
+ const T midVal = (*this)[mid];
+ if (item == midVal)
+ return (int)mid;
+ if (item < midVal)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+ }
+
+ int FindInSorted2(const T &item, unsigned left, unsigned right) const
+ {
+ while (left != right)
+ {
+ // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const unsigned mid = (left + right) / 2;
+ const T& midVal = (*this)[mid];
+ const int comp = item.Compare(midVal);
+ if (comp == 0)
+ return (int)mid;
+ if (comp < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+ }
+
+ int FindInSorted(const T item) const
+ {
+ return FindInSorted(item, 0, _size);
+ }
+
+ int FindInSorted2(const T &item) const
+ {
+ return FindInSorted2(item, 0, _size);
+ }
+
+ unsigned AddToUniqueSorted(const T item)
+ {
+ unsigned left = 0, right = _size;
+ while (left != right)
+ {
+ // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const unsigned mid = (left + right) / 2;
+ const T midVal = (*this)[mid];
+ if (item == midVal)
+ return mid;
+ if (item < midVal)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ Insert(right, item);
+ return right;
+ }
+
+ unsigned AddToUniqueSorted2(const T &item)
+ {
+ unsigned left = 0, right = _size;
+ while (left != right)
+ {
+ // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const unsigned mid = (left + right) / 2;
+ const T& midVal = (*this)[mid];
+ const int comp = item.Compare(midVal);
+ if (comp == 0)
+ return mid;
+ if (comp < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ Insert(right, item);
+ return right;
+ }
+
+ static void SortRefDown(T* p, unsigned k, unsigned size, int (*compare)(const T*, const T*, void *), void *param)
+ {
+ T temp = p[k];
+ for (;;)
+ {
+ unsigned s = (k << 1);
+ if (s > size)
+ break;
+ if (s < size && compare(p + s + 1, p + s, param) > 0)
+ s++;
+ if (compare(&temp, p + s, param) >= 0)
+ break;
+ p[k] = p[s];
+ k = s;
+ }
+ p[k] = temp;
+ }
+
+ void Sort(int (*compare)(const T*, const T*, void *), void *param)
+ {
+ unsigned size = _size;
+ if (size <= 1)
+ return;
+ T* p = (&Front()) - 1;
+ {
+ unsigned i = size >> 1;
+ do
+ SortRefDown(p, i, size, compare, param);
+ while (--i != 0);
+ }
+ do
+ {
+ T temp = p[size];
+ p[size--] = p[1];
+ p[1] = temp;
+ SortRefDown(p, 1, size, compare, param);
+ }
+ while (size > 1);
+ }
+
+ static void SortRefDown2(T* p, unsigned k, unsigned size)
+ {
+ T temp = p[k];
+ for (;;)
+ {
+ unsigned s = (k << 1);
+ if (s > size)
+ break;
+ if (s < size && p[(size_t)s + 1].Compare(p[s]) > 0)
+ s++;
+ if (temp.Compare(p[s]) >= 0)
+ break;
+ p[k] = p[s];
+ k = s;
+ }
+ p[k] = temp;
+ }
+
+ void Sort2()
+ {
+ unsigned size = _size;
+ if (size <= 1)
+ return;
+ T* p = (&Front()) - 1;
+ {
+ unsigned i = size >> 1;
+ do
+ SortRefDown2(p, i, size);
+ while (--i != 0);
+ }
+ do
+ {
+ T temp = p[size];
+ p[size--] = p[1];
+ p[1] = temp;
+ SortRefDown2(p, 1, size);
+ }
+ while (size > 1);
+ }
+};
+
+typedef CRecordVector<int> CIntVector;
+typedef CRecordVector<unsigned int> CUIntVector;
+typedef CRecordVector<bool> CBoolVector;
+typedef CRecordVector<unsigned char> CByteVector;
+typedef CRecordVector<void *> CPointerVector;
+
+template <class T>
+class CObjectVector
+{
+ CPointerVector _v;
+public:
+ unsigned Size() const { return _v.Size(); }
+ bool IsEmpty() const { return _v.IsEmpty(); }
+ void ReserveDown() { _v.ReserveDown(); }
+ // void Reserve(unsigned newCapacity) { _v.Reserve(newCapacity); }
+ void ClearAndReserve(unsigned newCapacity) { Clear(); _v.ClearAndReserve(newCapacity); }
+
+ CObjectVector() {}
+ CObjectVector(const CObjectVector &v)
+ {
+ const unsigned size = v.Size();
+ _v.ConstructReserve(size);
+ for (unsigned i = 0; i < size; i++)
+ AddInReserved(v[i]);
+ }
+ CObjectVector& operator=(const CObjectVector &v)
+ {
+ if (&v == this)
+ return *this;
+ Clear();
+ const unsigned size = v.Size();
+ _v.Reserve(size);
+ for (unsigned i = 0; i < size; i++)
+ AddInReserved(v[i]);
+ return *this;
+ }
+
+ CObjectVector& operator+=(const CObjectVector &v)
+ {
+ const unsigned addSize = v.Size();
+ if (addSize != 0)
+ {
+ const unsigned size = Size();
+ if (size >= k_VectorSizeMax || addSize > k_VectorSizeMax - size)
+ throw 2021;
+ _v.Reserve(size + addSize);
+ for (unsigned i = 0; i < addSize; i++)
+ AddInReserved(v[i]);
+ }
+ return *this;
+ }
+
+ const T& operator[](unsigned index) const { return *((T *)_v[index]); }
+ T& operator[](unsigned index) { return *((T *)_v[index]); }
+ const T& operator[](int index) const { return *((T *)_v[(unsigned)index]); }
+ T& operator[](int index) { return *((T *)_v[(unsigned)index]); }
+ const T& Front() const { return operator[](0); }
+ T& Front() { return operator[](0); }
+ const T& Back() const { return *(T *)_v.Back(); }
+ T& Back() { return *(T *)_v.Back(); }
+
+ void MoveToFront(unsigned index) { _v.MoveToFront(index); }
+
+ unsigned Add(const T& item)
+ {
+ _v.ReserveOnePosition();
+ return AddInReserved(item);
+ }
+
+ unsigned AddInReserved(const T& item)
+ {
+ return _v.AddInReserved(new T(item));
+ }
+
+ void ReserveOnePosition()
+ {
+ _v.ReserveOnePosition();
+ }
+
+ unsigned AddInReserved_Ptr_of_new(T *ptr)
+ {
+ return _v.AddInReserved(ptr);
+ }
+
+ #define VECTOR_ADD_NEW_OBJECT(v, a) \
+ (v).ReserveOnePosition(); \
+ (v).AddInReserved_Ptr_of_new(new a);
+
+
+ T& AddNew()
+ {
+ _v.ReserveOnePosition();
+ T *p = new T;
+ _v.AddInReserved(p);
+ return *p;
+ }
+
+ T& AddNewInReserved()
+ {
+ T *p = new T;
+ _v.AddInReserved(p);
+ return *p;
+ }
+
+ void Insert(unsigned index, const T& item)
+ {
+ _v.ReserveOnePosition();
+ _v.InsertInReserved(index, new T(item));
+ }
+
+ T& InsertNew(unsigned index)
+ {
+ _v.ReserveOnePosition();
+ T *p = new T;
+ _v.InsertInReserved(index, p);
+ return *p;
+ }
+
+ ~CObjectVector()
+ {
+ for (unsigned i = _v.Size(); i != 0;)
+ delete (T *)_v[--i];
+ }
+
+ void ClearAndFree()
+ {
+ Clear();
+ _v.ClearAndFree();
+ }
+
+ void Clear()
+ {
+ for (unsigned i = _v.Size(); i != 0;)
+ delete (T *)_v[--i];
+ _v.Clear();
+ }
+
+ void DeleteFrom(unsigned index)
+ {
+ const unsigned size = _v.Size();
+ for (unsigned i = index; i < size; i++)
+ delete (T *)_v[i];
+ _v.DeleteFrom(index);
+ }
+
+ void DeleteFrontal(unsigned num)
+ {
+ for (unsigned i = 0; i < num; i++)
+ delete (T *)_v[i];
+ _v.DeleteFrontal(num);
+ }
+
+ void DeleteBack()
+ {
+ delete (T *)_v.Back();
+ _v.DeleteBack();
+ }
+
+ void Delete(unsigned index)
+ {
+ delete (T *)_v[index];
+ _v.Delete(index);
+ }
+ // void Delete(int index) { Delete((unsigned)index); }
+
+ /*
+ void Delete(unsigned index, unsigned num)
+ {
+ for (unsigned i = 0; i < num; i++)
+ delete (T *)_v[index + i];
+ _v.Delete(index, num);
+ }
+ */
+
+ /*
+ int Find(const T& item) const
+ {
+ unsigned size = Size();
+ for (unsigned i = 0; i < size; i++)
+ if (item == (*this)[i])
+ return i;
+ return -1;
+ }
+ */
+
+ int FindInSorted(const T& item) const
+ {
+ unsigned left = 0, right = Size();
+ while (left != right)
+ {
+ // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const unsigned mid = (left + right) / 2;
+ const T& midVal = (*this)[mid];
+ const int comp = item.Compare(midVal);
+ if (comp == 0)
+ return (int)mid;
+ if (comp < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ return -1;
+ }
+
+ unsigned AddToUniqueSorted(const T& item)
+ {
+ unsigned left = 0, right = Size();
+ while (left != right)
+ {
+ // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const unsigned mid = (left + right) / 2;
+ const T& midVal = (*this)[mid];
+ const int comp = item.Compare(midVal);
+ if (comp == 0)
+ return mid;
+ if (comp < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ Insert(right, item);
+ return right;
+ }
+
+ /*
+ unsigned AddToSorted(const T& item)
+ {
+ unsigned left = 0, right = Size();
+ while (left != right)
+ {
+ // const unsigned mid = (unsigned)(((size_t)left + (size_t)right) / 2);
+ const unsigned mid = (left + right) / 2;
+ const T& midVal = (*this)[mid];
+ const int comp = item.Compare(midVal);
+ if (comp == 0)
+ {
+ right = mid + 1;
+ break;
+ }
+ if (comp < 0)
+ right = mid;
+ else
+ left = mid + 1;
+ }
+ Insert(right, item);
+ return right;
+ }
+ */
+
+ void Sort(int (*compare)(void *const *, void *const *, void *), void *param)
+ { _v.Sort(compare, param); }
+
+ static int CompareObjectItems(void *const *a1, void *const *a2, void * /* param */)
+ { return (*(*((const T *const *)a1))).Compare(*(*((const T *const *)a2))); }
+
+ void Sort() { _v.Sort(CompareObjectItems, NULL); }
+};
+
+#define FOR_VECTOR(_i_, _v_) for (unsigned _i_ = 0; _i_ < (_v_).Size(); _i_++)
+
+#endif
diff --git a/CPP/Common/MyWindows.cpp b/CPP/Common/MyWindows.cpp
index bc9f7be..ae284eb 100644
--- a/CPP/Common/MyWindows.cpp
+++ b/CPP/Common/MyWindows.cpp
@@ -1,145 +1,292 @@
-// MyWindows.cpp
-
-#include "StdAfx.h"
-
-#ifndef _WIN32
-
-#include <stdlib.h>
-
-#include "MyWindows.h"
-
-static inline void *AllocateForBSTR(size_t cb) { return ::malloc(cb); }
-static inline void FreeForBSTR(void *pv) { ::free(pv);}
-
-/* Win32 uses DWORD (32-bit) type to store size of string before (OLECHAR *) string.
- We must select CBstrSizeType for another systems (not Win32):
-
- if (CBstrSizeType is UINT32),
- then we support only strings smaller than 4 GB.
- Win32 version always has that limitation.
-
- if (CBstrSizeType is UINT),
- (UINT can be 16/32/64-bit)
- We can support strings larger than 4 GB (if UINT is 64-bit),
- but sizeof(UINT) can be different in parts compiled by
- different compilers/settings,
- and we can't send such BSTR strings between such parts.
-*/
-
-typedef UINT32 CBstrSizeType;
-// typedef UINT CBstrSizeType;
-
-#define k_BstrSize_Max 0xFFFFFFFF
-// #define k_BstrSize_Max UINT_MAX
-// #define k_BstrSize_Max ((UINT)(INT)-1)
-
-BSTR SysAllocStringByteLen(LPCSTR s, UINT len)
-{
- /* Original SysAllocStringByteLen in Win32 maybe fills only unaligned null OLECHAR at the end.
- We provide also aligned null OLECHAR at the end. */
-
- if (len >= (k_BstrSize_Max - sizeof(OLECHAR) - sizeof(OLECHAR) - sizeof(CBstrSizeType)))
- return NULL;
-
- UINT size = (len + sizeof(OLECHAR) + sizeof(OLECHAR) - 1) & ~(sizeof(OLECHAR) - 1);
- void *p = AllocateForBSTR(size + sizeof(CBstrSizeType));
- if (!p)
- return NULL;
- *(CBstrSizeType *)p = (CBstrSizeType)len;
- BSTR bstr = (BSTR)((CBstrSizeType *)p + 1);
- if (s)
- memcpy(bstr, s, len);
- for (; len < size; len++)
- ((Byte *)bstr)[len] = 0;
- return bstr;
-}
-
-BSTR SysAllocStringLen(const OLECHAR *s, UINT len)
-{
- if (len >= (k_BstrSize_Max - sizeof(OLECHAR) - sizeof(CBstrSizeType)) / sizeof(OLECHAR))
- return NULL;
-
- UINT size = len * sizeof(OLECHAR);
- void *p = AllocateForBSTR(size + sizeof(CBstrSizeType) + sizeof(OLECHAR));
- if (!p)
- return NULL;
- *(CBstrSizeType *)p = (CBstrSizeType)size;
- BSTR bstr = (BSTR)((CBstrSizeType *)p + 1);
- if (s)
- memcpy(bstr, s, size);
- bstr[len] = 0;
- return bstr;
-}
-
-BSTR SysAllocString(const OLECHAR *s)
-{
- if (!s)
- return 0;
- const OLECHAR *s2 = s;
- while (*s2 != 0)
- s2++;
- return SysAllocStringLen(s, (UINT)(s2 - s));
-}
-
-void SysFreeString(BSTR bstr)
-{
- if (bstr)
- FreeForBSTR((CBstrSizeType *)bstr - 1);
-}
-
-UINT SysStringByteLen(BSTR bstr)
-{
- if (!bstr)
- return 0;
- return *((CBstrSizeType *)bstr - 1);
-}
-
-UINT SysStringLen(BSTR bstr)
-{
- if (!bstr)
- return 0;
- return *((CBstrSizeType *)bstr - 1) / sizeof(OLECHAR);
-}
-
-
-HRESULT VariantClear(VARIANTARG *prop)
-{
- if (prop->vt == VT_BSTR)
- SysFreeString(prop->bstrVal);
- prop->vt = VT_EMPTY;
- return S_OK;
-}
-
-HRESULT VariantCopy(VARIANTARG *dest, const VARIANTARG *src)
-{
- HRESULT res = ::VariantClear(dest);
- if (res != S_OK)
- return res;
- if (src->vt == VT_BSTR)
- {
- dest->bstrVal = SysAllocStringByteLen((LPCSTR)src->bstrVal,
- SysStringByteLen(src->bstrVal));
- if (!dest->bstrVal)
- return E_OUTOFMEMORY;
- dest->vt = VT_BSTR;
- }
- else
- *dest = *src;
- return S_OK;
-}
-
-LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2)
-{
- if (ft1->dwHighDateTime < ft2->dwHighDateTime) return -1;
- if (ft1->dwHighDateTime > ft2->dwHighDateTime) return 1;
- if (ft1->dwLowDateTime < ft2->dwLowDateTime) return -1;
- if (ft1->dwLowDateTime > ft2->dwLowDateTime) return 1;
- return 0;
-}
-
-DWORD GetLastError()
-{
- return 0;
-}
-
-#endif
+// MyWindows.cpp
+
+#include "StdAfx.h"
+
+#ifndef _WIN32
+
+#include <stdlib.h>
+#include <time.h>
+#ifdef __GNUC__
+#include <sys/time.h>
+#endif
+
+#include "MyWindows.h"
+
+static inline void *AllocateForBSTR(size_t cb) { return ::malloc(cb); }
+static inline void FreeForBSTR(void *pv) { ::free(pv);}
+
+/* Win32 uses DWORD (32-bit) type to store size of string before (OLECHAR *) string.
+ We must select CBstrSizeType for another systems (not Win32):
+
+ if (CBstrSizeType is UINT32),
+ then we support only strings smaller than 4 GB.
+ Win32 version always has that limitation.
+
+ if (CBstrSizeType is UINT),
+ (UINT can be 16/32/64-bit)
+ We can support strings larger than 4 GB (if UINT is 64-bit),
+ but sizeof(UINT) can be different in parts compiled by
+ different compilers/settings,
+ and we can't send such BSTR strings between such parts.
+*/
+
+typedef UINT32 CBstrSizeType;
+// typedef UINT CBstrSizeType;
+
+#define k_BstrSize_Max 0xFFFFFFFF
+// #define k_BstrSize_Max UINT_MAX
+// #define k_BstrSize_Max ((UINT)(INT)-1)
+
+BSTR SysAllocStringByteLen(LPCSTR s, UINT len)
+{
+ /* Original SysAllocStringByteLen in Win32 maybe fills only unaligned null OLECHAR at the end.
+ We provide also aligned null OLECHAR at the end. */
+
+ if (len >= (k_BstrSize_Max - (UINT)sizeof(OLECHAR) - (UINT)sizeof(OLECHAR) - (UINT)sizeof(CBstrSizeType)))
+ return NULL;
+
+ UINT size = (len + (UINT)sizeof(OLECHAR) + (UINT)sizeof(OLECHAR) - 1) & ~((UINT)sizeof(OLECHAR) - 1);
+ void *p = AllocateForBSTR(size + (UINT)sizeof(CBstrSizeType));
+ if (!p)
+ return NULL;
+ *(CBstrSizeType *)p = (CBstrSizeType)len;
+ BSTR bstr = (BSTR)((CBstrSizeType *)p + 1);
+ if (s)
+ memcpy(bstr, s, len);
+ for (; len < size; len++)
+ ((Byte *)bstr)[len] = 0;
+ return bstr;
+}
+
+BSTR SysAllocStringLen(const OLECHAR *s, UINT len)
+{
+ if (len >= (k_BstrSize_Max - (UINT)sizeof(OLECHAR) - (UINT)sizeof(CBstrSizeType)) / (UINT)sizeof(OLECHAR))
+ return NULL;
+
+ UINT size = len * (UINT)sizeof(OLECHAR);
+ void *p = AllocateForBSTR(size + (UINT)sizeof(CBstrSizeType) + (UINT)sizeof(OLECHAR));
+ if (!p)
+ return NULL;
+ *(CBstrSizeType *)p = (CBstrSizeType)size;
+ BSTR bstr = (BSTR)((CBstrSizeType *)p + 1);
+ if (s)
+ memcpy(bstr, s, size);
+ bstr[len] = 0;
+ return bstr;
+}
+
+BSTR SysAllocString(const OLECHAR *s)
+{
+ if (!s)
+ return NULL;
+ const OLECHAR *s2 = s;
+ while (*s2 != 0)
+ s2++;
+ return SysAllocStringLen(s, (UINT)(s2 - s));
+}
+
+void SysFreeString(BSTR bstr)
+{
+ if (bstr)
+ FreeForBSTR((CBstrSizeType *)bstr - 1);
+}
+
+UINT SysStringByteLen(BSTR bstr)
+{
+ if (!bstr)
+ return 0;
+ return *((CBstrSizeType *)bstr - 1);
+}
+
+UINT SysStringLen(BSTR bstr)
+{
+ if (!bstr)
+ return 0;
+ return *((CBstrSizeType *)bstr - 1) / (UINT)sizeof(OLECHAR);
+}
+
+
+HRESULT VariantClear(VARIANTARG *prop)
+{
+ if (prop->vt == VT_BSTR)
+ SysFreeString(prop->bstrVal);
+ prop->vt = VT_EMPTY;
+ return S_OK;
+}
+
+HRESULT VariantCopy(VARIANTARG *dest, const VARIANTARG *src)
+{
+ HRESULT res = ::VariantClear(dest);
+ if (res != S_OK)
+ return res;
+ if (src->vt == VT_BSTR)
+ {
+ dest->bstrVal = SysAllocStringByteLen((LPCSTR)src->bstrVal,
+ SysStringByteLen(src->bstrVal));
+ if (!dest->bstrVal)
+ return E_OUTOFMEMORY;
+ dest->vt = VT_BSTR;
+ }
+ else
+ *dest = *src;
+ return S_OK;
+}
+
+LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2)
+{
+ if (ft1->dwHighDateTime < ft2->dwHighDateTime) return -1;
+ if (ft1->dwHighDateTime > ft2->dwHighDateTime) return 1;
+ if (ft1->dwLowDateTime < ft2->dwLowDateTime) return -1;
+ if (ft1->dwLowDateTime > ft2->dwLowDateTime) return 1;
+ return 0;
+}
+
+DWORD GetLastError()
+{
+ return (DWORD)errno;
+}
+
+void SetLastError(DWORD dw)
+{
+ errno = (int)dw;
+}
+
+
+static LONG TIME_GetBias()
+{
+ time_t utc = time(NULL);
+ struct tm *ptm = localtime(&utc);
+ int localdaylight = ptm->tm_isdst; /* daylight for local timezone */
+ ptm = gmtime(&utc);
+ ptm->tm_isdst = localdaylight; /* use local daylight, not that of Greenwich */
+ LONG bias = (int)(mktime(ptm)-utc);
+ return bias;
+}
+
+#define TICKS_PER_SEC 10000000
+/*
+#define SECS_PER_DAY (24 * 60 * 60)
+#define SECS_1601_TO_1970 ((369 * 365 + 89) * (UInt64)SECS_PER_DAY)
+#define TICKS_1601_TO_1970 (SECS_1601_TO_1970 * TICKS_PER_SEC)
+*/
+
+#define GET_TIME_64(pft) ((pft)->dwLowDateTime | ((UInt64)(pft)->dwHighDateTime << 32))
+
+#define SET_FILETIME(ft, v64) \
+ (ft)->dwLowDateTime = (DWORD)v64; \
+ (ft)->dwHighDateTime = (DWORD)(v64 >> 32);
+
+
+BOOL WINAPI FileTimeToLocalFileTime(const FILETIME *fileTime, FILETIME *localFileTime)
+{
+ UInt64 v = GET_TIME_64(fileTime);
+ v = (UInt64)((Int64)v - (Int64)TIME_GetBias() * TICKS_PER_SEC);
+ SET_FILETIME(localFileTime, v)
+ return TRUE;
+}
+
+BOOL WINAPI LocalFileTimeToFileTime(const FILETIME *localFileTime, FILETIME *fileTime)
+{
+ UInt64 v = GET_TIME_64(localFileTime);
+ v = (UInt64)((Int64)v + (Int64)TIME_GetBias() * TICKS_PER_SEC);
+ SET_FILETIME(fileTime, v)
+ return TRUE;
+}
+
+/*
+VOID WINAPI GetSystemTimeAsFileTime(FILETIME *ft)
+{
+ UInt64 t = 0;
+ timeval tv;
+ if (gettimeofday(&tv, NULL) == 0)
+ {
+ t = tv.tv_sec * (UInt64)TICKS_PER_SEC + TICKS_1601_TO_1970;
+ t += tv.tv_usec * 10;
+ }
+ SET_FILETIME(ft, t)
+}
+*/
+
+DWORD WINAPI GetTickCount(VOID)
+{
+ #ifndef _WIN32
+ // gettimeofday() doesn't work in some MINGWs by unknown reason
+ timeval tv;
+ if (gettimeofday(&tv, NULL) == 0)
+ {
+ // tv_sec and tv_usec are (long)
+ return (DWORD)((UInt64)(Int64)tv.tv_sec * (UInt64)1000 + (UInt64)(Int64)tv.tv_usec / 1000);
+ }
+ #endif
+ return (DWORD)time(NULL) * 1000;
+}
+
+
+#define PERIOD_4 (4 * 365 + 1)
+#define PERIOD_100 (PERIOD_4 * 25 - 1)
+#define PERIOD_400 (PERIOD_100 * 4 + 1)
+
+BOOL WINAPI FileTimeToSystemTime(const FILETIME *ft, SYSTEMTIME *st)
+{
+ UInt32 v;
+ UInt64 v64 = GET_TIME_64(ft);
+ v64 /= 10000;
+ st->wMilliseconds = (WORD)(v64 % 1000); v64 /= 1000;
+ st->wSecond = (WORD)(v64 % 60); v64 /= 60;
+ st->wMinute = (WORD)(v64 % 60); v64 /= 60;
+ v = (UInt32)v64;
+ st->wHour = (WORD)(v % 24); v /= 24;
+
+ // 1601-01-01 was Monday
+ st->wDayOfWeek = (WORD)((v + 1) % 7);
+
+ UInt32 leaps, year, day, mon;
+ leaps = (3 * ((4 * v + (365 - 31 - 28) * 4 + 3) / PERIOD_400) + 3) / 4;
+ v += 28188 + leaps;
+ // leaps - the number of exceptions from PERIOD_4 rules starting from 1600-03-01
+ // (1959 / 64) - converts day from 03-01 to month
+ year = (20 * v - 2442) / (5 * PERIOD_4);
+ day = v - (year * PERIOD_4) / 4;
+ mon = (64 * day) / 1959;
+ st->wDay = (WORD)(day - (1959 * mon) / 64);
+ mon -= 1;
+ year += 1524;
+ if (mon > 12)
+ {
+ mon -= 12;
+ year++;
+ }
+ st->wMonth = (WORD)mon;
+ st->wYear = (WORD)year;
+
+ /*
+ unsigned year, mon;
+ unsigned char ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ unsigned t;
+
+ year = (WORD)(1601 + v / PERIOD_400 * 400);
+ v %= PERIOD_400;
+
+ t = v / PERIOD_100; if (t == 4) t = 3; year += t * 100; v -= t * PERIOD_100;
+ t = v / PERIOD_4; if (t == 25) t = 24; year += t * 4; v -= t * PERIOD_4;
+ t = v / 365; if (t == 4) t = 3; year += t; v -= t * 365;
+
+ st->wYear = (WORD)year;
+
+ if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
+ ms[1] = 29;
+ for (mon = 0;; mon++)
+ {
+ unsigned d = ms[mon];
+ if (v < d)
+ break;
+ v -= d;
+ }
+ st->wDay = (WORD)(v + 1);
+ st->wMonth = (WORD)(mon + 1);
+ */
+
+ return TRUE;
+}
+
+#endif
diff --git a/CPP/Common/MyWindows.h b/CPP/Common/MyWindows.h
index cc78478..a76e14b 100644
--- a/CPP/Common/MyWindows.h
+++ b/CPP/Common/MyWindows.h
@@ -1,231 +1,324 @@
-// MyWindows.h
-
-#ifndef __MY_WINDOWS_H
-#define __MY_WINDOWS_H
-
-#ifdef _WIN32
-
-#include <windows.h>
-
-#ifdef UNDER_CE
- #undef VARIANT_TRUE
- #define VARIANT_TRUE ((VARIANT_BOOL)-1)
-#endif
-
-#else
-
-#include <stddef.h> // for wchar_t
-#include <string.h>
-// #include <stdint.h> // for uintptr_t
-
-#include "MyGuidDef.h"
-
-#define WINAPI
-
-typedef char CHAR;
-typedef unsigned char UCHAR;
-
-#undef BYTE
-typedef unsigned char BYTE;
-
-typedef short SHORT;
-typedef unsigned short USHORT;
-
-#undef WORD
-typedef unsigned short WORD;
-typedef short VARIANT_BOOL;
-
-typedef int INT;
-typedef Int32 INT32;
-typedef unsigned int UINT;
-typedef UInt32 UINT32;
-typedef INT32 LONG; // LONG, ULONG and DWORD must be 32-bit
-typedef UINT32 ULONG;
-
-#undef DWORD
-typedef UINT32 DWORD;
-
-typedef long BOOL;
-
-#ifndef FALSE
- #define FALSE 0
- #define TRUE 1
-#endif
-
-// typedef size_t ULONG_PTR;
-typedef size_t DWORD_PTR;
-// typedef uintptr_t UINT_PTR;
-// typedef ptrdiff_t UINT_PTR;
-
-typedef Int64 LONGLONG;
-typedef UInt64 ULONGLONG;
-
-typedef struct _LARGE_INTEGER { LONGLONG QuadPart; } LARGE_INTEGER;
-typedef struct _ULARGE_INTEGER { ULONGLONG QuadPart; } ULARGE_INTEGER;
-
-typedef const CHAR *LPCSTR;
-typedef CHAR TCHAR;
-typedef const TCHAR *LPCTSTR;
-typedef wchar_t WCHAR;
-typedef WCHAR OLECHAR;
-typedef const WCHAR *LPCWSTR;
-typedef OLECHAR *BSTR;
-typedef const OLECHAR *LPCOLESTR;
-typedef OLECHAR *LPOLESTR;
-
-typedef struct _FILETIME
-{
- DWORD dwLowDateTime;
- DWORD dwHighDateTime;
-} FILETIME;
-
-#define HRESULT LONG
-#define FAILED(Status) ((HRESULT)(Status)<0)
-typedef ULONG PROPID;
-typedef LONG SCODE;
-
-#define ERROR_NEGATIVE_SEEK 131L
-
-#define S_OK ((HRESULT)0x00000000L)
-#define S_FALSE ((HRESULT)0x00000001L)
-#define E_NOTIMPL ((HRESULT)0x80004001L)
-#define E_NOINTERFACE ((HRESULT)0x80004002L)
-#define E_ABORT ((HRESULT)0x80004004L)
-#define E_FAIL ((HRESULT)0x80004005L)
-#define STG_E_INVALIDFUNCTION ((HRESULT)0x80030001L)
-#define E_OUTOFMEMORY ((HRESULT)0x8007000EL)
-#define E_INVALIDARG ((HRESULT)0x80070057L)
-
-#ifdef _MSC_VER
-#define STDMETHODCALLTYPE __stdcall
-#else
-#define STDMETHODCALLTYPE
-#endif
-
-#define STDMETHOD_(t, f) virtual t STDMETHODCALLTYPE f
-#define STDMETHOD(f) STDMETHOD_(HRESULT, f)
-#define STDMETHODIMP_(type) type STDMETHODCALLTYPE
-#define STDMETHODIMP STDMETHODIMP_(HRESULT)
-
-#define PURE = 0
-
-#define MIDL_INTERFACE(x) struct
-
-#ifdef __cplusplus
-
-DEFINE_GUID(IID_IUnknown,
-0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
-struct IUnknown
-{
- STDMETHOD(QueryInterface) (REFIID iid, void **outObject) PURE;
- STDMETHOD_(ULONG, AddRef)() PURE;
- STDMETHOD_(ULONG, Release)() PURE;
- #ifndef _WIN32
- virtual ~IUnknown() {}
- #endif
-};
-
-typedef IUnknown *LPUNKNOWN;
-
-#endif
-
-#define VARIANT_TRUE ((VARIANT_BOOL)-1)
-#define VARIANT_FALSE ((VARIANT_BOOL)0)
-
-enum VARENUM
-{
- VT_EMPTY = 0,
- VT_NULL = 1,
- VT_I2 = 2,
- VT_I4 = 3,
- VT_R4 = 4,
- VT_R8 = 5,
- VT_CY = 6,
- VT_DATE = 7,
- VT_BSTR = 8,
- VT_DISPATCH = 9,
- VT_ERROR = 10,
- VT_BOOL = 11,
- VT_VARIANT = 12,
- VT_UNKNOWN = 13,
- VT_DECIMAL = 14,
- VT_I1 = 16,
- VT_UI1 = 17,
- VT_UI2 = 18,
- VT_UI4 = 19,
- VT_I8 = 20,
- VT_UI8 = 21,
- VT_INT = 22,
- VT_UINT = 23,
- VT_VOID = 24,
- VT_HRESULT = 25,
- VT_FILETIME = 64
-};
-
-typedef unsigned short VARTYPE;
-typedef WORD PROPVAR_PAD1;
-typedef WORD PROPVAR_PAD2;
-typedef WORD PROPVAR_PAD3;
-
-typedef struct tagPROPVARIANT
-{
- VARTYPE vt;
- PROPVAR_PAD1 wReserved1;
- PROPVAR_PAD2 wReserved2;
- PROPVAR_PAD3 wReserved3;
- union
- {
- CHAR cVal;
- UCHAR bVal;
- SHORT iVal;
- USHORT uiVal;
- LONG lVal;
- ULONG ulVal;
- INT intVal;
- UINT uintVal;
- LARGE_INTEGER hVal;
- ULARGE_INTEGER uhVal;
- VARIANT_BOOL boolVal;
- SCODE scode;
- FILETIME filetime;
- BSTR bstrVal;
- };
-} PROPVARIANT;
-
-typedef PROPVARIANT tagVARIANT;
-typedef tagVARIANT VARIANT;
-typedef VARIANT VARIANTARG;
-
-MY_EXTERN_C HRESULT VariantClear(VARIANTARG *prop);
-MY_EXTERN_C HRESULT VariantCopy(VARIANTARG *dest, const VARIANTARG *src);
-
-typedef struct tagSTATPROPSTG
-{
- LPOLESTR lpwstrName;
- PROPID propid;
- VARTYPE vt;
-} STATPROPSTG;
-
-MY_EXTERN_C BSTR SysAllocStringByteLen(LPCSTR psz, UINT len);
-MY_EXTERN_C BSTR SysAllocStringLen(const OLECHAR *sz, UINT len);
-MY_EXTERN_C BSTR SysAllocString(const OLECHAR *sz);
-MY_EXTERN_C void SysFreeString(BSTR bstr);
-MY_EXTERN_C UINT SysStringByteLen(BSTR bstr);
-MY_EXTERN_C UINT SysStringLen(BSTR bstr);
-
-MY_EXTERN_C DWORD GetLastError();
-MY_EXTERN_C LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2);
-
-#define CP_ACP 0
-#define CP_OEMCP 1
-#define CP_UTF8 65001
-
-typedef enum tagSTREAM_SEEK
-{
- STREAM_SEEK_SET = 0,
- STREAM_SEEK_CUR = 1,
- STREAM_SEEK_END = 2
-} STREAM_SEEK;
-
-#endif
-#endif
+// MyWindows.h
+
+#ifdef Z7_DEFINE_GUID
+#undef Z7_DEFINE_GUID
+#endif
+
+#ifdef INITGUID
+ #define Z7_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ EXTERN_C const GUID name; \
+ EXTERN_C const GUID name = { l, w1, w2, { b1, b2, b3, b4, b5, b6, b7, b8 } }
+#else
+ #define Z7_DEFINE_GUID(name, l, w1, w2, b1, b2, b3, b4, b5, b6, b7, b8) \
+ EXTERN_C const GUID name
+#endif
+
+
+#ifndef ZIP7_INC_MY_WINDOWS_H
+#define ZIP7_INC_MY_WINDOWS_H
+
+#ifdef _WIN32
+
+#include "../../C/7zWindows.h"
+
+#else // _WIN32
+
+#include <stddef.h> // for wchar_t
+#include <string.h>
+// #include <stdint.h> // for uintptr_t
+
+#include "../../C/7zTypes.h"
+#include "MyGuidDef.h"
+
+// WINAPI is __stdcall in Windows-MSVC in windef.h
+#define WINAPI
+
+typedef char CHAR;
+typedef unsigned char UCHAR;
+
+#undef BYTE
+typedef unsigned char BYTE;
+
+typedef short SHORT;
+typedef unsigned short USHORT;
+
+#undef WORD
+typedef unsigned short WORD;
+typedef short VARIANT_BOOL;
+
+#define LOWORD(l) ((WORD)((DWORD_PTR)(l) & 0xffff))
+#define HIWORD(l) ((WORD)((DWORD_PTR)(l) >> 16))
+
+// MS uses long for BOOL, but long is 32-bit in MS. So we use int.
+// typedef long BOOL;
+typedef int BOOL;
+
+#ifndef FALSE
+ #define FALSE 0
+ #define TRUE 1
+#endif
+
+// typedef size_t ULONG_PTR;
+// typedef size_t DWORD_PTR;
+// typedef uintptr_t UINT_PTR;
+// typedef ptrdiff_t UINT_PTR;
+
+typedef Int64 LONGLONG;
+typedef UInt64 ULONGLONG;
+
+typedef struct _LARGE_INTEGER { LONGLONG QuadPart; } LARGE_INTEGER;
+typedef struct _ULARGE_INTEGER { ULONGLONG QuadPart; } ULARGE_INTEGER;
+
+typedef const CHAR *LPCSTR;
+typedef CHAR TCHAR;
+typedef const TCHAR *LPCTSTR;
+typedef wchar_t WCHAR;
+typedef WCHAR OLECHAR;
+typedef const WCHAR *LPCWSTR;
+typedef OLECHAR *BSTR;
+typedef const OLECHAR *LPCOLESTR;
+typedef OLECHAR *LPOLESTR;
+
+typedef struct _FILETIME
+{
+ DWORD dwLowDateTime;
+ DWORD dwHighDateTime;
+} FILETIME;
+
+#define SUCCEEDED(hr) ((HRESULT)(hr) >= 0)
+#define FAILED(hr) ((HRESULT)(hr) < 0)
+typedef ULONG PROPID;
+typedef LONG SCODE;
+
+
+#define S_OK ((HRESULT)0x00000000L)
+#define S_FALSE ((HRESULT)0x00000001L)
+#define E_NOTIMPL ((HRESULT)0x80004001L)
+#define E_NOINTERFACE ((HRESULT)0x80004002L)
+#define E_ABORT ((HRESULT)0x80004004L)
+#define E_FAIL ((HRESULT)0x80004005L)
+#define STG_E_INVALIDFUNCTION ((HRESULT)0x80030001L)
+#define CLASS_E_CLASSNOTAVAILABLE ((HRESULT)0x80040111L)
+
+
+#ifdef _MSC_VER
+#define STDMETHODCALLTYPE __stdcall
+#define STDAPICALLTYPE __stdcall
+#else
+// do we need __export here?
+#define STDMETHODCALLTYPE
+#define STDAPICALLTYPE
+#endif
+
+#define STDAPI EXTERN_C HRESULT STDAPICALLTYPE
+
+#ifndef DECLSPEC_NOTHROW
+#define DECLSPEC_NOTHROW Z7_DECLSPEC_NOTHROW
+#endif
+
+#ifndef DECLSPEC_NOVTABLE
+#define DECLSPEC_NOVTABLE Z7_DECLSPEC_NOVTABLE
+#endif
+
+#ifndef COM_DECLSPEC_NOTHROW
+#ifdef COM_STDMETHOD_CAN_THROW
+ #define COM_DECLSPEC_NOTHROW
+#else
+ #define COM_DECLSPEC_NOTHROW DECLSPEC_NOTHROW
+#endif
+#endif
+
+#define DECLARE_INTERFACE(iface) struct DECLSPEC_NOVTABLE iface
+#define DECLARE_INTERFACE_(iface, baseiface) struct DECLSPEC_NOVTABLE iface : public baseiface
+
+#define STDMETHOD_(t, f) virtual COM_DECLSPEC_NOTHROW t STDMETHODCALLTYPE f
+#define STDMETHOD(f) STDMETHOD_(HRESULT, f)
+#define STDMETHODIMP_(t) COM_DECLSPEC_NOTHROW t STDMETHODCALLTYPE
+#define STDMETHODIMP STDMETHODIMP_(HRESULT)
+
+
+#define PURE = 0
+
+// #define MIDL_INTERFACE(x) struct
+
+
+#ifdef __cplusplus
+
+/*
+ p7zip and 7-Zip before v23 used virtual destructor in IUnknown,
+ if _WIN32 is not defined.
+ It used virtual destructor, because some compilers don't like virtual
+ interfaces without virtual destructor.
+ IUnknown in Windows (_WIN32) doesn't use virtual destructor in IUnknown.
+ We still can define Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN here,
+ if we want to be compatible with old plugin interface of p7zip and 7-Zip before v23.
+
+v23:
+ In new 7-Zip v23 we try to be more compatible with original IUnknown from _WIN32.
+ So we do not define Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN here,
+*/
+// #define Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN
+
+#ifdef Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN
+#if defined(__clang__)
+#pragma GCC diagnostic ignored "-Winconsistent-missing-destructor-override"
+#endif
+#endif
+
+Z7_PURE_INTERFACES_BEGIN
+
+DEFINE_GUID(IID_IUnknown,
+0x00000000, 0x0000, 0x0000, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46);
+struct IUnknown
+{
+ STDMETHOD(QueryInterface) (REFIID iid, void **outObject) =0;
+ STDMETHOD_(ULONG, AddRef)() =0;
+ STDMETHOD_(ULONG, Release)() =0;
+ #ifdef Z7_USE_VIRTUAL_DESTRUCTOR_IN_IUNKNOWN
+ virtual ~IUnknown() {}
+ #endif
+};
+
+typedef IUnknown *LPUNKNOWN;
+
+Z7_PURE_INTERFACES_END
+
+#endif // __cplusplus
+
+#define VARIANT_TRUE ((VARIANT_BOOL)-1)
+#define VARIANT_FALSE ((VARIANT_BOOL)0)
+
+enum VARENUM
+{
+ VT_EMPTY = 0,
+ VT_NULL = 1,
+ VT_I2 = 2,
+ VT_I4 = 3,
+ VT_R4 = 4,
+ VT_R8 = 5,
+ VT_CY = 6,
+ VT_DATE = 7,
+ VT_BSTR = 8,
+ VT_DISPATCH = 9,
+ VT_ERROR = 10,
+ VT_BOOL = 11,
+ VT_VARIANT = 12,
+ VT_UNKNOWN = 13,
+ VT_DECIMAL = 14,
+
+ VT_I1 = 16,
+ VT_UI1 = 17,
+ VT_UI2 = 18,
+ VT_UI4 = 19,
+ VT_I8 = 20,
+ VT_UI8 = 21,
+ VT_INT = 22,
+ VT_UINT = 23,
+ VT_VOID = 24,
+ VT_HRESULT = 25,
+ VT_FILETIME = 64
+};
+
+typedef unsigned short VARTYPE;
+typedef WORD PROPVAR_PAD1;
+typedef WORD PROPVAR_PAD2;
+typedef WORD PROPVAR_PAD3;
+
+typedef struct tagPROPVARIANT
+{
+ VARTYPE vt;
+ PROPVAR_PAD1 wReserved1;
+ PROPVAR_PAD2 wReserved2;
+ PROPVAR_PAD3 wReserved3;
+ union
+ {
+ CHAR cVal;
+ UCHAR bVal;
+ SHORT iVal;
+ USHORT uiVal;
+ LONG lVal;
+ ULONG ulVal;
+ INT intVal;
+ UINT uintVal;
+ LARGE_INTEGER hVal;
+ ULARGE_INTEGER uhVal;
+ VARIANT_BOOL boolVal;
+ SCODE scode;
+ FILETIME filetime;
+ BSTR bstrVal;
+ };
+} PROPVARIANT;
+
+typedef PROPVARIANT tagVARIANT;
+typedef tagVARIANT VARIANT;
+typedef VARIANT VARIANTARG;
+
+EXTERN_C HRESULT VariantClear(VARIANTARG *prop);
+EXTERN_C HRESULT VariantCopy(VARIANTARG *dest, const VARIANTARG *src);
+
+typedef struct tagSTATPROPSTG
+{
+ LPOLESTR lpwstrName;
+ PROPID propid;
+ VARTYPE vt;
+} STATPROPSTG;
+
+EXTERN_C BSTR SysAllocStringByteLen(LPCSTR psz, UINT len);
+EXTERN_C BSTR SysAllocStringLen(const OLECHAR *sz, UINT len);
+EXTERN_C BSTR SysAllocString(const OLECHAR *sz);
+EXTERN_C void SysFreeString(BSTR bstr);
+EXTERN_C UINT SysStringByteLen(BSTR bstr);
+EXTERN_C UINT SysStringLen(BSTR bstr);
+
+EXTERN_C DWORD GetLastError();
+EXTERN_C void SetLastError(DWORD dwCode);
+EXTERN_C LONG CompareFileTime(const FILETIME* ft1, const FILETIME* ft2);
+
+EXTERN_C DWORD GetCurrentThreadId();
+EXTERN_C DWORD GetCurrentProcessId();
+
+#define MAX_PATH 1024
+
+#define CP_ACP 0
+#define CP_OEMCP 1
+#define CP_UTF8 65001
+
+typedef enum tagSTREAM_SEEK
+{
+ STREAM_SEEK_SET = 0,
+ STREAM_SEEK_CUR = 1,
+ STREAM_SEEK_END = 2
+} STREAM_SEEK;
+
+
+
+typedef struct _SYSTEMTIME
+{
+ WORD wYear;
+ WORD wMonth;
+ WORD wDayOfWeek;
+ WORD wDay;
+ WORD wHour;
+ WORD wMinute;
+ WORD wSecond;
+ WORD wMilliseconds;
+} SYSTEMTIME;
+
+BOOL WINAPI FileTimeToLocalFileTime(const FILETIME *fileTime, FILETIME *localFileTime);
+BOOL WINAPI LocalFileTimeToFileTime(const FILETIME *localFileTime, FILETIME *fileTime);
+BOOL WINAPI FileTimeToSystemTime(const FILETIME *fileTime, SYSTEMTIME *systemTime);
+// VOID WINAPI GetSystemTimeAsFileTime(FILETIME *systemTimeAsFileTime);
+
+DWORD GetTickCount();
+
+
+#define CREATE_NEW 1
+#define CREATE_ALWAYS 2
+#define OPEN_EXISTING 3
+#define OPEN_ALWAYS 4
+#define TRUNCATE_EXISTING 5
+
+
+#endif // _WIN32
+
+#endif
diff --git a/CPP/Common/MyXml.cpp b/CPP/Common/MyXml.cpp
new file mode 100644
index 0000000..a879d34
--- /dev/null
+++ b/CPP/Common/MyXml.cpp
@@ -0,0 +1,260 @@
+// MyXml.cpp
+
+#include "StdAfx.h"
+
+#include "MyXml.h"
+
+static bool IsValidChar(char c)
+{
+ return
+ (c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') ||
+ c == '-';
+}
+
+static bool IsSpaceChar(char c)
+{
+ return (c == ' ' || c == '\t' || c == 0x0D || c == 0x0A);
+}
+
+#define SKIP_SPACES(s) while (IsSpaceChar(*s)) s++;
+
+int CXmlItem::FindProp(const char *propName) const throw()
+{
+ FOR_VECTOR (i, Props)
+ if (Props[i].Name == propName)
+ return (int)i;
+ return -1;
+}
+
+AString CXmlItem::GetPropVal(const char *propName) const
+{
+ int index = FindProp(propName);
+ if (index >= 0)
+ return Props[(unsigned)index].Value;
+ return AString();
+}
+
+bool CXmlItem::IsTagged(const char *tag) const throw()
+{
+ return (IsTag && Name == tag);
+}
+
+int CXmlItem::FindSubTag(const char *tag) const throw()
+{
+ FOR_VECTOR (i, SubItems)
+ if (SubItems[i].IsTagged(tag))
+ return (int)i;
+ return -1;
+}
+
+AString CXmlItem::GetSubString() const
+{
+ if (SubItems.Size() == 1)
+ {
+ const CXmlItem &item = SubItems[0];
+ if (!item.IsTag)
+ return item.Name;
+ }
+ return AString();
+}
+
+const AString * CXmlItem::GetSubStringPtr() const throw()
+{
+ if (SubItems.Size() == 1)
+ {
+ const CXmlItem &item = SubItems[0];
+ if (!item.IsTag)
+ return &item.Name;
+ }
+ return NULL;
+}
+
+AString CXmlItem::GetSubStringForTag(const char *tag) const
+{
+ int index = FindSubTag(tag);
+ if (index >= 0)
+ return SubItems[(unsigned)index].GetSubString();
+ return AString();
+}
+
+const char * CXmlItem::ParseItem(const char *s, int numAllowedLevels)
+{
+ SKIP_SPACES(s)
+
+ const char *beg = s;
+ for (;;)
+ {
+ char c;
+ c = *s; if (c == 0 || c == '<') break; s++;
+ c = *s; if (c == 0 || c == '<') break; s++;
+ }
+ if (*s == 0)
+ return NULL;
+ if (s != beg)
+ {
+ IsTag = false;
+ Name.SetFrom(beg, (unsigned)(s - beg));
+ return s;
+ }
+
+ IsTag = true;
+
+ s++;
+ SKIP_SPACES(s)
+
+ beg = s;
+ for (;; s++)
+ if (!IsValidChar(*s))
+ break;
+ if (s == beg || *s == 0)
+ return NULL;
+ Name.SetFrom(beg, (unsigned)(s - beg));
+
+ for (;;)
+ {
+ beg = s;
+ SKIP_SPACES(s)
+ if (*s == '/')
+ {
+ s++;
+ // SKIP_SPACES(s)
+ if (*s != '>')
+ return NULL;
+ return s + 1;
+ }
+ if (*s == '>')
+ {
+ s++;
+ if (numAllowedLevels == 0)
+ return NULL;
+ SubItems.Clear();
+ for (;;)
+ {
+ SKIP_SPACES(s)
+ if (s[0] == '<' && s[1] == '/')
+ break;
+ CXmlItem &item = SubItems.AddNew();
+ s = item.ParseItem(s, numAllowedLevels - 1);
+ if (!s)
+ return NULL;
+ }
+
+ s += 2;
+ unsigned len = Name.Len();
+ for (unsigned i = 0; i < len; i++)
+ if (s[i] != Name[i])
+ return NULL;
+ s += len;
+ if (s[0] != '>')
+ return NULL;
+ return s + 1;
+ }
+ if (beg == s)
+ return NULL;
+
+ // ReadProperty
+ CXmlProp &prop = Props.AddNew();
+
+ beg = s;
+ for (;; s++)
+ {
+ char c = *s;
+ if (!IsValidChar(c))
+ break;
+ }
+ if (s == beg)
+ return NULL;
+ prop.Name.SetFrom(beg, (unsigned)(s - beg));
+
+ SKIP_SPACES(s)
+ if (*s != '=')
+ return NULL;
+ s++;
+ SKIP_SPACES(s)
+ if (*s != '\"')
+ return NULL;
+ s++;
+
+ beg = s;
+ for (;;)
+ {
+ char c = *s;
+ if (c == 0)
+ return NULL;
+ if (c == '\"')
+ break;
+ s++;
+ }
+ prop.Value.SetFrom(beg, (unsigned)(s - beg));
+ s++;
+ }
+}
+
+static const char * SkipHeader(const char *s, const char *startString, const char *endString)
+{
+ SKIP_SPACES(s)
+ if (IsString1PrefixedByString2(s, startString))
+ {
+ s = strstr(s, endString);
+ if (!s)
+ return NULL;
+ s += strlen(endString);
+ }
+ return s;
+}
+
+void CXmlItem::AppendTo(AString &s) const
+{
+ if (IsTag)
+ s += '<';
+ s += Name;
+ if (IsTag)
+ {
+ FOR_VECTOR (i, Props)
+ {
+ const CXmlProp &prop = Props[i];
+ s.Add_Space();
+ s += prop.Name;
+ s += '=';
+ s += '\"';
+ s += prop.Value;
+ s += '\"';
+ }
+ s += '>';
+ }
+ FOR_VECTOR (i, SubItems)
+ {
+ const CXmlItem &item = SubItems[i];
+ if (i != 0 && !SubItems[i - 1].IsTag)
+ s.Add_Space();
+ item.AppendTo(s);
+ }
+ if (IsTag)
+ {
+ s += '<';
+ s += '/';
+ s += Name;
+ s += '>';
+ }
+}
+
+bool CXml::Parse(const char *s)
+{
+ s = SkipHeader(s, "<?xml", "?>"); if (!s) return false;
+ s = SkipHeader(s, "<!DOCTYPE", ">"); if (!s) return false;
+
+ s = Root.ParseItem(s, 1000);
+ if (!s || !Root.IsTag)
+ return false;
+ SKIP_SPACES(s)
+ return *s == 0;
+}
+
+/*
+void CXml::AppendTo(AString &s) const
+{
+ Root.AppendTo(s);
+}
+*/
diff --git a/CPP/Common/MyXml.h b/CPP/Common/MyXml.h
new file mode 100644
index 0000000..5362602
--- /dev/null
+++ b/CPP/Common/MyXml.h
@@ -0,0 +1,43 @@
+// MyXml.h
+
+#ifndef ZIP7_INC_MY_XML_H
+#define ZIP7_INC_MY_XML_H
+
+#include "MyString.h"
+
+struct CXmlProp
+{
+ AString Name;
+ AString Value;
+};
+
+class CXmlItem
+{
+public:
+ AString Name;
+ bool IsTag;
+ CObjectVector<CXmlProp> Props;
+ CObjectVector<CXmlItem> SubItems;
+
+ const char * ParseItem(const char *s, int numAllowedLevels);
+
+ bool IsTagged(const char *tag) const throw();
+ int FindProp(const char *propName) const throw();
+ AString GetPropVal(const char *propName) const;
+ AString GetSubString() const;
+ const AString * GetSubStringPtr() const throw();
+ int FindSubTag(const char *tag) const throw();
+ AString GetSubStringForTag(const char *tag) const;
+
+ void AppendTo(AString &s) const;
+};
+
+struct CXml
+{
+ CXmlItem Root;
+
+ bool Parse(const char *s);
+ // void AppendTo(AString &s) const;
+};
+
+#endif
diff --git a/CPP/Common/NewHandler.cpp b/CPP/Common/NewHandler.cpp
index 18d2d18..c95833e 100644
--- a/CPP/Common/NewHandler.cpp
+++ b/CPP/Common/NewHandler.cpp
@@ -1,163 +1,298 @@
-// NewHandler.cpp
-
-#include "StdAfx.h"
-
-#include <stdlib.h>
-
-#include "NewHandler.h"
-
-// #define DEBUG_MEMORY_LEAK
-
-#ifndef DEBUG_MEMORY_LEAK
-
-#ifdef _7ZIP_REDEFINE_OPERATOR_NEW
-
-/*
-void * my_new(size_t size)
-{
- // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size);
- void *p = ::malloc(size);
- if (p == 0)
- throw CNewException();
- return p;
-}
-
-void my_delete(void *p) throw()
-{
- // if (p == 0) return; ::HeapFree(::GetProcessHeap(), 0, p);
- ::free(p);
-}
-
-void * my_Realloc(void *p, size_t newSize, size_t oldSize)
-{
- void *newBuf = my_new(newSize);
- if (oldSize != 0)
- memcpy(newBuf, p, oldSize);
- my_delete(p);
- return newBuf;
-}
-*/
-
-void *
-#ifdef _MSC_VER
-__cdecl
-#endif
-operator new(size_t size)
-{
- // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size);
- void *p = ::malloc(size);
- if (p == 0)
- throw CNewException();
- return p;
-}
-
-void
-#ifdef _MSC_VER
-__cdecl
-#endif
-operator delete(void *p) throw()
-{
- // if (p == 0) return; ::HeapFree(::GetProcessHeap(), 0, p);
- ::free(p);
-}
-
-/*
-void *
-#ifdef _MSC_VER
-__cdecl
-#endif
-operator new[](size_t size)
-{
- // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size);
- void *p = ::malloc(size);
- if (p == 0)
- throw CNewException();
- return p;
-}
-
-void
-#ifdef _MSC_VER
-__cdecl
-#endif
-operator delete[](void *p) throw()
-{
- // if (p == 0) return; ::HeapFree(::GetProcessHeap(), 0, p);
- ::free(p);
-}
-*/
-
-#endif
-
-#else
-
-#include <stdio.h>
-
-// #pragma init_seg(lib)
-const int kDebugSize = 1000000;
-static void *a[kDebugSize];
-static int index = 0;
-
-static int numAllocs = 0;
-void * __cdecl operator new(size_t size)
-{
- numAllocs++;
- void *p = HeapAlloc(GetProcessHeap(), 0, size);
- if (index < kDebugSize)
- {
- a[index] = p;
- index++;
- }
- if (p == 0)
- throw CNewException();
- printf("Alloc %6d, size = %8u\n", numAllocs, (unsigned)size);
- return p;
-}
-
-class CC
-{
-public:
- CC()
- {
- for (int i = 0; i < kDebugSize; i++)
- a[i] = 0;
- }
- ~CC()
- {
- for (int i = 0; i < kDebugSize; i++)
- if (a[i] != 0)
- return;
- }
-} g_CC;
-
-
-void __cdecl operator delete(void *p)
-{
- if (p == 0)
- return;
- /*
- for (int i = 0; i < index; i++)
- if (a[i] == p)
- a[i] = 0;
- */
- HeapFree(GetProcessHeap(), 0, p);
- numAllocs--;
- printf("Free %d\n", numAllocs);
-}
-
-#endif
-
-/*
-int MemErrorVC(size_t)
-{
- throw CNewException();
- // return 1;
-}
-CNewHandlerSetter::CNewHandlerSetter()
-{
- // MemErrorOldVCFunction = _set_new_handler(MemErrorVC);
-}
-CNewHandlerSetter::~CNewHandlerSetter()
-{
- // _set_new_handler(MemErrorOldVCFunction);
-}
-*/
+// NewHandler.cpp
+
+#include "StdAfx.h"
+
+#include <stdlib.h>
+
+#include "NewHandler.h"
+
+// #define DEBUG_MEMORY_LEAK
+
+#ifndef DEBUG_MEMORY_LEAK
+
+#ifdef Z7_REDEFINE_OPERATOR_NEW
+
+/*
+void * my_new(size_t size)
+{
+ // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size);
+ if (size == 0)
+ size = 1;
+ void *p = ::malloc(size);
+ if (!p)
+ throw CNewException();
+ return p;
+}
+
+void my_delete(void *p) throw()
+{
+ // if (!p) return; ::HeapFree(::GetProcessHeap(), 0, p);
+ ::free(p);
+}
+
+void * my_Realloc(void *p, size_t newSize, size_t oldSize)
+{
+ void *newBuf = my_new(newSize);
+ if (oldSize != 0)
+ memcpy(newBuf, p, oldSize);
+ my_delete(p);
+ return newBuf;
+}
+*/
+
+void *
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator new(size_t size)
+{
+ /* by C++ specification:
+ if (size == 0), operator new(size) returns non_NULL pointer.
+ If (operator new(0) returns NULL), it's out of specification.
+ but some calling code can work correctly even in this case too. */
+ // if (size == 0) return NULL; // for debug only. don't use it
+
+ /* malloc(0) returns non_NULL in main compilers, as we need here.
+ But specification also allows malloc(0) to return NULL.
+ So we change (size=0) to (size=1) here to get real non_NULL pointer */
+ if (size == 0)
+ size = 1;
+ // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size);
+ // void *p = ::MyAlloc(size); // note: MyAlloc(0) returns NULL
+ void *p = ::malloc(size);
+ if (!p)
+ throw CNewException();
+ return p;
+}
+
+void
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator delete(void *p) throw()
+{
+ // if (!p) return; ::HeapFree(::GetProcessHeap(), 0, p);
+ // MyFree(p);
+ ::free(p);
+}
+
+/*
+void *
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator new[](size_t size)
+{
+ // void *p = ::HeapAlloc(::GetProcessHeap(), 0, size);
+ if (size == 0)
+ size = 1;
+ void *p = ::malloc(size);
+ if (!p)
+ throw CNewException();
+ return p;
+}
+
+void
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator delete[](void *p) throw()
+{
+ // if (!p) return; ::HeapFree(::GetProcessHeap(), 0, p);
+ ::free(p);
+}
+*/
+
+#endif
+
+#else
+
+#include <stdio.h>
+
+// #pragma init_seg(lib)
+/*
+const int kDebugSize = 1000000;
+static void *a[kDebugSize];
+static int g_index = 0;
+
+class CC
+{
+public:
+ CC()
+ {
+ for (int i = 0; i < kDebugSize; i++)
+ a[i] = 0;
+ }
+ ~CC()
+ {
+ printf("\nDestructor: %d\n", numAllocs);
+ for (int i = 0; i < kDebugSize; i++)
+ if (a[i] != 0)
+ return;
+ }
+} g_CC;
+*/
+
+#ifdef _WIN32
+static bool wasInit = false;
+static CRITICAL_SECTION cs;
+#endif
+
+static int numAllocs = 0;
+
+void *
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator new(size_t size)
+{
+ #ifdef _WIN32
+ if (!wasInit)
+ {
+ InitializeCriticalSection(&cs);
+ wasInit = true;
+ }
+ EnterCriticalSection(&cs);
+
+ numAllocs++;
+ int loc = numAllocs;
+ void *p = HeapAlloc(GetProcessHeap(), 0, size);
+ /*
+ if (g_index < kDebugSize)
+ {
+ a[g_index] = p;
+ g_index++;
+ }
+ */
+ printf("Alloc %6d, size = %8u\n", loc, (unsigned)size);
+ LeaveCriticalSection(&cs);
+ if (!p)
+ throw CNewException();
+ return p;
+ #else
+ numAllocs++;
+ int loc = numAllocs;
+ if (size == 0)
+ size = 1;
+ void *p = malloc(size);
+ /*
+ if (g_index < kDebugSize)
+ {
+ a[g_index] = p;
+ g_index++;
+ }
+ */
+ printf("Alloc %6d, size = %8u\n", loc, (unsigned)size);
+ if (!p)
+ throw CNewException();
+ return p;
+ #endif
+}
+
+void
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator delete(void *p) throw()
+{
+ if (!p)
+ return;
+ #ifdef _WIN32
+ EnterCriticalSection(&cs);
+ /*
+ for (int i = 0; i < g_index; i++)
+ if (a[i] == p)
+ a[i] = 0;
+ */
+ HeapFree(GetProcessHeap(), 0, p);
+ if (numAllocs == 0)
+ numAllocs = numAllocs; // ERROR
+ numAllocs--;
+ if (numAllocs == 0)
+ numAllocs = numAllocs; // OK: all objects were deleted
+ printf("Free %d\n", numAllocs);
+ LeaveCriticalSection(&cs);
+ #else
+ free(p);
+ numAllocs--;
+ printf("Free %d\n", numAllocs);
+ #endif
+}
+
+/*
+void *
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator new[](size_t size)
+{
+ printf("operator_new[] : ");
+ return operator new(size);
+}
+
+void
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator delete(void *p, size_t sz) throw();
+
+void
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator delete(void *p, size_t sz) throw()
+{
+ if (!p)
+ return;
+ printf("operator_delete_size : size=%d : ", (unsigned)sz);
+ operator delete(p);
+}
+
+void
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator delete[](void *p) throw()
+{
+ if (!p)
+ return;
+ printf("operator_delete[] : ");
+ operator delete(p);
+}
+
+void
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator delete[](void *p, size_t sz) throw();
+
+void
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator delete[](void *p, size_t sz) throw()
+{
+ if (!p)
+ return;
+ printf("operator_delete_size[] : size=%d : ", (unsigned)sz);
+ operator delete(p);
+}
+*/
+
+#endif
+
+/*
+int MemErrorVC(size_t)
+{
+ throw CNewException();
+ // return 1;
+}
+CNewHandlerSetter::CNewHandlerSetter()
+{
+ // MemErrorOldVCFunction = _set_new_handler(MemErrorVC);
+}
+CNewHandlerSetter::~CNewHandlerSetter()
+{
+ // _set_new_handler(MemErrorOldVCFunction);
+}
+*/
diff --git a/CPP/Common/NewHandler.h b/CPP/Common/NewHandler.h
index 9d20ee1..50f6d0a 100644
--- a/CPP/Common/NewHandler.h
+++ b/CPP/Common/NewHandler.h
@@ -1,88 +1,98 @@
-// Common/NewHandler.h
-
-#ifndef __COMMON_NEW_HANDLER_H
-#define __COMMON_NEW_HANDLER_H
-
-/*
-NewHandler.h and NewHandler.cpp allows to solve problem with compilers that
-don't throw exception in operator new().
-
-This file must be included before any code that uses operators new() or delete()
-and you must compile and link "NewHandler.cpp", if you use some old MSVC compiler.
-
-The operator new() in some MSVC versions doesn't throw exception std::bad_alloc.
-MSVC 6.0 (_MSC_VER == 1200) doesn't throw exception.
-The code produced by some another MSVC compilers also can be linked
-to library that doesn't throw exception.
-We suppose that code compiled with VS2015+ (_MSC_VER >= 1900) throws exception std::bad_alloc.
-For older _MSC_VER versions we redefine operator new() and operator delete().
-Our version of operator new() throws CNewException() exception on failure.
-
-It's still allowed to use redefined version of operator new() from "NewHandler.cpp"
-with any compiler. 7-Zip's code can work with std::bad_alloc and CNewException() exceptions.
-But if you use some additional code (outside of 7-Zip's code), you must check
-that redefined version of operator new() is not problem for your code.
-*/
-
-#include <stddef.h>
-
-#ifdef _WIN32
-// We can compile my_new and my_delete with _fastcall
-/*
-void * my_new(size_t size);
-void my_delete(void *p) throw();
-// void * my_Realloc(void *p, size_t newSize, size_t oldSize);
-*/
-#endif
-
-
-#if defined(_MSC_VER) && (_MSC_VER < 1900)
- // If you want to use default operator new(), you can disable the following line
- #define _7ZIP_REDEFINE_OPERATOR_NEW
-#endif
-
-
-#ifdef _7ZIP_REDEFINE_OPERATOR_NEW
-
-// std::bad_alloc can require additional DLL dependency.
-// So we don't define CNewException as std::bad_alloc here.
-
-class CNewException {};
-
-void *
-#ifdef _MSC_VER
-__cdecl
-#endif
-operator new(size_t size);
-
-void
-#ifdef _MSC_VER
-__cdecl
-#endif
-operator delete(void *p) throw();
-
-#else
-
-#include <new>
-
-#define CNewException std::bad_alloc
-
-#endif
-
-/*
-#ifdef _WIN32
-void *
-#ifdef _MSC_VER
-__cdecl
-#endif
-operator new[](size_t size);
-
-void
-#ifdef _MSC_VER
-__cdecl
-#endif
-operator delete[](void *p) throw();
-#endif
-*/
-
-#endif
+// Common/NewHandler.h
+
+#ifndef ZIP7_INC_COMMON_NEW_HANDLER_H
+#define ZIP7_INC_COMMON_NEW_HANDLER_H
+
+/*
+NewHandler.h and NewHandler.cpp allows to solve problem with compilers that
+don't throw exception in operator new().
+
+This file must be included before any code that uses operators new() or delete()
+and you must compile and link "NewHandler.cpp", if you use some old MSVC compiler.
+
+DOCs:
+ Since ISO C++98, operator new throws std::bad_alloc when memory allocation fails.
+ MSVC 6.0 returned a null pointer on an allocation failure.
+ Beginning in VS2002, operator new conforms to the standard and throws on failure.
+
+ By default, the compiler also generates defensive null checks to prevent
+ these older-style allocators from causing an immediate crash on failure.
+ The /Zc:throwingNew option tells the compiler to leave out these null checks,
+ on the assumption that all linked memory allocators conform to the standard.
+
+The operator new() in some MSVC versions doesn't throw exception std::bad_alloc.
+MSVC 6.0 (_MSC_VER == 1200) doesn't throw exception.
+The code produced by some another MSVC compilers also can be linked
+to library that doesn't throw exception.
+We suppose that code compiled with VS2015+ (_MSC_VER >= 1900) throws exception std::bad_alloc.
+For older _MSC_VER versions we redefine operator new() and operator delete().
+Our version of operator new() throws CNewException() exception on failure.
+
+It's still allowed to use redefined version of operator new() from "NewHandler.cpp"
+with any compiler. 7-Zip's code can work with std::bad_alloc and CNewException() exceptions.
+But if you use some additional code (outside of 7-Zip's code), you must check
+that redefined version of operator new() is not problem for your code.
+*/
+
+#include <stddef.h>
+
+#ifdef _WIN32
+// We can compile my_new and my_delete with _fastcall
+/*
+void * my_new(size_t size);
+void my_delete(void *p) throw();
+// void * my_Realloc(void *p, size_t newSize, size_t oldSize);
+*/
+#endif
+
+
+#if defined(_MSC_VER) && (_MSC_VER < 1600)
+ // If you want to use default operator new(), you can disable the following line
+ #define Z7_REDEFINE_OPERATOR_NEW
+#endif
+
+
+#ifdef Z7_REDEFINE_OPERATOR_NEW
+
+// std::bad_alloc can require additional DLL dependency.
+// So we don't define CNewException as std::bad_alloc here.
+
+class CNewException {};
+
+void *
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator new(size_t size);
+
+void
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator delete(void *p) throw();
+
+#else
+
+#include <new>
+
+#define CNewException std::bad_alloc
+
+#endif
+
+/*
+#ifdef _WIN32
+void *
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator new[](size_t size);
+
+void
+#ifdef _MSC_VER
+__cdecl
+#endif
+operator delete[](void *p) throw();
+#endif
+*/
+
+#endif
diff --git a/CPP/Common/Random.cpp b/CPP/Common/Random.cpp
new file mode 100644
index 0000000..fbdb8c9
--- /dev/null
+++ b/CPP/Common/Random.cpp
@@ -0,0 +1,28 @@
+// Common/Random.cpp
+
+#include "StdAfx.h"
+
+#include <stdlib.h>
+
+#ifndef _WIN32
+#include <time.h>
+#else
+#include "MyWindows.h"
+#endif
+
+#include "Random.h"
+
+void CRandom::Init(unsigned int seed) { srand(seed); }
+
+void CRandom::Init()
+{
+ Init((unsigned int)
+ #ifdef _WIN32
+ GetTickCount()
+ #else
+ time(NULL)
+ #endif
+ );
+}
+
+int CRandom::Generate() const { return rand(); }
diff --git a/CPP/Common/Random.h b/CPP/Common/Random.h
new file mode 100644
index 0000000..283869e
--- /dev/null
+++ b/CPP/Common/Random.h
@@ -0,0 +1,14 @@
+// Common/Random.h
+
+#ifndef ZIP7_INC_COMMON_RANDOM_H
+#define ZIP7_INC_COMMON_RANDOM_H
+
+class CRandom
+{
+public:
+ void Init();
+ void Init(unsigned int seed);
+ int Generate() const;
+};
+
+#endif
diff --git a/CPP/Common/Sha1Prepare.cpp b/CPP/Common/Sha1Prepare.cpp
new file mode 100644
index 0000000..2652f00
--- /dev/null
+++ b/CPP/Common/Sha1Prepare.cpp
@@ -0,0 +1,7 @@
+// Sha1Prepare.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/Sha1.h"
+
+static struct CSha1Prepare { CSha1Prepare() { Sha1Prepare(); } } g_Sha1Prepare;
diff --git a/CPP/Common/Sha1Reg.cpp b/CPP/Common/Sha1Reg.cpp
new file mode 100644
index 0000000..64eef34
--- /dev/null
+++ b/CPP/Common/Sha1Reg.cpp
@@ -0,0 +1,67 @@
+// Sha1Reg.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/Sha1.h"
+
+#include "../Common/MyBuffer2.h"
+#include "../Common/MyCom.h"
+
+#include "../7zip/Common/RegisterCodec.h"
+
+Z7_CLASS_IMP_COM_2(
+ CSha1Hasher
+ , IHasher
+ , ICompressSetCoderProperties
+)
+ CAlignedBuffer1 _buf;
+public:
+ Byte _mtDummy[1 << 7];
+
+ CSha1 *Sha() { return (CSha1 *)(void *)(Byte *)_buf; }
+public:
+ CSha1Hasher():
+ _buf(sizeof(CSha1))
+ {
+ Sha1_SetFunction(Sha(), 0);
+ Sha1_InitState(Sha());
+ }
+};
+
+Z7_COM7F_IMF2(void, CSha1Hasher::Init())
+{
+ Sha1_InitState(Sha());
+}
+
+Z7_COM7F_IMF2(void, CSha1Hasher::Update(const void *data, UInt32 size))
+{
+ Sha1_Update(Sha(), (const Byte *)data, size);
+}
+
+Z7_COM7F_IMF2(void, CSha1Hasher::Final(Byte *digest))
+{
+ Sha1_Final(Sha(), digest);
+}
+
+
+Z7_COM7F_IMF(CSha1Hasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps))
+{
+ unsigned algo = 0;
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ if (propIDs[i] == NCoderPropID::kDefaultProp)
+ {
+ const PROPVARIANT &prop = coderProps[i];
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ if (prop.ulVal > 2)
+ return E_NOTIMPL;
+ algo = (unsigned)prop.ulVal;
+ }
+ }
+ if (!Sha1_SetFunction(Sha(), algo))
+ return E_NOTIMPL;
+ return S_OK;
+}
+
+REGISTER_HASHER(CSha1Hasher, 0x201, "SHA1", SHA1_DIGEST_SIZE)
diff --git a/CPP/Common/Sha256Prepare.cpp b/CPP/Common/Sha256Prepare.cpp
new file mode 100644
index 0000000..1ec242b
--- /dev/null
+++ b/CPP/Common/Sha256Prepare.cpp
@@ -0,0 +1,7 @@
+// Sha256Prepare.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/Sha256.h"
+
+static struct CSha256Prepare { CSha256Prepare() { Sha256Prepare(); } } g_Sha256Prepare;
diff --git a/CPP/Common/Sha256Reg.cpp b/CPP/Common/Sha256Reg.cpp
index 14a3652..b5689c4 100644
--- a/CPP/Common/Sha256Reg.cpp
+++ b/CPP/Common/Sha256Reg.cpp
@@ -1,40 +1,67 @@
-// Sha256Reg.cpp
-
-#include "StdAfx.h"
-
-#include "../../C/Sha256.h"
-
-#include "../Common/MyCom.h"
-
-#include "../7zip/Common/RegisterCodec.h"
-
-class CSha256Hasher:
- public IHasher,
- public CMyUnknownImp
-{
- CSha256 _sha;
- Byte mtDummy[1 << 7];
-
-public:
- CSha256Hasher() { Sha256_Init(&_sha); }
-
- MY_UNKNOWN_IMP1(IHasher)
- INTERFACE_IHasher(;)
-};
-
-STDMETHODIMP_(void) CSha256Hasher::Init() throw()
-{
- Sha256_Init(&_sha);
-}
-
-STDMETHODIMP_(void) CSha256Hasher::Update(const void *data, UInt32 size) throw()
-{
- Sha256_Update(&_sha, (const Byte *)data, size);
-}
-
-STDMETHODIMP_(void) CSha256Hasher::Final(Byte *digest) throw()
-{
- Sha256_Final(&_sha, digest);
-}
-
-REGISTER_HASHER(CSha256Hasher, 0xA, "SHA256", SHA256_DIGEST_SIZE)
+// Sha256Reg.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/Sha256.h"
+
+#include "../Common/MyBuffer2.h"
+#include "../Common/MyCom.h"
+
+#include "../7zip/Common/RegisterCodec.h"
+
+Z7_CLASS_IMP_COM_2(
+ CSha256Hasher
+ , IHasher
+ , ICompressSetCoderProperties
+)
+ CAlignedBuffer1 _buf;
+public:
+ Byte _mtDummy[1 << 7];
+
+ CSha256 *Sha() { return (CSha256 *)(void *)(Byte *)_buf; }
+public:
+ CSha256Hasher():
+ _buf(sizeof(CSha256))
+ {
+ Sha256_SetFunction(Sha(), 0);
+ Sha256_InitState(Sha());
+ }
+};
+
+Z7_COM7F_IMF2(void, CSha256Hasher::Init())
+{
+ Sha256_InitState(Sha());
+}
+
+Z7_COM7F_IMF2(void, CSha256Hasher::Update(const void *data, UInt32 size))
+{
+ Sha256_Update(Sha(), (const Byte *)data, size);
+}
+
+Z7_COM7F_IMF2(void, CSha256Hasher::Final(Byte *digest))
+{
+ Sha256_Final(Sha(), digest);
+}
+
+
+Z7_COM7F_IMF(CSha256Hasher::SetCoderProperties(const PROPID *propIDs, const PROPVARIANT *coderProps, UInt32 numProps))
+{
+ unsigned algo = 0;
+ for (UInt32 i = 0; i < numProps; i++)
+ {
+ if (propIDs[i] == NCoderPropID::kDefaultProp)
+ {
+ const PROPVARIANT &prop = coderProps[i];
+ if (prop.vt != VT_UI4)
+ return E_INVALIDARG;
+ if (prop.ulVal > 2)
+ return E_NOTIMPL;
+ algo = (unsigned)prop.ulVal;
+ }
+ }
+ if (!Sha256_SetFunction(Sha(), algo))
+ return E_NOTIMPL;
+ return S_OK;
+}
+
+REGISTER_HASHER(CSha256Hasher, 0xA, "SHA256", SHA256_DIGEST_SIZE)
diff --git a/CPP/Common/StdAfx.h b/CPP/Common/StdAfx.h
index 3f1890a..a5228b0 100644
--- a/CPP/Common/StdAfx.h
+++ b/CPP/Common/StdAfx.h
@@ -1,8 +1,8 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "Common.h"
-
-#endif
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#include "Common.h"
+
+#endif
diff --git a/CPP/Common/StdInStream.cpp b/CPP/Common/StdInStream.cpp
index f547b54..7b209f1 100644
--- a/CPP/Common/StdInStream.cpp
+++ b/CPP/Common/StdInStream.cpp
@@ -1,89 +1,98 @@
-// Common/StdInStream.cpp
-
-#include "StdAfx.h"
-
-#include <tchar.h>
-
-#include "StdInStream.h"
-#include "StringConvert.h"
-#include "UTFConvert.h"
-
-// #define kEOFMessage "Unexpected end of input stream"
-// #define kReadErrorMessage "Error reading input stream"
-// #define kIllegalCharMessage "Illegal zero character in input stream"
-
-#define kFileOpenMode TEXT("r")
-
-extern int g_CodePage;
-
-CStdInStream g_StdIn(stdin);
-
-bool CStdInStream::Open(LPCTSTR fileName) throw()
-{
- Close();
- _stream = _tfopen(fileName, kFileOpenMode);
- _streamIsOpen = (_stream != 0);
- return _streamIsOpen;
-}
-
-bool CStdInStream::Close() throw()
-{
- if (!_streamIsOpen)
- return true;
- _streamIsOpen = (fclose(_stream) != 0);
- return !_streamIsOpen;
-}
-
-bool CStdInStream::ScanAStringUntilNewLine(AString &s)
-{
- s.Empty();
- for (;;)
- {
- int intChar = GetChar();
- if (intChar == EOF)
- return true;
- char c = (char)intChar;
- if (c == 0)
- return false;
- if (c == '\n')
- return true;
- s += c;
- }
-}
-
-bool CStdInStream::ScanUStringUntilNewLine(UString &dest)
-{
- dest.Empty();
- AString s;
- bool res = ScanAStringUntilNewLine(s);
- int codePage = g_CodePage;
- if (codePage == -1)
- codePage = CP_OEMCP;
- if (codePage == CP_UTF8)
- ConvertUTF8ToUnicode(s, dest);
- else
- MultiByteToUnicodeString2(dest, s, (UINT)codePage);
- return res;
-}
-
-/*
-bool CStdInStream::ReadToString(AString &resultString)
-{
- resultString.Empty();
- for (;;)
- {
- int intChar = GetChar();
- if (intChar == EOF)
- return !Error();
- char c = (char)intChar;
- if (c == 0)
- return false;
- resultString += c;
- }
-}
-*/
-
-int CStdInStream::GetChar()
-{
- return fgetc(_stream); // getc() doesn't work in BeOS?
-}
+// Common/StdInStream.cpp
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#include <tchar.h>
+#endif
+
+#include "StdInStream.h"
+#include "StringConvert.h"
+#include "UTFConvert.h"
+
+// #define kEOFMessage "Unexpected end of input stream"
+// #define kReadErrorMessage "Error reading input stream"
+// #define kIllegalCharMessage "Illegal zero character in input stream"
+
+
+CStdInStream g_StdIn(stdin);
+
+/*
+#define kFileOpenMode TEXT("r")
+
+bool CStdInStream::Open(LPCTSTR fileName) throw()
+{
+ Close();
+ _stream =
+ #ifdef _WIN32
+ _tfopen
+ #else
+ fopen
+ #endif
+ (fileName, kFileOpenMode);
+ _streamIsOpen = (_stream != 0);
+ return _streamIsOpen;
+}
+
+bool CStdInStream::Close() throw()
+{
+ if (!_streamIsOpen)
+ return true;
+ _streamIsOpen = (fclose(_stream) != 0);
+ return !_streamIsOpen;
+}
+*/
+
+bool CStdInStream::ScanAStringUntilNewLine(AString &s)
+{
+ s.Empty();
+ for (;;)
+ {
+ int intChar = GetChar();
+ if (intChar == EOF)
+ return true;
+ char c = (char)intChar;
+ if (c == 0)
+ return false;
+ if (c == '\n')
+ return true;
+ s += c;
+ }
+}
+
+bool CStdInStream::ScanUStringUntilNewLine(UString &dest)
+{
+ dest.Empty();
+ AString s;
+ bool res = ScanAStringUntilNewLine(s);
+ int codePage = CodePage;
+ if (codePage == -1)
+ codePage = CP_OEMCP;
+ if (codePage == CP_UTF8)
+ ConvertUTF8ToUnicode(s, dest);
+ else
+ MultiByteToUnicodeString2(dest, s, (UINT)codePage);
+ return res;
+}
+
+/*
+bool CStdInStream::ReadToString(AString &resultString)
+{
+ resultString.Empty();
+ for (;;)
+ {
+ int intChar = GetChar();
+ if (intChar == EOF)
+ return !Error();
+ char c = (char)intChar;
+ if (c == 0)
+ return false;
+ resultString += c;
+ }
+}
+*/
+
+int CStdInStream::GetChar()
+{
+ return fgetc(_stream); // getc() doesn't work in BeOS?
+}
diff --git a/CPP/Common/StdInStream.h b/CPP/Common/StdInStream.h
index 20f9ce3..81ca3bf 100644
--- a/CPP/Common/StdInStream.h
+++ b/CPP/Common/StdInStream.h
@@ -1,38 +1,46 @@
-// Common/StdInStream.h
-
-#ifndef __COMMON_STD_IN_STREAM_H
-#define __COMMON_STD_IN_STREAM_H
-
-#include <stdio.h>
-
-#include "MyString.h"
-#include "MyTypes.h"
-
-class CStdInStream
-{
- FILE *_stream;
- bool _streamIsOpen;
-public:
- CStdInStream(): _stream(0), _streamIsOpen(false) {};
- CStdInStream(FILE *stream): _stream(stream), _streamIsOpen(false) {};
- ~CStdInStream() { Close(); }
-
- bool Open(LPCTSTR fileName) throw();
- bool Close() throw();
-
- // returns:
- // false, if ZERO character in stream
- // true, if EOF or '\n'
- bool ScanAStringUntilNewLine(AString &s);
- bool ScanUStringUntilNewLine(UString &s);
- // bool ReadToString(AString &resultString);
-
- bool Eof() const throw() { return (feof(_stream) != 0); }
- bool Error() const throw() { return (ferror(_stream) != 0); }
-
- int GetChar();
-};
-
-extern CStdInStream g_StdIn;
-
-#endif
+// Common/StdInStream.h
+
+#ifndef ZIP7_INC_COMMON_STD_IN_STREAM_H
+#define ZIP7_INC_COMMON_STD_IN_STREAM_H
+
+#include <stdio.h>
+
+#include "MyString.h"
+#include "MyTypes.h"
+
+class CStdInStream
+{
+ FILE *_stream;
+ // bool _streamIsOpen;
+public:
+ int CodePage;
+
+ CStdInStream(FILE *stream = NULL):
+ _stream(stream),
+ // _streamIsOpen(false),
+ CodePage(-1)
+ {}
+
+ /*
+ ~CStdInStream() { Close(); }
+
+ bool Open(LPCTSTR fileName) throw();
+ bool Close() throw();
+ */
+
+ // returns:
+ // false, if ZERO character in stream
+ // true, if EOF or '\n'
+ bool ScanAStringUntilNewLine(AString &s);
+ bool ScanUStringUntilNewLine(UString &s);
+ // bool ReadToString(AString &resultString);
+
+ bool Eof() const throw() { return (feof(_stream) != 0); }
+ bool Error() const throw() { return (ferror(_stream) != 0); }
+
+ int GetChar();
+};
+
+extern CStdInStream g_StdIn;
+
+#endif
diff --git a/CPP/Common/StdOutStream.cpp b/CPP/Common/StdOutStream.cpp
index dc6d4bd..cfa5fde 100644
--- a/CPP/Common/StdOutStream.cpp
+++ b/CPP/Common/StdOutStream.cpp
@@ -1,163 +1,160 @@
-// Common/StdOutStream.cpp
-
-#include "StdAfx.h"
-
-#include <tchar.h>
-
-#include "IntToString.h"
-#include "StdOutStream.h"
-#include "StringConvert.h"
-#include "UTFConvert.h"
-
-#define kFileOpenMode "wt"
-
-extern int g_CodePage;
-
-CStdOutStream g_StdOut(stdout);
-CStdOutStream g_StdErr(stderr);
-
-bool CStdOutStream::Open(const char *fileName) throw()
-{
- Close();
- _stream = fopen(fileName, kFileOpenMode);
- _streamIsOpen = (_stream != 0);
- return _streamIsOpen;
-}
-
-bool CStdOutStream::Close() throw()
-{
- if (!_streamIsOpen)
- return true;
- if (fclose(_stream) != 0)
- return false;
- _stream = 0;
- _streamIsOpen = false;
- return true;
-}
-
-bool CStdOutStream::Flush() throw()
-{
- return (fflush(_stream) == 0);
-}
-
-CStdOutStream & endl(CStdOutStream & outStream) throw()
-{
- return outStream << '\n';
-}
-
-CStdOutStream & CStdOutStream::operator<<(const wchar_t *s)
-{
- int codePage = g_CodePage;
- if (codePage == -1)
- codePage = CP_OEMCP;
- AString dest;
- if (codePage == CP_UTF8)
- ConvertUnicodeToUTF8(s, dest);
- else
- UnicodeStringToMultiByte2(dest, s, (UINT)codePage);
- return operator<<((const char *)dest);
-}
-
-void StdOut_Convert_UString_to_AString(const UString &s, AString &temp)
-{
- int codePage = g_CodePage;
- if (codePage == -1)
- codePage = CP_OEMCP;
- if (codePage == CP_UTF8)
- ConvertUnicodeToUTF8(s, temp);
- else
- UnicodeStringToMultiByte2(temp, s, (UINT)codePage);
-}
-
-void CStdOutStream::PrintUString(const UString &s, AString &temp)
-{
- StdOut_Convert_UString_to_AString(s, temp);
- *this << (const char *)temp;
-}
-
-
-static const wchar_t kReplaceChar = '_';
-
-void CStdOutStream::Normalize_UString__LF_Allowed(UString &s)
-{
- unsigned len = s.Len();
- wchar_t *d = s.GetBuf();
-
- if (IsTerminalMode)
- for (unsigned i = 0; i < len; i++)
- {
- wchar_t c = d[i];
- if (c <= 13 && c >= 7 && c != '\n')
- d[i] = kReplaceChar;
- }
-}
-
-void CStdOutStream::Normalize_UString(UString &s)
-{
- unsigned len = s.Len();
- wchar_t *d = s.GetBuf();
-
- if (IsTerminalMode)
- for (unsigned i = 0; i < len; i++)
- {
- wchar_t c = d[i];
- if (c <= 13 && c >= 7)
- d[i] = kReplaceChar;
- }
- else
- for (unsigned i = 0; i < len; i++)
- {
- wchar_t c = d[i];
- if (c == '\n')
- d[i] = kReplaceChar;
- }
-}
-
-void CStdOutStream::NormalizePrint_UString(const UString &s, UString &tempU, AString &tempA)
-{
- tempU = s;
- Normalize_UString(tempU);
- PrintUString(tempU, tempA);
-}
-
-void CStdOutStream::NormalizePrint_UString(const UString &s)
-{
- NormalizePrint_wstr(s);
-}
-
-void CStdOutStream::NormalizePrint_wstr(const wchar_t *s)
-{
- UString tempU = s;
- Normalize_UString(tempU);
- AString tempA;
- PrintUString(tempU, tempA);
-}
-
-
-CStdOutStream & CStdOutStream::operator<<(Int32 number) throw()
-{
- char s[32];
- ConvertInt64ToString(number, s);
- return operator<<(s);
-}
-
-CStdOutStream & CStdOutStream::operator<<(Int64 number) throw()
-{
- char s[32];
- ConvertInt64ToString(number, s);
- return operator<<(s);
-}
-
-CStdOutStream & CStdOutStream::operator<<(UInt32 number) throw()
-{
- char s[16];
- ConvertUInt32ToString(number, s);
- return operator<<(s);
-}
-
-CStdOutStream & CStdOutStream::operator<<(UInt64 number) throw()
-{
- char s[32];
- ConvertUInt64ToString(number, s);
- return operator<<(s);
-}
+// Common/StdOutStream.cpp
+
+#include "StdAfx.h"
+
+#ifdef _WIN32
+#include <tchar.h>
+#endif
+
+#include "IntToString.h"
+#include "StdOutStream.h"
+#include "StringConvert.h"
+#include "UTFConvert.h"
+
+CStdOutStream g_StdOut(stdout);
+CStdOutStream g_StdErr(stderr);
+
+/*
+// #define kFileOpenMode "wt"
+
+bool CStdOutStream::Open(const char *fileName) throw()
+{
+ Close();
+ _stream = fopen(fileName, kFileOpenMode);
+ _streamIsOpen = (_stream != 0);
+ return _streamIsOpen;
+}
+
+bool CStdOutStream::Close() throw()
+{
+ if (!_streamIsOpen)
+ return true;
+ if (fclose(_stream) != 0)
+ return false;
+ _stream = 0;
+ _streamIsOpen = false;
+ return true;
+}
+*/
+
+bool CStdOutStream::Flush() throw()
+{
+ return (fflush(_stream) == 0);
+}
+
+CStdOutStream & endl(CStdOutStream & outStream) throw()
+{
+ return outStream << '\n';
+}
+
+CStdOutStream & CStdOutStream::operator<<(const wchar_t *s)
+{
+ AString temp;
+ UString s2(s);
+ PrintUString(s2, temp);
+ return *this;
+}
+
+void CStdOutStream::PrintUString(const UString &s, AString &temp)
+{
+ Convert_UString_to_AString(s, temp);
+ *this << (const char *)temp;
+}
+
+void CStdOutStream::Convert_UString_to_AString(const UString &src, AString &dest)
+{
+ int codePage = CodePage;
+ if (codePage == -1)
+ codePage = CP_OEMCP;
+ if (codePage == CP_UTF8)
+ ConvertUnicodeToUTF8(src, dest);
+ else
+ UnicodeStringToMultiByte2(dest, src, (UINT)codePage);
+}
+
+
+static const wchar_t kReplaceChar = '_';
+
+void CStdOutStream::Normalize_UString_LF_Allowed(UString &s)
+{
+ unsigned len = s.Len();
+ wchar_t *d = s.GetBuf();
+
+ if (IsTerminalMode)
+ for (unsigned i = 0; i < len; i++)
+ {
+ wchar_t c = d[i];
+ if (c <= 13 && c >= 7 && c != '\n')
+ d[i] = kReplaceChar;
+ }
+}
+
+void CStdOutStream::Normalize_UString(UString &s)
+{
+ unsigned len = s.Len();
+ wchar_t *d = s.GetBuf();
+
+ if (IsTerminalMode)
+ for (unsigned i = 0; i < len; i++)
+ {
+ wchar_t c = d[i];
+ if (c <= 13 && c >= 7)
+ d[i] = kReplaceChar;
+ }
+ else
+ for (unsigned i = 0; i < len; i++)
+ {
+ wchar_t c = d[i];
+ if (c == '\n')
+ d[i] = kReplaceChar;
+ }
+}
+
+void CStdOutStream::NormalizePrint_UString(const UString &s, UString &tempU, AString &tempA)
+{
+ tempU = s;
+ Normalize_UString(tempU);
+ PrintUString(tempU, tempA);
+}
+
+void CStdOutStream::NormalizePrint_UString(const UString &s)
+{
+ NormalizePrint_wstr(s);
+}
+
+void CStdOutStream::NormalizePrint_wstr(const wchar_t *s)
+{
+ UString tempU = s;
+ Normalize_UString(tempU);
+ AString tempA;
+ PrintUString(tempU, tempA);
+}
+
+
+CStdOutStream & CStdOutStream::operator<<(Int32 number) throw()
+{
+ char s[32];
+ ConvertInt64ToString(number, s);
+ return operator<<(s);
+}
+
+CStdOutStream & CStdOutStream::operator<<(Int64 number) throw()
+{
+ char s[32];
+ ConvertInt64ToString(number, s);
+ return operator<<(s);
+}
+
+CStdOutStream & CStdOutStream::operator<<(UInt32 number) throw()
+{
+ char s[16];
+ ConvertUInt32ToString(number, s);
+ return operator<<(s);
+}
+
+CStdOutStream & CStdOutStream::operator<<(UInt64 number) throw()
+{
+ char s[32];
+ ConvertUInt64ToString(number, s);
+ return operator<<(s);
+}
diff --git a/CPP/Common/StdOutStream.h b/CPP/Common/StdOutStream.h
index 475954c..bd15d7c 100644
--- a/CPP/Common/StdOutStream.h
+++ b/CPP/Common/StdOutStream.h
@@ -1,71 +1,78 @@
-// Common/StdOutStream.h
-
-#ifndef __COMMON_STD_OUT_STREAM_H
-#define __COMMON_STD_OUT_STREAM_H
-
-#include <stdio.h>
-
-#include "MyString.h"
-#include "MyTypes.h"
-
-class CStdOutStream
-{
- FILE *_stream;
- bool _streamIsOpen;
-public:
- bool IsTerminalMode;
-
- CStdOutStream(): _stream(0), _streamIsOpen(false), IsTerminalMode(false) {};
- CStdOutStream(FILE *stream): _stream(stream), _streamIsOpen(false) {};
- ~CStdOutStream() { Close(); }
-
- // void AttachStdStream(FILE *stream) { _stream = stream; _streamIsOpen = false; }
- // bool IsDefined() const { return _stream != NULL; }
-
- operator FILE *() { return _stream; }
- bool Open(const char *fileName) throw();
- bool Close() throw();
- bool Flush() throw();
-
- CStdOutStream & operator<<(CStdOutStream & (* func)(CStdOutStream &))
- {
- (*func)(*this);
- return *this;
- }
-
- CStdOutStream & operator<<(const char *s) throw()
- {
- fputs(s, _stream);
- return *this;
- }
-
- CStdOutStream & operator<<(char c) throw()
- {
- fputc((unsigned char)c, _stream);
- return *this;
- }
-
- CStdOutStream & operator<<(Int32 number) throw();
- CStdOutStream & operator<<(Int64 number) throw();
- CStdOutStream & operator<<(UInt32 number) throw();
- CStdOutStream & operator<<(UInt64 number) throw();
-
- CStdOutStream & operator<<(const wchar_t *s);
- void PrintUString(const UString &s, AString &temp);
-
- void Normalize_UString__LF_Allowed(UString &s);
- void Normalize_UString(UString &s);
-
- void NormalizePrint_UString(const UString &s, UString &tempU, AString &tempA);
- void NormalizePrint_UString(const UString &s);
- void NormalizePrint_wstr(const wchar_t *s);
-};
-
-CStdOutStream & endl(CStdOutStream & outStream) throw();
-
-extern CStdOutStream g_StdOut;
-extern CStdOutStream g_StdErr;
-
-void StdOut_Convert_UString_to_AString(const UString &s, AString &temp);
-
-#endif
+// Common/StdOutStream.h
+
+#ifndef ZIP7_INC_COMMON_STD_OUT_STREAM_H
+#define ZIP7_INC_COMMON_STD_OUT_STREAM_H
+
+#include <stdio.h>
+
+#include "MyString.h"
+#include "MyTypes.h"
+
+class CStdOutStream
+{
+ FILE *_stream;
+ // bool _streamIsOpen;
+public:
+ bool IsTerminalMode;
+ int CodePage;
+
+ CStdOutStream(FILE *stream = NULL):
+ _stream(stream),
+ // _streamIsOpen(false),
+ IsTerminalMode(false),
+ CodePage(-1)
+ {}
+
+ // ~CStdOutStream() { Close(); }
+
+ // void AttachStdStream(FILE *stream) { _stream = stream; _streamIsOpen = false; }
+ // bool IsDefined() const { return _stream != NULL; }
+
+ operator FILE *() { return _stream; }
+ /*
+ bool Open(const char *fileName) throw();
+ bool Close() throw();
+ */
+ bool Flush() throw();
+
+ CStdOutStream & operator<<(CStdOutStream & (* func)(CStdOutStream &))
+ {
+ (*func)(*this);
+ return *this;
+ }
+
+ CStdOutStream & operator<<(const char *s) throw()
+ {
+ fputs(s, _stream);
+ return *this;
+ }
+
+ CStdOutStream & operator<<(char c) throw()
+ {
+ fputc((unsigned char)c, _stream);
+ return *this;
+ }
+
+ CStdOutStream & operator<<(Int32 number) throw();
+ CStdOutStream & operator<<(Int64 number) throw();
+ CStdOutStream & operator<<(UInt32 number) throw();
+ CStdOutStream & operator<<(UInt64 number) throw();
+
+ CStdOutStream & operator<<(const wchar_t *s);
+ void PrintUString(const UString &s, AString &temp);
+ void Convert_UString_to_AString(const UString &src, AString &dest);
+
+ void Normalize_UString_LF_Allowed(UString &s);
+ void Normalize_UString(UString &s);
+
+ void NormalizePrint_UString(const UString &s, UString &tempU, AString &tempA);
+ void NormalizePrint_UString(const UString &s);
+ void NormalizePrint_wstr(const wchar_t *s);
+};
+
+CStdOutStream & endl(CStdOutStream & outStream) throw();
+
+extern CStdOutStream g_StdOut;
+extern CStdOutStream g_StdErr;
+
+#endif
diff --git a/CPP/Common/StringConvert.cpp b/CPP/Common/StringConvert.cpp
index b8f33cd..f25396a 100644
--- a/CPP/Common/StringConvert.cpp
+++ b/CPP/Common/StringConvert.cpp
@@ -1,319 +1,756 @@
-// Common/StringConvert.cpp
-
-#include "StdAfx.h"
-
-#include "StringConvert.h"
-
-#ifndef _WIN32
-#include <stdlib.h>
-#endif
-
-static const char k_DefultChar = '_';
-
-#ifdef _WIN32
-
-/*
-MultiByteToWideChar(CodePage, DWORD dwFlags,
- LPCSTR lpMultiByteStr, int cbMultiByte,
- LPWSTR lpWideCharStr, int cchWideChar)
-
- if (cbMultiByte == 0)
- return: 0. ERR: ERROR_INVALID_PARAMETER
-
- if (cchWideChar == 0)
- return: the required buffer size in characters.
-
- if (supplied buffer size was not large enough)
- return: 0. ERR: ERROR_INSUFFICIENT_BUFFER
- The number of filled characters in lpWideCharStr can be smaller than cchWideChar (if last character is complex)
-
- If there are illegal characters:
- if MB_ERR_INVALID_CHARS is set in dwFlags:
- - the function stops conversion on illegal character.
- - Return: 0. ERR: ERROR_NO_UNICODE_TRANSLATION.
-
- if MB_ERR_INVALID_CHARS is NOT set in dwFlags:
- before Vista: illegal character is dropped (skipped). WinXP-64: GetLastError() returns 0.
- in Vista+: illegal character is not dropped (MSDN). Undocumented: illegal
- character is converted to U+FFFD, which is REPLACEMENT CHARACTER.
-*/
-
-
-void MultiByteToUnicodeString2(UString &dest, const AString &src, UINT codePage)
-{
- dest.Empty();
- if (src.IsEmpty())
- return;
- {
- /*
- wchar_t *d = dest.GetBuf(src.Len());
- const char *s = (const char *)src;
- unsigned i;
-
- for (i = 0;;)
- {
- Byte c = (Byte)s[i];
- if (c >= 0x80 || c == 0)
- break;
- d[i++] = (wchar_t)c;
- }
-
- if (i != src.Len())
- {
- unsigned len = MultiByteToWideChar(codePage, 0, s + i,
- src.Len() - i, d + i,
- src.Len() + 1 - i);
- if (len == 0)
- throw 282228;
- i += len;
- }
-
- d[i] = 0;
- dest.ReleaseBuf_SetLen(i);
- */
- unsigned len = MultiByteToWideChar(codePage, 0, src, src.Len(), NULL, 0);
- if (len == 0)
- {
- if (GetLastError() != 0)
- throw 282228;
- }
- else
- {
- len = MultiByteToWideChar(codePage, 0, src, src.Len(), dest.GetBuf(len), len);
- if (len == 0)
- throw 282228;
- dest.ReleaseBuf_SetEnd(len);
- }
- }
-}
-
-/*
- int WideCharToMultiByte(
- UINT CodePage, DWORD dwFlags,
- LPCWSTR lpWideCharStr, int cchWideChar,
- LPSTR lpMultiByteStr, int cbMultiByte,
- LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar);
-
-if (lpDefaultChar == NULL),
- - it uses system default value.
-
-if (CodePage == CP_UTF7 || CodePage == CP_UTF8)
- if (lpDefaultChar != NULL || lpUsedDefaultChar != NULL)
- return: 0. ERR: ERROR_INVALID_PARAMETER.
-
-The function operates most efficiently, if (lpDefaultChar == NULL && lpUsedDefaultChar == NULL)
-
-*/
-
-static void UnicodeStringToMultiByte2(AString &dest, const UString &src, UINT codePage, char defaultChar, bool &defaultCharWasUsed)
-{
- dest.Empty();
- defaultCharWasUsed = false;
- if (src.IsEmpty())
- return;
- {
- /*
- unsigned numRequiredBytes = src.Len() * 2;
- char *d = dest.GetBuf(numRequiredBytes);
- const wchar_t *s = (const wchar_t *)src;
- unsigned i;
-
- for (i = 0;;)
- {
- wchar_t c = s[i];
- if (c >= 0x80 || c == 0)
- break;
- d[i++] = (char)c;
- }
-
- if (i != src.Len())
- {
- BOOL defUsed = FALSE;
- defaultChar = defaultChar;
-
- bool isUtf = (codePage == CP_UTF8 || codePage == CP_UTF7);
- unsigned len = WideCharToMultiByte(codePage, 0, s + i, src.Len() - i,
- d + i, numRequiredBytes + 1 - i,
- (isUtf ? NULL : &defaultChar),
- (isUtf ? NULL : &defUsed));
- defaultCharWasUsed = (defUsed != FALSE);
- if (len == 0)
- throw 282229;
- i += len;
- }
-
- d[i] = 0;
- dest.ReleaseBuf_SetLen(i);
- */
-
- /*
- if (codePage != CP_UTF7)
- {
- const wchar_t *s = (const wchar_t *)src;
- unsigned i;
- for (i = 0;; i++)
- {
- wchar_t c = s[i];
- if (c >= 0x80 || c == 0)
- break;
- }
-
- if (s[i] == 0)
- {
- char *d = dest.GetBuf(src.Len());
- for (i = 0;;)
- {
- wchar_t c = s[i];
- if (c == 0)
- break;
- d[i++] = (char)c;
- }
- d[i] = 0;
- dest.ReleaseBuf_SetLen(i);
- return;
- }
- }
- */
-
- unsigned len = WideCharToMultiByte(codePage, 0, src, src.Len(), NULL, 0, NULL, NULL);
- if (len == 0)
- {
- if (GetLastError() != 0)
- throw 282228;
- }
- else
- {
- BOOL defUsed = FALSE;
- bool isUtf = (codePage == CP_UTF8 || codePage == CP_UTF7);
- // defaultChar = defaultChar;
- len = WideCharToMultiByte(codePage, 0, src, src.Len(),
- dest.GetBuf(len), len,
- (isUtf ? NULL : &defaultChar),
- (isUtf ? NULL : &defUsed)
- );
- if (!isUtf)
- defaultCharWasUsed = (defUsed != FALSE);
- if (len == 0)
- throw 282228;
- dest.ReleaseBuf_SetEnd(len);
- }
- }
-}
-
-/*
-#ifndef UNDER_CE
-AString SystemStringToOemString(const CSysString &src)
-{
- AString dest;
- const unsigned len = src.Len() * 2;
- CharToOem(src, dest.GetBuf(len));
- dest.ReleaseBuf_CalcLen(len);
- return dest;
-}
-#endif
-*/
-
-#else
-
-void MultiByteToUnicodeString2(UString &dest, const AString &src, UINT /* codePage */)
-{
- dest.Empty();
- if (src.IsEmpty())
- return;
-
- size_t limit = ((size_t)src.Len() + 1) * 2;
- wchar_t *d = dest.GetBuf((unsigned)limit);
- size_t len = mbstowcs(d, src, limit);
- if (len != (size_t)-1)
- {
- dest.ReleaseBuf_SetEnd((unsigned)len);
- return;
- }
-
- {
- unsigned i;
- const char *s = (const char *)src;
- for (i = 0;;)
- {
- Byte c = (Byte)s[i];
- if (c == 0)
- break;
- d[i++] = (wchar_t)c;
- }
- d[i] = 0;
- dest.ReleaseBuf_SetLen(i);
- }
-}
-
-static void UnicodeStringToMultiByte2(AString &dest, const UString &src, UINT /* codePage */, char defaultChar, bool &defaultCharWasUsed)
-{
- dest.Empty();
- defaultCharWasUsed = false;
- if (src.IsEmpty())
- return;
-
- size_t limit = ((size_t)src.Len() + 1) * 6;
- char *d = dest.GetBuf((unsigned)limit);
- size_t len = wcstombs(d, src, limit);
- if (len != (size_t)-1)
- {
- dest.ReleaseBuf_SetEnd((unsigned)len);
- return;
- }
-
- {
- const wchar_t *s = (const wchar_t *)src;
- unsigned i;
- for (i = 0;;)
- {
- wchar_t c = s[i];
- if (c == 0)
- break;
- if (c >= 0x100)
- {
- c = defaultChar;
- defaultCharWasUsed = true;
- }
- d[i++] = (char)c;
- }
- d[i] = 0;
- dest.ReleaseBuf_SetLen(i);
- }
-}
-
-#endif
-
-
-UString MultiByteToUnicodeString(const AString &src, UINT codePage)
-{
- UString dest;
- MultiByteToUnicodeString2(dest, src, codePage);
- return dest;
-}
-
-UString MultiByteToUnicodeString(const char *src, UINT codePage)
-{
- return MultiByteToUnicodeString(AString(src), codePage);
-}
-
-
-void UnicodeStringToMultiByte2(AString &dest, const UString &src, UINT codePage)
-{
- bool defaultCharWasUsed;
- UnicodeStringToMultiByte2(dest, src, codePage, k_DefultChar, defaultCharWasUsed);
-}
-
-AString UnicodeStringToMultiByte(const UString &src, UINT codePage, char defaultChar, bool &defaultCharWasUsed)
-{
- AString dest;
- UnicodeStringToMultiByte2(dest, src, codePage, defaultChar, defaultCharWasUsed);
- return dest;
-}
-
-AString UnicodeStringToMultiByte(const UString &src, UINT codePage)
-{
- AString dest;
- bool defaultCharWasUsed;
- UnicodeStringToMultiByte2(dest, src, codePage, k_DefultChar, defaultCharWasUsed);
- return dest;
-}
+// Common/StringConvert.cpp
+
+#include "StdAfx.h"
+
+#include "StringConvert.h"
+
+#ifndef _WIN32
+// #include <stdio.h>
+#include <stdlib.h>
+#endif
+
+#if !defined(_WIN32) || defined(ENV_HAVE_LOCALE)
+#include "UTFConvert.h"
+#endif
+
+#ifdef ENV_HAVE_LOCALE
+#include <locale.h>
+#endif
+
+static const char k_DefultChar = '_';
+
+#ifdef _WIN32
+
+/*
+MultiByteToWideChar(CodePage, DWORD dwFlags,
+ LPCSTR lpMultiByteStr, int cbMultiByte,
+ LPWSTR lpWideCharStr, int cchWideChar)
+
+ if (cbMultiByte == 0)
+ return: 0. ERR: ERROR_INVALID_PARAMETER
+
+ if (cchWideChar == 0)
+ return: the required buffer size in characters.
+
+ if (supplied buffer size was not large enough)
+ return: 0. ERR: ERROR_INSUFFICIENT_BUFFER
+ The number of filled characters in lpWideCharStr can be smaller than cchWideChar (if last character is complex)
+
+ If there are illegal characters:
+ if MB_ERR_INVALID_CHARS is set in dwFlags:
+ - the function stops conversion on illegal character.
+ - Return: 0. ERR: ERROR_NO_UNICODE_TRANSLATION.
+
+ if MB_ERR_INVALID_CHARS is NOT set in dwFlags:
+ before Vista: illegal character is dropped (skipped). WinXP-64: GetLastError() returns 0.
+ in Vista+: illegal character is not dropped (MSDN). Undocumented: illegal
+ character is converted to U+FFFD, which is REPLACEMENT CHARACTER.
+*/
+
+
+void MultiByteToUnicodeString2(UString &dest, const AString &src, UINT codePage)
+{
+ dest.Empty();
+ if (src.IsEmpty())
+ return;
+ {
+ /*
+ wchar_t *d = dest.GetBuf(src.Len());
+ const char *s = (const char *)src;
+ unsigned i;
+
+ for (i = 0;;)
+ {
+ Byte c = (Byte)s[i];
+ if (c >= 0x80 || c == 0)
+ break;
+ d[i++] = (wchar_t)c;
+ }
+
+ if (i != src.Len())
+ {
+ unsigned len = MultiByteToWideChar(codePage, 0, s + i,
+ src.Len() - i, d + i,
+ src.Len() + 1 - i);
+ if (len == 0)
+ throw 282228;
+ i += len;
+ }
+
+ d[i] = 0;
+ dest.ReleaseBuf_SetLen(i);
+ */
+ unsigned len = (unsigned)MultiByteToWideChar(codePage, 0, src, (int)src.Len(), NULL, 0);
+ if (len == 0)
+ {
+ if (GetLastError() != 0)
+ throw 282228;
+ }
+ else
+ {
+ len = (unsigned)MultiByteToWideChar(codePage, 0, src, (int)src.Len(), dest.GetBuf(len), (int)len);
+ if (len == 0)
+ throw 282228;
+ dest.ReleaseBuf_SetEnd(len);
+ }
+ }
+}
+
+/*
+ int WideCharToMultiByte(
+ UINT CodePage, DWORD dwFlags,
+ LPCWSTR lpWideCharStr, int cchWideChar,
+ LPSTR lpMultiByteStr, int cbMultiByte,
+ LPCSTR lpDefaultChar, LPBOOL lpUsedDefaultChar);
+
+if (lpDefaultChar == NULL),
+ - it uses system default value.
+
+if (CodePage == CP_UTF7 || CodePage == CP_UTF8)
+ if (lpDefaultChar != NULL || lpUsedDefaultChar != NULL)
+ return: 0. ERR: ERROR_INVALID_PARAMETER.
+
+The function operates most efficiently, if (lpDefaultChar == NULL && lpUsedDefaultChar == NULL)
+
+*/
+
+static void UnicodeStringToMultiByte2(AString &dest, const UString &src, UINT codePage, char defaultChar, bool &defaultCharWasUsed)
+{
+ dest.Empty();
+ defaultCharWasUsed = false;
+ if (src.IsEmpty())
+ return;
+ {
+ /*
+ unsigned numRequiredBytes = src.Len() * 2;
+ char *d = dest.GetBuf(numRequiredBytes);
+ const wchar_t *s = (const wchar_t *)src;
+ unsigned i;
+
+ for (i = 0;;)
+ {
+ wchar_t c = s[i];
+ if (c >= 0x80 || c == 0)
+ break;
+ d[i++] = (char)c;
+ }
+
+ if (i != src.Len())
+ {
+ BOOL defUsed = FALSE;
+ defaultChar = defaultChar;
+
+ bool isUtf = (codePage == CP_UTF8 || codePage == CP_UTF7);
+ unsigned len = WideCharToMultiByte(codePage, 0, s + i, src.Len() - i,
+ d + i, numRequiredBytes + 1 - i,
+ (isUtf ? NULL : &defaultChar),
+ (isUtf ? NULL : &defUsed));
+ defaultCharWasUsed = (defUsed != FALSE);
+ if (len == 0)
+ throw 282229;
+ i += len;
+ }
+
+ d[i] = 0;
+ dest.ReleaseBuf_SetLen(i);
+ */
+
+ /*
+ if (codePage != CP_UTF7)
+ {
+ const wchar_t *s = (const wchar_t *)src;
+ unsigned i;
+ for (i = 0;; i++)
+ {
+ wchar_t c = s[i];
+ if (c >= 0x80 || c == 0)
+ break;
+ }
+
+ if (s[i] == 0)
+ {
+ char *d = dest.GetBuf(src.Len());
+ for (i = 0;;)
+ {
+ wchar_t c = s[i];
+ if (c == 0)
+ break;
+ d[i++] = (char)c;
+ }
+ d[i] = 0;
+ dest.ReleaseBuf_SetLen(i);
+ return;
+ }
+ }
+ */
+
+ unsigned len = (unsigned)WideCharToMultiByte(codePage, 0, src, (int)src.Len(), NULL, 0, NULL, NULL);
+ if (len == 0)
+ {
+ if (GetLastError() != 0)
+ throw 282228;
+ }
+ else
+ {
+ BOOL defUsed = FALSE;
+ bool isUtf = (codePage == CP_UTF8 || codePage == CP_UTF7);
+ // defaultChar = defaultChar;
+ len = (unsigned)WideCharToMultiByte(codePage, 0, src, (int)src.Len(),
+ dest.GetBuf(len), (int)len,
+ (isUtf ? NULL : &defaultChar),
+ (isUtf ? NULL : &defUsed)
+ );
+ if (!isUtf)
+ defaultCharWasUsed = (defUsed != FALSE);
+ if (len == 0)
+ throw 282228;
+ dest.ReleaseBuf_SetEnd(len);
+ }
+ }
+}
+
+/*
+#ifndef UNDER_CE
+AString SystemStringToOemString(const CSysString &src)
+{
+ AString dest;
+ const unsigned len = src.Len() * 2;
+ CharToOem(src, dest.GetBuf(len));
+ dest.ReleaseBuf_CalcLen(len);
+ return dest;
+}
+#endif
+*/
+
+#else // _WIN32
+
+// #include <stdio.h>
+/*
+ if (wchar_t is 32-bit (#if WCHAR_MAX > 0xffff),
+ and utf-8 string contains big unicode character > 0xffff),
+ then we still use 16-bit surrogate pair in UString.
+ It simplifies another code where utf-16 encoding is used.
+ So we use surrogate-conversion code only in is file.
+*/
+
+/*
+ mbstowcs() returns error if there is error in utf-8 stream,
+ mbstowcs() returns error if there is single surrogates point (d800-dfff) in utf-8 stream
+*/
+
+/*
+static void MultiByteToUnicodeString2_Native(UString &dest, const AString &src)
+{
+ dest.Empty();
+ if (src.IsEmpty())
+ return;
+
+ const size_t limit = ((size_t)src.Len() + 1) * 2;
+ wchar_t *d = dest.GetBuf((unsigned)limit);
+ const size_t len = mbstowcs(d, src, limit);
+ if (len != (size_t)-1)
+ {
+ dest.ReleaseBuf_SetEnd((unsigned)len);
+ return;
+ }
+ dest.ReleaseBuf_SetEnd(0);
+}
+*/
+
+bool g_ForceToUTF8 = true; // false;
+
+void MultiByteToUnicodeString2(UString &dest, const AString &src, UINT codePage)
+{
+ dest.Empty();
+ if (src.IsEmpty())
+ return;
+
+ if (codePage == CP_UTF8 || g_ForceToUTF8)
+ {
+ ConvertUTF8ToUnicode(src, dest);
+ return;
+ }
+
+ const size_t limit = ((size_t)src.Len() + 1) * 2;
+ wchar_t *d = dest.GetBuf((unsigned)limit);
+ const size_t len = mbstowcs(d, src, limit);
+ if (len != (size_t)-1)
+ {
+ dest.ReleaseBuf_SetEnd((unsigned)len);
+
+ #if WCHAR_MAX > 0xffff
+ d = dest.GetBuf();
+ for (size_t i = 0;; i++)
+ {
+ // wchar_t c = dest[i];
+ wchar_t c = d[i];
+ if (c == 0)
+ break;
+ if (c >= 0x10000 && c < 0x110000)
+ {
+ /*
+ c -= 0x10000;
+ unsigned c0 = 0xd800 + ((c >> 10) & 0x3FF);
+ dest.ReplaceOneCharAtPos(i, c0);
+ i++;
+ c = 0xdc00 + (c & 0x3FF);
+ dest.Insert_wchar_t(i, c);
+ */
+ UString temp = d + i;
+
+ for (size_t t = 0;; t++)
+ {
+ wchar_t w = temp[t];
+ if (w == 0)
+ break;
+ if (i == limit)
+ break; // unexpected error
+ if (w >= 0x10000 && w < 0x110000)
+ {
+ if (i + 1 == limit)
+ break; // unexpected error
+ w -= 0x10000;
+ d[i++] = (unsigned)0xd800 + (((unsigned)w >> 10) & 0x3FF);
+ w = 0xdc00 + (w & 0x3FF);
+ }
+ d[i++] = w;
+ }
+ dest.ReleaseBuf_SetEnd((unsigned)i);
+ }
+ }
+
+ #endif
+
+ /*
+ printf("\nMultiByteToUnicodeString2 (%d) %s\n", (int)src.Len(), src.Ptr());
+ printf("char: ");
+ for (unsigned i = 0; i < src.Len(); i++)
+ printf (" %02x", (int)(Byte)src[i]);
+ printf("\n");
+ printf("\n-> (%d) %ls\n", (int)dest.Len(), dest.Ptr());
+ printf("wchar_t: ");
+ for (unsigned i = 0; i < dest.Len(); i++)
+ {
+ printf (" %02x", (int)dest[i]);
+ }
+ printf("\n");
+ */
+
+ return;
+ }
+
+ /* if there is mbstowcs() error, we have two ways:
+
+ 1) change 0x80+ characters to some character: '_'
+ in that case we lose data, but we have correct UString()
+ and that scheme can show errors to user in early stages,
+ when file converted back to mbs() cannot be found
+
+ 2) transfer bad characters in some UTF-16 range.
+ it can be non-original Unicode character.
+ but later we still can restore original character.
+ */
+
+
+ // printf("\nmbstowcs ERROR !!!!!! s=%s\n", src.Ptr());
+ {
+ unsigned i;
+ const char *s = (const char *)src;
+ for (i = 0;;)
+ {
+ Byte c = (Byte)s[i];
+ if (c == 0)
+ break;
+ // we can use ascii compatibilty character '_'
+ // if (c > 0x7F) c = '_'; // we replace "bad: character
+ d[i++] = (wchar_t)c;
+ }
+ d[i] = 0;
+ dest.ReleaseBuf_SetLen(i);
+ }
+}
+
+static void UnicodeStringToMultiByte2_Native(AString &dest, const UString &src)
+{
+ dest.Empty();
+ if (src.IsEmpty())
+ return;
+
+ const size_t limit = ((size_t)src.Len() + 1) * 6;
+ char *d = dest.GetBuf((unsigned)limit);
+
+ const size_t len = wcstombs(d, src, limit);
+
+ if (len != (size_t)-1)
+ {
+ dest.ReleaseBuf_SetEnd((unsigned)len);
+ return;
+ }
+ dest.ReleaseBuf_SetEnd(0);
+}
+
+
+static void UnicodeStringToMultiByte2(AString &dest, const UString &src2, UINT codePage, char defaultChar, bool &defaultCharWasUsed)
+{
+ // if (codePage == 1234567) // for debug purposes
+ if (codePage == CP_UTF8 || g_ForceToUTF8)
+ {
+ defaultCharWasUsed = false;
+ ConvertUnicodeToUTF8(src2, dest);
+ return;
+ }
+
+ UString src = src2;
+ #if WCHAR_MAX > 0xffff
+ {
+ src.Empty();
+ for (unsigned i = 0; i < src2.Len();)
+ {
+ wchar_t c = src2[i];
+ if (c >= 0xd800 && c < 0xdc00 && i + 1 != src2.Len())
+ {
+ const wchar_t c2 = src2[i + 1];
+ if (c2 >= 0xdc00 && c2 < 0x10000)
+ {
+ // printf("\nSurragate [%d]: %4x %4x -> ", i, (int)c, (int)c2);
+ c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff);
+ // printf("%4x\n", (int)c);
+ i++;
+ }
+ }
+ src += c;
+ i++;
+ }
+ }
+ #endif
+
+ dest.Empty();
+ defaultCharWasUsed = false;
+ if (src.IsEmpty())
+ return;
+
+ const size_t len = wcstombs(NULL, src, 0);
+
+ if (len != (size_t)-1)
+ {
+ const unsigned limit = ((unsigned)len);
+ if (limit == len)
+ {
+ char *d = dest.GetBuf(limit);
+
+ /*
+ {
+ printf("\nwcstombs; len = %d %ls \n", (int)src.Len(), src.Ptr());
+ for (unsigned i = 0; i < src.Len(); i++)
+ printf (" %02x", (int)src[i]);
+ printf("\n");
+ printf("\ndest Limit = %d \n", limit);
+ }
+ */
+
+ const size_t len2 = wcstombs(d, src, len + 1);
+
+ if (len2 != (size_t)-1 && len2 <= limit)
+ {
+ /*
+ printf("\nOK : destLen = %d : %s\n", (int)len, dest.Ptr());
+ for (unsigned i = 0; i < len2; i++)
+ printf(" %02x", (int)(Byte)dest[i]);
+ printf("\n");
+ */
+ dest.ReleaseBuf_SetEnd((unsigned)len2);
+ return;
+ }
+ }
+ }
+
+ {
+ const wchar_t *s = (const wchar_t *)src;
+ char *d = dest.GetBuf(src.Len());
+
+ unsigned i;
+ for (i = 0;;)
+ {
+ wchar_t c = s[i];
+ if (c == 0)
+ break;
+ if (c >=
+ 0x100
+ // 0x80
+ )
+ {
+ c = defaultChar;
+ defaultCharWasUsed = true;
+ }
+
+ d[i++] = (char)c;
+ }
+ d[i] = 0;
+ dest.ReleaseBuf_SetLen(i);
+ /*
+ printf("\nUnicodeStringToMultiByte2; len = %d \n", (int)src.Len());
+ printf("ERROR: %s\n", dest.Ptr());
+ */
+ }
+}
+
+#endif // _WIN32
+
+
+UString MultiByteToUnicodeString(const AString &src, UINT codePage)
+{
+ UString dest;
+ MultiByteToUnicodeString2(dest, src, codePage);
+ return dest;
+}
+
+UString MultiByteToUnicodeString(const char *src, UINT codePage)
+{
+ return MultiByteToUnicodeString(AString(src), codePage);
+}
+
+
+void UnicodeStringToMultiByte2(AString &dest, const UString &src, UINT codePage)
+{
+ bool defaultCharWasUsed;
+ UnicodeStringToMultiByte2(dest, src, codePage, k_DefultChar, defaultCharWasUsed);
+}
+
+AString UnicodeStringToMultiByte(const UString &src, UINT codePage, char defaultChar, bool &defaultCharWasUsed)
+{
+ AString dest;
+ UnicodeStringToMultiByte2(dest, src, codePage, defaultChar, defaultCharWasUsed);
+ return dest;
+}
+
+AString UnicodeStringToMultiByte(const UString &src, UINT codePage)
+{
+ AString dest;
+ bool defaultCharWasUsed;
+ UnicodeStringToMultiByte2(dest, src, codePage, k_DefultChar, defaultCharWasUsed);
+ return dest;
+}
+
+
+
+
+#if !defined(_WIN32) || defined(ENV_HAVE_LOCALE)
+
+#ifdef _WIN32
+#define U_to_A(a, b, c) UnicodeStringToMultiByte2
+// #define A_to_U(a, b, c) MultiByteToUnicodeString2
+#else
+// void MultiByteToUnicodeString2_Native(UString &dest, const AString &src);
+#define U_to_A(a, b, c) UnicodeStringToMultiByte2_Native(a, b)
+// #define A_to_U(a, b, c) MultiByteToUnicodeString2_Native(a, b)
+#endif
+
+bool IsNativeUTF8()
+{
+ UString u;
+ AString a, a2;
+ // for (unsigned c = 0x80; c < (UInt32)0x10000; c += (c >> 9) + 1)
+ for (unsigned c = 0x80; c < (UInt32)0xD000; c += (c >> 2) + 1)
+ {
+ u.Empty();
+ u += (wchar_t)c;
+ /*
+ if (Unicode_Is_There_Utf16SurrogateError(u))
+ continue;
+ #ifndef _WIN32
+ if (Unicode_Is_There_BmpEscape(u))
+ continue;
+ #endif
+ */
+ ConvertUnicodeToUTF8(u, a);
+ U_to_A(a2, u, CP_OEMCP);
+ if (a != a2)
+ return false;
+ }
+ return true;
+}
+
+#endif
+
+
+#ifdef ENV_HAVE_LOCALE
+
+const char *GetLocale(void)
+{
+ #ifdef ENV_HAVE_LOCALE
+ // printf("\n\nsetlocale(LC_CTYPE, NULL) : return : ");
+ const char *s = setlocale(LC_CTYPE, NULL);
+ if (!s)
+ {
+ // printf("[NULL]\n");
+ s = "C";
+ }
+ else
+ {
+ // ubuntu returns "C" after program start
+ // printf("\"%s\"\n", s);
+ }
+ return s;
+ #elif defined(LOCALE_IS_UTF8)
+ return "utf8";
+ #else
+ return "C";
+ #endif
+}
+
+#ifdef _WIN32
+ static void Set_ForceToUTF8(bool) {}
+#else
+ static void Set_ForceToUTF8(bool val) { g_ForceToUTF8 = val; }
+#endif
+
+static bool Is_Default_Basic_Locale(const char *locale)
+{
+ const AString a (locale);
+ if (a.IsEqualTo_Ascii_NoCase("")
+ || a.IsEqualTo_Ascii_NoCase("C")
+ || a.IsEqualTo_Ascii_NoCase("POSIX"))
+ return true;
+ return false;
+}
+
+static bool Is_Default_Basic_Locale()
+{
+ return Is_Default_Basic_Locale(GetLocale());
+}
+
+
+void MY_SetLocale()
+{
+ #ifdef ENV_HAVE_LOCALE
+ /*
+ {
+ const char *s = GetLocale();
+ printf("\nGetLocale() : returned : \"%s\"\n", s);
+ }
+ */
+
+ unsigned start = 0;
+ // unsigned lim = 0;
+ unsigned lim = 3;
+
+ /*
+ #define MY_SET_LOCALE_FLAGS__FROM_ENV 1
+ #define MY_SET_LOCALE_FLAGS__TRY_UTF8 2
+
+ unsigned flags =
+ MY_SET_LOCALE_FLAGS__FROM_ENV |
+ MY_SET_LOCALE_FLAGS__TRY_UTF8
+
+ if (flags != 0)
+ {
+ if (flags & MY_SET_LOCALE_FLAGS__FROM_ENV)
+ lim = (flags & MY_SET_LOCALE_FLAGS__TRY_UTF8) ? 3 : 1;
+ else
+ {
+ start = 1;
+ lim = 2;
+ }
+ }
+ */
+
+ for (unsigned i = start; i < lim; i++)
+ {
+ /*
+ man7: "If locale is an empty string, "", each part of the locale that
+ should be modified is set according to the environment variables.
+ for glibc: glibc, first from the user's environment variables:
+ 1) the environment variable LC_ALL,
+ 2) environment variable with the same name as the category (see the
+ 3) the environment variable LANG
+ The locale "C" or "POSIX" is a portable locale; it exists on all conforming systems.
+
+ for WIN32 : MSDN :
+ Sets the locale to the default, which is the user-default
+ ANSI code page obtained from the operating system.
+ The locale name is set to the value returned by GetUserDefaultLocaleName.
+ The code page is set to the value returned by GetACP
+ */
+ const char *newLocale = "";
+
+ #ifdef __APPLE__
+
+ /* look also CFLocale
+ there is no C.UTF-8 in macos
+ macos has UTF-8 locale only with some language like en_US.UTF-8
+ what is best way to set UTF-8 locale in macos? */
+ if (i == 1)
+ newLocale = "en_US.UTF-8";
+
+ /* file open with non-utf8 sequencies return
+ #define EILSEQ 92 // "Illegal byte sequence"
+ */
+#else
+ // newLocale = "C";
+ if (i == 1)
+ {
+ newLocale = "C.UTF-8"; // main UTF-8 locale in ubuntu
+ // newLocale = ".utf8"; // supported in new Windows 10 build 17134 (April 2018 Update), the Universal C Runtime
+ // newLocale = "en_US.utf8"; // supported by ubuntu ?
+ // newLocale = "en_US.UTF-8";
+ /* setlocale() in ubuntu allows locales with minor chracter changes in strings
+ "en_US.UTF-8" / "en_US.utf8" */
+ }
+
+#endif
+
+ // printf("\nsetlocale(LC_ALL, \"%s\") : returned: ", newLocale);
+
+ // const char *s =
+ setlocale(LC_ALL, newLocale);
+
+ /*
+ if (!s)
+ printf("NULL: can't set locale");
+ else
+ printf("\"%s\"\n", s);
+ */
+
+ // request curent locale of program
+ const char *locale = GetLocale();
+ if (locale)
+ {
+ AString a (locale);
+ a.MakeLower_Ascii();
+ // if (a.Find("utf") >= 0)
+ {
+ if (IsNativeUTF8())
+ {
+ Set_ForceToUTF8(true);
+ return;
+ }
+ }
+ if (!Is_Default_Basic_Locale(locale))
+ {
+ // if there is some non-default and non-utf locale, we want to use it
+ break; // comment it for debug
+ }
+ }
+ }
+
+ if (IsNativeUTF8())
+ {
+ Set_ForceToUTF8(true);
+ return;
+ }
+
+ if (Is_Default_Basic_Locale())
+ {
+ Set_ForceToUTF8(true);
+ return;
+ }
+
+ Set_ForceToUTF8(false);
+
+ #elif defined(LOCALE_IS_UTF8)
+ // assume LC_CTYPE="utf8"
+ #else
+ // assume LC_CTYPE="C"
+ #endif
+}
+#endif
diff --git a/CPP/Common/StringConvert.h b/CPP/Common/StringConvert.h
index 05a2155..2092a2d 100644
--- a/CPP/Common/StringConvert.h
+++ b/CPP/Common/StringConvert.h
@@ -1,88 +1,110 @@
-// Common/StringConvert.h
-
-#ifndef __COMMON_STRING_CONVERT_H
-#define __COMMON_STRING_CONVERT_H
-
-#include "MyString.h"
-#include "MyWindows.h"
-
-UString MultiByteToUnicodeString(const AString &src, UINT codePage = CP_ACP);
-UString MultiByteToUnicodeString(const char *src, UINT codePage = CP_ACP);
-
-// optimized versions that work faster for ASCII strings
-void MultiByteToUnicodeString2(UString &dest, const AString &src, UINT codePage = CP_ACP);
-// void UnicodeStringToMultiByte2(AString &dest, const UString &s, UINT codePage, char defaultChar, bool &defaultCharWasUsed);
-void UnicodeStringToMultiByte2(AString &dest, const UString &src, UINT codePage);
-
-AString UnicodeStringToMultiByte(const UString &src, UINT codePage, char defaultChar, bool &defaultCharWasUsed);
-AString UnicodeStringToMultiByte(const UString &src, UINT codePage = CP_ACP);
-
-inline const wchar_t* GetUnicodeString(const wchar_t *u) { return u; }
-inline const UString& GetUnicodeString(const UString &u) { return u; }
-
-inline UString GetUnicodeString(const AString &a) { return MultiByteToUnicodeString(a); }
-inline UString GetUnicodeString(const char *a) { return MultiByteToUnicodeString(a); }
-
-inline UString GetUnicodeString(const AString &a, UINT codePage)
- { return MultiByteToUnicodeString(a, codePage); }
-inline UString GetUnicodeString(const char *a, UINT codePage)
- { return MultiByteToUnicodeString(a, codePage); }
-
-inline const wchar_t* GetUnicodeString(const wchar_t *u, UINT) { return u; }
-inline const UString& GetUnicodeString(const UString &u, UINT) { return u; }
-
-inline const char* GetAnsiString(const char *a) { return a; }
-inline const AString& GetAnsiString(const AString &a) { return a; }
-
-inline AString GetAnsiString(const wchar_t *u) { return UnicodeStringToMultiByte(UString(u)); }
-inline AString GetAnsiString(const UString &u) { return UnicodeStringToMultiByte(u); }
-
-/*
-inline const char* GetOemString(const char* oem)
- { return oem; }
-inline const AString& GetOemString(const AString &oem)
- { return oem; }
-*/
-const char* GetOemString(const char* oem);
-const AString& GetOemString(const AString &oem);
-inline AString GetOemString(const UString &u)
- { return UnicodeStringToMultiByte(u, CP_OEMCP); }
-
-#ifdef _UNICODE
- inline const wchar_t* GetSystemString(const wchar_t *u) { return u;}
- inline const UString& GetSystemString(const UString &u) { return u;}
- inline const wchar_t* GetSystemString(const wchar_t *u, UINT /* codePage */) { return u;}
- inline const UString& GetSystemString(const UString &u, UINT /* codePage */) { return u;}
-
- inline UString GetSystemString(const AString &a, UINT codePage) { return MultiByteToUnicodeString(a, codePage); }
- inline UString GetSystemString(const char *a, UINT codePage) { return MultiByteToUnicodeString(a, codePage); }
- inline UString GetSystemString(const AString &a) { return MultiByteToUnicodeString(a); }
- inline UString GetSystemString(const char *a) { return MultiByteToUnicodeString(a); }
-#else
- inline const char* GetSystemString(const char *a) { return a; }
- inline const AString& GetSystemString(const AString &a) { return a; }
- inline const char* GetSystemString(const char *a, UINT) { return a; }
- inline const AString& GetSystemString(const AString &a, UINT) { return a; }
-
- inline AString GetSystemString(const wchar_t *u) { return UnicodeStringToMultiByte(UString(u)); }
- inline AString GetSystemString(const UString &u) { return UnicodeStringToMultiByte(u); }
- inline AString GetSystemString(const UString &u, UINT codePage) { return UnicodeStringToMultiByte(u, codePage); }
-
-
-
- /*
- inline AString GetSystemString(const wchar_t *u)
- {
- UString s;
- s = u;
- return UnicodeStringToMultiByte(s);
- }
- */
-
-#endif
-
-#ifndef UNDER_CE
-AString SystemStringToOemString(const CSysString &src);
-#endif
-
-#endif
+// Common/StringConvert.h
+
+#ifndef ZIP7_INC_COMMON_STRING_CONVERT_H
+#define ZIP7_INC_COMMON_STRING_CONVERT_H
+
+#include "MyString.h"
+#include "MyWindows.h"
+
+UString MultiByteToUnicodeString(const AString &src, UINT codePage = CP_ACP);
+UString MultiByteToUnicodeString(const char *src, UINT codePage = CP_ACP);
+
+// optimized versions that work faster for ASCII strings
+void MultiByteToUnicodeString2(UString &dest, const AString &src, UINT codePage = CP_ACP);
+// void UnicodeStringToMultiByte2(AString &dest, const UString &s, UINT codePage, char defaultChar, bool &defaultCharWasUsed);
+void UnicodeStringToMultiByte2(AString &dest, const UString &src, UINT codePage);
+
+AString UnicodeStringToMultiByte(const UString &src, UINT codePage, char defaultChar, bool &defaultCharWasUsed);
+AString UnicodeStringToMultiByte(const UString &src, UINT codePage = CP_ACP);
+
+inline const wchar_t* GetUnicodeString(const wchar_t *u) { return u; }
+inline const UString& GetUnicodeString(const UString &u) { return u; }
+
+inline UString GetUnicodeString(const AString &a) { return MultiByteToUnicodeString(a); }
+inline UString GetUnicodeString(const char *a) { return MultiByteToUnicodeString(a); }
+
+inline UString GetUnicodeString(const AString &a, UINT codePage)
+ { return MultiByteToUnicodeString(a, codePage); }
+inline UString GetUnicodeString(const char *a, UINT codePage)
+ { return MultiByteToUnicodeString(a, codePage); }
+
+inline const wchar_t* GetUnicodeString(const wchar_t *u, UINT) { return u; }
+inline const UString& GetUnicodeString(const UString &u, UINT) { return u; }
+
+inline const char* GetAnsiString(const char *a) { return a; }
+inline const AString& GetAnsiString(const AString &a) { return a; }
+
+inline AString GetAnsiString(const wchar_t *u) { return UnicodeStringToMultiByte(UString(u)); }
+inline AString GetAnsiString(const UString &u) { return UnicodeStringToMultiByte(u); }
+
+/*
+inline const char* GetOemString(const char* oem)
+ { return oem; }
+inline const AString& GetOemString(const AString &oem)
+ { return oem; }
+*/
+const char* GetOemString(const char* oem);
+const AString& GetOemString(const AString &oem);
+inline AString GetOemString(const UString &u)
+ { return UnicodeStringToMultiByte(u, CP_OEMCP); }
+
+#ifdef _UNICODE
+ inline const wchar_t* GetSystemString(const wchar_t *u) { return u;}
+ inline const UString& GetSystemString(const UString &u) { return u;}
+ inline const wchar_t* GetSystemString(const wchar_t *u, UINT /* codePage */) { return u;}
+ inline const UString& GetSystemString(const UString &u, UINT /* codePage */) { return u;}
+
+ inline UString GetSystemString(const AString &a, UINT codePage) { return MultiByteToUnicodeString(a, codePage); }
+ inline UString GetSystemString(const char *a, UINT codePage) { return MultiByteToUnicodeString(a, codePage); }
+ inline UString GetSystemString(const AString &a) { return MultiByteToUnicodeString(a); }
+ inline UString GetSystemString(const char *a) { return MultiByteToUnicodeString(a); }
+#else
+ inline const char* GetSystemString(const char *a) { return a; }
+ inline const AString& GetSystemString(const AString &a) { return a; }
+ inline const char* GetSystemString(const char *a, UINT) { return a; }
+ inline const AString& GetSystemString(const AString &a, UINT) { return a; }
+
+ inline AString GetSystemString(const wchar_t *u) { return UnicodeStringToMultiByte(UString(u)); }
+ inline AString GetSystemString(const UString &u) { return UnicodeStringToMultiByte(u); }
+ inline AString GetSystemString(const UString &u, UINT codePage) { return UnicodeStringToMultiByte(u, codePage); }
+
+
+
+ /*
+ inline AString GetSystemString(const wchar_t *u)
+ {
+ UString s;
+ s = u;
+ return UnicodeStringToMultiByte(s);
+ }
+ */
+
+#endif
+
+#ifndef UNDER_CE
+AString SystemStringToOemString(const CSysString &src);
+#endif
+
+
+#ifdef _WIN32
+/* we don't need locale functions in Windows
+ but we can define ENV_HAVE_LOCALE here for debug purposes */
+// #define ENV_HAVE_LOCALE
+#else
+#define ENV_HAVE_LOCALE
+#endif
+
+#ifdef ENV_HAVE_LOCALE
+void MY_SetLocale();
+const char *GetLocale(void);
+#endif
+
+#if !defined(_WIN32) || defined(ENV_HAVE_LOCALE)
+bool IsNativeUTF8();
+#endif
+
+#ifndef _WIN32
+extern bool g_ForceToUTF8;
+#endif
+
+#endif
diff --git a/CPP/Common/StringToInt.cpp b/CPP/Common/StringToInt.cpp
index 295816e..bc4926e 100644
--- a/CPP/Common/StringToInt.cpp
+++ b/CPP/Common/StringToInt.cpp
@@ -1,144 +1,171 @@
-// Common/StringToInt.cpp
-
-#include "StdAfx.h"
-
-#include "StringToInt.h"
-
-static const UInt32 k_UInt32_max = 0xFFFFFFFF;
-static const UInt64 k_UInt64_max = UINT64_CONST(0xFFFFFFFFFFFFFFFF);
-// static const UInt64 k_UInt64_max = (UInt64)(Int64)-1;
-
-#define CONVERT_STRING_TO_UINT_FUNC(uintType, charType, charTypeUnsigned) \
- uintType ConvertStringTo ## uintType(const charType *s, const charType **end) throw() { \
- if (end) *end = s; \
- uintType res = 0; \
- for (;; s++) { \
- charTypeUnsigned c = (charTypeUnsigned)*s; \
- if (c < '0' || c > '9') { if (end) *end = s; return res; } \
- if (res > (k_ ## uintType ## _max) / 10) return 0; \
- res *= 10; \
- unsigned v = (c - '0'); \
- if (res > (k_ ## uintType ## _max) - v) return 0; \
- res += v; }}
-
-CONVERT_STRING_TO_UINT_FUNC(UInt32, char, Byte)
-CONVERT_STRING_TO_UINT_FUNC(UInt32, wchar_t, wchar_t)
-CONVERT_STRING_TO_UINT_FUNC(UInt64, char, Byte)
-CONVERT_STRING_TO_UINT_FUNC(UInt64, wchar_t, wchar_t)
-
-Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw()
-{
- if (end)
- *end = s;
- const wchar_t *s2 = s;
- if (*s == '-')
- s2++;
- if (*s2 == 0)
- return 0;
- const wchar_t *end2;
- UInt32 res = ConvertStringToUInt32(s2, &end2);
- if (*s == '-')
- {
- if (res > ((UInt32)1 << (32 - 1)))
- return 0;
- }
- else if ((res & ((UInt32)1 << (32 - 1))) != 0)
- return 0;
- if (end)
- *end = end2;
- if (*s == '-')
- return -(Int32)res;
- return (Int32)res;
-}
-
-UInt32 ConvertOctStringToUInt32(const char *s, const char **end) throw()
-{
- if (end)
- *end = s;
- UInt32 res = 0;
- for (;; s++)
- {
- unsigned c = (unsigned char)*s;
- if (c < '0' || c > '7')
- {
- if (end)
- *end = s;
- return res;
- }
- if ((res & (UInt32)7 << (32 - 3)) != 0)
- return 0;
- res <<= 3;
- res |= (unsigned)(c - '0');
- }
-}
-
-UInt64 ConvertOctStringToUInt64(const char *s, const char **end) throw()
-{
- if (end)
- *end = s;
- UInt64 res = 0;
- for (;; s++)
- {
- unsigned c = (unsigned char)*s;
- if (c < '0' || c > '7')
- {
- if (end)
- *end = s;
- return res;
- }
- if ((res & (UInt64)7 << (64 - 3)) != 0)
- return 0;
- res <<= 3;
- res |= (unsigned)(c - '0');
- }
-}
-
-UInt32 ConvertHexStringToUInt32(const char *s, const char **end) throw()
-{
- if (end)
- *end = s;
- UInt32 res = 0;
- for (;; s++)
- {
- unsigned c = (Byte)*s;
- unsigned v;
- if (c >= '0' && c <= '9') v = (c - '0');
- else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A');
- else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a');
- else
- {
- if (end)
- *end = s;
- return res;
- }
- if ((res & (UInt32)0xF << (32 - 4)) != 0)
- return 0;
- res <<= 4;
- res |= v;
- }
-}
-
-UInt64 ConvertHexStringToUInt64(const char *s, const char **end) throw()
-{
- if (end)
- *end = s;
- UInt64 res = 0;
- for (;; s++)
- {
- unsigned c = (Byte)*s;
- unsigned v;
- if (c >= '0' && c <= '9') v = (c - '0');
- else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A');
- else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a');
- else
- {
- if (end)
- *end = s;
- return res;
- }
- if ((res & (UInt64)0xF << (64 - 4)) != 0)
- return 0;
- res <<= 4;
- res |= v;
- }
-}
+// Common/StringToInt.cpp
+
+#include "StdAfx.h"
+
+#include "StringToInt.h"
+
+static const UInt32 k_UInt32_max = 0xFFFFFFFF;
+static const UInt64 k_UInt64_max = UINT64_CONST(0xFFFFFFFFFFFFFFFF);
+// static const UInt64 k_UInt64_max = (UInt64)(Int64)-1;
+
+#define CONVERT_STRING_TO_UINT_FUNC(uintType, charType, charTypeUnsigned) \
+ uintType ConvertStringTo ## uintType(const charType *s, const charType **end) throw() { \
+ if (end) *end = s; \
+ uintType res = 0; \
+ for (;; s++) { \
+ charTypeUnsigned c = (charTypeUnsigned)*s; \
+ if (c < '0' || c > '9') { if (end) *end = s; return res; } \
+ if (res > (k_ ## uintType ## _max) / 10) return 0; \
+ res *= 10; \
+ unsigned v = (unsigned)(c - '0'); \
+ if (res > (k_ ## uintType ## _max) - v) return 0; \
+ res += v; }}
+
+CONVERT_STRING_TO_UINT_FUNC(UInt32, char, Byte)
+CONVERT_STRING_TO_UINT_FUNC(UInt32, wchar_t, wchar_t)
+CONVERT_STRING_TO_UINT_FUNC(UInt64, char, Byte)
+CONVERT_STRING_TO_UINT_FUNC(UInt64, wchar_t, wchar_t)
+
+/*
+Int32 ConvertStringToInt32(const char *s, const char **end) throw()
+{
+ if (end)
+ *end = s;
+ const char *s2 = s;
+ if (*s == '-')
+ s2++;
+ if (*s2 == 0)
+ return 0;
+ const char *end2;
+ UInt32 res = ConvertStringToUInt32(s2, &end2);
+ if (*s == '-')
+ {
+ if (res > ((UInt32)1 << (32 - 1)))
+ return 0;
+ }
+ else if ((res & ((UInt32)1 << (32 - 1))) != 0)
+ return 0;
+ if (end)
+ *end = end2;
+ if (*s == '-')
+ return -(Int32)res;
+ return (Int32)res;
+}
+*/
+
+Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw()
+{
+ if (end)
+ *end = s;
+ const wchar_t *s2 = s;
+ if (*s == '-')
+ s2++;
+ if (*s2 == 0)
+ return 0;
+ const wchar_t *end2;
+ UInt32 res = ConvertStringToUInt32(s2, &end2);
+ if (*s == '-')
+ {
+ if (res > ((UInt32)1 << (32 - 1)))
+ return 0;
+ }
+ else if ((res & ((UInt32)1 << (32 - 1))) != 0)
+ return 0;
+ if (end)
+ *end = end2;
+ if (*s == '-')
+ return -(Int32)res;
+ return (Int32)res;
+}
+
+UInt32 ConvertOctStringToUInt32(const char *s, const char **end) throw()
+{
+ if (end)
+ *end = s;
+ UInt32 res = 0;
+ for (;; s++)
+ {
+ unsigned c = (unsigned char)*s;
+ if (c < '0' || c > '7')
+ {
+ if (end)
+ *end = s;
+ return res;
+ }
+ if ((res & (UInt32)7 << (32 - 3)) != 0)
+ return 0;
+ res <<= 3;
+ res |= (unsigned)(c - '0');
+ }
+}
+
+UInt64 ConvertOctStringToUInt64(const char *s, const char **end) throw()
+{
+ if (end)
+ *end = s;
+ UInt64 res = 0;
+ for (;; s++)
+ {
+ unsigned c = (unsigned char)*s;
+ if (c < '0' || c > '7')
+ {
+ if (end)
+ *end = s;
+ return res;
+ }
+ if ((res & (UInt64)7 << (64 - 3)) != 0)
+ return 0;
+ res <<= 3;
+ res |= (unsigned)(c - '0');
+ }
+}
+
+UInt32 ConvertHexStringToUInt32(const char *s, const char **end) throw()
+{
+ if (end)
+ *end = s;
+ UInt32 res = 0;
+ for (;; s++)
+ {
+ unsigned c = (Byte)*s;
+ unsigned v;
+ if (c >= '0' && c <= '9') v = (c - '0');
+ else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A');
+ else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a');
+ else
+ {
+ if (end)
+ *end = s;
+ return res;
+ }
+ if ((res & (UInt32)0xF << (32 - 4)) != 0)
+ return 0;
+ res <<= 4;
+ res |= v;
+ }
+}
+
+UInt64 ConvertHexStringToUInt64(const char *s, const char **end) throw()
+{
+ if (end)
+ *end = s;
+ UInt64 res = 0;
+ for (;; s++)
+ {
+ unsigned c = (Byte)*s;
+ unsigned v;
+ if (c >= '0' && c <= '9') v = (c - '0');
+ else if (c >= 'A' && c <= 'F') v = 10 + (c - 'A');
+ else if (c >= 'a' && c <= 'f') v = 10 + (c - 'a');
+ else
+ {
+ if (end)
+ *end = s;
+ return res;
+ }
+ if ((res & (UInt64)0xF << (64 - 4)) != 0)
+ return 0;
+ res <<= 4;
+ res |= v;
+ }
+}
diff --git a/CPP/Common/StringToInt.h b/CPP/Common/StringToInt.h
index 140d1ee..c9dce7d 100644
--- a/CPP/Common/StringToInt.h
+++ b/CPP/Common/StringToInt.h
@@ -1,21 +1,22 @@
-// Common/StringToInt.h
-
-#ifndef __COMMON_STRING_TO_INT_H
-#define __COMMON_STRING_TO_INT_H
-
-#include "MyTypes.h"
-
-UInt32 ConvertStringToUInt32(const char *s, const char **end) throw();
-UInt64 ConvertStringToUInt64(const char *s, const char **end) throw();
-UInt32 ConvertStringToUInt32(const wchar_t *s, const wchar_t **end) throw();
-UInt64 ConvertStringToUInt64(const wchar_t *s, const wchar_t **end) throw();
-
-Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw();
-
-UInt32 ConvertOctStringToUInt32(const char *s, const char **end) throw();
-UInt64 ConvertOctStringToUInt64(const char *s, const char **end) throw();
-
-UInt32 ConvertHexStringToUInt32(const char *s, const char **end) throw();
-UInt64 ConvertHexStringToUInt64(const char *s, const char **end) throw();
-
-#endif
+// Common/StringToInt.h
+
+#ifndef ZIP7_INC_COMMON_STRING_TO_INT_H
+#define ZIP7_INC_COMMON_STRING_TO_INT_H
+
+#include "MyTypes.h"
+
+UInt32 ConvertStringToUInt32(const char *s, const char **end) throw();
+UInt64 ConvertStringToUInt64(const char *s, const char **end) throw();
+UInt32 ConvertStringToUInt32(const wchar_t *s, const wchar_t **end) throw();
+UInt64 ConvertStringToUInt64(const wchar_t *s, const wchar_t **end) throw();
+
+// Int32 ConvertStringToInt32(const char *s, const char **end) throw();
+Int32 ConvertStringToInt32(const wchar_t *s, const wchar_t **end) throw();
+
+UInt32 ConvertOctStringToUInt32(const char *s, const char **end) throw();
+UInt64 ConvertOctStringToUInt64(const char *s, const char **end) throw();
+
+UInt32 ConvertHexStringToUInt32(const char *s, const char **end) throw();
+UInt64 ConvertHexStringToUInt64(const char *s, const char **end) throw();
+
+#endif
diff --git a/CPP/Common/TextConfig.cpp b/CPP/Common/TextConfig.cpp
index f54aa3f..d3e561c 100644
--- a/CPP/Common/TextConfig.cpp
+++ b/CPP/Common/TextConfig.cpp
@@ -1,124 +1,124 @@
-// Common/TextConfig.cpp
-
-#include "StdAfx.h"
-
-#include "TextConfig.h"
-#include "UTFConvert.h"
-
-static inline bool IsDelimitChar(char c)
-{
- return (c == ' ' || c == 0x0A || c == 0x0D || c == '\0' || c == '\t');
-}
-
-static AString GetIDString(const char *s, unsigned &finishPos)
-{
- AString result;
- for (finishPos = 0; ; finishPos++)
- {
- char c = s[finishPos];
- if (IsDelimitChar(c) || c == '=')
- break;
- result += c;
- }
- return result;
-}
-
-static bool WaitNextLine(const AString &s, unsigned &pos)
-{
- for (; pos < s.Len(); pos++)
- if (s[pos] == 0x0A)
- return true;
- return false;
-}
-
-static bool SkipSpaces(const AString &s, unsigned &pos)
-{
- for (; pos < s.Len(); pos++)
- {
- char c = s[pos];
- if (!IsDelimitChar(c))
- {
- if (c != ';')
- return true;
- if (!WaitNextLine(s, pos))
- return false;
- }
- }
- return false;
-}
-
-bool GetTextConfig(const AString &s, CObjectVector<CTextConfigPair> &pairs)
-{
- pairs.Clear();
- unsigned pos = 0;
-
- /////////////////////
- // read strings
-
- for (;;)
- {
- if (!SkipSpaces(s, pos))
- break;
- CTextConfigPair pair;
- unsigned finishPos;
- const AString temp (GetIDString(((const char *)s) + pos, finishPos));
- if (!ConvertUTF8ToUnicode(temp, pair.ID))
- return false;
- if (finishPos == 0)
- return false;
- pos += finishPos;
- if (!SkipSpaces(s, pos))
- return false;
- if (s[pos] != '=')
- return false;
- pos++;
- if (!SkipSpaces(s, pos))
- return false;
- if (s[pos] != '\"')
- return false;
- pos++;
- AString message;
- for (;;)
- {
- if (pos >= s.Len())
- return false;
- char c = s[pos++];
- if (c == '\"')
- break;
- if (c == '\\')
- {
- c = s[pos++];
- switch (c)
- {
- case 'n': message += '\n'; break;
- case 't': message += '\t'; break;
- case '\\': message += '\\'; break;
- case '\"': message += '\"'; break;
- default: message += '\\'; message += c; break;
- }
- }
- else
- message += c;
- }
- if (!ConvertUTF8ToUnicode(message, pair.String))
- return false;
- pairs.Add(pair);
- }
- return true;
-}
-
-int FindTextConfigItem(const CObjectVector<CTextConfigPair> &pairs, const char *id) throw()
-{
- FOR_VECTOR (i, pairs)
- if (pairs[i].ID.IsEqualTo(id))
- return i;
- return -1;
-}
-
-UString GetTextConfigValue(const CObjectVector<CTextConfigPair> &pairs, const char *id)
-{
- int index = FindTextConfigItem(pairs, id);
- if (index < 0)
- return UString();
- return pairs[index].String;
-}
+// Common/TextConfig.cpp
+
+#include "StdAfx.h"
+
+#include "TextConfig.h"
+#include "UTFConvert.h"
+
+static inline bool IsDelimitChar(char c)
+{
+ return (c == ' ' || c == 0x0A || c == 0x0D || c == '\0' || c == '\t');
+}
+
+static AString GetIDString(const char *s, unsigned &finishPos)
+{
+ AString result;
+ for (finishPos = 0; ; finishPos++)
+ {
+ const char c = s[finishPos];
+ if (IsDelimitChar(c) || c == '=')
+ break;
+ result += c;
+ }
+ return result;
+}
+
+static bool WaitNextLine(const AString &s, unsigned &pos)
+{
+ for (; pos < s.Len(); pos++)
+ if (s[pos] == 0x0A)
+ return true;
+ return false;
+}
+
+static bool SkipSpaces(const AString &s, unsigned &pos)
+{
+ for (; pos < s.Len(); pos++)
+ {
+ const char c = s[pos];
+ if (!IsDelimitChar(c))
+ {
+ if (c != ';')
+ return true;
+ if (!WaitNextLine(s, pos))
+ return false;
+ }
+ }
+ return false;
+}
+
+bool GetTextConfig(const AString &s, CObjectVector<CTextConfigPair> &pairs)
+{
+ pairs.Clear();
+ unsigned pos = 0;
+
+ /////////////////////
+ // read strings
+
+ for (;;)
+ {
+ if (!SkipSpaces(s, pos))
+ break;
+ CTextConfigPair pair;
+ unsigned finishPos;
+ const AString temp (GetIDString(((const char *)s) + pos, finishPos));
+ if (!ConvertUTF8ToUnicode(temp, pair.ID))
+ return false;
+ if (finishPos == 0)
+ return false;
+ pos += finishPos;
+ if (!SkipSpaces(s, pos))
+ return false;
+ if (s[pos] != '=')
+ return false;
+ pos++;
+ if (!SkipSpaces(s, pos))
+ return false;
+ if (s[pos] != '\"')
+ return false;
+ pos++;
+ AString message;
+ for (;;)
+ {
+ if (pos >= s.Len())
+ return false;
+ char c = s[pos++];
+ if (c == '\"')
+ break;
+ if (c == '\\')
+ {
+ c = s[pos++];
+ switch (c)
+ {
+ case 'n': message += '\n'; break;
+ case 't': message += '\t'; break;
+ case '\\': message += '\\'; break;
+ case '\"': message += '\"'; break;
+ default: message += '\\'; message += c; break;
+ }
+ }
+ else
+ message += c;
+ }
+ if (!ConvertUTF8ToUnicode(message, pair.String))
+ return false;
+ pairs.Add(pair);
+ }
+ return true;
+}
+
+int FindTextConfigItem(const CObjectVector<CTextConfigPair> &pairs, const char *id) throw()
+{
+ FOR_VECTOR (i, pairs)
+ if (pairs[i].ID.IsEqualTo(id))
+ return (int)i;
+ return -1;
+}
+
+UString GetTextConfigValue(const CObjectVector<CTextConfigPair> &pairs, const char *id)
+{
+ const int index = FindTextConfigItem(pairs, id);
+ if (index < 0)
+ return UString();
+ return pairs[index].String;
+}
diff --git a/CPP/Common/TextConfig.h b/CPP/Common/TextConfig.h
index c39e363..2263a44 100644
--- a/CPP/Common/TextConfig.h
+++ b/CPP/Common/TextConfig.h
@@ -1,19 +1,19 @@
-// Common/TextConfig.h
-
-#ifndef __COMMON_TEXT_CONFIG_H
-#define __COMMON_TEXT_CONFIG_H
-
-#include "MyString.h"
-
-struct CTextConfigPair
-{
- UString ID;
- UString String;
-};
-
-bool GetTextConfig(const AString &text, CObjectVector<CTextConfigPair> &pairs);
-
-int FindTextConfigItem(const CObjectVector<CTextConfigPair> &pairs, const char *id) throw();
-UString GetTextConfigValue(const CObjectVector<CTextConfigPair> &pairs, const char *id);
-
-#endif
+// Common/TextConfig.h
+
+#ifndef ZIP7_INC_COMMON_TEXT_CONFIG_H
+#define ZIP7_INC_COMMON_TEXT_CONFIG_H
+
+#include "MyString.h"
+
+struct CTextConfigPair
+{
+ UString ID;
+ UString String;
+};
+
+bool GetTextConfig(const AString &text, CObjectVector<CTextConfigPair> &pairs);
+
+int FindTextConfigItem(const CObjectVector<CTextConfigPair> &pairs, const char *id) throw();
+UString GetTextConfigValue(const CObjectVector<CTextConfigPair> &pairs, const char *id);
+
+#endif
diff --git a/CPP/Common/UTFConvert.cpp b/CPP/Common/UTFConvert.cpp
index b09bbcd..fb166b7 100644
--- a/CPP/Common/UTFConvert.cpp
+++ b/CPP/Common/UTFConvert.cpp
@@ -1,288 +1,863 @@
-// UTFConvert.cpp
-
-#include "StdAfx.h"
-
-#include "MyTypes.h"
-#include "UTFConvert.h"
-
-#ifdef _WIN32
-#define _WCHART_IS_16BIT 1
-#endif
-
-/*
- _UTF8_START(n) - is a base value for start byte (head), if there are (n) additional bytes after start byte
-
- n : _UTF8_START(n) : Bits of code point
-
- 0 : 0x80 : : unused
- 1 : 0xC0 : 11 :
- 2 : 0xE0 : 16 : Basic Multilingual Plane
- 3 : 0xF0 : 21 : Unicode space
- 3 : 0xF8 : 26 :
- 5 : 0xFC : 31 : UCS-4
- 6 : 0xFE : 36 : We can use it, if we want to encode any 32-bit value
- 7 : 0xFF :
-*/
-
-#define _UTF8_START(n) (0x100 - (1 << (7 - (n))))
-
-#define _UTF8_HEAD_PARSE2(n) if (c < _UTF8_START((n) + 1)) { numBytes = (n); c -= _UTF8_START(n); }
-
-#define _UTF8_HEAD_PARSE \
- _UTF8_HEAD_PARSE2(1) \
- else _UTF8_HEAD_PARSE2(2) \
- else _UTF8_HEAD_PARSE2(3) \
- else _UTF8_HEAD_PARSE2(4) \
- else _UTF8_HEAD_PARSE2(5) \
-
- // else _UTF8_HEAD_PARSE2(6)
-
-bool CheckUTF8(const char *src, bool allowReduced) throw()
-{
- for (;;)
- {
- Byte c = *src++;
- if (c == 0)
- return true;
-
- if (c < 0x80)
- continue;
- if (c < 0xC0) // (c < 0xC0 + 2) // if we support only optimal encoding chars
- return false;
-
- unsigned numBytes;
- _UTF8_HEAD_PARSE
- else
- return false;
-
- UInt32 val = c;
-
- do
- {
- Byte c2 = *src++;
- if (c2 < 0x80 || c2 >= 0xC0)
- return allowReduced && c2 == 0;
- val <<= 6;
- val |= (c2 - 0x80);
- }
- while (--numBytes);
-
- if (val >= 0x110000)
- return false;
- }
-}
-
-
-#define _ERROR_UTF8 \
- { if (dest) dest[destPos] = (wchar_t)0xFFFD; destPos++; ok = false; continue; }
-
-static bool Utf8_To_Utf16(wchar_t *dest, size_t *destLen, const char *src, const char *srcLim) throw()
-{
- size_t destPos = 0;
- bool ok = true;
-
- for (;;)
- {
- Byte c;
- if (src == srcLim)
- {
- *destLen = destPos;
- return ok;
- }
- c = *src++;
-
- if (c < 0x80)
- {
- if (dest)
- dest[destPos] = (wchar_t)c;
- destPos++;
- continue;
- }
- if (c < 0xC0)
- _ERROR_UTF8
-
- unsigned numBytes;
- _UTF8_HEAD_PARSE
- else
- _ERROR_UTF8
-
- UInt32 val = c;
-
- do
- {
- Byte c2;
- if (src == srcLim)
- break;
- c2 = *src;
- if (c2 < 0x80 || c2 >= 0xC0)
- break;
- src++;
- val <<= 6;
- val |= (c2 - 0x80);
- }
- while (--numBytes);
-
- if (numBytes != 0)
- _ERROR_UTF8
-
- if (val < 0x10000)
- {
- if (dest)
- dest[destPos] = (wchar_t)val;
- destPos++;
- }
- else
- {
- val -= 0x10000;
- if (val >= 0x100000)
- _ERROR_UTF8
- if (dest)
- {
- dest[destPos + 0] = (wchar_t)(0xD800 + (val >> 10));
- dest[destPos + 1] = (wchar_t)(0xDC00 + (val & 0x3FF));
- }
- destPos += 2;
- }
- }
-}
-
-#define _UTF8_RANGE(n) (((UInt32)1) << ((n) * 5 + 6))
-
-#define _UTF8_HEAD(n, val) ((char)(_UTF8_START(n) + (val >> (6 * (n)))))
-#define _UTF8_CHAR(n, val) ((char)(0x80 + (((val) >> (6 * (n))) & 0x3F)))
-
-static size_t Utf16_To_Utf8_Calc(const wchar_t *src, const wchar_t *srcLim)
-{
- size_t size = srcLim - src;
- for (;;)
- {
- if (src == srcLim)
- return size;
-
- UInt32 val = *src++;
-
- if (val < 0x80)
- continue;
-
- if (val < _UTF8_RANGE(1))
- {
- size++;
- continue;
- }
-
- if (val >= 0xD800 && val < 0xDC00 && src != srcLim)
- {
- UInt32 c2 = *src;
- if (c2 >= 0xDC00 && c2 < 0xE000)
- {
- src++;
- size += 2;
- continue;
- }
- }
-
- #ifdef _WCHART_IS_16BIT
-
- size += 2;
-
- #else
-
- if (val < _UTF8_RANGE(2)) size += 2;
- else if (val < _UTF8_RANGE(3)) size += 3;
- else if (val < _UTF8_RANGE(4)) size += 4;
- else if (val < _UTF8_RANGE(5)) size += 5;
- else size += 6;
-
- #endif
- }
-}
-
-static char *Utf16_To_Utf8(char *dest, const wchar_t *src, const wchar_t *srcLim)
-{
- for (;;)
- {
- if (src == srcLim)
- return dest;
-
- UInt32 val = *src++;
-
- if (val < 0x80)
- {
- *dest++ = (char)val;
- continue;
- }
-
- if (val < _UTF8_RANGE(1))
- {
- dest[0] = _UTF8_HEAD(1, val);
- dest[1] = _UTF8_CHAR(0, val);
- dest += 2;
- continue;
- }
-
- if (val >= 0xD800 && val < 0xDC00 && src != srcLim)
- {
- UInt32 c2 = *src;
- if (c2 >= 0xDC00 && c2 < 0xE000)
- {
- src++;
- val = (((val - 0xD800) << 10) | (c2 - 0xDC00)) + 0x10000;
- dest[0] = _UTF8_HEAD(3, val);
- dest[1] = _UTF8_CHAR(2, val);
- dest[2] = _UTF8_CHAR(1, val);
- dest[3] = _UTF8_CHAR(0, val);
- dest += 4;
- continue;
- }
- }
-
- #ifndef _WCHART_IS_16BIT
- if (val < _UTF8_RANGE(2))
- #endif
- {
- dest[0] = _UTF8_HEAD(2, val);
- dest[1] = _UTF8_CHAR(1, val);
- dest[2] = _UTF8_CHAR(0, val);
- dest += 3;
- continue;
- }
-
- #ifndef _WCHART_IS_16BIT
-
- UInt32 b;
- unsigned numBits;
- if (val < _UTF8_RANGE(3)) { numBits = 6 * 3; b = _UTF8_HEAD(3, val); }
- else if (val < _UTF8_RANGE(4)) { numBits = 6 * 4; b = _UTF8_HEAD(4, val); }
- else if (val < _UTF8_RANGE(5)) { numBits = 6 * 5; b = _UTF8_HEAD(5, val); }
- else { numBits = 6 * 6; b = _UTF8_START(6); }
-
- *dest++ = (Byte)b;
-
- do
- {
- numBits -= 6;
- *dest++ = (char)(0x80 + ((val >> numBits) & 0x3F));
- }
- while (numBits != 0);
-
- #endif
- }
-}
-
-bool ConvertUTF8ToUnicode(const AString &src, UString &dest)
-{
- dest.Empty();
- size_t destLen = 0;
- Utf8_To_Utf16(NULL, &destLen, src, src.Ptr(src.Len()));
- bool res = Utf8_To_Utf16(dest.GetBuf((unsigned)destLen), &destLen, src, src.Ptr(src.Len()));
- dest.ReleaseBuf_SetEnd((unsigned)destLen);
- return res;
-}
-
-void ConvertUnicodeToUTF8(const UString &src, AString &dest)
-{
- dest.Empty();
- size_t destLen = Utf16_To_Utf8_Calc(src, src.Ptr(src.Len()));
- Utf16_To_Utf8(dest.GetBuf((unsigned)destLen), src, src.Ptr(src.Len()));
- dest.ReleaseBuf_SetEnd((unsigned)destLen);
-}
+// UTFConvert.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#include "MyTypes.h"
+#include "UTFConvert.h"
+
+
+#ifndef Z7_WCHART_IS_16BIT
+#ifndef __APPLE__
+ // we define it if the system supports files with non-utf8 symbols:
+ #define MY_UTF8_RAW_NON_UTF8_SUPPORTED
+#endif
+#endif
+
+/*
+ MY_UTF8_START(n) - is a base value for start byte (head), if there are (n) additional bytes after start byte
+
+ n : MY_UTF8_START(n) : Bits of code point
+
+ 0 : 0x80 : : unused
+ 1 : 0xC0 : 11 :
+ 2 : 0xE0 : 16 : Basic Multilingual Plane
+ 3 : 0xF0 : 21 : Unicode space
+ 4 : 0xF8 : 26 :
+ 5 : 0xFC : 31 : UCS-4 : wcstombs() in ubuntu is limited to that value
+ 6 : 0xFE : 36 : We can use it, if we want to encode any 32-bit value
+ 7 : 0xFF :
+*/
+
+#define MY_UTF8_START(n) (0x100 - (1 << (7 - (n))))
+
+#define MY_UTF8_HEAD_PARSE2(n) \
+ if (c < MY_UTF8_START((n) + 1)) \
+ { numBytes = (n); val -= MY_UTF8_START(n); }
+
+#ifndef Z7_WCHART_IS_16BIT
+
+/*
+ if (wchar_t is 32-bit), we can support large points in long UTF-8 sequence,
+ when we convert wchar_t strings to UTF-8:
+ (_UTF8_NUM_TAIL_BYTES_MAX == 3) : (21-bits points) - Unicode
+ (_UTF8_NUM_TAIL_BYTES_MAX == 5) : (31-bits points) - UCS-4
+ (_UTF8_NUM_TAIL_BYTES_MAX == 6) : (36-bit hack)
+*/
+
+#define MY_UTF8_NUM_TAIL_BYTES_MAX 5
+#endif
+
+/*
+#define MY_UTF8_HEAD_PARSE \
+ UInt32 val = c; \
+ MY_UTF8_HEAD_PARSE2(1) \
+ else MY_UTF8_HEAD_PARSE2(2) \
+ else MY_UTF8_HEAD_PARSE2(3) \
+ else MY_UTF8_HEAD_PARSE2(4) \
+ else MY_UTF8_HEAD_PARSE2(5) \
+ #if MY_UTF8_NUM_TAIL_BYTES_MAX >= 6
+ else MY_UTF8_HEAD_PARSE2(6)
+ #endif
+*/
+
+#define MY_UTF8_HEAD_PARSE_MAX_3_BYTES \
+ UInt32 val = c; \
+ MY_UTF8_HEAD_PARSE2(1) \
+ else MY_UTF8_HEAD_PARSE2(2) \
+ else { numBytes = 3; val -= MY_UTF8_START(3); }
+
+
+#define MY_UTF8_RANGE(n) (((UInt32)1) << ((n) * 5 + 6))
+
+
+#define START_POINT_FOR_SURROGATE 0x10000
+
+
+/* we use 128 bytes block in 16-bit BMP-PLANE to encode non-UTF-8 Escapes
+ Also we can use additional HIGH-PLANE (we use 21-bit points above 0x1f0000)
+ to simplify internal intermediate conversion in Linux:
+ RAW-UTF-8 <-> internal wchar_t utf-16 strings <-> RAW-UTF-UTF-8
+*/
+
+
+#if defined(Z7_WCHART_IS_16BIT)
+
+#define UTF_ESCAPE_PLANE 0
+
+#else
+
+/*
+we can place 128 ESCAPE chars to
+ ef 80 - ee be 80 (3-bytes utf-8) : similar to WSL
+ ef ff - ee bf bf
+
+1f ef 80 - f7 be be 80 (4-bytes utf-8) : last 4-bytes utf-8 plane (out of Unicode)
+1f ef ff - f7 be bf bf (4-bytes utf-8) : last 4-bytes utf-8 plane (out of Unicode)
+*/
+
+// #define UTF_ESCAPE_PLANE_HIGH (0x1f << 16)
+// #define UTF_ESCAPE_PLANE UTF_ESCAPE_PLANE_HIGH
+#define UTF_ESCAPE_PLANE 0
+
+/*
+ if (Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE is set)
+ {
+ if (UTF_ESCAPE_PLANE is UTF_ESCAPE_PLANE_HIGH)
+ {
+ we can restore any 8-bit Escape from ESCAPE-PLANE-21 plane.
+ But ESCAPE-PLANE-21 point cannot be stored to utf-16 (7z archive)
+ So we still need a way to extract 8-bit Escapes and BMP-Escapes-8
+ from same BMP-Escapes-16 stored in 7z.
+ And if we want to restore any 8-bit from 7z archive,
+ we still must use Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT for (utf-8 -> utf-16)
+ Also we need additional Conversions to tranform from utf-16 to utf-16-With-Escapes-21
+ }
+ else (UTF_ESCAPE_PLANE == 0)
+ {
+ we must convert original 3-bytes utf-8 BMP-Escape point to sequence
+ of 3 BMP-Escape-16 points with Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT
+ so we can extract original RAW-UTF-8 from UTFD-16 later.
+ }
+ }
+*/
+
+#endif
+
+
+
+#define UTF_ESCAPE_BASE 0xef00
+
+
+#ifdef UTF_ESCAPE_BASE
+#define IS_ESCAPE_POINT(v, plane) (((v) & (UInt32)0xffffff80) == (plane) + UTF_ESCAPE_BASE + 0x80)
+#endif
+
+#define IS_SURROGATE_POINT(v) (((v) & (UInt32)0xfffff800) == 0xd800)
+#define IS_LOW_SURROGATE_POINT(v) (((v) & (UInt32)0xfffffC00) == 0xdc00)
+
+
+#define UTF_ERROR_UTF8_CHECK \
+ { NonUtf = true; continue; }
+
+void CUtf8Check::Check_Buf(const char *src, size_t size) throw()
+{
+ Clear();
+ // Byte maxByte = 0;
+
+ for (;;)
+ {
+ if (size == 0)
+ break;
+
+ const Byte c = (Byte)(*src++);
+ size--;
+
+ if (c == 0)
+ {
+ ZeroChar = true;
+ continue;
+ }
+
+ /*
+ if (c > maxByte)
+ maxByte = c;
+ */
+
+ if (c < 0x80)
+ continue;
+
+ if (c < 0xc0 + 2) // it's limit for 0x140000 unicode codes : win32 compatibility
+ UTF_ERROR_UTF8_CHECK
+
+ unsigned numBytes;
+
+ UInt32 val = c;
+ MY_UTF8_HEAD_PARSE2(1)
+ else MY_UTF8_HEAD_PARSE2(2)
+ else MY_UTF8_HEAD_PARSE2(4)
+ else MY_UTF8_HEAD_PARSE2(5)
+ else
+ {
+ UTF_ERROR_UTF8_CHECK
+ }
+
+ unsigned pos = 0;
+ do
+ {
+ if (pos == size)
+ break;
+ unsigned c2 = (Byte)src[pos];
+ c2 -= 0x80;
+ if (c2 >= 0x40)
+ break;
+ val <<= 6;
+ val |= c2;
+ if (pos == 0)
+ if (val < (((unsigned)1 << 7) >> numBytes))
+ break;
+ pos++;
+ }
+ while (--numBytes);
+
+ if (numBytes != 0)
+ {
+ if (pos == size)
+ Truncated = true;
+ else
+ UTF_ERROR_UTF8_CHECK
+ }
+
+ #ifdef UTF_ESCAPE_BASE
+ if (IS_ESCAPE_POINT(val, 0))
+ Escape = true;
+ #endif
+
+ if (MaxHighPoint < val)
+ MaxHighPoint = val;
+
+ if (IS_SURROGATE_POINT(val))
+ SingleSurrogate = true;
+
+ src += pos;
+ size -= pos;
+ }
+
+ // MaxByte = maxByte;
+}
+
+bool Check_UTF8_Buf(const char *src, size_t size, bool allowReduced) throw()
+{
+ CUtf8Check check;
+ check.Check_Buf(src, size);
+ return check.IsOK(allowReduced);
+}
+
+/*
+bool CheckUTF8_chars(const char *src, bool allowReduced) throw()
+{
+ CUtf8Check check;
+ check.CheckBuf(src, strlen(src));
+ return check.IsOK(allowReduced);
+}
+*/
+
+bool CheckUTF8_AString(const AString &s) throw()
+{
+ CUtf8Check check;
+ check.Check_AString(s);
+ return check.IsOK();
+}
+
+
+/*
+bool CheckUTF8(const char *src, bool allowReduced) throw()
+{
+ // return Check_UTF8_Buf(src, strlen(src), allowReduced);
+
+ for (;;)
+ {
+ const Byte c = (Byte)(*src++);
+ if (c == 0)
+ return true;
+
+ if (c < 0x80)
+ continue;
+ if (c < 0xC0 + 2 || c >= 0xf5)
+ return false;
+
+ unsigned numBytes;
+ MY_UTF8_HEAD_PARSE
+ else
+ return false;
+
+ unsigned pos = 0;
+
+ do
+ {
+ Byte c2 = (Byte)(*src++);
+ if (c2 < 0x80 || c2 >= 0xC0)
+ return allowReduced && c2 == 0;
+ val <<= 6;
+ val |= (c2 - 0x80);
+ pos++;
+ }
+ while (--numBytes);
+
+ if (val < MY_UTF8_RANGE(pos - 1))
+ return false;
+
+ if (val >= 0x110000)
+ return false;
+ }
+}
+*/
+
+// in case of UTF-8 error we have two ways:
+// 21.01- : old : 0xfffd: REPLACEMENT CHARACTER : old version
+// 21.02+ : new : 0xef00 + (c) : similar to WSL scheme for low symbols
+
+#define UTF_REPLACEMENT_CHAR 0xfffd
+
+
+
+#define UTF_ESCAPE(c) \
+ ((flags & Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE) ? \
+ UTF_ESCAPE_PLANE + UTF_ESCAPE_BASE + (c) : UTF_REPLACEMENT_CHAR)
+
+/*
+#define UTF_HARD_ERROR_UTF8
+ { if (dest) dest[destPos] = (wchar_t)UTF_ESCAPE(c); \
+ destPos++; ok = false; continue; }
+*/
+
+// we ignore utf errors, and don't change (ok) variable!
+
+#define UTF_ERROR_UTF8 \
+ { if (dest) dest[destPos] = (wchar_t)UTF_ESCAPE(c); \
+ destPos++; continue; }
+
+// we store UTF-16 in wchar_t strings. So we use surrogates for big unicode points:
+
+// for debug puposes only we can store UTF-32 in wchar_t:
+// #define START_POINT_FOR_SURROGATE ((UInt32)0 - 1)
+
+
+/*
+ WIN32 MultiByteToWideChar(CP_UTF8) emits 0xfffd point, if utf-8 error was found.
+ Ant it can emit single 0xfffd from 2 src bytes.
+ It doesn't emit single 0xfffd from 3-4 src bytes.
+ We can
+ 1) emit Escape point for each incorrect byte. So we can data recover later
+ 2) emit 0xfffd for each incorrect byte.
+ That scheme is similar to Escape scheme, but we emit 0xfffd
+ instead of each Escape point.
+ 3) emit single 0xfffd from 1-2 incorrect bytes, as WIN32 MultiByteToWideChar scheme
+*/
+
+static bool Utf8_To_Utf16(wchar_t *dest, size_t *destLen, const char *src, const char *srcLim, unsigned flags) throw()
+{
+ size_t destPos = 0;
+ bool ok = true;
+
+ for (;;)
+ {
+ if (src == srcLim)
+ {
+ *destLen = destPos;
+ return ok;
+ }
+
+ const Byte c = (Byte)(*src++);
+
+ if (c < 0x80)
+ {
+ if (dest)
+ dest[destPos] = (wchar_t)c;
+ destPos++;
+ continue;
+ }
+
+ if (c < 0xc0 + 2
+ || c >= 0xf5) // it's limit for 0x140000 unicode codes : win32 compatibility
+ {
+ UTF_ERROR_UTF8
+ }
+
+ unsigned numBytes;
+
+ MY_UTF8_HEAD_PARSE_MAX_3_BYTES
+
+ unsigned pos = 0;
+ do
+ {
+ if (src + pos == srcLim)
+ break;
+ unsigned c2 = (Byte)src[pos];
+ c2 -= 0x80;
+ if (c2 >= 0x40)
+ break;
+ val <<= 6;
+ val |= c2;
+ pos++;
+ if (pos == 1)
+ {
+ if (val < (((unsigned)1 << 7) >> numBytes))
+ break;
+ if (numBytes == 2)
+ {
+ if (flags & Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR)
+ if ((val & (0xF800 >> 6)) == (0xd800 >> 6))
+ break;
+ }
+ else if (numBytes == 3 && val >= (0x110000 >> 12))
+ break;
+ }
+ }
+ while (--numBytes);
+
+ if (numBytes != 0)
+ {
+ if ((flags & Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE) == 0)
+ {
+ // the following code to emit the 0xfffd chars as win32 Utf8 function.
+ // disable the folling line, if you need 0xfffd for each incorrect byte as in Escape mode
+ src += pos;
+ }
+ UTF_ERROR_UTF8
+ }
+
+ /*
+ if (val < MY_UTF8_RANGE(pos - 1))
+ UTF_ERROR_UTF8
+ */
+
+ #ifdef UTF_ESCAPE_BASE
+
+ if ((flags & Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT)
+ && IS_ESCAPE_POINT(val, 0))
+ {
+ // We will emit 3 utf16-Escape-16-21 points from one Escape-16 point (3 bytes)
+ UTF_ERROR_UTF8
+ }
+
+ #endif
+
+ /*
+ We don't expect virtual Escape-21 points in UTF-8 stream.
+ And we don't check for Escape-21.
+ So utf8-Escape-21 will be converted to another 3 utf16-Escape-21 points.
+ Maybe we could convert virtual utf8-Escape-21 to one utf16-Escape-21 point in some cases?
+ */
+
+ if (val < START_POINT_FOR_SURROGATE)
+ {
+ /*
+ if ((flags & Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR)
+ && IS_SURROGATE_POINT(val))
+ {
+ // We will emit 3 utf16-Escape-16-21 points from one Surrogate-16 point (3 bytes)
+ UTF_ERROR_UTF8
+ }
+ */
+ if (dest)
+ dest[destPos] = (wchar_t)val;
+ destPos++;
+ }
+ else
+ {
+ /*
+ if (val >= 0x110000)
+ {
+ // We will emit utf16-Escape-16-21 point from each source byte
+ UTF_ERROR_UTF8
+ }
+ */
+ if (dest)
+ {
+ dest[destPos + 0] = (wchar_t)(0xd800 - (0x10000 >> 10) + (val >> 10));
+ dest[destPos + 1] = (wchar_t)(0xdc00 + (val & 0x3ff));
+ }
+ destPos += 2;
+ }
+ src += pos;
+ }
+}
+
+
+
+#define MY_UTF8_HEAD(n, val) ((char)(MY_UTF8_START(n) + (val >> (6 * (n)))))
+#define MY_UTF8_CHAR(n, val) ((char)(0x80 + (((val) >> (6 * (n))) & 0x3F)))
+
+static size_t Utf16_To_Utf8_Calc(const wchar_t *src, const wchar_t *srcLim, unsigned flags)
+{
+ size_t size = (size_t)(srcLim - src);
+ for (;;)
+ {
+ if (src == srcLim)
+ return size;
+
+ UInt32 val = (UInt32)(*src++);
+
+ if (val < 0x80)
+ continue;
+
+ if (val < MY_UTF8_RANGE(1))
+ {
+ size++;
+ continue;
+ }
+
+ #ifdef UTF_ESCAPE_BASE
+
+ #if UTF_ESCAPE_PLANE != 0
+ if (flags & Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE)
+ if (IS_ESCAPE_POINT(val, UTF_ESCAPE_PLANE))
+ continue;
+ #endif
+
+ if (flags & Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE)
+ if (IS_ESCAPE_POINT(val, 0))
+ continue;
+
+ #endif
+
+ if (IS_SURROGATE_POINT(val))
+ {
+ // it's hack to UTF-8 encoding
+
+ if (val < 0xdc00 && src != srcLim)
+ {
+ const UInt32 c2 = (UInt32)*src;
+ if (c2 >= 0xdc00 && c2 < 0xe000)
+ src++;
+ }
+ size += 2;
+ continue;
+ }
+
+ #ifdef Z7_WCHART_IS_16BIT
+
+ size += 2;
+
+ #else
+
+ if (val < MY_UTF8_RANGE(2)) size += 2;
+ else if (val < MY_UTF8_RANGE(3)) size += 3;
+ else if (val < MY_UTF8_RANGE(4)) size += 4;
+ else if (val < MY_UTF8_RANGE(5)) size += 5;
+ else
+ #if MY_UTF8_NUM_TAIL_BYTES_MAX >= 6
+ size += 6;
+ #else
+ size += 3;
+ #endif
+
+ #endif
+ }
+}
+
+
+static char *Utf16_To_Utf8(char *dest, const wchar_t *src, const wchar_t *srcLim, unsigned flags)
+{
+ for (;;)
+ {
+ if (src == srcLim)
+ return dest;
+
+ UInt32 val = (UInt32)*src++;
+
+ if (val < 0x80)
+ {
+ *dest++ = (char)val;
+ continue;
+ }
+
+ if (val < MY_UTF8_RANGE(1))
+ {
+ dest[0] = MY_UTF8_HEAD(1, val);
+ dest[1] = MY_UTF8_CHAR(0, val);
+ dest += 2;
+ continue;
+ }
+
+ #ifdef UTF_ESCAPE_BASE
+
+ #if UTF_ESCAPE_PLANE != 0
+ /*
+ if (wchar_t is 32-bit)
+ && (Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE is set)
+ && (point is virtual escape plane)
+ we extract 8-bit byte from virtual HIGH-ESCAPE PLANE.
+ */
+ if (flags & Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE)
+ if (IS_ESCAPE_POINT(val, UTF_ESCAPE_PLANE))
+ {
+ *dest++ = (char)(val);
+ continue;
+ }
+ #endif // UTF_ESCAPE_PLANE != 0
+
+ /* if (Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE is defined)
+ we extract 8-bit byte from BMP-ESCAPE PLANE. */
+
+ if (flags & Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE)
+ if (IS_ESCAPE_POINT(val, 0))
+ {
+ *dest++ = (char)(val);
+ continue;
+ }
+
+ #endif // UTF_ESCAPE_BASE
+
+ if (IS_SURROGATE_POINT(val))
+ {
+ // it's hack to UTF-8 encoding
+ if (val < 0xdc00 && src != srcLim)
+ {
+ const UInt32 c2 = (UInt32)*src;
+ if (IS_LOW_SURROGATE_POINT(c2))
+ {
+ src++;
+ val = (((val - 0xd800) << 10) | (c2 - 0xdc00)) + 0x10000;
+ dest[0] = MY_UTF8_HEAD(3, val);
+ dest[1] = MY_UTF8_CHAR(2, val);
+ dest[2] = MY_UTF8_CHAR(1, val);
+ dest[3] = MY_UTF8_CHAR(0, val);
+ dest += 4;
+ continue;
+ }
+ }
+ if (flags & Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR)
+ val = UTF_REPLACEMENT_CHAR; // WIN32 function does it
+ }
+
+ #ifndef Z7_WCHART_IS_16BIT
+ if (val < MY_UTF8_RANGE(2))
+ #endif
+ {
+ dest[0] = MY_UTF8_HEAD(2, val);
+ dest[1] = MY_UTF8_CHAR(1, val);
+ dest[2] = MY_UTF8_CHAR(0, val);
+ dest += 3;
+ continue;
+ }
+
+ #ifndef Z7_WCHART_IS_16BIT
+
+ // we don't expect this case. so we can throw exception
+ // throw 20210407;
+
+ char b;
+ unsigned numBits;
+ if (val < MY_UTF8_RANGE(3)) { numBits = 6 * 3; b = MY_UTF8_HEAD(3, val); }
+ else if (val < MY_UTF8_RANGE(4)) { numBits = 6 * 4; b = MY_UTF8_HEAD(4, val); }
+ else if (val < MY_UTF8_RANGE(5)) { numBits = 6 * 5; b = MY_UTF8_HEAD(5, val); }
+ #if MY_UTF8_NUM_TAIL_BYTES_MAX >= 6
+ else { numBits = 6 * 6; b = (char)MY_UTF8_START(6); }
+ #else
+ else
+ {
+ val = UTF_REPLACEMENT_CHAR;
+ { numBits = 6 * 3; b = MY_UTF8_HEAD(3, val); }
+ }
+ #endif
+
+ *dest++ = b;
+
+ do
+ {
+ numBits -= 6;
+ *dest++ = (char)(0x80 + ((val >> numBits) & 0x3F));
+ }
+ while (numBits != 0);
+
+ #endif
+ }
+}
+
+bool Convert_UTF8_Buf_To_Unicode(const char *src, size_t srcSize, UString &dest, unsigned flags)
+{
+ dest.Empty();
+ size_t destLen = 0;
+ Utf8_To_Utf16(NULL, &destLen, src, src + srcSize, flags);
+ bool res = Utf8_To_Utf16(dest.GetBuf((unsigned)destLen), &destLen, src, src + srcSize, flags);
+ dest.ReleaseBuf_SetEnd((unsigned)destLen);
+ return res;
+}
+
+bool ConvertUTF8ToUnicode_Flags(const AString &src, UString &dest, unsigned flags)
+{
+ return Convert_UTF8_Buf_To_Unicode(src, src.Len(), dest, flags);
+}
+
+
+static
+unsigned g_UTF8_To_Unicode_Flags =
+ Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE
+ #ifndef Z7_WCHART_IS_16BIT
+ | Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR
+ #ifdef MY_UTF8_RAW_NON_UTF8_SUPPORTED
+ | Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT
+ #endif
+ #endif
+ ;
+
+
+/*
+bool ConvertUTF8ToUnicode_boolRes(const AString &src, UString &dest)
+{
+ return ConvertUTF8ToUnicode_Flags(src, dest, g_UTF8_To_Unicode_Flags);
+}
+*/
+
+bool ConvertUTF8ToUnicode(const AString &src, UString &dest)
+{
+ return ConvertUTF8ToUnicode_Flags(src, dest, g_UTF8_To_Unicode_Flags);
+}
+
+void Print_UString(const UString &a);
+
+void ConvertUnicodeToUTF8_Flags(const UString &src, AString &dest, unsigned flags)
+{
+ /*
+ if (src.Len()== 24)
+ throw "202104";
+ */
+ dest.Empty();
+ const size_t destLen = Utf16_To_Utf8_Calc(src, src.Ptr(src.Len()), flags);
+ char *destStart = dest.GetBuf((unsigned)destLen);
+ const char *destEnd = Utf16_To_Utf8(destStart, src, src.Ptr(src.Len()), flags);
+ dest.ReleaseBuf_SetEnd((unsigned)destLen);
+ // printf("\nlen = %d\n", src.Len());
+ if (destLen != (size_t)(destEnd - destStart))
+ {
+ /*
+ // dest.ReleaseBuf_SetEnd((unsigned)(destEnd - destStart));
+ printf("\nlen = %d\n", (unsigned)destLen);
+ printf("\n(destEnd - destStart) = %d\n", (unsigned)(destEnd - destStart));
+ printf("\n");
+ // Print_UString(src);
+ printf("\n");
+ // printf("\nlen = %d\n", destLen);
+ */
+ throw 20210406;
+ }
+}
+
+
+
+unsigned g_Unicode_To_UTF8_Flags =
+ // Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE
+ 0
+ #ifndef _WIN32
+ #ifdef MY_UTF8_RAW_NON_UTF8_SUPPORTED
+ | Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE
+ #else
+ | Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR
+ #endif
+ #endif
+ ;
+
+void ConvertUnicodeToUTF8(const UString &src, AString &dest)
+{
+ ConvertUnicodeToUTF8_Flags(src, dest, g_Unicode_To_UTF8_Flags);
+}
+
+void Convert_Unicode_To_UTF8_Buf(const UString &src, CByteBuffer &dest)
+{
+ const unsigned flags = g_Unicode_To_UTF8_Flags;
+ dest.Free();
+ const size_t destLen = Utf16_To_Utf8_Calc(src, src.Ptr(src.Len()), flags);
+ dest.Alloc(destLen);
+ const char *destEnd = Utf16_To_Utf8((char *)(void *)(Byte *)dest, src, src.Ptr(src.Len()), flags);
+ if (destLen != (size_t)(destEnd - (char *)(void *)(Byte *)dest))
+ throw 202104;
+}
+
+/*
+
+#ifndef _WIN32
+void Convert_UTF16_To_UTF32(const UString &src, UString &dest)
+{
+ dest.Empty();
+ for (size_t i = 0; i < src.Len();)
+ {
+ wchar_t c = src[i++];
+ if (c >= 0xd800 && c < 0xdc00 && i < src.Len())
+ {
+ const wchar_t c2 = src[i];
+ if (c2 >= 0xdc00 && c2 < 0x10000)
+ {
+ // printf("\nSurragate [%d]: %4x %4x -> ", i, (int)c, (int)c2);
+ c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff);
+ // printf("%4x\n", (int)c);
+ i++;
+ }
+ }
+ dest += c;
+ }
+}
+
+void Convert_UTF32_To_UTF16(const UString &src, UString &dest)
+{
+ dest.Empty();
+ for (size_t i = 0; i < src.Len();)
+ {
+ wchar_t w = src[i++];
+ if (w >= 0x10000 && w < 0x110000)
+ {
+ w -= 0x10000;
+ dest += (wchar_t)((unsigned)0xd800 + (((unsigned)w >> 10) & 0x3ff));
+ w = 0xdc00 + (w & 0x3ff);
+ }
+ dest += w;
+ }
+}
+
+bool UTF32_IsThere_BigPoint(const UString &src)
+{
+ for (size_t i = 0; i < src.Len();)
+ {
+ const UInt32 c = (UInt32)src[i++];
+ if (c >= 0x110000)
+ return true;
+ }
+ return false;
+}
+
+bool Unicode_IsThere_BmpEscape(const UString &src)
+{
+ for (size_t i = 0; i < src.Len();)
+ {
+ const UInt32 c = (UInt32)src[i++];
+ if (IS_ESCAPE_POINT(c, 0))
+ return true;
+ }
+ return false;
+}
+
+
+#endif
+
+bool Unicode_IsThere_Utf16SurrogateError(const UString &src)
+{
+ for (size_t i = 0; i < src.Len();)
+ {
+ const UInt32 val = (UInt32)src[i++];
+ if (IS_SURROGATE_POINT(val))
+ {
+ // it's hack to UTF-8 encoding
+ if (val >= 0xdc00 || i == src.Len())
+ return true;
+ const UInt32 c2 = (UInt32)*src;
+ if (!IS_LOW_SURROGATE_POINT(c2))
+ return true;
+ }
+ }
+ return false;
+}
+*/
+
+#ifndef Z7_WCHART_IS_16BIT
+
+void Convert_UnicodeEsc16_To_UnicodeEscHigh
+#if UTF_ESCAPE_PLANE == 0
+ (UString &) {}
+#else
+ (UString &s)
+{
+ const unsigned len = s.Len();
+ for (unsigned i = 0; i < len; i++)
+ {
+ wchar_t c = s[i];
+ if (IS_ESCAPE_POINT(c, 0))
+ {
+ c += UTF_ESCAPE_PLANE;
+ s.ReplaceOneCharAtPos(i, c);
+ }
+ }
+}
+#endif
+#endif
diff --git a/CPP/Common/UTFConvert.h b/CPP/Common/UTFConvert.h
index 1183170..94a8024 100644
--- a/CPP/Common/UTFConvert.h
+++ b/CPP/Common/UTFConvert.h
@@ -1,12 +1,384 @@
-// Common/UTFConvert.h
-
-#ifndef __COMMON_UTF_CONVERT_H
-#define __COMMON_UTF_CONVERT_H
-
-#include "MyString.h"
-
-bool CheckUTF8(const char *src, bool allowReduced = false) throw();
-bool ConvertUTF8ToUnicode(const AString &utfString, UString &resultString);
-void ConvertUnicodeToUTF8(const UString &unicodeString, AString &resultString);
-
-#endif
+// Common/UTFConvert.h
+
+#ifndef ZIP7_INC_COMMON_UTF_CONVERT_H
+#define ZIP7_INC_COMMON_UTF_CONVERT_H
+
+#include "MyBuffer.h"
+#include "MyString.h"
+
+struct CUtf8Check
+{
+ // Byte MaxByte; // in original src stream
+ bool NonUtf;
+ bool ZeroChar;
+ bool SingleSurrogate;
+ bool Escape;
+ bool Truncated;
+ UInt32 MaxHighPoint; // only for points >= 0x80
+
+ CUtf8Check() { Clear(); }
+
+ void Clear()
+ {
+ // MaxByte = 0;
+ NonUtf = false;
+ ZeroChar = false;
+ SingleSurrogate = false;
+ Escape = false;
+ Truncated = false;
+ MaxHighPoint = 0;
+ }
+
+ void Update(const CUtf8Check &c)
+ {
+ if (c.NonUtf) NonUtf = true;
+ if (c.ZeroChar) ZeroChar = true;
+ if (c.SingleSurrogate) SingleSurrogate = true;
+ if (c.Escape) Escape = true;
+ if (c.Truncated) Truncated = true;
+ if (MaxHighPoint < c.MaxHighPoint) MaxHighPoint = c.MaxHighPoint;
+ }
+
+ void PrintStatus(AString &s) const
+ {
+ s.Empty();
+
+ // s.Add_OptSpaced("MaxByte=");
+ // s.Add_UInt32(MaxByte);
+
+ if (NonUtf) s.Add_OptSpaced("non-UTF8");
+ if (ZeroChar) s.Add_OptSpaced("ZeroChar");
+ if (SingleSurrogate) s.Add_OptSpaced("SingleSurrogate");
+ if (Escape) s.Add_OptSpaced("Escape");
+ if (Truncated) s.Add_OptSpaced("Truncated");
+
+ if (MaxHighPoint != 0)
+ {
+ s.Add_OptSpaced("MaxUnicode=");
+ s.Add_UInt32(MaxHighPoint);
+ }
+ }
+
+
+ bool IsOK(bool allowReduced = false) const
+ {
+ if (NonUtf || SingleSurrogate || ZeroChar)
+ return false;
+ if (MaxHighPoint >= 0x110000)
+ return false;
+ if (Truncated && !allowReduced)
+ return false;
+ return true;
+ }
+
+ // it checks full buffer as specified in (size) and it doesn't stop on zero char
+ void Check_Buf(const char *src, size_t size) throw();
+
+ void Check_AString(const AString &s) throw()
+ {
+ Check_Buf(s.Ptr(), s.Len());
+ }
+};
+
+/*
+if (allowReduced == false) - all UTF-8 character sequences must be finished.
+if (allowReduced == true) - it allows truncated last character-Utf8-sequence
+*/
+
+bool Check_UTF8_Buf(const char *src, size_t size, bool allowReduced) throw();
+bool CheckUTF8_AString(const AString &s) throw();
+
+#define Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR (1 << 0)
+#define Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE (1 << 1)
+#define Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT (1 << 2)
+
+/*
+Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR
+
+ if (flag is NOT set)
+ {
+ it processes SINGLE-SURROGATE-8 as valid Unicode point.
+ it converts SINGLE-SURROGATE-8 to SINGLE-SURROGATE-16
+ Note: some sequencies of two SINGLE-SURROGATE-8 points
+ will generate correct SURROGATE-16-PAIR, and
+ that SURROGATE-16-PAIR later will be converted to correct
+ UTF8-SURROGATE-21 point. So we don't restore original
+ STR-8 sequence in that case.
+ }
+
+ if (flag is set)
+ {
+ if (Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE is defined)
+ it generates ESCAPE for SINGLE-SURROGATE-8,
+ if (Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE is not defined)
+ it generates U+fffd for SINGLE-SURROGATE-8,
+ }
+
+
+Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE
+
+ if (flag is NOT set)
+ it generates (U+fffd) code for non-UTF-8 (invalid) characters
+
+ if (flag is set)
+ {
+ It generates (ESCAPE) codes for NON-UTF-8 (invalid) characters.
+ And later we can restore original UTF-8-RAW characters from (ESCAPE-16-21) codes.
+ }
+
+Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT
+
+ if (flag is NOT set)
+ {
+ it process ESCAPE-8 points as another Unicode points.
+ In Linux: ESCAPE-16 will mean two different ESCAPE-8 seqences,
+ so we need HIGH-ESCAPE-PLANE-21 to restore UTF-8-RAW -> UTF-16 -> UTF-8-RAW
+ }
+
+ if (flag is set)
+ {
+ it generates ESCAPE-16-21 for ESCAPE-8 points
+ so we can restore UTF-8-RAW -> UTF-16 -> UTF-8-RAW without HIGH-ESCAPE-PLANE-21.
+ }
+
+
+Main USE CASES with UTF-8 <-> UTF-16 conversions:
+
+ WIN32: UTF-16-RAW -> UTF-8 (Archive) -> UTF-16-RAW
+ {
+ set Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE
+ Do NOT set Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR
+ Do NOT set Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT
+
+ So we restore original SINGLE-SURROGATE-16 from single SINGLE-SURROGATE-8.
+ }
+
+ Linux: UTF-8-RAW -> UTF-16 (Intermediate / Archive) -> UTF-8-RAW
+ {
+ we want restore original UTF-8-RAW sequence later from that ESCAPE-16.
+ Set the flags:
+ Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR
+ Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE
+ Z7_UTF_FLAG_FROM_UTF8_BMP_ESCAPE_CONVERT
+ }
+
+ MacOS: UTF-8-RAW -> UTF-16 (Intermediate / Archive) -> UTF-8-RAW
+ {
+ we want to restore correct UTF-8 without any BMP processing:
+ Set the flags:
+ Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR
+ Z7_UTF_FLAG_FROM_UTF8_USE_ESCAPE
+ }
+
+*/
+
+// zero char is not allowed in (src) buf
+bool Convert_UTF8_Buf_To_Unicode(const char *src, size_t srcSize, UString &dest, unsigned flags = 0);
+
+bool ConvertUTF8ToUnicode_Flags(const AString &src, UString &dest, unsigned flags = 0);
+bool ConvertUTF8ToUnicode(const AString &src, UString &dest);
+
+#define Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR (1 << 8)
+#define Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE (1 << 9)
+// #define Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE (1 << 10)
+
+/*
+Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR
+
+ if (flag is NOT set)
+ {
+ we extract SINGLE-SURROGATE as normal UTF-8
+
+ In Windows : for UTF-16-RAW <-> UTF-8 (archive) <-> UTF-16-RAW in .
+
+ In Linux :
+ use-case-1: UTF-8 -> UTF-16 -> UTF-8 doesn't generate UTF-16 SINGLE-SURROGATE,
+ if (Z7_UTF_FLAG_FROM_UTF8_SURROGATE_ERROR) is used.
+ use-case 2: UTF-16-7z (with SINGLE-SURROGATE from Windows) -> UTF-8 (Linux)
+ will generate SINGLE-SURROGATE-UTF-8 here.
+ }
+
+ if (flag is set)
+ {
+ we generate UTF_REPLACEMENT_CHAR (0xfffd) for SINGLE_SURROGATE
+ it can be used for compatibility mode with WIN32 UTF function
+ or if we want UTF-8 stream without any errors
+ }
+
+
+Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE
+
+ if (flag is NOT set) it doesn't extract raw 8-bit symbol from Escape-Plane-16
+ if (flag is set) it extracts raw 8-bit symbol from Escape-Plane-16
+
+ in Linux we need some way to extract NON-UTF8 RAW 8-bits from BMP (UTF-16 7z archive):
+ if (we use High-Escape-Plane), we can transfer BMP escapes to High-Escape-Plane.
+ if (we don't use High-Escape-Plane), we must use Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE.
+
+
+Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE
+ // that flag affects the code only if (wchar_t is 32-bit)
+ // that mode with high-escape can be disabled now in UTFConvert.cpp
+ if (flag is NOT set)
+ it doesn't extract raw 8-bit symbol from High-Escape-Plane
+ if (flag is set)
+ it extracts raw 8-bit symbol from High-Escape-Plane
+
+Main use cases:
+
+WIN32 : UTF-16-RAW -> UTF-8 (archive) -> UTF-16-RAW
+ {
+ Do NOT set Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE.
+ Do NOT set Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR.
+ So we restore original UTF-16-RAW.
+ }
+
+Linix : UTF-8 with Escapes -> UTF-16 (7z archive) -> UTF-8 with Escapes
+ set Z7_UTF_FLAG_TO_UTF8_EXTRACT_BMP_ESCAPE to extract non-UTF from 7z archive
+ set Z7_UTF_FLAG_TO_UTF8_PARSE_HIGH_ESCAPE for intermediate UTF-16.
+ Note: high esacape mode can be ignored now in UTFConvert.cpp
+
+macOS:
+ the system doesn't support incorrect UTF-8 in file names.
+ set Z7_UTF_FLAG_TO_UTF8_SURROGATE_ERROR
+*/
+
+extern unsigned g_Unicode_To_UTF8_Flags;
+
+void ConvertUnicodeToUTF8_Flags(const UString &src, AString &dest, unsigned flags = 0);
+void ConvertUnicodeToUTF8(const UString &src, AString &dest);
+
+void Convert_Unicode_To_UTF8_Buf(const UString &src, CByteBuffer &dest);
+
+/*
+#ifndef _WIN32
+void Convert_UTF16_To_UTF32(const UString &src, UString &dest);
+void Convert_UTF32_To_UTF16(const UString &src, UString &dest);
+bool UTF32_IsThere_BigPoint(const UString &src);
+bool Unicode_IsThere_BmpEscape(const UString &src);
+#endif
+
+bool Unicode_IsThere_Utf16SurrogateError(const UString &src);
+*/
+
+#ifdef Z7_WCHART_IS_16BIT
+#define Convert_UnicodeEsc16_To_UnicodeEscHigh(s)
+#else
+void Convert_UnicodeEsc16_To_UnicodeEscHigh(UString &s);
+#endif
+
+/*
+// #include "../../C/CpuArch.h"
+
+// ---------- Utf16 Little endian functions ----------
+
+// We store 16-bit surrogates even in 32-bit WCHARs in Linux.
+// So now we don't use the following code:
+
+#if WCHAR_MAX > 0xffff
+
+// void *p : pointer to src bytes stream
+// size_t len : num Utf16 characters : it can include or not include NULL character
+
+inline size_t Utf16LE__Get_Num_WCHARs(const void *p, size_t len)
+{
+ #if WCHAR_MAX > 0xffff
+ size_t num_wchars = 0;
+ for (size_t i = 0; i < len; i++)
+ {
+ wchar_t c = GetUi16(p);
+ p = (const void *)((const Byte *)p + 2);
+ if (c >= 0xd800 && c < 0xdc00 && i + 1 != len)
+ {
+ wchar_t c2 = GetUi16(p);
+ if (c2 >= 0xdc00 && c2 < 0xe000)
+ {
+ c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff);
+ p = (const void *)((const Byte *)p + 2);
+ i++;
+ }
+ }
+ num_wchars++;
+ }
+ return num_wchars;
+ #else
+ UNUSED_VAR(p)
+ return len;
+ #endif
+}
+
+// #include <stdio.h>
+
+inline wchar_t *Utf16LE__To_WCHARs_Sep(const void *p, size_t len, wchar_t *dest)
+{
+ for (size_t i = 0; i < len; i++)
+ {
+ wchar_t c = GetUi16(p);
+ p = (const void *)((const Byte *)p + 2);
+
+ #if WCHAR_PATH_SEPARATOR != L'/'
+ if (c == L'/')
+ c = WCHAR_PATH_SEPARATOR;
+ #endif
+
+ #if WCHAR_MAX > 0xffff
+
+ if (c >= 0xd800 && c < 0xdc00 && i + 1 != len)
+ {
+ wchar_t c2 = GetUi16(p);
+ if (c2 >= 0xdc00 && c2 < 0xe000)
+ {
+ // printf("\nSurragate : %4x %4x -> ", (int)c, (int)c2);
+ c = 0x10000 + ((c & 0x3ff) << 10) + (c2 & 0x3ff);
+ p = (const void *)((const Byte *)p + 2);
+ i++;
+ // printf("%4x\n", (int)c);
+ }
+ }
+
+ #endif
+
+ *dest++ = c;
+ }
+ return dest;
+}
+
+
+inline size_t Get_Num_Utf16_chars_from_wchar_string(const wchar_t *p)
+{
+ size_t num = 0;
+ for (;;)
+ {
+ wchar_t c = *p++;
+ if (c == 0)
+ return num;
+ num += ((c >= 0x10000 && c < 0x110000) ? 2 : 1);
+ }
+ return num;
+}
+
+inline Byte *wchars_to_Utf16LE(const wchar_t *p, Byte *dest)
+{
+ for (;;)
+ {
+ wchar_t c = *p++;
+ if (c == 0)
+ return dest;
+ if (c >= 0x10000 && c < 0x110000)
+ {
+ SetUi16(dest , (UInt16)(0xd800 + ((c >> 10) & 0x3FF)));
+ SetUi16(dest + 2, (UInt16)(0xdc00 + ( c & 0x3FF)));
+ dest += 4;
+ }
+ else
+ {
+ SetUi16(dest, c);
+ dest += 2;
+ }
+ }
+}
+
+#endif
+*/
+
+#endif
diff --git a/CPP/Common/Wildcard.cpp b/CPP/Common/Wildcard.cpp
index 43e4baa..798cbd9 100644
--- a/CPP/Common/Wildcard.cpp
+++ b/CPP/Common/Wildcard.cpp
@@ -1,676 +1,788 @@
-// Common/Wildcard.cpp
-
-#include "StdAfx.h"
-
-#include "Wildcard.h"
-
-bool g_CaseSensitive =
- #ifdef _WIN32
- false;
- #else
- true;
- #endif
-
-
-bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2)
-{
- if (g_CaseSensitive)
- return IsString1PrefixedByString2(s1, s2);
- return IsString1PrefixedByString2_NoCase(s1, s2);
-}
-
-int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW
-{
- if (g_CaseSensitive)
- return MyStringCompare(s1, s2);
- return MyStringCompareNoCase(s1, s2);
-}
-
-#ifndef USE_UNICODE_FSTRING
-int CompareFileNames(const char *s1, const char *s2)
-{
- const UString u1 = fs2us(s1);
- const UString u2 = fs2us(s2);
- if (g_CaseSensitive)
- return MyStringCompare(u1, u2);
- return MyStringCompareNoCase(u1, u2);
-}
-#endif
-
-// -----------------------------------------
-// this function compares name with mask
-// ? - any char
-// * - any char or empty
-
-static bool EnhancedMaskTest(const wchar_t *mask, const wchar_t *name)
-{
- for (;;)
- {
- wchar_t m = *mask;
- wchar_t c = *name;
- if (m == 0)
- return (c == 0);
- if (m == '*')
- {
- if (EnhancedMaskTest(mask + 1, name))
- return true;
- if (c == 0)
- return false;
- }
- else
- {
- if (m == '?')
- {
- if (c == 0)
- return false;
- }
- else if (m != c)
- if (g_CaseSensitive || MyCharUpper(m) != MyCharUpper(c))
- return false;
- mask++;
- }
- name++;
- }
-}
-
-// --------------------------------------------------
-// Splits path to strings
-
-void SplitPathToParts(const UString &path, UStringVector &pathParts)
-{
- pathParts.Clear();
- unsigned len = path.Len();
- if (len == 0)
- return;
- UString name;
- unsigned prev = 0;
- for (unsigned i = 0; i < len; i++)
- if (IsPathSepar(path[i]))
- {
- name.SetFrom(path.Ptr(prev), i - prev);
- pathParts.Add(name);
- prev = i + 1;
- }
- name.SetFrom(path.Ptr(prev), len - prev);
- pathParts.Add(name);
-}
-
-void SplitPathToParts_2(const UString &path, UString &dirPrefix, UString &name)
-{
- const wchar_t *start = path;
- const wchar_t *p = start + path.Len();
- for (; p != start; p--)
- if (IsPathSepar(*(p - 1)))
- break;
- dirPrefix.SetFrom(path, (unsigned)(p - start));
- name = p;
-}
-
-void SplitPathToParts_Smart(const UString &path, UString &dirPrefix, UString &name)
-{
- const wchar_t *start = path;
- const wchar_t *p = start + path.Len();
- if (p != start)
- {
- if (IsPathSepar(*(p - 1)))
- p--;
- for (; p != start; p--)
- if (IsPathSepar(*(p - 1)))
- break;
- }
- dirPrefix.SetFrom(path, (unsigned)(p - start));
- name = p;
-}
-
-/*
-UString ExtractDirPrefixFromPath(const UString &path)
-{
- return path.Left(path.ReverseFind_PathSepar() + 1));
-}
-*/
-
-UString ExtractFileNameFromPath(const UString &path)
-{
- return UString(path.Ptr(path.ReverseFind_PathSepar() + 1));
-}
-
-
-bool DoesWildcardMatchName(const UString &mask, const UString &name)
-{
- return EnhancedMaskTest(mask, name);
-}
-
-bool DoesNameContainWildcard(const UString &path)
-{
- for (unsigned i = 0; i < path.Len(); i++)
- {
- wchar_t c = path[i];
- if (c == '*' || c == '?')
- return true;
- }
- return false;
-}
-
-
-// ----------------------------------------------------------'
-// NWildcard
-
-namespace NWildcard {
-
-/*
-
-M = MaskParts.Size();
-N = TestNameParts.Size();
-
- File Dir
-ForFile rec M<=N [N-M, N) -
-!ForDir nonrec M=N [0, M) -
-
-ForDir rec M<N [0, M) ... [N-M-1, N-1) same as ForBoth-File
-!ForFile nonrec [0, M) same as ForBoth-File
-
-ForFile rec m<=N [0, M) ... [N-M, N) same as ForBoth-File
-ForDir nonrec [0, M) same as ForBoth-File
-
-*/
-
-bool CItem::AreAllAllowed() const
-{
- return ForFile && ForDir && WildcardMatching && PathParts.Size() == 1 && PathParts.Front() == L"*";
-}
-
-bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const
-{
- if (!isFile && !ForDir)
- return false;
-
- /*
- if (PathParts.IsEmpty())
- {
- // PathParts.IsEmpty() means all items (universal wildcard)
- if (!isFile)
- return true;
- if (pathParts.Size() <= 1)
- return ForFile;
- return (ForDir || Recursive && ForFile);
- }
- */
-
- int delta = (int)pathParts.Size() - (int)PathParts.Size();
- if (delta < 0)
- return false;
- int start = 0;
- int finish = 0;
-
- if (isFile)
- {
- if (!ForDir)
- {
- if (Recursive)
- start = delta;
- else if (delta !=0)
- return false;
- }
- if (!ForFile && delta == 0)
- return false;
- }
-
- if (Recursive)
- {
- finish = delta;
- if (isFile && !ForFile)
- finish = delta - 1;
- }
-
- for (int d = start; d <= finish; d++)
- {
- unsigned i;
- for (i = 0; i < PathParts.Size(); i++)
- {
- if (WildcardMatching)
- {
- if (!DoesWildcardMatchName(PathParts[i], pathParts[i + d]))
- break;
- }
- else
- {
- if (CompareFileNames(PathParts[i], pathParts[i + d]) != 0)
- break;
- }
- }
- if (i == PathParts.Size())
- return true;
- }
- return false;
-}
-
-bool CCensorNode::AreAllAllowed() const
-{
- if (!Name.IsEmpty() ||
- !SubNodes.IsEmpty() ||
- !ExcludeItems.IsEmpty() ||
- IncludeItems.Size() != 1)
- return false;
- return IncludeItems.Front().AreAllAllowed();
-}
-
-int CCensorNode::FindSubNode(const UString &name) const
-{
- FOR_VECTOR (i, SubNodes)
- if (CompareFileNames(SubNodes[i].Name, name) == 0)
- return i;
- return -1;
-}
-
-void CCensorNode::AddItemSimple(bool include, CItem &item)
-{
- if (include)
- IncludeItems.Add(item);
- else
- ExcludeItems.Add(item);
-}
-
-void CCensorNode::AddItem(bool include, CItem &item, int ignoreWildcardIndex)
-{
- if (item.PathParts.Size() <= 1)
- {
- if (item.PathParts.Size() != 0 && item.WildcardMatching)
- {
- if (!DoesNameContainWildcard(item.PathParts.Front()))
- item.WildcardMatching = false;
- }
- AddItemSimple(include, item);
- return;
- }
- const UString &front = item.PathParts.Front();
-
- // WIN32 doesn't support wildcards in file names
- if (item.WildcardMatching
- && ignoreWildcardIndex != 0
- && DoesNameContainWildcard(front))
- {
- AddItemSimple(include, item);
- return;
- }
- int index = FindSubNode(front);
- if (index < 0)
- index = SubNodes.Add(CCensorNode(front, this));
- item.PathParts.Delete(0);
- SubNodes[index].AddItem(include, item, ignoreWildcardIndex - 1);
-}
-
-void CCensorNode::AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir, bool wildcardMatching)
-{
- CItem item;
- SplitPathToParts(path, item.PathParts);
- item.Recursive = recursive;
- item.ForFile = forFile;
- item.ForDir = forDir;
- item.WildcardMatching = wildcardMatching;
- AddItem(include, item);
-}
-
-bool CCensorNode::NeedCheckSubDirs() const
-{
- FOR_VECTOR (i, IncludeItems)
- {
- const CItem &item = IncludeItems[i];
- if (item.Recursive || item.PathParts.Size() > 1)
- return true;
- }
- return false;
-}
-
-bool CCensorNode::AreThereIncludeItems() const
-{
- if (IncludeItems.Size() > 0)
- return true;
- FOR_VECTOR (i, SubNodes)
- if (SubNodes[i].AreThereIncludeItems())
- return true;
- return false;
-}
-
-bool CCensorNode::CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const
-{
- const CObjectVector<CItem> &items = include ? IncludeItems : ExcludeItems;
- FOR_VECTOR (i, items)
- if (items[i].CheckPath(pathParts, isFile))
- return true;
- return false;
-}
-
-bool CCensorNode::CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const
-{
- if (CheckPathCurrent(false, pathParts, isFile))
- {
- include = false;
- return true;
- }
- include = true;
- bool finded = CheckPathCurrent(true, pathParts, isFile);
- if (pathParts.Size() <= 1)
- return finded;
- int index = FindSubNode(pathParts.Front());
- if (index >= 0)
- {
- UStringVector pathParts2 = pathParts;
- pathParts2.Delete(0);
- if (SubNodes[index].CheckPathVect(pathParts2, isFile, include))
- return true;
- }
- return finded;
-}
-
-/*
-bool CCensorNode::CheckPath2(bool isAltStream, const UString &path, bool isFile, bool &include) const
-{
- UStringVector pathParts;
- SplitPathToParts(path, pathParts);
- if (CheckPathVect(pathParts, isFile, include))
- {
- if (!include || !isAltStream)
- return true;
- }
- if (isAltStream && !pathParts.IsEmpty())
- {
- UString &back = pathParts.Back();
- int pos = back.Find(L':');
- if (pos > 0)
- {
- back.DeleteFrom(pos);
- return CheckPathVect(pathParts, isFile, include);
- }
- }
- return false;
-}
-
-bool CCensorNode::CheckPath(bool isAltStream, const UString &path, bool isFile) const
-{
- bool include;
- if (CheckPath2(isAltStream, path, isFile, include))
- return include;
- return false;
-}
-*/
-
-bool CCensorNode::CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const
-{
- if (CheckPathCurrent(include, pathParts, isFile))
- return true;
- if (Parent == 0)
- return false;
- pathParts.Insert(0, Name);
- return Parent->CheckPathToRoot(include, pathParts, isFile);
-}
-
-/*
-bool CCensorNode::CheckPathToRoot(bool include, const UString &path, bool isFile) const
-{
- UStringVector pathParts;
- SplitPathToParts(path, pathParts);
- return CheckPathToRoot(include, pathParts, isFile);
-}
-*/
-
-void CCensorNode::AddItem2(bool include, const UString &path, bool recursive, bool wildcardMatching)
-{
- if (path.IsEmpty())
- return;
- bool forFile = true;
- bool forFolder = true;
- UString path2 (path);
- if (IsPathSepar(path.Back()))
- {
- path2.DeleteBack();
- forFile = false;
- }
- AddItem(include, path2, recursive, forFile, forFolder, wildcardMatching);
-}
-
-void CCensorNode::ExtendExclude(const CCensorNode &fromNodes)
-{
- ExcludeItems += fromNodes.ExcludeItems;
- FOR_VECTOR (i, fromNodes.SubNodes)
- {
- const CCensorNode &node = fromNodes.SubNodes[i];
- int subNodeIndex = FindSubNode(node.Name);
- if (subNodeIndex < 0)
- subNodeIndex = SubNodes.Add(CCensorNode(node.Name, this));
- SubNodes[subNodeIndex].ExtendExclude(node);
- }
-}
-
-int CCensor::FindPrefix(const UString &prefix) const
-{
- FOR_VECTOR (i, Pairs)
- if (CompareFileNames(Pairs[i].Prefix, prefix) == 0)
- return i;
- return -1;
-}
-
-#ifdef _WIN32
-
-bool IsDriveColonName(const wchar_t *s)
-{
- wchar_t c = s[0];
- return c != 0 && s[1] == ':' && s[2] == 0 && (c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z');
-}
-
-unsigned GetNumPrefixParts_if_DrivePath(UStringVector &pathParts)
-{
- if (pathParts.IsEmpty())
- return 0;
-
- unsigned testIndex = 0;
- if (pathParts[0].IsEmpty())
- {
- if (pathParts.Size() < 4
- || !pathParts[1].IsEmpty()
- || pathParts[2] != L"?")
- return 0;
- testIndex = 3;
- }
- if (NWildcard::IsDriveColonName(pathParts[testIndex]))
- return testIndex + 1;
- return 0;
-}
-
-#endif
-
-static unsigned GetNumPrefixParts(const UStringVector &pathParts)
-{
- if (pathParts.IsEmpty())
- return 0;
-
- #ifdef _WIN32
-
- if (IsDriveColonName(pathParts[0]))
- return 1;
- if (!pathParts[0].IsEmpty())
- return 0;
-
- if (pathParts.Size() == 1)
- return 1;
- if (!pathParts[1].IsEmpty())
- return 1;
- if (pathParts.Size() == 2)
- return 2;
- if (pathParts[2] == L".")
- return 3;
-
- unsigned networkParts = 2;
- if (pathParts[2] == L"?")
- {
- if (pathParts.Size() == 3)
- return 3;
- if (IsDriveColonName(pathParts[3]))
- return 4;
- if (!pathParts[3].IsEqualTo_Ascii_NoCase("UNC"))
- return 3;
- networkParts = 4;
- }
-
- networkParts +=
- // 2; // server/share
- 1; // server
- if (pathParts.Size() <= networkParts)
- return pathParts.Size();
- return networkParts;
-
- #else
-
- return pathParts[0].IsEmpty() ? 1 : 0;
-
- #endif
-}
-
-void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &path, bool recursive, bool wildcardMatching)
-{
- if (path.IsEmpty())
- throw "Empty file path";
-
- UStringVector pathParts;
- SplitPathToParts(path, pathParts);
-
- bool forFile = true;
- if (pathParts.Back().IsEmpty())
- {
- forFile = false;
- pathParts.DeleteBack();
- }
-
- UString prefix;
-
- int ignoreWildcardIndex = -1;
-
- // #ifdef _WIN32
- // we ignore "?" wildcard in "\\?\" prefix.
- if (pathParts.Size() >= 3
- && pathParts[0].IsEmpty()
- && pathParts[1].IsEmpty()
- && pathParts[2] == L"?")
- ignoreWildcardIndex = 2;
- // #endif
-
- if (pathMode != k_AbsPath)
- {
- ignoreWildcardIndex = -1;
-
- const unsigned numPrefixParts = GetNumPrefixParts(pathParts);
- unsigned numSkipParts = numPrefixParts;
-
- if (pathMode != k_FullPath)
- {
- if (numPrefixParts != 0 && pathParts.Size() > numPrefixParts)
- numSkipParts = pathParts.Size() - 1;
- }
- {
- int dotsIndex = -1;
- for (unsigned i = numPrefixParts; i < pathParts.Size(); i++)
- {
- const UString &part = pathParts[i];
- if (part == L".." || part == L".")
- dotsIndex = i;
- }
-
- if (dotsIndex >= 0)
- if (dotsIndex == (int)pathParts.Size() - 1)
- numSkipParts = pathParts.Size();
- else
- numSkipParts = pathParts.Size() - 1;
- }
-
- for (unsigned i = 0; i < numSkipParts; i++)
- {
- {
- const UString &front = pathParts.Front();
- // WIN32 doesn't support wildcards in file names
- if (wildcardMatching)
- if (i >= numPrefixParts && DoesNameContainWildcard(front))
- break;
- prefix += front;
- prefix.Add_PathSepar();
- }
- pathParts.Delete(0);
- }
- }
-
- int index = FindPrefix(prefix);
- if (index < 0)
- index = Pairs.Add(CPair(prefix));
-
- if (pathMode != k_AbsPath)
- {
- if (pathParts.IsEmpty() || pathParts.Size() == 1 && pathParts[0].IsEmpty())
- {
- // we create universal item, if we skip all parts as prefix (like \ or L:\ )
- pathParts.Clear();
- pathParts.Add(UString("*"));
- forFile = true;
- wildcardMatching = true;
- recursive = false;
- }
- }
-
- CItem item;
- item.PathParts = pathParts;
- item.ForDir = true;
- item.ForFile = forFile;
- item.Recursive = recursive;
- item.WildcardMatching = wildcardMatching;
- Pairs[index].Head.AddItem(include, item, ignoreWildcardIndex);
-}
-
-/*
-bool CCensor::CheckPath(bool isAltStream, const UString &path, bool isFile) const
-{
- bool finded = false;
- FOR_VECTOR (i, Pairs)
- {
- bool include;
- if (Pairs[i].Head.CheckPath2(isAltStream, path, isFile, include))
- {
- if (!include)
- return false;
- finded = true;
- }
- }
- return finded;
-}
-*/
-
-void CCensor::ExtendExclude()
-{
- unsigned i;
- for (i = 0; i < Pairs.Size(); i++)
- if (Pairs[i].Prefix.IsEmpty())
- break;
- if (i == Pairs.Size())
- return;
- unsigned index = i;
- for (i = 0; i < Pairs.Size(); i++)
- if (index != i)
- Pairs[i].Head.ExtendExclude(Pairs[index].Head);
-}
-
-void CCensor::AddPathsToCensor(ECensorPathMode censorPathMode)
-{
- FOR_VECTOR(i, CensorPaths)
- {
- const CCensorPath &cp = CensorPaths[i];
- AddItem(censorPathMode, cp.Include, cp.Path, cp.Recursive, cp.WildcardMatching);
- }
- CensorPaths.Clear();
-}
-
-void CCensor::AddPreItem(bool include, const UString &path, bool recursive, bool wildcardMatching)
-{
- CCensorPath &cp = CensorPaths.AddNew();
- cp.Path = path;
- cp.Include = include;
- cp.Recursive = recursive;
- cp.WildcardMatching = wildcardMatching;
-}
-
-}
+// Common/Wildcard.cpp
+
+#include "StdAfx.h"
+
+#include "Wildcard.h"
+
+extern
+bool g_CaseSensitive;
+bool g_CaseSensitive =
+ #ifdef _WIN32
+ false;
+ #elif defined (__APPLE__)
+ #ifdef TARGET_OS_IPHONE
+ true;
+ #else
+ false;
+ #endif
+ #else
+ true;
+ #endif
+
+
+bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2)
+{
+ if (g_CaseSensitive)
+ return IsString1PrefixedByString2(s1, s2);
+ return IsString1PrefixedByString2_NoCase(s1, s2);
+}
+
+// #include <stdio.h>
+
+/*
+static int MyStringCompare_PathLinux(const wchar_t *s1, const wchar_t *s2) throw()
+{
+ for (;;)
+ {
+ wchar_t c1 = *s1++;
+ wchar_t c2 = *s2++;
+ if (c1 != c2)
+ {
+ if (c1 == 0) return -1;
+ if (c2 == 0) return 1;
+ if (c1 == '/') c1 = 0;
+ if (c2 == '/') c2 = 0;
+ if (c1 < c2) return -1;
+ if (c1 > c2) return 1;
+ continue;
+ }
+ if (c1 == 0) return 0;
+ }
+}
+*/
+
+static int MyStringCompare_Path(const wchar_t *s1, const wchar_t *s2) throw()
+{
+ for (;;)
+ {
+ wchar_t c1 = *s1++;
+ wchar_t c2 = *s2++;
+ if (c1 != c2)
+ {
+ if (c1 == 0) return -1;
+ if (c2 == 0) return 1;
+ if (IS_PATH_SEPAR(c1)) c1 = 0;
+ if (IS_PATH_SEPAR(c2)) c2 = 0;
+ if (c1 < c2) return -1;
+ if (c1 > c2) return 1;
+ continue;
+ }
+ if (c1 == 0) return 0;
+ }
+}
+
+static int MyStringCompareNoCase_Path(const wchar_t *s1, const wchar_t *s2) throw()
+{
+ for (;;)
+ {
+ wchar_t c1 = *s1++;
+ wchar_t c2 = *s2++;
+ if (c1 != c2)
+ {
+ if (c1 == 0) return -1;
+ if (c2 == 0) return 1;
+ if (IS_PATH_SEPAR(c1)) c1 = 0;
+ if (IS_PATH_SEPAR(c2)) c2 = 0;
+ c1 = MyCharUpper(c1);
+ c2 = MyCharUpper(c2);
+ if (c1 < c2) return -1;
+ if (c1 > c2) return 1;
+ continue;
+ }
+ if (c1 == 0) return 0;
+ }
+}
+
+int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW
+{
+ /*
+ printf("\nCompareFileNames");
+ printf("\n S1: %ls", s1);
+ printf("\n S2: %ls", s2);
+ printf("\n");
+ */
+ // 21.07 : we parse PATH_SEPARATOR so: 0 < PATH_SEPARATOR < 1
+ if (g_CaseSensitive)
+ return MyStringCompare_Path(s1, s2);
+ return MyStringCompareNoCase_Path(s1, s2);
+}
+
+#ifndef USE_UNICODE_FSTRING
+int CompareFileNames(const char *s1, const char *s2)
+{
+ const UString u1 = fs2us(s1);
+ const UString u2 = fs2us(s2);
+ return CompareFileNames(u1, u2);
+}
+#endif
+
+// -----------------------------------------
+// this function compares name with mask
+// ? - any char
+// * - any char or empty
+
+static bool EnhancedMaskTest(const wchar_t *mask, const wchar_t *name)
+{
+ for (;;)
+ {
+ const wchar_t m = *mask;
+ const wchar_t c = *name;
+ if (m == 0)
+ return (c == 0);
+ if (m == '*')
+ {
+ if (EnhancedMaskTest(mask + 1, name))
+ return true;
+ if (c == 0)
+ return false;
+ }
+ else
+ {
+ if (m == '?')
+ {
+ if (c == 0)
+ return false;
+ }
+ else if (m != c)
+ if (g_CaseSensitive || MyCharUpper(m) != MyCharUpper(c))
+ return false;
+ mask++;
+ }
+ name++;
+ }
+}
+
+// --------------------------------------------------
+// Splits path to strings
+
+void SplitPathToParts(const UString &path, UStringVector &pathParts)
+{
+ pathParts.Clear();
+ unsigned len = path.Len();
+ if (len == 0)
+ return;
+ UString name;
+ unsigned prev = 0;
+ for (unsigned i = 0; i < len; i++)
+ if (IsPathSepar(path[i]))
+ {
+ name.SetFrom(path.Ptr(prev), i - prev);
+ pathParts.Add(name);
+ prev = i + 1;
+ }
+ name.SetFrom(path.Ptr(prev), len - prev);
+ pathParts.Add(name);
+}
+
+void SplitPathToParts_2(const UString &path, UString &dirPrefix, UString &name)
+{
+ const wchar_t *start = path;
+ const wchar_t *p = start + path.Len();
+ for (; p != start; p--)
+ if (IsPathSepar(*(p - 1)))
+ break;
+ dirPrefix.SetFrom(path, (unsigned)(p - start));
+ name = p;
+}
+
+void SplitPathToParts_Smart(const UString &path, UString &dirPrefix, UString &name)
+{
+ const wchar_t *start = path;
+ const wchar_t *p = start + path.Len();
+ if (p != start)
+ {
+ if (IsPathSepar(*(p - 1)))
+ p--;
+ for (; p != start; p--)
+ if (IsPathSepar(*(p - 1)))
+ break;
+ }
+ dirPrefix.SetFrom(path, (unsigned)(p - start));
+ name = p;
+}
+
+/*
+UString ExtractDirPrefixFromPath(const UString &path)
+{
+ return path.Left(path.ReverseFind_PathSepar() + 1));
+}
+*/
+
+UString ExtractFileNameFromPath(const UString &path)
+{
+ return UString(path.Ptr((unsigned)(path.ReverseFind_PathSepar() + 1)));
+}
+
+
+bool DoesWildcardMatchName(const UString &mask, const UString &name)
+{
+ return EnhancedMaskTest(mask, name);
+}
+
+bool DoesNameContainWildcard(const UString &path)
+{
+ for (unsigned i = 0; i < path.Len(); i++)
+ {
+ wchar_t c = path[i];
+ if (c == '*' || c == '?')
+ return true;
+ }
+ return false;
+}
+
+
+// ----------------------------------------------------------'
+// NWildcard
+
+namespace NWildcard {
+
+/*
+
+M = MaskParts.Size();
+N = TestNameParts.Size();
+
+ File Dir
+ForFile rec M<=N [N-M, N) -
+!ForDir nonrec M=N [0, M) -
+
+ForDir rec M<N [0, M) ... [N-M-1, N-1) same as ForBoth-File
+!ForFile nonrec [0, M) same as ForBoth-File
+
+ForFile rec m<=N [0, M) ... [N-M, N) same as ForBoth-File
+ForDir nonrec [0, M) same as ForBoth-File
+
+*/
+
+bool CItem::AreAllAllowed() const
+{
+ return ForFile && ForDir && WildcardMatching && PathParts.Size() == 1 && PathParts.Front() == L"*";
+}
+
+bool CItem::CheckPath(const UStringVector &pathParts, bool isFile) const
+{
+ if (!isFile && !ForDir)
+ return false;
+
+ /*
+ if (PathParts.IsEmpty())
+ {
+ // PathParts.IsEmpty() means all items (universal wildcard)
+ if (!isFile)
+ return true;
+ if (pathParts.Size() <= 1)
+ return ForFile;
+ return (ForDir || Recursive && ForFile);
+ }
+ */
+
+ int delta = (int)pathParts.Size() - (int)PathParts.Size();
+ if (delta < 0)
+ return false;
+ int start = 0;
+ int finish = 0;
+
+ if (isFile)
+ {
+ if (!ForDir)
+ {
+ if (Recursive)
+ start = delta;
+ else if (delta !=0)
+ return false;
+ }
+ if (!ForFile && delta == 0)
+ return false;
+ }
+
+ if (Recursive)
+ {
+ finish = delta;
+ if (isFile && !ForFile)
+ finish = delta - 1;
+ }
+
+ for (int d = start; d <= finish; d++)
+ {
+ unsigned i;
+ for (i = 0; i < PathParts.Size(); i++)
+ {
+ if (WildcardMatching)
+ {
+ if (!DoesWildcardMatchName(PathParts[i], pathParts[i + (unsigned)d]))
+ break;
+ }
+ else
+ {
+ if (CompareFileNames(PathParts[i], pathParts[i + (unsigned)d]) != 0)
+ break;
+ }
+ }
+ if (i == PathParts.Size())
+ return true;
+ }
+ return false;
+}
+
+bool CCensorNode::AreAllAllowed() const
+{
+ if (!Name.IsEmpty() ||
+ !SubNodes.IsEmpty() ||
+ !ExcludeItems.IsEmpty() ||
+ IncludeItems.Size() != 1)
+ return false;
+ return IncludeItems.Front().AreAllAllowed();
+}
+
+int CCensorNode::FindSubNode(const UString &name) const
+{
+ FOR_VECTOR (i, SubNodes)
+ if (CompareFileNames(SubNodes[i].Name, name) == 0)
+ return (int)i;
+ return -1;
+}
+
+void CCensorNode::AddItemSimple(bool include, CItem &item)
+{
+ CObjectVector<CItem> &items = include ? IncludeItems : ExcludeItems;
+ items.Add(item);
+}
+
+void CCensorNode::AddItem(bool include, CItem &item, int ignoreWildcardIndex)
+{
+ if (item.PathParts.Size() <= 1)
+ {
+ if (item.PathParts.Size() != 0 && item.WildcardMatching)
+ {
+ if (!DoesNameContainWildcard(item.PathParts.Front()))
+ item.WildcardMatching = false;
+ }
+ AddItemSimple(include, item);
+ return;
+ }
+
+ const UString &front = item.PathParts.Front();
+
+ // WIN32 doesn't support wildcards in file names
+ if (item.WildcardMatching
+ && ignoreWildcardIndex != 0
+ && DoesNameContainWildcard(front))
+ {
+ AddItemSimple(include, item);
+ return;
+ }
+ CCensorNode &subNode = Find_SubNode_Or_Add_New(front);
+ item.PathParts.Delete(0);
+ subNode.AddItem(include, item, ignoreWildcardIndex - 1);
+}
+
+/*
+void CCensorNode::AddItem(bool include, const UString &path, const CCensorPathProps &props)
+{
+ CItem item;
+ SplitPathToParts(path, item.PathParts);
+ item.Recursive = props.Recursive;
+ item.ForFile = props.ForFile;
+ item.ForDir = props.ForDir;
+ item.WildcardMatching = props.WildcardMatching;
+ AddItem(include, item);
+}
+*/
+
+bool CCensorNode::NeedCheckSubDirs() const
+{
+ FOR_VECTOR (i, IncludeItems)
+ {
+ const CItem &item = IncludeItems[i];
+ if (item.Recursive || item.PathParts.Size() > 1)
+ return true;
+ }
+ return false;
+}
+
+bool CCensorNode::AreThereIncludeItems() const
+{
+ if (IncludeItems.Size() > 0)
+ return true;
+ FOR_VECTOR (i, SubNodes)
+ if (SubNodes[i].AreThereIncludeItems())
+ return true;
+ return false;
+}
+
+bool CCensorNode::CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const
+{
+ const CObjectVector<CItem> &items = include ? IncludeItems : ExcludeItems;
+ FOR_VECTOR (i, items)
+ if (items[i].CheckPath(pathParts, isFile))
+ return true;
+ return false;
+}
+
+bool CCensorNode::CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const
+{
+ if (CheckPathCurrent(false, pathParts, isFile))
+ {
+ include = false;
+ return true;
+ }
+ if (pathParts.Size() > 1)
+ {
+ int index = FindSubNode(pathParts.Front());
+ if (index >= 0)
+ {
+ UStringVector pathParts2 = pathParts;
+ pathParts2.Delete(0);
+ if (SubNodes[(unsigned)index].CheckPathVect(pathParts2, isFile, include))
+ return true;
+ }
+ }
+ bool finded = CheckPathCurrent(true, pathParts, isFile);
+ include = finded; // if (!finded), then (true) is allowed also
+ return finded;
+}
+
+/*
+bool CCensorNode::CheckPath2(bool isAltStream, const UString &path, bool isFile, bool &include) const
+{
+ UStringVector pathParts;
+ SplitPathToParts(path, pathParts);
+ if (CheckPathVect(pathParts, isFile, include))
+ {
+ if (!include || !isAltStream)
+ return true;
+ }
+ if (isAltStream && !pathParts.IsEmpty())
+ {
+ UString &back = pathParts.Back();
+ int pos = back.Find(L':');
+ if (pos > 0)
+ {
+ back.DeleteFrom(pos);
+ return CheckPathVect(pathParts, isFile, include);
+ }
+ }
+ return false;
+}
+
+bool CCensorNode::CheckPath(bool isAltStream, const UString &path, bool isFile) const
+{
+ bool include;
+ if (CheckPath2(isAltStream, path, isFile, include))
+ return include;
+ return false;
+}
+*/
+
+bool CCensorNode::CheckPathToRoot_Change(bool include, UStringVector &pathParts, bool isFile) const
+{
+ if (CheckPathCurrent(include, pathParts, isFile))
+ return true;
+ if (!Parent)
+ return false;
+ pathParts.Insert(0, Name);
+ return Parent->CheckPathToRoot_Change(include, pathParts, isFile);
+}
+
+bool CCensorNode::CheckPathToRoot(bool include, const UStringVector &pathParts, bool isFile) const
+{
+ if (CheckPathCurrent(include, pathParts, isFile))
+ return true;
+ if (!Parent)
+ return false;
+ UStringVector pathParts2;
+ pathParts2.Add(Name);
+ pathParts2 += pathParts;
+ return Parent->CheckPathToRoot_Change(include, pathParts2, isFile);
+}
+
+/*
+bool CCensorNode::CheckPathToRoot(bool include, const UString &path, bool isFile) const
+{
+ UStringVector pathParts;
+ SplitPathToParts(path, pathParts);
+ return CheckPathToRoot(include, pathParts, isFile);
+}
+*/
+
+void CCensorNode::ExtendExclude(const CCensorNode &fromNodes)
+{
+ ExcludeItems += fromNodes.ExcludeItems;
+ FOR_VECTOR (i, fromNodes.SubNodes)
+ {
+ const CCensorNode &node = fromNodes.SubNodes[i];
+ Find_SubNode_Or_Add_New(node.Name).ExtendExclude(node);
+ }
+}
+
+int CCensor::FindPairForPrefix(const UString &prefix) const
+{
+ FOR_VECTOR (i, Pairs)
+ if (CompareFileNames(Pairs[i].Prefix, prefix) == 0)
+ return (int)i;
+ return -1;
+}
+
+#ifdef _WIN32
+
+bool IsDriveColonName(const wchar_t *s)
+{
+ unsigned c = s[0];
+ c |= 0x20;
+ c -= 'a';
+ return c <= (unsigned)('z' - 'a') && s[1] == ':' && s[2] == 0;
+}
+
+unsigned GetNumPrefixParts_if_DrivePath(UStringVector &pathParts)
+{
+ if (pathParts.IsEmpty())
+ return 0;
+
+ unsigned testIndex = 0;
+ if (pathParts[0].IsEmpty())
+ {
+ if (pathParts.Size() < 4
+ || !pathParts[1].IsEmpty()
+ || pathParts[2] != L"?")
+ return 0;
+ testIndex = 3;
+ }
+ if (NWildcard::IsDriveColonName(pathParts[testIndex]))
+ return testIndex + 1;
+ return 0;
+}
+
+#endif
+
+static unsigned GetNumPrefixParts(const UStringVector &pathParts)
+{
+ if (pathParts.IsEmpty())
+ return 0;
+
+ /* empty last part could be removed already from (pathParts),
+ if there was tail path separator (slash) in original full path string. */
+
+ #ifdef _WIN32
+
+ if (IsDriveColonName(pathParts[0]))
+ return 1;
+ if (!pathParts[0].IsEmpty())
+ return 0;
+
+ if (pathParts.Size() == 1)
+ return 1;
+ if (!pathParts[1].IsEmpty())
+ return 1;
+ if (pathParts.Size() == 2)
+ return 2;
+ if (pathParts[2] == L".")
+ return 3;
+
+ unsigned networkParts = 2;
+ if (pathParts[2] == L"?")
+ {
+ if (pathParts.Size() == 3)
+ return 3;
+ if (IsDriveColonName(pathParts[3]))
+ return 4;
+ if (!pathParts[3].IsEqualTo_Ascii_NoCase("UNC"))
+ return 3;
+ networkParts = 4;
+ }
+
+ networkParts +=
+ // 2; // server/share
+ 1; // server
+ if (pathParts.Size() <= networkParts)
+ return pathParts.Size();
+ return networkParts;
+
+ #else
+
+ return pathParts[0].IsEmpty() ? 1 : 0;
+
+ #endif
+}
+
+void CCensor::AddItem(ECensorPathMode pathMode, bool include, const UString &path,
+ const CCensorPathProps &props)
+{
+ if (path.IsEmpty())
+ throw "Empty file path";
+
+ UStringVector pathParts;
+ SplitPathToParts(path, pathParts);
+
+ CCensorPathProps props2 = props;
+
+ bool forFile = true;
+ bool forDir = true;
+ const UString &back = pathParts.Back();
+ if (back.IsEmpty())
+ {
+ // we have tail path separator. So it's directory.
+ // we delete tail path separator here even for "\" and "c:\"
+ forFile = false;
+ pathParts.DeleteBack();
+ }
+ else
+ {
+ if (props.MarkMode == kMark_StrictFile
+ || (props.MarkMode == kMark_StrictFile_IfWildcard
+ && DoesNameContainWildcard(back)))
+ forDir = false;
+ }
+
+
+ UString prefix;
+
+ int ignoreWildcardIndex = -1;
+
+ // #ifdef _WIN32
+ // we ignore "?" wildcard in "\\?\" prefix.
+ if (pathParts.Size() >= 3
+ && pathParts[0].IsEmpty()
+ && pathParts[1].IsEmpty()
+ && pathParts[2] == L"?")
+ ignoreWildcardIndex = 2;
+ // #endif
+
+ if (pathMode != k_AbsPath)
+ {
+ // detection of the number of Skip Parts for prefix
+ ignoreWildcardIndex = -1;
+
+ const unsigned numPrefixParts = GetNumPrefixParts(pathParts);
+ unsigned numSkipParts = numPrefixParts;
+
+ if (pathMode != k_FullPath)
+ {
+ // if absolute path, then all parts before last part will be in prefix
+ if (numPrefixParts != 0 && pathParts.Size() > numPrefixParts)
+ numSkipParts = pathParts.Size() - 1;
+ }
+ {
+ int dotsIndex = -1;
+ for (unsigned i = numPrefixParts; i < pathParts.Size(); i++)
+ {
+ const UString &part = pathParts[i];
+ if (part == L".." || part == L".")
+ dotsIndex = (int)i;
+ }
+
+ if (dotsIndex >= 0)
+ {
+ if (dotsIndex == (int)pathParts.Size() - 1)
+ numSkipParts = pathParts.Size();
+ else
+ numSkipParts = pathParts.Size() - 1;
+ }
+ }
+
+ // we split (pathParts) to (prefix) and (pathParts).
+ for (unsigned i = 0; i < numSkipParts; i++)
+ {
+ {
+ const UString &front = pathParts.Front();
+ // WIN32 doesn't support wildcards in file names
+ if (props.WildcardMatching)
+ if (i >= numPrefixParts && DoesNameContainWildcard(front))
+ break;
+ prefix += front;
+ prefix.Add_PathSepar();
+ }
+ pathParts.Delete(0);
+ }
+ }
+
+ int index = FindPairForPrefix(prefix);
+ if (index < 0)
+ {
+ index = (int)Pairs.Size();
+ Pairs.AddNew().Prefix = prefix;
+ }
+
+ if (pathMode != k_AbsPath)
+ {
+ if (pathParts.IsEmpty() || (pathParts.Size() == 1 && pathParts[0].IsEmpty()))
+ {
+ // we create universal item, if we skip all parts as prefix (like \ or L:\ )
+ pathParts.Clear();
+ pathParts.Add(UString("*"));
+ forFile = true;
+ forDir = true;
+ props2.WildcardMatching = true;
+ props2.Recursive = false;
+ }
+ }
+
+ /*
+ // not possible now
+ if (!forDir && !forFile)
+ {
+ UString s ("file path was blocked for files and directories: ");
+ s += path;
+ throw s;
+ // return; // for debug : ignore item (don't create Item)
+ }
+ */
+
+ CItem item;
+ item.PathParts = pathParts;
+ item.ForDir = forDir;
+ item.ForFile = forFile;
+ item.Recursive = props2.Recursive;
+ item.WildcardMatching = props2.WildcardMatching;
+ Pairs[(unsigned)index].Head.AddItem(include, item, ignoreWildcardIndex);
+}
+
+/*
+bool CCensor::CheckPath(bool isAltStream, const UString &path, bool isFile) const
+{
+ bool finded = false;
+ FOR_VECTOR (i, Pairs)
+ {
+ bool include;
+ if (Pairs[i].Head.CheckPath2(isAltStream, path, isFile, include))
+ {
+ if (!include)
+ return false;
+ finded = true;
+ }
+ }
+ return finded;
+}
+*/
+
+void CCensor::ExtendExclude()
+{
+ unsigned i;
+ for (i = 0; i < Pairs.Size(); i++)
+ if (Pairs[i].Prefix.IsEmpty())
+ break;
+ if (i == Pairs.Size())
+ return;
+ unsigned index = i;
+ for (i = 0; i < Pairs.Size(); i++)
+ if (index != i)
+ Pairs[i].Head.ExtendExclude(Pairs[index].Head);
+}
+
+void CCensor::AddPathsToCensor(ECensorPathMode censorPathMode)
+{
+ FOR_VECTOR(i, CensorPaths)
+ {
+ const CCensorPath &cp = CensorPaths[i];
+ AddItem(censorPathMode, cp.Include, cp.Path, cp.Props);
+ }
+ CensorPaths.Clear();
+}
+
+void CCensor::AddPreItem(bool include, const UString &path, const CCensorPathProps &props)
+{
+ CCensorPath &cp = CensorPaths.AddNew();
+ cp.Path = path;
+ cp.Include = include;
+ cp.Props = props;
+}
+
+}
diff --git a/CPP/Common/Wildcard.h b/CPP/Common/Wildcard.h
index 6e5f013..4f81da9 100644
--- a/CPP/Common/Wildcard.h
+++ b/CPP/Common/Wildcard.h
@@ -1,149 +1,231 @@
-// Common/Wildcard.h
-
-#ifndef __COMMON_WILDCARD_H
-#define __COMMON_WILDCARD_H
-
-#include "MyString.h"
-
-int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW;
-#ifndef USE_UNICODE_FSTRING
- int CompareFileNames(const char *s1, const char *s2);
-#endif
-
-bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2);
-
-void SplitPathToParts(const UString &path, UStringVector &pathParts);
-void SplitPathToParts_2(const UString &path, UString &dirPrefix, UString &name);
-void SplitPathToParts_Smart(const UString &path, UString &dirPrefix, UString &name); // ignores dir delimiter at the end of (path)
-
-UString ExtractDirPrefixFromPath(const UString &path);
-UString ExtractFileNameFromPath(const UString &path);
-
-bool DoesNameContainWildcard(const UString &path);
-bool DoesWildcardMatchName(const UString &mask, const UString &name);
-
-namespace NWildcard {
-
-#ifdef _WIN32
-// returns true, if name is like "a:", "c:", ...
-bool IsDriveColonName(const wchar_t *s);
-unsigned GetNumPrefixParts_if_DrivePath(UStringVector &pathParts);
-#endif
-
-struct CItem
-{
- UStringVector PathParts;
- bool Recursive;
- bool ForFile;
- bool ForDir;
- bool WildcardMatching;
-
- #ifdef _WIN32
- bool IsDriveItem() const
- {
- return PathParts.Size() == 1 && !ForFile && ForDir && IsDriveColonName(PathParts[0]);
- }
- #endif
-
- // CItem(): WildcardMatching(true) {}
-
- bool AreAllAllowed() const;
- bool CheckPath(const UStringVector &pathParts, bool isFile) const;
-};
-
-class CCensorNode
-{
- CCensorNode *Parent;
-
- bool CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const;
- void AddItemSimple(bool include, CItem &item);
-public:
- bool CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const;
-
- CCensorNode(): Parent(0) { };
- CCensorNode(const UString &name, CCensorNode *parent): Name(name), Parent(parent) { };
-
- UString Name; // WIN32 doesn't support wildcards in file names
- CObjectVector<CCensorNode> SubNodes;
- CObjectVector<CItem> IncludeItems;
- CObjectVector<CItem> ExcludeItems;
-
- bool AreAllAllowed() const;
-
- int FindSubNode(const UString &path) const;
-
- void AddItem(bool include, CItem &item, int ignoreWildcardIndex = -1);
- void AddItem(bool include, const UString &path, bool recursive, bool forFile, bool forDir, bool wildcardMatching);
- void AddItem2(bool include, const UString &path, bool recursive, bool wildcardMatching);
-
- bool NeedCheckSubDirs() const;
- bool AreThereIncludeItems() const;
-
- // bool CheckPath2(bool isAltStream, const UString &path, bool isFile, bool &include) const;
- // bool CheckPath(bool isAltStream, const UString &path, bool isFile) const;
-
- bool CheckPathToRoot(bool include, UStringVector &pathParts, bool isFile) const;
- // bool CheckPathToRoot(const UString &path, bool isFile, bool include) const;
- void ExtendExclude(const CCensorNode &fromNodes);
-};
-
-struct CPair
-{
- UString Prefix;
- CCensorNode Head;
-
- CPair(const UString &prefix): Prefix(prefix) { };
-};
-
-enum ECensorPathMode
-{
- k_RelatPath, // absolute prefix as Prefix, remain path in Tree
- k_FullPath, // drive prefix as Prefix, remain path in Tree
- k_AbsPath // full path in Tree
-};
-
-struct CCensorPath
-{
- UString Path;
- bool Include;
- bool Recursive;
- bool WildcardMatching;
-
- CCensorPath():
- Include(true),
- Recursive(false),
- WildcardMatching(true)
- {}
-};
-
-class CCensor
-{
- int FindPrefix(const UString &prefix) const;
-public:
- CObjectVector<CPair> Pairs;
-
- CObjectVector<NWildcard::CCensorPath> CensorPaths;
-
- bool AllAreRelative() const
- { return (Pairs.Size() == 1 && Pairs.Front().Prefix.IsEmpty()); }
-
- void AddItem(ECensorPathMode pathMode, bool include, const UString &path, bool recursive, bool wildcardMatching);
- // bool CheckPath(bool isAltStream, const UString &path, bool isFile) const;
- void ExtendExclude();
-
- void AddPathsToCensor(NWildcard::ECensorPathMode censorPathMode);
- void AddPreItem(bool include, const UString &path, bool recursive, bool wildcardMatching);
- void AddPreItem(const UString &path)
- {
- AddPreItem(true, path, false, false);
- }
- void AddPreItem_Wildcard()
- {
- AddPreItem(true, UString("*"), false, true);
- }
-};
-
-
-}
-
-#endif
+// Common/Wildcard.h
+
+#ifndef ZIP7_INC_COMMON_WILDCARD_H
+#define ZIP7_INC_COMMON_WILDCARD_H
+
+#include "MyString.h"
+
+int CompareFileNames(const wchar_t *s1, const wchar_t *s2) STRING_UNICODE_THROW;
+#ifndef USE_UNICODE_FSTRING
+ int CompareFileNames(const char *s1, const char *s2);
+#endif
+
+bool IsPath1PrefixedByPath2(const wchar_t *s1, const wchar_t *s2);
+
+void SplitPathToParts(const UString &path, UStringVector &pathParts);
+void SplitPathToParts_2(const UString &path, UString &dirPrefix, UString &name);
+void SplitPathToParts_Smart(const UString &path, UString &dirPrefix, UString &name); // ignores dir delimiter at the end of (path)
+
+UString ExtractDirPrefixFromPath(const UString &path);
+UString ExtractFileNameFromPath(const UString &path);
+
+bool DoesNameContainWildcard(const UString &path);
+bool DoesWildcardMatchName(const UString &mask, const UString &name);
+
+namespace NWildcard {
+
+#ifdef _WIN32
+// returns true, if name is like "a:", "c:", ...
+bool IsDriveColonName(const wchar_t *s);
+unsigned GetNumPrefixParts_if_DrivePath(UStringVector &pathParts);
+#endif
+
+struct CItem
+{
+ UStringVector PathParts;
+ bool Recursive;
+ bool ForFile;
+ bool ForDir;
+ bool WildcardMatching;
+
+ #ifdef _WIN32
+ bool IsDriveItem() const
+ {
+ return PathParts.Size() == 1 && !ForFile && ForDir && IsDriveColonName(PathParts[0]);
+ }
+ #endif
+
+ // CItem(): WildcardMatching(true) {}
+
+ bool AreAllAllowed() const;
+ bool CheckPath(const UStringVector &pathParts, bool isFile) const;
+};
+
+
+
+const Byte kMark_FileOrDir = 0;
+const Byte kMark_StrictFile = 1;
+const Byte kMark_StrictFile_IfWildcard = 2;
+
+struct CCensorPathProps
+{
+ bool Recursive;
+ bool WildcardMatching;
+ Byte MarkMode;
+
+ CCensorPathProps():
+ Recursive(false),
+ WildcardMatching(true),
+ MarkMode(kMark_FileOrDir)
+ {}
+};
+
+
+class CCensorNode MY_UNCOPYABLE
+{
+ CCensorNode *Parent;
+
+ bool CheckPathCurrent(bool include, const UStringVector &pathParts, bool isFile) const;
+ void AddItemSimple(bool include, CItem &item);
+public:
+ // bool ExcludeDirItems;
+
+ CCensorNode():
+ Parent(NULL)
+ // , ExcludeDirItems(false)
+ {}
+
+ CCensorNode(const UString &name, CCensorNode *parent):
+ Parent(parent)
+ // , ExcludeDirItems(false)
+ , Name(name)
+ {}
+
+ UString Name; // WIN32 doesn't support wildcards in file names
+ CObjectVector<CCensorNode> SubNodes;
+ CObjectVector<CItem> IncludeItems;
+ CObjectVector<CItem> ExcludeItems;
+
+ CCensorNode &Find_SubNode_Or_Add_New(const UString &name)
+ {
+ int i = FindSubNode(name);
+ if (i >= 0)
+ return SubNodes[(unsigned)i];
+ // return SubNodes.Add(CCensorNode(name, this));
+ CCensorNode &node = SubNodes.AddNew();
+ node.Parent = this;
+ node.Name = name;
+ return node;
+ }
+
+ bool AreAllAllowed() const;
+
+ int FindSubNode(const UString &path) const;
+
+ void AddItem(bool include, CItem &item, int ignoreWildcardIndex = -1);
+ // void AddItem(bool include, const UString &path, const CCensorPathProps &props);
+ void Add_Wildcard()
+ {
+ CItem item;
+ item.PathParts.Add(L"*");
+ item.Recursive = false;
+ item.ForFile = true;
+ item.ForDir = true;
+ item.WildcardMatching = true;
+ AddItem(
+ true // include
+ , item);
+ }
+
+ // NeedCheckSubDirs() returns true, if there are IncludeItems rules that affect items in subdirs
+ bool NeedCheckSubDirs() const;
+ bool AreThereIncludeItems() const;
+
+ /*
+ CheckPathVect() doesn't check path in Parent CCensorNode
+ so use CheckPathVect() for root CCensorNode
+ OUT:
+ returns (true) && (include = false) - file in exlude list
+ returns (true) && (include = true) - file in include list and is not in exlude list
+ returns (false) - file is not in (include/exlude) list
+ */
+ bool CheckPathVect(const UStringVector &pathParts, bool isFile, bool &include) const;
+
+ // bool CheckPath2(bool isAltStream, const UString &path, bool isFile, bool &include) const;
+ // bool CheckPath(bool isAltStream, const UString &path, bool isFile) const;
+
+ // CheckPathToRoot_Change() changes pathParts !!!
+ bool CheckPathToRoot_Change(bool include, UStringVector &pathParts, bool isFile) const;
+ bool CheckPathToRoot(bool include, const UStringVector &pathParts, bool isFile) const;
+
+ // bool CheckPathToRoot(const UString &path, bool isFile, bool include) const;
+ void ExtendExclude(const CCensorNode &fromNodes);
+};
+
+
+struct CPair MY_UNCOPYABLE
+{
+ UString Prefix;
+ CCensorNode Head;
+
+ // CPair(const UString &prefix): Prefix(prefix) { };
+};
+
+
+enum ECensorPathMode
+{
+ k_RelatPath, // absolute prefix as Prefix, remain path in Tree
+ k_FullPath, // drive prefix as Prefix, remain path in Tree
+ k_AbsPath // full path in Tree
+};
+
+
+struct CCensorPath
+{
+ UString Path;
+ bool Include;
+ CCensorPathProps Props;
+
+ CCensorPath():
+ Include(true)
+ {}
+};
+
+
+class CCensor MY_UNCOPYABLE
+{
+ int FindPairForPrefix(const UString &prefix) const;
+public:
+ CObjectVector<CPair> Pairs;
+
+ bool ExcludeDirItems;
+ bool ExcludeFileItems;
+
+ CCensor():
+ ExcludeDirItems(false),
+ ExcludeFileItems(false)
+ {}
+
+ CObjectVector<NWildcard::CCensorPath> CensorPaths;
+
+ bool AllAreRelative() const
+ { return (Pairs.Size() == 1 && Pairs.Front().Prefix.IsEmpty()); }
+
+ void AddItem(ECensorPathMode pathMode, bool include, const UString &path, const CCensorPathProps &props);
+ // bool CheckPath(bool isAltStream, const UString &path, bool isFile) const;
+ void ExtendExclude();
+
+ void AddPathsToCensor(NWildcard::ECensorPathMode censorPathMode);
+ void AddPreItem(bool include, const UString &path, const CCensorPathProps &props);
+
+ void AddPreItem_NoWildcard(const UString &path)
+ {
+ CCensorPathProps props;
+ props.WildcardMatching = false;
+ AddPreItem(
+ true, // include
+ path, props);
+ }
+ void AddPreItem_Wildcard()
+ {
+ CCensorPathProps props;
+ // props.WildcardMatching = true;
+ AddPreItem(
+ true, // include
+ UString("*"), props);
+ }
+};
+
+}
+
+#endif
diff --git a/CPP/Common/XzCrc64Init.cpp b/CPP/Common/XzCrc64Init.cpp
index 1eae72a..5cb8e67 100644
--- a/CPP/Common/XzCrc64Init.cpp
+++ b/CPP/Common/XzCrc64Init.cpp
@@ -1,7 +1,7 @@
-// XzCrc64Init.cpp
-
-#include "StdAfx.h"
-
-#include "../../C/XzCrc64.h"
-
-static struct CCrc64Gen { CCrc64Gen() { Crc64GenerateTable(); } } g_Crc64TableInit;
+// XzCrc64Init.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/XzCrc64.h"
+
+static struct CCrc64Gen { CCrc64Gen() { Crc64GenerateTable(); } } g_Crc64TableInit;
diff --git a/CPP/Common/XzCrc64Reg.cpp b/CPP/Common/XzCrc64Reg.cpp
index 92fce0a..e9e67ef 100644
--- a/CPP/Common/XzCrc64Reg.cpp
+++ b/CPP/Common/XzCrc64Reg.cpp
@@ -1,42 +1,39 @@
-// XzCrc64Reg.cpp
-
-#include "StdAfx.h"
-
-#include "../../C/CpuArch.h"
-#include "../../C/XzCrc64.h"
-
-#include "../Common/MyCom.h"
-
-#include "../7zip/Common/RegisterCodec.h"
-
-class CXzCrc64Hasher:
- public IHasher,
- public CMyUnknownImp
-{
- UInt64 _crc;
- Byte mtDummy[1 << 7];
-
-public:
- CXzCrc64Hasher(): _crc(CRC64_INIT_VAL) {}
-
- MY_UNKNOWN_IMP1(IHasher)
- INTERFACE_IHasher(;)
-};
-
-STDMETHODIMP_(void) CXzCrc64Hasher::Init() throw()
-{
- _crc = CRC64_INIT_VAL;
-}
-
-STDMETHODIMP_(void) CXzCrc64Hasher::Update(const void *data, UInt32 size) throw()
-{
- _crc = Crc64Update(_crc, data, size);
-}
-
-STDMETHODIMP_(void) CXzCrc64Hasher::Final(Byte *digest) throw()
-{
- UInt64 val = CRC64_GET_DIGEST(_crc);
- SetUi64(digest, val);
-}
-
-REGISTER_HASHER(CXzCrc64Hasher, 0x4, "CRC64", 8)
+// XzCrc64Reg.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/CpuArch.h"
+#include "../../C/XzCrc64.h"
+
+#include "../Common/MyCom.h"
+
+#include "../7zip/Common/RegisterCodec.h"
+
+Z7_CLASS_IMP_COM_1(
+ CXzCrc64Hasher
+ , IHasher
+)
+ UInt64 _crc;
+public:
+ Byte _mtDummy[1 << 7]; // it's public to eliminate clang warning: unused private field
+
+ CXzCrc64Hasher(): _crc(CRC64_INIT_VAL) {}
+};
+
+Z7_COM7F_IMF2(void, CXzCrc64Hasher::Init())
+{
+ _crc = CRC64_INIT_VAL;
+}
+
+Z7_COM7F_IMF2(void, CXzCrc64Hasher::Update(const void *data, UInt32 size))
+{
+ _crc = Crc64Update(_crc, data, size);
+}
+
+Z7_COM7F_IMF2(void, CXzCrc64Hasher::Final(Byte *digest))
+{
+ const UInt64 val = CRC64_GET_DIGEST(_crc);
+ SetUi64(digest, val)
+}
+
+REGISTER_HASHER(CXzCrc64Hasher, 0x4, "CRC64", 8)
diff --git a/CPP/Windows/COM.cpp b/CPP/Windows/COM.cpp
new file mode 100644
index 0000000..d0cb321
--- /dev/null
+++ b/CPP/Windows/COM.cpp
@@ -0,0 +1,41 @@
+// Windows/COM.cpp
+
+#include "StdAfx.h"
+
+/*
+
+#include "COM.h"
+#include "../Common/StringConvert.h"
+
+namespace NWindows {
+namespace NCOM {
+
+// CoInitialize (NULL); must be called!
+
+UString GUIDToStringW(REFGUID guid)
+{
+ UString s;
+ const unsigned kSize = 48;
+ StringFromGUID2(guid, s.GetBuf(kSize), kSize);
+ s.ReleaseBuf_CalcLen(kSize);
+ return s;
+}
+
+AString GUIDToStringA(REFGUID guid)
+{
+ return UnicodeStringToMultiByte(GUIDToStringW(guid));
+}
+
+HRESULT StringToGUIDW(const wchar_t *string, GUID &classID)
+{
+ return CLSIDFromString((wchar_t *)string, &classID);
+}
+
+HRESULT StringToGUIDA(const char *string, GUID &classID)
+{
+ return StringToGUIDW(MultiByteToUnicodeString(string), classID);
+}
+
+}}
+
+*/
diff --git a/CPP/Windows/COM.h b/CPP/Windows/COM.h
index e2cb002..a8780ca 100644
--- a/CPP/Windows/COM.h
+++ b/CPP/Windows/COM.h
@@ -1,70 +1,86 @@
-// Windows/COM.h
-
-#ifndef __WINDOWS_COM_H
-#define __WINDOWS_COM_H
-
-#include "../Common/MyString.h"
-
-namespace NWindows {
-namespace NCOM {
-
-#ifdef _WIN32
-
-class CComInitializer
-{
-public:
- CComInitializer()
- {
- #ifdef UNDER_CE
- CoInitializeEx(NULL, COINIT_MULTITHREADED);
- #else
- // it's single thread. Do we need multithread?
- CoInitialize(NULL);
- #endif
- };
- ~CComInitializer() { CoUninitialize(); }
-};
-
-class CStgMedium
-{
- STGMEDIUM _object;
-public:
- bool _mustBeReleased;
- CStgMedium(): _mustBeReleased(false) {}
- ~CStgMedium() { Free(); }
- void Free()
- {
- if (_mustBeReleased)
- ReleaseStgMedium(&_object);
- _mustBeReleased = false;
- }
- const STGMEDIUM* operator->() const { return &_object;}
- STGMEDIUM* operator->() { return &_object;}
- STGMEDIUM* operator&() { return &_object; }
-};
-
-#endif
-
-/*
-//////////////////////////////////
-// GUID <--> String Conversions
-UString GUIDToStringW(REFGUID guid);
-AString GUIDToStringA(REFGUID guid);
-#ifdef UNICODE
- #define GUIDToString GUIDToStringW
-#else
- #define GUIDToString GUIDToStringA
-#endif
-
-HRESULT StringToGUIDW(const wchar_t *string, GUID &classID);
-HRESULT StringToGUIDA(const char *string, GUID &classID);
-#ifdef UNICODE
- #define StringToGUID StringToGUIDW
-#else
- #define StringToGUID StringToGUIDA
-#endif
-*/
-
-}}
-
-#endif
+// Windows/COM.h
+
+#ifndef ZIP7_INC_WINDOWS_COM_H
+#define ZIP7_INC_WINDOWS_COM_H
+
+// #include "../Common/MyString.h"
+
+namespace NWindows {
+namespace NCOM {
+
+#ifdef _WIN32
+
+class CComInitializer
+{
+public:
+ CComInitializer()
+ {
+ #ifdef UNDER_CE
+ CoInitializeEx(NULL, COINIT_MULTITHREADED);
+ #else
+ // it's single thread. Do we need multithread?
+ CoInitialize(NULL);
+ #endif
+ }
+ ~CComInitializer() { CoUninitialize(); }
+};
+
+/*
+class CStgMedium2
+{
+ STGMEDIUM _object;
+ bool _mustBeReleased;
+public:
+ CStgMedium2(): _mustBeReleased(false) {}
+ ~CStgMedium2() { Free(); }
+ void Free()
+ {
+ if (_mustBeReleased)
+ ReleaseStgMedium(&_object);
+ _mustBeReleased = false;
+ }
+ const STGMEDIUM* operator->() const { return &_object;}
+ STGMEDIUM* operator->() { return &_object;}
+ STGMEDIUM* operator&() { return &_object; }
+};
+*/
+
+struct CStgMedium: public STGMEDIUM
+{
+ CStgMedium()
+ {
+ tymed = TYMED_NULL; // 0
+ hGlobal = NULL;
+ pUnkForRelease = NULL;
+ }
+ ~CStgMedium()
+ {
+ ReleaseStgMedium(this);
+ }
+};
+
+#endif
+
+/*
+//////////////////////////////////
+// GUID <--> String Conversions
+UString GUIDToStringW(REFGUID guid);
+AString GUIDToStringA(REFGUID guid);
+#ifdef UNICODE
+ #define GUIDToString GUIDToStringW
+#else
+ #define GUIDToString GUIDToStringA
+#endif
+
+HRESULT StringToGUIDW(const wchar_t *string, GUID &classID);
+HRESULT StringToGUIDA(const char *string, GUID &classID);
+#ifdef UNICODE
+ #define StringToGUID StringToGUIDW
+#else
+ #define StringToGUID StringToGUIDA
+#endif
+*/
+
+}}
+
+#endif
diff --git a/CPP/Windows/Clipboard.cpp b/CPP/Windows/Clipboard.cpp
new file mode 100644
index 0000000..bc7e201
--- /dev/null
+++ b/CPP/Windows/Clipboard.cpp
@@ -0,0 +1,130 @@
+// Windows/Clipboard.cpp
+
+#include "StdAfx.h"
+
+#ifdef UNDER_CE
+#include <winuserm.h>
+#endif
+
+#include "../Common/StringConvert.h"
+
+#include "Clipboard.h"
+#include "Defs.h"
+#include "MemoryGlobal.h"
+#include "Shell.h"
+
+namespace NWindows {
+
+bool CClipboard::Open(HWND wndNewOwner) throw()
+{
+ m_Open = BOOLToBool(::OpenClipboard(wndNewOwner));
+ return m_Open;
+}
+
+bool CClipboard::Close() throw()
+{
+ if (!m_Open)
+ return true;
+ m_Open = !BOOLToBool(CloseClipboard());
+ return !m_Open;
+}
+
+bool ClipboardIsFormatAvailableHDROP()
+{
+ return BOOLToBool(IsClipboardFormatAvailable(CF_HDROP));
+}
+
+/*
+bool ClipboardGetTextString(AString &s)
+{
+ s.Empty();
+ if (!IsClipboardFormatAvailable(CF_TEXT))
+ return false;
+ CClipboard clipboard;
+
+ if (!clipboard.Open(NULL))
+ return false;
+
+ HGLOBAL h = ::GetClipboardData(CF_TEXT);
+ if (h != NULL)
+ {
+ NMemory::CGlobalLock globalLock(h);
+ const char *p = (const char *)globalLock.GetPointer();
+ if (p != NULL)
+ {
+ s = p;
+ return true;
+ }
+ }
+ return false;
+}
+*/
+
+/*
+bool ClipboardGetFileNames(UStringVector &names)
+{
+ names.Clear();
+ if (!IsClipboardFormatAvailable(CF_HDROP))
+ return false;
+ CClipboard clipboard;
+
+ if (!clipboard.Open(NULL))
+ return false;
+
+ HGLOBAL h = ::GetClipboardData(CF_HDROP);
+ if (h != NULL)
+ {
+ NMemory::CGlobalLock globalLock(h);
+ void *p = (void *)globalLock.GetPointer();
+ if (p != NULL)
+ {
+ NShell::CDrop drop(false);
+ drop.Attach((HDROP)p);
+ drop.QueryFileNames(names);
+ return true;
+ }
+ }
+ return false;
+}
+*/
+
+static bool ClipboardSetData(UINT uFormat, const void *data, size_t size) throw()
+{
+ NMemory::CGlobal global;
+ if (!global.Alloc(GMEM_DDESHARE | GMEM_MOVEABLE, size))
+ return false;
+ {
+ NMemory::CGlobalLock globalLock(global);
+ LPVOID p = globalLock.GetPointer();
+ if (!p)
+ return false;
+ memcpy(p, data, size);
+ }
+ if (::SetClipboardData(uFormat, global) == NULL)
+ return false;
+ global.Detach();
+ return true;
+}
+
+bool ClipboardSetText(HWND owner, const UString &s)
+{
+ CClipboard clipboard;
+ if (!clipboard.Open(owner))
+ return false;
+ if (!::EmptyClipboard())
+ return false;
+
+ bool res;
+ res = ClipboardSetData(CF_UNICODETEXT, (const wchar_t *)s, (s.Len() + 1) * sizeof(wchar_t));
+ #ifndef _UNICODE
+ AString a (UnicodeStringToMultiByte(s, CP_ACP));
+ if (ClipboardSetData(CF_TEXT, (const char *)a, (a.Len() + 1) * sizeof(char)))
+ res = true;
+ a = UnicodeStringToMultiByte(s, CP_OEMCP);
+ if (ClipboardSetData(CF_OEMTEXT, (const char *)a, (a.Len() + 1) * sizeof(char)))
+ res = true;
+ #endif
+ return res;
+}
+
+}
diff --git a/CPP/Windows/Clipboard.h b/CPP/Windows/Clipboard.h
new file mode 100644
index 0000000..3b4f2fe
--- /dev/null
+++ b/CPP/Windows/Clipboard.h
@@ -0,0 +1,28 @@
+// Windows/Clipboard.h
+
+#ifndef ZIP7_INC_CLIPBOARD_H
+#define ZIP7_INC_CLIPBOARD_H
+
+#include "../Common/MyString.h"
+
+namespace NWindows {
+
+class CClipboard
+{
+ bool m_Open;
+public:
+ CClipboard(): m_Open(false) {}
+ ~CClipboard() { Close(); }
+ bool Open(HWND wndNewOwner) throw();
+ bool Close() throw();
+};
+
+bool ClipboardIsFormatAvailableHDROP();
+
+// bool ClipboardGetFileNames(UStringVector &names);
+// bool ClipboardGetTextString(AString &s);
+bool ClipboardSetText(HWND owner, const UString &s);
+
+}
+
+#endif
diff --git a/CPP/Windows/CommonDialog.cpp b/CPP/Windows/CommonDialog.cpp
index 8b3828c..7a92d5f 100644
--- a/CPP/Windows/CommonDialog.cpp
+++ b/CPP/Windows/CommonDialog.cpp
@@ -1,185 +1,269 @@
-// Windows/CommonDialog.cpp
-
-#include "StdAfx.h"
-
-#include "../Common/MyWindows.h"
-
-#ifdef UNDER_CE
-#include <commdlg.h>
-#endif
-
-#ifndef _UNICODE
-#include "../Common/StringConvert.h"
-#endif
-
-#include "CommonDialog.h"
-#include "Defs.h"
-
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-namespace NWindows {
-
-#ifndef _UNICODE
-
-class CDoubleZeroStringListA
-{
- LPTSTR Buf;
- unsigned Size;
-public:
- CDoubleZeroStringListA(LPSTR buf, unsigned size): Buf(buf), Size(size) {}
- bool Add(LPCSTR s) throw();
- void Finish() { *Buf = 0; }
-};
-
-bool CDoubleZeroStringListA::Add(LPCSTR s) throw()
-{
- unsigned len = MyStringLen(s) + 1;
- if (len >= Size)
- return false;
- MyStringCopy(Buf, s);
- Buf += len;
- Size -= len;
- return true;
-}
-
-#endif
-
-class CDoubleZeroStringListW
-{
- LPWSTR Buf;
- unsigned Size;
-public:
- CDoubleZeroStringListW(LPWSTR buf, unsigned size): Buf(buf), Size(size) {}
- bool Add(LPCWSTR s) throw();
- void Finish() { *Buf = 0; }
-};
-
-bool CDoubleZeroStringListW::Add(LPCWSTR s) throw()
-{
- unsigned len = MyStringLen(s) + 1;
- if (len >= Size)
- return false;
- MyStringCopy(Buf, s);
- Buf += len;
- Size -= len;
- return true;
-}
-
-#define MY__OFN_PROJECT 0x00400000
-#define MY__OFN_SHOW_ALL 0x01000000
-
-/* if (lpstrFilter == NULL && nFilterIndex == 0)
- MSDN : "the system doesn't show any files",
- but WinXP-64 shows all files. Why ??? */
-
-/*
-structures
- OPENFILENAMEW
- OPENFILENAMEA
-contain additional members:
-#if (_WIN32_WINNT >= 0x0500)
- void *pvReserved;
- DWORD dwReserved;
- DWORD FlagsEx;
-#endif
-
-If we compile the source code with (_WIN32_WINNT >= 0x0500), some functions
-will not work at NT 4.0, if we use sizeof(OPENFILENAME*).
-So we use size of old version of structure. */
-
-#if defined(UNDER_CE) || defined(_WIN64) || (_WIN32_WINNT < 0x0500)
-// || !defined(WINVER)
- #define my_compatib_OPENFILENAMEA_size sizeof(OPENFILENAMEA)
- #define my_compatib_OPENFILENAMEW_size sizeof(OPENFILENAMEW)
-#else
- #define my_compatib_OPENFILENAMEA_size OPENFILENAME_SIZE_VERSION_400A
- #define my_compatib_OPENFILENAMEW_size OPENFILENAME_SIZE_VERSION_400W
-#endif
-
-#define CONV_U_To_A(dest, src, temp) AString temp; if (src) { temp = GetSystemString(src); dest = temp; }
-
-bool MyGetOpenFileName(HWND hwnd, LPCWSTR title,
- LPCWSTR initialDir,
- LPCWSTR filePath,
- LPCWSTR filterDescription,
- LPCWSTR filter,
- UString &resPath
- #ifdef UNDER_CE
- , bool openFolder
- #endif
- )
-{
- const unsigned kBufSize = MAX_PATH * 2;
- const unsigned kFilterBufSize = MAX_PATH;
- if (!filter)
- filter = L"*.*";
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- CHAR buf[kBufSize];
- MyStringCopy(buf, (const char *)GetSystemString(filePath));
- // OPENFILENAME_NT4A
- OPENFILENAMEA p;
- memset(&p, 0, sizeof(p));
- p.lStructSize = my_compatib_OPENFILENAMEA_size;
- p.hwndOwner = hwnd;
- CHAR filterBuf[kFilterBufSize];
- {
- CDoubleZeroStringListA dz(filterBuf, kFilterBufSize);
- dz.Add(GetSystemString(filterDescription ? filterDescription : filter));
- dz.Add(GetSystemString(filter));
- dz.Finish();
- p.lpstrFilter = filterBuf;
- p.nFilterIndex = 1;
- }
-
- p.lpstrFile = buf;
- p.nMaxFile = kBufSize;
- CONV_U_To_A(p.lpstrInitialDir, initialDir, initialDirA);
- CONV_U_To_A(p.lpstrTitle, title, titleA);
- p.Flags = OFN_EXPLORER | OFN_HIDEREADONLY;
-
- bool res = BOOLToBool(::GetOpenFileNameA(&p));
- resPath = GetUnicodeString(buf);
- return res;
- }
- else
- #endif
- {
- WCHAR buf[kBufSize];
- MyStringCopy(buf, filePath);
- // OPENFILENAME_NT4W
- OPENFILENAMEW p;
- memset(&p, 0, sizeof(p));
- p.lStructSize = my_compatib_OPENFILENAMEW_size;
- p.hwndOwner = hwnd;
-
- WCHAR filterBuf[kFilterBufSize];
- {
- CDoubleZeroStringListW dz(filterBuf, kFilterBufSize);
- dz.Add(filterDescription ? filterDescription : filter);
- dz.Add(filter);
- dz.Finish();
- p.lpstrFilter = filterBuf;
- p.nFilterIndex = 1;
- }
-
- p.lpstrFile = buf;
- p.nMaxFile = kBufSize;
- p.lpstrInitialDir = initialDir;
- p.lpstrTitle = title;
- p.Flags = OFN_EXPLORER | OFN_HIDEREADONLY
- #ifdef UNDER_CE
- | (openFolder ? (MY__OFN_PROJECT | MY__OFN_SHOW_ALL) : 0)
- #endif
- ;
-
- bool res = BOOLToBool(::GetOpenFileNameW(&p));
- resPath = buf;
- return res;
- }
-}
-
-}
+// Windows/CommonDialog.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/MyBuffer.h"
+
+#ifdef UNDER_CE
+#include <commdlg.h>
+#endif
+
+#ifndef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+
+#include "CommonDialog.h"
+#include "Defs.h"
+// #include "FileDir.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+
+/*
+ GetSaveFileName()
+ GetOpenFileName()
+ OPENFILENAME
+
+(lpstrInitialDir) : the initial directory.
+DOCs: the algorithm for selecting the initial directory varies on different platforms:
+{
+ Win2000/XP/Vista:
+ 1. If lpstrFile contains a path, that path is the initial directory.
+ 2. Otherwise, lpstrInitialDir specifies the initial directory.
+
+ Win7:
+ If lpstrInitialDir has the same value as was passed the first time
+ the application used an Open or Save As dialog box, the path
+ most recently selected by the user is used as the initial directory.
+}
+
+Win10:
+ in:
+ function supports (lpstrInitialDir) path with super prefix "\\\\?\\"
+ function supports (lpstrInitialDir) path with long path
+ function doesn't support absolute (lpstrFile) path with super prefix "\\\\?\\"
+ function doesn't support absolute (lpstrFile) path with long path
+ out: the path with super prefix "\\\\?\\" will be returned, if selected path is long
+
+WinXP-64 and Win10: if no filters, the system shows all files.
+ but DOCs say: If all three members are zero or NULL,
+ the system does not use any filters and does not
+ show any files in the file list control of the dialog box.
+
+in Win7+: GetOpenFileName() and GetSaveFileName()
+ do not support pstrCustomFilter feature anymore
+*/
+
+#ifdef UNDER_CE
+#define MY_OFN_PROJECT 0x00400000
+#define MY_OFN_SHOW_ALL 0x01000000
+#endif
+
+
+/*
+structures
+ OPENFILENAMEW
+ OPENFILENAMEA
+contain additional members:
+#if (_WIN32_WINNT >= 0x0500)
+ void *pvReserved;
+ DWORD dwReserved;
+ DWORD FlagsEx;
+#endif
+
+If we compile the source code with (_WIN32_WINNT >= 0x0500), some functions
+will not work at NT 4.0, if we use sizeof(OPENFILENAME).
+We try to use reduced structure OPENFILENAME_NT4.
+*/
+
+// #if defined(_WIN64) || (defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500)
+#if defined(__GNUC__) && (__GNUC__ <= 9) || defined(Z7_OLD_WIN_SDK)
+ #ifndef _UNICODE
+ #define my_compatib_OPENFILENAMEA OPENFILENAMEA
+ #endif
+ #define my_compatib_OPENFILENAMEW OPENFILENAMEW
+
+ // MinGW doesn't support some required macros. So we define them here:
+ #ifndef CDSIZEOF_STRUCT
+ #define CDSIZEOF_STRUCT(structname, member) (((int)((LPBYTE)(&((structname*)0)->member) - ((LPBYTE)((structname*)0)))) + sizeof(((structname*)0)->member))
+ #endif
+ #ifndef _UNICODE
+ #ifndef OPENFILENAME_SIZE_VERSION_400A
+ #define OPENFILENAME_SIZE_VERSION_400A CDSIZEOF_STRUCT(OPENFILENAMEA,lpTemplateName)
+ #endif
+ #endif
+ #ifndef OPENFILENAME_SIZE_VERSION_400W
+ #define OPENFILENAME_SIZE_VERSION_400W CDSIZEOF_STRUCT(OPENFILENAMEW,lpTemplateName)
+ #endif
+
+ #ifndef _UNICODE
+ #define my_compatib_OPENFILENAMEA_size OPENFILENAME_SIZE_VERSION_400A
+ #endif
+ #define my_compatib_OPENFILENAMEW_size OPENFILENAME_SIZE_VERSION_400W
+#else
+ #ifndef _UNICODE
+ #define my_compatib_OPENFILENAMEA OPENFILENAME_NT4A
+ #define my_compatib_OPENFILENAMEA_size sizeof(my_compatib_OPENFILENAMEA)
+ #endif
+ #define my_compatib_OPENFILENAMEW OPENFILENAME_NT4W
+ #define my_compatib_OPENFILENAMEW_size sizeof(my_compatib_OPENFILENAMEW)
+#endif
+/*
+#elif defined(UNDER_CE) || defined(_WIN64) || (_WIN32_WINNT < 0x0500)
+// || !defined(WINVER)
+ #ifndef _UNICODE
+ #define my_compatib_OPENFILENAMEA OPENFILENAMEA
+ #define my_compatib_OPENFILENAMEA_size sizeof(OPENFILENAMEA)
+ #endif
+ #define my_compatib_OPENFILENAMEW OPENFILENAMEW
+ #define my_compatib_OPENFILENAMEW_size sizeof(OPENFILENAMEW)
+#else
+
+#endif
+*/
+
+#ifndef _UNICODE
+#define CONV_U_To_A(dest, src, temp) AString temp; if (src) { temp = GetSystemString(src); dest = temp; }
+#endif
+
+bool CCommonDialogInfo::CommonDlg_BrowseForFile(LPCWSTR lpstrInitialDir, const UStringVector &filters)
+{
+ /* GetSaveFileName() and GetOpenFileName() could change current dir,
+ if OFN_NOCHANGEDIR is not used.
+ We can restore current dir manually, if it's required.
+ 22.02: we use OFN_NOCHANGEDIR. So we don't need to restore current dir manually. */
+ // NFile::NDir::CCurrentDirRestorer curDirRestorer;
+
+#ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ AString tempPath;
+ AStringVector f;
+ unsigned i;
+ for (i = 0; i < filters.Size(); i++)
+ f.Add(GetSystemString(filters[i]));
+ unsigned size = f.Size() + 1;
+ for (i = 0; i < f.Size(); i++)
+ size += f[i].Len();
+ CObjArray<char> filterBuf(size);
+ // memset(filterBuf, 0, size * sizeof(char));
+ {
+ char *dest = filterBuf;
+ for (i = 0; i < f.Size(); i++)
+ {
+ const AString &s = f[i];
+ MyStringCopy(dest, s);
+ dest += s.Len() + 1;
+ }
+ *dest = 0;
+ }
+ my_compatib_OPENFILENAMEA p;
+ memset(&p, 0, sizeof(p));
+ p.lStructSize = my_compatib_OPENFILENAMEA_size;
+ p.hwndOwner = hwndOwner;
+ if (size > 1)
+ {
+ p.lpstrFilter = filterBuf;
+ p.nFilterIndex = (DWORD)(FilterIndex + 1);
+ }
+
+ CONV_U_To_A(p.lpstrInitialDir, lpstrInitialDir, initialDir_a)
+ CONV_U_To_A(p.lpstrTitle, lpstrTitle, title_a)
+
+ const AString filePath_a = GetSystemString(FilePath);
+ const unsigned bufSize = MAX_PATH * 8
+ + filePath_a.Len()
+ + initialDir_a.Len();
+ p.nMaxFile = bufSize;
+ p.lpstrFile = tempPath.GetBuf(bufSize);
+ MyStringCopy(p.lpstrFile, filePath_a);
+ p.Flags =
+ OFN_EXPLORER
+ | OFN_HIDEREADONLY
+ | OFN_NOCHANGEDIR;
+ const BOOL b = SaveMode ?
+ ::GetSaveFileNameA((LPOPENFILENAMEA)(void *)&p) :
+ ::GetOpenFileNameA((LPOPENFILENAMEA)(void *)&p);
+ if (!b)
+ return false;
+ {
+ tempPath.ReleaseBuf_CalcLen(bufSize);
+ FilePath = GetUnicodeString(tempPath);
+ FilterIndex = (int)p.nFilterIndex - 1;
+ return true;
+ }
+ }
+ else
+#endif
+ {
+ UString tempPath;
+ unsigned size = filters.Size() + 1;
+ unsigned i;
+ for (i = 0; i < filters.Size(); i++)
+ size += filters[i].Len();
+ CObjArray<wchar_t> filterBuf(size);
+ // memset(filterBuf, 0, size * sizeof(wchar_t));
+ {
+ wchar_t *dest = filterBuf;
+ for (i = 0; i < filters.Size(); i++)
+ {
+ const UString &s = filters[i];
+ MyStringCopy(dest, s);
+ dest += s.Len() + 1;
+ }
+ *dest = 0;
+ // if ((unsigned)(dest + 1 - filterBuf) != size) return false;
+ }
+ my_compatib_OPENFILENAMEW p;
+ memset(&p, 0, sizeof(p));
+ p.lStructSize = my_compatib_OPENFILENAMEW_size;
+ p.hwndOwner = hwndOwner;
+ if (size > 1)
+ {
+ p.lpstrFilter = filterBuf;
+ p.nFilterIndex = (DWORD)(FilterIndex + 1);
+ }
+ unsigned bufSize = MAX_PATH * 8 + FilePath.Len();
+ if (lpstrInitialDir)
+ {
+ p.lpstrInitialDir = lpstrInitialDir;
+ bufSize += MyStringLen(lpstrInitialDir);
+ }
+ p.nMaxFile = bufSize;
+ p.lpstrFile = tempPath.GetBuf(bufSize);
+ MyStringCopy(p.lpstrFile, FilePath);
+ p.lpstrTitle = lpstrTitle;
+ p.Flags =
+ OFN_EXPLORER
+ | OFN_HIDEREADONLY
+ | OFN_NOCHANGEDIR
+ // | OFN_FORCESHOWHIDDEN // Win10 shows hidden items even without this flag
+ // | OFN_PATHMUSTEXIST
+ #ifdef UNDER_CE
+ | (OpenFolderMode ? (MY_OFN_PROJECT | MY_OFN_SHOW_ALL) : 0)
+ #endif
+ ;
+ const BOOL b = SaveMode ?
+ ::GetSaveFileNameW((LPOPENFILENAMEW)(void *)&p) :
+ ::GetOpenFileNameW((LPOPENFILENAMEW)(void *)&p);
+ /* DOCs: lpstrFile :
+ if the buffer is too small, then:
+ - the function returns FALSE
+ - the CommDlgExtendedError() returns FNERR_BUFFERTOOSMALL
+ - the first two bytes of the lpstrFile buffer contain the
+ required size, in bytes or characters. */
+ if (!b)
+ return false;
+ {
+ tempPath.ReleaseBuf_CalcLen(bufSize);
+ FilePath = tempPath;
+ FilterIndex = (int)p.nFilterIndex - 1;
+ return true;
+ }
+ }
+}
+
+}
diff --git a/CPP/Windows/CommonDialog.h b/CPP/Windows/CommonDialog.h
index 2bfec28..85b071f 100644
--- a/CPP/Windows/CommonDialog.h
+++ b/CPP/Windows/CommonDialog.h
@@ -1,23 +1,43 @@
-// Windows/CommonDialog.h
-
-#ifndef __WINDOWS_COMMON_DIALOG_H
-#define __WINDOWS_COMMON_DIALOG_H
-
-#include "../Common/MyString.h"
-
-namespace NWindows {
-
-bool MyGetOpenFileName(HWND hwnd, LPCWSTR title,
- LPCWSTR initialDir, // can be NULL, so dir prefix in filePath will be used
- LPCWSTR filePath, // full path
- LPCWSTR filterDescription, // like "All files (*.*)"
- LPCWSTR filter, // like "*.exe"
- UString &resPath
- #ifdef UNDER_CE
- , bool openFolder = false
- #endif
-);
-
-}
-
-#endif
+// Windows/CommonDialog.h
+
+#ifndef ZIP7_INC_WINDOWS_COMMON_DIALOG_H
+#define ZIP7_INC_WINDOWS_COMMON_DIALOG_H
+
+#include "../Common/MyString.h"
+
+namespace NWindows {
+
+struct CCommonDialogInfo
+{
+ /* (FilterIndex == -1) means no selected filter.
+ and (-1) also is reserved for unsupported custom filter.
+ if (FilterIndex >= 0), then FilterIndex is index of filter */
+ int FilterIndex; // [in / out]
+ bool SaveMode;
+ #ifdef UNDER_CE
+ bool OpenFolderMode;
+ #endif
+ HWND hwndOwner;
+ // LPCWSTR lpstrInitialDir;
+ LPCWSTR lpstrTitle;
+ UString FilePath; // [in / out]
+
+ CCommonDialogInfo()
+ {
+ FilterIndex = -1;
+ SaveMode = false;
+ #ifdef UNDER_CE
+ OpenFolderMode = false;
+ #endif
+ hwndOwner = NULL;
+ // lpstrInitialDir = NULL;
+ lpstrTitle = NULL;
+ }
+
+ /* (filters) : 2 sequential vector strings (Description, Masks) represent each filter */
+ bool CommonDlg_BrowseForFile(LPCWSTR lpstrInitialDir, const UStringVector &filters);
+};
+
+}
+
+#endif
diff --git a/CPP/Windows/Console.cpp b/CPP/Windows/Console.cpp
new file mode 100644
index 0000000..28ba1c4
--- /dev/null
+++ b/CPP/Windows/Console.cpp
@@ -0,0 +1,10 @@
+// Windows/Console.cpp
+
+#include "StdAfx.h"
+
+#include "Console.h"
+
+namespace NWindows{
+namespace NConsole{
+
+}}
diff --git a/CPP/Windows/Console.h b/CPP/Windows/Console.h
new file mode 100644
index 0000000..818b8d4
--- /dev/null
+++ b/CPP/Windows/Console.h
@@ -0,0 +1,52 @@
+// Windows/Console.h
+
+#ifndef ZIP7_INC_WINDOWS_CONSOLE_H
+#define ZIP7_INC_WINDOWS_CONSOLE_H
+
+#include "Defs.h"
+
+namespace NWindows {
+namespace NConsole {
+
+class CBase
+{
+protected:
+ HANDLE m_Object;
+public:
+ void Attach(HANDLE handle) { m_Object = handle; }
+ bool GetMode(DWORD &mode)
+ { return BOOLToBool(::GetConsoleMode(m_Object, &mode)); }
+ bool SetMode(DWORD mode)
+ { return BOOLToBool(::SetConsoleMode(m_Object, mode)); }
+};
+
+class CIn: public CBase
+{
+public:
+ bool PeekEvents(PINPUT_RECORD events, DWORD numEvents, DWORD &numEventsRead)
+ { return BOOLToBool(::PeekConsoleInput(m_Object, events, numEvents, &numEventsRead)); }
+ bool PeekEvent(INPUT_RECORD &event, DWORD &numEventsRead)
+ { return PeekEvents(&event, 1, numEventsRead); }
+ bool ReadEvents(PINPUT_RECORD events, DWORD numEvents, DWORD &numEventsRead)
+ { return BOOLToBool(::ReadConsoleInput(m_Object, events, numEvents, &numEventsRead)); }
+ bool ReadEvent(INPUT_RECORD &event, DWORD &numEventsRead)
+ { return ReadEvents(&event, 1, numEventsRead); }
+ bool GetNumberOfEvents(DWORD &numEvents)
+ { return BOOLToBool(::GetNumberOfConsoleInputEvents(m_Object, &numEvents)); }
+
+ bool WriteEvents(const INPUT_RECORD *events, DWORD numEvents, DWORD &numEventsWritten)
+ { return BOOLToBool(::WriteConsoleInput(m_Object, events, numEvents, &numEventsWritten)); }
+ bool WriteEvent(const INPUT_RECORD &event, DWORD &numEventsWritten)
+ { return WriteEvents(&event, 1, numEventsWritten); }
+
+ bool Read(LPVOID buffer, DWORD numChars, DWORD &numCharsRead)
+ { return BOOLToBool(::ReadConsole(m_Object, buffer, numChars, &numCharsRead, NULL)); }
+
+ bool Flush()
+ { return BOOLToBool(::FlushConsoleInputBuffer(m_Object)); }
+
+};
+
+}}
+
+#endif
diff --git a/CPP/Windows/Control/ComboBox.cpp b/CPP/Windows/Control/ComboBox.cpp
index 6ab4717..8da487d 100644
--- a/CPP/Windows/Control/ComboBox.cpp
+++ b/CPP/Windows/Control/ComboBox.cpp
@@ -1,66 +1,66 @@
-// Windows/Control/ComboBox.cpp
-
-#include "StdAfx.h"
-
-#ifndef _UNICODE
-#include "../../Common/StringConvert.h"
-#endif
-
-#include "ComboBox.h"
-
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-namespace NWindows {
-namespace NControl {
-
-LRESULT CComboBox::GetLBText(int index, CSysString &s)
-{
- s.Empty();
- LRESULT len = GetLBTextLen(index); // length, excluding the terminating null character
- if (len == CB_ERR)
- return len;
- LRESULT len2 = GetLBText(index, s.GetBuf((unsigned)len));
- if (len2 == CB_ERR)
- return len;
- if (len > len2)
- len = len2;
- s.ReleaseBuf_CalcLen((unsigned)len);
- return len;
-}
-
-#ifndef _UNICODE
-LRESULT CComboBox::AddString(LPCWSTR s)
-{
- if (g_IsNT)
- return SendMsgW(CB_ADDSTRING, 0, (LPARAM)s);
- return AddString(GetSystemString(s));
-}
-
-LRESULT CComboBox::GetLBText(int index, UString &s)
-{
- s.Empty();
- if (g_IsNT)
- {
- LRESULT len = SendMsgW(CB_GETLBTEXTLEN, index, 0);
- if (len == CB_ERR)
- return len;
- LRESULT len2 = SendMsgW(CB_GETLBTEXT, index, (LPARAM)s.GetBuf((unsigned)len));
- if (len2 == CB_ERR)
- return len;
- if (len > len2)
- len = len2;
- s.ReleaseBuf_CalcLen((unsigned)len);
- return len;
- }
- AString sa;
- LRESULT len = GetLBText(index, sa);
- if (len == CB_ERR)
- return len;
- s = GetUnicodeString(sa);
- return s.Len();
-}
-#endif
-
-}}
+// Windows/Control/ComboBox.cpp
+
+#include "StdAfx.h"
+
+#ifndef _UNICODE
+#include "../../Common/StringConvert.h"
+#endif
+
+#include "ComboBox.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NControl {
+
+LRESULT CComboBox::GetLBText(int index, CSysString &s)
+{
+ s.Empty();
+ LRESULT len = GetLBTextLen(index); // length, excluding the terminating null character
+ if (len == CB_ERR)
+ return len;
+ LRESULT len2 = GetLBText(index, s.GetBuf((unsigned)len));
+ if (len2 == CB_ERR)
+ return len;
+ if (len > len2)
+ len = len2;
+ s.ReleaseBuf_CalcLen((unsigned)len);
+ return len;
+}
+
+#ifndef _UNICODE
+LRESULT CComboBox::AddString(LPCWSTR s)
+{
+ if (g_IsNT)
+ return SendMsgW(CB_ADDSTRING, 0, (LPARAM)s);
+ return AddString(GetSystemString(s));
+}
+
+LRESULT CComboBox::GetLBText(int index, UString &s)
+{
+ s.Empty();
+ if (g_IsNT)
+ {
+ LRESULT len = SendMsgW(CB_GETLBTEXTLEN, MY_int_TO_WPARAM(index), 0);
+ if (len == CB_ERR)
+ return len;
+ LRESULT len2 = SendMsgW(CB_GETLBTEXT, MY_int_TO_WPARAM(index), (LPARAM)s.GetBuf((unsigned)len));
+ if (len2 == CB_ERR)
+ return len;
+ if (len > len2)
+ len = len2;
+ s.ReleaseBuf_CalcLen((unsigned)len);
+ return len;
+ }
+ AString sa;
+ const LRESULT len = GetLBText(index, sa);
+ if (len == CB_ERR)
+ return len;
+ s = GetUnicodeString(sa);
+ return (LRESULT)s.Len();
+}
+#endif
+
+}}
diff --git a/CPP/Windows/Control/ComboBox.h b/CPP/Windows/Control/ComboBox.h
index 3439655..2a60b8a 100644
--- a/CPP/Windows/Control/ComboBox.h
+++ b/CPP/Windows/Control/ComboBox.h
@@ -1,65 +1,77 @@
-// Windows/Control/ComboBox.h
-
-#ifndef __WINDOWS_CONTROL_COMBOBOX_H
-#define __WINDOWS_CONTROL_COMBOBOX_H
-
-#include "../../Common/MyWindows.h"
-
-#include <commctrl.h>
-
-#include "../Window.h"
-
-namespace NWindows {
-namespace NControl {
-
-class CComboBox: public CWindow
-{
-public:
- void ResetContent() { SendMsg(CB_RESETCONTENT, 0, 0); }
- LRESULT AddString(LPCTSTR s) { return SendMsg(CB_ADDSTRING, 0, (LPARAM)s); }
- #ifndef _UNICODE
- LRESULT AddString(LPCWSTR s);
- #endif
- LRESULT SetCurSel(int index) { return SendMsg(CB_SETCURSEL, index, 0); }
- int GetCurSel() { return (int)SendMsg(CB_GETCURSEL, 0, 0); }
- int GetCount() { return (int)SendMsg(CB_GETCOUNT, 0, 0); }
-
- LRESULT GetLBTextLen(int index) { return SendMsg(CB_GETLBTEXTLEN, index, 0); }
- LRESULT GetLBText(int index, LPTSTR s) { return SendMsg(CB_GETLBTEXT, index, (LPARAM)s); }
- LRESULT GetLBText(int index, CSysString &s);
- #ifndef _UNICODE
- LRESULT GetLBText(int index, UString &s);
- #endif
-
- LRESULT SetItemData(int index, LPARAM lParam) { return SendMsg(CB_SETITEMDATA, index, lParam); }
- LRESULT GetItemData(int index) { return SendMsg(CB_GETITEMDATA, index, 0); }
-
- LRESULT GetItemData_of_CurSel() { return GetItemData(GetCurSel()); }
-
- void ShowDropDown(bool show = true) { SendMsg(CB_SHOWDROPDOWN, show ? TRUE : FALSE, 0); }
-};
-
-#ifndef UNDER_CE
-
-class CComboBoxEx: public CComboBox
-{
-public:
- bool SetUnicodeFormat(bool fUnicode) { return LRESULTToBool(SendMsg(CBEM_SETUNICODEFORMAT, BOOLToBool(fUnicode), 0)); }
-
- LRESULT DeleteItem(int index) { return SendMsg(CBEM_DELETEITEM, index, 0); }
- LRESULT InsertItem(COMBOBOXEXITEM *item) { return SendMsg(CBEM_INSERTITEM, 0, (LPARAM)item); }
- #ifndef _UNICODE
- LRESULT InsertItem(COMBOBOXEXITEMW *item) { return SendMsg(CBEM_INSERTITEMW, 0, (LPARAM)item); }
- #endif
-
- LRESULT SetItem(COMBOBOXEXITEM *item) { return SendMsg(CBEM_SETITEM, 0, (LPARAM)item); }
- DWORD SetExtendedStyle(DWORD exMask, DWORD exStyle) { return (DWORD)SendMsg(CBEM_SETEXTENDEDSTYLE, exMask, exStyle); }
- HWND GetEditControl() { return (HWND)SendMsg(CBEM_GETEDITCONTROL, 0, 0); }
- HIMAGELIST SetImageList(HIMAGELIST imageList) { return (HIMAGELIST)SendMsg(CBEM_SETIMAGELIST, 0, (LPARAM)imageList); }
-};
-
-#endif
-
-}}
-
-#endif
+// Windows/Control/ComboBox.h
+
+#ifndef ZIP7_INC_WINDOWS_CONTROL_COMBOBOX_H
+#define ZIP7_INC_WINDOWS_CONTROL_COMBOBOX_H
+
+#include "../../Common/MyWindows.h"
+
+#include <CommCtrl.h>
+
+#include "../Window.h"
+
+namespace NWindows {
+namespace NControl {
+
+class CComboBox: public CWindow
+{
+public:
+ void ResetContent() { SendMsg(CB_RESETCONTENT, 0, 0); }
+ LRESULT AddString(LPCTSTR s) { return SendMsg(CB_ADDSTRING, 0, (LPARAM)s); }
+ #ifndef _UNICODE
+ LRESULT AddString(LPCWSTR s);
+ #endif
+
+ /* If this parameter is -1, any current selection in the list is removed and the edit control is cleared.*/
+ LRESULT SetCurSel(int index) { return SendMsg(CB_SETCURSEL, MY_int_TO_WPARAM(index), 0); }
+ LRESULT SetCurSel(unsigned index) { return SendMsg(CB_SETCURSEL, index, 0); }
+
+ /* If no item is selected, it returns CB_ERR (-1) */
+ int GetCurSel() { return (int)SendMsg(CB_GETCURSEL, 0, 0); }
+
+ /* If an error occurs, it is CB_ERR (-1) */
+ int GetCount() { return (int)SendMsg(CB_GETCOUNT, 0, 0); }
+
+ LRESULT GetLBTextLen(int index) { return SendMsg(CB_GETLBTEXTLEN, MY_int_TO_WPARAM(index), 0); }
+ LRESULT GetLBText(int index, LPTSTR s) { return SendMsg(CB_GETLBTEXT, MY_int_TO_WPARAM(index), (LPARAM)s); }
+ LRESULT GetLBText(int index, CSysString &s);
+ #ifndef _UNICODE
+ LRESULT GetLBText(int index, UString &s);
+ #endif
+
+ LRESULT SetItemData(int index, LPARAM lParam) { return SendMsg(CB_SETITEMDATA, MY_int_TO_WPARAM(index), lParam); }
+ LRESULT GetItemData(int index) { return SendMsg(CB_GETITEMDATA, MY_int_TO_WPARAM(index), 0); }
+ LRESULT GetItemData(unsigned index) { return SendMsg(CB_GETITEMDATA, index, 0); }
+
+ LRESULT GetItemData_of_CurSel() { return GetItemData(GetCurSel()); }
+
+ void ShowDropDown(bool show = true) { SendMsg(CB_SHOWDROPDOWN, show ? TRUE : FALSE, 0); }
+};
+
+#ifndef UNDER_CE
+
+class CComboBoxEx: public CComboBox
+{
+public:
+ bool SetUnicodeFormat(bool fUnicode) { return LRESULTToBool(SendMsg(CBEM_SETUNICODEFORMAT, BOOLToBool(fUnicode), 0)); }
+
+ /* Returns:
+ an INT value that represents the number of items remaining in the control.
+ If (index) is invalid, the message returns CB_ERR. */
+ LRESULT DeleteItem(int index) { return SendMsg(CBEM_DELETEITEM, MY_int_TO_WPARAM(index), 0); }
+
+ LRESULT InsertItem(COMBOBOXEXITEM *item) { return SendMsg(CBEM_INSERTITEM, 0, (LPARAM)item); }
+ #ifndef _UNICODE
+ LRESULT InsertItem(COMBOBOXEXITEMW *item) { return SendMsg(CBEM_INSERTITEMW, 0, (LPARAM)item); }
+ #endif
+
+ LRESULT SetItem(COMBOBOXEXITEM *item) { return SendMsg(CBEM_SETITEM, 0, (LPARAM)item); }
+ DWORD SetExtendedStyle(DWORD exMask, DWORD exStyle) { return (DWORD)SendMsg(CBEM_SETEXTENDEDSTYLE, exMask, (LPARAM)exStyle); }
+ HWND GetEditControl() { return (HWND)SendMsg(CBEM_GETEDITCONTROL, 0, 0); }
+ HIMAGELIST SetImageList(HIMAGELIST imageList) { return (HIMAGELIST)SendMsg(CBEM_SETIMAGELIST, 0, (LPARAM)imageList); }
+};
+
+#endif
+
+}}
+
+#endif
diff --git a/CPP/Windows/Control/CommandBar.h b/CPP/Windows/Control/CommandBar.h
index c435568..d1b2f17 100644
--- a/CPP/Windows/Control/CommandBar.h
+++ b/CPP/Windows/Control/CommandBar.h
@@ -1,52 +1,52 @@
-// Windows/Control/CommandBar.h
-
-#ifndef __WINDOWS_CONTROL_COMMANDBAR_H
-#define __WINDOWS_CONTROL_COMMANDBAR_H
-
-#ifdef UNDER_CE
-
-#include "../../Common/MyWindows.h"
-
-#include <commctrl.h>
-
-#include "../Window.h"
-
-namespace NWindows {
-namespace NControl {
-
-class CCommandBar: public NWindows::CWindow
-{
-public:
- bool Create(HINSTANCE hInst, HWND hwndParent, int idCmdBar)
- {
- _window = ::CommandBar_Create(hInst, hwndParent, idCmdBar);
- return (_window != NULL);
- }
-
- // Macros
- // void Destroy() { CommandBar_Destroy(_window); }
- // bool AddButtons(UINT numButtons, LPTBBUTTON buttons) { return BOOLToBool(SendMsg(TB_ADDBUTTONS, (WPARAM)numButtons, (LPARAM)buttons)); }
- bool InsertButton(int iButton, LPTBBUTTON button) { return BOOLToBool(SendMsg(TB_INSERTBUTTON, (WPARAM)iButton, (LPARAM)button)); }
- BOOL AddToolTips(UINT numToolTips, LPTSTR toolTips) { return BOOLToBool(SendMsg(TB_SETTOOLTIPS, (WPARAM)numToolTips, (LPARAM)toolTips)); }
- void AutoSize() { SendMsg(TB_AUTOSIZE, 0, 0); }
-
- bool AddAdornments(DWORD dwFlags) { return BOOLToBool(::CommandBar_AddAdornments(_window, dwFlags, 0)); }
- int AddBitmap(HINSTANCE hInst, int idBitmap, int iNumImages, int iImageWidth, int iImageHeight) { return ::CommandBar_AddBitmap(_window, hInst, idBitmap, iNumImages, iImageWidth, iImageHeight); }
- bool DrawMenuBar(WORD iButton) { return BOOLToBool(::CommandBar_DrawMenuBar(_window, iButton)); }
- HMENU GetMenu(WORD iButton) { return ::CommandBar_GetMenu(_window, iButton); }
- int Height() { return CommandBar_Height(_window); }
- HWND InsertComboBox(HINSTANCE hInst, int iWidth, UINT dwStyle, WORD idComboBox, WORD iButton) { return ::CommandBar_InsertComboBox(_window, hInst, iWidth, dwStyle, idComboBox, iButton); }
- bool InsertMenubar(HINSTANCE hInst, WORD idMenu, WORD iButton) { return BOOLToBool(::CommandBar_InsertMenubar(_window, hInst, idMenu, iButton)); }
- bool InsertMenubarEx(HINSTANCE hInst, LPTSTR pszMenu, WORD iButton) { return BOOLToBool(::CommandBar_InsertMenubarEx(_window, hInst, pszMenu, iButton)); }
- bool Show(bool cmdShow) { return BOOLToBool(::CommandBar_Show(_window, BoolToBOOL(cmdShow))); }
-
-
- // CE 4.0
- void AlignAdornments() { CommandBar_AlignAdornments(_window); }
-};
-
-}}
-
-#endif
-
-#endif
+// Windows/Control/CommandBar.h
+
+#ifndef ZIP7_INC_WINDOWS_CONTROL_COMMANDBAR_H
+#define ZIP7_INC_WINDOWS_CONTROL_COMMANDBAR_H
+
+#ifdef UNDER_CE
+
+#include "../../Common/MyWindows.h"
+
+#include <commctrl.h>
+
+#include "../Window.h"
+
+namespace NWindows {
+namespace NControl {
+
+class CCommandBar: public NWindows::CWindow
+{
+public:
+ bool Create(HINSTANCE hInst, HWND hwndParent, int idCmdBar)
+ {
+ _window = ::CommandBar_Create(hInst, hwndParent, idCmdBar);
+ return (_window != NULL);
+ }
+
+ // Macros
+ // void Destroy() { CommandBar_Destroy(_window); }
+ // bool AddButtons(UINT numButtons, LPTBBUTTON buttons) { return BOOLToBool(SendMsg(TB_ADDBUTTONS, (WPARAM)numButtons, (LPARAM)buttons)); }
+ // bool InsertButton(unsigned iButton, LPTBBUTTON button) { return BOOLToBool(SendMsg(TB_INSERTBUTTON, (WPARAM)iButton, (LPARAM)button)); }
+ // BOOL AddToolTips(UINT numToolTips, LPTSTR toolTips) { return BOOLToBool(SendMsg(TB_SETTOOLTIPS, (WPARAM)numToolTips, (LPARAM)toolTips)); }
+ void AutoSize() { SendMsg(TB_AUTOSIZE, 0, 0); }
+
+ // bool AddAdornments(DWORD dwFlags) { return BOOLToBool(::CommandBar_AddAdornments(_window, dwFlags, 0)); }
+ // int AddBitmap(HINSTANCE hInst, int idBitmap, int iNumImages, int iImageWidth, int iImageHeight) { return ::CommandBar_AddBitmap(_window, hInst, idBitmap, iNumImages, iImageWidth, iImageHeight); }
+ bool DrawMenuBar(WORD iButton) { return BOOLToBool(::CommandBar_DrawMenuBar(_window, iButton)); }
+ HMENU GetMenu(WORD iButton) { return ::CommandBar_GetMenu(_window, iButton); }
+ int Height() { return CommandBar_Height(_window); }
+ HWND InsertComboBox(HINSTANCE hInst, int iWidth, UINT dwStyle, WORD idComboBox, WORD iButton) { return ::CommandBar_InsertComboBox(_window, hInst, iWidth, dwStyle, idComboBox, iButton); }
+ bool InsertMenubar(HINSTANCE hInst, WORD idMenu, WORD iButton) { return BOOLToBool(::CommandBar_InsertMenubar(_window, hInst, idMenu, iButton)); }
+ bool InsertMenubarEx(HINSTANCE hInst, LPTSTR pszMenu, WORD iButton) { return BOOLToBool(::CommandBar_InsertMenubarEx(_window, hInst, pszMenu, iButton)); }
+ bool Show(bool cmdShow) { return BOOLToBool(::CommandBar_Show(_window, BoolToBOOL(cmdShow))); }
+
+
+ // CE 4.0
+ void AlignAdornments() { CommandBar_AlignAdornments(_window); }
+};
+
+}}
+
+#endif
+
+#endif
diff --git a/CPP/Windows/Control/Dialog.cpp b/CPP/Windows/Control/Dialog.cpp
index 8e61a2b..c8f1bd2 100644
--- a/CPP/Windows/Control/Dialog.cpp
+++ b/CPP/Windows/Control/Dialog.cpp
@@ -1,251 +1,445 @@
-// Windows/Control/Dialog.cpp
-
-#include "StdAfx.h"
-
-#ifndef _UNICODE
-#include "../../Common/StringConvert.h"
-#endif
-
-#include "Dialog.h"
-
-extern HINSTANCE g_hInstance;
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-namespace NWindows {
-namespace NControl {
-
-static INT_PTR APIENTRY DialogProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam)
-{
- CWindow tempDialog(dialogHWND);
- if (message == WM_INITDIALOG)
- tempDialog.SetUserDataLongPtr(lParam);
- CDialog *dialog = (CDialog *)(tempDialog.GetUserDataLongPtr());
- if (dialog == NULL)
- return FALSE;
- if (message == WM_INITDIALOG)
- dialog->Attach(dialogHWND);
- try { return BoolToBOOL(dialog->OnMessage(message, wParam, lParam)); }
- catch(...) { return TRUE; }
-}
-
-bool CDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
-{
- switch (message)
- {
- case WM_INITDIALOG: return OnInit();
- case WM_COMMAND: return OnCommand(wParam, lParam);
- case WM_NOTIFY: return OnNotify((UINT)wParam, (LPNMHDR) lParam);
- case WM_TIMER: return OnTimer(wParam, lParam);
- case WM_SIZE: return OnSize(wParam, LOWORD(lParam), HIWORD(lParam));
- case WM_HELP: OnHelp(); return true;
- /*
- OnHelp(
- #ifdef UNDER_CE
- (void *)
- #else
- (LPHELPINFO)
- #endif
- lParam);
- return true;
- */
- default: return false;
- }
-}
-
-bool CDialog::OnCommand(WPARAM wParam, LPARAM lParam)
-{
- return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam);
-}
-
-bool CDialog::OnCommand(int code, int itemID, LPARAM lParam)
-{
- if (code == BN_CLICKED)
- return OnButtonClicked(itemID, (HWND)lParam);
- return false;
-}
-
-bool CDialog::OnButtonClicked(int buttonID, HWND /* buttonHWND */)
-{
- switch (buttonID)
- {
- case IDOK: OnOK(); break;
- case IDCANCEL: OnCancel(); break;
- case IDCLOSE: OnClose(); break;
- case IDHELP: OnHelp(); break;
- default: return false;
- }
- return true;
-}
-
-static bool GetWorkAreaRect(RECT *rect)
-{
- // use another function for multi-monitor.
- return BOOLToBool(::SystemParametersInfo(SPI_GETWORKAREA, 0, rect, 0));
-}
-
-bool IsDialogSizeOK(int xSize, int ySize)
-{
- // it returns for system font. Real font uses another values
- LONG v = GetDialogBaseUnits();
- int x = LOWORD(v);
- int y = HIWORD(v);
-
- RECT rect;
- GetWorkAreaRect(&rect);
- int wx = RECT_SIZE_X(rect);
- int wy = RECT_SIZE_Y(rect);
- return
- xSize / 4 * x <= wx &&
- ySize / 8 * y <= wy;
-}
-
-bool CDialog::GetMargins(int margin, int &x, int &y)
-{
- x = margin;
- y = margin;
- RECT rect;
- rect.left = 0;
- rect.top = 0;
- rect.right = margin;
- rect.bottom = margin;
- if (!MapRect(&rect))
- return false;
- x = rect.right - rect.left;
- y = rect.bottom - rect.top;
- return true;
-}
-
-int CDialog::Units_To_Pixels_X(int units)
-{
- RECT rect;
- rect.left = 0;
- rect.top = 0;
- rect.right = units;
- rect.bottom = units;
- if (!MapRect(&rect))
- return units * 3 / 2;
- return rect.right - rect.left;
-}
-
-bool CDialog::GetItemSizes(int id, int &x, int &y)
-{
- RECT rect;
- if (!::GetWindowRect(GetItem(id), &rect))
- return false;
- x = RECT_SIZE_X(rect);
- y = RECT_SIZE_Y(rect);
- return true;
-}
-
-void CDialog::GetClientRectOfItem(int id, RECT &rect)
-{
- ::GetWindowRect(GetItem(id), &rect);
- ScreenToClient(&rect);
-}
-
-bool CDialog::MoveItem(int id, int x, int y, int width, int height, bool repaint)
-{
- return BOOLToBool(::MoveWindow(GetItem(id), x, y, width, height, BoolToBOOL(repaint)));
-}
-
-void CDialog::NormalizeSize(bool fullNormalize)
-{
- RECT workRect;
- GetWorkAreaRect(&workRect);
- int xSize = RECT_SIZE_X(workRect);
- int ySize = RECT_SIZE_Y(workRect);
- RECT rect;
- GetWindowRect(&rect);
- int xSize2 = RECT_SIZE_X(rect);
- int ySize2 = RECT_SIZE_Y(rect);
- bool needMove = (xSize2 > xSize || ySize2 > ySize);
- if (xSize2 > xSize || (needMove && fullNormalize))
- {
- rect.left = workRect.left;
- rect.right = workRect.right;
- xSize2 = xSize;
- }
- if (ySize2 > ySize || (needMove && fullNormalize))
- {
- rect.top = workRect.top;
- rect.bottom = workRect.bottom;
- ySize2 = ySize;
- }
- if (needMove)
- {
- if (fullNormalize)
- Show(SW_SHOWMAXIMIZED);
- else
- Move(rect.left, rect.top, xSize2, ySize2, true);
- }
-}
-
-void CDialog::NormalizePosition()
-{
- RECT workRect, rect;
- GetWorkAreaRect(&workRect);
- GetWindowRect(&rect);
- if (rect.bottom > workRect.bottom && rect.top > workRect.top)
- Move(rect.left, workRect.top, RECT_SIZE_X(rect), RECT_SIZE_Y(rect), true);
-}
-
-bool CModelessDialog::Create(LPCTSTR templateName, HWND parentWindow)
-{
- HWND aHWND = CreateDialogParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
- if (aHWND == 0)
- return false;
- Attach(aHWND);
- return true;
-}
-
-INT_PTR CModalDialog::Create(LPCTSTR templateName, HWND parentWindow)
-{
- return DialogBoxParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
-}
-
-#ifndef _UNICODE
-
-bool CModelessDialog::Create(LPCWSTR templateName, HWND parentWindow)
-{
- HWND aHWND;
- if (g_IsNT)
- aHWND = CreateDialogParamW(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
- else
- {
- AString name;
- LPCSTR templateNameA;
- if (IS_INTRESOURCE(templateName))
- templateNameA = (LPCSTR)templateName;
- else
- {
- name = GetSystemString(templateName);
- templateNameA = name;
- }
- aHWND = CreateDialogParamA(g_hInstance, templateNameA, parentWindow, DialogProcedure, (LPARAM)this);
- }
- if (aHWND == 0)
- return false;
- Attach(aHWND);
- return true;
-}
-
-INT_PTR CModalDialog::Create(LPCWSTR templateName, HWND parentWindow)
-{
- if (g_IsNT)
- return DialogBoxParamW(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
- AString name;
- LPCSTR templateNameA;
- if (IS_INTRESOURCE(templateName))
- templateNameA = (LPCSTR)templateName;
- else
- {
- name = GetSystemString(templateName);
- templateNameA = name;
- }
- return DialogBoxParamA(g_hInstance, templateNameA, parentWindow, DialogProcedure, (LPARAM)this);
-}
-#endif
-
-}}
+// Windows/Control/Dialog.cpp
+
+#include "StdAfx.h"
+
+// #include "../../Windows/DLL.h"
+
+#ifndef _UNICODE
+#include "../../Common/StringConvert.h"
+#endif
+
+#include "Dialog.h"
+
+extern HINSTANCE g_hInstance;
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NControl {
+
+static
+#ifdef Z7_OLD_WIN_SDK
+ BOOL
+#else
+ INT_PTR
+#endif
+APIENTRY
+DialogProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ CWindow tempDialog(dialogHWND);
+ if (message == WM_INITDIALOG)
+ tempDialog.SetUserDataLongPtr(lParam);
+ CDialog *dialog = (CDialog *)(tempDialog.GetUserDataLongPtr());
+ if (dialog == NULL)
+ return FALSE;
+ if (message == WM_INITDIALOG)
+ dialog->Attach(dialogHWND);
+
+ /* MSDN: The dialog box procedure should return
+ TRUE - if it processed the message
+ FALSE - if it did not process the message
+ If the dialog box procedure returns FALSE,
+ the dialog manager performs the default dialog operation in response to the message.
+ */
+
+ try { return BoolToBOOL(dialog->OnMessage(message, wParam, lParam)); }
+ catch(...) { return TRUE; }
+}
+
+bool CDialog::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message)
+ {
+ case WM_INITDIALOG: return OnInit();
+ case WM_COMMAND: return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam);
+ case WM_NOTIFY: return OnNotify((UINT)wParam, (LPNMHDR) lParam);
+ case WM_TIMER: return OnTimer(wParam, lParam);
+ case WM_SIZE: return OnSize(wParam, LOWORD(lParam), HIWORD(lParam));
+ case WM_DESTROY: return OnDestroy();
+ case WM_HELP: OnHelp(); return true;
+ /*
+ OnHelp(
+ #ifdef UNDER_CE
+ (void *)
+ #else
+ (LPHELPINFO)
+ #endif
+ lParam);
+ return true;
+ */
+ default: return false;
+ }
+}
+
+/*
+bool CDialog::OnCommand2(WPARAM wParam, LPARAM lParam)
+{
+ return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam);
+}
+*/
+
+bool CDialog::OnCommand(unsigned code, unsigned itemID, LPARAM lParam)
+{
+ if (code == BN_CLICKED)
+ return OnButtonClicked(itemID, (HWND)lParam);
+ return false;
+}
+
+bool CDialog::OnButtonClicked(unsigned buttonID, HWND /* buttonHWND */)
+{
+ switch (buttonID)
+ {
+ case IDOK: OnOK(); break;
+ case IDCANCEL: OnCancel(); break;
+ case IDCLOSE: OnClose(); break;
+ case IDHELP: OnHelp(); break;
+ default: return false;
+ }
+ return true;
+}
+
+#ifndef UNDER_CE
+/* in win2000/win98 : monitor functions are supported.
+ We need dynamic linking, if we want nt4/win95 support in program.
+ Even if we compile the code with low (WINVER) value, we still
+ want to use monitor functions. So we declare missing functions here */
+// #if (WINVER < 0x0500)
+#ifndef MONITOR_DEFAULTTOPRIMARY
+extern "C" {
+DECLARE_HANDLE(HMONITOR);
+#define MONITOR_DEFAULTTOPRIMARY 0x00000001
+typedef struct tagMONITORINFO
+{
+ DWORD cbSize;
+ RECT rcMonitor;
+ RECT rcWork;
+ DWORD dwFlags;
+} MONITORINFO, *LPMONITORINFO;
+WINUSERAPI HMONITOR WINAPI MonitorFromWindow(HWND hwnd, DWORD dwFlags);
+WINUSERAPI BOOL WINAPI GetMonitorInfoA(HMONITOR hMonitor, LPMONITORINFO lpmi);
+}
+#endif
+#endif
+
+static bool GetWorkAreaRect(RECT *rect, HWND hwnd)
+{
+ if (hwnd)
+ {
+ #ifndef UNDER_CE
+ /* MonitorFromWindow() is supported in Win2000+
+ MonitorFromWindow() : retrieves a handle to the display monitor that has the
+ largest area of intersection with the bounding rectangle of a specified window.
+ dwFlags: Determines the function's return value if the window does not intersect any display monitor.
+ MONITOR_DEFAULTTONEAREST : Returns display that is nearest to the window.
+ MONITOR_DEFAULTTONULL : Returns NULL.
+ MONITOR_DEFAULTTOPRIMARY : Returns the primary display monitor.
+ */
+ const HMONITOR hmon = MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY);
+ if (hmon)
+ {
+ MONITORINFO mi;
+ memset(&mi, 0, sizeof(mi));
+ mi.cbSize = sizeof(mi);
+ if (GetMonitorInfoA(hmon, &mi))
+ {
+ *rect = mi.rcWork;
+ return true;
+ }
+ }
+ #endif
+ }
+
+ /* Retrieves the size of the work area on the primary display monitor.
+ The work area is the portion of the screen not obscured
+ by the system taskbar or by application desktop toolbars.
+ Any DPI virtualization mode of the caller has no effect on this output. */
+
+ return BOOLToBool(::SystemParametersInfo(SPI_GETWORKAREA, 0, rect, 0));
+}
+
+
+bool IsDialogSizeOK(int xSize, int ySize, HWND hwnd)
+{
+ // it returns for system font. Real font uses another values
+ const LONG v = GetDialogBaseUnits();
+ const int x = LOWORD(v);
+ const int y = HIWORD(v);
+
+ RECT rect;
+ GetWorkAreaRect(&rect, hwnd);
+ const int wx = RECT_SIZE_X(rect);
+ const int wy = RECT_SIZE_Y(rect);
+ return
+ xSize / 4 * x <= wx &&
+ ySize / 8 * y <= wy;
+}
+
+bool CDialog::GetMargins(int margin, int &x, int &y)
+{
+ x = margin;
+ y = margin;
+ RECT rect;
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = margin;
+ rect.bottom = margin;
+ if (!MapRect(&rect))
+ return false;
+ x = rect.right - rect.left;
+ y = rect.bottom - rect.top;
+ return true;
+}
+
+int CDialog::Units_To_Pixels_X(int units)
+{
+ RECT rect;
+ rect.left = 0;
+ rect.top = 0;
+ rect.right = units;
+ rect.bottom = units;
+ if (!MapRect(&rect))
+ return units * 3 / 2;
+ return rect.right - rect.left;
+}
+
+bool CDialog::GetItemSizes(unsigned id, int &x, int &y)
+{
+ RECT rect;
+ if (!::GetWindowRect(GetItem(id), &rect))
+ return false;
+ x = RECT_SIZE_X(rect);
+ y = RECT_SIZE_Y(rect);
+ return true;
+}
+
+void CDialog::GetClientRectOfItem(unsigned id, RECT &rect)
+{
+ ::GetWindowRect(GetItem(id), &rect);
+ ScreenToClient(&rect);
+}
+
+bool CDialog::MoveItem(unsigned id, int x, int y, int width, int height, bool repaint)
+{
+ return BOOLToBool(::MoveWindow(GetItem(id), x, y, width, height, BoolToBOOL(repaint)));
+}
+
+
+/*
+typedef BOOL (WINAPI * Func_DwmGetWindowAttribute)(
+ HWND hwnd, DWORD dwAttribute, PVOID pvAttribute, DWORD cbAttribute);
+
+static bool GetWindowsRect_DWM(HWND hwnd, RECT *rect)
+{
+ // dll load and free is too slow : 300 calls in second.
+ NDLL::CLibrary dll;
+ if (!dll.Load(FTEXT("dwmapi.dll")))
+ return false;
+ Func_DwmGetWindowAttribute f = (Func_DwmGetWindowAttribute)dll.GetProc("DwmGetWindowAttribute" );
+ if (f)
+ {
+ #define MY__DWMWA_EXTENDED_FRAME_BOUNDS 9
+ // 30000 per second
+ RECT r;
+ if (f(hwnd, MY__DWMWA_EXTENDED_FRAME_BOUNDS, &r, sizeof(RECT)) == S_OK)
+ {
+ *rect = r;
+ return true;
+ }
+ }
+ return false;
+}
+*/
+
+
+static bool IsRect_Small_Inside_Big(const RECT &sm, const RECT &big)
+{
+ return sm.left >= big.left
+ && sm.right <= big.right
+ && sm.top >= big.top
+ && sm.bottom <= big.bottom;
+}
+
+
+static bool AreRectsOverlapped(const RECT &r1, const RECT &r2)
+{
+ return r1.left < r2.right
+ && r1.right > r2.left
+ && r1.top < r2.bottom
+ && r1.bottom > r2.top;
+}
+
+
+static bool AreRectsEqual(const RECT &r1, const RECT &r2)
+{
+ return r1.left == r2.left
+ && r1.right == r2.right
+ && r1.top == r2.top
+ && r1.bottom == r2.bottom;
+}
+
+
+void CDialog::NormalizeSize(bool fullNormalize)
+{
+ RECT workRect;
+ if (!GetWorkAreaRect(&workRect, *this))
+ return;
+ RECT rect;
+ if (!GetWindowRect(&rect))
+ return;
+ int xs = RECT_SIZE_X(rect);
+ int ys = RECT_SIZE_Y(rect);
+
+ // we don't want to change size using workRect, if window is outside of WorkArea
+ if (!AreRectsOverlapped(rect, workRect))
+ return;
+
+ /* here rect and workRect are overlapped, but it can be false
+ overlapping of small shadow when window in another display. */
+
+ const int xsW = RECT_SIZE_X(workRect);
+ const int ysW = RECT_SIZE_Y(workRect);
+ if (xs <= xsW && ys <= ysW)
+ return; // size of window is OK
+ if (fullNormalize)
+ {
+ Show(SW_SHOWMAXIMIZED);
+ return;
+ }
+ int x = workRect.left;
+ int y = workRect.top;
+ if (xs < xsW) x += (xsW - xs) / 2; else xs = xsW;
+ if (ys < ysW) y += (ysW - ys) / 2; else ys = ysW;
+ Move(x, y, xs, ys, true);
+}
+
+
+void CDialog::NormalizePosition()
+{
+ RECT workRect;
+ if (!GetWorkAreaRect(&workRect, *this))
+ return;
+
+ RECT rect2 = workRect;
+ bool useWorkArea = true;
+ const HWND parentHWND = GetParent();
+
+ if (parentHWND)
+ {
+ RECT workRectParent;
+ if (!GetWorkAreaRect(&workRectParent, parentHWND))
+ return;
+
+ // if windows are in different monitors, we use only workArea of current window
+
+ if (AreRectsEqual(workRectParent, workRect))
+ {
+ // RECT rect3; if (GetWindowsRect_DWM(parentHWND, &rect3)) {}
+ CWindow wnd(parentHWND);
+ if (wnd.GetWindowRect(&rect2))
+ {
+ // it's same monitor. So we try to use parentHWND rect.
+ /* we don't want to change position, if parent window is not inside work area.
+ In Win10 : parent window rect is 8 pixels larger for each corner than window size for shadow.
+ In maximize mode : window is outside of workRect.
+ if parent window is inside workRect, we will use parent window instead of workRect */
+ if (IsRect_Small_Inside_Big(rect2, workRect))
+ useWorkArea = false;
+ }
+ }
+ }
+
+ RECT rect;
+ if (!GetWindowRect(&rect))
+ return;
+
+ if (useWorkArea)
+ {
+ // we don't want to move window, if it's already inside.
+ if (IsRect_Small_Inside_Big(rect, workRect))
+ return;
+ // we don't want to move window, if it's outside of workArea
+ if (!AreRectsOverlapped(rect, workRect))
+ return;
+ rect2 = workRect;
+ }
+
+ {
+ const int xs = RECT_SIZE_X(rect);
+ const int ys = RECT_SIZE_Y(rect);
+ const int xs2 = RECT_SIZE_X(rect2);
+ const int ys2 = RECT_SIZE_Y(rect2);
+ // we don't want to change position if parent is smaller.
+ if (xs <= xs2 && ys <= ys2)
+ {
+ const int x = rect2.left + (xs2 - xs) / 2;
+ const int y = rect2.top + (ys2 - ys) / 2;
+
+ if (x != rect.left || y != rect.top)
+ Move(x, y, xs, ys, true);
+ // SetWindowPos(*this, HWND_TOP, x, y, 0, 0, SWP_NOSIZE);
+ return;
+ }
+ }
+}
+
+
+
+bool CModelessDialog::Create(LPCTSTR templateName, HWND parentWindow)
+{
+ const HWND aHWND = CreateDialogParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
+ if (!aHWND)
+ return false;
+ Attach(aHWND);
+ return true;
+}
+
+INT_PTR CModalDialog::Create(LPCTSTR templateName, HWND parentWindow)
+{
+ return DialogBoxParam(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
+}
+
+#ifndef _UNICODE
+
+bool CModelessDialog::Create(LPCWSTR templateName, HWND parentWindow)
+{
+ HWND aHWND;
+ if (g_IsNT)
+ aHWND = CreateDialogParamW(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
+ else
+ {
+ AString name;
+ LPCSTR templateNameA;
+ if (IS_INTRESOURCE(templateName))
+ templateNameA = (LPCSTR)templateName;
+ else
+ {
+ name = GetSystemString(templateName);
+ templateNameA = name;
+ }
+ aHWND = CreateDialogParamA(g_hInstance, templateNameA, parentWindow, DialogProcedure, (LPARAM)this);
+ }
+ if (aHWND == 0)
+ return false;
+ Attach(aHWND);
+ return true;
+}
+
+INT_PTR CModalDialog::Create(LPCWSTR templateName, HWND parentWindow)
+{
+ if (g_IsNT)
+ return DialogBoxParamW(g_hInstance, templateName, parentWindow, DialogProcedure, (LPARAM)this);
+ AString name;
+ LPCSTR templateNameA;
+ if (IS_INTRESOURCE(templateName))
+ templateNameA = (LPCSTR)templateName;
+ else
+ {
+ name = GetSystemString(templateName);
+ templateNameA = name;
+ }
+ return DialogBoxParamA(g_hInstance, templateNameA, parentWindow, DialogProcedure, (LPARAM)this);
+}
+#endif
+
+}}
diff --git a/CPP/Windows/Control/Dialog.h b/CPP/Windows/Control/Dialog.h
index f9c3442..06be4bf 100644
--- a/CPP/Windows/Control/Dialog.h
+++ b/CPP/Windows/Control/Dialog.h
@@ -1,170 +1,194 @@
-// Windows/Control/Dialog.h
-
-#ifndef __WINDOWS_CONTROL_DIALOG_H
-#define __WINDOWS_CONTROL_DIALOG_H
-
-#include "../Window.h"
-
-namespace NWindows {
-namespace NControl {
-
-class CDialog: public CWindow
-{
-public:
- CDialog(HWND wnd = NULL): CWindow(wnd){};
- virtual ~CDialog() {};
-
- HWND GetItem(int itemID) const
- { return GetDlgItem(_window, itemID); }
-
- bool EnableItem(int itemID, bool enable) const
- { return BOOLToBool(::EnableWindow(GetItem(itemID), BoolToBOOL(enable))); }
-
- bool ShowItem(int itemID, int cmdShow) const
- { return BOOLToBool(::ShowWindow(GetItem(itemID), cmdShow)); }
-
- bool ShowItem_Bool(int itemID, bool show) const
- { return ShowItem(itemID, show ? SW_SHOW: SW_HIDE); }
-
- bool HideItem(int itemID) const { return ShowItem(itemID, SW_HIDE); }
-
- bool SetItemText(int itemID, LPCTSTR s)
- { return BOOLToBool(SetDlgItemText(_window, itemID, s)); }
-
- #ifndef _UNICODE
- bool SetItemText(int itemID, LPCWSTR s)
- {
- CWindow window(GetItem(itemID));
- return window.SetText(s);
- }
- #endif
-
- UINT GetItemText(int itemID, LPTSTR string, int maxCount)
- { return GetDlgItemText(_window, itemID, string, maxCount); }
- #ifndef _UNICODE
- /*
- bool GetItemText(int itemID, LPWSTR string, int maxCount)
- {
- CWindow window(GetItem(itemID));
- return window.GetText(string, maxCount);
- }
- */
- #endif
-
- bool SetItemInt(int itemID, UINT value, bool isSigned)
- { return BOOLToBool(SetDlgItemInt(_window, itemID, value, BoolToBOOL(isSigned))); }
- bool GetItemInt(int itemID, bool isSigned, UINT &value)
- {
- BOOL result;
- value = GetDlgItemInt(_window, itemID, &result, BoolToBOOL(isSigned));
- return BOOLToBool(result);
- }
-
- HWND GetNextGroupItem(HWND control, bool previous)
- { return GetNextDlgGroupItem(_window, control, BoolToBOOL(previous)); }
- HWND GetNextTabItem(HWND control, bool previous)
- { return GetNextDlgTabItem(_window, control, BoolToBOOL(previous)); }
-
- bool MapRect(LPRECT rect)
- { return BOOLToBool(MapDialogRect(_window, rect)); }
-
- bool IsMessage(LPMSG message)
- { return BOOLToBool(IsDialogMessage(_window, message)); }
-
- LRESULT SendItemMessage(int itemID, UINT message, WPARAM wParam, LPARAM lParam)
- { return SendDlgItemMessage(_window, itemID, message, wParam, lParam); }
-
- bool CheckButton(int buttonID, UINT checkState)
- { return BOOLToBool(CheckDlgButton(_window, buttonID, checkState)); }
- bool CheckButton(int buttonID, bool checkState)
- { return CheckButton(buttonID, UINT(checkState ? BST_CHECKED : BST_UNCHECKED)); }
-
- UINT IsButtonChecked(int buttonID) const
- { return IsDlgButtonChecked(_window, buttonID); }
- bool IsButtonCheckedBool(int buttonID) const
- { return (IsButtonChecked(buttonID) == BST_CHECKED); }
-
- bool CheckRadioButton(int firstButtonID, int lastButtonID, int checkButtonID)
- { return BOOLToBool(::CheckRadioButton(_window, firstButtonID, lastButtonID, checkButtonID)); }
-
- virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
- virtual bool OnInit() { return true; }
- virtual bool OnCommand(WPARAM wParam, LPARAM lParam);
- virtual bool OnCommand(int code, int itemID, LPARAM lParam);
- virtual bool OnSize(WPARAM /* wParam */, int /* xSize */, int /* ySize */) { return false; }
-
- /*
- #ifdef UNDER_CE
- virtual void OnHelp(void *) { OnHelp(); }
- #else
- virtual void OnHelp(LPHELPINFO) { OnHelp(); }
- #endif
- */
- virtual void OnHelp() {};
-
- virtual bool OnButtonClicked(int buttonID, HWND buttonHWND);
- virtual void OnOK() {};
- virtual void OnCancel() {};
- virtual void OnClose() {}
- virtual bool OnNotify(UINT /* controlID */, LPNMHDR /* lParam */) { return false; }
- virtual bool OnTimer(WPARAM /* timerID */, LPARAM /* callback */) { return false; }
-
- LONG_PTR SetMsgResult(LONG_PTR newLongPtr )
- { return SetLongPtr(DWLP_MSGRESULT, newLongPtr); }
- LONG_PTR GetMsgResult() const
- { return GetLongPtr(DWLP_MSGRESULT); }
-
- bool GetMargins(int margin, int &x, int &y);
- int Units_To_Pixels_X(int units);
- bool GetItemSizes(int id, int &x, int &y);
- void GetClientRectOfItem(int id, RECT &rect);
- bool MoveItem(int id, int x, int y, int width, int height, bool repaint = true);
-
- void NormalizeSize(bool fullNormalize = false);
- void NormalizePosition();
-};
-
-class CModelessDialog: public CDialog
-{
-public:
- bool Create(LPCTSTR templateName, HWND parentWindow);
- bool Create(UINT resID, HWND parentWindow) { return Create(MAKEINTRESOURCEW(resID), parentWindow); }
- #ifndef _UNICODE
- bool Create(LPCWSTR templateName, HWND parentWindow);
- #endif
- virtual void OnOK() { Destroy(); }
- virtual void OnCancel() { Destroy(); }
- virtual void OnClose() { Destroy(); }
-};
-
-class CModalDialog: public CDialog
-{
-public:
- INT_PTR Create(LPCTSTR templateName, HWND parentWindow);
- INT_PTR Create(UINT resID, HWND parentWindow) { return Create(MAKEINTRESOURCEW(resID), parentWindow); }
- #ifndef _UNICODE
- INT_PTR Create(LPCWSTR templateName, HWND parentWindow);
- #endif
-
- bool End(INT_PTR result) { return BOOLToBool(::EndDialog(_window, result)); }
- virtual void OnOK() { End(IDOK); }
- virtual void OnCancel() { End(IDCANCEL); }
- virtual void OnClose() { End(IDCLOSE); }
-};
-
-class CDialogChildControl: public NWindows::CWindow
-{
- int m_ID;
-public:
- void Init(const NWindows::NControl::CDialog &parentDialog, int id)
- {
- m_ID = id;
- Attach(parentDialog.GetItem(id));
- }
-};
-
-bool IsDialogSizeOK(int xSize, int ySize);
-
-}}
-
-#endif
+// Windows/Control/Dialog.h
+
+#ifndef ZIP7_INC_WINDOWS_CONTROL_DIALOG_H
+#define ZIP7_INC_WINDOWS_CONTROL_DIALOG_H
+
+#include "../Window.h"
+
+namespace NWindows {
+namespace NControl {
+
+class CDialog: public CWindow
+{
+ // Z7_CLASS_NO_COPY(CDialog)
+public:
+ CDialog(HWND wnd = NULL): CWindow(wnd) {}
+ virtual ~CDialog() {}
+
+ HWND GetItem(unsigned itemID) const
+ { return GetDlgItem(_window, (int)itemID); }
+
+ bool EnableItem(unsigned itemID, bool enable) const
+ { return BOOLToBool(::EnableWindow(GetItem(itemID), BoolToBOOL(enable))); }
+
+ bool ShowItem(unsigned itemID, int cmdShow) const
+ { return BOOLToBool(::ShowWindow(GetItem(itemID), cmdShow)); }
+
+ bool ShowItem_Bool(unsigned itemID, bool show) const
+ { return ShowItem(itemID, show ? SW_SHOW: SW_HIDE); }
+
+ bool HideItem(unsigned itemID) const { return ShowItem(itemID, SW_HIDE); }
+
+ bool SetItemText(unsigned itemID, LPCTSTR s)
+ { return BOOLToBool(SetDlgItemText(_window, (int)itemID, s)); }
+
+ bool SetItemTextA(unsigned itemID, LPCSTR s)
+ { return BOOLToBool(SetDlgItemTextA(_window, (int)itemID, s)); }
+
+ bool SetItemText_Empty(unsigned itemID)
+ { return SetItemText(itemID, TEXT("")); }
+
+ #ifndef _UNICODE
+ bool SetItemText(unsigned itemID, LPCWSTR s)
+ {
+ CWindow window(GetItem(itemID));
+ return window.SetText(s);
+ }
+ #endif
+
+ UINT GetItemText(unsigned itemID, LPTSTR string, unsigned maxCount)
+ { return GetDlgItemText(_window, (int)itemID, string, (int)maxCount); }
+ #ifndef _UNICODE
+ /*
+ bool GetItemText(unsigned itemID, LPWSTR string, int maxCount)
+ {
+ CWindow window(GetItem(unsigned));
+ return window.GetText(string, maxCount);
+ }
+ */
+ #endif
+
+ bool GetItemText(unsigned itemID, UString &s)
+ {
+ CWindow window(GetItem(itemID));
+ return window.GetText(s);
+ }
+
+ bool SetItemInt(unsigned itemID, UINT value, bool isSigned)
+ { return BOOLToBool(SetDlgItemInt(_window, (int)itemID, value, BoolToBOOL(isSigned))); }
+ bool GetItemInt(unsigned itemID, bool isSigned, UINT &value)
+ {
+ BOOL result;
+ value = GetDlgItemInt(_window, (int)itemID, &result, BoolToBOOL(isSigned));
+ return BOOLToBool(result);
+ }
+
+ HWND GetNextGroupItem(HWND control, bool previous)
+ { return GetNextDlgGroupItem(_window, control, BoolToBOOL(previous)); }
+ HWND GetNextTabItem(HWND control, bool previous)
+ { return GetNextDlgTabItem(_window, control, BoolToBOOL(previous)); }
+
+ LRESULT SendMsg_NextDlgCtl(WPARAM wParam, LPARAM lParam)
+ { return SendMsg(WM_NEXTDLGCTL, wParam, lParam); }
+ LRESULT SendMsg_NextDlgCtl_HWND(HWND hwnd) { return SendMsg_NextDlgCtl((WPARAM)hwnd, TRUE); }
+ LRESULT SendMsg_NextDlgCtl_CtlId(unsigned id) { return SendMsg_NextDlgCtl_HWND(GetItem(id)); }
+ LRESULT SendMsg_NextDlgCtl_Next() { return SendMsg_NextDlgCtl(0, FALSE); }
+ LRESULT SendMsg_NextDlgCtl_Prev() { return SendMsg_NextDlgCtl(1, FALSE); }
+
+ bool MapRect(LPRECT rect)
+ { return BOOLToBool(MapDialogRect(_window, rect)); }
+
+ bool IsMessage(LPMSG message)
+ { return BOOLToBool(IsDialogMessage(_window, message)); }
+
+ LRESULT SendItemMessage(unsigned itemID, UINT message, WPARAM wParam, LPARAM lParam)
+ { return SendDlgItemMessage(_window, (int)itemID, message, wParam, lParam); }
+
+ bool CheckButton(unsigned buttonID, UINT checkState)
+ { return BOOLToBool(CheckDlgButton(_window, (int)buttonID, checkState)); }
+ bool CheckButton(unsigned buttonID, bool checkState)
+ { return CheckButton(buttonID, UINT(checkState ? BST_CHECKED : BST_UNCHECKED)); }
+
+ UINT IsButtonChecked_BST(unsigned buttonID) const
+ { return IsDlgButtonChecked(_window, (int)buttonID); }
+ bool IsButtonCheckedBool(unsigned buttonID) const
+ { return (IsButtonChecked_BST(buttonID) == BST_CHECKED); }
+
+ bool CheckRadioButton(unsigned firstButtonID, unsigned lastButtonID, unsigned checkButtonID)
+ { return BOOLToBool(::CheckRadioButton(_window,
+ (int)firstButtonID, (int)lastButtonID, (int)checkButtonID)); }
+
+ virtual bool OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
+ virtual bool OnInit() { return true; }
+ // virtual bool OnCommand2(WPARAM wParam, LPARAM lParam);
+ virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam);
+ virtual bool OnSize(WPARAM /* wParam */, int /* xSize */, int /* ySize */) { return false; }
+ virtual bool OnDestroy() { return false; }
+
+ /*
+ #ifdef UNDER_CE
+ virtual void OnHelp(void *) { OnHelp(); }
+ #else
+ virtual void OnHelp(LPHELPINFO) { OnHelp(); }
+ #endif
+ */
+ virtual void OnHelp() {}
+
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND);
+ virtual void OnOK() {}
+ virtual void OnCancel() {}
+ virtual void OnClose() {}
+ virtual bool OnNotify(UINT /* controlID */, LPNMHDR /* lParam */) { return false; }
+ virtual bool OnTimer(WPARAM /* timerID */, LPARAM /* callback */) { return false; }
+
+ LONG_PTR SetMsgResult(LONG_PTR newLongPtr )
+ { return SetLongPtr(DWLP_MSGRESULT, newLongPtr); }
+ LONG_PTR GetMsgResult() const
+ { return GetLongPtr(DWLP_MSGRESULT); }
+
+ bool GetMargins(int margin, int &x, int &y);
+ int Units_To_Pixels_X(int units);
+ bool GetItemSizes(unsigned id, int &x, int &y);
+ void GetClientRectOfItem(unsigned id, RECT &rect);
+ bool MoveItem(unsigned id, int x, int y, int width, int height, bool repaint = true);
+ bool MoveItem_RECT(unsigned id, const RECT &r, bool repaint = true)
+ { return MoveItem(id, r.left, r.top, RECT_SIZE_X(r), RECT_SIZE_Y(r), repaint); }
+
+ void NormalizeSize(bool fullNormalize = false);
+ void NormalizePosition();
+};
+
+class CModelessDialog: public CDialog
+{
+public:
+ bool Create(LPCTSTR templateName, HWND parentWindow);
+ bool Create(UINT resID, HWND parentWindow) { return Create(MAKEINTRESOURCEW(resID), parentWindow); }
+ #ifndef _UNICODE
+ bool Create(LPCWSTR templateName, HWND parentWindow);
+ #endif
+ virtual void OnOK() Z7_override { Destroy(); }
+ virtual void OnCancel() Z7_override { Destroy(); }
+ virtual void OnClose() Z7_override { Destroy(); }
+};
+
+class CModalDialog: public CDialog
+{
+public:
+ INT_PTR Create(LPCTSTR templateName, HWND parentWindow);
+ INT_PTR Create(UINT resID, HWND parentWindow) { return Create(MAKEINTRESOURCEW(resID), parentWindow); }
+ #ifndef _UNICODE
+ INT_PTR Create(LPCWSTR templateName, HWND parentWindow);
+ #endif
+
+ bool End(INT_PTR result) { return BOOLToBool(::EndDialog(_window, result)); }
+ virtual void OnOK() Z7_override { End(IDOK); }
+ virtual void OnCancel() Z7_override { End(IDCANCEL); }
+ virtual void OnClose() Z7_override { End(IDCLOSE); }
+};
+
+class CDialogChildControl: public NWindows::CWindow
+{
+ // unsigned m_ID;
+public:
+ void Init(const NWindows::NControl::CDialog &parentDialog, unsigned id)
+ {
+ // m_ID = id;
+ Attach(parentDialog.GetItem(id));
+ }
+};
+
+bool IsDialogSizeOK(int xSize, int ySize, HWND hwnd = NULL);
+
+}}
+
+#endif
diff --git a/CPP/Windows/Control/Edit.h b/CPP/Windows/Control/Edit.h
index 4f503aa..963470d 100644
--- a/CPP/Windows/Control/Edit.h
+++ b/CPP/Windows/Control/Edit.h
@@ -1,19 +1,19 @@
-// Windows/Control/Edit.h
-
-#ifndef __WINDOWS_CONTROL_EDIT_H
-#define __WINDOWS_CONTROL_EDIT_H
-
-#include "../Window.h"
-
-namespace NWindows {
-namespace NControl {
-
-class CEdit: public CWindow
-{
-public:
- void SetPasswordChar(WPARAM c) { SendMsg(EM_SETPASSWORDCHAR, c); }
-};
-
-}}
-
-#endif
+// Windows/Control/Edit.h
+
+#ifndef ZIP7_INC_WINDOWS_CONTROL_EDIT_H
+#define ZIP7_INC_WINDOWS_CONTROL_EDIT_H
+
+#include "../Window.h"
+
+namespace NWindows {
+namespace NControl {
+
+class CEdit: public CWindow
+{
+public:
+ void SetPasswordChar(WPARAM c) { SendMsg(EM_SETPASSWORDCHAR, c); }
+};
+
+}}
+
+#endif
diff --git a/CPP/Windows/Control/ImageList.cpp b/CPP/Windows/Control/ImageList.cpp
index d201c8f..3e22b95 100644
--- a/CPP/Windows/Control/ImageList.cpp
+++ b/CPP/Windows/Control/ImageList.cpp
@@ -1,10 +1,10 @@
-// Windows/Control/ImageList.cpp
-
-#include "StdAfx.h"
-
-#include "ImageList.h"
-
-namespace NWindows {
-namespace NControl {
-
-}}
+// Windows/Control/ImageList.cpp
+
+#include "StdAfx.h"
+
+#include "ImageList.h"
+
+namespace NWindows {
+namespace NControl {
+
+}}
diff --git a/CPP/Windows/Control/ImageList.h b/CPP/Windows/Control/ImageList.h
index f72ea0d..688f177 100644
--- a/CPP/Windows/Control/ImageList.h
+++ b/CPP/Windows/Control/ImageList.h
@@ -1,87 +1,87 @@
-// Windows/Control/ImageList.h
-
-#ifndef __WINDOWS_CONTROL_IMAGE_LIST_H
-#define __WINDOWS_CONTROL_IMAGE_LIST_H
-
-#include <commctrl.h>
-
-#include "../Defs.h"
-
-namespace NWindows {
-namespace NControl {
-
-class CImageList
-{
- HIMAGELIST m_Object;
-public:
- operator HIMAGELIST() const {return m_Object; }
- CImageList(): m_Object(NULL) {}
- bool Attach(HIMAGELIST imageList)
- {
- if (imageList == NULL)
- return false;
- m_Object = imageList;
- return true;
- }
-
- HIMAGELIST Detach()
- {
- HIMAGELIST imageList = m_Object;
- m_Object = NULL;
- return imageList;
- }
-
- bool Create(int width, int height, UINT flags, int initialNumber, int grow)
- {
- HIMAGELIST a = ImageList_Create(width, height, flags,
- initialNumber, grow);
- if (a == NULL)
- return false;
- return Attach(a);
- }
-
- bool Destroy() // DeleteImageList() in MFC
- {
- if (m_Object == NULL)
- return false;
- return BOOLToBool(ImageList_Destroy(Detach()));
- }
-
- ~CImageList()
- { Destroy(); }
-
- int GetImageCount() const
- { return ImageList_GetImageCount(m_Object); }
-
- bool GetImageInfo(int index, IMAGEINFO* imageInfo) const
- { return BOOLToBool(ImageList_GetImageInfo(m_Object, index, imageInfo)); }
-
- int Add(HBITMAP hbmImage, HBITMAP hbmMask = 0)
- { return ImageList_Add(m_Object, hbmImage, hbmMask); }
- int AddMasked(HBITMAP hbmImage, COLORREF mask)
- { return ImageList_AddMasked(m_Object, hbmImage, mask); }
- int AddIcon(HICON icon)
- { return ImageList_AddIcon(m_Object, icon); }
- int Replace(int index, HICON icon)
- { return ImageList_ReplaceIcon(m_Object, index, icon); }
-
- // If index is -1, the function removes all images.
- bool Remove(int index)
- { return BOOLToBool(ImageList_Remove(m_Object, index)); }
- bool RemoveAll()
- { return BOOLToBool(ImageList_RemoveAll(m_Object)); }
-
- HICON ExtractIcon(int index)
- { return ImageList_ExtractIcon(NULL, m_Object, index); }
- HICON GetIcon(int index, UINT flags)
- { return ImageList_GetIcon(m_Object, index, flags); }
-
- bool GetIconSize(int &width, int &height) const
- { return BOOLToBool(ImageList_GetIconSize(m_Object, &width, &height)); }
- bool SetIconSize(int width, int height)
- { return BOOLToBool(ImageList_SetIconSize(m_Object, width, height)); }
-};
-
-}}
-
-#endif
+// Windows/Control/ImageList.h
+
+#ifndef ZIP7_INC_WINDOWS_CONTROL_IMAGE_LIST_H
+#define ZIP7_INC_WINDOWS_CONTROL_IMAGE_LIST_H
+
+#include <CommCtrl.h>
+
+#include "../Defs.h"
+
+namespace NWindows {
+namespace NControl {
+
+class CImageList
+{
+ HIMAGELIST m_Object;
+public:
+ operator HIMAGELIST() const {return m_Object; }
+ CImageList(): m_Object(NULL) {}
+ bool Attach(HIMAGELIST imageList)
+ {
+ if (imageList == NULL)
+ return false;
+ m_Object = imageList;
+ return true;
+ }
+
+ HIMAGELIST Detach()
+ {
+ HIMAGELIST imageList = m_Object;
+ m_Object = NULL;
+ return imageList;
+ }
+
+ bool Create(int width, int height, UINT flags, int initialNumber, int grow)
+ {
+ HIMAGELIST a = ImageList_Create(width, height, flags,
+ initialNumber, grow);
+ if (a == NULL)
+ return false;
+ return Attach(a);
+ }
+
+ bool Destroy() // DeleteImageList() in MFC
+ {
+ if (m_Object == NULL)
+ return false;
+ return BOOLToBool(ImageList_Destroy(Detach()));
+ }
+
+ ~CImageList()
+ { Destroy(); }
+
+ int GetImageCount() const
+ { return ImageList_GetImageCount(m_Object); }
+
+ bool GetImageInfo(int index, IMAGEINFO* imageInfo) const
+ { return BOOLToBool(ImageList_GetImageInfo(m_Object, index, imageInfo)); }
+
+ int Add(HBITMAP hbmImage, HBITMAP hbmMask = NULL)
+ { return ImageList_Add(m_Object, hbmImage, hbmMask); }
+ int AddMasked(HBITMAP hbmImage, COLORREF mask)
+ { return ImageList_AddMasked(m_Object, hbmImage, mask); }
+ int AddIcon(HICON icon)
+ { return ImageList_AddIcon(m_Object, icon); }
+ int Replace(int index, HICON icon)
+ { return ImageList_ReplaceIcon(m_Object, index, icon); }
+
+ // If index is -1, the function removes all images.
+ bool Remove(int index)
+ { return BOOLToBool(ImageList_Remove(m_Object, index)); }
+ bool RemoveAll()
+ { return BOOLToBool(ImageList_RemoveAll(m_Object)); }
+
+ HICON ExtractIcon(int index)
+ { return ImageList_ExtractIcon(NULL, m_Object, index); }
+ HICON GetIcon(int index, UINT flags)
+ { return ImageList_GetIcon(m_Object, index, flags); }
+
+ bool GetIconSize(int &width, int &height) const
+ { return BOOLToBool(ImageList_GetIconSize(m_Object, &width, &height)); }
+ bool SetIconSize(int width, int height)
+ { return BOOLToBool(ImageList_SetIconSize(m_Object, width, height)); }
+};
+
+}}
+
+#endif
diff --git a/CPP/Windows/Control/ListView.cpp b/CPP/Windows/Control/ListView.cpp
index fb22f95..3e8786a 100644
--- a/CPP/Windows/Control/ListView.cpp
+++ b/CPP/Windows/Control/ListView.cpp
@@ -1,155 +1,162 @@
-// Windows/Control/ListView.cpp
-
-#include "StdAfx.h"
-
-#include "ListView.h"
-
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-namespace NWindows {
-namespace NControl {
-
-bool CListView::CreateEx(DWORD exStyle, DWORD style,
- int x, int y, int width, int height,
- HWND parentWindow, HMENU idOrHMenu,
- HINSTANCE instance, LPVOID createParam)
-{
- return CWindow::CreateEx(exStyle, WC_LISTVIEW, TEXT(""), style, x, y, width,
- height, parentWindow, idOrHMenu, instance, createParam);
-}
-
-bool CListView::GetItemParam(int index, LPARAM &param) const
-{
- LVITEM item;
- item.iItem = index;
- item.iSubItem = 0;
- item.mask = LVIF_PARAM;
- bool aResult = GetItem(&item);
- param = item.lParam;
- return aResult;
-}
-
-int CListView::InsertColumn(int columnIndex, LPCTSTR text, int width)
-{
- LVCOLUMN ci;
- ci.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
- ci.pszText = (LPTSTR)text;
- ci.iSubItem = columnIndex;
- ci.cx = width;
- return InsertColumn(columnIndex, &ci);
-}
-
-int CListView::InsertItem(int index, LPCTSTR text)
-{
- LVITEM item;
- item.mask = LVIF_TEXT | LVIF_PARAM;
- item.iItem = index;
- item.lParam = index;
- item.pszText = (LPTSTR)text;
- item.iSubItem = 0;
- return InsertItem(&item);
-}
-
-int CListView::SetSubItem(int index, int subIndex, LPCTSTR text)
-{
- LVITEM item;
- item.mask = LVIF_TEXT;
- item.iItem = index;
- item.pszText = (LPTSTR)text;
- item.iSubItem = subIndex;
- return SetItem(&item);
-}
-
-#ifndef _UNICODE
-
-int CListView::InsertColumn(int columnIndex, LPCWSTR text, int width)
-{
- LVCOLUMNW ci;
- ci.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
- ci.pszText = (LPWSTR)text;
- ci.iSubItem = columnIndex;
- ci.cx = width;
- return InsertColumn(columnIndex, &ci);
-}
-
-int CListView::InsertItem(int index, LPCWSTR text)
-{
- LVITEMW item;
- item.mask = LVIF_TEXT | LVIF_PARAM;
- item.iItem = index;
- item.lParam = index;
- item.pszText = (LPWSTR)text;
- item.iSubItem = 0;
- return InsertItem(&item);
-}
-
-int CListView::SetSubItem(int index, int subIndex, LPCWSTR text)
-{
- LVITEMW item;
- item.mask = LVIF_TEXT;
- item.iItem = index;
- item.pszText = (LPWSTR)text;
- item.iSubItem = subIndex;
- return SetItem(&item);
-}
-
-#endif
-
-static LRESULT APIENTRY ListViewSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
-{
- CWindow window(hwnd);
- CListView2 *w = (CListView2 *)(window.GetUserDataLongPtr());
- if (w == NULL)
- return 0;
- return w->OnMessage(message, wParam, lParam);
-}
-
-LRESULT CListView2::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
-{
- #ifndef _UNICODE
- if (g_IsNT)
- return CallWindowProcW(_origWindowProc, *this, message, wParam, lParam);
- else
- #endif
- return CallWindowProc(_origWindowProc, *this, message, wParam, lParam);
-}
-
-void CListView2::SetWindowProc()
-{
- SetUserDataLongPtr((LONG_PTR)this);
- #ifndef _UNICODE
- if (g_IsNT)
- _origWindowProc = (WNDPROC)SetLongPtrW(GWLP_WNDPROC, (LONG_PTR)ListViewSubclassProc);
- else
- #endif
- _origWindowProc = (WNDPROC)SetLongPtr(GWLP_WNDPROC, (LONG_PTR)ListViewSubclassProc);
-}
-
-/*
-LRESULT CListView3::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
-{
- LRESULT res = CListView2::OnMessage(message, wParam, lParam);
- if (message == WM_GETDLGCODE)
- {
- // when user presses RETURN, windows sends default (first) button command to parent dialog.
- // we disable this:
- MSG *msg = (MSG *)lParam;
- WPARAM key = wParam;
- bool change = false;
- if (msg)
- {
- if (msg->message == WM_KEYDOWN && msg->wParam == VK_RETURN)
- change = true;
- }
- else if (wParam == VK_RETURN)
- change = true;
- if (change)
- res |= DLGC_WANTALLKEYS;
- }
- return res;
-}
-*/
-
-}}
+// Windows/Control/ListView.cpp
+
+#include "StdAfx.h"
+
+#include "ListView.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NControl {
+
+bool CListView::CreateEx(DWORD exStyle, DWORD style,
+ int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu,
+ HINSTANCE instance, LPVOID createParam)
+{
+ return CWindow::CreateEx(exStyle, WC_LISTVIEW, TEXT(""), style, x, y, width,
+ height, parentWindow, idOrHMenu, instance, createParam);
+}
+
+/* note: LVITEM and LVCOLUMN structures contain optional fields
+ depending from preprocessor macros:
+ #if (_WIN32_IE >= 0x0300)
+ #if (_WIN32_WINNT >= 0x0501)
+ #if (_WIN32_WINNT >= 0x0600)
+*/
+
+bool CListView::GetItemParam(unsigned index, LPARAM &param) const
+{
+ LVITEM item;
+ item.iItem = (int)index;
+ item.iSubItem = 0;
+ item.mask = LVIF_PARAM;
+ const bool res = GetItem(&item);
+ param = item.lParam;
+ return res;
+}
+
+int CListView::InsertColumn(unsigned columnIndex, LPCTSTR text, int width)
+{
+ LVCOLUMN ci;
+ ci.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
+ ci.pszText = (LPTSTR)(void *)text;
+ ci.iSubItem = (int)columnIndex;
+ ci.cx = width;
+ return InsertColumn(columnIndex, &ci);
+}
+
+int CListView::InsertItem(unsigned index, LPCTSTR text)
+{
+ LVITEM item;
+ item.mask = LVIF_TEXT | LVIF_PARAM;
+ item.iItem = (int)index;
+ item.lParam = (LPARAM)index;
+ item.pszText = (LPTSTR)(void *)text;
+ item.iSubItem = 0;
+ return InsertItem(&item);
+}
+
+int CListView::SetSubItem(unsigned index, unsigned subIndex, LPCTSTR text)
+{
+ LVITEM item;
+ item.mask = LVIF_TEXT;
+ item.iItem = (int)index;
+ item.pszText = (LPTSTR)(void *)text;
+ item.iSubItem = (int)subIndex;
+ return SetItem(&item);
+}
+
+#ifndef _UNICODE
+
+int CListView::InsertColumn(unsigned columnIndex, LPCWSTR text, int width)
+{
+ LVCOLUMNW ci;
+ ci.mask = LVCF_TEXT | LVCF_WIDTH | LVCF_SUBITEM;
+ ci.pszText = (LPWSTR)(void *)text;
+ ci.iSubItem = (int)columnIndex;
+ ci.cx = width;
+ return InsertColumn(columnIndex, &ci);
+}
+
+int CListView::InsertItem(unsigned index, LPCWSTR text)
+{
+ LVITEMW item;
+ item.mask = LVIF_TEXT | LVIF_PARAM;
+ item.iItem = (int)index;
+ item.lParam = (LPARAM)index;
+ item.pszText = (LPWSTR)(void *)text;
+ item.iSubItem = 0;
+ return InsertItem(&item);
+}
+
+int CListView::SetSubItem(unsigned index, unsigned subIndex, LPCWSTR text)
+{
+ LVITEMW item;
+ item.mask = LVIF_TEXT;
+ item.iItem = (int)index;
+ item.pszText = (LPWSTR)(void *)text;
+ item.iSubItem = (int)subIndex;
+ return SetItem(&item);
+}
+
+#endif
+
+static LRESULT APIENTRY ListViewSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ CWindow window(hwnd);
+ CListView2 *w = (CListView2 *)(window.GetUserDataLongPtr());
+ if (w == NULL)
+ return 0;
+ return w->OnMessage(message, wParam, lParam);
+}
+
+LRESULT CListView2::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ #ifndef _UNICODE
+ if (g_IsNT)
+ return CallWindowProcW(_origWindowProc, *this, message, wParam, lParam);
+ else
+ #endif
+ return CallWindowProc(_origWindowProc, *this, message, wParam, lParam);
+}
+
+void CListView2::SetWindowProc()
+{
+ SetUserDataLongPtr((LONG_PTR)this);
+ #ifndef _UNICODE
+ if (g_IsNT)
+ _origWindowProc = (WNDPROC)SetLongPtrW(GWLP_WNDPROC, (LONG_PTR)ListViewSubclassProc);
+ else
+ #endif
+ _origWindowProc = (WNDPROC)SetLongPtr(GWLP_WNDPROC, (LONG_PTR)ListViewSubclassProc);
+}
+
+/*
+LRESULT CListView3::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT res = CListView2::OnMessage(message, wParam, lParam);
+ if (message == WM_GETDLGCODE)
+ {
+ // when user presses RETURN, windows sends default (first) button command to parent dialog.
+ // we disable this:
+ MSG *msg = (MSG *)lParam;
+ WPARAM key = wParam;
+ bool change = false;
+ if (msg)
+ {
+ if (msg->message == WM_KEYDOWN && msg->wParam == VK_RETURN)
+ change = true;
+ }
+ else if (wParam == VK_RETURN)
+ change = true;
+ if (change)
+ res |= DLGC_WANTALLKEYS;
+ }
+ return res;
+}
+*/
+
+}}
diff --git a/CPP/Windows/Control/ListView.h b/CPP/Windows/Control/ListView.h
index 1ed496d..11a33a0 100644
--- a/CPP/Windows/Control/ListView.h
+++ b/CPP/Windows/Control/ListView.h
@@ -1,146 +1,156 @@
-// Windows/Control/ListView.h
-
-#ifndef __WINDOWS_CONTROL_LISTVIEW_H
-#define __WINDOWS_CONTROL_LISTVIEW_H
-
-#include "../../Common/MyWindows.h"
-
-#include <commctrl.h>
-
-#include "../Window.h"
-
-namespace NWindows {
-namespace NControl {
-
-class CListView: public NWindows::CWindow
-{
-public:
- bool CreateEx(DWORD exStyle, DWORD style,
- int x, int y, int width, int height,
- HWND parentWindow, HMENU idOrHMenu,
- HINSTANCE instance, LPVOID createParam);
-
- void SetUnicodeFormat()
- {
- #ifndef UNDER_CE
- ListView_SetUnicodeFormat(_window, TRUE);
- #endif
- }
-
- bool DeleteAllItems() { return BOOLToBool(ListView_DeleteAllItems(_window)); }
- bool DeleteColumn(int columnIndex) { return BOOLToBool(ListView_DeleteColumn(_window, columnIndex)); }
-
- int InsertColumn(int columnIndex, const LVCOLUMN *columnInfo) { return ListView_InsertColumn(_window, columnIndex, columnInfo); }
- int InsertColumn(int columnIndex, LPCTSTR text, int width);
- bool SetColumnOrderArray(int count, const int *columns) { return BOOLToBool(ListView_SetColumnOrderArray(_window, count, columns)); }
-
- /*
- int GetNumColumns()
- {
- HWND header = ListView_GetHeader(_window);
- if (!header)
- return -1;
- return Header_GetItemCount(header);
- }
- */
-
- int InsertItem(const LVITEM* item) { return ListView_InsertItem(_window, item); }
- int InsertItem(int index, LPCTSTR text);
- bool SetItem(const LVITEM* item) { return BOOLToBool(ListView_SetItem(_window, item)); }
- int SetSubItem(int index, int subIndex, LPCTSTR text);
-
- #ifndef _UNICODE
-
- int InsertColumn(int columnIndex, const LVCOLUMNW *columnInfo) { return (int)SendMsg(LVM_INSERTCOLUMNW, (WPARAM)columnIndex, (LPARAM)columnInfo); }
- int InsertColumn(int columnIndex, LPCWSTR text, int width);
- int InsertItem(const LV_ITEMW* item) { return (int)SendMsg(LVM_INSERTITEMW, 0, (LPARAM)item); }
- int InsertItem(int index, LPCWSTR text);
- bool SetItem(const LV_ITEMW* item) { return BOOLToBool((BOOL)SendMsg(LVM_SETITEMW, 0, (LPARAM)item)); }
- int SetSubItem(int index, int subIndex, LPCWSTR text);
-
- #endif
-
- bool DeleteItem(int itemIndex) { return BOOLToBool(ListView_DeleteItem(_window, itemIndex)); }
-
- UINT GetSelectedCount() const { return ListView_GetSelectedCount(_window); }
- int GetItemCount() const { return ListView_GetItemCount(_window); }
-
- INT GetSelectionMark() const { return ListView_GetSelectionMark(_window); }
-
- void SetItemCount(int numItems) { ListView_SetItemCount(_window, numItems); }
- void SetItemCountEx(int numItems, DWORD flags) { ListView_SetItemCountEx(_window, numItems, flags); }
-
- int GetNextItem(int startIndex, UINT flags) const { return ListView_GetNextItem(_window, startIndex, flags); }
- int GetNextSelectedItem(int startIndex) const { return GetNextItem(startIndex, LVNI_SELECTED); }
- int GetFocusedItem() const { return GetNextItem(-1, LVNI_FOCUSED); }
-
- bool GetItem(LVITEM* item) const { return BOOLToBool(ListView_GetItem(_window, item)); }
- bool GetItemParam(int itemIndex, LPARAM &param) const;
- void GetItemText(int itemIndex, int subItemIndex, LPTSTR text, int textSizeMax) const
- { ListView_GetItemText(_window, itemIndex, subItemIndex, text, textSizeMax); }
- bool SortItems(PFNLVCOMPARE compareFunction, LPARAM dataParam)
- { return BOOLToBool(ListView_SortItems(_window, compareFunction, dataParam)); }
-
- void SetItemState(int index, UINT state, UINT mask) { ListView_SetItemState(_window, index, state, mask); }
- void SetItemState_Selected(int index, bool select) { SetItemState(index, select ? LVIS_SELECTED : 0, LVIS_SELECTED); }
- void SetItemState_Selected(int index) { SetItemState(index, LVIS_SELECTED, LVIS_SELECTED); }
- void SelectAll() { SetItemState_Selected(-1); }
- void SetItemState_FocusedSelected(int index) { SetItemState(index, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); }
- UINT GetItemState(int index, UINT mask) const { return ListView_GetItemState(_window, index, mask); }
- bool IsItemSelected(int index) const { return GetItemState(index, LVIS_SELECTED) == LVIS_SELECTED; }
-
- bool GetColumn(int columnIndex, LVCOLUMN* columnInfo) const
- { return BOOLToBool(ListView_GetColumn(_window, columnIndex, columnInfo)); }
-
- HIMAGELIST SetImageList(HIMAGELIST imageList, int imageListType)
- { return ListView_SetImageList(_window, imageList, imageListType); }
-
- // version 4.70: NT5 | (NT4 + ie3) | w98 | (w95 + ie3)
- DWORD GetExtendedListViewStyle() { return ListView_GetExtendedListViewStyle(_window); }
- void SetExtendedListViewStyle(DWORD exStyle) { ListView_SetExtendedListViewStyle(_window, exStyle); }
- void SetExtendedListViewStyle(DWORD exMask, DWORD exStyle) { ListView_SetExtendedListViewStyleEx(_window, exMask, exStyle); }
-
- void SetCheckState(UINT index, bool checkState) { ListView_SetCheckState(_window, index, BoolToBOOL(checkState)); }
- bool GetCheckState(UINT index) { return BOOLToBool(ListView_GetCheckState(_window, index)); }
-
- bool EnsureVisible(int index, bool partialOK) { return BOOLToBool(ListView_EnsureVisible(_window, index, BoolToBOOL(partialOK))); }
-
- bool GetItemRect(int index, RECT *rect, int code) { return BOOLToBool(ListView_GetItemRect(_window, index, rect, code)); }
-
- HWND GetEditControl() { return ListView_GetEditControl(_window) ; }
- HWND EditLabel(int itemIndex) { return ListView_EditLabel(_window, itemIndex) ; }
-
- bool RedrawItems(int firstIndex, int lastIndex) { return BOOLToBool(ListView_RedrawItems(_window, firstIndex, lastIndex)); }
- bool RedrawAllItems()
- {
- if (GetItemCount() > 0)
- return RedrawItems(0, GetItemCount() - 1);
- return true;
- }
- bool RedrawItem(int index) { return RedrawItems(index, index); }
-
- int HitTest(LPLVHITTESTINFO info) { return ListView_HitTest(_window, info); }
- COLORREF GetBkColor() { return ListView_GetBkColor(_window); }
- bool SetColumnWidth(int iCol, int cx) { return BOOLToBool(ListView_SetColumnWidth(_window, iCol, cx)); }
- bool SetColumnWidthAuto(int iCol) { return SetColumnWidth(iCol, LVSCW_AUTOSIZE); }
-};
-
-class CListView2: public CListView
-{
- WNDPROC _origWindowProc;
-public:
- void SetWindowProc();
- virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
-};
-
-/*
-class CListView3: public CListView2
-{
-public:
- virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
-};
-*/
-
-}}
-
-#endif
+// Windows/Control/ListView.h
+
+#ifndef ZIP7_INC_WINDOWS_CONTROL_LISTVIEW_H
+#define ZIP7_INC_WINDOWS_CONTROL_LISTVIEW_H
+
+#include "../../Common/MyWindows.h"
+
+#include <CommCtrl.h>
+
+#include "../Window.h"
+
+namespace NWindows {
+namespace NControl {
+
+class CListView: public NWindows::CWindow
+{
+public:
+ bool CreateEx(DWORD exStyle, DWORD style,
+ int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu,
+ HINSTANCE instance, LPVOID createParam);
+
+ void SetUnicodeFormat()
+ {
+ #ifndef UNDER_CE
+ ListView_SetUnicodeFormat(_window, TRUE);
+ #endif
+ }
+
+ bool DeleteAllItems() { return BOOLToBool(ListView_DeleteAllItems(_window)); }
+ bool DeleteColumn(unsigned columnIndex) { return BOOLToBool(ListView_DeleteColumn(_window, columnIndex)); }
+
+ int InsertColumn(unsigned columnIndex, const LVCOLUMN *columnInfo) { return ListView_InsertColumn(_window, columnIndex, columnInfo); }
+ int InsertColumn(unsigned columnIndex, LPCTSTR text, int width);
+ bool SetColumnOrderArray(unsigned count, const int *columns)
+ { return BOOLToBool(ListView_SetColumnOrderArray(_window, count, (int *)(void *)columns)); }
+
+ /*
+ int GetNumColumns()
+ {
+ HWND header = ListView_GetHeader(_window);
+ if (!header)
+ return -1;
+ return Header_GetItemCount(header);
+ }
+ */
+
+ int InsertItem(const LVITEM* item) { return ListView_InsertItem(_window, item); }
+ int InsertItem(unsigned index, LPCTSTR text);
+ bool SetItem(const LVITEM* item) { return BOOLToBool(ListView_SetItem(_window, item)); }
+ int SetSubItem(unsigned index, unsigned subIndex, LPCTSTR text);
+
+ #ifndef _UNICODE
+
+ int InsertColumn(unsigned columnIndex, const LVCOLUMNW *columnInfo) { return (int)SendMsg(LVM_INSERTCOLUMNW, (WPARAM)columnIndex, (LPARAM)columnInfo); }
+ int InsertColumn(unsigned columnIndex, LPCWSTR text, int width);
+ int InsertItem(const LV_ITEMW* item) { return (int)SendMsg(LVM_INSERTITEMW, 0, (LPARAM)item); }
+ int InsertItem(unsigned index, LPCWSTR text);
+ bool SetItem(const LV_ITEMW* item) { return BOOLToBool((BOOL)SendMsg(LVM_SETITEMW, 0, (LPARAM)item)); }
+ int SetSubItem(unsigned index, unsigned subIndex, LPCWSTR text);
+
+ #endif
+
+ bool DeleteItem(unsigned itemIndex) { return BOOLToBool(ListView_DeleteItem(_window, itemIndex)); }
+
+ UINT GetSelectedCount() const { return ListView_GetSelectedCount(_window); }
+ int GetItemCount() const { return ListView_GetItemCount(_window); }
+
+ INT GetSelectionMark() const { return ListView_GetSelectionMark(_window); }
+
+ void SetItemCount(unsigned numItems) { ListView_SetItemCount(_window, numItems); }
+ void SetItemCountEx(unsigned numItems, DWORD flags) { ListView_SetItemCountEx(_window, numItems, flags); }
+
+ /* startIndex : The index of the item with which to begin the search,
+ or -1 to find the first item that matches the specified flags.
+ The specified item itself is excluded from the search. */
+ int GetNextItem(int startIndex, UINT flags) const { return ListView_GetNextItem(_window, startIndex, flags); }
+ int GetNextSelectedItem(int startIndex) const { return GetNextItem(startIndex, LVNI_SELECTED); }
+ int GetFocusedItem() const { return GetNextItem(-1, LVNI_FOCUSED); }
+
+ bool GetItem(LVITEM* item) const { return BOOLToBool(ListView_GetItem(_window, item)); }
+ bool GetItemParam(unsigned itemIndex, LPARAM &param) const;
+ /*
+ void GetItemText(unsigned itemIndex, unsigned subItemIndex, LPTSTR text, unsigned textSizeMax) const
+ { ListView_GetItemText(_window, itemIndex, subItemIndex, text, textSizeMax) }
+ */
+ bool SortItems(PFNLVCOMPARE compareFunction, LPARAM dataParam)
+ { return BOOLToBool(ListView_SortItems(_window, compareFunction, dataParam)); }
+
+ // If (index == -1), then the state change is applied to all items.
+ void SetItemState(int index, UINT state, UINT mask) { ListView_SetItemState(_window, index, state, mask) }
+ void SetItemState_Selected(int index, bool select) { SetItemState(index, select ? LVIS_SELECTED : 0, LVIS_SELECTED); }
+ void SetItemState_Selected(int index) { SetItemState(index, LVIS_SELECTED, LVIS_SELECTED); }
+ void SelectAll() { SetItemState_Selected(-1); }
+ void SetItemState_FocusedSelected(int index) { SetItemState(index, LVIS_FOCUSED | LVIS_SELECTED, LVIS_FOCUSED | LVIS_SELECTED); }
+ UINT GetItemState(int index, UINT mask) const { return ListView_GetItemState(_window, index, mask); }
+ bool IsItemSelected(int index) const { return GetItemState(index, LVIS_SELECTED) == LVIS_SELECTED; }
+
+ bool GetColumn(unsigned columnIndex, LVCOLUMN* columnInfo) const
+ { return BOOLToBool(ListView_GetColumn(_window, columnIndex, columnInfo)); }
+
+ HIMAGELIST SetImageList(HIMAGELIST imageList, int imageListType)
+ { return ListView_SetImageList(_window, imageList, imageListType); }
+
+ // version 4.70: NT5 | (NT4 + ie3) | w98 | (w95 + ie3)
+ DWORD GetExtendedListViewStyle() { return ListView_GetExtendedListViewStyle(_window); }
+ void SetExtendedListViewStyle(DWORD exStyle) { ListView_SetExtendedListViewStyle(_window, exStyle); }
+ void SetExtendedListViewStyle(DWORD exMask, DWORD exStyle) { ListView_SetExtendedListViewStyleEx(_window, exMask, exStyle); }
+
+ void SetCheckState(UINT index, bool checkState) { ListView_SetCheckState(_window, index, BoolToBOOL(checkState)) }
+ bool GetCheckState(UINT index) { return BOOLToBool(ListView_GetCheckState(_window, index)); }
+
+ bool EnsureVisible(int index, bool partialOK) { return BOOLToBool(ListView_EnsureVisible(_window, index, BoolToBOOL(partialOK))); }
+
+ bool GetItemRect(int index, RECT *rect, int code) { return BOOLToBool(ListView_GetItemRect(_window, index, rect, code)); }
+
+ HWND GetEditControl() { return ListView_GetEditControl(_window) ; }
+ HWND EditLabel(int itemIndex) { return ListView_EditLabel(_window, itemIndex) ; }
+
+ bool RedrawItems(int firstIndex, int lastIndex) { return BOOLToBool(ListView_RedrawItems(_window, firstIndex, lastIndex)); }
+ bool RedrawAllItems()
+ {
+ if (GetItemCount() > 0)
+ return RedrawItems(0, GetItemCount() - 1);
+ return true;
+ }
+ bool RedrawItem(int index) { return RedrawItems(index, index); }
+
+ int HitTest(LPLVHITTESTINFO info) { return ListView_HitTest(_window, info); }
+ COLORREF GetBkColor() { return ListView_GetBkColor(_window); }
+ bool SetColumnWidth(int iCol, int cx) { return BOOLToBool(ListView_SetColumnWidth(_window, iCol, cx)); }
+ bool SetColumnWidthAuto(int iCol) { return SetColumnWidth(iCol, LVSCW_AUTOSIZE); }
+};
+
+class CListView2: public CListView
+{
+ WNDPROC _origWindowProc;
+ // ~CListView2() ZIP7_eq_delete;
+public:
+ virtual ~CListView2() {}
+ CListView2() {}
+ void SetWindowProc();
+ virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
+};
+
+/*
+class CListView3: public CListView2
+{
+public:
+ virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
+};
+*/
+
+}}
+
+#endif
diff --git a/CPP/Windows/Control/ProgressBar.h b/CPP/Windows/Control/ProgressBar.h
index f18d89c..2256aa9 100644
--- a/CPP/Windows/Control/ProgressBar.h
+++ b/CPP/Windows/Control/ProgressBar.h
@@ -1,35 +1,35 @@
-// Windows/Control/ProgressBar.h
-
-#ifndef __WINDOWS_CONTROL_PROGRESSBAR_H
-#define __WINDOWS_CONTROL_PROGRESSBAR_H
-
-#include "../../Common/MyWindows.h"
-
-#include <commctrl.h>
-
-#include "../Window.h"
-
-namespace NWindows {
-namespace NControl {
-
-class CProgressBar: public CWindow
-{
-public:
- LRESULT SetPos(int pos) { return SendMsg(PBM_SETPOS, pos, 0); }
- LRESULT DeltaPos(int increment) { return SendMsg(PBM_DELTAPOS, increment, 0); }
- UINT GetPos() { return (UINT)SendMsg(PBM_GETPOS, 0, 0); }
- LRESULT SetRange(unsigned short minValue, unsigned short maxValue) { return SendMsg(PBM_SETRANGE, 0, MAKELPARAM(minValue, maxValue)); }
- DWORD SetRange32(int minValue, int maxValue) { return (DWORD)SendMsg(PBM_SETRANGE32, minValue, maxValue); }
- int SetStep(int step) { return (int)SendMsg(PBM_SETSTEP, step, 0); }
- LRESULT StepIt() { return SendMsg(PBM_STEPIT, 0, 0); }
- INT GetRange(bool minValue, PPBRANGE range) { return (INT)SendMsg(PBM_GETRANGE, BoolToBOOL(minValue), (LPARAM)range); }
-
- #ifndef UNDER_CE
- COLORREF SetBarColor(COLORREF color) { return (COLORREF)SendMsg(PBM_SETBARCOLOR, 0, color); }
- COLORREF SetBackgroundColor(COLORREF color) { return (COLORREF)SendMsg(PBM_SETBKCOLOR, 0, color); }
- #endif
-};
-
-}}
-
-#endif
+// Windows/Control/ProgressBar.h
+
+#ifndef ZIP7_INC_WINDOWS_CONTROL_PROGRESSBAR_H
+#define ZIP7_INC_WINDOWS_CONTROL_PROGRESSBAR_H
+
+#include "../../Common/MyWindows.h"
+
+#include <CommCtrl.h>
+
+#include "../Window.h"
+
+namespace NWindows {
+namespace NControl {
+
+class CProgressBar: public CWindow
+{
+public:
+ LRESULT SetPos(int pos) { return SendMsg(PBM_SETPOS, (unsigned)pos, 0); }
+ // LRESULT DeltaPos(int increment) { return SendMsg(PBM_DELTAPOS, increment, 0); }
+ // UINT GetPos() { return (UINT)SendMsg(PBM_GETPOS, 0, 0); }
+ // LRESULT SetRange(unsigned short minValue, unsigned short maxValue) { return SendMsg(PBM_SETRANGE, 0, MAKELPARAM(minValue, maxValue)); }
+ DWORD SetRange32(int minValue, int maxValue) { return (DWORD)SendMsg(PBM_SETRANGE32, (unsigned)minValue, (LPARAM)(unsigned)maxValue); }
+ // int SetStep(int step) { return (int)SendMsg(PBM_SETSTEP, step, 0); }
+ // LRESULT StepIt() { return SendMsg(PBM_STEPIT, 0, 0); }
+ // INT GetRange(bool minValue, PPBRANGE range) { return (INT)SendMsg(PBM_GETRANGE, BoolToBOOL(minValue), (LPARAM)range); }
+
+ #ifndef UNDER_CE
+ COLORREF SetBarColor(COLORREF color) { return (COLORREF)SendMsg(PBM_SETBARCOLOR, 0, (LPARAM)color); }
+ COLORREF SetBackgroundColor(COLORREF color) { return (COLORREF)SendMsg(PBM_SETBKCOLOR, 0, (LPARAM)color); }
+ #endif
+};
+
+}}
+
+#endif
diff --git a/CPP/Windows/Control/PropertyPage.cpp b/CPP/Windows/Control/PropertyPage.cpp
index 48947c0..f8effe6 100644
--- a/CPP/Windows/Control/PropertyPage.cpp
+++ b/CPP/Windows/Control/PropertyPage.cpp
@@ -1,143 +1,165 @@
-// Windows/Control/PropertyPage.cpp
-
-#include "StdAfx.h"
-
-#ifndef _UNICODE
-#include "../../Common/StringConvert.h"
-#endif
-
-#include "PropertyPage.h"
-
-extern HINSTANCE g_hInstance;
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-namespace NWindows {
-namespace NControl {
-
-static INT_PTR APIENTRY MyProperyPageProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam)
-{
- CWindow tempDialog(dialogHWND);
- if (message == WM_INITDIALOG)
- tempDialog.SetUserDataLongPtr(((PROPSHEETPAGE *)lParam)->lParam);
- CDialog *dialog = (CDialog *)(tempDialog.GetUserDataLongPtr());
- if (dialog == NULL)
- return FALSE;
- if (message == WM_INITDIALOG)
- dialog->Attach(dialogHWND);
- try { return BoolToBOOL(dialog->OnMessage(message, wParam, lParam)); }
- catch(...) { return TRUE; }
-}
-
-bool CPropertyPage::OnNotify(UINT /* controlID */, LPNMHDR lParam)
-{
- switch (lParam->code)
- {
- case PSN_APPLY: SetMsgResult(OnApply(LPPSHNOTIFY(lParam))); break;
- case PSN_KILLACTIVE: SetMsgResult(BoolToBOOL(OnKillActive(LPPSHNOTIFY(lParam)))); break;
- case PSN_SETACTIVE: SetMsgResult(OnSetActive(LPPSHNOTIFY(lParam))); break;
- case PSN_RESET: OnReset(LPPSHNOTIFY(lParam)); break;
- case PSN_HELP: OnNotifyHelp(LPPSHNOTIFY(lParam)); break;
- default: return false;
- }
- return true;
-}
-
-INT_PTR MyPropertySheet(const CObjectVector<CPageInfo> &pagesInfo, HWND hwndParent, const UString &title)
-{
- #ifndef _UNICODE
- AStringVector titles;
- #endif
- #ifndef _UNICODE
- CRecordVector<PROPSHEETPAGEA> pagesA;
- #endif
- CRecordVector<PROPSHEETPAGEW> pagesW;
-
- unsigned i;
- #ifndef _UNICODE
- for (i = 0; i < pagesInfo.Size(); i++)
- titles.Add(GetSystemString(pagesInfo[i].Title));
- #endif
-
- for (i = 0; i < pagesInfo.Size(); i++)
- {
- const CPageInfo &pageInfo = pagesInfo[i];
- #ifndef _UNICODE
- {
- PROPSHEETPAGE page;
- page.dwSize = sizeof(page);
- page.dwFlags = PSP_HASHELP;
- page.hInstance = g_hInstance;
- page.pszTemplate = MAKEINTRESOURCE(pageInfo.ID);
- page.pszIcon = NULL;
- page.pfnDlgProc = NWindows::NControl::MyProperyPageProcedure;
-
- if (titles[i].IsEmpty())
- page.pszTitle = NULL;
- else
- {
- page.dwFlags |= PSP_USETITLE;
- page.pszTitle = titles[i];
- }
- page.lParam = (LPARAM)pageInfo.Page;
- page.pfnCallback = NULL;
- pagesA.Add(page);
- }
- #endif
- {
- PROPSHEETPAGEW page;
- page.dwSize = sizeof(page);
- page.dwFlags = PSP_HASHELP;
- page.hInstance = g_hInstance;
- page.pszTemplate = MAKEINTRESOURCEW(pageInfo.ID);
- page.pszIcon = NULL;
- page.pfnDlgProc = NWindows::NControl::MyProperyPageProcedure;
-
- if (pageInfo.Title.IsEmpty())
- page.pszTitle = NULL;
- else
- {
- page.dwFlags |= PSP_USETITLE;
- page.pszTitle = pageInfo.Title;
- }
- page.lParam = (LPARAM)pageInfo.Page;
- page.pfnCallback = NULL;
- pagesW.Add(page);
- }
- }
-
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- PROPSHEETHEADER sheet;
- sheet.dwSize = sizeof(sheet);
- sheet.dwFlags = PSH_PROPSHEETPAGE;
- sheet.hwndParent = hwndParent;
- sheet.hInstance = g_hInstance;
- AString titleA (GetSystemString(title));
- sheet.pszCaption = titleA;
- sheet.nPages = pagesInfo.Size();
- sheet.nStartPage = 0;
- sheet.ppsp = &pagesA.Front();
- sheet.pfnCallback = NULL;
- return ::PropertySheetA(&sheet);
- }
- else
- #endif
- {
- PROPSHEETHEADERW sheet;
- sheet.dwSize = sizeof(sheet);
- sheet.dwFlags = PSH_PROPSHEETPAGE;
- sheet.hwndParent = hwndParent;
- sheet.hInstance = g_hInstance;
- sheet.pszCaption = title;
- sheet.nPages = pagesInfo.Size();
- sheet.nStartPage = 0;
- sheet.ppsp = &pagesW.Front();
- sheet.pfnCallback = NULL;
- return ::PropertySheetW(&sheet);
- }
-}
-
-}}
+// Windows/Control/PropertyPage.cpp
+
+#include "StdAfx.h"
+
+#ifndef _UNICODE
+#include "../../Common/StringConvert.h"
+#endif
+
+#include "PropertyPage.h"
+
+extern HINSTANCE g_hInstance;
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NControl {
+
+static
+#ifdef Z7_OLD_WIN_SDK
+ BOOL
+#else
+ INT_PTR
+#endif
+APIENTRY MyProperyPageProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ CWindow tempDialog(dialogHWND);
+ if (message == WM_INITDIALOG)
+ tempDialog.SetUserDataLongPtr(((PROPSHEETPAGE *)lParam)->lParam);
+ CDialog *dialog = (CDialog *)(tempDialog.GetUserDataLongPtr());
+ if (dialog == NULL)
+ return FALSE;
+ if (message == WM_INITDIALOG)
+ dialog->Attach(dialogHWND);
+ try { return BoolToBOOL(dialog->OnMessage(message, wParam, lParam)); }
+ catch(...) { return TRUE; }
+}
+
+bool CPropertyPage::OnNotify(UINT /* controlID */, LPNMHDR lParam)
+{
+ switch (lParam->code)
+ {
+ case PSN_APPLY: SetMsgResult(OnApply2(LPPSHNOTIFY(lParam))); break;
+ case PSN_KILLACTIVE: SetMsgResult(BoolToBOOL(OnKillActive2(LPPSHNOTIFY(lParam)))); break;
+ case PSN_SETACTIVE: SetMsgResult(OnSetActive2(LPPSHNOTIFY(lParam))); break;
+ case PSN_RESET: OnReset2(LPPSHNOTIFY(lParam)); break;
+ case PSN_HELP: OnNotifyHelp2(LPPSHNOTIFY(lParam)); break;
+ default: return false;
+ }
+ return true;
+}
+
+/*
+PROPSHEETPAGE fields depend from
+#if (_WIN32_WINNT >= 0x0600)
+#elif (_WIN32_WINNT >= 0x0501)
+#elif (_WIN32_IE >= 0x0400)
+PROPSHEETHEADER fields depend from
+#if (_WIN32_IE >= 0x0400)
+*/
+#if defined(PROPSHEETPAGEA_V1_SIZE) && !defined(Z7_OLD_WIN_SDK)
+#ifndef _UNICODE
+#define my_compatib_PROPSHEETPAGEA PROPSHEETPAGEA_V1
+#endif
+#define my_compatib_PROPSHEETPAGEW PROPSHEETPAGEW_V1
+#else
+// for old mingw:
+#ifndef _UNICODE
+#define my_compatib_PROPSHEETPAGEA PROPSHEETPAGEA
+#endif
+#define my_compatib_PROPSHEETPAGEW PROPSHEETPAGEW
+#endif
+
+INT_PTR MyPropertySheet(const CObjectVector<CPageInfo> &pagesInfo, HWND hwndParent, const UString &title)
+{
+ unsigned i;
+ #ifndef _UNICODE
+ AStringVector titles;
+ for (i = 0; i < pagesInfo.Size(); i++)
+ titles.Add(GetSystemString(pagesInfo[i].Title));
+ CRecordVector<my_compatib_PROPSHEETPAGEA> pagesA;
+ #endif
+ CRecordVector<my_compatib_PROPSHEETPAGEW> pagesW;
+
+ for (i = 0; i < pagesInfo.Size(); i++)
+ {
+ const CPageInfo &pageInfo = pagesInfo[i];
+ #ifndef _UNICODE
+ {
+ my_compatib_PROPSHEETPAGEA page;
+ memset(&page, 0, sizeof(page));
+ page.dwSize = sizeof(page);
+ page.dwFlags = PSP_HASHELP;
+ page.hInstance = g_hInstance;
+ page.pszTemplate = MAKEINTRESOURCEA(pageInfo.ID);
+ // page.pszIcon = NULL;
+ page.pfnDlgProc = NWindows::NControl::MyProperyPageProcedure;
+
+ if (!titles[i].IsEmpty())
+ {
+ page.pszTitle = titles[i];
+ page.dwFlags |= PSP_USETITLE;
+ }
+ // else page.pszTitle = NULL;
+ page.lParam = (LPARAM)pageInfo.Page;
+ // page.pfnCallback = NULL;
+ pagesA.Add(page);
+ }
+ #endif
+ {
+ my_compatib_PROPSHEETPAGEW page;
+ memset(&page, 0, sizeof(page));
+ page.dwSize = sizeof(page);
+ page.dwFlags = PSP_HASHELP;
+ page.hInstance = g_hInstance;
+ page.pszTemplate = MAKEINTRESOURCEW(pageInfo.ID);
+ // page.pszIcon = NULL;
+ page.pfnDlgProc = NWindows::NControl::MyProperyPageProcedure;
+
+ if (!pageInfo.Title.IsEmpty())
+ {
+ page.pszTitle = pageInfo.Title;
+ page.dwFlags |= PSP_USETITLE;
+ }
+ // else page.pszTitle = NULL;
+ page.lParam = (LPARAM)pageInfo.Page;
+ // page.pfnCallback = NULL;
+ pagesW.Add(page);
+ }
+ }
+
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ PROPSHEETHEADERA sheet;
+ sheet.dwSize = sizeof(sheet);
+ sheet.dwFlags = PSH_PROPSHEETPAGE;
+ sheet.hwndParent = hwndParent;
+ sheet.hInstance = g_hInstance;
+ AString titleA (GetSystemString(title));
+ sheet.pszCaption = titleA;
+ sheet.nPages = pagesA.Size();
+ sheet.nStartPage = 0;
+ sheet.ppsp = (LPCPROPSHEETPAGEA)(const void *)&pagesA.Front();
+ sheet.pfnCallback = NULL;
+ return ::PropertySheetA(&sheet);
+ }
+ else
+ #endif
+ {
+ PROPSHEETHEADERW sheet;
+ sheet.dwSize = sizeof(sheet);
+ sheet.dwFlags = PSH_PROPSHEETPAGE;
+ sheet.hwndParent = hwndParent;
+ sheet.hInstance = g_hInstance;
+ sheet.pszCaption = title;
+ sheet.nPages = pagesW.Size();
+ sheet.nStartPage = 0;
+ sheet.ppsp = (LPCPROPSHEETPAGEW)(const void *)&pagesW.Front();
+ sheet.pfnCallback = NULL;
+ return ::PropertySheetW(&sheet);
+ }
+}
+
+}}
diff --git a/CPP/Windows/Control/PropertyPage.h b/CPP/Windows/Control/PropertyPage.h
index 551c959..264a5d2 100644
--- a/CPP/Windows/Control/PropertyPage.h
+++ b/CPP/Windows/Control/PropertyPage.h
@@ -1,50 +1,50 @@
-// Windows/Control/PropertyPage.h
-
-#ifndef __WINDOWS_CONTROL_PROPERTYPAGE_H
-#define __WINDOWS_CONTROL_PROPERTYPAGE_H
-
-#include "../../Common/MyWindows.h"
-
-#include <prsht.h>
-
-#include "Dialog.h"
-
-namespace NWindows {
-namespace NControl {
-
-INT_PTR APIENTRY ProperyPageProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam);
-
-class CPropertyPage: public CDialog
-{
-public:
- CPropertyPage(HWND window = NULL): CDialog(window){};
-
- void Changed() { PropSheet_Changed(GetParent(), (HWND)*this); }
- void UnChanged() { PropSheet_UnChanged(GetParent(), (HWND)*this); }
-
- virtual bool OnNotify(UINT controlID, LPNMHDR lParam);
-
- virtual bool OnKillActive() { return false; } // false = OK
- virtual bool OnKillActive(const PSHNOTIFY *) { return OnKillActive(); }
- virtual LONG OnSetActive() { return false; } // false = OK
- virtual LONG OnSetActive(const PSHNOTIFY *) { return OnSetActive(); }
- virtual LONG OnApply() { return PSNRET_NOERROR; }
- virtual LONG OnApply(const PSHNOTIFY *) { return OnApply(); }
- virtual void OnNotifyHelp() {}
- virtual void OnNotifyHelp(const PSHNOTIFY *) { OnNotifyHelp(); }
- virtual void OnReset() {}
- virtual void OnReset(const PSHNOTIFY *) { OnReset(); }
-};
-
-struct CPageInfo
-{
- CPropertyPage *Page;
- UString Title;
- UINT ID;
-};
-
-INT_PTR MyPropertySheet(const CObjectVector<CPageInfo> &pagesInfo, HWND hwndParent, const UString &title);
-
-}}
-
-#endif
+// Windows/Control/PropertyPage.h
+
+#ifndef ZIP7_INC_WINDOWS_CONTROL_PROPERTYPAGE_H
+#define ZIP7_INC_WINDOWS_CONTROL_PROPERTYPAGE_H
+
+#include "../../Common/MyWindows.h"
+
+#include <prsht.h>
+
+#include "Dialog.h"
+
+namespace NWindows {
+namespace NControl {
+
+INT_PTR APIENTRY ProperyPageProcedure(HWND dialogHWND, UINT message, WPARAM wParam, LPARAM lParam);
+
+class CPropertyPage: public CDialog
+{
+public:
+ CPropertyPage(HWND window = NULL): CDialog(window) {}
+
+ void Changed() { PropSheet_Changed(GetParent(), (HWND)*this); }
+ void UnChanged() { PropSheet_UnChanged(GetParent(), (HWND)*this); }
+
+ virtual bool OnNotify(UINT controlID, LPNMHDR lParam) Z7_override;
+
+ virtual bool OnKillActive() { return false; } // false = OK
+ virtual bool OnKillActive2(const PSHNOTIFY *) { return OnKillActive(); }
+ virtual LONG OnSetActive() { return false; } // false = OK
+ virtual LONG OnSetActive2(const PSHNOTIFY *) { return OnSetActive(); }
+ virtual LONG OnApply() { return PSNRET_NOERROR; }
+ virtual LONG OnApply2(const PSHNOTIFY *) { return OnApply(); }
+ virtual void OnNotifyHelp() {}
+ virtual void OnNotifyHelp2(const PSHNOTIFY *) { OnNotifyHelp(); }
+ virtual void OnReset() {}
+ virtual void OnReset2(const PSHNOTIFY *) { OnReset(); }
+};
+
+struct CPageInfo
+{
+ CPropertyPage *Page;
+ UString Title;
+ UINT ID;
+};
+
+INT_PTR MyPropertySheet(const CObjectVector<CPageInfo> &pagesInfo, HWND hwndParent, const UString &title);
+
+}}
+
+#endif
diff --git a/CPP/Windows/Control/ReBar.h b/CPP/Windows/Control/ReBar.h
index 26fa311..b56f018 100644
--- a/CPP/Windows/Control/ReBar.h
+++ b/CPP/Windows/Control/ReBar.h
@@ -1,34 +1,34 @@
-// Windows/Control/ReBar.h
-
-#ifndef __WINDOWS_CONTROL_REBAR_H
-#define __WINDOWS_CONTROL_REBAR_H
-
-#include "../Window.h"
-
-namespace NWindows {
-namespace NControl {
-
-class CReBar: public NWindows::CWindow
-{
-public:
- bool SetBarInfo(LPREBARINFO barInfo)
- { return LRESULTToBool(SendMsg(RB_SETBARINFO, 0, (LPARAM)barInfo)); }
- bool InsertBand(int index, LPREBARBANDINFO bandInfo)
- { return LRESULTToBool(SendMsg(RB_INSERTBAND, index, (LPARAM)bandInfo)); }
- bool SetBandInfo(unsigned index, LPREBARBANDINFO bandInfo)
- { return LRESULTToBool(SendMsg(RB_SETBANDINFO, index, (LPARAM)bandInfo)); }
- void MaximizeBand(unsigned index, bool ideal)
- { SendMsg(RB_MAXIMIZEBAND, index, BoolToBOOL(ideal)); }
- bool SizeToRect(LPRECT rect)
- { return LRESULTToBool(SendMsg(RB_SIZETORECT, 0, (LPARAM)rect)); }
- UINT GetHeight()
- { return (UINT)SendMsg(RB_GETBARHEIGHT); }
- UINT GetBandCount()
- { return (UINT)SendMsg(RB_GETBANDCOUNT); }
- bool DeleteBand(UINT index)
- { return LRESULTToBool(SendMsg(RB_DELETEBAND, index)); }
-};
-
-}}
-
-#endif
+// Windows/Control/ReBar.h
+
+#ifndef ZIP7_INC_WINDOWS_CONTROL_REBAR_H
+#define ZIP7_INC_WINDOWS_CONTROL_REBAR_H
+
+#include "../Window.h"
+
+namespace NWindows {
+namespace NControl {
+
+class CReBar: public NWindows::CWindow
+{
+public:
+ bool SetBarInfo(LPREBARINFO barInfo)
+ { return LRESULTToBool(SendMsg(RB_SETBARINFO, 0, (LPARAM)barInfo)); }
+ bool InsertBand(int index, LPREBARBANDINFO bandInfo)
+ { return LRESULTToBool(SendMsg(RB_INSERTBAND, MY_int_TO_WPARAM(index), (LPARAM)bandInfo)); }
+ bool SetBandInfo(unsigned index, LPREBARBANDINFO bandInfo)
+ { return LRESULTToBool(SendMsg(RB_SETBANDINFO, index, (LPARAM)bandInfo)); }
+ void MaximizeBand(unsigned index, bool ideal)
+ { SendMsg(RB_MAXIMIZEBAND, index, BoolToBOOL(ideal)); }
+ bool SizeToRect(LPRECT rect)
+ { return LRESULTToBool(SendMsg(RB_SIZETORECT, 0, (LPARAM)rect)); }
+ UINT GetHeight()
+ { return (UINT)SendMsg(RB_GETBARHEIGHT); }
+ UINT GetBandCount()
+ { return (UINT)SendMsg(RB_GETBANDCOUNT); }
+ bool DeleteBand(UINT index)
+ { return LRESULTToBool(SendMsg(RB_DELETEBAND, index)); }
+};
+
+}}
+
+#endif
diff --git a/CPP/Windows/Control/Static.h b/CPP/Windows/Control/Static.h
index 936dd3c..ceeedf9 100644
--- a/CPP/Windows/Control/Static.h
+++ b/CPP/Windows/Control/Static.h
@@ -1,28 +1,28 @@
-// Windows/Control/Static.h
-
-#ifndef __WINDOWS_CONTROL_STATIC_H
-#define __WINDOWS_CONTROL_STATIC_H
-
-#include "../Window.h"
-
-namespace NWindows {
-namespace NControl {
-
-class CStatic: public CWindow
-{
-public:
- HANDLE SetImage(WPARAM imageType, HANDLE handle) { return (HANDLE)SendMsg(STM_SETIMAGE, imageType, (LPARAM)handle); }
- HANDLE GetImage(WPARAM imageType) { return (HANDLE)SendMsg(STM_GETIMAGE, imageType, 0); }
-
- #ifdef UNDER_CE
- HICON SetIcon(HICON icon) { return (HICON)SetImage(IMAGE_ICON, icon); }
- HICON GetIcon() { return (HICON)GetImage(IMAGE_ICON); }
- #else
- HICON SetIcon(HICON icon) { return (HICON)SendMsg(STM_SETICON, (WPARAM)icon, 0); }
- HICON GetIcon() { return (HICON)SendMsg(STM_GETICON, 0, 0); }
- #endif
-};
-
-}}
-
-#endif
+// Windows/Control/Static.h
+
+#ifndef ZIP7_INC_WINDOWS_CONTROL_STATIC_H
+#define ZIP7_INC_WINDOWS_CONTROL_STATIC_H
+
+#include "../Window.h"
+
+namespace NWindows {
+namespace NControl {
+
+class CStatic: public CWindow
+{
+public:
+ HANDLE SetImage(WPARAM imageType, HANDLE handle) { return (HANDLE)SendMsg(STM_SETIMAGE, imageType, (LPARAM)handle); }
+ HANDLE GetImage(WPARAM imageType) { return (HANDLE)SendMsg(STM_GETIMAGE, imageType, 0); }
+
+ #ifdef UNDER_CE
+ HICON SetIcon(HICON icon) { return (HICON)SetImage(IMAGE_ICON, icon); }
+ HICON GetIcon() { return (HICON)GetImage(IMAGE_ICON); }
+ #else
+ HICON SetIcon(HICON icon) { return (HICON)SendMsg(STM_SETICON, (WPARAM)icon, 0); }
+ HICON GetIcon() { return (HICON)SendMsg(STM_GETICON, 0, 0); }
+ #endif
+};
+
+}}
+
+#endif
diff --git a/CPP/Windows/Control/StatusBar.h b/CPP/Windows/Control/StatusBar.h
index 7f7d66b..38aca47 100644
--- a/CPP/Windows/Control/StatusBar.h
+++ b/CPP/Windows/Control/StatusBar.h
@@ -1,42 +1,42 @@
-// Windows/Control/StatusBar.h
-
-#ifndef __WINDOWS_CONTROL_STATUSBAR_H
-#define __WINDOWS_CONTROL_STATUSBAR_H
-
-#include "../Window.h"
-
-namespace NWindows {
-namespace NControl {
-
-class CStatusBar: public NWindows::CWindow
-{
-public:
- bool Create(LONG style, LPCTSTR text, HWND hwndParent, UINT id)
- { return (_window = ::CreateStatusWindow(style, text, hwndParent, id)) != 0; }
- bool SetText(LPCTSTR text)
- { return CWindow::SetText(text); }
- bool SetText(unsigned index, LPCTSTR text, UINT type)
- { return LRESULTToBool(SendMsg(SB_SETTEXT, index | type, (LPARAM)text)); }
- bool SetText(unsigned index, LPCTSTR text)
- { return SetText(index, text, 0); }
-
- #ifndef _UNICODE
- bool Create(LONG style, LPCWSTR text, HWND hwndParent, UINT id)
- { return (_window = ::CreateStatusWindowW(style, text, hwndParent, id)) != 0; }
- bool SetText(LPCWSTR text)
- { return CWindow::SetText(text); }
- bool SetText(unsigned index, LPCWSTR text, UINT type)
- { return LRESULTToBool(SendMsg(SB_SETTEXTW, index | type, (LPARAM)text)); }
- bool SetText(unsigned index, LPCWSTR text)
- { return SetText(index, text, 0); }
- #endif
-
- bool SetParts(unsigned numParts, const int *edgePostions)
- { return LRESULTToBool(SendMsg(SB_SETPARTS, numParts, (LPARAM)edgePostions)); }
- void Simple(bool simple)
- { SendMsg(SB_SIMPLE, BoolToBOOL(simple), 0); }
-};
-
-}}
-
-#endif
+// Windows/Control/StatusBar.h
+
+#ifndef ZIP7_INC_WINDOWS_CONTROL_STATUSBAR_H
+#define ZIP7_INC_WINDOWS_CONTROL_STATUSBAR_H
+
+#include "../Window.h"
+
+namespace NWindows {
+namespace NControl {
+
+class CStatusBar: public NWindows::CWindow
+{
+public:
+ bool Create(LONG style, LPCTSTR text, HWND hwndParent, UINT id)
+ { return (_window = ::CreateStatusWindow(style, text, hwndParent, id)) != NULL; }
+ bool SetText(LPCTSTR text)
+ { return CWindow::SetText(text); }
+ bool SetText(unsigned index, LPCTSTR text, UINT type)
+ { return LRESULTToBool(SendMsg(SB_SETTEXT, index | type, (LPARAM)text)); }
+ bool SetText(unsigned index, LPCTSTR text)
+ { return SetText(index, text, 0); }
+
+ #ifndef _UNICODE
+ bool Create(LONG style, LPCWSTR text, HWND hwndParent, UINT id)
+ { return (_window = ::CreateStatusWindowW(style, text, hwndParent, id)) != NULL; }
+ bool SetText(LPCWSTR text)
+ { return CWindow::SetText(text); }
+ bool SetText(unsigned index, LPCWSTR text, UINT type)
+ { return LRESULTToBool(SendMsg(SB_SETTEXTW, index | type, (LPARAM)text)); }
+ bool SetText(unsigned index, LPCWSTR text)
+ { return SetText(index, text, 0); }
+ #endif
+
+ bool SetParts(unsigned numParts, const int *edgePostions)
+ { return LRESULTToBool(SendMsg(SB_SETPARTS, numParts, (LPARAM)edgePostions)); }
+ void Simple(bool simple)
+ { SendMsg(SB_SIMPLE, (WPARAM)BoolToBOOL(simple), 0); }
+};
+
+}}
+
+#endif
diff --git a/CPP/Windows/Control/StdAfx.h b/CPP/Windows/Control/StdAfx.h
index 42a088f..8086655 100644
--- a/CPP/Windows/Control/StdAfx.h
+++ b/CPP/Windows/Control/StdAfx.h
@@ -1,8 +1,11 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "../../Common/Common.h"
-
-#endif
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+#include "../../Common/Common.h"
+
+#endif
diff --git a/CPP/Windows/Control/ToolBar.h b/CPP/Windows/Control/ToolBar.h
index 02ed9a1..2bf20a5 100644
--- a/CPP/Windows/Control/ToolBar.h
+++ b/CPP/Windows/Control/ToolBar.h
@@ -1,43 +1,43 @@
-// Windows/Control/ToolBar.h
-
-#ifndef __WINDOWS_CONTROL_TOOLBAR_H
-#define __WINDOWS_CONTROL_TOOLBAR_H
-
-#include "../Window.h"
-
-namespace NWindows {
-namespace NControl {
-
-class CToolBar: public NWindows::CWindow
-{
-public:
- void AutoSize() { SendMsg(TB_AUTOSIZE, 0, 0); }
- DWORD GetButtonSize() { return (DWORD)SendMsg(TB_GETBUTTONSIZE, 0, 0); }
-
- bool GetMaxSize(LPSIZE size)
- #ifdef UNDER_CE
- {
- // maybe it must be fixed for more than 1 buttons
- DWORD val = GetButtonSize();
- size->cx = LOWORD(val);
- size->cy = HIWORD(val);
- return true;
- }
- #else
- {
- return LRESULTToBool(SendMsg(TB_GETMAXSIZE, 0, (LPARAM)size));
- }
- #endif
-
- bool EnableButton(UINT buttonID, bool enable) { return LRESULTToBool(SendMsg(TB_ENABLEBUTTON, buttonID, MAKELONG(BoolToBOOL(enable), 0))); }
- void ButtonStructSize() { SendMsg(TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON)); }
- HIMAGELIST SetImageList(UINT listIndex, HIMAGELIST imageList) { return HIMAGELIST(SendMsg(TB_SETIMAGELIST, listIndex, (LPARAM)imageList)); }
- bool AddButton(UINT numButtons, LPTBBUTTON buttons) { return LRESULTToBool(SendMsg(TB_ADDBUTTONS, numButtons, (LPARAM)buttons)); }
- #ifndef _UNICODE
- bool AddButtonW(UINT numButtons, LPTBBUTTON buttons) { return LRESULTToBool(SendMsg(TB_ADDBUTTONSW, numButtons, (LPARAM)buttons)); }
- #endif
-};
-
-}}
-
-#endif
+// Windows/Control/ToolBar.h
+
+#ifndef ZIP7_INC_WINDOWS_CONTROL_TOOLBAR_H
+#define ZIP7_INC_WINDOWS_CONTROL_TOOLBAR_H
+
+#include "../Window.h"
+
+namespace NWindows {
+namespace NControl {
+
+class CToolBar: public NWindows::CWindow
+{
+public:
+ void AutoSize() { SendMsg(TB_AUTOSIZE, 0, 0); }
+ DWORD GetButtonSize() { return (DWORD)SendMsg(TB_GETBUTTONSIZE, 0, 0); }
+
+ bool GetMaxSize(LPSIZE size)
+ #ifdef UNDER_CE
+ {
+ // maybe it must be fixed for more than 1 buttons
+ const DWORD val = GetButtonSize();
+ size->cx = LOWORD(val);
+ size->cy = HIWORD(val);
+ return true;
+ }
+ #else
+ {
+ return LRESULTToBool(SendMsg(TB_GETMAXSIZE, 0, (LPARAM)size));
+ }
+ #endif
+
+ bool EnableButton(UINT buttonID, bool enable) { return LRESULTToBool(SendMsg(TB_ENABLEBUTTON, buttonID, MAKELONG(BoolToBOOL(enable), 0))); }
+ void ButtonStructSize() { SendMsg(TB_BUTTONSTRUCTSIZE, sizeof(TBBUTTON)); }
+ HIMAGELIST SetImageList(UINT listIndex, HIMAGELIST imageList) { return HIMAGELIST(SendMsg(TB_SETIMAGELIST, listIndex, (LPARAM)imageList)); }
+ bool AddButton(UINT numButtons, LPTBBUTTON buttons) { return LRESULTToBool(SendMsg(TB_ADDBUTTONS, numButtons, (LPARAM)buttons)); }
+ #ifndef _UNICODE
+ bool AddButtonW(UINT numButtons, LPTBBUTTON buttons) { return LRESULTToBool(SendMsg(TB_ADDBUTTONSW, numButtons, (LPARAM)buttons)); }
+ #endif
+};
+
+}}
+
+#endif
diff --git a/CPP/Windows/Control/Trackbar.h b/CPP/Windows/Control/Trackbar.h
index afc9bf2..18d1b29 100644
--- a/CPP/Windows/Control/Trackbar.h
+++ b/CPP/Windows/Control/Trackbar.h
@@ -1,27 +1,27 @@
-// Windows/Control/Trackbar.h
-
-#ifndef __WINDOWS_CONTROL_TRACKBAR_H
-#define __WINDOWS_CONTROL_TRACKBAR_H
-
-#include "../Window.h"
-
-namespace NWindows {
-namespace NControl {
-
-class CTrackbar: public CWindow
-{
-public:
- void SetRange(int minimum, int maximum, bool redraw = true)
- { SendMsg(TBM_SETRANGE, BoolToBOOL(redraw), MAKELONG(minimum, maximum)); }
- void SetPos(int pos, bool redraw = true)
- { SendMsg(TBM_SETPOS, BoolToBOOL(redraw), pos); }
- void SetTicFreq(int freq)
- { SendMsg(TBM_SETTICFREQ, freq); }
-
- int GetPos()
- { return (int)SendMsg(TBM_GETPOS); }
-};
-
-}}
-
-#endif
+// Windows/Control/Trackbar.h
+
+#ifndef ZIP7_INC_WINDOWS_CONTROL_TRACKBAR_H
+#define ZIP7_INC_WINDOWS_CONTROL_TRACKBAR_H
+
+#include "../Window.h"
+
+namespace NWindows {
+namespace NControl {
+
+class CTrackbar: public CWindow
+{
+public:
+ void SetRange(int minimum, int maximum, bool redraw = true)
+ { SendMsg(TBM_SETRANGE, BoolToBOOL(redraw), MAKELONG(minimum, maximum)); }
+ void SetPos(int pos, bool redraw = true)
+ { SendMsg(TBM_SETPOS, BoolToBOOL(redraw), pos); }
+ void SetTicFreq(int freq)
+ { SendMsg(TBM_SETTICFREQ, freq); }
+
+ int GetPos()
+ { return (int)SendMsg(TBM_GETPOS); }
+};
+
+}}
+
+#endif
diff --git a/CPP/Windows/Control/Window2.cpp b/CPP/Windows/Control/Window2.cpp
index b6e6d67..8fe908e 100644
--- a/CPP/Windows/Control/Window2.cpp
+++ b/CPP/Windows/Control/Window2.cpp
@@ -1,200 +1,202 @@
-// Windows/Control/Window2.cpp
-
-#include "StdAfx.h"
-
-#ifndef _UNICODE
-#include "../../Common/StringConvert.h"
-#endif
-
-#include "Window2.h"
-
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-namespace NWindows {
-
-#ifndef _UNICODE
-ATOM MyRegisterClass(CONST WNDCLASSW *wndClass);
-#endif
-
-namespace NControl {
-
-#ifdef UNDER_CE
-#define MY_START_WM_CREATE WM_CREATE
-#else
-#define MY_START_WM_CREATE WM_NCCREATE
-#endif
-
-static LRESULT CALLBACK WindowProcedure(HWND aHWND, UINT message, WPARAM wParam, LPARAM lParam)
-{
- CWindow tempWindow(aHWND);
- if (message == MY_START_WM_CREATE)
- tempWindow.SetUserDataLongPtr((LONG_PTR)(((LPCREATESTRUCT)lParam)->lpCreateParams));
- CWindow2 *window = (CWindow2 *)(tempWindow.GetUserDataLongPtr());
- if (window != NULL && message == MY_START_WM_CREATE)
- window->Attach(aHWND);
- if (window == 0)
- {
- #ifndef _UNICODE
- if (g_IsNT)
- return DefWindowProcW(aHWND, message, wParam, lParam);
- else
- #endif
- return DefWindowProc(aHWND, message, wParam, lParam);
- }
- return window->OnMessage(message, wParam, lParam);
-}
-
-bool CWindow2::CreateEx(DWORD exStyle, LPCTSTR className, LPCTSTR windowName,
- DWORD style, int x, int y, int width, int height,
- HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance)
-{
- WNDCLASS wc;
- if (!::GetClassInfo(instance, className, &wc))
- {
- // wc.style = CS_HREDRAW | CS_VREDRAW;
- wc.style = 0;
- wc.lpfnWndProc = WindowProcedure;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = instance;
- wc.hIcon = NULL;
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
- wc.lpszMenuName = NULL;
- wc.lpszClassName = className;
- if (::RegisterClass(&wc) == 0)
- return false;
- }
- return CWindow::CreateEx(exStyle, className, windowName, style,
- x, y, width, height, parentWindow, idOrHMenu, instance, this);
-}
-
-#ifndef _UNICODE
-
-bool CWindow2::CreateEx(DWORD exStyle, LPCWSTR className, LPCWSTR windowName,
- DWORD style, int x, int y, int width, int height,
- HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance)
-{
- bool needRegister;
- if (g_IsNT)
- {
- WNDCLASSW wc;
- needRegister = ::GetClassInfoW(instance, className, &wc) == 0;
- }
- else
- {
- WNDCLASSA windowClassA;
- AString classNameA;
- LPCSTR classNameP;
- if (IS_INTRESOURCE(className))
- classNameP = (LPCSTR)className;
- else
- {
- classNameA = GetSystemString(className);
- classNameP = classNameA;
- }
- needRegister = ::GetClassInfoA(instance, classNameP, &windowClassA) == 0;
- }
- if (needRegister)
- {
- WNDCLASSW wc;
- // wc.style = CS_HREDRAW | CS_VREDRAW;
- wc.style = 0;
- wc.lpfnWndProc = WindowProcedure;
- wc.cbClsExtra = 0;
- wc.cbWndExtra = 0;
- wc.hInstance = instance;
- wc.hIcon = NULL;
- wc.hCursor = LoadCursor(NULL, IDC_ARROW);
- wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
- wc.lpszMenuName = NULL;
- wc.lpszClassName = className;
- if (MyRegisterClass(&wc) == 0)
- return false;
- }
- return CWindow::CreateEx(exStyle, className, windowName, style,
- x, y, width, height, parentWindow, idOrHMenu, instance, this);
-}
-
-#endif
-
-LRESULT CWindow2::DefProc(UINT message, WPARAM wParam, LPARAM lParam)
-{
- #ifndef _UNICODE
- if (g_IsNT)
- return DefWindowProcW(_window, message, wParam, lParam);
- else
- #endif
- return DefWindowProc(_window, message, wParam, lParam);
-}
-
-LRESULT CWindow2::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
-{
- LRESULT result;
- switch (message)
- {
- case WM_CREATE:
- if (!OnCreate((CREATESTRUCT *)lParam))
- return -1;
- break;
- case WM_COMMAND:
- if (OnCommand(wParam, lParam, result))
- return result;
- break;
- case WM_NOTIFY:
- if (OnNotify((UINT)wParam, (LPNMHDR) lParam, result))
- return result;
- break;
- case WM_DESTROY:
- OnDestroy();
- break;
- case WM_CLOSE:
- OnClose();
- return 0;
- case WM_SIZE:
- if (OnSize(wParam, LOWORD(lParam), HIWORD(lParam)))
- return 0;
- }
- return DefProc(message, wParam, lParam);
-}
-
-bool CWindow2::OnCommand(WPARAM wParam, LPARAM lParam, LRESULT &result)
-{
- return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam, result);
-}
-
-bool CWindow2::OnCommand(int /* code */, int /* itemID */, LPARAM /* lParam */, LRESULT & /* result */)
-{
- return false;
- // return DefProc(message, wParam, lParam);
- /*
- if (code == BN_CLICKED)
- return OnButtonClicked(itemID, (HWND)lParam);
- */
-}
-
-/*
-bool CDialog::OnButtonClicked(int buttonID, HWND buttonHWND)
-{
- switch (buttonID)
- {
- case IDOK:
- OnOK();
- break;
- case IDCANCEL:
- OnCancel();
- break;
- case IDHELP:
- OnHelp();
- break;
- default:
- return false;
- }
- return true;
-}
-
-*/
-
-}}
+// Windows/Control/Window2.cpp
+
+#include "StdAfx.h"
+
+#ifndef _UNICODE
+#include "../../Common/StringConvert.h"
+#endif
+
+#include "Window2.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+
+#ifndef _UNICODE
+ATOM MyRegisterClass(CONST WNDCLASSW *wndClass);
+#endif
+
+namespace NControl {
+
+#ifdef UNDER_CE
+#define MY_START_WM_CREATE WM_CREATE
+#else
+#define MY_START_WM_CREATE WM_NCCREATE
+#endif
+
+static LRESULT CALLBACK WindowProcedure(HWND aHWND, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ CWindow tempWindow(aHWND);
+ if (message == MY_START_WM_CREATE)
+ tempWindow.SetUserDataLongPtr((LONG_PTR)(((LPCREATESTRUCT)lParam)->lpCreateParams));
+ CWindow2 *window = (CWindow2 *)(tempWindow.GetUserDataLongPtr());
+ if (window && message == MY_START_WM_CREATE)
+ window->Attach(aHWND);
+ if (!window)
+ {
+ #ifndef _UNICODE
+ if (g_IsNT)
+ return DefWindowProcW(aHWND, message, wParam, lParam);
+ else
+ #endif
+ return DefWindowProc(aHWND, message, wParam, lParam);
+ }
+ return window->OnMessage(message, wParam, lParam);
+}
+
+bool CWindow2::CreateEx(DWORD exStyle, LPCTSTR className, LPCTSTR windowName,
+ DWORD style, int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance)
+{
+ WNDCLASS wc;
+ if (!::GetClassInfo(instance, className, &wc))
+ {
+ // wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.style = 0;
+ wc.lpfnWndProc = WindowProcedure;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = instance;
+ wc.hIcon = NULL;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = className;
+ if (::RegisterClass(&wc) == 0)
+ return false;
+ }
+ return CWindow::CreateEx(exStyle, className, windowName, style,
+ x, y, width, height, parentWindow, idOrHMenu, instance, this);
+}
+
+#ifndef _UNICODE
+
+bool CWindow2::CreateEx(DWORD exStyle, LPCWSTR className, LPCWSTR windowName,
+ DWORD style, int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance)
+{
+ bool needRegister;
+ if (g_IsNT)
+ {
+ WNDCLASSW wc;
+ needRegister = ::GetClassInfoW(instance, className, &wc) == 0;
+ }
+ else
+ {
+ WNDCLASSA windowClassA;
+ AString classNameA;
+ LPCSTR classNameP;
+ if (IS_INTRESOURCE(className))
+ classNameP = (LPCSTR)className;
+ else
+ {
+ classNameA = GetSystemString(className);
+ classNameP = classNameA;
+ }
+ needRegister = ::GetClassInfoA(instance, classNameP, &windowClassA) == 0;
+ }
+ if (needRegister)
+ {
+ WNDCLASSW wc;
+ // wc.style = CS_HREDRAW | CS_VREDRAW;
+ wc.style = 0;
+ wc.lpfnWndProc = WindowProcedure;
+ wc.cbClsExtra = 0;
+ wc.cbWndExtra = 0;
+ wc.hInstance = instance;
+ wc.hIcon = NULL;
+ wc.hCursor = LoadCursor(NULL, IDC_ARROW);
+ wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
+ wc.lpszMenuName = NULL;
+ wc.lpszClassName = className;
+ if (MyRegisterClass(&wc) == 0)
+ return false;
+ }
+ return CWindow::CreateEx(exStyle, className, windowName, style,
+ x, y, width, height, parentWindow, idOrHMenu, instance, this);
+}
+
+#endif
+
+LRESULT CWindow2::DefProc(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ #ifndef _UNICODE
+ if (g_IsNT)
+ return DefWindowProcW(_window, message, wParam, lParam);
+ else
+ #endif
+ return DefWindowProc(_window, message, wParam, lParam);
+}
+
+LRESULT CWindow2::OnMessage(UINT message, WPARAM wParam, LPARAM lParam)
+{
+ LRESULT result;
+ switch (message)
+ {
+ case WM_CREATE:
+ if (!OnCreate((CREATESTRUCT *)lParam))
+ return -1;
+ break;
+ case WM_COMMAND:
+ if (OnCommand(HIWORD(wParam), LOWORD(wParam), lParam, result))
+ return result;
+ break;
+ case WM_NOTIFY:
+ if (OnNotify((UINT)wParam, (LPNMHDR) lParam, result))
+ return result;
+ break;
+ case WM_DESTROY:
+ OnDestroy();
+ break;
+ case WM_CLOSE:
+ OnClose();
+ return 0;
+ case WM_SIZE:
+ if (OnSize(wParam, LOWORD(lParam), HIWORD(lParam)))
+ return 0;
+ }
+ return DefProc(message, wParam, lParam);
+}
+
+/*
+bool CWindow2::OnCommand2(WPARAM wParam, LPARAM lParam, LRESULT &result)
+{
+ return OnCommand(HIWORD(wParam), LOWORD(wParam), lParam, result);
+}
+*/
+
+bool CWindow2::OnCommand(unsigned /* code */, unsigned /* itemID */, LPARAM /* lParam */, LRESULT & /* result */)
+{
+ return false;
+ // return DefProc(message, wParam, lParam);
+ /*
+ if (code == BN_CLICKED)
+ return OnButtonClicked(itemID, (HWND)lParam);
+ */
+}
+
+/*
+bool CDialog::OnButtonClicked(unsigned buttonID, HWND buttonHWND)
+{
+ switch (buttonID)
+ {
+ case IDOK:
+ OnOK();
+ break;
+ case IDCANCEL:
+ OnCancel();
+ break;
+ case IDHELP:
+ OnHelp();
+ break;
+ default:
+ return false;
+ }
+ return true;
+}
+
+*/
+
+}}
diff --git a/CPP/Windows/Control/Window2.h b/CPP/Windows/Control/Window2.h
index d632b86..ebb5979 100644
--- a/CPP/Windows/Control/Window2.h
+++ b/CPP/Windows/Control/Window2.h
@@ -1,51 +1,53 @@
-// Windows/Control/Window2.h
-
-#ifndef __WINDOWS_CONTROL_WINDOW2_H
-#define __WINDOWS_CONTROL_WINDOW2_H
-
-#include "../Window.h"
-
-namespace NWindows {
-namespace NControl {
-
-class CWindow2: public CWindow
-{
- LRESULT DefProc(UINT message, WPARAM wParam, LPARAM lParam);
-public:
- CWindow2(HWND newWindow = NULL): CWindow(newWindow){};
- virtual ~CWindow2() {};
-
- bool CreateEx(DWORD exStyle, LPCTSTR className, LPCTSTR windowName,
- DWORD style, int x, int y, int width, int height,
- HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance);
-
- #ifndef _UNICODE
- bool CreateEx(DWORD exStyle, LPCWSTR className, LPCWSTR windowName,
- DWORD style, int x, int y, int width, int height,
- HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance);
- #endif
-
- virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
- virtual bool OnCreate(CREATESTRUCT * /* createStruct */) { return true; }
- // virtual LRESULT OnCommand(WPARAM wParam, LPARAM lParam);
- virtual bool OnCommand(WPARAM wParam, LPARAM lParam, LRESULT &result);
- virtual bool OnCommand(int code, int itemID, LPARAM lParam, LRESULT &result);
- virtual bool OnSize(WPARAM /* wParam */, int /* xSize */, int /* ySize */) { return false; }
- virtual bool OnNotify(UINT /* controlID */, LPNMHDR /* lParam */, LRESULT & /* result */) { return false; }
- virtual void OnDestroy() { PostQuitMessage(0); }
- virtual void OnClose() { Destroy(); }
- /*
- virtual LRESULT OnHelp(LPHELPINFO helpInfo) { OnHelp(); }
- virtual LRESULT OnHelp() {};
- virtual bool OnButtonClicked(int buttonID, HWND buttonHWND);
- virtual void OnOK() {};
- virtual void OnCancel() {};
- */
-
- LONG_PTR SetMsgResult(LONG_PTR newLongPtr) { return SetLongPtr(DWLP_MSGRESULT, newLongPtr); }
- LONG_PTR GetMsgResult() const { return GetLongPtr(DWLP_MSGRESULT); }
-};
-
-}}
-
-#endif
+// Windows/Control/Window2.h
+
+#ifndef ZIP7_INC_WINDOWS_CONTROL_WINDOW2_H
+#define ZIP7_INC_WINDOWS_CONTROL_WINDOW2_H
+
+#include "../Window.h"
+
+namespace NWindows {
+namespace NControl {
+
+class CWindow2: public CWindow
+{
+ // Z7_CLASS_NO_COPY(CWindow2)
+
+ LRESULT DefProc(UINT message, WPARAM wParam, LPARAM lParam);
+public:
+ CWindow2(HWND newWindow = NULL): CWindow(newWindow) {}
+ virtual ~CWindow2() {}
+
+ bool CreateEx(DWORD exStyle, LPCTSTR className, LPCTSTR windowName,
+ DWORD style, int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance);
+
+ #ifndef _UNICODE
+ bool CreateEx(DWORD exStyle, LPCWSTR className, LPCWSTR windowName,
+ DWORD style, int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu, HINSTANCE instance);
+ #endif
+
+ virtual LRESULT OnMessage(UINT message, WPARAM wParam, LPARAM lParam);
+ virtual bool OnCreate(CREATESTRUCT * /* createStruct */) { return true; }
+ // virtual LRESULT OnCommand(WPARAM wParam, LPARAM lParam);
+ // bool OnCommand2(WPARAM wParam, LPARAM lParam, LRESULT &result);
+ virtual bool OnCommand(unsigned code, unsigned itemID, LPARAM lParam, LRESULT &result);
+ virtual bool OnSize(WPARAM /* wParam */, int /* xSize */, int /* ySize */) { return false; }
+ virtual bool OnNotify(UINT /* controlID */, LPNMHDR /* lParam */, LRESULT & /* result */) { return false; }
+ virtual void OnDestroy() { PostQuitMessage(0); }
+ virtual void OnClose() { Destroy(); }
+ /*
+ virtual LRESULT OnHelp(LPHELPINFO helpInfo) { OnHelp(); }
+ virtual LRESULT OnHelp() {};
+ virtual bool OnButtonClicked(unsigned buttonID, HWND buttonHWND);
+ virtual void OnOK() {};
+ virtual void OnCancel() {};
+ */
+
+ LONG_PTR SetMsgResult(LONG_PTR newLongPtr) { return SetLongPtr(DWLP_MSGRESULT, newLongPtr); }
+ LONG_PTR GetMsgResult() const { return GetLongPtr(DWLP_MSGRESULT); }
+};
+
+}}
+
+#endif
diff --git a/CPP/Windows/DLL.cpp b/CPP/Windows/DLL.cpp
index efee379..b2499ec 100644
--- a/CPP/Windows/DLL.cpp
+++ b/CPP/Windows/DLL.cpp
@@ -1,109 +1,179 @@
-// Windows/DLL.cpp
-
-#include "StdAfx.h"
-
-#include "DLL.h"
-
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-extern HINSTANCE g_hInstance;
-
-namespace NWindows {
-namespace NDLL {
-
-bool CLibrary::Free() throw()
-{
- if (_module == 0)
- return true;
- if (!::FreeLibrary(_module))
- return false;
- _module = 0;
- return true;
-}
-
-bool CLibrary::LoadEx(CFSTR path, DWORD flags) throw()
-{
- if (!Free())
- return false;
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- _module = ::LoadLibraryEx(fs2fas(path), NULL, flags);
- }
- else
- #endif
- {
- _module = ::LoadLibraryExW(fs2us(path), NULL, flags);
- }
- return (_module != NULL);
-}
-
-bool CLibrary::Load(CFSTR path) throw()
-{
- if (!Free())
- return false;
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- _module = ::LoadLibrary(fs2fas(path));
- }
- else
- #endif
- {
- _module = ::LoadLibraryW(fs2us(path));
- }
- return (_module != NULL);
-}
-
-bool MyGetModuleFileName(FString &path)
-{
- HMODULE hModule = g_hInstance;
- path.Empty();
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- TCHAR s[MAX_PATH + 2];
- s[0] = 0;
- DWORD size = ::GetModuleFileName(hModule, s, MAX_PATH + 1);
- if (size <= MAX_PATH && size != 0)
- {
- path = fas2fs(s);
- return true;
- }
- }
- else
- #endif
- {
- WCHAR s[MAX_PATH + 2];
- s[0] = 0;
- DWORD size = ::GetModuleFileNameW(hModule, s, MAX_PATH + 1);
- if (size <= MAX_PATH && size != 0)
- {
- path = us2fs(s);
- return true;
- }
- }
- return false;
-}
-
-#ifndef _SFX
-
-FString GetModuleDirPrefix()
-{
- FString s;
- if (MyGetModuleFileName(s))
- {
- int pos = s.ReverseFind_PathSepar();
- if (pos >= 0)
- s.DeleteFrom(pos + 1);
- }
- if (s.IsEmpty())
- s = "." STRING_PATH_SEPARATOR;
- return s;
-}
-
-#endif
-
-}}
+// Windows/DLL.cpp
+
+#include "StdAfx.h"
+
+#include "DLL.h"
+
+#ifdef _WIN32
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+extern HINSTANCE g_hInstance;
+
+namespace NWindows {
+namespace NDLL {
+
+bool CLibrary::Free() throw()
+{
+ if (_module == NULL)
+ return true;
+ if (!::FreeLibrary(_module))
+ return false;
+ _module = NULL;
+ return true;
+}
+
+bool CLibrary::LoadEx(CFSTR path, DWORD flags) throw()
+{
+ if (!Free())
+ return false;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ _module = ::LoadLibraryEx(fs2fas(path), NULL, flags);
+ }
+ else
+ #endif
+ {
+ _module = ::LoadLibraryExW(fs2us(path), NULL, flags);
+ }
+ return (_module != NULL);
+}
+
+bool CLibrary::Load(CFSTR path) throw()
+{
+ if (!Free())
+ return false;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ _module = ::LoadLibrary(fs2fas(path));
+ }
+ else
+ #endif
+ {
+ _module = ::LoadLibraryW(fs2us(path));
+ }
+ return (_module != NULL);
+}
+
+bool MyGetModuleFileName(FString &path)
+{
+ HMODULE hModule = g_hInstance;
+ path.Empty();
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ TCHAR s[MAX_PATH + 2];
+ s[0] = 0;
+ DWORD size = ::GetModuleFileName(hModule, s, MAX_PATH + 1);
+ if (size <= MAX_PATH && size != 0)
+ {
+ path = fas2fs(s);
+ return true;
+ }
+ }
+ else
+ #endif
+ {
+ WCHAR s[MAX_PATH + 2];
+ s[0] = 0;
+ DWORD size = ::GetModuleFileNameW(hModule, s, MAX_PATH + 1);
+ if (size <= MAX_PATH && size != 0)
+ {
+ path = us2fs(s);
+ return true;
+ }
+ }
+ return false;
+}
+
+#ifndef Z7_SFX
+
+FString GetModuleDirPrefix()
+{
+ FString s;
+ if (MyGetModuleFileName(s))
+ {
+ int pos = s.ReverseFind_PathSepar();
+ if (pos >= 0)
+ s.DeleteFrom((unsigned)(pos + 1));
+ }
+ if (s.IsEmpty())
+ s = "." STRING_PATH_SEPARATOR;
+ return s;
+}
+
+#endif
+
+}}
+
+#else // _WIN32
+
+#include <dlfcn.h>
+#include <stdlib.h>
+#include "../Common/Common.h"
+
+// FARPROC
+void *GetProcAddress(HMODULE module, LPCSTR procName)
+{
+ void *ptr = NULL;
+ if (module)
+ ptr = dlsym(module, procName);
+ return ptr;
+}
+
+namespace NWindows {
+namespace NDLL {
+
+bool CLibrary::Free() throw()
+{
+ if (!_module)
+ return true;
+ const int ret = dlclose(_module);
+ if (ret != 0)
+ return false;
+ _module = NULL;
+ return true;
+}
+
+bool CLibrary::Load(CFSTR path) throw()
+{
+ if (!Free())
+ return false;
+
+ int options = 0;
+
+ #ifdef RTLD_LOCAL
+ options |= RTLD_LOCAL;
+ #endif
+
+ #ifdef RTLD_NOW
+ options |= RTLD_NOW;
+ #endif
+
+ #ifdef RTLD_GROUP
+ #if ! (defined(hpux) || defined(__hpux))
+ options |= RTLD_GROUP; // mainly for solaris but not for HPUX
+ #endif
+ #endif
+
+ _module = dlopen(path, options);
+ return (_module != NULL);
+}
+
+/*
+// FARPROC
+void * CLibrary::GetProc(LPCSTR procName) const
+{
+ // return My_GetProcAddress(_module, procName);
+ return local_GetProcAddress(_module, procName);
+ // return NULL;
+}
+*/
+
+}}
+
+#endif
diff --git a/CPP/Windows/DLL.h b/CPP/Windows/DLL.h
index 58bcf19..19a82b3 100644
--- a/CPP/Windows/DLL.h
+++ b/CPP/Windows/DLL.h
@@ -1,58 +1,103 @@
-// Windows/DLL.h
-
-#ifndef __WINDOWS_DLL_H
-#define __WINDOWS_DLL_H
-
-#include "../Common/MyString.h"
-
-namespace NWindows {
-namespace NDLL {
-
-#ifdef UNDER_CE
-#define My_GetProcAddress(module, procName) ::GetProcAddressA(module, procName)
-#else
-#define My_GetProcAddress(module, procName) ::GetProcAddress(module, procName)
-#endif
-
-/* Win32: Don't call CLibrary::Free() and FreeLibrary() from another
- FreeLibrary() code: detaching code in DLL entry-point or in
- destructors of global objects in DLL module. */
-
-class CLibrary
-{
- HMODULE _module;
-
- // CLASS_NO_COPY(CLibrary);
-public:
- CLibrary(): _module(NULL) {};
- ~CLibrary() { Free(); }
-
- operator HMODULE() const { return _module; }
- HMODULE* operator&() { return &_module; }
- bool IsLoaded() const { return (_module != NULL); }
-
- void Attach(HMODULE m)
- {
- Free();
- _module = m;
- }
- HMODULE Detach()
- {
- HMODULE m = _module;
- _module = NULL;
- return m;
- }
-
- bool Free() throw();
- bool LoadEx(CFSTR path, DWORD flags = LOAD_LIBRARY_AS_DATAFILE) throw();
- bool Load(CFSTR path) throw();
- FARPROC GetProc(LPCSTR procName) const { return My_GetProcAddress(_module, procName); }
-};
-
-bool MyGetModuleFileName(FString &path);
-
-FString GetModuleDirPrefix();
-
-}}
-
-#endif
+// Windows/DLL.h
+
+#ifndef ZIP7_INC_WINDOWS_DLL_H
+#define ZIP7_INC_WINDOWS_DLL_H
+
+#include "../Common/MyString.h"
+
+#ifndef _WIN32
+typedef void * HMODULE;
+// typedef int (*FARPROC)();
+// typedef void *FARPROC;
+void *GetProcAddress(HMODULE module, LPCSTR procName);
+#endif
+
+namespace NWindows {
+namespace NDLL {
+
+#ifdef _WIN32
+
+/*
+#ifdef UNDER_CE
+#define My_GetProcAddress(module, procName) (void *)::GetProcAddressA(module, procName)
+#else
+#define My_GetProcAddress(module, procName) (void *)::GetProcAddress(module, procName)
+#endif
+*/
+
+/* Win32: Don't call CLibrary::Free() and FreeLibrary() from another
+ FreeLibrary() code: detaching code in DLL entry-point or in
+ destructors of global objects in DLL module. */
+
+class CLibrary
+{
+ HMODULE _module;
+
+ // Z7_CLASS_NO_COPY(CLibrary);
+ // copy constructor is required here
+public:
+ CLibrary(): _module(NULL) {}
+ ~CLibrary() { Free(); }
+
+ CLibrary(const CLibrary &c): _module(NULL)
+ {
+ if (c._module)
+ {
+ // we need non const to reference from original item
+ // c._module = NULL;
+ throw 20230102;
+ }
+ }
+
+ HMODULE Get_HMODULE() const { return _module; }
+ // operator HMODULE() const { return _module; }
+ // HMODULE* operator&() { return &_module; }
+ bool IsLoaded() const { return (_module != NULL); }
+
+ void Attach(HMODULE m)
+ {
+ Free();
+ _module = m;
+ }
+ HMODULE Detach()
+ {
+ const HMODULE m = _module;
+ _module = NULL;
+ return m;
+ }
+
+ bool Free() throw();
+ bool LoadEx(CFSTR path, DWORD flags = LOAD_LIBRARY_AS_DATAFILE) throw();
+ bool Load(CFSTR path) throw();
+ // FARPROC
+ // void *GetProc(LPCSTR procName) const { return My_GetProcAddress(_module, procName); }
+};
+
+#else
+
+class CLibrary
+{
+ HMODULE _module;
+
+ // Z7_CLASS_NO_COPY(CLibrary);
+public:
+ CLibrary(): _module(NULL) {}
+ ~CLibrary() { Free(); }
+
+ HMODULE Get_HMODULE() const { return _module; }
+
+ bool Free() throw();
+ bool Load(CFSTR path) throw();
+ // FARPROC
+ // void *GetProc(LPCSTR procName) const; // { return My_GetProcAddress(_module, procName); }
+};
+
+#endif
+
+bool MyGetModuleFileName(FString &path);
+
+FString GetModuleDirPrefix();
+
+}}
+
+#endif
diff --git a/CPP/Windows/Defs.h b/CPP/Windows/Defs.h
index f3d692f..8ab9cf5 100644
--- a/CPP/Windows/Defs.h
+++ b/CPP/Windows/Defs.h
@@ -1,17 +1,17 @@
-// Windows/Defs.h
-
-#ifndef __WINDOWS_DEFS_H
-#define __WINDOWS_DEFS_H
-
-#include "../Common/MyWindows.h"
-
-#ifdef _WIN32
-inline bool LRESULTToBool(LRESULT v) { return (v != FALSE); }
-inline bool BOOLToBool(BOOL v) { return (v != FALSE); }
-inline BOOL BoolToBOOL(bool v) { return (v ? TRUE: FALSE); }
-#endif
-
-inline VARIANT_BOOL BoolToVARIANT_BOOL(bool v) { return (v ? VARIANT_TRUE: VARIANT_FALSE); }
-inline bool VARIANT_BOOLToBool(VARIANT_BOOL v) { return (v != VARIANT_FALSE); }
-
-#endif
+// Windows/Defs.h
+
+#ifndef ZIP7_INC_WINDOWS_DEFS_H
+#define ZIP7_INC_WINDOWS_DEFS_H
+
+#include "../Common/MyWindows.h"
+
+#ifdef _WIN32
+inline BOOL BoolToBOOL(bool v) { return (v ? TRUE: FALSE); }
+#endif
+
+inline bool BOOLToBool(BOOL v) { return (v != FALSE); }
+
+inline VARIANT_BOOL BoolToVARIANT_BOOL(bool v) { return (v ? VARIANT_TRUE: VARIANT_FALSE); }
+inline bool VARIANT_BOOLToBool(VARIANT_BOOL v) { return (v != VARIANT_FALSE); }
+
+#endif
diff --git a/CPP/Windows/ErrorMsg.cpp b/CPP/Windows/ErrorMsg.cpp
index 6434ec2..5acf3ad 100644
--- a/CPP/Windows/ErrorMsg.cpp
+++ b/CPP/Windows/ErrorMsg.cpp
@@ -1,66 +1,133 @@
-// Windows/ErrorMsg.h
-
-#include "StdAfx.h"
-
-#ifndef _UNICODE
-#include "../Common/StringConvert.h"
-#endif
-
-#include "ErrorMsg.h"
-
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-namespace NWindows {
-namespace NError {
-
-static bool MyFormatMessage(DWORD errorCode, UString &message)
-{
- LPVOID msgBuf;
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- if (::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, errorCode, 0, (LPTSTR) &msgBuf, 0, NULL) == 0)
- return false;
- message = GetUnicodeString((LPCTSTR)msgBuf);
- }
- else
- #endif
- {
- if (::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
- FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
- NULL, errorCode, 0, (LPWSTR) &msgBuf, 0, NULL) == 0)
- return false;
- message = (LPCWSTR)msgBuf;
- }
- ::LocalFree(msgBuf);
- return true;
-}
-
-UString MyFormatMessage(DWORD errorCode)
-{
- UString m;
- if (!MyFormatMessage(errorCode, m) || m.IsEmpty())
- {
- char s[16];
- for (int i = 0; i < 8; i++)
- {
- unsigned t = errorCode & 0xF;
- errorCode >>= 4;
- s[7 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
- }
- s[8] = 0;
- m += "Error #";
- m += s;
- }
- else if (m.Len() >= 2
- && m[m.Len() - 1] == 0x0A
- && m[m.Len() - 2] == 0x0D)
- m.DeleteFrom(m.Len() - 2);
- return m;
-}
-
-}}
+// Windows/ErrorMsg.h
+
+#include "StdAfx.h"
+
+#if !defined(_UNICODE) || !defined(_WIN32)
+#include "../Common/StringConvert.h"
+#endif
+
+#include "ErrorMsg.h"
+
+#ifdef _WIN32
+#if !defined(_UNICODE)
+extern bool g_IsNT;
+#endif
+#endif
+
+namespace NWindows {
+namespace NError {
+
+static bool MyFormatMessage(DWORD errorCode, UString &message)
+{
+ #ifndef Z7_SFX
+ if ((HRESULT)errorCode == MY_HRES_ERROR_INTERNAL_ERROR)
+ {
+ message = "Internal Error: The failure in hardware (RAM or CPU), OS or program";
+ return true;
+ }
+ #endif
+
+ #ifdef _WIN32
+
+ LPVOID msgBuf;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ if (::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, errorCode, 0, (LPTSTR) &msgBuf, 0, NULL) == 0)
+ return false;
+ message = GetUnicodeString((LPCTSTR)msgBuf);
+ }
+ else
+ #endif
+ {
+ if (::FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, errorCode, 0, (LPWSTR) &msgBuf, 0, NULL) == 0)
+ return false;
+ message = (LPCWSTR)msgBuf;
+ }
+ ::LocalFree(msgBuf);
+ return true;
+
+ #else // _WIN32
+
+ AString m;
+
+ const char *s = NULL;
+
+ switch ((Int32)errorCode)
+ {
+ // case ERROR_NO_MORE_FILES : s = "No more files"; break;
+ // case ERROR_DIRECTORY : s = "Error Directory"; break;
+ case E_NOTIMPL : s = "E_NOTIMPL : Not implemented"; break;
+ case E_NOINTERFACE : s = "E_NOINTERFACE : No such interface supported"; break;
+ case E_ABORT : s = "E_ABORT : Operation aborted"; break;
+ case E_FAIL : s = "E_FAIL : Unspecified error"; break;
+
+ case STG_E_INVALIDFUNCTION : s = "STG_E_INVALIDFUNCTION"; break;
+ case CLASS_E_CLASSNOTAVAILABLE : s = "CLASS_E_CLASSNOTAVAILABLE"; break;
+
+ case E_OUTOFMEMORY : s = "E_OUTOFMEMORY : Can't allocate required memory"; break;
+ case E_INVALIDARG : s = "E_INVALIDARG : One or more arguments are invalid"; break;
+
+ // case MY_E_ERROR_NEGATIVE_SEEK : s = "MY_E_ERROR_NEGATIVE_SEEK"; break;
+ default:
+ break;
+ }
+
+ /* strerror() for unknown errors still shows message "Unknown error -12345678")
+ So we must transfer error codes before strerror() */
+ if (!s)
+ {
+ if ((errorCode & 0xFFFF0000) == (UInt32)((MY_FACILITY_WRes << 16) | 0x80000000))
+ errorCode &= 0xFFFF;
+ else if ((errorCode & ((UInt32)1 << 31)))
+ return false; // we will show hex error later for that case
+
+ s = strerror((int)errorCode);
+
+ // if (!s)
+ {
+ m += "errno=";
+ m.Add_UInt32(errorCode);
+ if (s)
+ m += " : ";
+ }
+ }
+
+ if (s)
+ m += s;
+
+ MultiByteToUnicodeString2(message, m);
+ return true;
+
+ #endif
+}
+
+
+UString MyFormatMessage(DWORD errorCode)
+{
+ UString m;
+ if (!MyFormatMessage(errorCode, m) || m.IsEmpty())
+ {
+ char s[16];
+ for (int i = 0; i < 8; i++)
+ {
+ unsigned t = errorCode & 0xF;
+ errorCode >>= 4;
+ s[7 - i] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
+ }
+ s[8] = 0;
+ m += "Error #";
+ m += s;
+ }
+ else if (m.Len() >= 2
+ && m[m.Len() - 1] == 0x0A
+ && m[m.Len() - 2] == 0x0D)
+ m.DeleteFrom(m.Len() - 2);
+ return m;
+}
+
+}}
diff --git a/CPP/Windows/ErrorMsg.h b/CPP/Windows/ErrorMsg.h
index e05e950..6142b4e 100644
--- a/CPP/Windows/ErrorMsg.h
+++ b/CPP/Windows/ErrorMsg.h
@@ -1,15 +1,16 @@
-// Windows/ErrorMsg.h
-
-#ifndef __WINDOWS_ERROR_MSG_H
-#define __WINDOWS_ERROR_MSG_H
-
-#include "../Common/MyString.h"
-
-namespace NWindows {
-namespace NError {
-
-UString MyFormatMessage(DWORD errorCode);
-
-}}
-
-#endif
+// Windows/ErrorMsg.h
+
+#ifndef ZIP7_INC_WINDOWS_ERROR_MSG_H
+#define ZIP7_INC_WINDOWS_ERROR_MSG_H
+
+#include "../Common/MyString.h"
+
+namespace NWindows {
+namespace NError {
+
+UString MyFormatMessage(DWORD errorCode);
+inline UString MyFormatMessage(HRESULT errorCode) { return MyFormatMessage((DWORD)errorCode); }
+
+}}
+
+#endif
diff --git a/CPP/Windows/FileDir.cpp b/CPP/Windows/FileDir.cpp
index 124569e..5b1f340 100644
--- a/CPP/Windows/FileDir.cpp
+++ b/CPP/Windows/FileDir.cpp
@@ -1,714 +1,1229 @@
-// Windows/FileDir.cpp
-
-#include "StdAfx.h"
-
-#ifndef _UNICODE
-#include "../Common/StringConvert.h"
-#endif
-
-#include "FileDir.h"
-#include "FileFind.h"
-#include "FileName.h"
-
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NName;
-
-namespace NWindows {
-namespace NFile {
-namespace NDir {
-
-#ifndef UNDER_CE
-
-bool GetWindowsDir(FString &path)
-{
- UINT needLength;
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- TCHAR s[MAX_PATH + 2];
- s[0] = 0;
- needLength = ::GetWindowsDirectory(s, MAX_PATH + 1);
- path = fas2fs(s);
- }
- else
- #endif
- {
- WCHAR s[MAX_PATH + 2];
- s[0] = 0;
- needLength = ::GetWindowsDirectoryW(s, MAX_PATH + 1);
- path = us2fs(s);
- }
- return (needLength > 0 && needLength <= MAX_PATH);
-}
-
-bool GetSystemDir(FString &path)
-{
- UINT needLength;
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- TCHAR s[MAX_PATH + 2];
- s[0] = 0;
- needLength = ::GetSystemDirectory(s, MAX_PATH + 1);
- path = fas2fs(s);
- }
- else
- #endif
- {
- WCHAR s[MAX_PATH + 2];
- s[0] = 0;
- needLength = ::GetSystemDirectoryW(s, MAX_PATH + 1);
- path = us2fs(s);
- }
- return (needLength > 0 && needLength <= MAX_PATH);
-}
-#endif
-
-bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime)
-{
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return false;
- }
- #endif
-
- HANDLE hDir = INVALID_HANDLE_VALUE;
- IF_USE_MAIN_PATH
- hDir = ::CreateFileW(fs2us(path), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- #ifdef WIN_LONG_PATH
- if (hDir == INVALID_HANDLE_VALUE && USE_SUPER_PATH)
- {
- UString superPath;
- if (GetSuperPath(path, superPath, USE_MAIN_PATH))
- hDir = ::CreateFileW(superPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
- NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
- }
- #endif
-
- bool res = false;
- if (hDir != INVALID_HANDLE_VALUE)
- {
- res = BOOLToBool(::SetFileTime(hDir, cTime, aTime, mTime));
- ::CloseHandle(hDir);
- }
- return res;
-}
-
-bool SetFileAttrib(CFSTR path, DWORD attrib)
-{
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- if (::SetFileAttributes(fs2fas(path), attrib))
- return true;
- }
- else
- #endif
- {
- IF_USE_MAIN_PATH
- if (::SetFileAttributesW(fs2us(path), attrib))
- return true;
- #ifdef WIN_LONG_PATH
- if (USE_SUPER_PATH)
- {
- UString superPath;
- if (GetSuperPath(path, superPath, USE_MAIN_PATH))
- return BOOLToBool(::SetFileAttributesW(superPath, attrib));
- }
- #endif
- }
- return false;
-}
-
-
-bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib)
-{
- if ((attrib & 0xF0000000) != 0)
- attrib &= 0x3FFF;
- return SetFileAttrib(path, attrib);
-}
-
-
-bool RemoveDir(CFSTR path)
-{
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- if (::RemoveDirectory(fs2fas(path)))
- return true;
- }
- else
- #endif
- {
- IF_USE_MAIN_PATH
- if (::RemoveDirectoryW(fs2us(path)))
- return true;
- #ifdef WIN_LONG_PATH
- if (USE_SUPER_PATH)
- {
- UString superPath;
- if (GetSuperPath(path, superPath, USE_MAIN_PATH))
- return BOOLToBool(::RemoveDirectoryW(superPath));
- }
- #endif
- }
- return false;
-}
-
-bool MyMoveFile(CFSTR oldFile, CFSTR newFile)
-{
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- if (::MoveFile(fs2fas(oldFile), fs2fas(newFile)))
- return true;
- }
- else
- #endif
- {
- IF_USE_MAIN_PATH_2(oldFile, newFile)
- if (::MoveFileW(fs2us(oldFile), fs2us(newFile)))
- return true;
- #ifdef WIN_LONG_PATH
- if (USE_SUPER_PATH_2)
- {
- UString d1, d2;
- if (GetSuperPaths(oldFile, newFile, d1, d2, USE_MAIN_PATH_2))
- return BOOLToBool(::MoveFileW(d1, d2));
- }
- #endif
- }
- return false;
-}
-
-#ifndef UNDER_CE
-
-EXTERN_C_BEGIN
-typedef BOOL (WINAPI *Func_CreateHardLinkW)(
- LPCWSTR lpFileName,
- LPCWSTR lpExistingFileName,
- LPSECURITY_ATTRIBUTES lpSecurityAttributes
- );
-EXTERN_C_END
-
-bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName)
-{
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return false;
- /*
- if (::CreateHardLink(fs2fas(newFileName), fs2fas(existFileName), NULL))
- return true;
- */
- }
- else
- #endif
- {
- Func_CreateHardLinkW my_CreateHardLinkW = (Func_CreateHardLinkW)
- ::GetProcAddress(::GetModuleHandleW(L"kernel32.dll"), "CreateHardLinkW");
- if (!my_CreateHardLinkW)
- return false;
- IF_USE_MAIN_PATH_2(newFileName, existFileName)
- if (my_CreateHardLinkW(fs2us(newFileName), fs2us(existFileName), NULL))
- return true;
- #ifdef WIN_LONG_PATH
- if (USE_SUPER_PATH_2)
- {
- UString d1, d2;
- if (GetSuperPaths(newFileName, existFileName, d1, d2, USE_MAIN_PATH_2))
- return BOOLToBool(my_CreateHardLinkW(d1, d2, NULL));
- }
- #endif
- }
- return false;
-}
-
-#endif
-
-/*
-WinXP-64 CreateDir():
- "" - ERROR_PATH_NOT_FOUND
- \ - ERROR_ACCESS_DENIED
- C:\ - ERROR_ACCESS_DENIED, if there is such drive,
-
- D:\folder - ERROR_PATH_NOT_FOUND, if there is no such drive,
- C:\nonExistent\folder - ERROR_PATH_NOT_FOUND
-
- C:\existFolder - ERROR_ALREADY_EXISTS
- C:\existFolder\ - ERROR_ALREADY_EXISTS
-
- C:\folder - OK
- C:\folder\ - OK
-
- \\Server\nonExistent - ERROR_BAD_NETPATH
- \\Server\Share_Readonly - ERROR_ACCESS_DENIED
- \\Server\Share - ERROR_ALREADY_EXISTS
-
- \\Server\Share_NTFS_drive - ERROR_ACCESS_DENIED
- \\Server\Share_FAT_drive - ERROR_ALREADY_EXISTS
-*/
-
-bool CreateDir(CFSTR path)
-{
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- if (::CreateDirectory(fs2fas(path), NULL))
- return true;
- }
- else
- #endif
- {
- IF_USE_MAIN_PATH
- if (::CreateDirectoryW(fs2us(path), NULL))
- return true;
- #ifdef WIN_LONG_PATH
- if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH)
- {
- UString superPath;
- if (GetSuperPath(path, superPath, USE_MAIN_PATH))
- return BOOLToBool(::CreateDirectoryW(superPath, NULL));
- }
- #endif
- }
- return false;
-}
-
-/*
- CreateDir2 returns true, if directory can contain files after the call (two cases):
- 1) the directory already exists
- 2) the directory was created
- path must be WITHOUT trailing path separator.
-
- We need CreateDir2, since fileInfo.Find() for reserved names like "com8"
- returns FILE instead of DIRECTORY. And we need to use SuperPath */
-
-static bool CreateDir2(CFSTR path)
-{
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- if (::CreateDirectory(fs2fas(path), NULL))
- return true;
- }
- else
- #endif
- {
- IF_USE_MAIN_PATH
- if (::CreateDirectoryW(fs2us(path), NULL))
- return true;
- #ifdef WIN_LONG_PATH
- if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH)
- {
- UString superPath;
- if (GetSuperPath(path, superPath, USE_MAIN_PATH))
- {
- if (::CreateDirectoryW(superPath, NULL))
- return true;
- if (::GetLastError() != ERROR_ALREADY_EXISTS)
- return false;
- NFind::CFileInfo fi;
- if (!fi.Find(us2fs(superPath)))
- return false;
- return fi.IsDir();
- }
- }
- #endif
- }
- if (::GetLastError() != ERROR_ALREADY_EXISTS)
- return false;
- NFind::CFileInfo fi;
- if (!fi.Find(path))
- return false;
- return fi.IsDir();
-}
-
-bool CreateComplexDir(CFSTR _path)
-{
- #ifdef _WIN32
-
- {
- DWORD attrib = NFind::GetFileAttrib(_path);
- if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)
- return true;
- }
-
- #ifndef UNDER_CE
-
- if (IsDriveRootPath_SuperAllowed(_path))
- return false;
-
- unsigned prefixSize = GetRootPrefixSize(_path);
-
- #endif
-
- #endif
-
- FString path (_path);
-
- int pos = path.ReverseFind_PathSepar();
- if (pos >= 0 && (unsigned)pos == path.Len() - 1)
- {
- if (path.Len() == 1)
- return true;
- path.DeleteBack();
- }
-
- const FString path2 (path);
- pos = path.Len();
-
- for (;;)
- {
- if (CreateDir2(path))
- break;
- if (::GetLastError() == ERROR_ALREADY_EXISTS)
- return false;
- pos = path.ReverseFind_PathSepar();
- if (pos < 0 || pos == 0)
- return false;
-
- #if defined(_WIN32) && !defined(UNDER_CE)
- if (pos == 1 && IS_PATH_SEPAR(path[0]))
- return false;
- if (prefixSize >= (unsigned)pos + 1)
- return false;
- #endif
-
- path.DeleteFrom(pos);
- }
-
- while (pos < (int)path2.Len())
- {
- int pos2 = NName::FindSepar(path2.Ptr(pos + 1));
- if (pos2 < 0)
- pos = path2.Len();
- else
- pos += 1 + pos2;
- path.SetFrom(path2, pos);
- if (!CreateDir(path))
- return false;
- }
-
- return true;
-}
-
-bool DeleteFileAlways(CFSTR path)
-{
- /* If alt stream, we also need to clear READ-ONLY attribute of main file before delete.
- SetFileAttrib("name:stream", ) changes attributes of main file. */
- {
- DWORD attrib = NFind::GetFileAttrib(path);
- if (attrib != INVALID_FILE_ATTRIBUTES
- && (attrib & FILE_ATTRIBUTE_DIRECTORY) == 0
- && (attrib & FILE_ATTRIBUTE_READONLY) != 0)
- {
- if (!SetFileAttrib(path, attrib & ~FILE_ATTRIBUTE_READONLY))
- return false;
- }
- }
-
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- if (::DeleteFile(fs2fas(path)))
- return true;
- }
- else
- #endif
- {
- /* DeleteFile("name::$DATA") deletes all alt streams (same as delete DeleteFile("name")).
- Maybe it's better to open "name::$DATA" and clear data for unnamed stream? */
- IF_USE_MAIN_PATH
- if (::DeleteFileW(fs2us(path)))
- return true;
- #ifdef WIN_LONG_PATH
- if (USE_SUPER_PATH)
- {
- UString superPath;
- if (GetSuperPath(path, superPath, USE_MAIN_PATH))
- return BOOLToBool(::DeleteFileW(superPath));
- }
- #endif
- }
- return false;
-}
-
-bool RemoveDirWithSubItems(const FString &path)
-{
- bool needRemoveSubItems = true;
- {
- NFind::CFileInfo fi;
- if (!fi.Find(path))
- return false;
- if (!fi.IsDir())
- {
- ::SetLastError(ERROR_DIRECTORY);
- return false;
- }
- if (fi.HasReparsePoint())
- needRemoveSubItems = false;
- }
-
- if (needRemoveSubItems)
- {
- FString s (path);
- s.Add_PathSepar();
- const unsigned prefixSize = s.Len();
- NFind::CEnumerator enumerator;
- enumerator.SetDirPrefix(s);
- NFind::CFileInfo fi;
- while (enumerator.Next(fi))
- {
- s.DeleteFrom(prefixSize);
- s += fi.Name;
- if (fi.IsDir())
- {
- if (!RemoveDirWithSubItems(s))
- return false;
- }
- else if (!DeleteFileAlways(s))
- return false;
- }
- }
-
- if (!SetFileAttrib(path, 0))
- return false;
- return RemoveDir(path);
-}
-
-#ifdef UNDER_CE
-
-bool MyGetFullPathName(CFSTR path, FString &resFullPath)
-{
- resFullPath = path;
- return true;
-}
-
-#else
-
-bool MyGetFullPathName(CFSTR path, FString &resFullPath)
-{
- return GetFullPath(path, resFullPath);
-}
-
-bool SetCurrentDir(CFSTR path)
-{
- // SetCurrentDirectory doesn't support \\?\ prefix
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- return BOOLToBool(::SetCurrentDirectory(fs2fas(path)));
- }
- else
- #endif
- {
- return BOOLToBool(::SetCurrentDirectoryW(fs2us(path)));
- }
-}
-
-bool GetCurrentDir(FString &path)
-{
- path.Empty();
- DWORD needLength;
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- TCHAR s[MAX_PATH + 2];
- s[0] = 0;
- needLength = ::GetCurrentDirectory(MAX_PATH + 1, s);
- path = fas2fs(s);
- }
- else
- #endif
- {
- WCHAR s[MAX_PATH + 2];
- s[0] = 0;
- needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, s);
- path = us2fs(s);
- }
- return (needLength > 0 && needLength <= MAX_PATH);
-}
-
-#endif
-
-bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName)
-{
- bool res = MyGetFullPathName(path, resDirPrefix);
- if (!res)
- resDirPrefix = path;
- int pos = resDirPrefix.ReverseFind_PathSepar();
- resFileName = resDirPrefix.Ptr(pos + 1);
- resDirPrefix.DeleteFrom(pos + 1);
- return res;
-}
-
-bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix)
-{
- FString resFileName;
- return GetFullPathAndSplit(path, resDirPrefix, resFileName);
-}
-
-bool MyGetTempPath(FString &path)
-{
- path.Empty();
- DWORD needLength;
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- TCHAR s[MAX_PATH + 2];
- s[0] = 0;
- needLength = ::GetTempPath(MAX_PATH + 1, s);
- path = fas2fs(s);
- }
- else
- #endif
- {
- WCHAR s[MAX_PATH + 2];
- s[0] = 0;
- needLength = ::GetTempPathW(MAX_PATH + 1, s);;
- path = us2fs(s);
- }
- return (needLength > 0 && needLength <= MAX_PATH);
-}
-
-static bool CreateTempFile(CFSTR prefix, bool addRandom, FString &path, NIO::COutFile *outFile)
-{
- UInt32 d = (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId();
- for (unsigned i = 0; i < 100; i++)
- {
- path = prefix;
- if (addRandom)
- {
- char s[16];
- UInt32 val = d;
- unsigned k;
- for (k = 0; k < 8; k++)
- {
- unsigned t = val & 0xF;
- val >>= 4;
- s[k] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
- }
- s[k] = '\0';
- if (outFile)
- path += '.';
- path += s;
- UInt32 step = GetTickCount() + 2;
- if (step == 0)
- step = 1;
- d += step;
- }
- addRandom = true;
- if (outFile)
- path += ".tmp";
- if (NFind::DoesFileOrDirExist(path))
- {
- SetLastError(ERROR_ALREADY_EXISTS);
- continue;
- }
- if (outFile)
- {
- if (outFile->Create(path, false))
- return true;
- }
- else
- {
- if (CreateDir(path))
- return true;
- }
- DWORD error = GetLastError();
- if (error != ERROR_FILE_EXISTS &&
- error != ERROR_ALREADY_EXISTS)
- break;
- }
- path.Empty();
- return false;
-}
-
-bool CTempFile::Create(CFSTR prefix, NIO::COutFile *outFile)
-{
- if (!Remove())
- return false;
- if (!CreateTempFile(prefix, false, _path, outFile))
- return false;
- _mustBeDeleted = true;
- return true;
-}
-
-bool CTempFile::CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile)
-{
- if (!Remove())
- return false;
- FString tempPath;
- if (!MyGetTempPath(tempPath))
- return false;
- if (!CreateTempFile(tempPath + namePrefix, true, _path, outFile))
- return false;
- _mustBeDeleted = true;
- return true;
-}
-
-bool CTempFile::Remove()
-{
- if (!_mustBeDeleted)
- return true;
- _mustBeDeleted = !DeleteFileAlways(_path);
- return !_mustBeDeleted;
-}
-
-bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore)
-{
- // DWORD attrib = 0;
- if (deleteDestBefore)
- {
- if (NFind::DoesFileExist(name))
- {
- // attrib = NFind::GetFileAttrib(name);
- if (!DeleteFileAlways(name))
- return false;
- }
- }
- DisableDeleting();
- return MyMoveFile(_path, name);
-
- /*
- if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY))
- {
- DWORD attrib2 = NFind::GetFileAttrib(name);
- if (attrib2 != INVALID_FILE_ATTRIBUTES)
- SetFileAttrib(name, attrib2 | FILE_ATTRIBUTE_READONLY);
- }
- */
-}
-
-bool CTempDir::Create(CFSTR prefix)
-{
- if (!Remove())
- return false;
- FString tempPath;
- if (!MyGetTempPath(tempPath))
- return false;
- if (!CreateTempFile(tempPath + prefix, true, _path, NULL))
- return false;
- _mustBeDeleted = true;
- return true;
-}
-
-bool CTempDir::Remove()
-{
- if (!_mustBeDeleted)
- return true;
- _mustBeDeleted = !RemoveDirWithSubItems(_path);
- return !_mustBeDeleted;
-}
-
-}}}
+// Windows/FileDir.cpp
+
+#include "StdAfx.h"
+
+
+#ifndef _WIN32
+#include <stdio.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+#include <time.h>
+#include <utime.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include "../Common/StringConvert.h"
+#include "../Common/C_FileIO.h"
+#endif
+
+#include "FileDir.h"
+#include "FileFind.h"
+#include "FileName.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NName;
+
+#ifndef _WIN32
+
+static bool FiTime_To_timespec(const CFiTime *ft, timespec &ts)
+{
+ if (ft)
+ {
+ ts = *ft;
+ return true;
+ }
+ // else
+ {
+ ts.tv_sec = 0;
+ ts.tv_nsec =
+ #ifdef UTIME_OMIT
+ UTIME_OMIT; // -2 keep old timesptamp
+ #else
+ // UTIME_NOW; -1 // set to the current time
+ 0;
+ #endif
+ return false;
+ }
+}
+#endif
+
+namespace NWindows {
+namespace NFile {
+namespace NDir {
+
+#ifdef _WIN32
+
+#ifndef UNDER_CE
+
+bool GetWindowsDir(FString &path)
+{
+ const unsigned kBufSize = MAX_PATH + 16;
+ UINT len;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ TCHAR s[kBufSize + 1];
+ s[0] = 0;
+ len = ::GetWindowsDirectory(s, kBufSize);
+ path = fas2fs(s);
+ }
+ else
+ #endif
+ {
+ WCHAR s[kBufSize + 1];
+ s[0] = 0;
+ len = ::GetWindowsDirectoryW(s, kBufSize);
+ path = us2fs(s);
+ }
+ return (len != 0 && len < kBufSize);
+}
+
+
+/*
+new DOCs for GetSystemDirectory:
+ returned path does not end with a backslash unless the
+ system directory is the root directory.
+*/
+
+bool GetSystemDir(FString &path)
+{
+ const unsigned kBufSize = MAX_PATH + 16;
+ UINT len;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ TCHAR s[kBufSize + 1];
+ s[0] = 0;
+ len = ::GetSystemDirectory(s, kBufSize);
+ path = fas2fs(s);
+ }
+ else
+ #endif
+ {
+ WCHAR s[kBufSize + 1];
+ s[0] = 0;
+ len = ::GetSystemDirectoryW(s, kBufSize);
+ path = us2fs(s);
+ }
+ return (len != 0 && len < kBufSize);
+}
+#endif // UNDER_CE
+
+
+bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return false;
+ }
+ #endif
+
+ HANDLE hDir = INVALID_HANDLE_VALUE;
+ IF_USE_MAIN_PATH
+ hDir = ::CreateFileW(fs2us(path), GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ #ifdef Z7_LONG_PATH
+ if (hDir == INVALID_HANDLE_VALUE && USE_SUPER_PATH)
+ {
+ UString superPath;
+ if (GetSuperPath(path, superPath, USE_MAIN_PATH))
+ hDir = ::CreateFileW(superPath, GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ }
+ #endif
+
+ bool res = false;
+ if (hDir != INVALID_HANDLE_VALUE)
+ {
+ res = BOOLToBool(::SetFileTime(hDir, cTime, aTime, mTime));
+ ::CloseHandle(hDir);
+ }
+ return res;
+}
+
+
+
+bool SetFileAttrib(CFSTR path, DWORD attrib)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ if (::SetFileAttributes(fs2fas(path), attrib))
+ return true;
+ }
+ else
+ #endif
+ {
+ IF_USE_MAIN_PATH
+ if (::SetFileAttributesW(fs2us(path), attrib))
+ return true;
+ #ifdef Z7_LONG_PATH
+ if (USE_SUPER_PATH)
+ {
+ UString superPath;
+ if (GetSuperPath(path, superPath, USE_MAIN_PATH))
+ return BOOLToBool(::SetFileAttributesW(superPath, attrib));
+ }
+ #endif
+ }
+ return false;
+}
+
+
+bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib)
+{
+ #ifdef _WIN32
+ if ((attrib & 0xF0000000) != 0)
+ attrib &= 0x3FFF;
+ #endif
+ return SetFileAttrib(path, attrib);
+}
+
+
+bool RemoveDir(CFSTR path)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ if (::RemoveDirectory(fs2fas(path)))
+ return true;
+ }
+ else
+ #endif
+ {
+ IF_USE_MAIN_PATH
+ if (::RemoveDirectoryW(fs2us(path)))
+ return true;
+ #ifdef Z7_LONG_PATH
+ if (USE_SUPER_PATH)
+ {
+ UString superPath;
+ if (GetSuperPath(path, superPath, USE_MAIN_PATH))
+ return BOOLToBool(::RemoveDirectoryW(superPath));
+ }
+ #endif
+ }
+ return false;
+}
+
+
+bool MyMoveFile(CFSTR oldFile, CFSTR newFile)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ if (::MoveFile(fs2fas(oldFile), fs2fas(newFile)))
+ return true;
+ }
+ else
+ #endif
+ {
+ IF_USE_MAIN_PATH_2(oldFile, newFile)
+ {
+ if (::MoveFileW(fs2us(oldFile), fs2us(newFile)))
+ return true;
+ }
+ #ifdef Z7_LONG_PATH
+ if (USE_SUPER_PATH_2)
+ {
+ UString d1, d2;
+ if (GetSuperPaths(oldFile, newFile, d1, d2, USE_MAIN_PATH_2))
+ return BOOLToBool(::MoveFileW(d1, d2));
+ }
+ #endif
+ }
+ return false;
+}
+
+#ifndef UNDER_CE
+EXTERN_C_BEGIN
+typedef BOOL (WINAPI *Func_CreateHardLinkW)(
+ LPCWSTR lpFileName,
+ LPCWSTR lpExistingFileName,
+ LPSECURITY_ATTRIBUTES lpSecurityAttributes
+ );
+EXTERN_C_END
+#endif // UNDER_CE
+
+bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return false;
+ /*
+ if (::CreateHardLink(fs2fas(newFileName), fs2fas(existFileName), NULL))
+ return true;
+ */
+ }
+ else
+ #endif
+ {
+ const
+ Func_CreateHardLinkW
+ my_CreateHardLinkW = Z7_GET_PROC_ADDRESS(
+ Func_CreateHardLinkW, ::GetModuleHandleW(L"kernel32.dll"),
+ "CreateHardLinkW");
+ if (!my_CreateHardLinkW)
+ return false;
+ IF_USE_MAIN_PATH_2(newFileName, existFileName)
+ {
+ if (my_CreateHardLinkW(fs2us(newFileName), fs2us(existFileName), NULL))
+ return true;
+ }
+ #ifdef Z7_LONG_PATH
+ if (USE_SUPER_PATH_2)
+ {
+ UString d1, d2;
+ if (GetSuperPaths(newFileName, existFileName, d1, d2, USE_MAIN_PATH_2))
+ return BOOLToBool(my_CreateHardLinkW(d1, d2, NULL));
+ }
+ #endif
+ }
+ return false;
+}
+
+
+/*
+WinXP-64 CreateDir():
+ "" - ERROR_PATH_NOT_FOUND
+ \ - ERROR_ACCESS_DENIED
+ C:\ - ERROR_ACCESS_DENIED, if there is such drive,
+
+ D:\folder - ERROR_PATH_NOT_FOUND, if there is no such drive,
+ C:\nonExistent\folder - ERROR_PATH_NOT_FOUND
+
+ C:\existFolder - ERROR_ALREADY_EXISTS
+ C:\existFolder\ - ERROR_ALREADY_EXISTS
+
+ C:\folder - OK
+ C:\folder\ - OK
+
+ \\Server\nonExistent - ERROR_BAD_NETPATH
+ \\Server\Share_Readonly - ERROR_ACCESS_DENIED
+ \\Server\Share - ERROR_ALREADY_EXISTS
+
+ \\Server\Share_NTFS_drive - ERROR_ACCESS_DENIED
+ \\Server\Share_FAT_drive - ERROR_ALREADY_EXISTS
+*/
+
+bool CreateDir(CFSTR path)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ if (::CreateDirectory(fs2fas(path), NULL))
+ return true;
+ }
+ else
+ #endif
+ {
+ IF_USE_MAIN_PATH
+ if (::CreateDirectoryW(fs2us(path), NULL))
+ return true;
+ #ifdef Z7_LONG_PATH
+ if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH)
+ {
+ UString superPath;
+ if (GetSuperPath(path, superPath, USE_MAIN_PATH))
+ return BOOLToBool(::CreateDirectoryW(superPath, NULL));
+ }
+ #endif
+ }
+ return false;
+}
+
+/*
+ CreateDir2 returns true, if directory can contain files after the call (two cases):
+ 1) the directory already exists
+ 2) the directory was created
+ path must be WITHOUT trailing path separator.
+
+ We need CreateDir2, since fileInfo.Find() for reserved names like "com8"
+ returns FILE instead of DIRECTORY. And we need to use SuperPath */
+
+static bool CreateDir2(CFSTR path)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ if (::CreateDirectory(fs2fas(path), NULL))
+ return true;
+ }
+ else
+ #endif
+ {
+ IF_USE_MAIN_PATH
+ if (::CreateDirectoryW(fs2us(path), NULL))
+ return true;
+ #ifdef Z7_LONG_PATH
+ if ((!USE_MAIN_PATH || ::GetLastError() != ERROR_ALREADY_EXISTS) && USE_SUPER_PATH)
+ {
+ UString superPath;
+ if (GetSuperPath(path, superPath, USE_MAIN_PATH))
+ {
+ if (::CreateDirectoryW(superPath, NULL))
+ return true;
+ if (::GetLastError() != ERROR_ALREADY_EXISTS)
+ return false;
+ NFind::CFileInfo fi;
+ if (!fi.Find(us2fs(superPath)))
+ return false;
+ return fi.IsDir();
+ }
+ }
+ #endif
+ }
+ if (::GetLastError() != ERROR_ALREADY_EXISTS)
+ return false;
+ NFind::CFileInfo fi;
+ if (!fi.Find(path))
+ return false;
+ return fi.IsDir();
+}
+
+#endif // _WIN32
+
+static bool CreateDir2(CFSTR path);
+
+bool CreateComplexDir(CFSTR _path)
+{
+ #ifdef _WIN32
+
+ {
+ const DWORD attrib = NFind::GetFileAttrib(_path);
+ if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ return true;
+ }
+
+ #ifndef UNDER_CE
+
+ if (IsDriveRootPath_SuperAllowed(_path))
+ return false;
+
+ const unsigned prefixSize = GetRootPrefixSize(_path);
+
+ #endif // UNDER_CE
+
+ #else // _WIN32
+
+ // Posix
+ NFind::CFileInfo fi;
+ if (fi.Find(_path))
+ {
+ if (fi.IsDir())
+ return true;
+ }
+
+ #endif // _WIN32
+
+ FString path (_path);
+
+ int pos = path.ReverseFind_PathSepar();
+ if (pos >= 0 && (unsigned)pos == path.Len() - 1)
+ {
+ if (path.Len() == 1)
+ return true;
+ path.DeleteBack();
+ }
+
+ const FString path2 (path);
+ pos = (int)path.Len();
+
+ for (;;)
+ {
+ if (CreateDir2(path))
+ break;
+ if (::GetLastError() == ERROR_ALREADY_EXISTS)
+ return false;
+ pos = path.ReverseFind_PathSepar();
+ if (pos < 0 || pos == 0)
+ return false;
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (pos == 1 && IS_PATH_SEPAR(path[0]))
+ return false;
+ if (prefixSize >= (unsigned)pos + 1)
+ return false;
+ #endif
+
+ path.DeleteFrom((unsigned)pos);
+ }
+
+ while (pos < (int)path2.Len())
+ {
+ int pos2 = NName::FindSepar(path2.Ptr((unsigned)pos + 1));
+ if (pos2 < 0)
+ pos = (int)path2.Len();
+ else
+ pos += 1 + pos2;
+ path.SetFrom(path2, (unsigned)pos);
+ if (!CreateDir(path))
+ return false;
+ }
+
+ return true;
+}
+
+
+#ifdef _WIN32
+
+bool DeleteFileAlways(CFSTR path)
+{
+ /* If alt stream, we also need to clear READ-ONLY attribute of main file before delete.
+ SetFileAttrib("name:stream", ) changes attributes of main file. */
+ {
+ DWORD attrib = NFind::GetFileAttrib(path);
+ if (attrib != INVALID_FILE_ATTRIBUTES
+ && (attrib & FILE_ATTRIBUTE_DIRECTORY) == 0
+ && (attrib & FILE_ATTRIBUTE_READONLY) != 0)
+ {
+ if (!SetFileAttrib(path, attrib & ~(DWORD)FILE_ATTRIBUTE_READONLY))
+ return false;
+ }
+ }
+
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ if (::DeleteFile(fs2fas(path)))
+ return true;
+ }
+ else
+ #endif
+ {
+ /* DeleteFile("name::$DATA") deletes all alt streams (same as delete DeleteFile("name")).
+ Maybe it's better to open "name::$DATA" and clear data for unnamed stream? */
+ IF_USE_MAIN_PATH
+ if (::DeleteFileW(fs2us(path)))
+ return true;
+ #ifdef Z7_LONG_PATH
+ if (USE_SUPER_PATH)
+ {
+ UString superPath;
+ if (GetSuperPath(path, superPath, USE_MAIN_PATH))
+ return BOOLToBool(::DeleteFileW(superPath));
+ }
+ #endif
+ }
+ return false;
+}
+
+
+
+bool RemoveDirWithSubItems(const FString &path)
+{
+ bool needRemoveSubItems = true;
+ {
+ NFind::CFileInfo fi;
+ if (!fi.Find(path))
+ return false;
+ if (!fi.IsDir())
+ {
+ ::SetLastError(ERROR_DIRECTORY);
+ return false;
+ }
+ if (fi.HasReparsePoint())
+ needRemoveSubItems = false;
+ }
+
+ if (needRemoveSubItems)
+ {
+ FString s (path);
+ s.Add_PathSepar();
+ const unsigned prefixSize = s.Len();
+ NFind::CEnumerator enumerator;
+ enumerator.SetDirPrefix(s);
+ NFind::CDirEntry fi;
+ bool isError = false;
+ DWORD lastError = 0;
+ while (enumerator.Next(fi))
+ {
+ s.DeleteFrom(prefixSize);
+ s += fi.Name;
+ if (fi.IsDir())
+ {
+ if (!RemoveDirWithSubItems(s))
+ {
+ lastError = GetLastError();
+ isError = true;
+ }
+ }
+ else if (!DeleteFileAlways(s))
+ {
+ lastError = GetLastError();
+ isError = false;
+ }
+ }
+ if (isError)
+ {
+ SetLastError(lastError);
+ return false;
+ }
+ }
+
+ // we clear read-only attrib to remove read-only dir
+ if (!SetFileAttrib(path, 0))
+ return false;
+ return RemoveDir(path);
+}
+
+#endif // _WIN32
+
+#ifdef UNDER_CE
+
+bool MyGetFullPathName(CFSTR path, FString &resFullPath)
+{
+ resFullPath = path;
+ return true;
+}
+
+#else
+
+bool MyGetFullPathName(CFSTR path, FString &resFullPath)
+{
+ return GetFullPath(path, resFullPath);
+}
+
+#ifdef _WIN32
+
+/* Win10: SetCurrentDirectory() doesn't support long paths and
+ doesn't support super prefix "\\?\", if long path behavior is not
+ enabled in registry (LongPathsEnabled) and in manifest (longPathAware). */
+
+bool SetCurrentDir(CFSTR path)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ return BOOLToBool(::SetCurrentDirectory(fs2fas(path)));
+ }
+ else
+ #endif
+ {
+ return BOOLToBool(::SetCurrentDirectoryW(fs2us(path)));
+ }
+}
+
+
+/*
+we use system function GetCurrentDirectory()
+new GetCurrentDirectory() DOCs:
+ - If the function fails, the return value is zero.
+ - If the function succeeds, the return value specifies
+ the number of characters that are written to the buffer,
+ not including the terminating null character.
+ - If the buffer is not large enough, the return value specifies
+ the required size of the buffer, in characters,
+ including the null-terminating character.
+
+GetCurrentDir() calls GetCurrentDirectory().
+GetCurrentDirectory() in win10 in tests:
+ the returned (path) does not end with a backslash, if
+ current directory is not root directory of drive.
+ But that behavior is not guarantied in specification docs.
+*/
+
+bool GetCurrentDir(FString &path)
+{
+ const unsigned kBufSize = MAX_PATH + 16;
+ path.Empty();
+
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ TCHAR s[kBufSize + 1];
+ s[0] = 0;
+ const DWORD len = ::GetCurrentDirectory(kBufSize, s);
+ if (len == 0 || len >= kBufSize)
+ return false;
+ s[kBufSize] = 0; // optional guard
+ path = fas2fs(s);
+ return true;
+ }
+ else
+ #endif
+ {
+ DWORD len;
+ {
+ WCHAR s[kBufSize + 1];
+ s[0] = 0;
+ len = ::GetCurrentDirectoryW(kBufSize, s);
+ if (len == 0)
+ return false;
+ if (len < kBufSize)
+ {
+ s[kBufSize] = 0; // optional guard
+ path = us2fs(s);
+ return true;
+ }
+ }
+ UString temp;
+ const DWORD len2 = ::GetCurrentDirectoryW(len, temp.GetBuf(len));
+ if (len2 == 0)
+ return false;
+ temp.ReleaseBuf_CalcLen(len);
+ if (temp.Len() != len2 || len - 1 != len2)
+ {
+ /* it's unexpected case, if current dir of process
+ was changed between two function calls,
+ or some unexpected function implementation */
+ // SetLastError((DWORD)E_FAIL); // we can set some error code
+ return false;
+ }
+ path = us2fs(temp);
+ return true;
+ }
+}
+
+#endif // _WIN32
+#endif // UNDER_CE
+
+
+bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName)
+{
+ bool res = MyGetFullPathName(path, resDirPrefix);
+ if (!res)
+ resDirPrefix = path;
+ int pos = resDirPrefix.ReverseFind_PathSepar();
+ pos++;
+ resFileName = resDirPrefix.Ptr((unsigned)pos);
+ resDirPrefix.DeleteFrom((unsigned)pos);
+ return res;
+}
+
+bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix)
+{
+ FString resFileName;
+ return GetFullPathAndSplit(path, resDirPrefix, resFileName);
+}
+
+
+
+bool MyGetTempPath(FString &path)
+{
+ #ifdef _WIN32
+
+ /*
+ new DOCs for GetTempPathW():
+ - The returned string ends with a backslash.
+ - The maximum possible return value is MAX_PATH+1 (261).
+ */
+
+ const unsigned kBufSize = MAX_PATH + 16;
+ DWORD len;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ TCHAR s[kBufSize + 1];
+ s[0] = 0;
+ len = ::GetTempPath(kBufSize, s);
+ path = fas2fs(s);
+ }
+ else
+ #endif
+ {
+ WCHAR s[kBufSize + 1];
+ s[0] = 0;
+ len = ::GetTempPathW(kBufSize, s);
+ path = us2fs(s);
+ }
+ /* win10: GetTempPathW() doesn't set backslash at the end of path,
+ if (buffer_size == len_of(path_with_backslash)).
+ So we normalize path here: */
+ NormalizeDirPathPrefix(path);
+ return (len != 0 && len < kBufSize);
+
+ #else // !_WIN32
+
+ // FIXME: improve that code
+ path = STRING_PATH_SEPARATOR "tmp";
+ const char *s;
+ if (NFind::DoesDirExist_FollowLink(path))
+ s = STRING_PATH_SEPARATOR "tmp" STRING_PATH_SEPARATOR;
+ else
+ s = "." STRING_PATH_SEPARATOR;
+ path = s;
+ return true;
+
+ #endif
+}
+
+
+bool CreateTempFile2(CFSTR prefix, bool addRandom, AString &postfix, NIO::COutFile *outFile)
+{
+ UInt32 d =
+ #ifdef _WIN32
+ (GetTickCount() << 12) ^ (GetCurrentThreadId() << 14) ^ GetCurrentProcessId();
+ #else
+ (UInt32)(time(NULL) << 12) ^ ((UInt32)getppid() << 14) ^ (UInt32)(getpid());
+ #endif
+
+ for (unsigned i = 0; i < 100; i++)
+ {
+ postfix.Empty();
+ if (addRandom)
+ {
+ char s[16];
+ UInt32 val = d;
+ unsigned k;
+ for (k = 0; k < 8; k++)
+ {
+ const unsigned t = val & 0xF;
+ val >>= 4;
+ s[k] = (char)((t < 10) ? ('0' + t) : ('A' + (t - 10)));
+ }
+ s[k] = '\0';
+ if (outFile)
+ postfix.Add_Dot();
+ postfix += s;
+ UInt32 step = GetTickCount() + 2;
+ if (step == 0)
+ step = 1;
+ d += step;
+ }
+ addRandom = true;
+ if (outFile)
+ postfix += ".tmp";
+ FString path (prefix);
+ path += postfix;
+ if (NFind::DoesFileOrDirExist(path))
+ {
+ SetLastError(ERROR_ALREADY_EXISTS);
+ continue;
+ }
+ if (outFile)
+ {
+ if (outFile->Create(path, false))
+ return true;
+ }
+ else
+ {
+ if (CreateDir(path))
+ return true;
+ }
+ const DWORD error = GetLastError();
+ if (error != ERROR_FILE_EXISTS &&
+ error != ERROR_ALREADY_EXISTS)
+ break;
+ }
+ postfix.Empty();
+ return false;
+}
+
+bool CTempFile::Create(CFSTR prefix, NIO::COutFile *outFile)
+{
+ if (!Remove())
+ return false;
+ _path.Empty();
+ AString postfix;
+ if (!CreateTempFile2(prefix, false, postfix, outFile))
+ return false;
+ _path = prefix;
+ _path += postfix;
+ _mustBeDeleted = true;
+ return true;
+}
+
+bool CTempFile::CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile)
+{
+ if (!Remove())
+ return false;
+ _path.Empty();
+ FString tempPath;
+ if (!MyGetTempPath(tempPath))
+ return false;
+ AString postfix;
+ tempPath += namePrefix;
+ if (!CreateTempFile2(tempPath, true, postfix, outFile))
+ return false;
+ _path = tempPath;
+ _path += postfix;
+ _mustBeDeleted = true;
+ return true;
+}
+
+bool CTempFile::Remove()
+{
+ if (!_mustBeDeleted)
+ return true;
+ _mustBeDeleted = !DeleteFileAlways(_path);
+ return !_mustBeDeleted;
+}
+
+bool CTempFile::MoveTo(CFSTR name, bool deleteDestBefore)
+{
+ // DWORD attrib = 0;
+ if (deleteDestBefore)
+ {
+ if (NFind::DoesFileExist_Raw(name))
+ {
+ // attrib = NFind::GetFileAttrib(name);
+ if (!DeleteFileAlways(name))
+ return false;
+ }
+ }
+ DisableDeleting();
+ return MyMoveFile(_path, name);
+
+ /*
+ if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_READONLY))
+ {
+ DWORD attrib2 = NFind::GetFileAttrib(name);
+ if (attrib2 != INVALID_FILE_ATTRIBUTES)
+ SetFileAttrib(name, attrib2 | FILE_ATTRIBUTE_READONLY);
+ }
+ */
+}
+
+#ifdef _WIN32
+bool CTempDir::Create(CFSTR prefix)
+{
+ if (!Remove())
+ return false;
+ _path.Empty();
+ FString tempPath;
+ if (!MyGetTempPath(tempPath))
+ return false;
+ tempPath += prefix;
+ AString postfix;
+ if (!CreateTempFile2(tempPath, true, postfix, NULL))
+ return false;
+ _path = tempPath;
+ _path += postfix;
+ _mustBeDeleted = true;
+ return true;
+}
+
+bool CTempDir::Remove()
+{
+ if (!_mustBeDeleted)
+ return true;
+ _mustBeDeleted = !RemoveDirWithSubItems(_path);
+ return !_mustBeDeleted;
+}
+#endif
+
+
+
+#ifndef _WIN32
+
+bool RemoveDir(CFSTR path)
+{
+ return (rmdir(path) == 0);
+}
+
+
+static BOOL My_CopyFile(CFSTR oldFile, CFSTR newFile)
+{
+ NWindows::NFile::NIO::COutFile outFile;
+ if (!outFile.Create(newFile, false))
+ return FALSE;
+
+ NWindows::NFile::NIO::CInFile inFile;
+ if (!inFile.Open(oldFile))
+ return FALSE;
+
+ char buf[1 << 14];
+
+ for (;;)
+ {
+ const ssize_t num = inFile.read_part(buf, sizeof(buf));
+ if (num == 0)
+ return TRUE;
+ if (num < 0)
+ return FALSE;
+ size_t processed;
+ const ssize_t num2 = outFile.write_full(buf, (size_t)num, processed);
+ if (num2 != num || processed != (size_t)num)
+ return FALSE;
+ }
+}
+
+
+bool MyMoveFile(CFSTR oldFile, CFSTR newFile)
+{
+ int res = rename(oldFile, newFile);
+ if (res == 0)
+ return true;
+ if (errno != EXDEV) // (oldFile and newFile are not on the same mounted filesystem)
+ return false;
+
+ if (My_CopyFile(oldFile, newFile) == FALSE)
+ return false;
+
+ struct stat info_file;
+ res = stat(oldFile, &info_file);
+ if (res != 0)
+ return false;
+
+ /*
+ ret = chmod(dst,info_file.st_mode & g_umask.mask);
+ */
+ return (unlink(oldFile) == 0);
+}
+
+
+bool CreateDir(CFSTR path)
+{
+ return (mkdir(path, 0777) == 0); // change it
+}
+
+static bool CreateDir2(CFSTR path)
+{
+ return (mkdir(path, 0777) == 0); // change it
+}
+
+
+bool DeleteFileAlways(CFSTR path)
+{
+ return (remove(path) == 0);
+}
+
+bool SetCurrentDir(CFSTR path)
+{
+ return (chdir(path) == 0);
+}
+
+
+bool GetCurrentDir(FString &path)
+{
+ path.Empty();
+
+ #define MY_PATH_MAX PATH_MAX
+ // #define MY_PATH_MAX 1024
+
+ char s[MY_PATH_MAX + 1];
+ char *res = getcwd(s, MY_PATH_MAX);
+ if (res)
+ {
+ path = fas2fs(s);
+ return true;
+ }
+ {
+ // if (errno != ERANGE) return false;
+ #if defined(__GLIBC__) || defined(__APPLE__)
+ /* As an extension to the POSIX.1-2001 standard, glibc's getcwd()
+ allocates the buffer dynamically using malloc(3) if buf is NULL. */
+ res = getcwd(NULL, 0);
+ if (res)
+ {
+ path = fas2fs(res);
+ ::free(res);
+ return true;
+ }
+ #endif
+ return false;
+ }
+}
+
+
+
+// #undef UTIME_OMIT // to debug
+
+#ifndef UTIME_OMIT
+ /* we can define UTIME_OMIT for debian and another systems.
+ Is it OK to define UTIME_OMIT to -2 here, if UTIME_OMIT is not defined? */
+ // #define UTIME_OMIT -2
+#endif
+
+
+
+
+
+bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime)
+{
+ // need testing
+ /*
+ struct utimbuf buf;
+ struct stat st;
+ UNUSED_VAR(cTime)
+
+ printf("\nstat = %s\n", path);
+ int ret = stat(path, &st);
+
+ if (ret == 0)
+ {
+ buf.actime = st.st_atime;
+ buf.modtime = st.st_mtime;
+ }
+ else
+ {
+ time_t cur_time = time(0);
+ buf.actime = cur_time;
+ buf.modtime = cur_time;
+ }
+
+ if (aTime)
+ {
+ UInt32 ut;
+ if (NTime::FileTimeToUnixTime(*aTime, ut))
+ buf.actime = ut;
+ }
+
+ if (mTime)
+ {
+ UInt32 ut;
+ if (NTime::FileTimeToUnixTime(*mTime, ut))
+ buf.modtime = ut;
+ }
+
+ return utime(path, &buf) == 0;
+ */
+
+ // if (!aTime && !mTime) return true;
+
+ struct timespec times[2];
+ UNUSED_VAR(cTime)
+
+ bool needChange;
+ needChange = FiTime_To_timespec(aTime, times[0]);
+ needChange |= FiTime_To_timespec(mTime, times[1]);
+
+ /*
+ if (mTime)
+ {
+ printf("\n time = %ld.%9ld\n", mTime->tv_sec, mTime->tv_nsec);
+ }
+ */
+
+ if (!needChange)
+ return true;
+ const int flags = 0; // follow link
+ // = AT_SYMLINK_NOFOLLOW; // don't follow link
+ return utimensat(AT_FDCWD, path, times, flags) == 0;
+}
+
+
+
+struct C_umask
+{
+ mode_t mask;
+
+ C_umask()
+ {
+ /* by security reasons we restrict attributes according
+ with process's file mode creation mask (umask) */
+ const mode_t um = umask(0); // octal :0022 is expected
+ mask = 0777 & (~um); // octal: 0755 is expected
+ umask(um); // restore the umask
+ // printf("\n umask = 0%03o mask = 0%03o\n", um, mask);
+
+ // mask = 0777; // debug we can disable the restriction:
+ }
+};
+
+static C_umask g_umask;
+
+// #define PRF(x) x;
+#define PRF(x)
+
+#define TRACE_SetFileAttrib(msg) \
+ PRF(printf("\nSetFileAttrib(%s, %x) : %s\n", (const char *)path, attrib, msg);)
+
+#define TRACE_chmod(s, mode) \
+ PRF(printf("\n chmod(%s, %o)\n", (const char *)path, (unsigned)(mode));)
+
+int my_chown(CFSTR path, uid_t owner, gid_t group)
+{
+ return chown(path, owner, group);
+}
+
+bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib)
+{
+ TRACE_SetFileAttrib("")
+
+ struct stat st;
+
+ bool use_lstat = true;
+ if (use_lstat)
+ {
+ if (lstat(path, &st) != 0)
+ {
+ TRACE_SetFileAttrib("bad lstat()")
+ return false;
+ }
+ // TRACE_chmod("lstat", st.st_mode);
+ }
+ else
+ {
+ if (stat(path, &st) != 0)
+ {
+ TRACE_SetFileAttrib("bad stat()")
+ return false;
+ }
+ }
+
+ if (attrib & FILE_ATTRIBUTE_UNIX_EXTENSION)
+ {
+ TRACE_SetFileAttrib("attrib & FILE_ATTRIBUTE_UNIX_EXTENSION")
+ st.st_mode = attrib >> 16;
+ if (S_ISDIR(st.st_mode))
+ {
+ // user/7z must be able to create files in this directory
+ st.st_mode |= (S_IRUSR | S_IWUSR | S_IXUSR);
+ }
+ else if (!S_ISREG(st.st_mode))
+ return true;
+ }
+ else if (S_ISLNK(st.st_mode))
+ {
+ /* for most systems: permissions for symlinks are fixed to rwxrwxrwx.
+ so we don't need chmod() for symlinks. */
+ return true;
+ // SetLastError(ENOSYS);
+ // return false;
+ }
+ else
+ {
+ TRACE_SetFileAttrib("Only Windows Attributes")
+ // Only Windows Attributes
+ if (S_ISDIR(st.st_mode)
+ || (attrib & FILE_ATTRIBUTE_READONLY) == 0)
+ return true;
+ st.st_mode &= ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); // octal: ~0222; // disable write permissions
+ }
+
+ int res;
+ /*
+ if (S_ISLNK(st.st_mode))
+ {
+ printf("\nfchmodat()\n");
+ TRACE_chmod(path, (st.st_mode) & g_umask.mask)
+ // AT_SYMLINK_NOFOLLOW is not implemted still in Linux.
+ res = fchmodat(AT_FDCWD, path, (st.st_mode) & g_umask.mask,
+ S_ISLNK(st.st_mode) ? AT_SYMLINK_NOFOLLOW : 0);
+ }
+ else
+ */
+ {
+ TRACE_chmod(path, (st.st_mode) & g_umask.mask)
+ res = chmod(path, (st.st_mode) & g_umask.mask);
+ }
+ // TRACE_SetFileAttrib("End")
+ return (res == 0);
+}
+
+
+bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName)
+{
+ PRF(printf("\nhard link() %s -> %s\n", newFileName, existFileName);)
+ return (link(existFileName, newFileName) == 0);
+}
+
+#endif // !_WIN32
+
+// #endif
+
+}}}
diff --git a/CPP/Windows/FileDir.h b/CPP/Windows/FileDir.h
index 8d2b56a..573ffa2 100644
--- a/CPP/Windows/FileDir.h
+++ b/CPP/Windows/FileDir.h
@@ -1,117 +1,135 @@
-// Windows/FileDir.h
-
-#ifndef __WINDOWS_FILE_DIR_H
-#define __WINDOWS_FILE_DIR_H
-
-#include "../Common/MyString.h"
-
-#include "FileIO.h"
-
-namespace NWindows {
-namespace NFile {
-namespace NDir {
-
-bool GetWindowsDir(FString &path);
-bool GetSystemDir(FString &path);
-
-bool SetDirTime(CFSTR path, const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime);
-
-
-bool SetFileAttrib(CFSTR path, DWORD attrib);
-
-/*
- Some programs store posix attributes in high 16 bits of windows attributes field.
- Also some programs use additional flag markers: 0x8000 or 0x4000.
- SetFileAttrib_PosixHighDetect() tries to detect posix field, and it extracts only attribute
- bits that are related to current system only.
-*/
-
-bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib);
-
-
-bool MyMoveFile(CFSTR existFileName, CFSTR newFileName);
-
-#ifndef UNDER_CE
-bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName);
-#endif
-
-bool RemoveDir(CFSTR path);
-bool CreateDir(CFSTR path);
-
-/* CreateComplexDir returns true, if directory can contain files after the call (two cases):
- 1) the directory already exists (network shares and drive paths are supported)
- 2) the directory was created
- path can be WITH or WITHOUT trailing path separator. */
-
-bool CreateComplexDir(CFSTR path);
-
-bool DeleteFileAlways(CFSTR name);
-bool RemoveDirWithSubItems(const FString &path);
-
-bool MyGetFullPathName(CFSTR path, FString &resFullPath);
-bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName);
-bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix);
-
-#ifndef UNDER_CE
-
-bool SetCurrentDir(CFSTR path);
-bool GetCurrentDir(FString &resultPath);
-
-#endif
-
-bool MyGetTempPath(FString &resultPath);
-
-class CTempFile
-{
- bool _mustBeDeleted;
- FString _path;
- void DisableDeleting() { _mustBeDeleted = false; }
-public:
- CTempFile(): _mustBeDeleted(false) {}
- ~CTempFile() { Remove(); }
- const FString &GetPath() const { return _path; }
- bool Create(CFSTR pathPrefix, NIO::COutFile *outFile); // pathPrefix is not folder prefix
- bool CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile);
- bool Remove();
- bool MoveTo(CFSTR name, bool deleteDestBefore);
-};
-
-class CTempDir
-{
- bool _mustBeDeleted;
- FString _path;
-public:
- CTempDir(): _mustBeDeleted(false) {}
- ~CTempDir() { Remove(); }
- const FString &GetPath() const { return _path; }
- void DisableDeleting() { _mustBeDeleted = false; }
- bool Create(CFSTR namePrefix) ;
- bool Remove();
-};
-
-#if !defined(UNDER_CE)
-class CCurrentDirRestorer
-{
- FString _path;
-public:
- bool NeedRestore;
-
- CCurrentDirRestorer(): NeedRestore(true)
- {
- GetCurrentDir(_path);
- }
- ~CCurrentDirRestorer()
- {
- if (!NeedRestore)
- return;
- FString s;
- if (GetCurrentDir(s))
- if (s != _path)
- SetCurrentDir(_path);
- }
-};
-#endif
-
-}}}
-
-#endif
+// Windows/FileDir.h
+
+#ifndef ZIP7_INC_WINDOWS_FILE_DIR_H
+#define ZIP7_INC_WINDOWS_FILE_DIR_H
+
+#include "../Common/MyString.h"
+
+#include "FileIO.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NDir {
+
+bool GetWindowsDir(FString &path);
+bool GetSystemDir(FString &path);
+
+/*
+WIN32 API : SetFileTime() doesn't allow to set zero timestamps in file
+but linux : allows unix time = 0 in filesystem
+*/
+
+bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime);
+
+
+#ifdef _WIN32
+
+bool SetFileAttrib(CFSTR path, DWORD attrib);
+
+/*
+ Some programs store posix attributes in high 16 bits of windows attributes field.
+ Also some programs use additional flag markers: 0x8000 or 0x4000.
+ SetFileAttrib_PosixHighDetect() tries to detect posix field, and it extracts only attribute
+ bits that are related to current system only.
+*/
+#else
+
+int my_chown(CFSTR path, uid_t owner, gid_t group);
+
+#endif
+
+bool SetFileAttrib_PosixHighDetect(CFSTR path, DWORD attrib);
+
+
+bool MyMoveFile(CFSTR existFileName, CFSTR newFileName);
+
+#ifndef UNDER_CE
+bool MyCreateHardLink(CFSTR newFileName, CFSTR existFileName);
+#endif
+
+bool RemoveDir(CFSTR path);
+bool CreateDir(CFSTR path);
+
+/* CreateComplexDir returns true, if directory can contain files after the call (two cases):
+ 1) the directory already exists (network shares and drive paths are supported)
+ 2) the directory was created
+ path can be WITH or WITHOUT trailing path separator. */
+
+bool CreateComplexDir(CFSTR path);
+
+bool DeleteFileAlways(CFSTR name);
+bool RemoveDirWithSubItems(const FString &path);
+
+bool MyGetFullPathName(CFSTR path, FString &resFullPath);
+bool GetFullPathAndSplit(CFSTR path, FString &resDirPrefix, FString &resFileName);
+bool GetOnlyDirPrefix(CFSTR path, FString &resDirPrefix);
+
+#ifndef UNDER_CE
+
+bool SetCurrentDir(CFSTR path);
+bool GetCurrentDir(FString &resultPath);
+
+#endif
+
+bool MyGetTempPath(FString &resultPath);
+
+bool CreateTempFile2(CFSTR prefix, bool addRandom, AString &postfix, NIO::COutFile *outFile);
+
+class CTempFile MY_UNCOPYABLE
+{
+ bool _mustBeDeleted;
+ FString _path;
+ void DisableDeleting() { _mustBeDeleted = false; }
+public:
+ CTempFile(): _mustBeDeleted(false) {}
+ ~CTempFile() { Remove(); }
+ const FString &GetPath() const { return _path; }
+ bool Create(CFSTR pathPrefix, NIO::COutFile *outFile); // pathPrefix is not folder prefix
+ bool CreateRandomInTempFolder(CFSTR namePrefix, NIO::COutFile *outFile);
+ bool Remove();
+ bool MoveTo(CFSTR name, bool deleteDestBefore);
+};
+
+
+#ifdef _WIN32
+class CTempDir MY_UNCOPYABLE
+{
+ bool _mustBeDeleted;
+ FString _path;
+public:
+ CTempDir(): _mustBeDeleted(false) {}
+ ~CTempDir() { Remove(); }
+ const FString &GetPath() const { return _path; }
+ void DisableDeleting() { _mustBeDeleted = false; }
+ bool Create(CFSTR namePrefix) ;
+ bool Remove();
+};
+#endif
+
+
+#if !defined(UNDER_CE)
+class CCurrentDirRestorer MY_UNCOPYABLE
+{
+ FString _path;
+public:
+ bool NeedRestore;
+
+ CCurrentDirRestorer(): NeedRestore(true)
+ {
+ GetCurrentDir(_path);
+ }
+ ~CCurrentDirRestorer()
+ {
+ if (!NeedRestore)
+ return;
+ FString s;
+ if (GetCurrentDir(s))
+ if (s != _path)
+ SetCurrentDir(_path);
+ }
+};
+#endif
+
+}}}
+
+#endif
diff --git a/CPP/Windows/FileFind.cpp b/CPP/Windows/FileFind.cpp
index 8c6255b..c562a90 100644
--- a/CPP/Windows/FileFind.cpp
+++ b/CPP/Windows/FileFind.cpp
@@ -1,749 +1,1329 @@
-// Windows/FileFind.cpp
-
-#include "StdAfx.h"
-
-#ifndef _UNICODE
-#include "../Common/StringConvert.h"
-#endif
-
-#include "FileFind.h"
-#include "FileIO.h"
-#include "FileName.h"
-
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NName;
-
-#if defined(_WIN32) && !defined(UNDER_CE)
-
-EXTERN_C_BEGIN
-
-typedef enum
-{
- My_FindStreamInfoStandard,
- My_FindStreamInfoMaxInfoLevel
-} MY_STREAM_INFO_LEVELS;
-
-typedef struct
-{
- LARGE_INTEGER StreamSize;
- WCHAR cStreamName[MAX_PATH + 36];
-} MY_WIN32_FIND_STREAM_DATA, *MY_PWIN32_FIND_STREAM_DATA;
-
-typedef WINBASEAPI HANDLE (WINAPI *FindFirstStreamW_Ptr)(LPCWSTR fileName, MY_STREAM_INFO_LEVELS infoLevel,
- LPVOID findStreamData, DWORD flags);
-
-typedef WINBASEAPI BOOL (APIENTRY *FindNextStreamW_Ptr)(HANDLE findStream, LPVOID findStreamData);
-
-EXTERN_C_END
-
-#endif
-
-namespace NWindows {
-namespace NFile {
-
-#ifdef SUPPORT_DEVICE_FILE
-namespace NSystem
-{
-bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
-}
-#endif
-
-namespace NFind {
-
-bool CFileInfo::IsDots() const throw()
-{
- if (!IsDir() || Name.IsEmpty())
- return false;
- if (Name[0] != '.')
- return false;
- return Name.Len() == 1 || (Name.Len() == 2 && Name[1] == '.');
-}
-
-#define WIN_FD_TO_MY_FI(fi, fd) \
- fi.Attrib = fd.dwFileAttributes; \
- fi.CTime = fd.ftCreationTime; \
- fi.ATime = fd.ftLastAccessTime; \
- fi.MTime = fd.ftLastWriteTime; \
- fi.Size = (((UInt64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow; \
- fi.IsAltStream = false; \
- fi.IsDevice = false;
-
- /*
- #ifdef UNDER_CE
- fi.ObjectID = fd.dwOID;
- #else
- fi.ReparseTag = fd.dwReserved0;
- #endif
- */
-
-static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATAW &fd, CFileInfo &fi)
-{
- WIN_FD_TO_MY_FI(fi, fd);
- fi.Name = us2fs(fd.cFileName);
- #if defined(_WIN32) && !defined(UNDER_CE)
- // fi.ShortName = us2fs(fd.cAlternateFileName);
- #endif
-}
-
-#ifndef _UNICODE
-
-static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATA &fd, CFileInfo &fi)
-{
- WIN_FD_TO_MY_FI(fi, fd);
- fi.Name = fas2fs(fd.cFileName);
- #if defined(_WIN32) && !defined(UNDER_CE)
- // fi.ShortName = fas2fs(fd.cAlternateFileName);
- #endif
-}
-#endif
-
-////////////////////////////////
-// CFindFile
-
-bool CFindFileBase::Close() throw()
-{
- if (_handle == INVALID_HANDLE_VALUE)
- return true;
- if (!::FindClose(_handle))
- return false;
- _handle = INVALID_HANDLE_VALUE;
- return true;
-}
-
-/*
-WinXP-64 FindFirstFile():
- "" - ERROR_PATH_NOT_FOUND
- folder\ - ERROR_FILE_NOT_FOUND
- \ - ERROR_FILE_NOT_FOUND
- c:\ - ERROR_FILE_NOT_FOUND
- c: - ERROR_FILE_NOT_FOUND, if current dir is ROOT ( c:\ )
- c: - OK, if current dir is NOT ROOT ( c:\folder )
- folder - OK
-
- \\ - ERROR_INVALID_NAME
- \\Server - ERROR_INVALID_NAME
- \\Server\ - ERROR_INVALID_NAME
-
- \\Server\Share - ERROR_BAD_NETPATH
- \\Server\Share - ERROR_BAD_NET_NAME (Win7).
- !!! There is problem : Win7 makes some requests for "\\Server\Shar" (look in Procmon),
- when we call it for "\\Server\Share"
-
- \\Server\Share\ - ERROR_FILE_NOT_FOUND
-
- \\?\UNC\Server\Share - ERROR_INVALID_NAME
- \\?\UNC\Server\Share - ERROR_BAD_PATHNAME (Win7)
- \\?\UNC\Server\Share\ - ERROR_FILE_NOT_FOUND
-
- \\Server\Share_RootDrive - ERROR_INVALID_NAME
- \\Server\Share_RootDrive\ - ERROR_INVALID_NAME
-
- c:\* - ERROR_FILE_NOT_FOUND, if thare are no item in that folder
-*/
-
-bool CFindFile::FindFirst(CFSTR path, CFileInfo &fi)
-{
- if (!Close())
- return false;
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- WIN32_FIND_DATAA fd;
- _handle = ::FindFirstFileA(fs2fas(path), &fd);
- if (_handle == INVALID_HANDLE_VALUE)
- return false;
- Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi);
- }
- else
- #endif
- {
- WIN32_FIND_DATAW fd;
-
- IF_USE_MAIN_PATH
- _handle = ::FindFirstFileW(fs2us(path), &fd);
- #ifdef WIN_LONG_PATH
- if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH)
- {
- UString superPath;
- if (GetSuperPath(path, superPath, USE_MAIN_PATH))
- _handle = ::FindFirstFileW(superPath, &fd);
- }
- #endif
- if (_handle == INVALID_HANDLE_VALUE)
- return false;
- Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi);
- }
- return true;
-}
-
-bool CFindFile::FindNext(CFileInfo &fi)
-{
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- WIN32_FIND_DATAA fd;
- if (!::FindNextFileA(_handle, &fd))
- return false;
- Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi);
- }
- else
- #endif
- {
- WIN32_FIND_DATAW fd;
- if (!::FindNextFileW(_handle, &fd))
- return false;
- Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi);
- }
- return true;
-}
-
-#if defined(_WIN32) && !defined(UNDER_CE)
-
-////////////////////////////////
-// AltStreams
-
-static FindFirstStreamW_Ptr g_FindFirstStreamW;
-static FindNextStreamW_Ptr g_FindNextStreamW;
-
-struct CFindStreamLoader
-{
- CFindStreamLoader()
- {
- g_FindFirstStreamW = (FindFirstStreamW_Ptr)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "FindFirstStreamW");
- g_FindNextStreamW = (FindNextStreamW_Ptr)::GetProcAddress(::GetModuleHandleA("kernel32.dll"), "FindNextStreamW");
- }
-} g_FindStreamLoader;
-
-bool CStreamInfo::IsMainStream() const throw()
-{
- return StringsAreEqualNoCase_Ascii(Name, "::$DATA");
-};
-
-UString CStreamInfo::GetReducedName() const
-{
- // remove ":$DATA" postfix, but keep postfix, if Name is "::$DATA"
- UString s (Name);
- if (s.Len() > 6 + 1 && StringsAreEqualNoCase_Ascii(s.RightPtr(6), ":$DATA"))
- s.DeleteFrom(s.Len() - 6);
- return s;
-}
-
-/*
-UString CStreamInfo::GetReducedName2() const
-{
- UString s = GetReducedName();
- if (!s.IsEmpty() && s[0] == ':')
- s.Delete(0);
- return s;
-}
-*/
-
-static void Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(const MY_WIN32_FIND_STREAM_DATA &sd, CStreamInfo &si)
-{
- si.Size = sd.StreamSize.QuadPart;
- si.Name = sd.cStreamName;
-}
-
-/*
- WinXP-64 FindFirstStream():
- "" - ERROR_PATH_NOT_FOUND
- folder\ - OK
- folder - OK
- \ - OK
- c:\ - OK
- c: - OK, if current dir is ROOT ( c:\ )
- c: - OK, if current dir is NOT ROOT ( c:\folder )
- \\Server\Share - OK
- \\Server\Share\ - OK
-
- \\ - ERROR_INVALID_NAME
- \\Server - ERROR_INVALID_NAME
- \\Server\ - ERROR_INVALID_NAME
-*/
-
-bool CFindStream::FindFirst(CFSTR path, CStreamInfo &si)
-{
- if (!Close())
- return false;
- if (!g_FindFirstStreamW)
- {
- ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return false;
- }
- {
- MY_WIN32_FIND_STREAM_DATA sd;
- SetLastError(0);
- IF_USE_MAIN_PATH
- _handle = g_FindFirstStreamW(fs2us(path), My_FindStreamInfoStandard, &sd, 0);
- if (_handle == INVALID_HANDLE_VALUE)
- {
- if (::GetLastError() == ERROR_HANDLE_EOF)
- return false;
- // long name can be tricky for path like ".\dirName".
- #ifdef WIN_LONG_PATH
- if (USE_SUPER_PATH)
- {
- UString superPath;
- if (GetSuperPath(path, superPath, USE_MAIN_PATH))
- _handle = g_FindFirstStreamW(superPath, My_FindStreamInfoStandard, &sd, 0);
- }
- #endif
- }
- if (_handle == INVALID_HANDLE_VALUE)
- return false;
- Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(sd, si);
- }
- return true;
-}
-
-bool CFindStream::FindNext(CStreamInfo &si)
-{
- if (!g_FindNextStreamW)
- {
- ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return false;
- }
- {
- MY_WIN32_FIND_STREAM_DATA sd;
- if (!g_FindNextStreamW(_handle, &sd))
- return false;
- Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(sd, si);
- }
- return true;
-}
-
-bool CStreamEnumerator::Next(CStreamInfo &si, bool &found)
-{
- bool res;
- if (_find.IsHandleAllocated())
- res = _find.FindNext(si);
- else
- res = _find.FindFirst(_filePath, si);
- if (res)
- {
- found = true;
- return true;
- }
- found = false;
- return (::GetLastError() == ERROR_HANDLE_EOF);
-}
-
-#endif
-
-
-#define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0;
-
-void CFileInfoBase::ClearBase() throw()
-{
- Size = 0;
- MY_CLEAR_FILETIME(CTime);
- MY_CLEAR_FILETIME(ATime);
- MY_CLEAR_FILETIME(MTime);
- Attrib = 0;
- IsAltStream = false;
- IsDevice = false;
-}
-
-/*
-WinXP-64 GetFileAttributes():
- If the function fails, it returns INVALID_FILE_ATTRIBUTES and use GetLastError() to get error code
-
- \ - OK
- C:\ - OK, if there is such drive,
- D:\ - ERROR_PATH_NOT_FOUND, if there is no such drive,
-
- C:\folder - OK
- C:\folder\ - OK
- C:\folderBad - ERROR_FILE_NOT_FOUND
-
- \\Server\BadShare - ERROR_BAD_NETPATH
- \\Server\Share - WORKS OK, but MSDN says:
- GetFileAttributes for a network share, the function fails, and GetLastError
- returns ERROR_BAD_NETPATH. You must specify a path to a subfolder on that share.
-*/
-
-DWORD GetFileAttrib(CFSTR path)
-{
- #ifndef _UNICODE
- if (!g_IsNT)
- return ::GetFileAttributes(fs2fas(path));
- else
- #endif
- {
- IF_USE_MAIN_PATH
- {
- DWORD dw = ::GetFileAttributesW(fs2us(path));
- if (dw != INVALID_FILE_ATTRIBUTES)
- return dw;
- }
- #ifdef WIN_LONG_PATH
- if (USE_SUPER_PATH)
- {
- UString superPath;
- if (GetSuperPath(path, superPath, USE_MAIN_PATH))
- return ::GetFileAttributesW(superPath);
- }
- #endif
- return INVALID_FILE_ATTRIBUTES;
- }
-}
-
-/* if path is "c:" or "c::" then CFileInfo::Find() returns name of current folder for that disk
- so instead of absolute path we have relative path in Name. That is not good in some calls */
-
-/* In CFileInfo::Find() we want to support same names for alt streams as in CreateFile(). */
-
-/* CFileInfo::Find()
-We alow the following paths (as FindFirstFile):
- C:\folder
- c: - if current dir is NOT ROOT ( c:\folder )
-
-also we support paths that are not supported by FindFirstFile:
- \
- \\.\c:
- c:\ - Name will be without tail slash ( c: )
- \\?\c:\ - Name will be without tail slash ( c: )
- \\Server\Share
- \\?\UNC\Server\Share
-
- c:\folder:stream - Name = folder:stream
- c:\:stream - Name = :stream
- c::stream - Name = c::stream
-*/
-
-bool CFileInfo::Find(CFSTR path)
-{
- #ifdef SUPPORT_DEVICE_FILE
- if (IsDevicePath(path))
- {
- ClearBase();
- Name = path + 4;
- IsDevice = true;
-
- if (NName::IsDrivePath2(path + 4) && path[6] == 0)
- {
- FChar drive[4] = { path[4], ':', '\\', 0 };
- UInt64 clusterSize, totalSize, freeSize;
- if (NSystem::MyGetDiskFreeSpace(drive, clusterSize, totalSize, freeSize))
- {
- Size = totalSize;
- return true;
- }
- }
-
- NIO::CInFile inFile;
- // ::OutputDebugStringW(path);
- if (!inFile.Open(path))
- return false;
- // ::OutputDebugStringW(L"---");
- if (inFile.SizeDefined)
- Size = inFile.Size;
- return true;
- }
- #endif
-
- #if defined(_WIN32) && !defined(UNDER_CE)
-
- int colonPos = FindAltStreamColon(path);
- if (colonPos >= 0 && path[(unsigned)colonPos + 1] != 0)
- {
- UString streamName = fs2us(path + (unsigned)colonPos);
- FString filePath (path);
- filePath.DeleteFrom(colonPos);
- /* we allow both cases:
- name:stream
- name:stream:$DATA
- */
- const unsigned kPostfixSize = 6;
- if (streamName.Len() <= kPostfixSize
- || !StringsAreEqualNoCase_Ascii(streamName.RightPtr(kPostfixSize), ":$DATA"))
- streamName += ":$DATA";
-
- bool isOk = true;
-
- if (IsDrivePath2(filePath) &&
- (colonPos == 2 || colonPos == 3 && filePath[2] == '\\'))
- {
- // FindFirstFile doesn't work for "c:\" and for "c:" (if current dir is ROOT)
- ClearBase();
- Name.Empty();
- if (colonPos == 2)
- Name = filePath;
- }
- else
- isOk = Find(filePath);
-
- if (isOk)
- {
- Attrib &= ~(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT);
- Size = 0;
- CStreamEnumerator enumerator(filePath);
- for (;;)
- {
- CStreamInfo si;
- bool found;
- if (!enumerator.Next(si, found))
- return false;
- if (!found)
- {
- ::SetLastError(ERROR_FILE_NOT_FOUND);
- return false;
- }
- if (si.Name.IsEqualTo_NoCase(streamName))
- {
- // we delete postfix, if alt stream name is not "::$DATA"
- if (si.Name.Len() > kPostfixSize + 1)
- si.Name.DeleteFrom(si.Name.Len() - kPostfixSize);
- Name += us2fs(si.Name);
- Size = si.Size;
- IsAltStream = true;
- return true;
- }
- }
- }
- }
-
- #endif
-
- CFindFile finder;
-
- #if defined(_WIN32) && !defined(UNDER_CE)
- {
- /*
- DWORD lastError = GetLastError();
- if (lastError == ERROR_FILE_NOT_FOUND
- || lastError == ERROR_BAD_NETPATH // XP64: "\\Server\Share"
- || lastError == ERROR_BAD_NET_NAME // Win7: "\\Server\Share"
- || lastError == ERROR_INVALID_NAME // XP64: "\\?\UNC\Server\Share"
- || lastError == ERROR_BAD_PATHNAME // Win7: "\\?\UNC\Server\Share"
- )
- */
-
- unsigned rootSize = 0;
- if (IsSuperPath(path))
- rootSize = kSuperPathPrefixSize;
-
- if (NName::IsDrivePath(path + rootSize) && path[rootSize + 3] == 0)
- {
- DWORD attrib = GetFileAttrib(path);
- if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)
- {
- ClearBase();
- Attrib = attrib;
- Name = path + rootSize;
- Name.DeleteFrom(2); // we don't need backslash (C:)
- return true;
- }
- }
- else if (IS_PATH_SEPAR(path[0]))
- if (path[1] == 0)
- {
- DWORD attrib = GetFileAttrib(path);
- if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)
- {
- ClearBase();
- Name.Empty();
- Attrib = attrib;
- return true;
- }
- }
- else
- {
- const unsigned prefixSize = GetNetworkServerPrefixSize(path);
- if (prefixSize > 0 && path[prefixSize] != 0)
- {
- if (NName::FindSepar(path + prefixSize) < 0)
- {
- FString s (path);
- s.Add_PathSepar();
- s += '*'; // CHAR_ANY_MASK
-
- bool isOK = false;
- if (finder.FindFirst(s, *this))
- {
- if (Name == FTEXT("."))
- {
- Name = path + prefixSize;
- return true;
- }
- isOK = true;
- /* if "\\server\share" maps to root folder "d:\", there is no "." item.
- But it's possible that there are another items */
- }
- {
- DWORD attrib = GetFileAttrib(path);
- if (isOK || attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)
- {
- ClearBase();
- if (attrib != INVALID_FILE_ATTRIBUTES)
- Attrib = attrib;
- else
- SetAsDir();
- Name = path + prefixSize;
- return true;
- }
- }
- // ::SetLastError(lastError);
- }
- }
- }
- }
- #endif
-
- return finder.FindFirst(path, *this);
-}
-
-
-bool DoesFileExist(CFSTR name)
-{
- CFileInfo fi;
- return fi.Find(name) && !fi.IsDir();
-}
-
-bool DoesDirExist(CFSTR name)
-{
- CFileInfo fi;
- return fi.Find(name) && fi.IsDir();
-}
-
-bool DoesFileOrDirExist(CFSTR name)
-{
- CFileInfo fi;
- return fi.Find(name);
-}
-
-
-void CEnumerator::SetDirPrefix(const FString &dirPrefix)
-{
- _wildcard = dirPrefix;
- _wildcard += '*';
-}
-
-bool CEnumerator::NextAny(CFileInfo &fi)
-{
- if (_findFile.IsHandleAllocated())
- return _findFile.FindNext(fi);
- else
- return _findFile.FindFirst(_wildcard, fi);
-}
-
-bool CEnumerator::Next(CFileInfo &fi)
-{
- for (;;)
- {
- if (!NextAny(fi))
- return false;
- if (!fi.IsDots())
- return true;
- }
-}
-
-bool CEnumerator::Next(CFileInfo &fi, bool &found)
-{
- if (Next(fi))
- {
- found = true;
- return true;
- }
- found = false;
- return (::GetLastError() == ERROR_NO_MORE_FILES);
-}
-
-////////////////////////////////
-// CFindChangeNotification
-// FindFirstChangeNotification can return 0. MSDN doesn't tell about it.
-
-bool CFindChangeNotification::Close() throw()
-{
- if (!IsHandleAllocated())
- return true;
- if (!::FindCloseChangeNotification(_handle))
- return false;
- _handle = INVALID_HANDLE_VALUE;
- return true;
-}
-
-HANDLE CFindChangeNotification::FindFirst(CFSTR path, bool watchSubtree, DWORD notifyFilter)
-{
- #ifndef _UNICODE
- if (!g_IsNT)
- _handle = ::FindFirstChangeNotification(fs2fas(path), BoolToBOOL(watchSubtree), notifyFilter);
- else
- #endif
- {
- IF_USE_MAIN_PATH
- _handle = ::FindFirstChangeNotificationW(fs2us(path), BoolToBOOL(watchSubtree), notifyFilter);
- #ifdef WIN_LONG_PATH
- if (!IsHandleAllocated())
- {
- UString superPath;
- if (GetSuperPath(path, superPath, USE_MAIN_PATH))
- _handle = ::FindFirstChangeNotificationW(superPath, BoolToBOOL(watchSubtree), notifyFilter);
- }
- #endif
- }
- return _handle;
-}
-
-#ifndef UNDER_CE
-
-bool MyGetLogicalDriveStrings(CObjectVector<FString> &driveStrings)
-{
- driveStrings.Clear();
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- driveStrings.Clear();
- UINT32 size = GetLogicalDriveStrings(0, NULL);
- if (size == 0)
- return false;
- CObjArray<char> buf(size);
- UINT32 newSize = GetLogicalDriveStrings(size, buf);
- if (newSize == 0 || newSize > size)
- return false;
- AString s;
- UINT32 prev = 0;
- for (UINT32 i = 0; i < newSize; i++)
- {
- if (buf[i] == 0)
- {
- s = buf + prev;
- prev = i + 1;
- driveStrings.Add(fas2fs(s));
- }
- }
- return prev == newSize;
- }
- else
- #endif
- {
- UINT32 size = GetLogicalDriveStringsW(0, NULL);
- if (size == 0)
- return false;
- CObjArray<wchar_t> buf(size);
- UINT32 newSize = GetLogicalDriveStringsW(size, buf);
- if (newSize == 0 || newSize > size)
- return false;
- UString s;
- UINT32 prev = 0;
- for (UINT32 i = 0; i < newSize; i++)
- {
- if (buf[i] == 0)
- {
- s = buf + prev;
- prev = i + 1;
- driveStrings.Add(us2fs(s));
- }
- }
- return prev == newSize;
- }
-}
-
-#endif
-
-}}}
+// Windows/FileFind.cpp
+
+#include "StdAfx.h"
+
+// #include <stdio.h>
+
+#ifndef _WIN32
+#include <fcntl.h> /* Definition of AT_* constants */
+#include "TimeUtils.h"
+// for major
+// #include <sys/sysmacros.h>
+#endif
+
+#include "FileFind.h"
+#include "FileIO.h"
+#include "FileName.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NName;
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+
+EXTERN_C_BEGIN
+
+typedef enum
+{
+ My_FindStreamInfoStandard,
+ My_FindStreamInfoMaxInfoLevel
+} MY_STREAM_INFO_LEVELS;
+
+typedef struct
+{
+ LARGE_INTEGER StreamSize;
+ WCHAR cStreamName[MAX_PATH + 36];
+} MY_WIN32_FIND_STREAM_DATA, *MY_PWIN32_FIND_STREAM_DATA;
+
+typedef HANDLE (WINAPI *Func_FindFirstStreamW)(LPCWSTR fileName, MY_STREAM_INFO_LEVELS infoLevel,
+ LPVOID findStreamData, DWORD flags);
+
+typedef BOOL (APIENTRY *Func_FindNextStreamW)(HANDLE findStream, LPVOID findStreamData);
+
+EXTERN_C_END
+
+#endif // defined(_WIN32) && !defined(UNDER_CE)
+
+
+namespace NWindows {
+namespace NFile {
+
+
+#ifdef _WIN32
+#ifdef Z7_DEVICE_FILE
+namespace NSystem
+{
+bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
+}
+#endif
+#endif
+
+namespace NFind {
+
+/*
+#ifdef _WIN32
+#define MY_CLEAR_FILETIME(ft) ft.dwLowDateTime = ft.dwHighDateTime = 0;
+#else
+#define MY_CLEAR_FILETIME(ft) ft.tv_sec = 0; ft.tv_nsec = 0;
+#endif
+*/
+
+void CFileInfoBase::ClearBase() throw()
+{
+ Size = 0;
+ FiTime_Clear(CTime);
+ FiTime_Clear(ATime);
+ FiTime_Clear(MTime);
+
+ #ifdef _WIN32
+ Attrib = 0;
+ // ReparseTag = 0;
+ IsAltStream = false;
+ IsDevice = false;
+ #else
+ dev = 0;
+ ino = 0;
+ mode = 0;
+ nlink = 0;
+ uid = 0;
+ gid = 0;
+ rdev = 0;
+ #endif
+}
+
+bool CFileInfo::IsDots() const throw()
+{
+ if (!IsDir() || Name.IsEmpty())
+ return false;
+ if (Name[0] != '.')
+ return false;
+ return Name.Len() == 1 || (Name.Len() == 2 && Name[1] == '.');
+}
+
+
+#ifdef _WIN32
+
+
+#define WIN_FD_TO_MY_FI(fi, fd) \
+ fi.Attrib = fd.dwFileAttributes; \
+ fi.CTime = fd.ftCreationTime; \
+ fi.ATime = fd.ftLastAccessTime; \
+ fi.MTime = fd.ftLastWriteTime; \
+ fi.Size = (((UInt64)fd.nFileSizeHigh) << 32) + fd.nFileSizeLow; \
+ /* fi.ReparseTag = fd.dwReserved0; */ \
+ fi.IsAltStream = false; \
+ fi.IsDevice = false;
+
+ /*
+ #ifdef UNDER_CE
+ fi.ObjectID = fd.dwOID;
+ #else
+ fi.ReparseTag = fd.dwReserved0;
+ #endif
+ */
+
+static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATAW &fd, CFileInfo &fi)
+{
+ WIN_FD_TO_MY_FI(fi, fd)
+ fi.Name = us2fs(fd.cFileName);
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ // fi.ShortName = us2fs(fd.cAlternateFileName);
+ #endif
+}
+
+#ifndef _UNICODE
+static void Convert_WIN32_FIND_DATA_to_FileInfo(const WIN32_FIND_DATA &fd, CFileInfo &fi)
+{
+ WIN_FD_TO_MY_FI(fi, fd)
+ fi.Name = fas2fs(fd.cFileName);
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ // fi.ShortName = fas2fs(fd.cAlternateFileName);
+ #endif
+}
+#endif
+
+////////////////////////////////
+// CFindFile
+
+bool CFindFileBase::Close() throw()
+{
+ if (_handle == INVALID_HANDLE_VALUE)
+ return true;
+ if (!::FindClose(_handle))
+ return false;
+ _handle = INVALID_HANDLE_VALUE;
+ return true;
+}
+
+/*
+WinXP-64 FindFirstFile():
+ "" - ERROR_PATH_NOT_FOUND
+ folder\ - ERROR_FILE_NOT_FOUND
+ \ - ERROR_FILE_NOT_FOUND
+ c:\ - ERROR_FILE_NOT_FOUND
+ c: - ERROR_FILE_NOT_FOUND, if current dir is ROOT ( c:\ )
+ c: - OK, if current dir is NOT ROOT ( c:\folder )
+ folder - OK
+
+ \\ - ERROR_INVALID_NAME
+ \\Server - ERROR_INVALID_NAME
+ \\Server\ - ERROR_INVALID_NAME
+
+ \\Server\Share - ERROR_BAD_NETPATH
+ \\Server\Share - ERROR_BAD_NET_NAME (Win7).
+ !!! There is problem : Win7 makes some requests for "\\Server\Shar" (look in Procmon),
+ when we call it for "\\Server\Share"
+
+ \\Server\Share\ - ERROR_FILE_NOT_FOUND
+
+ \\?\UNC\Server\Share - ERROR_INVALID_NAME
+ \\?\UNC\Server\Share - ERROR_BAD_PATHNAME (Win7)
+ \\?\UNC\Server\Share\ - ERROR_FILE_NOT_FOUND
+
+ \\Server\Share_RootDrive - ERROR_INVALID_NAME
+ \\Server\Share_RootDrive\ - ERROR_INVALID_NAME
+
+ e:\* - ERROR_FILE_NOT_FOUND, if there are no items in that root folder
+ w:\* - ERROR_PATH_NOT_FOUND, if there is no such drive w:
+*/
+
+bool CFindFile::FindFirst(CFSTR path, CFileInfo &fi)
+{
+ if (!Close())
+ return false;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ WIN32_FIND_DATAA fd;
+ _handle = ::FindFirstFileA(fs2fas(path), &fd);
+ if (_handle == INVALID_HANDLE_VALUE)
+ return false;
+ Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi);
+ }
+ else
+ #endif
+ {
+ WIN32_FIND_DATAW fd;
+
+ IF_USE_MAIN_PATH
+ _handle = ::FindFirstFileW(fs2us(path), &fd);
+ #ifdef Z7_LONG_PATH
+ if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH)
+ {
+ UString superPath;
+ if (GetSuperPath(path, superPath, USE_MAIN_PATH))
+ _handle = ::FindFirstFileW(superPath, &fd);
+ }
+ #endif
+ if (_handle == INVALID_HANDLE_VALUE)
+ return false;
+ Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi);
+ }
+ return true;
+}
+
+bool CFindFile::FindNext(CFileInfo &fi)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ WIN32_FIND_DATAA fd;
+ if (!::FindNextFileA(_handle, &fd))
+ return false;
+ Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi);
+ }
+ else
+ #endif
+ {
+ WIN32_FIND_DATAW fd;
+ if (!::FindNextFileW(_handle, &fd))
+ return false;
+ Convert_WIN32_FIND_DATA_to_FileInfo(fd, fi);
+ }
+ return true;
+}
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+
+////////////////////////////////
+// AltStreams
+
+static Func_FindFirstStreamW g_FindFirstStreamW;
+static Func_FindNextStreamW g_FindNextStreamW;
+
+static struct CFindStreamLoader
+{
+ CFindStreamLoader()
+ {
+ const HMODULE hm = ::GetModuleHandleA("kernel32.dll");
+ g_FindFirstStreamW = Z7_GET_PROC_ADDRESS(
+ Func_FindFirstStreamW, hm,
+ "FindFirstStreamW");
+ g_FindNextStreamW = Z7_GET_PROC_ADDRESS(
+ Func_FindNextStreamW, hm,
+ "FindNextStreamW");
+ }
+} g_FindStreamLoader;
+
+bool CStreamInfo::IsMainStream() const throw()
+{
+ return StringsAreEqualNoCase_Ascii(Name, "::$DATA");
+}
+
+UString CStreamInfo::GetReducedName() const
+{
+ // remove ":$DATA" postfix, but keep postfix, if Name is "::$DATA"
+ UString s (Name);
+ if (s.Len() > 6 + 1 && StringsAreEqualNoCase_Ascii(s.RightPtr(6), ":$DATA"))
+ s.DeleteFrom(s.Len() - 6);
+ return s;
+}
+
+/*
+UString CStreamInfo::GetReducedName2() const
+{
+ UString s = GetReducedName();
+ if (!s.IsEmpty() && s[0] == ':')
+ s.Delete(0);
+ return s;
+}
+*/
+
+static void Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(const MY_WIN32_FIND_STREAM_DATA &sd, CStreamInfo &si)
+{
+ si.Size = (UInt64)sd.StreamSize.QuadPart;
+ si.Name = sd.cStreamName;
+}
+
+/*
+ WinXP-64 FindFirstStream():
+ "" - ERROR_PATH_NOT_FOUND
+ folder\ - OK
+ folder - OK
+ \ - OK
+ c:\ - OK
+ c: - OK, if current dir is ROOT ( c:\ )
+ c: - OK, if current dir is NOT ROOT ( c:\folder )
+ \\Server\Share - OK
+ \\Server\Share\ - OK
+
+ \\ - ERROR_INVALID_NAME
+ \\Server - ERROR_INVALID_NAME
+ \\Server\ - ERROR_INVALID_NAME
+*/
+
+bool CFindStream::FindFirst(CFSTR path, CStreamInfo &si)
+{
+ if (!Close())
+ return false;
+ if (!g_FindFirstStreamW)
+ {
+ ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return false;
+ }
+ {
+ MY_WIN32_FIND_STREAM_DATA sd;
+ SetLastError(0);
+ IF_USE_MAIN_PATH
+ _handle = g_FindFirstStreamW(fs2us(path), My_FindStreamInfoStandard, &sd, 0);
+ if (_handle == INVALID_HANDLE_VALUE)
+ {
+ if (::GetLastError() == ERROR_HANDLE_EOF)
+ return false;
+ // long name can be tricky for path like ".\dirName".
+ #ifdef Z7_LONG_PATH
+ if (USE_SUPER_PATH)
+ {
+ UString superPath;
+ if (GetSuperPath(path, superPath, USE_MAIN_PATH))
+ _handle = g_FindFirstStreamW(superPath, My_FindStreamInfoStandard, &sd, 0);
+ }
+ #endif
+ }
+ if (_handle == INVALID_HANDLE_VALUE)
+ return false;
+ Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(sd, si);
+ }
+ return true;
+}
+
+bool CFindStream::FindNext(CStreamInfo &si)
+{
+ if (!g_FindNextStreamW)
+ {
+ ::SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
+ return false;
+ }
+ {
+ MY_WIN32_FIND_STREAM_DATA sd;
+ if (!g_FindNextStreamW(_handle, &sd))
+ return false;
+ Convert_WIN32_FIND_STREAM_DATA_to_StreamInfo(sd, si);
+ }
+ return true;
+}
+
+bool CStreamEnumerator::Next(CStreamInfo &si, bool &found)
+{
+ bool res;
+ if (_find.IsHandleAllocated())
+ res = _find.FindNext(si);
+ else
+ res = _find.FindFirst(_filePath, si);
+ if (res)
+ {
+ found = true;
+ return true;
+ }
+ found = false;
+ return (::GetLastError() == ERROR_HANDLE_EOF);
+}
+
+#endif
+
+
+/*
+WinXP-64 GetFileAttributes():
+ If the function fails, it returns INVALID_FILE_ATTRIBUTES and use GetLastError() to get error code
+
+ \ - OK
+ C:\ - OK, if there is such drive,
+ D:\ - ERROR_PATH_NOT_FOUND, if there is no such drive,
+
+ C:\folder - OK
+ C:\folder\ - OK
+ C:\folderBad - ERROR_FILE_NOT_FOUND
+
+ \\Server\BadShare - ERROR_BAD_NETPATH
+ \\Server\Share - WORKS OK, but MSDN says:
+ GetFileAttributes for a network share, the function fails, and GetLastError
+ returns ERROR_BAD_NETPATH. You must specify a path to a subfolder on that share.
+*/
+
+DWORD GetFileAttrib(CFSTR path)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ return ::GetFileAttributes(fs2fas(path));
+ else
+ #endif
+ {
+ IF_USE_MAIN_PATH
+ {
+ DWORD dw = ::GetFileAttributesW(fs2us(path));
+ if (dw != INVALID_FILE_ATTRIBUTES)
+ return dw;
+ }
+ #ifdef Z7_LONG_PATH
+ if (USE_SUPER_PATH)
+ {
+ UString superPath;
+ if (GetSuperPath(path, superPath, USE_MAIN_PATH))
+ return ::GetFileAttributesW(superPath);
+ }
+ #endif
+ return INVALID_FILE_ATTRIBUTES;
+ }
+}
+
+/* if path is "c:" or "c::" then CFileInfo::Find() returns name of current folder for that disk
+ so instead of absolute path we have relative path in Name. That is not good in some calls */
+
+/* In CFileInfo::Find() we want to support same names for alt streams as in CreateFile(). */
+
+/* CFileInfo::Find()
+We alow the following paths (as FindFirstFile):
+ C:\folder
+ c: - if current dir is NOT ROOT ( c:\folder )
+
+also we support paths that are not supported by FindFirstFile:
+ \
+ \\.\c:
+ c:\ - Name will be without tail slash ( c: )
+ \\?\c:\ - Name will be without tail slash ( c: )
+ \\Server\Share
+ \\?\UNC\Server\Share
+
+ c:\folder:stream - Name = folder:stream
+ c:\:stream - Name = :stream
+ c::stream - Name = c::stream
+*/
+
+bool CFileInfo::Find(CFSTR path, bool followLink)
+{
+ #ifdef Z7_DEVICE_FILE
+
+ if (IS_PATH_SEPAR(path[0]) &&
+ IS_PATH_SEPAR(path[1]) &&
+ path[2] == '.' &&
+ path[3] == 0)
+ {
+ // 22.00 : it's virtual directory for devices
+ // IsDevice = true;
+ ClearBase();
+ Name = path + 2;
+ Attrib = FILE_ATTRIBUTE_DIRECTORY;
+ return true;
+ }
+
+ if (IsDevicePath(path))
+ {
+ ClearBase();
+ Name = path + 4;
+ IsDevice = true;
+
+ if (NName::IsDrivePath2(path + 4) && path[6] == 0)
+ {
+ FChar drive[4] = { path[4], ':', '\\', 0 };
+ UInt64 clusterSize, totalSize, freeSize;
+ if (NSystem::MyGetDiskFreeSpace(drive, clusterSize, totalSize, freeSize))
+ {
+ Size = totalSize;
+ return true;
+ }
+ }
+
+ NIO::CInFile inFile;
+ // ::OutputDebugStringW(path);
+ if (!inFile.Open(path))
+ return false;
+ // ::OutputDebugStringW(L"---");
+ if (inFile.SizeDefined)
+ Size = inFile.Size;
+ return true;
+ }
+ #endif
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+
+ const int colonPos = FindAltStreamColon(path);
+ if (colonPos >= 0 && path[(unsigned)colonPos + 1] != 0)
+ {
+ UString streamName = fs2us(path + (unsigned)colonPos);
+ FString filePath (path);
+ filePath.DeleteFrom((unsigned)colonPos);
+ /* we allow both cases:
+ name:stream
+ name:stream:$DATA
+ */
+ const unsigned kPostfixSize = 6;
+ if (streamName.Len() <= kPostfixSize
+ || !StringsAreEqualNoCase_Ascii(streamName.RightPtr(kPostfixSize), ":$DATA"))
+ streamName += ":$DATA";
+
+ bool isOk = true;
+
+ if (IsDrivePath2(filePath) &&
+ (colonPos == 2 || (colonPos == 3 && filePath[2] == '\\')))
+ {
+ // FindFirstFile doesn't work for "c:\" and for "c:" (if current dir is ROOT)
+ ClearBase();
+ Name.Empty();
+ if (colonPos == 2)
+ Name = filePath;
+ }
+ else
+ isOk = Find(filePath, followLink); // check it (followLink)
+
+ if (isOk)
+ {
+ Attrib &= ~(DWORD)(FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_REPARSE_POINT);
+ Size = 0;
+ CStreamEnumerator enumerator(filePath);
+ for (;;)
+ {
+ CStreamInfo si;
+ bool found;
+ if (!enumerator.Next(si, found))
+ return false;
+ if (!found)
+ {
+ ::SetLastError(ERROR_FILE_NOT_FOUND);
+ return false;
+ }
+ if (si.Name.IsEqualTo_NoCase(streamName))
+ {
+ // we delete postfix, if alt stream name is not "::$DATA"
+ if (si.Name.Len() > kPostfixSize + 1)
+ si.Name.DeleteFrom(si.Name.Len() - kPostfixSize);
+ Name += us2fs(si.Name);
+ Size = si.Size;
+ IsAltStream = true;
+ return true;
+ }
+ }
+ }
+ }
+
+ #endif
+
+ CFindFile finder;
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ {
+ /*
+ DWORD lastError = GetLastError();
+ if (lastError == ERROR_FILE_NOT_FOUND
+ || lastError == ERROR_BAD_NETPATH // XP64: "\\Server\Share"
+ || lastError == ERROR_BAD_NET_NAME // Win7: "\\Server\Share"
+ || lastError == ERROR_INVALID_NAME // XP64: "\\?\UNC\Server\Share"
+ || lastError == ERROR_BAD_PATHNAME // Win7: "\\?\UNC\Server\Share"
+ )
+ */
+
+ unsigned rootSize = 0;
+ if (IsSuperPath(path))
+ rootSize = kSuperPathPrefixSize;
+
+ if (NName::IsDrivePath(path + rootSize) && path[rootSize + 3] == 0)
+ {
+ DWORD attrib = GetFileAttrib(path);
+ if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ {
+ ClearBase();
+ Attrib = attrib;
+ Name = path + rootSize;
+ Name.DeleteFrom(2);
+ if (!Fill_From_ByHandleFileInfo(path))
+ {
+ }
+ return true;
+ }
+ }
+ else if (IS_PATH_SEPAR(path[0]))
+ {
+ if (path[1] == 0)
+ {
+ DWORD attrib = GetFileAttrib(path);
+ if (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ {
+ ClearBase();
+ Name.Empty();
+ Attrib = attrib;
+ return true;
+ }
+ }
+ else
+ {
+ const unsigned prefixSize = GetNetworkServerPrefixSize(path);
+ if (prefixSize > 0 && path[prefixSize] != 0)
+ {
+ if (NName::FindSepar(path + prefixSize) < 0)
+ {
+ if (Fill_From_ByHandleFileInfo(path))
+ {
+ Name = path + prefixSize;
+ return true;
+ }
+
+ FString s (path);
+ s.Add_PathSepar();
+ s += '*'; // CHAR_ANY_MASK
+ bool isOK = false;
+ if (finder.FindFirst(s, *this))
+ {
+ if (Name == FTEXT("."))
+ {
+ Name = path + prefixSize;
+ return true;
+ }
+ isOK = true;
+ /* if "\\server\share" maps to root folder "d:\", there is no "." item.
+ But it's possible that there are another items */
+ }
+ {
+ DWORD attrib = GetFileAttrib(path);
+ if (isOK || (attrib != INVALID_FILE_ATTRIBUTES && (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0))
+ {
+ ClearBase();
+ if (attrib != INVALID_FILE_ATTRIBUTES)
+ Attrib = attrib;
+ else
+ SetAsDir();
+ Name = path + prefixSize;
+ return true;
+ }
+ }
+ // ::SetLastError(lastError);
+ }
+ }
+ }
+ }
+ }
+ #endif
+
+ bool res = finder.FindFirst(path, *this);
+ if (!followLink
+ || !res
+ || !HasReparsePoint())
+ return res;
+
+ // return FollowReparse(path, IsDir());
+ return Fill_From_ByHandleFileInfo(path);
+}
+
+bool CFileInfoBase::Fill_From_ByHandleFileInfo(CFSTR path)
+{
+ BY_HANDLE_FILE_INFORMATION info;
+ if (!NIO::CFileBase::GetFileInformation(path, &info))
+ return false;
+ {
+ Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
+ CTime = info.ftCreationTime;
+ ATime = info.ftLastAccessTime;
+ MTime = info.ftLastWriteTime;
+ Attrib = info.dwFileAttributes;
+ return true;
+ }
+}
+
+/*
+bool CFileInfo::FollowReparse(CFSTR path, bool isDir)
+{
+ if (isDir)
+ {
+ FString prefix = path;
+ prefix.Add_PathSepar();
+
+ // "folder/." refers to folder itself. So we can't use that path
+ // we must use enumerator and search "." item
+ CEnumerator enumerator;
+ enumerator.SetDirPrefix(prefix);
+ for (;;)
+ {
+ CFileInfo fi;
+ if (!enumerator.NextAny(fi))
+ break;
+ if (fi.Name.IsEqualTo_Ascii_NoCase("."))
+ {
+ // we can copy preperies;
+ CTime = fi.CTime;
+ ATime = fi.ATime;
+ MTime = fi.MTime;
+ Attrib = fi.Attrib;
+ Size = fi.Size;
+ return true;
+ }
+ break;
+ }
+ // LastError(lastError);
+ return false;
+ }
+
+ {
+ NIO::CInFile inFile;
+ if (inFile.Open(path))
+ {
+ BY_HANDLE_FILE_INFORMATION info;
+ if (inFile.GetFileInformation(&info))
+ {
+ ClearBase();
+ Size = (((UInt64)info.nFileSizeHigh) << 32) + info.nFileSizeLow;
+ CTime = info.ftCreationTime;
+ ATime = info.ftLastAccessTime;
+ MTime = info.ftLastWriteTime;
+ Attrib = info.dwFileAttributes;
+ return true;
+ }
+ }
+ return false;
+ }
+}
+*/
+
+bool DoesFileExist_Raw(CFSTR name)
+{
+ CFileInfo fi;
+ return fi.Find(name) && !fi.IsDir();
+}
+
+bool DoesFileExist_FollowLink(CFSTR name)
+{
+ CFileInfo fi;
+ return fi.Find_FollowLink(name) && !fi.IsDir();
+}
+
+bool DoesDirExist(CFSTR name, bool followLink)
+{
+ CFileInfo fi;
+ return fi.Find(name, followLink) && fi.IsDir();
+}
+
+bool DoesFileOrDirExist(CFSTR name)
+{
+ CFileInfo fi;
+ return fi.Find(name);
+}
+
+
+void CEnumerator::SetDirPrefix(const FString &dirPrefix)
+{
+ _wildcard = dirPrefix;
+ _wildcard += '*';
+}
+
+bool CEnumerator::NextAny(CFileInfo &fi)
+{
+ if (_findFile.IsHandleAllocated())
+ return _findFile.FindNext(fi);
+ else
+ return _findFile.FindFirst(_wildcard, fi);
+}
+
+bool CEnumerator::Next(CFileInfo &fi)
+{
+ for (;;)
+ {
+ if (!NextAny(fi))
+ return false;
+ if (!fi.IsDots())
+ return true;
+ }
+}
+
+bool CEnumerator::Next(CFileInfo &fi, bool &found)
+{
+ /*
+ for (;;)
+ {
+ if (!NextAny(fi))
+ break;
+ if (!fi.IsDots())
+ {
+ found = true;
+ return true;
+ }
+ }
+ */
+
+ if (Next(fi))
+ {
+ found = true;
+ return true;
+ }
+
+ found = false;
+ DWORD lastError = ::GetLastError();
+ if (_findFile.IsHandleAllocated())
+ return (lastError == ERROR_NO_MORE_FILES);
+ // we support the case for empty root folder: FindFirstFile("c:\\*") returns ERROR_FILE_NOT_FOUND
+ if (lastError == ERROR_FILE_NOT_FOUND)
+ return true;
+ if (lastError == ERROR_ACCESS_DENIED)
+ {
+ // here we show inaccessible root system folder as empty folder to eliminate redundant user warnings
+ const char *s = "System Volume Information" STRING_PATH_SEPARATOR "*";
+ const int len = (int)strlen(s);
+ const int delta = (int)_wildcard.Len() - len;
+ if (delta == 0 || (delta > 0 && IS_PATH_SEPAR(_wildcard[(unsigned)delta - 1])))
+ if (StringsAreEqual_Ascii(_wildcard.Ptr((unsigned)delta), s))
+ return true;
+ }
+ return false;
+}
+
+
+////////////////////////////////
+// CFindChangeNotification
+// FindFirstChangeNotification can return 0. MSDN doesn't tell about it.
+
+bool CFindChangeNotification::Close() throw()
+{
+ if (!IsHandleAllocated())
+ return true;
+ if (!::FindCloseChangeNotification(_handle))
+ return false;
+ _handle = INVALID_HANDLE_VALUE;
+ return true;
+}
+
+HANDLE CFindChangeNotification::FindFirst(CFSTR path, bool watchSubtree, DWORD notifyFilter)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ _handle = ::FindFirstChangeNotification(fs2fas(path), BoolToBOOL(watchSubtree), notifyFilter);
+ else
+ #endif
+ {
+ IF_USE_MAIN_PATH
+ _handle = ::FindFirstChangeNotificationW(fs2us(path), BoolToBOOL(watchSubtree), notifyFilter);
+ #ifdef Z7_LONG_PATH
+ if (!IsHandleAllocated())
+ {
+ UString superPath;
+ if (GetSuperPath(path, superPath, USE_MAIN_PATH))
+ _handle = ::FindFirstChangeNotificationW(superPath, BoolToBOOL(watchSubtree), notifyFilter);
+ }
+ #endif
+ }
+ return _handle;
+}
+
+#ifndef UNDER_CE
+
+bool MyGetLogicalDriveStrings(CObjectVector<FString> &driveStrings)
+{
+ driveStrings.Clear();
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ driveStrings.Clear();
+ UINT32 size = GetLogicalDriveStrings(0, NULL);
+ if (size == 0)
+ return false;
+ CObjArray<char> buf(size);
+ UINT32 newSize = GetLogicalDriveStrings(size, buf);
+ if (newSize == 0 || newSize > size)
+ return false;
+ AString s;
+ UINT32 prev = 0;
+ for (UINT32 i = 0; i < newSize; i++)
+ {
+ if (buf[i] == 0)
+ {
+ s = buf + prev;
+ prev = i + 1;
+ driveStrings.Add(fas2fs(s));
+ }
+ }
+ return prev == newSize;
+ }
+ else
+ #endif
+ {
+ UINT32 size = GetLogicalDriveStringsW(0, NULL);
+ if (size == 0)
+ return false;
+ CObjArray<wchar_t> buf(size);
+ UINT32 newSize = GetLogicalDriveStringsW(size, buf);
+ if (newSize == 0 || newSize > size)
+ return false;
+ UString s;
+ UINT32 prev = 0;
+ for (UINT32 i = 0; i < newSize; i++)
+ {
+ if (buf[i] == 0)
+ {
+ s = buf + prev;
+ prev = i + 1;
+ driveStrings.Add(us2fs(s));
+ }
+ }
+ return prev == newSize;
+ }
+}
+
+#endif // UNDER_CE
+
+
+
+#else // _WIN32
+
+// ---------- POSIX ----------
+
+static int MY__lstat(CFSTR path, struct stat *st, bool followLink)
+{
+ memset(st, 0, sizeof(*st));
+ int res;
+ // #ifdef ENV_HAVE_LSTAT
+ if (/* global_use_lstat && */ !followLink)
+ {
+ // printf("\nlstat\n");
+ res = lstat(path, st);
+ }
+ else
+ // #endif
+ {
+ // printf("\nstat\n");
+ res = stat(path, st);
+ }
+ /*
+ printf("\nres = %d\n", res);
+ printf("\n st_dev = %lld \n", (long long)(st->st_dev));
+ printf("\n st_ino = %lld \n", (long long)(st->st_ino));
+ printf("\n st_mode = %lld \n", (long long)(st->st_mode));
+ printf("\n st_nlink = %lld \n", (long long)(st->st_nlink));
+ printf("\n st_uid = %lld \n", (long long)(st->st_uid));
+ printf("\n st_gid = %lld \n", (long long)(st->st_gid));
+ printf("\n st_size = %lld \n", (long long)(st->st_size));
+ printf("\n st_blksize = %lld \n", (long long)(st->st_blksize));
+ printf("\n st_blocks = %lld \n", (long long)(st->st_blocks));
+ */
+
+ return res;
+}
+
+
+static const char *Get_Name_from_Path(CFSTR path) throw()
+{
+ size_t len = strlen(path);
+ if (len == 0)
+ return path;
+ const char *p = path + len - 1;
+ {
+ if (p == path)
+ return path;
+ p--;
+ }
+ for (;;)
+ {
+ char c = *p;
+ if (IS_PATH_SEPAR(c))
+ return p + 1;
+ if (p == path)
+ return path;
+ p--;
+ }
+}
+
+
+UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode)
+{
+ UInt32 attrib = S_ISDIR(mode) ?
+ FILE_ATTRIBUTE_DIRECTORY :
+ FILE_ATTRIBUTE_ARCHIVE;
+ if ((mode & 0222) == 0) // S_IWUSR in p7zip
+ attrib |= FILE_ATTRIBUTE_READONLY;
+ return attrib | FILE_ATTRIBUTE_UNIX_EXTENSION | ((mode & 0xFFFF) << 16);
+}
+
+/*
+UInt32 Get_WinAttrib_From_stat(const struct stat &st)
+{
+ UInt32 attrib = S_ISDIR(st.st_mode) ?
+ FILE_ATTRIBUTE_DIRECTORY :
+ FILE_ATTRIBUTE_ARCHIVE;
+
+ if ((st.st_mode & 0222) == 0) // check it !!!
+ attrib |= FILE_ATTRIBUTE_READONLY;
+
+ attrib |= FILE_ATTRIBUTE_UNIX_EXTENSION + ((st.st_mode & 0xFFFF) << 16);
+ return attrib;
+}
+*/
+
+void CFileInfo::SetFrom_stat(const struct stat &st)
+{
+ // IsDevice = false;
+
+ if (S_ISDIR(st.st_mode))
+ {
+ Size = 0;
+ }
+ else
+ {
+ Size = (UInt64)st.st_size; // for a symbolic link, size = size of filename
+ }
+
+ // Attrib = Get_WinAttribPosix_From_PosixMode(st.st_mode);
+
+ // NTime::UnixTimeToFileTime(st.st_ctime, CTime);
+ // NTime::UnixTimeToFileTime(st.st_mtime, MTime);
+ // NTime::UnixTimeToFileTime(st.st_atime, ATime);
+ #ifdef __APPLE__
+ // #ifdef _DARWIN_FEATURE_64_BIT_INODE
+ /*
+ here we can use birthtime instead of st_ctimespec.
+ but we use st_ctimespec for compatibility with previous versions and p7zip.
+ st_birthtimespec in OSX
+ st_birthtim : at FreeBSD, NetBSD
+ */
+ // timespec_To_FILETIME(st.st_birthtimespec, CTime);
+ // #else
+ // timespec_To_FILETIME(st.st_ctimespec, CTime);
+ // #endif
+ // timespec_To_FILETIME(st.st_mtimespec, MTime);
+ // timespec_To_FILETIME(st.st_atimespec, ATime);
+ CTime = st.st_ctimespec;
+ MTime = st.st_mtimespec;
+ ATime = st.st_atimespec;
+
+ #else
+ // timespec_To_FILETIME(st.st_ctim, CTime, &CTime_ns100);
+ // timespec_To_FILETIME(st.st_mtim, MTime, &MTime_ns100);
+ // timespec_To_FILETIME(st.st_atim, ATime, &ATime_ns100);
+ CTime = st.st_ctim;
+ MTime = st.st_mtim;
+ ATime = st.st_atim;
+
+ #endif
+
+ dev = st.st_dev;
+ ino = st.st_ino;
+ mode = st.st_mode;
+ nlink = st.st_nlink;
+ uid = st.st_uid;
+ gid = st.st_gid;
+ rdev = st.st_rdev;
+
+ /*
+ printf("\n sizeof timespec = %d", (int)sizeof(timespec));
+ printf("\n sizeof st_rdev = %d", (int)sizeof(rdev));
+ printf("\n sizeof st_ino = %d", (int)sizeof(ino));
+ printf("\n sizeof mode_t = %d", (int)sizeof(mode_t));
+ printf("\n sizeof nlink_t = %d", (int)sizeof(nlink_t));
+ printf("\n sizeof uid_t = %d", (int)sizeof(uid_t));
+ printf("\n");
+ */
+ /*
+ printf("\n st_rdev = %llx", (long long)rdev);
+ printf("\n st_dev = %llx", (long long)dev);
+ printf("\n dev : major = %5x minor = %5x", (unsigned)major(dev), (unsigned)minor(dev));
+ printf("\n st_ino = %lld", (long long)(ino));
+ printf("\n rdev : major = %5x minor = %5x", (unsigned)major(rdev), (unsigned)minor(rdev));
+ printf("\n size = %lld \n", (long long)(Size));
+ printf("\n");
+ */
+}
+
+/*
+int Uid_To_Uname(uid_t uid, AString &name)
+{
+ name.Empty();
+ struct passwd *passwd;
+
+ if (uid != 0 && uid == cached_no_such_uid)
+ {
+ *uname = xstrdup ("");
+ return;
+ }
+
+ if (!cached_uname || uid != cached_uid)
+ {
+ passwd = getpwuid (uid);
+ if (passwd)
+ {
+ cached_uid = uid;
+ assign_string (&cached_uname, passwd->pw_name);
+ }
+ else
+ {
+ cached_no_such_uid = uid;
+ *uname = xstrdup ("");
+ return;
+ }
+ }
+ *uname = xstrdup (cached_uname);
+}
+*/
+
+bool CFileInfo::Find_DontFill_Name(CFSTR path, bool followLink)
+{
+ struct stat st;
+ if (MY__lstat(path, &st, followLink) != 0)
+ return false;
+ // printf("\nFind_DontFill_Name : name=%s\n", path);
+ SetFrom_stat(st);
+ return true;
+}
+
+
+bool CFileInfo::Find(CFSTR path, bool followLink)
+{
+ // printf("\nCEnumerator::Find() name = %s\n", path);
+ if (!Find_DontFill_Name(path, followLink))
+ return false;
+
+ // printf("\nOK\n");
+
+ Name = Get_Name_from_Path(path);
+ if (!Name.IsEmpty())
+ {
+ char c = Name.Back();
+ if (IS_PATH_SEPAR(c))
+ Name.DeleteBack();
+ }
+ return true;
+}
+
+
+bool DoesFileExist_Raw(CFSTR name)
+{
+ // FIXME for symbolic links.
+ struct stat st;
+ if (MY__lstat(name, &st, false) != 0)
+ return false;
+ return !S_ISDIR(st.st_mode);
+}
+
+bool DoesFileExist_FollowLink(CFSTR name)
+{
+ // FIXME for symbolic links.
+ struct stat st;
+ if (MY__lstat(name, &st, true) != 0)
+ return false;
+ return !S_ISDIR(st.st_mode);
+}
+
+bool DoesDirExist(CFSTR name, bool followLink)
+{
+ struct stat st;
+ if (MY__lstat(name, &st, followLink) != 0)
+ return false;
+ return S_ISDIR(st.st_mode);
+}
+
+bool DoesFileOrDirExist(CFSTR name)
+{
+ struct stat st;
+ if (MY__lstat(name, &st, false) != 0)
+ return false;
+ return true;
+}
+
+
+CEnumerator::~CEnumerator()
+{
+ if (_dir)
+ closedir(_dir);
+}
+
+void CEnumerator::SetDirPrefix(const FString &dirPrefix)
+{
+ _wildcard = dirPrefix;
+}
+
+bool CDirEntry::IsDots() const throw()
+{
+ /* some systems (like CentOS 7.x on XFS) have (Type == DT_UNKNOWN)
+ we can call fstatat() for that case, but we use only (Name) check here */
+
+ #if !defined(_AIX)
+ if (Type != DT_DIR && Type != DT_UNKNOWN)
+ return false;
+ #endif
+
+ return Name.Len() != 0
+ && Name.Len() <= 2
+ && Name[0] == '.'
+ && (Name.Len() == 1 || Name[1] == '.');
+}
+
+
+bool CEnumerator::NextAny(CDirEntry &fi, bool &found)
+{
+ found = false;
+
+ if (!_dir)
+ {
+ const char *w = "./";
+ if (!_wildcard.IsEmpty())
+ w = _wildcard.Ptr();
+ _dir = ::opendir((const char *)w);
+ if (_dir == NULL)
+ return false;
+ }
+
+ // To distinguish end of stream from an error, we must set errno to zero before readdir()
+ errno = 0;
+
+ struct dirent *de = readdir(_dir);
+ if (!de)
+ {
+ if (errno == 0)
+ return true; // it's end of stream, and we report it with (found = false)
+ // it's real error
+ return false;
+ }
+
+ fi.iNode = de->d_ino;
+
+ #if !defined(_AIX)
+ fi.Type = de->d_type;
+ /* some systems (like CentOS 7.x on XFS) have (Type == DT_UNKNOWN)
+ we can set (Type) from fstatat() in that case.
+ But (Type) is not too important. So we don't set it here with slow fstatat() */
+ /*
+ // fi.Type = DT_UNKNOWN; // for debug
+ if (fi.Type == DT_UNKNOWN)
+ {
+ struct stat st;
+ if (fstatat(dirfd(_dir), de->d_name, &st, AT_SYMLINK_NOFOLLOW) == 0)
+ if (S_ISDIR(st.st_mode))
+ fi.Type = DT_DIR;
+ }
+ */
+ #endif
+
+ /*
+ if (de->d_type == DT_DIR)
+ fi.Attrib = FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_UNIX_EXTENSION | ((UInt32)(S_IFDIR) << 16);
+ else if (de->d_type < 16)
+ fi.Attrib = FILE_ATTRIBUTE_UNIX_EXTENSION | ((UInt32)(de->d_type) << (16 + 12));
+ */
+ fi.Name = de->d_name;
+
+ /*
+ printf("\nCEnumerator::NextAny; len = %d %s \n", (int)fi.Name.Len(), fi.Name.Ptr());
+ for (unsigned i = 0; i < fi.Name.Len(); i++)
+ printf (" %02x", (unsigned)(Byte)de->d_name[i]);
+ printf("\n");
+ */
+
+ found = true;
+ return true;
+}
+
+
+bool CEnumerator::Next(CDirEntry &fi, bool &found)
+{
+ // printf("\nCEnumerator::Next()\n");
+ // PrintName("Next", "");
+ for (;;)
+ {
+ if (!NextAny(fi, found))
+ return false;
+ if (!found)
+ return true;
+ if (!fi.IsDots())
+ {
+ /*
+ if (!NeedFullStat)
+ return true;
+ // we silently skip error file here - it can be wrong link item
+ if (fi.Find_DontFill_Name(path))
+ return true;
+ */
+ return true;
+ }
+ }
+}
+
+/*
+bool CEnumerator::Next(CDirEntry &fileInfo, bool &found)
+{
+ bool found;
+ if (!Next(fi, found))
+ return false;
+ return found;
+}
+*/
+
+bool CEnumerator::Fill_FileInfo(const CDirEntry &de, CFileInfo &fileInfo, bool followLink) const
+{
+ // printf("\nCEnumerator::Fill_FileInfo()\n");
+ struct stat st;
+ // probably it's OK to use fstatat() even if it changes file position dirfd(_dir)
+ int res = fstatat(dirfd(_dir), de.Name, &st, followLink ? 0 : AT_SYMLINK_NOFOLLOW);
+ // if fstatat() is not supported, we can use stat() / lstat()
+
+ /*
+ const FString path = _wildcard + s;
+ int res = MY__lstat(path, &st, followLink);
+ */
+
+ if (res != 0)
+ return false;
+ // printf("\nname=%s\n", de.Name.Ptr());
+ fileInfo.SetFrom_stat(st);
+ fileInfo.Name = de.Name;
+ return true;
+}
+
+#endif // _WIN32
+
+}}}
diff --git a/CPP/Windows/FileFind.h b/CPP/Windows/FileFind.h
index 77d8dc3..11408d0 100644
--- a/CPP/Windows/FileFind.h
+++ b/CPP/Windows/FileFind.h
@@ -1,161 +1,348 @@
-// Windows/FileFind.h
-
-#ifndef __WINDOWS_FILE_FIND_H
-#define __WINDOWS_FILE_FIND_H
-
-#include "../Common/MyString.h"
-#include "Defs.h"
-
-namespace NWindows {
-namespace NFile {
-namespace NFind {
-
-namespace NAttributes
-{
- inline bool IsReadOnly(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_READONLY) != 0; }
- inline bool IsHidden(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_HIDDEN) != 0; }
- inline bool IsSystem(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_SYSTEM) != 0; }
- inline bool IsDir(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; }
- inline bool IsArchived(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ARCHIVE) != 0; }
- inline bool IsCompressed(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_COMPRESSED) != 0; }
- inline bool IsEncrypted(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ENCRYPTED) != 0; }
-}
-
-class CFileInfoBase
-{
- bool MatchesMask(UINT32 mask) const { return ((Attrib & mask) != 0); }
-public:
- UInt64 Size;
- FILETIME CTime;
- FILETIME ATime;
- FILETIME MTime;
- DWORD Attrib;
- bool IsAltStream;
- bool IsDevice;
-
- /*
- #ifdef UNDER_CE
- DWORD ObjectID;
- #else
- UINT32 ReparseTag;
- #endif
- */
-
- CFileInfoBase() { ClearBase(); }
- void ClearBase() throw();
-
- void SetAsDir() { Attrib = FILE_ATTRIBUTE_DIRECTORY; }
-
- bool IsArchived() const { return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); }
- bool IsCompressed() const { return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); }
- bool IsDir() const { return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); }
- bool IsEncrypted() const { return MatchesMask(FILE_ATTRIBUTE_ENCRYPTED); }
- bool IsHidden() const { return MatchesMask(FILE_ATTRIBUTE_HIDDEN); }
- bool IsNormal() const { return MatchesMask(FILE_ATTRIBUTE_NORMAL); }
- bool IsOffline() const { return MatchesMask(FILE_ATTRIBUTE_OFFLINE); }
- bool IsReadOnly() const { return MatchesMask(FILE_ATTRIBUTE_READONLY); }
- bool HasReparsePoint() const { return MatchesMask(FILE_ATTRIBUTE_REPARSE_POINT); }
- bool IsSparse() const { return MatchesMask(FILE_ATTRIBUTE_SPARSE_FILE); }
- bool IsSystem() const { return MatchesMask(FILE_ATTRIBUTE_SYSTEM); }
- bool IsTemporary() const { return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); }
-};
-
-struct CFileInfo: public CFileInfoBase
-{
- FString Name;
- #if defined(_WIN32) && !defined(UNDER_CE)
- // FString ShortName;
- #endif
-
- bool IsDots() const throw();
- bool Find(CFSTR path);
-};
-
-class CFindFileBase
-{
-protected:
- HANDLE _handle;
-public:
- bool IsHandleAllocated() const { return _handle != INVALID_HANDLE_VALUE; }
- CFindFileBase(): _handle(INVALID_HANDLE_VALUE) {}
- ~CFindFileBase() { Close(); }
- bool Close() throw();
-};
-
-class CFindFile: public CFindFileBase
-{
-public:
- bool FindFirst(CFSTR wildcard, CFileInfo &fileInfo);
- bool FindNext(CFileInfo &fileInfo);
-};
-
-#if defined(_WIN32) && !defined(UNDER_CE)
-
-struct CStreamInfo
-{
- UString Name;
- UInt64 Size;
-
- UString GetReducedName() const; // returns ":Name"
- // UString GetReducedName2() const; // returns "Name"
- bool IsMainStream() const throw();
-};
-
-class CFindStream: public CFindFileBase
-{
-public:
- bool FindFirst(CFSTR filePath, CStreamInfo &streamInfo);
- bool FindNext(CStreamInfo &streamInfo);
-};
-
-class CStreamEnumerator
-{
- CFindStream _find;
- FString _filePath;
-
- bool NextAny(CFileInfo &fileInfo);
-public:
- CStreamEnumerator(const FString &filePath): _filePath(filePath) {}
- bool Next(CStreamInfo &streamInfo, bool &found);
-};
-
-#endif
-
-bool DoesFileExist(CFSTR name);
-bool DoesDirExist(CFSTR name);
-bool DoesFileOrDirExist(CFSTR name);
-
-DWORD GetFileAttrib(CFSTR path);
-
-class CEnumerator
-{
- CFindFile _findFile;
- FString _wildcard;
-
- bool NextAny(CFileInfo &fileInfo);
-public:
- void SetDirPrefix(const FString &dirPrefix);
- bool Next(CFileInfo &fileInfo);
- bool Next(CFileInfo &fileInfo, bool &found);
-};
-
-class CFindChangeNotification
-{
- HANDLE _handle;
-public:
- operator HANDLE () { return _handle; }
- bool IsHandleAllocated() const { return _handle != INVALID_HANDLE_VALUE && _handle != 0; }
- CFindChangeNotification(): _handle(INVALID_HANDLE_VALUE) {}
- ~CFindChangeNotification() { Close(); }
- bool Close() throw();
- HANDLE FindFirst(CFSTR pathName, bool watchSubtree, DWORD notifyFilter);
- bool FindNext() { return BOOLToBool(::FindNextChangeNotification(_handle)); }
-};
-
-#ifndef UNDER_CE
-bool MyGetLogicalDriveStrings(CObjectVector<FString> &driveStrings);
-#endif
-
-}}}
-
-#endif
+// Windows/FileFind.h
+
+#ifndef ZIP7_INC_WINDOWS_FILE_FIND_H
+#define ZIP7_INC_WINDOWS_FILE_FIND_H
+
+#ifndef _WIN32
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <dirent.h>
+#endif
+
+#include "../Common/MyLinux.h"
+#include "../Common/MyString.h"
+#include "../Common/MyWindows.h"
+
+#include "Defs.h"
+
+#include "FileIO.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NFind {
+
+// bool DoesFileExist(CFSTR name, bool followLink);
+bool DoesFileExist_Raw(CFSTR name);
+bool DoesFileExist_FollowLink(CFSTR name);
+bool DoesDirExist(CFSTR name, bool followLink);
+
+inline bool DoesDirExist(CFSTR name)
+ { return DoesDirExist(name, false); }
+inline bool DoesDirExist_FollowLink(CFSTR name)
+ { return DoesDirExist(name, true); }
+
+// it's always _Raw
+bool DoesFileOrDirExist(CFSTR name);
+
+DWORD GetFileAttrib(CFSTR path);
+
+#ifdef _WIN32
+
+namespace NAttributes
+{
+ inline bool IsReadOnly(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_READONLY) != 0; }
+ inline bool IsHidden(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_HIDDEN) != 0; }
+ inline bool IsSystem(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_SYSTEM) != 0; }
+ inline bool IsDir(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_DIRECTORY) != 0; }
+ inline bool IsArchived(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ARCHIVE) != 0; }
+ inline bool IsCompressed(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_COMPRESSED) != 0; }
+ inline bool IsEncrypted(DWORD attrib) { return (attrib & FILE_ATTRIBUTE_ENCRYPTED) != 0; }
+
+ inline UInt32 Get_PosixMode_From_WinAttrib(DWORD attrib)
+ {
+ UInt32 v = IsDir(attrib) ? MY_LIN_S_IFDIR : MY_LIN_S_IFREG;
+ /* 21.06: as WSL we allow write permissions (0222) for directories even for (FILE_ATTRIBUTE_READONLY).
+ So extracting at Linux will be allowed to write files inside (0777) directories. */
+ v |= ((IsReadOnly(attrib) && !IsDir(attrib)) ? 0555 : 0777);
+ return v;
+ }
+}
+
+#else
+
+UInt32 Get_WinAttribPosix_From_PosixMode(UInt32 mode);
+
+#endif
+
+class CFileInfoBase
+{
+ #ifdef _WIN32
+ bool MatchesMask(UINT32 mask) const { return ((Attrib & mask) != 0); }
+ #endif
+public:
+ UInt64 Size;
+ CFiTime CTime;
+ CFiTime ATime;
+ CFiTime MTime;
+ #ifdef _WIN32
+ DWORD Attrib;
+ bool IsAltStream;
+ bool IsDevice;
+
+ /*
+ #ifdef UNDER_CE
+ DWORD ObjectID;
+ #else
+ UINT32 ReparseTag;
+ #endif
+ */
+ #else
+ dev_t dev; /* ID of device containing file */
+ ino_t ino;
+ mode_t mode;
+ nlink_t nlink;
+ uid_t uid; /* user ID of owner */
+ gid_t gid; /* group ID of owner */
+ dev_t rdev; /* device ID (defined, if S_ISCHR(mode) || S_ISBLK(mode)) */
+ // bool Use_lstat;
+ #endif
+
+ CFileInfoBase() { ClearBase(); }
+ void ClearBase() throw();
+
+ #ifdef _WIN32
+
+ bool Fill_From_ByHandleFileInfo(CFSTR path);
+ void SetAsDir() { Attrib = FILE_ATTRIBUTE_DIRECTORY; } // |= (FILE_ATTRIBUTE_UNIX_EXTENSION + (S_IFDIR << 16));
+ void SetAsFile() { Attrib = 0; }
+
+ bool IsArchived() const { return MatchesMask(FILE_ATTRIBUTE_ARCHIVE); }
+ bool IsCompressed() const { return MatchesMask(FILE_ATTRIBUTE_COMPRESSED); }
+ bool IsDir() const { return MatchesMask(FILE_ATTRIBUTE_DIRECTORY); }
+ bool IsEncrypted() const { return MatchesMask(FILE_ATTRIBUTE_ENCRYPTED); }
+ bool IsHidden() const { return MatchesMask(FILE_ATTRIBUTE_HIDDEN); }
+ bool IsNormal() const { return MatchesMask(FILE_ATTRIBUTE_NORMAL); }
+ bool IsOffline() const { return MatchesMask(FILE_ATTRIBUTE_OFFLINE); }
+ bool IsReadOnly() const { return MatchesMask(FILE_ATTRIBUTE_READONLY); }
+ bool HasReparsePoint() const { return MatchesMask(FILE_ATTRIBUTE_REPARSE_POINT); }
+ bool IsSparse() const { return MatchesMask(FILE_ATTRIBUTE_SPARSE_FILE); }
+ bool IsSystem() const { return MatchesMask(FILE_ATTRIBUTE_SYSTEM); }
+ bool IsTemporary() const { return MatchesMask(FILE_ATTRIBUTE_TEMPORARY); }
+
+ UInt32 GetWinAttrib() const { return Attrib; }
+ UInt32 GetPosixAttrib() const
+ {
+ return NAttributes::Get_PosixMode_From_WinAttrib(Attrib);
+ }
+ bool Has_Attrib_ReparsePoint() const { return (Attrib & FILE_ATTRIBUTE_REPARSE_POINT) != 0; }
+
+ #else
+
+ UInt32 GetPosixAttrib() const { return mode; }
+ UInt32 GetWinAttrib() const { return Get_WinAttribPosix_From_PosixMode(mode); }
+
+ bool IsDir() const { return S_ISDIR(mode); }
+ void SetAsDir() { mode = S_IFDIR; }
+ void SetAsFile() { mode = S_IFREG; }
+
+ bool IsReadOnly() const
+ {
+ // does linux support writing to ReadOnly files?
+ if ((mode & 0222) == 0) // S_IWUSR in p7zip
+ return true;
+ return false;
+ }
+
+ bool IsPosixLink() const { return S_ISLNK(mode); }
+
+ #endif
+
+ bool IsOsSymLink() const
+ {
+ #ifdef _WIN32
+ return HasReparsePoint();
+ #else
+ return IsPosixLink();
+ #endif
+ }
+};
+
+struct CFileInfo: public CFileInfoBase
+{
+ FString Name;
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ // FString ShortName;
+ #endif
+
+ bool IsDots() const throw();
+ bool Find(CFSTR path, bool followLink = false);
+ bool Find_FollowLink(CFSTR path) { return Find(path, true); }
+
+ #ifdef _WIN32
+ // bool Fill_From_ByHandleFileInfo(CFSTR path);
+ // bool FollowReparse(CFSTR path, bool isDir);
+ #else
+ bool Find_DontFill_Name(CFSTR path, bool followLink = false);
+ void SetFrom_stat(const struct stat &st);
+ #endif
+};
+
+
+#ifdef _WIN32
+
+class CFindFileBase MY_UNCOPYABLE
+{
+protected:
+ HANDLE _handle;
+public:
+ bool IsHandleAllocated() const { return _handle != INVALID_HANDLE_VALUE; }
+ CFindFileBase(): _handle(INVALID_HANDLE_VALUE) {}
+ ~CFindFileBase() { Close(); }
+ bool Close() throw();
+};
+
+class CFindFile: public CFindFileBase
+{
+public:
+ bool FindFirst(CFSTR wildcard, CFileInfo &fileInfo);
+ bool FindNext(CFileInfo &fileInfo);
+};
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+
+struct CStreamInfo
+{
+ UString Name;
+ UInt64 Size;
+
+ UString GetReducedName() const; // returns ":Name"
+ // UString GetReducedName2() const; // returns "Name"
+ bool IsMainStream() const throw();
+};
+
+class CFindStream: public CFindFileBase
+{
+public:
+ bool FindFirst(CFSTR filePath, CStreamInfo &streamInfo);
+ bool FindNext(CStreamInfo &streamInfo);
+};
+
+class CStreamEnumerator MY_UNCOPYABLE
+{
+ CFindStream _find;
+ FString _filePath;
+
+ bool NextAny(CFileInfo &fileInfo, bool &found);
+public:
+ CStreamEnumerator(const FString &filePath): _filePath(filePath) {}
+ bool Next(CStreamInfo &streamInfo, bool &found);
+};
+
+#endif // defined(_WIN32) && !defined(UNDER_CE)
+
+
+class CEnumerator MY_UNCOPYABLE
+{
+ CFindFile _findFile;
+ FString _wildcard;
+
+ bool NextAny(CFileInfo &fileInfo);
+public:
+ void SetDirPrefix(const FString &dirPrefix);
+ bool Next(CFileInfo &fileInfo);
+ bool Next(CFileInfo &fileInfo, bool &found);
+};
+
+
+class CFindChangeNotification MY_UNCOPYABLE
+{
+ HANDLE _handle;
+public:
+ operator HANDLE () { return _handle; }
+ bool IsHandleAllocated() const
+ {
+ /* at least on win2000/XP (undocumented):
+ if pathName is "" or NULL,
+ FindFirstChangeNotification() could return NULL.
+ So we check for INVALID_HANDLE_VALUE and NULL.
+ */
+ return _handle != INVALID_HANDLE_VALUE && _handle != NULL;
+ }
+ CFindChangeNotification(): _handle(INVALID_HANDLE_VALUE) {}
+ ~CFindChangeNotification() { Close(); }
+ bool Close() throw();
+ HANDLE FindFirst(CFSTR pathName, bool watchSubtree, DWORD notifyFilter);
+ bool FindNext() { return BOOLToBool(::FindNextChangeNotification(_handle)); }
+};
+
+#ifndef UNDER_CE
+bool MyGetLogicalDriveStrings(CObjectVector<FString> &driveStrings);
+#endif
+
+typedef CFileInfo CDirEntry;
+
+
+#else // WIN32
+
+
+struct CDirEntry
+{
+ ino_t iNode;
+ #if !defined(_AIX)
+ Byte Type;
+ #endif
+ FString Name;
+
+ /*
+ #if !defined(_AIX)
+ bool IsDir() const
+ {
+ // (Type == DT_UNKNOWN) on some systems
+ return Type == DT_DIR;
+ }
+ #endif
+ */
+
+ bool IsDots() const throw();
+};
+
+class CEnumerator MY_UNCOPYABLE
+{
+ DIR *_dir;
+ FString _wildcard;
+
+ bool NextAny(CDirEntry &fileInfo, bool &found);
+public:
+ CEnumerator(): _dir(NULL) {}
+ ~CEnumerator();
+ void SetDirPrefix(const FString &dirPrefix);
+
+ bool Next(CDirEntry &fileInfo, bool &found);
+ bool Fill_FileInfo(const CDirEntry &de, CFileInfo &fileInfo, bool followLink) const;
+ bool DirEntry_IsDir(const CDirEntry &de, bool followLink) const
+ {
+ #if !defined(_AIX)
+ if (de.Type == DT_DIR)
+ return true;
+ if (de.Type != DT_UNKNOWN)
+ return false;
+ #endif
+ CFileInfo fileInfo;
+ if (Fill_FileInfo(de, fileInfo, followLink))
+ {
+ return fileInfo.IsDir();
+ }
+ return false; // change it
+ }
+};
+
+/*
+inline UInt32 Get_WinAttrib_From_PosixMode(UInt32 mode)
+{
+ UInt32 attrib = S_ISDIR(mode) ?
+ FILE_ATTRIBUTE_DIRECTORY :
+ FILE_ATTRIBUTE_ARCHIVE;
+ if ((st.st_mode & 0222) == 0) // check it !!!
+ attrib |= FILE_ATTRIBUTE_READONLY;
+ return attrib;
+}
+*/
+
+// UInt32 Get_WinAttrib_From_stat(const struct stat &st);
+
+
+#endif // WIN32
+
+}}}
+
+#endif
diff --git a/CPP/Windows/FileIO.cpp b/CPP/Windows/FileIO.cpp
index a1d52c0..4ecbb7e 100644
--- a/CPP/Windows/FileIO.cpp
+++ b/CPP/Windows/FileIO.cpp
@@ -1,432 +1,905 @@
-// Windows/FileIO.cpp
-
-#include "StdAfx.h"
-
-#ifdef SUPPORT_DEVICE_FILE
-#include "../../C/Alloc.h"
-#endif
-
-#include "FileIO.h"
-#include "FileName.h"
-
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-using namespace NWindows;
-using namespace NFile;
-using namespace NName;
-
-namespace NWindows {
-namespace NFile {
-
-#ifdef SUPPORT_DEVICE_FILE
-
-namespace NSystem
-{
-bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
-}
-#endif
-
-namespace NIO {
-
-/*
-WinXP-64 CreateFile():
- "" - ERROR_PATH_NOT_FOUND
- :stream - OK
- .:stream - ERROR_PATH_NOT_FOUND
- .\:stream - OK
-
- folder\:stream - ERROR_INVALID_NAME
- folder:stream - OK
-
- c:\:stream - OK
-
- c::stream - ERROR_INVALID_NAME, if current dir is NOT ROOT ( c:\dir1 )
- c::stream - OK, if current dir is ROOT ( c:\ )
-*/
-
-bool CFileBase::Create(CFSTR path, DWORD desiredAccess,
- DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
-{
- if (!Close())
- return false;
-
- #ifdef SUPPORT_DEVICE_FILE
- IsDeviceFile = false;
- #endif
-
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- _handle = ::CreateFile(fs2fas(path), desiredAccess, shareMode,
- (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL);
- }
- else
- #endif
- {
- IF_USE_MAIN_PATH
- _handle = ::CreateFileW(fs2us(path), desiredAccess, shareMode,
- (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL);
- #ifdef WIN_LONG_PATH
- if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH)
- {
- UString superPath;
- if (GetSuperPath(path, superPath, USE_MAIN_PATH))
- _handle = ::CreateFileW(superPath, desiredAccess, shareMode,
- (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL);
- }
- #endif
- }
- return (_handle != INVALID_HANDLE_VALUE);
-}
-
-bool CFileBase::Close() throw()
-{
- if (_handle == INVALID_HANDLE_VALUE)
- return true;
- if (!::CloseHandle(_handle))
- return false;
- _handle = INVALID_HANDLE_VALUE;
- return true;
-}
-
-bool CFileBase::GetPosition(UInt64 &position) const throw()
-{
- return Seek(0, FILE_CURRENT, position);
-}
-
-bool CFileBase::GetLength(UInt64 &length) const throw()
-{
- #ifdef SUPPORT_DEVICE_FILE
- if (IsDeviceFile && SizeDefined)
- {
- length = Size;
- return true;
- }
- #endif
-
- DWORD sizeHigh;
- DWORD sizeLow = ::GetFileSize(_handle, &sizeHigh);
- if (sizeLow == 0xFFFFFFFF)
- if (::GetLastError() != NO_ERROR)
- return false;
- length = (((UInt64)sizeHigh) << 32) + sizeLow;
- return true;
-}
-
-bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw()
-{
- #ifdef SUPPORT_DEVICE_FILE
- if (IsDeviceFile && SizeDefined && moveMethod == FILE_END)
- {
- distanceToMove += Size;
- moveMethod = FILE_BEGIN;
- }
- #endif
-
- LONG high = (LONG)(distanceToMove >> 32);
- DWORD low = ::SetFilePointer(_handle, (LONG)(distanceToMove & 0xFFFFFFFF), &high, moveMethod);
- if (low == 0xFFFFFFFF)
- if (::GetLastError() != NO_ERROR)
- return false;
- newPosition = (((UInt64)(UInt32)high) << 32) + low;
- return true;
-}
-
-bool CFileBase::Seek(UInt64 position, UInt64 &newPosition) const throw()
-{
- return Seek(position, FILE_BEGIN, newPosition);
-}
-
-bool CFileBase::SeekToBegin() const throw()
-{
- UInt64 newPosition;
- return Seek(0, newPosition);
-}
-
-bool CFileBase::SeekToEnd(UInt64 &newPosition) const throw()
-{
- return Seek(0, FILE_END, newPosition);
-}
-
-// ---------- CInFile ---------
-
-#ifdef SUPPORT_DEVICE_FILE
-
-void CInFile::CorrectDeviceSize()
-{
- // maybe we must decrease kClusterSize to 1 << 12, if we want correct size at tail
- static const UInt32 kClusterSize = 1 << 14;
- UInt64 pos = Size & ~(UInt64)(kClusterSize - 1);
- UInt64 realNewPosition;
- if (!Seek(pos, realNewPosition))
- return;
- Byte *buf = (Byte *)MidAlloc(kClusterSize);
-
- bool needbackward = true;
-
- for (;;)
- {
- UInt32 processed = 0;
- // up test is slow for "PhysicalDrive".
- // processed size for latest block for "PhysicalDrive0" is 0.
- if (!Read1(buf, kClusterSize, processed))
- break;
- if (processed == 0)
- break;
- needbackward = false;
- Size = pos + processed;
- if (processed != kClusterSize)
- break;
- pos += kClusterSize;
- }
-
- if (needbackward && pos != 0)
- {
- pos -= kClusterSize;
- for (;;)
- {
- // break;
- if (!Seek(pos, realNewPosition))
- break;
- if (!buf)
- {
- buf = (Byte *)MidAlloc(kClusterSize);
- if (!buf)
- break;
- }
- UInt32 processed = 0;
- // that code doesn't work for "PhysicalDrive0"
- if (!Read1(buf, kClusterSize, processed))
- break;
- if (processed != 0)
- {
- Size = pos + processed;
- break;
- }
- if (pos == 0)
- break;
- pos -= kClusterSize;
- }
- }
- MidFree(buf);
-}
-
-
-void CInFile::CalcDeviceSize(CFSTR s)
-{
- SizeDefined = false;
- Size = 0;
- if (_handle == INVALID_HANDLE_VALUE || !IsDeviceFile)
- return;
- #ifdef UNDER_CE
-
- SizeDefined = true;
- Size = 128 << 20;
-
- #else
-
- PARTITION_INFORMATION partInfo;
- bool needCorrectSize = true;
-
- /*
- WinXP 64-bit:
-
- HDD \\.\PhysicalDrive0 (MBR):
- GetPartitionInfo == GeometryEx : corrrect size? (includes tail)
- Geometry : smaller than GeometryEx (no tail, maybe correct too?)
- MyGetDiskFreeSpace : FAIL
- Size correction is slow and block size (kClusterSize) must be small?
-
- HDD partition \\.\N: (NTFS):
- MyGetDiskFreeSpace : Size of NTFS clusters. Same size can be calculated after correction
- GetPartitionInfo : size of partition data: NTFS clusters + TAIL; TAIL contains extra empty sectors and copy of first sector of NTFS
- Geometry / CdRomGeometry / GeometryEx : size of HDD (not that partition)
-
- CD-ROM drive (ISO):
- MyGetDiskFreeSpace : correct size. Same size can be calculated after correction
- Geometry == CdRomGeometry : smaller than corrrect size
- GetPartitionInfo == GeometryEx : larger than corrrect size
-
- Floppy \\.\a: (FAT):
- Geometry : correct size.
- CdRomGeometry / GeometryEx / GetPartitionInfo / MyGetDiskFreeSpace - FAIL
- correction works OK for FAT.
- correction works OK for non-FAT, if kClusterSize = 512.
- */
-
- if (GetPartitionInfo(&partInfo))
- {
- Size = partInfo.PartitionLength.QuadPart;
- SizeDefined = true;
- needCorrectSize = false;
- if ((s)[0] == '\\' && (s)[1] == '\\' && (s)[2] == '.' && (s)[3] == '\\' && (s)[5] == ':' && (s)[6] == 0)
- {
- FChar path[4] = { s[4], ':', '\\', 0 };
- UInt64 clusterSize, totalSize, freeSize;
- if (NSystem::MyGetDiskFreeSpace(path, clusterSize, totalSize, freeSize))
- Size = totalSize;
- else
- needCorrectSize = true;
- }
- }
-
- if (!SizeDefined)
- {
- my_DISK_GEOMETRY_EX geomEx;
- SizeDefined = GetGeometryEx(&geomEx);
- if (SizeDefined)
- Size = geomEx.DiskSize.QuadPart;
- else
- {
- DISK_GEOMETRY geom;
- SizeDefined = GetGeometry(&geom);
- if (!SizeDefined)
- SizeDefined = GetCdRomGeometry(&geom);
- if (SizeDefined)
- Size = geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector;
- }
- }
-
- if (needCorrectSize && SizeDefined && Size != 0)
- {
- CorrectDeviceSize();
- SeekToBegin();
- }
-
- // SeekToBegin();
- #endif
-}
-
-// ((desiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE)) == 0 &&
-
-#define MY_DEVICE_EXTRA_CODE \
- IsDeviceFile = IsDevicePath(fileName); \
- CalcDeviceSize(fileName);
-#else
-#define MY_DEVICE_EXTRA_CODE
-#endif
-
-bool CInFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
-{
- bool res = Create(fileName, GENERIC_READ, shareMode, creationDisposition, flagsAndAttributes);
- MY_DEVICE_EXTRA_CODE
- return res;
-}
-
-bool CInFile::OpenShared(CFSTR fileName, bool shareForWrite)
-{ return Open(fileName, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); }
-
-bool CInFile::Open(CFSTR fileName)
- { return OpenShared(fileName, false); }
-
-// ReadFile and WriteFile functions in Windows have BUG:
-// If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
-// from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
-// (Insufficient system resources exist to complete the requested service).
-
-// Probably in some version of Windows there are problems with other sizes:
-// for 32 MB (maybe also for 16 MB).
-// And message can be "Network connection was lost"
-
-static UInt32 kChunkSizeMax = (1 << 22);
-
-bool CInFile::Read1(void *data, UInt32 size, UInt32 &processedSize) throw()
-{
- DWORD processedLoc = 0;
- bool res = BOOLToBool(::ReadFile(_handle, data, size, &processedLoc, NULL));
- processedSize = (UInt32)processedLoc;
- return res;
-}
-
-bool CInFile::ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw()
-{
- if (size > kChunkSizeMax)
- size = kChunkSizeMax;
- return Read1(data, size, processedSize);
-}
-
-bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize) throw()
-{
- processedSize = 0;
- do
- {
- UInt32 processedLoc = 0;
- bool res = ReadPart(data, size, processedLoc);
- processedSize += processedLoc;
- if (!res)
- return false;
- if (processedLoc == 0)
- return true;
- data = (void *)((unsigned char *)data + processedLoc);
- size -= processedLoc;
- }
- while (size > 0);
- return true;
-}
-
-// ---------- COutFile ---------
-
-static inline DWORD GetCreationDisposition(bool createAlways)
- { return createAlways? CREATE_ALWAYS: CREATE_NEW; }
-
-bool COutFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
- { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); }
-
-bool COutFile::Open(CFSTR fileName, DWORD creationDisposition)
- { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); }
-
-bool COutFile::Create(CFSTR fileName, bool createAlways)
- { return Open(fileName, GetCreationDisposition(createAlways)); }
-
-bool COutFile::CreateAlways(CFSTR fileName, DWORD flagsAndAttributes)
- { return Open(fileName, FILE_SHARE_READ, GetCreationDisposition(true), flagsAndAttributes); }
-
-bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw()
- { return BOOLToBool(::SetFileTime(_handle, cTime, aTime, mTime)); }
-
-bool COutFile::SetMTime(const FILETIME *mTime) throw() { return SetTime(NULL, NULL, mTime); }
-
-bool COutFile::WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw()
-{
- if (size > kChunkSizeMax)
- size = kChunkSizeMax;
- DWORD processedLoc = 0;
- bool res = BOOLToBool(::WriteFile(_handle, data, size, &processedLoc, NULL));
- processedSize = (UInt32)processedLoc;
- return res;
-}
-
-bool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize) throw()
-{
- processedSize = 0;
- do
- {
- UInt32 processedLoc = 0;
- bool res = WritePart(data, size, processedLoc);
- processedSize += processedLoc;
- if (!res)
- return false;
- if (processedLoc == 0)
- return true;
- data = (const void *)((const unsigned char *)data + processedLoc);
- size -= processedLoc;
- }
- while (size > 0);
- return true;
-}
-
-bool COutFile::SetEndOfFile() throw() { return BOOLToBool(::SetEndOfFile(_handle)); }
-
-bool COutFile::SetLength(UInt64 length) throw()
-{
- UInt64 newPosition;
- if (!Seek(length, newPosition))
- return false;
- if (newPosition != length)
- return false;
- return SetEndOfFile();
-}
-
-}}}
+// Windows/FileIO.cpp
+
+#include "StdAfx.h"
+
+#ifdef Z7_DEVICE_FILE
+#include "../../C/Alloc.h"
+#endif
+
+// #include <stdio.h>
+
+/*
+#ifndef _WIN32
+// for ioctl BLKGETSIZE64
+#include <sys/ioctl.h>
+#include <linux/fs.h>
+#endif
+*/
+
+#include "FileIO.h"
+#include "FileName.h"
+
+HRESULT GetLastError_noZero_HRESULT()
+{
+ const DWORD res = ::GetLastError();
+ if (res == 0)
+ return E_FAIL;
+ return HRESULT_FROM_WIN32(res);
+}
+
+#ifdef _WIN32
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+using namespace NWindows;
+using namespace NFile;
+using namespace NName;
+
+namespace NWindows {
+namespace NFile {
+
+#ifdef Z7_DEVICE_FILE
+
+namespace NSystem
+{
+bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
+}
+#endif
+
+namespace NIO {
+
+/*
+WinXP-64 CreateFile():
+ "" - ERROR_PATH_NOT_FOUND
+ :stream - OK
+ .:stream - ERROR_PATH_NOT_FOUND
+ .\:stream - OK
+
+ folder\:stream - ERROR_INVALID_NAME
+ folder:stream - OK
+
+ c:\:stream - OK
+
+ c::stream - ERROR_INVALID_NAME, if current dir is NOT ROOT ( c:\dir1 )
+ c::stream - OK, if current dir is ROOT ( c:\ )
+*/
+
+bool CFileBase::Create(CFSTR path, DWORD desiredAccess,
+ DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+{
+ if (!Close())
+ return false;
+
+ #ifdef Z7_DEVICE_FILE
+ IsDeviceFile = false;
+ #endif
+
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ _handle = ::CreateFile(fs2fas(path), desiredAccess, shareMode,
+ (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL);
+ }
+ else
+ #endif
+ {
+ IF_USE_MAIN_PATH
+ _handle = ::CreateFileW(fs2us(path), desiredAccess, shareMode,
+ (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL);
+ #ifdef Z7_LONG_PATH
+ if (_handle == INVALID_HANDLE_VALUE && USE_SUPER_PATH)
+ {
+ UString superPath;
+ if (GetSuperPath(path, superPath, USE_MAIN_PATH))
+ _handle = ::CreateFileW(superPath, desiredAccess, shareMode,
+ (LPSECURITY_ATTRIBUTES)NULL, creationDisposition, flagsAndAttributes, (HANDLE)NULL);
+ }
+ #endif
+ }
+
+ /*
+ #ifndef UNDER_CE
+ #ifndef Z7_SFX
+ if (_handle == INVALID_HANDLE_VALUE)
+ {
+ // it's debug hack to open symbolic links in Windows XP and WSL links in Windows 10
+ DWORD lastError = GetLastError();
+ if (lastError == ERROR_CANT_ACCESS_FILE)
+ {
+ CByteBuffer buf;
+ if (NIO::GetReparseData(path, buf, NULL))
+ {
+ CReparseAttr attr;
+ if (attr.Parse(buf, buf.Size()))
+ {
+ FString dirPrefix, fileName;
+ if (NDir::GetFullPathAndSplit(path, dirPrefix, fileName))
+ {
+ FString fullPath;
+ if (GetFullPath(dirPrefix, us2fs(attr.GetPath()), fullPath))
+ {
+ // FIX IT: recursion levels must be restricted
+ return Create(fullPath, desiredAccess,
+ shareMode, creationDisposition, flagsAndAttributes);
+ }
+ }
+ }
+ }
+ SetLastError(lastError);
+ }
+ }
+ #endif
+ #endif
+ */
+
+ return (_handle != INVALID_HANDLE_VALUE);
+}
+
+bool CFileBase::Close() throw()
+{
+ if (_handle == INVALID_HANDLE_VALUE)
+ return true;
+ if (!::CloseHandle(_handle))
+ return false;
+ _handle = INVALID_HANDLE_VALUE;
+ return true;
+}
+
+bool CFileBase::GetLength(UInt64 &length) const throw()
+{
+ #ifdef Z7_DEVICE_FILE
+ if (IsDeviceFile && SizeDefined)
+ {
+ length = Size;
+ return true;
+ }
+ #endif
+
+ DWORD high = 0;
+ const DWORD low = ::GetFileSize(_handle, &high);
+ if (low == INVALID_FILE_SIZE)
+ if (::GetLastError() != NO_ERROR)
+ return false;
+ length = (((UInt64)high) << 32) + low;
+ return true;
+
+ /*
+ LARGE_INTEGER fileSize;
+ // GetFileSizeEx() is unsupported in 98/ME/NT, and supported in Win2000+
+ if (!GetFileSizeEx(_handle, &fileSize))
+ return false;
+ length = (UInt64)fileSize.QuadPart;
+ return true;
+ */
+}
+
+
+/* Specification for SetFilePointer():
+
+ If a new file pointer is a negative value,
+ {
+ the function fails,
+ the file pointer is not moved,
+ the code returned by GetLastError() is ERROR_NEGATIVE_SEEK.
+ }
+
+ If the hFile handle is opened with the FILE_FLAG_NO_BUFFERING flag set
+ {
+ an application can move the file pointer only to sector-aligned positions.
+ A sector-aligned position is a position that is a whole number multiple of
+ the volume sector size.
+ An application can obtain a volume sector size by calling the GetDiskFreeSpace.
+ }
+
+ It is not an error to set a file pointer to a position beyond the end of the file.
+ The size of the file does not increase until you call the SetEndOfFile, WriteFile, or WriteFileEx function.
+
+ If the return value is INVALID_SET_FILE_POINTER and if lpDistanceToMoveHigh is non-NULL,
+ an application must call GetLastError to determine whether or not the function has succeeded or failed.
+*/
+
+bool CFileBase::GetPosition(UInt64 &position) const throw()
+{
+ LONG high = 0;
+ const DWORD low = ::SetFilePointer(_handle, 0, &high, FILE_CURRENT);
+ if (low == INVALID_SET_FILE_POINTER && GetLastError() != NO_ERROR)
+ {
+ // for error case we can set (position) to (-1) or (0) or leave (position) unchanged.
+ // position = (UInt64)(Int64)-1; // for debug
+ position = 0;
+ return false;
+ }
+ position = (((UInt64)(UInt32)high) << 32) + low;
+ return true;
+ // we don't want recursed GetPosition()
+ // return Seek(0, FILE_CURRENT, position);
+}
+
+bool CFileBase::Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw()
+{
+ #ifdef Z7_DEVICE_FILE
+ if (IsDeviceFile && SizeDefined && moveMethod == FILE_END)
+ {
+ distanceToMove += Size;
+ moveMethod = FILE_BEGIN;
+ }
+ #endif
+
+ LONG high = (LONG)(distanceToMove >> 32);
+ const DWORD low = ::SetFilePointer(_handle, (LONG)(distanceToMove & 0xFFFFFFFF), &high, moveMethod);
+ if (low == INVALID_SET_FILE_POINTER)
+ {
+ const DWORD lastError = ::GetLastError();
+ if (lastError != NO_ERROR)
+ {
+ // 21.07: we set (newPosition) to real position even after error.
+ GetPosition(newPosition);
+ SetLastError(lastError); // restore LastError
+ return false;
+ }
+ }
+ newPosition = (((UInt64)(UInt32)high) << 32) + low;
+ return true;
+}
+
+bool CFileBase::Seek(UInt64 position, UInt64 &newPosition) const throw()
+{
+ return Seek((Int64)position, FILE_BEGIN, newPosition);
+}
+
+bool CFileBase::SeekToBegin() const throw()
+{
+ UInt64 newPosition = 0;
+ return Seek(0, newPosition) && (newPosition == 0);
+}
+
+bool CFileBase::SeekToEnd(UInt64 &newPosition) const throw()
+{
+ return Seek(0, FILE_END, newPosition);
+}
+
+// ---------- CInFile ---------
+
+#ifdef Z7_DEVICE_FILE
+
+void CInFile::CorrectDeviceSize()
+{
+ // maybe we must decrease kClusterSize to 1 << 12, if we want correct size at tail
+ const UInt32 kClusterSize = 1 << 14;
+ UInt64 pos = Size & ~(UInt64)(kClusterSize - 1);
+ UInt64 realNewPosition;
+ if (!Seek(pos, realNewPosition))
+ return;
+ Byte *buf = (Byte *)MidAlloc(kClusterSize);
+
+ bool needbackward = true;
+
+ for (;;)
+ {
+ UInt32 processed = 0;
+ // up test is slow for "PhysicalDrive".
+ // processed size for latest block for "PhysicalDrive0" is 0.
+ if (!Read1(buf, kClusterSize, processed))
+ break;
+ if (processed == 0)
+ break;
+ needbackward = false;
+ Size = pos + processed;
+ if (processed != kClusterSize)
+ break;
+ pos += kClusterSize;
+ }
+
+ if (needbackward && pos != 0)
+ {
+ pos -= kClusterSize;
+ for (;;)
+ {
+ // break;
+ if (!Seek(pos, realNewPosition))
+ break;
+ if (!buf)
+ {
+ buf = (Byte *)MidAlloc(kClusterSize);
+ if (!buf)
+ break;
+ }
+ UInt32 processed = 0;
+ // that code doesn't work for "PhysicalDrive0"
+ if (!Read1(buf, kClusterSize, processed))
+ break;
+ if (processed != 0)
+ {
+ Size = pos + processed;
+ break;
+ }
+ if (pos == 0)
+ break;
+ pos -= kClusterSize;
+ }
+ }
+ MidFree(buf);
+}
+
+
+void CInFile::CalcDeviceSize(CFSTR s)
+{
+ SizeDefined = false;
+ Size = 0;
+ if (_handle == INVALID_HANDLE_VALUE || !IsDeviceFile)
+ return;
+ #ifdef UNDER_CE
+
+ SizeDefined = true;
+ Size = 128 << 20;
+
+ #else
+
+ PARTITION_INFORMATION partInfo;
+ bool needCorrectSize = true;
+
+ /*
+ WinXP 64-bit:
+
+ HDD \\.\PhysicalDrive0 (MBR):
+ GetPartitionInfo == GeometryEx : corrrect size? (includes tail)
+ Geometry : smaller than GeometryEx (no tail, maybe correct too?)
+ MyGetDiskFreeSpace : FAIL
+ Size correction is slow and block size (kClusterSize) must be small?
+
+ HDD partition \\.\N: (NTFS):
+ MyGetDiskFreeSpace : Size of NTFS clusters. Same size can be calculated after correction
+ GetPartitionInfo : size of partition data: NTFS clusters + TAIL; TAIL contains extra empty sectors and copy of first sector of NTFS
+ Geometry / CdRomGeometry / GeometryEx : size of HDD (not that partition)
+
+ CD-ROM drive (ISO):
+ MyGetDiskFreeSpace : correct size. Same size can be calculated after correction
+ Geometry == CdRomGeometry : smaller than corrrect size
+ GetPartitionInfo == GeometryEx : larger than corrrect size
+
+ Floppy \\.\a: (FAT):
+ Geometry : correct size.
+ CdRomGeometry / GeometryEx / GetPartitionInfo / MyGetDiskFreeSpace - FAIL
+ correction works OK for FAT.
+ correction works OK for non-FAT, if kClusterSize = 512.
+ */
+
+ if (GetPartitionInfo(&partInfo))
+ {
+ Size = (UInt64)partInfo.PartitionLength.QuadPart;
+ SizeDefined = true;
+ needCorrectSize = false;
+ if ((s)[0] == '\\' && (s)[1] == '\\' && (s)[2] == '.' && (s)[3] == '\\' && (s)[5] == ':' && (s)[6] == 0)
+ {
+ FChar path[4] = { s[4], ':', '\\', 0 };
+ UInt64 clusterSize, totalSize, freeSize;
+ if (NSystem::MyGetDiskFreeSpace(path, clusterSize, totalSize, freeSize))
+ Size = totalSize;
+ else
+ needCorrectSize = true;
+ }
+ }
+
+ if (!SizeDefined)
+ {
+ my_DISK_GEOMETRY_EX geomEx;
+ SizeDefined = GetGeometryEx(&geomEx);
+ if (SizeDefined)
+ Size = (UInt64)geomEx.DiskSize.QuadPart;
+ else
+ {
+ DISK_GEOMETRY geom;
+ SizeDefined = GetGeometry(&geom);
+ if (!SizeDefined)
+ SizeDefined = GetCdRomGeometry(&geom);
+ if (SizeDefined)
+ Size = (UInt64)geom.Cylinders.QuadPart * geom.TracksPerCylinder * geom.SectorsPerTrack * geom.BytesPerSector;
+ }
+ }
+
+ if (needCorrectSize && SizeDefined && Size != 0)
+ {
+ CorrectDeviceSize();
+ SeekToBegin();
+ }
+
+ // SeekToBegin();
+ #endif
+}
+
+// ((desiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA | GENERIC_WRITE)) == 0 &&
+
+#define MY_DEVICE_EXTRA_CODE \
+ IsDeviceFile = IsDevicePath(fileName); \
+ CalcDeviceSize(fileName);
+#else
+#define MY_DEVICE_EXTRA_CODE
+#endif
+
+bool CInFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+{
+ DWORD desiredAccess = GENERIC_READ;
+
+ #ifdef _WIN32
+ if (PreserveATime)
+ desiredAccess |= FILE_WRITE_ATTRIBUTES;
+ #endif
+
+ bool res = Create(fileName, desiredAccess, shareMode, creationDisposition, flagsAndAttributes);
+
+ #ifdef _WIN32
+ if (res && PreserveATime)
+ {
+ FILETIME ft;
+ ft.dwHighDateTime = ft.dwLowDateTime = 0xFFFFFFFF;
+ ::SetFileTime(_handle, NULL, &ft, NULL);
+ }
+ #endif
+
+ MY_DEVICE_EXTRA_CODE
+ return res;
+}
+
+bool CInFile::OpenShared(CFSTR fileName, bool shareForWrite)
+{ return Open(fileName, FILE_SHARE_READ | (shareForWrite ? FILE_SHARE_WRITE : 0), OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL); }
+
+bool CInFile::Open(CFSTR fileName)
+ { return OpenShared(fileName, false); }
+
+// ReadFile and WriteFile functions in Windows have BUG:
+// If you Read or Write 64MB or more (probably min_failure_size = 64MB - 32KB + 1)
+// from/to Network file, it returns ERROR_NO_SYSTEM_RESOURCES
+// (Insufficient system resources exist to complete the requested service).
+
+// Probably in some version of Windows there are problems with other sizes:
+// for 32 MB (maybe also for 16 MB).
+// And message can be "Network connection was lost"
+
+static const UInt32 kChunkSizeMax = (1 << 22);
+
+bool CInFile::Read1(void *data, UInt32 size, UInt32 &processedSize) throw()
+{
+ DWORD processedLoc = 0;
+ const bool res = BOOLToBool(::ReadFile(_handle, data, size, &processedLoc, NULL));
+ processedSize = (UInt32)processedLoc;
+ return res;
+}
+
+bool CInFile::ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw()
+{
+ if (size > kChunkSizeMax)
+ size = kChunkSizeMax;
+ return Read1(data, size, processedSize);
+}
+
+bool CInFile::Read(void *data, UInt32 size, UInt32 &processedSize) throw()
+{
+ processedSize = 0;
+ do
+ {
+ UInt32 processedLoc = 0;
+ const bool res = ReadPart(data, size, processedLoc);
+ processedSize += processedLoc;
+ if (!res)
+ return false;
+ if (processedLoc == 0)
+ return true;
+ data = (void *)((unsigned char *)data + processedLoc);
+ size -= processedLoc;
+ }
+ while (size > 0);
+ return true;
+}
+
+bool CInFile::ReadFull(void *data, size_t size, size_t &processedSize) throw()
+{
+ processedSize = 0;
+ do
+ {
+ UInt32 processedLoc = 0;
+ const UInt32 sizeLoc = (size > kChunkSizeMax ? (UInt32)kChunkSizeMax : (UInt32)size);
+ const bool res = Read1(data, sizeLoc, processedLoc);
+ processedSize += processedLoc;
+ if (!res)
+ return false;
+ if (processedLoc == 0)
+ return true;
+ data = (void *)((unsigned char *)data + processedLoc);
+ size -= processedLoc;
+ }
+ while (size > 0);
+ return true;
+}
+
+// ---------- COutFile ---------
+
+static inline DWORD GetCreationDisposition(bool createAlways)
+ { return createAlways? CREATE_ALWAYS: CREATE_NEW; }
+
+bool COutFile::Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes)
+ { return CFileBase::Create(fileName, GENERIC_WRITE, shareMode, creationDisposition, flagsAndAttributes); }
+
+bool COutFile::Open(CFSTR fileName, DWORD creationDisposition)
+ { return Open(fileName, FILE_SHARE_READ, creationDisposition, FILE_ATTRIBUTE_NORMAL); }
+
+bool COutFile::Create(CFSTR fileName, bool createAlways)
+ { return Open(fileName, GetCreationDisposition(createAlways)); }
+
+bool COutFile::CreateAlways(CFSTR fileName, DWORD flagsAndAttributes)
+ { return Open(fileName, FILE_SHARE_READ, GetCreationDisposition(true), flagsAndAttributes); }
+
+bool COutFile::SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw()
+ { return BOOLToBool(::SetFileTime(_handle, cTime, aTime, mTime)); }
+
+bool COutFile::SetMTime(const FILETIME *mTime) throw() { return SetTime(NULL, NULL, mTime); }
+
+bool COutFile::WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw()
+{
+ if (size > kChunkSizeMax)
+ size = kChunkSizeMax;
+ DWORD processedLoc = 0;
+ bool res = BOOLToBool(::WriteFile(_handle, data, size, &processedLoc, NULL));
+ processedSize = (UInt32)processedLoc;
+ return res;
+}
+
+bool COutFile::Write(const void *data, UInt32 size, UInt32 &processedSize) throw()
+{
+ processedSize = 0;
+ do
+ {
+ UInt32 processedLoc = 0;
+ const bool res = WritePart(data, size, processedLoc);
+ processedSize += processedLoc;
+ if (!res)
+ return false;
+ if (processedLoc == 0)
+ return true;
+ data = (const void *)((const unsigned char *)data + processedLoc);
+ size -= processedLoc;
+ }
+ while (size != 0);
+ return true;
+}
+
+bool COutFile::WriteFull(const void *data, size_t size) throw()
+{
+ do
+ {
+ UInt32 processedLoc = 0;
+ const UInt32 sizeCur = (size > kChunkSizeMax ? kChunkSizeMax : (UInt32)size);
+ if (!WritePart(data, sizeCur, processedLoc))
+ return false;
+ if (processedLoc == 0)
+ return (size == 0);
+ data = (const void *)((const unsigned char *)data + processedLoc);
+ size -= processedLoc;
+ }
+ while (size != 0);
+ return true;
+}
+
+bool COutFile::SetEndOfFile() throw() { return BOOLToBool(::SetEndOfFile(_handle)); }
+
+bool COutFile::SetLength(UInt64 length) throw()
+{
+ UInt64 newPosition;
+ if (!Seek(length, newPosition))
+ return false;
+ if (newPosition != length)
+ return false;
+ return SetEndOfFile();
+}
+
+bool COutFile::SetLength_KeepPosition(UInt64 length) throw()
+{
+ UInt64 currentPos = 0;
+ if (!GetPosition(currentPos))
+ return false;
+ DWORD lastError = 0;
+ const bool result = SetLength(length);
+ if (!result)
+ lastError = GetLastError();
+ UInt64 currentPos2;
+ const bool result2 = Seek(currentPos, currentPos2);
+ if (lastError != 0)
+ SetLastError(lastError);
+ return (result && result2);
+}
+
+}}}
+
+#else // _WIN32
+
+
+// POSIX
+
+#include <fcntl.h>
+#include <unistd.h>
+
+namespace NWindows {
+namespace NFile {
+
+namespace NDir {
+bool SetDirTime(CFSTR path, const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime);
+}
+
+namespace NIO {
+
+bool CFileBase::OpenBinary(const char *name, int flags, mode_t mode)
+{
+ #ifdef O_BINARY
+ flags |= O_BINARY;
+ #endif
+
+ Close();
+ _handle = ::open(name, flags, mode);
+ return _handle != -1;
+
+ /*
+ if (_handle == -1)
+ return false;
+ if (IsString1PrefixedByString2(name, "/dev/"))
+ {
+ // /dev/sda
+ // IsDeviceFile = true; // for debug
+ // SizeDefined = false;
+ // SizeDefined = (GetDeviceSize_InBytes(Size) == 0);
+ }
+ return true;
+ */
+}
+
+bool CFileBase::Close()
+{
+ if (_handle == -1)
+ return true;
+ if (close(_handle) != 0)
+ return false;
+ _handle = -1;
+ /*
+ IsDeviceFile = false;
+ SizeDefined = false;
+ */
+ return true;
+}
+
+bool CFileBase::GetLength(UInt64 &length) const
+{
+ length = 0;
+ // length = (UInt64)(Int64)-1; // for debug
+ const off_t curPos = seekToCur();
+ if (curPos == -1)
+ return false;
+ const off_t lengthTemp = seek(0, SEEK_END);
+ seek(curPos, SEEK_SET);
+ length = (UInt64)lengthTemp;
+
+ /*
+ // 22.00:
+ if (lengthTemp == 1)
+ if (IsDeviceFile && SizeDefined)
+ {
+ length = Size;
+ return true;
+ }
+ */
+
+ return (lengthTemp != -1);
+}
+
+off_t CFileBase::seek(off_t distanceToMove, int moveMethod) const
+{
+ /*
+ if (IsDeviceFile && SizeDefined && moveMethod == SEEK_END)
+ {
+ printf("\n seek : IsDeviceFile moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove);
+ distanceToMove += Size;
+ moveMethod = SEEK_SET;
+ }
+ */
+
+ // printf("\nCFileBase::seek() moveMethod = %d, distanceToMove = %lld", moveMethod, (long long)distanceToMove);
+ // off_t res = ::lseek(_handle, distanceToMove, moveMethod);
+ // printf("\n lseek : moveMethod = %d distanceToMove = %ld\n", moveMethod, distanceToMove);
+ return ::lseek(_handle, distanceToMove, moveMethod);
+ // return res;
+}
+
+off_t CFileBase::seekToBegin() const throw()
+{
+ return seek(0, SEEK_SET);
+}
+
+off_t CFileBase::seekToCur() const throw()
+{
+ return seek(0, SEEK_CUR);
+}
+
+/*
+bool CFileBase::SeekToBegin() const throw()
+{
+ return (::seek(0, SEEK_SET) != -1);
+}
+*/
+
+
+/////////////////////////
+// CInFile
+
+bool CInFile::Open(const char *name)
+{
+ return CFileBase::OpenBinary(name, O_RDONLY);
+}
+
+bool CInFile::OpenShared(const char *name, bool)
+{
+ return Open(name);
+}
+
+
+/*
+int CFileBase::my_ioctl_BLKGETSIZE64(unsigned long long *numBlocks)
+{
+ // we can read "/sys/block/sda/size" "/sys/block/sda/sda1/size" - partition
+ // #include <linux/fs.h>
+ return ioctl(_handle, BLKGETSIZE64, numBlocks);
+ // in block size
+}
+
+int CFileBase::GetDeviceSize_InBytes(UInt64 &size)
+{
+ size = 0;
+ unsigned long long numBlocks;
+ int res = my_ioctl_BLKGETSIZE64(&numBlocks);
+ if (res == 0)
+ size = numBlocks; // another blockSize s possible?
+ printf("\nGetDeviceSize_InBytes res = %d, size = %lld\n", res, (long long)size);
+ return res;
+}
+*/
+
+/*
+On Linux (32-bit and 64-bit):
+read(), write() (and similar system calls) will transfer at most
+0x7ffff000 = (2GiB - 4 KiB) bytes, returning the number of bytes actually transferred.
+*/
+
+static const size_t kChunkSizeMax = ((size_t)1 << 22);
+
+ssize_t CInFile::read_part(void *data, size_t size) throw()
+{
+ if (size > kChunkSizeMax)
+ size = kChunkSizeMax;
+ return ::read(_handle, data, size);
+}
+
+bool CInFile::ReadFull(void *data, size_t size, size_t &processed) throw()
+{
+ processed = 0;
+ do
+ {
+ const ssize_t res = read_part(data, size);
+ if (res < 0)
+ return false;
+ if (res == 0)
+ break;
+ data = (void *)((unsigned char *)data + (size_t)res);
+ size -= (size_t)res;
+ processed += (size_t)res;
+ }
+ while (size > 0);
+ return true;
+}
+
+
+/////////////////////////
+// COutFile
+
+bool COutFile::Create(const char *name, bool createAlways)
+{
+ Path = name; // change it : set it only if open is success.
+ if (createAlways)
+ {
+ Close();
+ _handle = ::creat(name, mode_for_Create);
+ return _handle != -1;
+ }
+ return OpenBinary(name, O_CREAT | O_EXCL | O_WRONLY, mode_for_Create);
+}
+
+bool COutFile::Open(const char *name, DWORD creationDisposition)
+{
+ UNUSED_VAR(creationDisposition) // FIXME
+ return Create(name, false);
+}
+
+ssize_t COutFile::write_part(const void *data, size_t size) throw()
+{
+ if (size > kChunkSizeMax)
+ size = kChunkSizeMax;
+ return ::write(_handle, data, size);
+}
+
+ssize_t COutFile::write_full(const void *data, size_t size, size_t &processed) throw()
+{
+ processed = 0;
+ do
+ {
+ const ssize_t res = write_part(data, size);
+ if (res < 0)
+ return res;
+ if (res == 0)
+ break;
+ data = (const void *)((const unsigned char *)data + (size_t)res);
+ size -= (size_t)res;
+ processed += (size_t)res;
+ }
+ while (size > 0);
+ return (ssize_t)processed;
+}
+
+bool COutFile::SetLength(UInt64 length) throw()
+{
+ const off_t len2 = (off_t)length;
+ if ((Int64)length != len2)
+ {
+ SetLastError(EFBIG);
+ return false;
+ }
+ // The value of the seek pointer shall not be modified by a call to ftruncate().
+ const int iret = ftruncate(_handle, len2);
+ return (iret == 0);
+}
+
+bool COutFile::Close()
+{
+ const bool res = CFileBase::Close();
+ if (!res)
+ return res;
+ if (CTime_defined || ATime_defined || MTime_defined)
+ {
+ /* bool res2 = */ NWindows::NFile::NDir::SetDirTime(Path,
+ CTime_defined ? &CTime : NULL,
+ ATime_defined ? &ATime : NULL,
+ MTime_defined ? &MTime : NULL);
+ }
+ return res;
+}
+
+bool COutFile::SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw()
+{
+ // On some OS (cygwin, MacOSX ...), you must close the file before updating times
+ // return true;
+
+ if (cTime) { CTime = *cTime; CTime_defined = true; } else CTime_defined = false;
+ if (aTime) { ATime = *aTime; ATime_defined = true; } else ATime_defined = false;
+ if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false;
+ return true;
+
+ /*
+ struct timespec times[2];
+ UNUSED_VAR(cTime)
+ if (!aTime && !mTime)
+ return true;
+ bool needChange;
+ needChange = FiTime_To_timespec(aTime, times[0]);
+ needChange |= FiTime_To_timespec(mTime, times[1]);
+ if (!needChange)
+ return true;
+ return futimens(_handle, times) == 0;
+ */
+}
+
+bool COutFile::SetMTime(const CFiTime *mTime) throw()
+{
+ if (mTime) { MTime = *mTime; MTime_defined = true; } else MTime_defined = false;
+ return true;
+}
+
+}}}
+
+
+#endif
diff --git a/CPP/Windows/FileIO.h b/CPP/Windows/FileIO.h
index e31bc20..03e061a 100644
--- a/CPP/Windows/FileIO.h
+++ b/CPP/Windows/FileIO.h
@@ -1,212 +1,390 @@
-// Windows/FileIO.h
-
-#ifndef __WINDOWS_FILE_IO_H
-#define __WINDOWS_FILE_IO_H
-
-#include "../Common/MyWindows.h"
-
-#if defined(_WIN32) && !defined(UNDER_CE)
-#include <winioctl.h>
-#endif
-
-#include "../Common/MyString.h"
-#include "../Common/MyBuffer.h"
-
-#include "Defs.h"
-
-#define _my_IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L)
-#define _my_IO_REPARSE_TAG_SYMLINK (0xA000000CL)
-
-#define _my_SYMLINK_FLAG_RELATIVE 1
-
-#define my_FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER
-#define my_FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) // REPARSE_DATA_BUFFER
-
-namespace NWindows {
-namespace NFile {
-
-#if defined(_WIN32) && !defined(UNDER_CE)
-bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink);
-#endif
-
-struct CReparseShortInfo
-{
- unsigned Offset;
- unsigned Size;
-
- bool Parse(const Byte *p, size_t size);
-};
-
-struct CReparseAttr
-{
- UInt32 Tag;
- UInt32 Flags;
- UString SubsName;
- UString PrintName;
-
- CReparseAttr(): Tag(0), Flags(0) {}
-
- // Parse()
- // returns true and (errorCode = 0), if (correct MOUNT_POINT or SYMLINK)
- // returns false and (errorCode = ERROR_REPARSE_TAG_MISMATCH), if not (MOUNT_POINT or SYMLINK)
- bool Parse(const Byte *p, size_t size, DWORD &errorCode);
-
- bool IsMountPoint() const { return Tag == _my_IO_REPARSE_TAG_MOUNT_POINT; } // it's Junction
- bool IsSymLink() const { return Tag == _my_IO_REPARSE_TAG_SYMLINK; }
- bool IsRelative() const { return Flags == _my_SYMLINK_FLAG_RELATIVE; }
- // bool IsVolume() const;
-
- bool IsOkNamePair() const;
- UString GetPath() const;
-};
-
-namespace NIO {
-
-bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo = NULL);
-bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size);
-
-class CFileBase
-{
-protected:
- HANDLE _handle;
-
- bool Create(CFSTR path, DWORD desiredAccess,
- DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
-
-public:
-
- bool DeviceIoControl(DWORD controlCode, LPVOID inBuffer, DWORD inSize,
- LPVOID outBuffer, DWORD outSize, LPDWORD bytesReturned, LPOVERLAPPED overlapped = NULL) const
- {
- return BOOLToBool(::DeviceIoControl(_handle, controlCode, inBuffer, inSize,
- outBuffer, outSize, bytesReturned, overlapped));
- }
-
- bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize, LPDWORD bytesReturned) const
- {
- return DeviceIoControl(controlCode, NULL, 0, outBuffer, outSize, bytesReturned);
- }
-
- bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize) const
- {
- DWORD bytesReturned;
- return DeviceIoControlOut(controlCode, outBuffer, outSize, &bytesReturned);
- }
-
-public:
- #ifdef SUPPORT_DEVICE_FILE
- bool IsDeviceFile;
- bool SizeDefined;
- UInt64 Size; // it can be larger than real available size
- #endif
-
- CFileBase(): _handle(INVALID_HANDLE_VALUE) {};
- ~CFileBase() { Close(); }
-
- bool Close() throw();
-
- bool GetPosition(UInt64 &position) const throw();
- bool GetLength(UInt64 &length) const throw();
-
- bool Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw();
- bool Seek(UInt64 position, UInt64 &newPosition) const throw();
- bool SeekToBegin() const throw();
- bool SeekToEnd(UInt64 &newPosition) const throw();
-
- bool GetFileInformation(BY_HANDLE_FILE_INFORMATION *info) const
- { return BOOLToBool(GetFileInformationByHandle(_handle, info)); }
-
- static bool GetFileInformation(CFSTR path, BY_HANDLE_FILE_INFORMATION *info)
- {
- NIO::CFileBase file;
- if (!file.Create(path, 0, FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS))
- return false;
- return file.GetFileInformation(info);
- }
-};
-
-#ifndef UNDER_CE
-#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
-#define IOCTL_CDROM_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS)
-// #define IOCTL_CDROM_MEDIA_REMOVAL CTL_CODE(IOCTL_CDROM_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS)
-
-// IOCTL_DISK_GET_DRIVE_GEOMETRY_EX works since WinXP
-#define my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS)
-
-struct my_DISK_GEOMETRY_EX
-{
- DISK_GEOMETRY Geometry;
- LARGE_INTEGER DiskSize;
- BYTE Data[1];
-};
-#endif
-
-class CInFile: public CFileBase
-{
- #ifdef SUPPORT_DEVICE_FILE
-
- #ifndef UNDER_CE
-
- bool GetGeometry(DISK_GEOMETRY *res) const
- { return DeviceIoControlOut(IOCTL_DISK_GET_DRIVE_GEOMETRY, res, sizeof(*res)); }
-
- bool GetGeometryEx(my_DISK_GEOMETRY_EX *res) const
- { return DeviceIoControlOut(my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, res, sizeof(*res)); }
-
- bool GetCdRomGeometry(DISK_GEOMETRY *res) const
- { return DeviceIoControlOut(IOCTL_CDROM_GET_DRIVE_GEOMETRY, res, sizeof(*res)); }
-
- bool GetPartitionInfo(PARTITION_INFORMATION *res)
- { return DeviceIoControlOut(IOCTL_DISK_GET_PARTITION_INFO, LPVOID(res), sizeof(*res)); }
-
- #endif
-
- void CorrectDeviceSize();
- void CalcDeviceSize(CFSTR name);
-
- #endif
-
-public:
- bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
- bool OpenShared(CFSTR fileName, bool shareForWrite);
- bool Open(CFSTR fileName);
-
- #ifndef UNDER_CE
-
- bool OpenReparse(CFSTR fileName)
- {
- // 17.02 fix: to support Windows XP compatibility junctions:
- // we use Create() with (desiredAccess = 0) instead of Open() with GENERIC_READ
- return
- Create(fileName, 0,
- // Open(fileName,
- FILE_SHARE_READ, OPEN_EXISTING,
- FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS);
- }
-
- #endif
-
- bool Read1(void *data, UInt32 size, UInt32 &processedSize) throw();
- bool ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw();
- bool Read(void *data, UInt32 size, UInt32 &processedSize) throw();
-};
-
-class COutFile: public CFileBase
-{
-public:
- bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
- bool Open(CFSTR fileName, DWORD creationDisposition);
- bool Create(CFSTR fileName, bool createAlways);
- bool CreateAlways(CFSTR fileName, DWORD flagsAndAttributes);
-
- bool SetTime(const FILETIME *cTime, const FILETIME *aTime, const FILETIME *mTime) throw();
- bool SetMTime(const FILETIME *mTime) throw();
- bool WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw();
- bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw();
- bool SetEndOfFile() throw();
- bool SetLength(UInt64 length) throw();
-};
-
-}}}
-
-#endif
+// Windows/FileIO.h
+
+#ifndef ZIP7_INC_WINDOWS_FILE_IO_H
+#define ZIP7_INC_WINDOWS_FILE_IO_H
+
+#include "../Common/MyWindows.h"
+
+#define Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT (0xA0000003L)
+#define Z7_WIN_IO_REPARSE_TAG_SYMLINK (0xA000000CL)
+#define Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK (0xA000001DL)
+
+#define Z7_WIN_SYMLINK_FLAG_RELATIVE 1
+
+// what the meaning of that FLAG or field (2)?
+#define Z7_WIN_LX_SYMLINK_FLAG 2
+
+#ifdef _WIN32
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+#include <winioctl.h>
+#endif
+
+#else
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#endif
+
+#include "../Common/MyString.h"
+#include "../Common/MyBuffer.h"
+
+#include "../Windows/TimeUtils.h"
+
+#include "Defs.h"
+
+HRESULT GetLastError_noZero_HRESULT();
+
+#define my_FSCTL_SET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 41, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER
+#define my_FSCTL_GET_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 42, METHOD_BUFFERED, FILE_ANY_ACCESS) // REPARSE_DATA_BUFFER
+#define my_FSCTL_DELETE_REPARSE_POINT CTL_CODE(FILE_DEVICE_FILE_SYSTEM, 43, METHOD_BUFFERED, FILE_SPECIAL_ACCESS) // REPARSE_DATA_BUFFER
+
+namespace NWindows {
+namespace NFile {
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL);
+#endif
+
+struct CReparseShortInfo
+{
+ unsigned Offset;
+ unsigned Size;
+
+ bool Parse(const Byte *p, size_t size);
+};
+
+struct CReparseAttr
+{
+ UInt32 Tag;
+ UInt32 Flags;
+ UString SubsName;
+ UString PrintName;
+
+ AString WslName;
+
+ bool HeaderError;
+ bool TagIsUnknown;
+ bool MinorError;
+ DWORD ErrorCode;
+
+ CReparseAttr(): Tag(0), Flags(0) {}
+
+ // Parse()
+ // returns (true) and (ErrorCode = 0), if (it'a correct known link)
+ // returns (false) and (ErrorCode = ERROR_REPARSE_TAG_INVALID), if unknown tag
+ bool Parse(const Byte *p, size_t size);
+
+ bool IsMountPoint() const { return Tag == Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT; } // it's Junction
+ bool IsSymLink_Win() const { return Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK; }
+ bool IsSymLink_WSL() const { return Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK; }
+
+ bool IsRelative_Win() const { return Flags == Z7_WIN_SYMLINK_FLAG_RELATIVE; }
+
+ bool IsRelative_WSL() const
+ {
+ if (WslName.IsEmpty())
+ return true;
+ char c = WslName[0];
+ return !IS_PATH_SEPAR(c);
+ }
+
+ // bool IsVolume() const;
+
+ bool IsOkNamePair() const;
+ UString GetPath() const;
+};
+
+#ifdef _WIN32
+#define CFiInfo BY_HANDLE_FILE_INFORMATION
+#define ST_MTIME(st) (st).ftLastWriteTime
+#else
+#define CFiInfo stat
+#endif
+
+#ifdef _WIN32
+
+namespace NIO {
+
+bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo = NULL);
+bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size);
+bool DeleteReparseData(CFSTR path);
+
+class CFileBase MY_UNCOPYABLE
+{
+protected:
+ HANDLE _handle;
+
+ bool Create(CFSTR path, DWORD desiredAccess,
+ DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+
+public:
+
+ bool DeviceIoControl(DWORD controlCode, LPVOID inBuffer, DWORD inSize,
+ LPVOID outBuffer, DWORD outSize, LPDWORD bytesReturned, LPOVERLAPPED overlapped = NULL) const
+ {
+ return BOOLToBool(::DeviceIoControl(_handle, controlCode, inBuffer, inSize,
+ outBuffer, outSize, bytesReturned, overlapped));
+ }
+
+ bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize, LPDWORD bytesReturned) const
+ {
+ return DeviceIoControl(controlCode, NULL, 0, outBuffer, outSize, bytesReturned);
+ }
+
+ bool DeviceIoControlOut(DWORD controlCode, LPVOID outBuffer, DWORD outSize) const
+ {
+ DWORD bytesReturned;
+ return DeviceIoControlOut(controlCode, outBuffer, outSize, &bytesReturned);
+ }
+
+public:
+ bool PreserveATime;
+ #ifdef Z7_DEVICE_FILE
+ bool IsDeviceFile;
+ bool SizeDefined;
+ UInt64 Size; // it can be larger than real available size
+ #endif
+
+ CFileBase(): _handle(INVALID_HANDLE_VALUE), PreserveATime(false) {}
+ ~CFileBase() { Close(); }
+
+ HANDLE GetHandle() const { return _handle; }
+
+ // void Detach() { _handle = INVALID_HANDLE_VALUE; }
+
+ bool Close() throw();
+
+ bool GetPosition(UInt64 &position) const throw();
+ bool GetLength(UInt64 &length) const throw();
+
+ bool Seek(Int64 distanceToMove, DWORD moveMethod, UInt64 &newPosition) const throw();
+ bool Seek(UInt64 position, UInt64 &newPosition) const throw();
+ bool SeekToBegin() const throw();
+ bool SeekToEnd(UInt64 &newPosition) const throw();
+
+ bool GetFileInformation(BY_HANDLE_FILE_INFORMATION *info) const
+ { return BOOLToBool(GetFileInformationByHandle(_handle, info)); }
+
+ static bool GetFileInformation(CFSTR path, BY_HANDLE_FILE_INFORMATION *info)
+ {
+ // probably it can work for complex paths: unsupported by another things
+ NIO::CFileBase file;
+ if (!file.Create(path, 0, FILE_SHARE_READ, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS))
+ return false;
+ return file.GetFileInformation(info);
+ }
+};
+
+#ifndef UNDER_CE
+#define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
+#define IOCTL_CDROM_GET_DRIVE_GEOMETRY CTL_CODE(IOCTL_CDROM_BASE, 0x0013, METHOD_BUFFERED, FILE_READ_ACCESS)
+// #define IOCTL_CDROM_MEDIA_REMOVAL CTL_CODE(IOCTL_CDROM_BASE, 0x0201, METHOD_BUFFERED, FILE_READ_ACCESS)
+
+// IOCTL_DISK_GET_DRIVE_GEOMETRY_EX works since WinXP
+#define my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX CTL_CODE(IOCTL_DISK_BASE, 0x0028, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+struct my_DISK_GEOMETRY_EX
+{
+ DISK_GEOMETRY Geometry;
+ LARGE_INTEGER DiskSize;
+ BYTE Data[1];
+};
+#endif
+
+class CInFile: public CFileBase
+{
+ #ifdef Z7_DEVICE_FILE
+
+ #ifndef UNDER_CE
+
+ bool GetGeometry(DISK_GEOMETRY *res) const
+ { return DeviceIoControlOut(IOCTL_DISK_GET_DRIVE_GEOMETRY, res, sizeof(*res)); }
+
+ bool GetGeometryEx(my_DISK_GEOMETRY_EX *res) const
+ { return DeviceIoControlOut(my_IOCTL_DISK_GET_DRIVE_GEOMETRY_EX, res, sizeof(*res)); }
+
+ bool GetCdRomGeometry(DISK_GEOMETRY *res) const
+ { return DeviceIoControlOut(IOCTL_CDROM_GET_DRIVE_GEOMETRY, res, sizeof(*res)); }
+
+ bool GetPartitionInfo(PARTITION_INFORMATION *res)
+ { return DeviceIoControlOut(IOCTL_DISK_GET_PARTITION_INFO, LPVOID(res), sizeof(*res)); }
+
+ #endif
+
+ void CorrectDeviceSize();
+ void CalcDeviceSize(CFSTR name);
+
+ #endif
+
+public:
+ bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+ bool OpenShared(CFSTR fileName, bool shareForWrite);
+ bool Open(CFSTR fileName);
+
+ #ifndef UNDER_CE
+
+ bool Open_for_ReadAttributes(CFSTR fileName)
+ {
+ return Create(fileName, FILE_READ_ATTRIBUTES,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS);
+ // we must use (FILE_FLAG_BACKUP_SEMANTICS) to open handle of directory.
+ }
+
+ bool Open_for_FileRenameInformation(CFSTR fileName)
+ {
+ return Create(fileName, DELETE | SYNCHRONIZE | GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
+ OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL);
+ // we must use (FILE_FLAG_BACKUP_SEMANTICS) to open handle of directory.
+ }
+
+ bool OpenReparse(CFSTR fileName)
+ {
+ // 17.02 fix: to support Windows XP compatibility junctions:
+ // we use Create() with (desiredAccess = 0) instead of Open() with GENERIC_READ
+ return
+ Create(fileName, 0,
+ // Open(fileName,
+ FILE_SHARE_READ, OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS);
+ }
+
+ #endif
+
+ bool Read1(void *data, UInt32 size, UInt32 &processedSize) throw();
+ bool ReadPart(void *data, UInt32 size, UInt32 &processedSize) throw();
+ bool Read(void *data, UInt32 size, UInt32 &processedSize) throw();
+ bool ReadFull(void *data, size_t size, size_t &processedSize) throw();
+};
+
+class COutFile: public CFileBase
+{
+public:
+ bool Open(CFSTR fileName, DWORD shareMode, DWORD creationDisposition, DWORD flagsAndAttributes);
+ bool Open(CFSTR fileName, DWORD creationDisposition);
+ bool Create(CFSTR fileName, bool createAlways);
+ bool CreateAlways(CFSTR fileName, DWORD flagsAndAttributes);
+
+ bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw();
+ bool SetMTime(const CFiTime *mTime) throw();
+ bool WritePart(const void *data, UInt32 size, UInt32 &processedSize) throw();
+ bool Write(const void *data, UInt32 size, UInt32 &processedSize) throw();
+ bool WriteFull(const void *data, size_t size) throw();
+ bool SetEndOfFile() throw();
+ bool SetLength(UInt64 length) throw();
+ bool SetLength_KeepPosition(UInt64 length) throw();
+};
+
+}
+
+
+#else // _WIN32
+
+namespace NIO {
+
+bool GetReparseData(CFSTR path, CByteBuffer &reparseData);
+// bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size);
+
+// parameters are in reverse order of symlink() function !!!
+bool SetSymLink(CFSTR from, CFSTR to);
+bool SetSymLink_UString(CFSTR from, const UString &to);
+
+
+class CFileBase
+{
+protected:
+ int _handle;
+
+ /*
+ bool IsDeviceFile;
+ bool SizeDefined;
+ UInt64 Size; // it can be larger than real available size
+ */
+
+ bool OpenBinary(const char *name, int flags, mode_t mode = 0666);
+public:
+ bool PreserveATime;
+
+ CFileBase(): _handle(-1), PreserveATime(false) {}
+ ~CFileBase() { Close(); }
+ // void Detach() { _handle = -1; }
+ bool Close();
+ bool GetLength(UInt64 &length) const;
+ off_t seek(off_t distanceToMove, int moveMethod) const;
+ off_t seekToBegin() const throw();
+ off_t seekToCur() const throw();
+ // bool SeekToBegin() throw();
+ int my_fstat(struct stat *st) const { return fstat(_handle, st); }
+ /*
+ int my_ioctl_BLKGETSIZE64(unsigned long long *val);
+ int GetDeviceSize_InBytes(UInt64 &size);
+ void CalcDeviceSize(CFSTR s);
+ */
+};
+
+class CInFile: public CFileBase
+{
+public:
+ bool Open(const char *name);
+ bool OpenShared(const char *name, bool shareForWrite);
+ ssize_t read_part(void *data, size_t size) throw();
+ // ssize_t read_full(void *data, size_t size, size_t &processed);
+ bool ReadFull(void *data, size_t size, size_t &processedSize) throw();
+};
+
+class COutFile: public CFileBase
+{
+ bool CTime_defined;
+ bool ATime_defined;
+ bool MTime_defined;
+ CFiTime CTime;
+ CFiTime ATime;
+ CFiTime MTime;
+
+ AString Path;
+ ssize_t write_part(const void *data, size_t size) throw();
+public:
+ mode_t mode_for_Create;
+
+ COutFile():
+ CTime_defined(false),
+ ATime_defined(false),
+ MTime_defined(false),
+ mode_for_Create(0666)
+ {}
+
+ bool Close();
+ bool Create(const char *name, bool createAlways);
+ bool Open(const char *name, DWORD creationDisposition);
+ ssize_t write_full(const void *data, size_t size, size_t &processed) throw();
+
+ bool WriteFull(const void *data, size_t size) throw()
+ {
+ size_t processed;
+ ssize_t res = write_full(data, size, processed);
+ if (res == -1)
+ return false;
+ return processed == size;
+ }
+
+ bool SetLength(UInt64 length) throw();
+ bool SetLength_KeepPosition(UInt64 length) throw()
+ {
+ return SetLength(length);
+ }
+ bool SetTime(const CFiTime *cTime, const CFiTime *aTime, const CFiTime *mTime) throw();
+ bool SetMTime(const CFiTime *mTime) throw();
+};
+
+}
+
+#endif // _WIN32
+
+}}
+
+
+#endif
diff --git a/CPP/Windows/FileLink.cpp b/CPP/Windows/FileLink.cpp
index b5e47e7..2b9fa1a 100644
--- a/CPP/Windows/FileLink.cpp
+++ b/CPP/Windows/FileLink.cpp
@@ -1,440 +1,622 @@
-// Windows/FileLink.cpp
-
-#include "StdAfx.h"
-
-#include "../../C/CpuArch.h"
-
-#ifdef SUPPORT_DEVICE_FILE
-#include "../../C/Alloc.h"
-#endif
-
-#include "FileDir.h"
-#include "FileFind.h"
-#include "FileIO.h"
-#include "FileName.h"
-
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-namespace NWindows {
-namespace NFile {
-
-using namespace NName;
-
-/*
- Reparse Points (Junctions and Symbolic Links):
- struct
- {
- UInt32 Tag;
- UInt16 Size; // not including starting 8 bytes
- UInt16 Reserved; // = 0
-
- UInt16 SubstituteOffset; // offset in bytes from start of namesChars
- UInt16 SubstituteLen; // size in bytes, it doesn't include tailed NUL
- UInt16 PrintOffset; // offset in bytes from start of namesChars
- UInt16 PrintLen; // size in bytes, it doesn't include tailed NUL
-
- [UInt32] Flags; // for Symbolic Links only.
-
- UInt16 namesChars[]
- }
-
- MOUNT_POINT (Junction point):
- 1) there is NUL wchar after path
- 2) Default Order in table:
- Substitute Path
- Print Path
- 3) pathnames can not contain dot directory names
-
- SYMLINK:
- 1) there is no NUL wchar after path
- 2) Default Order in table:
- Print Path
- Substitute Path
-*/
-
-/*
-static const UInt32 kReparseFlags_Alias = (1 << 29);
-static const UInt32 kReparseFlags_HighLatency = (1 << 30);
-static const UInt32 kReparseFlags_Microsoft = ((UInt32)1 << 31);
-
-#define _my_IO_REPARSE_TAG_HSM (0xC0000004L)
-#define _my_IO_REPARSE_TAG_HSM2 (0x80000006L)
-#define _my_IO_REPARSE_TAG_SIS (0x80000007L)
-#define _my_IO_REPARSE_TAG_WIM (0x80000008L)
-#define _my_IO_REPARSE_TAG_CSV (0x80000009L)
-#define _my_IO_REPARSE_TAG_DFS (0x8000000AL)
-#define _my_IO_REPARSE_TAG_DFSR (0x80000012L)
-*/
-
-#define Get16(p) GetUi16(p)
-#define Get32(p) GetUi32(p)
-
-#define Set16(p, v) SetUi16(p, v)
-#define Set32(p, v) SetUi32(p, v)
-
-static const wchar_t * const k_LinkPrefix = L"\\??\\";
-static const unsigned k_LinkPrefix_Size = 4;
-
-static const bool IsLinkPrefix(const wchar_t *s)
-{
- return IsString1PrefixedByString2(s, k_LinkPrefix);
-}
-
-/*
-static const wchar_t * const k_VolumePrefix = L"Volume{";
-static const bool IsVolumeName(const wchar_t *s)
-{
- return IsString1PrefixedByString2(s, k_VolumePrefix);
-}
-*/
-
-void WriteString(Byte *dest, const wchar_t *path)
-{
- for (;;)
- {
- wchar_t c = *path++;
- if (c == 0)
- return;
- Set16(dest, (UInt16)c);
- dest += 2;
- }
-}
-
-#if defined(_WIN32) && !defined(UNDER_CE)
-
-bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink)
-{
- bool isAbs = IsAbsolutePath(path);
- if (!isAbs && !isSymLink)
- return false;
-
- bool needPrintName = true;
-
- if (IsSuperPath(path))
- {
- path += kSuperPathPrefixSize;
- if (!IsDrivePath(path))
- needPrintName = false;
- }
-
- const unsigned add_Prefix_Len = isAbs ? k_LinkPrefix_Size : 0;
-
- unsigned len2 = MyStringLen(path) * 2;
- const unsigned len1 = len2 + add_Prefix_Len * 2;
- if (!needPrintName)
- len2 = 0;
-
- unsigned totalNamesSize = (len1 + len2);
-
- /* some WIM imagex software uses old scheme for symbolic links.
- so we can old scheme for byte to byte compatibility */
-
- bool newOrderScheme = isSymLink;
- // newOrderScheme = false;
-
- if (!newOrderScheme)
- totalNamesSize += 2 * 2;
-
- const size_t size = 8 + 8 + (isSymLink ? 4 : 0) + totalNamesSize;
- dest.Alloc(size);
- memset(dest, 0, size);
- const UInt32 tag = isSymLink ?
- _my_IO_REPARSE_TAG_SYMLINK :
- _my_IO_REPARSE_TAG_MOUNT_POINT;
- Byte *p = dest;
- Set32(p, tag);
- Set16(p + 4, (UInt16)(size - 8));
- Set16(p + 6, 0);
- p += 8;
-
- unsigned subOffs = 0;
- unsigned printOffs = 0;
- if (newOrderScheme)
- subOffs = len2;
- else
- printOffs = len1 + 2;
-
- Set16(p + 0, (UInt16)subOffs);
- Set16(p + 2, (UInt16)len1);
- Set16(p + 4, (UInt16)printOffs);
- Set16(p + 6, (UInt16)len2);
-
- p += 8;
- if (isSymLink)
- {
- UInt32 flags = isAbs ? 0 : _my_SYMLINK_FLAG_RELATIVE;
- Set32(p, flags);
- p += 4;
- }
-
- if (add_Prefix_Len != 0)
- WriteString(p + subOffs, k_LinkPrefix);
- WriteString(p + subOffs + add_Prefix_Len * 2, path);
- if (needPrintName)
- WriteString(p + printOffs, path);
- return true;
-}
-
-#endif
-
-static void GetString(const Byte *p, unsigned len, UString &res)
-{
- wchar_t *s = res.GetBuf(len);
- unsigned i;
- for (i = 0; i < len; i++)
- {
- wchar_t c = Get16(p + i * 2);
- if (c == 0)
- break;
- s[i] = c;
- }
- s[i] = 0;
- res.ReleaseBuf_SetLen(i);
-}
-
-bool CReparseAttr::Parse(const Byte *p, size_t size, DWORD &errorCode)
-{
- errorCode = ERROR_INVALID_REPARSE_DATA;
- if (size < 8)
- return false;
- Tag = Get32(p);
- UInt32 len = Get16(p + 4);
- if (len + 8 > size)
- return false;
- /*
- if ((type & kReparseFlags_Alias) == 0 ||
- (type & kReparseFlags_Microsoft) == 0 ||
- (type & 0xFFFF) != 3)
- */
- if (Tag != _my_IO_REPARSE_TAG_MOUNT_POINT &&
- Tag != _my_IO_REPARSE_TAG_SYMLINK)
- {
- errorCode = ERROR_REPARSE_TAG_MISMATCH; // ERROR_REPARSE_TAG_INVALID
- return false;
- }
-
- if (Get16(p + 6) != 0) // padding
- return false;
-
- p += 8;
- size -= 8;
-
- if (len != size) // do we need that check?
- return false;
-
- if (len < 8)
- return false;
- unsigned subOffs = Get16(p);
- unsigned subLen = Get16(p + 2);
- unsigned printOffs = Get16(p + 4);
- unsigned printLen = Get16(p + 6);
- len -= 8;
- p += 8;
-
- Flags = 0;
- if (Tag == _my_IO_REPARSE_TAG_SYMLINK)
- {
- if (len < 4)
- return false;
- Flags = Get32(p);
- len -= 4;
- p += 4;
- }
-
- if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen)
- return false;
- if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen)
- return false;
- GetString(p + subOffs, subLen >> 1, SubsName);
- GetString(p + printOffs, printLen >> 1, PrintName);
-
- errorCode = 0;
- return true;
-}
-
-bool CReparseShortInfo::Parse(const Byte *p, size_t size)
-{
- const Byte *start = p;
- Offset= 0;
- Size = 0;
- if (size < 8)
- return false;
- UInt32 Tag = Get32(p);
- UInt32 len = Get16(p + 4);
- if (len + 8 > size)
- return false;
- /*
- if ((type & kReparseFlags_Alias) == 0 ||
- (type & kReparseFlags_Microsoft) == 0 ||
- (type & 0xFFFF) != 3)
- */
- if (Tag != _my_IO_REPARSE_TAG_MOUNT_POINT &&
- Tag != _my_IO_REPARSE_TAG_SYMLINK)
- // return true;
- return false;
-
- if (Get16(p + 6) != 0) // padding
- return false;
-
- p += 8;
- size -= 8;
-
- if (len != size) // do we need that check?
- return false;
-
- if (len < 8)
- return false;
- unsigned subOffs = Get16(p);
- unsigned subLen = Get16(p + 2);
- unsigned printOffs = Get16(p + 4);
- unsigned printLen = Get16(p + 6);
- len -= 8;
- p += 8;
-
- // UInt32 Flags = 0;
- if (Tag == _my_IO_REPARSE_TAG_SYMLINK)
- {
- if (len < 4)
- return false;
- // Flags = Get32(p);
- len -= 4;
- p += 4;
- }
-
- if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen)
- return false;
- if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen)
- return false;
-
- Offset = (unsigned)(p - start) + subOffs;
- Size = subLen;
- return true;
-}
-
-bool CReparseAttr::IsOkNamePair() const
-{
- if (IsLinkPrefix(SubsName))
- {
- if (!IsDrivePath(SubsName.Ptr(k_LinkPrefix_Size)))
- return PrintName.IsEmpty();
- if (wcscmp(SubsName.Ptr(k_LinkPrefix_Size), PrintName) == 0)
- return true;
- }
- return wcscmp(SubsName, PrintName) == 0;
-}
-
-/*
-bool CReparseAttr::IsVolume() const
-{
- if (!IsLinkPrefix(SubsName))
- return false;
- return IsVolumeName(SubsName.Ptr(k_LinkPrefix_Size));
-}
-*/
-
-UString CReparseAttr::GetPath() const
-{
- UString s (SubsName);
- if (IsLinkPrefix(s))
- {
- s.ReplaceOneCharAtPos(1, '\\');
- if (IsDrivePath(s.Ptr(k_LinkPrefix_Size)))
- s.DeleteFrontal(k_LinkPrefix_Size);
- }
- return s;
-}
-
-
-#ifdef SUPPORT_DEVICE_FILE
-
-namespace NSystem
-{
-bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
-}
-#endif
-
-#ifndef UNDER_CE
-
-namespace NIO {
-
-bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo)
-{
- reparseData.Free();
- CInFile file;
- if (!file.OpenReparse(path))
- return false;
-
- if (fileInfo)
- file.GetFileInformation(fileInfo);
-
- const unsigned kBufSize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
- CByteArr buf(kBufSize);
- DWORD returnedSize;
- if (!file.DeviceIoControlOut(my_FSCTL_GET_REPARSE_POINT, buf, kBufSize, &returnedSize))
- return false;
- reparseData.CopyFrom(buf, returnedSize);
- return true;
-}
-
-static bool CreatePrefixDirOfFile(CFSTR path)
-{
- FString path2 (path);
- int pos = path2.ReverseFind_PathSepar();
- if (pos < 0)
- return true;
- #ifdef _WIN32
- if (pos == 2 && path2[1] == L':')
- return true; // we don't create Disk folder;
- #endif
- path2.DeleteFrom(pos);
- return NDir::CreateComplexDir(path2);
-}
-
-// If there is Reprase data already, it still writes new Reparse data
-bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size)
-{
- NFile::NFind::CFileInfo fi;
- if (fi.Find(path))
- {
- if (fi.IsDir() != isDir)
- {
- ::SetLastError(ERROR_DIRECTORY);
- return false;
- }
- }
- else
- {
- if (isDir)
- {
- if (!NDir::CreateComplexDir(path))
- return false;
- }
- else
- {
- CreatePrefixDirOfFile(path);
- COutFile file;
- if (!file.Create(path, CREATE_NEW))
- return false;
- }
- }
-
- COutFile file;
- if (!file.Open(path,
- FILE_SHARE_WRITE,
- OPEN_EXISTING,
- FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS))
- return false;
-
- DWORD returnedSize;
- if (!file.DeviceIoControl(my_FSCTL_SET_REPARSE_POINT, (void *)data, size, NULL, 0, &returnedSize))
- return false;
- return true;
-}
-
-}
-
-#endif
-
-}}
+// Windows/FileLink.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/CpuArch.h"
+
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+#ifdef Z7_DEVICE_FILE
+#include "../../C/Alloc.h"
+#endif
+
+#include "../Common/UTFConvert.h"
+#include "../Common/StringConvert.h"
+
+#include "FileDir.h"
+#include "FileFind.h"
+#include "FileIO.h"
+#include "FileName.h"
+
+#ifdef Z7_OLD_WIN_SDK
+#ifndef ERROR_INVALID_REPARSE_DATA
+#define ERROR_INVALID_REPARSE_DATA 4392L
+#endif
+#ifndef ERROR_REPARSE_TAG_INVALID
+#define ERROR_REPARSE_TAG_INVALID 4393L
+#endif
+#endif
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NFile {
+
+using namespace NName;
+
+/*
+ Reparse Points (Junctions and Symbolic Links):
+ struct
+ {
+ UInt32 Tag;
+ UInt16 Size; // not including starting 8 bytes
+ UInt16 Reserved; // = 0
+
+ UInt16 SubstituteOffset; // offset in bytes from start of namesChars
+ UInt16 SubstituteLen; // size in bytes, it doesn't include tailed NUL
+ UInt16 PrintOffset; // offset in bytes from start of namesChars
+ UInt16 PrintLen; // size in bytes, it doesn't include tailed NUL
+
+ [UInt32] Flags; // for Symbolic Links only.
+
+ UInt16 namesChars[]
+ }
+
+ MOUNT_POINT (Junction point):
+ 1) there is NUL wchar after path
+ 2) Default Order in table:
+ Substitute Path
+ Print Path
+ 3) pathnames can not contain dot directory names
+
+ SYMLINK:
+ 1) there is no NUL wchar after path
+ 2) Default Order in table:
+ Print Path
+ Substitute Path
+*/
+
+/*
+Win10 WSL2:
+admin rights + sudo: it creates normal windows symbolic link.
+in another cases : it creates IO_REPARSE_TAG_LX_SYMLINK repare point.
+*/
+
+/*
+static const UInt32 kReparseFlags_Alias = (1 << 29);
+static const UInt32 kReparseFlags_HighLatency = (1 << 30);
+static const UInt32 kReparseFlags_Microsoft = ((UInt32)1 << 31);
+
+#define Z7_WIN_IO_REPARSE_TAG_HSM (0xC0000004L)
+#define Z7_WIN_IO_REPARSE_TAG_HSM2 (0x80000006L)
+#define Z7_WIN_IO_REPARSE_TAG_SIS (0x80000007L)
+#define Z7_WIN_IO_REPARSE_TAG_WIM (0x80000008L)
+#define Z7_WIN_IO_REPARSE_TAG_CSV (0x80000009L)
+#define Z7_WIN_IO_REPARSE_TAG_DFS (0x8000000AL)
+#define Z7_WIN_IO_REPARSE_TAG_DFSR (0x80000012L)
+*/
+
+#define Get16(p) GetUi16(p)
+#define Get32(p) GetUi32(p)
+
+static const wchar_t * const k_LinkPrefix = L"\\??\\";
+static const unsigned k_LinkPrefix_Size = 4;
+
+static bool IsLinkPrefix(const wchar_t *s)
+{
+ return IsString1PrefixedByString2(s, k_LinkPrefix);
+}
+
+/*
+static const wchar_t * const k_VolumePrefix = L"Volume{";
+static const bool IsVolumeName(const wchar_t *s)
+{
+ return IsString1PrefixedByString2(s, k_VolumePrefix);
+}
+*/
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+
+#define Set16(p, v) SetUi16(p, v)
+#define Set32(p, v) SetUi32(p, v)
+
+static void WriteString(Byte *dest, const wchar_t *path)
+{
+ for (;;)
+ {
+ wchar_t c = *path++;
+ if (c == 0)
+ return;
+ Set16(dest, (UInt16)c)
+ dest += 2;
+ }
+}
+
+bool FillLinkData(CByteBuffer &dest, const wchar_t *path, bool isSymLink, bool isWSL)
+{
+ bool isAbs = IsAbsolutePath(path);
+ if (!isAbs && !isSymLink)
+ return false;
+
+ if (isWSL)
+ {
+ // unsupported characters probably use Replacement Character UTF-16 0xFFFD
+ AString utf;
+ ConvertUnicodeToUTF8(path, utf);
+ const size_t size = 4 + utf.Len();
+ if (size != (UInt16)size)
+ return false;
+ dest.Alloc(8 + size);
+ Byte *p = dest;
+ Set32(p, Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK)
+ Set16(p + 4, (UInt16)(size))
+ Set16(p + 6, 0)
+ Set32(p + 8, Z7_WIN_LX_SYMLINK_FLAG)
+ memcpy(p + 12, utf.Ptr(), utf.Len());
+ return true;
+ }
+
+ // usual symbolic LINK (NOT WSL)
+
+ bool needPrintName = true;
+
+ if (IsSuperPath(path))
+ {
+ path += kSuperPathPrefixSize;
+ if (!IsDrivePath(path))
+ needPrintName = false;
+ }
+
+ const unsigned add_Prefix_Len = isAbs ? k_LinkPrefix_Size : 0;
+
+ size_t len2 = (size_t)MyStringLen(path) * 2;
+ const size_t len1 = len2 + add_Prefix_Len * 2;
+ if (!needPrintName)
+ len2 = 0;
+
+ size_t totalNamesSize = (len1 + len2);
+
+ /* some WIM imagex software uses old scheme for symbolic links.
+ so we can old scheme for byte to byte compatibility */
+
+ bool newOrderScheme = isSymLink;
+ // newOrderScheme = false;
+
+ if (!newOrderScheme)
+ totalNamesSize += 2 * 2;
+
+ const size_t size = 8 + 8 + (isSymLink ? 4 : 0) + totalNamesSize;
+ if (size != (UInt16)size)
+ return false;
+ dest.Alloc(size);
+ memset(dest, 0, size);
+ const UInt32 tag = isSymLink ?
+ Z7_WIN_IO_REPARSE_TAG_SYMLINK :
+ Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT;
+ Byte *p = dest;
+ Set32(p, tag)
+ Set16(p + 4, (UInt16)(size - 8))
+ Set16(p + 6, 0)
+ p += 8;
+
+ unsigned subOffs = 0;
+ unsigned printOffs = 0;
+ if (newOrderScheme)
+ subOffs = (unsigned)len2;
+ else
+ printOffs = (unsigned)len1 + 2;
+
+ Set16(p + 0, (UInt16)subOffs)
+ Set16(p + 2, (UInt16)len1)
+ Set16(p + 4, (UInt16)printOffs)
+ Set16(p + 6, (UInt16)len2)
+
+ p += 8;
+ if (isSymLink)
+ {
+ UInt32 flags = isAbs ? 0 : Z7_WIN_SYMLINK_FLAG_RELATIVE;
+ Set32(p, flags)
+ p += 4;
+ }
+
+ if (add_Prefix_Len != 0)
+ WriteString(p + subOffs, k_LinkPrefix);
+ WriteString(p + subOffs + add_Prefix_Len * 2, path);
+ if (needPrintName)
+ WriteString(p + printOffs, path);
+ return true;
+}
+
+#endif // defined(_WIN32) && !defined(UNDER_CE)
+
+
+static void GetString(const Byte *p, unsigned len, UString &res)
+{
+ wchar_t *s = res.GetBuf(len);
+ unsigned i;
+ for (i = 0; i < len; i++)
+ {
+ wchar_t c = Get16(p + i * 2);
+ if (c == 0)
+ break;
+ s[i] = c;
+ }
+ s[i] = 0;
+ res.ReleaseBuf_SetLen(i);
+}
+
+bool CReparseAttr::Parse(const Byte *p, size_t size)
+{
+ ErrorCode = (DWORD)ERROR_INVALID_REPARSE_DATA;
+ HeaderError = true;
+ TagIsUnknown = true;
+ MinorError = false;
+
+ if (size < 8)
+ return false;
+ Tag = Get32(p);
+ UInt32 len = Get16(p + 4);
+ if (len + 8 != size)
+ // if (len + 8 > size)
+ return false;
+ /*
+ if ((type & kReparseFlags_Alias) == 0 ||
+ (type & kReparseFlags_Microsoft) == 0 ||
+ (type & 0xFFFF) != 3)
+ */
+
+ if (Get16(p + 6) != 0) // padding
+ return false;
+
+ HeaderError = false;
+
+ if ( Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT
+ && Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK
+ && Tag != Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK)
+ {
+ // for unsupported reparse points
+ ErrorCode = (DWORD)ERROR_REPARSE_TAG_INVALID; // ERROR_REPARSE_TAG_MISMATCH
+ // errorCode = ERROR_REPARSE_TAG_MISMATCH; // ERROR_REPARSE_TAG_INVALID
+ return false;
+ }
+
+ TagIsUnknown = false;
+
+ p += 8;
+ size -= 8;
+
+ if (Tag == Z7_WIN_IO_REPARSE_TAG_LX_SYMLINK)
+ {
+ if (len < 4)
+ return false;
+ Flags = Get32(p); // maybe it's not Flags
+ if (Flags != Z7_WIN_LX_SYMLINK_FLAG)
+ return false;
+ len -= 4;
+ p += 4;
+ char *s = WslName.GetBuf(len);
+ unsigned i;
+ for (i = 0; i < len; i++)
+ {
+ char c = (char)p[i];
+ s[i] = c;
+ if (c == 0)
+ break;
+ }
+ WslName.ReleaseBuf_SetEnd(i);
+ MinorError = (i != len);
+ ErrorCode = 0;
+ return true;
+ }
+
+ if (len < 8)
+ return false;
+ unsigned subOffs = Get16(p);
+ unsigned subLen = Get16(p + 2);
+ unsigned printOffs = Get16(p + 4);
+ unsigned printLen = Get16(p + 6);
+ len -= 8;
+ p += 8;
+
+ Flags = 0;
+ if (Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK)
+ {
+ if (len < 4)
+ return false;
+ Flags = Get32(p);
+ len -= 4;
+ p += 4;
+ }
+
+ if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen)
+ return false;
+ if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen)
+ return false;
+ GetString(p + subOffs, subLen >> 1, SubsName);
+ GetString(p + printOffs, printLen >> 1, PrintName);
+
+ ErrorCode = 0;
+ return true;
+}
+
+
+bool CReparseShortInfo::Parse(const Byte *p, size_t size)
+{
+ const Byte *start = p;
+ Offset= 0;
+ Size = 0;
+ if (size < 8)
+ return false;
+ UInt32 Tag = Get32(p);
+ UInt32 len = Get16(p + 4);
+ if (len + 8 > size)
+ return false;
+ /*
+ if ((type & kReparseFlags_Alias) == 0 ||
+ (type & kReparseFlags_Microsoft) == 0 ||
+ (type & 0xFFFF) != 3)
+ */
+ if (Tag != Z7_WIN_IO_REPARSE_TAG_MOUNT_POINT &&
+ Tag != Z7_WIN_IO_REPARSE_TAG_SYMLINK)
+ // return true;
+ return false;
+
+ if (Get16(p + 6) != 0) // padding
+ return false;
+
+ p += 8;
+ size -= 8;
+
+ if (len != size) // do we need that check?
+ return false;
+
+ if (len < 8)
+ return false;
+ unsigned subOffs = Get16(p);
+ unsigned subLen = Get16(p + 2);
+ unsigned printOffs = Get16(p + 4);
+ unsigned printLen = Get16(p + 6);
+ len -= 8;
+ p += 8;
+
+ // UInt32 Flags = 0;
+ if (Tag == Z7_WIN_IO_REPARSE_TAG_SYMLINK)
+ {
+ if (len < 4)
+ return false;
+ // Flags = Get32(p);
+ len -= 4;
+ p += 4;
+ }
+
+ if ((subOffs & 1) != 0 || subOffs > len || len - subOffs < subLen)
+ return false;
+ if ((printOffs & 1) != 0 || printOffs > len || len - printOffs < printLen)
+ return false;
+
+ Offset = (unsigned)(p - start) + subOffs;
+ Size = subLen;
+ return true;
+}
+
+bool CReparseAttr::IsOkNamePair() const
+{
+ if (IsLinkPrefix(SubsName))
+ {
+ if (!IsDrivePath(SubsName.Ptr(k_LinkPrefix_Size)))
+ return PrintName.IsEmpty();
+ if (wcscmp(SubsName.Ptr(k_LinkPrefix_Size), PrintName) == 0)
+ return true;
+ }
+ return wcscmp(SubsName, PrintName) == 0;
+}
+
+/*
+bool CReparseAttr::IsVolume() const
+{
+ if (!IsLinkPrefix(SubsName))
+ return false;
+ return IsVolumeName(SubsName.Ptr(k_LinkPrefix_Size));
+}
+*/
+
+UString CReparseAttr::GetPath() const
+{
+ if (IsSymLink_WSL())
+ {
+ UString u;
+ // if (CheckUTF8(attr.WslName)
+ if (!ConvertUTF8ToUnicode(WslName, u))
+ MultiByteToUnicodeString2(u, WslName);
+ return u;
+ }
+
+ UString s (SubsName);
+ if (IsLinkPrefix(s))
+ {
+ s.ReplaceOneCharAtPos(1, '\\'); // we normalize prefix from "\??\" to "\\?\"
+ if (IsDrivePath(s.Ptr(k_LinkPrefix_Size)))
+ s.DeleteFrontal(k_LinkPrefix_Size);
+ }
+ return s;
+}
+
+#ifdef Z7_DEVICE_FILE
+
+namespace NSystem
+{
+bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
+}
+#endif // Z7_DEVICE_FILE
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+
+namespace NIO {
+
+bool GetReparseData(CFSTR path, CByteBuffer &reparseData, BY_HANDLE_FILE_INFORMATION *fileInfo)
+{
+ reparseData.Free();
+ CInFile file;
+ if (!file.OpenReparse(path))
+ return false;
+
+ if (fileInfo)
+ file.GetFileInformation(fileInfo);
+
+ const unsigned kBufSize = MAXIMUM_REPARSE_DATA_BUFFER_SIZE;
+ CByteArr buf(kBufSize);
+ DWORD returnedSize;
+ if (!file.DeviceIoControlOut(my_FSCTL_GET_REPARSE_POINT, buf, kBufSize, &returnedSize))
+ return false;
+ reparseData.CopyFrom(buf, returnedSize);
+ return true;
+}
+
+static bool CreatePrefixDirOfFile(CFSTR path)
+{
+ FString path2 (path);
+ int pos = path2.ReverseFind_PathSepar();
+ if (pos < 0)
+ return true;
+ #ifdef _WIN32
+ if (pos == 2 && path2[1] == L':')
+ return true; // we don't create Disk folder;
+ #endif
+ path2.DeleteFrom((unsigned)pos);
+ return NDir::CreateComplexDir(path2);
+}
+
+
+static bool OutIoReparseData(DWORD controlCode, CFSTR path, void *data, DWORD size)
+{
+ COutFile file;
+ if (!file.Open(path,
+ FILE_SHARE_WRITE,
+ OPEN_EXISTING,
+ FILE_FLAG_OPEN_REPARSE_POINT | FILE_FLAG_BACKUP_SEMANTICS))
+ return false;
+
+ DWORD returnedSize;
+ return file.DeviceIoControl(controlCode, data, size, NULL, 0, &returnedSize);
+}
+
+
+// If there is Reparse data already, it still writes new Reparse data
+bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size)
+{
+ NFile::NFind::CFileInfo fi;
+ if (fi.Find(path))
+ {
+ if (fi.IsDir() != isDir)
+ {
+ ::SetLastError(ERROR_DIRECTORY);
+ return false;
+ }
+ }
+ else
+ {
+ if (isDir)
+ {
+ if (!NDir::CreateComplexDir(path))
+ return false;
+ }
+ else
+ {
+ CreatePrefixDirOfFile(path);
+ COutFile file;
+ if (!file.Create(path, CREATE_NEW))
+ return false;
+ }
+ }
+
+ return OutIoReparseData(my_FSCTL_SET_REPARSE_POINT, path, (void *)(const Byte *)(data), size);
+}
+
+
+bool DeleteReparseData(CFSTR path)
+{
+ CByteBuffer reparseData;
+ if (!GetReparseData(path, reparseData, NULL))
+ return false;
+ /* MSDN: The tag specified in the ReparseTag member of this structure
+ must match the tag of the reparse point to be deleted,
+ and the ReparseDataLength member must be zero */
+ #define my_REPARSE_DATA_BUFFER_HEADER_SIZE 8
+ if (reparseData.Size() < my_REPARSE_DATA_BUFFER_HEADER_SIZE)
+ {
+ SetLastError(ERROR_INVALID_REPARSE_DATA);
+ return false;
+ }
+ BYTE buf[my_REPARSE_DATA_BUFFER_HEADER_SIZE];
+ memset(buf, 0, sizeof(buf));
+ memcpy(buf, reparseData, 4); // tag
+ return OutIoReparseData(my_FSCTL_DELETE_REPARSE_POINT, path, buf, sizeof(buf));
+}
+
+}
+
+#endif // defined(_WIN32) && !defined(UNDER_CE)
+
+
+#ifndef _WIN32
+
+namespace NIO {
+
+bool GetReparseData(CFSTR path, CByteBuffer &reparseData)
+{
+ reparseData.Free();
+
+ #define MAX_PATHNAME_LEN 1024
+ char buf[MAX_PATHNAME_LEN + 2];
+ const size_t request = sizeof(buf) - 1;
+
+ // printf("\nreadlink() path = %s \n", path);
+ const ssize_t size = readlink(path, buf, request);
+ // there is no tail zero
+
+ if (size < 0)
+ return false;
+ if ((size_t)size >= request)
+ {
+ SetLastError(EINVAL); // check it: ENAMETOOLONG
+ return false;
+ }
+
+ // printf("\nreadlink() res = %s size = %d \n", buf, (int)size);
+ reparseData.CopyFrom((const Byte *)buf, (size_t)size);
+ return true;
+}
+
+
+/*
+// If there is Reparse data already, it still writes new Reparse data
+bool SetReparseData(CFSTR path, bool isDir, const void *data, DWORD size)
+{
+ // AString s;
+ // s.SetFrom_CalcLen(data, size);
+ // return (symlink(s, path) == 0);
+ UNUSED_VAR(path)
+ UNUSED_VAR(isDir)
+ UNUSED_VAR(data)
+ UNUSED_VAR(size)
+ SetLastError(ENOSYS);
+ return false;
+}
+*/
+
+bool SetSymLink(CFSTR from, CFSTR to)
+{
+ // printf("\nsymlink() %s -> %s\n", from, to);
+ int ir;
+ // ir = unlink(path);
+ // if (ir == 0)
+ ir = symlink(to, from);
+ return (ir == 0);
+}
+
+bool SetSymLink_UString(CFSTR from, const UString &to)
+{
+ AString utf;
+ ConvertUnicodeToUTF8(to, utf);
+ return SetSymLink(from, utf);
+}
+
+}
+
+#endif // !_WIN32
+
+}}
diff --git a/CPP/Windows/FileMapping.cpp b/CPP/Windows/FileMapping.cpp
index 01c4a94..1933f7c 100644
--- a/CPP/Windows/FileMapping.cpp
+++ b/CPP/Windows/FileMapping.cpp
@@ -1,12 +1,12 @@
-// Windows/FileMapping.cpp
-
-#include "StdAfx.h"
-
-#include "FileMapping.h"
-
-namespace NWindows {
-namespace NFile {
-namespace NMapping {
-
-
-}}}
+// Windows/FileMapping.cpp
+
+#include "StdAfx.h"
+
+#include "FileMapping.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NMapping {
+
+
+}}}
diff --git a/CPP/Windows/FileMapping.h b/CPP/Windows/FileMapping.h
index 27d076b..caa7ea3 100644
--- a/CPP/Windows/FileMapping.h
+++ b/CPP/Windows/FileMapping.h
@@ -1,66 +1,66 @@
-// Windows/FileMapping.h
-
-#ifndef __WINDOWS_FILEMAPPING_H
-#define __WINDOWS_FILEMAPPING_H
-
-#include "../Common/MyTypes.h"
-
-#include "Handle.h"
-
-namespace NWindows {
-
-class CFileMapping: public CHandle
-{
-public:
- WRes Create(DWORD protect, UInt64 maxSize, LPCTSTR name)
- {
- _handle = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, protect, (DWORD)(maxSize >> 32), (DWORD)maxSize, name);
- return ::GetLastError();
- }
-
- WRes Open(DWORD
- #ifndef UNDER_CE
- desiredAccess
- #endif
- , LPCTSTR name)
- {
- #ifdef UNDER_CE
- WRes res = Create(PAGE_READONLY, 0, name);
- if (res == ERROR_ALREADY_EXISTS)
- return 0;
- Close();
- if (res == 0)
- res = ERROR_FILE_NOT_FOUND;
- return res;
- #else
- _handle = ::OpenFileMapping(desiredAccess, FALSE, name);
- if (_handle != 0)
- return 0;
- return ::GetLastError();
- #endif
- }
-
- LPVOID Map(DWORD desiredAccess, UInt64 fileOffset, SIZE_T numberOfBytesToMap)
- {
- return ::MapViewOfFile(_handle, desiredAccess, (DWORD)(fileOffset >> 32), (DWORD)fileOffset, numberOfBytesToMap);
- }
-
- #ifndef UNDER_CE
- LPVOID Map(DWORD desiredAccess, UInt64 fileOffset, SIZE_T numberOfBytesToMap, LPVOID baseAddress)
- {
- return ::MapViewOfFileEx(_handle, desiredAccess, (DWORD)(fileOffset >> 32), (DWORD)fileOffset, numberOfBytesToMap, baseAddress);
- }
- #endif
-};
-
-class CFileUnmapper
-{
- const void *_data;
-public:
- CFileUnmapper(const void *data) : _data(data) {}
- ~CFileUnmapper() { ::UnmapViewOfFile(_data); }
-};
-
-}
-
-#endif
+// Windows/FileMapping.h
+
+#ifndef ZIP7_INC_WINDOWS_FILE_MAPPING_H
+#define ZIP7_INC_WINDOWS_FILE_MAPPING_H
+
+#include "../Common/MyTypes.h"
+
+#include "Handle.h"
+
+namespace NWindows {
+
+class CFileMapping: public CHandle
+{
+public:
+ WRes Create(DWORD protect, UInt64 maxSize, LPCTSTR name)
+ {
+ _handle = ::CreateFileMapping(INVALID_HANDLE_VALUE, NULL, protect, (DWORD)(maxSize >> 32), (DWORD)maxSize, name);
+ return ::GetLastError();
+ }
+
+ WRes Open(DWORD
+ #ifndef UNDER_CE
+ desiredAccess
+ #endif
+ , LPCTSTR name)
+ {
+ #ifdef UNDER_CE
+ WRes res = Create(PAGE_READONLY, 0, name);
+ if (res == ERROR_ALREADY_EXISTS)
+ return 0;
+ Close();
+ if (res == 0)
+ res = ERROR_FILE_NOT_FOUND;
+ return res;
+ #else
+ _handle = ::OpenFileMapping(desiredAccess, FALSE, name);
+ if (_handle != NULL)
+ return 0;
+ return ::GetLastError();
+ #endif
+ }
+
+ LPVOID Map(DWORD desiredAccess, UInt64 fileOffset, SIZE_T numberOfBytesToMap)
+ {
+ return ::MapViewOfFile(_handle, desiredAccess, (DWORD)(fileOffset >> 32), (DWORD)fileOffset, numberOfBytesToMap);
+ }
+
+ #ifndef UNDER_CE
+ LPVOID Map(DWORD desiredAccess, UInt64 fileOffset, SIZE_T numberOfBytesToMap, LPVOID baseAddress)
+ {
+ return ::MapViewOfFileEx(_handle, desiredAccess, (DWORD)(fileOffset >> 32), (DWORD)fileOffset, numberOfBytesToMap, baseAddress);
+ }
+ #endif
+};
+
+class CFileUnmapper
+{
+ const void *_data;
+public:
+ CFileUnmapper(const void *data) : _data(data) {}
+ ~CFileUnmapper() { ::UnmapViewOfFile(_data); }
+};
+
+}
+
+#endif
diff --git a/CPP/Windows/FileName.cpp b/CPP/Windows/FileName.cpp
index 2a227dc..c9c4f8b 100644
--- a/CPP/Windows/FileName.cpp
+++ b/CPP/Windows/FileName.cpp
@@ -1,839 +1,894 @@
-// Windows/FileName.cpp
-
-#include "StdAfx.h"
-
-#include "FileName.h"
-
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-namespace NWindows {
-namespace NFile {
-namespace NName {
-
-#define IS_SEPAR(c) IS_PATH_SEPAR(c)
-
-int FindSepar(const wchar_t *s) throw()
-{
- for (const wchar_t *p = s;; p++)
- {
- const wchar_t c = *p;
- if (c == 0)
- return -1;
- if (IS_SEPAR(c))
- return (int)(p - s);
- }
-}
-
-#ifndef USE_UNICODE_FSTRING
-int FindSepar(const FChar *s) throw()
-{
- for (const FChar *p = s;; p++)
- {
- const FChar c = *p;
- if (c == 0)
- return -1;
- if (IS_SEPAR(c))
- return (int)(p - s);
- }
-}
-#endif
-
-#ifndef USE_UNICODE_FSTRING
-void NormalizeDirPathPrefix(FString &dirPath)
-{
- if (dirPath.IsEmpty())
- return;
- if (!IsPathSepar(dirPath.Back()))
- dirPath.Add_PathSepar();
-}
-#endif
-
-void NormalizeDirPathPrefix(UString &dirPath)
-{
- if (dirPath.IsEmpty())
- return;
- if (!IsPathSepar(dirPath.Back()))
- dirPath.Add_PathSepar();
-}
-
-#define IS_LETTER_CHAR(c) ((c) >= 'a' && (c) <= 'z' || (c) >= 'A' && (c) <= 'Z')
-
-bool IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); }
-
-bool IsAltPathPrefix(CFSTR s) throw()
-{
- unsigned len = MyStringLen(s);
- if (len == 0)
- return false;
- if (s[len - 1] != ':')
- return false;
-
- #if defined(_WIN32) && !defined(UNDER_CE)
- if (IsDevicePath(s))
- return false;
- if (IsSuperPath(s))
- {
- s += kSuperPathPrefixSize;
- len -= kSuperPathPrefixSize;
- }
- if (len == 2 && IsDrivePath2(s))
- return false;
- #endif
-
- return true;
-}
-
-#if defined(_WIN32) && !defined(UNDER_CE)
-
-const char * const kSuperPathPrefix = "\\\\?\\";
-static const char * const kSuperUncPrefix = "\\\\?\\UNC\\";
-
-#define IS_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '.' && IS_SEPAR((s)[3]))
-#define IS_SUPER_PREFIX(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '?' && IS_SEPAR((s)[3]))
-#define IS_SUPER_OR_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && ((s)[2] == '?' || (s)[2] == '.') && IS_SEPAR((s)[3]))
-
-#define IS_UNC_WITH_SLASH(s) ( \
- ((s)[0] == 'U' || (s)[0] == 'u') \
- && ((s)[1] == 'N' || (s)[1] == 'n') \
- && ((s)[2] == 'C' || (s)[2] == 'c') \
- && IS_SEPAR((s)[3]))
-
-bool IsDevicePath(CFSTR s) throw()
-{
- #ifdef UNDER_CE
-
- s = s;
- return false;
- /*
- // actually we don't know the way to open device file in WinCE.
- unsigned len = MyStringLen(s);
- if (len < 5 || len > 5 || !IsString1PrefixedByString2(s, "DSK"))
- return false;
- if (s[4] != ':')
- return false;
- // for reading use SG_REQ sg; if (DeviceIoControl(dsk, IOCTL_DISK_READ));
- */
-
- #else
-
- if (!IS_DEVICE_PATH(s))
- return false;
- unsigned len = MyStringLen(s);
- if (len == 6 && s[5] == ':')
- return true;
- if (len < 18 || len > 22 || !IsString1PrefixedByString2(s + kDevicePathPrefixSize, "PhysicalDrive"))
- return false;
- for (unsigned i = 17; i < len; i++)
- if (s[i] < '0' || s[i] > '9')
- return false;
- return true;
-
- #endif
-}
-
-bool IsSuperUncPath(CFSTR s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); }
-bool IsNetworkPath(CFSTR s) throw()
-{
- if (!IS_SEPAR(s[0]) || !IS_SEPAR(s[1]))
- return false;
- if (IsSuperUncPath(s))
- return true;
- FChar c = s[2];
- return (c != '.' && c != '?');
-}
-
-unsigned GetNetworkServerPrefixSize(CFSTR s) throw()
-{
- if (!IS_SEPAR(s[0]) || !IS_SEPAR(s[1]))
- return 0;
- unsigned prefixSize = 2;
- if (IsSuperUncPath(s))
- prefixSize = kSuperUncPathPrefixSize;
- else
- {
- FChar c = s[2];
- if (c == '.' || c == '?')
- return 0;
- }
- int pos = FindSepar(s + prefixSize);
- if (pos < 0)
- return 0;
- return prefixSize + pos + 1;
-}
-
-bool IsNetworkShareRootPath(CFSTR s) throw()
-{
- unsigned prefixSize = GetNetworkServerPrefixSize(s);
- if (prefixSize == 0)
- return false;
- s += prefixSize;
- int pos = FindSepar(s);
- if (pos < 0)
- return true;
- return s[(unsigned)pos + 1] == 0;
-}
-
-static const unsigned kDrivePrefixSize = 3; /* c:\ */
-
-bool IsDrivePath2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; }
-// bool IsDriveName2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; }
-bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); }
-bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); }
-// bool IsSuperUncPath(const wchar_t *s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); }
-
-#ifndef USE_UNICODE_FSTRING
-bool IsDrivePath2(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; }
-// bool IsDriveName2(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; }
-bool IsDrivePath(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); }
-bool IsSuperPath(CFSTR s) throw() { return IS_SUPER_PREFIX(s); }
-bool IsSuperOrDevicePath(CFSTR s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); }
-#endif // USE_UNICODE_FSTRING
-
-bool IsDrivePath_SuperAllowed(CFSTR s) throw()
-{
- if (IsSuperPath(s))
- s += kSuperPathPrefixSize;
- return IsDrivePath(s);
-}
-
-bool IsDriveRootPath_SuperAllowed(CFSTR s) throw()
-{
- if (IsSuperPath(s))
- s += kSuperPathPrefixSize;
- return IsDrivePath(s) && s[kDrivePrefixSize] == 0;
-}
-
-bool IsAbsolutePath(const wchar_t *s) throw()
-{
- return IS_SEPAR(s[0]) || IsDrivePath2(s);
-}
-
-int FindAltStreamColon(CFSTR path) throw()
-{
- unsigned i = 0;
- if (IsDrivePath2(path))
- i = 2;
- int colonPos = -1;
- for (;; i++)
- {
- FChar c = path[i];
- if (c == 0)
- return colonPos;
- if (c == ':')
- {
- if (colonPos < 0)
- colonPos = i;
- continue;
- }
- if (IS_SEPAR(c))
- colonPos = -1;
- }
-}
-
-#ifndef USE_UNICODE_FSTRING
-
-static unsigned GetRootPrefixSize_Of_NetworkPath(CFSTR s)
-{
- // Network path: we look "server\path\" as root prefix
- int pos = FindSepar(s);
- if (pos < 0)
- return 0;
- int pos2 = FindSepar(s + (unsigned)pos + 1);
- if (pos2 < 0)
- return 0;
- return pos + pos2 + 2;
-}
-
-static unsigned GetRootPrefixSize_Of_SimplePath(CFSTR s)
-{
- if (IsDrivePath(s))
- return kDrivePrefixSize;
- if (!IS_SEPAR(s[0]))
- return 0;
- if (s[1] == 0 || !IS_SEPAR(s[1]))
- return 1;
- unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2);
- return (size == 0) ? 0 : 2 + size;
-}
-
-static unsigned GetRootPrefixSize_Of_SuperPath(CFSTR s)
-{
- if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize))
- {
- unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize);
- return (size == 0) ? 0 : kSuperUncPathPrefixSize + size;
- }
- // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\"
- int pos = FindSepar(s + kSuperPathPrefixSize);
- if (pos < 0)
- return 0;
- return kSuperPathPrefixSize + pos + 1;
-}
-
-unsigned GetRootPrefixSize(CFSTR s) throw()
-{
- if (IS_DEVICE_PATH(s))
- return kDevicePathPrefixSize;
- if (IsSuperPath(s))
- return GetRootPrefixSize_Of_SuperPath(s);
- return GetRootPrefixSize_Of_SimplePath(s);
-}
-
-#endif // USE_UNICODE_FSTRING
-
-static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw()
-{
- // Network path: we look "server\path\" as root prefix
- int pos = FindSepar(s);
- if (pos < 0)
- return 0;
- int pos2 = FindSepar(s + (unsigned)pos + 1);
- if (pos2 < 0)
- return 0;
- return pos + pos2 + 2;
-}
-
-static unsigned GetRootPrefixSize_Of_SimplePath(const wchar_t *s) throw()
-{
- if (IsDrivePath(s))
- return kDrivePrefixSize;
- if (!IS_SEPAR(s[0]))
- return 0;
- if (s[1] == 0 || !IS_SEPAR(s[1]))
- return 1;
- unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2);
- return (size == 0) ? 0 : 2 + size;
-}
-
-static unsigned GetRootPrefixSize_Of_SuperPath(const wchar_t *s) throw()
-{
- if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize))
- {
- unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize);
- return (size == 0) ? 0 : kSuperUncPathPrefixSize + size;
- }
- // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\"
- int pos = FindSepar(s + kSuperPathPrefixSize);
- if (pos < 0)
- return 0;
- return kSuperPathPrefixSize + pos + 1;
-}
-
-unsigned GetRootPrefixSize(const wchar_t *s) throw()
-{
- if (IS_DEVICE_PATH(s))
- return kDevicePathPrefixSize;
- if (IsSuperPath(s))
- return GetRootPrefixSize_Of_SuperPath(s);
- return GetRootPrefixSize_Of_SimplePath(s);
-}
-
-#else // _WIN32
-
-bool IsAbsolutePath(const wchar_t *s) { return IS_SEPAR(s[0]); }
-
-#ifndef USE_UNICODE_FSTRING
-unsigned GetRootPrefixSize(CFSTR s) { return IS_SEPAR(s[0]) ? 1 : 0; }
-#endif
-unsigned GetRootPrefixSize(const wchar_t *s) { return IS_SEPAR(s[0]) ? 1 : 0; }
-
-#endif // _WIN32
-
-
-#ifndef UNDER_CE
-
-static bool GetCurDir(UString &path)
-{
- path.Empty();
- DWORD needLength;
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- TCHAR s[MAX_PATH + 2];
- s[0] = 0;
- needLength = ::GetCurrentDirectory(MAX_PATH + 1, s);
- path = fs2us(fas2fs(s));
- }
- else
- #endif
- {
- WCHAR s[MAX_PATH + 2];
- s[0] = 0;
- needLength = ::GetCurrentDirectoryW(MAX_PATH + 1, s);
- path = s;
- }
- return (needLength > 0 && needLength <= MAX_PATH);
-}
-
-static bool ResolveDotsFolders(UString &s)
-{
- #ifdef _WIN32
- // s.Replace(L'/', WCHAR_PATH_SEPARATOR);
- #endif
-
- for (unsigned i = 0;;)
- {
- const wchar_t c = s[i];
- if (c == 0)
- return true;
- if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1])))
- {
- const wchar_t c1 = s[i + 1];
- if (c1 == '.')
- {
- const wchar_t c2 = s[i + 2];
- if (IS_SEPAR(c2) || c2 == 0)
- {
- if (i == 0)
- return false;
- int k = i - 2;
- i += 2;
-
- for (;; k--)
- {
- if (k < 0)
- return false;
- if (!IS_SEPAR(s[(unsigned)k]))
- break;
- }
-
- do
- k--;
- while (k >= 0 && !IS_SEPAR(s[(unsigned)k]));
-
- unsigned num;
-
- if (k >= 0)
- {
- num = i - k;
- i = k;
- }
- else
- {
- num = (c2 == 0 ? i : (i + 1));
- i = 0;
- }
-
- s.Delete(i, num);
- continue;
- }
- }
- else if (IS_SEPAR(c1) || c1 == 0)
- {
- unsigned num = 2;
- if (i != 0)
- i--;
- else if (c1 == 0)
- num = 1;
- s.Delete(i, num);
- continue;
- }
- }
-
- i++;
- }
-}
-
-#endif // UNDER_CE
-
-#define LONG_PATH_DOTS_FOLDERS_PARSING
-
-
-/*
-Windows (at least 64-bit XP) can't resolve "." or ".." in paths that start with SuperPrefix \\?\
-To solve that problem we check such path:
- - super path contains "." or ".." - we use kSuperPathType_UseOnlySuper
- - super path doesn't contain "." or ".." - we use kSuperPathType_UseOnlyMain
-*/
-#ifdef LONG_PATH_DOTS_FOLDERS_PARSING
-#ifndef UNDER_CE
-static bool AreThereDotsFolders(CFSTR s)
-{
- for (unsigned i = 0;; i++)
- {
- FChar c = s[i];
- if (c == 0)
- return false;
- if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1])))
- {
- FChar c1 = s[i + 1];
- if (c1 == 0 || IS_SEPAR(c1) ||
- (c1 == '.' && (s[i + 2] == 0 || IS_SEPAR(s[i + 2]))))
- return true;
- }
- }
-}
-#endif
-#endif // LONG_PATH_DOTS_FOLDERS_PARSING
-
-#ifdef WIN_LONG_PATH
-
-/*
-Most of Windows versions have problems, if some file or dir name
-contains '.' or ' ' at the end of name (Bad Path).
-To solve that problem, we always use Super Path ("\\?\" prefix and full path)
-in such cases. Note that "." and ".." are not bad names.
-
-There are 3 cases:
- 1) If the path is already Super Path, we use that path
- 2) If the path is not Super Path :
- 2.1) Bad Path; we use only Super Path.
- 2.2) Good Path; we use Main Path. If it fails, we use Super Path.
-
- NeedToUseOriginalPath returns:
- kSuperPathType_UseOnlyMain : Super already
- kSuperPathType_UseOnlySuper : not Super, Bad Path
- kSuperPathType_UseMainAndSuper : not Super, Good Path
-*/
-
-int GetUseSuperPathType(CFSTR s) throw()
-{
- if (IsSuperOrDevicePath(s))
- {
- #ifdef LONG_PATH_DOTS_FOLDERS_PARSING
- if ((s)[2] != '.')
- if (AreThereDotsFolders(s + kSuperPathPrefixSize))
- return kSuperPathType_UseOnlySuper;
- #endif
- return kSuperPathType_UseOnlyMain;
- }
-
- for (unsigned i = 0;; i++)
- {
- FChar c = s[i];
- if (c == 0)
- return kSuperPathType_UseMainAndSuper;
- if (c == '.' || c == ' ')
- {
- FChar c2 = s[i + 1];
- if (c2 == 0 || IS_SEPAR(c2))
- {
- // if it's "." or "..", it's not bad name.
- if (c == '.')
- {
- if (i == 0 || IS_SEPAR(s[i - 1]))
- continue;
- if (s[i - 1] == '.')
- {
- if (i - 1 == 0 || IS_SEPAR(s[i - 2]))
- continue;
- }
- }
- return kSuperPathType_UseOnlySuper;
- }
- }
- }
-}
-
-
-/*
- returns false in two cases:
- - if GetCurDir was used, and GetCurDir returned error.
- - if we can't resolve ".." name.
- if path is ".", "..", res is empty.
- if it's Super Path already, res is empty.
- for \**** , and if GetCurDir is not drive (c:\), res is empty
- for absolute paths, returns true, res is Super path.
-*/
-
-
-static bool GetSuperPathBase(CFSTR s, UString &res)
-{
- res.Empty();
-
- FChar c = s[0];
- if (c == 0)
- return true;
- if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0)))
- return true;
-
- if (IsSuperOrDevicePath(s))
- {
- #ifdef LONG_PATH_DOTS_FOLDERS_PARSING
-
- if ((s)[2] == '.')
- return true;
-
- // we will return true here, so we will try to use these problem paths.
-
- if (!AreThereDotsFolders(s + kSuperPathPrefixSize))
- return true;
-
- UString temp = fs2us(s);
- unsigned fixedSize = GetRootPrefixSize_Of_SuperPath(temp);
- if (fixedSize == 0)
- return true;
-
- UString rem = &temp[fixedSize];
- if (!ResolveDotsFolders(rem))
- return true;
-
- temp.DeleteFrom(fixedSize);
- res += temp;
- res += rem;
-
- #endif
-
- return true;
- }
-
- if (IS_SEPAR(c))
- {
- if (IS_SEPAR(s[1]))
- {
- UString temp = fs2us(s + 2);
- unsigned fixedSize = GetRootPrefixSize_Of_NetworkPath(temp);
- // we ignore that error to allow short network paths server\share?
- /*
- if (fixedSize == 0)
- return false;
- */
- UString rem = &temp[fixedSize];
- if (!ResolveDotsFolders(rem))
- return false;
- res += kSuperUncPrefix;
- temp.DeleteFrom(fixedSize);
- res += temp;
- res += rem;
- return true;
- }
- }
- else
- {
- if (IsDrivePath2(s))
- {
- UString temp = fs2us(s);
- unsigned prefixSize = 2;
- if (IsDrivePath(s))
- prefixSize = kDrivePrefixSize;
- UString rem = temp.Ptr(prefixSize);
- if (!ResolveDotsFolders(rem))
- return true;
- res += kSuperPathPrefix;
- temp.DeleteFrom(prefixSize);
- res += temp;
- res += rem;
- return true;
- }
- }
-
- UString curDir;
- if (!GetCurDir(curDir))
- return false;
- NormalizeDirPathPrefix(curDir);
-
- unsigned fixedSizeStart = 0;
- unsigned fixedSize = 0;
- const char *superMarker = NULL;
- if (IsSuperPath(curDir))
- {
- fixedSize = GetRootPrefixSize_Of_SuperPath(curDir);
- if (fixedSize == 0)
- return false;
- }
- else
- {
- if (IsDrivePath(curDir))
- {
- superMarker = kSuperPathPrefix;
- fixedSize = kDrivePrefixSize;
- }
- else
- {
- if (!IsPathSepar(curDir[0]) || !IsPathSepar(curDir[1]))
- return false;
- fixedSizeStart = 2;
- fixedSize = GetRootPrefixSize_Of_NetworkPath(curDir.Ptr(2));
- if (fixedSize == 0)
- return false;
- superMarker = kSuperUncPrefix;
- }
- }
-
- UString temp;
- if (IS_SEPAR(c))
- {
- temp = fs2us(s + 1);
- }
- else
- {
- temp += &curDir[fixedSizeStart + fixedSize];
- temp += fs2us(s);
- }
- if (!ResolveDotsFolders(temp))
- return false;
- if (superMarker)
- res += superMarker;
- res += curDir.Mid(fixedSizeStart, fixedSize);
- res += temp;
- return true;
-}
-
-
-/*
- In that case if GetSuperPathBase doesn't return new path, we don't need
- to use same path that was used as main path
-
- GetSuperPathBase superPath.IsEmpty() onlyIfNew
- false * * GetCurDir Error
- true false * use Super path
- true true true don't use any path, we already used mainPath
- true true false use main path as Super Path, we don't try mainMath
- That case is possible now if GetCurDir returns unknow
- type of path (not drive and not network)
-
- We can change that code if we want to try mainPath, if GetSuperPathBase returns error,
- and we didn't try mainPath still.
- If we want to work that way, we don't need to use GetSuperPathBase return code.
-*/
-
-bool GetSuperPath(CFSTR path, UString &superPath, bool onlyIfNew)
-{
- if (GetSuperPathBase(path, superPath))
- {
- if (superPath.IsEmpty())
- {
- // actually the only possible when onlyIfNew == true and superPath is empty
- // is case when
-
- if (onlyIfNew)
- return false;
- superPath = fs2us(path);
- }
- return true;
- }
- return false;
-}
-
-bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew)
-{
- if (!GetSuperPathBase(s1, d1) ||
- !GetSuperPathBase(s2, d2))
- return false;
- if (d1.IsEmpty() && d2.IsEmpty() && onlyIfNew)
- return false;
- if (d1.IsEmpty()) d1 = fs2us(s1);
- if (d2.IsEmpty()) d2 = fs2us(s2);
- return true;
-}
-
-
-/*
-// returns true, if we need additional use with New Super path.
-bool GetSuperPath(CFSTR path, UString &superPath)
-{
- if (GetSuperPathBase(path, superPath))
- return !superPath.IsEmpty();
- return false;
-}
-*/
-#endif // WIN_LONG_PATH
-
-bool GetFullPath(CFSTR dirPrefix, CFSTR s, FString &res)
-{
- res = s;
-
- #ifdef UNDER_CE
-
- if (!IS_SEPAR(s[0]))
- {
- if (!dirPrefix)
- return false;
- res = dirPrefix;
- res += s;
- }
-
- #else
-
- unsigned prefixSize = GetRootPrefixSize(s);
- if (prefixSize != 0)
- {
- if (!AreThereDotsFolders(s + prefixSize))
- return true;
-
- UString rem = fs2us(s + prefixSize);
- if (!ResolveDotsFolders(rem))
- return true; // maybe false;
- res.DeleteFrom(prefixSize);
- res += us2fs(rem);
- return true;
- }
-
- /*
- FChar c = s[0];
- if (c == 0)
- return true;
- if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0)))
- return true;
- if (IS_SEPAR(c) && IS_SEPAR(s[1]))
- return true;
- if (IsDrivePath(s))
- return true;
- */
-
- UString curDir;
- if (dirPrefix)
- curDir = fs2us(dirPrefix);
- else
- {
- if (!GetCurDir(curDir))
- return false;
- }
- NormalizeDirPathPrefix(curDir);
-
- unsigned fixedSize = 0;
-
- #ifdef _WIN32
-
- if (IsSuperPath(curDir))
- {
- fixedSize = GetRootPrefixSize_Of_SuperPath(curDir);
- if (fixedSize == 0)
- return false;
- }
- else
- {
- if (IsDrivePath(curDir))
- fixedSize = kDrivePrefixSize;
- else
- {
- if (!IsPathSepar(curDir[0]) || !IsPathSepar(curDir[1]))
- return false;
- fixedSize = GetRootPrefixSize_Of_NetworkPath(curDir.Ptr(2));
- if (fixedSize == 0)
- return false;
- fixedSize += 2;
- }
- }
-
- #endif // _WIN32
-
- UString temp;
- if (IS_SEPAR(s[0]))
- {
- temp = fs2us(s + 1);
- }
- else
- {
- temp += curDir.Ptr(fixedSize);
- temp += fs2us(s);
- }
- if (!ResolveDotsFolders(temp))
- return false;
- curDir.DeleteFrom(fixedSize);
- res = us2fs(curDir);
- res += us2fs(temp);
-
- #endif // UNDER_CE
-
- return true;
-}
-
-bool GetFullPath(CFSTR path, FString &fullPath)
-{
- return GetFullPath(NULL, path, fullPath);
-}
-
-}}}
+// Windows/FileName.cpp
+
+#include "StdAfx.h"
+
+#ifndef _WIN32
+#include <limits.h>
+#include <unistd.h>
+#include "../Common/StringConvert.h"
+#endif
+
+#include "FileDir.h"
+#include "FileName.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NFile {
+namespace NName {
+
+#define IS_SEPAR(c) IS_PATH_SEPAR(c)
+
+int FindSepar(const wchar_t *s) throw()
+{
+ for (const wchar_t *p = s;; p++)
+ {
+ const wchar_t c = *p;
+ if (c == 0)
+ return -1;
+ if (IS_SEPAR(c))
+ return (int)(p - s);
+ }
+}
+
+#ifndef USE_UNICODE_FSTRING
+int FindSepar(const FChar *s) throw()
+{
+ for (const FChar *p = s;; p++)
+ {
+ const FChar c = *p;
+ if (c == 0)
+ return -1;
+ if (IS_SEPAR(c))
+ return (int)(p - s);
+ }
+}
+#endif
+
+#ifndef USE_UNICODE_FSTRING
+void NormalizeDirPathPrefix(FString &dirPath)
+{
+ if (dirPath.IsEmpty())
+ return;
+ if (!IsPathSepar(dirPath.Back()))
+ dirPath.Add_PathSepar();
+}
+#endif
+
+void NormalizeDirPathPrefix(UString &dirPath)
+{
+ if (dirPath.IsEmpty())
+ return;
+ if (!IsPathSepar(dirPath.Back()))
+ dirPath.Add_PathSepar();
+}
+
+#ifdef _WIN32
+
+#ifndef USE_UNICODE_FSTRING
+#ifdef Z7_LONG_PATH
+static void NormalizeDirSeparators(UString &s)
+{
+ const unsigned len = s.Len();
+ for (unsigned i = 0; i < len; i++)
+ if (s[i] == '/')
+ s.ReplaceOneCharAtPos(i, WCHAR_PATH_SEPARATOR);
+}
+#endif
+#endif
+
+void NormalizeDirSeparators(FString &s)
+{
+ const unsigned len = s.Len();
+ for (unsigned i = 0; i < len; i++)
+ if (s[i] == '/')
+ s.ReplaceOneCharAtPos(i, FCHAR_PATH_SEPARATOR);
+}
+
+#endif
+
+
+#define IS_LETTER_CHAR(c) ((((unsigned)(int)(c) | 0x20) - (unsigned)'a' <= (unsigned)('z' - 'a')))
+
+bool IsDrivePath(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); }
+
+bool IsAltPathPrefix(CFSTR s) throw()
+{
+ unsigned len = MyStringLen(s);
+ if (len == 0)
+ return false;
+ if (s[len - 1] != ':')
+ return false;
+
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ if (IsDevicePath(s))
+ return false;
+ if (IsSuperPath(s))
+ {
+ s += kSuperPathPrefixSize;
+ len -= kSuperPathPrefixSize;
+ }
+ if (len == 2 && IsDrivePath2(s))
+ return false;
+ #endif
+
+ return true;
+}
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+
+const char * const kSuperPathPrefix = "\\\\?\\";
+#ifdef Z7_LONG_PATH
+static const char * const kSuperUncPrefix = "\\\\?\\UNC\\";
+#endif
+
+#define IS_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '.' && IS_SEPAR((s)[3]))
+#define IS_SUPER_PREFIX(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && (s)[2] == '?' && IS_SEPAR((s)[3]))
+#define IS_SUPER_OR_DEVICE_PATH(s) (IS_SEPAR((s)[0]) && IS_SEPAR((s)[1]) && ((s)[2] == '?' || (s)[2] == '.') && IS_SEPAR((s)[3]))
+
+#define IS_UNC_WITH_SLASH(s) ( \
+ ((s)[0] == 'U' || (s)[0] == 'u') \
+ && ((s)[1] == 'N' || (s)[1] == 'n') \
+ && ((s)[2] == 'C' || (s)[2] == 'c') \
+ && IS_SEPAR((s)[3]))
+
+bool IsDevicePath(CFSTR s) throw()
+{
+ #ifdef UNDER_CE
+
+ s = s;
+ return false;
+ /*
+ // actually we don't know the way to open device file in WinCE.
+ unsigned len = MyStringLen(s);
+ if (len < 5 || len > 5 || !IsString1PrefixedByString2(s, "DSK"))
+ return false;
+ if (s[4] != ':')
+ return false;
+ // for reading use SG_REQ sg; if (DeviceIoControl(dsk, IOCTL_DISK_READ));
+ */
+
+ #else
+
+ if (!IS_DEVICE_PATH(s))
+ return false;
+ unsigned len = MyStringLen(s);
+ if (len == 6 && s[5] == ':')
+ return true;
+ if (len < 18 || len > 22 || !IsString1PrefixedByString2(s + kDevicePathPrefixSize, "PhysicalDrive"))
+ return false;
+ for (unsigned i = 17; i < len; i++)
+ if (s[i] < '0' || s[i] > '9')
+ return false;
+ return true;
+
+ #endif
+}
+
+bool IsSuperUncPath(CFSTR s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); }
+bool IsNetworkPath(CFSTR s) throw()
+{
+ if (!IS_SEPAR(s[0]) || !IS_SEPAR(s[1]))
+ return false;
+ if (IsSuperUncPath(s))
+ return true;
+ FChar c = s[2];
+ return (c != '.' && c != '?');
+}
+
+unsigned GetNetworkServerPrefixSize(CFSTR s) throw()
+{
+ if (!IS_SEPAR(s[0]) || !IS_SEPAR(s[1]))
+ return 0;
+ unsigned prefixSize = 2;
+ if (IsSuperUncPath(s))
+ prefixSize = kSuperUncPathPrefixSize;
+ else
+ {
+ FChar c = s[2];
+ if (c == '.' || c == '?')
+ return 0;
+ }
+ const int pos = FindSepar(s + prefixSize);
+ if (pos < 0)
+ return 0;
+ return prefixSize + (unsigned)(pos + 1);
+}
+
+bool IsNetworkShareRootPath(CFSTR s) throw()
+{
+ const unsigned prefixSize = GetNetworkServerPrefixSize(s);
+ if (prefixSize == 0)
+ return false;
+ s += prefixSize;
+ const int pos = FindSepar(s);
+ if (pos < 0)
+ return true;
+ return s[(unsigned)pos + 1] == 0;
+}
+
+static const unsigned kDrivePrefixSize = 3; /* c:\ */
+
+bool IsDrivePath2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; }
+// bool IsDriveName2(const wchar_t *s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; }
+bool IsSuperPath(const wchar_t *s) throw() { return IS_SUPER_PREFIX(s); }
+bool IsSuperOrDevicePath(const wchar_t *s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); }
+// bool IsSuperUncPath(const wchar_t *s) throw() { return (IS_SUPER_PREFIX(s) && IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize)); }
+
+bool IsAltStreamPrefixWithColon(const UString &s) throw()
+{
+ if (s.IsEmpty())
+ return false;
+ if (s.Back() != ':')
+ return false;
+ unsigned pos = 0;
+ if (IsSuperPath(s))
+ pos = kSuperPathPrefixSize;
+ if (s.Len() - pos == 2 && IsDrivePath2(s.Ptr(pos)))
+ return false;
+ return true;
+}
+
+bool If_IsSuperPath_RemoveSuperPrefix(UString &s)
+{
+ if (!IsSuperPath(s))
+ return false;
+ unsigned start = 0;
+ unsigned count = kSuperPathPrefixSize;
+ const wchar_t *s2 = s.Ptr(kSuperPathPrefixSize);
+ if (IS_UNC_WITH_SLASH(s2))
+ {
+ start = 2;
+ count = kSuperUncPathPrefixSize - 2;
+ }
+ s.Delete(start, count);
+ return true;
+}
+
+
+#ifndef USE_UNICODE_FSTRING
+bool IsDrivePath2(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':'; }
+// bool IsDriveName2(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && s[2] == 0; }
+bool IsDrivePath(CFSTR s) throw() { return IS_LETTER_CHAR(s[0]) && s[1] == ':' && IS_SEPAR(s[2]); }
+bool IsSuperPath(CFSTR s) throw() { return IS_SUPER_PREFIX(s); }
+bool IsSuperOrDevicePath(CFSTR s) throw() { return IS_SUPER_OR_DEVICE_PATH(s); }
+#endif // USE_UNICODE_FSTRING
+
+bool IsDrivePath_SuperAllowed(CFSTR s) throw()
+{
+ if (IsSuperPath(s))
+ s += kSuperPathPrefixSize;
+ return IsDrivePath(s);
+}
+
+bool IsDriveRootPath_SuperAllowed(CFSTR s) throw()
+{
+ if (IsSuperPath(s))
+ s += kSuperPathPrefixSize;
+ return IsDrivePath(s) && s[kDrivePrefixSize] == 0;
+}
+
+bool IsAbsolutePath(const wchar_t *s) throw()
+{
+ return IS_SEPAR(s[0]) || IsDrivePath2(s);
+}
+
+int FindAltStreamColon(CFSTR path) throw()
+{
+ unsigned i = 0;
+ if (IsDrivePath2(path))
+ i = 2;
+ int colonPos = -1;
+ for (;; i++)
+ {
+ FChar c = path[i];
+ if (c == 0)
+ return colonPos;
+ if (c == ':')
+ {
+ if (colonPos < 0)
+ colonPos = (int)i;
+ continue;
+ }
+ if (IS_SEPAR(c))
+ colonPos = -1;
+ }
+}
+
+#ifndef USE_UNICODE_FSTRING
+
+static unsigned GetRootPrefixSize_Of_NetworkPath(CFSTR s)
+{
+ // Network path: we look "server\path\" as root prefix
+ int pos = FindSepar(s);
+ if (pos < 0)
+ return 0;
+ int pos2 = FindSepar(s + (unsigned)pos + 1);
+ if (pos2 < 0)
+ return 0;
+ return pos + pos2 + 2;
+}
+
+static unsigned GetRootPrefixSize_Of_SimplePath(CFSTR s)
+{
+ if (IsDrivePath(s))
+ return kDrivePrefixSize;
+ if (!IS_SEPAR(s[0]))
+ return 0;
+ if (s[1] == 0 || !IS_SEPAR(s[1]))
+ return 1;
+ const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2);
+ return (size == 0) ? 0 : 2 + size;
+}
+
+static unsigned GetRootPrefixSize_Of_SuperPath(CFSTR s)
+{
+ if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize))
+ {
+ const unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize);
+ return (size == 0) ? 0 : kSuperUncPathPrefixSize + size;
+ }
+ // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\"
+ const int pos = FindSepar(s + kSuperPathPrefixSize);
+ if (pos < 0)
+ return 0;
+ return kSuperPathPrefixSize + pos + 1;
+}
+
+unsigned GetRootPrefixSize(CFSTR s) throw()
+{
+ if (IS_DEVICE_PATH(s))
+ return kDevicePathPrefixSize;
+ if (IsSuperPath(s))
+ return GetRootPrefixSize_Of_SuperPath(s);
+ return GetRootPrefixSize_Of_SimplePath(s);
+}
+
+#endif // USE_UNICODE_FSTRING
+
+static unsigned GetRootPrefixSize_Of_NetworkPath(const wchar_t *s) throw()
+{
+ // Network path: we look "server\path\" as root prefix
+ int pos = FindSepar(s);
+ if (pos < 0)
+ return 0;
+ int pos2 = FindSepar(s + (unsigned)pos + 1);
+ if (pos2 < 0)
+ return 0;
+ return (unsigned)(pos + pos2 + 2);
+}
+
+static unsigned GetRootPrefixSize_Of_SimplePath(const wchar_t *s) throw()
+{
+ if (IsDrivePath(s))
+ return kDrivePrefixSize;
+ if (!IS_SEPAR(s[0]))
+ return 0;
+ if (s[1] == 0 || !IS_SEPAR(s[1]))
+ return 1;
+ unsigned size = GetRootPrefixSize_Of_NetworkPath(s + 2);
+ return (size == 0) ? 0 : 2 + size;
+}
+
+static unsigned GetRootPrefixSize_Of_SuperPath(const wchar_t *s) throw()
+{
+ if (IS_UNC_WITH_SLASH(s + kSuperPathPrefixSize))
+ {
+ unsigned size = GetRootPrefixSize_Of_NetworkPath(s + kSuperUncPathPrefixSize);
+ return (size == 0) ? 0 : kSuperUncPathPrefixSize + size;
+ }
+ // we support \\?\c:\ paths and volume GUID paths \\?\Volume{GUID}\"
+ int pos = FindSepar(s + kSuperPathPrefixSize);
+ if (pos < 0)
+ return 0;
+ return kSuperPathPrefixSize + (unsigned)(pos + 1);
+}
+
+unsigned GetRootPrefixSize(const wchar_t *s) throw()
+{
+ if (IS_DEVICE_PATH(s))
+ return kDevicePathPrefixSize;
+ if (IsSuperPath(s))
+ return GetRootPrefixSize_Of_SuperPath(s);
+ return GetRootPrefixSize_Of_SimplePath(s);
+}
+
+#else // _WIN32
+
+bool IsAbsolutePath(const wchar_t *s) throw() { return IS_SEPAR(s[0]); }
+
+#ifndef USE_UNICODE_FSTRING
+unsigned GetRootPrefixSize(CFSTR s) throw();
+unsigned GetRootPrefixSize(CFSTR s) throw() { return IS_SEPAR(s[0]) ? 1 : 0; }
+#endif
+unsigned GetRootPrefixSize(const wchar_t *s) throw() { return IS_SEPAR(s[0]) ? 1 : 0; }
+
+#endif // _WIN32
+
+
+#ifndef UNDER_CE
+
+
+#ifdef USE_UNICODE_FSTRING
+
+#define GetCurDir NDir::GetCurrentDir
+
+#else
+
+static bool GetCurDir(UString &path)
+{
+ path.Empty();
+ FString s;
+ if (!NDir::GetCurrentDir(s))
+ return false;
+ path = fs2us(s);
+ return true;
+}
+
+#endif
+
+
+static bool ResolveDotsFolders(UString &s)
+{
+ #ifdef _WIN32
+ // s.Replace(L'/', WCHAR_PATH_SEPARATOR);
+ #endif
+
+ for (unsigned i = 0;;)
+ {
+ const wchar_t c = s[i];
+ if (c == 0)
+ return true;
+ if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1])))
+ {
+ const wchar_t c1 = s[i + 1];
+ if (c1 == '.')
+ {
+ const wchar_t c2 = s[i + 2];
+ if (IS_SEPAR(c2) || c2 == 0)
+ {
+ if (i == 0)
+ return false;
+ int k = (int)i - 2;
+ i += 2;
+
+ for (;; k--)
+ {
+ if (k < 0)
+ return false;
+ if (!IS_SEPAR(s[(unsigned)k]))
+ break;
+ }
+
+ do
+ k--;
+ while (k >= 0 && !IS_SEPAR(s[(unsigned)k]));
+
+ unsigned num;
+
+ if (k >= 0)
+ {
+ num = i - (unsigned)k;
+ i = (unsigned)k;
+ }
+ else
+ {
+ num = (c2 == 0 ? i : (i + 1));
+ i = 0;
+ }
+
+ s.Delete(i, num);
+ continue;
+ }
+ }
+ else if (IS_SEPAR(c1) || c1 == 0)
+ {
+ unsigned num = 2;
+ if (i != 0)
+ i--;
+ else if (c1 == 0)
+ num = 1;
+ s.Delete(i, num);
+ continue;
+ }
+ }
+
+ i++;
+ }
+}
+
+#endif // UNDER_CE
+
+#define LONG_PATH_DOTS_FOLDERS_PARSING
+
+
+/*
+Windows (at least 64-bit XP) can't resolve "." or ".." in paths that start with SuperPrefix \\?\
+To solve that problem we check such path:
+ - super path contains "." or ".." - we use kSuperPathType_UseOnlySuper
+ - super path doesn't contain "." or ".." - we use kSuperPathType_UseOnlyMain
+*/
+#ifdef LONG_PATH_DOTS_FOLDERS_PARSING
+#ifndef UNDER_CE
+static bool AreThereDotsFolders(CFSTR s)
+{
+ for (unsigned i = 0;; i++)
+ {
+ FChar c = s[i];
+ if (c == 0)
+ return false;
+ if (c == '.' && (i == 0 || IS_SEPAR(s[i - 1])))
+ {
+ FChar c1 = s[i + 1];
+ if (c1 == 0 || IS_SEPAR(c1) ||
+ (c1 == '.' && (s[i + 2] == 0 || IS_SEPAR(s[i + 2]))))
+ return true;
+ }
+ }
+}
+#endif
+#endif // LONG_PATH_DOTS_FOLDERS_PARSING
+
+#ifdef Z7_LONG_PATH
+
+/*
+Most of Windows versions have problems, if some file or dir name
+contains '.' or ' ' at the end of name (Bad Path).
+To solve that problem, we always use Super Path ("\\?\" prefix and full path)
+in such cases. Note that "." and ".." are not bad names.
+
+There are 3 cases:
+ 1) If the path is already Super Path, we use that path
+ 2) If the path is not Super Path :
+ 2.1) Bad Path; we use only Super Path.
+ 2.2) Good Path; we use Main Path. If it fails, we use Super Path.
+
+ NeedToUseOriginalPath returns:
+ kSuperPathType_UseOnlyMain : Super already
+ kSuperPathType_UseOnlySuper : not Super, Bad Path
+ kSuperPathType_UseMainAndSuper : not Super, Good Path
+*/
+
+int GetUseSuperPathType(CFSTR s) throw()
+{
+ if (IsSuperOrDevicePath(s))
+ {
+ #ifdef LONG_PATH_DOTS_FOLDERS_PARSING
+ if ((s)[2] != '.')
+ if (AreThereDotsFolders(s + kSuperPathPrefixSize))
+ return kSuperPathType_UseOnlySuper;
+ #endif
+ return kSuperPathType_UseOnlyMain;
+ }
+
+ for (unsigned i = 0;; i++)
+ {
+ FChar c = s[i];
+ if (c == 0)
+ return kSuperPathType_UseMainAndSuper;
+ if (c == '.' || c == ' ')
+ {
+ FChar c2 = s[i + 1];
+ if (c2 == 0 || IS_SEPAR(c2))
+ {
+ // if it's "." or "..", it's not bad name.
+ if (c == '.')
+ {
+ if (i == 0 || IS_SEPAR(s[i - 1]))
+ continue;
+ if (s[i - 1] == '.')
+ {
+ if (i - 1 == 0 || IS_SEPAR(s[i - 2]))
+ continue;
+ }
+ }
+ return kSuperPathType_UseOnlySuper;
+ }
+ }
+ }
+}
+
+
+
+/*
+ returns false in two cases:
+ - if GetCurDir was used, and GetCurDir returned error.
+ - if we can't resolve ".." name.
+ if path is ".", "..", res is empty.
+ if it's Super Path already, res is empty.
+ for \**** , and if GetCurDir is not drive (c:\), res is empty
+ for absolute paths, returns true, res is Super path.
+*/
+
+static bool GetSuperPathBase(CFSTR s, UString &res)
+{
+ res.Empty();
+
+ FChar c = s[0];
+ if (c == 0)
+ return true;
+ if (c == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0)))
+ return true;
+
+ if (IsSuperOrDevicePath(s))
+ {
+ #ifdef LONG_PATH_DOTS_FOLDERS_PARSING
+
+ if ((s)[2] == '.')
+ return true;
+
+ // we will return true here, so we will try to use these problem paths.
+
+ if (!AreThereDotsFolders(s + kSuperPathPrefixSize))
+ return true;
+
+ UString temp = fs2us(s);
+ const unsigned fixedSize = GetRootPrefixSize_Of_SuperPath(temp);
+ if (fixedSize == 0)
+ return true;
+
+ UString rem = temp.Ptr(fixedSize);
+ if (!ResolveDotsFolders(rem))
+ return true;
+
+ temp.DeleteFrom(fixedSize);
+ res += temp;
+ res += rem;
+
+ #endif
+
+ return true;
+ }
+
+ if (IS_SEPAR(c))
+ {
+ if (IS_SEPAR(s[1]))
+ {
+ UString temp = fs2us(s + 2);
+ const unsigned fixedSize = GetRootPrefixSize_Of_NetworkPath(temp);
+ // we ignore that error to allow short network paths server\share?
+ /*
+ if (fixedSize == 0)
+ return false;
+ */
+ UString rem = temp.Ptr(fixedSize);
+ if (!ResolveDotsFolders(rem))
+ return false;
+ res += kSuperUncPrefix;
+ temp.DeleteFrom(fixedSize);
+ res += temp;
+ res += rem;
+ return true;
+ }
+ }
+ else
+ {
+ if (IsDrivePath2(s))
+ {
+ UString temp = fs2us(s);
+ unsigned prefixSize = 2;
+ if (IsDrivePath(s))
+ prefixSize = kDrivePrefixSize;
+ UString rem = temp.Ptr(prefixSize);
+ if (!ResolveDotsFolders(rem))
+ return true;
+ res += kSuperPathPrefix;
+ temp.DeleteFrom(prefixSize);
+ res += temp;
+ res += rem;
+ return true;
+ }
+ }
+
+ UString curDir;
+ if (!GetCurDir(curDir))
+ return false;
+ NormalizeDirPathPrefix(curDir);
+
+ unsigned fixedSizeStart = 0;
+ unsigned fixedSize = 0;
+ const char *superMarker = NULL;
+ if (IsSuperPath(curDir))
+ {
+ fixedSize = GetRootPrefixSize_Of_SuperPath(curDir);
+ if (fixedSize == 0)
+ return false;
+ }
+ else
+ {
+ if (IsDrivePath(curDir))
+ {
+ superMarker = kSuperPathPrefix;
+ fixedSize = kDrivePrefixSize;
+ }
+ else
+ {
+ if (!IsPathSepar(curDir[0]) || !IsPathSepar(curDir[1]))
+ return false;
+ fixedSizeStart = 2;
+ fixedSize = GetRootPrefixSize_Of_NetworkPath(curDir.Ptr(2));
+ if (fixedSize == 0)
+ return false;
+ superMarker = kSuperUncPrefix;
+ }
+ }
+
+ UString temp;
+ if (IS_SEPAR(c))
+ {
+ temp = fs2us(s + 1);
+ }
+ else
+ {
+ temp += &curDir[fixedSizeStart + fixedSize];
+ temp += fs2us(s);
+ }
+ if (!ResolveDotsFolders(temp))
+ return false;
+ if (superMarker)
+ res += superMarker;
+ res += curDir.Mid(fixedSizeStart, fixedSize);
+ res += temp;
+ return true;
+}
+
+
+/*
+ In that case if GetSuperPathBase doesn't return new path, we don't need
+ to use same path that was used as main path
+
+ GetSuperPathBase superPath.IsEmpty() onlyIfNew
+ false * * GetCurDir Error
+ true false * use Super path
+ true true true don't use any path, we already used mainPath
+ true true false use main path as Super Path, we don't try mainMath
+ That case is possible now if GetCurDir returns unknown
+ type of path (not drive and not network)
+
+ We can change that code if we want to try mainPath, if GetSuperPathBase returns error,
+ and we didn't try mainPath still.
+ If we want to work that way, we don't need to use GetSuperPathBase return code.
+*/
+
+bool GetSuperPath(CFSTR path, UString &superPath, bool onlyIfNew)
+{
+ if (GetSuperPathBase(path, superPath))
+ {
+ if (superPath.IsEmpty())
+ {
+ // actually the only possible when onlyIfNew == true and superPath is empty
+ // is case when
+
+ if (onlyIfNew)
+ return false;
+ superPath = fs2us(path);
+ }
+
+ NormalizeDirSeparators(superPath);
+ return true;
+ }
+ return false;
+}
+
+bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew)
+{
+ if (!GetSuperPathBase(s1, d1) ||
+ !GetSuperPathBase(s2, d2))
+ return false;
+
+ NormalizeDirSeparators(d1);
+ NormalizeDirSeparators(d2);
+
+ if (d1.IsEmpty() && d2.IsEmpty() && onlyIfNew)
+ return false;
+ if (d1.IsEmpty()) d1 = fs2us(s1);
+ if (d2.IsEmpty()) d2 = fs2us(s2);
+ return true;
+}
+
+
+/*
+// returns true, if we need additional use with New Super path.
+bool GetSuperPath(CFSTR path, UString &superPath)
+{
+ if (GetSuperPathBase(path, superPath))
+ return !superPath.IsEmpty();
+ return false;
+}
+*/
+#endif // Z7_LONG_PATH
+
+bool GetFullPath(CFSTR dirPrefix, CFSTR s, FString &res)
+{
+ res = s;
+
+ #ifdef UNDER_CE
+
+ if (!IS_SEPAR(s[0]))
+ {
+ if (!dirPrefix)
+ return false;
+ res = dirPrefix;
+ res += s;
+ }
+
+ #else
+
+ const unsigned prefixSize = GetRootPrefixSize(s);
+ if (prefixSize != 0)
+#ifdef _WIN32
+ if (prefixSize != 1)
+#endif
+ {
+ if (!AreThereDotsFolders(s + prefixSize))
+ return true;
+
+ UString rem = fs2us(s + prefixSize);
+ if (!ResolveDotsFolders(rem))
+ return true; // maybe false;
+ res.DeleteFrom(prefixSize);
+ res += us2fs(rem);
+ return true;
+ }
+
+ UString curDir;
+ if (dirPrefix && prefixSize == 0)
+ curDir = fs2us(dirPrefix); // we use (dirPrefix), only if (s) path is relative
+ else
+ {
+ if (!GetCurDir(curDir))
+ return false;
+ }
+ NormalizeDirPathPrefix(curDir);
+
+ unsigned fixedSize = GetRootPrefixSize(curDir);
+
+ UString temp;
+#ifdef _WIN32
+ if (prefixSize != 0)
+ {
+ /* (s) is absolute path, but only (prefixSize == 1) is possible here.
+ So for full resolving we need root of current folder and
+ relative part of (s). */
+ s += prefixSize;
+ // (s) is relative part now
+ if (fixedSize == 0)
+ {
+ // (curDir) is not absolute.
+ // That case is unexpected, but we support it too.
+ curDir.Empty();
+ curDir.Add_PathSepar();
+ fixedSize = 1;
+ // (curDir) now is just Separ character.
+ // So final (res) path later also will have Separ prefix.
+ }
+ }
+ else
+#endif // _WIN32
+ {
+ // (s) is relative path
+ temp = curDir.Ptr(fixedSize);
+ // (temp) is relative_part_of(curDir)
+ }
+ temp += fs2us(s);
+ if (!ResolveDotsFolders(temp))
+ return false;
+ curDir.DeleteFrom(fixedSize);
+ // (curDir) now contains only absolute prefix part
+ res = us2fs(curDir);
+ res += us2fs(temp);
+
+ #endif // UNDER_CE
+
+ return true;
+}
+
+
+bool GetFullPath(CFSTR path, FString &fullPath)
+{
+ return GetFullPath(NULL, path, fullPath);
+}
+
+}}}
diff --git a/CPP/Windows/FileName.h b/CPP/Windows/FileName.h
index 1e47098..219b656 100644
--- a/CPP/Windows/FileName.h
+++ b/CPP/Windows/FileName.h
@@ -1,115 +1,133 @@
-// Windows/FileName.h
-
-#ifndef __WINDOWS_FILE_NAME_H
-#define __WINDOWS_FILE_NAME_H
-
-#include "../Common/MyString.h"
-
-namespace NWindows {
-namespace NFile {
-namespace NName {
-
-int FindSepar(const wchar_t *s) throw();
-#ifndef USE_UNICODE_FSTRING
-int FindSepar(const FChar *s) throw();
-#endif
-
-void NormalizeDirPathPrefix(FString &dirPath); // ensures that it ended with '\\', if dirPath is not epmty
-void NormalizeDirPathPrefix(UString &dirPath);
-
-bool IsDrivePath(const wchar_t *s) throw(); // first 3 chars are drive chars like "a:\\"
-
-bool IsAltPathPrefix(CFSTR s) throw(); /* name: */
-
-#if defined(_WIN32) && !defined(UNDER_CE)
-
-extern const char * const kSuperPathPrefix; /* \\?\ */
-const unsigned kDevicePathPrefixSize = 4;
-const unsigned kSuperPathPrefixSize = 4;
-const unsigned kSuperUncPathPrefixSize = kSuperPathPrefixSize + 4;
-
-bool IsDevicePath(CFSTR s) throw(); /* \\.\ */
-bool IsSuperUncPath(CFSTR s) throw(); /* \\?\UNC\ */
-bool IsNetworkPath(CFSTR s) throw(); /* \\?\UNC\ or \\SERVER */
-
-/* GetNetworkServerPrefixSize() returns size of server prefix:
- \\?\UNC\SERVER\
- \\SERVER\
- in another cases it returns 0
-*/
-
-unsigned GetNetworkServerPrefixSize(CFSTR s) throw();
-
-bool IsNetworkShareRootPath(CFSTR s) throw(); /* \\?\UNC\SERVER\share or \\SERVER\share or with slash */
-
-bool IsDrivePath_SuperAllowed(CFSTR s) throw(); // first chars are drive chars like "a:\" or "\\?\a:\"
-bool IsDriveRootPath_SuperAllowed(CFSTR s) throw(); // exact drive root path "a:\" or "\\?\a:\"
-
-bool IsDrivePath2(const wchar_t *s) throw(); // first 2 chars are drive chars like "a:"
-// bool IsDriveName2(const wchar_t *s) throw(); // is drive name like "a:"
-bool IsSuperPath(const wchar_t *s) throw();
-bool IsSuperOrDevicePath(const wchar_t *s) throw();
-
-#ifndef USE_UNICODE_FSTRING
-bool IsDrivePath2(CFSTR s) throw(); // first 2 chars are drive chars like "a:"
-// bool IsDriveName2(CFSTR s) throw(); // is drive name like "a:"
-bool IsDrivePath(CFSTR s) throw();
-bool IsSuperPath(CFSTR s) throw();
-bool IsSuperOrDevicePath(CFSTR s) throw();
-
-/* GetRootPrefixSize() returns size of ROOT PREFIX for cases:
- \
- \\.\
- C:\
- \\?\C:\
- \\?\UNC\SERVER\Shared\
- \\SERVER\Shared\
- in another cases it returns 0
-*/
-
-unsigned GetRootPrefixSize(CFSTR s) throw();
-
-#endif
-
-int FindAltStreamColon(CFSTR path) throw();
-
-#endif // _WIN32
-
-bool IsAbsolutePath(const wchar_t *s) throw();
-unsigned GetRootPrefixSize(const wchar_t *s) throw();
-
-#ifdef WIN_LONG_PATH
-
-const int kSuperPathType_UseOnlyMain = 0;
-const int kSuperPathType_UseOnlySuper = 1;
-const int kSuperPathType_UseMainAndSuper = 2;
-
-int GetUseSuperPathType(CFSTR s) throw();
-bool GetSuperPath(CFSTR path, UString &superPath, bool onlyIfNew);
-bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew);
-
-#define USE_MAIN_PATH (__useSuperPathType != kSuperPathType_UseOnlySuper)
-#define USE_MAIN_PATH_2 (__useSuperPathType1 != kSuperPathType_UseOnlySuper && __useSuperPathType2 != kSuperPathType_UseOnlySuper)
-
-#define USE_SUPER_PATH (__useSuperPathType != kSuperPathType_UseOnlyMain)
-#define USE_SUPER_PATH_2 (__useSuperPathType1 != kSuperPathType_UseOnlyMain || __useSuperPathType2 != kSuperPathType_UseOnlyMain)
-
-#define IF_USE_MAIN_PATH int __useSuperPathType = GetUseSuperPathType(path); if (USE_MAIN_PATH)
-#define IF_USE_MAIN_PATH_2(x1, x2) \
- int __useSuperPathType1 = GetUseSuperPathType(x1); \
- int __useSuperPathType2 = GetUseSuperPathType(x2); \
- if (USE_MAIN_PATH_2)
-
-#else
-
-#define IF_USE_MAIN_PATH
-#define IF_USE_MAIN_PATH_2(x1, x2)
-
-#endif // WIN_LONG_PATH
-
-bool GetFullPath(CFSTR dirPrefix, CFSTR path, FString &fullPath);
-bool GetFullPath(CFSTR path, FString &fullPath);
-
-}}}
-
-#endif
+// Windows/FileName.h
+
+#ifndef ZIP7_INC_WINDOWS_FILE_NAME_H
+#define ZIP7_INC_WINDOWS_FILE_NAME_H
+
+#include "../Common/MyString.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NName {
+
+int FindSepar(const wchar_t *s) throw();
+#ifndef USE_UNICODE_FSTRING
+int FindSepar(const FChar *s) throw();
+#endif
+
+void NormalizeDirPathPrefix(FString &dirPath); // ensures that it ended with '\\', if dirPath is not epmty
+void NormalizeDirPathPrefix(UString &dirPath);
+
+#ifdef _WIN32
+void NormalizeDirSeparators(FString &s);
+#endif
+
+bool IsDrivePath(const wchar_t *s) throw(); // first 3 chars are drive chars like "a:\\"
+
+bool IsAltPathPrefix(CFSTR s) throw(); /* name: */
+
+#if defined(_WIN32) && !defined(UNDER_CE)
+
+extern const char * const kSuperPathPrefix; /* \\?\ */
+const unsigned kDevicePathPrefixSize = 4;
+const unsigned kSuperPathPrefixSize = 4;
+const unsigned kSuperUncPathPrefixSize = kSuperPathPrefixSize + 4;
+
+bool IsDevicePath(CFSTR s) throw(); /* \\.\ */
+bool IsSuperUncPath(CFSTR s) throw(); /* \\?\UNC\ */
+bool IsNetworkPath(CFSTR s) throw(); /* \\?\UNC\ or \\SERVER */
+
+/* GetNetworkServerPrefixSize() returns size of server prefix:
+ \\?\UNC\SERVER\
+ \\SERVER\
+ in another cases it returns 0
+*/
+
+unsigned GetNetworkServerPrefixSize(CFSTR s) throw();
+
+bool IsNetworkShareRootPath(CFSTR s) throw(); /* \\?\UNC\SERVER\share or \\SERVER\share or with slash */
+
+bool IsDrivePath_SuperAllowed(CFSTR s) throw(); // first chars are drive chars like "a:\" or "\\?\a:\"
+bool IsDriveRootPath_SuperAllowed(CFSTR s) throw(); // exact drive root path "a:\" or "\\?\a:\"
+
+bool IsDrivePath2(const wchar_t *s) throw(); // first 2 chars are drive chars like "a:"
+// bool IsDriveName2(const wchar_t *s) throw(); // is drive name like "a:"
+bool IsSuperPath(const wchar_t *s) throw();
+bool IsSuperOrDevicePath(const wchar_t *s) throw();
+
+bool IsAltStreamPrefixWithColon(const UString &s) throw();
+// returns true, if super prefix was removed
+bool If_IsSuperPath_RemoveSuperPrefix(UString &s);
+
+#ifndef USE_UNICODE_FSTRING
+bool IsDrivePath2(CFSTR s) throw(); // first 2 chars are drive chars like "a:"
+// bool IsDriveName2(CFSTR s) throw(); // is drive name like "a:"
+bool IsDrivePath(CFSTR s) throw();
+bool IsSuperPath(CFSTR s) throw();
+bool IsSuperOrDevicePath(CFSTR s) throw();
+
+/* GetRootPrefixSize() returns size of ROOT PREFIX for cases:
+ \
+ \\.\
+ C:\
+ \\?\C:\
+ \\?\UNC\SERVER\Shared\
+ \\SERVER\Shared\
+ in another cases it returns 0
+*/
+
+unsigned GetRootPrefixSize(CFSTR s) throw();
+
+#endif
+
+int FindAltStreamColon(CFSTR path) throw();
+
+#endif // _WIN32
+
+bool IsAbsolutePath(const wchar_t *s) throw();
+unsigned GetRootPrefixSize(const wchar_t *s) throw();
+
+#ifdef Z7_LONG_PATH
+
+const int kSuperPathType_UseOnlyMain = 0;
+const int kSuperPathType_UseOnlySuper = 1;
+const int kSuperPathType_UseMainAndSuper = 2;
+
+int GetUseSuperPathType(CFSTR s) throw();
+bool GetSuperPath(CFSTR path, UString &superPath, bool onlyIfNew);
+bool GetSuperPaths(CFSTR s1, CFSTR s2, UString &d1, UString &d2, bool onlyIfNew);
+
+#define USE_MAIN_PATH (_useSuperPathType != kSuperPathType_UseOnlySuper)
+#define USE_MAIN_PATH_2 (_useSuperPathType1 != kSuperPathType_UseOnlySuper && _useSuperPathType2 != kSuperPathType_UseOnlySuper)
+
+#define USE_SUPER_PATH (_useSuperPathType != kSuperPathType_UseOnlyMain)
+#define USE_SUPER_PATH_2 (_useSuperPathType1 != kSuperPathType_UseOnlyMain || _useSuperPathType2 != kSuperPathType_UseOnlyMain)
+
+#define IF_USE_MAIN_PATH int _useSuperPathType = GetUseSuperPathType(path); if (USE_MAIN_PATH)
+#define IF_USE_MAIN_PATH_2(x1, x2) \
+ int _useSuperPathType1 = GetUseSuperPathType(x1); \
+ int _useSuperPathType2 = GetUseSuperPathType(x2); \
+ if (USE_MAIN_PATH_2)
+
+#else
+
+#define IF_USE_MAIN_PATH
+#define IF_USE_MAIN_PATH_2(x1, x2)
+
+#endif // Z7_LONG_PATH
+
+/*
+ if (dirPrefix != NULL && (path) is relative)
+ {
+ (dirPrefix) will be used
+ result (fullPath) will contain prefix part of (dirPrefix).
+ }
+ Current_Dir path can be used in 2 cases:
+ 1) if (path) is relative && dirPrefix == NULL
+ 2) for _WIN32: if (path) is absolute starting wuth "\"
+*/
+bool GetFullPath(CFSTR dirPrefix, CFSTR path, FString &fullPath);
+bool GetFullPath(CFSTR path, FString &fullPath);
+
+}}}
+
+#endif
diff --git a/CPP/Windows/FileSystem.cpp b/CPP/Windows/FileSystem.cpp
index 9861062..6a262d9 100644
--- a/CPP/Windows/FileSystem.cpp
+++ b/CPP/Windows/FileSystem.cpp
@@ -1,131 +1,139 @@
-// Windows/FileSystem.cpp
-
-#include "StdAfx.h"
-
-#ifndef UNDER_CE
-
-#ifndef _UNICODE
-#include "../Common/StringConvert.h"
-#endif
-
-#include "FileSystem.h"
-#include "Defs.h"
-
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-namespace NWindows {
-namespace NFile {
-namespace NSystem {
-
-bool MyGetVolumeInformation(
- CFSTR rootPath,
- UString &volumeName,
- LPDWORD volumeSerialNumber,
- LPDWORD maximumComponentLength,
- LPDWORD fileSystemFlags,
- UString &fileSystemName)
-{
- BOOL res;
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- TCHAR v[MAX_PATH + 2]; v[0] = 0;
- TCHAR f[MAX_PATH + 2]; f[0] = 0;
- res = GetVolumeInformation(fs2fas(rootPath),
- v, MAX_PATH,
- volumeSerialNumber, maximumComponentLength, fileSystemFlags,
- f, MAX_PATH);
- volumeName = MultiByteToUnicodeString(v);
- fileSystemName = MultiByteToUnicodeString(f);
- }
- else
- #endif
- {
- WCHAR v[MAX_PATH + 2]; v[0] = 0;
- WCHAR f[MAX_PATH + 2]; f[0] = 0;
- res = GetVolumeInformationW(fs2us(rootPath),
- v, MAX_PATH,
- volumeSerialNumber, maximumComponentLength, fileSystemFlags,
- f, MAX_PATH);
- volumeName = v;
- fileSystemName = f;
- }
- return BOOLToBool(res);
-}
-
-UINT MyGetDriveType(CFSTR pathName)
-{
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- return GetDriveType(fs2fas(pathName));
- }
- else
- #endif
- {
- return GetDriveTypeW(fs2us(pathName));
- }
-}
-
-typedef BOOL (WINAPI * GetDiskFreeSpaceExA_Pointer)(
- LPCSTR lpDirectoryName, // directory name
- PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller
- PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk
- PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk
-);
-
-typedef BOOL (WINAPI * GetDiskFreeSpaceExW_Pointer)(
- LPCWSTR lpDirectoryName, // directory name
- PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller
- PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk
- PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk
-);
-
-bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize)
-{
- DWORD numSectorsPerCluster, bytesPerSector, numFreeClusters, numClusters;
- bool sizeIsDetected = false;
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- GetDiskFreeSpaceExA_Pointer pGetDiskFreeSpaceEx = (GetDiskFreeSpaceExA_Pointer)GetProcAddress(
- GetModuleHandle(TEXT("kernel32.dll")), "GetDiskFreeSpaceExA");
- if (pGetDiskFreeSpaceEx)
- {
- ULARGE_INTEGER freeBytesToCaller2, totalSize2, freeSize2;
- sizeIsDetected = BOOLToBool(pGetDiskFreeSpaceEx(fs2fas(rootPath), &freeBytesToCaller2, &totalSize2, &freeSize2));
- totalSize = totalSize2.QuadPart;
- freeSize = freeSize2.QuadPart;
- }
- if (!::GetDiskFreeSpace(fs2fas(rootPath), &numSectorsPerCluster, &bytesPerSector, &numFreeClusters, &numClusters))
- return false;
- }
- else
- #endif
- {
- GetDiskFreeSpaceExW_Pointer pGetDiskFreeSpaceEx = (GetDiskFreeSpaceExW_Pointer)GetProcAddress(
- GetModuleHandle(TEXT("kernel32.dll")), "GetDiskFreeSpaceExW");
- if (pGetDiskFreeSpaceEx)
- {
- ULARGE_INTEGER freeBytesToCaller2, totalSize2, freeSize2;
- sizeIsDetected = BOOLToBool(pGetDiskFreeSpaceEx(fs2us(rootPath), &freeBytesToCaller2, &totalSize2, &freeSize2));
- totalSize = totalSize2.QuadPart;
- freeSize = freeSize2.QuadPart;
- }
- if (!::GetDiskFreeSpaceW(fs2us(rootPath), &numSectorsPerCluster, &bytesPerSector, &numFreeClusters, &numClusters))
- return false;
- }
- clusterSize = (UInt64)bytesPerSector * (UInt64)numSectorsPerCluster;
- if (!sizeIsDetected)
- {
- totalSize = clusterSize * (UInt64)numClusters;
- freeSize = clusterSize * (UInt64)numFreeClusters;
- }
- return true;
-}
-
-}}}
-
-#endif
+// Windows/FileSystem.cpp
+
+#include "StdAfx.h"
+
+#ifndef UNDER_CE
+
+#ifndef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+
+#include "FileSystem.h"
+#include "Defs.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NFile {
+namespace NSystem {
+
+#ifdef _WIN32
+
+bool MyGetVolumeInformation(
+ CFSTR rootPath,
+ UString &volumeName,
+ LPDWORD volumeSerialNumber,
+ LPDWORD maximumComponentLength,
+ LPDWORD fileSystemFlags,
+ UString &fileSystemName)
+{
+ BOOL res;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ TCHAR v[MAX_PATH + 2]; v[0] = 0;
+ TCHAR f[MAX_PATH + 2]; f[0] = 0;
+ res = GetVolumeInformation(fs2fas(rootPath),
+ v, MAX_PATH,
+ volumeSerialNumber, maximumComponentLength, fileSystemFlags,
+ f, MAX_PATH);
+ volumeName = MultiByteToUnicodeString(v);
+ fileSystemName = MultiByteToUnicodeString(f);
+ }
+ else
+ #endif
+ {
+ WCHAR v[MAX_PATH + 2]; v[0] = 0;
+ WCHAR f[MAX_PATH + 2]; f[0] = 0;
+ res = GetVolumeInformationW(fs2us(rootPath),
+ v, MAX_PATH,
+ volumeSerialNumber, maximumComponentLength, fileSystemFlags,
+ f, MAX_PATH);
+ volumeName = v;
+ fileSystemName = f;
+ }
+ return BOOLToBool(res);
+}
+
+UINT MyGetDriveType(CFSTR pathName)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ return GetDriveType(fs2fas(pathName));
+ }
+ else
+ #endif
+ {
+ return GetDriveTypeW(fs2us(pathName));
+ }
+}
+
+typedef BOOL (WINAPI * Func_GetDiskFreeSpaceExA)(
+ LPCSTR lpDirectoryName, // directory name
+ PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller
+ PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk
+ PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk
+);
+
+typedef BOOL (WINAPI * Func_GetDiskFreeSpaceExW)(
+ LPCWSTR lpDirectoryName, // directory name
+ PULARGE_INTEGER lpFreeBytesAvailable, // bytes available to caller
+ PULARGE_INTEGER lpTotalNumberOfBytes, // bytes on disk
+ PULARGE_INTEGER lpTotalNumberOfFreeBytes // free bytes on disk
+);
+
+bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize)
+{
+ DWORD numSectorsPerCluster, bytesPerSector, numFreeClusters, numClusters;
+ bool sizeIsDetected = false;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ const
+ Func_GetDiskFreeSpaceExA f = Z7_GET_PROC_ADDRESS(
+ Func_GetDiskFreeSpaceExA, GetModuleHandle(TEXT("kernel32.dll")),
+ "GetDiskFreeSpaceExA");
+ if (f)
+ {
+ ULARGE_INTEGER freeBytesToCaller2, totalSize2, freeSize2;
+ sizeIsDetected = BOOLToBool(f(fs2fas(rootPath), &freeBytesToCaller2, &totalSize2, &freeSize2));
+ totalSize = totalSize2.QuadPart;
+ freeSize = freeSize2.QuadPart;
+ }
+ if (!::GetDiskFreeSpace(fs2fas(rootPath), &numSectorsPerCluster, &bytesPerSector, &numFreeClusters, &numClusters))
+ return false;
+ }
+ else
+ #endif
+ {
+ const
+ Func_GetDiskFreeSpaceExW f = Z7_GET_PROC_ADDRESS(
+ Func_GetDiskFreeSpaceExW, GetModuleHandle(TEXT("kernel32.dll")),
+ "GetDiskFreeSpaceExW");
+ if (f)
+ {
+ ULARGE_INTEGER freeBytesToCaller2, totalSize2, freeSize2;
+ sizeIsDetected = BOOLToBool(f(fs2us(rootPath), &freeBytesToCaller2, &totalSize2, &freeSize2));
+ totalSize = totalSize2.QuadPart;
+ freeSize = freeSize2.QuadPart;
+ }
+ if (!::GetDiskFreeSpaceW(fs2us(rootPath), &numSectorsPerCluster, &bytesPerSector, &numFreeClusters, &numClusters))
+ return false;
+ }
+ clusterSize = (UInt64)bytesPerSector * (UInt64)numSectorsPerCluster;
+ if (!sizeIsDetected)
+ {
+ totalSize = clusterSize * (UInt64)numClusters;
+ freeSize = clusterSize * (UInt64)numFreeClusters;
+ }
+ return true;
+}
+
+#endif
+
+}}}
+
+#endif
diff --git a/CPP/Windows/FileSystem.h b/CPP/Windows/FileSystem.h
index b0149de..9f9e399 100644
--- a/CPP/Windows/FileSystem.h
+++ b/CPP/Windows/FileSystem.h
@@ -1,27 +1,31 @@
-// Windows/FileSystem.h
-
-#ifndef __WINDOWS_FILE_SYSTEM_H
-#define __WINDOWS_FILE_SYSTEM_H
-
-#include "../Common/MyString.h"
-#include "../Common/MyTypes.h"
-
-namespace NWindows {
-namespace NFile {
-namespace NSystem {
-
-bool MyGetVolumeInformation(
- CFSTR rootPath ,
- UString &volumeName,
- LPDWORD volumeSerialNumber,
- LPDWORD maximumComponentLength,
- LPDWORD fileSystemFlags,
- UString &fileSystemName);
-
-UINT MyGetDriveType(CFSTR pathName);
-
-bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
-
-}}}
-
-#endif
+// Windows/FileSystem.h
+
+#ifndef ZIP7_INC_WINDOWS_FILE_SYSTEM_H
+#define ZIP7_INC_WINDOWS_FILE_SYSTEM_H
+
+#include "../Common/MyString.h"
+#include "../Common/MyTypes.h"
+
+namespace NWindows {
+namespace NFile {
+namespace NSystem {
+
+#ifdef _WIN32
+
+bool MyGetVolumeInformation(
+ CFSTR rootPath ,
+ UString &volumeName,
+ LPDWORD volumeSerialNumber,
+ LPDWORD maximumComponentLength,
+ LPDWORD fileSystemFlags,
+ UString &fileSystemName);
+
+UINT MyGetDriveType(CFSTR pathName);
+
+bool MyGetDiskFreeSpace(CFSTR rootPath, UInt64 &clusterSize, UInt64 &totalSize, UInt64 &freeSize);
+
+#endif
+
+}}}
+
+#endif
diff --git a/CPP/Windows/Handle.h b/CPP/Windows/Handle.h
index 755eeb8..6ae09ec 100644
--- a/CPP/Windows/Handle.h
+++ b/CPP/Windows/Handle.h
@@ -1,37 +1,39 @@
-// Windows/Handle.h
-
-#ifndef __WINDOWS_HANDLE_H
-#define __WINDOWS_HANDLE_H
-
-namespace NWindows {
-
-class CHandle
-{
-protected:
- HANDLE _handle;
-public:
- operator HANDLE() { return _handle; }
- CHandle(): _handle(NULL) {}
- ~CHandle() { Close(); }
- bool IsCreated() const { return (_handle != NULL); }
- bool Close()
- {
- if (_handle == NULL)
- return true;
- if (!::CloseHandle(_handle))
- return false;
- _handle = NULL;
- return true;
- }
- void Attach(HANDLE handle) { _handle = handle; }
- HANDLE Detach()
- {
- HANDLE handle = _handle;
- _handle = NULL;
- return handle;
- }
-};
-
-}
-
-#endif
+// Windows/Handle.h
+
+#ifndef ZIP7_INC_WINDOWS_HANDLE_H
+#define ZIP7_INC_WINDOWS_HANDLE_H
+
+#include "../Common/MyWindows.h"
+
+namespace NWindows {
+
+class CHandle MY_UNCOPYABLE
+{
+protected:
+ HANDLE _handle;
+public:
+ operator HANDLE() { return _handle; }
+ CHandle(): _handle(NULL) {}
+ ~CHandle() { Close(); }
+ bool IsCreated() const { return (_handle != NULL); }
+ bool Close()
+ {
+ if (_handle == NULL)
+ return true;
+ if (!::CloseHandle(_handle))
+ return false;
+ _handle = NULL;
+ return true;
+ }
+ void Attach(HANDLE handle) { _handle = handle; }
+ HANDLE Detach()
+ {
+ const HANDLE handle = _handle;
+ _handle = NULL;
+ return handle;
+ }
+};
+
+}
+
+#endif
diff --git a/CPP/Windows/MemoryGlobal.cpp b/CPP/Windows/MemoryGlobal.cpp
new file mode 100644
index 0000000..2a22394
--- /dev/null
+++ b/CPP/Windows/MemoryGlobal.cpp
@@ -0,0 +1,36 @@
+// Windows/MemoryGlobal.cpp
+
+#include "StdAfx.h"
+
+#include "MemoryGlobal.h"
+
+namespace NWindows {
+namespace NMemory {
+
+bool CGlobal::Alloc(UINT flags, SIZE_T size) throw()
+{
+ HGLOBAL newBlock = ::GlobalAlloc(flags, size);
+ if (newBlock == NULL)
+ return false;
+ _global = newBlock;
+ return true;
+}
+
+bool CGlobal::Free() throw()
+{
+ if (_global == NULL)
+ return true;
+ _global = ::GlobalFree(_global);
+ return (_global == NULL);
+}
+
+bool CGlobal::ReAlloc(SIZE_T size) throw()
+{
+ HGLOBAL newBlock = ::GlobalReAlloc(_global, size, GMEM_MOVEABLE);
+ if (newBlock == NULL)
+ return false;
+ _global = newBlock;
+ return true;
+}
+
+}}
diff --git a/CPP/Windows/MemoryGlobal.h b/CPP/Windows/MemoryGlobal.h
new file mode 100644
index 0000000..6852591
--- /dev/null
+++ b/CPP/Windows/MemoryGlobal.h
@@ -0,0 +1,55 @@
+// Windows/MemoryGlobal.h
+
+#ifndef ZIP7_INC_WINDOWS_MEMORY_GLOBAL_H
+#define ZIP7_INC_WINDOWS_MEMORY_GLOBAL_H
+
+#include "../Common/MyWindows.h"
+
+namespace NWindows {
+namespace NMemory {
+
+class CGlobal
+{
+ HGLOBAL _global;
+public:
+ CGlobal(): _global(NULL) {}
+ ~CGlobal() { Free(); }
+ operator HGLOBAL() const { return _global; }
+ void Attach(HGLOBAL hGlobal)
+ {
+ Free();
+ _global = hGlobal;
+ }
+ HGLOBAL Detach()
+ {
+ const HGLOBAL h = _global;
+ _global = NULL;
+ return h;
+ }
+ bool Alloc(UINT flags, SIZE_T size) throw();
+ bool Free() throw();
+ LPVOID Lock() const { return GlobalLock(_global); }
+ void Unlock() const { GlobalUnlock(_global); }
+ bool ReAlloc(SIZE_T size) throw();
+};
+
+class CGlobalLock
+{
+ HGLOBAL _global;
+ LPVOID _ptr;
+public:
+ LPVOID GetPointer() const { return _ptr; }
+ CGlobalLock(HGLOBAL hGlobal): _global(hGlobal)
+ {
+ _ptr = GlobalLock(hGlobal);
+ }
+ ~CGlobalLock()
+ {
+ if (_ptr)
+ GlobalUnlock(_global);
+ }
+};
+
+}}
+
+#endif
diff --git a/CPP/Windows/MemoryLock.cpp b/CPP/Windows/MemoryLock.cpp
index d1b3bcc..0bd7504 100644
--- a/CPP/Windows/MemoryLock.cpp
+++ b/CPP/Windows/MemoryLock.cpp
@@ -1,112 +1,124 @@
-// Windows/MemoryLock.cpp
-
-#include "StdAfx.h"
-
-#include "../../C/CpuArch.h"
-
-#include "MemoryLock.h"
-
-namespace NWindows {
-namespace NSecurity {
-
-#ifndef UNDER_CE
-
-#ifdef _UNICODE
-#define MY_FUNC_SELECT(f) :: f
-#else
-#define MY_FUNC_SELECT(f) my_ ## f
-extern "C" {
-typedef BOOL (WINAPI * Func_OpenProcessToken)(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle);
-typedef BOOL (WINAPI * Func_LookupPrivilegeValue)(LPCTSTR lpSystemName, LPCTSTR lpName, PLUID lpLuid);
-typedef BOOL (WINAPI * Func_AdjustTokenPrivileges)(HANDLE TokenHandle, BOOL DisableAllPrivileges,
- PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength);
-}
-#define GET_PROC_ADDR(fff, name) Func_ ## fff my_ ## fff = (Func_ ## fff)GetProcAddress(hModule, name)
-#endif
-
-bool EnablePrivilege(LPCTSTR privilegeName, bool enable)
-{
- bool res = false;
-
- #ifndef _UNICODE
-
- HMODULE hModule = ::LoadLibrary(TEXT("Advapi32.dll"));
- if (hModule == NULL)
- return false;
-
- GET_PROC_ADDR(OpenProcessToken, "OpenProcessToken");
- GET_PROC_ADDR(LookupPrivilegeValue, "LookupPrivilegeValueA");
- GET_PROC_ADDR(AdjustTokenPrivileges, "AdjustTokenPrivileges");
-
- if (my_OpenProcessToken &&
- my_AdjustTokenPrivileges &&
- my_LookupPrivilegeValue)
-
- #endif
-
- {
- HANDLE token;
- if (MY_FUNC_SELECT(OpenProcessToken)(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
- {
- TOKEN_PRIVILEGES tp;
- if (MY_FUNC_SELECT(LookupPrivilegeValue)(NULL, privilegeName, &(tp.Privileges[0].Luid)))
- {
- tp.PrivilegeCount = 1;
- tp.Privileges[0].Attributes = (enable ? SE_PRIVILEGE_ENABLED : 0);
- if (MY_FUNC_SELECT(AdjustTokenPrivileges)(token, FALSE, &tp, 0, NULL, NULL))
- res = (GetLastError() == ERROR_SUCCESS);
- }
- ::CloseHandle(token);
- }
- }
-
- #ifndef _UNICODE
-
- ::FreeLibrary(hModule);
-
- #endif
-
- return res;
-}
-
-
-
-typedef void (WINAPI * Func_RtlGetVersion) (OSVERSIONINFOEXW *);
-
-/*
- We suppose that Window 10 works incorrectly with "Large Pages" at:
- - Windows 10 1703 (15063)
- - Windows 10 1709 (16299)
-
- - Windows 10 1809 (17763) on some CPUs that have no 1 GB page support.
- We need more information about that new BUG in Windows.
-*/
-
-unsigned Get_LargePages_RiskLevel()
-{
- OSVERSIONINFOEXW vi;
- HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll");
- if (!ntdll)
- return 0;
- Func_RtlGetVersion func = (Func_RtlGetVersion)GetProcAddress(ntdll, "RtlGetVersion");
- if (!func)
- return 0;
- func(&vi);
- if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT)
- return 0;
- if (vi.dwMajorVersion + vi.dwMinorVersion != 10)
- return 0;
- if (vi.dwBuildNumber <= 16299)
- return 1;
-
- #ifdef MY_CPU_X86_OR_AMD64
- if (!CPU_IsSupported_PageGB())
- return 1;
- #endif
-
- return 0;
-}
-
-#endif
-
-}}
+// Windows/MemoryLock.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/CpuArch.h"
+
+#include "MemoryLock.h"
+
+namespace NWindows {
+namespace NSecurity {
+
+#ifndef UNDER_CE
+
+#ifdef _UNICODE
+#define MY_FUNC_SELECT(f) :: f
+#else
+#define MY_FUNC_SELECT(f) my_ ## f
+extern "C" {
+typedef BOOL (WINAPI * Func_OpenProcessToken)(HANDLE ProcessHandle, DWORD DesiredAccess, PHANDLE TokenHandle);
+typedef BOOL (WINAPI * Func_LookupPrivilegeValue)(LPCTSTR lpSystemName, LPCTSTR lpName, PLUID lpLuid);
+typedef BOOL (WINAPI * Func_AdjustTokenPrivileges)(HANDLE TokenHandle, BOOL DisableAllPrivileges,
+ PTOKEN_PRIVILEGES NewState, DWORD BufferLength, PTOKEN_PRIVILEGES PreviousState, PDWORD ReturnLength);
+}
+
+#define GET_PROC_ADDR(fff, name) \
+ const Func_ ## fff my_ ## fff = Z7_GET_PROC_ADDRESS( \
+ Func_ ## fff, hModule, name);
+#endif
+
+bool EnablePrivilege(LPCTSTR privilegeName, bool enable)
+{
+ bool res = false;
+
+ #ifndef _UNICODE
+
+ const HMODULE hModule = ::LoadLibrary(TEXT("advapi32.dll"));
+ if (!hModule)
+ return false;
+
+ GET_PROC_ADDR(
+ OpenProcessToken,
+ "OpenProcessToken")
+ GET_PROC_ADDR(
+ LookupPrivilegeValue,
+ "LookupPrivilegeValueA")
+ GET_PROC_ADDR(
+ AdjustTokenPrivileges,
+ "AdjustTokenPrivileges")
+
+ if (my_OpenProcessToken &&
+ my_AdjustTokenPrivileges &&
+ my_LookupPrivilegeValue)
+
+ #endif
+
+ {
+ HANDLE token;
+ if (MY_FUNC_SELECT(OpenProcessToken)(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token))
+ {
+ TOKEN_PRIVILEGES tp;
+ if (MY_FUNC_SELECT(LookupPrivilegeValue)(NULL, privilegeName, &(tp.Privileges[0].Luid)))
+ {
+ tp.PrivilegeCount = 1;
+ tp.Privileges[0].Attributes = (enable ? SE_PRIVILEGE_ENABLED : 0);
+ if (MY_FUNC_SELECT(AdjustTokenPrivileges)(token, FALSE, &tp, 0, NULL, NULL))
+ res = (GetLastError() == ERROR_SUCCESS);
+ }
+ ::CloseHandle(token);
+ }
+ }
+
+ #ifndef _UNICODE
+
+ ::FreeLibrary(hModule);
+
+ #endif
+
+ return res;
+}
+
+
+
+typedef void (WINAPI * Func_RtlGetVersion) (OSVERSIONINFOEXW *);
+
+/*
+ We suppose that Window 10 works incorrectly with "Large Pages" at:
+ - Windows 10 1703 (15063) : incorrect allocating after VirtualFree()
+ - Windows 10 1709 (16299) : incorrect allocating after VirtualFree()
+ - Windows 10 1809 (17763) : the failures for blocks of 1 GiB and larger,
+ if CPU doesn't support 1 GB pages.
+ Windows 10 1903 (18362) probably works correctly.
+*/
+
+unsigned Get_LargePages_RiskLevel()
+{
+ OSVERSIONINFOEXW vi;
+ const HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll");
+ if (!ntdll)
+ return 0;
+ const
+ Func_RtlGetVersion func = Z7_GET_PROC_ADDRESS(
+ Func_RtlGetVersion, ntdll,
+ "RtlGetVersion");
+ if (!func)
+ return 0;
+ func(&vi);
+ if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT)
+ return 0;
+ if (vi.dwMajorVersion + vi.dwMinorVersion != 10)
+ return 0;
+ if (vi.dwBuildNumber <= 16299)
+ return 1;
+
+ #ifdef MY_CPU_X86_OR_AMD64
+ if (vi.dwBuildNumber < 18362 && !CPU_IsSupported_PageGB())
+ return 1;
+ #endif
+
+ return 0;
+}
+
+#endif
+
+}}
diff --git a/CPP/Windows/MemoryLock.h b/CPP/Windows/MemoryLock.h
index d82910f..2b85002 100644
--- a/CPP/Windows/MemoryLock.h
+++ b/CPP/Windows/MemoryLock.h
@@ -1,40 +1,40 @@
-// Windows/MemoryLock.h
-
-#ifndef __WINDOWS_MEMORY_LOCK_H
-#define __WINDOWS_MEMORY_LOCK_H
-
-#include "../Common/MyWindows.h"
-
-namespace NWindows {
-namespace NSecurity {
-
-#ifndef UNDER_CE
-
-bool EnablePrivilege(LPCTSTR privilegeName, bool enable = true);
-
-inline bool EnablePrivilege_LockMemory(bool enable = true)
-{
- return EnablePrivilege(SE_LOCK_MEMORY_NAME, enable);
-}
-
-inline void EnablePrivilege_SymLink()
-{
- /* Probably we do not to set any Privilege for junction points.
- But we need them for Symbolic links */
- NSecurity::EnablePrivilege(SE_RESTORE_NAME);
-
- /* Probably we need only SE_RESTORE_NAME, but there is also
- SE_CREATE_SYMBOLIC_LINK_NAME. So we set it also. Do we need it? */
-
- NSecurity::EnablePrivilege(TEXT("SeCreateSymbolicLinkPrivilege")); // SE_CREATE_SYMBOLIC_LINK_NAME
-
- // Do we need to set SE_BACKUP_NAME ?
-}
-
-unsigned Get_LargePages_RiskLevel();
-
-#endif
-
-}}
-
-#endif
+// Windows/MemoryLock.h
+
+#ifndef ZIP7_INC_WINDOWS_MEMORY_LOCK_H
+#define ZIP7_INC_WINDOWS_MEMORY_LOCK_H
+
+#include "../Common/MyWindows.h"
+
+namespace NWindows {
+namespace NSecurity {
+
+#ifndef UNDER_CE
+
+bool EnablePrivilege(LPCTSTR privilegeName, bool enable = true);
+
+inline bool EnablePrivilege_LockMemory(bool enable = true)
+{
+ return EnablePrivilege(SE_LOCK_MEMORY_NAME, enable);
+}
+
+inline void EnablePrivilege_SymLink()
+{
+ /* Probably we do not to set any Privilege for junction points.
+ But we need them for Symbolic links */
+ NSecurity::EnablePrivilege(SE_RESTORE_NAME);
+
+ /* Probably we need only SE_RESTORE_NAME, but there is also
+ SE_CREATE_SYMBOLIC_LINK_NAME. So we set it also. Do we need it? */
+
+ NSecurity::EnablePrivilege(TEXT("SeCreateSymbolicLinkPrivilege")); // SE_CREATE_SYMBOLIC_LINK_NAME
+
+ // Do we need to set SE_BACKUP_NAME ?
+}
+
+unsigned Get_LargePages_RiskLevel();
+
+#endif
+
+}}
+
+#endif
diff --git a/CPP/Windows/Menu.cpp b/CPP/Windows/Menu.cpp
new file mode 100644
index 0000000..af54c66
--- /dev/null
+++ b/CPP/Windows/Menu.cpp
@@ -0,0 +1,265 @@
+// Windows/Menu.cpp
+
+#include "StdAfx.h"
+
+#ifndef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+#include "Menu.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+
+/*
+structures
+ MENUITEMINFOA
+ MENUITEMINFOW
+contain additional member:
+ #if (WINVER >= 0x0500)
+ HBITMAP hbmpItem;
+ #endif
+If we compile the source code with (WINVER >= 0x0500), some functions
+will not work at NT4, if cbSize is set as sizeof(MENUITEMINFO).
+So we use size of old version of structure in some conditions.
+Win98 probably supports full structure including hbmpItem.
+
+We have 2 ways to get/set string in menu item:
+win95/NT4: we must use MIIM_TYPE only.
+ MIIM_TYPE : Retrieves or sets the fType and dwTypeData members.
+win98/win2000: there are new flags that can be used instead of MIIM_TYPE:
+ MIIM_FTYPE : Retrieves or sets the fType member.
+ MIIM_STRING : Retrieves or sets the dwTypeData member.
+
+Windows versions probably support MIIM_TYPE flag, if we set MENUITEMINFO::cbSize
+as sizeof of old (small) MENUITEMINFO that doesn't include (hbmpItem) field.
+But do all Windows versions support old MIIM_TYPE flag, if we use
+MENUITEMINFO::cbSize as sizeof of new (big) MENUITEMINFO including (hbmpItem) field ?
+win10 probably supports any combination of small/big (cbSize) and old/new MIIM_TYPE/MIIM_STRING.
+*/
+
+#if defined(UNDER_CE) || defined(_WIN64) || (WINVER < 0x0500)
+ #ifndef _UNICODE
+ #define my_compatib_MENUITEMINFOA_size sizeof(MENUITEMINFOA)
+ #endif
+ #define my_compatib_MENUITEMINFOW_size sizeof(MENUITEMINFOW)
+#else
+ #define MY_STRUCT_SIZE_BEFORE(structname, member) ((UINT)(UINT_PTR)((LPBYTE)(&((structname*)0)->member) - (LPBYTE)(structname*)0))
+ #ifndef _UNICODE
+ #define my_compatib_MENUITEMINFOA_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOA, hbmpItem)
+ #endif
+ #define my_compatib_MENUITEMINFOW_size MY_STRUCT_SIZE_BEFORE(MENUITEMINFOW, hbmpItem)
+#if defined(__clang__) && __clang_major__ >= 13
+// error : performing pointer subtraction with a null pointer may have undefined behavior
+#pragma GCC diagnostic ignored "-Wnull-pointer-subtraction"
+#endif
+#endif
+
+
+#define COPY_MENUITEM_field(d, s, name) \
+ d.name = s.name;
+
+#define COPY_MENUITEM_fields(d, s) \
+ COPY_MENUITEM_field(d, s, fMask) \
+ COPY_MENUITEM_field(d, s, fType) \
+ COPY_MENUITEM_field(d, s, fState) \
+ COPY_MENUITEM_field(d, s, wID) \
+ COPY_MENUITEM_field(d, s, hSubMenu) \
+ COPY_MENUITEM_field(d, s, hbmpChecked) \
+ COPY_MENUITEM_field(d, s, hbmpUnchecked) \
+ COPY_MENUITEM_field(d, s, dwItemData) \
+
+static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOW &si)
+{
+ ZeroMemory(&si, sizeof(si));
+ si.cbSize = my_compatib_MENUITEMINFOW_size; // sizeof(si);
+ COPY_MENUITEM_fields(si, item)
+}
+
+#ifndef _UNICODE
+static void ConvertItemToSysForm(const CMenuItem &item, MENUITEMINFOA &si)
+{
+ ZeroMemory(&si, sizeof(si));
+ si.cbSize = my_compatib_MENUITEMINFOA_size; // sizeof(si);
+ COPY_MENUITEM_fields(si, item)
+}
+#endif
+
+static void ConvertItemToMyForm(const MENUITEMINFOW &si, CMenuItem &item)
+{
+ COPY_MENUITEM_fields(item, si)
+}
+
+#ifndef _UNICODE
+static void ConvertItemToMyForm(const MENUITEMINFOA &si, CMenuItem &item)
+{
+ COPY_MENUITEM_fields(item, si)
+}
+#endif
+
+
+bool CMenu::GetItem(UINT itemIndex, bool byPosition, CMenuItem &item) const
+{
+ item.StringValue.Empty();
+ const unsigned kMaxSize = 512;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ MENUITEMINFOA si;
+ ConvertItemToSysForm(item, si);
+ const bool isString = item.IsString();
+ unsigned bufSize = kMaxSize;
+ AString a;
+ if (isString)
+ {
+ si.cch = bufSize;
+ si.dwTypeData = a.GetBuf(bufSize);
+ }
+ bool res = GetItemInfo(itemIndex, byPosition, &si);
+ if (isString)
+ a.ReleaseBuf_CalcLen(bufSize);
+ if (!res)
+ return false;
+ {
+ if (isString && si.cch >= bufSize - 1)
+ {
+ si.dwTypeData = NULL;
+ res = GetItemInfo(itemIndex, byPosition, &si);
+ if (!res)
+ return false;
+ si.cch++;
+ bufSize = si.cch;
+ si.dwTypeData = a.GetBuf(bufSize);
+ res = GetItemInfo(itemIndex, byPosition, &si);
+ a.ReleaseBuf_CalcLen(bufSize);
+ if (!res)
+ return false;
+ }
+ ConvertItemToMyForm(si, item);
+ if (isString)
+ item.StringValue = GetUnicodeString(a);
+ return true;
+ }
+ }
+ else
+ #endif
+ {
+ wchar_t s[kMaxSize + 1];
+ s[0] = 0;
+ MENUITEMINFOW si;
+ ConvertItemToSysForm(item, si);
+ const bool isString = item.IsString();
+ unsigned bufSize = kMaxSize;
+ if (isString)
+ {
+ si.cch = bufSize;
+ si.dwTypeData = s;
+ }
+ bool res = GetItemInfo(itemIndex, byPosition, &si);
+ if (!res)
+ return false;
+ if (isString)
+ {
+ s[Z7_ARRAY_SIZE(s) - 1] = 0;
+ item.StringValue = s;
+ if (si.cch >= bufSize - 1)
+ {
+ si.dwTypeData = NULL;
+ res = GetItemInfo(itemIndex, byPosition, &si);
+ if (!res)
+ return false;
+ si.cch++;
+ bufSize = si.cch;
+ si.dwTypeData = item.StringValue.GetBuf(bufSize);
+ res = GetItemInfo(itemIndex, byPosition, &si);
+ item.StringValue.ReleaseBuf_CalcLen(bufSize);
+ if (!res)
+ return false;
+ }
+ // if (item.StringValue.Len() != si.cch) throw 123; // for debug
+ }
+ ConvertItemToMyForm(si, item);
+ return true;
+ }
+}
+
+
+bool CMenu::SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ MENUITEMINFOA si;
+ ConvertItemToSysForm(item, si);
+ AString s;
+ if (item.IsString())
+ {
+ s = GetSystemString(item.StringValue);
+ si.dwTypeData = s.Ptr_non_const();
+ }
+ return SetItemInfo(itemIndex, byPosition, &si);
+ }
+ else
+ #endif
+ {
+ MENUITEMINFOW si;
+ ConvertItemToSysForm(item, si);
+ if (item.IsString())
+ si.dwTypeData = item.StringValue.Ptr_non_const();
+ return SetItemInfo(itemIndex, byPosition, &si);
+ }
+}
+
+
+bool CMenu::InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ MENUITEMINFOA si;
+ ConvertItemToSysForm(item, si);
+ AString s;
+ if (item.IsString())
+ {
+ s = GetSystemString(item.StringValue);
+ si.dwTypeData = s.Ptr_non_const();
+ }
+ return InsertItem(itemIndex, byPosition, &si);
+ }
+ else
+ #endif
+ {
+ MENUITEMINFOW si;
+ ConvertItemToSysForm(item, si);
+ if (item.IsString())
+ si.dwTypeData = item.StringValue.Ptr_non_const();
+ #ifdef UNDER_CE
+ UINT flags = (item.fType & MFT_SEPARATOR) ? MF_SEPARATOR : MF_STRING;
+ UINT_PTR id = item.wID;
+ if ((item.fMask & MIIM_SUBMENU) != 0)
+ {
+ flags |= MF_POPUP;
+ id = (UINT_PTR)item.hSubMenu;
+ }
+ if (!Insert(itemIndex, flags | (byPosition ? MF_BYPOSITION : MF_BYCOMMAND), id, item.StringValue))
+ return false;
+ return SetItemInfo(itemIndex, byPosition, &si);
+ #else
+ return InsertItem(itemIndex, byPosition, &si);
+ #endif
+ }
+}
+
+#ifndef _UNICODE
+bool CMenu::AppendItem(UINT flags, UINT_PTR newItemID, LPCWSTR newItem)
+{
+ if (g_IsNT)
+ return BOOLToBool(::AppendMenuW(_menu, flags, newItemID, newItem));
+ else
+ return AppendItem(flags, newItemID, GetSystemString(newItem));
+}
+#endif
+
+}
diff --git a/CPP/Windows/Menu.h b/CPP/Windows/Menu.h
new file mode 100644
index 0000000..e1de4c4
--- /dev/null
+++ b/CPP/Windows/Menu.h
@@ -0,0 +1,170 @@
+// Windows/Menu.h
+
+#ifndef ZIP7_INC_WINDOWS_MENU_H
+#define ZIP7_INC_WINDOWS_MENU_H
+
+#include "../Common/MyWindows.h"
+#include "../Common/MyString.h"
+
+#include "Defs.h"
+
+namespace NWindows {
+
+#ifndef MIIM_STRING
+#define MIIM_STRING 0x00000040
+#endif
+/*
+#ifndef MIIM_BITMAP
+#define MIIM_BITMAP 0x00000080
+#endif
+*/
+#ifndef MIIM_FTYPE
+#define MIIM_FTYPE 0x00000100
+#endif
+
+struct CMenuItem
+{
+ UString StringValue;
+ UINT fMask;
+ UINT fType;
+ UINT fState;
+ UINT wID;
+ HMENU hSubMenu;
+ HBITMAP hbmpChecked;
+ HBITMAP hbmpUnchecked;
+ ULONG_PTR dwItemData;
+ // LPTSTR dwTypeData;
+ // UINT cch;
+ // HBITMAP hbmpItem;
+ bool IsString() const { return (fMask & (MIIM_TYPE | MIIM_STRING)) != 0; }
+ bool IsSeparator() const { return (fType == MFT_SEPARATOR); }
+ CMenuItem(): fMask(0), fType(0), fState(0), wID(0),
+ hSubMenu(NULL), hbmpChecked(NULL), hbmpUnchecked(NULL), dwItemData(0) {}
+};
+
+class CMenu
+{
+ HMENU _menu;
+public:
+ CMenu(): _menu(NULL) {}
+ operator HMENU() const { return _menu; }
+ void Attach(HMENU menu) { _menu = menu; }
+
+ HMENU Detach()
+ {
+ const HMENU menu = _menu;
+ _menu = NULL;
+ return menu;
+ }
+
+ bool Create()
+ {
+ _menu = ::CreateMenu();
+ return (_menu != NULL);
+ }
+
+ bool CreatePopup()
+ {
+ _menu = ::CreatePopupMenu();
+ return (_menu != NULL);
+ }
+
+ bool Destroy()
+ {
+ if (!_menu)
+ return false;
+ return BOOLToBool(::DestroyMenu(Detach()));
+ }
+
+ int GetItemCount() const
+ {
+ #ifdef UNDER_CE
+ for (unsigned i = 0;; i++)
+ {
+ CMenuItem item;
+ item.fMask = MIIM_STATE;
+ if (!GetItem(i, true, item))
+ return (int)i;
+ }
+ #else
+ return GetMenuItemCount(_menu);
+ #endif
+ }
+
+ HMENU GetSubMenu(int pos) const { return ::GetSubMenu(_menu, pos); }
+ #ifndef UNDER_CE
+ /*
+ bool GetItemString(UINT idItem, UINT flag, CSysString &result)
+ {
+ result.Empty();
+ int len = ::GetMenuString(_menu, idItem, 0, 0, flag);
+ int len2 = ::GetMenuString(_menu, idItem, result.GetBuf(len + 2), len + 1, flag);
+ if (len > len2)
+ len = len2;
+ result.ReleaseBuf_CalcLen(len + 2);
+ return (len != 0);
+ }
+ */
+ UINT GetItemID(int pos) const { return ::GetMenuItemID(_menu, pos); }
+ UINT GetItemState(UINT id, UINT flags) const { return ::GetMenuState(_menu, id, flags); }
+ #endif
+
+ bool GetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFO itemInfo) const
+ { return BOOLToBool(::GetMenuItemInfo(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); }
+ bool SetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFO itemInfo)
+ { return BOOLToBool(::SetMenuItemInfo(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); }
+
+ bool AppendItem(UINT flags, UINT_PTR newItemID, LPCTSTR newItem)
+ { return BOOLToBool(::AppendMenu(_menu, flags, newItemID, newItem)); }
+
+ bool Insert(UINT position, UINT flags, UINT_PTR idNewItem, LPCTSTR newItem)
+ { return BOOLToBool(::InsertMenu(_menu, position, flags, idNewItem, newItem)); }
+
+ #ifndef UNDER_CE
+ bool InsertItem(UINT itemIndex, bool byPosition, LPCMENUITEMINFO itemInfo)
+ { return BOOLToBool(::InsertMenuItem(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); }
+ #endif
+
+ bool RemoveItem(UINT item, UINT flags) { return BOOLToBool(::RemoveMenu(_menu, item, flags)); }
+ void RemoveAllItemsFrom(UINT index) { while (RemoveItem(index, MF_BYPOSITION)); }
+ void RemoveAllItems() { RemoveAllItemsFrom(0); }
+
+ #ifndef _UNICODE
+ bool GetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo) const
+ { return BOOLToBool(::GetMenuItemInfoW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); }
+ bool InsertItem(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo)
+ { return BOOLToBool(::InsertMenuItemW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); }
+ bool SetItemInfo(UINT itemIndex, bool byPosition, LPMENUITEMINFOW itemInfo)
+ { return BOOLToBool(::SetMenuItemInfoW(_menu, itemIndex, BoolToBOOL(byPosition), itemInfo)); }
+ bool AppendItem(UINT flags, UINT_PTR newItemID, LPCWSTR newItem);
+ #endif
+
+ bool GetItem(UINT itemIndex, bool byPosition, CMenuItem &item) const;
+ bool SetItem(UINT itemIndex, bool byPosition, const CMenuItem &item);
+ bool InsertItem(UINT itemIndex, bool byPosition, const CMenuItem &item);
+
+ int Track(UINT flags, int x, int y, HWND hWnd) { return ::TrackPopupMenuEx(_menu, flags, x, y, hWnd, NULL); }
+
+ bool CheckRadioItem(UINT idFirst, UINT idLast, UINT idCheck, UINT flags)
+ { return BOOLToBool(::CheckMenuRadioItem(_menu, idFirst, idLast, idCheck, flags)); }
+
+ DWORD CheckItem(UINT id, UINT uCheck) { return ::CheckMenuItem(_menu, id, uCheck); }
+ DWORD CheckItemByID(UINT id, bool check) { return CheckItem(id, MF_BYCOMMAND | (check ? MF_CHECKED : MF_UNCHECKED)); }
+
+ BOOL EnableItem(UINT uIDEnableItem, UINT uEnable) { return EnableMenuItem(_menu, uIDEnableItem, uEnable); }
+};
+
+class CMenuDestroyer
+{
+ CMenu *_menu;
+public:
+ CMenuDestroyer(CMenu &menu): _menu(&menu) {}
+ CMenuDestroyer(): _menu(NULL) {}
+ ~CMenuDestroyer() { if (_menu) _menu->Destroy(); }
+ void Attach(CMenu &menu) { _menu = &menu; }
+ void Disable() { _menu = NULL; }
+};
+
+}
+
+#endif
diff --git a/CPP/Windows/NationalTime.cpp b/CPP/Windows/NationalTime.cpp
new file mode 100644
index 0000000..d3c38de
--- /dev/null
+++ b/CPP/Windows/NationalTime.cpp
@@ -0,0 +1,37 @@
+// Windows/NationalTime.cpp
+
+#include "StdAfx.h"
+
+#include "NationalTime.h"
+
+namespace NWindows {
+namespace NNational {
+namespace NTime {
+
+bool MyGetTimeFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time,
+ LPCTSTR format, CSysString &resultString)
+{
+ resultString.Empty();
+ int numChars = ::GetTimeFormat(locale, flags, time, format, NULL, 0);
+ if (numChars == 0)
+ return false;
+ numChars = ::GetTimeFormat(locale, flags, time, format,
+ resultString.GetBuf((unsigned)numChars), numChars + 1);
+ resultString.ReleaseBuf_CalcLen((unsigned)numChars);
+ return (numChars != 0);
+}
+
+bool MyGetDateFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time,
+ LPCTSTR format, CSysString &resultString)
+{
+ resultString.Empty();
+ int numChars = ::GetDateFormat(locale, flags, time, format, NULL, 0);
+ if (numChars == 0)
+ return false;
+ numChars = ::GetDateFormat(locale, flags, time, format,
+ resultString.GetBuf((unsigned)numChars), numChars + 1);
+ resultString.ReleaseBuf_CalcLen((unsigned)numChars);
+ return (numChars != 0);
+}
+
+}}}
diff --git a/CPP/Windows/NationalTime.h b/CPP/Windows/NationalTime.h
new file mode 100644
index 0000000..32ba479
--- /dev/null
+++ b/CPP/Windows/NationalTime.h
@@ -0,0 +1,20 @@
+// Windows/NationalTime.h
+
+#ifndef ZIP7_INC_WINDOWS_NATIONAL_TIME_H
+#define ZIP7_INC_WINDOWS_NATIONAL_TIME_H
+
+#include "../Common/MyString.h"
+
+namespace NWindows {
+namespace NNational {
+namespace NTime {
+
+bool MyGetTimeFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time,
+ LPCTSTR format, CSysString &resultString);
+
+bool MyGetDateFormat(LCID locale, DWORD flags, CONST SYSTEMTIME *time,
+ LPCTSTR format, CSysString &resultString);
+
+}}}
+
+#endif
diff --git a/CPP/Windows/Net.cpp b/CPP/Windows/Net.cpp
new file mode 100644
index 0000000..0ac82d4
--- /dev/null
+++ b/CPP/Windows/Net.cpp
@@ -0,0 +1,398 @@
+// Windows/Net.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/MyBuffer.h"
+
+#ifndef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+
+#include "Net.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+extern "C"
+{
+#if !defined(WNetGetResourceParent)
+// #if defined(Z7_OLD_WIN_SDK)
+// #if (WINVER >= 0x0400)
+DWORD APIENTRY WNetGetResourceParentA(IN LPNETRESOURCEA lpNetResource,
+ OUT LPVOID lpBuffer, IN OUT LPDWORD lpcbBuffer);
+DWORD APIENTRY WNetGetResourceParentW(IN LPNETRESOURCEW lpNetResource,
+ OUT LPVOID lpBuffer, IN OUT LPDWORD lpcbBuffer);
+#ifdef UNICODE
+#define WNetGetResourceParent WNetGetResourceParentW
+#else
+#define WNetGetResourceParent WNetGetResourceParentA
+#endif
+
+DWORD APIENTRY WNetGetResourceInformationA(IN LPNETRESOURCEA lpNetResource,
+ OUT LPVOID lpBuffer, IN OUT LPDWORD lpcbBuffer, OUT LPSTR *lplpSystem);
+DWORD APIENTRY WNetGetResourceInformationW(IN LPNETRESOURCEW lpNetResource,
+ OUT LPVOID lpBuffer, IN OUT LPDWORD lpcbBuffer, OUT LPWSTR *lplpSystem);
+#ifdef UNICODE
+#define WNetGetResourceInformation WNetGetResourceInformationW
+#else
+#define WNetGetResourceInformation WNetGetResourceInformationA
+#endif
+// #endif // (WINVER >= 0x0400)
+#endif
+}
+
+namespace NWindows {
+namespace NNet {
+
+DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCE netResource)
+{
+ Close();
+ const DWORD result = ::WNetOpenEnum(scope, type, usage, netResource, &_handle);
+ _handleAllocated = (result == NO_ERROR);
+ return result;
+}
+
+#ifndef _UNICODE
+DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCEW netResource)
+{
+ Close();
+ const DWORD result = ::WNetOpenEnumW(scope, type, usage, netResource, &_handle);
+ _handleAllocated = (result == NO_ERROR);
+ return result;
+}
+#endif
+
+static void SetComplexString(bool &defined, CSysString &destString, LPCTSTR srcString)
+{
+ defined = (srcString != NULL);
+ if (defined)
+ destString = srcString;
+ else
+ destString.Empty();
+}
+
+static void ConvertNETRESOURCEToCResource(const NETRESOURCE &netResource, CResource &resource)
+{
+ resource.Scope = netResource.dwScope;
+ resource.Type = netResource.dwType;
+ resource.DisplayType = netResource.dwDisplayType;
+ resource.Usage = netResource.dwUsage;
+ SetComplexString(resource.LocalNameIsDefined, resource.LocalName, netResource.lpLocalName);
+ SetComplexString(resource.RemoteNameIsDefined, resource.RemoteName, netResource.lpRemoteName);
+ SetComplexString(resource.CommentIsDefined, resource.Comment, netResource.lpComment);
+ SetComplexString(resource.ProviderIsDefined, resource.Provider, netResource.lpProvider);
+}
+
+static void SetComplexString2(LPTSTR *destString, bool defined, const CSysString &srcString)
+{
+ if (defined)
+ *destString = srcString.Ptr_non_const();
+ else
+ *destString = NULL;
+}
+
+static void ConvertCResourceToNETRESOURCE(const CResource &resource, NETRESOURCE &netResource)
+{
+ netResource.dwScope = resource.Scope;
+ netResource.dwType = resource.Type;
+ netResource.dwDisplayType = resource.DisplayType;
+ netResource.dwUsage = resource.Usage;
+ SetComplexString2(&netResource.lpLocalName, resource.LocalNameIsDefined, resource.LocalName);
+ SetComplexString2(&netResource.lpRemoteName, resource.RemoteNameIsDefined, resource.RemoteName);
+ SetComplexString2(&netResource.lpComment, resource.CommentIsDefined, resource.Comment);
+ SetComplexString2(&netResource.lpProvider, resource.ProviderIsDefined, resource.Provider);
+}
+
+#ifndef _UNICODE
+
+static void SetComplexString(bool &defined, UString &destString, LPCWSTR src)
+{
+ defined = (src != NULL);
+ if (defined)
+ destString = src;
+ else
+ destString.Empty();
+}
+
+static void ConvertNETRESOURCEToCResource(const NETRESOURCEW &netResource, CResourceW &resource)
+{
+ resource.Scope = netResource.dwScope;
+ resource.Type = netResource.dwType;
+ resource.DisplayType = netResource.dwDisplayType;
+ resource.Usage = netResource.dwUsage;
+ SetComplexString(resource.LocalNameIsDefined, resource.LocalName, netResource.lpLocalName);
+ SetComplexString(resource.RemoteNameIsDefined, resource.RemoteName, netResource.lpRemoteName);
+ SetComplexString(resource.CommentIsDefined, resource.Comment, netResource.lpComment);
+ SetComplexString(resource.ProviderIsDefined, resource.Provider, netResource.lpProvider);
+}
+
+static void SetComplexString2(LPWSTR *destString, bool defined, const UString &srcString)
+{
+ if (defined)
+ *destString = srcString.Ptr_non_const();
+ else
+ *destString = NULL;
+}
+
+static void ConvertCResourceToNETRESOURCE(const CResourceW &resource, NETRESOURCEW &netResource)
+{
+ netResource.dwScope = resource.Scope;
+ netResource.dwType = resource.Type;
+ netResource.dwDisplayType = resource.DisplayType;
+ netResource.dwUsage = resource.Usage;
+ SetComplexString2(&netResource.lpLocalName, resource.LocalNameIsDefined, resource.LocalName);
+ SetComplexString2(&netResource.lpRemoteName, resource.RemoteNameIsDefined, resource.RemoteName);
+ SetComplexString2(&netResource.lpComment, resource.CommentIsDefined, resource.Comment);
+ SetComplexString2(&netResource.lpProvider, resource.ProviderIsDefined, resource.Provider);
+}
+
+static void ConvertResourceWToResource(const CResourceW &resourceW, CResource &resource)
+{
+ *(CResourceBase *)&resource = *(CResourceBase *)&resourceW;
+ resource.LocalName = GetSystemString(resourceW.LocalName);
+ resource.RemoteName = GetSystemString(resourceW.RemoteName);
+ resource.Comment = GetSystemString(resourceW.Comment);
+ resource.Provider = GetSystemString(resourceW.Provider);
+}
+
+static void ConvertResourceToResourceW(const CResource &resource, CResourceW &resourceW)
+{
+ *(CResourceBase *)&resourceW = *(CResourceBase *)&resource;
+ resourceW.LocalName = GetUnicodeString(resource.LocalName);
+ resourceW.RemoteName = GetUnicodeString(resource.RemoteName);
+ resourceW.Comment = GetUnicodeString(resource.Comment);
+ resourceW.Provider = GetUnicodeString(resource.Provider);
+}
+#endif
+
+DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, const CResource *resource)
+{
+ NETRESOURCE netResource;
+ LPNETRESOURCE pointer = NULL;
+ if (resource)
+ {
+ ConvertCResourceToNETRESOURCE(*resource, netResource);
+ pointer = &netResource;
+ }
+ return Open(scope, type, usage, pointer);
+}
+
+#ifndef _UNICODE
+DWORD CEnum::Open(DWORD scope, DWORD type, DWORD usage, const CResourceW *resource)
+{
+ if (g_IsNT)
+ {
+ NETRESOURCEW netResource;
+ LPNETRESOURCEW pointer = NULL;
+ if (resource)
+ {
+ ConvertCResourceToNETRESOURCE(*resource, netResource);
+ pointer = &netResource;
+ }
+ return Open(scope, type, usage, pointer);
+ }
+ CResource resourceA;
+ CResource *pointer = NULL;
+ if (resource)
+ {
+ ConvertResourceWToResource(*resource, resourceA);
+ pointer = &resourceA;
+ }
+ return Open(scope, type, usage, pointer);
+}
+#endif
+
+DWORD CEnum::Close()
+{
+ if (!_handleAllocated)
+ return NO_ERROR;
+ const DWORD result = ::WNetCloseEnum(_handle);
+ _handleAllocated = (result != NO_ERROR);
+ return result;
+}
+
+DWORD CEnum::Next(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
+{
+ return ::WNetEnumResource(_handle, lpcCount, lpBuffer, lpBufferSize);
+}
+
+#ifndef _UNICODE
+DWORD CEnum::NextW(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize)
+{
+ return ::WNetEnumResourceW(_handle, lpcCount, lpBuffer, lpBufferSize);
+}
+#endif
+
+DWORD CEnum::Next(CResource &resource)
+{
+ const DWORD kBufferSize = 16384;
+ CByteArr byteBuffer(kBufferSize);
+ LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (void *) (BYTE *)(byteBuffer);
+ ZeroMemory(lpnrLocal, kBufferSize);
+ DWORD bufferSize = kBufferSize;
+ DWORD numEntries = 1;
+ const DWORD result = Next(&numEntries, lpnrLocal, &bufferSize);
+ if (result != NO_ERROR)
+ return result;
+ if (numEntries != 1)
+ return (DWORD)E_FAIL;
+ ConvertNETRESOURCEToCResource(lpnrLocal[0], resource);
+ return result;
+}
+
+#ifndef _UNICODE
+DWORD CEnum::Next(CResourceW &resource)
+{
+ if (g_IsNT)
+ {
+ const DWORD kBufferSize = 16384;
+ CByteArr byteBuffer(kBufferSize);
+ LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (void *) (BYTE *)(byteBuffer);
+ ZeroMemory(lpnrLocal, kBufferSize);
+ DWORD bufferSize = kBufferSize;
+ DWORD numEntries = 1;
+ const DWORD result = NextW(&numEntries, lpnrLocal, &bufferSize);
+ if (result != NO_ERROR)
+ return result;
+ if (numEntries != 1)
+ return (DWORD)E_FAIL;
+ ConvertNETRESOURCEToCResource(lpnrLocal[0], resource);
+ return result;
+ }
+ CResource resourceA;
+ const DWORD result = Next(resourceA);
+ ConvertResourceToResourceW(resourceA, resource);
+ return result;
+}
+#endif
+
+
+DWORD GetResourceParent(const CResource &resource, CResource &parentResource)
+{
+ const DWORD kBufferSize = 16384;
+ CByteArr byteBuffer(kBufferSize);
+ LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (void *) (BYTE *)(byteBuffer);
+ ZeroMemory(lpnrLocal, kBufferSize);
+ DWORD bufferSize = kBufferSize;
+ NETRESOURCE netResource;
+ ConvertCResourceToNETRESOURCE(resource, netResource);
+ const DWORD result = ::WNetGetResourceParent(&netResource, lpnrLocal, &bufferSize);
+ if (result != NO_ERROR)
+ return result;
+ ConvertNETRESOURCEToCResource(lpnrLocal[0], parentResource);
+ return result;
+}
+
+#ifndef _UNICODE
+DWORD GetResourceParent(const CResourceW &resource, CResourceW &parentResource)
+{
+ if (g_IsNT)
+ {
+ const DWORD kBufferSize = 16384;
+ CByteArr byteBuffer(kBufferSize);
+ LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (void *) (BYTE *)(byteBuffer);
+ ZeroMemory(lpnrLocal, kBufferSize);
+ DWORD bufferSize = kBufferSize;
+ NETRESOURCEW netResource;
+ ConvertCResourceToNETRESOURCE(resource, netResource);
+ const DWORD result = ::WNetGetResourceParentW(&netResource, lpnrLocal, &bufferSize);
+ if (result != NO_ERROR)
+ return result;
+ ConvertNETRESOURCEToCResource(lpnrLocal[0], parentResource);
+ return result;
+ }
+ CResource resourceA, parentResourceA;
+ ConvertResourceWToResource(resource, resourceA);
+ const DWORD result = GetResourceParent(resourceA, parentResourceA);
+ ConvertResourceToResourceW(parentResourceA, parentResource);
+ return result;
+}
+#endif
+
+DWORD GetResourceInformation(const CResource &resource,
+ CResource &destResource, CSysString &systemPathPart)
+{
+ const DWORD kBufferSize = 16384;
+ CByteArr byteBuffer(kBufferSize);
+ LPNETRESOURCE lpnrLocal = (LPNETRESOURCE) (void *) (BYTE *)(byteBuffer);
+ ZeroMemory(lpnrLocal, kBufferSize);
+ DWORD bufferSize = kBufferSize;
+ NETRESOURCE netResource;
+ ConvertCResourceToNETRESOURCE(resource, netResource);
+ LPTSTR lplpSystem;
+ const DWORD result = ::WNetGetResourceInformation(&netResource,
+ lpnrLocal, &bufferSize, &lplpSystem);
+ if (result != NO_ERROR)
+ return result;
+ if (lplpSystem != NULL)
+ systemPathPart = lplpSystem;
+ ConvertNETRESOURCEToCResource(lpnrLocal[0], destResource);
+ return result;
+}
+
+#ifndef _UNICODE
+DWORD GetResourceInformation(const CResourceW &resource,
+ CResourceW &destResource, UString &systemPathPart)
+{
+ if (g_IsNT)
+ {
+ const DWORD kBufferSize = 16384;
+ CByteArr byteBuffer(kBufferSize);
+ LPNETRESOURCEW lpnrLocal = (LPNETRESOURCEW) (void *) (BYTE *)(byteBuffer);
+ ZeroMemory(lpnrLocal, kBufferSize);
+ DWORD bufferSize = kBufferSize;
+ NETRESOURCEW netResource;
+ ConvertCResourceToNETRESOURCE(resource, netResource);
+ LPWSTR lplpSystem;
+ const DWORD result = ::WNetGetResourceInformationW(&netResource,
+ lpnrLocal, &bufferSize, &lplpSystem);
+ if (result != NO_ERROR)
+ return result;
+ if (lplpSystem != 0)
+ systemPathPart = lplpSystem;
+ ConvertNETRESOURCEToCResource(lpnrLocal[0], destResource);
+ return result;
+ }
+ CResource resourceA, destResourceA;
+ ConvertResourceWToResource(resource, resourceA);
+ AString systemPathPartA;
+ const DWORD result = GetResourceInformation(resourceA, destResourceA, systemPathPartA);
+ ConvertResourceToResourceW(destResourceA, destResource);
+ systemPathPart = GetUnicodeString(systemPathPartA);
+ return result;
+}
+#endif
+
+DWORD AddConnection2(const CResource &resource,
+ LPCTSTR password, LPCTSTR userName, DWORD flags)
+{
+ NETRESOURCE netResource;
+ ConvertCResourceToNETRESOURCE(resource, netResource);
+ return ::WNetAddConnection2(&netResource,
+ password, userName, flags);
+}
+
+DWORD AddConnection2(const CResource &resource, LPCTSTR password, LPCTSTR userName, DWORD flags);
+
+#ifndef _UNICODE
+DWORD AddConnection2(const CResourceW &resource, LPCWSTR password, LPCWSTR userName, DWORD flags)
+{
+ if (g_IsNT)
+ {
+ NETRESOURCEW netResource;
+ ConvertCResourceToNETRESOURCE(resource, netResource);
+ return ::WNetAddConnection2W(&netResource,password, userName, flags);
+ }
+ CResource resourceA;
+ ConvertResourceWToResource(resource, resourceA);
+ const CSysString passwordA (GetSystemString(password));
+ const CSysString userNameA (GetSystemString(userName));
+ return AddConnection2(resourceA,
+ password ? (LPCTSTR)passwordA: 0,
+ userName ? (LPCTSTR)userNameA: 0,
+ flags);
+}
+#endif
+
+}}
diff --git a/CPP/Windows/Net.h b/CPP/Windows/Net.h
new file mode 100644
index 0000000..a954bdb
--- /dev/null
+++ b/CPP/Windows/Net.h
@@ -0,0 +1,87 @@
+// Windows/Net.h
+
+#ifndef ZIP7_INC_WINDOWS_NET_H
+#define ZIP7_INC_WINDOWS_NET_H
+
+#include "../Common/MyString.h"
+#include "../Common/MyWindows.h"
+
+namespace NWindows {
+namespace NNet {
+
+struct CResourceBase
+{
+ DWORD Scope;
+ DWORD Type;
+ DWORD DisplayType;
+ DWORD Usage;
+ bool LocalNameIsDefined;
+ bool RemoteNameIsDefined;
+ bool CommentIsDefined;
+ bool ProviderIsDefined;
+};
+
+struct CResource: public CResourceBase
+{
+ CSysString LocalName;
+ CSysString RemoteName;
+ CSysString Comment;
+ CSysString Provider;
+};
+
+#ifdef _UNICODE
+typedef CResource CResourceW;
+#else
+struct CResourceW: public CResourceBase
+{
+ UString LocalName;
+ UString RemoteName;
+ UString Comment;
+ UString Provider;
+};
+#endif
+
+class CEnum
+{
+ HANDLE _handle;
+ bool _handleAllocated;
+ DWORD Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCE netResource);
+ DWORD Next(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize);
+ #ifndef _UNICODE
+ DWORD Open(DWORD scope, DWORD type, DWORD usage, LPNETRESOURCEW netResource);
+ DWORD NextW(LPDWORD lpcCount, LPVOID lpBuffer, LPDWORD lpBufferSize);
+ #endif
+protected:
+ bool IsHandleAllocated() const { return _handleAllocated; }
+public:
+ CEnum(): _handleAllocated(false) {}
+ ~CEnum() { Close(); }
+ DWORD Close();
+ DWORD Open(DWORD scope, DWORD type, DWORD usage, const CResource *resource);
+ DWORD Next(CResource &resource);
+ #ifndef _UNICODE
+ DWORD Open(DWORD scope, DWORD type, DWORD usage, const CResourceW *resource);
+ DWORD Next(CResourceW &resource);
+ #endif
+};
+
+DWORD GetResourceParent(const CResource &resource, CResource &parentResource);
+#ifndef _UNICODE
+DWORD GetResourceParent(const CResourceW &resource, CResourceW &parentResource);
+#endif
+
+DWORD GetResourceInformation(const CResource &resource,
+ CResource &destResource, CSysString &systemPathPart);
+#ifndef _UNICODE
+DWORD GetResourceInformation(const CResourceW &resource,
+ CResourceW &destResource, UString &systemPathPart);
+#endif
+
+DWORD AddConnection2(const CResource &resource, LPCTSTR password, LPCTSTR userName, DWORD flags);
+#ifndef _UNICODE
+DWORD AddConnection2(const CResourceW &resource, LPCWSTR password, LPCWSTR userName, DWORD flags);
+#endif
+
+}}
+
+#endif
diff --git a/CPP/Windows/NtCheck.h b/CPP/Windows/NtCheck.h
index 401e239..362a05a 100644
--- a/CPP/Windows/NtCheck.h
+++ b/CPP/Windows/NtCheck.h
@@ -1,46 +1,58 @@
-// Windows/NtCheck.h
-
-#ifndef __WINDOWS_NT_CHECK_H
-#define __WINDOWS_NT_CHECK_H
-
-#ifdef _WIN32
-
-#include "../Common/MyWindows.h"
-
-#if !defined(_WIN64) && !defined(UNDER_CE)
-static inline bool IsItWindowsNT()
-{
- OSVERSIONINFO vi;
- vi.dwOSVersionInfoSize = sizeof(vi);
- return (::GetVersionEx(&vi) && vi.dwPlatformId == VER_PLATFORM_WIN32_NT);
-}
-#endif
-
-#ifndef _UNICODE
- #if defined(_WIN64) || defined(UNDER_CE)
- bool g_IsNT = true;
- #define SET_IS_NT
- #else
- bool g_IsNT = false;
- #define SET_IS_NT g_IsNT = IsItWindowsNT();
- #endif
- #define NT_CHECK_ACTION
- // #define NT_CHECK_ACTION { NT_CHECK_FAIL_ACTION }
-#else
- #if !defined(_WIN64) && !defined(UNDER_CE)
- #define NT_CHECK_ACTION if (!IsItWindowsNT()) { NT_CHECK_FAIL_ACTION }
- #else
- #define NT_CHECK_ACTION
- #endif
- #define SET_IS_NT
-#endif
-
-#define NT_CHECK NT_CHECK_ACTION SET_IS_NT
-
-#else
-
-#define NT_CHECK
-
-#endif
-
-#endif
+// Windows/NtCheck.h
+
+#ifndef ZIP7_INC_WINDOWS_NT_CHECK_H
+#define ZIP7_INC_WINDOWS_NT_CHECK_H
+
+#ifdef _WIN32
+
+#include "../Common/MyWindows.h"
+
+#if !defined(_WIN64) && !defined(UNDER_CE)
+
+#if defined(_MSC_VER) && _MSC_VER >= 1900
+#pragma warning(push)
+// GetVersionExW was declared deprecated
+#pragma warning(disable : 4996)
+#endif
+static inline bool IsItWindowsNT()
+{
+ OSVERSIONINFO vi;
+ vi.dwOSVersionInfoSize = sizeof(vi);
+ return (::GetVersionEx(&vi) && vi.dwPlatformId == VER_PLATFORM_WIN32_NT);
+}
+#if defined(_MSC_VER) && _MSC_VER >= 1900
+#pragma warning(pop)
+#endif
+
+#endif
+
+#ifndef _UNICODE
+ extern
+ bool g_IsNT;
+ #if defined(_WIN64) || defined(UNDER_CE)
+ bool g_IsNT = true;
+ #define SET_IS_NT
+ #else
+ bool g_IsNT = false;
+ #define SET_IS_NT g_IsNT = IsItWindowsNT();
+ #endif
+ #define NT_CHECK_ACTION
+ // #define NT_CHECK_ACTION { NT_CHECK_FAIL_ACTION }
+#else
+ #if !defined(_WIN64) && !defined(UNDER_CE)
+ #define NT_CHECK_ACTION if (!IsItWindowsNT()) { NT_CHECK_FAIL_ACTION }
+ #else
+ #define NT_CHECK_ACTION
+ #endif
+ #define SET_IS_NT
+#endif
+
+#define NT_CHECK NT_CHECK_ACTION SET_IS_NT
+
+#else
+
+#define NT_CHECK
+
+#endif
+
+#endif
diff --git a/CPP/Windows/ProcessMessages.cpp b/CPP/Windows/ProcessMessages.cpp
new file mode 100644
index 0000000..0f48aee
--- /dev/null
+++ b/CPP/Windows/ProcessMessages.cpp
@@ -0,0 +1,22 @@
+// Windows/ProcessMessages.cpp
+
+#include "StdAfx.h"
+
+#include "ProcessMessages.h"
+
+namespace NWindows {
+
+void ProcessMessages(HWND window)
+{
+ MSG msg;
+ while (::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) )
+ {
+ if (window == (HWND) NULL || !IsDialogMessage(window, &msg))
+ {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+}
+
+}
diff --git a/CPP/Windows/ProcessMessages.h b/CPP/Windows/ProcessMessages.h
new file mode 100644
index 0000000..aa98bbb
--- /dev/null
+++ b/CPP/Windows/ProcessMessages.h
@@ -0,0 +1,12 @@
+// Windows/ProcessMessages.h
+
+#ifndef ZIP7_INC_WINDOWS_PROCESS_MESSAGES_H
+#define ZIP7_INC_WINDOWS_PROCESS_MESSAGES_H
+
+namespace NWindows {
+
+void ProcessMessages(HWND window);
+
+}
+
+#endif
diff --git a/CPP/Windows/ProcessUtils.cpp b/CPP/Windows/ProcessUtils.cpp
new file mode 100644
index 0000000..607b4bb
--- /dev/null
+++ b/CPP/Windows/ProcessUtils.cpp
@@ -0,0 +1,102 @@
+// ProcessUtils.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/StringConvert.h"
+
+#include "ProcessUtils.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+
+#ifndef UNDER_CE
+static UString GetQuotedString(const UString &s)
+{
+ UString s2 ('\"');
+ s2 += s;
+ s2 += '\"';
+ return s2;
+}
+#endif
+
+WRes CProcess::Create(LPCWSTR imageName, const UString &params, LPCWSTR curDir)
+{
+ /*
+ OutputDebugStringW(L"CProcess::Create");
+ OutputDebugStringW(imageName);
+ if (params)
+ {
+ OutputDebugStringW(L"params:");
+ OutputDebugStringW(params);
+ }
+ if (curDir)
+ {
+ OutputDebugStringW(L"cur dir:");
+ OutputDebugStringW(curDir);
+ }
+ */
+
+ Close();
+ const UString params2 =
+ #ifndef UNDER_CE
+ GetQuotedString(imageName) + L' ' +
+ #endif
+ params;
+ #ifdef UNDER_CE
+ curDir = NULL;
+ #else
+ imageName = NULL;
+ #endif
+ PROCESS_INFORMATION pi;
+ BOOL result;
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ STARTUPINFOA si;
+ si.cb = sizeof(si);
+ si.lpReserved = NULL;
+ si.lpDesktop = NULL;
+ si.lpTitle = NULL;
+ si.dwFlags = 0;
+ si.cbReserved2 = 0;
+ si.lpReserved2 = NULL;
+
+ CSysString curDirA;
+ if (curDir != 0)
+ curDirA = GetSystemString(curDir);
+ const AString s = GetSystemString(params2);
+ result = ::CreateProcessA(NULL, s.Ptr_non_const(),
+ NULL, NULL, FALSE, 0, NULL, ((curDir != 0) ? (LPCSTR)curDirA: 0), &si, &pi);
+ }
+ else
+ #endif
+ {
+ STARTUPINFOW si;
+ si.cb = sizeof(si);
+ si.lpReserved = NULL;
+ si.lpDesktop = NULL;
+ si.lpTitle = NULL;
+ si.dwFlags = 0;
+ si.cbReserved2 = 0;
+ si.lpReserved2 = NULL;
+
+ result = CreateProcessW(imageName, params2.Ptr_non_const(),
+ NULL, NULL, FALSE, 0, NULL, curDir, &si, &pi);
+ }
+ if (result == 0)
+ return ::GetLastError();
+ ::CloseHandle(pi.hThread);
+ _handle = pi.hProcess;
+ return 0;
+}
+
+WRes MyCreateProcess(LPCWSTR imageName, const UString &params)
+{
+ CProcess process;
+ return process.Create(imageName, params, NULL);
+}
+
+}
diff --git a/CPP/Windows/ProcessUtils.h b/CPP/Windows/ProcessUtils.h
new file mode 100644
index 0000000..b1fce3a
--- /dev/null
+++ b/CPP/Windows/ProcessUtils.h
@@ -0,0 +1,138 @@
+// Windows/ProcessUtils.h
+
+#ifndef ZIP7_INC_WINDOWS_PROCESS_UTILS_H
+#define ZIP7_INC_WINDOWS_PROCESS_UTILS_H
+
+#include "../Common/MyWindows.h"
+
+#ifndef Z7_OLD_WIN_SDK
+
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <psapi.h>
+#else
+#include <Psapi.h>
+#endif
+
+#else // Z7_OLD_WIN_SDK
+
+typedef struct _MODULEINFO {
+ LPVOID lpBaseOfDll;
+ DWORD SizeOfImage;
+ LPVOID EntryPoint;
+} MODULEINFO, *LPMODULEINFO;
+
+typedef struct _PROCESS_MEMORY_COUNTERS {
+ DWORD cb;
+ DWORD PageFaultCount;
+ SIZE_T PeakWorkingSetSize;
+ SIZE_T WorkingSetSize;
+ SIZE_T QuotaPeakPagedPoolUsage;
+ SIZE_T QuotaPagedPoolUsage;
+ SIZE_T QuotaPeakNonPagedPoolUsage;
+ SIZE_T QuotaNonPagedPoolUsage;
+ SIZE_T PagefileUsage;
+ SIZE_T PeakPagefileUsage;
+} PROCESS_MEMORY_COUNTERS;
+typedef PROCESS_MEMORY_COUNTERS *PPROCESS_MEMORY_COUNTERS;
+
+#endif // Z7_OLD_WIN_SDK
+
+#include "../Common/MyString.h"
+
+#include "Defs.h"
+#include "Handle.h"
+
+namespace NWindows {
+
+class CProcess: public CHandle
+{
+public:
+ bool Open(DWORD desiredAccess, bool inheritHandle, DWORD processId)
+ {
+ _handle = ::OpenProcess(desiredAccess, inheritHandle, processId);
+ return (_handle != NULL);
+ }
+
+ #ifndef UNDER_CE
+
+ bool GetExitCodeProcess(LPDWORD lpExitCode) { return BOOLToBool(::GetExitCodeProcess(_handle, lpExitCode)); }
+ bool Terminate(UINT exitCode) { return BOOLToBool(::TerminateProcess(_handle, exitCode)); }
+ #if (WINVER >= 0x0500)
+ DWORD GetGuiResources (DWORD uiFlags) { return ::GetGuiResources(_handle, uiFlags); }
+ #endif
+ bool SetPriorityClass(DWORD dwPriorityClass) { return BOOLToBool(::SetPriorityClass(_handle, dwPriorityClass)); }
+ DWORD GetPriorityClass() { return ::GetPriorityClass(_handle); }
+ // bool GetIoCounters(PIO_COUNTERS lpIoCounters ) { return BOOLToBool(::GetProcessIoCounters(_handle, lpIoCounters )); }
+
+ bool GetTimes(LPFILETIME creationTime, LPFILETIME exitTime, LPFILETIME kernelTime, LPFILETIME userTime)
+ { return BOOLToBool(::GetProcessTimes(_handle, creationTime, exitTime, kernelTime, userTime)); }
+
+ DWORD WaitForInputIdle(DWORD milliseconds) { return ::WaitForInputIdle(_handle, milliseconds); }
+
+ // Debug
+
+ bool ReadMemory(LPCVOID baseAddress, LPVOID buffer, SIZE_T size, SIZE_T* numberOfBytesRead)
+ { return BOOLToBool(::ReadProcessMemory(_handle, baseAddress, buffer, size, numberOfBytesRead)); }
+
+ bool WriteMemory(LPVOID baseAddress, LPCVOID buffer, SIZE_T size, SIZE_T* numberOfBytesWritten)
+ { return BOOLToBool(::WriteProcessMemory(_handle, baseAddress,
+ #ifdef Z7_OLD_WIN_SDK
+ (LPVOID)
+ #endif
+ buffer,
+ size, numberOfBytesWritten)); }
+
+ bool FlushInstructionCache(LPCVOID baseAddress = NULL, SIZE_T size = 0)
+ { return BOOLToBool(::FlushInstructionCache(_handle, baseAddress, size)); }
+
+ LPVOID VirtualAlloc(LPVOID address, SIZE_T size, DWORD allocationType, DWORD protect)
+ { return VirtualAllocEx(_handle, address, size, allocationType, protect); }
+
+ bool VirtualFree(LPVOID address, SIZE_T size, DWORD freeType)
+ { return BOOLToBool(::VirtualFreeEx(_handle, address, size, freeType)); }
+
+ // Process Status API (PSAPI)
+
+ /*
+ bool EmptyWorkingSet()
+ { return BOOLToBool(::EmptyWorkingSet(_handle)); }
+ bool EnumModules(HMODULE *hModules, DWORD arraySizeInBytes, LPDWORD receivedBytes)
+ { return BOOLToBool(::EnumProcessModules(_handle, hModules, arraySizeInBytes, receivedBytes)); }
+ DWORD MyGetModuleBaseName(HMODULE hModule, LPTSTR baseName, DWORD size)
+ { return ::GetModuleBaseName(_handle, hModule, baseName, size); }
+ bool MyGetModuleBaseName(HMODULE hModule, CSysString &name)
+ {
+ const unsigned len = MAX_PATH + 100;
+ const DWORD resultLen = MyGetModuleBaseName(hModule, name.GetBuf(len), len);
+ name.ReleaseBuf_CalcLen(len);
+ return (resultLen != 0);
+ }
+
+ DWORD MyGetModuleFileNameEx(HMODULE hModule, LPTSTR baseName, DWORD size)
+ { return ::GetModuleFileNameEx(_handle, hModule, baseName, size); }
+ bool MyGetModuleFileNameEx(HMODULE hModule, CSysString &name)
+ {
+ const unsigned len = MAX_PATH + 100;
+ const DWORD resultLen = MyGetModuleFileNameEx(hModule, name.GetBuf(len), len);
+ name.ReleaseBuf_CalcLen(len);
+ return (resultLen != 0);
+ }
+
+ bool GetModuleInformation(HMODULE hModule, LPMODULEINFO moduleInfo)
+ { return BOOLToBool(::GetModuleInformation(_handle, hModule, moduleInfo, sizeof(MODULEINFO))); }
+ bool GetMemoryInfo(PPROCESS_MEMORY_COUNTERS memCounters)
+ { return BOOLToBool(::GetProcessMemoryInfo(_handle, memCounters, sizeof(PROCESS_MEMORY_COUNTERS))); }
+ */
+
+ #endif
+
+ WRes Create(LPCWSTR imageName, const UString &params, LPCWSTR curDir);
+
+ DWORD Wait() { return ::WaitForSingleObject(_handle, INFINITE); }
+};
+
+WRes MyCreateProcess(LPCWSTR imageName, const UString &params);
+
+}
+
+#endif
diff --git a/CPP/Windows/PropVariant.cpp b/CPP/Windows/PropVariant.cpp
index 6d9fb48..457b1dc 100644
--- a/CPP/Windows/PropVariant.cpp
+++ b/CPP/Windows/PropVariant.cpp
@@ -1,347 +1,391 @@
-// Windows/PropVariant.cpp
-
-#include "StdAfx.h"
-
-#include "../Common/Defs.h"
-
-#include "PropVariant.h"
-
-namespace NWindows {
-namespace NCOM {
-
-BSTR AllocBstrFromAscii(const char *s) throw()
-{
- if (!s)
- return NULL;
- UINT len = (UINT)strlen(s);
- BSTR p = ::SysAllocStringLen(NULL, len);
- if (p)
- {
- for (UINT i = 0; i <= len; i++)
- p[i] = (Byte)s[i];
- }
- return p;
-}
-
-HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw()
-{
- p->bstrVal = ::SysAllocStringLen(NULL, numChars);
- if (!p->bstrVal)
- {
- p->vt = VT_ERROR;
- p->scode = E_OUTOFMEMORY;
- return E_OUTOFMEMORY;
- }
- p->vt = VT_BSTR;
- return S_OK;
-}
-
-HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw()
-{
- p->bstrVal = AllocBstrFromAscii(s);
- if (p->bstrVal)
- {
- p->vt = VT_BSTR;
- return S_OK;
- }
- p->vt = VT_ERROR;
- p->scode = E_OUTOFMEMORY;
- return E_OUTOFMEMORY;
-}
-
-CPropVariant::CPropVariant(const PROPVARIANT &varSrc)
-{
- vt = VT_EMPTY;
- InternalCopy(&varSrc);
-}
-
-CPropVariant::CPropVariant(const CPropVariant &varSrc)
-{
- vt = VT_EMPTY;
- InternalCopy(&varSrc);
-}
-
-CPropVariant::CPropVariant(BSTR bstrSrc)
-{
- vt = VT_EMPTY;
- *this = bstrSrc;
-}
-
-CPropVariant::CPropVariant(LPCOLESTR lpszSrc)
-{
- vt = VT_EMPTY;
- *this = lpszSrc;
-}
-
-CPropVariant& CPropVariant::operator=(const CPropVariant &varSrc)
-{
- InternalCopy(&varSrc);
- return *this;
-}
-
-CPropVariant& CPropVariant::operator=(const PROPVARIANT &varSrc)
-{
- InternalCopy(&varSrc);
- return *this;
-}
-
-CPropVariant& CPropVariant::operator=(BSTR bstrSrc)
-{
- *this = (LPCOLESTR)bstrSrc;
- return *this;
-}
-
-static const char * const kMemException = "out of memory";
-
-CPropVariant& CPropVariant::operator=(LPCOLESTR lpszSrc)
-{
- InternalClear();
- vt = VT_BSTR;
- wReserved1 = 0;
- bstrVal = ::SysAllocString(lpszSrc);
- if (!bstrVal && lpszSrc)
- {
- throw kMemException;
- // vt = VT_ERROR;
- // scode = E_OUTOFMEMORY;
- }
- return *this;
-}
-
-CPropVariant& CPropVariant::operator=(const UString &s)
-{
- InternalClear();
- vt = VT_BSTR;
- wReserved1 = 0;
- bstrVal = ::SysAllocStringLen(s, s.Len());
- if (!bstrVal)
- throw kMemException;
- return *this;
-}
-
-CPropVariant& CPropVariant::operator=(const UString2 &s)
-{
- /*
- if (s.IsEmpty())
- *this = L"";
- else
- */
- {
- InternalClear();
- vt = VT_BSTR;
- wReserved1 = 0;
- bstrVal = ::SysAllocStringLen(s.GetRawPtr(), s.Len());
- if (!bstrVal)
- throw kMemException;
- /* SysAllocStringLen probably appends a null-terminating character for NULL string.
- But it doesn't specified in MSDN.
- But we suppose that it works
-
- if (!s.GetRawPtr())
- {
- *bstrVal = 0;
- }
- */
-
- /* MSDN: Windows CE: SysAllocStringLen() : Passing invalid (and under some circumstances NULL)
- pointers to this function causes an unexpected termination of the application.
- Is it safe? Maybe we must chamnge the code for that case ? */
- }
- return *this;
-}
-
-CPropVariant& CPropVariant::operator=(const char *s)
-{
- InternalClear();
- vt = VT_BSTR;
- wReserved1 = 0;
- bstrVal = AllocBstrFromAscii(s);
- if (!bstrVal)
- {
- throw kMemException;
- // vt = VT_ERROR;
- // scode = E_OUTOFMEMORY;
- }
- return *this;
-}
-
-CPropVariant& CPropVariant::operator=(bool bSrc) throw()
-{
- if (vt != VT_BOOL)
- {
- InternalClear();
- vt = VT_BOOL;
- }
- boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE;
- return *this;
-}
-
-BSTR CPropVariant::AllocBstr(unsigned numChars)
-{
- if (vt != VT_EMPTY)
- InternalClear();
- vt = VT_BSTR;
- wReserved1 = 0;
- bstrVal = ::SysAllocStringLen(NULL, numChars);
- if (!bstrVal)
- {
- throw kMemException;
- // vt = VT_ERROR;
- // scode = E_OUTOFMEMORY;
- }
- return bstrVal;
-}
-
-#define SET_PROP_FUNC(type, id, dest) \
- CPropVariant& CPropVariant::operator=(type value) throw() \
- { if (vt != id) { InternalClear(); vt = id; } \
- dest = value; return *this; }
-
-SET_PROP_FUNC(Byte, VT_UI1, bVal)
-// SET_PROP_FUNC(Int16, VT_I2, iVal)
-SET_PROP_FUNC(Int32, VT_I4, lVal)
-SET_PROP_FUNC(UInt32, VT_UI4, ulVal)
-SET_PROP_FUNC(UInt64, VT_UI8, uhVal.QuadPart)
-SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart)
-SET_PROP_FUNC(const FILETIME &, VT_FILETIME, filetime)
-
-HRESULT PropVariant_Clear(PROPVARIANT *prop) throw()
-{
- switch (prop->vt)
- {
- case VT_EMPTY:
- case VT_UI1:
- case VT_I1:
- case VT_I2:
- case VT_UI2:
- case VT_BOOL:
- case VT_I4:
- case VT_UI4:
- case VT_R4:
- case VT_INT:
- case VT_UINT:
- case VT_ERROR:
- case VT_FILETIME:
- case VT_UI8:
- case VT_R8:
- case VT_CY:
- case VT_DATE:
- prop->vt = VT_EMPTY;
- prop->wReserved1 = 0;
- prop->wReserved2 = 0;
- prop->wReserved3 = 0;
- prop->uhVal.QuadPart = 0;
- return S_OK;
- }
- return ::VariantClear((VARIANTARG *)prop);
- // return ::PropVariantClear(prop);
- // PropVariantClear can clear VT_BLOB.
-}
-
-HRESULT CPropVariant::Clear() throw()
-{
- if (vt == VT_EMPTY)
- return S_OK;
- return PropVariant_Clear(this);
-}
-
-HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw()
-{
- ::VariantClear((tagVARIANT *)this);
- switch (pSrc->vt)
- {
- case VT_UI1:
- case VT_I1:
- case VT_I2:
- case VT_UI2:
- case VT_BOOL:
- case VT_I4:
- case VT_UI4:
- case VT_R4:
- case VT_INT:
- case VT_UINT:
- case VT_ERROR:
- case VT_FILETIME:
- case VT_UI8:
- case VT_R8:
- case VT_CY:
- case VT_DATE:
- memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT));
- return S_OK;
- }
- return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast<PROPVARIANT *>(pSrc));
-}
-
-
-HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw()
-{
- HRESULT hr = Clear();
- if (FAILED(hr))
- return hr;
- memcpy(this, pSrc, sizeof(PROPVARIANT));
- pSrc->vt = VT_EMPTY;
- return S_OK;
-}
-
-HRESULT CPropVariant::Detach(PROPVARIANT *pDest) throw()
-{
- if (pDest->vt != VT_EMPTY)
- {
- HRESULT hr = PropVariant_Clear(pDest);
- if (FAILED(hr))
- return hr;
- }
- memcpy(pDest, this, sizeof(PROPVARIANT));
- vt = VT_EMPTY;
- return S_OK;
-}
-
-HRESULT CPropVariant::InternalClear() throw()
-{
- if (vt == VT_EMPTY)
- return S_OK;
- HRESULT hr = Clear();
- if (FAILED(hr))
- {
- vt = VT_ERROR;
- scode = hr;
- }
- return hr;
-}
-
-void CPropVariant::InternalCopy(const PROPVARIANT *pSrc)
-{
- HRESULT hr = Copy(pSrc);
- if (FAILED(hr))
- {
- if (hr == E_OUTOFMEMORY)
- throw kMemException;
- vt = VT_ERROR;
- scode = hr;
- }
-}
-
-int CPropVariant::Compare(const CPropVariant &a) throw()
-{
- if (vt != a.vt)
- return MyCompare(vt, a.vt);
- switch (vt)
- {
- case VT_EMPTY: return 0;
- // case VT_I1: return MyCompare(cVal, a.cVal);
- case VT_UI1: return MyCompare(bVal, a.bVal);
- case VT_I2: return MyCompare(iVal, a.iVal);
- case VT_UI2: return MyCompare(uiVal, a.uiVal);
- case VT_I4: return MyCompare(lVal, a.lVal);
- case VT_UI4: return MyCompare(ulVal, a.ulVal);
- // case VT_UINT: return MyCompare(uintVal, a.uintVal);
- case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart);
- case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart);
- case VT_BOOL: return -MyCompare(boolVal, a.boolVal);
- case VT_FILETIME: return ::CompareFileTime(&filetime, &a.filetime);
- case VT_BSTR: return 0; // Not implemented
- default: return 0;
- }
-}
-
-}}
+// Windows/PropVariant.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/Defs.h"
+
+#include "PropVariant.h"
+
+namespace NWindows {
+namespace NCOM {
+
+BSTR AllocBstrFromAscii(const char *s) throw()
+{
+ if (!s)
+ return NULL;
+ UINT len = (UINT)strlen(s);
+ BSTR p = ::SysAllocStringLen(NULL, len);
+ if (p)
+ {
+ for (UINT i = 0; i <= len; i++)
+ p[i] = (Byte)s[i];
+ }
+ return p;
+}
+
+HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw()
+{
+ p->bstrVal = ::SysAllocStringLen(NULL, numChars);
+ if (!p->bstrVal)
+ {
+ p->vt = VT_ERROR;
+ p->scode = E_OUTOFMEMORY;
+ return E_OUTOFMEMORY;
+ }
+ p->vt = VT_BSTR;
+ return S_OK;
+}
+
+HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw()
+{
+ p->bstrVal = AllocBstrFromAscii(s);
+ if (p->bstrVal)
+ {
+ p->vt = VT_BSTR;
+ return S_OK;
+ }
+ p->vt = VT_ERROR;
+ p->scode = E_OUTOFMEMORY;
+ return E_OUTOFMEMORY;
+}
+
+CPropVariant::CPropVariant(const PROPVARIANT &varSrc)
+{
+ vt = VT_EMPTY;
+ InternalCopy(&varSrc);
+}
+
+CPropVariant::CPropVariant(const CPropVariant &varSrc)
+{
+ vt = VT_EMPTY;
+ InternalCopy(&varSrc);
+}
+
+CPropVariant::CPropVariant(BSTR bstrSrc)
+{
+ vt = VT_EMPTY;
+ *this = bstrSrc;
+}
+
+CPropVariant::CPropVariant(LPCOLESTR lpszSrc)
+{
+ vt = VT_EMPTY;
+ *this = lpszSrc;
+}
+
+CPropVariant& CPropVariant::operator=(const CPropVariant &varSrc)
+{
+ InternalCopy(&varSrc);
+ return *this;
+}
+
+CPropVariant& CPropVariant::operator=(const PROPVARIANT &varSrc)
+{
+ InternalCopy(&varSrc);
+ return *this;
+}
+
+CPropVariant& CPropVariant::operator=(BSTR bstrSrc)
+{
+ *this = (LPCOLESTR)bstrSrc;
+ return *this;
+}
+
+static const char * const kMemException = "out of memory";
+
+CPropVariant& CPropVariant::operator=(LPCOLESTR lpszSrc)
+{
+ InternalClear();
+ vt = VT_BSTR;
+ wReserved1 = 0;
+ bstrVal = ::SysAllocString(lpszSrc);
+ if (!bstrVal && lpszSrc)
+ {
+ throw kMemException;
+ // vt = VT_ERROR;
+ // scode = E_OUTOFMEMORY;
+ }
+ return *this;
+}
+
+CPropVariant& CPropVariant::operator=(const UString &s)
+{
+ InternalClear();
+ vt = VT_BSTR;
+ wReserved1 = 0;
+ bstrVal = ::SysAllocStringLen(s, s.Len());
+ if (!bstrVal)
+ throw kMemException;
+ return *this;
+}
+
+CPropVariant& CPropVariant::operator=(const UString2 &s)
+{
+ /*
+ if (s.IsEmpty())
+ *this = L"";
+ else
+ */
+ {
+ InternalClear();
+ vt = VT_BSTR;
+ wReserved1 = 0;
+ bstrVal = ::SysAllocStringLen(s.GetRawPtr(), s.Len());
+ if (!bstrVal)
+ throw kMemException;
+ /* SysAllocStringLen probably appends a null-terminating character for NULL string.
+ But it doesn't specified in MSDN.
+ But we suppose that it works
+
+ if (!s.GetRawPtr())
+ {
+ *bstrVal = 0;
+ }
+ */
+
+ /* MSDN: Windows CE: SysAllocStringLen() : Passing invalid (and under some circumstances NULL)
+ pointers to this function causes an unexpected termination of the application.
+ Is it safe? Maybe we must chamnge the code for that case ? */
+ }
+ return *this;
+}
+
+CPropVariant& CPropVariant::operator=(const char *s)
+{
+ InternalClear();
+ vt = VT_BSTR;
+ wReserved1 = 0;
+ bstrVal = AllocBstrFromAscii(s);
+ if (!bstrVal)
+ {
+ throw kMemException;
+ // vt = VT_ERROR;
+ // scode = E_OUTOFMEMORY;
+ }
+ return *this;
+}
+
+CPropVariant& CPropVariant::operator=(bool bSrc) throw()
+{
+ if (vt != VT_BOOL)
+ {
+ InternalClear();
+ vt = VT_BOOL;
+ }
+ boolVal = bSrc ? VARIANT_TRUE : VARIANT_FALSE;
+ return *this;
+}
+
+BSTR CPropVariant::AllocBstr(unsigned numChars)
+{
+ if (vt != VT_EMPTY)
+ InternalClear();
+ vt = VT_BSTR;
+ wReserved1 = 0;
+ bstrVal = ::SysAllocStringLen(NULL, numChars);
+ if (!bstrVal)
+ {
+ throw kMemException;
+ // vt = VT_ERROR;
+ // scode = E_OUTOFMEMORY;
+ }
+ return bstrVal;
+}
+
+#define SET_PROP_id_dest(id, dest) \
+ if (vt != id) { InternalClear(); vt = id; } dest = value; wReserved1 = 0;
+
+void CPropVariant::Set_Int32(Int32 value) throw()
+{
+ SET_PROP_id_dest(VT_I4, lVal)
+}
+
+void CPropVariant::Set_Int64(Int64 value) throw()
+{
+ SET_PROP_id_dest(VT_I8, hVal.QuadPart)
+}
+
+#define SET_PROP_FUNC(type, id, dest) \
+ CPropVariant& CPropVariant::operator=(type value) throw() \
+ { SET_PROP_id_dest(id, dest) return *this; }
+
+SET_PROP_FUNC(Byte, VT_UI1, bVal)
+// SET_PROP_FUNC(Int16, VT_I2, iVal)
+// SET_PROP_FUNC(Int32, VT_I4, lVal)
+SET_PROP_FUNC(UInt32, VT_UI4, ulVal)
+SET_PROP_FUNC(UInt64, VT_UI8, uhVal.QuadPart)
+// SET_PROP_FUNC(Int64, VT_I8, hVal.QuadPart)
+SET_PROP_FUNC(const FILETIME &, VT_FILETIME, filetime)
+
+#define CASE_SIMPLE_VT_VALUES \
+ case VT_EMPTY: \
+ case VT_BOOL: \
+ case VT_FILETIME: \
+ case VT_UI8: \
+ case VT_UI4: \
+ case VT_UI2: \
+ case VT_UI1: \
+ case VT_I8: \
+ case VT_I4: \
+ case VT_I2: \
+ case VT_I1: \
+ case VT_UINT: \
+ case VT_INT: \
+ case VT_NULL: \
+ case VT_ERROR: \
+ case VT_R4: \
+ case VT_R8: \
+ case VT_CY: \
+ case VT_DATE: \
+
+
+/*
+ ::VariantClear() and ::VariantCopy() don't work, if (vt == VT_FILETIME)
+ So we handle VT_FILETIME and another simple types directly
+ we call system functions for VT_BSTR and for unknown typed
+*/
+
+CPropVariant::~CPropVariant() throw()
+{
+ switch ((unsigned)vt)
+ {
+ CASE_SIMPLE_VT_VALUES
+ // vt = VT_EMPTY; // it's optional
+ return;
+ }
+ ::VariantClear((tagVARIANT *)this);
+}
+
+HRESULT PropVariant_Clear(PROPVARIANT *prop) throw()
+{
+ switch ((unsigned)prop->vt)
+ {
+ CASE_SIMPLE_VT_VALUES
+ prop->vt = VT_EMPTY;
+ break;
+ default:
+ {
+ const HRESULT res = ::VariantClear((VARIANTARG *)prop);
+ if (res != S_OK || prop->vt != VT_EMPTY)
+ return res;
+ break;
+ }
+ }
+ prop->wReserved1 = 0;
+ prop->wReserved2 = 0;
+ prop->wReserved3 = 0;
+ prop->uhVal.QuadPart = 0;
+ return S_OK;
+}
+
+HRESULT CPropVariant::Clear() throw()
+{
+ if (vt == VT_EMPTY)
+ {
+ wReserved1 = 0;
+ return S_OK;
+ }
+ return PropVariant_Clear(this);
+}
+
+HRESULT CPropVariant::Copy(const PROPVARIANT* pSrc) throw()
+{
+ Clear();
+ switch ((unsigned)pSrc->vt)
+ {
+ CASE_SIMPLE_VT_VALUES
+ memmove((PROPVARIANT*)this, pSrc, sizeof(PROPVARIANT));
+ return S_OK;
+ }
+ return ::VariantCopy((tagVARIANT *)this, (tagVARIANT *)const_cast<PROPVARIANT *>(pSrc));
+}
+
+
+HRESULT CPropVariant::Attach(PROPVARIANT *pSrc) throw()
+{
+ const HRESULT hr = Clear();
+ if (FAILED(hr))
+ return hr;
+ // memcpy((PROPVARIANT *)this, pSrc, sizeof(PROPVARIANT));
+ *(PROPVARIANT *)this = *pSrc;
+ pSrc->vt = VT_EMPTY;
+ pSrc->wReserved1 = 0;
+ return S_OK;
+}
+
+HRESULT CPropVariant::Detach(PROPVARIANT *pDest) throw()
+{
+ if (pDest->vt != VT_EMPTY)
+ {
+ const HRESULT hr = PropVariant_Clear(pDest);
+ if (FAILED(hr))
+ return hr;
+ }
+ // memcpy(pDest, this, sizeof(PROPVARIANT));
+ *pDest = *(PROPVARIANT *)this;
+ vt = VT_EMPTY;
+ wReserved1 = 0;
+ return S_OK;
+}
+
+HRESULT CPropVariant::InternalClear() throw()
+{
+ if (vt == VT_EMPTY)
+ {
+ wReserved1 = 0;
+ return S_OK;
+ }
+ const HRESULT hr = Clear();
+ if (FAILED(hr))
+ {
+ vt = VT_ERROR;
+ scode = hr;
+ }
+ return hr;
+}
+
+void CPropVariant::InternalCopy(const PROPVARIANT *pSrc)
+{
+ const HRESULT hr = Copy(pSrc);
+ if (FAILED(hr))
+ {
+ if (hr == E_OUTOFMEMORY)
+ throw kMemException;
+ vt = VT_ERROR;
+ scode = hr;
+ }
+}
+
+
+int CPropVariant::Compare(const CPropVariant &a) throw()
+{
+ if (vt != a.vt)
+ return MyCompare(vt, a.vt);
+ switch ((unsigned)vt)
+ {
+ case VT_EMPTY: return 0;
+ // case VT_I1: return MyCompare(cVal, a.cVal);
+ case VT_UI1: return MyCompare(bVal, a.bVal);
+ case VT_I2: return MyCompare(iVal, a.iVal);
+ case VT_UI2: return MyCompare(uiVal, a.uiVal);
+ case VT_I4: return MyCompare(lVal, a.lVal);
+ case VT_UI4: return MyCompare(ulVal, a.ulVal);
+ // case VT_UINT: return MyCompare(uintVal, a.uintVal);
+ case VT_I8: return MyCompare(hVal.QuadPart, a.hVal.QuadPart);
+ case VT_UI8: return MyCompare(uhVal.QuadPart, a.uhVal.QuadPart);
+ case VT_BOOL: return -MyCompare(boolVal, a.boolVal);
+ case VT_FILETIME:
+ {
+ const int res = CompareFileTime(&filetime, &a.filetime);
+ if (res != 0)
+ return res;
+ const unsigned v1 = Get_Ns100();
+ const unsigned v2 = a.Get_Ns100();
+ return MyCompare(v1, v2);
+ }
+ case VT_BSTR: return 0; // Not implemented
+ default: return 0;
+ }
+}
+
+}}
diff --git a/CPP/Windows/PropVariant.h b/CPP/Windows/PropVariant.h
index f2eaba2..f358fde 100644
--- a/CPP/Windows/PropVariant.h
+++ b/CPP/Windows/PropVariant.h
@@ -1,114 +1,173 @@
-// Windows/PropVariant.h
-
-#ifndef __WINDOWS_PROP_VARIANT_H
-#define __WINDOWS_PROP_VARIANT_H
-
-#include "../Common/MyTypes.h"
-#include "../Common/MyWindows.h"
-#include "../Common/MyString.h"
-
-namespace NWindows {
-namespace NCOM {
-
-BSTR AllocBstrFromAscii(const char *s) throw();
-
-HRESULT PropVariant_Clear(PROPVARIANT *p) throw();
-
-HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw();
-HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw();
-
-inline void PropVarEm_Set_UInt32(PROPVARIANT *p, UInt32 v) throw()
-{
- p->vt = VT_UI4;
- p->ulVal = v;
-}
-
-inline void PropVarEm_Set_UInt64(PROPVARIANT *p, UInt64 v) throw()
-{
- p->vt = VT_UI8;
- p->uhVal.QuadPart = v;
-}
-
-inline void PropVarEm_Set_FileTime64(PROPVARIANT *p, UInt64 v) throw()
-{
- p->vt = VT_FILETIME;
- p->filetime.dwLowDateTime = (DWORD)v;
- p->filetime.dwHighDateTime = (DWORD)(v >> 32);
-}
-
-inline void PropVarEm_Set_Bool(PROPVARIANT *p, bool b) throw()
-{
- p->vt = VT_BOOL;
- p->boolVal = (b ? VARIANT_TRUE : VARIANT_FALSE);
-}
-
-
-class CPropVariant : public tagPROPVARIANT
-{
-public:
- CPropVariant()
- {
- vt = VT_EMPTY;
- wReserved1 = 0;
- // wReserved2 = 0;
- // wReserved3 = 0;
- // uhVal.QuadPart = 0;
- bstrVal = 0;
- }
- ~CPropVariant() throw() { Clear(); }
- CPropVariant(const PROPVARIANT &varSrc);
- CPropVariant(const CPropVariant &varSrc);
- CPropVariant(BSTR bstrSrc);
- CPropVariant(LPCOLESTR lpszSrc);
- CPropVariant(bool bSrc) { vt = VT_BOOL; wReserved1 = 0; boolVal = (bSrc ? VARIANT_TRUE : VARIANT_FALSE); }
- CPropVariant(Byte value) { vt = VT_UI1; wReserved1 = 0; bVal = value; }
-
-private:
- CPropVariant(Int16 value); // { vt = VT_I2; wReserved1 = 0; iVal = value; }
- CPropVariant(Int32 value); // { vt = VT_I4; wReserved1 = 0; lVal = value; }
-
-public:
- CPropVariant(UInt32 value) { vt = VT_UI4; wReserved1 = 0; ulVal = value; }
- CPropVariant(UInt64 value) { vt = VT_UI8; wReserved1 = 0; uhVal.QuadPart = value; }
- CPropVariant(Int64 value) { vt = VT_I8; wReserved1 = 0; hVal.QuadPart = value; }
- CPropVariant(const FILETIME &value) { vt = VT_FILETIME; wReserved1 = 0; filetime = value; }
-
- CPropVariant& operator=(const CPropVariant &varSrc);
- CPropVariant& operator=(const PROPVARIANT &varSrc);
- CPropVariant& operator=(BSTR bstrSrc);
- CPropVariant& operator=(LPCOLESTR lpszSrc);
- CPropVariant& operator=(const UString &s);
- CPropVariant& operator=(const UString2 &s);
- CPropVariant& operator=(const char *s);
- CPropVariant& operator=(const AString &s)
- { return (*this)=(const char *)s; }
-
- CPropVariant& operator=(bool bSrc) throw();
- CPropVariant& operator=(Byte value) throw();
-
-private:
- CPropVariant& operator=(Int16 value) throw();
-
-public:
- CPropVariant& operator=(Int32 value) throw();
- CPropVariant& operator=(UInt32 value) throw();
- CPropVariant& operator=(UInt64 value) throw();
- CPropVariant& operator=(Int64 value) throw();
- CPropVariant& operator=(const FILETIME &value) throw();
-
- BSTR AllocBstr(unsigned numChars);
-
- HRESULT Clear() throw();
- HRESULT Copy(const PROPVARIANT *pSrc) throw();
- HRESULT Attach(PROPVARIANT *pSrc) throw();
- HRESULT Detach(PROPVARIANT *pDest) throw();
-
- HRESULT InternalClear() throw();
- void InternalCopy(const PROPVARIANT *pSrc);
-
- int Compare(const CPropVariant &a) throw();
-};
-
-}}
-
-#endif
+// Windows/PropVariant.h
+
+#ifndef ZIP7_INC_WINDOWS_PROP_VARIANT_H
+#define ZIP7_INC_WINDOWS_PROP_VARIANT_H
+
+#include "../Common/MyTypes.h"
+#include "../Common/MyWindows.h"
+#include "../Common/MyString.h"
+
+namespace NWindows {
+namespace NCOM {
+
+BSTR AllocBstrFromAscii(const char *s) throw();
+
+HRESULT PropVariant_Clear(PROPVARIANT *p) throw();
+
+HRESULT PropVarEm_Alloc_Bstr(PROPVARIANT *p, unsigned numChars) throw();
+HRESULT PropVarEm_Set_Str(PROPVARIANT *p, const char *s) throw();
+
+inline void PropVarEm_Set_UInt32(PROPVARIANT *p, UInt32 v) throw()
+{
+ p->vt = VT_UI4;
+ p->ulVal = v;
+}
+
+inline void PropVarEm_Set_UInt64(PROPVARIANT *p, UInt64 v) throw()
+{
+ p->vt = VT_UI8;
+ p->uhVal.QuadPart = v;
+}
+
+inline void PropVarEm_Set_FileTime64_Prec(PROPVARIANT *p, UInt64 v, unsigned prec) throw()
+{
+ p->vt = VT_FILETIME;
+ p->filetime.dwLowDateTime = (DWORD)v;
+ p->filetime.dwHighDateTime = (DWORD)(v >> 32);
+ p->wReserved1 = (WORD)prec;
+ p->wReserved2 = 0;
+ p->wReserved3 = 0;
+}
+
+inline void PropVarEm_Set_Bool(PROPVARIANT *p, bool b) throw()
+{
+ p->vt = VT_BOOL;
+ p->boolVal = (b ? VARIANT_TRUE : VARIANT_FALSE);
+}
+
+
+class CPropVariant : public tagPROPVARIANT
+{
+ // ---------- forbidden functions ----------
+ CPropVariant(const char *s);
+ // CPropVariant(const UString &s);
+ #ifdef DEBUG_FSTRING_INHERITS_ASTRING
+ CPropVariant(const FString &s);
+ CPropVariant& operator=(const FString &s);
+ #endif
+
+public:
+ CPropVariant()
+ {
+ vt = VT_EMPTY;
+ wReserved1 = 0;
+ // wReserved2 = 0;
+ // wReserved3 = 0;
+ // uhVal.QuadPart = 0;
+ bstrVal = NULL;
+ }
+
+
+ void Set_FtPrec(unsigned prec)
+ {
+ wReserved1 = (WORD)prec;
+ wReserved2 = 0;
+ wReserved3 = 0;
+ }
+
+ void SetAsTimeFrom_FT_Prec(const FILETIME &ft, unsigned prec)
+ {
+ operator=(ft);
+ Set_FtPrec(prec);
+ }
+
+ void SetAsTimeFrom_Ft64_Prec(UInt64 v, unsigned prec)
+ {
+ FILETIME ft;
+ ft.dwLowDateTime = (DWORD)(UInt32)v;
+ ft.dwHighDateTime = (DWORD)(UInt32)(v >> 32);
+ operator=(ft);
+ Set_FtPrec(prec);
+ }
+
+ void SetAsTimeFrom_FT_Prec_Ns100(const FILETIME &ft, unsigned prec, unsigned ns100)
+ {
+ operator=(ft);
+ wReserved1 = (WORD)prec;
+ wReserved2 = (WORD)ns100;
+ wReserved3 = 0;
+ }
+
+ unsigned Get_Ns100() const
+ {
+ const unsigned prec = wReserved1;
+ const unsigned ns100 = wReserved2;
+ if (prec == 0
+ && prec <= k_PropVar_TimePrec_1ns
+ && ns100 < 100
+ && wReserved3 == 0)
+ return ns100;
+ return 0;
+ }
+
+ ~CPropVariant() throw();
+ CPropVariant(const PROPVARIANT &varSrc);
+ CPropVariant(const CPropVariant &varSrc);
+ CPropVariant(BSTR bstrSrc);
+ CPropVariant(LPCOLESTR lpszSrc);
+ CPropVariant(bool bSrc) { vt = VT_BOOL; wReserved1 = 0; boolVal = (bSrc ? VARIANT_TRUE : VARIANT_FALSE); }
+ CPropVariant(Byte value) { vt = VT_UI1; wReserved1 = 0; bVal = value; }
+
+private:
+ CPropVariant(UInt16 value); // { vt = VT_UI2; wReserved1 = 0; uiVal = value; }
+ CPropVariant(Int16 value); // { vt = VT_I2; wReserved1 = 0; iVal = value; }
+ CPropVariant(Int32 value); // { vt = VT_I4; wReserved1 = 0; lVal = value; }
+ CPropVariant(Int64 value); // { vt = VT_I8; wReserved1 = 0; hVal.QuadPart = value; }
+
+public:
+ CPropVariant(UInt32 value) { vt = VT_UI4; wReserved1 = 0; ulVal = value; }
+ CPropVariant(UInt64 value) { vt = VT_UI8; wReserved1 = 0; uhVal.QuadPart = value; }
+ CPropVariant(const FILETIME &value) { vt = VT_FILETIME; wReserved1 = 0; filetime = value; }
+
+ CPropVariant& operator=(const CPropVariant &varSrc);
+ CPropVariant& operator=(const PROPVARIANT &varSrc);
+ CPropVariant& operator=(BSTR bstrSrc);
+ CPropVariant& operator=(LPCOLESTR lpszSrc);
+ CPropVariant& operator=(const UString &s);
+ CPropVariant& operator=(const UString2 &s);
+ CPropVariant& operator=(const char *s);
+ CPropVariant& operator=(const AString &s)
+ { return (*this)=(const char *)s; }
+
+ CPropVariant& operator=(bool bSrc) throw();
+ CPropVariant& operator=(Byte value) throw();
+
+private:
+ CPropVariant& operator=(Int16 value) throw();
+ CPropVariant& operator=(UInt16 value) throw();
+ CPropVariant& operator=(Int32 value) throw();
+ CPropVariant& operator=(Int64 value) throw();
+
+public:
+ CPropVariant& operator=(UInt32 value) throw();
+ CPropVariant& operator=(UInt64 value) throw();
+ CPropVariant& operator=(const FILETIME &value) throw();
+
+ void Set_Int32(Int32 value) throw();
+ void Set_Int64(Int64 value) throw();
+
+ BSTR AllocBstr(unsigned numChars);
+
+ HRESULT Clear() throw();
+ HRESULT Copy(const PROPVARIANT *pSrc) throw();
+ HRESULT Attach(PROPVARIANT *pSrc) throw();
+ HRESULT Detach(PROPVARIANT *pDest) throw();
+
+ HRESULT InternalClear() throw();
+ void InternalCopy(const PROPVARIANT *pSrc);
+ int Compare(const CPropVariant &a) throw();
+};
+
+}}
+
+#endif
diff --git a/CPP/Windows/PropVariantConv.cpp b/CPP/Windows/PropVariantConv.cpp
index c5ac212..5fb96a7 100644
--- a/CPP/Windows/PropVariantConv.cpp
+++ b/CPP/Windows/PropVariantConv.cpp
@@ -1,138 +1,190 @@
-// PropVariantConvert.cpp
-
-#include "StdAfx.h"
-
-#include "../Common/IntToString.h"
-
-#include "Defs.h"
-#include "PropVariantConv.h"
-
-#define UINT_TO_STR_2(c, val) { s[0] = (c); s[1] = (char)('0' + (val) / 10); s[2] = (char)('0' + (val) % 10); s += 3; }
-
-bool ConvertUtcFileTimeToString(const FILETIME &utc, char *s, int level) throw()
-{
- *s = 0;
- FILETIME ft;
- if (!FileTimeToLocalFileTime(&utc, &ft))
- return false;
-
- SYSTEMTIME st;
- if (!BOOLToBool(FileTimeToSystemTime(&ft, &st)))
- return false;
-
- {
- unsigned val = st.wYear;
- if (val >= 10000)
- {
- *s++ = (char)('0' + val / 10000);
- val %= 10000;
- }
- s[3] = (char)('0' + val % 10); val /= 10;
- s[2] = (char)('0' + val % 10); val /= 10;
- s[1] = (char)('0' + val % 10);
- s[0] = (char)('0' + val / 10);
- s += 4;
- }
- UINT_TO_STR_2('-', st.wMonth);
- UINT_TO_STR_2('-', st.wDay);
-
- if (level > kTimestampPrintLevel_DAY)
- {
- UINT_TO_STR_2(' ', st.wHour);
- UINT_TO_STR_2(':', st.wMinute);
-
- if (level >= kTimestampPrintLevel_SEC)
- {
- UINT_TO_STR_2(':', st.wSecond);
-
- if (level > kTimestampPrintLevel_SEC)
- {
- *s++ = '.';
- /*
- {
- unsigned val = st.wMilliseconds;
- s[2] = (char)('0' + val % 10); val /= 10;
- s[1] = (char)('0' + val % 10);
- s[0] = (char)('0' + val / 10);
- s += 3;
- }
- *s++ = ' ';
- */
-
- {
- unsigned numDigits = 7;
- UInt32 val = (UInt32)((((UInt64)ft.dwHighDateTime << 32) + ft.dwLowDateTime) % 10000000);
- for (unsigned i = numDigits; i != 0;)
- {
- i--;
- s[i] = (char)('0' + val % 10); val /= 10;
- }
- if (numDigits > (unsigned)level)
- numDigits = (unsigned)level;
- s += numDigits;
- }
- }
- }
- }
-
- *s = 0;
- return true;
-}
-
-
-bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *dest, int level) throw()
-{
- char s[32];
- bool res = ConvertUtcFileTimeToString(ft, s, level);
- for (unsigned i = 0;; i++)
- {
- unsigned char c = s[i];
- dest[i] = c;
- if (c == 0)
- break;
- }
- return res;
-}
-
-
-void ConvertPropVariantToShortString(const PROPVARIANT &prop, char *dest) throw()
-{
- *dest = 0;
- switch (prop.vt)
- {
- case VT_EMPTY: return;
- case VT_BSTR: dest[0] = '?'; dest[1] = 0; return;
- case VT_UI1: ConvertUInt32ToString(prop.bVal, dest); return;
- case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return;
- case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return;
- case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return;
- case VT_FILETIME: ConvertUtcFileTimeToString(prop.filetime, dest); return;
- // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return;
- case VT_I2: ConvertInt64ToString(prop.iVal, dest); return;
- case VT_I4: ConvertInt64ToString(prop.lVal, dest); return;
- case VT_I8: ConvertInt64ToString(prop.hVal.QuadPart, dest); return;
- case VT_BOOL: dest[0] = VARIANT_BOOLToBool(prop.boolVal) ? '+' : '-'; dest[1] = 0; return;
- default: dest[0] = '?'; dest[1] = ':'; ConvertUInt64ToString(prop.vt, dest + 2);
- }
-}
-
-void ConvertPropVariantToShortString(const PROPVARIANT &prop, wchar_t *dest) throw()
-{
- *dest = 0;
- switch (prop.vt)
- {
- case VT_EMPTY: return;
- case VT_BSTR: dest[0] = '?'; dest[1] = 0; return;
- case VT_UI1: ConvertUInt32ToString(prop.bVal, dest); return;
- case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return;
- case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return;
- case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return;
- case VT_FILETIME: ConvertUtcFileTimeToString(prop.filetime, dest); return;
- // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return;
- case VT_I2: ConvertInt64ToString(prop.iVal, dest); return;
- case VT_I4: ConvertInt64ToString(prop.lVal, dest); return;
- case VT_I8: ConvertInt64ToString(prop.hVal.QuadPart, dest); return;
- case VT_BOOL: dest[0] = VARIANT_BOOLToBool(prop.boolVal) ? (wchar_t)'+' : (wchar_t)'-'; dest[1] = 0; return;
- default: dest[0] = '?'; dest[1] = ':'; ConvertUInt32ToString(prop.vt, dest + 2);
- }
-}
+// PropVariantConv.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/IntToString.h"
+
+#include "Defs.h"
+#include "PropVariantConv.h"
+
+#define UINT_TO_STR_2(c, val) { s[0] = (c); s[1] = (char)('0' + (val) / 10); s[2] = (char)('0' + (val) % 10); s += 3; }
+
+bool ConvertUtcFileTimeToString2(const FILETIME &utc, unsigned ns100, char *s, int level) throw()
+{
+ *s = 0;
+ FILETIME ft;
+ if (!FileTimeToLocalFileTime(&utc, &ft))
+ return false;
+
+ SYSTEMTIME st;
+ if (!BOOLToBool(FileTimeToSystemTime(&ft, &st)))
+ {
+ // win10 : that function doesn't work, if bit 63 of 64-bit FILETIME is set.
+ return false;
+ }
+
+ {
+ unsigned val = st.wYear;
+ if (val >= 10000)
+ {
+ *s++ = (char)('0' + val / 10000);
+ val %= 10000;
+ }
+ s[3] = (char)('0' + val % 10); val /= 10;
+ s[2] = (char)('0' + val % 10); val /= 10;
+ s[1] = (char)('0' + val % 10);
+ s[0] = (char)('0' + val / 10);
+ s += 4;
+ }
+ UINT_TO_STR_2('-', st.wMonth)
+ UINT_TO_STR_2('-', st.wDay)
+
+ if (level > kTimestampPrintLevel_DAY)
+ {
+ UINT_TO_STR_2(' ', st.wHour)
+ UINT_TO_STR_2(':', st.wMinute)
+
+ if (level >= kTimestampPrintLevel_SEC)
+ {
+ UINT_TO_STR_2(':', st.wSecond)
+
+ if (level > kTimestampPrintLevel_SEC)
+ {
+ *s++ = '.';
+ /*
+ {
+ unsigned val = st.wMilliseconds;
+ s[2] = (char)('0' + val % 10); val /= 10;
+ s[1] = (char)('0' + val % 10);
+ s[0] = (char)('0' + val / 10);
+ s += 3;
+ }
+ *s++ = ' ';
+ */
+
+ {
+ unsigned numDigits = 7;
+ UInt32 val = (UInt32)((((UInt64)ft.dwHighDateTime << 32) + ft.dwLowDateTime) % 10000000);
+ for (unsigned i = numDigits; i != 0;)
+ {
+ i--;
+ s[i] = (char)('0' + val % 10); val /= 10;
+ }
+ if (numDigits > (unsigned)level)
+ numDigits = (unsigned)level;
+ s += numDigits;
+ }
+ if (level >= kTimestampPrintLevel_NTFS + 1)
+ {
+ *s++ = (char)('0' + (ns100 / 10));
+ if (level >= kTimestampPrintLevel_NTFS + 2)
+ *s++ = (char)('0' + (ns100 % 10));
+ }
+ }
+ }
+ }
+
+ *s = 0;
+ return true;
+}
+
+
+bool ConvertUtcFileTimeToString(const FILETIME &utc, char *s, int level) throw()
+{
+ return ConvertUtcFileTimeToString2(utc, 0, s, level);
+}
+
+bool ConvertUtcFileTimeToString2(const FILETIME &ft, unsigned ns100, wchar_t *dest, int level) throw()
+{
+ char s[32];
+ bool res = ConvertUtcFileTimeToString2(ft, ns100, s, level);
+ for (unsigned i = 0;; i++)
+ {
+ Byte c = (Byte)s[i];
+ dest[i] = c;
+ if (c == 0)
+ break;
+ }
+ return res;
+}
+
+bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *dest, int level) throw()
+{
+ char s[32];
+ bool res = ConvertUtcFileTimeToString(ft, s, level);
+ for (unsigned i = 0;; i++)
+ {
+ Byte c = (Byte)s[i];
+ dest[i] = c;
+ if (c == 0)
+ break;
+ }
+ return res;
+}
+
+
+void ConvertPropVariantToShortString(const PROPVARIANT &prop, char *dest) throw()
+{
+ *dest = 0;
+ switch (prop.vt)
+ {
+ case VT_EMPTY: return;
+ case VT_BSTR: dest[0] = '?'; dest[1] = 0; return;
+ case VT_UI1: ConvertUInt32ToString(prop.bVal, dest); return;
+ case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return;
+ case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return;
+ case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return;
+ case VT_FILETIME:
+ {
+ // const unsigned prec = prop.wReserved1;
+ int level = 0;
+ /*
+ if (prec == 0)
+ level = 7;
+ else if (prec > 16 && prec <= 16 + 9)
+ level = prec - 16;
+ */
+ ConvertUtcFileTimeToString(prop.filetime, dest, level);
+ return;
+ }
+ // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return;
+ case VT_I2: ConvertInt64ToString(prop.iVal, dest); return;
+ case VT_I4: ConvertInt64ToString(prop.lVal, dest); return;
+ case VT_I8: ConvertInt64ToString(prop.hVal.QuadPart, dest); return;
+ case VT_BOOL: dest[0] = VARIANT_BOOLToBool(prop.boolVal) ? '+' : '-'; dest[1] = 0; return;
+ default: dest[0] = '?'; dest[1] = ':'; ConvertUInt64ToString(prop.vt, dest + 2);
+ }
+}
+
+void ConvertPropVariantToShortString(const PROPVARIANT &prop, wchar_t *dest) throw()
+{
+ *dest = 0;
+ switch (prop.vt)
+ {
+ case VT_EMPTY: return;
+ case VT_BSTR: dest[0] = '?'; dest[1] = 0; return;
+ case VT_UI1: ConvertUInt32ToString(prop.bVal, dest); return;
+ case VT_UI2: ConvertUInt32ToString(prop.uiVal, dest); return;
+ case VT_UI4: ConvertUInt32ToString(prop.ulVal, dest); return;
+ case VT_UI8: ConvertUInt64ToString(prop.uhVal.QuadPart, dest); return;
+ case VT_FILETIME:
+ {
+ // const unsigned prec = prop.wReserved1;
+ int level = 0;
+ /*
+ if (prec == 0)
+ level = 7;
+ else if (prec > 16 && prec <= 16 + 9)
+ level = prec - 16;
+ */
+ ConvertUtcFileTimeToString(prop.filetime, dest, level);
+ return;
+ }
+ // case VT_I1: return ConvertInt64ToString(prop.cVal, dest); return;
+ case VT_I2: ConvertInt64ToString(prop.iVal, dest); return;
+ case VT_I4: ConvertInt64ToString(prop.lVal, dest); return;
+ case VT_I8: ConvertInt64ToString(prop.hVal.QuadPart, dest); return;
+ case VT_BOOL: dest[0] = VARIANT_BOOLToBool(prop.boolVal) ? (wchar_t)'+' : (wchar_t)'-'; dest[1] = 0; return;
+ default: dest[0] = '?'; dest[1] = ':'; ConvertUInt32ToString(prop.vt, dest + 2);
+ }
+}
diff --git a/CPP/Windows/PropVariantConv.h b/CPP/Windows/PropVariantConv.h
index 3e24569..ec5223b 100644
--- a/CPP/Windows/PropVariantConv.h
+++ b/CPP/Windows/PropVariantConv.h
@@ -1,37 +1,40 @@
-// Windows/PropVariantConv.h
-
-#ifndef __PROP_VARIANT_CONV_H
-#define __PROP_VARIANT_CONV_H
-
-#include "../Common/MyTypes.h"
-
-// provide at least 32 bytes for buffer including zero-end
-
-#define kTimestampPrintLevel_DAY -3
-// #define kTimestampPrintLevel_HOUR -2
-#define kTimestampPrintLevel_MIN -1
-#define kTimestampPrintLevel_SEC 0
-#define kTimestampPrintLevel_NTFS 7
-
-bool ConvertUtcFileTimeToString(const FILETIME &ft, char *s, int level = kTimestampPrintLevel_SEC) throw();
-bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *s, int level = kTimestampPrintLevel_SEC) throw();
-
-// provide at least 32 bytes for buffer including zero-end
-// don't send VT_BSTR to these functions
-void ConvertPropVariantToShortString(const PROPVARIANT &prop, char *dest) throw();
-void ConvertPropVariantToShortString(const PROPVARIANT &prop, wchar_t *dest) throw();
-
-inline bool ConvertPropVariantToUInt64(const PROPVARIANT &prop, UInt64 &value)
-{
- switch (prop.vt)
- {
- case VT_UI8: value = (UInt64)prop.uhVal.QuadPart; return true;
- case VT_UI4: value = prop.ulVal; return true;
- case VT_UI2: value = prop.uiVal; return true;
- case VT_UI1: value = prop.bVal; return true;
- case VT_EMPTY: return false;
- default: throw 151199;
- }
-}
-
-#endif
+// Windows/PropVariantConv.h
+
+#ifndef ZIP7_INC_PROP_VARIANT_CONV_H
+#define ZIP7_INC_PROP_VARIANT_CONV_H
+
+#include "../Common/MyTypes.h"
+
+// provide at least 32 bytes for buffer including zero-end
+
+#define kTimestampPrintLevel_DAY -3
+// #define kTimestampPrintLevel_HOUR -2
+#define kTimestampPrintLevel_MIN -1
+#define kTimestampPrintLevel_SEC 0
+#define kTimestampPrintLevel_NTFS 7
+#define kTimestampPrintLevel_NS 9
+
+bool ConvertUtcFileTimeToString(const FILETIME &ft, char *s, int level = kTimestampPrintLevel_SEC) throw();
+bool ConvertUtcFileTimeToString(const FILETIME &ft, wchar_t *s, int level = kTimestampPrintLevel_SEC) throw();
+bool ConvertUtcFileTimeToString2(const FILETIME &ft, unsigned ns100, char *s, int level = kTimestampPrintLevel_SEC) throw();
+bool ConvertUtcFileTimeToString2(const FILETIME &ft, unsigned ns100, wchar_t *s, int level = kTimestampPrintLevel_SEC) throw();
+
+// provide at least 32 bytes for buffer including zero-end
+// don't send VT_BSTR to these functions
+void ConvertPropVariantToShortString(const PROPVARIANT &prop, char *dest) throw();
+void ConvertPropVariantToShortString(const PROPVARIANT &prop, wchar_t *dest) throw();
+
+inline bool ConvertPropVariantToUInt64(const PROPVARIANT &prop, UInt64 &value)
+{
+ switch (prop.vt)
+ {
+ case VT_UI8: value = (UInt64)prop.uhVal.QuadPart; return true;
+ case VT_UI4: value = prop.ulVal; return true;
+ case VT_UI2: value = prop.uiVal; return true;
+ case VT_UI1: value = prop.bVal; return true;
+ case VT_EMPTY: return false;
+ default: throw 151199;
+ }
+}
+
+#endif
diff --git a/CPP/Windows/PropVariantUtils.cpp b/CPP/Windows/PropVariantUtils.cpp
new file mode 100644
index 0000000..6daee83
--- /dev/null
+++ b/CPP/Windows/PropVariantUtils.cpp
@@ -0,0 +1,161 @@
+// PropVariantUtils.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/IntToString.h"
+
+#include "PropVariantUtils.h"
+
+using namespace NWindows;
+
+static void AddHex(AString &s, UInt32 v)
+{
+ char sz[16];
+ sz[0] = '0';
+ sz[1] = 'x';
+ ConvertUInt32ToHex(v, sz + 2);
+ s += sz;
+}
+
+
+AString TypePairToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 value)
+{
+ char sz[16];
+ const char *p = NULL;
+ for (unsigned i = 0; i < num; i++)
+ {
+ const CUInt32PCharPair &pair = pairs[i];
+ if (pair.Value == value)
+ p = pair.Name;
+ }
+ if (!p)
+ {
+ ConvertUInt32ToString(value, sz);
+ p = sz;
+ }
+ return (AString)p;
+}
+
+void PairToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 value, NCOM::CPropVariant &prop)
+{
+ prop = TypePairToString(pairs, num, value);
+}
+
+
+AString TypeToString(const char * const table[], unsigned num, UInt32 value)
+{
+ char sz[16];
+ const char *p = NULL;
+ if (value < num)
+ p = table[value];
+ if (!p)
+ {
+ ConvertUInt32ToString(value, sz);
+ p = sz;
+ }
+ return (AString)p;
+}
+
+void TypeToProp(const char * const table[], unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop)
+{
+ char sz[16];
+ const char *p = NULL;
+ if (value < num)
+ p = table[value];
+ if (!p)
+ {
+ ConvertUInt32ToString(value, sz);
+ p = sz;
+ }
+ prop = p;
+}
+
+
+AString FlagsToString(const char * const *names, unsigned num, UInt32 flags)
+{
+ AString s;
+ for (unsigned i = 0; i < num; i++)
+ {
+ UInt32 flag = (UInt32)1 << i;
+ if ((flags & flag) != 0)
+ {
+ const char *name = names[i];
+ if (name && name[0] != 0)
+ {
+ s.Add_OptSpaced(name);
+ flags &= ~flag;
+ }
+ }
+ }
+ if (flags != 0)
+ {
+ s.Add_Space_if_NotEmpty();
+ AddHex(s, flags);
+ }
+ return s;
+}
+
+AString FlagsToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags)
+{
+ AString s;
+ for (unsigned i = 0; i < num; i++)
+ {
+ const CUInt32PCharPair &p = pairs[i];
+ UInt32 flag = (UInt32)1 << (unsigned)p.Value;
+ if ((flags & flag) != 0)
+ {
+ if (p.Name[0] != 0)
+ s.Add_OptSpaced(p.Name);
+ }
+ flags &= ~flag;
+ }
+ if (flags != 0)
+ {
+ s.Add_Space_if_NotEmpty();
+ AddHex(s, flags);
+ }
+ return s;
+}
+
+void FlagsToProp(const char * const *names, unsigned num, UInt32 flags, NCOM::CPropVariant &prop)
+{
+ prop = FlagsToString(names, num, flags);
+}
+
+void FlagsToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags, NCOM::CPropVariant &prop)
+{
+ prop = FlagsToString(pairs, num, flags);
+}
+
+
+static AString Flags64ToString(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags)
+{
+ AString s;
+ for (unsigned i = 0; i < num; i++)
+ {
+ const CUInt32PCharPair &p = pairs[i];
+ UInt64 flag = (UInt64)1 << (unsigned)p.Value;
+ if ((flags & flag) != 0)
+ {
+ if (p.Name[0] != 0)
+ s.Add_OptSpaced(p.Name);
+ }
+ flags &= ~flag;
+ }
+ if (flags != 0)
+ {
+ {
+ char sz[32];
+ sz[0] = '0';
+ sz[1] = 'x';
+ ConvertUInt64ToHex(flags, sz + 2);
+ s.Add_OptSpaced(sz);
+ }
+ }
+ return s;
+}
+
+void Flags64ToProp(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags, NCOM::CPropVariant &prop)
+{
+ prop = Flags64ToString(pairs, num, flags);
+}
diff --git a/CPP/Windows/PropVariantUtils.h b/CPP/Windows/PropVariantUtils.h
new file mode 100644
index 0000000..78adb50
--- /dev/null
+++ b/CPP/Windows/PropVariantUtils.h
@@ -0,0 +1,34 @@
+// Windows/PropVariantUtils.h
+
+#ifndef ZIP7_INC_PROP_VARIANT_UTILS_H
+#define ZIP7_INC_PROP_VARIANT_UTILS_H
+
+#include "../Common/MyString.h"
+
+#include "PropVariant.h"
+
+struct CUInt32PCharPair
+{
+ UInt32 Value;
+ const char *Name;
+};
+
+AString TypePairToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 value);
+void PairToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop);
+
+AString FlagsToString(const char * const *names, unsigned num, UInt32 flags);
+AString FlagsToString(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags);
+void FlagsToProp(const char * const *names, unsigned num, UInt32 flags, NWindows::NCOM::CPropVariant &prop);
+void FlagsToProp(const CUInt32PCharPair *pairs, unsigned num, UInt32 flags, NWindows::NCOM::CPropVariant &prop);
+
+AString TypeToString(const char * const table[], unsigned num, UInt32 value);
+void TypeToProp(const char * const table[], unsigned num, UInt32 value, NWindows::NCOM::CPropVariant &prop);
+
+#define PAIR_TO_PROP(pairs, value, prop) PairToProp(pairs, Z7_ARRAY_SIZE(pairs), value, prop)
+#define FLAGS_TO_PROP(pairs, value, prop) FlagsToProp(pairs, Z7_ARRAY_SIZE(pairs), value, prop)
+#define TYPE_TO_PROP(table, value, prop) TypeToProp(table, Z7_ARRAY_SIZE(table), value, prop)
+
+void Flags64ToProp(const CUInt32PCharPair *pairs, unsigned num, UInt64 flags, NWindows::NCOM::CPropVariant &prop);
+#define FLAGS64_TO_PROP(pairs, value, prop) Flags64ToProp(pairs, Z7_ARRAY_SIZE(pairs), value, prop)
+
+#endif
diff --git a/CPP/Windows/Registry.cpp b/CPP/Windows/Registry.cpp
index 0146621..b20157d 100644
--- a/CPP/Windows/Registry.cpp
+++ b/CPP/Windows/Registry.cpp
@@ -1,390 +1,406 @@
-// Windows/Registry.cpp
-
-#include "StdAfx.h"
-
-#include <wchar.h>
-
-#ifndef _UNICODE
-#include "../Common/StringConvert.h"
-#endif
-#include "Registry.h"
-
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-namespace NWindows {
-namespace NRegistry {
-
-#define MYASSERT(expr) // _ASSERTE(expr)
-
-LONG CKey::Create(HKEY parentKey, LPCTSTR keyName,
- LPTSTR keyClass, DWORD options, REGSAM accessMask,
- LPSECURITY_ATTRIBUTES securityAttributes, LPDWORD disposition) throw()
-{
- MYASSERT(parentKey != NULL);
- DWORD dispositionReal;
- HKEY key = NULL;
- LONG res = RegCreateKeyEx(parentKey, keyName, 0, keyClass,
- options, accessMask, securityAttributes, &key, &dispositionReal);
- if (disposition != NULL)
- *disposition = dispositionReal;
- if (res == ERROR_SUCCESS)
- {
- res = Close();
- _object = key;
- }
- return res;
-}
-
-LONG CKey::Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask) throw()
-{
- MYASSERT(parentKey != NULL);
- HKEY key = NULL;
- LONG res = RegOpenKeyEx(parentKey, keyName, 0, accessMask, &key);
- if (res == ERROR_SUCCESS)
- {
- res = Close();
- MYASSERT(res == ERROR_SUCCESS);
- _object = key;
- }
- return res;
-}
-
-LONG CKey::Close() throw()
-{
- LONG res = ERROR_SUCCESS;
- if (_object != NULL)
- {
- res = RegCloseKey(_object);
- _object = NULL;
- }
- return res;
-}
-
-// win95, win98: deletes sunkey and all its subkeys
-// winNT to be deleted must not have subkeys
-LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw()
-{
- MYASSERT(_object != NULL);
- return RegDeleteKey(_object, subKeyName);
-}
-
-LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName) throw()
-{
- CKey key;
- LONG res = key.Open(_object, subKeyName, KEY_READ | KEY_WRITE);
- if (res != ERROR_SUCCESS)
- return res;
- FILETIME fileTime;
- const UInt32 kBufSize = MAX_PATH + 1; // 256 in ATL
- DWORD size = kBufSize;
- TCHAR buffer[kBufSize];
- while (RegEnumKeyEx(key._object, 0, buffer, &size, NULL, NULL, NULL, &fileTime) == ERROR_SUCCESS)
- {
- res = key.RecurseDeleteKey(buffer);
- if (res != ERROR_SUCCESS)
- return res;
- size = kBufSize;
- }
- key.Close();
- return DeleteSubKey(subKeyName);
-}
-
-
-/////////////////////////
-// Value Functions
-
-static inline UInt32 BoolToUINT32(bool value) { return (value ? 1: 0); }
-static inline bool UINT32ToBool(UInt32 value) { return (value != 0); }
-
-
-LONG CKey::DeleteValue(LPCTSTR name) throw()
-{
- MYASSERT(_object != NULL);
- return ::RegDeleteValue(_object, name);
-}
-
-#ifndef _UNICODE
-LONG CKey::DeleteValue(LPCWSTR name)
-{
- MYASSERT(_object != NULL);
- if (g_IsNT)
- return ::RegDeleteValueW(_object, name);
- return DeleteValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name));
-}
-#endif
-
-LONG CKey::SetValue(LPCTSTR name, UInt32 value) throw()
-{
- MYASSERT(_object != NULL);
- return RegSetValueEx(_object, name, 0, REG_DWORD,
- (BYTE * const)&value, sizeof(UInt32));
-}
-
-LONG CKey::SetValue(LPCTSTR name, bool value) throw()
-{
- return SetValue(name, BoolToUINT32(value));
-}
-
-LONG CKey::SetValue(LPCTSTR name, LPCTSTR value) throw()
-{
- MYASSERT(value != NULL);
- MYASSERT(_object != NULL);
- return RegSetValueEx(_object, name, 0, REG_SZ,
- (const BYTE * )value, (lstrlen(value) + 1) * sizeof(TCHAR));
-}
-
-/*
-LONG CKey::SetValue(LPCTSTR name, const CSysString &value)
-{
- MYASSERT(value != NULL);
- MYASSERT(_object != NULL);
- return RegSetValueEx(_object, name, NULL, REG_SZ,
- (const BYTE *)(const TCHAR *)value, (value.Len() + 1) * sizeof(TCHAR));
-}
-*/
-
-#ifndef _UNICODE
-
-LONG CKey::SetValue(LPCWSTR name, LPCWSTR value)
-{
- MYASSERT(value != NULL);
- MYASSERT(_object != NULL);
- if (g_IsNT)
- return RegSetValueExW(_object, name, 0, REG_SZ,
- (const BYTE * )value, (DWORD)((wcslen(value) + 1) * sizeof(wchar_t)));
- return SetValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name),
- value == 0 ? 0 : (LPCSTR)GetSystemString(value));
-}
-
-#endif
-
-
-LONG CKey::SetValue(LPCTSTR name, const void *value, UInt32 size) throw()
-{
- MYASSERT(value != NULL);
- MYASSERT(_object != NULL);
- return RegSetValueEx(_object, name, 0, REG_BINARY,
- (const BYTE *)value, size);
-}
-
-LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value)
-{
- MYASSERT(value != NULL);
- CKey key;
- LONG res = key.Create(parentKey, keyName);
- if (res == ERROR_SUCCESS)
- res = key.SetValue(valueName, value);
- return res;
-}
-
-LONG CKey::SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw()
-{
- MYASSERT(value != NULL);
- CKey key;
- LONG res = key.Create(_object, keyName);
- if (res == ERROR_SUCCESS)
- res = key.SetValue(valueName, value);
- return res;
-}
-
-LONG CKey::QueryValue(LPCTSTR name, UInt32 &value) throw()
-{
- DWORD type = 0;
- DWORD count = sizeof(DWORD);
- LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type,
- (LPBYTE)&value, &count);
- MYASSERT((res != ERROR_SUCCESS) || (type == REG_DWORD));
- MYASSERT((res != ERROR_SUCCESS) || (count == sizeof(UInt32)));
- return res;
-}
-
-LONG CKey::QueryValue(LPCTSTR name, bool &value) throw()
-{
- UInt32 uintValue = BoolToUINT32(value);
- LONG res = QueryValue(name, uintValue);
- value = UINT32ToBool(uintValue);
- return res;
-}
-
-LONG CKey::GetValue_IfOk(LPCTSTR name, UInt32 &value) throw()
-{
- UInt32 newVal;
- LONG res = QueryValue(name, newVal);
- if (res == ERROR_SUCCESS)
- value = newVal;
- return res;
-}
-
-LONG CKey::GetValue_IfOk(LPCTSTR name, bool &value) throw()
-{
- bool newVal;
- LONG res = QueryValue(name, newVal);
- if (res == ERROR_SUCCESS)
- value = newVal;
- return res;
-}
-
-LONG CKey::QueryValue(LPCTSTR name, LPTSTR value, UInt32 &count) throw()
-{
- DWORD type = 0;
- LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, (LPBYTE)value, (DWORD *)&count);
- MYASSERT((res != ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
- return res;
-}
-
-LONG CKey::QueryValue(LPCTSTR name, CSysString &value)
-{
- value.Empty();
- DWORD type = 0;
- UInt32 curSize = 0;
- LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, NULL, (DWORD *)&curSize);
- if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
- return res;
- UInt32 curSize2 = curSize;
- res = QueryValue(name, value.GetBuf(curSize), curSize2);
- if (curSize > curSize2)
- curSize = curSize2;
- value.ReleaseBuf_CalcLen(curSize / sizeof(TCHAR));
- return res;
-}
-
-
-#ifndef _UNICODE
-
-LONG CKey::QueryValue(LPCWSTR name, LPWSTR value, UInt32 &count)
-{
- DWORD type = 0;
- LONG res = RegQueryValueExW(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count);
- MYASSERT((res != ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
- return res;
-}
-
-LONG CKey::QueryValue(LPCWSTR name, UString &value)
-{
- value.Empty();
- DWORD type = 0;
- UInt32 curSize = 0;
-
- LONG res;
-
- if (g_IsNT)
- {
- res = RegQueryValueExW(_object, name, NULL, &type, NULL, (DWORD *)&curSize);
- if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
- return res;
- UInt32 curSize2 = curSize;
- res = QueryValue(name, value.GetBuf(curSize), curSize2);
- if (curSize > curSize2)
- curSize = curSize2;
- value.ReleaseBuf_CalcLen(curSize / sizeof(wchar_t));
- }
- else
- {
- AString vTemp;
- res = QueryValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name), vTemp);
- value = GetUnicodeString(vTemp);
- }
-
- return res;
-}
-
-#endif
-
-
-LONG CKey::QueryValue(LPCTSTR name, void *value, UInt32 &count) throw()
-{
- DWORD type = 0;
- LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, (LPBYTE)value, (DWORD *)&count);
- MYASSERT((res != ERROR_SUCCESS) || (type == REG_BINARY));
- return res;
-}
-
-
-LONG CKey::QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize)
-{
- DWORD type = 0;
- dataSize = 0;
- LONG res = RegQueryValueEx(_object, (LPTSTR)name, NULL, &type, NULL, (DWORD *)&dataSize);
- if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
- return res;
- value.Alloc(dataSize);
- return QueryValue(name, (BYTE *)value, dataSize);
-}
-
-LONG CKey::EnumKeys(CSysStringVector &keyNames)
-{
- keyNames.Clear();
- CSysString keyName;
- for (DWORD index = 0; ; index++)
- {
- const unsigned kBufSize = MAX_PATH + 1; // 256 in ATL
- FILETIME lastWriteTime;
- UInt32 nameSize = kBufSize;
- LONG result = ::RegEnumKeyEx(_object, index, keyName.GetBuf(kBufSize),
- (DWORD *)&nameSize, NULL, NULL, NULL, &lastWriteTime);
- keyName.ReleaseBuf_CalcLen(kBufSize);
- if (result == ERROR_NO_MORE_ITEMS)
- break;
- if (result != ERROR_SUCCESS)
- return result;
- keyNames.Add(keyName);
- }
- return ERROR_SUCCESS;
-}
-
-LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings)
-{
- size_t numChars = 0;
-
- unsigned i;
-
- for (i = 0; i < strings.Size(); i++)
- numChars += strings[i].Len() + 1;
-
- CObjArray<wchar_t> buffer(numChars);
- size_t pos = 0;
-
- for (i = 0; i < strings.Size(); i++)
- {
- const UString &s = strings[i];
- size_t size = s.Len() + 1;
- wmemcpy(buffer + pos, s, size);
- pos += size;
- }
- return SetValue(valueName, buffer, (UInt32)numChars * sizeof(wchar_t));
-}
-
-LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings)
-{
- strings.Clear();
- CByteBuffer buffer;
- UInt32 dataSize = 0;
- LONG res = QueryValue(valueName, buffer, dataSize);
- if (res != ERROR_SUCCESS)
- return res;
- if (dataSize > buffer.Size())
- return E_FAIL;
- if (dataSize % sizeof(wchar_t) != 0)
- return E_FAIL;
-
- const wchar_t *data = (const wchar_t *)(const Byte *)buffer;
- size_t numChars = dataSize / sizeof(wchar_t);
- size_t prev = 0;
- UString s;
-
- for (size_t i = 0; i < numChars; i++)
- {
- if (data[i] == 0)
- {
- s = data + prev;
- strings.Add(s);
- prev = i + 1;
- }
- }
-
- return res;
-}
-
-}}
+// Windows/Registry.cpp
+
+#include "StdAfx.h"
+
+#include <wchar.h>
+// #include <stdio.h>
+
+#ifndef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+#include "Registry.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+namespace NRegistry {
+
+#define MYASSERT(expr) // _ASSERTE(expr)
+#define MY_ASSUME(expr)
+
+/*
+static void Error()
+{
+ #ifdef _CONSOLE
+ printf("\nregistry error\n");
+ #else
+ MessageBoxW(0, L"registry error", L"", 0);
+ // exit(1);
+ #endif
+}
+
+#define MY_ASSUME(expr) { if (!(expr)) Error(); }
+*/
+
+LONG CKey::Create(HKEY parentKey, LPCTSTR keyName,
+ LPTSTR keyClass, DWORD options, REGSAM accessMask,
+ LPSECURITY_ATTRIBUTES securityAttributes, LPDWORD disposition) throw()
+{
+ MY_ASSUME(parentKey != NULL);
+ DWORD dispositionReal;
+ HKEY key = NULL;
+ LONG res = RegCreateKeyEx(parentKey, keyName, 0, keyClass,
+ options, accessMask, securityAttributes, &key, &dispositionReal);
+ if (disposition != NULL)
+ *disposition = dispositionReal;
+ if (res == ERROR_SUCCESS)
+ {
+ res = Close();
+ _object = key;
+ }
+ return res;
+}
+
+LONG CKey::Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask) throw()
+{
+ MY_ASSUME(parentKey != NULL);
+ HKEY key = NULL;
+ LONG res = RegOpenKeyEx(parentKey, keyName, 0, accessMask, &key);
+ if (res == ERROR_SUCCESS)
+ {
+ res = Close();
+ MYASSERT(res == ERROR_SUCCESS);
+ _object = key;
+ }
+ return res;
+}
+
+LONG CKey::Close() throw()
+{
+ LONG res = ERROR_SUCCESS;
+ if (_object != NULL)
+ {
+ res = RegCloseKey(_object);
+ _object = NULL;
+ }
+ return res;
+}
+
+// win95, win98: deletes sunkey and all its subkeys
+// winNT to be deleted must not have subkeys
+LONG CKey::DeleteSubKey(LPCTSTR subKeyName) throw()
+{
+ MY_ASSUME(_object != NULL);
+ return RegDeleteKey(_object, subKeyName);
+}
+
+LONG CKey::RecurseDeleteKey(LPCTSTR subKeyName) throw()
+{
+ CKey key;
+ LONG res = key.Open(_object, subKeyName, KEY_READ | KEY_WRITE);
+ if (res != ERROR_SUCCESS)
+ return res;
+ FILETIME fileTime;
+ const UInt32 kBufSize = MAX_PATH + 1; // 256 in ATL
+ DWORD size = kBufSize;
+ TCHAR buffer[kBufSize];
+ while (RegEnumKeyEx(key._object, 0, buffer, &size, NULL, NULL, NULL, &fileTime) == ERROR_SUCCESS)
+ {
+ res = key.RecurseDeleteKey(buffer);
+ if (res != ERROR_SUCCESS)
+ return res;
+ size = kBufSize;
+ }
+ key.Close();
+ return DeleteSubKey(subKeyName);
+}
+
+
+/////////////////////////
+// Value Functions
+
+static inline UInt32 BoolToUINT32(bool value) { return (value ? 1: 0); }
+static inline bool UINT32ToBool(UInt32 value) { return (value != 0); }
+
+
+LONG CKey::DeleteValue(LPCTSTR name) throw()
+{
+ MY_ASSUME(_object != NULL);
+ return ::RegDeleteValue(_object, name);
+}
+
+#ifndef _UNICODE
+LONG CKey::DeleteValue(LPCWSTR name)
+{
+ MY_ASSUME(_object != NULL);
+ if (g_IsNT)
+ return ::RegDeleteValueW(_object, name);
+ return DeleteValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name));
+}
+#endif
+
+LONG CKey::SetValue(LPCTSTR name, UInt32 value) throw()
+{
+ MY_ASSUME(_object != NULL);
+ return RegSetValueEx(_object, name, 0, REG_DWORD,
+ (const BYTE *)&value, sizeof(UInt32));
+}
+
+LONG CKey::SetValue(LPCTSTR name, bool value) throw()
+{
+ return SetValue(name, BoolToUINT32(value));
+}
+
+LONG CKey::SetValue(LPCTSTR name, LPCTSTR value) throw()
+{
+ MYASSERT(value != NULL);
+ MY_ASSUME(_object != NULL);
+ return RegSetValueEx(_object, name, 0, REG_SZ,
+ (const BYTE *)value, ((DWORD)lstrlen(value) + 1) * sizeof(TCHAR));
+}
+
+/*
+LONG CKey::SetValue(LPCTSTR name, const CSysString &value)
+{
+ MYASSERT(value != NULL);
+ MY_ASSUME(_object != NULL);
+ return RegSetValueEx(_object, name, NULL, REG_SZ,
+ (const BYTE *)(const TCHAR *)value, (value.Len() + 1) * sizeof(TCHAR));
+}
+*/
+
+#ifndef _UNICODE
+
+LONG CKey::SetValue(LPCWSTR name, LPCWSTR value)
+{
+ MYASSERT(value != NULL);
+ MY_ASSUME(_object != NULL);
+ if (g_IsNT)
+ return RegSetValueExW(_object, name, 0, REG_SZ,
+ (const BYTE * )value, (DWORD)((wcslen(value) + 1) * sizeof(wchar_t)));
+ return SetValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name),
+ value == 0 ? 0 : (LPCSTR)GetSystemString(value));
+}
+
+#endif
+
+
+LONG CKey::SetValue(LPCTSTR name, const void *value, UInt32 size) throw()
+{
+ MYASSERT(value != NULL);
+ MY_ASSUME(_object != NULL);
+ return RegSetValueEx(_object, name, 0, REG_BINARY,
+ (const BYTE *)value, size);
+}
+
+LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value)
+{
+ MYASSERT(value != NULL);
+ CKey key;
+ LONG res = key.Create(parentKey, keyName);
+ if (res == ERROR_SUCCESS)
+ res = key.SetValue(valueName, value);
+ return res;
+}
+
+LONG CKey::SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw()
+{
+ MYASSERT(value != NULL);
+ CKey key;
+ LONG res = key.Create(_object, keyName);
+ if (res == ERROR_SUCCESS)
+ res = key.SetValue(valueName, value);
+ return res;
+}
+
+LONG CKey::QueryValue(LPCTSTR name, UInt32 &value) throw()
+{
+ DWORD type = 0;
+ DWORD count = sizeof(DWORD);
+ LONG res = RegQueryValueEx(_object, name, NULL, &type,
+ (LPBYTE)&value, &count);
+ MYASSERT((res != ERROR_SUCCESS) || (type == REG_DWORD));
+ MYASSERT((res != ERROR_SUCCESS) || (count == sizeof(UInt32)));
+ return res;
+}
+
+LONG CKey::QueryValue(LPCTSTR name, bool &value) throw()
+{
+ UInt32 uintValue = BoolToUINT32(value);
+ LONG res = QueryValue(name, uintValue);
+ value = UINT32ToBool(uintValue);
+ return res;
+}
+
+LONG CKey::GetValue_IfOk(LPCTSTR name, UInt32 &value) throw()
+{
+ UInt32 newVal;
+ LONG res = QueryValue(name, newVal);
+ if (res == ERROR_SUCCESS)
+ value = newVal;
+ return res;
+}
+
+LONG CKey::GetValue_IfOk(LPCTSTR name, bool &value) throw()
+{
+ bool newVal = false;
+ LONG res = QueryValue(name, newVal);
+ if (res == ERROR_SUCCESS)
+ value = newVal;
+ return res;
+}
+
+LONG CKey::QueryValue(LPCTSTR name, LPTSTR value, UInt32 &count) throw()
+{
+ DWORD type = 0;
+ LONG res = RegQueryValueEx(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count);
+ MYASSERT((res != ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
+ return res;
+}
+
+LONG CKey::QueryValue(LPCTSTR name, CSysString &value)
+{
+ value.Empty();
+ DWORD type = 0;
+ UInt32 curSize = 0;
+ LONG res = RegQueryValueEx(_object, name, NULL, &type, NULL, (DWORD *)&curSize);
+ if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
+ return res;
+ UInt32 curSize2 = curSize;
+ res = QueryValue(name, value.GetBuf(curSize), curSize2);
+ if (curSize > curSize2)
+ curSize = curSize2;
+ value.ReleaseBuf_CalcLen(curSize / sizeof(TCHAR));
+ return res;
+}
+
+
+#ifndef _UNICODE
+
+LONG CKey::QueryValue(LPCWSTR name, LPWSTR value, UInt32 &count)
+{
+ DWORD type = 0;
+ LONG res = RegQueryValueExW(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count);
+ MYASSERT((res != ERROR_SUCCESS) || (type == REG_SZ) || (type == REG_MULTI_SZ) || (type == REG_EXPAND_SZ));
+ return res;
+}
+
+LONG CKey::QueryValue(LPCWSTR name, UString &value)
+{
+ value.Empty();
+ DWORD type = 0;
+ UInt32 curSize = 0;
+
+ LONG res;
+
+ if (g_IsNT)
+ {
+ res = RegQueryValueExW(_object, name, NULL, &type, NULL, (DWORD *)&curSize);
+ if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
+ return res;
+ UInt32 curSize2 = curSize;
+ res = QueryValue(name, value.GetBuf(curSize), curSize2);
+ if (curSize > curSize2)
+ curSize = curSize2;
+ value.ReleaseBuf_CalcLen(curSize / sizeof(wchar_t));
+ }
+ else
+ {
+ AString vTemp;
+ res = QueryValue(name == 0 ? 0 : (LPCSTR)GetSystemString(name), vTemp);
+ value = GetUnicodeString(vTemp);
+ }
+
+ return res;
+}
+
+#endif
+
+
+LONG CKey::QueryValue(LPCTSTR name, void *value, UInt32 &count) throw()
+{
+ DWORD type = 0;
+ LONG res = RegQueryValueEx(_object, name, NULL, &type, (LPBYTE)value, (DWORD *)&count);
+ MYASSERT((res != ERROR_SUCCESS) || (type == REG_BINARY));
+ return res;
+}
+
+
+LONG CKey::QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize)
+{
+ DWORD type = 0;
+ dataSize = 0;
+ LONG res = RegQueryValueEx(_object, name, NULL, &type, NULL, (DWORD *)&dataSize);
+ if (res != ERROR_SUCCESS && res != ERROR_MORE_DATA)
+ return res;
+ value.Alloc(dataSize);
+ return QueryValue(name, (BYTE *)value, dataSize);
+}
+
+LONG CKey::EnumKeys(CSysStringVector &keyNames)
+{
+ keyNames.Clear();
+ CSysString keyName;
+ for (DWORD index = 0; ; index++)
+ {
+ const unsigned kBufSize = MAX_PATH + 1; // 256 in ATL
+ FILETIME lastWriteTime;
+ UInt32 nameSize = kBufSize;
+ LONG result = ::RegEnumKeyEx(_object, index, keyName.GetBuf(kBufSize),
+ (DWORD *)&nameSize, NULL, NULL, NULL, &lastWriteTime);
+ keyName.ReleaseBuf_CalcLen(kBufSize);
+ if (result == ERROR_NO_MORE_ITEMS)
+ break;
+ if (result != ERROR_SUCCESS)
+ return result;
+ keyNames.Add(keyName);
+ }
+ return ERROR_SUCCESS;
+}
+
+LONG CKey::SetValue_Strings(LPCTSTR valueName, const UStringVector &strings)
+{
+ size_t numChars = 0;
+
+ unsigned i;
+
+ for (i = 0; i < strings.Size(); i++)
+ numChars += strings[i].Len() + 1;
+
+ CObjArray<wchar_t> buffer(numChars);
+ size_t pos = 0;
+
+ for (i = 0; i < strings.Size(); i++)
+ {
+ const UString &s = strings[i];
+ size_t size = s.Len() + 1;
+ wmemcpy(buffer + pos, s, size);
+ pos += size;
+ }
+ return SetValue(valueName, buffer, (UInt32)numChars * sizeof(wchar_t));
+}
+
+LONG CKey::GetValue_Strings(LPCTSTR valueName, UStringVector &strings)
+{
+ strings.Clear();
+ CByteBuffer buffer;
+ UInt32 dataSize = 0;
+ LONG res = QueryValue(valueName, buffer, dataSize);
+ if (res != ERROR_SUCCESS)
+ return res;
+ if (dataSize > buffer.Size())
+ return E_FAIL;
+ if (dataSize % sizeof(wchar_t) != 0)
+ return E_FAIL;
+
+ const wchar_t *data = (const wchar_t *)(const void *)(const Byte *)buffer;
+ size_t numChars = dataSize / sizeof(wchar_t);
+ size_t prev = 0;
+ UString s;
+
+ for (size_t i = 0; i < numChars; i++)
+ {
+ if (data[i] == 0)
+ {
+ s = data + prev;
+ strings.Add(s);
+ prev = i + 1;
+ }
+ }
+
+ return res;
+}
+
+}}
diff --git a/CPP/Windows/Registry.h b/CPP/Windows/Registry.h
index 0a31230..0d3b4fc 100644
--- a/CPP/Windows/Registry.h
+++ b/CPP/Windows/Registry.h
@@ -1,84 +1,84 @@
-// Windows/Registry.h
-
-#ifndef __WINDOWS_REGISTRY_H
-#define __WINDOWS_REGISTRY_H
-
-#include "../Common/MyBuffer.h"
-#include "../Common/MyString.h"
-
-namespace NWindows {
-namespace NRegistry {
-
-LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value);
-
-class CKey
-{
- HKEY _object;
-public:
- CKey(): _object(NULL) {}
- ~CKey() { Close(); }
-
- operator HKEY() const { return _object; }
- void Attach(HKEY key) { _object = key; }
- HKEY Detach()
- {
- HKEY key = _object;
- _object = NULL;
- return key;
- }
-
- LONG Create(HKEY parentKey, LPCTSTR keyName,
- LPTSTR keyClass = REG_NONE, DWORD options = REG_OPTION_NON_VOLATILE,
- REGSAM accessMask = KEY_ALL_ACCESS,
- LPSECURITY_ATTRIBUTES securityAttributes = NULL,
- LPDWORD disposition = NULL) throw();
- LONG Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask = KEY_ALL_ACCESS) throw();
-
- LONG Close() throw();
-
- LONG DeleteSubKey(LPCTSTR subKeyName) throw();
- LONG RecurseDeleteKey(LPCTSTR subKeyName) throw();
-
- LONG DeleteValue(LPCTSTR name) throw();
- #ifndef _UNICODE
- LONG DeleteValue(LPCWSTR name);
- #endif
-
- LONG SetValue(LPCTSTR valueName, UInt32 value) throw();
- LONG SetValue(LPCTSTR valueName, bool value) throw();
- LONG SetValue(LPCTSTR valueName, LPCTSTR value) throw();
- // LONG SetValue(LPCTSTR valueName, const CSysString &value);
- #ifndef _UNICODE
- LONG SetValue(LPCWSTR name, LPCWSTR value);
- // LONG SetValue(LPCWSTR name, const UString &value);
- #endif
-
- LONG SetValue(LPCTSTR name, const void *value, UInt32 size) throw();
-
- LONG SetValue_Strings(LPCTSTR valueName, const UStringVector &strings);
- LONG GetValue_Strings(LPCTSTR valueName, UStringVector &strings);
-
- LONG SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw();
-
- LONG QueryValue(LPCTSTR name, UInt32 &value) throw();
- LONG QueryValue(LPCTSTR name, bool &value) throw();
- LONG QueryValue(LPCTSTR name, LPTSTR value, UInt32 &dataSize) throw();
- LONG QueryValue(LPCTSTR name, CSysString &value);
-
- LONG GetValue_IfOk(LPCTSTR name, UInt32 &value) throw();
- LONG GetValue_IfOk(LPCTSTR name, bool &value) throw();
-
- #ifndef _UNICODE
- LONG QueryValue(LPCWSTR name, LPWSTR value, UInt32 &dataSize);
- LONG QueryValue(LPCWSTR name, UString &value);
- #endif
-
- LONG QueryValue(LPCTSTR name, void *value, UInt32 &dataSize) throw();
- LONG QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize);
-
- LONG EnumKeys(CSysStringVector &keyNames);
-};
-
-}}
-
-#endif
+// Windows/Registry.h
+
+#ifndef ZIP7_INC_WINDOWS_REGISTRY_H
+#define ZIP7_INC_WINDOWS_REGISTRY_H
+
+#include "../Common/MyBuffer.h"
+#include "../Common/MyString.h"
+
+namespace NWindows {
+namespace NRegistry {
+
+LONG SetValue(HKEY parentKey, LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value);
+
+class CKey
+{
+ HKEY _object;
+public:
+ CKey(): _object(NULL) {}
+ ~CKey() { Close(); }
+
+ operator HKEY() const { return _object; }
+ void Attach(HKEY key) { _object = key; }
+ HKEY Detach()
+ {
+ HKEY key = _object;
+ _object = NULL;
+ return key;
+ }
+
+ LONG Create(HKEY parentKey, LPCTSTR keyName,
+ LPTSTR keyClass = REG_NONE, DWORD options = REG_OPTION_NON_VOLATILE,
+ REGSAM accessMask = KEY_ALL_ACCESS,
+ LPSECURITY_ATTRIBUTES securityAttributes = NULL,
+ LPDWORD disposition = NULL) throw();
+ LONG Open(HKEY parentKey, LPCTSTR keyName, REGSAM accessMask = KEY_ALL_ACCESS) throw();
+
+ LONG Close() throw();
+
+ LONG DeleteSubKey(LPCTSTR subKeyName) throw();
+ LONG RecurseDeleteKey(LPCTSTR subKeyName) throw();
+
+ LONG DeleteValue(LPCTSTR name) throw();
+ #ifndef _UNICODE
+ LONG DeleteValue(LPCWSTR name);
+ #endif
+
+ LONG SetValue(LPCTSTR valueName, UInt32 value) throw();
+ LONG SetValue(LPCTSTR valueName, bool value) throw();
+ LONG SetValue(LPCTSTR valueName, LPCTSTR value) throw();
+ // LONG SetValue(LPCTSTR valueName, const CSysString &value);
+ #ifndef _UNICODE
+ LONG SetValue(LPCWSTR name, LPCWSTR value);
+ // LONG SetValue(LPCWSTR name, const UString &value);
+ #endif
+
+ LONG SetValue(LPCTSTR name, const void *value, UInt32 size) throw();
+
+ LONG SetValue_Strings(LPCTSTR valueName, const UStringVector &strings);
+ LONG GetValue_Strings(LPCTSTR valueName, UStringVector &strings);
+
+ LONG SetKeyValue(LPCTSTR keyName, LPCTSTR valueName, LPCTSTR value) throw();
+
+ LONG QueryValue(LPCTSTR name, UInt32 &value) throw();
+ LONG QueryValue(LPCTSTR name, bool &value) throw();
+ LONG QueryValue(LPCTSTR name, LPTSTR value, UInt32 &dataSize) throw();
+ LONG QueryValue(LPCTSTR name, CSysString &value);
+
+ LONG GetValue_IfOk(LPCTSTR name, UInt32 &value) throw();
+ LONG GetValue_IfOk(LPCTSTR name, bool &value) throw();
+
+ #ifndef _UNICODE
+ LONG QueryValue(LPCWSTR name, LPWSTR value, UInt32 &dataSize);
+ LONG QueryValue(LPCWSTR name, UString &value);
+ #endif
+
+ LONG QueryValue(LPCTSTR name, void *value, UInt32 &dataSize) throw();
+ LONG QueryValue(LPCTSTR name, CByteBuffer &value, UInt32 &dataSize);
+
+ LONG EnumKeys(CSysStringVector &keyNames);
+};
+
+}}
+
+#endif
diff --git a/CPP/Windows/ResourceString.cpp b/CPP/Windows/ResourceString.cpp
index c28e60e..ae8182e 100644
--- a/CPP/Windows/ResourceString.cpp
+++ b/CPP/Windows/ResourceString.cpp
@@ -1,103 +1,103 @@
-// Windows/ResourceString.cpp
-
-#include "StdAfx.h"
-
-#ifndef _UNICODE
-#include "../Common/StringConvert.h"
-#endif
-
-#include "ResourceString.h"
-
-extern HINSTANCE g_hInstance;
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-namespace NWindows {
-
-#ifndef _UNICODE
-
-static CSysString MyLoadStringA(HINSTANCE hInstance, UINT resourceID)
-{
- CSysString s;
- int size = 128;
- int len;
- do
- {
- size <<= 1;
- len = ::LoadString(hInstance, resourceID, s.GetBuf(size - 1), size);
- }
- while (size - len <= 1);
- s.ReleaseBuf_CalcLen(len);
- return s;
-}
-
-#endif
-
-static const int kStartSize = 256;
-
-static void MyLoadString2(HINSTANCE hInstance, UINT resourceID, UString &s)
-{
- int size = kStartSize;
- int len;
- do
- {
- size <<= 1;
- len = ::LoadStringW(hInstance, resourceID, s.GetBuf(size - 1), size);
- }
- while (size - len <= 1);
- s.ReleaseBuf_CalcLen(len);
-}
-
-// NT4 doesn't support LoadStringW(,,, 0) to get pointer to resource string. So we don't use it.
-
-UString MyLoadString(UINT resourceID)
-{
- #ifndef _UNICODE
- if (!g_IsNT)
- return GetUnicodeString(MyLoadStringA(g_hInstance, resourceID));
- else
- #endif
- {
- {
- wchar_t s[kStartSize];
- s[0] = 0;
- int len = ::LoadStringW(g_hInstance, resourceID, s, kStartSize);
- if (kStartSize - len > 1)
- return s;
- }
- UString dest;
- MyLoadString2(g_hInstance, resourceID, dest);
- return dest;
- }
-}
-
-void MyLoadString(HINSTANCE hInstance, UINT resourceID, UString &dest)
-{
- dest.Empty();
- #ifndef _UNICODE
- if (!g_IsNT)
- MultiByteToUnicodeString2(dest, MyLoadStringA(hInstance, resourceID));
- else
- #endif
- {
- {
- wchar_t s[kStartSize];
- s[0] = 0;
- int len = ::LoadStringW(hInstance, resourceID, s, kStartSize);
- if (kStartSize - len > 1)
- {
- dest = s;
- return;
- }
- }
- MyLoadString2(hInstance, resourceID, dest);
- }
-}
-
-void MyLoadString(UINT resourceID, UString &dest)
-{
- MyLoadString(g_hInstance, resourceID, dest);
-}
-
-}
+// Windows/ResourceString.cpp
+
+#include "StdAfx.h"
+
+#ifndef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+
+#include "ResourceString.h"
+
+extern HINSTANCE g_hInstance;
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+
+#ifndef _UNICODE
+
+static CSysString MyLoadStringA(HINSTANCE hInstance, UINT resourceID)
+{
+ CSysString s;
+ int size = 128;
+ int len;
+ do
+ {
+ size <<= 1;
+ len = ::LoadString(hInstance, resourceID, s.GetBuf((unsigned)size - 1), size);
+ }
+ while (size - len <= 1);
+ s.ReleaseBuf_CalcLen((unsigned)len);
+ return s;
+}
+
+#endif
+
+static const int kStartSize = 256;
+
+static void MyLoadString2(HINSTANCE hInstance, UINT resourceID, UString &s)
+{
+ int size = kStartSize;
+ int len;
+ do
+ {
+ size <<= 1;
+ len = ::LoadStringW(hInstance, resourceID, s.GetBuf((unsigned)size - 1), size);
+ }
+ while (size - len <= 1);
+ s.ReleaseBuf_CalcLen((unsigned)len);
+}
+
+// NT4 doesn't support LoadStringW(,,, 0) to get pointer to resource string. So we don't use it.
+
+UString MyLoadString(UINT resourceID)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ return GetUnicodeString(MyLoadStringA(g_hInstance, resourceID));
+ else
+ #endif
+ {
+ {
+ wchar_t s[kStartSize];
+ s[0] = 0;
+ int len = ::LoadStringW(g_hInstance, resourceID, s, kStartSize);
+ if (kStartSize - len > 1)
+ return s;
+ }
+ UString dest;
+ MyLoadString2(g_hInstance, resourceID, dest);
+ return dest;
+ }
+}
+
+void MyLoadString(HINSTANCE hInstance, UINT resourceID, UString &dest)
+{
+ dest.Empty();
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ MultiByteToUnicodeString2(dest, MyLoadStringA(hInstance, resourceID));
+ else
+ #endif
+ {
+ {
+ wchar_t s[kStartSize];
+ s[0] = 0;
+ int len = ::LoadStringW(hInstance, resourceID, s, kStartSize);
+ if (kStartSize - len > 1)
+ {
+ dest = s;
+ return;
+ }
+ }
+ MyLoadString2(hInstance, resourceID, dest);
+ }
+}
+
+void MyLoadString(UINT resourceID, UString &dest)
+{
+ MyLoadString(g_hInstance, resourceID, dest);
+}
+
+}
diff --git a/CPP/Windows/ResourceString.h b/CPP/Windows/ResourceString.h
index cbaef4b..773307b 100644
--- a/CPP/Windows/ResourceString.h
+++ b/CPP/Windows/ResourceString.h
@@ -1,16 +1,17 @@
-// Windows/ResourceString.h
-
-#ifndef __WINDOWS_RESOURCE_STRING_H
-#define __WINDOWS_RESOURCE_STRING_H
-
-#include "../Common/MyString.h"
-
-namespace NWindows {
-
-UString MyLoadString(UINT resourceID);
-void MyLoadString(HINSTANCE hInstance, UINT resourceID, UString &dest);
-void MyLoadString(UINT resourceID, UString &dest);
-
-}
-
-#endif
+// Windows/ResourceString.h
+
+#ifndef ZIP7_INC_WINDOWS_RESOURCE_STRING_H
+#define ZIP7_INC_WINDOWS_RESOURCE_STRING_H
+
+#include "../Common/MyString.h"
+#include "../Common/MyWindows.h"
+
+namespace NWindows {
+
+UString MyLoadString(UINT resourceID);
+void MyLoadString(HINSTANCE hInstance, UINT resourceID, UString &dest);
+void MyLoadString(UINT resourceID, UString &dest);
+
+}
+
+#endif
diff --git a/CPP/Windows/SecurityUtils.cpp b/CPP/Windows/SecurityUtils.cpp
index 8646cc9..d4282d0 100644
--- a/CPP/Windows/SecurityUtils.cpp
+++ b/CPP/Windows/SecurityUtils.cpp
@@ -1,181 +1,186 @@
-// Windows/SecurityUtils.cpp
-
-#include "StdAfx.h"
-
-#include "../Common/MyString.h"
-
-#include "SecurityUtils.h"
-
-namespace NWindows {
-namespace NSecurity {
-
-/*
-bool MyLookupAccountSid(LPCTSTR systemName, PSID sid,
- CSysString &accountName, CSysString &domainName, PSID_NAME_USE sidNameUse)
-{
- DWORD accountNameSize = 0, domainNameSize = 0;
-
- if (!::LookupAccountSid(systemName, sid,
- accountName.GetBuf(0), &accountNameSize,
- domainName.GetBuf(0), &domainNameSize, sidNameUse))
- {
- if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
- return false;
- }
- DWORD accountNameSize2 = accountNameSize, domainNameSize2 = domainNameSize;
- bool result = BOOLToBool(::LookupAccountSid(systemName, sid,
- accountName.GetBuf(accountNameSize), &accountNameSize2,
- domainName.GetBuf(domainNameSize), &domainNameSize2, sidNameUse));
- accountName.ReleaseBuf_CalcLen(accountNameSize);
- domainName.ReleaseBuf_CalcLen(domainNameSize);
- return result;
-}
-*/
-
-static void SetLsaString(LPWSTR src, PLSA_UNICODE_STRING dest)
-{
- int len = (int)wcslen(src);
- dest->Length = (USHORT)(len * sizeof(WCHAR));
- dest->MaximumLength = (USHORT)((len + 1) * sizeof(WCHAR));
- dest->Buffer = src;
-}
-
-/*
-static void MyLookupSids(CPolicy &policy, PSID ps)
-{
- LSA_REFERENCED_DOMAIN_LIST *referencedDomains = NULL;
- LSA_TRANSLATED_NAME *names = NULL;
- NTSTATUS nts = policy.LookupSids(1, &ps, &referencedDomains, &names);
- int res = LsaNtStatusToWinError(nts);
- LsaFreeMemory(referencedDomains);
- LsaFreeMemory(names);
-}
-*/
-
-#ifndef _UNICODE
-typedef BOOL (WINAPI * LookupAccountNameWP)(
- LPCWSTR lpSystemName,
- LPCWSTR lpAccountName,
- PSID Sid,
- LPDWORD cbSid,
- LPWSTR ReferencedDomainName,
- LPDWORD cchReferencedDomainName,
- PSID_NAME_USE peUse
- );
-#endif
-
-static PSID GetSid(LPWSTR accountName)
-{
- #ifndef _UNICODE
- HMODULE hModule = GetModuleHandle(TEXT("Advapi32.dll"));
- if (hModule == NULL)
- return NULL;
- LookupAccountNameWP lookupAccountNameW = (LookupAccountNameWP)GetProcAddress(hModule, "LookupAccountNameW");
- if (lookupAccountNameW == NULL)
- return NULL;
- #endif
-
- DWORD sidLen = 0, domainLen = 0;
- SID_NAME_USE sidNameUse;
- if (!
- #ifdef _UNICODE
- ::LookupAccountNameW
- #else
- lookupAccountNameW
- #endif
- (NULL, accountName, NULL, &sidLen, NULL, &domainLen, &sidNameUse))
- {
- if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
- {
- PSID pSid = ::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sidLen);
- LPWSTR domainName = (LPWSTR)::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (domainLen + 1) * sizeof(WCHAR));
- BOOL res =
- #ifdef _UNICODE
- ::LookupAccountNameW
- #else
- lookupAccountNameW
- #endif
- (NULL, accountName, pSid, &sidLen, domainName, &domainLen, &sidNameUse);
- ::HeapFree(GetProcessHeap(), 0, domainName);
- if (res)
- return pSid;
- }
- }
- return NULL;
-}
-
-#define MY__SE_LOCK_MEMORY_NAME L"SeLockMemoryPrivilege"
-
-bool AddLockMemoryPrivilege()
-{
- CPolicy policy;
- LSA_OBJECT_ATTRIBUTES attr;
- attr.Length = sizeof(attr);
- attr.RootDirectory = NULL;
- attr.ObjectName = NULL;
- attr.Attributes = 0;
- attr.SecurityDescriptor = NULL;
- attr.SecurityQualityOfService = NULL;
- if (policy.Open(NULL, &attr,
- // GENERIC_WRITE)
- POLICY_ALL_ACCESS)
- // STANDARD_RIGHTS_REQUIRED,
- // GENERIC_READ | GENERIC_EXECUTE | POLICY_VIEW_LOCAL_INFORMATION | POLICY_LOOKUP_NAMES)
- != 0)
- return false;
- LSA_UNICODE_STRING userRights;
- wchar_t s[128] = MY__SE_LOCK_MEMORY_NAME;
- SetLsaString(s, &userRights);
- WCHAR userName[256 + 2];
- DWORD size = 256;
- if (!GetUserNameW(userName, &size))
- return false;
- PSID psid = GetSid(userName);
- if (psid == NULL)
- return false;
- bool res = false;
-
- /*
- PLSA_UNICODE_STRING userRightsArray;
- ULONG countOfRights;
- NTSTATUS status = policy.EnumerateAccountRights(psid, &userRightsArray, &countOfRights);
- if (status != 0)
- return false;
- bool finded = false;
- for (ULONG i = 0; i < countOfRights; i++)
- {
- LSA_UNICODE_STRING &ur = userRightsArray[i];
- if (ur.Length != s.Length() * sizeof(WCHAR))
- continue;
- if (wcsncmp(ur.Buffer, s, s.Length()) != 0)
- continue;
- finded = true;
- res = true;
- break;
- }
- if (!finded)
- */
- {
- /*
- LSA_ENUMERATION_INFORMATION *enums;
- ULONG countReturned;
- NTSTATUS status = policy.EnumerateAccountsWithUserRight(&userRights, &enums, &countReturned);
- if (status == 0)
- {
- for (ULONG i = 0; i < countReturned; i++)
- MyLookupSids(policy, enums[i].Sid);
- if (enums)
- ::LsaFreeMemory(enums);
- res = true;
- }
- */
- NTSTATUS status = policy.AddAccountRights(psid, &userRights);
- if (status == 0)
- res = true;
- // ULONG res = LsaNtStatusToWinError(status);
- }
- HeapFree(GetProcessHeap(), 0, psid);
- return res;
-}
-
-}}
+// Windows/SecurityUtils.cpp
+
+#include "StdAfx.h"
+
+#include "SecurityUtils.h"
+
+namespace NWindows {
+namespace NSecurity {
+
+/*
+bool MyLookupAccountSid(LPCTSTR systemName, PSID sid,
+ CSysString &accountName, CSysString &domainName, PSID_NAME_USE sidNameUse)
+{
+ DWORD accountNameSize = 0, domainNameSize = 0;
+
+ if (!::LookupAccountSid(systemName, sid,
+ accountName.GetBuf(0), &accountNameSize,
+ domainName.GetBuf(0), &domainNameSize, sidNameUse))
+ {
+ if (::GetLastError() != ERROR_INSUFFICIENT_BUFFER)
+ return false;
+ }
+ DWORD accountNameSize2 = accountNameSize, domainNameSize2 = domainNameSize;
+ bool result = BOOLToBool(::LookupAccountSid(systemName, sid,
+ accountName.GetBuf(accountNameSize), &accountNameSize2,
+ domainName.GetBuf(domainNameSize), &domainNameSize2, sidNameUse));
+ accountName.ReleaseBuf_CalcLen(accountNameSize);
+ domainName.ReleaseBuf_CalcLen(domainNameSize);
+ return result;
+}
+*/
+
+static void SetLsaString(LPWSTR src, PLSA_UNICODE_STRING dest)
+{
+ const size_t len = (size_t)wcslen(src);
+ dest->Length = (USHORT)(len * sizeof(WCHAR));
+ dest->MaximumLength = (USHORT)((len + 1) * sizeof(WCHAR));
+ dest->Buffer = src;
+}
+
+/*
+static void MyLookupSids(CPolicy &policy, PSID ps)
+{
+ LSA_REFERENCED_DOMAIN_LIST *referencedDomains = NULL;
+ LSA_TRANSLATED_NAME *names = NULL;
+ NTSTATUS nts = policy.LookupSids(1, &ps, &referencedDomains, &names);
+ int res = LsaNtStatusToWinError(nts);
+ LsaFreeMemory(referencedDomains);
+ LsaFreeMemory(names);
+}
+*/
+
+extern "C" {
+
+#ifndef _UNICODE
+typedef BOOL (WINAPI * Func_LookupAccountNameW)(
+ LPCWSTR lpSystemName,
+ LPCWSTR lpAccountName,
+ PSID Sid,
+ LPDWORD cbSid,
+ LPWSTR ReferencedDomainName,
+ LPDWORD cchReferencedDomainName,
+ PSID_NAME_USE peUse
+ );
+#endif
+
+}
+
+static PSID GetSid(LPWSTR accountName)
+{
+ #ifndef _UNICODE
+ const HMODULE hModule = GetModuleHandle(TEXT("advapi32.dll"));
+ if (!hModule)
+ return NULL;
+ const
+ Func_LookupAccountNameW lookupAccountNameW = Z7_GET_PROC_ADDRESS(
+ Func_LookupAccountNameW, hModule,
+ "LookupAccountNameW");
+ if (!lookupAccountNameW)
+ return NULL;
+ #endif
+
+ DWORD sidLen = 0, domainLen = 0;
+ SID_NAME_USE sidNameUse;
+ if (!
+ #ifdef _UNICODE
+ ::LookupAccountNameW
+ #else
+ lookupAccountNameW
+ #endif
+ (NULL, accountName, NULL, &sidLen, NULL, &domainLen, &sidNameUse))
+ {
+ if (::GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+ {
+ const PSID pSid = ::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sidLen);
+ LPWSTR domainName = (LPWSTR)::HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (domainLen + 1) * sizeof(WCHAR));
+ const BOOL res =
+ #ifdef _UNICODE
+ ::LookupAccountNameW
+ #else
+ lookupAccountNameW
+ #endif
+ (NULL, accountName, pSid, &sidLen, domainName, &domainLen, &sidNameUse);
+ ::HeapFree(GetProcessHeap(), 0, domainName);
+ if (res)
+ return pSid;
+ }
+ }
+ return NULL;
+}
+
+#define Z7_WIN_SE_LOCK_MEMORY_NAME L"SeLockMemoryPrivilege"
+
+bool AddLockMemoryPrivilege()
+{
+ CPolicy policy;
+ LSA_OBJECT_ATTRIBUTES attr;
+ attr.Length = sizeof(attr);
+ attr.RootDirectory = NULL;
+ attr.ObjectName = NULL;
+ attr.Attributes = 0;
+ attr.SecurityDescriptor = NULL;
+ attr.SecurityQualityOfService = NULL;
+ if (policy.Open(NULL, &attr,
+ // GENERIC_WRITE)
+ POLICY_ALL_ACCESS)
+ // STANDARD_RIGHTS_REQUIRED,
+ // GENERIC_READ | GENERIC_EXECUTE | POLICY_VIEW_LOCAL_INFORMATION | POLICY_LOOKUP_NAMES)
+ != 0)
+ return false;
+ LSA_UNICODE_STRING userRights;
+ wchar_t s[128] = Z7_WIN_SE_LOCK_MEMORY_NAME;
+ SetLsaString(s, &userRights);
+ WCHAR userName[256 + 2];
+ DWORD size = 256;
+ if (!GetUserNameW(userName, &size))
+ return false;
+ const PSID psid = GetSid(userName);
+ if (psid == NULL)
+ return false;
+ bool res = false;
+
+ /*
+ PLSA_UNICODE_STRING userRightsArray;
+ ULONG countOfRights;
+ NTSTATUS status = policy.EnumerateAccountRights(psid, &userRightsArray, &countOfRights);
+ if (status != 0)
+ return false;
+ bool finded = false;
+ for (ULONG i = 0; i < countOfRights; i++)
+ {
+ LSA_UNICODE_STRING &ur = userRightsArray[i];
+ if (ur.Length != s.Length() * sizeof(WCHAR))
+ continue;
+ if (wcsncmp(ur.Buffer, s, s.Length()) != 0)
+ continue;
+ finded = true;
+ res = true;
+ break;
+ }
+ if (!finded)
+ */
+ {
+ /*
+ LSA_ENUMERATION_INFORMATION *enums;
+ ULONG countReturned;
+ NTSTATUS status = policy.EnumerateAccountsWithUserRight(&userRights, &enums, &countReturned);
+ if (status == 0)
+ {
+ for (ULONG i = 0; i < countReturned; i++)
+ MyLookupSids(policy, enums[i].Sid);
+ if (enums)
+ ::LsaFreeMemory(enums);
+ res = true;
+ }
+ */
+ const NTSTATUS status = policy.AddAccountRights(psid, &userRights);
+ if (status == 0)
+ res = true;
+ // ULONG res = LsaNtStatusToWinError(status);
+ }
+ HeapFree(GetProcessHeap(), 0, psid);
+ return res;
+}
+
+}}
diff --git a/CPP/Windows/SecurityUtils.h b/CPP/Windows/SecurityUtils.h
index 16b6606..4ef3939 100644
--- a/CPP/Windows/SecurityUtils.h
+++ b/CPP/Windows/SecurityUtils.h
@@ -1,167 +1,148 @@
-// Windows/SecurityUtils.h
-
-#ifndef __WINDOWS_SECURITY_UTILS_H
-#define __WINDOWS_SECURITY_UTILS_H
-
-#include <NTSecAPI.h>
-
-#include "Defs.h"
-
-namespace NWindows {
-namespace NSecurity {
-
-class CAccessToken
-{
- HANDLE _handle;
-public:
- CAccessToken(): _handle(NULL) {};
- ~CAccessToken() { Close(); }
- bool Close()
- {
- if (_handle == NULL)
- return true;
- bool res = BOOLToBool(::CloseHandle(_handle));
- if (res)
- _handle = NULL;
- return res;
- }
-
- bool OpenProcessToken(HANDLE processHandle, DWORD desiredAccess)
- {
- Close();
- return BOOLToBool(::OpenProcessToken(processHandle, desiredAccess, &_handle));
- }
-
- /*
- bool OpenThreadToken(HANDLE threadHandle, DWORD desiredAccess, bool openAsSelf)
- {
- Close();
- return BOOLToBool(::OpenTreadToken(threadHandle, desiredAccess, BoolToBOOL(anOpenAsSelf), &_handle));
- }
- */
-
- bool AdjustPrivileges(bool disableAllPrivileges, PTOKEN_PRIVILEGES newState,
- DWORD bufferLength, PTOKEN_PRIVILEGES previousState, PDWORD returnLength)
- { return BOOLToBool(::AdjustTokenPrivileges(_handle, BoolToBOOL(disableAllPrivileges),
- newState, bufferLength, previousState, returnLength)); }
-
- bool AdjustPrivileges(bool disableAllPrivileges, PTOKEN_PRIVILEGES newState)
- { return AdjustPrivileges(disableAllPrivileges, newState, 0, NULL, NULL); }
-
- bool AdjustPrivileges(PTOKEN_PRIVILEGES newState)
- { return AdjustPrivileges(false, newState); }
-
-};
-
-#ifndef _UNICODE
-typedef NTSTATUS (NTAPI *LsaOpenPolicyP)(PLSA_UNICODE_STRING SystemName,
- PLSA_OBJECT_ATTRIBUTES ObjectAttributes, ACCESS_MASK DesiredAccess, PLSA_HANDLE PolicyHandle);
-typedef NTSTATUS (NTAPI *LsaCloseP)(LSA_HANDLE ObjectHandle);
-typedef NTSTATUS (NTAPI *LsaAddAccountRightsP)(LSA_HANDLE PolicyHandle,
- PSID AccountSid, PLSA_UNICODE_STRING UserRights, ULONG CountOfRights );
-#define MY_STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L)
-#endif
-
-struct CPolicy
-{
-protected:
- LSA_HANDLE _handle;
- #ifndef _UNICODE
- HMODULE hModule;
- #endif
-public:
- operator LSA_HANDLE() const { return _handle; }
- CPolicy(): _handle(NULL)
- {
- #ifndef _UNICODE
- hModule = GetModuleHandle(TEXT("Advapi32.dll"));
- #endif
- };
- ~CPolicy() { Close(); }
-
- NTSTATUS Open(PLSA_UNICODE_STRING systemName, PLSA_OBJECT_ATTRIBUTES objectAttributes,
- ACCESS_MASK desiredAccess)
- {
- #ifndef _UNICODE
- if (hModule == NULL)
- return MY_STATUS_NOT_IMPLEMENTED;
- LsaOpenPolicyP lsaOpenPolicy = (LsaOpenPolicyP)GetProcAddress(hModule, "LsaOpenPolicy");
- if (lsaOpenPolicy == NULL)
- return MY_STATUS_NOT_IMPLEMENTED;
- #endif
-
- Close();
- return
- #ifdef _UNICODE
- ::LsaOpenPolicy
- #else
- lsaOpenPolicy
- #endif
- (systemName, objectAttributes, desiredAccess, &_handle);
- }
-
- NTSTATUS Close()
- {
- if (_handle == NULL)
- return 0;
-
- #ifndef _UNICODE
- if (hModule == NULL)
- return MY_STATUS_NOT_IMPLEMENTED;
- LsaCloseP lsaClose = (LsaCloseP)GetProcAddress(hModule, "LsaClose");
- if (lsaClose == NULL)
- return MY_STATUS_NOT_IMPLEMENTED;
- #endif
-
- NTSTATUS res =
- #ifdef _UNICODE
- ::LsaClose
- #else
- lsaClose
- #endif
- (_handle);
- _handle = NULL;
- return res;
- }
-
- NTSTATUS EnumerateAccountsWithUserRight(PLSA_UNICODE_STRING userRights,
- PLSA_ENUMERATION_INFORMATION *enumerationBuffer, PULONG countReturned)
- { return LsaEnumerateAccountsWithUserRight(_handle, userRights, (void **)enumerationBuffer, countReturned); }
-
- NTSTATUS EnumerateAccountRights(PSID sid, PLSA_UNICODE_STRING* userRights, PULONG countOfRights)
- { return ::LsaEnumerateAccountRights(_handle, sid, userRights, countOfRights); }
-
- NTSTATUS LookupSids(ULONG count, PSID* sids,
- PLSA_REFERENCED_DOMAIN_LIST* referencedDomains, PLSA_TRANSLATED_NAME* names)
- { return LsaLookupSids(_handle, count, sids, referencedDomains, names); }
-
- NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights, ULONG countOfRights)
- {
- #ifndef _UNICODE
- if (hModule == NULL)
- return MY_STATUS_NOT_IMPLEMENTED;
- LsaAddAccountRightsP lsaAddAccountRights = (LsaAddAccountRightsP)GetProcAddress(hModule, "LsaAddAccountRights");
- if (lsaAddAccountRights == NULL)
- return MY_STATUS_NOT_IMPLEMENTED;
- #endif
-
- return
- #ifdef _UNICODE
- ::LsaAddAccountRights
- #else
- lsaAddAccountRights
- #endif
- (_handle, accountSid, userRights, countOfRights);
- }
- NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights)
- { return AddAccountRights(accountSid, userRights, 1); }
-
- NTSTATUS RemoveAccountRights(PSID accountSid, bool allRights, PLSA_UNICODE_STRING userRights, ULONG countOfRights)
- { return LsaRemoveAccountRights(_handle, accountSid, (BOOLEAN)(allRights ? TRUE : FALSE), userRights, countOfRights); }
-};
-
-bool AddLockMemoryPrivilege();
-
-}}
-
-#endif
+// Windows/SecurityUtils.h
+
+#ifndef ZIP7_INC_WINDOWS_SECURITY_UTILS_H
+#define ZIP7_INC_WINDOWS_SECURITY_UTILS_H
+
+#include <NTSecAPI.h>
+
+#include "Defs.h"
+
+#ifndef _UNICODE
+
+extern "C" {
+typedef NTSTATUS (NTAPI *Func_LsaOpenPolicy)(PLSA_UNICODE_STRING SystemName,
+ PLSA_OBJECT_ATTRIBUTES ObjectAttributes, ACCESS_MASK DesiredAccess, PLSA_HANDLE PolicyHandle);
+typedef NTSTATUS (NTAPI *Func_LsaClose)(LSA_HANDLE ObjectHandle);
+typedef NTSTATUS (NTAPI *Func_LsaAddAccountRights)(LSA_HANDLE PolicyHandle,
+ PSID AccountSid, PLSA_UNICODE_STRING UserRights, ULONG CountOfRights );
+#define MY_STATUS_NOT_IMPLEMENTED ((NTSTATUS)0xC0000002L)
+}
+
+#define POLICY_FUNC_CALL(fff, str) \
+ if (hModule == NULL) return MY_STATUS_NOT_IMPLEMENTED; \
+ const Func_ ## fff v = Z7_GET_PROC_ADDRESS(Func_ ## fff, hModule, str); \
+ if (!v) return MY_STATUS_NOT_IMPLEMENTED; \
+ const NTSTATUS res = v
+
+#else
+
+#define POLICY_FUNC_CALL(fff, str) \
+ const NTSTATUS res = ::fff
+
+#endif
+
+
+namespace NWindows {
+namespace NSecurity {
+
+class CAccessToken
+{
+ HANDLE _handle;
+public:
+ CAccessToken(): _handle(NULL) {}
+ ~CAccessToken() { Close(); }
+ bool Close()
+ {
+ if (_handle == NULL)
+ return true;
+ bool res = BOOLToBool(::CloseHandle(_handle));
+ if (res)
+ _handle = NULL;
+ return res;
+ }
+
+ bool OpenProcessToken(HANDLE processHandle, DWORD desiredAccess)
+ {
+ Close();
+ return BOOLToBool(::OpenProcessToken(processHandle, desiredAccess, &_handle));
+ }
+
+ /*
+ bool OpenThreadToken(HANDLE threadHandle, DWORD desiredAccess, bool openAsSelf)
+ {
+ Close();
+ return BOOLToBool(::OpenTreadToken(threadHandle, desiredAccess, BoolToBOOL(anOpenAsSelf), &_handle));
+ }
+ */
+
+ bool AdjustPrivileges(bool disableAllPrivileges, PTOKEN_PRIVILEGES newState,
+ DWORD bufferLength, PTOKEN_PRIVILEGES previousState, PDWORD returnLength)
+ { return BOOLToBool(::AdjustTokenPrivileges(_handle, BoolToBOOL(disableAllPrivileges),
+ newState, bufferLength, previousState, returnLength)); }
+
+ bool AdjustPrivileges(bool disableAllPrivileges, PTOKEN_PRIVILEGES newState)
+ { return AdjustPrivileges(disableAllPrivileges, newState, 0, NULL, NULL); }
+
+ bool AdjustPrivileges(PTOKEN_PRIVILEGES newState)
+ { return AdjustPrivileges(false, newState); }
+
+};
+
+
+
+
+struct CPolicy
+{
+protected:
+ LSA_HANDLE _handle;
+ #ifndef _UNICODE
+ HMODULE hModule;
+ #endif
+public:
+ operator LSA_HANDLE() const { return _handle; }
+ CPolicy(): _handle(NULL)
+ {
+ #ifndef _UNICODE
+ hModule = GetModuleHandle(TEXT("advapi32.dll"));
+ #endif
+ }
+ ~CPolicy() { Close(); }
+
+ NTSTATUS Open(PLSA_UNICODE_STRING systemName, PLSA_OBJECT_ATTRIBUTES objectAttributes,
+ ACCESS_MASK desiredAccess)
+ {
+ Close();
+ POLICY_FUNC_CALL (LsaOpenPolicy, "LsaOpenPolicy")
+ (systemName, objectAttributes, desiredAccess, &_handle);
+ return res;
+ }
+
+ NTSTATUS Close()
+ {
+ if (_handle == NULL)
+ return 0;
+ POLICY_FUNC_CALL (LsaClose, "LsaClose")
+ (_handle);
+ _handle = NULL;
+ return res;
+ }
+
+ NTSTATUS EnumerateAccountsWithUserRight(PLSA_UNICODE_STRING userRights,
+ PLSA_ENUMERATION_INFORMATION *enumerationBuffer, PULONG countReturned)
+ { return LsaEnumerateAccountsWithUserRight(_handle, userRights, (void **)enumerationBuffer, countReturned); }
+
+ NTSTATUS EnumerateAccountRights(PSID sid, PLSA_UNICODE_STRING* userRights, PULONG countOfRights)
+ { return ::LsaEnumerateAccountRights(_handle, sid, userRights, countOfRights); }
+
+ NTSTATUS LookupSids(ULONG count, PSID* sids,
+ PLSA_REFERENCED_DOMAIN_LIST* referencedDomains, PLSA_TRANSLATED_NAME* names)
+ { return LsaLookupSids(_handle, count, sids, referencedDomains, names); }
+
+ NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights, ULONG countOfRights)
+ {
+ POLICY_FUNC_CALL (LsaAddAccountRights, "LsaAddAccountRights")
+ (_handle, accountSid, userRights, countOfRights);
+ return res;
+ }
+ NTSTATUS AddAccountRights(PSID accountSid, PLSA_UNICODE_STRING userRights)
+ { return AddAccountRights(accountSid, userRights, 1); }
+
+ NTSTATUS RemoveAccountRights(PSID accountSid, bool allRights, PLSA_UNICODE_STRING userRights, ULONG countOfRights)
+ { return LsaRemoveAccountRights(_handle, accountSid, (BOOLEAN)(allRights ? TRUE : FALSE), userRights, countOfRights); }
+};
+
+bool AddLockMemoryPrivilege();
+
+}}
+
+#endif
diff --git a/CPP/Windows/Shell.cpp b/CPP/Windows/Shell.cpp
index 7ba82d4..b2a3489 100644
--- a/CPP/Windows/Shell.cpp
+++ b/CPP/Windows/Shell.cpp
@@ -1,358 +1,821 @@
-// Windows/Shell.cpp
-
-#include "StdAfx.h"
-
-/*
-#include <stdio.h>
-#include <string.h>
-*/
-
-#include "../Common/MyCom.h"
-#ifndef _UNICODE
-#include "../Common/StringConvert.h"
-#endif
-
-#include "COM.h"
-#include "Shell.h"
-
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-namespace NWindows {
-namespace NShell {
-
-#ifndef UNDER_CE
-
-// SHGetMalloc is unsupported in Windows Mobile?
-
-void CItemIDList::Free()
-{
- if (m_Object == NULL)
- return;
- CMyComPtr<IMalloc> shellMalloc;
- if (::SHGetMalloc(&shellMalloc) != NOERROR)
- throw 41099;
- shellMalloc->Free(m_Object);
- m_Object = NULL;
-}
-
-/*
-CItemIDList::(LPCITEMIDLIST itemIDList): m_Object(NULL)
- { *this = itemIDList; }
-CItemIDList::(const CItemIDList& itemIDList): m_Object(NULL)
- { *this = itemIDList; }
-
-CItemIDList& CItemIDList::operator=(LPCITEMIDLIST object)
-{
- Free();
- if (object != 0)
- {
- UINT32 size = GetSize(object);
- m_Object = (LPITEMIDLIST)CoTaskMemAlloc(size);
- if (m_Object != NULL)
- MoveMemory(m_Object, object, size);
- }
- return *this;
-}
-
-CItemIDList& CItemIDList::operator=(const CItemIDList &object)
-{
- Free();
- if (object.m_Object != NULL)
- {
- UINT32 size = GetSize(object.m_Object);
- m_Object = (LPITEMIDLIST)CoTaskMemAlloc(size);
- if (m_Object != NULL)
- MoveMemory(m_Object, object.m_Object, size);
- }
- return *this;
-}
-*/
-
-/////////////////////////////
-// CDrop
-
-void CDrop::Attach(HDROP object)
-{
- Free();
- m_Object = object;
- m_Assigned = true;
-}
-
-void CDrop::Free()
-{
- if (m_MustBeFinished && m_Assigned)
- Finish();
- m_Assigned = false;
-}
-
-UINT CDrop::QueryCountOfFiles()
-{
- return QueryFile(0xFFFFFFFF, (LPTSTR)NULL, 0);
-}
-
-UString CDrop::QueryFileName(UINT fileIndex)
-{
- UString fileName;
- #ifndef _UNICODE
- if (!g_IsNT)
- {
- AString fileNameA;
- UINT bufferSize = QueryFile(fileIndex, (LPTSTR)NULL, 0);
- const unsigned len = bufferSize + 2;
- QueryFile(fileIndex, fileNameA.GetBuf(len), bufferSize + 1);
- fileNameA.ReleaseBuf_CalcLen(len);
- fileName = GetUnicodeString(fileNameA);
- }
- else
- #endif
- {
- UINT bufferSize = QueryFile(fileIndex, (LPWSTR)NULL, 0);
- const unsigned len = bufferSize + 2;
- QueryFile(fileIndex, fileName.GetBuf(len), bufferSize + 1);
- fileName.ReleaseBuf_CalcLen(len);
- }
- return fileName;
-}
-
-void CDrop::QueryFileNames(UStringVector &fileNames)
-{
- UINT numFiles = QueryCountOfFiles();
- /*
- char s[100];
- sprintf(s, "QueryFileNames: %d files", numFiles);
- OutputDebugStringA(s);
- */
- fileNames.ClearAndReserve(numFiles);
- for (UINT i = 0; i < numFiles; i++)
- {
- const UString s2 = QueryFileName(i);
- if (!s2.IsEmpty())
- fileNames.AddInReserved(s2);
- /*
- OutputDebugStringW(L"file ---");
- OutputDebugStringW(s2);
- */
- }
-}
-
-
-bool GetPathFromIDList(LPCITEMIDLIST itemIDList, CSysString &path)
-{
- const unsigned len = MAX_PATH * 2;
- bool result = BOOLToBool(::SHGetPathFromIDList(itemIDList, path.GetBuf(len)));
- path.ReleaseBuf_CalcLen(len);
- return result;
-}
-
-#endif
-
-#ifdef UNDER_CE
-
-bool BrowseForFolder(LPBROWSEINFO, CSysString)
-{
- return false;
-}
-
-bool BrowseForFolder(HWND, LPCTSTR, UINT, LPCTSTR, CSysString &)
-{
- return false;
-}
-
-bool BrowseForFolder(HWND /* owner */, LPCTSTR /* title */,
- LPCTSTR /* initialFolder */, CSysString & /* resultPath */)
-{
- /*
- // SHBrowseForFolder doesn't work before CE 6.0 ?
- if (GetProcAddress(LoadLibrary(L"ceshell.dll", L"SHBrowseForFolder") == 0)
- MessageBoxW(0, L"no", L"", 0);
- else
- MessageBoxW(0, L"yes", L"", 0);
- */
- /*
- UString s = "all files";
- s += " (*.*)";
- return MyGetOpenFileName(owner, title, initialFolder, s, resultPath, true);
- */
- return false;
-}
-
-#else
-
-bool BrowseForFolder(LPBROWSEINFO browseInfo, CSysString &resultPath)
-{
- NWindows::NCOM::CComInitializer comInitializer;
- LPITEMIDLIST itemIDList = ::SHBrowseForFolder(browseInfo);
- if (itemIDList == NULL)
- return false;
- CItemIDList itemIDListHolder;
- itemIDListHolder.Attach(itemIDList);
- return GetPathFromIDList(itemIDList, resultPath);
-}
-
-
-int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data)
-{
- #ifndef UNDER_CE
- switch (uMsg)
- {
- case BFFM_INITIALIZED:
- {
- SendMessage(hwnd, BFFM_SETSELECTION, TRUE, data);
- break;
- }
- /*
- case BFFM_SELCHANGED:
- {
- TCHAR dir[MAX_PATH];
- if (::SHGetPathFromIDList((LPITEMIDLIST) lp , dir))
- SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)dir);
- else
- SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)TEXT(""));
- break;
- }
- */
- default:
- break;
- }
- #endif
- return 0;
-}
-
-
-bool BrowseForFolder(HWND owner, LPCTSTR title, UINT ulFlags,
- LPCTSTR initialFolder, CSysString &resultPath)
-{
- CSysString displayName;
- BROWSEINFO browseInfo;
- browseInfo.hwndOwner = owner;
- browseInfo.pidlRoot = NULL;
-
- // there are Unicode/Astring problems in some WinCE SDK ?
- /*
- #ifdef UNDER_CE
- browseInfo.pszDisplayName = (LPSTR)displayName.GetBuf(MAX_PATH);
- browseInfo.lpszTitle = (LPCSTR)title;
- #else
- */
- browseInfo.pszDisplayName = displayName.GetBuf(MAX_PATH);
- browseInfo.lpszTitle = title;
- // #endif
- browseInfo.ulFlags = ulFlags;
- browseInfo.lpfn = (initialFolder != NULL) ? BrowseCallbackProc : NULL;
- browseInfo.lParam = (LPARAM)initialFolder;
- return BrowseForFolder(&browseInfo, resultPath);
-}
-
-bool BrowseForFolder(HWND owner, LPCTSTR title,
- LPCTSTR initialFolder, CSysString &resultPath)
-{
- return BrowseForFolder(owner, title,
- #ifndef UNDER_CE
- BIF_NEWDIALOGSTYLE |
- #endif
- BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT, initialFolder, resultPath);
- // BIF_STATUSTEXT; BIF_USENEWUI (Version 5.0)
-}
-
-#ifndef _UNICODE
-
-typedef BOOL (WINAPI * SHGetPathFromIDListWP)(LPCITEMIDLIST pidl, LPWSTR pszPath);
-
-bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path)
-{
- path.Empty();
- SHGetPathFromIDListWP shGetPathFromIDListW = (SHGetPathFromIDListWP)
- ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHGetPathFromIDListW");
- if (shGetPathFromIDListW == 0)
- return false;
- const unsigned len = MAX_PATH * 2;
- bool result = BOOLToBool(shGetPathFromIDListW(itemIDList, path.GetBuf(len)));
- path.ReleaseBuf_CalcLen(len);
- return result;
-}
-
-typedef LPITEMIDLIST (WINAPI * SHBrowseForFolderWP)(LPBROWSEINFOW lpbi);
-
-bool BrowseForFolder(LPBROWSEINFOW browseInfo, UString &resultPath)
-{
- NWindows::NCOM::CComInitializer comInitializer;
- SHBrowseForFolderWP shBrowseForFolderW = (SHBrowseForFolderWP)
- ::GetProcAddress(::GetModuleHandleW(L"shell32.dll"), "SHBrowseForFolderW");
- if (shBrowseForFolderW == 0)
- return false;
- LPITEMIDLIST itemIDList = shBrowseForFolderW(browseInfo);
- if (itemIDList == NULL)
- return false;
- CItemIDList itemIDListHolder;
- itemIDListHolder.Attach(itemIDList);
- return GetPathFromIDList(itemIDList, resultPath);
-}
-
-
-int CALLBACK BrowseCallbackProc2(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data)
-{
- switch (uMsg)
- {
- case BFFM_INITIALIZED:
- {
- SendMessageW(hwnd, BFFM_SETSELECTIONW, TRUE, data);
- break;
- }
- /*
- case BFFM_SELCHANGED:
- {
- wchar_t dir[MAX_PATH * 2];
-
- if (shGetPathFromIDListW((LPITEMIDLIST)lp , dir))
- SendMessageW(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)dir);
- else
- SendMessageW(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)L"");
- break;
- }
- */
- default:
- break;
- }
- return 0;
-}
-
-
-static bool BrowseForFolder(HWND owner, LPCWSTR title, UINT ulFlags,
- LPCWSTR initialFolder, UString &resultPath)
-{
- UString displayName;
- BROWSEINFOW browseInfo;
- browseInfo.hwndOwner = owner;
- browseInfo.pidlRoot = NULL;
- browseInfo.pszDisplayName = displayName.GetBuf(MAX_PATH);
- browseInfo.lpszTitle = title;
- browseInfo.ulFlags = ulFlags;
- browseInfo.lpfn = (initialFolder != NULL) ? BrowseCallbackProc2 : NULL;
- browseInfo.lParam = (LPARAM)initialFolder;
- return BrowseForFolder(&browseInfo, resultPath);
-}
-
-bool BrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR initialFolder, UString &resultPath)
-{
- if (g_IsNT)
- return BrowseForFolder(owner, title,
- BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS
- // | BIF_STATUSTEXT // This flag is not supported when BIF_NEWDIALOGSTYLE is specified.
- , initialFolder, resultPath);
- // BIF_STATUSTEXT; BIF_USENEWUI (Version 5.0)
- CSysString s;
- bool res = BrowseForFolder(owner, GetSystemString(title),
- BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS
- // | BIF_STATUSTEXT // This flag is not supported when BIF_NEWDIALOGSTYLE is specified.
- , GetSystemString(initialFolder), s);
- resultPath = GetUnicodeString(s);
- return res;
-}
-
-#endif
-
-#endif
-
-}}
+// Windows/Shell.cpp
+
+#include "StdAfx.h"
+
+#include "../Common/MyCom.h"
+#include "../Common/StringConvert.h"
+
+#include "COM.h"
+#include "FileName.h"
+#include "MemoryGlobal.h"
+#include "Shell.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+// MSVC6 and old SDK don't support this function:
+// #define LWSTDAPI EXTERN_C DECLSPEC_IMPORT HRESULT STDAPICALLTYPE
+// LWSTDAPI StrRetToStrW(STRRET *pstr, LPCITEMIDLIST pidl, LPWSTR *ppsz);
+
+// #define SHOW_DEBUG_SHELL
+
+#ifdef SHOW_DEBUG_SHELL
+
+#include "../Common/IntToString.h"
+
+static void Print_Number(UInt32 number, const char *s)
+{
+ AString s2;
+ s2.Add_UInt32(number);
+ s2.Add_Space();
+ s2 += s;
+ OutputDebugStringA(s2);
+}
+
+#define ODS(sz) { OutputDebugStringA(sz); }
+#define ODS_U(s) { OutputDebugStringW(s); }
+#define ODS_(op) { op; }
+
+#else
+
+#define ODS(sz)
+#define ODS_U(s)
+#define ODS_(op)
+
+#endif
+
+
+namespace NWindows {
+namespace NShell {
+
+#ifndef UNDER_CE
+
+// SHGetMalloc is unsupported in Windows Mobile?
+
+void CItemIDList::Free()
+{
+ if (!m_Object)
+ return;
+ /* DOCs:
+ SHGetMalloc was introduced in Windows 95 and Microsoft Windows NT 4.0,
+ but as of Windows 2000 it is no longer necessary.
+ In its place, programs can call the equivalent (and easier to use) CoTaskMemAlloc and CoTaskMemFree.
+ Description from oldnewthings:
+ shell functions could work without COM (if OLE32.DLL is not loaded),
+ but now if OLE32.DLL is loaded, then shell functions and com functions do same things.
+ 22.02: so we use OLE32.DLL function to free memory:
+ */
+ /*
+ CMyComPtr<IMalloc> shellMalloc;
+ if (::SHGetMalloc(&shellMalloc) != NOERROR)
+ throw 41099;
+ shellMalloc->Free(m_Object);
+ */
+ CoTaskMemFree(m_Object);
+ m_Object = NULL;
+}
+
+/*
+CItemIDList::(LPCITEMIDLIST itemIDList): m_Object(NULL)
+ { *this = itemIDList; }
+CItemIDList::(const CItemIDList& itemIDList): m_Object(NULL)
+ { *this = itemIDList; }
+
+CItemIDList& CItemIDList::operator=(LPCITEMIDLIST object)
+{
+ Free();
+ if (object != 0)
+ {
+ UINT32 size = GetSize(object);
+ m_Object = (LPITEMIDLIST)CoTaskMemAlloc(size);
+ if (m_Object != NULL)
+ MoveMemory(m_Object, object, size);
+ }
+ return *this;
+}
+
+CItemIDList& CItemIDList::operator=(const CItemIDList &object)
+{
+ Free();
+ if (object.m_Object != NULL)
+ {
+ UINT32 size = GetSize(object.m_Object);
+ m_Object = (LPITEMIDLIST)CoTaskMemAlloc(size);
+ if (m_Object != NULL)
+ MoveMemory(m_Object, object.m_Object, size);
+ }
+ return *this;
+}
+*/
+
+
+static HRESULT ReadUnicodeStrings(const wchar_t *p, size_t size, UStringVector &names)
+{
+ names.Clear();
+ const wchar_t *lim = p + size;
+ UString s;
+ /*
+ if (size == 0 || p[size - 1] != 0)
+ return E_INVALIDARG;
+ if (size == 1)
+ return S_OK;
+ if (p[size - 2] != 0)
+ return E_INVALIDARG;
+ */
+ for (;;)
+ {
+ const wchar_t *start = p;
+ for (;;)
+ {
+ if (p == lim) return E_INVALIDARG; // S_FALSE
+ if (*p++ == 0)
+ break;
+ }
+ const size_t num = (size_t)(p - start);
+ if (num == 1)
+ {
+ if (p != lim) return E_INVALIDARG; // S_FALSE
+ return S_OK;
+ }
+ s.SetFrom(start, (unsigned)(num - 1));
+ ODS_U(s)
+ names.Add(s);
+ // names.ReserveOnePosition();
+ // names.AddInReserved_Ptr_of_new(new UString((unsigned)num - 1, start));
+ }
+}
+
+
+static HRESULT ReadAnsiStrings(const char *p, size_t size, UStringVector &names)
+{
+ names.Clear();
+ AString name;
+ for (; size != 0; size--)
+ {
+ const char c = *p++;
+ if (c == 0)
+ {
+ if (name.IsEmpty())
+ return S_OK;
+ names.Add(GetUnicodeString(name));
+ name.Empty();
+ }
+ else
+ name += c;
+ }
+ return E_INVALIDARG;
+}
+
+
+#define INIT_FORMATETC_HGLOBAL(type) { (type), NULL, DVASPECT_CONTENT, -1, TYMED_HGLOBAL }
+
+static HRESULT DataObject_GetData_HGLOBAL(IDataObject *dataObject, CLIPFORMAT cf, NCOM::CStgMedium &medium)
+{
+ FORMATETC etc = INIT_FORMATETC_HGLOBAL(cf);
+ RINOK(dataObject->GetData(&etc, &medium))
+ if (medium.tymed != TYMED_HGLOBAL)
+ return E_INVALIDARG;
+ return S_OK;
+}
+
+static HRESULT DataObject_GetData_HDROP_Names(IDataObject *dataObject, UStringVector &names)
+{
+ names.Clear();
+ NCOM::CStgMedium medium;
+
+ /* Win10 : if (dataObject) is from IContextMenu::Initialize() and
+ if (len_of_path >= MAX_PATH (260) for some file in data object)
+ {
+ GetData() returns HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER)
+ "The data area passed to a system call is too small",
+ Is there a way to fix this code for long paths?
+ } */
+
+ RINOK(DataObject_GetData_HGLOBAL(dataObject, CF_HDROP, medium))
+ const size_t blockSize = GlobalSize(medium.hGlobal);
+ if (blockSize < sizeof(DROPFILES))
+ return E_INVALIDARG;
+ NMemory::CGlobalLock dropLock(medium.hGlobal);
+ const DROPFILES *dropFiles = (const DROPFILES *)dropLock.GetPointer();
+ if (!dropFiles)
+ return E_INVALIDARG;
+ if (blockSize < dropFiles->pFiles
+ || dropFiles->pFiles < sizeof(DROPFILES)
+ // || dropFiles->pFiles != sizeof(DROPFILES)
+ )
+ return E_INVALIDARG;
+ const size_t size = blockSize - dropFiles->pFiles;
+ const void *namesData = (const Byte *)(const void *)dropFiles + dropFiles->pFiles;
+ HRESULT hres;
+ if (dropFiles->fWide)
+ {
+ if (size % sizeof(wchar_t) != 0)
+ return E_INVALIDARG;
+ hres = ReadUnicodeStrings((const wchar_t *)namesData, size / sizeof(wchar_t), names);
+ }
+ else
+ hres = ReadAnsiStrings((const char *)namesData, size, names);
+
+ ODS_(Print_Number(names.Size(), "DataObject_GetData_HDROP_Names"))
+ return hres;
+}
+
+
+
+// CF_IDLIST:
+#define MYWIN_CFSTR_SHELLIDLIST TEXT("Shell IDList Array")
+
+typedef struct
+{
+ UINT cidl;
+ UINT aoffset[1];
+} MYWIN_CIDA;
+/*
+ cidl : number of PIDLs that are being transferred, not including the parent folder.
+ aoffset : An array of offsets, relative to the beginning of this structure.
+ aoffset[0] - fully qualified PIDL of a parent folder.
+ If this PIDL is empty, the parent folder is the desktop.
+ aoffset[1] ... aoffset[cidl] : offset to one of the PIDLs to be transferred.
+ All of these PIDLs are relative to the PIDL of the parent folder.
+*/
+
+static HRESULT DataObject_GetData_IDLIST(IDataObject *dataObject, UStringVector &names)
+{
+ names.Clear();
+ NCOM::CStgMedium medium;
+ RINOK(DataObject_GetData_HGLOBAL(dataObject, (CLIPFORMAT)
+ RegisterClipboardFormat(MYWIN_CFSTR_SHELLIDLIST), medium))
+ const size_t blockSize = GlobalSize(medium.hGlobal);
+ if (blockSize < sizeof(MYWIN_CIDA) || blockSize >= (UInt32)((UInt32)0 - 1))
+ return E_INVALIDARG;
+ NMemory::CGlobalLock dropLock(medium.hGlobal);
+ const MYWIN_CIDA *cida = (const MYWIN_CIDA *)dropLock.GetPointer();
+ if (!cida)
+ return E_INVALIDARG;
+ if (cida->cidl == 0)
+ {
+ // is it posssible to have no selected items?
+ // it's unexpected case.
+ return E_INVALIDARG;
+ }
+ if (cida->cidl >= (blockSize - (UInt32)sizeof(MYWIN_CIDA)) / sizeof(UINT))
+ return E_INVALIDARG;
+ const UInt32 start = cida->cidl * (UInt32)sizeof(UINT) + (UInt32)sizeof(MYWIN_CIDA);
+
+ STRRET strret;
+ CMyComPtr<IShellFolder> parentFolder;
+ {
+ const UINT offset = cida->aoffset[0];
+ if (offset < start || offset >= blockSize
+ // || offset != start
+ )
+ return E_INVALIDARG;
+
+ CMyComPtr<IShellFolder> desktopFolder;
+ RINOK(::SHGetDesktopFolder(&desktopFolder))
+ if (!desktopFolder)
+ return E_FAIL;
+
+ LPCITEMIDLIST const lpcItem = (LPCITEMIDLIST)(const void *)((const Byte *)cida + offset);
+
+ #ifdef SHOW_DEBUG_SHELL
+ {
+ const HRESULT res = desktopFolder->GetDisplayNameOf(
+ lpcItem, SHGDN_FORPARSING, &strret);
+ if (res == S_OK && strret.uType == STRRET_WSTR)
+ {
+ ODS_U(strret.pOleStr)
+ /* if lpcItem is empty, the path will be
+ "C:\Users\user_name\Desktop"
+ if lpcItem is "My Computer" folder, the path will be
+ "::{20D04FE0-3AEA-1069-A2D8-08002B30309D}" */
+ CoTaskMemFree(strret.pOleStr);
+ }
+ }
+ #endif
+
+ RINOK(desktopFolder->BindToObject(lpcItem,
+ NULL, IID_IShellFolder, (void **)&parentFolder))
+ if (!parentFolder)
+ return E_FAIL;
+ }
+
+ names.ClearAndReserve(cida->cidl);
+ UString path;
+
+ // for (int y = 0; y < 1; y++) // for debug
+ for (unsigned i = 1; i <= cida->cidl; i++)
+ {
+ const UINT offset = cida->aoffset[i];
+ if (offset < start || offset >= blockSize)
+ return E_INVALIDARG;
+ const void *p = (const Byte *)(const void *)cida + offset;
+ /* ITEMIDLIST of file can contain more than one SHITEMID item.
+ In win10 only SHGDN_FORPARSING returns path that contains
+ all path parts related to parts of ITEMIDLIST.
+ So we can use only SHGDN_FORPARSING here.
+ Don't use (SHGDN_INFOLDER)
+ Don't use (SHGDN_INFOLDER | SHGDN_FORPARSING)
+ */
+ RINOK(parentFolder->GetDisplayNameOf((LPCITEMIDLIST)p, SHGDN_FORPARSING, &strret))
+
+ /*
+ // MSVC6 and old SDK do not support StrRetToStrW().
+ LPWSTR lpstr;
+ RINOK (StrRetToStrW(&strret, NULL, &lpstr))
+ ODS_U(lpstr)
+ path = lpstr;
+ CoTaskMemFree(lpstr);
+ */
+ if (strret.uType != STRRET_WSTR)
+ return E_INVALIDARG;
+ ODS_U(strret.pOleStr)
+ path = strret.pOleStr;
+ // the path could have super path prefix "\\\\?\\"
+ // we can remove super path prefix here, if we don't need that prefix
+ #ifdef Z7_LONG_PATH
+ // we remove super prefix, if we can work without that prefix
+ NFile::NName::If_IsSuperPath_RemoveSuperPrefix(path);
+ #endif
+ names.AddInReserved(path);
+ CoTaskMemFree(strret.pOleStr);
+ }
+
+ ODS_(Print_Number(cida->cidl, "CFSTR_SHELLIDLIST END"))
+ return S_OK;
+}
+
+
+HRESULT DataObject_GetData_HDROP_or_IDLIST_Names(IDataObject *dataObject, UStringVector &paths)
+{
+ ODS("-- DataObject_GetData_HDROP_or_IDLIST_Names START")
+ HRESULT hres = NShell::DataObject_GetData_HDROP_Names(dataObject, paths);
+ // if (hres == HRESULT_FROM_WIN32(ERROR_INSUFFICIENT_BUFFER))
+ if (hres != S_OK)
+ {
+ ODS("-- DataObject_GetData_IDLIST START")
+ // for (int y = 0; y < 10000; y++) // for debug
+ hres = NShell::DataObject_GetData_IDLIST(dataObject, paths);
+ }
+ ODS("-- DataObject_GetData_HDROP_or_IDLIST_Names END")
+ return hres;
+}
+
+
+
+// #if (NTDDI_VERSION >= NTDDI_VISTA)
+typedef struct
+{
+ UINT cItems; // number of items in rgdwFileAttributes array
+ DWORD dwSumFileAttributes; // all of the attributes ORed together
+ DWORD dwProductFileAttributes; // all of the attributes ANDed together
+ DWORD rgdwFileAttributes[1]; // array
+} MYWIN_FILE_ATTRIBUTES_ARRAY;
+
+#define MYWIN_CFSTR_FILE_ATTRIBUTES_ARRAY TEXT("File Attributes Array")
+
+HRESULT DataObject_GetData_FILE_ATTRS(IDataObject *dataObject, CFileAttribs &attribs)
+{
+ attribs.Clear();
+ NCOM::CStgMedium medium;
+ RINOK(DataObject_GetData_HGLOBAL(dataObject, (CLIPFORMAT)
+ RegisterClipboardFormat(MYWIN_CFSTR_FILE_ATTRIBUTES_ARRAY), medium))
+ const size_t blockSize = GlobalSize(medium.hGlobal);
+ if (blockSize < sizeof(MYWIN_FILE_ATTRIBUTES_ARRAY))
+ return E_INVALIDARG;
+ NMemory::CGlobalLock dropLock(medium.hGlobal);
+ const MYWIN_FILE_ATTRIBUTES_ARRAY *faa = (const MYWIN_FILE_ATTRIBUTES_ARRAY *)dropLock.GetPointer();
+ if (!faa)
+ return E_INVALIDARG;
+ const unsigned numFiles = faa->cItems;
+ if (numFiles == 0)
+ {
+ // is it posssible to have empty array here?
+ return E_INVALIDARG;
+ }
+ if ((blockSize - (sizeof(MYWIN_FILE_ATTRIBUTES_ARRAY) - sizeof(DWORD)))
+ / sizeof(DWORD) != numFiles)
+ return E_INVALIDARG;
+ // attribs.Sum = faa->dwSumFileAttributes;
+ // attribs.Product = faa->dwProductFileAttributes;
+ // attribs.Vals.SetFromArray(faa->rgdwFileAttributes, numFiles);
+ // attribs.IsDirVector.ClearAndSetSize(numFiles);
+
+ if ((faa->dwSumFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0)
+ {
+ /* in win10: if selected items are volumes (c:\, d:\ ..) in My Compter,
+ all items have FILE_ATTRIBUTE_DIRECTORY attribute
+ ntfs volume also have FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_SYSTEM
+ udf volume: FILE_ATTRIBUTE_READONLY
+ dvd-rom device: (-1) : all bits are set
+ */
+ const DWORD *attr = faa->rgdwFileAttributes;
+ // DWORD product = (UInt32)0 - 1, sum = 0;
+ for (unsigned i = 0; i < numFiles; i++)
+ {
+ if (attr[i] & FILE_ATTRIBUTE_DIRECTORY)
+ {
+ // attribs.ThereAreDirs = true;
+ attribs.FirstDirIndex = (int)i;
+ break;
+ }
+ // attribs.IsDirVector[i] = (attr[i] & FILE_ATTRIBUTE_DIRECTORY) != 0;
+ // product &= v;
+ // sum |= v;
+ }
+ // ODS_(Print_Number(product, "Product calc FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names"))
+ // ODS_(Print_Number(sum, "Sum calc FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names"))
+ }
+ // ODS_(Print_Number(attribs.Product, "Product FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names"))
+ // ODS_(Print_Number(attribs.Sum, "Sum FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names"))
+ ODS_(Print_Number(numFiles, "FILE_ATTRIBUTES_ARRAY ==== DataObject_GetData_HDROP_Names"))
+ return S_OK;
+}
+
+
+/////////////////////////////
+// CDrop
+
+/*
+ win10:
+ DragQueryFile() implementation code is not effective because
+ there is no pointer inside DROP internal file list, so
+ DragQueryFile(fileIndex) runs all names in range [0, fileIndex].
+ DragQueryFile(,, buf, bufSize)
+ if (buf == NULL) by spec
+ {
+ returns value is the required size
+ in characters, of the buffer, not including the terminating null character
+ tests show that if (bufSize == 0), then it also returns required size.
+ }
+ if (bufSize != NULL)
+ {
+ returns: the count of the characters copied, not including null character.
+ win10: null character is also copied at position buf[ret_count];
+ }
+*/
+
+/*
+void CDrop::Attach(HDROP object)
+{
+ Free();
+ m_Object = object;
+ m_Assigned = true;
+}
+
+void CDrop::Free()
+{
+ if (m_MustBeFinished && m_Assigned)
+ Finish();
+ m_Assigned = false;
+}
+
+UINT CDrop::QueryCountOfFiles()
+{
+ return QueryFile(0xFFFFFFFF, (LPTSTR)NULL, 0);
+}
+
+void CDrop::QueryFileName(UINT fileIndex, UString &fileName)
+{
+ #ifndef _UNICODE
+ if (!g_IsNT)
+ {
+ AString fileNameA;
+ const UINT len = QueryFile(fileIndex, (LPTSTR)NULL, 0);
+ const UINT numCopied = QueryFile(fileIndex, fileNameA.GetBuf(len + 2), len + 2);
+ fileNameA.ReleaseBuf_CalcLen(len);
+ if (numCopied != len)
+ throw 20221223;
+ fileName = GetUnicodeString(fileNameA);
+ }
+ else
+ #endif
+ {
+ // kReserve must be >= 3 for additional buffer size
+ // safety and for optimal performance
+ const unsigned kReserve = 3;
+ {
+ unsigned len = 0;
+ wchar_t *buf = fileName.GetBuf_GetMaxAvail(len);
+ if (len >= kReserve)
+ {
+ const UINT numCopied = QueryFile(fileIndex, buf, len);
+ if (numCopied < len - 1)
+ {
+ // (numCopied < len - 1) case means that it have copied full string.
+ fileName.ReleaseBuf_CalcLen(numCopied);
+ return;
+ }
+ }
+ }
+ const UINT len = QueryFile(fileIndex, (LPWSTR)NULL, 0);
+ const UINT numCopied = QueryFile(fileIndex,
+ fileName.GetBuf(len + kReserve), len + kReserve);
+ fileName.ReleaseBuf_CalcLen(len);
+ if (numCopied != len)
+ throw 20221223;
+ }
+}
+
+
+void CDrop::QueryFileNames(UStringVector &fileNames)
+{
+ UINT numFiles = QueryCountOfFiles();
+
+ Print_Number(numFiles, "\n====== CDrop::QueryFileNames START ===== \n");
+
+ fileNames.ClearAndReserve(numFiles);
+ UString s;
+ for (UINT i = 0; i < numFiles; i++)
+ {
+ QueryFileName(i, s);
+ if (!s.IsEmpty())
+ fileNames.AddInReserved(s);
+ }
+ Print_Number(numFiles, "\n====== CDrop::QueryFileNames END ===== \n");
+}
+*/
+
+
+// #if (NTDDI_VERSION >= NTDDI_VISTA)
+// SHGetPathFromIDListEx returns a win32 file system path for the item in the name space.
+typedef int Z7_WIN_GPFIDL_FLAGS;
+
+extern "C" {
+typedef BOOL (WINAPI * Func_SHGetPathFromIDListW)(LPCITEMIDLIST pidl, LPWSTR pszPath);
+typedef BOOL (WINAPI * Func_SHGetPathFromIDListEx)(LPCITEMIDLIST pidl, PWSTR pszPath, DWORD cchPath, Z7_WIN_GPFIDL_FLAGS uOpts);
+}
+
+#ifndef _UNICODE
+
+bool GetPathFromIDList(LPCITEMIDLIST itemIDList, AString &path)
+{
+ path.Empty();
+ const unsigned len = MAX_PATH + 16;
+ const bool result = BOOLToBool(::SHGetPathFromIDList(itemIDList, path.GetBuf(len)));
+ path.ReleaseBuf_CalcLen(len);
+ return result;
+}
+
+#endif
+
+bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path)
+{
+ path.Empty();
+ unsigned len = MAX_PATH + 16;
+
+#ifdef _UNICODE
+ bool result = BOOLToBool(::SHGetPathFromIDList(itemIDList, path.GetBuf(len)));
+#else
+ const
+ Func_SHGetPathFromIDListW
+ shGetPathFromIDListW = Z7_GET_PROC_ADDRESS(
+ Func_SHGetPathFromIDListW, ::GetModuleHandleW(L"shell32.dll"),
+ "SHGetPathFromIDListW");
+ if (!shGetPathFromIDListW)
+ return false;
+ bool result = BOOLToBool(shGetPathFromIDListW(itemIDList, path.GetBuf(len)));
+#endif
+
+ if (!result)
+ {
+ ODS("==== GetPathFromIDList() SHGetPathFromIDList() returned false")
+ /* for long path we need SHGetPathFromIDListEx().
+ win10: SHGetPathFromIDListEx() for long path returns path with
+ with super path prefix "\\\\?\\". */
+ const
+ Func_SHGetPathFromIDListEx
+ func_SHGetPathFromIDListEx = Z7_GET_PROC_ADDRESS(
+ Func_SHGetPathFromIDListEx, ::GetModuleHandleW(L"shell32.dll"),
+ "SHGetPathFromIDListEx");
+ if (func_SHGetPathFromIDListEx)
+ {
+ ODS("==== GetPathFromIDList() (SHGetPathFromIDListEx)")
+ do
+ {
+ len *= 4;
+ result = BOOLToBool(func_SHGetPathFromIDListEx(itemIDList, path.GetBuf(len), len, 0));
+ if (result)
+ break;
+ }
+ while (len <= (1 << 16));
+ }
+ }
+
+ path.ReleaseBuf_CalcLen(len);
+ return result;
+}
+
+#endif
+
+#ifdef UNDER_CE
+
+bool BrowseForFolder(LPBROWSEINFO, CSysString)
+{
+ return false;
+}
+
+bool BrowseForFolder(HWND, LPCTSTR, UINT, LPCTSTR, CSysString &)
+{
+ return false;
+}
+
+bool BrowseForFolder(HWND /* owner */, LPCTSTR /* title */,
+ LPCTSTR /* initialFolder */, CSysString & /* resultPath */)
+{
+ /*
+ // SHBrowseForFolder doesn't work before CE 6.0 ?
+ if (GetProcAddress(LoadLibrary(L"ceshell.dll", L"SHBrowseForFolder") == 0)
+ MessageBoxW(0, L"no", L"", 0);
+ else
+ MessageBoxW(0, L"yes", L"", 0);
+ */
+ /*
+ UString s = "all files";
+ s += " (*.*)";
+ return MyGetOpenFileName(owner, title, initialFolder, s, resultPath, true);
+ */
+ return false;
+}
+
+#else
+
+/* win10: SHBrowseForFolder() doesn't support long paths,
+ even if long path suppport is enabled in registry and in manifest.
+ and SHBrowseForFolder() doesn't support super path prefix "\\\\?\\". */
+
+bool BrowseForFolder(LPBROWSEINFO browseInfo, CSysString &resultPath)
+{
+ resultPath.Empty();
+ NWindows::NCOM::CComInitializer comInitializer;
+ LPITEMIDLIST itemIDList = ::SHBrowseForFolder(browseInfo);
+ if (!itemIDList)
+ return false;
+ CItemIDList itemIDListHolder;
+ itemIDListHolder.Attach(itemIDList);
+ return GetPathFromIDList(itemIDList, resultPath);
+}
+
+
+static int CALLBACK BrowseCallbackProc(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data)
+{
+ #ifndef UNDER_CE
+ switch (uMsg)
+ {
+ case BFFM_INITIALIZED:
+ {
+ SendMessage(hwnd, BFFM_SETSELECTION, TRUE, data);
+ break;
+ }
+ /*
+ case BFFM_SELCHANGED:
+ {
+ TCHAR dir[MAX_PATH];
+ if (::SHGetPathFromIDList((LPITEMIDLIST) lp , dir))
+ SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)dir);
+ else
+ SendMessage(hwnd, BFFM_SETSTATUSTEXT, 0, (LPARAM)TEXT(""));
+ break;
+ }
+ */
+ default:
+ break;
+ }
+ #endif
+ return 0;
+}
+
+
+static bool BrowseForFolder(HWND owner, LPCTSTR title, UINT ulFlags,
+ LPCTSTR initialFolder, CSysString &resultPath)
+{
+ CSysString displayName;
+ BROWSEINFO browseInfo;
+ browseInfo.hwndOwner = owner;
+ browseInfo.pidlRoot = NULL;
+
+ // there are Unicode/Astring problems in some WinCE SDK ?
+ /*
+ #ifdef UNDER_CE
+ browseInfo.pszDisplayName = (LPSTR)displayName.GetBuf(MAX_PATH);
+ browseInfo.lpszTitle = (LPCSTR)title;
+ #else
+ */
+ browseInfo.pszDisplayName = displayName.GetBuf(MAX_PATH);
+ browseInfo.lpszTitle = title;
+ // #endif
+ browseInfo.ulFlags = ulFlags;
+ browseInfo.lpfn = initialFolder ? BrowseCallbackProc : NULL;
+ browseInfo.lParam = (LPARAM)initialFolder;
+ return BrowseForFolder(&browseInfo, resultPath);
+}
+
+#ifdef Z7_OLD_WIN_SDK
+// ShlObj.h:
+#ifndef BIF_NEWDIALOGSTYLE
+#define BIF_NEWDIALOGSTYLE 0x0040
+#endif
+#endif
+
+bool BrowseForFolder(HWND owner, LPCTSTR title,
+ LPCTSTR initialFolder, CSysString &resultPath)
+{
+ return BrowseForFolder(owner, title,
+ #ifndef UNDER_CE
+ BIF_NEWDIALOGSTYLE |
+ #endif
+ BIF_RETURNONLYFSDIRS | BIF_STATUSTEXT, initialFolder, resultPath);
+ // BIF_STATUSTEXT; BIF_USENEWUI (Version 5.0)
+}
+
+#ifndef _UNICODE
+
+extern "C" {
+typedef LPITEMIDLIST (WINAPI * Func_SHBrowseForFolderW)(LPBROWSEINFOW lpbi);
+}
+
+static bool BrowseForFolder(LPBROWSEINFOW browseInfo, UString &resultPath)
+{
+ NWindows::NCOM::CComInitializer comInitializer;
+ const
+ Func_SHBrowseForFolderW
+ f_SHBrowseForFolderW = Z7_GET_PROC_ADDRESS(
+ Func_SHBrowseForFolderW, ::GetModuleHandleW(L"shell32.dll"),
+ "SHBrowseForFolderW");
+ if (!f_SHBrowseForFolderW)
+ return false;
+ LPITEMIDLIST itemIDList = f_SHBrowseForFolderW(browseInfo);
+ if (!itemIDList)
+ return false;
+ CItemIDList itemIDListHolder;
+ itemIDListHolder.Attach(itemIDList);
+ return GetPathFromIDList(itemIDList, resultPath);
+}
+
+static
+int CALLBACK BrowseCallbackProc2(HWND hwnd, UINT uMsg, LPARAM /* lp */, LPARAM data)
+{
+ switch (uMsg)
+ {
+ case BFFM_INITIALIZED:
+ {
+ SendMessageW(hwnd, BFFM_SETSELECTIONW, TRUE, data);
+ break;
+ }
+ /*
+ case BFFM_SELCHANGED:
+ {
+ wchar_t dir[MAX_PATH * 2];
+
+ if (shGetPathFromIDListW((LPITEMIDLIST)lp , dir))
+ SendMessageW(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)dir);
+ else
+ SendMessageW(hwnd, BFFM_SETSTATUSTEXTW, 0, (LPARAM)L"");
+ break;
+ }
+ */
+ default:
+ break;
+ }
+ return 0;
+}
+
+
+static bool BrowseForFolder(HWND owner, LPCWSTR title, UINT ulFlags,
+ LPCWSTR initialFolder, UString &resultPath)
+{
+ UString displayName;
+ BROWSEINFOW browseInfo;
+ browseInfo.hwndOwner = owner;
+ browseInfo.pidlRoot = NULL;
+ browseInfo.pszDisplayName = displayName.GetBuf(MAX_PATH);
+ browseInfo.lpszTitle = title;
+ browseInfo.ulFlags = ulFlags;
+ browseInfo.lpfn = initialFolder ? BrowseCallbackProc2 : NULL;
+ browseInfo.lParam = (LPARAM)initialFolder;
+ return BrowseForFolder(&browseInfo, resultPath);
+}
+
+bool BrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR initialFolder, UString &resultPath)
+{
+ if (g_IsNT)
+ return BrowseForFolder(owner, title,
+ BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS
+ // | BIF_STATUSTEXT // This flag is not supported when BIF_NEWDIALOGSTYLE is specified.
+ , initialFolder, resultPath);
+ // BIF_STATUSTEXT; BIF_USENEWUI (Version 5.0)
+ CSysString s;
+ bool res = BrowseForFolder(owner, GetSystemString(title),
+ BIF_NEWDIALOGSTYLE | BIF_RETURNONLYFSDIRS
+ // | BIF_STATUSTEXT // This flag is not supported when BIF_NEWDIALOGSTYLE is specified.
+ , GetSystemString(initialFolder), s);
+ resultPath = GetUnicodeString(s);
+ return res;
+}
+
+#endif
+
+#endif
+
+}}
diff --git a/CPP/Windows/Shell.h b/CPP/Windows/Shell.h
index 9068040..b4cdb30 100644
--- a/CPP/Windows/Shell.h
+++ b/CPP/Windows/Shell.h
@@ -1,94 +1,130 @@
-// Windows/Shell.h
-
-#ifndef __WINDOWS_SHELL_H
-#define __WINDOWS_SHELL_H
-
-#include <windows.h>
-#include <shlobj.h>
-
-#include "../Common/MyString.h"
-
-#include "Defs.h"
-
-namespace NWindows{
-namespace NShell{
-
-/////////////////////////
-// CItemIDList
-#ifndef UNDER_CE
-
-class CItemIDList
-{
- LPITEMIDLIST m_Object;
-public:
- CItemIDList(): m_Object(NULL) {}
- // CItemIDList(LPCITEMIDLIST itemIDList);
- // CItemIDList(const CItemIDList& itemIDList);
- ~CItemIDList() { Free(); }
- void Free();
- void Attach(LPITEMIDLIST object)
- {
- Free();
- m_Object = object;
- }
- LPITEMIDLIST Detach()
- {
- LPITEMIDLIST object = m_Object;
- m_Object = NULL;
- return object;
- }
- operator LPITEMIDLIST() { return m_Object;}
- operator LPCITEMIDLIST() const { return m_Object;}
- LPITEMIDLIST* operator&() { return &m_Object; }
- LPITEMIDLIST operator->() { return m_Object; }
-
- // CItemIDList& operator=(LPCITEMIDLIST object);
- // CItemIDList& operator=(const CItemIDList &object);
-};
-
-/////////////////////////////
-// CDrop
-
-class CDrop
-{
- HDROP m_Object;
- bool m_MustBeFinished;
- bool m_Assigned;
- void Free();
-public:
- CDrop(bool mustBeFinished) : m_MustBeFinished(mustBeFinished), m_Assigned(false) {}
- ~CDrop() { Free(); }
-
- void Attach(HDROP object);
- operator HDROP() { return m_Object;}
- bool QueryPoint(LPPOINT point)
- { return BOOLToBool(::DragQueryPoint(m_Object, point)); }
- void Finish() { ::DragFinish(m_Object); }
- UINT QueryFile(UINT fileIndex, LPTSTR fileName, UINT fileNameSize)
- { return ::DragQueryFile(m_Object, fileIndex, fileName, fileNameSize); }
- #ifndef _UNICODE
- UINT QueryFile(UINT fileIndex, LPWSTR fileName, UINT fileNameSize)
- { return ::DragQueryFileW(m_Object, fileIndex, fileName, fileNameSize); }
- #endif
- UINT QueryCountOfFiles();
- UString QueryFileName(UINT fileIndex);
- void QueryFileNames(UStringVector &fileNames);
-};
-
-#endif
-
-/////////////////////////////
-// Functions
-
-bool GetPathFromIDList(LPCITEMIDLIST itemIDList, CSysString &path);
-bool BrowseForFolder(LPBROWSEINFO lpbi, CSysString &resultPath);
-bool BrowseForFolder(HWND owner, LPCTSTR title, LPCTSTR initialFolder, CSysString &resultPath);
-
-#ifndef _UNICODE
-bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path);
-bool BrowseForFolder(LPBROWSEINFO lpbi, UString &resultPath);
-bool BrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR initialFolder, UString &resultPath);
-#endif
-}}
-
-#endif
+// Windows/Shell.h
+
+#ifndef ZIP7_WINDOWS_SHELL_H
+#define ZIP7_WINDOWS_SHELL_H
+
+#include "../Common/Common.h"
+#include "../Common/MyWindows.h"
+#if defined(__MINGW32__) || defined(__MINGW64__)
+#include <shlobj.h>
+#else
+#include <ShlObj.h>
+#endif
+
+#include "../Common/MyString.h"
+
+#include "Defs.h"
+
+namespace NWindows {
+namespace NShell {
+
+/////////////////////////
+// CItemIDList
+#ifndef UNDER_CE
+
+class CItemIDList
+{
+ LPITEMIDLIST m_Object;
+ Z7_CLASS_NO_COPY(CItemIDList)
+public:
+ CItemIDList(): m_Object(NULL) {}
+ // CItemIDList(LPCITEMIDLIST itemIDList);
+ // CItemIDList(const CItemIDList& itemIDList);
+ ~CItemIDList() { Free(); }
+ void Free();
+ void Attach(LPITEMIDLIST object)
+ {
+ Free();
+ m_Object = object;
+ }
+ LPITEMIDLIST Detach()
+ {
+ LPITEMIDLIST object = m_Object;
+ m_Object = NULL;
+ return object;
+ }
+ operator LPITEMIDLIST() { return m_Object;}
+ operator LPCITEMIDLIST() const { return m_Object;}
+ LPITEMIDLIST* operator&() { return &m_Object; }
+ LPITEMIDLIST operator->() { return m_Object; }
+
+ // CItemIDList& operator=(LPCITEMIDLIST object);
+ // CItemIDList& operator=(const CItemIDList &object);
+};
+
+/////////////////////////////
+// CDrop
+
+/*
+class CDrop
+{
+ HDROP m_Object;
+ bool m_MustBeFinished;
+ bool m_Assigned;
+ void Free();
+public:
+ CDrop(bool mustBeFinished) : m_MustBeFinished(mustBeFinished), m_Assigned(false) {}
+ ~CDrop() { Free(); }
+
+ void Attach(HDROP object);
+ operator HDROP() { return m_Object;}
+ bool QueryPoint(LPPOINT point)
+ { return BOOLToBool(::DragQueryPoint(m_Object, point)); }
+ void Finish()
+ {
+ ::DragFinish(m_Object);
+ }
+ UINT QueryFile(UINT fileIndex, LPTSTR fileName, UINT bufSize)
+ { return ::DragQueryFile(m_Object, fileIndex, fileName, bufSize); }
+ #ifndef _UNICODE
+ UINT QueryFile(UINT fileIndex, LPWSTR fileName, UINT bufSize)
+ { return ::DragQueryFileW(m_Object, fileIndex, fileName, bufSize); }
+ #endif
+ UINT QueryCountOfFiles();
+ void QueryFileName(UINT fileIndex, UString &fileName);
+ void QueryFileNames(UStringVector &fileNames);
+};
+*/
+#endif
+
+struct CFileAttribs
+{
+ int FirstDirIndex;
+ // DWORD Sum;
+ // DWORD Product;
+ // CRecordVector<DWORD> Vals;
+ // CRecordVector<bool> IsDirVector;
+
+ CFileAttribs()
+ {
+ Clear();
+ }
+
+ void Clear()
+ {
+ FirstDirIndex = -1;
+ // Sum = 0;
+ // Product = 0;
+ // IsDirVector.Clear();
+ }
+};
+
+
+/* read pathnames from HDROP or SHELLIDLIST.
+ The parser can return E_INVALIDARG, if there is some unexpected data in dataObject */
+HRESULT DataObject_GetData_HDROP_or_IDLIST_Names(IDataObject *dataObject, UStringVector &names);
+
+HRESULT DataObject_GetData_FILE_ATTRS(IDataObject *dataObject, CFileAttribs &attribs);
+
+bool GetPathFromIDList(LPCITEMIDLIST itemIDList, CSysString &path);
+bool BrowseForFolder(LPBROWSEINFO lpbi, CSysString &resultPath);
+bool BrowseForFolder(HWND owner, LPCTSTR title, LPCTSTR initialFolder, CSysString &resultPath);
+
+#ifndef _UNICODE
+bool GetPathFromIDList(LPCITEMIDLIST itemIDList, UString &path);
+bool BrowseForFolder(LPBROWSEINFO lpbi, UString &resultPath);
+bool BrowseForFolder(HWND owner, LPCWSTR title, LPCWSTR initialFolder, UString &resultPath);
+#endif
+}}
+
+#endif
diff --git a/CPP/Windows/StdAfx.h b/CPP/Windows/StdAfx.h
index 47a4895..bd5084f 100644
--- a/CPP/Windows/StdAfx.h
+++ b/CPP/Windows/StdAfx.h
@@ -1,8 +1,12 @@
-// StdAfx.h
-
-#ifndef __STDAFX_H
-#define __STDAFX_H
-
-#include "../Common/Common.h"
-
-#endif
+// StdAfx.h
+
+#ifndef ZIP7_INC_STDAFX_H
+#define ZIP7_INC_STDAFX_H
+
+#if defined(_MSC_VER) && _MSC_VER >= 1800
+#pragma warning(disable : 4464) // relative include path contains '..'
+#endif
+
+#include "../Common/Common.h"
+
+#endif
diff --git a/CPP/Windows/Synchronization.cpp b/CPP/Windows/Synchronization.cpp
index 01f1ad9..d5542af 100644
--- a/CPP/Windows/Synchronization.cpp
+++ b/CPP/Windows/Synchronization.cpp
@@ -1,10 +1,87 @@
-// Windows/Synchronization.cpp
-
-#include "StdAfx.h"
-
-#include "Synchronization.h"
-
-namespace NWindows {
-namespace NSynchronization {
-
-}}
+// Windows/Synchronization.cpp
+
+#include "StdAfx.h"
+
+#ifndef _WIN32
+
+#include "Synchronization.h"
+
+namespace NWindows {
+namespace NSynchronization {
+
+/*
+#define INFINITE 0xFFFFFFFF
+#define MAXIMUM_WAIT_OBJECTS 64
+#define STATUS_ABANDONED_WAIT_0 ((NTSTATUS)0x00000080L)
+#define WAIT_ABANDONED ((STATUS_ABANDONED_WAIT_0 ) + 0 )
+#define WAIT_ABANDONED_0 ((STATUS_ABANDONED_WAIT_0 ) + 0 )
+// WINAPI
+DWORD WaitForMultipleObjects(DWORD count, const HANDLE *handles, BOOL wait_all, DWORD timeout);
+*/
+
+/* clang: we need to place some virtual functions in cpp file to rid off the warning:
+ 'CBaseHandle_WFMO' has no out-of-line virtual method definitions;
+ its vtable will be emitted in every translation unit */
+CBaseHandle_WFMO::~CBaseHandle_WFMO()
+{
+}
+
+bool CBaseEvent_WFMO::IsSignaledAndUpdate()
+{
+ if (this->_state == false)
+ return false;
+ if (this->_manual_reset == false)
+ this->_state = false;
+ return true;
+}
+
+bool CSemaphore_WFMO::IsSignaledAndUpdate()
+{
+ if (this->_count == 0)
+ return false;
+ this->_count--;
+ return true;
+}
+
+DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles)
+{
+ if (count < 1)
+ {
+ // abort();
+ SetLastError(EINVAL);
+ return WAIT_FAILED;
+ }
+
+ CSynchro *synchro = handles[0]->_sync;
+ synchro->Enter();
+
+ // #ifdef DEBUG_SYNCHRO
+ for (DWORD i = 1; i < count; i++)
+ {
+ if (synchro != handles[i]->_sync)
+ {
+ // abort();
+ synchro->Leave();
+ SetLastError(EINVAL);
+ return WAIT_FAILED;
+ }
+ }
+ // #endif
+
+ for (;;)
+ {
+ for (DWORD i = 0; i < count; i++)
+ {
+ if (handles[i]->IsSignaledAndUpdate())
+ {
+ synchro->Leave();
+ return WAIT_OBJECT_0 + i;
+ }
+ }
+ synchro->WaitCond();
+ }
+}
+
+}}
+
+#endif
diff --git a/CPP/Windows/Synchronization.h b/CPP/Windows/Synchronization.h
index 786da00..afd03d2 100644
--- a/CPP/Windows/Synchronization.h
+++ b/CPP/Windows/Synchronization.h
@@ -1,164 +1,381 @@
-// Windows/Synchronization.h
-
-#ifndef __WINDOWS_SYNCHRONIZATION_H
-#define __WINDOWS_SYNCHRONIZATION_H
-
-#include "../../C/Threads.h"
-
-#include "Defs.h"
-
-#ifdef _WIN32
-#include "Handle.h"
-#endif
-
-namespace NWindows {
-namespace NSynchronization {
-
-class CBaseEvent
-{
-protected:
- ::CEvent _object;
-public:
- bool IsCreated() { return Event_IsCreated(&_object) != 0; }
- operator HANDLE() { return _object; }
- CBaseEvent() { Event_Construct(&_object); }
- ~CBaseEvent() { Close(); }
- WRes Close() { return Event_Close(&_object); }
- #ifdef _WIN32
- WRes Create(bool manualReset, bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL)
- {
- _object = ::CreateEvent(sa, BoolToBOOL(manualReset), BoolToBOOL(initiallyOwn), name);
- if (name == NULL && _object != 0)
- return 0;
- return ::GetLastError();
- }
- WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name)
- {
- _object = ::OpenEvent(desiredAccess, BoolToBOOL(inheritHandle), name);
- if (_object != 0)
- return 0;
- return ::GetLastError();
- }
- #endif
-
- WRes Set() { return Event_Set(&_object); }
- // bool Pulse() { return BOOLToBool(::PulseEvent(_handle)); }
- WRes Reset() { return Event_Reset(&_object); }
- WRes Lock() { return Event_Wait(&_object); }
-};
-
-class CManualResetEvent: public CBaseEvent
-{
-public:
- WRes Create(bool initiallyOwn = false)
- {
- return ManualResetEvent_Create(&_object, initiallyOwn ? 1: 0);
- }
- WRes CreateIfNotCreated()
- {
- if (IsCreated())
- return 0;
- return ManualResetEvent_CreateNotSignaled(&_object);
- }
- #ifdef _WIN32
- WRes CreateWithName(bool initiallyOwn, LPCTSTR name)
- {
- return CBaseEvent::Create(true, initiallyOwn, name);
- }
- #endif
-};
-
-class CAutoResetEvent: public CBaseEvent
-{
-public:
- WRes Create()
- {
- return AutoResetEvent_CreateNotSignaled(&_object);
- }
- WRes CreateIfNotCreated()
- {
- if (IsCreated())
- return 0;
- return AutoResetEvent_CreateNotSignaled(&_object);
- }
-};
-
-#ifdef _WIN32
-class CObject: public CHandle
-{
-public:
- WRes Lock(DWORD timeoutInterval = INFINITE)
- { return (::WaitForSingleObject(_handle, timeoutInterval) == WAIT_OBJECT_0 ? 0 : ::GetLastError()); }
-};
-class CMutex: public CObject
-{
-public:
- WRes Create(bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL)
- {
- _handle = ::CreateMutex(sa, BoolToBOOL(initiallyOwn), name);
- if (name == NULL && _handle != 0)
- return 0;
- return ::GetLastError();
- }
- #ifndef UNDER_CE
- WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name)
- {
- _handle = ::OpenMutex(desiredAccess, BoolToBOOL(inheritHandle), name);
- if (_handle != 0)
- return 0;
- return ::GetLastError();
- }
- #endif
- WRes Release()
- {
- return ::ReleaseMutex(_handle) ? 0 : ::GetLastError();
- }
-};
-class CMutexLock
-{
- CMutex *_object;
-public:
- CMutexLock(CMutex &object): _object(&object) { _object->Lock(); }
- ~CMutexLock() { _object->Release(); }
-};
-#endif
-
-class CSemaphore
-{
- ::CSemaphore _object;
-public:
- CSemaphore() { Semaphore_Construct(&_object); }
- ~CSemaphore() { Close(); }
- WRes Close() { return Semaphore_Close(&_object); }
- operator HANDLE() { return _object; }
- WRes Create(UInt32 initiallyCount, UInt32 maxCount)
- {
- return Semaphore_Create(&_object, initiallyCount, maxCount);
- }
- WRes Release() { return Semaphore_Release1(&_object); }
- WRes Release(UInt32 releaseCount) { return Semaphore_ReleaseN(&_object, releaseCount); }
- WRes Lock() { return Semaphore_Wait(&_object); }
-};
-
-class CCriticalSection
-{
- ::CCriticalSection _object;
-public:
- CCriticalSection() { CriticalSection_Init(&_object); }
- ~CCriticalSection() { CriticalSection_Delete(&_object); }
- void Enter() { CriticalSection_Enter(&_object); }
- void Leave() { CriticalSection_Leave(&_object); }
-};
-
-class CCriticalSectionLock
-{
- CCriticalSection *_object;
- void Unlock() { _object->Leave(); }
-public:
- CCriticalSectionLock(CCriticalSection &object): _object(&object) {_object->Enter(); }
- ~CCriticalSectionLock() { Unlock(); }
-};
-
-}}
-
-#endif
+// Windows/Synchronization.h
+
+#ifndef ZIP7_INC_WINDOWS_SYNCHRONIZATION_H
+#define ZIP7_INC_WINDOWS_SYNCHRONIZATION_H
+
+#include "../../C/Threads.h"
+
+#include "../Common/MyTypes.h"
+
+#include "Defs.h"
+
+#ifdef _WIN32
+#include "Handle.h"
+#endif
+
+namespace NWindows {
+namespace NSynchronization {
+
+class CBaseEvent MY_UNCOPYABLE
+{
+protected:
+ ::CEvent _object;
+public:
+ bool IsCreated() { return Event_IsCreated(&_object) != 0; }
+
+ CBaseEvent() { Event_Construct(&_object); }
+ ~CBaseEvent() { Close(); }
+ WRes Close() { return Event_Close(&_object); }
+
+ #ifdef _WIN32
+ operator HANDLE() { return _object; }
+ WRes Create(bool manualReset, bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL)
+ {
+ _object = ::CreateEvent(sa, BoolToBOOL(manualReset), BoolToBOOL(initiallyOwn), name);
+ if (name == NULL && _object != NULL)
+ return 0;
+ return ::GetLastError();
+ }
+ WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name)
+ {
+ _object = ::OpenEvent(desiredAccess, BoolToBOOL(inheritHandle), name);
+ if (_object != NULL)
+ return 0;
+ return ::GetLastError();
+ }
+ #endif
+
+ WRes Set() { return Event_Set(&_object); }
+ // bool Pulse() { return BOOLToBool(::PulseEvent(_handle)); }
+ WRes Reset() { return Event_Reset(&_object); }
+ WRes Lock() { return Event_Wait(&_object); }
+};
+
+class CManualResetEvent: public CBaseEvent
+{
+public:
+ WRes Create(bool initiallyOwn = false)
+ {
+ return ManualResetEvent_Create(&_object, initiallyOwn ? 1: 0);
+ }
+ WRes CreateIfNotCreated_Reset()
+ {
+ if (IsCreated())
+ return Reset();
+ return ManualResetEvent_CreateNotSignaled(&_object);
+ }
+ #ifdef _WIN32
+ WRes CreateWithName(bool initiallyOwn, LPCTSTR name)
+ {
+ return CBaseEvent::Create(true, initiallyOwn, name);
+ }
+ #endif
+};
+
+class CAutoResetEvent: public CBaseEvent
+{
+public:
+ WRes Create()
+ {
+ return AutoResetEvent_CreateNotSignaled(&_object);
+ }
+ WRes CreateIfNotCreated_Reset()
+ {
+ if (IsCreated())
+ return Reset();
+ return AutoResetEvent_CreateNotSignaled(&_object);
+ }
+};
+
+
+/*
+#ifdef _WIN32
+
+class CObject: public CHandle
+{
+public:
+ WRes Lock(DWORD timeoutInterval = INFINITE)
+ { return (::WaitForSingleObject(_handle, timeoutInterval) == WAIT_OBJECT_0 ? 0 : ::GetLastError()); }
+};
+
+class CMutex: public CObject
+{
+public:
+ WRes Create(bool initiallyOwn, LPCTSTR name = NULL, LPSECURITY_ATTRIBUTES sa = NULL)
+ {
+ _handle = ::CreateMutex(sa, BoolToBOOL(initiallyOwn), name);
+ if (name == NULL && _handle != 0)
+ return 0;
+ return ::GetLastError();
+ }
+ #ifndef UNDER_CE
+ WRes Open(DWORD desiredAccess, bool inheritHandle, LPCTSTR name)
+ {
+ _handle = ::OpenMutex(desiredAccess, BoolToBOOL(inheritHandle), name);
+ if (_handle != 0)
+ return 0;
+ return ::GetLastError();
+ }
+ #endif
+ WRes Release()
+ {
+ return ::ReleaseMutex(_handle) ? 0 : ::GetLastError();
+ }
+};
+
+class CMutexLock MY_UNCOPYABLE
+{
+ CMutex *_object;
+public:
+ CMutexLock(CMutex &object): _object(&object) { _object->Lock(); }
+ ~CMutexLock() { _object->Release(); }
+};
+
+#endif // _WIN32
+*/
+
+
+class CSemaphore MY_UNCOPYABLE
+{
+ ::CSemaphore _object;
+public:
+ CSemaphore() { Semaphore_Construct(&_object); }
+ ~CSemaphore() { Close(); }
+ WRes Close() { return Semaphore_Close(&_object); }
+
+ #ifdef _WIN32
+ operator HANDLE() { return _object; }
+ #endif
+
+ // bool IsCreated() const { return Semaphore_IsCreated(&_object) != 0; }
+
+ WRes Create(UInt32 initCount, UInt32 maxCount)
+ {
+ return Semaphore_Create(&_object, initCount, maxCount);
+ }
+ WRes OptCreateInit(UInt32 initCount, UInt32 maxCount)
+ {
+ return Semaphore_OptCreateInit(&_object, initCount, maxCount);
+ }
+ WRes Release() { return Semaphore_Release1(&_object); }
+ WRes Release(UInt32 releaseCount) { return Semaphore_ReleaseN(&_object, releaseCount); }
+ WRes Lock() { return Semaphore_Wait(&_object); }
+};
+
+class CCriticalSection MY_UNCOPYABLE
+{
+ ::CCriticalSection _object;
+public:
+ CCriticalSection() { CriticalSection_Init(&_object); }
+ ~CCriticalSection() { CriticalSection_Delete(&_object); }
+ void Enter() { CriticalSection_Enter(&_object); }
+ void Leave() { CriticalSection_Leave(&_object); }
+};
+
+class CCriticalSectionLock MY_UNCOPYABLE
+{
+ CCriticalSection *_object;
+ void Unlock() { _object->Leave(); }
+public:
+ CCriticalSectionLock(CCriticalSection &object): _object(&object) {_object->Enter(); }
+ ~CCriticalSectionLock() { Unlock(); }
+};
+
+
+#ifdef _WIN32
+
+typedef HANDLE CHandle_WFMO;
+typedef CSemaphore CSemaphore_WFMO;
+typedef CAutoResetEvent CAutoResetEvent_WFMO;
+typedef CManualResetEvent CManualResetEvent_WFMO;
+
+inline DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles)
+{
+ return ::WaitForMultipleObjects(count, handles, FALSE, INFINITE);
+}
+
+#define SYNC_OBJ_DECL(obj)
+#define SYNC_WFMO(x)
+#define SYNC_PARAM(x)
+#define SYNC_PARAM_DECL(x)
+
+#else // _WIN32
+
+// POSIX sync objects for WaitForMultipleObjects
+
+#define SYNC_WFMO(x) x
+#define SYNC_PARAM(x) x,
+#define SYNC_PARAM_DECL(x) NWindows::NSynchronization::CSynchro *x
+#define SYNC_OBJ_DECL(x) NWindows::NSynchronization::CSynchro x;
+
+class CSynchro MY_UNCOPYABLE
+{
+ pthread_mutex_t _mutex;
+ pthread_cond_t _cond;
+ bool _isValid;
+
+public:
+ CSynchro() { _isValid = false; }
+ ~CSynchro()
+ {
+ if (_isValid)
+ {
+ ::pthread_mutex_destroy(&_mutex);
+ ::pthread_cond_destroy(&_cond);
+ }
+ _isValid = false;
+ }
+ WRes Create()
+ {
+ RINOK(::pthread_mutex_init(&_mutex, NULL))
+ const WRes ret = ::pthread_cond_init(&_cond, NULL);
+ _isValid = 1;
+ return ret;
+ }
+ WRes Enter()
+ {
+ return ::pthread_mutex_lock(&_mutex);
+ }
+ WRes Leave()
+ {
+ return ::pthread_mutex_unlock(&_mutex);
+ }
+ WRes WaitCond()
+ {
+ return ::pthread_cond_wait(&_cond, &_mutex);
+ }
+ WRes LeaveAndSignal()
+ {
+ const WRes res1 = ::pthread_cond_broadcast(&_cond);
+ const WRes res2 = ::pthread_mutex_unlock(&_mutex);
+ return (res2 ? res2 : res1);
+ }
+};
+
+
+struct CBaseHandle_WFMO;
+typedef NWindows::NSynchronization::CBaseHandle_WFMO *CHandle_WFMO;
+
+// these constants are from Windows
+#define WAIT_OBJECT_0 0
+#define WAIT_FAILED ((DWORD)0xFFFFFFFF)
+
+DWORD WINAPI WaitForMultiObj_Any_Infinite(DWORD count, const CHandle_WFMO *handles);
+
+
+struct CBaseHandle_WFMO MY_UNCOPYABLE
+{
+ CSynchro *_sync;
+
+ CBaseHandle_WFMO(): _sync(NULL) {}
+ virtual ~CBaseHandle_WFMO();
+
+ operator CHandle_WFMO() { return this; }
+ virtual bool IsSignaledAndUpdate() = 0;
+};
+
+
+class CBaseEvent_WFMO : public CBaseHandle_WFMO
+{
+ bool _manual_reset;
+ bool _state;
+
+public:
+
+ // bool IsCreated() { return (this->_sync != NULL); }
+ // CBaseEvent_WFMO() { ; }
+ // ~CBaseEvent_WFMO() Z7_override { Close(); }
+
+ WRes Close() { this->_sync = NULL; return 0; }
+
+ WRes Create(
+ CSynchro *sync,
+ bool manualReset, bool initiallyOwn)
+ {
+ this->_sync = sync;
+ this->_manual_reset = manualReset;
+ this->_state = initiallyOwn;
+ return 0;
+ }
+
+ WRes Set()
+ {
+ RINOK(this->_sync->Enter())
+ this->_state = true;
+ return this->_sync->LeaveAndSignal();
+ }
+
+ WRes Reset()
+ {
+ RINOK(this->_sync->Enter())
+ this->_state = false;
+ return this->_sync->Leave();
+ }
+
+ virtual bool IsSignaledAndUpdate() Z7_override;
+};
+
+
+class CManualResetEvent_WFMO Z7_final: public CBaseEvent_WFMO
+{
+public:
+ WRes Create(CSynchro *sync, bool initiallyOwn = false) { return CBaseEvent_WFMO::Create(sync, true, initiallyOwn); }
+};
+
+
+class CAutoResetEvent_WFMO Z7_final: public CBaseEvent_WFMO
+{
+public:
+ WRes Create(CSynchro *sync) { return CBaseEvent_WFMO::Create(sync, false, false); }
+ WRes CreateIfNotCreated_Reset(CSynchro *sync)
+ {
+ return Create(sync);
+ }
+};
+
+
+class CSemaphore_WFMO Z7_final: public CBaseHandle_WFMO
+{
+ UInt32 _count;
+ UInt32 _maxCount;
+
+public:
+ CSemaphore_WFMO() : _count(0), _maxCount(0) {}
+
+ WRes Close() { this->_sync = NULL; return 0; }
+
+ WRes Create(CSynchro *sync, UInt32 initCount, UInt32 maxCount)
+ {
+ if (initCount > maxCount || maxCount < 1)
+ return EINVAL;
+ this->_sync = sync;
+ this->_count = initCount;
+ this->_maxCount = maxCount;
+ return 0;
+ }
+
+ WRes Release(UInt32 releaseCount = 1)
+ {
+ if (releaseCount < 1)
+ return EINVAL;
+
+ RINOK(this->_sync->Enter())
+ UInt32 newCount = this->_count + releaseCount;
+ if (newCount > this->_maxCount)
+ {
+ RINOK(this->_sync->Leave())
+ return ERROR_TOO_MANY_POSTS; // EINVAL
+ }
+ this->_count = newCount;
+
+ return this->_sync->LeaveAndSignal();
+ }
+
+ virtual bool IsSignaledAndUpdate() Z7_override;
+};
+
+#endif // _WIN32
+
+}}
+
+#endif
diff --git a/CPP/Windows/System.cpp b/CPP/Windows/System.cpp
index c6f8275..dbe287a 100644
--- a/CPP/Windows/System.cpp
+++ b/CPP/Windows/System.cpp
@@ -1,142 +1,278 @@
-// Windows/System.cpp
-
-#include "StdAfx.h"
-
-#include "../Common/MyWindows.h"
-
-#include "../Common/Defs.h"
-
-#include "System.h"
-
-namespace NWindows {
-namespace NSystem {
-
-UInt32 CountAffinity(DWORD_PTR mask)
-{
- UInt32 num = 0;
- for (unsigned i = 0; i < sizeof(mask) * 8; i++)
- num += (UInt32)((mask >> i) & 1);
- return num;
-}
-
-#ifdef _WIN32
-
-BOOL CProcessAffinity::Get()
-{
- #ifndef UNDER_CE
- return GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask);
- #else
- return FALSE;
- #endif
-}
-
-
-UInt32 GetNumberOfProcessors()
-{
- // We need to know how many threads we can use.
- // By default the process is assigned to one group.
- // So we get the number of logical processors (threads)
- // assigned to current process in the current group.
- // Group size can be smaller than total number logical processors, for exammple, 2x36
-
- CProcessAffinity pa;
-
- if (pa.Get() && pa.processAffinityMask != 0)
- return pa.GetNumProcessThreads();
-
- SYSTEM_INFO systemInfo;
- GetSystemInfo(&systemInfo);
- // the number of logical processors in the current group
- return (UInt32)systemInfo.dwNumberOfProcessors;
-}
-
-#else
-
-UInt32 GetNumberOfProcessors()
-{
- return 1;
-}
-
-#endif
-
-
-#ifdef _WIN32
-
-#ifndef UNDER_CE
-
-#if !defined(_WIN64) && defined(__GNUC__)
-
-typedef struct _MY_MEMORYSTATUSEX {
- DWORD dwLength;
- DWORD dwMemoryLoad;
- DWORDLONG ullTotalPhys;
- DWORDLONG ullAvailPhys;
- DWORDLONG ullTotalPageFile;
- DWORDLONG ullAvailPageFile;
- DWORDLONG ullTotalVirtual;
- DWORDLONG ullAvailVirtual;
- DWORDLONG ullAvailExtendedVirtual;
-} MY_MEMORYSTATUSEX, *MY_LPMEMORYSTATUSEX;
-
-#else
-
-#define MY_MEMORYSTATUSEX MEMORYSTATUSEX
-#define MY_LPMEMORYSTATUSEX LPMEMORYSTATUSEX
-
-#endif
-
-typedef BOOL (WINAPI *GlobalMemoryStatusExP)(MY_LPMEMORYSTATUSEX lpBuffer);
-
-#endif
-
-#endif
-
-
-bool GetRamSize(UInt64 &size)
-{
- size = (UInt64)(sizeof(size_t)) << 29;
-
- #ifdef _WIN32
-
- #ifndef UNDER_CE
- MY_MEMORYSTATUSEX stat;
- stat.dwLength = sizeof(stat);
- #endif
-
- #ifdef _WIN64
-
- if (!::GlobalMemoryStatusEx(&stat))
- return false;
- size = MyMin(stat.ullTotalVirtual, stat.ullTotalPhys);
- return true;
-
- #else
-
- #ifndef UNDER_CE
- GlobalMemoryStatusExP globalMemoryStatusEx = (GlobalMemoryStatusExP)
- ::GetProcAddress(::GetModuleHandle(TEXT("kernel32.dll")), "GlobalMemoryStatusEx");
- if (globalMemoryStatusEx && globalMemoryStatusEx(&stat))
- {
- size = MyMin(stat.ullTotalVirtual, stat.ullTotalPhys);
- return true;
- }
- #endif
-
- {
- MEMORYSTATUS stat2;
- stat2.dwLength = sizeof(stat2);
- ::GlobalMemoryStatus(&stat2);
- size = MyMin(stat2.dwTotalVirtual, stat2.dwTotalPhys);
- return true;
- }
-
- #endif
-
- #else
-
- return false;
-
- #endif
-}
-
-}}
+// Windows/System.cpp
+
+#include "StdAfx.h"
+
+#ifndef _WIN32
+#include <unistd.h>
+#include <limits.h>
+#ifdef __APPLE__
+#include <sys/sysctl.h>
+#else
+#include <sys/sysinfo.h>
+#endif
+#endif
+
+#include "../Common/Defs.h"
+// #include "../Common/MyWindows.h"
+
+// #include "../../C/CpuArch.h"
+
+#include "System.h"
+
+namespace NWindows {
+namespace NSystem {
+
+#ifdef _WIN32
+
+UInt32 CountAffinity(DWORD_PTR mask)
+{
+ UInt32 num = 0;
+ for (unsigned i = 0; i < sizeof(mask) * 8; i++)
+ num += (UInt32)((mask >> i) & 1);
+ return num;
+}
+
+BOOL CProcessAffinity::Get()
+{
+ #ifndef UNDER_CE
+ return GetProcessAffinityMask(GetCurrentProcess(), &processAffinityMask, &systemAffinityMask);
+ #else
+ return FALSE;
+ #endif
+}
+
+
+UInt32 GetNumberOfProcessors()
+{
+ // We need to know how many threads we can use.
+ // By default the process is assigned to one group.
+ // So we get the number of logical processors (threads)
+ // assigned to current process in the current group.
+ // Group size can be smaller than total number logical processors, for exammple, 2x36
+
+ CProcessAffinity pa;
+
+ if (pa.Get() && pa.processAffinityMask != 0)
+ return pa.GetNumProcessThreads();
+
+ SYSTEM_INFO systemInfo;
+ GetSystemInfo(&systemInfo);
+ // the number of logical processors in the current group
+ return (UInt32)systemInfo.dwNumberOfProcessors;
+}
+
+#else
+
+
+BOOL CProcessAffinity::Get()
+{
+ numSysThreads = GetNumberOfProcessors();
+
+ /*
+ numSysThreads = 8;
+ for (unsigned i = 0; i < numSysThreads; i++)
+ CpuSet_Set(&cpu_set, i);
+ return TRUE;
+ */
+
+ #ifdef Z7_AFFINITY_SUPPORTED
+
+ // numSysThreads = sysconf(_SC_NPROCESSORS_ONLN); // The number of processors currently online
+ if (sched_getaffinity(0, sizeof(cpu_set), &cpu_set) != 0)
+ return FALSE;
+ return TRUE;
+
+ #else
+
+ // cpu_set = ((CCpuSet)1 << (numSysThreads)) - 1;
+ return TRUE;
+ // errno = ENOSYS;
+ // return FALSE;
+
+ #endif
+}
+
+UInt32 GetNumberOfProcessors()
+{
+ #ifndef Z7_ST
+ long n = sysconf(_SC_NPROCESSORS_CONF); // The number of processors configured
+ if (n < 1)
+ n = 1;
+ return (UInt32)n;
+ #else
+ return 1;
+ #endif
+}
+
+#endif
+
+
+#ifdef _WIN32
+
+#ifndef UNDER_CE
+
+#if !defined(_WIN64) && \
+ (defined(__MINGW32_VERSION) || defined(Z7_OLD_WIN_SDK))
+
+typedef struct _MY_MEMORYSTATUSEX {
+ DWORD dwLength;
+ DWORD dwMemoryLoad;
+ DWORDLONG ullTotalPhys;
+ DWORDLONG ullAvailPhys;
+ DWORDLONG ullTotalPageFile;
+ DWORDLONG ullAvailPageFile;
+ DWORDLONG ullTotalVirtual;
+ DWORDLONG ullAvailVirtual;
+ DWORDLONG ullAvailExtendedVirtual;
+} MY_MEMORYSTATUSEX, *MY_LPMEMORYSTATUSEX;
+
+#else
+
+#define MY_MEMORYSTATUSEX MEMORYSTATUSEX
+#define MY_LPMEMORYSTATUSEX LPMEMORYSTATUSEX
+
+#endif
+
+typedef BOOL (WINAPI *Func_GlobalMemoryStatusEx)(MY_LPMEMORYSTATUSEX lpBuffer);
+
+#endif // !UNDER_CE
+
+
+bool GetRamSize(UInt64 &size)
+{
+ size = (UInt64)(sizeof(size_t)) << 29;
+
+ #ifndef UNDER_CE
+ MY_MEMORYSTATUSEX stat;
+ stat.dwLength = sizeof(stat);
+ #endif
+
+ #ifdef _WIN64
+
+ if (!::GlobalMemoryStatusEx(&stat))
+ return false;
+ size = MyMin(stat.ullTotalVirtual, stat.ullTotalPhys);
+ return true;
+
+ #else
+
+ #ifndef UNDER_CE
+ const
+ Func_GlobalMemoryStatusEx fn = Z7_GET_PROC_ADDRESS(
+ Func_GlobalMemoryStatusEx, ::GetModuleHandleA("kernel32.dll"),
+ "GlobalMemoryStatusEx");
+ if (fn && fn(&stat))
+ {
+ size = MyMin(stat.ullTotalVirtual, stat.ullTotalPhys);
+ return true;
+ }
+ #endif
+
+ {
+ MEMORYSTATUS stat2;
+ stat2.dwLength = sizeof(stat2);
+ ::GlobalMemoryStatus(&stat2);
+ size = MyMin(stat2.dwTotalVirtual, stat2.dwTotalPhys);
+ return true;
+ }
+ #endif
+}
+
+#else
+
+// POSIX
+// #include <stdio.h>
+
+bool GetRamSize(UInt64 &size)
+{
+ size = (UInt64)(sizeof(size_t)) << 29;
+
+ #ifdef __APPLE__
+
+ #ifdef HW_MEMSIZE
+ uint64_t val = 0; // support 2Gb+ RAM
+ int mib[2] = { CTL_HW, HW_MEMSIZE };
+ #elif defined(HW_PHYSMEM64)
+ uint64_t val = 0; // support 2Gb+ RAM
+ int mib[2] = { CTL_HW, HW_PHYSMEM64 };
+ #else
+ unsigned int val = 0; // For old system
+ int mib[2] = { CTL_HW, HW_PHYSMEM };
+ #endif // HW_MEMSIZE
+ size_t size_sys = sizeof(val);
+
+ sysctl(mib, 2, &val, &size_sys, NULL, 0);
+ if (val)
+ size = val;
+
+ #elif defined(_AIX)
+ // fixme
+ #elif defined(__gnu_hurd__)
+ // fixme
+ #elif defined(__FreeBSD_kernel__) && defined(__GLIBC__)
+ // GNU/kFreeBSD Debian
+ // fixme
+ #else
+
+ struct sysinfo info;
+ if (::sysinfo(&info) != 0)
+ return false;
+ size = (UInt64)info.mem_unit * info.totalram;
+ const UInt64 kLimit = (UInt64)1 << (sizeof(size_t) * 8 - 1);
+ if (size > kLimit)
+ size = kLimit;
+
+ /*
+ printf("\n mem_unit = %lld", (UInt64)info.mem_unit);
+ printf("\n totalram = %lld", (UInt64)info.totalram);
+ printf("\n freeram = %lld", (UInt64)info.freeram);
+ */
+
+ #endif
+
+ return true;
+}
+
+#endif
+
+
+unsigned long Get_File_OPEN_MAX()
+{
+ #ifdef _WIN32
+ return (1 << 24) - (1 << 16); // ~16M handles
+ #else
+ // some linux versions have default open file limit for user process of 1024 files.
+ long n = sysconf(_SC_OPEN_MAX);
+ // n = -1; // for debug
+ // n = 9; // for debug
+ if (n < 1)
+ {
+ // n = OPEN_MAX; // ???
+ // n = FOPEN_MAX; // = 16 : <stdio.h>
+ #ifdef _POSIX_OPEN_MAX
+ n = _POSIX_OPEN_MAX; // = 20 : <limits.h>
+ #else
+ n = 30; // our limit
+ #endif
+ }
+ return (unsigned long)n;
+ #endif
+}
+
+unsigned Get_File_OPEN_MAX_Reduced_for_3_tasks()
+{
+ unsigned long numFiles_OPEN_MAX = NSystem::Get_File_OPEN_MAX();
+ const unsigned delta = 10; // the reserve for another internal needs of process
+ if (numFiles_OPEN_MAX > delta)
+ numFiles_OPEN_MAX -= delta;
+ else
+ numFiles_OPEN_MAX = 1;
+ numFiles_OPEN_MAX /= 3; // we suppose that we have up to 3 tasks in total for multiple file processing
+ numFiles_OPEN_MAX = MyMax(numFiles_OPEN_MAX, (unsigned long)3);
+ unsigned n = (UInt32)(UInt32)-1;
+ if (n > numFiles_OPEN_MAX)
+ n = (unsigned)numFiles_OPEN_MAX;
+ return n;
+}
+
+}}
diff --git a/CPP/Windows/System.h b/CPP/Windows/System.h
index bc28f47..0650007 100644
--- a/CPP/Windows/System.h
+++ b/CPP/Windows/System.h
@@ -1,40 +1,132 @@
-// Windows/System.h
-
-#ifndef __WINDOWS_SYSTEM_H
-#define __WINDOWS_SYSTEM_H
-
-#include "../Common/MyTypes.h"
-
-namespace NWindows {
-namespace NSystem {
-
-UInt32 CountAffinity(DWORD_PTR mask);
-
-struct CProcessAffinity
-{
- // UInt32 numProcessThreads;
- // UInt32 numSysThreads;
- DWORD_PTR processAffinityMask;
- DWORD_PTR systemAffinityMask;
-
- void InitST()
- {
- // numProcessThreads = 1;
- // numSysThreads = 1;
- processAffinityMask = 1;
- systemAffinityMask = 1;
- }
-
- UInt32 GetNumProcessThreads() const { return CountAffinity(processAffinityMask); }
- UInt32 GetNumSystemThreads() const { return CountAffinity(systemAffinityMask); }
-
- BOOL Get();
-};
-
-UInt32 GetNumberOfProcessors();
-
-bool GetRamSize(UInt64 &size); // returns false, if unknown ram size
-
-}}
-
-#endif
+// Windows/System.h
+
+#ifndef ZIP7_INC_WINDOWS_SYSTEM_H
+#define ZIP7_INC_WINDOWS_SYSTEM_H
+
+#ifndef _WIN32
+// #include <sched.h>
+#include "../../C/Threads.h"
+#endif
+
+#include "../Common/MyTypes.h"
+#include "../Common/MyWindows.h"
+
+namespace NWindows {
+namespace NSystem {
+
+#ifdef _WIN32
+
+UInt32 CountAffinity(DWORD_PTR mask);
+
+struct CProcessAffinity
+{
+ // UInt32 numProcessThreads;
+ // UInt32 numSysThreads;
+ DWORD_PTR processAffinityMask;
+ DWORD_PTR systemAffinityMask;
+
+ void InitST()
+ {
+ // numProcessThreads = 1;
+ // numSysThreads = 1;
+ processAffinityMask = 1;
+ systemAffinityMask = 1;
+ }
+
+ void CpuZero()
+ {
+ processAffinityMask = 0;
+ }
+
+ void CpuSet(unsigned cpuIndex)
+ {
+ processAffinityMask |= ((DWORD_PTR)1 << cpuIndex);
+ }
+
+ UInt32 GetNumProcessThreads() const { return CountAffinity(processAffinityMask); }
+ UInt32 GetNumSystemThreads() const { return CountAffinity(systemAffinityMask); }
+
+ BOOL Get();
+
+ BOOL SetProcAffinity() const
+ {
+ return SetProcessAffinityMask(GetCurrentProcess(), processAffinityMask);
+ }
+};
+
+
+#else // WIN32
+
+struct CProcessAffinity
+{
+ UInt32 numSysThreads;
+
+ UInt32 GetNumSystemThreads() const { return (UInt32)numSysThreads; }
+ BOOL Get();
+
+ #ifdef Z7_AFFINITY_SUPPORTED
+
+ CCpuSet cpu_set;
+
+ void InitST()
+ {
+ numSysThreads = 1;
+ CpuSet_Zero(&cpu_set);
+ CpuSet_Set(&cpu_set, 0);
+ }
+
+ UInt32 GetNumProcessThreads() const { return (UInt32)CPU_COUNT(&cpu_set); }
+ void CpuZero() { CpuSet_Zero(&cpu_set); }
+ void CpuSet(unsigned cpuIndex) { CpuSet_Set(&cpu_set, cpuIndex); }
+ int IsCpuSet(unsigned cpuIndex) const { return CpuSet_IsSet(&cpu_set, cpuIndex); }
+ // void CpuClr(int cpuIndex) { CPU_CLR(cpuIndex, &cpu_set); }
+
+ BOOL SetProcAffinity() const
+ {
+ return sched_setaffinity(0, sizeof(cpu_set), &cpu_set) == 0;
+ }
+
+ #else // Z7_AFFINITY_SUPPORTED
+
+ void InitST()
+ {
+ numSysThreads = 1;
+ }
+
+ UInt32 GetNumProcessThreads() const
+ {
+ return numSysThreads;
+ /*
+ UInt32 num = 0;
+ for (unsigned i = 0; i < sizeof(cpu_set) * 8; i++)
+ num += (UInt32)((cpu_set >> i) & 1);
+ return num;
+ */
+ }
+
+ void CpuZero() { }
+ void CpuSet(unsigned cpuIndex) { UNUSED_VAR(cpuIndex); }
+ int IsCpuSet(unsigned cpuIndex) const { return (cpuIndex < numSysThreads) ? 1 : 0; }
+
+ BOOL SetProcAffinity() const
+ {
+ errno = ENOSYS;
+ return FALSE;
+ }
+
+ #endif // Z7_AFFINITY_SUPPORTED
+};
+
+#endif // _WIN32
+
+
+UInt32 GetNumberOfProcessors();
+
+bool GetRamSize(UInt64 &size); // returns false, if unknown ram size
+
+unsigned long Get_File_OPEN_MAX();
+unsigned Get_File_OPEN_MAX_Reduced_for_3_tasks();
+
+}}
+
+#endif
diff --git a/CPP/Windows/SystemInfo.cpp b/CPP/Windows/SystemInfo.cpp
new file mode 100644
index 0000000..6bafc80
--- /dev/null
+++ b/CPP/Windows/SystemInfo.cpp
@@ -0,0 +1,1022 @@
+// Windows/SystemInfo.cpp
+
+#include "StdAfx.h"
+
+#include "../../C/CpuArch.h"
+
+#include "../Common/IntToString.h"
+
+#ifdef _WIN32
+
+#include "Registry.h"
+
+#else
+
+#include <unistd.h>
+#include <sys/utsname.h>
+#ifdef __APPLE__
+#include <sys/sysctl.h>
+#elif !defined(_AIX)
+
+#include <sys/auxv.h>
+
+// #undef AT_HWCAP // to debug
+// #undef AT_HWCAP2 // to debug
+
+/* the following patch for some debian systems.
+ Is it OK to define AT_HWCAP and AT_HWCAP2 here with these constant numbers? */
+/*
+#if defined(__FreeBSD_kernel__) && defined(__GLIBC__)
+ #ifndef AT_HWCAP
+ #define AT_HWCAP 16
+ #endif
+ #ifndef AT_HWCAP2
+ #define AT_HWCAP2 26
+ #endif
+#endif
+*/
+
+#ifdef MY_CPU_ARM_OR_ARM64
+#include <asm/hwcap.h>
+#endif
+#endif
+
+#ifdef __linux__
+#include "../Windows/FileIO.h"
+#endif
+
+#endif // WIN32
+
+#include "SystemInfo.h"
+#include "System.h"
+
+using namespace NWindows;
+
+#ifdef __linux__
+
+static bool ReadFile_to_Buffer(CFSTR fileName, CByteBuffer &buf)
+{
+ NWindows::NFile::NIO::CInFile file;
+ if (!file.Open(fileName))
+ return false;
+ /*
+ UInt64 size;
+ if (!file.GetLength(size))
+ {
+ // GetLength() doesn't work "/proc/cpuinfo"
+ return false;
+ }
+ if (size >= ((UInt32)1 << 29))
+ return false;
+ */
+ size_t size = 0;
+ size_t addSize = ((size_t)1 << 12);
+ for (;;)
+ {
+ // printf("\nsize = %d\n", (unsigned)size);
+ buf.ChangeSize_KeepData(size + addSize, size);
+ size_t processed;
+ if (!file.ReadFull(buf + size, addSize, processed))
+ return false;
+ if (processed == 0)
+ {
+ buf.ChangeSize_KeepData(size, size);
+ return true;
+ }
+ size += processed;
+ addSize *= 2;
+ }
+}
+
+#endif
+
+
+#if defined(_WIN32) || defined(AT_HWCAP) || defined(AT_HWCAP2)
+static void PrintHex(AString &s, UInt64 v)
+{
+ char temp[32];
+ ConvertUInt64ToHex(v, temp);
+ s += temp;
+}
+#endif
+
+#ifdef MY_CPU_X86_OR_AMD64
+
+Z7_NO_INLINE
+static void PrintCpuChars(AString &s, UInt32 v)
+{
+ for (unsigned j = 0; j < 4; j++)
+ {
+ Byte b = (Byte)(v & 0xFF);
+ v >>= 8;
+ if (b == 0)
+ break;
+ if (b >= 0x20 && b <= 0x7f)
+ s += (char)b;
+ else
+ {
+ s += '[';
+ char temp[16];
+ ConvertUInt32ToHex(b, temp);
+ s += temp;
+ s += ']';
+ }
+ }
+}
+
+
+static void x86cpuid_to_String(AString &s)
+{
+ s.Empty();
+
+ UInt32 a[4];
+ // cpuid was called already. So we don't check for cpuid availability here
+ z7_x86_cpuid(a, 0x80000000);
+
+ if (a[0] >= 0x80000004) // if (maxFunc2 >= hi+4) the full name is available
+ {
+ for (unsigned i = 0; i < 3; i++)
+ {
+ z7_x86_cpuid(a, 0x80000002 + i);
+ for (unsigned j = 0; j < 4; j++)
+ PrintCpuChars(s, a[j]);
+ }
+ }
+
+ s.Trim();
+
+ if (s.IsEmpty())
+ {
+ z7_x86_cpuid(a, 0);
+ for (unsigned i = 1; i < 4; i++)
+ {
+ const unsigned j = (i ^ (i >> 1));
+ PrintCpuChars(s, a[j]);
+ }
+ s.Trim();
+ }
+}
+
+/*
+static void x86cpuid_all_to_String(AString &s)
+{
+ Cx86cpuid p;
+ if (!x86cpuid_CheckAndRead(&p))
+ return;
+ s += "x86cpuid maxFunc = ";
+ s.Add_UInt32(p.maxFunc);
+ for (unsigned j = 0; j <= p.maxFunc; j++)
+ {
+ s.Add_LF();
+ // s.Add_UInt32(j); // align
+ {
+ char temp[32];
+ ConvertUInt32ToString(j, temp);
+ unsigned len = (unsigned)strlen(temp);
+ while (len < 8)
+ {
+ len++;
+ s.Add_Space();
+ }
+ s += temp;
+ }
+
+ s += ":";
+ UInt32 d[4] = { 0 };
+ MyCPUID(j, &d[0], &d[1], &d[2], &d[3]);
+ for (unsigned i = 0; i < 4; i++)
+ {
+ char temp[32];
+ ConvertUInt32ToHex8Digits(d[i], temp);
+ s.Add_Space();
+ s += temp;
+ }
+ }
+}
+*/
+
+#endif
+
+
+
+#ifdef _WIN32
+
+static const char * const k_PROCESSOR_ARCHITECTURE[] =
+{
+ "x86" // "INTEL"
+ , "MIPS"
+ , "ALPHA"
+ , "PPC"
+ , "SHX"
+ , "ARM"
+ , "IA64"
+ , "ALPHA64"
+ , "MSIL"
+ , "x64" // "AMD64"
+ , "IA32_ON_WIN64"
+ , "NEUTRAL"
+ , "ARM64"
+ , "ARM32_ON_WIN64"
+};
+
+#define Z7_WIN_PROCESSOR_ARCHITECTURE_INTEL 0
+#define Z7_WIN_PROCESSOR_ARCHITECTURE_AMD64 9
+
+
+#define Z7_WIN_PROCESSOR_INTEL_PENTIUM 586
+#define Z7_WIN_PROCESSOR_AMD_X8664 8664
+
+/*
+static const CUInt32PCharPair k_PROCESSOR[] =
+{
+ { 2200, "IA64" },
+ { 8664, "x64" }
+};
+
+#define PROCESSOR_INTEL_386 386
+#define PROCESSOR_INTEL_486 486
+#define PROCESSOR_INTEL_PENTIUM 586
+#define PROCESSOR_INTEL_860 860
+#define PROCESSOR_INTEL_IA64 2200
+#define PROCESSOR_AMD_X8664 8664
+#define PROCESSOR_MIPS_R2000 2000
+#define PROCESSOR_MIPS_R3000 3000
+#define PROCESSOR_MIPS_R4000 4000
+#define PROCESSOR_ALPHA_21064 21064
+#define PROCESSOR_PPC_601 601
+#define PROCESSOR_PPC_603 603
+#define PROCESSOR_PPC_604 604
+#define PROCESSOR_PPC_620 620
+#define PROCESSOR_HITACHI_SH3 10003
+#define PROCESSOR_HITACHI_SH3E 10004
+#define PROCESSOR_HITACHI_SH4 10005
+#define PROCESSOR_MOTOROLA_821 821
+#define PROCESSOR_SHx_SH3 103
+#define PROCESSOR_SHx_SH4 104
+#define PROCESSOR_STRONGARM 2577 // 0xA11
+#define PROCESSOR_ARM720 1824 // 0x720
+#define PROCESSOR_ARM820 2080 // 0x820
+#define PROCESSOR_ARM920 2336 // 0x920
+#define PROCESSOR_ARM_7TDMI 70001
+#define PROCESSOR_OPTIL 18767 // 0x494f
+*/
+
+
+/*
+static const char * const k_PF[] =
+{
+ "FP_ERRATA"
+ , "FP_EMU"
+ , "CMPXCHG"
+ , "MMX"
+ , "PPC_MOVEMEM_64BIT"
+ , "ALPHA_BYTE"
+ , "SSE"
+ , "3DNOW"
+ , "RDTSC"
+ , "PAE"
+ , "SSE2"
+ , "SSE_DAZ"
+ , "NX"
+ , "SSE3"
+ , "CMPXCHG16B"
+ , "CMP8XCHG16"
+ , "CHANNELS"
+ , "XSAVE"
+ , "ARM_VFP_32"
+ , "ARM_NEON"
+ , "L2AT"
+ , "VIRT_FIRMWARE"
+ , "RDWRFSGSBASE"
+ , "FASTFAIL"
+ , "ARM_DIVIDE"
+ , "ARM_64BIT_LOADSTORE_ATOMIC"
+ , "ARM_EXTERNAL_CACHE"
+ , "ARM_FMAC"
+ , "RDRAND"
+ , "ARM_V8"
+ , "ARM_V8_CRYPTO"
+ , "ARM_V8_CRC32"
+ , "RDTSCP"
+ , "RDPID"
+ , "ARM_V81_ATOMIC"
+ , "MONITORX"
+};
+*/
+
+#endif
+
+
+static void PrintPage(AString &s, UInt64 v)
+{
+ const char *t = "B";
+ if ((v & 0x3ff) == 0)
+ {
+ v >>= 10;
+ t = "KB";
+ }
+ s.Add_UInt64(v);
+ s += t;
+}
+
+#ifdef _WIN32
+
+static AString TypeToString2(const char * const table[], unsigned num, UInt32 value)
+{
+ char sz[16];
+ const char *p = NULL;
+ if (value < num)
+ p = table[value];
+ if (!p)
+ {
+ ConvertUInt32ToString(value, sz);
+ p = sz;
+ }
+ return (AString)p;
+}
+
+// #if defined(Z7_LARGE_PAGES) || defined(_WIN32)
+// #ifdef _WIN32
+void PrintSize_KMGT_Or_Hex(AString &s, UInt64 v)
+{
+ char c = 0;
+ if ((v & 0x3FF) == 0) { v >>= 10; c = 'K';
+ if ((v & 0x3FF) == 0) { v >>= 10; c = 'M';
+ if ((v & 0x3FF) == 0) { v >>= 10; c = 'G';
+ if ((v & 0x3FF) == 0) { v >>= 10; c = 'T';
+ }}}}
+ else
+ {
+ // s += "0x";
+ PrintHex(s, v);
+ return;
+ }
+ s.Add_UInt64(v);
+ if (c)
+ s += c;
+ s += 'B';
+}
+// #endif
+// #endif
+
+static void SysInfo_To_String(AString &s, const SYSTEM_INFO &si)
+{
+ s += TypeToString2(k_PROCESSOR_ARCHITECTURE, Z7_ARRAY_SIZE(k_PROCESSOR_ARCHITECTURE), si.wProcessorArchitecture);
+
+ if (!( (si.wProcessorArchitecture == Z7_WIN_PROCESSOR_ARCHITECTURE_INTEL && si.dwProcessorType == Z7_WIN_PROCESSOR_INTEL_PENTIUM)
+ || (si.wProcessorArchitecture == Z7_WIN_PROCESSOR_ARCHITECTURE_AMD64 && si.dwProcessorType == Z7_WIN_PROCESSOR_AMD_X8664)))
+ {
+ s.Add_Space();
+ // s += TypePairToString(k_PROCESSOR, Z7_ARRAY_SIZE(k_PROCESSOR), si.dwProcessorType);
+ s.Add_UInt32(si.dwProcessorType);
+ }
+ s.Add_Space();
+ PrintHex(s, si.wProcessorLevel);
+ s.Add_Dot();
+ PrintHex(s, si.wProcessorRevision);
+ if ((UInt64)si.dwActiveProcessorMask + 1 != ((UInt64)1 << si.dwNumberOfProcessors))
+ if ((UInt64)si.dwActiveProcessorMask + 1 != 0 || si.dwNumberOfProcessors != sizeof(UInt64) * 8)
+ {
+ s += " act:";
+ PrintHex(s, si.dwActiveProcessorMask);
+ }
+ s += " cpus:";
+ s.Add_UInt32(si.dwNumberOfProcessors);
+ if (si.dwPageSize != 1 << 12)
+ {
+ s += " page:";
+ PrintPage(s, si.dwPageSize);
+ }
+ if (si.dwAllocationGranularity != 1 << 16)
+ {
+ s += " gran:";
+ PrintPage(s, si.dwAllocationGranularity);
+ }
+ s.Add_Space();
+
+ const DWORD_PTR minAdd = (DWORD_PTR)si.lpMinimumApplicationAddress;
+ UInt64 maxSize = (UInt64)(DWORD_PTR)si.lpMaximumApplicationAddress + 1;
+ const UInt32 kReserveSize = ((UInt32)1 << 16);
+ if (minAdd != kReserveSize)
+ {
+ PrintSize_KMGT_Or_Hex(s, minAdd);
+ s += "-";
+ }
+ else
+ {
+ if ((maxSize & (kReserveSize - 1)) == 0)
+ maxSize += kReserveSize;
+ }
+ PrintSize_KMGT_Or_Hex(s, maxSize);
+}
+
+#ifndef _WIN64
+EXTERN_C_BEGIN
+typedef VOID (WINAPI *Func_GetNativeSystemInfo)(LPSYSTEM_INFO lpSystemInfo);
+EXTERN_C_END
+#endif
+
+#endif
+
+#ifdef __APPLE__
+#ifndef MY_CPU_X86_OR_AMD64
+static void Add_sysctlbyname_to_String(const char *name, AString &s)
+{
+ size_t bufSize = 256;
+ char buf[256];
+ if (z7_sysctlbyname_Get(name, &buf, &bufSize) == 0)
+ s += buf;
+}
+#endif
+#endif
+
+void GetSysInfo(AString &s1, AString &s2);
+void GetSysInfo(AString &s1, AString &s2)
+{
+ s1.Empty();
+ s2.Empty();
+
+ #ifdef _WIN32
+ SYSTEM_INFO si;
+ GetSystemInfo(&si);
+ {
+ SysInfo_To_String(s1, si);
+ // s += " : ";
+ }
+
+ #if !defined(_WIN64) && !defined(UNDER_CE)
+ const
+ Func_GetNativeSystemInfo fn = Z7_GET_PROC_ADDRESS(
+ Func_GetNativeSystemInfo, GetModuleHandleA("kernel32.dll"),
+ "GetNativeSystemInfo");
+ if (fn)
+ {
+ SYSTEM_INFO si2;
+ fn(&si2);
+ // if (memcmp(&si, &si2, sizeof(si)) != 0)
+ {
+ // s += " - ";
+ SysInfo_To_String(s2, si2);
+ }
+ }
+ #endif
+ #endif
+}
+
+
+void GetCpuName(AString &s);
+
+static void AddBracedString(AString &dest, AString &src)
+{
+ if (!src.IsEmpty())
+ {
+ AString s;
+ s += '(';
+ s += src;
+ s += ')';
+ dest.Add_OptSpaced(s);
+ }
+}
+
+struct CCpuName
+{
+ AString CpuName;
+ AString Revision;
+ AString Microcode;
+ AString LargePages;
+
+ void Fill();
+
+ void Get_Revision_Microcode_LargePages(AString &s)
+ {
+ s.Empty();
+ AddBracedString(s, Revision);
+ AddBracedString(s, Microcode);
+ s.Add_OptSpaced(LargePages);
+ }
+};
+
+void CCpuName::Fill()
+{
+ CpuName.Empty();
+ Revision.Empty();
+ Microcode.Empty();
+ LargePages.Empty();
+
+ AString &s = CpuName;
+
+ #ifdef MY_CPU_X86_OR_AMD64
+ {
+ #if !defined(MY_CPU_AMD64)
+ if (!z7_x86_cpuid_GetMaxFunc())
+ s += "x86";
+ else
+ #endif
+ {
+ x86cpuid_to_String(s);
+ {
+ UInt32 a[4];
+ z7_x86_cpuid(a, 1);
+ char temp[16];
+ ConvertUInt32ToHex(a[0], temp);
+ Revision += temp;
+ }
+ }
+ }
+ #elif defined(__APPLE__)
+ {
+ Add_sysctlbyname_to_String("machdep.cpu.brand_string", s);
+ }
+ #endif
+
+
+ if (s.IsEmpty())
+ {
+ #ifdef MY_CPU_LE
+ s += "LE";
+ #elif defined(MY_CPU_BE)
+ s += "BE";
+ #endif
+ }
+
+ #ifdef __APPLE__
+ {
+ AString s2;
+ UInt32 v = 0;
+ if (z7_sysctlbyname_Get_UInt32("machdep.cpu.core_count", &v) == 0)
+ {
+ s2.Add_UInt32(v);
+ s2 += 'C';
+ }
+ if (z7_sysctlbyname_Get_UInt32("machdep.cpu.thread_count", &v) == 0)
+ {
+ s2.Add_UInt32(v);
+ s2 += 'T';
+ }
+ if (!s2.IsEmpty())
+ {
+ s.Add_Space_if_NotEmpty();
+ s += s2;
+ }
+ }
+ #endif
+
+
+ #ifdef _WIN32
+ {
+ NRegistry::CKey key;
+ if (key.Open(HKEY_LOCAL_MACHINE, TEXT("HARDWARE\\DESCRIPTION\\System\\CentralProcessor\\0"), KEY_READ) == ERROR_SUCCESS)
+ {
+ LONG res[2];
+ CByteBuffer bufs[2];
+ {
+ for (unsigned i = 0; i < 2; i++)
+ {
+ UInt32 size = 0;
+ res[i] = key.QueryValue(i == 0 ?
+ TEXT("Previous Update Revision") :
+ TEXT("Update Revision"), bufs[i], size);
+ if (res[i] == ERROR_SUCCESS)
+ if (size != bufs[i].Size())
+ res[i] = ERROR_SUCCESS + 1;
+ }
+ }
+ if (res[0] == ERROR_SUCCESS || res[1] == ERROR_SUCCESS)
+ {
+ for (unsigned i = 0; i < 2; i++)
+ {
+ if (i == 1)
+ Microcode += "->";
+ if (res[i] != ERROR_SUCCESS)
+ continue;
+ const CByteBuffer &buf = bufs[i];
+ if (buf.Size() == 8)
+ {
+ UInt32 high = GetUi32(buf);
+ if (high != 0)
+ {
+ PrintHex(Microcode, high);
+ Microcode += ".";
+ }
+ PrintHex(Microcode, GetUi32(buf + 4));
+ }
+ }
+ }
+ }
+ }
+ #endif
+
+
+ #ifdef Z7_LARGE_PAGES
+ Add_LargePages_String(LargePages);
+ #endif
+}
+
+void AddCpuFeatures(AString &s);
+void AddCpuFeatures(AString &s)
+{
+ #ifdef _WIN32
+ // const unsigned kNumFeatures_Extra = 32; // we check also for unknown features
+ // const unsigned kNumFeatures = Z7_ARRAY_SIZE(k_PF) + kNumFeatures_Extra;
+ const unsigned kNumFeatures = 64;
+ UInt64 flags = 0;
+ for (unsigned i = 0; i < kNumFeatures; i++)
+ {
+ if (IsProcessorFeaturePresent(i))
+ {
+ flags += (UInt64)1 << i;
+ // s.Add_Space_if_NotEmpty();
+ // s += TypeToString2(k_PF, Z7_ARRAY_SIZE(k_PF), i);
+ }
+ }
+ s.Add_OptSpaced("f:");
+ PrintHex(s, flags);
+
+ #elif defined(__APPLE__)
+ {
+ UInt32 v = 0;
+ if (z7_sysctlbyname_Get_UInt32("hw.pagesize", &v) == 0)
+ {
+ s.Add_OptSpaced("PageSize:");
+ PrintPage(s, v);
+ }
+ }
+
+ #else
+
+ const long v = sysconf(_SC_PAGESIZE);
+ if (v != -1)
+ {
+ s.Add_OptSpaced("PageSize:");
+ PrintPage(s, (unsigned long)v);
+ }
+
+ #if !defined(_AIX)
+
+ #ifdef __linux__
+
+ CByteBuffer buf;
+ if (ReadFile_to_Buffer("/sys/kernel/mm/transparent_hugepage/enabled", buf))
+ // if (ReadFile_to_Buffer("/proc/cpuinfo", buf))
+ {
+ s.Add_OptSpaced("THP:");
+ AString s2;
+ s2.SetFrom_CalcLen((const char *)(const void *)(const Byte *)buf, (unsigned)buf.Size());
+ const int pos = s2.Find('[');
+ if (pos >= 0)
+ {
+ const int pos2 = s2.Find(']', (unsigned)pos + 1);
+ if (pos2 >= 0)
+ {
+ s2.DeleteFrom((unsigned)pos2);
+ s2.DeleteFrontal((unsigned)pos + 1);
+ }
+ }
+ s += s2;
+ }
+ // else throw CSystemException(MY_SRes_HRESULT_FROM_WRes(errno));
+
+ #endif
+
+
+ #ifdef AT_HWCAP
+ s.Add_OptSpaced("hwcap:");
+ {
+ unsigned long h = getauxval(AT_HWCAP);
+ PrintHex(s, h);
+ #ifdef MY_CPU_ARM64
+ if (h & HWCAP_CRC32) s += ":CRC32";
+ if (h & HWCAP_SHA1) s += ":SHA1";
+ if (h & HWCAP_SHA2) s += ":SHA2";
+ if (h & HWCAP_AES) s += ":AES";
+ if (h & HWCAP_ASIMD) s += ":ASIMD";
+ #elif defined(MY_CPU_ARM)
+ if (h & HWCAP_NEON) s += ":NEON";
+ #endif
+ }
+ #endif // AT_HWCAP
+
+ #ifdef AT_HWCAP2
+ {
+ unsigned long h = getauxval(AT_HWCAP2);
+ #ifndef MY_CPU_ARM
+ if (h != 0)
+ #endif
+ {
+ s += " hwcap2:";
+ PrintHex(s, h);
+ #ifdef MY_CPU_ARM
+ if (h & HWCAP2_CRC32) s += ":CRC32";
+ if (h & HWCAP2_SHA1) s += ":SHA1";
+ if (h & HWCAP2_SHA2) s += ":SHA2";
+ if (h & HWCAP2_AES) s += ":AES";
+ #endif
+ }
+ }
+ #endif // AT_HWCAP2
+ #endif // _AIX
+ #endif // _WIN32
+}
+
+
+#ifdef _WIN32
+#ifndef UNDER_CE
+
+EXTERN_C_BEGIN
+typedef void (WINAPI * Func_RtlGetVersion) (OSVERSIONINFOEXW *);
+EXTERN_C_END
+
+static BOOL My_RtlGetVersion(OSVERSIONINFOEXW *vi)
+{
+ const HMODULE ntdll = ::GetModuleHandleW(L"ntdll.dll");
+ if (!ntdll)
+ return FALSE;
+ const
+ Func_RtlGetVersion func = Z7_GET_PROC_ADDRESS(
+ Func_RtlGetVersion, ntdll,
+ "RtlGetVersion");
+ if (!func)
+ return FALSE;
+ func(vi);
+ return TRUE;
+}
+
+#endif
+#endif
+
+
+void GetOsInfoText(AString &sRes)
+{
+ sRes.Empty();
+ AString s;
+
+ #ifdef _WIN32
+ #ifndef UNDER_CE
+ // OSVERSIONINFO vi;
+ OSVERSIONINFOEXW vi;
+ vi.dwOSVersionInfoSize = sizeof(vi);
+ // if (::GetVersionEx(&vi))
+ if (My_RtlGetVersion(&vi))
+ {
+ s += "Windows";
+ if (vi.dwPlatformId != VER_PLATFORM_WIN32_NT)
+ s.Add_UInt32(vi.dwPlatformId);
+ s.Add_Space(); s.Add_UInt32(vi.dwMajorVersion);
+ s.Add_Dot(); s.Add_UInt32(vi.dwMinorVersion);
+ s.Add_Space(); s.Add_UInt32(vi.dwBuildNumber);
+
+ if (vi.wServicePackMajor != 0 || vi.wServicePackMinor != 0)
+ {
+ s += " SP:"; s.Add_UInt32(vi.wServicePackMajor);
+ s.Add_Dot(); s.Add_UInt32(vi.wServicePackMinor);
+ }
+ // s += " Suite:"; PrintHex(s, vi.wSuiteMask);
+ // s += " Type:"; s.Add_UInt32(vi.wProductType);
+ // s.Add_Space(); s += GetOemString(vi.szCSDVersion);
+ }
+ /*
+ {
+ s += " OEMCP:"; s.Add_UInt32(GetOEMCP());
+ s += " ACP:"; s.Add_UInt32(GetACP());
+ }
+ */
+ #endif
+ #else // _WIN32
+
+ if (!s.IsEmpty())
+ s.Add_LF();
+ struct utsname un;
+ if (uname(&un) == 0)
+ {
+ s += un.sysname;
+ // s += " : "; s += un.nodename; // we don't want to show name of computer
+ s += " : "; s += un.release;
+ s += " : "; s += un.version;
+ s += " : "; s += un.machine;
+
+ #ifdef __APPLE__
+ // Add_sysctlbyname_to_String("kern.version", s);
+ // it's same as "utsname.version"
+ #endif
+ }
+ #endif // _WIN32
+
+ sRes += s;
+ #ifdef MY_CPU_X86_OR_AMD64
+ {
+ AString s2;
+ GetVirtCpuid(s2);
+ if (!s2.IsEmpty())
+ {
+ sRes += " : ";
+ sRes += s2;
+ }
+ }
+ #endif
+}
+
+
+
+void GetSystemInfoText(AString &sRes)
+{
+ GetOsInfoText(sRes);
+ sRes.Add_LF();
+
+ {
+ AString s, s1, s2;
+ GetSysInfo(s1, s2);
+ if (!s1.IsEmpty() || !s2.IsEmpty())
+ {
+ s = s1;
+ if (s1 != s2 && !s2.IsEmpty())
+ {
+ s += " - ";
+ s += s2;
+ }
+ }
+ {
+ AddCpuFeatures(s);
+ if (!s.IsEmpty())
+ {
+ sRes += s;
+ sRes.Add_LF();
+ }
+ }
+ }
+ {
+ AString s;
+ GetCpuName(s);
+ if (!s.IsEmpty())
+ {
+ sRes += s;
+ sRes.Add_LF();
+ }
+ }
+ /*
+ #ifdef MY_CPU_X86_OR_AMD64
+ {
+ AString s;
+ x86cpuid_all_to_String(s);
+ if (!s.IsEmpty())
+ {
+ printCallback->Print(s);
+ printCallback->NewLine();
+ }
+ }
+ #endif
+ */
+}
+
+
+void GetCpuName(AString &s);
+void GetCpuName(AString &s)
+{
+ CCpuName cpuName;
+ cpuName.Fill();
+ s = cpuName.CpuName;
+ AString s2;
+ cpuName.Get_Revision_Microcode_LargePages(s2);
+ s.Add_OptSpaced(s2);
+}
+
+
+void GetCpuName_MultiLine(AString &s);
+void GetCpuName_MultiLine(AString &s)
+{
+ CCpuName cpuName;
+ cpuName.Fill();
+ s = cpuName.CpuName;
+ AString s2;
+ cpuName.Get_Revision_Microcode_LargePages(s2);
+ if (!s2.IsEmpty())
+ {
+ s.Add_LF();
+ s += s2;
+ }
+}
+
+
+#ifdef MY_CPU_X86_OR_AMD64
+
+void GetVirtCpuid(AString &s)
+{
+ const UInt32 kHv = 0x40000000;
+
+ Z7_IF_X86_CPUID_SUPPORTED
+ {
+ UInt32 a[4];
+ z7_x86_cpuid(a, kHv);
+
+ if (a[0] < kHv || a[0] >= kHv + (1 << 16))
+ return;
+ {
+ {
+ for (unsigned j = 1; j < 4; j++)
+ PrintCpuChars(s, a[j]);
+ }
+ }
+ if (a[0] >= kHv + 1)
+ {
+ UInt32 d[4];
+ z7_x86_cpuid(d, kHv + 1);
+ s += " : ";
+ PrintCpuChars(s, d[0]);
+ if (a[0] >= kHv + 2)
+ {
+ z7_x86_cpuid(d, kHv + 2);
+ s += " : ";
+ s.Add_UInt32(d[1] >> 16);
+ s.Add_Dot(); s.Add_UInt32(d[1] & 0xffff);
+ s.Add_Dot(); s.Add_UInt32(d[0]);
+ s.Add_Dot(); s.Add_UInt32(d[2]);
+ s.Add_Dot(); s.Add_UInt32(d[3] >> 24);
+ s.Add_Dot(); s.Add_UInt32(d[3] & 0xffffff);
+ }
+ /*
+ if (a[0] >= kHv + 5)
+ {
+ z7_x86_cpuid(d, kHv + 5);
+ s += " : ";
+ s.Add_UInt32(d[0]);
+ s += "p";
+ s.Add_UInt32(d[1]);
+ s += "t";
+ }
+ */
+ }
+ }
+}
+
+#endif
+
+
+void GetCompiler(AString &s)
+{
+ #ifdef __VERSION__
+ s += __VERSION__;
+ #endif
+
+ #ifdef __GNUC__
+ s += " GCC ";
+ s.Add_UInt32(__GNUC__);
+ s.Add_Dot();
+ s.Add_UInt32(__GNUC_MINOR__);
+ s.Add_Dot();
+ s.Add_UInt32(__GNUC_PATCHLEVEL__);
+ #endif
+
+ #ifdef __clang__
+ s += " CLANG ";
+ s.Add_UInt32(__clang_major__);
+ s.Add_Dot();
+ s.Add_UInt32(__clang_minor__);
+ #endif
+
+ #ifdef __xlC__
+ s += " XLC ";
+ s.Add_UInt32(__xlC__ >> 8);
+ s.Add_Dot();
+ s.Add_UInt32(__xlC__ & 0xFF);
+ #ifdef __xlC_ver__
+ s.Add_Dot();
+ s.Add_UInt32(__xlC_ver__ >> 8);
+ s.Add_Dot();
+ s.Add_UInt32(__xlC_ver__ & 0xFF);
+ #endif
+ #endif
+
+ #ifdef _MSC_VER
+ s += " MSC ";
+ s.Add_UInt32(_MSC_VER);
+ #endif
+
+ #if defined(__AVX2__)
+ #define MY_CPU_COMPILE_ISA "AVX2"
+ #elif defined(__AVX__)
+ #define MY_CPU_COMPILE_ISA "AVX"
+ #elif defined(__SSE2__)
+ #define MY_CPU_COMPILE_ISA "SSE2"
+ #elif defined(_M_IX86_FP) && (_M_IX86_FP >= 2)
+ #define MY_CPU_COMPILE_ISA "SSE2"
+ #elif defined(__SSE__)
+ #define MY_CPU_COMPILE_ISA "SSE"
+ #elif defined(_M_IX86_FP) && (_M_IX86_FP >= 1)
+ #define MY_CPU_COMPILE_ISA "SSE"
+ #elif defined(__i686__)
+ #define MY_CPU_COMPILE_ISA "i686"
+ #elif defined(__i586__)
+ #define MY_CPU_COMPILE_ISA "i586"
+ #elif defined(__i486__)
+ #define MY_CPU_COMPILE_ISA "i486"
+ #elif defined(__i386__)
+ #define MY_CPU_COMPILE_ISA "i386"
+ #elif defined(_M_IX86_FP)
+ #define MY_CPU_COMPILE_ISA "IA32"
+ #endif
+
+
+ #ifdef MY_CPU_COMPILE_ISA
+ s += ':';
+ s.Add_OptSpaced(MY_CPU_COMPILE_ISA);
+ #endif
+}
diff --git a/CPP/Windows/SystemInfo.h b/CPP/Windows/SystemInfo.h
new file mode 100644
index 0000000..c2e2e3b
--- /dev/null
+++ b/CPP/Windows/SystemInfo.h
@@ -0,0 +1,19 @@
+// Windows/SystemInfo.h
+
+#ifndef ZIP7_INC_WINDOWS_SYSTEM_INFO_H
+#define ZIP7_INC_WINDOWS_SYSTEM_INFO_H
+
+#include "../Common/MyString.h"
+
+
+void GetCpuName_MultiLine(AString &s);
+
+void GetOsInfoText(AString &sRes);
+void GetSystemInfoText(AString &s);
+void PrintSize_KMGT_Or_Hex(AString &s, UInt64 v);
+void Add_LargePages_String(AString &s);
+
+void GetCompiler(AString &s);
+void GetVirtCpuid(AString &s);
+
+#endif
diff --git a/CPP/Windows/Thread.h b/CPP/Windows/Thread.h
index 1b5863c..d72f64c 100644
--- a/CPP/Windows/Thread.h
+++ b/CPP/Windows/Thread.h
@@ -1,38 +1,44 @@
-// Windows/Thread.h
-
-#ifndef __WINDOWS_THREAD_H
-#define __WINDOWS_THREAD_H
-
-#include "../../C/Threads.h"
-
-#include "Defs.h"
-
-namespace NWindows {
-
-class CThread
-{
- ::CThread thread;
-public:
- CThread() { Thread_Construct(&thread); }
- ~CThread() { Close(); }
- bool IsCreated() { return Thread_WasCreated(&thread) != 0; }
- WRes Close() { return Thread_Close(&thread); }
- WRes Create(THREAD_FUNC_RET_TYPE (THREAD_FUNC_CALL_TYPE *startAddress)(void *), LPVOID parameter)
- { return Thread_Create(&thread, startAddress, parameter); }
- WRes Wait() { return Thread_Wait(&thread); }
-
- #ifdef _WIN32
- operator HANDLE() { return thread; }
- void Attach(HANDLE handle) { thread = handle; }
- HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; }
- DWORD Resume() { return ::ResumeThread(thread); }
- DWORD Suspend() { return ::SuspendThread(thread); }
- bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); }
- int GetPriority() { return ::GetThreadPriority(thread); }
- bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); }
- #endif
-};
-
-}
-
-#endif
+// Windows/Thread.h
+
+#ifndef ZIP7_INC_WINDOWS_THREAD_H
+#define ZIP7_INC_WINDOWS_THREAD_H
+
+#include "../../C/Threads.h"
+
+#include "Defs.h"
+
+namespace NWindows {
+
+class CThread MY_UNCOPYABLE
+{
+ ::CThread thread;
+public:
+ CThread() { Thread_CONSTRUCT(&thread) }
+ ~CThread() { Close(); }
+ bool IsCreated() { return Thread_WasCreated(&thread) != 0; }
+ WRes Close() { return Thread_Close(&thread); }
+ // WRes Wait() { return Thread_Wait(&thread); }
+ WRes Wait_Close() { return Thread_Wait_Close(&thread); }
+
+ WRes Create(THREAD_FUNC_TYPE startAddress, LPVOID param)
+ { return Thread_Create(&thread, startAddress, param); }
+ WRes Create_With_Affinity(THREAD_FUNC_TYPE startAddress, LPVOID param, CAffinityMask affinity)
+ { return Thread_Create_With_Affinity(&thread, startAddress, param, affinity); }
+ WRes Create_With_CpuSet(THREAD_FUNC_TYPE startAddress, LPVOID param, const CCpuSet *cpuSet)
+ { return Thread_Create_With_CpuSet(&thread, startAddress, param, cpuSet); }
+
+ #ifdef _WIN32
+ operator HANDLE() { return thread; }
+ void Attach(HANDLE handle) { thread = handle; }
+ HANDLE Detach() { HANDLE h = thread; thread = NULL; return h; }
+ DWORD Resume() { return ::ResumeThread(thread); }
+ DWORD Suspend() { return ::SuspendThread(thread); }
+ bool Terminate(DWORD exitCode) { return BOOLToBool(::TerminateThread(thread, exitCode)); }
+ int GetPriority() { return ::GetThreadPriority(thread); }
+ bool SetPriority(int priority) { return BOOLToBool(::SetThreadPriority(thread, priority)); }
+ #endif
+};
+
+}
+
+#endif
diff --git a/CPP/Windows/TimeUtils.cpp b/CPP/Windows/TimeUtils.cpp
index 3fc02bc..e80ae13 100644
--- a/CPP/Windows/TimeUtils.cpp
+++ b/CPP/Windows/TimeUtils.cpp
@@ -1,213 +1,404 @@
-// Windows/TimeUtils.cpp
-
-#include "StdAfx.h"
-
-#include "Defs.h"
-#include "TimeUtils.h"
-
-namespace NWindows {
-namespace NTime {
-
-static const UInt32 kNumTimeQuantumsInSecond = 10000000;
-static const UInt32 kFileTimeStartYear = 1601;
-static const UInt32 kDosTimeStartYear = 1980;
-static const UInt32 kUnixTimeStartYear = 1970;
-static const UInt64 kUnixTimeOffset =
- (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear));
-static const UInt64 kNumSecondsInFileTime = (UInt64)(Int64)-1 / kNumTimeQuantumsInSecond;
-
-bool DosTimeToFileTime(UInt32 dosTime, FILETIME &ft) throw()
-{
- #if defined(_WIN32) && !defined(UNDER_CE)
- return BOOLToBool(::DosDateTimeToFileTime((UInt16)(dosTime >> 16), (UInt16)(dosTime & 0xFFFF), &ft));
- #else
- ft.dwLowDateTime = 0;
- ft.dwHighDateTime = 0;
- UInt64 res;
- if (!GetSecondsSince1601(kDosTimeStartYear + (dosTime >> 25), (dosTime >> 21) & 0xF, (dosTime >> 16) & 0x1F,
- (dosTime >> 11) & 0x1F, (dosTime >> 5) & 0x3F, (dosTime & 0x1F) * 2, res))
- return false;
- res *= kNumTimeQuantumsInSecond;
- ft.dwLowDateTime = (UInt32)res;
- ft.dwHighDateTime = (UInt32)(res >> 32);
- return true;
- #endif
-}
-
-static const UInt32 kHighDosTime = 0xFF9FBF7D;
-static const UInt32 kLowDosTime = 0x210000;
-
-#define PERIOD_4 (4 * 365 + 1)
-#define PERIOD_100 (PERIOD_4 * 25 - 1)
-#define PERIOD_400 (PERIOD_100 * 4 + 1)
-
-bool FileTimeToDosTime(const FILETIME &ft, UInt32 &dosTime) throw()
-{
- #if defined(_WIN32) && !defined(UNDER_CE)
-
- WORD datePart, timePart;
- if (!::FileTimeToDosDateTime(&ft, &datePart, &timePart))
- {
- dosTime = (ft.dwHighDateTime >= 0x01C00000) ? kHighDosTime : kLowDosTime;
- return false;
- }
- dosTime = (((UInt32)datePart) << 16) + timePart;
-
- #else
-
- unsigned year, mon, day, hour, min, sec;
- UInt64 v64 = ft.dwLowDateTime | ((UInt64)ft.dwHighDateTime << 32);
- Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
- unsigned temp;
- UInt32 v;
- v64 += (kNumTimeQuantumsInSecond * 2 - 1);
- v64 /= kNumTimeQuantumsInSecond;
- sec = (unsigned)(v64 % 60);
- v64 /= 60;
- min = (unsigned)(v64 % 60);
- v64 /= 60;
- hour = (unsigned)(v64 % 24);
- v64 /= 24;
-
- v = (UInt32)v64;
-
- year = (unsigned)(kFileTimeStartYear + v / PERIOD_400 * 400);
- v %= PERIOD_400;
-
- temp = (unsigned)(v / PERIOD_100);
- if (temp == 4)
- temp = 3;
- year += temp * 100;
- v -= temp * PERIOD_100;
-
- temp = v / PERIOD_4;
- if (temp == 25)
- temp = 24;
- year += temp * 4;
- v -= temp * PERIOD_4;
-
- temp = v / 365;
- if (temp == 4)
- temp = 3;
- year += temp;
- v -= temp * 365;
-
- if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
- ms[1] = 29;
- for (mon = 1; mon <= 12; mon++)
- {
- unsigned s = ms[mon - 1];
- if (v < s)
- break;
- v -= s;
- }
- day = (unsigned)v + 1;
-
- dosTime = kLowDosTime;
- if (year < kDosTimeStartYear)
- return false;
- year -= kDosTimeStartYear;
- dosTime = kHighDosTime;
- if (year >= 128)
- return false;
- dosTime = (year << 25) | (mon << 21) | (day << 16) | (hour << 11) | (min << 5) | (sec >> 1);
- #endif
- return true;
-}
-
-UInt64 UnixTimeToFileTime64(UInt32 unixTime) throw()
-{
- return (kUnixTimeOffset + (UInt64)unixTime) * kNumTimeQuantumsInSecond;
-}
-
-void UnixTimeToFileTime(UInt32 unixTime, FILETIME &ft) throw()
-{
- UInt64 v = UnixTimeToFileTime64(unixTime);
- ft.dwLowDateTime = (DWORD)v;
- ft.dwHighDateTime = (DWORD)(v >> 32);
-}
-
-UInt64 UnixTime64ToFileTime64(Int64 unixTime) throw()
-{
- return (UInt64)(kUnixTimeOffset + unixTime) * kNumTimeQuantumsInSecond;
-}
-
-bool UnixTime64ToFileTime(Int64 unixTime, FILETIME &ft) throw()
-{
- if (unixTime > (Int64)(kNumSecondsInFileTime - kUnixTimeOffset))
- {
- ft.dwLowDateTime = ft.dwHighDateTime = (UInt32)(Int32)-1;
- return false;
- }
- Int64 v = (Int64)kUnixTimeOffset + unixTime;
- if (v < 0)
- {
- ft.dwLowDateTime = ft.dwHighDateTime = 0;
- return false;
- }
- UInt64 v2 = (UInt64)v * kNumTimeQuantumsInSecond;
- ft.dwLowDateTime = (DWORD)v2;
- ft.dwHighDateTime = (DWORD)(v2 >> 32);
- return true;
-}
-
-Int64 FileTimeToUnixTime64(const FILETIME &ft) throw()
-{
- UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
- return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset;
-}
-
-bool FileTimeToUnixTime(const FILETIME &ft, UInt32 &unixTime) throw()
-{
- UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
- winTime /= kNumTimeQuantumsInSecond;
- if (winTime < kUnixTimeOffset)
- {
- unixTime = 0;
- return false;
- }
- winTime -= kUnixTimeOffset;
- if (winTime > 0xFFFFFFFF)
- {
- unixTime = 0xFFFFFFFF;
- return false;
- }
- unixTime = (UInt32)winTime;
- return true;
-}
-
-bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day,
- unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw()
-{
- resSeconds = 0;
- if (year < kFileTimeStartYear || year >= 10000 || month < 1 || month > 12 ||
- day < 1 || day > 31 || hour > 23 || min > 59 || sec > 59)
- return false;
- UInt32 numYears = year - kFileTimeStartYear;
- UInt32 numDays = numYears * 365 + numYears / 4 - numYears / 100 + numYears / 400;
- Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
- if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
- ms[1] = 29;
- month--;
- for (unsigned i = 0; i < month; i++)
- numDays += ms[i];
- numDays += day - 1;
- resSeconds = ((UInt64)(numDays * 24 + hour) * 60 + min) * 60 + sec;
- return true;
-}
-
-void GetCurUtcFileTime(FILETIME &ft) throw()
-{
- // Both variants provide same low resolution on WinXP: about 15 ms.
- // But GetSystemTimeAsFileTime is much faster.
-
- #ifdef UNDER_CE
- SYSTEMTIME st;
- GetSystemTime(&st);
- SystemTimeToFileTime(&st, &ft);
- #else
- GetSystemTimeAsFileTime(&ft);
- #endif
-}
-
-}}
+// Windows/TimeUtils.cpp
+
+#include "StdAfx.h"
+
+#ifndef _WIN32
+#include <sys/time.h>
+#endif
+
+#include "Defs.h"
+#include "TimeUtils.h"
+
+namespace NWindows {
+namespace NTime {
+
+static const UInt32 kNumTimeQuantumsInSecond = 10000000;
+static const UInt32 kFileTimeStartYear = 1601;
+#if !defined(_WIN32) || defined(UNDER_CE)
+static const UInt32 kDosTimeStartYear = 1980;
+#endif
+static const UInt32 kUnixTimeStartYear = 1970;
+static const UInt64 kUnixTimeOffset =
+ (UInt64)60 * 60 * 24 * (89 + 365 * (kUnixTimeStartYear - kFileTimeStartYear));
+static const UInt64 kNumSecondsInFileTime = (UInt64)(Int64)-1 / kNumTimeQuantumsInSecond;
+
+bool DosTime_To_FileTime(UInt32 dosTime, FILETIME &ft) throw()
+{
+ #if defined(_WIN32) && !defined(UNDER_CE)
+ return BOOLToBool(::DosDateTimeToFileTime((UInt16)(dosTime >> 16), (UInt16)(dosTime & 0xFFFF), &ft));
+ #else
+ ft.dwLowDateTime = 0;
+ ft.dwHighDateTime = 0;
+ UInt64 res;
+ if (!GetSecondsSince1601(kDosTimeStartYear + (dosTime >> 25), (dosTime >> 21) & 0xF, (dosTime >> 16) & 0x1F,
+ (dosTime >> 11) & 0x1F, (dosTime >> 5) & 0x3F, (dosTime & 0x1F) * 2, res))
+ return false;
+ res *= kNumTimeQuantumsInSecond;
+ ft.dwLowDateTime = (UInt32)res;
+ ft.dwHighDateTime = (UInt32)(res >> 32);
+ return true;
+ #endif
+}
+
+static const UInt32 kHighDosTime = 0xFF9FBF7D;
+static const UInt32 kLowDosTime = 0x210000;
+
+bool FileTime_To_DosTime(const FILETIME &ft, UInt32 &dosTime) throw()
+{
+ #if defined(_WIN32) && !defined(UNDER_CE)
+
+ WORD datePart, timePart;
+ if (!::FileTimeToDosDateTime(&ft, &datePart, &timePart))
+ {
+ dosTime = (ft.dwHighDateTime >= 0x01C00000) ? kHighDosTime : kLowDosTime;
+ return false;
+ }
+ dosTime = (((UInt32)datePart) << 16) + timePart;
+
+ #else
+
+#define PERIOD_4 (4 * 365 + 1)
+#define PERIOD_100 (PERIOD_4 * 25 - 1)
+#define PERIOD_400 (PERIOD_100 * 4 + 1)
+
+ unsigned year, mon, day, hour, min, sec;
+ UInt64 v64 = ft.dwLowDateTime | ((UInt64)ft.dwHighDateTime << 32);
+ Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ unsigned temp;
+ UInt32 v;
+ v64 += (kNumTimeQuantumsInSecond * 2 - 1);
+ v64 /= kNumTimeQuantumsInSecond;
+ sec = (unsigned)(v64 % 60);
+ v64 /= 60;
+ min = (unsigned)(v64 % 60);
+ v64 /= 60;
+ hour = (unsigned)(v64 % 24);
+ v64 /= 24;
+
+ v = (UInt32)v64;
+
+ year = (unsigned)(kFileTimeStartYear + v / PERIOD_400 * 400);
+ v %= PERIOD_400;
+
+ temp = (unsigned)(v / PERIOD_100);
+ if (temp == 4)
+ temp = 3;
+ year += temp * 100;
+ v -= temp * PERIOD_100;
+
+ temp = v / PERIOD_4;
+ if (temp == 25)
+ temp = 24;
+ year += temp * 4;
+ v -= temp * PERIOD_4;
+
+ temp = v / 365;
+ if (temp == 4)
+ temp = 3;
+ year += temp;
+ v -= temp * 365;
+
+ if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
+ ms[1] = 29;
+ for (mon = 1; mon <= 12; mon++)
+ {
+ unsigned s = ms[mon - 1];
+ if (v < s)
+ break;
+ v -= s;
+ }
+ day = (unsigned)v + 1;
+
+ dosTime = kLowDosTime;
+ if (year < kDosTimeStartYear)
+ return false;
+ year -= kDosTimeStartYear;
+ dosTime = kHighDosTime;
+ if (year >= 128)
+ return false;
+ dosTime = (year << 25) | (mon << 21) | (day << 16) | (hour << 11) | (min << 5) | (sec >> 1);
+ #endif
+ return true;
+}
+
+
+bool UtcFileTime_To_LocalDosTime(const FILETIME &utc, UInt32 &dosTime) throw()
+{
+ FILETIME loc = { 0, 0 };
+ const UInt64 u1 = FILETIME_To_UInt64(utc);
+ const UInt64 kDelta = ((UInt64)1 << 41); // it's larger than quantums in 1 sec.
+ if (u1 >= kDelta)
+ {
+ if (!FileTimeToLocalFileTime(&utc, &loc))
+ loc = utc;
+ else
+ {
+ const UInt64 u2 = FILETIME_To_UInt64(loc);
+ const UInt64 delta = u1 < u2 ? (u2 - u1) : (u1 - u2);
+ if (delta > kDelta) // if FileTimeToLocalFileTime() overflow, we use UTC time
+ loc = utc;
+ }
+ }
+ return FileTime_To_DosTime(loc, dosTime);
+}
+
+UInt64 UnixTime_To_FileTime64(UInt32 unixTime) throw()
+{
+ return (kUnixTimeOffset + (UInt64)unixTime) * kNumTimeQuantumsInSecond;
+}
+
+void UnixTime_To_FileTime(UInt32 unixTime, FILETIME &ft) throw()
+{
+ const UInt64 v = UnixTime_To_FileTime64(unixTime);
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+}
+
+UInt64 UnixTime64_To_FileTime64(Int64 unixTime) throw()
+{
+ return (UInt64)((Int64)kUnixTimeOffset + unixTime) * kNumTimeQuantumsInSecond;
+}
+
+
+bool UnixTime64_To_FileTime64(Int64 unixTime, UInt64 &fileTime) throw()
+{
+ if (unixTime > (Int64)(kNumSecondsInFileTime - kUnixTimeOffset))
+ {
+ fileTime = (UInt64)(Int64)-1;
+ return false;
+ }
+ if (unixTime < -(Int64)kUnixTimeOffset)
+ {
+ fileTime = 0;
+ return false;
+ }
+ fileTime = UnixTime64_To_FileTime64(unixTime);
+ return true;
+}
+
+
+bool UnixTime64_To_FileTime(Int64 unixTime, FILETIME &ft) throw()
+{
+ UInt64 v;
+ const bool res = UnixTime64_To_FileTime64(unixTime, v);
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+ return res;
+}
+
+
+Int64 FileTime_To_UnixTime64(const FILETIME &ft) throw()
+{
+ const UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
+ return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset;
+}
+
+Int64 FileTime_To_UnixTime64_and_Quantums(const FILETIME &ft, UInt32 &quantums) throw()
+{
+ const UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
+ quantums = (UInt32)(winTime % kNumTimeQuantumsInSecond);
+ return (Int64)(winTime / kNumTimeQuantumsInSecond) - (Int64)kUnixTimeOffset;
+}
+
+bool FileTime_To_UnixTime(const FILETIME &ft, UInt32 &unixTime) throw()
+{
+ UInt64 winTime = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
+ winTime /= kNumTimeQuantumsInSecond;
+ if (winTime < kUnixTimeOffset)
+ {
+ unixTime = 0;
+ return false;
+ }
+ winTime -= kUnixTimeOffset;
+ if (winTime > (UInt32)0xFFFFFFFF)
+ {
+ unixTime = (UInt32)0xFFFFFFFF;
+ return false;
+ }
+ unixTime = (UInt32)winTime;
+ return true;
+}
+
+bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day,
+ unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw()
+{
+ resSeconds = 0;
+ if (year < kFileTimeStartYear || year >= 10000 || month < 1 || month > 12 ||
+ day < 1 || day > 31 || hour > 23 || min > 59 || sec > 59)
+ return false;
+ UInt32 numYears = year - kFileTimeStartYear;
+ UInt32 numDays = numYears * 365 + numYears / 4 - numYears / 100 + numYears / 400;
+ Byte ms[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
+ if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0))
+ ms[1] = 29;
+ month--;
+ for (unsigned i = 0; i < month; i++)
+ numDays += ms[i];
+ numDays += day - 1;
+ resSeconds = ((UInt64)(numDays * 24 + hour) * 60 + min) * 60 + sec;
+ return true;
+}
+
+
+void GetCurUtc_FiTime(CFiTime &ft) throw()
+{
+ #ifdef _WIN32
+
+ // Both variants provide same low resolution on WinXP: about 15 ms.
+ // But GetSystemTimeAsFileTime is much faster.
+ #ifdef UNDER_CE
+ SYSTEMTIME st;
+ GetSystemTime(&st);
+ SystemTimeToFileTime(&st, &ft);
+ #else
+ GetSystemTimeAsFileTime(&ft);
+ #endif
+
+ #else
+
+ FiTime_Clear(ft);
+ struct timeval now;
+ if (gettimeofday(&now, NULL) == 0)
+ {
+ ft.tv_sec = now.tv_sec;
+ ft.tv_nsec = now.tv_usec * 1000;
+ }
+
+ #endif
+}
+
+#ifndef _WIN32
+void GetCurUtcFileTime(FILETIME &ft) throw()
+{
+ UInt64 v = 0;
+ struct timeval now;
+ if (gettimeofday(&now, NULL) == 0)
+ {
+ v = ((UInt64)now.tv_sec + kUnixTimeOffset) *
+ kNumTimeQuantumsInSecond + (UInt64)now.tv_usec * 10;
+ }
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+}
+#endif
+
+
+}}
+
+
+#ifdef _WIN32
+
+/*
+void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec)
+{
+ if (prec == k_PropVar_TimePrec_0
+ || prec == k_PropVar_TimePrec_HighPrec
+ || prec >= k_PropVar_TimePrec_100ns)
+ return;
+ UInt64 v = (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
+
+ int numDigits = (int)prec - (int)k_PropVar_TimePrec_Base;
+ UInt32 d;
+ if (prec == k_PropVar_TimePrec_DOS)
+ {
+ // we round up as windows DosDateTimeToFileTime()
+ v += NWindows::NTime::kNumTimeQuantumsInSecond * 2 - 1;
+ d = NWindows::NTime::kNumTimeQuantumsInSecond * 2;
+ }
+ else
+ {
+ if (prec == k_PropVar_TimePrec_Unix)
+ numDigits = 0;
+ else if (numDigits < 0)
+ return;
+ d = 1;
+ for (unsigned k = numDigits; k < 7; k++)
+ d *= 10;
+ }
+ v /= d;
+ v *= d;
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+}
+*/
+
+#else
+
+/*
+void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec)
+{
+ if (prec >= k_PropVar_TimePrec_1ns
+ || prec == k_PropVar_TimePrec_HighPrec)
+ return;
+
+ int numDigits = (int)prec - (int)k_PropVar_TimePrec_Base;
+ UInt32 d;
+ if (prec == k_PropVar_TimePrec_Unix ||
+ prec == (int)k_PropVar_TimePrec_Base)
+ {
+ ft.tv_nsec = 0;
+ return;
+ }
+ if (prec == k_PropVar_TimePrec_DOS)
+ {
+ // we round up as windows DosDateTimeToFileTime()
+ const unsigned sec1 = (ft.tv_sec & 1);
+ if (ft.tv_nsec == 0 && sec1 == 0)
+ return;
+ ft.tv_nsec = 0;
+ ft.tv_sec += 2 - sec1;
+ return;
+ }
+ {
+ if (prec == k_PropVar_TimePrec_0
+ || numDigits < 0)
+ numDigits = 7;
+ d = 1;
+ for (unsigned k = numDigits; k < 9; k++)
+ d *= 10;
+ ft.tv_nsec /= d;
+ ft.tv_nsec *= d;
+ }
+}
+*/
+
+int Compare_FiTime(const CFiTime *a1, const CFiTime *a2)
+{
+ if (a1->tv_sec < a2->tv_sec) return -1;
+ if (a1->tv_sec > a2->tv_sec) return 1;
+ if (a1->tv_nsec < a2->tv_nsec) return -1;
+ if (a1->tv_nsec > a2->tv_nsec) return 1;
+ return 0;
+}
+
+bool FILETIME_To_timespec(const FILETIME &ft, timespec &ts)
+{
+ UInt32 quantums;
+ const Int64 sec = NWindows::NTime::FileTime_To_UnixTime64_and_Quantums(ft, quantums);
+ // time_t is long
+ const time_t sec2 = (time_t)sec;
+ if (sec2 == sec)
+ {
+ ts.tv_sec = sec2;
+ ts.tv_nsec = (long)(quantums * 100);
+ return true;
+ }
+ return false;
+}
+
+void FiTime_To_FILETIME_ns100(const CFiTime &ts, FILETIME &ft, unsigned &ns100)
+{
+ const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100);
+ ns100 = (unsigned)((UInt64)ts.tv_nsec % 100);
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+}
+
+void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft)
+{
+ const UInt64 v = NWindows::NTime::UnixTime64_To_FileTime64(ts.tv_sec) + ((UInt64)ts.tv_nsec / 100);
+ ft.dwLowDateTime = (DWORD)v;
+ ft.dwHighDateTime = (DWORD)(v >> 32);
+}
+
+#endif
diff --git a/CPP/Windows/TimeUtils.h b/CPP/Windows/TimeUtils.h
index b0092f8..4a9d0f2 100644
--- a/CPP/Windows/TimeUtils.h
+++ b/CPP/Windows/TimeUtils.h
@@ -1,32 +1,146 @@
-// Windows/TimeUtils.h
-
-#ifndef __WINDOWS_TIME_UTILS_H
-#define __WINDOWS_TIME_UTILS_H
-
-#include "../Common/MyTypes.h"
-#include "../Common/MyWindows.h"
-
-namespace NWindows {
-namespace NTime {
-
-bool DosTimeToFileTime(UInt32 dosTime, FILETIME &fileTime) throw();
-bool FileTimeToDosTime(const FILETIME &fileTime, UInt32 &dosTime) throw();
-
-// UInt32 Unix Time : for dates 1970-2106
-UInt64 UnixTimeToFileTime64(UInt32 unixTime) throw();
-void UnixTimeToFileTime(UInt32 unixTime, FILETIME &fileTime) throw();
-
-// Int64 Unix Time : negative values for dates before 1970
-UInt64 UnixTime64ToFileTime64(Int64 unixTime) throw();
-bool UnixTime64ToFileTime(Int64 unixTime, FILETIME &fileTime) throw();
-
-bool FileTimeToUnixTime(const FILETIME &fileTime, UInt32 &unixTime) throw();
-Int64 FileTimeToUnixTime64(const FILETIME &ft) throw();
-
-bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day,
- unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw();
-void GetCurUtcFileTime(FILETIME &ft) throw();
-
-}}
-
-#endif
+// Windows/TimeUtils.h
+
+#ifndef ZIP7_INC_WINDOWS_TIME_UTILS_H
+#define ZIP7_INC_WINDOWS_TIME_UTILS_H
+
+#include "../Common/MyTypes.h"
+#include "../Common/MyWindows.h"
+#include "PropVariant.h"
+
+inline UInt64 FILETIME_To_UInt64(const FILETIME &ft)
+{
+ return (((UInt64)ft.dwHighDateTime) << 32) + ft.dwLowDateTime;
+}
+
+inline void FILETIME_Clear(FILETIME &ft)
+{
+ ft.dwLowDateTime = 0;
+ ft.dwHighDateTime = 0;
+}
+
+inline bool FILETIME_IsZero(const FILETIME &ft)
+{
+ return (ft.dwHighDateTime == 0 && ft.dwLowDateTime == 0);
+}
+
+
+#ifdef _WIN32
+ #define CFiTime FILETIME
+ #define Compare_FiTime ::CompareFileTime
+ inline void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft)
+ {
+ ft = ts;
+ }
+ /*
+ inline void FILETIME_To_FiTime(const FILETIME &ft, CFiTime &ts)
+ {
+ ts = ft;
+ }
+ */
+ inline void FiTime_Clear(CFiTime &ft)
+ {
+ ft.dwLowDateTime = 0;
+ ft.dwHighDateTime = 0;
+ }
+#else
+
+ #include <sys/stat.h>
+
+ #if defined(_AIX)
+ #define CFiTime st_timespec
+ #else
+ #define CFiTime timespec
+ #endif
+ int Compare_FiTime(const CFiTime *a1, const CFiTime *a2);
+ bool FILETIME_To_timespec(const FILETIME &ft, CFiTime &ts);
+ void FiTime_To_FILETIME(const CFiTime &ts, FILETIME &ft);
+ void FiTime_To_FILETIME_ns100(const CFiTime &ts, FILETIME &ft, unsigned &ns100);
+ inline void FiTime_Clear(CFiTime &ft)
+ {
+ ft.tv_sec = 0;
+ ft.tv_nsec = 0;
+ }
+
+ #ifdef __APPLE__
+ #define ST_MTIME(st) st.st_mtimespec
+ #define ST_ATIME(st) st.st_atimespec
+ #define ST_CTIME(st) st.st_ctimespec
+ #else
+ #define ST_MTIME(st) st.st_mtim
+ #define ST_ATIME(st) st.st_atim
+ #define ST_CTIME(st) st.st_ctim
+ #endif
+
+#endif
+
+// void FiTime_Normalize_With_Prec(CFiTime &ft, unsigned prec);
+
+namespace NWindows {
+namespace NTime {
+
+bool DosTime_To_FileTime(UInt32 dosTime, FILETIME &fileTime) throw();
+bool UtcFileTime_To_LocalDosTime(const FILETIME &utc, UInt32 &dosTime) throw();
+bool FileTime_To_DosTime(const FILETIME &fileTime, UInt32 &dosTime) throw();
+
+// UInt32 Unix Time : for dates 1970-2106
+UInt64 UnixTime_To_FileTime64(UInt32 unixTime) throw();
+void UnixTime_To_FileTime(UInt32 unixTime, FILETIME &fileTime) throw();
+
+// Int64 Unix Time : negative values for dates before 1970
+UInt64 UnixTime64_To_FileTime64(Int64 unixTime) throw(); // no check
+bool UnixTime64_To_FileTime64(Int64 unixTime, UInt64 &fileTime) throw();
+bool UnixTime64_To_FileTime(Int64 unixTime, FILETIME &fileTime) throw();
+
+Int64 FileTime64_To_UnixTime64(UInt64 ft64) throw();
+bool FileTime_To_UnixTime(const FILETIME &fileTime, UInt32 &unixTime) throw();
+Int64 FileTime_To_UnixTime64(const FILETIME &ft) throw();
+Int64 FileTime_To_UnixTime64_and_Quantums(const FILETIME &ft, UInt32 &quantums) throw();
+
+bool GetSecondsSince1601(unsigned year, unsigned month, unsigned day,
+ unsigned hour, unsigned min, unsigned sec, UInt64 &resSeconds) throw();
+
+void GetCurUtc_FiTime(CFiTime &ft) throw();
+#ifdef _WIN32
+#define GetCurUtcFileTime GetCurUtc_FiTime
+#else
+void GetCurUtcFileTime(FILETIME &ft) throw();
+#endif
+
+}}
+
+inline void PropVariant_SetFrom_UnixTime(NWindows::NCOM::CPropVariant &prop, UInt32 unixTime)
+{
+ FILETIME ft;
+ NWindows::NTime::UnixTime_To_FileTime(unixTime, ft);
+ prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_Unix);
+}
+
+inline void PropVariant_SetFrom_NtfsTime(NWindows::NCOM::CPropVariant &prop, const FILETIME &ft)
+{
+ prop.SetAsTimeFrom_FT_Prec(ft, k_PropVar_TimePrec_100ns);
+}
+
+inline void PropVariant_SetFrom_FiTime(NWindows::NCOM::CPropVariant &prop, const CFiTime &fts)
+{
+ #ifdef _WIN32
+ PropVariant_SetFrom_NtfsTime(prop, fts);
+ #else
+ unsigned ns100;
+ FILETIME ft;
+ FiTime_To_FILETIME_ns100(fts, ft, ns100);
+ prop.SetAsTimeFrom_FT_Prec_Ns100(ft, k_PropVar_TimePrec_1ns, ns100);
+ #endif
+}
+
+inline bool PropVariant_SetFrom_DosTime(NWindows::NCOM::CPropVariant &prop, UInt32 dosTime)
+{
+ FILETIME localFileTime, utc;
+ if (!NWindows::NTime::DosTime_To_FileTime(dosTime, localFileTime))
+ return false;
+ if (!LocalFileTimeToFileTime(&localFileTime, &utc))
+ return false;
+ prop.SetAsTimeFrom_FT_Prec(utc, k_PropVar_TimePrec_DOS);
+ return true;
+}
+
+#endif
diff --git a/CPP/Windows/Window.cpp b/CPP/Windows/Window.cpp
index 0c74222..102c503 100644
--- a/CPP/Windows/Window.cpp
+++ b/CPP/Windows/Window.cpp
@@ -1,179 +1,179 @@
-// Windows/Window.cpp
-
-#include "StdAfx.h"
-
-#ifndef _UNICODE
-#include "../Common/StringConvert.h"
-#endif
-#include "Window.h"
-
-#ifndef _UNICODE
-extern bool g_IsNT;
-#endif
-
-namespace NWindows {
-
-#ifndef _UNICODE
-ATOM MyRegisterClass(CONST WNDCLASSW *wndClass)
-{
- if (g_IsNT)
- return RegisterClassW(wndClass);
- WNDCLASSA wndClassA;
- wndClassA.style = wndClass->style;
- wndClassA.lpfnWndProc = wndClass->lpfnWndProc;
- wndClassA.cbClsExtra = wndClass->cbClsExtra;
- wndClassA.cbWndExtra = wndClass->cbWndExtra;
- wndClassA.hInstance = wndClass->hInstance;
- wndClassA.hIcon = wndClass->hIcon;
- wndClassA.hCursor = wndClass->hCursor;
- wndClassA.hbrBackground = wndClass->hbrBackground;
- AString menuName;
- AString className;
- if (IS_INTRESOURCE(wndClass->lpszMenuName))
- wndClassA.lpszMenuName = (LPCSTR)wndClass->lpszMenuName;
- else
- {
- menuName = GetSystemString(wndClass->lpszMenuName);
- wndClassA.lpszMenuName = menuName;
- }
- if (IS_INTRESOURCE(wndClass->lpszClassName))
- wndClassA.lpszClassName = (LPCSTR)wndClass->lpszClassName;
- else
- {
- className = GetSystemString(wndClass->lpszClassName);
- wndClassA.lpszClassName = className;
- }
- return RegisterClassA(&wndClassA);
-}
-
-bool CWindow::Create(LPCWSTR className,
- LPCWSTR windowName, DWORD style,
- int x, int y, int width, int height,
- HWND parentWindow, HMENU idOrHMenu,
- HINSTANCE instance, LPVOID createParam)
-{
- if (g_IsNT)
- {
- _window = ::CreateWindowW(className, windowName,
- style, x, y, width, height, parentWindow,
- idOrHMenu, instance, createParam);
- return (_window != NULL);
- }
- return Create(GetSystemString(className), GetSystemString(windowName),
- style, x, y, width, height, parentWindow,
- idOrHMenu, instance, createParam);
-}
-
-bool CWindow::CreateEx(DWORD exStyle, LPCWSTR className,
- LPCWSTR windowName, DWORD style,
- int x, int y, int width, int height,
- HWND parentWindow, HMENU idOrHMenu,
- HINSTANCE instance, LPVOID createParam)
-{
- if (g_IsNT)
- {
- _window = ::CreateWindowExW(exStyle, className, windowName,
- style, x, y, width, height, parentWindow,
- idOrHMenu, instance, createParam);
- return (_window != NULL);
- }
- AString classNameA;
- LPCSTR classNameP;
- if (IS_INTRESOURCE(className))
- classNameP = (LPCSTR)className;
- else
- {
- classNameA = GetSystemString(className);
- classNameP = classNameA;
- }
- AString windowNameA;
- LPCSTR windowNameP;
- if (IS_INTRESOURCE(windowName))
- windowNameP = (LPCSTR)windowName;
- else
- {
- windowNameA = GetSystemString(windowName);
- windowNameP = windowNameA;
- }
- return CreateEx(exStyle, classNameP, windowNameP,
- style, x, y, width, height, parentWindow,
- idOrHMenu, instance, createParam);
-}
-
-#endif
-
-#ifndef _UNICODE
-bool MySetWindowText(HWND wnd, LPCWSTR s)
-{
- if (g_IsNT)
- return BOOLToBool(::SetWindowTextW(wnd, s));
- return BOOLToBool(::SetWindowTextA(wnd, UnicodeStringToMultiByte(s)));
-}
-#endif
-
-bool CWindow::GetText(CSysString &s)
-{
- s.Empty();
- int len = GetTextLength();
- if (len == 0)
- return (::GetLastError() == ERROR_SUCCESS);
- TCHAR *p = s.GetBuf(len);
- {
- int len2 = GetText(p, len + 1);
- if (len > len2)
- len = len2;
- }
- s.ReleaseBuf_CalcLen(len);
- if (len == 0)
- return (::GetLastError() == ERROR_SUCCESS);
- return true;
-}
-
-#ifndef _UNICODE
-bool CWindow::GetText(UString &s)
-{
- if (g_IsNT)
- {
- s.Empty();
- int len = GetWindowTextLengthW(_window);
- if (len == 0)
- return (::GetLastError() == ERROR_SUCCESS);
- wchar_t *p = s.GetBuf(len);
- {
- int len2 = GetWindowTextW(_window, p, len + 1);
- if (len > len2)
- len = len2;
- }
- s.ReleaseBuf_CalcLen(len);
- if (len == 0)
- return (::GetLastError() == ERROR_SUCCESS);
- return true;
- }
- CSysString sysString;
- bool result = GetText(sysString);
- MultiByteToUnicodeString2(s, sysString);
- return result;
-}
-#endif
-
-
-/*
-bool CWindow::ModifyStyleBase(int styleOffset,
- DWORD remove, DWORD add, UINT flags)
-{
- DWORD style = GetWindowLong(styleOffset);
- DWORD newStyle = (style & ~remove) | add;
- if (style == newStyle)
- return false; // it is not good
-
- SetWindowLong(styleOffset, newStyle);
- if (flags != 0)
- {
- ::SetWindowPos(_window, NULL, 0, 0, 0, 0,
- SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | flags);
- }
- return TRUE;
-}
-*/
-
-}
+// Windows/Window.cpp
+
+#include "StdAfx.h"
+
+#ifndef _UNICODE
+#include "../Common/StringConvert.h"
+#endif
+#include "Window.h"
+
+#ifndef _UNICODE
+extern bool g_IsNT;
+#endif
+
+namespace NWindows {
+
+#ifndef _UNICODE
+ATOM MyRegisterClass(CONST WNDCLASSW *wndClass)
+{
+ if (g_IsNT)
+ return RegisterClassW(wndClass);
+ WNDCLASSA wndClassA;
+ wndClassA.style = wndClass->style;
+ wndClassA.lpfnWndProc = wndClass->lpfnWndProc;
+ wndClassA.cbClsExtra = wndClass->cbClsExtra;
+ wndClassA.cbWndExtra = wndClass->cbWndExtra;
+ wndClassA.hInstance = wndClass->hInstance;
+ wndClassA.hIcon = wndClass->hIcon;
+ wndClassA.hCursor = wndClass->hCursor;
+ wndClassA.hbrBackground = wndClass->hbrBackground;
+ AString menuName;
+ AString className;
+ if (IS_INTRESOURCE(wndClass->lpszMenuName))
+ wndClassA.lpszMenuName = (LPCSTR)wndClass->lpszMenuName;
+ else
+ {
+ menuName = GetSystemString(wndClass->lpszMenuName);
+ wndClassA.lpszMenuName = menuName;
+ }
+ if (IS_INTRESOURCE(wndClass->lpszClassName))
+ wndClassA.lpszClassName = (LPCSTR)wndClass->lpszClassName;
+ else
+ {
+ className = GetSystemString(wndClass->lpszClassName);
+ wndClassA.lpszClassName = className;
+ }
+ return RegisterClassA(&wndClassA);
+}
+
+bool CWindow::Create(LPCWSTR className,
+ LPCWSTR windowName, DWORD style,
+ int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu,
+ HINSTANCE instance, LPVOID createParam)
+{
+ if (g_IsNT)
+ {
+ _window = ::CreateWindowW(className, windowName,
+ style, x, y, width, height, parentWindow,
+ idOrHMenu, instance, createParam);
+ return (_window != NULL);
+ }
+ return Create(GetSystemString(className), GetSystemString(windowName),
+ style, x, y, width, height, parentWindow,
+ idOrHMenu, instance, createParam);
+}
+
+bool CWindow::CreateEx(DWORD exStyle, LPCWSTR className,
+ LPCWSTR windowName, DWORD style,
+ int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu,
+ HINSTANCE instance, LPVOID createParam)
+{
+ if (g_IsNT)
+ {
+ _window = ::CreateWindowExW(exStyle, className, windowName,
+ style, x, y, width, height, parentWindow,
+ idOrHMenu, instance, createParam);
+ return (_window != NULL);
+ }
+ AString classNameA;
+ LPCSTR classNameP;
+ if (IS_INTRESOURCE(className))
+ classNameP = (LPCSTR)className;
+ else
+ {
+ classNameA = GetSystemString(className);
+ classNameP = classNameA;
+ }
+ AString windowNameA;
+ LPCSTR windowNameP;
+ if (IS_INTRESOURCE(windowName))
+ windowNameP = (LPCSTR)windowName;
+ else
+ {
+ windowNameA = GetSystemString(windowName);
+ windowNameP = windowNameA;
+ }
+ return CreateEx(exStyle, classNameP, windowNameP,
+ style, x, y, width, height, parentWindow,
+ idOrHMenu, instance, createParam);
+}
+
+#endif
+
+#ifndef _UNICODE
+bool MySetWindowText(HWND wnd, LPCWSTR s)
+{
+ if (g_IsNT)
+ return BOOLToBool(::SetWindowTextW(wnd, s));
+ return BOOLToBool(::SetWindowTextA(wnd, UnicodeStringToMultiByte(s)));
+}
+#endif
+
+bool CWindow::GetText(CSysString &s) const
+{
+ s.Empty();
+ unsigned len = (unsigned)GetTextLength();
+ if (len == 0)
+ return (::GetLastError() == ERROR_SUCCESS);
+ TCHAR *p = s.GetBuf(len);
+ {
+ const unsigned len2 = (unsigned)GetText(p, (int)(len + 1));
+ if (len > len2)
+ len = len2;
+ }
+ s.ReleaseBuf_CalcLen(len);
+ if (len == 0)
+ return (::GetLastError() == ERROR_SUCCESS);
+ return true;
+}
+
+#ifndef _UNICODE
+bool CWindow::GetText(UString &s) const
+{
+ if (g_IsNT)
+ {
+ s.Empty();
+ unsigned len = (unsigned)GetWindowTextLengthW(_window);
+ if (len == 0)
+ return (::GetLastError() == ERROR_SUCCESS);
+ wchar_t *p = s.GetBuf(len);
+ {
+ const unsigned len2 = (unsigned)GetWindowTextW(_window, p, (int)(len + 1));
+ if (len > len2)
+ len = len2;
+ }
+ s.ReleaseBuf_CalcLen(len);
+ if (len == 0)
+ return (::GetLastError() == ERROR_SUCCESS);
+ return true;
+ }
+ CSysString sysString;
+ const bool result = GetText(sysString);
+ MultiByteToUnicodeString2(s, sysString);
+ return result;
+}
+#endif
+
+
+/*
+bool CWindow::ModifyStyleBase(int styleOffset,
+ DWORD remove, DWORD add, UINT flags)
+{
+ DWORD style = GetWindowLong(styleOffset);
+ DWORD newStyle = (style & ~remove) | add;
+ if (style == newStyle)
+ return false; // it is not good
+
+ SetWindowLong(styleOffset, newStyle);
+ if (flags != 0)
+ {
+ ::SetWindowPos(_window, NULL, 0, 0, 0, 0,
+ SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | flags);
+ }
+ return TRUE;
+}
+*/
+
+}
diff --git a/CPP/Windows/Window.h b/CPP/Windows/Window.h
index 4c80a5b..a99143b 100644
--- a/CPP/Windows/Window.h
+++ b/CPP/Windows/Window.h
@@ -1,284 +1,363 @@
-// Windows/Window.h
-
-#ifndef __WINDOWS_WINDOW_H
-#define __WINDOWS_WINDOW_H
-
-#include "../Common/MyWindows.h"
-#include "../Common/MyString.h"
-
-#include "Defs.h"
-
-#ifndef UNDER_CE
-
-#define MY__WM_CHANGEUISTATE 0x0127
-#define MY__WM_UPDATEUISTATE 0x0128
-#define MY__WM_QUERYUISTATE 0x0129
-
-// LOWORD(wParam) values in WM_*UISTATE
-#define MY__UIS_SET 1
-#define MY__UIS_CLEAR 2
-#define MY__UIS_INITIALIZE 3
-
-// HIWORD(wParam) values in WM_*UISTATE
-#define MY__UISF_HIDEFOCUS 0x1
-#define MY__UISF_HIDEACCEL 0x2
-#define MY__UISF_ACTIVE 0x4
-
-#endif
-
-namespace NWindows {
-
-inline ATOM MyRegisterClass(CONST WNDCLASS *wndClass)
- { return ::RegisterClass(wndClass); }
-
-#ifndef _UNICODE
-ATOM MyRegisterClass(CONST WNDCLASSW *wndClass);
-#endif
-
-#ifdef _UNICODE
-inline bool MySetWindowText(HWND wnd, LPCWSTR s) { return BOOLToBool(::SetWindowText(wnd, s)); }
-#else
-bool MySetWindowText(HWND wnd, LPCWSTR s);
-#endif
-
-
-#ifdef UNDER_CE
-#define GWLP_USERDATA GWL_USERDATA
-#define GWLP_WNDPROC GWL_WNDPROC
-#define BTNS_BUTTON TBSTYLE_BUTTON
-#define WC_COMBOBOXW L"ComboBox"
-#define DWLP_MSGRESULT DWL_MSGRESULT
-#endif
-
-class CWindow
-{
-private:
- // bool ModifyStyleBase(int styleOffset, DWORD remove, DWORD add, UINT flags);
-protected:
- HWND _window;
-public:
- CWindow(HWND newWindow = NULL): _window(newWindow){};
- CWindow& operator=(HWND newWindow)
- {
- _window = newWindow;
- return *this;
- }
- operator HWND() const { return _window; }
- void Attach(HWND newWindow) { _window = newWindow; }
- HWND Detach()
- {
- HWND window = _window;
- _window = NULL;
- return window;
- }
-
- bool Foreground() { return BOOLToBool(::SetForegroundWindow(_window)); }
-
- HWND GetParent() const { return ::GetParent(_window); }
- bool GetWindowRect(LPRECT rect) const { return BOOLToBool(::GetWindowRect(_window,rect)); }
- #ifndef UNDER_CE
- bool IsZoomed() const { return BOOLToBool(::IsZoomed(_window)); }
- #endif
- bool ClientToScreen(LPPOINT point) const { return BOOLToBool(::ClientToScreen(_window, point)); }
- bool ScreenToClient(LPPOINT point) const { return BOOLToBool(::ScreenToClient(_window, point)); }
-
- bool CreateEx(DWORD exStyle, LPCTSTR className,
- LPCTSTR windowName, DWORD style,
- int x, int y, int width, int height,
- HWND parentWindow, HMENU idOrHMenu,
- HINSTANCE instance, LPVOID createParam)
- {
- _window = ::CreateWindowEx(exStyle, className, windowName,
- style, x, y, width, height, parentWindow,
- idOrHMenu, instance, createParam);
- return (_window != NULL);
- }
-
- bool Create(LPCTSTR className,
- LPCTSTR windowName, DWORD style,
- int x, int y, int width, int height,
- HWND parentWindow, HMENU idOrHMenu,
- HINSTANCE instance, LPVOID createParam)
- {
- _window = ::CreateWindow(className, windowName,
- style, x, y, width, height, parentWindow,
- idOrHMenu, instance, createParam);
- return (_window != NULL);
- }
-
- #ifndef _UNICODE
- bool Create(LPCWSTR className,
- LPCWSTR windowName, DWORD style,
- int x, int y, int width, int height,
- HWND parentWindow, HMENU idOrHMenu,
- HINSTANCE instance, LPVOID createParam);
- bool CreateEx(DWORD exStyle, LPCWSTR className,
- LPCWSTR windowName, DWORD style,
- int x, int y, int width, int height,
- HWND parentWindow, HMENU idOrHMenu,
- HINSTANCE instance, LPVOID createParam);
- #endif
-
-
- bool Destroy()
- {
- if (_window == NULL)
- return true;
- bool result = BOOLToBool(::DestroyWindow(_window));
- if (result)
- _window = NULL;
- return result;
- }
- bool IsWindow() { return BOOLToBool(::IsWindow(_window)); }
- bool Move(int x, int y, int width, int height, bool repaint = true)
- { return BOOLToBool(::MoveWindow(_window, x, y, width, height, BoolToBOOL(repaint))); }
-
- bool ChangeSubWindowSizeX(HWND hwnd, int xSize)
- {
- RECT rect;
- ::GetWindowRect(hwnd, &rect);
- POINT p1;
- p1.x = rect.left;
- p1.y = rect.top;
- ScreenToClient(&p1);
- return BOOLToBool(::MoveWindow(hwnd, p1.x, p1.y, xSize, rect.bottom - rect.top, TRUE));
- }
-
- void ScreenToClient(RECT *rect)
- {
- POINT p1, p2;
- p1.x = rect->left;
- p1.y = rect->top;
- p2.x = rect->right;
- p2.y = rect->bottom;
- ScreenToClient(&p1);
- ScreenToClient(&p2);
-
- rect->left = p1.x;
- rect->top = p1.y;
- rect->right = p2.x;
- rect->bottom = p2.y;
- }
-
- bool GetClientRect(LPRECT rect) { return BOOLToBool(::GetClientRect(_window, rect)); }
- bool Show(int cmdShow) { return BOOLToBool(::ShowWindow(_window, cmdShow)); }
- bool Show_Bool(bool show) { return Show(show ? SW_SHOW: SW_HIDE); }
-
- #ifndef UNDER_CE
- bool SetPlacement(CONST WINDOWPLACEMENT *placement) { return BOOLToBool(::SetWindowPlacement(_window, placement)); }
- bool GetPlacement(WINDOWPLACEMENT *placement) { return BOOLToBool(::GetWindowPlacement(_window, placement)); }
- #endif
- bool Update() { return BOOLToBool(::UpdateWindow(_window)); }
- bool InvalidateRect(LPCRECT rect, bool backgroundErase = true)
- { return BOOLToBool(::InvalidateRect(_window, rect, BoolToBOOL(backgroundErase))); }
- void SetRedraw(bool redraw = true) { SendMsg(WM_SETREDRAW, BoolToBOOL(redraw), 0); }
-
- LONG_PTR SetStyle(LONG_PTR style) { return SetLongPtr(GWL_STYLE, style); }
- LONG_PTR GetStyle() const { return GetLongPtr(GWL_STYLE); }
- // bool MyIsMaximized() const { return ((GetStyle() & WS_MAXIMIZE) != 0); }
-
- LONG_PTR SetLong(int index, LONG newLongPtr) { return ::SetWindowLong(_window, index, newLongPtr); }
- LONG_PTR GetLong(int index) const { return ::GetWindowLong(_window, index); }
- LONG_PTR SetUserDataLong(LONG newLongPtr) { return SetLong(GWLP_USERDATA, newLongPtr); }
- LONG_PTR GetUserDataLong() const { return GetLong(GWLP_USERDATA); }
-
-
- #ifdef UNDER_CE
-
- LONG_PTR SetLongPtr(int index, LONG_PTR newLongPtr) { return SetLong(index, newLongPtr); }
- LONG_PTR GetLongPtr(int index) const { return GetLong(index); }
-
- LONG_PTR SetUserDataLongPtr(LONG_PTR newLongPtr) { return SetUserDataLong(newLongPtr); }
- LONG_PTR GetUserDataLongPtr() const { return GetUserDataLong(); }
-
- #else
-
- LONG_PTR SetLongPtr(int index, LONG_PTR newLongPtr)
- { return ::SetWindowLongPtr(_window, index,
- #ifndef _WIN64
- (LONG)
- #endif
- newLongPtr); }
- #ifndef _UNICODE
- LONG_PTR SetLongPtrW(int index, LONG_PTR newLongPtr)
- { return ::SetWindowLongPtrW(_window, index,
- #ifndef _WIN64
- (LONG)
- #endif
- newLongPtr); }
- #endif
-
- LONG_PTR GetLongPtr(int index) const { return ::GetWindowLongPtr(_window, index); }
- LONG_PTR SetUserDataLongPtr(LONG_PTR newLongPtr) { return SetLongPtr(GWLP_USERDATA, newLongPtr); }
- LONG_PTR GetUserDataLongPtr() const { return GetLongPtr(GWLP_USERDATA); }
-
- #endif
-
- /*
- bool ModifyStyle(HWND hWnd, DWORD remove, DWORD add, UINT flags = 0)
- { return ModifyStyleBase(GWL_STYLE, remove, add, flags); }
- bool ModifyStyleEx(HWND hWnd, DWORD remove, DWORD add, UINT flags = 0)
- { return ModifyStyleBase(GWL_EXSTYLE, remove, add, flags); }
- */
-
- HWND SetFocus() { return ::SetFocus(_window); }
-
- LRESULT SendMsg(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
- { return ::SendMessage(_window, message, wParam, lParam); }
- #ifndef _UNICODE
- LRESULT SendMsgW(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
- { return ::SendMessageW(_window, message, wParam, lParam); }
- #endif
-
- bool PostMsg(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
- { return BOOLToBool(::PostMessage(_window, message, wParam, lParam)); }
- #ifndef _UNICODE
- bool PostMsgW(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
- { return BOOLToBool(::PostMessageW(_window, message, wParam, lParam)); }
- #endif
-
- bool SetText(LPCTSTR s) { return BOOLToBool(::SetWindowText(_window, s)); }
- #ifndef _UNICODE
- bool SetText(LPCWSTR s) { return MySetWindowText(_window, s); }
- #endif
-
- int GetTextLength() const
- { return GetWindowTextLength(_window); }
- UINT GetText(LPTSTR string, int maxCount) const
- { return GetWindowText(_window, string, maxCount); }
- bool GetText(CSysString &s);
- #ifndef _UNICODE
- /*
- UINT GetText(LPWSTR string, int maxCount) const
- { return GetWindowTextW(_window, string, maxCount); }
- */
- bool GetText(UString &s);
- #endif
-
- bool Enable(bool enable)
- { return BOOLToBool(::EnableWindow(_window, BoolToBOOL(enable))); }
-
- bool IsEnabled()
- { return BOOLToBool(::IsWindowEnabled(_window)); }
-
- #ifndef UNDER_CE
- HMENU GetSystemMenu(bool revert)
- { return ::GetSystemMenu(_window, BoolToBOOL(revert)); }
- #endif
-
- UINT_PTR SetTimer(UINT_PTR idEvent, UINT elapse, TIMERPROC timerFunc = 0)
- { return ::SetTimer(_window, idEvent, elapse, timerFunc); }
- bool KillTimer(UINT_PTR idEvent)
- {return BOOLToBool(::KillTimer(_window, idEvent)); }
-
- HICON SetIcon(WPARAM sizeType, HICON icon) { return (HICON)SendMsg(WM_SETICON, sizeType, (LPARAM)icon); }
-};
-
-#define RECT_SIZE_X(r) ((r).right - (r).left)
-#define RECT_SIZE_Y(r) ((r).bottom - (r).top)
-
-inline bool IsKeyDown(int virtKey) { return (::GetKeyState(virtKey) & 0x8000) != 0; }
-
-}
-
-#endif
+// Windows/Window.h
+
+#ifndef ZIP7_INC_WINDOWS_WINDOW_H
+#define ZIP7_INC_WINDOWS_WINDOW_H
+
+#include "../Common/MyWindows.h"
+#include "../Common/MyString.h"
+
+#include "Defs.h"
+
+#ifndef UNDER_CE
+#ifdef WM_CHANGEUISTATE
+#define Z7_WIN_WM_CHANGEUISTATE WM_CHANGEUISTATE
+#define Z7_WIN_WM_UPDATEUISTATE WM_UPDATEUISTATE
+#define Z7_WIN_WM_QUERYUISTATE WM_QUERYUISTATE
+#else
+// these are defined for (_WIN32_WINNT >= 0x0500):
+#define Z7_WIN_WM_CHANGEUISTATE 0x0127
+#define Z7_WIN_WM_UPDATEUISTATE 0x0128
+#define Z7_WIN_WM_QUERYUISTATE 0x0129
+#endif
+
+#ifdef UIS_SET
+
+#define Z7_WIN_UIS_SET UIS_SET
+#define Z7_WIN_UIS_CLEAR UIS_CLEAR
+#define Z7_WIN_UIS_INITIALIZE UIS_INITIALIZE
+
+#define Z7_WIN_UISF_HIDEFOCUS UISF_HIDEFOCUS
+#define Z7_WIN_UISF_HIDEACCEL UISF_HIDEACCEL
+
+#else
+// these are defined for (_WIN32_WINNT >= 0x0500):
+// LOWORD(wParam) values in WM_*UISTATE
+#define Z7_WIN_UIS_SET 1
+#define Z7_WIN_UIS_CLEAR 2
+#define Z7_WIN_UIS_INITIALIZE 3
+
+// HIWORD(wParam) values in WM_*UISTATE
+#define Z7_WIN_UISF_HIDEFOCUS 0x1
+#define Z7_WIN_UISF_HIDEACCEL 0x2
+// defined for for (_WIN32_WINNT >= 0x0501):
+// #define Z7_WIN_UISF_ACTIVE 0x4
+
+#endif
+
+#endif // UNDER_CE
+
+
+#ifdef Z7_OLD_WIN_SDK
+
+// #define VK_OEM_1 0xBA // ';:' for US
+#define VK_OEM_PLUS 0xBB // '+' any country
+// #define VK_OEM_COMMA 0xBC // ',' any country
+#define VK_OEM_MINUS 0xBD // '-' any country
+// #define VK_OEM_PERIOD 0xBE // '.' any country
+// #define VK_OEM_2 0xBF // '/?' for US
+// #define VK_OEM_3 0xC0 // '`~' for US
+
+// #ifndef GWLP_USERDATA
+#define GWLP_WNDPROC (-4)
+#define GWLP_USERDATA (-21)
+// #endif
+#define DWLP_MSGRESULT 0
+// #define DWLP_DLGPROC DWLP_MSGRESULT + sizeof(LRESULT)
+// #define DWLP_USER DWLP_DLGPROC + sizeof(DLGPROC)
+
+#define BTNS_BUTTON TBSTYLE_BUTTON // 0x0000
+
+/*
+vc6 defines INT_PTR via long:
+ typedef long INT_PTR, *PINT_PTR;
+ typedef unsigned long UINT_PTR, *PUINT_PTR;
+but newer sdk (sdk2003+) defines INT_PTR via int:
+ typedef _W64 int INT_PTR, *PINT_PTR;
+ typedef _W64 unsigned int UINT_PTR, *PUINT_PTR;
+*/
+
+#define IS_INTRESOURCE(_r) (((ULONG_PTR)(_r) >> 16) == 0)
+
+#define GetWindowLongPtrA GetWindowLongA
+#define GetWindowLongPtrW GetWindowLongW
+#ifdef UNICODE
+#define GetWindowLongPtr GetWindowLongPtrW
+#else
+#define GetWindowLongPtr GetWindowLongPtrA
+#endif // !UNICODE
+
+#define SetWindowLongPtrA SetWindowLongA
+#define SetWindowLongPtrW SetWindowLongW
+#ifdef UNICODE
+#define SetWindowLongPtr SetWindowLongPtrW
+#else
+#define SetWindowLongPtr SetWindowLongPtrA
+#endif // !UNICODE
+
+#define ListView_SetCheckState(hwndLV, i, fCheck) \
+ ListView_SetItemState(hwndLV, i, INDEXTOSTATEIMAGEMASK((fCheck)?2:1), LVIS_STATEIMAGEMASK)
+
+#endif // Z7_OLD_WIN_SDK
+
+inline bool LRESULTToBool(LRESULT v) { return (v != FALSE); }
+
+#define MY_int_TO_WPARAM(i) ((WPARAM)(INT_PTR)(i))
+
+namespace NWindows {
+
+inline ATOM MyRegisterClass(CONST WNDCLASS *wndClass)
+ { return ::RegisterClass(wndClass); }
+
+#ifndef _UNICODE
+ATOM MyRegisterClass(CONST WNDCLASSW *wndClass);
+#endif
+
+#ifdef _UNICODE
+inline bool MySetWindowText(HWND wnd, LPCWSTR s) { return BOOLToBool(::SetWindowText(wnd, s)); }
+#else
+bool MySetWindowText(HWND wnd, LPCWSTR s);
+#endif
+
+
+#ifdef UNDER_CE
+#define GWLP_USERDATA GWL_USERDATA
+#define GWLP_WNDPROC GWL_WNDPROC
+#define BTNS_BUTTON TBSTYLE_BUTTON
+#define WC_COMBOBOXW L"ComboBox"
+#define DWLP_MSGRESULT DWL_MSGRESULT
+#endif
+
+class CWindow
+{
+ Z7_CLASS_NO_COPY(CWindow)
+private:
+ // bool ModifyStyleBase(int styleOffset, DWORD remove, DWORD add, UINT flags);
+protected:
+ HWND _window;
+public:
+ CWindow(HWND newWindow = NULL): _window(newWindow) {}
+ CWindow& operator=(HWND newWindow)
+ {
+ _window = newWindow;
+ return *this;
+ }
+ operator HWND() const { return _window; }
+ void Attach(HWND newWindow) { _window = newWindow; }
+ HWND Detach()
+ {
+ HWND window = _window;
+ _window = NULL;
+ return window;
+ }
+
+ bool Foreground() { return BOOLToBool(::SetForegroundWindow(_window)); }
+
+ HWND GetParent() const { return ::GetParent(_window); }
+ bool GetWindowRect(LPRECT rect) const { return BOOLToBool(::GetWindowRect(_window,rect)); }
+ #ifndef UNDER_CE
+ bool IsZoomed() const { return BOOLToBool(::IsZoomed(_window)); }
+ #endif
+ bool ClientToScreen(LPPOINT point) const { return BOOLToBool(::ClientToScreen(_window, point)); }
+ bool ScreenToClient(LPPOINT point) const { return BOOLToBool(::ScreenToClient(_window, point)); }
+
+ bool CreateEx(DWORD exStyle, LPCTSTR className,
+ LPCTSTR windowName, DWORD style,
+ int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu,
+ HINSTANCE instance, LPVOID createParam)
+ {
+ _window = ::CreateWindowEx(exStyle, className, windowName,
+ style, x, y, width, height, parentWindow,
+ idOrHMenu, instance, createParam);
+ return (_window != NULL);
+ }
+
+ bool Create(LPCTSTR className,
+ LPCTSTR windowName, DWORD style,
+ int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu,
+ HINSTANCE instance, LPVOID createParam)
+ {
+ _window = ::CreateWindow(className, windowName,
+ style, x, y, width, height, parentWindow,
+ idOrHMenu, instance, createParam);
+ return (_window != NULL);
+ }
+
+ #ifndef _UNICODE
+ bool Create(LPCWSTR className,
+ LPCWSTR windowName, DWORD style,
+ int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu,
+ HINSTANCE instance, LPVOID createParam);
+ bool CreateEx(DWORD exStyle, LPCWSTR className,
+ LPCWSTR windowName, DWORD style,
+ int x, int y, int width, int height,
+ HWND parentWindow, HMENU idOrHMenu,
+ HINSTANCE instance, LPVOID createParam);
+ #endif
+
+
+ bool Destroy()
+ {
+ if (_window == NULL)
+ return true;
+ bool result = BOOLToBool(::DestroyWindow(_window));
+ if (result)
+ _window = NULL;
+ return result;
+ }
+ bool IsWindow() { return BOOLToBool(::IsWindow(_window)); }
+ bool Move(int x, int y, int width, int height, bool repaint = true)
+ { return BOOLToBool(::MoveWindow(_window, x, y, width, height, BoolToBOOL(repaint))); }
+
+ bool ChangeSubWindowSizeX(HWND hwnd, int xSize)
+ {
+ RECT rect;
+ ::GetWindowRect(hwnd, &rect);
+ POINT p1;
+ p1.x = rect.left;
+ p1.y = rect.top;
+ ScreenToClient(&p1);
+ return BOOLToBool(::MoveWindow(hwnd, p1.x, p1.y, xSize, rect.bottom - rect.top, TRUE));
+ }
+
+ void ScreenToClient(RECT *rect)
+ {
+ POINT p1, p2;
+ p1.x = rect->left;
+ p1.y = rect->top;
+ p2.x = rect->right;
+ p2.y = rect->bottom;
+ ScreenToClient(&p1);
+ ScreenToClient(&p2);
+
+ rect->left = p1.x;
+ rect->top = p1.y;
+ rect->right = p2.x;
+ rect->bottom = p2.y;
+ }
+
+ bool GetClientRect(LPRECT rect) { return BOOLToBool(::GetClientRect(_window, rect)); }
+ bool Show(int cmdShow) { return BOOLToBool(::ShowWindow(_window, cmdShow)); }
+ bool Show_Bool(bool show) { return Show(show ? SW_SHOW: SW_HIDE); }
+
+ #ifndef UNDER_CE
+ bool SetPlacement(CONST WINDOWPLACEMENT *placement) { return BOOLToBool(::SetWindowPlacement(_window, placement)); }
+ bool GetPlacement(WINDOWPLACEMENT *placement) { return BOOLToBool(::GetWindowPlacement(_window, placement)); }
+ #endif
+ bool Update() { return BOOLToBool(::UpdateWindow(_window)); }
+ bool InvalidateRect(LPCRECT rect, bool backgroundErase = true)
+ { return BOOLToBool(::InvalidateRect(_window, rect, BoolToBOOL(backgroundErase))); }
+ void SetRedraw(bool redraw = true) { SendMsg(WM_SETREDRAW, (WPARAM)BoolToBOOL(redraw), 0); }
+
+ LONG_PTR SetStyle(LONG_PTR style) { return SetLongPtr(GWL_STYLE, style); }
+ // LONG_PTR SetStyle(DWORD style) { return SetLongPtr(GWL_STYLE, (LONG_PTR)style); }
+ LONG_PTR GetStyle() const { return GetLongPtr(GWL_STYLE); }
+ // bool MyIsMaximized() const { return ((GetStyle() & WS_MAXIMIZE) != 0); }
+
+ LONG_PTR SetLong(int index, LONG newLongPtr) { return ::SetWindowLong(_window, index, newLongPtr); }
+ LONG_PTR GetLong(int index) const { return ::GetWindowLong(_window, index); }
+ LONG_PTR SetUserDataLong(LONG newLongPtr) { return SetLong(GWLP_USERDATA, newLongPtr); }
+ LONG_PTR GetUserDataLong() const { return GetLong(GWLP_USERDATA); }
+
+
+ #ifdef UNDER_CE
+
+ LONG_PTR SetLongPtr(int index, LONG_PTR newLongPtr) { return SetLong(index, newLongPtr); }
+ LONG_PTR GetLongPtr(int index) const { return GetLong(index); }
+
+ LONG_PTR SetUserDataLongPtr(LONG_PTR newLongPtr) { return SetUserDataLong(newLongPtr); }
+ LONG_PTR GetUserDataLongPtr() const { return GetUserDataLong(); }
+
+ #else
+
+ LONG_PTR SetLongPtr(int index, LONG_PTR newLongPtr)
+ { return ::SetWindowLongPtr(_window, index,
+ #ifndef _WIN64
+ (LONG)
+ #endif
+ newLongPtr); }
+ #ifndef _UNICODE
+ LONG_PTR SetLongPtrW(int index, LONG_PTR newLongPtr)
+ { return ::SetWindowLongPtrW(_window, index,
+ #ifndef _WIN64
+ (LONG)
+ #endif
+ newLongPtr); }
+ #endif
+
+ LONG_PTR GetLongPtr(int index) const { return ::GetWindowLongPtr(_window, index); }
+ LONG_PTR SetUserDataLongPtr(LONG_PTR newLongPtr) { return SetLongPtr(GWLP_USERDATA, newLongPtr); }
+ LONG_PTR GetUserDataLongPtr() const { return GetLongPtr(GWLP_USERDATA); }
+
+ #endif
+
+ /*
+ bool ModifyStyle(HWND hWnd, DWORD remove, DWORD add, UINT flags = 0)
+ { return ModifyStyleBase(GWL_STYLE, remove, add, flags); }
+ bool ModifyStyleEx(HWND hWnd, DWORD remove, DWORD add, UINT flags = 0)
+ { return ModifyStyleBase(GWL_EXSTYLE, remove, add, flags); }
+ */
+
+ HWND SetFocus() { return ::SetFocus(_window); }
+
+ LRESULT SendMsg(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
+ { return ::SendMessage(_window, message, wParam, lParam); }
+ #ifndef _UNICODE
+ LRESULT SendMsgW(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
+ { return ::SendMessageW(_window, message, wParam, lParam); }
+ #endif
+
+ bool PostMsg(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
+ { return BOOLToBool(::PostMessage(_window, message, wParam, lParam)); }
+ #ifndef _UNICODE
+ bool PostMsgW(UINT message, WPARAM wParam = 0, LPARAM lParam = 0)
+ { return BOOLToBool(::PostMessageW(_window, message, wParam, lParam)); }
+ #endif
+
+ bool SetText(LPCTSTR s) { return BOOLToBool(::SetWindowText(_window, s)); }
+ #ifndef _UNICODE
+ bool SetText(LPCWSTR s) { return MySetWindowText(_window, s); }
+ #endif
+
+ int GetTextLength() const
+ { return GetWindowTextLength(_window); }
+ int GetText(LPTSTR string, int maxCount) const
+ { return GetWindowText(_window, string, maxCount); }
+ bool GetText(CSysString &s) const;
+ #ifndef _UNICODE
+ /*
+ UINT GetText(LPWSTR string, int maxCount) const
+ { return GetWindowTextW(_window, string, maxCount); }
+ */
+ bool GetText(UString &s) const;
+ #endif
+
+ bool Enable(bool enable)
+ { return BOOLToBool(::EnableWindow(_window, BoolToBOOL(enable))); }
+
+ bool IsEnabled() const
+ { return BOOLToBool(::IsWindowEnabled(_window)); }
+
+ #ifndef UNDER_CE
+ HMENU GetSystemMenu(bool revert)
+ { return ::GetSystemMenu(_window, BoolToBOOL(revert)); }
+ #endif
+
+ UINT_PTR SetTimer(UINT_PTR idEvent, UINT elapse, TIMERPROC timerFunc = NULL)
+ { return ::SetTimer(_window, idEvent, elapse, timerFunc); }
+ bool KillTimer(UINT_PTR idEvent)
+ {return BOOLToBool(::KillTimer(_window, idEvent)); }
+
+ HICON SetIcon(WPARAM sizeType, HICON icon) { return (HICON)SendMsg(WM_SETICON, sizeType, (LPARAM)icon); }
+};
+
+#define RECT_SIZE_X(r) ((r).right - (r).left)
+#define RECT_SIZE_Y(r) ((r).bottom - (r).top)
+
+inline bool IsKeyDown(int virtKey) { return (::GetKeyState(virtKey) & 0x8000) != 0; }
+
+}
+
+#endif
diff --git a/CS/7zip/Common/CRC.cs b/CS/7zip/Common/CRC.cs
deleted file mode 100644
index 62bb847..0000000
--- a/CS/7zip/Common/CRC.cs
+++ /dev/null
@@ -1,55 +0,0 @@
-// Common/CRC.cs
-
-namespace SevenZip
-{
- class CRC
- {
- public static readonly uint[] Table;
-
- static CRC()
- {
- Table = new uint[256];
- const uint kPoly = 0xEDB88320;
- for (uint i = 0; i < 256; i++)
- {
- uint r = i;
- for (int j = 0; j < 8; j++)
- if ((r & 1) != 0)
- r = (r >> 1) ^ kPoly;
- else
- r >>= 1;
- Table[i] = r;
- }
- }
-
- uint _value = 0xFFFFFFFF;
-
- public void Init() { _value = 0xFFFFFFFF; }
-
- public void UpdateByte(byte b)
- {
- _value = Table[(((byte)(_value)) ^ b)] ^ (_value >> 8);
- }
-
- public void Update(byte[] data, uint offset, uint size)
- {
- for (uint i = 0; i < size; i++)
- _value = Table[(((byte)(_value)) ^ data[offset + i])] ^ (_value >> 8);
- }
-
- public uint GetDigest() { return _value ^ 0xFFFFFFFF; }
-
- static uint CalculateDigest(byte[] data, uint offset, uint size)
- {
- CRC crc = new CRC();
- // crc.Init();
- crc.Update(data, offset, size);
- return crc.GetDigest();
- }
-
- static bool VerifyDigest(uint digest, byte[] data, uint offset, uint size)
- {
- return (CalculateDigest(data, offset, size) == digest);
- }
- }
-}
diff --git a/CS/7zip/Common/CommandLineParser.cs b/CS/7zip/Common/CommandLineParser.cs
deleted file mode 100644
index b46f6f2..0000000
--- a/CS/7zip/Common/CommandLineParser.cs
+++ /dev/null
@@ -1,274 +0,0 @@
-// CommandLineParser.cs
-
-using System;
-using System.Collections;
-
-namespace SevenZip.CommandLineParser
-{
- public enum SwitchType
- {
- Simple,
- PostMinus,
- LimitedPostString,
- UnLimitedPostString,
- PostChar
- }
-
- public class SwitchForm
- {
- public string IDString;
- public SwitchType Type;
- public bool Multi;
- public int MinLen;
- public int MaxLen;
- public string PostCharSet;
-
- public SwitchForm(string idString, SwitchType type, bool multi,
- int minLen, int maxLen, string postCharSet)
- {
- IDString = idString;
- Type = type;
- Multi = multi;
- MinLen = minLen;
- MaxLen = maxLen;
- PostCharSet = postCharSet;
- }
- public SwitchForm(string idString, SwitchType type, bool multi, int minLen):
- this(idString, type, multi, minLen, 0, "")
- {
- }
- public SwitchForm(string idString, SwitchType type, bool multi):
- this(idString, type, multi, 0)
- {
- }
- }
-
- public class SwitchResult
- {
- public bool ThereIs;
- public bool WithMinus;
- public ArrayList PostStrings = new ArrayList();
- public int PostCharIndex;
- public SwitchResult()
- {
- ThereIs = false;
- }
- }
-
- public class Parser
- {
- public ArrayList NonSwitchStrings = new ArrayList();
- SwitchResult[] _switches;
-
- public Parser(int numSwitches)
- {
- _switches = new SwitchResult[numSwitches];
- for (int i = 0; i < numSwitches; i++)
- _switches[i] = new SwitchResult();
- }
-
- bool ParseString(string srcString, SwitchForm[] switchForms)
- {
- int len = srcString.Length;
- if (len == 0)
- return false;
- int pos = 0;
- if (!IsItSwitchChar(srcString[pos]))
- return false;
- while (pos < len)
- {
- if (IsItSwitchChar(srcString[pos]))
- pos++;
- const int kNoLen = -1;
- int matchedSwitchIndex = 0;
- int maxLen = kNoLen;
- for (int switchIndex = 0; switchIndex < _switches.Length; switchIndex++)
- {
- int switchLen = switchForms[switchIndex].IDString.Length;
- if (switchLen <= maxLen || pos + switchLen > len)
- continue;
- if (String.Compare(switchForms[switchIndex].IDString, 0,
- srcString, pos, switchLen, true) == 0)
- {
- matchedSwitchIndex = switchIndex;
- maxLen = switchLen;
- }
- }
- if (maxLen == kNoLen)
- throw new Exception("maxLen == kNoLen");
- SwitchResult matchedSwitch = _switches[matchedSwitchIndex];
- SwitchForm switchForm = switchForms[matchedSwitchIndex];
- if ((!switchForm.Multi) && matchedSwitch.ThereIs)
- throw new Exception("switch must be single");
- matchedSwitch.ThereIs = true;
- pos += maxLen;
- int tailSize = len - pos;
- SwitchType type = switchForm.Type;
- switch (type)
- {
- case SwitchType.PostMinus:
- {
- if (tailSize == 0)
- matchedSwitch.WithMinus = false;
- else
- {
- matchedSwitch.WithMinus = (srcString[pos] == kSwitchMinus);
- if (matchedSwitch.WithMinus)
- pos++;
- }
- break;
- }
- case SwitchType.PostChar:
- {
- if (tailSize < switchForm.MinLen)
- throw new Exception("switch is not full");
- string charSet = switchForm.PostCharSet;
- const int kEmptyCharValue = -1;
- if (tailSize == 0)
- matchedSwitch.PostCharIndex = kEmptyCharValue;
- else
- {
- int index = charSet.IndexOf(srcString[pos]);
- if (index < 0)
- matchedSwitch.PostCharIndex = kEmptyCharValue;
- else
- {
- matchedSwitch.PostCharIndex = index;
- pos++;
- }
- }
- break;
- }
- case SwitchType.LimitedPostString:
- case SwitchType.UnLimitedPostString:
- {
- int minLen = switchForm.MinLen;
- if (tailSize < minLen)
- throw new Exception("switch is not full");
- if (type == SwitchType.UnLimitedPostString)
- {
- matchedSwitch.PostStrings.Add(srcString.Substring(pos));
- return true;
- }
- String stringSwitch = srcString.Substring(pos, minLen);
- pos += minLen;
- for (int i = minLen; i < switchForm.MaxLen && pos < len; i++, pos++)
- {
- char c = srcString[pos];
- if (IsItSwitchChar(c))
- break;
- stringSwitch += c;
- }
- matchedSwitch.PostStrings.Add(stringSwitch);
- break;
- }
- }
- }
- return true;
-
- }
-
- public void ParseStrings(SwitchForm[] switchForms, string[] commandStrings)
- {
- int numCommandStrings = commandStrings.Length;
- bool stopSwitch = false;
- for (int i = 0; i < numCommandStrings; i++)
- {
- string s = commandStrings[i];
- if (stopSwitch)
- NonSwitchStrings.Add(s);
- else
- if (s == kStopSwitchParsing)
- stopSwitch = true;
- else
- if (!ParseString(s, switchForms))
- NonSwitchStrings.Add(s);
- }
- }
-
- public SwitchResult this[int index] { get { return _switches[index]; } }
-
- public static int ParseCommand(CommandForm[] commandForms, string commandString,
- out string postString)
- {
- for (int i = 0; i < commandForms.Length; i++)
- {
- string id = commandForms[i].IDString;
- if (commandForms[i].PostStringMode)
- {
- if (commandString.IndexOf(id) == 0)
- {
- postString = commandString.Substring(id.Length);
- return i;
- }
- }
- else
- if (commandString == id)
- {
- postString = "";
- return i;
- }
- }
- postString = "";
- return -1;
- }
-
- static bool ParseSubCharsCommand(int numForms, CommandSubCharsSet[] forms,
- string commandString, ArrayList indices)
- {
- indices.Clear();
- int numUsedChars = 0;
- for (int i = 0; i < numForms; i++)
- {
- CommandSubCharsSet charsSet = forms[i];
- int currentIndex = -1;
- int len = charsSet.Chars.Length;
- for (int j = 0; j < len; j++)
- {
- char c = charsSet.Chars[j];
- int newIndex = commandString.IndexOf(c);
- if (newIndex >= 0)
- {
- if (currentIndex >= 0)
- return false;
- if (commandString.IndexOf(c, newIndex + 1) >= 0)
- return false;
- currentIndex = j;
- numUsedChars++;
- }
- }
- if (currentIndex == -1 && !charsSet.EmptyAllowed)
- return false;
- indices.Add(currentIndex);
- }
- return (numUsedChars == commandString.Length);
- }
- const char kSwitchID1 = '-';
- const char kSwitchID2 = '/';
-
- const char kSwitchMinus = '-';
- const string kStopSwitchParsing = "--";
-
- static bool IsItSwitchChar(char c)
- {
- return (c == kSwitchID1 || c == kSwitchID2);
- }
- }
-
- public class CommandForm
- {
- public string IDString = "";
- public bool PostStringMode = false;
- public CommandForm(string idString, bool postStringMode)
- {
- IDString = idString;
- PostStringMode = postStringMode;
- }
- }
-
- class CommandSubCharsSet
- {
- public string Chars = "";
- public bool EmptyAllowed = false;
- }
-}
diff --git a/CS/7zip/Common/InBuffer.cs b/CS/7zip/Common/InBuffer.cs
deleted file mode 100644
index 9c47c73..0000000
--- a/CS/7zip/Common/InBuffer.cs
+++ /dev/null
@@ -1,72 +0,0 @@
-// InBuffer.cs
-
-namespace SevenZip.Buffer
-{
- public class InBuffer
- {
- byte[] m_Buffer;
- uint m_Pos;
- uint m_Limit;
- uint m_BufferSize;
- System.IO.Stream m_Stream;
- bool m_StreamWasExhausted;
- ulong m_ProcessedSize;
-
- public InBuffer(uint bufferSize)
- {
- m_Buffer = new byte[bufferSize];
- m_BufferSize = bufferSize;
- }
-
- public void Init(System.IO.Stream stream)
- {
- m_Stream = stream;
- m_ProcessedSize = 0;
- m_Limit = 0;
- m_Pos = 0;
- m_StreamWasExhausted = false;
- }
-
- public bool ReadBlock()
- {
- if (m_StreamWasExhausted)
- return false;
- m_ProcessedSize += m_Pos;
- int aNumProcessedBytes = m_Stream.Read(m_Buffer, 0, (int)m_BufferSize);
- m_Pos = 0;
- m_Limit = (uint)aNumProcessedBytes;
- m_StreamWasExhausted = (aNumProcessedBytes == 0);
- return (!m_StreamWasExhausted);
- }
-
-
- public void ReleaseStream()
- {
- // m_Stream.Close();
- m_Stream = null;
- }
-
- public bool ReadByte(byte b) // check it
- {
- if (m_Pos >= m_Limit)
- if (!ReadBlock())
- return false;
- b = m_Buffer[m_Pos++];
- return true;
- }
-
- public byte ReadByte()
- {
- // return (byte)m_Stream.ReadByte();
- if (m_Pos >= m_Limit)
- if (!ReadBlock())
- return 0xFF;
- return m_Buffer[m_Pos++];
- }
-
- public ulong GetProcessedSize()
- {
- return m_ProcessedSize + m_Pos;
- }
- }
-}
diff --git a/CS/7zip/Common/OutBuffer.cs b/CS/7zip/Common/OutBuffer.cs
deleted file mode 100644
index c205aa6..0000000
--- a/CS/7zip/Common/OutBuffer.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-// OutBuffer.cs
-
-namespace SevenZip.Buffer
-{
- public class OutBuffer
- {
- byte[] m_Buffer;
- uint m_Pos;
- uint m_BufferSize;
- System.IO.Stream m_Stream;
- ulong m_ProcessedSize;
-
- public OutBuffer(uint bufferSize)
- {
- m_Buffer = new byte[bufferSize];
- m_BufferSize = bufferSize;
- }
-
- public void SetStream(System.IO.Stream stream) { m_Stream = stream; }
- public void FlushStream() { m_Stream.Flush(); }
- public void CloseStream() { m_Stream.Close(); }
- public void ReleaseStream() { m_Stream = null; }
-
- public void Init()
- {
- m_ProcessedSize = 0;
- m_Pos = 0;
- }
-
- public void WriteByte(byte b)
- {
- m_Buffer[m_Pos++] = b;
- if (m_Pos >= m_BufferSize)
- FlushData();
- }
-
- public void FlushData()
- {
- if (m_Pos == 0)
- return;
- m_Stream.Write(m_Buffer, 0, (int)m_Pos);
- m_Pos = 0;
- }
-
- public ulong GetProcessedSize() { return m_ProcessedSize + m_Pos; }
- }
-}
diff --git a/CS/7zip/Compress/LZ/IMatchFinder.cs b/CS/7zip/Compress/LZ/IMatchFinder.cs
deleted file mode 100644
index 30fab86..0000000
--- a/CS/7zip/Compress/LZ/IMatchFinder.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-// IMatchFinder.cs
-
-using System;
-
-namespace SevenZip.Compression.LZ
-{
- interface IInWindowStream
- {
- void SetStream(System.IO.Stream inStream);
- void Init();
- void ReleaseStream();
- Byte GetIndexByte(Int32 index);
- UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit);
- UInt32 GetNumAvailableBytes();
- }
-
- interface IMatchFinder : IInWindowStream
- {
- void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
- UInt32 matchMaxLen, UInt32 keepAddBufferAfter);
- UInt32 GetMatches(UInt32[] distances);
- void Skip(UInt32 num);
- }
-}
diff --git a/CS/7zip/Compress/LZ/LzBinTree.cs b/CS/7zip/Compress/LZ/LzBinTree.cs
deleted file mode 100644
index 7a9ca20..0000000
--- a/CS/7zip/Compress/LZ/LzBinTree.cs
+++ /dev/null
@@ -1,367 +0,0 @@
-// LzBinTree.cs
-
-using System;
-
-namespace SevenZip.Compression.LZ
-{
- public class BinTree : InWindow, IMatchFinder
- {
- UInt32 _cyclicBufferPos;
- UInt32 _cyclicBufferSize = 0;
- UInt32 _matchMaxLen;
-
- UInt32[] _son;
- UInt32[] _hash;
-
- UInt32 _cutValue = 0xFF;
- UInt32 _hashMask;
- UInt32 _hashSizeSum = 0;
-
- bool HASH_ARRAY = true;
-
- const UInt32 kHash2Size = 1 << 10;
- const UInt32 kHash3Size = 1 << 16;
- const UInt32 kBT2HashSize = 1 << 16;
- const UInt32 kStartMaxLen = 1;
- const UInt32 kHash3Offset = kHash2Size;
- const UInt32 kEmptyHashValue = 0;
- const UInt32 kMaxValForNormalize = ((UInt32)1 << 31) - 1;
-
- UInt32 kNumHashDirectBytes = 0;
- UInt32 kMinMatchCheck = 4;
- UInt32 kFixHashSize = kHash2Size + kHash3Size;
-
- public void SetType(int numHashBytes)
- {
- HASH_ARRAY = (numHashBytes > 2);
- if (HASH_ARRAY)
- {
- kNumHashDirectBytes = 0;
- kMinMatchCheck = 4;
- kFixHashSize = kHash2Size + kHash3Size;
- }
- else
- {
- kNumHashDirectBytes = 2;
- kMinMatchCheck = 2 + 1;
- kFixHashSize = 0;
- }
- }
-
- public new void SetStream(System.IO.Stream stream) { base.SetStream(stream); }
- public new void ReleaseStream() { base.ReleaseStream(); }
-
- public new void Init()
- {
- base.Init();
- for (UInt32 i = 0; i < _hashSizeSum; i++)
- _hash[i] = kEmptyHashValue;
- _cyclicBufferPos = 0;
- ReduceOffsets(-1);
- }
-
- public new void MovePos()
- {
- if (++_cyclicBufferPos >= _cyclicBufferSize)
- _cyclicBufferPos = 0;
- base.MovePos();
- if (_pos == kMaxValForNormalize)
- Normalize();
- }
-
- public new Byte GetIndexByte(Int32 index) { return base.GetIndexByte(index); }
-
- public new UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
- { return base.GetMatchLen(index, distance, limit); }
-
- public new UInt32 GetNumAvailableBytes() { return base.GetNumAvailableBytes(); }
-
- public void Create(UInt32 historySize, UInt32 keepAddBufferBefore,
- UInt32 matchMaxLen, UInt32 keepAddBufferAfter)
- {
- if (historySize > kMaxValForNormalize - 256)
- throw new Exception();
- _cutValue = 16 + (matchMaxLen >> 1);
-
- UInt32 windowReservSize = (historySize + keepAddBufferBefore +
- matchMaxLen + keepAddBufferAfter) / 2 + 256;
-
- base.Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize);
-
- _matchMaxLen = matchMaxLen;
-
- UInt32 cyclicBufferSize = historySize + 1;
- if (_cyclicBufferSize != cyclicBufferSize)
- _son = new UInt32[(_cyclicBufferSize = cyclicBufferSize) * 2];
-
- UInt32 hs = kBT2HashSize;
-
- if (HASH_ARRAY)
- {
- hs = historySize - 1;
- hs |= (hs >> 1);
- hs |= (hs >> 2);
- hs |= (hs >> 4);
- hs |= (hs >> 8);
- hs >>= 1;
- hs |= 0xFFFF;
- if (hs > (1 << 24))
- hs >>= 1;
- _hashMask = hs;
- hs++;
- hs += kFixHashSize;
- }
- if (hs != _hashSizeSum)
- _hash = new UInt32[_hashSizeSum = hs];
- }
-
- public UInt32 GetMatches(UInt32[] distances)
- {
- UInt32 lenLimit;
- if (_pos + _matchMaxLen <= _streamPos)
- lenLimit = _matchMaxLen;
- else
- {
- lenLimit = _streamPos - _pos;
- if (lenLimit < kMinMatchCheck)
- {
- MovePos();
- return 0;
- }
- }
-
- UInt32 offset = 0;
- UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
- UInt32 cur = _bufferOffset + _pos;
- UInt32 maxLen = kStartMaxLen; // to avoid items for len < hashSize;
- UInt32 hashValue, hash2Value = 0, hash3Value = 0;
-
- if (HASH_ARRAY)
- {
- UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
- hash2Value = temp & (kHash2Size - 1);
- temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8);
- hash3Value = temp & (kHash3Size - 1);
- hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
- }
- else
- hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8);
-
- UInt32 curMatch = _hash[kFixHashSize + hashValue];
- if (HASH_ARRAY)
- {
- UInt32 curMatch2 = _hash[hash2Value];
- UInt32 curMatch3 = _hash[kHash3Offset + hash3Value];
- _hash[hash2Value] = _pos;
- _hash[kHash3Offset + hash3Value] = _pos;
- if (curMatch2 > matchMinPos)
- if (_bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur])
- {
- distances[offset++] = maxLen = 2;
- distances[offset++] = _pos - curMatch2 - 1;
- }
- if (curMatch3 > matchMinPos)
- if (_bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur])
- {
- if (curMatch3 == curMatch2)
- offset -= 2;
- distances[offset++] = maxLen = 3;
- distances[offset++] = _pos - curMatch3 - 1;
- curMatch2 = curMatch3;
- }
- if (offset != 0 && curMatch2 == curMatch)
- {
- offset -= 2;
- maxLen = kStartMaxLen;
- }
- }
-
- _hash[kFixHashSize + hashValue] = _pos;
-
- UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
- UInt32 ptr1 = (_cyclicBufferPos << 1);
-
- UInt32 len0, len1;
- len0 = len1 = kNumHashDirectBytes;
-
- if (kNumHashDirectBytes != 0)
- {
- if (curMatch > matchMinPos)
- {
- if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] !=
- _bufferBase[cur + kNumHashDirectBytes])
- {
- distances[offset++] = maxLen = kNumHashDirectBytes;
- distances[offset++] = _pos - curMatch - 1;
- }
- }
- }
-
- UInt32 count = _cutValue;
-
- while(true)
- {
- if(curMatch <= matchMinPos || count-- == 0)
- {
- _son[ptr0] = _son[ptr1] = kEmptyHashValue;
- break;
- }
- UInt32 delta = _pos - curMatch;
- UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
- (_cyclicBufferPos - delta) :
- (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
-
- UInt32 pby1 = _bufferOffset + curMatch;
- UInt32 len = Math.Min(len0, len1);
- if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
- {
- while(++len != lenLimit)
- if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
- break;
- if (maxLen < len)
- {
- distances[offset++] = maxLen = len;
- distances[offset++] = delta - 1;
- if (len == lenLimit)
- {
- _son[ptr1] = _son[cyclicPos];
- _son[ptr0] = _son[cyclicPos + 1];
- break;
- }
- }
- }
- if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
- {
- _son[ptr1] = curMatch;
- ptr1 = cyclicPos + 1;
- curMatch = _son[ptr1];
- len1 = len;
- }
- else
- {
- _son[ptr0] = curMatch;
- ptr0 = cyclicPos;
- curMatch = _son[ptr0];
- len0 = len;
- }
- }
- MovePos();
- return offset;
- }
-
- public void Skip(UInt32 num)
- {
- do
- {
- UInt32 lenLimit;
- if (_pos + _matchMaxLen <= _streamPos)
- lenLimit = _matchMaxLen;
- else
- {
- lenLimit = _streamPos - _pos;
- if (lenLimit < kMinMatchCheck)
- {
- MovePos();
- continue;
- }
- }
-
- UInt32 matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
- UInt32 cur = _bufferOffset + _pos;
-
- UInt32 hashValue;
-
- if (HASH_ARRAY)
- {
- UInt32 temp = CRC.Table[_bufferBase[cur]] ^ _bufferBase[cur + 1];
- UInt32 hash2Value = temp & (kHash2Size - 1);
- _hash[hash2Value] = _pos;
- temp ^= ((UInt32)(_bufferBase[cur + 2]) << 8);
- UInt32 hash3Value = temp & (kHash3Size - 1);
- _hash[kHash3Offset + hash3Value] = _pos;
- hashValue = (temp ^ (CRC.Table[_bufferBase[cur + 3]] << 5)) & _hashMask;
- }
- else
- hashValue = _bufferBase[cur] ^ ((UInt32)(_bufferBase[cur + 1]) << 8);
-
- UInt32 curMatch = _hash[kFixHashSize + hashValue];
- _hash[kFixHashSize + hashValue] = _pos;
-
- UInt32 ptr0 = (_cyclicBufferPos << 1) + 1;
- UInt32 ptr1 = (_cyclicBufferPos << 1);
-
- UInt32 len0, len1;
- len0 = len1 = kNumHashDirectBytes;
-
- UInt32 count = _cutValue;
- while (true)
- {
- if (curMatch <= matchMinPos || count-- == 0)
- {
- _son[ptr0] = _son[ptr1] = kEmptyHashValue;
- break;
- }
-
- UInt32 delta = _pos - curMatch;
- UInt32 cyclicPos = ((delta <= _cyclicBufferPos) ?
- (_cyclicBufferPos - delta) :
- (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
-
- UInt32 pby1 = _bufferOffset + curMatch;
- UInt32 len = Math.Min(len0, len1);
- if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
- {
- while (++len != lenLimit)
- if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
- break;
- if (len == lenLimit)
- {
- _son[ptr1] = _son[cyclicPos];
- _son[ptr0] = _son[cyclicPos + 1];
- break;
- }
- }
- if (_bufferBase[pby1 + len] < _bufferBase[cur + len])
- {
- _son[ptr1] = curMatch;
- ptr1 = cyclicPos + 1;
- curMatch = _son[ptr1];
- len1 = len;
- }
- else
- {
- _son[ptr0] = curMatch;
- ptr0 = cyclicPos;
- curMatch = _son[ptr0];
- len0 = len;
- }
- }
- MovePos();
- }
- while (--num != 0);
- }
-
- void NormalizeLinks(UInt32[] items, UInt32 numItems, UInt32 subValue)
- {
- for (UInt32 i = 0; i < numItems; i++)
- {
- UInt32 value = items[i];
- if (value <= subValue)
- value = kEmptyHashValue;
- else
- value -= subValue;
- items[i] = value;
- }
- }
-
- void Normalize()
- {
- UInt32 subValue = _pos - _cyclicBufferSize;
- NormalizeLinks(_son, _cyclicBufferSize * 2, subValue);
- NormalizeLinks(_hash, _hashSizeSum, subValue);
- ReduceOffsets((Int32)subValue);
- }
-
- public void SetCutValue(UInt32 cutValue) { _cutValue = cutValue; }
- }
-}
diff --git a/CS/7zip/Compress/LZ/LzInWindow.cs b/CS/7zip/Compress/LZ/LzInWindow.cs
deleted file mode 100644
index f1974ce..0000000
--- a/CS/7zip/Compress/LZ/LzInWindow.cs
+++ /dev/null
@@ -1,132 +0,0 @@
-// LzInWindow.cs
-
-using System;
-
-namespace SevenZip.Compression.LZ
-{
- public class InWindow
- {
- public Byte[] _bufferBase = null; // pointer to buffer with data
- System.IO.Stream _stream;
- UInt32 _posLimit; // offset (from _buffer) of first byte when new block reading must be done
- bool _streamEndWasReached; // if (true) then _streamPos shows real end of stream
-
- UInt32 _pointerToLastSafePosition;
-
- public UInt32 _bufferOffset;
-
- public UInt32 _blockSize; // Size of Allocated memory block
- public UInt32 _pos; // offset (from _buffer) of curent byte
- UInt32 _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos
- UInt32 _keepSizeAfter; // how many BYTEs must be kept buffer after _pos
- public UInt32 _streamPos; // offset (from _buffer) of first not read byte from Stream
-
- public void MoveBlock()
- {
- UInt32 offset = (UInt32)(_bufferOffset) + _pos - _keepSizeBefore;
- // we need one additional byte, since MovePos moves on 1 byte.
- if (offset > 0)
- offset--;
-
- UInt32 numBytes = (UInt32)(_bufferOffset) + _streamPos - offset;
-
- // check negative offset ????
- for (UInt32 i = 0; i < numBytes; i++)
- _bufferBase[i] = _bufferBase[offset + i];
- _bufferOffset -= offset;
- }
-
- public virtual void ReadBlock()
- {
- if (_streamEndWasReached)
- return;
- while (true)
- {
- int size = (int)((0 - _bufferOffset) + _blockSize - _streamPos);
- if (size == 0)
- return;
- int numReadBytes = _stream.Read(_bufferBase, (int)(_bufferOffset + _streamPos), size);
- if (numReadBytes == 0)
- {
- _posLimit = _streamPos;
- UInt32 pointerToPostion = _bufferOffset + _posLimit;
- if (pointerToPostion > _pointerToLastSafePosition)
- _posLimit = (UInt32)(_pointerToLastSafePosition - _bufferOffset);
-
- _streamEndWasReached = true;
- return;
- }
- _streamPos += (UInt32)numReadBytes;
- if (_streamPos >= _pos + _keepSizeAfter)
- _posLimit = _streamPos - _keepSizeAfter;
- }
- }
-
- void Free() { _bufferBase = null; }
-
- public void Create(UInt32 keepSizeBefore, UInt32 keepSizeAfter, UInt32 keepSizeReserv)
- {
- _keepSizeBefore = keepSizeBefore;
- _keepSizeAfter = keepSizeAfter;
- UInt32 blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv;
- if (_bufferBase == null || _blockSize != blockSize)
- {
- Free();
- _blockSize = blockSize;
- _bufferBase = new Byte[_blockSize];
- }
- _pointerToLastSafePosition = _blockSize - keepSizeAfter;
- }
-
- public void SetStream(System.IO.Stream stream) { _stream = stream; }
- public void ReleaseStream() { _stream = null; }
-
- public void Init()
- {
- _bufferOffset = 0;
- _pos = 0;
- _streamPos = 0;
- _streamEndWasReached = false;
- ReadBlock();
- }
-
- public void MovePos()
- {
- _pos++;
- if (_pos > _posLimit)
- {
- UInt32 pointerToPostion = _bufferOffset + _pos;
- if (pointerToPostion > _pointerToLastSafePosition)
- MoveBlock();
- ReadBlock();
- }
- }
-
- public Byte GetIndexByte(Int32 index) { return _bufferBase[_bufferOffset + _pos + index]; }
-
- // index + limit have not to exceed _keepSizeAfter;
- public UInt32 GetMatchLen(Int32 index, UInt32 distance, UInt32 limit)
- {
- if (_streamEndWasReached)
- if ((_pos + index) + limit > _streamPos)
- limit = _streamPos - (UInt32)(_pos + index);
- distance++;
- // Byte *pby = _buffer + (size_t)_pos + index;
- UInt32 pby = _bufferOffset + _pos + (UInt32)index;
-
- UInt32 i;
- for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++);
- return i;
- }
-
- public UInt32 GetNumAvailableBytes() { return _streamPos - _pos; }
-
- public void ReduceOffsets(Int32 subValue)
- {
- _bufferOffset += (UInt32)subValue;
- _posLimit -= (UInt32)subValue;
- _pos -= (UInt32)subValue;
- _streamPos -= (UInt32)subValue;
- }
- }
-}
diff --git a/CS/7zip/Compress/LZ/LzOutWindow.cs b/CS/7zip/Compress/LZ/LzOutWindow.cs
deleted file mode 100644
index 84914f0..0000000
--- a/CS/7zip/Compress/LZ/LzOutWindow.cs
+++ /dev/null
@@ -1,110 +0,0 @@
-// LzOutWindow.cs
-
-namespace SevenZip.Compression.LZ
-{
- public class OutWindow
- {
- byte[] _buffer = null;
- uint _pos;
- uint _windowSize = 0;
- uint _streamPos;
- System.IO.Stream _stream;
-
- public uint TrainSize = 0;
-
- public void Create(uint windowSize)
- {
- if (_windowSize != windowSize)
- {
- // System.GC.Collect();
- _buffer = new byte[windowSize];
- }
- _windowSize = windowSize;
- _pos = 0;
- _streamPos = 0;
- }
-
- public void Init(System.IO.Stream stream, bool solid)
- {
- ReleaseStream();
- _stream = stream;
- if (!solid)
- {
- _streamPos = 0;
- _pos = 0;
- TrainSize = 0;
- }
- }
-
- public bool Train(System.IO.Stream stream)
- {
- long len = stream.Length;
- uint size = (len < _windowSize) ? (uint)len : _windowSize;
- TrainSize = size;
- stream.Position = len - size;
- _streamPos = _pos = 0;
- while (size > 0)
- {
- uint curSize = _windowSize - _pos;
- if (size < curSize)
- curSize = size;
- int numReadBytes = stream.Read(_buffer, (int)_pos, (int)curSize);
- if (numReadBytes == 0)
- return false;
- size -= (uint)numReadBytes;
- _pos += (uint)numReadBytes;
- _streamPos += (uint)numReadBytes;
- if (_pos == _windowSize)
- _streamPos = _pos = 0;
- }
- return true;
- }
-
- public void ReleaseStream()
- {
- Flush();
- _stream = null;
- }
-
- public void Flush()
- {
- uint size = _pos - _streamPos;
- if (size == 0)
- return;
- _stream.Write(_buffer, (int)_streamPos, (int)size);
- if (_pos >= _windowSize)
- _pos = 0;
- _streamPos = _pos;
- }
-
- public void CopyBlock(uint distance, uint len)
- {
- uint pos = _pos - distance - 1;
- if (pos >= _windowSize)
- pos += _windowSize;
- for (; len > 0; len--)
- {
- if (pos >= _windowSize)
- pos = 0;
- _buffer[_pos++] = _buffer[pos++];
- if (_pos >= _windowSize)
- Flush();
- }
- }
-
- public void PutByte(byte b)
- {
- _buffer[_pos++] = b;
- if (_pos >= _windowSize)
- Flush();
- }
-
- public byte GetByte(uint distance)
- {
- uint pos = _pos - distance - 1;
- if (pos >= _windowSize)
- pos += _windowSize;
- return _buffer[pos];
- }
- }
-}
diff --git a/CS/7zip/Compress/LZMA/LzmaBase.cs b/CS/7zip/Compress/LZMA/LzmaBase.cs
deleted file mode 100644
index 8447a2a..0000000
--- a/CS/7zip/Compress/LZMA/LzmaBase.cs
+++ /dev/null
@@ -1,76 +0,0 @@
-// LzmaBase.cs
-
-namespace SevenZip.Compression.LZMA
-{
- internal abstract class Base
- {
- public const uint kNumRepDistances = 4;
- public const uint kNumStates = 12;
-
- // static byte []kLiteralNextStates = {0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5};
- // static byte []kMatchNextStates = {7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10};
- // static byte []kRepNextStates = {8, 8, 8, 8, 8, 8, 8, 11, 11, 11, 11, 11};
- // static byte []kShortRepNextStates = {9, 9, 9, 9, 9, 9, 9, 11, 11, 11, 11, 11};
-
- public struct State
- {
- public uint Index;
- public void Init() { Index = 0; }
- public void UpdateChar()
- {
- if (Index < 4) Index = 0;
- else if (Index < 10) Index -= 3;
- else Index -= 6;
- }
- public void UpdateMatch() { Index = (uint)(Index < 7 ? 7 : 10); }
- public void UpdateRep() { Index = (uint)(Index < 7 ? 8 : 11); }
- public void UpdateShortRep() { Index = (uint)(Index < 7 ? 9 : 11); }
- public bool IsCharState() { return Index < 7; }
- }
-
- public const int kNumPosSlotBits = 6;
- public const int kDicLogSizeMin = 0;
- // public const int kDicLogSizeMax = 30;
- // public const uint kDistTableSizeMax = kDicLogSizeMax * 2;
-
- public const int kNumLenToPosStatesBits = 2; // it's for speed optimization
- public const uint kNumLenToPosStates = 1 << kNumLenToPosStatesBits;
-
- public const uint kMatchMinLen = 2;
-
- public static uint GetLenToPosState(uint len)
- {
- len -= kMatchMinLen;
- if (len < kNumLenToPosStates)
- return len;
- return (uint)(kNumLenToPosStates - 1);
- }
-
- public const int kNumAlignBits = 4;
- public const uint kAlignTableSize = 1 << kNumAlignBits;
- public const uint kAlignMask = (kAlignTableSize - 1);
-
- public const uint kStartPosModelIndex = 4;
- public const uint kEndPosModelIndex = 14;
- public const uint kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;
-
- public const uint kNumFullDistances = 1 << ((int)kEndPosModelIndex / 2);
-
- public const uint kNumLitPosStatesBitsEncodingMax = 4;
- public const uint kNumLitContextBitsMax = 8;
-
- public const int kNumPosStatesBitsMax = 4;
- public const uint kNumPosStatesMax = (1 << kNumPosStatesBitsMax);
- public const int kNumPosStatesBitsEncodingMax = 4;
- public const uint kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax);
-
- public const int kNumLowLenBits = 3;
- public const int kNumMidLenBits = 3;
- public const int kNumHighLenBits = 8;
- public const uint kNumLowLenSymbols = 1 << kNumLowLenBits;
- public const uint kNumMidLenSymbols = 1 << kNumMidLenBits;
- public const uint kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols +
- (1 << kNumHighLenBits);
- public const uint kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1;
- }
-}
diff --git a/CS/7zip/Compress/LZMA/LzmaDecoder.cs b/CS/7zip/Compress/LZMA/LzmaDecoder.cs
deleted file mode 100644
index 00bfe63..0000000
--- a/CS/7zip/Compress/LZMA/LzmaDecoder.cs
+++ /dev/null
@@ -1,398 +0,0 @@
-// LzmaDecoder.cs
-
-using System;
-
-namespace SevenZip.Compression.LZMA
-{
- using RangeCoder;
-
- public class Decoder : ICoder, ISetDecoderProperties // ,System.IO.Stream
- {
- class LenDecoder
- {
- BitDecoder m_Choice = new BitDecoder();
- BitDecoder m_Choice2 = new BitDecoder();
- BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
- BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
- BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits);
- uint m_NumPosStates = 0;
-
- public void Create(uint numPosStates)
- {
- for (uint posState = m_NumPosStates; posState < numPosStates; posState++)
- {
- m_LowCoder[posState] = new BitTreeDecoder(Base.kNumLowLenBits);
- m_MidCoder[posState] = new BitTreeDecoder(Base.kNumMidLenBits);
- }
- m_NumPosStates = numPosStates;
- }
-
- public void Init()
- {
- m_Choice.Init();
- for (uint posState = 0; posState < m_NumPosStates; posState++)
- {
- m_LowCoder[posState].Init();
- m_MidCoder[posState].Init();
- }
- m_Choice2.Init();
- m_HighCoder.Init();
- }
-
- public uint Decode(RangeCoder.Decoder rangeDecoder, uint posState)
- {
- if (m_Choice.Decode(rangeDecoder) == 0)
- return m_LowCoder[posState].Decode(rangeDecoder);
- else
- {
- uint symbol = Base.kNumLowLenSymbols;
- if (m_Choice2.Decode(rangeDecoder) == 0)
- symbol += m_MidCoder[posState].Decode(rangeDecoder);
- else
- {
- symbol += Base.kNumMidLenSymbols;
- symbol += m_HighCoder.Decode(rangeDecoder);
- }
- return symbol;
- }
- }
- }
-
- class LiteralDecoder
- {
- struct Decoder2
- {
- BitDecoder[] m_Decoders;
- public void Create() { m_Decoders = new BitDecoder[0x300]; }
- public void Init() { for (int i = 0; i < 0x300; i++) m_Decoders[i].Init(); }
-
- public byte DecodeNormal(RangeCoder.Decoder rangeDecoder)
- {
- uint symbol = 1;
- do
- symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
- while (symbol < 0x100);
- return (byte)symbol;
- }
-
- public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, byte matchByte)
- {
- uint symbol = 1;
- do
- {
- uint matchBit = (uint)(matchByte >> 7) & 1;
- matchByte <<= 1;
- uint bit = m_Decoders[((1 + matchBit) << 8) + symbol].Decode(rangeDecoder);
- symbol = (symbol << 1) | bit;
- if (matchBit != bit)
- {
- while (symbol < 0x100)
- symbol = (symbol << 1) | m_Decoders[symbol].Decode(rangeDecoder);
- break;
- }
- }
- while (symbol < 0x100);
- return (byte)symbol;
- }
- }
-
- Decoder2[] m_Coders;
- int m_NumPrevBits;
- int m_NumPosBits;
- uint m_PosMask;
-
- public void Create(int numPosBits, int numPrevBits)
- {
- if (m_Coders != null && m_NumPrevBits == numPrevBits &&
- m_NumPosBits == numPosBits)
- return;
- m_NumPosBits = numPosBits;
- m_PosMask = ((uint)1 << numPosBits) - 1;
- m_NumPrevBits = numPrevBits;
- uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
- m_Coders = new Decoder2[numStates];
- for (uint i = 0; i < numStates; i++)
- m_Coders[i].Create();
- }
-
- public void Init()
- {
- uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
- for (uint i = 0; i < numStates; i++)
- m_Coders[i].Init();
- }
-
- uint GetState(uint pos, byte prevByte)
- { return ((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits)); }
-
- public byte DecodeNormal(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte)
- { return m_Coders[GetState(pos, prevByte)].DecodeNormal(rangeDecoder); }
-
- public byte DecodeWithMatchByte(RangeCoder.Decoder rangeDecoder, uint pos, byte prevByte, byte matchByte)
- { return m_Coders[GetState(pos, prevByte)].DecodeWithMatchByte(rangeDecoder, matchByte); }
- };
-
- LZ.OutWindow m_OutWindow = new LZ.OutWindow();
- RangeCoder.Decoder m_RangeDecoder = new RangeCoder.Decoder();
-
- BitDecoder[] m_IsMatchDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
- BitDecoder[] m_IsRepDecoders = new BitDecoder[Base.kNumStates];
- BitDecoder[] m_IsRepG0Decoders = new BitDecoder[Base.kNumStates];
- BitDecoder[] m_IsRepG1Decoders = new BitDecoder[Base.kNumStates];
- BitDecoder[] m_IsRepG2Decoders = new BitDecoder[Base.kNumStates];
- BitDecoder[] m_IsRep0LongDecoders = new BitDecoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
-
- BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates];
- BitDecoder[] m_PosDecoders = new BitDecoder[Base.kNumFullDistances - Base.kEndPosModelIndex];
-
- BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits);
-
- LenDecoder m_LenDecoder = new LenDecoder();
- LenDecoder m_RepLenDecoder = new LenDecoder();
-
- LiteralDecoder m_LiteralDecoder = new LiteralDecoder();
-
- uint m_DictionarySize;
- uint m_DictionarySizeCheck;
-
- uint m_PosStateMask;
-
- public Decoder()
- {
- m_DictionarySize = 0xFFFFFFFF;
- for (int i = 0; i < Base.kNumLenToPosStates; i++)
- m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits);
- }
-
- void SetDictionarySize(uint dictionarySize)
- {
- if (m_DictionarySize != dictionarySize)
- {
- m_DictionarySize = dictionarySize;
- m_DictionarySizeCheck = Math.Max(m_DictionarySize, 1);
- uint blockSize = Math.Max(m_DictionarySizeCheck, (1 << 12));
- m_OutWindow.Create(blockSize);
- }
- }
-
- void SetLiteralProperties(int lp, int lc)
- {
- if (lp > 8)
- throw new InvalidParamException();
- if (lc > 8)
- throw new InvalidParamException();
- m_LiteralDecoder.Create(lp, lc);
- }
-
- void SetPosBitsProperties(int pb)
- {
- if (pb > Base.kNumPosStatesBitsMax)
- throw new InvalidParamException();
- uint numPosStates = (uint)1 << pb;
- m_LenDecoder.Create(numPosStates);
- m_RepLenDecoder.Create(numPosStates);
- m_PosStateMask = numPosStates - 1;
- }
-
- bool _solid = false;
- void Init(System.IO.Stream inStream, System.IO.Stream outStream)
- {
- m_RangeDecoder.Init(inStream);
- m_OutWindow.Init(outStream, _solid);
-
- uint i;
- for (i = 0; i < Base.kNumStates; i++)
- {
- for (uint j = 0; j <= m_PosStateMask; j++)
- {
- uint index = (i << Base.kNumPosStatesBitsMax) + j;
- m_IsMatchDecoders[index].Init();
- m_IsRep0LongDecoders[index].Init();
- }
- m_IsRepDecoders[i].Init();
- m_IsRepG0Decoders[i].Init();
- m_IsRepG1Decoders[i].Init();
- m_IsRepG2Decoders[i].Init();
- }
-
- m_LiteralDecoder.Init();
- for (i = 0; i < Base.kNumLenToPosStates; i++)
- m_PosSlotDecoder[i].Init();
- // m_PosSpecDecoder.Init();
- for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++)
- m_PosDecoders[i].Init();
-
- m_LenDecoder.Init();
- m_RepLenDecoder.Init();
- m_PosAlignDecoder.Init();
- }
-
- public void Code(System.IO.Stream inStream, System.IO.Stream outStream,
- Int64 inSize, Int64 outSize, ICodeProgress progress)
- {
- Init(inStream, outStream);
-
- Base.State state = new Base.State();
- state.Init();
- uint rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;
-
- UInt64 nowPos64 = 0;
- UInt64 outSize64 = (UInt64)outSize;
- if (nowPos64 < outSize64)
- {
- if (m_IsMatchDecoders[state.Index << Base.kNumPosStatesBitsMax].Decode(m_RangeDecoder) != 0)
- throw new DataErrorException();
- state.UpdateChar();
- byte b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, 0, 0);
- m_OutWindow.PutByte(b);
- nowPos64++;
- }
- while (nowPos64 < outSize64)
- {
- // UInt64 next = Math.Min(nowPos64 + (1 << 18), outSize64);
- // while(nowPos64 < next)
- {
- uint posState = (uint)nowPos64 & m_PosStateMask;
- if (m_IsMatchDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
- {
- byte b;
- byte prevByte = m_OutWindow.GetByte(0);
- if (!state.IsCharState())
- b = m_LiteralDecoder.DecodeWithMatchByte(m_RangeDecoder,
- (uint)nowPos64, prevByte, m_OutWindow.GetByte(rep0));
- else
- b = m_LiteralDecoder.DecodeNormal(m_RangeDecoder, (uint)nowPos64, prevByte);
- m_OutWindow.PutByte(b);
- state.UpdateChar();
- nowPos64++;
- }
- else
- {
- uint len;
- if (m_IsRepDecoders[state.Index].Decode(m_RangeDecoder) == 1)
- {
- if (m_IsRepG0Decoders[state.Index].Decode(m_RangeDecoder) == 0)
- {
- if (m_IsRep0LongDecoders[(state.Index << Base.kNumPosStatesBitsMax) + posState].Decode(m_RangeDecoder) == 0)
- {
- state.UpdateShortRep();
- m_OutWindow.PutByte(m_OutWindow.GetByte(rep0));
- nowPos64++;
- continue;
- }
- }
- else
- {
- UInt32 distance;
- if (m_IsRepG1Decoders[state.Index].Decode(m_RangeDecoder) == 0)
- {
- distance = rep1;
- }
- else
- {
- if (m_IsRepG2Decoders[state.Index].Decode(m_RangeDecoder) == 0)
- distance = rep2;
- else
- {
- distance = rep3;
- rep3 = rep2;
- }
- rep2 = rep1;
- }
- rep1 = rep0;
- rep0 = distance;
- }
- len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen;
- state.UpdateRep();
- }
- else
- {
- rep3 = rep2;
- rep2 = rep1;
- rep1 = rep0;
- len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState);
- state.UpdateMatch();
- uint posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder);
- if (posSlot >= Base.kStartPosModelIndex)
- {
- int numDirectBits = (int)((posSlot >> 1) - 1);
- rep0 = ((2 | (posSlot & 1)) << numDirectBits);
- if (posSlot < Base.kEndPosModelIndex)
- rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders,
- rep0 - posSlot - 1, m_RangeDecoder, numDirectBits);
- else
- {
- rep0 += (m_RangeDecoder.DecodeDirectBits(
- numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits);
- rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder);
- }
- }
- else
- rep0 = posSlot;
- }
- if (rep0 >= m_OutWindow.TrainSize + nowPos64 || rep0 >= m_DictionarySizeCheck)
- {
- if (rep0 == 0xFFFFFFFF)
- break;
- throw new DataErrorException();
- }
- m_OutWindow.CopyBlock(rep0, len);
- nowPos64 += len;
- }
- }
- }
- m_OutWindow.Flush();
- m_OutWindow.ReleaseStream();
- m_RangeDecoder.ReleaseStream();
- }
-
- public void SetDecoderProperties(byte[] properties)
- {
- if (properties.Length < 5)
- throw new InvalidParamException();
- int lc = properties[0] % 9;
- int remainder = properties[0] / 9;
- int lp = remainder % 5;
- int pb = remainder / 5;
- if (pb > Base.kNumPosStatesBitsMax)
- throw new InvalidParamException();
- UInt32 dictionarySize = 0;
- for (int i = 0; i < 4; i++)
- dictionarySize += ((UInt32)(properties[1 + i])) << (i * 8);
- SetDictionarySize(dictionarySize);
- SetLiteralProperties(lp, lc);
- SetPosBitsProperties(pb);
- }
-
- public bool Train(System.IO.Stream stream)
- {
- _solid = true;
- return m_OutWindow.Train(stream);
- }
-
- /*
- public override bool CanRead { get { return true; }}
- public override bool CanWrite { get { return true; }}
- public override bool CanSeek { get { return true; }}
- public override long Length { get { return 0; }}
- public override long Position
- {
- get { return 0; }
- set { }
- }
- public override void Flush() { }
- public override int Read(byte[] buffer, int offset, int count)
- {
- return 0;
- }
- public override void Write(byte[] buffer, int offset, int count)
- {
- }
- public override long Seek(long offset, System.IO.SeekOrigin origin)
- {
- return 0;
- }
- public override void SetLength(long value) {}
- */
- }
-}
diff --git a/CS/7zip/Compress/LZMA/LzmaEncoder.cs b/CS/7zip/Compress/LZMA/LzmaEncoder.cs
deleted file mode 100644
index 6dc2708..0000000
--- a/CS/7zip/Compress/LZMA/LzmaEncoder.cs
+++ /dev/null
@@ -1,1480 +0,0 @@
-// LzmaEncoder.cs
-
-using System;
-
-namespace SevenZip.Compression.LZMA
-{
- using RangeCoder;
-
- public class Encoder : ICoder, ISetCoderProperties, IWriteCoderProperties
- {
- enum EMatchFinderType
- {
- BT2,
- BT4,
- };
-
- const UInt32 kIfinityPrice = 0xFFFFFFF;
-
- static Byte[] g_FastPos = new Byte[1 << 11];
-
- static Encoder()
- {
- const Byte kFastSlots = 22;
- int c = 2;
- g_FastPos[0] = 0;
- g_FastPos[1] = 1;
- for (Byte slotFast = 2; slotFast < kFastSlots; slotFast++)
- {
- UInt32 k = ((UInt32)1 << ((slotFast >> 1) - 1));
- for (UInt32 j = 0; j < k; j++, c++)
- g_FastPos[c] = slotFast;
- }
- }
-
- static UInt32 GetPosSlot(UInt32 pos)
- {
- if (pos < (1 << 11))
- return g_FastPos[pos];
- if (pos < (1 << 21))
- return (UInt32)(g_FastPos[pos >> 10] + 20);
- return (UInt32)(g_FastPos[pos >> 20] + 40);
- }
-
- static UInt32 GetPosSlot2(UInt32 pos)
- {
- if (pos < (1 << 17))
- return (UInt32)(g_FastPos[pos >> 6] + 12);
- if (pos < (1 << 27))
- return (UInt32)(g_FastPos[pos >> 16] + 32);
- return (UInt32)(g_FastPos[pos >> 26] + 52);
- }
-
- Base.State _state = new Base.State();
- Byte _previousByte;
- UInt32[] _repDistances = new UInt32[Base.kNumRepDistances];
-
- void BaseInit()
- {
- _state.Init();
- _previousByte = 0;
- for (UInt32 i = 0; i < Base.kNumRepDistances; i++)
- _repDistances[i] = 0;
- }
-
- const int kDefaultDictionaryLogSize = 22;
- const UInt32 kNumFastBytesDefault = 0x20;
-
- class LiteralEncoder
- {
- public struct Encoder2
- {
- BitEncoder[] m_Encoders;
-
- public void Create() { m_Encoders = new BitEncoder[0x300]; }
-
- public void Init() { for (int i = 0; i < 0x300; i++) m_Encoders[i].Init(); }
-
- public void Encode(RangeCoder.Encoder rangeEncoder, byte symbol)
- {
- uint context = 1;
- for (int i = 7; i >= 0; i--)
- {
- uint bit = (uint)((symbol >> i) & 1);
- m_Encoders[context].Encode(rangeEncoder, bit);
- context = (context << 1) | bit;
- }
- }
-
- public void EncodeMatched(RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol)
- {
- uint context = 1;
- bool same = true;
- for (int i = 7; i >= 0; i--)
- {
- uint bit = (uint)((symbol >> i) & 1);
- uint state = context;
- if (same)
- {
- uint matchBit = (uint)((matchByte >> i) & 1);
- state += ((1 + matchBit) << 8);
- same = (matchBit == bit);
- }
- m_Encoders[state].Encode(rangeEncoder, bit);
- context = (context << 1) | bit;
- }
- }
-
- public uint GetPrice(bool matchMode, byte matchByte, byte symbol)
- {
- uint price = 0;
- uint context = 1;
- int i = 7;
- if (matchMode)
- {
- for (; i >= 0; i--)
- {
- uint matchBit = (uint)(matchByte >> i) & 1;
- uint bit = (uint)(symbol >> i) & 1;
- price += m_Encoders[((1 + matchBit) << 8) + context].GetPrice(bit);
- context = (context << 1) | bit;
- if (matchBit != bit)
- {
- i--;
- break;
- }
- }
- }
- for (; i >= 0; i--)
- {
- uint bit = (uint)(symbol >> i) & 1;
- price += m_Encoders[context].GetPrice(bit);
- context = (context << 1) | bit;
- }
- return price;
- }
- }
-
- Encoder2[] m_Coders;
- int m_NumPrevBits;
- int m_NumPosBits;
- uint m_PosMask;
-
- public void Create(int numPosBits, int numPrevBits)
- {
- if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits)
- return;
- m_NumPosBits = numPosBits;
- m_PosMask = ((uint)1 << numPosBits) - 1;
- m_NumPrevBits = numPrevBits;
- uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
- m_Coders = new Encoder2[numStates];
- for (uint i = 0; i < numStates; i++)
- m_Coders[i].Create();
- }
-
- public void Init()
- {
- uint numStates = (uint)1 << (m_NumPrevBits + m_NumPosBits);
- for (uint i = 0; i < numStates; i++)
- m_Coders[i].Init();
- }
-
- public Encoder2 GetSubCoder(UInt32 pos, Byte prevByte)
- { return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + (uint)(prevByte >> (8 - m_NumPrevBits))]; }
- }
-
- class LenEncoder
- {
- RangeCoder.BitEncoder _choice = new RangeCoder.BitEncoder();
- RangeCoder.BitEncoder _choice2 = new RangeCoder.BitEncoder();
- RangeCoder.BitTreeEncoder[] _lowCoder = new RangeCoder.BitTreeEncoder[Base.kNumPosStatesEncodingMax];
- RangeCoder.BitTreeEncoder[] _midCoder = new RangeCoder.BitTreeEncoder[Base.kNumPosStatesEncodingMax];
- RangeCoder.BitTreeEncoder _highCoder = new RangeCoder.BitTreeEncoder(Base.kNumHighLenBits);
-
- public LenEncoder()
- {
- for (UInt32 posState = 0; posState < Base.kNumPosStatesEncodingMax; posState++)
- {
- _lowCoder[posState] = new RangeCoder.BitTreeEncoder(Base.kNumLowLenBits);
- _midCoder[posState] = new RangeCoder.BitTreeEncoder(Base.kNumMidLenBits);
- }
- }
-
- public void Init(UInt32 numPosStates)
- {
- _choice.Init();
- _choice2.Init();
- for (UInt32 posState = 0; posState < numPosStates; posState++)
- {
- _lowCoder[posState].Init();
- _midCoder[posState].Init();
- }
- _highCoder.Init();
- }
-
- public void Encode(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState)
- {
- if (symbol < Base.kNumLowLenSymbols)
- {
- _choice.Encode(rangeEncoder, 0);
- _lowCoder[posState].Encode(rangeEncoder, symbol);
- }
- else
- {
- symbol -= Base.kNumLowLenSymbols;
- _choice.Encode(rangeEncoder, 1);
- if (symbol < Base.kNumMidLenSymbols)
- {
- _choice2.Encode(rangeEncoder, 0);
- _midCoder[posState].Encode(rangeEncoder, symbol);
- }
- else
- {
- _choice2.Encode(rangeEncoder, 1);
- _highCoder.Encode(rangeEncoder, symbol - Base.kNumMidLenSymbols);
- }
- }
- }
-
- public void SetPrices(UInt32 posState, UInt32 numSymbols, UInt32[] prices, UInt32 st)
- {
- UInt32 a0 = _choice.GetPrice0();
- UInt32 a1 = _choice.GetPrice1();
- UInt32 b0 = a1 + _choice2.GetPrice0();
- UInt32 b1 = a1 + _choice2.GetPrice1();
- UInt32 i = 0;
- for (i = 0; i < Base.kNumLowLenSymbols; i++)
- {
- if (i >= numSymbols)
- return;
- prices[st + i] = a0 + _lowCoder[posState].GetPrice(i);
- }
- for (; i < Base.kNumLowLenSymbols + Base.kNumMidLenSymbols; i++)
- {
- if (i >= numSymbols)
- return;
- prices[st + i] = b0 + _midCoder[posState].GetPrice(i - Base.kNumLowLenSymbols);
- }
- for (; i < numSymbols; i++)
- prices[st + i] = b1 + _highCoder.GetPrice(i - Base.kNumLowLenSymbols - Base.kNumMidLenSymbols);
- }
- };
-
- const UInt32 kNumLenSpecSymbols = Base.kNumLowLenSymbols + Base.kNumMidLenSymbols;
-
- class LenPriceTableEncoder : LenEncoder
- {
- UInt32[] _prices = new UInt32[Base.kNumLenSymbols << Base.kNumPosStatesBitsEncodingMax];
- UInt32 _tableSize;
- UInt32[] _counters = new UInt32[Base.kNumPosStatesEncodingMax];
-
- public void SetTableSize(UInt32 tableSize) { _tableSize = tableSize; }
-
- public UInt32 GetPrice(UInt32 symbol, UInt32 posState)
- {
- return _prices[posState * Base.kNumLenSymbols + symbol];
- }
-
- void UpdateTable(UInt32 posState)
- {
- SetPrices(posState, _tableSize, _prices, posState * Base.kNumLenSymbols);
- _counters[posState] = _tableSize;
- }
-
- public void UpdateTables(UInt32 numPosStates)
- {
- for (UInt32 posState = 0; posState < numPosStates; posState++)
- UpdateTable(posState);
- }
-
- public new void Encode(RangeCoder.Encoder rangeEncoder, UInt32 symbol, UInt32 posState)
- {
- base.Encode(rangeEncoder, symbol, posState);
- if (--_counters[posState] == 0)
- UpdateTable(posState);
- }
- }
-
- const UInt32 kNumOpts = 1 << 12;
- class Optimal
- {
- public Base.State State;
-
- public bool Prev1IsChar;
- public bool Prev2;
-
- public UInt32 PosPrev2;
- public UInt32 BackPrev2;
-
- public UInt32 Price;
- public UInt32 PosPrev;
- public UInt32 BackPrev;
-
- public UInt32 Backs0;
- public UInt32 Backs1;
- public UInt32 Backs2;
- public UInt32 Backs3;
-
- public void MakeAsChar() { BackPrev = 0xFFFFFFFF; Prev1IsChar = false; }
- public void MakeAsShortRep() { BackPrev = 0; ; Prev1IsChar = false; }
- public bool IsShortRep() { return (BackPrev == 0); }
- };
- Optimal[] _optimum = new Optimal[kNumOpts];
- LZ.IMatchFinder _matchFinder = null;
- RangeCoder.Encoder _rangeEncoder = new RangeCoder.Encoder();
-
- RangeCoder.BitEncoder[] _isMatch = new RangeCoder.BitEncoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
- RangeCoder.BitEncoder[] _isRep = new RangeCoder.BitEncoder[Base.kNumStates];
- RangeCoder.BitEncoder[] _isRepG0 = new RangeCoder.BitEncoder[Base.kNumStates];
- RangeCoder.BitEncoder[] _isRepG1 = new RangeCoder.BitEncoder[Base.kNumStates];
- RangeCoder.BitEncoder[] _isRepG2 = new RangeCoder.BitEncoder[Base.kNumStates];
- RangeCoder.BitEncoder[] _isRep0Long = new RangeCoder.BitEncoder[Base.kNumStates << Base.kNumPosStatesBitsMax];
-
- RangeCoder.BitTreeEncoder[] _posSlotEncoder = new RangeCoder.BitTreeEncoder[Base.kNumLenToPosStates];
-
- RangeCoder.BitEncoder[] _posEncoders = new RangeCoder.BitEncoder[Base.kNumFullDistances - Base.kEndPosModelIndex];
- RangeCoder.BitTreeEncoder _posAlignEncoder = new RangeCoder.BitTreeEncoder(Base.kNumAlignBits);
-
- LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder();
- LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder();
-
- LiteralEncoder _literalEncoder = new LiteralEncoder();
-
- UInt32[] _matchDistances = new UInt32[Base.kMatchMaxLen * 2 + 2];
-
- UInt32 _numFastBytes = kNumFastBytesDefault;
- UInt32 _longestMatchLength;
- UInt32 _numDistancePairs;
-
- UInt32 _additionalOffset;
-
- UInt32 _optimumEndIndex;
- UInt32 _optimumCurrentIndex;
-
- bool _longestMatchWasFound;
-
- UInt32[] _posSlotPrices = new UInt32[1 << (Base.kNumPosSlotBits + Base.kNumLenToPosStatesBits)];
- UInt32[] _distancesPrices = new UInt32[Base.kNumFullDistances << Base.kNumLenToPosStatesBits];
- UInt32[] _alignPrices = new UInt32[Base.kAlignTableSize];
- UInt32 _alignPriceCount;
-
- UInt32 _distTableSize = (kDefaultDictionaryLogSize * 2);
-
- int _posStateBits = 2;
- UInt32 _posStateMask = (4 - 1);
- int _numLiteralPosStateBits = 0;
- int _numLiteralContextBits = 3;
-
- UInt32 _dictionarySize = (1 << kDefaultDictionaryLogSize);
- UInt32 _dictionarySizePrev = 0xFFFFFFFF;
- UInt32 _numFastBytesPrev = 0xFFFFFFFF;
-
- Int64 nowPos64;
- bool _finished;
- System.IO.Stream _inStream;
-
- EMatchFinderType _matchFinderType = EMatchFinderType.BT4;
- bool _writeEndMark = false;
-
- bool _needReleaseMFStream;
-
- void Create()
- {
- if (_matchFinder == null)
- {
- LZ.BinTree bt = new LZ.BinTree();
- int numHashBytes = 4;
- if (_matchFinderType == EMatchFinderType.BT2)
- numHashBytes = 2;
- bt.SetType(numHashBytes);
- _matchFinder = bt;
- }
- _literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits);
-
- if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes)
- return;
- _matchFinder.Create(_dictionarySize, kNumOpts, _numFastBytes, Base.kMatchMaxLen + 1);
- _dictionarySizePrev = _dictionarySize;
- _numFastBytesPrev = _numFastBytes;
- }
-
- public Encoder()
- {
- for (int i = 0; i < kNumOpts; i++)
- _optimum[i] = new Optimal();
- for (int i = 0; i < Base.kNumLenToPosStates; i++)
- _posSlotEncoder[i] = new RangeCoder.BitTreeEncoder(Base.kNumPosSlotBits);
- }
-
- void SetWriteEndMarkerMode(bool writeEndMarker)
- {
- _writeEndMark = writeEndMarker;
- }
-
- void Init()
- {
- BaseInit();
- _rangeEncoder.Init();
-
- uint i;
- for (i = 0; i < Base.kNumStates; i++)
- {
- for (uint j = 0; j <= _posStateMask; j++)
- {
- uint complexState = (i << Base.kNumPosStatesBitsMax) + j;
- _isMatch[complexState].Init();
- _isRep0Long[complexState].Init();
- }
- _isRep[i].Init();
- _isRepG0[i].Init();
- _isRepG1[i].Init();
- _isRepG2[i].Init();
- }
- _literalEncoder.Init();
- for (i = 0; i < Base.kNumLenToPosStates; i++)
- _posSlotEncoder[i].Init();
- for (i = 0; i < Base.kNumFullDistances - Base.kEndPosModelIndex; i++)
- _posEncoders[i].Init();
-
- _lenEncoder.Init((UInt32)1 << _posStateBits);
- _repMatchLenEncoder.Init((UInt32)1 << _posStateBits);
-
- _posAlignEncoder.Init();
-
- _longestMatchWasFound = false;
- _optimumEndIndex = 0;
- _optimumCurrentIndex = 0;
- _additionalOffset = 0;
- }
-
- void ReadMatchDistances(out UInt32 lenRes, out UInt32 numDistancePairs)
- {
- lenRes = 0;
- numDistancePairs = _matchFinder.GetMatches(_matchDistances);
- if (numDistancePairs > 0)
- {
- lenRes = _matchDistances[numDistancePairs - 2];
- if (lenRes == _numFastBytes)
- lenRes += _matchFinder.GetMatchLen((int)lenRes - 1, _matchDistances[numDistancePairs - 1],
- Base.kMatchMaxLen - lenRes);
- }
- _additionalOffset++;
- }
-
-
- void MovePos(UInt32 num)
- {
- if (num > 0)
- {
- _matchFinder.Skip(num);
- _additionalOffset += num;
- }
- }
-
- UInt32 GetRepLen1Price(Base.State state, UInt32 posState)
- {
- return _isRepG0[state.Index].GetPrice0() +
- _isRep0Long[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0();
- }
-
- UInt32 GetPureRepPrice(UInt32 repIndex, Base.State state, UInt32 posState)
- {
- UInt32 price;
- if (repIndex == 0)
- {
- price = _isRepG0[state.Index].GetPrice0();
- price += _isRep0Long[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1();
- }
- else
- {
- price = _isRepG0[state.Index].GetPrice1();
- if (repIndex == 1)
- price += _isRepG1[state.Index].GetPrice0();
- else
- {
- price += _isRepG1[state.Index].GetPrice1();
- price += _isRepG2[state.Index].GetPrice(repIndex - 2);
- }
- }
- return price;
- }
-
- UInt32 GetRepPrice(UInt32 repIndex, UInt32 len, Base.State state, UInt32 posState)
- {
- UInt32 price = _repMatchLenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
- return price + GetPureRepPrice(repIndex, state, posState);
- }
-
- UInt32 GetPosLenPrice(UInt32 pos, UInt32 len, UInt32 posState)
- {
- UInt32 price;
- UInt32 lenToPosState = Base.GetLenToPosState(len);
- if (pos < Base.kNumFullDistances)
- price = _distancesPrices[(lenToPosState * Base.kNumFullDistances) + pos];
- else
- price = _posSlotPrices[(lenToPosState << Base.kNumPosSlotBits) + GetPosSlot2(pos)] +
- _alignPrices[pos & Base.kAlignMask];
- return price + _lenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
- }
-
- UInt32 Backward(out UInt32 backRes, UInt32 cur)
- {
- _optimumEndIndex = cur;
- UInt32 posMem = _optimum[cur].PosPrev;
- UInt32 backMem = _optimum[cur].BackPrev;
- do
- {
- if (_optimum[cur].Prev1IsChar)
- {
- _optimum[posMem].MakeAsChar();
- _optimum[posMem].PosPrev = posMem - 1;
- if (_optimum[cur].Prev2)
- {
- _optimum[posMem - 1].Prev1IsChar = false;
- _optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2;
- _optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2;
- }
- }
- UInt32 posPrev = posMem;
- UInt32 backCur = backMem;
-
- backMem = _optimum[posPrev].BackPrev;
- posMem = _optimum[posPrev].PosPrev;
-
- _optimum[posPrev].BackPrev = backCur;
- _optimum[posPrev].PosPrev = cur;
- cur = posPrev;
- }
- while (cur > 0);
- backRes = _optimum[0].BackPrev;
- _optimumCurrentIndex = _optimum[0].PosPrev;
- return _optimumCurrentIndex;
- }
-
- UInt32[] reps = new UInt32[Base.kNumRepDistances];
- UInt32[] repLens = new UInt32[Base.kNumRepDistances];
-
-
- UInt32 GetOptimum(UInt32 position, out UInt32 backRes)
- {
- if (_optimumEndIndex != _optimumCurrentIndex)
- {
- UInt32 lenRes = _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex;
- backRes = _optimum[_optimumCurrentIndex].BackPrev;
- _optimumCurrentIndex = _optimum[_optimumCurrentIndex].PosPrev;
- return lenRes;
- }
- _optimumCurrentIndex = _optimumEndIndex = 0;
-
- UInt32 lenMain, numDistancePairs;
- if (!_longestMatchWasFound)
- {
- ReadMatchDistances(out lenMain, out numDistancePairs);
- }
- else
- {
- lenMain = _longestMatchLength;
- numDistancePairs = _numDistancePairs;
- _longestMatchWasFound = false;
- }
-
- UInt32 numAvailableBytes = _matchFinder.GetNumAvailableBytes() + 1;
- if (numAvailableBytes < 2)
- {
- backRes = 0xFFFFFFFF;
- return 1;
- }
- if (numAvailableBytes > Base.kMatchMaxLen)
- numAvailableBytes = Base.kMatchMaxLen;
-
- UInt32 repMaxIndex = 0;
- UInt32 i;
- for (i = 0; i < Base.kNumRepDistances; i++)
- {
- reps[i] = _repDistances[i];
- repLens[i] = _matchFinder.GetMatchLen(0 - 1, reps[i], Base.kMatchMaxLen);
- if (repLens[i] > repLens[repMaxIndex])
- repMaxIndex = i;
- }
- if (repLens[repMaxIndex] >= _numFastBytes)
- {
- backRes = repMaxIndex;
- UInt32 lenRes = repLens[repMaxIndex];
- MovePos(lenRes - 1);
- return lenRes;
- }
-
- if (lenMain >= _numFastBytes)
- {
- backRes = _matchDistances[numDistancePairs - 1] + Base.kNumRepDistances;
- MovePos(lenMain - 1);
- return lenMain;
- }
-
- Byte currentByte = _matchFinder.GetIndexByte(0 - 1);
- Byte matchByte = _matchFinder.GetIndexByte((Int32)(0 - _repDistances[0] - 1 - 1));
-
- if (lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2)
- {
- backRes = (UInt32)0xFFFFFFFF;
- return 1;
- }
-
- _optimum[0].State = _state;
-
- UInt32 posState = (position & _posStateMask);
-
- _optimum[1].Price = _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0() +
- _literalEncoder.GetSubCoder(position, _previousByte).GetPrice(!_state.IsCharState(), matchByte, currentByte);
- _optimum[1].MakeAsChar();
-
- UInt32 matchPrice = _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1();
- UInt32 repMatchPrice = matchPrice + _isRep[_state.Index].GetPrice1();
-
- if (matchByte == currentByte)
- {
- UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState);
- if (shortRepPrice < _optimum[1].Price)
- {
- _optimum[1].Price = shortRepPrice;
- _optimum[1].MakeAsShortRep();
- }
- }
-
- UInt32 lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]);
-
- if(lenEnd < 2)
- {
- backRes = _optimum[1].BackPrev;
- return 1;
- }
-
- _optimum[1].PosPrev = 0;
-
- _optimum[0].Backs0 = reps[0];
- _optimum[0].Backs1 = reps[1];
- _optimum[0].Backs2 = reps[2];
- _optimum[0].Backs3 = reps[3];
-
- UInt32 len = lenEnd;
- do
- _optimum[len--].Price = kIfinityPrice;
- while (len >= 2);
-
- for (i = 0; i < Base.kNumRepDistances; i++)
- {
- UInt32 repLen = repLens[i];
- if (repLen < 2)
- continue;
- UInt32 price = repMatchPrice + GetPureRepPrice(i, _state, posState);
- do
- {
- UInt32 curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState);
- Optimal optimum = _optimum[repLen];
- if (curAndLenPrice < optimum.Price)
- {
- optimum.Price = curAndLenPrice;
- optimum.PosPrev = 0;
- optimum.BackPrev = i;
- optimum.Prev1IsChar = false;
- }
- }
- while (--repLen >= 2);
- }
-
- UInt32 normalMatchPrice = matchPrice + _isRep[_state.Index].GetPrice0();
-
- len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
- if (len <= lenMain)
- {
- UInt32 offs = 0;
- while (len > _matchDistances[offs])
- offs += 2;
- for (; ; len++)
- {
- UInt32 distance = _matchDistances[offs + 1];
- UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState);
- Optimal optimum = _optimum[len];
- if (curAndLenPrice < optimum.Price)
- {
- optimum.Price = curAndLenPrice;
- optimum.PosPrev = 0;
- optimum.BackPrev = distance + Base.kNumRepDistances;
- optimum.Prev1IsChar = false;
- }
- if (len == _matchDistances[offs])
- {
- offs += 2;
- if (offs == numDistancePairs)
- break;
- }
- }
- }
-
- UInt32 cur = 0;
-
- while (true)
- {
- cur++;
- if (cur == lenEnd)
- return Backward(out backRes, cur);
- UInt32 newLen;
- ReadMatchDistances(out newLen, out numDistancePairs);
- if (newLen >= _numFastBytes)
- {
- _numDistancePairs = numDistancePairs;
- _longestMatchLength = newLen;
- _longestMatchWasFound = true;
- return Backward(out backRes, cur);
- }
- position++;
- UInt32 posPrev = _optimum[cur].PosPrev;
- Base.State state;
- if (_optimum[cur].Prev1IsChar)
- {
- posPrev--;
- if (_optimum[cur].Prev2)
- {
- state = _optimum[_optimum[cur].PosPrev2].State;
- if (_optimum[cur].BackPrev2 < Base.kNumRepDistances)
- state.UpdateRep();
- else
- state.UpdateMatch();
- }
- else
- state = _optimum[posPrev].State;
- state.UpdateChar();
- }
- else
- state = _optimum[posPrev].State;
- if (posPrev == cur - 1)
- {
- if (_optimum[cur].IsShortRep())
- state.UpdateShortRep();
- else
- state.UpdateChar();
- }
- else
- {
- UInt32 pos;
- if (_optimum[cur].Prev1IsChar && _optimum[cur].Prev2)
- {
- posPrev = _optimum[cur].PosPrev2;
- pos = _optimum[cur].BackPrev2;
- state.UpdateRep();
- }
- else
- {
- pos = _optimum[cur].BackPrev;
- if (pos < Base.kNumRepDistances)
- state.UpdateRep();
- else
- state.UpdateMatch();
- }
- Optimal opt = _optimum[posPrev];
- if (pos < Base.kNumRepDistances)
- {
- if (pos == 0)
- {
- reps[0] = opt.Backs0;
- reps[1] = opt.Backs1;
- reps[2] = opt.Backs2;
- reps[3] = opt.Backs3;
- }
- else if (pos == 1)
- {
- reps[0] = opt.Backs1;
- reps[1] = opt.Backs0;
- reps[2] = opt.Backs2;
- reps[3] = opt.Backs3;
- }
- else if (pos == 2)
- {
- reps[0] = opt.Backs2;
- reps[1] = opt.Backs0;
- reps[2] = opt.Backs1;
- reps[3] = opt.Backs3;
- }
- else
- {
- reps[0] = opt.Backs3;
- reps[1] = opt.Backs0;
- reps[2] = opt.Backs1;
- reps[3] = opt.Backs2;
- }
- }
- else
- {
- reps[0] = (pos - Base.kNumRepDistances);
- reps[1] = opt.Backs0;
- reps[2] = opt.Backs1;
- reps[3] = opt.Backs2;
- }
- }
- _optimum[cur].State = state;
- _optimum[cur].Backs0 = reps[0];
- _optimum[cur].Backs1 = reps[1];
- _optimum[cur].Backs2 = reps[2];
- _optimum[cur].Backs3 = reps[3];
- UInt32 curPrice = _optimum[cur].Price;
-
- currentByte = _matchFinder.GetIndexByte(0 - 1);
- matchByte = _matchFinder.GetIndexByte((Int32)(0 - reps[0] - 1 - 1));
-
- posState = (position & _posStateMask);
-
- UInt32 curAnd1Price = curPrice +
- _isMatch[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice0() +
- _literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)).
- GetPrice(!state.IsCharState(), matchByte, currentByte);
-
- Optimal nextOptimum = _optimum[cur + 1];
-
- bool nextIsChar = false;
- if (curAnd1Price < nextOptimum.Price)
- {
- nextOptimum.Price = curAnd1Price;
- nextOptimum.PosPrev = cur;
- nextOptimum.MakeAsChar();
- nextIsChar = true;
- }
-
- matchPrice = curPrice + _isMatch[(state.Index << Base.kNumPosStatesBitsMax) + posState].GetPrice1();
- repMatchPrice = matchPrice + _isRep[state.Index].GetPrice1();
-
- if (matchByte == currentByte &&
- !(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0))
- {
- UInt32 shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState);
- if (shortRepPrice <= nextOptimum.Price)
- {
- nextOptimum.Price = shortRepPrice;
- nextOptimum.PosPrev = cur;
- nextOptimum.MakeAsShortRep();
- nextIsChar = true;
- }
- }
-
- UInt32 numAvailableBytesFull = _matchFinder.GetNumAvailableBytes() + 1;
- numAvailableBytesFull = Math.Min(kNumOpts - 1 - cur, numAvailableBytesFull);
- numAvailableBytes = numAvailableBytesFull;
-
- if (numAvailableBytes < 2)
- continue;
- if (numAvailableBytes > _numFastBytes)
- numAvailableBytes = _numFastBytes;
- if (!nextIsChar && matchByte != currentByte)
- {
- // try Literal + rep0
- UInt32 t = Math.Min(numAvailableBytesFull - 1, _numFastBytes);
- UInt32 lenTest2 = _matchFinder.GetMatchLen(0, reps[0], t);
- if (lenTest2 >= 2)
- {
- Base.State state2 = state;
- state2.UpdateChar();
- UInt32 posStateNext = (position + 1) & _posStateMask;
- UInt32 nextRepMatchPrice = curAnd1Price +
- _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1() +
- _isRep[state2.Index].GetPrice1();
- {
- UInt32 offset = cur + 1 + lenTest2;
- while (lenEnd < offset)
- _optimum[++lenEnd].Price = kIfinityPrice;
- UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(
- 0, lenTest2, state2, posStateNext);
- Optimal optimum = _optimum[offset];
- if (curAndLenPrice < optimum.Price)
- {
- optimum.Price = curAndLenPrice;
- optimum.PosPrev = cur + 1;
- optimum.BackPrev = 0;
- optimum.Prev1IsChar = true;
- optimum.Prev2 = false;
- }
- }
- }
- }
-
- UInt32 startLen = 2; // speed optimization
-
- for (UInt32 repIndex = 0; repIndex < Base.kNumRepDistances; repIndex++)
- {
- UInt32 lenTest = _matchFinder.GetMatchLen(0 - 1, reps[repIndex], numAvailableBytes);
- if (lenTest < 2)
- continue;
- UInt32 lenTestTemp = lenTest;
- do
- {
- while (lenEnd < cur + lenTest)
- _optimum[++lenEnd].Price = kIfinityPrice;
- UInt32 curAndLenPrice = repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState);
- Optimal optimum = _optimum[cur + lenTest];
- if (curAndLenPrice < optimum.Price)
- {
- optimum.Price = curAndLenPrice;
- optimum.PosPrev = cur;
- optimum.BackPrev = repIndex;
- optimum.Prev1IsChar = false;
- }
- }
- while(--lenTest >= 2);
- lenTest = lenTestTemp;
-
- if (repIndex == 0)
- startLen = lenTest + 1;
-
- // if (_maxMode)
- if (lenTest < numAvailableBytesFull)
- {
- UInt32 t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
- UInt32 lenTest2 = _matchFinder.GetMatchLen((Int32)lenTest, reps[repIndex], t);
- if (lenTest2 >= 2)
- {
- Base.State state2 = state;
- state2.UpdateRep();
- UInt32 posStateNext = (position + lenTest) & _posStateMask;
- UInt32 curAndLenCharPrice =
- repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState) +
- _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice0() +
- _literalEncoder.GetSubCoder(position + lenTest,
- _matchFinder.GetIndexByte((Int32)lenTest - 1 - 1)).GetPrice(true,
- _matchFinder.GetIndexByte((Int32)((Int32)lenTest - 1 - (Int32)(reps[repIndex] + 1))),
- _matchFinder.GetIndexByte((Int32)lenTest - 1));
- state2.UpdateChar();
- posStateNext = (position + lenTest + 1) & _posStateMask;
- UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1();
- UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1();
-
- // for(; lenTest2 >= 2; lenTest2--)
- {
- UInt32 offset = lenTest + 1 + lenTest2;
- while(lenEnd < cur + offset)
- _optimum[++lenEnd].Price = kIfinityPrice;
- UInt32 curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
- Optimal optimum = _optimum[cur + offset];
- if (curAndLenPrice < optimum.Price)
- {
- optimum.Price = curAndLenPrice;
- optimum.PosPrev = cur + lenTest + 1;
- optimum.BackPrev = 0;
- optimum.Prev1IsChar = true;
- optimum.Prev2 = true;
- optimum.PosPrev2 = cur;
- optimum.BackPrev2 = repIndex;
- }
- }
- }
- }
- }
-
- if (newLen > numAvailableBytes)
- {
- newLen = numAvailableBytes;
- for (numDistancePairs = 0; newLen > _matchDistances[numDistancePairs]; numDistancePairs += 2) ;
- _matchDistances[numDistancePairs] = newLen;
- numDistancePairs += 2;
- }
- if (newLen >= startLen)
- {
- normalMatchPrice = matchPrice + _isRep[state.Index].GetPrice0();
- while (lenEnd < cur + newLen)
- _optimum[++lenEnd].Price = kIfinityPrice;
-
- UInt32 offs = 0;
- while (startLen > _matchDistances[offs])
- offs += 2;
-
- for (UInt32 lenTest = startLen; ; lenTest++)
- {
- UInt32 curBack = _matchDistances[offs + 1];
- UInt32 curAndLenPrice = normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState);
- Optimal optimum = _optimum[cur + lenTest];
- if (curAndLenPrice < optimum.Price)
- {
- optimum.Price = curAndLenPrice;
- optimum.PosPrev = cur;
- optimum.BackPrev = curBack + Base.kNumRepDistances;
- optimum.Prev1IsChar = false;
- }
-
- if (lenTest == _matchDistances[offs])
- {
- if (lenTest < numAvailableBytesFull)
- {
- UInt32 t = Math.Min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
- UInt32 lenTest2 = _matchFinder.GetMatchLen((Int32)lenTest, curBack, t);
- if (lenTest2 >= 2)
- {
- Base.State state2 = state;
- state2.UpdateMatch();
- UInt32 posStateNext = (position + lenTest) & _posStateMask;
- UInt32 curAndLenCharPrice = curAndLenPrice +
- _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice0() +
- _literalEncoder.GetSubCoder(position + lenTest,
- _matchFinder.GetIndexByte((Int32)lenTest - 1 - 1)).
- GetPrice(true,
- _matchFinder.GetIndexByte((Int32)lenTest - (Int32)(curBack + 1) - 1),
- _matchFinder.GetIndexByte((Int32)lenTest - 1));
- state2.UpdateChar();
- posStateNext = (position + lenTest + 1) & _posStateMask;
- UInt32 nextMatchPrice = curAndLenCharPrice + _isMatch[(state2.Index << Base.kNumPosStatesBitsMax) + posStateNext].GetPrice1();
- UInt32 nextRepMatchPrice = nextMatchPrice + _isRep[state2.Index].GetPrice1();
-
- UInt32 offset = lenTest + 1 + lenTest2;
- while (lenEnd < cur + offset)
- _optimum[++lenEnd].Price = kIfinityPrice;
- curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
- optimum = _optimum[cur + offset];
- if (curAndLenPrice < optimum.Price)
- {
- optimum.Price = curAndLenPrice;
- optimum.PosPrev = cur + lenTest + 1;
- optimum.BackPrev = 0;
- optimum.Prev1IsChar = true;
- optimum.Prev2 = true;
- optimum.PosPrev2 = cur;
- optimum.BackPrev2 = curBack + Base.kNumRepDistances;
- }
- }
- }
- offs += 2;
- if (offs == numDistancePairs)
- break;
- }
- }
- }
- }
- }
-
- bool ChangePair(UInt32 smallDist, UInt32 bigDist)
- {
- const int kDif = 7;
- return (smallDist < ((UInt32)(1) << (32 - kDif)) && bigDist >= (smallDist << kDif));
- }
-
- void WriteEndMarker(UInt32 posState)
- {
- if (!_writeEndMark)
- return;
-
- _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].Encode(_rangeEncoder, 1);
- _isRep[_state.Index].Encode(_rangeEncoder, 0);
- _state.UpdateMatch();
- UInt32 len = Base.kMatchMinLen;
- _lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
- UInt32 posSlot = (1 << Base.kNumPosSlotBits) - 1;
- UInt32 lenToPosState = Base.GetLenToPosState(len);
- _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
- int footerBits = 30;
- UInt32 posReduced = (((UInt32)1) << footerBits) - 1;
- _rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
- _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
- }
-
- void Flush(UInt32 nowPos)
- {
- ReleaseMFStream();
- WriteEndMarker(nowPos & _posStateMask);
- _rangeEncoder.FlushData();
- _rangeEncoder.FlushStream();
- }
-
- public void CodeOneBlock(out Int64 inSize, out Int64 outSize, out bool finished)
- {
- inSize = 0;
- outSize = 0;
- finished = true;
-
- if (_inStream != null)
- {
- _matchFinder.SetStream(_inStream);
- _matchFinder.Init();
- _needReleaseMFStream = true;
- _inStream = null;
- if (_trainSize > 0)
- _matchFinder.Skip(_trainSize);
- }
-
- if (_finished)
- return;
- _finished = true;
-
-
- Int64 progressPosValuePrev = nowPos64;
- if (nowPos64 == 0)
- {
- if (_matchFinder.GetNumAvailableBytes() == 0)
- {
- Flush((UInt32)nowPos64);
- return;
- }
- UInt32 len, numDistancePairs; // it's not used
- ReadMatchDistances(out len, out numDistancePairs);
- UInt32 posState = (UInt32)(nowPos64) & _posStateMask;
- _isMatch[(_state.Index << Base.kNumPosStatesBitsMax) + posState].Encode(_rangeEncoder, 0);
- _state.UpdateChar();
- Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset));
- _literalEncoder.GetSubCoder((UInt32)(nowPos64), _previousByte).Encode(_rangeEncoder, curByte);
- _previousByte = curByte;
- _additionalOffset--;
- nowPos64++;
- }
- if (_matchFinder.GetNumAvailableBytes() == 0)
- {
- Flush((UInt32)nowPos64);
- return;
- }
- while (true)
- {
- UInt32 pos;
- UInt32 len = GetOptimum((UInt32)nowPos64, out pos);
-
- UInt32 posState = ((UInt32)nowPos64) & _posStateMask;
- UInt32 complexState = (_state.Index << Base.kNumPosStatesBitsMax) + posState;
- if (len == 1 && pos == 0xFFFFFFFF)
- {
- _isMatch[complexState].Encode(_rangeEncoder, 0);
- Byte curByte = _matchFinder.GetIndexByte((Int32)(0 - _additionalOffset));
- LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((UInt32)nowPos64, _previousByte);
- if (!_state.IsCharState())
- {
- Byte matchByte = _matchFinder.GetIndexByte((Int32)(0 - _repDistances[0] - 1 - _additionalOffset));
- subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte);
- }
- else
- subCoder.Encode(_rangeEncoder, curByte);
- _previousByte = curByte;
- _state.UpdateChar();
- }
- else
- {
- _isMatch[complexState].Encode(_rangeEncoder, 1);
- if (pos < Base.kNumRepDistances)
- {
- _isRep[_state.Index].Encode(_rangeEncoder, 1);
- if (pos == 0)
- {
- _isRepG0[_state.Index].Encode(_rangeEncoder, 0);
- if (len == 1)
- _isRep0Long[complexState].Encode(_rangeEncoder, 0);
- else
- _isRep0Long[complexState].Encode(_rangeEncoder, 1);
- }
- else
- {
- _isRepG0[_state.Index].Encode(_rangeEncoder, 1);
- if (pos == 1)
- _isRepG1[_state.Index].Encode(_rangeEncoder, 0);
- else
- {
- _isRepG1[_state.Index].Encode(_rangeEncoder, 1);
- _isRepG2[_state.Index].Encode(_rangeEncoder, pos - 2);
- }
- }
- if (len == 1)
- _state.UpdateShortRep();
- else
- {
- _repMatchLenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
- _state.UpdateRep();
- }
- UInt32 distance = _repDistances[pos];
- if (pos != 0)
- {
- for (UInt32 i = pos; i >= 1; i--)
- _repDistances[i] = _repDistances[i - 1];
- _repDistances[0] = distance;
- }
- }
- else
- {
- _isRep[_state.Index].Encode(_rangeEncoder, 0);
- _state.UpdateMatch();
- _lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
- pos -= Base.kNumRepDistances;
- UInt32 posSlot = GetPosSlot(pos);
- UInt32 lenToPosState = Base.GetLenToPosState(len);
- _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
-
- if (posSlot >= Base.kStartPosModelIndex)
- {
- int footerBits = (int)((posSlot >> 1) - 1);
- UInt32 baseVal = ((2 | (posSlot & 1)) << footerBits);
- UInt32 posReduced = pos - baseVal;
-
- if (posSlot < Base.kEndPosModelIndex)
- RangeCoder.BitTreeEncoder.ReverseEncode(_posEncoders,
- baseVal - posSlot - 1, _rangeEncoder, footerBits, posReduced);
- else
- {
- _rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
- _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
- _alignPriceCount++;
- }
- }
- UInt32 distance = pos;
- for (UInt32 i = Base.kNumRepDistances - 1; i >= 1; i--)
- _repDistances[i] = _repDistances[i - 1];
- _repDistances[0] = distance;
- _matchPriceCount++;
- }
- _previousByte = _matchFinder.GetIndexByte((Int32)(len - 1 - _additionalOffset));
- }
- _additionalOffset -= len;
- nowPos64 += len;
- if (_additionalOffset == 0)
- {
- // if (!_fastMode)
- if (_matchPriceCount >= (1 << 7))
- FillDistancesPrices();
- if (_alignPriceCount >= Base.kAlignTableSize)
- FillAlignPrices();
- inSize = nowPos64;
- outSize = _rangeEncoder.GetProcessedSizeAdd();
- if (_matchFinder.GetNumAvailableBytes() == 0)
- {
- Flush((UInt32)nowPos64);
- return;
- }
-
- if (nowPos64 - progressPosValuePrev >= (1 << 12))
- {
- _finished = false;
- finished = false;
- return;
- }
- }
- }
- }
-
- void ReleaseMFStream()
- {
- if (_matchFinder != null && _needReleaseMFStream)
- {
- _matchFinder.ReleaseStream();
- _needReleaseMFStream = false;
- }
- }
-
- void SetOutStream(System.IO.Stream outStream) { _rangeEncoder.SetStream(outStream); }
- void ReleaseOutStream() { _rangeEncoder.ReleaseStream(); }
-
- void ReleaseStreams()
- {
- ReleaseMFStream();
- ReleaseOutStream();
- }
-
- void SetStreams(System.IO.Stream inStream, System.IO.Stream outStream,
- Int64 inSize, Int64 outSize)
- {
- _inStream = inStream;
- _finished = false;
- Create();
- SetOutStream(outStream);
- Init();
-
- // if (!_fastMode)
- {
- FillDistancesPrices();
- FillAlignPrices();
- }
-
- _lenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);
- _lenEncoder.UpdateTables((UInt32)1 << _posStateBits);
- _repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);
- _repMatchLenEncoder.UpdateTables((UInt32)1 << _posStateBits);
-
- nowPos64 = 0;
- }
-
-
- public void Code(System.IO.Stream inStream, System.IO.Stream outStream,
- Int64 inSize, Int64 outSize, ICodeProgress progress)
- {
- _needReleaseMFStream = false;
- try
- {
- SetStreams(inStream, outStream, inSize, outSize);
- while (true)
- {
- Int64 processedInSize;
- Int64 processedOutSize;
- bool finished;
- CodeOneBlock(out processedInSize, out processedOutSize, out finished);
- if (finished)
- return;
- if (progress != null)
- {
- progress.SetProgress(processedInSize, processedOutSize);
- }
- }
- }
- finally
- {
- ReleaseStreams();
- }
- }
-
- const int kPropSize = 5;
- Byte[] properties = new Byte[kPropSize];
-
- public void WriteCoderProperties(System.IO.Stream outStream)
- {
- properties[0] = (Byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits);
- for (int i = 0; i < 4; i++)
- properties[1 + i] = (Byte)((_dictionarySize >> (8 * i)) & 0xFF);
- outStream.Write(properties, 0, kPropSize);
- }
-
- UInt32[] tempPrices = new UInt32[Base.kNumFullDistances];
- UInt32 _matchPriceCount;
-
- void FillDistancesPrices()
- {
- for (UInt32 i = Base.kStartPosModelIndex; i < Base.kNumFullDistances; i++)
- {
- UInt32 posSlot = GetPosSlot(i);
- int footerBits = (int)((posSlot >> 1) - 1);
- UInt32 baseVal = ((2 | (posSlot & 1)) << footerBits);
- tempPrices[i] = BitTreeEncoder.ReverseGetPrice(_posEncoders,
- baseVal - posSlot - 1, footerBits, i - baseVal);
- }
-
- for (UInt32 lenToPosState = 0; lenToPosState < Base.kNumLenToPosStates; lenToPosState++)
- {
- UInt32 posSlot;
- RangeCoder.BitTreeEncoder encoder = _posSlotEncoder[lenToPosState];
-
- UInt32 st = (lenToPosState << Base.kNumPosSlotBits);
- for (posSlot = 0; posSlot < _distTableSize; posSlot++)
- _posSlotPrices[st + posSlot] = encoder.GetPrice(posSlot);
- for (posSlot = Base.kEndPosModelIndex; posSlot < _distTableSize; posSlot++)
- _posSlotPrices[st + posSlot] += ((((posSlot >> 1) - 1) - Base.kNumAlignBits) << RangeCoder.BitEncoder.kNumBitPriceShiftBits);
-
- UInt32 st2 = lenToPosState * Base.kNumFullDistances;
- UInt32 i;
- for (i = 0; i < Base.kStartPosModelIndex; i++)
- _distancesPrices[st2 + i] = _posSlotPrices[st + i];
- for (; i < Base.kNumFullDistances; i++)
- _distancesPrices[st2 + i] = _posSlotPrices[st + GetPosSlot(i)] + tempPrices[i];
- }
- _matchPriceCount = 0;
- }
-
- void FillAlignPrices()
- {
- for (UInt32 i = 0; i < Base.kAlignTableSize; i++)
- _alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);
- _alignPriceCount = 0;
- }
-
-
- static string[] kMatchFinderIDs =
- {
- "BT2",
- "BT4",
- };
-
- static int FindMatchFinder(string s)
- {
- for (int m = 0; m < kMatchFinderIDs.Length; m++)
- if (s == kMatchFinderIDs[m])
- return m;
- return -1;
- }
-
- public void SetCoderProperties(CoderPropID[] propIDs, object[] properties)
- {
- for (UInt32 i = 0; i < properties.Length; i++)
- {
- object prop = properties[i];
- switch (propIDs[i])
- {
- case CoderPropID.NumFastBytes:
- {
- if (!(prop is Int32))
- throw new InvalidParamException();
- Int32 numFastBytes = (Int32)prop;
- if (numFastBytes < 5 || numFastBytes > Base.kMatchMaxLen)
- throw new InvalidParamException();
- _numFastBytes = (UInt32)numFastBytes;
- break;
- }
- case CoderPropID.Algorithm:
- {
- /*
- if (!(prop is Int32))
- throw new InvalidParamException();
- Int32 maximize = (Int32)prop;
- _fastMode = (maximize == 0);
- _maxMode = (maximize >= 2);
- */
- break;
- }
- case CoderPropID.MatchFinder:
- {
- if (!(prop is String))
- throw new InvalidParamException();
- EMatchFinderType matchFinderIndexPrev = _matchFinderType;
- int m = FindMatchFinder(((string)prop).ToUpper());
- if (m < 0)
- throw new InvalidParamException();
- _matchFinderType = (EMatchFinderType)m;
- if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType)
- {
- _dictionarySizePrev = 0xFFFFFFFF;
- _matchFinder = null;
- }
- break;
- }
- case CoderPropID.DictionarySize:
- {
- const int kDicLogSizeMaxCompress = 30;
- if (!(prop is Int32))
- throw new InvalidParamException(); ;
- Int32 dictionarySize = (Int32)prop;
- if (dictionarySize < (UInt32)(1 << Base.kDicLogSizeMin) ||
- dictionarySize > (UInt32)(1 << kDicLogSizeMaxCompress))
- throw new InvalidParamException();
- _dictionarySize = (UInt32)dictionarySize;
- int dicLogSize;
- for (dicLogSize = 0; dicLogSize < (UInt32)kDicLogSizeMaxCompress; dicLogSize++)
- if (dictionarySize <= ((UInt32)(1) << dicLogSize))
- break;
- _distTableSize = (UInt32)dicLogSize * 2;
- break;
- }
- case CoderPropID.PosStateBits:
- {
- if (!(prop is Int32))
- throw new InvalidParamException();
- Int32 v = (Int32)prop;
- if (v < 0 || v > (UInt32)Base.kNumPosStatesBitsEncodingMax)
- throw new InvalidParamException();
- _posStateBits = (int)v;
- _posStateMask = (((UInt32)1) << (int)_posStateBits) - 1;
- break;
- }
- case CoderPropID.LitPosBits:
- {
- if (!(prop is Int32))
- throw new InvalidParamException();
- Int32 v = (Int32)prop;
- if (v < 0 || v > (UInt32)Base.kNumLitPosStatesBitsEncodingMax)
- throw new InvalidParamException();
- _numLiteralPosStateBits = (int)v;
- break;
- }
- case CoderPropID.LitContextBits:
- {
- if (!(prop is Int32))
- throw new InvalidParamException();
- Int32 v = (Int32)prop;
- if (v < 0 || v > (UInt32)Base.kNumLitContextBitsMax)
- throw new InvalidParamException(); ;
- _numLiteralContextBits = (int)v;
- break;
- }
- case CoderPropID.EndMarker:
- {
- if (!(prop is Boolean))
- throw new InvalidParamException();
- SetWriteEndMarkerMode((Boolean)prop);
- break;
- }
- default:
- throw new InvalidParamException();
- }
- }
- }
-
- uint _trainSize = 0;
- public void SetTrainSize(uint trainSize)
- {
- _trainSize = trainSize;
- }
-
- }
-}
diff --git a/CS/7zip/Compress/LzmaAlone/LzmaAlone.cs b/CS/7zip/Compress/LzmaAlone/LzmaAlone.cs
deleted file mode 100644
index 8aa4462..0000000
--- a/CS/7zip/Compress/LzmaAlone/LzmaAlone.cs
+++ /dev/null
@@ -1,364 +0,0 @@
-using System;
-using System.IO;
-namespace SevenZip
-{
- using CommandLineParser;
-
- public class CDoubleStream: Stream
- {
- public System.IO.Stream s1;
- public System.IO.Stream s2;
- public int fileIndex;
- public long skipSize;
-
- public override bool CanRead { get { return true; }}
- public override bool CanWrite { get { return false; }}
- public override bool CanSeek { get { return false; }}
- public override long Length { get { return s1.Length + s2.Length - skipSize; } }
- public override long Position
- {
- get { return 0; }
- set { }
- }
- public override void Flush() { }
- public override int Read(byte[] buffer, int offset, int count)
- {
- int numTotal = 0;
- while (count > 0)
- {
- if (fileIndex == 0)
- {
- int num = s1.Read(buffer, offset, count);
- offset += num;
- count -= num;
- numTotal += num;
- if (num == 0)
- fileIndex++;
- }
- if (fileIndex == 1)
- {
- numTotal += s2.Read(buffer, offset, count);
- return numTotal;
- }
- }
- return numTotal;
- }
- public override void Write(byte[] buffer, int offset, int count)
- {
- throw (new Exception("can't Write"));
- }
- public override long Seek(long offset, System.IO.SeekOrigin origin)
- {
- throw (new Exception("can't Seek"));
- }
- public override void SetLength(long value)
- {
- throw (new Exception("can't SetLength"));
- }
- }
-
- class LzmaAlone
- {
- enum Key
- {
- Help1 = 0,
- Help2,
- Mode,
- Dictionary,
- FastBytes,
- LitContext,
- LitPos,
- PosBits,
- MatchFinder,
- EOS,
- StdIn,
- StdOut,
- Train
- };
-
- static void PrintHelp()
- {
- System.Console.WriteLine("\nUsage: LZMA <e|d> [<switches>...] inputFile outputFile\n" +
- " e: encode file\n" +
- " d: decode file\n" +
- " b: Benchmark\n" +
- "<Switches>\n" +
- // " -a{N}: set compression mode - [0, 1], default: 1 (max)\n" +
- " -d{N}: set dictionary - [0, 29], default: 23 (8MB)\n" +
- " -fb{N}: set number of fast bytes - [5, 273], default: 128\n" +
- " -lc{N}: set number of literal context bits - [0, 8], default: 3\n" +
- " -lp{N}: set number of literal pos bits - [0, 4], default: 0\n" +
- " -pb{N}: set number of pos bits - [0, 4], default: 2\n" +
- " -mf{MF_ID}: set Match Finder: [bt2, bt4], default: bt4\n" +
- " -eos: write End Of Stream marker\n"
- // + " -si: read data from stdin\n"
- // + " -so: write data to stdout\n"
- );
- }
-
- static bool GetNumber(string s, out Int32 v)
- {
- v = 0;
- for (int i = 0; i < s.Length; i++)
- {
- char c = s[i];
- if (c < '0' || c > '9')
- return false;
- v *= 10;
- v += (Int32)(c - '0');
- }
- return true;
- }
-
- static int IncorrectCommand()
- {
- throw (new Exception("Command line error"));
- // System.Console.WriteLine("\nCommand line error\n");
- // return 1;
- }
- static int Main2(string[] args)
- {
- System.Console.WriteLine("\nLZMA# 4.61 2008-11-23\n");
-
- if (args.Length == 0)
- {
- PrintHelp();
- return 0;
- }
-
- SwitchForm[] kSwitchForms = new SwitchForm[13];
- int sw = 0;
- kSwitchForms[sw++] = new SwitchForm("?", SwitchType.Simple, false);
- kSwitchForms[sw++] = new SwitchForm("H", SwitchType.Simple, false);
- kSwitchForms[sw++] = new SwitchForm("A", SwitchType.UnLimitedPostString, false, 1);
- kSwitchForms[sw++] = new SwitchForm("D", SwitchType.UnLimitedPostString, false, 1);
- kSwitchForms[sw++] = new SwitchForm("FB", SwitchType.UnLimitedPostString, false, 1);
- kSwitchForms[sw++] = new SwitchForm("LC", SwitchType.UnLimitedPostString, false, 1);
- kSwitchForms[sw++] = new SwitchForm("LP", SwitchType.UnLimitedPostString, false, 1);
- kSwitchForms[sw++] = new SwitchForm("PB", SwitchType.UnLimitedPostString, false, 1);
- kSwitchForms[sw++] = new SwitchForm("MF", SwitchType.UnLimitedPostString, false, 1);
- kSwitchForms[sw++] = new SwitchForm("EOS", SwitchType.Simple, false);
- kSwitchForms[sw++] = new SwitchForm("SI", SwitchType.Simple, false);
- kSwitchForms[sw++] = new SwitchForm("SO", SwitchType.Simple, false);
- kSwitchForms[sw++] = new SwitchForm("T", SwitchType.UnLimitedPostString, false, 1);
-
-
- Parser parser = new Parser(sw);
- try
- {
- parser.ParseStrings(kSwitchForms, args);
- }
- catch
- {
- return IncorrectCommand();
- }
-
- if (parser[(int)Key.Help1].ThereIs || parser[(int)Key.Help2].ThereIs)
- {
- PrintHelp();
- return 0;
- }
-
- System.Collections.ArrayList nonSwitchStrings = parser.NonSwitchStrings;
-
- int paramIndex = 0;
- if (paramIndex >= nonSwitchStrings.Count)
- return IncorrectCommand();
- string command = (string)nonSwitchStrings[paramIndex++];
- command = command.ToLower();
-
- bool dictionaryIsDefined = false;
- Int32 dictionary = 1 << 21;
- if (parser[(int)Key.Dictionary].ThereIs)
- {
- Int32 dicLog;
- if (!GetNumber((string)parser[(int)Key.Dictionary].PostStrings[0], out dicLog))
- IncorrectCommand();
- dictionary = (Int32)1 << dicLog;
- dictionaryIsDefined = true;
- }
- string mf = "bt4";
- if (parser[(int)Key.MatchFinder].ThereIs)
- mf = (string)parser[(int)Key.MatchFinder].PostStrings[0];
- mf = mf.ToLower();
-
- if (command == "b")
- {
- const Int32 kNumDefaultItereations = 10;
- Int32 numIterations = kNumDefaultItereations;
- if (paramIndex < nonSwitchStrings.Count)
- if (!GetNumber((string)nonSwitchStrings[paramIndex++], out numIterations))
- numIterations = kNumDefaultItereations;
- return LzmaBench.LzmaBenchmark(numIterations, (UInt32)dictionary);
- }
-
- string train = "";
- if (parser[(int)Key.Train].ThereIs)
- train = (string)parser[(int)Key.Train].PostStrings[0];
-
- bool encodeMode = false;
- if (command == "e")
- encodeMode = true;
- else if (command == "d")
- encodeMode = false;
- else
- IncorrectCommand();
-
- bool stdInMode = parser[(int)Key.StdIn].ThereIs;
- bool stdOutMode = parser[(int)Key.StdOut].ThereIs;
-
- Stream inStream = null;
- if (stdInMode)
- {
- throw (new Exception("Not implemeted"));
- }
- else
- {
- if (paramIndex >= nonSwitchStrings.Count)
- IncorrectCommand();
- string inputName = (string)nonSwitchStrings[paramIndex++];
- inStream = new FileStream(inputName, FileMode.Open, FileAccess.Read);
- }
-
- FileStream outStream = null;
- if (stdOutMode)
- {
- throw (new Exception("Not implemeted"));
- }
- else
- {
- if (paramIndex >= nonSwitchStrings.Count)
- IncorrectCommand();
- string outputName = (string)nonSwitchStrings[paramIndex++];
- outStream = new FileStream(outputName, FileMode.Create, FileAccess.Write);
- }
-
- FileStream trainStream = null;
- if (train.Length != 0)
- trainStream = new FileStream(train, FileMode.Open, FileAccess.Read);
-
- if (encodeMode)
- {
- if (!dictionaryIsDefined)
- dictionary = 1 << 23;
-
- Int32 posStateBits = 2;
- Int32 litContextBits = 3; // for normal files
- // UInt32 litContextBits = 0; // for 32-bit data
- Int32 litPosBits = 0;
- // UInt32 litPosBits = 2; // for 32-bit data
- Int32 algorithm = 2;
- Int32 numFastBytes = 128;
-
- bool eos = parser[(int)Key.EOS].ThereIs || stdInMode;
-
- if (parser[(int)Key.Mode].ThereIs)
- if (!GetNumber((string)parser[(int)Key.Mode].PostStrings[0], out algorithm))
- IncorrectCommand();
-
- if (parser[(int)Key.FastBytes].ThereIs)
- if (!GetNumber((string)parser[(int)Key.FastBytes].PostStrings[0], out numFastBytes))
- IncorrectCommand();
- if (parser[(int)Key.LitContext].ThereIs)
- if (!GetNumber((string)parser[(int)Key.LitContext].PostStrings[0], out litContextBits))
- IncorrectCommand();
- if (parser[(int)Key.LitPos].ThereIs)
- if (!GetNumber((string)parser[(int)Key.LitPos].PostStrings[0], out litPosBits))
- IncorrectCommand();
- if (parser[(int)Key.PosBits].ThereIs)
- if (!GetNumber((string)parser[(int)Key.PosBits].PostStrings[0], out posStateBits))
- IncorrectCommand();
-
- CoderPropID[] propIDs =
- {
- CoderPropID.DictionarySize,
- CoderPropID.PosStateBits,
- CoderPropID.LitContextBits,
- CoderPropID.LitPosBits,
- CoderPropID.Algorithm,
- CoderPropID.NumFastBytes,
- CoderPropID.MatchFinder,
- CoderPropID.EndMarker
- };
- object[] properties =
- {
- (Int32)(dictionary),
- (Int32)(posStateBits),
- (Int32)(litContextBits),
- (Int32)(litPosBits),
- (Int32)(algorithm),
- (Int32)(numFastBytes),
- mf,
- eos
- };
-
- Compression.LZMA.Encoder encoder = new Compression.LZMA.Encoder();
- encoder.SetCoderProperties(propIDs, properties);
- encoder.WriteCoderProperties(outStream);
- Int64 fileSize;
- if (eos || stdInMode)
- fileSize = -1;
- else
- fileSize = inStream.Length;
- for (int i = 0; i < 8; i++)
- outStream.WriteByte((Byte)(fileSize >> (8 * i)));
- if (trainStream != null)
- {
- CDoubleStream doubleStream = new CDoubleStream();
- doubleStream.s1 = trainStream;
- doubleStream.s2 = inStream;
- doubleStream.fileIndex = 0;
- inStream = doubleStream;
- long trainFileSize = trainStream.Length;
- doubleStream.skipSize = 0;
- if (trainFileSize > dictionary)
- doubleStream.skipSize = trainFileSize - dictionary;
- trainStream.Seek(doubleStream.skipSize, SeekOrigin.Begin);
- encoder.SetTrainSize((uint)(trainFileSize - doubleStream.skipSize));
- }
- encoder.Code(inStream, outStream, -1, -1, null);
- }
- else if (command == "d")
- {
- byte[] properties = new byte[5];
- if (inStream.Read(properties, 0, 5) != 5)
- throw (new Exception("input .lzma is too short"));
- Compression.LZMA.Decoder decoder = new Compression.LZMA.Decoder();
- decoder.SetDecoderProperties(properties);
- if (trainStream != null)
- {
- if (!decoder.Train(trainStream))
- throw (new Exception("can't train"));
- }
- long outSize = 0;
- for (int i = 0; i < 8; i++)
- {
- int v = inStream.ReadByte();
- if (v < 0)
- throw (new Exception("Can't Read 1"));
- outSize |= ((long)(byte)v) << (8 * i);
- }
- long compressedSize = inStream.Length - inStream.Position;
- decoder.Code(inStream, outStream, compressedSize, outSize, null);
- }
- else
- throw (new Exception("Command Error"));
- return 0;
- }
-
- [STAThread]
- static int Main(string[] args)
- {
- try
- {
- return Main2(args);
- }
- catch (Exception e)
- {
- Console.WriteLine("{0} Caught exception #1.", e);
- // throw e;
- return 1;
- }
- }
- }
-}
diff --git a/CS/7zip/Compress/LzmaAlone/LzmaAlone.csproj b/CS/7zip/Compress/LzmaAlone/LzmaAlone.csproj
deleted file mode 100644
index ceb7073..0000000
--- a/CS/7zip/Compress/LzmaAlone/LzmaAlone.csproj
+++ /dev/null
@@ -1,90 +0,0 @@
-<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
- <PropertyGroup>
- <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
- <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
- <ProductVersion>8.0.50727</ProductVersion>
- <SchemaVersion>2.0</SchemaVersion>
- <ProjectGuid>{CE33DF18-F9C8-4D6F-9057-DBB4DB96E973}</ProjectGuid>
- <OutputType>Exe</OutputType>
- <RootNamespace>LzmaAlone</RootNamespace>
- <AssemblyName>Lzma#</AssemblyName>
- <WarningLevel>4</WarningLevel>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
- <DebugSymbols>true</DebugSymbols>
- <DebugType>full</DebugType>
- <Optimize>false</Optimize>
- <OutputPath>.\bin\Debug\</OutputPath>
- <DefineConstants>DEBUG;TRACE</DefineConstants>
- </PropertyGroup>
- <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
- <DebugSymbols>false</DebugSymbols>
- <Optimize>true</Optimize>
- <OutputPath>.\bin\Release\</OutputPath>
- <DefineConstants>TRACE</DefineConstants>
- <PlatformTarget>AnyCPU</PlatformTarget>
- </PropertyGroup>
- <ItemGroup>
- <Reference Include="System" />
- <Reference Include="System.Data" />
- <Reference Include="System.Xml" />
- </ItemGroup>
- <ItemGroup>
- <Compile Include="..\..\Common\CommandLineParser.cs">
- <Link>Common\CommandLineParser.cs</Link>
- </Compile>
- <Compile Include="..\..\Common\CRC.cs">
- <Link>Common\CRC.cs</Link>
- </Compile>
- <Compile Include="..\..\ICoder.cs">
- <Link>ICoder.cs</Link>
- </Compile>
- <Compile Include="..\LZ\IMatchFinder.cs">
- <Link>LZ\IMatchFinder.cs</Link>
- </Compile>
- <Compile Include="..\LZ\LzBinTree.cs">
- <Link>LZ\LzBinTree.cs</Link>
- </Compile>
- <Compile Include="..\LZ\LzInWindow.cs">
- <Link>LZ\LzInWindow.cs</Link>
- </Compile>
- <Compile Include="..\LZ\LzOutWindow.cs">
- <Link>LZ\LzOutWindow.cs</Link>
- </Compile>
- <Compile Include="..\LZMA\LzmaBase.cs">
- <Link>LZMA\LzmaBase.cs</Link>
- </Compile>
- <Compile Include="..\LZMA\LzmaDecoder.cs">
- <Link>LZMA\LzmaDecoder.cs</Link>
- </Compile>
- <Compile Include="..\LZMA\LzmaEncoder.cs">
- <Link>LZMA\LzmaEncoder.cs</Link>
- </Compile>
- <Compile Include="..\RangeCoder\RangeCoder.cs">
- <Link>RangeCoder\RangeCoder.cs</Link>
- </Compile>
- <Compile Include="..\RangeCoder\RangeCoderBit.cs">
- <Link>RangeCoder\RangeCoderBit.cs</Link>
- </Compile>
- <Compile Include="..\RangeCoder\RangeCoderBitTree.cs">
- <Link>RangeCoder\RangeCoderBitTree.cs</Link>
- </Compile>
- <Compile Include="LzmaAlone.cs">
- <SubType>Code</SubType>
- </Compile>
- <Compile Include="LzmaBench.cs">
- <SubType>Code</SubType>
- </Compile>
- <Compile Include="Properties\AssemblyInfo.cs" />
- <Compile Include="Properties\Settings.cs">
- <AutoGen>True</AutoGen>
- <DependentUpon>Settings.settings</DependentUpon>
- </Compile>
- <None Include="Properties\Settings.settings">
- <Generator>SettingsSingleFileGenerator</Generator>
- <LastGenOutput>Settings.cs</LastGenOutput>
- </None>
- <AppDesigner Include="Properties\" />
- </ItemGroup>
- <Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />
-</Project> \ No newline at end of file
diff --git a/CS/7zip/Compress/LzmaAlone/LzmaAlone.sln b/CS/7zip/Compress/LzmaAlone/LzmaAlone.sln
deleted file mode 100644
index a96ee3e..0000000
--- a/CS/7zip/Compress/LzmaAlone/LzmaAlone.sln
+++ /dev/null
@@ -1,20 +0,0 @@
-
-Microsoft Visual Studio Solution File, Format Version 9.00
-# Visual C# Express 2005
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LzmaAlone", "LzmaAlone.csproj", "{CE33DF18-F9C8-4D6F-9057-DBB4DB96E973}"
-EndProject
-Global
- GlobalSection(SolutionConfigurationPlatforms) = preSolution
- Debug|Any CPU = Debug|Any CPU
- Release|Any CPU = Release|Any CPU
- EndGlobalSection
- GlobalSection(ProjectConfigurationPlatforms) = postSolution
- {CE33DF18-F9C8-4D6F-9057-DBB4DB96E973}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
- {CE33DF18-F9C8-4D6F-9057-DBB4DB96E973}.Debug|Any CPU.Build.0 = Debug|Any CPU
- {CE33DF18-F9C8-4D6F-9057-DBB4DB96E973}.Release|Any CPU.ActiveCfg = Release|Any CPU
- {CE33DF18-F9C8-4D6F-9057-DBB4DB96E973}.Release|Any CPU.Build.0 = Release|Any CPU
- EndGlobalSection
- GlobalSection(SolutionProperties) = preSolution
- HideSolutionNode = FALSE
- EndGlobalSection
-EndGlobal
diff --git a/CS/7zip/Compress/LzmaAlone/LzmaBench.cs b/CS/7zip/Compress/LzmaAlone/LzmaBench.cs
deleted file mode 100644
index 6a1ffe2..0000000
--- a/CS/7zip/Compress/LzmaAlone/LzmaBench.cs
+++ /dev/null
@@ -1,340 +0,0 @@
-// LzmaBench.cs
-
-using System;
-using System.IO;
-
-namespace SevenZip
-{
- /// <summary>
- /// LZMA Benchmark
- /// </summary>
- internal abstract class LzmaBench
- {
- const UInt32 kAdditionalSize = (6 << 20);
- const UInt32 kCompressedAdditionalSize = (1 << 10);
- const UInt32 kMaxLzmaPropSize = 10;
-
- class CRandomGenerator
- {
- UInt32 A1;
- UInt32 A2;
- public CRandomGenerator() { Init(); }
- public void Init() { A1 = 362436069; A2 = 521288629; }
- public UInt32 GetRnd()
- {
- return
- ((A1 = 36969 * (A1 & 0xffff) + (A1 >> 16)) << 16) ^
- ((A2 = 18000 * (A2 & 0xffff) + (A2 >> 16)));
- }
- };
-
- class CBitRandomGenerator
- {
- CRandomGenerator RG = new CRandomGenerator();
- UInt32 Value;
- int NumBits;
- public void Init()
- {
- Value = 0;
- NumBits = 0;
- }
- public UInt32 GetRnd(int numBits)
- {
- UInt32 result;
- if (NumBits > numBits)
- {
- result = Value & (((UInt32)1 << numBits) - 1);
- Value >>= numBits;
- NumBits -= numBits;
- return result;
- }
- numBits -= NumBits;
- result = (Value << numBits);
- Value = RG.GetRnd();
- result |= Value & (((UInt32)1 << numBits) - 1);
- Value >>= numBits;
- NumBits = 32 - numBits;
- return result;
- }
- };
-
- class CBenchRandomGenerator
- {
- CBitRandomGenerator RG = new CBitRandomGenerator();
- UInt32 Pos;
- UInt32 Rep0;
-
- public UInt32 BufferSize;
- public Byte[] Buffer = null;
-
- public CBenchRandomGenerator() { }
-
- public void Set(UInt32 bufferSize)
- {
- Buffer = new Byte[bufferSize];
- Pos = 0;
- BufferSize = bufferSize;
- }
- UInt32 GetRndBit() { return RG.GetRnd(1); }
- UInt32 GetLogRandBits(int numBits)
- {
- UInt32 len = RG.GetRnd(numBits);
- return RG.GetRnd((int)len);
- }
- UInt32 GetOffset()
- {
- if (GetRndBit() == 0)
- return GetLogRandBits(4);
- return (GetLogRandBits(4) << 10) | RG.GetRnd(10);
- }
- UInt32 GetLen1() { return RG.GetRnd(1 + (int)RG.GetRnd(2)); }
- UInt32 GetLen2() { return RG.GetRnd(2 + (int)RG.GetRnd(2)); }
- public void Generate()
- {
- RG.Init();
- Rep0 = 1;
- while (Pos < BufferSize)
- {
- if (GetRndBit() == 0 || Pos < 1)
- Buffer[Pos++] = (Byte)RG.GetRnd(8);
- else
- {
- UInt32 len;
- if (RG.GetRnd(3) == 0)
- len = 1 + GetLen1();
- else
- {
- do
- Rep0 = GetOffset();
- while (Rep0 >= Pos);
- Rep0++;
- len = 2 + GetLen2();
- }
- for (UInt32 i = 0; i < len && Pos < BufferSize; i++, Pos++)
- Buffer[Pos] = Buffer[Pos - Rep0];
- }
- }
- }
- };
-
- class CrcOutStream : System.IO.Stream
- {
- public CRC CRC = new CRC();
- public void Init() { CRC.Init(); }
- public UInt32 GetDigest() { return CRC.GetDigest(); }
-
- public override bool CanRead { get { return false; } }
- public override bool CanSeek { get { return false; } }
- public override bool CanWrite { get { return true; } }
- public override Int64 Length { get { return 0; } }
- public override Int64 Position { get { return 0; } set { } }
- public override void Flush() { }
- public override long Seek(long offset, SeekOrigin origin) { return 0; }
- public override void SetLength(long value) { }
- public override int Read(byte[] buffer, int offset, int count) { return 0; }
-
- public override void WriteByte(byte b)
- {
- CRC.UpdateByte(b);
- }
- public override void Write(byte[] buffer, int offset, int count)
- {
- CRC.Update(buffer, (uint)offset, (uint)count);
- }
- };
-
- class CProgressInfo : ICodeProgress
- {
- public Int64 ApprovedStart;
- public Int64 InSize;
- public System.DateTime Time;
- public void Init() { InSize = 0; }
- public void SetProgress(Int64 inSize, Int64 outSize)
- {
- if (inSize >= ApprovedStart && InSize == 0)
- {
- Time = DateTime.UtcNow;
- InSize = inSize;
- }
- }
- }
- const int kSubBits = 8;
-
- static UInt32 GetLogSize(UInt32 size)
- {
- for (int i = kSubBits; i < 32; i++)
- for (UInt32 j = 0; j < (1 << kSubBits); j++)
- if (size <= (((UInt32)1) << i) + (j << (i - kSubBits)))
- return (UInt32)(i << kSubBits) + j;
- return (32 << kSubBits);
- }
-
- static UInt64 MyMultDiv64(UInt64 value, UInt64 elapsedTime)
- {
- UInt64 freq = TimeSpan.TicksPerSecond;
- UInt64 elTime = elapsedTime;
- while (freq > 1000000)
- {
- freq >>= 1;
- elTime >>= 1;
- }
- if (elTime == 0)
- elTime = 1;
- return value * freq / elTime;
- }
-
- static UInt64 GetCompressRating(UInt32 dictionarySize, UInt64 elapsedTime, UInt64 size)
- {
- UInt64 t = GetLogSize(dictionarySize) - (18 << kSubBits);
- UInt64 numCommandsForOne = 1060 + ((t * t * 10) >> (2 * kSubBits));
- UInt64 numCommands = (UInt64)(size) * numCommandsForOne;
- return MyMultDiv64(numCommands, elapsedTime);
- }
-
- static UInt64 GetDecompressRating(UInt64 elapsedTime, UInt64 outSize, UInt64 inSize)
- {
- UInt64 numCommands = inSize * 220 + outSize * 20;
- return MyMultDiv64(numCommands, elapsedTime);
- }
-
- static UInt64 GetTotalRating(
- UInt32 dictionarySize,
- UInt64 elapsedTimeEn, UInt64 sizeEn,
- UInt64 elapsedTimeDe,
- UInt64 inSizeDe, UInt64 outSizeDe)
- {
- return (GetCompressRating(dictionarySize, elapsedTimeEn, sizeEn) +
- GetDecompressRating(elapsedTimeDe, inSizeDe, outSizeDe)) / 2;
- }
-
- static void PrintValue(UInt64 v)
- {
- string s = v.ToString();
- for (int i = 0; i + s.Length < 6; i++)
- System.Console.Write(" ");
- System.Console.Write(s);
- }
-
- static void PrintRating(UInt64 rating)
- {
- PrintValue(rating / 1000000);
- System.Console.Write(" MIPS");
- }
-
- static void PrintResults(
- UInt32 dictionarySize,
- UInt64 elapsedTime,
- UInt64 size,
- bool decompressMode, UInt64 secondSize)
- {
- UInt64 speed = MyMultDiv64(size, elapsedTime);
- PrintValue(speed / 1024);
- System.Console.Write(" KB/s ");
- UInt64 rating;
- if (decompressMode)
- rating = GetDecompressRating(elapsedTime, size, secondSize);
- else
- rating = GetCompressRating(dictionarySize, elapsedTime, size);
- PrintRating(rating);
- }
-
- static public int LzmaBenchmark(Int32 numIterations, UInt32 dictionarySize)
- {
- if (numIterations <= 0)
- return 0;
- if (dictionarySize < (1 << 18))
- {
- System.Console.WriteLine("\nError: dictionary size for benchmark must be >= 19 (512 KB)");
- return 1;
- }
- System.Console.Write("\n Compressing Decompressing\n\n");
-
- Compression.LZMA.Encoder encoder = new Compression.LZMA.Encoder();
- Compression.LZMA.Decoder decoder = new Compression.LZMA.Decoder();
-
-
- CoderPropID[] propIDs =
- {
- CoderPropID.DictionarySize,
- };
- object[] properties =
- {
- (Int32)(dictionarySize),
- };
-
- UInt32 kBufferSize = dictionarySize + kAdditionalSize;
- UInt32 kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize;
-
- encoder.SetCoderProperties(propIDs, properties);
- System.IO.MemoryStream propStream = new System.IO.MemoryStream();
- encoder.WriteCoderProperties(propStream);
- byte[] propArray = propStream.ToArray();
-
- CBenchRandomGenerator rg = new CBenchRandomGenerator();
-
- rg.Set(kBufferSize);
- rg.Generate();
- CRC crc = new CRC();
- crc.Init();
- crc.Update(rg.Buffer, 0, rg.BufferSize);
-
- CProgressInfo progressInfo = new CProgressInfo();
- progressInfo.ApprovedStart = dictionarySize;
-
- UInt64 totalBenchSize = 0;
- UInt64 totalEncodeTime = 0;
- UInt64 totalDecodeTime = 0;
- UInt64 totalCompressedSize = 0;
-
- MemoryStream inStream = new MemoryStream(rg.Buffer, 0, (int)rg.BufferSize);
- MemoryStream compressedStream = new MemoryStream((int)kCompressedBufferSize);
- CrcOutStream crcOutStream = new CrcOutStream();
- for (Int32 i = 0; i < numIterations; i++)
- {
- progressInfo.Init();
- inStream.Seek(0, SeekOrigin.Begin);
- compressedStream.Seek(0, SeekOrigin.Begin);
- encoder.Code(inStream, compressedStream, -1, -1, progressInfo);
- TimeSpan sp2 = DateTime.UtcNow - progressInfo.Time;
- UInt64 encodeTime = (UInt64)sp2.Ticks;
-
- long compressedSize = compressedStream.Position;
- if (progressInfo.InSize == 0)
- throw (new Exception("Internal ERROR 1282"));
-
- UInt64 decodeTime = 0;
- for (int j = 0; j < 2; j++)
- {
- compressedStream.Seek(0, SeekOrigin.Begin);
- crcOutStream.Init();
-
- decoder.SetDecoderProperties(propArray);
- UInt64 outSize = kBufferSize;
- System.DateTime startTime = DateTime.UtcNow;
- decoder.Code(compressedStream, crcOutStream, 0, (Int64)outSize, null);
- TimeSpan sp = (DateTime.UtcNow - startTime);
- decodeTime = (ulong)sp.Ticks;
- if (crcOutStream.GetDigest() != crc.GetDigest())
- throw (new Exception("CRC Error"));
- }
- UInt64 benchSize = kBufferSize - (UInt64)progressInfo.InSize;
- PrintResults(dictionarySize, encodeTime, benchSize, false, 0);
- System.Console.Write(" ");
- PrintResults(dictionarySize, decodeTime, kBufferSize, true, (ulong)compressedSize);
- System.Console.WriteLine();
-
- totalBenchSize += benchSize;
- totalEncodeTime += encodeTime;
- totalDecodeTime += decodeTime;
- totalCompressedSize += (ulong)compressedSize;
- }
- System.Console.WriteLine("---------------------------------------------------");
- PrintResults(dictionarySize, totalEncodeTime, totalBenchSize, false, 0);
- System.Console.Write(" ");
- PrintResults(dictionarySize, totalDecodeTime,
- kBufferSize * (UInt64)numIterations, true, totalCompressedSize);
- System.Console.WriteLine(" Average");
- return 0;
- }
- }
-}
diff --git a/CS/7zip/Compress/LzmaAlone/Properties/AssemblyInfo.cs b/CS/7zip/Compress/LzmaAlone/Properties/AssemblyInfo.cs
deleted file mode 100644
index a394aee..0000000
--- a/CS/7zip/Compress/LzmaAlone/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,29 +0,0 @@
-#region Using directives
-
-using System.Reflection;
-using System.Runtime.CompilerServices;
-
-#endregion
-
-// General Information about an assembly is controlled through the following
-// set of attributes. Change these attribute values to modify the information
-// associated with an assembly.
-[assembly: AssemblyTitle("LZMA#")]
-[assembly: AssemblyDescription("")]
-[assembly: AssemblyConfiguration("")]
-[assembly: AssemblyCompany("Igor Pavlov")]
-[assembly: AssemblyProduct("LZMA# SDK")]
-[assembly: AssemblyCopyright("Copyright @ Igor Pavlov 1999-2004")]
-[assembly: AssemblyTrademark("")]
-[assembly: AssemblyCulture("")]
-
-// Version information for an assembly consists of the following four values:
-//
-// Major Version
-// Minor Version
-// Build Number
-// Revision
-//
-// You can specify all the values or you can default the Revision and Build Numbers
-// by using the '*' as shown below:
-[assembly: AssemblyVersion("4.12.*")]
diff --git a/CS/7zip/Compress/LzmaAlone/Properties/Resources.cs b/CS/7zip/Compress/LzmaAlone/Properties/Resources.cs
deleted file mode 100644
index efe4ee9..0000000
--- a/CS/7zip/Compress/LzmaAlone/Properties/Resources.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-//------------------------------------------------------------------------------
-// <autogenerated>
-// This code was generated by a tool.
-// Runtime Version:2.0.40607.42
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-// </autogenerated>
-//------------------------------------------------------------------------------
-
-namespace LzmaAlone.Properties
-{
- using System;
- using System.IO;
- using System.Resources;
-
- /// <summary>
- /// A strongly-typed resource class, for looking up localized strings, etc.
- /// </summary>
- // This class was auto-generated by the Strongly Typed Resource Builder
- // class via a tool like ResGen or Visual Studio.NET.
- // To add or remove a member, edit your .ResX file then rerun ResGen
- // with the /str option, or rebuild your VS project.
- class Resources
- {
-
- private static System.Resources.ResourceManager _resMgr;
-
- private static System.Globalization.CultureInfo _resCulture;
-
- /*FamANDAssem*/
- internal Resources()
- {
- }
-
- /// <summary>
- /// Returns the cached ResourceManager instance used by this class.
- /// </summary>
- [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
- public static System.Resources.ResourceManager ResourceManager
- {
- get
- {
- if ((_resMgr == null))
- {
- System.Resources.ResourceManager temp = new System.Resources.ResourceManager("Resources", typeof(Resources).Assembly);
- _resMgr = temp;
- }
- return _resMgr;
- }
- }
-
- /// <summary>
- /// Overrides the current thread's CurrentUICulture property for all
- /// resource lookups using this strongly typed resource class.
- /// </summary>
- [System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsableState.Advanced)]
- public static System.Globalization.CultureInfo Culture
- {
- get
- {
- return _resCulture;
- }
- set
- {
- _resCulture = value;
- }
- }
- }
-}
diff --git a/CS/7zip/Compress/LzmaAlone/Properties/Settings.cs b/CS/7zip/Compress/LzmaAlone/Properties/Settings.cs
deleted file mode 100644
index 1281fd2..0000000
--- a/CS/7zip/Compress/LzmaAlone/Properties/Settings.cs
+++ /dev/null
@@ -1,42 +0,0 @@
-//------------------------------------------------------------------------------
-// <autogenerated>
-// This code was generated by a tool.
-// Runtime Version:2.0.40607.42
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-// </autogenerated>
-//------------------------------------------------------------------------------
-
-namespace LzmaAlone.Properties
-{
- public partial class Settings : System.Configuration.ApplicationSettingsBase
- {
- private static Settings m_Value;
-
- private static object m_SyncObject = new object();
-
- public static Settings Value
- {
- get
- {
- if ((Settings.m_Value == null))
- {
- System.Threading.Monitor.Enter(Settings.m_SyncObject);
- if ((Settings.m_Value == null))
- {
- try
- {
- Settings.m_Value = new Settings();
- }
- finally
- {
- System.Threading.Monitor.Exit(Settings.m_SyncObject);
- }
- }
- }
- return Settings.m_Value;
- }
- }
- }
-}
diff --git a/CS/7zip/Compress/RangeCoder/RangeCoder.cs b/CS/7zip/Compress/RangeCoder/RangeCoder.cs
deleted file mode 100644
index 4ced247..0000000
--- a/CS/7zip/Compress/RangeCoder/RangeCoder.cs
+++ /dev/null
@@ -1,234 +0,0 @@
-using System;
-
-namespace SevenZip.Compression.RangeCoder
-{
- class Encoder
- {
- public const uint kTopValue = (1 << 24);
-
- System.IO.Stream Stream;
-
- public UInt64 Low;
- public uint Range;
- uint _cacheSize;
- byte _cache;
-
- long StartPosition;
-
- public void SetStream(System.IO.Stream stream)
- {
- Stream = stream;
- }
-
- public void ReleaseStream()
- {
- Stream = null;
- }
-
- public void Init()
- {
- StartPosition = Stream.Position;
-
- Low = 0;
- Range = 0xFFFFFFFF;
- _cacheSize = 1;
- _cache = 0;
- }
-
- public void FlushData()
- {
- for (int i = 0; i < 5; i++)
- ShiftLow();
- }
-
- public void FlushStream()
- {
- Stream.Flush();
- }
-
- public void CloseStream()
- {
- Stream.Close();
- }
-
- public void Encode(uint start, uint size, uint total)
- {
- Low += start * (Range /= total);
- Range *= size;
- while (Range < kTopValue)
- {
- Range <<= 8;
- ShiftLow();
- }
- }
-
- public void ShiftLow()
- {
- if ((uint)Low < (uint)0xFF000000 || (uint)(Low >> 32) == 1)
- {
- byte temp = _cache;
- do
- {
- Stream.WriteByte((byte)(temp + (Low >> 32)));
- temp = 0xFF;
- }
- while (--_cacheSize != 0);
- _cache = (byte)(((uint)Low) >> 24);
- }
- _cacheSize++;
- Low = ((uint)Low) << 8;
- }
-
- public void EncodeDirectBits(uint v, int numTotalBits)
- {
- for (int i = numTotalBits - 1; i >= 0; i--)
- {
- Range >>= 1;
- if (((v >> i) & 1) == 1)
- Low += Range;
- if (Range < kTopValue)
- {
- Range <<= 8;
- ShiftLow();
- }
- }
- }
-
- public void EncodeBit(uint size0, int numTotalBits, uint symbol)
- {
- uint newBound = (Range >> numTotalBits) * size0;
- if (symbol == 0)
- Range = newBound;
- else
- {
- Low += newBound;
- Range -= newBound;
- }
- while (Range < kTopValue)
- {
- Range <<= 8;
- ShiftLow();
- }
- }
-
- public long GetProcessedSizeAdd()
- {
- return _cacheSize +
- Stream.Position - StartPosition + 4;
- // (long)Stream.GetProcessedSize();
- }
- }
-
- class Decoder
- {
- public const uint kTopValue = (1 << 24);
- public uint Range;
- public uint Code;
- // public Buffer.InBuffer Stream = new Buffer.InBuffer(1 << 16);
- public System.IO.Stream Stream;
-
- public void Init(System.IO.Stream stream)
- {
- // Stream.Init(stream);
- Stream = stream;
-
- Code = 0;
- Range = 0xFFFFFFFF;
- for (int i = 0; i < 5; i++)
- Code = (Code << 8) | (byte)Stream.ReadByte();
- }
-
- public void ReleaseStream()
- {
- // Stream.ReleaseStream();
- Stream = null;
- }
-
- public void CloseStream()
- {
- Stream.Close();
- }
-
- public void Normalize()
- {
- while (Range < kTopValue)
- {
- Code = (Code << 8) | (byte)Stream.ReadByte();
- Range <<= 8;
- }
- }
-
- public void Normalize2()
- {
- if (Range < kTopValue)
- {
- Code = (Code << 8) | (byte)Stream.ReadByte();
- Range <<= 8;
- }
- }
-
- public uint GetThreshold(uint total)
- {
- return Code / (Range /= total);
- }
-
- public void Decode(uint start, uint size, uint total)
- {
- Code -= start * Range;
- Range *= size;
- Normalize();
- }
-
- public uint DecodeDirectBits(int numTotalBits)
- {
- uint range = Range;
- uint code = Code;
- uint result = 0;
- for (int i = numTotalBits; i > 0; i--)
- {
- range >>= 1;
- /*
- result <<= 1;
- if (code >= range)
- {
- code -= range;
- result |= 1;
- }
- */
- uint t = (code - range) >> 31;
- code -= range & (t - 1);
- result = (result << 1) | (1 - t);
-
- if (range < kTopValue)
- {
- code = (code << 8) | (byte)Stream.ReadByte();
- range <<= 8;
- }
- }
- Range = range;
- Code = code;
- return result;
- }
-
- public uint DecodeBit(uint size0, int numTotalBits)
- {
- uint newBound = (Range >> numTotalBits) * size0;
- uint symbol;
- if (Code < newBound)
- {
- symbol = 0;
- Range = newBound;
- }
- else
- {
- symbol = 1;
- Code -= newBound;
- Range -= newBound;
- }
- Normalize();
- return symbol;
- }
-
- // ulong GetProcessedSize() {return Stream.GetProcessedSize(); }
- }
-}
diff --git a/CS/7zip/Compress/RangeCoder/RangeCoderBit.cs b/CS/7zip/Compress/RangeCoder/RangeCoderBit.cs
deleted file mode 100644
index 000a5a0..0000000
--- a/CS/7zip/Compress/RangeCoder/RangeCoderBit.cs
+++ /dev/null
@@ -1,117 +0,0 @@
-using System;
-
-namespace SevenZip.Compression.RangeCoder
-{
- struct BitEncoder
- {
- public const int kNumBitModelTotalBits = 11;
- public const uint kBitModelTotal = (1 << kNumBitModelTotalBits);
- const int kNumMoveBits = 5;
- const int kNumMoveReducingBits = 2;
- public const int kNumBitPriceShiftBits = 6;
-
- uint Prob;
-
- public void Init() { Prob = kBitModelTotal >> 1; }
-
- public void UpdateModel(uint symbol)
- {
- if (symbol == 0)
- Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
- else
- Prob -= (Prob) >> kNumMoveBits;
- }
-
- public void Encode(Encoder encoder, uint symbol)
- {
- // encoder.EncodeBit(Prob, kNumBitModelTotalBits, symbol);
- // UpdateModel(symbol);
- uint newBound = (encoder.Range >> kNumBitModelTotalBits) * Prob;
- if (symbol == 0)
- {
- encoder.Range = newBound;
- Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
- }
- else
- {
- encoder.Low += newBound;
- encoder.Range -= newBound;
- Prob -= (Prob) >> kNumMoveBits;
- }
- if (encoder.Range < Encoder.kTopValue)
- {
- encoder.Range <<= 8;
- encoder.ShiftLow();
- }
- }
-
- private static UInt32[] ProbPrices = new UInt32[kBitModelTotal >> kNumMoveReducingBits];
-
- static BitEncoder()
- {
- const int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits);
- for (int i = kNumBits - 1; i >= 0; i--)
- {
- UInt32 start = (UInt32)1 << (kNumBits - i - 1);
- UInt32 end = (UInt32)1 << (kNumBits - i);
- for (UInt32 j = start; j < end; j++)
- ProbPrices[j] = ((UInt32)i << kNumBitPriceShiftBits) +
- (((end - j) << kNumBitPriceShiftBits) >> (kNumBits - i - 1));
- }
- }
-
- public uint GetPrice(uint symbol)
- {
- return ProbPrices[(((Prob - symbol) ^ ((-(int)symbol))) & (kBitModelTotal - 1)) >> kNumMoveReducingBits];
- }
- public uint GetPrice0() { return ProbPrices[Prob >> kNumMoveReducingBits]; }
- public uint GetPrice1() { return ProbPrices[(kBitModelTotal - Prob) >> kNumMoveReducingBits]; }
- }
-
- struct BitDecoder
- {
- public const int kNumBitModelTotalBits = 11;
- public const uint kBitModelTotal = (1 << kNumBitModelTotalBits);
- const int kNumMoveBits = 5;
-
- uint Prob;
-
- public void UpdateModel(int numMoveBits, uint symbol)
- {
- if (symbol == 0)
- Prob += (kBitModelTotal - Prob) >> numMoveBits;
- else
- Prob -= (Prob) >> numMoveBits;
- }
-
- public void Init() { Prob = kBitModelTotal >> 1; }
-
- public uint Decode(RangeCoder.Decoder rangeDecoder)
- {
- uint newBound = (uint)(rangeDecoder.Range >> kNumBitModelTotalBits) * (uint)Prob;
- if (rangeDecoder.Code < newBound)
- {
- rangeDecoder.Range = newBound;
- Prob += (kBitModelTotal - Prob) >> kNumMoveBits;
- if (rangeDecoder.Range < Decoder.kTopValue)
- {
- rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
- rangeDecoder.Range <<= 8;
- }
- return 0;
- }
- else
- {
- rangeDecoder.Range -= newBound;
- rangeDecoder.Code -= newBound;
- Prob -= (Prob) >> kNumMoveBits;
- if (rangeDecoder.Range < Decoder.kTopValue)
- {
- rangeDecoder.Code = (rangeDecoder.Code << 8) | (byte)rangeDecoder.Stream.ReadByte();
- rangeDecoder.Range <<= 8;
- }
- return 1;
- }
- }
- }
-}
diff --git a/CS/7zip/Compress/RangeCoder/RangeCoderBitTree.cs b/CS/7zip/Compress/RangeCoder/RangeCoderBitTree.cs
deleted file mode 100644
index 3309c14..0000000
--- a/CS/7zip/Compress/RangeCoder/RangeCoderBitTree.cs
+++ /dev/null
@@ -1,157 +0,0 @@
-using System;
-
-namespace SevenZip.Compression.RangeCoder
-{
- struct BitTreeEncoder
- {
- BitEncoder[] Models;
- int NumBitLevels;
-
- public BitTreeEncoder(int numBitLevels)
- {
- NumBitLevels = numBitLevels;
- Models = new BitEncoder[1 << numBitLevels];
- }
-
- public void Init()
- {
- for (uint i = 1; i < (1 << NumBitLevels); i++)
- Models[i].Init();
- }
-
- public void Encode(Encoder rangeEncoder, UInt32 symbol)
- {
- UInt32 m = 1;
- for (int bitIndex = NumBitLevels; bitIndex > 0; )
- {
- bitIndex--;
- UInt32 bit = (symbol >> bitIndex) & 1;
- Models[m].Encode(rangeEncoder, bit);
- m = (m << 1) | bit;
- }
- }
-
- public void ReverseEncode(Encoder rangeEncoder, UInt32 symbol)
- {
- UInt32 m = 1;
- for (UInt32 i = 0; i < NumBitLevels; i++)
- {
- UInt32 bit = symbol & 1;
- Models[m].Encode(rangeEncoder, bit);
- m = (m << 1) | bit;
- symbol >>= 1;
- }
- }
-
- public UInt32 GetPrice(UInt32 symbol)
- {
- UInt32 price = 0;
- UInt32 m = 1;
- for (int bitIndex = NumBitLevels; bitIndex > 0; )
- {
- bitIndex--;
- UInt32 bit = (symbol >> bitIndex) & 1;
- price += Models[m].GetPrice(bit);
- m = (m << 1) + bit;
- }
- return price;
- }
-
- public UInt32 ReverseGetPrice(UInt32 symbol)
- {
- UInt32 price = 0;
- UInt32 m = 1;
- for (int i = NumBitLevels; i > 0; i--)
- {
- UInt32 bit = symbol & 1;
- symbol >>= 1;
- price += Models[m].GetPrice(bit);
- m = (m << 1) | bit;
- }
- return price;
- }
-
- public static UInt32 ReverseGetPrice(BitEncoder[] Models, UInt32 startIndex,
- int NumBitLevels, UInt32 symbol)
- {
- UInt32 price = 0;
- UInt32 m = 1;
- for (int i = NumBitLevels; i > 0; i--)
- {
- UInt32 bit = symbol & 1;
- symbol >>= 1;
- price += Models[startIndex + m].GetPrice(bit);
- m = (m << 1) | bit;
- }
- return price;
- }
-
- public static void ReverseEncode(BitEncoder[] Models, UInt32 startIndex,
- Encoder rangeEncoder, int NumBitLevels, UInt32 symbol)
- {
- UInt32 m = 1;
- for (int i = 0; i < NumBitLevels; i++)
- {
- UInt32 bit = symbol & 1;
- Models[startIndex + m].Encode(rangeEncoder, bit);
- m = (m << 1) | bit;
- symbol >>= 1;
- }
- }
- }
-
- struct BitTreeDecoder
- {
- BitDecoder[] Models;
- int NumBitLevels;
-
- public BitTreeDecoder(int numBitLevels)
- {
- NumBitLevels = numBitLevels;
- Models = new BitDecoder[1 << numBitLevels];
- }
-
- public void Init()
- {
- for (uint i = 1; i < (1 << NumBitLevels); i++)
- Models[i].Init();
- }
-
- public uint Decode(RangeCoder.Decoder rangeDecoder)
- {
- uint m = 1;
- for (int bitIndex = NumBitLevels; bitIndex > 0; bitIndex--)
- m = (m << 1) + Models[m].Decode(rangeDecoder);
- return m - ((uint)1 << NumBitLevels);
- }
-
- public uint ReverseDecode(RangeCoder.Decoder rangeDecoder)
- {
- uint m = 1;
- uint symbol = 0;
- for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
- {
- uint bit = Models[m].Decode(rangeDecoder);
- m <<= 1;
- m += bit;
- symbol |= (bit << bitIndex);
- }
- return symbol;
- }
-
- public static uint ReverseDecode(BitDecoder[] Models, UInt32 startIndex,
- RangeCoder.Decoder rangeDecoder, int NumBitLevels)
- {
- uint m = 1;
- uint symbol = 0;
- for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
- {
- uint bit = Models[startIndex + m].Decode(rangeDecoder);
- m <<= 1;
- m += bit;
- symbol |= (bit << bitIndex);
- }
- return symbol;
- }
- }
-}
diff --git a/CS/7zip/ICoder.cs b/CS/7zip/ICoder.cs
deleted file mode 100644
index 875cb27..0000000
--- a/CS/7zip/ICoder.cs
+++ /dev/null
@@ -1,157 +0,0 @@
-// ICoder.h
-
-using System;
-
-namespace SevenZip
-{
- /// <summary>
- /// The exception that is thrown when an error in input stream occurs during decoding.
- /// </summary>
- class DataErrorException : ApplicationException
- {
- public DataErrorException(): base("Data Error") { }
- }
-
- /// <summary>
- /// The exception that is thrown when the value of an argument is outside the allowable range.
- /// </summary>
- class InvalidParamException : ApplicationException
- {
- public InvalidParamException(): base("Invalid Parameter") { }
- }
-
- public interface ICodeProgress
- {
- /// <summary>
- /// Callback progress.
- /// </summary>
- /// <param name="inSize">
- /// input size. -1 if unknown.
- /// </param>
- /// <param name="outSize">
- /// output size. -1 if unknown.
- /// </param>
- void SetProgress(Int64 inSize, Int64 outSize);
- };
-
- public interface ICoder
- {
- /// <summary>
- /// Codes streams.
- /// </summary>
- /// <param name="inStream">
- /// input Stream.
- /// </param>
- /// <param name="outStream">
- /// output Stream.
- /// </param>
- /// <param name="inSize">
- /// input Size. -1 if unknown.
- /// </param>
- /// <param name="outSize">
- /// output Size. -1 if unknown.
- /// </param>
- /// <param name="progress">
- /// callback progress reference.
- /// </param>
- /// <exception cref="SevenZip.DataErrorException">
- /// if input stream is not valid
- /// </exception>
- void Code(System.IO.Stream inStream, System.IO.Stream outStream,
- Int64 inSize, Int64 outSize, ICodeProgress progress);
- };
-
- /*
- public interface ICoder2
- {
- void Code(ISequentialInStream []inStreams,
- const UInt64 []inSizes,
- ISequentialOutStream []outStreams,
- UInt64 []outSizes,
- ICodeProgress progress);
- };
- */
-
- /// <summary>
- /// Provides the fields that represent properties idenitifiers for compressing.
- /// </summary>
- public enum CoderPropID
- {
- /// <summary>
- /// Specifies default property.
- /// </summary>
- DefaultProp = 0,
- /// <summary>
- /// Specifies size of dictionary.
- /// </summary>
- DictionarySize,
- /// <summary>
- /// Specifies size of memory for PPM*.
- /// </summary>
- UsedMemorySize,
- /// <summary>
- /// Specifies order for PPM methods.
- /// </summary>
- Order,
- /// <summary>
- /// Specifies Block Size.
- /// </summary>
- BlockSize,
- /// <summary>
- /// Specifies number of postion state bits for LZMA (0 <= x <= 4).
- /// </summary>
- PosStateBits,
- /// <summary>
- /// Specifies number of literal context bits for LZMA (0 <= x <= 8).
- /// </summary>
- LitContextBits,
- /// <summary>
- /// Specifies number of literal position bits for LZMA (0 <= x <= 4).
- /// </summary>
- LitPosBits,
- /// <summary>
- /// Specifies number of fast bytes for LZ*.
- /// </summary>
- NumFastBytes,
- /// <summary>
- /// Specifies match finder. LZMA: "BT2", "BT4" or "BT4B".
- /// </summary>
- MatchFinder,
- /// <summary>
- /// Specifies the number of match finder cyckes.
- /// </summary>
- MatchFinderCycles,
- /// <summary>
- /// Specifies number of passes.
- /// </summary>
- NumPasses,
- /// <summary>
- /// Specifies number of algorithm.
- /// </summary>
- Algorithm,
- /// <summary>
- /// Specifies the number of threads.
- /// </summary>
- NumThreads,
- /// <summary>
- /// Specifies mode with end marker.
- /// </summary>
- EndMarker
- };
-
-
- public interface ISetCoderProperties
- {
- void SetCoderProperties(CoderPropID[] propIDs, object[] properties);
- };
-
- public interface IWriteCoderProperties
- {
- void WriteCoderProperties(System.IO.Stream outStream);
- }
-
- public interface ISetDecoderProperties
- {
- void SetDecoderProperties(byte[] properties);
- }
-}
diff --git a/DOC/7zC.txt b/DOC/7zC.txt
index 4927678..939b720 100644
--- a/DOC/7zC.txt
+++ b/DOC/7zC.txt
@@ -1,187 +1,187 @@
-7z ANSI-C Decoder 9.35
-----------------------
-
-7z ANSI-C provides 7z/LZMA decoding.
-7z ANSI-C version is simplified version ported from C++ code.
-
-LZMA is default and general compression method of 7z format
-in 7-Zip compression program (www.7-zip.org). LZMA provides high
-compression ratio and very fast decompression.
-
-
-LICENSE
--------
-
-7z ANSI-C Decoder is part of the LZMA SDK.
-LZMA SDK is written and placed in the public domain by Igor Pavlov.
-
-Files
----------------------
-
-7zDecode.* - Low level 7z decoding
-7zExtract.* - High level 7z decoding
-7zHeader.* - .7z format constants
-7zIn.* - .7z archive opening
-7zItem.* - .7z structures
-7zMain.c - Test application
-
-
-How To Use
-----------
-
-You can create .7z archive with 7z.exe, 7za.exe or 7zr.exe:
-
- 7z.exe a archive.7z *.htm -r -mx -m0fb=255
-
-If you have big number of files in archive, and you need fast extracting,
-you can use partly-solid archives:
-
- 7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K
-
-In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only
-512KB for extracting one file from such archive.
-
-
-Limitations of current version of 7z ANSI-C Decoder
----------------------------------------------------
-
- - It reads only "FileName", "Size", "LastWriteTime" and "CRC" information for each file in archive.
- - It supports only LZMA and Copy (no compression) methods with BCJ or BCJ2 filters.
- - It converts original UTF-16 Unicode file names to UTF-8 Unicode file names.
-
-These limitations will be fixed in future versions.
-
-
-Using 7z ANSI-C Decoder Test application:
------------------------------------------
-
-Usage: 7zDec <command> <archive_name>
-
-<Command>:
- e: Extract files from archive
- l: List contents of archive
- t: Test integrity of archive
-
-Example:
-
- 7zDec l archive.7z
-
-lists contents of archive.7z
-
- 7zDec e archive.7z
-
-extracts files from archive.7z to current folder.
-
-
-How to use .7z Decoder
-----------------------
-
-Memory allocation
-~~~~~~~~~~~~~~~~~
-
-7z Decoder uses two memory pools:
-1) Temporary pool
-2) Main pool
-Such scheme can allow you to avoid fragmentation of allocated blocks.
-
-
-Steps for using 7z decoder
---------------------------
-
-Use code at 7zMain.c as example.
-
-1) Declare variables:
- inStream /* implements ILookInStream interface */
- CSzArEx db; /* 7z archive database structure */
- ISzAlloc allocImp; /* memory functions for main pool */
- ISzAlloc allocTempImp; /* memory functions for temporary pool */
-
-2) call CrcGenerateTable(); function to initialize CRC structures.
-
-3) call SzArEx_Init(&db); function to initialize db structures.
-
-4) call SzArEx_Open(&db, inStream, &allocMain, &allocTemp) to open archive
-
-This function opens archive "inStream" and reads headers to "db".
-All items in "db" will be allocated with "allocMain" functions.
-SzArEx_Open function allocates and frees temporary structures by "allocTemp" functions.
-
-5) List items or Extract items
-
- Listing code:
- ~~~~~~~~~~~~~
-
- Use SzArEx_GetFileNameUtf16 function. Look example code in C\Util\7z\7zMain.c file.
-
-
- Extracting code:
- ~~~~~~~~~~~~~~~~
-
- SZ_RESULT SzAr_Extract(
- CArchiveDatabaseEx *db,
- ILookInStream *inStream,
- UInt32 fileIndex, /* index of file */
- UInt32 *blockIndex, /* index of solid block */
- Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */
- size_t *outBufferSize, /* buffer size for output buffer */
- size_t *offset, /* offset of stream for required file in *outBuffer */
- size_t *outSizeProcessed, /* size of file in *outBuffer */
- ISzAlloc *allocMain,
- ISzAlloc *allocTemp);
-
- If you need to decompress more than one file, you can send these values from previous call:
- blockIndex,
- outBuffer,
- outBufferSize,
- You can consider "outBuffer" as cache of solid block. If your archive is solid,
- it will increase decompression speed.
-
- After decompressing you must free "outBuffer":
- allocImp.Free(outBuffer);
-
-6) call SzArEx_Free(&db, allocImp.Free) to free allocated items in "db".
-
-
-
-
-Memory requirements for .7z decoding
-------------------------------------
-
-Memory usage for Archive opening:
- - Temporary pool:
- - Memory for uncompressed .7z headers
- - some other temporary blocks
- - Main pool:
- - Memory for database:
- Estimated size of one file structures in solid archive:
- - Size (4 or 8 Bytes)
- - CRC32 (4 bytes)
- - LastWriteTime (8 bytes)
- - Some file information (4 bytes)
- - File Name (variable length) + pointer + allocation structures
-
-Memory usage for archive Decompressing:
- - Temporary pool:
- - Memory for LZMA decompressing structures
- - Main pool:
- - Memory for decompressed solid block
- - Memory for temprorary buffers, if BCJ2 fileter is used. Usually these
- temprorary buffers can be about 15% of solid block size.
-
-
-7z Decoder doesn't allocate memory for compressed blocks.
-Instead of this, you must allocate buffer with desired
-size before calling 7z Decoder. Use 7zMain.c as example.
-
-
-Defines
--------
-
-_SZ_ALLOC_DEBUG - define it if you want to debug alloc/free operations to stderr.
-
-
----
-
-http://www.7-zip.org
-http://www.7-zip.org/sdk.html
-http://www.7-zip.org/support.html
+7z ANSI-C Decoder 9.35
+----------------------
+
+7z ANSI-C provides 7z/LZMA decoding.
+7z ANSI-C version is simplified version ported from C++ code.
+
+LZMA is default and general compression method of 7z format
+in 7-Zip compression program (www.7-zip.org). LZMA provides high
+compression ratio and very fast decompression.
+
+
+LICENSE
+-------
+
+7z ANSI-C Decoder is part of the LZMA SDK.
+LZMA SDK is written and placed in the public domain by Igor Pavlov.
+
+Files
+---------------------
+
+7zDecode.* - Low level 7z decoding
+7zExtract.* - High level 7z decoding
+7zHeader.* - .7z format constants
+7zIn.* - .7z archive opening
+7zItem.* - .7z structures
+7zMain.c - Test application
+
+
+How To Use
+----------
+
+You can create .7z archive with 7z.exe, 7za.exe or 7zr.exe:
+
+ 7z.exe a archive.7z *.htm -r -mx -m0fb=255
+
+If you have big number of files in archive, and you need fast extracting,
+you can use partly-solid archives:
+
+ 7za.exe a archive.7z *.htm -ms=512K -r -mx -m0fb=255 -m0d=512K
+
+In that example 7-Zip will use 512KB solid blocks. So it needs to decompress only
+512KB for extracting one file from such archive.
+
+
+Limitations of current version of 7z ANSI-C Decoder
+---------------------------------------------------
+
+ - It reads only "FileName", "Size", "LastWriteTime" and "CRC" information for each file in archive.
+ - It supports only LZMA and Copy (no compression) methods with BCJ or BCJ2 filters.
+ - It converts original UTF-16 Unicode file names to UTF-8 Unicode file names.
+
+These limitations will be fixed in future versions.
+
+
+Using 7z ANSI-C Decoder Test application:
+-----------------------------------------
+
+Usage: 7zDec <command> <archive_name>
+
+<Command>:
+ e: Extract files from archive
+ l: List contents of archive
+ t: Test integrity of archive
+
+Example:
+
+ 7zDec l archive.7z
+
+lists contents of archive.7z
+
+ 7zDec e archive.7z
+
+extracts files from archive.7z to current folder.
+
+
+How to use .7z Decoder
+----------------------
+
+Memory allocation
+~~~~~~~~~~~~~~~~~
+
+7z Decoder uses two memory pools:
+1) Temporary pool
+2) Main pool
+Such scheme can allow you to avoid fragmentation of allocated blocks.
+
+
+Steps for using 7z decoder
+--------------------------
+
+Use code at 7zMain.c as example.
+
+1) Declare variables:
+ inStream /* implements ILookInStream interface */
+ CSzArEx db; /* 7z archive database structure */
+ ISzAlloc allocImp; /* memory functions for main pool */
+ ISzAlloc allocTempImp; /* memory functions for temporary pool */
+
+2) call CrcGenerateTable(); function to initialize CRC structures.
+
+3) call SzArEx_Init(&db); function to initialize db structures.
+
+4) call SzArEx_Open(&db, inStream, &allocMain, &allocTemp) to open archive
+
+This function opens archive "inStream" and reads headers to "db".
+All items in "db" will be allocated with "allocMain" functions.
+SzArEx_Open function allocates and frees temporary structures by "allocTemp" functions.
+
+5) List items or Extract items
+
+ Listing code:
+ ~~~~~~~~~~~~~
+
+ Use SzArEx_GetFileNameUtf16 function. Look example code in C\Util\7z\7zMain.c file.
+
+
+ Extracting code:
+ ~~~~~~~~~~~~~~~~
+
+ SZ_RESULT SzAr_Extract(
+ CArchiveDatabaseEx *db,
+ ILookInStream *inStream,
+ UInt32 fileIndex, /* index of file */
+ UInt32 *blockIndex, /* index of solid block */
+ Byte **outBuffer, /* pointer to pointer to output buffer (allocated with allocMain) */
+ size_t *outBufferSize, /* buffer size for output buffer */
+ size_t *offset, /* offset of stream for required file in *outBuffer */
+ size_t *outSizeProcessed, /* size of file in *outBuffer */
+ ISzAlloc *allocMain,
+ ISzAlloc *allocTemp);
+
+ If you need to decompress more than one file, you can send these values from previous call:
+ blockIndex,
+ outBuffer,
+ outBufferSize,
+ You can consider "outBuffer" as cache of solid block. If your archive is solid,
+ it will increase decompression speed.
+
+ After decompressing you must free "outBuffer":
+ allocImp.Free(outBuffer);
+
+6) call SzArEx_Free(&db, allocImp.Free) to free allocated items in "db".
+
+
+
+
+Memory requirements for .7z decoding
+------------------------------------
+
+Memory usage for Archive opening:
+ - Temporary pool:
+ - Memory for uncompressed .7z headers
+ - some other temporary blocks
+ - Main pool:
+ - Memory for database:
+ Estimated size of one file structures in solid archive:
+ - Size (4 or 8 Bytes)
+ - CRC32 (4 bytes)
+ - LastWriteTime (8 bytes)
+ - Some file information (4 bytes)
+ - File Name (variable length) + pointer + allocation structures
+
+Memory usage for archive Decompressing:
+ - Temporary pool:
+ - Memory for LZMA decompressing structures
+ - Main pool:
+ - Memory for decompressed solid block
+ - Memory for temprorary buffers, if BCJ2 fileter is used. Usually these
+ temprorary buffers can be about 15% of solid block size.
+
+
+7z Decoder doesn't allocate memory for compressed blocks.
+Instead of this, you must allocate buffer with desired
+size before calling 7z Decoder. Use 7zMain.c as example.
+
+
+Defines
+-------
+
+_SZ_ALLOC_DEBUG - define it if you want to debug alloc/free operations to stderr.
+
+
+---
+
+http://www.7-zip.org
+http://www.7-zip.org/sdk.html
+http://www.7-zip.org/support.html
diff --git a/DOC/7zFormat.txt b/DOC/7zFormat.txt
index 9239e93..74cdfa4 100644
--- a/DOC/7zFormat.txt
+++ b/DOC/7zFormat.txt
@@ -1,469 +1,469 @@
-7z Format description (18.06)
-----------------------------
-
-This file contains description of 7z archive format.
-7z archive can contain files compressed with any method.
-See "Methods.txt" for description for defined compressing methods.
-
-
-Format structure Overview
--------------------------
-
-Some fields can be optional.
-
-Archive structure
-~~~~~~~~~~~~~~~~~
-SignatureHeader
-[PackedStreams]
-[PackedStreamsForHeaders]
-[
- Header
- or
- {
- Packed Header
- HeaderInfo
- }
-]
-
-
-
-Header structure
-~~~~~~~~~~~~~~~~
-{
- ArchiveProperties
- AdditionalStreams
- {
- PackInfo
- {
- PackPos
- NumPackStreams
- Sizes[NumPackStreams]
- CRCs[NumPackStreams]
- }
- CodersInfo
- {
- NumFolders
- Folders[NumFolders]
- {
- NumCoders
- CodersInfo[NumCoders]
- {
- ID
- NumInStreams;
- NumOutStreams;
- PropertiesSize
- Properties[PropertiesSize]
- }
- NumBindPairs
- BindPairsInfo[NumBindPairs]
- {
- InIndex;
- OutIndex;
- }
- PackedIndices
- }
- UnPackSize[Folders][Folders.NumOutstreams]
- CRCs[NumFolders]
- }
- SubStreamsInfo
- {
- NumUnPackStreamsInFolders[NumFolders];
- UnPackSizes[]
- CRCs[]
- }
- }
- MainStreamsInfo
- {
- (Same as in AdditionalStreams)
- }
- FilesInfo
- {
- NumFiles
- Properties[]
- {
- ID
- Size
- Data
- }
- }
-}
-
-HeaderInfo structure
-~~~~~~~~~~~~~~~~~~~~
-{
- (Same as in AdditionalStreams)
-}
-
-
-
-Notes about Notation and encoding
----------------------------------
-
-7z uses little endian encoding.
-
-7z archive format has optional headers that are marked as
-[]
-Header
-[]
-
-REAL_UINT64 means real UINT64.
-
-UINT64 means real UINT64 encoded with the following scheme:
-
- Size of encoding sequence depends from first byte:
- First_Byte Extra_Bytes Value
- (binary)
- 0xxxxxxx : ( xxxxxxx )
- 10xxxxxx BYTE y[1] : ( xxxxxx << (8 * 1)) + y
- 110xxxxx BYTE y[2] : ( xxxxx << (8 * 2)) + y
- ...
- 1111110x BYTE y[6] : ( x << (8 * 6)) + y
- 11111110 BYTE y[7] : y
- 11111111 BYTE y[8] : y
-
-
-
-Property IDs
-------------
-
-0x00 = kEnd
-
-0x01 = kHeader
-
-0x02 = kArchiveProperties
-
-0x03 = kAdditionalStreamsInfo
-0x04 = kMainStreamsInfo
-0x05 = kFilesInfo
-
-0x06 = kPackInfo
-0x07 = kUnPackInfo
-0x08 = kSubStreamsInfo
-
-0x09 = kSize
-0x0A = kCRC
-
-0x0B = kFolder
-
-0x0C = kCodersUnPackSize
-0x0D = kNumUnPackStream
-
-0x0E = kEmptyStream
-0x0F = kEmptyFile
-0x10 = kAnti
-
-0x11 = kName
-0x12 = kCTime
-0x13 = kATime
-0x14 = kMTime
-0x15 = kWinAttributes
-0x16 = kComment
-
-0x17 = kEncodedHeader
-
-0x18 = kStartPos
-0x19 = kDummy
-
-
-7z format headers
------------------
-
-SignatureHeader
-~~~~~~~~~~~~~~~
- BYTE kSignature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
-
- ArchiveVersion
- {
- BYTE Major; // now = 0
- BYTE Minor; // now = 4
- };
-
- UINT32 StartHeaderCRC;
-
- StartHeader
- {
- REAL_UINT64 NextHeaderOffset
- REAL_UINT64 NextHeaderSize
- UINT32 NextHeaderCRC
- }
-
-
-...........................
-
-
-ArchiveProperties
-~~~~~~~~~~~~~~~~~
-BYTE NID::kArchiveProperties (0x02)
-for (;;)
-{
- BYTE PropertyType;
- if (aType == 0)
- break;
- UINT64 PropertySize;
- BYTE PropertyData[PropertySize];
-}
-
-
-Digests (NumStreams)
-~~~~~~~~~~~~~~~~~~~~~
- BYTE AllAreDefined
- if (AllAreDefined == 0)
- {
- for(NumStreams)
- BIT Defined
- }
- UINT32 CRCs[NumDefined]
-
-
-PackInfo
-~~~~~~~~~~~~
- BYTE NID::kPackInfo (0x06)
- UINT64 PackPos
- UINT64 NumPackStreams
-
- []
- BYTE NID::kSize (0x09)
- UINT64 PackSizes[NumPackStreams]
- []
-
- []
- BYTE NID::kCRC (0x0A)
- PackStreamDigests[NumPackStreams]
- []
-
- BYTE NID::kEnd
-
-
-Folder
-~~~~~~
- UINT64 NumCoders;
- for (NumCoders)
- {
- BYTE
- {
- 0:3 CodecIdSize
- 4: Is Complex Coder
- 5: There Are Attributes
- 6: Reserved
- 7: There are more alternative methods. (Not used anymore, must be 0).
- }
- BYTE CodecId[CodecIdSize]
- if (Is Complex Coder)
- {
- UINT64 NumInStreams;
- UINT64 NumOutStreams;
- }
- if (There Are Attributes)
- {
- UINT64 PropertiesSize
- BYTE Properties[PropertiesSize]
- }
- }
-
- NumBindPairs = NumOutStreamsTotal - 1;
-
- for (NumBindPairs)
- {
- UINT64 InIndex;
- UINT64 OutIndex;
- }
-
- NumPackedStreams = NumInStreamsTotal - NumBindPairs;
- if (NumPackedStreams > 1)
- for(NumPackedStreams)
- {
- UINT64 Index;
- };
-
-
-
-
-Coders Info
-~~~~~~~~~~~
-
- BYTE NID::kUnPackInfo (0x07)
-
-
- BYTE NID::kFolder (0x0B)
- UINT64 NumFolders
- BYTE External
- switch(External)
- {
- case 0:
- Folders[NumFolders]
- case 1:
- UINT64 DataStreamIndex
- }
-
-
- BYTE ID::kCodersUnPackSize (0x0C)
- for(Folders)
- for(Folder.NumOutStreams)
- UINT64 UnPackSize;
-
-
- []
- BYTE NID::kCRC (0x0A)
- UnPackDigests[NumFolders]
- []
-
-
-
- BYTE NID::kEnd
-
-
-
-SubStreams Info
-~~~~~~~~~~~~~~
- BYTE NID::kSubStreamsInfo; (0x08)
-
- []
- BYTE NID::kNumUnPackStream; (0x0D)
- UINT64 NumUnPackStreamsInFolders[NumFolders];
- []
-
-
- []
- BYTE NID::kSize (0x09)
- UINT64 UnPackSizes[]
- []
-
-
- []
- BYTE NID::kCRC (0x0A)
- Digests[Number of streams with unknown CRC]
- []
-
-
- BYTE NID::kEnd
-
-
-Streams Info
-~~~~~~~~~~~~
-
- []
- PackInfo
- []
-
-
- []
- CodersInfo
- []
-
-
- []
- SubStreamsInfo
- []
-
- BYTE NID::kEnd
-
-
-FilesInfo
-~~~~~~~~~
- BYTE NID::kFilesInfo; (0x05)
- UINT64 NumFiles
-
- for (;;)
- {
- BYTE PropertyType;
- if (aType == 0)
- break;
-
- UINT64 Size;
-
- switch(PropertyType)
- {
- kEmptyStream: (0x0E)
- for(NumFiles)
- BIT IsEmptyStream
-
- kEmptyFile: (0x0F)
- for(EmptyStreams)
- BIT IsEmptyFile
-
- kAnti: (0x10)
- for(EmptyStreams)
- BIT IsAntiFile
-
- case kCTime: (0x12)
- case kATime: (0x13)
- case kMTime: (0x14)
- BYTE AllAreDefined
- if (AllAreDefined == 0)
- {
- for(NumFiles)
- BIT TimeDefined
- }
- BYTE External;
- if(External != 0)
- UINT64 DataIndex
- []
- for(Definded Items)
- REAL_UINT64 Time
- []
-
- kNames: (0x11)
- BYTE External;
- if(External != 0)
- UINT64 DataIndex
- []
- for(Files)
- {
- wchar_t Names[NameSize];
- wchar_t 0;
- }
- []
-
- kAttributes: (0x15)
- BYTE AllAreDefined
- if (AllAreDefined == 0)
- {
- for(NumFiles)
- BIT AttributesAreDefined
- }
- BYTE External;
- if(External != 0)
- UINT64 DataIndex
- []
- for(Definded Attributes)
- UINT32 Attributes
- []
- }
- }
-
-
-Header
-~~~~~~
- BYTE NID::kHeader (0x01)
-
- []
- ArchiveProperties
- []
-
- []
- BYTE NID::kAdditionalStreamsInfo; (0x03)
- StreamsInfo
- []
-
- []
- BYTE NID::kMainStreamsInfo; (0x04)
- StreamsInfo
- []
-
- []
- FilesInfo
- []
-
- BYTE NID::kEnd
-
-
-HeaderInfo
-~~~~~~~~~~
- []
- BYTE NID::kEncodedHeader; (0x17)
- StreamsInfo for Encoded Header
- []
-
-
----
-End of document
+7z Format description (18.06)
+----------------------------
+
+This file contains description of 7z archive format.
+7z archive can contain files compressed with any method.
+See "Methods.txt" for description for defined compressing methods.
+
+
+Format structure Overview
+-------------------------
+
+Some fields can be optional.
+
+Archive structure
+~~~~~~~~~~~~~~~~~
+SignatureHeader
+[PackedStreams]
+[PackedStreamsForHeaders]
+[
+ Header
+ or
+ {
+ Packed Header
+ HeaderInfo
+ }
+]
+
+
+
+Header structure
+~~~~~~~~~~~~~~~~
+{
+ ArchiveProperties
+ AdditionalStreams
+ {
+ PackInfo
+ {
+ PackPos
+ NumPackStreams
+ Sizes[NumPackStreams]
+ CRCs[NumPackStreams]
+ }
+ CodersInfo
+ {
+ NumFolders
+ Folders[NumFolders]
+ {
+ NumCoders
+ CodersInfo[NumCoders]
+ {
+ ID
+ NumInStreams;
+ NumOutStreams;
+ PropertiesSize
+ Properties[PropertiesSize]
+ }
+ NumBindPairs
+ BindPairsInfo[NumBindPairs]
+ {
+ InIndex;
+ OutIndex;
+ }
+ PackedIndices
+ }
+ UnPackSize[Folders][Folders.NumOutstreams]
+ CRCs[NumFolders]
+ }
+ SubStreamsInfo
+ {
+ NumUnPackStreamsInFolders[NumFolders];
+ UnPackSizes[]
+ CRCs[]
+ }
+ }
+ MainStreamsInfo
+ {
+ (Same as in AdditionalStreams)
+ }
+ FilesInfo
+ {
+ NumFiles
+ Properties[]
+ {
+ ID
+ Size
+ Data
+ }
+ }
+}
+
+HeaderInfo structure
+~~~~~~~~~~~~~~~~~~~~
+{
+ (Same as in AdditionalStreams)
+}
+
+
+
+Notes about Notation and encoding
+---------------------------------
+
+7z uses little endian encoding.
+
+7z archive format has optional headers that are marked as
+[]
+Header
+[]
+
+REAL_UINT64 means real UINT64.
+
+UINT64 means real UINT64 encoded with the following scheme:
+
+ Size of encoding sequence depends from first byte:
+ First_Byte Extra_Bytes Value
+ (binary)
+ 0xxxxxxx : ( xxxxxxx )
+ 10xxxxxx BYTE y[1] : ( xxxxxx << (8 * 1)) + y
+ 110xxxxx BYTE y[2] : ( xxxxx << (8 * 2)) + y
+ ...
+ 1111110x BYTE y[6] : ( x << (8 * 6)) + y
+ 11111110 BYTE y[7] : y
+ 11111111 BYTE y[8] : y
+
+
+
+Property IDs
+------------
+
+0x00 = kEnd
+
+0x01 = kHeader
+
+0x02 = kArchiveProperties
+
+0x03 = kAdditionalStreamsInfo
+0x04 = kMainStreamsInfo
+0x05 = kFilesInfo
+
+0x06 = kPackInfo
+0x07 = kUnPackInfo
+0x08 = kSubStreamsInfo
+
+0x09 = kSize
+0x0A = kCRC
+
+0x0B = kFolder
+
+0x0C = kCodersUnPackSize
+0x0D = kNumUnPackStream
+
+0x0E = kEmptyStream
+0x0F = kEmptyFile
+0x10 = kAnti
+
+0x11 = kName
+0x12 = kCTime
+0x13 = kATime
+0x14 = kMTime
+0x15 = kWinAttributes
+0x16 = kComment
+
+0x17 = kEncodedHeader
+
+0x18 = kStartPos
+0x19 = kDummy
+
+
+7z format headers
+-----------------
+
+SignatureHeader
+~~~~~~~~~~~~~~~
+ BYTE kSignature[6] = {'7', 'z', 0xBC, 0xAF, 0x27, 0x1C};
+
+ ArchiveVersion
+ {
+ BYTE Major; // now = 0
+ BYTE Minor; // now = 4
+ };
+
+ UINT32 StartHeaderCRC;
+
+ StartHeader
+ {
+ REAL_UINT64 NextHeaderOffset
+ REAL_UINT64 NextHeaderSize
+ UINT32 NextHeaderCRC
+ }
+
+
+...........................
+
+
+ArchiveProperties
+~~~~~~~~~~~~~~~~~
+BYTE NID::kArchiveProperties (0x02)
+for (;;)
+{
+ BYTE PropertyType;
+ if (aType == 0)
+ break;
+ UINT64 PropertySize;
+ BYTE PropertyData[PropertySize];
+}
+
+
+Digests (NumStreams)
+~~~~~~~~~~~~~~~~~~~~~
+ BYTE AllAreDefined
+ if (AllAreDefined == 0)
+ {
+ for(NumStreams)
+ BIT Defined
+ }
+ UINT32 CRCs[NumDefined]
+
+
+PackInfo
+~~~~~~~~~~~~
+ BYTE NID::kPackInfo (0x06)
+ UINT64 PackPos
+ UINT64 NumPackStreams
+
+ []
+ BYTE NID::kSize (0x09)
+ UINT64 PackSizes[NumPackStreams]
+ []
+
+ []
+ BYTE NID::kCRC (0x0A)
+ PackStreamDigests[NumPackStreams]
+ []
+
+ BYTE NID::kEnd
+
+
+Folder
+~~~~~~
+ UINT64 NumCoders;
+ for (NumCoders)
+ {
+ BYTE
+ {
+ 0:3 CodecIdSize
+ 4: Is Complex Coder
+ 5: There Are Attributes
+ 6: Reserved
+ 7: There are more alternative methods. (Not used anymore, must be 0).
+ }
+ BYTE CodecId[CodecIdSize]
+ if (Is Complex Coder)
+ {
+ UINT64 NumInStreams;
+ UINT64 NumOutStreams;
+ }
+ if (There Are Attributes)
+ {
+ UINT64 PropertiesSize
+ BYTE Properties[PropertiesSize]
+ }
+ }
+
+ NumBindPairs = NumOutStreamsTotal - 1;
+
+ for (NumBindPairs)
+ {
+ UINT64 InIndex;
+ UINT64 OutIndex;
+ }
+
+ NumPackedStreams = NumInStreamsTotal - NumBindPairs;
+ if (NumPackedStreams > 1)
+ for(NumPackedStreams)
+ {
+ UINT64 Index;
+ };
+
+
+
+
+Coders Info
+~~~~~~~~~~~
+
+ BYTE NID::kUnPackInfo (0x07)
+
+
+ BYTE NID::kFolder (0x0B)
+ UINT64 NumFolders
+ BYTE External
+ switch(External)
+ {
+ case 0:
+ Folders[NumFolders]
+ case 1:
+ UINT64 DataStreamIndex
+ }
+
+
+ BYTE ID::kCodersUnPackSize (0x0C)
+ for(Folders)
+ for(Folder.NumOutStreams)
+ UINT64 UnPackSize;
+
+
+ []
+ BYTE NID::kCRC (0x0A)
+ UnPackDigests[NumFolders]
+ []
+
+
+
+ BYTE NID::kEnd
+
+
+
+SubStreams Info
+~~~~~~~~~~~~~~
+ BYTE NID::kSubStreamsInfo; (0x08)
+
+ []
+ BYTE NID::kNumUnPackStream; (0x0D)
+ UINT64 NumUnPackStreamsInFolders[NumFolders];
+ []
+
+
+ []
+ BYTE NID::kSize (0x09)
+ UINT64 UnPackSizes[]
+ []
+
+
+ []
+ BYTE NID::kCRC (0x0A)
+ Digests[Number of streams with unknown CRC]
+ []
+
+
+ BYTE NID::kEnd
+
+
+Streams Info
+~~~~~~~~~~~~
+
+ []
+ PackInfo
+ []
+
+
+ []
+ CodersInfo
+ []
+
+
+ []
+ SubStreamsInfo
+ []
+
+ BYTE NID::kEnd
+
+
+FilesInfo
+~~~~~~~~~
+ BYTE NID::kFilesInfo; (0x05)
+ UINT64 NumFiles
+
+ for (;;)
+ {
+ BYTE PropertyType;
+ if (aType == 0)
+ break;
+
+ UINT64 Size;
+
+ switch(PropertyType)
+ {
+ kEmptyStream: (0x0E)
+ for(NumFiles)
+ BIT IsEmptyStream
+
+ kEmptyFile: (0x0F)
+ for(EmptyStreams)
+ BIT IsEmptyFile
+
+ kAnti: (0x10)
+ for(EmptyStreams)
+ BIT IsAntiFile
+
+ case kCTime: (0x12)
+ case kATime: (0x13)
+ case kMTime: (0x14)
+ BYTE AllAreDefined
+ if (AllAreDefined == 0)
+ {
+ for(NumFiles)
+ BIT TimeDefined
+ }
+ BYTE External;
+ if(External != 0)
+ UINT64 DataIndex
+ []
+ for(Definded Items)
+ REAL_UINT64 Time
+ []
+
+ kNames: (0x11)
+ BYTE External;
+ if(External != 0)
+ UINT64 DataIndex
+ []
+ for(Files)
+ {
+ wchar_t Names[NameSize];
+ wchar_t 0;
+ }
+ []
+
+ kAttributes: (0x15)
+ BYTE AllAreDefined
+ if (AllAreDefined == 0)
+ {
+ for(NumFiles)
+ BIT AttributesAreDefined
+ }
+ BYTE External;
+ if(External != 0)
+ UINT64 DataIndex
+ []
+ for(Definded Attributes)
+ UINT32 Attributes
+ []
+ }
+ }
+
+
+Header
+~~~~~~
+ BYTE NID::kHeader (0x01)
+
+ []
+ ArchiveProperties
+ []
+
+ []
+ BYTE NID::kAdditionalStreamsInfo; (0x03)
+ StreamsInfo
+ []
+
+ []
+ BYTE NID::kMainStreamsInfo; (0x04)
+ StreamsInfo
+ []
+
+ []
+ FilesInfo
+ []
+
+ BYTE NID::kEnd
+
+
+HeaderInfo
+~~~~~~~~~~
+ []
+ BYTE NID::kEncodedHeader; (0x17)
+ StreamsInfo for Encoded Header
+ []
+
+
+---
+End of document
diff --git a/DOC/7zip.hhp b/DOC/7zip.hhp
new file mode 100644
index 0000000..6c6bd70
--- /dev/null
+++ b/DOC/7zip.hhp
@@ -0,0 +1,83 @@
+[OPTIONS]
+Compatibility=1.1 or later
+Compiled file=7-zip.chm
+Contents file=7zip.hhc
+Default topic=start.htm
+Display compile progress=No
+Full-text search=Yes
+Index file=7zip.hhk
+Language=0x409 English (United States)
+
+
+[FILES]
+start.htm
+general\thanks.htm
+general\faq.htm
+general\formats.htm
+general\index.htm
+general\license.htm
+general\performance.htm
+general\7z.htm
+cmdline\index.htm
+cmdline\syntax.htm
+cmdline\exit_codes.htm
+cmdline\commands\add.htm
+cmdline\commands\bench.htm
+cmdline\commands\delete.htm
+cmdline\commands\extract.htm
+cmdline\commands\extract_full.htm
+cmdline\commands\update.htm
+cmdline\commands\hash.htm
+cmdline\commands\index.htm
+cmdline\commands\list.htm
+cmdline\commands\rename.htm
+cmdline\commands\test.htm
+cmdline\switches\index.htm
+cmdline\switches\yes.htm
+cmdline\switches\include.htm
+cmdline\switches\method.htm
+cmdline\switches\ar_include.htm
+cmdline\switches\ar_exclude.htm
+cmdline\switches\ar_no.htm
+cmdline\switches\bb.htm
+cmdline\switches\bs.htm
+cmdline\switches\charset.htm
+cmdline\switches\email.htm
+cmdline\switches\list_tech.htm
+cmdline\switches\large_pages.htm
+cmdline\switches\output_dir.htm
+cmdline\switches\overwrite.htm
+cmdline\switches\password.htm
+cmdline\switches\recurse.htm
+cmdline\switches\sa.htm
+cmdline\switches\scc.htm
+cmdline\switches\scrc.htm
+cmdline\switches\sdel.htm
+cmdline\switches\sfx.htm
+cmdline\switches\shared.htm
+cmdline\switches\sni.htm
+cmdline\switches\sns.htm
+cmdline\switches\spf.htm
+cmdline\switches\spm.htm
+cmdline\switches\ssc.htm
+cmdline\switches\stdin.htm
+cmdline\switches\stdout.htm
+cmdline\switches\stl.htm
+cmdline\switches\stop_switch.htm
+cmdline\switches\stx.htm
+cmdline\switches\type.htm
+cmdline\switches\update.htm
+cmdline\switches\working_dir.htm
+cmdline\switches\exclude.htm
+fm\options.htm
+fm\benchmark.htm
+fm\index.htm
+fm\menu.htm
+fm\about.htm
+fm\plugins\index.htm
+fm\plugins\7-zip\extract.htm
+fm\plugins\7-zip\index.htm
+fm\plugins\7-zip\add.htm
+
+[INFOTYPES]
+
diff --git a/DOC/7zip.wxs b/DOC/7zip.wxs
new file mode 100644
index 0000000..df1d320
--- /dev/null
+++ b/DOC/7zip.wxs
@@ -0,0 +1,403 @@
+<?xml version="1.0"?>
+
+<?define VerMajor = "23" ?>
+<?define VerMinor = "01" ?>
+<?define VerBuild = "00" ?>
+<?define MmVer = "$(var.VerMajor).$(var.VerMinor)" ?>
+<?define MmHex = "$(var.VerMajor)$(var.VerMinor)" ?>
+<?define MmmmVer = "$(var.MmVer).$(var.VerBuild).0" ?>
+<?define UpgradeMinVer = "4.38" ?>
+
+<?define ProductName = "7-Zip" ?>
+
+<?ifndef MyCPU?>
+ <?define MyCPU = "Intel" ?>
+<?endif?>
+
+<?if $(var.MyCPU) = "x64" ?>
+ <?define CpuId = "2" ?>
+ <?define PFilesFolder = "ProgramFiles64Folder" ?>
+ <?define Platforms = "x64" ?>
+ <?define CpuPostfix = " (x64 edition)" ?>
+ <?define Is64 = "yes" ?>
+ <?define NumBits = "64" ?>
+<?elseif $(var.MyCPU) = "ia64" ?>
+ <?define CpuId = "3" ?>
+ <?define PFilesFolder = "ProgramFiles64Folder" ?>
+ <?define Platforms = "Intel64" ?>
+ <?define CpuPostfix = " (ia64 edition)" ?>
+ <?define Is64 = "yes" ?>
+ <?define NumBits = "64" ?>
+<?else ?>
+ <?define CpuId = "1" ?>
+ <?define PFilesFolder = "ProgramFilesFolder" ?>
+ <?define Platforms = "Intel" ?>
+ <?define CpuPostfix = "" ?>
+ <?define Is64 = "no" ?>
+ <?define NumBits = "32" ?>
+<?endif ?>
+
+
+<?define ShellExtId = "{23170F69-40C1-278A-1000-000100020000}" ?>
+
+<?define BaseId = "23170F69-40C1-270$(var.CpuId)" ?>
+<?define BaseIdVer = "$(var.BaseId)-$(var.MmHex)-$(var.VerBuild)00" ?>
+<?define ProductId = "$(var.BaseIdVer)01000000" ?>
+<?define PackageId = "$(var.BaseIdVer)02000000" ?>
+<?define CompId = "$(var.BaseIdVer)030000" ?>
+<?define UpgradeCode = "$(var.BaseId)-0000-000004000000" ?>
+
+<?define CompFm = "$(var.CompId)01" ?>
+<?define CompShellExt = "$(var.CompId)02" ?>
+<?define CompCmdLine = "$(var.CompId)03" ?>
+<?define CompCmdLineA = "$(var.CompId)04" ?>
+<?define CompGui = "$(var.CompId)05" ?>
+<?define CompGuiSfx = "$(var.CompId)06" ?>
+<?define CompConSfx = "$(var.CompId)07" ?>
+<?define CompHelp = "$(var.CompId)08" ?>
+<?define CompDocs = "$(var.CompId)09" ?>
+<?define CompFormats = "$(var.CompId)10" ?>
+<?define CompCodecs = "$(var.CompId)11" ?>
+<?define CompLang = "$(var.CompId)12" ?>
+<?define CompShellExt2 = "$(var.CompId)13" ?>
+<?define CompInstallRegCU = "$(var.CompId)80" ?>
+<?define CompInstallRegLM = "$(var.CompId)81" ?>
+<?define CompInstallRegWild = "$(var.CompId)82" ?>
+<?define CompInstallRegDirectory = "$(var.CompId)83" ?>
+<?define CompInstallRegDirDD = "$(var.CompId)84" ?>
+<?define CompInstallRegDriveDD = "$(var.CompId)85" ?>
+<?define CompInstallRegApproved = "$(var.CompId)86" ?>
+<?define CompInstallRegAppPath = "$(var.CompId)87" ?>
+<?define CompInstallRegFolder = "$(var.CompId)88" ?>
+
+
+<?define Manufacturer = "Igor Pavlov" ?>
+<?define HomePage = "http://www.7-zip.org/" ?>
+<?define AboutURL = "$(var.HomePage)" ?>
+<?define UpdatesURL = "$(var.HomePage)download.html" ?>
+<?define SupportURL = "$(var.HomePage)support.html" ?>
+
+<Wix xmlns="http://schemas.microsoft.com/wix/2003/01/wi">
+ <Product
+ Id="$(var.ProductId)"
+ UpgradeCode="$(var.UpgradeCode)"
+ Name="$(var.ProductName) $(var.MmVer)$(var.CpuPostfix)"
+ Language="1033"
+ Version="$(var.MmmmVer)"
+ Manufacturer="$(var.Manufacturer)">
+
+ <Package
+ Id="$(var.PackageId)"
+ Description="$(var.ProductName)$(var.CpuPostfix) Package"
+ Comments="$(var.ProductName)$(var.CpuPostfix) Package"
+ Manufacturer="$(var.Manufacturer)"
+ InstallerVersion="200"
+ Compressed="yes"
+ Platforms="$(var.Platforms)"
+ />
+
+ <!-- Major upgrade -->
+ <Upgrade Id="$(var.UpgradeCode)">
+ <UpgradeVersion Minimum="$(var.UpgradeMinVer)" IncludeMinimum="yes"
+ Maximum="$(var.MmmmVer)" IncludeMaximum="no" Property="OLDERVERSIONBEINGUPGRADED" />
+ </Upgrade>
+
+ <Media Id="1" Cabinet="product.cab" EmbedCab="yes" CompressionLevel="high" />
+
+ <Property Id="MSIRMSHUTDOWN" Value="2"/>
+
+ <Property Id="INSTALLDIR">
+ <RegistrySearch Id="My7zipPathLM" Type="raw" Root="HKLM" Key="Software\7-Zip" Name="Path" />
+ <RegistrySearch Id="My7zipPathLM2" Type="raw" Root="HKLM" Key="Software\7-Zip" Name="Path$(var.NumBits)" />
+ <RegistrySearch Id="My7zipPath" Type="raw" Root="HKCU" Key="Software\7-Zip" Name="Path" />
+ <RegistrySearch Id="My7zipPath2" Type="raw" Root="HKCU" Key="Software\7-Zip" Name="Path$(var.NumBits)" />
+ </Property>
+
+ <Property Id="ALLUSERS">2</Property>
+
+ <Property Id="LicenseAccepted">1</Property>
+
+ <Property Id="ARPURLINFOABOUT" Value="$(var.AboutURL)" />
+ <Property Id="ARPHELPLINK" Value="$(var.SupportURL)" />
+ <Property Id="ARPURLUPDATEINFO" Value="$(var.UpdatesURL)" />
+
+
+ <Directory Id="TARGETDIR" Name="SourceDir">
+ <Directory Id="$(var.PFilesFolder)" Name="Files">
+ <Directory Id="INSTALLDIR" Name="7-Zip">
+
+ <Component Id="InstallRegCU" Guid="$(var.CompInstallRegCU)" DiskId="1" Win64="$(var.Is64)">
+ <Registry Id="MyInstallRegCU" Root="HKCU" Key="Software\7-Zip" Name="Path" Action="write" Type="string" Value="[INSTALLDIR]" />
+ <Registry Id="MyInstallRegCU2" Root="HKCU" Key="Software\7-Zip" Name="Path$(var.NumBits)" Action="write" Type="string" Value="[INSTALLDIR]" />
+ </Component>
+ <Component Id="InstallRegLM" Guid="$(var.CompInstallRegLM)" DiskId="1" Win64="$(var.Is64)">
+ <Condition>Privileged</Condition>
+ <Registry Id="MyInstallRegLM" Root="HKLM" Key="Software\7-Zip" Name="Path" Action="write" Type="string" Value="[INSTALLDIR]" />
+ <Registry Id="MyInstallRegLM2" Root="HKLM" Key="Software\7-Zip" Name="Path$(var.NumBits)" Action="write" Type="string" Value="[INSTALLDIR]" />
+ </Component>
+
+
+ <Component Id="InstallRegWild" Guid="$(var.CompInstallRegWild)" DiskId="1" Win64="$(var.Is64)">
+ <Registry Id="MyInstallRegWild" Action="write" Type="string"
+ Root="HKCR" Key="*\shellex\ContextMenuHandlers\7-Zip"
+ Value="$(var.ShellExtId)" />
+ </Component>
+
+ <Component Id="InstallRegDirectory" Guid="$(var.CompInstallRegDirectory)" DiskId="1" Win64="$(var.Is64)">
+ <Registry Id="MyInstallRegDirectory" Action="write" Type="string"
+ Root="HKCR" Key="Directory\shellex\ContextMenuHandlers\7-Zip"
+ Value="$(var.ShellExtId)" />
+ </Component>
+
+ <Component Id="InstallRegFolder" Guid="$(var.CompInstallRegFolder)" DiskId="1" Win64="$(var.Is64)">
+ <Registry Id="MyInstallRegFolder" Action="write" Type="string"
+ Root="HKCR" Key="Folder\shellex\ContextMenuHandlers\7-Zip"
+ Value="$(var.ShellExtId)" />
+ </Component>
+
+ <Component Id="InstallRegDirDD" Guid="$(var.CompInstallRegDirDD)" DiskId="1" Win64="$(var.Is64)">
+ <Registry Id="MyInstallRegDirDD" Action="write" Type="string"
+ Root="HKCR" Key="Directory\shellex\DragDropHandlers\7-Zip"
+ Value="$(var.ShellExtId)" />
+ </Component>
+
+ <Component Id="InstallRegDriveDD" Guid="$(var.CompInstallRegDriveDD)" DiskId="1" Win64="$(var.Is64)">
+ <Registry Id="MyInstallRegDriveDD" Action="write" Type="string"
+ Root="HKCR" Key="Drive\shellex\DragDropHandlers\7-Zip"
+ Value="$(var.ShellExtId)" />
+ </Component>
+
+ <Component Id="InstallRegApproved" Guid="$(var.CompInstallRegApproved)" DiskId="1" Win64="$(var.Is64)">
+ <Condition>Privileged</Condition>
+ <Registry Id="MyInstallRegApproved" Action="write" Type="string"
+ Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\Shell Extensions\Approved"
+ Name="$(var.ShellExtId)" Value="7-Zip Shell Extension" />
+ </Component>
+
+
+ <Component Id="InstallRegAppPath" Guid="$(var.CompInstallRegAppPath)" DiskId="1" Win64="$(var.Is64)">
+ <Condition>Privileged</Condition>
+ <Registry Id="MyInstallRegAppPath" Action="write" Type="string"
+ Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\App Paths\7zFM.exe"
+ Value="[INSTALLDIR]7zFM.exe" />
+ <Registry Id="MyInstallRegAppPath2" Action="write" Type="string"
+ Root="HKLM" Key="Software\Microsoft\Windows\CurrentVersion\App Paths\7zFM.exe" Name="Path"
+ Value="[INSTALLDIR]" />
+ </Component>
+
+ <Component Id="Fm" Guid="$(var.CompFm)" DiskId="1" Win64="$(var.Is64)">
+ <File Id="_7zFM.exe" Name="7zFM.exe">
+ <Shortcut Id="startmenuFmShortcut" Directory="PMenu" Name="7zipFM" LongName="7-Zip File Manager" />
+ </File>
+ </Component>
+
+ <?if $(var.MyCPU) = "x64" ?>
+
+ <Component Id="ShellExt32" Guid="$(var.CompShellExt2)" DiskId="1" Win64="no">
+ <File Id="_7zip32.dll" Name="7-zip32.dll" />
+ <Registry Id="shellReg0_32" Action="write" Type="string" Root="HKCR"
+ Key="CLSID\$(var.ShellExtId)\InprocServer32"
+ Value="[INSTALLDIR]7-zip32.dll" />
+ <Registry Id="shellReg1_32" Action="write" Type="string" Root="HKCR"
+ Key="CLSID\$(var.ShellExtId)\InprocServer32"
+ Name="ThreadingModel"
+ Value="Apartment" />
+ </Component>
+
+ <?endif ?>
+
+ <Component Id="ShellExt" Guid="$(var.CompShellExt)" DiskId="1" Win64="$(var.Is64)">
+ <File Id="_7zip.dll" Name="7-zip.dll" />
+ <Registry Id="shellReg0" Action="write" Type="string" Root="HKCR"
+ Key="CLSID\$(var.ShellExtId)\InprocServer32"
+ Value="[INSTALLDIR]7-zip.dll" />
+ <Registry Id="shellReg1" Action="write" Type="string" Root="HKCR"
+ Key="CLSID\$(var.ShellExtId)\InprocServer32"
+ Name="ThreadingModel"
+ Value="Apartment" />
+ </Component>
+
+ <Component Id="Gui" Guid="$(var.CompGui)" DiskId="1" Win64="$(var.Is64)">
+ <File Id="_7zG.exe" Name="7zG.exe" />
+ </Component>
+
+ <Component Id="Formats" Guid="$(var.CompFormats)" DiskId="1" Win64="$(var.Is64)">
+ <File Id="_7z.dll" Name="7z.dll" />
+ </Component>
+
+ <Component Id="CmdLine" Guid="$(var.CompCmdLine)" DiskId="1" Win64="$(var.Is64)">
+ <File Id="_7z.exe" Name="7z.exe" />
+ </Component>
+
+ <Component Id="GuiSfx" Guid="$(var.CompGuiSfx)" DiskId="1" Win64="$(var.Is64)">
+ <File Id="_7z.sfx" Name="7z.sfx" />
+ </Component>
+
+ <Component Id="ConSfx" Guid="$(var.CompConSfx)" DiskId="1" Win64="$(var.Is64)">
+ <File Id="_7zCon.sfx" Name="7zCon.sfx" />
+ </Component>
+
+ <Component Id="Docs" Guid="$(var.CompDocs)" DiskId="1" Win64="$(var.Is64)">
+ <File Id="descript.ion" Name="descript.ion" />
+ <File Id="History.txt" Name="History.txt" />
+ <File Id="License.txt" Name="License.txt" />
+ <File Id="readme.txt" Name="readme.txt" />
+ </Component>
+
+
+ <Component Id="Help" Guid="$(var.CompHelp)">
+ <File Id="_7zip.chm" Name="7-zip.chm" DiskId="1" >
+ <Shortcut Id="startmenuHelpShortcut" Directory="PMenu" Name="7zipHelp" LongName="7-Zip Help" />
+ </File>
+ </Component>
+
+ <Directory Id="MyLang" Name="Lang">
+ <Component Id="Lang" Guid="$(var.CompLang)" DiskId="1" Win64="$(var.Is64)">
+ <File Id="en.ttt" Name="en.ttt" />
+ <File Id="af.txt" Name="af.txt" />
+ <File Id="an.txt" Name="an.txt" />
+ <File Id="ar.txt" Name="ar.txt" />
+ <File Id="ast.txt" Name="ast.txt" />
+ <File Id="az.txt" Name="az.txt" />
+ <File Id="ba.txt" Name="ba.txt" />
+ <File Id="be.txt" Name="be.txt" />
+ <File Id="bg.txt" Name="bg.txt" />
+ <File Id="bn.txt" Name="bn.txt" />
+ <File Id="br.txt" Name="br.txt" />
+ <File Id="ca.txt" Name="ca.txt" />
+ <File Id="co.txt" Name="co.txt" />
+ <File Id="cs.txt" Name="cs.txt" />
+ <File Id="cy.txt" Name="cy.txt" />
+ <File Id="da.txt" Name="da.txt" />
+ <File Id="de.txt" Name="de.txt" />
+ <File Id="el.txt" Name="el.txt" />
+ <File Id="eo.txt" Name="eo.txt" />
+ <File Id="es.txt" Name="es.txt" />
+ <File Id="et.txt" Name="et.txt" />
+ <File Id="eu.txt" Name="eu.txt" />
+ <File Id="ext.txt" Name="ext.txt" />
+ <File Id="fa.txt" Name="fa.txt" />
+ <File Id="fi.txt" Name="fi.txt" />
+ <File Id="fr.txt" Name="fr.txt" />
+ <File Id="fur.txt" Name="fur.txt" />
+ <File Id="fy.txt" Name="fy.txt" />
+ <File Id="ga.txt" Name="ga.txt" />
+ <File Id="gl.txt" Name="gl.txt" />
+ <File Id="gu.txt" Name="gu.txt" />
+ <File Id="he.txt" Name="he.txt" />
+ <File Id="hi.txt" Name="hi.txt" />
+ <File Id="hr.txt" Name="hr.txt" />
+ <File Id="hu.txt" Name="hu.txt" />
+ <File Id="hy.txt" Name="hy.txt" />
+ <File Id="id.txt" Name="id.txt" />
+ <File Id="io.txt" Name="io.txt" />
+ <File Id="is.txt" Name="is.txt" />
+ <File Id="it.txt" Name="it.txt" />
+ <File Id="ja.txt" Name="ja.txt" />
+ <File Id="ka.txt" Name="ka.txt" />
+ <File Id="kaa.txt" Name="kaa.txt" />
+ <File Id="kab.txt" Name="kab.txt" />
+ <File Id="kk.txt" Name="kk.txt" />
+ <File Id="ko.txt" Name="ko.txt" />
+ <File Id="ku.txt" Name="ku.txt" />
+ <File Id="ku_ckb.txt" Name="ku-ckb.txt" />
+ <File Id="ky.txt" Name="ky.txt" />
+ <File Id="lij.txt" Name="lij.txt" />
+ <File Id="lt.txt" Name="lt.txt" />
+ <File Id="lv.txt" Name="lv.txt" />
+ <File Id="mk.txt" Name="mk.txt" />
+ <File Id="mn.txt" Name="mn.txt" />
+ <File Id="mng.txt" Name="mng.txt" />
+ <File Id="mng2.txt" Name="mng2.txt" />
+ <File Id="mr.txt" Name="mr.txt" />
+ <File Id="ms.txt" Name="ms.txt" />
+ <File Id="ne.txt" Name="ne.txt" />
+ <File Id="nl.txt" Name="nl.txt" />
+ <File Id="nb.txt" Name="nb.txt" />
+ <File Id="nn.txt" Name="nn.txt" />
+ <File Id="pa_in.txt" Name="pa-in.txt" />
+ <File Id="pl.txt" Name="pl.txt" />
+ <File Id="ps.txt" Name="ps.txt" />
+ <File Id="pt.txt" Name="pt.txt" />
+ <File Id="pt_br.txt" Name="pt-br.txt" />
+ <File Id="ro.txt" Name="ro.txt" />
+ <File Id="ru.txt" Name="ru.txt" />
+ <File Id="sa.txt" Name="sa.txt" />
+ <File Id="si.txt" Name="si.txt" />
+ <File Id="sk.txt" Name="sk.txt" />
+ <File Id="sl.txt" Name="sl.txt" />
+ <File Id="sq.txt" Name="sq.txt" />
+ <File Id="sr_spl.txt" Name="sr-spl.txt" />
+ <File Id="sr_spc.txt" Name="sr-spc.txt" />
+ <File Id="sv.txt" Name="sv.txt" />
+ <File Id="sw.txt" Name="sw.txt" />
+ <File Id="ta.txt" Name="ta.txt" />
+ <File Id="tg.txt" Name="tg.txt" />
+ <File Id="th.txt" Name="th.txt" />
+ <File Id="tk.txt" Name="tk.txt" />
+ <File Id="tr.txt" Name="tr.txt" />
+ <File Id="tt.txt" Name="tt.txt" />
+ <File Id="ug.txt" Name="ug.txt" />
+ <File Id="uk.txt" Name="uk.txt" />
+ <File Id="uz.txt" Name="uz.txt" />
+ <File Id="uz_cyrl.txt" Name="uz-cyrl.txt" />
+ <File Id="va.txt" Name="va.txt" />
+ <File Id="vi.txt" Name="vi.txt" />
+ <File Id="yo.txt" Name="yo.txt" />
+ <File Id="zh_cn.txt" Name="zh-cn.txt" />
+ <File Id="zh_tw.txt" Name="zh-tw.txt" />
+ </Component>
+ </Directory>
+
+
+ </Directory>
+ </Directory>
+
+ <Directory Id="ProgramMenuFolder" Name="PMenu" LongName="Programs">
+ <Directory Id="PMenu" Name="7zip" LongName="7-Zip" />
+ </Directory>
+ </Directory>
+
+ <Feature Id="Complete" Title="7-Zip" Description="The complete package."
+ Display="expand" Level="1" ConfigurableDirectory="INSTALLDIR"
+ Absent="disallow" AllowAdvertise="no" >
+ <Feature Id="Program" Title="Program files" Description="Program files." Level="1"
+ Absent="disallow" AllowAdvertise="no">
+ <ComponentRef Id="Fm" />
+ <ComponentRef Id="ShellExt" />
+ <?if $(var.MyCPU) = "x64" ?>
+ <ComponentRef Id="ShellExt32" />
+ <?endif ?>
+ <ComponentRef Id="CmdLine" />
+ <ComponentRef Id="Gui" />
+ <ComponentRef Id="GuiSfx" />
+ <ComponentRef Id="ConSfx" />
+ <ComponentRef Id="Formats" />
+ <ComponentRef Id="Docs" />
+ <ComponentRef Id="Help" />
+ <ComponentRef Id="InstallRegCU" />
+ <ComponentRef Id="InstallRegLM" />
+ <ComponentRef Id="InstallRegWild" />
+ <ComponentRef Id="InstallRegDirectory" />
+ <ComponentRef Id="InstallRegDirDD" />
+ <ComponentRef Id="InstallRegDriveDD" />
+ <ComponentRef Id="InstallRegApproved" />
+ <ComponentRef Id="InstallRegAppPath" />
+ <ComponentRef Id="InstallRegFolder" />
+
+ </Feature>
+ <Feature Id="LanguageFiles" Title="Localization files" Description="Localization files for 71 languages."
+ Level="1" AllowAdvertise="no">
+ <ComponentRef Id="Lang" />
+ </Feature>
+ </Feature>
+
+ <UIRef Id="WixUI" />
+
+ <!-- Install Sequences -->
+ <InstallExecuteSequence>
+ <RemoveExistingProducts After="InstallValidate" />
+ </InstallExecuteSequence>
+
+ </Product>
+</Wix>
diff --git a/DOC/License.txt b/DOC/License.txt
new file mode 100644
index 0000000..c9e858f
--- /dev/null
+++ b/DOC/License.txt
@@ -0,0 +1,90 @@
+ 7-Zip source code
+ ~~~~~~~~~~~~~~~~~
+ License for use and distribution
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+ 7-Zip Copyright (C) 1999-2020 Igor Pavlov.
+
+ The licenses for files are:
+
+ 1) CPP/7zip/Compress/Rar* files: the "GNU LGPL" with "unRAR license restriction"
+ 2) CPP/7zip/Compress/LzfseDecoder.cpp: the "BSD 3-clause License"
+ 3) Some files are "public domain" files, if "public domain" status is stated in source file.
+ 4) the "GNU LGPL" for all other files. If there is no license information in
+ some source file, that file is under the "GNU LGPL".
+
+ The "GNU LGPL" with "unRAR license restriction" means that you must follow both
+ "GNU LGPL" rules and "unRAR license restriction" rules.
+
+
+
+
+ GNU LGPL information
+ --------------------
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+
+
+ BSD 3-clause License
+ --------------------
+
+ The "BSD 3-clause License" is used for the code in LzfseDecoder.cpp that implements LZFSE data decompression.
+ That code was derived from the code in the "LZFSE compression library" developed by Apple Inc,
+ that also uses the "BSD 3-clause License":
+
+ ----
+ Copyright (c) 2015-2016, Apple Inc. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+
+ 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+
+ 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
+ in the documentation and/or other materials provided with the distribution.
+
+ 3. Neither the name of the copyright holder(s) nor the names of any contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ ----
+
+
+
+
+ unRAR license restriction
+ -------------------------
+
+ The decompression engine for RAR archives was developed using source
+ code of unRAR program.
+ All copyrights to original unRAR code are owned by Alexander Roshal.
+
+ The license for original unRAR code has the following restriction:
+
+ The unRAR sources cannot be used to re-create the RAR compression algorithm,
+ which is proprietary. Distribution of modified unRAR sources in separate form
+ or as a part of other software is permitted, provided that it is clearly
+ stated in the documentation and source comments that the code may
+ not be used to develop a RAR (WinRAR) compatible archiver.
+
+
+ --
+ Igor Pavlov
diff --git a/DOC/Methods.txt b/DOC/Methods.txt
index 6d0641b..541f1c1 100644
--- a/DOC/Methods.txt
+++ b/DOC/Methods.txt
@@ -1,173 +1,176 @@
-7-Zip method IDs for 7z and xz archives
----------------------------------------
-
-Version: 18.06
-Date: 2018-06-30
-
-Each compression or crypto method in 7z is associated with unique binary value (ID).
-The length of ID in bytes is arbitrary but it can not exceed 63 bits (8 bytes).
-
-xz and 7z formats use same ID map.
-
-If you want to add some new ID, you have two ways:
- 1) Write request for allocating IDs to 7-Zip developers.
- 2) Generate 8-bytes ID:
-
- 3F ZZ ZZ ZZ ZZ ZZ MM MM
-
- 3F - Prefix for random IDs (1 byte)
- ZZ ZZ ZZ ZZ ZZ - Developer ID (5 bytes). Use real random bytes.
-
- MM MM - Method ID (2 bytes)
-
- You can notify 7-Zip developers about your Developer ID / Method ID.
-
- Note: Use new ID, if old codec can not decode data encoded with new version.
-
-
-List of defined IDs
--------------------
-
-00 - Copy
-
-03 - Delta
-04 - BCJ (x86)
-05 - PPC (big-endian)
-06 - IA64
-07 - ARM (little-endian)
-08 - ARMT (little-endian)
-09 - SPARC
-
-21 - LZMA2
-
-02.. - Common
- 03 [Swap]
- - 2 Swap2
- - 4 Swap4
-
-03.. - 7z
- 01 -
- 01 - LZMA
-
- 03 - [Branch Codecs]
- 01 - [x86 Codecs]
- 03 - BCJ
- 1B - BCJ2 (4 packed streams)
- 02 -
- 05 - PPC (big-endian)
- 03 -
- 01 - Alpha
- 04 -
- 01 - IA64
- 05 -
- 01 - ARM (little-endian)
- 06 -
- 05 - M68 (big-endian)
- 07 -
- 01 - ARMT (little-endian)
- 08 -
- 05 - SPARC
-
- 04 -
- 01 - PPMD
-
- 7F -
- 01 - experimental method.
-
-
-04.. - Misc codecs
-
- 00 - Reserved
-
- 01 - [Zip]
- 00 - Copy (not used. Use {00} instead)
- 01 - Shrink
- 06 - Implode
- 08 - Deflate
- 09 - Deflate64
- 0A - Imploding
- 0C - BZip2 (not used. Use {040202} instead)
- 0E - LZMA (LZMA-zip)
- 5F - xz
- 60 - Jpeg
- 61 - WavPack
- 62 - PPMd (PPMd-zip)
- 63 - wzAES
-
- 02 -
- 02 - BZip2
-
- 03 - [Rar]
- 01 - Rar1
- 02 - Rar2
- 03 - Rar3
- 05 - Rar5
-
- 04 - [Arj]
- 01 - Arj(1,2,3)
- 02 - Arj4
-
- 05 - [Z]
-
- 06 - [Lzh]
-
- 07 - Reserved for 7z
-
- 08 - [Cab]
-
- 09 - [NSIS]
- 01 - DeflateNSIS
- 02 - BZip2NSIS
-
- F7 - External codecs (that are not included to 7-Zip)
-
- 0x xx - reserved
-
- 10 xx - reserved (LZHAM)
- 01 - LZHAM
-
- 11 xx - reserved (Tino Reichardt)
- 01 - ZSTD
- 02 - BROTLI
- 04 - LZ4
- 05 - LZ5
- 06 - LIZARD
-
- 12 xx - reserverd (Denis Anisimov)
-
- 01 - WavPack2
- FE - eSplitter
- FF - RawSplitter
-
-
-06.. - Crypto
-
- F0 - Ciphers without hashing algo
-
- 01 - [AES]
- 0x - AES-128
- 4x - AES-192
- 8x - AES-256
- Cx - AES
-
- x0 - ECB
- x1 - CBC
- x2 - CFB
- x3 - OFB
- x4 - CTR
-
- F1 - Combine Ciphers
-
- 01 - [Zip]
- 01 - ZipCrypto (Main Zip crypto algo)
-
- 03 - [RAR]
- 02 -
- 03 - Rar29AES (AES-128 + modified SHA-1)
-
- 07 - [7z]
- 01 - 7zAES (AES-256 + SHA-256)
-
-
----
-End of document
+7-Zip method IDs for 7z and xz archives
+---------------------------------------
+
+Version: 23.01
+Date: 2023-06-30
+
+Each compression or crypto method in 7z is associated with unique binary value (ID).
+The length of ID in bytes is arbitrary but it can not exceed 63 bits (8 bytes).
+
+xz and 7z formats use same ID map.
+
+If you want to add some new ID, you have two ways:
+ 1) Write request for allocating IDs to 7-Zip developers.
+ 2) Generate 8-bytes ID:
+
+ 3F ZZ ZZ ZZ ZZ ZZ MM MM
+
+ 3F - Prefix for random IDs (1 byte)
+ ZZ ZZ ZZ ZZ ZZ - Developer ID (5 bytes). Use real random bytes.
+
+ MM MM - Method ID (2 bytes)
+
+ You can notify 7-Zip developers about your Developer ID / Method ID.
+
+ Note: Use new ID, if old codec can not decode data encoded with new version.
+
+
+List of defined IDs
+-------------------
+
+00 - Copy
+
+03 - Delta
+04 - BCJ (x86)
+05 - PPC (big-endian)
+06 - IA64
+07 - ARM (little-endian)
+08 - ARMT (little-endian)
+09 - SPARC
+0A - ARM64
+
+21 - LZMA2
+
+02.. - Common
+ 03 [Swap]
+ - 2 Swap2
+ - 4 Swap4
+
+03.. - 7z
+ 01 -
+ 01 - LZMA
+
+ 03 - [Branch Codecs]
+ 01 - [x86 Codecs]
+ 03 - BCJ
+ 1B - BCJ2 (4 packed streams)
+ 02 -
+ 05 - PPC (big-endian)
+ 03 -
+ 01 - Alpha
+ 04 -
+ 01 - IA64
+ 05 -
+ 01 - ARM (little-endian)
+ 06 -
+ 05 - M68 (big-endian)
+ 07 -
+ 01 - ARMT (little-endian)
+ 08 -
+ 05 - SPARC
+
+ 04 -
+ 01 - PPMD
+
+ 7F -
+ 01 - experimental method.
+
+
+04.. - Misc codecs
+
+ 00 - Reserved
+
+ 01 - [Zip]
+ 00 - Copy (not used. Use {00} instead)
+ 01 - Shrink
+ 06 - Implode
+ 08 - Deflate
+ 09 - Deflate64
+ 0A - Imploding
+ 0C - BZip2 (not used. Use {040202} instead)
+ 0E - LZMA (LZMA-zip)
+
+ 5D - ZSTD
+ 5F - xz
+ 60 - Jpeg
+ 61 - WavPack
+ 62 - PPMd (PPMd-zip)
+ 63 - wzAES
+
+ 02 -
+ 02 - BZip2
+
+ 03 - [Rar]
+ 01 - Rar1
+ 02 - Rar2
+ 03 - Rar3
+ 05 - Rar5
+
+ 04 - [Arj]
+ 01 - Arj(1,2,3)
+ 02 - Arj4
+
+ 05 - [Z]
+
+ 06 - [Lzh]
+
+ 07 - Reserved for 7z
+
+ 08 - [Cab]
+
+ 09 - [NSIS]
+ 01 - DeflateNSIS
+ 02 - BZip2NSIS
+
+ F7 - External codecs (that are not included to 7-Zip)
+
+ 0x xx - reserved
+
+ 10 xx - reserved (LZHAM)
+ 01 - LZHAM
+
+ 11 xx - reserved (Tino Reichardt)
+ 01 - ZSTD
+ 02 - BROTLI
+ 04 - LZ4
+ 05 - LZ5
+ 06 - LIZARD
+
+ 12 xx - reserverd (Denis Anisimov)
+
+ 01 - WavPack2
+ FE - eSplitter
+ FF - RawSplitter
+
+
+06.. - Crypto
+
+ F0 - Ciphers without hashing algo
+
+ 01 - [AES]
+ 0x - AES-128
+ 4x - AES-192
+ 8x - AES-256
+ Cx - AES
+
+ x0 - ECB
+ x1 - CBC
+ x2 - CFB
+ x3 - OFB
+ x4 - CTR
+
+ F1 - Combine Ciphers
+
+ 01 - [Zip]
+ 01 - ZipCrypto (Main Zip crypto algo)
+
+ 03 - [RAR]
+ 02 -
+ 03 - Rar29AES (AES-128 + modified SHA-1)
+
+ 07 - [7z]
+ 01 - 7zAES (AES-256 + SHA-256)
+
+
+---
+End of document
diff --git a/DOC/copying.txt b/DOC/copying.txt
new file mode 100644
index 0000000..4362b49
--- /dev/null
+++ b/DOC/copying.txt
@@ -0,0 +1,502 @@
+ GNU LESSER GENERAL PUBLIC LICENSE
+ Version 2.1, February 1999
+
+ Copyright (C) 1991, 1999 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+[This is the first released version of the Lesser GPL. It also counts
+ as the successor of the GNU Library Public License, version 2, hence
+ the version number 2.1.]
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+Licenses are intended to guarantee your freedom to share and change
+free software--to make sure the software is free for all its users.
+
+ This license, the Lesser General Public License, applies to some
+specially designated software packages--typically libraries--of the
+Free Software Foundation and other authors who decide to use it. You
+can use it too, but we suggest you first think carefully about whether
+this license or the ordinary General Public License is the better
+strategy to use in any particular case, based on the explanations below.
+
+ When we speak of free software, we are referring to freedom of use,
+not price. Our General Public Licenses are designed to make sure that
+you have the freedom to distribute copies of free software (and charge
+for this service if you wish); that you receive source code or can get
+it if you want it; that you can change the software and use pieces of
+it in new free programs; and that you are informed that you can do
+these things.
+
+ To protect your rights, we need to make restrictions that forbid
+distributors to deny you these rights or to ask you to surrender these
+rights. These restrictions translate to certain responsibilities for
+you if you distribute copies of the library or if you modify it.
+
+ For example, if you distribute copies of the library, whether gratis
+or for a fee, you must give the recipients all the rights that we gave
+you. You must make sure that they, too, receive or can get the source
+code. If you link other code with the library, you must provide
+complete object files to the recipients, so that they can relink them
+with the library after making changes to the library and recompiling
+it. And you must show them these terms so they know their rights.
+
+ We protect your rights with a two-step method: (1) we copyright the
+library, and (2) we offer you this license, which gives you legal
+permission to copy, distribute and/or modify the library.
+
+ To protect each distributor, we want to make it very clear that
+there is no warranty for the free library. Also, if the library is
+modified by someone else and passed on, the recipients should know
+that what they have is not the original version, so that the original
+author's reputation will not be affected by problems that might be
+introduced by others.
+
+ Finally, software patents pose a constant threat to the existence of
+any free program. We wish to make sure that a company cannot
+effectively restrict the users of a free program by obtaining a
+restrictive license from a patent holder. Therefore, we insist that
+any patent license obtained for a version of the library must be
+consistent with the full freedom of use specified in this license.
+
+ Most GNU software, including some libraries, is covered by the
+ordinary GNU General Public License. This license, the GNU Lesser
+General Public License, applies to certain designated libraries, and
+is quite different from the ordinary General Public License. We use
+this license for certain libraries in order to permit linking those
+libraries into non-free programs.
+
+ When a program is linked with a library, whether statically or using
+a shared library, the combination of the two is legally speaking a
+combined work, a derivative of the original library. The ordinary
+General Public License therefore permits such linking only if the
+entire combination fits its criteria of freedom. The Lesser General
+Public License permits more lax criteria for linking other code with
+the library.
+
+ We call this license the "Lesser" General Public License because it
+does Less to protect the user's freedom than the ordinary General
+Public License. It also provides other free software developers Less
+of an advantage over competing non-free programs. These disadvantages
+are the reason we use the ordinary General Public License for many
+libraries. However, the Lesser license provides advantages in certain
+special circumstances.
+
+ For example, on rare occasions, there may be a special need to
+encourage the widest possible use of a certain library, so that it becomes
+a de-facto standard. To achieve this, non-free programs must be
+allowed to use the library. A more frequent case is that a free
+library does the same job as widely used non-free libraries. In this
+case, there is little to gain by limiting the free library to free
+software only, so we use the Lesser General Public License.
+
+ In other cases, permission to use a particular library in non-free
+programs enables a greater number of people to use a large body of
+free software. For example, permission to use the GNU C Library in
+non-free programs enables many more people to use the whole GNU
+operating system, as well as its variant, the GNU/Linux operating
+system.
+
+ Although the Lesser General Public License is Less protective of the
+users' freedom, it does ensure that the user of a program that is
+linked with the Library has the freedom and the wherewithal to run
+that program using a modified version of the Library.
+
+ The precise terms and conditions for copying, distribution and
+modification follow. Pay close attention to the difference between a
+"work based on the library" and a "work that uses the library". The
+former contains code derived from the library, whereas the latter must
+be combined with the library in order to run.
+
+ GNU LESSER GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License Agreement applies to any software library or other
+program which contains a notice placed by the copyright holder or
+other authorized party saying it may be distributed under the terms of
+this Lesser General Public License (also called "this License").
+Each licensee is addressed as "you".
+
+ A "library" means a collection of software functions and/or data
+prepared so as to be conveniently linked with application programs
+(which use some of those functions and data) to form executables.
+
+ The "Library", below, refers to any such software library or work
+which has been distributed under these terms. A "work based on the
+Library" means either the Library or any derivative work under
+copyright law: that is to say, a work containing the Library or a
+portion of it, either verbatim or with modifications and/or translated
+straightforwardly into another language. (Hereinafter, translation is
+included without limitation in the term "modification".)
+
+ "Source code" for a work means the preferred form of the work for
+making modifications to it. For a library, complete source code means
+all the source code for all modules it contains, plus any associated
+interface definition files, plus the scripts used to control compilation
+and installation of the library.
+
+ Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running a program using the Library is not restricted, and output from
+such a program is covered only if its contents constitute a work based
+on the Library (independent of the use of the Library in a tool for
+writing it). Whether that is true depends on what the Library does
+and what the program that uses the Library does.
+
+ 1. You may copy and distribute verbatim copies of the Library's
+complete source code as you receive it, in any medium, provided that
+you conspicuously and appropriately publish on each copy an
+appropriate copyright notice and disclaimer of warranty; keep intact
+all the notices that refer to this License and to the absence of any
+warranty; and distribute a copy of this License along with the
+Library.
+
+ You may charge a fee for the physical act of transferring a copy,
+and you may at your option offer warranty protection in exchange for a
+fee.
+
+ 2. You may modify your copy or copies of the Library or any portion
+of it, thus forming a work based on the Library, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) The modified work must itself be a software library.
+
+ b) You must cause the files modified to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ c) You must cause the whole of the work to be licensed at no
+ charge to all third parties under the terms of this License.
+
+ d) If a facility in the modified Library refers to a function or a
+ table of data to be supplied by an application program that uses
+ the facility, other than as an argument passed when the facility
+ is invoked, then you must make a good faith effort to ensure that,
+ in the event an application does not supply such function or
+ table, the facility still operates, and performs whatever part of
+ its purpose remains meaningful.
+
+ (For example, a function in a library to compute square roots has
+ a purpose that is entirely well-defined independent of the
+ application. Therefore, Subsection 2d requires that any
+ application-supplied function or table used by this function must
+ be optional: if the application does not supply it, the square
+ root function must still compute square roots.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Library,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Library, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote
+it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Library.
+
+In addition, mere aggregation of another work not based on the Library
+with the Library (or with a work based on the Library) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may opt to apply the terms of the ordinary GNU General Public
+License instead of this License to a given copy of the Library. To do
+this, you must alter all the notices that refer to this License, so
+that they refer to the ordinary GNU General Public License, version 2,
+instead of to this License. (If a newer version than version 2 of the
+ordinary GNU General Public License has appeared, then you can specify
+that version instead if you wish.) Do not make any other change in
+these notices.
+
+ Once this change is made in a given copy, it is irreversible for
+that copy, so the ordinary GNU General Public License applies to all
+subsequent copies and derivative works made from that copy.
+
+ This option is useful when you wish to copy part of the code of
+the Library into a program that is not a library.
+
+ 4. You may copy and distribute the Library (or a portion or
+derivative of it, under Section 2) in object code or executable form
+under the terms of Sections 1 and 2 above provided that you accompany
+it with the complete corresponding machine-readable source code, which
+must be distributed under the terms of Sections 1 and 2 above on a
+medium customarily used for software interchange.
+
+ If distribution of object code is made by offering access to copy
+from a designated place, then offering equivalent access to copy the
+source code from the same place satisfies the requirement to
+distribute the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 5. A program that contains no derivative of any portion of the
+Library, but is designed to work with the Library by being compiled or
+linked with it, is called a "work that uses the Library". Such a
+work, in isolation, is not a derivative work of the Library, and
+therefore falls outside the scope of this License.
+
+ However, linking a "work that uses the Library" with the Library
+creates an executable that is a derivative of the Library (because it
+contains portions of the Library), rather than a "work that uses the
+library". The executable is therefore covered by this License.
+Section 6 states terms for distribution of such executables.
+
+ When a "work that uses the Library" uses material from a header file
+that is part of the Library, the object code for the work may be a
+derivative work of the Library even though the source code is not.
+Whether this is true is especially significant if the work can be
+linked without the Library, or if the work is itself a library. The
+threshold for this to be true is not precisely defined by law.
+
+ If such an object file uses only numerical parameters, data
+structure layouts and accessors, and small macros and small inline
+functions (ten lines or less in length), then the use of the object
+file is unrestricted, regardless of whether it is legally a derivative
+work. (Executables containing this object code plus portions of the
+Library will still fall under Section 6.)
+
+ Otherwise, if the work is a derivative of the Library, you may
+distribute the object code for the work under the terms of Section 6.
+Any executables containing that work also fall under Section 6,
+whether or not they are linked directly with the Library itself.
+
+ 6. As an exception to the Sections above, you may also combine or
+link a "work that uses the Library" with the Library to produce a
+work containing portions of the Library, and distribute that work
+under terms of your choice, provided that the terms permit
+modification of the work for the customer's own use and reverse
+engineering for debugging such modifications.
+
+ You must give prominent notice with each copy of the work that the
+Library is used in it and that the Library and its use are covered by
+this License. You must supply a copy of this License. If the work
+during execution displays copyright notices, you must include the
+copyright notice for the Library among them, as well as a reference
+directing the user to the copy of this License. Also, you must do one
+of these things:
+
+ a) Accompany the work with the complete corresponding
+ machine-readable source code for the Library including whatever
+ changes were used in the work (which must be distributed under
+ Sections 1 and 2 above); and, if the work is an executable linked
+ with the Library, with the complete machine-readable "work that
+ uses the Library", as object code and/or source code, so that the
+ user can modify the Library and then relink to produce a modified
+ executable containing the modified Library. (It is understood
+ that the user who changes the contents of definitions files in the
+ Library will not necessarily be able to recompile the application
+ to use the modified definitions.)
+
+ b) Use a suitable shared library mechanism for linking with the
+ Library. A suitable mechanism is one that (1) uses at run time a
+ copy of the library already present on the user's computer system,
+ rather than copying library functions into the executable, and (2)
+ will operate properly with a modified version of the library, if
+ the user installs one, as long as the modified version is
+ interface-compatible with the version that the work was made with.
+
+ c) Accompany the work with a written offer, valid for at
+ least three years, to give the same user the materials
+ specified in Subsection 6a, above, for a charge no more
+ than the cost of performing this distribution.
+
+ d) If distribution of the work is made by offering access to copy
+ from a designated place, offer equivalent access to copy the above
+ specified materials from the same place.
+
+ e) Verify that the user has already received a copy of these
+ materials or that you have already sent this user a copy.
+
+ For an executable, the required form of the "work that uses the
+Library" must include any data and utility programs needed for
+reproducing the executable from it. However, as a special exception,
+the materials to be distributed need not include anything that is
+normally distributed (in either source or binary form) with the major
+components (compiler, kernel, and so on) of the operating system on
+which the executable runs, unless that component itself accompanies
+the executable.
+
+ It may happen that this requirement contradicts the license
+restrictions of other proprietary libraries that do not normally
+accompany the operating system. Such a contradiction means you cannot
+use both them and the Library together in an executable that you
+distribute.
+
+ 7. You may place library facilities that are a work based on the
+Library side-by-side in a single library together with other library
+facilities not covered by this License, and distribute such a combined
+library, provided that the separate distribution of the work based on
+the Library and of the other library facilities is otherwise
+permitted, and provided that you do these two things:
+
+ a) Accompany the combined library with a copy of the same work
+ based on the Library, uncombined with any other library
+ facilities. This must be distributed under the terms of the
+ Sections above.
+
+ b) Give prominent notice with the combined library of the fact
+ that part of it is a work based on the Library, and explaining
+ where to find the accompanying uncombined form of the same work.
+
+ 8. You may not copy, modify, sublicense, link with, or distribute
+the Library except as expressly provided under this License. Any
+attempt otherwise to copy, modify, sublicense, link with, or
+distribute the Library is void, and will automatically terminate your
+rights under this License. However, parties who have received copies,
+or rights, from you under this License will not have their licenses
+terminated so long as such parties remain in full compliance.
+
+ 9. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Library or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Library (or any work based on the
+Library), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Library or works based on it.
+
+ 10. Each time you redistribute the Library (or any work based on the
+Library), the recipient automatically receives a license from the
+original licensor to copy, distribute, link with or modify the Library
+subject to these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties with
+this License.
+
+ 11. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Library at all. For example, if a patent
+license would not permit royalty-free redistribution of the Library by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Library.
+
+If any portion of this section is held invalid or unenforceable under any
+particular circumstance, the balance of the section is intended to apply,
+and the section as a whole is intended to apply in other circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 12. If the distribution and/or use of the Library is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Library under this License may add
+an explicit geographical distribution limitation excluding those countries,
+so that distribution is permitted only in or among countries not thus
+excluded. In such case, this License incorporates the limitation as if
+written in the body of this License.
+
+ 13. The Free Software Foundation may publish revised and/or new
+versions of the Lesser General Public License from time to time.
+Such new versions will be similar in spirit to the present version,
+but may differ in detail to address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Library
+specifies a version number of this License which applies to it and
+"any later version", you have the option of following the terms and
+conditions either of that version or of any later version published by
+the Free Software Foundation. If the Library does not specify a
+license version number, you may choose any version ever published by
+the Free Software Foundation.
+
+ 14. If you wish to incorporate parts of the Library into other free
+programs whose distribution conditions are incompatible with these,
+write to the author to ask for permission. For software which is
+copyrighted by the Free Software Foundation, write to the Free
+Software Foundation; we sometimes make exceptions for this. Our
+decision will be guided by the two goals of preserving the free status
+of all derivatives of our free software and of promoting the sharing
+and reuse of software generally.
+
+ NO WARRANTY
+
+ 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
+WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
+EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
+OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
+KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
+LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
+THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
+WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
+AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
+FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
+CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
+LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
+RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
+FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
+SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
+DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Libraries
+
+ If you develop a new library, and you want it to be of the greatest
+possible use to the public, we recommend making it free software that
+everyone can redistribute and change. You can do so by permitting
+redistribution under these terms (or, alternatively, under the terms of the
+ordinary General Public License).
+
+ To apply these terms, attach the following notices to the library. It is
+safest to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least the
+"copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the library's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ This library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with this library; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+Also add information on how to contact you by electronic and paper mail.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the library, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the
+ library `Frob' (a library for tweaking knobs) written by James Random Hacker.
+
+ <signature of Ty Coon>, 1 April 1990
+ Ty Coon, President of Vice
+
+That's all there is to it!
diff --git a/DOC/installer.txt b/DOC/installer.txt
deleted file mode 100644
index 70ad7dc..0000000
--- a/DOC/installer.txt
+++ /dev/null
@@ -1,166 +0,0 @@
-7-Zip for installers 9.38
--------------------------
-
-7-Zip is a file archiver for Windows NT/2000/2003/2008/XP/Vista/7/8/10.
-
-7-Zip for installers is part of LZMA SDK.
-LZMA SDK is written and placed in the public domain by Igor Pavlov.
-
-It's allowed to join 7-Zip SFX module with another software.
-It's allowed to change resources of 7-Zip's SFX modules.
-
-
-HOW to use
------------
-
-7zr.exe is reduced version of 7za.exe of 7-Zip.
-7zr.exe supports only format with these codecs: LZMA, LZMA2, BCJ, BCJ2, ARM, Copy.
-
-Example of compressing command for installation packages:
-
-7zr a archive.7z files
-
-7zSD.sfx is SFX module for installers. 7zSD.sfx uses msvcrt.dll.
-
-SFX modules for installers allow to create installation program.
-Such module extracts archive to temp folder and then runs specified program and removes
-temp files after program finishing. Self-extract archive for installers must be created
-as joining 3 files: SFX_Module, Installer_Config, 7z_Archive.
-Installer_Config is optional file. You can use the following command to create installer
-self-extract archive:
-
-copy /b 7zSD.sfx + config.txt + archive.7z archive.exe
-
-The smallest installation package size can be achieved, if installation files was
-uncompressed before including to 7z archive.
-
--y switch for installer module (at runtime) specifies quiet mode for extracting.
-
-Installer Config file format
-~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-Config file contains commands for Installer. File begins from string
-;!@Install@!UTF-8! and ends with ;!@InstallEnd@!. File must be written
-in UTF-8 encoding. File contains string pairs:
-
-ID_String="Value"
-
-ID_String Description
-
-Title Title for messages
-BeginPrompt Begin Prompt message
-Progress Value can be "yes" or "no". Default value is "yes".
-RunProgram Command for executing. Default value is "setup.exe".
- Substring %%T will be replaced with path to temporary
- folder, where files were extracted
-Directory Directory prefix for "RunProgram". Default value is ".\\"
-ExecuteFile Name of file for executing
-ExecuteParameters Parameters for "ExecuteFile"
-
-
-You can omit any string pair.
-
-There are two ways to run program: RunProgram and ExecuteFile.
-Use RunProgram, if you want to run some program from .7z archive.
-Use ExecuteFile, if you want to open some document from .7z archive or
-if you want to execute some command from Windows.
-
-If you use RunProgram and if you specify empty directory prefix: Directory="",
-the system searches for the executable file in the following sequence:
-
-1. The directory from which the application (installer) loaded.
-2. The temporary folder, where files were extracted.
-3. The Windows system directory.
-
-
-Config file Examples
-~~~~~~~~~~~~~~~~~~~~
-
-;!@Install@!UTF-8!
-Title="7-Zip 4.00"
-BeginPrompt="Do you want to install the 7-Zip 4.00?"
-RunProgram="setup.exe"
-;!@InstallEnd@!
-
-
-
-;!@Install@!UTF-8!
-Title="7-Zip 4.00"
-BeginPrompt="Do you want to install the 7-Zip 4.00?"
-ExecuteFile="7zip.msi"
-;!@InstallEnd@!
-
-
-
-;!@Install@!UTF-8!
-Title="7-Zip 4.01 Update"
-BeginPrompt="Do you want to install the 7-Zip 4.01 Update?"
-ExecuteFile="msiexec.exe"
-ExecuteParameters="/i 7zip.msi REINSTALL=ALL REINSTALLMODE=vomus"
-;!@InstallEnd@!
-
-
-
-Small SFX modules for installers
---------------------------------
-
-7zS2.sfx - small SFX module (GUI version)
-7zS2con.sfx - small SFX module (Console version)
-
-Small SFX modules support this codecs: LZMA, LZMA2, BCJ, BCJ2, ARM, COPY
-
-Small SFX module is similar to common SFX module for installers.
-The difference (what's new in small version):
- - Smaller size (30 KB vs 100 KB)
- - C source code instead of Ñ++
- - No installer Configuration file
- - No extracting progress window
- - It decompresses solid 7z blocks (it can be whole 7z archive) to RAM.
- So user that calls SFX installer must have free RAM of size of largest
- solid 7z block (size of 7z archive at simplest case).
-
-How to use
-----------
-
-copy /b 7zS2.sfx + archive.7z sfx.exe
-
-When you run installer sfx module (sfx.exe)
-1) It creates "7zNNNNNNNN" temp folder in system temp folder.
-2) It extracts .7z archive to that folder
-3) It executes one file from "7zNNNNNNNN" temp folder.
-4) It removes "7zNNNNNNNN" temp folder
-
-You can send parameters to installer, and installer will transfer them to extracted .exe file.
-
-Small SFX uses 3 levels of priorities to select file to execute:
-
- 1) Files in root folder have higher priority than files in subfolders.
- 2) File extension priorities (from high to low priority order):
- bat, cmd, exe, inf, msi, cab (under Windows CE), html, htm
- 3) File name priorities (from high to low priority order):
- setup, install, run, start
-
-Windows CE (ARM) version of 7zS2.sfx is included to 7-Zip for Windows Mobile package.
-
-
-Examples
---------
-
-1) To create compressed console 7-Zip:
-
-7zr a c.7z 7z.exe 7z.dll -mx
-copy /b 7zS2con.sfx + c.7z 7zCompr.exe
-7zCompr.exe b -md22
-
-
-2) To create compressed GUI 7-Zip:
-
-7zr a g.7z 7zg.exe 7z.dll -mx
-copy /b 7zS2.sfx + g.7z 7zgCompr.exe
-7zgCompr.exe b -md22
-
-
-3) To open some file:
-
-7zr a h.7z readme.txt -mx
-copy /b 7zS2.sfx + h.7z 7zTxt.exe
-7zTxt.exe
diff --git a/DOC/lzma-history.txt b/DOC/lzma-history.txt
deleted file mode 100644
index 3a6f0f3..0000000
--- a/DOC/lzma-history.txt
+++ /dev/null
@@ -1,446 +0,0 @@
-HISTORY of the LZMA SDK
------------------------
-
-19.00 2019-02-21
--------------------------
-- Encryption strength for 7z archives was increased:
- the size of random initialization vector was increased from 64-bit to 128-bit,
- and the pseudo-random number generator was improved.
-- The bug in 7zIn.c code was fixed.
-
-
-18.06 2018-12-30
--------------------------
-- The speed for LZMA/LZMA2 compressing was increased by 3-10%,
- and there are minor changes in compression ratio.
-- Some bugs were fixed.
-- The bug in 7-Zip 18.02-18.05 was fixed:
- There was memory leak in multithreading xz decoder - XzDecMt_Decode(),
- if xz stream contains only one block.
-- The changes for MSVS compiler makefiles:
- - the makefiles now use "PLATFORM" macroname with values (x64, x86, arm64)
- instead of "CPU" macroname with values (AMD64, ARM64).
- - the makefiles by default now use static version of the run-time library.
-
-
-18.05 2018-04-30
--------------------------
-- The speed for LZMA/LZMA2 compressing was increased
- by 8% for fastest/fast compression levels and
- by 3% for normal/maximum compression levels.
-- Previous versions of 7-Zip could work incorrectly in "Large memory pages" mode in
- Windows 10 because of some BUG with "Large Pages" in Windows 10.
- Now 7-Zip doesn't use "Large Pages" on Windows 10 up to revision 1709 (16299).
-- The BUG was fixed in Lzma2Enc.c
- Lzma2Enc_Encode2() function worked incorretly,
- if (inStream == NULL) and the number of block threads is more than 1.
-
-
-18.03 beta 2018-03-04
--------------------------
-- Asm\x86\LzmaDecOpt.asm: new optimized LZMA decoder written in asm
- for x64 with about 30% higher speed than main version of LZMA decoder written in C.
-- The speed for single-thread LZMA/LZMA2 decoder written in C was increased by 3%.
-- 7-Zip now can use multi-threading for 7z/LZMA2 decoding,
- if there are multiple independent data chunks in LZMA2 stream.
-- 7-Zip now can use multi-threading for xz decoding,
- if there are multiple blocks in xz stream.
-
-
-18.01 2019-01-28
--------------------------
-- The BUG in 17.01 - 18.00 beta was fixed:
- XzDec.c : random block unpacking and XzUnpacker_IsBlockFinished()
- didn't work correctly for xz archives without checksum (CRC).
-
-
-18.00 beta 2019-01-10
--------------------------
-- The BUG in xz encoder was fixed:
- There was memory leak of 16 KB for each file compressed with
- xz compression method, if additional filter was used.
-
-
-17.01 beta 2017-08-28
--------------------------
-- Minor speed optimization for LZMA2 (xz and 7z) multi-threading compression.
- 7-Zip now uses additional memory buffers for multi-block LZMA2 compression.
- CPU utilization was slightly improved.
-- 7-zip now creates multi-block xz archives by default. Block size can be
- specified with -ms[Size]{m|g} switch.
-- xz decoder now can unpack random block from multi-block xz archives.
-- 7-Zip command line: @listfile now doesn't work after -- switch.
- Use -i@listfile before -- switch instead.
-- The BUGs were fixed:
- 7-Zip 17.00 beta crashed for commands that write anti-item to 7z archive.
-
-
-17.00 beta 2017-04-29
--------------------------
-- NewHandler.h / NewHandler.cpp:
- now it redefines operator new() only for old MSVC compilers (_MSC_VER < 1900).
-- C/7zTypes.h : the names of variables in interface structures were changed (vt).
-- Some bugs were fixed. 7-Zip could crash in some cases.
-- Some internal changes in code.
-
-
-16.04 2016-10-04
--------------------------
-- The bug was fixed in DllSecur.c.
-
-
-16.03 2016-09-28
--------------------------
-- SFX modules now use some protection against DLL preloading attack.
-- Some bugs in 7z code were fixed.
-
-
-16.02 2016-05-21
--------------------------
-- The BUG in 16.00 - 16.01 was fixed:
- Split Handler (SplitHandler.cpp) returned incorrect
- total size value (kpidSize) for split archives.
-
-
-16.01 2016-05-19
--------------------------
-- Some internal changes to reduce the number of compiler warnings.
-
-
-16.00 2016-05-10
--------------------------
-- Some bugs were fixed.
-
-
-15.12 2015-11-19
--------------------------
-- The BUG in C version of 7z decoder was fixed:
- 7zDec.c : SzDecodeLzma2()
- 7z decoder could mistakenly report about decoding error for some 7z archives
- that use LZMA2 compression method.
- The probability to get that mistaken decoding error report was about
- one error per 16384 solid blocks for solid blocks larger than 16 KB (compressed size).
-- The BUG (in 9.26-15.11) in C version of 7z decoder was fixed:
- 7zArcIn.c : SzReadHeader2()
- 7z decoder worked incorrectly for 7z archives that contain
- empty solid blocks, that can be placed to 7z archive, if some file is
- unavailable for reading during archive creation.
-
-
-15.09 beta 2015-10-16
--------------------------
-- The BUG in LZMA / LZMA2 encoding code was fixed.
- The BUG in LzFind.c::MatchFinder_ReadBlock() function.
- If input data size is larger than (4 GiB - dictionary_size),
- the following code worked incorrectly:
- - LZMA : LzmaEnc_MemEncode(), LzmaEncode() : LZMA encoding functions
- for compressing from memory to memory.
- That BUG is not related to LZMA encoder version that works via streams.
- - LZMA2 : multi-threaded version of LZMA2 encoder worked incorrectly, if
- default value of chunk size (CLzma2EncProps::blockSize) is changed
- to value larger than (4 GiB - dictionary_size).
-
-
-9.38 beta 2015-01-03
--------------------------
-- The BUG in 9.31-9.37 was fixed:
- IArchiveGetRawProps interface was disabled for 7z archives.
-- The BUG in 9.26-9.36 was fixed:
- Some code in CPP\7zip\Archive\7z\ worked correctly only under Windows.
-
-
-9.36 beta 2014-12-26
--------------------------
-- The BUG in command line version was fixed:
- 7-Zip created temporary archive in current folder during update archive
- operation, if -w{Path} switch was not specified.
- The fixed 7-Zip creates temporary archive in folder that contains updated archive.
-- The BUG in 9.33-9.35 was fixed:
- 7-Zip silently ignored file reading errors during 7z or gz archive creation,
- and the created archive contained only part of file that was read before error.
- The fixed 7-Zip stops archive creation and it reports about error.
-
-
-9.35 beta 2014-12-07
--------------------------
-- 7zr.exe now support AES encryption.
-- SFX mudules were added to LZMA SDK
-- Some bugs were fixed.
-
-
-9.21 beta 2011-04-11
--------------------------
-- New class FString for file names at file systems.
-- Speed optimization in CRC code for big-endian CPUs.
-- The BUG in Lzma2Dec.c was fixed:
- Lzma2Decode function didn't work.
-
-
-9.18 beta 2010-11-02
--------------------------
-- New small SFX module for installers (SfxSetup).
-
-
-9.12 beta 2010-03-24
--------------------------
-- The BUG in LZMA SDK 9.* was fixed: LZMA2 codec didn't work,
- if more than 10 threads were used (or more than 20 threads in some modes).
-
-
-9.11 beta 2010-03-15
--------------------------
-- PPMd compression method support
-
-
-9.09 2009-12-12
--------------------------
-- The bug was fixed:
- Utf16_To_Utf8 funstions in UTFConvert.cpp and 7zMain.c
- incorrectly converted surrogate characters (the code >= 0x10000) to UTF-8.
-- Some bugs were fixed
-
-
-9.06 2009-08-17
--------------------------
-- Some changes in ANSI-C 7z Decoder interfaces.
-
-
-9.04 2009-05-30
--------------------------
-- LZMA2 compression method support
-- xz format support
-
-
-4.65 2009-02-03
--------------------------
-- Some minor fixes
-
-
-4.63 2008-12-31
--------------------------
-- Some minor fixes
-
-
-4.61 beta 2008-11-23
--------------------------
-- The bug in ANSI-C LZMA Decoder was fixed:
- If encoded stream was corrupted, decoder could access memory
- outside of allocated range.
-- Some changes in ANSI-C 7z Decoder interfaces.
-- LZMA SDK is placed in the public domain.
-
-
-4.60 beta 2008-08-19
--------------------------
-- Some minor fixes.
-
-
-4.59 beta 2008-08-13
--------------------------
-- The bug was fixed:
- LZMA Encoder in fast compression mode could access memory outside of
- allocated range in some rare cases.
-
-
-4.58 beta 2008-05-05
--------------------------
-- ANSI-C LZMA Decoder was rewritten for speed optimizations.
-- ANSI-C LZMA Encoder was included to LZMA SDK.
-- C++ LZMA code now is just wrapper over ANSI-C code.
-
-
-4.57 2007-12-12
--------------------------
-- Speed optimizations in Ñ++ LZMA Decoder.
-- Small changes for more compatibility with some C/C++ compilers.
-
-
-4.49 beta 2007-07-05
--------------------------
-- .7z ANSI-C Decoder:
- - now it supports BCJ and BCJ2 filters
- - now it supports files larger than 4 GB.
- - now it supports "Last Write Time" field for files.
-- C++ code for .7z archives compressing/decompressing from 7-zip
- was included to LZMA SDK.
-
-
-4.43 2006-06-04
--------------------------
-- Small changes for more compatibility with some C/C++ compilers.
-
-
-4.42 2006-05-15
--------------------------
-- Small changes in .h files in ANSI-C version.
-
-
-4.39 beta 2006-04-14
--------------------------
-- The bug in versions 4.33b:4.38b was fixed:
- C++ version of LZMA encoder could not correctly compress
- files larger than 2 GB with HC4 match finder (-mfhc4).
-
-
-4.37 beta 2005-04-06
--------------------------
-- Fixes in C++ code: code could no be compiled if _NO_EXCEPTIONS was defined.
-
-
-4.35 beta 2005-03-02
--------------------------
-- The bug was fixed in C++ version of LZMA Decoder:
- If encoded stream was corrupted, decoder could access memory
- outside of allocated range.
-
-
-4.34 beta 2006-02-27
--------------------------
-- Compressing speed and memory requirements for compressing were increased
-- LZMA now can use only these match finders: HC4, BT2, BT3, BT4
-
-
-4.32 2005-12-09
--------------------------
-- Java version of LZMA SDK was included
-
-
-4.30 2005-11-20
--------------------------
-- Compression ratio was improved in -a2 mode
-- Speed optimizations for compressing in -a2 mode
-- -fb switch now supports values up to 273
-- The bug in 7z_C (7zIn.c) was fixed:
- It used Alloc/Free functions from different memory pools.
- So if program used two memory pools, it worked incorrectly.
-- 7z_C: .7z format supporting was improved
-- LZMA# SDK (C#.NET version) was included
-
-
-4.27 (Updated) 2005-09-21
--------------------------
-- Some GUIDs/interfaces in C++ were changed.
- IStream.h:
- ISequentialInStream::Read now works as old ReadPart
- ISequentialOutStream::Write now works as old WritePart
-
-
-4.27 2005-08-07
--------------------------
-- The bug in LzmaDecodeSize.c was fixed:
- if _LZMA_IN_CB and _LZMA_OUT_READ were defined,
- decompressing worked incorrectly.
-
-
-4.26 2005-08-05
--------------------------
-- Fixes in 7z_C code and LzmaTest.c:
- previous versions could work incorrectly,
- if malloc(0) returns 0
-
-
-4.23 2005-06-29
--------------------------
-- Small fixes in C++ code
-
-
-4.22 2005-06-10
--------------------------
-- Small fixes
-
-
-4.21 2005-06-08
--------------------------
-- Interfaces for ANSI-C LZMA Decoder (LzmaDecode.c) were changed
-- New additional version of ANSI-C LZMA Decoder with zlib-like interface:
- - LzmaStateDecode.h
- - LzmaStateDecode.c
- - LzmaStateTest.c
-- ANSI-C LZMA Decoder now can decompress files larger than 4 GB
-
-
-4.17 2005-04-18
--------------------------
-- New example for RAM->RAM compressing/decompressing:
- LZMA + BCJ (filter for x86 code):
- - LzmaRam.h
- - LzmaRam.cpp
- - LzmaRamDecode.h
- - LzmaRamDecode.c
- - -f86 switch for lzma.exe
-
-
-4.16 2005-03-29
--------------------------
-- The bug was fixed in LzmaDecode.c (ANSI-C LZMA Decoder):
- If _LZMA_OUT_READ was defined, and if encoded stream was corrupted,
- decoder could access memory outside of allocated range.
-- Speed optimization of ANSI-C LZMA Decoder (now it's about 20% faster).
- Old version of LZMA Decoder now is in file LzmaDecodeSize.c.
- LzmaDecodeSize.c can provide slightly smaller code than LzmaDecode.c
-- Small speed optimization in LZMA C++ code
-- filter for SPARC's code was added
-- Simplified version of .7z ANSI-C Decoder was included
-
-
-4.06 2004-09-05
--------------------------
-- The bug in v4.05 was fixed:
- LZMA-Encoder didn't release output stream in some cases.
-
-
-4.05 2004-08-25
--------------------------
-- Source code of filters for x86, IA-64, ARM, ARM-Thumb
- and PowerPC code was included to SDK
-- Some internal minor changes
-
-
-4.04 2004-07-28
--------------------------
-- More compatibility with some C++ compilers
-
-
-4.03 2004-06-18
--------------------------
-- "Benchmark" command was added. It measures compressing
- and decompressing speed and shows rating values.
- Also it checks hardware errors.
-
-
-4.02 2004-06-10
--------------------------
-- C++ LZMA Encoder/Decoder code now is more portable
- and it can be compiled by GCC on Linux.
-
-
-4.01 2004-02-15
--------------------------
-- Some detection of data corruption was enabled.
- LzmaDecode.c / RangeDecoderReadByte
- .....
- {
- rd->ExtraBytes = 1;
- return 0xFF;
- }
-
-
-4.00 2004-02-13
--------------------------
-- Original version of LZMA SDK
-
-
-
-HISTORY of the LZMA
--------------------
- 2001-2008: Improvements to LZMA compressing/decompressing code,
- keeping compatibility with original LZMA format
- 1996-2001: Development of LZMA compression format
-
- Some milestones:
-
- 2001-08-30: LZMA compression was added to 7-Zip
- 1999-01-02: First version of 7-Zip was released
-
-
-End of document
diff --git a/DOC/lzma-sdk.txt b/DOC/lzma-sdk.txt
deleted file mode 100644
index 1bde6db..0000000
--- a/DOC/lzma-sdk.txt
+++ /dev/null
@@ -1,357 +0,0 @@
-LZMA SDK 19.00
---------------
-
-LZMA SDK provides the documentation, samples, header files,
-libraries, and tools you need to develop applications that
-use 7z / LZMA / LZMA2 / XZ compression.
-
-LZMA is an improved version of famous LZ77 compression algorithm.
-It was improved in way of maximum increasing of compression ratio,
-keeping high decompression speed and low memory requirements for
-decompressing.
-
-LZMA2 is a LZMA based compression method. LZMA2 provides better
-multithreading support for compression than LZMA and some other improvements.
-
-7z is a file format for data compression and file archiving.
-7z is a main file format for 7-Zip compression program (www.7-zip.org).
-7z format supports different compression methods: LZMA, LZMA2 and others.
-7z also supports AES-256 based encryption.
-
-XZ is a file format for data compression that uses LZMA2 compression.
-XZ format provides additional features: SHA/CRC check, filters for
-improved compression ratio, splitting to blocks and streams,
-
-
-
-LICENSE
--------
-
-LZMA SDK is written and placed in the public domain by Igor Pavlov.
-
-Some code in LZMA SDK is based on public domain code from another developers:
- 1) PPMd var.H (2001): Dmitry Shkarin
- 2) SHA-256: Wei Dai (Crypto++ library)
-
-Anyone is free to copy, modify, publish, use, compile, sell, or distribute the
-original LZMA SDK code, either in source code form or as a compiled binary, for
-any purpose, commercial or non-commercial, and by any means.
-
-LZMA SDK code is compatible with open source licenses, for example, you can
-include it to GNU GPL or GNU LGPL code.
-
-
-LZMA SDK Contents
------------------
-
- Source code:
-
- - C / C++ / C# / Java - LZMA compression and decompression
- - C / C++ - LZMA2 compression and decompression
- - C / C++ - XZ compression and decompression
- - C - 7z decompression
- - C++ - 7z compression and decompression
- - C - small SFXs for installers (7z decompression)
- - C++ - SFXs and SFXs for installers (7z decompression)
-
- Precomiled binaries:
-
- - console programs for lzma / 7z / xz compression and decompression
- - SFX modules for installers.
-
-
-UNIX/Linux version
-------------------
-To compile C++ version of file->file LZMA encoding, go to directory
-CPP/7zip/Bundles/LzmaCon
-and call make to recompile it:
- make -f makefile.gcc clean all
-
-In some UNIX/Linux versions you must compile LZMA with static libraries.
-To compile with static libraries, you can use
-LIB = -lm -static
-
-Also you can use p7zip (port of 7-Zip for POSIX systems like Unix or Linux):
-
- http://p7zip.sourceforge.net/
-
-
-Files
------
-
-DOC/7zC.txt - 7z ANSI-C Decoder description
-DOC/7zFormat.txt - 7z Format description
-DOC/installer.txt - information about 7-Zip for installers
-DOC/lzma.txt - LZMA compression description
-DOC/lzma-sdk.txt - LZMA SDK description (this file)
-DOC/lzma-history.txt - history of LZMA SDK
-DOC/lzma-specification.txt - Specification of LZMA
-DOC/Methods.txt - Compression method IDs for .7z
-
-bin/installer/ - example script to create installer that uses SFX module,
-
-bin/7zdec.exe - simplified 7z archive decoder
-bin/7zr.exe - 7-Zip console program (reduced version)
-bin/x64/7zr.exe - 7-Zip console program (reduced version) (x64 version)
-bin/lzma.exe - file->file LZMA encoder/decoder for Windows
-bin/7zS2.sfx - small SFX module for installers (GUI version)
-bin/7zS2con.sfx - small SFX module for installers (Console version)
-bin/7zSD.sfx - SFX module for installers.
-
-
-7zDec.exe
----------
-7zDec.exe is simplified 7z archive decoder.
-It supports only LZMA, LZMA2, and PPMd methods.
-7zDec decodes whole solid block from 7z archive to RAM.
-The RAM consumption can be high.
-
-
-
-
-Source code structure
----------------------
-
-
-Asm/ - asm files (optimized code for CRC calculation and Intel-AES encryption)
-
-C/ - C files (compression / decompression and other)
- Util/
- 7z - 7z decoder program (decoding 7z files)
- Lzma - LZMA program (file->file LZMA encoder/decoder).
- LzmaLib - LZMA library (.DLL for Windows)
- SfxSetup - small SFX module for installers
-
-CPP/ -- CPP files
-
- Common - common files for C++ projects
- Windows - common files for Windows related code
-
- 7zip - files related to 7-Zip
-
- Archive - files related to archiving
-
- Common - common files for archive handling
- 7z - 7z C++ Encoder/Decoder
-
- Bundles - Modules that are bundles of other modules (files)
-
- Alone7z - 7zr.exe: Standalone 7-Zip console program (reduced version)
- Format7zExtractR - 7zxr.dll: Reduced version of 7z DLL: extracting from 7z/LZMA/BCJ/BCJ2.
- Format7zR - 7zr.dll: Reduced version of 7z DLL: extracting/compressing to 7z/LZMA/BCJ/BCJ2
- LzmaCon - lzma.exe: LZMA compression/decompression
- LzmaSpec - example code for LZMA Specification
- SFXCon - 7zCon.sfx: Console 7z SFX module
- SFXSetup - 7zS.sfx: 7z SFX module for installers
- SFXWin - 7z.sfx: GUI 7z SFX module
-
- Common - common files for 7-Zip
-
- Compress - files for compression/decompression
-
- Crypto - files for encryption / decompression
-
- UI - User Interface files
-
- Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll
- Common - Common UI files
- Console - Code for console program (7z.exe)
- Explorer - Some code from 7-Zip Shell extension
- FileManager - Some GUI code from 7-Zip File Manager
- GUI - Some GUI code from 7-Zip
-
-
-CS/ - C# files
- 7zip
- Common - some common files for 7-Zip
- Compress - files related to compression/decompression
- LZ - files related to LZ (Lempel-Ziv) compression algorithm
- LZMA - LZMA compression/decompression
- LzmaAlone - file->file LZMA compression/decompression
- RangeCoder - Range Coder (special code of compression/decompression)
-
-Java/ - Java files
- SevenZip
- Compression - files related to compression/decompression
- LZ - files related to LZ (Lempel-Ziv) compression algorithm
- LZMA - LZMA compression/decompression
- RangeCoder - Range Coder (special code of compression/decompression)
-
-
-Note:
- Asm / C / C++ source code of LZMA SDK is part of 7-Zip's source code.
- 7-Zip's source code can be downloaded from 7-Zip's SourceForge page:
-
- http://sourceforge.net/projects/sevenzip/
-
-
-
-LZMA features
--------------
- - Variable dictionary size (up to 1 GB)
- - Estimated compressing speed: about 2 MB/s on 2 GHz CPU
- - Estimated decompressing speed:
- - 20-30 MB/s on modern 2 GHz cpu
- - 1-2 MB/s on 200 MHz simple RISC cpu: (ARM, MIPS, PowerPC)
- - Small memory requirements for decompressing (16 KB + DictionarySize)
- - Small code size for decompressing: 5-8 KB
-
-LZMA decoder uses only integer operations and can be
-implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions).
-
-Some critical operations that affect the speed of LZMA decompression:
- 1) 32*16 bit integer multiply
- 2) Mispredicted branches (penalty mostly depends from pipeline length)
- 3) 32-bit shift and arithmetic operations
-
-The speed of LZMA decompressing mostly depends from CPU speed.
-Memory speed has no big meaning. But if your CPU has small data cache,
-overall weight of memory speed will slightly increase.
-
-
-How To Use
-----------
-
-Using LZMA encoder/decoder executable
---------------------------------------
-
-Usage: LZMA <e|d> inputFile outputFile [<switches>...]
-
- e: encode file
-
- d: decode file
-
- b: Benchmark. There are two tests: compressing and decompressing
- with LZMA method. Benchmark shows rating in MIPS (million
- instructions per second). Rating value is calculated from
- measured speed and it is normalized with Intel's Core 2 results.
- Also Benchmark checks possible hardware errors (RAM
- errors in most cases). Benchmark uses these settings:
- (-a1, -d21, -fb32, -mfbt4). You can change only -d parameter.
- Also you can change the number of iterations. Example for 30 iterations:
- LZMA b 30
- Default number of iterations is 10.
-
-<Switches>
-
-
- -a{N}: set compression mode 0 = fast, 1 = normal
- default: 1 (normal)
-
- d{N}: Sets Dictionary size - [0, 30], default: 23 (8MB)
- The maximum value for dictionary size is 1 GB = 2^30 bytes.
- Dictionary size is calculated as DictionarySize = 2^N bytes.
- For decompressing file compressed by LZMA method with dictionary
- size D = 2^N you need about D bytes of memory (RAM).
-
- -fb{N}: set number of fast bytes - [5, 273], default: 128
- Usually big number gives a little bit better compression ratio
- and slower compression process.
-
- -lc{N}: set number of literal context bits - [0, 8], default: 3
- Sometimes lc=4 gives gain for big files.
-
- -lp{N}: set number of literal pos bits - [0, 4], default: 0
- lp switch is intended for periodical data when period is
- equal 2^N. For example, for 32-bit (4 bytes)
- periodical data you can use lp=2. Often it's better to set lc0,
- if you change lp switch.
-
- -pb{N}: set number of pos bits - [0, 4], default: 2
- pb switch is intended for periodical data
- when period is equal 2^N.
-
- -mf{MF_ID}: set Match Finder. Default: bt4.
- Algorithms from hc* group doesn't provide good compression
- ratio, but they often works pretty fast in combination with
- fast mode (-a0).
-
- Memory requirements depend from dictionary size
- (parameter "d" in table below).
-
- MF_ID Memory Description
-
- bt2 d * 9.5 + 4MB Binary Tree with 2 bytes hashing.
- bt3 d * 11.5 + 4MB Binary Tree with 3 bytes hashing.
- bt4 d * 11.5 + 4MB Binary Tree with 4 bytes hashing.
- hc4 d * 7.5 + 4MB Hash Chain with 4 bytes hashing.
-
- -eos: write End Of Stream marker. By default LZMA doesn't write
- eos marker, since LZMA decoder knows uncompressed size
- stored in .lzma file header.
-
- -si: Read data from stdin (it will write End Of Stream marker).
- -so: Write data to stdout
-
-
-Examples:
-
-1) LZMA e file.bin file.lzma -d16 -lc0
-
-compresses file.bin to file.lzma with 64 KB dictionary (2^16=64K)
-and 0 literal context bits. -lc0 allows to reduce memory requirements
-for decompression.
-
-
-2) LZMA e file.bin file.lzma -lc0 -lp2
-
-compresses file.bin to file.lzma with settings suitable
-for 32-bit periodical data (for example, ARM or MIPS code).
-
-3) LZMA d file.lzma file.bin
-
-decompresses file.lzma to file.bin.
-
-
-Compression ratio hints
------------------------
-
-Recommendations
----------------
-
-To increase the compression ratio for LZMA compressing it's desirable
-to have aligned data (if it's possible) and also it's desirable to locate
-data in such order, where code is grouped in one place and data is
-grouped in other place (it's better than such mixing: code, data, code,
-data, ...).
-
-
-Filters
--------
-You can increase the compression ratio for some data types, using
-special filters before compressing. For example, it's possible to
-increase the compression ratio on 5-10% for code for those CPU ISAs:
-x86, IA-64, ARM, ARM-Thumb, PowerPC, SPARC.
-
-You can find C source code of such filters in C/Bra*.* files
-
-You can check the compression ratio gain of these filters with such
-7-Zip commands (example for ARM code):
-No filter:
- 7z a a1.7z a.bin -m0=lzma
-
-With filter for little-endian ARM code:
- 7z a a2.7z a.bin -m0=arm -m1=lzma
-
-It works in such manner:
-Compressing = Filter_encoding + LZMA_encoding
-Decompressing = LZMA_decoding + Filter_decoding
-
-Compressing and decompressing speed of such filters is very high,
-so it will not increase decompressing time too much.
-Moreover, it reduces decompression time for LZMA_decoding,
-since compression ratio with filtering is higher.
-
-These filters convert CALL (calling procedure) instructions
-from relative offsets to absolute addresses, so such data becomes more
-compressible.
-
-For some ISAs (for example, for MIPS) it's impossible to get gain from such filter.
-
-
-
----
-
-http://www.7-zip.org
-http://www.7-zip.org/sdk.html
-http://www.7-zip.org/support.html
diff --git a/DOC/lzma-specification.txt b/DOC/lzma-specification.txt
deleted file mode 100644
index b6796df..0000000
--- a/DOC/lzma-specification.txt
+++ /dev/null
@@ -1,1176 +0,0 @@
-LZMA specification (DRAFT version)
-----------------------------------
-
-Author: Igor Pavlov
-Date: 2015-06-14
-
-This specification defines the format of LZMA compressed data and lzma file format.
-
-Notation
---------
-
-We use the syntax of C++ programming language.
-We use the following types in C++ code:
- unsigned - unsigned integer, at least 16 bits in size
- int - signed integer, at least 16 bits in size
- UInt64 - 64-bit unsigned integer
- UInt32 - 32-bit unsigned integer
- UInt16 - 16-bit unsigned integer
- Byte - 8-bit unsigned integer
- bool - boolean type with two possible values: false, true
-
-
-lzma file format
-================
-
-The lzma file contains the raw LZMA stream and the header with related properties.
-
-The files in that format use ".lzma" extension.
-
-The lzma file format layout:
-
-Offset Size Description
-
- 0 1 LZMA model properties (lc, lp, pb) in encoded form
- 1 4 Dictionary size (32-bit unsigned integer, little-endian)
- 5 8 Uncompressed size (64-bit unsigned integer, little-endian)
- 13 Compressed data (LZMA stream)
-
-LZMA properties:
-
- name Range Description
-
- lc [0, 8] the number of "literal context" bits
- lp [0, 4] the number of "literal pos" bits
- pb [0, 4] the number of "pos" bits
-dictSize [0, 2^32 - 1] the dictionary size
-
-The following code encodes LZMA properties:
-
-void EncodeProperties(Byte *properties)
-{
- properties[0] = (Byte)((pb * 5 + lp) * 9 + lc);
- Set_UInt32_LittleEndian(properties + 1, dictSize);
-}
-
-If the value of dictionary size in properties is smaller than (1 << 12),
-the LZMA decoder must set the dictionary size variable to (1 << 12).
-
-#define LZMA_DIC_MIN (1 << 12)
-
- unsigned lc, pb, lp;
- UInt32 dictSize;
- UInt32 dictSizeInProperties;
-
- void DecodeProperties(const Byte *properties)
- {
- unsigned d = properties[0];
- if (d >= (9 * 5 * 5))
- throw "Incorrect LZMA properties";
- lc = d % 9;
- d /= 9;
- pb = d / 5;
- lp = d % 5;
- dictSizeInProperties = 0;
- for (int i = 0; i < 4; i++)
- dictSizeInProperties |= (UInt32)properties[i + 1] << (8 * i);
- dictSize = dictSizeInProperties;
- if (dictSize < LZMA_DIC_MIN)
- dictSize = LZMA_DIC_MIN;
- }
-
-If "Uncompressed size" field contains ones in all 64 bits, it means that
-uncompressed size is unknown and there is the "end marker" in stream,
-that indicates the end of decoding point.
-In opposite case, if the value from "Uncompressed size" field is not
-equal to ((2^64) - 1), the LZMA stream decoding must be finished after
-specified number of bytes (Uncompressed size) is decoded. And if there
-is the "end marker", the LZMA decoder must read that marker also.
-
-
-The new scheme to encode LZMA properties
-----------------------------------------
-
-If LZMA compression is used for some another format, it's recommended to
-use a new improved scheme to encode LZMA properties. That new scheme was
-used in xz format that uses the LZMA2 compression algorithm.
-The LZMA2 is a new compression algorithm that is based on the LZMA algorithm.
-
-The dictionary size in LZMA2 is encoded with just one byte and LZMA2 supports
-only reduced set of dictionary sizes:
- (2 << 11), (3 << 11),
- (2 << 12), (3 << 12),
- ...
- (2 << 30), (3 << 30),
- (2 << 31) - 1
-
-The dictionary size can be extracted from encoded value with the following code:
-
- dictSize = (p == 40) ? 0xFFFFFFFF : (((UInt32)2 | ((p) & 1)) << ((p) / 2 + 11));
-
-Also there is additional limitation (lc + lp <= 4) in LZMA2 for values of
-"lc" and "lp" properties:
-
- if (lc + lp > 4)
- throw "Unsupported properties: (lc + lp) > 4";
-
-There are some advantages for LZMA decoder with such (lc + lp) value
-limitation. It reduces the maximum size of tables allocated by decoder.
-And it reduces the complexity of initialization procedure, that can be
-important to keep high speed of decoding of big number of small LZMA streams.
-
-It's recommended to use that limitation (lc + lp <= 4) for any new format
-that uses LZMA compression. Note that the combinations of "lc" and "lp"
-parameters, where (lc + lp > 4), can provide significant improvement in
-compression ratio only in some rare cases.
-
-The LZMA properties can be encoded into two bytes in new scheme:
-
-Offset Size Description
-
- 0 1 The dictionary size encoded with LZMA2 scheme
- 1 1 LZMA model properties (lc, lp, pb) in encoded form
-
-
-The RAM usage
-=============
-
-The RAM usage for LZMA decoder is determined by the following parts:
-
-1) The Sliding Window (from 4 KiB to 4 GiB).
-2) The probability model counter arrays (arrays of 16-bit variables).
-3) Some additional state variables (about 10 variables of 32-bit integers).
-
-
-The RAM usage for Sliding Window
---------------------------------
-
-There are two main scenarios of decoding:
-
-1) The decoding of full stream to one RAM buffer.
-
- If we decode full LZMA stream to one output buffer in RAM, the decoder
- can use that output buffer as sliding window. So the decoder doesn't
- need additional buffer allocated for sliding window.
-
-2) The decoding to some external storage.
-
- If we decode LZMA stream to external storage, the decoder must allocate
- the buffer for sliding window. The size of that buffer must be equal
- or larger than the value of dictionary size from properties of LZMA stream.
-
-In this specification we describe the code for decoding to some external
-storage. The optimized version of code for decoding of full stream to one
-output RAM buffer can require some minor changes in code.
-
-
-The RAM usage for the probability model counters
-------------------------------------------------
-
-The size of the probability model counter arrays is calculated with the
-following formula:
-
-size_of_prob_arrays = 1846 + 768 * (1 << (lp + lc))
-
-Each probability model counter is 11-bit unsigned integer.
-If we use 16-bit integer variables (2-byte integers) for these probability
-model counters, the RAM usage required by probability model counter arrays
-can be estimated with the following formula:
-
- RAM = 4 KiB + 1.5 KiB * (1 << (lp + lc))
-
-For example, for default LZMA parameters (lp = 0 and lc = 3), the RAM usage is
-
- RAM_lc3_lp0 = 4 KiB + 1.5 KiB * 8 = 16 KiB
-
-The maximum RAM state usage is required for decoding the stream with lp = 4
-and lc = 8:
-
- RAM_lc8_lp4 = 4 KiB + 1.5 KiB * 4096 = 6148 KiB
-
-If the decoder uses LZMA2's limited property condition
-(lc + lp <= 4), the RAM usage will be not larger than
-
- RAM_lc_lp_4 = 4 KiB + 1.5 KiB * 16 = 28 KiB
-
-
-The RAM usage for encoder
--------------------------
-
-There are many variants for LZMA encoding code.
-These variants have different values for memory consumption.
-Note that memory consumption for LZMA Encoder can not be
-smaller than memory consumption of LZMA Decoder for same stream.
-
-The RAM usage required by modern effective implementation of
-LZMA Encoder can be estimated with the following formula:
-
- Encoder_RAM_Usage = 4 MiB + 11 * dictionarySize.
-
-But there are some modes of the encoder that require less memory.
-
-
-LZMA Decoding
-=============
-
-The LZMA compression algorithm uses LZ-based compression with Sliding Window
-and Range Encoding as entropy coding method.
-
-
-Sliding Window
---------------
-
-LZMA uses Sliding Window compression similar to LZ77 algorithm.
-
-LZMA stream must be decoded to the sequence that consists
-of MATCHES and LITERALS:
-
- - a LITERAL is a 8-bit character (one byte).
- The decoder just puts that LITERAL to the uncompressed stream.
-
- - a MATCH is a pair of two numbers (DISTANCE-LENGTH pair).
- The decoder takes one byte exactly "DISTANCE" characters behind
- current position in the uncompressed stream and puts it to
- uncompressed stream. The decoder must repeat it "LENGTH" times.
-
-The "DISTANCE" can not be larger than dictionary size.
-And the "DISTANCE" can not be larger than the number of bytes in
-the uncompressed stream that were decoded before that match.
-
-In this specification we use cyclic buffer to implement Sliding Window
-for LZMA decoder:
-
-class COutWindow
-{
- Byte *Buf;
- UInt32 Pos;
- UInt32 Size;
- bool IsFull;
-
-public:
- unsigned TotalPos;
- COutStream OutStream;
-
- COutWindow(): Buf(NULL) {}
- ~COutWindow() { delete []Buf; }
-
- void Create(UInt32 dictSize)
- {
- Buf = new Byte[dictSize];
- Pos = 0;
- Size = dictSize;
- IsFull = false;
- TotalPos = 0;
- }
-
- void PutByte(Byte b)
- {
- TotalPos++;
- Buf[Pos++] = b;
- if (Pos == Size)
- {
- Pos = 0;
- IsFull = true;
- }
- OutStream.WriteByte(b);
- }
-
- Byte GetByte(UInt32 dist) const
- {
- return Buf[dist <= Pos ? Pos - dist : Size - dist + Pos];
- }
-
- void CopyMatch(UInt32 dist, unsigned len)
- {
- for (; len > 0; len--)
- PutByte(GetByte(dist));
- }
-
- bool CheckDistance(UInt32 dist) const
- {
- return dist <= Pos || IsFull;
- }
-
- bool IsEmpty() const
- {
- return Pos == 0 && !IsFull;
- }
-};
-
-
-In another implementation it's possible to use one buffer that contains
-Sliding Window and the whole data stream after uncompressing.
-
-
-Range Decoder
--------------
-
-LZMA algorithm uses Range Encoding (1) as entropy coding method.
-
-LZMA stream contains just one very big number in big-endian encoding.
-LZMA decoder uses the Range Decoder to extract a sequence of binary
-symbols from that big number.
-
-The state of the Range Decoder:
-
-struct CRangeDecoder
-{
- UInt32 Range;
- UInt32 Code;
- InputStream *InStream;
-
- bool Corrupted;
-}
-
-The notes about UInt32 type for the "Range" and "Code" variables:
-
- It's possible to use 64-bit (unsigned or signed) integer type
- for the "Range" and the "Code" variables instead of 32-bit unsigned,
- but some additional code must be used to truncate the values to
- low 32-bits after some operations.
-
- If the programming language does not support 32-bit unsigned integer type
- (like in case of JAVA language), it's possible to use 32-bit signed integer,
- but some code must be changed. For example, it's required to change the code
- that uses comparison operations for UInt32 variables in this specification.
-
-The Range Decoder can be in some states that can be treated as
-"Corruption" in LZMA stream. The Range Decoder uses the variable "Corrupted":
-
- (Corrupted == false), if the Range Decoder has not detected any corruption.
- (Corrupted == true), if the Range Decoder has detected some corruption.
-
-The reference LZMA Decoder ignores the value of the "Corrupted" variable.
-So it continues to decode the stream, even if the corruption can be detected
-in the Range Decoder. To provide the full compatibility with output of the
-reference LZMA Decoder, another LZMA Decoder implementations must also
-ignore the value of the "Corrupted" variable.
-
-The LZMA Encoder is required to create only such LZMA streams, that will not
-lead the Range Decoder to states, where the "Corrupted" variable is set to true.
-
-The Range Decoder reads first 5 bytes from input stream to initialize
-the state:
-
-bool CRangeDecoder::Init()
-{
- Corrupted = false;
- Range = 0xFFFFFFFF;
- Code = 0;
-
- Byte b = InStream->ReadByte();
-
- for (int i = 0; i < 4; i++)
- Code = (Code << 8) | InStream->ReadByte();
-
- if (b != 0 || Code == Range)
- Corrupted = true;
- return b == 0;
-}
-
-The LZMA Encoder always writes ZERO in initial byte of compressed stream.
-That scheme allows to simplify the code of the Range Encoder in the
-LZMA Encoder. If initial byte is not equal to ZERO, the LZMA Decoder must
-stop decoding and report error.
-
-After the last bit of data was decoded by Range Decoder, the value of the
-"Code" variable must be equal to 0. The LZMA Decoder must check it by
-calling the IsFinishedOK() function:
-
- bool IsFinishedOK() const { return Code == 0; }
-
-If there is corruption in data stream, there is big probability that
-the "Code" value will be not equal to 0 in the Finish() function. So that
-check in the IsFinishedOK() function provides very good feature for
-corruption detection.
-
-The value of the "Range" variable before each bit decoding can not be smaller
-than ((UInt32)1 << 24). The Normalize() function keeps the "Range" value in
-described range.
-
-#define kTopValue ((UInt32)1 << 24)
-
-void CRangeDecoder::Normalize()
-{
- if (Range < kTopValue)
- {
- Range <<= 8;
- Code = (Code << 8) | InStream->ReadByte();
- }
-}
-
-Notes: if the size of the "Code" variable is larger than 32 bits, it's
-required to keep only low 32 bits of the "Code" variable after the change
-in Normalize() function.
-
-If the LZMA Stream is not corrupted, the value of the "Code" variable is
-always smaller than value of the "Range" variable.
-But the Range Decoder ignores some types of corruptions, so the value of
-the "Code" variable can be equal or larger than value of the "Range" variable
-for some "Corrupted" archives.
-
-
-LZMA uses Range Encoding only with binary symbols of two types:
- 1) binary symbols with fixed and equal probabilities (direct bits)
- 2) binary symbols with predicted probabilities
-
-The DecodeDirectBits() function decodes the sequence of direct bits:
-
-UInt32 CRangeDecoder::DecodeDirectBits(unsigned numBits)
-{
- UInt32 res = 0;
- do
- {
- Range >>= 1;
- Code -= Range;
- UInt32 t = 0 - ((UInt32)Code >> 31);
- Code += Range & t;
-
- if (Code == Range)
- Corrupted = true;
-
- Normalize();
- res <<= 1;
- res += t + 1;
- }
- while (--numBits);
- return res;
-}
-
-
-The Bit Decoding with Probability Model
----------------------------------------
-
-The task of Bit Probability Model is to estimate probabilities of binary
-symbols. And then it provides the Range Decoder with that information.
-The better prediction provides better compression ratio.
-The Bit Probability Model uses statistical data of previous decoded
-symbols.
-
-That estimated probability is presented as 11-bit unsigned integer value
-that represents the probability of symbol "0".
-
-#define kNumBitModelTotalBits 11
-
-Mathematical probabilities can be presented with the following formulas:
- probability(symbol_0) = prob / 2048.
- probability(symbol_1) = 1 - Probability(symbol_0) =
- = 1 - prob / 2048 =
- = (2048 - prob) / 2048
-where the "prob" variable contains 11-bit integer probability counter.
-
-It's recommended to use 16-bit unsigned integer type, to store these 11-bit
-probability values:
-
-typedef UInt16 CProb;
-
-Each probability value must be initialized with value ((1 << 11) / 2),
-that represents the state, where probabilities of symbols 0 and 1
-are equal to 0.5:
-
-#define PROB_INIT_VAL ((1 << kNumBitModelTotalBits) / 2)
-
-The INIT_PROBS macro is used to initialize the array of CProb variables:
-
-#define INIT_PROBS(p) \
- { for (unsigned i = 0; i < sizeof(p) / sizeof(p[0]); i++) p[i] = PROB_INIT_VAL; }
-
-
-The DecodeBit() function decodes one bit.
-The LZMA decoder provides the pointer to CProb variable that contains
-information about estimated probability for symbol 0 and the Range Decoder
-updates that CProb variable after decoding. The Range Decoder increases
-estimated probability of the symbol that was decoded:
-
-#define kNumMoveBits 5
-
-unsigned CRangeDecoder::DecodeBit(CProb *prob)
-{
- unsigned v = *prob;
- UInt32 bound = (Range >> kNumBitModelTotalBits) * v;
- unsigned symbol;
- if (Code < bound)
- {
- v += ((1 << kNumBitModelTotalBits) - v) >> kNumMoveBits;
- Range = bound;
- symbol = 0;
- }
- else
- {
- v -= v >> kNumMoveBits;
- Code -= bound;
- Range -= bound;
- symbol = 1;
- }
- *prob = (CProb)v;
- Normalize();
- return symbol;
-}
-
-
-The Binary Tree of bit model counters
--------------------------------------
-
-LZMA uses a tree of Bit model variables to decode symbol that needs
-several bits for storing. There are two versions of such trees in LZMA:
- 1) the tree that decodes bits from high bit to low bit (the normal scheme).
- 2) the tree that decodes bits from low bit to high bit (the reverse scheme).
-
-Each binary tree structure supports different size of decoded symbol
-(the size of binary sequence that contains value of symbol).
-If that size of decoded symbol is "NumBits" bits, the tree structure
-uses the array of (2 << NumBits) counters of CProb type.
-But only ((2 << NumBits) - 1) items are used by encoder and decoder.
-The first item (the item with index equal to 0) in array is unused.
-That scheme with unused array's item allows to simplify the code.
-
-unsigned BitTreeReverseDecode(CProb *probs, unsigned numBits, CRangeDecoder *rc)
-{
- unsigned m = 1;
- unsigned symbol = 0;
- for (unsigned i = 0; i < numBits; i++)
- {
- unsigned bit = rc->DecodeBit(&probs[m]);
- m <<= 1;
- m += bit;
- symbol |= (bit << i);
- }
- return symbol;
-}
-
-template <unsigned NumBits>
-class CBitTreeDecoder
-{
- CProb Probs[(unsigned)1 << NumBits];
-
-public:
-
- void Init()
- {
- INIT_PROBS(Probs);
- }
-
- unsigned Decode(CRangeDecoder *rc)
- {
- unsigned m = 1;
- for (unsigned i = 0; i < NumBits; i++)
- m = (m << 1) + rc->DecodeBit(&Probs[m]);
- return m - ((unsigned)1 << NumBits);
- }
-
- unsigned ReverseDecode(CRangeDecoder *rc)
- {
- return BitTreeReverseDecode(Probs, NumBits, rc);
- }
-};
-
-
-LZ part of LZMA
----------------
-
-LZ part of LZMA describes details about the decoding of MATCHES and LITERALS.
-
-
-The Literal Decoding
---------------------
-
-The LZMA Decoder uses (1 << (lc + lp)) tables with CProb values, where
-each table contains 0x300 CProb values:
-
- CProb *LitProbs;
-
- void CreateLiterals()
- {
- LitProbs = new CProb[(UInt32)0x300 << (lc + lp)];
- }
-
- void InitLiterals()
- {
- UInt32 num = (UInt32)0x300 << (lc + lp);
- for (UInt32 i = 0; i < num; i++)
- LitProbs[i] = PROB_INIT_VAL;
- }
-
-To select the table for decoding it uses the context that consists of
-(lc) high bits from previous literal and (lp) low bits from value that
-represents current position in outputStream.
-
-If (State > 7), the Literal Decoder also uses "matchByte" that represents
-the byte in OutputStream at position the is the DISTANCE bytes before
-current position, where the DISTANCE is the distance in DISTANCE-LENGTH pair
-of latest decoded match.
-
-The following code decodes one literal and puts it to Sliding Window buffer:
-
- void DecodeLiteral(unsigned state, UInt32 rep0)
- {
- unsigned prevByte = 0;
- if (!OutWindow.IsEmpty())
- prevByte = OutWindow.GetByte(1);
-
- unsigned symbol = 1;
- unsigned litState = ((OutWindow.TotalPos & ((1 << lp) - 1)) << lc) + (prevByte >> (8 - lc));
- CProb *probs = &LitProbs[(UInt32)0x300 * litState];
-
- if (state >= 7)
- {
- unsigned matchByte = OutWindow.GetByte(rep0 + 1);
- do
- {
- unsigned matchBit = (matchByte >> 7) & 1;
- matchByte <<= 1;
- unsigned bit = RangeDec.DecodeBit(&probs[((1 + matchBit) << 8) + symbol]);
- symbol = (symbol << 1) | bit;
- if (matchBit != bit)
- break;
- }
- while (symbol < 0x100);
- }
- while (symbol < 0x100)
- symbol = (symbol << 1) | RangeDec.DecodeBit(&probs[symbol]);
- OutWindow.PutByte((Byte)(symbol - 0x100));
- }
-
-
-The match length decoding
--------------------------
-
-The match length decoder returns normalized (zero-based value)
-length of match. That value can be converted to real length of the match
-with the following code:
-
-#define kMatchMinLen 2
-
- matchLen = len + kMatchMinLen;
-
-The match length decoder can return the values from 0 to 271.
-And the corresponded real match length values can be in the range
-from 2 to 273.
-
-The following scheme is used for the match length encoding:
-
- Binary encoding Binary Tree structure Zero-based match length
- sequence (binary + decimal):
-
- 0 xxx LowCoder[posState] xxx
- 1 0 yyy MidCoder[posState] yyy + 8
- 1 1 zzzzzzzz HighCoder zzzzzzzz + 16
-
-LZMA uses bit model variable "Choice" to decode the first selection bit.
-
-If the first selection bit is equal to 0, the decoder uses binary tree
- LowCoder[posState] to decode 3-bit zero-based match length (xxx).
-
-If the first selection bit is equal to 1, the decoder uses bit model
- variable "Choice2" to decode the second selection bit.
-
- If the second selection bit is equal to 0, the decoder uses binary tree
- MidCoder[posState] to decode 3-bit "yyy" value, and zero-based match
- length is equal to (yyy + 8).
-
- If the second selection bit is equal to 1, the decoder uses binary tree
- HighCoder to decode 8-bit "zzzzzzzz" value, and zero-based
- match length is equal to (zzzzzzzz + 16).
-
-LZMA uses "posState" value as context to select the binary tree
-from LowCoder and MidCoder binary tree arrays:
-
- unsigned posState = OutWindow.TotalPos & ((1 << pb) - 1);
-
-The full code of the length decoder:
-
-class CLenDecoder
-{
- CProb Choice;
- CProb Choice2;
- CBitTreeDecoder<3> LowCoder[1 << kNumPosBitsMax];
- CBitTreeDecoder<3> MidCoder[1 << kNumPosBitsMax];
- CBitTreeDecoder<8> HighCoder;
-
-public:
-
- void Init()
- {
- Choice = PROB_INIT_VAL;
- Choice2 = PROB_INIT_VAL;
- HighCoder.Init();
- for (unsigned i = 0; i < (1 << kNumPosBitsMax); i++)
- {
- LowCoder[i].Init();
- MidCoder[i].Init();
- }
- }
-
- unsigned Decode(CRangeDecoder *rc, unsigned posState)
- {
- if (rc->DecodeBit(&Choice) == 0)
- return LowCoder[posState].Decode(rc);
- if (rc->DecodeBit(&Choice2) == 0)
- return 8 + MidCoder[posState].Decode(rc);
- return 16 + HighCoder.Decode(rc);
- }
-};
-
-The LZMA decoder uses two instances of CLenDecoder class.
-The first instance is for the matches of "Simple Match" type,
-and the second instance is for the matches of "Rep Match" type:
-
- CLenDecoder LenDecoder;
- CLenDecoder RepLenDecoder;
-
-
-The match distance decoding
----------------------------
-
-LZMA supports dictionary sizes up to 4 GiB minus 1.
-The value of match distance (decoded by distance decoder) can be
-from 1 to 2^32. But the distance value that is equal to 2^32 is used to
-indicate the "End of stream" marker. So real largest match distance
-that is used for LZ-window match is (2^32 - 1).
-
-LZMA uses normalized match length (zero-based length)
-to calculate the context state "lenState" do decode the distance value:
-
-#define kNumLenToPosStates 4
-
- unsigned lenState = len;
- if (lenState > kNumLenToPosStates - 1)
- lenState = kNumLenToPosStates - 1;
-
-The distance decoder returns the "dist" value that is zero-based value
-of match distance. The real match distance can be calculated with the
-following code:
-
- matchDistance = dist + 1;
-
-The state of the distance decoder and the initialization code:
-
- #define kEndPosModelIndex 14
- #define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
- #define kNumAlignBits 4
-
- CBitTreeDecoder<6> PosSlotDecoder[kNumLenToPosStates];
- CProb PosDecoders[1 + kNumFullDistances - kEndPosModelIndex];
- CBitTreeDecoder<kNumAlignBits> AlignDecoder;
-
- void InitDist()
- {
- for (unsigned i = 0; i < kNumLenToPosStates; i++)
- PosSlotDecoder[i].Init();
- AlignDecoder.Init();
- INIT_PROBS(PosDecoders);
- }
-
-At first stage the distance decoder decodes 6-bit "posSlot" value with bit
-tree decoder from PosSlotDecoder array. It's possible to get 2^6=64 different
-"posSlot" values.
-
- unsigned posSlot = PosSlotDecoder[lenState].Decode(&RangeDec);
-
-The encoding scheme for distance value is shown in the following table:
-
-posSlot (decimal) /
- zero-based distance (binary)
- 0 0
- 1 1
- 2 10
- 3 11
-
- 4 10 x
- 5 11 x
- 6 10 xx
- 7 11 xx
- 8 10 xxx
- 9 11 xxx
-10 10 xxxx
-11 11 xxxx
-12 10 xxxxx
-13 11 xxxxx
-
-14 10 yy zzzz
-15 11 yy zzzz
-16 10 yyy zzzz
-17 11 yyy zzzz
-...
-62 10 yyyyyyyyyyyyyyyyyyyyyyyyyy zzzz
-63 11 yyyyyyyyyyyyyyyyyyyyyyyyyy zzzz
-
-where
- "x ... x" means the sequence of binary symbols encoded with binary tree and
- "Reverse" scheme. It uses separated binary tree for each posSlot from 4 to 13.
- "y" means direct bit encoded with range coder.
- "zzzz" means the sequence of four binary symbols encoded with binary
- tree with "Reverse" scheme, where one common binary tree "AlignDecoder"
- is used for all posSlot values.
-
-If (posSlot < 4), the "dist" value is equal to posSlot value.
-
-If (posSlot >= 4), the decoder uses "posSlot" value to calculate the value of
- the high bits of "dist" value and the number of the low bits.
-
- If (4 <= posSlot < kEndPosModelIndex), the decoder uses bit tree decoders.
- (one separated bit tree decoder per one posSlot value) and "Reverse" scheme.
- In this implementation we use one CProb array "PosDecoders" that contains
- all CProb variables for all these bit decoders.
-
- if (posSlot >= kEndPosModelIndex), the middle bits are decoded as direct
- bits from RangeDecoder and the low 4 bits are decoded with a bit tree
- decoder "AlignDecoder" with "Reverse" scheme.
-
-The code to decode zero-based match distance:
-
- unsigned DecodeDistance(unsigned len)
- {
- unsigned lenState = len;
- if (lenState > kNumLenToPosStates - 1)
- lenState = kNumLenToPosStates - 1;
-
- unsigned posSlot = PosSlotDecoder[lenState].Decode(&RangeDec);
- if (posSlot < 4)
- return posSlot;
-
- unsigned numDirectBits = (unsigned)((posSlot >> 1) - 1);
- UInt32 dist = ((2 | (posSlot & 1)) << numDirectBits);
- if (posSlot < kEndPosModelIndex)
- dist += BitTreeReverseDecode(PosDecoders + dist - posSlot, numDirectBits, &RangeDec);
- else
- {
- dist += RangeDec.DecodeDirectBits(numDirectBits - kNumAlignBits) << kNumAlignBits;
- dist += AlignDecoder.ReverseDecode(&RangeDec);
- }
- return dist;
- }
-
-
-
-LZMA Decoding modes
--------------------
-
-There are 2 types of LZMA streams:
-
-1) The stream with "End of stream" marker.
-2) The stream without "End of stream" marker.
-
-And the LZMA Decoder supports 3 modes of decoding:
-
-1) The unpack size is undefined. The LZMA decoder stops decoding after
- getting "End of stream" marker.
- The input variables for that case:
-
- markerIsMandatory = true
- unpackSizeDefined = false
- unpackSize contains any value
-
-2) The unpack size is defined and LZMA decoder supports both variants,
- where the stream can contain "End of stream" marker or the stream is
- finished without "End of stream" marker. The LZMA decoder must detect
- any of these situations.
- The input variables for that case:
-
- markerIsMandatory = false
- unpackSizeDefined = true
- unpackSize contains unpack size
-
-3) The unpack size is defined and the LZMA stream must contain
- "End of stream" marker
- The input variables for that case:
-
- markerIsMandatory = true
- unpackSizeDefined = true
- unpackSize contains unpack size
-
-
-The main loop of decoder
-------------------------
-
-The main loop of LZMA decoder:
-
-Initialize the LZMA state.
-loop
-{
- // begin of loop
- Check "end of stream" conditions.
- Decode Type of MATCH / LITERAL.
- If it's LITERAL, decode LITERAL value and put the LITERAL to Window.
- If it's MATCH, decode the length of match and the match distance.
- Check error conditions, check end of stream conditions and copy
- the sequence of match bytes from sliding window to current position
- in window.
- Go to begin of loop
-}
-
-The reference implementation of LZMA decoder uses "unpackSize" variable
-to keep the number of remaining bytes in output stream. So it reduces
-"unpackSize" value after each decoded LITERAL or MATCH.
-
-The following code contains the "end of stream" condition check at the start
-of the loop:
-
- if (unpackSizeDefined && unpackSize == 0 && !markerIsMandatory)
- if (RangeDec.IsFinishedOK())
- return LZMA_RES_FINISHED_WITHOUT_MARKER;
-
-LZMA uses three types of matches:
-
-1) "Simple Match" - the match with distance value encoded with bit models.
-
-2) "Rep Match" - the match that uses the distance from distance
- history table.
-
-3) "Short Rep Match" - the match of single byte length, that uses the latest
- distance from distance history table.
-
-The LZMA decoder keeps the history of latest 4 match distances that were used
-by decoder. That set of 4 variables contains zero-based match distances and
-these variables are initialized with zero values:
-
- UInt32 rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;
-
-The LZMA decoder uses binary model variables to select type of MATCH or LITERAL:
-
-#define kNumStates 12
-#define kNumPosBitsMax 4
-
- CProb IsMatch[kNumStates << kNumPosBitsMax];
- CProb IsRep[kNumStates];
- CProb IsRepG0[kNumStates];
- CProb IsRepG1[kNumStates];
- CProb IsRepG2[kNumStates];
- CProb IsRep0Long[kNumStates << kNumPosBitsMax];
-
-The decoder uses "state" variable value to select exact variable
-from "IsRep", "IsRepG0", "IsRepG1" and "IsRepG2" arrays.
-The "state" variable can get the value from 0 to 11.
-Initial value for "state" variable is zero:
-
- unsigned state = 0;
-
-The "state" variable is updated after each LITERAL or MATCH with one of the
-following functions:
-
-unsigned UpdateState_Literal(unsigned state)
-{
- if (state < 4) return 0;
- else if (state < 10) return state - 3;
- else return state - 6;
-}
-unsigned UpdateState_Match (unsigned state) { return state < 7 ? 7 : 10; }
-unsigned UpdateState_Rep (unsigned state) { return state < 7 ? 8 : 11; }
-unsigned UpdateState_ShortRep(unsigned state) { return state < 7 ? 9 : 11; }
-
-The decoder calculates "state2" variable value to select exact variable from
-"IsMatch" and "IsRep0Long" arrays:
-
-unsigned posState = OutWindow.TotalPos & ((1 << pb) - 1);
-unsigned state2 = (state << kNumPosBitsMax) + posState;
-
-The decoder uses the following code flow scheme to select exact
-type of LITERAL or MATCH:
-
-IsMatch[state2] decode
- 0 - the Literal
- 1 - the Match
- IsRep[state] decode
- 0 - Simple Match
- 1 - Rep Match
- IsRepG0[state] decode
- 0 - the distance is rep0
- IsRep0Long[state2] decode
- 0 - Short Rep Match
- 1 - Rep Match 0
- 1 -
- IsRepG1[state] decode
- 0 - Rep Match 1
- 1 -
- IsRepG2[state] decode
- 0 - Rep Match 2
- 1 - Rep Match 3
-
-
-LITERAL symbol
---------------
-If the value "0" was decoded with IsMatch[state2] decoding, we have "LITERAL" type.
-
-At first the LZMA decoder must check that it doesn't exceed
-specified uncompressed size:
-
- if (unpackSizeDefined && unpackSize == 0)
- return LZMA_RES_ERROR;
-
-Then it decodes literal value and puts it to sliding window:
-
- DecodeLiteral(state, rep0);
-
-Then the decoder must update the "state" value and "unpackSize" value;
-
- state = UpdateState_Literal(state);
- unpackSize--;
-
-Then the decoder must go to the begin of main loop to decode next Match or Literal.
-
-
-Simple Match
-------------
-
-If the value "1" was decoded with IsMatch[state2] decoding,
-we have the "Simple Match" type.
-
-The distance history table is updated with the following scheme:
-
- rep3 = rep2;
- rep2 = rep1;
- rep1 = rep0;
-
-The zero-based length is decoded with "LenDecoder":
-
- len = LenDecoder.Decode(&RangeDec, posState);
-
-The state is update with UpdateState_Match function:
-
- state = UpdateState_Match(state);
-
-and the new "rep0" value is decoded with DecodeDistance:
-
- rep0 = DecodeDistance(len);
-
-That "rep0" will be used as zero-based distance for current match.
-
-If the value of "rep0" is equal to 0xFFFFFFFF, it means that we have
-"End of stream" marker, so we can stop decoding and check finishing
-condition in Range Decoder:
-
- if (rep0 == 0xFFFFFFFF)
- return RangeDec.IsFinishedOK() ?
- LZMA_RES_FINISHED_WITH_MARKER :
- LZMA_RES_ERROR;
-
-If uncompressed size is defined, LZMA decoder must check that it doesn't
-exceed that specified uncompressed size:
-
- if (unpackSizeDefined && unpackSize == 0)
- return LZMA_RES_ERROR;
-
-Also the decoder must check that "rep0" value is not larger than dictionary size
-and is not larger than the number of already decoded bytes:
-
- if (rep0 >= dictSize || !OutWindow.CheckDistance(rep0))
- return LZMA_RES_ERROR;
-
-Then the decoder must copy match bytes as described in
-"The match symbols copying" section.
-
-
-Rep Match
----------
-
-If the LZMA decoder has decoded the value "1" with IsRep[state] variable,
-we have "Rep Match" type.
-
-At first the LZMA decoder must check that it doesn't exceed
-specified uncompressed size:
-
- if (unpackSizeDefined && unpackSize == 0)
- return LZMA_RES_ERROR;
-
-Also the decoder must return error, if the LZ window is empty:
-
- if (OutWindow.IsEmpty())
- return LZMA_RES_ERROR;
-
-If the match type is "Rep Match", the decoder uses one of the 4 variables of
-distance history table to get the value of distance for current match.
-And there are 4 corresponding ways of decoding flow.
-
-The decoder updates the distance history with the following scheme
-depending from type of match:
-
-- "Rep Match 0" or "Short Rep Match":
- ; LZMA doesn't update the distance history
-
-- "Rep Match 1":
- UInt32 dist = rep1;
- rep1 = rep0;
- rep0 = dist;
-
-- "Rep Match 2":
- UInt32 dist = rep2;
- rep2 = rep1;
- rep1 = rep0;
- rep0 = dist;
-
-- "Rep Match 3":
- UInt32 dist = rep3;
- rep3 = rep2;
- rep2 = rep1;
- rep1 = rep0;
- rep0 = dist;
-
-Then the decoder decodes exact subtype of "Rep Match" using "IsRepG0", "IsRep0Long",
-"IsRepG1", "IsRepG2".
-
-If the subtype is "Short Rep Match", the decoder updates the state, puts
-the one byte from window to current position in window and goes to next
-MATCH/LITERAL symbol (the begin of main loop):
-
- state = UpdateState_ShortRep(state);
- OutWindow.PutByte(OutWindow.GetByte(rep0 + 1));
- unpackSize--;
- continue;
-
-In other cases (Rep Match 0/1/2/3), it decodes the zero-based
-length of match with "RepLenDecoder" decoder:
-
- len = RepLenDecoder.Decode(&RangeDec, posState);
-
-Then it updates the state:
-
- state = UpdateState_Rep(state);
-
-Then the decoder must copy match bytes as described in
-"The Match symbols copying" section.
-
-
-The match symbols copying
--------------------------
-
-If we have the match (Simple Match or Rep Match 0/1/2/3), the decoder must
-copy the sequence of bytes with calculated match distance and match length.
-If uncompressed size is defined, LZMA decoder must check that it doesn't
-exceed that specified uncompressed size:
-
- len += kMatchMinLen;
- bool isError = false;
- if (unpackSizeDefined && unpackSize < len)
- {
- len = (unsigned)unpackSize;
- isError = true;
- }
- OutWindow.CopyMatch(rep0 + 1, len);
- unpackSize -= len;
- if (isError)
- return LZMA_RES_ERROR;
-
-Then the decoder must go to the begin of main loop to decode next MATCH or LITERAL.
-
-
-
-NOTES
------
-
-This specification doesn't describe the variant of decoder implementation
-that supports partial decoding. Such partial decoding case can require some
-changes in "end of stream" condition checks code. Also such code
-can use additional status codes, returned by decoder.
-
-This specification uses C++ code with templates to simplify describing.
-The optimized version of LZMA decoder doesn't need templates.
-Such optimized version can use just two arrays of CProb variables:
- 1) The dynamic array of CProb variables allocated for the Literal Decoder.
- 2) The one common array that contains all other CProb variables.
-
-
-References:
-
-1. G. N. N. Martin, Range encoding: an algorithm for removing redundancy
- from a digitized message, Video & Data Recording Conference,
- Southampton, UK, July 24-27, 1979.
diff --git a/DOC/lzma.txt b/DOC/lzma.txt
index 1f92142..142feb1 100644
--- a/DOC/lzma.txt
+++ b/DOC/lzma.txt
@@ -1,328 +1,345 @@
-LZMA compression
-----------------
-Version: 9.35
-
-This file describes LZMA encoding and decoding functions written in C language.
-
-LZMA is an improved version of famous LZ77 compression algorithm.
-It was improved in way of maximum increasing of compression ratio,
-keeping high decompression speed and low memory requirements for
-decompressing.
-
-Note: you can read also LZMA Specification (lzma-specification.txt from LZMA SDK)
-
-Also you can look source code for LZMA encoding and decoding:
- C/Util/Lzma/LzmaUtil.c
-
-
-LZMA compressed file format
----------------------------
-Offset Size Description
- 0 1 Special LZMA properties (lc,lp, pb in encoded form)
- 1 4 Dictionary size (little endian)
- 5 8 Uncompressed size (little endian). -1 means unknown size
- 13 Compressed data
-
-
-
-ANSI-C LZMA Decoder
-~~~~~~~~~~~~~~~~~~~
-
-Please note that interfaces for ANSI-C code were changed in LZMA SDK 4.58.
-If you want to use old interfaces you can download previous version of LZMA SDK
-from sourceforge.net site.
-
-To use ANSI-C LZMA Decoder you need the following files:
-1) LzmaDec.h + LzmaDec.c + 7zTypes.h + Precomp.h + Compiler.h
-
-Look example code:
- C/Util/Lzma/LzmaUtil.c
-
-
-Memory requirements for LZMA decoding
--------------------------------------
-
-Stack usage of LZMA decoding function for local variables is not
-larger than 200-400 bytes.
-
-LZMA Decoder uses dictionary buffer and internal state structure.
-Internal state structure consumes
- state_size = (4 + (1.5 << (lc + lp))) KB
-by default (lc=3, lp=0), state_size = 16 KB.
-
-
-How To decompress data
-----------------------
-
-LZMA Decoder (ANSI-C version) now supports 2 interfaces:
-1) Single-call Decompressing
-2) Multi-call State Decompressing (zlib-like interface)
-
-You must use external allocator:
-Example:
-void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
-void SzFree(void *p, void *address) { p = p; free(address); }
-ISzAlloc alloc = { SzAlloc, SzFree };
-
-You can use p = p; operator to disable compiler warnings.
-
-
-Single-call Decompressing
--------------------------
-When to use: RAM->RAM decompressing
-Compile files: LzmaDec.h + LzmaDec.c + 7zTypes.h
-Compile defines: no defines
-Memory Requirements:
- - Input buffer: compressed size
- - Output buffer: uncompressed size
- - LZMA Internal Structures: state_size (16 KB for default settings)
-
-Interface:
- int LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
- const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
- ELzmaStatus *status, ISzAlloc *alloc);
- In:
- dest - output data
- destLen - output data size
- src - input data
- srcLen - input data size
- propData - LZMA properties (5 bytes)
- propSize - size of propData buffer (5 bytes)
- finishMode - It has meaning only if the decoding reaches output limit (*destLen).
- LZMA_FINISH_ANY - Decode just destLen bytes.
- LZMA_FINISH_END - Stream must be finished after (*destLen).
- You can use LZMA_FINISH_END, when you know that
- current output buffer covers last bytes of stream.
- alloc - Memory allocator.
-
- Out:
- destLen - processed output size
- srcLen - processed input size
-
- Output:
- SZ_OK
- status:
- LZMA_STATUS_FINISHED_WITH_MARK
- LZMA_STATUS_NOT_FINISHED
- LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
- SZ_ERROR_DATA - Data error
- SZ_ERROR_MEM - Memory allocation error
- SZ_ERROR_UNSUPPORTED - Unsupported properties
- SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
-
- If LZMA decoder sees end_marker before reaching output limit, it returns OK result,
- and output value of destLen will be less than output buffer size limit.
-
- You can use multiple checks to test data integrity after full decompression:
- 1) Check Result and "status" variable.
- 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
- 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
- You must use correct finish mode in that case. */
-
-
-Multi-call State Decompressing (zlib-like interface)
-----------------------------------------------------
-
-When to use: file->file decompressing
-Compile files: LzmaDec.h + LzmaDec.c + 7zTypes.h
-
-Memory Requirements:
- - Buffer for input stream: any size (for example, 16 KB)
- - Buffer for output stream: any size (for example, 16 KB)
- - LZMA Internal Structures: state_size (16 KB for default settings)
- - LZMA dictionary (dictionary size is encoded in LZMA properties header)
-
-1) read LZMA properties (5 bytes) and uncompressed size (8 bytes, little-endian) to header:
- unsigned char header[LZMA_PROPS_SIZE + 8];
- ReadFile(inFile, header, sizeof(header)
-
-2) Allocate CLzmaDec structures (state + dictionary) using LZMA properties
-
- CLzmaDec state;
- LzmaDec_Constr(&state);
- res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc);
- if (res != SZ_OK)
- return res;
-
-3) Init LzmaDec structure before any new LZMA stream. And call LzmaDec_DecodeToBuf in loop
-
- LzmaDec_Init(&state);
- for (;;)
- {
- ...
- int res = LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
- const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode);
- ...
- }
-
-
-4) Free all allocated structures
- LzmaDec_Free(&state, &g_Alloc);
-
-Look example code:
- C/Util/Lzma/LzmaUtil.c
-
-
-How To compress data
---------------------
-
-Compile files:
- 7zTypes.h
- Threads.h
- LzmaEnc.h
- LzmaEnc.c
- LzFind.h
- LzFind.c
- LzFindMt.h
- LzFindMt.c
- LzHash.h
-
-Memory Requirements:
- - (dictSize * 11.5 + 6 MB) + state_size
-
-Lzma Encoder can use two memory allocators:
-1) alloc - for small arrays.
-2) allocBig - for big arrays.
-
-For example, you can use Large RAM Pages (2 MB) in allocBig allocator for
-better compression speed. Note that Windows has bad implementation for
-Large RAM Pages.
-It's OK to use same allocator for alloc and allocBig.
-
-
-Single-call Compression with callbacks
---------------------------------------
-
-Look example code:
- C/Util/Lzma/LzmaUtil.c
-
-When to use: file->file compressing
-
-1) you must implement callback structures for interfaces:
-ISeqInStream
-ISeqOutStream
-ICompressProgress
-ISzAlloc
-
-static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
-static void SzFree(void *p, void *address) { p = p; MyFree(address); }
-static ISzAlloc g_Alloc = { SzAlloc, SzFree };
-
- CFileSeqInStream inStream;
- CFileSeqOutStream outStream;
-
- inStream.funcTable.Read = MyRead;
- inStream.file = inFile;
- outStream.funcTable.Write = MyWrite;
- outStream.file = outFile;
-
-
-2) Create CLzmaEncHandle object;
-
- CLzmaEncHandle enc;
-
- enc = LzmaEnc_Create(&g_Alloc);
- if (enc == 0)
- return SZ_ERROR_MEM;
-
-
-3) initialize CLzmaEncProps properties;
-
- LzmaEncProps_Init(&props);
-
- Then you can change some properties in that structure.
-
-4) Send LZMA properties to LZMA Encoder
-
- res = LzmaEnc_SetProps(enc, &props);
-
-5) Write encoded properties to header
-
- Byte header[LZMA_PROPS_SIZE + 8];
- size_t headerSize = LZMA_PROPS_SIZE;
- UInt64 fileSize;
- int i;
-
- res = LzmaEnc_WriteProperties(enc, header, &headerSize);
- fileSize = MyGetFileLength(inFile);
- for (i = 0; i < 8; i++)
- header[headerSize++] = (Byte)(fileSize >> (8 * i));
- MyWriteFileAndCheck(outFile, header, headerSize)
-
-6) Call encoding function:
- res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable,
- NULL, &g_Alloc, &g_Alloc);
-
-7) Destroy LZMA Encoder Object
- LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
-
-
-If callback function return some error code, LzmaEnc_Encode also returns that code
-or it can return the code like SZ_ERROR_READ, SZ_ERROR_WRITE or SZ_ERROR_PROGRESS.
-
-
-Single-call RAM->RAM Compression
---------------------------------
-
-Single-call RAM->RAM Compression is similar to Compression with callbacks,
-but you provide pointers to buffers instead of pointers to stream callbacks:
-
-SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
- const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
- ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
-
-Return code:
- SZ_OK - OK
- SZ_ERROR_MEM - Memory allocation error
- SZ_ERROR_PARAM - Incorrect paramater
- SZ_ERROR_OUTPUT_EOF - output buffer overflow
- SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
-
-
-
-Defines
--------
-
-_LZMA_SIZE_OPT - Enable some optimizations in LZMA Decoder to get smaller executable code.
-
-_LZMA_PROB32 - It can increase the speed on some 32-bit CPUs, but memory usage for
- some structures will be doubled in that case.
-
-_LZMA_UINT32_IS_ULONG - Define it if int is 16-bit on your compiler and long is 32-bit.
-
-_LZMA_NO_SYSTEM_SIZE_T - Define it if you don't want to use size_t type.
-
-
-_7ZIP_PPMD_SUPPPORT - Define it if you don't want to support PPMD method in AMSI-C .7z decoder.
-
-
-C++ LZMA Encoder/Decoder
-~~~~~~~~~~~~~~~~~~~~~~~~
-C++ LZMA code use COM-like interfaces. So if you want to use it,
-you can study basics of COM/OLE.
-C++ LZMA code is just wrapper over ANSI-C code.
-
-
-C++ Notes
-~~~~~~~~~~~~~~~~~~~~~~~~
-If you use some C++ code folders in 7-Zip (for example, C++ code for .7z handling),
-you must check that you correctly work with "new" operator.
-7-Zip can be compiled with MSVC 6.0 that doesn't throw "exception" from "new" operator.
-So 7-Zip uses "CPP\Common\NewHandler.cpp" that redefines "new" operator:
-operator new(size_t size)
-{
- void *p = ::malloc(size);
- if (p == 0)
- throw CNewException();
- return p;
-}
-If you use MSCV that throws exception for "new" operator, you can compile without
-"NewHandler.cpp". So standard exception will be used. Actually some code of
-7-Zip catches any exception in internal code and converts it to HRESULT code.
-So you don't need to catch CNewException, if you call COM interfaces of 7-Zip.
-
----
-
-http://www.7-zip.org
-http://www.7-zip.org/sdk.html
-http://www.7-zip.org/support.html
+LZMA compression
+----------------
+Version: 23.01
+
+This file describes LZMA encoding and decoding functions written in C language.
+
+LZMA is an improved version of famous LZ77 compression algorithm.
+It was improved in way of maximum increasing of compression ratio,
+keeping high decompression speed and low memory requirements for
+decompressing.
+
+Note: you can read also LZMA Specification (lzma-specification.txt from LZMA SDK)
+
+Also you can look source code for LZMA encoding and decoding:
+ C/Util/Lzma/LzmaUtil.c
+
+
+LZMA compressed file format
+---------------------------
+Offset Size Description
+ 0 1 Special LZMA properties (lc,lp, pb in encoded form)
+ 1 4 Dictionary size (little endian)
+ 5 8 Uncompressed size (little endian). -1 means unknown size
+ 13 Compressed data
+
+
+
+ANSI-C LZMA Decoder
+~~~~~~~~~~~~~~~~~~~
+
+Please note that interfaces for ANSI-C code were changed in LZMA SDK 4.58.
+If you want to use old interfaces you can download previous version of LZMA SDK
+from sourceforge.net site.
+
+To use ANSI-C LZMA Decoder you need the following files:
+1) LzmaDec.h + LzmaDec.c + 7zTypes.h + Precomp.h + Compiler.h
+
+Look example code:
+ C/Util/Lzma/LzmaUtil.c
+
+
+Memory requirements for LZMA decoding
+-------------------------------------
+
+Stack usage of LZMA decoding function for local variables is not
+larger than 200-400 bytes.
+
+LZMA Decoder uses dictionary buffer and internal state structure.
+Internal state structure consumes
+ state_size = (4 + (1.5 << (lc + lp))) KB
+by default (lc=3, lp=0), state_size = 16 KB.
+
+
+How To decompress data
+----------------------
+
+LZMA Decoder (ANSI-C version) now supports 2 interfaces:
+1) Single-call Decompressing
+2) Multi-call State Decompressing (zlib-like interface)
+
+You must use external allocator:
+Example:
+void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
+void SzFree(void *p, void *address) { p = p; free(address); }
+ISzAlloc alloc = { SzAlloc, SzFree };
+
+You can use p = p; operator to disable compiler warnings.
+
+
+Single-call Decompressing
+-------------------------
+When to use: RAM->RAM decompressing
+Compile files: LzmaDec.h + LzmaDec.c + 7zTypes.h
+Compile defines: no defines
+Memory Requirements:
+ - Input buffer: compressed size
+ - Output buffer: uncompressed size
+ - LZMA Internal Structures: state_size (16 KB for default settings)
+
+Interface:
+ int LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc);
+ In:
+ dest - output data
+ destLen - output data size
+ src - input data
+ srcLen - input data size
+ propData - LZMA properties (5 bytes)
+ propSize - size of propData buffer (5 bytes)
+ finishMode - It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+ You can use LZMA_FINISH_END, when you know that
+ current output buffer covers last bytes of stream.
+ alloc - Memory allocator.
+
+ Out:
+ destLen - processed output size
+ srcLen - processed input size
+
+ Output:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+
+ If LZMA decoder sees end_marker before reaching output limit, it returns OK result,
+ and output value of destLen will be less than output buffer size limit.
+
+ You can use multiple checks to test data integrity after full decompression:
+ 1) Check Result and "status" variable.
+ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
+ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
+ You must use correct finish mode in that case. */
+
+
+Multi-call State Decompressing (zlib-like interface)
+----------------------------------------------------
+
+When to use: file->file decompressing
+Compile files: LzmaDec.h + LzmaDec.c + 7zTypes.h
+
+Memory Requirements:
+ - Buffer for input stream: any size (for example, 16 KB)
+ - Buffer for output stream: any size (for example, 16 KB)
+ - LZMA Internal Structures: state_size (16 KB for default settings)
+ - LZMA dictionary (dictionary size is encoded in LZMA properties header)
+
+1) read LZMA properties (5 bytes) and uncompressed size (8 bytes, little-endian) to header:
+ unsigned char header[LZMA_PROPS_SIZE + 8];
+ ReadFile(inFile, header, sizeof(header)
+
+2) Allocate CLzmaDec structures (state + dictionary) using LZMA properties
+
+ CLzmaDec state;
+ LzmaDec_Constr(&state);
+ res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc);
+ if (res != SZ_OK)
+ return res;
+
+3) Init LzmaDec structure before any new LZMA stream. And call LzmaDec_DecodeToBuf in loop
+
+ LzmaDec_Init(&state);
+ for (;;)
+ {
+ ...
+ int res = LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode);
+ ...
+ }
+
+
+4) Free all allocated structures
+ LzmaDec_Free(&state, &g_Alloc);
+
+Look example code:
+ C/Util/Lzma/LzmaUtil.c
+
+
+How To compress data
+--------------------
+
+Compile files:
+ 7zTypes.h
+ Threads.h
+ Threads.c
+ LzmaEnc.h
+ LzmaEnc.c
+ LzFind.h
+ LzFind.c
+ LzFindMt.h
+ LzFindMt.c
+ LzFindOpt.c
+ LzHash.h
+
+Memory Requirements:
+ - (dictSize * 11.5 + 6 MB) + state_size
+
+Lzma Encoder can use two memory allocators:
+1) alloc - for small arrays.
+2) allocBig - for big arrays.
+
+For example, you can use Large RAM Pages (2 MB) in allocBig allocator for
+better compression speed. Note that Windows has bad implementation for
+Large RAM Pages.
+It's OK to use same allocator for alloc and allocBig.
+
+
+Single-call Compression with callbacks
+--------------------------------------
+
+Look example code:
+ C/Util/Lzma/LzmaUtil.c
+
+When to use: file->file compressing
+
+1) you must implement callback structures for interfaces:
+ISeqInStream
+ISeqOutStream
+ICompressProgress
+ISzAlloc
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+ CFileSeqInStream inStream;
+ CFileSeqOutStream outStream;
+
+ inStream.funcTable.Read = MyRead;
+ inStream.file = inFile;
+ outStream.funcTable.Write = MyWrite;
+ outStream.file = outFile;
+
+
+2) Create CLzmaEncHandle object;
+
+ CLzmaEncHandle enc;
+
+ enc = LzmaEnc_Create(&g_Alloc);
+ if (enc == 0)
+ return SZ_ERROR_MEM;
+
+
+3) initialize CLzmaEncProps properties;
+
+ LzmaEncProps_Init(&props);
+
+ Then you can change some properties in that structure.
+
+4) Send LZMA properties to LZMA Encoder
+
+ res = LzmaEnc_SetProps(enc, &props);
+
+5) Write encoded properties to header
+
+ Byte header[LZMA_PROPS_SIZE + 8];
+ size_t headerSize = LZMA_PROPS_SIZE;
+ UInt64 fileSize;
+ int i;
+
+ res = LzmaEnc_WriteProperties(enc, header, &headerSize);
+ fileSize = MyGetFileLength(inFile);
+ for (i = 0; i < 8; i++)
+ header[headerSize++] = (Byte)(fileSize >> (8 * i));
+ MyWriteFileAndCheck(outFile, header, headerSize)
+
+6) Call encoding function:
+ res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable,
+ NULL, &g_Alloc, &g_Alloc);
+
+7) Destroy LZMA Encoder Object
+ LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
+
+
+If callback function return some error code, LzmaEnc_Encode also returns that code
+or it can return the code like SZ_ERROR_READ, SZ_ERROR_WRITE or SZ_ERROR_PROGRESS.
+
+
+Single-call RAM->RAM Compression
+--------------------------------
+
+Single-call RAM->RAM Compression is similar to Compression with callbacks,
+but you provide pointers to buffers instead of pointers to stream callbacks:
+
+SRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ const CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+
+Return code:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+
+
+
+Defines
+-------
+
+Z7_LZMA_SIZE_OPT - Enable some code size optimizations in LZMA Decoder to get smaller executable code.
+
+Z7_LZMA_PROB32 - It can increase the speed on some 32-bit CPUs, but memory usage for
+ some structures will be doubled in that case.
+
+Z7_DECL_Int32_AS_long - Define it if int is 16-bit on your compiler and long is 32-bit.
+
+Z7_DECL_SizeT_AS_unsigned_int - Define it if you don't want to use size_t type.
+
+
+Defines for 7z decoder written in C
+-----------------------------------
+These defines are for 7zDec.c only (the decoder in C).
+C++ 7z decoder doesn't uses these macros.
+
+Z7_PPMD_SUPPORT - define it if you need PPMD method support.
+Z7_NO_METHODS_FILTERS - do not use filters (except of BCJ2 filter).
+Z7_USE_NATIVE_BRANCH_FILTER - use filter for native ISA:
+ use x86 filter, if compiled to x86 executable,
+ use arm64 filter, if compiled to arm64 executable.
+
+
+C++ LZMA Encoder/Decoder
+~~~~~~~~~~~~~~~~~~~~~~~~
+C++ LZMA code use COM-like interfaces. So if you want to use it,
+you can study basics of COM/OLE.
+C++ LZMA code is just wrapper over ANSI-C code.
+
+
+C++ Notes
+~~~~~~~~~~~~~~~~~~~~~~~~
+If you use some C++ code folders in 7-Zip (for example, C++ code for 7z archive handling),
+you must check that you correctly work with "new" operator.
+7-Zip can be compiled with MSVC 6.0 that doesn't throw "exception" from "new" operator.
+So 7-Zip uses "CPP\Common\NewHandler.cpp" that redefines "new" operator,
+if compiled by old MSVC compilers (MSVC before version VS 2010):
+
+operator new(size_t size)
+{
+ void *p = ::malloc(size);
+ if (!p)
+ throw CNewException();
+ return p;
+}
+
+If the compiler is VS 2010 or newer, NewHandler.cpp doesn't redefine "new" operator.
+Sp if you use new compiler (VS 2010 or newer), you still can include "NewHandler.cpp"
+to compilation, and it will not redefine operator new.
+Also you can compile without "NewHandler.cpp" with new compilers.
+If 7-zip doesn't redefine operator "new", standard exception will be used instead of CNewException.
+Some code of 7-Zip catches any exception in internal code and converts it to HRESULT code.
+So you don't need to catch CNewException, if you call COM interfaces of 7-Zip.
+
+---
+
+http://www.7-zip.org
+http://www.7-zip.org/sdk.html
+http://www.7-zip.org/support.html
diff --git a/DOC/readme.txt b/DOC/readme.txt
new file mode 100644
index 0000000..5cd90c5
--- /dev/null
+++ b/DOC/readme.txt
@@ -0,0 +1,273 @@
+7-Zip 23.01 Sources
+-------------------
+
+7-Zip is a file archiver for Windows.
+
+7-Zip Copyright (C) 1999-2023 Igor Pavlov.
+
+
+License Info
+------------
+
+7-Zip is free software distributed under the GNU LGPL
+(except for unRar code). Also some code
+is licensed under the "BSD 3-clause License".
+Read "License.txt" for more infomation about license.
+
+Notes about unRAR license:
+
+Please check main restriction from unRar license:
+
+ 2. The unRAR sources may be used in any software to handle RAR
+ archives without limitations free of charge, but cannot be used
+ to re-create the RAR compression algorithm, which is proprietary.
+ Distribution of modified unRAR sources in separate form or as a
+ part of other software is permitted, provided that it is clearly
+ stated in the documentation and source comments that the code may
+ not be used to develop a RAR (WinRAR) compatible archiver.
+
+In brief it means:
+1) You can compile and use compiled files under GNU LGPL rules, since
+ unRAR license almost has no restrictions for compiled files.
+ You can link these compiled files to LGPL programs.
+2) You can fix bugs in source code and use compiled fixed version.
+3) You can not use unRAR sources to re-create the RAR compression algorithm.
+
+
+LZMA SDK
+--------
+
+This package also contains some files from LZMA SDK
+You can download LZMA SDK from:
+ http://www.7-zip.org/sdk.html
+LZMA SDK is written and placed in the public domain by Igor Pavlov.
+
+
+How to compile in Windows
+-------------------------
+
+To compile the sources to Windows binaries you need Visual Studio compiler and/or Windows SDK.
+You can use latest Windows Studio 2017/2019/2022 to compile binaries for x86, x64, arm64 and arm platforms.
+Also you can use old compilers for some platforms:
+ x86 : Visual C++ 6.0 with Platform SDK
+ x64 : Windows Server 2003 R2 Platform SDK
+ ia64 (itanium) : Windows Server 2003 R2 Platform SDK
+ arm for Windows CE : Standard SDK for Windows CE 5.0
+
+If you use MSVC6, specify also Platform SDK directories at top of directories lists:
+Tools / Options / Directories
+ - Include files
+ - Library files
+
+Also you need Microsoft Macro Assembler:
+ - ml.exe for x86
+ - ml64.exe for x64
+You can use ml.exe from Windows SDK for Windows Vista or some later versions.
+
+There are two ways to compile 7-Zip binaries:
+1) via makefile in command line.
+2) via dsp file in Visual Studio.
+
+The dsp file compiling can be used for development and debug purposes.
+All final 7-Zip binaries are compiled via makefiles, that provide best
+optimization options.
+
+
+How to compile with makefile
+----------------------------
+
+Some macronames can be defined for compiling with makefile:
+
+PLATFORM
+ with possible values: x64, x86, arm64, arm, ia64
+
+OLD_COMPILER
+ for old VC compiler, like MSCV 6.0.
+
+MY_DYNAMIC_LINK
+ for dynamic linking to the run-time library (msvcrt.dll).
+ The default makefile option is static linking to the run-time library.
+
+
+
+Compiling 7-Zip for Unix/Linux
+------------------------------
+
+There are several options to compile 7-Zip with different compilers: gcc and clang.
+Also 7-Zip code contains two versions for some parts of code: in C and in Assembeler.
+So if you compile the version with Assembeler code, you will get faster 7-Zip binary.
+
+7-Zip's assembler code uses the following syntax for different platforms:
+
+1) x86 and x86-64 (AMD64): MASM syntax.
+ There are 2 programs that supports MASM syntax in Linux.
+' 'Asmc Macro Assembler and JWasm. But JWasm now doesn't support some
+ cpu instructions used in 7-Zip.
+ So you must install Asmc Macro Assembler in Linux, if you want to compile fastest version
+ of 7-Zip x86 and x86-64:
+ https://github.com/nidud/asmc
+
+2) arm64: GNU assembler for ARM64 with preprocessor.
+ That systax is supported by GCC and CLANG for ARM64.
+
+There are different binaries that can be compiled from 7-Zip source.
+There are 2 main files in folder for compiling:
+ makefile - that can be used for compiling Windows version of 7-Zip with nmake command
+ makefile.gcc - that can be used for compiling Linux/macOS versions of 7-Zip or Windows version
+ with MINGW (GCC) with make command.
+
+At first you must change the current folder to folder that contains `makefile.gcc`:
+
+ cd CPP/7zip/Bundles/Alone2
+
+Then you can compile `makefile.gcc` with the command:
+
+ make -j -f makefile.gcc
+
+Also there are additional "*.mak" files in folder "CPP/7zip/" that can be used to compile
+7-Zip binaries with optimized code and optimzing options.
+
+To compile with GCC without assembler:
+ cd CPP/7zip/Bundles/Alone2
+ make -j -f ../../cmpl_gcc.mak
+
+To compile with CLANG without assembler:
+ make -j -f ../../cmpl_clang.mak
+
+To compile 7-Zip for x86-64 with asmc assembler:
+ make -j -f ../../cmpl_gcc_x64.mak
+
+To compile 7-Zip for arm64 with assembler:
+ make -j -f ../../cmpl_gcc_arm64.mak
+
+To compile 7-Zip for arm64 for macOS:
+ make -j -f ../../cmpl_mac_arm64.mak
+
+Also you can change some compiler options in the "mak" files:
+ cmpl_gcc.mak
+ var_gcc.mak
+ warn_gcc.mak
+
+makefile.gcc supports some variables that can change compile options
+
+USE_JWASM=1
+ use JWasm assembler instead of Asmc.
+ Note that JWasm doesn't support AES instructions. So AES code from C version AesOpt.c
+ will be used instead of assembler code from AesOpt.asm.
+
+DISABLE_RAR=1
+ removes whole RAR related code from compilation.
+
+DISABLE_RAR_COMPRESS=1
+ removes "not fully free" code of RAR decompression codecs from compilation.
+
+RAR decompression codecs in 7-Zip code has some additional license restrictions,
+that can be treated as not fully compatible with free-software licenses.
+DISABLE_RAR_COMPRESS=1 allows to exclude such "not-fully-free" RAR code from compilation.
+if DISABLE_RAR_COMPRESS=1 is specified, 7-zip will not be able to decompress files
+from rar archives, but 7-zip still will be able to open rar archives to get list of
+files or to extract files that are stored without compression.
+if DISABLE_RAR=1 is specified, 7-zip will not be able to work with RAR archives.
+
+
+
+7-Zip and p7zip
+===============
+Now there are two different ports of 7-Zip for Linux/macOS:
+
+1) p7zip - another port of 7-Zip for Linux, made by an independent developer.
+ The latest version of p7zip now is 16.02, and that p7zip 16.02 is outdated now.
+ http://sourceforge.net/projects/p7zip/
+
+2) 7-Zip for Linux/macOS - this package - it's new code with all changes from latest 7-Zip for Windows.
+
+These two ports are not identical.
+Note also that some Linux specific things can be implemented better in p7zip than in new 7-Zip for Linux.
+
+
+
+
+Notes:
+------
+7-Zip consists of COM modules (DLL files).
+But 7-Zip doesn't use standard COM interfaces for creating objects.
+Look at
+7zip\UI\Client7z folder for example of using DLL files of 7-Zip.
+Some DLL files can use other DLL files from 7-Zip.
+If you don't like it, you must use standalone version of DLL.
+To compile standalone version of DLL you must include all used parts
+to project and define some defs.
+For example, 7zip\Bundles\Format7z is a standalone version of 7z.dll
+that works with 7z format. So you can use such DLL in your project
+without additional DLL files.
+
+
+Description of 7-Zip sources package
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+DOC Documentation
+---
+ readme.txt - Readme file
+ src-history.txt - Sources history
+ 7zC.txt - 7z ANSI-C Decoder description
+ 7zFormat.txt - 7z format description
+ Methods.txt - Compression method IDs
+ lzma.txt - LZMA compression description
+ License.txt - license information
+ copying.txt - GNU LGPL license
+ unRarLicense.txt - License for unRAR part of source code
+ 7zip.wxs - installer script for WIX
+ 7zip.hhp - html help project file
+
+Asm - Source code in Assembler : optimized code for CRC, SHA, AES, LZMA decoding.
+
+C - Source code in C
+
+CPP - Source code in C++
+
+Common common files for C++ projects
+
+Windows common files for Windows related code
+
+7zip
+
+ Common Common modules for 7-zip
+
+ Archive files related to archiving
+
+ Bundle Modules that are bundles of other modules (files)
+
+ Alone 7za.exe: Standalone version of 7-Zip console that supports only 7z/xz/cab/zip/gzip/bzip2/tar.
+ Alone2 7zz.exe: Standalone version of 7-Zip console that supports all formats.
+ Alone7z 7zr.exe: Standalone version of 7-Zip console that supports only 7z (reduced version)
+ Fm Standalone version of 7-Zip File Manager
+ Format7z 7za.dll: .7z support
+ Format7zExtract 7zxa.dll: .7z support, extracting only
+ Format7zR 7zr.dll: .7z support, reduced version
+ Format7zExtractR 7zxr.dll: .7z support, reduced version, extracting only
+ Format7zF 7z.dll: all formats
+ LzmaCon lzma.exe: LZMA compression/decompression
+ SFXCon 7zCon.sfx: Console 7z SFX module
+ SFXWin 7z.sfx: Windows 7z SFX module
+ SFXSetup 7zS.sfx: Windows 7z SFX module for Installers
+
+ Compress files for compression / decompression
+
+ Crypto files for encryption / decryption
+
+ UI
+
+ Agent Intermediary modules for FAR plugin and Explorer plugin
+ Client7z Test application for 7za.dll
+ Common Common UI files
+ Console 7z.exe : Console version
+ Explorer 7-zip.dll: 7-Zip Shell extension
+ Far plugin for Far Manager
+ FileManager 7zFM.exe: 7-Zip File Manager
+ GUI 7zG.exe: 7-Zip GUI version
+
+
+
+---
+Igor Pavlov
+http://www.7-zip.org
diff --git a/DOC/src-history.txt b/DOC/src-history.txt
new file mode 100644
index 0000000..c1c1b71
--- /dev/null
+++ b/DOC/src-history.txt
@@ -0,0 +1,709 @@
+HISTORY of the 7-Zip source code
+--------------------------------
+
+23.01 2023-06-20
+-------------------------
+- All external macros for compiling C/C++ code of 7-Zip now have Z7_ prefix.
+- 7-Zip COM interfaces now use new macros that allow to declare and implement COM interface.
+- The code has been modified to compile with the maximum diagnostic warning level:
+ -Wall in MSVC and -Weverything in CLANG.
+ And some warning types are disabled in 2 files:
+ - C/Compiler.h for C/C++ code warnings.
+ - CPP/Common/Common.h for C++ code warnings.
+- Linux/macOS versions of 7-Zip: IUnknown interface in new code doesn't use
+ virtual destructor that was used in previous 7-Zip and p7zip:
+ // virtual ~IUnknown() {}
+ So 7-Zip's dynamically linked shared libraries (codecs) are not compatible
+ between new 7-Zip for Linux/macOS and old 7-Zip (and p7zip).
+- Some optimizations in filters code: BCJ, BCJ2, Swap* and opthers.
+- If 7-Zip uses BCJ2 filter for big datasets compressing, it can use additional temp
+ files in system's TEMP folder. 7-Zip uses temp file for additional compressed
+ data stream, if size of such compressed stream is larger than predefined limit:
+ 16 MiB in 32-bit version, 4 GiB in 64-bit version.
+- Some bugs were fixed.
+
+
+22.00 2022-06-16
+-------------------------
+- 7-Zip interfaces now support high precision (1 ns) timestamps with reserved
+ fields of tagPROPVARIANT (VT_FILETIME).
+
+
+21.07 2021-12-26
+-------------------------
+- The sorting order of files in archives was slightly changed to be more consistent
+ for cases where the name of some directory is the same as the prefix part of the name
+ of another directory or file.
+- TAR archives created by 7-Zip now are more consistent with archives created by GNU TAR program.
+
+
+21.06 2021-11-24
+-------------------------
+- Bug in LZMA encoder in file LzmaEnc.c was fixed:
+ LzmaEnc_MemEncode(), LzmaEncode() and LzmaCompress() could work incorrectly,
+ if size value for output buffer is smaller than size required for all compressed data.
+ LzmaEnc_Encode() could work incorrectly,
+ if callback ISeqOutStream::Write() doesn't write all compressed data.
+ NCompress::NLzma::CEncoder::Code() could work incorrectly,
+ if callback ISequentialOutStream::Write() returns error code.
+- Bug in versions 21.00-21.05 was fixed:
+ 7-Zip didn't set attributes of directories during archive extracting.
+
+
+21.04 beta 2021-11-02
+-------------------------
+- 7-Zip now reduces the number of working CPU threads for compression,
+ if RAM size is not enough for compression with big LZMA2 dictionary.
+- 7-Zip now can create and check "file.sha256" and "file.sha1" text files
+ that contain the list of file names and SHA-1 / SHA-256 checksums in format
+ compatible with sha1sum/sha256sum programs.
+
+
+21.03 beta 2021-07-20
+-------------------------
+- The maximum dictionary size for LZMA/LZMA2 compressing was increased to 4 GB (3840 MiB).
+- Minor speed optimizations in LZMA/LZMA2 compressing.
+
+
+21.02 alpha 2021-05-06
+-------------------------
+- 7-Zip now writes additional field for filename in UTF-8 encoding to zip archives.
+ It allows to extract correct file name from zip archives on different systems.
+- The command line version of 7-Zip for macOS was released.
+- The speed for LZMA and LZMA2 decompression in arm64 versions for macOS and Linux
+ was increased by 20%-60%.
+- Some changes and improvements in ZIP, TAR and NSIS code.
+
+
+21.01 alpha 2021-03-09
+-------------------------
+- The command line version of 7-Zip for Linux was released.
+- The improvements for speed of ARM64 version using hardware CPU instructions
+ for AES, CRC-32, SHA-1 and SHA-256.
+- The bug in versions 18.02 - 21.00 was fixed:
+ 7-Zip could not correctly extract some ZIP archives created with xz compression method.
+- Some bugs were fixed.
+
+
+20.02 alpha 2020-08-08
+-------------------------
+- The default number of LZMA2 chunks per solid block in 7z archive was increased to 64.
+ It allows to increase the compression speed for big 7z archives, if there is a big number
+ of CPU cores and threads.
+- The speed of PPMd compressing/decompressing was increased for 7z/ZIP/RAR archives.
+- The new -ssp switch. If the switch -ssp is specified, 7-Zip doesn't allow the system
+ to modify "Last Access Time" property of source files for archiving and hashing operations.
+- Some bugs were fixed.
+
+
+20.00 alpha 2020-02-06
+-------------------------
+- 7-Zip now supports new optional match finders for LZMA/LZMA2 compression: bt5 and hc5,
+ that can work faster than bt4 and hc4 match finders for the data with big redundancy.
+- The compression ratio was improved for Fast and Fastest compression levels with the
+ following default settings:
+ - Fastest level (-mx1) : hc5 match finder with 256 KB dictionary.
+ - Fast level (-mx3) : hc5 match finder with 4 MB dictionary.
+- Minor speed optimizations in multithreaded LZMA/LZMA2 compression for Normal/Maximum/Ultra
+ compression levels.
+- bzip2 decoding code was updated to support bzip2 archives, created by lbzip2 program.
+
+
+19.02 2019-09-05
+-------------------------
+- Support for SHA-1/SHA-256 optimized code in
+ Sha1Opt.c, Sha256Opt.c, Sha256Opt.asm, Sha1Opt.asm.
+
+
+19.00 2019-02-21
+-------------------------
+- Encryption strength for 7z archives was increased:
+ the size of random initialization vector was increased from 64-bit to 128-bit,
+ and the pseudo-random number generator was improved.
+- Some bugs were fixed.
+
+
+18.06 2018-12-30
+-------------------------
+- The speed for LZMA/LZMA2 compressing was increased by 3-10%,
+ and there are minor changes in compression ratio.
+- Some bugs were fixed.
+- The bug in 7-Zip 18.02-18.05 was fixed:
+ There was memory leak in multithreading xz decoder - XzDecMt_Decode(),
+ if xz stream contains only one block.
+- 7-Zip 18.02-18.05 used only one CPU thread for bz2 archive creation.
+- The changes for MSVS compiler makefiles:
+ - the makefiles now use "PLATFORM" macroname with values (x64, x86, arm64)
+ instead of "CPU" macroname with values (AMD64, ARM64).
+ - the makefiles by default now use static version of the run-time library.
+
+
+18.05 2018-04-30
+-------------------------
+- The speed for LZMA/LZMA2 compressing was increased
+ by 8% for fastest/fast compression levels and
+ by 3% for normal/maximum compression levels.
+- Previous versions of 7-Zip could work incorrectly in "Large memory pages" mode in
+ Windows 10 because of some BUG with "Large Pages" in Windows 10.
+ Now 7-Zip doesn't use "Large Pages" on Windows 10 up to revision 1709 (16299).
+
+
+18.03 beta 2018-03-04
+-------------------------
+- Asm\x86\LzmaDecOpt.asm: new optimized LZMA decoder written in asm
+ for x64 with about 30% higher speed than main version of LZMA decoder written in C.
+- The speed for single-thread LZMA/LZMA2 decoder written in C was increased by 3%.
+- 7-Zip now can use multi-threading for 7z/LZMA2 decoding,
+ if there are multiple independent data chunks in LZMA2 stream.
+- 7-Zip now can use multi-threading for xz decoding,
+ if there are multiple blocks in xz stream.
+
+
+17.00 beta 2017-04-29
+-------------------------
+- NewHandler.h / NewHandler.cpp:
+ now it redefines operator new() only for old MSVC compilers (_MSC_VER < 1900).
+- C/7zTypes.h : the names of variables in interface structures were changed (vt).
+- Some bugs were fixed. 7-Zip could crash in some cases.
+- Some internal changes in code.
+
+
+16.02 2016-05-21
+-------------------------
+- The BUG in 16.00 - 16.01 was fixed:
+ Split Handler (SplitHandler.cpp) returned incorrect
+ total size value (kpidSize) for split archives.
+
+
+16.01 2016-05-19
+-------------------------
+- Some bugs were fixed,
+- Some internal changes to reduce the number of compiler warnings.
+
+
+16.00 2016-05-10
+-------------------------
+- 7-Zip now can extract multivolume ZIP archives (z01, z02, ... , zip).
+- Some bugs were fixed,
+
+
+15.12 2015-11-19
+-------------------------
+- The BUG in C version of 7z decoder was fixed:
+ 7zDec.c : SzDecodeLzma2()
+ 7z decoder could mistakenly report about decoding error for some 7z archives
+ that use LZMA2 compression method.
+ The probability to get that mistaken decoding error report was about
+ one error per 16384 solid blocks for solid blocks larger than 16 KB (compressed size).
+- The BUG (in 9.26-15.11) in C version of 7z decoder was fixed:
+ 7zArcIn.c : SzReadHeader2()
+ 7z decoder worked incorrectly for 7z archives that contain
+ empty solid blocks, that can be placed to 7z archive, if some file is
+ unavailable for reading during archive creation.
+
+
+15.09 beta 2015-10-16
+-------------------------
+- The BUG in LZMA / LZMA2 encoding code was fixed.
+ The BUG in LzFind.c::MatchFinder_ReadBlock() function.
+ If input data size is larger than (4 GiB - dictionary_size),
+ the following code worked incorrectly:
+ - LZMA : LzmaEnc_MemEncode(), LzmaEncode() : LZMA encoding functions
+ for compressing from memory to memory.
+ That BUG is not related to LZMA encoder version that works via streams.
+ - LZMA2 : multi-threaded version of LZMA2 encoder worked incorrectly, if
+ default value of chunk size (CLzma2EncProps::blockSize) is changed
+ to value larger than (4 GiB - dictionary_size).
+
+
+9.38 beta 2015-01-03
+-------------------------
+- The BUG in 9.31-9.37 was fixed:
+ IArchiveGetRawProps interface was disabled for 7z archives.
+- The BUG in 9.26-9.36 was fixed:
+ Some code in CPP\7zip\Archive\7z\ worked correctly only under Windows.
+
+
+9.36 beta 2014-12-26
+-------------------------
+- The BUG in command line version was fixed:
+ 7-Zip created temporary archive in current folder during update archive
+ operation, if -w{Path} switch was not specified.
+ The fixed 7-Zip creates temporary archive in folder that contains updated archive.
+- The BUG in 9.33-9.35 was fixed:
+ 7-Zip silently ignored file reading errors during 7z or gz archive creation,
+ and the created archive contained only part of file that was read before error.
+ The fixed 7-Zip stops archive creation and it reports about error.
+
+
+9.31 2012-10-31
+-------------------------
+- InBuffer.h : CInBuffer uses ISequentialInStream *_stream; instead of CMyComPtr<ISequentialInStream>
+ OutBuffer.h: COutBuffer uses ISequentialOutStream *_stream; instead of CMyComPtr<ISequentialOutStream>
+
+
+9.26 2011-04-11
+-------------------------
+- The BUG was fixed: multi-threaded ZIP stored file size that was at scan stage,
+ So if the file was changed after scan, the Unpack Size field was incorrect
+
+
+9.21 2011-04-11
+-------------------------
+- New class FString for file names at file systems.
+- Speed optimization in CRC code for big-endian CPUs.
+
+
+9.18 2010-11-02
+-------------------------
+- New small SFX module for installers (C/Util/SfxSetup).
+
+
+9.17 2010-10-04
+-------------------------
+- IStream.h::IOutStream::
+ STDMETHOD(SetSize)(Int64 newSize) PURE;
+ was changed to
+ STDMETHOD(SetSize)(UInt64 newSize) PURE;
+
+
+9.09 2009-12-12
+-------------------------
+- The bug was fixed:
+ Utf16_To_Utf8 funstions in UTFConvert.cpp and 7zMain.c
+ incorrectly converted surrogate characters (the code >= 0x10000) to UTF-8.
+
+
+9.05 2009-07-05
+-------------------------
+- FileMapping.h::CFileMapping now returns WRes
+
+
+9.04 2009-05-30
+-------------------------
+- ICoder.h: NCoderPropID::EEnum values were changed
+
+
+9.02 2009-04-23
+-------------------------
+- Bug was fixed: if swap2 filter was requests at compression,
+ 7-zip used swap4 filter instead (but id was swap2), so archives were incorrect.
+
+4.61 2008-11-23
+-------------------------
+- Bug in ver. 4.58+ was fixed:
+ 7-Zip didn't use any -m* switch after -mtc, -mcl or -mcu for .zip archives.
+- Bug in .CAB code was fixed. 7-Zip didn't show some empty files,
+ if .CAB archive contains more than one empty file.
+
+
+4.59 2008-07-27
+-------------------------
+- Bug was fixed:
+ LZMA Encoder in fast compression mode could access memory outside of
+ allocated range in some rare cases.
+
+
+4.59 alpha 2008-05-30
+-------------------------
+- BUGS was fixed:
+ 7zOut.cpp: 7-Zip incorrectly wrote size of property records in some cases.
+ 7zIn.cpp: 7-Zip incorrectly work with archive, containg archive properties.
+
+4.58 alpha 9 2008-04-29
+-------------------------
+- BUG was fixed: 7-Zip showed incorrect timestamps in ISO files.
+
+
+4.58 alpha 8 2008-04-15
+-------------------------
+- BUG in 4.58 alpha 5/6/7 was fixed:
+ LZMA encoder worked incorrectly, if lp != 0.
+- Unicode (UTF-8) support for filenames in .ZIP archives. Now there are 3 modes:
+ 1) Default mode: 7-Zip uses UTF-8, if the local code page doesn't contain required symbols.
+ 2) -mcu switch: 7-Zip uses UTF-8, if there are non-ASCII symbols.
+ 3) -mcl switch: 7-Zip uses local code page.
+- Now it's possible to use -mSW- and -mSW+ switches instead of -mSW=off and -mSW=on
+
+
+4.58 alpha 7 2008-04-08
+-------------------------
+- BUG was fixed: BZip2Encoder and BZip2Decoder used CEvent objects without
+ creating, when BZip2 code was called with one thread (with -mmt1 switch or with
+ default switches on single thread CPU).
+- .lzma support.
+- RPM and NSIS support was improved.
+- LZMA now stores only (2 << n) or (3 << n) dictionary size value to LZMA properties.
+
+
+4.58 alpha 6 2008-03-27
+-------------------------
+- NTFS time extra in ZIP.
+- New item property - kpidTimeType - VT_UI4 (0 - NTFS, 1 - Unix, 2 - DOS).
+- Static CRC table is not required now for Lzma Encoder (in Lz MatchFinder).
+
+
+4.58 alpha 5 2008-03-19
+-------------------------
+- Creation time (-mtc switch) for .7z archives
+- LZMA encoder was converted to ANSI-C
+
+
+4.58 alpha 3 2008-02-25
+-------------------------
+- Speed optimizations for LZMA decoding. Now it uses C code instead of C++.
+- 7-Zip now has 128 MB dictionary limit for 32-bit version:
+ It's for speed optimization: kNumLogBits = 9 + sizeof(size_t) / 2;
+- TAR: 'D' link flag support.
+- 7-Zip now can unpack multivolume RAR archives created with
+ "old style volume names" scheme (-vn switch) and names *.001, *.002, ...
+- Fixed bugs:
+ - 7-Zip FM could not copy / move files to root network folders like \\COMPNAME\FOLDERNAME\
+ In case of move it removed original files.
+ - SFX-WIN: if there are errors, it still could return 0.
+ - ZIP (.XPS file) isZip64 && thisDiskNumber16 == 0xFFFF.
+ - ZIP name updating:
+ If zip file contains extra field and you try to change properties of files,
+ 7-zip tries to delete all extra fileds (except for WzAES).
+ And that code could hang.
+ - 7-Zip GUI didn't suggest BZip2 dictionary size used in previous run.
+ - If creation time stamp was included in .RAR archive, 7-zip used creation time stamp
+ as modification time stamp.
+
+4.58 alpha 2 2007-12-31
+-------------------------
+- Small changes in Deflate and LZMA compression.
+- Some speed optimizations.
+
+
+4.57
+----
+- Bug was fixed:
+ Anti item is created for wrong file:
+ http://sourceforge.net/forum/forum.php?thread_id=1880366&forum_id=45798
+
+
+4.52 beta 2007-07-32
+-------------------------
+- 7-Zip could not decompress some cab files
+- "." dir creating at FAT was fixed / long names
+
+
+4.50 beta 2007-07-24
+-------------------------
+- 7-Zip now replaces unsupported filenames (like "nul", "com1") during extracting.
+- New switch for command line version:
+ -ssc[-] enables/disables case-sensitive mode.
+- 7z.exe l shows archive comment for zip archives
+- Some bugs were fixed: long paths names shorter than 4.
+- Speed optimizations for AES encryption.
+
+
+
+4.56 beta 2007-09-13
+-------------------------
+- some fixes in LZ encoder (LZMA and Deflate) code.
+ size_t was replaces to ptrdiff_t.
+ size_t version worked incorrectly with some compilers.
+
+
+4.46 beta 2007-05-25
+-------------------------
+- CPP Synchronization objects now return HRes (error code) instead of bool.
+
+
+4.45 beta 2007-04-16
+-------------------------
+- 7-Zip now uses C version of CRC, so you must call CrcGenerateTable at
+ stratup code, or you must add CPP/Common/CRC.cpp to your project.
+- Method ID in .7z now is 63-bit integer (UInt64).
+- Open error messages
+- unRar 1.5 fixed
+- unShrink fixed
+- BUG of 4.43 beta and 4.44 beta was fixed.
+ 7-Zip compressing to .zip in multi-threading mode didn't work in some cases.
+
+
+4.44 beta 2007-01-20
+-------------------------
+
+- Bug was fixed: LZMAEncoder.cpp::CEncoder::GetOptimumFast
+ it was:
+ data++
+ fixed version:
+ data = _matchFinder.GetPointerToCurrentPos(_matchFinderObj) - 1;
+ It could lead to very small cpmpression ratio decreasing when block needs move.
+
+
+4.30 beta 2005-11-18
+-------------------------
+- Security.h::AddLockMemoryPrivilege - installs "Large pages" feature
+- MemoryLock.h::EnableLockMemoryPrivilege - enables "Large pages" feature
+- Alloc.h::SetLargePageSize - sets optimal LargePageSize size
+
+
+4.27 2005-09-21
+-------------------------
+- Some GUIDs/interfaces were changed.
+ IStream.h:
+ ISequentialInStream::Read now works as old ReadPart
+ ISequentialOutStream::Write now works as old WritePart
+
+
+4.26 beta 2005-08-05
+-------------------------
+- MyAlloc(0)/BigAlloc(0) now return 0
+
+
+4.25 beta 2005-07-31
+-------------------------
+- More 64-bit compatibilty
+
+
+4.24 beta 2005-07-06
+-------------------------
+- Common\NewHandler.h: using throw() for code size optimization.
+
+
+4.23 2005-06-29
+-------------------------
+- Bug was fixed: memory leak in Cab decoder.
+
+
+4.19 beta 2005-05-21
+-------------------------
+- BZip2 code was rewritten. Now 7-Zip doesn't use original BZip2 code.
+ Old (original) version was moved to folder 7zip/Compress/BZip2Original/
+
+
+4.14 beta 2005-01-11
+-------------------------
+- STL using was reduced
+- 7za now supports Split(001) archves
+
+
+4.10 beta 2004-10-21
+-------------------------
+- Codecs now use new interface: ICompressSetDecoderProperties2
+
+
+4.07 beta 2004-10-03
+-------------------------
+- some interfaces were changed slightly to support
+ -stdin -stdout mode.
+- FilterCoder for simple filters
+- Wildcard censor class was changed.
+- Bug was fixed: when encrypted stream was multiple 16,
+ it used additional 16 empty bytes.
+
+
+3.11 2003-10-06
+-------------------------
+ File functions support unicode strings even
+ on Windows 95/98/ME.
+
+
+3.08.02 2003-09-20
+-------------------------
+ More compatible with GCC.
+
+
+3.08.02 beta 2003-08-20
+-------------------------
+ Extracting bug in 7zExtract.cpp was fixed.
+
+
+3.08 beta 2003-08-19
+-------------------------
+ Big source code reconstruction.
+
+
+2.30 Beta 32 2003-05-15
+-------------------------
+ Small changes in Deflate decoder.
+
+
+2.30 Beta 31 2003-04-29
+-------------------------
+ Common/NewHandler.cpp
+ HeapAlloc in (included to beta 30) was changed to malloc.
+ HeapAlloc worked slower in Win95/98/Me.
+
+
+2.30 Beta 30 2003-04-21
+-------------------------
+ new file: Common/String.cpp
+ Common/NewHandler.* were changed
+
+
+2.30 Beta 29 2003-04-07
+-------------------------
+ Small changes in LZMA code.
+
+
+2.30 Beta 28 2003-02-16
+-------------------------
+ Processing anti-files was corrected.
+
+
+2.30 Beta 27 2003-01-24
+-------------------------
+ Project/Archiver/Format/Common/ArchiveInterface.h:
+ new IArchiveOpenVolumeCallback interface.
+
+
+2.30 Beta 26 2003-01-12
+-------------------------
+ SDK/Interface/PropID.h:
+ kpidComment now is kpidCommented
+
+
+2.30 Beta 25 2003-01-02
+-------------------------
+ Main archive interfaces were changed.
+
+
+2.30 Beta 24 2002-11-01
+-------------------------
+ SDK/Windows/Synchronization.h
+ SDK/Windows/Synchronization.cpp
+ - some changes.
+
+
+2.30 Beta 23 2002-09-07
+-------------------------
+ Project/FileManager folder was added.
+ Notation of some source files was changed.
+
+
+2.30 Beta 22 2002-08-28
+-------------------------
+ Project/FileManager folder was added.
+ Notation of some source files was changed.
+
+
+
+2.30 Beta 21 2002-07-08
+-------------------------
+ Project/Compress/LZ/MatchFinder/BinTree/BinTree.h
+ Project/Compress/LZ/MatchFinder/BinTree/BinTreeMain.h
+ Project/Compress/LZ/MatchFinder/BinTree/HC.h
+ Project/Compress/LZ/MatchFinder/BinTree/HCMain.h
+ - RAM requirements for LZMA (7z) compression were reduced.
+
+
+2.30 Beta 20 2002-07-01
+-------------------------
+- SDK/Stream/WindowOut.h
+ now it uses only required memory (dictionary size).
+- Project/Archiver/Resource
+ contains common resurces
+
+
+2.30 Beta 19 2002-04-11
+-------------------------
+- SDK/Archive/Rar/Handler.cpp
+ supporting RAR29
+
+2.30 Beta 18 2002-03-25
+-------------------------
+- SDK/Archive/Cab/MSZipDecoder.cpp
+ SDK/Archive/Cab/LZXDecoder.cpp:
+ bug with corrupted archives was fixed
+- Project/Compress/LZ/MatchFinder/BinTree/BinTree.h
+- Project/Compress/LZ/MatchFinder/BinTree/BinTreeMain.h
+ some speed optimization (using prefetching)
+
+
+2.30 Beta 17 2002-03-03
+-------------------------
+- ARJ suppport.
+
+
+2.30 Beta 16 2002-02-24
+-------------------------
+- Project/Compress/LZ/LZMA/Decoder.cpp:
+ Bug was fixed: LZMA could not extract more than 4 GB.
+- RPM and CPIO formats.
+- Project/Compress/LZ/LZMA/Encoder.*
+ Project/Archiver/Format/7z/OutHandler.cpp
+ New fast compression mode for LZMA: -m0a=0.
+- New match finders for LZMA: bt4b, hc3, hc4.
+
+
+2.30 Beta 15 2002-02-17
+-------------------------
+- Compression ratio in LZMA was slightly improved:
+ Project/Compress/LZ/LZMA/Encoder.*
+ Project/Archiver/Format/7z/OutHandler.cpp
+
+
+2.30 Beta 14 2002-02-10
+-------------------------
+- Supporting multithreading for LZMA:
+ Project/Compress/LZ/MatchFinder/MT
+- Common/String.h:
+ CStringBase::Replace function was fixed.
+
+
+2.30 Beta 13 2002-01-27
+-------------------------
+- Compress/LZ/MatchFinder/BinTree3.h:
+ method
+- Compress/LZ/MatchFinder/BinTreemain.h:
+ - one VirtualAlloc array was splitted to
+ the for 3 arrays.
+ - Hash-functions were changed.
+
+
+
+2.30 Beta 12 2002-01-16
+-------------------------
+- Compress/LZ/MatchFinder/BinTreemain.h:
+ Compress/LZ/MatchFinder/Patricia.h:
+ Compress/PPM/PPMd/SubAlloc.h:
+ Beta 11 bugs were fixed:
+ - VirtualFree was used incorrectly
+ - checking WIN32 instead _WINDOWS.
+ Compress/LZ/MatchFinder/Patricia.h:
+ Beta 11 bug with deleting m_Hash2Descendants was fixed.
+
+
+2.30 Beta 11 2002-01-15
+-------------------------
+- Compress/LZ/MatchFinder/BinTreemain.h:
+ Compress/LZ/MatchFinder/Patricia.h:
+ Compress/PPM/PPMd/SubAlloc.h:
+ using VirtualAlloc for memory allocating
+- Exlorer/ContextMenu.cpp:
+ Testing supporting.
+ CreateProcess instead WinExec
+- Format/Common/IArchiveHandler.h:
+ Exlorer/ProxyHandler.cpp:
+ FAR/Plugin.cpp:
+ New properties names: Method, HostOS.
+- Exlorer/OverwriteDialog.cpp:
+ FAR/OverwriteDialog.cpp:
+ Windows/PropVariantConversions.h
+ Using National time format was eliminated.
+
+
+
+2.30 Beta 10 2002-01-11
+-------------------------
+- Exlorer/ContextMenu.cpp: bug with context menu on
+ Windows NT4 in Unicode version was fixed.
+- Format/7z/UpdateArchiveEngine.cpp: bug was fixed -
+ Updating in Beta 8 and 9 didn't work.
+- Exlorer/CCompressDialog.cpp: history growing bug was fixed.
+
+
+2.30 Beta 9 2002-01-08
+-------------------------
+- SDK/Common/Vector.h: sopporting sorted object vectors .
+- Lang features.
+- Two new match finders: pat3h and pat4h.
+- SDK/Archive/Zip/InEngine.cpp: bug was fixed.
+- SDK/Windows/FileDir.cpp: function CreateComplexDirectory
+ was changed.
+
diff --git a/DOC/unRarLicense.txt b/DOC/unRarLicense.txt
new file mode 100644
index 0000000..5f78b72
--- /dev/null
+++ b/DOC/unRarLicense.txt
@@ -0,0 +1,41 @@
+ ****** ***** ****** unRAR - free utility for RAR archives
+ ** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ****** ******* ****** License for use and distribution of
+ ** ** ** ** ** ** ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ ** ** ** ** ** ** FREE portable version
+ ~~~~~~~~~~~~~~~~~~~~~
+
+ The source code of unRAR utility is freeware. This means:
+
+ 1. All copyrights to RAR and the utility unRAR are exclusively
+ owned by the author - Alexander Roshal.
+
+ 2. The unRAR sources may be used in any software to handle RAR
+ archives without limitations free of charge, but cannot be used
+ to re-create the RAR compression algorithm, which is proprietary.
+ Distribution of modified unRAR sources in separate form or as a
+ part of other software is permitted, provided that it is clearly
+ stated in the documentation and source comments that the code may
+ not be used to develop a RAR (WinRAR) compatible archiver.
+
+ 3. The unRAR utility may be freely distributed. No person or company
+ may charge a fee for the distribution of unRAR without written
+ permission from the copyright holder.
+
+ 4. THE RAR ARCHIVER AND THE UNRAR UTILITY ARE DISTRIBUTED "AS IS".
+ NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED. YOU USE AT
+ YOUR OWN RISK. THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS,
+ DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING
+ OR MISUSING THIS SOFTWARE.
+
+ 5. Installing and using the unRAR utility signifies acceptance of
+ these terms and conditions of the license.
+
+ 6. If you don't agree with terms of the license you must remove
+ unRAR files from your storage devices and cease to use the
+ utility.
+
+ Thank you for your interest in RAR and unRAR.
+
+
+ Alexander L. Roshal \ No newline at end of file
diff --git a/Java/SevenZip/CRC.java b/Java/SevenZip/CRC.java
deleted file mode 100644
index f2f791f..0000000
--- a/Java/SevenZip/CRC.java
+++ /dev/null
@@ -1,52 +0,0 @@
-// SevenZip/CRC.java
-
-package SevenZip;
-
-public class CRC
-{
- static public int[] Table = new int[256];
-
- static
- {
- for (int i = 0; i < 256; i++)
- {
- int r = i;
- for (int j = 0; j < 8; j++)
- if ((r & 1) != 0)
- r = (r >>> 1) ^ 0xEDB88320;
- else
- r >>>= 1;
- Table[i] = r;
- }
- }
-
- int _value = -1;
-
- public void Init()
- {
- _value = -1;
- }
-
- public void Update(byte[] data, int offset, int size)
- {
- for (int i = 0; i < size; i++)
- _value = Table[(_value ^ data[offset + i]) & 0xFF] ^ (_value >>> 8);
- }
-
- public void Update(byte[] data)
- {
- int size = data.length;
- for (int i = 0; i < size; i++)
- _value = Table[(_value ^ data[i]) & 0xFF] ^ (_value >>> 8);
- }
-
- public void UpdateByte(int b)
- {
- _value = Table[(_value ^ b) & 0xFF] ^ (_value >>> 8);
- }
-
- public int GetDigest()
- {
- return _value ^ (-1);
- }
-}
diff --git a/Java/SevenZip/Compression/LZ/BinTree.java b/Java/SevenZip/Compression/LZ/BinTree.java
deleted file mode 100644
index 63d58c0..0000000
--- a/Java/SevenZip/Compression/LZ/BinTree.java
+++ /dev/null
@@ -1,382 +0,0 @@
-// LZ.BinTree
-
-package SevenZip.Compression.LZ;
-import java.io.IOException;
-
-
-public class BinTree extends InWindow
-{
- int _cyclicBufferPos;
- int _cyclicBufferSize = 0;
- int _matchMaxLen;
-
- int[] _son;
- int[] _hash;
-
- int _cutValue = 0xFF;
- int _hashMask;
- int _hashSizeSum = 0;
-
- boolean HASH_ARRAY = true;
-
- static final int kHash2Size = 1 << 10;
- static final int kHash3Size = 1 << 16;
- static final int kBT2HashSize = 1 << 16;
- static final int kStartMaxLen = 1;
- static final int kHash3Offset = kHash2Size;
- static final int kEmptyHashValue = 0;
- static final int kMaxValForNormalize = (1 << 30) - 1;
-
- int kNumHashDirectBytes = 0;
- int kMinMatchCheck = 4;
- int kFixHashSize = kHash2Size + kHash3Size;
-
- public void SetType(int numHashBytes)
- {
- HASH_ARRAY = (numHashBytes > 2);
- if (HASH_ARRAY)
- {
- kNumHashDirectBytes = 0;
- kMinMatchCheck = 4;
- kFixHashSize = kHash2Size + kHash3Size;
- }
- else
- {
- kNumHashDirectBytes = 2;
- kMinMatchCheck = 2 + 1;
- kFixHashSize = 0;
- }
- }
-
-
-
-
- public void Init() throws IOException
- {
- super.Init();
- for (int i = 0; i < _hashSizeSum; i++)
- _hash[i] = kEmptyHashValue;
- _cyclicBufferPos = 0;
- ReduceOffsets(-1);
- }
-
- public void MovePos() throws IOException
- {
- if (++_cyclicBufferPos >= _cyclicBufferSize)
- _cyclicBufferPos = 0;
- super.MovePos();
- if (_pos == kMaxValForNormalize)
- Normalize();
- }
-
-
-
-
-
-
-
-
- public boolean Create(int historySize, int keepAddBufferBefore,
- int matchMaxLen, int keepAddBufferAfter)
- {
- if (historySize > kMaxValForNormalize - 256)
- return false;
- _cutValue = 16 + (matchMaxLen >> 1);
-
- int windowReservSize = (historySize + keepAddBufferBefore +
- matchMaxLen + keepAddBufferAfter) / 2 + 256;
-
- super.Create(historySize + keepAddBufferBefore, matchMaxLen + keepAddBufferAfter, windowReservSize);
-
- _matchMaxLen = matchMaxLen;
-
- int cyclicBufferSize = historySize + 1;
- if (_cyclicBufferSize != cyclicBufferSize)
- _son = new int[(_cyclicBufferSize = cyclicBufferSize) * 2];
-
- int hs = kBT2HashSize;
-
- if (HASH_ARRAY)
- {
- hs = historySize - 1;
- hs |= (hs >> 1);
- hs |= (hs >> 2);
- hs |= (hs >> 4);
- hs |= (hs >> 8);
- hs >>= 1;
- hs |= 0xFFFF;
- if (hs > (1 << 24))
- hs >>= 1;
- _hashMask = hs;
- hs++;
- hs += kFixHashSize;
- }
- if (hs != _hashSizeSum)
- _hash = new int [_hashSizeSum = hs];
- return true;
- }
- public int GetMatches(int[] distances) throws IOException
- {
- int lenLimit;
- if (_pos + _matchMaxLen <= _streamPos)
- lenLimit = _matchMaxLen;
- else
- {
- lenLimit = _streamPos - _pos;
- if (lenLimit < kMinMatchCheck)
- {
- MovePos();
- return 0;
- }
- }
-
- int offset = 0;
- int matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
- int cur = _bufferOffset + _pos;
- int maxLen = kStartMaxLen; // to avoid items for len < hashSize;
- int hashValue, hash2Value = 0, hash3Value = 0;
-
- if (HASH_ARRAY)
- {
- int temp = CrcTable[_bufferBase[cur] & 0xFF] ^ (_bufferBase[cur + 1] & 0xFF);
- hash2Value = temp & (kHash2Size - 1);
- temp ^= ((int)(_bufferBase[cur + 2] & 0xFF) << 8);
- hash3Value = temp & (kHash3Size - 1);
- hashValue = (temp ^ (CrcTable[_bufferBase[cur + 3] & 0xFF] << 5)) & _hashMask;
- }
- else
- hashValue = ((_bufferBase[cur] & 0xFF) ^ ((int)(_bufferBase[cur + 1] & 0xFF) << 8));
-
- int curMatch = _hash[kFixHashSize + hashValue];
- if (HASH_ARRAY)
- {
- int curMatch2 = _hash[hash2Value];
- int curMatch3 = _hash[kHash3Offset + hash3Value];
- _hash[hash2Value] = _pos;
- _hash[kHash3Offset + hash3Value] = _pos;
- if (curMatch2 > matchMinPos)
- if (_bufferBase[_bufferOffset + curMatch2] == _bufferBase[cur])
- {
- distances[offset++] = maxLen = 2;
- distances[offset++] = _pos - curMatch2 - 1;
- }
- if (curMatch3 > matchMinPos)
- if (_bufferBase[_bufferOffset + curMatch3] == _bufferBase[cur])
- {
- if (curMatch3 == curMatch2)
- offset -= 2;
- distances[offset++] = maxLen = 3;
- distances[offset++] = _pos - curMatch3 - 1;
- curMatch2 = curMatch3;
- }
- if (offset != 0 && curMatch2 == curMatch)
- {
- offset -= 2;
- maxLen = kStartMaxLen;
- }
- }
-
- _hash[kFixHashSize + hashValue] = _pos;
-
- int ptr0 = (_cyclicBufferPos << 1) + 1;
- int ptr1 = (_cyclicBufferPos << 1);
-
- int len0, len1;
- len0 = len1 = kNumHashDirectBytes;
-
- if (kNumHashDirectBytes != 0)
- {
- if (curMatch > matchMinPos)
- {
- if (_bufferBase[_bufferOffset + curMatch + kNumHashDirectBytes] !=
- _bufferBase[cur + kNumHashDirectBytes])
- {
- distances[offset++] = maxLen = kNumHashDirectBytes;
- distances[offset++] = _pos - curMatch - 1;
- }
- }
- }
-
- int count = _cutValue;
-
- while (true)
- {
- if (curMatch <= matchMinPos || count-- == 0)
- {
- _son[ptr0] = _son[ptr1] = kEmptyHashValue;
- break;
- }
- int delta = _pos - curMatch;
- int cyclicPos = ((delta <= _cyclicBufferPos) ?
- (_cyclicBufferPos - delta) :
- (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
-
- int pby1 = _bufferOffset + curMatch;
- int len = Math.min(len0, len1);
- if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
- {
- while(++len != lenLimit)
- if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
- break;
- if (maxLen < len)
- {
- distances[offset++] = maxLen = len;
- distances[offset++] = delta - 1;
- if (len == lenLimit)
- {
- _son[ptr1] = _son[cyclicPos];
- _son[ptr0] = _son[cyclicPos + 1];
- break;
- }
- }
- }
- if ((_bufferBase[pby1 + len] & 0xFF) < (_bufferBase[cur + len] & 0xFF))
- {
- _son[ptr1] = curMatch;
- ptr1 = cyclicPos + 1;
- curMatch = _son[ptr1];
- len1 = len;
- }
- else
- {
- _son[ptr0] = curMatch;
- ptr0 = cyclicPos;
- curMatch = _son[ptr0];
- len0 = len;
- }
- }
- MovePos();
- return offset;
- }
-
- public void Skip(int num) throws IOException
- {
- do
- {
- int lenLimit;
- if (_pos + _matchMaxLen <= _streamPos)
- lenLimit = _matchMaxLen;
- else
- {
- lenLimit = _streamPos - _pos;
- if (lenLimit < kMinMatchCheck)
- {
- MovePos();
- continue;
- }
- }
-
- int matchMinPos = (_pos > _cyclicBufferSize) ? (_pos - _cyclicBufferSize) : 0;
- int cur = _bufferOffset + _pos;
-
- int hashValue;
-
- if (HASH_ARRAY)
- {
- int temp = CrcTable[_bufferBase[cur] & 0xFF] ^ (_bufferBase[cur + 1] & 0xFF);
- int hash2Value = temp & (kHash2Size - 1);
- _hash[hash2Value] = _pos;
- temp ^= ((int)(_bufferBase[cur + 2] & 0xFF) << 8);
- int hash3Value = temp & (kHash3Size - 1);
- _hash[kHash3Offset + hash3Value] = _pos;
- hashValue = (temp ^ (CrcTable[_bufferBase[cur + 3] & 0xFF] << 5)) & _hashMask;
- }
- else
- hashValue = ((_bufferBase[cur] & 0xFF) ^ ((int)(_bufferBase[cur + 1] & 0xFF) << 8));
-
- int curMatch = _hash[kFixHashSize + hashValue];
- _hash[kFixHashSize + hashValue] = _pos;
-
- int ptr0 = (_cyclicBufferPos << 1) + 1;
- int ptr1 = (_cyclicBufferPos << 1);
-
- int len0, len1;
- len0 = len1 = kNumHashDirectBytes;
-
- int count = _cutValue;
- while (true)
- {
- if (curMatch <= matchMinPos || count-- == 0)
- {
- _son[ptr0] = _son[ptr1] = kEmptyHashValue;
- break;
- }
-
- int delta = _pos - curMatch;
- int cyclicPos = ((delta <= _cyclicBufferPos) ?
- (_cyclicBufferPos - delta) :
- (_cyclicBufferPos - delta + _cyclicBufferSize)) << 1;
-
- int pby1 = _bufferOffset + curMatch;
- int len = Math.min(len0, len1);
- if (_bufferBase[pby1 + len] == _bufferBase[cur + len])
- {
- while (++len != lenLimit)
- if (_bufferBase[pby1 + len] != _bufferBase[cur + len])
- break;
- if (len == lenLimit)
- {
- _son[ptr1] = _son[cyclicPos];
- _son[ptr0] = _son[cyclicPos + 1];
- break;
- }
- }
- if ((_bufferBase[pby1 + len] & 0xFF) < (_bufferBase[cur + len] & 0xFF))
- {
- _son[ptr1] = curMatch;
- ptr1 = cyclicPos + 1;
- curMatch = _son[ptr1];
- len1 = len;
- }
- else
- {
- _son[ptr0] = curMatch;
- ptr0 = cyclicPos;
- curMatch = _son[ptr0];
- len0 = len;
- }
- }
- MovePos();
- }
- while (--num != 0);
- }
-
- void NormalizeLinks(int[] items, int numItems, int subValue)
- {
- for (int i = 0; i < numItems; i++)
- {
- int value = items[i];
- if (value <= subValue)
- value = kEmptyHashValue;
- else
- value -= subValue;
- items[i] = value;
- }
- }
-
- void Normalize()
- {
- int subValue = _pos - _cyclicBufferSize;
- NormalizeLinks(_son, _cyclicBufferSize * 2, subValue);
- NormalizeLinks(_hash, _hashSizeSum, subValue);
- ReduceOffsets(subValue);
- }
-
- public void SetCutValue(int cutValue) { _cutValue = cutValue; }
-
- private static final int[] CrcTable = new int[256];
-
- static
- {
- for (int i = 0; i < 256; i++)
- {
- int r = i;
- for (int j = 0; j < 8; j++)
- if ((r & 1) != 0)
- r = (r >>> 1) ^ 0xEDB88320;
- else
- r >>>= 1;
- CrcTable[i] = r;
- }
- }
-}
diff --git a/Java/SevenZip/Compression/LZ/InWindow.java b/Java/SevenZip/Compression/LZ/InWindow.java
deleted file mode 100644
index 5f3f0b4..0000000
--- a/Java/SevenZip/Compression/LZ/InWindow.java
+++ /dev/null
@@ -1,131 +0,0 @@
-// LZ.InWindow
-
-package SevenZip.Compression.LZ;
-
-import java.io.IOException;
-
-public class InWindow
-{
- public byte[] _bufferBase; // pointer to buffer with data
- java.io.InputStream _stream;
- int _posLimit; // offset (from _buffer) of first byte when new block reading must be done
- boolean _streamEndWasReached; // if (true) then _streamPos shows real end of stream
-
- int _pointerToLastSafePosition;
-
- public int _bufferOffset;
-
- public int _blockSize; // Size of Allocated memory block
- public int _pos; // offset (from _buffer) of curent byte
- int _keepSizeBefore; // how many BYTEs must be kept in buffer before _pos
- int _keepSizeAfter; // how many BYTEs must be kept buffer after _pos
- public int _streamPos; // offset (from _buffer) of first not read byte from Stream
-
- public void MoveBlock()
- {
- int offset = _bufferOffset + _pos - _keepSizeBefore;
- // we need one additional byte, since MovePos moves on 1 byte.
- if (offset > 0)
- offset--;
-
- int numBytes = _bufferOffset + _streamPos - offset;
-
- // check negative offset ????
- for (int i = 0; i < numBytes; i++)
- _bufferBase[i] = _bufferBase[offset + i];
- _bufferOffset -= offset;
- }
-
- public void ReadBlock() throws IOException
- {
- if (_streamEndWasReached)
- return;
- while (true)
- {
- int size = (0 - _bufferOffset) + _blockSize - _streamPos;
- if (size == 0)
- return;
- int numReadBytes = _stream.read(_bufferBase, _bufferOffset + _streamPos, size);
- if (numReadBytes == -1)
- {
- _posLimit = _streamPos;
- int pointerToPostion = _bufferOffset + _posLimit;
- if (pointerToPostion > _pointerToLastSafePosition)
- _posLimit = _pointerToLastSafePosition - _bufferOffset;
-
- _streamEndWasReached = true;
- return;
- }
- _streamPos += numReadBytes;
- if (_streamPos >= _pos + _keepSizeAfter)
- _posLimit = _streamPos - _keepSizeAfter;
- }
- }
-
- void Free() { _bufferBase = null; }
-
- public void Create(int keepSizeBefore, int keepSizeAfter, int keepSizeReserv)
- {
- _keepSizeBefore = keepSizeBefore;
- _keepSizeAfter = keepSizeAfter;
- int blockSize = keepSizeBefore + keepSizeAfter + keepSizeReserv;
- if (_bufferBase == null || _blockSize != blockSize)
- {
- Free();
- _blockSize = blockSize;
- _bufferBase = new byte[_blockSize];
- }
- _pointerToLastSafePosition = _blockSize - keepSizeAfter;
- }
-
- public void SetStream(java.io.InputStream stream) { _stream = stream; }
- public void ReleaseStream() { _stream = null; }
-
- public void Init() throws IOException
- {
- _bufferOffset = 0;
- _pos = 0;
- _streamPos = 0;
- _streamEndWasReached = false;
- ReadBlock();
- }
-
- public void MovePos() throws IOException
- {
- _pos++;
- if (_pos > _posLimit)
- {
- int pointerToPostion = _bufferOffset + _pos;
- if (pointerToPostion > _pointerToLastSafePosition)
- MoveBlock();
- ReadBlock();
- }
- }
-
- public byte GetIndexByte(int index) { return _bufferBase[_bufferOffset + _pos + index]; }
-
- // index + limit have not to exceed _keepSizeAfter;
- public int GetMatchLen(int index, int distance, int limit)
- {
- if (_streamEndWasReached)
- if ((_pos + index) + limit > _streamPos)
- limit = _streamPos - (_pos + index);
- distance++;
- // Byte *pby = _buffer + (size_t)_pos + index;
- int pby = _bufferOffset + _pos + index;
-
- int i;
- for (i = 0; i < limit && _bufferBase[pby + i] == _bufferBase[pby + i - distance]; i++);
- return i;
- }
-
- public int GetNumAvailableBytes() { return _streamPos - _pos; }
-
- public void ReduceOffsets(int subValue)
- {
- _bufferOffset += subValue;
- _posLimit -= subValue;
- _pos -= subValue;
- _streamPos -= subValue;
- }
-}
diff --git a/Java/SevenZip/Compression/LZ/OutWindow.java b/Java/SevenZip/Compression/LZ/OutWindow.java
deleted file mode 100644
index 620cb41..0000000
--- a/Java/SevenZip/Compression/LZ/OutWindow.java
+++ /dev/null
@@ -1,85 +0,0 @@
-// LZ.OutWindow
-
-package SevenZip.Compression.LZ;
-
-import java.io.IOException;
-
-public class OutWindow
-{
- byte[] _buffer;
- int _pos;
- int _windowSize = 0;
- int _streamPos;
- java.io.OutputStream _stream;
-
- public void Create(int windowSize)
- {
- if (_buffer == null || _windowSize != windowSize)
- _buffer = new byte[windowSize];
- _windowSize = windowSize;
- _pos = 0;
- _streamPos = 0;
- }
-
- public void SetStream(java.io.OutputStream stream) throws IOException
- {
- ReleaseStream();
- _stream = stream;
- }
-
- public void ReleaseStream() throws IOException
- {
- Flush();
- _stream = null;
- }
-
- public void Init(boolean solid)
- {
- if (!solid)
- {
- _streamPos = 0;
- _pos = 0;
- }
- }
-
- public void Flush() throws IOException
- {
- int size = _pos - _streamPos;
- if (size == 0)
- return;
- _stream.write(_buffer, _streamPos, size);
- if (_pos >= _windowSize)
- _pos = 0;
- _streamPos = _pos;
- }
-
- public void CopyBlock(int distance, int len) throws IOException
- {
- int pos = _pos - distance - 1;
- if (pos < 0)
- pos += _windowSize;
- for (; len != 0; len--)
- {
- if (pos >= _windowSize)
- pos = 0;
- _buffer[_pos++] = _buffer[pos++];
- if (_pos >= _windowSize)
- Flush();
- }
- }
-
- public void PutByte(byte b) throws IOException
- {
- _buffer[_pos++] = b;
- if (_pos >= _windowSize)
- Flush();
- }
-
- public byte GetByte(int distance)
- {
- int pos = _pos - distance - 1;
- if (pos < 0)
- pos += _windowSize;
- return _buffer[pos];
- }
-}
diff --git a/Java/SevenZip/Compression/LZMA/Base.java b/Java/SevenZip/Compression/LZMA/Base.java
deleted file mode 100644
index 18deed9..0000000
--- a/Java/SevenZip/Compression/LZMA/Base.java
+++ /dev/null
@@ -1,88 +0,0 @@
-// Base.java
-
-package SevenZip.Compression.LZMA;
-
-public class Base
-{
- public static final int kNumRepDistances = 4;
- public static final int kNumStates = 12;
-
- public static final int StateInit()
- {
- return 0;
- }
-
- public static final int StateUpdateChar(int index)
- {
- if (index < 4)
- return 0;
- if (index < 10)
- return index - 3;
- return index - 6;
- }
-
- public static final int StateUpdateMatch(int index)
- {
- return (index < 7 ? 7 : 10);
- }
-
- public static final int StateUpdateRep(int index)
- {
- return (index < 7 ? 8 : 11);
- }
-
- public static final int StateUpdateShortRep(int index)
- {
- return (index < 7 ? 9 : 11);
- }
-
- public static final boolean StateIsCharState(int index)
- {
- return index < 7;
- }
-
- public static final int kNumPosSlotBits = 6;
- public static final int kDicLogSizeMin = 0;
- // public static final int kDicLogSizeMax = 28;
- // public static final int kDistTableSizeMax = kDicLogSizeMax * 2;
-
- public static final int kNumLenToPosStatesBits = 2; // it's for speed optimization
- public static final int kNumLenToPosStates = 1 << kNumLenToPosStatesBits;
-
- public static final int kMatchMinLen = 2;
-
- public static final int GetLenToPosState(int len)
- {
- len -= kMatchMinLen;
- if (len < kNumLenToPosStates)
- return len;
- return (int)(kNumLenToPosStates - 1);
- }
-
- public static final int kNumAlignBits = 4;
- public static final int kAlignTableSize = 1 << kNumAlignBits;
- public static final int kAlignMask = (kAlignTableSize - 1);
-
- public static final int kStartPosModelIndex = 4;
- public static final int kEndPosModelIndex = 14;
- public static final int kNumPosModels = kEndPosModelIndex - kStartPosModelIndex;
-
- public static final int kNumFullDistances = 1 << (kEndPosModelIndex / 2);
-
- public static final int kNumLitPosStatesBitsEncodingMax = 4;
- public static final int kNumLitContextBitsMax = 8;
-
- public static final int kNumPosStatesBitsMax = 4;
- public static final int kNumPosStatesMax = (1 << kNumPosStatesBitsMax);
- public static final int kNumPosStatesBitsEncodingMax = 4;
- public static final int kNumPosStatesEncodingMax = (1 << kNumPosStatesBitsEncodingMax);
-
- public static final int kNumLowLenBits = 3;
- public static final int kNumMidLenBits = 3;
- public static final int kNumHighLenBits = 8;
- public static final int kNumLowLenSymbols = 1 << kNumLowLenBits;
- public static final int kNumMidLenSymbols = 1 << kNumMidLenBits;
- public static final int kNumLenSymbols = kNumLowLenSymbols + kNumMidLenSymbols +
- (1 << kNumHighLenBits);
- public static final int kMatchMaxLen = kMatchMinLen + kNumLenSymbols - 1;
-}
diff --git a/Java/SevenZip/Compression/LZMA/Decoder.java b/Java/SevenZip/Compression/LZMA/Decoder.java
deleted file mode 100644
index 4ebd571..0000000
--- a/Java/SevenZip/Compression/LZMA/Decoder.java
+++ /dev/null
@@ -1,329 +0,0 @@
-package SevenZip.Compression.LZMA;
-
-import SevenZip.Compression.RangeCoder.BitTreeDecoder;
-import SevenZip.Compression.LZMA.Base;
-import SevenZip.Compression.LZ.OutWindow;
-import java.io.IOException;
-
-public class Decoder
-{
- class LenDecoder
- {
- short[] m_Choice = new short[2];
- BitTreeDecoder[] m_LowCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
- BitTreeDecoder[] m_MidCoder = new BitTreeDecoder[Base.kNumPosStatesMax];
- BitTreeDecoder m_HighCoder = new BitTreeDecoder(Base.kNumHighLenBits);
- int m_NumPosStates = 0;
-
- public void Create(int numPosStates)
- {
- for (; m_NumPosStates < numPosStates; m_NumPosStates++)
- {
- m_LowCoder[m_NumPosStates] = new BitTreeDecoder(Base.kNumLowLenBits);
- m_MidCoder[m_NumPosStates] = new BitTreeDecoder(Base.kNumMidLenBits);
- }
- }
-
- public void Init()
- {
- SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_Choice);
- for (int posState = 0; posState < m_NumPosStates; posState++)
- {
- m_LowCoder[posState].Init();
- m_MidCoder[posState].Init();
- }
- m_HighCoder.Init();
- }
-
- public int Decode(SevenZip.Compression.RangeCoder.Decoder rangeDecoder, int posState) throws IOException
- {
- if (rangeDecoder.DecodeBit(m_Choice, 0) == 0)
- return m_LowCoder[posState].Decode(rangeDecoder);
- int symbol = Base.kNumLowLenSymbols;
- if (rangeDecoder.DecodeBit(m_Choice, 1) == 0)
- symbol += m_MidCoder[posState].Decode(rangeDecoder);
- else
- symbol += Base.kNumMidLenSymbols + m_HighCoder.Decode(rangeDecoder);
- return symbol;
- }
- }
-
- class LiteralDecoder
- {
- class Decoder2
- {
- short[] m_Decoders = new short[0x300];
-
- public void Init()
- {
- SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_Decoders);
- }
-
- public byte DecodeNormal(SevenZip.Compression.RangeCoder.Decoder rangeDecoder) throws IOException
- {
- int symbol = 1;
- do
- symbol = (symbol << 1) | rangeDecoder.DecodeBit(m_Decoders, symbol);
- while (symbol < 0x100);
- return (byte)symbol;
- }
-
- public byte DecodeWithMatchByte(SevenZip.Compression.RangeCoder.Decoder rangeDecoder, byte matchByte) throws IOException
- {
- int symbol = 1;
- do
- {
- int matchBit = (matchByte >> 7) & 1;
- matchByte <<= 1;
- int bit = rangeDecoder.DecodeBit(m_Decoders, ((1 + matchBit) << 8) + symbol);
- symbol = (symbol << 1) | bit;
- if (matchBit != bit)
- {
- while (symbol < 0x100)
- symbol = (symbol << 1) | rangeDecoder.DecodeBit(m_Decoders, symbol);
- break;
- }
- }
- while (symbol < 0x100);
- return (byte)symbol;
- }
- }
-
- Decoder2[] m_Coders;
- int m_NumPrevBits;
- int m_NumPosBits;
- int m_PosMask;
-
- public void Create(int numPosBits, int numPrevBits)
- {
- if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits)
- return;
- m_NumPosBits = numPosBits;
- m_PosMask = (1 << numPosBits) - 1;
- m_NumPrevBits = numPrevBits;
- int numStates = 1 << (m_NumPrevBits + m_NumPosBits);
- m_Coders = new Decoder2[numStates];
- for (int i = 0; i < numStates; i++)
- m_Coders[i] = new Decoder2();
- }
-
- public void Init()
- {
- int numStates = 1 << (m_NumPrevBits + m_NumPosBits);
- for (int i = 0; i < numStates; i++)
- m_Coders[i].Init();
- }
-
- Decoder2 GetDecoder(int pos, byte prevByte)
- {
- return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + ((prevByte & 0xFF) >>> (8 - m_NumPrevBits))];
- }
- }
-
- OutWindow m_OutWindow = new OutWindow();
- SevenZip.Compression.RangeCoder.Decoder m_RangeDecoder = new SevenZip.Compression.RangeCoder.Decoder();
-
- short[] m_IsMatchDecoders = new short[Base.kNumStates << Base.kNumPosStatesBitsMax];
- short[] m_IsRepDecoders = new short[Base.kNumStates];
- short[] m_IsRepG0Decoders = new short[Base.kNumStates];
- short[] m_IsRepG1Decoders = new short[Base.kNumStates];
- short[] m_IsRepG2Decoders = new short[Base.kNumStates];
- short[] m_IsRep0LongDecoders = new short[Base.kNumStates << Base.kNumPosStatesBitsMax];
-
- BitTreeDecoder[] m_PosSlotDecoder = new BitTreeDecoder[Base.kNumLenToPosStates];
- short[] m_PosDecoders = new short[Base.kNumFullDistances - Base.kEndPosModelIndex];
-
- BitTreeDecoder m_PosAlignDecoder = new BitTreeDecoder(Base.kNumAlignBits);
-
- LenDecoder m_LenDecoder = new LenDecoder();
- LenDecoder m_RepLenDecoder = new LenDecoder();
-
- LiteralDecoder m_LiteralDecoder = new LiteralDecoder();
-
- int m_DictionarySize = -1;
- int m_DictionarySizeCheck = -1;
-
- int m_PosStateMask;
-
- public Decoder()
- {
- for (int i = 0; i < Base.kNumLenToPosStates; i++)
- m_PosSlotDecoder[i] = new BitTreeDecoder(Base.kNumPosSlotBits);
- }
-
- boolean SetDictionarySize(int dictionarySize)
- {
- if (dictionarySize < 0)
- return false;
- if (m_DictionarySize != dictionarySize)
- {
- m_DictionarySize = dictionarySize;
- m_DictionarySizeCheck = Math.max(m_DictionarySize, 1);
- m_OutWindow.Create(Math.max(m_DictionarySizeCheck, (1 << 12)));
- }
- return true;
- }
-
- boolean SetLcLpPb(int lc, int lp, int pb)
- {
- if (lc > Base.kNumLitContextBitsMax || lp > 4 || pb > Base.kNumPosStatesBitsMax)
- return false;
- m_LiteralDecoder.Create(lp, lc);
- int numPosStates = 1 << pb;
- m_LenDecoder.Create(numPosStates);
- m_RepLenDecoder.Create(numPosStates);
- m_PosStateMask = numPosStates - 1;
- return true;
- }
-
- void Init() throws IOException
- {
- m_OutWindow.Init(false);
-
- SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsMatchDecoders);
- SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRep0LongDecoders);
- SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRepDecoders);
- SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRepG0Decoders);
- SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRepG1Decoders);
- SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_IsRepG2Decoders);
- SevenZip.Compression.RangeCoder.Decoder.InitBitModels(m_PosDecoders);
-
- m_LiteralDecoder.Init();
- int i;
- for (i = 0; i < Base.kNumLenToPosStates; i++)
- m_PosSlotDecoder[i].Init();
- m_LenDecoder.Init();
- m_RepLenDecoder.Init();
- m_PosAlignDecoder.Init();
- m_RangeDecoder.Init();
- }
-
- public boolean Code(java.io.InputStream inStream, java.io.OutputStream outStream,
- long outSize) throws IOException
- {
- m_RangeDecoder.SetStream(inStream);
- m_OutWindow.SetStream(outStream);
- Init();
-
- int state = Base.StateInit();
- int rep0 = 0, rep1 = 0, rep2 = 0, rep3 = 0;
-
- long nowPos64 = 0;
- byte prevByte = 0;
- while (outSize < 0 || nowPos64 < outSize)
- {
- int posState = (int)nowPos64 & m_PosStateMask;
- if (m_RangeDecoder.DecodeBit(m_IsMatchDecoders, (state << Base.kNumPosStatesBitsMax) + posState) == 0)
- {
- LiteralDecoder.Decoder2 decoder2 = m_LiteralDecoder.GetDecoder((int)nowPos64, prevByte);
- if (!Base.StateIsCharState(state))
- prevByte = decoder2.DecodeWithMatchByte(m_RangeDecoder, m_OutWindow.GetByte(rep0));
- else
- prevByte = decoder2.DecodeNormal(m_RangeDecoder);
- m_OutWindow.PutByte(prevByte);
- state = Base.StateUpdateChar(state);
- nowPos64++;
- }
- else
- {
- int len;
- if (m_RangeDecoder.DecodeBit(m_IsRepDecoders, state) == 1)
- {
- len = 0;
- if (m_RangeDecoder.DecodeBit(m_IsRepG0Decoders, state) == 0)
- {
- if (m_RangeDecoder.DecodeBit(m_IsRep0LongDecoders, (state << Base.kNumPosStatesBitsMax) + posState) == 0)
- {
- state = Base.StateUpdateShortRep(state);
- len = 1;
- }
- }
- else
- {
- int distance;
- if (m_RangeDecoder.DecodeBit(m_IsRepG1Decoders, state) == 0)
- distance = rep1;
- else
- {
- if (m_RangeDecoder.DecodeBit(m_IsRepG2Decoders, state) == 0)
- distance = rep2;
- else
- {
- distance = rep3;
- rep3 = rep2;
- }
- rep2 = rep1;
- }
- rep1 = rep0;
- rep0 = distance;
- }
- if (len == 0)
- {
- len = m_RepLenDecoder.Decode(m_RangeDecoder, posState) + Base.kMatchMinLen;
- state = Base.StateUpdateRep(state);
- }
- }
- else
- {
- rep3 = rep2;
- rep2 = rep1;
- rep1 = rep0;
- len = Base.kMatchMinLen + m_LenDecoder.Decode(m_RangeDecoder, posState);
- state = Base.StateUpdateMatch(state);
- int posSlot = m_PosSlotDecoder[Base.GetLenToPosState(len)].Decode(m_RangeDecoder);
- if (posSlot >= Base.kStartPosModelIndex)
- {
- int numDirectBits = (posSlot >> 1) - 1;
- rep0 = ((2 | (posSlot & 1)) << numDirectBits);
- if (posSlot < Base.kEndPosModelIndex)
- rep0 += BitTreeDecoder.ReverseDecode(m_PosDecoders,
- rep0 - posSlot - 1, m_RangeDecoder, numDirectBits);
- else
- {
- rep0 += (m_RangeDecoder.DecodeDirectBits(
- numDirectBits - Base.kNumAlignBits) << Base.kNumAlignBits);
- rep0 += m_PosAlignDecoder.ReverseDecode(m_RangeDecoder);
- if (rep0 < 0)
- {
- if (rep0 == -1)
- break;
- return false;
- }
- }
- }
- else
- rep0 = posSlot;
- }
- if (rep0 >= nowPos64 || rep0 >= m_DictionarySizeCheck)
- {
- // m_OutWindow.Flush();
- return false;
- }
- m_OutWindow.CopyBlock(rep0, len);
- nowPos64 += len;
- prevByte = m_OutWindow.GetByte(0);
- }
- }
- m_OutWindow.Flush();
- m_OutWindow.ReleaseStream();
- m_RangeDecoder.ReleaseStream();
- return true;
- }
-
- public boolean SetDecoderProperties(byte[] properties)
- {
- if (properties.length < 5)
- return false;
- int val = properties[0] & 0xFF;
- int lc = val % 9;
- int remainder = val / 9;
- int lp = remainder % 5;
- int pb = remainder / 5;
- int dictionarySize = 0;
- for (int i = 0; i < 4; i++)
- dictionarySize += ((int)(properties[1 + i]) & 0xFF) << (i * 8);
- if (!SetLcLpPb(lc, lp, pb))
- return false;
- return SetDictionarySize(dictionarySize);
- }
-}
diff --git a/Java/SevenZip/Compression/LZMA/Encoder.java b/Java/SevenZip/Compression/LZMA/Encoder.java
deleted file mode 100644
index 771fb21..0000000
--- a/Java/SevenZip/Compression/LZMA/Encoder.java
+++ /dev/null
@@ -1,1416 +0,0 @@
-package SevenZip.Compression.LZMA;
-
-import SevenZip.Compression.RangeCoder.BitTreeEncoder;
-import SevenZip.Compression.LZMA.Base;
-import SevenZip.Compression.LZ.BinTree;
-import SevenZip.ICodeProgress;
-import java.io.IOException;
-
-public class Encoder
-{
- public static final int EMatchFinderTypeBT2 = 0;
- public static final int EMatchFinderTypeBT4 = 1;
-
-
-
-
- static final int kIfinityPrice = 0xFFFFFFF;
-
- static byte[] g_FastPos = new byte[1 << 11];
-
- static
- {
- int kFastSlots = 22;
- int c = 2;
- g_FastPos[0] = 0;
- g_FastPos[1] = 1;
- for (int slotFast = 2; slotFast < kFastSlots; slotFast++)
- {
- int k = (1 << ((slotFast >> 1) - 1));
- for (int j = 0; j < k; j++, c++)
- g_FastPos[c] = (byte)slotFast;
- }
- }
-
- static int GetPosSlot(int pos)
- {
- if (pos < (1 << 11))
- return g_FastPos[pos];
- if (pos < (1 << 21))
- return (g_FastPos[pos >> 10] + 20);
- return (g_FastPos[pos >> 20] + 40);
- }
-
- static int GetPosSlot2(int pos)
- {
- if (pos < (1 << 17))
- return (g_FastPos[pos >> 6] + 12);
- if (pos < (1 << 27))
- return (g_FastPos[pos >> 16] + 32);
- return (g_FastPos[pos >> 26] + 52);
- }
-
- int _state = Base.StateInit();
- byte _previousByte;
- int[] _repDistances = new int[Base.kNumRepDistances];
-
- void BaseInit()
- {
- _state = Base.StateInit();
- _previousByte = 0;
- for (int i = 0; i < Base.kNumRepDistances; i++)
- _repDistances[i] = 0;
- }
-
- static final int kDefaultDictionaryLogSize = 22;
- static final int kNumFastBytesDefault = 0x20;
-
- class LiteralEncoder
- {
- class Encoder2
- {
- short[] m_Encoders = new short[0x300];
-
- public void Init() { SevenZip.Compression.RangeCoder.Encoder.InitBitModels(m_Encoders); }
-
-
-
- public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, byte symbol) throws IOException
- {
- int context = 1;
- for (int i = 7; i >= 0; i--)
- {
- int bit = ((symbol >> i) & 1);
- rangeEncoder.Encode(m_Encoders, context, bit);
- context = (context << 1) | bit;
- }
- }
-
- public void EncodeMatched(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, byte matchByte, byte symbol) throws IOException
- {
- int context = 1;
- boolean same = true;
- for (int i = 7; i >= 0; i--)
- {
- int bit = ((symbol >> i) & 1);
- int state = context;
- if (same)
- {
- int matchBit = ((matchByte >> i) & 1);
- state += ((1 + matchBit) << 8);
- same = (matchBit == bit);
- }
- rangeEncoder.Encode(m_Encoders, state, bit);
- context = (context << 1) | bit;
- }
- }
-
- public int GetPrice(boolean matchMode, byte matchByte, byte symbol)
- {
- int price = 0;
- int context = 1;
- int i = 7;
- if (matchMode)
- {
- for (; i >= 0; i--)
- {
- int matchBit = (matchByte >> i) & 1;
- int bit = (symbol >> i) & 1;
- price += SevenZip.Compression.RangeCoder.Encoder.GetPrice(m_Encoders[((1 + matchBit) << 8) + context], bit);
- context = (context << 1) | bit;
- if (matchBit != bit)
- {
- i--;
- break;
- }
- }
- }
- for (; i >= 0; i--)
- {
- int bit = (symbol >> i) & 1;
- price += SevenZip.Compression.RangeCoder.Encoder.GetPrice(m_Encoders[context], bit);
- context = (context << 1) | bit;
- }
- return price;
- }
- }
-
- Encoder2[] m_Coders;
- int m_NumPrevBits;
- int m_NumPosBits;
- int m_PosMask;
-
- public void Create(int numPosBits, int numPrevBits)
- {
- if (m_Coders != null && m_NumPrevBits == numPrevBits && m_NumPosBits == numPosBits)
- return;
- m_NumPosBits = numPosBits;
- m_PosMask = (1 << numPosBits) - 1;
- m_NumPrevBits = numPrevBits;
- int numStates = 1 << (m_NumPrevBits + m_NumPosBits);
- m_Coders = new Encoder2[numStates];
- for (int i = 0; i < numStates; i++)
- m_Coders[i] = new Encoder2();
- }
-
- public void Init()
- {
- int numStates = 1 << (m_NumPrevBits + m_NumPosBits);
- for (int i = 0; i < numStates; i++)
- m_Coders[i].Init();
- }
-
- public Encoder2 GetSubCoder(int pos, byte prevByte)
- { return m_Coders[((pos & m_PosMask) << m_NumPrevBits) + ((prevByte & 0xFF) >>> (8 - m_NumPrevBits))]; }
- }
-
- class LenEncoder
- {
- short[] _choice = new short[2];
- BitTreeEncoder[] _lowCoder = new BitTreeEncoder[Base.kNumPosStatesEncodingMax];
- BitTreeEncoder[] _midCoder = new BitTreeEncoder[Base.kNumPosStatesEncodingMax];
- BitTreeEncoder _highCoder = new BitTreeEncoder(Base.kNumHighLenBits);
-
-
- public LenEncoder()
- {
- for (int posState = 0; posState < Base.kNumPosStatesEncodingMax; posState++)
- {
- _lowCoder[posState] = new BitTreeEncoder(Base.kNumLowLenBits);
- _midCoder[posState] = new BitTreeEncoder(Base.kNumMidLenBits);
- }
- }
-
- public void Init(int numPosStates)
- {
- SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_choice);
-
- for (int posState = 0; posState < numPosStates; posState++)
- {
- _lowCoder[posState].Init();
- _midCoder[posState].Init();
- }
- _highCoder.Init();
- }
-
- public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, int symbol, int posState) throws IOException
- {
- if (symbol < Base.kNumLowLenSymbols)
- {
- rangeEncoder.Encode(_choice, 0, 0);
- _lowCoder[posState].Encode(rangeEncoder, symbol);
- }
- else
- {
- symbol -= Base.kNumLowLenSymbols;
- rangeEncoder.Encode(_choice, 0, 1);
- if (symbol < Base.kNumMidLenSymbols)
- {
- rangeEncoder.Encode(_choice, 1, 0);
- _midCoder[posState].Encode(rangeEncoder, symbol);
- }
- else
- {
- rangeEncoder.Encode(_choice, 1, 1);
- _highCoder.Encode(rangeEncoder, symbol - Base.kNumMidLenSymbols);
- }
- }
- }
-
- public void SetPrices(int posState, int numSymbols, int[] prices, int st)
- {
- int a0 = SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_choice[0]);
- int a1 = SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_choice[0]);
- int b0 = a1 + SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_choice[1]);
- int b1 = a1 + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_choice[1]);
- int i = 0;
- for (i = 0; i < Base.kNumLowLenSymbols; i++)
- {
- if (i >= numSymbols)
- return;
- prices[st + i] = a0 + _lowCoder[posState].GetPrice(i);
- }
- for (; i < Base.kNumLowLenSymbols + Base.kNumMidLenSymbols; i++)
- {
- if (i >= numSymbols)
- return;
- prices[st + i] = b0 + _midCoder[posState].GetPrice(i - Base.kNumLowLenSymbols);
- }
- for (; i < numSymbols; i++)
- prices[st + i] = b1 + _highCoder.GetPrice(i - Base.kNumLowLenSymbols - Base.kNumMidLenSymbols);
- }
- };
-
- public static final int kNumLenSpecSymbols = Base.kNumLowLenSymbols + Base.kNumMidLenSymbols;
-
- class LenPriceTableEncoder extends LenEncoder
- {
- int[] _prices = new int[Base.kNumLenSymbols<<Base.kNumPosStatesBitsEncodingMax];
- int _tableSize;
- int[] _counters = new int[Base.kNumPosStatesEncodingMax];
-
- public void SetTableSize(int tableSize) { _tableSize = tableSize; }
-
- public int GetPrice(int symbol, int posState)
- {
- return _prices[posState * Base.kNumLenSymbols + symbol];
- }
-
- void UpdateTable(int posState)
- {
- SetPrices(posState, _tableSize, _prices, posState * Base.kNumLenSymbols);
- _counters[posState] = _tableSize;
- }
-
- public void UpdateTables(int numPosStates)
- {
- for (int posState = 0; posState < numPosStates; posState++)
- UpdateTable(posState);
- }
-
- public void Encode(SevenZip.Compression.RangeCoder.Encoder rangeEncoder, int symbol, int posState) throws IOException
- {
- super.Encode(rangeEncoder, symbol, posState);
- if (--_counters[posState] == 0)
- UpdateTable(posState);
- }
- }
-
- static final int kNumOpts = 1 << 12;
- class Optimal
- {
- public int State;
-
- public boolean Prev1IsChar;
- public boolean Prev2;
-
- public int PosPrev2;
- public int BackPrev2;
-
- public int Price;
- public int PosPrev;
- public int BackPrev;
-
- public int Backs0;
- public int Backs1;
- public int Backs2;
- public int Backs3;
-
- public void MakeAsChar() { BackPrev = -1; Prev1IsChar = false; }
- public void MakeAsShortRep() { BackPrev = 0; ; Prev1IsChar = false; }
- public boolean IsShortRep() { return (BackPrev == 0); }
- };
- Optimal[] _optimum = new Optimal[kNumOpts];
- SevenZip.Compression.LZ.BinTree _matchFinder = null;
- SevenZip.Compression.RangeCoder.Encoder _rangeEncoder = new SevenZip.Compression.RangeCoder.Encoder();
-
- short[] _isMatch = new short[Base.kNumStates<<Base.kNumPosStatesBitsMax];
- short[] _isRep = new short[Base.kNumStates];
- short[] _isRepG0 = new short[Base.kNumStates];
- short[] _isRepG1 = new short[Base.kNumStates];
- short[] _isRepG2 = new short[Base.kNumStates];
- short[] _isRep0Long = new short[Base.kNumStates<<Base.kNumPosStatesBitsMax];
-
- BitTreeEncoder[] _posSlotEncoder = new BitTreeEncoder[Base.kNumLenToPosStates]; // kNumPosSlotBits
-
- short[] _posEncoders = new short[Base.kNumFullDistances-Base.kEndPosModelIndex];
- BitTreeEncoder _posAlignEncoder = new BitTreeEncoder(Base.kNumAlignBits);
-
- LenPriceTableEncoder _lenEncoder = new LenPriceTableEncoder();
- LenPriceTableEncoder _repMatchLenEncoder = new LenPriceTableEncoder();
-
- LiteralEncoder _literalEncoder = new LiteralEncoder();
-
- int[] _matchDistances = new int[Base.kMatchMaxLen*2+2];
-
- int _numFastBytes = kNumFastBytesDefault;
- int _longestMatchLength;
- int _numDistancePairs;
-
- int _additionalOffset;
-
- int _optimumEndIndex;
- int _optimumCurrentIndex;
-
- boolean _longestMatchWasFound;
-
- int[] _posSlotPrices = new int[1<<(Base.kNumPosSlotBits+Base.kNumLenToPosStatesBits)];
- int[] _distancesPrices = new int[Base.kNumFullDistances<<Base.kNumLenToPosStatesBits];
- int[] _alignPrices = new int[Base.kAlignTableSize];
- int _alignPriceCount;
-
- int _distTableSize = (kDefaultDictionaryLogSize * 2);
-
- int _posStateBits = 2;
- int _posStateMask = (4 - 1);
- int _numLiteralPosStateBits = 0;
- int _numLiteralContextBits = 3;
-
- int _dictionarySize = (1 << kDefaultDictionaryLogSize);
- int _dictionarySizePrev = -1;
- int _numFastBytesPrev = -1;
-
- long nowPos64;
- boolean _finished;
- java.io.InputStream _inStream;
-
- int _matchFinderType = EMatchFinderTypeBT4;
- boolean _writeEndMark = false;
-
- boolean _needReleaseMFStream = false;
-
- void Create()
- {
- if (_matchFinder == null)
- {
- SevenZip.Compression.LZ.BinTree bt = new SevenZip.Compression.LZ.BinTree();
- int numHashBytes = 4;
- if (_matchFinderType == EMatchFinderTypeBT2)
- numHashBytes = 2;
- bt.SetType(numHashBytes);
- _matchFinder = bt;
- }
- _literalEncoder.Create(_numLiteralPosStateBits, _numLiteralContextBits);
-
- if (_dictionarySize == _dictionarySizePrev && _numFastBytesPrev == _numFastBytes)
- return;
- _matchFinder.Create(_dictionarySize, kNumOpts, _numFastBytes, Base.kMatchMaxLen + 1);
- _dictionarySizePrev = _dictionarySize;
- _numFastBytesPrev = _numFastBytes;
- }
-
- public Encoder()
- {
- for (int i = 0; i < kNumOpts; i++)
- _optimum[i] = new Optimal();
- for (int i = 0; i < Base.kNumLenToPosStates; i++)
- _posSlotEncoder[i] = new BitTreeEncoder(Base.kNumPosSlotBits);
- }
-
- void SetWriteEndMarkerMode(boolean writeEndMarker)
- {
- _writeEndMark = writeEndMarker;
- }
-
- void Init()
- {
- BaseInit();
- _rangeEncoder.Init();
-
- SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isMatch);
- SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRep0Long);
- SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRep);
- SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRepG0);
- SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRepG1);
- SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_isRepG2);
- SevenZip.Compression.RangeCoder.Encoder.InitBitModels(_posEncoders);
-
-
-
-
-
-
-
- _literalEncoder.Init();
- for (int i = 0; i < Base.kNumLenToPosStates; i++)
- _posSlotEncoder[i].Init();
-
-
-
- _lenEncoder.Init(1 << _posStateBits);
- _repMatchLenEncoder.Init(1 << _posStateBits);
-
- _posAlignEncoder.Init();
-
- _longestMatchWasFound = false;
- _optimumEndIndex = 0;
- _optimumCurrentIndex = 0;
- _additionalOffset = 0;
- }
-
- int ReadMatchDistances() throws java.io.IOException
- {
- int lenRes = 0;
- _numDistancePairs = _matchFinder.GetMatches(_matchDistances);
- if (_numDistancePairs > 0)
- {
- lenRes = _matchDistances[_numDistancePairs - 2];
- if (lenRes == _numFastBytes)
- lenRes += _matchFinder.GetMatchLen((int)lenRes - 1, _matchDistances[_numDistancePairs - 1],
- Base.kMatchMaxLen - lenRes);
- }
- _additionalOffset++;
- return lenRes;
- }
-
- void MovePos(int num) throws java.io.IOException
- {
- if (num > 0)
- {
- _matchFinder.Skip(num);
- _additionalOffset += num;
- }
- }
-
- int GetRepLen1Price(int state, int posState)
- {
- return SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRepG0[state]) +
- SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRep0Long[(state << Base.kNumPosStatesBitsMax) + posState]);
- }
-
- int GetPureRepPrice(int repIndex, int state, int posState)
- {
- int price;
- if (repIndex == 0)
- {
- price = SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRepG0[state]);
- price += SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep0Long[(state << Base.kNumPosStatesBitsMax) + posState]);
- }
- else
- {
- price = SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRepG0[state]);
- if (repIndex == 1)
- price += SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRepG1[state]);
- else
- {
- price += SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRepG1[state]);
- price += SevenZip.Compression.RangeCoder.Encoder.GetPrice(_isRepG2[state], repIndex - 2);
- }
- }
- return price;
- }
-
- int GetRepPrice(int repIndex, int len, int state, int posState)
- {
- int price = _repMatchLenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
- return price + GetPureRepPrice(repIndex, state, posState);
- }
-
- int GetPosLenPrice(int pos, int len, int posState)
- {
- int price;
- int lenToPosState = Base.GetLenToPosState(len);
- if (pos < Base.kNumFullDistances)
- price = _distancesPrices[(lenToPosState * Base.kNumFullDistances) + pos];
- else
- price = _posSlotPrices[(lenToPosState << Base.kNumPosSlotBits) + GetPosSlot2(pos)] +
- _alignPrices[pos & Base.kAlignMask];
- return price + _lenEncoder.GetPrice(len - Base.kMatchMinLen, posState);
- }
-
- int Backward(int cur)
- {
- _optimumEndIndex = cur;
- int posMem = _optimum[cur].PosPrev;
- int backMem = _optimum[cur].BackPrev;
- do
- {
- if (_optimum[cur].Prev1IsChar)
- {
- _optimum[posMem].MakeAsChar();
- _optimum[posMem].PosPrev = posMem - 1;
- if (_optimum[cur].Prev2)
- {
- _optimum[posMem - 1].Prev1IsChar = false;
- _optimum[posMem - 1].PosPrev = _optimum[cur].PosPrev2;
- _optimum[posMem - 1].BackPrev = _optimum[cur].BackPrev2;
- }
- }
- int posPrev = posMem;
- int backCur = backMem;
-
- backMem = _optimum[posPrev].BackPrev;
- posMem = _optimum[posPrev].PosPrev;
-
- _optimum[posPrev].BackPrev = backCur;
- _optimum[posPrev].PosPrev = cur;
- cur = posPrev;
- }
- while (cur > 0);
- backRes = _optimum[0].BackPrev;
- _optimumCurrentIndex = _optimum[0].PosPrev;
- return _optimumCurrentIndex;
- }
-
- int[] reps = new int[Base.kNumRepDistances];
- int[] repLens = new int[Base.kNumRepDistances];
- int backRes;
-
- int GetOptimum(int position) throws IOException
- {
- if (_optimumEndIndex != _optimumCurrentIndex)
- {
- int lenRes = _optimum[_optimumCurrentIndex].PosPrev - _optimumCurrentIndex;
- backRes = _optimum[_optimumCurrentIndex].BackPrev;
- _optimumCurrentIndex = _optimum[_optimumCurrentIndex].PosPrev;
- return lenRes;
- }
- _optimumCurrentIndex = _optimumEndIndex = 0;
-
- int lenMain, numDistancePairs;
- if (!_longestMatchWasFound)
- {
- lenMain = ReadMatchDistances();
- }
- else
- {
- lenMain = _longestMatchLength;
- _longestMatchWasFound = false;
- }
- numDistancePairs = _numDistancePairs;
-
- int numAvailableBytes = _matchFinder.GetNumAvailableBytes() + 1;
- if (numAvailableBytes < 2)
- {
- backRes = -1;
- return 1;
- }
- if (numAvailableBytes > Base.kMatchMaxLen)
- numAvailableBytes = Base.kMatchMaxLen;
-
- int repMaxIndex = 0;
- int i;
- for (i = 0; i < Base.kNumRepDistances; i++)
- {
- reps[i] = _repDistances[i];
- repLens[i] = _matchFinder.GetMatchLen(0 - 1, reps[i], Base.kMatchMaxLen);
- if (repLens[i] > repLens[repMaxIndex])
- repMaxIndex = i;
- }
- if (repLens[repMaxIndex] >= _numFastBytes)
- {
- backRes = repMaxIndex;
- int lenRes = repLens[repMaxIndex];
- MovePos(lenRes - 1);
- return lenRes;
- }
-
- if (lenMain >= _numFastBytes)
- {
- backRes = _matchDistances[numDistancePairs - 1] + Base.kNumRepDistances;
- MovePos(lenMain - 1);
- return lenMain;
- }
-
- byte currentByte = _matchFinder.GetIndexByte(0 - 1);
- byte matchByte = _matchFinder.GetIndexByte(0 - _repDistances[0] - 1 - 1);
-
- if (lenMain < 2 && currentByte != matchByte && repLens[repMaxIndex] < 2)
- {
- backRes = -1;
- return 1;
- }
-
- _optimum[0].State = _state;
-
- int posState = (position & _posStateMask);
-
- _optimum[1].Price = SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(_state << Base.kNumPosStatesBitsMax) + posState]) +
- _literalEncoder.GetSubCoder(position, _previousByte).GetPrice(!Base.StateIsCharState(_state), matchByte, currentByte);
- _optimum[1].MakeAsChar();
-
- int matchPrice = SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(_state << Base.kNumPosStatesBitsMax) + posState]);
- int repMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[_state]);
-
- if (matchByte == currentByte)
- {
- int shortRepPrice = repMatchPrice + GetRepLen1Price(_state, posState);
- if (shortRepPrice < _optimum[1].Price)
- {
- _optimum[1].Price = shortRepPrice;
- _optimum[1].MakeAsShortRep();
- }
- }
-
- int lenEnd = ((lenMain >= repLens[repMaxIndex]) ? lenMain : repLens[repMaxIndex]);
-
- if (lenEnd < 2)
- {
- backRes = _optimum[1].BackPrev;
- return 1;
- }
-
- _optimum[1].PosPrev = 0;
-
- _optimum[0].Backs0 = reps[0];
- _optimum[0].Backs1 = reps[1];
- _optimum[0].Backs2 = reps[2];
- _optimum[0].Backs3 = reps[3];
-
- int len = lenEnd;
- do
- _optimum[len--].Price = kIfinityPrice;
- while (len >= 2);
-
- for (i = 0; i < Base.kNumRepDistances; i++)
- {
- int repLen = repLens[i];
- if (repLen < 2)
- continue;
- int price = repMatchPrice + GetPureRepPrice(i, _state, posState);
- do
- {
- int curAndLenPrice = price + _repMatchLenEncoder.GetPrice(repLen - 2, posState);
- Optimal optimum = _optimum[repLen];
- if (curAndLenPrice < optimum.Price)
- {
- optimum.Price = curAndLenPrice;
- optimum.PosPrev = 0;
- optimum.BackPrev = i;
- optimum.Prev1IsChar = false;
- }
- }
- while (--repLen >= 2);
- }
-
- int normalMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRep[_state]);
-
- len = ((repLens[0] >= 2) ? repLens[0] + 1 : 2);
- if (len <= lenMain)
- {
- int offs = 0;
- while (len > _matchDistances[offs])
- offs += 2;
- for (; ; len++)
- {
- int distance = _matchDistances[offs + 1];
- int curAndLenPrice = normalMatchPrice + GetPosLenPrice(distance, len, posState);
- Optimal optimum = _optimum[len];
- if (curAndLenPrice < optimum.Price)
- {
- optimum.Price = curAndLenPrice;
- optimum.PosPrev = 0;
- optimum.BackPrev = distance + Base.kNumRepDistances;
- optimum.Prev1IsChar = false;
- }
- if (len == _matchDistances[offs])
- {
- offs += 2;
- if (offs == numDistancePairs)
- break;
- }
- }
- }
-
- int cur = 0;
-
- while (true)
- {
- cur++;
- if (cur == lenEnd)
- return Backward(cur);
- int newLen = ReadMatchDistances();
- numDistancePairs = _numDistancePairs;
- if (newLen >= _numFastBytes)
- {
-
- _longestMatchLength = newLen;
- _longestMatchWasFound = true;
- return Backward(cur);
- }
- position++;
- int posPrev = _optimum[cur].PosPrev;
- int state;
- if (_optimum[cur].Prev1IsChar)
- {
- posPrev--;
- if (_optimum[cur].Prev2)
- {
- state = _optimum[_optimum[cur].PosPrev2].State;
- if (_optimum[cur].BackPrev2 < Base.kNumRepDistances)
- state = Base.StateUpdateRep(state);
- else
- state = Base.StateUpdateMatch(state);
- }
- else
- state = _optimum[posPrev].State;
- state = Base.StateUpdateChar(state);
- }
- else
- state = _optimum[posPrev].State;
- if (posPrev == cur - 1)
- {
- if (_optimum[cur].IsShortRep())
- state = Base.StateUpdateShortRep(state);
- else
- state = Base.StateUpdateChar(state);
- }
- else
- {
- int pos;
- if (_optimum[cur].Prev1IsChar && _optimum[cur].Prev2)
- {
- posPrev = _optimum[cur].PosPrev2;
- pos = _optimum[cur].BackPrev2;
- state = Base.StateUpdateRep(state);
- }
- else
- {
- pos = _optimum[cur].BackPrev;
- if (pos < Base.kNumRepDistances)
- state = Base.StateUpdateRep(state);
- else
- state = Base.StateUpdateMatch(state);
- }
- Optimal opt = _optimum[posPrev];
- if (pos < Base.kNumRepDistances)
- {
- if (pos == 0)
- {
- reps[0] = opt.Backs0;
- reps[1] = opt.Backs1;
- reps[2] = opt.Backs2;
- reps[3] = opt.Backs3;
- }
- else if (pos == 1)
- {
- reps[0] = opt.Backs1;
- reps[1] = opt.Backs0;
- reps[2] = opt.Backs2;
- reps[3] = opt.Backs3;
- }
- else if (pos == 2)
- {
- reps[0] = opt.Backs2;
- reps[1] = opt.Backs0;
- reps[2] = opt.Backs1;
- reps[3] = opt.Backs3;
- }
- else
- {
- reps[0] = opt.Backs3;
- reps[1] = opt.Backs0;
- reps[2] = opt.Backs1;
- reps[3] = opt.Backs2;
- }
- }
- else
- {
- reps[0] = (pos - Base.kNumRepDistances);
- reps[1] = opt.Backs0;
- reps[2] = opt.Backs1;
- reps[3] = opt.Backs2;
- }
- }
- _optimum[cur].State = state;
- _optimum[cur].Backs0 = reps[0];
- _optimum[cur].Backs1 = reps[1];
- _optimum[cur].Backs2 = reps[2];
- _optimum[cur].Backs3 = reps[3];
- int curPrice = _optimum[cur].Price;
-
- currentByte = _matchFinder.GetIndexByte(0 - 1);
- matchByte = _matchFinder.GetIndexByte(0 - reps[0] - 1 - 1);
-
- posState = (position & _posStateMask);
-
- int curAnd1Price = curPrice +
- SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(state << Base.kNumPosStatesBitsMax) + posState]) +
- _literalEncoder.GetSubCoder(position, _matchFinder.GetIndexByte(0 - 2)).
- GetPrice(!Base.StateIsCharState(state), matchByte, currentByte);
-
- Optimal nextOptimum = _optimum[cur + 1];
-
- boolean nextIsChar = false;
- if (curAnd1Price < nextOptimum.Price)
- {
- nextOptimum.Price = curAnd1Price;
- nextOptimum.PosPrev = cur;
- nextOptimum.MakeAsChar();
- nextIsChar = true;
- }
-
- matchPrice = curPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state << Base.kNumPosStatesBitsMax) + posState]);
- repMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state]);
-
- if (matchByte == currentByte &&
- !(nextOptimum.PosPrev < cur && nextOptimum.BackPrev == 0))
- {
- int shortRepPrice = repMatchPrice + GetRepLen1Price(state, posState);
- if (shortRepPrice <= nextOptimum.Price)
- {
- nextOptimum.Price = shortRepPrice;
- nextOptimum.PosPrev = cur;
- nextOptimum.MakeAsShortRep();
- nextIsChar = true;
- }
- }
-
- int numAvailableBytesFull = _matchFinder.GetNumAvailableBytes() + 1;
- numAvailableBytesFull = Math.min(kNumOpts - 1 - cur, numAvailableBytesFull);
- numAvailableBytes = numAvailableBytesFull;
-
- if (numAvailableBytes < 2)
- continue;
- if (numAvailableBytes > _numFastBytes)
- numAvailableBytes = _numFastBytes;
- if (!nextIsChar && matchByte != currentByte)
- {
- // try Literal + rep0
- int t = Math.min(numAvailableBytesFull - 1, _numFastBytes);
- int lenTest2 = _matchFinder.GetMatchLen(0, reps[0], t);
- if (lenTest2 >= 2)
- {
- int state2 = Base.StateUpdateChar(state);
-
- int posStateNext = (position + 1) & _posStateMask;
- int nextRepMatchPrice = curAnd1Price +
- SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) +
- SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state2]);
- {
- int offset = cur + 1 + lenTest2;
- while (lenEnd < offset)
- _optimum[++lenEnd].Price = kIfinityPrice;
- int curAndLenPrice = nextRepMatchPrice + GetRepPrice(
- 0, lenTest2, state2, posStateNext);
- Optimal optimum = _optimum[offset];
- if (curAndLenPrice < optimum.Price)
- {
- optimum.Price = curAndLenPrice;
- optimum.PosPrev = cur + 1;
- optimum.BackPrev = 0;
- optimum.Prev1IsChar = true;
- optimum.Prev2 = false;
- }
- }
- }
- }
-
- int startLen = 2; // speed optimization
-
- for (int repIndex = 0; repIndex < Base.kNumRepDistances; repIndex++)
- {
- int lenTest = _matchFinder.GetMatchLen(0 - 1, reps[repIndex], numAvailableBytes);
- if (lenTest < 2)
- continue;
- int lenTestTemp = lenTest;
- do
- {
- while (lenEnd < cur + lenTest)
- _optimum[++lenEnd].Price = kIfinityPrice;
- int curAndLenPrice = repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState);
- Optimal optimum = _optimum[cur + lenTest];
- if (curAndLenPrice < optimum.Price)
- {
- optimum.Price = curAndLenPrice;
- optimum.PosPrev = cur;
- optimum.BackPrev = repIndex;
- optimum.Prev1IsChar = false;
- }
- }
- while (--lenTest >= 2);
- lenTest = lenTestTemp;
-
- if (repIndex == 0)
- startLen = lenTest + 1;
-
- // if (_maxMode)
- if (lenTest < numAvailableBytesFull)
- {
- int t = Math.min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
- int lenTest2 = _matchFinder.GetMatchLen(lenTest, reps[repIndex], t);
- if (lenTest2 >= 2)
- {
- int state2 = Base.StateUpdateRep(state);
-
- int posStateNext = (position + lenTest) & _posStateMask;
- int curAndLenCharPrice =
- repMatchPrice + GetRepPrice(repIndex, lenTest, state, posState) +
- SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) +
- _literalEncoder.GetSubCoder(position + lenTest,
- _matchFinder.GetIndexByte(lenTest - 1 - 1)).GetPrice(true,
- _matchFinder.GetIndexByte(lenTest - 1 - (reps[repIndex] + 1)),
- _matchFinder.GetIndexByte(lenTest - 1));
- state2 = Base.StateUpdateChar(state2);
- posStateNext = (position + lenTest + 1) & _posStateMask;
- int nextMatchPrice = curAndLenCharPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]);
- int nextRepMatchPrice = nextMatchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state2]);
-
- // for(; lenTest2 >= 2; lenTest2--)
- {
- int offset = lenTest + 1 + lenTest2;
- while (lenEnd < cur + offset)
- _optimum[++lenEnd].Price = kIfinityPrice;
- int curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
- Optimal optimum = _optimum[cur + offset];
- if (curAndLenPrice < optimum.Price)
- {
- optimum.Price = curAndLenPrice;
- optimum.PosPrev = cur + lenTest + 1;
- optimum.BackPrev = 0;
- optimum.Prev1IsChar = true;
- optimum.Prev2 = true;
- optimum.PosPrev2 = cur;
- optimum.BackPrev2 = repIndex;
- }
- }
- }
- }
- }
-
- if (newLen > numAvailableBytes)
- {
- newLen = numAvailableBytes;
- for (numDistancePairs = 0; newLen > _matchDistances[numDistancePairs]; numDistancePairs += 2) ;
- _matchDistances[numDistancePairs] = newLen;
- numDistancePairs += 2;
- }
- if (newLen >= startLen)
- {
- normalMatchPrice = matchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isRep[state]);
- while (lenEnd < cur + newLen)
- _optimum[++lenEnd].Price = kIfinityPrice;
-
- int offs = 0;
- while (startLen > _matchDistances[offs])
- offs += 2;
-
- for (int lenTest = startLen; ; lenTest++)
- {
- int curBack = _matchDistances[offs + 1];
- int curAndLenPrice = normalMatchPrice + GetPosLenPrice(curBack, lenTest, posState);
- Optimal optimum = _optimum[cur + lenTest];
- if (curAndLenPrice < optimum.Price)
- {
- optimum.Price = curAndLenPrice;
- optimum.PosPrev = cur;
- optimum.BackPrev = curBack + Base.kNumRepDistances;
- optimum.Prev1IsChar = false;
- }
-
- if (lenTest == _matchDistances[offs])
- {
- if (lenTest < numAvailableBytesFull)
- {
- int t = Math.min(numAvailableBytesFull - 1 - lenTest, _numFastBytes);
- int lenTest2 = _matchFinder.GetMatchLen(lenTest, curBack, t);
- if (lenTest2 >= 2)
- {
- int state2 = Base.StateUpdateMatch(state);
-
- int posStateNext = (position + lenTest) & _posStateMask;
- int curAndLenCharPrice = curAndLenPrice +
- SevenZip.Compression.RangeCoder.Encoder.GetPrice0(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]) +
- _literalEncoder.GetSubCoder(position + lenTest,
- _matchFinder.GetIndexByte(lenTest - 1 - 1)).
- GetPrice(true,
- _matchFinder.GetIndexByte(lenTest - (curBack + 1) - 1),
- _matchFinder.GetIndexByte(lenTest - 1));
- state2 = Base.StateUpdateChar(state2);
- posStateNext = (position + lenTest + 1) & _posStateMask;
- int nextMatchPrice = curAndLenCharPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isMatch[(state2 << Base.kNumPosStatesBitsMax) + posStateNext]);
- int nextRepMatchPrice = nextMatchPrice + SevenZip.Compression.RangeCoder.Encoder.GetPrice1(_isRep[state2]);
-
- int offset = lenTest + 1 + lenTest2;
- while (lenEnd < cur + offset)
- _optimum[++lenEnd].Price = kIfinityPrice;
- curAndLenPrice = nextRepMatchPrice + GetRepPrice(0, lenTest2, state2, posStateNext);
- optimum = _optimum[cur + offset];
- if (curAndLenPrice < optimum.Price)
- {
- optimum.Price = curAndLenPrice;
- optimum.PosPrev = cur + lenTest + 1;
- optimum.BackPrev = 0;
- optimum.Prev1IsChar = true;
- optimum.Prev2 = true;
- optimum.PosPrev2 = cur;
- optimum.BackPrev2 = curBack + Base.kNumRepDistances;
- }
- }
- }
- offs += 2;
- if (offs == numDistancePairs)
- break;
- }
- }
- }
- }
- }
-
- boolean ChangePair(int smallDist, int bigDist)
- {
- int kDif = 7;
- return (smallDist < (1 << (32 - kDif)) && bigDist >= (smallDist << kDif));
- }
-
- void WriteEndMarker(int posState) throws IOException
- {
- if (!_writeEndMark)
- return;
-
- _rangeEncoder.Encode(_isMatch, (_state << Base.kNumPosStatesBitsMax) + posState, 1);
- _rangeEncoder.Encode(_isRep, _state, 0);
- _state = Base.StateUpdateMatch(_state);
- int len = Base.kMatchMinLen;
- _lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
- int posSlot = (1 << Base.kNumPosSlotBits) - 1;
- int lenToPosState = Base.GetLenToPosState(len);
- _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
- int footerBits = 30;
- int posReduced = (1 << footerBits) - 1;
- _rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
- _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
- }
-
- void Flush(int nowPos) throws IOException
- {
- ReleaseMFStream();
- WriteEndMarker(nowPos & _posStateMask);
- _rangeEncoder.FlushData();
- _rangeEncoder.FlushStream();
- }
-
- public void CodeOneBlock(long[] inSize, long[] outSize, boolean[] finished) throws IOException
- {
- inSize[0] = 0;
- outSize[0] = 0;
- finished[0] = true;
-
- if (_inStream != null)
- {
- _matchFinder.SetStream(_inStream);
- _matchFinder.Init();
- _needReleaseMFStream = true;
- _inStream = null;
- }
-
- if (_finished)
- return;
- _finished = true;
-
-
- long progressPosValuePrev = nowPos64;
- if (nowPos64 == 0)
- {
- if (_matchFinder.GetNumAvailableBytes() == 0)
- {
- Flush((int)nowPos64);
- return;
- }
-
- ReadMatchDistances();
- int posState = (int)(nowPos64) & _posStateMask;
- _rangeEncoder.Encode(_isMatch, (_state << Base.kNumPosStatesBitsMax) + posState, 0);
- _state = Base.StateUpdateChar(_state);
- byte curByte = _matchFinder.GetIndexByte(0 - _additionalOffset);
- _literalEncoder.GetSubCoder((int)(nowPos64), _previousByte).Encode(_rangeEncoder, curByte);
- _previousByte = curByte;
- _additionalOffset--;
- nowPos64++;
- }
- if (_matchFinder.GetNumAvailableBytes() == 0)
- {
- Flush((int)nowPos64);
- return;
- }
- while (true)
- {
-
- int len = GetOptimum((int)nowPos64);
- int pos = backRes;
- int posState = ((int)nowPos64) & _posStateMask;
- int complexState = (_state << Base.kNumPosStatesBitsMax) + posState;
- if (len == 1 && pos == -1)
- {
- _rangeEncoder.Encode(_isMatch, complexState, 0);
- byte curByte = _matchFinder.GetIndexByte((int)(0 - _additionalOffset));
- LiteralEncoder.Encoder2 subCoder = _literalEncoder.GetSubCoder((int)nowPos64, _previousByte);
- if (!Base.StateIsCharState(_state))
- {
- byte matchByte = _matchFinder.GetIndexByte((int)(0 - _repDistances[0] - 1 - _additionalOffset));
- subCoder.EncodeMatched(_rangeEncoder, matchByte, curByte);
- }
- else
- subCoder.Encode(_rangeEncoder, curByte);
- _previousByte = curByte;
- _state = Base.StateUpdateChar(_state);
- }
- else
- {
- _rangeEncoder.Encode(_isMatch, complexState, 1);
- if (pos < Base.kNumRepDistances)
- {
- _rangeEncoder.Encode(_isRep, _state, 1);
- if (pos == 0)
- {
- _rangeEncoder.Encode(_isRepG0, _state, 0);
- if (len == 1)
- _rangeEncoder.Encode(_isRep0Long, complexState, 0);
- else
- _rangeEncoder.Encode(_isRep0Long, complexState, 1);
- }
- else
- {
- _rangeEncoder.Encode(_isRepG0, _state, 1);
- if (pos == 1)
- _rangeEncoder.Encode(_isRepG1, _state, 0);
- else
- {
- _rangeEncoder.Encode(_isRepG1, _state, 1);
- _rangeEncoder.Encode(_isRepG2, _state, pos - 2);
- }
- }
- if (len == 1)
- _state = Base.StateUpdateShortRep(_state);
- else
- {
- _repMatchLenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
- _state = Base.StateUpdateRep(_state);
- }
- int distance = _repDistances[pos];
- if (pos != 0)
- {
- for (int i = pos; i >= 1; i--)
- _repDistances[i] = _repDistances[i - 1];
- _repDistances[0] = distance;
- }
- }
- else
- {
- _rangeEncoder.Encode(_isRep, _state, 0);
- _state = Base.StateUpdateMatch(_state);
- _lenEncoder.Encode(_rangeEncoder, len - Base.kMatchMinLen, posState);
- pos -= Base.kNumRepDistances;
- int posSlot = GetPosSlot(pos);
- int lenToPosState = Base.GetLenToPosState(len);
- _posSlotEncoder[lenToPosState].Encode(_rangeEncoder, posSlot);
-
- if (posSlot >= Base.kStartPosModelIndex)
- {
- int footerBits = (int)((posSlot >> 1) - 1);
- int baseVal = ((2 | (posSlot & 1)) << footerBits);
- int posReduced = pos - baseVal;
-
- if (posSlot < Base.kEndPosModelIndex)
- BitTreeEncoder.ReverseEncode(_posEncoders,
- baseVal - posSlot - 1, _rangeEncoder, footerBits, posReduced);
- else
- {
- _rangeEncoder.EncodeDirectBits(posReduced >> Base.kNumAlignBits, footerBits - Base.kNumAlignBits);
- _posAlignEncoder.ReverseEncode(_rangeEncoder, posReduced & Base.kAlignMask);
- _alignPriceCount++;
- }
- }
- int distance = pos;
- for (int i = Base.kNumRepDistances - 1; i >= 1; i--)
- _repDistances[i] = _repDistances[i - 1];
- _repDistances[0] = distance;
- _matchPriceCount++;
- }
- _previousByte = _matchFinder.GetIndexByte(len - 1 - _additionalOffset);
- }
- _additionalOffset -= len;
- nowPos64 += len;
- if (_additionalOffset == 0)
- {
- // if (!_fastMode)
- if (_matchPriceCount >= (1 << 7))
- FillDistancesPrices();
- if (_alignPriceCount >= Base.kAlignTableSize)
- FillAlignPrices();
- inSize[0] = nowPos64;
- outSize[0] = _rangeEncoder.GetProcessedSizeAdd();
- if (_matchFinder.GetNumAvailableBytes() == 0)
- {
- Flush((int)nowPos64);
- return;
- }
-
- if (nowPos64 - progressPosValuePrev >= (1 << 12))
- {
- _finished = false;
- finished[0] = false;
- return;
- }
- }
- }
- }
-
- void ReleaseMFStream()
- {
- if (_matchFinder != null && _needReleaseMFStream)
- {
- _matchFinder.ReleaseStream();
- _needReleaseMFStream = false;
- }
- }
-
- void SetOutStream(java.io.OutputStream outStream)
- { _rangeEncoder.SetStream(outStream); }
- void ReleaseOutStream()
- { _rangeEncoder.ReleaseStream(); }
-
- void ReleaseStreams()
- {
- ReleaseMFStream();
- ReleaseOutStream();
- }
-
- void SetStreams(java.io.InputStream inStream, java.io.OutputStream outStream,
- long inSize, long outSize)
- {
- _inStream = inStream;
- _finished = false;
- Create();
- SetOutStream(outStream);
- Init();
-
- // if (!_fastMode)
- {
- FillDistancesPrices();
- FillAlignPrices();
- }
-
- _lenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);
- _lenEncoder.UpdateTables(1 << _posStateBits);
- _repMatchLenEncoder.SetTableSize(_numFastBytes + 1 - Base.kMatchMinLen);
- _repMatchLenEncoder.UpdateTables(1 << _posStateBits);
-
- nowPos64 = 0;
- }
-
- long[] processedInSize = new long[1]; long[] processedOutSize = new long[1]; boolean[] finished = new boolean[1];
- public void Code(java.io.InputStream inStream, java.io.OutputStream outStream,
- long inSize, long outSize, ICodeProgress progress) throws IOException
- {
- _needReleaseMFStream = false;
- try
- {
- SetStreams(inStream, outStream, inSize, outSize);
- while (true)
- {
-
-
-
- CodeOneBlock(processedInSize, processedOutSize, finished);
- if (finished[0])
- return;
- if (progress != null)
- {
- progress.SetProgress(processedInSize[0], processedOutSize[0]);
- }
- }
- }
- finally
- {
- ReleaseStreams();
- }
- }
-
- public static final int kPropSize = 5;
- byte[] properties = new byte[kPropSize];
-
- public void WriteCoderProperties(java.io.OutputStream outStream) throws IOException
- {
- properties[0] = (byte)((_posStateBits * 5 + _numLiteralPosStateBits) * 9 + _numLiteralContextBits);
- for (int i = 0; i < 4; i++)
- properties[1 + i] = (byte)(_dictionarySize >> (8 * i));
- outStream.write(properties, 0, kPropSize);
- }
-
- int[] tempPrices = new int[Base.kNumFullDistances];
- int _matchPriceCount;
-
- void FillDistancesPrices()
- {
- for (int i = Base.kStartPosModelIndex; i < Base.kNumFullDistances; i++)
- {
- int posSlot = GetPosSlot(i);
- int footerBits = (int)((posSlot >> 1) - 1);
- int baseVal = ((2 | (posSlot & 1)) << footerBits);
- tempPrices[i] = BitTreeEncoder.ReverseGetPrice(_posEncoders,
- baseVal - posSlot - 1, footerBits, i - baseVal);
- }
-
- for (int lenToPosState = 0; lenToPosState < Base.kNumLenToPosStates; lenToPosState++)
- {
- int posSlot;
- BitTreeEncoder encoder = _posSlotEncoder[lenToPosState];
-
- int st = (lenToPosState << Base.kNumPosSlotBits);
- for (posSlot = 0; posSlot < _distTableSize; posSlot++)
- _posSlotPrices[st + posSlot] = encoder.GetPrice(posSlot);
- for (posSlot = Base.kEndPosModelIndex; posSlot < _distTableSize; posSlot++)
- _posSlotPrices[st + posSlot] += ((((posSlot >> 1) - 1) - Base.kNumAlignBits) << SevenZip.Compression.RangeCoder.Encoder.kNumBitPriceShiftBits);
-
- int st2 = lenToPosState * Base.kNumFullDistances;
- int i;
- for (i = 0; i < Base.kStartPosModelIndex; i++)
- _distancesPrices[st2 + i] = _posSlotPrices[st + i];
- for (; i < Base.kNumFullDistances; i++)
- _distancesPrices[st2 + i] = _posSlotPrices[st + GetPosSlot(i)] + tempPrices[i];
- }
- _matchPriceCount = 0;
- }
-
- void FillAlignPrices()
- {
- for (int i = 0; i < Base.kAlignTableSize; i++)
- _alignPrices[i] = _posAlignEncoder.ReverseGetPrice(i);
- _alignPriceCount = 0;
- }
-
-
- public boolean SetAlgorithm(int algorithm)
- {
- /*
- _fastMode = (algorithm == 0);
- _maxMode = (algorithm >= 2);
- */
- return true;
- }
-
- public boolean SetDictionarySize(int dictionarySize)
- {
- int kDicLogSizeMaxCompress = 29;
- if (dictionarySize < (1 << Base.kDicLogSizeMin) || dictionarySize > (1 << kDicLogSizeMaxCompress))
- return false;
- _dictionarySize = dictionarySize;
- int dicLogSize;
- for (dicLogSize = 0; dictionarySize > (1 << dicLogSize); dicLogSize++) ;
- _distTableSize = dicLogSize * 2;
- return true;
- }
-
- public boolean SetNumFastBytes(int numFastBytes)
- {
- if (numFastBytes < 5 || numFastBytes > Base.kMatchMaxLen)
- return false;
- _numFastBytes = numFastBytes;
- return true;
- }
-
- public boolean SetMatchFinder(int matchFinderIndex)
- {
- if (matchFinderIndex < 0 || matchFinderIndex > 2)
- return false;
- int matchFinderIndexPrev = _matchFinderType;
- _matchFinderType = matchFinderIndex;
- if (_matchFinder != null && matchFinderIndexPrev != _matchFinderType)
- {
- _dictionarySizePrev = -1;
- _matchFinder = null;
- }
- return true;
- }
-
- public boolean SetLcLpPb(int lc, int lp, int pb)
- {
- if (
- lp < 0 || lp > Base.kNumLitPosStatesBitsEncodingMax ||
- lc < 0 || lc > Base.kNumLitContextBitsMax ||
- pb < 0 || pb > Base.kNumPosStatesBitsEncodingMax)
- return false;
- _numLiteralPosStateBits = lp;
- _numLiteralContextBits = lc;
- _posStateBits = pb;
- _posStateMask = ((1) << _posStateBits) - 1;
- return true;
- }
-
- public void SetEndMarkerMode(boolean endMarkerMode)
- {
- _writeEndMark = endMarkerMode;
- }
-}
-
diff --git a/Java/SevenZip/Compression/RangeCoder/BitTreeDecoder.java b/Java/SevenZip/Compression/RangeCoder/BitTreeDecoder.java
deleted file mode 100644
index 6864c69..0000000
--- a/Java/SevenZip/Compression/RangeCoder/BitTreeDecoder.java
+++ /dev/null
@@ -1,55 +0,0 @@
-package SevenZip.Compression.RangeCoder;
-
-public class BitTreeDecoder
-{
- short[] Models;
- int NumBitLevels;
-
- public BitTreeDecoder(int numBitLevels)
- {
- NumBitLevels = numBitLevels;
- Models = new short[1 << numBitLevels];
- }
-
- public void Init()
- {
- Decoder.InitBitModels(Models);
- }
-
- public int Decode(Decoder rangeDecoder) throws java.io.IOException
- {
- int m = 1;
- for (int bitIndex = NumBitLevels; bitIndex != 0; bitIndex--)
- m = (m << 1) + rangeDecoder.DecodeBit(Models, m);
- return m - (1 << NumBitLevels);
- }
-
- public int ReverseDecode(Decoder rangeDecoder) throws java.io.IOException
- {
- int m = 1;
- int symbol = 0;
- for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
- {
- int bit = rangeDecoder.DecodeBit(Models, m);
- m <<= 1;
- m += bit;
- symbol |= (bit << bitIndex);
- }
- return symbol;
- }
-
- public static int ReverseDecode(short[] Models, int startIndex,
- Decoder rangeDecoder, int NumBitLevels) throws java.io.IOException
- {
- int m = 1;
- int symbol = 0;
- for (int bitIndex = 0; bitIndex < NumBitLevels; bitIndex++)
- {
- int bit = rangeDecoder.DecodeBit(Models, startIndex + m);
- m <<= 1;
- m += bit;
- symbol |= (bit << bitIndex);
- }
- return symbol;
- }
-}
diff --git a/Java/SevenZip/Compression/RangeCoder/BitTreeEncoder.java b/Java/SevenZip/Compression/RangeCoder/BitTreeEncoder.java
deleted file mode 100644
index b4c0a07..0000000
--- a/Java/SevenZip/Compression/RangeCoder/BitTreeEncoder.java
+++ /dev/null
@@ -1,99 +0,0 @@
-package SevenZip.Compression.RangeCoder;
-import java.io.IOException;
-
-public class BitTreeEncoder
-{
- short[] Models;
- int NumBitLevels;
-
- public BitTreeEncoder(int numBitLevels)
- {
- NumBitLevels = numBitLevels;
- Models = new short[1 << numBitLevels];
- }
-
- public void Init()
- {
- Decoder.InitBitModels(Models);
- }
-
- public void Encode(Encoder rangeEncoder, int symbol) throws IOException
- {
- int m = 1;
- for (int bitIndex = NumBitLevels; bitIndex != 0; )
- {
- bitIndex--;
- int bit = (symbol >>> bitIndex) & 1;
- rangeEncoder.Encode(Models, m, bit);
- m = (m << 1) | bit;
- }
- }
-
- public void ReverseEncode(Encoder rangeEncoder, int symbol) throws IOException
- {
- int m = 1;
- for (int i = 0; i < NumBitLevels; i++)
- {
- int bit = symbol & 1;
- rangeEncoder.Encode(Models, m, bit);
- m = (m << 1) | bit;
- symbol >>= 1;
- }
- }
-
- public int GetPrice(int symbol)
- {
- int price = 0;
- int m = 1;
- for (int bitIndex = NumBitLevels; bitIndex != 0; )
- {
- bitIndex--;
- int bit = (symbol >>> bitIndex) & 1;
- price += Encoder.GetPrice(Models[m], bit);
- m = (m << 1) + bit;
- }
- return price;
- }
-
- public int ReverseGetPrice(int symbol)
- {
- int price = 0;
- int m = 1;
- for (int i = NumBitLevels; i != 0; i--)
- {
- int bit = symbol & 1;
- symbol >>>= 1;
- price += Encoder.GetPrice(Models[m], bit);
- m = (m << 1) | bit;
- }
- return price;
- }
-
- public static int ReverseGetPrice(short[] Models, int startIndex,
- int NumBitLevels, int symbol)
- {
- int price = 0;
- int m = 1;
- for (int i = NumBitLevels; i != 0; i--)
- {
- int bit = symbol & 1;
- symbol >>>= 1;
- price += Encoder.GetPrice(Models[startIndex + m], bit);
- m = (m << 1) | bit;
- }
- return price;
- }
-
- public static void ReverseEncode(short[] Models, int startIndex,
- Encoder rangeEncoder, int NumBitLevels, int symbol) throws IOException
- {
- int m = 1;
- for (int i = 0; i < NumBitLevels; i++)
- {
- int bit = symbol & 1;
- rangeEncoder.Encode(Models, startIndex + m, bit);
- m = (m << 1) | bit;
- symbol >>= 1;
- }
- }
-}
diff --git a/Java/SevenZip/Compression/RangeCoder/Decoder.java b/Java/SevenZip/Compression/RangeCoder/Decoder.java
deleted file mode 100644
index 7453383..0000000
--- a/Java/SevenZip/Compression/RangeCoder/Decoder.java
+++ /dev/null
@@ -1,88 +0,0 @@
-package SevenZip.Compression.RangeCoder;
-import java.io.IOException;
-
-public class Decoder
-{
- static final int kTopMask = ~((1 << 24) - 1);
-
- static final int kNumBitModelTotalBits = 11;
- static final int kBitModelTotal = (1 << kNumBitModelTotalBits);
- static final int kNumMoveBits = 5;
-
- int Range;
- int Code;
-
- java.io.InputStream Stream;
-
- public final void SetStream(java.io.InputStream stream)
- {
- Stream = stream;
- }
-
- public final void ReleaseStream()
- {
- Stream = null;
- }
-
- public final void Init() throws IOException
- {
- Code = 0;
- Range = -1;
- for (int i = 0; i < 5; i++)
- Code = (Code << 8) | Stream.read();
- }
-
- public final int DecodeDirectBits(int numTotalBits) throws IOException
- {
- int result = 0;
- for (int i = numTotalBits; i != 0; i--)
- {
- Range >>>= 1;
- int t = ((Code - Range) >>> 31);
- Code -= Range & (t - 1);
- result = (result << 1) | (1 - t);
-
- if ((Range & kTopMask) == 0)
- {
- Code = (Code << 8) | Stream.read();
- Range <<= 8;
- }
- }
- return result;
- }
-
- public int DecodeBit(short []probs, int index) throws IOException
- {
- int prob = probs[index];
- int newBound = (Range >>> kNumBitModelTotalBits) * prob;
- if ((Code ^ 0x80000000) < (newBound ^ 0x80000000))
- {
- Range = newBound;
- probs[index] = (short)(prob + ((kBitModelTotal - prob) >>> kNumMoveBits));
- if ((Range & kTopMask) == 0)
- {
- Code = (Code << 8) | Stream.read();
- Range <<= 8;
- }
- return 0;
- }
- else
- {
- Range -= newBound;
- Code -= newBound;
- probs[index] = (short)(prob - ((prob) >>> kNumMoveBits));
- if ((Range & kTopMask) == 0)
- {
- Code = (Code << 8) | Stream.read();
- Range <<= 8;
- }
- return 1;
- }
- }
-
- public static void InitBitModels(short []probs)
- {
- for (int i = 0; i < probs.length; i++)
- probs[i] = (kBitModelTotal >>> 1);
- }
-}
diff --git a/Java/SevenZip/Compression/RangeCoder/Encoder.java b/Java/SevenZip/Compression/RangeCoder/Encoder.java
deleted file mode 100644
index 2273e92..0000000
--- a/Java/SevenZip/Compression/RangeCoder/Encoder.java
+++ /dev/null
@@ -1,151 +0,0 @@
-package SevenZip.Compression.RangeCoder;
-import java.io.IOException;
-
-public class Encoder
-{
- static final int kTopMask = ~((1 << 24) - 1);
-
- static final int kNumBitModelTotalBits = 11;
- static final int kBitModelTotal = (1 << kNumBitModelTotalBits);
- static final int kNumMoveBits = 5;
-
- java.io.OutputStream Stream;
-
- long Low;
- int Range;
- int _cacheSize;
- int _cache;
-
- long _position;
-
- public void SetStream(java.io.OutputStream stream)
- {
- Stream = stream;
- }
-
- public void ReleaseStream()
- {
- Stream = null;
- }
-
- public void Init()
- {
- _position = 0;
- Low = 0;
- Range = -1;
- _cacheSize = 1;
- _cache = 0;
- }
-
- public void FlushData() throws IOException
- {
- for (int i = 0; i < 5; i++)
- ShiftLow();
- }
-
- public void FlushStream() throws IOException
- {
- Stream.flush();
- }
-
- public void ShiftLow() throws IOException
- {
- int LowHi = (int)(Low >>> 32);
- if (LowHi != 0 || Low < 0xFF000000L)
- {
- _position += _cacheSize;
- int temp = _cache;
- do
- {
- Stream.write(temp + LowHi);
- temp = 0xFF;
- }
- while(--_cacheSize != 0);
- _cache = (((int)Low) >>> 24);
- }
- _cacheSize++;
- Low = (Low & 0xFFFFFF) << 8;
- }
-
- public void EncodeDirectBits(int v, int numTotalBits) throws IOException
- {
- for (int i = numTotalBits - 1; i >= 0; i--)
- {
- Range >>>= 1;
- if (((v >>> i) & 1) == 1)
- Low += Range;
- if ((Range & Encoder.kTopMask) == 0)
- {
- Range <<= 8;
- ShiftLow();
- }
- }
- }
-
-
- public long GetProcessedSizeAdd()
- {
- return _cacheSize + _position + 4;
- }
-
-
-
- static final int kNumMoveReducingBits = 2;
- public static final int kNumBitPriceShiftBits = 6;
-
- public static void InitBitModels(short []probs)
- {
- for (int i = 0; i < probs.length; i++)
- probs[i] = (kBitModelTotal >>> 1);
- }
-
- public void Encode(short []probs, int index, int symbol) throws IOException
- {
- int prob = probs[index];
- int newBound = (Range >>> kNumBitModelTotalBits) * prob;
- if (symbol == 0)
- {
- Range = newBound;
- probs[index] = (short)(prob + ((kBitModelTotal - prob) >>> kNumMoveBits));
- }
- else
- {
- Low += (newBound & 0xFFFFFFFFL);
- Range -= newBound;
- probs[index] = (short)(prob - ((prob) >>> kNumMoveBits));
- }
- if ((Range & kTopMask) == 0)
- {
- Range <<= 8;
- ShiftLow();
- }
- }
-
- private static int[] ProbPrices = new int[kBitModelTotal >>> kNumMoveReducingBits];
-
- static
- {
- int kNumBits = (kNumBitModelTotalBits - kNumMoveReducingBits);
- for (int i = kNumBits - 1; i >= 0; i--)
- {
- int start = 1 << (kNumBits - i - 1);
- int end = 1 << (kNumBits - i);
- for (int j = start; j < end; j++)
- ProbPrices[j] = (i << kNumBitPriceShiftBits) +
- (((end - j) << kNumBitPriceShiftBits) >>> (kNumBits - i - 1));
- }
- }
-
- static public int GetPrice(int Prob, int symbol)
- {
- return ProbPrices[(((Prob - symbol) ^ ((-symbol))) & (kBitModelTotal - 1)) >>> kNumMoveReducingBits];
- }
- static public int GetPrice0(int Prob)
- {
- return ProbPrices[Prob >>> kNumMoveReducingBits];
- }
- static public int GetPrice1(int Prob)
- {
- return ProbPrices[(kBitModelTotal - Prob) >>> kNumMoveReducingBits];
- }
-}
diff --git a/Java/SevenZip/ICodeProgress.java b/Java/SevenZip/ICodeProgress.java
deleted file mode 100644
index 290bd2d..0000000
--- a/Java/SevenZip/ICodeProgress.java
+++ /dev/null
@@ -1,6 +0,0 @@
-package SevenZip;
-
-public interface ICodeProgress
-{
- public void SetProgress(long inSize, long outSize);
-}
diff --git a/Java/SevenZip/LzmaAlone.java b/Java/SevenZip/LzmaAlone.java
deleted file mode 100644
index de39a22..0000000
--- a/Java/SevenZip/LzmaAlone.java
+++ /dev/null
@@ -1,253 +0,0 @@
-package SevenZip;
-
-public class LzmaAlone
-{
- static public class CommandLine
- {
- public static final int kEncode = 0;
- public static final int kDecode = 1;
- public static final int kBenchmak = 2;
-
- public int Command = -1;
- public int NumBenchmarkPasses = 10;
-
- public int DictionarySize = 1 << 23;
- public boolean DictionarySizeIsDefined = false;
-
- public int Lc = 3;
- public int Lp = 0;
- public int Pb = 2;
-
- public int Fb = 128;
- public boolean FbIsDefined = false;
-
- public boolean Eos = false;
-
- public int Algorithm = 2;
- public int MatchFinder = 1;
-
- public String InFile;
- public String OutFile;
-
- boolean ParseSwitch(String s)
- {
- if (s.startsWith("d"))
- {
- DictionarySize = 1 << Integer.parseInt(s.substring(1));
- DictionarySizeIsDefined = true;
- }
- else if (s.startsWith("fb"))
- {
- Fb = Integer.parseInt(s.substring(2));
- FbIsDefined = true;
- }
- else if (s.startsWith("a"))
- Algorithm = Integer.parseInt(s.substring(1));
- else if (s.startsWith("lc"))
- Lc = Integer.parseInt(s.substring(2));
- else if (s.startsWith("lp"))
- Lp = Integer.parseInt(s.substring(2));
- else if (s.startsWith("pb"))
- Pb = Integer.parseInt(s.substring(2));
- else if (s.startsWith("eos"))
- Eos = true;
- else if (s.startsWith("mf"))
- {
- String mfs = s.substring(2);
- if (mfs.equals("bt2"))
- MatchFinder = 0;
- else if (mfs.equals("bt4"))
- MatchFinder = 1;
- else if (mfs.equals("bt4b"))
- MatchFinder = 2;
- else
- return false;
- }
- else
- return false;
- return true;
- }
-
- public boolean Parse(String[] args) throws Exception
- {
- int pos = 0;
- boolean switchMode = true;
- for (int i = 0; i < args.length; i++)
- {
- String s = args[i];
- if (s.length() == 0)
- return false;
- if (switchMode)
- {
- if (s.compareTo("--") == 0)
- {
- switchMode = false;
- continue;
- }
- if (s.charAt(0) == '-')
- {
- String sw = s.substring(1).toLowerCase();
- if (sw.length() == 0)
- return false;
- try
- {
- if (!ParseSwitch(sw))
- return false;
- }
- catch (NumberFormatException e)
- {
- return false;
- }
- continue;
- }
- }
- if (pos == 0)
- {
- if (s.equalsIgnoreCase("e"))
- Command = kEncode;
- else if (s.equalsIgnoreCase("d"))
- Command = kDecode;
- else if (s.equalsIgnoreCase("b"))
- Command = kBenchmak;
- else
- return false;
- }
- else if(pos == 1)
- {
- if (Command == kBenchmak)
- {
- try
- {
- NumBenchmarkPasses = Integer.parseInt(s);
- if (NumBenchmarkPasses < 1)
- return false;
- }
- catch (NumberFormatException e)
- {
- return false;
- }
- }
- else
- InFile = s;
- }
- else if(pos == 2)
- OutFile = s;
- else
- return false;
- pos++;
- continue;
- }
- return true;
- }
- }
-
-
- static void PrintHelp()
- {
- System.out.println(
- "\nUsage: LZMA <e|d> [<switches>...] inputFile outputFile\n" +
- " e: encode file\n" +
- " d: decode file\n" +
- " b: Benchmark\n" +
- "<Switches>\n" +
- // " -a{N}: set compression mode - [0, 1], default: 1 (max)\n" +
- " -d{N}: set dictionary - [0,28], default: 23 (8MB)\n" +
- " -fb{N}: set number of fast bytes - [5, 273], default: 128\n" +
- " -lc{N}: set number of literal context bits - [0, 8], default: 3\n" +
- " -lp{N}: set number of literal pos bits - [0, 4], default: 0\n" +
- " -pb{N}: set number of pos bits - [0, 4], default: 2\n" +
- " -mf{MF_ID}: set Match Finder: [bt2, bt4], default: bt4\n" +
- " -eos: write End Of Stream marker\n"
- );
- }
-
- public static void main(String[] args) throws Exception
- {
- System.out.println("\nLZMA (Java) 4.61 2008-11-23\n");
-
- if (args.length < 1)
- {
- PrintHelp();
- return;
- }
-
- CommandLine params = new CommandLine();
- if (!params.Parse(args))
- {
- System.out.println("\nIncorrect command");
- return;
- }
-
- if (params.Command == CommandLine.kBenchmak)
- {
- int dictionary = (1 << 21);
- if (params.DictionarySizeIsDefined)
- dictionary = params.DictionarySize;
- if (params.MatchFinder > 1)
- throw new Exception("Unsupported match finder");
- SevenZip.LzmaBench.LzmaBenchmark(params.NumBenchmarkPasses, dictionary);
- }
- else if (params.Command == CommandLine.kEncode || params.Command == CommandLine.kDecode)
- {
- java.io.File inFile = new java.io.File(params.InFile);
- java.io.File outFile = new java.io.File(params.OutFile);
-
- java.io.BufferedInputStream inStream = new java.io.BufferedInputStream(new java.io.FileInputStream(inFile));
- java.io.BufferedOutputStream outStream = new java.io.BufferedOutputStream(new java.io.FileOutputStream(outFile));
-
- boolean eos = false;
- if (params.Eos)
- eos = true;
- if (params.Command == CommandLine.kEncode)
- {
- SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder();
- if (!encoder.SetAlgorithm(params.Algorithm))
- throw new Exception("Incorrect compression mode");
- if (!encoder.SetDictionarySize(params.DictionarySize))
- throw new Exception("Incorrect dictionary size");
- if (!encoder.SetNumFastBytes(params.Fb))
- throw new Exception("Incorrect -fb value");
- if (!encoder.SetMatchFinder(params.MatchFinder))
- throw new Exception("Incorrect -mf value");
- if (!encoder.SetLcLpPb(params.Lc, params.Lp, params.Pb))
- throw new Exception("Incorrect -lc or -lp or -pb value");
- encoder.SetEndMarkerMode(eos);
- encoder.WriteCoderProperties(outStream);
- long fileSize;
- if (eos)
- fileSize = -1;
- else
- fileSize = inFile.length();
- for (int i = 0; i < 8; i++)
- outStream.write((int)(fileSize >>> (8 * i)) & 0xFF);
- encoder.Code(inStream, outStream, -1, -1, null);
- }
- else
- {
- int propertiesSize = 5;
- byte[] properties = new byte[propertiesSize];
- if (inStream.read(properties, 0, propertiesSize) != propertiesSize)
- throw new Exception("input .lzma file is too short");
- SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder();
- if (!decoder.SetDecoderProperties(properties))
- throw new Exception("Incorrect stream properties");
- long outSize = 0;
- for (int i = 0; i < 8; i++)
- {
- int v = inStream.read();
- if (v < 0)
- throw new Exception("Can't read stream size");
- outSize |= ((long)v) << (8 * i);
- }
- if (!decoder.Code(inStream, outStream, outSize))
- throw new Exception("Error in data stream");
- }
- outStream.flush();
- outStream.close();
- inStream.close();
- }
- else
- throw new Exception("Incorrect command");
- return;
- }
-}
diff --git a/Java/SevenZip/LzmaBench.java b/Java/SevenZip/LzmaBench.java
deleted file mode 100644
index cceda24..0000000
--- a/Java/SevenZip/LzmaBench.java
+++ /dev/null
@@ -1,392 +0,0 @@
-package SevenZip;
-
-import java.io.ByteArrayOutputStream;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-
-public class LzmaBench
-{
- static final int kAdditionalSize = (1 << 21);
- static final int kCompressedAdditionalSize = (1 << 10);
-
- static class CRandomGenerator
- {
- int A1;
- int A2;
- public CRandomGenerator() { Init(); }
- public void Init() { A1 = 362436069; A2 = 521288629; }
- public int GetRnd()
- {
- return
- ((A1 = 36969 * (A1 & 0xffff) + (A1 >>> 16)) << 16) ^
- ((A2 = 18000 * (A2 & 0xffff) + (A2 >>> 16)));
- }
- };
-
- static class CBitRandomGenerator
- {
- CRandomGenerator RG = new CRandomGenerator();
- int Value;
- int NumBits;
- public void Init()
- {
- Value = 0;
- NumBits = 0;
- }
- public int GetRnd(int numBits)
- {
- int result;
- if (NumBits > numBits)
- {
- result = Value & ((1 << numBits) - 1);
- Value >>>= numBits;
- NumBits -= numBits;
- return result;
- }
- numBits -= NumBits;
- result = (Value << numBits);
- Value = RG.GetRnd();
- result |= Value & (((int)1 << numBits) - 1);
- Value >>>= numBits;
- NumBits = 32 - numBits;
- return result;
- }
- };
-
- static class CBenchRandomGenerator
- {
- CBitRandomGenerator RG = new CBitRandomGenerator();
- int Pos;
- int Rep0;
-
- public int BufferSize;
- public byte[] Buffer = null;
-
- public CBenchRandomGenerator() { }
- public void Set(int bufferSize)
- {
- Buffer = new byte[bufferSize];
- Pos = 0;
- BufferSize = bufferSize;
- }
- int GetRndBit() { return RG.GetRnd(1); }
- int GetLogRandBits(int numBits)
- {
- int len = RG.GetRnd(numBits);
- return RG.GetRnd((int)len);
- }
- int GetOffset()
- {
- if (GetRndBit() == 0)
- return GetLogRandBits(4);
- return (GetLogRandBits(4) << 10) | RG.GetRnd(10);
- }
- int GetLen1() { return RG.GetRnd(1 + (int)RG.GetRnd(2)); }
- int GetLen2() { return RG.GetRnd(2 + (int)RG.GetRnd(2)); }
- public void Generate()
- {
- RG.Init();
- Rep0 = 1;
- while (Pos < BufferSize)
- {
- if (GetRndBit() == 0 || Pos < 1)
- Buffer[Pos++] = (byte)(RG.GetRnd(8));
- else
- {
- int len;
- if (RG.GetRnd(3) == 0)
- len = 1 + GetLen1();
- else
- {
- do
- Rep0 = GetOffset();
- while (Rep0 >= Pos);
- Rep0++;
- len = 2 + GetLen2();
- }
- for (int i = 0; i < len && Pos < BufferSize; i++, Pos++)
- Buffer[Pos] = Buffer[Pos - Rep0];
- }
- }
- }
- };
-
- static class CrcOutStream extends java.io.OutputStream
- {
- public CRC CRC = new CRC();
-
- public void Init()
- {
- CRC.Init();
- }
- public int GetDigest()
- {
- return CRC.GetDigest();
- }
- public void write(byte[] b)
- {
- CRC.Update(b);
- }
- public void write(byte[] b, int off, int len)
- {
- CRC.Update(b, off, len);
- }
- public void write(int b)
- {
- CRC.UpdateByte(b);
- }
- };
-
- static class MyOutputStream extends java.io.OutputStream
- {
- byte[] _buffer;
- int _size;
- int _pos;
-
- public MyOutputStream(byte[] buffer)
- {
- _buffer = buffer;
- _size = _buffer.length;
- }
-
- public void reset()
- {
- _pos = 0;
- }
-
- public void write(int b) throws IOException
- {
- if (_pos >= _size)
- throw new IOException("Error");
- _buffer[_pos++] = (byte)b;
- }
-
- public int size()
- {
- return _pos;
- }
- };
-
- static class MyInputStream extends java.io.InputStream
- {
- byte[] _buffer;
- int _size;
- int _pos;
-
- public MyInputStream(byte[] buffer, int size)
- {
- _buffer = buffer;
- _size = size;
- }
-
- public void reset()
- {
- _pos = 0;
- }
-
- public int read()
- {
- if (_pos >= _size)
- return -1;
- return _buffer[_pos++] & 0xFF;
- }
- };
-
- static class CProgressInfo implements ICodeProgress
- {
- public long ApprovedStart;
- public long InSize;
- public long Time;
- public void Init()
- { InSize = 0; }
- public void SetProgress(long inSize, long outSize)
- {
- if (inSize >= ApprovedStart && InSize == 0)
- {
- Time = System.currentTimeMillis();
- InSize = inSize;
- }
- }
- }
- static final int kSubBits = 8;
-
- static int GetLogSize(int size)
- {
- for (int i = kSubBits; i < 32; i++)
- for (int j = 0; j < (1 << kSubBits); j++)
- if (size <= ((1) << i) + (j << (i - kSubBits)))
- return (i << kSubBits) + j;
- return (32 << kSubBits);
- }
-
- static long MyMultDiv64(long value, long elapsedTime)
- {
- long freq = 1000; // ms
- long elTime = elapsedTime;
- while (freq > 1000000)
- {
- freq >>>= 1;
- elTime >>>= 1;
- }
- if (elTime == 0)
- elTime = 1;
- return value * freq / elTime;
- }
-
- static long GetCompressRating(int dictionarySize, long elapsedTime, long size)
- {
- long t = GetLogSize(dictionarySize) - (18 << kSubBits);
- long numCommandsForOne = 1060 + ((t * t * 10) >> (2 * kSubBits));
- long numCommands = (long)(size) * numCommandsForOne;
- return MyMultDiv64(numCommands, elapsedTime);
- }
-
- static long GetDecompressRating(long elapsedTime, long outSize, long inSize)
- {
- long numCommands = inSize * 220 + outSize * 20;
- return MyMultDiv64(numCommands, elapsedTime);
- }
-
- static long GetTotalRating(
- int dictionarySize,
- long elapsedTimeEn, long sizeEn,
- long elapsedTimeDe,
- long inSizeDe, long outSizeDe)
- {
- return (GetCompressRating(dictionarySize, elapsedTimeEn, sizeEn) +
- GetDecompressRating(elapsedTimeDe, inSizeDe, outSizeDe)) / 2;
- }
-
- static void PrintValue(long v)
- {
- String s = "";
- s += v;
- for (int i = 0; i + s.length() < 6; i++)
- System.out.print(" ");
- System.out.print(s);
- }
-
- static void PrintRating(long rating)
- {
- PrintValue(rating / 1000000);
- System.out.print(" MIPS");
- }
-
- static void PrintResults(
- int dictionarySize,
- long elapsedTime,
- long size,
- boolean decompressMode, long secondSize)
- {
- long speed = MyMultDiv64(size, elapsedTime);
- PrintValue(speed / 1024);
- System.out.print(" KB/s ");
- long rating;
- if (decompressMode)
- rating = GetDecompressRating(elapsedTime, size, secondSize);
- else
- rating = GetCompressRating(dictionarySize, elapsedTime, size);
- PrintRating(rating);
- }
-
- static public int LzmaBenchmark(int numIterations, int dictionarySize) throws Exception
- {
- if (numIterations <= 0)
- return 0;
- if (dictionarySize < (1 << 18))
- {
- System.out.println("\nError: dictionary size for benchmark must be >= 18 (256 KB)");
- return 1;
- }
- System.out.print("\n Compressing Decompressing\n\n");
-
- SevenZip.Compression.LZMA.Encoder encoder = new SevenZip.Compression.LZMA.Encoder();
- SevenZip.Compression.LZMA.Decoder decoder = new SevenZip.Compression.LZMA.Decoder();
-
- if (!encoder.SetDictionarySize(dictionarySize))
- throw new Exception("Incorrect dictionary size");
-
- int kBufferSize = dictionarySize + kAdditionalSize;
- int kCompressedBufferSize = (kBufferSize / 2) + kCompressedAdditionalSize;
-
- ByteArrayOutputStream propStream = new ByteArrayOutputStream();
- encoder.WriteCoderProperties(propStream);
- byte[] propArray = propStream.toByteArray();
- decoder.SetDecoderProperties(propArray);
-
- CBenchRandomGenerator rg = new CBenchRandomGenerator();
-
- rg.Set(kBufferSize);
- rg.Generate();
- CRC crc = new CRC();
- crc.Init();
- crc.Update(rg.Buffer, 0, rg.BufferSize);
-
- CProgressInfo progressInfo = new CProgressInfo();
- progressInfo.ApprovedStart = dictionarySize;
-
- long totalBenchSize = 0;
- long totalEncodeTime = 0;
- long totalDecodeTime = 0;
- long totalCompressedSize = 0;
-
- MyInputStream inStream = new MyInputStream(rg.Buffer, rg.BufferSize);
-
- byte[] compressedBuffer = new byte[kCompressedBufferSize];
- MyOutputStream compressedStream = new MyOutputStream(compressedBuffer);
- CrcOutStream crcOutStream = new CrcOutStream();
- MyInputStream inputCompressedStream = null;
- int compressedSize = 0;
- for (int i = 0; i < numIterations; i++)
- {
- progressInfo.Init();
- inStream.reset();
- compressedStream.reset();
- encoder.Code(inStream, compressedStream, -1, -1, progressInfo);
- long encodeTime = System.currentTimeMillis() - progressInfo.Time;
-
- if (i == 0)
- {
- compressedSize = compressedStream.size();
- inputCompressedStream = new MyInputStream(compressedBuffer, compressedSize);
- }
- else if (compressedSize != compressedStream.size())
- throw (new Exception("Encoding error"));
-
- if (progressInfo.InSize == 0)
- throw (new Exception("Internal ERROR 1282"));
-
- long decodeTime = 0;
- for (int j = 0; j < 2; j++)
- {
- inputCompressedStream.reset();
- crcOutStream.Init();
-
- long outSize = kBufferSize;
- long startTime = System.currentTimeMillis();
- if (!decoder.Code(inputCompressedStream, crcOutStream, outSize))
- throw (new Exception("Decoding Error"));;
- decodeTime = System.currentTimeMillis() - startTime;
- if (crcOutStream.GetDigest() != crc.GetDigest())
- throw (new Exception("CRC Error"));
- }
- long benchSize = kBufferSize - (long)progressInfo.InSize;
- PrintResults(dictionarySize, encodeTime, benchSize, false, 0);
- System.out.print(" ");
- PrintResults(dictionarySize, decodeTime, kBufferSize, true, compressedSize);
- System.out.println();
-
- totalBenchSize += benchSize;
- totalEncodeTime += encodeTime;
- totalDecodeTime += decodeTime;
- totalCompressedSize += compressedSize;
- }
- System.out.println("---------------------------------------------------");
- PrintResults(dictionarySize, totalEncodeTime, totalBenchSize, false, 0);
- System.out.print(" ");
- PrintResults(dictionarySize, totalDecodeTime,
- kBufferSize * (long)numIterations, true, totalCompressedSize);
- System.out.println(" Average");
- return 0;
- }
-}
diff --git a/METADATA b/METADATA
index 102ab5b..50c7d6e 100644
--- a/METADATA
+++ b/METADATA
@@ -1,19 +1,20 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update external/lzma
+# For more info, check https://cs.android.com/android/platform/superproject/+/main:tools/external_updater/README.md
+
name: "lzma"
description: "LZMA is default and general compression method of 7z format."
third_party {
- url {
- type: HOMEPAGE
- value: "https://7-zip.org/"
- }
- url {
- type: ARCHIVE
- value: "https://7-zip.org/a/lzma1900.7z"
- }
- version: "19.00"
license_type: UNENCUMBERED
last_upgrade_date {
- year: 2023
- month: 2
- day: 14
+ year: 2024
+ month: 4
+ day: 18
+ }
+ homepage: "https://7-zip.org/"
+ identifier {
+ type: "Archive"
+ value: "https://github.com/ip7z/7zip/archive/23.01.tar.gz"
+ version: "23.01"
}
}
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..e1e4514
--- /dev/null
+++ b/README.md
@@ -0,0 +1,2 @@
+# 7-Zip on GitHub
+7-Zip website: [7-zip.org](https://7-zip.org)